shithub: rott

Download patch

ref: 14fe6d1445b3679340a400c2c0ee1d32638ad22e
author: levesqu8 <levesqu8@msu.edu>
date: Thu Aug 17 21:38:40 EDT 2017

Everything from 6/2017 to now. First commit.

diff: cannot open b/rott/audiolib//null: file does not exist: 'b/rott/audiolib//null' diff: cannot open b/rott//null: file does not exist: 'b/rott//null'
--- /dev/null
+++ b/README.txt
@@ -1,0 +1,56 @@
+Based off of the icculus Rise of the Triad source port (can be found here: https://icculus.org/rott/)
+
+This source port of Rise of the Triad features the following:
+
+New gameplay options including the following
+	Blitzguards being outfitted with anything from the missile arsenal!
+	You can now pick up ammo from dropped missile weapons!
+	A special respawning enemy game mode called ZomROTT, where you have to gib your enemies to keep them from coming back!
+	Toggalable Auto Aim
+	Auto Aim for Missile Weapons
+	...and more
+
+Top Bar of the status bar isn't off to the side anymore!
+
+And all of the improvements made in the icculus source port...
+
+
+
+
+To run the game you'll need the following things:
+
+SDL.dll (https://www.libsdl.org/download-1.2.php)
+
+SDL_mixer.dll (https://www.libsdl.org/projects/SDL_mixer/release-1.2.html)
+
+And Either:
+
+DARKWAR.RTC
+DARKWAR.RTL
+DARKWAR.WAD
+DEMO1_3.DMO
+DEMO2_3.DMO
+DEMO3_3.DMO
+DEMO4_3.DMO
+REMOTE1.RTS
+
+Or
+
+HUNTBGIN.RTC
+HUNTBGIN.RTL
+HUNTBGIN.WAD
+DEMO1_3.DMO
+DEMO2_3.DMO
+DEMO3_3.DMO
+DEMO4_3.DMO
+REMOTE1.RTS
+
+Place all those files in the same directory as rott.exe.
+
+
+BUILDING:
+
+To build the project, you'll need the SDL1.2 development libraries (https://www.libsdl.org/download-1.2.php) 
+as well as the SDL_mixer developement libaries (https://www.libsdl.org/projects/SDL_mixer/release-1.2.html, under Binary).
+
+I used MinGW with gcc to build the project.
--- /dev/null
+++ b/rott/LICENSE.DOC
@@ -1,0 +1,56 @@
+"Rise of the Triad: Dark War"
+Copyright 1994/1995 Apogee Software, Ltd.
+P.O. Box 496389, Garland, TX 75049, TEL: 214-271-2137 ("Apogee")
+
+BY COPYING OR USING THIS PROGRAM, YOU INDICATE YOUR AGREEMENT TO
+THE FOLLOWING TERMS, WHICH ARE THE ONLY ONES BY WHICH APOGEE
+PERMITS COPYING OR USE.  THIS PROGRAM IS NOT SHAREWARE. 
+DISTRIBUTING IT WITHOUT APOGEE'S PERMISSION IS ILLEGAL.
+
+[1] OWNERSHIP.  Except to the extent expressly licensed by us,
+we have and reserve the exclusive copyright, trade secret and
+other rights to the Program, and the right to use the Trademarks
+"Apogee", the Apogee "comet", "Rise of the Triad", and "Dark War"
+in connection with it.
+
+[2] USE AND COPIES. You may use the Program only for your own
+purposes "just like a book".  This permits use by any number of
+people on any number of machines to use it so long as -- just
+like a book -- there is NO POSSIBILITY that more than one copy
+will be used at a time.  You have no right to copy this Program
+except for legal backups.
+
+[3] LIMITED WARRANTY AND LIMITATION OF REMEDIES
+
+If this Program (including any related written material)
+contained a physical defect, you may receive a replacement if
+you return it within 90 days of receiving it from Apogee.  Aside
+from this, IT IS PROVIDED "AS-IS", AND NO WARRANTIES OF ANY KIND
+(INCLUDING IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR
+A PARTICULAR PURPOSE), EXPRESS OR IMPLIED, ARE MADE AS TO IT OR
+ANY MEDIUM IT MAY BE ON.  OUR ENTIRE LIABILITY AND YOUR
+EXCLUSIVE REMEDY IS SUCH REPLACEMENT, AND UNDER NO CIRCUMSTANCES
+WILL WE PROVIDE ANY OTHER REMEDY FOR DIRECT, INDIRECT, SPECIAL,
+CONSEQUENTIAL, PUNITIVE, INCIDENTAL OR OTHER DAMAGES ARISING
+FROM IT, INCLUDING SUCH FROM NEGLIGENCE, STRICT LIABILITY, OR
+BREACH OF WARRANTY OR CONTRACT, EVEN AFTER NOTICE OF THE
+POSSIBILITY OF SUCH DAMAGES.  Some states do not allow the
+exclusion or limitation of implied warranties or liability for
+incidental or consequential damages, so this may not apply to
+buyers of the Program.  This gives you specific legal rights,
+and you may also have other rights which vary from state to
+state.
+
+[4] MISCELLANY
+
+ [A] With respect to every matter arising under this, you
+consent to the exclusive jurisdiction and venue of the state and
+federal courts sitting in Dallas, Texas and to service by
+certified mail, return receipt requested, or as otherwise
+permitted by law.
+
+ [B] You will not modify, reverse compile, disassemble, or
+reverse engineer the Program, or use or disclose any of our
+secret information that it contains.
+
+[V.07.15.94]
--- /dev/null
+++ b/rott/Makefile
@@ -1,0 +1,102 @@
+# Determine which version to build
+# Make sure only one of the following is set to 1 at once
+# Triple 0 will build the commercial/registered version
+
+SHAREWARE   ?= 1
+SUPERROTT   ?= 0
+SITELICENSE ?= 0
+
+CPPFLAGS += -DSHAREWARE=$(SHAREWARE)
+CPPFLAGS += -DSUPERROTT=$(SUPERROTT)
+CPPFLAGS += -DSITELICENSE=$(SITELICENSE)
+
+ROTT ?= rott
+
+# Regular build flags and rules
+
+CC ?= gcc
+
+CFLAGS ?= -g -O2
+CFLAGS += -Wall -Wno-unused
+CFLAGS += $(shell sdl-config --cflags)
+CFLAGS += $(EXTRACFLAGS)
+
+CPPFLAGS += -DUSE_SDL=1
+CPPFLAGS += -DPLATFORM_UNIX=1
+CPPFLAGS += $(EXTRACPPFLAGS)
+
+LDFLAGS += $(EXTRALDFLAGS)
+
+LDLIBS += $(shell sdl-config --libs)
+LDLIBS += -lSDL_mixer
+LDLIBS += $(EXTRALDLIBS)
+
+OBJS :=
+OBJS += cin_actr.o
+OBJS += cin_efct.o
+OBJS += cin_evnt.o
+OBJS += cin_glob.o
+OBJS += cin_main.o
+OBJS += cin_util.o
+OBJS += dosutil.o
+OBJS += engine.o
+OBJS += isr.o
+OBJS += modexlib.o
+OBJS += rt_actor.o
+OBJS += rt_battl.o
+OBJS += rt_build.o
+OBJS += rt_cfg.o
+OBJS += rt_crc.o
+OBJS += rt_com.o
+OBJS += rt_debug.o
+OBJS += rt_dmand.o
+OBJS += rt_door.o
+OBJS += rt_draw.o
+OBJS += rt_floor.o
+OBJS += rt_game.o
+OBJS += rt_in.o
+OBJS += rt_main.o
+OBJS += rt_map.o
+OBJS += rt_menu.o
+OBJS += rt_msg.o
+OBJS += rt_net.o
+OBJS += rt_playr.o
+OBJS += rt_rand.o
+OBJS += rt_scale.o
+OBJS += rt_sound.o
+OBJS += rt_spbal.o
+OBJS += rt_sqrt.o
+OBJS += rt_stat.o
+OBJS += rt_state.o
+OBJS += rt_str.o
+OBJS += rt_swift.o
+OBJS += rt_ted.o
+OBJS += rt_util.o
+OBJS += rt_view.o
+OBJS += rt_vid.o
+OBJS += rt_err.o
+OBJS += scriplib.o
+OBJS += w_wad.o
+OBJS += watcom.o
+OBJS += z_zone.o
+OBJS += byteordr.o
+OBJS += dukemusc.o
+OBJS += winrott.o
+
+AUDIOLIB := audiolib/audiolib.a
+
+all: $(ROTT)
+
+$(ROTT): $(OBJS) $(AUDIOLIB)
+	$(CC) $(CFLAGS) $(LDFLAGS) $^ $(LDLIBS) -o $@
+
+$(OBJS): develop.h
+
+$(AUDIOLIB):
+	$(MAKE) -C audiolib
+
+tidy: 
+	$(RM) $(OBJS) $(ROTT) $(ROTT).exe
+
+clean: tidy
+	$(MAKE) -C audiolib $@
\ No newline at end of file
binary files /dev/null b/rott/SDL.dll differ
binary files /dev/null b/rott/SDL_mixer.dll differ
--- /dev/null
+++ b/rott/WinRott.h
@@ -1,0 +1,58 @@
+
+
+// winrott.h
+
+
+//husk at rette i winrott.c
+
+extern int iGLOBAL_SCREENWIDTH;//bna val 800
+extern int iGLOBAL_SCREENHEIGHT;//bna val 600
+
+//extern int topBarCenterOffsetX;
+
+extern int iGLOBAL_SCREENBWIDE ;
+extern int iG_SCREENWIDTH;// default screen width in bytes
+
+extern int iGLOBAL_HEALTH_X;
+extern int iGLOBAL_HEALTH_Y;
+extern int iGLOBAL_AMMO_X;
+extern int iGLOBAL_AMMO_Y;
+
+extern int iGLOBAL_FOCALWIDTH;
+extern double dGLOBAL_FPFOCALWIDTH;
+
+void EnableScreenStretch(void);
+void DisableScreenStretch(void);
+
+/*
+double dYZANGLELIMIT;
+
+#define FOCALWIDTH 160//160
+#define FPFOCALWIDTH 160.0//160.0
+
+
+
+#define MAXSCREENHEIGHT    480//600//     200*2
+#define MAXSCREENWIDTH     640//800//     320*2
+#define SCREENBWIDE        640*(96/320)//800*(96/320)//     96*2
+#define MAXVIEWWIDTH       640//     320*2
+#define SCREENWIDTH        640*(96/320)//800*(96/320)//     96*2              // default screen width in bytes
+
+
+#define MAXSCREENHEIGHT    600
+#define MAXSCREENWIDTH     800
+#define SCREENBWIDE        800*(96/320)
+#define MAXVIEWWIDTH       800
+#define SCREENWIDTH        800*(96/320)// default screen width in bytes
+
+*/
+//#define VIEWWIDTH               MAXSCREENWIDTH//320*2             // size of view window
+//#define VIEWHEIGHT              MAXSCREENHEIGHT//200*2
+//#define MAXSCANLINES            MAXSCREENHEIGHT//200*2             // size of ylookup table
+
+
+
+
+
+
+
--- /dev/null
+++ b/rott/_engine.h
@@ -1,0 +1,27 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+#ifndef _engine_private
+#define _engine_private
+
+#define NOTSAMETILE(x1,x2)     ( (posts[(x1)].posttype!=posts[(x2)].posttype) || \
+                                 (posts[(x1)].offset!=posts[(x2)].offset))
+#define SGN(x)                 (x>0 ? 1 : -1)
+
+#endif
--- /dev/null
+++ b/rott/_isr.h
@@ -1,0 +1,32 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+//***************************************************************************
+//
+//    ISR Constants
+//
+//***************************************************************************
+
+#ifndef _isr_private
+#define _isr_private
+
+#define TIMERINT                0x08
+#define KEYBOARDINT             0x09
+
+#endif
--- /dev/null
+++ b/rott/_rt_acto.h
@@ -1,0 +1,296 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+#ifndef _rt_actor_private
+#define _rt_actor_private
+
+#define MAXGIBS            600
+#define HAAPT              24
+#define VAAPT              24
+#define GODHAPT            1024
+#define GODVAPT            1024
+#define MAXDELTAYZSHOOT    (((5*FINEANGLES)/360))
+#define MAXDELTAYZSEE      (((15*FINEANGLES)/360))
+#define MAXSHOOTOFFSET     (((15*FINEANGLES)/360))
+#define MAXSHOOTSHIFT      (1)
+#define MAXDAMAGE          (64)
+#define MAXYZANGLE         (((30*FINEANGLES)/360))
+#define SMOKEWALLOFFSET    (0x800)
+#define MZADJUST           0x30000;
+#define MAXSTEPHEIGHT      24
+#define SIGN(x)            ((x)>=0)?(1):(-1)
+#define MAXRAIN            128
+#define SG_PSTAT      0x4000
+#define SG_PSTATE     0x2000
+#define EXPLOSION_DAMAGE   50
+#define LOWFALLCLIPZ       (maxheight - 96)
+#define HIGHFALLCLIPZ      -5
+#define LOWRISECLIPZ       (nominalheight)
+#define HIGHRISECLIPZ      64
+#define NORMALGIBSPEED     0x2f00
+
+#define FL_PLEADING        0x400
+#define FL_EYEBALL         0x400
+#define FL_UNDEAD          0x8000
+
+#define NME_DRUNKTYPE       0x01
+#define NME_HEATSEEKINGTYPE 0x02
+
+#define NUMSTATES 11
+
+enum {
+    STAND,
+    PATH,
+    COLLIDE1,
+    COLLIDE2,
+    CHASE,
+    USE,
+    AIM,
+    DIE,
+    FIRE,
+    WAIT,
+    CRUSH
+};
+
+#define SHOTMOM                0x200l
+#define NEXT                   1
+#define PREV                   0
+#define ANGLEMOVE              0x2b000l
+#define PAINTIME               5l
+#define LOOKAHEAD              (20 << 16)
+#define DRAINTIME              70l
+#define EXPLOSION_IMPULSE      0x2600l
+#define ZEROMOM                ob->momentumx = ob->momentumy = 0
+#define NOMOM                  ((!ob->momentumx) && (!ob->momentumy))
+#define WHICHACTOR             (ob->obclass-lowguardobj)
+#define SPDPATROL              0x600l
+//#define ENEMYRUNSPEED          (3*SPDPATROL)
+#define ENEMYRUNSPEED          (0xc00)
+#define ENEMYFASTRUNSPEED      (5*SPDPATROL)
+#define ENEMYINSANESPEED       (7*SPDPATROL)
+#define MAXMOVE                0x2000l
+#define PROJECTILESIZE         0x6000l
+#define DEADFRICTION           0x6000l
+#define ROLLMOMENTUM           0x920l
+#define PROJSIZE               0x4000l
+#define PILLARMOM              0x800l
+#define HALFGLOBAL1            (TILEGLOBAL/2)
+#define TOUCHDIST              0xb000l
+#define STANDDIST              0x5000l
+#define SNAKERAD               0x4000l
+#define MINSIGHT               0x18000l
+#define HBM                    -2
+#define SNEAKY                 -3
+#define GIBVALUE               -3
+#define DISKMOMZ               4
+
+//=========================== macros =============================
+
+#define M_ISWALL(x)           ((x->which == WALL) || (x->which == PWALL) || (x->which == MWALL))
+#define M_DISTOK(p1,p2,d)     (abs((p1)-(p2)) <= d)
+#define M_NONS(x)             ((x->obclass == wallfireobj) || (x->obclass == pillarobj))
+#define M_CHOOSETIME(x)       ((int)(TILEGLOBAL/((x->speed))))
+#define M_DIST(x1,x2,y1,y2)   (((x1-x2)*(x1-x2))+((y1-y2)*(y1-y2)))
+#define M_S(x)                (UPDATE_STATES[x][ob->obclass-lowguardobj])
+#define Fix(a)                (a &= (FINEANGLES - 1))
+
+
+#define STOPACTOR(ob)                   \
+   {                                    \
+   ob->momentumx = ob->momentumy = 0;   \
+   ob->dirchoosetime = 0;               \
+   }
+
+
+#define M_CHECKDIR(ob,tdir)             \
+   {                                    \
+   ob->dir = tdir;                      \
+   ParseMomentum(ob,dirangle8[tdir]);   \
+   ActorMovement(ob);                   \
+   if (ob->momentumx || ob->momentumy)  \
+      return;                           \
+   }                                    \
+
+
+#define M_CHECKTURN(x,ndir)                             \
+   {                                                    \
+   if (ndir == olddir)                                  \
+      ZEROMOM;                                          \
+   ParseMomentum(x,dirangle8[ndir]);                    \
+   ActorMovement(x);                                    \
+   if (!NOMOM)                                          \
+      {                                                 \
+      if (ndir != olddir)                               \
+         {                                              \
+         next = dirorder[olddir][NEXT];                 \
+         prev = dirorder[olddir][PREV];                 \
+         x->temp1 = ndir;                               \
+         if (dirdiff[ndir][next] < dirdiff[ndir][prev]) \
+            NewState(x,&s_kristleft);                   \
+         else                                           \
+            NewState(x,&s_kristright);                  \
+         }                                              \
+      return;                                           \
+      }                                                 \
+   }                                                    \
+
+#define M_CheckDoor(ob)                          \
+   {                                             \
+   door = ob->door_to_open;                      \
+   if (door != -1)                               \
+      {                                          \
+      if ((ob->obclass > shurikenobj) &&         \
+          (ob->obclass != collectorobj)          \
+         )                                       \
+         Error("you got it !!!");                \
+      LinkedOpenDoor(door);                      \
+      if (doorobjlist[door]->action != dr_open)  \
+         return;                                 \
+      ob->door_to_open = -1;                     \
+      }                                          \
+   }                                             \
+
+#define M_CheckBossSounds(ob)                                 \
+   {                                                          \
+   if ((ob->obclass >= b_darianobj) &&                        \
+       (ob->obclass <= b_darksnakeobj) &&                     \
+       (ob->flags & FL_ATTACKMODE)  &&                        \
+       (ob->obclass != b_robobossobj) &&                      \
+       (!(ob->flags & FL_DYING))                              \
+      )                                                       \
+      {                                                       \
+      if (MISCVARS->SOUNDTIME)                                \
+         MISCVARS->SOUNDTIME --;                              \
+      else                                                    \
+         {                                                    \
+         MISCVARS->SOUNDTIME = 5*VBLCOUNTER;                  \
+         if (GameRandomNumber("boss sound check",0)<160)      \
+            {                                                 \
+            int rand,sound;                                   \
+                                                              \
+            rand = GameRandomNumber("boss sounds",0);         \
+            sound = BAS[ob->obclass].operate;                 \
+            if (rand < 160)                                   \
+               sound ++;                                      \
+            if (rand < 80)                                    \
+               sound ++;                                      \
+                                                              \
+            SD_PlaySoundRTP(sound,ob->x,ob->y);               \
+            }                                                 \
+         }                                                    \
+      if (MISCVARS->REDTIME)                                  \
+         {                                                    \
+         MISCVARS->REDTIME --;                                \
+         MISCVARS->redindex = ((MISCVARS->REDTIME >> 1) & 15);\
+         }                                                    \
+      }                                                       \
+   }
+
+
+
+
+#define SET_DEATH_SHAPEOFFSET(ob)                     \
+   {                                                  \
+   ob->flags |= FL_ALTERNATE;                         \
+   ob->shapeoffset += deathshapeoffset[ob->obclass];  \
+   }
+
+
+#define RESET_DEATH_SHAPEOFFSET(ob)                   \
+   {                                                  \
+   ob->flags &= ~FL_ALTERNATE;                        \
+   ob->shapeoffset -= deathshapeoffset[ob->obclass];  \
+   }
+
+#define LOW_VIOLENCE_DEATH_SHOULD_BE_SET(ob)          \
+     ((gamestate.violence < vl_high) &&               \
+      (ob->obclass >= lowguardobj) &&                 \
+      (ob->obclass <= triadenforcerobj) &&            \
+      (!(ob->flags & FL_ALTERNATE))                   \
+     )                                                \
+
+#define LOW_VIOLENCE_DEATH_IS_SET(ob)   (ob->flags & FL_ALTERNATE)
+
+#define LOW_VIOLENCE_PAIN_SHOULD_BE_SET  LOW_VIOLENCE_DEATH_SHOULD_BE_SET
+
+#define LOW_VIOLENCE_PAIN_IS_SET  LOW_VIOLENCE_DEATH_IS_SET
+
+#define SET_PAIN_SHAPEOFFSET  SET_DEATH_SHAPEOFFSET
+
+#define RESET_PAIN_SHAPEOFFSET  RESET_DEATH_SHAPEOFFSET
+
+
+// default = actor
+
+typedef struct  sat
+{   int          x,y,z;
+    unsigned     flags;
+    int          hitpoints;
+    int          targetx,targety;
+    int          angle;
+    int          yzangle;
+    int          speed;
+    int          momentumx,momentumy,momentumz;
+    int          temp1,temp2,temp3;
+    int          whateverindex,targetindex;
+
+    short        ticcount;
+    short        shapeoffset;
+    short        stateindex;
+    short        dirchoosetime;
+
+    byte         areanumber;
+    byte         obclass;
+    signed char  door_to_open;
+    signed char  dir;
+
+} saved_actor_type;
+
+
+typedef struct
+{   thingtype which;
+    byte tilex,tiley;
+    fixed x,y,z;
+} tpoint;
+
+
+//========================== Function Prototypes ==============================
+
+void     MissileMovement(objtype*);
+boolean  MissileTryMove(objtype*,int,int,int);
+void     T_DarkSnakeChase(objtype*);
+void     HeatSeek(objtype*);
+boolean  CheckDoor(objtype *ob,doorobj_t*,int,int);
+boolean  NextToDoor(objtype*ob);
+void     MissileHit (objtype *ob,void*);
+int      Near(objtype*,void*,int);
+void     FirstSighting(objtype*);
+void     SelectOrobotChaseDir(objtype*);
+void     SelectPathDir(objtype*);
+void     SelectChaseDir(objtype*);
+void     SelectRoboChaseDir(objtype*);
+void     SelectDodgeDir(objtype*);
+void     SelectRollDir (objtype*);
+void     SelectTouchDir(objtype*);
+void     SelectMineDir(objtype*);
+boolean  WallCheck(int,int);
+boolean  NMEspincheck(objtype*);
+void     TurnActorIntoSprite(objtype*ob);
+void     ActivateEnemy(objtype*);
+#endif
--- /dev/null
+++ b/rott/_rt_buil.h
@@ -1,0 +1,48 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+#ifndef _rt_build_private
+#define _rt_build_private
+
+#define MAX(x,y)               ((x>y) ? (x) : (y))
+#define MAXPLANES 10
+
+// Should be 10 with titles
+#define MENUOFFY     (10)
+#define MENUBACKNAME ("plane")
+#define MENUTITLEY 10
+#define TEXTUREW     (288)
+#define TEXTUREWIDTH ((TEXTUREW*1024)-1)
+#define TEXTUREHEIGHT (158)
+#define NORMALVIEW   (0x40400L)
+#define NORMALHEIGHTDIVISOR   (156000000)
+#define NORMALWIDTHMULTIPLIER (241)
+#define FLIPTIME     20//60
+
+
+typedef struct
+{
+    int   x1, y1;
+    int   x2, y2;
+    int   texturewidth;
+    int   texture;
+    int   origheight;
+} plane_t;
+
+#endif
--- /dev/null
+++ b/rott/_rt_com.h
@@ -1,0 +1,53 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+#ifndef _rt_com_private
+#define _rt_com_private
+
+
+#define SYNCPACKETSIZE 32
+
+#define SYNC_PHASE0 6
+#define SYNC_PHASE1 0
+#define SYNC_PHASE2 1
+#define SYNC_PHASE3 2
+#define SYNC_PHASE4 3
+#define SYNC_PHASE5 4
+#define SYNC_MEMO   99
+#define NUMSYNCPHASES 5
+
+#define SYNCTIME    15
+
+typedef struct
+{
+    byte type;
+    int  phase;
+    int  clocktime;
+    int  delta;
+    byte data[SYNCPACKETSIZE];
+} syncpackettype;
+
+typedef struct
+{
+    int  sendtime;
+    int  deltatime;
+    syncpackettype pkt;
+} synctype;
+
+#endif
--- /dev/null
+++ b/rott/_rt_dman.h
@@ -1,0 +1,29 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+#ifndef _rt_dmand_private
+#define _rt_dmand_private
+
+#define RECORDINGSAMPLERATE 7000
+#define RECORDINGBUFFERSIZE 16384
+#define PLAYBACKBUFFERSIZE 16384
+#define PLAYBACKDELTASIZE  256
+
+#endif
+
--- /dev/null
+++ b/rott/_rt_door.h
@@ -1,0 +1,48 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+#ifndef _rt_door_private
+#define _rt_door_private
+
+#define OPENTICS	165
+
+typedef struct tp
+{
+    signed char actionindex;
+    signed char swapactionindex;
+    int         whichobj;
+    byte        tictime;
+    byte        ticcount;
+    byte        triggered;
+    byte        complete;
+    byte        done;
+} saved_touch_type;
+
+
+#define NUMTOUCHPLATEACTIONS 8
+
+#define FL_TACT 0x4000
+#define FL_TSTAT 0x8000
+
+#define PUSHWALLSPEED 10
+
+#define AMW_NUMFRAMES 9
+#define AMW_TICCOUNT  3
+
+#endif
--- /dev/null
+++ b/rott/_rt_draw.h
@@ -1,0 +1,74 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+#ifndef _rt_draw_private
+#define _rt_draw_private
+
+#include "develop.h"
+
+#define MINZ                            0x2700
+#define MAXBOB                          0x9000
+
+#define GOLOWER  0x38000
+#define GOHIGHER 0x20000
+
+#define MAXVISIBLEDOORS 30
+
+#define DHEIGHTFRACTION 8
+
+#define MINZ                            0x2700
+#define MAXDRAWNTICS                    40
+
+#define W_CHANGE  (WEAPONUPTICS || WEAPONDOWNTICS)
+
+#if (SHAREWARE == 0)
+#define NUMWEAPGRAPHICS 16
+#else
+#define NUMWEAPGRAPHICS 9
+#endif
+
+#define HFRACTION (6+HEIGHTFRACTION)
+
+#define FIXEDTRANSLEVEL (30)
+
+typedef struct
+{
+    int x;
+    int y;
+    int angle;
+    int scale;
+    int dx;
+    int dy;
+    int dangle;
+    int dscale;
+    int phase;
+    int time;
+    int pausetime;
+    int pausex;
+    int pausey;
+} screensaver_t;
+
+void  DrawPlayerWeapon(void);
+boolean TransformPlane (int x1, int y1, int x2, int y2, visobj_t * plane);
+int   CalcRotate (objtype *ob);
+void  DrawScaleds (void);
+void  FixOfs (void);
+void SetSpriteLightLevel (int x, int y, visobj_t * sprite, int dir, int fullbright);
+
+#endif
--- /dev/null
+++ b/rott/_rt_floo.h
@@ -1,0 +1,28 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+#ifndef _rt_floor_private
+#define _rt_floor_private
+
+//#define	MAXVIEWHEIGHT MAXSCREENHEIGHT
+#define MAXSKYSEGS    2048
+#define MAXSKYDATA    8
+#define MINSKYHEIGHT  148
+
+#endif
--- /dev/null
+++ b/rott/_rt_game.h
@@ -1,0 +1,165 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+#ifndef _rt_game_private
+#define _rt_game_private
+
+//******************************************************************************
+//
+// Private header for RT_GAME.C
+//
+//******************************************************************************
+
+
+//******************************************************************************
+//
+// TYPEDEFS
+//
+//******************************************************************************
+
+typedef struct {
+    char str[10];
+    int length;
+} STR;
+
+//******************************************************************************
+//
+// DEFINES
+//
+//******************************************************************************
+
+#define MENUSHADELEVEL  105
+
+#define KILLS_X      0
+#define KILLS_Y      176
+#define KILLS_WIDTH  32
+#define KILLS_HEIGHT 24
+#define KILLS_OFFSET 14
+#define KILLS_NAME_Y ( KILLS_Y + 16 )
+#define MAXKILLBOXES 10
+#define PLAYERS_Y      ( 107 + ( gamestate.teamplay ? 0 : 4 ) )
+#define PLAYERS_NAME_Y ( PLAYERS_Y + 16 )
+#define PLAYERS_TEAM_Y ( PLAYERS_Y + 24 )
+
+#define LEADER_X      0
+#define LEADER_Y      0
+#define LEADER_NUM_X  61
+#define LEADER_NUM_Y  ( LEADER_Y )
+#define LEADER_NAME_X ( LEADER_X + 3 )
+#define LEADER_NAME_Y ( LEADER_Y + 2 )
+#define LEADER_WIDTH  88
+#define LEADER_HEIGHT 16
+/* bna++
+#define HEALTH_X  20
+#define HEALTH_Y  185
+
+#define AMMO_X    300
+#define AMMO_Y    184
+*/
+//--------------------
+#define HEALTH_X  20*2
+#define HEALTH_Y  (185*2)+16
+
+#define AMMO_X    300*2
+#define AMMO_Y    (184*2)+16
+//--------------------
+
+#define SCORE_X   4
+#define SCORE_Y   0
+
+/*
+#define KEY1_X    152
+#define KEY2_X    160
+#define KEY3_X    168
+#define KEY4_X    176
+#define KEY_Y     0
+
+#define POWER_X   184
+#define POWER_Y   0
+
+#define ARMOR_X   200
+#define ARMOR_Y   0
+
+#define MEN_X     216
+#define MEN_Y     0
+*/
+//--------------------
+#define KEY1_X    152
+#define KEY2_X    160
+#define KEY3_X    168
+#define KEY4_X    176
+#define KEY_Y     0
+
+#define POWER_X   (184)
+#define POWER_Y   0
+
+#define ARMOR_X   200
+#define ARMOR_Y   0
+
+#define MEN_X     216
+#define MEN_Y     0
+//--------------------
+#define HOUR_X    7
+#define MIN_X     26
+#define SEC_X     45
+#define TIME_Y    0
+
+#define GAMETIME_X 88
+#define GAMETIME_Y 0
+
+#define TALLYTIME_X 130
+#define TALLYTIME_Y 8
+
+#define LIVES_X   288
+#define LIVES_Y   0
+
+#define TRIAD_X   308
+#define TRIAD_Y   6
+
+#define POWERUP1X 184
+#define POWERUP2X 200
+#define POWERUPY  0
+
+#define EXTRAPOINTS        50000
+#define ADRENALINEBONUS    5
+
+#define STR_SAVECHT1 "Your Save Game file is,"
+#define STR_SAVECHT2 "shall we say, \"corrupted\"."
+#define STR_SAVECHT3 "But I'll let you go on and"
+#define STR_SAVECHT4 "play anyway...."
+
+#define MAXSAVEDGAMESIZE 120000
+
+#if (SHAREWARE == 0)
+#define WEAPON_IS_MAGICAL(x) (((x) == wp_dog) || ((x) == wp_godhand))
+#else
+#define WEAPON_IS_MAGICAL(x) ((x) == wp_godhand)
+#endif
+
+//******************************************************************************
+//
+// PROTOTYPES
+//
+//******************************************************************************
+
+void DrawMPPic (int xpos, int ypos, int width, int height, int heightmod, byte *src, boolean bufferofsonly);
+void DrawHighScores (void);
+void GM_MemToScreen (byte *source, int width, int height, int x, int y);
+
+#endif
--- /dev/null
+++ b/rott/_rt_in.h
@@ -1,0 +1,61 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+//****************************************************************************
+//
+// Private header for RT_IN.C
+//
+//****************************************************************************
+
+#ifndef _rt_in_private
+#define _rt_in_private
+
+
+//****************************************************************************
+//
+// TYPEDEFS
+//
+//****************************************************************************
+
+
+//****************************************************************************
+//
+// DEFINES
+//
+//****************************************************************************
+
+#define  KeyInt         9  // The keyboard ISR number
+#define  MReset         0
+#define  MButtons       3
+#define  MDelta         11
+#define  MouseInt       0x33
+#define  JoyScaleMax    32768
+#define  JoyScaleShift  8
+#define  MaxJoyValue    5000
+
+void Mouse (int x);
+
+#if defined(__WATCOMC__)
+#pragma aux Mouse =  \
+   "int  33h"        \
+   parm [EAX]        \
+   modify [EAX]
+#endif
+
+#endif
--- /dev/null
+++ b/rott/_rt_main.h
@@ -1,0 +1,74 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+#ifndef _rt_main_private
+#define _rt_main_private
+
+#include "develop.h"
+
+void GameLoop (void);
+void PlayLoop (void);
+void PollKeyboard(void);
+void FixColorMap( void );
+
+#define QUITTIMEINTERVAL ((35*6)-5)
+boolean CheckForQuickLoad ( void );
+
+#if SAVE_SCREEN
+
+void WriteLBMfile (char *filename, byte *data, int width, int height);
+void GetFileName (boolean saveLBM);
+void DrawRottTitle ( void );
+
+void WritePCX (char * file, byte * source);
+int PutBytes (unsigned char *ptr, unsigned int bytes);
+
+typedef struct
+{
+    unsigned short w,h;
+    short          x,y;
+    unsigned char  nPlanes;
+    unsigned char  masking;
+    unsigned char  compression;
+    unsigned char  pad1;
+    unsigned short transparentColor;
+    unsigned char  xAspect,yAspect;
+    short          pageWidth,pageHeight;
+} bmhd_t;
+
+
+typedef struct {
+    unsigned char manufacturer;
+    unsigned char version;
+    unsigned char encoding;
+    unsigned char bitsperpixel;
+    unsigned short int  xmin, ymin, xmax, ymax;
+    unsigned short int  hres, vres;
+    unsigned char colormap[16][3];
+    unsigned char reserved;
+    unsigned char nplanes;
+    unsigned short int  bytesperline;
+} PCX_HEADER;
+
+#define GAP_SIZE  (128 - sizeof (PCX_HEADER))
+
+
+#endif
+
+#endif
--- /dev/null
+++ b/rott/_rt_map.h
@@ -1,0 +1,44 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+#ifndef _rt_map_private
+#define _rt_map_private
+
+#if defined(__WATCOM__)
+#pragma aux FastFill =  \
+        "rep stosb"       \
+        parm    [edi] [eax] [ecx] \
+        modify exact [ecx]
+#endif
+void FastFill(byte * buf, int color, int count);
+
+
+#define MAP_PLAYERCOLOR 4
+#define MAP_MWALLCOLOR 13
+#define MAP_PWALLCOLOR 8
+#define MAP_AWALLCOLOR 9
+#define MAP_WALLCOLOR 7
+#define MAP_DOORCOLOR 3
+#define MAP_SPRITECOLOR 2
+#define MAP_ACTORCOLOR 15
+#define MAP_SKYCOLOR 11
+
+#define FULLMAP_SCALE 5
+
+#endif
--- /dev/null
+++ b/rott/_rt_menu.h
@@ -1,0 +1,369 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+#ifndef _rt_menu_private
+#define _rt_menu_private
+
+//******************************************************************************
+//
+// Private Header for RT_MENU.C
+//
+//******************************************************************************
+
+#include "rt_in.h"
+
+//
+// Specific Menu defines
+//
+
+#define BORDCOLOR       0x29
+#define BORD2COLOR      0x23
+#define DEACTIVE        0x2b
+#define BKGDCOLOR       0x2d
+#define STRIPE          0x2c
+
+
+#define SENSITIVE       60
+#define CENTER          SENSITIVE*2
+
+
+#define MENU_X          32
+#define MENU_Y          16
+#define MENU_W          235
+#define MENU_H          14*9+4
+
+
+#define LSM_X           180      //32
+#define LSM_Y           16
+#define LSM_W           80       //176
+#define LSM_H           10*14+8
+
+#define LSA_X           96
+#define LSA_Y           80
+#define LSA_W           130
+#define LSA_H           42
+
+
+#define SM_X            32
+#define SM_Y            52
+#define SM_W            252
+#define SM_H            35
+
+#define SM_Y1           20
+#define SM_H1           4*14-9
+#define SM_Y2           SM_Y1+5*14
+#define SM_H2           4*14-9
+#define SM_Y3           SM_Y2+5*14
+#define SM_H3           3*14-9
+
+
+#define CTL_X           19
+#define CTL_Y           32
+#define CTL_W           284
+#define CTL_H           105
+
+
+#define CST_X           20
+#define CST_Y           43
+#define CST_START       60
+#define CST_SPC         60
+
+
+#define TUF_X           0
+#define TUF_Y           32
+
+
+#define HLP_X           34
+#define HLP_Y           63
+#define HLP_W           264
+#define HLP_H           51
+
+
+#define MU_X            32
+#define MU_Y            22
+#define MU_W            252
+#define MU_H            118
+
+
+#define FX_X            32
+#define FX_Y            16
+#define FX_W            252
+#define FX_H            130
+
+
+#define MP_X            55//32
+#define MP_Y            60
+#define MP_W            252
+#define MP_H            35
+
+
+#define X1_X            55
+#define X1_Y            25
+#define X1_W            252
+
+#define X2_X            55
+#define X2_Y            65
+#define X2_W            252
+#define X2_H            35
+
+#define X3_X            55
+#define X3_Y            65
+#define X3_W            252
+#define X3_H            35
+
+#define LEVSEL_X            32
+#define LEVSEL_Y            22
+#define LEVSEL_W            252
+#define LEVSEL_H            118
+#define MAXCUSTOM       12
+
+#define STARTITEM       newgame
+
+//
+// General defines
+//
+#define CP_SemiActive      4
+#define CP_Highlight       5
+
+#define OUTOFRANGE         100
+#define ESCPRESSED         -1
+#define PAGEUP             -2
+#define PAGEDOWN           -3
+#define NOTAVAILABLECOLOR  7
+#define NEXTPAGECOLOR      16
+#define NORMALCOLOR        21
+#define DIMMEDCOLOR        24
+#define ACTIVECOLOR        241
+#define HIGHLIGHTCOLOR     1
+
+#define MouseInt 0x33
+#define GAMESVD      "There's already a game\n" \
+                     "saved at this position.\n"\
+                     "Overwrite?"
+#define COLOR        235
+
+#define CUSTOMX      76
+
+#define NUMSAVEGAMES 14
+
+#define PWORDX 58
+#define PWORDY 46
+//#define PBOXX  68
+#define PBOXX  ( ( 288 - PBOXW ) / 2 )
+#define PBOXY  71
+#define PBOXW  115
+#define PSTRW  110
+#define PBOXH  12
+
+
+#define QUICKSAVEBACKUP ("rottgamf.rot")
+//******************************************************************************
+//
+// ENUMS
+//
+//******************************************************************************
+
+typedef struct
+{
+    int allowed[4];
+} CustomCtrls;
+
+// FOR INPUT TYPES
+enum {MOUSE, JOYSTICK, KEYBOARDBTNS, KEYBOARDMOVE, SPECIAL1, SPECIAL2};
+
+
+//******************************************************************************
+//
+// GLOBALS
+//
+//******************************************************************************
+
+static byte *ScanNames[] =    // Scan code names with single chars
+{
+    "?","?","1","2","3","4","5","6","7","8","9","0","-","+","?","?",
+    "Q","W","E","R","T","Y","U","I","O","P","[","]","|","?","A","S",
+    "D","F","G","H","J","K","L",";","\"","?","?","?","Z","X","C","V",
+    "B","N","M",",",".","/","?","?","?","?","?","?","?","?","?","?",
+    "?","?","?","?","?","?","?","?","\xf","?","-","\x15","5","\x11","+","?",
+    "\x13","?","?","?","?","?","?","?","?","?","?","?","?","?","?","?",
+    "?","?","?","?","?","?","?","?","?","?","?","?","?","?","?","?",
+    "?","?","?","?","?","?","?","?","?","?","?","?","?","?","?","?"
+};
+
+
+static byte ExtScanCodes[] = // Scan codes with >1 char names
+{
+    1,    0xe,  0xf,  0x1d, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e,
+    0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x57, 0x58, 0x46, 0x1c, 0x36,
+    0x37, 0x38, 0x47, 0x49, 0x4f, 0x51, 0x52, 0x53, 0x45, 0x48,
+    0x50, 0x4b, 0x4d, 0x00
+};
+
+static byte *ExtScanNames[] = // Names corresponding to ExtScanCodes
+{
+    "Esc","BkSp","Tab","Ctrl","Space","CapLk","F1","F2","F3","F4",
+    "F5","F6","F7","F8","F9","F10","F11","F12","SclLk","Enter","Shift",
+    "PrtSc","Alt","Home","PgUp","End","PgDn","Ins","Del","NumLk","Up",
+    "Down","Left","Right",""
+};
+
+
+//******************************************************************************
+//
+// PROTOTYPES
+//
+//******************************************************************************
+
+void MouseSensitivity (void);
+void DoThreshold (void);
+byte * IN_GetScanName (ScanCode scan);
+void DisplayInfo (int which);
+
+void PrintLSEntry (int w);
+
+void DrawHalfStep (int x, int y);
+
+void DrawCtlScreen (void);
+void DrawCtlButtons (void);
+void DrawSoundMenu (void);
+void DrawCustomScreen (void);
+void DrawLoadSaveScreen (int loadsave);
+void DrawLoadSaveScreenAlt (int loadsave);
+void DrawMusicMenu (void);
+void DrawNewGame (void);
+void DrawNewGameDiff (int w);
+void DrawNewPlayerDiff (int w);
+void DrawFXMenu (void);
+void DrawFXButtons (void);
+void DrawCustomJoystick (void);
+void DrawCustomMouse (void);
+void DrawCustomSpecial (void);
+void DrawCustomMenu (void);
+void DrawPlayerMenu (void);
+
+void DoMainMenu (void);
+
+boolean CP_DisplayMsg (char *s, int number);
+void CP_EndGame (void);
+int CP_SaveGame (void);
+void CP_Control (void);
+void CP_Sound (void);
+void CP_ChangeView (void);
+void CP_DoubleClickSpeed( void );
+void CP_ErrorMsg( char *title, char *error, int font );
+void CP_Quit (int which);
+void CP_NewGame (void);
+void CP_Music (void);
+void CP_FX (void);
+void CP_MCports (void);
+void CP_FXMenu (void);
+void CP_Custom (void);
+void CP_Keyboard (void);
+void CP_Mouse (void);
+void CP_Joystick (void);
+void CP_Special (void);
+void CP_OrderInfo( void );
+
+void DefineMouseBtns1 (void);
+void DefineMouseBtns2 (void);
+void DefineKeyBtns1 (void);
+void DefineKeyBtns2 (void);
+void DefineKeyMove1 (void);
+void DefineKeyMove2 (void);
+void DefineJoyBtns1 (void);
+void DefineJoyBtns2 (void);
+void DefineSpecialBtns1 (void);
+void DefineSpecialBtns2 (void);
+
+void DrawSTMenuBuf (int x, int y, int w, int h, boolean up);
+
+void MusicVolume (void);
+void FXVolume (void);
+
+void DefineKey( void );
+void DefineJoyBtn( void );
+void DefineMouseBtn( void );
+
+void DrawControlMenu (void);
+void CP_ControlMenu (void);
+void DrawOptionsMenu (void);
+void DrawExtOptionsMenu (void);
+void CP_ExtOptionsMenu (void);
+void CP_OptionsMenu (void);
+void DrawOptionsButtons (void);
+void DrawExtOptionsButtons (void);
+void MenuFlipSpeed (void);
+void DrawDetailMenu (void);
+void CP_DetailMenu (void);
+void DrawBattleMenu (void);
+void CP_BattleMenu (void);
+void MCERROR (void);
+
+void DrawKeyboardMenu (void);
+void CP_KeyboardMenu (void);
+boolean SliderMenu( int *number, int upperbound, int lowerbound, int erasex,
+                    int erasey, int erasew, int numadjust, char *blockname,
+                    void (*routine) (int w), char *title, char *left, char *right );
+
+void DrawF1Help (void);
+void CP_F1Help (void);
+void CP_ScreenSize( void );
+
+void CP_ViolenceMenu (void);
+void DrawViolenceLevelMenu (void);
+void DrawViolenceLevelPWord (void);
+
+void DrawViolenceLevel (void);
+void CP_ViolenceLevel (void);
+
+void DrawPWMenu (void);
+void CP_PWMenu (void);
+
+void DrawBattleModes (void);
+void CP_BattleModes (void);
+
+void DrawBattleOptions (void);
+void CP_BattleOptions (void);
+
+void DrawGravityMenu (void);
+void CP_GravityOptions (void);
+void DrawSpeedMenu (void);
+void CP_SpeedOptions (void);
+void DrawAmmoPerWeaponMenu (void);
+void CP_AmmoPerWeaponOptions (void);
+void DrawHitPointsMenu (void);
+void CP_HitPointsOptions (void);
+void DrawSpawnControlMenu (void);
+void DrawSpawnControlButtons (void);
+void CP_SpawnControlOptions (void);
+void DrawLightLevelMenu (void);
+void CP_LightLevelOptions (void);
+void DrawPointGoalMenu (void);
+void CP_PointGoalOptions (void);
+void DrawDangerMenu (void);
+void CP_DangerOptions (void);
+void DrawTimeLimitMenu (void);
+void CP_TimeLimitOptions (void);
+void PrintBattleOption( boolean inmenu, int x, int y, char *text );
+
+void CP_OnePlayerWarningMessage( void );
+
+void DrawMultiPageCustomMenu( char *title, void ( *redrawfunc )( void ) );
+
+#endif
--- /dev/null
+++ b/rott/_rt_msg.h
@@ -1,0 +1,25 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+#ifndef _rt_msg_private
+#define _rt_msg_private
+
+#define MESSAGETIME (35*6)
+
+#endif
--- /dev/null
+++ b/rott/_rt_net.h
@@ -1,0 +1,122 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+#ifndef _rt_net_private
+#define _rt_net_private
+
+#define DEMOBUFFSIZE 50000
+
+#define FASTSPEED (0xB000)
+
+#define SETUPTIME     15
+
+#define PlayerCommand(player,command)    \
+        (PlayerCmds[(player)]->Commands[(command)])
+
+#define ClientCommand(player,command)    \
+        (ClientCmds[(player)]->Commands[(command)])
+
+#define LocalCommand(command)    \
+        (LocalCmds->Commands[(command)])
+
+#define ServerCommand(command)    \
+        (ServerCmds->Commands[(command)])
+
+#define CommandAddress(time)    \
+        (((time)-controlupdatestartedtime) & (MAXCMDS-1))
+
+#define NextLocalCommand()    \
+        (LocalCommand(CommandAddress(controlupdatetime)))
+
+#define NextServerCommand()    \
+        (ServerCommand(CommandAddress(serverupdatetime)))
+
+#define ClientTimeCommand(which,whichtime)    \
+        (ClientCmds[(which)]->Commands[(CommandAddress((whichtime)))])
+
+#define ServerCommandStatus(whichtime)    \
+        (CommandState[0]->CommandStates[(CommandAddress((whichtime)))])
+
+#define ServerCommandNumberStatus(command)    \
+        (CommandState[0]->CommandStates[(command)])
+
+#define ClientCommandStatus(which, whichtime)    \
+        (CommandState[(which+1)]->CommandStates[(CommandAddress((whichtime)))])
+
+#define ClientCommandNumberStatus(which, command)    \
+        (CommandState[(which+1)]->CommandStates[(command)])
+
+/*
+#define PacketAddress(time)    \
+        ((time) & (MAXCMDS-1))
+*/
+
+#define PacketAddress(time)    \
+        (time)
+
+
+#define NETWORKTIMEOUT  (VBLCOUNTER/3)
+#define MODEMTIMEOUT    (VBLCOUNTER/2)
+#define SERVERTIMEOUT    (VBLCOUNTER<<3)
+
+#define MAXPOLLTICS 3
+
+
+typedef enum {
+    scfp_nodata,
+    scfp_gameready,
+    scfp_data,
+    scfp_done
+} setupcheckforpacketstate;
+
+typedef enum {
+    cs_ready,
+    cs_notarrived,
+    cs_fixing
+} en_CommandStatus;
+
+typedef enum {
+    player_ingame,
+    player_quitgame,
+    player_leftgame
+} en_playerstatus;
+
+void PreparePacket (MoveType * pkt);
+int  GetPacketSize (void * pkt);
+void SendPacket (void * pkt, int dest);
+void GetRemotePacket (int from, int delay);
+void ResendLocalPackets  (int time, int dest, int numpackets);
+void ResendServerPackets (int time, int dest, int numpackets);
+void ResendPacket (void * pkt, int dest);
+void AddClientDelta (void * pkt, int src);
+void FixupPacket (void * pkt, int src);
+void ProcessPacket (void * pkt, int src);
+void AddServerPacket(void * pkt, int src);
+void AddClientPacket (void * pkt, int src);
+void AddPacket (void * pkt, int src);
+void RequestPacket (int time, int dest, int numpackets);
+boolean AllPlayersReady ( void );
+boolean AreClientsReady ( void );
+boolean IsServerCommandReady ( int time );
+void UpdatePlayerObj ( int player );
+void AddServerSubPacket(COM_ServerHeaderType * serverpkt);
+void AddSubPacket (void * pkt, int src);
+
+
+#endif
--- /dev/null
+++ b/rott/_rt_play.h
@@ -1,0 +1,125 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+#ifndef _rt_playr_private
+#define _rt_playr_private
+
+#include "watcom.h"
+//double dTopYZANGLELIMIT; in winrott.c
+#define TopYZANGLELIMIT  (44*FINEANGLES/360)//bna added
+#define YZANGLELIMIT  (80*FINEANGLES/360)//bna--(30*FINEANGLES/360)
+/*
+//bna++ had to limit this or the sky would fuck up
+#define TopYZANGLELIMIT  (6*FINEANGLES/360)//bna added
+#define YZANGLELIMIT  (40*FINEANGLES/360)//bna--(30*FINEANGLES/360)
+//partly fixed you can now se up but not down very much see rt_playr.c TopYZANGLELIMIT
+*/
+
+
+#define YZTILTSPEED   20*4//*2 = bna added
+#define SNAPBACKSPEED 10*15//*2 = bna added
+#define YZHORIZONSPEED 4*5//*2 = bna added
+#define HORIZONYZOFFSET (FINEANGLES/4)
+#define SetPlayerHorizon(ps,hlevel)    \
+    {                                  \
+    if ((hlevel)>YZANGLELIMIT)           \
+       (ps)->horizon=HORIZONYZOFFSET+YZANGLELIMIT;\
+    else if ((hlevel)<-YZANGLELIMIT)     \
+       (ps)->horizon=HORIZONYZOFFSET-YZANGLELIMIT;\
+    else                                  \
+       (ps)->horizon=HORIZONYZOFFSET+(hlevel);\
+	 }
+
+#define StartWeaponChange \
+{\
+ SD_PlaySoundRTP(SD_SELECTWPNSND,ob->x,ob->y);\
+ pstate->weapondowntics = WEAPONS[pstate->weapon].screenheight/GMOVE;\
+ if ((ob==player) && SHOW_BOTTOM_STATUS_BAR() )\
+	 DrawBarAmmo (false);            \
+}
+
+
+#define BULLETHOLEOFFSET 0x700
+
+#define M_DIST(x1,x2,y1,y2)   (((x1-x2)*(x1-x2))+((y1-y2)*(y1-y2)))
+
+#define W_CHANGE(x)   ((x->weapondowntics) || (x->weaponuptics))
+#define NOMOM         ((!ob->momentumx) && (!ob->momentumy))
+#define DISTOK(p1,p2,d)    (abs((p1)-(p2)) <= d)
+#define Fix(a)        (a &= (FINEANGLES-1))
+#define REMOTEPKTSIZE    (sizeof(MoveType))
+#define BJRUNSPEED   2048
+#define BJJUMPSPEED  680
+#define PROJECTILESIZE 0xc000l
+
+#define MOVESCALE       150l
+#define BACKMOVESCALE   100l
+#define EXTRAPOINTS     40000
+#define JETPACKTHRUST (64)
+
+#define RUNMOVE      0xa00
+#define BASEMOVE     0x600
+#define ANGLEMOVE    0x100000
+
+#define SGN(x)                 (x>0 ? 1 : -1)
+#define NETMOM    (BASEMOVE+0x10000)
+
+#define DISTANCE(x1,x2,y1,y2)   (FixedMulShift((x1-x2),(x1-x2),16)+FixedMulShift((y1-y2),(y1-y2),16))
+
+#define TILTLIMIT     95
+#define PLAYERSTEPTIME 0xf000
+
+#define HITWALLSPEED  0x2800
+#define GODVIEWANGLE  FINEANGLES/150
+#define GODOFFSET     10
+#define DOGOFFSET     46
+#define KESTICS       70
+#define BBTIME        105
+
+#define KEYBOARDNORMALTURNAMOUNT (0x160000)
+//#define KEYBOARDPREAMBLETURNAMOUNT (0xe0000)
+#define KEYBOARDPREAMBLETURNAMOUNT (0xa0000)
+#define TURBOTURNTIME      (5)
+#define TURBOTURNAMOUNT    (0x1e000)
+#define TURNAROUNDSPEED   ((ANG180<<16)/15)
+
+#define VR_INPUT_SERVICE (0x30)
+#define VR_FEEDBACK_SERVICE (0x31)
+
+#define VR_RUNBUTTON         (0)
+#define VR_STRAFELEFTBUTTON  (1)
+#define VR_STRAFERIGHTBUTTON (2)
+#define VR_ATTACKBUTTON      (3)
+#define VR_LOOKUPBUTTON      (4)
+#define VR_LOOKDOWNBUTTON    (5)
+#define VR_SWAPWEAPONBUTTON  (6)
+#define VR_USEBUTTON         (7)
+#define VR_HORIZONUPBUTTON   (8)
+#define VR_HORIZONDOWNBUTTON (9)
+#define VR_MAPBUTTON         (10)
+#define VR_PISTOLBUTTON      (11)
+#define VR_DUALPISTOLBUTTON  (12)
+#define VR_MP40BUTTON        (13)
+#define VR_MISSILEWEAPONBUTTON (14)
+#define VR_RECORDBUTTON      (15)
+
+#define STEPADJUST 3
+void BatAttack(objtype*ob);
+void  T_DogLick (objtype *ob);
+#endif
--- /dev/null
+++ b/rott/_rt_rand.h
@@ -1,0 +1,291 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+#ifndef _rt_rand_private
+#define _rt_rand_private
+
+//****************************************************************************
+//
+// Private header for RT_RAND.C
+//
+//****************************************************************************
+
+#define SIZE_OF_RANDOM_TABLE   2048
+
+static const unsigned char RandomTable[ SIZE_OF_RANDOM_TABLE ] =
+{
+    107,   65,  179,   81,  212,    1,   34,  230,
+    167,  142,   82,   27,   62,   88,  140,  119,
+    222,  252,  254,  160,   26,   33,   30,  234,
+    162,  216,  126,   42,   20,  108,  245,  150,
+    167,  145,  215,  226,  153,  184,  251,  141,
+    116,  225,  201,  114,  111,   92,  223,  185,
+    199,  160,  244,  190,  113,   77,  217,  239,
+    15,  239,  129,  243,   21,  242,  202,  183,
+    49,  151,   38,   38,  147,  179,  234,  130,
+    138,  110,  228,  118,   93,   81,  253,   98,
+    246,   44,   75,  161,  189,   86,   85,  204,
+    169,   95,  199,  178,  186,  123,  200,  250,
+    118,  242,   86,   48,    7,  205,   71,  132,
+    185,  214,  192,   68,  191,  236,  175,  197,
+    199,  177,  163,   57,  220,  139,  133,  182,
+    91,  196,  246,   29,  177,   82,  184,  226,
+    209,  151,  206,  250,  195,  119,  193,  235,
+    144,  146,   58,   61,  245,   83,  204,  214,
+    249,  164,  212,  172,   90,  199,  242,  182,
+    228,  159,  127,   37,  209,  165,   89,  122,
+    87,  254,  222,   43,  148,  205,  155,  230,
+    74,  127,  238,  181,  154,  170,  232,   47,
+    105,   31,   96,  166,  208,    5,  201,   73,
+    244,   67,   55,  168,   84,  221,  251,   85,
+    44,  198,    8,   35,  229,  122,  229,   80,
+    137,   28,  202,  135,  211,   69,  100,  250,
+    224,  156,   75,  128,  176,   53,  207,  157,
+    241,  216,  210,  124,  163,  248,  223,  174,
+    241,  235,   97,  120,   25,    3,  218,  102,
+    143,  187,  202,  116,  209,  253,  227,  151,
+    203,  254,  223,   65,  146,  255,  231,  237,
+    162,  187,  194,   90,  198,   81,  219,   94,
+    70,  158,  106,  175,   81,  239,  181,   79,
+    62,  184,   21,   30,   98,  245,  233,    8,
+    57,   54,  133,   95,   43,  125,  161,  109,
+    167,  130,   32,   46,   72,    3,   42,   34,
+    147,  139,   19,  122,   49,   23,  253,  192,
+    231,  116,  165,    8,   15,   16,  223,  140,
+    29,  136,    2,  114,  248,  219,  214,  168,
+    36,  241,  210,   63,  230,   42,  197,  100,
+    134,  159,  179,  149,   17,   96,  152,   45,
+    93,  151,   26,  202,   35,   58,  189,  220,
+    74,  173,  250,   76,   57,   52,   55,   14,
+    205,   80,  213,  190,   14,  108,   60,   89,
+    236,   41,   53,   59,  249,  237,   88,  217,
+    129,  252,  169,  123,   87,   23,   91,   79,
+    36,  164,   89,   24,  102,  111,  104,  115,
+    116,  221,  212,   82,  166,   16,  244,   18,
+    68,   73,   64,  194,   82,  115,  121,  216,
+    133,   47,   85,  124,  242,  144,    1,   65,
+    0,   75,   91,   83,  137,  183,  132,   15,
+    66,  227,   67,   98,  186,  100,  208,  150,
+    74,   61,   69,  130,  120,   56,   39,   21,
+    44,  166,  180,  145,   97,  101,   68,   19,
+    243,  162,  222,  228,    9,  160,  185,   10,
+    168,   64,  109,  198,  113,   75,   48,   52,
+    119,  163,  176,  201,   12,  246,   20,   92,
+    31,  175,   33,    4,   70,  169,  218,   86,
+    240,  127,    7,   38,  102,   94,  112,   90,
+    114,   63,  139,  119,   45,    5,  183,  224,
+    155,   13,  141,   90,   93,  177,  118,   67,
+    211,  117,   58,  158,  135,   83,  236,  194,
+    72,   59,  131,   40,  196,  232,  247,  132,
+    18,   73,   37,  207,   50,  187,   32,  174,
+    13,   34,  135,   39,   46,  192,   51,  203,
+    216,    3,  188,   99,  245,  112,   61,  206,
+    127,  118,  136,  186,  153,  148,  140,  106,
+    55,  201,   19,    9,   27,   97,   84,   24,
+    48,  227,  108,  202,    5,  190,    6,  235,
+    160,  146,  123,  222,  212,  147,   27,   28,
+    50,  226,  200,  221,  180,  244,   34,  146,
+    41,  104,   37,  217,   10,  238,   52,  198,
+    4,   29,  126,   16,   45,  124,   64,   25,
+    40,   20,  138,  225,   71,  247,  128,   62,
+    62,  178,   31,  251,  197,  215,  226,  193,
+    28,   25,   82,   15,   21,   43,   30,   86,
+    50,   99,  199,  191,   80,  171,  250,    4,
+    149,   61,  163,  128,  143,   95,   76,   56,
+    14,  109,   54,   84,  137,   43,   77,  255,
+    204,  151,  129,    8,   20,   26,  193,   38,
+    205,  125,  203,   22,   78,   47,  101,   37,
+    121,  113,  141,   36,   33,   23,  131,   55,
+    78,   96,  123,  228,   69,  213,   51,  147,
+    195,  195,   85,   54,  225,   65,  143,   13,
+    152,   60,  110,   29,  146,  179,  164,   17,
+    96,   67,  156,    7,    3,   92,   26,  104,
+    157,  220,  211,  154,  103,    2,  174,  136,
+    83,  229,   18,  116,   66,   87,    0,   74,
+    98,   58,   75,  162,  254,  177,   89,  173,
+    169,  107,   12,   90,   71,  193,   53,  255,
+    138,    2,  233,  163,   11,  138,  183,  209,
+    119,  210,  249,  112,  113,   30,  185,  180,
+    11,  171,  164,   77,    5,   99,   35,  218,
+    11,  159,  221,  148,  170,  137,  129,  188,
+    231,  172,  191,  135,  176,   33,  189,   68,
+    190,  152,    7,  220,  246,  203,  181,   63,
+    199,   91,  251,  208,  217,   39,  170,  111,
+    182,  209,  216,  247,  240,  165,  153,  118,
+    238,  233,  204,   12,  126,  105,  168,  234,
+    38,  184,  132,  110,  145,  227,  165,   92,
+    241,   24,  251,  231,  213,  126,  240,  214,
+    31,   11,  223,   46,    0,   35,  218,  242,
+    211,  191,   48,  110,  253,   94,  161,  139,
+    42,  148,  198,  246,  239,  107,   57,    5,
+    117,  252,    9,   12,   73,   77,   58,  167,
+    6,  142,   32,   34,   72,   31,  243,  170,
+    0,   93,  182,   56,  254,  158,  250,   23,
+    77,   81,   45,   69,  142,  237,  225,   44,
+    232,  142,  209,  115,   61,   38,  224,   70,
+    53,   82,   10,  229,  214,  224,  101,   42,
+    100,  121,  133,   85,   67,  150,  116,   91,
+    79,   79,  235,   22,    1,  244,   16,  101,
+    88,   25,   43,  242,   53,  106,  128,   40,
+    18,    2,  196,   22,   47,   96,  130,  249,
+    49,  117,  178,  171,  132,  189,   95,   66,
+    153,  200,   71,   71,  215,  113,  102,  131,
+    172,  235,  192,  204,  107,  127,   60,   52,
+    254,   84,   20,   27,  107,   44,   72,  149,
+    230,   87,   64,  144,  140,  186,  154,   49,
+    76,  156,  162,  219,    9,  146,   41,   80,
+    59,  142,  147,  184,  115,  158,  103,  140,
+    8,  234,  157,   17,  112,   22,  163,  187,
+    47,  178,  207,   63,  125,  202,  156,   30,
+    97,  193,  171,  173,  204,   28,    4,  195,
+    109,  211,  105,  103,  179,  221,  203,  138,
+    139,  172,   14,   44,  119,  150,  185,  180,
+    205,  255,  152,   94,  205,  173,   40,  134,
+    13,   65,  194,  196,   68,  124,   26,  134,
+    85,  228,   50,  216,  159,  254,  237,  206,
+    103,   69,   90,  187,  182,  183,    2,  114,
+    3,  201,    1,  129,  212,  232,   81,   33,
+    56,  182,  133,  176,   19,    6,  144,   84,
+    145,   24,  243,  234,   35,   25,   89,  150,
+    54,  143,  207,  104,  248,  102,   41,  253,
+    46,   44,  197,  208,  200,   52,  219,  238,
+    223,  241,   60,  230,  196,   42,   88,   51,
+    170,   25,   40,  114,   39,   45,   57,   29,
+    186,   54,   36,  167,   51,  249,  194,  108,
+    250,  199,   67,  212,  123,  151,   92,   32,
+    46,   12,  248,  165,  223,   24,  143,  189,
+    120,   57,   38,  222,  169,   17,  188,   27,
+    209,  176,  215,  108,  177,   96,   50,  154,
+    41,   15,   32,  181,   99,  120,   73,  225,
+    49,  200,   43,  177,   72,  202,   97,   92,
+    240,  110,  252,   21,   28,  192,   70,  128,
+    85,   60,  127,   63,  235,  100,  155,   65,
+    241,  119,   34,   80,   75,  117,  148,  102,
+    15,   90,  121,  206,  104,  164,  132,   98,
+    36,  108,  214,    0,   84,   94,  107,  154,
+    14,   26,   23,   93,  195,  224,  162,  171,
+    245,   76,  125,  158,  120,   66,   80,  130,
+    183,  120,  179,  118,   31,  176,  106,  184,
+    164,  111,   59,  253,  118,   62,  114,  215,
+    156,  161,  127,  210,  112,  122,  204,   86,
+    29,   69,  187,  218,  233,   47,  188,   91,
+    105,  153,  236,  116,  135,   19,   83,  175,
+    88,  166,  156,  238,  245,  227,  248,  161,
+    10,  180,   22,  230,  157,  205,    6,   37,
+    3,  234,  155,   49,  239,  229,  122,  223,
+    234,  206,   82,  135,  190,   77,  130,  197,
+    144,  226,  123,  181,  143,  208,  169,    8,
+    1,  174,   97,  177,  232,  201,  210,  193,
+    192,   62,  211,   28,  252,   19,  189,  229,
+    191,  246,    7,  202,   35,   20,   28,   30,
+    70,  221,   55,  159,  237,   10,   15,  134,
+    124,  103,   73,  172,   26,  201,   13,  117,
+    35,  131,  136,   66,   33,  245,  159,  207,
+    225,  147,   18,  248,  126,  131,   33,  153,
+    101,   60,  186,  216,  250,   11,   30,   50,
+    57,   58,  151,  178,  181,  227,  128,  253,
+    10,    5,  224,   48,  160,   34,    7,  111,
+    124,   27,  160,   75,  137,   17,   53,   39,
+    243,  236,   39,   81,  217,  122,   79,   32,
+    13,  115,  191,  167,  137,   87,  228,   91,
+    86,   78,   18,   22,   40,   76,   94,  129,
+    119,   87,   63,  197,  203,   21,  218,  185,
+    166,   49,  161,  213,   38,  111,  209,  154,
+    43,  152,  134,  132,    4,  133,  108,   83,
+    145,   41,   97,   74,  251,  173,   42,  213,
+    46,  118,   73,   68,   21,  244,  106,  158,
+    11,   90,  252,  140,   44,  157,  194,   66,
+    229,   58,  215,  251,  144,  125,  146,  172,
+    165,  136,  105,  102,  173,   95,  150,  169,
+    78,  230,  111,  160,  196,  112,  120,  231,
+    168,  152,  149,  174,  128,  232,  194,  122,
+    3,   74,  231,  105,   12,  239,  180,  239,
+    89,  235,   95,  157,  149,  187,    6,  203,
+    188,   71,  110,    8,  126,  242,  188,  249,
+    71,  123,  162,   93,   59,   65,   16,  222,
+    192,   24,   27,  142,  168,  114,   89,  220,
+    226,  182,  207,   94,  195,  207,  174,  228,
+    142,  130,  115,  175,  154,  106,  206,   48,
+    185,  147,  155,  224,  239,   64,   88,   83,
+    54,  247,  113,  248,  137,   96,    5,  110,
+    240,   51,    1,  208,  166,  200,  233,  167,
+    230,   14,   20,  198,   36,   13,    0,  220,
+    165,  104,   85,  122,    1,  255,  212,  161,
+    190,   37,   86,  226,  195,  105,   78,  244,
+    236,  168,   48,  211,  121,  216,   25,  144,
+    16,  237,    7,   75,   12,   99,   56,  109,
+    218,   87,   35,  204,  155,   61,  191,   41,
+    61,   57,  121,  236,   62,   22,  187,   95,
+    92,   69,  210,  163,  205,  214,   34,   84,
+    73,  184,  109,  124,  231,  103,  217,  241,
+    77,  175,  183,  232,  198,  164,   14,  125,
+    103,  197,  249,  241,  176,   59,   48,   50,
+    25,  222,  134,  199,  252,  196,   23,   19,
+    78,    0,   59,  120,   91,  121,  117,  228,
+    52,   68,  113,  127,  141,   67,   65,  130,
+    132,  243,  160,  138,  138,  116,   10,   98,
+    170,   70,  246,  206,  219,   28,   94,  226,
+    29,   58,  255,   31,  141,   82,  134,  152,
+    251,   84,   52,   23,  154,  139,   74,   55,
+    47,  198,  167,  162,    4,   16,  220,   53,
+    37,  158,  135,  136,  190,   86,  151,  178,
+    238,  161,   88,  171,  148,  169,  137,  212,
+    181,  146,  189,   70,   49,   79,  142,  131,
+    195,  126,  149,  156,   93,   55,  164,  174,
+    87,  243,   66,   92,  207,    9,  126,  123,
+    40,   51,  133,  143,    9,   55,  193,  173,
+    56,   64,  210,  159,    6,  178,  145,  153,
+    115,  215,  185,  238,  101,  210,   98,  157,
+    95,  171,  235,  217,  240,  232,  107,   53,
+    54,  211,  111,  236,  100,   37,  147,   64,
+    60,  215,  174,  136,  128,   98,   79,  234,
+    145,   76,  197,  165,  191,  141,  114,  109,
+    148,  214,   93,   12,  163,  125,  222,   96,
+    71,  220,    8,  225,  200,   14,  139,  166,
+    155,    9,  237,    9,  172,    6,  229,  179,
+    247,   76,   24,  213,   26,  248,   56,  247,
+    106,  221,   63,   20,  206,  231,  168,  196,
+    208,   36,   31,  175,  178,  255,  124,  156,
+    129,  186,   45,  201,    7,  112,  189,   68,
+    225,   64,  150,   74,    2,  218,   62,  159,
+    4,   11,  213,   40,   23,   15,   67,   52,
+    182,  203,  246,  194,   72,   33,   89,  104,
+    16,  131,   60,  150,  243,   21,   59,  175,
+    219,  149,   56,  224,   32,  105,  153,   99,
+    80,  148,  107,   99,  108,   43,  106,   41,
+    32,  244,    4,  186,  253,   27,  233,  104,
+    245,    5,    2,  252,  170,    2,  101,   39,
+    17,  166,  221,   11,  227,  129,  103,   45,
+    144,   79,   17,  139,   70,  237,  176,    6,
+    76,  134,   54,   30,   69,   13,  100,  149,
+    141,  227,  255,   22,  179,   61,   88,   97,
+    121,   29,   24,   77,  170,  190,  242,  109,
+    152,   47,   81,  140,   45,   46,  249,   78,
+    180,  143,  102,   19,  208,  177,   72,   72,
+    247,   51,  115,    3,  141,  117,   39,  188,
+    180,  171,   83,    1,    0,   51,  100,  112,
+    172,   18,  219,  136,  155,  125,  200,  131,
+    157,  217,   78,   63,  213,  238,  193,  173,
+    145,   46,  101,  158,   42,  140,  110,   66,
+    183,  181,  233,  188,   10,  133,   36,  135,
+    17,  254,  138,  233,  117,  240,  184,   80,
+    113,   18,   99,  219,  240,   50,  192,  247
+};
+
+#endif
--- /dev/null
+++ b/rott/_rt_scal.h
@@ -1,0 +1,25 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+#ifndef _rt_scale_private
+#define _rt_scale_private
+
+#define PLAYERHEIGHT (260<<HEIGHTFRACTION)
+
+#endif
--- /dev/null
+++ b/rott/_rt_soun.h
@@ -1,0 +1,114 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+#ifndef _rt_sound_private
+#define _rt_sound_private
+
+#define SOUNDTYPES 2
+
+typedef struct
+{
+    int     snds[SOUNDTYPES];
+    byte    flags;
+    byte    priority;
+    byte    count;
+    int     prevhandle;
+    int     prevdistance;
+} sound_t;
+
+#define SD_OVERWRITE  0x01
+#define SD_WRITE      0x02
+#define SD_LOOP       0x04
+#define SD_PITCHSHIFTOFF 0x08
+#define SD_PLAYONCE      0x10
+
+enum {
+    sd_prio0=17,
+    sd_prio1=16,
+    sd_prio2=15,
+    sd_prio3=14,
+    sd_prio4=13,
+    sd_prio5=12,
+    sd_prio6=11,
+    sd_prio7=10,
+    sd_prio8=9,
+    sd_prio9=8,
+    sd_prio10=7,
+    sd_prio11=6,
+    sd_prio12=5,
+    sd_prio13=4,
+    sd_prio14=3,
+    sd_prio15=2,
+    sd_prio16=1
+} ;
+
+#define SD_PRIOSECRET sd_prio1
+#define SD_PRIOREMOTE sd_prio1
+#define SD_PRIOPHURT  sd_prio1
+#define SD_PRIOGAME   sd_prio2
+#define SD_PRIOBOSS   sd_prio2
+#define SD_PRIOGODDOG sd_prio2
+#define SD_PRIOEXPL   sd_prio3
+#define SD_PRIOASNEAK sd_prio3
+#define SD_PRIOADEATH sd_prio3
+#define SD_PRIOPMISS  sd_prio4
+#define SD_PRIOPGUNS  sd_prio5
+#define SD_PRIOAFIRE  sd_prio6
+#define SD_PRIOPMP40  sd_prio7
+#define SD_PRIOAHURT  sd_prio8
+#define SD_PRIOGLASS  sd_prio9
+#define SD_PRIOPSNDS  sd_prio11
+#define SD_PRIOPCAUSD sd_prio12
+#define SD_PRIOAGREET sd_prio13
+#define SD_PRIOENVRON sd_prio14
+#define SD_PRIOQUIT   sd_prio15
+#define SD_PRIOMENU   sd_prio16
+
+#define SD_DISTANCESHIFT 12
+
+#define USEADLIB 255
+
+#define SD_RANDOMSHIFT 1
+
+#define PitchOffset()  ((RandomNumber("Pitch Offset",0)-128)>>SD_RANDOMSHIFT)
+
+#define SoundOffset(x) (sounds[x].snds[soundtype])
+
+#define GUSMIDIINIFILE ("gusmidi.ini")
+
+
+typedef enum {
+    loop_yes,
+    loop_no
+} looptypes;
+
+
+typedef struct
+{
+    byte    loopflag;
+    byte    songtype;
+    char    lumpname[9];
+    char    songname[40];
+} song_t;
+
+int SD_PlayIt ( int sndnum, int angle, int distance, int pitch );
+boolean SD_SoundOkay ( int sndnum );
+
+#endif
+
--- /dev/null
+++ b/rott/_rt_spba.h
@@ -1,0 +1,27 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+#ifndef _rt_spba_private
+#define _rt_spba_private
+
+#define SGN(x)                 (x>0 ? 1 : -1)
+
+#define NUMSPACEBALLBUTTONS 6
+
+#endif
--- /dev/null
+++ b/rott/_rt_stat.h
@@ -1,0 +1,58 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+#ifndef _rt_stat_private
+#define _rt_stat_private
+
+void        AddStatic(statobj_t*);
+void        AddAnimStatic(statobj_t*);
+void        PreCacheStaticSounds(int);
+
+#define SOLIDCOLORTICTIME   1
+#define SOLIDCOLORINCREMENT 1
+#define MAXFIRECOLOR      248
+#define INITIALFIRECOLOR  246
+#define IsLight(x,y)          ( (x>=0) && (x<=127) && (y>=0) && (y<=127) &&   \
+										  (sprites[x][y]) && (sprites[x][y]->flags & FL_LIGHT) )
+
+typedef struct
+{
+    int  tictime,
+         numanims;
+    char firstlump[9];
+} awallinfo_t;
+
+
+typedef struct sas
+{
+    int          x,y,z;
+    int          flags;
+    signed char  ticcount;
+    int          hitpoints;
+    short int    shapenum;
+    signed char  ammo;
+    signed char  count;
+    signed char  itemnumber;
+    short int    areanumber;
+    short int    whichstat;
+    byte         numanims;
+    int          linked_to;
+} saved_stat_type;
+
+#endif
--- /dev/null
+++ b/rott/_rt_str.h
@@ -1,0 +1,44 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+//******************************************************************************
+//
+// Private header for RT_STR.C
+//
+//******************************************************************************
+
+#ifndef _rt_str_private
+#define _rt_str_private
+
+//******************************************************************************
+//
+// PROTOTYPES
+//
+//******************************************************************************
+
+void VWB_DrawPropString  (const char *string);
+void VW_MeasurePropString (const char *string, int *width, int *height );
+
+//void (*USL_MeasureString)(const char *, int *, int *, font_t *) = VW_MeasurePropString,
+//     (*USL_DrawString)(const char *) = VWB_DrawPropString;
+void (*USL_MeasureString)(const char *, int *, int *, font_t *) = (void (*)(const char *, int *, int *, font_t *))VW_MeasurePropString,
+(*USL_DrawString)(const char *) = VWB_DrawPropString;
+
+
+#endif
--- /dev/null
+++ b/rott/_rt_swft.h
@@ -1,0 +1,109 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+#ifndef _rt_swift_private
+#define _rt_swift_private
+
+#ifdef DOS
+//****************************************************************************
+//
+// Private header for RT_SWIFT.C.
+//
+//****************************************************************************
+
+
+
+//****************************************************************************
+//
+// DEFINES
+//
+//****************************************************************************
+
+#define DPMI_INT     0x31
+#define MOUSE_INT    0x33
+#define DOSMEMSIZE   64                // enough for any SWIFT structure
+
+//
+// device type codes, returned in deviceType field (SWIFT_StaticData)
+//
+#define SWIFT_DEV_NONE		0
+#define SWIFT_DEV_CYBERMAN	1
+
+//
+// Dynamic device data
+//
+#define SDD_EXTERNAL_POWER_CONNECTED	1
+#define SDD_EXTERNAL_POWER_TOO_HIGH	   2
+
+#define AX(r) ((r).x.eax)
+#define BX(r) ((r).x.ebx)
+#define CX(r) ((r).x.ecx)
+#define DX(r) ((r).x.edx)
+#define SI(r) ((r).x.esi)
+#define DI(r) ((r).x.edi)
+
+
+//****************************************************************************
+//
+// TYPEDEFS
+//
+//****************************************************************************
+
+// Active flag:
+static int fActive;                       //  TRUE after successful init
+//  and before termination
+static int nAttached = SWIFT_DEV_NONE;    // type of SWIFT device
+
+union REGS regs;
+struct SREGS sregs;
+
+short selector;                           // selector of DOS memory block
+short segment;                            // segment of DOS memory block
+void far *pdosmem;                        // pointer to DOS memory block
+
+// DPMI real mode interrupt structure
+static struct rminfo
+{
+    long di;
+    long si;
+    long bp;
+    long reserved_by_system;
+    long bx;
+    long dx;
+    long cx;
+    long ax;
+    short flags;
+    short es, ds, fs, gs, ip, cs, sp, ss;
+} RMI;
+
+
+//****************************************************************************
+//
+// PROTOTYPES
+//
+//****************************************************************************
+
+void MouseInt (struct rminfo *prmi);
+static void far *allocDOS (unsigned nbytes, short *pseg, short *psel);
+static void freeDOS (short sel);
+
+#endif
+
+#endif
+
--- /dev/null
+++ b/rott/_rt_ted.h
@@ -1,0 +1,90 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+#ifndef _rt_ted_private
+#define _rt_ted_private
+
+#define  MAXPRECACHE    3500
+
+#include "rt_actor.h"
+#include "develop.h"
+
+#define SHAREWARE_TAG     0x4d4b
+#define REGISTERED_TAG    0x4344
+#define RTL_VERSION       ( 0x0101 )
+#define COMMBAT_SIGNATURE ( "RTC" )
+#define NORMAL_SIGNATURE  ( "RTL" )
+#define RTL_HEADER_OFFSET 8
+
+typedef struct
+{
+    int  lump;
+    int  cachelevel;
+    int  type; // To make precaching possible on big endian machines
+} cachetype;
+
+//========================================
+
+typedef struct
+{
+    short   RLEWtag;
+    int             headeroffsets[100];
+    byte            tileinfo[1];
+} mapfiletype;
+
+
+typedef struct
+{
+    int   planestart[3];
+    word  planelength[3];
+    word  width,height;
+    char            name[16];
+} maptype;
+
+#define ActorIsPushWall(xx,yy)   ((actorat[xx][yy])&&(((objtype *)actorat[xx][yy])->which==PWALL) )
+#define ActorIsWall(xx,yy)   ((actorat[xx][yy])&&(((objtype *)actorat[xx][yy])->which==WALL) )
+#define ActorIsSpring(xx,yy)   ((actorat[xx][yy])&&(((objtype *)actorat[xx][yy])->obclass==springobj) )
+#define StaticUndefined(xx,yy)   ((sprites[xx][yy])&&(((statobj_t *)sprites[xx][yy])->z<-64) )
+
+#define  PRECACHEASTRINGX 141
+#define  PRECACHEASTRINGY 8
+
+#define  PRECACHEESTRINGX 16
+#define  PRECACHEESTRINGY 8
+
+#define  PRECACHESTRINGX 16
+#define  PRECACHESTRINGY 144
+
+#define  PRECACHEBARX 28
+#define  PRECACHEBARY 178
+
+#define  PRECACHELED1X 9
+#define  PRECACHELED1Y 8
+
+#define  PRECACHELED2X 9
+#define  PRECACHELED2Y 12
+
+#define  MAXLEDS 57
+
+#define  MAXSILLYSTRINGS 32
+
+
+
+
+#endif
--- /dev/null
+++ b/rott/_rt_util.h
@@ -1,0 +1,47 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+#ifndef _rt_util_private
+#define _rt_util_private
+
+#ifdef DOS
+#define PEL_WRITE_ADR   0x3c8
+#define PEL_READ_ADR    0x3c7
+#define PEL_DATA        0x3c9
+#define PEL_MASK        0x3c6
+#endif
+
+#define ERRORROW        2
+#define ERRORCOL        11
+
+#define ERRORFILE       ("rotterr.txt")
+#define SOFTERRORFILE   ("error.txt")
+#define DEBUGFILE       ("rott.dbg")
+#define MAPDEBUGFILE    ("mapinfo.txt")
+
+#define SGN(x)          ((x>0) ? (1) : ((x==0) ? (0) : (-1)))
+
+#define SLASHES         ('\\')
+#define MAXCHARS        8
+
+#define WeightR  3
+#define WeightG  5
+#define WeightB  2
+
+#endif
--- /dev/null
+++ b/rott/_rt_vid.h
@@ -1,0 +1,45 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+#ifndef _rt_vid_private
+#define _rt_vid_private
+
+//******************************************************************************
+//
+// Private header for RT_VID.C
+//
+//******************************************************************************
+
+
+//******************************************************************************
+//
+// DEFINES
+//
+//******************************************************************************
+
+#define PIXTOBLOCK         4
+
+#define VW_Hlin(x,z,y,c)   VL_Hlin(x,y,(z)-(x)+1,c)
+#define VW_Vlin(y,z,x,c)   VL_Vlin(x,y,(z)-(y)+1,c)
+
+#define VW_THlin(x,z,y,up)    VL_THlin(x,y,(z)-(x)+1, up)
+#define VW_TVlin(y,z,x,up)    VL_TVlin(x,y,(z)-(y)+1, up)
+
+
+#endif
--- /dev/null
+++ b/rott/_w_wad.h
@@ -1,0 +1,76 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+#ifndef _w_wad_private
+#define _w_wad_private
+
+#include "develop.h"
+
+#define CHECKPERIOD 20
+
+
+#if ( SHAREWARE == 1 )
+
+#if ( DELUXE == 1)
+#define WADCHECKSUM (54748)
+#elif ( LOWCOST == 1)
+#define WADCHECKSUM (12185)
+#else
+#ifdef DOS
+#define WADCHECKSUM (45677)
+#else
+#define WADCHECKSUM (20567)
+#endif
+#endif
+
+#else
+
+#define WADCHECKSUM (24222)
+
+#endif
+
+//===============
+//   TYPES
+//===============
+
+
+typedef struct
+{
+    char            name[8];
+    int             handle,position,size;
+    int             byteswapped;
+} lumpinfo_t;
+
+
+typedef struct
+{
+    char            identification[4];              // should be IWAD
+    int             numlumps;
+    int             infotableofs;
+} wadinfo_t;
+
+
+typedef struct
+{
+    int             filepos;
+    int             size;
+    char            name[8];
+} filelump_t;
+
+#endif
--- /dev/null
+++ b/rott/_z_zone.h
@@ -1,0 +1,57 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+#ifndef _z_zone_private
+#define _z_zone_private
+
+#include "develop.h"
+
+#define MINFRAGMENT     64
+#define DPMI_INT  0x31
+#define MAXMEMORYSIZE   9000000
+
+#define LEVELZONESIZE   250000
+
+// memory storage data types
+
+#define MEMORYPRETAG   (0x1a2b3c4d)
+#define MEMORYPOSTTAG  (0x9f8e7d6b)
+
+typedef struct memblock_s
+{
+#if (MEMORYCORRUPTIONTEST==1)
+    int     pretag;
+#endif
+    int     size;   // including the header and possibly tiny fragments
+    void    **user; // NULL if a free block
+    int     tag;    // purgelevel
+    struct memblock_s   *next, *prev;
+#if (MEMORYCORRUPTIONTEST==1)
+    int     posttag;
+#endif
+} memblock_t;
+
+typedef struct
+{
+    int     size;          // total bytes malloced, including header
+    memblock_t  blocklist; // start / end cap for linked list
+    memblock_t  *rover;
+} memzone_t;
+
+#endif
--- /dev/null
+++ b/rott/audiolib/Makefile
@@ -1,0 +1,31 @@
+AUDIOLIB ?= audiolib.a
+
+AR ?= ar
+CC ?= gcc
+RANLIB ?= ranlib
+
+ARFLAGS ?= rcT
+
+CFLAGS ?= -g -O2
+CFLAGS += -Wall
+CFLAGS += $(shell sdl-config --cflags)
+
+OBJS :=
+OBJS += fx_man.o
+OBJS += dsl.o
+OBJS += ll_man.o
+OBJS += multivoc.o
+OBJS += mv_mix.o
+OBJS += mvreverb.o
+OBJS += nodpmi.o
+OBJS += pitch.o
+OBJS += user.o
+OBJS += usrhooks.o
+
+$(AUDIOLIB): $(OBJS)
+	$(RM) $@
+	$(AR) $(ARFLAGS) $@ $^
+	$(RANLIB) $@
+
+clean:
+	$(RM) $(AUDIOLIB) $(OBJS)
--- /dev/null
+++ b/rott/audiolib/Makefile.am
@@ -1,0 +1,13 @@
+noinst_LIBRARIES = libaudiolib.a
+libaudiolib_a_SOURCES = \
+	dsl.c \
+	fx_man.c \
+	ll_man.c \
+	multivoc.c \
+	mv_mix.c \
+	mvreverb.c \
+	nodpmi.c \
+	pitch.c \
+	user.c \
+	usrhooks.c
+libaudiolib_a_CFLAGS = @SDL_CFLAGS@
--- /dev/null
+++ b/rott/audiolib/Makefile_old
@@ -1,0 +1,30 @@
+AUDIOLIB ?= audiolib.a
+
+AR ?= ar
+CC ?= gcc
+RANLIB ?= ranlib
+
+ARFLAGS ?= rcT
+CFLAGS ?= -g -O2
+CFLAGS += -Wall
+CFLAGS += $(shell sdl-config --cflags)
+
+OBJS :=
+OBJS += fx_man.o
+OBJS += dsl.o
+OBJS += ll_man.o
+OBJS += multivoc.o
+OBJS += mv_mix.o
+OBJS += mvreverb.o
+OBJS += nodpmi.o
+OBJS += pitch.o
+OBJS += user.o
+OBJS += usrhooks.o
+
+$(AUDIOLIB): $(OBJS)
+	$(RM) $@
+	$(AR) $(ARFLAGS) $@ $^
+	$(RANLIB) $@
+
+clean:
+	$(RM) $(AUDIOLIB) $(OBJS)
--- /dev/null
+++ b/rott/audiolib/_al_midi.h
@@ -1,0 +1,174 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+#ifndef ___AL_MIDI_H
+#define ___AL_MIDI_H
+
+#define NO_ADLIB_DETECTION    "NOAL"
+
+#define STEREO_DETUNE 5
+
+#define lobyte( num )   ( ( unsigned )*( ( char * )&( num ) ) )
+#define hibyte( num )   ( ( unsigned )*( ( ( char * )&( num ) ) + 1 ) )
+
+#define AL_VoiceNotFound -1
+
+#define  alFreqH     0xb0
+#define  alEffects   0xbd
+
+/* Number of slots for the voices on the chip */
+#define NumChipSlots 18
+
+#define NUM_VOICES      9
+#define NUM_CHANNELS    16
+
+#define NOTE_ON         0x2000  /* Used to turn note on or toggle note */
+#define NOTE_OFF        0x0000
+
+#define MAX_VELOCITY   0x7f
+#define MAX_OCTAVE     7
+#define MAX_NOTE       ( MAX_OCTAVE * 12 + 11 )
+#define FINETUNE_MAX   31
+#define FINETUNE_RANGE ( FINETUNE_MAX + 1 )
+
+#define PITCHBEND_CENTER 1638400
+
+#define note_off             0x80
+#define note_on              0x90
+#define poly_aftertouch      0xa0
+#define control_change       0xb0
+#define program_chng         0xc0
+#define channel_aftertouch   0xd0
+#define pitch_wheel          0xe0
+
+#define MIDI_VOLUME          7
+#define MIDI_PAN             10
+#define MIDI_DETUNE          94
+#define MIDI_ALL_NOTES_OFF   0x7B
+#define MIDI_RESET_ALL_CONTROLLERS 0x79
+#define MIDI_RPN_MSB               100
+#define MIDI_RPN_LSB               101
+#define MIDI_DATAENTRY_MSB         6
+#define MIDI_DATAENTRY_LSB         38
+#define MIDI_PITCHBEND_RPN         0
+
+enum cromatic_scale
+   {
+   C       = 0x157,
+   C_SHARP = 0x16B,
+   D_FLAT  = 0x16B,
+   D       = 0x181,
+   D_SHARP = 0x198,
+   E_FLAT  = 0x198,
+   E       = 0x1B0,
+   F_FLAT  = 0x1B0,
+   E_SHARP = 0x1CA,
+   F       = 0x1CA,
+   F_SHARP = 0x1E5,
+   G_FLAT  = 0x1E5,
+   G       = 0x202,
+   G_SHARP = 0x220,
+   A_FLAT  = 0x220,
+   A       = 0x241,
+   A_SHARP = 0x263,
+   B_FLAT  = 0x263,
+   B       = 0x287,
+   C_FLAT  = 0x287,
+   B_SHARP = 0x2AE,
+   };
+
+/* Definition of octave information to be ORed onto F-Number */
+
+enum octaves
+   {
+   OCTAVE_0 = 0x0000,
+   OCTAVE_1 = 0x0400,
+   OCTAVE_2 = 0x0800,
+   OCTAVE_3 = 0x0C00,
+   OCTAVE_4 = 0x1000,
+   OCTAVE_5 = 0x1400,
+   OCTAVE_6 = 0x1800,
+   OCTAVE_7 = 0x1C00
+   };
+
+typedef struct VOICE
+   {
+   struct VOICE *next;
+   struct VOICE *prev;
+
+   unsigned num;
+   unsigned key;
+   unsigned velocity;
+   unsigned channel;
+   unsigned pitchleft;
+   unsigned pitchright;
+   int      timbre;
+   int      port;
+   unsigned status;
+   } VOICE;
+
+typedef struct
+   {
+   VOICE *start;
+   VOICE *end;
+   } VOICELIST;
+
+typedef struct
+   {
+   VOICELIST Voices;
+   int       Timbre;
+   int       Pitchbend;
+   int       KeyOffset;
+   unsigned  KeyDetune;
+   unsigned  Volume;
+   unsigned  EffectiveVolume;
+   int       Pan;
+   int       Detune;
+   unsigned  RPN;
+   short     PitchBendRange;
+   short     PitchBendSemiTones;
+   short     PitchBendHundreds;
+   } CHANNEL;
+
+typedef struct
+   {
+   unsigned char SAVEK[ 2 ];
+   unsigned char Level[ 2 ];
+   unsigned char Env1[ 2 ];
+   unsigned char Env2[ 2 ];
+   unsigned char Wave[ 2 ];
+   unsigned char Feedback;
+   signed   char Transpose;
+   signed   char Velocity;
+   } TIMBRE;
+
+extern TIMBRE ADLIB_TimbreBank[ 256 ];
+
+static void AL_ResetVoices( void );
+static void AL_CalcPitchInfo( void );
+static void AL_SetVoiceTimbre( int voice );
+static void AL_SetVoiceVolume( int voice );
+static int  AL_AllocVoice( void );
+static int  AL_GetVoice( int channel, int key );
+static void AL_SetVoicePitch( int voice );
+static void AL_SetChannelVolume( int channel, int volume );
+static void AL_SetChannelPan( int channel, int pan );
+static void AL_SetChannelDetune( int channel, int detune );
+
+#endif
--- /dev/null
+++ b/rott/audiolib/_blaster.h
@@ -1,0 +1,133 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+/**********************************************************************
+   module: _BLASTER.H
+
+   author: James R. Dose
+   date:   February 4, 1994
+
+   Private header for for BLASTER.C
+
+   (c) Copyright 1994 James R. Dose.  All Rights Reserved.
+**********************************************************************/
+
+#ifndef ___BLASTER_H
+#define ___BLASTER_H
+
+#define VALID   ( 1 == 1 )
+#define INVALID ( !VALID )
+
+#define TRUE  ( 1 == 1 )
+#define FALSE ( !TRUE )
+
+#define YES ( 1 == 1 )
+#define NO  ( !YES )
+
+#define lobyte( num )   ( ( int )*( ( char * )&( num ) ) )
+#define hibyte( num )   ( ( int )*( ( ( char * )&( num ) ) + 1 ) )
+
+#define BLASTER_MixerAddressPort  0x04
+#define BLASTER_MixerDataPort     0x05
+#define BLASTER_ResetPort         0x06
+#define BLASTER_ReadPort          0x0A
+#define BLASTER_WritePort         0x0C
+#define BLASTER_DataAvailablePort 0x0E
+#define BLASTER_Ready             0xAA
+#define BLASTER_16BitDMAAck       0x0F
+
+#define MIXER_DSP4xxISR_Ack       0x82
+#define MIXER_DSP4xxISR_Enable    0x83
+#define MIXER_MPU401_INT          0x4
+#define MIXER_16BITDMA_INT        0x2
+#define MIXER_8BITDMA_INT         0x1
+#define MIXER_DisableMPU401Interrupts 0xB
+#define MIXER_SBProOutputSetting  0x0E
+#define MIXER_SBProStereoFlag     0x02
+#define MIXER_SBProVoice          0x04
+#define MIXER_SBProMidi           0x26
+#define MIXER_SB16VoiceLeft       0x32
+#define MIXER_SB16VoiceRight      0x33
+#define MIXER_SB16MidiLeft        0x34
+#define MIXER_SB16MidiRight       0x35
+
+#define DSP_Version1xx            0x0100
+#define DSP_Version2xx            0x0200
+#define DSP_Version201            0x0201
+#define DSP_Version3xx            0x0300
+#define DSP_Version4xx            0x0400
+#define DSP_SB16Version           DSP_Version4xx
+
+#define DSP_MaxNormalRate         22000
+#define DSP_MaxHighSpeedRate      44000
+
+#define DSP_8BitAutoInitRecord        0x2c
+#define DSP_8BitHighSpeedAutoInitRecord 0x98
+#define DSP_Old8BitADC                0x24
+#define DSP_8BitAutoInitMode          0x1c
+#define DSP_8BitHighSpeedAutoInitMode 0x90
+#define DSP_SetBlockLength            0x48
+#define DSP_Old8BitDAC                0x14
+#define DSP_16BitDAC                  0xB6
+#define DSP_8BitDAC                   0xC6
+#define DSP_8BitADC                   0xCe
+#define DSP_SetTimeConstant           0x40
+#define DSP_Set_DA_Rate               0x41
+#define DSP_Set_AD_Rate               0x42
+#define DSP_Halt8bitTransfer          0xd0
+#define DSP_Continue8bitTransfer      0xd4
+#define DSP_Halt16bitTransfer         0xd5
+#define DSP_Continue16bitTransfer     0xd6
+#define DSP_SpeakerOn                 0xd1
+#define DSP_SpeakerOff                0xd3
+#define DSP_GetVersion                0xE1
+#define DSP_Reset                     0xFFFF
+
+#define DSP_SignedBit                 0x10
+#define DSP_StereoBit                 0x20
+
+#define DSP_UnsignedMonoData      0x00
+#define DSP_SignedMonoData        ( DSP_SignedBit )
+#define DSP_UnsignedStereoData    ( DSP_StereoBit )
+#define DSP_SignedStereoData      ( DSP_SignedBit | DSP_StereoBit )
+
+#define BlasterEnv_Address    'A'
+#define BlasterEnv_Interrupt  'I'
+#define BlasterEnv_8bitDma    'D'
+#define BlasterEnv_16bitDma   'H'
+#define BlasterEnv_Type       'T'
+#define BlasterEnv_Midi       'P'
+#define BlasterEnv_EmuAddress 'E'
+
+#define CalcTimeConstant( rate, samplesize ) \
+   ( ( 65536L - ( 256000000L / ( ( samplesize ) * ( rate ) ) ) ) >> 8 )
+
+#define CalcSamplingRate( tc ) \
+   ( 256000000L / ( 65536L - ( tc << 8 ) ) )
+
+typedef struct
+   {
+   int IsSupported;
+   int HasMixer;
+   int MaxMixMode;
+   int MinSamplingRate;
+   int MaxSamplingRate;
+   } CARD_CAPABILITY;
+
+#endif
--- /dev/null
+++ b/rott/audiolib/_guswave.h
@@ -1,0 +1,164 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+/**********************************************************************
+   file:   _GUSWAVE.H
+
+   author: James R. Dose
+   date:   March 23, 1994
+
+   Private header for GUSWAVE.C
+
+   (c) Copyright 1994 James R. Dose.  All Rights Reserved.
+**********************************************************************/
+
+#ifndef ___GUSWAVE_H
+#define ___GUSWAVE_H
+
+#define TRUE  ( 1 == 1 )
+#define FALSE ( !TRUE )
+
+#define LOADDS _loadds
+
+#define VOC_8BIT            0x0
+#define VOC_CT4_ADPCM       0x1
+#define VOC_CT3_ADPCM       0x2
+#define VOC_CT2_ADPCM       0x3
+#define VOC_16BIT           0x4
+#define VOC_ALAW            0x6
+#define VOC_MULAW           0x7
+#define VOC_CREATIVE_ADPCM  0x200
+
+#define MAX_BLOCK_LENGTH 0x8000
+
+#define GF1BSIZE   896L   /* size of buffer per wav on GUS */
+//#define GF1BSIZE   512L   /* size of buffer per wav on GUS */
+
+//#define VOICES     8      /* maximum amount of concurrent wav files */
+#define VOICES     2      /* maximum amount of concurrent wav files */
+#define MAX_VOICES 32     /* This should always be 32 */
+#define MAX_VOLUME 4095
+#define BUFFER     2048U  /* size of DMA buffer for patch loading */
+
+typedef enum
+   {
+   Raw,
+   VOC,
+   DemandFeed,
+   WAV
+   } wavedata;
+
+typedef enum
+   {
+   NoMoreData,
+   KeepPlaying,
+   SoundDone
+   } playbackstatus;
+
+
+typedef volatile struct VoiceNode
+   {
+   struct VoiceNode *next;
+   struct VoiceNode *prev;
+
+   wavedata      wavetype;
+   int           bits;
+   playbackstatus ( *GetSound )( struct VoiceNode *voice );
+
+   int num;
+
+   unsigned long  mem;           /* location in ultrasound memory */
+   int            Active;        /* this instance in use */
+   int            GF1voice;      /* handle to active voice */
+
+   char          *NextBlock;
+   char          *LoopStart;
+   char          *LoopEnd;
+   unsigned       LoopCount;
+   unsigned long  LoopSize;
+   unsigned long  BlockLength;
+
+   unsigned long  PitchScale;
+
+   unsigned char *sound;
+   unsigned long  length;
+   unsigned long  SamplingRate;
+   unsigned long  RateScale;
+   int            Playing;
+
+   int    handle;
+   int    priority;
+
+   void          ( *DemandFeed )( char **ptr, unsigned long *length );
+
+   unsigned long callbackval;
+
+   int    Volume;
+   int    Pan;
+   }
+VoiceNode;
+
+typedef struct
+   {
+   VoiceNode *start;
+   VoiceNode *end;
+   }
+voicelist;
+
+typedef volatile struct voicestatus
+   {
+   VoiceNode *Voice;
+   int playing;
+   }
+voicestatus;
+
+typedef struct
+   {
+   char          RIFF[ 4 ];
+   unsigned long file_size;
+   char          WAVE[ 4 ];
+   char          fmt[ 4 ];
+   unsigned long format_size;
+   } riff_header;
+
+typedef struct
+   {
+   unsigned short wFormatTag;
+   unsigned short nChannels;
+   unsigned long  nSamplesPerSec;
+   unsigned long  nAvgBytesPerSec;
+   unsigned short nBlockAlign;
+   unsigned short nBitsPerSample;
+   } format_header;
+
+typedef struct
+   {
+   unsigned char DATA[ 4 ];
+   unsigned long size;
+   } data_header;
+
+playbackstatus GUSWAVE_GetNextVOCBlock( VoiceNode *voice );
+VoiceNode *GUSWAVE_GetVoice( int handle );
+
+int GUSWAVE_Play( VoiceNode *voice, int angle, int volume, int channels );
+
+VoiceNode *GUSWAVE_AllocVoice( int priority );
+static int GUSWAVE_InitVoices( void );
+
+#endif
--- /dev/null
+++ b/rott/audiolib/_midi.h
@@ -1,0 +1,290 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+/**********************************************************************
+   module: _MIDI.H
+
+   author: James R. Dose
+   date:   May 25, 1994
+
+   Private header for MIDI.C.  Midi song file playback routines.
+
+   (c) Copyright 1994 James R. Dose.  All Rights Reserved.
+**********************************************************************/
+
+#ifndef ___MIDI_H
+#define ___MIDI_H
+
+#define RELATIVE_BEAT( measure, beat, tick ) \
+   ( ( tick ) + ( ( beat ) << 9 ) + ( ( measure ) << 16 ) )
+
+//Bobby Prince thinks this may be 100
+//#define GENMIDI_DefaultVolume 100
+#define GENMIDI_DefaultVolume 90
+
+#define MAX_FORMAT            1
+
+#define NUM_MIDI_CHANNELS     16
+
+#define TIME_PRECISION        16
+
+#define MIDI_HEADER_SIGNATURE 0x6468544d    // "MThd"
+#define MIDI_TRACK_SIGNATURE  0x6b72544d    // "MTrk"
+
+#define MIDI_VOLUME                7
+#define MIDI_PAN                   10
+#define MIDI_DETUNE                94
+#define MIDI_RHYTHM_CHANNEL        9
+#define MIDI_RPN_MSB               100
+#define MIDI_RPN_LSB               101
+#define MIDI_DATAENTRY_MSB         6
+#define MIDI_DATAENTRY_LSB         38
+#define MIDI_PITCHBEND_MSB         0
+#define MIDI_PITCHBEND_LSB         0
+#define MIDI_RUNNING_STATUS        0x80
+#define MIDI_NOTE_OFF              0x8
+#define MIDI_NOTE_ON               0x9
+#define MIDI_POLY_AFTER_TCH        0xA
+#define MIDI_CONTROL_CHANGE        0xB
+#define MIDI_PROGRAM_CHANGE        0xC
+#define MIDI_AFTER_TOUCH           0xD
+#define MIDI_PITCH_BEND            0xE
+#define MIDI_SPECIAL               0xF
+#define MIDI_SYSEX                 0xF0
+#define MIDI_SYSEX_CONTINUE        0xF7
+#define MIDI_META_EVENT            0xFF
+#define MIDI_END_OF_TRACK          0x2F
+#define MIDI_TEMPO_CHANGE          0x51
+#define MIDI_TIME_SIGNATURE        0x58
+#define MIDI_RESET_ALL_CONTROLLERS 0x79
+#define MIDI_ALL_NOTES_OFF         0x7b
+#define MIDI_MONO_MODE_ON          0x7E
+#define MIDI_SYSTEM_RESET          0xFF
+
+#define GET_NEXT_EVENT( track, data ) \
+   ( data ) = *( track )->pos; \
+   ( track )->pos += 1
+
+#define GET_MIDI_CHANNEL( event )       ( ( event ) & 0xf )
+#define GET_MIDI_COMMAND( event )       ( ( event ) >> 4 )
+
+#define EMIDI_INFINITE          -1
+#define EMIDI_END_LOOP_VALUE    127
+#define EMIDI_ALL_CARDS         127
+#define EMIDI_INCLUDE_TRACK     110
+#define EMIDI_EXCLUDE_TRACK     111
+#define EMIDI_PROGRAM_CHANGE    112
+#define EMIDI_VOLUME_CHANGE     113
+#define EMIDI_CONTEXT_START     114
+#define EMIDI_CONTEXT_END       115
+#define EMIDI_LOOP_START        116
+#define EMIDI_LOOP_END          117
+#define EMIDI_SONG_LOOP_START   118
+#define EMIDI_SONG_LOOP_END     119
+
+#define EMIDI_GeneralMIDI       0
+#define EMIDI_SoundCanvas       1
+#define EMIDI_AWE32             2
+#define EMIDI_WaveBlaster       3
+#define EMIDI_SoundBlaster      4
+#define EMIDI_ProAudio          5
+#define EMIDI_SoundMan16        6
+#define EMIDI_Adlib             7
+#define EMIDI_Soundscape        8
+#define EMIDI_Ultrasound        9
+
+#define EMIDI_AffectsCurrentCard( c, type ) \
+   ( ( ( c ) == EMIDI_ALL_CARDS ) || ( ( c ) == ( type ) ) )
+
+
+#define EMIDI_NUM_CONTEXTS      7
+typedef struct
+   {
+   unsigned char *pos;
+   unsigned char *loopstart;
+   short          loopcount;
+   short          RunningStatus;
+   unsigned       time;
+   long           FPSecondsPerTick;
+   short          tick;
+   short          beat;
+   short          measure;
+   short          BeatsPerMeasure;
+   short          TicksPerBeat;
+   short          TimeBase;
+   long           delay;
+   short          active;
+   } songcontext;
+
+typedef struct
+   {
+   unsigned char *start;
+   unsigned char *pos;
+
+   long           delay;
+   short          active;
+   short          RunningStatus;
+
+   short          currentcontext;
+   songcontext    context[ EMIDI_NUM_CONTEXTS ];
+
+   char           EMIDI_IncludeTrack;
+   char           EMIDI_ProgramChange;
+   char           EMIDI_VolumeChange;
+   } track;
+
+static long _MIDI_ReadNumber( void *from, size_t size );
+static long _MIDI_ReadDelta( track *ptr );
+static void _MIDI_ResetTracks( void );
+static void _MIDI_AdvanceTick( void );
+static void _MIDI_MetaEvent( track *Track );
+static void _MIDI_SysEx( track *Track );
+static int  _MIDI_InterpretControllerInfo( track *Track, int TimeSet,
+   int channel, int c1, int c2 );
+//static
+   void _MIDI_ServiceRoutine( task *Task );
+static int  _MIDI_SendControlChange( int channel, int c1, int c2 );
+static void _MIDI_SetChannelVolume( int channel, int volume );
+static void _MIDI_SendChannelVolumes( void );
+static int  _MIDI_ProcessNextTick( void );
+static void _MIDI_InitEMIDI( void );
+
+/*
+               if ( c1 == EMIDI_LOOP_START )
+                  {
+                  if ( c2 == 0 )
+                     {
+                     Track->context[ 0 ].loopcount = EMIDI_INFINITE;
+                     }
+                  else
+                     {
+                     Track->context[ 0 ].loopcount = c2;
+                     }
+
+                  Track->context[ 0 ].pos              = Track->pos;
+                  Track->context[ 0 ].loopstart        = Track->pos;
+                  Track->context[ 0 ].RunningStatus    = Track->RunningStatus;
+                  Track->context[ 0 ].time             = _MIDI_Time;
+                  Track->context[ 0 ].FPSecondsPerTick = _MIDI_FPSecondsPerTick;
+                  Track->context[ 0 ].tick             = _MIDI_Tick;
+                  Track->context[ 0 ].beat             = _MIDI_Beat;
+                  Track->context[ 0 ].measure          = _MIDI_Measure;
+                  Track->context[ 0 ].BeatsPerMeasure  = _MIDI_BeatsPerMeasure;
+                  Track->context[ 0 ].TicksPerBeat     = _MIDI_TicksPerBeat;
+                  Track->context[ 0 ].TimeBase         = _MIDI_TimeBase;
+                  break;
+                  }
+
+               if ( ( c1 == EMIDI_LOOP_END ) &&
+                  ( c2 == EMIDI_END_LOOP_VALUE ) )
+                  {
+                  if ( ( Track->context[ 0 ].loopstart != NULL ) &&
+                     ( Track->context[ 0 ].loopcount != 0 ) )
+                     {
+                     if ( Track->context[ 0 ].loopcount != EMIDI_INFINITE )
+                        {
+                        Track->context[ 0 ].loopcount--;
+                        }
+
+                     Track->pos           = Track->context[ 0 ].loopstart;
+                     Track->RunningStatus = Track->context[ 0 ].RunningStatus;
+
+                     if ( !TimeSet )
+                        {
+                        _MIDI_Time             = Track->context[ 0 ].time;
+                        _MIDI_FPSecondsPerTick = Track->context[ 0 ].FPSecondsPerTick;
+                        _MIDI_Tick             = Track->context[ 0 ].tick;
+                        _MIDI_Beat             = Track->context[ 0 ].beat;
+                        _MIDI_Measure          = Track->context[ 0 ].measure;
+                        _MIDI_BeatsPerMeasure  = Track->context[ 0 ].BeatsPerMeasure;
+                        _MIDI_TicksPerBeat     = Track->context[ 0 ].TicksPerBeat;
+                        _MIDI_TimeBase         = Track->context[ 0 ].TimeBase;
+                        TimeSet = TRUE;
+                        }
+                     }
+                  break;
+                  }
+
+               if ( c1 == MIDI_MONO_MODE_ON )
+                  {
+                  Track->pos++;
+                  }
+
+               if ( ( c1 == MIDI_VOLUME ) && ( !Track->EMIDI_VolumeChange ) )
+                  {
+                  _MIDI_SetChannelVolume( channel, c2 );
+                  break;
+                  }
+               else if ( ( c1 == EMIDI_VOLUME_CHANGE ) &&
+                  ( Track->EMIDI_VolumeChange ) )
+                  {
+                  _MIDI_SetChannelVolume( channel, c2 );
+                  break;
+                  }
+
+               if ( ( c1 == EMIDI_PROGRAM_CHANGE ) &&
+                  ( Track->EMIDI_ProgramChange ) )
+                  {
+                  _MIDI_Funcs->ProgramChange( channel, MIDI_PatchMap[ c2 & 0x7f ] );
+                  break;
+                  }
+
+               if ( c1 == EMIDI_CONTEXT_START )
+                  {
+                  break;
+                  }
+
+               if ( c1 == EMIDI_CONTEXT_END )
+                  {
+                  if ( ( Track->currentcontext != _MIDI_Context ) ||
+                     ( Track->context[ _MIDI_Context ].pos == NULL )
+                     {
+                     break;
+                     }
+
+                  Track->currentcontext = _MIDI_Context;
+                  Track->context[ 0 ].loopstart = Track->context[ _MIDI_Context ].loopstart;
+                  Track->context[ 0 ].loopcount = Track->context[ _MIDI_Context ].loopcount;
+                  Track->pos           = Track->context[ _MIDI_Context ].pos;
+                  Track->RunningStatus = Track->context[ _MIDI_Context ].RunningStatus;
+
+                  if ( TimeSet )
+                     {
+                     break;
+                     }
+
+                  _MIDI_Time             = Track->context[ _MIDI_Context ].time;
+                  _MIDI_FPSecondsPerTick = Track->context[ _MIDI_Context ].FPSecondsPerTick;
+                  _MIDI_Tick             = Track->context[ _MIDI_Context ].tick;
+                  _MIDI_Beat             = Track->context[ _MIDI_Context ].beat;
+                  _MIDI_Measure          = Track->context[ _MIDI_Context ].measure;
+                  _MIDI_BeatsPerMeasure  = Track->context[ _MIDI_Context ].BeatsPerMeasure;
+                  _MIDI_TicksPerBeat     = Track->context[ _MIDI_Context ].TicksPerBeat;
+                  _MIDI_TimeBase         = Track->context[ _MIDI_Context ].TimeBase;
+                  TimeSet = TRUE;
+                  break;
+                  }
+
+               if ( _MIDI_Funcs->ControlChange )
+                  {
+                  _MIDI_Funcs->ControlChange( channel, c1, c2 );
+                  }
+ */
+
+#endif
--- /dev/null
+++ b/rott/audiolib/_multivc.h
@@ -1,0 +1,286 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+/**********************************************************************
+   file:   _MULTIVC.H
+
+   author: James R. Dose
+   date:   December 20, 1993
+
+   Private header for MULTIVOC.C
+
+   (c) Copyright 1993 James R. Dose.  All Rights Reserved.
+**********************************************************************/
+
+#ifndef ___MULTIVC_H
+#define ___MULTIVC_H
+
+#define TRUE  ( 1 == 1 )
+#define FALSE ( !TRUE )
+
+#define VOC_8BIT            0x0
+#define VOC_CT4_ADPCM       0x1
+#define VOC_CT3_ADPCM       0x2
+#define VOC_CT2_ADPCM       0x3
+#define VOC_16BIT           0x4
+#define VOC_ALAW            0x6
+#define VOC_MULAW           0x7
+#define VOC_CREATIVE_ADPCM  0x200
+
+#define T_SIXTEENBIT_STEREO 0
+#define T_8BITS       1
+#define T_MONO        2
+#define T_16BITSOURCE 4
+#define T_LEFTQUIET   8
+#define T_RIGHTQUIET  16
+#define T_DEFAULT     T_SIXTEENBIT_STEREO
+
+#define MV_MaxPanPosition  31
+#define MV_NumPanPositions ( MV_MaxPanPosition + 1 )
+#define MV_MaxTotalVolume  255
+//#define MV_MaxVolume       63
+#define MV_NumVoices       8
+
+#define MIX_VOLUME( volume ) \
+   ( ( max( 0, min( ( volume ), 255 ) ) * ( MV_MaxVolume + 1 ) ) >> 8 )
+//   ( ( max( 0, min( ( volume ), 255 ) ) ) >> 2 )
+
+//#define SILENCE_16BIT     0x80008000
+#define SILENCE_16BIT     0
+#define SILENCE_8BIT      0x80808080
+//#define SILENCE_16BIT_PAS 0
+
+#define MixBufferSize     256
+
+#define NumberOfBuffers   16
+#define TotalBufferSize   ( MixBufferSize * NumberOfBuffers )
+
+#define PI                3.1415926536
+
+typedef enum
+   {
+   Raw,
+   VOC,
+   DemandFeed,
+   WAV
+   } wavedata;
+
+typedef enum
+   {
+   NoMoreData,
+   KeepPlaying
+   } playbackstatus;
+
+
+typedef struct VoiceNode
+   {
+   struct VoiceNode *next;
+   struct VoiceNode *prev;
+
+   wavedata      wavetype;
+   char          bits;
+
+   playbackstatus ( *GetSound )( struct VoiceNode *voice );
+
+   void ( *mix )( unsigned long position, unsigned long rate,
+      const char *start, unsigned long length );
+
+   char         *NextBlock;
+   char         *LoopStart;
+   char         *LoopEnd;
+   unsigned      LoopCount;
+   unsigned long LoopSize;
+   unsigned long BlockLength;
+
+   unsigned long PitchScale;
+   unsigned long FixedPointBufferSize;
+
+   char         *sound;
+   unsigned long length;
+   unsigned long SamplingRate;
+   unsigned long RateScale;
+   unsigned long position;
+   int           Playing;
+
+   int           handle;
+   int           priority;
+
+   void          ( *DemandFeed )( char **ptr, unsigned long *length );
+
+   short        *LeftVolume;
+   short        *RightVolume;
+
+   unsigned long callbackval;
+
+   } VoiceNode;
+
+typedef struct
+   {
+   VoiceNode *start;
+   VoiceNode *end;
+   } VList;
+
+typedef struct
+   {
+   unsigned char left;
+   unsigned char right;
+   } Pan;
+
+typedef signed short MONO16;
+typedef signed char  MONO8;
+
+typedef struct
+   {
+   MONO16 left;
+   MONO16 right;
+//   unsigned short left;
+//   unsigned short right;
+   } STEREO16;
+
+typedef struct
+   {
+   MONO16 left;
+   MONO16 right;
+   } SIGNEDSTEREO16;
+
+typedef struct
+   {
+//   MONO8 left;
+//   MONO8 right;
+   char left;
+   char right;
+   } STEREO8;
+
+typedef struct
+   {
+   char          RIFF[ 4 ];
+   unsigned long file_size;
+   char          WAVE[ 4 ];
+   char          fmt[ 4 ];
+   unsigned long format_size;
+   } riff_header;
+
+typedef struct
+   {
+   unsigned short wFormatTag;
+   unsigned short nChannels;
+   unsigned long  nSamplesPerSec;
+   unsigned long  nAvgBytesPerSec;
+   unsigned short nBlockAlign;
+   unsigned short nBitsPerSample;
+   } format_header;
+
+typedef struct
+   {
+   unsigned char DATA[ 4 ];
+   unsigned long size;
+   } data_header;
+
+typedef MONO8  VOLUME8[ 256 ];
+typedef MONO16 VOLUME16[ 256 ];
+
+typedef char HARSH_CLIP_TABLE_8[ MV_NumVoices * 256 ];
+
+static void MV_Mix( VoiceNode *voice, int buffer );
+static void MV_PlayVoice( VoiceNode *voice );
+static void MV_StopVoice( VoiceNode *voice );
+static void MV_ServiceVoc( void );
+
+static playbackstatus MV_GetNextVOCBlock( VoiceNode *voice );
+static playbackstatus MV_GetNextDemandFeedBlock( VoiceNode *voice );
+static playbackstatus MV_GetNextRawBlock( VoiceNode *voice );
+static playbackstatus MV_GetNextWAVBlock( VoiceNode *voice );
+
+static void       MV_ServiceRecord( void );
+static VoiceNode *MV_GetVoice( int handle );
+static VoiceNode *MV_AllocVoice( int priority );
+
+static short     *MV_GetVolumeTable( int vol );
+
+static void       MV_SetVoiceMixMode( VoiceNode *voice );
+
+static void       MV_SetVoicePitch( VoiceNode *voice, unsigned long rate, int pitchoffset );
+static void       MV_CalcVolume( int MaxLevel );
+static void       MV_CalcPanTable( void );
+
+#ifdef PLAT_DOS
+#define ATR_INDEX               0x3c0
+#define STATUS_REGISTER_1       0x3da
+
+#define SetBorderColor(color) \
+   { \
+   inp  (STATUS_REGISTER_1); \
+   outp (ATR_INDEX,0x31);    \
+   outp (ATR_INDEX,color);   \
+   }
+#endif
+
+void ClearBuffer_DW( void *ptr, unsigned data, int length );
+
+#ifdef PLAT_DOS
+#pragma aux ClearBuffer_DW = \
+   "cld",                    \
+   "push   es",              \
+   "push   ds",              \
+   "pop    es",              \
+   "rep    stosd",           \
+   "pop    es",              \
+parm [ edi ] [ eax ] [ ecx ] modify exact [ ecx edi ];
+#endif
+
+void MV_Mix8BitMono( unsigned long position, unsigned long rate,
+   const char *start, unsigned long length );
+
+void MV_Mix8BitStereo( unsigned long position,
+   unsigned long rate, const char *start, unsigned long length );
+
+void MV_Mix16BitMono( unsigned long position,
+   unsigned long rate, const char *start, unsigned long length );
+
+void MV_Mix16BitStereo( unsigned long position,
+   unsigned long rate, const char *start, unsigned long length );
+
+void MV_Mix16BitMono16( unsigned long position,
+   unsigned long rate, const char *start, unsigned long length );
+
+void MV_Mix8BitMono16( unsigned long position, unsigned long rate,
+   const char *start, unsigned long length );
+
+void MV_Mix8BitStereo16( unsigned long position,
+   unsigned long rate, const char *start, unsigned long length );
+
+void MV_Mix16BitStereo16( unsigned long position,
+   unsigned long rate, const char *start, unsigned long length );
+
+void MV_16BitReverb( const char *src, char *dest, const VOLUME16 *volume, int count );
+
+void MV_8BitReverb( const signed char *src, signed char *dest, const VOLUME16 *volume, int count );
+
+void MV_16BitReverbFast( const char *src, char *dest, int count, int shift );
+
+void MV_8BitReverbFast( const signed char *src, signed char *dest, int count, int shift );
+
+#ifdef PLAT_DOS
+#pragma aux MV_16BitReverb parm [eax] [edx] [ebx] [ecx] modify exact [eax ebx ecx edx esi edi]
+#pragma aux MV_8BitReverb parm [eax] [edx] [ebx] [ecx] modify exact [eax ebx ecx edx esi edi]
+#pragma aux MV_16BitReverbFast parm [eax] [edx] [ebx] [ecx] modify exact [eax ebx ecx edx esi edi]
+#pragma aux MV_8BitReverbFast parm [eax] [edx] [ebx] [ecx] modify exact [eax ebx ecx edx esi edi]
+#endif
+
+#endif
--- /dev/null
+++ b/rott/audiolib/_pas16.h
@@ -1,0 +1,250 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+/**********************************************************************
+   module: _PAS16.H
+
+   author: James R. Dose
+   date:   March 27, 1994
+
+   Private header for for PAS16.C
+
+   (c) Copyright 1994 James R. Dose.  All Rights Reserved.
+**********************************************************************/
+
+#ifndef ___PAS16_H
+#define ___PAS16_H
+
+#define TRUE    ( 1 == 1 )
+#define FALSE   ( !TRUE )
+
+#define VALID   ( 1 == 1 )
+#define INVALID ( !VALID )
+
+#define lobyte( num )   ( ( int )*( ( char * )&( num ) ) )
+#define hibyte( num )   ( ( int )*( ( ( char * )&( num ) ) + 1 ) )
+
+#define STEREO      1
+#define SIXTEEN_BIT 2
+
+#define MONO_8BIT    0
+#define STEREO_8BIT  ( STEREO )
+#define MONO_16BIT   ( SIXTEEN_BIT )
+#define STEREO_16BIT ( STEREO | SIXTEEN_BIT )
+
+#define PAS_MaxMixMode        STEREO_16BIT
+
+#define MONO_8BIT_SAMPLE_SIZE    1
+#define MONO_16BIT_SAMPLE_SIZE   2
+#define STEREO_8BIT_SAMPLE_SIZE  ( 2 * MONO_8BIT_SAMPLE_SIZE )
+#define STEREO_16BIT_SAMPLE_SIZE ( 2 * MONO_16BIT_SAMPLE_SIZE )
+
+#define PAS_RevisionBits        0xe0
+
+#define AudioFilterControl      0xb8a
+#define InterruptControl        0xb8b
+#define InterruptStatus         0xb89
+#define PCMDataRegister         0xf88
+#define CrossChannelControl     0xf8a
+#define SampleRateTimer         0x1388
+#define SampleBufferCount       0x1389
+#define LocalSpeakerTimerCount  0x138a
+#define LocalTimerControl       0x138b
+#define SampleSizeConfiguration 0x8389
+
+#define AudioMuteFlag             0x20
+#define SampleRateTimerGateFlag   0x40
+#define SampleBufferCountGateFlag 0x80
+
+#define SampleRateInterruptFlag   0x04
+#define SampleBufferInterruptFlag 0x08
+
+#define PAS_SampleSizeMask     0xf3
+#define PAS_SignedSampleMask   0xe3
+#define PAS_16BitSampleFlag    0x04
+#define PAS_UnsignedSampleFlag 0x10
+//bSC2msbinv   equ   00010000b   ;; invert MSB from standard method
+
+#define PAS_OverSamplingMask 0xfc
+
+#define PAS_1xOverSampling  0x00
+#define PAS_2xOverSampling  0x01
+#define PAS_4xOverSampling  0x03
+
+#define PAS_StereoFlag      0x20
+
+#define PAS_AudioMuteFlag  0x20
+
+#define DEFAULT_BASE ( 0x0388 ^ 0x388 ) /* default base I/O address */
+#define ALT_BASE_1   ( 0x0384 ^ 0x388 ) /* first alternate address  */
+#define ALT_BASE_2   ( 0x038C ^ 0x388 ) /* second alternate address */
+#define ALT_BASE_3   ( 0x0288 ^ 0x388 ) /* third alternate address  */
+
+#define PAS_DMAEnable          0x80
+#define PAS_ChannelConnectMask 0x0f
+#define PAS_PCMStartDAC        0xD0
+#define PAS_PCMStartADC        0xC0
+#define PAS_PCMStopMask        0x3f
+
+#define RECORD   0
+#define PLAYBACK 1
+
+#define SelectSampleRateTimer   0x36   // 00110110b
+#define SelectSampleBufferCount 0x74   // 01110100b
+
+#define CalcTimeInterval( rate ) \
+   ( 1193180UL / ( rate ) )
+
+#define CalcSamplingRate( interval ) \
+   ( 1193180UL / ( interval ) )
+
+#define MV_Signature                 0x4d56
+#define MV_SoundInt                  0x2f
+#define MV_CheckForDriver            0xbc00
+#define MV_GetVersion                0xbc01
+#define MV_GetPointerToStateTable    0xbc02
+#define MV_GetPointerToFunctionTable 0xbc03
+#define MV_GetDmaIrqInt              0xbc04
+#define MV_SendCommandStructure      0xbc05
+#define MV_GetDriverMessage          0xbc06
+#define MV_SetHotkeyScanCodes        0xbc0a
+#define MV_GetPathToDriver           0xbc0b
+
+#define OUTPUTMIXER     0x00         /* output mixer H/W select */
+#define INPUTMIXER      0x40         /* input mixer select      */
+#define DEFMIXER        -1           /* use last mixer selected   */
+
+/* left channel values */
+
+#define L_FM            0x01
+#define L_IMIXER        0x02
+#define L_EXT           0x03
+#define L_INT           0x04
+#define L_MIC           0x05
+#define L_PCM           0x06
+#define L_SPEAKER       0x07
+#define L_FREE          0x00
+#define L_SBDAC         0x00
+
+/* right channel values */
+
+#define R_FM            0x08
+#define R_IMIXER        0x09
+#define R_EXT           0x0A
+#define R_INT           0x0B
+#define R_MIC           0x0C
+#define R_PCM           0x0D
+#define R_SPEAKER       0x0E
+#define R_FREE          0x0F
+#define R_SBDAC         0x0F
+
+typedef struct
+   {
+   unsigned char  sysspkrtmr;   /*   42 System Speaker Timer Address */
+   unsigned char  systmrctlr;   /*   43 System Timer Control         */
+   unsigned char  sysspkrreg;   /*   61 System Speaker Register      */
+   unsigned char  joystick;     /*  201 Joystick Register            */
+   unsigned char  lfmaddr;      /*  388 Left  FM Synth Address       */
+   unsigned char  lfmdata;      /*  389 Left  FM Synth Data          */
+   unsigned char  rfmaddr;      /*  38A Right FM Synth Address       */
+   unsigned char  rfmdata;      /*  38B Right FM Synth Data          */
+   unsigned char  dfmaddr;      /*  788 Dual  FM Synth Address       */
+   unsigned char  dfmdata;      /*  789 Dual  FM Synth Data          */
+   unsigned char  RESRVD1[1];   /*      reserved                     */
+   unsigned char  paudiomixr;   /*  78B Paralllel Audio Mixer Control*/
+   unsigned char  audiomixr;    /*  B88 Audio Mixer Control          */
+   unsigned char  intrctlrst;   /*  B89 Interrupt Status             */
+   unsigned char  audiofilt;    /*  B8A Audio Filter Control         */
+   unsigned char  intrctlr;     /*  B8B Interrupt Control            */
+   unsigned char  pcmdata;      /*  F88 PCM Data I/O Register        */
+   unsigned char  RESRVD2;      /*      reserved                     */
+   unsigned char  crosschannel; /*  F8A Cross Channel                */
+   unsigned char  RESRVD3;      /*      reserved                     */
+   unsigned short samplerate;   /* 1388 Sample Rate Timer            */
+   unsigned short samplecnt;    /* 1389 Sample Count Register        */
+   unsigned short spkrtmr;      /* 138A Shadow Speaker Timer Count   */
+   unsigned char  tmrctlr;      /* 138B Shadow Speaker Timer Control */
+   unsigned char  mdirqvect;    /* 1788 MIDI IRQ Vector Register     */
+   unsigned char  mdsysctlr;    /* 1789 MIDI System Control Register */
+   unsigned char  mdsysstat;    /* 178A MIDI IRQ Status Register     */
+   unsigned char  mdirqclr;     /* 178B MIDI IRQ Clear Register      */
+   unsigned char  mdgroup1;     /* 1B88 MIDI Group #1 Register       */
+   unsigned char  mdgroup2;     /* 1B89 MIDI Group #2 Register       */
+   unsigned char  mdgroup3;     /* 1B8A MIDI Group #3 Register       */
+   unsigned char  mdgroup4;     /* 1B8B MIDI Group #4 Register       */
+   } MVState;
+
+typedef struct
+   {
+   unsigned long SetMixer;
+   unsigned long SetVolume;
+   unsigned long SetFilter;
+   unsigned long SetCrossChannel;
+   unsigned long GetMixer;
+   unsigned long GetVolume;
+   unsigned long GetFilter;
+   unsigned long GetCrossChannel;
+   unsigned long ReadSound;
+   unsigned long FMSplit;
+   } MVFunc;
+
+int     PAS_CheckForDriver( void );
+MVState *PAS_GetStateTable( void );
+MVFunc  *PAS_GetFunctionTable( void );
+int     PAS_GetCardSettings( void );
+void    PAS_EnableInterrupt( void );
+void    PAS_DisableInterrupt( void );
+void    interrupt far PAS_ServiceInterrupt( void );
+//void    interrupt PAS_ServiceInterrupt( void );
+void    PAS_Write( int Register, int Data );
+int     PAS_Read( int Register );
+void    PAS_SetSampleRateTimer( void );
+void    PAS_SetSampleBufferCount( void );
+int     PAS_SetupDMABuffer( char *BufferPtr, int BufferSize, int mode );
+int     PAS_GetFilterSetting( int rate );
+void    PAS_BeginTransfer( int mode );
+int     PAS_TestAddress( int address );
+int     PAS_FindCard( void );
+int     PAS_CallMVFunction( unsigned long function, int ebx, int ecx, int edx );
+void    PAS_SaveState( void );
+void    PAS_RestoreState( void );
+
+
+#pragma aux PAS_TestAddress = \
+   "mov   dx, 0b8bh", \
+   "xor    dx, ax", \
+   "in    al, dx", \
+   "cmp   al, 0ffh", \
+   "je    TestExit", \
+   "mov   ah, al", \
+   "xor   al, 0e0h", \
+   "out   dx, al", \
+   "jmp   TestDelay1", \
+   "TestDelay1:", \
+   "jmp   TestDelay2", \
+   "TestDelay2:", \
+   "in    al, dx", \
+   "xchg  al, ah", \
+   "out   dx, al", \
+   "sub   al, ah", \
+   "TestExit:", \
+   "and   eax, 0ffh" \
+   parm [ eax ] modify exact [ eax dx ];
+
+#endif
--- /dev/null
+++ b/rott/audiolib/_sndscap.h
@@ -1,0 +1,136 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+/**********************************************************************
+   module: _SNDSCAP.H
+
+   author: James R. Dose
+   date:   October 26, 1994
+
+   Private header for SNDSCAPE.C
+
+   (c) Copyright 1994 James R. Dose.  All Rights Reserved.
+**********************************************************************/
+
+#ifndef ___SNDSCAP_H
+#define ___SNDSCAP_H
+
+#define VALID   ( 1 == 1 )
+#define INVALID ( !VALID )
+
+#define TRUE  ( 1 == 1 )
+#define FALSE ( !TRUE )
+
+#define lobyte( num )   ( ( int )*( ( char * )&( num ) ) )
+#define hibyte( num )   ( ( int )*( ( ( char * )&( num ) ) + 1 ) )
+
+#define STEREO      1
+#define SIXTEEN_BIT 2
+
+#define MONO_8BIT    0
+#define STEREO_8BIT  ( STEREO )
+#define MONO_16BIT   ( SIXTEEN_BIT )
+#define STEREO_16BIT ( STEREO | SIXTEEN_BIT )
+
+#define SOUNDSCAPE_MaxMixMode        STEREO_16BIT
+
+#define MONO_8BIT_SAMPLE_SIZE    1
+#define MONO_16BIT_SAMPLE_SIZE   2
+#define STEREO_8BIT_SAMPLE_SIZE  ( 2 * MONO_8BIT_SAMPLE_SIZE )
+#define STEREO_16BIT_SAMPLE_SIZE ( 2 * MONO_16BIT_SAMPLE_SIZE )
+
+#define SOUNDSCAPE_DefaultSampleRate 11000
+#define SOUNDSCAPE_DefaultMixMode    MONO_8BIT
+#define SOUNDSCAPE_MaxIrq            15
+
+/* Ensoniq gate-array chip defines ... */
+#define ODIE            0       /* ODIE gate array */
+#define OPUS            1       /* OPUS gate array */
+#define MMIC            2       /* MiMIC gate array */
+
+/* relevant direct register defines - offsets from base address */
+#define GA_HOSTCSTAT    2       /* host port ctrl/stat reg */
+#define GA_HOSTDATA     3       /* host port data reg */
+#define GA_REGADDR      4       /* indirect address reg */
+#define GA_REGDATA      5       /* indirect data reg */
+#define SB_IACK      0x22e /* SoundBlaster IACK register */
+
+/* relevant indirect register defines */
+#define GA_DMACHB       3       /* DMA chan B assign reg */
+#define GA_INTCFG       4       /* interrupt configuration reg */
+#define GA_DMACFG       5       /* DMA config reg */
+#define GA_CDCFG        6       /* CD-ROM (AD-1848) config reg */
+#define GA_HMCTL  9  /* host master control reg */
+#define GA_CHIPSEL      10      /* programmable external chip select */
+
+/* AD-1848 chip defines ... */
+/* relevant direct register defines */
+#define AD_REGADDR      0       /* indirect address reg */
+#define AD_REGDATA      1       /* indirect data reg */
+#define AD_STATUS       2       /* status register */
+#define AD_OFFSET       8       /* for some boards, a fixed BasePort offset */
+
+/* relevant indirect register defines */
+#define AD_LEFTOUT      6       /* left DAC output control reg */
+#define AD_RIGHTOUT     7       /* right DAC output control reg */
+#define AD_FORMAT       8       /* clock and data format reg */
+#define AD_CONFIG       9       /* interface config register */
+#define AD_PINCTRL      10      /* external pin control reg */
+#define AD_UCOUNT       14      /* upper count reg */
+#define AD_LCOUNT       15      /* lower count reg */
+
+/* some firmware command and communication defines */
+#define SET_CTL      0x88  /* set a control value */
+#define GET_CTL      0x89  /* get a control value */
+#define SET_REV      0xb0  /* set synth reverb */
+#define SYNTH_VOL 0x04  /* Synth Vol control number */
+#define RXRDY     0x01  /* Receive-Ready bit mask */
+#define TXRDY     0x02  /* Transmit-Ready bit mask */
+
+/* some miscellaneous defines ... soundscape reg values, sytem int regs, ... */
+#define INTCONT1        0x20    /* Interrupt Controller 1 control register */
+#define INTCONT2        0xa0    /* Interrupt Controller 2 control register */
+#define INTMASK1        0x21    /* Interrupt Controller 1 mask register */
+#define INTMASK2        0xa1    /* Interrupt Controller 2 mask register */
+#define VECTBASE1       0x08    /* vector base for XT interrupts */
+#define VECTBASE2       0x70    /* vector base for AT extended interrupts */
+#define EOI             0x20    /* End Of Interrupt command */
+#define AUTO_OUT        0x58    /* DMA controller mode */
+
+static void SOUNDSCAPE_EnableInterrupt( void );
+static void SOUNDSCAPE_DisableInterrupt( void );
+static void __interrupt __far SOUNDSCAPE_ServiceInterrupt( void );
+static int  ga_read( int rnum );
+static void ga_write( int rnum, int value );
+static int  ad_read( int rnum );
+static void ad_write( int rnum, int value );
+static void tdelay( void );
+static void pcm_format( void );
+static int  SOUNDSCAPE_SetupDMABuffer( char *BufferPtr, int BufferSize, int mode );
+static int  SOUNDSCAPE_BeginPlayback( int length );
+static void SOUNDSCAPE_LockEnd( void );
+static void SOUNDSCAPE_UnlockMemory( void );
+static int  SOUNDSCAPE_LockMemory( void );
+static unsigned short allocateTimerStack( unsigned short size );
+static void deallocateTimerStack( unsigned short selector );
+static int  parse( char *val, char *str, FILE *p1 );
+static int  SOUNDSCAPE_FindCard( void );
+static int  SOUNDSCAPE_Setup( void );
+
+#endif
--- /dev/null
+++ b/rott/audiolib/adlibfx.c
@@ -1,0 +1,552 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+/**********************************************************************
+   module: ADLIBFX.C
+
+   author: James R. Dose
+   date:   April 1, 1994
+
+   Low level routines to support Adlib sound effects created by Muse.
+
+   (c) Copyright 1994 James R. Dose.  All Rights Reserved.
+**********************************************************************/
+
+#include <dos.h>
+#include <stdlib.h>
+#include <conio.h>
+#include "dpmi.h"
+#include "task_man.h"
+#include "interrup.h"
+#include "al_midi.h"
+#include "adlibfx.h"
+
+#define TRUE  ( 1 == 1 )
+#define FALSE ( !TRUE )
+
+static void ADLIBFX_SendOutput( int reg, int data );
+static void ADLIBFX_Service( task *Task );
+
+static long     ADLIBFX_LengthLeft;
+static int      ADLIBFX_Block;
+static ALSound *ADLIBFX_Sound = NULL;
+static char    *ADLIBFX_SoundPtr = NULL;
+static int      ADLIBFX_Priority;
+static unsigned long ADLIBFX_CallBackVal;
+static void     ( *ADLIBFX_CallBackFunc )( unsigned long ) = NULL;
+static int      ADLIBFX_SoundVolume;
+static int      ADLIBFX_TotalVolume = ADLIBFX_MaxVolume;
+static task    *ADLIBFX_ServiceTask = NULL;
+static int      ADLIBFX_VoiceHandle = ADLIBFX_MinVoiceHandle;
+
+int ADLIBFX_Installed = FALSE;
+
+int ADLIBFX_ErrorCode = ADLIBFX_Ok;
+
+#define ADLIBFX_SetErrorCode( status ) \
+   ADLIBFX_ErrorCode   = ( status );
+
+
+/*---------------------------------------------------------------------
+   Function: ADLIBFX_ErrorString
+
+   Returns a pointer to the error message associated with an error
+   number.  A -1 returns a pointer the current error.
+---------------------------------------------------------------------*/
+
+char *ADLIBFX_ErrorString
+   (
+   int ErrorNumber
+   )
+
+   {
+   char *ErrorString;
+
+   switch( ErrorNumber )
+      {
+      case ADLIBFX_Warning :
+      case ADLIBFX_Error :
+         ErrorString = ADLIBFX_ErrorString( ADLIBFX_ErrorCode );
+         break;
+
+      case ADLIBFX_Ok :
+         ErrorString = "Adlib FX ok.";
+         break;
+
+      case ADLIBFX_NoVoices :
+         ErrorString = "No free voices available in Adlib FX.";
+         break;
+
+      case ADLIBFX_VoiceNotFound :
+         ErrorString = "No voice with matching handle found.";
+         break;
+
+      case ADLIBFX_DPMI_Error :
+         ErrorString = "DPMI Error in AdlibFX.";
+         break;
+
+      default :
+         ErrorString = "Unknown Adlib FX error code.";
+         break;
+      }
+
+   return( ErrorString );
+   }
+
+
+/**********************************************************************
+
+   Memory locked functions:
+
+**********************************************************************/
+
+
+#define ADLIBFX_LockStart ADLIBFX_SendOutput
+
+/*---------------------------------------------------------------------
+   Function: ADLIBFX_SendOutput
+
+   Writes a byte of data to the specified register on the Adlib card.
+---------------------------------------------------------------------*/
+
+static void ADLIBFX_SendOutput
+   (
+   int reg,
+   int data
+   )
+
+   {
+   int i;
+   int adlib_port = 0x388;
+   unsigned flags;
+
+   flags = DisableInterrupts();
+
+   outp( adlib_port, reg );
+
+   for( i = 6; i ; i-- )
+      {
+      inp( adlib_port );
+      }
+
+   outp( adlib_port + 1, data );
+
+   for( i = 35; i ; i-- )
+      {
+      inp( adlib_port );
+      }
+
+   RestoreInterrupts( flags );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: ADLIBFX_Stop
+
+   Halts playback of the currently playing sound effect.
+---------------------------------------------------------------------*/
+
+int ADLIBFX_Stop
+   (
+   int handle
+   )
+
+   {
+   unsigned flags;
+
+   if ( ( handle != ADLIBFX_VoiceHandle ) || ( ADLIBFX_Sound == NULL ) )
+      {
+      ADLIBFX_SetErrorCode( ADLIBFX_VoiceNotFound );
+      return( ADLIBFX_Warning );
+      }
+
+   flags = DisableInterrupts();
+
+   ADLIBFX_SendOutput( 0xb0, 0 );
+
+   ADLIBFX_Sound      = NULL;
+   ADLIBFX_SoundPtr   = NULL;
+   ADLIBFX_LengthLeft = 0;
+   ADLIBFX_Priority   = 0;
+
+   RestoreInterrupts( flags );
+
+   if ( ADLIBFX_CallBackFunc )
+      {
+      ADLIBFX_CallBackFunc( ADLIBFX_CallBackVal );
+      }
+
+   return( ADLIBFX_Ok );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: ADLIBFX_Service
+
+   Task Manager routine to perform the playback of a sound effect.
+---------------------------------------------------------------------*/
+
+static void ADLIBFX_Service
+   (
+   task *Task
+   )
+
+   {
+   int value;
+
+   if ( ADLIBFX_SoundPtr )
+      {
+      value = *ADLIBFX_SoundPtr++;
+      if ( value != 0 )
+         {
+         ADLIBFX_SendOutput( 0xa0, value );
+         ADLIBFX_SendOutput( 0xb0, ADLIBFX_Block );
+         }
+      else
+         {
+         ADLIBFX_SendOutput( 0xb0, 0 );
+         }
+
+      ADLIBFX_LengthLeft--;
+      if ( ADLIBFX_LengthLeft <= 0 )
+         {
+         ADLIBFX_Stop( ADLIBFX_VoiceHandle );
+         }
+      }
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: ADLIBFX_SetVolume
+
+   Sets the volume of the currently playing sound effect.
+---------------------------------------------------------------------*/
+
+int ADLIBFX_SetVolume
+   (
+   int handle,
+   int volume
+   )
+
+   {
+   unsigned flags;
+   int      carrierlevel;
+
+   flags = DisableInterrupts();
+   if ( ( handle != ADLIBFX_VoiceHandle ) || ( ADLIBFX_Sound == NULL ) )
+      {
+      RestoreInterrupts( flags );
+      ADLIBFX_SetErrorCode( ADLIBFX_VoiceNotFound );
+      return( ADLIBFX_Warning );
+      }
+
+   volume  = min( volume, ADLIBFX_MaxVolume );
+   volume  = max( volume, 0 );
+   ADLIBFX_SoundVolume = volume;
+
+   volume *= ADLIBFX_TotalVolume;
+   volume /= ADLIBFX_MaxVolume;
+
+   carrierlevel  = ADLIBFX_Sound->cScale & 0x3f;
+   carrierlevel ^= 0x3f;
+   carrierlevel *= ( volume / 2 ) + 0x80;
+   carrierlevel /= ADLIBFX_MaxVolume;
+   carrierlevel ^= 0x3f;
+   carrierlevel |= ADLIBFX_Sound->cScale & 0xc0;
+
+   ADLIBFX_SendOutput( 0x43, carrierlevel );
+
+   RestoreInterrupts( flags );
+   return( ADLIBFX_Ok );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: ADLIBFX_SetTotalVolume
+
+   Sets the total volume of the sound effect.
+---------------------------------------------------------------------*/
+
+int ADLIBFX_SetTotalVolume
+   (
+   int volume
+   )
+
+   {
+   volume = max( volume, 0 );
+   volume = min( volume, ADLIBFX_MaxVolume );
+
+   ADLIBFX_TotalVolume = volume;
+   ADLIBFX_SetVolume( ADLIBFX_VoiceHandle, ADLIBFX_SoundVolume );
+
+   return( ADLIBFX_Ok );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: ADLIBFX_GetTotalVolume
+
+   Returns the total volume of the sound effect.
+---------------------------------------------------------------------*/
+
+int ADLIBFX_GetTotalVolume
+   (
+   void
+   )
+
+   {
+   return( ADLIBFX_TotalVolume );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: ADLIBFX_VoiceAvailable
+
+   Checks if a voice can be play at the specified priority.
+---------------------------------------------------------------------*/
+
+int ADLIBFX_VoiceAvailable
+   (
+   int priority
+   )
+
+   {
+   if ( priority < ADLIBFX_Priority )
+      {
+      return( FALSE );
+      }
+
+   return( TRUE );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: ADLIBFX_Play
+
+   Starts playback of a Muse sound effect.
+---------------------------------------------------------------------*/
+
+int ADLIBFX_Play
+   (
+   ALSound *sound,
+   int volume,
+   int priority,
+   unsigned long callbackval
+   )
+
+   {
+   unsigned flags;
+   int      carrierlevel;
+
+   if ( priority < ADLIBFX_Priority )
+      {
+      ADLIBFX_SetErrorCode( ADLIBFX_NoVoices );
+      return( ADLIBFX_Warning );
+      }
+
+   ADLIBFX_Stop( ADLIBFX_VoiceHandle );
+
+   ADLIBFX_VoiceHandle++;
+   if ( ADLIBFX_VoiceHandle < ADLIBFX_MinVoiceHandle )
+      {
+      ADLIBFX_VoiceHandle = ADLIBFX_MinVoiceHandle;
+      }
+
+   flags = DisableInterrupts();
+
+   ADLIBFX_LengthLeft  = sound->length;
+   ADLIBFX_Priority    = priority;
+   ADLIBFX_Sound       = sound;
+   ADLIBFX_SoundPtr    = &sound->data;
+   ADLIBFX_CallBackVal = callbackval;
+
+   ADLIBFX_Block = ( ( sound->block & 7 ) << 2 ) | 0x20;
+
+   volume = min( volume, ADLIBFX_MaxVolume );
+   volume = max( volume, 0 );
+   ADLIBFX_SoundVolume = volume;
+
+   volume *= ADLIBFX_TotalVolume;
+   volume /= ADLIBFX_MaxVolume;
+
+   carrierlevel  = sound->cScale & 0x3f;
+   carrierlevel ^= 0x3f;
+   carrierlevel *= ( volume / 2 ) + 0x80;
+   carrierlevel /= ADLIBFX_MaxVolume;
+   carrierlevel ^= 0x3f;
+   carrierlevel |= sound->cScale & 0xc0;
+
+   ADLIBFX_SendOutput( 0x20, sound->mChar );
+   ADLIBFX_SendOutput( 0x40, sound->mScale );
+   ADLIBFX_SendOutput( 0x60, sound->mAttack );
+   ADLIBFX_SendOutput( 0x80, sound->mSus );
+   ADLIBFX_SendOutput( 0xe0, sound->mWave );
+
+   ADLIBFX_SendOutput( 0x23, sound->cChar );
+   ADLIBFX_SendOutput( 0x43, carrierlevel );
+   ADLIBFX_SendOutput( 0x63, sound->cAttack );
+   ADLIBFX_SendOutput( 0x83, sound->cSus );
+   ADLIBFX_SendOutput( 0xe3, sound->cWave );
+
+   ADLIBFX_SendOutput( 0xc0, 0 );
+
+   RestoreInterrupts( flags );
+
+   return( ADLIBFX_VoiceHandle );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: ADLIBFX_SoundPlaying
+
+   Checks if a sound effect is currently playing.
+---------------------------------------------------------------------*/
+
+int ADLIBFX_SoundPlaying
+   (
+   int handle
+   )
+
+   {
+   int status;
+
+   status = FALSE;
+   if ( ( handle == ADLIBFX_VoiceHandle ) && ( ADLIBFX_LengthLeft > 0 ) )
+      {
+      status = TRUE;
+      }
+
+   return( status );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: ADLIBFX_LockEnd
+
+   Used for determining the length of the functions to lock in memory.
+---------------------------------------------------------------------*/
+
+static void ADLIBFX_LockEnd
+   (
+   void
+   )
+
+   {
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: ADLIBFX_SetCallBack
+
+   Set the function to call when a voice stops.
+---------------------------------------------------------------------*/
+
+void ADLIBFX_SetCallBack
+   (
+   void ( *function )( unsigned long )
+   )
+
+   {
+   ADLIBFX_CallBackFunc = function;
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: ADLIBFX_Init
+
+   Initializes the sound effect engine.
+---------------------------------------------------------------------*/
+
+int ADLIBFX_Init
+   (
+   void
+   )
+
+   {
+   int status;
+
+   if ( ADLIBFX_Installed )
+      {
+      ADLIBFX_Shutdown();
+      }
+
+   status  = DPMI_LockMemoryRegion( ADLIBFX_LockStart, ADLIBFX_LockEnd );
+   status |= DPMI_Lock( ADLIBFX_VoiceHandle );
+   status |= DPMI_Lock( ADLIBFX_Sound );
+   status |= DPMI_Lock( ADLIBFX_ErrorCode );
+   status |= DPMI_Lock( ADLIBFX_SoundPtr );
+   status |= DPMI_Lock( ADLIBFX_LengthLeft );
+   status |= DPMI_Lock( ADLIBFX_Priority );
+   status |= DPMI_Lock( ADLIBFX_CallBackFunc );
+   status |= DPMI_Lock( ADLIBFX_Block );
+
+   if ( status != DPMI_Ok )
+      {
+      ADLIBFX_SetErrorCode( ADLIBFX_DPMI_Error );
+      return( ADLIBFX_Error );
+      }
+
+//JIM
+//   AL_ReserveVoice( 0 );
+   ADLIBFX_Stop( ADLIBFX_VoiceHandle );
+   ADLIBFX_ServiceTask = TS_ScheduleTask( &ADLIBFX_Service, 140, 2, NULL );
+   TS_Dispatch();
+   ADLIBFX_Installed = TRUE;
+   ADLIBFX_CallBackFunc = NULL;
+
+   ADLIBFX_SetErrorCode( ADLIBFX_Ok );
+   return( ADLIBFX_Ok );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: ADLIBFX_Shutdown
+
+   Ends the use of the sound effect engine.
+---------------------------------------------------------------------*/
+
+int ADLIBFX_Shutdown
+   (
+   void
+   )
+
+   {
+   if ( ADLIBFX_Installed )
+      {
+      ADLIBFX_Stop( ADLIBFX_VoiceHandle );
+      TS_Terminate( ADLIBFX_ServiceTask );
+      ADLIBFX_ServiceTask = NULL;
+//JIM
+//      AL_ReleaseVoice( 0 );
+      ADLIBFX_Installed = FALSE;
+
+      DPMI_UnlockMemoryRegion( ADLIBFX_LockStart, ADLIBFX_LockEnd );
+      DPMI_Unlock( ADLIBFX_VoiceHandle );
+      DPMI_Unlock( ADLIBFX_Sound );
+      DPMI_Unlock( ADLIBFX_ErrorCode );
+      DPMI_Unlock( ADLIBFX_SoundPtr );
+      DPMI_Unlock( ADLIBFX_LengthLeft );
+      DPMI_Unlock( ADLIBFX_Priority );
+      DPMI_Unlock( ADLIBFX_CallBackFunc );
+      DPMI_Unlock( ADLIBFX_Block );
+      }
+
+   ADLIBFX_SetErrorCode( ADLIBFX_Ok );
+   return( ADLIBFX_Ok );
+   }
--- /dev/null
+++ b/rott/audiolib/adlibfx.h
@@ -1,0 +1,80 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+/**********************************************************************
+   module: ADLIBFX.H
+
+   author: James R. Dose
+   date:   April 1, 1994
+
+   Public header for ADLIBFX.C
+
+   (c) Copyright 1994 James R. Dose.  All Rights Reserved.
+**********************************************************************/
+
+#ifndef __ADLIBFX_H
+#define __ADLIBFX_H
+
+enum ADLIBFX_Errors
+   {
+   ADLIBFX_Warning = -2,
+   ADLIBFX_Error   = -1,
+   ADLIBFX_Ok      = 0,
+   ADLIBFX_NoVoices,
+   ADLIBFX_VoiceNotFound,
+   ADLIBFX_DPMI_Error
+   };
+
+typedef	struct
+   {
+   unsigned long  length;
+   short int      priority;
+   char           mChar, cChar;
+   char           mScale, cScale;
+   char           mAttack, cAttack;
+   char           mSus, cSus;
+   char           mWave, cWave;
+   char           nConn;
+   char           voice;
+   char           mode;
+   char           unused[ 3 ];
+   char           block;
+   char           data[];
+   } ALSound;
+
+#define ADLIBFX_MaxVolume      255
+#define ADLIBFX_MinVoiceHandle 1
+
+char *ADLIBFX_ErrorString( int ErrorNumber );
+int   ADLIBFX_Stop( int handle );
+int   ADLIBFX_SetVolume( int handle, int volume );
+int   ADLIBFX_SetTotalVolume( int volume );
+int   ADLIBFX_GetTotalVolume( void );
+int   ADLIBFX_VoiceAvailable( int priority );
+int   ADLIBFX_Play( ALSound *sound, int volume, int priority, unsigned long callbackval );
+int   ADLIBFX_SoundPlaying( int handle );
+void  ADLIBFX_SetCallBack( void ( *function )( unsigned long ) );
+int   ADLIBFX_Init( void );
+int   ADLIBFX_Shutdown( void );
+   #pragma aux ADLIBFX_Shutdown frame;
+void  PCFX_UnlockMemory( void );
+   #pragma aux ADLIBFX_UnlockMemory frame;
+int   PCFX_LockMemory( void );
+
+#endif
--- /dev/null
+++ b/rott/audiolib/al_midi.c
@@ -1,0 +1,1510 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+/**********************************************************************
+   module: AL_MIDI.C
+
+   author: James R. Dose
+   date:   April 1, 1994
+
+   Low level routines to support General MIDI music on Adlib compatible
+   cards.
+
+   (c) Copyright 1994 James R. Dose.  All Rights Reserved.
+**********************************************************************/
+
+#include <conio.h>
+#include <dos.h>
+#include <stddef.h>
+#include <stdlib.h>
+//#include <math.h>
+#include "dpmi.h"
+#include "interrup.h"
+#include "sndcards.h"
+#include "blaster.h"
+#include "user.h"
+#include "al_midi.h"
+#include "_al_midi.h"
+#include "ll_man.h"
+
+#define TRUE  ( 1 == 1 )
+#define FALSE ( !TRUE )
+
+static unsigned OctavePitch[ MAX_OCTAVE + 1 ] =
+   {
+   OCTAVE_0, OCTAVE_1, OCTAVE_2, OCTAVE_3,
+   OCTAVE_4, OCTAVE_5, OCTAVE_6, OCTAVE_7,
+   };
+
+static unsigned NoteMod12[ MAX_NOTE + 1 ];
+static unsigned NoteDiv12[ MAX_NOTE + 1 ];
+
+// Pitch table
+
+//static unsigned NotePitch[ FINETUNE_MAX + 1 ][ 12 ] =
+//   {
+//      { C, C_SHARP, D, D_SHARP, E, F, F_SHARP, G, G_SHARP, A, A_SHARP, B },
+//   };
+
+static unsigned NotePitch[ FINETUNE_MAX + 1 ][ 12 ] =
+   {
+      { 0x157, 0x16b, 0x181, 0x198, 0x1b0, 0x1ca, 0x1e5, 0x202, 0x220, 0x241, 0x263, 0x287 },
+      { 0x157, 0x16b, 0x181, 0x198, 0x1b0, 0x1ca, 0x1e5, 0x202, 0x220, 0x242, 0x264, 0x288 },
+      { 0x158, 0x16c, 0x182, 0x199, 0x1b1, 0x1cb, 0x1e6, 0x203, 0x221, 0x243, 0x265, 0x289 },
+      { 0x158, 0x16c, 0x183, 0x19a, 0x1b2, 0x1cc, 0x1e7, 0x204, 0x222, 0x244, 0x266, 0x28a },
+      { 0x159, 0x16d, 0x183, 0x19a, 0x1b3, 0x1cd, 0x1e8, 0x205, 0x223, 0x245, 0x267, 0x28b },
+      { 0x15a, 0x16e, 0x184, 0x19b, 0x1b3, 0x1ce, 0x1e9, 0x206, 0x224, 0x246, 0x268, 0x28c },
+      { 0x15a, 0x16e, 0x185, 0x19c, 0x1b4, 0x1ce, 0x1ea, 0x207, 0x225, 0x247, 0x269, 0x28e },
+      { 0x15b, 0x16f, 0x185, 0x19d, 0x1b5, 0x1cf, 0x1eb, 0x208, 0x226, 0x248, 0x26a, 0x28f },
+      { 0x15b, 0x170, 0x186, 0x19d, 0x1b6, 0x1d0, 0x1ec, 0x209, 0x227, 0x249, 0x26b, 0x290 },
+      { 0x15c, 0x170, 0x187, 0x19e, 0x1b7, 0x1d1, 0x1ec, 0x20a, 0x228, 0x24a, 0x26d, 0x291 },
+      { 0x15d, 0x171, 0x188, 0x19f, 0x1b7, 0x1d2, 0x1ed, 0x20b, 0x229, 0x24b, 0x26e, 0x292 },
+      { 0x15d, 0x172, 0x188, 0x1a0, 0x1b8, 0x1d3, 0x1ee, 0x20c, 0x22a, 0x24c, 0x26f, 0x293 },
+      { 0x15e, 0x172, 0x189, 0x1a0, 0x1b9, 0x1d4, 0x1ef, 0x20d, 0x22b, 0x24d, 0x270, 0x295 },
+      { 0x15f, 0x173, 0x18a, 0x1a1, 0x1ba, 0x1d4, 0x1f0, 0x20e, 0x22c, 0x24e, 0x271, 0x296 },
+      { 0x15f, 0x174, 0x18a, 0x1a2, 0x1bb, 0x1d5, 0x1f1, 0x20f, 0x22d, 0x24f, 0x272, 0x297 },
+      { 0x160, 0x174, 0x18b, 0x1a3, 0x1bb, 0x1d6, 0x1f2, 0x210, 0x22e, 0x250, 0x273, 0x298 },
+      { 0x161, 0x175, 0x18c, 0x1a3, 0x1bc, 0x1d7, 0x1f3, 0x211, 0x22f, 0x251, 0x274, 0x299 },
+      { 0x161, 0x176, 0x18c, 0x1a4, 0x1bd, 0x1d8, 0x1f4, 0x212, 0x230, 0x252, 0x276, 0x29b },
+      { 0x162, 0x176, 0x18d, 0x1a5, 0x1be, 0x1d9, 0x1f5, 0x212, 0x231, 0x254, 0x277, 0x29c },
+      { 0x162, 0x177, 0x18e, 0x1a6, 0x1bf, 0x1d9, 0x1f5, 0x213, 0x232, 0x255, 0x278, 0x29d },
+      { 0x163, 0x178, 0x18f, 0x1a6, 0x1bf, 0x1da, 0x1f6, 0x214, 0x233, 0x256, 0x279, 0x29e },
+      { 0x164, 0x179, 0x18f, 0x1a7, 0x1c0, 0x1db, 0x1f7, 0x215, 0x235, 0x257, 0x27a, 0x29f },
+      { 0x164, 0x179, 0x190, 0x1a8, 0x1c1, 0x1dc, 0x1f8, 0x216, 0x236, 0x258, 0x27b, 0x2a1 },
+      { 0x165, 0x17a, 0x191, 0x1a9, 0x1c2, 0x1dd, 0x1f9, 0x217, 0x237, 0x259, 0x27c, 0x2a2 },
+      { 0x166, 0x17b, 0x192, 0x1aa, 0x1c3, 0x1de, 0x1fa, 0x218, 0x238, 0x25a, 0x27e, 0x2a3 },
+      { 0x166, 0x17b, 0x192, 0x1aa, 0x1c3, 0x1df, 0x1fb, 0x219, 0x239, 0x25b, 0x27f, 0x2a4 },
+      { 0x167, 0x17c, 0x193, 0x1ab, 0x1c4, 0x1e0, 0x1fc, 0x21a, 0x23a, 0x25c, 0x280, 0x2a6 },
+      { 0x168, 0x17d, 0x194, 0x1ac, 0x1c5, 0x1e0, 0x1fd, 0x21b, 0x23b, 0x25d, 0x281, 0x2a7 },
+      { 0x168, 0x17d, 0x194, 0x1ad, 0x1c6, 0x1e1, 0x1fe, 0x21c, 0x23c, 0x25e, 0x282, 0x2a8 },
+      { 0x169, 0x17e, 0x195, 0x1ad, 0x1c7, 0x1e2, 0x1ff, 0x21d, 0x23d, 0x260, 0x283, 0x2a9 },
+      { 0x16a, 0x17f, 0x196, 0x1ae, 0x1c8, 0x1e3, 0x1ff, 0x21e, 0x23e, 0x261, 0x284, 0x2ab },
+      { 0x16a, 0x17f, 0x197, 0x1af, 0x1c8, 0x1e4, 0x200, 0x21f, 0x23f, 0x262, 0x286, 0x2ac }
+   };
+
+// Slot numbers as a function of the voice and the operator.
+// ( melodic only)
+
+static int slotVoice[ NUM_VOICES ][ 2 ] =
+   {
+      { 0, 3 },    // voice 0
+      { 1, 4 },    // 1
+      { 2, 5 },    // 2
+      { 6, 9 },    // 3
+      { 7, 10 },   // 4
+      { 8, 11 },   // 5
+      { 12, 15 },  // 6
+      { 13, 16 },  // 7
+      { 14, 17 },  // 8
+   };
+
+static int VoiceLevel[ NumChipSlots ][ 2 ];
+static int VoiceKsl[ NumChipSlots ][ 2 ];
+
+// This table gives the offset of each slot within the chip.
+// offset = fn( slot)
+
+static char offsetSlot[ NumChipSlots ] =
+   {
+    0,  1,  2,  3,  4,  5,
+    8,  9, 10, 11, 12, 13,
+   16, 17, 18, 19, 20, 21
+   };
+
+static int VoiceReserved[ NUM_VOICES * 2 ] =
+   {
+   FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
+   FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE
+   };
+
+static VOICE     Voice[ NUM_VOICES * 2 ];
+static VOICELIST Voice_Pool;
+
+static CHANNEL   Channel[ NUM_CHANNELS ];
+
+static int AL_LeftPort   = 0x388;
+static int AL_RightPort  = 0x388;
+static int AL_Stereo     = FALSE;
+static int AL_SendStereo = FALSE;
+static int AL_OPL3       = FALSE;
+static int AL_MaxMidiChannel = 16;
+
+
+/**********************************************************************
+
+   Memory locked functions:
+
+**********************************************************************/
+
+
+#define AL_LockStart AL_SendOutputToPort
+
+
+/*---------------------------------------------------------------------
+   Function: AL_SendOutputToPort
+
+   Sends data to the Adlib using a specified port.
+---------------------------------------------------------------------*/
+
+void AL_SendOutputToPort
+   (
+   int  port,
+   int  reg,
+   int  data
+   )
+
+   {
+   int delay;
+
+   outp( port, reg );
+
+   for( delay = 6; delay > 0 ; delay-- )
+//   for( delay = 2; delay > 0 ; delay-- )
+      {
+      inp( port );
+      }
+
+   outp( port + 1, data );
+
+//   for( delay = 35; delay > 0 ; delay-- )
+   for( delay = 27; delay > 0 ; delay-- )
+//   for( delay = 2; delay > 0 ; delay-- )
+      {
+      inp( port );
+      }
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: AL_SendOutput
+
+   Sends data to the Adlib.
+---------------------------------------------------------------------*/
+
+void AL_SendOutput
+   (
+   int  voice,
+   int  reg,
+   int  data
+   )
+
+   {
+   int port;
+
+   if ( AL_SendStereo )
+      {
+      AL_SendOutputToPort( AL_LeftPort, reg, data );
+      AL_SendOutputToPort( AL_RightPort, reg, data );
+      }
+   else
+      {
+      port = ( voice == 0 ) ? AL_RightPort : AL_LeftPort;
+      AL_SendOutputToPort( port, reg, data );
+      }
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: AL_SetVoiceTimbre
+
+   Programs the specified voice's timbre.
+---------------------------------------------------------------------*/
+
+static void AL_SetVoiceTimbre
+   (
+   int voice
+   )
+
+   {
+   int    off;
+   int    slot;
+   int    port;
+   int    voc;
+   int    patch;
+   int    channel;
+   TIMBRE *timbre;
+
+   channel = Voice[ voice ].channel;
+
+   if ( channel == 9 )
+      {
+      patch = Voice[ voice ].key + 128;
+      }
+   else
+      {
+      patch = Channel[ channel ].Timbre;
+      }
+
+   if ( Voice[ voice ].timbre == patch )
+      {
+      return;
+      }
+
+   Voice[ voice ].timbre = patch;
+   timbre = &ADLIB_TimbreBank[ patch ];
+
+   port = Voice[ voice ].port;
+   voc  = ( voice >= NUM_VOICES ) ? voice - NUM_VOICES : voice;
+   slot = slotVoice[ voc ][ 0 ];
+   off  = offsetSlot[ slot ];
+
+   VoiceLevel[ slot ][ port ] = 63 - ( timbre->Level[ 0 ] & 0x3f );
+   VoiceKsl[ slot ][ port ]   = timbre->Level[ 0 ] & 0xc0;
+
+   AL_SendOutput( port, 0xA0 + voc, 0 );
+   AL_SendOutput( port, 0xB0 + voc, 0 );
+
+   // Let voice clear the release
+   AL_SendOutput( port, 0x80 + off, 0xff );
+
+   AL_SendOutput( port, 0x60 + off, timbre->Env1[ 0 ] );
+   AL_SendOutput( port, 0x80 + off, timbre->Env2[ 0 ] );
+   AL_SendOutput( port, 0x20 + off, timbre->SAVEK[ 0 ] );
+   AL_SendOutput( port, 0xE0 + off, timbre->Wave[ 0 ] );
+
+   AL_SendOutput( port, 0x40 + off, timbre->Level[ 0 ] );
+   slot = slotVoice[ voc ][ 1 ];
+
+   if ( AL_SendStereo )
+      {
+      AL_SendOutputToPort( AL_LeftPort, 0xC0 + voice,
+         ( timbre->Feedback & 0x0f ) | 0x20 );
+      AL_SendOutputToPort( AL_RightPort, 0xC0 + voice,
+         ( timbre->Feedback & 0x0f ) | 0x10 );
+      }
+   else
+      {
+      if ( AL_OPL3 )
+         {
+         AL_SendOutput( port, 0xC0 + voc, ( timbre->Feedback & 0x0f ) |
+            0x30 );
+         }
+      else
+         {
+         AL_SendOutputToPort( ADLIB_PORT, 0xC0 + voice, timbre->Feedback );
+         }
+      }
+
+   off = offsetSlot[ slot ];
+
+   VoiceLevel[ slot ][ port ] = 63 - ( timbre->Level[ 1 ] & 0x3f );
+   VoiceKsl[ slot ][ port ]   = timbre->Level[ 1 ] & 0xc0;
+   AL_SendOutput( port, 0x40 + off, 63 );
+
+   // Let voice clear the release
+   AL_SendOutput( port, 0x80 + off, 0xff );
+
+   AL_SendOutput( port, 0x60 + off, timbre->Env1[ 1 ] );
+   AL_SendOutput( port, 0x80 + off, timbre->Env2[ 1 ] );
+   AL_SendOutput( port, 0x20 + off, timbre->SAVEK[ 1 ] );
+   AL_SendOutput( port, 0xE0 + off, timbre->Wave[ 1 ] );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: AL_SetVoiceVolume
+
+   Sets the volume of the specified voice.
+---------------------------------------------------------------------*/
+
+static void AL_SetVoiceVolume
+   (
+   int voice
+   )
+
+   {
+   int channel;
+   int velocity;
+   int slot;
+   int port;
+   int voc;
+   unsigned long t1;
+   unsigned long t2;
+   unsigned long volume;
+   TIMBRE *timbre;
+
+   channel = Voice[ voice ].channel;
+
+   timbre = &ADLIB_TimbreBank[ Voice[ voice ].timbre ];
+
+   velocity = Voice[ voice ].velocity + timbre->Velocity;
+   velocity = min( velocity, MAX_VELOCITY );
+
+   voc  = ( voice >= NUM_VOICES ) ? voice - NUM_VOICES : voice;
+   slot = slotVoice[ voc ][ 1 ];
+   port = Voice[ voice ].port;
+
+   // amplitude
+   t1  = ( unsigned )VoiceLevel[ slot ][ port ];
+   t1 *= ( velocity + 0x80 );
+   t1  = ( Channel[ channel ].Volume * t1 ) >> 15;
+
+   if ( !AL_SendStereo )
+      {
+      volume  = t1 ^ 63;
+      volume |= ( unsigned )VoiceKsl[ slot ][ port ];
+
+      AL_SendOutput( port, 0x40 + offsetSlot[ slot ], volume );
+
+      // Check if this timbre is Additive
+      if ( timbre->Feedback & 0x01 )
+         {
+         slot = slotVoice[ voc ][ 0 ];
+
+         // amplitude
+         t2  = ( unsigned )VoiceLevel[ slot ][ port ];
+         t2 *= ( velocity + 0x80 );
+         t2  = ( Channel[ channel ].Volume * t1 ) >> 15;
+
+         volume  = t2 ^ 63;
+         volume |= ( unsigned )VoiceKsl[ slot ][ port ];
+
+         AL_SendOutput( port, 0x40 + offsetSlot[ slot ], volume );
+         }
+      }
+   else
+      {
+      // Set left channel volume
+      volume = t1;
+      if ( Channel[ channel ].Pan < 64 )
+         {
+         volume *= Channel[ channel ].Pan;
+         volume >>= 6;
+         }
+
+      volume ^= 63;
+      volume |= ( unsigned )VoiceKsl[ slot ][ port ];
+
+      AL_SendOutputToPort( AL_LeftPort, 0x40 + offsetSlot[ slot ], volume );
+
+      // Set right channel volume
+      volume = t1;
+      if ( Channel[ channel ].Pan > 64 )
+         {
+         volume *= 127 - Channel[ channel ].Pan;
+         volume >>= 6;
+         }
+
+      volume ^= 63;
+      volume |= ( unsigned )VoiceKsl[ slot ][ port ];
+
+      AL_SendOutputToPort( AL_RightPort, 0x40 + offsetSlot[ slot ], volume );
+
+      // Check if this timbre is Additive
+      if ( timbre->Feedback & 0x01 )
+         {
+         // amplitude
+         t2  = ( unsigned )VoiceLevel[ slot ][ port ];
+         t2 *= ( velocity + 0x80 );
+         t2  = ( Channel[ channel ].Volume * t1 ) >> 15;
+
+         slot = slotVoice[ voc ][ 0 ];
+
+         // Set left channel volume
+         volume = t2;
+         if ( Channel[ channel ].Pan < 64 )
+            {
+            volume *= Channel[ channel ].Pan;
+            volume >>= 6;
+            }
+
+         volume ^= 63;
+         volume |= ( unsigned )VoiceKsl[ slot ][ port ];
+
+         AL_SendOutputToPort( AL_LeftPort, 0x40 + offsetSlot[ slot ], volume );
+
+         // Set right channel volume
+         volume = t2;
+         if ( Channel[ channel ].Pan > 64 )
+            {
+            volume *= 127 - Channel[ channel ].Pan;
+            volume >>= 6;
+            }
+
+         volume ^= 63;
+         volume |= ( unsigned )VoiceKsl[ slot ][ port ];
+
+         AL_SendOutputToPort( AL_RightPort, 0x40 + offsetSlot[ slot ], volume );
+         }
+      }
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: AL_AllocVoice
+
+   Retrieves a free voice from the voice pool.
+---------------------------------------------------------------------*/
+
+static int AL_AllocVoice
+   (
+   void
+   )
+
+   {
+   int voice;
+
+   if ( Voice_Pool.start )
+      {
+      voice = Voice_Pool.start->num;
+      LL_Remove( VOICE, &Voice_Pool, &Voice[ voice ] );
+      return( voice );
+      }
+
+   return( AL_VoiceNotFound );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: AL_GetVoice
+
+   Determines which voice is associated with a specified note and
+   MIDI channel.
+---------------------------------------------------------------------*/
+
+static int AL_GetVoice
+   (
+   int channel,
+   int key
+   )
+
+   {
+   VOICE *voice;
+
+   voice = Channel[ channel ].Voices.start;
+
+   while( voice != NULL )
+      {
+      if ( voice->key == key )
+         {
+         return( voice->num );
+         }
+      voice = voice->next;
+      }
+
+   return( AL_VoiceNotFound );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: AL_SetVoicePitch
+
+   Programs the pitch of the specified voice.
+---------------------------------------------------------------------*/
+
+static void AL_SetVoicePitch
+   (
+   int voice
+   )
+
+   {
+   int note;
+   int channel;
+   int patch;
+   int detune;
+   int ScaleNote;
+   int Octave;
+   int pitch;
+   int port;
+   int voc;
+
+   port = Voice[ voice ].port;
+   voc  = ( voice >= NUM_VOICES ) ? voice - NUM_VOICES : voice;
+   channel = Voice[ voice ].channel;
+
+   if ( channel == 9 )
+      {
+      patch = Voice[ voice ].key + 128;
+      note  = ADLIB_TimbreBank[ patch ].Transpose;
+      }
+   else
+      {
+      patch = Channel[ channel ].Timbre;
+      note  = Voice[ voice ].key + ADLIB_TimbreBank[ patch ].Transpose;
+      }
+
+   note += Channel[ channel ].KeyOffset - 12;
+   if ( note > MAX_NOTE )
+      {
+      note = MAX_NOTE;
+      }
+   if ( note < 0 )
+      {
+      note = 0;
+      }
+
+   detune = Channel[ channel ].KeyDetune;
+
+   ScaleNote = NoteMod12[ note ];
+   Octave    = NoteDiv12[ note ];
+
+   pitch = OctavePitch[ Octave ] | NotePitch[ detune ][ ScaleNote ];
+
+   Voice[ voice ].pitchleft = pitch;
+
+   pitch |= Voice[ voice ].status;
+
+   if ( !AL_SendStereo )
+      {
+      AL_SendOutput( port, 0xA0 + voc, pitch );
+      AL_SendOutput( port, 0xB0 + voc, pitch >> 8 );
+      }
+   else
+      {
+      AL_SendOutputToPort( AL_LeftPort, 0xA0 + voice, pitch );
+      AL_SendOutputToPort( AL_LeftPort, 0xB0 + voice, pitch >> 8 );
+
+      if ( channel != 9 )
+         {
+         detune += STEREO_DETUNE;
+         }
+
+      if ( detune > FINETUNE_MAX )
+         {
+         detune -= FINETUNE_RANGE;
+         if ( note < MAX_NOTE )
+            {
+            note++;
+            ScaleNote = NoteMod12[ note ];
+            Octave    = NoteDiv12[ note ];
+            }
+         }
+
+      pitch = OctavePitch[ Octave ] | NotePitch[ detune ][ ScaleNote ];
+
+      Voice[ voice ].pitchright = pitch;
+
+      pitch |= Voice[ voice ].status;
+
+      AL_SendOutputToPort( AL_RightPort, 0xA0 + voice, pitch );
+      AL_SendOutputToPort( AL_RightPort, 0xB0 + voice, pitch >> 8 );
+      }
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: AL_SetChannelVolume
+
+   Sets the volume of the specified MIDI channel.
+---------------------------------------------------------------------*/
+
+static void AL_SetChannelVolume
+   (
+   int channel,
+   int volume
+   )
+
+   {
+   VOICE *voice;
+
+   volume = max( 0, volume );
+   volume = min( volume, AL_MaxVolume );
+   Channel[ channel ].Volume = volume;
+
+   voice = Channel[ channel ].Voices.start;
+   while( voice != NULL )
+      {
+      AL_SetVoiceVolume( voice->num );
+      voice = voice->next;
+      }
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: AL_SetChannelPan
+
+   Sets the pan position of the specified MIDI channel.
+---------------------------------------------------------------------*/
+
+static void AL_SetChannelPan
+   (
+   int channel,
+   int pan
+   )
+
+   {
+   // Don't pan drum sounds
+   if ( channel != 9 )
+      {
+      Channel[ channel ].Pan = pan;
+      }
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: AL_SetChannelDetune
+
+   Sets the stereo voice detune of the specified MIDI channel.
+---------------------------------------------------------------------*/
+
+static void AL_SetChannelDetune
+   (
+   int channel,
+   int detune
+   )
+
+   {
+   Channel[ channel ].Detune = detune;
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: AL_ResetVoices
+
+   Sets all voice info to the default state.
+---------------------------------------------------------------------*/
+
+static void AL_ResetVoices
+   (
+   void
+   )
+
+   {
+   int index;
+   int numvoices;
+
+   Voice_Pool.start = NULL;
+   Voice_Pool.end = NULL;
+
+   numvoices = NUM_VOICES;
+   if ( ( AL_OPL3 ) && ( !AL_Stereo ) )
+      {
+      numvoices = NUM_VOICES * 2;
+      }
+   for( index = 0; index < numvoices; index++ )
+      {
+      if ( VoiceReserved[ index ] == FALSE )
+         {
+         Voice[ index ].num = index;
+         Voice[ index ].key = 0;
+         Voice[ index ].velocity = 0;
+         Voice[ index ].channel = -1;
+         Voice[ index ].timbre = -1;
+         Voice[ index ].port = ( index < NUM_VOICES ) ? 0 : 1;
+         Voice[ index ].status = NOTE_OFF;
+         LL_AddToTail( VOICE, &Voice_Pool, &Voice[ index ] );
+         }
+      }
+
+   for( index = 0; index < NUM_CHANNELS; index++ )
+      {
+      Channel[ index ].Voices.start    = NULL;
+      Channel[ index ].Voices.end      = NULL;
+      Channel[ index ].Timbre          = 0;
+      Channel[ index ].Pitchbend       = 0;
+      Channel[ index ].KeyOffset       = 0;
+      Channel[ index ].KeyDetune       = 0;
+      Channel[ index ].Volume          = AL_DefaultChannelVolume;
+      Channel[ index ].Pan             = 64;
+      Channel[ index ].RPN             = 0;
+      Channel[ index ].PitchBendRange     = AL_DefaultPitchBendRange;
+      Channel[ index ].PitchBendSemiTones = AL_DefaultPitchBendRange / 100;
+      Channel[ index ].PitchBendHundreds  = AL_DefaultPitchBendRange % 100;
+      }
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: AL_CalcPitchInfo
+
+   Calculates the pitch table.
+---------------------------------------------------------------------*/
+
+static void AL_CalcPitchInfo
+   (
+   void
+   )
+
+   {
+   int    note;
+//   int    finetune;
+//   double detune;
+
+   for( note = 0; note <= MAX_NOTE; note++ )
+      {
+      NoteMod12[ note ] = note % 12;
+      NoteDiv12[ note ] = note / 12;
+      }
+
+//   for( finetune = 1; finetune <= FINETUNE_MAX; finetune++ )
+//      {
+//      detune = pow( 2, ( double )finetune / ( 12.0 * FINETUNE_RANGE ) );
+//      for( note = 0; note < 12; note++ )
+//         {
+//         NotePitch[ finetune ][ note ] = ( ( double )NotePitch[ 0 ][ note ] * detune );
+//         }
+//      }
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: AL_FlushCard
+
+   Sets all voices to a known (quiet) state.
+---------------------------------------------------------------------*/
+
+void AL_FlushCard
+   (
+   int port
+   )
+
+   {
+   int i;
+   unsigned slot1;
+   unsigned slot2;
+
+   for( i = 0 ; i < NUM_VOICES; i++ )
+      {
+      if ( VoiceReserved[ i ] == FALSE )
+         {
+         slot1 = offsetSlot[ slotVoice[ i ][ 0 ] ];
+         slot2 = offsetSlot[ slotVoice[ i ][ 1 ] ];
+
+         AL_SendOutputToPort( port, 0xA0 + i, 0 );
+         AL_SendOutputToPort( port, 0xB0 + i, 0 );
+
+         AL_SendOutputToPort( port, 0xE0 + slot1, 0 );
+         AL_SendOutputToPort( port, 0xE0 + slot2, 0 );
+
+         // Set the envelope to be fast and quiet
+         AL_SendOutputToPort( port, 0x60 + slot1, 0xff );
+         AL_SendOutputToPort( port, 0x60 + slot2, 0xff );
+         AL_SendOutputToPort( port, 0x80 + slot1, 0xff );
+         AL_SendOutputToPort( port, 0x80 + slot2, 0xff );
+
+         // Maximum attenuation
+         AL_SendOutputToPort( port, 0x40 + slot1, 0xff );
+         AL_SendOutputToPort( port, 0x40 + slot2, 0xff );
+         }
+      }
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: AL_StereoOn
+
+   Sets the card send info in stereo.
+---------------------------------------------------------------------*/
+
+void AL_StereoOn
+   (
+   void
+   )
+
+   {
+   if ( ( AL_Stereo ) && ( !AL_SendStereo ) )
+      {
+      AL_SendStereo = TRUE;
+      if ( AL_OPL3 )
+         {
+         // Set card to OPL3 operation
+         AL_SendOutputToPort( AL_RightPort, 0x5, 1 );
+         }
+      }
+   else if ( AL_OPL3 )
+      {
+      // Set card to OPL3 operation
+      AL_SendOutputToPort( AL_RightPort, 0x5, 1 );
+      }
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: AL_StereoOff
+
+   Sets the card send info in mono.
+---------------------------------------------------------------------*/
+
+void AL_StereoOff
+   (
+   void
+   )
+
+   {
+   if ( ( AL_Stereo ) && ( AL_SendStereo ) )
+      {
+      AL_SendStereo = FALSE;
+      if ( AL_OPL3 )
+         {
+         // Set card back to OPL2 operation
+         AL_SendOutputToPort( AL_RightPort, 0x5, 0 );
+         }
+      }
+   else if ( AL_OPL3 )
+      {
+      // Set card back to OPL2 operation
+      AL_SendOutputToPort( AL_RightPort, 0x5, 0 );
+      }
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: AL_Reset
+
+   Sets the card to a known (quiet) state.
+---------------------------------------------------------------------*/
+
+void AL_Reset
+   (
+   void
+   )
+
+   {
+   AL_SendOutputToPort( ADLIB_PORT, 1, 0x20 );
+   AL_SendOutputToPort( ADLIB_PORT, 0x08, 0 );
+
+   // Set the values: AM Depth, VIB depth & Rhythm
+   AL_SendOutputToPort( ADLIB_PORT, 0xBD, 0 );
+
+   AL_StereoOn();
+
+   if ( ( AL_SendStereo ) || ( AL_OPL3 ) )
+      {
+      AL_FlushCard( AL_LeftPort );
+      AL_FlushCard( AL_RightPort );
+      }
+   else
+      {
+      AL_FlushCard( ADLIB_PORT );
+      }
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: AL_ReserveVoice
+
+   Marks a voice as being not available for use.  This allows the
+   driver to use the rest of the card while another driver uses the
+   reserved voice.
+---------------------------------------------------------------------*/
+
+int AL_ReserveVoice
+   (
+   int voice
+   )
+
+   {
+   unsigned flags;
+
+   if ( ( voice < 0 ) || ( voice >= NUM_VOICES ) )
+      {
+      return( AL_Error );
+      }
+
+   if ( VoiceReserved[ voice ] )
+      {
+      return( AL_Warning );
+      }
+
+   flags = DisableInterrupts();
+
+   if ( Voice[ voice ].status == NOTE_ON )
+      {
+      AL_NoteOff( Voice[ voice ].channel, Voice[ voice ].key, 0 );
+      }
+
+   VoiceReserved[ voice ] = TRUE;
+   LL_Remove( VOICE, &Voice_Pool, &Voice[ voice ] );
+
+   RestoreInterrupts( flags );
+   return( AL_Ok );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: AL_ReleaseVoice
+
+   Marks a previously reserved voice as being free to use.
+---------------------------------------------------------------------*/
+
+int AL_ReleaseVoice
+   (
+   int voice
+   )
+
+   {
+   unsigned flags;
+
+   if ( ( voice < 0 ) || ( voice >= NUM_VOICES ) )
+      {
+      return( AL_Error );
+      }
+
+   if ( !VoiceReserved[ voice ] )
+      {
+      return( AL_Warning );
+      }
+
+   flags = DisableInterrupts();
+
+   VoiceReserved[ voice ] = FALSE;
+   LL_AddToTail( VOICE, &Voice_Pool, &Voice[ voice ] );
+
+   RestoreInterrupts( flags );
+   return( AL_Ok );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: AL_NoteOff
+
+   Turns off a note on the specified MIDI channel.
+---------------------------------------------------------------------*/
+
+void AL_NoteOff
+   (
+   int channel,
+   int key,
+   int velocity
+   )
+
+   {
+   int voice;
+   int port;
+   int voc;
+
+   // We only play channels 1 through 10
+   if ( channel > AL_MaxMidiChannel )
+      {
+      return;
+      }
+
+   voice = AL_GetVoice( channel, key );
+
+   if ( voice == AL_VoiceNotFound )
+      {
+      return;
+      }
+
+   Voice[ voice ].status = NOTE_OFF;
+
+   port = Voice[ voice ].port;
+   voc  = ( voice >= NUM_VOICES ) ? voice - NUM_VOICES : voice;
+
+   if ( AL_SendStereo )
+      {
+      AL_SendOutputToPort( AL_LeftPort, 0xB0 + voice,
+         hibyte( Voice[ voice ].pitchleft ) );
+      AL_SendOutputToPort( AL_RightPort, 0xB0 + voice,
+         hibyte( Voice[ voice ].pitchright ) );
+      }
+   else
+      {
+      AL_SendOutput( port, 0xB0 + voc, hibyte( Voice[ voice ].pitchleft ) );
+      }
+
+   LL_Remove( VOICE, &Channel[ channel ].Voices, &Voice[ voice ] );
+   LL_AddToTail( VOICE, &Voice_Pool, &Voice[ voice ] );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: AL_NoteOn
+
+   Plays a note on the specified MIDI channel.
+---------------------------------------------------------------------*/
+
+void AL_NoteOn
+   (
+   int channel,
+   int key,
+   int velocity
+   )
+
+   {
+   int voice;
+
+   // We only play channels 1 through 10
+   if ( channel > AL_MaxMidiChannel )
+      {
+      return;
+      }
+
+   if ( velocity == 0 )
+      {
+      AL_NoteOff( channel, key, velocity );
+      return;
+      }
+
+   voice = AL_AllocVoice();
+
+   if ( voice == AL_VoiceNotFound )
+      {
+      if ( Channel[ 9 ].Voices.start )
+         {
+         AL_NoteOff( 9, Channel[ 9 ].Voices.start->key, 0 );
+         voice = AL_AllocVoice();
+         }
+      if ( voice == AL_VoiceNotFound )
+         {
+         return;
+         }
+      }
+
+   Voice[ voice ].key      = key;
+   Voice[ voice ].channel  = channel;
+   Voice[ voice ].velocity = velocity;
+   Voice[ voice ].status   = NOTE_ON;
+
+   LL_AddToTail( VOICE, &Channel[ channel ].Voices, &Voice[ voice ] );
+
+   AL_SetVoiceTimbre( voice );
+   AL_SetVoiceVolume( voice );
+   AL_SetVoicePitch( voice );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: AL_AllNotesOff
+
+   Turns off all currently playing voices.
+---------------------------------------------------------------------*/
+
+void AL_AllNotesOff
+   (
+   int channel
+   )
+
+   {
+   while( Channel[ channel ].Voices.start != NULL )
+      {
+      AL_NoteOff( channel, Channel[ channel ].Voices.start->key, 0 );
+      }
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: AL_ControlChange
+
+   Sets the value of a controller on the specified MIDI channel.
+---------------------------------------------------------------------*/
+
+void AL_ControlChange
+   (
+   int channel,
+   int type,
+   int data
+   )
+
+   {
+   // We only play channels 1 through 10
+   if ( channel > AL_MaxMidiChannel )
+      {
+      return;
+      }
+
+   switch( type )
+      {
+      case MIDI_VOLUME :
+         AL_SetChannelVolume( channel, data );
+         break;
+
+      case MIDI_PAN :
+         AL_SetChannelPan( channel, data );
+         break;
+
+      case MIDI_DETUNE :
+         AL_SetChannelDetune( channel, data );
+         break;
+
+      case MIDI_ALL_NOTES_OFF :
+         AL_AllNotesOff( channel );
+         break;
+
+      case MIDI_RESET_ALL_CONTROLLERS :
+         AL_ResetVoices();
+         AL_SetChannelVolume( channel, AL_DefaultChannelVolume );
+         AL_SetChannelPan( channel, 64 );
+         AL_SetChannelDetune( channel, 0 );
+         break;
+
+      case MIDI_RPN_MSB :
+         Channel[ channel ].RPN &= 0x00FF;
+         Channel[ channel ].RPN |= ( data & 0xFF ) << 8;
+         break;
+
+      case MIDI_RPN_LSB :
+         Channel[ channel ].RPN &= 0xFF00;
+         Channel[ channel ].RPN |= data & 0xFF;
+         break;
+
+      case MIDI_DATAENTRY_MSB :
+         if ( Channel[ channel ].RPN == MIDI_PITCHBEND_RPN )
+            {
+            Channel[ channel ].PitchBendSemiTones = data;
+            Channel[ channel ].PitchBendRange     =
+               Channel[ channel ].PitchBendSemiTones * 100 +
+               Channel[ channel ].PitchBendHundreds;
+            }
+         break;
+
+      case MIDI_DATAENTRY_LSB :
+         if ( Channel[ channel ].RPN == MIDI_PITCHBEND_RPN )
+            {
+            Channel[ channel ].PitchBendHundreds = data;
+            Channel[ channel ].PitchBendRange    =
+               Channel[ channel ].PitchBendSemiTones * 100 +
+               Channel[ channel ].PitchBendHundreds;
+            }
+         break;
+      }
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: AL_ProgramChange
+
+   Selects the instrument to use on the specified MIDI channel.
+---------------------------------------------------------------------*/
+
+void AL_ProgramChange
+   (
+   int channel,
+   int patch
+   )
+
+   {
+   // We only play channels 1 through 10
+   if ( channel > AL_MaxMidiChannel )
+      {
+      return;
+      }
+
+   Channel[ channel ].Timbre  = patch;
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: AL_SetPitchBend
+
+   Sets the pitch bend amount on the specified MIDI channel.
+---------------------------------------------------------------------*/
+
+void AL_SetPitchBend
+   (
+   int channel,
+   int lsb,
+   int msb
+   )
+
+   {
+   int            pitchbend;
+   unsigned long  TotalBend;
+   VOICE         *voice;
+
+   // We only play channels 1 through 10
+   if ( channel > AL_MaxMidiChannel )
+      {
+      return;
+      }
+
+   pitchbend = lsb + ( msb << 8 );
+   Channel[ channel ].Pitchbend = pitchbend;
+
+   TotalBend  = pitchbend * Channel[ channel ].PitchBendRange;
+   TotalBend /= ( PITCHBEND_CENTER / FINETUNE_RANGE );
+
+   Channel[ channel ].KeyOffset  = ( int )( TotalBend / FINETUNE_RANGE );
+   Channel[ channel ].KeyOffset -= Channel[ channel ].PitchBendSemiTones;
+
+   Channel[ channel ].KeyDetune = ( unsigned )( TotalBend % FINETUNE_RANGE );
+
+   voice = Channel[ channel ].Voices.start;
+   while( voice != NULL )
+      {
+      AL_SetVoicePitch( voice->num );
+      voice = voice->next;
+      }
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: AL_DetectFM
+
+   Determines if an Adlib compatible card is installed in the machine.
+---------------------------------------------------------------------*/
+
+int AL_DetectFM
+   (
+   void
+   )
+
+   {
+   int status1;
+   int status2;
+   int i;
+
+   if ( USER_CheckParameter( NO_ADLIB_DETECTION ) )
+      {
+      return( FALSE );
+      }
+
+   AL_SendOutputToPort( ADLIB_PORT, 4, 0x60 );   // Reset T1 & T2
+   AL_SendOutputToPort( ADLIB_PORT, 4, 0x80 );   // Reset IRQ
+
+   status1 = inp( ADLIB_PORT );
+
+   AL_SendOutputToPort( ADLIB_PORT, 2, 0xff );   // Set timer 1
+   AL_SendOutputToPort( ADLIB_PORT, 4, 0x21 );   // Start timer 1
+
+   for( i = 100; i > 0; i-- )
+      {
+      inp( ADLIB_PORT );
+      }
+
+   status2 = inp( ADLIB_PORT );
+
+   AL_SendOutputToPort( ADLIB_PORT, 4, 0x60 );
+   AL_SendOutputToPort( ADLIB_PORT, 4, 0x80 );
+
+   return( ( ( status1 & 0xe0 ) == 0x00 ) && ( ( status2 & 0xe0 ) == 0xc0 ) );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: AL_LockEnd
+
+   Used for determining the length of the functions to lock in memory.
+---------------------------------------------------------------------*/
+
+static void AL_LockEnd
+   (
+   void
+   )
+
+   {
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: AL_Shutdown
+
+   Ends use of the sound card and resets it to a quiet state.
+---------------------------------------------------------------------*/
+
+void AL_Shutdown
+   (
+   void
+   )
+
+   {
+   AL_StereoOff();
+
+   AL_OPL3 = FALSE;
+   AL_ResetVoices();
+   AL_Reset();
+
+   DPMI_UnlockMemoryRegion( AL_LockStart, AL_LockEnd );
+   DPMI_Unlock( slotVoice );
+   DPMI_Unlock( VoiceLevel );
+   DPMI_Unlock( VoiceKsl );
+   DPMI_Unlock( offsetSlot );
+   DPMI_Unlock( NotePitch );
+   DPMI_Unlock( OctavePitch );
+   DPMI_Unlock( NoteMod12 );
+   DPMI_Unlock( NoteDiv12 );
+   DPMI_Unlock( VoiceReserved );
+   DPMI_Unlock( Voice );
+   DPMI_Unlock( Voice_Pool );
+   DPMI_Unlock( Channel );
+   DPMI_Unlock( AL_LeftPort );
+   DPMI_Unlock( AL_RightPort );
+   DPMI_Unlock( AL_Stereo );
+   DPMI_Unlock( AL_SendStereo );
+   DPMI_Unlock( AL_OPL3 );
+   DPMI_Unlock( AL_MaxMidiChannel );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: AL_SetMaxMidiChannel
+
+   Sets the maximum MIDI channel that FM cards respond to.
+---------------------------------------------------------------------*/
+
+void AL_SetMaxMidiChannel
+   (
+   int channel
+   )
+
+   {
+   AL_MaxMidiChannel = channel - 1;
+   }
+
+/*---------------------------------------------------------------------
+   Function: AL_Init
+
+   Begins use of the sound card.
+---------------------------------------------------------------------*/
+
+int AL_Init
+   (
+   int soundcard
+   )
+
+   {
+   BLASTER_CONFIG Blaster;
+   int status;
+
+   status  = DPMI_LockMemoryRegion( AL_LockStart, AL_LockEnd );
+   status |= DPMI_Lock( slotVoice );
+   status |= DPMI_Lock( VoiceLevel );
+   status |= DPMI_Lock( VoiceKsl );
+   status |= DPMI_Lock( offsetSlot );
+   status |= DPMI_Lock( NotePitch );
+   status |= DPMI_Lock( OctavePitch );
+   status |= DPMI_Lock( NoteMod12 );
+   status |= DPMI_Lock( NoteDiv12 );
+   status |= DPMI_Lock( VoiceReserved );
+   status |= DPMI_Lock( Voice );
+   status |= DPMI_Lock( Voice_Pool );
+   status |= DPMI_Lock( Channel );
+   status |= DPMI_Lock( AL_LeftPort );
+   status |= DPMI_Lock( AL_RightPort );
+   status |= DPMI_Lock( AL_Stereo );
+   status |= DPMI_Lock( AL_SendStereo );
+   status |= DPMI_Lock( AL_OPL3 );
+   status |= DPMI_Lock( AL_MaxMidiChannel );
+
+   if ( status != DPMI_Ok )
+      {
+      return( AL_Error );
+      }
+
+   AL_Stereo = FALSE;
+   AL_OPL3   = FALSE;
+   AL_LeftPort = 0x388;
+   AL_RightPort = 0x388;
+
+   switch( soundcard )
+      {
+      case ProAudioSpectrum :
+      case SoundMan16 :
+         AL_OPL3 = TRUE;
+         AL_LeftPort = 0x388;
+         AL_RightPort = 0x38A;
+         break;
+
+      case SoundBlaster :
+         status = BLASTER_GetCardSettings( &Blaster );
+         if ( status != BLASTER_Ok )
+            {
+            status = BLASTER_GetEnv( &Blaster );
+            if ( status != BLASTER_Ok )
+               {
+               break;
+               }
+            }
+
+         switch( Blaster.Type )
+            {
+            case SBPro2 :
+            case SB16 :
+               AL_OPL3 = TRUE;
+               AL_LeftPort  = Blaster.Address;
+               AL_RightPort = Blaster.Address + 2;
+               break;
+            }
+         break;
+      }
+// Temporarally commented out for ROTT.
+// Stereo FM seems to take too long on some computers and
+// causes the mouse driver to miss interrupts.
+
+/*
+   switch( soundcard )
+      {
+      case ProAudioSpectrum :
+      case SoundMan16 :
+         AL_OPL3 = TRUE;
+         AL_Stereo = TRUE;
+         AL_LeftPort  = 0x388;
+         AL_RightPort = 0x38A;
+         break;
+
+      case SoundBlaster :
+         status = BLASTER_GetCardSettings( &Blaster );
+         if ( status != BLASTER_Ok )
+            {
+            status = BLASTER_GetEnv( &Blaster );
+            if ( status != BLASTER_Ok )
+               {
+               break;
+               }
+            }
+
+         switch( Blaster.Type )
+            {
+            case SBPro2 :
+            case SB16 :
+               AL_OPL3 = TRUE;
+               AL_Stereo = TRUE;
+               AL_LeftPort  = Blaster.Address;
+               AL_RightPort = Blaster.Address + 2;
+               break;
+
+            case SBPro :
+               AL_Stereo = TRUE;
+               AL_LeftPort  = Blaster.Address;
+               AL_RightPort = Blaster.Address + 2;
+               break;
+            }
+         break;
+      }
+*/
+
+   AL_CalcPitchInfo();
+   AL_Reset();
+   AL_ResetVoices();
+
+   return( AL_Ok );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: AL_RegisterTimbreBank
+
+   Copies user supplied timbres over the default timbre bank.
+---------------------------------------------------------------------*/
+
+void AL_RegisterTimbreBank
+   (
+   unsigned char *timbres
+   )
+
+   {
+   int i;
+
+   for( i = 0; i < 256; i++ )
+      {
+      ADLIB_TimbreBank[ i ].SAVEK[ 0 ] = *( timbres++ );
+      ADLIB_TimbreBank[ i ].SAVEK[ 1 ] = *( timbres++ );
+      ADLIB_TimbreBank[ i ].Level[ 0 ] = *( timbres++ );
+      ADLIB_TimbreBank[ i ].Level[ 1 ] = *( timbres++ );
+      ADLIB_TimbreBank[ i ].Env1[ 0 ]  = *( timbres++ );
+      ADLIB_TimbreBank[ i ].Env1[ 1 ]  = *( timbres++ );
+      ADLIB_TimbreBank[ i ].Env2[ 0 ]  = *( timbres++ );
+      ADLIB_TimbreBank[ i ].Env2[ 1 ]  = *( timbres++ );
+      ADLIB_TimbreBank[ i ].Wave[ 0 ]  = *( timbres++ );
+      ADLIB_TimbreBank[ i ].Wave[ 1 ]  = *( timbres++ );
+      ADLIB_TimbreBank[ i ].Feedback   = *( timbres++ );
+      ADLIB_TimbreBank[ i ].Transpose  = *( signed char * )( timbres++ );
+      ADLIB_TimbreBank[ i ].Velocity   = *( signed char * )( timbres++ );
+      }
+   }
--- /dev/null
+++ b/rott/audiolib/al_midi.h
@@ -1,0 +1,58 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+#ifndef __AL_MIDI_H
+#define __AL_MIDI_H
+
+enum AL_Errors
+   {
+   AL_Warning  = -2,
+   AL_Error    = -1,
+   AL_Ok       = 0,
+   };
+
+#define AL_MaxVolume             127
+#define AL_DefaultChannelVolume  90
+//#define AL_DefaultPitchBendRange 2
+#define AL_DefaultPitchBendRange 200
+
+#define ADLIB_PORT 0x388
+
+void AL_SendOutputToPort( int port, int reg, int data );
+void AL_SendOutput( int  voice, int reg, int data );
+void AL_StereoOn( void );
+void AL_StereoOff( void );
+int  AL_ReserveVoice( int voice );
+int  AL_ReleaseVoice( int voice );
+void AL_Shutdown( void );
+int  AL_Init( int soundcard );
+void AL_SetMaxMidiChannel( int channel );
+void AL_Reset( void );
+void AL_NoteOff( int channel, int key, int velocity );
+void AL_NoteOn( int channel, int key, int vel );
+//Turned off to test if it works with Watcom 10a
+//   #pragma aux AL_NoteOn frame;
+void AL_AllNotesOff( int channel );
+void AL_ControlChange( int channel, int type, int data );
+void AL_ProgramChange( int channel, int patch );
+void AL_SetPitchBend( int channel, int lsb, int msb );
+int  AL_DetectFM( void );
+void AL_RegisterTimbreBank( unsigned char *timbres );
+
+#endif
--- /dev/null
+++ b/rott/audiolib/assert.h
@@ -1,0 +1,45 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+#ifndef    __ASSERT_H
+
+    #define    __ASSERT_H
+
+    #ifdef NDEBUG
+
+        #define ASSERT(f)
+
+    #else
+
+        #pragma aux _Assert aborts;          /* _Assert will not return */
+        extern void _Assert( char *strFile, unsigned  uLine ); /*prototype */
+
+        #define ASSERT(f)          \
+            if (f)                 \
+                ;                  \
+            else                   \
+                _Assert( __FILE__, __LINE__ )
+
+    #endif
+
+#else
+
+    #error Multiple definition of ASSERT()
+
+#endif
binary files /dev/null b/rott/audiolib/audiolib.a differ
--- /dev/null
+++ b/rott/audiolib/awe32.c
@@ -1,0 +1,540 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+/**********************************************************************
+   module: AWE32.C
+
+   author: James R. Dose
+   date:   August 23, 1994
+
+   Cover functions for calling the AWE32 low-level library.
+
+   (c) Copyright 1994 James R. Dose.  All Rights Reserved.
+**********************************************************************/
+
+#include <conio.h>
+#include <string.h>
+#include "dpmi.h"
+#include "blaster.h"
+#include "ctaweapi.h"
+#include "awe32.h"
+
+#define _inp    inp
+#define _outp   outp
+
+/*  DSP defines  */
+#define MPU_ACK_OK          0xfe
+#define MPU_RESET_CMD       0xff
+#define MPU_ENTER_UART      0x3f
+
+static WORD wSBCBaseAddx;            /* Sound Blaster base address */
+static WORD wEMUBaseAddx;            /* EMU8000 subsystem base address */
+static WORD wMpuBaseAddx;            /* MPU401 base address */
+
+static unsigned short NoteFlags[ 128 ];
+
+/*  macros  */
+#define SBCPort( x )  ( ( x ) + wSBCBaseAddx )
+#define MPUPort( x )  ( ( x ) + wMpuBaseAddx )
+
+static SOUND_PACKET spSound =
+   {
+   0
+   };
+
+static LONG lBankSizes[ MAXBANKS ] =
+   {
+   0
+   };
+
+unsigned SetES( void );
+#pragma aux SetES = \
+        "xor eax, eax" \
+        "mov ax, es" \
+        "mov bx, ds" \
+        "mov es, bx" \
+        modify [ eax ebx ];
+
+void RestoreES( unsigned num );
+#pragma aux RestoreES = \
+        "mov  es, ax" \
+        parm [ eax ];
+
+int AWE32_ErrorCode = AWE32_Ok;
+
+#define AWE32_SetErrorCode( status ) \
+   AWE32_ErrorCode = ( status );
+
+
+/*---------------------------------------------------------------------
+   Function: AWE32_ErrorString
+
+   Returns a pointer to the error message associated with an error
+   number.  A -1 returns a pointer the current error.
+---------------------------------------------------------------------*/
+
+char *AWE32_ErrorString
+   (
+   int ErrorNumber
+   )
+
+   {
+   char *ErrorString;
+
+   switch( ErrorNumber )
+      {
+      case AWE32_Warning :
+      case AWE32_Error :
+         ErrorString = AWE32_ErrorString( AWE32_ErrorCode );
+         break;
+
+      case AWE32_Ok :
+         ErrorString = "AWE32 ok.";
+         break;
+
+      case AWE32_SoundBlasterError :
+         ErrorString = BLASTER_ErrorString( BLASTER_Error );
+         break;
+
+      case AWE32_NotDetected :
+         ErrorString = "Could not detect AWE32.";
+         break;
+
+      case AWE32_UnableToInitialize :
+         ErrorString = "Unable to initialize AWE32.";
+
+      case AWE32_MPU401Error :
+         ErrorString = "MPU-401 initialization failed in AWE32.";
+         break;
+
+      case AWE32_DPMI_Error :
+         ErrorString = "DPMI Error in AWE32.";
+         break;
+
+      default :
+         ErrorString = "Unknown AWE32 error code.";
+         break;
+      }
+
+   return( ErrorString );
+   }
+
+
+/**********************************************************************
+
+   Memory locked functions:
+
+**********************************************************************/
+
+
+#define AWE32_LockStart AWE32_NoteOff
+
+
+void AWE32_NoteOff
+   (
+   int channel,
+   int key,
+   int velocity
+   )
+
+   {
+   unsigned temp;
+
+   temp = SetES();
+   awe32NoteOff( channel, key, velocity );
+   RestoreES( temp );
+   NoteFlags[ key ] ^= ( 1 << channel );
+   }
+
+void AWE32_NoteOn
+   (
+   int channel,
+   int key,
+   int velocity
+   )
+
+   {
+   unsigned temp;
+
+   temp = SetES();
+   awe32NoteOn( channel, key, velocity );
+   RestoreES( temp );
+   NoteFlags[ key ] |= ( 1 << channel );
+   }
+
+void AWE32_PolyAftertouch
+   (
+   int channel,
+   int key,
+   int pressure
+   )
+
+   {
+   unsigned temp;
+
+   temp = SetES();
+   awe32PolyKeyPressure( channel, key, pressure );
+   RestoreES( temp );
+   }
+
+void AWE32_ChannelAftertouch
+   (
+   int channel,
+   int pressure
+   )
+
+   {
+   unsigned temp;
+
+   temp = SetES();
+   awe32ChannelPressure( channel, pressure );
+   RestoreES( temp );
+   }
+
+void AWE32_ControlChange
+   (
+   int channel,
+   int number,
+   int value
+   )
+
+   {
+   unsigned temp;
+   int i;
+   unsigned channelmask;
+
+   temp = SetES();
+
+   if ( number == 0x7b )
+      {
+      channelmask = 1 << channel;
+      for( i = 0; i < 128; i++ )
+         {
+         if ( NoteFlags[ i ] & channelmask )
+            {
+            awe32NoteOff( channel, i, 0 );
+            NoteFlags[ i ] ^= channelmask;
+            }
+         }
+      }
+   else
+      {
+      awe32Controller( channel, number, value );
+      }
+   RestoreES( temp );
+   }
+
+void AWE32_ProgramChange
+   (
+   int channel,
+   int program
+   )
+
+   {
+   unsigned temp;
+
+   temp = SetES();
+   awe32ProgramChange( channel, program );
+   RestoreES( temp );
+   }
+
+void AWE32_PitchBend
+   (
+   int channel,
+   int lsb,
+   int msb
+   )
+
+   {
+   unsigned temp;
+
+   temp = SetES();
+   awe32PitchBend( channel, lsb, msb );
+   RestoreES( temp );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: AWE32_LockEnd
+
+   Used for determining the length of the functions to lock in memory.
+---------------------------------------------------------------------*/
+
+static void AWE32_LockEnd
+   (
+   void
+   )
+
+   {
+   }
+
+
+/*
+static int InitMPU
+   (
+   void
+   )
+
+   {
+   volatile DWORD dwCount;
+
+   for (dwCount=0; dwCount<0x2000; dwCount++) ;
+   dwCount = 0x2000;
+   while (dwCount && _inp(MPUPort(1)) & 0x40) --dwCount;
+   _outp(MPUPort(1), MPU_RESET_CMD);
+
+   for (dwCount=0; dwCount<0x2000; dwCount++) ;
+   dwCount = 0x2000;
+   while (dwCount && _inp(MPUPort(1)) & 0x80) --dwCount;
+   _inp(MPUPort(0));
+
+   for (dwCount=0; dwCount<0x2000; dwCount++) ;
+   dwCount = 0x2000;
+   while (dwCount && _inp(MPUPort(1)) & 0x40) --dwCount;
+   _outp(MPUPort(1), MPU_RESET_CMD);
+
+   for (dwCount=0; dwCount<0x2000; dwCount++) ;
+   dwCount = 0x2000;
+   while (dwCount && _inp(MPUPort(1)) & 0x80) --dwCount;
+   _inp(MPUPort(0));
+
+   for (dwCount=0; dwCount<0x2000; dwCount++) ;
+   dwCount = 0x2000;
+   while (dwCount && _inp(MPUPort(1)) & 0x40) --dwCount;
+   _outp(MPUPort(1), MPU_ENTER_UART);
+
+   for (dwCount=0; dwCount<0x2000; dwCount++) ;
+   dwCount = 0x2000;
+   while (dwCount && _inp(MPUPort(1)) & 0x80) --dwCount;
+   if (!dwCount) return TRUE;
+   if (_inp(MPUPort(0)) != MPU_ACK_OK) return TRUE;
+
+   // mask MPU-401 interrupt
+   _outp(SBCPort(0x4), 0x83);
+   _outp(SBCPort(0x5), _inp(SBCPort(0x5)) & ~0x04);
+
+   return FALSE;
+   }
+*/
+
+/*������������������������������������������������������������������������͸*/
+/*� ShutdownMPU                                                    �*/
+/*� Cleans up Sound Blaster to normal state.                               �*/
+/*������������������������������������������������������������������������;*/
+
+static void ShutdownMPU
+   (
+   void
+   )
+
+   {
+   volatile DWORD dwCount;
+
+   for (dwCount=0; dwCount<0x2000; dwCount++) ;
+   dwCount = 0x2000;
+   while (dwCount && _inp(MPUPort(1)) & 0x40) --dwCount;
+   _outp(MPUPort(1), MPU_RESET_CMD);
+   for (dwCount=0; dwCount<0x2000; dwCount++) ;
+   _inp(MPUPort(0));
+
+   for (dwCount=0; dwCount<0x2000; dwCount++) ;
+   dwCount = 0x2000;
+   while (dwCount && _inp(MPUPort(1)) & 0x40) --dwCount;
+   _outp(MPUPort(1), MPU_RESET_CMD);
+   for (dwCount=0; dwCount<0x2000; dwCount++) ;
+   _inp(MPUPort(0));
+   }
+
+
+/*������������������������������������������������������������������������͸*/
+/*� LoadSBK                                                                �*/
+/*������������������������������������������������������������������������;*/
+
+static void LoadSBK
+   (
+   void
+   )
+
+   {
+   /* use embeded preset objects */
+   spSound.bank_no = 0;            /* load as Bank 0 */
+   spSound.total_banks = 1;        /* use 1 bank first */
+   lBankSizes[ 0 ] = 0;            /* ram is not needed */
+
+   spSound.banksizes = lBankSizes;
+   awe32DefineBankSizes( &spSound );
+   awe32SoundPad.SPad1 = awe32SPad1Obj;
+   awe32SoundPad.SPad2 = awe32SPad2Obj;
+   awe32SoundPad.SPad3 = awe32SPad3Obj;
+   awe32SoundPad.SPad4 = awe32SPad4Obj;
+   awe32SoundPad.SPad5 = awe32SPad5Obj;
+   awe32SoundPad.SPad6 = awe32SPad6Obj;
+   awe32SoundPad.SPad7 = awe32SPad7Obj;
+   }
+
+
+int AWE32_Init
+   (
+   void
+   )
+
+   {
+   int status;
+   BLASTER_CONFIG Blaster;
+
+   wSBCBaseAddx = 0x220;
+   wEMUBaseAddx = 0x620;
+   wMpuBaseAddx = 0x330;
+
+   status = BLASTER_GetCardSettings( &Blaster );
+   if ( status != BLASTER_Ok )
+      {
+      status = BLASTER_GetEnv( &Blaster );
+      if ( status != BLASTER_Ok )
+         {
+         AWE32_SetErrorCode( AWE32_SoundBlasterError );
+         return( AWE32_Error );
+         }
+      }
+
+   wSBCBaseAddx = Blaster.Address;
+   if ( wSBCBaseAddx == UNDEFINED )
+      {
+      wSBCBaseAddx = 0x220;
+      }
+
+   wMpuBaseAddx = Blaster.Midi;
+   if ( wMpuBaseAddx == UNDEFINED )
+      {
+      wMpuBaseAddx = 0x330;
+      }
+
+   wEMUBaseAddx = Blaster.Emu;
+   if ( wEMUBaseAddx <= 0 )
+      {
+      wEMUBaseAddx = wSBCBaseAddx + 0x400;
+      }
+
+   status = awe32Detect( wEMUBaseAddx );
+   if ( status )
+      {
+      AWE32_SetErrorCode( AWE32_NotDetected );
+      return( AWE32_Error );
+      }
+
+   status = awe32InitHardware();
+   if ( status )
+      {
+      AWE32_SetErrorCode( AWE32_UnableToInitialize );
+      return( AWE32_Error );
+      }
+
+
+   status = awe32InitMIDI();
+   if ( status )
+      {
+      AWE32_Shutdown();
+      AWE32_SetErrorCode( AWE32_MPU401Error )
+      return( AWE32_Error );
+      }
+
+/*
+    status = InitMPU();
+   if ( status )
+      {
+      ShutdownMPU();
+      status = InitMPU();
+      if ( status )
+         {
+         ShutdownMPU();
+         status = InitMPU();
+         if ( status )
+            {
+            AWE32_Shutdown();
+            AWE32_SetErrorCode( AWE32_MPU401Error )
+            return( AWE32_Error );
+            }
+         }
+      }
+*/
+   status  = DPMI_LockMemoryRegion( AWE32_LockStart, AWE32_LockEnd );
+   status |= DPMI_Lock( wSBCBaseAddx );
+   status |= DPMI_Lock( wEMUBaseAddx );
+   status |= DPMI_Lock( wMpuBaseAddx );
+   status |= DPMI_Lock( spSound );
+   status |= DPMI_Lock( lBankSizes );
+   status |= DPMI_LockMemory( NoteFlags, sizeof( NoteFlags ) );
+
+   // Lock awe32 library
+   status  = DPMI_LockMemoryRegion( __midieng_code, __midieng_ecode );
+   status  = DPMI_LockMemoryRegion( __midieng_code(), __midieng_ecode() );
+   status  = DPMI_LockMemoryRegion( __nrpn_code, __nrpn_ecode );
+   status  = DPMI_LockMemoryRegion( __nrpn_code(), __nrpn_ecode() );
+   status  = DPMI_LockMemoryRegion( &__midivar_data, &__midivar_edata );
+   status  = DPMI_LockMemoryRegion( &__nrpnvar_data, &__nrpnvar_edata );
+   status  = DPMI_LockMemoryRegion( &__embed_data, &__embed_edata );
+
+   if ( status != DPMI_Ok )
+      {
+      ShutdownMPU();
+      awe32Terminate();
+      AWE32_SetErrorCode( AWE32_DPMI_Error );
+      return( AWE32_Error );
+      }
+
+   // Set the number of voices to use to 32
+   awe32NumG = 32;
+
+   awe32TotalPatchRam(&spSound);
+
+   LoadSBK();
+   awe32InitMIDI();
+   awe32InitNRPN();
+
+   memset( NoteFlags, 0, sizeof( NoteFlags ) );
+
+   return( AWE32_Ok );
+   }
+
+void AWE32_Shutdown
+   (
+   void
+   )
+
+   {
+   ShutdownMPU();
+   awe32Terminate();
+
+   DPMI_UnlockMemoryRegion( AWE32_LockStart, AWE32_LockEnd );
+   DPMI_Unlock( wSBCBaseAddx );
+   DPMI_Unlock( wEMUBaseAddx );
+   DPMI_Unlock( wMpuBaseAddx );
+   DPMI_Unlock( spSound );
+   DPMI_Unlock( lBankSizes );
+   DPMI_UnlockMemory( NoteFlags, sizeof( NoteFlags ) );
+
+   // Unlock awe32 library
+   DPMI_UnlockMemoryRegion( __midieng_code, __midieng_ecode );
+   DPMI_UnlockMemoryRegion( __midieng_code(), __midieng_ecode() );
+   DPMI_UnlockMemoryRegion( __nrpn_code, __nrpn_ecode );
+   DPMI_UnlockMemoryRegion( __nrpn_code(), __nrpn_ecode() );
+   DPMI_UnlockMemoryRegion( &__midivar_data, &__midivar_edata );
+   DPMI_UnlockMemoryRegion( &__nrpnvar_data, &__nrpnvar_edata );
+   DPMI_UnlockMemoryRegion( &__embed_data, &__embed_edata );
+   }
--- /dev/null
+++ b/rott/audiolib/awe32.h
@@ -1,0 +1,58 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+/**********************************************************************
+   module: AWE32.H
+
+   author: James R. Dose
+   date:   August 23, 1994
+
+   Public header for AWE32.C  Cover functions for calling the
+   AWE32 low-level library.
+
+   (c) Copyright 1994 James R. Dose.  All Rights Reserved.
+**********************************************************************/
+
+#ifndef __AWE32_H
+#define __AWE32_H
+
+enum AWE32_ERRORS
+   {
+   AWE32_Warning = -2,
+   AWE32_Error = -1,
+   AWE32_Ok = 0,
+   AWE32_SoundBlasterError,
+   AWE32_NotDetected,
+   AWE32_UnableToInitialize,
+   AWE32_MPU401Error,
+   AWE32_DPMI_Error
+   };
+
+char *AWE32_ErrorString( int ErrorNumber );
+int  AWE32_Init( void );
+void AWE32_Shutdown( void );
+void AWE32_NoteOff( int channel, int key, int velocity );
+void AWE32_NoteOn( int channel, int key, int velocity );
+void AWE32_PolyAftertouch( int channel, int key, int pressure );
+void AWE32_ChannelAftertouch( int channel, int pressure );
+void AWE32_ControlChange( int channel, int number, int value );
+void AWE32_ProgramChange( int channel, int program );
+void AWE32_PitchBend( int channel, int lsb, int msb );
+
+#endif
--- /dev/null
+++ b/rott/audiolib/blaster.c
@@ -1,0 +1,2330 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+/**********************************************************************
+   module: BLASTER.C
+
+   author: James R. Dose
+   date:   February 4, 1994
+
+   Low level routines to support Sound Blaster, Sound Blaster Pro,
+   Sound Blaster 16, and compatible sound cards.
+
+   (c) Copyright 1994 James R. Dose.  All Rights Reserved.
+**********************************************************************/
+
+#include <dos.h>
+#include <conio.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include "dpmi.h"
+#include "dma.h"
+#include "irq.h"
+#include "blaster.h"
+#include "_blaster.h"
+
+#define USESTACK
+
+const int BLASTER_Interrupts[ BLASTER_MaxIrq + 1 ]  =
+   {
+   INVALID, INVALID,     0xa,     0xb,
+   INVALID,     0xd, INVALID,     0xf,
+   INVALID, INVALID,    0x72,    0x73,
+      0x74, INVALID, INVALID,    0x77
+   };
+
+const int BLASTER_SampleSize[ BLASTER_MaxMixMode + 1 ] =
+   {
+   MONO_8BIT_SAMPLE_SIZE,  STEREO_8BIT_SAMPLE_SIZE,
+   MONO_16BIT_SAMPLE_SIZE, STEREO_16BIT_SAMPLE_SIZE
+   };
+
+const CARD_CAPABILITY BLASTER_CardConfig[ BLASTER_MaxCardType + 1 ] =
+   {
+      { FALSE, INVALID,      INVALID, INVALID, INVALID }, // Unsupported
+      {  TRUE,      NO,    MONO_8BIT,    4000,   23000 }, // SB 1.0
+      {  TRUE,     YES,  STEREO_8BIT,    4000,   44100 }, // SBPro
+      {  TRUE,      NO,    MONO_8BIT,    4000,   23000 }, // SB 2.xx
+      {  TRUE,     YES,  STEREO_8BIT,    4000,   44100 }, // SBPro 2
+      { FALSE, INVALID,      INVALID, INVALID, INVALID }, // Unsupported
+      {  TRUE,     YES, STEREO_16BIT,    5000,   44100 }, // SB16
+   };
+
+CARD_CAPABILITY BLASTER_Card;
+
+static void    ( __interrupt __far *BLASTER_OldInt )( void );
+
+BLASTER_CONFIG BLASTER_Config =
+   {
+   UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED
+   };
+
+static int BLASTER_Installed = FALSE;
+
+int BLASTER_Version;
+
+static char   *BLASTER_DMABuffer;
+static char   *BLASTER_DMABufferEnd;
+static char   *BLASTER_CurrentDMABuffer;
+static int     BLASTER_TotalDMABufferSize;
+
+static int      BLASTER_TransferLength   = 0;
+static int      BLASTER_MixMode          = BLASTER_DefaultMixMode;
+static int      BLASTER_SamplePacketSize = MONO_16BIT_SAMPLE_SIZE;
+static unsigned BLASTER_SampleRate       = BLASTER_DefaultSampleRate;
+
+static unsigned BLASTER_HaltTransferCommand = DSP_Halt8bitTransfer;
+
+volatile int   BLASTER_SoundPlaying;
+volatile int   BLASTER_SoundRecording;
+
+void ( *BLASTER_CallBack )( void );
+
+static int  BLASTER_IntController1Mask;
+static int  BLASTER_IntController2Mask;
+
+static int BLASTER_MixerAddress = UNDEFINED;
+static int BLASTER_MixerType    = 0;
+static int BLASTER_OriginalMidiVolumeLeft   = 255;
+static int BLASTER_OriginalMidiVolumeRight  = 255;
+static int BLASTER_OriginalVoiceVolumeLeft  = 255;
+static int BLASTER_OriginalVoiceVolumeRight = 255;
+
+static int BLASTER_WaveBlasterState = 0x0F;
+
+// adequate stack size
+#define kStackSize 2048
+
+static unsigned short StackSelector = NULL;
+static unsigned long  StackPointer;
+
+static unsigned short oldStackSelector;
+static unsigned long  oldStackPointer;
+
+// This is defined because we can't create local variables in a
+// function that switches stacks.
+static int GlobalStatus;
+
+// These declarations are necessary to use the inline assembly pragmas.
+
+extern void GetStack(unsigned short *selptr,unsigned long *stackptr);
+extern void SetStack(unsigned short selector,unsigned long stackptr);
+
+// This function will get the current stack selector and pointer and save
+// them off.
+#pragma aux GetStack =  \
+   "mov  [edi],esp"     \
+   "mov  ax,ss"         \
+   "mov  [esi],ax"      \
+   parm [esi] [edi]     \
+   modify [eax esi edi];
+
+// This function will set the stack selector and pointer to the specified
+// values.
+#pragma aux SetStack =  \
+   "mov  ss,ax"         \
+   "mov  esp,edx"       \
+   parm [ax] [edx]      \
+   modify [eax edx];
+
+int BLASTER_DMAChannel;
+
+int BLASTER_ErrorCode = BLASTER_Ok;
+
+#define BLASTER_SetErrorCode( status ) \
+   BLASTER_ErrorCode   = ( status );
+
+
+/*---------------------------------------------------------------------
+   Function: BLASTER_ErrorString
+
+   Returns a pointer to the error message associated with an error
+   number.  A -1 returns a pointer the current error.
+---------------------------------------------------------------------*/
+
+char *BLASTER_ErrorString
+   (
+   int ErrorNumber
+   )
+
+   {
+   char *ErrorString;
+
+   switch( ErrorNumber )
+      {
+      case BLASTER_Warning :
+      case BLASTER_Error :
+         ErrorString = BLASTER_ErrorString( BLASTER_ErrorCode );
+         break;
+
+      case BLASTER_Ok :
+         ErrorString = "Sound Blaster ok.";
+         break;
+
+      case BLASTER_EnvNotFound :
+         ErrorString = "BLASTER environment variable not set.";
+         break;
+
+      case BLASTER_AddrNotSet :
+         ErrorString = "Sound Blaster address not set.";
+         break;
+
+      case BLASTER_DMANotSet :
+         ErrorString = "Sound Blaster 8-bit DMA channel not set.";
+         break;
+
+      case BLASTER_DMA16NotSet :
+         ErrorString = "Sound Blaster 16-bit DMA channel not set.";
+         break;
+
+      case BLASTER_InvalidParameter :
+         ErrorString = "Invalid parameter in BLASTER environment variable.";
+         break;
+
+      case BLASTER_CardNotReady :
+         ErrorString = "Sound Blaster not responding on selected port.";
+         break;
+
+      case BLASTER_NoSoundPlaying :
+         ErrorString = "No sound playing on Sound Blaster.";
+         break;
+
+      case BLASTER_InvalidIrq :
+         ErrorString = "Invalid Sound Blaster Irq.";
+         break;
+
+      case BLASTER_UnableToSetIrq :
+         ErrorString = "Unable to set Sound Blaster IRQ.  Try selecting an IRQ of 7 or below.";
+         break;
+
+      case BLASTER_DmaError :
+         ErrorString = DMA_ErrorString( DMA_Error );
+         break;
+
+      case BLASTER_NoMixer :
+         ErrorString = "Mixer not available on selected Sound Blaster card.";
+         break;
+
+      case BLASTER_DPMI_Error :
+         ErrorString = "DPMI Error in Blaster.";
+         break;
+
+      case BLASTER_OutOfMemory :
+         ErrorString = "Out of conventional memory in Blaster.";
+         break;
+
+      default :
+         ErrorString = "Unknown Sound Blaster error code.";
+         break;
+      }
+
+   return( ErrorString );
+   }
+
+
+/**********************************************************************
+
+   Memory locked functions:
+
+**********************************************************************/
+
+
+#define BLASTER_LockStart BLASTER_EnableInterrupt
+
+
+/*---------------------------------------------------------------------
+   Function: BLASTER_EnableInterrupt
+
+   Enables the triggering of the sound card interrupt.
+---------------------------------------------------------------------*/
+
+void BLASTER_EnableInterrupt
+   (
+   void
+   )
+
+   {
+   int Irq;
+   int mask;
+
+   // Unmask system interrupt
+   Irq  = BLASTER_Config.Interrupt;
+   if ( Irq < 8 )
+      {
+      mask = inp( 0x21 ) & ~( 1 << Irq );
+      outp( 0x21, mask  );
+      }
+   else
+      {
+      mask = inp( 0xA1 ) & ~( 1 << ( Irq - 8 ) );
+      outp( 0xA1, mask  );
+
+      mask = inp( 0x21 ) & ~( 1 << 2 );
+      outp( 0x21, mask  );
+      }
+
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: BLASTER_DisableInterrupt
+
+   Disables the triggering of the sound card interrupt.
+---------------------------------------------------------------------*/
+
+void BLASTER_DisableInterrupt
+   (
+   void
+   )
+
+   {
+   int Irq;
+   int mask;
+
+   // Restore interrupt mask
+   Irq  = BLASTER_Config.Interrupt;
+   if ( Irq < 8 )
+      {
+      mask  = inp( 0x21 ) & ~( 1 << Irq );
+      mask |= BLASTER_IntController1Mask & ( 1 << Irq );
+      outp( 0x21, mask  );
+      }
+   else
+      {
+      mask  = inp( 0x21 ) & ~( 1 << 2 );
+      mask |= BLASTER_IntController1Mask & ( 1 << 2 );
+      outp( 0x21, mask  );
+
+      mask  = inp( 0xA1 ) & ~( 1 << ( Irq - 8 ) );
+      mask |= BLASTER_IntController2Mask & ( 1 << ( Irq - 8 ) );
+      outp( 0xA1, mask  );
+      }
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: BLASTER_ServiceInterrupt
+
+   Handles interrupt generated by sound card at the end of a voice
+   transfer.  Calls the user supplied callback function.
+---------------------------------------------------------------------*/
+
+void __interrupt __far BLASTER_ServiceInterrupt
+   (
+   void
+   )
+
+   {
+   #ifdef USESTACK
+   // save stack
+   GetStack( &oldStackSelector, &oldStackPointer );
+
+   // set our stack
+   SetStack( StackSelector, StackPointer );
+   #endif
+
+   // Acknowledge interrupt
+   // Check if this is this an SB16 or newer
+   if ( BLASTER_Version >= DSP_Version4xx )
+      {
+      outp( BLASTER_Config.Address + BLASTER_MixerAddressPort,
+         MIXER_DSP4xxISR_Ack );
+
+      GlobalStatus = inp( BLASTER_Config.Address + BLASTER_MixerDataPort );
+
+      // Check if a 16-bit DMA interrupt occurred
+      if ( GlobalStatus & MIXER_16BITDMA_INT )
+         {
+         // Acknowledge 16-bit transfer interrupt
+         inp( BLASTER_Config.Address + BLASTER_16BitDMAAck );
+         }
+      else if ( GlobalStatus & MIXER_8BITDMA_INT )
+         {
+         inp( BLASTER_Config.Address + BLASTER_DataAvailablePort );
+         }
+      else
+         {
+         #ifdef USESTACK
+         // restore stack
+         SetStack( oldStackSelector, oldStackPointer );
+         #endif
+
+         // Wasn't our interrupt.  Call the old one.
+         _chain_intr( BLASTER_OldInt );
+         }
+      }
+   else
+      {
+      // Older card - can't detect if an interrupt occurred.
+      inp( BLASTER_Config.Address + BLASTER_DataAvailablePort );
+      }
+
+   // Keep track of current buffer
+   BLASTER_CurrentDMABuffer += BLASTER_TransferLength;
+
+   if ( BLASTER_CurrentDMABuffer >= BLASTER_DMABufferEnd )
+      {
+      BLASTER_CurrentDMABuffer = BLASTER_DMABuffer;
+      }
+
+   // Continue playback on cards without autoinit mode
+   if ( BLASTER_Version < DSP_Version2xx )
+      {
+      if ( BLASTER_SoundPlaying )
+         {
+         BLASTER_DSP1xx_BeginPlayback( BLASTER_TransferLength );
+         }
+
+      if ( BLASTER_SoundRecording )
+         {
+         BLASTER_DSP1xx_BeginRecord( BLASTER_TransferLength );
+         }
+      }
+
+   // Call the caller's callback function
+   if ( BLASTER_CallBack != NULL )
+      {
+      BLASTER_CallBack();
+      }
+
+   #ifdef USESTACK
+   // restore stack
+   SetStack( oldStackSelector, oldStackPointer );
+   #endif
+
+   // send EOI to Interrupt Controller
+   if ( BLASTER_Config.Interrupt > 7 )
+      {
+      outp( 0xA0, 0x20 );
+      }
+
+   outp( 0x20, 0x20 );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: BLASTER_WriteDSP
+
+   Writes a byte of data to the sound card's DSP.
+---------------------------------------------------------------------*/
+
+int BLASTER_WriteDSP
+   (
+   unsigned data
+   )
+
+   {
+   int      port;
+   unsigned count;
+   int      status;
+
+   port = BLASTER_Config.Address + BLASTER_WritePort;
+
+   status = BLASTER_Error;
+
+   count = 0xFFFF;
+
+   do
+      {
+      if ( ( inp( port ) & 0x80 ) == 0 )
+         {
+         outp( port, data );
+         status = BLASTER_Ok;
+         break;
+         }
+
+      count--;
+      }
+   while( count > 0 );
+
+   if ( status != BLASTER_Ok )
+      {
+      BLASTER_SetErrorCode( BLASTER_CardNotReady );
+      }
+
+   return( status );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: BLASTER_ReadDSP
+
+   Reads a byte of data from the sound card's DSP.
+---------------------------------------------------------------------*/
+
+int BLASTER_ReadDSP
+   (
+   void
+   )
+
+   {
+   int      port;
+   unsigned count;
+   int      status;
+
+   port = BLASTER_Config.Address + BLASTER_DataAvailablePort;
+
+   status = BLASTER_Error;
+
+   count = 0xFFFF;
+
+   do
+      {
+      if ( inp( port ) & 0x80 )
+         {
+         status = inp( BLASTER_Config.Address + BLASTER_ReadPort );
+         break;
+         }
+
+      count--;
+      }
+   while( count > 0 );
+
+   if ( status == BLASTER_Error )
+      {
+      BLASTER_SetErrorCode( BLASTER_CardNotReady );
+      }
+
+   return( status );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: BLASTER_ResetDSP
+
+   Sends a reset command to the sound card's Digital Signal Processor
+   (DSP), causing it to perform an initialization.
+---------------------------------------------------------------------*/
+
+int BLASTER_ResetDSP
+   (
+   void
+   )
+
+   {
+   volatile int count;
+   int port;
+   int status;
+
+   port = BLASTER_Config.Address + BLASTER_ResetPort;
+
+   status = BLASTER_CardNotReady;
+
+   outp( port, 1 );
+
+/* What the hell am I doing here?
+   count = 100;
+
+   do
+      {
+      if ( inp( port ) == 255 )
+         {
+         break;
+         }
+
+      count--;
+      }
+   while( count > 0 );
+*/
+
+   count = 0x100;
+   do
+      {
+      count--;
+      }
+   while( count > 0 );
+
+   outp( port, 0 );
+
+   count = 100;
+
+   do
+      {
+      if ( BLASTER_ReadDSP() == BLASTER_Ready )
+         {
+         status = BLASTER_Ok;
+         break;
+         }
+
+      count--;
+      }
+   while( count > 0 );
+
+   return( status );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: BLASTER_GetDSPVersion
+
+   Returns the version number of the sound card's DSP.
+---------------------------------------------------------------------*/
+
+int BLASTER_GetDSPVersion
+   (
+   void
+   )
+
+   {
+   int MajorVersion;
+   int MinorVersion;
+   int version;
+
+   BLASTER_WriteDSP( DSP_GetVersion );
+
+   MajorVersion   = BLASTER_ReadDSP();
+   MinorVersion   = BLASTER_ReadDSP();
+
+   if ( ( MajorVersion == BLASTER_Error ) ||
+      ( MinorVersion == BLASTER_Error ) )
+      {
+      BLASTER_SetErrorCode( BLASTER_CardNotReady );
+      return( BLASTER_Error );
+      }
+
+   version = ( MajorVersion << 8 ) + MinorVersion;
+
+   if ( version >= DSP_Version4xx )
+      {
+      BLASTER_Card.IsSupported     = TRUE;
+      BLASTER_Card.HasMixer        = YES;
+      BLASTER_Card.MaxMixMode      = STEREO_16BIT;
+      BLASTER_Card.MinSamplingRate = 5000;
+      BLASTER_Card.MaxSamplingRate = 44100;
+      BLASTER_MixerType = SB16;
+      }
+   else if ( version >= DSP_Version3xx )
+      {
+      BLASTER_Card.IsSupported     = TRUE;
+      BLASTER_Card.HasMixer        = YES;
+      BLASTER_Card.MaxMixMode      = STEREO_8BIT;
+      BLASTER_Card.MinSamplingRate = 4000;
+      BLASTER_Card.MaxSamplingRate = 44100;
+      BLASTER_MixerType = SBPro;
+      }
+   else if ( version >= DSP_Version2xx )
+      {
+      BLASTER_Card.IsSupported     = TRUE;
+      BLASTER_Card.HasMixer        = NO;
+      BLASTER_Card.MaxMixMode      = MONO_8BIT;
+      BLASTER_Card.MinSamplingRate = 4000;
+      BLASTER_Card.MaxSamplingRate = 23000;
+      BLASTER_MixerType = 0;
+      }
+   else
+      {
+      // DSP_Version1xx
+      BLASTER_Card.IsSupported     = TRUE;
+      BLASTER_Card.HasMixer        = NO;
+      BLASTER_Card.MaxMixMode      = MONO_8BIT;
+      BLASTER_Card.MinSamplingRate = 4000;
+      BLASTER_Card.MaxSamplingRate = 23000;
+      BLASTER_MixerType = 0;
+      }
+
+   return( version );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: BLASTER_SpeakerOn
+
+   Enables output from the DAC.
+---------------------------------------------------------------------*/
+
+void BLASTER_SpeakerOn
+   (
+   void
+   )
+
+   {
+   BLASTER_WriteDSP( DSP_SpeakerOn );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: BLASTER_SpeakerOff
+
+   Disables output from the DAC.
+---------------------------------------------------------------------*/
+
+void BLASTER_SpeakerOff
+   (
+   void
+   )
+
+   {
+   BLASTER_WriteDSP( DSP_SpeakerOff );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: BLASTER_SetPlaybackRate
+
+   Sets the rate at which the digitized sound will be played in
+   hertz.
+---------------------------------------------------------------------*/
+
+void BLASTER_SetPlaybackRate
+   (
+   unsigned rate
+   )
+
+   {
+   int LoByte;
+   int HiByte;
+
+   if ( BLASTER_Version < DSP_Version4xx )
+      {
+      int  timeconstant;
+      long ActualRate;
+
+      // Send sampling rate as time constant for older Sound
+      // Blaster compatible cards.
+
+      ActualRate = rate * BLASTER_SamplePacketSize;
+      if ( ActualRate < BLASTER_Card.MinSamplingRate )
+         {
+         rate = BLASTER_Card.MinSamplingRate / BLASTER_SamplePacketSize;
+         }
+
+      if ( ActualRate > BLASTER_Card.MaxSamplingRate )
+         {
+         rate = BLASTER_Card.MaxSamplingRate / BLASTER_SamplePacketSize;
+         }
+
+      timeconstant = ( int )CalcTimeConstant( rate, BLASTER_SamplePacketSize );
+
+      // Keep track of what the actual rate is
+      BLASTER_SampleRate  = ( unsigned )CalcSamplingRate( timeconstant );
+      BLASTER_SampleRate /= BLASTER_SamplePacketSize;
+
+      BLASTER_WriteDSP( DSP_SetTimeConstant );
+      BLASTER_WriteDSP( timeconstant );
+      }
+   else
+      {
+      // Send literal sampling rate for cards with DSP version
+      // 4.xx (Sound Blaster 16)
+
+      BLASTER_SampleRate = rate;
+
+      if ( BLASTER_SampleRate < BLASTER_Card.MinSamplingRate )
+         {
+         BLASTER_SampleRate = BLASTER_Card.MinSamplingRate;
+         }
+
+      if ( BLASTER_SampleRate > BLASTER_Card.MaxSamplingRate )
+         {
+         BLASTER_SampleRate = BLASTER_Card.MaxSamplingRate;
+         }
+
+      HiByte = hibyte( BLASTER_SampleRate );
+      LoByte = lobyte( BLASTER_SampleRate );
+
+      // Set playback rate
+      BLASTER_WriteDSP( DSP_Set_DA_Rate );
+      BLASTER_WriteDSP( HiByte );
+      BLASTER_WriteDSP( LoByte );
+
+      // Set recording rate
+      BLASTER_WriteDSP( DSP_Set_AD_Rate );
+      BLASTER_WriteDSP( HiByte );
+      BLASTER_WriteDSP( LoByte );
+      }
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: BLASTER_GetPlaybackRate
+
+   Returns the rate at which the digitized sound will be played in
+   hertz.
+---------------------------------------------------------------------*/
+
+unsigned BLASTER_GetPlaybackRate
+   (
+   void
+   )
+
+   {
+   return( BLASTER_SampleRate );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: BLASTER_SetMixMode
+
+   Sets the sound card to play samples in mono or stereo.
+---------------------------------------------------------------------*/
+
+int BLASTER_SetMixMode
+   (
+   int mode
+   )
+
+   {
+   int   port;
+   int   data;
+   int   CardType;
+
+   CardType = BLASTER_Config.Type;
+
+   mode &= BLASTER_MaxMixMode;
+
+   if ( !( BLASTER_Card.MaxMixMode & STEREO ) )
+      {
+      mode &= ~STEREO;
+      }
+
+   if ( !( BLASTER_Card.MaxMixMode & SIXTEEN_BIT ) )
+      {
+      mode &= ~SIXTEEN_BIT;
+      }
+
+   BLASTER_MixMode = mode;
+   BLASTER_SamplePacketSize = BLASTER_SampleSize[ mode ];
+
+   // For the Sound Blaster Pro, we have to set the mixer chip
+   // to play mono or stereo samples.
+
+   if ( ( CardType == SBPro ) || ( CardType == SBPro2 ) )
+      {
+      port = BLASTER_Config.Address + BLASTER_MixerAddressPort;
+      outp( port, MIXER_SBProOutputSetting );
+
+      port = BLASTER_Config.Address + BLASTER_MixerDataPort;
+
+      // Get current mode
+      data = inp( port );
+
+      // set stereo mode bit
+      if ( mode & STEREO )
+         {
+         data |= MIXER_SBProStereoFlag;
+         }
+      else
+         {
+         data &= ~MIXER_SBProStereoFlag;
+         }
+
+      // set the mode
+      outp( port, data );
+
+      BLASTER_SetPlaybackRate( BLASTER_SampleRate );
+      }
+
+   return( mode );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: BLASTER_StopPlayback
+
+   Ends the DMA transfer of digitized sound to the sound card.
+---------------------------------------------------------------------*/
+
+void BLASTER_StopPlayback
+   (
+   void
+   )
+
+   {
+   int DmaChannel;
+
+   // Don't allow anymore interrupts
+   BLASTER_DisableInterrupt();
+
+   if ( BLASTER_HaltTransferCommand == DSP_Reset )
+      {
+      BLASTER_ResetDSP();
+      }
+   else
+      {
+      BLASTER_WriteDSP( BLASTER_HaltTransferCommand );
+      }
+
+   // Disable the DMA channel
+   if ( BLASTER_MixMode & SIXTEEN_BIT )
+      {
+      DmaChannel = BLASTER_Config.Dma16;
+      }
+   else
+      {
+      DmaChannel = BLASTER_Config.Dma8;
+      }
+   DMA_EndTransfer( DmaChannel );
+
+   // Turn off speaker
+   BLASTER_SpeakerOff();
+
+   BLASTER_SoundPlaying = FALSE;
+   BLASTER_SoundRecording = FALSE;
+
+   BLASTER_DMABuffer = NULL;
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: BLASTER_SetupDMABuffer
+
+   Programs the DMAC for sound transfer.
+---------------------------------------------------------------------*/
+
+int BLASTER_SetupDMABuffer
+   (
+   char *BufferPtr,
+   int   BufferSize,
+   int   mode
+   )
+
+   {
+   int DmaChannel;
+   int DmaStatus;
+   int errorcode;
+
+   if ( BLASTER_MixMode & SIXTEEN_BIT )
+      {
+      DmaChannel = BLASTER_Config.Dma16;
+      errorcode  = BLASTER_DMA16NotSet;
+      }
+   else
+      {
+      DmaChannel = BLASTER_Config.Dma8;
+      errorcode  = BLASTER_DMANotSet;
+      }
+
+   if ( DmaChannel == UNDEFINED )
+      {
+      BLASTER_SetErrorCode( errorcode );
+      return( BLASTER_Error );
+      }
+
+   DmaStatus = DMA_SetupTransfer( DmaChannel, BufferPtr, BufferSize, mode );
+   if ( DmaStatus == DMA_Error )
+      {
+      BLASTER_SetErrorCode( BLASTER_DmaError );
+      return( BLASTER_Error );
+      }
+
+   BLASTER_DMAChannel = DmaChannel;
+
+   BLASTER_DMABuffer          = BufferPtr;
+   BLASTER_CurrentDMABuffer   = BufferPtr;
+   BLASTER_TotalDMABufferSize = BufferSize;
+   BLASTER_DMABufferEnd       = BufferPtr + BufferSize;
+
+   return( BLASTER_Ok );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: BLASTER_GetCurrentPos
+
+   Returns the offset within the current sound being played.
+---------------------------------------------------------------------*/
+
+int BLASTER_GetCurrentPos
+   (
+   void
+   )
+
+   {
+   char *CurrentAddr;
+   int   DmaChannel;
+   int   offset;
+
+   if ( !BLASTER_SoundPlaying )
+      {
+      BLASTER_SetErrorCode( BLASTER_NoSoundPlaying );
+      return( BLASTER_Error );
+      }
+
+   if ( BLASTER_MixMode & SIXTEEN_BIT )
+      {
+      DmaChannel = BLASTER_Config.Dma16;
+      }
+   else
+      {
+      DmaChannel = BLASTER_Config.Dma8;
+      }
+
+   if ( DmaChannel == UNDEFINED )
+      {
+      BLASTER_SetErrorCode( BLASTER_DMANotSet );
+      return( BLASTER_Error );
+      }
+
+   CurrentAddr = DMA_GetCurrentPos( DmaChannel );
+
+   offset = ( int )( ( ( unsigned long )CurrentAddr ) -
+      ( ( unsigned long )BLASTER_CurrentDMABuffer ) );
+
+   if ( BLASTER_MixMode & SIXTEEN_BIT )
+      {
+      offset >>= 1;
+      }
+
+   if ( BLASTER_MixMode & STEREO )
+      {
+      offset >>= 1;
+      }
+
+   return( offset );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: BLASTER_DSP1xx_BeginPlayback
+
+   Starts playback of digitized sound on cards compatible with DSP
+   version 1.xx.
+---------------------------------------------------------------------*/
+
+int BLASTER_DSP1xx_BeginPlayback
+   (
+   int length
+   )
+
+   {
+   int SampleLength;
+   int LoByte;
+   int HiByte;
+
+   SampleLength = length - 1;
+   HiByte = hibyte( SampleLength );
+   LoByte = lobyte( SampleLength );
+
+   // Program DSP to play sound
+   BLASTER_WriteDSP( DSP_Old8BitDAC );
+   BLASTER_WriteDSP( LoByte );
+   BLASTER_WriteDSP( HiByte );
+
+   BLASTER_HaltTransferCommand = DSP_Halt8bitTransfer;
+
+   BLASTER_SoundPlaying = TRUE;
+
+   return( BLASTER_Ok );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: BLASTER_DSP2xx_BeginPlayback
+
+   Starts playback of digitized sound on cards compatible with DSP
+   version 2.xx.
+---------------------------------------------------------------------*/
+
+int BLASTER_DSP2xx_BeginPlayback
+   (
+   int length
+   )
+
+   {
+   int SampleLength;
+   int LoByte;
+   int HiByte;
+
+   SampleLength = length - 1;
+   HiByte = hibyte( SampleLength );
+   LoByte = lobyte( SampleLength );
+
+   BLASTER_WriteDSP( DSP_SetBlockLength );
+   BLASTER_WriteDSP( LoByte );
+   BLASTER_WriteDSP( HiByte );
+
+   if ( ( BLASTER_Version >= DSP_Version201 ) && ( DSP_MaxNormalRate <
+      ( BLASTER_SampleRate * BLASTER_SamplePacketSize ) ) )
+      {
+      BLASTER_WriteDSP( DSP_8BitHighSpeedAutoInitMode );
+      BLASTER_HaltTransferCommand = DSP_Reset;
+      }
+   else
+      {
+      BLASTER_WriteDSP( DSP_8BitAutoInitMode );
+      BLASTER_HaltTransferCommand = DSP_Halt8bitTransfer;
+      }
+
+   BLASTER_SoundPlaying = TRUE;
+
+   return( BLASTER_Ok );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: BLASTER_DSP4xx_BeginPlayback
+
+   Starts playback of digitized sound on cards compatible with DSP
+   version 4.xx, such as the Sound Blaster 16.
+---------------------------------------------------------------------*/
+
+int BLASTER_DSP4xx_BeginPlayback
+   (
+   int length
+   )
+
+   {
+   int TransferCommand;
+   int TransferMode;
+   int SampleLength;
+   int LoByte;
+   int HiByte;
+
+   if ( BLASTER_MixMode & SIXTEEN_BIT )
+      {
+      TransferCommand = DSP_16BitDAC;
+      SampleLength = ( length / 2 ) - 1;
+      BLASTER_HaltTransferCommand = DSP_Halt16bitTransfer;
+      if ( BLASTER_MixMode & STEREO )
+         {
+         TransferMode = DSP_SignedStereoData;
+         }
+      else
+         {
+         TransferMode = DSP_SignedMonoData;
+         }
+      }
+   else
+      {
+      TransferCommand = DSP_8BitDAC;
+      SampleLength = length - 1;
+      BLASTER_HaltTransferCommand = DSP_Halt8bitTransfer;
+      if ( BLASTER_MixMode & STEREO )
+         {
+         TransferMode = DSP_UnsignedStereoData;
+         }
+      else
+         {
+         TransferMode = DSP_UnsignedMonoData;
+         }
+      }
+
+   HiByte = hibyte( SampleLength );
+   LoByte = lobyte( SampleLength );
+
+   // Program DSP to play sound
+   BLASTER_WriteDSP( TransferCommand );
+   BLASTER_WriteDSP( TransferMode );
+   BLASTER_WriteDSP( LoByte );
+   BLASTER_WriteDSP( HiByte );
+
+   BLASTER_SoundPlaying = TRUE;
+
+   return( BLASTER_Ok );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: BLASTER_BeginBufferedPlayback
+
+   Begins multibuffered playback of digitized sound on the sound card.
+---------------------------------------------------------------------*/
+
+int BLASTER_BeginBufferedPlayback
+   (
+   char    *BufferStart,
+   int      BufferSize,
+   int      NumDivisions,
+   unsigned SampleRate,
+   int      MixMode,
+   void  ( *CallBackFunc )( void )
+   )
+
+   {
+   int DmaStatus;
+   int TransferLength;
+
+//JIM
+//   if ( BLASTER_SoundPlaying || BLASTER_SoundRecording )
+      {
+      BLASTER_StopPlayback();
+      }
+
+   BLASTER_SetMixMode( MixMode );
+
+   DmaStatus = BLASTER_SetupDMABuffer( BufferStart, BufferSize, DMA_AutoInitRead );
+   if ( DmaStatus == BLASTER_Error )
+      {
+      return( BLASTER_Error );
+      }
+
+   BLASTER_SetPlaybackRate( SampleRate );
+
+   BLASTER_SetCallBack( CallBackFunc );
+
+   BLASTER_EnableInterrupt();
+
+   // Turn on speaker
+   BLASTER_SpeakerOn();
+
+   TransferLength = BufferSize / NumDivisions;
+   BLASTER_TransferLength = TransferLength;
+
+   //  Program the sound card to start the transfer.
+   if ( BLASTER_Version < DSP_Version2xx )
+      {
+      BLASTER_DSP1xx_BeginPlayback( TransferLength );
+      }
+   else if ( BLASTER_Version < DSP_Version4xx )
+      {
+      BLASTER_DSP2xx_BeginPlayback( TransferLength );
+      }
+   else
+      {
+      BLASTER_DSP4xx_BeginPlayback( TransferLength );
+      }
+
+   return( BLASTER_Ok );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: BLASTER_DSP4xx_BeginRecord
+
+   Starts recording of digitized sound on cards compatible with DSP
+   version 4.xx, such as the Sound Blaster 16.
+---------------------------------------------------------------------*/
+
+int BLASTER_DSP4xx_BeginRecord
+   (
+   int length
+   )
+
+   {
+   int TransferCommand;
+   int TransferMode;
+   int SampleLength;
+   int LoByte;
+   int HiByte;
+
+   TransferCommand = DSP_8BitADC;
+   SampleLength = length - 1;
+   BLASTER_HaltTransferCommand = DSP_Halt8bitTransfer;
+
+   TransferMode = DSP_UnsignedMonoData;
+
+   HiByte = hibyte( SampleLength );
+   LoByte = lobyte( SampleLength );
+
+   // Program DSP to play sound
+   BLASTER_WriteDSP( TransferCommand );
+   BLASTER_WriteDSP( TransferMode );
+   BLASTER_WriteDSP( LoByte );
+   BLASTER_WriteDSP( HiByte );
+
+   BLASTER_SoundRecording = TRUE;
+
+   return( BLASTER_Ok );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: BLASTER_DSP2xx_BeginRecord
+
+   Starts recording of digitized sound on cards compatible with DSP
+   version 2.xx.
+---------------------------------------------------------------------*/
+
+int BLASTER_DSP2xx_BeginRecord
+   (
+   int length
+   )
+
+   {
+   int SampleLength;
+   int LoByte;
+   int HiByte;
+
+   SampleLength = length - 1;
+   HiByte = hibyte( SampleLength );
+   LoByte = lobyte( SampleLength );
+
+   BLASTER_WriteDSP( DSP_SetBlockLength );
+   BLASTER_WriteDSP( LoByte );
+   BLASTER_WriteDSP( HiByte );
+
+   if ( ( BLASTER_Version >= DSP_Version201 ) && ( DSP_MaxNormalRate <
+      ( BLASTER_SampleRate * BLASTER_SamplePacketSize ) ) )
+      {
+      BLASTER_WriteDSP( DSP_8BitHighSpeedAutoInitRecord );
+      BLASTER_HaltTransferCommand = DSP_Reset;
+      }
+   else
+      {
+      BLASTER_WriteDSP( DSP_8BitAutoInitRecord );
+      BLASTER_HaltTransferCommand = DSP_Halt8bitTransfer;
+      }
+
+   BLASTER_SoundRecording = TRUE;
+
+   return( BLASTER_Ok );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: BLASTER_DSP1xx_BeginRecord
+
+   Starts recording of digitized sound on cards compatible with DSP
+   version 1.xx.
+---------------------------------------------------------------------*/
+
+int BLASTER_DSP1xx_BeginRecord
+   (
+   int length
+   )
+
+   {
+   int SampleLength;
+   int LoByte;
+   int HiByte;
+
+   SampleLength = length - 1;
+   HiByte = hibyte( SampleLength );
+   LoByte = lobyte( SampleLength );
+
+   // Program DSP to play sound
+   BLASTER_WriteDSP( DSP_Old8BitADC );
+   BLASTER_WriteDSP( LoByte );
+   BLASTER_WriteDSP( HiByte );
+
+   BLASTER_HaltTransferCommand = DSP_Halt8bitTransfer;
+
+   BLASTER_SoundRecording = TRUE;
+
+   return( BLASTER_Ok );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: BLASTER_BeginBufferedRecord
+
+   Begins multibuffered recording of digitized sound on the sound card.
+---------------------------------------------------------------------*/
+
+int BLASTER_BeginBufferedRecord
+   (
+   char    *BufferStart,
+   int      BufferSize,
+   int      NumDivisions,
+   unsigned SampleRate,
+   int      MixMode,
+   void  ( *CallBackFunc )( void )
+   )
+
+   {
+   int DmaStatus;
+   int TransferLength;
+
+//JIM
+//   if ( BLASTER_SoundPlaying || BLASTER_SoundRecording )
+      {
+      BLASTER_StopPlayback();
+      }
+
+   BLASTER_SetMixMode( MixMode );
+
+   DmaStatus = BLASTER_SetupDMABuffer( BufferStart, BufferSize, DMA_AutoInitWrite );
+   if ( DmaStatus == BLASTER_Error )
+      {
+      return( BLASTER_Error );
+      }
+
+   BLASTER_SetPlaybackRate( SampleRate );
+
+   BLASTER_SetCallBack( CallBackFunc );
+
+   BLASTER_EnableInterrupt();
+
+   // Turn off speaker
+   BLASTER_SpeakerOff();
+
+   TransferLength = BufferSize / NumDivisions;
+   BLASTER_TransferLength = TransferLength;
+
+   //  Program the sound card to start the transfer.
+   if ( BLASTER_Version < DSP_Version2xx )
+      {
+      BLASTER_DSP1xx_BeginRecord( TransferLength );
+      }
+   else if ( BLASTER_Version < DSP_Version4xx )
+      {
+      BLASTER_DSP2xx_BeginRecord( TransferLength );
+      }
+   else
+      {
+      BLASTER_DSP4xx_BeginRecord( TransferLength );
+      }
+
+   return( BLASTER_Ok );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: BLASTER_WriteMixer
+
+   Writes a byte of data to the Sound Blaster's mixer chip.
+---------------------------------------------------------------------*/
+
+void BLASTER_WriteMixer
+   (
+   int reg,
+   int data
+   )
+
+   {
+   outp( BLASTER_MixerAddress + BLASTER_MixerAddressPort, reg );
+   outp( BLASTER_MixerAddress + BLASTER_MixerDataPort, data );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: BLASTER_ReadMixer
+
+   Reads a byte of data from the Sound Blaster's mixer chip.
+---------------------------------------------------------------------*/
+
+int BLASTER_ReadMixer
+   (
+   int reg
+   )
+
+   {
+   int data;
+
+   outp( BLASTER_MixerAddress + BLASTER_MixerAddressPort, reg );
+   data = inp( BLASTER_MixerAddress + BLASTER_MixerDataPort );
+   return( data );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: BLASTER_GetVoiceVolume
+
+   Reads the average volume of the digitized sound channel from the
+   Sound Blaster's mixer chip.
+---------------------------------------------------------------------*/
+
+int BLASTER_GetVoiceVolume
+   (
+   void
+   )
+
+   {
+   int volume;
+   int left;
+   int right;
+
+   switch( BLASTER_MixerType )
+      {
+      case SBPro :
+      case SBPro2 :
+         left   = BLASTER_ReadMixer( MIXER_SBProVoice );
+         right  = ( left & 0x0f ) << 4;
+         left  &= 0xf0;
+         volume = ( left + right ) / 2;
+         break;
+
+      case SB16 :
+         left  = BLASTER_ReadMixer( MIXER_SB16VoiceLeft );
+         right = BLASTER_ReadMixer( MIXER_SB16VoiceRight );
+         volume = ( left + right ) / 2;
+         break;
+
+      default :
+         BLASTER_SetErrorCode( BLASTER_NoMixer );
+         volume = BLASTER_Error;
+      }
+
+   return( volume );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: BLASTER_SetVoiceVolume
+
+   Sets the volume of the digitized sound channel on the Sound
+   Blaster's mixer chip.
+---------------------------------------------------------------------*/
+
+int BLASTER_SetVoiceVolume
+   (
+   int volume
+   )
+
+   {
+   int data;
+   int status;
+
+   volume = min( 255, volume );
+   volume = max( 0, volume );
+
+   status = BLASTER_Ok;
+   switch( BLASTER_MixerType )
+      {
+      case SBPro :
+      case SBPro2 :
+         data = ( volume & 0xf0 ) + ( volume >> 4 );
+         BLASTER_WriteMixer( MIXER_SBProVoice, data );
+         break;
+
+      case SB16 :
+         BLASTER_WriteMixer( MIXER_SB16VoiceLeft, volume & 0xf8 );
+         BLASTER_WriteMixer( MIXER_SB16VoiceRight, volume & 0xf8 );
+         break;
+
+      default :
+         BLASTER_SetErrorCode( BLASTER_NoMixer );
+         status = BLASTER_Error;
+      }
+
+   return( status );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: BLASTER_GetMidiVolume
+
+   Reads the average volume of the Midi sound channel from the
+   Sound Blaster's mixer chip.
+---------------------------------------------------------------------*/
+
+int BLASTER_GetMidiVolume
+   (
+   void
+   )
+
+   {
+   int volume;
+   int left;
+   int right;
+
+   switch( BLASTER_MixerType )
+      {
+      case SBPro :
+      case SBPro2 :
+         left   = BLASTER_ReadMixer( MIXER_SBProMidi );
+         right  = ( left & 0x0f ) << 4;
+         left  &= 0xf0;
+         volume = ( left + right ) / 2;
+         break;
+
+      case SB16 :
+         left  = BLASTER_ReadMixer( MIXER_SB16MidiLeft );
+         right = BLASTER_ReadMixer( MIXER_SB16MidiRight );
+         volume = ( left + right ) / 2;
+         break;
+
+      default :
+         BLASTER_SetErrorCode( BLASTER_NoMixer );
+         volume = BLASTER_Error;
+      }
+
+   return( volume );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: BLASTER_SetMidiVolume
+
+   Sets the volume of the Midi sound channel on the Sound
+   Blaster's mixer chip.
+---------------------------------------------------------------------*/
+
+int BLASTER_SetMidiVolume
+   (
+   int volume
+   )
+
+   {
+   int data;
+   int status;
+
+   volume = min( 255, volume );
+   volume = max( 0, volume );
+
+   status = BLASTER_Ok;
+   switch( BLASTER_MixerType )
+      {
+      case SBPro :
+      case SBPro2 :
+         data = ( volume & 0xf0 ) + ( volume >> 4 );
+         BLASTER_WriteMixer( MIXER_SBProMidi, data );
+         break;
+
+      case SB16 :
+         BLASTER_WriteMixer( MIXER_SB16MidiLeft, volume & 0xf8 );
+         BLASTER_WriteMixer( MIXER_SB16MidiRight, volume & 0xf8 );
+         break;
+
+      default :
+         BLASTER_SetErrorCode( BLASTER_NoMixer );
+         status = BLASTER_Error;
+      }
+
+   return( status );
+   }
+
+/*---------------------------------------------------------------------
+   Function: BLASTER_CardHasMixer
+
+   Checks if the selected Sound Blaster card has a mixer.
+---------------------------------------------------------------------*/
+
+int BLASTER_CardHasMixer
+   (
+   void
+   )
+
+   {
+   return( BLASTER_Card.HasMixer );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: BLASTER_SaveVoiceVolume
+
+   Saves the user's voice mixer settings.
+---------------------------------------------------------------------*/
+
+void BLASTER_SaveVoiceVolume
+   (
+   void
+   )
+
+   {
+   switch( BLASTER_MixerType )
+      {
+      case SBPro :
+      case SBPro2 :
+         BLASTER_OriginalVoiceVolumeLeft =
+            BLASTER_ReadMixer( MIXER_SBProVoice );
+         break;
+
+      case SB16 :
+         BLASTER_OriginalVoiceVolumeLeft =
+            BLASTER_ReadMixer( MIXER_SB16VoiceLeft );
+         BLASTER_OriginalVoiceVolumeRight =
+            BLASTER_ReadMixer( MIXER_SB16VoiceRight );
+         break;
+      }
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: BLASTER_RestoreVoiceVolume
+
+   Restores the user's voice mixer settings.
+---------------------------------------------------------------------*/
+
+void BLASTER_RestoreVoiceVolume
+   (
+   void
+   )
+
+   {
+   switch( BLASTER_MixerType )
+      {
+      case SBPro :
+      case SBPro2 :
+         BLASTER_WriteMixer( MIXER_SBProVoice,
+            BLASTER_OriginalVoiceVolumeLeft );
+         break;
+
+      case SB16 :
+         BLASTER_WriteMixer( MIXER_SB16VoiceLeft,
+            BLASTER_OriginalVoiceVolumeLeft );
+         BLASTER_WriteMixer( MIXER_SB16VoiceRight,
+            BLASTER_OriginalVoiceVolumeRight );
+         break;
+      }
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: BLASTER_SaveMidiVolume
+
+   Saves the user's FM mixer settings.
+---------------------------------------------------------------------*/
+
+void BLASTER_SaveMidiVolume
+   (
+   void
+   )
+
+   {
+   switch( BLASTER_MixerType )
+      {
+      case SBPro :
+      case SBPro2 :
+         BLASTER_OriginalMidiVolumeLeft =
+            BLASTER_ReadMixer( MIXER_SBProMidi );
+         break;
+
+      case SB16 :
+         BLASTER_OriginalMidiVolumeLeft =
+            BLASTER_ReadMixer( MIXER_SB16MidiLeft );
+         BLASTER_OriginalMidiVolumeRight =
+            BLASTER_ReadMixer( MIXER_SB16MidiRight );
+         break;
+      }
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: BLASTER_RestoreMidiVolume
+
+   Restores the user's FM mixer settings.
+---------------------------------------------------------------------*/
+
+void BLASTER_RestoreMidiVolume
+   (
+   void
+   )
+
+   {
+   switch( BLASTER_MixerType )
+      {
+      case SBPro :
+      case SBPro2 :
+         BLASTER_WriteMixer( MIXER_SBProMidi,
+            BLASTER_OriginalMidiVolumeLeft );
+         break;
+
+      case SB16 :
+         BLASTER_WriteMixer( MIXER_SB16MidiLeft,
+            BLASTER_OriginalMidiVolumeLeft );
+         BLASTER_WriteMixer( MIXER_SB16MidiRight,
+            BLASTER_OriginalMidiVolumeRight );
+         break;
+      }
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: BLASTER_GetEnv
+
+   Retrieves the BLASTER environment settings and returns them to
+   the caller.
+---------------------------------------------------------------------*/
+
+int BLASTER_GetEnv
+   (
+   BLASTER_CONFIG *Config
+   )
+
+   {
+   char *Blaster;
+   char parameter;
+
+   Config->Address   = UNDEFINED;
+   Config->Type      = UNDEFINED;
+   Config->Interrupt = UNDEFINED;
+   Config->Dma8      = UNDEFINED;
+   Config->Dma16     = UNDEFINED;
+   Config->Midi      = UNDEFINED;
+   Config->Emu       = UNDEFINED;
+
+   Blaster = getenv( "BLASTER" );
+   if ( Blaster == NULL )
+      {
+      BLASTER_SetErrorCode( BLASTER_EnvNotFound );
+      return( BLASTER_Error );
+      }
+
+   while( *Blaster != 0 )
+      {
+      if ( *Blaster == ' ' )
+         {
+         Blaster++;
+         continue;
+         }
+
+      parameter = toupper( *Blaster );
+      Blaster++;
+
+      if ( !isxdigit( *Blaster ) )
+         {
+         BLASTER_SetErrorCode( BLASTER_InvalidParameter );
+         return( BLASTER_Error );
+         }
+
+      switch( parameter )
+         {
+         case BlasterEnv_Address :
+            sscanf( Blaster, "%x", &Config->Address );
+            break;
+         case BlasterEnv_Interrupt :
+            sscanf( Blaster, "%d", &Config->Interrupt );
+            break;
+         case BlasterEnv_8bitDma :
+            sscanf( Blaster, "%d", &Config->Dma8 );
+            break;
+         case BlasterEnv_Type :
+            sscanf( Blaster, "%d", &Config->Type );
+            break;
+         case BlasterEnv_16bitDma :
+            sscanf( Blaster, "%d", &Config->Dma16 );
+            break;
+         case BlasterEnv_Midi :
+            sscanf( Blaster, "%x", &Config->Midi );
+            break;
+         case BlasterEnv_EmuAddress :
+            sscanf( Blaster, "%x", &Config->Emu );
+            break;
+         default  :
+            // Skip the offending data
+            // sscanf( Blaster, "%*s" );
+            break;
+         }
+
+      while( isxdigit( *Blaster ) )
+         {
+         Blaster++;
+         }
+      }
+
+   return( BLASTER_Ok );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: BLASTER_SetCardSettings
+
+   Sets up the sound card's parameters.
+---------------------------------------------------------------------*/
+
+int BLASTER_SetCardSettings
+   (
+   BLASTER_CONFIG Config
+   )
+
+   {
+   if ( BLASTER_Installed )
+      {
+      BLASTER_Shutdown();
+      }
+
+   BLASTER_Config.Address   = Config.Address;
+   BLASTER_Config.Type      = Config.Type;
+   BLASTER_Config.Interrupt = Config.Interrupt;
+   BLASTER_Config.Dma8      = Config.Dma8;
+   BLASTER_Config.Dma16     = Config.Dma16;
+   BLASTER_Config.Midi      = Config.Midi;
+   BLASTER_Config.Emu       = Config.Emu;
+   BLASTER_MixerAddress     = Config.Address;
+   BLASTER_MixerType        = Config.Type;
+
+   if ( BLASTER_Config.Emu == UNDEFINED )
+      {
+      BLASTER_Config.Emu = BLASTER_Config.Address + 0x400;
+      }
+
+   return( BLASTER_Ok );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: BLASTER_GetCardSettings
+
+   Sets up the sound card's parameters.
+---------------------------------------------------------------------*/
+
+int BLASTER_GetCardSettings
+   (
+   BLASTER_CONFIG *Config
+   )
+
+   {
+   if ( BLASTER_Config.Address == UNDEFINED )
+      {
+      return( BLASTER_Warning );
+      }
+   else
+      {
+      Config->Address   = BLASTER_Config.Address;
+      Config->Type      = BLASTER_Config.Type;
+      Config->Interrupt = BLASTER_Config.Interrupt;
+      Config->Dma8      = BLASTER_Config.Dma8;
+      Config->Dma16     = BLASTER_Config.Dma16;
+      Config->Midi      = BLASTER_Config.Midi;
+      Config->Emu       = BLASTER_Config.Emu;
+      }
+
+   return( BLASTER_Ok );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: BLASTER_GetCardInfo
+
+   Returns the maximum number of bits that can represent a sample
+   (8 or 16) and the number of channels (1 for mono, 2 for stereo).
+---------------------------------------------------------------------*/
+
+int BLASTER_GetCardInfo
+   (
+   int *MaxSampleBits,
+   int *MaxChannels
+   )
+
+   {
+   if ( BLASTER_Card.MaxMixMode & STEREO )
+      {
+      *MaxChannels = 2;
+      }
+   else
+      {
+      *MaxChannels = 1;
+      }
+
+   if ( BLASTER_Card.MaxMixMode & SIXTEEN_BIT )
+      {
+      *MaxSampleBits = 16;
+      }
+   else
+      {
+      *MaxSampleBits = 8;
+      }
+
+   return( BLASTER_Ok );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: BLASTER_SetCallBack
+
+   Specifies the user function to call at the end of a sound transfer.
+---------------------------------------------------------------------*/
+
+void BLASTER_SetCallBack
+   (
+   void ( *func )( void )
+   )
+
+   {
+   BLASTER_CallBack = func;
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: BLASTER_LockEnd
+
+   Used for determining the length of the functions to lock in memory.
+---------------------------------------------------------------------*/
+
+static void BLASTER_LockEnd
+   (
+   void
+   )
+
+   {
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: BLASTER_UnlockMemory
+
+   Unlocks all neccessary data.
+---------------------------------------------------------------------*/
+
+void BLASTER_UnlockMemory
+   (
+   void
+   )
+
+   {
+   DPMI_UnlockMemoryRegion( BLASTER_LockStart, BLASTER_LockEnd );
+   DPMI_UnlockMemory( ( void * )&BLASTER_Interrupts[ 0 ],
+      sizeof( BLASTER_Interrupts ) );
+   DPMI_UnlockMemory( ( void * )&BLASTER_SampleSize[ 0 ],
+      sizeof( BLASTER_SampleSize ) );
+   DPMI_Unlock( BLASTER_Card );
+   DPMI_Unlock( BLASTER_OldInt );
+   DPMI_Unlock( BLASTER_Config );
+   DPMI_Unlock( BLASTER_Installed );
+   DPMI_Unlock( BLASTER_Version );
+   DPMI_Unlock( BLASTER_DMABuffer );
+   DPMI_Unlock( BLASTER_DMABufferEnd );
+   DPMI_Unlock( BLASTER_CurrentDMABuffer );
+   DPMI_Unlock( BLASTER_TotalDMABufferSize );
+   DPMI_Unlock( BLASTER_TransferLength );
+   DPMI_Unlock( BLASTER_MixMode );
+   DPMI_Unlock( BLASTER_SamplePacketSize );
+   DPMI_Unlock( BLASTER_SampleRate );
+   DPMI_Unlock( BLASTER_HaltTransferCommand );
+   DPMI_Unlock( ( int )BLASTER_SoundPlaying );
+   DPMI_Unlock( ( int )BLASTER_SoundRecording );
+   DPMI_Unlock( BLASTER_CallBack );
+   DPMI_Unlock( BLASTER_IntController1Mask );
+   DPMI_Unlock( BLASTER_IntController2Mask );
+   DPMI_Unlock( BLASTER_MixerAddress );
+   DPMI_Unlock( BLASTER_MixerType );
+   DPMI_Unlock( BLASTER_OriginalMidiVolumeLeft );
+   DPMI_Unlock( BLASTER_OriginalMidiVolumeRight );
+   DPMI_Unlock( BLASTER_OriginalVoiceVolumeLeft );
+   DPMI_Unlock( BLASTER_OriginalVoiceVolumeRight );
+   DPMI_Unlock( GlobalStatus );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: BLASTER_LockMemory
+
+   Locks all neccessary data.
+---------------------------------------------------------------------*/
+
+int BLASTER_LockMemory
+   (
+   void
+   )
+
+   {
+   int status;
+
+   status  = DPMI_LockMemoryRegion( BLASTER_LockStart, BLASTER_LockEnd );
+   status |= DPMI_LockMemory( ( void * )&BLASTER_Interrupts[ 0 ],
+      sizeof( BLASTER_Interrupts ) );
+   status |= DPMI_LockMemory( ( void * )&BLASTER_SampleSize[ 0 ],
+      sizeof( BLASTER_SampleSize ) );
+   status |= DPMI_Lock( BLASTER_Card );
+   status |= DPMI_Lock( BLASTER_OldInt );
+   status |= DPMI_Lock( BLASTER_Config );
+   status |= DPMI_Lock( BLASTER_Installed );
+   status |= DPMI_Lock( BLASTER_Version );
+   status |= DPMI_Lock( BLASTER_DMABuffer );
+   status |= DPMI_Lock( BLASTER_DMABufferEnd );
+   status |= DPMI_Lock( BLASTER_CurrentDMABuffer );
+   status |= DPMI_Lock( BLASTER_TotalDMABufferSize );
+   status |= DPMI_Lock( BLASTER_TransferLength );
+   status |= DPMI_Lock( BLASTER_MixMode );
+   status |= DPMI_Lock( BLASTER_SamplePacketSize );
+   status |= DPMI_Lock( BLASTER_SampleRate );
+   status |= DPMI_Lock( BLASTER_HaltTransferCommand );
+   status |= DPMI_Lock( ( ( int )BLASTER_SoundPlaying ) );
+   status |= DPMI_Lock( ( ( int )BLASTER_SoundRecording ) );
+   status |= DPMI_Lock( BLASTER_CallBack );
+   status |= DPMI_Lock( BLASTER_IntController1Mask );
+   status |= DPMI_Lock( BLASTER_IntController2Mask );
+   status |= DPMI_Lock( BLASTER_MixerAddress );
+   status |= DPMI_Lock( BLASTER_MixerType );
+   status |= DPMI_Lock( BLASTER_OriginalMidiVolumeLeft );
+   status |= DPMI_Lock( BLASTER_OriginalMidiVolumeRight );
+   status |= DPMI_Lock( BLASTER_OriginalVoiceVolumeLeft );
+   status |= DPMI_Lock( BLASTER_OriginalVoiceVolumeRight );
+   status |= DPMI_Lock( GlobalStatus );
+
+   if ( status != DPMI_Ok )
+      {
+      BLASTER_UnlockMemory();
+      BLASTER_SetErrorCode( BLASTER_DPMI_Error );
+      return( BLASTER_Error );
+      }
+
+   return( BLASTER_Ok );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: allocateTimerStack
+
+   Allocate a block of memory from conventional (low) memory and return
+   the selector (which can go directly into a segment register) of the
+   memory block or 0 if an error occured.
+---------------------------------------------------------------------*/
+
+static unsigned short allocateTimerStack
+   (
+   unsigned short size
+   )
+
+   {
+   union REGS regs;
+
+   // clear all registers
+   memset( &regs, 0, sizeof( regs ) );
+
+   // DPMI allocate conventional memory
+   regs.w.ax = 0x100;
+
+   // size in paragraphs
+   regs.w.bx = ( size + 15 ) / 16;
+
+   int386( 0x31, &regs, &regs );
+   if (!regs.w.cflag)
+      {
+      // DPMI call returns selector in dx
+      // (ax contains real mode segment
+      // which is ignored here)
+
+      return( regs.w.dx );
+      }
+
+   // Couldn't allocate memory.
+   return( NULL );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: deallocateTimerStack
+
+   Deallocate a block of conventional (low) memory given a selector to
+   it.  Assumes the block was allocated with DPMI function 0x100.
+---------------------------------------------------------------------*/
+
+static void deallocateTimerStack
+   (
+   unsigned short selector
+   )
+
+   {
+   union REGS regs;
+
+   if ( selector != NULL )
+      {
+      // clear all registers
+      memset( &regs, 0, sizeof( regs ) );
+
+      regs.w.ax = 0x101;
+      regs.w.dx = selector;
+      int386( 0x31, &regs, &regs );
+      }
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: BLASTER_SetupWaveBlaster
+
+   Allows the WaveBlaster to play music while the Sound Blaster 16
+   plays digital sound.
+---------------------------------------------------------------------*/
+
+void BLASTER_SetupWaveBlaster
+   (
+   void
+   )
+
+   {
+
+   if ( BLASTER_MixerType == SB16 )
+      {
+      // Disable MPU401 interrupts.  If they are not disabled,
+      // the SB16 will not produce sound or music.
+      BLASTER_WaveBlasterState = BLASTER_ReadMixer( MIXER_DSP4xxISR_Enable );
+      BLASTER_WriteMixer( MIXER_DSP4xxISR_Enable, MIXER_DisableMPU401Interrupts );
+      }
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: BLASTER_ShutdownWaveBlaster
+
+   Restores WaveBlaster mixer to original state.
+---------------------------------------------------------------------*/
+
+void BLASTER_ShutdownWaveBlaster
+   (
+   void
+   )
+
+   {
+   if ( BLASTER_MixerType == SB16 )
+      {
+      // Restore the state of MPU401 interrupts.  If they are not disabled,
+      // the SB16 will not produce sound or music.
+      BLASTER_WriteMixer( MIXER_DSP4xxISR_Enable, BLASTER_WaveBlasterState );
+      }
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: BLASTER_Init
+
+   Initializes the sound card and prepares the module to play
+   digitized sounds.
+---------------------------------------------------------------------*/
+
+int BLASTER_Init
+   (
+   void
+   )
+
+   {
+   int Irq;
+   int Interrupt;
+   int status;
+
+   if ( BLASTER_Installed )
+      {
+      BLASTER_Shutdown();
+      }
+
+   if ( BLASTER_Config.Address == UNDEFINED )
+      {
+      BLASTER_SetErrorCode( BLASTER_AddrNotSet );
+      return( BLASTER_Error );
+      }
+
+   // Save the interrupt masks
+   BLASTER_IntController1Mask = inp( 0x21 );
+   BLASTER_IntController2Mask = inp( 0xA1 );
+
+   status = BLASTER_ResetDSP();
+   if ( status == BLASTER_Ok )
+      {
+      BLASTER_SaveVoiceVolume();
+
+      BLASTER_SoundPlaying = FALSE;
+
+      BLASTER_SetCallBack( NULL );
+
+      BLASTER_DMABuffer = NULL;
+
+      BLASTER_Version = BLASTER_GetDSPVersion();
+
+      BLASTER_SetPlaybackRate( BLASTER_DefaultSampleRate );
+      BLASTER_SetMixMode( BLASTER_DefaultMixMode );
+
+      if ( BLASTER_Config.Dma16 != UNDEFINED )
+         {
+         status = DMA_VerifyChannel( BLASTER_Config.Dma16 );
+         if ( status == DMA_Error )
+            {
+            BLASTER_SetErrorCode( BLASTER_DmaError );
+            return( BLASTER_Error );
+            }
+         }
+
+      if ( BLASTER_Config.Dma8 != UNDEFINED )
+         {
+         status = DMA_VerifyChannel( BLASTER_Config.Dma8 );
+         if ( status == DMA_Error )
+            {
+            BLASTER_SetErrorCode( BLASTER_DmaError );
+            return( BLASTER_Error );
+            }
+         }
+
+      // Install our interrupt handler
+      Irq = BLASTER_Config.Interrupt;
+      if ( !VALID_IRQ( Irq ) )
+         {
+         BLASTER_SetErrorCode( BLASTER_InvalidIrq );
+         return( BLASTER_Error );
+         }
+
+      Interrupt = BLASTER_Interrupts[ Irq ];
+      if ( Interrupt == INVALID )
+         {
+         BLASTER_SetErrorCode( BLASTER_InvalidIrq );
+         return( BLASTER_Error );
+         }
+
+      status = BLASTER_LockMemory();
+      if ( status != BLASTER_Ok )
+         {
+         BLASTER_UnlockMemory();
+         return( status );
+         }
+
+      StackSelector = allocateTimerStack( kStackSize );
+      if ( StackSelector == NULL )
+         {
+         BLASTER_UnlockMemory();
+         BLASTER_SetErrorCode( BLASTER_OutOfMemory );
+         return( BLASTER_Error );
+         }
+
+      // Leave a little room at top of stack just for the hell of it...
+      StackPointer = kStackSize - sizeof( long );
+
+      BLASTER_OldInt = _dos_getvect( Interrupt );
+      if ( Irq < 8 )
+         {
+         _dos_setvect( Interrupt, BLASTER_ServiceInterrupt );
+         }
+      else
+         {
+         status = IRQ_SetVector( Interrupt, BLASTER_ServiceInterrupt );
+         if ( status != IRQ_Ok )
+            {
+            BLASTER_UnlockMemory();
+            deallocateTimerStack( StackSelector );
+            StackSelector = NULL;
+            BLASTER_SetErrorCode( BLASTER_UnableToSetIrq );
+            return( BLASTER_Error );
+            }
+         }
+
+      BLASTER_Installed = TRUE;
+      status = BLASTER_Ok;
+      }
+
+   BLASTER_SetErrorCode( status );
+   return( status );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: BLASTER_Shutdown
+
+   Ends transfer of sound data to the sound card and restores the
+   system resources used by the card.
+---------------------------------------------------------------------*/
+
+void BLASTER_Shutdown
+   (
+   void
+   )
+
+   {
+   int Irq;
+   int Interrupt;
+
+   // Halt the DMA transfer
+   BLASTER_StopPlayback();
+
+   BLASTER_RestoreVoiceVolume();
+
+   // Reset the DSP
+   BLASTER_ResetDSP();
+
+   // Restore the original interrupt
+   Irq = BLASTER_Config.Interrupt;
+   Interrupt = BLASTER_Interrupts[ Irq ];
+   if ( Irq >= 8 )
+      {
+      IRQ_RestoreVector( Interrupt );
+      }
+   _dos_setvect( Interrupt, BLASTER_OldInt );
+
+   BLASTER_SoundPlaying = FALSE;
+
+   BLASTER_DMABuffer = NULL;
+
+   BLASTER_SetCallBack( NULL );
+
+   BLASTER_UnlockMemory();
+
+   deallocateTimerStack( StackSelector );
+   StackSelector = NULL;
+
+   BLASTER_Installed = FALSE;
+   }
--- /dev/null
+++ b/rott/audiolib/blaster.h
@@ -1,0 +1,148 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+/**********************************************************************
+   module: BLASTER.H
+
+   author: James R. Dose
+   date:   February 4, 1994
+
+   Public header for BLASTER.C
+
+   (c) Copyright 1994 James R. Dose.  All Rights Reserved.
+**********************************************************************/
+
+#ifndef __BLASTER_H
+#define __BLASTER_H
+
+typedef struct
+   {
+   unsigned Address;
+   unsigned Type;
+   unsigned Interrupt;
+   unsigned Dma8;
+   unsigned Dma16;
+   unsigned Midi;
+   unsigned Emu;
+   } BLASTER_CONFIG;
+
+extern BLASTER_CONFIG BLASTER_Config;
+extern int BLASTER_DMAChannel;
+
+#define UNDEFINED -1
+
+enum BLASTER_ERRORS
+   {
+   BLASTER_Warning = -2,
+   BLASTER_Error = -1,
+   BLASTER_Ok = 0,
+   BLASTER_EnvNotFound,
+   BLASTER_AddrNotSet,
+   BLASTER_DMANotSet,
+   BLASTER_DMA16NotSet,
+   BLASTER_InvalidParameter,
+   BLASTER_CardNotReady,
+   BLASTER_NoSoundPlaying,
+   BLASTER_InvalidIrq,
+   BLASTER_UnableToSetIrq,
+   BLASTER_DmaError,
+   BLASTER_NoMixer,
+   BLASTER_DPMI_Error,
+   BLASTER_OutOfMemory
+   };
+
+enum BLASTER_Types
+   {
+   SB     = 1,
+   SBPro  = 2,
+   SB20   = 3,
+   SBPro2 = 4,
+   SB16   = 6
+   };
+
+#define BLASTER_MinCardType    SB
+#define BLASTER_MaxCardType    SB16
+
+#define STEREO      1
+#define SIXTEEN_BIT 2
+
+#define MONO_8BIT    0
+#define STEREO_8BIT  ( STEREO )
+#define MONO_16BIT   ( SIXTEEN_BIT )
+#define STEREO_16BIT ( STEREO | SIXTEEN_BIT )
+
+#define BLASTER_MaxMixMode        STEREO_16BIT
+
+#define MONO_8BIT_SAMPLE_SIZE    1
+#define MONO_16BIT_SAMPLE_SIZE   2
+#define STEREO_8BIT_SAMPLE_SIZE  ( 2 * MONO_8BIT_SAMPLE_SIZE )
+#define STEREO_16BIT_SAMPLE_SIZE ( 2 * MONO_16BIT_SAMPLE_SIZE )
+
+#define BLASTER_DefaultSampleRate 11000
+#define BLASTER_DefaultMixMode    MONO_8BIT
+#define BLASTER_MaxIrq            15
+
+char *BLASTER_ErrorString( int ErrorNumber );
+void  BLASTER_EnableInterrupt( void );
+void  BLASTER_DisableInterrupt( void );
+int   BLASTER_WriteDSP( unsigned data );
+int   BLASTER_ReadDSP( void );
+int   BLASTER_ResetDSP( void );
+int   BLASTER_GetDSPVersion( void );
+void  BLASTER_SpeakerOn( void );
+void  BLASTER_SpeakerOff( void );
+void  BLASTER_SetPlaybackRate( unsigned rate );
+unsigned BLASTER_GetPlaybackRate( void );
+int   BLASTER_SetMixMode( int mode );
+void  BLASTER_StopPlayback( void );
+int   BLASTER_SetupDMABuffer( char *BufferPtr, int BufferSize, int mode );
+int   BLASTER_GetCurrentPos( void );
+int   BLASTER_DSP1xx_BeginPlayback( int length );
+int   BLASTER_DSP2xx_BeginPlayback( int length );
+int   BLASTER_DSP4xx_BeginPlayback( int length );
+int   BLASTER_BeginBufferedRecord( char *BufferStart, int BufferSize,
+          int NumDivisions, unsigned SampleRate, int MixMode,
+          void ( *CallBackFunc )( void ) );
+int   BLASTER_BeginBufferedPlayback( char *BufferStart,
+         int BufferSize, int NumDivisions, unsigned SampleRate,
+         int MixMode, void ( *CallBackFunc )( void ) );
+void  BLASTER_WriteMixer( int reg, int data );
+int   BLASTER_ReadMixer( int reg );
+int   BLASTER_GetVoiceVolume( void );
+int   BLASTER_SetVoiceVolume( int volume );
+int   BLASTER_GetMidiVolume( void );
+int   BLASTER_SetMidiVolume( int volume );
+int   BLASTER_CardHasMixer( void );
+void  BLASTER_SaveVoiceVolume( void );
+void  BLASTER_RestoreVoiceVolume( void );
+void  BLASTER_SaveMidiVolume( void );
+void  BLASTER_RestoreMidiVolume( void );
+int   BLASTER_GetEnv( BLASTER_CONFIG *Config );
+int   BLASTER_SetCardSettings( BLASTER_CONFIG Config );
+int   BLASTER_GetCardSettings( BLASTER_CONFIG *Config );
+int   BLASTER_GetCardInfo( int *MaxSampleBits, int *MaxChannels );
+void  BLASTER_SetCallBack( void ( *func )( void ) );
+void  BLASTER_SetupWaveBlaster( void );
+void  BLASTER_ShutdownWaveBlaster( void );
+int   BLASTER_Init( void );
+void  BLASTER_Shutdown( void );
+void  BLASTER_UnlockMemory( void );
+int   BLASTER_LockMemory( void );
+
+#endif
--- /dev/null
+++ b/rott/audiolib/ctaweapi.h
@@ -1,0 +1,352 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+/****************************************************************************\
+*                                                                            *
+* CTAWEAPI.H SB AWE32 DOS API header                                         *
+*                                                                            *
+* (C) Copyright Creative Technology Ltd. 1992-94. All rights reserved        *
+* worldwide.                                                                 *
+*                                                                            *
+* THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY      *
+* KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE        *
+* IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR      *
+* PURPOSE.                                                                   *
+*                                                                            *
+* You have a royalty-free right to use, modify, reproduce and                *
+* distribute the Sample Files (and/or any modified version) in               *
+* any way you find useful, provided that you agree to                        *
+* the Creative's Software Licensing Aggreement and you also agree that       *
+* Creative has no warranty obligations or liability for any Sample Files.    *
+*                                                                            *
+\****************************************************************************/
+
+/****************************************************************************\
+*      File name       : CTAWEAPI.H                                          *
+*                                                                            *
+*      Programmer      : Creative SB AWE32 Team                              *
+*                        Creative Technology Ltd, 1994. All rights reserved. *
+*                                                                            *
+*      Version         : 2.0b                                                *
+*                                                                            *
+\****************************************************************************/
+
+#ifndef _CTAWEAPI
+#define _CTAWEAPI
+
+
+#define MAXBANKS            64      /* maximum number of banks */
+#define MAXNRPN             32      /* maximum number of NRPN */
+
+
+#if defined(__FLAT__) || defined(__HIGHC__) || defined(DOS386)
+#define PACKETSIZE      8192        /* packet size for 32bit libraries */
+#else
+#define PACKETSIZE      512         /* packet size for real mode libraries */
+#endif
+
+
+#if defined(__FLAT__)
+    #define NEAR
+    #define FAR
+#endif
+
+
+#if defined(__SC__)
+    #pragma pack(1)
+    #if defined(DOS386)
+        #define NEAR
+        #define FAR
+    #endif
+#endif
+
+
+#if defined(__WATCOMC__)
+    #pragma pack(1)
+#endif
+
+
+#if defined(__HIGHC__)
+    #define NEAR
+    #define FAR
+    #define PASCAL  _DCC((_DEFAULT_CALLING_CONVENTION|_CALLEE_POPS_STACK) & \
+                         ~ (_REVERSE_PARMS|_OVERLOADED))
+    #pragma Push_align_members(1)
+    #pragma Global_aliasing_convention("_%r")
+#endif
+
+
+typedef int                     BOOL;
+#define FALSE                   0
+#define TRUE                    1
+
+typedef unsigned char		BYTE;
+typedef unsigned short		WORD;
+typedef unsigned long		DWORD;
+
+typedef short int               SHORT;
+typedef unsigned int		UINT;
+typedef signed long 		LONG;
+
+#ifndef FAR
+#define FAR                     __far
+#endif
+
+#ifndef HUGE
+#define HUGE                    __huge
+#endif
+
+#ifndef PASCAL
+#define PASCAL                  __pascal
+#endif
+
+typedef void FAR*               LPVOID;
+typedef BYTE FAR*               LPBYTE;
+typedef WORD FAR*               LPWORD;
+typedef DWORD FAR*              LPDWORD;
+
+#define LOBYTE(w)               ((BYTE)(w))
+#define HIBYTE(w)               ((BYTE)(((UINT)(w) >> 8) & 0xFF))
+
+#define LOWORD(l)               ((WORD)(DWORD)(l))
+#define HIWORD(l)               ((WORD)((((DWORD)(l)) >> 16) & 0xFFFF))
+
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+
+/* Start of modules */
+extern int* __midieng_code(void);
+extern int* __hardware_code(void);
+extern int* __sbkload_code(void);
+extern int* __nrpn_code(void);
+extern int __midivar_data;
+extern int __nrpnvar_data;
+extern int __embed_data;
+
+
+typedef char SCRATCH[702];
+typedef char SOUNDFONT[124];
+typedef char GCHANNEL[20];
+typedef char MIDICHANNEL[32];
+typedef char NRPNCHANNEL[96];
+
+typedef struct {
+    SHORT bank_no;          /* Slot number being used */
+    SHORT total_banks;      /* Total number of banks */
+    LONG FAR* banksizes;    /* Pointer to a list of bank sizes */
+    LONG file_size;         /* exact size of the sound font file */
+    char FAR* data;         /* Address of buffer of size >= PACKETSIZE */
+    char FAR* presets;      /* Allocated memory for preset data */
+
+    LONG total_patch_ram;   /* Total patch ram available */
+    SHORT no_sample_packets;/* Number of packets of sound sample to stream */
+    LONG sample_seek;       /* Start file location of sound sample */
+    LONG preset_seek;       /* Address of preset_seek location */
+    LONG preset_read_size;  /* Number of bytes from preset_seek to allocate and read */
+    LONG preset_size;       /* Preset actual size */
+} SOUND_PACKET;
+
+typedef struct {
+    SHORT tag;              /* Must be 0x100 or 0x101 */
+    SHORT preset_size;      /* Preset table of this size is required */
+    SHORT no_wave_packets;  /* Number of packets of Wave sample to stream. */
+    LONG reserved;
+
+    SHORT bank_no;          /* bank number */
+    char FAR* data;         /* Address of packet of size PACKETSIZE */
+    char FAR* presets;      /* Allocated memory for preset data */
+    LONG sample_size;       /* Sample size, i.e. number of samples */
+    LONG samples_per_sec;   /* Samples per second */
+    SHORT bits_per_sample;  /* Bits per sample, 8 or 16 */
+    SHORT no_channels;      /* Number of channels, 1=mono, 2=stereo */
+    SHORT looping;          /* Looping? 0=no, 1=yes */
+    LONG startloop;         /* if looping, then these are the addresses */
+    LONG endloop;
+    SHORT release;          /* release time, 0=24ms, 8191=23.78s */
+} WAVE_PACKET;
+
+typedef struct {
+    LPBYTE SPad1;
+    LPBYTE SPad2;
+    LPBYTE SPad3;
+    LPBYTE SPad4;
+    LPBYTE SPad5;
+    LPBYTE SPad6;
+    LPBYTE SPad7;
+} SOUNDPAD;
+
+/* AWE32 variables */
+extern WORD         awe32NumG;
+extern WORD         awe32BaseAddx;
+extern DWORD        awe32DramSize;
+
+/* MIDI variables */
+extern SCRATCH      awe32Scratch;
+extern SOUNDFONT    awe32SFont[4];
+extern GCHANNEL     awe32GChannel[32];
+extern MIDICHANNEL  awe32MIDIChannel[16];
+extern SOUNDPAD     awe32SoundPad;
+
+/* NRPN variables */
+extern NRPNCHANNEL  awe32NRPNChannel[16];
+
+/* SoundFont objects */
+extern BYTE awe32SPad1Obj[];
+extern BYTE awe32SPad2Obj[];
+extern BYTE awe32SPad3Obj[];
+extern BYTE awe32SPad4Obj[];
+extern BYTE awe32SPad5Obj[];
+extern BYTE awe32SPad6Obj[];
+extern BYTE awe32SPad7Obj[];
+
+/* AWE register functions */
+extern void PASCAL awe32RegW(WORD, WORD);
+extern WORD PASCAL awe32RegRW(WORD);
+extern void PASCAL awe32RegDW(WORD, DWORD);
+extern DWORD PASCAL awe32RegRDW(WORD);
+
+/* MIDI support functions */
+extern WORD PASCAL awe32InitMIDI(void);
+extern WORD PASCAL awe32NoteOn(WORD, WORD, WORD);
+extern WORD PASCAL awe32NoteOff(WORD, WORD, WORD);
+extern WORD PASCAL awe32ProgramChange(WORD, WORD);
+extern WORD PASCAL awe32Controller(WORD, WORD, WORD);
+extern WORD PASCAL awe32PolyKeyPressure(WORD, WORD, WORD);
+extern WORD PASCAL awe32ChannelPressure(WORD, WORD);
+extern WORD PASCAL awe32PitchBend(WORD, WORD, WORD);
+extern WORD PASCAL awe32Sysex(WORD, LPBYTE, WORD);
+extern WORD PASCAL __awe32NoteOff(WORD, WORD, WORD, WORD);
+extern WORD PASCAL __awe32IsPlaying(WORD, WORD, WORD, WORD);
+
+/* NRPN support functions */
+extern WORD PASCAL awe32InitNRPN(void);
+
+/* Hardware support functions */
+extern WORD PASCAL awe32Detect(WORD);
+extern WORD PASCAL awe32InitHardware(void);
+extern WORD PASCAL awe32Terminate(void);
+
+/* SoundFont support functions */
+extern WORD PASCAL awe32TotalPatchRam(SOUND_PACKET FAR*);
+extern WORD PASCAL awe32DefineBankSizes(SOUND_PACKET FAR*);
+extern WORD PASCAL awe32SFontLoadRequest(SOUND_PACKET FAR*);
+extern WORD PASCAL awe32StreamSample(SOUND_PACKET FAR*);
+extern WORD PASCAL awe32SetPresets(SOUND_PACKET FAR*);
+extern WORD PASCAL awe32ReleaseBank(SOUND_PACKET FAR*);
+extern WORD PASCAL awe32ReleaseAllBanks(SOUND_PACKET FAR*);
+extern WORD PASCAL awe32WPLoadRequest(WAVE_PACKET FAR*);
+extern WORD PASCAL awe32WPLoadWave(WAVE_PACKET FAR*);
+extern WORD PASCAL awe32WPStreamWave(WAVE_PACKET FAR*);
+extern WORD PASCAL awe32WPBuildSFont(WAVE_PACKET FAR*);
+
+/* End of modules */
+extern int* __midieng_ecode(void);
+extern int* __hardware_ecode(void);
+extern int* __sbkload_ecode(void);
+extern int* __nrpn_ecode(void);
+extern int __midivar_edata;
+extern int __nrpnvar_edata;
+extern int __embed_edata;
+
+
+#if defined(__cplusplus)
+}
+#endif
+
+
+#if defined(__SC__)
+    #pragma pack()
+#endif
+
+
+#if defined(__HIGHC__)
+    #pragma Pop_align_members
+    #pragma Global_aliasing_convention()
+    #pragma Alias(awe32RegW,"AWE32REGW")
+    #pragma Alias(awe32RegRW,"AWE32REGRW")
+    #pragma Alias(awe32RegDW,"AWE32REGDW")
+    #pragma Alias(awe32RegRDW,"AWE32REGRDW")
+    #pragma Alias(awe32InitMIDI,"AWE32INITMIDI")
+    #pragma Alias(awe32NoteOn,"AWE32NOTEON")
+    #pragma Alias(awe32NoteOff,"AWE32NOTEOFF")
+    #pragma Alias(awe32ProgramChange,"AWE32PROGRAMCHANGE")
+    #pragma Alias(awe32Controller,"AWE32CONTROLLER")
+    #pragma Alias(awe32PolyKeyPressure,"AWE32POLYKEYPRESSURE")
+    #pragma Alias(awe32ChannelPressure,"AWE32CHANNELPRESSURE")
+    #pragma Alias(awe32PitchBend,"AWE32PITCHBEND")
+    #pragma Alias(awe32Sysex,"AWE32SYSEX")
+    #pragma Alias(__awe32NoteOff,"__AWE32NOTEOFF")
+    #pragma Alias(__awe32IsPlaying,"__AWE32ISPLAYING")
+    #pragma Alias(awe32InitNRPN,"AWE32INITNRPN")
+    #pragma Alias(awe32Detect,"AWE32DETECT")
+    #pragma Alias(awe32InitHardware,"AWE32INITHARDWARE")
+    #pragma Alias(awe32Terminate,"AWE32TERMINATE")
+    #pragma Alias(awe32TotalPatchRam,"AWE32TOTALPATCHRAM")
+    #pragma Alias(awe32DefineBankSizes,"AWE32DEFINEBANKSIZES")
+    #pragma Alias(awe32SFontLoadRequest,"AWE32SFONTLOADREQUEST")
+    #pragma Alias(awe32StreamSample,"AWE32STREAMSAMPLE")
+    #pragma Alias(awe32SetPresets,"AWE32SETPRESETS")
+    #pragma Alias(awe32ReleaseBank,"AWE32RELEASEBANK")
+    #pragma Alias(awe32ReleaseAllBanks,"AWE32RELEASEALLBANKS")
+    #pragma Alias(awe32WPLoadRequest,"AWE32WPLOADREQUEST")
+    #pragma Alias(awe32WPLoadWave,"AWE32WPLOADWAVE")
+    #pragma Alias(awe32WPStreamWave,"AWE32WPSTREAMWAVE")
+    #pragma Alias(awe32WPBuildSFont,"AWE32WPBUILDSFONT")
+#endif
+
+
+#if defined(__WATCOMC__)
+    #pragma pack()
+    #pragma aux awe32NumG "_*"
+    #pragma aux awe32BaseAddx "_*"
+    #pragma aux awe32DramSize "_*"
+    #pragma aux awe32Scratch "_*"
+    #pragma aux awe32SFont "_*"
+    #pragma aux awe32GChannel "_*"
+    #pragma aux awe32MIDIChannel "_*"
+    #pragma aux awe32SoundPad "_*"
+    #pragma aux awe32NRPNChannel "_*"
+    #pragma aux awe32SPad1Obj "_*"
+    #pragma aux awe32SPad2Obj "_*"
+    #pragma aux awe32SPad3Obj "_*"
+    #pragma aux awe32SPad4Obj "_*"
+    #pragma aux awe32SPad5Obj "_*"
+    #pragma aux awe32SPad6Obj "_*"
+    #pragma aux awe32SPad7Obj "_*"
+    #pragma aux __midieng_code "_*"
+    #pragma aux __midieng_ecode "_*"
+    #pragma aux __hardware_code "_*"
+    #pragma aux __hardware_ecode "_*"
+    #pragma aux __sbkload_code "_*"
+    #pragma aux __sbkload_ecode "_*"
+    #pragma aux __nrpn_code "_*"
+    #pragma aux __nrpn_ecode "_*"
+    #pragma aux __midivar_data "_*"
+    #pragma aux __midivar_edata "_*"
+    #pragma aux __nrpnvar_data "_*"
+    #pragma aux __nrpnvar_edata "_*"
+    #pragma aux __embed_data "_*"
+    #pragma aux __embed_edata "_*"
+#endif
+
+
+#endif      /* _CTAWEAPI */
--- /dev/null
+++ b/rott/audiolib/debugio.c
@@ -1,0 +1,251 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include "debugio.h"
+
+static unsigned short disp_offset = 160 * 24;
+static void myutoa( unsigned num, char *string, int radix );
+static void myitoa( int num, char *string, int radix );
+
+void DB_SetXY
+   (
+   int x,
+   int y
+   )
+
+   {
+   disp_offset = ( x * 2 ) + ( y * 160 );
+   }
+
+void DB_PutChar
+   (
+   char ch
+   )
+
+   {
+   int j;
+   char *disp_start = (char *)( 0xb0000 );
+
+   if ( disp_offset >= 160 * 24 )
+      {
+      for ( j = 160; j < 160 * 24; j += 2 )
+         {
+         *( disp_start + j - 160 ) = *( disp_start + j );
+         }
+
+      disp_offset = 160 * 23;
+
+      for ( j = disp_offset; j < ( 160 * 24 ); j += 2 )
+         {
+         *( disp_start + j ) = ' ';
+         }
+      }
+
+   if ( ch >= 32 )
+      {
+      *( disp_start + disp_offset ) = ch;
+      disp_offset = disp_offset + 2;
+      }
+
+   if ( ch == '\r' )
+      {
+      disp_offset = disp_offset / 160;
+      disp_offset = disp_offset * 160;
+      }
+
+   if ( ch == '\n' )
+      {
+      disp_offset = disp_offset + 160;
+      if ( disp_offset < 160 * 24 )
+         {
+         for ( j = disp_offset; j < ( ( ( disp_offset / 160 ) + 1 ) *
+            160 ); j += 2 )
+            {
+            *( disp_start + j ) = ' ';
+            }
+         }
+      }
+   }
+
+int DB_PrintString
+   (
+   char *string
+   )
+
+   {
+   int count;
+   char *ptr;
+
+   ptr = string;
+   count = 0;
+
+   while ( *ptr )
+      {
+      DB_PutChar( *ptr );
+      count++;
+      ptr++;
+      }
+
+   return( count );
+   }
+
+static void myutoa
+   (
+   unsigned num,
+   char *string,
+   int radix
+   )
+
+   {
+   int val;
+   int length;
+   int pos;
+   char temp[ 100 ];
+
+   length = 0;
+   do
+      {
+      val = num % radix;
+      if ( val < 10 )
+         {
+         temp[ length ] = '0' + val;
+         }
+      else
+         {
+         temp[ length ] = 'A' + val - 10;
+         }
+      num /= radix;
+      length++;
+      }
+   while( num > 0 );
+
+   pos = 0;
+   while( length > 0 )
+      {
+      length--;
+      string[ length ] = temp[ pos ];
+      pos++;
+      }
+   string[ pos ] = 0;
+   }
+
+static void myitoa
+   (
+   int num,
+   char *string,
+   int radix
+   )
+
+   {
+   if ( num < 0 )
+      {
+      *string++ = '-';
+      num = -num;
+      }
+
+   myutoa( num, string, radix );
+   }
+
+int DB_PrintNum
+   (
+   int number
+   )
+
+   {
+   char string[ 100 ];
+   int  count;
+
+   myitoa( number, &string[ 0 ], 10 );
+   count = DB_PrintString( &string[ 0 ] );
+
+   return( count );
+   }
+
+int DB_PrintUnsigned
+   (
+   unsigned long number,
+   int radix
+   )
+
+   {
+   char string[ 100 ];
+   int  count;
+
+   myutoa( number, &string[ 0 ], radix );
+   count = DB_PrintString( &string[ 0 ] );
+
+   return( count );
+   }
+
+int DB_printf
+   (
+   char *fmt,
+   ...
+   )
+
+   {
+   va_list argptr;
+   int     count;
+   char    *ptr;
+
+   va_start( argptr, fmt );
+   ptr = fmt;
+   count = 0;
+
+   while( *ptr != 0 )
+      {
+      if ( *ptr == '%' )
+         {
+         ptr++;
+         switch( *ptr )
+            {
+            case 0 :
+               return( EOF );
+               break;
+            case 'd' :
+               count += DB_PrintNum( va_arg( argptr, int ) );
+               break;
+            case 's' :
+               count += DB_PrintString( va_arg( argptr, char * ) );
+               break;
+            case 'u' :
+               count += DB_PrintUnsigned( va_arg( argptr, int ), 10 );
+               break;
+            case 'x' :
+            case 'X' :
+               count += DB_PrintUnsigned( va_arg( argptr, int ), 16 );
+               break;
+            }
+         ptr++;
+         }
+      else
+         {
+         DB_PutChar( *ptr );
+         count++;
+         ptr++;
+         }
+      }
+
+   va_end( argptr );
+
+   return( count );
+   }
--- /dev/null
+++ b/rott/audiolib/debugio.h
@@ -1,0 +1,30 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+#ifndef __DEBUGIO_H
+#define __DEBUGIO_H
+
+void DB_SetXY( int x, int y );
+void DB_PutChar( char ch );
+int  DB_PrintString( char *string );
+int  DB_PrintNum( int number );
+int  DB_PrintUnsigned( unsigned long number, int radix );
+int  DB_printf( char *fmt, ... );
+
+#endif
--- /dev/null
+++ b/rott/audiolib/dma.c
@@ -1,0 +1,379 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+/**********************************************************************
+   module: DMA.C
+
+   author: James R. Dose
+   date:   February 4, 1994
+
+   Low level routines to for programming the DMA controller for 8 bit
+   and 16 bit transfers.
+
+   (c) Copyright 1994 James R. Dose.  All Rights Reserved.
+**********************************************************************/
+
+#include <dos.h>
+#include <conio.h>
+#include <stdlib.h>
+#include "dma.h"
+
+#define DMA_MaxChannel 7
+
+#define VALID   ( 1 == 1 )
+#define INVALID ( !VALID )
+
+#define BYTE 0
+#define WORD 1
+
+typedef struct
+   {
+   int Valid;
+   int Width;
+   int Mask;
+   int Mode;
+   int Clear;
+   int Page;
+   int Address;
+   int Length;
+   } DMA_PORT;
+
+static const DMA_PORT DMA_PortInfo[ DMA_MaxChannel + 1 ] =
+   {
+      {   VALID, BYTE,  0xA,  0xB,  0xC, 0x87,  0x0,  0x1 },
+      {   VALID, BYTE,  0xA,  0xB,  0xC, 0x83,  0x2,  0x3 },
+      { INVALID, BYTE,  0xA,  0xB,  0xC, 0x81,  0x4,  0x5 },
+      {   VALID, BYTE,  0xA,  0xB,  0xC, 0x82,  0x6,  0x7 },
+      { INVALID, WORD, 0xD4, 0xD6, 0xD8, 0x8F, 0xC0, 0xC2 },
+      {   VALID, WORD, 0xD4, 0xD6, 0xD8, 0x8B, 0xC4, 0xC6 },
+      {   VALID, WORD, 0xD4, 0xD6, 0xD8, 0x89, 0xC8, 0xCA },
+      {   VALID, WORD, 0xD4, 0xD6, 0xD8, 0x8A, 0xCC, 0xCE },
+   };
+
+int DMA_ErrorCode = DMA_Ok;
+
+#define DMA_SetErrorCode( status ) \
+   DMA_ErrorCode   = ( status );
+
+
+/*---------------------------------------------------------------------
+   Function: DMA_ErrorString
+
+   Returns a pointer to the error message associated with an error
+   number.  A -1 returns a pointer the current error.
+---------------------------------------------------------------------*/
+
+char *DMA_ErrorString
+   (
+   int ErrorNumber
+   )
+
+   {
+   char *ErrorString;
+
+   switch( ErrorNumber )
+      {
+      case DMA_Error :
+         ErrorString = DMA_ErrorString( DMA_ErrorCode );
+         break;
+
+      case DMA_Ok :
+         ErrorString = "DMA channel ok.";
+         break;
+
+      case DMA_ChannelOutOfRange :
+         ErrorString = "DMA channel out of valid range.";
+         break;
+
+      case DMA_InvalidChannel :
+         ErrorString = "Unsupported DMA channel.";
+         break;
+
+      default :
+         ErrorString = "Unknown DMA error code.";
+         break;
+      }
+
+   return( ErrorString );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: DMA_VerifyChannel
+
+   Verifies whether a DMA channel is available to transfer data.
+---------------------------------------------------------------------*/
+
+int DMA_VerifyChannel
+   (
+   int channel
+   )
+
+   {
+   int      status;
+   int      Error;
+
+   status = DMA_Ok;
+   Error  = DMA_Ok;
+
+   if ( ( channel < 0 ) || ( DMA_MaxChannel < channel ) )
+      {
+      Error = DMA_ChannelOutOfRange;
+      status = DMA_Error;
+      }
+   else if ( DMA_PortInfo[ channel ].Valid == INVALID )
+      {
+      Error = DMA_InvalidChannel;
+      status = DMA_Error;
+      }
+
+   DMA_SetErrorCode( Error );
+   return( status );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: DMA_SetupTransfer
+
+   Programs the specified DMA channel to transfer data.
+---------------------------------------------------------------------*/
+
+int DMA_SetupTransfer
+   (
+   int  channel,
+   char *address,
+   int  length,
+   int  mode
+   )
+
+   {
+   DMA_PORT *Port;
+   int      addr;
+   int      ChannelSelect;
+   int      Page;
+   int      HiByte;
+   int      LoByte;
+   int      TransferLength;
+   int      status;
+
+   status = DMA_VerifyChannel( channel );
+
+   if ( status == DMA_Ok )
+      {
+      Port = &DMA_PortInfo[ channel ];
+      ChannelSelect = channel & 0x3;
+
+      addr = ( int )address;
+
+      if ( Port->Width == WORD )
+         {
+         Page   = ( addr >> 16 ) & 255;
+         HiByte = ( addr >> 9 ) & 255;
+         LoByte = ( addr >> 1 ) & 255;
+
+         // Convert the length in bytes to the length in words
+         TransferLength = ( length + 1 ) >> 1;
+
+         // The length is always one less the number of bytes or words
+         // that we're going to send
+         TransferLength--;
+         }
+      else
+         {
+         Page   = ( addr >> 16 ) & 255;
+         HiByte = ( addr >> 8 ) & 255;
+         LoByte = addr & 255;
+
+         // The length is always one less the number of bytes or words
+         // that we're going to send
+         TransferLength = length - 1;
+         }
+
+      // Mask off DMA channel
+      outp( Port->Mask, 4 | ChannelSelect );
+
+      // Clear flip-flop to lower byte with any data
+      outp( Port->Clear, 0 );
+
+      // Set DMA mode
+      switch( mode )
+         {
+         case DMA_SingleShotRead :
+            outp( Port->Mode, 0x48 | ChannelSelect );
+            break;
+
+         case DMA_SingleShotWrite :
+            outp( Port->Mode, 0x44 | ChannelSelect );
+            break;
+
+         case DMA_AutoInitRead :
+            outp( Port->Mode, 0x58 | ChannelSelect );
+            break;
+
+         case DMA_AutoInitWrite :
+            outp( Port->Mode, 0x54 | ChannelSelect );
+            break;
+         }
+
+      // Send address
+      outp( Port->Address, LoByte );
+      outp( Port->Address, HiByte );
+
+      // Send page
+      outp( Port->Page, Page );
+
+      // Send length
+      outp( Port->Length, TransferLength );
+      outp( Port->Length, TransferLength >> 8 );
+
+      // enable DMA channel
+      outp( Port->Mask, ChannelSelect );
+      }
+
+   return( status );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: DMA_EndTransfer
+
+   Ends use of the specified DMA channel.
+---------------------------------------------------------------------*/
+
+int DMA_EndTransfer
+   (
+   int channel
+   )
+
+   {
+   DMA_PORT *Port;
+   int       ChannelSelect;
+   int       status;
+
+   status = DMA_VerifyChannel( channel );
+   if ( status == DMA_Ok )
+      {
+      Port = &DMA_PortInfo[ channel ];
+      ChannelSelect = channel & 0x3;
+
+      // Mask off DMA channel
+      outp( Port->Mask, 4 | ChannelSelect );
+
+      // Clear flip-flop to lower byte with any data
+      outp( Port->Clear, 0 );
+      }
+
+   return( status );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: DMA_GetCurrentPos
+
+   Returns the position of the specified DMA transfer.
+---------------------------------------------------------------------*/
+
+char *DMA_GetCurrentPos
+   (
+   int channel
+   )
+
+   {
+   DMA_PORT      *Port;
+   unsigned long addr;
+   int           status;
+
+   addr   = NULL;
+   status = DMA_VerifyChannel( channel );
+
+   if ( status == DMA_Ok )
+      {
+      Port = &DMA_PortInfo[ channel ];
+
+      if ( Port->Width == WORD )
+         {
+         // Get address
+         addr  = inp( Port->Address ) << 1;
+         addr |= inp( Port->Address ) << 9;
+
+         // Get page
+         addr |= inp( Port->Page ) << 16;
+         }
+      else
+         {
+         // Get address
+         addr = inp( Port->Address );
+         addr |= inp( Port->Address ) << 8;
+
+         // Get page
+         addr |= inp( Port->Page ) << 16;
+         }
+      }
+
+   return( ( char * )addr );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: DMA_GetTransferCount
+
+   Returns how many bytes are left in the DMA's transfer.
+---------------------------------------------------------------------*/
+
+int DMA_GetTransferCount
+   (
+   int channel
+   )
+
+   {
+   DMA_PORT      *Port;
+   int           count;
+   int           status;
+
+   status = DMA_Ok;
+
+   count = 0;
+
+   if ( ( channel < 0 ) || ( DMA_MaxChannel < channel ) )
+      {
+      status = DMA_ChannelOutOfRange;
+      }
+   else if ( DMA_PortInfo[ channel ].Valid == INVALID )
+      {
+      status = DMA_InvalidChannel;
+      }
+
+   if ( status == DMA_Ok )
+      {
+      Port = &DMA_PortInfo[ channel ];
+
+      outp( Port->Clear, 0 );
+      count  = inp( Port->Length );
+      count += inp( Port->Length ) << 8;
+
+      if ( Port->Width == WORD )
+         {
+         count <<= 1;
+         }
+      }
+
+   DMA_SetErrorCode( status );
+
+   return( count );
+   }
--- /dev/null
+++ b/rott/audiolib/dma.h
@@ -1,0 +1,83 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+/**********************************************************************
+   file:   DMA.H
+
+   author: James R. Dose
+   date:   February 4, 1994
+
+   Public header file for DMA.C
+
+   (c) Copyright 1994 James R. Dose.  All Rights Reserved.
+**********************************************************************/
+
+#ifndef __DMA_H
+#define __DMA_H
+
+enum DMA_ERRORS
+   {
+   DMA_Error = -1,
+   DMA_Ok    = 0,
+   DMA_ChannelOutOfRange,
+   DMA_InvalidChannel
+   };
+
+enum DMA_Modes
+   {
+   DMA_SingleShotRead,
+   DMA_SingleShotWrite,
+   DMA_AutoInitRead,
+   DMA_AutoInitWrite
+   };
+
+char *DMA_ErrorString
+   (
+   int ErrorNumber
+   );
+
+int DMA_VerifyChannel
+   (
+   int channel
+   );
+
+int DMA_SetupTransfer
+   (
+   int  channel,
+   char *address,
+   int  length,
+   int  mode
+   );
+
+int DMA_EndTransfer
+   (
+   int channel
+   );
+
+char *DMA_GetCurrentPos
+   (
+   int channel
+   );
+
+int DMA_GetTransferCount
+   (
+   int channel
+   );
+
+#endif
--- /dev/null
+++ b/rott/audiolib/dpmi.c
@@ -1,0 +1,250 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+/**********************************************************************
+   module: DPMI.C
+
+   author: James R. Dose
+   date:   April 8, 1994
+
+   Functions for performing DPMI calls.
+
+   (c) Copyright 1994 James R. Dose.  All Rights Reserved.
+**********************************************************************/
+
+#include <dos.h>
+#include <string.h>
+#include "dpmi.h"
+
+#define TRUE  ( 1 == 1 )
+#define FALSE ( !TRUE )
+
+static union  REGS  Regs;
+static struct SREGS SegRegs;
+
+
+/*---------------------------------------------------------------------
+   Function: DPMI_GetRealModeVector
+
+   Returns the vector of a real mode interrupt.
+---------------------------------------------------------------------*/
+
+unsigned long DPMI_GetRealModeVector
+   (
+   int num
+   )
+
+   {
+   unsigned long vector;
+
+   Regs.x.eax = 0x0200;
+   Regs.h.bl  = num;
+   int386( 0x31, &Regs, &Regs );
+
+   vector   = Regs.w.cx & 0xffff;
+   vector <<= 16;
+   vector  |= Regs.w.dx & 0xffff;
+
+   return( vector );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: DPMI_SetRealModeVector
+
+   Sets the vector of a real mode interrupt.
+---------------------------------------------------------------------*/
+
+void DPMI_SetRealModeVector
+   (
+   int num,
+   unsigned long vector
+   )
+
+   {
+   Regs.x.eax = 0x0201;
+   Regs.h.bl  = num;
+   Regs.w.dx = vector & 0xffff;
+   Regs.w.cx = ( vector >> 16 ) & 0xffff;
+
+   int386( 0x31, &Regs, &Regs );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: DPMI_CallRealModeFunction
+
+   Performs a call to a real mode function.
+---------------------------------------------------------------------*/
+
+int DPMI_CallRealModeFunction
+   (
+   dpmi_regs *callregs
+   )
+
+   {
+   // Setup our registers to call DPMI
+   Regs.w.ax = 0x0301;
+   Regs.h.bl = 0;
+   Regs.h.bh = 0;
+   Regs.w.cx = 0;
+
+   SegRegs.es = FP_SEG( callregs );
+   Regs.x.edi = FP_OFF( callregs );
+
+   // Call Real-mode procedure with Far Return Frame
+   int386x( 0x31, &Regs, &Regs, &SegRegs );
+
+   if ( Regs.x.cflag )
+      {
+      return( DPMI_Error );
+      }
+
+   return( DPMI_Ok );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: DPMI_LockMemory
+
+   Locks a region of memory to keep the virtual memory manager from
+   paging the region out.
+---------------------------------------------------------------------*/
+
+int DPMI_LockMemory
+   (
+   void *address,
+   unsigned length
+   )
+
+   {
+   unsigned linear;
+
+   // Thanks to DOS/4GW's zero-based flat memory model, converting
+   // a pointer of any type to a linear address is trivial.
+
+   linear = (unsigned) address;
+
+   // DPMI Lock Linear Region
+   Regs.w.ax = 0x600;
+
+   // Linear address in BX:CX
+   Regs.w.bx = (linear >> 16);
+   Regs.w.cx = (linear & 0xFFFF);
+
+   // Length in SI:DI
+   Regs.w.si = (length >> 16);
+   Regs.w.di = (length & 0xFFFF);
+
+   int386 (0x31, &Regs, &Regs);
+
+   // Return 0 if can't lock
+   if ( Regs.w.cflag )
+      {
+      return( DPMI_Error );
+      }
+
+   return ( DPMI_Ok );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: DPMI_LockMemoryRegion
+
+   Locks a region of memory to keep the virtual memory manager from
+   paging the region out.
+---------------------------------------------------------------------*/
+
+int DPMI_LockMemoryRegion
+   (
+   void *start,
+   void *end
+   )
+
+   {
+   int status;
+
+   status = DPMI_LockMemory( start, ( char * )end - ( char * )start );
+
+   return( status );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: DPMI_UnlockMemory
+
+   Unlocks a region of memory that was previously locked.
+---------------------------------------------------------------------*/
+
+int DPMI_UnlockMemory
+   (
+   void *address,
+   unsigned length
+   )
+
+   {
+   unsigned linear;
+
+   // Thanks to DOS/4GW's zero-based flat memory model, converting
+   // a pointer of any type to a linear address is trivial.
+
+   linear = (unsigned) address;
+
+   // DPMI Unlock Linear Region
+   Regs.w.ax = 0x601;
+
+   // Linear address in BX:CX
+   Regs.w.bx = (linear >> 16);
+   Regs.w.cx = (linear & 0xFFFF);
+
+   // Length in SI:DI
+   Regs.w.si = (length >> 16);
+   Regs.w.di = (length & 0xFFFF);
+
+   int386 (0x31, &Regs, &Regs);
+
+   // Return 0 if can't unlock
+   if ( Regs.w.cflag )
+      {
+      return( DPMI_Error );
+      }
+
+   return ( DPMI_Ok );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: DPMI_UnlockMemoryRegion
+
+   Unlocks a region of memory that was previously locked.
+---------------------------------------------------------------------*/
+
+int DPMI_UnlockMemoryRegion
+   (
+   void *start,
+   void *end
+   )
+
+   {
+   int status;
+
+   status = DPMI_UnlockMemory( start, ( char * )end - ( char * )start );
+
+   return( status );
+   }
--- /dev/null
+++ b/rott/audiolib/dpmi.h
@@ -1,0 +1,102 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+/**********************************************************************
+   module: DPMI.H
+
+   author: James R. Dose
+   date:   March 31, 1994
+
+   Inline functions for performing DPMI calls.
+
+   (c) Copyright 1994 James R. Dose.  All Rights Reserved.
+**********************************************************************/
+
+#ifndef __DPMI_H
+#define __DPMI_H
+
+enum DPMI_Errors
+   {
+   DPMI_Warning = -2,
+   DPMI_Error   = -1,
+   DPMI_Ok      = 0
+   };
+
+typedef struct
+   {
+   unsigned long  EDI;
+   unsigned long  ESI;
+   unsigned long  EBP;
+   unsigned long  Reserved;
+   unsigned long  EBX;
+   unsigned long  EDX;
+   unsigned long  ECX;
+   unsigned long  EAX;
+   unsigned short Flags;
+   unsigned short ES;
+   unsigned short DS;
+   unsigned short FS;
+   unsigned short GS;
+   unsigned short IP;
+   unsigned short CS;
+   unsigned short SP;
+   unsigned short SS;
+   } dpmi_regs;
+
+unsigned long DPMI_GetRealModeVector( int num );
+void DPMI_SetRealModeVector( int num, unsigned long vector );
+int  DPMI_CallRealModeFunction( dpmi_regs *callregs );
+int  DPMI_GetDOSMemory( void **ptr, long *descriptor, unsigned length );
+int  DPMI_FreeDOSMemory( long descriptor );
+int  DPMI_LockMemory( void *address, unsigned length );
+int  DPMI_LockMemoryRegion( void *start, void *end );
+int  DPMI_UnlockMemory( void *address, unsigned length );
+int  DPMI_UnlockMemoryRegion( void *start, void *end );
+
+#define DPMI_Lock( variable ) \
+   ( DPMI_LockMemory( (void *) &( variable ), sizeof( variable ) ) )
+
+#define DPMI_Unlock( variable ) \
+   ( DPMI_UnlockMemory( (void *) &( variable ), sizeof( variable ) ) )
+
+#ifdef PLAT_DOS
+#pragma aux DPMI_GetDOSMemory = \
+   "mov    eax, 0100h",         \
+   "add    ebx, 15",            \
+   "shr    ebx, 4",             \
+   "int    31h",                \
+   "jc     DPMI_Exit",          \
+   "movzx  eax, ax",            \
+   "shl    eax, 4",             \
+   "mov    [ esi ], eax",       \
+   "mov    [ edi ], edx",       \
+   "sub    eax, eax",           \
+   "DPMI_Exit:",                \
+   parm [ esi ] [ edi ] [ ebx ] modify exact [ eax ebx edx ];
+
+#pragma aux DPMI_FreeDOSMemory = \
+   "mov    eax, 0101h",          \
+   "int    31h",                 \
+   "jc     DPMI_Exit",           \
+   "sub    eax, eax",            \
+   "DPMI_Exit:",                 \
+   parm [ edx ] modify exact [ eax ];
+#endif
+
+#endif
--- /dev/null
+++ b/rott/audiolib/dsl.c
@@ -1,0 +1,235 @@
+#include <stdlib.h>
+#include <string.h>
+
+#include "dsl.h"
+#include "util.h"
+
+#include "SDL.h"
+#include "SDL_mixer.h"
+
+extern volatile int MV_MixPage;
+
+static int DSL_ErrorCode = DSL_Ok;
+
+static int mixer_initialized;
+
+static void ( *_CallBackFunc )( void );
+static volatile char *_BufferStart;
+static int _BufferSize;
+static int _NumDivisions;
+static int _SampleRate;
+static int _remainder;
+
+static Mix_Chunk *blank;
+static unsigned char *blank_buf;
+
+/*
+possible todo ideas: cache sdl/sdl mixer error messages.
+*/
+
+char *DSL_ErrorString( int ErrorNumber )
+{
+	char *ErrorString;
+	
+	switch (ErrorNumber) {
+		case DSL_Warning:
+		case DSL_Error:
+			ErrorString = DSL_ErrorString(DSL_ErrorCode);
+			break;
+		
+		case DSL_Ok:
+			ErrorString = "SDL Driver ok.";
+			break;
+		
+		case DSL_SDLInitFailure:
+			ErrorString = "SDL Audio initialization failed.";
+			break;
+		
+		case DSL_MixerActive:
+			ErrorString = "SDL Mixer already initialized.";
+			break;	
+	
+		case DSL_MixerInitFailure:
+			ErrorString = "SDL Mixer initialization failed.";
+			break;
+			
+		default:
+			ErrorString = "Unknown SDL Driver error.";
+			break;
+	}
+	
+	return ErrorString;
+}
+
+static void DSL_SetErrorCode(int ErrorCode)
+{
+	DSL_ErrorCode = ErrorCode;
+}
+
+int DSL_Init( void )
+{
+	DSL_SetErrorCode(DSL_Ok);
+	
+	if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) {
+		DSL_SetErrorCode(DSL_SDLInitFailure);
+		
+		return DSL_Error;
+	}
+	
+	return DSL_Ok;
+}
+
+void DSL_Shutdown( void )
+{
+	DSL_StopPlayback();
+}
+
+static void mixer_callback(int chan, void *stream, int len, void *udata)
+{
+	Uint8 *stptr;
+	Uint8 *fxptr;
+	int copysize;
+	
+	/* len should equal _BufferSize, else this is screwed up */
+
+	stptr = (Uint8 *)stream;
+	
+	if (_remainder > 0) {
+		copysize = min(len, _remainder);
+		
+		fxptr = (Uint8 *)(&_BufferStart[MV_MixPage * 
+			_BufferSize]);
+		
+		memcpy(stptr, fxptr+(_BufferSize-_remainder), copysize);
+		
+		len -= copysize;
+		_remainder -= copysize;
+		
+		stptr += copysize;
+	}
+	
+	while (len > 0) {
+		/* new buffer */
+		
+		_CallBackFunc();
+		
+		fxptr = (Uint8 *)(&_BufferStart[MV_MixPage * 
+			_BufferSize]);
+
+		copysize = min(len, _BufferSize);
+		
+		memcpy(stptr, fxptr, copysize);
+		
+		len -= copysize;
+		
+		stptr += copysize;
+	}
+	
+	_remainder = len;
+}
+
+int   DSL_BeginBufferedPlayback( char *BufferStart,
+      int BufferSize, int NumDivisions, unsigned SampleRate,
+      int MixMode, void ( *CallBackFunc )( void ) )
+{
+	Uint16 format;
+	Uint8 *tmp;
+	int channels;
+	int chunksize;
+		
+	if (mixer_initialized) {
+		DSL_SetErrorCode(DSL_MixerActive);
+		
+		return DSL_Error;
+	}
+	
+	_CallBackFunc = CallBackFunc;
+	_BufferStart = BufferStart;
+	_BufferSize = (BufferSize / NumDivisions);
+	_NumDivisions = NumDivisions;
+	_SampleRate = SampleRate;
+
+	_remainder = 0;
+	
+	format = (MixMode & SIXTEEN_BIT) ? AUDIO_S16SYS : AUDIO_U8;
+	channels = (MixMode & STEREO) ? 2 : 1;
+
+/*
+	23ms is typically ideal (11025,22050,44100)
+	46ms isn't bad
+*/
+	
+	chunksize = 512;
+	
+	if (SampleRate >= 16000) chunksize *= 2;
+	if (SampleRate >= 32000) chunksize *= 2;
+	
+/*	
+// SDL mixer does this already
+	if (MixMode & SIXTEEN_BIT) chunksize *= 2;
+	if (MixMode & STEREO) chunksize *= 2;
+*/
+	
+	if (Mix_OpenAudio(SampleRate, format, channels, chunksize) < 0) {
+		DSL_SetErrorCode(DSL_MixerInitFailure);
+		
+		return DSL_Error;
+	}
+
+/*
+	Mix_SetPostMix(mixer_callback, NULL);
+*/
+	/* have to use a channel because postmix will overwrite the music... */
+	Mix_RegisterEffect(0, mixer_callback, NULL, NULL);
+	
+	/* create a dummy sample just to allocate that channel */
+	blank_buf = (Uint8 *)malloc(4096);
+	memset(blank_buf, 0, 4096);
+	
+	blank = Mix_QuickLoad_RAW(blank_buf, 4096);
+		
+	Mix_PlayChannel(0, blank, -1);
+	
+	mixer_initialized = 1;
+	
+	return DSL_Ok;
+}
+
+void DSL_StopPlayback( void )
+{
+	if (mixer_initialized) {
+		Mix_HaltChannel(0);
+	}
+	
+	if (blank != NULL) {
+		Mix_FreeChunk(blank);
+	}
+	
+	blank = NULL;
+	
+	if (blank_buf  != NULL) {
+		free(blank_buf);
+	}
+	
+	blank_buf = NULL;
+	
+	if (mixer_initialized) {
+		Mix_CloseAudio();
+	}
+	
+	mixer_initialized = 0;
+}
+
+unsigned DSL_GetPlaybackRate( void )
+{
+	return _SampleRate;
+}
+
+unsigned long DisableInterrupts( void )
+{
+	return 0;
+}
+
+void RestoreInterrupts( unsigned long flags )
+{
+}
--- /dev/null
+++ b/rott/audiolib/dsl.h
@@ -1,0 +1,28 @@
+#ifndef AUDIOLIB__DSL_H
+#define AUDIOLIB__DSL_H
+
+#define MONO_8BIT    0
+#define STEREO      1
+#define SIXTEEN_BIT 2
+#define STEREO_16BIT ( STEREO | SIXTEEN_BIT )
+
+enum DSL_ERRORS
+   {
+   DSL_Warning = -2,
+   DSL_Error = -1,
+   DSL_Ok = 0,
+   DSL_SDLInitFailure,
+   DSL_MixerActive,
+   DSL_MixerInitFailure
+   };
+
+char *DSL_ErrorString( int ErrorNumber );
+int   DSL_Init( void );
+void  DSL_StopPlayback( void );
+unsigned DSL_GetPlaybackRate( void );
+int   DSL_BeginBufferedPlayback( char *BufferStart,
+      int BufferSize, int NumDivisions, unsigned SampleRate,
+      int MixMode, void ( *CallBackFunc )( void ) );
+void  DSL_Shutdown( void );
+
+#endif
--- /dev/null
+++ b/rott/audiolib/fx_man.c
@@ -1,0 +1,1376 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+/**********************************************************************
+   module: FX_MAN.C
+
+   author: James R. Dose
+   date:   March 17, 1994
+
+   Device independant sound effect routines.
+
+   (c) Copyright 1994 James R. Dose.  All Rights Reserved.
+**********************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "sndcards.h"
+#include "multivoc.h"
+
+#ifdef PLAT_DOS
+#include "blaster.h"
+#include "pas16.h"
+#include "sndscape.h"
+#include "guswave.h"
+#include "sndsrc.h"
+#else
+#include "dsl.h"
+#endif
+
+#include "ll_man.h"
+#include "user.h"
+#include "fx_man.h"
+
+#define TRUE  ( 1 == 1 )
+#define FALSE ( !TRUE )
+
+static unsigned FX_MixRate;
+
+int FX_SoundDevice = -1;
+int FX_ErrorCode = FX_Ok;
+int FX_Installed = FALSE;
+
+#define FX_SetErrorCode( status ) \
+   FX_ErrorCode = ( status );
+
+/*---------------------------------------------------------------------
+   Function: FX_ErrorString
+
+   Returns a pointer to the error message associated with an error
+   number.  A -1 returns a pointer the current error.
+---------------------------------------------------------------------*/
+
+char *FX_ErrorString
+   (
+   int ErrorNumber
+   )
+
+   {
+   char *ErrorString;
+
+   switch( ErrorNumber )
+      {
+      case FX_Warning :
+      case FX_Error :
+         ErrorString = FX_ErrorString( FX_ErrorCode );
+         break;
+
+      case FX_Ok :
+         ErrorString = "Fx ok.";
+         break;
+
+      case FX_ASSVersion :
+         ErrorString = "Apogee Sound System Version " ASS_VERSION_STRING "  "
+            "Programmed by Jim Dose\n"
+            "(c) Copyright 1995 James R. Dose.  All Rights Reserved.\n";
+         break;
+
+#ifdef PLAT_DOS
+      case FX_BlasterError :
+         ErrorString = BLASTER_ErrorString( BLASTER_Error );
+         break;
+#endif
+
+      case FX_SoundCardError :
+#ifdef PLAT_DOS
+         switch( FX_SoundDevice )
+         {
+            case SoundBlaster :
+            case Awe32 :
+               ErrorString = BLASTER_ErrorString( BLASTER_Error );
+               break;
+
+            case ProAudioSpectrum :
+            case SoundMan16 :
+               ErrorString = PAS_ErrorString( PAS_Error );
+               break;
+
+            case SoundScape :
+               ErrorString = SOUNDSCAPE_ErrorString( SOUNDSCAPE_Error );
+               break;
+
+            case UltraSound :
+               ErrorString = GUSWAVE_ErrorString( GUSWAVE_Error );
+               break;
+
+            case SoundSource :
+            case TandySoundSource :
+               ErrorString = SS_ErrorString( SS_Error );
+               break;
+            }
+#else
+         ErrorString = DSL_ErrorString( DSL_Error );
+#endif
+         break;
+
+      case FX_InvalidCard :
+         ErrorString = "Invalid Sound Fx device.";
+         break;
+
+      case FX_MultiVocError :
+         ErrorString = MV_ErrorString( MV_Error );
+         break;
+
+      case FX_DPMI_Error :
+         ErrorString = "DPMI Error in FX_MAN.";
+         break;
+
+      default :
+         ErrorString = "Unknown Fx error code.";
+         break;
+      }
+
+   return( ErrorString );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: FX_SetupCard
+
+   Sets the configuration of a sound device.
+---------------------------------------------------------------------*/
+
+int FX_SetupCard
+   (
+   int SoundCard,
+   fx_device *device
+   )
+
+   {
+   int status;
+   int DeviceStatus;
+
+   if ( USER_CheckParameter( "ASSVER" ) )
+      {
+      FX_SetErrorCode( FX_ASSVersion );
+      return( FX_Error );
+      }
+
+   FX_SoundDevice = SoundCard;
+
+   status = FX_Ok;
+   FX_SetErrorCode( FX_Ok );
+
+#ifdef PLAT_DOS
+   switch( SoundCard )
+      {
+      case SoundBlaster :
+      case Awe32 :
+         DeviceStatus = BLASTER_Init();
+         if ( DeviceStatus != BLASTER_Ok )
+            {
+            FX_SetErrorCode( FX_SoundCardError );
+            status = FX_Error;
+            break;
+            }
+
+         device->MaxVoices = 32;
+         BLASTER_GetCardInfo( &device->MaxSampleBits, &device->MaxChannels );
+         break;
+
+      case ProAudioSpectrum :
+      case SoundMan16 :
+         DeviceStatus = PAS_Init();
+         if ( DeviceStatus != PAS_Ok )
+            {
+            FX_SetErrorCode( FX_SoundCardError );
+            status = FX_Error;
+            break;
+            }
+
+         device->MaxVoices = 32;
+         PAS_GetCardInfo( &device->MaxSampleBits, &device->MaxChannels );
+         break;
+
+      case GenMidi :
+      case SoundCanvas :
+      case WaveBlaster :
+         device->MaxVoices     = 0;
+         device->MaxSampleBits = 0;
+         device->MaxChannels   = 0;
+         break;
+
+      case SoundScape :
+         device->MaxVoices = 32;
+         DeviceStatus = SOUNDSCAPE_GetCardInfo( &device->MaxSampleBits,
+            &device->MaxChannels );
+         if ( DeviceStatus != SOUNDSCAPE_Ok )
+            {
+            FX_SetErrorCode( FX_SoundCardError );
+            status = FX_Error;
+            }
+         break;
+
+      case UltraSound :
+         if ( GUSWAVE_Init( 8 ) != GUSWAVE_Ok )
+            {
+            FX_SetErrorCode( FX_SoundCardError );
+            status = FX_Error;
+            break;
+            }
+
+         device->MaxVoices     = 8;
+         device->MaxSampleBits = 0;
+         device->MaxChannels   = 0;
+         break;
+
+      case SoundSource :
+      case TandySoundSource :
+         DeviceStatus = SS_Init( SoundCard );
+         if ( DeviceStatus != SS_Ok )
+            {
+            FX_SetErrorCode( FX_SoundCardError );
+            status = FX_Error;
+            break;
+            }
+         SS_Shutdown();
+         device->MaxVoices     = 32;
+         device->MaxSampleBits = 8;
+         device->MaxChannels   = 1;
+         break;
+      default :
+         FX_SetErrorCode( FX_InvalidCard );
+         status = FX_Error;
+      }
+#else
+      DeviceStatus = DSL_Init();
+      if ( DeviceStatus != DSL_Ok )
+         {
+         FX_SetErrorCode( FX_SoundCardError );
+         status = FX_Error;
+         }
+         else
+         {
+         device->MaxVoices     = 32;
+         device->MaxSampleBits = 0;
+         device->MaxChannels   = 0;
+         }
+#endif
+
+   return( status );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: FX_GetBlasterSettings
+
+   Returns the current BLASTER environment variable settings.
+---------------------------------------------------------------------*/
+
+int FX_GetBlasterSettings
+   (
+   fx_blaster_config *blaster
+   )
+
+   {
+#ifdef PLAT_DOS
+   int status;
+   BLASTER_CONFIG Blaster;
+
+   FX_SetErrorCode( FX_Ok );
+
+   status = BLASTER_GetEnv( &Blaster );
+   if ( status != BLASTER_Ok )
+      {
+      FX_SetErrorCode( FX_BlasterError );
+      return( FX_Error );
+      }
+
+   blaster->Type      = Blaster.Type;
+   blaster->Address   = Blaster.Address;
+   blaster->Interrupt = Blaster.Interrupt;
+   blaster->Dma8      = Blaster.Dma8;
+   blaster->Dma16     = Blaster.Dma16;
+   blaster->Midi      = Blaster.Midi;
+   blaster->Emu       = Blaster.Emu;
+#endif
+
+   return( FX_Ok );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: FX_SetupSoundBlaster
+
+   Handles manual setup of the Sound Blaster information.
+---------------------------------------------------------------------*/
+
+int FX_SetupSoundBlaster
+   (
+   fx_blaster_config blaster,
+   int *MaxVoices,
+   int *MaxSampleBits,
+   int *MaxChannels
+   )
+
+   {
+#ifdef PLAT_DOS
+   int DeviceStatus;
+   BLASTER_CONFIG Blaster;
+
+   FX_SetErrorCode( FX_Ok );
+
+   FX_SoundDevice = SoundBlaster;
+
+   Blaster.Type      = blaster.Type;
+   Blaster.Address   = blaster.Address;
+   Blaster.Interrupt = blaster.Interrupt;
+   Blaster.Dma8      = blaster.Dma8;
+   Blaster.Dma16     = blaster.Dma16;
+   Blaster.Midi      = blaster.Midi;
+   Blaster.Emu       = blaster.Emu;
+
+   BLASTER_SetCardSettings( Blaster );
+
+   DeviceStatus = BLASTER_Init();
+   if ( DeviceStatus != BLASTER_Ok )
+      {
+      FX_SetErrorCode( FX_SoundCardError );
+      return( FX_Error );
+      }
+
+   *MaxVoices = 8;
+   BLASTER_GetCardInfo( MaxSampleBits, MaxChannels );
+#endif
+
+   return( FX_Ok );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: FX_Init
+
+   Selects which sound device to use.
+---------------------------------------------------------------------*/
+
+int FX_Init
+   (
+   int SoundCard,
+   int numvoices,
+   int numchannels,
+   int samplebits,
+   unsigned mixrate
+   )
+
+   {
+   int status;
+   int devicestatus;
+
+   if ( FX_Installed )
+      {
+      FX_Shutdown();
+      }
+
+   if ( USER_CheckParameter( "ASSVER" ) )
+      {
+      FX_SetErrorCode( FX_ASSVersion );
+      return( FX_Error );
+      }
+
+   status = LL_LockMemory();
+   if ( status != LL_Ok )
+      {
+      FX_SetErrorCode( FX_DPMI_Error );
+      return( FX_Error );
+      }
+
+   FX_MixRate = mixrate;
+
+   status = FX_Ok;
+   FX_SoundDevice = SoundCard;
+   switch( SoundCard )
+      {
+      case SoundBlaster :
+      case Awe32 :
+      case ProAudioSpectrum :
+      case SoundMan16 :
+      case SoundScape :
+      case SoundSource :
+      case TandySoundSource :
+      case UltraSound :
+         devicestatus = MV_Init( SoundCard, FX_MixRate, numvoices,
+            numchannels, samplebits );
+         if ( devicestatus != MV_Ok )
+            {
+            FX_SetErrorCode( FX_MultiVocError );
+            status = FX_Error;
+            }
+         break;
+
+      default :
+         FX_SetErrorCode( FX_InvalidCard );
+         status = FX_Error;
+      }
+
+   if ( status != FX_Ok )
+      {
+      LL_UnlockMemory();
+      }
+   else
+      {
+      FX_Installed = TRUE;
+      }
+
+   return( status );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: FX_Shutdown
+
+   Terminates use of sound device.
+---------------------------------------------------------------------*/
+
+int FX_Shutdown
+   (
+   void
+   )
+
+   {
+   int status;
+
+   if ( !FX_Installed )
+      {
+      return( FX_Ok );
+      }
+
+   status = FX_Ok;
+   switch( FX_SoundDevice )
+      {
+      case SoundBlaster :
+      case Awe32 :
+      case ProAudioSpectrum :
+      case SoundMan16 :
+      case SoundScape :
+      case SoundSource :
+      case TandySoundSource :
+      case UltraSound :
+         status = MV_Shutdown();
+         if ( status != MV_Ok )
+            {
+            FX_SetErrorCode( FX_MultiVocError );
+            status = FX_Error;
+            }
+         break;
+
+      default :
+         FX_SetErrorCode( FX_InvalidCard );
+         status = FX_Error;
+      }
+
+   FX_Installed = FALSE;
+   LL_UnlockMemory();
+
+   return( status );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: FX_SetCallback
+
+   Sets the function to call when a voice is done.
+---------------------------------------------------------------------*/
+
+int FX_SetCallBack
+   (
+   void ( *function )( unsigned long )
+   )
+
+   {
+   int status;
+
+   status = FX_Ok;
+
+   switch( FX_SoundDevice )
+      {
+      case SoundBlaster :
+      case Awe32 :
+      case ProAudioSpectrum :
+      case SoundMan16 :
+      case SoundScape :
+      case SoundSource :
+      case TandySoundSource :
+      case UltraSound :
+         MV_SetCallBack( function );
+         break;
+
+      default :
+         FX_SetErrorCode( FX_InvalidCard );
+         status = FX_Error;
+      }
+
+   return( status );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: FX_SetVolume
+
+   Sets the volume of the current sound device.
+---------------------------------------------------------------------*/
+
+void FX_SetVolume
+   (
+   int volume
+   )
+
+   {
+   int status;
+
+#ifdef PLAT_DOS
+   switch( FX_SoundDevice )
+      {
+      case SoundBlaster :
+      case Awe32 :
+         if ( BLASTER_CardHasMixer() )
+            {
+            BLASTER_SetVoiceVolume( volume );
+            }
+         else
+            {
+            MV_SetVolume( volume );
+            }
+         break;
+
+      case ProAudioSpectrum :
+      case SoundMan16 :
+         status = PAS_SetPCMVolume( volume );
+         if ( status != PAS_Ok )
+            {
+            MV_SetVolume( volume );
+            }
+         break;
+
+      case GenMidi :
+      case SoundCanvas :
+      case WaveBlaster :
+         break;
+
+      case SoundScape :
+         MV_SetVolume( volume );
+         break;
+
+      case UltraSound :
+         GUSWAVE_SetVolume( volume );
+         break;
+
+      case SoundSource :
+      case TandySoundSource :
+         MV_SetVolume( volume );
+         break;
+      }
+#else
+   MV_SetVolume( volume );
+#endif
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: FX_GetVolume
+
+   Returns the volume of the current sound device.
+---------------------------------------------------------------------*/
+
+int FX_GetVolume
+   (
+   void
+   )
+
+   {
+   int volume;
+
+#ifdef PLAT_DOS
+   switch( FX_SoundDevice )
+      {
+      case SoundBlaster :
+      case Awe32 :
+         if ( BLASTER_CardHasMixer() )
+            {
+            volume = BLASTER_GetVoiceVolume();
+            }
+         else
+            {
+            volume = MV_GetVolume();
+            }
+         break;
+
+      case ProAudioSpectrum :
+      case SoundMan16 :
+         volume = PAS_GetPCMVolume();
+         if ( volume == PAS_Error )
+            {
+            volume = MV_GetVolume();
+            }
+         break;
+
+      case GenMidi :
+      case SoundCanvas :
+      case WaveBlaster :
+         volume = 255;
+         break;
+
+      case SoundScape :
+         volume = MV_GetVolume();
+         break;
+
+      case UltraSound :
+         volume = GUSWAVE_GetVolume();
+         break;
+
+      case SoundSource :
+      case TandySoundSource :
+         volume = MV_GetVolume();
+         break;
+
+      default :
+         volume = 0;
+      }
+#else
+   volume = MV_GetVolume();
+#endif
+
+   return( volume );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: FX_SetReverseStereo
+
+   Set the orientation of the left and right channels.
+---------------------------------------------------------------------*/
+
+void FX_SetReverseStereo
+   (
+   int setting
+   )
+
+   {
+   MV_SetReverseStereo( setting );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: FX_GetReverseStereo
+
+   Returns the orientation of the left and right channels.
+---------------------------------------------------------------------*/
+
+int FX_GetReverseStereo
+   (
+   void
+   )
+
+   {
+   return MV_GetReverseStereo();
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: FX_SetReverb
+
+   Sets the reverb level.
+---------------------------------------------------------------------*/
+
+void FX_SetReverb
+   (
+   int reverb
+   )
+
+   {
+   MV_SetReverb( reverb );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: FX_SetFastReverb
+
+   Sets the reverb level.
+---------------------------------------------------------------------*/
+
+void FX_SetFastReverb
+   (
+   int reverb
+   )
+
+   {
+   MV_SetFastReverb( reverb );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: FX_GetMaxReverbDelay
+
+   Returns the maximum delay time for reverb.
+---------------------------------------------------------------------*/
+
+int FX_GetMaxReverbDelay
+   (
+   void
+   )
+
+   {
+   return MV_GetMaxReverbDelay();
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: FX_GetReverbDelay
+
+   Returns the current delay time for reverb.
+---------------------------------------------------------------------*/
+
+int FX_GetReverbDelay
+   (
+   void
+   )
+
+   {
+   return MV_GetReverbDelay();
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: FX_SetReverbDelay
+
+   Sets the delay level of reverb to add to mix.
+---------------------------------------------------------------------*/
+
+void FX_SetReverbDelay
+   (
+   int delay
+   )
+
+   {
+   MV_SetReverbDelay( delay );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: FX_VoiceAvailable
+
+   Checks if a voice can be play at the specified priority.
+---------------------------------------------------------------------*/
+
+int FX_VoiceAvailable
+   (
+   int priority
+   )
+
+   {
+   return MV_VoiceAvailable( priority );
+   }
+
+/*---------------------------------------------------------------------
+   Function: FX_EndLooping
+
+   Stops the voice associated with the specified handle from looping
+   without stoping the sound.
+---------------------------------------------------------------------*/
+
+int FX_EndLooping
+   (
+   int handle
+   )
+
+   {
+   int status;
+
+   status = MV_EndLooping( handle );
+   if ( status == MV_Error )
+      {
+      FX_SetErrorCode( FX_MultiVocError );
+      status = FX_Warning;
+      }
+
+   return( status );
+   }
+
+/*---------------------------------------------------------------------
+   Function: FX_SetPan
+
+   Sets the stereo and mono volume level of the voice associated
+   with the specified handle.
+---------------------------------------------------------------------*/
+
+int FX_SetPan
+   (
+   int handle,
+   int vol,
+   int left,
+   int right
+   )
+
+   {
+   int status;
+
+   status = MV_SetPan( handle, vol, left, right );
+   if ( status == MV_Error )
+      {
+      FX_SetErrorCode( FX_MultiVocError );
+      status = FX_Warning;
+      }
+
+   return( status );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: FX_SetPitch
+
+   Sets the pitch of the voice associated with the specified handle.
+---------------------------------------------------------------------*/
+
+int FX_SetPitch
+   (
+   int handle,
+   int pitchoffset
+   )
+
+   {
+   int status;
+
+   status = MV_SetPitch( handle, pitchoffset );
+   if ( status == MV_Error )
+      {
+      FX_SetErrorCode( FX_MultiVocError );
+      status = FX_Warning;
+      }
+
+   return( status );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: FX_SetFrequency
+
+   Sets the frequency of the voice associated with the specified handle.
+---------------------------------------------------------------------*/
+
+int FX_SetFrequency
+   (
+   int handle,
+   int frequency
+   )
+
+   {
+   int status;
+
+   status = MV_SetFrequency( handle, frequency );
+   if ( status == MV_Error )
+      {
+      FX_SetErrorCode( FX_MultiVocError );
+      status = FX_Warning;
+      }
+
+   return( status );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: FX_PlayVOC
+
+   Begin playback of sound data with the given volume and priority.
+---------------------------------------------------------------------*/
+
+int FX_PlayVOC
+   (
+   char *ptr,
+   int pitchoffset,
+   int vol,
+   int left,
+   int right,
+   int priority,
+   unsigned long callbackval
+   )
+
+   {
+   int handle;
+
+   handle = MV_PlayVOC( ptr, pitchoffset, vol, left, right,
+      priority, callbackval );
+   if ( handle < MV_Ok )
+      {
+      FX_SetErrorCode( FX_MultiVocError );
+      handle = FX_Warning;
+      }
+
+   return( handle );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: FX_PlayLoopedVOC
+
+   Begin playback of sound data with the given volume and priority.
+---------------------------------------------------------------------*/
+
+int FX_PlayLoopedVOC
+   (
+   char *ptr,
+   long loopstart,
+   long loopend,
+   int pitchoffset,
+   int vol,
+   int left,
+   int right,
+   int priority,
+   unsigned long callbackval
+   )
+
+   {
+   int handle;
+
+   handle = MV_PlayLoopedVOC( ptr, loopstart, loopend, pitchoffset,
+      vol, left, right, priority, callbackval );
+   if ( handle < MV_Ok )
+      {
+      FX_SetErrorCode( FX_MultiVocError );
+      handle = FX_Warning;
+      }
+
+   return( handle );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: FX_PlayWAV
+
+   Begin playback of sound data with the given volume and priority.
+---------------------------------------------------------------------*/
+
+int FX_PlayWAV
+   (
+   char *ptr,
+   int pitchoffset,
+   int vol,
+   int left,
+   int right,
+   int priority,
+   unsigned long callbackval
+   )
+
+   {
+   int handle;
+
+   handle = MV_PlayWAV( ptr, pitchoffset, vol, left, right,
+      priority, callbackval );
+   if ( handle < MV_Ok )
+      {
+      FX_SetErrorCode( FX_MultiVocError );
+      handle = FX_Warning;
+      }
+
+   return( handle );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: FX_PlayWAV
+
+   Begin playback of sound data with the given volume and priority.
+---------------------------------------------------------------------*/
+
+int FX_PlayLoopedWAV
+   (
+   char *ptr,
+   long loopstart,
+   long loopend,
+   int pitchoffset,
+   int vol,
+   int left,
+   int right,
+   int priority,
+   unsigned long callbackval
+   )
+
+   {
+   int handle;
+
+   handle = MV_PlayLoopedWAV( ptr, loopstart, loopend,
+      pitchoffset, vol, left, right, priority, callbackval );
+   if ( handle < MV_Ok )
+      {
+      FX_SetErrorCode( FX_MultiVocError );
+      handle = FX_Warning;
+      }
+
+   return( handle );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: FX_PlayVOC3D
+
+   Begin playback of sound data at specified angle and distance
+   from listener.
+---------------------------------------------------------------------*/
+
+int FX_PlayVOC3D
+   (
+   char *ptr,
+   int pitchoffset,
+   int angle,
+   int distance,
+   int priority,
+   unsigned long callbackval
+   )
+
+   {
+   int handle;
+
+   handle = MV_PlayVOC3D( ptr, pitchoffset, angle, distance,
+      priority, callbackval );
+   if ( handle < MV_Ok )
+      {
+      FX_SetErrorCode( FX_MultiVocError );
+      handle = FX_Warning;
+      }
+
+   return( handle );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: FX_PlayWAV3D
+
+   Begin playback of sound data at specified angle and distance
+   from listener.
+---------------------------------------------------------------------*/
+
+int FX_PlayWAV3D
+   (
+   char *ptr,
+   int pitchoffset,
+   int angle,
+   int distance,
+   int priority,
+   unsigned long callbackval
+   )
+
+   {
+   int handle;
+
+   handle = MV_PlayWAV3D( ptr, pitchoffset, angle, distance,
+      priority, callbackval );
+   if ( handle < MV_Ok )
+      {
+      FX_SetErrorCode( FX_MultiVocError );
+      handle = FX_Warning;
+      }
+
+   return( handle );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: FX_PlayRaw
+
+   Begin playback of raw sound data with the given volume and priority.
+---------------------------------------------------------------------*/
+
+int FX_PlayRaw
+   (
+   char *ptr,
+   unsigned long length,
+   unsigned rate,
+   int pitchoffset,
+   int vol,
+   int left,
+   int right,
+   int priority,
+   unsigned long callbackval
+   )
+
+   {
+   int handle;
+
+   handle = MV_PlayRaw( ptr, length, rate, pitchoffset,
+      vol, left, right, priority, callbackval );
+   if ( handle < MV_Ok )
+      {
+      FX_SetErrorCode( FX_MultiVocError );
+      handle = FX_Warning;
+      }
+
+   return( handle );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: FX_PlayLoopedRaw
+
+   Begin playback of raw sound data with the given volume and priority.
+---------------------------------------------------------------------*/
+
+int FX_PlayLoopedRaw
+   (
+   char *ptr,
+   unsigned long length,
+   char *loopstart,
+   char *loopend,
+   unsigned rate,
+   int pitchoffset,
+   int vol,
+   int left,
+   int right,
+   int priority,
+   unsigned long callbackval
+   )
+
+   {
+   int handle;
+
+   handle = MV_PlayLoopedRaw( ptr, length, loopstart, loopend,
+      rate, pitchoffset, vol, left, right, priority, callbackval );
+   if ( handle < MV_Ok )
+      {
+      FX_SetErrorCode( FX_MultiVocError );
+      handle = FX_Warning;
+      }
+
+   return( handle );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: FX_Pan3D
+
+   Set the angle and distance from the listener of the voice associated
+   with the specified handle.
+---------------------------------------------------------------------*/
+
+int FX_Pan3D
+   (
+   int handle,
+   int angle,
+   int distance
+   )
+
+   {
+   int status;
+
+   status = MV_Pan3D( handle, angle, distance );
+   if ( status != MV_Ok )
+      {
+      FX_SetErrorCode( FX_MultiVocError );
+      status = FX_Warning;
+      }
+
+   return( status );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: FX_SoundActive
+
+   Tests if the specified sound is currently playing.
+---------------------------------------------------------------------*/
+
+int FX_SoundActive
+   (
+   int handle
+   )
+
+   {
+   return( MV_VoicePlaying( handle ) );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: FX_SoundsPlaying
+
+   Reports the number of voices playing.
+---------------------------------------------------------------------*/
+
+int FX_SoundsPlaying
+   (
+   void
+   )
+
+   {
+   return( MV_VoicesPlaying() );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: FX_StopSound
+
+   Halts playback of a specific voice
+---------------------------------------------------------------------*/
+
+int FX_StopSound
+   (
+   int handle
+   )
+
+   {
+   int status;
+
+   status = MV_Kill( handle );
+   if ( status != MV_Ok )
+      {
+      FX_SetErrorCode( FX_MultiVocError );
+      return( FX_Warning );
+      }
+
+   return( FX_Ok );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: FX_StopAllSounds
+
+   Halts playback of all sounds.
+---------------------------------------------------------------------*/
+
+int FX_StopAllSounds
+   (
+   void
+   )
+
+   {
+   int status;
+
+   status = MV_KillAllVoices();
+   if ( status != MV_Ok )
+      {
+      FX_SetErrorCode( FX_MultiVocError );
+      return( FX_Warning );
+      }
+
+   return( FX_Ok );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: FX_StartDemandFeedPlayback
+
+   Plays a digitized sound from a user controlled buffering system.
+---------------------------------------------------------------------*/
+
+int FX_StartDemandFeedPlayback
+   (
+   void ( *function )( char **ptr, unsigned long *length ),
+   int rate,
+   int pitchoffset,
+   int vol,
+   int left,
+   int right,
+   int priority,
+   unsigned long callbackval
+   )
+
+   {
+   int handle;
+
+   handle = MV_StartDemandFeedPlayback( function, rate,
+      pitchoffset, vol, left, right, priority, callbackval );
+   if ( handle < MV_Ok )
+      {
+      FX_SetErrorCode( FX_MultiVocError );
+      handle = FX_Warning;
+      }
+
+   return( handle );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: FX_StartRecording
+
+   Starts the sound recording engine.
+---------------------------------------------------------------------*/
+
+int FX_StartRecording
+   (
+   int MixRate,
+   void ( *function )( char *ptr, int length )
+   )
+
+   {
+   int status;
+
+#ifdef PLAT_DOS
+   switch( FX_SoundDevice )
+      {
+      case SoundBlaster :
+      case Awe32 :
+      case ProAudioSpectrum :
+      case SoundMan16 :
+         status = MV_StartRecording( MixRate, function );
+         if ( status != MV_Ok )
+            {
+            FX_SetErrorCode( FX_MultiVocError );
+            status = FX_Warning;
+            }
+         else
+            {
+            status = FX_Ok;
+            }
+         break;
+
+      default :
+         FX_SetErrorCode( FX_InvalidCard );
+         status = FX_Warning;
+         break;
+      }
+#else
+   FX_SetErrorCode( FX_InvalidCard );
+   status = FX_Warning;
+#endif
+
+   return( status );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: FX_StopRecord
+
+   Stops the sound record engine.
+---------------------------------------------------------------------*/
+
+void FX_StopRecord
+   (
+   void
+   )
+
+   {
+#ifdef PLAT_DOS
+   // Stop sound playback
+   switch( FX_SoundDevice )
+      {
+      case SoundBlaster :
+      case Awe32 :
+      case ProAudioSpectrum :
+      case SoundMan16 :
+         MV_StopRecord();
+         break;
+      }
+#endif
+   }
--- /dev/null
+++ b/rott/audiolib/fx_man.h
@@ -1,0 +1,135 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+/**********************************************************************
+   module: FX_MAN.H
+
+   author: James R. Dose
+   date:   March 17, 1994
+
+   Public header for FX_MAN.C
+
+   (c) Copyright 1994 James R. Dose.  All Rights Reserved.
+**********************************************************************/
+
+#ifndef __FX_MAN_H
+#define __FX_MAN_H
+
+#include "sndcards.h"
+
+typedef struct
+   {
+   int MaxVoices;
+   int MaxSampleBits;
+   int MaxChannels;
+   } fx_device;
+
+#define MonoFx   1
+#define StereoFx 2
+
+typedef struct
+   {
+   unsigned long Address;
+   unsigned long Type;
+   unsigned long Interrupt;
+   unsigned long Dma8;
+   unsigned long Dma16;
+   unsigned long Midi;
+   unsigned long Emu;
+   } fx_blaster_config;
+
+enum FX_ERRORS
+   {
+   FX_Warning = -2,
+   FX_Error = -1,
+   FX_Ok = 0,
+   FX_ASSVersion,
+   FX_BlasterError,
+   FX_SoundCardError,
+   FX_InvalidCard,
+   FX_MultiVocError,
+   FX_DPMI_Error
+   };
+
+enum fx_BLASTER_Types
+   {
+   fx_SB     = 1,
+   fx_SBPro  = 2,
+   fx_SB20   = 3,
+   fx_SBPro2 = 4,
+   fx_SB16   = 6
+   };
+
+
+char *FX_ErrorString( int ErrorNumber );
+int   FX_SetupCard( int SoundCard, fx_device *device );
+int   FX_GetBlasterSettings( fx_blaster_config *blaster );
+int   FX_SetupSoundBlaster( fx_blaster_config blaster, int *MaxVoices, int *MaxSampleBits, int *MaxChannels );
+int   FX_Init( int SoundCard, int numvoices, int numchannels, int samplebits, unsigned mixrate );
+int   FX_Shutdown( void );
+int   FX_SetCallBack( void ( *function )( unsigned long ) );
+void  FX_SetVolume( int volume );
+int   FX_GetVolume( void );
+
+void  FX_SetReverseStereo( int setting );
+int   FX_GetReverseStereo( void );
+void  FX_SetReverb( int reverb );
+void  FX_SetFastReverb( int reverb );
+int   FX_GetMaxReverbDelay( void );
+int   FX_GetReverbDelay( void );
+void  FX_SetReverbDelay( int delay );
+
+int FX_VoiceAvailable( int priority );
+int FX_EndLooping( int handle );
+int FX_SetPan( int handle, int vol, int left, int right );
+int FX_SetPitch( int handle, int pitchoffset );
+int FX_SetFrequency( int handle, int frequency );
+
+int FX_PlayVOC( char *ptr, int pitchoffset, int vol, int left, int right,
+       int priority, unsigned long callbackval );
+int FX_PlayLoopedVOC( char *ptr, long loopstart, long loopend,
+       int pitchoffset, int vol, int left, int right, int priority,
+       unsigned long callbackval );
+int FX_PlayWAV( char *ptr, int pitchoffset, int vol, int left, int right,
+       int priority, unsigned long callbackval );
+int FX_PlayLoopedWAV( char *ptr, long loopstart, long loopend,
+       int pitchoffset, int vol, int left, int right, int priority,
+       unsigned long callbackval );
+int FX_PlayVOC3D( char *ptr, int pitchoffset, int angle, int distance,
+       int priority, unsigned long callbackval );
+int FX_PlayWAV3D( char *ptr, int pitchoffset, int angle, int distance,
+       int priority, unsigned long callbackval );
+int FX_PlayRaw( char *ptr, unsigned long length, unsigned rate,
+       int pitchoffset, int vol, int left, int right, int priority,
+       unsigned long callbackval );
+int FX_PlayLoopedRaw( char *ptr, unsigned long length, char *loopstart,
+       char *loopend, unsigned rate, int pitchoffset, int vol, int left,
+       int right, int priority, unsigned long callbackval );
+int FX_Pan3D( int handle, int angle, int distance );
+int FX_SoundActive( int handle );
+int FX_SoundsPlaying( void );
+int FX_StopSound( int handle );
+int FX_StopAllSounds( void );
+int FX_StartDemandFeedPlayback( void ( *function )( char **ptr, unsigned long *length ),
+       int rate, int pitchoffset, int vol, int left, int right,
+       int priority, unsigned long callbackval );
+int  FX_StartRecording( int MixRate, void ( *function )( char *ptr, int length ) );
+void FX_StopRecord( void );
+
+#endif
--- /dev/null
+++ b/rott/audiolib/gmtimbre.c
@@ -1,0 +1,290 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+typedef struct
+   {
+   unsigned char SAVEK[ 2 ];
+   unsigned char Level[ 2 ];
+   unsigned char Env1[ 2 ];
+   unsigned char Env2[ 2 ];
+   unsigned char Wave[ 2 ];
+   unsigned char Feedback;
+   signed   char Transpose;
+   signed   char Velocity;
+   } TIMBRE;
+
+TIMBRE ADLIB_TimbreBank[ 256 ] =
+   {
+      { { 33, 33 }, { 143, 6 }, { 242, 242 }, { 69, 118 }, { 0, 0 }, 8, 0 },
+      { { 49, 33 }, { 75, 0 }, { 242, 242 }, { 84, 86 }, { 0, 0 }, 8, 0 },
+      { { 49, 33 }, { 73, 0 }, { 242, 242 }, { 85, 118 }, { 0, 0 }, 8, 0 },
+      { { 177, 97 }, { 14, 0 }, { 242, 243 }, { 59, 11 }, { 0, 0 }, 6, 0 },
+      { { 1, 33 }, { 87, 0 }, { 241, 241 }, { 56, 40 }, { 0, 0 }, 0, 0 },
+      { { 1, 33 }, { 147, 0 }, { 241, 241 }, { 56, 40 }, { 0, 0 }, 0, 0 },
+      { { 33, 54 }, { 128, 14 }, { 162, 241 }, { 1, 213 }, { 0, 0 }, 8, 0 },
+      { { 1, 1 }, { 146, 0 }, { 194, 194 }, { 168, 88 }, { 0, 0 }, 10, 0 },
+      { { 12, 129 }, { 92, 0 }, { 246, 243 }, { 84, 181 }, { 0, 0 }, 0, 0 },
+      { { 7, 17 }, { 151, 128 }, { 246, 245 }, { 50, 17 }, { 0, 0 }, 2, 0 },
+      { { 23, 1 }, { 33, 0 }, { 86, 246 }, { 4, 4 }, { 0, 0 }, 2, 0 },
+      { { 24, 129 }, { 98, 0 }, { 243, 242 }, { 230, 246 }, { 0, 0 }, 0, 0 },
+      { { 24, 33 }, { 35, 0 }, { 247, 229 }, { 85, 216 }, { 0, 0 }, 0, 0 },
+      { { 21, 1 }, { 145, 0 }, { 246, 246 }, { 166, 230 }, { 0, 0 }, 4, 0 },
+      { { 69, 129 }, { 89, 128 }, { 211, 163 }, { 130, 227 }, { 0, 0 }, 12, 0 },
+      { { 3, 129 }, { 73, 128 }, { 116, 179 }, { 85, 5 }, { 1, 0 }, 4, 0 },
+      { { 113, 49 }, { 146, 0 }, { 246, 241 }, { 20, 7 }, { 0, 0 }, 2, 0 },
+      { { 114, 48 }, { 20, 0 }, { 199, 199 }, { 88, 8 }, { 0, 0 }, 2, 0 },
+      { { 112, 177 }, { 68, 0 }, { 170, 138 }, { 24, 8 }, { 0, 0 }, 4, 0 },
+      { { 35, 177 }, { 147, 0 }, { 151, 85 }, { 35, 20 }, { 1, 0 }, 4, 0 },
+      { { 97, 177 }, { 19, 128 }, { 151, 85 }, { 4, 4 }, { 1, 0 }, 0, 0 },
+      { { 36, 177 }, { 72, 0 }, { 152, 70 }, { 42, 26 }, { 1, 0 }, 12, 0 },
+      { { 97, 33 }, { 19, 0 }, { 145, 97 }, { 6, 7 }, { 1, 0 }, 10, 0 },
+      { { 33, 161 }, { 19, 137 }, { 113, 97 }, { 6, 7 }, { 0, 0 }, 6, 0 },
+      { { 2, 65 }, { 156, 128 }, { 243, 243 }, { 148, 200 }, { 1, 0 }, 12, 0 },
+      { { 3, 17 }, { 84, 0 }, { 243, 241 }, { 154, 231 }, { 1, 0 }, 12, 0 },
+      { { 35, 33 }, { 95, 0 }, { 241, 242 }, { 58, 248 }, { 0, 0 }, 0, 0 },
+      { { 3, 33 }, { 135, 128 }, { 246, 243 }, { 34, 243 }, { 1, 0 }, 6, 0 },
+      { { 3, 33 }, { 71, 0 }, { 249, 246 }, { 84, 58 }, { 0, 0 }, 0, 0 },
+      { { 35, 33 }, { 72, 0 }, { 149, 132 }, { 25, 25 }, { 1, 0 }, 8, 0 },
+      { { 35, 33 }, { 74, 0 }, { 149, 148 }, { 25, 25 }, { 1, 0 }, 8, 0 },
+      { { 9, 132 }, { 161, 128 }, { 32, 209 }, { 79, 248 }, { 0, 0 }, 8, 0 },
+      { { 33, 162 }, { 30, 0 }, { 148, 195 }, { 6, 166 }, { 0, 0 }, 2, 0 },
+      { { 49, 49 }, { 18, 0 }, { 241, 241 }, { 40, 24 }, { 0, 0 }, 10, 0 },
+      { { 49, 49 }, { 141, 0 }, { 241, 241 }, { 232, 120 }, { 0, 0 }, 10, 0 },
+      { { 49, 50 }, { 91, 0 }, { 81, 113 }, { 40, 72 }, { 0, 0 }, 12, 0 },
+      { { 1, 33 }, { 139, 64 }, { 161, 242 }, { 154, 223 }, { 0, 0 }, 8, 0 },
+      { { 1, 33 }, { 137, 64 }, { 161, 242 }, { 154, 223 }, { 0, 0 }, 8, 0 },
+      { { 49, 49 }, { 139, 0 }, { 244, 241 }, { 232, 120 }, { 0, 0 }, 10, 0 },
+      { { 49, 49 }, { 18, 0 }, { 241, 241 }, { 40, 24 }, { 0, 0 }, 10, 0 },
+      { { 49, 33 }, { 21, 0 }, { 221, 86 }, { 19, 38 }, { 1, 0 }, 8, 0 },
+      { { 49, 33 }, { 22, 0 }, { 221, 102 }, { 19, 6 }, { 1, 0 }, 8, 0 },
+      { { 113, 49 }, { 73, 0 }, { 209, 97 }, { 28, 12 }, { 1, 0 }, 8, 0 },
+      { { 33, 35 }, { 77, 128 }, { 113, 114 }, { 18, 6 }, { 1, 0 }, 2, 0 },
+      { { 241, 225 }, { 64, 0 }, { 241, 111 }, { 33, 22 }, { 1, 0 }, 2, 0 },
+      { { 2, 1 }, { 26, 128 }, { 245, 133 }, { 117, 53 }, { 1, 0 }, 0, 0 },
+      { { 2, 1 }, { 29, 128 }, { 245, 243 }, { 117, 244 }, { 1, 0 }, 0, 0 },
+      { { 16, 17 }, { 65, 0 }, { 245, 242 }, { 5, 195 }, { 1, 0 }, 2, 0 },
+      { { 33, 162 }, { 155, 1 }, { 177, 114 }, { 37, 8 }, { 1, 0 }, 14, 0 },
+      { { 161, 33 }, { 152, 0 }, { 127, 63 }, { 3, 7 }, { 1, 1 }, 0, 0 },
+      { { 161, 97 }, { 147, 0 }, { 193, 79 }, { 18, 5 }, { 0, 0 }, 10, 0 },
+      { { 33, 97 }, { 24, 0 }, { 193, 79 }, { 34, 5 }, { 0, 0 }, 12, 0 },
+      { { 49, 114 }, { 91, 131 }, { 244, 138 }, { 21, 5 }, { 0, 0 }, 0, 0 },
+      { { 161, 97 }, { 144, 0 }, { 116, 113 }, { 57, 103 }, { 0, 0 }, 0, 0 },
+      { { 113, 114 }, { 87, 0 }, { 84, 122 }, { 5, 5 }, { 0, 0 }, 12, 0 },
+      { { 144, 65 }, { 0, 0 }, { 84, 165 }, { 99, 69 }, { 0, 0 }, 8, 0 },
+      { { 33, 33 }, { 146, 1 }, { 133, 143 }, { 23, 9 }, { 0, 0 }, 12, 0 },
+      { { 33, 33 }, { 148, 5 }, { 117, 143 }, { 23, 9 }, { 0, 0 }, 12, 0 },
+      { { 33, 97 }, { 148, 0 }, { 118, 130 }, { 21, 55 }, { 0, 0 }, 12, 0 },
+      { { 49, 33 }, { 67, 0 }, { 158, 98 }, { 23, 44 }, { 1, 1 }, 2, 0 },
+      { { 33, 33 }, { 155, 0 }, { 97, 127 }, { 106, 10 }, { 0, 0 }, 2, 0 },
+      { { 97, 34 }, { 138, 6 }, { 117, 116 }, { 31, 15 }, { 0, 0 }, 8, 0 },
+      { { 161, 33 }, { 134, 13 }, { 114, 113 }, { 85, 24 }, { 1, 0 }, 0, 0 },
+      { { 33, 33 }, { 77, 0 }, { 84, 166 }, { 60, 28 }, { 0, 0 }, 8, 0 },
+      { { 49, 97 }, { 143, 0 }, { 147, 114 }, { 2, 11 }, { 1, 0 }, 8, 0 },
+      { { 49, 97 }, { 142, 0 }, { 147, 114 }, { 3, 9 }, { 1, 0 }, 8, 0 },
+      { { 49, 97 }, { 145, 0 }, { 147, 130 }, { 3, 9 }, { 1, 0 }, 10, 0 },
+      { { 49, 97 }, { 142, 0 }, { 147, 114 }, { 15, 15 }, { 1, 0 }, 10, 0 },
+      { { 33, 33 }, { 75, 0 }, { 170, 143 }, { 22, 10 }, { 1, 0 }, 8, 0 },
+      { { 49, 33 }, { 144, 0 }, { 126, 139 }, { 23, 12 }, { 1, 1 }, 6, 0 },
+      { { 49, 50 }, { 129, 0 }, { 117, 97 }, { 25, 25 }, { 1, 0 }, 0, 0 },
+      { { 50, 33 }, { 144, 0 }, { 155, 114 }, { 33, 23 }, { 0, 0 }, 4, 0 },
+      { { 225, 225 }, { 31, 0 }, { 133, 101 }, { 95, 26 }, { 0, 0 }, 0, 0 },
+      { { 225, 225 }, { 70, 0 }, { 136, 101 }, { 95, 26 }, { 0, 0 }, 0, 0 },
+      { { 161, 33 }, { 156, 0 }, { 117, 117 }, { 31, 10 }, { 0, 0 }, 2, 0 },
+      { { 49, 33 }, { 139, 0 }, { 132, 101 }, { 88, 26 }, { 0, 0 }, 0, 0 },
+      { { 225, 161 }, { 76, 0 }, { 102, 101 }, { 86, 38 }, { 0, 0 }, 0, 0 },
+      { { 98, 161 }, { 203, 0 }, { 118, 85 }, { 70, 54 }, { 0, 0 }, 0, 0 },
+      { { 98, 161 }, { 153, 0 }, { 87, 86 }, { 7, 7 }, { 0, 0 }, 11, 0 },
+      { { 98, 161 }, { 147, 0 }, { 119, 118 }, { 7, 7 }, { 0, 0 }, 11, 0 },
+      { { 34, 33 }, { 89, 0 }, { 255, 255 }, { 3, 15 }, { 2, 0 }, 0, 0 },
+      { { 33, 33 }, { 14, 0 }, { 255, 255 }, { 15, 15 }, { 1, 1 }, 0, 0 },
+      { { 34, 33 }, { 70, 128 }, { 134, 100 }, { 85, 24 }, { 0, 0 }, 0, 0 },
+      { { 33, 161 }, { 69, 0 }, { 102, 150 }, { 18, 10 }, { 0, 0 }, 0, 0 },
+      { { 33, 34 }, { 139, 0 }, { 146, 145 }, { 42, 42 }, { 1, 0 }, 0, 0 },
+      { { 162, 97 }, { 158, 64 }, { 223, 111 }, { 5, 7 }, { 0, 0 }, 2, 0 },
+      { { 32, 96 }, { 26, 0 }, { 239, 143 }, { 1, 6 }, { 0, 2 }, 0, 0 },
+      { { 33, 33 }, { 143, 128 }, { 241, 244 }, { 41, 9 }, { 0, 0 }, 10, 0 },
+      { { 119, 161 }, { 165, 0 }, { 83, 160 }, { 148, 5 }, { 0, 0 }, 2, 0 },
+      { { 97, 177 }, { 31, 128 }, { 168, 37 }, { 17, 3 }, { 0, 0 }, 10, 0 },
+      { { 97, 97 }, { 23, 0 }, { 145, 85 }, { 52, 22 }, { 0, 0 }, 12, 0 },
+      { { 113, 114 }, { 93, 0 }, { 84, 106 }, { 1, 3 }, { 0, 0 }, 0, 0 },
+      { { 33, 162 }, { 151, 0 }, { 33, 66 }, { 67, 53 }, { 0, 0 }, 8, 0 },
+      { { 161, 33 }, { 28, 0 }, { 161, 49 }, { 119, 71 }, { 1, 1 }, 0, 0 },
+      { { 33, 97 }, { 137, 3 }, { 17, 66 }, { 51, 37 }, { 0, 0 }, 10, 0 },
+      { { 161, 33 }, { 21, 0 }, { 17, 207 }, { 71, 7 }, { 1, 0 }, 0, 0 },
+      { { 58, 81 }, { 206, 0 }, { 248, 134 }, { 246, 2 }, { 0, 0 }, 2, 0 },
+      { { 33, 33 }, { 21, 0 }, { 33, 65 }, { 35, 19 }, { 1, 0 }, 0, 0 },
+      { { 6, 1 }, { 91, 0 }, { 116, 165 }, { 149, 114 }, { 0, 0 }, 0, 0 },
+      { { 34, 97 }, { 146, 131 }, { 177, 242 }, { 129, 38 }, { 0, 0 }, 12, 0 },
+      { { 65, 66 }, { 77, 0 }, { 241, 242 }, { 81, 245 }, { 1, 0 }, 0, 0 },
+      { { 97, 163 }, { 148, 128 }, { 17, 17 }, { 81, 19 }, { 1, 0 }, 6, 0 },
+      { { 97, 161 }, { 140, 128 }, { 17, 29 }, { 49, 3 }, { 0, 0 }, 6, 0 },
+      { { 164, 97 }, { 76, 0 }, { 243, 129 }, { 115, 35 }, { 1, 0 }, 4, 0 },
+      { { 2, 7 }, { 133, 3 }, { 210, 242 }, { 83, 246 }, { 0, 1 }, 0, 0 },
+      { { 17, 19 }, { 12, 128 }, { 163, 162 }, { 17, 229 }, { 1, 0 }, 0, 0 },
+      { { 17, 17 }, { 6, 0 }, { 246, 242 }, { 65, 230 }, { 1, 2 }, 4, 0 },
+      { { 147, 145 }, { 145, 0 }, { 212, 235 }, { 50, 17 }, { 0, 1 }, 8, 0 },
+      { { 4, 1 }, { 79, 0 }, { 250, 194 }, { 86, 5 }, { 0, 0 }, 12, 0 },
+      { { 33, 34 }, { 73, 0 }, { 124, 111 }, { 32, 12 }, { 0, 1 }, 6, 0 },
+      { { 49, 33 }, { 133, 0 }, { 221, 86 }, { 51, 22 }, { 1, 0 }, 10, 0 },
+      { { 32, 33 }, { 4, 129 }, { 218, 143 }, { 5, 11 }, { 2, 0 }, 6, 0 },
+      { { 5, 3 }, { 106, 128 }, { 241, 195 }, { 229, 229 }, { 0, 0 }, 6, 0 },
+      { { 7, 2 }, { 21, 0 }, { 236, 248 }, { 38, 22 }, { 0, 0 }, 10, 0 },
+      { { 5, 1 }, { 157, 0 }, { 103, 223 }, { 53, 5 }, { 0, 0 }, 8, 0 },
+      { { 24, 18 }, { 150, 0 }, { 250, 248 }, { 40, 229 }, { 0, 0 }, 10, 0 },
+      { { 16, 0 }, { 134, 3 }, { 168, 250 }, { 7, 3 }, { 0, 0 }, 6, 0 },
+      { { 17, 16 }, { 65, 3 }, { 248, 243 }, { 71, 3 }, { 2, 0 }, 4, 0 },
+      { { 1, 16 }, { 142, 0 }, { 241, 243 }, { 6, 2 }, { 2, 0 }, 14, 0 },
+      { { 14, 192 }, { 0, 0 }, { 31, 31 }, { 0, 255 }, { 0, 3 }, 14, 0 },
+      { { 6, 3 }, { 128, 136 }, { 248, 86 }, { 36, 132 }, { 0, 2 }, 14, 0 },
+      { { 14, 208 }, { 0, 5 }, { 248, 52 }, { 0, 4 }, { 0, 3 }, 14, 0 },
+      { { 14, 192 }, { 0, 0 }, { 246, 31 }, { 0, 2 }, { 0, 3 }, 14, 0 },
+      { { 213, 218 }, { 149, 64 }, { 55, 86 }, { 163, 55 }, { 0, 0 }, 0, 0 },
+      { { 53, 20 }, { 92, 8 }, { 178, 244 }, { 97, 21 }, { 2, 0 }, 10, 0 },
+      { { 14, 208 }, { 0, 0 }, { 246, 79 }, { 0, 245 }, { 0, 3 }, 14, 0 },
+      { { 38, 228 }, { 0, 0 }, { 255, 18 }, { 1, 22 }, { 0, 1 }, 14, 0 },
+      { { 0, 0 }, { 0, 0 }, { 243, 246 }, { 240, 201 }, { 0, 2 }, 14, 0 },
+      { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 },
+      { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 },
+      { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 },
+      { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 },
+      { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 },
+      { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 },
+      { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 },
+      { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 },
+      { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 },
+      { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 },
+      { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 },
+      { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 },
+      { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 },
+      { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 },
+      { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 },
+      { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 },
+      { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 },
+      { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 },
+      { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 },
+      { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 },
+      { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 },
+      { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 },
+      { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 },
+      { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 },
+      { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 },
+      { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 },
+      { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 },
+      { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 },
+      { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 },
+      { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 },
+      { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 },
+      { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 },
+      { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 },
+      { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 },
+      { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 },
+      { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 },
+      { { 0, 0 }, { 0, 0 }, { 252, 250 }, { 5, 23 }, { 2, 0 }, 14, 52 },
+      { { 0, 1 }, { 2, 0 }, { 255, 255 }, { 7, 8 }, { 0, 0 }, 0, 48 },
+      { { 0, 0 }, { 0, 0 }, { 252, 250 }, { 5, 23 }, { 2, 0 }, 14, 58 },
+      { { 0, 0 }, { 0, 0 }, { 246, 246 }, { 12, 6 }, { 0, 0 }, 4, 60 },
+      { { 12, 18 }, { 0, 0 }, { 246, 251 }, { 8, 71 }, { 0, 2 }, 10, 47 },
+      { { 0, 0 }, { 3, 0 }, { 248, 246 }, { 42, 69 }, { 0, 1 }, 4, 43 },
+      { { 12, 18 }, { 0, 0 }, { 246, 251 }, { 8, 71 }, { 0, 2 }, 10, 49 },
+      { { 0, 0 }, { 3, 0 }, { 248, 246 }, { 42, 69 }, { 0, 1 }, 4, 43 },
+      { { 12, 18 }, { 0, 0 }, { 246, 251 }, { 8, 71 }, { 0, 2 }, 10, 51 },
+      { { 0, 0 }, { 3, 0 }, { 248, 246 }, { 42, 69 }, { 0, 1 }, 4, 43 },
+      { { 12, 18 }, { 0, 0 }, { 246, 251 }, { 8, 71 }, { 0, 2 }, 10, 54 },
+      { { 12, 18 }, { 0, 0 }, { 246, 251 }, { 8, 71 }, { 0, 2 }, 10, 57 },
+      { { 0, 0 }, { 3, 0 }, { 248, 246 }, { 42, 69 }, { 0, 1 }, 4, 72 },
+      { { 12, 18 }, { 0, 0 }, { 246, 251 }, { 8, 71 }, { 0, 2 }, 10, 60 },
+      { { 14, 208 }, { 0, 10 }, { 245, 159 }, { 48, 2 }, { 0, 0 }, 14, 76 },
+      { { 14, 7 }, { 10, 93 }, { 228, 245 }, { 228, 229 }, { 3, 1 }, 6, 84 },
+      { { 2, 5 }, { 3, 10 }, { 180, 151 }, { 4, 247 }, { 0, 0 }, 14, 36 },
+      { { 78, 158 }, { 0, 0 }, { 246, 159 }, { 0, 2 }, { 0, 3 }, 14, 76 },
+      { { 17, 16 }, { 69, 8 }, { 248, 243 }, { 55, 5 }, { 2, 0 }, 8, 84 },
+      { { 14, 208 }, { 0, 0 }, { 246, 159 }, { 0, 2 }, { 0, 3 }, 14, 83 },
+      { { 128, 16 }, { 0, 13 }, { 255, 255 }, { 3, 20 }, { 3, 0 }, 12, 84 },
+      { { 14, 7 }, { 8, 81 }, { 248, 244 }, { 66, 228 }, { 0, 3 }, 14, 24 },
+      { { 14, 208 }, { 0, 10 }, { 245, 159 }, { 48, 2 }, { 0, 0 }, 14, 77 },
+      { { 1, 2 }, { 0, 0 }, { 250, 200 }, { 191, 151 }, { 0, 0 }, 7, 60 },
+      { { 1, 1 }, { 81, 0 }, { 250, 250 }, { 135, 183 }, { 0, 0 }, 6, 65 },
+      { { 1, 2 }, { 84, 0 }, { 250, 248 }, { 141, 184 }, { 0, 0 }, 6, 59 },
+      { { 1, 2 }, { 89, 0 }, { 250, 248 }, { 136, 182 }, { 0, 0 }, 6, 51 },
+      { { 1, 0 }, { 0, 0 }, { 249, 250 }, { 10, 6 }, { 3, 0 }, 14, 45 },
+      { { 0, 0 }, { 128, 0 }, { 249, 246 }, { 137, 108 }, { 3, 0 }, 14, 71 },
+      { { 3, 12 }, { 128, 8 }, { 248, 246 }, { 136, 182 }, { 3, 0 }, 15, 60 },
+      { { 3, 12 }, { 133, 0 }, { 248, 246 }, { 136, 182 }, { 3, 0 }, 15, 58 },
+      { { 14, 0 }, { 64, 8 }, { 118, 119 }, { 79, 24 }, { 0, 2 }, 14, 53 },
+      { { 14, 3 }, { 64, 0 }, { 200, 155 }, { 73, 105 }, { 0, 2 }, 14, 64 },
+      { { 215, 199 }, { 220, 0 }, { 173, 141 }, { 5, 5 }, { 3, 0 }, 14, 71 },
+      { { 215, 199 }, { 220, 0 }, { 168, 136 }, { 4, 4 }, { 3, 0 }, 14, 61 },
+      { { 128, 17 }, { 0, 0 }, { 246, 103 }, { 6, 23 }, { 3, 3 }, 14, 61 },
+      { { 128, 17 }, { 0, 9 }, { 245, 70 }, { 5, 22 }, { 2, 3 }, 14, 48 },
+      { { 6, 21 }, { 63, 0 }, { 0, 247 }, { 244, 245 }, { 0, 0 }, 1, 48 },
+      { { 6, 18 }, { 63, 0 }, { 0, 247 }, { 244, 245 }, { 3, 0 }, 0, 69 },
+      { { 6, 18 }, { 63, 0 }, { 0, 247 }, { 244, 245 }, { 0, 0 }, 1, 68 },
+      { { 1, 2 }, { 88, 0 }, { 103, 117 }, { 231, 7 }, { 0, 0 }, 0, 63 },
+      { { 65, 66 }, { 69, 8 }, { 248, 117 }, { 72, 5 }, { 0, 0 }, 0, 74 },
+      { { 10, 30 }, { 64, 78 }, { 224, 255 }, { 240, 5 }, { 3, 0 }, 8, 60 },
+      { { 10, 30 }, { 124, 82 }, { 224, 255 }, { 240, 2 }, { 3, 0 }, 8, 80 },
+      { { 14, 0 }, { 64, 8 }, { 122, 123 }, { 74, 27 }, { 0, 2 }, 14, 64 },
+      { { 14, 7 }, { 10, 64 }, { 228, 85 }, { 228, 57 }, { 3, 1 }, 6, 69 },
+      { { 5, 4 }, { 5, 64 }, { 249, 214 }, { 50, 165 }, { 3, 0 }, 14, 73 },
+      { { 2, 21 }, { 63, 0 }, { 0, 247 }, { 243, 245 }, { 3, 0 }, 8, 75 },
+      { { 1, 2 }, { 79, 0 }, { 250, 248 }, { 141, 181 }, { 0, 0 }, 7, 68 },
+      { { 0, 0 }, { 0, 0 }, { 246, 246 }, { 12, 6 }, { 0, 0 }, 4, 48 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 53 },
+      { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 },
+      { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 },
+      { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 },
+      { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 },
+      { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 },
+      { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 },
+      { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 },
+      { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 },
+      { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 },
+      { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 },
+      { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 },
+      { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 },
+      { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 },
+      { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 },
+      { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 },
+      { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 },
+      { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 },
+      { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 },
+      { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 },
+      { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 },
+      { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 },
+      { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 },
+      { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 },
+      { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 },
+      { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 },
+      { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 },
+      { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 },
+      { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 },
+      { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 },
+      { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 },
+      { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 },
+      { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 },
+      { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 },
+      { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 },
+      { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 },
+      { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 },
+      { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 },
+      { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 },
+      { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 },
+      { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 },
+      { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }
+   };
--- /dev/null
+++ b/rott/audiolib/gus.c
@@ -1,0 +1,283 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+/**********************************************************************
+   file:   GUS.C
+
+   author: James R. Dose
+   date:   September 7, 1994
+
+   Gravis Ultrasound initialization routines.
+
+   (c) Copyright 1994 James R. Dose.  All Rights Reserved.
+**********************************************************************/
+
+#include <conio.h>
+#include <dos.h>
+#include <stdio.h>
+#include <io.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdlib.h>
+#include "usrhooks.h"
+#include "interrup.h"
+#include "newgf1.h"
+#include "gusmidi.h"
+#include "guswave.h"
+#include "_guswave.h"
+
+#define TRUE  ( 1 == 1 )
+#define FALSE ( !TRUE )
+
+// size of DMA buffer for patch loading
+#define DMABUFFSIZE 2048U
+
+struct gf1_dma_buff GUS_HoldBuffer;
+static int          HoldBufferAllocated = FALSE;
+
+static int GUS_Installed = 0;
+
+extern VoiceNode   GUSWAVE_Voices[ VOICES ];
+extern int GUSWAVE_Installed;
+
+unsigned long GUS_TotalMemory;
+int           GUS_MemConfig;
+
+int GUS_AuxError  = 0;
+
+int GUS_ErrorCode = GUS_Ok;
+
+#define GUS_SetErrorCode( status ) \
+   GUS_ErrorCode   = ( status );
+
+
+/*---------------------------------------------------------------------
+   Function: GUS_ErrorString
+
+   Returns a pointer to the error message associated with an error
+   number.  A -1 returns a pointer the current error.
+---------------------------------------------------------------------*/
+
+char *GUS_ErrorString
+   (
+   int ErrorNumber
+   )
+
+   {
+   char *ErrorString;
+
+   switch( ErrorNumber )
+      {
+      case GUS_Warning :
+      case GUS_Error :
+         ErrorString = GUS_ErrorString( GUS_ErrorCode );
+         break;
+
+      case GUS_Ok :
+         ErrorString = "Ultrasound music ok.";
+         break;
+
+      case GUS_OutOfMemory :
+         ErrorString = "Out of memory in GusMidi.";
+         break;
+
+      case GUS_OutOfDosMemory :
+         ErrorString = "Out of conventional (640K) memory in GusMidi.";
+         break;
+
+      case GUS_GF1Error :
+         ErrorString = gf1_error_str( GUS_AuxError );
+         break;
+
+      case GUS_InvalidIrq :
+         ErrorString = "Ultrasound IRQ must be 7 or less.";
+         break;
+
+      case GUS_ULTRADIRNotSet :
+         ErrorString = "ULTRADIR environment variable not set.";
+         break;
+
+      case GUS_MissingConfig :
+//         ErrorString = "Can't find GUSMIDI.INI file.";
+         ErrorString = "Can't find ULTRAMID.INI file.";
+         break;
+
+      case GUS_FileError :
+         ErrorString = strerror( GUS_AuxError );
+         break;
+
+      default :
+         ErrorString = "Unknown Ultrasound error code.";
+         break;
+      }
+
+   return( ErrorString );
+   }
+
+
+
+/*---------------------------------------------------------------------
+   Function: D32DosMemAlloc
+
+   Allocate a block of Conventional memory.
+---------------------------------------------------------------------*/
+
+void *D32DosMemAlloc
+   (
+   unsigned size
+   )
+
+   {
+   union REGS r;
+
+   // DPMI allocate DOS memory
+   r.x.eax = 0x0100;
+
+   // Number of paragraphs requested
+   r.x.ebx = ( size + 15 ) >> 4;
+   int386( 0x31, &r, &r );
+   if ( r.x.cflag )
+      {
+      // Failed
+      return( NULL );
+      }
+
+   return( ( void * )( ( r.x.eax & 0xFFFF ) << 4 ) );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: GUS_Init
+
+   Initializes the Gravis Ultrasound for sound and music playback.
+---------------------------------------------------------------------*/
+
+int GUS_Init
+   (
+   void
+   )
+
+   {
+   struct load_os os;
+   int ret;
+
+   if ( GUS_Installed > 0 )
+      {
+      GUS_Installed++;
+      return( GUS_Ok );
+      }
+
+   GUS_SetErrorCode( GUS_Ok );
+
+   GUS_Installed = 0;
+
+   GetUltraCfg( &os );
+
+   if ( os.forced_gf1_irq > 7 )
+      {
+      GUS_SetErrorCode( GUS_InvalidIrq );
+      return( GUS_Error );
+      }
+
+   if ( !HoldBufferAllocated )
+      {
+      GUS_HoldBuffer.vptr = D32DosMemAlloc( DMABUFFSIZE );
+      if ( GUS_HoldBuffer.vptr == NULL )
+         {
+         GUS_SetErrorCode( GUS_OutOfDosMemory );
+         return( GUS_Error );
+         }
+      GUS_HoldBuffer.paddr = ( unsigned long )GUS_HoldBuffer.vptr;
+
+      HoldBufferAllocated = TRUE;
+      }
+
+   os.voices = 24;
+   ret = gf1_load_os( &os );
+   if ( ret )
+      {
+      GUS_AuxError = ret;
+      GUS_SetErrorCode( GUS_GF1Error );
+      return( GUS_Error );
+      }
+
+   GUS_TotalMemory = gf1_mem_avail();
+   GUS_MemConfig   = ( GUS_TotalMemory - 1 ) >> 18;
+
+   GUS_Installed = 1;
+   return( GUS_Ok );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: GUS_Shutdown
+
+   Ends use of the Gravis Ultrasound.  Must be called the same number
+   of times as GUS_Init.
+---------------------------------------------------------------------*/
+
+void GUS_Shutdown
+   (
+   void
+   )
+
+   {
+   if ( GUS_Installed > 0 )
+      {
+      GUS_Installed--;
+      if ( GUS_Installed == 0 )
+         {
+         gf1_unload_os();
+         }
+      }
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: GUSWAVE_Shutdown
+
+   Terminates use of the Gravis Ultrasound for digitized sound playback.
+---------------------------------------------------------------------*/
+
+void GUSWAVE_Shutdown
+   (
+   void
+   )
+
+   {
+   int i;
+
+   if ( GUSWAVE_Installed )
+      {
+      GUSWAVE_KillAllVoices();
+
+      // free memory
+      for ( i = 0; i < VOICES; i++ )
+         {
+         if ( GUSWAVE_Voices[ i ].mem != NULL )
+            {
+            gf1_free( GUSWAVE_Voices[ i ].mem );
+            GUSWAVE_Voices[ i ].mem = NULL;
+            }
+         }
+
+      GUS_Shutdown();
+      GUSWAVE_Installed = FALSE;
+      }
+   }
--- /dev/null
+++ b/rott/audiolib/gusmidi.c
@@ -1,0 +1,561 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+/**********************************************************************
+   file:   GUSMIDI.C
+
+   author: James R. Dose
+   date:   March 23, 1994
+
+   General MIDI playback functions for the Gravis Ultrasound
+
+   (c) Copyright 1994 James R. Dose.  All Rights Reserved.
+**********************************************************************/
+
+// Module MUST be compiled with structure allignment set to a maximum
+// of 1 byte ( zp1 ).
+
+#include <conio.h>
+#include <dos.h>
+#include <stdio.h>
+#include <io.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdlib.h>
+#include "usrhooks.h"
+#include "interrup.h"
+#include "newgf1.h"
+#include "gusmidi.h"
+
+#define TRUE  ( 1 == 1 )
+#define FALSE ( !TRUE )
+
+// size of DMA buffer for patch loading
+#define DMABUFFSIZE 2048U
+
+#define MAX_MEM_CONFIG   3
+
+// size of patch array (128 perc, 128 melodic)
+#define NUM_PATCHES 256
+
+// size of largest patch name
+#define BIGGEST_NAME 9
+
+#define UNUSED_PATCH -1
+
+static struct patch   Patch[ NUM_PATCHES ];
+static unsigned char *PatchWaves[ NUM_PATCHES ];
+
+static int   PatchMap[ NUM_PATCHES ][ MAX_MEM_CONFIG + 1 ];
+static char  ProgramName[ NUM_PATCHES ][ BIGGEST_NAME ];
+static char  PatchLoaded[ NUM_PATCHES ];
+
+static char  ConfigFileName[] = "ULTRAMID.INI";
+static char  ConfigDirectory[ 80 ] = { '\0' };
+
+// The name of the configuration directory
+static char  InstrumentDirectory[ 80 ];
+
+extern struct gf1_dma_buff GUS_HoldBuffer;
+
+extern unsigned long GUS_TotalMemory;
+extern int           GUS_MemConfig;
+
+static int GUSMIDI_Volume = 255;
+
+extern int GUS_AuxError;
+extern int GUS_ErrorCode;
+
+int GUSMIDI_Installed = FALSE;
+
+#define GUS_SetErrorCode( status ) \
+   GUS_ErrorCode   = ( status );
+
+
+/*---------------------------------------------------------------------
+   Function: GUS_GetPatchMap
+
+   Reads the patch map from disk.
+---------------------------------------------------------------------*/
+
+int GUS_GetPatchMap
+   (
+   char *name
+   )
+
+   {
+   char text[ 80 ];
+   char *ud;
+   int  index;
+   int  ignore;
+   FILE *fp;
+
+   for( index = 0; index < NUM_PATCHES; index++ )
+      {
+      PatchMap[ index ][ 0 ] = UNUSED_PATCH;
+      PatchMap[ index ][ 1 ] = UNUSED_PATCH;
+      PatchMap[ index ][ 2 ] = UNUSED_PATCH;
+      PatchMap[ index ][ 3 ] = UNUSED_PATCH;
+      ProgramName[ index ][ 0 ] = 0;
+      }
+
+   ud = getenv( "ULTRADIR" );
+   if ( ud == NULL )
+      {
+      GUS_SetErrorCode( GUS_ULTRADIRNotSet );
+      return( GUS_Error );
+      }
+
+   strcpy( InstrumentDirectory, ud );
+   strcat( InstrumentDirectory, "\\midi\\" );
+   strcpy( ConfigDirectory, ud );
+   strcat( ConfigDirectory, "\\midi\\" );
+   strcpy( text, name );
+
+   fp = fopen( text, "r" );
+   if ( fp == NULL )
+      {
+      strcpy( text, InstrumentDirectory );
+      strcat( text, name );
+
+      fp = fopen( text, "r" );
+      if ( fp == NULL )
+         {
+         GUS_SetErrorCode( GUS_MissingConfig );
+         return( GUS_Error );
+         }
+      }
+
+   while( 1 )
+      {
+      if ( fgets( text, 80, fp ) == NULL )
+         {
+         break;
+         }
+
+      if ( text[ 0 ] == '#' )
+         {
+         continue;
+         }
+
+      if ( sscanf( text, "%d", &index ) != 1 )
+         {
+         continue;
+         }
+
+      sscanf( text, "%d, %d, %d, %d, %d, %s\n", &ignore,
+         &PatchMap[ index ][ 0 ],
+         &PatchMap[ index ][ 1 ],
+         &PatchMap[ index ][ 2 ],
+         &PatchMap[ index ][ 3 ],
+         ProgramName[ index ] );
+      }
+
+   fclose( fp );
+
+   return( GUS_Ok );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: GUSMIDI_UnloadPatch
+
+   Unloads a patch from the GUS's memory.
+---------------------------------------------------------------------*/
+
+int GUSMIDI_UnloadPatch
+   (
+   int prognum
+   )
+
+   {
+   int      prog;
+   unsigned flags;
+
+   prog = PatchMap[ prognum ][ GUS_MemConfig ];
+
+   if ( PatchLoaded[ prog ] )
+      {
+      flags = DisableInterrupts();
+
+      gf1_unload_patch( &Patch[ prog ] );
+      if ( PatchWaves[ prog ] != NULL )
+         {
+         USRHOOKS_FreeMem( PatchWaves[ prog ] );
+         PatchWaves[ prog ] = NULL;
+         }
+
+      // just in case sequence is still playing
+      Patch[ prog ].nlayers = 0;
+      PatchLoaded[ prog ]   = FALSE;
+
+      RestoreInterrupts( flags );
+      }
+
+   return( GUS_Ok );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: GUSMIDI_LoadPatch
+
+   Loads a patch into the GUS's memory.
+---------------------------------------------------------------------*/
+
+int GUSMIDI_LoadPatch
+   (
+   int prognum
+   )
+
+   {
+   int  prog;
+   char text[ 80 ];
+   int  ret;
+   unsigned char *wave_buff;
+   struct patchinfo  patchi;
+   int  status;
+
+   prog = PatchMap[ prognum ][ GUS_MemConfig ];
+
+   if ( ( PatchLoaded[ prog ] ) || ( prog == UNUSED_PATCH ) )
+      {
+      return( GUS_Ok );
+      }
+
+   if ( !ProgramName[ prog ][ 0 ] )
+      {
+      return( GUS_Ok );
+      }
+
+   strcpy( text, InstrumentDirectory );
+   strcat( text, ProgramName[ prog ] );
+   strcat( text, ".pat" );
+
+   ret = gf1_get_patch_info( text, &patchi );
+   if ( ret != OK )
+      {
+      GUS_AuxError = ret;
+      GUS_SetErrorCode( GUS_GF1Error );
+      return( GUS_Error );
+      }
+
+   status = USRHOOKS_GetMem( &wave_buff, patchi.header.wave_forms *
+      sizeof( struct wave_struct ) );
+   if ( status != USRHOOKS_Ok )
+      {
+      GUS_SetErrorCode( GUS_OutOfMemory );
+      return( GUS_Error );
+      }
+
+   ret = gf1_load_patch( text, &patchi, &Patch[ prog ], &GUS_HoldBuffer,
+      DMABUFFSIZE, ( unsigned char * )wave_buff, PATCH_LOAD_8_BIT );
+
+   if ( ret != OK )
+      {
+      USRHOOKS_FreeMem( wave_buff );
+      GUS_AuxError = ret;
+      GUS_SetErrorCode( GUS_GF1Error );
+      return( GUS_Error );
+      }
+
+   PatchWaves[ prog ] = wave_buff;
+   PatchLoaded[ prog ] = TRUE;
+
+   return( GUS_Ok );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: GUSMIDI_ProgramChange
+
+   Selects the instrument to use on the specified MIDI channel.
+---------------------------------------------------------------------*/
+
+void GUSMIDI_ProgramChange
+   (
+   int channel,
+   int prognum
+   )
+
+   {
+   int  prog;
+
+   prog = PatchMap[ prognum ][ GUS_MemConfig ];
+
+   if ( PatchLoaded[ prog ] )
+      {
+      gf1_midi_change_program( &Patch[ prog ], channel );
+      }
+   else
+      {
+      gf1_midi_change_program( NULL, channel );
+      }
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: GUSMIDI_NoteOn
+
+   Plays a note on the specified channel.
+---------------------------------------------------------------------*/
+
+void GUSMIDI_NoteOn
+   (
+   int chan,
+   int note,
+   int velocity
+   )
+
+   {
+   int prog;
+
+   if ( chan == 9 )
+      {
+      prog = PatchMap[ note + 128 ][ GUS_MemConfig ];
+
+      if ( PatchLoaded[ prog ] )
+         {
+         gf1_midi_note_on( &Patch[ note + 128 ], 1,
+            note, velocity, 9 );
+         }
+      }
+   else
+      {
+      gf1_midi_note_on( 0L, 1, note, velocity, chan );
+      }
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: GUSMIDI_NoteOff
+
+   Turns off a note on the specified channel.
+---------------------------------------------------------------------*/
+#pragma warn -par
+void GUSMIDI_NoteOff
+   (
+   int chan,
+   int note,
+   int velocity
+   )
+
+   {
+   gf1_midi_note_off( note, chan );
+   }
+#pragma warn .par
+
+
+/*---------------------------------------------------------------------
+   Function: GUSMIDI_ControlChange
+
+   Sets the value of a controller on the specified channel.
+---------------------------------------------------------------------*/
+
+void GUSMIDI_ControlChange
+   (
+   int channel,
+   int number,
+   int value
+   )
+
+   {
+   gf1_midi_parameter( channel, number, value );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: GUSMIDI_PitchBend
+
+   Sets the pitch bend on the specified MIDI channel.
+---------------------------------------------------------------------*/
+
+void GUSMIDI_PitchBend
+   (
+   int channel,
+   int lsb,
+   int msb
+   )
+
+   {
+   gf1_midi_pitch_bend( channel, lsb, msb );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: GUSMIDI_ReleasePatches
+
+   Removes all the instruments from the GUS's memory.
+---------------------------------------------------------------------*/
+
+void GUSMIDI_ReleasePatches
+   (
+   void
+   )
+
+   {
+   int i;
+
+   for( i = 0; i < 256; i++ )
+      {
+      GUSMIDI_UnloadPatch( i );
+      }
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: GUSMIDI_SetVolume
+
+   Sets the total music volume.
+---------------------------------------------------------------------*/
+
+void GUSMIDI_SetVolume
+   (
+   int volume
+   )
+
+   {
+   // Set the minimum to 2 because 0 has a tremolo problem
+   volume = max( 2, volume );
+   volume = min( volume, 255 );
+
+   GUSMIDI_Volume = volume;
+
+   // range = 0 to 127
+   gf1_midi_synth_volume( 0, volume >> 1 );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: GUSMIDI_GetVolume
+
+   Returns the total music volume.
+---------------------------------------------------------------------*/
+
+int GUSMIDI_GetVolume
+   (
+   void
+   )
+
+   {
+   return( GUSMIDI_Volume );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: GUSMIDI_Init
+
+   Initializes the Gravis Ultrasound for music playback.
+---------------------------------------------------------------------*/
+
+int GUSMIDI_Init
+   (
+   void
+   )
+
+   {
+   int ret;
+   int i;
+   int startmem;
+//   unsigned long mem;
+   extern int GUSWAVE_Installed;
+
+   if ( GUSMIDI_Installed )
+      {
+      GUSMIDI_Shutdown();
+      }
+
+   ret = GUS_Init();
+   if ( ret != GUS_Ok )
+      {
+      return( ret );
+      }
+
+   if ( GUS_MemConfig < 0 )
+      {
+      GUS_MemConfig = 0;
+      }
+
+   if ( GUS_MemConfig > MAX_MEM_CONFIG )
+      {
+      GUS_MemConfig = MAX_MEM_CONFIG;
+      }
+
+   for( i = 0; i < NUM_PATCHES; i++ )
+      {
+      ProgramName[ i ][ 0 ] = '\0';
+      PatchWaves[ i ]       = NULL;
+      PatchLoaded[ i ]      = FALSE;
+      }
+
+   GUSMIDI_SetVolume( 255 );
+
+   GUSMIDI_Installed = TRUE;
+
+   ret = GUS_GetPatchMap( ConfigFileName );
+   if ( ret != GUS_Ok )
+      {
+      GUSMIDI_Shutdown();
+      return( ret );
+      }
+
+//   if ( !GUSWAVE_Installed )
+//      {
+//      mem = gf1_malloc( 8192 );
+//      }
+
+   startmem = gf1_mem_avail();
+   for( i = 0; i < NUM_PATCHES; i++ )
+      {
+      ret = GUSMIDI_LoadPatch( i );
+      if ( ret != GUS_Ok )
+         {
+         }
+//      if ( ret != GUS_Ok )
+//         {
+//         return( ret );
+//         }
+      }
+
+//   if ( !GUSWAVE_Installed )
+//      {
+//      gf1_free( mem );
+//      }
+
+   GUSMIDI_Installed = TRUE;
+
+   return( GUS_Ok );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: GUSMIDI_Shutdown
+
+   Ends use of the Gravis Ultrasound for music playback.
+---------------------------------------------------------------------*/
+
+void GUSMIDI_Shutdown
+   (
+   void
+   )
+
+   {
+   GUSMIDI_ReleasePatches();
+   GUS_Shutdown();
+   GUSMIDI_Installed = FALSE;
+   }
--- /dev/null
+++ b/rott/audiolib/gusmidi.h
@@ -1,0 +1,59 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+#ifndef __GUSMIDI_H
+#define __GUSMIDI_H
+
+extern struct gf1_dma_buff GUS_HoldBuffer;
+
+enum GUS_Errors
+   {
+   GUS_Warning        = -2,
+   GUS_Error          = -1,
+   GUS_Ok             = 0,
+   GUS_OutOfMemory,
+   GUS_OutOfDosMemory,
+   GUS_OutOfDRAM,
+   GUS_GF1Error,
+   GUS_InvalidIrq,
+   GUS_ULTRADIRNotSet,
+   GUS_MissingConfig,
+   GUS_FileError
+   };
+
+char *GUS_ErrorString( int ErrorNumber );
+int   GUS_GetPatchMap( char *name );
+int   GUSMIDI_UnloadPatch( int prog );
+int   GUSMIDI_LoadPatch( int prog );
+void  GUSMIDI_ProgramChange( int channel, int prog );
+void  GUSMIDI_NoteOn( int chan, int note, int velocity );
+void  GUSMIDI_NoteOff( int chan, int note, int velocity );
+void  GUSMIDI_ControlChange( int channel, int number, int value );
+void  GUSMIDI_PitchBend( int channel, int lsb, int msb );
+void  GUSMIDI_ReleasePatches( void );
+void  GUSMIDI_SetVolume( int volume );
+int   GUSMIDI_GetVolume( void );
+int   GUS_Init( void );
+void  GUS_Shutdown( void );
+#pragma aux GUS_Shutdown frame;
+int   GUSMIDI_Init( void );
+void  GUSMIDI_Shutdown( void );
+void *D32DosMemAlloc( unsigned size );
+
+#endif
--- /dev/null
+++ b/rott/audiolib/guswave.c
@@ -1,0 +1,1773 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+/**********************************************************************
+   file:   GUSWAVE.C
+
+   author: James R. Dose
+   date:   March 23, 1994
+
+   Digitized sound playback routines for the Gravis Ultrasound.
+
+   (c) Copyright 1994 James R. Dose.  All Rights Reserved.
+**********************************************************************/
+
+#include <stdlib.h>
+#include <conio.h>
+#include <dos.h>
+#include <stdio.h>
+#include <io.h>
+#include <string.h>
+#include "debugio.h"
+#include "interrup.h"
+#include "ll_man.h"
+#include "pitch.h"
+#include "user.h"
+#include "multivoc.h"
+#include "_guswave.h"
+#include "newgf1.h"
+#include "gusmidi.h"
+#include "guswave.h"
+
+#define ATR_INDEX               0x3c0
+#define STATUS_REGISTER_1       0x3da
+
+#define SetBorderColor(color) \
+   { \
+   inp  (STATUS_REGISTER_1); \
+   outp (ATR_INDEX,0x31);    \
+   outp (ATR_INDEX,color);   \
+   }
+
+static const int GUSWAVE_PanTable[ 32 ] =
+   {
+      8,  9, 10, 11, 11, 12, 13, 14,
+     15, 14, 13, 12, 11, 10,  9,  8,
+      7,  6,  5,  4,  4,  3,  2,  1,
+      0,  1,  2,  3,  4,  5,  6,  7
+   };
+
+static voicelist VoiceList;
+static voicelist VoicePool;
+
+static voicestatus VoiceStatus[ MAX_VOICES ];
+//static
+VoiceNode GUSWAVE_Voices[ VOICES ];
+
+static int GUSWAVE_VoiceHandle  = GUSWAVE_MinVoiceHandle;
+static int GUSWAVE_MaxVoices = VOICES;
+//static
+int GUSWAVE_Installed = FALSE;
+
+static void ( *GUSWAVE_CallBackFunc )( unsigned long ) = NULL;
+
+// current volume for dig audio - from 0 to 4095
+static int GUSWAVE_Volume = MAX_VOLUME;
+
+static int GUSWAVE_SwapLeftRight = FALSE;
+
+static int GUS_Debug = FALSE;
+
+extern int GUSMIDI_Installed;
+
+int GUSWAVE_ErrorCode = GUSWAVE_Ok;
+
+#define GUSWAVE_SetErrorCode( status ) \
+   GUSWAVE_ErrorCode   = ( status );
+
+
+/*---------------------------------------------------------------------
+   Function: GUSWAVE_ErrorString
+
+   Returns a pointer to the error message associated with an error
+   number.  A -1 returns a pointer the current error.
+---------------------------------------------------------------------*/
+
+char *GUSWAVE_ErrorString
+   (
+   int ErrorNumber
+   )
+
+   {
+   char *ErrorString;
+
+   switch( ErrorNumber )
+      {
+      case GUSWAVE_Warning :
+      case GUSWAVE_Error :
+         ErrorString = GUSWAVE_ErrorString( GUSWAVE_ErrorCode );
+         break;
+
+      case GUSWAVE_Ok :
+         ErrorString = "GUSWAVE ok.";
+         break;
+
+      case GUSWAVE_GUSError :
+         ErrorString = GUS_ErrorString( GUS_Error );
+         break;
+
+      case GUSWAVE_NotInstalled :
+         ErrorString = "GUSWAVE not installed.";
+         break;
+
+      case GUSWAVE_NoVoices :
+         ErrorString = "No free voices available to GUSWAVE.";
+         break;
+
+      case GUSWAVE_UltraNoMem :
+         ErrorString = "Not enough Ultrasound memory available for GUSWAVE.";
+         break;
+
+      case GUSWAVE_UltraNoMemMIDI :
+         ErrorString = "Not enough Ultrasound memory available for GUSWAVE.  "
+            "Try initializing Sound FX before Music.";
+         break;
+
+      case GUSWAVE_VoiceNotFound :
+         ErrorString = "No voice with matching handle found.";
+         break;
+
+      case GUSWAVE_InvalidVOCFile :
+         ErrorString = "Invalid VOC file passed in to GUSWAVE.";
+         break;
+
+      case GUSWAVE_InvalidWAVFile :
+         ErrorString = "Invalid WAV file passed in to GUSWAVE.";
+         break;
+
+      default :
+         ErrorString = "Unknown GUSWAVE error code.";
+         break;
+      }
+
+   return( ErrorString );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: GUSWAVE_CallBack
+
+   GF1 callback service routine.
+---------------------------------------------------------------------*/
+
+char GUS_Silence8[ 1024 ] = //256 ] =
+   {
+   0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+   0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+   0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+   0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+   0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+   0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+   0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+   0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+   0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+   0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+   0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+   0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+   0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+   0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+   0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+   0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+
+   0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+   0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+   0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+   0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+   0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+   0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+   0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+   0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+   0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+   0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+   0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+   0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+   0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+   0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+   0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+   0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+   0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+   0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+   0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+   0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+   0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+   0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+   0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+   0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+   0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+   0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+   0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+   0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+   0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+   0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+   0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+   0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+   0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+   0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+   0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+   0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+   0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+   0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+   0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+   0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+   0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+   0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+   0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+   0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+   0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+   0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+   0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+   0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80
+
+
+   };
+
+//unsigned short GUS_Silence16[ 128 ] =
+unsigned short GUS_Silence16[ 512 ] =
+   {
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+
+
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+   };
+
+static int LOADDS GUSWAVE_CallBack
+   (
+   int reason,
+   int voice,
+   unsigned char **buf,
+   unsigned long *size
+   )
+
+   {
+   VoiceNode *Voice;
+   playbackstatus status;
+
+   // this function is called from an interrupt
+   // remember not to make any DOS or BIOS calls from here
+   // also don't call any C library functions unless you are sure that
+   // they are reentrant
+   // restore our DS register
+
+   if ( VoiceStatus[ voice ].playing == FALSE )
+      {
+      return( DIG_DONE );
+      }
+
+   if ( reason == DIG_MORE_DATA )
+      {
+//      SetBorderColor(16);
+      Voice = VoiceStatus[ voice ].Voice;
+
+      if ( ( Voice != NULL ) && ( Voice->Playing ) )
+/*
+         {
+         *buf = ( unsigned char * )GUS_Silence16;
+         *size = 1024;
+
+         SetBorderColor(0);
+         return( DIG_MORE_DATA );
+         }
+ */
+         {
+         status = Voice->GetSound( Voice );
+         if ( status != SoundDone )
+            {
+            if ( ( Voice->sound == NULL ) || ( status == NoMoreData ) )
+               {
+               if ( Voice->bits == 8 )
+                  {
+                  *buf = GUS_Silence8;
+                  }
+               else
+                  {
+                  *buf = ( unsigned char * )GUS_Silence16;
+                  }
+               *size = 256;
+               }
+            else
+               {
+               *buf  = Voice->sound;
+               *size = Voice->length;
+               }
+            return( DIG_MORE_DATA );
+            }
+         }
+//      SetBorderColor(16);
+      return( DIG_DONE );
+      }
+
+   if ( reason == DIG_DONE )
+      {
+      Voice = VoiceStatus[ voice ].Voice;
+      VoiceStatus[ voice ].playing = FALSE;
+
+      if ( Voice != NULL )
+         {
+         Voice->Active   = FALSE;
+         Voice->Playing  = FALSE;
+
+// I'm commenting this out because a -1 could cause a crash if it
+// is sent to the GF1 code.  This shouldn't be necessary since
+// Active should be false when GF1voice is -1, but this is just
+// a precaution.  Adjust the pan on the wrong voice is a lot
+// more pleasant than a crash!
+//         Voice->GF1voice = -1;
+
+         LL_Remove( VoiceNode, &VoiceList, Voice );
+         LL_AddToTail( VoiceNode, &VoicePool, Voice );
+         }
+
+      if ( GUSWAVE_CallBackFunc )
+         {
+         GUSWAVE_CallBackFunc( Voice->callbackval );
+         }
+      }
+
+   return( DIG_DONE );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: GUSWAVE_DebugCallBack
+
+   GF1 callback service routine with debugging info.
+---------------------------------------------------------------------*/
+
+static int LOADDS GUSWAVE_DebugCallBack
+   (
+   int reason,
+   int voice,
+   unsigned char **buf,
+   unsigned long *size
+   )
+
+   {
+   VoiceNode *Voice;
+
+   // this function is called from an interrupt
+   // remember not to make any DOS or BIOS calls from here
+   // also don't call any C library functions unless you are sure that
+   // they are reentrant
+   // restore our DS register
+
+   if ( VoiceStatus[ voice ].playing == FALSE )
+      {
+//      DB_printf( "GUS Voice %d not playing.\n", voice );
+      DB_printf( "GUS Voice " );
+      DB_PrintNum( voice );
+      DB_printf( " not playing.\n" );
+      return( DIG_DONE );
+         }
+
+      if ( reason == DIG_MORE_DATA )
+         {
+         Voice = VoiceStatus[ voice ].Voice;
+
+//         DB_printf( "Voice %d : More data -- ", Voice );
+         DB_printf( "Voice " );
+         DB_PrintNum( voice );
+         DB_printf( " : More data -- " );
+         if ( Voice != NULL )
+            {
+            if ( Voice->Playing )
+               {
+               GUSWAVE_GetNextVOCBlock( Voice );
+               if ( Voice->Playing )
+                  {
+//                  DB_printf( "More data -- size = %u blocklength = %u\n",
+//                     Voice->length, Voice->BlockLength );
+                  DB_printf( "More data -- size = " );
+                  DB_PrintNum( Voice->length );
+                  DB_printf( " blocklength = " );
+                  DB_PrintNum( Voice->BlockLength );
+                  DB_printf( "\n" );
+                  *buf  = Voice->sound;
+                  *size = Voice->length;
+                  return( DIG_MORE_DATA );
+                  }
+               else
+                  {
+                  DB_printf( "Voice done.\n" );
+                  }
+               }
+            else
+               {
+               DB_printf( "Voice not active.\n" );
+               }
+            }
+         else
+            {
+            DB_printf( " NULL Voice\n" );
+            }
+
+         return( DIG_DONE );
+         }
+
+      if ( reason == DIG_DONE )
+         {
+         VoiceStatus[ voice ].playing = FALSE;
+         Voice = VoiceStatus[ voice ].Voice;
+//         DB_printf( "Voice %d : Done -- ", Voice );
+         DB_printf( "Voice " );
+         DB_PrintNum( voice );
+         DB_printf( " : Done -- " );
+
+         if ( Voice != NULL )
+            {
+            DB_printf( "Ok\n" );
+
+            Voice->Active   = FALSE;
+            Voice->Playing  = FALSE;
+
+// I'm commenting this out because a -1 could cause a crash if it
+// is sent to the GF1 code.  This shouldn't be necessary since
+// Active should be false when GF1voice is -1, but this is just
+// a precaution.  Adjust the pan on the wrong voice is a lot
+// more pleasant than a crash!
+//         Voice->GF1voice = -1;
+
+         LL_Remove( VoiceNode, &VoiceList, Voice );
+         LL_AddToTail( VoiceNode, &VoicePool, Voice );
+         }
+      else
+         {
+         DB_printf( "Null voice\n" );
+         }
+
+      if ( GUSWAVE_CallBackFunc )
+         {
+         GUSWAVE_CallBackFunc( Voice->callbackval );
+         }
+      }
+
+   return( DIG_DONE );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: GUSWAVE_GetVoice
+
+   Locates the voice with the specified handle.
+---------------------------------------------------------------------*/
+
+static VoiceNode *GUSWAVE_GetVoice
+   (
+   int handle
+   )
+
+   {
+   VoiceNode *voice;
+   unsigned  flags;
+
+   flags = DisableInterrupts();
+
+   voice = VoiceList.start;
+
+   while( voice != NULL )
+      {
+      if ( handle == voice->handle )
+         {
+         break;
+         }
+
+      voice = voice->next;
+      }
+
+   RestoreInterrupts( flags );
+
+   if ( voice == NULL )
+      {
+      GUSWAVE_SetErrorCode( GUSWAVE_VoiceNotFound );
+      }
+
+   return( voice );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: GUSWAVE_VoicePlaying
+
+   Checks if the voice associated with the specified handle is
+   playing.
+---------------------------------------------------------------------*/
+
+int GUSWAVE_VoicePlaying
+   (
+   int handle
+   )
+
+   {
+   VoiceNode   *voice;
+
+   voice = GUSWAVE_GetVoice( handle );
+   if ( voice != NULL )
+      {
+      return( voice->Active );
+      }
+
+   return( FALSE );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: GUSWAVE_VoicesPlaying
+
+   Determines the number of currently active voices.
+---------------------------------------------------------------------*/
+
+int GUSWAVE_VoicesPlaying
+   (
+   void
+   )
+
+   {
+   int         index;
+   int         NumVoices = 0;
+   unsigned    flags;
+
+   flags = DisableInterrupts();
+
+   for( index = 0; index < GUSWAVE_MaxVoices; index++ )
+      {
+      if ( GUSWAVE_Voices[ index ].Active )
+         {
+         NumVoices++;
+         }
+      }
+
+   RestoreInterrupts( flags );
+
+   if ( GUS_Debug )
+      {
+      DB_printf( "Number of voices = %d.\n", NumVoices );
+      }
+
+   return( NumVoices );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: GUSWAVE_Kill
+
+   Stops output of the voice associated with the specified handle.
+---------------------------------------------------------------------*/
+
+int GUSWAVE_Kill
+   (
+   int handle
+   )
+
+   {
+   VoiceNode *voice;
+   unsigned  flags;
+
+   flags = DisableInterrupts();
+
+   voice = GUSWAVE_GetVoice( handle );
+
+   if ( voice == NULL )
+      {
+      RestoreInterrupts( flags );
+      GUSWAVE_SetErrorCode( GUSWAVE_VoiceNotFound );
+
+      if ( GUS_Debug )
+         {
+         DB_printf( "Could not find voice to kill.\n" );
+         }
+
+      return( GUSWAVE_Warning );
+      }
+
+   RestoreInterrupts( flags );
+
+   if ( !GUS_Debug )
+      {
+      if ( voice->Active )
+         {
+         gf1_stop_digital( voice->GF1voice );
+         }
+      }
+   else
+      {
+      DB_printf( "Kill - GUS Voice %d ", voice->GF1voice );
+      if ( voice->Active )
+         {
+         DB_printf( "active\n" );
+         gf1_stop_digital( voice->GF1voice );
+         }
+      else
+         {
+         DB_printf( "inactive\n" );
+         }
+      }
+
+//   RestoreInterrupts( flags );
+
+   return( GUSWAVE_Ok );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: GUSWAVE_KillAllVoices
+
+   Stops output of all currently active voices.
+---------------------------------------------------------------------*/
+
+int GUSWAVE_KillAllVoices
+   (
+   void
+   )
+
+   {
+   int i;
+   unsigned  flags;
+
+   if ( !GUSWAVE_Installed )
+      {
+      return( GUSWAVE_Ok );
+      }
+
+   if ( GUS_Debug )
+      {
+      DB_printf( "Kill All Voices\n" );
+      }
+
+   flags = DisableInterrupts();
+
+   // Remove all the voices from the list
+   for( i = 0; i < GUSWAVE_MaxVoices; i++ )
+      {
+      if ( GUSWAVE_Voices[ i ].Active )
+         {
+//         GUSWAVE_Kill( GUSWAVE_Voices[ i ].handle );
+
+         gf1_stop_digital( GUSWAVE_Voices[ i ].GF1voice );
+         }
+      }
+
+   for( i = 0; i < MAX_VOICES; i++ )
+      {
+      VoiceStatus[ i ].playing = FALSE;
+      VoiceStatus[ i ].Voice   = NULL;
+      }
+
+   VoicePool.start = NULL;
+   VoicePool.end   = NULL;
+   VoiceList.start = NULL;
+   VoiceList.end   = NULL;
+
+   for( i = 0; i < GUSWAVE_MaxVoices; i++ )
+      {
+      GUSWAVE_Voices[ i ].Active = FALSE;
+      if ( GUSWAVE_Voices[ i ].mem != NULL )
+         {
+         LL_AddToTail( VoiceNode, &VoicePool, &GUSWAVE_Voices[ i ] );
+         }
+      }
+
+   RestoreInterrupts( flags );
+
+   return( GUSWAVE_Ok );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: GUSWAVE_SetPitch
+
+   Sets the pitch for the voice associated with the specified handle.
+---------------------------------------------------------------------*/
+
+int GUSWAVE_SetPitch
+   (
+   int handle,
+   int pitchoffset
+   )
+
+   {
+   VoiceNode *voice;
+   unsigned  flags;
+
+   flags = DisableInterrupts();
+
+   voice = GUSWAVE_GetVoice( handle );
+
+   if ( voice == NULL )
+      {
+      RestoreInterrupts( flags );
+
+      GUSWAVE_SetErrorCode( GUSWAVE_VoiceNotFound );
+      return( GUSWAVE_Warning );
+      }
+
+   if ( voice->Active )
+      {
+      voice->PitchScale  = PITCH_GetScale( pitchoffset );
+      voice->RateScale   = ( voice->SamplingRate * voice->PitchScale ) >> 16;
+      gf1_dig_set_freq( voice->GF1voice, voice->RateScale );
+      }
+
+   RestoreInterrupts( flags );
+
+   return( GUSWAVE_Ok );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: GUSWAVE_SetPan3D
+
+   Sets the pan position of the voice with the specified handle.
+---------------------------------------------------------------------*/
+
+int GUSWAVE_SetPan3D
+   (
+   int handle,
+   int angle,
+   int distance
+   )
+
+   {
+   VoiceNode *voice;
+   int        pan;
+   unsigned  flags;
+
+   flags = DisableInterrupts();
+
+   voice = GUSWAVE_GetVoice( handle );
+
+   if ( voice == NULL )
+      {
+      RestoreInterrupts( flags );
+
+      GUSWAVE_SetErrorCode( GUSWAVE_VoiceNotFound );
+      return( GUSWAVE_Warning );
+      }
+
+   if ( voice->Active )
+      {
+      angle &= 31;
+
+      pan = GUSWAVE_PanTable[ angle ];
+      if ( GUSWAVE_SwapLeftRight )
+         {
+         pan = 15 - pan;
+         }
+
+      distance = max( 0, distance );
+      distance = min( 255, distance );
+
+      voice->Volume = 255 - distance;
+      voice->Pan    = pan;
+
+      gf1_dig_set_pan( voice->GF1voice, pan );
+      gf1_dig_set_vol( voice->GF1voice, GUSWAVE_Volume - distance * 4 );
+      }
+
+   RestoreInterrupts( flags );
+
+   return( GUSWAVE_Ok );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: GUSWAVE_SetVolume
+
+   Sets the total volume of the digitized sounds.
+---------------------------------------------------------------------*/
+
+void GUSWAVE_SetVolume
+   (
+   int volume
+   )
+
+   {
+   int i;
+
+   volume = max( 0, volume );
+   volume = min( 255, volume );
+   GUSWAVE_Volume = MAX_VOLUME - ( 255 - volume ) * 4;
+
+   for( i = 0; i < GUSWAVE_MaxVoices; i++ )
+      {
+      if ( GUSWAVE_Voices[ i ].Active )
+         {
+         gf1_dig_set_vol( GUSWAVE_Voices[ i ].GF1voice,
+            GUSWAVE_Volume - ( 255 - GUSWAVE_Voices[ i ].Volume ) * 4 );
+         }
+      }
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: GUSWAVE_GetVolume
+
+   Returns the total volume of the digitized sounds.
+---------------------------------------------------------------------*/
+
+int GUSWAVE_GetVolume
+   (
+   void
+   )
+
+   {
+   return( 255 - ( ( MAX_VOLUME - GUSWAVE_Volume ) / 4 ) );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: GUSWAVE_AllocVoice
+
+   Retrieve an inactive or lower priority voice for output.
+---------------------------------------------------------------------*/
+
+static VoiceNode *GUSWAVE_AllocVoice
+   (
+   int priority
+   )
+
+   {
+   VoiceNode   *voice;
+   VoiceNode   *node;
+   unsigned    flags;
+
+   // If we don't have any free voices, check if we have a higher
+   // priority than one that is playing.
+   if ( GUSWAVE_VoicesPlaying() >= GUSWAVE_MaxVoices )
+      {
+      flags = DisableInterrupts();
+
+      node = VoiceList.start;
+      voice = node;
+      while( node != NULL )
+         {
+         if ( node->priority < voice->priority )
+            {
+            voice = node;
+            }
+
+         node = node->next;
+         }
+
+      RestoreInterrupts( flags );
+
+      if ( priority >= voice->priority )
+         {
+         GUSWAVE_Kill( voice->handle );
+         }
+      }
+
+   // Check if any voices are in the voice pool
+   flags = DisableInterrupts();
+
+   voice = VoicePool.start;
+   if ( voice != NULL )
+      {
+      LL_Remove( VoiceNode, &VoicePool, voice );
+      }
+
+   RestoreInterrupts( flags );
+
+   if ( voice != NULL )
+      {
+      do
+         {
+         GUSWAVE_VoiceHandle++;
+         if ( GUSWAVE_VoiceHandle < GUSWAVE_MinVoiceHandle )
+            {
+            GUSWAVE_VoiceHandle = GUSWAVE_MinVoiceHandle;
+            }
+         }
+      while( GUSWAVE_VoicePlaying( GUSWAVE_VoiceHandle ) );
+
+      voice->handle = GUSWAVE_VoiceHandle;
+      }
+
+   return( voice );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: GUSWAVE_VoiceAvailable
+
+   Checks if a voice can be play at the specified priority.
+---------------------------------------------------------------------*/
+
+int GUSWAVE_VoiceAvailable
+   (
+   int priority
+   )
+
+   {
+   VoiceNode   *voice;
+   VoiceNode   *node;
+   unsigned    flags;
+
+   if ( GUSWAVE_VoicesPlaying() < GUSWAVE_MaxVoices )
+      {
+      return( TRUE );
+      }
+
+   flags = DisableInterrupts();
+
+   node = VoiceList.start;
+   voice = node;
+   while( node != NULL )
+      {
+      if ( node->priority < voice->priority )
+         {
+         voice = node;
+         }
+
+      node = node->next;
+      }
+
+   RestoreInterrupts( flags );
+
+   if ( priority >= voice->priority )
+      {
+      return( TRUE );
+      }
+
+   return( FALSE );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: GUSWAVE_GetNextVOCBlock
+
+   Interperate the information of a VOC format sound file.
+---------------------------------------------------------------------*/
+
+playbackstatus GUSWAVE_GetNextVOCBlock
+   (
+   VoiceNode *voice
+   )
+
+   {
+   unsigned char *ptr;
+   int            blocktype;
+   int            lastblocktype;
+   unsigned long  blocklength;
+   unsigned long  samplespeed;
+   unsigned int   tc;
+   int            packtype;
+   int            voicemode;
+   int            done;
+   unsigned       BitsPerSample;
+   unsigned       Channels;
+   unsigned       Format;
+
+   if ( voice->BlockLength > 0 )
+      {
+      voice->sound       += MAX_BLOCK_LENGTH;
+      voice->length       = min( voice->BlockLength, MAX_BLOCK_LENGTH );
+      voice->BlockLength -= voice->length;
+      return( KeepPlaying );
+      }
+
+   ptr = ( unsigned char * )voice->NextBlock;
+
+   voice->Playing = TRUE;
+
+   voicemode = 0;
+   lastblocktype = 0;
+   packtype = 0;
+
+   done = FALSE;
+   while( !done )
+      {
+      // Stop playing if we get a NULL pointer
+      if ( ptr == NULL )
+         {
+         voice->Playing = FALSE;
+         done = TRUE;
+         break;
+         }
+
+      blocktype = ( int )*ptr;
+      blocklength = ( *( unsigned long * )( ptr + 1 ) ) & 0x00ffffff;
+      ptr += 4;
+
+      switch( blocktype )
+         {
+         case 0 :
+            // End of data
+            voice->Playing = FALSE;
+            done = TRUE;
+            break;
+
+         case 1 :
+            // Sound data block
+            voice->bits = 8;
+            if ( lastblocktype != 8 )
+               {
+               tc = ( unsigned int )*ptr << 8;
+               packtype = *( ptr + 1 );
+               }
+
+            ptr += 2;
+            blocklength -= 2;
+
+            samplespeed = 256000000L / ( 65536 - tc );
+
+            // Skip packed or stereo data
+            if ( ( packtype != 0 ) || ( voicemode != 0 ) )
+               {
+               ptr += blocklength;
+               }
+            else
+               {
+               done = TRUE;
+               }
+            voicemode = 0;
+            break;
+
+         case 2 :
+            // Sound continuation block
+            samplespeed = voice->SamplingRate;
+            done = TRUE;
+            break;
+
+         case 3 :
+            // Silence
+            // Not implimented.
+            ptr += blocklength;
+            break;
+
+         case 4 :
+            // Marker
+            // Not implimented.
+            ptr += blocklength;
+            break;
+
+         case 5 :
+            // ASCII string
+            // Not implimented.
+            ptr += blocklength;
+            break;
+
+         case 6 :
+            // Repeat begin
+            voice->LoopCount = *( unsigned short * )ptr;
+            ptr += blocklength;
+            voice->LoopStart = ptr;
+            break;
+
+         case 7 :
+            // Repeat end
+            ptr += blocklength;
+            if ( lastblocktype == 6 )
+               {
+               voice->LoopCount = 0;
+               }
+            else
+               {
+               if ( ( voice->LoopCount > 0 ) && ( voice->LoopStart != NULL ) )
+                  {
+                  ptr = voice->LoopStart;
+                  if ( voice->LoopCount < 0xffff )
+                     {
+                     voice->LoopCount--;
+                     if ( voice->LoopCount == 0 )
+                        {
+                        voice->LoopStart = NULL;
+                        }
+                     }
+                  }
+               }
+            break;
+
+         case 8 :
+            // Extended block
+            voice->bits = 8;
+            tc = *( unsigned short * )ptr;
+            packtype = *( ptr + 2 );
+            voicemode = *( ptr + 3 );
+            ptr += blocklength;
+            break;
+
+         case 9 :
+            // New sound data block
+            samplespeed = *( unsigned long * )ptr;
+            BitsPerSample = ( unsigned )*( ptr + 4 );
+            Channels = ( unsigned )*( ptr + 5 );
+            Format = ( unsigned )*( unsigned short * )( ptr + 6 );
+
+            if ( ( BitsPerSample == 8 ) && ( Channels == 1 ) &&
+               ( Format == VOC_8BIT ) )
+               {
+               ptr += 12;
+               blocklength -= 12;
+               voice->bits  = 8;
+               done = TRUE;
+               }
+            else if ( ( BitsPerSample == 16 ) && ( Channels == 1 ) &&
+               ( Format == VOC_16BIT ) )
+               {
+               ptr         += 12;
+               blocklength -= 12;
+               voice->bits  = 16;
+               done         = TRUE;
+               }
+            else
+               {
+               ptr += blocklength;
+               }
+            break;
+
+         default :
+            // Unknown data.  Probably not a VOC file.
+            voice->Playing = FALSE;
+            done = TRUE;
+            break;
+         }
+
+      lastblocktype = blocktype;
+      }
+
+   if ( voice->Playing )
+      {
+      voice->NextBlock    = ptr + blocklength;
+      voice->sound        = ptr;
+
+      voice->SamplingRate = samplespeed;
+      voice->RateScale    = ( voice->SamplingRate * voice->PitchScale ) >> 16;
+
+      voice->length       = min( blocklength, MAX_BLOCK_LENGTH );
+      voice->BlockLength  = blocklength - voice->length;
+
+      return( KeepPlaying );
+      }
+
+   return( SoundDone );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: GUSWAVE_GetNextWAVBlock
+
+   Controls playback of demand fed data.
+---------------------------------------------------------------------*/
+
+playbackstatus GUSWAVE_GetNextWAVBlock
+   (
+   VoiceNode *voice
+   )
+
+   {
+   if ( voice->BlockLength <= 0 )
+      {
+      if ( voice->LoopStart == NULL )
+         {
+         voice->Playing = FALSE;
+         return( SoundDone );
+         }
+
+      voice->BlockLength = voice->LoopSize;
+      voice->NextBlock   = voice->LoopStart;
+      voice->length      = 0;
+      }
+
+   voice->sound        = voice->NextBlock;
+   voice->length       = min( voice->BlockLength, 0x8000 );
+   voice->NextBlock   += voice->length;
+   voice->BlockLength -= voice->length;
+
+   return( KeepPlaying );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: GUSWAVE_GetNextDemandFeedBlock
+
+   Controls playback of demand fed data.
+---------------------------------------------------------------------*/
+
+playbackstatus GUSWAVE_GetNextDemandFeedBlock
+   (
+   VoiceNode *voice
+   )
+
+   {
+   if ( voice->BlockLength > 0 )
+      {
+      voice->sound       += voice->length;
+      voice->length       = min( voice->BlockLength, 0x8000 );
+      voice->BlockLength -= voice->length;
+
+      return( KeepPlaying );
+      }
+
+   if ( voice->DemandFeed == NULL )
+      {
+      return( SoundDone );
+      }
+
+   ( voice->DemandFeed )( &voice->sound, &voice->BlockLength );
+//   voice->sound = GUS_Silence16;
+//   voice->BlockLength = 256;
+
+   voice->length       = min( voice->BlockLength, 0x8000 );
+   voice->BlockLength -= voice->length;
+
+   if ( ( voice->length > 0 ) && ( voice->sound != NULL ) )
+      {
+      return( KeepPlaying );
+      }
+   return( NoMoreData );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: GUSWAVE_Play
+
+   Begins playback of digitized sound.
+---------------------------------------------------------------------*/
+
+int GUSWAVE_Play
+   (
+   VoiceNode *voice,
+   int angle,
+   int volume,
+   int channels
+   )
+
+   {
+   int      VoiceNumber;
+   int      type;
+   int      pan;
+   unsigned flags;
+   int ( *servicefunction )( int reason, int voice, unsigned char **buf, unsigned long *size );
+
+   type = 0;
+   if ( channels != 1 )
+      {
+      type |= TYPE_STEREO;
+      }
+
+   if ( voice->bits == 8 )
+      {
+      type |= TYPE_8BIT;
+      type |= TYPE_INVERT_MSB;
+      }
+
+   voice->GF1voice  = -1;
+
+   angle &= 31;
+   pan = GUSWAVE_PanTable[ angle ];
+   if ( GUSWAVE_SwapLeftRight )
+      {
+      pan = 15 - pan;
+      }
+
+   voice->Pan = pan;
+
+   volume = max( 0, volume );
+   volume = min( 255, volume );
+   voice->Volume = volume;
+
+   if ( !GUS_Debug )
+      {
+      servicefunction = GUSWAVE_CallBack;
+      }
+   else
+      {
+      servicefunction = GUSWAVE_DebugCallBack;
+      }
+
+   VoiceNumber = gf1_play_digital( 0, voice->sound, voice->length,
+      voice->mem, GUSWAVE_Volume - ( 255 - volume ) * 4, pan,
+      voice->RateScale, type, &GUS_HoldBuffer, servicefunction );
+
+   if ( VoiceNumber == NO_MORE_VOICES )
+      {
+      if ( GUS_Debug )
+         {
+         DB_printf( "Out of voices.\n" );
+         }
+
+      flags = DisableInterrupts();
+      LL_AddToTail( VoiceNode, &VoicePool, voice );
+      RestoreInterrupts( flags );
+
+      GUSWAVE_SetErrorCode( GUSWAVE_NoVoices );
+      return( GUSWAVE_Warning );
+      }
+
+   flags = DisableInterrupts();
+   voice->GF1voice = VoiceNumber;
+   voice->Active   = TRUE;
+   LL_AddToTail( VoiceNode, &VoiceList, voice );
+   VoiceStatus[ VoiceNumber ].playing = TRUE;
+   VoiceStatus[ VoiceNumber ].Voice   = voice;
+
+   if ( GUS_Debug )
+      {
+      DB_printf( "GUS voice %d playing\n", VoiceNumber );
+      }
+
+   RestoreInterrupts( flags );
+
+   return( voice->handle );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: GUSWAVE_PlayVOC
+
+   Begins playback of digitized sound.
+---------------------------------------------------------------------*/
+
+int GUSWAVE_PlayVOC
+   (
+   char *sample,
+   int   pitchoffset,
+   int   angle,
+   int   volume,
+   int   priority,
+   unsigned long callbackval
+   )
+
+   {
+   int handle;
+   int status;
+   playbackstatus soundstatus;
+   VoiceNode *voice;
+   unsigned flags;
+
+   // Make sure it's a valid VOC file.
+   status = strncmp( sample, "Creative Voice File", 19 );
+   if ( status != 0 )
+      {
+      // Tell multivoc that we had a bad VOC file
+      MV_ErrorCode = MV_InvalidVOCFile;
+
+      GUSWAVE_SetErrorCode( GUSWAVE_InvalidVOCFile );
+      return( GUSWAVE_Error );
+      }
+
+   // Request a voice from the voice pool
+   voice = GUSWAVE_AllocVoice( priority );
+   if ( voice == NULL )
+      {
+      if ( GUS_Debug )
+         {
+         DB_printf( "No more voices.  Skipping sound.\n" );
+         }
+      GUSWAVE_SetErrorCode( GUSWAVE_NoVoices );
+      return( GUSWAVE_Warning );
+      }
+
+   voice->NextBlock   = sample + *( unsigned short int * )( sample + 0x14 );
+   voice->LoopStart   = NULL;
+   voice->LoopCount   = 0;
+   voice->BlockLength = 0;
+   voice->PitchScale  = PITCH_GetScale( pitchoffset );
+   voice->wavetype    = VOC;
+   voice->bits        = 8;
+   voice->GetSound    = GUSWAVE_GetNextVOCBlock;
+   voice->length      = 0;
+   voice->next        = NULL;
+   voice->prev        = NULL;
+   voice->priority    = priority;
+   voice->callbackval = callbackval;
+
+   soundstatus = GUSWAVE_GetNextVOCBlock( voice );
+   if ( soundstatus == SoundDone )
+      {
+      flags = DisableInterrupts();
+      LL_AddToTail( VoiceNode, &VoicePool, voice );
+      RestoreInterrupts( flags );
+
+      if ( GUS_Debug )
+         {
+         DB_printf( "Voice ended before playback.\n" );
+         }
+
+      // Tell multivoc that we had a bad VOC file
+      MV_ErrorCode = MV_InvalidVOCFile;
+
+      GUSWAVE_SetErrorCode( GUSWAVE_InvalidVOCFile );
+      return( GUSWAVE_Error );
+      }
+
+   handle = GUSWAVE_Play( voice, angle, volume, 1 );
+   return( handle );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: GUSWAVE_PlayWAV
+
+   Begins playback of digitized sound.
+---------------------------------------------------------------------*/
+
+int GUSWAVE_PlayWAV
+   (
+   char *sample,
+   int   pitchoffset,
+   int   angle,
+   int   volume,
+   int   priority,
+   unsigned long callbackval
+   )
+
+   {
+   VoiceNode *voice;
+   int        handle;
+   int        channels;
+   int        bits;
+   int        length;
+   riff_header   *riff;
+   format_header *format;
+   data_header   *data;
+
+   riff = ( riff_header * )sample;
+
+   if ( ( strncmp( riff->RIFF, "RIFF", 4 ) != 0 ) ||
+      ( strncmp( riff->WAVE, "WAVE", 4 ) != 0 ) ||
+      ( strncmp( riff->fmt, "fmt ", 4) != 0 ) )
+      {
+      GUSWAVE_SetErrorCode( GUSWAVE_InvalidWAVFile );
+      return( GUSWAVE_Error );
+      }
+
+   format = ( format_header * )( riff + 1 );
+   data   = ( data_header * )( ( ( char * )format ) + riff->format_size );
+
+   if ( format->wFormatTag != 1 )
+      {
+      GUSWAVE_SetErrorCode( GUSWAVE_InvalidWAVFile );
+      return( GUSWAVE_Error );
+      }
+
+   channels = format->nChannels;
+   if ( ( channels != 1 ) && ( channels != 2 ) )
+      {
+      GUSWAVE_SetErrorCode( GUSWAVE_InvalidWAVFile );
+      return( GUSWAVE_Error );
+      }
+
+   bits = format->nBitsPerSample;
+   if ( ( bits != 8 ) && ( bits != 16 ) )
+      {
+      GUSWAVE_SetErrorCode( GUSWAVE_InvalidWAVFile );
+      return( GUSWAVE_Error );
+      }
+
+   if ( strncmp( data->DATA, "data", 4 ) != 0 )
+      {
+      GUSWAVE_SetErrorCode( GUSWAVE_InvalidWAVFile );
+      return( GUSWAVE_Error );
+      }
+
+   // Request a voice from the voice pool
+   voice = GUSWAVE_AllocVoice( priority );
+   if ( voice == NULL )
+      {
+      if ( GUS_Debug )
+         {
+         DB_printf( "No more voices.  Skipping sound.\n" );
+         }
+      GUSWAVE_SetErrorCode( GUSWAVE_NoVoices );
+      return( GUSWAVE_Warning );
+      }
+
+   voice->wavetype    = WAV;
+   voice->bits        = bits;
+   voice->GetSound    = GUSWAVE_GetNextWAVBlock;
+
+   length = data->size;
+
+   voice->Playing     = TRUE;
+   voice->DemandFeed  = NULL;
+   voice->LoopStart   = NULL;
+   voice->LoopCount   = 0;
+   voice->length      = min( length, 0x8000 );
+   voice->BlockLength = length - voice->length;//  min( loopend + 1, data->size );
+   voice->sound       = ( char * )( data + 1 );
+   voice->NextBlock   = voice->sound + voice->length;
+   voice->next        = NULL;
+   voice->prev        = NULL;
+   voice->priority    = priority;
+   voice->callbackval = callbackval;
+   voice->LoopStart   = NULL;// voice->NextBlock + loopstart;
+   voice->LoopEnd     = NULL;//voice->NextBlock + min( loopend, data->size - 1 );
+   voice->LoopSize    = 0;//( voice->LoopEnd - voice->LoopStart ) + 1;
+   voice->PitchScale  = PITCH_GetScale( pitchoffset );
+   voice->SamplingRate = format->nSamplesPerSec;
+   voice->RateScale   = ( voice->SamplingRate * voice->PitchScale ) >> 16;
+
+   handle = GUSWAVE_Play( voice, angle, volume, channels );
+
+   return( handle );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: GUSWAVE_StartDemandFeedPlayback
+
+   Begins playback of digitized sound.
+---------------------------------------------------------------------*/
+
+int GUSWAVE_StartDemandFeedPlayback
+   (
+   void ( *function )( char **ptr, unsigned long *length ),
+   int   channels,
+   int   bits,
+   int   rate,
+   int   pitchoffset,
+   int   angle,
+   int   volume,
+   int   priority,
+   unsigned long callbackval
+   )
+
+   {
+   VoiceNode *voice;
+   int        handle;
+
+   // Request a voice from the voice pool
+   voice = GUSWAVE_AllocVoice( priority );
+   if ( voice == NULL )
+      {
+      if ( GUS_Debug )
+         {
+         DB_printf( "No more voices.  Skipping sound.\n" );
+         }
+      GUSWAVE_SetErrorCode( GUSWAVE_NoVoices );
+      return( GUSWAVE_Warning );
+      }
+
+   voice->wavetype    = DemandFeed;
+   voice->bits        = bits;
+   voice->GetSound    = GUSWAVE_GetNextDemandFeedBlock;
+   voice->Playing     = TRUE;
+   voice->DemandFeed  = function;
+   voice->LoopStart   = NULL;
+   voice->LoopCount   = 0;
+   voice->BlockLength = 0;
+   voice->length      = 256;
+   voice->sound       = ( bits == 8 ) ? GUS_Silence8 : ( char * )GUS_Silence16;
+   voice->NextBlock   = NULL;
+   voice->next        = NULL;
+   voice->prev        = NULL;
+   voice->priority    = priority;
+   voice->callbackval = callbackval;
+   voice->PitchScale  = PITCH_GetScale( pitchoffset );
+   voice->SamplingRate = rate;
+   voice->RateScale   = ( voice->SamplingRate * voice->PitchScale ) >> 16;
+
+   handle = GUSWAVE_Play( voice, angle, volume, channels );
+
+   return( handle );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: GUSWAVE_SetReverseStereo
+
+   Set the orientation of the left and right channels.
+---------------------------------------------------------------------*/
+
+void GUSWAVE_SetReverseStereo
+   (
+   int setting
+   )
+
+   {
+   GUSWAVE_SwapLeftRight = setting;
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: GUSWAVE_GetReverseStereo
+
+   Returns the orientation of the left and right channels.
+---------------------------------------------------------------------*/
+
+int GUSWAVE_GetReverseStereo
+   (
+   void
+   )
+
+   {
+   return( GUSWAVE_SwapLeftRight );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: GUSWAVE_InitVoices
+
+   Begins playback of digitized sound.
+---------------------------------------------------------------------*/
+
+static int GUSWAVE_InitVoices
+   (
+   void
+   )
+
+   {
+   int i;
+
+   for( i = 0; i < MAX_VOICES; i++ )
+      {
+      VoiceStatus[ i ].playing = FALSE;
+      VoiceStatus[ i ].Voice   = NULL;
+      }
+
+   VoicePool.start = NULL;
+   VoicePool.end   = NULL;
+   VoiceList.start = NULL;
+   VoiceList.end   = NULL;
+
+   for( i = 0; i < VOICES; i++ )
+      {
+      GUSWAVE_Voices[ i ].num      = -1;
+      GUSWAVE_Voices[ i ].Active   = FALSE;
+      GUSWAVE_Voices[ i ].GF1voice = -1;
+      GUSWAVE_Voices[ i ].mem      = NULL;
+      }
+
+   for( i = 0; i < VOICES; i++ )
+      {
+      GUSWAVE_Voices[ i ].num      = i;
+      GUSWAVE_Voices[ i ].Active   = FALSE;
+      GUSWAVE_Voices[ i ].GF1voice = 0;
+
+      GUSWAVE_Voices[ i ].mem = gf1_malloc( GF1BSIZE );
+      if ( GUSWAVE_Voices[ i ].mem == NULL )
+         {
+         GUSWAVE_MaxVoices = i;
+         if ( i < 1 )
+            {
+            if ( GUSMIDI_Installed )
+               {
+               GUSWAVE_SetErrorCode( GUSWAVE_UltraNoMemMIDI );
+               }
+            else
+               {
+               GUSWAVE_SetErrorCode( GUSWAVE_UltraNoMem );
+               }
+            return( GUSWAVE_Error );
+            }
+
+         break;
+         }
+
+      LL_AddToTail( VoiceNode, &VoicePool, &GUSWAVE_Voices[ i ] );
+      }
+
+   return( GUSWAVE_Ok );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: GUSWAVE_SetCallBack
+
+   Set the function to call when a voice stops.
+---------------------------------------------------------------------*/
+
+void GUSWAVE_SetCallBack
+   (
+   void ( *function )( unsigned long )
+   )
+
+   {
+   GUSWAVE_CallBackFunc = function;
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: GUSWAVE_Init
+
+   Initializes the Gravis Ultrasound for digitized sound playback.
+---------------------------------------------------------------------*/
+
+int GUSWAVE_Init
+   (
+   int numvoices
+   )
+
+   {
+   int status;
+
+   if ( GUSWAVE_Installed )
+      {
+      GUSWAVE_Shutdown();
+      }
+
+   GUSWAVE_SetErrorCode( GUSWAVE_Ok );
+
+   status = GUS_Init();
+   if ( status != GUS_Ok )
+      {
+      GUSWAVE_SetErrorCode( GUSWAVE_GUSError );
+      return( GUSWAVE_Error );
+      }
+
+   GUS_Debug = USER_CheckParameter( "DEBUGGUS" );
+
+   GUSWAVE_MaxVoices = min( numvoices, VOICES );
+   GUSWAVE_MaxVoices = max( GUSWAVE_MaxVoices, 0 );
+
+   status = GUSWAVE_InitVoices();
+   if ( status != GUSWAVE_Ok )
+      {
+      GUS_Shutdown();
+      return( status );
+      }
+
+   GUSWAVE_SetReverseStereo( FALSE );
+
+   GUSWAVE_CallBackFunc = NULL;
+   GUSWAVE_Installed = TRUE;
+
+   return( GUSWAVE_Ok );
+   }
--- /dev/null
+++ b/rott/audiolib/guswave.h
@@ -1,0 +1,75 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+/**********************************************************************
+   module: GUSWAVE.H
+
+   author: James R. Dose
+   date:   March 23, 1994
+
+   Public header for for GUSWAVE.C
+
+   (c) Copyright 1994 James R. Dose.  All Rights Reserved.
+**********************************************************************/
+
+#ifndef __GUSWAVE_H
+#define __GUSWAVE_H
+
+#define GUSWAVE_MinVoiceHandle 1
+
+enum GUSWAVE_Errors
+   {
+   GUSWAVE_Warning  = -2,
+   GUSWAVE_Error    = -1,
+   GUSWAVE_Ok       = 0,
+   GUSWAVE_GUSError,
+   GUSWAVE_NotInstalled,
+   GUSWAVE_NoVoices,
+   GUSWAVE_UltraNoMem,
+   GUSWAVE_UltraNoMemMIDI,
+   GUSWAVE_VoiceNotFound,
+   GUSWAVE_InvalidVOCFile,
+   GUSWAVE_InvalidWAVFile
+   };
+
+char *GUSWAVE_ErrorString( int ErrorNumber );
+int   GUSWAVE_VoicePlaying( int handle );
+int   GUSWAVE_VoicesPlaying( void );
+int   GUSWAVE_Kill( int handle );
+int   GUSWAVE_KillAllVoices( void );
+int   GUSWAVE_SetPitch( int handle, int pitchoffset );
+int   GUSWAVE_SetPan3D( int handle, int angle, int distance );
+void  GUSWAVE_SetVolume( int volume );
+int   GUSWAVE_GetVolume( void );
+int   GUSWAVE_VoiceAvailable( int priority );
+int   GUSWAVE_PlayVOC( char *sample, int pitchoffset, int angle, int volume,
+         int priority, unsigned long callbackval );
+int   GUSWAVE_PlayWAV( char *sample, int pitchoffset, int angle, int volume,
+         int priority, unsigned long callbackval );
+int   GUSWAVE_StartDemandFeedPlayback( void ( *function )( char **ptr, unsigned long *length ),
+         int channels, int bits, int rate, int pitchoffset, int angle,
+         int volume, int priority, unsigned long callbackval );
+void  GUSWAVE_SetCallBack( void ( *function )( unsigned long ) );
+void  GUSWAVE_SetReverseStereo( int setting );
+int   GUSWAVE_GetReverseStereo( void );
+int   GUSWAVE_Init( int numvoices );
+void  GUSWAVE_Shutdown( void );
+#pragma aux GUSWAVE_Shutdown frame;
+
+#endif
--- /dev/null
+++ b/rott/audiolib/interrup.h
@@ -1,0 +1,50 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+/**********************************************************************
+   module: INTERRUP.H
+
+   author: James R. Dose
+   date:   March 31, 1994
+
+   Inline functions for disabling and restoring the interrupt flag.
+
+   (c) Copyright 1994 James R. Dose.  All Rights Reserved.
+**********************************************************************/
+
+#ifndef __INTERRUPT_H
+#define __INTERRUPT_H
+
+unsigned long DisableInterrupts( void );
+void          RestoreInterrupts( unsigned long flags );
+
+#ifdef PLAT_DOS
+#pragma aux DisableInterrupts = \
+   "pushfd",                    \
+   "pop    eax",                \
+   "cli"                        \
+   modify [ eax ];
+
+#pragma aux RestoreInterrupts = \
+   "push   eax",                \
+   "popfd"                      \
+   parm [ eax ];
+#endif
+
+#endif
--- /dev/null
+++ b/rott/audiolib/irq.c
@@ -1,0 +1,325 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+/**********************************************************************
+   module: IRQ.C
+
+   author: James R. Dose
+   date:   August 26, 1994
+
+   Low level routines to set and restore IRQ's through DPMI.
+
+   (c) Copyright 1994 James R. Dose.  All Rights Reserved.
+**********************************************************************/
+
+#include <dos.h>
+#include <stdlib.h>
+#include "irq.h"
+
+#define D32RealSeg(P) ( ( ( ( unsigned long )( P ) ) >> 4 ) & 0xFFFF )
+#define D32RealOff(P) ( ( ( unsigned long )( P ) ) & 0xF )
+
+typedef struct
+   {
+   unsigned long  drdi;
+   unsigned long  drsi;
+   unsigned long  drbp;
+   unsigned long  drxx;
+   unsigned long  drbx;
+   unsigned long  drdx;
+   unsigned long  drcx;
+   unsigned long  drax;
+
+   unsigned short drflags;
+   unsigned short dres;
+   unsigned short drds;
+   unsigned short drfs;
+   unsigned short drgs;
+   unsigned short drip;
+   unsigned short drcs;
+   unsigned short drsp;
+   unsigned short drss;
+   } DPMI_REGS;
+
+static DPMI_REGS rmregs = { 0 };
+static void ( __interrupt __far *IRQ_Callback )( void ) = NULL;
+
+static char *IRQ_RealModeCode = NULL;
+
+static unsigned short IRQ_CallBackSegment;
+static unsigned short IRQ_CallBackOffset;
+static unsigned short IRQ_RealModeSegment;
+static unsigned short IRQ_RealModeOffset;
+static unsigned long  IRQ_ProtectedModeOffset;
+static unsigned short IRQ_ProtectedModeSelector;
+
+static union  REGS  Regs;
+static struct SREGS SegRegs;
+
+static void *D32DosMemAlloc
+   (
+   unsigned long size
+   )
+
+   {
+   // DPMI allocate DOS memory
+   Regs.x.eax = 0x0100;
+
+   // Number of paragraphs requested
+   Regs.x.ebx = ( size + 15 ) >> 4;
+
+   int386( 0x31, &Regs, &Regs );
+
+   if ( Regs.x.cflag != 0 )
+      {
+      // Failed
+      return ( ( unsigned long )0 );
+      }
+
+   return( ( void * )( ( Regs.x.eax & 0xFFFF ) << 4  ) );
+   }
+
+// Intermediary function: DPMI calls this, making it
+// easier to write in C
+// handle 16-bit incoming stack
+
+void fixebp
+   (
+   void
+   );
+
+#pragma aux fixebp = \
+        "mov   bx,  ss" \
+        "lar   ebx, ebx" \
+        "bt    ebx, 22" \
+        "jc    bigstk" \
+        "movzx esp, sp" \
+        "mov   ebp, esp" \
+        "bigstk:" \
+modify exact [ ebx ];
+
+#pragma aux rmcallback parm [];
+
+void rmcallback
+   (
+   unsigned short _far *stkp
+   )
+
+   {
+   // "Pop" the real mode return frame so we
+   // can resume where we left off
+   rmregs.drip = *stkp++;
+   rmregs.drcs = *stkp++;
+
+   rmregs.drsp = FP_OFF(stkp);
+
+   // Call protected-mode handler
+   IRQ_Callback();
+   }
+
+static void _interrupt _cdecl callback_x
+   (
+   // regs pushed in this order by prologue
+
+   int rgs,
+   int rfs,
+   int res,
+   int rds,
+   int rdi,
+   int rsi,
+   int rbp,
+   int rsp,
+   int rbx,
+   int rdx,
+   int rcx,
+   int rax
+   )
+
+   {
+//   unsigned short _far *stkp;
+//   return;
+
+   fixebp();
+   rmcallback (MK_FP(rds, rsi));
+   }
+
+/*
+static void _interrupt _cdecl callback_x
+   (
+   // regs pushed in this order by prologue
+
+   int rgs,
+   int rfs,
+   int res,
+   int rds,
+   int rdi,
+   int rsi,
+   int rbp,
+   int rsp,
+   int rbx,
+   int rdx,
+   int rcx,
+   int rax
+   )
+
+   {
+   unsigned short _far *stkp;
+
+   fixebp();
+   stkp = MK_FP(rds, rsi);
+
+   // "Pop" the real mode return frame so we
+   // can resume where we left off
+   rmregs.drip = *stkp++;
+   rmregs.drcs = *stkp++;
+
+   rmregs.drsp = FP_OFF(stkp);
+
+   // Call protected-mode handler
+   IRQ_Callback();
+   }
+*/
+
+
+int IRQ_SetVector
+   (
+   int vector,
+   void ( __interrupt __far *function )( void )
+   )
+
+   {
+   void far *fp;
+
+   IRQ_Callback = function;
+
+   // Save the starting real-mode and protected-mode handler addresses
+
+   // DPMI get protected mode vector */
+   Regs.w.ax = 0x0204;
+   Regs.w.bx = vector;
+   int386( 0x31, &Regs, &Regs );
+   IRQ_ProtectedModeSelector = Regs.w.cx;
+   IRQ_ProtectedModeOffset = Regs.x.edx;
+
+   // DPMI get real mode vector
+   Regs.w.ax = 0x0200;
+   Regs.w.bx = vector;
+   int386( 0x31, &Regs, &Regs );
+   IRQ_RealModeSegment = Regs.w.cx;
+   IRQ_RealModeOffset = Regs.w.dx;
+
+   // Set up callback
+   // DPMI allocate real mode callback
+   Regs.w.ax = 0x0303;
+   fp = ( void far * )callback_x;
+   SegRegs.ds   = FP_SEG( fp );
+   Regs.x.esi = FP_OFF( fp );
+   fp      = ( void _far * )&rmregs;
+   SegRegs.es   = FP_SEG( fp );
+   Regs.x.edi = FP_OFF( fp );
+   int386x( 0x31, &Regs, &Regs, &SegRegs );
+
+   IRQ_CallBackSegment = Regs.w.cx;
+   IRQ_CallBackOffset = Regs.w.dx;
+
+   if ( Regs.x.cflag != 0 )
+      {
+      return( IRQ_Error );
+      }
+
+   if ( IRQ_RealModeCode == NULL )
+      {
+      // Allocate 6 bytes of low memory for real mode interrupt handler
+      IRQ_RealModeCode = D32DosMemAlloc( 6 );
+      if ( IRQ_RealModeCode == NULL )
+         {
+         // Free callback
+         Regs.w.ax = 0x304;
+         Regs.w.cx = IRQ_CallBackSegment;
+         Regs.w.dx = IRQ_CallBackOffset;
+         int386x( 0x31, &Regs, &Regs, &SegRegs );
+
+         return( IRQ_Error );
+         }
+      }
+
+   // Poke code (to call callback) into real mode handler
+
+   // CALL FAR PTR (callback)
+   IRQ_RealModeCode[ 0 ] = '\x9A';
+   *( ( unsigned short * )&IRQ_RealModeCode[ 1 ] ) = IRQ_CallBackOffset;
+   *( ( unsigned short * )&IRQ_RealModeCode[ 3 ] ) = IRQ_CallBackSegment;
+
+   // IRET
+   IRQ_RealModeCode[ 5 ] = '\xCF';
+
+   // Install protected mode handler
+   // DPMI set protected mode vector
+   Regs.w.ax = 0x0205;
+   Regs.w.bx = vector;
+   fp = function;
+
+   Regs.w.cx  = FP_SEG( fp );
+   Regs.x.edx = FP_OFF( fp );
+   int386( 0x31, &Regs, &Regs );
+
+   // Install callback address as real mode handler
+   // DPMI set real mode vector
+   Regs.w.ax = 0x0201;
+   Regs.w.bx = vector;
+   Regs.w.cx = D32RealSeg( IRQ_RealModeCode );
+   Regs.w.dx = D32RealOff( IRQ_RealModeCode );
+   int386( 0x31, &Regs, &Regs );
+
+   return( IRQ_Ok );
+   }
+
+int IRQ_RestoreVector
+   (
+   int vector
+   )
+
+   {
+   // Restore original interrupt handlers
+   // DPMI set real mode vector
+   Regs.w.ax = 0x0201;
+   Regs.w.bx = vector;
+   Regs.w.cx = IRQ_RealModeSegment;
+   Regs.w.dx = IRQ_RealModeOffset;
+   int386( 0x31, &Regs, &Regs );
+
+   Regs.w.ax = 0x0205;
+   Regs.w.bx = vector;
+   Regs.w.cx = IRQ_ProtectedModeSelector;
+   Regs.x.edx = IRQ_ProtectedModeOffset;
+   int386( 0x31, &Regs, &Regs );
+
+   // Free callback
+   Regs.w.ax = 0x304;
+   Regs.w.cx = IRQ_CallBackSegment;
+   Regs.w.dx = IRQ_CallBackOffset;
+   int386x( 0x31, &Regs, &Regs, &SegRegs );
+
+   if ( Regs.x.cflag )
+      {
+      return( IRQ_Error );
+      }
+
+   return( IRQ_Ok );
+   }
--- /dev/null
+++ b/rott/audiolib/irq.h
@@ -1,0 +1,54 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+/**********************************************************************
+   module: IRQ.H
+
+   author: James R. Dose
+   date:   August 8, 1994
+
+   Public header for IRQ.C
+
+   (c) Copyright 1994 James R. Dose.  All Rights Reserved.
+**********************************************************************/
+
+#ifndef __IRQ_H
+#define __IRQ_H
+
+enum IRQ_ERRORS
+   {
+   IRQ_Warning = -2,
+   IRQ_Error = -1,
+   IRQ_Ok = 0,
+   };
+
+#define VALID_IRQ( irq )  ( ( ( irq ) >= 0 ) && ( ( irq ) <= 15 ) )
+
+int IRQ_SetVector
+   (
+   int vector,
+   void ( __interrupt *function )( void )
+   );
+int IRQ_RestoreVector
+   (
+   int vector
+   );
+
+
+#endif
--- /dev/null
+++ b/rott/audiolib/leetimbr.c
@@ -1,0 +1,290 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+typedef struct
+   {
+   unsigned char SAVEK[ 2 ];
+   unsigned char Level[ 2 ];
+   unsigned char Env1[ 2 ];
+   unsigned char Env2[ 2 ];
+   unsigned char Wave[ 2 ];
+   unsigned char Feedback;
+   signed   char Transpose;
+   signed   char Velocity;
+   } TIMBRE;
+
+TIMBRE ADLIB_TimbreBank[ 256 ] =
+   {
+      { { 33, 49 }, { 79, 0 }, { 242, 210 }, { 82, 115 }, { 0, 0 }, 6, 0 },
+      { { 19, 17 }, { 198, 10 }, { 242, 241 }, { 245, 245 }, { 1, 0 }, 0, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 3, 18 }, { 48, 16 }, { 246, 242 }, { 25, 244 }, { 0, 0 }, 15, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 24, 129 }, { 98, 0 }, { 243, 242 }, { 230, 246 }, { 0, 0 }, 0, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 23, 2 }, { 79, 16 }, { 242, 242 }, { 96, 114 }, { 0, 0 }, 8, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 178, 176 }, { 192, 134 }, { 159, 148 }, { 6, 15 }, { 1, 1 }, 9, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 178, 176 }, { 192, 128 }, { 159, 148 }, { 6, 15 }, { 1, 1 }, 9, 0 },
+      { { 130, 128 }, { 192, 134 }, { 145, 145 }, { 246, 246 }, { 1, 1 }, 9, 0 },
+      { { 36, 49 }, { 79, 27 }, { 242, 82 }, { 11, 11 }, { 0, 0 }, 14, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 35, 33 }, { 72, 0 }, { 149, 132 }, { 25, 25 }, { 1, 0 }, 8, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 19, 49 }, { 150, 128 }, { 254, 242 }, { 33, 148 }, { 0, 0 }, 10, 0 },
+      { { 1, 17 }, { 77, 0 }, { 242, 245 }, { 83, 116 }, { 1, 1 }, 8, 0 },
+      { { 33, 40 }, { 1, 9 }, { 148, 148 }, { 25, 9 }, { 0, 0 }, 6, 0 },
+      { { 33, 40 }, { 1, 19 }, { 148, 148 }, { 25, 9 }, { 0, 0 }, 6, 0 },
+      { { 36, 194 }, { 138, 3 }, { 250, 145 }, { 111, 248 }, { 0, 0 }, 8, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 33 }, { 26, 0 }, { 241, 246 }, { 207, 72 }, { 0, 0 }, 10, 0 },
+      { { 1, 34 }, { 29, 0 }, { 183, 196 }, { 34, 55 }, { 0, 0 }, 14, 0 },
+      { { 49, 34 }, { 30, 0 }, { 242, 241 }, { 239, 104 }, { 0, 0 }, 14, 0 },
+      { { 49, 34 }, { 30, 0 }, { 242, 245 }, { 239, 120 }, { 0, 0 }, 14, 0 },
+      { { 49, 34 }, { 30, 0 }, { 242, 245 }, { 239, 120 }, { 0, 0 }, 14, 0 },
+      { { 17, 49 }, { 5, 9 }, { 249, 241 }, { 37, 52 }, { 0, 0 }, 10, 0 },
+      { { 17, 49 }, { 5, 0 }, { 249, 241 }, { 37, 52 }, { 0, 0 }, 10, 0 },
+      { { 49, 114 }, { 138, 0 }, { 213, 97 }, { 25, 27 }, { 0, 0 }, 12, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 17, 17 }, { 150, 128 }, { 165, 245 }, { 85, 179 }, { 2, 1 }, 12, 0 },
+      { { 1, 17 }, { 156, 128 }, { 128, 240 }, { 5, 6 }, { 0, 0 }, 0, 0 },
+      { { 17, 17 }, { 150, 128 }, { 165, 245 }, { 85, 179 }, { 2, 1 }, 12, 0 },
+      { { 2, 1 }, { 153, 128 }, { 245, 246 }, { 85, 83 }, { 0, 0 }, 0, 0 },
+      { { 192, 0 }, { 13, 0 }, { 165, 212 }, { 67, 35 }, { 2, 1 }, 0, 0 },
+      { { 33, 32 }, { 88, 0 }, { 194, 97 }, { 227, 22 }, { 1, 3 }, 0, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 34 }, { 22, 0 }, { 176, 179 }, { 129, 44 }, { 0, 1 }, 12, 0 },
+      { { 49, 114 }, { 91, 131 }, { 244, 138 }, { 21, 5 }, { 0, 0 }, 0, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 33 }, { 29, 0 }, { 113, 129 }, { 174, 158 }, { 0, 0 }, 14, 0 },
+      { { 49, 97 }, { 28, 128 }, { 65, 146 }, { 11, 59 }, { 0, 0 }, 14, 0 },
+      { { 49, 241 }, { 28, 0 }, { 65, 146 }, { 11, 27 }, { 0, 0 }, 10, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 33 }, { 155, 0 }, { 97, 127 }, { 106, 10 }, { 0, 0 }, 2, 0 },
+      { { 225, 226 }, { 21, 3 }, { 113, 129 }, { 174, 158 }, { 0, 0 }, 14, 0 },
+      { { 33, 33 }, { 29, 0 }, { 113, 129 }, { 174, 158 }, { 0, 0 }, 14, 0 },
+      { { 33, 33 }, { 77, 0 }, { 84, 166 }, { 60, 28 }, { 0, 0 }, 8, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 50 }, { 79, 0 }, { 113, 82 }, { 83, 76 }, { 0, 0 }, 10, 0 },
+      { { 33, 50 }, { 79, 0 }, { 113, 82 }, { 83, 76 }, { 0, 0 }, 10, 0 },
+      { { 32, 49 }, { 78, 0 }, { 113, 82 }, { 104, 94 }, { 0, 0 }, 10, 0 },
+      { { 33, 33 }, { 75, 0 }, { 170, 143 }, { 22, 10 }, { 1, 0 }, 8, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 50, 97 }, { 154, 130 }, { 81, 162 }, { 27, 59 }, { 0, 0 }, 12, 0 },
+      { { 50, 33 }, { 192, 0 }, { 155, 114 }, { 33, 7 }, { 0, 0 }, 4, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 162 }, { 131, 141 }, { 116, 101 }, { 23, 23 }, { 0, 0 }, 7, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 225, 98 }, { 236, 0 }, { 110, 101 }, { 143, 42 }, { 0, 0 }, 14, 0 },
+      { { 50, 33 }, { 144, 0 }, { 155, 114 }, { 33, 23 }, { 0, 0 }, 4, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 245, 242 }, { 154, 128 }, { 12, 96 }, { 199, 165 }, { 0, 0 }, 13, 0 },
+      { { 98, 161 }, { 147, 0 }, { 119, 118 }, { 7, 7 }, { 0, 0 }, 11, 0 },
+      { { 34, 33 }, { 89, 8 }, { 255, 255 }, { 3, 15 }, { 2, 0 }, 0, 0 },
+      { { 33, 33 }, { 29, 0 }, { 113, 129 }, { 14, 14 }, { 0, 0 }, 14, 0 },
+      { { 34, 33 }, { 70, 128 }, { 134, 100 }, { 85, 24 }, { 0, 0 }, 0, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 113, 114 }, { 93, 0 }, { 84, 106 }, { 1, 3 }, { 0, 0 }, 0, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 0, 17 }, { 13, 128 }, { 241, 80 }, { 255, 255 }, { 0, 0 }, 6, 0 },
+      { { 33, 97 }, { 137, 3 }, { 17, 66 }, { 51, 37 }, { 0, 0 }, 10, 0 },
+      { { 0, 49 }, { 16, 128 }, { 17, 176 }, { 239, 15 }, { 0, 0 }, 10, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 164, 97 }, { 76, 16 }, { 243, 129 }, { 115, 35 }, { 1, 0 }, 4, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 1, 1 }, { 0, 0 }, { 255, 255 }, { 7, 7 }, { 0, 0 }, 7, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 1, 221 }, { 0, 0 }, { 246, 31 }, { 0, 6 }, { 2, 3 }, 12, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 36 },
+      { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 36 },
+      { { 3, 15 }, { 0, 0 }, { 251, 245 }, { 43, 11 }, { 2, 0 }, 15, 36 },
+      { { 33, 0 }, { 128, 0 }, { 255, 249 }, { 7, 7 }, { 0, 1 }, 14, 36 },
+      { { 240, 229 }, { 192, 0 }, { 255, 251 }, { 255, 240 }, { 3, 0 }, 14, 48 },
+      { { 33, 0 }, { 128, 0 }, { 255, 248 }, { 10, 25 }, { 0, 1 }, 14, 36 },
+      { { 1, 0 }, { 0, 0 }, { 250, 242 }, { 124, 4 }, { 0, 0 }, 0, 48 },
+      { { 12, 18 }, { 0, 0 }, { 246, 251 }, { 8, 71 }, { 0, 2 }, 10, 69 },
+      { { 1, 0 }, { 0, 0 }, { 250, 242 }, { 124, 4 }, { 0, 0 }, 0, 52 },
+      { { 14, 0 }, { 64, 8 }, { 118, 119 }, { 79, 24 }, { 0, 2 }, 14, 48 },
+      { { 1, 0 }, { 0, 0 }, { 250, 242 }, { 124, 4 }, { 0, 0 }, 0, 55 },
+      { { 2, 5 }, { 3, 10 }, { 180, 151 }, { 4, 247 }, { 0, 0 }, 14, 57 },
+      { { 1, 0 }, { 0, 0 }, { 250, 242 }, { 124, 4 }, { 0, 0 }, 0, 58 },
+      { { 1, 0 }, { 0, 0 }, { 250, 242 }, { 124, 4 }, { 0, 0 }, 0, 60 },
+      { { 1, 221 }, { 12, 0 }, { 246, 159 }, { 0, 2 }, { 0, 3 }, 12, 62 },
+      { { 1, 0 }, { 0, 0 }, { 250, 242 }, { 124, 4 }, { 0, 0 }, 0, 63 },
+      { { 12, 18 }, { 0, 0 }, { 246, 203 }, { 2, 67 }, { 0, 2 }, 10, 70 },
+      { { 12, 18 }, { 0, 0 }, { 246, 203 }, { 2, 19 }, { 0, 2 }, 10, 70 },
+      { { 14, 7 }, { 6, 68 }, { 248, 244 }, { 66, 228 }, { 3, 3 }, 14, 53 },
+      { { 14, 0 }, { 64, 8 }, { 150, 183 }, { 79, 24 }, { 0, 2 }, 14, 48 },
+      { { 1, 221 }, { 0, 0 }, { 246, 159 }, { 0, 2 }, { 2, 3 }, 12, 84 },
+      { { 2, 9 }, { 27, 0 }, { 245, 246 }, { 118, 214 }, { 2, 0 }, 4, 43 },
+      { { 0, 223 }, { 9, 0 }, { 246, 147 }, { 0, 67 }, { 0, 2 }, 14, 56 },
+      { { 128, 144 }, { 13, 0 }, { 248, 159 }, { 0, 4 }, { 2, 3 }, 14, 24 },
+      { { 12, 18 }, { 0, 0 }, { 246, 203 }, { 2, 67 }, { 0, 2 }, 10, 65 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 1, 2 }, { 84, 0 }, { 250, 248 }, { 141, 184 }, { 0, 0 }, 6, 48 },
+      { { 1, 2 }, { 84, 0 }, { 250, 248 }, { 141, 184 }, { 0, 0 }, 6, 51 },
+      { { 1, 2 }, { 84, 0 }, { 250, 248 }, { 141, 184 }, { 0, 0 }, 6, 54 },
+      { { 2, 4 }, { 0, 0 }, { 250, 200 }, { 191, 151 }, { 0, 0 }, 11, 42 },
+      { { 2, 4 }, { 0, 0 }, { 250, 200 }, { 191, 151 }, { 0, 0 }, 11, 39 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 14, 0 }, { 64, 8 }, { 118, 119 }, { 79, 24 }, { 0, 2 }, 14, 64 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 128, 17 }, { 0, 0 }, { 255, 111 }, { 6, 22 }, { 3, 0 }, 14, 52 },
+      { { 128, 17 }, { 0, 0 }, { 255, 79 }, { 6, 22 }, { 3, 0 }, 14, 52 },
+      { { 6, 21 }, { 63, 0 }, { 0, 247 }, { 244, 245 }, { 0, 0 }, 1, 60 },
+      { { 6, 21 }, { 63, 0 }, { 0, 247 }, { 244, 245 }, { 0, 0 }, 1, 66 },
+      { { 6, 21 }, { 63, 0 }, { 0, 247 }, { 244, 245 }, { 0, 0 }, 1, 59 },
+      { { 65, 66 }, { 69, 0 }, { 252, 105 }, { 69, 5 }, { 0, 0 }, 0, 91 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 23, 2 }, { 79, 16 }, { 242, 242 }, { 96, 114 }, { 0, 0 }, 8, 109 },
+      { { 14, 0 }, { 64, 8 }, { 118, 119 }, { 79, 24 }, { 0, 2 }, 14, 64 },
+      { { 133, 132 }, { 5, 64 }, { 249, 214 }, { 50, 165 }, { 3, 0 }, 14, 79 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 },
+      { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }
+   };
--- /dev/null
+++ b/rott/audiolib/linklist.h
@@ -1,0 +1,118 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+#ifndef __linklist_h
+#define __linklist_h
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#define NewNode(type)  ((type*)SafeMalloc(sizeof(type)))
+
+
+#define LL_CreateNewLinkedList(rootnode,type,next,prev) 			\
+   { 																				\
+   (rootnode) = NewNode(type);                            		\
+   (rootnode)->prev = (rootnode);                         		\
+   (rootnode)->next = (rootnode);                         		\
+   }
+
+
+
+#define LL_AddNode(rootnode, newnode, next, prev) 			\
+   {                                              			\
+   (newnode)->next = (rootnode);                  			\
+   (newnode)->prev = (rootnode)->prev;                	\
+   (rootnode)->prev->next = (newnode);                	\
+   (rootnode)->prev = (newnode);                      	\
+   }
+
+#define LL_TransferList(oldroot,newroot,next,prev)  \
+   {                                                \
+   if ((oldroot)->prev != (oldroot))                    \
+      {                                             \
+      (oldroot)->prev->next = (newroot);                \
+      (oldroot)->next->prev = (newroot)->prev;          \
+      (newroot)->prev->next = (oldroot)->next;          \
+      (newroot)->prev = (oldroot)->prev;                \
+      (oldroot)->next = (oldroot);                      \
+      (oldroot)->prev = (oldroot);                      \
+      }                                             \
+   }
+
+#define LL_ReverseList(root,type,next,prev)              \
+   {                                                     \
+   type *newend,*trav,*tprev;                            \
+                                                         \
+   newend = (root)->next;                                  \
+   for(trav = (root)->prev; trav != newend; trav = tprev)  \
+      {                                                  \
+      tprev = trav->prev;                                \
+      LL_MoveNode(trav,newend,next,prev);                \
+      }                                                  \
+   }
+
+
+#define LL_RemoveNode(node,next,prev) \
+   {                                  \
+   (node)->prev->next = (node)->next;     \
+   (node)->next->prev = (node)->prev;     \
+   (node)->next = (node);                 \
+   (node)->prev = (node);                 \
+   }
+
+
+#define LL_SortedInsertion(rootnode,insertnode,next,prev,type,sortparm) \
+   {                                                                    \
+   type *hoya;                                                          \
+                                                                        \
+   hoya = (rootnode)->next;                                               \
+   while((hoya != (rootnode)) && ((insertnode)->sortparm > hoya->sortparm)) \
+      {                                                                 \
+      hoya = hoya->next;                                                \
+      }                                                                 \
+   LL_AddNode(hoya,(insertnode),next,prev);                               \
+   }
+
+#define LL_MoveNode(node,newroot,next,prev) \
+   {                                        \
+   LL_RemoveNode((node),next,prev);           \
+   LL_AddNode((newroot),(node),next,prev);      \
+   }
+
+#define LL_ListEmpty(list,next,prev) \
+   (                                 \
+   ((list)->next == (list)) &&       \
+   ((list)->prev == (list))          \
+   )
+
+#define LL_Free(list)   SafeFree(list)
+#define LL_Reset(list,next,prev)    (list)->next = (list)->prev = (list)
+#define LL_New      LL_CreateNewLinkedList
+#define LL_Remove   LL_RemoveNode
+#define LL_Add      LL_AddNode
+#define LL_Empty    LL_ListEmpty
+#define LL_Move     LL_MoveNode
+
+
+#ifdef __cplusplus
+};
+#endif
+#endif
--- /dev/null
+++ b/rott/audiolib/ll_man.c
@@ -1,0 +1,173 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+/**********************************************************************
+   module: LL_MAN.C
+
+   author: James R. Dose
+   date:   January 1, 1994
+
+   Linked list management routines.
+
+   (c) Copyright 1994 James R. Dose.  All Rights Reserved.
+**********************************************************************/
+
+#define LOCKMEMORY
+
+#include <stddef.h>
+#include "ll_man.h"
+
+#ifdef LOCKMEMORY
+#include "dpmi.h"
+#endif
+
+#define OFFSET( structure, offset ) \
+   ( *( ( char ** )&( structure )[ offset ] ) )
+
+
+/**********************************************************************
+
+   Memory locked functions:
+
+**********************************************************************/
+
+
+#define LL_LockStart LL_AddNode
+
+
+void LL_AddNode
+   (
+   char *item,
+   char **head,
+   char **tail,
+   int next,
+   int prev
+   )
+
+   {
+   OFFSET( item, prev ) = NULL;
+   OFFSET( item, next ) = *head;
+
+   if ( *head )
+      {
+      OFFSET( *head, prev ) = item;
+      }
+   else
+      {
+      *tail = item;
+      }
+
+   *head = item;
+   }
+
+void LL_RemoveNode
+   (
+   char *item,
+   char **head,
+   char **tail,
+   int next,
+   int prev
+   )
+
+   {
+   if ( OFFSET( item, prev ) == NULL )
+      {
+      *head = OFFSET( item, next );
+      }
+   else
+      {
+      OFFSET( OFFSET( item, prev ), next ) = OFFSET( item, next );
+      }
+
+   if ( OFFSET( item, next ) == NULL )
+      {
+      *tail = OFFSET( item, prev );
+      }
+   else
+      {
+      OFFSET( OFFSET( item, next ), prev ) = OFFSET( item, prev );
+      }
+
+   OFFSET( item, next ) = NULL;
+   OFFSET( item, prev ) = NULL;
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: LL_LockEnd
+
+   Used for determining the length of the functions to lock in memory.
+---------------------------------------------------------------------*/
+
+static void LL_LockEnd
+   (
+   void
+   )
+
+   {
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: LL_UnlockMemory
+
+   Unlocks all neccessary data.
+---------------------------------------------------------------------*/
+
+void LL_UnlockMemory
+   (
+   void
+   )
+
+   {
+#ifdef LOCKMEMORY
+
+   DPMI_UnlockMemoryRegion( LL_LockStart, LL_LockEnd );
+
+#endif
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: LL_LockMemory
+
+   Locks all neccessary data.
+---------------------------------------------------------------------*/
+
+int LL_LockMemory
+   (
+   void
+   )
+
+   {
+
+#ifdef LOCKMEMORY
+
+   int status;
+
+   status = DPMI_LockMemoryRegion( LL_LockStart, LL_LockEnd );
+   if ( status != DPMI_Ok )
+      {
+      return( LL_Error );
+      }
+
+#endif
+
+   return( LL_Ok );
+   }
--- /dev/null
+++ b/rott/audiolib/ll_man.h
@@ -1,0 +1,76 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+/**********************************************************************
+   module: LL_MAN.H
+
+   author: James R. Dose
+   date:   February 4, 1994
+
+   Public header for LL_MAN.C.  Linked list management routines.
+
+   (c) Copyright 1994 James R. Dose.  All Rights Reserved.
+**********************************************************************/
+
+#ifndef __LL_MAN_H
+#define __LL_MAN_H
+
+enum LL_Errors
+   {
+   LL_Warning = -2,
+   LL_Error   = -1,
+   LL_Ok      = 0
+   };
+
+typedef struct list
+   {
+   void *start;
+   void *end;
+   } list;
+
+void LL_AddNode( char *node, char **head, char **tail, int next, int prev );
+void LL_RemoveNode( char *node, char **head, char **tail, int next, int prev );
+void LL_UnlockMemory( void );
+int  LL_LockMemory( void );
+
+#define LL_AddToHead( type, listhead, node )         \
+    LL_AddNode( ( char * )( node ),                  \
+                ( char ** )&( ( listhead )->start ), \
+                ( char ** )&( ( listhead )->end ),   \
+                ( int )&( ( type * ) 0 )->next,      \
+                ( int )&( ( type * ) 0 )->prev )
+
+#define LL_AddToTail( type, listhead, node )         \
+    LL_AddNode( ( char * )( node ),                  \
+                ( char ** )&( ( listhead )->end ),   \
+                ( char ** )&( ( listhead )->start ), \
+                ( int )&( ( type * ) 0 )->prev,      \
+                ( int )&( ( type * ) 0 )->next )
+
+#define LL_Remove( type, listhead, node )               \
+    LL_RemoveNode( ( char * )( node ),                  \
+                   ( char ** )&( ( listhead )->start ), \
+                   ( char ** )&( ( listhead )->end ),   \
+                   ( int )&( ( type * ) 0 )->next,      \
+                   ( int )&( ( type * ) 0 )->prev )
+
+#define LL_NextNode( node )     ( ( node )->next )
+#define LL_PreviousNode( node ) ( ( node )->prev )
+
+#endif
--- /dev/null
+++ b/rott/audiolib/midi.c
@@ -1,0 +1,2265 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+/**********************************************************************
+   module: MIDI.C
+
+   author: James R. Dose
+   date:   May 25, 1994
+
+   Midi song file playback routines.
+
+   (c) Copyright 1994 James R. Dose.  All Rights Reserved.
+**********************************************************************/
+
+#include <stdlib.h>
+#include <time.h>
+#include <dos.h>
+#include <string.h>
+#include "sndcards.h"
+#include "interrup.h"
+#include "dpmi.h"
+#include "standard.h"
+#include "task_man.h"
+#include "ll_man.h"
+#include "usrhooks.h"
+#include "music.h"
+#include "_midi.h"
+#include "midi.h"
+#include "debugio.h"
+
+extern int MUSIC_SoundDevice;
+
+static const int _MIDI_CommandLengths[ NUM_MIDI_CHANNELS ] =
+   {
+   0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 1, 1, 2, 0
+   };
+
+static int cdecl ( *_MIDI_RerouteFunctions[ NUM_MIDI_CHANNELS ] )
+   (
+   int event,
+   int c1,
+   int c2
+   ) = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+         NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL };
+
+static track *_MIDI_TrackPtr = NULL;
+static int    _MIDI_TrackMemSize;
+static int    _MIDI_NumTracks;
+
+static int _MIDI_SongActive = FALSE;
+static int _MIDI_SongLoaded = FALSE;
+static int _MIDI_Loop = FALSE;
+
+static task *_MIDI_PlayRoutine = NULL;
+
+static int  _MIDI_Division;
+static int  _MIDI_Tick    = 0;
+static int  _MIDI_Beat    = 1;
+static int  _MIDI_Measure = 1;
+static unsigned _MIDI_Time;
+static int  _MIDI_BeatsPerMeasure;
+static int  _MIDI_TicksPerBeat;
+static int  _MIDI_TimeBase;
+static long _MIDI_FPSecondsPerTick;
+static unsigned _MIDI_TotalTime;
+static int  _MIDI_TotalTicks;
+static int  _MIDI_TotalBeats;
+static int  _MIDI_TotalMeasures;
+
+static unsigned long _MIDI_PositionInTicks;
+
+static int  _MIDI_Context;
+
+static int _MIDI_ActiveTracks;
+static int _MIDI_TotalVolume = MIDI_MaxVolume;
+
+static int _MIDI_ChannelVolume[ NUM_MIDI_CHANNELS ];
+static int _MIDI_UserChannelVolume[ NUM_MIDI_CHANNELS ] =
+   {
+   256, 256, 256, 256, 256, 256, 256, 256,
+   256, 256, 256, 256, 256, 256, 256, 256
+   };
+
+static midifuncs *_MIDI_Funcs = NULL;
+
+static int Reset = FALSE;
+
+int MIDI_Tempo = 120;
+
+char MIDI_PatchMap[ 128 ];
+
+
+/**********************************************************************
+
+   Memory locked functions:
+
+**********************************************************************/
+
+
+#define MIDI_LockStart _MIDI_ReadNumber
+
+
+/*---------------------------------------------------------------------
+   Function: _MIDI_ReadNumber
+
+   Reads a variable length number from a MIDI track.
+---------------------------------------------------------------------*/
+
+static long _MIDI_ReadNumber
+   (
+   void *from,
+   size_t size
+   )
+
+   {
+   unsigned char *FromPtr;
+   long          value;
+
+   if ( size > 4 )
+      {
+      size = 4;
+      }
+
+   FromPtr = ( unsigned char * )from;
+
+   value = 0;
+   while( size-- )
+      {
+      value <<= 8;
+      value += *FromPtr++;
+      }
+
+   return( value );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: _MIDI_ReadDelta
+
+   Reads a variable length encoded delta delay time from the MIDI data.
+---------------------------------------------------------------------*/
+
+static long _MIDI_ReadDelta
+   (
+   track *ptr
+   )
+
+   {
+   long          value;
+   unsigned char c;
+
+   GET_NEXT_EVENT( ptr, value );
+
+   if ( value & 0x80 )
+      {
+      value &= 0x7f;
+      do
+         {
+         GET_NEXT_EVENT( ptr, c );
+         value = ( value << 7 ) + ( c & 0x7f );
+         }
+      while ( c & 0x80 );
+      }
+
+   return( value );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: _MIDI_ResetTracks
+
+   Sets the track pointers to the beginning of the song.
+---------------------------------------------------------------------*/
+
+static void _MIDI_ResetTracks
+   (
+   void
+   )
+
+   {
+   int    i;
+   track *ptr;
+
+   _MIDI_Tick = 0;
+   _MIDI_Beat = 1;
+   _MIDI_Measure = 1;
+   _MIDI_Time = 0;
+   _MIDI_BeatsPerMeasure = 4;
+   _MIDI_TicksPerBeat = _MIDI_Division;
+   _MIDI_TimeBase = 4;
+
+   _MIDI_PositionInTicks = 0;
+   _MIDI_ActiveTracks    = 0;
+   _MIDI_Context         = 0;
+
+   ptr = _MIDI_TrackPtr;
+   for( i = 0; i < _MIDI_NumTracks; i++ )
+      {
+      ptr->pos                    = ptr->start;
+      ptr->delay                  = _MIDI_ReadDelta( ptr );
+      ptr->active                 = ptr->EMIDI_IncludeTrack;
+      ptr->RunningStatus          = 0;
+      ptr->currentcontext         = 0;
+      ptr->context[ 0 ].loopstart = ptr->start;
+      ptr->context[ 0 ].loopcount = 0;
+
+      if ( ptr->active )
+         {
+         _MIDI_ActiveTracks++;
+         }
+
+      ptr++;
+      }
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: _MIDI_AdvanceTick
+
+   Increment tick counters.
+---------------------------------------------------------------------*/
+
+static void _MIDI_AdvanceTick
+   (
+   void
+   )
+
+   {
+   _MIDI_PositionInTicks++;
+   _MIDI_Time += _MIDI_FPSecondsPerTick;
+
+   _MIDI_Tick++;
+   while( _MIDI_Tick > _MIDI_TicksPerBeat )
+      {
+      _MIDI_Tick -= _MIDI_TicksPerBeat;
+      _MIDI_Beat++;
+      }
+   while( _MIDI_Beat > _MIDI_BeatsPerMeasure )
+      {
+      _MIDI_Beat -= _MIDI_BeatsPerMeasure;
+      _MIDI_Measure++;
+      }
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: _MIDI_SysEx
+
+   Interpret SysEx Event.
+---------------------------------------------------------------------*/
+
+static void _MIDI_SysEx
+   (
+   track *Track
+   )
+
+   {
+   int length;
+
+   length = _MIDI_ReadDelta( Track );
+   Track->pos += length;
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: _MIDI_MetaEvent
+
+   Interpret Meta Event.
+---------------------------------------------------------------------*/
+
+static void _MIDI_MetaEvent
+   (
+   track *Track
+   )
+
+   {
+   int   command;
+   int   length;
+   int   denominator;
+   long  tempo;
+
+   GET_NEXT_EVENT( Track, command );
+   GET_NEXT_EVENT( Track, length );
+
+   switch( command )
+      {
+      case MIDI_END_OF_TRACK :
+         Track->active = FALSE;
+
+         _MIDI_ActiveTracks--;
+         break;
+
+      case MIDI_TEMPO_CHANGE :
+         tempo = 60000000L / _MIDI_ReadNumber( Track->pos, 3 );
+         MIDI_SetTempo( tempo );
+         break;
+
+      case MIDI_TIME_SIGNATURE :
+         if ( ( _MIDI_Tick > 0 ) || ( _MIDI_Beat > 1 ) )
+            {
+            _MIDI_Measure++;
+            }
+
+         _MIDI_Tick = 0;
+         _MIDI_Beat = 1;
+
+         _MIDI_BeatsPerMeasure = (int)*Track->pos;
+         denominator = (int)*( Track->pos + 1 );
+         _MIDI_TimeBase = 1;
+         while( denominator > 0 )
+            {
+            _MIDI_TimeBase += _MIDI_TimeBase;
+            denominator--;
+            }
+         _MIDI_TicksPerBeat = ( _MIDI_Division * 4 ) / _MIDI_TimeBase;
+         break;
+      }
+
+   Track->pos += length;
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: _MIDI_InterpretControllerInfo
+
+   Interprets the MIDI controller info.
+---------------------------------------------------------------------*/
+
+static int _MIDI_InterpretControllerInfo
+   (
+   track *Track,
+   int   TimeSet,
+   int   channel,
+   int   c1,
+   int   c2
+   )
+
+   {
+   track *trackptr;
+   int tracknum;
+   int loopcount;
+
+   switch( c1 )
+      {
+      case MIDI_MONO_MODE_ON :
+         Track->pos++;
+         break;
+
+      case MIDI_VOLUME :
+         if ( !Track->EMIDI_VolumeChange )
+            {
+            _MIDI_SetChannelVolume( channel, c2 );
+            }
+         break;
+
+      case EMIDI_INCLUDE_TRACK :
+      case EMIDI_EXCLUDE_TRACK :
+         break;
+
+      case EMIDI_PROGRAM_CHANGE :
+         if ( Track->EMIDI_ProgramChange )
+            {
+            _MIDI_Funcs->ProgramChange( channel, MIDI_PatchMap[ c2 & 0x7f ] );
+            }
+         break;
+
+      case EMIDI_VOLUME_CHANGE :
+         if ( Track->EMIDI_VolumeChange )
+            {
+            _MIDI_SetChannelVolume( channel, c2 );
+            }
+         break;
+
+      case EMIDI_CONTEXT_START :
+         break;
+
+      case EMIDI_CONTEXT_END :
+         if ( ( Track->currentcontext == _MIDI_Context ) ||
+            ( _MIDI_Context < 0 ) ||
+            ( Track->context[ _MIDI_Context ].pos == NULL ) )
+            {
+            break;
+            }
+
+         Track->currentcontext = _MIDI_Context;
+         Track->context[ 0 ].loopstart = Track->context[ _MIDI_Context ].loopstart;
+         Track->context[ 0 ].loopcount = Track->context[ _MIDI_Context ].loopcount;
+         Track->pos           = Track->context[ _MIDI_Context ].pos;
+         Track->RunningStatus = Track->context[ _MIDI_Context ].RunningStatus;
+
+         if ( TimeSet )
+            {
+            break;
+            }
+
+         _MIDI_Time             = Track->context[ _MIDI_Context ].time;
+         _MIDI_FPSecondsPerTick = Track->context[ _MIDI_Context ].FPSecondsPerTick;
+         _MIDI_Tick             = Track->context[ _MIDI_Context ].tick;
+         _MIDI_Beat             = Track->context[ _MIDI_Context ].beat;
+         _MIDI_Measure          = Track->context[ _MIDI_Context ].measure;
+         _MIDI_BeatsPerMeasure  = Track->context[ _MIDI_Context ].BeatsPerMeasure;
+         _MIDI_TicksPerBeat     = Track->context[ _MIDI_Context ].TicksPerBeat;
+         _MIDI_TimeBase         = Track->context[ _MIDI_Context ].TimeBase;
+         TimeSet = TRUE;
+         break;
+
+      case EMIDI_LOOP_START :
+      case EMIDI_SONG_LOOP_START :
+         if ( c2 == 0 )
+            {
+            loopcount = EMIDI_INFINITE;
+            }
+         else
+            {
+            loopcount = c2;
+            }
+
+         if ( c1 == EMIDI_SONG_LOOP_START )
+            {
+            trackptr = _MIDI_TrackPtr;
+            tracknum = _MIDI_NumTracks;
+            }
+         else
+            {
+            trackptr = Track;
+            tracknum = 1;
+            }
+
+         while( tracknum > 0 )
+            {
+            trackptr->context[ 0 ].loopcount        = loopcount;
+            trackptr->context[ 0 ].pos              = trackptr->pos;
+            trackptr->context[ 0 ].loopstart        = trackptr->pos;
+            trackptr->context[ 0 ].RunningStatus    = trackptr->RunningStatus;
+            trackptr->context[ 0 ].active           = trackptr->active;
+            trackptr->context[ 0 ].delay            = trackptr->delay;
+            trackptr->context[ 0 ].time             = _MIDI_Time;
+            trackptr->context[ 0 ].FPSecondsPerTick = _MIDI_FPSecondsPerTick;
+            trackptr->context[ 0 ].tick             = _MIDI_Tick;
+            trackptr->context[ 0 ].beat             = _MIDI_Beat;
+            trackptr->context[ 0 ].measure          = _MIDI_Measure;
+            trackptr->context[ 0 ].BeatsPerMeasure  = _MIDI_BeatsPerMeasure;
+            trackptr->context[ 0 ].TicksPerBeat     = _MIDI_TicksPerBeat;
+            trackptr->context[ 0 ].TimeBase         = _MIDI_TimeBase;
+            trackptr++;
+            tracknum--;
+            }
+         break;
+
+      case EMIDI_LOOP_END :
+      case EMIDI_SONG_LOOP_END :
+         if ( ( c2 != EMIDI_END_LOOP_VALUE ) ||
+            ( Track->context[ 0 ].loopstart == NULL ) ||
+            ( Track->context[ 0 ].loopcount == 0 ) )
+            {
+            break;
+            }
+
+         if ( c1 == EMIDI_SONG_LOOP_END )
+            {
+            trackptr = _MIDI_TrackPtr;
+            tracknum = _MIDI_NumTracks;
+            _MIDI_ActiveTracks = 0;
+            }
+         else
+            {
+            trackptr = Track;
+            tracknum = 1;
+            _MIDI_ActiveTracks--;
+            }
+
+         while( tracknum > 0 )
+            {
+            if ( trackptr->context[ 0 ].loopcount != EMIDI_INFINITE )
+               {
+               trackptr->context[ 0 ].loopcount--;
+               }
+
+            trackptr->pos           = trackptr->context[ 0 ].loopstart;
+            trackptr->RunningStatus = trackptr->context[ 0 ].RunningStatus;
+            trackptr->delay         = trackptr->context[ 0 ].delay;
+            trackptr->active        = trackptr->context[ 0 ].active;
+            if ( trackptr->active )
+               {
+               _MIDI_ActiveTracks++;
+               }
+
+            if ( !TimeSet )
+               {
+               _MIDI_Time             = trackptr->context[ 0 ].time;
+               _MIDI_FPSecondsPerTick = trackptr->context[ 0 ].FPSecondsPerTick;
+               _MIDI_Tick             = trackptr->context[ 0 ].tick;
+               _MIDI_Beat             = trackptr->context[ 0 ].beat;
+               _MIDI_Measure          = trackptr->context[ 0 ].measure;
+               _MIDI_BeatsPerMeasure  = trackptr->context[ 0 ].BeatsPerMeasure;
+               _MIDI_TicksPerBeat     = trackptr->context[ 0 ].TicksPerBeat;
+               _MIDI_TimeBase         = trackptr->context[ 0 ].TimeBase;
+               TimeSet = TRUE;
+               }
+
+            trackptr++;
+            tracknum--;
+            }
+         break;
+
+      default :
+         if ( _MIDI_Funcs->ControlChange )
+            {
+            _MIDI_Funcs->ControlChange( channel, c1, c2 );
+            }
+      }
+
+   return TimeSet;
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: _MIDI_ServiceRoutine
+
+   Task that interperates the MIDI data.
+---------------------------------------------------------------------*/
+// NOTE: We have to use a stack frame here because of a strange bug
+// that occurs with Watcom.  This means that we cannot access Task!
+//Turned off to test if it works with Watcom 10a
+//#pragma aux _MIDI_ServiceRoutine frame;
+/*
+static void test
+   (
+   task *Task
+   )
+   {
+   _MIDI_ServiceRoutine( Task );
+   _MIDI_ServiceRoutine( Task );
+   _MIDI_ServiceRoutine( Task );
+   _MIDI_ServiceRoutine( Task );
+   }
+*/
+static void _MIDI_ServiceRoutine
+   (
+   task *Task
+   )
+
+   {
+   int   event;
+   int   channel;
+   int   command;
+   track *Track;
+   int   tracknum;
+   int   status;
+   int   c1;
+   int   c2;
+   int   TimeSet = FALSE;
+
+   if ( !_MIDI_SongActive )
+      {
+      return;
+      }
+
+   Track = _MIDI_TrackPtr;
+   tracknum = 0;
+   while( tracknum < _MIDI_NumTracks )
+      {
+      while ( ( Track->active ) && ( Track->delay == 0 ) )
+         {
+         GET_NEXT_EVENT( Track, event );
+
+         if ( GET_MIDI_COMMAND( event ) == MIDI_SPECIAL )
+            {
+            switch( event )
+               {
+               case MIDI_SYSEX :
+               case MIDI_SYSEX_CONTINUE :
+                  _MIDI_SysEx( Track );
+                  break;
+
+               case MIDI_META_EVENT :
+                  _MIDI_MetaEvent( Track );
+                  break;
+               }
+
+            if ( Track->active )
+               {
+               Track->delay = _MIDI_ReadDelta( Track );
+               }
+
+            continue;
+            }
+
+         if ( event & MIDI_RUNNING_STATUS )
+            {
+            Track->RunningStatus = event;
+            }
+         else
+            {
+            event = Track->RunningStatus;
+            Track->pos--;
+            }
+
+         channel = GET_MIDI_CHANNEL( event );
+         command = GET_MIDI_COMMAND( event );
+
+         if ( _MIDI_CommandLengths[ command ] > 0 )
+            {
+            GET_NEXT_EVENT( Track, c1 );
+            if ( _MIDI_CommandLengths[ command ] > 1 )
+               {
+               GET_NEXT_EVENT( Track, c2 );
+               }
+            }
+
+         if ( _MIDI_RerouteFunctions[ channel ] != NULL )
+            {
+            status = _MIDI_RerouteFunctions[ channel ]( event, c1, c2 );
+
+            if ( status == MIDI_DONT_PLAY )
+               {
+               Track->delay = _MIDI_ReadDelta( Track );
+               continue;
+               }
+            }
+
+         switch ( command )
+            {
+            case MIDI_NOTE_OFF :
+               if ( _MIDI_Funcs->NoteOff )
+                  {
+                  _MIDI_Funcs->NoteOff( channel, c1, c2 );
+                  }
+               break;
+
+            case MIDI_NOTE_ON :
+               if ( _MIDI_Funcs->NoteOn )
+                  {
+                  _MIDI_Funcs->NoteOn( channel, c1, c2 );
+                  }
+               break;
+
+            case MIDI_POLY_AFTER_TCH :
+               if ( _MIDI_Funcs->PolyAftertouch )
+                  {
+                  _MIDI_Funcs->PolyAftertouch( channel, c1, c2 );
+                  }
+               break;
+
+            case MIDI_CONTROL_CHANGE :
+               TimeSet = _MIDI_InterpretControllerInfo( Track, TimeSet,
+                  channel, c1, c2 );
+               break;
+
+            case MIDI_PROGRAM_CHANGE :
+               if ( ( _MIDI_Funcs->ProgramChange ) &&
+                  ( !Track->EMIDI_ProgramChange ) )
+                  {
+                  _MIDI_Funcs->ProgramChange( channel, MIDI_PatchMap[ c1 & 0x7f ] );
+                  }
+               break;
+
+            case MIDI_AFTER_TOUCH :
+               if ( _MIDI_Funcs->ChannelAftertouch )
+                  {
+                  _MIDI_Funcs->ChannelAftertouch( channel, c1 );
+                  }
+               break;
+
+            case MIDI_PITCH_BEND :
+               if ( _MIDI_Funcs->PitchBend )
+                  {
+                  _MIDI_Funcs->PitchBend( channel, c1, c2 );
+                  }
+               break;
+
+            default :
+               break;
+            }
+
+         Track->delay = _MIDI_ReadDelta( Track );
+         }
+
+      Track->delay--;
+      Track++;
+      tracknum++;
+
+      if ( _MIDI_ActiveTracks == 0 )
+         {
+         _MIDI_ResetTracks();
+         if ( _MIDI_Loop )
+            {
+            tracknum = 0;
+            Track = _MIDI_TrackPtr;
+            }
+         else
+            {
+            _MIDI_SongActive = FALSE;
+            break;
+            }
+         }
+      }
+
+   _MIDI_AdvanceTick();
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: _MIDI_SendControlChange
+
+   Sends a control change to the proper device
+---------------------------------------------------------------------*/
+
+static int _MIDI_SendControlChange
+   (
+   int channel,
+   int c1,
+   int c2
+   )
+
+   {
+   int status;
+
+   if ( _MIDI_RerouteFunctions[ channel ] != NULL )
+      {
+      status = _MIDI_RerouteFunctions[ channel ]( 0xB0 + channel,
+         c1, c2 );
+      if ( status == MIDI_DONT_PLAY )
+         {
+         return( MIDI_Ok );
+         }
+      }
+
+   if ( _MIDI_Funcs == NULL )
+      {
+      return( MIDI_Error );
+      }
+
+   if ( _MIDI_Funcs->ControlChange == NULL )
+      {
+      return( MIDI_Error );
+      }
+
+   _MIDI_Funcs->ControlChange( channel, c1, c2 );
+
+   return( MIDI_Ok );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MIDI_RerouteMidiChannel
+
+   Sets callback function to reroute MIDI commands from specified
+   function.
+---------------------------------------------------------------------*/
+
+void MIDI_RerouteMidiChannel
+   (
+   int channel,
+   int cdecl ( *function )( int event, int c1, int c2 )
+   )
+
+   {
+   if ( ( channel >= 1 ) && ( channel <= 16 ) )
+      {
+      _MIDI_RerouteFunctions[ channel - 1 ] = function;
+      }
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MIDI_AllNotesOff
+
+   Sends all notes off commands on all midi channels.
+---------------------------------------------------------------------*/
+
+int MIDI_AllNotesOff
+   (
+   void
+   )
+
+   {
+   int channel;
+
+   for( channel = 0; channel < NUM_MIDI_CHANNELS; channel++ )
+      {
+      _MIDI_SendControlChange( channel, 0x40, 0 );
+      _MIDI_SendControlChange( channel, MIDI_ALL_NOTES_OFF, 0 );
+      _MIDI_SendControlChange( channel, 0x78, 0 );
+      }
+
+   return( MIDI_Ok );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: _MIDI_SetChannelVolume
+
+   Sets the volume of the specified midi channel.
+---------------------------------------------------------------------*/
+
+static void _MIDI_SetChannelVolume
+   (
+   int channel,
+   int volume
+   )
+
+   {
+   int status;
+   int remotevolume;
+
+   _MIDI_ChannelVolume[ channel ] = volume;
+
+   if ( _MIDI_RerouteFunctions[ channel ] != NULL )
+      {
+      remotevolume = volume * _MIDI_TotalVolume;
+      remotevolume *= _MIDI_UserChannelVolume[ channel ];
+      remotevolume /= MIDI_MaxVolume;
+      remotevolume >>= 8;
+
+      status = _MIDI_RerouteFunctions[ channel ]( 0xB0 + channel,
+         MIDI_VOLUME, remotevolume );
+      if ( status == MIDI_DONT_PLAY )
+         {
+         return;
+         }
+      }
+
+   if ( _MIDI_Funcs == NULL )
+      {
+      return;
+      }
+
+   if ( _MIDI_Funcs->ControlChange == NULL )
+      {
+      return;
+      }
+
+   // For user volume
+   volume *= _MIDI_UserChannelVolume[ channel ];
+
+   if ( _MIDI_Funcs->SetVolume == NULL )
+      {
+      volume *= _MIDI_TotalVolume;
+      volume /= MIDI_MaxVolume;
+      }
+
+   // For user volume
+   volume >>= 8;
+
+   _MIDI_Funcs->ControlChange( channel, MIDI_VOLUME, volume );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MIDI_SetUserChannelVolume
+
+   Sets the volume of the specified midi channel.
+---------------------------------------------------------------------*/
+
+void MIDI_SetUserChannelVolume
+   (
+   int channel,
+   int volume
+   )
+
+   {
+   // Convert channel from 1-16 to 0-15
+   channel--;
+
+   volume = max( 0, volume );
+   volume = min( volume, 256 );
+
+   if ( ( channel >= 0 ) && ( channel < NUM_MIDI_CHANNELS ) )
+      {
+      _MIDI_UserChannelVolume[ channel ] = volume;
+      _MIDI_SetChannelVolume( channel, _MIDI_ChannelVolume[ channel ] );
+      }
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MIDI_ResetUserChannelVolume
+
+   Sets the volume of the specified midi channel.
+---------------------------------------------------------------------*/
+
+void MIDI_ResetUserChannelVolume
+   (
+   void
+   )
+
+   {
+   int channel;
+
+   for( channel = 0; channel < NUM_MIDI_CHANNELS; channel++ )
+      {
+      _MIDI_UserChannelVolume[ channel ] = 256;
+      }
+
+   _MIDI_SendChannelVolumes();
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: _MIDI_SendChannelVolumes
+
+   Sets the volume on all the midi channels.
+---------------------------------------------------------------------*/
+
+static void _MIDI_SendChannelVolumes
+   (
+   void
+   )
+
+   {
+   int channel;
+
+   for( channel = 0; channel < NUM_MIDI_CHANNELS; channel++ )
+      {
+      _MIDI_SetChannelVolume( channel, _MIDI_ChannelVolume[ channel ] );
+      }
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MIDI_Reset
+
+   Resets the MIDI device to General Midi defaults.
+---------------------------------------------------------------------*/
+
+int MIDI_Reset
+   (
+   void
+   )
+
+   {
+   int channel;
+   long time;
+   unsigned flags;
+
+   MIDI_AllNotesOff();
+
+   flags = DisableInterrupts();
+   _enable();
+   time = clock() + CLOCKS_PER_SEC/24;
+   while(clock() < time)
+      ;
+
+   RestoreInterrupts( flags );
+
+   for( channel = 0; channel < NUM_MIDI_CHANNELS; channel++ )
+      {
+      _MIDI_SendControlChange( channel, MIDI_RESET_ALL_CONTROLLERS, 0 );
+      _MIDI_SendControlChange( channel, MIDI_RPN_MSB, MIDI_PITCHBEND_MSB );
+      _MIDI_SendControlChange( channel, MIDI_RPN_LSB, MIDI_PITCHBEND_LSB );
+      _MIDI_SendControlChange( channel, MIDI_DATAENTRY_MSB, 2 ); /* Pitch Bend Sensitivity MSB */
+      _MIDI_SendControlChange( channel, MIDI_DATAENTRY_LSB, 0 ); /* Pitch Bend Sensitivity LSB */
+      _MIDI_ChannelVolume[ channel ] = GENMIDI_DefaultVolume;
+      }
+
+   _MIDI_SendChannelVolumes();
+
+   Reset = TRUE;
+
+   return( MIDI_Ok );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MIDI_SetVolume
+
+   Sets the total volume of the music.
+---------------------------------------------------------------------*/
+
+int MIDI_SetVolume
+   (
+   int volume
+   )
+
+   {
+   int i;
+
+   if ( _MIDI_Funcs == NULL )
+      {
+      return( MIDI_NullMidiModule );
+      }
+
+   volume = min( MIDI_MaxVolume, volume );
+   volume = max( 0, volume );
+
+   _MIDI_TotalVolume = volume;
+
+   if ( _MIDI_Funcs->SetVolume )
+      {
+      _MIDI_Funcs->SetVolume( volume );
+
+      for( i = 0; i < NUM_MIDI_CHANNELS; i++ )
+         {
+         if ( _MIDI_RerouteFunctions[ i ] != NULL )
+            {
+            _MIDI_SetChannelVolume( i, _MIDI_ChannelVolume[ i ] );
+            }
+         }
+      }
+   else
+      {
+      _MIDI_SendChannelVolumes();
+      }
+
+   return( MIDI_Ok );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MIDI_GetVolume
+
+   Returns the total volume of the music.
+---------------------------------------------------------------------*/
+
+int MIDI_GetVolume
+   (
+   void
+   )
+
+   {
+   int volume;
+
+   if ( _MIDI_Funcs == NULL )
+      {
+      return( MIDI_NullMidiModule );
+      }
+
+   if ( _MIDI_Funcs->GetVolume )
+      {
+      volume = _MIDI_Funcs->GetVolume();
+      }
+   else
+      {
+      volume = _MIDI_TotalVolume;
+      }
+
+   return( volume );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MIDI_SetContext
+
+   Sets the song context.
+---------------------------------------------------------------------*/
+
+void MIDI_SetContext
+   (
+   int context
+   )
+
+   {
+   if ( ( context > 0 ) && ( context < EMIDI_NUM_CONTEXTS ) )
+      {
+      _MIDI_Context = context;
+      }
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MIDI_GetContext
+
+   Returns the current song context.
+---------------------------------------------------------------------*/
+
+int MIDI_GetContext
+   (
+   void
+   )
+
+   {
+   return _MIDI_Context;
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MIDI_SetLoopFlag
+
+   Sets whether the song should loop when finished or not.
+---------------------------------------------------------------------*/
+
+void MIDI_SetLoopFlag
+   (
+   int loopflag
+   )
+
+   {
+   _MIDI_Loop = loopflag;
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MIDI_ContinueSong
+
+   Continues playback of a paused song.
+---------------------------------------------------------------------*/
+
+void MIDI_ContinueSong
+   (
+   void
+   )
+
+   {
+   if ( _MIDI_SongLoaded )
+      {
+      _MIDI_SongActive = TRUE;
+      }
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MIDI_PauseSong
+
+   Pauses playback of the current song.
+---------------------------------------------------------------------*/
+
+void MIDI_PauseSong
+   (
+   void
+   )
+
+   {
+   if ( _MIDI_SongLoaded )
+      {
+      _MIDI_SongActive = FALSE;
+      MIDI_AllNotesOff();
+      }
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MIDI_SongPlaying
+
+   Returns whether a song is playing or not.
+---------------------------------------------------------------------*/
+
+int MIDI_SongPlaying
+   (
+   void
+   )
+
+   {
+   return( _MIDI_SongActive );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MIDI_SetMidiFuncs
+
+   Selects the routines that send the MIDI data to the music device.
+---------------------------------------------------------------------*/
+
+void MIDI_SetMidiFuncs
+   (
+   midifuncs *funcs
+   )
+
+   {
+   _MIDI_Funcs = funcs;
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MIDI_StopSong
+
+   Stops playback of the currently playing song.
+---------------------------------------------------------------------*/
+
+void MIDI_StopSong
+   (
+   void
+   )
+
+   {
+   if ( _MIDI_SongLoaded )
+      {
+      TS_Terminate( _MIDI_PlayRoutine );
+
+      _MIDI_PlayRoutine = NULL;
+      _MIDI_SongActive = FALSE;
+      _MIDI_SongLoaded = FALSE;
+
+      MIDI_Reset();
+      _MIDI_ResetTracks();
+
+      if ( _MIDI_Funcs->ReleasePatches )
+         {
+         _MIDI_Funcs->ReleasePatches();
+         }
+
+      DPMI_UnlockMemory( _MIDI_TrackPtr, _MIDI_TrackMemSize );
+      USRHOOKS_FreeMem( _MIDI_TrackPtr );
+
+      _MIDI_TrackPtr     = NULL;
+      _MIDI_NumTracks    = 0;
+      _MIDI_TrackMemSize = 0;
+
+      _MIDI_TotalTime     = 0;
+      _MIDI_TotalTicks    = 0;
+      _MIDI_TotalBeats    = 0;
+      _MIDI_TotalMeasures = 0;
+      }
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MIDI_PlaySong
+
+   Begins playback of a MIDI song.
+---------------------------------------------------------------------*/
+
+int MIDI_PlaySong
+   (
+   unsigned char *song,
+   int loopflag
+   )
+
+   {
+   int    numtracks;
+   int    format;
+   long   headersize;
+   long   tracklength;
+   track *CurrentTrack;
+   unsigned char *ptr;
+   int    status;
+
+   if ( _MIDI_SongLoaded )
+      {
+      MIDI_StopSong();
+      }
+
+   _MIDI_Loop = loopflag;
+
+   if ( _MIDI_Funcs == NULL )
+      {
+      return( MIDI_NullMidiModule );
+      }
+
+   if ( *( unsigned long * )song != MIDI_HEADER_SIGNATURE )
+      {
+      return( MIDI_InvalidMidiFile );
+      }
+
+   song += 4;
+
+   headersize      = _MIDI_ReadNumber( song, 4 );
+   song += 4;
+   format          = _MIDI_ReadNumber( song, 2 );
+   _MIDI_NumTracks = _MIDI_ReadNumber( song + 2, 2 );
+   _MIDI_Division  = _MIDI_ReadNumber( song + 4, 2 );
+   if ( _MIDI_Division < 0 )
+      {
+      // If a SMPTE time division is given, just set to 96 so no errors occur
+      _MIDI_Division = 96;
+      }
+
+   if ( format > MAX_FORMAT )
+      {
+      return( MIDI_UnknownMidiFormat );
+      }
+
+   ptr = song + headersize;
+
+   if ( _MIDI_NumTracks == 0 )
+      {
+      return( MIDI_NoTracks );
+      }
+
+   _MIDI_TrackMemSize = _MIDI_NumTracks  * sizeof( track );
+   status = USRHOOKS_GetMem( &_MIDI_TrackPtr, _MIDI_TrackMemSize );
+   if ( status != USRHOOKS_Ok )
+      {
+      return( MIDI_NoMemory );
+      }
+
+   status = DPMI_LockMemory( _MIDI_TrackPtr, _MIDI_TrackMemSize );
+   if ( status != DPMI_Ok )
+      {
+      USRHOOKS_FreeMem( _MIDI_TrackPtr );
+
+      _MIDI_TrackPtr     = NULL;
+      _MIDI_TrackMemSize = 0;
+      _MIDI_NumTracks    = 0;
+//      MIDI_SetErrorCode( MIDI_DPMI_Error );
+      return( MIDI_Error );
+      }
+
+   CurrentTrack = _MIDI_TrackPtr;
+   numtracks    = _MIDI_NumTracks;
+   while( numtracks-- )
+      {
+      if ( *( unsigned long * )ptr != MIDI_TRACK_SIGNATURE )
+         {
+         DPMI_UnlockMemory( _MIDI_TrackPtr, _MIDI_TrackMemSize );
+
+         USRHOOKS_FreeMem( _MIDI_TrackPtr );
+
+         _MIDI_TrackPtr = NULL;
+         _MIDI_TrackMemSize = 0;
+
+         return( MIDI_InvalidTrack );
+         }
+
+      tracklength = _MIDI_ReadNumber( ptr + 4, 4 );
+      ptr += 8;
+      CurrentTrack->start = ptr;
+      ptr += tracklength;
+      CurrentTrack++;
+      }
+
+   if ( _MIDI_Funcs->GetVolume != NULL )
+      {
+      _MIDI_TotalVolume = _MIDI_Funcs->GetVolume();
+      }
+
+   _MIDI_InitEMIDI();
+
+   if ( _MIDI_Funcs->LoadPatch )
+      {
+      MIDI_LoadTimbres();
+      }
+
+   _MIDI_ResetTracks();
+
+   if ( !Reset )
+      {
+      MIDI_Reset();
+      }
+
+   Reset = FALSE;
+
+   _MIDI_PlayRoutine = TS_ScheduleTask( _MIDI_ServiceRoutine, 100, 1, NULL );
+//   _MIDI_PlayRoutine = TS_ScheduleTask( test, 100, 1, NULL );
+   MIDI_SetTempo( 120 );
+   TS_Dispatch();
+
+   _MIDI_SongLoaded = TRUE;
+   _MIDI_SongActive = TRUE;
+
+   return( MIDI_Ok );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MIDI_SetTempo
+
+   Sets the song tempo.
+---------------------------------------------------------------------*/
+
+void MIDI_SetTempo
+   (
+   int tempo
+   )
+
+   {
+   long tickspersecond;
+
+   MIDI_Tempo = tempo;
+   tickspersecond = ( tempo * _MIDI_Division ) / 60;
+   if ( _MIDI_PlayRoutine != NULL )
+      {
+      TS_SetTaskRate( _MIDI_PlayRoutine, tickspersecond );
+//      TS_SetTaskRate( _MIDI_PlayRoutine, tickspersecond / 4 );
+      }
+   _MIDI_FPSecondsPerTick = ( 1 << TIME_PRECISION ) / tickspersecond;
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MIDI_GetTempo
+
+   Returns the song tempo.
+---------------------------------------------------------------------*/
+
+int MIDI_GetTempo
+   (
+   void
+   )
+
+   {
+   return( MIDI_Tempo );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: _MIDI_ProcessNextTick
+
+   Sets the position of the song pointer.
+---------------------------------------------------------------------*/
+
+static int _MIDI_ProcessNextTick
+   (
+   void
+   )
+
+   {
+   int   event;
+   int   channel;
+   int   command;
+   track *Track;
+   int   tracknum;
+   int   status;
+   int   c1;
+   int   c2;
+   int   TimeSet = FALSE;
+
+   Track = _MIDI_TrackPtr;
+   tracknum = 0;
+   while( ( tracknum < _MIDI_NumTracks ) && ( Track != NULL ) )
+      {
+      while ( ( Track->active ) && ( Track->delay == 0 ) )
+         {
+         GET_NEXT_EVENT( Track, event );
+
+         if ( GET_MIDI_COMMAND( event ) == MIDI_SPECIAL )
+            {
+            switch( event )
+               {
+               case MIDI_SYSEX :
+               case MIDI_SYSEX_CONTINUE :
+                  _MIDI_SysEx( Track );
+                  break;
+
+               case MIDI_META_EVENT :
+                  _MIDI_MetaEvent( Track );
+                  break;
+               }
+
+            if ( Track->active )
+               {
+               Track->delay = _MIDI_ReadDelta( Track );
+               }
+
+            continue;
+            }
+
+         if ( event & MIDI_RUNNING_STATUS )
+            {
+            Track->RunningStatus = event;
+            }
+         else
+            {
+            event = Track->RunningStatus;
+            Track->pos--;
+            }
+
+         channel = GET_MIDI_CHANNEL( event );
+         command = GET_MIDI_COMMAND( event );
+
+         if ( _MIDI_CommandLengths[ command ] > 0 )
+            {
+            GET_NEXT_EVENT( Track, c1 );
+            if ( _MIDI_CommandLengths[ command ] > 1 )
+               {
+               GET_NEXT_EVENT( Track, c2 );
+               }
+            }
+
+         if ( _MIDI_RerouteFunctions[ channel ] != NULL )
+            {
+            status = _MIDI_RerouteFunctions[ channel ]( event, c1, c2 );
+
+            if ( status == MIDI_DONT_PLAY )
+               {
+               Track->delay = _MIDI_ReadDelta( Track );
+               continue;
+               }
+            }
+
+         switch ( command )
+            {
+            case MIDI_NOTE_OFF :
+               break;
+
+            case MIDI_NOTE_ON :
+               break;
+
+            case MIDI_POLY_AFTER_TCH :
+               if ( _MIDI_Funcs->PolyAftertouch )
+                  {
+                  _MIDI_Funcs->PolyAftertouch( channel, c1, c2 );
+                  }
+               break;
+
+            case MIDI_CONTROL_CHANGE :
+               TimeSet = _MIDI_InterpretControllerInfo( Track, TimeSet,
+                  channel, c1, c2 );
+               break;
+
+            case MIDI_PROGRAM_CHANGE :
+               if ( ( _MIDI_Funcs->ProgramChange ) &&
+                  ( !Track->EMIDI_ProgramChange ) )
+                  {
+                  _MIDI_Funcs->ProgramChange( channel, c1 );
+                  }
+               break;
+
+            case MIDI_AFTER_TOUCH :
+               if ( _MIDI_Funcs->ChannelAftertouch )
+                  {
+                  _MIDI_Funcs->ChannelAftertouch( channel, c1 );
+                  }
+               break;
+
+            case MIDI_PITCH_BEND :
+               if ( _MIDI_Funcs->PitchBend )
+                  {
+                  _MIDI_Funcs->PitchBend( channel, c1, c2 );
+                  }
+               break;
+
+            default :
+               break;
+            }
+
+         Track->delay = _MIDI_ReadDelta( Track );
+         }
+
+      Track->delay--;
+      Track++;
+      tracknum++;
+
+      if ( _MIDI_ActiveTracks == 0 )
+         {
+         break;
+         }
+      }
+
+   _MIDI_AdvanceTick();
+
+   return( TimeSet );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MIDI_SetSongTick
+
+   Sets the position of the song pointer.
+---------------------------------------------------------------------*/
+
+void MIDI_SetSongTick
+   (
+   unsigned long PositionInTicks
+   )
+
+   {
+   if ( !_MIDI_SongLoaded )
+      {
+      return;
+      }
+
+   MIDI_PauseSong();
+
+   if ( PositionInTicks < _MIDI_PositionInTicks )
+      {
+      _MIDI_ResetTracks();
+      MIDI_Reset();
+      }
+
+   while( _MIDI_PositionInTicks < PositionInTicks )
+      {
+      if ( _MIDI_ProcessNextTick() )
+         {
+         break;
+         }
+      if ( _MIDI_ActiveTracks == 0 )
+         {
+         _MIDI_ResetTracks();
+         if ( !_MIDI_Loop )
+            {
+            return;
+            }
+         break;
+         }
+      }
+
+   MIDI_SetVolume( _MIDI_TotalVolume );
+   MIDI_ContinueSong();
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MIDI_SetSongTime
+
+   Sets the position of the song pointer.
+---------------------------------------------------------------------*/
+
+void MIDI_SetSongTime
+   (
+   unsigned long milliseconds
+   )
+
+   {
+   unsigned long mil;
+   unsigned long sec;
+   unsigned long newtime;
+
+   if ( !_MIDI_SongLoaded )
+      {
+      return;
+      }
+
+   MIDI_PauseSong();
+
+   mil = ( ( milliseconds % 1000 ) << TIME_PRECISION ) / 1000;
+   sec = ( milliseconds / 1000 ) << TIME_PRECISION;
+   newtime = sec + mil;
+
+   if ( newtime < _MIDI_Time )
+      {
+      _MIDI_ResetTracks();
+      MIDI_Reset();
+      }
+
+   while( _MIDI_Time < newtime )
+      {
+      if ( _MIDI_ProcessNextTick() )
+         {
+         break;
+         }
+      if ( _MIDI_ActiveTracks == 0 )
+         {
+         _MIDI_ResetTracks();
+         if ( !_MIDI_Loop )
+            {
+            return;
+            }
+         break;
+         }
+      }
+
+   MIDI_SetVolume( _MIDI_TotalVolume );
+   MIDI_ContinueSong();
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MIDI_SetSongPosition
+
+   Sets the position of the song pointer.
+---------------------------------------------------------------------*/
+
+void MIDI_SetSongPosition
+   (
+   int measure,
+   int beat,
+   int tick
+   )
+
+   {
+   unsigned long pos;
+
+   if ( !_MIDI_SongLoaded )
+      {
+      return;
+      }
+
+   MIDI_PauseSong();
+
+   pos = RELATIVE_BEAT( measure, beat, tick );
+
+   if ( pos < RELATIVE_BEAT( _MIDI_Measure, _MIDI_Beat, _MIDI_Tick ) )
+      {
+      _MIDI_ResetTracks();
+      MIDI_Reset();
+      }
+
+   while( RELATIVE_BEAT( _MIDI_Measure, _MIDI_Beat, _MIDI_Tick ) < pos )
+      {
+      if ( _MIDI_ProcessNextTick() )
+         {
+         break;
+         }
+      if ( _MIDI_ActiveTracks == 0 )
+         {
+         _MIDI_ResetTracks();
+         if ( !_MIDI_Loop )
+            {
+            return;
+            }
+         break;
+         }
+      }
+
+   MIDI_SetVolume( _MIDI_TotalVolume );
+   MIDI_ContinueSong();
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MIDI_GetSongPosition
+
+   Returns the position of the song pointer in Measures, beats, ticks.
+---------------------------------------------------------------------*/
+
+void MIDI_GetSongPosition
+   (
+   songposition *pos
+   )
+
+   {
+   unsigned long mil;
+   unsigned long sec;
+
+   mil = ( _MIDI_Time & ( ( 1 << TIME_PRECISION ) - 1 ) ) * 1000;
+   sec = _MIDI_Time >> TIME_PRECISION;
+   pos->milliseconds = ( mil >> TIME_PRECISION ) + ( sec * 1000 );
+   pos->tickposition = _MIDI_PositionInTicks;
+   pos->measure      = _MIDI_Measure;
+   pos->beat         = _MIDI_Beat;
+   pos->tick         = _MIDI_Tick;
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MIDI_GetSongLength
+
+   Returns the length of the song.
+---------------------------------------------------------------------*/
+
+void MIDI_GetSongLength
+   (
+   songposition *pos
+   )
+
+   {
+   unsigned long mil;
+   unsigned long sec;
+
+   mil = ( _MIDI_TotalTime & ( ( 1 << TIME_PRECISION ) - 1 ) ) * 1000;
+   sec = _MIDI_TotalTime >> TIME_PRECISION;
+
+   pos->milliseconds = ( mil >> TIME_PRECISION ) + ( sec * 1000 );
+   pos->measure      = _MIDI_TotalMeasures;
+   pos->beat         = _MIDI_TotalBeats;
+   pos->tick         = _MIDI_TotalTicks;
+   pos->tickposition = 0;
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MIDI_InitEMIDI
+
+   Sets up the EMIDI
+---------------------------------------------------------------------*/
+
+static void _MIDI_InitEMIDI
+   (
+   void
+   )
+
+   {
+   int    event;
+   int    command;
+   int    channel;
+   int    length;
+   int    IncludeFound;
+   track *Track;
+   int    tracknum;
+   int    type;
+   int    c1;
+   int    c2;
+
+   type = EMIDI_GeneralMIDI;
+   switch( MUSIC_SoundDevice )
+      {
+      case SoundBlaster :
+         type = EMIDI_SoundBlaster;
+         break;
+
+      case ProAudioSpectrum :
+         type = EMIDI_ProAudio;
+         break;
+
+      case SoundMan16 :
+         type = EMIDI_SoundMan16;
+         break;
+
+      case Adlib :
+         type = EMIDI_Adlib;
+         break;
+
+      case GenMidi :
+         type = EMIDI_GeneralMIDI;
+         break;
+
+      case SoundCanvas :
+         type = EMIDI_SoundCanvas;
+         break;
+
+      case Awe32 :
+         type = EMIDI_AWE32;
+         break;
+
+      case WaveBlaster :
+         type = EMIDI_WaveBlaster;
+         break;
+
+      case SoundScape :
+         type = EMIDI_Soundscape;
+         break;
+
+      case UltraSound :
+         type = EMIDI_Ultrasound;
+         break;
+      }
+
+   _MIDI_ResetTracks();
+
+   _MIDI_TotalTime     = 0;
+   _MIDI_TotalTicks    = 0;
+   _MIDI_TotalBeats    = 0;
+   _MIDI_TotalMeasures = 0;
+
+   Track = _MIDI_TrackPtr;
+   tracknum = 0;
+   while( ( tracknum < _MIDI_NumTracks ) && ( Track != NULL ) )
+      {
+      _MIDI_Tick = 0;
+      _MIDI_Beat = 1;
+      _MIDI_Measure = 1;
+      _MIDI_Time = 0;
+      _MIDI_BeatsPerMeasure = 4;
+      _MIDI_TicksPerBeat = _MIDI_Division;
+      _MIDI_TimeBase = 4;
+
+      _MIDI_PositionInTicks = 0;
+      _MIDI_ActiveTracks    = 0;
+      _MIDI_Context         = -1;
+
+      Track->RunningStatus = 0;
+      Track->active        = TRUE;
+
+      Track->EMIDI_ProgramChange = FALSE;
+      Track->EMIDI_VolumeChange  = FALSE;
+      Track->EMIDI_IncludeTrack  = TRUE;
+
+      memset( Track->context, 0, sizeof( Track->context ) );
+
+      while( Track->delay > 0 )
+         {
+         _MIDI_AdvanceTick();
+         Track->delay--;
+         }
+
+      IncludeFound = FALSE;
+      while ( Track->active )
+         {
+         GET_NEXT_EVENT( Track, event );
+
+         if ( GET_MIDI_COMMAND( event ) == MIDI_SPECIAL )
+            {
+            switch( event )
+               {
+               case MIDI_SYSEX :
+               case MIDI_SYSEX_CONTINUE :
+                  _MIDI_SysEx( Track );
+                  break;
+
+               case MIDI_META_EVENT :
+                  _MIDI_MetaEvent( Track );
+                  break;
+               }
+
+            if ( Track->active )
+               {
+               Track->delay = _MIDI_ReadDelta( Track );
+               while( Track->delay > 0 )
+                  {
+                  _MIDI_AdvanceTick();
+                  Track->delay--;
+                  }
+               }
+
+            continue;
+            }
+
+         if ( event & MIDI_RUNNING_STATUS )
+            {
+            Track->RunningStatus = event;
+            }
+         else
+            {
+            event = Track->RunningStatus;
+            Track->pos--;
+            }
+
+         channel = GET_MIDI_CHANNEL( event );
+         command = GET_MIDI_COMMAND( event );
+         length = _MIDI_CommandLengths[ command ];
+
+         if ( command == MIDI_CONTROL_CHANGE )
+            {
+            if ( *Track->pos == MIDI_MONO_MODE_ON )
+               {
+               length++;
+               }
+            GET_NEXT_EVENT( Track, c1 );
+            GET_NEXT_EVENT( Track, c2 );
+            length -= 2;
+
+            switch( c1 )
+               {
+               case EMIDI_LOOP_START :
+               case EMIDI_SONG_LOOP_START :
+                  if ( c2 == 0 )
+                     {
+                     Track->context[ 0 ].loopcount = EMIDI_INFINITE;
+                     }
+                  else
+                     {
+                     Track->context[ 0 ].loopcount = c2;
+                     }
+
+                  Track->context[ 0 ].pos              = Track->pos;
+                  Track->context[ 0 ].loopstart        = Track->pos;
+                  Track->context[ 0 ].RunningStatus    = Track->RunningStatus;
+                  Track->context[ 0 ].time             = _MIDI_Time;
+                  Track->context[ 0 ].FPSecondsPerTick = _MIDI_FPSecondsPerTick;
+                  Track->context[ 0 ].tick             = _MIDI_Tick;
+                  Track->context[ 0 ].beat             = _MIDI_Beat;
+                  Track->context[ 0 ].measure          = _MIDI_Measure;
+                  Track->context[ 0 ].BeatsPerMeasure  = _MIDI_BeatsPerMeasure;
+                  Track->context[ 0 ].TicksPerBeat     = _MIDI_TicksPerBeat;
+                  Track->context[ 0 ].TimeBase         = _MIDI_TimeBase;
+                  break;
+
+               case EMIDI_LOOP_END :
+               case EMIDI_SONG_LOOP_END :
+                  if ( c2 == EMIDI_END_LOOP_VALUE )
+                     {
+                     Track->context[ 0 ].loopstart = NULL;
+                     Track->context[ 0 ].loopcount = 0;
+                     }
+                  break;
+
+               case EMIDI_INCLUDE_TRACK :
+                  if ( EMIDI_AffectsCurrentCard( c2, type ) )
+                     {
+                     //printf( "Include track %d on card %d\n", tracknum, c2 );
+                     IncludeFound = TRUE;
+                     Track->EMIDI_IncludeTrack = TRUE;
+                     }
+                  else if ( !IncludeFound )
+                     {
+                     //printf( "Track excluded %d on card %d\n", tracknum, c2 );
+                     IncludeFound = TRUE;
+                     Track->EMIDI_IncludeTrack = FALSE;
+                     }
+                  break;
+
+               case EMIDI_EXCLUDE_TRACK :
+                  if ( EMIDI_AffectsCurrentCard( c2, type ) )
+                     {
+                     //printf( "Exclude track %d on card %d\n", tracknum, c2 );
+                     Track->EMIDI_IncludeTrack = FALSE;
+                     }
+                  break;
+
+               case EMIDI_PROGRAM_CHANGE :
+                  if ( !Track->EMIDI_ProgramChange )
+                     //printf( "Program change on track %d\n", tracknum );
+                  Track->EMIDI_ProgramChange = TRUE;
+                  break;
+
+               case EMIDI_VOLUME_CHANGE :
+                  if ( !Track->EMIDI_VolumeChange )
+                     //printf( "Volume change on track %d\n", tracknum );
+                  Track->EMIDI_VolumeChange = TRUE;
+                  break;
+
+               case EMIDI_CONTEXT_START :
+                  if ( ( c2 > 0 ) && ( c2 < EMIDI_NUM_CONTEXTS ) )
+                     {
+                     Track->context[ c2 ].pos              = Track->pos;
+                     Track->context[ c2 ].loopstart        = Track->context[ 0 ].loopstart;
+                     Track->context[ c2 ].loopcount        = Track->context[ 0 ].loopcount;
+                     Track->context[ c2 ].RunningStatus    = Track->RunningStatus;
+                     Track->context[ c2 ].time             = _MIDI_Time;
+                     Track->context[ c2 ].FPSecondsPerTick = _MIDI_FPSecondsPerTick;
+                     Track->context[ c2 ].tick             = _MIDI_Tick;
+                     Track->context[ c2 ].beat             = _MIDI_Beat;
+                     Track->context[ c2 ].measure          = _MIDI_Measure;
+                     Track->context[ c2 ].BeatsPerMeasure  = _MIDI_BeatsPerMeasure;
+                     Track->context[ c2 ].TicksPerBeat     = _MIDI_TicksPerBeat;
+                     Track->context[ c2 ].TimeBase         = _MIDI_TimeBase;
+                     }
+                  break;
+
+               case EMIDI_CONTEXT_END :
+                  break;
+               }
+            }
+
+         Track->pos += length;
+         Track->delay = _MIDI_ReadDelta( Track );
+
+         while( Track->delay > 0 )
+            {
+            _MIDI_AdvanceTick();
+            Track->delay--;
+            }
+         }
+
+      _MIDI_TotalTime = max( _MIDI_TotalTime, _MIDI_Time );
+      if ( RELATIVE_BEAT( _MIDI_Measure, _MIDI_Beat, _MIDI_Tick ) >
+         RELATIVE_BEAT( _MIDI_TotalMeasures, _MIDI_TotalBeats,
+         _MIDI_TotalTicks ) )
+         {
+         _MIDI_TotalTicks    = _MIDI_Tick;
+         _MIDI_TotalBeats    = _MIDI_Beat;
+         _MIDI_TotalMeasures = _MIDI_Measure;
+         }
+
+      Track++;
+      tracknum++;
+      }
+
+   _MIDI_ResetTracks();
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MIDI_LoadTimbres
+
+   Preloads the timbres on cards that use patch-caching.
+---------------------------------------------------------------------*/
+
+void MIDI_LoadTimbres
+   (
+   void
+   )
+
+   {
+   int    event;
+   int    command;
+   int    channel;
+   int    length;
+   int    Finished;
+   track *Track;
+   int    tracknum;
+
+   Track = _MIDI_TrackPtr;
+   tracknum = 0;
+   while( ( tracknum < _MIDI_NumTracks ) && ( Track != NULL ) )
+      {
+      Finished = FALSE;
+      while ( !Finished )
+         {
+         GET_NEXT_EVENT( Track, event );
+
+         if ( GET_MIDI_COMMAND( event ) == MIDI_SPECIAL )
+            {
+            switch( event )
+               {
+               case MIDI_SYSEX :
+               case MIDI_SYSEX_CONTINUE :
+                  length = _MIDI_ReadDelta( Track );
+                  Track->pos += length;
+                  break;
+
+               case MIDI_META_EVENT :
+                  GET_NEXT_EVENT( Track, command );
+                  GET_NEXT_EVENT( Track, length );
+
+                  if ( command == MIDI_END_OF_TRACK )
+                     {
+                     Finished = TRUE;
+                     }
+
+                  Track->pos += length;
+                  break;
+               }
+
+            if ( !Finished )
+               {
+               _MIDI_ReadDelta( Track );
+               }
+
+            continue;
+            }
+
+         if ( event & MIDI_RUNNING_STATUS )
+            {
+            Track->RunningStatus = event;
+            }
+         else
+            {
+            event = Track->RunningStatus;
+            Track->pos--;
+            }
+
+         channel = GET_MIDI_CHANNEL( event );
+         command = GET_MIDI_COMMAND( event );
+         length = _MIDI_CommandLengths[ command ];
+
+         if ( command == MIDI_CONTROL_CHANGE )
+            {
+            if ( *Track->pos == MIDI_MONO_MODE_ON )
+               {
+               length++;
+               }
+
+            if ( *Track->pos == EMIDI_PROGRAM_CHANGE )
+               {
+               _MIDI_Funcs->LoadPatch( *( Track->pos + 1 ) );
+               }
+            }
+
+         if ( channel == MIDI_RHYTHM_CHANNEL )
+            {
+            if ( command == MIDI_NOTE_ON )
+               {
+               _MIDI_Funcs->LoadPatch( 128 + *Track->pos );
+               }
+            }
+         else
+            {
+            if ( command == MIDI_PROGRAM_CHANGE )
+               {
+               _MIDI_Funcs->LoadPatch( *Track->pos );
+               }
+            }
+         Track->pos += length;
+         _MIDI_ReadDelta( Track );
+         }
+      Track++;
+      tracknum++;
+      }
+
+   _MIDI_ResetTracks();
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MIDI_LockEnd
+
+   Used for determining the length of the functions to lock in memory.
+---------------------------------------------------------------------*/
+
+static void MIDI_LockEnd
+   (
+   void
+   )
+
+   {
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MIDI_UnlockMemory
+
+   Unlocks all neccessary data.
+---------------------------------------------------------------------*/
+
+void MIDI_UnlockMemory
+   (
+   void
+   )
+
+   {
+   DPMI_UnlockMemoryRegion( MIDI_LockStart, MIDI_LockEnd );
+   DPMI_UnlockMemory( ( void * )&_MIDI_CommandLengths[ 0 ],
+      sizeof( _MIDI_CommandLengths ) );
+   DPMI_Unlock( _MIDI_TrackPtr );
+   DPMI_Unlock( _MIDI_NumTracks );
+   DPMI_Unlock( _MIDI_SongActive );
+   DPMI_Unlock( _MIDI_SongLoaded );
+   DPMI_Unlock( _MIDI_Loop );
+   DPMI_Unlock( _MIDI_PlayRoutine );
+   DPMI_Unlock( _MIDI_Division );
+   DPMI_Unlock( _MIDI_ActiveTracks );
+   DPMI_Unlock( _MIDI_TotalVolume );
+   DPMI_Unlock( _MIDI_ChannelVolume );
+   DPMI_Unlock( _MIDI_Funcs );
+   DPMI_Unlock( _MIDI_PositionInTicks );
+   DPMI_Unlock( _MIDI_Division );
+   DPMI_Unlock( _MIDI_Tick );
+   DPMI_Unlock( _MIDI_Beat );
+   DPMI_Unlock( _MIDI_Measure );
+   DPMI_Unlock( _MIDI_Time );
+   DPMI_Unlock( _MIDI_BeatsPerMeasure );
+   DPMI_Unlock( _MIDI_TicksPerBeat );
+   DPMI_Unlock( _MIDI_TimeBase );
+   DPMI_Unlock( _MIDI_FPSecondsPerTick );
+   DPMI_Unlock( _MIDI_Context );
+   DPMI_Unlock( _MIDI_TotalTime );
+   DPMI_Unlock( _MIDI_TotalTicks );
+   DPMI_Unlock( _MIDI_TotalBeats );
+   DPMI_Unlock( _MIDI_TotalMeasures );
+   DPMI_Unlock( MIDI_Tempo );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MIDI_LockMemory
+
+   Locks all neccessary data.
+---------------------------------------------------------------------*/
+
+int MIDI_LockMemory
+   (
+   void
+   )
+
+   {
+   int status;
+
+   status  = DPMI_LockMemoryRegion( MIDI_LockStart, MIDI_LockEnd );
+   status |= DPMI_LockMemory( ( void * )&_MIDI_CommandLengths[ 0 ],
+      sizeof( _MIDI_CommandLengths ) );
+   status |= DPMI_Lock( _MIDI_TrackPtr );
+   status |= DPMI_Lock( _MIDI_NumTracks );
+   status |= DPMI_Lock( _MIDI_SongActive );
+   status |= DPMI_Lock( _MIDI_SongLoaded );
+   status |= DPMI_Lock( _MIDI_Loop );
+   status |= DPMI_Lock( _MIDI_PlayRoutine );
+   status |= DPMI_Lock( _MIDI_Division );
+   status |= DPMI_Lock( _MIDI_ActiveTracks );
+   status |= DPMI_Lock( _MIDI_TotalVolume );
+   status |= DPMI_Lock( _MIDI_ChannelVolume );
+   status |= DPMI_Lock( _MIDI_Funcs );
+   status |= DPMI_Lock( _MIDI_PositionInTicks );
+   status |= DPMI_Lock( _MIDI_Division );
+   status |= DPMI_Lock( _MIDI_Tick );
+   status |= DPMI_Lock( _MIDI_Beat );
+   status |= DPMI_Lock( _MIDI_Measure );
+   status |= DPMI_Lock( _MIDI_Time );
+   status |= DPMI_Lock( _MIDI_BeatsPerMeasure );
+   status |= DPMI_Lock( _MIDI_TicksPerBeat );
+   status |= DPMI_Lock( _MIDI_TimeBase );
+   status |= DPMI_Lock( _MIDI_FPSecondsPerTick );
+   status |= DPMI_Lock( _MIDI_Context );
+   status |= DPMI_Lock( _MIDI_TotalTime );
+   status |= DPMI_Lock( _MIDI_TotalTicks );
+   status |= DPMI_Lock( _MIDI_TotalBeats );
+   status |= DPMI_Lock( _MIDI_TotalMeasures );
+   status |= DPMI_Lock( MIDI_Tempo );
+
+   if ( status != DPMI_Ok )
+      {
+      MIDI_UnlockMemory();
+//      MIDI_SetErrorCode( MIDI_DPMI_Error );
+      return( MIDI_Error );
+      }
+
+   return( MIDI_Ok );
+   }
--- /dev/null
+++ b/rott/audiolib/midi.h
@@ -1,0 +1,98 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+/**********************************************************************
+   module: MIDI.H
+
+   author: James R. Dose
+   date:   May 25, 1994
+
+   Public header for MIDI.C.  Midi song file playback routines.
+
+   (c) Copyright 1994 James R. Dose.  All Rights Reserved.
+**********************************************************************/
+
+#ifndef __MIDI_H
+#define __MIDI_H
+
+enum MIDI_Errors
+   {
+   MIDI_Warning = -2,
+   MIDI_Error   = -1,
+   MIDI_Ok      = 0,
+   MIDI_NullMidiModule,
+   MIDI_InvalidMidiFile,
+   MIDI_UnknownMidiFormat,
+   MIDI_NoTracks,
+   MIDI_InvalidTrack,
+   MIDI_NoMemory,
+   MIDI_DPMI_Error
+   };
+
+
+#define MIDI_PASS_THROUGH 1
+#define MIDI_DONT_PLAY    0
+
+#define MIDI_MaxVolume 255
+
+extern char MIDI_PatchMap[ 128 ];
+
+typedef struct
+   {
+   void ( *NoteOff )( int channel, int key, int velocity );
+   void ( *NoteOn )( int channel, int key, int velocity );
+   void ( *PolyAftertouch )( int channel, int key, int pressure );
+   void ( *ControlChange )( int channel, int number, int value );
+   void ( *ProgramChange )( int channel, int program );
+   void ( *ChannelAftertouch )( int channel, int pressure );
+   void ( *PitchBend )( int channel, int lsb, int msb );
+   void ( *ReleasePatches )( void );
+   void ( *LoadPatch )( int number );
+   void ( *SetVolume )( int volume );
+   int  ( *GetVolume )( void );
+   } midifuncs;
+
+void MIDI_RerouteMidiChannel( int channel, int cdecl ( *function )( int event, int c1, int c2 ) );
+int  MIDI_AllNotesOff( void );
+void MIDI_SetUserChannelVolume( int channel, int volume );
+void MIDI_ResetUserChannelVolume( void );
+int  MIDI_Reset( void );
+int  MIDI_SetVolume( int volume );
+int  MIDI_GetVolume( void );
+void MIDI_SetMidiFuncs( midifuncs *funcs );
+void MIDI_SetContext( int context );
+int  MIDI_GetContext( void );
+void MIDI_SetLoopFlag( int loopflag );
+void MIDI_ContinueSong( void );
+void MIDI_PauseSong( void );
+int  MIDI_SongPlaying( void );
+void MIDI_StopSong( void );
+int  MIDI_PlaySong( unsigned char *song, int loopflag );
+void MIDI_SetTempo( int tempo );
+int  MIDI_GetTempo( void );
+void MIDI_SetSongTick( unsigned long PositionInTicks );
+void MIDI_SetSongTime( unsigned long milliseconds );
+void MIDI_SetSongPosition( int measure, int beat, int tick );
+void MIDI_GetSongPosition( songposition *pos );
+void MIDI_GetSongLength( songposition *pos );
+void MIDI_LoadTimbres( void );
+void MIDI_UnlockMemory( void );
+int  MIDI_LockMemory( void );
+
+#endif
--- /dev/null
+++ b/rott/audiolib/mpu401.c
@@ -1,0 +1,451 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+/**********************************************************************
+   module: MPU401.C
+
+   author: James R. Dose
+   date:   January 1, 1994
+
+   Low level routines to support sending of MIDI data to MPU401
+   compatible MIDI interfaces.
+
+   (c) Copyright 1994 James R. Dose.  All Rights Reserved.
+**********************************************************************/
+
+#include <conio.h>
+#include <dos.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "dpmi.h"
+#include "user.h"
+#include "mpu401.h"
+
+#define MIDI_NOTE_OFF         0x80
+#define MIDI_NOTE_ON          0x90
+#define MIDI_POLY_AFTER_TCH   0xA0
+#define MIDI_CONTROL_CHANGE   0xB0
+#define MIDI_PROGRAM_CHANGE   0xC0
+#define MIDI_AFTER_TOUCH      0xD0
+#define MIDI_PITCH_BEND       0xE0
+#define MIDI_META_EVENT       0xFF
+#define MIDI_END_OF_TRACK     0x2F
+#define MIDI_TEMPO_CHANGE     0x51
+#define MIDI_MONO_MODE_ON     0x7E
+#define MIDI_ALL_NOTES_OFF    0x7B
+
+int MPU_BaseAddr = MPU_DefaultAddress;
+
+//unsigned MPU_Delay = 500;
+//unsigned MPU_Delay = 5000;
+unsigned MPU_Delay = 0x5000;
+
+
+/**********************************************************************
+
+   Memory locked functions:
+
+**********************************************************************/
+
+
+#define MPU_LockStart MPU_SendMidi
+
+
+/*---------------------------------------------------------------------
+   Function: MPU_SendMidi
+
+   Sends a byte of MIDI data to the music device.
+---------------------------------------------------------------------*/
+
+void MPU_SendMidi
+   (
+   int data
+   )
+
+   {
+   int      port = MPU_BaseAddr + 1;
+   unsigned count;
+
+   count = MPU_Delay;
+   while( count > 0 )
+      {
+      // check if status port says we're ready for write
+      if ( !( inp( port ) & MPU_ReadyToWrite ) )
+         {
+         break;
+         }
+
+      count--;
+      }
+
+   port--;
+
+   // Send the midi data
+   outp( port, data );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MPU_NoteOff
+
+   Sends a full MIDI note off event out to the music device.
+---------------------------------------------------------------------*/
+
+void MPU_NoteOff
+   (
+   int channel,
+   int key,
+   int velocity
+   )
+
+   {
+   MPU_SendMidi( MIDI_NOTE_OFF | channel );
+   MPU_SendMidi( key );
+   MPU_SendMidi( velocity );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MPU_NoteOn
+
+   Sends a full MIDI note on event out to the music device.
+---------------------------------------------------------------------*/
+
+void MPU_NoteOn
+   (
+   int channel,
+   int key,
+   int velocity
+   )
+
+   {
+   MPU_SendMidi( MIDI_NOTE_ON | channel );
+   MPU_SendMidi( key );
+   MPU_SendMidi( velocity );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MPU_PolyAftertouch
+
+   Sends a full MIDI polyphonic aftertouch event out to the music device.
+---------------------------------------------------------------------*/
+
+void MPU_PolyAftertouch
+   (
+   int channel,
+   int key,
+   int pressure
+   )
+
+   {
+   MPU_SendMidi( MIDI_POLY_AFTER_TCH | channel );
+   MPU_SendMidi( key );
+   MPU_SendMidi( pressure );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MPU_ControlChange
+
+   Sends a full MIDI control change event out to the music device.
+---------------------------------------------------------------------*/
+
+void MPU_ControlChange
+   (
+   int channel,
+   int number,
+   int value
+   )
+
+   {
+   MPU_SendMidi( MIDI_CONTROL_CHANGE | channel );
+   MPU_SendMidi( number );
+   MPU_SendMidi( value );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MPU_ProgramChange
+
+   Sends a full MIDI program change event out to the music device.
+---------------------------------------------------------------------*/
+
+void MPU_ProgramChange
+   (
+   int channel,
+   int program
+   )
+
+   {
+   MPU_SendMidi( MIDI_PROGRAM_CHANGE | channel );
+   MPU_SendMidi( program );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MPU_ChannelAftertouch
+
+   Sends a full MIDI channel aftertouch event out to the music device.
+---------------------------------------------------------------------*/
+
+void MPU_ChannelAftertouch
+   (
+   int channel,
+   int pressure
+   )
+
+   {
+   MPU_SendMidi( MIDI_AFTER_TOUCH | channel );
+   MPU_SendMidi( pressure );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MPU_PitchBend
+
+   Sends a full MIDI pitch bend event out to the music device.
+---------------------------------------------------------------------*/
+
+void MPU_PitchBend
+   (
+   int channel,
+   int lsb,
+   int msb
+   )
+
+   {
+   MPU_SendMidi( MIDI_PITCH_BEND | channel );
+   MPU_SendMidi( lsb );
+   MPU_SendMidi( msb );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MPU_SendCommand
+
+   Sends a command to the MPU401 card.
+---------------------------------------------------------------------*/
+
+void MPU_SendCommand
+   (
+   int data
+   )
+
+   {
+   int      port = MPU_BaseAddr + 1;
+   unsigned count;
+
+   count = 0xffff;
+   while( count > 0 )
+      {
+      // check if status port says we're ready for write
+      if ( !( inp( port ) & MPU_ReadyToWrite ) )
+         {
+         break;
+         }
+      count--;
+      }
+
+   outp( port, data );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MPU_Reset
+
+   Resets the MPU401 card.
+---------------------------------------------------------------------*/
+
+int MPU_Reset
+   (
+   void
+   )
+
+   {
+   int      port = MPU_BaseAddr + 1;
+   unsigned count;
+
+   // Output "Reset" command via Command port
+   MPU_SendCommand( MPU_CmdReset );
+
+   // Wait for status port to be ready for read
+   count = 0xffff;
+   while( count > 0 )
+      {
+      if ( !( inp( port ) & MPU_ReadyToRead ) )
+         {
+         port--;
+
+         // Check for a successful reset
+         if ( inp( port ) == MPU_CmdAcknowledge )
+            {
+            return( MPU_Ok );
+            }
+
+         port++;
+         }
+      count--;
+      }
+
+   // Failed to reset : MPU-401 not detected
+   return( MPU_NotFound );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MPU_EnterUART
+
+   Sets the MPU401 card to operate in UART mode.
+---------------------------------------------------------------------*/
+
+int MPU_EnterUART
+   (
+   void
+   )
+
+   {
+   int      port = MPU_BaseAddr + 1;
+   unsigned count;
+
+   // Output "Enter UART" command via Command port
+   MPU_SendCommand( MPU_CmdEnterUART );
+
+   // Wait for status port to be ready for read
+   count = 0xffff;
+   while( count > 0 )
+      {
+      if ( !( inp( port ) & MPU_ReadyToRead ) )
+         {
+         port--;
+
+         // Check for a successful reset
+         if ( inp( port ) == MPU_CmdAcknowledge )
+            {
+            return( MPU_Ok );
+            }
+
+         port++;
+         }
+      count--;
+      }
+
+   // Failed to reset : MPU-401 not detected
+   return( MPU_UARTFailed );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MPU_Init
+
+   Detects and initializes the MPU401 card.
+---------------------------------------------------------------------*/
+
+int MPU_Init
+   (
+   int addr
+   )
+
+   {
+   int status;
+   int count;
+   char *ptr;
+
+   ptr = USER_GetText( "MPUDELAY" );
+   if ( ptr != NULL )
+      {
+      MPU_Delay = ( unsigned )atol( ptr );
+      }
+
+   MPU_BaseAddr = addr;
+
+   count = 4;
+   while( count > 0 )
+      {
+      status = MPU_Reset();
+      if ( status == MPU_Ok )
+         {
+         return( MPU_EnterUART() );
+         }
+      count--;
+      }
+
+   return( status );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MPU_LockEnd
+
+   Used for determining the length of the functions to lock in memory.
+---------------------------------------------------------------------*/
+
+static void MPU_LockEnd
+   (
+   void
+   )
+
+   {
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MPU_UnlockMemory
+
+   Locks all neccessary data.
+---------------------------------------------------------------------*/
+
+void MPU_UnlockMemory
+   (
+   void
+   )
+
+   {
+   DPMI_UnlockMemoryRegion( MPU_LockStart, MPU_LockEnd );
+   DPMI_Unlock( MPU_BaseAddr );
+   DPMI_Unlock( MPU_Delay );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MPU_LockMemory
+
+   Locks all neccessary data.
+---------------------------------------------------------------------*/
+
+int MPU_LockMemory
+   (
+   void
+   )
+
+   {
+   int status;
+
+   status  = DPMI_LockMemoryRegion( MPU_LockStart, MPU_LockEnd );
+   status |= DPMI_Lock( MPU_BaseAddr );
+   status |= DPMI_Lock( MPU_Delay );
+
+   if ( status != DPMI_Ok )
+      {
+      MPU_UnlockMemory();
+      return( MPU_Error );
+      }
+
+   return( MPU_Ok );
+   }
--- /dev/null
+++ b/rott/audiolib/mpu401.h
@@ -1,0 +1,61 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+#ifndef __MPU401_H
+#define __MPU401_H
+
+#define MPU_DefaultAddress 0x330
+
+enum MPU_ERRORS
+   {
+   MPU_Warning = -2,
+   MPU_Error = -1,
+   MPU_Ok = 0,
+   MPU_DPMI_Error
+   };
+
+#define MPU_NotFound       -1
+#define MPU_UARTFailed     -2
+
+#define MPU_ReadyToWrite   0x40
+#define MPU_ReadyToRead    0x80
+#define MPU_CmdEnterUART   0x3f
+#define MPU_CmdReset       0xff
+#define MPU_CmdAcknowledge 0xfe
+
+extern int MPU_BaseAddr;
+extern unsigned MPU_Delay;
+
+void MPU_SendCommand( int data );
+void MPU_SendMidi( int data );
+int  MPU_Reset( void );
+int  MPU_EnterUART( void );
+int  MPU_Init( int addr );
+void MPU_ResetMidi( void );
+void MPU_NoteOff( int channel, int key, int velocity );
+void MPU_NoteOn( int channel, int key, int velocity );
+void MPU_PolyAftertouch( int channel, int key, int pressure );
+void MPU_ControlChange( int channel, int number, int value );
+void MPU_ProgramChange( int channel, int program );
+void MPU_ChannelAftertouch( int channel, int pressure );
+void MPU_PitchBend( int channel, int lsb, int msb );
+void MPU_UnlockMemory( void );
+int  MPU_LockMemory( void );
+
+#endif
--- /dev/null
+++ b/rott/audiolib/multivoc.c
@@ -1,0 +1,3555 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+/**********************************************************************
+   module: MULTIVOC.C
+
+   author: James R. Dose
+   date:   December 20, 1993
+
+   Routines to provide multichannel digitized sound playback for
+   Sound Blaster compatible sound cards.
+
+   (c) Copyright 1993 James R. Dose.  All Rights Reserved.
+**********************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#ifdef PLAT_DOS
+#include <dos.h>
+#include <conio.h>
+#endif
+
+#include "util.h"
+#include "dpmi.h"
+#include "usrhooks.h"
+#include "interrup.h"
+#include "dma.h"
+#include "linklist.h"
+#include "sndcards.h"
+
+#ifdef PLAT_DOS
+#include "blaster.h"
+#include "sndscape.h"
+#include "sndsrc.h"
+#include "pas16.h"
+#include "guswave.h"
+#else
+#include "dsl.h"
+#endif
+
+#include "pitch.h"
+#include "multivoc.h"
+#include "_multivc.h"
+#include "debugio.h"
+
+#define RoundFixed( fixedval, bits )            \
+        (                                       \
+          (                                     \
+            (fixedval) + ( 1 << ( (bits) - 1 ) )\
+          ) >> (bits)                           \
+        )
+
+#define IS_QUIET( ptr )  ( ( void * )( ptr ) == ( void * )&MV_VolumeTable[ 0 ] )
+
+static int       MV_ReverbLevel;
+static int       MV_ReverbDelay;
+static VOLUME16 *MV_ReverbTable = NULL;
+
+//static signed short MV_VolumeTable[ MV_MaxVolume + 1 ][ 256 ];
+static signed short MV_VolumeTable[ 63 + 1 ][ 256 ];
+
+//static Pan MV_PanTable[ MV_NumPanPositions ][ MV_MaxVolume + 1 ];
+static Pan MV_PanTable[ MV_NumPanPositions ][ 63 + 1 ];
+
+static int MV_Installed   = FALSE;
+static int MV_SoundCard   = SoundBlaster;
+static int MV_TotalVolume = MV_MaxTotalVolume;
+static int MV_MaxVoices   = 1;
+static int MV_Recording;
+
+static int MV_BufferSize = MixBufferSize;
+static int MV_BufferLength;
+
+static int MV_NumberOfBuffers = NumberOfBuffers;
+
+static int MV_MixMode    = MONO_8BIT;
+static int MV_Channels   = 1;
+static int MV_Bits       = 8;
+
+static int MV_Silence    = SILENCE_8BIT;
+static int MV_SwapLeftRight = FALSE;
+
+static int MV_RequestedMixRate;
+static int MV_MixRate;
+
+static int MV_DMAChannel = -1;
+static int MV_BuffShift;
+
+static int MV_TotalMemory;
+
+static long   MV_BufferDescriptor;
+static int   MV_BufferEmpty[ NumberOfBuffers ];
+char *MV_MixBuffer[ NumberOfBuffers + 1 ];
+
+static VoiceNode *MV_Voices = NULL;
+
+static volatile VoiceNode VoiceList;
+static volatile VoiceNode VoicePool;
+
+/*static*/ int MV_MixPage      = 0;
+static int MV_VoiceHandle  = MV_MinVoiceHandle;
+
+static void ( *MV_CallBackFunc )( unsigned long ) = NULL;
+static void ( *MV_RecordFunc )( char *ptr, int length ) = NULL;
+static void ( *MV_MixFunction )( VoiceNode *voice, int buffer );
+
+static int MV_MaxVolume = 63;
+
+char  *MV_HarshClipTable;
+char  *MV_MixDestination;
+short *MV_LeftVolume;
+short *MV_RightVolume;
+int    MV_SampleSize = 1;
+int    MV_RightChannelOffset;
+
+unsigned long MV_MixPosition;
+
+int MV_ErrorCode = MV_Ok;
+
+#define MV_SetErrorCode( status ) \
+   MV_ErrorCode   = ( status );
+
+
+/*---------------------------------------------------------------------
+   Function: MV_ErrorString
+
+   Returns a pointer to the error message associated with an error
+   number.  A -1 returns a pointer the current error.
+---------------------------------------------------------------------*/
+
+char *MV_ErrorString
+   (
+   int ErrorNumber
+   )
+
+   {
+   char *ErrorString;
+
+   switch( ErrorNumber )
+      {
+      case MV_Warning :
+      case MV_Error :
+         ErrorString = MV_ErrorString( MV_ErrorCode );
+         break;
+
+      case MV_Ok :
+         ErrorString = "Multivoc ok.";
+         break;
+
+      case MV_UnsupportedCard :
+         ErrorString = "Selected sound card is not supported by Multivoc.";
+         break;
+
+      case MV_NotInstalled :
+         ErrorString = "Multivoc not installed.";
+         break;
+
+      case MV_NoVoices :
+         ErrorString = "No free voices available to Multivoc.";
+         break;
+
+      case MV_NoMem :
+         ErrorString = "Out of memory in Multivoc.";
+         break;
+
+      case MV_VoiceNotFound :
+         ErrorString = "No voice with matching handle found.";
+         break;
+
+#ifdef PLAT_DOS
+      case MV_BlasterError :
+         ErrorString = BLASTER_ErrorString( BLASTER_Error );
+         break;
+
+      case MV_PasError :
+         ErrorString = PAS_ErrorString( PAS_Error );
+         break;
+
+      case MV_SoundScapeError :
+         ErrorString = SOUNDSCAPE_ErrorString( SOUNDSCAPE_Error );
+         break;
+
+      #ifndef SOUNDSOURCE_OFF
+      case MV_SoundSourceError :
+         ErrorString = SS_ErrorString( SS_Error );
+         break;
+      #endif
+#endif
+
+      case MV_DPMI_Error :
+         ErrorString = "DPMI Error in Multivoc.";
+         break;
+
+      case MV_InvalidVOCFile :
+         ErrorString = "Invalid VOC file passed in to Multivoc.";
+         break;
+
+      case MV_InvalidWAVFile :
+         ErrorString = "Invalid WAV file passed in to Multivoc.";
+         break;
+
+      case MV_InvalidMixMode :
+         ErrorString = "Invalid mix mode request in Multivoc.";
+         break;
+
+      case MV_SoundSourceFailure :
+         ErrorString = "Sound Source playback failed.";
+         break;
+
+      case MV_IrqFailure :
+         ErrorString = "Playback failed, possibly due to an invalid or conflicting IRQ.";
+         break;
+
+      case MV_DMAFailure :
+         ErrorString = "Playback failed, possibly due to an invalid or conflicting DMA channel.";
+         break;
+
+      case MV_DMA16Failure :
+         ErrorString = "Playback failed, possibly due to an invalid or conflicting DMA channel.  \n"
+                       "Make sure the 16-bit DMA channel is correct.";
+         break;
+
+      case MV_NullRecordFunction :
+         ErrorString = "Null record function passed to MV_StartRecording.";
+         break;
+
+      default :
+         ErrorString = "Unknown Multivoc error code.";
+         break;
+      }
+
+   return( ErrorString );
+   }
+
+
+/**********************************************************************
+
+   Memory locked functions:
+
+**********************************************************************/
+
+
+#define MV_LockStart MV_Mix
+
+
+/*---------------------------------------------------------------------
+   Function: MV_Mix
+
+   Mixes the sound into the buffer.
+---------------------------------------------------------------------*/
+
+static void MV_Mix
+   (
+   VoiceNode *voice,
+   int        buffer
+   )
+
+   {
+   char          *start;
+   int            length;
+   long           voclength;
+   unsigned long  position;
+   unsigned long  rate;
+   unsigned long  FixedPointBufferSize;
+
+   if ( ( voice->length == 0 ) &&
+        ( voice->GetSound != NULL ) &&
+        ( voice->GetSound( voice ) != KeepPlaying ) )
+      {
+      return;
+      }
+
+   length               = MixBufferSize;
+   FixedPointBufferSize = voice->FixedPointBufferSize;
+
+   MV_MixDestination    = MV_MixBuffer[ buffer ];
+   MV_LeftVolume        = voice->LeftVolume;
+   MV_RightVolume       = voice->RightVolume;
+
+   if ( ( MV_Channels == 2 ) && ( IS_QUIET( MV_LeftVolume ) ) )
+      {
+      MV_LeftVolume      = MV_RightVolume;
+      MV_MixDestination += MV_RightChannelOffset;
+      }
+
+   // Add this voice to the mix
+   while( length > 0 )
+      {
+      start    = voice->sound;
+      rate     = voice->RateScale;
+      position = voice->position;
+
+      // Check if the last sample in this buffer would be
+      // beyond the length of the sample block
+      if ( ( position + FixedPointBufferSize ) >= voice->length )
+         {
+         if ( position < voice->length )
+            {
+            voclength = ( voice->length - position + rate - 1 ) / rate;
+            }
+         else
+            {
+            voice->GetSound( voice );
+            return;
+            }
+         }
+      else
+         {
+         voclength = length;
+         }
+
+      voice->mix( position, rate, start, voclength );
+
+      if ( voclength & 1 )
+         {
+         MV_MixPosition += rate;
+         voclength -= 1;
+         }
+      voice->position = MV_MixPosition;
+
+      length -= voclength;
+
+      if ( voice->position >= voice->length )
+         {
+         // Get the next block of sound
+         if ( voice->GetSound( voice ) != KeepPlaying )
+            {
+            return;
+            }
+
+         if ( length > 0 )
+            {
+            // Get the position of the last sample in the buffer
+            FixedPointBufferSize = voice->RateScale * ( length - 1 );
+            }
+         }
+      }
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MV_PlayVoice
+
+   Adds a voice to the play list.
+---------------------------------------------------------------------*/
+
+void MV_PlayVoice
+   (
+   VoiceNode *voice
+   )
+
+   {
+   unsigned flags;
+
+   flags = DisableInterrupts();
+   LL_SortedInsertion( &VoiceList, voice, prev, next, VoiceNode, priority );
+
+   RestoreInterrupts( flags );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MV_StopVoice
+
+   Removes the voice from the play list and adds it to the free list.
+---------------------------------------------------------------------*/
+
+void MV_StopVoice
+   (
+   VoiceNode *voice
+   )
+
+   {
+   unsigned  flags;
+
+   flags = DisableInterrupts();
+
+   // move the voice from the play list to the free list
+   LL_Remove( voice, next, prev );
+   LL_Add( (VoiceNode *)&VoicePool, voice, next, prev );
+
+   RestoreInterrupts( flags );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MV_ServiceVoc
+
+   Starts playback of the waiting buffer and mixes the next one.
+---------------------------------------------------------------------*/
+
+// static int backcolor = 1;
+
+void MV_ServiceVoc
+   (
+   void
+   )
+
+   {
+   VoiceNode *voice;
+   VoiceNode *next;
+   char      *buffer;
+
+#ifdef PLAT_DOS
+   if ( MV_DMAChannel >= 0 )
+      {
+      // Get the currently playing buffer
+      buffer = ( char * )DMA_GetCurrentPos( MV_DMAChannel );
+      MV_MixPage   = ( unsigned )( buffer - MV_MixBuffer[ 0 ] );
+      MV_MixPage >>= MV_BuffShift;
+      }
+#endif
+
+   // Toggle which buffer we'll mix next
+   MV_MixPage++;
+   if ( MV_MixPage >= MV_NumberOfBuffers )
+      {
+      MV_MixPage -= MV_NumberOfBuffers;
+      }
+
+   if ( MV_ReverbLevel == 0 )
+      {
+      // Initialize buffer
+      //Commented out so that the buffer is always cleared.
+      //This is so the guys at Echo Speech can mix into the
+      //buffer even when no sounds are playing.
+      //if ( !MV_BufferEmpty[ MV_MixPage ] )
+         {
+         ClearBuffer_DW( MV_MixBuffer[ MV_MixPage ], MV_Silence, MV_BufferSize >> 2 );
+         if ( ( MV_SoundCard == UltraSound ) && ( MV_Channels == 2 ) )
+            {
+            ClearBuffer_DW( MV_MixBuffer[ MV_MixPage ] + MV_RightChannelOffset,
+               MV_Silence, MV_BufferSize >> 2 );
+            }
+         MV_BufferEmpty[ MV_MixPage ] = TRUE;
+         }
+      }
+   else
+      {
+      char *end;
+      char *source;
+      char *dest;
+      int   count;
+      int   length;
+
+      end = MV_MixBuffer[ 0 ] + MV_BufferLength;;
+      dest = MV_MixBuffer[ MV_MixPage ];
+      source = MV_MixBuffer[ MV_MixPage ] - MV_ReverbDelay;
+      if ( source < MV_MixBuffer[ 0 ] )
+         {
+         source += MV_BufferLength;
+         }
+
+      length = MV_BufferSize;
+      while( length > 0 )
+         {
+         count = length;
+         if ( source + count > end )
+            {
+            count = end - source;
+            }
+
+         if ( MV_Bits == 16 )
+            {
+            if ( MV_ReverbTable != NULL )
+               {
+               MV_16BitReverb( source, dest, (const VOLUME16 *)MV_ReverbTable, count / 2 );
+               if ( ( MV_SoundCard == UltraSound ) && ( MV_Channels == 2 ) )
+                  {
+                  MV_16BitReverb( source + MV_RightChannelOffset,
+                     dest + MV_RightChannelOffset, (const VOLUME16 *)MV_ReverbTable, count / 2 );
+                  }
+               }
+            else
+               {
+               MV_16BitReverbFast( source, dest, count / 2, MV_ReverbLevel );
+               if ( ( MV_SoundCard == UltraSound ) && ( MV_Channels == 2 ) )
+                  {
+                  MV_16BitReverbFast( source + MV_RightChannelOffset,
+                     dest + MV_RightChannelOffset, count / 2, MV_ReverbLevel );
+                  }
+               }
+            }
+         else
+            {
+            if ( MV_ReverbTable != NULL )
+               {
+               MV_8BitReverb( source, dest, (const VOLUME16 *)MV_ReverbTable, count );
+               if ( ( MV_SoundCard == UltraSound ) && ( MV_Channels == 2 ) )
+                  {
+                  MV_8BitReverb( source + MV_RightChannelOffset,
+                     dest + MV_RightChannelOffset, (const VOLUME16 *)MV_ReverbTable, count );
+                  }
+               }
+            else
+               {
+               MV_8BitReverbFast( source, dest, count, MV_ReverbLevel );
+               if ( ( MV_SoundCard == UltraSound ) && ( MV_Channels == 2 ) )
+                  {
+                  MV_8BitReverbFast( source + MV_RightChannelOffset,
+                     dest + MV_RightChannelOffset, count, MV_ReverbLevel );
+                  }
+               }
+            }
+
+         // if we go through the loop again, it means that we've wrapped around the buffer
+         source  = MV_MixBuffer[ 0 ];
+         dest   += count;
+         length -= count;
+         }
+      }
+
+   // Play any waiting voices
+   for( voice = VoiceList.next; voice != &VoiceList; voice = next )
+      {
+//      if ( ( voice < &MV_Voices[ 0 ] ) || ( voice > &MV_Voices[ 8 ] ) )
+//         {
+//         SetBorderColor(backcolor++);
+//         break;
+//         }
+
+      MV_BufferEmpty[ MV_MixPage ] = FALSE;
+
+      MV_MixFunction( voice, MV_MixPage );
+
+      next = voice->next;
+
+      // Is this voice done?
+      if ( !voice->Playing )
+         {
+         MV_StopVoice( voice );
+
+         if ( MV_CallBackFunc )
+            {
+            MV_CallBackFunc( voice->callbackval );
+            }
+         }
+      }
+   }
+
+
+int leftpage  = -1;
+int rightpage = -1;
+
+void MV_ServiceGus( char **ptr, unsigned long *length )
+   {
+   if ( leftpage == MV_MixPage )
+      {
+      MV_ServiceVoc();
+      }
+
+   leftpage = MV_MixPage;
+
+   *ptr = MV_MixBuffer[ MV_MixPage ];
+   *length = MV_BufferSize;
+   }
+
+void MV_ServiceRightGus( char **ptr, unsigned long *length )
+   {
+   if ( rightpage == MV_MixPage )
+      {
+      MV_ServiceVoc();
+      }
+
+   rightpage = MV_MixPage;
+
+   *ptr = MV_MixBuffer[ MV_MixPage ] + MV_RightChannelOffset;
+   *length = MV_BufferSize;
+   }
+
+/*---------------------------------------------------------------------
+   Function: MV_GetNextVOCBlock
+
+   Interperate the information of a VOC format sound file.
+---------------------------------------------------------------------*/
+static __inline unsigned int get_le32(void *p0)
+{
+	//unsigned char *p = p0;
+	//return p[0] | (p[1]<<8) | (p[2]<<16) | (p[3]<<24);
+	unsigned int val = *((unsigned int *) p0);
+	return(BUILDSWAP_INTEL32(val));
+}
+
+static __inline unsigned int get_le16(void *p0)
+{
+	//unsigned char *p = p0;
+	//return p[0] | (p[1]<<8);
+	unsigned short val = *((unsigned short *) p0);
+	return( (unsigned int) (BUILDSWAP_INTEL16(val)) );
+}
+
+playbackstatus MV_GetNextVOCBlock
+   (
+   VoiceNode *voice
+   )
+
+   {
+   unsigned char *ptr;
+   int            blocktype=0;
+   int            lastblocktype=0;
+   unsigned long  blocklength=0l;
+   unsigned long  samplespeed=0l;
+   unsigned int   tc=0;
+   int            packtype=0;
+   int            voicemode=0;
+   int            done=0;
+   unsigned       BitsPerSample;
+   unsigned       Channels;
+   unsigned       Format;
+
+   if ( voice->BlockLength > 0 )
+      {
+      voice->position    -= voice->length;
+      voice->sound       += voice->length >> 16;
+      if ( voice->bits == 16 )
+         {
+         voice->sound += voice->length >> 16;
+         }
+      voice->length       = min( voice->BlockLength, 0x8000 );
+      voice->BlockLength -= voice->length;
+      voice->length     <<= 16;
+      return( KeepPlaying );
+      }
+
+   if ( ( voice->length > 0 ) && ( voice->LoopEnd != NULL ) &&
+      ( voice->LoopStart != NULL ) )
+      {
+      voice->BlockLength  = voice->LoopSize;
+      voice->sound        = voice->LoopStart;
+      voice->position     = 0;
+      voice->length       = min( voice->BlockLength, 0x8000 );
+      voice->BlockLength -= voice->length;
+      voice->length     <<= 16;
+      return( KeepPlaying );
+      }
+
+   ptr = ( unsigned char * )voice->NextBlock;
+
+   voice->Playing = TRUE;
+
+   voicemode = 0;
+   lastblocktype = 0;
+   packtype = 0;
+
+   done = FALSE;
+   while( !done )
+      {
+      // Stop playing if we get a NULL pointer
+      if ( ptr == NULL )
+         {
+         voice->Playing = FALSE;
+         done = TRUE;
+         break;
+         }
+
+      {
+      unsigned tmp = get_le32(ptr);
+      blocktype = tmp&255;
+      blocklength = tmp>>8;
+      }
+      ptr += 4;
+
+      switch( blocktype )
+         {
+         case 0 :
+            // End of data
+            if ( ( voice->LoopStart == NULL ) ||
+               ( (unsigned char *)voice->LoopStart >= ( ptr - 4 ) ) )
+               {
+               voice->Playing = FALSE;
+               done = TRUE;
+               }
+            else
+               {
+               voice->BlockLength  = ( ptr - 4 ) - (unsigned char *)voice->LoopStart;
+               voice->sound        = voice->LoopStart;
+               voice->position     = 0;
+               voice->length       = min( voice->BlockLength, 0x8000 );
+               voice->BlockLength -= voice->length;
+               voice->length     <<= 16;
+               return( KeepPlaying );
+               }
+            break;
+
+         case 1 :
+            // Sound data block
+            voice->bits  = 8;
+            if ( lastblocktype != 8 )
+               {
+               tc = ( unsigned int )*ptr << 8;
+               packtype = *( ptr + 1 );
+               }
+
+            ptr += 2;
+            blocklength -= 2;
+
+            samplespeed = 256000000L / ( 65536 - tc );
+
+            // Skip packed or stereo data
+            if ( ( packtype != 0 ) || ( voicemode != 0 ) )
+               {
+               ptr += blocklength;
+               }
+            else
+               {
+               done = TRUE;
+               }
+            voicemode = 0;
+            break;
+
+         case 2 :
+            // Sound continuation block
+            samplespeed = voice->SamplingRate;
+            done = TRUE;
+            break;
+
+         case 3 :
+            // Silence
+            // Not implimented.
+            ptr += blocklength;
+            break;
+
+         case 4 :
+            // Marker
+            // Not implimented.
+            ptr += blocklength;
+            break;
+
+         case 5 :
+            // ASCII string
+            // Not implimented.
+            ptr += blocklength;
+            break;
+
+         case 6 :
+            // Repeat begin
+            if ( voice->LoopEnd == NULL )
+               {
+               voice->LoopCount = get_le16(ptr);
+               voice->LoopStart = ptr + blocklength;
+               }
+            ptr += blocklength;
+            break;
+
+         case 7 :
+            // Repeat end
+            ptr += blocklength;
+            if ( lastblocktype == 6 )
+               {
+               voice->LoopCount = 0;
+               }
+            else
+               {
+               if ( ( voice->LoopCount > 0 ) && ( voice->LoopStart != NULL ) )
+                  {
+                  ptr = voice->LoopStart;
+                  if ( voice->LoopCount < 0xffff )
+                     {
+                     voice->LoopCount--;
+                     if ( voice->LoopCount == 0 )
+                        {
+                        voice->LoopStart = NULL;
+                        }
+                     }
+                  }
+               }
+            break;
+
+         case 8 :
+            // Extended block
+            voice->bits  = 8;
+            tc = get_le16(ptr);
+            packtype = *( ptr + 2 );
+            voicemode = *( ptr + 3 );
+            ptr += blocklength;
+            break;
+
+         case 9 :
+            // New sound data block
+            samplespeed = get_le32(ptr);
+            BitsPerSample = ptr[4];
+            Channels = ptr[5];
+            Format = get_le16(ptr+6);
+
+            if ( ( BitsPerSample == 8 ) && ( Channels == 1 ) &&
+               ( Format == VOC_8BIT ) )
+               {
+               ptr         += 12;
+               blocklength -= 12;
+               voice->bits  = 8;
+               done         = TRUE;
+               }
+            else if ( ( BitsPerSample == 16 ) && ( Channels == 1 ) &&
+               ( Format == VOC_16BIT ) )
+               {
+               ptr         += 12;
+               blocklength -= 12;
+               voice->bits  = 16;
+               done         = TRUE;
+               }
+            else
+               {
+               ptr += blocklength;
+               }
+            break;
+
+         default :
+            // Unknown data.  Probably not a VOC file.
+            voice->Playing = FALSE;
+            done = TRUE;
+            break;
+         }
+
+      lastblocktype = blocktype;
+      }
+
+   if ( voice->Playing )
+      {
+      voice->NextBlock    = ptr + blocklength;
+      voice->sound        = ptr;
+
+      voice->SamplingRate = samplespeed;
+      voice->RateScale    = ( voice->SamplingRate * voice->PitchScale ) / MV_MixRate;
+
+      // Multiply by MixBufferSize - 1
+      voice->FixedPointBufferSize = ( voice->RateScale * MixBufferSize ) -
+         voice->RateScale;
+
+      if ( voice->LoopEnd != NULL )
+         {
+         if ( blocklength > ( unsigned long )voice->LoopEnd )
+            {
+            blocklength = ( unsigned long )voice->LoopEnd;
+            }
+         else
+            {
+            voice->LoopEnd = ( char * )blocklength;
+            }
+
+         voice->LoopStart = voice->sound + ( unsigned long )voice->LoopStart;
+         voice->LoopEnd   = voice->sound + ( unsigned long )voice->LoopEnd;
+         voice->LoopSize  = voice->LoopEnd - voice->LoopStart;
+         }
+
+      if ( voice->bits == 16 )
+         {
+         blocklength /= 2;
+         }
+
+      voice->position     = 0;
+      voice->length       = min( blocklength, 0x8000 );
+      voice->BlockLength  = blocklength - voice->length;
+      voice->length     <<= 16;
+
+      MV_SetVoiceMixMode( voice );
+
+      return( KeepPlaying );
+      }
+
+   return( NoMoreData );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MV_GetNextDemandFeedBlock
+
+   Controls playback of demand fed data.
+---------------------------------------------------------------------*/
+
+playbackstatus MV_GetNextDemandFeedBlock
+   (
+   VoiceNode *voice
+   )
+
+   {
+   if ( voice->BlockLength > 0 )
+      {
+      voice->position    -= voice->length;
+      voice->sound       += voice->length >> 16;
+      voice->length       = min( voice->BlockLength, 0x8000 );
+      voice->BlockLength -= voice->length;
+      voice->length     <<= 16;
+
+      return( KeepPlaying );
+      }
+
+   if ( voice->DemandFeed == NULL )
+      {
+      return( NoMoreData );
+      }
+
+   voice->position     = 0;
+   ( voice->DemandFeed )( &voice->sound, &voice->BlockLength );
+   voice->length       = min( voice->BlockLength, 0x8000 );
+   voice->BlockLength -= voice->length;
+   voice->length     <<= 16;
+
+   if ( ( voice->length > 0 ) && ( voice->sound != NULL ) )
+      {
+      return( KeepPlaying );
+      }
+   return( NoMoreData );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MV_GetNextRawBlock
+
+   Controls playback of demand fed data.
+---------------------------------------------------------------------*/
+
+playbackstatus MV_GetNextRawBlock
+   (
+   VoiceNode *voice
+   )
+
+   {
+   if ( voice->BlockLength <= 0 )
+      {
+      if ( voice->LoopStart == NULL )
+         {
+         voice->Playing = FALSE;
+         return( NoMoreData );
+         }
+
+      voice->BlockLength = voice->LoopSize;
+      voice->NextBlock   = voice->LoopStart;
+      voice->length = 0;
+      voice->position = 0;
+      }
+
+   voice->sound        = voice->NextBlock;
+   voice->position    -= voice->length;
+   voice->length       = min( voice->BlockLength, 0x8000 );
+   voice->NextBlock   += voice->length;
+   if ( voice->bits == 16 )
+      {
+      voice->NextBlock += voice->length;
+      }
+   voice->BlockLength -= voice->length;
+   voice->length     <<= 16;
+
+   return( KeepPlaying );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MV_GetNextWAVBlock
+
+   Controls playback of demand fed data.
+---------------------------------------------------------------------*/
+
+playbackstatus MV_GetNextWAVBlock
+   (
+   VoiceNode *voice
+   )
+
+   {
+   if ( voice->BlockLength <= 0 )
+      {
+      if ( voice->LoopStart == NULL )
+         {
+         voice->Playing = FALSE;
+         return( NoMoreData );
+         }
+
+      voice->BlockLength = voice->LoopSize;
+      voice->NextBlock   = voice->LoopStart;
+      voice->length      = 0;
+      voice->position    = 0;
+      }
+
+   voice->sound        = voice->NextBlock;
+   voice->position    -= voice->length;
+   voice->length       = min( voice->BlockLength, 0x8000 );
+   voice->NextBlock   += voice->length;
+   if ( voice->bits == 16 )
+      {
+      voice->NextBlock += voice->length;
+      }
+   voice->BlockLength -= voice->length;
+   voice->length     <<= 16;
+
+   return( KeepPlaying );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MV_ServiceRecord
+
+   Starts recording of the waiting buffer.
+---------------------------------------------------------------------*/
+
+static void MV_ServiceRecord
+   (
+   void
+   )
+
+   {
+   if ( MV_RecordFunc )
+      {
+      MV_RecordFunc( MV_MixBuffer[ 0 ] + MV_MixPage * MixBufferSize,
+         MixBufferSize );
+      }
+
+   // Toggle which buffer we'll mix next
+   MV_MixPage++;
+   if ( MV_MixPage >= NumberOfBuffers )
+      {
+      MV_MixPage = 0;
+      }
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MV_GetVoice
+
+   Locates the voice with the specified handle.
+---------------------------------------------------------------------*/
+
+VoiceNode *MV_GetVoice
+   (
+   int handle
+   )
+
+   {
+   VoiceNode *voice;
+   unsigned  flags;
+
+   flags = DisableInterrupts();
+
+   for( voice = VoiceList.next; voice != &VoiceList; voice = voice->next )
+      {
+      if ( handle == voice->handle )
+         {
+         break;
+         }
+      }
+
+   RestoreInterrupts( flags );
+
+   if ( voice == &VoiceList )
+      {
+      MV_SetErrorCode( MV_VoiceNotFound );
+      
+      // SBF - should this return null?
+      return NULL;
+      }
+
+   return( voice );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MV_VoicePlaying
+
+   Checks if the voice associated with the specified handle is
+   playing.
+---------------------------------------------------------------------*/
+
+int MV_VoicePlaying
+   (
+   int handle
+   )
+
+   {
+   VoiceNode *voice;
+
+   if ( !MV_Installed )
+      {
+      MV_SetErrorCode( MV_NotInstalled );
+      return( FALSE );
+      }
+
+   voice = MV_GetVoice( handle );
+
+   if ( voice == NULL )
+      {
+      return( FALSE );
+      }
+
+   return( TRUE );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MV_KillAllVoices
+
+   Stops output of all currently active voices.
+---------------------------------------------------------------------*/
+
+int MV_KillAllVoices
+   (
+   void
+   )
+
+   {
+   if ( !MV_Installed )
+      {
+      MV_SetErrorCode( MV_NotInstalled );
+      return( MV_Error );
+      }
+
+   // Remove all the voices from the list
+   while( VoiceList.next != &VoiceList )
+      {
+      MV_Kill( VoiceList.next->handle );
+      }
+
+   return( MV_Ok );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MV_Kill
+
+   Stops output of the voice associated with the specified handle.
+---------------------------------------------------------------------*/
+
+int MV_Kill
+   (
+   int handle
+   )
+
+   {
+   VoiceNode *voice;
+   unsigned  flags;
+   unsigned  long callbackval;
+
+   if ( !MV_Installed )
+      {
+      MV_SetErrorCode( MV_NotInstalled );
+      return( MV_Error );
+      }
+
+   flags = DisableInterrupts();
+
+   voice = MV_GetVoice( handle );
+   if ( voice == NULL )
+      {
+      RestoreInterrupts( flags );
+      MV_SetErrorCode( MV_VoiceNotFound );
+      return( MV_Error );
+      }
+
+   callbackval = voice->callbackval;
+
+   MV_StopVoice( voice );
+
+   RestoreInterrupts( flags );
+
+   if ( MV_CallBackFunc )
+      {
+      MV_CallBackFunc( callbackval );
+      }
+
+   return( MV_Ok );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MV_VoicesPlaying
+
+   Determines the number of currently active voices.
+---------------------------------------------------------------------*/
+
+int MV_VoicesPlaying
+   (
+   void
+   )
+
+   {
+   VoiceNode   *voice;
+   int         NumVoices = 0;
+   unsigned    flags;
+
+   if ( !MV_Installed )
+      {
+      MV_SetErrorCode( MV_NotInstalled );
+      return( 0 );
+      }
+
+   flags = DisableInterrupts();
+
+   for( voice = VoiceList.next; voice != &VoiceList; voice = voice->next )
+      {
+      NumVoices++;
+      }
+
+   RestoreInterrupts( flags );
+
+   return( NumVoices );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MV_AllocVoice
+
+   Retrieve an inactive or lower priority voice for output.
+---------------------------------------------------------------------*/
+
+VoiceNode *MV_AllocVoice
+   (
+   int priority
+   )
+
+   {
+   VoiceNode   *voice;
+   VoiceNode   *node;
+   unsigned    flags;
+
+//return( NULL );
+   if ( MV_Recording )
+      {
+      return( NULL );
+      }
+
+   flags = DisableInterrupts();
+
+   // Check if we have any free voices
+   if ( LL_Empty( &VoicePool, next, prev ) )
+      {
+      // check if we have a higher priority than a voice that is playing.
+      voice = VoiceList.next;
+      for( node = voice->next; node != &VoiceList; node = node->next )
+         {
+         if ( node->priority < voice->priority )
+            {
+            voice = node;
+            }
+         }
+
+      if ( priority >= voice->priority )
+         {
+         MV_Kill( voice->handle );
+         }
+      }
+
+   // Check if any voices are in the voice pool
+   if ( LL_Empty( &VoicePool, next, prev ) )
+      {
+      // No free voices
+      RestoreInterrupts( flags );
+      return( NULL );
+      }
+
+   voice = VoicePool.next;
+   LL_Remove( voice, next, prev );
+   RestoreInterrupts( flags );
+
+   // Find a free voice handle
+   do
+      {
+      MV_VoiceHandle++;
+      if ( MV_VoiceHandle < MV_MinVoiceHandle )
+         {
+         MV_VoiceHandle = MV_MinVoiceHandle;
+         }
+      }
+   while( MV_VoicePlaying( MV_VoiceHandle ) );
+
+   voice->handle = MV_VoiceHandle;
+
+   return( voice );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MV_VoiceAvailable
+
+   Checks if a voice can be play at the specified priority.
+---------------------------------------------------------------------*/
+
+int MV_VoiceAvailable
+   (
+   int priority
+   )
+
+   {
+   VoiceNode   *voice;
+   VoiceNode   *node;
+   unsigned    flags;
+
+   // Check if we have any free voices
+   if ( !LL_Empty( &VoicePool, next, prev ) )
+      {
+      return( TRUE );
+      }
+
+   flags = DisableInterrupts();
+
+   // check if we have a higher priority than a voice that is playing.
+   voice = VoiceList.next;
+   for( node = VoiceList.next; node != &VoiceList; node = node->next )
+      {
+      if ( node->priority < voice->priority )
+         {
+         voice = node;
+         }
+      }
+
+   RestoreInterrupts( flags );
+
+   if ( ( voice != &VoiceList ) && ( priority >= voice->priority ) )
+      {
+      return( TRUE );
+      }
+
+   return( FALSE );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MV_SetVoicePitch
+
+   Sets the pitch for the specified voice.
+---------------------------------------------------------------------*/
+
+void MV_SetVoicePitch
+   (
+   VoiceNode *voice,
+   unsigned long rate,
+   int pitchoffset
+   )
+
+   {
+   voice->SamplingRate = rate;
+   voice->PitchScale   = PITCH_GetScale( pitchoffset );
+   voice->RateScale    = ( rate * voice->PitchScale ) / MV_MixRate;
+
+   // Multiply by MixBufferSize - 1
+   voice->FixedPointBufferSize = ( voice->RateScale * MixBufferSize ) -
+      voice->RateScale;
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MV_SetPitch
+
+   Sets the pitch for the voice associated with the specified handle.
+---------------------------------------------------------------------*/
+
+int MV_SetPitch
+   (
+   int handle,
+   int pitchoffset
+   )
+
+   {
+   VoiceNode *voice;
+
+   if ( !MV_Installed )
+      {
+      MV_SetErrorCode( MV_NotInstalled );
+      return( MV_Error );
+      }
+
+   voice = MV_GetVoice( handle );
+   if ( voice == NULL )
+      {
+      MV_SetErrorCode( MV_VoiceNotFound );
+      return( MV_Error );
+      }
+
+   MV_SetVoicePitch( voice, voice->SamplingRate, pitchoffset );
+
+   return( MV_Ok );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MV_SetFrequency
+
+   Sets the frequency for the voice associated with the specified handle.
+---------------------------------------------------------------------*/
+
+int MV_SetFrequency
+   (
+   int handle,
+   int frequency
+   )
+
+   {
+   VoiceNode *voice;
+
+   if ( !MV_Installed )
+      {
+      MV_SetErrorCode( MV_NotInstalled );
+      return( MV_Error );
+      }
+
+   voice = MV_GetVoice( handle );
+   if ( voice == NULL )
+      {
+      MV_SetErrorCode( MV_VoiceNotFound );
+      return( MV_Error );
+      }
+
+   MV_SetVoicePitch( voice, frequency, 0 );
+
+   return( MV_Ok );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MV_GetVolumeTable
+
+   Returns a pointer to the volume table associated with the specified
+   volume.
+---------------------------------------------------------------------*/
+
+static short *MV_GetVolumeTable
+   (
+   int vol
+   )
+
+   {
+   int volume;
+   short *table;
+
+   volume = MIX_VOLUME( vol );
+
+   table = (short *)&MV_VolumeTable[ volume ];
+
+   return( table );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MV_SetVoiceMixMode
+
+   Selects which method should be used to mix the voice.
+---------------------------------------------------------------------*/
+
+static void MV_SetVoiceMixMode
+   (
+   VoiceNode *voice
+   )
+
+   {
+   unsigned flags;
+   int test;
+
+   flags = DisableInterrupts();
+
+   test = T_DEFAULT;
+   if ( MV_Bits == 8 )
+      {
+      test |= T_8BITS;
+      }
+
+   if ( voice->bits == 16 )
+      {
+      test |= T_16BITSOURCE;
+      }
+
+   if ( MV_Channels == 1 )
+      {
+      test |= T_MONO;
+      }
+   else
+      {
+      if ( IS_QUIET( voice->RightVolume ) )
+         {
+         test |= T_RIGHTQUIET;
+         }
+      else if ( IS_QUIET( voice->LeftVolume ) )
+         {
+         test |= T_LEFTQUIET;
+         }
+      }
+
+   // Default case
+   voice->mix = MV_Mix8BitMono;
+
+   switch( test )
+      {
+      case T_8BITS | T_MONO | T_16BITSOURCE :
+         voice->mix = MV_Mix8BitMono16;
+         break;
+
+      case T_8BITS | T_MONO :
+         voice->mix = MV_Mix8BitMono;
+         break;
+
+      case T_8BITS | T_16BITSOURCE | T_LEFTQUIET :
+         MV_LeftVolume = MV_RightVolume;
+         voice->mix = MV_Mix8BitMono16;
+         break;
+
+      case T_8BITS | T_LEFTQUIET :
+         MV_LeftVolume = MV_RightVolume;
+         voice->mix = MV_Mix8BitMono;
+         break;
+
+      case T_8BITS | T_16BITSOURCE | T_RIGHTQUIET :
+         voice->mix = MV_Mix8BitMono16;
+         break;
+
+      case T_8BITS | T_RIGHTQUIET :
+         voice->mix = MV_Mix8BitMono;
+         break;
+
+      case T_8BITS | T_16BITSOURCE :
+         voice->mix = MV_Mix8BitStereo16;
+         break;
+
+      case T_8BITS :
+         voice->mix = MV_Mix8BitStereo;
+         break;
+
+      case T_MONO | T_16BITSOURCE :
+         voice->mix = MV_Mix16BitMono16;
+         break;
+
+      case T_MONO :
+         voice->mix = MV_Mix16BitMono;
+         break;
+
+      case T_16BITSOURCE | T_LEFTQUIET :
+         MV_LeftVolume = MV_RightVolume;
+         voice->mix = MV_Mix16BitMono16;
+         break;
+
+      case T_LEFTQUIET :
+         MV_LeftVolume = MV_RightVolume;
+         voice->mix = MV_Mix16BitMono;
+         break;
+
+      case T_16BITSOURCE | T_RIGHTQUIET :
+         voice->mix = MV_Mix16BitMono16;
+         break;
+
+      case T_RIGHTQUIET :
+         voice->mix = MV_Mix16BitMono;
+         break;
+
+      case T_16BITSOURCE :
+         voice->mix = MV_Mix16BitStereo16;
+         break;
+
+      case T_SIXTEENBIT_STEREO :
+         voice->mix = MV_Mix16BitStereo;
+         break;
+
+      default :
+         voice->mix = MV_Mix8BitMono;
+      }
+
+   RestoreInterrupts( flags );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MV_SetVoiceVolume
+
+   Sets the stereo and mono volume level of the voice associated
+   with the specified handle.
+---------------------------------------------------------------------*/
+
+void MV_SetVoiceVolume
+   (
+   VoiceNode *voice,
+   int vol,
+   int left,
+   int right
+   )
+
+   {
+   if ( MV_Channels == 1 )
+      {
+      left  = vol;
+      right = vol;
+      }
+
+   if ( MV_SwapLeftRight )
+      {
+      // SBPro uses reversed panning
+      voice->LeftVolume  = MV_GetVolumeTable( right );
+      voice->RightVolume = MV_GetVolumeTable( left );
+      }
+   else
+      {
+      voice->LeftVolume  = MV_GetVolumeTable( left );
+      voice->RightVolume = MV_GetVolumeTable( right );
+      }
+
+   MV_SetVoiceMixMode( voice );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MV_EndLooping
+
+   Stops the voice associated with the specified handle from looping
+   without stoping the sound.
+---------------------------------------------------------------------*/
+
+int MV_EndLooping
+   (
+   int handle
+   )
+
+   {
+   VoiceNode *voice;
+   unsigned flags;
+
+   if ( !MV_Installed )
+      {
+      MV_SetErrorCode( MV_NotInstalled );
+      return( MV_Error );
+      }
+
+   flags = DisableInterrupts();
+
+   voice = MV_GetVoice( handle );
+   if ( voice == NULL )
+      {
+      RestoreInterrupts( flags );
+      MV_SetErrorCode( MV_VoiceNotFound );
+      return( MV_Warning );
+      }
+
+   voice->LoopCount = 0;
+   voice->LoopStart = NULL;
+   voice->LoopEnd   = NULL;
+
+   RestoreInterrupts( flags );
+
+   return( MV_Ok );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MV_SetPan
+
+   Sets the stereo and mono volume level of the voice associated
+   with the specified handle.
+---------------------------------------------------------------------*/
+
+int MV_SetPan
+   (
+   int handle,
+   int vol,
+   int left,
+   int right
+   )
+
+   {
+   VoiceNode *voice;
+
+   if ( !MV_Installed )
+      {
+      MV_SetErrorCode( MV_NotInstalled );
+      return( MV_Error );
+      }
+
+   voice = MV_GetVoice( handle );
+   if ( voice == NULL )
+      {
+      MV_SetErrorCode( MV_VoiceNotFound );
+      return( MV_Warning );
+      }
+
+   MV_SetVoiceVolume( voice, vol, left, right );
+
+   return( MV_Ok );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MV_Pan3D
+
+   Set the angle and distance from the listener of the voice associated
+   with the specified handle.
+---------------------------------------------------------------------*/
+
+int MV_Pan3D
+   (
+   int handle,
+   int angle,
+   int distance
+   )
+
+   {
+   int left;
+   int right;
+   int mid;
+   int volume;
+   int status;
+
+   if ( distance < 0 )
+      {
+      distance  = -distance;
+      angle    += MV_NumPanPositions / 2;
+      }
+
+   volume = MIX_VOLUME( distance );
+
+   // Ensure angle is within 0 - 31
+   angle &= MV_MaxPanPosition;
+
+   left  = MV_PanTable[ angle ][ volume ].left;
+   right = MV_PanTable[ angle ][ volume ].right;
+   mid   = max( 0, 255 - distance );
+
+   status = MV_SetPan( handle, mid, left, right );
+
+   return( status );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MV_SetReverb
+
+   Sets the level of reverb to add to mix.
+---------------------------------------------------------------------*/
+
+void MV_SetReverb
+   (
+   int reverb
+   )
+
+   {
+   MV_ReverbLevel = MIX_VOLUME( reverb );
+   MV_ReverbTable = &MV_VolumeTable[ MV_ReverbLevel ];
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MV_SetFastReverb
+
+   Sets the level of reverb to add to mix.
+---------------------------------------------------------------------*/
+
+void MV_SetFastReverb
+   (
+   int reverb
+   )
+
+   {
+   MV_ReverbLevel = max( 0, min( 16, reverb ) );
+   MV_ReverbTable = NULL;
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MV_GetMaxReverbDelay
+
+   Returns the maximum delay time for reverb.
+---------------------------------------------------------------------*/
+
+int MV_GetMaxReverbDelay
+   (
+   void
+   )
+
+   {
+   int maxdelay;
+
+   maxdelay = MixBufferSize * MV_NumberOfBuffers;
+
+   return maxdelay;
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MV_GetReverbDelay
+
+   Returns the current delay time for reverb.
+---------------------------------------------------------------------*/
+
+int MV_GetReverbDelay
+   (
+   void
+   )
+
+   {
+   return MV_ReverbDelay / MV_SampleSize;
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MV_SetReverbDelay
+
+   Sets the delay level of reverb to add to mix.
+---------------------------------------------------------------------*/
+
+void MV_SetReverbDelay
+   (
+   int delay
+   )
+
+   {
+   int maxdelay;
+
+   maxdelay = MV_GetMaxReverbDelay();
+   MV_ReverbDelay = max( MixBufferSize, min( delay, maxdelay ) );
+   MV_ReverbDelay *= MV_SampleSize;
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MV_SetMixMode
+
+   Prepares Multivoc to play stereo of mono digitized sounds.
+---------------------------------------------------------------------*/
+
+int MV_SetMixMode
+   (
+   int numchannels,
+   int samplebits
+   )
+
+   {
+   int mode;
+
+   if ( !MV_Installed )
+      {
+      MV_SetErrorCode( MV_NotInstalled );
+      return( MV_Error );
+      }
+
+   mode = 0;
+   if ( numchannels == 2 )
+      {
+      mode |= STEREO;
+      }
+   if ( samplebits == 16 )
+      {
+      mode |= SIXTEEN_BIT;
+      }
+
+#ifdef PLAT_DOS
+   switch( MV_SoundCard )
+      {
+      case UltraSound :
+         MV_MixMode = mode;
+         break;
+
+      case SoundBlaster :
+      case Awe32 :
+         MV_MixMode = BLASTER_SetMixMode( mode );
+         break;
+
+      case ProAudioSpectrum :
+      case SoundMan16 :
+         MV_MixMode = PAS_SetMixMode( mode );
+         break;
+
+      case SoundScape :
+         MV_MixMode = SOUNDSCAPE_SetMixMode( mode );
+         break;
+
+      #ifndef SOUNDSOURCE_OFF
+      case SoundSource :
+      case TandySoundSource :
+         MV_MixMode = SS_SetMixMode( mode );
+         break;
+      #endif
+      }
+#else
+   MV_MixMode = mode;
+#endif
+
+   MV_Channels = 1;
+   if ( MV_MixMode & STEREO )
+      {
+      MV_Channels = 2;
+      }
+
+   MV_Bits = 8;
+   if ( MV_MixMode & SIXTEEN_BIT )
+      {
+      MV_Bits = 16;
+      }
+
+   MV_BuffShift  = 7 + MV_Channels;
+   MV_SampleSize = sizeof( MONO8 ) * MV_Channels;
+
+   if ( MV_Bits == 8 )
+      {
+      MV_Silence = SILENCE_8BIT;
+      }
+   else
+      {
+      MV_Silence     = SILENCE_16BIT;
+      MV_BuffShift  += 1;
+      MV_SampleSize *= 2;
+      }
+
+   MV_BufferSize = MixBufferSize * MV_SampleSize;
+   MV_NumberOfBuffers = TotalBufferSize / MV_BufferSize;
+   MV_BufferLength = TotalBufferSize;
+
+   MV_RightChannelOffset = MV_SampleSize / 2;
+   if ( ( MV_SoundCard == UltraSound ) && ( MV_Channels == 2 ) )
+      {
+      MV_SampleSize         /= 2;
+      MV_BufferSize         /= 2;
+      MV_RightChannelOffset  = MV_BufferSize * MV_NumberOfBuffers;
+      MV_BufferLength       /= 2;
+      }
+
+   return( MV_Ok );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MV_StartPlayback
+
+   Starts the sound playback engine.
+---------------------------------------------------------------------*/
+
+int MV_StartPlayback
+   (
+   void
+   )
+
+   {
+   int status;
+   int buffer;
+
+   // Initialize the buffers
+   ClearBuffer_DW( MV_MixBuffer[ 0 ], MV_Silence, TotalBufferSize >> 2 );
+   for( buffer = 0; buffer < MV_NumberOfBuffers; buffer++ )
+      {
+      MV_BufferEmpty[ buffer ] = TRUE;
+      }
+
+   // Set the mix buffer variables
+   MV_MixPage = 1;
+
+   MV_MixFunction = MV_Mix;
+
+//JIM
+//   MV_MixRate = MV_RequestedMixRate;
+//   return( MV_Ok );
+
+   // Start playback
+#ifdef PLAT_DOS
+   switch( MV_SoundCard )
+      {
+      case SoundBlaster :
+      case Awe32 :
+         status = BLASTER_BeginBufferedPlayback( MV_MixBuffer[ 0 ],
+            TotalBufferSize, MV_NumberOfBuffers,
+            MV_RequestedMixRate, MV_MixMode, MV_ServiceVoc );
+
+         if ( status != BLASTER_Ok )
+            {
+            MV_SetErrorCode( MV_BlasterError );
+            return( MV_Error );
+            }
+
+         MV_MixRate = BLASTER_GetPlaybackRate();
+         MV_DMAChannel = BLASTER_DMAChannel;
+         break;
+
+      case UltraSound :
+
+         status = GUSWAVE_StartDemandFeedPlayback( MV_ServiceGus, 1,
+            MV_Bits, MV_RequestedMixRate, 0, ( MV_Channels == 1 ) ?
+            0 : 24, 255, 0xffff, 0 );
+         if ( status < GUSWAVE_Ok )
+            {
+            MV_SetErrorCode( MV_BlasterError );
+            return( MV_Error );
+            }
+
+         if ( MV_Channels == 2 )
+            {
+            status = GUSWAVE_StartDemandFeedPlayback( MV_ServiceRightGus, 1,
+               MV_Bits, MV_RequestedMixRate, 0, 8, 255, 0xffff, 0 );
+            if ( status < GUSWAVE_Ok )
+               {
+               GUSWAVE_KillAllVoices();
+               MV_SetErrorCode( MV_BlasterError );
+               return( MV_Error );
+               }
+            }
+
+         MV_MixRate = MV_RequestedMixRate;
+         MV_DMAChannel = -1;
+         break;
+
+      case ProAudioSpectrum :
+      case SoundMan16 :
+         status = PAS_BeginBufferedPlayback( MV_MixBuffer[ 0 ],
+            TotalBufferSize, MV_NumberOfBuffers,
+            MV_RequestedMixRate, MV_MixMode, MV_ServiceVoc );
+
+         if ( status != PAS_Ok )
+            {
+            MV_SetErrorCode( MV_PasError );
+            return( MV_Error );
+            }
+
+         MV_MixRate = PAS_GetPlaybackRate();
+         MV_DMAChannel = PAS_DMAChannel;
+         break;
+
+      case SoundScape :
+         status = SOUNDSCAPE_BeginBufferedPlayback( MV_MixBuffer[ 0 ],
+            TotalBufferSize, MV_NumberOfBuffers, MV_RequestedMixRate,
+            MV_MixMode, MV_ServiceVoc );
+
+         if ( status != SOUNDSCAPE_Ok )
+            {
+            MV_SetErrorCode( MV_SoundScapeError );
+            return( MV_Error );
+            }
+
+         MV_MixRate = SOUNDSCAPE_GetPlaybackRate();
+         MV_DMAChannel = SOUNDSCAPE_DMAChannel;
+         break;
+
+      #ifndef SOUNDSOURCE_OFF
+      case SoundSource :
+      case TandySoundSource :
+         SS_BeginBufferedPlayback( MV_MixBuffer[ 0 ],
+            TotalBufferSize, MV_NumberOfBuffers,
+            MV_ServiceVoc );
+         MV_MixRate = SS_SampleRate;
+         MV_DMAChannel = -1;
+         break;
+      #endif
+      }
+#else
+    status = DSL_BeginBufferedPlayback( MV_MixBuffer[ 0 ],
+            TotalBufferSize, MV_NumberOfBuffers,
+            MV_RequestedMixRate, MV_MixMode, MV_ServiceVoc );
+
+    if ( status != DSL_Ok )
+       {
+       MV_SetErrorCode( MV_BlasterError );
+       return( MV_Error );
+       }
+
+    MV_MixRate = DSL_GetPlaybackRate();
+#endif
+
+   return( MV_Ok );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MV_StopPlayback
+
+   Stops the sound playback engine.
+---------------------------------------------------------------------*/
+
+void MV_StopPlayback
+   (
+   void
+   )
+
+   {
+   VoiceNode   *voice;
+   VoiceNode   *next;
+   unsigned    flags;
+
+#ifdef PLAT_DOS
+   // Stop sound playback
+   switch( MV_SoundCard )
+      {
+      case SoundBlaster :
+      case Awe32 :
+         BLASTER_StopPlayback();
+         break;
+
+      case UltraSound :
+         GUSWAVE_KillAllVoices();
+         break;
+
+      case ProAudioSpectrum :
+      case SoundMan16 :
+         PAS_StopPlayback();
+         break;
+
+      case SoundScape :
+         SOUNDSCAPE_StopPlayback();
+         break;
+
+      #ifndef SOUNDSOURCE_OFF
+      case SoundSource :
+      case TandySoundSource :
+         SS_StopPlayback();
+         break;
+      #endif
+      }
+#else
+   DSL_StopPlayback();
+#endif
+
+   // Make sure all callbacks are done.
+   flags = DisableInterrupts();
+
+   for( voice = VoiceList.next; voice != &VoiceList; voice = next )
+      {
+      next = voice->next;
+
+      MV_StopVoice( voice );
+
+      if ( MV_CallBackFunc )
+         {
+         MV_CallBackFunc( voice->callbackval );
+         }
+      }
+
+   RestoreInterrupts( flags );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MV_StartRecording
+
+   Starts the sound recording engine.
+---------------------------------------------------------------------*/
+
+int MV_StartRecording
+   (
+   int MixRate,
+   void ( *function )( char *ptr, int length )
+   )
+
+   {
+#ifdef PLAT_DOS
+   int status;
+
+   switch( MV_SoundCard )
+      {
+      case SoundBlaster :
+      case Awe32 :
+      case ProAudioSpectrum :
+      case SoundMan16 :
+         break;
+
+      default :
+         MV_SetErrorCode( MV_UnsupportedCard );
+         return( MV_Error );
+         break;
+      }
+
+   if ( function == NULL )
+      {
+      MV_SetErrorCode( MV_NullRecordFunction );
+      return( MV_Error );
+      }
+
+   MV_StopPlayback();
+
+   // Initialize the buffers
+   ClearBuffer_DW( MV_MixBuffer[ 0 ], SILENCE_8BIT, TotalBufferSize >> 2 );
+
+   // Set the mix buffer variables
+   MV_MixPage  = 0;
+
+   MV_RecordFunc = function;
+
+   // Start playback
+   switch( MV_SoundCard )
+      {
+      case SoundBlaster :
+      case Awe32 :
+         status = BLASTER_BeginBufferedRecord( MV_MixBuffer[ 0 ],
+            TotalBufferSize, NumberOfBuffers, MixRate, MONO_8BIT,
+            MV_ServiceRecord );
+
+         if ( status != BLASTER_Ok )
+            {
+            MV_SetErrorCode( MV_BlasterError );
+            return( MV_Error );
+            }
+         break;
+
+      case ProAudioSpectrum :
+      case SoundMan16 :
+         status = PAS_BeginBufferedRecord( MV_MixBuffer[ 0 ],
+            TotalBufferSize, NumberOfBuffers, MixRate, MONO_8BIT,
+            MV_ServiceRecord );
+
+         if ( status != PAS_Ok )
+            {
+            MV_SetErrorCode( MV_PasError );
+            return( MV_Error );
+            }
+         break;
+      }
+
+   MV_Recording = TRUE;
+   return( MV_Ok );
+#else
+   MV_SetErrorCode( MV_UnsupportedCard );
+   return( MV_Error );
+#endif
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MV_StopRecord
+
+   Stops the sound record engine.
+---------------------------------------------------------------------*/
+
+void MV_StopRecord
+   (
+   void
+   )
+
+   {
+#ifdef PLAT_DOS
+   // Stop sound playback
+   switch( MV_SoundCard )
+      {
+      case SoundBlaster :
+      case Awe32 :
+         BLASTER_StopPlayback();
+         break;
+
+      case ProAudioSpectrum :
+      case SoundMan16 :
+         PAS_StopPlayback();
+         break;
+      }
+
+   MV_Recording = FALSE;
+   MV_StartPlayback();
+#endif
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MV_StartDemandFeedPlayback
+
+   Plays a digitized sound from a user controlled buffering system.
+---------------------------------------------------------------------*/
+
+int MV_StartDemandFeedPlayback
+   (
+   void ( *function )( char **ptr, unsigned long *length ),
+   int rate,
+   int pitchoffset,
+   int vol,
+   int left,
+   int right,
+   int priority,
+   unsigned long callbackval
+   )
+
+   {
+   VoiceNode *voice;
+
+   if ( !MV_Installed )
+      {
+      MV_SetErrorCode( MV_NotInstalled );
+      return( MV_Error );
+      }
+
+   // Request a voice from the voice pool
+   voice = MV_AllocVoice( priority );
+   if ( voice == NULL )
+      {
+      MV_SetErrorCode( MV_NoVoices );
+      return( MV_Error );
+      }
+
+   voice->wavetype    = DemandFeed;
+   voice->bits        = 8;
+   voice->GetSound    = MV_GetNextDemandFeedBlock;
+   voice->NextBlock   = NULL;
+   voice->DemandFeed  = function;
+   voice->LoopStart   = NULL;
+   voice->LoopCount   = 0;
+   voice->BlockLength = 0;
+   voice->position    = 0;
+   voice->sound       = NULL;
+   voice->length      = 0;
+   voice->BlockLength = 0;
+   voice->Playing     = TRUE;
+   voice->next        = NULL;
+   voice->prev        = NULL;
+   voice->priority    = priority;
+   voice->callbackval = callbackval;
+
+   MV_SetVoicePitch( voice, rate, pitchoffset );
+   MV_SetVoiceVolume( voice, vol, left, right );
+   MV_PlayVoice( voice );
+
+   return( voice->handle );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MV_PlayRaw
+
+   Begin playback of sound data with the given sound levels and
+   priority.
+---------------------------------------------------------------------*/
+
+int MV_PlayRaw
+   (
+   char *ptr,
+   unsigned long length,
+   unsigned rate,
+   int   pitchoffset,
+   int   vol,
+   int   left,
+   int   right,
+   int   priority,
+   unsigned long callbackval
+   )
+
+   {
+   int status;
+
+   status = MV_PlayLoopedRaw( ptr, length, NULL, NULL, rate, pitchoffset,
+      vol, left, right, priority, callbackval );
+
+   return( status );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MV_PlayLoopedRaw
+
+   Begin playback of sound data with the given sound levels and
+   priority.
+---------------------------------------------------------------------*/
+
+int MV_PlayLoopedRaw
+   (
+   char *ptr,
+   unsigned long length,
+   char *loopstart,
+   char *loopend,
+   unsigned rate,
+   int   pitchoffset,
+   int   vol,
+   int   left,
+   int   right,
+   int   priority,
+   unsigned long callbackval
+   )
+
+   {
+   VoiceNode *voice;
+
+   if ( !MV_Installed )
+      {
+      MV_SetErrorCode( MV_NotInstalled );
+      return( MV_Error );
+      }
+
+   // Request a voice from the voice pool
+   voice = MV_AllocVoice( priority );
+   if ( voice == NULL )
+      {
+      MV_SetErrorCode( MV_NoVoices );
+      return( MV_Error );
+      }
+
+   voice->wavetype    = Raw;
+   voice->bits        = 8;
+   voice->GetSound    = MV_GetNextRawBlock;
+   voice->Playing     = TRUE;
+   voice->NextBlock   = ptr;
+   voice->position    = 0;
+   voice->BlockLength = length;
+   voice->length      = 0;
+   voice->next        = NULL;
+   voice->prev        = NULL;
+   voice->priority    = priority;
+   voice->callbackval = callbackval;
+   voice->LoopStart   = loopstart;
+   voice->LoopEnd     = loopend;
+   voice->LoopSize    = ( voice->LoopEnd - voice->LoopStart ) + 1;
+
+   MV_SetVoicePitch( voice, rate, pitchoffset );
+   MV_SetVoiceVolume( voice, vol, left, right );
+   MV_PlayVoice( voice );
+
+   return( voice->handle );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MV_PlayWAV
+
+   Begin playback of sound data with the given sound levels and
+   priority.
+---------------------------------------------------------------------*/
+
+int MV_PlayWAV
+   (
+   char *ptr,
+   int   pitchoffset,
+   int   vol,
+   int   left,
+   int   right,
+   int   priority,
+   unsigned long callbackval
+   )
+
+   {
+   int status;
+
+   status = MV_PlayLoopedWAV( ptr, -1, -1, pitchoffset, vol, left, right,
+      priority, callbackval );
+
+   return( status );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MV_PlayWAV3D
+
+   Begin playback of sound data at specified angle and distance
+   from listener.
+---------------------------------------------------------------------*/
+
+int MV_PlayWAV3D
+   (
+   char *ptr,
+   int  pitchoffset,
+   int  angle,
+   int  distance,
+   int  priority,
+   unsigned long callbackval
+   )
+
+   {
+   int left;
+   int right;
+   int mid;
+   int volume;
+   int status;
+
+   if ( !MV_Installed )
+      {
+      MV_SetErrorCode( MV_NotInstalled );
+      return( MV_Error );
+      }
+
+   if ( distance < 0 )
+      {
+      distance  = -distance;
+      angle    += MV_NumPanPositions / 2;
+      }
+
+   volume = MIX_VOLUME( distance );
+
+   // Ensure angle is within 0 - 31
+   angle &= MV_MaxPanPosition;
+
+   left  = MV_PanTable[ angle ][ volume ].left;
+   right = MV_PanTable[ angle ][ volume ].right;
+   mid   = max( 0, 255 - distance );
+
+   status = MV_PlayWAV( ptr, pitchoffset, mid, left, right, priority,
+      callbackval );
+
+   return( status );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MV_PlayLoopedWAV
+
+   Begin playback of sound data with the given sound levels and
+   priority.
+---------------------------------------------------------------------*/
+
+int MV_PlayLoopedWAV
+   (
+   char *ptr,
+   long  loopstart,
+   long  loopend,
+   int   pitchoffset,
+   int   vol,
+   int   left,
+   int   right,
+   int   priority,
+   unsigned long callbackval
+   )
+
+   {
+   riff_header   *riff;
+   format_header *format;
+   data_header   *data;
+   VoiceNode     *voice;
+   int length;
+   int absloopend;
+   int absloopstart;
+
+   if ( !MV_Installed )
+      {
+      MV_SetErrorCode( MV_NotInstalled );
+      return( MV_Error );
+      }
+
+   riff = ( riff_header * )ptr;
+
+   if ( ( strncmp( riff->RIFF, "RIFF", 4 ) != 0 ) ||
+      ( strncmp( riff->WAVE, "WAVE", 4 ) != 0 ) ||
+      ( strncmp( riff->fmt, "fmt ", 4) != 0 ) )
+      {
+      MV_SetErrorCode( MV_InvalidWAVFile );
+      return( MV_Error );
+      }
+
+   format = ( format_header * )( riff + 1 );
+   data   = ( data_header * )( ( ( char * )format ) + riff->format_size );
+
+   // Check if it's PCM data.
+   if ( format->wFormatTag != 1 )
+      {
+      MV_SetErrorCode( MV_InvalidWAVFile );
+      return( MV_Error );
+      }
+
+   if ( format->nChannels != 1 )
+      {
+      MV_SetErrorCode( MV_InvalidWAVFile );
+      return( MV_Error );
+      }
+
+   if ( ( format->nBitsPerSample != 8 ) &&
+      ( format->nBitsPerSample != 16 ) )
+      {
+      MV_SetErrorCode( MV_InvalidWAVFile );
+      return( MV_Error );
+      }
+
+   if ( strncmp( data->DATA, "data", 4 ) != 0 )
+      {
+      MV_SetErrorCode( MV_InvalidWAVFile );
+      return( MV_Error );
+      }
+
+   // Request a voice from the voice pool
+   voice = MV_AllocVoice( priority );
+   if ( voice == NULL )
+      {
+      MV_SetErrorCode( MV_NoVoices );
+      return( MV_Error );
+      }
+
+   voice->wavetype    = WAV;
+   voice->bits        = format->nBitsPerSample;
+   voice->GetSound    = MV_GetNextWAVBlock;
+
+   length = data->size;
+   absloopstart = loopstart;
+   absloopend   = loopend;
+   if ( voice->bits == 16 )
+      {
+      loopstart  *= 2;
+      data->size &= ~1;
+      loopend    *= 2;
+      length     /= 2;
+      }
+
+   loopend    = min( loopend, (long)data->size );
+   absloopend = min( absloopend, length );
+
+   voice->Playing     = TRUE;
+   voice->DemandFeed  = NULL;
+   voice->LoopStart   = NULL;
+   voice->LoopCount   = 0;
+   voice->position    = 0;
+   voice->length      = 0;
+   voice->BlockLength = absloopend;
+   voice->NextBlock   = ( char * )( data + 1 );
+   voice->next        = NULL;
+   voice->prev        = NULL;
+   voice->priority    = priority;
+   voice->callbackval = callbackval;
+   voice->LoopStart   = voice->NextBlock + loopstart;
+   voice->LoopEnd     = voice->NextBlock + loopend;
+   voice->LoopSize    = absloopend - absloopstart;
+
+   if ( ( loopstart >= (long)data->size ) || ( loopstart < 0 ) )
+      {
+      voice->LoopStart = NULL;
+      voice->LoopEnd   = NULL;
+      voice->BlockLength = length;
+      }
+
+   MV_SetVoicePitch( voice, format->nSamplesPerSec, pitchoffset );
+   MV_SetVoiceVolume( voice, vol, left, right );
+   MV_PlayVoice( voice );
+
+   return( voice->handle );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MV_PlayVOC3D
+
+   Begin playback of sound data at specified angle and distance
+   from listener.
+---------------------------------------------------------------------*/
+
+int MV_PlayVOC3D
+   (
+   char *ptr,
+   int  pitchoffset,
+   int  angle,
+   int  distance,
+   int  priority,
+   unsigned long callbackval
+   )
+
+   {
+   int left;
+   int right;
+   int mid;
+   int volume;
+   int status;
+
+   if ( !MV_Installed )
+      {
+      MV_SetErrorCode( MV_NotInstalled );
+      return( MV_Error );
+      }
+
+   if ( distance < 0 )
+      {
+      distance  = -distance;
+      angle    += MV_NumPanPositions / 2;
+      }
+
+   volume = MIX_VOLUME( distance );
+
+   // Ensure angle is within 0 - 31
+   angle &= MV_MaxPanPosition;
+
+   left  = MV_PanTable[ angle ][ volume ].left;
+   right = MV_PanTable[ angle ][ volume ].right;
+   mid   = max( 0, 255 - distance );
+
+   status = MV_PlayVOC( ptr, pitchoffset, mid, left, right, priority,
+      callbackval );
+
+   return( status );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MV_PlayVOC
+
+   Begin playback of sound data with the given sound levels and
+   priority.
+---------------------------------------------------------------------*/
+
+int MV_PlayVOC
+   (
+   char *ptr,
+   int   pitchoffset,
+   int   vol,
+   int   left,
+   int   right,
+   int   priority,
+   unsigned long callbackval
+   )
+
+   {
+   int status;
+
+   status = MV_PlayLoopedVOC( ptr, -1, -1, pitchoffset, vol, left, right,
+      priority, callbackval );
+
+   return( status );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MV_PlayLoopedVOC
+
+   Begin playback of sound data with the given sound levels and
+   priority.
+---------------------------------------------------------------------*/
+
+int MV_PlayLoopedVOC
+   (
+   char *ptr,
+   long  loopstart,
+   long  loopend,
+   int   pitchoffset,
+   int   vol,
+   int   left,
+   int   right,
+   int   priority,
+   unsigned long callbackval
+   )
+
+   {
+   VoiceNode   *voice;
+   int          status;
+   unsigned short nextpos;
+
+   if ( !MV_Installed )
+      {
+      MV_SetErrorCode( MV_NotInstalled );
+      return( MV_Error );
+      }
+
+   // Make sure it's a valid VOC file.
+   status = strncmp( ptr, "Creative Voice File", 19 );
+   if ( status != 0 )
+      {
+      MV_SetErrorCode( MV_InvalidVOCFile );
+      return( MV_Error );
+      }
+
+   // Request a voice from the voice pool
+   voice = MV_AllocVoice( priority );
+   if ( voice == NULL )
+      {
+      MV_SetErrorCode( MV_NoVoices );
+      return( MV_Error );
+      }
+
+   voice->wavetype    = VOC;
+   voice->bits        = 8;
+   voice->GetSound    = MV_GetNextVOCBlock;
+
+   nextpos = *( unsigned short * )( ptr + 0x14 );
+   voice->NextBlock   = ptr + BUILDSWAP_INTEL16(nextpos);
+
+   voice->DemandFeed  = NULL;
+   voice->LoopStart   = NULL;
+   voice->LoopCount   = 0;
+   voice->BlockLength = 0;
+   voice->PitchScale  = PITCH_GetScale( pitchoffset );
+   voice->length      = 0;
+   voice->next        = NULL;
+   voice->prev        = NULL;
+   voice->priority    = priority;
+   voice->callbackval = callbackval;
+   voice->LoopStart   = ( char * )loopstart;
+   voice->LoopEnd     = ( char * )loopend;
+   voice->LoopSize    = loopend - loopstart + 1;
+
+   if ( loopstart < 0 )
+      {
+      voice->LoopStart = NULL;
+      voice->LoopEnd   = NULL;
+      }
+
+   MV_SetVoiceVolume( voice, vol, left, right );
+   MV_PlayVoice( voice );
+
+   return( voice->handle );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MV_LockEnd
+
+   Used for determining the length of the functions to lock in memory.
+---------------------------------------------------------------------*/
+
+static void MV_LockEnd
+   (
+   void
+   )
+
+   {
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MV_CreateVolumeTable
+
+   Create the table used to convert sound data to a specific volume
+   level.
+---------------------------------------------------------------------*/
+
+void MV_CreateVolumeTable
+   (
+   int index,
+   int volume,
+   int MaxVolume
+   )
+
+   {
+   int val;
+   int level;
+   int i;
+
+   level = ( volume * MaxVolume ) / MV_MaxTotalVolume;
+   if ( MV_Bits == 16 )
+      {
+      for( i = 0; i < 65536; i += 256 )
+         {
+         val   = i - 0x8000;
+         val  *= level;
+         val  /= MV_MaxVolume;
+         MV_VolumeTable[ index ][ i / 256 ] = val;
+         }
+      }
+   else
+      {
+      for( i = 0; i < 256; i++ )
+         {
+         val   = i - 0x80;
+         val  *= level;
+         val  /= MV_MaxVolume;
+         MV_VolumeTable[ volume ][ i ] = val;
+         }
+      }
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MV_CalcVolume
+
+   Create the table used to convert sound data to a specific volume
+   level.
+---------------------------------------------------------------------*/
+
+void MV_CalcVolume
+   (
+   int MaxVolume
+   )
+
+   {
+   int volume;
+
+   for( volume = 0; volume < 128; volume++ )
+      {
+      MV_HarshClipTable[ volume ] = 0;
+      MV_HarshClipTable[ volume + 384 ] = 255;
+      }
+   for( volume = 0; volume < 256; volume++ )
+      {
+      MV_HarshClipTable[ volume + 128 ] = volume;
+      }
+
+   // For each volume level, create a translation table with the
+   // appropriate volume calculated.
+   for( volume = 0; volume <= MV_MaxVolume; volume++ )
+      {
+      MV_CreateVolumeTable( volume, volume, MaxVolume );
+      }
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MV_CalcPanTable
+
+   Create the table used to determine the stereo volume level of
+   a sound located at a specific angle and distance from the listener.
+---------------------------------------------------------------------*/
+
+void MV_CalcPanTable
+   (
+   void
+   )
+
+   {
+   int   level;
+   int   angle;
+   int   distance;
+   int   HalfAngle;
+   int   ramp;
+
+   HalfAngle = ( MV_NumPanPositions / 2 );
+
+   for( distance = 0; distance <= MV_MaxVolume; distance++ )
+      {
+      level = ( 255 * ( MV_MaxVolume - distance ) ) / MV_MaxVolume;
+      for( angle = 0; angle <= HalfAngle / 2; angle++ )
+         {
+         ramp = level - ( ( level * angle ) /
+            ( MV_NumPanPositions / 4 ) );
+
+         MV_PanTable[ angle ][ distance ].left = ramp;
+         MV_PanTable[ HalfAngle - angle ][ distance ].left = ramp;
+         MV_PanTable[ HalfAngle + angle ][ distance ].left = level;
+         MV_PanTable[ MV_MaxPanPosition - angle ][ distance ].left = level;
+
+         MV_PanTable[ angle ][ distance ].right = level;
+         MV_PanTable[ HalfAngle - angle ][ distance ].right = level;
+         MV_PanTable[ HalfAngle + angle ][ distance ].right = ramp;
+         MV_PanTable[ MV_MaxPanPosition - angle ][ distance ].right = ramp;
+         }
+      }
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MV_SetVolume
+
+   Sets the volume of digitized sound playback.
+---------------------------------------------------------------------*/
+
+void MV_SetVolume
+   (
+   int volume
+   )
+
+   {
+   volume = max( 0, volume );
+   volume = min( volume, MV_MaxTotalVolume );
+
+   MV_TotalVolume = volume;
+
+   // Calculate volume table
+   MV_CalcVolume( volume );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MV_GetVolume
+
+   Returns the volume of digitized sound playback.
+---------------------------------------------------------------------*/
+
+int MV_GetVolume
+   (
+   void
+   )
+
+   {
+   return( MV_TotalVolume );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MV_SetCallBack
+
+   Set the function to call when a voice stops.
+---------------------------------------------------------------------*/
+
+void MV_SetCallBack
+   (
+   void ( *function )( unsigned long )
+   )
+
+   {
+   MV_CallBackFunc = function;
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MV_SetReverseStereo
+
+   Set the orientation of the left and right channels.
+---------------------------------------------------------------------*/
+
+void MV_SetReverseStereo
+   (
+   int setting
+   )
+
+   {
+   MV_SwapLeftRight = setting;
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MV_GetReverseStereo
+
+   Returns the orientation of the left and right channels.
+---------------------------------------------------------------------*/
+
+int MV_GetReverseStereo
+   (
+   void
+   )
+
+   {
+   return( MV_SwapLeftRight );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MV_TestPlayback
+
+   Checks if playback has started.
+---------------------------------------------------------------------*/
+
+int MV_TestPlayback
+   (
+   void
+   )
+
+   {
+#ifdef PLAT_DOS
+   unsigned flags;
+   long time;
+   int  start;
+   int  status;
+   int  pos;
+
+   if ( MV_SoundCard == UltraSound )
+      {
+      return( MV_Ok );
+      }
+
+   flags = DisableInterrupts();
+   _enable();
+
+   status = MV_Error;
+   start  = MV_MixPage;
+   time   = clock() + CLOCKS_PER_SEC * 2;
+
+   while( clock() < time )
+      {
+      if ( MV_MixPage != start )
+         {
+         status = MV_Ok;
+         }
+      }
+
+   RestoreInterrupts( flags );
+
+   if ( status != MV_Ok )
+      {
+      // Just in case an error doesn't get reported
+      MV_SetErrorCode( MV_DMAFailure );
+
+      switch( MV_SoundCard )
+         {
+         case SoundBlaster :
+         case Awe32 :
+            pos = BLASTER_GetCurrentPos();
+            break;
+
+         case ProAudioSpectrum :
+         case SoundMan16 :
+            pos = PAS_GetCurrentPos();
+            break;
+
+         case SoundScape :
+            pos = SOUNDSCAPE_GetCurrentPos();
+            break;
+
+         #ifndef SOUNDSOURCE_OFF
+         case SoundSource :
+         case TandySoundSource :
+            MV_SetErrorCode( MV_SoundSourceFailure );
+            pos = -1;
+            break;
+         #endif
+
+         default :
+            MV_SetErrorCode( MV_UnsupportedCard );
+            pos = -2;
+            break;
+         }
+
+      if ( pos > 0 )
+         {
+         MV_SetErrorCode( MV_IrqFailure );
+         }
+      else if ( pos == 0 )
+         {
+         if ( MV_Bits == 16 )
+            {
+            MV_SetErrorCode( MV_DMA16Failure );
+            }
+         else
+            {
+            MV_SetErrorCode( MV_DMAFailure );
+            }
+         }
+      }
+
+   return( status );
+#else
+   return MV_Ok;
+#endif
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MV_Init
+
+   Perform the initialization of variables and memory used by
+   Multivoc.
+---------------------------------------------------------------------*/
+
+int MV_Init
+   (
+   int soundcard,
+   int MixRate,
+   int Voices,
+   int numchannels,
+   int samplebits
+   )
+
+   {
+   char *ptr;
+   int  status;
+   int  buffer;
+   int  index;
+
+   if ( MV_Installed )
+      {
+      MV_Shutdown();
+      }
+
+   MV_SetErrorCode( MV_Ok );
+
+   status = MV_LockMemory();
+   if ( status != MV_Ok )
+      {
+      return( status );
+      }
+
+   MV_TotalMemory = Voices * sizeof( VoiceNode ) + sizeof( HARSH_CLIP_TABLE_8 );
+   status = USRHOOKS_GetMem( ( void ** )&ptr, MV_TotalMemory );
+   if ( status != USRHOOKS_Ok )
+      {
+      MV_UnlockMemory();
+      MV_SetErrorCode( MV_NoMem );
+      return( MV_Error );
+      }
+
+   status = DPMI_LockMemory( ptr, MV_TotalMemory );
+   if ( status != DPMI_Ok )
+      {
+      USRHOOKS_FreeMem( ptr );
+      MV_UnlockMemory();
+      MV_SetErrorCode( MV_DPMI_Error );
+      return( MV_Error );
+      }
+
+   MV_Voices = ( VoiceNode * )ptr;
+   MV_HarshClipTable = ptr + ( MV_TotalMemory - sizeof( HARSH_CLIP_TABLE_8 ) );
+
+   // Set number of voices before calculating volume table
+   MV_MaxVoices = Voices;
+
+   LL_Reset( (VoiceNode *)&VoiceList, next, prev );
+   LL_Reset( (VoiceNode *)&VoicePool, next, prev );
+
+   for( index = 0; index < Voices; index++ )
+      {
+      LL_Add( (VoiceNode *)&VoicePool, &MV_Voices[ index ], next, prev );
+      }
+
+   // Allocate mix buffer within 1st megabyte
+   status = DPMI_GetDOSMemory( ( void ** )&ptr, &MV_BufferDescriptor,
+      2 * TotalBufferSize );
+
+   if ( status )
+      {
+      DPMI_UnlockMemory( MV_Voices, MV_TotalMemory );
+      USRHOOKS_FreeMem( MV_Voices );
+      MV_Voices      = NULL;
+      MV_TotalMemory = 0;
+      MV_UnlockMemory();
+
+      MV_SetErrorCode( MV_NoMem );
+      return( MV_Error );
+      }
+
+   MV_SetReverseStereo( FALSE );
+
+   // Initialize the sound card
+#ifdef PLAT_DOS
+   switch( soundcard )
+      {
+      case UltraSound :
+         status = GUSWAVE_Init( 2 );
+         if ( status != GUSWAVE_Ok )
+            {
+            //JIM
+            MV_SetErrorCode( MV_BlasterError );
+            }
+         break;
+
+      case SoundBlaster :
+      case Awe32 :
+         status = BLASTER_Init();
+         if ( status != BLASTER_Ok )
+            {
+            MV_SetErrorCode( MV_BlasterError );
+            }
+
+         if ( ( BLASTER_Config.Type == SBPro ) ||
+            ( BLASTER_Config.Type == SBPro2 ) )
+            {
+            MV_SetReverseStereo( TRUE );
+            }
+         break;
+
+      case ProAudioSpectrum :
+      case SoundMan16 :
+         status = PAS_Init();
+         if ( status != PAS_Ok )
+            {
+            MV_SetErrorCode( MV_PasError );
+            }
+         break;
+
+      case SoundScape :
+         status = SOUNDSCAPE_Init();
+         if ( status != SOUNDSCAPE_Ok )
+            {
+            MV_SetErrorCode( MV_SoundScapeError );
+            }
+         break;
+
+      #ifndef SOUNDSOURCE_OFF
+      case SoundSource :
+      case TandySoundSource :
+         status = SS_Init( soundcard );
+         if ( status != SS_Ok )
+            {
+            MV_SetErrorCode( MV_SoundSourceError );
+            }
+         break;
+      #endif
+
+      default :
+         MV_SetErrorCode( MV_UnsupportedCard );
+         break;
+      }
+#else
+   status = DSL_Init();
+   if ( status != DSL_Ok )
+      {
+      MV_SetErrorCode( MV_BlasterError );
+      }
+#endif
+
+   if ( MV_ErrorCode != MV_Ok )
+      {
+      status = MV_ErrorCode;
+
+      DPMI_UnlockMemory( MV_Voices, MV_TotalMemory );
+      USRHOOKS_FreeMem( MV_Voices );
+      MV_Voices      = NULL;
+      MV_TotalMemory = 0;
+
+      DPMI_FreeDOSMemory( MV_BufferDescriptor );
+      MV_UnlockMemory();
+
+      MV_SetErrorCode( status );
+      return( MV_Error );
+      }
+
+   MV_SoundCard    = soundcard;
+   MV_Installed    = TRUE;
+   MV_CallBackFunc = NULL;
+   MV_RecordFunc   = NULL;
+   MV_Recording    = FALSE;
+   MV_ReverbLevel  = 0;
+   MV_ReverbTable  = NULL;
+
+   // Set the sampling rate
+   MV_RequestedMixRate = MixRate;
+
+   // Set Mixer to play stereo digitized sound
+   MV_SetMixMode( numchannels, samplebits );
+   MV_ReverbDelay = MV_BufferSize * 3;
+
+#ifdef PLAT_DOS
+   // Make sure we don't cross a physical page
+   if ( ( ( unsigned long )ptr & 0xffff ) + TotalBufferSize > 0x10000 )
+      {
+      ptr = ( char * )( ( ( unsigned long )ptr & 0xff0000 ) + 0x10000 );
+      }
+#endif
+
+   MV_MixBuffer[ MV_NumberOfBuffers ] = ptr;
+   for( buffer = 0; buffer < MV_NumberOfBuffers; buffer++ )
+      {
+      MV_MixBuffer[ buffer ] = ptr;
+      ptr += MV_BufferSize;
+      }
+
+   // Calculate pan table
+   MV_CalcPanTable();
+
+   MV_SetVolume( MV_MaxTotalVolume );
+
+   // Start the playback engine
+   status = MV_StartPlayback();
+   if ( status != MV_Ok )
+      {
+      // Preserve error code while we shutdown.
+      status = MV_ErrorCode;
+      MV_Shutdown();
+      MV_SetErrorCode( status );
+      return( MV_Error );
+      }
+
+   if ( MV_TestPlayback() != MV_Ok )
+      {
+      status = MV_ErrorCode;
+      MV_Shutdown();
+      MV_SetErrorCode( status );
+      return( MV_Error );
+      }
+
+   return( MV_Ok );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MV_Shutdown
+
+   Restore any resources allocated by Multivoc back to the system.
+---------------------------------------------------------------------*/
+
+int MV_Shutdown
+   (
+   void
+   )
+
+   {
+   int      buffer;
+   unsigned flags;
+
+   if ( !MV_Installed )
+      {
+      return( MV_Ok );
+      }
+
+   flags = DisableInterrupts();
+
+   MV_KillAllVoices();
+
+   MV_Installed = FALSE;
+
+   // Stop the sound recording engine
+   if ( MV_Recording )
+      {
+      MV_StopRecord();
+      }
+
+   // Stop the sound playback engine
+   MV_StopPlayback();
+
+   // Shutdown the sound card
+#ifdef PLAT_DOS
+   switch( MV_SoundCard )
+      {
+      case UltraSound :
+         GUSWAVE_Shutdown();
+         break;
+
+      case SoundBlaster :
+      case Awe32 :
+         BLASTER_Shutdown();
+         break;
+
+      case ProAudioSpectrum :
+      case SoundMan16 :
+         PAS_Shutdown();
+         break;
+
+      case SoundScape :
+         SOUNDSCAPE_Shutdown();
+         break;
+
+      #ifndef SOUNDSOURCE_OFF
+      case SoundSource :
+      case TandySoundSource :
+         SS_Shutdown();
+         break;
+      #endif
+      }
+#else
+   DSL_Shutdown();
+#endif
+
+   RestoreInterrupts( flags );
+
+   // Free any voices we allocated
+   DPMI_UnlockMemory( MV_Voices, MV_TotalMemory );
+   USRHOOKS_FreeMem( MV_Voices );
+   MV_Voices      = NULL;
+   MV_TotalMemory = 0;
+
+   LL_Reset( (VoiceNode *)&VoiceList, next, prev );
+   LL_Reset( (VoiceNode *)&VoicePool, next, prev );
+
+   MV_MaxVoices = 1;
+
+   // Release the descriptor from our mix buffer
+   DPMI_FreeDOSMemory( MV_BufferDescriptor );
+   for( buffer = 0; buffer < NumberOfBuffers; buffer++ )
+      {
+      MV_MixBuffer[ buffer ] = NULL;
+      }
+
+   return( MV_Ok );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MV_UnlockMemory
+
+   Unlocks all neccessary data.
+---------------------------------------------------------------------*/
+
+void MV_UnlockMemory
+   (
+   void
+   )
+
+   {
+   PITCH_UnlockMemory();
+
+   DPMI_UnlockMemoryRegion( MV_LockStart, MV_LockEnd );
+   DPMI_Unlock( MV_VolumeTable );
+   DPMI_Unlock( MV_PanTable );
+   DPMI_Unlock( MV_Installed );
+   DPMI_Unlock( MV_SoundCard );
+   DPMI_Unlock( MV_TotalVolume );
+   DPMI_Unlock( MV_MaxVoices );
+   DPMI_Unlock( MV_BufferSize );
+   DPMI_Unlock( MV_BufferLength );
+   DPMI_Unlock( MV_SampleSize );
+   DPMI_Unlock( MV_NumberOfBuffers );
+   DPMI_Unlock( MV_MixMode );
+   DPMI_Unlock( MV_Channels );
+   DPMI_Unlock( MV_Bits );
+   DPMI_Unlock( MV_Silence );
+   DPMI_Unlock( MV_SwapLeftRight );
+   DPMI_Unlock( MV_RequestedMixRate );
+   DPMI_Unlock( MV_MixRate );
+   DPMI_Unlock( MV_BufferDescriptor );
+   DPMI_Unlock( MV_MixBuffer );
+   DPMI_Unlock( MV_BufferEmpty );
+   DPMI_Unlock( MV_Voices );
+   DPMI_Unlock( VoiceList );
+   DPMI_Unlock( VoicePool );
+   DPMI_Unlock( MV_MixPage );
+   DPMI_Unlock( MV_VoiceHandle );
+   DPMI_Unlock( MV_CallBackFunc );
+   DPMI_Unlock( MV_RecordFunc );
+   DPMI_Unlock( MV_Recording );
+   DPMI_Unlock( MV_MixFunction );
+   DPMI_Unlock( MV_HarshClipTable );
+   DPMI_Unlock( MV_MixDestination );
+   DPMI_Unlock( MV_LeftVolume );
+   DPMI_Unlock( MV_RightVolume );
+   DPMI_Unlock( MV_MixPosition );
+   DPMI_Unlock( MV_ErrorCode );
+   DPMI_Unlock( MV_DMAChannel );
+   DPMI_Unlock( MV_BuffShift );
+   DPMI_Unlock( MV_ReverbLevel );
+   DPMI_Unlock( MV_ReverbDelay );
+   DPMI_Unlock( MV_ReverbTable );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MV_LockMemory
+
+   Locks all neccessary data.
+---------------------------------------------------------------------*/
+
+int MV_LockMemory
+   (
+   void
+   )
+
+   {
+   int status;
+   int pitchstatus;
+
+   status  = DPMI_LockMemoryRegion( MV_LockStart, MV_LockEnd );
+   status |= DPMI_Lock( MV_VolumeTable );
+   status |= DPMI_Lock( MV_PanTable );
+   status |= DPMI_Lock( MV_Installed );
+   status |= DPMI_Lock( MV_SoundCard );
+   status |= DPMI_Lock( MV_TotalVolume );
+   status |= DPMI_Lock( MV_MaxVoices );
+   status |= DPMI_Lock( MV_BufferSize );
+   status |= DPMI_Lock( MV_BufferLength );
+   status |= DPMI_Lock( MV_SampleSize );
+   status |= DPMI_Lock( MV_NumberOfBuffers );
+   status |= DPMI_Lock( MV_MixMode );
+   status |= DPMI_Lock( MV_Channels );
+   status |= DPMI_Lock( MV_Bits );
+   status |= DPMI_Lock( MV_Silence );
+   status |= DPMI_Lock( MV_SwapLeftRight );
+   status |= DPMI_Lock( MV_RequestedMixRate );
+   status |= DPMI_Lock( MV_MixRate );
+   status |= DPMI_Lock( MV_BufferDescriptor );
+   status |= DPMI_Lock( MV_MixBuffer );
+   status |= DPMI_Lock( MV_BufferEmpty );
+   status |= DPMI_Lock( MV_Voices );
+   status |= DPMI_Lock( VoiceList );
+   status |= DPMI_Lock( VoicePool );
+   status |= DPMI_Lock( MV_MixPage );
+   status |= DPMI_Lock( MV_VoiceHandle );
+   status |= DPMI_Lock( MV_CallBackFunc );
+   status |= DPMI_Lock( MV_RecordFunc );
+   status |= DPMI_Lock( MV_Recording );
+   status |= DPMI_Lock( MV_MixFunction );
+   status |= DPMI_Lock( MV_HarshClipTable );
+   status |= DPMI_Lock( MV_MixDestination );
+   status |= DPMI_Lock( MV_LeftVolume );
+   status |= DPMI_Lock( MV_RightVolume );
+   status |= DPMI_Lock( MV_MixPosition );
+   status |= DPMI_Lock( MV_ErrorCode );
+   status |= DPMI_Lock( MV_DMAChannel );
+   status |= DPMI_Lock( MV_BuffShift );
+   status |= DPMI_Lock( MV_ReverbLevel );
+   status |= DPMI_Lock( MV_ReverbDelay );
+   status |= DPMI_Lock( MV_ReverbTable );
+
+   pitchstatus = PITCH_LockMemory();
+   if ( ( pitchstatus != PITCH_Ok ) || ( status != DPMI_Ok ) )
+      {
+      MV_UnlockMemory();
+      MV_SetErrorCode( MV_DPMI_Error );
+      return( MV_Error );
+      }
+
+   return( MV_Ok );
+   }
+
+#ifndef PLAT_DOS
+void ClearBuffer_DW( void *ptr, unsigned data, int length )
+{
+	unsigned *d = (unsigned *)ptr;
+	
+	while (length--) {
+		*d = data;
+		
+		d++;
+	}
+}
+#endif
--- /dev/null
+++ b/rott/audiolib/multivoc.h
@@ -1,0 +1,123 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+/**********************************************************************
+   file:   MULTIVOC.H
+
+   author: James R. Dose
+   date:   December 20, 1993
+
+   Public header for MULTIVOC.C
+
+   (c) Copyright 1993 James R. Dose.  All Rights Reserved.
+**********************************************************************/
+
+#ifndef __MULTIVOC_H
+#define __MULTIVOC_H
+
+// platform.h is in buildengine, but I need the byteswapping macros... --ryan.
+#include "platform.h"
+
+#define MV_MinVoiceHandle  1
+
+extern int MV_ErrorCode;
+
+enum MV_Errors
+   {
+   MV_Warning = -2,
+   MV_Error   = -1,
+   MV_Ok      = 0,
+   MV_UnsupportedCard,
+   MV_NotInstalled,
+   MV_NoVoices,
+   MV_NoMem,
+   MV_VoiceNotFound,
+   MV_BlasterError,
+   MV_PasError,
+   MV_SoundScapeError,
+   MV_SoundSourceError,
+   MV_DPMI_Error,
+   MV_InvalidVOCFile,
+   MV_InvalidWAVFile,
+   MV_InvalidMixMode,
+   MV_SoundSourceFailure,
+   MV_IrqFailure,
+   MV_DMAFailure,
+   MV_DMA16Failure,
+   MV_NullRecordFunction
+   };
+
+char *MV_ErrorString( int ErrorNumber );
+int   MV_VoicePlaying( int handle );
+int   MV_KillAllVoices( void );
+int   MV_Kill( int handle );
+int   MV_VoicesPlaying( void );
+int   MV_VoiceAvailable( int priority );
+int   MV_SetPitch( int handle, int pitchoffset );
+int   MV_SetFrequency( int handle, int frequency );
+int   MV_EndLooping( int handle );
+int   MV_SetPan( int handle, int vol, int left, int right );
+int   MV_Pan3D( int handle, int angle, int distance );
+void  MV_SetReverb( int reverb );
+void  MV_SetFastReverb( int reverb );
+int   MV_GetMaxReverbDelay( void );
+int   MV_GetReverbDelay( void );
+void  MV_SetReverbDelay( int delay );
+int   MV_SetMixMode( int numchannels, int samplebits );
+int   MV_StartPlayback( void );
+void  MV_StopPlayback( void );
+int   MV_StartRecording( int MixRate, void ( *function )( char *ptr, int length ) );
+void  MV_StopRecord( void );
+int   MV_StartDemandFeedPlayback( void ( *function )( char **ptr, unsigned long *length ),
+         int rate, int pitchoffset, int vol, int left, int right,
+         int priority, unsigned long callbackval );
+int   MV_PlayRaw( char *ptr, unsigned long length,
+         unsigned rate, int pitchoffset, int vol, int left,
+         int right, int priority, unsigned long callbackval );
+int   MV_PlayLoopedRaw( char *ptr, unsigned long length,
+         char *loopstart, char *loopend, unsigned rate, int pitchoffset,
+         int vol, int left, int right, int priority,
+         unsigned long callbackval );
+int   MV_PlayWAV( char *ptr, int pitchoffset, int vol, int left,
+         int right, int priority, unsigned long callbackval );
+int   MV_PlayWAV3D( char *ptr, int pitchoffset, int angle, int distance,
+         int priority, unsigned long callbackval );
+int   MV_PlayLoopedWAV( char *ptr, long loopstart, long loopend,
+         int pitchoffset, int vol, int left, int right, int priority,
+         unsigned long callbackval );
+int   MV_PlayVOC3D( char *ptr, int pitchoffset, int angle, int distance,
+         int priority, unsigned long callbackval );
+int   MV_PlayVOC( char *ptr, int pitchoffset, int vol, int left, int right,
+         int priority, unsigned long callbackval );
+int   MV_PlayLoopedVOC( char *ptr, long loopstart, long loopend,
+         int pitchoffset, int vol, int left, int right, int priority,
+         unsigned long callbackval );
+void  MV_CreateVolumeTable( int index, int volume, int MaxVolume );
+void  MV_SetVolume( int volume );
+int   MV_GetVolume( void );
+void  MV_SetCallBack( void ( *function )( unsigned long ) );
+void  MV_SetReverseStereo( int setting );
+int   MV_GetReverseStereo( void );
+int   MV_Init( int soundcard, int MixRate, int Voices, int numchannels,
+         int samplebits );
+int   MV_Shutdown( void );
+void  MV_UnlockMemory( void );
+int   MV_LockMemory( void );
+
+#endif
--- /dev/null
+++ b/rott/audiolib/music.c
@@ -1,0 +1,1035 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+/**********************************************************************
+   module: MUSIC.C
+
+   author: James R. Dose
+   date:   March 25, 1994
+
+   Device independant music playback routines.
+
+   (c) Copyright 1994 James R. Dose.  All Rights Reserved.
+**********************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "task_man.h"
+#include "sndcards.h"
+#include "music.h"
+#include "midi.h"
+#include "al_midi.h"
+#include "pas16.h"
+#include "blaster.h"
+#include "gusmidi.h"
+#include "mpu401.h"
+#include "awe32.h"
+#include "sndscape.h"
+#include "ll_man.h"
+#include "user.h"
+
+#define TRUE  ( 1 == 1 )
+#define FALSE ( !TRUE )
+
+void TextMode( void );
+#pragma aux TextMode =  \
+    "mov    ax, 0003h", \
+    "int    10h"        \
+    modify [ ax ];
+
+int MUSIC_SoundDevice = -1;
+int MUSIC_ErrorCode = MUSIC_Ok;
+
+static midifuncs MUSIC_MidiFunctions;
+
+static int       MUSIC_FadeLength;
+static int       MUSIC_FadeRate;
+static unsigned  MUSIC_CurrentFadeVolume;
+static unsigned  MUSIC_LastFadeVolume;
+static int       MUSIC_EndingFadeVolume;
+static task     *MUSIC_FadeTask = NULL;
+
+int MUSIC_InitAWE32( midifuncs *Funcs );
+int MUSIC_InitFM( int card, midifuncs *Funcs );
+int MUSIC_InitMidi( int card, midifuncs *Funcs, int Address );
+int MUSIC_InitGUS( midifuncs *Funcs );
+
+#define MUSIC_SetErrorCode( status ) \
+   MUSIC_ErrorCode = ( status );
+
+/*---------------------------------------------------------------------
+   Function: MUSIC_ErrorString
+
+   Returns a pointer to the error message associated with an error
+   number.  A -1 returns a pointer the current error.
+---------------------------------------------------------------------*/
+
+char *MUSIC_ErrorString
+   (
+   int ErrorNumber
+   )
+
+   {
+   char *ErrorString;
+
+   switch( ErrorNumber )
+      {
+      case MUSIC_Warning :
+      case MUSIC_Error :
+         ErrorString = MUSIC_ErrorString( MUSIC_ErrorCode );
+         break;
+
+      case MUSIC_Ok :
+         ErrorString = "Music ok.";
+         break;
+
+      case MUSIC_ASSVersion :
+         ErrorString = "Apogee Sound System Version " ASS_VERSION_STRING "  "
+            "Programmed by Jim Dose\n"
+            "(c) Copyright 1996 James R. Dose.  All Rights Reserved.\n";
+         break;
+
+      case MUSIC_SoundCardError :
+         switch( MUSIC_SoundDevice )
+         {
+            case SoundBlaster :
+            case WaveBlaster :
+               ErrorString = BLASTER_ErrorString( BLASTER_Error );
+               break;
+
+            case ProAudioSpectrum :
+            case SoundMan16 :
+               ErrorString = PAS_ErrorString( PAS_Error );
+               break;
+
+            case Adlib :
+               ErrorString = "Adlib error.";
+               break;
+
+            case GenMidi :
+            case SoundCanvas :
+               ErrorString = "Could not detect MPU-401.";
+               break;
+
+            case SoundScape :
+               ErrorString = SOUNDSCAPE_ErrorString( SOUNDSCAPE_Error );
+               break;
+
+            case Awe32 :
+               ErrorString = AWE32_ErrorString( AWE32_Error );
+               break;
+
+            case UltraSound :
+               ErrorString = GUS_ErrorString( GUS_Error );
+               break;
+
+            default :
+               ErrorString = MUSIC_ErrorString( MUSIC_InvalidCard );
+               break;
+            }
+         break;
+
+      case MUSIC_MPU401Error :
+         ErrorString = "Could not detect MPU-401.";
+         break;
+
+      case MUSIC_InvalidCard :
+         ErrorString = "Invalid Music device.";
+         break;
+
+      case MUSIC_MidiError :
+         ErrorString = "Error playing MIDI file.";
+         break;
+
+      case MUSIC_TaskManError :
+         ErrorString = "TaskMan error.";
+         break;
+
+      case MUSIC_FMNotDetected :
+         ErrorString = "Could not detect FM chip.";
+         break;
+
+      case MUSIC_DPMI_Error :
+         ErrorString = "DPMI Error in MUSIC.";
+         break;
+
+      default :
+         ErrorString = "Unknown Music error code.";
+         break;
+      }
+
+   return( ErrorString );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MUSIC_Init
+
+   Selects which sound device to use.
+---------------------------------------------------------------------*/
+
+int MUSIC_Init
+   (
+   int SoundCard,
+   int Address
+   )
+
+   {
+   int i;
+   int status;
+
+   if ( USER_CheckParameter( "ASSVER" ) )
+      {
+      MUSIC_SetErrorCode( MUSIC_ASSVersion );
+      return( MUSIC_Error );
+      }
+
+   status = LL_LockMemory();
+   if ( status != LL_Ok )
+      {
+      MUSIC_SetErrorCode( MUSIC_DPMI_Error );
+      return( MUSIC_Error );
+      }
+
+   for( i = 0; i < 128; i++ )
+      {
+      MIDI_PatchMap[ i ] = i;
+      }
+
+   status = MUSIC_Ok;
+   MUSIC_SoundDevice = SoundCard;
+
+   switch( SoundCard )
+      {
+      case SoundBlaster :
+      case Adlib :
+      case ProAudioSpectrum :
+      case SoundMan16 :
+         status = MUSIC_InitFM( SoundCard, &MUSIC_MidiFunctions );
+         break;
+
+      case GenMidi :
+      case SoundCanvas :
+      case WaveBlaster :
+      case SoundScape :
+         status = MUSIC_InitMidi( SoundCard, &MUSIC_MidiFunctions, Address );
+         break;
+
+      case Awe32 :
+         status = MUSIC_InitAWE32( &MUSIC_MidiFunctions );
+         break;
+
+      case UltraSound :
+         status = MUSIC_InitGUS( &MUSIC_MidiFunctions );
+         break;
+
+      case SoundSource :
+      case PC :
+      default :
+         MUSIC_SetErrorCode( MUSIC_InvalidCard );
+         status = MUSIC_Error;
+      }
+
+   if ( status != MUSIC_Ok )
+      {
+      LL_UnlockMemory();
+      }
+
+   return( status );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MUSIC_Shutdown
+
+   Terminates use of sound device.
+---------------------------------------------------------------------*/
+
+int MUSIC_Shutdown
+   (
+   void
+   )
+
+   {
+   int status;
+
+   status = MUSIC_Ok;
+
+   MIDI_StopSong();
+
+   if ( MUSIC_FadeTask != NULL )
+      {
+      MUSIC_StopFade();
+      }
+
+   switch ( MUSIC_SoundDevice )
+      {
+      case Adlib :
+         AL_Shutdown();
+         break;
+
+      case SoundBlaster :
+         AL_Shutdown();
+         BLASTER_RestoreMidiVolume();
+         break;
+
+      case GenMidi :
+      case SoundCanvas :
+      case SoundScape :
+         MPU_Reset();
+         break;
+
+      case WaveBlaster :
+         BLASTER_ShutdownWaveBlaster();
+         MPU_Reset();
+         BLASTER_RestoreMidiVolume();
+         break;
+
+      case Awe32 :
+         AWE32_Shutdown();
+         BLASTER_RestoreMidiVolume();
+         break;
+
+      case ProAudioSpectrum :
+      case SoundMan16 :
+         AL_Shutdown();
+         PAS_RestoreMusicVolume();
+         break;
+
+      case UltraSound :
+         GUSMIDI_Shutdown();
+         break;
+      }
+
+   LL_UnlockMemory();
+
+   return( status );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MUSIC_SetMaxFMMidiChannel
+
+   Sets the maximum MIDI channel that FM cards respond to.
+---------------------------------------------------------------------*/
+
+void MUSIC_SetMaxFMMidiChannel
+   (
+   int channel
+   )
+
+   {
+   AL_SetMaxMidiChannel( channel );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MUSIC_SetVolume
+
+   Sets the volume of music playback.
+---------------------------------------------------------------------*/
+
+void MUSIC_SetVolume
+   (
+   int volume
+   )
+
+   {
+   volume = max( 0, volume );
+   volume = min( volume, 255 );
+
+   if ( MUSIC_SoundDevice != -1 )
+      {
+      MIDI_SetVolume( volume );
+      }
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MUSIC_SetMidiChannelVolume
+
+   Sets the volume of music playback on the specified MIDI channel.
+---------------------------------------------------------------------*/
+
+void MUSIC_SetMidiChannelVolume
+   (
+   int channel,
+   int volume
+   )
+
+   {
+   MIDI_SetUserChannelVolume( channel, volume );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MUSIC_ResetMidiChannelVolumes
+
+   Sets the volume of music playback on all MIDI channels to full volume.
+---------------------------------------------------------------------*/
+
+void MUSIC_ResetMidiChannelVolumes
+   (
+   void
+   )
+
+   {
+   MIDI_ResetUserChannelVolume();
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MUSIC_GetVolume
+
+   Returns the volume of music playback.
+---------------------------------------------------------------------*/
+
+int MUSIC_GetVolume
+   (
+   void
+   )
+
+   {
+   if ( MUSIC_SoundDevice == -1 )
+      {
+      return( 0 );
+      }
+   return( MIDI_GetVolume() );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MUSIC_SetLoopFlag
+
+   Set whether the music will loop or end when it reaches the end of
+   the song.
+---------------------------------------------------------------------*/
+
+void MUSIC_SetLoopFlag
+   (
+   int loopflag
+   )
+
+   {
+   MIDI_SetLoopFlag( loopflag );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MUSIC_SongPlaying
+
+   Returns whether there is a song playing.
+---------------------------------------------------------------------*/
+
+int MUSIC_SongPlaying
+   (
+   void
+   )
+
+   {
+   return( MIDI_SongPlaying() );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MUSIC_Continue
+
+   Continues playback of a paused song.
+---------------------------------------------------------------------*/
+
+void MUSIC_Continue
+   (
+   void
+   )
+
+   {
+   MIDI_ContinueSong();
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MUSIC_Pause
+
+   Pauses playback of a song.
+---------------------------------------------------------------------*/
+
+void MUSIC_Pause
+   (
+   void
+   )
+
+   {
+   MIDI_PauseSong();
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MUSIC_StopSong
+
+   Stops playback of current song.
+---------------------------------------------------------------------*/
+
+int MUSIC_StopSong
+   (
+   void
+   )
+
+   {
+   MUSIC_StopFade();
+   MIDI_StopSong();
+   MUSIC_SetErrorCode( MUSIC_Ok );
+   return( MUSIC_Ok );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MUSIC_PlaySong
+
+   Begins playback of MIDI song.
+---------------------------------------------------------------------*/
+
+int MUSIC_PlaySong
+   (
+   unsigned char *song,
+   int loopflag
+   )
+
+   {
+   int status;
+
+   switch( MUSIC_SoundDevice )
+      {
+      case SoundBlaster :
+      case Adlib :
+      case ProAudioSpectrum :
+      case SoundMan16 :
+      case GenMidi :
+      case SoundCanvas :
+      case WaveBlaster :
+      case SoundScape :
+      case Awe32 :
+      case UltraSound :
+         MIDI_StopSong();
+         status = MIDI_PlaySong( song, loopflag );
+         if ( status != MIDI_Ok )
+            {
+            MUSIC_SetErrorCode( MUSIC_MidiError );
+            return( MUSIC_Warning );
+            }
+         break;
+
+      case SoundSource :
+      case PC :
+      default :
+         MUSIC_SetErrorCode( MUSIC_InvalidCard );
+         return( MUSIC_Warning );
+         break;
+      }
+
+   return( MUSIC_Ok );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MUSIC_SetContext
+
+   Sets the song context.
+---------------------------------------------------------------------*/
+
+void MUSIC_SetContext
+   (
+   int context
+   )
+
+   {
+   MIDI_SetContext( context );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MUSIC_GetContext
+
+   Returns the current song context.
+---------------------------------------------------------------------*/
+
+int MUSIC_GetContext
+   (
+   void
+   )
+
+   {
+   return MIDI_GetContext();
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MUSIC_SetSongTick
+
+   Sets the position of the song pointer.
+---------------------------------------------------------------------*/
+
+void MUSIC_SetSongTick
+   (
+   unsigned long PositionInTicks
+   )
+
+   {
+   MIDI_SetSongTick( PositionInTicks );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MUSIC_SetSongTime
+
+   Sets the position of the song pointer.
+---------------------------------------------------------------------*/
+
+void MUSIC_SetSongTime
+   (
+   unsigned long milliseconds
+   )
+
+   {
+   MIDI_SetSongTime( milliseconds );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MUSIC_SetSongPosition
+
+   Sets the position of the song pointer.
+---------------------------------------------------------------------*/
+
+void MUSIC_SetSongPosition
+   (
+   int measure,
+   int beat,
+   int tick
+   )
+
+   {
+   MIDI_SetSongPosition( measure, beat, tick );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MUSIC_GetSongPosition
+
+   Returns the position of the song pointer.
+---------------------------------------------------------------------*/
+
+void MUSIC_GetSongPosition
+   (
+   songposition *pos
+   )
+
+   {
+   MIDI_GetSongPosition( pos );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MUSIC_GetSongLength
+
+   Returns the length of the song.
+---------------------------------------------------------------------*/
+
+void MUSIC_GetSongLength
+   (
+   songposition *pos
+   )
+
+   {
+   MIDI_GetSongLength( pos );
+   }
+
+
+int MUSIC_InitAWE32
+   (
+   midifuncs *Funcs
+   )
+
+   {
+   int status;
+
+   status = AWE32_Init();
+   if ( status != AWE32_Ok )
+      {
+      MUSIC_SetErrorCode( MUSIC_SoundCardError );
+      return( MUSIC_Error );
+      }
+
+   Funcs->NoteOff           = AWE32_NoteOff;
+   Funcs->NoteOn            = AWE32_NoteOn;
+   Funcs->PolyAftertouch    = AWE32_PolyAftertouch;
+   Funcs->ControlChange     = AWE32_ControlChange;
+   Funcs->ProgramChange     = AWE32_ProgramChange;
+   Funcs->ChannelAftertouch = AWE32_ChannelAftertouch;
+   Funcs->PitchBend         = AWE32_PitchBend;
+   Funcs->ReleasePatches    = NULL;
+   Funcs->LoadPatch         = NULL;
+   Funcs->SetVolume         = NULL;
+   Funcs->GetVolume         = NULL;
+
+   if ( BLASTER_CardHasMixer() )
+      {
+      BLASTER_SaveMidiVolume();
+      Funcs->SetVolume = BLASTER_SetMidiVolume;
+      Funcs->GetVolume = BLASTER_GetMidiVolume;
+      }
+
+   status = MUSIC_Ok;
+   MIDI_SetMidiFuncs( Funcs );
+
+   return( status );
+   }
+
+
+int MUSIC_InitFM
+   (
+   int card,
+   midifuncs *Funcs
+   )
+
+   {
+   int status;
+   int passtatus;
+
+   status = MIDI_Ok;
+
+   if ( !AL_DetectFM() )
+      {
+      MUSIC_SetErrorCode( MUSIC_FMNotDetected );
+      return( MUSIC_Error );
+      }
+
+   // Init the fm routines
+   AL_Init( card );
+
+   Funcs->NoteOff           = AL_NoteOff;
+   Funcs->NoteOn            = AL_NoteOn;
+   Funcs->PolyAftertouch    = NULL;
+   Funcs->ControlChange     = AL_ControlChange;
+   Funcs->ProgramChange     = AL_ProgramChange;
+   Funcs->ChannelAftertouch = NULL;
+   Funcs->PitchBend         = AL_SetPitchBend;
+   Funcs->ReleasePatches    = NULL;
+   Funcs->LoadPatch         = NULL;
+   Funcs->SetVolume         = NULL;
+   Funcs->GetVolume         = NULL;
+
+   switch( card )
+      {
+      case SoundBlaster :
+         if ( BLASTER_CardHasMixer() )
+            {
+            BLASTER_SaveMidiVolume();
+            Funcs->SetVolume = BLASTER_SetMidiVolume;
+            Funcs->GetVolume = BLASTER_GetMidiVolume;
+            }
+         else
+            {
+            Funcs->SetVolume = NULL;
+            Funcs->GetVolume = NULL;
+            }
+         break;
+
+      case Adlib :
+         Funcs->SetVolume = NULL;
+         Funcs->GetVolume = NULL;
+         break;
+
+      case ProAudioSpectrum :
+      case SoundMan16 :
+         Funcs->SetVolume = NULL;
+         Funcs->GetVolume = NULL;
+
+         passtatus = PAS_SaveMusicVolume();
+         if ( passtatus == PAS_Ok )
+            {
+            Funcs->SetVolume = PAS_SetFMVolume;
+            Funcs->GetVolume = PAS_GetFMVolume;
+            }
+         break;
+      }
+
+   MIDI_SetMidiFuncs( Funcs );
+
+   return( status );
+   }
+
+int MUSIC_InitMidi
+   (
+   int        card,
+   midifuncs *Funcs,
+   int        Address
+   )
+
+   {
+   int status;
+
+   status = MUSIC_Ok;
+
+   if ( ( card == WaveBlaster ) || ( card == SoundCanvas ) ||
+      ( card == GenMidi ) )
+      {
+      // Setup WaveBlaster Daughterboard clone
+      // (ie. SoundCanvas DB, TurtleBeach Rio)
+      BLASTER_SetupWaveBlaster();
+      }
+
+   if ( card == SoundScape )
+      {
+      Address = SOUNDSCAPE_GetMIDIPort();
+      if ( Address < SOUNDSCAPE_Ok )
+         {
+         MUSIC_SetErrorCode( MUSIC_SoundCardError );
+         return( MUSIC_Error );
+         }
+      }
+
+   if ( MPU_Init( Address ) != MPU_Ok )
+      {
+      MUSIC_SetErrorCode( MUSIC_MPU401Error );
+      return( MUSIC_Error );
+      }
+
+   Funcs->NoteOff           = MPU_NoteOff;
+   Funcs->NoteOn            = MPU_NoteOn;
+   Funcs->PolyAftertouch    = MPU_PolyAftertouch;
+   Funcs->ControlChange     = MPU_ControlChange;
+   Funcs->ProgramChange     = MPU_ProgramChange;
+   Funcs->ChannelAftertouch = MPU_ChannelAftertouch;
+   Funcs->PitchBend         = MPU_PitchBend;
+   Funcs->ReleasePatches    = NULL;
+   Funcs->LoadPatch         = NULL;
+   Funcs->SetVolume         = NULL;
+   Funcs->GetVolume         = NULL;
+
+   if ( card == WaveBlaster )
+      {
+      if ( BLASTER_CardHasMixer() )
+         {
+         BLASTER_SaveMidiVolume();
+         Funcs->SetVolume = BLASTER_SetMidiVolume;
+         Funcs->GetVolume = BLASTER_GetMidiVolume;
+         }
+      }
+
+   MIDI_SetMidiFuncs( Funcs );
+
+   return( status );
+   }
+
+int MUSIC_InitGUS
+   (
+   midifuncs *Funcs
+   )
+
+   {
+   int status;
+
+   status = MUSIC_Ok;
+
+   if ( GUSMIDI_Init() != GUS_Ok )
+      {
+      MUSIC_SetErrorCode( MUSIC_SoundCardError );
+      return( MUSIC_Error );
+      }
+
+   Funcs->NoteOff           = GUSMIDI_NoteOff;
+   Funcs->NoteOn            = GUSMIDI_NoteOn;
+   Funcs->PolyAftertouch    = NULL;
+   Funcs->ControlChange     = GUSMIDI_ControlChange;
+   Funcs->ProgramChange     = GUSMIDI_ProgramChange;
+   Funcs->ChannelAftertouch = NULL;
+   Funcs->PitchBend         = GUSMIDI_PitchBend;
+   Funcs->ReleasePatches    = NULL;//GUSMIDI_ReleasePatches;
+   Funcs->LoadPatch         = NULL;//GUSMIDI_LoadPatch;
+   Funcs->SetVolume         = GUSMIDI_SetVolume;
+   Funcs->GetVolume         = GUSMIDI_GetVolume;
+
+   MIDI_SetMidiFuncs( Funcs );
+
+   return( status );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MUSIC_FadeRoutine
+
+   Fades music volume from current level to another over a specified
+   period of time.
+---------------------------------------------------------------------*/
+
+static void MUSIC_FadeRoutine
+   (
+   task *Task
+   )
+
+   {
+   int volume;
+
+   MUSIC_CurrentFadeVolume += MUSIC_FadeRate;
+   if ( MUSIC_FadeLength == 0 )
+      {
+      MIDI_SetVolume( MUSIC_EndingFadeVolume );
+      TS_Terminate( Task );
+      MUSIC_FadeTask = NULL;
+      }
+   else
+      {
+      MUSIC_FadeLength--;
+//      if ( ( MUSIC_SoundDevice == GenMidi ) &&
+//         ( ( MUSIC_FadeLength % 12 ) != 0 ) )
+//         {
+//         return;
+//         }
+
+      volume = MUSIC_CurrentFadeVolume >> 7;
+      if ( MUSIC_LastFadeVolume != volume )
+         {
+         MUSIC_LastFadeVolume = volume;
+         MIDI_SetVolume( volume );
+         }
+      }
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MUSIC_FadeVolume
+
+   Fades music volume from current level to another over a specified
+   period of time.
+---------------------------------------------------------------------*/
+
+int MUSIC_FadeVolume
+   (
+   int tovolume,
+   int milliseconds
+   )
+
+   {
+   int fromvolume;
+
+   if ( ( MUSIC_SoundDevice == ProAudioSpectrum ) ||
+      ( MUSIC_SoundDevice == SoundMan16 ) ||
+      ( MUSIC_SoundDevice == GenMidi ) ||
+      ( MUSIC_SoundDevice == SoundScape ) ||
+      ( MUSIC_SoundDevice == SoundCanvas ) )
+      {
+      MIDI_SetVolume( tovolume );
+      return( MUSIC_Ok );
+      }
+
+   if ( MUSIC_FadeTask != NULL )
+      {
+      MUSIC_StopFade();
+      }
+
+   tovolume = max( 0, tovolume );
+   tovolume = min( 255, tovolume );
+   fromvolume = MUSIC_GetVolume();
+
+   MUSIC_FadeLength = milliseconds / 25;
+   MUSIC_FadeRate   = ( ( tovolume - fromvolume ) << 7 ) / MUSIC_FadeLength;
+   MUSIC_LastFadeVolume = fromvolume;
+   MUSIC_CurrentFadeVolume = fromvolume << 7;
+   MUSIC_EndingFadeVolume = tovolume;
+
+   MUSIC_FadeTask = TS_ScheduleTask( MUSIC_FadeRoutine, 40, 1, NULL );
+   if ( MUSIC_FadeTask == NULL )
+      {
+      MUSIC_SetErrorCode( MUSIC_TaskManError );
+      return( MUSIC_Warning );
+      }
+
+   TS_Dispatch();
+   return( MUSIC_Ok );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MUSIC_FadeActive
+
+   Returns whether the fade routine is active.
+---------------------------------------------------------------------*/
+
+int MUSIC_FadeActive
+   (
+   void
+   )
+
+   {
+   return( MUSIC_FadeTask != NULL );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MUSIC_StopFade
+
+   Stops fading the music.
+---------------------------------------------------------------------*/
+
+void MUSIC_StopFade
+   (
+   void
+   )
+
+   {
+   if ( MUSIC_FadeTask != NULL )
+      {
+      TS_Terminate( MUSIC_FadeTask );
+      MUSIC_FadeTask = NULL;
+      }
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MUSIC_RerouteMidiChannel
+
+   Sets callback function to reroute MIDI commands from specified
+   function.
+---------------------------------------------------------------------*/
+
+void MUSIC_RerouteMidiChannel
+   (
+   int channel,
+   int cdecl ( *function )( int event, int c1, int c2 )
+   )
+
+   {
+   MIDI_RerouteMidiChannel( channel, function );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: MUSIC_RegisterTimbreBank
+
+   Halts playback of all sounds.
+---------------------------------------------------------------------*/
+
+void MUSIC_RegisterTimbreBank
+   (
+   unsigned char *timbres
+   )
+
+   {
+   AL_RegisterTimbreBank( timbres );
+   }
--- /dev/null
+++ b/rott/audiolib/music.h
@@ -1,0 +1,96 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+/**********************************************************************
+   module: MUSIC.H
+
+   author: James R. Dose
+   date:   March 25, 1994
+
+   Public header for MUSIC.C
+
+   (c) Copyright 1994 James R. Dose.  All Rights Reserved.
+**********************************************************************/
+
+#ifndef __MUSIC_H
+#define __MUSIC_H
+
+#include "sndcards.h"
+
+#ifndef PLAT_DOS
+#define cdecl
+#endif
+
+extern int MUSIC_ErrorCode;
+
+enum MUSIC_ERRORS
+   {
+   MUSIC_Warning = -2,
+   MUSIC_Error   = -1,
+   MUSIC_Ok      = 0,
+   MUSIC_ASSVersion,
+   MUSIC_SoundCardError,
+   MUSIC_MPU401Error,
+   MUSIC_InvalidCard,
+   MUSIC_MidiError,
+   MUSIC_TaskManError,
+   MUSIC_FMNotDetected,
+   MUSIC_DPMI_Error
+   };
+
+typedef struct
+   {
+   unsigned long tickposition;
+   unsigned long milliseconds;
+   unsigned int  measure;
+   unsigned int  beat;
+   unsigned int  tick;
+   } songposition;
+
+#define MUSIC_LoopSong ( 1 == 1 )
+#define MUSIC_PlayOnce ( !MUSIC_LoopSong )
+
+char *MUSIC_ErrorString( int ErrorNumber );
+int   MUSIC_Init( int SoundCard, int Address );
+int   MUSIC_Shutdown( void );
+void  MUSIC_SetMaxFMMidiChannel( int channel );
+void  MUSIC_SetVolume( int volume );
+void  MUSIC_SetMidiChannelVolume( int channel, int volume );
+void  MUSIC_ResetMidiChannelVolumes( void );
+int   MUSIC_GetVolume( void );
+void  MUSIC_SetLoopFlag( int loopflag );
+int   MUSIC_SongPlaying( void );
+void  MUSIC_Continue( void );
+void  MUSIC_Pause( void );
+int   MUSIC_StopSong( void );
+int   MUSIC_PlaySong( unsigned char *song, int loopflag );
+void  MUSIC_SetContext( int context );
+int   MUSIC_GetContext( void );
+void  MUSIC_SetSongTick( unsigned long PositionInTicks );
+void  MUSIC_SetSongTime( unsigned long milliseconds );
+void  MUSIC_SetSongPosition( int measure, int beat, int tick );
+void  MUSIC_GetSongPosition( songposition *pos );
+void  MUSIC_GetSongLength( songposition *pos );
+int   MUSIC_FadeVolume( int tovolume, int milliseconds );
+int   MUSIC_FadeActive( void );
+void  MUSIC_StopFade( void );
+void  MUSIC_RerouteMidiChannel( int channel, int cdecl ( *function )( int event, int c1, int c2 ) );
+void  MUSIC_RegisterTimbreBank( unsigned char *timbres );
+
+#endif
--- /dev/null
+++ b/rott/audiolib/mv_mix.asm
@@ -1,0 +1,505 @@
+        IDEAL
+
+        p386
+        MODEL  flat
+
+        dataseg
+        CODESEG
+
+        MASM
+        ALIGN 4
+
+EXTRN   _MV_HarshClipTable:DWORD
+EXTRN   _MV_MixDestination:DWORD
+EXTRN   _MV_MixPosition:DWORD
+EXTRN   _MV_LeftVolume:DWORD
+EXTRN   _MV_RightVolume:DWORD
+EXTRN   _MV_SampleSize:DWORD
+EXTRN   _MV_RightChannelOffset:DWORD
+
+;================
+;
+; MV_Mix8BitMono
+;
+;================
+
+; eax - position
+; edx - rate
+; ebx - start
+; ecx - number of samples to mix
+
+PROC    MV_Mix8BitMono_
+PUBLIC  MV_Mix8BitMono_
+; Two at once
+        pushad
+
+        mov     ebp, eax
+
+        mov     esi, ebx                        ; Source pointer
+
+        ; Sample size
+        mov     ebx, _MV_SampleSize
+        mov     eax,OFFSET apatch7+2            ; convice tasm to modify code...
+        mov     [eax],bl
+        mov     eax,OFFSET apatch8+2            ; convice tasm to modify code...
+        mov     [eax],bl
+        mov     eax,OFFSET apatch9+3            ; convice tasm to modify code...
+        mov     [eax],bl
+
+        ; Volume table ptr
+        mov     ebx, _MV_LeftVolume             ; Since we're mono, use left volume
+        mov     eax,OFFSET apatch1+4            ; convice tasm to modify code...
+        mov     [eax],ebx
+        mov     eax,OFFSET apatch2+4            ; convice tasm to modify code...
+        mov     [eax],ebx
+
+        ; Harsh Clip table ptr
+        mov     ebx, _MV_HarshClipTable
+        add     ebx, 128
+        mov     eax,OFFSET apatch3+2            ; convice tasm to modify code...
+        mov     [eax],ebx
+        mov     eax,OFFSET apatch4+2            ; convice tasm to modify code...
+        mov     [eax],ebx
+
+        ; Rate scale ptr
+        mov     eax,OFFSET apatch5+2            ; convice tasm to modify code...
+        mov     [eax],edx
+        mov     eax,OFFSET apatch6+2            ; convice tasm to modify code...
+        mov     [eax],edx
+
+        mov     edi, _MV_MixDestination         ; Get the position to write to
+
+        ; Number of samples to mix
+        shr     ecx, 1                          ; double sample count
+        cmp     ecx, 0
+        je      short exit8m
+
+;     eax - scratch
+;     ebx - scratch
+;     edx - scratch
+;     ecx - count
+;     edi - destination
+;     esi - source
+;     ebp - frac pointer
+; apatch1 - volume table
+; apatch2 - volume table
+; apatch3 - harsh clip table
+; apatch4 - harsh clip table
+; apatch5 - sample rate
+; apatch6 - sample rate
+
+        mov     eax,ebp                         ; begin calculating first sample
+        add     ebp,edx                         ; advance frac pointer
+        shr     eax,16                          ; finish calculation for first sample
+
+        mov     ebx,ebp                         ; begin calculating second sample
+        add     ebp,edx                         ; advance frac pointer
+        shr     ebx,16                          ; finish calculation for second sample
+
+        movzx   eax, byte ptr [esi+eax]         ; get first sample
+        movzx   ebx, byte ptr [esi+ebx]         ; get second sample
+
+        ALIGN 4
+mix8Mloop:
+        movzx   edx, byte ptr [edi]             ; get current sample from destination
+apatch1:
+        movsx   eax, byte ptr [2*eax+12345678h] ; volume translate first sample
+apatch2:
+        movsx   ebx, byte ptr [2*ebx+12345678h] ; volume translate second sample
+        add     eax, edx                        ; mix first sample
+apatch9:
+        movzx   edx, byte ptr [edi + 1]         ; get current sample from destination
+apatch3:
+        mov     eax, [eax + 12345678h]          ; harsh clip new sample
+        add     ebx, edx                        ; mix second sample
+        mov     [edi], al                       ; write new sample to destination
+        mov     edx, ebp                        ; begin calculating third sample
+apatch4:
+        mov     ebx, [ebx + 12345678h]          ; harsh clip new sample
+apatch5:
+        add     ebp,12345678h                   ; advance frac pointer
+        shr     edx, 16                         ; finish calculation for third sample
+        mov     eax, ebp                        ; begin calculating fourth sample
+apatch7:
+        add     edi, 1                          ; move destination to second sample
+        shr     eax, 16                         ; finish calculation for fourth sample
+        mov     [edi], bl                       ; write new sample to destination
+apatch6:
+        add     ebp,12345678h                   ; advance frac pointer
+        movzx   ebx, byte ptr [esi+eax]         ; get fourth sample
+        movzx   eax, byte ptr [esi+edx]         ; get third sample
+apatch8:
+        add     edi, 2                          ; move destination to third sample
+        dec     ecx                             ; decrement count
+        jnz     mix8Mloop                       ; loop
+
+        mov     _MV_MixDestination, edi         ; Store the current write position
+        mov     _MV_MixPosition, ebp            ; return position
+exit8m:
+        popad
+        ret
+ENDP    MV_Mix8BitMono_
+
+;================
+;
+; MV_Mix8BitStereo
+;
+;================
+
+; eax - position
+; edx - rate
+; ebx - start
+; ecx - number of samples to mix
+
+PROC    MV_Mix8BitStereo_
+PUBLIC  MV_Mix8BitStereo_
+
+        pushad
+        mov     ebp, eax
+
+        mov     esi, ebx                        ; Source pointer
+
+        ; Sample size
+        mov     ebx, _MV_SampleSize
+        mov     eax,OFFSET bpatch8+2            ; convice tasm to modify code...
+        mov     [eax],bl
+
+        ; Right channel offset
+        mov     ebx, _MV_RightChannelOffset
+        mov     eax,OFFSET bpatch6+3            ; convice tasm to modify code...
+        mov     [eax],ebx
+        mov     eax,OFFSET bpatch7+2            ; convice tasm to modify code...
+        mov     [eax],ebx
+
+        ; Volume table ptr
+        mov     ebx, _MV_LeftVolume
+        mov     eax,OFFSET bpatch1+4            ; convice tasm to modify code...
+        mov     [eax],ebx
+
+        mov     ebx, _MV_RightVolume
+        mov     eax,OFFSET bpatch2+4            ; convice tasm to modify code...
+        mov     [eax],ebx
+
+        ; Rate scale ptr
+        mov     eax,OFFSET bpatch3+2            ; convice tasm to modify code...
+        mov     [eax],edx
+
+        ; Harsh Clip table ptr
+        mov     ebx, _MV_HarshClipTable
+        add     ebx,128
+        mov     eax,OFFSET bpatch4+2            ; convice tasm to modify code...
+        mov     [eax],ebx
+        mov     eax,OFFSET bpatch5+2            ; convice tasm to modify code...
+        mov     [eax],ebx
+
+        mov     edi, _MV_MixDestination         ; Get the position to write to
+
+        ; Number of samples to mix
+        cmp     ecx, 0
+        je      short exit8S
+
+;     eax - scratch
+;     ebx - scratch
+;     edx - scratch
+;     ecx - count
+;     edi - destination
+;     esi - source
+;     ebp - frac pointer
+; bpatch1 - left volume table
+; bpatch2 - right volume table
+; bpatch3 - sample rate
+; bpatch4 - harsh clip table
+; bpatch5 - harsh clip table
+
+        mov     eax,ebp                         ; begin calculating first sample
+        shr     eax,16                          ; finish calculation for first sample
+
+        movzx   ebx, byte ptr [esi+eax]         ; get first sample
+
+        ALIGN 4
+mix8Sloop:
+bpatch1:
+        movsx   eax, byte ptr [2*ebx+12345678h] ; volume translate left sample
+        movzx   edx, byte ptr [edi]             ; get current sample from destination
+bpatch2:
+        movsx   ebx, byte ptr [2*ebx+12345678h] ; volume translate right sample
+        add     eax, edx                        ; mix left sample
+bpatch3:
+        add     ebp,12345678h                   ; advance frac pointer
+bpatch6:
+        movzx   edx, byte ptr [edi+12345678h]   ; get current sample from destination
+bpatch4:
+        mov     eax, [eax + 12345678h]          ; harsh clip left sample
+        add     ebx, edx                        ; mix right sample
+        mov     [edi], al                       ; write left sample to destination
+bpatch5:
+        mov     ebx, [ebx + 12345678h]          ; harsh clip right sample
+        mov     edx, ebp                        ; begin calculating second sample
+bpatch7:
+        mov     [edi+12345678h], bl             ; write right sample to destination
+        shr     edx, 16                         ; finish calculation for second sample
+bpatch8:
+        add     edi, 2                          ; move destination to second sample
+        movzx   ebx, byte ptr [esi+edx]         ; get second sample
+        dec     ecx                             ; decrement count
+        jnz     mix8Sloop                       ; loop
+
+        mov     _MV_MixDestination, edi         ; Store the current write position
+        mov     _MV_MixPosition, ebp            ; return position
+
+EXIT8S:
+        popad
+        ret
+ENDP    MV_Mix8BitStereo_
+
+;================
+;
+; MV_Mix16BitMono
+;
+;================
+
+; eax - position
+; edx - rate
+; ebx - start
+; ecx - number of samples to mix
+
+PROC    MV_Mix16BitMono_
+PUBLIC  MV_Mix16BitMono_
+; Two at once
+        pushad
+
+        mov     ebp, eax
+
+        mov     esi, ebx                        ; Source pointer
+
+        ; Sample size
+        mov     ebx, _MV_SampleSize
+        mov     eax,OFFSET cpatch5+3            ; convice tasm to modify code...
+        mov     [eax],bl
+        mov     eax,OFFSET cpatch6+3            ; convice tasm to modify code...
+        mov     [eax],bl
+        mov     eax,OFFSET cpatch7+2            ; convice tasm to modify code...
+        add     bl,bl
+        mov     [eax],bl
+
+        ; Volume table ptr
+        mov     ebx, _MV_LeftVolume
+        mov     eax,OFFSET cpatch1+4            ; convice tasm to modify code...
+        mov     [eax],ebx
+        mov     eax,OFFSET cpatch2+4            ; convice tasm to modify code...
+        mov     [eax],ebx
+
+        ; Rate scale ptr
+        mov     eax,OFFSET cpatch3+2            ; convice tasm to modify code...
+        mov     [eax],edx
+        mov     eax,OFFSET cpatch4+2            ; convice tasm to modify code...
+        mov     [eax],edx
+
+        mov     edi, _MV_MixDestination         ; Get the position to write to
+
+        ; Number of samples to mix
+        shr     ecx, 1                          ; double sample count
+        cmp     ecx, 0
+        je      exit16M
+
+;     eax - scratch
+;     ebx - scratch
+;     edx - scratch
+;     ecx - count
+;     edi - destination
+;     esi - source
+;     ebp - frac pointer
+; cpatch1 - volume table
+; cpatch2 - volume table
+; cpatch3 - sample rate
+; cpatch4 - sample rate
+
+        mov     eax,ebp                         ; begin calculating first sample
+        add     ebp,edx                         ; advance frac pointer
+        shr     eax,16                          ; finish calculation for first sample
+
+        mov     ebx,ebp                         ; begin calculating second sample
+        add     ebp,edx                         ; advance frac pointer
+        shr     ebx,16                          ; finish calculation for second sample
+
+        movzx   eax, byte ptr [esi+eax]         ; get first sample
+        movzx   ebx, byte ptr [esi+ebx]         ; get second sample
+
+        ALIGN 4
+mix16Mloop:
+        movsx   edx, word ptr [edi]             ; get current sample from destination
+cpatch1:
+        movsx   eax, word ptr [2*eax+12345678h] ; volume translate first sample
+cpatch2:
+        movsx   ebx, word ptr [2*ebx+12345678h] ; volume translate second sample
+        add     eax, edx                        ; mix first sample
+cpatch5:
+        movsx   edx, word ptr [edi + 2]         ; get current sample from destination
+
+        cmp     eax, -32768                     ; Harsh clip sample
+        jge     short m16skip1
+        mov     eax, -32768
+        jmp     short m16skip2
+m16skip1:
+        cmp     eax, 32767
+        jle     short m16skip2
+        mov     eax, 32767
+m16skip2:
+        add     ebx, edx                        ; mix second sample
+        mov     [edi], ax                       ; write new sample to destination
+        mov     edx, ebp                        ; begin calculating third sample
+
+        cmp     ebx, -32768                     ; Harsh clip sample
+        jge     short m16skip3
+        mov     ebx, -32768
+        jmp     short m16skip4
+m16skip3:
+        cmp     ebx, 32767
+        jle     short m16skip4
+        mov     ebx, 32767
+m16skip4:
+cpatch3:
+        add     ebp,12345678h                   ; advance frac pointer
+        shr     edx, 16                         ; finish calculation for third sample
+        mov     eax, ebp                        ; begin calculating fourth sample
+cpatch6:
+        mov     [edi + 2], bx                   ; write new sample to destination
+        shr     eax, 16                         ; finish calculation for fourth sample
+
+cpatch4:
+        add     ebp,12345678h                   ; advance frac pointer
+        movzx   ebx, byte ptr [esi+eax]         ; get fourth sample
+cpatch7:
+        add     edi, 4                          ; move destination to third sample
+        movzx   eax, byte ptr [esi+edx]         ; get third sample
+        dec     ecx                             ; decrement count
+        jnz     mix16Mloop                      ; loop
+
+        mov     _MV_MixDestination, edi         ; Store the current write position
+        mov     _MV_MixPosition, ebp            ; return position
+EXIT16M:
+        popad
+        ret
+ENDP    MV_Mix16BitMono_
+
+;================
+;
+; MV_Mix16BitStereo
+;
+;================
+
+; eax - position
+; edx - rate
+; ebx - start
+; ecx - number of samples to mix
+
+PROC    MV_Mix16BitStereo_
+PUBLIC  MV_Mix16BitStereo_
+
+        pushad
+        mov     ebp, eax
+
+        mov     esi, ebx                        ; Source pointer
+
+        ; Sample size
+        mov     ebx, _MV_SampleSize
+        mov     eax,OFFSET dpatch6+2            ; convice tasm to modify code...
+        mov     [eax],bl
+
+        ; Right channel offset
+        mov     ebx, _MV_RightChannelOffset
+        mov     eax,OFFSET dpatch4+3            ; convice tasm to modify code...
+        mov     [eax],ebx
+        mov     eax,OFFSET dpatch5+3            ; convice tasm to modify code...
+        mov     [eax],ebx
+
+        ; Volume table ptr
+        mov     ebx, _MV_LeftVolume
+        mov     eax,OFFSET dpatch1+4            ; convice tasm to modify code...
+        mov     [eax],ebx
+
+        mov     ebx, _MV_RightVolume
+        mov     eax,OFFSET dpatch2+4            ; convice tasm to modify code...
+        mov     [eax],ebx
+
+        ; Rate scale ptr
+        mov     eax,OFFSET dpatch3+2            ; convice tasm to modify code...
+        mov     [eax],edx
+
+        mov     edi, _MV_MixDestination         ; Get the position to write to
+
+        ; Number of samples to mix
+        cmp     ecx, 0
+        je      exit16S
+
+;     eax - scratch
+;     ebx - scratch
+;     edx - scratch
+;     ecx - count
+;     edi - destination
+;     esi - source
+;     ebp - frac pointer
+; dpatch1 - left volume table
+; dpatch2 - right volume table
+; dpatch3 - sample rate
+
+        mov     eax,ebp                         ; begin calculating first sample
+        shr     eax,16                          ; finish calculation for first sample
+
+        movzx   ebx, byte ptr [esi+eax]         ; get first sample
+
+        ALIGN 4
+mix16Sloop:
+dpatch1:
+        movsx   eax, word ptr [2*ebx+12345678h] ; volume translate left sample
+        movsx   edx, word ptr [edi]             ; get current sample from destination
+dpatch2:
+        movsx   ebx, word ptr [2*ebx+12345678h] ; volume translate right sample
+        add     eax, edx                        ; mix left sample
+dpatch3:
+        add     ebp,12345678h                   ; advance frac pointer
+dpatch4:
+        movsx   edx, word ptr [edi+12345678h]   ; get current sample from destination
+
+        cmp     eax, -32768                     ; Harsh clip sample
+        jge     short s16skip1
+        mov     eax, -32768
+        jmp     short s16skip2
+s16skip1:
+        cmp     eax, 32767
+        jle     short s16skip2
+        mov     eax, 32767
+s16skip2:
+        add     ebx, edx                        ; mix right sample
+        mov     [edi], ax                       ; write left sample to destination
+
+        cmp     ebx, -32768                     ; Harsh clip sample
+        jge     short s16skip3
+        mov     ebx, -32768
+        jmp     short s16skip4
+s16skip3:
+        cmp     ebx, 32767
+        jle     short s16skip4
+        mov     ebx, 32767
+s16skip4:
+
+        mov     edx, ebp                        ; begin calculating second sample
+dpatch5:
+        mov     [edi+12345678h], bx             ; write right sample to destination
+        shr     edx, 16                         ; finish calculation for second sample
+dpatch6:
+        add     edi, 4                          ; move destination to second sample
+        movzx   ebx, byte ptr [esi+edx]         ; get second sample
+        dec     ecx                             ; decrement count
+        jnz     mix16Sloop                      ; loop
+
+        mov     _MV_MixDestination, edi         ; Store the current write position
+        mov     _MV_MixPosition, ebp            ; return position
+exit16S:
+        popad
+        ret
+ENDP    MV_Mix16BitStereo_
+
+        ENDS
+
+        END
--- /dev/null
+++ b/rott/audiolib/mv_mix.c
@@ -1,0 +1,293 @@
+#include "multivoc.h"
+
+extern char  *MV_MixDestination;
+extern unsigned long MV_MixPosition;
+
+extern char *MV_LeftVolume;
+extern char *MV_RightVolume;
+
+extern unsigned char *MV_HarshClipTable;
+
+extern int MV_RightChannelOffset;
+extern int MV_SampleSize;
+
+void MV_Mix8BitMono( unsigned long position, unsigned long rate,
+   const char *start, unsigned long length )
+{
+	const unsigned char *src;
+	unsigned char *dest;
+	unsigned int i;
+
+	src = (const unsigned char *)start;
+	dest = (unsigned char *)MV_MixDestination;
+
+	for (i = 0; i < length; i++) {
+		int s = src[position >> 16];
+		int d = *dest;
+		
+		s = MV_LeftVolume[s * 2];
+
+		s += d;
+		
+		s = MV_HarshClipTable[s + 0x80];
+		
+		*dest = (s & 0xff);
+		
+		position += rate;
+		dest += MV_SampleSize;
+	}
+	
+	MV_MixPosition = position;
+	MV_MixDestination = (char *)dest;
+}
+
+void MV_Mix8BitStereo( unsigned long position,
+   unsigned long rate, const char *start, unsigned long length )
+{
+	const unsigned char *src;
+	unsigned char *dest;
+	unsigned int i;
+	
+	src = (const unsigned char *)start;
+	dest = (unsigned char *)MV_MixDestination;
+
+	for (i = 0; i < length; i++) {
+		int s = src[(position >> 16)];
+		int dl = dest[0];
+		int dr = dest[MV_RightChannelOffset];
+		
+		dl += MV_LeftVolume[s * 2];
+		dr += MV_RightVolume[s * 2];
+		
+		dl = MV_HarshClipTable[dl + 0x80];
+		dr = MV_HarshClipTable[dr + 0x80];
+		
+		dest[0] = (dl & 0xff);
+		dest[MV_RightChannelOffset] = (dr & 0xff);
+		
+		position += rate;
+		dest += MV_SampleSize;
+	}
+	
+	MV_MixPosition = position;
+	MV_MixDestination = (char *)dest;
+}
+
+void MV_Mix16BitMono( unsigned long position,
+   unsigned long rate, const char *start, unsigned long length )
+{
+	const short *MV_LeftVolumeS;
+	const unsigned char *src;
+	short *dest;
+	unsigned int i;
+
+	src = (const unsigned char *)start;
+	dest = (short *)MV_MixDestination;
+	
+	MV_LeftVolumeS = (const short *)MV_LeftVolume;
+	
+	for (i = 0; i < length; i++) {
+		int s = src[position >> 16];
+		int d = dest[0];
+		
+		s = MV_LeftVolumeS[s];
+		
+		s += d;
+		
+		if (s < -32768) s = -32768;
+		if (s >  32767) s =  32767;
+		
+		*dest = (short) s;
+		
+		position += rate;
+		dest += MV_SampleSize/2;
+	}
+	
+	MV_MixPosition = position;
+	MV_MixDestination = (char *)dest;
+}
+
+void MV_Mix16BitStereo( unsigned long position,
+   unsigned long rate, const char *start, unsigned long length )
+{
+	const short *MV_LeftVolumeS;
+	const short *MV_RightVolumeS;
+	const unsigned char *src;
+	short *dest;
+	unsigned int i;
+
+	src = (unsigned char *)start;
+	dest = (short *)MV_MixDestination;
+	
+	MV_LeftVolumeS = (const short *)MV_LeftVolume;
+	MV_RightVolumeS = (const short *)MV_RightVolume;
+	
+	for (i = 0; i < length; i++) {
+		int s = src[position >> 16];
+		int dl = dest[0];
+		int dr = dest[MV_RightChannelOffset/2];
+		
+		dl += MV_LeftVolumeS[s];
+		dr += MV_RightVolumeS[s];
+		
+		if (dl < -32768) dl = -32768;
+		if (dl >  32767) dl =  32767;
+		if (dr < -32768) dr = -32768;
+		if (dr >  32767) dr =  32767;
+		
+		dest[0] = (short) dl;
+		dest[MV_RightChannelOffset/2] = (short) dr;
+		
+		position += rate;
+		dest += MV_SampleSize/2;
+	}
+	
+	MV_MixPosition = position;
+	MV_MixDestination = (char *)dest;
+}
+
+void MV_Mix8BitMono16( unsigned long position, unsigned long rate,
+   const char *start, unsigned long length )
+{
+	const char *src;
+	unsigned char *dest;
+	unsigned int i;
+
+	src = (const char *)start + 1;
+	dest = (unsigned char *)MV_MixDestination;
+
+	for (i = 0; i < length; i++) {
+		int s = (int)src[(position >> 16) * 2] + 0x80;
+		int d = *dest;
+		
+		s = MV_LeftVolume[s * 2];
+		
+		s += d;
+		
+		s = MV_HarshClipTable[s + 0x80];
+		
+		*dest = (s & 0xff);
+		
+		position += rate;
+		dest += MV_SampleSize;
+	}
+	
+	MV_MixPosition = position;
+	MV_MixDestination = (char *)dest;
+}
+
+void MV_Mix8BitStereo16( unsigned long position,
+   unsigned long rate, const char *start, unsigned long length )
+{
+	const char *src;
+	unsigned char *dest;
+	unsigned int i;
+	
+	src = (const char *)start + 1;
+	dest = (unsigned char *)MV_MixDestination;
+	
+	for (i = 0; i < length; i++) {
+		int s = src[(position >> 16) * 2] + 0x80;
+		int dl = dest[0];
+		int dr = dest[MV_RightChannelOffset];
+		
+		dl += MV_LeftVolume[s * 2];
+		dr += MV_RightVolume[s * 2];
+		
+		dl = MV_HarshClipTable[dl + 0x80];
+		dr = MV_HarshClipTable[dr + 0x80];
+		
+		dest[0] = (dl & 0xff);
+		dest[MV_RightChannelOffset] = (dr & 0xff);
+		
+		position += rate;
+		dest += MV_SampleSize;
+	}
+	
+	MV_MixPosition = position;
+	MV_MixDestination = (char *)dest;
+}
+
+void MV_Mix16BitMono16( unsigned long position,
+   unsigned long rate, const char *start, unsigned long length )
+{
+	const short *MV_LeftVolumeS;
+	const unsigned char *src;
+	short *dest;
+	unsigned int i;
+	
+	src = (const unsigned char *)start;
+	dest = (short *)MV_MixDestination;
+	
+	MV_LeftVolumeS = (const short *)MV_LeftVolume;
+	
+	for (i = 0; i < length; i++) {
+		int sl = src[(position >> 16) * 2 + 0];
+		int sh = src[(position >> 16) * 2 + 1] ^ 0x80;
+		
+		int d = *dest;
+		
+		sl = MV_LeftVolume[sl * 2 + 1];
+		sh = MV_LeftVolumeS[sh];
+		
+		d = sl + sh + 0x80 + d;
+		
+		if (d < -32768) d = -32768;
+		if (d >  32767) d =  32767;
+		
+		*dest = (short) d;
+		
+		position += rate;
+		dest += MV_SampleSize/2;
+	}
+	
+	MV_MixPosition = position;
+	MV_MixDestination = (char *)dest;
+}
+
+void MV_Mix16BitStereo16( unsigned long position,
+   unsigned long rate, const char *start, unsigned long length )
+{
+	const short *MV_LeftVolumeS;
+	const short *MV_RightVolumeS;
+	const unsigned char *src;
+	short *dest;
+	unsigned int i;
+	
+	src = (const unsigned char *)start;
+	dest = (short *)MV_MixDestination;
+	
+	MV_LeftVolumeS = (const short *)MV_LeftVolume;
+	MV_RightVolumeS = (const short *)MV_RightVolume;
+	
+	for (i = 0; i < length; i++) {
+		int sl = src[(position >> 16) * 2 + 0];
+		int sh = src[(position >> 16) * 2 + 1] ^ 0x80;
+		
+		int dl = dest[0];
+		int dr = dest[MV_RightChannelOffset/2];
+		
+		int sll = MV_LeftVolume[sl * 2 + 1];
+		int slh = MV_LeftVolumeS[sh];
+		
+		int srl = MV_RightVolume[sl * 2 + 1];
+		int srh = MV_RightVolumeS[sh];
+		
+		dl = sll + slh + 0x80 + dl;
+		dr = srl + srh + 0x80 + dr;
+		
+		if (dl < -32768) dl = -32768;
+		if (dl >  32767) dl =  32767;
+		if (dr < -32768) dr = -32768;
+		if (dr >  32767) dr =  32767;
+		
+		dest[0] = (short) dl;
+		dest[MV_RightChannelOffset/2] = (short) dr;
+		
+		position += rate;
+		dest += MV_SampleSize/2;
+	}
+	
+	MV_MixPosition = position;
+	MV_MixDestination = (char *)dest;
+}
--- /dev/null
+++ b/rott/audiolib/mv_mix16.asm
@@ -1,0 +1,524 @@
+        IDEAL
+
+        p386
+        MODEL  flat
+
+        dataseg
+        CODESEG
+
+        MASM
+        ALIGN 4
+
+EXTRN   _MV_HarshClipTable:DWORD
+EXTRN   _MV_MixDestination:DWORD
+EXTRN   _MV_MixPosition:DWORD
+EXTRN   _MV_LeftVolume:DWORD
+EXTRN   _MV_RightVolume:DWORD
+EXTRN   _MV_SampleSize:DWORD
+EXTRN   _MV_RightChannelOffset:DWORD
+
+;================
+;
+; MV_Mix8BitMono16
+;
+;================
+
+; eax - position
+; edx - rate
+; ebx - start
+; ecx - number of samples to mix
+
+PROC    MV_Mix8BitMono16_
+PUBLIC  MV_Mix8BitMono16_
+; Two at once
+        pushad
+        mov     ebp, eax
+
+        mov     esi, ebx                        ; Source pointer
+        inc     esi
+
+        ; Sample size
+        mov     ebx, _MV_SampleSize
+        mov     eax,OFFSET apatch7+2            ; convice tasm to modify code...
+        mov     [eax],bl
+        mov     eax,OFFSET apatch8+2            ; convice tasm to modify code...
+        mov     [eax],bl
+        mov     eax,OFFSET apatch9+3            ; convice tasm to modify code...
+        mov     [eax],bl
+
+        ; Volume table ptr
+        mov     ebx, _MV_LeftVolume             ; Since we're mono, use left volume
+        mov     eax,OFFSET apatch1+4            ; convice tasm to modify code...
+        mov     [eax],ebx
+        mov     eax,OFFSET apatch2+4            ; convice tasm to modify code...
+        mov     [eax],ebx
+
+        ; Harsh Clip table ptr
+        mov     ebx, _MV_HarshClipTable
+        add     ebx, 128
+        mov     eax,OFFSET apatch3+2            ; convice tasm to modify code...
+        mov     [eax],ebx
+        mov     eax,OFFSET apatch4+2            ; convice tasm to modify code...
+        mov     [eax],ebx
+
+        ; Rate scale ptr
+        mov     eax,OFFSET apatch5+2            ; convice tasm to modify code...
+        mov     [eax],edx
+        mov     eax,OFFSET apatch6+2            ; convice tasm to modify code...
+        mov     [eax],edx
+
+        mov     edi, _MV_MixDestination         ; Get the position to write to
+
+        ; Number of samples to mix
+        shr     ecx, 1                          ; double sample count
+        cmp     ecx, 0
+        je      exit8m
+
+;     eax - scratch
+;     ebx - scratch
+;     edx - scratch
+;     ecx - count
+;     edi - destination
+;     esi - source
+;     ebp - frac pointer
+; apatch1 - volume table
+; apatch2 - volume table
+; apatch3 - harsh clip table
+; apatch4 - harsh clip table
+; apatch5 - sample rate
+; apatch6 - sample rate
+
+        mov     eax,ebp                         ; begin calculating first sample
+        add     ebp,edx                         ; advance frac pointer
+        shr     eax,16                          ; finish calculation for first sample
+
+        mov     ebx,ebp                         ; begin calculating second sample
+        add     ebp,edx                         ; advance frac pointer
+        shr     ebx,16                          ; finish calculation for second sample
+
+        movsx   eax, byte ptr [esi+2*eax]       ; get first sample
+        movsx   ebx, byte ptr [esi+2*ebx]       ; get second sample
+        add     eax, 80h
+        add     ebx, 80h
+
+        ALIGN 4
+mix8Mloop:
+        movzx   edx, byte ptr [edi]             ; get current sample from destination
+apatch1:
+        movsx   eax, byte ptr [2*eax+12345678h] ; volume translate first sample
+apatch2:
+        movsx   ebx, byte ptr [2*ebx+12345678h] ; volume translate second sample
+        add     eax, edx                        ; mix first sample
+apatch9:
+        movzx   edx, byte ptr [edi + 1]         ; get current sample from destination
+apatch3:
+        mov     eax, [eax + 12345678h]          ; harsh clip new sample
+        add     ebx, edx                        ; mix second sample
+        mov     [edi], al                       ; write new sample to destination
+        mov     edx, ebp                        ; begin calculating third sample
+apatch4:
+        mov     ebx, [ebx + 12345678h]          ; harsh clip new sample
+apatch5:
+        add     ebp,12345678h                   ; advance frac pointer
+        shr     edx, 16                         ; finish calculation for third sample
+        mov     eax, ebp                        ; begin calculating fourth sample
+apatch7:
+        add     edi, 2                          ; move destination to second sample
+        shr     eax, 16                         ; finish calculation for fourth sample
+        mov     [edi], bl                       ; write new sample to destination
+apatch6:
+        add     ebp,12345678h                   ; advance frac pointer
+        movsx   ebx, byte ptr [esi+2*eax]         ; get fourth sample
+        movsx   eax, byte ptr [esi+2*edx]         ; get third sample
+        add     ebx, 80h
+        add     eax, 80h
+apatch8:
+        add     edi, 2                          ; move destination to third sample
+        dec     ecx                             ; decrement count
+        jnz     mix8Mloop                       ; loop
+
+        mov     _MV_MixDestination, edi         ; Store the current write position
+        mov     _MV_MixPosition, ebp            ; return position
+exit8m:
+        popad
+        ret
+ENDP    MV_Mix8BitMono16_
+
+;================
+;
+; MV_Mix8BitStereo16
+;
+;================
+
+; eax - position
+; edx - rate
+; ebx - start
+; ecx - number of samples to mix
+
+PROC    MV_Mix8BitStereo16_
+PUBLIC  MV_Mix8BitStereo16_
+
+        pushad
+        mov     ebp, eax
+
+        mov     esi, ebx                        ; Source pointer
+        inc     esi
+
+        ; Sample size
+        mov     ebx, _MV_SampleSize
+        mov     eax,OFFSET bpatch8+2            ; convice tasm to modify code...
+        mov     [eax],bl
+ ;       mov     eax,OFFSET bpatch9+2            ; convice tasm to modify code...
+ ;       mov     [eax],bl
+
+        ; Right channel offset
+        mov     ebx, _MV_RightChannelOffset
+        mov     eax,OFFSET bpatch6+3            ; convice tasm to modify code...
+        mov     [eax],ebx
+        mov     eax,OFFSET bpatch7+2            ; convice tasm to modify code...
+        mov     [eax],ebx
+
+        ; Volume table ptr
+        mov     ebx, _MV_LeftVolume
+        mov     eax,OFFSET bpatch1+4            ; convice tasm to modify code...
+        mov     [eax],ebx
+
+        mov     ebx, _MV_RightVolume
+        mov     eax,OFFSET bpatch2+4            ; convice tasm to modify code...
+        mov     [eax],ebx
+
+        ; Rate scale ptr
+        mov     eax,OFFSET bpatch3+2            ; convice tasm to modify code...
+        mov     [eax],edx
+
+        ; Harsh Clip table ptr
+        mov     ebx, _MV_HarshClipTable
+        add     ebx,128
+        mov     eax,OFFSET bpatch4+2            ; convice tasm to modify code...
+        mov     [eax],ebx
+        mov     eax,OFFSET bpatch5+2            ; convice tasm to modify code...
+        mov     [eax],ebx
+
+        mov     edi, _MV_MixDestination         ; Get the position to write to
+
+        ; Number of samples to mix
+        cmp     ecx, 0
+        je      short exit8S
+
+;     eax - scratch
+;     ebx - scratch
+;     edx - scratch
+;     ecx - count
+;     edi - destination
+;     esi - source
+;     ebp - frac pointer
+; bpatch1 - left volume table
+; bpatch2 - right volume table
+; bpatch3 - sample rate
+; bpatch4 - harsh clip table
+; bpatch5 - harsh clip table
+
+        mov     eax,ebp                         ; begin calculating first sample
+        shr     eax,16                          ; finish calculation for first sample
+
+        movsx   ebx, byte ptr [esi+2*eax]       ; get first sample
+        add     ebx, 80h
+
+        ALIGN 4
+mix8Sloop:
+bpatch1:
+        movsx   eax, byte ptr [2*ebx+12345678h] ; volume translate left sample
+        movzx   edx, byte ptr [edi]             ; get current sample from destination
+bpatch2:
+        movsx   ebx, byte ptr [2*ebx+12345678h] ; volume translate right sample
+        add     eax, edx                        ; mix left sample
+bpatch3:
+        add     ebp,12345678h                   ; advance frac pointer
+bpatch6:
+        movzx   edx, byte ptr [edi+12345678h]   ; get current sample from destination
+bpatch4:
+        mov     eax, [eax + 12345678h]          ; harsh clip left sample
+        add     ebx, edx                        ; mix right sample
+        mov     [edi], al                       ; write left sample to destination
+bpatch5:
+        mov     ebx, [ebx + 12345678h]          ; harsh clip right sample
+        mov     edx, ebp                        ; begin calculating second sample
+bpatch7:
+        mov     [edi+12345678h], bl             ; write right sample to destination
+        shr     edx, 16                         ; finish calculation for second sample
+bpatch8:
+        add     edi, 1                          ; move destination to second sample
+        movsx   ebx, byte ptr [esi+2*edx]       ; get second sample
+        add     ebx, 80h
+        dec     ecx                             ; decrement count
+        jnz     mix8Sloop                       ; loop
+
+        mov     _MV_MixDestination, edi         ; Store the current write position
+        mov     _MV_MixPosition, ebp            ; return position
+
+EXIT8S:
+        popad
+        ret
+ENDP    MV_Mix8BitStereo16_
+
+;================
+;
+; MV_Mix16BitMono16
+;
+;================
+
+; eax - position
+; edx - rate
+; ebx - start
+; ecx - number of samples to mix
+
+PROC    MV_Mix16BitMono16_
+PUBLIC  MV_Mix16BitMono16_
+
+        pushad
+        mov     ebp, eax
+
+        mov     esi, ebx                        ; Source pointer
+
+        ; Sample size
+        mov     ebx, _MV_SampleSize
+        mov     eax,OFFSET cpatch4+2            ; convice tasm to modify code...
+        mov     [eax],bl
+        mov     eax,OFFSET cpatch5+3            ; convice tasm to modify code...
+        mov     [eax],bl
+
+        ; Volume table ptr
+        mov     ebx, _MV_LeftVolume
+        mov     eax,OFFSET cpatch2+4            ; convice tasm to modify code...
+        mov     [eax],ebx
+        mov     eax,OFFSET cpatch1+4            ; convice tasm to modify code...
+        inc     ebx
+        mov     [eax],ebx
+
+        ; Rate scale ptr
+        mov     eax,OFFSET cpatch3+2            ; convice tasm to modify code...
+        mov     [eax],edx
+
+        mov     edi, _MV_MixDestination         ; Get the position to write to
+
+        ; Number of samples to mix
+        cmp     ecx, 0
+        je exit16M
+
+;     eax - scratch
+;     ebx - scratch
+;     edx - scratch
+;     ecx - count
+;     edi - destination
+;     esi - source
+;     ebp - frac pointer
+; cpatch1 - volume table
+; cpatch2 - volume table
+; cpatch3 - sample rate
+; cpatch4 - sample rate
+
+        mov     ebx,ebp                         ; begin calculating first sample
+        add     ebp,edx                         ; advance frac pointer
+        shr     ebx,16                          ; finish calculation for first sample
+        movzx   eax, word ptr [esi+2*ebx]       ; get low byte of sample
+        xor     eax, 8000h
+        movzx   ebx, ah
+        sub     ah, ah
+
+        movsx   edx, word ptr [edi]             ; get current sample from destination
+
+        ALIGN 4
+mix16Mloop:
+cpatch1:
+        movsx   eax, byte ptr [2*eax+12345678h] ; volume translate low byte of sample
+cpatch2:
+        movsx   ebx, word ptr [2*ebx+12345678h] ; volume translate high byte of sample
+        lea     eax, [ eax + ebx + 80h ]        ; mix high byte of sample
+        add     eax, edx                        ; mix low byte of sample
+cpatch5:
+        movsx   edx, word ptr [edi + 2]         ; get current sample from destination
+
+        cmp     eax, -32768                     ; Harsh clip sample
+        jge     short m16skip1
+        mov     eax, -32768
+        jmp     short m16skip2
+m16skip1:
+        cmp     eax, 32767
+        jle     short m16skip2
+        mov     eax, 32767
+m16skip2:
+        mov     ebx, ebp                        ; begin calculating second sample
+        mov     [edi], ax                       ; write new sample to destination
+
+        shr     ebx, 16                         ; finish calculation for second sample
+cpatch3:
+        add     ebp, 12345678h                  ; advance frac pointer
+
+        movzx   eax, word ptr [esi+2*ebx]       ; get second sample
+cpatch4:
+        add     edi, 2                          ; move destination to second sample
+        xor     eax, 8000h
+        movzx   ebx, ah
+        sub     ah, ah
+
+        dec     ecx                             ; decrement count
+        jnz     mix16Mloop                      ; loop
+
+        mov     _MV_MixDestination, edi         ; Store the current write position
+        mov     _MV_MixPosition, ebp            ; return position
+EXIT16M:
+        popad
+        ret
+ENDP    MV_Mix16BitMono16_
+
+;================
+;
+; MV_Mix16BitStereo16
+;
+;================
+
+; eax - position
+; edx - rate
+; ebx - start
+; ecx - number of samples to mix
+
+PROC    MV_Mix16BitStereo16_
+PUBLIC  MV_Mix16BitStereo16_
+
+        pushad
+        mov     ebp, eax
+
+        mov     esi, ebx                        ; Source pointer
+
+        ; Sample size
+        mov     ebx, _MV_SampleSize
+        mov     eax,OFFSET dpatch9+2            ; convice tasm to modify code...
+        mov     [eax],bl
+
+        ; Right channel offset
+        mov     ebx, _MV_RightChannelOffset
+        mov     eax,OFFSET dpatch7+3            ; convice tasm to modify code...
+        mov     [eax],ebx
+        mov     eax,OFFSET dpatch8+3            ; convice tasm to modify code...
+        mov     [eax],ebx
+
+        ; Volume table ptr
+        mov     ebx, _MV_LeftVolume
+        mov     eax,OFFSET dpatch1+4            ; convice tasm to modify code...
+        mov     [eax],ebx
+        mov     eax,OFFSET dpatch2+4            ; convice tasm to modify code...
+        inc     ebx
+        mov     [eax],ebx
+
+        mov     ebx, _MV_RightVolume
+        mov     eax,OFFSET dpatch3+4            ; convice tasm to modify code...
+        mov     [eax],ebx
+        mov     eax,OFFSET dpatch4+4            ; convice tasm to modify code...
+        inc     ebx
+        mov     [eax],ebx
+
+        ; Rate scale ptr
+        mov     eax,OFFSET dpatch5+2            ; convice tasm to modify code...
+        mov     [eax],edx
+
+        ; Source ptr
+        mov     eax,OFFSET dpatch6+4            ; convice tasm to modify code...
+        mov     [eax],esi
+
+        mov     edi, _MV_MixDestination         ; Get the position to write to
+
+        ; Number of samples to mix
+        cmp     ecx, 0
+        je      exit16S
+
+;     eax - scratch
+;     ebx - scratch
+;     edx - scratch
+;     esi - scratch
+;     ecx - count
+;     edi - destination
+;     ebp - frac pointer
+; dpatch1 - left volume table
+; dpatch2 - right volume table
+; dpatch3 - sample rate
+
+        mov     ebx,ebp                         ; begin calculating first sample
+        shr     ebx,16                          ; finish calculation for first sample
+
+        movzx   edx, word ptr [esi+2*ebx]       ; get first sample
+        xor     edx, 8000h                      ; Change from signed to unsigned
+        movzx   esi, dh                         ; put high byte in esi
+        sub     dh, dh                          ; lo byte in edx
+
+        ALIGN 4
+mix16Sloop:
+        ; Left channel
+dpatch1:
+        movsx   eax, word ptr [2*esi+12345678h] ; volume translate high byte of sample
+dpatch2:
+        movsx   ebx, byte ptr [2*edx+12345678h] ; volume translate low byte of sample
+        lea     eax, [ eax + ebx + 80h ]        ; mix high byte of sample
+
+        ; Right channel
+dpatch3:
+        movsx   esi, word ptr [2*esi+12345678h] ; volume translate high byte of sample
+dpatch4:
+        movsx   ebx, byte ptr [2*edx+12345678h] ; volume translate low byte of sample
+        lea     ebx, [ esi + ebx + 80h ]        ; mix high byte of sample
+
+dpatch7:
+        movsx   edx, word ptr [edi+12345678h]   ; get current sample from destination
+dpatch5:
+        add     ebp,12345678h                   ; advance frac pointer
+
+        add     eax, edx                        ; mix left sample
+
+        cmp     eax, -32768                     ; Harsh clip sample
+        jge     short s16skip1
+        mov     eax, -32768
+        jmp     short s16skip2
+s16skip1:
+        cmp     eax, 32767
+        jle     short s16skip2
+        mov     eax, 32767
+s16skip2:
+        movsx   edx, word ptr [edi+2]           ; get current sample from destination
+        mov     [edi], ax                       ; write left sample to destination
+        add     ebx, edx                        ; mix right sample
+
+        cmp     ebx, -32768                     ; Harsh clip sample
+        jge     short s16skip3
+        mov     ebx, -32768
+        jmp     short s16skip4
+s16skip3:
+        cmp     ebx, 32767
+        jle     short s16skip4
+        mov     ebx, 32767
+s16skip4:
+
+        mov     edx, ebp                        ; begin calculating second sample
+dpatch8:
+        mov     [edi+12345678h], bx             ; write right sample to destination
+        shr     edx, 16                         ; finish calculation for second sample
+dpatch9:
+        add     edi, 4                          ; move destination to second sample
+
+dpatch6:
+        movzx   edx, word ptr [2*edx+12345678h] ; get second sample
+        xor     edx, 8000h                      ; Change from signed to unsigned
+        movzx   esi, dh                         ; put high byte in esi
+        sub     dh, dh                          ; lo byte in edx
+
+        dec     ecx                             ; decrement count
+        jnz     mix16Sloop                      ; loop
+
+        mov     _MV_MixDestination, edi         ; Store the current write position
+        mov     _MV_MixPosition, ebp            ; return position
+exit16S:
+        popad
+        ret
+ENDP    MV_Mix16BitStereo16_
+
+        ENDS
+
+        END
--- /dev/null
+++ b/rott/audiolib/mvreverb.asm
@@ -1,0 +1,181 @@
+        IDEAL
+
+        p386
+        MODEL  flat
+
+        dataseg
+        CODESEG
+
+        MASM
+        ALIGN 4
+
+;================
+;
+; MV_16BitReverb
+;
+;================
+
+; eax - source position
+; edx - destination position
+; ebx - Volume table
+; ecx - number of samples
+
+PROC    MV_16BitReverb_
+PUBLIC  MV_16BitReverb_
+
+        mov     esi, eax
+        lea     edi, [edx - 2]
+
+        ALIGN 4
+rev16loop:
+        movzx   eax, word ptr [esi]             ; get sample
+        add     edi, 2
+
+        movzx   edx, ah
+        sub     ah, ah
+
+        movsx   eax, byte ptr [2*eax+ebx+1]     ; volume translate low byte of sample
+        xor     edx, 80h
+
+        movsx   edx, word ptr [2*edx+ebx]       ; volume translate high byte of sample
+        add     esi, 2
+
+        lea     eax, [ eax + edx + 80h ]        ; mix high byte of sample
+        dec     ecx                             ; decrement count
+
+        mov     [edi], ax                       ; write new sample to destination
+        jnz     rev16loop                       ; loop
+
+        ret
+ENDP    MV_16BitReverb_
+
+;================
+;
+; MV_8BitReverb
+;
+;================
+
+; eax - source position
+; edx - destination position
+; ebx - Volume table
+; ecx - number of samples
+
+PROC    MV_8BitReverb_
+PUBLIC  MV_8BitReverb_
+
+        mov     esi, eax
+        lea     edi, [edx - 1]
+
+        xor     eax, eax
+
+        ALIGN 4
+rev8loop:
+;        movzx   eax, byte ptr [esi]             ; get sample
+        mov     al, byte ptr [esi]              ; get sample
+        inc     edi
+
+;        movsx   eax, byte ptr [2*eax+ebx]       ; volume translate sample
+        mov     al, byte ptr [2*eax+ebx]        ; volume translate sample
+        inc     esi
+
+;        add     eax, 80h
+        add     al, 80h
+        dec     ecx                             ; decrement count
+
+        mov     [edi], al                       ; write new sample to destination
+        jnz     rev8loop                        ; loop
+
+        ret
+ENDP    MV_8BitReverb_
+
+;================
+;
+; MV_16BitReverbFast
+;
+;================
+
+; eax - source position
+; edx - destination position
+; ebx - number of samples
+; ecx - shift
+
+PROC    MV_16BitReverbFast_
+PUBLIC  MV_16BitReverbFast_
+
+        mov     esi, eax
+        mov     eax,OFFSET rpatch16+3
+
+        mov     [eax],cl
+        lea     edi, [edx - 2]
+
+        ALIGN 4
+frev16loop:
+        mov     ax, word ptr [esi]             ; get sample
+        add     edi, 2
+
+rpatch16:
+        sar     ax, 5    ;;;;Add 1 before shift
+        add     esi, 2
+
+        mov     [edi], ax                       ; write new sample to destination
+        dec     ebx                             ; decrement count
+
+        jnz     frev16loop                      ; loop
+
+        ret
+ENDP    MV_16BITREVERBFAST_
+
+;================
+;
+; MV_8BitReverbFast
+;
+;================
+
+; eax - source position
+; edx - destination position
+; ebx - number of samples
+; ecx - shift
+
+PROC    MV_8BitReverbFast_
+PUBLIC  MV_8BitReverbFast_
+        mov     esi, eax
+        mov     eax,OFFSET rpatch8+2
+
+        mov     edi, edx
+        mov     edx, 80h
+
+        mov     [eax],cl
+        mov     eax, 80h
+
+        shr     eax, cl
+
+        dec     edi
+        sub     edx, eax
+
+        ALIGN 4
+frev8loop:
+        mov     al, byte ptr [esi]             ; get sample
+        inc     esi
+
+        mov     ecx, eax
+        inc     edi
+
+rpatch8:
+        shr     eax, 3
+        xor     ecx, 80h                        ; flip the sign bit
+
+        shr     ecx, 7                          ; shift the sign down to 1
+        add     eax, edx
+
+        add     eax, ecx                        ; add sign bit to round to 0
+        dec     ebx                             ; decrement count
+
+        mov     [edi], al                       ; write new sample to destination
+        jnz     frev8loop                       ; loop
+
+        ret
+ENDP    MV_8BITREVERBFAST_
+
+        ENDS
+
+        END
--- /dev/null
+++ b/rott/audiolib/mvreverb.c
@@ -1,0 +1,58 @@
+#include "multivoc.h"
+#include "_multivc.h"
+
+void MV_16BitReverb( const char *src, char *dest, const VOLUME16 *volume, int count )
+{
+	int i;
+
+	short *pdest = (short *)dest;
+	
+	for (i = 0; i < count; i++) {
+		int sl = src[i*2+0];
+		int sh = src[i*2+1] ^ 0x80;
+		
+		sl = (*volume)[sl] >> 8;
+		sh = (*volume)[sh];
+		
+		pdest[i] = (short)(sl + sh + 0x80);
+	}
+}
+
+void MV_8BitReverb( const signed char *src, signed char *dest, const VOLUME16 *volume, int count )
+{
+	int i;
+
+	for (i = 0; i < count; i++) {
+		unsigned char s = (unsigned char) src[i];
+		
+		s = (*volume)[s] & 0xff;
+		
+		dest[i] = (char)(s + 0x80);
+	}
+}
+
+void MV_16BitReverbFast( const char *src, char *dest, int count, int shift )
+{
+	int i;
+
+	short *pdest = (short *)dest;
+	const short *psrc = (const short *)src;
+	
+	for (i = 0; i < count; i++) {
+		pdest[i] = psrc[i] >> shift;
+	}
+}
+
+void MV_8BitReverbFast( const signed char *src, signed char *dest, int count, int shift )
+{
+	int i;
+
+	unsigned char sh = 0x80 - (0x80 >> shift);
+	
+	for (i = 0; i < count; i++) {
+		unsigned char a = ((unsigned char) src[i]) >> shift;
+		unsigned char c = (((unsigned char) src[i]) ^ 0x80) >> 7;
+		
+		dest[i] = (signed char) (a + sh + c);
+	}
+}
--- /dev/null
+++ b/rott/audiolib/myprint.c
@@ -1,0 +1,310 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include "myprint.h"
+
+static unsigned short disp_offset = 160 * 24;
+
+void DrawText
+   (
+   int x,
+   int y,
+   int ch,
+   int foreground,
+   int background
+   )
+
+   {
+   char *vid;
+
+   vid  = ( char * )( 0xb0000 );
+   vid += y * 160;
+   vid += x * 2;
+
+   if ( ch != NONE )
+      {
+      *vid = ch;
+      }
+   vid++;
+   *vid = ( ( background & 0x0f ) << 4 ) | ( foreground & 0x0f );
+   }
+
+void TextBox
+   (
+   int  x1,
+   int  y1,
+   int  x2,
+   int  y2,
+   int ch,
+   int  foreground,
+   int  background
+   )
+
+   {
+   int x;
+   int y;
+
+   for( x = x1; x <= x2; x++ )
+      {
+      for( y = y1; y <= y2; y++ )
+         {
+         DrawText( x, y, ch, foreground, background );
+         }
+      }
+   }
+
+void TextFrame
+   (
+   int x1,
+   int y1,
+   int x2,
+   int y2,
+   int type,
+   int foreground,
+   int background
+   )
+
+   {
+   int x;
+   int y;
+
+   if ( type == 0 )
+      {
+      for( x = x1 + 1; x < x2; x++ )
+         {
+         DrawText( x, y1, type, foreground, background );
+         DrawText( x, y2, type, foreground, background );
+         }
+      for( y = y1 + 1; y < y2; y++ )
+         {
+         DrawText( x1, y, type, foreground, background );
+         DrawText( x2, y, type, foreground, background );
+         }
+      }
+   if ( type == SINGLE_FRAME )
+      {
+      DrawText( x1, y1, '�', foreground, background );
+      DrawText( x2, y1, '�', foreground, background );
+      DrawText( x1, y2, '�', foreground, background );
+      DrawText( x2, y2, '�', foreground, background );
+      for( x = x1 + 1; x < x2; x++ )
+         {
+         DrawText( x, y1, '�', foreground, background );
+         DrawText( x, y2, '�', foreground, background );
+         }
+      for( y = y1 + 1; y < y2; y++ )
+         {
+         DrawText( x1, y, '�', foreground, background );
+         DrawText( x2, y, '�', foreground, background );
+         }
+      }
+   if ( type == DOUBLE_FRAME )
+      {
+      DrawText( x1, y1, '�', foreground, background );
+      DrawText( x2, y1, '�', foreground, background );
+      DrawText( x1, y2, '�', foreground, background );
+      DrawText( x2, y2, '�', foreground, background );
+      for( x = x1 + 1; x < x2; x++ )
+         {
+         DrawText( x, y1, '�', foreground, background );
+         DrawText( x, y2, '�', foreground, background );
+         }
+      for( y = y1 + 1; y < y2; y++ )
+         {
+         DrawText( x1, y, '�', foreground, background );
+         DrawText( x2, y, '�', foreground, background );
+         }
+      }
+   }
+
+void mysetxy
+   (
+   int x,
+   int y
+   )
+
+   {
+   disp_offset = ( x * 2 ) + ( y * 160 );
+   }
+
+void myputch
+   (
+   char ch
+   )
+
+   {
+   int j;
+   char *disp_start = (char *)( 0xb0000 );
+
+   if ( disp_offset >= 160 * 24 )
+      {
+      for ( j = 160; j < 160 * 24; j += 2 )
+         {
+         *( disp_start + j - 160 ) = *( disp_start + j );
+         }
+
+      disp_offset = 160 * 23;
+
+      for ( j = disp_offset; j < ( 160 * 24 ); j += 2 )
+         {
+         *( disp_start + j ) = ' ';
+         }
+      }
+
+   if ( ch >= 32 )
+      {
+      *( disp_start + disp_offset ) = ch;
+      disp_offset = disp_offset + 2;
+      }
+
+   if ( ch == '\r' )
+      {
+      disp_offset = disp_offset / 160;
+      disp_offset = disp_offset * 160;
+      }
+
+   if ( ch == '\n' )
+      {
+      disp_offset = disp_offset + 160;
+      if ( disp_offset < 160 * 24 )
+         {
+         for ( j = disp_offset; j < ( ( ( disp_offset / 160 ) + 1 ) *
+            160 ); j += 2 )
+            {
+            *( disp_start + j ) = ' ';
+            }
+         }
+      }
+   }
+
+int printstring
+   (
+   char *string
+   )
+
+   {
+   int count;
+   char *ptr;
+
+   ptr = string;
+   count = 0;
+
+   while ( *ptr )
+      {
+      myputch( *ptr );
+      count++;
+      ptr++;
+      }
+
+   return( count );
+   }
+
+
+int printnum
+   (
+   int number
+   )
+
+   {
+   char string[ 100 ];
+   int  count;
+
+   itoa( number, string, 10 );
+   count = printstring( string );
+
+   return( count );
+   }
+
+int printunsigned
+   (
+   unsigned long number,
+   int radix
+   )
+
+   {
+   char string[ 100 ];
+   int  count;
+
+   ultoa( number, string, radix );
+   count = printstring( string );
+
+   return( count );
+   }
+
+int myprintf
+   (
+   char *fmt,
+   ...
+   )
+
+   {
+   va_list argptr;
+   int     count;
+   char    *ptr;
+
+   return( 0 );
+
+   // DEBUG
+   mysetxy( 0, 0 );
+
+   va_start( argptr, fmt );
+   ptr = fmt;
+   count = 0;
+
+   while( *ptr != 0 )
+      {
+      if ( *ptr == '%' )
+         {
+         ptr++;
+         switch( *ptr )
+            {
+            case 0 :
+               return( EOF );
+               break;
+            case 'd' :
+               count += printnum( va_arg( argptr, int ) );
+               break;
+            case 's' :
+               count += printstring( va_arg( argptr, char * ) );
+               break;
+            case 'u' :
+               count += printunsigned( va_arg( argptr, int ), 10 );
+               break;
+            case 'x' :
+            case 'X' :
+               count += printunsigned( va_arg( argptr, int ), 16 );
+               break;
+            }
+         ptr++;
+         }
+      else
+         {
+         myputch( *ptr );
+         count++;
+         ptr++;
+         }
+      }
+
+   va_end( argptr );
+
+   return( count );
+   }
--- /dev/null
+++ b/rott/audiolib/myprint.h
@@ -1,0 +1,43 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+#ifndef __MYPRINT_H
+#define __MYPRINT_H
+
+enum COLORS
+   {
+   BLACK, BLUE, GREEN, CYAN, RED, MAGENTA, BROWN, LIGHTGRAY, DARKGRAY,
+   LIGHTBLUE, LIGHTGREEN, LIGHTCYAN, LIGHTRED, LIGHTMAGENTA, YELLOW, WHITE
+   };
+
+#define NONE         -1
+#define SINGLE_FRAME -1
+#define DOUBLE_FRAME -2
+
+void DrawText( int x, int y, int ch, int foreground, int background );
+void TextBox( int x1, int y1, int x2, int y2, int ch, int foreground, int background );
+void TextFrame( int x1, int y1, int x2, int y2, int type, int foreground, int background );
+void mysetxy( int x, int y );
+void myputch( char ch );
+int  printstring( char *string );
+int  printnum( int number );
+int  printunsigned( unsigned long number, int radix );
+int  myprintf( char *fmt, ... );
+
+#endif
--- /dev/null
+++ b/rott/audiolib/newgf1.h
@@ -1,0 +1,431 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+/***************************************************************************
+*	NAME:  GF1.H
+**	COPYRIGHT:
+**	"Copyright (c) 1991,1992, by FORTE
+**
+**       "This software is furnished under a license and may be used,
+**       copied, or disclosed only in accordance with the terms of such
+**       license and with the inclusion of the above copyright notice.
+**       This software or any other copies thereof may not be provided or
+**       otherwise made available to any other person. No title to and
+**       ownership of the software is hereby transfered."
+****************************************************************************
+*  CREATION DATE: 07/01/92
+*--------------------------------------------------------------------------*
+*     VERSION	DATE	   NAME		DESCRIPTION
+*>	1.0	07/01/92		Original
+***************************************************************************/
+
+#ifndef	_GF1_H		/* allow header to be processed only once */
+#define _GF1_H
+
+/* error codes */
+#define OK			0
+#define NO_MORE_VOICES		-1
+#define	BASE_NOT_FOUND		1
+#define BAD_IRQ			2
+#define BAD_DMA			3
+#define OS_LOADED		4
+#define NOT_LOADED		5
+#define NO_MEMORY		6
+#define DMA_BUSY		7
+#define NO_MORE_HANDLERS	8
+#define DMA_HUNG		9
+#define CARD_NOT_FOUND		10
+#define CARD_BEING_USED		11
+#define NO_MORE_INTERRUPTS	12
+#define BAD_TIMER		13
+#define BAD_PATCH		14
+#define OLD_PATCH		15
+#define DOS_ERROR		16
+#define FILE_NOT_FOUND		17
+
+/* bits */
+#define	BIT0	0x01
+#define	BIT1	0x02
+#define	BIT2	0x04
+#define	BIT3	0x08
+#define	BIT4	0x10
+#define	BIT5	0x20
+#define	BIT6	0x40
+#define	BIT7	0x80
+
+/* bounds for volume enveloping functions */
+#define MIN_OFFSET      5U
+#define MAX_OFFSET      251U
+
+/* bounds for voice allocation */
+#define MIN_VOICES	14
+#define MAX_VOICES	32
+
+/* DMA control bits */
+#define DMA_ENABLE		BIT0
+#define DMA_READ		BIT1
+#define DMA_WIDTH_16		BIT2 /* width of DMA channel */
+#define DMA_RATE_DIV_1		BIT3
+#define DMA_RATE_DIV_2		BIT4
+#define DMA_IRQ_ENABLE		BIT5
+#define DMA_IRQ_PRESENT		BIT6
+#define DMA_DATA_16		BIT6 /* width of data */
+#define DMA_INVERT_MSB		BIT7
+
+/* SAMPLE control bits */
+#define DMA_STEREO		2
+
+/* DMA flags */
+#define GF1_RECORD	0 /* use dma control or sample control */
+#define GF1_DMA		1
+
+/* MIDI control register */
+#define MIDI_RESET	(BIT0|BIT1)
+#define MIDI_TD_INT	BIT5
+#define MIDI_RD_INT	BIT7
+
+/* MIDI_STATUS_REGISTER */
+#define MIDI_RD		BIT0
+#define MIDI_TD		BIT1
+#define MIDI_ERR_FRAMING BIT4
+#define MIDI_ERR_OVERRUN BIT5
+
+/* digital playback flags */
+#define TYPE_8BIT	BIT0	/* 1 use 8 bit data */
+				/* 0 use 16 bit data */
+#define TYPE_PRELOAD	BIT1	/* preload data */
+#define TYPE_INVERT_MSB BIT2	/* invert most significant bit during dma */
+#define TYPE_STEREO	BIT3	/* 1 for stereo data */
+
+/* sound effects and digital music types */
+#define SND_LOOP_MASK		(BIT0|BIT1)
+#define SND_LOOP_NONE		0
+#define SND_LOOP		1
+#define SND_LOOP_BIDIR		2
+#define SND_8BIT		(BIT2)
+#define SND_BACKWARD		(BIT3)
+
+#define SOUND_PLAYING		2
+#define SOUND_ACTIVE		1
+
+/* patch macros */
+#define HEADER_SIZE	           12
+#define ID_SIZE		           10
+#define DESC_SIZE 	           60
+#define RESERVED_SIZE	           40
+#define PATCH_HEADER_RESERVED_SIZE 36
+#define LAYER_RESERVED_SIZE	   40
+#define PATCH_DATA_RESERVED_SIZE   36
+#define GF1_HEADER_TEXT            "GF1PATCH110"
+#define INST_NAME_SIZE		   16
+#define ENVELOPES		   6
+#define MAX_LAYERS		   4
+
+/* patch modes */
+#define PATCH_16		BIT0
+#define PATCH_UNSIGNED		BIT1
+#define PATCH_LOOPEN		BIT2
+#define PATCH_BIDIR		BIT3
+#define PATCH_BACKWARD  	BIT4
+#define PATCH_SUSTAIN   	BIT5
+#define PATCH_NO_SRELEASE	BIT6
+#define PATCH_FAST_REL		BIT7
+
+/* flags for patch loading */
+#define PATCH_LOAD_8_BIT BIT0
+
+/* digital playback callback reasons & return values */
+#define	DIG_DONE	   0
+#define DIG_MORE_DATA	   1
+#define DIG_BUFFER_DONE    2
+#define DIG_PAUSE          3
+
+/* log table used for vibrato and pitch bend.  log table made public for
+** developers use */
+#define LOG_TAB_SIZE 12
+extern long gf1_log_table[LOG_TAB_SIZE];
+
+#if defined(__BORLANDC__)
+#undef RFAR
+#define RFAR far
+#elif defined(_MSC_VER) && (_MSC_VER <= 600)
+#define RFAR far
+#elif defined(_MSC_VER) && (_MSC_VER > 600)
+#define RFAR __far
+#else
+#undef RFAR
+#define RFAR
+#endif
+
+/* structure definitions */
+struct	load_os	
+{
+	unsigned short 	voices;
+	unsigned short	forced_base_port;
+	unsigned char	forced_gf1_irq;
+	unsigned char	forced_midi_irq;
+	unsigned char	forced_channel_in;
+	unsigned char	forced_channel_out;
+};
+
+struct	patchheader
+{
+	char		header[ HEADER_SIZE ];	
+	char		gravis_id[ ID_SIZE ];	/* Id = "ID#000002" */
+	char		description[ DESC_SIZE ];
+	unsigned char	instruments;
+	char		voices;
+	char		channels;
+	unsigned short	wave_forms;
+	unsigned short	master_volume;
+	unsigned long	data_size;
+	char		reserved[ PATCH_HEADER_RESERVED_SIZE ];
+};
+
+struct	instrumentdata
+{
+	unsigned short	instrument;
+	char		instrument_name[ INST_NAME_SIZE ];
+	long		instrument_size;
+	char		layers;
+	char		reserved[ RESERVED_SIZE ];	
+};
+
+struct	layerdata
+{
+	char		layer_duplicate;
+	char		layer;
+	long		layer_size;
+	char		samples;
+	char		reserved[ LAYER_RESERVED_SIZE ];	
+};
+
+struct	patchdata
+{
+	char		wave_name[7];
+	unsigned char	fractions;
+	long		wave_size;
+	long		start_loop;
+	long		end_loop;
+	unsigned short	sample_rate;
+	long		low_frequency;
+	long		high_frequency;
+	long		root_frequency;
+	short		tune;
+	unsigned char	balance;
+	unsigned char	envelope_rate[ ENVELOPES ];
+	unsigned char	envelope_offset[ ENVELOPES ];	
+	unsigned char	tremolo_sweep;
+	unsigned char	tremolo_rate;
+	unsigned char	tremolo_depth;
+	unsigned char	vibrato_sweep;
+	unsigned char	vibrato_rate;
+	unsigned char	vibrato_depth;
+	char		modes;
+	short		scale_frequency;
+	unsigned short	scale_factor;		/* from 0 to 2048 or 0 to 2 */
+	char		reserved[ PATCH_DATA_RESERVED_SIZE ];
+};
+
+struct wave_struct
+{
+	unsigned long		start_loop;
+	unsigned long		end_loop;
+	long		low_frequency;
+	long		high_frequency;
+	long		root_frequency;
+	unsigned long	mem;
+	unsigned short	scale_frequency;
+	unsigned short	sample_rate;
+	unsigned short	scale_factor;
+	unsigned short	start_acc_low;
+	unsigned short	start_acc_high;
+	unsigned short	start_low;
+	unsigned short	start_high;
+	unsigned short	end_low;
+	unsigned short	end_high;
+	unsigned short	end_acc_low;
+	unsigned short	end_acc_high;
+	unsigned short	sample_ratio;
+	unsigned long	wave_size;
+	unsigned char	fractions;
+	unsigned char	balance;
+	unsigned char	envelope_rate[ ENVELOPES ];
+	unsigned char	envelope_offset[ ENVELOPES ];	
+	unsigned char	tremolo_sweep;
+	unsigned char	tremolo_rate;
+	unsigned char	tremolo_depth;
+	unsigned char	vibrato_sweep;
+	unsigned char	vibrato_rate;
+	unsigned char	vibrato_depth;
+	unsigned char	modes;
+};
+
+struct patchinfo {
+	struct patchheader header;
+	struct instrumentdata idata;
+};
+
+struct patch {
+	short nlayers;
+	struct wave_struct RFAR *layer_waves[MAX_LAYERS];
+	short layer_nwaves[MAX_LAYERS];
+	unsigned short detune;
+};
+
+struct gf1_dma_buff {
+	unsigned char RFAR *vptr;
+	unsigned long paddr;
+};
+
+struct gf1_sound {
+	unsigned long mem_pos;
+	unsigned long start_loop;
+	unsigned long end_loop;
+	unsigned char type;
+};
+
+/* GLOBAL VARIABLES (flags) */
+extern char gf1_linear_volumes;
+extern char gf1_dig_use_extra_voice;
+
+/* FUNCTION PROTOTYPES */
+/* Initializeation routines */
+int	gf1_init_ports(int);
+int	gf1_load_os(struct load_os RFAR *os);
+int	gf1_unload_os(void);
+void	gf1_set_appname(char RFAR *);
+void	reset_ultra(int);
+int	gf1_asm_init(void);
+unsigned char gf1_peek(unsigned long address);
+void gf1_poke(unsigned long address, unsigned char data);
+void gf1_poke_block(unsigned char RFAR *data, unsigned long address, unsigned long len, unsigned char dma_control);
+char gf1_good_dram(unsigned long address);
+int GetUltraCfg(struct load_os RFAR *os);
+unsigned long gf1_malloc(unsigned long);
+void gf1_free(unsigned long);
+unsigned long gf1_mem_avail(void);
+unsigned long gf1_mem_largest_avail(void);
+void gf1_delay(void);
+int gf1_allocate_voice(int priority, void (RFAR *steal_notify)(int));
+void gf1_free_voice(unsigned int i);
+void gf1_adjust_priority(int voice, int priority);
+int gf1_dram_xfer(struct gf1_dma_buff RFAR *dptr, unsigned long size, unsigned long dram_address, unsigned char dma_control, unsigned short flags);
+void gf1_stop_dma(void);
+long convert_to_16bit(long address);
+int gf1_wait_dma(void);
+int gf1_dma_ready(void);
+unsigned long gf1_amount_xferred(void);
+int gf1_detect_card(unsigned short port);
+char *gf1_error_str(int);
+int gf1_play_digital(unsigned short priority, unsigned char RFAR *buffer,
+	unsigned long size, unsigned long gf1_addr, unsigned short volume,
+	unsigned short pan, unsigned short frequency, unsigned char type,
+	struct gf1_dma_buff RFAR *dptr,
+	int (RFAR *callback)(int, int, unsigned char RFAR * RFAR *, unsigned long RFAR *));
+void gf1_restart_digital(int voice);
+void gf1_start_digital(int voice);
+void gf1_pause_digital(int voice);
+void RFAR gf1_stop_digital(int voice);
+void gf1_dig_set_dma_rate(unsigned short rate);
+unsigned long gf1_digital_position(int voice);
+int gf1_myatoi(void);
+int gf1_update_waveform(struct wave_struct RFAR *wave_info);
+int gf1_get_patch_info(char RFAR *patch_file, struct patchinfo RFAR *patch);
+int gf1_load_patch(char RFAR *patch_file, struct patchinfo RFAR *patchinfo,
+	struct patch RFAR *patch,
+	struct gf1_dma_buff RFAR *dptr, unsigned short size,
+	unsigned char RFAR *wavemem, int flags);
+void gf1_unload_patch(struct patch RFAR *patch);
+void gf1_detune_patch(struct patch RFAR *patch, unsigned short detune);
+unsigned short gf1_calc_fc(unsigned int sample_ratio,long root,long frequency);
+void gf1_midi_stop_voice(int voice);
+void gf1_midi_wait_voice(int voice);
+unsigned short gf1_midi_status_note(int voice);
+unsigned short gf1_midi_status_voice(int voice);
+void RFAR gf1_midi_stop_note(int note_voice);
+void gf1_midi_note_on(struct patch RFAR *patch, int priority, int note, int velocity, int channel);
+void gf1_midi_note_off(int note, int channel);
+void gf1_midi_silence_patch_notes(struct patch RFAR *patch);
+void gf1_midi_patch_removed(struct patch RFAR *patch);
+int gf1_enable_timer1(int (RFAR *callback)(void), int resolution);
+int gf1_enable_timer2(int (RFAR *callback)(void), int resolution);
+void gf1_disable_timer1(void);
+void gf1_disable_timer2(void);
+void gf1_channel_pitch_bend(int channel, unsigned int bend);
+void gf1_midi_synth_volume(unsigned short synth, int master_volume);
+void gf1_midi_change_program(struct patch RFAR *patch, int channel);
+void gf1_midi_set_vibrato(int channel, int value);
+void gf1_midi_change_volume(int channel, unsigned int volume);
+void gf1_midi_set_balance(int balance, int channel);
+void gf1_midi_channel_sustain(int channel, int sustain);
+void gf1_midi_all_notes_off(int channel);
+void gf1_midi_pitch_bend(int channel, int lsb, int msb);
+void gf1_midi_parameter(int channel, int control, int value);
+int gf1_midi_get_channel_notes(int channel, int notes[]);
+int gf1_midi_get_channel_volume(int channel);
+int gf1_midi_get_master_volume(void);
+int gf1_midi_get_volume(int voice);
+unsigned short gf1_read(int handle, void RFAR *io_buffer, unsigned short size);
+unsigned short gf1_close_file(int handle);
+unsigned int gf1_seek(int handle, unsigned long offset, int method);
+int gf1_open(char RFAR *name);
+#ifdef __FLAT__
+int gf1_atoi(char RFAR **str, int base);
+#else
+int gf1_atoi(void);
+#endif
+void gf1_leave(void);
+short gf1_enter(void);
+void gf1_enter1(void);
+int gf1_play_next_buffer(int voice, unsigned char RFAR *buff, unsigned long size);
+void gf1_dig_set_vol(unsigned short voice, unsigned short vol);
+void gf1_dig_set_pan(unsigned short voice, unsigned short pan);
+int gf1_set_external_semaphore(void RFAR *addr);
+int gf1_clear_external_semaphore(void RFAR *addr);
+void gf1_midi_reset(int c);
+int gf1_add_midi_recv_handler(int (RFAR *handler)());
+int gf1_add_dma_handler(int (*handler)());
+int gf1_add_voice_handler(int (*handler)(int));
+int gf1_add_volume_handler(int (*handler)(int));
+int gf1_add_timer_handler(int timer, int (RFAR *handler)(void));
+void gf1_set_record_rate(unsigned long rate);
+void gf1_create_patch(struct patch RFAR *patch);
+int gf1_add_layer(struct patch RFAR *patch, int layer, char RFAR *wavemem);
+void gf1_get_waveform_info(struct patch RFAR *patch, int layer, int waven,
+	struct wave_struct RFAR *wave);
+void gf1_set_waveform_info(struct patch RFAR *patch, int layer, int waven,
+	struct wave_struct RFAR *wave);
+void gf1_enable_line_in(void);
+void gf1_disable_line_in(void);
+void gf1_enable_mic_in(void);
+void gf1_disable_mic_in(void);
+void gf1_enable_output(void);
+void gf1_disable_output(void);
+void gf1_sound_volume(unsigned short voice, int volume,
+	unsigned long period /* us*10 */);
+void gf1_sound_pan(unsigned short voice, unsigned short pan);
+void gf1_sound_frequency(unsigned short voice, unsigned long freq);
+void RFAR gf1_sound_stop(int voice);
+void gf1_sound_mode(int voice, struct gf1_sound RFAR *sound,
+	unsigned char type);
+int gf1_sound_start(unsigned short priority, struct gf1_sound RFAR *sound,
+	short volume, unsigned long period, short pan, unsigned long freq);
+int gf1_sound_playing(int voice);
+#endif
--- /dev/null
+++ b/rott/audiolib/nodpmi.c
@@ -1,0 +1,179 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+/**********************************************************************
+   module: DPMI.C
+
+   author: James R. Dose
+   date:   April 8, 1994
+
+   Functions for performing DPMI calls.
+
+   (c) Copyright 1994 James R. Dose.  All Rights Reserved.
+**********************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+#include "dpmi.h"
+
+#define TRUE  ( 1 == 1 )
+#define FALSE ( !TRUE )
+
+/*---------------------------------------------------------------------
+   Function: DPMI_GetRealModeVector
+
+   Returns the vector of a real mode interrupt.
+---------------------------------------------------------------------*/
+
+unsigned long DPMI_GetRealModeVector
+   (
+   int num
+   )
+
+   {
+   return 0;
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: DPMI_SetRealModeVector
+
+   Sets the vector of a real mode interrupt.
+---------------------------------------------------------------------*/
+
+void DPMI_SetRealModeVector
+   (
+   int num,
+   unsigned long vector
+   )
+
+   {
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: DPMI_CallRealModeFunction
+
+   Performs a call to a real mode function.
+---------------------------------------------------------------------*/
+
+int DPMI_CallRealModeFunction
+   (
+   dpmi_regs *callregs
+   )
+
+   {
+   return( DPMI_Ok );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: DPMI_LockMemory
+
+   Locks a region of memory to keep the virtual memory manager from
+   paging the region out.
+---------------------------------------------------------------------*/
+
+int DPMI_LockMemory
+   (
+   void *address,
+   unsigned length
+   )
+
+   {
+   return ( DPMI_Ok );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: DPMI_LockMemoryRegion
+
+   Locks a region of memory to keep the virtual memory manager from
+   paging the region out.
+---------------------------------------------------------------------*/
+
+int DPMI_LockMemoryRegion
+   (
+   void *start,
+   void *end
+   )
+
+   {
+   int status;
+
+   status = DPMI_LockMemory( start, ( char * )end - ( char * )start );
+
+   return( status );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: DPMI_UnlockMemory
+
+   Unlocks a region of memory that was previously locked.
+---------------------------------------------------------------------*/
+
+int DPMI_UnlockMemory
+   (
+   void *address,
+   unsigned length
+   )
+
+   {
+   return ( DPMI_Ok );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: DPMI_UnlockMemoryRegion
+
+   Unlocks a region of memory that was previously locked.
+---------------------------------------------------------------------*/
+
+int DPMI_UnlockMemoryRegion
+   (
+   void *start,
+   void *end
+   )
+
+   {
+   int status;
+
+   status = DPMI_UnlockMemory( start, ( char * )end - ( char * )start );
+
+   return( status );
+   }
+
+int DPMI_GetDOSMemory( void **ptr, long *descriptor, unsigned length )
+{
+	/* Lovely... */
+	
+	*ptr = (void *)malloc(length);
+	
+	*descriptor = (long) *ptr;
+	
+	return (descriptor == 0) ? DPMI_Error : DPMI_Ok;
+}
+
+int DPMI_FreeDOSMemory( long descriptor )
+{
+	free((void *)descriptor);
+	
+	return (descriptor == 0) ? DPMI_Error : DPMI_Ok;
+}
--- /dev/null
+++ b/rott/audiolib/nomusic.c
@@ -1,0 +1,115 @@
+#include "music.h"
+
+char *MUSIC_ErrorString(int ErrorNumber)
+{
+	return "";
+}
+
+int MUSIC_Init(int SoundCard, int Address)
+{
+	return 0;
+}
+
+int MUSIC_Shutdown(void)
+{
+	return 0;
+}
+
+void MUSIC_SetMaxFMMidiChannel(int channel)
+{
+}
+
+void MUSIC_SetVolume(int volume)
+{
+}
+
+void MUSIC_SetMidiChannelVolume(int channel, int volume)
+{
+}
+
+void MUSIC_ResetMidiChannelVolumes(void)
+{
+}
+
+int MUSIC_GetVolume(void)
+{
+	return 0;
+}
+
+void MUSIC_SetLoopFlag(int loopflag)
+{
+}
+
+int MUSIC_SongPlaying(void)
+{
+	return 0;
+}
+
+void MUSIC_Continue(void)
+{
+}
+
+void MUSIC_Pause(void)
+{
+}
+
+int MUSIC_StopSong(void)
+{
+	return 0;
+}
+
+int MUSIC_PlaySong(unsigned char *song, int loopflag)
+{
+	return 0;
+}
+
+void MUSIC_SetContext(int context)
+{
+}
+
+int MUSIC_GetContext(void)
+{
+	return 0;
+}
+
+void MUSIC_SetSongTick(unsigned long PositionInTicks)
+{
+}
+
+void MUSIC_SetSongTime(unsigned long milliseconds)
+{
+}
+
+void MUSIC_SetSongPosition(int measure, int beat, int tick)
+{
+}
+
+void MUSIC_GetSongPosition(songposition *pos)
+{
+}
+
+void MUSIC_GetSongLength(songposition *pos)
+{
+}
+
+int MUSIC_FadeVolume(int tovolume, int milliseconds)
+{
+	return 0;
+}
+
+int MUSIC_FadeActive(void)
+{
+	return 0;
+}
+
+void MUSIC_StopFade(void)
+{
+}
+
+void MUSIC_RerouteMidiChannel(int channel, int cdecl function( int event, int c1, int c2 ))
+{
+}
+
+void MUSIC_RegisterTimbreBank(unsigned char *timbres)
+{
+}
--- /dev/null
+++ b/rott/audiolib/pas16.c
@@ -1,0 +1,1924 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+/**********************************************************************
+   module: PAS16.C
+
+   author: James R. Dose
+   date:   March 27, 1994
+
+   Low level routines to support Pro AudioSpectrum and compatible
+   sound cards.
+
+   (c) Copyright 1994 James R. Dose.  All Rights Reserved.
+**********************************************************************/
+
+#include <dos.h>
+#include <conio.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "dpmi.h"
+#include "dma.h"
+#include "interrup.h"
+#include "irq.h"
+#include "pas16.h"
+#include "_pas16.h"
+
+#define USESTACK
+
+static const int PAS_Interrupts[ PAS_MaxIrq + 1 ]  =
+   {
+   INVALID, INVALID,     0xa,     0xb,
+   INVALID,     0xd, INVALID,     0xf,
+   INVALID, INVALID,    0x72,    0x73,
+      0x74, INVALID, INVALID,    0x77
+   };
+
+static void    ( interrupt far *PAS_OldInt )( void );
+
+static int PAS_IntController1Mask;
+static int PAS_IntController2Mask;
+
+static int PAS_Installed = FALSE;
+static int PAS_TranslateCode = DEFAULT_BASE;
+
+static int PAS_OriginalPCMLeftVolume  = 75;
+static int PAS_OriginalPCMRightVolume = 75;
+
+static int PAS_OriginalFMLeftVolume  = 75;
+static int PAS_OriginalFMRightVolume = 75;
+
+unsigned int PAS_DMAChannel;
+static int PAS_Irq;
+
+static MVState *PAS_State = NULL;
+static MVFunc  *PAS_Func  = NULL;
+
+static MVState PAS_OriginalState;
+static int     PAS_SampleSizeConfig;
+
+static char   *PAS_DMABuffer;
+static char   *PAS_DMABufferEnd;
+static char   *PAS_CurrentDMABuffer;
+static int     PAS_TotalDMABufferSize;
+
+static int      PAS_TransferLength   = 0;
+static int      PAS_MixMode          = PAS_DefaultMixMode;
+static unsigned PAS_SampleRate       = PAS_DefaultSampleRate;
+static int      PAS_TimeInterval     = 0;
+
+volatile int   PAS_SoundPlaying;
+
+void ( *PAS_CallBack )( void );
+
+// adequate stack size
+#define kStackSize 2048
+
+static unsigned short StackSelector = NULL;
+static unsigned long  StackPointer;
+
+static unsigned short oldStackSelector;
+static unsigned long  oldStackPointer;
+
+// This is defined because we can't create local variables in a
+// function that switches stacks.
+static int irqstatus;
+
+// These declarations are necessary to use the inline assembly pragmas.
+
+extern void GetStack(unsigned short *selptr,unsigned long *stackptr);
+extern void SetStack(unsigned short selector,unsigned long stackptr);
+
+// This function will get the current stack selector and pointer and save
+// them off.
+#pragma aux GetStack =  \
+   "mov  [edi],esp"     \
+   "mov  ax,ss"         \
+   "mov  [esi],ax"      \
+   parm [esi] [edi]     \
+   modify [eax esi edi];
+
+// This function will set the stack selector and pointer to the specified
+// values.
+#pragma aux SetStack =  \
+   "mov  ss,ax"         \
+   "mov  esp,edx"       \
+   parm [ax] [edx]      \
+   modify [eax edx];
+
+int PAS_ErrorCode = PAS_Ok;
+
+#define PAS_SetErrorCode( status ) \
+   PAS_ErrorCode   = ( status );
+
+/*---------------------------------------------------------------------
+   Function: PAS_ErrorString
+
+   Returns a pointer to the error message associated with an error
+   number.  A -1 returns a pointer the current error.
+---------------------------------------------------------------------*/
+
+char *PAS_ErrorString
+   (
+   int ErrorNumber
+   )
+
+   {
+   char *ErrorString;
+
+   switch( ErrorNumber )
+      {
+      case PAS_Warning :
+      case PAS_Error :
+         ErrorString = PAS_ErrorString( PAS_ErrorCode );
+         break;
+
+      case PAS_Ok :
+         ErrorString = "Pro AudioSpectrum ok.";
+         break;
+
+      case PAS_DriverNotFound :
+         ErrorString = "MVSOUND.SYS not loaded.";
+         break;
+
+      case PAS_DmaError :
+         ErrorString = DMA_ErrorString( DMA_Error );
+         break;
+
+      case PAS_InvalidIrq :
+         ErrorString = "Invalid Pro AudioSpectrum Irq.";
+         break;
+
+      case PAS_UnableToSetIrq :
+         ErrorString = "Unable to set Pro AudioSpectrum IRQ.  Try selecting an IRQ of 7 or below.";
+         break;
+
+      case PAS_Dos4gwIrqError :
+         ErrorString = "Unsupported Pro AudioSpectrum Irq.";
+         break;
+
+      case PAS_NoSoundPlaying :
+         ErrorString = "No sound playing on Pro AudioSpectrum.";
+         break;
+
+      case PAS_CardNotFound :
+         ErrorString = "Could not find Pro AudioSpectrum.";
+         break;
+
+      case PAS_DPMI_Error :
+         ErrorString = "DPMI Error in PAS16.";
+         break;
+
+      case PAS_OutOfMemory :
+         ErrorString = "Out of conventional memory in PAS16.";
+         break;
+
+      default :
+         ErrorString = "Unknown Pro AudioSpectrum error code.";
+         break;
+      }
+
+   return( ErrorString );
+   }
+
+
+/**********************************************************************
+
+   Memory locked functions:
+
+**********************************************************************/
+
+
+#define PAS_LockStart PAS_CheckForDriver
+
+
+/*---------------------------------------------------------------------
+   Function: PAS_CheckForDriver
+
+   Checks to see if MVSOUND.SYS is installed.
+---------------------------------------------------------------------*/
+
+int PAS_CheckForDriver
+   (
+   void
+   )
+
+   {
+   union REGS regs;
+   unsigned   result;
+
+   regs.w.ax = MV_CheckForDriver;
+   regs.w.bx = 0x3f3f;
+
+   #ifdef __386__
+      int386( MV_SoundInt, &regs, &regs );
+   #else
+      int86( MV_SoundInt, &regs, &regs );
+   #endif
+
+   if ( regs.w.ax != MV_CheckForDriver )
+      {
+      PAS_SetErrorCode( PAS_DriverNotFound );
+      return( PAS_Error );
+      }
+
+   result = regs.w.bx ^ regs.w.cx ^ regs.w.dx;
+   if ( result != MV_Signature )
+      {
+      PAS_SetErrorCode( PAS_DriverNotFound );
+      return( PAS_Error );
+      }
+
+   return( PAS_Ok );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: PAS_GetStateTable
+
+   Returns a pointer to the state table containing hardware state
+   information.  The state table is necessary because the Pro Audio-
+   Spectrum contains only write-only registers.
+---------------------------------------------------------------------*/
+
+MVState *PAS_GetStateTable
+   (
+   void
+   )
+
+   {
+   union REGS   regs;
+   MVState *ptr;
+
+   regs.w.ax = MV_GetPointerToStateTable;
+
+   #ifdef __386__
+      int386( MV_SoundInt, &regs, &regs );
+   #else
+      int86( MV_SoundInt, &regs, &regs );
+   #endif
+
+   if ( regs.w.ax != MV_Signature )
+      {
+      PAS_SetErrorCode( PAS_DriverNotFound );
+      return( NULL );
+      }
+
+   #if defined(__WATCOMC__) && defined(__FLAT__)
+      ptr = ( MVState * )( ( ( ( unsigned )regs.w.dx ) << 4 ) +
+         ( ( unsigned )regs.w.bx ) );
+   #else
+      ptr = MK_FP( regs.w.dx, regs.w.bx );
+   #endif
+
+   return( ptr );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: PAS_GetFunctionTable
+
+   Returns a pointer to the function table containing addresses of
+   driver functions.
+---------------------------------------------------------------------*/
+
+MVFunc *PAS_GetFunctionTable
+   (
+   void
+   )
+
+   {
+   union REGS   regs;
+   MVFunc *ptr;
+
+   regs.w.ax = MV_GetPointerToFunctionTable;
+
+   #ifdef __386__
+      int386( MV_SoundInt, &regs, &regs );
+   #else
+      int86( MV_SoundInt, &regs, &regs );
+   #endif
+
+   if ( regs.w.ax != MV_Signature )
+      {
+      PAS_SetErrorCode( PAS_DriverNotFound );
+      return( NULL );
+      }
+
+   #if defined(__WATCOMC__) && defined(__FLAT__)
+      ptr = ( MVFunc * )( ( ( ( unsigned )regs.w.dx ) << 4 ) +
+         ( ( unsigned )regs.w.bx ) );
+   #else
+      ptr = MK_FP( regs.w.dx, regs.w.bx );
+   #endif
+
+   return( ptr );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: PAS_GetCardSettings
+
+   Returns the DMA and the IRQ channels of the sound card.
+---------------------------------------------------------------------*/
+
+int PAS_GetCardSettings
+   (
+   void
+   )
+
+   {
+   union REGS   regs;
+   int          status;
+
+   regs.w.ax = MV_GetDmaIrqInt;
+
+   #ifdef __386__
+      int386( MV_SoundInt, &regs, &regs );
+   #else
+      int86( MV_SoundInt, &regs, &regs );
+   #endif
+
+   if ( regs.w.ax != MV_Signature )
+      {
+      PAS_SetErrorCode( PAS_DriverNotFound );
+      return( PAS_Error );
+      }
+
+   PAS_DMAChannel = regs.w.bx;
+   PAS_Irq        = regs.w.cx;
+
+   if ( PAS_Irq > PAS_MaxIrq )
+      {
+      PAS_SetErrorCode( PAS_Dos4gwIrqError );
+      return( PAS_Error );
+      }
+
+   if ( !VALID_IRQ( PAS_Irq ) )
+      {
+      PAS_SetErrorCode( PAS_InvalidIrq );
+      return( PAS_Error );
+      }
+
+   if ( PAS_Interrupts[ PAS_Irq ] == INVALID )
+      {
+      PAS_SetErrorCode( PAS_InvalidIrq );
+      return( PAS_Error );
+      }
+
+   status = DMA_VerifyChannel( PAS_DMAChannel );
+   if ( status == DMA_Error )
+      {
+      PAS_SetErrorCode( PAS_DmaError );
+      return( PAS_Error );
+      }
+
+   return( PAS_Ok );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: PAS_EnableInterrupt
+
+   Enables the triggering of the sound card interrupt.
+---------------------------------------------------------------------*/
+
+void PAS_EnableInterrupt
+   (
+   void
+   )
+
+   {
+   int mask;
+   int data;
+   unsigned flags;
+
+   flags = DisableInterrupts();
+
+   if ( PAS_Irq < 8 )
+      {
+      mask = inp( 0x21 ) & ~( 1 << PAS_Irq );
+      outp( 0x21, mask  );
+      }
+   else
+      {
+      mask = inp( 0xA1 ) & ~( 1 << ( PAS_Irq - 8 ) );
+      outp( 0xA1, mask  );
+
+      mask = inp( 0x21 ) & ~( 1 << 2 );
+      outp( 0x21, mask  );
+      }
+
+   // Flush any pending interrupts
+   PAS_Write( InterruptStatus, PAS_Read( InterruptStatus ) & 0x40 );
+
+   // Enable the interrupt on the PAS
+   data = PAS_State->intrctlr;
+   data |= SampleBufferInterruptFlag;
+   PAS_Write( InterruptControl, data );
+   PAS_State->intrctlr = data;
+
+   RestoreInterrupts( flags );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: PAS_DisableInterrupt
+
+   Disables the triggering of the sound card interrupt.
+---------------------------------------------------------------------*/
+
+void PAS_DisableInterrupt
+   (
+   void
+   )
+
+   {
+   int mask;
+   int data;
+   unsigned flags;
+
+   flags = DisableInterrupts();
+
+   // Disable the interrupt on the PAS
+   data = PAS_State->intrctlr;
+   data &= ~( SampleRateInterruptFlag | SampleBufferInterruptFlag );
+   PAS_Write( InterruptControl, data );
+   PAS_State->intrctlr = data;
+
+   // Restore interrupt mask
+   if ( PAS_Irq < 8 )
+      {
+      mask  = inp( 0x21 ) & ~( 1 << PAS_Irq );
+      mask |= PAS_IntController1Mask & ( 1 << PAS_Irq );
+      outp( 0x21, mask  );
+      }
+   else
+      {
+      mask  = inp( 0x21 ) & ~( 1 << 2 );
+      mask |= PAS_IntController1Mask & ( 1 << 2 );
+      outp( 0x21, mask  );
+
+      mask  = inp( 0xA1 ) & ~( 1 << ( PAS_Irq - 8 ) );
+      mask |= PAS_IntController2Mask & ( 1 << ( PAS_Irq - 8 ) );
+      outp( 0xA1, mask  );
+      }
+
+   RestoreInterrupts( flags );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: PAS_ServiceInterrupt
+
+   Handles interrupt generated by sound card at the end of a voice
+   transfer.  Calls the user supplied callback function.
+---------------------------------------------------------------------*/
+
+void interrupt far PAS_ServiceInterrupt
+   (
+   void
+   )
+
+   {
+   #ifdef USESTACK
+   // save stack
+   GetStack( &oldStackSelector, &oldStackPointer );
+
+   // set our stack
+   SetStack( StackSelector, StackPointer );
+   #endif
+
+   irqstatus = PAS_Read( InterruptStatus );
+   if ( ( irqstatus & SampleBufferInterruptFlag ) == 0 )
+      {
+      #ifdef USESTACK
+      // restore stack
+      SetStack( oldStackSelector, oldStackPointer );
+      #endif
+
+      _chain_intr( PAS_OldInt );
+      }
+
+   // Clear the interrupt
+   irqstatus &= ~SampleBufferInterruptFlag;
+   PAS_Write( InterruptStatus, irqstatus );
+
+   // send EOI to Interrupt Controller
+   if ( PAS_Irq > 7 )
+      {
+      outp( 0xA0, 0x20 );
+      }
+   outp( 0x20, 0x20 );
+
+
+   // Keep track of current buffer
+   PAS_CurrentDMABuffer += PAS_TransferLength;
+   if ( PAS_CurrentDMABuffer >= PAS_DMABufferEnd )
+      {
+      PAS_CurrentDMABuffer = PAS_DMABuffer;
+      }
+
+   // Call the caller's callback function
+   if ( PAS_CallBack != NULL )
+      {
+      PAS_CallBack();
+      }
+
+   #ifdef USESTACK
+   // restore stack
+   SetStack( oldStackSelector, oldStackPointer );
+   #endif
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: PAS_Write
+
+   Writes a byte of data to the sound card.
+---------------------------------------------------------------------*/
+
+void PAS_Write
+   (
+   int Register,
+   int Data
+   )
+
+   {
+   int port;
+
+   port = Register ^ PAS_TranslateCode;
+   outp( port, Data );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: PAS_Read
+
+   Reads a byte of data from the sound card.
+---------------------------------------------------------------------*/
+
+int PAS_Read
+   (
+   int Register
+   )
+
+   {
+   int port;
+   int data;
+
+   port = Register ^ PAS_TranslateCode;
+   data = inp( port );
+   return( data );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: PAS_SetSampleRateTimer
+
+   Programs the Sample Rate Timer.
+---------------------------------------------------------------------*/
+
+void PAS_SetSampleRateTimer
+   (
+   void
+   )
+
+   {
+   int LoByte;
+   int HiByte;
+   int data;
+   unsigned flags;
+
+   flags = DisableInterrupts();
+
+   // Disable the Sample Rate Timer
+   data = PAS_State->audiofilt;
+   data &= ~SampleRateTimerGateFlag;
+   PAS_Write( AudioFilterControl, data );
+   PAS_State->audiofilt = data;
+
+   // Select the Sample Rate Timer
+   data = SelectSampleRateTimer;
+   PAS_Write( LocalTimerControl, data );
+   PAS_State->tmrctlr = data;
+
+   LoByte = lobyte( PAS_TimeInterval );
+   HiByte = hibyte( PAS_TimeInterval );
+
+   // Program the Sample Rate Timer
+   PAS_Write( SampleRateTimer, LoByte );
+   PAS_Write( SampleRateTimer, HiByte );
+   PAS_State->samplerate = PAS_TimeInterval;
+
+   RestoreInterrupts( flags );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: PAS_SetSampleBufferCount
+
+   Programs the Sample Buffer Count.
+---------------------------------------------------------------------*/
+
+void PAS_SetSampleBufferCount
+   (
+   void
+   )
+
+   {
+   int LoByte;
+   int HiByte;
+   int count;
+   int data;
+   unsigned flags;
+
+   flags = DisableInterrupts();
+
+   // Disable the Sample Buffer Count
+   data = PAS_State->audiofilt;
+   data &= ~SampleBufferCountGateFlag;
+   PAS_Write( AudioFilterControl, data );
+   PAS_State->audiofilt = data;
+
+   // Select the Sample Buffer Count
+   data = SelectSampleBufferCount;
+   PAS_Write( LocalTimerControl, data );
+   PAS_State->tmrctlr = data;
+
+   count = PAS_TransferLength;
+
+   // Check if we're using a 16-bit DMA channel
+   if ( PAS_DMAChannel > 3 )
+      {
+      count >>= 1;
+      }
+
+   LoByte = lobyte( count );
+   HiByte = hibyte( count );
+
+   // Program the Sample Buffer Count
+   PAS_Write( SampleBufferCount, LoByte );
+   PAS_Write( SampleBufferCount, HiByte );
+   PAS_State->samplecnt = count;
+
+   RestoreInterrupts( flags );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: PAS_SetPlaybackRate
+
+   Sets the rate at which the digitized sound will be played in
+   hertz.
+---------------------------------------------------------------------*/
+
+void PAS_SetPlaybackRate
+   (
+   unsigned rate
+   )
+
+   {
+   if ( rate < PAS_MinSamplingRate )
+      {
+      rate = PAS_MinSamplingRate;
+      }
+
+   if ( rate > PAS_MaxSamplingRate )
+      {
+      rate = PAS_MaxSamplingRate;
+      }
+
+   PAS_TimeInterval = ( unsigned )CalcTimeInterval( rate );
+   if ( PAS_MixMode & STEREO )
+      {
+      PAS_TimeInterval /= 2;
+      }
+
+   // Keep track of what the actual rate is
+   PAS_SampleRate = CalcSamplingRate( PAS_TimeInterval );
+   if ( PAS_MixMode & STEREO )
+      {
+      PAS_SampleRate /= 2;
+      }
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: PAS_GetPlaybackRate
+
+   Returns the rate at which the digitized sound will be played in
+   hertz.
+---------------------------------------------------------------------*/
+
+unsigned PAS_GetPlaybackRate
+   (
+   void
+   )
+
+   {
+   return( PAS_SampleRate );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: PAS_SetMixMode
+
+   Sets the sound card to play samples in mono or stereo.
+---------------------------------------------------------------------*/
+
+int PAS_SetMixMode
+   (
+   int mode
+   )
+
+   {
+   mode &= PAS_MaxMixMode;
+
+   // Check board revision.  Revision # 0 can't play 16-bit data.
+   if ( ( PAS_State->intrctlr & 0xe0 ) == 0 )
+      {
+      // Force the mode to 8-bit data.
+      mode &= ~SIXTEEN_BIT;
+      }
+
+   PAS_MixMode = mode;
+
+   PAS_SetPlaybackRate( PAS_SampleRate );
+
+   return( mode );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: PAS_StopPlayback
+
+   Ends the DMA transfer of digitized sound to the sound card.
+---------------------------------------------------------------------*/
+
+void PAS_StopPlayback
+   (
+   void
+   )
+
+   {
+   int data;
+
+   // Don't allow anymore interrupts
+   PAS_DisableInterrupt();
+
+   // Stop the transfer of digital data
+   data = PAS_State->crosschannel;
+   data &= PAS_PCMStopMask;
+   PAS_Write( CrossChannelControl, data );
+   PAS_State->crosschannel = data;
+
+   // Turn off 16-bit unsigned data
+   data = PAS_Read( SampleSizeConfiguration );
+   data &= PAS_SampleSizeMask;
+   PAS_Write( SampleSizeConfiguration, data );
+
+   // Disable the DMA channel
+   DMA_EndTransfer( PAS_DMAChannel );
+
+   PAS_SoundPlaying = FALSE;
+
+   PAS_DMABuffer = NULL;
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: PAS_SetupDMABuffer
+
+   Programs the DMAC for sound transfer.
+---------------------------------------------------------------------*/
+
+int PAS_SetupDMABuffer
+   (
+   char *BufferPtr,
+   int   BufferSize,
+   int   mode
+   )
+
+   {
+   int DmaStatus;
+   int data;
+
+   // Enable PAS Dma
+   data  = PAS_State->crosschannel;
+   data |= PAS_DMAEnable;
+   PAS_Write( CrossChannelControl, data );
+   PAS_State->crosschannel = data;
+
+   DmaStatus = DMA_SetupTransfer( PAS_DMAChannel, BufferPtr, BufferSize, mode );
+   if ( DmaStatus == DMA_Error )
+      {
+      PAS_SetErrorCode( PAS_DmaError );
+      return( PAS_Error );
+      }
+
+   PAS_DMABuffer          = BufferPtr;
+   PAS_CurrentDMABuffer   = BufferPtr;
+   PAS_TotalDMABufferSize = BufferSize;
+   PAS_DMABufferEnd       = BufferPtr + BufferSize;
+
+   return( PAS_Ok );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: PAS_GetCurrentPos
+
+   Returns the offset within the current sound being played.
+---------------------------------------------------------------------*/
+
+int PAS_GetCurrentPos
+   (
+   void
+   )
+
+   {
+   char *CurrentAddr;
+   int   offset;
+
+   if ( !PAS_SoundPlaying )
+      {
+      PAS_SetErrorCode( PAS_NoSoundPlaying );
+      return( PAS_Error );
+      }
+
+   CurrentAddr = DMA_GetCurrentPos( PAS_DMAChannel );
+   if ( CurrentAddr == NULL )
+      {
+      PAS_SetErrorCode( PAS_DmaError );
+      return( PAS_Error );
+      }
+
+   offset = ( int )( ( ( unsigned long )CurrentAddr ) -
+      ( ( unsigned long )PAS_CurrentDMABuffer ) );
+
+   if ( PAS_MixMode & SIXTEEN_BIT )
+      {
+      offset >>= 1;
+      }
+
+   if ( PAS_MixMode & STEREO )
+      {
+      offset >>= 1;
+      }
+
+   return( offset );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: PAS_GetFilterSetting
+
+   Returns the bit settings for the appropriate filter level.
+---------------------------------------------------------------------*/
+
+int PAS_GetFilterSetting
+   (
+   int rate
+   )
+
+   {
+   /* CD Quality 17897hz */
+   if ( ( unsigned long )rate > ( unsigned long )17897L * 2 )
+      {
+      /* 00001b 20hz to 17.8khz */
+      return( 0x01 );
+      }
+
+   /* Cassette Quality 15090hz */
+   if ( ( unsigned long )rate > ( unsigned long )15909L * 2 )
+      {
+      /* 00010b 20hz to 15.9khz */
+      return( 0x02 );
+      }
+
+   /* FM Radio Quality 11931hz */
+   if ( ( unsigned long )rate > ( unsigned long )11931L * 2 )
+      {
+      /* 01001b 20hz to 11.9khz */
+      return( 0x09 );
+      }
+
+   /* AM Radio Quality  8948hz */
+   if ( ( unsigned long )rate > ( unsigned long )8948L * 2 )
+      {
+      /* 10001b 20hz to 8.9khz */
+      return( 0x11 );
+      }
+
+   /* Telphone Quality  5965hz */
+   if ( ( unsigned long )rate > ( unsigned long )5965L * 2 )
+      {
+      /* 00100b 20hz to 5.9khz */
+      return( 0x19 );
+      }
+
+   /* Male voice quality 2982hz */
+   /* 111001b 20hz to 2.9khz */
+   return( 0x04 );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: PAS_BeginTransfer
+
+   Starts playback of digitized sound on the sound card.
+---------------------------------------------------------------------*/
+
+void PAS_BeginTransfer
+   (
+   int mode
+   )
+
+   {
+   int data;
+
+   PAS_SetSampleRateTimer();
+
+   PAS_SetSampleBufferCount();
+
+   PAS_EnableInterrupt();
+
+   // Get sample size configuration
+   data = PAS_Read( SampleSizeConfiguration );
+
+   // Check board revision.  Revision # 0 can't play 16-bit data.
+   if ( PAS_State->intrctlr & 0xe0 )
+      {
+      data &= PAS_SampleSizeMask;
+
+      // set sample size bit
+      if ( PAS_MixMode & SIXTEEN_BIT )
+         {
+         data |= PAS_16BitSampleFlag;
+         }
+      }
+
+   // set oversampling rate
+   data &= PAS_OverSamplingMask;
+   data |= PAS_4xOverSampling;
+
+   // Set sample size configuration
+   PAS_Write( SampleSizeConfiguration, data );
+
+   // Get Cross channel setting
+   data  = PAS_State->crosschannel;
+   data &= PAS_ChannelConnectMask;
+   if ( mode == RECORD )
+      {
+      data |= PAS_PCMStartADC;
+      }
+   else
+      {
+      data |= PAS_PCMStartDAC;
+      }
+
+   // set stereo mode bit
+   if ( !( PAS_MixMode & STEREO ) )
+      {
+      data |= PAS_StereoFlag;
+      }
+
+   PAS_Write( CrossChannelControl, data );
+   PAS_State->crosschannel = data;
+
+   // Get the filter appropriate filter setting
+   data = PAS_GetFilterSetting( PAS_SampleRate );
+
+   // Enable the Sample Rate Timer and Sample Buffer Count
+   data |= SampleRateTimerGateFlag | SampleBufferCountGateFlag;
+
+   if ( mode != RECORD )
+      {
+      // Enable audio (not Audio Mute)
+      data |= PAS_AudioMuteFlag;
+      }
+
+   PAS_Write( AudioFilterControl, data );
+   PAS_State->audiofilt = data;
+
+   PAS_SoundPlaying = TRUE;
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: PAS_BeginBufferedPlayback
+
+   Begins multibuffered playback of digitized sound on the sound card.
+---------------------------------------------------------------------*/
+
+int PAS_BeginBufferedPlayback
+   (
+   char *BufferStart,
+   int   BufferSize,
+   int   NumDivisions,
+   unsigned SampleRate,
+   int   MixMode,
+   void ( *CallBackFunc )( void )
+   )
+
+   {
+   int DmaStatus;
+
+   PAS_StopPlayback();
+
+   PAS_SetMixMode( MixMode );
+   PAS_SetPlaybackRate( SampleRate );
+
+   PAS_TransferLength = BufferSize / NumDivisions;
+   PAS_SetCallBack( CallBackFunc );
+
+   DmaStatus = PAS_SetupDMABuffer( BufferStart, BufferSize, DMA_AutoInitRead );
+   if ( DmaStatus == PAS_Error )
+      {
+      return( PAS_Error );
+      }
+
+   PAS_BeginTransfer( PLAYBACK );
+
+   return( PAS_Ok );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: PAS_BeginBufferedRecord
+
+   Begins multibuffered recording of digitized sound on the sound card.
+---------------------------------------------------------------------*/
+
+int PAS_BeginBufferedRecord
+   (
+   char *BufferStart,
+   int   BufferSize,
+   int   NumDivisions,
+   unsigned SampleRate,
+   int   MixMode,
+   void ( *CallBackFunc )( void )
+   )
+
+   {
+   int DmaStatus;
+
+   PAS_StopPlayback();
+
+   PAS_SetMixMode( MixMode );
+   PAS_SetPlaybackRate( SampleRate );
+
+   PAS_TransferLength = BufferSize / NumDivisions;
+   PAS_SetCallBack( CallBackFunc );
+
+   DmaStatus = PAS_SetupDMABuffer( BufferStart, BufferSize, DMA_AutoInitWrite );
+   if ( DmaStatus == PAS_Error )
+      {
+      return( PAS_Error );
+      }
+
+   PAS_BeginTransfer( RECORD );
+
+   return( PAS_Ok );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: PAS_CallInt
+
+   Calls interrupt 2fh.
+---------------------------------------------------------------------*/
+
+int PAS_CallInt( int ebx, int ecx, int edx );
+#pragma aux PAS_CallInt = \
+   "int 2fh",         \
+   parm [ ebx ] [ ecx ] [ edx ] modify exact [ eax ebx ecx edx esi edi ] value [ ebx ];
+
+
+/*---------------------------------------------------------------------
+   Function: PAS_CallMVFunction
+
+   Performs a call to a real mode function.
+---------------------------------------------------------------------*/
+
+int PAS_CallMVFunction
+   (
+   unsigned long function,
+   int ebx,
+   int ecx,
+   int edx
+   )
+
+   {
+   dpmi_regs callregs;
+   int       status;
+
+   callregs.EBX = ebx;
+   callregs.ECX = ecx;
+   callregs.EDX = edx;
+
+   callregs.SS  = 0;
+   callregs.SP  = 0;
+
+   callregs.DS  = 0;
+   callregs.ES  = 0;
+   callregs.FS  = 0;
+   callregs.GS  = 0;
+
+   callregs.IP = function;
+   callregs.CS = function >> 16;
+
+   status = DPMI_CallRealModeFunction( &callregs );
+   if ( status != DPMI_Ok )
+      {
+      return( PAS_Error );
+      }
+
+   return( callregs.EBX & 0xff );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: PAS_SetPCMVolume
+
+   Sets the volume of digitized sound playback.
+---------------------------------------------------------------------*/
+
+int PAS_SetPCMVolume
+   (
+   int volume
+   )
+
+   {
+   int status;
+
+   volume = max( 0, volume );
+   volume = min( volume, 255 );
+
+   volume *= 100;
+   volume /= 255;
+
+   status = PAS_CallMVFunction( PAS_Func->SetMixer, volume,
+      OUTPUTMIXER, L_PCM );
+   if ( status == PAS_Error )
+      {
+      return( status );
+      }
+
+   status = PAS_CallMVFunction( PAS_Func->SetMixer, volume,
+      OUTPUTMIXER, R_PCM );
+   if ( status == PAS_Error )
+      {
+      return( status );
+      }
+
+   return( PAS_Ok );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: PAS_GetPCMVolume
+
+   Returns the current volume of digitized sound playback.
+---------------------------------------------------------------------*/
+
+int PAS_GetPCMVolume
+   (
+   void
+   )
+
+   {
+   int leftvolume;
+   int rightvolume;
+   int totalvolume;
+
+   if ( PAS_Func == NULL )
+      {
+      return( PAS_Error );
+      }
+
+   leftvolume = PAS_CallMVFunction( PAS_Func->GetMixer, 0,
+      OUTPUTMIXER, L_PCM );
+   rightvolume = PAS_CallMVFunction( PAS_Func->GetMixer, 0,
+      OUTPUTMIXER, R_PCM );
+
+   if ( ( leftvolume == PAS_Error ) || ( rightvolume == PAS_Error ) )
+      {
+      return( PAS_Error );
+      }
+
+   leftvolume  &= 0xff;
+   rightvolume &= 0xff;
+
+   totalvolume = ( rightvolume + leftvolume ) / 2;
+   totalvolume *= 255;
+   totalvolume /= 100;
+   return( totalvolume );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: PAS_SetFMVolume
+
+   Sets the volume of FM sound playback.
+---------------------------------------------------------------------*/
+
+void PAS_SetFMVolume
+   (
+   int volume
+   )
+
+   {
+   volume = max( 0, volume );
+   volume = min( volume, 255 );
+
+   volume *= 100;
+   volume /= 255;
+   if ( PAS_Func )
+      {
+      PAS_CallMVFunction( PAS_Func->SetMixer, volume, OUTPUTMIXER, L_FM );
+      PAS_CallMVFunction( PAS_Func->SetMixer, volume, OUTPUTMIXER, R_FM );
+      }
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: PAS_GetFMVolume
+
+   Returns the current volume of FM sound playback.
+---------------------------------------------------------------------*/
+
+int PAS_GetFMVolume
+   (
+   void
+   )
+
+   {
+   int leftvolume;
+   int rightvolume;
+   int totalvolume;
+
+   if ( PAS_Func == NULL )
+      {
+      return( 255 );
+      }
+
+   leftvolume = PAS_CallMVFunction( PAS_Func->GetMixer, 0,
+      OUTPUTMIXER, L_FM ) & 0xff;
+   rightvolume = PAS_CallMVFunction( PAS_Func->GetMixer, 0,
+      OUTPUTMIXER, R_FM ) & 0xff;
+
+   totalvolume  = ( rightvolume + leftvolume ) / 2;
+   totalvolume *= 255;
+   totalvolume /= 100;
+   totalvolume  = min( 255, totalvolume );
+
+   return( totalvolume );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: PAS_GetCardInfo
+
+   Returns the maximum number of bits that can represent a sample
+   (8 or 16) and the number of channels (1 for mono, 2 for stereo).
+---------------------------------------------------------------------*/
+
+int PAS_GetCardInfo
+   (
+   int *MaxSampleBits,
+   int *MaxChannels
+   )
+
+   {
+   int status;
+
+   if ( PAS_State == NULL )
+      {
+      status = PAS_CheckForDriver();
+      if ( status != PAS_Ok )
+         {
+         return( status );
+         }
+
+      PAS_State = PAS_GetStateTable();
+      if ( PAS_State == NULL )
+         {
+         return( PAS_Error );
+         }
+      }
+
+   *MaxChannels = 2;
+
+   // Check board revision.  Revision # 0 can't play 16-bit data.
+   if ( ( PAS_State->intrctlr & 0xe0 ) == 0 )
+      {
+      *MaxSampleBits = 8;
+      }
+   else
+      {
+      *MaxSampleBits = 16;
+      }
+
+   return( PAS_Ok );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: PAS_SetCallBack
+
+   Specifies the user function to call at the end of a sound transfer.
+---------------------------------------------------------------------*/
+
+void PAS_SetCallBack
+   (
+   void ( *func )( void )
+   )
+
+   {
+   PAS_CallBack = func;
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: PAS_FindCard
+
+   Auto-detects the port the Pro AudioSpectrum is set for.
+---------------------------------------------------------------------*/
+
+int PAS_FindCard
+   (
+   void
+   )
+
+   {
+   int status;
+
+   status = PAS_TestAddress( DEFAULT_BASE );
+   if ( status == 0 )
+      {
+      PAS_TranslateCode = DEFAULT_BASE;
+      return( PAS_Ok );
+      }
+
+   status = PAS_TestAddress( ALT_BASE_1 );
+   if ( status == 0 )
+      {
+      PAS_TranslateCode = ALT_BASE_1;
+      return( PAS_Ok );
+      }
+
+   status = PAS_TestAddress( ALT_BASE_2 );
+   if ( status == 0 )
+      {
+      PAS_TranslateCode = ALT_BASE_2;
+      return( PAS_Ok );
+      }
+
+   status = PAS_TestAddress( ALT_BASE_3 );
+   if ( status == 0 )
+      {
+      PAS_TranslateCode = ALT_BASE_3;
+      return( PAS_Ok );
+      }
+
+   PAS_SetErrorCode( PAS_CardNotFound );
+   return( PAS_Error );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: PAS_SaveMusicVolume
+
+   Saves the user's FM mixer settings.
+---------------------------------------------------------------------*/
+
+int PAS_SaveMusicVolume
+   (
+   void
+   )
+
+   {
+   int status;
+   int data;
+
+   if ( !PAS_Installed )
+      {
+      status = PAS_CheckForDriver();
+      if ( status != PAS_Ok )
+         {
+         return( status );
+         }
+
+      PAS_State = PAS_GetStateTable();
+      if ( PAS_State == NULL )
+         {
+         return( PAS_Error );
+         }
+
+      PAS_Func = PAS_GetFunctionTable();
+      if ( PAS_Func == NULL )
+         {
+         return( PAS_Error );
+         }
+
+      status = PAS_GetCardSettings();
+      if ( status != PAS_Ok )
+         {
+         return( status );
+         }
+
+      status = PAS_FindCard();
+      if ( status != PAS_Ok )
+         {
+         return( status );
+         }
+
+      // Enable PAS Sound
+      data  = PAS_State->audiofilt;
+      data |= PAS_AudioMuteFlag;
+
+      PAS_Write( AudioFilterControl, data );
+      PAS_State->audiofilt = data;
+      }
+
+   status = PAS_CallMVFunction( PAS_Func->GetMixer, 0, OUTPUTMIXER, L_FM );
+   if ( status != PAS_Error )
+      {
+      PAS_OriginalFMLeftVolume  = PAS_CallMVFunction( PAS_Func->GetMixer,
+         0, OUTPUTMIXER, L_FM ) & 0xff;
+
+      PAS_OriginalFMRightVolume = PAS_CallMVFunction( PAS_Func->GetMixer,
+         0, OUTPUTMIXER, R_FM ) & 0xff;
+
+      return( PAS_Ok );
+      }
+
+   return( PAS_Warning );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: PAS_RestoreMusicVolume
+
+   Restores the user's FM mixer settings.
+---------------------------------------------------------------------*/
+
+void PAS_RestoreMusicVolume
+   (
+   void
+   )
+
+   {
+   if ( PAS_Func )
+      {
+      PAS_CallMVFunction( PAS_Func->SetMixer, PAS_OriginalFMLeftVolume,
+         OUTPUTMIXER, L_FM );
+      PAS_CallMVFunction( PAS_Func->SetMixer, PAS_OriginalFMRightVolume,
+         OUTPUTMIXER, R_FM );
+      }
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: PAS_SaveState
+
+   Saves the original state of the PAS prior to use.
+---------------------------------------------------------------------*/
+
+void PAS_SaveState
+   (
+   void
+   )
+
+   {
+   PAS_OriginalState.intrctlr     = PAS_State->intrctlr;
+   PAS_OriginalState.audiofilt    = PAS_State->audiofilt;
+   PAS_OriginalState.tmrctlr      = PAS_State->tmrctlr;
+   PAS_OriginalState.samplerate   = PAS_State->samplerate;
+   PAS_OriginalState.samplecnt    = PAS_State->samplecnt;
+   PAS_OriginalState.crosschannel = PAS_State->crosschannel;
+   PAS_SampleSizeConfig = PAS_Read( SampleSizeConfiguration );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: PAS_RestoreState
+
+   Restores the original state of the PAS after use.
+---------------------------------------------------------------------*/
+
+void PAS_RestoreState
+   (
+   void
+   )
+
+   {
+   int LoByte;
+   int HiByte;
+
+   // Select the Sample Rate Timer
+   PAS_Write( LocalTimerControl, SelectSampleRateTimer );
+   PAS_State->tmrctlr = SelectSampleRateTimer;
+
+   PAS_Write( SampleRateTimer, PAS_OriginalState.samplerate );
+   PAS_State->samplerate = PAS_OriginalState.samplerate;
+
+   // Select the Sample Buffer Count
+   PAS_Write( LocalTimerControl, SelectSampleBufferCount );
+   PAS_State->tmrctlr = SelectSampleBufferCount;
+
+   LoByte = lobyte( PAS_OriginalState.samplecnt );
+   HiByte = hibyte( PAS_OriginalState.samplecnt );
+   PAS_Write( SampleRateTimer, LoByte );
+   PAS_Write( SampleRateTimer, HiByte );
+   PAS_State->samplecnt = PAS_OriginalState.samplecnt;
+
+   PAS_Write( CrossChannelControl, PAS_OriginalState.crosschannel );
+   PAS_State->crosschannel = PAS_OriginalState.crosschannel;
+
+   PAS_Write( SampleSizeConfiguration, PAS_SampleSizeConfig );
+
+   PAS_Write( InterruptControl, PAS_OriginalState.intrctlr );
+   PAS_State->intrctlr = PAS_OriginalState.intrctlr;
+
+   PAS_Write( AudioFilterControl, PAS_OriginalState.audiofilt );
+   PAS_State->audiofilt = PAS_OriginalState.audiofilt;
+
+   PAS_Write( LocalTimerControl, PAS_OriginalState.tmrctlr );
+   PAS_State->tmrctlr = PAS_OriginalState.tmrctlr;
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: PAS_LockEnd
+
+   Used for determining the length of the functions to lock in memory.
+---------------------------------------------------------------------*/
+
+static void PAS_LockEnd
+   (
+   void
+   )
+
+   {
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: allocateTimerStack
+
+   Allocate a block of memory from conventional (low) memory and return
+   the selector (which can go directly into a segment register) of the
+   memory block or 0 if an error occured.
+---------------------------------------------------------------------*/
+
+static unsigned short allocateTimerStack
+   (
+   unsigned short size
+   )
+
+   {
+   union REGS regs;
+
+   // clear all registers
+   memset( &regs, 0, sizeof( regs ) );
+
+   // DPMI allocate conventional memory
+   regs.w.ax = 0x100;
+
+   // size in paragraphs
+   regs.w.bx = ( size + 15 ) / 16;
+
+   int386( 0x31, &regs, &regs );
+   if (!regs.w.cflag)
+      {
+      // DPMI call returns selector in dx
+      // (ax contains real mode segment
+      // which is ignored here)
+
+      return( regs.w.dx );
+      }
+
+   // Couldn't allocate memory.
+   return( NULL );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: deallocateTimerStack
+
+   Deallocate a block of conventional (low) memory given a selector to
+   it.  Assumes the block was allocated with DPMI function 0x100.
+---------------------------------------------------------------------*/
+
+static void deallocateTimerStack
+   (
+   unsigned short selector
+   )
+
+   {
+   union REGS regs;
+
+   if ( selector != NULL )
+      {
+      // clear all registers
+      memset( &regs, 0, sizeof( regs ) );
+
+      regs.w.ax = 0x101;
+      regs.w.dx = selector;
+      int386( 0x31, &regs, &regs );
+      }
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: PAS_Init
+
+   Initializes the sound card and prepares the module to play
+   digitized sounds.
+---------------------------------------------------------------------*/
+
+int PAS_Init
+   (
+   void
+   )
+
+   {
+   int Interrupt;
+   int status;
+   int data;
+
+   if ( PAS_Installed )
+      {
+      return( PAS_Ok );
+      }
+
+   PAS_IntController1Mask = inp( 0x21 );
+   PAS_IntController2Mask = inp( 0xA1 );
+
+   status = PAS_CheckForDriver();
+   if ( status != PAS_Ok )
+      {
+      return( status );
+      }
+
+   PAS_State = PAS_GetStateTable();
+   if ( PAS_State == NULL )
+      {
+      return( PAS_Error );
+      }
+
+   PAS_Func = PAS_GetFunctionTable();
+   if ( PAS_Func == NULL )
+      {
+      return( PAS_Error );
+      }
+
+   status = PAS_GetCardSettings();
+   if ( status != PAS_Ok )
+      {
+      return( status );
+      }
+
+   status = PAS_FindCard();
+   if ( status != PAS_Ok )
+      {
+      return( status );
+      }
+
+   PAS_SaveState();
+
+   PAS_OriginalPCMLeftVolume  = PAS_CallMVFunction( PAS_Func->GetMixer, 0,
+      OUTPUTMIXER, L_PCM ) & 0xff;
+   PAS_OriginalPCMRightVolume = PAS_CallMVFunction( PAS_Func->GetMixer, 0,
+      OUTPUTMIXER, R_PCM ) & 0xff;
+
+   PAS_SoundPlaying = FALSE;
+
+   PAS_SetCallBack( NULL );
+
+   PAS_DMABuffer = NULL;
+
+   status = PAS_LockMemory();
+   if ( status != PAS_Ok )
+      {
+      PAS_UnlockMemory();
+      return( status );
+      }
+
+   StackSelector = allocateTimerStack( kStackSize );
+   if ( StackSelector == NULL )
+      {
+      PAS_UnlockMemory();
+      PAS_SetErrorCode( PAS_OutOfMemory );
+      return( PAS_Error );
+      }
+
+   // Leave a little room at top of stack just for the hell of it...
+   StackPointer = kStackSize - sizeof( long );
+
+   // Install our interrupt handler
+   Interrupt = PAS_Interrupts[ PAS_Irq ];
+   PAS_OldInt = _dos_getvect( Interrupt );
+   if ( PAS_Irq < 8 )
+      {
+      _dos_setvect( Interrupt, PAS_ServiceInterrupt );
+      }
+   else
+      {
+      status = IRQ_SetVector( Interrupt, PAS_ServiceInterrupt );
+      if ( status != IRQ_Ok )
+         {
+         PAS_UnlockMemory();
+         deallocateTimerStack( StackSelector );
+         StackSelector = NULL;
+         PAS_SetErrorCode( PAS_UnableToSetIrq );
+         return( PAS_Error );
+         }
+      }
+
+   // Enable PAS Sound
+   data  = PAS_State->audiofilt;
+   data |= PAS_AudioMuteFlag;
+
+   PAS_Write( AudioFilterControl, data );
+   PAS_State->audiofilt = data;
+
+   PAS_SetPlaybackRate( PAS_DefaultSampleRate );
+   PAS_SetMixMode( PAS_DefaultMixMode );
+
+   PAS_Installed = TRUE;
+
+   PAS_SetErrorCode( PAS_Ok );
+   return( PAS_Ok );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: PAS_Shutdown
+
+   Ends transfer of sound data to the sound card and restores the
+   system resources used by the card.
+---------------------------------------------------------------------*/
+
+void PAS_Shutdown
+   (
+   void
+   )
+
+   {
+   int Interrupt;
+
+   if ( PAS_Installed )
+      {
+      // Halt the DMA transfer
+      PAS_StopPlayback();
+
+      // Restore the original interrupt
+      Interrupt = PAS_Interrupts[ PAS_Irq ];
+      if ( PAS_Irq >= 8 )
+         {
+         IRQ_RestoreVector( Interrupt );
+         }
+      _dos_setvect( Interrupt, PAS_OldInt );
+
+      PAS_SoundPlaying = FALSE;
+
+      PAS_DMABuffer = NULL;
+
+      PAS_SetCallBack( NULL );
+
+      PAS_CallMVFunction( PAS_Func->SetMixer, PAS_OriginalPCMLeftVolume,
+         OUTPUTMIXER, L_PCM );
+      PAS_CallMVFunction( PAS_Func->SetMixer, PAS_OriginalPCMRightVolume,
+         OUTPUTMIXER, R_PCM );
+
+// DEBUG
+//      PAS_RestoreState();
+
+      PAS_UnlockMemory();
+
+      deallocateTimerStack( StackSelector );
+      StackSelector = NULL;
+
+      PAS_Installed = FALSE;
+      }
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: PAS_UnlockMemory
+
+   Unlocks all neccessary data.
+---------------------------------------------------------------------*/
+
+void PAS_UnlockMemory
+   (
+   void
+   )
+
+   {
+   DPMI_UnlockMemoryRegion( PAS_LockStart, PAS_LockEnd );
+   DPMI_Unlock( PAS_Interrupts );
+   DPMI_Unlock( PAS_OldInt );
+   DPMI_Unlock( PAS_IntController1Mask );
+   DPMI_Unlock( PAS_IntController2Mask  );
+   DPMI_Unlock( PAS_Installed );
+   DPMI_Unlock( PAS_TranslateCode );
+   DPMI_Unlock( PAS_OriginalPCMLeftVolume );
+   DPMI_Unlock( PAS_OriginalPCMRightVolume );
+   DPMI_Unlock( PAS_OriginalFMLeftVolume );
+   DPMI_Unlock( PAS_OriginalFMRightVolume );
+   DPMI_Unlock( PAS_DMAChannel );
+   DPMI_Unlock( PAS_Irq );
+   DPMI_Unlock( PAS_State );
+   DPMI_Unlock( PAS_Func );
+   DPMI_Unlock( PAS_OriginalState );
+   DPMI_Unlock( PAS_SampleSizeConfig );
+   DPMI_Unlock( PAS_DMABuffer );
+   DPMI_Unlock( PAS_DMABufferEnd );
+   DPMI_Unlock( PAS_CurrentDMABuffer );
+   DPMI_Unlock( PAS_TotalDMABufferSize );
+   DPMI_Unlock( PAS_TransferLength );
+   DPMI_Unlock( PAS_MixMode );
+   DPMI_Unlock( PAS_SampleRate );
+   DPMI_Unlock( PAS_TimeInterval );
+   DPMI_Unlock( PAS_SoundPlaying );
+   DPMI_Unlock( PAS_CallBack );
+   DPMI_Unlock( PAS_ErrorCode );
+   DPMI_Unlock( irqstatus );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: PAS_LockMemory
+
+   Locks all neccessary data.
+---------------------------------------------------------------------*/
+
+int PAS_LockMemory
+   (
+   void
+   )
+
+   {
+   int status;
+
+   status  = DPMI_LockMemoryRegion( PAS_LockStart, PAS_LockEnd );
+   status |= DPMI_Lock( PAS_Interrupts );
+   status |= DPMI_Lock( PAS_OldInt );
+   status |= DPMI_Lock( PAS_IntController1Mask );
+   status |= DPMI_Lock( PAS_IntController2Mask  );
+   status |= DPMI_Lock( PAS_Installed );
+   status |= DPMI_Lock( PAS_TranslateCode );
+   status |= DPMI_Lock( PAS_OriginalPCMLeftVolume );
+   status |= DPMI_Lock( PAS_OriginalPCMRightVolume );
+   status |= DPMI_Lock( PAS_OriginalFMLeftVolume );
+   status |= DPMI_Lock( PAS_OriginalFMRightVolume );
+   status |= DPMI_Lock( PAS_DMAChannel );
+   status |= DPMI_Lock( PAS_Irq );
+   status |= DPMI_Lock( PAS_State );
+   status |= DPMI_Lock( PAS_Func );
+   status |= DPMI_Lock( PAS_OriginalState );
+   status |= DPMI_Lock( PAS_SampleSizeConfig );
+   status |= DPMI_Lock( PAS_DMABuffer );
+   status |= DPMI_Lock( PAS_DMABufferEnd );
+   status |= DPMI_Lock( PAS_CurrentDMABuffer );
+   status |= DPMI_Lock( PAS_TotalDMABufferSize );
+   status |= DPMI_Lock( PAS_TransferLength );
+   status |= DPMI_Lock( PAS_MixMode );
+   status |= DPMI_Lock( PAS_SampleRate );
+   status |= DPMI_Lock( PAS_TimeInterval );
+   status |= DPMI_Lock( PAS_SoundPlaying );
+   status |= DPMI_Lock( PAS_CallBack );
+   status |= DPMI_Lock( PAS_ErrorCode );
+   status |= DPMI_Lock( irqstatus );
+
+   if ( status != DPMI_Ok )
+      {
+      PAS_UnlockMemory();
+      PAS_SetErrorCode( PAS_DPMI_Error );
+      return( PAS_Error );
+      }
+
+   return( PAS_Ok );
+   }
--- /dev/null
+++ b/rott/audiolib/pas16.h
@@ -1,0 +1,81 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+/**********************************************************************
+   module: PAS16.H
+
+   author: James R. Dose
+   date:   March 27, 1994
+
+   Public header for for PAS16.C
+
+   (c) Copyright 1994 James R. Dose.  All Rights Reserved.
+**********************************************************************/
+
+#ifndef __PAS16_H
+#define __PAS16_H
+
+enum PAS_ERRORS
+   {
+   PAS_Warning = -2,
+   PAS_Error   = -1,
+   PAS_Ok      = 0,
+   PAS_DriverNotFound,
+   PAS_DmaError,
+   PAS_InvalidIrq,
+   PAS_UnableToSetIrq,
+   PAS_Dos4gwIrqError,
+   PAS_NoSoundPlaying,
+   PAS_CardNotFound,
+   PAS_DPMI_Error,
+   PAS_OutOfMemory
+   };
+
+#define PAS_MaxMixMode        STEREO_16BIT
+#define PAS_DefaultSampleRate 11000
+#define PAS_DefaultMixMode    MONO_8BIT
+#define PAS_MaxIrq            15
+
+#define PAS_MinSamplingRate   4000
+#define PAS_MaxSamplingRate   44000
+
+extern unsigned int PAS_DMAChannel;
+
+char *PAS_ErrorString( int ErrorNumber );
+void  PAS_SetPlaybackRate( unsigned rate );
+unsigned PAS_GetPlaybackRate( void );
+int   PAS_SetMixMode( int mode );
+void  PAS_StopPlayback( void );
+int   PAS_GetCurrentPos( void );
+int   PAS_BeginBufferedPlayback( char *BufferStart, int BufferSize, int NumDivisions, unsigned SampleRate, int MixMode, void ( *CallBackFunc )( void ) );
+int   PAS_BeginBufferedRecord( char *BufferStart, int BufferSize, int NumDivisions, unsigned SampleRate, int MixMode, void ( *CallBackFunc )( void ) );
+int   PAS_SetPCMVolume( int volume );
+int   PAS_GetPCMVolume( void );
+void  PAS_SetFMVolume( int volume );
+int   PAS_GetFMVolume( void );
+int   PAS_GetCardInfo( int *MaxSampleBits, int *MaxChannels );
+void  PAS_SetCallBack( void ( *func )( void ) );
+int   PAS_SaveMusicVolume( void );
+void  PAS_RestoreMusicVolume( void );
+int   PAS_Init( void );
+void  PAS_Shutdown( void );
+void  PAS_UnlockMemory( void );
+int   PAS_LockMemory( void );
+
+#endif
--- /dev/null
+++ b/rott/audiolib/pitch.c
@@ -1,0 +1,258 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+/**********************************************************************
+   module: PITCH.C
+
+   author: James R. Dose
+   date:   June 14, 1993
+
+   Routines for pitch scaling.
+
+   (c) Copyright 1993 James R. Dose.  All Rights Reserved.
+**********************************************************************/
+
+#include <stdlib.h>
+//#include <math.h>
+#include "dpmi.h"
+#include "standard.h"
+#include "pitch.h"
+
+#define MAXDETUNE 25
+
+static unsigned long PitchTable[ 12 ][ MAXDETUNE ] =
+   {
+      { 0x10000, 0x10097, 0x1012f, 0x101c7, 0x10260, 0x102f9, 0x10392, 0x1042c,
+      0x104c6, 0x10561, 0x105fb, 0x10696, 0x10732, 0x107ce, 0x1086a, 0x10907,
+      0x109a4, 0x10a41, 0x10adf, 0x10b7d, 0x10c1b, 0x10cba, 0x10d59, 0x10df8,
+      0x10e98 },
+      { 0x10f38, 0x10fd9, 0x1107a, 0x1111b, 0x111bd, 0x1125f, 0x11302, 0x113a5,
+      0x11448, 0x114eb, 0x1158f, 0x11634, 0x116d8, 0x1177e, 0x11823, 0x118c9,
+      0x1196f, 0x11a16, 0x11abd, 0x11b64, 0x11c0c, 0x11cb4, 0x11d5d, 0x11e06,
+      0x11eaf },
+      { 0x11f59, 0x12003, 0x120ae, 0x12159, 0x12204, 0x122b0, 0x1235c, 0x12409,
+      0x124b6, 0x12563, 0x12611, 0x126bf, 0x1276d, 0x1281c, 0x128cc, 0x1297b,
+      0x12a2b, 0x12adc, 0x12b8d, 0x12c3e, 0x12cf0, 0x12da2, 0x12e55, 0x12f08,
+      0x12fbc },
+      { 0x1306f, 0x13124, 0x131d8, 0x1328d, 0x13343, 0x133f9, 0x134af, 0x13566,
+      0x1361d, 0x136d5, 0x1378d, 0x13846, 0x138fe, 0x139b8, 0x13a72, 0x13b2c,
+      0x13be6, 0x13ca1, 0x13d5d, 0x13e19, 0x13ed5, 0x13f92, 0x1404f, 0x1410d,
+      0x141cb },
+      { 0x1428a, 0x14349, 0x14408, 0x144c8, 0x14588, 0x14649, 0x1470a, 0x147cc,
+      0x1488e, 0x14951, 0x14a14, 0x14ad7, 0x14b9b, 0x14c5f, 0x14d24, 0x14dea,
+      0x14eaf, 0x14f75, 0x1503c, 0x15103, 0x151cb, 0x15293, 0x1535b, 0x15424,
+      0x154ee },
+      { 0x155b8, 0x15682, 0x1574d, 0x15818, 0x158e4, 0x159b0, 0x15a7d, 0x15b4a,
+      0x15c18, 0x15ce6, 0x15db4, 0x15e83, 0x15f53, 0x16023, 0x160f4, 0x161c5,
+      0x16296, 0x16368, 0x1643a, 0x1650d, 0x165e1, 0x166b5, 0x16789, 0x1685e,
+      0x16934 },
+      { 0x16a09, 0x16ae0, 0x16bb7, 0x16c8e, 0x16d66, 0x16e3e, 0x16f17, 0x16ff1,
+      0x170ca, 0x171a5, 0x17280, 0x1735b, 0x17437, 0x17513, 0x175f0, 0x176ce,
+      0x177ac, 0x1788a, 0x17969, 0x17a49, 0x17b29, 0x17c09, 0x17cea, 0x17dcc,
+      0x17eae },
+      { 0x17f91, 0x18074, 0x18157, 0x1823c, 0x18320, 0x18406, 0x184eb, 0x185d2,
+      0x186b8, 0x187a0, 0x18888, 0x18970, 0x18a59, 0x18b43, 0x18c2d, 0x18d17,
+      0x18e02, 0x18eee, 0x18fda, 0x190c7, 0x191b5, 0x192a2, 0x19391, 0x19480,
+      0x1956f },
+      { 0x1965f, 0x19750, 0x19841, 0x19933, 0x19a25, 0x19b18, 0x19c0c, 0x19d00,
+      0x19df4, 0x19ee9, 0x19fdf, 0x1a0d5, 0x1a1cc, 0x1a2c4, 0x1a3bc, 0x1a4b4,
+      0x1a5ad, 0x1a6a7, 0x1a7a1, 0x1a89c, 0x1a998, 0x1aa94, 0x1ab90, 0x1ac8d,
+      0x1ad8b },
+      { 0x1ae89, 0x1af88, 0x1b088, 0x1b188, 0x1b289, 0x1b38a, 0x1b48c, 0x1b58f,
+      0x1b692, 0x1b795, 0x1b89a, 0x1b99f, 0x1baa4, 0x1bbaa, 0x1bcb1, 0x1bdb8,
+      0x1bec0, 0x1bfc9, 0x1c0d2, 0x1c1dc, 0x1c2e6, 0x1c3f1, 0x1c4fd, 0x1c609,
+      0x1c716 },
+      { 0x1c823, 0x1c931, 0x1ca40, 0x1cb50, 0x1cc60, 0x1cd70, 0x1ce81, 0x1cf93,
+      0x1d0a6, 0x1d1b9, 0x1d2cd, 0x1d3e1, 0x1d4f6, 0x1d60c, 0x1d722, 0x1d839,
+      0x1d951, 0x1da69, 0x1db82, 0x1dc9c, 0x1ddb6, 0x1ded1, 0x1dfec, 0x1e109,
+      0x1e225 },
+      { 0x1e343, 0x1e461, 0x1e580, 0x1e6a0, 0x1e7c0, 0x1e8e0, 0x1ea02, 0x1eb24,
+      0x1ec47, 0x1ed6b, 0x1ee8f, 0x1efb4, 0x1f0d9, 0x1f1ff, 0x1f326, 0x1f44e,
+      0x1f576, 0x1f69f, 0x1f7c9, 0x1f8f3, 0x1fa1e, 0x1fb4a, 0x1fc76, 0x1fda3,
+      0x1fed1 }
+   };
+
+
+//static int PITCH_Installed = FALSE;
+
+
+/*---------------------------------------------------------------------
+   Function: PITCH_Init
+
+   Initializes pitch table.
+---------------------------------------------------------------------*/
+/*
+void PITCH_Init
+   (
+   void
+   )
+
+   {
+   int note;
+   int detune;
+
+   if ( !PITCH_Installed )
+      {
+      for( note = 0; note < 12; note++ )
+         {
+         for( detune = 0; detune < MAXDETUNE; detune++ )
+            {
+            PitchTable[ note ][ detune ] = 0x10000 *
+               pow( 2, ( note * MAXDETUNE + detune ) / ( 12.0 * MAXDETUNE ) );
+            }
+         }
+
+      PITCH_Installed = TRUE;
+      }
+   }
+*/
+
+/**********************************************************************
+
+   Memory locked functions:
+
+**********************************************************************/
+
+
+#define PITCH_LockStart PITCH_GetScale
+
+
+/*---------------------------------------------------------------------
+   Function: PITCH_GetScale
+
+   Returns a fixed-point value to scale number the specified amount.
+---------------------------------------------------------------------*/
+
+unsigned long PITCH_GetScale
+   (
+   int pitchoffset
+   )
+
+   {
+   unsigned long scale;
+   int octaveshift;
+   int noteshift;
+   int note;
+   int detune;
+
+//   if ( !PITCH_Installed )
+//      {
+//      PITCH_Init();
+//      }
+
+   if ( pitchoffset == 0 )
+      {
+      return( PitchTable[ 0 ][ 0 ] );
+      }
+
+   noteshift = pitchoffset % 1200;
+   if ( noteshift < 0 )
+      {
+      noteshift += 1200;
+      }
+
+   note   = noteshift / 100;
+   detune = ( noteshift % 100 ) / ( 100 / MAXDETUNE );
+   octaveshift = ( pitchoffset - noteshift ) / 1200;
+
+   if ( detune < 0 )
+      {
+      detune += ( 100 / MAXDETUNE );
+      note--;
+      if ( note < 0 )
+         {
+         note += 12;
+         octaveshift--;
+         }
+      }
+
+   scale = PitchTable[ note ][ detune ];
+
+   if ( octaveshift < 0 )
+      {
+      scale >>= -octaveshift;
+      }
+   else
+      {
+      scale <<= octaveshift;
+      }
+
+   return( scale );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: PITCH_LockEnd
+
+   Used for determining the length of the functions to lock in memory.
+---------------------------------------------------------------------*/
+
+static void PITCH_LockEnd
+   (
+   void
+   )
+
+   {
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: PITCH_UnlockMemory
+
+   Unlocks all neccessary data.
+---------------------------------------------------------------------*/
+
+void PITCH_UnlockMemory
+   (
+   void
+   )
+
+   {
+   DPMI_UnlockMemoryRegion( PITCH_LockStart, PITCH_LockEnd );
+   DPMI_Unlock( PitchTable );
+//   DPMI_Unlock( PITCH_Installed );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: PITCH_LockMemory
+
+   Unlocks all neccessary data.
+---------------------------------------------------------------------*/
+
+int PITCH_LockMemory
+   (
+   void
+   )
+
+   {
+   int status;
+
+   status  = DPMI_LockMemoryRegion( PITCH_LockStart, PITCH_LockEnd );
+   status |= DPMI_Lock( PitchTable );
+//   status |= DPMI_Lock( PITCH_Installed );
+
+   if ( status != DPMI_Ok )
+      {
+      PITCH_UnlockMemory();
+      return( PITCH_Error );
+      }
+
+   return( PITCH_Ok );
+   }
--- /dev/null
+++ b/rott/audiolib/pitch.h
@@ -1,0 +1,45 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+/**********************************************************************
+   module: PITCH.H
+
+   author: James R. Dose
+   date:   June 14, 1994
+
+   Public header for PITCH.C
+
+   (c) Copyright 1994 James R. Dose.  All Rights Reserved.
+**********************************************************************/
+
+#ifndef __PITCH_H
+#define __PITCH_H
+
+enum PITCH_ERRORS
+   {
+   PITCH_Warning = -2,
+   PITCH_Error = -1,
+   PITCH_Ok = 0,
+   };
+
+//void          PITCH_Init( void );
+unsigned long PITCH_GetScale( int pitchoffset );
+void          PITCH_UnlockMemory( void );
+int           PITCH_LockMemory( void );
+#endif
--- /dev/null
+++ b/rott/audiolib/platform.h
@@ -1,0 +1,77 @@
+#ifndef _INCLUDE_PLATFORM_H_
+#define _INCLUDE_PLATFORM_H_
+
+/* this file originally from buildengine */
+#ifdef BUILDENGINE
+
+#if (defined PLATFORM_WIN32)
+#include "win32_compat.h"
+#elif (defined PLATFORM_UNIX)
+#include "unix_compat.h"
+#elif (defined PLATFORM_DOS)
+#include "doscmpat.h"
+#else
+#error Define your platform!
+#endif
+
+#if (!defined __EXPORT__)
+#define __EXPORT__
+#endif
+
+#if ((defined PLATFORM_SUPPORTS_SDL) && (!defined PLATFORM_TIMER_HZ))
+#define PLATFORM_TIMER_HZ 100
+#endif
+
+#if (!defined PLATFORM_TIMER_HZ)
+#error You need to define PLATFORM_TIMER_HZ for your platform.
+#endif
+
+#if (defined __WATCOMC__)
+#define snprintf _snprintf
+#endif
+
+#endif
+
+static __inline unsigned short _swap16(unsigned short D)
+{
+#if PLATFORM_MACOSX
+    register unsigned short returnValue;
+    __asm__ volatile("lhbrx %0,0,%1"
+        : "=r" (returnValue)
+        : "r" (&D)
+    );
+    return returnValue;
+#else
+    return((D<<8)|(D>>8));
+#endif
+}
+
+static __inline unsigned int _swap32(unsigned int D)
+{
+#if PLATFORM_MACOSX
+    register unsigned int returnValue;
+    __asm__ volatile("lwbrx %0,0,%1"
+        : "=r" (returnValue)
+        : "r" (&D)
+    );
+    return returnValue;
+#else
+    return((D<<24)|((D<<8)&0x00FF0000)|((D>>8)&0x0000FF00)|(D>>24));
+#endif
+}
+
+#if PLATFORM_MACOSX
+#define PLATFORM_BIGENDIAN 1
+#define BUILDSWAP_INTEL16(x) _swap16(x)
+#define BUILDSWAP_INTEL32(x) _swap32(x)
+#else
+#define PLATFORM_LITTLEENDIAN 1
+#define BUILDSWAP_INTEL16(x) (x)
+#define BUILDSWAP_INTEL32(x) (x)
+#endif
+
+#endif  /* !defined _INCLUDE_PLATFORM_H_ */
+
+/* end of platform.h ... */
+
+
--- /dev/null
+++ b/rott/audiolib/sndcards.h
@@ -1,0 +1,55 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+/**********************************************************************
+   module: SNDCARDS.H
+
+   author: James R. Dose
+   date:   March 31, 1994
+
+   Contains enumerated type definitions for sound cards.
+
+   (c) Copyright 1994 James R. Dose.  All Rights Reserved.
+**********************************************************************/
+
+#ifndef __SNDCARDS_H
+#define __SNDCARDS_H
+
+#define ASS_VERSION_STRING "1.12"
+
+typedef enum
+   {
+//   ASS_NoSound,
+   SoundBlaster,
+   ProAudioSpectrum,
+   SoundMan16,
+   Adlib,
+   GenMidi,
+   SoundCanvas,
+   Awe32,
+   WaveBlaster,
+   SoundScape,
+   UltraSound,
+   SoundSource,
+   TandySoundSource,
+   PC,
+   NumSoundCards
+   } soundcardnames;
+
+#endif
--- /dev/null
+++ b/rott/audiolib/sndscape.c
@@ -1,0 +1,1661 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+/**********************************************************************
+   module: SNDSCAPE.C
+
+   author: James R. Dose
+   date:   October 25, 1994
+
+   Low level routines to support the Ensoniq Soundscape.
+
+   (c) Copyright 1994 James R. Dose.  All Rights Reserved.
+**********************************************************************/
+
+#include <dos.h>
+#include <conio.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <time.h>
+#include "interrup.h"
+#include "dpmi.h"
+#include "dma.h"
+#include "irq.h"
+#include "sndscape.h"
+#include "_sndscap.h"
+
+const int SOUNDSCAPE_Interrupts[ SOUNDSCAPE_MaxIrq + 1 ]  =
+   {
+   INVALID, INVALID,     0xa, INVALID,
+   INVALID,     0xd, INVALID,     0xf,
+   INVALID, INVALID,    0x72, INVALID,
+   INVALID, INVALID, INVALID, INVALID
+   };
+
+const int SOUNDSCAPE_SampleSize[ SOUNDSCAPE_MaxMixMode + 1 ] =
+   {
+   MONO_8BIT_SAMPLE_SIZE,  STEREO_8BIT_SAMPLE_SIZE,
+   MONO_16BIT_SAMPLE_SIZE, STEREO_16BIT_SAMPLE_SIZE
+   };
+
+static void ( __interrupt __far *SOUNDSCAPE_OldInt )( void );
+
+static int SOUNDSCAPE_Installed = FALSE;
+static int SOUNDSCAPE_FoundCard = FALSE;
+
+static char   *SOUNDSCAPE_DMABuffer;
+static char   *SOUNDSCAPE_DMABufferEnd;
+static char   *SOUNDSCAPE_CurrentDMABuffer;
+static int     SOUNDSCAPE_TotalDMABufferSize;
+
+static int      SOUNDSCAPE_TransferLength   = 0;
+static int      SOUNDSCAPE_MixMode          = SOUNDSCAPE_DefaultMixMode;
+static int      SOUNDSCAPE_SamplePacketSize = MONO_16BIT_SAMPLE_SIZE;
+static unsigned SOUNDSCAPE_SampleRate       = SOUNDSCAPE_DefaultSampleRate;
+
+volatile int   SOUNDSCAPE_SoundPlaying;
+
+void ( *SOUNDSCAPE_CallBack )( void );
+
+static int  SOUNDSCAPE_IntController1Mask;
+static int  SOUNDSCAPE_IntController2Mask;
+
+// some globals for chip type, ports, DMA, IRQs ... and stuff
+static struct
+   {
+   int BasePort;  // base address of the Ensoniq gate-array chip
+   int WavePort;  // the AD-1848 base address
+   int DMAChan;   // the DMA channel used for PCM
+   int WaveIRQ;   // the PCM IRQ
+   int MIDIIRQ;   // the MPU-401 IRQ
+   int ChipID;    // the Ensoniq chip type
+   int SBEmul;    // SoundBlaster emulation flag
+   int CDROM;     // CD-ROM flag
+   int IRQIndx;   // the Wave IRQ index - for hardware regs
+   int OldIRQs;   // Old IRQs flag to support older HW
+   } SOUNDSCAPE_Config;
+
+// adequate stack size
+#define kStackSize 2048
+
+static unsigned short StackSelector = NULL;
+static unsigned long  StackPointer;
+
+static unsigned short oldStackSelector;
+static unsigned long  oldStackPointer;
+
+// These declarations are necessary to use the inline assembly pragmas.
+
+extern void GetStack(unsigned short *selptr,unsigned long *stackptr);
+extern void SetStack(unsigned short selector,unsigned long stackptr);
+
+// This function will get the current stack selector and pointer and save
+// them off.
+#pragma aux GetStack =	\
+	"mov  [edi],esp"		\
+	"mov	ax,ss"	 		\
+	"mov  [esi],ax" 		\
+	parm [esi] [edi]		\
+	modify [eax esi edi];
+
+// This function will set the stack selector and pointer to the specified
+// values.
+#pragma aux SetStack =	\
+	"mov  ss,ax"			\
+	"mov  esp,edx"			\
+	parm [ax] [edx]		\
+	modify [eax edx];
+
+int SOUNDSCAPE_DMAChannel = -1;
+
+int SOUNDSCAPE_ErrorCode = SOUNDSCAPE_Ok;
+
+#define SOUNDSCAPE_SetErrorCode( status ) \
+   SOUNDSCAPE_ErrorCode   = ( status );
+
+
+/*---------------------------------------------------------------------
+   Function: SOUNDSCAPE_ErrorString
+
+   Returns a pointer to the error message associated with an error
+   number.  A -1 returns a pointer the current error.
+---------------------------------------------------------------------*/
+
+char *SOUNDSCAPE_ErrorString
+   (
+   int ErrorNumber
+   )
+
+   {
+   char *ErrorString;
+
+   switch( ErrorNumber )
+      {
+      case SOUNDSCAPE_Warning :
+      case SOUNDSCAPE_Error :
+         ErrorString = SOUNDSCAPE_ErrorString( SOUNDSCAPE_ErrorCode );
+         break;
+
+      case SOUNDSCAPE_Ok :
+         ErrorString = "SoundScape ok.";
+         break;
+
+      case SOUNDSCAPE_EnvNotFound :
+         ErrorString = "SNDSCAPE environment variable not set.  This is used to locate \n"
+                       "SNDSCAPE.INI which is used to describe your sound card setup.";
+         break;
+
+      case SOUNDSCAPE_InitFileNotFound :
+         ErrorString = "Missing SNDSCAPE.INI file for SoundScape.  This file should be \n"
+                       "located in the directory indicated by the SNDSCAPE environment \n"
+                       "variable or in 'C:\SNDSCAPE' if SNDSCAPE is not set.";
+         break;
+
+      case SOUNDSCAPE_MissingProductInfo :
+         ErrorString = "Missing 'Product' field in SNDSCAPE.INI file for SoundScape.";
+         break;
+
+      case SOUNDSCAPE_MissingPortInfo :
+         ErrorString = "Missing 'Port' field in SNDSCAPE.INI file for SoundScape.";
+         break;
+
+      case SOUNDSCAPE_MissingDMAInfo :
+         ErrorString = "Missing 'DMA' field in SNDSCAPE.INI file for SoundScape.";
+         break;
+
+      case SOUNDSCAPE_MissingIRQInfo :
+         ErrorString = "Missing 'IRQ' field in SNDSCAPE.INI file for SoundScape.";
+         break;
+
+      case SOUNDSCAPE_MissingSBIRQInfo :
+         ErrorString = "Missing 'SBIRQ' field in SNDSCAPE.INI file for SoundScape.";
+         break;
+
+      case SOUNDSCAPE_MissingSBENABLEInfo :
+         ErrorString = "Missing 'SBEnable' field in SNDSCAPE.INI file for SoundScape.";
+         break;
+
+      case SOUNDSCAPE_MissingWavePortInfo :
+         ErrorString = "Missing 'WavePort' field in SNDSCAPE.INI file for SoundScape.";
+         break;
+
+      case SOUNDSCAPE_HardwareError :
+         ErrorString = "Could not detect SoundScape.  Make sure your SNDSCAPE.INI file \n"
+                       "contains correct information about your hardware setup.";
+         break;
+
+      case SOUNDSCAPE_NoSoundPlaying :
+         ErrorString = "No sound playing on SoundScape.";
+         break;
+
+      case SOUNDSCAPE_InvalidSBIrq :
+         ErrorString = "Invalid SoundScape Irq in SBIRQ field of SNDSCAPE.INI.";
+         break;
+
+      case SOUNDSCAPE_UnableToSetIrq :
+         ErrorString = "Unable to set SoundScape IRQ.  Try selecting an IRQ of 7 or below.";
+         break;
+
+      case SOUNDSCAPE_DmaError :
+         ErrorString = DMA_ErrorString( DMA_Error );
+         break;
+
+      case SOUNDSCAPE_DPMI_Error :
+         ErrorString = "DPMI Error in SoundScape.";
+         break;
+
+      case SOUNDSCAPE_OutOfMemory :
+         ErrorString = "Out of conventional memory in SoundScape.";
+         break;
+
+      default :
+         ErrorString = "Unknown SoundScape error code.";
+         break;
+      }
+
+   return( ErrorString );
+   }
+
+
+/**********************************************************************
+
+   Memory locked functions:
+
+**********************************************************************/
+
+
+#define SOUNDSCAPE_LockStart SOUNDSCAPE_EnableInterrupt
+
+
+/*---------------------------------------------------------------------
+   Function: SOUNDSCAPE_EnableInterrupt
+
+   Enables the triggering of the sound card interrupt.
+---------------------------------------------------------------------*/
+
+static void SOUNDSCAPE_EnableInterrupt
+   (
+   void
+   )
+
+   {
+   int mask;
+
+   // Unmask system interrupt
+   if ( SOUNDSCAPE_Config.WaveIRQ < 8 )
+      {
+      mask = inp( 0x21 ) & ~( 1 << SOUNDSCAPE_Config.WaveIRQ );
+      outp( 0x21, mask  );
+      }
+   else
+      {
+      mask = inp( 0xA1 ) & ~( 1 << ( SOUNDSCAPE_Config.WaveIRQ - 8 ) );
+      outp( 0xA1, mask  );
+
+      mask = inp( 0x21 ) & ~( 1 << 2 );
+      outp( 0x21, mask  );
+      }
+
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: SOUNDSCAPE_DisableInterrupt
+
+   Disables the triggering of the sound card interrupt.
+---------------------------------------------------------------------*/
+
+static void SOUNDSCAPE_DisableInterrupt
+   (
+   void
+   )
+
+   {
+   int mask;
+
+   // Restore interrupt mask
+   if ( SOUNDSCAPE_Config.WaveIRQ < 8 )
+      {
+      mask  = inp( 0x21 ) & ~( 1 << SOUNDSCAPE_Config.WaveIRQ );
+      mask |= SOUNDSCAPE_IntController1Mask & ( 1 << SOUNDSCAPE_Config.WaveIRQ );
+      outp( 0x21, mask  );
+      }
+   else
+      {
+      mask  = inp( 0x21 ) & ~( 1 << 2 );
+      mask |= SOUNDSCAPE_IntController1Mask & ( 1 << 2 );
+      outp( 0x21, mask  );
+
+      mask  = inp( 0xA1 ) & ~( 1 << ( SOUNDSCAPE_Config.WaveIRQ - 8 ) );
+      mask |= SOUNDSCAPE_IntController2Mask & ( 1 << ( SOUNDSCAPE_Config.WaveIRQ - 8 ) );
+      outp( 0xA1, mask  );
+      }
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: SOUNDSCAPE_ServiceInterrupt
+
+   Handles interrupt generated by sound card at the end of a voice
+   transfer.  Calls the user supplied callback function.
+---------------------------------------------------------------------*/
+
+static void __interrupt __far SOUNDSCAPE_ServiceInterrupt
+   (
+   void
+   )
+
+   {
+   // save stack
+   GetStack( &oldStackSelector, &oldStackPointer );
+
+   // set our stack
+   SetStack( StackSelector, StackPointer );
+
+	if ( !( inp( SOUNDSCAPE_Config.WavePort + AD_STATUS ) & 0x01 ) )
+      {
+      // restore stack
+      SetStack( oldStackSelector, oldStackPointer );
+
+      // Wasn't our interrupt.  Call the old one.
+      _chain_intr( SOUNDSCAPE_OldInt );
+      }
+
+   // clear the AD-1848 interrupt
+	outp( SOUNDSCAPE_Config.WavePort + AD_STATUS, 0x00 );
+
+   // Keep track of current buffer
+   SOUNDSCAPE_CurrentDMABuffer += SOUNDSCAPE_TransferLength;
+   if ( SOUNDSCAPE_CurrentDMABuffer >= SOUNDSCAPE_DMABufferEnd )
+      {
+      SOUNDSCAPE_CurrentDMABuffer = SOUNDSCAPE_DMABuffer;
+      }
+
+   // Call the caller's callback function
+   if ( SOUNDSCAPE_CallBack != NULL )
+      {
+      SOUNDSCAPE_CallBack();
+      }
+
+   // restore stack
+   SetStack( oldStackSelector, oldStackPointer );
+
+   // send EOI to Interrupt Controller
+   if ( SOUNDSCAPE_Config.WaveIRQ > 7 )
+      {
+      outp( 0xA0, 0x20 );
+      }
+   outp( 0x20, 0x20 );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: ga_read
+
+   Reads Ensoniq indirect registers.
+---------------------------------------------------------------------*/
+
+static int ga_read
+   (
+   int rnum
+   )
+
+   {
+   int data;
+
+   outp( SOUNDSCAPE_Config.BasePort + GA_REGADDR, rnum );
+   data = inp( SOUNDSCAPE_Config.BasePort + GA_REGDATA );
+   return( data );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: ga_write
+
+   Writes to Ensoniq indirect registers.
+---------------------------------------------------------------------*/
+
+static void ga_write
+   (
+   int rnum,
+   int value
+   )
+
+   {
+	outp( SOUNDSCAPE_Config.BasePort + GA_REGADDR, rnum );
+	outp( SOUNDSCAPE_Config.BasePort + GA_REGDATA, value );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: ad_read
+
+   Reads the AD-1848 indirect registers.  This function should not be
+   used while the AD-1848 mode change is enabled
+---------------------------------------------------------------------*/
+
+static int ad_read
+   (
+   int rnum
+   )
+
+   {
+   int data;
+
+	outp( SOUNDSCAPE_Config.WavePort + AD_REGADDR, rnum );
+	data = inp( SOUNDSCAPE_Config.WavePort + AD_REGDATA );
+   return( data );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: ad_write
+
+   Writes to the AD-1848 indirect registers.  This function should
+   not be used while the AD-1848 mode change is enabled.
+---------------------------------------------------------------------*/
+
+static void ad_write
+   (
+   int rnum,
+   int value
+   )
+
+   {
+   outp( SOUNDSCAPE_Config.WavePort + AD_REGADDR, rnum );
+   outp( SOUNDSCAPE_Config.WavePort + AD_REGDATA, value );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: tdelay
+
+   Delay function - 250ms - for AD-1848 re-synch and autocalibration.
+---------------------------------------------------------------------*/
+
+static void tdelay
+   (
+   void
+   )
+
+   {
+	long time;
+   unsigned flags;
+
+   flags = DisableInterrupts();
+   _enable();
+	time = clock() + CLOCKS_PER_SEC/4;
+	while(clock() < time)
+		;
+
+   RestoreInterrupts( flags );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: pcm_format
+
+   Sets the PCM data format.
+---------------------------------------------------------------------*/
+
+static void pcm_format
+   (
+   void
+   )
+
+   {
+	int format;
+
+	// build the register value based on format
+	format = 0;
+
+   switch( SOUNDSCAPE_SampleRate )
+      {
+      case 11025:
+         format = 0x03;
+         break;
+
+      case 22050:
+         format = 0x07;
+         break;
+
+      case 44100:
+         format = 0x0b;
+         break;
+
+      default:
+         // Set it to 11025 hz
+         format = 0x03;
+         break;
+      }
+
+	// set other format bits and format globals
+   if ( SOUNDSCAPE_MixMode & SIXTEEN_BIT )
+      {
+      format |= 0x40;
+      }
+
+   if ( SOUNDSCAPE_MixMode & STEREO )
+      {
+      format |= 0x10;
+      }
+
+	// enable mode change, point to format reg
+	outp( SOUNDSCAPE_Config.WavePort + AD_REGADDR, 0x40 | AD_FORMAT );
+
+	// write the format
+	outp( SOUNDSCAPE_Config.WavePort + AD_REGDATA, format );
+
+	// delay for internal re-synch
+	tdelay();
+
+	// exit mode change state
+	outp( SOUNDSCAPE_Config.WavePort + AD_REGADDR, 0x00 );
+
+	// delay for autocalibration
+	tdelay();
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: SOUNDSCAPE_SetPlaybackRate
+
+   Sets the rate at which the digitized sound will be played in
+   hertz.
+---------------------------------------------------------------------*/
+
+void SOUNDSCAPE_SetPlaybackRate
+   (
+   unsigned rate
+   )
+
+   {
+   if ( rate < 20000 )
+      {
+      rate = 11025;
+      }
+   else if ( rate < 30000 )
+      {
+      rate = 22050;
+      }
+   else
+      {
+      rate = 44100;
+      }
+
+   SOUNDSCAPE_SampleRate = rate;
+
+   // Set the rate
+   pcm_format();
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: SOUNDSCAPE_GetPlaybackRate
+
+   Returns the rate at which the digitized sound will be played in
+   hertz.
+---------------------------------------------------------------------*/
+
+unsigned SOUNDSCAPE_GetPlaybackRate
+   (
+   void
+   )
+
+   {
+   return( SOUNDSCAPE_SampleRate );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: SOUNDSCAPE_SetMixMode
+
+   Sets the sound card to play samples in mono or stereo.
+---------------------------------------------------------------------*/
+
+int SOUNDSCAPE_SetMixMode
+   (
+   int mode
+   )
+
+   {
+   SOUNDSCAPE_MixMode = mode & SOUNDSCAPE_MaxMixMode;
+   SOUNDSCAPE_SamplePacketSize = SOUNDSCAPE_SampleSize[ SOUNDSCAPE_MixMode ];
+
+   // Set the mixmode
+   pcm_format();
+
+   return( mode );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: SOUNDSCAPE_StopPlayback
+
+   Ends the DMA transfer of digitized sound to the sound card.
+---------------------------------------------------------------------*/
+
+void SOUNDSCAPE_StopPlayback
+   (
+   void
+   )
+
+   {
+   // Don't allow anymore interrupts
+   SOUNDSCAPE_DisableInterrupt();
+
+	/* stop the AD-1848 */
+	ad_write( AD_CONFIG, 0x00 );
+
+	/* let it finish it's cycles */
+	tdelay();
+
+   // Disable the DMA channel
+   DMA_EndTransfer( SOUNDSCAPE_Config.DMAChan );
+
+   SOUNDSCAPE_SoundPlaying = FALSE;
+
+   SOUNDSCAPE_DMABuffer = NULL;
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: SOUNDSCAPE_SetupDMABuffer
+
+   Programs the DMAC for sound transfer.
+---------------------------------------------------------------------*/
+
+static int SOUNDSCAPE_SetupDMABuffer
+   (
+   char *BufferPtr,
+   int   BufferSize,
+   int   mode
+   )
+
+   {
+   int DmaStatus;
+
+   DmaStatus = DMA_SetupTransfer( SOUNDSCAPE_Config.DMAChan, BufferPtr, BufferSize, mode );
+   if ( DmaStatus == DMA_Error )
+      {
+      SOUNDSCAPE_SetErrorCode( SOUNDSCAPE_DmaError );
+      return( SOUNDSCAPE_Error );
+      }
+
+   SOUNDSCAPE_DMAChannel         = SOUNDSCAPE_Config.DMAChan;
+   SOUNDSCAPE_DMABuffer          = BufferPtr;
+   SOUNDSCAPE_CurrentDMABuffer   = BufferPtr;
+   SOUNDSCAPE_TotalDMABufferSize = BufferSize;
+   SOUNDSCAPE_DMABufferEnd       = BufferPtr + BufferSize;
+
+   return( SOUNDSCAPE_Ok );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: SOUNDSCAPE_GetCurrentPos
+
+   Returns the offset within the current sound being played.
+---------------------------------------------------------------------*/
+
+int SOUNDSCAPE_GetCurrentPos
+   (
+   void
+   )
+
+   {
+   char *CurrentAddr;
+   int   offset;
+
+   if ( !SOUNDSCAPE_SoundPlaying )
+      {
+      SOUNDSCAPE_SetErrorCode( SOUNDSCAPE_NoSoundPlaying );
+      return( SOUNDSCAPE_Error );
+      }
+
+   CurrentAddr = DMA_GetCurrentPos( SOUNDSCAPE_Config.DMAChan );
+
+   offset = ( int )( ( ( unsigned long )CurrentAddr ) -
+      ( ( unsigned long )SOUNDSCAPE_CurrentDMABuffer ) );
+
+   if ( SOUNDSCAPE_MixMode & SIXTEEN_BIT )
+      {
+      offset >>= 1;
+      }
+
+   if ( SOUNDSCAPE_MixMode & STEREO )
+      {
+      offset >>= 1;
+      }
+
+   return( offset );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: SOUNDSCAPE_BeginPlayback
+
+   Starts playback of digitized sound.
+---------------------------------------------------------------------*/
+
+static int SOUNDSCAPE_BeginPlayback
+   (
+   int length
+   )
+
+   {
+   int SampleLength;
+   int LoByte;
+   int HiByte;
+
+   if ( SOUNDSCAPE_MixMode & SIXTEEN_BIT )
+      {
+      SampleLength = length / 2;
+      }
+   else
+      {
+      SampleLength = length;
+      }
+
+   if ( SOUNDSCAPE_MixMode & STEREO )
+      {
+      SampleLength >>= 1;
+      }
+
+   SampleLength--;
+
+	// setup the AD-1848 interrupt count
+	// set the interrupt count value based on the format.
+	// count will decrement every sample period and generate
+	// an interrupt when in rolls over. we want this always
+	// to be at every 1/2 buffer, regardless of the data format,
+	// so the count must be adjusted accordingly.
+   HiByte = hibyte( SampleLength );
+   LoByte = lobyte( SampleLength );
+	ad_write( AD_LCOUNT, LoByte );
+	ad_write( AD_UCOUNT, HiByte );
+
+	/* unmask the host DMA controller */
+   SOUNDSCAPE_EnableInterrupt();
+
+	/* start the AD-1848 */
+	ad_write(AD_CONFIG, 0x01);
+
+   SOUNDSCAPE_SoundPlaying = TRUE;
+
+   return( SOUNDSCAPE_Ok );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: SOUNDSCAPE_BeginBufferedPlayback
+
+   Begins multibuffered playback of digitized sound on the sound card.
+---------------------------------------------------------------------*/
+
+int SOUNDSCAPE_BeginBufferedPlayback
+   (
+   char    *BufferStart,
+   int      BufferSize,
+   int      NumDivisions,
+   unsigned SampleRate,
+   int      MixMode,
+   void  ( *CallBackFunc )( void )
+   )
+
+   {
+   int DmaStatus;
+   int TransferLength;
+
+   if ( SOUNDSCAPE_SoundPlaying )
+      {
+      SOUNDSCAPE_StopPlayback();
+      }
+
+   SOUNDSCAPE_SetMixMode( MixMode );
+
+   DmaStatus = SOUNDSCAPE_SetupDMABuffer( BufferStart, BufferSize,
+      DMA_AutoInitRead );
+   if ( DmaStatus == SOUNDSCAPE_Error )
+      {
+      return( SOUNDSCAPE_Error );
+      }
+
+   SOUNDSCAPE_SetPlaybackRate( SampleRate );
+
+   SOUNDSCAPE_SetCallBack( CallBackFunc );
+
+   SOUNDSCAPE_EnableInterrupt();
+
+   TransferLength = BufferSize / NumDivisions;
+   SOUNDSCAPE_TransferLength = TransferLength;
+
+   SOUNDSCAPE_BeginPlayback( TransferLength );
+
+   return( SOUNDSCAPE_Ok );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: SOUNDSCAPE_GetCardInfo
+
+   Returns the maximum number of bits that can represent a sample
+   (8 or 16) and the number of channels (1 for mono, 2 for stereo).
+---------------------------------------------------------------------*/
+
+int SOUNDSCAPE_GetCardInfo
+   (
+   int *MaxSampleBits,
+   int *MaxChannels
+   )
+
+   {
+   int status;
+
+   status = SOUNDSCAPE_FindCard();
+   if ( status == SOUNDSCAPE_Ok )
+      {
+      *MaxChannels = 2;
+      *MaxSampleBits = 16;
+      return( SOUNDSCAPE_Ok );
+      }
+
+   return( status );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: SOUNDSCAPE_SetCallBack
+
+   Specifies the user function to call at the end of a sound transfer.
+---------------------------------------------------------------------*/
+
+void SOUNDSCAPE_SetCallBack
+   (
+   void ( *func )( void )
+   )
+
+   {
+   SOUNDSCAPE_CallBack = func;
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: SOUNDSCAPE_LockEnd
+
+   Used for determining the length of the functions to lock in memory.
+---------------------------------------------------------------------*/
+
+static void SOUNDSCAPE_LockEnd
+   (
+   void
+   )
+
+   {
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: SOUNDSCAPE_UnlockMemory
+
+   Unlocks all neccessary data.
+---------------------------------------------------------------------*/
+
+static void SOUNDSCAPE_UnlockMemory
+   (
+   void
+   )
+
+   {
+   DPMI_UnlockMemoryRegion( SOUNDSCAPE_LockStart, SOUNDSCAPE_LockEnd );
+   DPMI_Unlock( SOUNDSCAPE_Config );
+   DPMI_Unlock( SOUNDSCAPE_OldInt );
+   DPMI_Unlock( SOUNDSCAPE_Installed );
+   DPMI_Unlock( SOUNDSCAPE_DMABuffer );
+   DPMI_Unlock( SOUNDSCAPE_DMABufferEnd );
+   DPMI_Unlock( SOUNDSCAPE_CurrentDMABuffer );
+   DPMI_Unlock( SOUNDSCAPE_TotalDMABufferSize );
+   DPMI_Unlock( SOUNDSCAPE_TransferLength );
+   DPMI_Unlock( SOUNDSCAPE_MixMode );
+   DPMI_Unlock( SOUNDSCAPE_SamplePacketSize );
+   DPMI_Unlock( SOUNDSCAPE_SampleRate );
+   DPMI_Unlock( SOUNDSCAPE_SoundPlaying );
+   DPMI_Unlock( SOUNDSCAPE_CallBack );
+   DPMI_Unlock( SOUNDSCAPE_IntController1Mask );
+   DPMI_Unlock( SOUNDSCAPE_IntController2Mask );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: SOUNDSCAPE_LockMemory
+
+   Locks all neccessary data.
+---------------------------------------------------------------------*/
+
+static int SOUNDSCAPE_LockMemory
+   (
+   void
+   )
+
+   {
+   int status;
+
+   status  = DPMI_LockMemoryRegion( SOUNDSCAPE_LockStart, SOUNDSCAPE_LockEnd );
+   status |= DPMI_Lock( SOUNDSCAPE_Config );
+   status |= DPMI_Lock( SOUNDSCAPE_OldInt );
+   status |= DPMI_Lock( SOUNDSCAPE_Installed );
+   status |= DPMI_Lock( SOUNDSCAPE_DMABuffer );
+   status |= DPMI_Lock( SOUNDSCAPE_DMABufferEnd );
+   status |= DPMI_Lock( SOUNDSCAPE_CurrentDMABuffer );
+   status |= DPMI_Lock( SOUNDSCAPE_TotalDMABufferSize );
+   status |= DPMI_Lock( SOUNDSCAPE_TransferLength );
+   status |= DPMI_Lock( SOUNDSCAPE_MixMode );
+   status |= DPMI_Lock( SOUNDSCAPE_SamplePacketSize );
+   status |= DPMI_Lock( SOUNDSCAPE_SampleRate );
+   status |= DPMI_Lock( SOUNDSCAPE_SoundPlaying );
+   status |= DPMI_Lock( SOUNDSCAPE_CallBack );
+   status |= DPMI_Lock( SOUNDSCAPE_IntController1Mask );
+   status |= DPMI_Lock( SOUNDSCAPE_IntController2Mask );
+
+   if ( status != DPMI_Ok )
+      {
+      SOUNDSCAPE_UnlockMemory();
+      SOUNDSCAPE_SetErrorCode( SOUNDSCAPE_DPMI_Error );
+      return( SOUNDSCAPE_Error );
+      }
+
+   return( SOUNDSCAPE_Ok );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: allocateTimerStack
+
+   Allocate a block of memory from conventional (low) memory and return
+   the selector (which can go directly into a segment register) of the
+   memory block or 0 if an error occured.
+---------------------------------------------------------------------*/
+
+static unsigned short allocateTimerStack
+   (
+   unsigned short size
+   )
+
+   {
+   union REGS regs;
+
+   // clear all registers
+   memset( &regs, 0, sizeof( regs ) );
+
+   // DPMI allocate conventional memory
+   regs.w.ax = 0x100;
+
+   // size in paragraphs
+   regs.w.bx = ( size + 15 ) / 16;
+
+   int386( 0x31, &regs, &regs );
+   if (!regs.w.cflag)
+      {
+      // DPMI call returns selector in dx
+      // (ax contains real mode segment
+      // which is ignored here)
+
+      return( regs.w.dx );
+      }
+
+   // Couldn't allocate memory.
+   return( NULL );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: deallocateTimerStack
+
+   Deallocate a block of conventional (low) memory given a selector to
+   it.  Assumes the block was allocated with DPMI function 0x100.
+---------------------------------------------------------------------*/
+
+static void deallocateTimerStack
+   (
+   unsigned short selector
+   )
+
+   {
+   union REGS regs;
+
+   if ( selector != NULL )
+      {
+      // clear all registers
+      memset( &regs, 0, sizeof( regs ) );
+
+      regs.w.ax = 0x101;
+      regs.w.dx = selector;
+      int386( 0x31, &regs, &regs );
+      }
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: parse
+
+   Parses for the right hand string of an .INI file equate.
+---------------------------------------------------------------------*/
+
+static int parse
+   (
+   char *val,
+   char *str,
+   FILE *p1
+   )
+
+   {
+	int  i;
+	int  j;
+   char tmpstr[ 81 ];
+
+	rewind( p1 );
+
+	while( !feof( p1 ) )
+      {
+      // get a new string
+      fgets( tmpstr, 81, p1 );
+      if( ( tmpstr[ 0 ] == '[' ) || ( tmpstr[ 0 ] == ';' ) ||
+         ( tmpstr[ 0 ] == '\n' ) )
+         {
+         continue;
+         }
+
+		// parse up to the '='
+      i = 0;
+      while( ( tmpstr[ i ] != '=' ) && ( tmpstr[ i ] != '\n' ) )
+         {
+         i++;
+         }
+
+		if( tmpstr[ i ] != '=' )
+         {
+         continue;
+         }
+
+		tmpstr[ i ] = '\0';
+
+		// see if it's the one we want
+		if ( strcmp( tmpstr, str ) )
+         {
+         continue;
+         }
+
+		// copy the right hand value to the destination string
+      i++;
+		for( j = 0; j < 32; j++ )
+         {
+         if ( ( tmpstr[ i ] == ' ' ) || ( tmpstr[ i ] == '\t' ) ||
+            ( tmpstr[ i ] == ',' ) || ( tmpstr[ i ] == '\n' ) )
+            {
+            break;
+            }
+
+			val[ j ] = tmpstr[ i ];
+         i++;
+         }
+		val[j] = '\0';
+
+      return( TRUE );
+      }
+
+   return( FALSE );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: SOUNDSCAPE_FindCard
+
+   Determines if a SoundScape is present and where it is located.
+---------------------------------------------------------------------*/
+
+static int SOUNDSCAPE_FindCard
+   (
+   void
+   )
+
+   {
+   int   found;
+   int   status;
+   int   tmp;
+	char *cp;
+   char  str[ 33 ];
+	FILE *fp;
+
+   if ( SOUNDSCAPE_FoundCard )
+      {
+      return( SOUNDSCAPE_Ok );
+      }
+
+	cp = getenv( "SNDSCAPE" );
+   if ( cp == NULL )
+      {
+      strcpy( str, "C:\\SNDSCAPE" );
+      }
+   else
+      {
+      strcpy( str, cp );
+      }
+
+   strcat(str, "\\SNDSCAPE.INI");
+
+	fp = fopen( str, "r" );
+   if ( fp == NULL )
+      {
+      if ( cp == NULL )
+         {
+         SOUNDSCAPE_SetErrorCode( SOUNDSCAPE_EnvNotFound );
+         return( SOUNDSCAPE_Error );
+         }
+
+      SOUNDSCAPE_SetErrorCode( SOUNDSCAPE_InitFileNotFound );
+      return( SOUNDSCAPE_Error );
+      }
+
+	found = parse( str, "Product", fp );
+   if ( !found )
+      {
+      fclose( fp );
+      SOUNDSCAPE_SetErrorCode( SOUNDSCAPE_MissingProductInfo );
+      return( SOUNDSCAPE_Error );
+      }
+
+	if( strstr( str, "SoundFX" ) == NULL )
+      {
+      SOUNDSCAPE_Config.OldIRQs = FALSE;
+      }
+	else
+      {
+		SOUNDSCAPE_Config.OldIRQs = TRUE;
+      }
+
+	found = parse( str, "Port", fp );
+   if ( !found )
+      {
+      fclose( fp );
+      SOUNDSCAPE_SetErrorCode( SOUNDSCAPE_MissingPortInfo );
+      return( SOUNDSCAPE_Error );
+      }
+
+	SOUNDSCAPE_Config.BasePort = strtol( str, ( char ** )0, 16);
+
+	found = parse( str, "DMA", fp );
+   if ( !found )
+      {
+      fclose( fp );
+      SOUNDSCAPE_SetErrorCode( SOUNDSCAPE_MissingDMAInfo );
+      return( SOUNDSCAPE_Error );
+      }
+
+	SOUNDSCAPE_Config.DMAChan = ( int )strtol( str, ( char ** )0, 10 );
+   status = DMA_VerifyChannel( SOUNDSCAPE_Config.DMAChan );
+   if ( status == DMA_Error )
+      {
+      fclose( fp );
+      SOUNDSCAPE_SetErrorCode( SOUNDSCAPE_DmaError );
+      return( SOUNDSCAPE_Error );
+      }
+
+	found = parse( str, "IRQ", fp );
+   if ( !found )
+      {
+      fclose( fp );
+      SOUNDSCAPE_SetErrorCode( SOUNDSCAPE_MissingIRQInfo );
+      return( SOUNDSCAPE_Error );
+      }
+
+	SOUNDSCAPE_Config.MIDIIRQ = ( int )strtol( str, ( char ** )0, 10 );
+   if ( SOUNDSCAPE_Config.MIDIIRQ == 2 )
+      {
+      SOUNDSCAPE_Config.MIDIIRQ = 9;
+      }
+
+	found = parse( str, "SBIRQ", fp );
+   if ( !found )
+      {
+      fclose( fp );
+      SOUNDSCAPE_SetErrorCode( SOUNDSCAPE_MissingSBIRQInfo );
+      return( SOUNDSCAPE_Error );
+      }
+
+	SOUNDSCAPE_Config.WaveIRQ = ( int )strtol( str, ( char ** )0, 10 );
+	if ( SOUNDSCAPE_Config.WaveIRQ == 2 )
+      {
+		SOUNDSCAPE_Config.WaveIRQ = 9;
+      }
+
+   if ( !VALID_IRQ( SOUNDSCAPE_Config.WaveIRQ ) )
+      {
+      fclose( fp );
+      SOUNDSCAPE_SetErrorCode( SOUNDSCAPE_InvalidSBIrq );
+      return( SOUNDSCAPE_Error );
+      }
+
+   if ( SOUNDSCAPE_Interrupts[ SOUNDSCAPE_Config.WaveIRQ ] == INVALID )
+      {
+      fclose( fp );
+      SOUNDSCAPE_SetErrorCode( SOUNDSCAPE_InvalidSBIrq );
+      return( SOUNDSCAPE_Error );
+      }
+
+	found = parse( str, "SBEnable", fp );
+   if ( !found )
+      {
+      fclose( fp );
+      SOUNDSCAPE_SetErrorCode( SOUNDSCAPE_MissingSBENABLEInfo );
+      return( SOUNDSCAPE_Error );
+      }
+
+	if( !strcmp( str, "false" ) )
+      {
+      SOUNDSCAPE_Config.SBEmul = FALSE;
+      }
+	else
+      {
+      SOUNDSCAPE_Config.SBEmul = TRUE;
+      }
+
+	// do a hardware test
+	outp( SOUNDSCAPE_Config.BasePort + GA_REGADDR, 0x00f5 );
+	tmp = inp( SOUNDSCAPE_Config.BasePort + GA_REGADDR );
+	if ( ( tmp & 0x000f ) != 0x0005 )
+      {
+      fclose( fp );
+      SOUNDSCAPE_SetErrorCode( SOUNDSCAPE_HardwareError );
+      return( SOUNDSCAPE_Error );
+      }
+
+	if( ( tmp & 0x00f0 ) == 0x00f0 )
+      {
+      fclose( fp );
+      SOUNDSCAPE_SetErrorCode( SOUNDSCAPE_HardwareError );
+      return( SOUNDSCAPE_Error );
+      }
+
+	// formulate the chip ID
+	tmp >>= 4;
+	if( tmp == 0 )
+      {
+      SOUNDSCAPE_Config.ChipID = ODIE;
+      }
+	else if ( !( tmp & 0x0008 ) )
+      {
+		SOUNDSCAPE_Config.ChipID = OPUS;
+      }
+	else
+      {
+		SOUNDSCAPE_Config.ChipID = MMIC;
+      }
+
+	// parse for the AD-1848 address if necessary
+	if( SOUNDSCAPE_Config.ChipID == ODIE )
+      {
+      found = parse( str, "WavePort", fp );
+      if ( !found )
+         {
+         fclose( fp );
+         SOUNDSCAPE_SetErrorCode( SOUNDSCAPE_MissingWavePortInfo );
+         return( SOUNDSCAPE_Error );
+         }
+
+      SOUNDSCAPE_Config.WavePort = strtol( str, ( char ** )0, 16 );
+      }
+	else
+      {
+      // otherwise, the base address is fixed
+      SOUNDSCAPE_Config.WavePort = SOUNDSCAPE_Config.BasePort + AD_OFFSET;
+      }
+
+	// we're done with the file
+	fclose( fp );
+
+	// if it's an ODIE board, note CD-ROM decode enable
+	if ( SOUNDSCAPE_Config.ChipID == ODIE )
+      {
+		SOUNDSCAPE_Config.CDROM = ga_read( GA_CDCFG ) & 0x80;
+      }
+
+	// build the Wave IRQ index value
+	if( !SOUNDSCAPE_Config.OldIRQs )
+      {
+      switch( SOUNDSCAPE_Config.WaveIRQ )
+         {
+         case 9 :
+            SOUNDSCAPE_Config.IRQIndx = 0;
+            break;
+
+         case 5 :
+            SOUNDSCAPE_Config.IRQIndx = 1;
+            break;
+
+         case 7 :
+            SOUNDSCAPE_Config.IRQIndx = 2;
+            break;
+
+         default :
+            SOUNDSCAPE_Config.IRQIndx = 3;
+            break;
+         }
+      }
+   else
+      {
+      switch( SOUNDSCAPE_Config.WaveIRQ )
+         {
+         case 9 :
+            SOUNDSCAPE_Config.IRQIndx = 0;
+            break;
+
+         case 5 :
+            SOUNDSCAPE_Config.IRQIndx = 2;
+            break;
+
+         case 7 :
+            SOUNDSCAPE_Config.IRQIndx = 1;
+            break;
+
+         default :
+            SOUNDSCAPE_Config.IRQIndx = 3;
+            break;
+         }
+      }
+
+   SOUNDSCAPE_FoundCard = TRUE;
+   SOUNDSCAPE_SetErrorCode( SOUNDSCAPE_Ok );
+   return( SOUNDSCAPE_Ok );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: SOUNDSCAPE_Setup
+
+   Setup the Soundscape card for native mode PCM.
+---------------------------------------------------------------------*/
+
+static int SOUNDSCAPE_Setup
+   (
+   void
+   )
+
+   {
+   int tmp;
+   int Interrupt;
+   int status;
+
+	// if necessary, clear any pending SB ints
+	if ( SOUNDSCAPE_Config.SBEmul )
+      {
+      inp( SB_IACK );
+      }
+
+   SOUNDSCAPE_DisableInterrupt();
+
+	// make sure the AD-1848 is not running
+	if ( ad_read( AD_CONFIG ) & 0x01 )
+      {
+      SOUNDSCAPE_StopPlayback();
+      }
+
+	// if necessary, do some signal re-routing
+	if( SOUNDSCAPE_Config.ChipID != MMIC )
+      {
+      // get the gate-array off of the DMA channel
+		ga_write( GA_DMACHB, 0x20 );
+
+      if ( !SOUNDSCAPE_Config.OldIRQs )
+         {
+         switch( SOUNDSCAPE_Config.MIDIIRQ )
+            {
+            case 5 :
+               tmp = 1;
+               break;
+
+            case 7 :
+               tmp = 2;
+               break;
+
+            case 9 :
+               tmp = 0;
+               break;
+
+            default :
+               tmp = 3;
+               break;
+            }
+         }
+      else
+         {
+         switch( SOUNDSCAPE_Config.MIDIIRQ )
+            {
+            case 5 :
+               tmp = 2;
+               break;
+
+            case 7 :
+               tmp = 1;
+               break;
+
+            case 9 :
+               tmp = 0;
+               break;
+
+            default :
+               tmp = 3;
+               break;
+            }
+         }
+
+      // set HostIRQ to MIDIIRQ for now
+      ga_write( GA_INTCFG, 0xf0 | ( tmp << 2 ) | tmp );
+
+      // now, route the AD-1848 stuff ...
+		if ( SOUNDSCAPE_Config.ChipID == OPUS )
+         {
+         // set the AD-1848 chip decode
+         ga_write( GA_HMCTL, ( ga_read( GA_HMCTL ) & 0xcf ) | 0x10 );
+         }
+      // setup the DMA polarity
+		ga_write( GA_DMACFG, 0x50 );
+
+		// init the CD-ROM (AD-1848) config register
+		ga_write( GA_CDCFG, 0x89 | ( SOUNDSCAPE_Config.DMAChan << 4 ) | ( SOUNDSCAPE_Config.IRQIndx << 1 ) );
+
+      // enable mode change, point to config reg
+		outp( SOUNDSCAPE_Config.WavePort + AD_REGADDR, 0x40 | AD_CONFIG );
+
+      // set interf cnfg reg for DMA mode, single chan, autocal on
+		outp( SOUNDSCAPE_Config.WavePort + AD_REGDATA, 0x0c );
+
+      // exit mode change state
+		outp( SOUNDSCAPE_Config.WavePort + AD_REGADDR, 0x00 );
+
+      // delay for autocalibration
+      tdelay();
+      }
+
+   // Install our interrupt handler
+   Interrupt = SOUNDSCAPE_Interrupts[ SOUNDSCAPE_Config.WaveIRQ ];
+   SOUNDSCAPE_OldInt = _dos_getvect( Interrupt );
+   if ( SOUNDSCAPE_Config.WaveIRQ < 8 )
+      {
+      _dos_setvect( Interrupt, SOUNDSCAPE_ServiceInterrupt );
+      }
+   else
+      {
+      status = IRQ_SetVector( Interrupt, SOUNDSCAPE_ServiceInterrupt );
+      if ( status != IRQ_Ok )
+         {
+         SOUNDSCAPE_SetErrorCode( SOUNDSCAPE_UnableToSetIrq );
+         return( SOUNDSCAPE_Error );
+         }
+      }
+
+	// max left and right volumes
+	ad_write( AD_LEFTOUT, 0 );
+	ad_write( AD_RIGHTOUT, 0 );
+
+	// clear any pending interrupt condition
+	outp( SOUNDSCAPE_Config.WavePort + AD_STATUS, 0x00 );
+
+	// enable the interrupt pin
+	ad_write( AD_PINCTRL, ad_read( AD_PINCTRL ) | 0x02 );
+
+   SOUNDSCAPE_EnableInterrupt();
+
+   SOUNDSCAPE_SetErrorCode( SOUNDSCAPE_Ok );
+   return( SOUNDSCAPE_Ok );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: SOUNDSCAPE_GetMIDIPort
+
+   Gets the address of the SoundScape MIDI port.
+---------------------------------------------------------------------*/
+
+int SOUNDSCAPE_GetMIDIPort
+   (
+   void
+   )
+
+   {
+   int status;
+
+   status = SOUNDSCAPE_FindCard();
+   if ( status != SOUNDSCAPE_Ok )
+      {
+      return( status );
+      }
+
+   return( SOUNDSCAPE_Config.BasePort );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: SOUNDSCAPE_Init
+
+   Initializes the sound card and prepares the module to play
+   digitized sounds.
+---------------------------------------------------------------------*/
+
+int SOUNDSCAPE_Init
+   (
+   void
+   )
+
+   {
+   int status;
+
+   if ( SOUNDSCAPE_Installed )
+      {
+      SOUNDSCAPE_Shutdown();
+      }
+
+   // Save the interrupt masks
+   SOUNDSCAPE_IntController1Mask = inp( 0x21 );
+   SOUNDSCAPE_IntController2Mask = inp( 0xA1 );
+
+   SOUNDSCAPE_SoundPlaying = FALSE;
+   SOUNDSCAPE_SetCallBack( NULL );
+   SOUNDSCAPE_DMABuffer = NULL;
+
+   status = SOUNDSCAPE_FindCard();
+   if ( status != SOUNDSCAPE_Ok )
+      {
+      return( status );
+      }
+
+   status = SOUNDSCAPE_LockMemory();
+   if ( status != SOUNDSCAPE_Ok )
+      {
+      SOUNDSCAPE_UnlockMemory();
+      return( status );
+      }
+
+   StackSelector = allocateTimerStack( kStackSize );
+   if ( StackSelector == NULL )
+      {
+      SOUNDSCAPE_UnlockMemory();
+      SOUNDSCAPE_SetErrorCode( SOUNDSCAPE_OutOfMemory );
+      return( SOUNDSCAPE_Error );
+      }
+
+   // Leave a little room at top of stack just for the hell of it...
+   StackPointer = kStackSize - sizeof( long );
+
+   SOUNDSCAPE_Installed = TRUE;
+
+   status = SOUNDSCAPE_Setup();
+   if ( status != SOUNDSCAPE_Ok )
+      {
+      SOUNDSCAPE_Shutdown();
+      return( status );
+      }
+
+//	printf("Testing DMA and IRQ ...\n");
+//	if( test_dma_irq() )
+//      {
+//      printf("\t\007Hardware Not Responding\n\n");
+//      close_soundscape();
+//      return( SOUNDSCAPE_Error );
+//      }
+
+   SOUNDSCAPE_SetPlaybackRate( SOUNDSCAPE_DefaultSampleRate );
+   SOUNDSCAPE_SetMixMode( SOUNDSCAPE_DefaultMixMode );
+
+   SOUNDSCAPE_SetErrorCode( SOUNDSCAPE_Ok );
+   return( SOUNDSCAPE_Ok );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: SOUNDSCAPE_Shutdown
+
+   Ends transfer of sound data to the sound card and restores the
+   system resources used by the card.
+---------------------------------------------------------------------*/
+
+void SOUNDSCAPE_Shutdown
+   (
+   void
+   )
+
+   {
+   int Interrupt;
+
+   // Halt the DMA transfer
+   SOUNDSCAPE_StopPlayback();
+
+	// disable the AD-1848 interrupt pin
+	ad_write( AD_PINCTRL, ad_read( AD_PINCTRL ) & 0xfd );
+
+	// if necessary, do some signal re-routing
+	if ( SOUNDSCAPE_Config.ChipID != MMIC )
+      {
+		// re-init the CD-ROM (AD-1848) config register as needed.
+		// this will disable the AD-1848 interface.
+		if ( SOUNDSCAPE_Config.ChipID == ODIE )
+         {
+         ga_write( GA_CDCFG, SOUNDSCAPE_Config.CDROM );
+         }
+		else
+         {
+         ga_write( GA_CDCFG, ga_read( GA_CDCFG ) & 0x7f);
+         }
+
+		// if necessary, reset the SoundBlaster IRQ
+		if ( SOUNDSCAPE_Config.SBEmul )
+         {
+         ga_write( GA_INTCFG, ( ga_read( GA_INTCFG ) & 0xf3 ) |
+            ( SOUNDSCAPE_Config.IRQIndx << 2 ) );
+         }
+
+      // re-assign the gate-array DMA channel
+		ga_write( GA_DMACHB, 0x80 | ( SOUNDSCAPE_Config.DMAChan << 4 ) );
+      }
+
+   // Restore the original interrupt
+   Interrupt = SOUNDSCAPE_Interrupts[ SOUNDSCAPE_Config.WaveIRQ ];
+   if ( SOUNDSCAPE_Config.WaveIRQ >= 8 )
+      {
+      IRQ_RestoreVector( Interrupt );
+      }
+   _dos_setvect( Interrupt, SOUNDSCAPE_OldInt );
+
+   SOUNDSCAPE_SoundPlaying = FALSE;
+
+   SOUNDSCAPE_DMABuffer = NULL;
+
+   SOUNDSCAPE_SetCallBack( NULL );
+
+   SOUNDSCAPE_UnlockMemory();
+
+   if ( StackSelector != NULL )
+      {
+      deallocateTimerStack( StackSelector );
+      StackSelector = NULL;
+      }
+
+   SOUNDSCAPE_Installed = FALSE;
+   }
--- /dev/null
+++ b/rott/audiolib/sndscape.h
@@ -1,0 +1,73 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+/**********************************************************************
+   module: SNDSCAPE.H
+
+   author: James R. Dose
+   date:   October 26, 1994
+
+   Public header for SNDSCAPE.C
+
+   (c) Copyright 1994 James R. Dose.  All Rights Reserved.
+**********************************************************************/
+
+#ifndef __SNDSCAPE_H
+#define __SNDSCAPE_H
+
+extern int SOUNDSCAPE_DMAChannel;
+extern int SOUNDSCAPE_ErrorCode;
+
+enum SOUNDSCAPE_ERRORS
+   {
+   SOUNDSCAPE_Warning = -2,
+   SOUNDSCAPE_Error = -1,
+   SOUNDSCAPE_Ok = 0,
+   SOUNDSCAPE_EnvNotFound,
+   SOUNDSCAPE_InitFileNotFound,
+   SOUNDSCAPE_MissingProductInfo,
+   SOUNDSCAPE_MissingPortInfo,
+   SOUNDSCAPE_MissingDMAInfo,
+   SOUNDSCAPE_MissingIRQInfo,
+   SOUNDSCAPE_MissingSBIRQInfo,
+   SOUNDSCAPE_MissingSBENABLEInfo,
+   SOUNDSCAPE_MissingWavePortInfo,
+   SOUNDSCAPE_HardwareError,
+   SOUNDSCAPE_NoSoundPlaying,
+   SOUNDSCAPE_InvalidSBIrq,
+   SOUNDSCAPE_UnableToSetIrq,
+   SOUNDSCAPE_DmaError,
+   SOUNDSCAPE_DPMI_Error,
+   SOUNDSCAPE_OutOfMemory
+   };
+
+char    *SOUNDSCAPE_ErrorString( int ErrorNumber );
+void     SOUNDSCAPE_SetPlaybackRate( unsigned rate );
+unsigned SOUNDSCAPE_GetPlaybackRate( void );
+int      SOUNDSCAPE_SetMixMode( int mode );
+void     SOUNDSCAPE_StopPlayback( void );
+int      SOUNDSCAPE_GetCurrentPos( void );
+int      SOUNDSCAPE_BeginBufferedPlayback( char *BufferStart, int BufferSize, int NumDivisions, unsigned SampleRate, int MixMode, void ( *CallBackFunc )( void ) );
+int      SOUNDSCAPE_GetCardInfo( int *MaxSampleBits, int *MaxChannels );
+void     SOUNDSCAPE_SetCallBack( void ( *func )( void ) );
+int      SOUNDSCAPE_GetMIDIPort( void );
+int      SOUNDSCAPE_Init( void );
+void     SOUNDSCAPE_Shutdown( void );
+
+#endif
--- /dev/null
+++ b/rott/audiolib/sndsrc.c
@@ -1,0 +1,658 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+/**********************************************************************
+   module: SNDSRC.C
+
+   author: James R. Dose
+   date:   March 26, 1994
+
+   Low level routines to support the Disney Sound Source.
+
+   (c) Copyright 1994 James R. Dose.  All Rights Reserved.
+**********************************************************************/
+
+#define STEREO      1
+#define SIXTEEN_BIT 2
+
+#define MONO_8BIT    0
+#define STEREO_8BIT  ( STEREO )
+#define MONO_16BIT   ( SIXTEEN_BIT )
+#define STEREO_16BIT ( STEREO | SIXTEEN_BIT )
+
+#include <stdlib.h>
+#include <dos.h>
+#include <conio.h>
+#include "dpmi.h"
+#include "task_man.h"
+#include "sndcards.h"
+#include "user.h"
+#include "sndsrc.h"
+
+#define TRUE  ( 1 == 1 )
+#define FALSE ( !TRUE )
+
+static int SS_Installed = FALSE;
+
+static int SS_Port = SS_DefaultPort;
+static int SS_OffCommand = 0xc;
+
+static char   *SS_BufferStart;
+static char   *SS_BufferEnd;
+static char   *SS_CurrentBuffer;
+static int     SS_BufferNum = 0;
+static int     SS_NumBuffers = 0;
+static int     SS_TotalBufferSize = 0;
+static int     SS_TransferLength  = 0;
+static int     SS_CurrentLength   = 0;
+
+static char   *SS_SoundPtr;
+volatile int   SS_SoundPlaying;
+
+static task   *SS_Timer;
+
+void ( *SS_CallBack )( void );
+
+int SS_ErrorCode = SS_Ok;
+
+#define SS_SetErrorCode( status ) \
+   SS_ErrorCode   = ( status );
+
+/*---------------------------------------------------------------------
+   Function: SS_ErrorString
+
+   Returns a pointer to the error message associated with an error
+   number.  A -1 returns a pointer the current error.
+---------------------------------------------------------------------*/
+
+char *SS_ErrorString
+   (
+   int ErrorNumber
+   )
+
+   {
+   char *ErrorString;
+
+   switch( ErrorNumber )
+      {
+      case SS_Error :
+         ErrorString = SS_ErrorString( SS_ErrorCode );
+         break;
+
+      case SS_Ok :
+         ErrorString = "Sound Source ok.";
+         break;
+
+      case SS_NotFound :
+         ErrorString = "Could not detect Sound Source.";
+         break;
+
+      case SS_NoSoundPlaying :
+         ErrorString = "No sound playing in SndSrc.";
+         break;
+
+      case SS_DPMI_Error :
+         ErrorString = "DPMI Error in SndSrc.";
+         break;
+
+      default :
+         ErrorString = "Unknown Sound Source error code.";
+         break;
+      }
+
+   return( ErrorString );
+   }
+
+
+/**********************************************************************
+
+   Memory locked functions:
+
+**********************************************************************/
+
+
+#define SS_LockStart SS_ServiceInterrupt
+
+
+/*---------------------------------------------------------------------
+   Function: SS_ServiceInterrupt
+
+   Handles interrupt generated by sound card at the end of a voice
+   transfer.  Calls the user supplied callback function.
+---------------------------------------------------------------------*/
+
+static void SS_ServiceInterrupt
+   (
+   task *Task
+   )
+
+   {
+   int port = SS_Port;
+   int count;
+
+   count = 0;
+   while( ( inp( port + 1 ) & 0x40 ) == 0 )
+      {
+      outp( port, *SS_SoundPtr++ );
+      outp( port + 2, SS_OffCommand );
+      outp( port + 2, 4 );
+
+      SS_CurrentLength--;
+      if ( SS_CurrentLength == 0 )
+         {
+         // Keep track of current buffer
+         SS_CurrentBuffer += SS_TransferLength;
+         SS_BufferNum++;
+         if ( SS_BufferNum >= SS_NumBuffers )
+            {
+            SS_BufferNum = 0;
+            SS_CurrentBuffer = SS_BufferStart;
+            }
+
+         SS_CurrentLength = SS_TransferLength;
+         SS_SoundPtr = SS_CurrentBuffer;
+
+         // Call the caller's callback function
+         if ( SS_CallBack != NULL )
+            {
+            SS_CallBack();
+            }
+         }
+
+      count++;
+      // Only do at most 14 samples per tick
+      if ( count > 13 )
+         {
+         break;
+         }
+      }
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: SS_StopPlayback
+
+   Ends the transfer of digitized sound to the Sound Source.
+---------------------------------------------------------------------*/
+
+void SS_StopPlayback
+   (
+   void
+   )
+
+   {
+   if ( SS_SoundPlaying )
+      {
+      TS_Terminate( SS_Timer );
+
+      outp( SS_Port, 0x80 );
+      outp( SS_Port + 2, SS_OffCommand );
+      outp( SS_Port + 2, 4 );
+
+      SS_SoundPlaying = FALSE;
+
+      SS_BufferStart = NULL;
+      }
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: SS_GetCurrentPos
+
+   Returns the offset within the current sound being played.
+---------------------------------------------------------------------*/
+
+int SS_GetCurrentPos
+   (
+   void
+   )
+
+   {
+   int offset;
+
+   if ( !SS_SoundPlaying )
+      {
+      SS_SetErrorCode( SS_NoSoundPlaying );
+      return( SS_Warning );
+      }
+
+   offset = ( int )( ( ( unsigned long )SS_SoundPtr ) -
+      ( ( unsigned long )SS_CurrentBuffer ) );
+
+   return( offset );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: SS_LockEnd
+
+   Used for determining the length of the functions to lock in memory.
+---------------------------------------------------------------------*/
+
+static void SS_LockEnd
+   (
+   void
+   )
+
+   {
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: SS_BeginBufferedPlayback
+
+   Begins multibuffered playback of digitized sound on the Sound Source.
+---------------------------------------------------------------------*/
+
+int SS_BeginBufferedPlayback
+   (
+   char *BufferStart,
+   int   BufferSize,
+   int   NumDivisions,
+   void ( *CallBackFunc )( void )
+   )
+
+   {
+   if ( SS_SoundPlaying )
+      {
+      SS_StopPlayback();
+      }
+
+   SS_SetCallBack( CallBackFunc );
+
+   SS_BufferStart     = BufferStart;
+   SS_CurrentBuffer   = BufferStart;
+   SS_SoundPtr        = BufferStart;
+   SS_TotalBufferSize = BufferSize;
+   SS_BufferEnd       = BufferStart + BufferSize;
+   SS_TransferLength  = BufferSize / NumDivisions;
+   SS_CurrentLength   = SS_TransferLength;
+   SS_BufferNum       = 0;
+   SS_NumBuffers      = NumDivisions;
+
+   SS_SoundPlaying = TRUE;
+
+//   SS_Timer = TS_ScheduleTask( SS_ServiceInterrupt, 438, 1, NULL );
+   SS_Timer = TS_ScheduleTask( SS_ServiceInterrupt, 510, 1, NULL );
+   TS_Dispatch();
+
+   return( SS_Ok );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: SS_GetPlaybackRate
+
+   Returns the rate at which the digitized sound will be played in
+   hertz.
+---------------------------------------------------------------------*/
+
+int SS_GetPlaybackRate
+   (
+   void
+   )
+
+   {
+   return( SS_SampleRate );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: SS_SetMixMode
+
+   Sets the sound card to play samples in mono or stereo.
+---------------------------------------------------------------------*/
+
+int SS_SetMixMode
+   (
+   int mode
+   )
+
+   {
+   mode = MONO_8BIT;
+   return( mode );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: SS_SetPort
+
+   Selects which port to use to write to the Sound Source.
+---------------------------------------------------------------------*/
+
+int SS_SetPort
+   (
+   int port
+   )
+
+   {
+   if ( SS_Installed )
+      {
+      SS_Shutdown();
+      }
+
+   SS_Port = port;
+
+   return( SS_Ok );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: SS_SetCallBack
+
+   Specifies the user function to call at the end of a sound transfer.
+---------------------------------------------------------------------*/
+
+void SS_SetCallBack
+   (
+   void ( *func )( void )
+   )
+
+   {
+   SS_CallBack = func;
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: SS_TestTimer
+
+   Used as a delay in SS_TestSoundSource.
+---------------------------------------------------------------------*/
+
+void SS_TestTimer
+   (
+   task *Task
+   )
+
+   {
+   ( *( int * )( Task->data ) )++;
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: SS_TestSoundSource
+
+   Detect if the Sound Source is located at the specified port.
+---------------------------------------------------------------------*/
+
+int SS_TestSoundSource
+   (
+   int port
+   )
+
+   {
+   int   present;
+   task *timer;
+   volatile int ticks;
+   int   i;
+
+   present = FALSE;
+
+   timer = TS_ScheduleTask( SS_TestTimer, 140, 1, &ticks );
+   TS_Dispatch();
+
+   outp( port + 2, 4 );
+
+   ticks = 0;
+
+   while( ticks < 4 )
+      {
+      // Do nothing for a while
+      }
+
+   TS_Terminate( timer );
+
+   if ( ( inp( port + 1 ) & 0x40 ) == 0 )
+      {
+      for( i = 32; i > 0; i-- )
+         {
+         outp( port, 0x80 );
+         outp( port + 2, SS_OffCommand );
+         outp( port + 2, 4 );
+         }
+
+      if ( inp( port + 1 ) & 0x40 )
+         {
+         present = TRUE;
+         }
+      }
+
+   outp( port + 2, SS_OffCommand );
+
+   return( present );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: SS_DetectSoundSource
+
+   Detects which port the Sound Source is located.
+---------------------------------------------------------------------*/
+
+int SS_DetectSoundSource
+   (
+   void
+   )
+
+   {
+   if ( USER_CheckParameter( SELECT_SOUNDSOURCE_PORT1 ) )
+      {
+      SS_Port = SS_Port1;
+      return( TRUE );
+      }
+
+   if ( USER_CheckParameter( SELECT_SOUNDSOURCE_PORT2 ) )
+      {
+      SS_Port = SS_Port2;
+      return( TRUE );
+      }
+
+   if ( USER_CheckParameter( SELECT_SOUNDSOURCE_PORT3 ) )
+      {
+      SS_Port = SS_Port3;
+      return( TRUE );
+      }
+
+   if ( SS_TestSoundSource( SS_Port1 ) )
+      {
+      SS_Port = SS_Port1;
+      return( TRUE );
+      }
+
+   if ( SS_TestSoundSource( SS_Port2 ) )
+      {
+      SS_Port = SS_Port2;
+      return( TRUE );
+      }
+
+   if ( SS_TestSoundSource( SS_Port3 ) )
+      {
+      SS_Port = SS_Port3;
+      return( TRUE );
+      }
+
+   return( FALSE );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: SS_Init
+
+   Initializes the Sound Source prepares the module to play digitized
+   sounds.
+---------------------------------------------------------------------*/
+
+int SS_Init
+   (
+   int soundcard
+   )
+
+   {
+   int status;
+
+   if ( SS_Installed )
+      {
+      SS_Shutdown();
+      }
+
+   if ( ( soundcard == TandySoundSource ) ||
+      ( USER_CheckParameter( SELECT_TANDY_SOUNDSOURCE ) ) )
+      {
+      // Tandy
+      SS_OffCommand = 0x0e;
+      }
+   else
+      {
+      // Disney
+      SS_OffCommand = 0x0c;
+      }
+
+   status = SS_DetectSoundSource();
+   if ( !status )
+      {
+      SS_SetErrorCode( SS_NotFound );
+      return( SS_Warning );
+      }
+
+   status = SS_LockMemory();
+   if ( status != SS_Ok )
+      {
+      SS_UnlockMemory();
+      return( status );
+      }
+
+   status = SS_Ok;
+
+   outp( SS_Port + 2, 4 );
+
+   SS_SoundPlaying = FALSE;
+
+   SS_SetCallBack( NULL );
+
+   SS_BufferStart = NULL;
+
+   SS_Installed = TRUE;
+
+   SS_SetErrorCode( status );
+   return( status );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: SS_Shutdown
+
+   Ends transfer of sound data to the Sound Source.
+---------------------------------------------------------------------*/
+
+void SS_Shutdown
+   (
+   void
+   )
+
+   {
+   // Halt the transfer
+   SS_StopPlayback();
+
+   outp( SS_Port + 2, SS_OffCommand );
+
+   SS_SoundPlaying = FALSE;
+
+   SS_BufferStart = NULL;
+
+   SS_SetCallBack( NULL );
+
+   SS_UnlockMemory();
+
+   SS_Installed = FALSE;
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: SS_UnlockMemory
+
+   Unlocks all neccessary data.
+---------------------------------------------------------------------*/
+
+void SS_UnlockMemory
+   (
+   void
+   )
+
+   {
+   DPMI_UnlockMemoryRegion( SS_LockStart, SS_LockEnd );
+   DPMI_Unlock( SS_Installed );
+   DPMI_Unlock( SS_Port );
+   DPMI_Unlock( SS_OffCommand );
+   DPMI_Unlock( SS_BufferStart );
+   DPMI_Unlock( SS_BufferEnd );
+   DPMI_Unlock( SS_CurrentBuffer );
+   DPMI_Unlock( SS_BufferNum );
+   DPMI_Unlock( SS_NumBuffers );
+   DPMI_Unlock( SS_TotalBufferSize );
+   DPMI_Unlock( SS_TransferLength );
+   DPMI_Unlock( SS_CurrentLength );
+   DPMI_Unlock( SS_SoundPtr );
+   DPMI_Unlock( SS_SoundPlaying );
+   DPMI_Unlock( SS_Timer );
+   DPMI_Unlock( SS_CallBack );
+   DPMI_Unlock( SS_ErrorCode );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: SS_LockMemory
+
+   Locks all neccessary data.
+---------------------------------------------------------------------*/
+
+int SS_LockMemory
+   (
+   void
+   )
+
+   {
+   int status;
+
+   status  = DPMI_LockMemoryRegion( SS_LockStart, SS_LockEnd );
+   status |= DPMI_Lock( SS_Installed );
+   status |= DPMI_Lock( SS_Port );
+   status |= DPMI_Lock( SS_OffCommand );
+   status |= DPMI_Lock( SS_BufferStart );
+   status |= DPMI_Lock( SS_BufferEnd );
+   status |= DPMI_Lock( SS_CurrentBuffer );
+   status |= DPMI_Lock( SS_BufferNum );
+   status |= DPMI_Lock( SS_NumBuffers );
+   status |= DPMI_Lock( SS_TotalBufferSize );
+   status |= DPMI_Lock( SS_TransferLength );
+   status |= DPMI_Lock( SS_CurrentLength );
+   status |= DPMI_Lock( SS_SoundPtr );
+   status |= DPMI_Lock( SS_SoundPlaying );
+   status |= DPMI_Lock( SS_Timer );
+   status |= DPMI_Lock( SS_CallBack );
+   status |= DPMI_Lock( SS_ErrorCode );
+
+   if ( status != DPMI_Ok )
+      {
+      SS_UnlockMemory();
+      SS_SetErrorCode( SS_DPMI_Error );
+      return( SS_Error );
+      }
+
+   return( SS_Ok );
+   }
--- /dev/null
+++ b/rott/audiolib/sndsrc.h
@@ -1,0 +1,70 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+/**********************************************************************
+   module: SNDSRC.H
+
+   author: James R. Dose
+   date:   March 26, 1994
+
+   Public header for for SNDSRC.C
+
+   (c) Copyright 1994 James R. Dose.  All Rights Reserved.
+**********************************************************************/
+
+#ifndef __SNDSRC_H
+#define __SNDSRC_H
+
+enum SS_ERRORS
+   {
+   SS_Warning = -2,
+   SS_Error   = -1,
+   SS_Ok      = 0,
+   SS_NotFound,
+   SS_NoSoundPlaying,
+   SS_DPMI_Error
+   };
+
+#define SELECT_SOUNDSOURCE_PORT1 "ss1"
+#define SELECT_SOUNDSOURCE_PORT2 "ss2"
+#define SELECT_SOUNDSOURCE_PORT3 "ss3"
+#define SELECT_TANDY_SOUNDSOURCE "sst"
+
+#define SS_Port1 0x3bc
+#define SS_Port2 0x378
+#define SS_Port3 0x278
+
+#define SS_DefaultPort 0x378
+#define SS_SampleRate  7000
+#define SS_DMAChannel  -1
+
+char *SS_ErrorString( int ErrorNumber );
+void  SS_StopPlayback( void );
+int   SS_GetCurrentPos( void );
+int   SS_BeginBufferedPlayback( char *BufferStart, int BufferSize, int NumDivisions, void ( *CallBackFunc )( void ) );
+int   SS_GetPlaybackRate( void );
+int   SS_SetMixMode( int mode );
+int   SS_SetPort( int port );
+void  SS_SetCallBack( void ( *func )( void ) );
+int   SS_Init( int soundcard );
+void  SS_Shutdown( void );
+void  SS_UnlockMemory( void );
+int   SS_LockMemory( void );
+
+#endif
--- /dev/null
+++ b/rott/audiolib/standard.h
@@ -1,0 +1,72 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+/**********************************************************************
+   module: STANDARD.H
+
+   author: James R. Dose
+   date:   May 25, 1994
+
+   Header containing standard definitions.
+
+   (c) Copyright 1994 James R. Dose.  All Rights Reserved.
+**********************************************************************/
+
+#ifndef __STANDARD_H
+#define __STANDARD_H
+
+typedef int boolean;
+typedef int errorcode;
+
+#ifndef TRUE
+   #define TRUE ( 1 == 1 )
+   #define FALSE ( !TRUE )
+#endif
+
+enum STANDARD_ERRORS
+   {
+   Warning = -2,
+   FatalError = -1,
+   Success = 0
+   };
+
+#define BITSET( data, bit ) \
+   ( ( ( data ) & ( bit ) ) == ( bit ) )
+
+#define ARRAY_LENGTH( array ) \
+   ( sizeof( array ) / sizeof( ( array )[ 0 ] ) )
+
+#define WITHIN_BOUNDS( array, index ) \
+   ( ( 0 <= ( index ) ) && ( ( index ) < ARRAY_LENGTH( array ) ) )
+
+#define FOREVER    for( ; ; )
+
+#ifdef NDEBUG
+   #define DEBUGGING 0
+#else
+   #define DEBUGGING 1
+#endif
+
+#define DEBUG_CODE \
+   if ( DEBUGGING == 0 ) \
+      { \
+      } \
+   else
+
+#endif
--- /dev/null
+++ b/rott/audiolib/task_man.c
@@ -1,0 +1,976 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+/**********************************************************************
+   module: TASK_MAN.C
+
+   author: James R. Dose
+   date:   July 25, 1994
+
+   Low level timer task scheduler.
+
+   (c) Copyright 1994 James R. Dose.  All Rights Reserved.
+**********************************************************************/
+
+#define TRUE  ( 1 == 1 )
+#define FALSE ( !TRUE )
+
+//#define USESTACK
+#define LOCKMEMORY
+#define NOINTS
+#define USE_USRHOOKS
+
+#include <stdlib.h>
+#include <dos.h>
+#include <conio.h>
+#include <string.h>
+#include "interrup.h"
+#include "linklist.h"
+#include "task_man.h"
+
+#ifdef USESTACK
+#include "dpmi.h"
+#endif
+#ifdef LOCKMEMORY
+#include "dpmi.h"
+#endif
+
+#ifdef USE_USRHOOKS
+#include "usrhooks.h"
+#define FreeMem( ptr )   USRHOOKS_FreeMem( ( ptr ) )
+#else
+#define FreeMem( ptr )   free( ( ptr ) )
+#endif
+
+typedef struct
+   {
+   task *start;
+   task *end;
+   } tasklist;
+
+
+/*---------------------------------------------------------------------
+   Global variables
+---------------------------------------------------------------------*/
+
+#ifdef USESTACK
+
+// adequate stack size
+#define kStackSize 2048
+
+static unsigned short StackSelector = NULL;
+static unsigned long  StackPointer;
+
+static unsigned short oldStackSelector;
+static unsigned long  oldStackPointer;
+
+#endif
+
+static task HeadTask;
+static task *TaskList = &HeadTask;
+
+static void ( __interrupt __far *OldInt8 )( void );
+
+static volatile long TaskServiceRate  = 0x10000L;
+static volatile long TaskServiceCount = 0;
+
+#ifndef NOINTS
+static volatile int  TS_TimesInInterrupt;
+#endif
+
+static char TS_Installed = FALSE;
+
+volatile int TS_InInterrupt = FALSE;
+
+/*---------------------------------------------------------------------
+   Function prototypes
+---------------------------------------------------------------------*/
+
+static void TS_FreeTaskList( void );
+static void TS_SetClockSpeed( long speed );
+static long TS_SetTimer( long TickBase );
+static void TS_SetTimerToMaxTaskRate( void );
+static void __interrupt __far TS_ServiceSchedule( void );
+static void __interrupt __far TS_ServiceScheduleIntEnabled( void );
+static void TS_AddTask( task *ptr );
+static int  TS_Startup( void );
+static void RestoreRealTimeClock( void );
+
+// These declarations are necessary to use the inline assembly pragmas.
+
+extern void GetStack(unsigned short *selptr,unsigned long *stackptr);
+extern void SetStack(unsigned short selector,unsigned long stackptr);
+
+// This function will get the current stack selector and pointer and save
+// them off.
+#pragma aux GetStack =	\
+	"mov  [edi],esp"		\
+	"mov	ax,ss"	 		\
+	"mov  [esi],ax" 		\
+	parm [esi] [edi]		\
+	modify [eax esi edi];
+
+// This function will set the stack selector and pointer to the specified
+// values.
+#pragma aux SetStack =	\
+	"mov  ss,ax"			\
+	"mov  esp,edx"			\
+	parm [ax] [edx]		\
+	modify [eax edx];
+
+
+/**********************************************************************
+
+   Memory locked functions:
+
+**********************************************************************/
+
+
+#define TS_LockStart TS_FreeTaskList
+
+
+/*---------------------------------------------------------------------
+   Function: TS_FreeTaskList
+
+   Terminates all tasks and releases any memory used for control
+   structures.
+---------------------------------------------------------------------*/
+
+static void TS_FreeTaskList
+   (
+   void
+   )
+
+   {
+   task *node;
+   task *next;
+   unsigned flags;
+
+   flags = DisableInterrupts();
+
+   node = TaskList->next;
+   while( node != TaskList )
+      {
+      next = node->next;
+      FreeMem( node );
+      node = next;
+      }
+
+   TaskList->next = TaskList;
+   TaskList->prev = TaskList;
+
+   RestoreInterrupts( flags );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: TS_SetClockSpeed
+
+   Sets the rate of the 8253 timer.
+---------------------------------------------------------------------*/
+
+static void TS_SetClockSpeed
+   (
+   long speed
+   )
+
+   {
+   unsigned flags;
+
+   flags = DisableInterrupts();
+
+   if ( ( speed > 0 ) && ( speed < 0x10000L ) )
+      {
+      TaskServiceRate = speed;
+      }
+   else
+      {
+      TaskServiceRate = 0x10000L;
+      }
+
+   outp( 0x43, 0x36 );
+   outp( 0x40, TaskServiceRate );
+   outp( 0x40, TaskServiceRate >> 8 );
+
+   RestoreInterrupts( flags );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: TS_SetTimer
+
+   Calculates the rate at which a task will occur and sets the clock
+   speed if necessary.
+---------------------------------------------------------------------*/
+
+static long TS_SetTimer
+   (
+   long TickBase
+   )
+
+   {
+   long speed;
+
+   speed = 1192030L / TickBase;
+   if ( speed < TaskServiceRate )
+      {
+      TS_SetClockSpeed( speed );
+      }
+
+   return( speed );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: TS_SetTimerToMaxTaskRate
+
+   Finds the fastest running task and sets the clock to operate at
+   that speed.
+---------------------------------------------------------------------*/
+
+static void TS_SetTimerToMaxTaskRate
+   (
+   void
+   )
+
+   {
+   task     *ptr;
+   long      MaxServiceRate;
+   unsigned  flags;
+
+   flags = DisableInterrupts();
+
+   MaxServiceRate = 0x10000L;
+
+   ptr = TaskList->next;
+   while( ptr != TaskList )
+      {
+      if ( ptr->rate < MaxServiceRate )
+         {
+         MaxServiceRate = ptr->rate;
+         }
+
+      ptr = ptr->next;
+      }
+
+   if ( TaskServiceRate != MaxServiceRate )
+      {
+      TS_SetClockSpeed( MaxServiceRate );
+      }
+
+   RestoreInterrupts( flags );
+   }
+
+
+#ifdef NOINTS
+/*---------------------------------------------------------------------
+   Function: TS_ServiceSchedule
+
+   Interrupt service routine
+---------------------------------------------------------------------*/
+
+static void __interrupt __far TS_ServiceSchedule
+   (
+   void
+   )
+
+   {
+   task *ptr;
+   task *next;
+
+
+   TS_InInterrupt = TRUE;
+
+   #ifdef USESTACK
+   // save stack
+   GetStack( &oldStackSelector, &oldStackPointer );
+
+   // set our stack
+   SetStack( StackSelector, StackPointer );
+   #endif
+
+   ptr = TaskList->next;
+   while( ptr != TaskList )
+      {
+      next = ptr->next;
+
+      if ( ptr->active )
+         {
+         ptr->count += TaskServiceRate;
+//JIM
+//         if ( ptr->count >= ptr->rate )
+         while( ptr->count >= ptr->rate )
+            {
+            ptr->count -= ptr->rate;
+            ptr->TaskService( ptr );
+            }
+         }
+      ptr = next;
+      }
+
+   #ifdef USESTACK
+   // restore stack
+   SetStack( oldStackSelector, oldStackPointer );
+   #endif
+
+   TaskServiceCount += TaskServiceRate;
+   if ( TaskServiceCount > 0xffffL )
+      {
+      TaskServiceCount &= 0xffff;
+      _chain_intr( OldInt8 );
+      }
+
+   outp( 0x20,0x20 );
+
+   TS_InInterrupt = FALSE;
+   }
+
+#else
+
+/*---------------------------------------------------------------------
+   Function: TS_ServiceScheduleIntEnabled
+
+   Interrupt service routine with interrupts enabled.
+---------------------------------------------------------------------*/
+
+static void __interrupt __far TS_ServiceScheduleIntEnabled
+   (
+   void
+   )
+
+   {
+   task *ptr;
+   task *next;
+
+   TS_TimesInInterrupt++;
+   TaskServiceCount += TaskServiceRate;
+   if ( TaskServiceCount > 0xffffL )
+      {
+      TaskServiceCount &= 0xffff;
+      _chain_intr( OldInt8 );
+      }
+
+   outp( 0x20,0x20 );
+
+   if ( TS_InInterrupt )
+      {
+      return;
+      }
+
+   TS_InInterrupt = TRUE;
+   _enable();
+
+   #ifdef USESTACK
+   // save stack
+   GetStack( &oldStackSelector, &oldStackPointer );
+
+   // set our stack
+   SetStack( StackSelector, StackPointer );
+   #endif
+
+   while( TS_TimesInInterrupt )
+      {
+      ptr = TaskList->next ;
+      while( ptr != TaskList )
+         {
+         next = ptr->next;
+
+         if ( ptr->active )
+            {
+            ptr->count += TaskServiceRate;
+            if ( ptr->count >= ptr->rate )
+               {
+               ptr->count -= ptr->rate;
+               ptr->TaskService( ptr );
+               }
+            }
+         ptr = next;
+         }
+      TS_TimesInInterrupt--;
+      }
+
+   _disable();
+
+   #ifdef USESTACK
+   // restore stack
+   SetStack( oldStackSelector, oldStackPointer );
+   #endif
+
+   TS_InInterrupt = FALSE;
+   }
+#endif
+
+
+#ifdef USESTACK
+
+/*---------------------------------------------------------------------
+   Function: allocateTimerStack
+
+   Allocate a block of memory from conventional (low) memory and return
+   the selector (which can go directly into a segment register) of the
+   memory block or 0 if an error occured.
+---------------------------------------------------------------------*/
+
+static unsigned short allocateTimerStack
+   (
+   unsigned short size
+   )
+
+   {
+   union REGS regs;
+
+   // clear all registers
+   memset( &regs, 0, sizeof( regs ) );
+
+   // DPMI allocate conventional memory
+   regs.w.ax = 0x100;
+
+   // size in paragraphs
+   regs.w.bx = ( size + 15 ) / 16;
+
+   int386( 0x31, &regs, &regs );
+   if (!regs.w.cflag)
+      {
+      // DPMI call returns selector in dx
+      // (ax contains real mode segment
+      // which is ignored here)
+
+      return( regs.w.dx );
+      }
+
+   // Couldn't allocate memory.
+   return( NULL );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: deallocateTimerStack
+
+   Deallocate a block of conventional (low) memory given a selector to
+   it.  Assumes the block was allocated with DPMI function 0x100.
+---------------------------------------------------------------------*/
+
+static void deallocateTimerStack
+   (
+   unsigned short selector
+   )
+
+   {
+	union REGS regs;
+
+	if ( selector != NULL )
+      {
+      // clear all registers
+      memset( &regs, 0, sizeof( regs ) );
+
+      regs.w.ax = 0x101;
+      regs.w.dx = selector;
+      int386( 0x31, &regs, &regs );
+      }
+   }
+
+#endif
+
+/*---------------------------------------------------------------------
+   Function: TS_Startup
+
+   Sets up the task service routine.
+---------------------------------------------------------------------*/
+
+static int TS_Startup
+   (
+   void
+   )
+
+   {
+   if ( !TS_Installed )
+      {
+#ifdef LOCKMEMORY
+
+      int status;
+
+      status = TS_LockMemory();
+      if ( status != TASK_Ok )
+         {
+         TS_UnlockMemory();
+         return( status );
+         }
+
+#endif
+
+#ifdef USESTACK
+
+	   StackSelector = allocateTimerStack( kStackSize );
+      if ( StackSelector == NULL )
+         {
+
+#ifdef LOCKMEMORY
+
+         TS_UnlockMemory();
+
+#endif
+         return( TASK_Error );
+         }
+
+      // Leave a little room at top of stack just for the hell of it...
+      StackPointer = kStackSize - sizeof( long );
+
+#endif
+
+//static const task *TaskList = &HeadTask;
+      TaskList->next = TaskList;
+      TaskList->prev = TaskList;
+
+      TaskServiceRate  = 0x10000L;
+      TaskServiceCount = 0;
+
+#ifndef NOINTS
+      TS_TimesInInterrupt = 0;
+#endif
+
+      OldInt8 = _dos_getvect( 0x08 );
+      #ifdef NOINTS
+         _dos_setvect( 0x08, TS_ServiceSchedule );
+      #else
+         _dos_setvect( 0x08, TS_ServiceScheduleIntEnabled );
+      #endif
+
+      TS_Installed = TRUE;
+      }
+
+   return( TASK_Ok );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: TS_Shutdown
+
+   Ends processing of all tasks.
+---------------------------------------------------------------------*/
+
+void TS_Shutdown
+   (
+   void
+   )
+
+   {
+   if ( TS_Installed )
+      {
+      TS_FreeTaskList();
+
+      TS_SetClockSpeed( 0 );
+
+      _dos_setvect( 0x08, OldInt8 );
+
+#ifdef USESTACK
+
+      deallocateTimerStack( StackSelector );
+      StackSelector = NULL;
+
+#endif
+
+      // Set Date and Time from CMOS
+//      RestoreRealTimeClock();
+
+#ifdef LOCKMEMORY
+
+      TS_UnlockMemory();
+
+#endif
+      TS_Installed = FALSE;
+      }
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: TS_ScheduleTask
+
+   Schedules a new task for processing.
+---------------------------------------------------------------------*/
+
+task *TS_ScheduleTask
+   (
+   void  ( *Function )( task * ),
+   int   rate,
+   int   priority,
+   void *data
+   )
+
+   {
+   task *ptr;
+
+#ifdef USE_USRHOOKS
+   int   status;
+
+   ptr = NULL;
+
+   status = USRHOOKS_GetMem( &ptr, sizeof( task ) );
+   if ( status == USRHOOKS_Ok )
+#else
+   ptr = malloc( sizeof( task ) );
+   if ( ptr != NULL )
+#endif
+      {
+      if ( !TS_Installed )
+         {
+         status = TS_Startup();
+         if ( status != TASK_Ok )
+            {
+            FreeMem( ptr );
+            return( NULL );
+            }
+         }
+
+      ptr->TaskService = Function;
+      ptr->data = data;
+      ptr->rate = TS_SetTimer( rate );
+      ptr->count = 0;
+      ptr->priority = priority;
+      ptr->active = FALSE;
+
+      TS_AddTask( ptr );
+      }
+
+   return( ptr );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: TS_AddTask
+
+   Adds a new task to our list of tasks.
+---------------------------------------------------------------------*/
+
+static void TS_AddTask
+   (
+   task *node
+   )
+
+   {
+   LL_SortedInsertion( TaskList, node, next, prev, task, priority );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: TS_Terminate
+
+   Ends processing of a specific task.
+---------------------------------------------------------------------*/
+
+int TS_Terminate
+   (
+   task *NodeToRemove
+   )
+
+   {
+   task *ptr;
+   task *next;
+   unsigned flags;
+
+   flags = DisableInterrupts();
+
+   ptr = TaskList->next;
+   while( ptr != TaskList )
+      {
+      next = ptr->next;
+
+      if ( ptr == NodeToRemove )
+         {
+         LL_RemoveNode( NodeToRemove, next, prev );
+         NodeToRemove->next = NULL;
+         NodeToRemove->prev = NULL;
+         FreeMem( NodeToRemove );
+
+         TS_SetTimerToMaxTaskRate();
+
+         RestoreInterrupts( flags );
+
+         return( TASK_Ok );
+         }
+
+      ptr = next;
+      }
+
+   RestoreInterrupts( flags );
+
+   return( TASK_Warning );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: TS_Dispatch
+
+   Begins processing of all inactive tasks.
+---------------------------------------------------------------------*/
+
+void TS_Dispatch
+   (
+   void
+   )
+
+   {
+   task *ptr;
+   unsigned flags;
+
+   flags = DisableInterrupts();
+
+   ptr = TaskList->next;
+   while( ptr != TaskList )
+      {
+      ptr->active = TRUE;
+      ptr = ptr->next;
+      }
+
+   RestoreInterrupts( flags );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: TS_SetTaskRate
+
+   Sets the rate at which the specified task is serviced.
+---------------------------------------------------------------------*/
+
+void TS_SetTaskRate
+   (
+   task *Task,
+   int rate
+   )
+
+   {
+   unsigned flags;
+
+   flags = DisableInterrupts();
+
+   Task->rate = TS_SetTimer( rate );
+   TS_SetTimerToMaxTaskRate();
+
+   RestoreInterrupts( flags );
+   }
+
+
+#ifdef LOCKMEMORY
+
+/*---------------------------------------------------------------------
+   Function: TS_LockEnd
+
+   Used for determining the length of the functions to lock in memory.
+---------------------------------------------------------------------*/
+
+static void TS_LockEnd
+   (
+   void
+   )
+
+   {
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: TS_UnlockMemory
+
+   Unlocks all neccessary data.
+---------------------------------------------------------------------*/
+
+void TS_UnlockMemory
+   (
+   void
+   )
+
+   {
+   DPMI_UnlockMemoryRegion( TS_LockStart, TS_LockEnd );
+   DPMI_Unlock( TaskList );
+   DPMI_Unlock( OldInt8 );
+   DPMI_Unlock( TaskServiceRate );
+   DPMI_Unlock( TaskServiceCount );
+   DPMI_Unlock( TS_Installed );
+
+#ifndef NOINTS
+   DPMI_Unlock( TS_TimesInInterrupt );
+#endif
+
+#ifdef USESTACK
+   DPMI_Unlock( StackSelector );
+   DPMI_Unlock( StackPointer );
+   DPMI_Unlock( oldStackSelector );
+   DPMI_Unlock( oldStackPointer );
+#endif
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: TS_LockMemory
+
+   Locks all neccessary data.
+---------------------------------------------------------------------*/
+
+int TS_LockMemory
+   (
+   void
+   )
+
+   {
+   int status;
+
+   status  = DPMI_LockMemoryRegion( TS_LockStart, TS_LockEnd );
+   status |= DPMI_Lock( TaskList );
+   status |= DPMI_Lock( OldInt8 );
+   status |= DPMI_Lock( TaskServiceRate );
+   status |= DPMI_Lock( TaskServiceCount );
+   status |= DPMI_Lock( TS_Installed );
+
+#ifndef NOINTS
+   status |= DPMI_Lock( TS_TimesInInterrupt );
+#endif
+
+#ifdef USESTACK
+   status |= DPMI_Lock( StackSelector );
+   status |= DPMI_Lock( StackPointer );
+   status |= DPMI_Lock( oldStackSelector );
+   status |= DPMI_Lock( oldStackPointer );
+#endif
+
+   if ( status != DPMI_Ok )
+      {
+      TS_UnlockMemory();
+      return( TASK_Error );
+      }
+
+   return( TASK_Ok );
+   }
+
+#endif
+
+/*
+// Converts a hex byte to an integer
+
+static int btoi
+   (
+   unsigned char bcd
+   )
+
+   {
+   unsigned b;
+   unsigned c;
+   unsigned d;
+
+   b = bcd / 16;
+   c = bcd - b * 16;
+   d = b * 10 + c;
+   return( d );
+   }
+
+
+static void RestoreRealTimeClock
+   (
+   void
+   )
+
+   {
+   int read;
+   int i;
+   int hr;
+   int min;
+   int sec;
+   int cent;
+   int yr;
+   int mo;
+   int day;
+   int year;
+   union REGS inregs;
+
+   // Read Real Time Clock Time.
+   read = FALSE;
+	inregs.h.ah = 0x02;
+   for( i = 1; i <= 3; i++ )
+      {
+      int386( 0x1A, &inregs, &inregs );
+      if ( inregs.x.cflag == 0 )
+         {
+         read = TRUE;
+         }
+      }
+
+   if ( read )
+      {
+      //and convert BCD to integer format
+      hr  = btoi( inregs.h.ch );
+      min = btoi( inregs.h.cl );
+      sec = btoi( inregs.h.dh );
+
+      // Read Real Time Clock Date.
+      inregs.h.ah = 0x04;
+      int386( 0x1A, &inregs, &inregs );
+      if ( inregs.x.cflag == 0 )
+         {
+         //and convert BCD to integer format
+         cent = btoi( inregs.h.ch );
+         yr   = btoi( inregs.h.cl );
+         mo   = btoi( inregs.h.dh );
+         day  = btoi( inregs.h.dl );
+         year = cent * 100 + yr;
+
+         // Set System Time.
+         inregs.h.ch = hr;
+         inregs.h.cl = min;
+         inregs.h.dh = sec;
+         inregs.h.dl = 0;
+         inregs.h.ah = 0x2D;
+         int386( 0x21, &inregs, &inregs );
+
+         // Set System Date.
+         inregs.w.cx = year;
+         inregs.h.dh = mo;
+         inregs.h.dl = day;
+         inregs.h.ah = 0x2B;
+         int386( 0x21, &inregs, &inregs );
+         }
+      }
+   }
+*/
+/*
+   struct dostime_t time;
+   struct dosdate_t date;
+
+   outp(0x70,0);
+   time.second=inp(0x71);
+   outp(0x70,2);
+   time.minute=inp(0x71);
+   outp(0x70,4);
+   time.hour=inp(0x71);
+
+   outp(0x70,7);
+   date.day=inp(0x71);
+   outp(0x70,8);
+   date.month=inp(0x71);
+   outp(0x70,9);
+   date.year=inp(0x71);
+
+   time.second=(time.second&0x0f)+((time.second>>4)*10);
+   time.minute=(time.minute&0x0f)+((time.minute>>4)*10);
+   time.hour=(time.hour&0x0f)+((time.hour>>4)*10);
+
+   date.day=(date.day&0x0f)+((date.day>>4)*10);
+   date.month=(date.month&0x0f)+((date.month>>4)*10);
+   date.year=(date.year&0x0f)+((date.year>>4)*10);
+
+   _dos_settime(&time);
+   _dos_setdate(&date);
+
+*/
--- /dev/null
+++ b/rott/audiolib/task_man.h
@@ -1,0 +1,68 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+/**********************************************************************
+   module: TASK_MAN.C
+
+   author: James R. Dose
+   date:   July 25, 1994
+
+   Public header for TASK_MAN.C, a low level timer task scheduler.
+
+   (c) Copyright 1994 James R. Dose.  All Rights Reserved.
+**********************************************************************/
+
+#ifndef __TASK_MAN_H
+#define __TASK_MAN_H
+
+enum TASK_ERRORS
+   {
+   TASK_Warning = -2,
+   TASK_Error = -1,
+   TASK_Ok = 0
+   };
+
+typedef struct task
+{
+    struct   task *next;
+    struct   task *prev;
+    void          ( *TaskService )( struct task * );
+    void          *data;
+    long          rate;
+    volatile long count;
+    int           priority;
+    int           active;
+} task;
+
+// TS_InInterrupt is TRUE during a taskman interrupt.
+// Use this if you have code that may be used both outside
+// and within interrupts.
+
+extern volatile int TS_InInterrupt;
+
+void    TS_Shutdown( void );
+task    *TS_ScheduleTask( void ( *Function )( task * ), int rate,
+                          int priority, void *data );
+int     TS_Terminate( task *ptr );
+void    TS_Dispatch( void );
+void    TS_SetTaskRate( task *Task, int rate );
+void    TS_UnlockMemory( void );
+int     TS_LockMemory( void );
+
+#endif
--- /dev/null
+++ b/rott/audiolib/user.c
@@ -1,0 +1,133 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+/**********************************************************************
+   module: USER.C
+
+   author: James R. Dose
+   date:   April 26, 1994
+
+   Routines to parse command line options.
+
+   (c) Copyright 1994 James R. Dose.  All Rights Reserved.
+**********************************************************************/
+
+#ifdef PLAT_DOS
+#include <dos.h>
+#endif
+
+#include <string.h>
+#include "user.h"
+
+#define TRUE  ( 1 == 1 )
+#define FALSE ( !TRUE )
+
+#ifdef PLAT_DOS
+extern int   _argc;
+extern char **_argv;
+#endif
+
+/*---------------------------------------------------------------------
+   Function: USER_CheckParameter
+
+   Checks if the specified string is present in the command line.
+---------------------------------------------------------------------*/
+
+int USER_CheckParameter
+   (
+   const char *parameter
+   )
+
+   {
+#ifdef PLAT_DOS
+   int i;
+   int found;
+   char *ptr;
+
+   found = FALSE;
+   i = 1;
+   while( i < _argc )
+      {
+      ptr = _argv[ i ];
+
+      // Only check parameters preceded by - or /
+      if ( ( *ptr == '-' ) || ( *ptr == '/' ) )
+         {
+         ptr++;
+         if ( stricmp( parameter, ptr ) == 0 )
+            {
+            found = TRUE;
+            break;
+            }
+         }
+
+      i++;
+      }
+
+   return( found );
+#else
+   return FALSE;
+#endif
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: USER_GetText
+
+   Checks if the specified string is present in the command line
+   and returns a pointer to the text following it.
+---------------------------------------------------------------------*/
+
+char *USER_GetText
+   (
+   const char *parameter
+   )
+
+   {
+#ifdef PLAT_DOS
+   int i;
+   char *text;
+   char *ptr;
+
+   text = NULL;
+   i = 1;
+   while( i < _argc )
+      {
+      ptr = _argv[ i ];
+
+      // Only check parameters preceded by - or /
+      if ( ( *ptr == '-' ) || ( *ptr == '/' ) )
+         {
+         ptr++;
+         if ( stricmp( parameter, ptr ) == 0 )
+            {
+            i++;
+            text = _argv[ i ];
+            break;
+            }
+         }
+
+      i++;
+      }
+
+   return( text );
+#else
+   return NULL;
+#endif
+   }
--- /dev/null
+++ b/rott/audiolib/user.h
@@ -1,0 +1,38 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+/**********************************************************************
+   module: USER.H
+
+   author: James R. Dose
+   phone:  (214)-271-1365 Ext #221
+   date:   April 26, 1994
+
+   Public header for USER.C
+
+   (c) Copyright 1994 James R. Dose.  All Rights Reserved.
+**********************************************************************/
+
+#ifndef __USER_H
+#define __USER_H
+
+int   USER_CheckParameter( const char *parameter );
+char *USER_GetText( const char *parameter );
+
+#endif
--- /dev/null
+++ b/rott/audiolib/usrhooks.c
@@ -1,0 +1,84 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+/**********************************************************************
+   module: USRHOOKS.C
+
+   author: James R. Dose
+   date:   July 26, 1994
+
+   This module contains cover functions for operations the library
+   needs that may be restricted by the calling program.  This code
+   is left public for you to modify.
+**********************************************************************/
+
+#include <stdlib.h>
+#include "usrhooks.h"
+
+
+/*---------------------------------------------------------------------
+   Function: USRHOOKS_GetMem
+
+   Allocates the requested amount of memory and returns a pointer to
+   its location, or NULL if an error occurs.  NOTE: pointer is assumed
+   to be dword aligned.
+---------------------------------------------------------------------*/
+
+int USRHOOKS_GetMem
+   (
+   void **ptr,
+   unsigned long size
+   )
+
+   {
+   void *memory;
+
+   memory = malloc( size );
+   if ( memory == NULL )
+      {
+      return( USRHOOKS_Error );
+      }
+
+   *ptr = memory;
+
+   return( USRHOOKS_Ok );
+   }
+
+
+/*---------------------------------------------------------------------
+   Function: USRHOOKS_FreeMem
+
+   Deallocates the memory associated with the specified pointer.
+---------------------------------------------------------------------*/
+
+int USRHOOKS_FreeMem
+   (
+   void *ptr
+   )
+
+   {
+   if ( ptr == NULL )
+      {
+      return( USRHOOKS_Error );
+      }
+
+   free( ptr );
+
+   return( USRHOOKS_Ok );
+   }
--- /dev/null
+++ b/rott/audiolib/usrhooks.h
@@ -1,0 +1,55 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+/**********************************************************************
+   module: USRHOOKS.H
+
+   author: James R. Dose
+   date:   July 26, 1994
+
+   Public header file for USRHOOKS.C.
+
+   This module contains cover functions for operations the library
+   needs that may be restricted by the calling program.  The function
+   prototypes in this header should not be modified.
+**********************************************************************/
+
+#ifndef __USRHOOKS_H
+#define __USRHOOKS_H
+
+/*---------------------------------------------------------------------
+   Error definitions
+---------------------------------------------------------------------*/
+
+enum USRHOOKS_Errors
+   {
+   USRHOOKS_Warning = -2,
+   USRHOOKS_Error   = -1,
+   USRHOOKS_Ok      = 0
+   };
+
+
+/*---------------------------------------------------------------------
+   Function Prototypes
+---------------------------------------------------------------------*/
+
+int USRHOOKS_GetMem( void **ptr, unsigned long size );
+int USRHOOKS_FreeMem( void *ptr );
+
+#endif
--- /dev/null
+++ b/rott/audiolib/util.h
@@ -1,0 +1,13 @@
+#ifndef AUDIOLIB__UTIL_H
+#define AUDIOLIB__UTIL_H
+
+#ifndef min
+#define min(a, b)  ((a) < (b) ? (a) : (b))
+#endif
+
+#ifndef max
+#define max(a, b)  ((a) > (b) ? (a) : (b))
+#endif
+
+#endif
+
--- /dev/null
+++ b/rott/byteordr.c
@@ -1,0 +1,84 @@
+/*
+Copyright (C) 2002 John R. Hall
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+//***************************************************************************
+//
+//    byteordr.c - Byte order conversion routines.
+//
+//***************************************************************************
+
+#include "rt_def.h"
+#include "rt_util.h"
+#include "byteordr.h"
+#include "lumpy.h"
+
+#define DEFINE_CONVERTER(type)            \
+void Cvt_##type(void *lmp, int num)       \
+{                                         \
+    int i;                                \
+    type *recs = (type *)lmp;             \
+    for (i = 0; i < num; i++, recs++) {   \
+        CONVERT_ENDIAN_##type(recs);      \
+    }                                     \
+}
+
+DEFINE_CONVERTER(pic_t);
+DEFINE_CONVERTER(lpic_t);
+DEFINE_CONVERTER(font_t);
+DEFINE_CONVERTER(lbm_t);
+DEFINE_CONVERTER(patch_t);
+DEFINE_CONVERTER(transpatch_t);
+DEFINE_CONVERTER(cfont_t);
+
+
+void CvtNull(void *lmp, int num)
+{
+    Debug("No-op endian converter on %p.\n", lmp);
+}
+
+// Returns converter for the designated type
+converter_t CvtForType(int type)
+{
+    switch(type) {
+    case cache_pic_t:
+        return Cvt_pic_t;
+        break;
+    case cache_lpic_t:
+        return Cvt_lpic_t;
+        break;
+    case cache_font_t:
+        return Cvt_font_t;
+        break;
+    case cache_lbm_t:
+        return Cvt_lbm_t;
+        break;
+    case cache_patch_t:
+        return Cvt_patch_t;
+        break;
+    case cache_transpatch_t:
+        return Cvt_transpatch_t;
+        break;
+    case cache_cfont_t:
+        return Cvt_cfont_t;
+        break;
+    default:
+        return CvtNull;
+        break;
+    }
+}
--- /dev/null
+++ b/rott/byteordr.h
@@ -1,0 +1,43 @@
+/*
+Copyright (C) 2002 John R. Hall
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+//***************************************************************************
+//
+//    byteordr.c - Byte order conversion routines.
+//
+//***************************************************************************
+
+#ifndef BYTEORDER_H
+#define BYTEORDER_H
+
+typedef void (*converter_t)(void *, int);
+
+#define DECLARE_CONVERTER(type) void Cvt_##type(void *lmp, int num);
+
+DECLARE_CONVERTER(pic_t);
+DECLARE_CONVERTER(lpic_t);
+DECLARE_CONVERTER(font_t);
+DECLARE_CONVERTER(lbm_t);
+DECLARE_CONVERTER(patch_t);
+DECLARE_CONVERTER(transpatch_t);
+DECLARE_CONVERTER(cfont_t);
+void CvtNull(void *lmp, int num);
+converter_t CvtForType(int type);
+
+#endif
--- /dev/null
+++ b/rott/cin_actr.c
@@ -1,0 +1,305 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+
+#include "cin_glob.h"
+#include "cin_def.h"
+#include "cin_actr.h"
+#include "cin_efct.h"
+#include "modexlib.h"
+//MED
+#include "memcheck.h"
+
+actortype * firstcinematicactor;
+actortype * lastcinematicactor;
+
+
+// LOCALS
+
+boolean cinematicactorsystemstarted=false;
+static int numcinematicactors;
+
+/*
+===============
+=
+= AddCinematicActor
+=
+===============
+*/
+
+void AddCinematicActor ( actortype * actor )
+{
+    if (!firstcinematicactor)
+    {
+        firstcinematicactor  = actor;
+    }
+    else
+    {
+        actor->prev = lastcinematicactor;
+        lastcinematicactor->next = actor;
+    }
+    lastcinematicactor = actor;
+}
+
+
+/*
+===============
+=
+= DeleteCinematicActor
+=
+===============
+*/
+
+void DeleteCinematicActor ( actortype * actor)
+{
+    if (actor == lastcinematicactor)
+    {
+        lastcinematicactor = actor->prev;
+    }
+    else
+    {
+        actor->next->prev = actor->prev;
+    }
+
+    if (actor == firstcinematicactor)
+    {
+        firstcinematicactor = actor->next;
+    }
+    else
+    {
+        actor->prev->next = actor->next;
+    }
+
+    actor->prev = NULL;
+    actor->next = NULL;
+
+    if (actor->effect != NULL)
+        SafeFree(actor->effect);
+    SafeFree(actor);
+}
+
+/*
+===============
+=
+= GetNewCinematicActor
+=
+===============
+*/
+
+actortype * GetNewCinematicActor ( void )
+{
+    actortype * actor;
+
+    numcinematicactors++;
+
+    if ( numcinematicactors > MAXCINEMATICACTORS )
+        Error ("Too many Cinematic actors\n");
+
+    actor = SafeMalloc( sizeof (actortype) );
+
+    actor->next=NULL;
+    actor->prev=NULL;
+
+    AddCinematicActor ( actor );
+
+    return actor;
+}
+
+/*
+===============
+=
+= StartupCinematicActors
+=
+===============
+*/
+
+void StartupCinematicActors ( void )
+{
+    if (cinematicactorsystemstarted==true)
+        return;
+    cinematicactorsystemstarted=true;
+    firstcinematicactor = NULL;
+    lastcinematicactor  = NULL;
+
+    numcinematicactors=0;
+}
+
+/*
+===============
+=
+= ShutdownCinematicActors
+=
+===============
+*/
+
+void ShutdownCinematicActors ( void )
+{
+    actortype * actor;
+    if (cinematicactorsystemstarted==false)
+        return;
+    cinematicactorsystemstarted=false;
+
+    actor=firstcinematicactor;
+    while (actor != NULL)
+    {
+        actortype * nextactor;
+
+        nextactor=actor->next;
+        DeleteCinematicActor(actor);
+        actor=nextactor;
+    }
+}
+
+/*
+===============
+=
+= SpawnCinematicActor
+=
+===============
+*/
+
+void SpawnCinematicActor ( enum_eventtype type, void * effect )
+{
+    actortype * actor;
+
+    actor = GetNewCinematicActor ();
+    actor->effecttype=type;
+    actor->effect=effect;
+}
+
+/*
+===============
+=
+= UpdateCinematicActors
+=
+===============
+*/
+void UpdateCinematicActors ( void )
+{
+    actortype * actor;
+
+    for (actor=firstcinematicactor; actor != NULL;)
+    {
+        if (UpdateCinematicEffect ( actor->effecttype, actor->effect ) == false)
+        {
+            actortype * nextactor;
+
+            nextactor=actor->next;
+            DeleteCinematicActor(actor);
+            actor=nextactor;
+        }
+        else
+            actor=actor->next;
+    }
+}
+
+/*
+===============
+=
+= DrawCinematicActors
+=
+===============
+*/
+typedef enum {
+    screenfunctions,
+    background,
+    backgroundsprites,
+    backdrop,
+    foregroundsprites,
+    palettefunctions,
+    numdrawphases
+} enum_drawphases;
+
+void DrawCinematicActors ( void )
+{
+    actortype * actor;
+    actortype * nextactor;
+    boolean draw;
+    enum_drawphases sequence;
+#if DUMP
+    int numactors=0;
+#endif
+    boolean flippage=true;
+
+    for (sequence=screenfunctions; sequence<numdrawphases; sequence++)
+    {
+        for (actor=firstcinematicactor; actor != NULL;)
+        {
+            draw=false;
+            switch (actor->effecttype)
+            {
+            case fadeout:
+            case blankscreen:
+            case clearbuffer:
+            case cinematicend:
+            case flic:
+                if (sequence==screenfunctions)
+                    draw=true;
+                flippage=false;
+                break;
+            case palette:
+                if (sequence==palettefunctions)
+                    draw=true;
+                flippage=false;
+                break;
+            case background_noscrolling:
+            case background_scrolling:
+            case background_multi:
+                if (sequence==background)
+                    draw=true;
+                break;
+            case sprite_background:
+                if (sequence==backgroundsprites)
+                    draw=true;
+                break;
+            case backdrop_noscrolling:
+            case backdrop_scrolling:
+                if (sequence==backdrop)
+                    draw=true;
+                break;
+            case sprite_foreground:
+                if (sequence==foregroundsprites)
+                    draw=true;
+                break;
+            }
+            nextactor=actor->next;
+            if (draw==true)
+            {
+#if DUMP
+                printf("drawing type=%ld\n",actor->effecttype);
+#endif
+                if (DrawCinematicEffect ( actor->effecttype, actor->effect ) == false)
+                {
+                    DeleteCinematicActor(actor);
+                }
+#if DUMP
+                numactors++;
+#endif
+            }
+            actor=nextactor;
+        }
+    }
+    if (flippage==true)
+        XFlipPage ();
+#if DUMP
+    printf("Total actors drawn=%ld\n",numactors);
+#endif
+}
+
+
--- /dev/null
+++ b/rott/cin_actr.h
@@ -1,0 +1,40 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+#ifndef _cin_actr_public
+#define _cin_actr_public
+
+#include "cin_glob.h"
+#include "cin_def.h"
+
+extern actortype * firstcinematicactor;
+extern actortype * lastcinematicactor;
+
+void AddCinematicActor ( actortype * actor );
+void DeleteCinematicActor ( actortype * actor);
+
+actortype * GetNewCinematicActor ( void );
+void StartupCinematicActors ( void );
+void ShutdownCinematicActors ( void );
+void SpawnCinematicActor ( enum_eventtype type, void * effect );
+void DrawCinematicActors ( void );
+void UpdateCinematicActors ( void );
+
+#endif
+
--- /dev/null
+++ b/rott/cin_def.h
@@ -1,0 +1,104 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+#ifndef _cin_def_public
+#define _cin_def_public
+
+#define MAXCINEMATICEVENTS 100
+#define MAXCINEMATICACTORS 30
+
+#define FRACTIONBITS (16)
+#define FRACTIONUNIT (1<<FRACTIONBITS)
+
+typedef enum {
+    background_noscrolling,
+    background_scrolling,
+    background_multi,
+    sprite_background,
+    sprite_foreground,
+    backdrop_scrolling,
+    backdrop_noscrolling,
+    palette,
+    flic,
+    fadeout,
+    cinematicend,
+    blankscreen,
+    clearbuffer
+} enum_eventtype;
+
+typedef struct eventtype
+{
+    int time;
+    enum_eventtype effecttype;
+    void * effect;
+    struct eventtype * next;
+    struct eventtype * prev;
+} eventtype;
+
+typedef struct actortype
+{
+    enum_eventtype effecttype;
+    void * effect;
+    struct actortype * next;
+    struct actortype * prev;
+} actortype;
+
+typedef struct
+{
+    char name[10];
+    boolean loop;
+    boolean usefile;
+} flicevent;
+
+typedef struct
+{
+    char name[10];
+    int duration;
+    int frame;
+    int frametime;
+    int numframes;
+    int framedelay;
+    int x;
+    int y;
+    int scale;
+    int dx;
+    int dy;
+    int dscale;
+} spriteevent;
+
+typedef struct
+{
+    char name[10];
+    int duration;
+    int backdropwidth;
+    int currentoffset;
+    int dx;
+    int yoffset;
+    int height;
+    byte * data;
+} backevent;
+
+typedef struct
+{
+    char name[10];
+} paletteevent;
+
+
+#endif
+
--- /dev/null
+++ b/rott/cin_efct.c
@@ -1,0 +1,957 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+
+#include "cin_glob.h"
+#include "cin_util.h"
+#include "cin_def.h"
+#include "cin_main.h"
+#include "f_scale.h"
+#include "watcom.h"
+#include "lumpy.h"
+#include "w_wad.h"
+#include "z_zone.h"
+#include <string.h>
+
+#ifdef DOS
+#include <conio.h>
+#endif
+
+#include "modexlib.h"
+#include "fli_glob.h"
+//MED
+#include "memcheck.h"
+
+static int cin_sprtopoffset;
+static int cin_invscale;
+
+void DrawFadeout ( void );
+void DrawBlankScreen ( void );
+void DrawClearBuffer ( void );
+
+/*
+===============
+=
+= SpawnCinematicFlic
+=
+===============
+*/
+
+flicevent * SpawnCinematicFlic ( char * name, boolean loop, boolean usefile )
+{
+    flicevent * flic;
+
+    flic = SafeMalloc ( sizeof(flicevent) );
+
+    // copy name of flic
+
+    strcpy ( flic->name, name );
+
+    flic->loop=loop;
+
+    flic->usefile=usefile;
+
+    return flic;
+}
+
+/*
+===============
+=
+= SpawnCinematicSprite
+=
+===============
+*/
+
+spriteevent * SpawnCinematicSprite ( char * name,
+                                     int duration,
+                                     int numframes,
+                                     int framedelay,
+                                     int x,
+                                     int y,
+                                     int scale,
+                                     int endx,
+                                     int endy,
+                                     int endscale
+                                   )
+{
+    spriteevent * sprite;
+    patch_t *p;
+
+    sprite = SafeMalloc ( sizeof (spriteevent) );
+
+    // copy name of sprite
+
+    strcpy ( sprite->name, name );
+
+    // copy rest of sprite information
+
+    sprite->duration = duration;
+    sprite->numframes = numframes;
+    sprite->framedelay = framedelay;
+    sprite->frame=0;
+    sprite->frametime=framedelay;
+
+    p=(patch_t *)W_CacheLumpNum( W_GetNumForName(sprite->name), PU_CACHE, Cvt_patch_t, 1);
+
+    sprite->x=x << FRACTIONBITS;
+    sprite->y=y << FRACTIONBITS;
+
+//   sprite->y+=(p->width-p->height)<<(FRACTIONBITS-1);
+
+    sprite->scale=scale << FRACTIONBITS;
+    sprite->dx= ( (endx-x) << FRACTIONBITS ) / duration;
+    sprite->dy= ( (endy-y) << FRACTIONBITS ) / duration;
+    sprite->dscale= ( (endscale-scale) << FRACTIONBITS ) / duration;
+
+    return sprite;
+}
+
+/*
+===============
+=
+= SpawnCinematicBack
+=
+===============
+*/
+
+backevent * SpawnCinematicBack ( char * name,
+                                 int duration,
+                                 int width,
+                                 int startx,
+                                 int endx,
+                                 int yoffset
+                               )
+{
+    backevent * back;
+
+    back = SafeMalloc ( sizeof (backevent) );
+
+    // copy name of back
+
+    strcpy ( back->name, name );
+
+    // copy rest of back information
+
+    back->duration = duration;
+    back->backdropwidth = width;
+    back->dx = ((endx-startx) << FRACTIONBITS)/duration;
+    back->currentoffset = startx << FRACTIONBITS;
+    back->yoffset=yoffset;
+
+    return back;
+}
+
+/*
+===============
+=
+= SpawnCinematicMultiBack
+=
+===============
+*/
+
+backevent * SpawnCinematicMultiBack ( char * name,
+                                      char * name2,
+                                      int duration,
+                                      int startx,
+                                      int endx,
+                                      int yoffset
+                                    )
+{
+    backevent * back;
+    lpic_t * pic1;
+    lpic_t * pic2;
+
+    pic1=(lpic_t *)W_CacheLumpName(name,PU_CACHE, Cvt_lpic_t, 1);
+    pic2=(lpic_t *)W_CacheLumpName(name2,PU_CACHE, Cvt_lpic_t, 1);
+
+    back = SafeMalloc ( sizeof (backevent) );
+
+    // copy name of back
+
+    strcpy ( back->name, name );
+
+    // copy rest of back information
+
+    back->duration = duration;
+    back->dx = ((endx-startx) << FRACTIONBITS)/duration;
+    back->currentoffset = startx << FRACTIONBITS;
+    back->yoffset=yoffset;
+    if (pic1->height != pic2->height)
+    {
+        Error("SpawnCinematicMultiBack: heights are not the same\n"
+              "                         name1=%s name2=%s\n",name,name2);
+    }
+    back->backdropwidth=pic1->width+pic2->width;
+    back->height=pic1->height;
+    back->data=SafeMalloc (back->backdropwidth*back->height);
+    memcpy( back->data, &(pic1->data), pic1->width*pic1->height);
+    memcpy( back->data+(pic1->width*pic1->height),
+            &(pic2->data),
+            pic2->width*pic2->height
+          );
+    return back;
+}
+
+/*
+===============
+=
+= SpawnCinematicPalette
+=
+===============
+*/
+
+paletteevent * SpawnCinematicPalette ( char * name )
+{
+    paletteevent * palette;
+
+    palette = SafeMalloc ( sizeof (paletteevent) );
+
+    // copy name of palette
+
+    strcpy ( palette->name, name );
+
+    return palette;
+}
+
+
+/*
+=================
+=
+= ScaleFilmPost
+=
+=================
+*/
+void ScaleFilmPost (byte * src, byte * buf)
+{
+    int  offset;
+    int  length;
+    int  topscreen;
+    int  bottomscreen;
+
+
+    offset=*(src++);
+    for (; offset!=255;)
+    {
+        length=*(src++);
+        topscreen = cin_sprtopoffset + (cin_invscale*offset);
+        bottomscreen = topscreen + (cin_invscale*length);
+        cin_yl = (topscreen+FRACTIONUNIT-1)>>FRACTIONBITS;
+        cin_yh = (bottomscreen-FRACTIONUNIT)>>FRACTIONBITS;
+        if (cin_yh >= iGLOBAL_SCREENHEIGHT)
+            cin_yh = iGLOBAL_SCREENHEIGHT-1;
+        if (cin_yl < 0)
+            cin_yl = 0;
+        if (cin_yl <= cin_yh)
+        {
+            cin_source=src-offset;
+            R_DrawFilmColumn (buf);
+        }
+        src+=length;
+        offset=*(src++);
+    }
+
+}
+
+/*
+=================
+=
+= DrawFlic
+=
+=================
+*/
+void DrawFlic ( flicevent * flic )
+{
+    byte * curpal;
+    byte * buf;
+    char flicname[40];
+
+    curpal = SafeMalloc (768);
+
+    CinematicGetPalette (curpal);
+
+    DrawFadeout ( );
+
+    if (flic->usefile==false)
+    {
+        buf=W_CacheLumpName(flic->name,PU_CACHE, CvtNull, 1);
+        strcpy(flicname,flic->name);
+    }
+    else
+    {
+        strcpy(flicname,flic->name);
+        strcat(flicname,".fli");
+    }
+
+// med
+//   PlayFlic ( flicname, buf, flic->usefile, flic->loop);
+
+    if (flic->loop==true)
+        ClearCinematicAbort();
+
+    DrawFadeout ( );
+
+    DrawBlankScreen ( );
+
+#ifdef DOS
+    VL_SetVGAPlaneMode ();
+#endif
+
+    CinematicSetPalette (curpal);
+
+    SafeFree (curpal);
+    GetCinematicTics ();
+    GetCinematicTics ();
+}
+
+/*
+=================
+=
+= PrecacheFlic
+=
+=================
+*/
+
+void PrecacheFlic (flicevent * flic)
+{
+    if (flic->usefile==false)
+    {
+        W_CacheLumpName(flic->name,PU_CACHE, CvtNull, 1);
+    }
+}
+
+/*
+===============
+=
+= DrawCinematicBackground
+=
+===============
+*/
+
+void DrawCinematicBackground ( backevent * back )
+{
+    byte * src;
+    byte * buf;
+    lpic_t * pic;
+    int i;
+    int plane;
+    int offset;
+    int height;
+
+    pic=(lpic_t *)W_CacheLumpName(back->name,PU_CACHE, Cvt_lpic_t, 1);
+
+    height = pic->height;
+    if (height+back->yoffset>iGLOBAL_SCREENHEIGHT)
+        height=iGLOBAL_SCREENHEIGHT-back->yoffset;
+
+    if (height!=iGLOBAL_SCREENHEIGHT)
+        DrawClearBuffer ();
+
+    plane = 0;
+
+#ifdef DOS
+    for (plane=0; plane<4; plane++)
+#endif
+    {
+        buf=(byte *)bufferofs+ylookup[back->yoffset];
+        offset=(back->currentoffset>>FRACTIONBITS)+plane;
+
+        VGAWRITEMAP(plane);
+
+#ifdef DOS
+        for (i=plane; i<iGLOBAL_SCREENWIDTH; i+=4,offset+=4,buf++)
+#else
+        for (i=0; i<iGLOBAL_SCREENWIDTH; i++,offset++,buf++)
+#endif
+        {
+            if (offset>=back->backdropwidth)
+                src=&(pic->data) + ( (offset - back->backdropwidth) * (pic->height) );
+            else if (offset<0)
+                src=&(pic->data) + ( (offset + back->backdropwidth) * (pic->height) );
+            else
+                src=&(pic->data) + ( offset * (pic->height) );
+            DrawFilmPost(buf,src,height);
+        }
+    }
+}
+
+/*
+===============
+=
+= DrawCinematicMultiBackground
+=
+===============
+*/
+
+void DrawCinematicMultiBackground ( backevent * back )
+{
+    byte * src;
+    byte * buf;
+    int i;
+    int plane;
+    int offset;
+    int height;
+
+    height = back->height;
+    if (height+back->yoffset>iGLOBAL_SCREENHEIGHT)
+        height=iGLOBAL_SCREENHEIGHT-back->yoffset;
+
+    if (height!=iGLOBAL_SCREENHEIGHT)
+        DrawClearBuffer ();
+
+    plane = 0;
+
+#ifdef DOS
+    for (plane=0; plane<4; plane++)
+#endif
+    {
+        buf=(byte *)bufferofs+ylookup[back->yoffset];
+        offset=(back->currentoffset>>FRACTIONBITS)+plane;
+
+        VGAWRITEMAP(plane);
+
+#ifdef DOS
+        for (i=plane; i<iGLOBAL_SCREENWIDTH; i+=4,offset+=4,buf++)
+#else
+        for (i=0; i<iGLOBAL_SCREENWIDTH; i++,offset++,buf++)
+#endif
+        {
+            if (offset>=back->backdropwidth)
+                src=back->data + ( (offset - back->backdropwidth) * (back->height) );
+            else if (offset<0)
+                src=back->data + ( (offset + back->backdropwidth) * (back->height) );
+            else
+                src=back->data + ( offset * (back->height) );
+            DrawFilmPost(buf,src,height);
+        }
+    }
+}
+
+/*
+===============
+=
+= DrawCinematicBackdrop
+=
+===============
+*/
+
+void DrawCinematicBackdrop ( backevent * back )
+{
+    byte * src;
+    byte * shape;
+    byte * buf;
+    patch_t * p;
+    int i;
+    int plane;
+    int offset;
+    int postoffset;
+    int postlength;
+    int toppost;
+
+    shape=W_CacheLumpName(back->name,PU_CACHE, Cvt_patch_t, 1);
+    p=(patch_t *)shape;
+
+    toppost=-p->topoffset+back->yoffset;
+
+    plane = 0;
+
+#ifdef DOS
+    for (plane=0; plane<4; plane++)
+#endif
+    {
+        buf=(byte *)bufferofs;
+        offset=(back->currentoffset>>FRACTIONBITS)+plane;
+
+        VGAWRITEMAP(plane);
+
+#ifdef DOS
+        for (i=plane; i<iGLOBAL_SCREENWIDTH; i+=4,offset+=4,buf++)
+#else
+        for (i=0; i<iGLOBAL_SCREENWIDTH; i++,offset++,buf++)
+#endif
+        {
+            if (offset>=back->backdropwidth)
+                src = shape + p->collumnofs[offset - back->backdropwidth];
+            else if (offset<0)
+                src=shape + p->collumnofs[offset + back->backdropwidth];
+            else
+                src = shape + p->collumnofs[offset];
+
+            postoffset=*(src++);
+            for (; postoffset!=255;)
+            {
+                postlength=*(src++);
+                DrawFilmPost(buf + ylookup[toppost+postoffset],src,postlength);
+                src+=postlength;
+                postoffset=*(src++);
+            }
+        }
+    }
+}
+
+/*
+=================
+=
+= PrecacheBack
+=
+=================
+*/
+void PrecacheBack ( backevent * back )
+{
+    W_CacheLumpName( back->name, PU_CACHE, CvtNull, 1);
+}
+
+
+/*
+=================
+=
+= DrawCinematicSprite
+=
+=================
+*/
+void DrawCinematicSprite ( spriteevent * sprite )
+{
+    byte   *shape;
+    int    frac;
+    patch_t *p;
+    int    x1,x2;
+    int    tx;
+    int    xcent;
+    byte * buf;
+    int    height;
+
+    height = sprite->scale >> FRACTIONBITS;
+
+    if (height<2)
+        return;
+
+    shape=W_CacheLumpNum( W_GetNumForName(sprite->name)+sprite->frame, PU_CACHE, Cvt_patch_t, 1);
+    p=(patch_t *)shape;
+
+
+    cin_ycenter=sprite->y >> FRACTIONBITS;
+    cin_invscale = (height<<FRACTIONBITS)/p->origsize;
+    buf=(byte *)bufferofs;
+    tx=-p->leftoffset;
+    xcent=(sprite->x & 0xffff0000)-(height<<(FRACTIONBITS-1))+(FRACTIONUNIT>>1);
+
+//
+// calculate edges of the shape
+//
+    x1 = (xcent+(tx*cin_invscale))>>FRACTIONBITS;
+    if (x1 >= iGLOBAL_SCREENWIDTH)
+        return;               // off the right side
+    tx+=p->width;
+    x2 = ((xcent+(tx*cin_invscale)) >>FRACTIONBITS) - 1 ;
+    if (x2 < 0)
+        return;         // off the left side
+
+    cin_iscale=(p->origsize<<FRACTIONBITS)/height;
+
+    if (x1<0)
+    {
+        frac=cin_iscale*(-x1);
+        x1=0;
+    }
+    else
+        frac=0;
+    x2 = x2 >= iGLOBAL_SCREENWIDTH ? (iGLOBAL_SCREENWIDTH-1) : x2;
+
+    cin_texturemid = (((p->origsize>>1)+p->topoffset)<<FRACTIONBITS)+(FRACTIONUNIT>>1);
+    cin_sprtopoffset = (cin_ycenter<<16) - FixedMul(cin_texturemid,cin_invscale);
+
+    for (; x1<=x2 ; x1++, frac += cin_iscale)
+    {
+        VGAWRITEMAP(x1&3);
+#ifdef DOS
+        ScaleFilmPost(((p->collumnofs[frac>>FRACTIONBITS])+shape),buf+(x1>>2));
+#else
+        ScaleFilmPost(((p->collumnofs[frac>>FRACTIONBITS])+shape),buf+x1);
+#endif
+    }
+}
+
+/*
+=================
+=
+= PrecacheCinematicSprite
+=
+=================
+*/
+void PrecacheCinematicSprite ( spriteevent * sprite )
+{
+    int i;
+
+    for (i=0; i<sprite->numframes; i++)
+    {
+        W_CacheLumpNum( W_GetNumForName(sprite->name)+i, PU_CACHE, Cvt_patch_t, 1);
+    }
+}
+
+
+/*
+=================
+=
+= DrawPalette
+=
+=================
+*/
+
+void DrawPalette (paletteevent * event)
+{
+    byte * pal;
+
+    pal=W_CacheLumpName(event->name,PU_CACHE, CvtNull, 1);
+    XFlipPage ();
+    CinematicSetPalette (pal);
+}
+
+/*
+=================
+=
+= PrecachePalette
+=
+=================
+*/
+
+void PrecachePalette (paletteevent * event)
+{
+    W_CacheLumpName(event->name,PU_CACHE, CvtNull, 1);
+}
+
+
+/*
+=================
+=
+= DrawFadeout
+=
+=================
+*/
+#define FADEOUTTIME 20
+
+void DrawFadeout ( void )
+{
+    byte origpal[768];
+    byte newpal[768];
+    int      i,j;
+
+    CinematicGetPalette (&origpal[0]);
+    for (j = 0; j < FADEOUTTIME; j++)
+    {
+        for (i = 0; i < 768; i++)
+        {
+            newpal[i] = ( origpal[i] * (FADEOUTTIME - j - 1) ) / FADEOUTTIME;
+        }
+        WaitVBL();
+        CinematicSetPalette (&newpal[0]);
+        CinematicDelay();
+    }
+    VL_ClearVideo (0);
+    GetCinematicTics ();
+    GetCinematicTics ();
+}
+
+/*
+=================
+=
+= DrawBlankScreen
+=
+=================
+*/
+void DrawBlankScreen ( void )
+{
+    VL_ClearVideo (0);
+}
+
+/*
+=================
+=
+= DrawClearBuffer
+=
+=================
+*/
+void DrawClearBuffer ( void )
+{
+#ifdef DOS
+    VGAMAPMASK(15);
+    memset((byte *)bufferofs,0,iGLOBAL_SCREENBWIDE*iGLOBAL_SCREENHEIGHT);
+#else
+    memset((byte *)bufferofs,0,iGLOBAL_SCREENWIDTH*iGLOBAL_SCREENHEIGHT);
+#endif
+}
+
+/*
+===============
+=
+= UpdateCinematicBack
+=
+===============
+*/
+
+boolean UpdateCinematicBack ( backevent * back )
+{
+    back->duration--;
+
+    if (back->duration<0)
+        return false;
+
+    back->currentoffset += back->dx;
+
+    return true;
+}
+
+/*
+=================
+=
+= UpdateCinematicSprite
+=
+=================
+*/
+boolean UpdateCinematicSprite ( spriteevent * sprite )
+{
+    sprite->duration--;
+
+    if (sprite->duration<0)
+        return false;
+
+    sprite->framedelay--;
+
+    if (sprite->framedelay==0)
+    {
+        sprite->frame++;
+        if (sprite->frame==sprite->numframes)
+            sprite->frame=0;
+        sprite->framedelay=sprite->frametime;
+    }
+
+    sprite->x+=sprite->dx;
+    sprite->y+=sprite->dy;
+    sprite->scale+=sprite->dscale;
+
+    return true;
+}
+
+/*
+=================
+=
+= UpdateCinematicEffect
+=
+=================
+*/
+boolean UpdateCinematicEffect ( enum_eventtype type, void * effect )
+{
+    switch (type)
+    {
+    case background_noscrolling:
+    case background_scrolling:
+    case backdrop_scrolling:
+    case backdrop_noscrolling:
+    case background_multi:
+        return UpdateCinematicBack ( (backevent *) effect );
+        break;
+    case sprite_background:
+    case sprite_foreground:
+        return UpdateCinematicSprite ( (spriteevent *) effect );
+        break;
+    case flic:
+        return true;
+        break;
+    case palette:
+    case fadeout:
+    case blankscreen:
+    case clearbuffer:
+        return true;
+        break;
+    case cinematicend:
+        cinematicdone=true;
+        return true;
+        break;
+    }
+    return true;
+}
+/*
+=================
+=
+= DrawCinematicEffect
+=
+=================
+*/
+boolean DrawCinematicEffect ( enum_eventtype type, void * effect )
+{
+    switch (type)
+    {
+    case background_noscrolling:
+    case background_scrolling:
+        DrawCinematicBackground ( (backevent *) effect );
+        return true;
+        break;
+    case background_multi:
+        DrawCinematicMultiBackground ( (backevent *) effect );
+        return true;
+        break;
+    case backdrop_scrolling:
+    case backdrop_noscrolling:
+        DrawCinematicBackdrop ( (backevent *) effect );
+        return true;
+        break;
+    case sprite_background:
+    case sprite_foreground:
+        DrawCinematicSprite ( (spriteevent *) effect );
+        return true;
+        break;
+    case flic:
+        DrawFlic ( (flicevent *) effect );
+        return false;
+        break;
+    case palette:
+        DrawPalette ( (paletteevent *) effect );
+        return false;
+        break;
+    case fadeout:
+        DrawFadeout ();
+        return false;
+        break;
+    case blankscreen:
+        DrawBlankScreen ();
+        return false;
+        break;
+    case clearbuffer:
+        DrawClearBuffer ();
+        return false;
+        break;
+    case cinematicend:
+        return true;
+        break;
+    }
+    return true;
+}
+
+/*
+=================
+=
+= PrecacheCinematicEffect
+=
+=================
+*/
+void PrecacheCinematicEffect ( enum_eventtype type, void * effect )
+{
+    switch (type)
+    {
+    case background_noscrolling:
+    case background_scrolling:
+    case backdrop_scrolling:
+    case backdrop_noscrolling:
+        PrecacheBack ( (backevent *) effect );
+        break;
+    case sprite_background:
+    case sprite_foreground:
+        PrecacheCinematicSprite ( (spriteevent *) effect );
+        break;
+    case palette:
+        PrecachePalette ( (paletteevent *) effect );
+        break;
+    case flic:
+        PrecacheFlic ( (flicevent *) effect );
+        break;
+    default:
+        ;
+    }
+}
+
+/*
+===============
+=
+= ProfileDisplay
+=
+===============
+*/
+
+void ProfileDisplay ( void )
+{
+    byte * buf;
+    int i;
+    int plane;
+    byte src[200];
+    int width = StretchScreen? 320:iGLOBAL_SCREENWIDTH;
+
+    DrawClearBuffer ();
+
+    plane = 0;
+
+#ifdef DOS
+    for (plane=0; plane<4; plane++)
+#endif
+    {
+        buf=(byte *)bufferofs;
+        VGAWRITEMAP(plane);
+
+#ifdef DOS
+        for (i=plane; i<width; i+=4,buf++)
+#else
+        for (i=0; i<width; i++,buf++)
+#endif
+        {
+            DrawFilmPost(buf,&src[0],200);
+        }
+    }
+}
+
+/*
+===============
+=
+= DrawPostPic
+=
+===============
+*/
+
+void DrawPostPic ( int lumpnum )
+{
+    byte * src;
+    byte * buf;
+    lpic_t * pic;
+    int i;
+    int plane;
+    int height;
+    int width = StretchScreen? 320:iGLOBAL_SCREENWIDTH;
+
+    pic=(lpic_t *)W_CacheLumpNum(lumpnum,PU_CACHE, Cvt_lpic_t, 1);
+
+    height = pic->height;
+
+    plane = 0;
+
+#ifdef DOS
+    for (plane=0; plane<4; plane++)
+#endif
+    {
+        buf=(byte *)bufferofs;
+
+        src=&(pic->data) + (plane*pic->height);
+
+        VGAWRITEMAP(plane);
+
+#ifdef DOS
+        for (i=plane; i<width; i+=4,src+=(pic->height<<2),buf++)
+#else
+        for (i=0; i<width; i++,src+=pic->height,buf++)
+#endif
+        {
+            DrawFilmPost(buf,src,height);
+        }
+    }
+}
--- /dev/null
+++ b/rott/cin_efct.h
@@ -1,0 +1,70 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+#ifndef _cin_efct_public
+#define _cin_efct_public
+
+#include "cin_glob.h"
+#include "cin_def.h"
+
+flicevent * SpawnCinematicFlic ( char * name, boolean loop, boolean usefile );
+spriteevent * SpawnCinematicSprite ( char * name,
+                                     int duration,
+                                     int numframes,
+                                     int framedelay,
+                                     int x,
+                                     int y,
+                                     int scale,
+                                     int endx,
+                                     int endy,
+                                     int endscale
+                                   );
+backevent * SpawnCinematicBack ( char * name,
+                                 int duration,
+                                 int width,
+                                 int startx,
+                                 int endx,
+                                 int yoffset
+                               );
+
+backevent * SpawnCinematicMultiBack ( char * name,
+                                      char * name2,
+                                      int duration,
+                                      int startx,
+                                      int endx,
+                                      int yoffset
+                                    );
+paletteevent * SpawnCinematicPalette ( char * name );
+void DrawFlic ( flicevent * flic );
+void DrawCinematicBackdrop ( backevent * back );
+void DrawCinematicBackground ( backevent * back );
+void DrawPalette (paletteevent * event);
+void DrawCinematicSprite ( spriteevent * sprite );
+void DrawClearBuffer ( void );
+void DrawBlankScreen ( void );
+boolean DrawCinematicEffect ( enum_eventtype type, void * effect );
+boolean UpdateCinematicBack ( backevent * back );
+boolean UpdateCinematicSprite ( spriteevent * sprite );
+boolean UpdateCinematicEffect ( enum_eventtype type, void * effect );
+void PrecacheCinematicEffect ( enum_eventtype type, void * effect );
+void ProfileDisplay ( void );
+void DrawPostPic ( int lumpnum );
+
+#endif
+
--- /dev/null
+++ b/rott/cin_evnt.c
@@ -1,0 +1,530 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+
+#include "cin_glob.h"
+#include "cin_evnt.h"
+#include "cin_efct.h"
+#include "cin_actr.h"
+#include "cin_def.h"
+#include "scriplib.h"
+#include "lumpy.h"
+#include "w_wad.h"
+#include "z_zone.h"
+#include <string.h>
+//MED
+#include "memcheck.h"
+
+eventtype * firstevent;
+eventtype * lastevent;
+
+// LOCALS
+
+static int numevents=0;
+static boolean eventsystemstarted=false;
+
+
+/*
+===============
+=
+= AddEvent
+=
+===============
+*/
+
+void AddEvent (eventtype * event)
+{
+    if (!firstevent)
+        firstevent  = event;
+    else
+    {
+        event->prev = lastevent;
+        lastevent->next = event;
+    }
+    lastevent = event;
+}
+
+
+/*
+===============
+=
+= DeleteEvent
+=
+===============
+*/
+
+void DeleteEvent(eventtype * event)
+{
+    if (event == lastevent)
+        lastevent = event->prev;
+    else
+        event->next->prev = event->prev;
+
+    if (event == firstevent)
+        firstevent = event->next;
+    else
+        event->prev->next = event->next;
+
+    event->prev = NULL;
+    event->next = NULL;
+
+    SafeFree ( event );
+}
+
+/*
+===============
+=
+= GetNewEvent
+=
+===============
+*/
+
+eventtype * GetNewEvent ( void )
+{
+    eventtype * event;
+
+    numevents++;
+
+    if ( numevents > MAXCINEMATICEVENTS )
+        Error ("Too many Cinematic events\n");
+
+    event = SafeMalloc( sizeof (eventtype) );
+
+    event->next=NULL;
+    event->prev=NULL;
+
+    return event;
+}
+
+/*
+===============
+=
+= StartupEvents
+=
+===============
+*/
+
+void StartupEvents ( void )
+{
+    if (eventsystemstarted==true)
+        return;
+    eventsystemstarted=true;
+    firstevent = NULL;
+    lastevent  = NULL;
+
+    numevents=0;
+}
+
+/*
+===============
+=
+= ShutdownEvents
+=
+===============
+*/
+
+void ShutdownEvents ( void )
+{
+    eventtype * event;
+
+    if (eventsystemstarted==false)
+        return;
+    eventsystemstarted=false;
+
+    event=firstevent;
+    while (event != NULL)
+    {
+        eventtype * nextevent;
+
+        nextevent=event->next;
+        DeleteEvent(event);
+        event=nextevent;
+    }
+}
+
+/*
+===============
+=
+= CreateEvent
+=
+===============
+*/
+eventtype * CreateEvent ( int time, int type )
+{
+    eventtype * event;
+
+    event = GetNewEvent ();
+
+    event->time = time;
+    event->effecttype = type;
+    event->effect = NULL;
+
+    AddEvent (event);
+
+    return event;
+}
+
+/*
+===============
+=
+= GetEventType
+=
+= Gets event type from token
+=
+===============
+*/
+enum_eventtype GetEventType ( void )
+{
+    // Get Event Token
+
+    GetToken (false);
+
+    if (!strcmpi (token,"BACKGROUND"))
+    {
+        GetToken (false);
+        if (!strcmpi (token,"SCROLL"))
+        {
+            return background_scrolling;
+        }
+        else if (!strcmpi (token,"NOSCROLL"))
+        {
+            return background_noscrolling;
+        }
+        else if (!strcmpi (token,"MULTISCROLL"))
+        {
+            return background_multi;
+        }
+        else
+        {
+            Error("Illegal Background Scrolling token\n");
+        }
+    }
+    else if (!strcmpi (token,"BACKDROP"))
+    {
+        GetToken (false);
+        if (!strcmpi (token,"SCROLL"))
+        {
+            return backdrop_scrolling;
+        }
+        else if (!strcmpi (token,"NOSCROLL"))
+        {
+            return backdrop_noscrolling;
+        }
+        else
+        {
+            Error("Illegal Backdrop Scrolling token\n");
+        }
+    }
+    else if (!strcmpi (token,"BACKGROUNDSPRITE"))
+    {
+        return sprite_background;
+    }
+    else if (!strcmpi (token,"FOREGROUNDSPRITE"))
+    {
+        return sprite_foreground;
+    }
+    else if (!strcmpi (token,"PALETTE"))
+    {
+        return palette;
+    }
+    else if (!strcmpi (token,"FADEOUT"))
+    {
+        return fadeout;
+    }
+    else if (!strcmpi (token,"FLIC"))
+    {
+        return flic;
+    }
+    else if (!strcmpi (token,"MOVIEEND"))
+    {
+        return cinematicend;
+    }
+    else if (!strcmpi (token,"BLANKSCREEN"))
+    {
+        return blankscreen;
+    }
+    else if (!strcmpi (token,"CLEARBUFFER"))
+    {
+        return clearbuffer;
+    }
+    else
+    {
+        Error("GetEventType: Illegal Token %s\n",token);
+    }
+    return -1;
+}
+
+/*
+===============
+=
+= ParseBack
+=
+===============
+*/
+void ParseBack ( eventtype * event )
+{
+    char name[10];
+    char name2[10];
+    int duration;
+    int yoffset;
+    int width;
+    int startx;
+    int endx;
+
+    GetToken (false);
+    strcpy(&(name[0]),token);
+
+    if (event->effecttype==background_multi)
+    {
+        GetToken (false);
+        strcpy(&(name2[0]),token);
+    }
+
+    GetToken (false);
+    duration=ParseNum(token);
+    GetToken (false);
+    yoffset=ParseNum(token);
+    if (
+        (event->effecttype==background_noscrolling) ||
+        (event->effecttype==background_scrolling)
+    )
+    {
+        lpic_t * lpic;
+
+        lpic = (lpic_t *)W_CacheLumpName(name,PU_CACHE, Cvt_lpic_t, 1);
+        width = lpic->width;
+    }
+    else if (event->effecttype!=background_multi)
+    {
+        patch_t * patch;
+
+        patch = (patch_t *)W_CacheLumpName(name,PU_CACHE, Cvt_lpic_t, 1);
+        width = patch->width;
+    }
+
+    startx=0;
+    endx=0;
+    if (
+        (event->effecttype==backdrop_scrolling) ||
+        (event->effecttype==background_scrolling) ||
+        (event->effecttype==background_multi)
+    )
+    {
+        GetToken (false);
+        startx=ParseNum(token);
+        GetToken (false);
+        endx=ParseNum(token);
+    }
+
+    if (event->effecttype==background_multi)
+        event->effect = SpawnCinematicMultiBack ( name, name2, duration, startx, endx, yoffset);
+    else
+        event->effect = SpawnCinematicBack ( name, duration, width, startx, endx, yoffset);
+}
+
+/*
+===============
+=
+= ParseSprite
+=
+===============
+*/
+void ParseSprite ( eventtype * event )
+{
+    char name[10];
+    int duration;
+    int numframes;
+    int framedelay;
+    int x,y,scale;
+    int endx,endy,endscale;
+
+    GetToken (false);
+    strcpy(&(name[0]),token);
+    GetToken (false);
+    duration=ParseNum(token);
+    GetToken (false);
+    numframes=ParseNum(token);
+    GetToken (false);
+    framedelay=ParseNum(token);
+    GetToken (false);
+    x=ParseNum(token);
+    GetToken (false);
+    y=ParseNum(token);
+    GetToken (false);
+    scale=ParseNum(token);
+    GetToken (false);
+    endx=ParseNum(token);
+    GetToken (false);
+    endy=ParseNum(token);
+    GetToken (false);
+    endscale=ParseNum(token);
+
+    event->effect = SpawnCinematicSprite ( name, duration, numframes,
+                                           framedelay, x, y, scale,
+                                           endx, endy, endscale
+                                         );
+}
+
+/*
+===============
+=
+= ParseFlic
+=
+===============
+*/
+void ParseFlic ( eventtype * event )
+{
+    char name[10];
+    boolean loop;
+    boolean usefile;
+
+    GetToken (false);
+    strcpy(&(name[0]),token);
+
+    GetToken (false);
+    if (!strcmpi (token,"LOOP"))
+    {
+        loop = true;
+    }
+    else if (!strcmpi (token,"NOLOOP"))
+    {
+        loop = false;
+    }
+    else
+        Error("ParseFlic: Illegal or missing flic loop token %s\n",token);
+
+    GetToken (false);
+    if (!strcmpi (token,"FILE"))
+    {
+        usefile=true;
+    }
+    else if (!strcmpi (token,"LUMP"))
+    {
+        usefile=false;
+    }
+    else
+        Error("ParseFlic: Illegal or missing flic use token %s\n",token);
+
+    event->effect = SpawnCinematicFlic ( name, loop, usefile );
+}
+
+/*
+===============
+=
+= ParsePalette
+=
+===============
+*/
+void ParsePalette ( eventtype * event )
+{
+    char name[10];
+
+    GetToken (false);
+    strcpy(&(name[0]),token);
+
+    event->effect = SpawnCinematicPalette ( name );
+}
+
+/*
+===============
+=
+= ParseEvent
+=
+===============
+*/
+void ParseEvent ( int time )
+{
+    eventtype * event;
+
+    event = CreateEvent ( time, GetEventType() );
+
+    switch (event->effecttype)
+    {
+    case background_noscrolling:
+    case background_scrolling:
+    case background_multi:
+    case backdrop_scrolling:
+    case backdrop_noscrolling:
+        ParseBack(event);
+        break;
+    case sprite_background:
+    case sprite_foreground:
+        ParseSprite(event);
+        break;
+    case palette:
+        ParsePalette(event);
+        break;
+    case flic:
+        ParseFlic(event);
+        break;
+    case fadeout:
+    case blankscreen:
+    case clearbuffer:
+    case cinematicend:
+        break;
+    }
+}
+
+/*
+===============
+=
+= UpdateCinematicEvents
+=
+===============
+*/
+void UpdateCinematicEvents ( int time )
+{
+    eventtype * event;
+
+    for (event=firstevent; event != NULL;)
+    {
+        if (event->time==time)
+        {
+            eventtype * nextevent;
+
+            nextevent=event->next;
+            SpawnCinematicActor ( event->effecttype, event->effect );
+            DeleteEvent(event);
+            event=nextevent;
+        }
+        else if (event->time>time)
+            break;
+        else
+            event=event->next;
+    }
+}
+
+/*
+===============
+=
+= PrecacheCinematic
+=
+===============
+*/
+void PrecacheCinematic ( void )
+{
+    eventtype * event;
+
+    for (event=firstevent; event != NULL;)
+    {
+        PrecacheCinematicEffect ( event->effecttype, event->effect );
+        event=event->next;
+    }
+}
+
--- /dev/null
+++ b/rott/cin_evnt.h
@@ -1,0 +1,41 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+#ifndef _cin_evnt_public
+#define _cin_evnt_public
+
+#include "cin_glob.h"
+#include "cin_def.h"
+
+extern eventtype * firstevent;
+extern eventtype * lastevent;
+
+void AddEvent (eventtype * event);
+void DeleteEvent(eventtype * event);
+
+eventtype * GetNewEvent ( void );
+void StartupEvents ( void );
+void ShutdownEvents ( void );
+eventtype * CreateEvent ( int time, int type );
+void ParseEvent ( int time );
+void UpdateCinematicEvents ( int time );
+void PrecacheCinematic ( void );
+
+#endif
+
--- /dev/null
+++ b/rott/cin_glob.c
@@ -1,0 +1,45 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+#include "cin_glob.h"
+#include "rt_in.h"
+#include "rt_draw.h"
+//MED
+#include "memcheck.h"
+
+void CinematicDelay ( void )
+{
+    CalcTics();
+}
+
+int GetCinematicTime ( void )
+{
+    return GetTicCount ();
+}
+
+boolean CinematicAbort( void )
+{
+    return (IN_CheckAck ());
+}
+
+void ClearCinematicAbort( void )
+{
+    IN_StartAck ();
+}
+
--- /dev/null
+++ b/rott/cin_glob.h
@@ -1,0 +1,37 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+#include "rt_def.h"
+#include "rt_util.h"
+#include "isr.h"
+#include <time.h>
+
+#ifndef CIN_GLOB_H
+#define CIN_GLOB_H
+
+#define DUMP 0
+
+#define CLOCKSPEED (VBLCOUNTER)
+
+void CinematicDelay( void );
+int GetCinematicTime( void );
+boolean CinematicAbort( void );
+void ClearCinematicAbort( void );
+
+#endif
--- /dev/null
+++ b/rott/cin_main.c
@@ -1,0 +1,286 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+
+#ifdef DOS
+#include <malloc.h>
+#include <dos.h>
+#include <io.h>
+#include <conio.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <string.h>
+#include "cin_glob.h"
+#include "scriplib.h"
+#include "watcom.h"
+#include "z_zone.h"
+#include "w_wad.h"
+#include "cin_main.h"
+#include "modexlib.h"
+#include "lumpy.h"
+
+#include "cin_actr.h"
+#include "cin_evnt.h"
+#include "cin_efct.h"
+//MED
+#include "memcheck.h"
+
+boolean cinematicdone;
+static int cinematictime;
+static int cinematictics;
+static int cinematictictime;
+static int profiletics=-1;
+
+/*
+================
+=
+= ProfileMachine
+=
+================
+*/
+void ProfileMachine ( void )
+{
+    int i;
+    int time;
+    int endtime;
+
+    if (profiletics>0)
+        return;
+    time=GetCinematicTime();
+    for (i=0; i<4; i++)
+    {
+        ProfileDisplay();
+    }
+    endtime=GetCinematicTime();
+
+    profiletics = (endtime-time)>>2;
+    if (profiletics<1)
+        profiletics=1;
+}
+
+/*
+================
+=
+= StartupCinematic
+=
+================
+*/
+void StartupCinematic ( void )
+{
+    StartupEvents ();
+    StartupCinematicActors ();
+    cinematicdone=false;
+    cinematictime=0;
+    GetCinematicTics ();
+    ClearCinematicAbort();
+    ProfileMachine();
+}
+
+
+/*
+================
+=
+= ShutdownCinematic
+=
+================
+*/
+void ShutdownCinematic ( void )
+{
+    ShutdownEvents ();
+    ShutdownCinematicActors ();
+}
+
+
+/*
+================
+=
+= ParseCinematicScript
+=
+================
+*/
+
+void ParseCinematicScript (void)
+{
+    int time;
+
+    time=0;
+    do
+    {
+        //
+        // get next command time
+        //
+        GetToken (true);
+        if (endofscript)
+            break;
+        time+=ParseNum(token);
+        ParseEvent ( time );
+    }
+    while (script_p < scriptend_p);
+}
+
+
+/*
+==============
+=
+= CacheScriptFile
+=
+==============
+*/
+
+void CacheScriptFile (char *filename)
+{
+    long            size;
+    int lump;
+
+    lump=W_GetNumForName(filename);
+
+    scriptbuffer=W_CacheLumpNum(lump,PU_CACHE, CvtNull, 1);
+    size = W_LumpLength(lump);
+
+    script_p = scriptbuffer;
+    scriptend_p = script_p + size;
+    scriptline = 1;
+    endofscript = false;
+    tokenready = false;
+}
+
+
+/*
+=================
+=
+= GrabCinematicScript
+=
+=================
+*/
+
+void GrabCinematicScript (char const *basename, boolean uselumpy)
+{
+    char script[256];
+
+//
+// read in the script file
+//
+    strcpy (script, basename);
+    strcat (script,".ms");
+    if (uselumpy==false)
+        LoadScriptFile (script);
+    else
+        CacheScriptFile ((char *)basename);
+
+    ParseCinematicScript ();
+}
+
+/*
+==============
+=
+= GetCinematicTics
+=
+==============
+*/
+
+void GetCinematicTics ( void )
+{
+    int time;
+
+    time=GetCinematicTime();
+    while (time==cinematictictime)
+    {
+        time=GetCinematicTime();
+    }
+    cinematictics=(time-cinematictictime);
+    cinematictictime=time;
+    cinematictics=profiletics;
+}
+
+
+void PlayMovie ( char * name, boolean uselumpy )
+{
+    int i;
+
+    StartupCinematic ( );
+    GrabCinematicScript (name, uselumpy);
+
+    PrecacheCinematic ( );
+    GetCinematicTics();
+    while (cinematicdone==false)
+    {
+        cinematicdone=CinematicAbort();
+#if DUMP
+        printf("time=%ld\n",cinematictime);
+#endif
+        for (i=0; i<cinematictics; i++)
+        {
+            UpdateCinematicEvents ( cinematictime );
+            UpdateCinematicActors ( );
+            cinematictime++;
+        }
+        DrawCinematicActors ();
+        GetCinematicTics();
+    }
+
+    ShutdownCinematic ();
+}
+
+#ifndef DOS
+int cin_iscale;
+byte *cin_source;
+int cin_texturemid;
+int cin_ycenter;
+int cin_yh;
+int cin_yl;
+
+/* f_scale.asm */
+
+void R_DrawFilmColumn (byte * buf)
+{
+    // This is *NOT* 100% correct - DDOI
+    int count;
+    int frac, fracstep;
+    byte *dest;
+
+    count = cin_yh - cin_yl;
+    if (count < 0) return;
+
+    dest = buf + ylookup[cin_yl];
+
+    fracstep = cin_iscale;
+    frac = cin_texturemid + (cin_yl-cin_ycenter)*fracstep;
+
+    while (count--) {
+        *dest = cin_source[(frac>>SFRACBITS)];
+        dest += iGLOBAL_SCREENWIDTH;
+        frac += fracstep;
+    }
+}
+
+void DrawFilmPost (byte * buf, byte * src, int height)
+{
+    while (height--) {
+        *buf = *src;
+
+        src++;
+
+        buf += linewidth;
+    }
+}
+#endif
+
--- /dev/null
+++ b/rott/cin_main.h
@@ -1,0 +1,36 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+#ifndef _cin_main_public
+#define _cin_main_public
+
+//***************************************************************************
+//
+// CIN_MAIN.H
+//
+//***************************************************************************
+#include "cin_glob.h"
+
+void GrabMovieScript (char const *basename, boolean uselumpy);
+void PlayMovie (char * name, boolean uselumpy);
+void GetCinematicTics ( void );
+
+extern boolean cinematicdone;
+
+#endif
--- /dev/null
+++ b/rott/cin_util.c
@@ -1,0 +1,72 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+#include "cin_glob.h"
+#include "modexlib.h"
+
+#ifdef DOS
+#include <conio.h>
+#endif
+
+//MED
+#include "memcheck.h"
+
+/*
+==============
+=
+= CinematicGetPalette
+=
+= Return an 8 bit / color palette
+=
+==============
+*/
+
+void CinematicGetPalette (byte *pal)
+{
+#ifdef DOS
+    int	i;
+
+    outp (PEL_READ_ADR,0);
+    for (i=0 ; i<768 ; i++)
+        pal[i] = ((inp (PEL_DATA))<<2);
+#else
+#endif
+}
+
+/*
+==============
+=
+= CinematicSetPalette
+=
+= Sets an 8 bit / color palette
+=
+==============
+*/
+
+void CinematicSetPalette (byte *pal)
+{
+#ifdef DOS
+    int	i;
+
+    outp (PEL_WRITE_ADR,0);
+    for (i=0 ; i<768 ; i++)
+        outp (PEL_DATA, pal[i]>>2);
+#else
+#endif
+}
--- /dev/null
+++ b/rott/cin_util.h
@@ -1,0 +1,28 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+#ifndef _cin_util_public
+#define _cin_util_public
+
+
+void CinematicGetPalette (byte *pal);
+void CinematicSetPalette (byte *pal);
+
+#endif
+
--- /dev/null
+++ b/rott/develop.h
@@ -1,0 +1,82 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+#ifndef _develop_public
+#define _develop_public
+
+#define NOMEMCHECK
+#define DEBUG 0
+#define DEVELOPMENT 0
+#define BETA 0
+#define SOUNDTEST 0
+#define PRECACHETEST 0
+#define ELEVATORTEST 0
+#define TEAMTEST     0
+#define LOADSAVETEST 0
+#define WEAPONCHEAT  1
+#define MEMORYCORRUPTIONTEST  0
+#define SYNCCHECK    1
+#define DATACORRUPTIONTEST    0
+#define BATTLECHECK 0 // This should be turned off for release, on for beta
+#define BATTLEINFO  0 // This should be turned off for release
+
+#define DELUXE   0
+#define LOWCOST  0
+
+#define BNACRASHPREVENT  1 //bna added 
+// Flavor selection (shareware, registered, cd version, site license) has moved to the Makefile
+#ifndef SHAREWARE
+#define SHAREWARE 0
+#endif
+
+// cute little dopefish thing, only works with special patch?
+#define DOPEFISH 0
+
+// okay?
+
+#define TEDLAUNCH   0
+#define SOFTERROR   0
+#define RANDOMTEST  0
+#define WHEREAMI    0
+
+
+
+
+#if (WHEREAMI==1)
+
+#define wami(val)      \
+   {                   \
+   programlocation=val;\
+   }
+
+#define waminot()
+/*
+   {                  \
+   programlocation=-1;\
+   }
+*/
+
+#else
+
+#define wami(val)
+#define waminot()
+
+#endif
+
+#endif
--- /dev/null
+++ b/rott/dosutil.c
@@ -1,0 +1,394 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#include <sys/stat.h>
+#if PLATFORM_UNIX
+#include <sys/types.h>
+#include <errno.h>
+#include <unistd.h>
+#endif
+
+#include <fcntl.h>
+
+#include "rt_def.h"
+
+#if defined(USE_SDL)
+#include "SDL.h"
+#endif
+
+/*
+  Copied over from Wolf3D Linux: http://www.icculus.org/wolf3d/
+  Modified for ROTT.
+ */
+
+int _argc;
+char **_argv;
+
+#if PLATFORM_UNIX
+long filelength(int handle)
+{
+    struct stat buf;
+
+    if (fstat(handle, &buf) == -1) {
+        perror("filelength");
+        exit(EXIT_FAILURE);
+    }
+
+    return buf.st_size;
+}
+
+char *strlwr(char *s)
+{
+    char *p = s;
+
+    while (*p) {
+        *p = tolower(*p);
+        p++;
+    }
+
+    return s;
+}
+
+char *strupr(char *s)
+{
+    char *p = s;
+
+    while (*p) {
+        *p = toupper(*p);
+        p++;
+    }
+
+    return s;
+}
+
+char *itoa(int value, char *string, int radix)
+{
+    switch (radix) {
+    case 10:
+        sprintf(string, "%d", value);
+        break;
+    case 16:
+        sprintf(string, "%x", value);
+        break;
+    default:
+        STUB_FUNCTION;
+        break;
+    }
+
+    return string;
+}
+
+char *ltoa(long value, char *string, int radix)
+{
+    switch (radix) {
+    case 10:
+        sprintf(string, "%ld", value);
+        break;
+    case 16:
+        sprintf(string, "%lx", value);
+        break;
+    default:
+        STUB_FUNCTION;
+        break;
+    }
+
+    return string;
+}
+
+char *ultoa(unsigned long value, char *string, int radix)
+{
+    switch (radix) {
+    case 10:
+        sprintf(string, "%lu", value);
+        break;
+    case 16:
+        sprintf(string, "%lux", value);
+        break;
+    default:
+        STUB_FUNCTION;
+        break;
+    }
+
+    return string;
+}
+#endif
+
+char getch(void)
+{
+    getchar();
+    return 0;
+}
+
+extern char ApogeePath[256];
+
+int setup_homedir (void)
+{
+#if PLATFORM_UNIX && !defined(__MINGW32__)
+    int err;
+
+    /* try to create the root directory */
+    snprintf (ApogeePath, sizeof (ApogeePath), "%s/.rott/", getenv ("HOME"));
+    err = mkdir (ApogeePath, S_IRWXU);
+
+    /* keep the shareware and registered game data separated */
+#if (SHAREWARE == 1)
+    snprintf (ApogeePath, sizeof (ApogeePath), "%s/.rott/", getenv ("HOME"));
+#else
+    snprintf (ApogeePath, sizeof (ApogeePath), "%s/.rott/darkwar/", getenv ("HOME"));
+#endif
+
+    err = mkdir (ApogeePath, S_IRWXU);
+    if (err == -1 && errno != EEXIST)
+    {
+        fprintf (stderr, "Couldn't create preferences directory: %s\n",
+                 strerror (errno));
+        return -1;
+    }
+#else
+    sprintf(ApogeePath, ".%s", PATH_SEP_STR);
+#endif
+
+    return 0;
+}
+
+/* from Dan Olson */
+void put_dos2ansi(byte attrib)
+{
+    int lookup[] = {30,34,32,36,31,35,33,37};
+    byte fore,back,blink=0,intens=0;
+
+    fore = attrib&15;	/* bits 0-3 */
+    back = attrib&112; /* bits 4-6 */
+    blink = attrib&128; /* bit 7 */
+
+    /* Fix background, blink is either on or off. */
+    back = back>>4;
+
+    /* Fix foreground */
+    if (fore > 7) {
+        intens = 1;
+        fore-=8;
+    }
+
+    /* Convert fore/back */
+    fore = lookup[fore];
+    back = lookup[back]+10;
+
+    // 'Render"
+    if (blink)
+        printf ("\033[%d;5;%dm\033[%dm", intens, fore, back);
+    else
+        printf ("\033[%d;25;%dm\033[%dm", intens, fore, back);
+}
+
+void DisplayTextSplash(byte *text, int l)
+{
+    int i;
+    int bound = 80*l*2;
+
+    for (i=0; i<bound; i+=2)
+    {
+        put_dos2ansi(text[i+1]);
+        putchar (text[i]);
+    }
+
+    printf ("\033[m");
+}
+
+#if !defined(__CYGWIN__) && !defined(__MINGW32__)
+#include <execinfo.h>
+
+void print_stack (int level)
+{
+    void *array[64];
+    char **syms;
+    int size, i;
+
+    printf ("Stack dump:\n");
+    printf ("{\n");
+    size = backtrace (array, (sizeof (array))/(sizeof (array[0])));
+    syms = backtrace_symbols (array, size);
+    for (i=level+1; i<size; ++i) {
+        printf ("\t%s\n",syms[i]);
+    }
+    free (syms);
+    /*
+    for (i = 2; i <size; ++i) {
+    	printf ("\t%p\n", array[i]);
+    }
+    */
+    printf ("}\n");
+}
+#else
+
+void print_stack (int level)
+{
+    printf("Stack dump not implemented.\n");
+}
+
+#endif
+
+void crash_print (int sig)
+{
+    printf ("OH NO OH NO ROTT CRASHED!\n");
+    printf ("Here is where:\n");
+    print_stack (1);
+#if defined(USE_SDL)
+    SDL_Quit ();
+#endif
+    exit (1);
+}
+
+#if 0
+/* ** */
+
+uint16_t SwapInt16L(uint16_t i)
+{
+#if BYTE_ORDER == BIG_ENDIAN
+    return ((uint16_t)i >> 8) | ((uint16_t)i << 8);
+#else
+    return i;
+#endif
+}
+
+uint32_t SwapInt32L(uint32_t i)
+{
+#if BYTE_ORDER == BIG_ENDIAN
+    return	((uint32_t)(i & 0xFF000000) >> 24) |
+            ((uint32_t)(i & 0x00FF0000) >>  8) |
+            ((uint32_t)(i & 0x0000FF00) <<  8) |
+            ((uint32_t)(i & 0x000000FF) << 24);
+#else
+    return i;
+#endif
+}
+
+/* ** */
+
+int OpenWrite(char *_fn)
+{
+    int fp;
+    char fn[MAX_PATH];
+    strncpy(fn, _fn, sizeof (fn));
+    fn[sizeof (fn) - 1] = '\0';
+    FixFilePath(fn);
+
+    fp = open(fn, O_CREAT|O_WRONLY|O_TRUNC|O_BINARY, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
+    return fp;
+}
+
+int OpenWriteAppend(char *_fn)
+{
+    int fp;
+    char fn[MAX_PATH];
+    strncpy(fn, _fn, sizeof (fn));
+    fn[sizeof (fn) - 1] = '\0';
+    FixFilePath(fn);
+
+    fp = open(fn, O_CREAT|O_WRONLY|O_BINARY, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
+    return fp;
+}
+
+void CloseWrite(int fp)
+{
+    close(fp);
+}
+
+int WriteSeek(int fp, int offset, int whence)
+{
+    return lseek(fp, offset, whence);
+}
+
+int WritePos(int fp)
+{
+    return lseek(fp, 0, SEEK_CUR);
+}
+
+int WriteInt8(int fp, int8_t d)
+{
+    return write(fp, &d, 1);
+}
+
+int WriteInt16(int fp, int16_t d)
+{
+    int16_t b = SwapInt16L(d);
+
+    return write(fp, &b, 2) / 2;
+}
+
+int WriteInt32(int fp, int32_t d)
+{
+    int32_t b = SwapInt32L(d);
+
+    return write(fp, &b, 4) / 4;
+}
+
+int WriteBytes(int fp, byte *d, int len)
+{
+    return write(fp, d, len);
+}
+
+
+int OpenRead(char *_fn)
+{
+    int fp;
+    char fn[MAX_PATH];
+    strncpy(fn, _fn, sizeof (fn));
+    fn[sizeof (fn) - 1] = '\0';
+    FixFilePath(fn);
+
+    fp = open(fn, O_RDONLY | O_BINARY);
+
+    return fp;
+}
+
+void CloseRead(int fp)
+{
+    close(fp);
+}
+
+int ReadSeek(int fp, int offset, int whence)
+{
+    return lseek(fp, offset, whence);
+}
+
+int ReadLength(int fp)
+{
+    return filelength(fp);
+}
+
+int8_t ReadInt8(int fp)
+{
+    byte d[1];
+
+    read(fp, d, 1);
+
+    return d[0];
+}
+
+int16_t ReadInt16(int fp)
+{
+    byte d[2];
+
+    read(fp, d, 2);
+
+    return (d[0]) | (d[1] << 8);
+}
+
+int32_t ReadInt32(int fp)
+{
+    byte d[4];
+
+    read(fp, d, 4);
+
+    return (d[0]) | (d[1] << 8) | (d[2] << 16) | (d[3] << 24);
+}
+
+int ReadBytes(int fp, byte *d, int len)
+{
+    return read(fp, d, len);
+}
+
+#endif
--- /dev/null
+++ b/rott/dukemusc.c
@@ -1,0 +1,507 @@
+/*
+ * A reimplementation of Jim Dose's FX_MAN routines, using  SDL_mixer 1.2.
+ *   Whee. FX_MAN is also known as the "Apogee Sound System", or "ASS" for
+ *   short. How strangely appropriate that seems.
+ *
+ * Written by Ryan C. Gordon. (icculus@clutteredmind.org)
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <assert.h>
+
+#define ROTT
+
+#ifdef DUKE3D
+#include "duke3d.h"
+#include "buildengine/cache1d.h"
+#endif
+
+#if PLATFORM_DOS
+// Use the original Apogee Sound System libs instead.  --ryan.
+#error you probably should not compile this.
+#endif
+
+#if (defined __WATCOMC__)
+// This is probably out of date.  --ryan.
+#include "dukesnd_watcom.h"
+#endif
+
+#if (!defined __WATCOMC__)
+#define cdecl
+#endif
+
+#include "SDL.h"
+#include "SDL_mixer.h"
+#ifdef ROTT
+#include "rt_def.h"      // ROTT music hack
+#include "rt_cfg.h"      // ROTT music hack
+#include "rt_util.h"     // ROTT music hack
+#endif
+#include "music.h"
+
+#define __FX_TRUE  (1 == 1)
+#define __FX_FALSE (!__FX_TRUE)
+
+#define DUKESND_DEBUG       "DUKESND_DEBUG"
+
+#ifndef min
+#define min(a, b)  (((a) < (b)) ? (a) : (b))
+#endif
+
+#ifndef max
+#define max(a, b)  (((a) > (b)) ? (a) : (b))
+#endif
+
+int MUSIC_ErrorCode = MUSIC_Ok;
+
+static char warningMessage[80];
+static char errorMessage[80];
+static int fx_initialized = 0;
+static int numChannels = MIX_CHANNELS;
+static void (*callback)(unsigned long);
+static int reverseStereo = 0;
+static int reverbDelay = 256;
+static int reverbLevel = 0;
+static int fastReverb = 0;
+static FILE *debug_file = NULL;
+static int initialized_debugging = 0;
+static int mixerIsStereo = 1;
+
+// This gets called all over the place for information and debugging messages.
+//  If the user set the DUKESND_DEBUG environment variable, the messages
+//  go to the file that is specified in that variable. Otherwise, they
+//  are ignored for the expense of the function call. If DUKESND_DEBUG is
+//  set to "-" (without the quotes), then the output goes to stdout.
+static void musdebug(const char *fmt, ...)
+{
+    va_list ap;
+
+    if (debug_file)
+    {
+        fprintf(debug_file, "DUKEMUS: ");
+        va_start(ap, fmt);
+        vfprintf(debug_file, fmt, ap);
+        va_end(ap);
+        fprintf(debug_file, "\n");
+        fflush(debug_file);
+    } // if
+} // musdebug
+
+static void init_debugging(void)
+{
+    const char *envr;
+
+    if (initialized_debugging)
+        return;
+
+    envr = getenv(DUKESND_DEBUG);
+    if (envr != NULL)
+    {
+        if (strcmp(envr, "-") == 0)
+            debug_file = stdout;
+        else
+            debug_file = fopen(envr, "w");
+
+        if (debug_file == NULL)
+            fprintf(stderr, "DUKESND: -WARNING- Could not open debug file!\n");
+        else
+            setbuf(debug_file, NULL);
+    } // if
+
+    initialized_debugging = 1;
+} // init_debugging
+
+static void setWarningMessage(const char *msg)
+{
+    strncpy(warningMessage, msg, sizeof (warningMessage));
+    // strncpy() doesn't add the null char if there isn't room...
+    warningMessage[sizeof (warningMessage) - 1] = '\0';
+    musdebug("Warning message set to [%s].", warningMessage);
+} // setErrorMessage
+
+
+static void setErrorMessage(const char *msg)
+{
+    strncpy(errorMessage, msg, sizeof (errorMessage));
+    // strncpy() doesn't add the null char if there isn't room...
+    errorMessage[sizeof (errorMessage) - 1] = '\0';
+    musdebug("Error message set to [%s].", errorMessage);
+} // setErrorMessage
+
+// The music functions...
+
+char *MUSIC_ErrorString(int ErrorNumber)
+{
+    switch (ErrorNumber)
+    {
+    case MUSIC_Warning:
+        return(warningMessage);
+
+    case MUSIC_Error:
+        return(errorMessage);
+
+    case MUSIC_Ok:
+        return("OK; no error.");
+
+    case MUSIC_ASSVersion:
+        return("Incorrect sound library version.");
+
+    case MUSIC_SoundCardError:
+        return("General sound card error.");
+
+    case MUSIC_InvalidCard:
+        return("Invalid sound card.");
+
+    case MUSIC_MidiError:
+        return("MIDI error.");
+
+    case MUSIC_MPU401Error:
+        return("MPU401 error.");
+
+    case MUSIC_TaskManError:
+        return("Task Manager error.");
+
+    case MUSIC_FMNotDetected:
+        return("FM not detected error.");
+
+    case MUSIC_DPMI_Error:
+        return("DPMI error.");
+
+    default:
+        return("Unknown error.");
+    } // switch
+
+    assert(0);    // shouldn't hit this point.
+    return(NULL);
+} // MUSIC_ErrorString
+
+
+static int music_initialized = 0;
+static int music_context = 0;
+static int music_loopflag = MUSIC_PlayOnce;
+static char *music_songdata = NULL;
+static Mix_Music *music_musicchunk = NULL;
+
+int MUSIC_Init(int SoundCard, int Address)
+{
+    init_debugging();
+
+    musdebug("INIT! card=>%d, address=>%d...", SoundCard, Address);
+
+    if (music_initialized)
+    {
+        setErrorMessage("Music system is already initialized.");
+        return(MUSIC_Error);
+    } // if
+
+    if (SoundCard != SoundScape) // We pretend there's a SoundScape installed.
+    {
+        setErrorMessage("Card not found.");
+        musdebug("We pretend to be an Ensoniq SoundScape only.");
+        return(MUSIC_Error);
+    } // if
+
+    music_initialized = 1;
+    return(MUSIC_Ok);
+} // MUSIC_Init
+
+
+int MUSIC_Shutdown(void)
+{
+    musdebug("shutting down sound subsystem.");
+
+    if (!music_initialized)
+    {
+        setErrorMessage("Music system is not currently initialized.");
+        return(MUSIC_Error);
+    } // if
+
+    MUSIC_StopSong();
+    music_context = 0;
+    music_initialized = 0;
+    music_loopflag = MUSIC_PlayOnce;
+
+    return(MUSIC_Ok);
+} // MUSIC_Shutdown
+
+
+void MUSIC_SetMaxFMMidiChannel(int channel)
+{
+    musdebug("STUB ... MUSIC_SetMaxFMMidiChannel(%d).\n", channel);
+} // MUSIC_SetMaxFMMidiChannel
+
+
+void MUSIC_SetVolume(int volume)
+{
+    Mix_VolumeMusic(volume >> 1);  // convert 0-255 to 0-128.
+} // MUSIC_SetVolume
+
+
+void MUSIC_SetMidiChannelVolume(int channel, int volume)
+{
+    musdebug("STUB ... MUSIC_SetMidiChannelVolume(%d, %d).\n", channel, volume);
+} // MUSIC_SetMidiChannelVolume
+
+
+void MUSIC_ResetMidiChannelVolumes(void)
+{
+    musdebug("STUB ... MUSIC_ResetMidiChannelVolumes().\n");
+} // MUSIC_ResetMidiChannelVolumes
+
+
+int MUSIC_GetVolume(void)
+{
+    return(Mix_VolumeMusic(-1) << 1);  // convert 0-128 to 0-255.
+} // MUSIC_GetVolume
+
+
+void MUSIC_SetLoopFlag(int loopflag)
+{
+    music_loopflag = loopflag;
+} // MUSIC_SetLoopFlag
+
+
+int MUSIC_SongPlaying(void)
+{
+    return((Mix_PlayingMusic()) ? __FX_TRUE : __FX_FALSE);
+} // MUSIC_SongPlaying
+
+
+void MUSIC_Continue(void)
+{
+    if (Mix_PausedMusic())
+        Mix_ResumeMusic();
+    else if (music_songdata)
+        MUSIC_PlaySong(music_songdata, MUSIC_PlayOnce);
+} // MUSIC_Continue
+
+
+void MUSIC_Pause(void)
+{
+    Mix_PauseMusic();
+} // MUSIC_Pause
+
+
+int MUSIC_StopSong(void)
+{
+    //if (!fx_initialized)
+    if (!Mix_QuerySpec(NULL, NULL, NULL))
+    {
+        setErrorMessage("Need FX system initialized, too. Sorry.");
+        return(MUSIC_Error);
+    } // if
+
+    if ( (Mix_PlayingMusic()) || (Mix_PausedMusic()) )
+        Mix_HaltMusic();
+
+    if (music_musicchunk)
+        Mix_FreeMusic(music_musicchunk);
+
+    music_songdata = NULL;
+    music_musicchunk = NULL;
+    return(MUSIC_Ok);
+} // MUSIC_StopSong
+
+
+int MUSIC_PlaySong(unsigned char *song, int loopflag)
+{
+    //SDL_RWops *rw;
+
+    MUSIC_StopSong();
+
+    music_songdata = song;
+
+    // !!! FIXME: This could be a problem...SDL/SDL_mixer wants a RWops, which
+    // !!! FIXME:  is an i/o abstraction. Since we already have the MIDI data
+    // !!! FIXME:  in memory, we fake it with a memory-based RWops. None of
+    // !!! FIXME:  this is a problem, except the RWops wants to know how big
+    // !!! FIXME:  its memory block is (so it can do things like seek on an
+    // !!! FIXME:  offset from the end of the block), and since we don't have
+    // !!! FIXME:  this information, we have to give it SOMETHING.
+
+    /* !!! ARGH! There's no LoadMUS_RW  ?!
+    rw = SDL_RWFromMem((void *) song, (10 * 1024) * 1024);  // yikes.
+    music_musicchunk = Mix_LoadMUS_RW(rw);
+    Mix_PlayMusic(music_musicchunk, (loopflag == MUSIC_PlayOnce) ? 0 : -1);
+    */
+
+    musdebug("Need to use PlaySongROTT.  :(");
+
+    return(MUSIC_Ok);
+} // MUSIC_PlaySong
+
+
+extern char ApogeePath[256];
+
+#ifdef DUKE3D
+// Duke3D-specific.  --ryan.
+void PlayMusic(char *_filename)
+{
+    //char filename[MAX_PATH];
+    //strcpy(filename, _filename);
+    //FixFilePath(filename);
+
+    char filename[MAX_PATH];
+    long handle;
+    long size;
+    void *song;
+    long rc;
+
+    MUSIC_StopSong();
+
+    // Read from a groupfile, write it to disk so SDL_mixer can read it.
+    //   Lame.  --ryan.
+    handle = kopen4load(_filename, 0);
+    if (handle == -1)
+        return;
+
+    size = kfilelength(handle);
+    if (size == -1)
+    {
+        kclose(handle);
+        return;
+    } // if
+
+    song = malloc(size);
+    if (song == NULL)
+    {
+        kclose(handle);
+        return;
+    } // if
+
+    rc = kread(handle, song, size);
+    kclose(handle);
+    if (rc != size)
+    {
+        free(song);
+        return;
+    } // if
+
+    // save the file somewhere, so SDL_mixer can load it
+    GetPathFromEnvironment(filename, MAX_PATH, "tmpsong.mid");
+    handle = SafeOpenWrite(filename, filetype_binary);
+
+    SafeWrite(handle, song, size);
+    close(handle);
+    free(song);
+
+    //music_songdata = song;
+
+    music_musicchunk = Mix_LoadMUS(filename);
+    if (music_musicchunk != NULL)
+    {
+        // !!! FIXME: I set the music to loop. Hope that's okay. --ryan.
+        Mix_PlayMusic(music_musicchunk, -1);
+    } // if
+}
+#endif
+
+#ifdef ROTT
+// ROTT Special - SBF
+int MUSIC_PlaySongROTT(unsigned char *song, int size, int loopflag)
+{
+    char filename[MAX_PATH];
+    int handle;
+
+    MUSIC_StopSong();
+
+    // save the file somewhere, so SDL_mixer can load it
+    GetPathFromEnvironment(filename, ApogeePath, "tmpsong.mid");
+    handle = SafeOpenWrite(filename);
+
+    SafeWrite(handle, song, size);
+    close(handle);
+
+    music_songdata = song;
+
+    // finally, we can load it with SDL_mixer
+    music_musicchunk = Mix_LoadMUS(filename);
+    if (music_musicchunk == NULL) {
+        return MUSIC_Error;
+    }
+
+    Mix_PlayMusic(music_musicchunk, (loopflag == MUSIC_PlayOnce) ? 0 : -1);
+
+    return(MUSIC_Ok);
+} // MUSIC_PlaySongROTT
+#endif
+
+
+void MUSIC_SetContext(int context)
+{
+    musdebug("STUB ... MUSIC_SetContext().\n");
+    music_context = context;
+} // MUSIC_SetContext
+
+
+int MUSIC_GetContext(void)
+{
+    return(music_context);
+} // MUSIC_GetContext
+
+
+void MUSIC_SetSongTick(unsigned long PositionInTicks)
+{
+    musdebug("STUB ... MUSIC_SetSongTick().\n");
+} // MUSIC_SetSongTick
+
+
+void MUSIC_SetSongTime(unsigned long milliseconds)
+{
+    musdebug("STUB ... MUSIC_SetSongTime().\n");
+}// MUSIC_SetSongTime
+
+
+void MUSIC_SetSongPosition(int measure, int beat, int tick)
+{
+    musdebug("STUB ... MUSIC_SetSongPosition().\n");
+} // MUSIC_SetSongPosition
+
+
+void MUSIC_GetSongPosition(songposition *pos)
+{
+    musdebug("STUB ... MUSIC_GetSongPosition().\n");
+} // MUSIC_GetSongPosition
+
+
+void MUSIC_GetSongLength(songposition *pos)
+{
+    musdebug("STUB ... MUSIC_GetSongLength().\n");
+} // MUSIC_GetSongLength
+
+
+int MUSIC_FadeVolume(int tovolume, int milliseconds)
+{
+    Mix_FadeOutMusic(milliseconds);
+    return(MUSIC_Ok);
+} // MUSIC_FadeVolume
+
+
+int MUSIC_FadeActive(void)
+{
+    return((Mix_FadingMusic() == MIX_FADING_OUT) ? __FX_TRUE : __FX_FALSE);
+} // MUSIC_FadeActive
+
+
+void MUSIC_StopFade(void)
+{
+    musdebug("STUB ... MUSIC_StopFade().\n");
+} // MUSIC_StopFade
+
+
+void MUSIC_RerouteMidiChannel(int channel, int cdecl (*function)( int event, int c1, int c2 ))
+{
+    musdebug("STUB ... MUSIC_RerouteMidiChannel().\n");
+} // MUSIC_RerouteMidiChannel
+
+
+void MUSIC_RegisterTimbreBank(unsigned char *timbres)
+{
+    musdebug("STUB ... MUSIC_RegisterTimbreBank().\n");
+} // MUSIC_RegisterTimbreBank
+
+
+// end of fx_man.c ...
--- /dev/null
+++ b/rott/engine.c
@@ -1,0 +1,419 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+#include "rt_def.h"
+#include "watcom.h"
+#include "engine.h"
+#include "_engine.h"
+#include "rt_draw.h"
+#include "rt_door.h"
+#include "rt_stat.h"
+#include "rt_ted.h"
+#include "rt_view.h"
+#include <stdlib.h>
+//MED
+#include "memcheck.h"
+
+
+/*
+=============================================================================
+
+Global Variables                                                                                                                                 GLOBAL VARIABLES
+
+=============================================================================
+*/
+//wallcast_t posts[642];//bna++
+wallcast_t posts[800+2];//bna++
+//wallcast_t posts[321];
+int lasttilex;
+int lasttiley;
+/*
+=============================================================================
+
+Local Variables                                                                                                                                 GLOBAL VARIABLES
+
+=============================================================================
+*/
+
+static int xtilestep,ytilestep;
+static int c_vx,c_vy;
+
+void InitialCast ( void );
+void Cast ( int curx );
+
+void Interpolate (int x1, int x2)
+{
+    int i;
+    int dtexture;
+    int frac;
+    int dheight;
+    int hfrac;
+    int dx;
+
+    dx=x2-x1;
+    dtexture=(((posts[x2].texture-posts[x1].texture)<<12)+0x800)/dx;
+    dheight=(((posts[x2].wallheight-posts[x1].wallheight)<<8)+0x80)/dx;
+    frac=dtexture+(posts[x1].texture<<12);
+    hfrac=dheight+(posts[x1].wallheight<<8);
+    for (i=x1+1; i<=x2-1; i++,frac+=dtexture,hfrac+=dheight)
+    {
+        posts[i].lump=posts[x1].lump;
+        posts[i].posttype=posts[x1].posttype;
+        posts[i].offset=posts[x1].offset;
+        posts[i].alttile=posts[x1].alttile;
+        posts[i].texture=(frac>>12);
+        posts[i].wallheight=hfrac>>8;
+    }
+}
+
+void Refresh ( void )
+{
+    int x;
+
+// Cast Initial comb filter
+
+    InitialCast();
+
+    for (x=0; x<=viewwidth-4; x+=4)
+    {
+        if NOTSAMETILE(x,x+4)
+        {
+            Cast(x+2);
+            if NOTSAMETILE(x,x+2)
+            {
+                Cast(x+1);
+            }
+            else
+                Interpolate (x,x+2);
+            if NOTSAMETILE(x+2,x+4)
+            {
+                Cast(x+3);
+            }
+            else
+                Interpolate (x+2,x+4);
+        }
+        else
+            Interpolate(x,x+4);
+    }
+}
+
+
+void HitWall(int curx, int vertical, int xtile, int ytile)
+{
+    int num;
+
+    posts[curx].offset=(xtile<<7)+ytile;
+    posts[curx].lump = tilemap[xtile][ytile];
+    posts[curx].alttile=0;
+    posts[curx].posttype=0;
+
+    if (vertical<0)
+    {
+        xintercept=xtile<<16;
+        if (xtilestep<0)
+            xintercept+=0xffff;
+        yintercept=FixedScale(xintercept-viewx,c_vy,c_vx)+viewy;
+        if (posts[curx].lump & 0x4000)
+        {
+            if (tilemap[xtile-(xtilestep>>7)][ytile]&0x8000)
+            {
+                num=tilemap[xtile-(xtilestep>>7)][ytile];
+                if (num&0x4000)
+                {
+                    if (maskobjlist[num&0x3ff]->sidepic)
+                        posts[curx].lump = maskobjlist[num&0x3ff]->sidepic;
+                    else
+                        posts[curx].lump &= 0x3ff;
+                }
+                else
+                    posts[curx].lump = doorobjlist[num&0x3ff]->sidepic;
+            }
+            else
+            {
+                if (posts[curx].lump&0x1000)
+                    posts[curx].lump=animwalls[posts[curx].lump&0x3ff].texture;
+                else
+                    posts[curx].lump &= 0x3ff;
+            }
+        }
+        else if (posts[curx].lump & 0x2000)
+        {
+            if (IsWindow(xtile,ytile))
+                posts[curx].alttile=-1;
+            else
+                posts[curx].alttile=(MAPSPOT(xtile,ytile,2))+1;
+            posts[curx].lump &= 0x3ff;
+        }
+        else if (posts[curx].lump & 0x1000)
+            posts[curx].lump=animwalls[posts[curx].lump&0x3ff].texture;
+        else if (posts[curx].lump & 0x800)
+        {
+            posts[curx].lump &= 0x3ff;
+            posts[curx].posttype=2;
+        }
+        posts[curx].texture=yintercept-(ytile<<16);
+//      posts[curx].texture&=0xffff;
+        if (posts[curx].texture<0)
+            posts[curx].texture=0;
+        if (posts[curx].texture>65535)
+            posts[curx].texture=65535;
+        if (xtilestep<0)
+            posts[curx].texture^=0xffff;
+        posts[curx].posttype+=1;
+//      posts[curx].texture=(posts[curx].texture+firstcoloffset)&65535;
+    }
+    else
+    {
+        yintercept=ytile<<16;
+        if (ytilestep<0)
+            yintercept+=0xffff;
+        xintercept=FixedScale(yintercept-viewy,c_vx,c_vy)+viewx;
+        if (posts[curx].lump & 0x4000)
+        {   // check for adjacent doors
+            if (tilemap[xtile][ytile-ytilestep]&0x8000)
+            {
+                num=tilemap[xtile][ytile-ytilestep];
+                if (num&0x4000)
+                {
+                    if (maskobjlist[num&0x3ff]->sidepic)
+                        posts[curx].lump = maskobjlist[num&0x3ff]->sidepic;
+                    else
+                        posts[curx].lump &= 0x3ff;
+                }
+                else
+                    posts[curx].lump = doorobjlist[num&0x3ff]->sidepic;
+            }
+            else
+            {
+                if (posts[curx].lump&0x1000)
+                    posts[curx].lump=animwalls[posts[curx].lump&0x3ff].texture;
+                else
+                    posts[curx].lump &= 0x3ff;
+            }
+        }
+        else if (posts[curx].lump & 0x2000)
+        {
+            if (IsWindow(xtile,ytile))
+                posts[curx].alttile=-1;
+            else
+                posts[curx].alttile=(MAPSPOT(xtile,ytile,2))+1;
+            posts[curx].lump &= 0x3ff;
+        }
+        else if (posts[curx].lump & 0x1000)
+            posts[curx].lump=animwalls[posts[curx].lump&0x3ff].texture;
+        else if (posts[curx].lump & 0x800)
+        {
+            posts[curx].lump &= 0x3ff;
+            posts[curx].posttype=2;
+        }
+        posts[curx].texture=xintercept-(xtile<<16);
+//      posts[curx].texture&=0xffff;
+        if (posts[curx].texture<0)
+            posts[curx].texture=0;
+        if (posts[curx].texture>65535)
+            posts[curx].texture=65535;
+        if (ytilestep>0)
+            posts[curx].texture^=0xffff;
+//      posts[curx].posttype+=0;
+//      posts[curx].texture=(posts[curx].texture+firstcoloffset)&65535;
+    }
+    posts[curx].wallheight=CalcHeight();
+}
+
+void InitialCast ( void )
+{
+    int snx,sny;
+    int incr[2];
+    int thedir[2];
+    int cnt;
+    int grid[2];
+    int index;
+    int curx;
+
+    c_vx=c_startx;
+    c_vy=c_starty;
+    for (curx=0; curx<=viewwidth; curx+=4)
+    {
+        snx=viewx&0xffff;
+        sny=viewy&0xffff;
+
+        if (c_vx>0)
+        {
+            thedir[0]=1;
+            xtilestep=0x80;
+            snx^=0xffff;
+            incr[1]=-c_vx;
+        }
+        else
+        {
+            thedir[0]=-1;
+            xtilestep=-0x80;
+            incr[1]=c_vx;
+        }
+        if (c_vy>0)
+        {
+            thedir[1]=1;
+            ytilestep=1;
+            sny^=0xffff;
+            incr[0]=c_vy;
+        }
+        else
+        {
+            thedir[1]=-1;
+            ytilestep=-1;
+            incr[0]=-c_vy;
+        }
+        cnt=FixedMul(snx,incr[0])+FixedMul(sny,incr[1]);
+        grid[0]=viewx>>16;
+        grid[1]=viewy>>16;
+        do
+        {
+            int tile;
+
+            index=(cnt>=0);
+            cnt+=incr[index];
+            spotvis[grid[0]][grid[1]]=1;
+            grid[index]+=thedir[index];
+
+            if ((tile=tilemap[grid[0]][grid[1]])!=0)
+            {
+                if (tile&0x8000)
+                {
+                    if ( (!(tile&0x4000)) && (doorobjlist[tile&0x3ff]->action==dr_closed))
+                    {
+                        spotvis[grid[0]][grid[1]]=1;
+                        if (doorobjlist[tile&0x3ff]->flags&DF_MULTI)
+                            MakeWideDoorVisible(tile&0x3ff);
+                        do
+                        {
+                            index=(cnt>=0);
+                            cnt+=incr[index];
+                            grid[index]+=thedir[index];
+                            if ((tilemap[grid[0]][grid[1]]!=0) &&
+                                    (!(tilemap[grid[0]][grid[1]]&0x8000)) )
+                                break;
+                        }
+                        while (1);
+                        break;
+                    }
+                    else
+                        continue;
+                }
+                else
+                {
+                    mapseen[grid[0]][grid[1]]=1;
+                    break;
+                }
+            }
+        }
+        while (1);
+        HitWall(curx, cnt-incr[index], grid[0], grid[1]);
+        c_vx+=viewsin<<2;
+        c_vy+=viewcos<<2;
+    }
+}
+
+
+void Cast ( int curx )
+{
+    int snx,sny;
+    int incr[2];
+    int thedir[2];
+    int cnt;
+    int grid[2];
+    int index;
+
+    c_vx=c_startx+(curx*viewsin);
+    c_vy=c_starty+(curx*viewcos);
+    snx=viewx&0xffff;
+    sny=viewy&0xffff;
+
+    if (c_vx>0)
+    {
+        thedir[0]=1;
+        xtilestep=0x80;
+        snx^=0xffff;
+        incr[1]=-c_vx;
+    }
+    else
+    {
+        thedir[0]=-1;
+        xtilestep=-0x80;
+        incr[1]=c_vx;
+    }
+    if (c_vy>0)
+    {
+        thedir[1]=1;
+        ytilestep=1;
+        sny^=0xffff;
+        incr[0]=c_vy;
+    }
+    else
+    {
+        thedir[1]=-1;
+        ytilestep=-1;
+        incr[0]=-c_vy;
+    }
+    cnt=FixedMul(snx,incr[0])+FixedMul(sny,incr[1]);
+    grid[0]=viewx>>16;
+    grid[1]=viewy>>16;
+    do
+    {
+        int tile;
+
+        index=(cnt>=0);
+        cnt+=incr[index];
+        spotvis[grid[0]][grid[1]]=1;
+        grid[index]+=thedir[index];
+
+        if ((tile=tilemap[grid[0]][grid[1]])!=0)
+        {
+            if (tile&0x8000)
+            {
+                if ( (!(tile&0x4000)) && (doorobjlist[tile&0x3ff]->action==dr_closed))
+                {
+                    spotvis[grid[0]][grid[1]]=1;
+                    if (doorobjlist[tile&0x3ff]->flags&DF_MULTI)
+                        MakeWideDoorVisible(tile&0x3ff);
+                    do
+                    {
+                        index=(cnt>=0);
+                        cnt+=incr[index];
+                        grid[index]+=thedir[index];
+                        if ((tilemap[grid[0]][grid[1]]!=0) &&
+                                (!(tilemap[grid[0]][grid[1]]&0x8000)) )
+                            break;
+                    }
+                    while (1);
+                    break;
+                }
+                else
+                    continue;
+            }
+            else
+            {
+                mapseen[grid[0]][grid[1]]=1;
+                break;
+            }
+        }
+    }
+    while (1);
+    HitWall(curx, cnt-incr[index], grid[0], grid[1]);
+}
+
--- /dev/null
+++ b/rott/engine.h
@@ -1,0 +1,52 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+#ifndef _engine_public
+#define _engine_public
+
+#include "modexlib.h"
+//***************************************************************************
+//
+// ENGINE.C
+//
+//***************************************************************************
+
+typedef struct
+{
+    int      offset;
+    int      wallheight;
+    int      ceilingclip;
+    int      floorclip;
+    int      texture;
+    int      lump;
+    int      posttype;
+    int      alttile;
+} wallcast_t;
+extern wallcast_t posts[800+2];//bna++ JUST MAKE IT MAX RES
+//extern wallcast_t posts[642];//bna++
+//extern wallcast_t posts[321];
+
+extern int lasttilex;
+extern int lasttiley;
+
+void Refresh ( void );
+
+#define IsWindow(x,y)       (MAPSPOT((x),(y),2)==13)
+
+#endif
--- /dev/null
+++ b/rott/f_scale.h
@@ -1,0 +1,38 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+#ifndef _f_scale_public
+#define _f_scale_public
+
+extern int cin_yl;
+extern int cin_yh;
+extern int cin_ycenter;
+extern int cin_iscale;
+extern int cin_texturemid;
+extern byte * cin_source;
+
+void R_DrawFilmColumn (byte * buf);
+void DrawFilmPost (byte * buf, byte * src, int height);
+
+#if (defined __WATCOMC__)
+#pragma aux R_DrawFilmColumn parm [EDI] modify exact [eax ebx ecx edx esi edi]
+#pragma aux DrawFilmPost parm [EDI] [ESI] [ECX] modify exact [eax ecx edx edi esi ebx]
+#endif
+
+#endif
--- /dev/null
+++ b/rott/fli_def.h
@@ -1,0 +1,104 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+/* Flic.h - header file containing structure of a flic file.
+ *
+ * Copyright (c) 1992 Jim Kent.  This file may be freely used, modified,
+ * copied and distributed.  This file was first published as part of
+ * an article for Dr. Dobb's Journal March 1993 issue.
+ */
+
+#ifndef FLIC_H		/* Keep this from being included twice */
+#define FLIC_H
+
+#pragma pack (1)
+/* Flic Header */
+
+#warning fli_def structures need to be packed
+
+typedef struct
+{
+    Long	size;		/* Size of flic including this header. */
+    Ushort 	type;		/* Either FLI_TYPE or FLC_TYPE below. */
+    Ushort	frames;		/* Number of frames in flic. */
+    Ushort	width;		/* Flic width in pixels. */
+    Ushort	height;		/* Flic height in pixels. */
+    Ushort	depth;		/* Bits per pixel.  (Always 8 now.) */
+    Ushort	flags;		/* FLI_FINISHED | FLI_LOOPED ideally. */
+    Long 	speed;		/* Delay between frames. */
+    Short	reserved1;	/* Set to zero. */
+    Ulong	created;	/* Date of flic creation. (FLC only.) */
+    Ulong	creator;	/* Serial # of flic creator. (FLC only.) */
+    Ulong	updated;	/* Date of flic update. (FLC only.) */
+    Ulong	updater;	/* Serial # of flic updater. (FLC only.) */
+    Ushort	aspect_dx;	/* Width of square rectangle. (FLC only.) */
+    Ushort	aspect_dy;	/* Height of square rectangle. (FLC only.) */
+    Char 	reserved2[38];/* Set to zero. */
+    Long 	oframe1;	/* Offset to frame 1. (FLC only.) */
+    Long 	oframe2;	/* Offset to frame 2. (FLC only.) */
+    Char 	reserved3[40];/* Set to zero. */
+} FlicHead;
+/* Values for FlicHead.type */
+#define FLI_TYPE 0xAF11u	/* 320x200 .FLI type ID */
+#define FLC_TYPE 0xAF12u	/* Variable rez .FLC type ID */
+/* Values for FlicHead.flags */
+#define FLI_FINISHED 0x0001
+#define FLI_LOOPED	 0x0002
+
+/* Optional Prefix Header */
+typedef struct
+{
+    Long size;		/* Size of prefix including header. */
+    Ushort type;	/* Always PREFIX_TYPE. */
+    Short chunks;	/* Number of subchunks in prefix. */
+    Char reserved[8];/* Always 0. */
+} PrefixHead;
+/* Value for PrefixHead.type */
+#define PREFIX_TYPE  0xF100u
+
+/* Frame Header */
+typedef struct
+{
+    Long size;		/* Size of frame including header. */
+    Ushort type;	/* Always FRAME_TYPE */
+    Short chunks;	/* Number of chunks in frame. */
+    Char reserved[8];/* Always 0. */
+} FrameHead;
+/* Value for FrameHead.type */
+#define FRAME_TYPE 0xF1FAu
+
+/* Chunk Header */
+typedef struct
+{
+    Long size;		/* Size of chunk including header. */
+    Ushort type;	/* Value from ChunkTypes below. */
+} ChunkHead;
+enum ChunkTypes
+{
+    COLOR_256 = 4,	/* 256 level color pallette info. (FLC only.) */
+    DELTA_FLC = 7,	/* Word-oriented delta compression. (FLC only.) */
+    COLOR_64 = 11,	/* 64 level color pallette info. */
+    DELTA_FLI = 12,	/* Byte-oriented delta compression. */
+    BLACK = 13,		/* whole frame is color 0 */
+    BYTE_RUN = 15,	/* Byte run-length compression. */
+    LITERAL = 16,	/* Uncompressed pixels. */
+    PSTAMP = 18,	/* "Postage stamp" chunk. (FLC only.) */
+};
+
+#endif /* FLIC_H */
--- /dev/null
+++ b/rott/fli_glob.h
@@ -1,0 +1,22 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+void PlayFlic ( char * name, unsigned char * buffer, int usefile, int loop);
+
+
--- /dev/null
+++ b/rott/fli_main.c
@@ -1,0 +1,603 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+/* readflic.c - This module contains the routines to read and decompress
+ * a flic.  They assume Intel byte ordering,  but otherwise should be
+ * fairly portable.  They call machine specific stuff in pcclone.c.
+ * This file starts with the low level decompression routines - first
+ * for colors and then for pixels.  Then it goes to the higher level
+ * exported flic_xxxx routines as prototyped in readflic.h.
+ *
+ * Copyright (c) 1992 Jim Kent.  This file may be freely used, modified,
+ * copied and distributed.  This file was first published as part of
+ * an article for Dr. Dobb's Journal March 1993 issue.
+ */
+
+#include "cin_glob.h"
+#include <errno.h>
+#include <string.h>
+#include <io.h>
+#include "fli_type.h"
+#include "fli_util.h"
+#include "fli_def.h"
+#include "fli_main.h"
+//MED
+#include "memcheck.h"
+
+
+
+typedef void ColorOut(Screen *s, int start, Color  *colors, int count);
+/* This is the type of output parameter to our decode_color below.
+ * Not coincedently screen_put_color is of this type. */
+
+static void decode_color(Uchar  *data
+                         , Flic *flic, Screen *s, ColorOut *output)
+/* Decode color map.  Put results into output.  The two color
+ * compressions are identical except for whether the RGB values
+ * are 0-63 or 0-255.  Passing in an output that does the appropriate
+ * shifting on the way to the real pallete lets us use the same
+ * code for both COLOR_64 and COLOR_256 compression.
+ */
+{
+    int start = 0;
+    Uchar  *cbuf = (Uchar  *)data;
+    Short  *wp = (Short  *)cbuf;
+    Short ops;
+    int count;
+
+    ops = *wp;
+    cbuf += sizeof(*wp);
+    while (--ops >= 0)
+    {
+        start += *cbuf++;
+        if ((count = *cbuf++) == 0)
+            count = 256;
+        (*output)(s, start, (Color  *)cbuf, count);
+        cbuf += 3*count;
+        start += count;
+    }
+}
+
+static void decode_color_256(Uchar  *data, Flic *flic, Screen *s)
+/* Decode COLOR_256 chunk. */
+{
+    decode_color(data, flic, s, screen_put_colors);
+}
+
+static void decode_color_64(Uchar  *data, Flic *flic, Screen *s)
+/* Decode COLOR_64 chunk. */
+{
+    decode_color(data, flic, s, screen_put_colors_64);
+}
+
+
+static void decode_byte_run(Uchar  *data, Flic *flic, Screen *s)
+/* Byte-run-length decompression. */
+{
+    int x,y;
+    int width = flic->head.width;
+    int height = flic->head.height;
+    Char psize;
+    Char  *cpt = data;
+    int end;
+
+    y = flic->yoff;
+    end = flic->xoff + width;
+    while (--height >= 0)
+    {
+        x = flic->xoff;
+        cpt += 1;	/* skip over obsolete opcount byte */
+        psize = 0;
+        while ((x+=psize) < end)
+        {
+            psize = *cpt++;
+            if (psize >= 0)
+            {
+                screen_repeat_one(s, x, y, *cpt++, psize);
+            }
+            else
+            {
+                psize = -psize;
+                screen_copy_seg(s, x, y, (Pixel  *)cpt, psize);
+                cpt += psize;
+            }
+        }
+        y++;
+    }
+}
+
+static void decode_delta_fli(Uchar  *data, Flic *flic, Screen *s)
+/* Fli style delta decompression. */
+{
+    int xorg = flic->xoff;
+    int yorg = flic->yoff;
+    Short  *wpt = (Short  *)data;
+    Uchar  *cpt = (Uchar  *)(wpt + 2);
+    int x,y;
+    Short lines;
+    Uchar opcount;
+    Char psize;
+
+    y = yorg + *wpt++;
+    lines = *wpt;
+    while (--lines >= 0)
+    {
+        x = xorg;
+        opcount = *cpt++;
+        while (opcount > 0)
+        {
+            x += *cpt++;
+            psize = *cpt++;
+            if (psize < 0)
+            {
+                psize = -psize;
+                screen_repeat_one(s, x, y, *cpt++, psize);
+                x += psize;
+                opcount-=1;
+            }
+            else
+            {
+                screen_copy_seg(s, x, y, (Pixel  *)cpt, psize);
+                cpt += psize;
+                x += psize;
+                opcount -= 1;
+            }
+        }
+        y++;
+    }
+}
+
+
+static void decode_delta_flc(Uchar  *data, Flic *flic, Screen *s)
+/* Flc-style delta decompression.  The data is word oriented though
+* a lot of the control info (how  to skip, how many words to
+ * copy) are byte oriented still to save space. */
+{
+    int xorg = flic->xoff;
+    int yorg = flic->yoff;
+    int width = flic->head.width;
+    int x,y;
+    Short lp_count;
+    Short opcount;
+    int psize;
+    union {
+        Short  *w;
+        Uchar  *ub;
+        Char  *b;
+        Pixels2  *p2;
+    } wpt;
+    int lastx;
+
+
+    lastx = xorg + width - 1;
+    wpt.ub = data;
+    lp_count = *wpt.w++;
+    y = yorg;
+    goto LPACK;
+
+SKIPLINES:	/* Advance over some lines. */
+    y -= opcount;
+
+LPACK:		/* do next line */
+    if ((opcount = *wpt.w++) >= 0)
+        goto DO_SS2OPS;
+    if( ((Ushort)opcount) & 0x4000) /* skip lines */
+        goto SKIPLINES;
+    screen_put_dot(s,(Uchar)opcount,lastx,y); /* put dot at eol with low byte */
+    if((opcount = *wpt.w++) == 0)
+    {
+        ++y;
+        if (--lp_count > 0)
+            goto LPACK;
+        goto OUT;
+    }
+DO_SS2OPS:
+    x = xorg;
+
+PPACK:				/* do next packet */
+    x += *wpt.ub++;
+    psize = *wpt.b++;
+    if ((psize += psize) >= 0)
+    {
+        screen_copy_seg(s, x, y, (Pixel  *)wpt.ub, psize);
+        x += psize;
+        wpt.ub += psize;
+        if (--opcount != 0)
+            goto PPACK;
+        ++y;
+        if (--lp_count > 0)
+            goto LPACK;
+    }
+    else
+    {
+        psize = -psize;
+        screen_repeat_two(s, x, y, *wpt.p2++, psize>>1);
+        x += psize;
+        if (--opcount != 0)
+            goto PPACK;
+        ++y;
+        if (--lp_count > 0)
+            goto LPACK;
+    }
+OUT:
+    return;
+}
+
+static void decode_black(Uchar  *data, Flic *flic, Screen *s)
+/* Decode a BLACK chunk.  Set frame to solid color 0 one
+ * line at a time. */
+{
+    Pixels2 black;
+    int i;
+    int height = flic->head.height;
+    int width = flic->head.width;
+    int x = flic->xoff;
+    int y = flic->yoff;
+
+    black.pixels[0] = black.pixels[1] = 0;
+    for (i=0; i<height; ++i)
+    {
+        screen_repeat_two(s, x, y+i, black, width/2);
+        if (width & 1)	/* if odd set last pixel */
+            screen_put_dot(s, x+width-1, y+i, 0);
+    }
+}
+
+static void decode_literal(Uchar  *data, Flic *flic, Screen *s)
+/* Decode a LITERAL chunk.  Just copy data to screen one line at
+ * a time. */
+{
+    int i;
+    int height = flic->head.height;
+    int width = flic->head.width;
+    int x = flic->xoff;
+    int y = flic->yoff;
+
+    for (i=0; i<height; ++i)
+    {
+        screen_copy_seg(s, x, y+i, (Pixel  *)data, width);
+        data += width;
+    }
+}
+
+ErrCode SetupFlicAccess (Flic * flic)
+{
+    if (flic->usefile==TRUE)
+    {
+        return file_open_to_read(&flic->handle, flic->name);
+    }
+    else
+    {
+        flic->flicoffset=0;
+        return Success;
+    }
+}
+
+ErrCode CopyNextFlicBlock (Flic * flic, MemPtr buf, Ulong size)
+{
+    ErrCode err;
+
+    if (flic->usefile==TRUE)
+    {
+        err = file_read_big_block(flic->handle, buf, size);
+        return err;
+    }
+    else
+    {
+        memcpy(buf, flic->flicbuffer+flic->flicoffset, size);
+        flic->flicoffset+=size;
+        return Success;
+    }
+}
+
+void    SetFlicOffset (Flic * flic, Ulong offset )
+{
+    if (flic->usefile==TRUE)
+    {
+        lseek(flic->handle,offset,SEEK_SET);
+    }
+    else
+    {
+        flic->flicoffset = offset;
+    }
+}
+
+
+ErrCode flic_open(Flic *flic, char *name, MemPtr buf, Boolean usefile)
+/* Open flic file.  Read header and verify it's a flic.
+ * Seek to first frame. */
+{
+    ErrCode err;
+
+    ClearStruct(flic);		/* Start at a known state. */
+    flic->usefile=usefile;  /* use file or buffer */
+    flic->name = name;      /* Save name for future use. */
+    flic->flicbuffer=buf;   /* save address of flicbuffer */
+
+    if ((err = SetupFlicAccess (flic)) >= Success)
+    {
+        if ((err = CopyNextFlicBlock (flic, (Uchar *)&flic->head, sizeof(flic->head)))
+                >= Success)
+        {
+            if (flic->head.type == FLC_TYPE)
+            {
+                /* Seek frame 1. */
+                SetFlicOffset (flic, flic->head.oframe1 );
+                return Success;
+            }
+            if (flic->head.type == FLI_TYPE)
+            {
+                /* Do some conversion work here. */
+                flic->head.oframe1 = sizeof(flic->head);
+                flic->head.speed = flic->head.speed * 1000L / 70L;
+                return Success;
+            }
+            else
+            {
+                err = ErrBadFlic;
+            }
+        }
+    }
+    flic_close(flic);    /* Close down and scrub partially opened flic. */
+    return err;
+}
+
+
+void flic_close(Flic *flic)
+/* Close flic file and scrub flic. */
+{
+    if (flic->usefile==TRUE)
+    {
+        close(flic->handle);
+    }
+    ClearStruct(flic);		/* Discourage use after close. */
+}
+
+static ErrCode decode_frame(Flic *flic
+                            , FrameHead *frame, Uchar  *data, Screen *s)
+/* Decode a frame that is in memory already into screen.
+ * Here we just loop through each chunk calling appropriate
+ * chunk decoder.
+ */
+{
+    int i;
+    ChunkHead  *chunk;
+
+    for (i=0; i<frame->chunks; ++i)
+    {
+        chunk = (ChunkHead  *)data;
+        data += chunk->size;
+        switch (chunk->type)
+        {
+        case COLOR_256:
+            decode_color_256((Uchar  *)(chunk+1), flic, s);
+            break;
+        case DELTA_FLC:
+            decode_delta_flc((Uchar  *)(chunk+1), flic, s);
+            break;
+        case COLOR_64:
+            decode_color_64((Uchar  *)(chunk+1), flic, s);
+            break;
+        case DELTA_FLI:
+            decode_delta_fli((Uchar  *)(chunk+1), flic, s);
+            break;
+        case BLACK:
+            decode_black((Uchar  *)(chunk+1), flic, s);
+            break;
+        case BYTE_RUN:
+            decode_byte_run((Uchar  *)(chunk+1), flic, s);
+            break;
+        case LITERAL:
+            decode_literal((Uchar  *)(chunk+1), flic, s);
+            break;
+        default:
+            break;
+        }
+    }
+    return Success;
+}
+
+ErrCode flic_next_frame(Flic *flic, Screen *screen)
+/* Advance to next frame of flic. */
+{
+    FrameHead head;
+    ErrCode err;
+    MemPtr bb;
+    long size;
+
+    if ((err = CopyNextFlicBlock (flic, (Uchar *)&head, sizeof(head))) >= Success)
+    {
+        if (head.type == FRAME_TYPE)
+        {
+            size = head.size - sizeof(head);	/* Don't include head. */
+            if (size > 0)
+            {
+                if ((err = big_alloc(&bb, size)) >= Success)
+                {
+                    if ((err = CopyNextFlicBlock (flic, bb, size)) >= Success)
+                    {
+                        err = decode_frame(flic, &head, bb, screen);
+                    }
+                    big_free(&bb);
+                }
+            }
+        }
+        else
+        {
+            err = ErrBadFrame;
+        }
+    }
+    return err;
+}
+
+
+static Ulong calc_end_time(Ulong millis)
+/* Little helper subroutine to find out when to start on next
+ * frame. */
+{
+    return (GetCinematicTime() + ( (millis * CLOCKSPEED) / 4000l) );
+}
+
+static ErrCode wait_til(Ulong end_time, Machine *machine)
+/* This waits until key is hit or end_time arrives.
+ * Return Success if timed out,  ErrCancel if key hit.
+ * Insures keyboard will be polled at least once.
+ */
+{
+    do
+    {
+        if (CinematicAbort()!=0)
+            return ErrCancel;
+    }
+    while (GetCinematicTime() < end_time);
+    return Success;
+}
+
+ErrCode flic_play_once(Flic *flic, Machine *machine)
+/* Play a flic through once. */
+{
+    ErrCode err;
+    int i;
+    Ulong end_time;
+
+    for (i=0; i<flic->head.frames; ++i)
+    {
+        end_time = calc_end_time(flic->head.speed);
+        if ((err = flic_next_frame(flic, &machine->screen)) < Success)
+            break;
+        if ((err = wait_til(end_time, machine)) < Success)
+            break;
+    }
+    return err;
+}
+
+static ErrCode fill_in_frame2(Flic *flic)
+/* This figures out where the second frame of the flic is
+ * (useful for playing in a loop).  */
+{
+    FrameHead head;
+    ErrCode err;
+
+    SetFlicOffset (flic, flic->head.oframe1 );
+    if ((err = CopyNextFlicBlock (flic, (MemPtr)&head, sizeof(head))) < Success)
+        return err;
+    flic->head.oframe2 = flic->head.oframe1 + head.size;
+    return Success;
+}
+
+ErrCode flic_play_loop(Flic *flic, Machine *machine)
+/* Play a flic until key is pressed. */
+{
+    int i;
+    Ulong end_time;
+    ErrCode err;
+
+    if (flic->head.oframe2 == 0)
+    {
+        fill_in_frame2(flic);
+    }
+    /* Seek to first frame. */
+    SetFlicOffset (flic, flic->head.oframe1 );
+    /* Save time to move on. */
+    end_time = calc_end_time(flic->head.speed);
+    /* Display first frame. */
+    if ((err = flic_next_frame(flic, &machine->screen)) < Success)
+        return err;
+    for (;;)
+    {
+        /* Seek to second frame */
+        SetFlicOffset (flic, flic->head.oframe2 );
+        /* Loop from 2nd frame thru ring frame*/
+        for (i=0; i<flic->head.frames; ++i)
+        {
+            if (wait_til(end_time, machine) < Success)
+                return Success;		/* Time out is a success here. */
+            if ((err = flic_next_frame(flic, &machine->screen)) < Success)
+                return err;
+            end_time = calc_end_time(flic->head.speed);
+        }
+    }
+}
+
+
+static char *err_strings[] =
+{
+    "Unspecified error",
+    "Not enough memory",
+    "Not a flic file",
+    "Bad frame in flic",
+    NULL,
+    NULL,
+    "Couldn't open display",
+    "Couldn't open keyboard",
+    "User canceled action",
+};
+
+char *flic_err_string(ErrCode err)
+/* Return a string that describes an error. */
+{
+    if (err >= Success)
+        return "Success";		/* Shouldn't happen really... */
+    if (err == ErrOpen || err == ErrRead)
+        return strerror(errno);	/* Get Disk IO error from DOS. */
+    err = -err;
+    err -= 1;
+    if (err > ArrayEls(err_strings))
+        return "Unknown error";
+    return err_strings[err];
+}
+
+
+static void center_flic(Flic *flic, Screen *s)
+/* Set flic.xoff and flic.yoff so flic plays centered rather
+ * than in upper left corner of display. */
+{
+    flic->xoff = (screen_width(s) - (signed)flic->head.width)/2;
+    flic->yoff = (screen_height(s) - (signed)flic->head.height)/2;
+}
+
+void PlayFlic ( char * name, unsigned char * buffer, int usefile, int loop)
+{
+    ErrCode err;
+    Flic flic;
+    Machine machine;
+
+    if ((err = machine_open(&machine)) >= Success)
+    {
+        if ((err = flic_open(&flic, name, buffer, usefile)) >= Success)
+        {
+            center_flic(&flic, &machine.screen);
+            if (loop==0)
+            {
+                err = flic_play_once(&flic, &machine);
+            }
+            else
+            {
+                err = flic_play_loop(&flic, &machine);
+            }
+            flic_close(&flic);
+        }
+        machine_close(&machine);
+    }
+    if (err < Success && err != ErrCancel)
+    {
+        Error("Play Flic had troubles with %s.\n%s.\n",name, flic_err_string(err));
+    }
+}
+
--- /dev/null
+++ b/rott/fli_main.h
@@ -1,0 +1,92 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+/* Readflic.h - file containing prototypes and other
+ * structural info for readflic program.
+ *
+ * Copyright (c) 1992 Jim Kent.  This file may be freely used, modified,
+ * copied and distributed.  This file was first published as part of
+ * an article for Dr. Dobb's Journal March 1993 issue.
+ */
+
+/* Some handy macros I use in lots of programs: */
+
+#define ArrayEls(a) (sizeof(a)/sizeof((a)[0]))
+/* Count up number of elements in an array */
+
+#define ClearMem(buf,size)	memset(buf, 0, size)
+/* Clear a block of memory. */
+
+#define ClearStruct(pt)	ClearMem(pt, sizeof(*(pt)))
+/* Clear a structure (pass in pointer) */
+
+
+/* Data structures peculiar to readflic program: */
+
+typedef struct
+{
+    FlicHead head;	/* Flic file header. */
+    int handle;		/* File handle. */
+    int frame;		/* Current frame in flic. */
+    char *name;		/* Name from flic_open.  Helps error reporting. */
+    int xoff,yoff;	/* Offset to display flic at. */
+    MemPtr flicbuffer; // address of flicbuffer in memory
+    int flicoffset;
+    Boolean usefile;
+} Flic;
+
+
+/* Prototypes peculiar to readflic program: */
+
+ErrCode flic_open(Flic *flic, char *name, MemPtr buf, Boolean usefile);
+/* Open flic file.  Read header and verify it's a flic. */
+
+void flic_close(Flic *flic);
+/* Close flic file and scrub flic. */
+
+ErrCode flic_play_once(Flic *flic, Machine *machine);
+/* Play a flic through once. */
+
+ErrCode flic_play_loop(Flic *flic, Machine *machine);
+/* Play a flic until key is pressed. */
+
+ErrCode flic_next_frame(Flic *flic, Screen *screen);
+/* Advance to next frame of flic. */
+
+ErrCode SetupFlicAccess (Flic * flic);
+
+ErrCode CopyNextFlicBlock (Flic * flic, MemPtr buf, Ulong size);
+
+void    SetFlicOffset (Flic * flic, Ulong offset );
+
+
+char *flic_err_string(ErrCode err);
+
+/* Various error codes flic reader can get. */
+#define ErrNoMemory	-2		/* Not enough memory. */
+#define ErrBadFlic	-3		/* File isn't a flic. */
+#define ErrBadFrame	-4		/* Bad frame in flic. */
+#define ErrOpen		-5		/* Couldn't open file.  Check errno. */
+#define ErrRead		-6		/* Couldn't read file.  Check errno. */
+#define ErrDisplay	-7		/* Couldn't open display. */
+#define ErrClock	-8		/* Couldn't open clock. */
+#define ErrKey		-9		/* Couldn't open keyboard. */
+#define ErrCancel	-10		/* User cancelled. */
+
+
--- /dev/null
+++ b/rott/fli_type.h
@@ -1,0 +1,53 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+/* Types.h - integer types defined for portability between compilers and
+ * notational convenience.
+ *
+ * Copyright (c) 1992 Jim Kent.  This file may be freely used, modified,
+ * copied and distributed.  This file was first published as part of
+ * an article for Dr. Dobb's Journal March 1993 issue.
+ */
+
+#ifndef TYPES_H		/* Prevent file from being included twice. */
+#define TYPES_H
+
+typedef signed char Char;		/* Signed 8 bits. */
+typedef unsigned char Uchar;	/* Unsigned 8 bits. */
+typedef short Short;			/* Signed 16 bits please. */
+typedef unsigned short Ushort;	/* Unsigned 16 bits please. */
+typedef int Long;				/* Signed 32 bits. */
+typedef unsigned int Ulong;	/* Unsigned 32 bits. */
+
+typedef int Boolean;			/* TRUE or FALSE value. */
+typedef int ErrCode;			/* ErrXXX or Success. */
+typedef int FileHandle;			/* OS file handle. */
+
+/* Values for Boolean types */
+#define FALSE 0
+#define TRUE (!FALSE)
+
+/* Values for ErrCodes */
+#define Success		0		/* Things are fine. */
+#define AError     -1    /* Unclassified error. */
+
+#define int86 int386
+#define inportb inp
+#define outportb outp
+#endif /* TYPES_H */
--- /dev/null
+++ b/rott/fli_util.c
@@ -1,0 +1,414 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+/* pcclone.c - This file contains all the machine specific bits of the
+ * flic reader.  It's job is to set up data structures and routines for
+ * the Screen, Clock, and Key structures,  and the Machine structure
+ * that contains them all.
+ *
+ * For optimum performance a flic-reader should be coded in assembler.
+ * However you can get significantly greater performance merely by
+ * recoding in assembler the three routines: screen_copy_seg(),
+ * screen_repeat_one() and screen_repeat_two().
+ *
+ * Copyright (c) 1992 Jim Kent.  This file may be freely used, modified,
+ * copied and distributed.  This file was first published as part of
+ * an article for Dr. Dobb's Journal March 1993 issue.
+ */
+
+#include "cin_glob.h"
+#include <bios.h>
+#include <dos.h>
+#include <time.h>
+#include <stdlib.h>
+#include <mem.h>
+#include <limits.h>
+#include <fcntl.h>
+#include <io.h>
+#include <conio.h>
+#include "fli_type.h"
+#include "fli_util.h"
+#include "fli_def.h"
+#include "fli_main.h"
+//MED
+#include "memcheck.h"
+
+static Ushort screenlookup[200];
+
+/** Screen oriented stuff. **/
+
+static Boolean set_vmode(Uchar mode)
+/* Ask bios to set video mode. */
+{
+    union REGS regs;
+
+    regs.h.ah = 0;		/* Set Video Mode request. */
+    regs.h.al = mode;	/* For our specific mode. */
+    int86(0x10, &regs, &regs);
+    return TRUE;
+// return (regs.x.cflag == 0);	/* Carry flag clear? */
+}
+
+static Uchar get_vmode()
+/* Ask bios for current video mode. */
+{
+    union REGS regs;
+
+    regs.h.ah = 0xF;			/* Get Video Mode request. */
+    int86(0x10, &regs, &regs);
+    return regs.h.al;
+}
+
+ErrCode screen_open(Screen *s)
+/* Put machine into graphics mode and fill out screen structure. */
+{
+    ClearStruct(s);			/* Start in a known state... */
+    s->old_mode = get_vmode();
+    if (set_vmode(0x13))
+    {
+        if (get_vmode() == 0x13)
+        {
+            int i;
+
+            s->is_open = TRUE;	/* Now it's open. */
+            s->width = 320;
+            s->height = 200;
+            for (i=0; i<200; i++)
+                screenlookup[i]=320*i;
+            s->pixels = (unsigned char *)0xA0000;  /* Base video screen address. */
+            return Success;
+        }
+    }
+    /* If got to here have failed.  Restore old video mode and return
+     * failure code. */
+    set_vmode(s->old_mode);
+    return ErrDisplay;
+}
+
+void screen_close(Screen *s)
+/* Close screen.  Restore original display mode. */
+{
+    if (s->is_open)		/* Don't do this twice... */
+    {
+//   set_vmode(s->old_mode);
+        ClearStruct(s);		/* Discourage use after it's closed... */
+    }
+}
+
+int screen_width(Screen *s)
+/* Return width of screen. */
+{
+    return s->width;
+}
+
+int screen_height(Screen *s)
+/* Return height of screen. */
+{
+    return s->height;
+}
+
+void screen_put_dot(Screen *s, int x, int y, Pixel color)
+/* Set one dot. */
+{
+    /* First clip it. */
+    if (x < 0 || y < 0 || x >= s->width || y >= s->height)
+        return;
+
+    /* Then set it. */
+    s->pixels[screenlookup[y] + x] = color;
+}
+
+static Boolean line_clip(Screen *s, int *px, int *py, int *pwidth)
+/* Clip a horizontal line segment so that it fits on the screen.
+ * Return FALSE if clipped out entirely. */
+{
+    int x = *px;
+    int y = *py;
+    int width = *pwidth;
+    int xend = x + width;
+
+    if (y < 0 || y >= s->height || xend < 0 || x >= s->width)
+        return FALSE;	/* Clipped off screen. */
+    if (x < 0)
+    {
+        *pwidth = width = width + x;		/* and shortens width. */
+        *px = 0;
+    }
+    if (xend > s->width)
+    {
+        *pwidth = width = width - (xend - s->width);
+    }
+    if (width < 0)
+        return FALSE;
+    return TRUE;
+}
+
+void screen_copy_seg(Screen *s, int x, int y, Pixel  *pixels, int count)
+/* Copy pixels from memory into screen. */
+{
+    Pixel  *pt;
+    int unclipped_x = x;
+
+    /* First let's do some clipping. */
+    if (!line_clip(s, &x, &y, &count))
+        return;
+
+    pixels += (x - unclipped_x);   /* Clipping change in start position. */
+
+    /* Calculate start screen address. */
+    pt = s->pixels + (unsigned)screenlookup[y] + (unsigned)x;
+
+    /* Copy pixels to display. */
+    memcpy (pt,pixels,count);
+}
+
+void screen_repeat_one(Screen *s, int x, int y, Pixel color, int count)
+/* Draw a horizontal line of a solid color */
+{
+    Pixel  *pt;
+
+    /* First let's do some clipping. */
+    if (!line_clip(s, &x, &y, &count))
+        return;
+
+    /* Calculate start screen address. */
+    pt = s->pixels + (unsigned)screenlookup[y] + (unsigned)x;
+
+    /* Repeat pixel on display. */
+    memset (pt,color,count);
+}
+
+void screen_repeat_two(Screen *s, int x, int y, Pixels2 pixels2, int count)
+/* Repeat 2 pixels count times on screen. */
+{
+    Pixels2  *pt;
+    int is_odd;
+
+    /* First let's do some clipping. */
+    count <<= 1;		/* Convert from word to pixel count. */
+    if (!line_clip(s, &x, &y, &count))
+        return;
+    is_odd = (count&1);		/* Did it turn odd after clipping?  Ack! */
+    count >>= 1;			/* Convert back to word count. */
+
+    /* Calculate start screen address. */
+    pt = (Pixels2  *)(s->pixels + (unsigned)screenlookup[y] + (unsigned)x);
+
+    while (--count >= 0)	/* Go set screen 2 pixels at a time. */
+        *pt++ = pixels2;
+
+    if (is_odd)				/* Deal with pixel at end of screen if needed. */
+    {
+        Pixel  *end = (Pixel  *)pt;
+        *end = pixels2.pixels[0];
+    }
+}
+
+
+void screen_put_colors(Screen *s, int start, Color  *colors, int count)
+/* Set count colors in color map starting at start.  RGB values
+ * go from 0 to 255. */
+{
+    int end = start + count;
+    int ix;
+
+    for (ix = start; ix < end; ++ix)
+    {
+        outportb(0x3C8, ix);
+        outportb(0x3C9, colors->r>>2);
+        outportb(0x3C9, colors->g>>2);
+        outportb(0x3C9, colors->b>>2);
+        ++colors;
+    }
+}
+
+void screen_put_colors_64(Screen *s, int start, Color  *colors, int count)
+/* Set count colors in color map starting at start.  RGB values
+ * go from 0 to 64. */
+{
+    int end = start + count;
+    int ix;
+
+    for (ix = start; ix < end; ++ix)
+    {
+        outportb(0x3C8, ix);
+        outportb(0x3C9, colors->r);
+        outportb(0x3C9, colors->g);
+        outportb(0x3C9, colors->b);
+        ++colors;
+    }
+}
+
+#if 0
+/** Clock oriented stuff. **/
+
+#define CMODE	0x43
+#define CDATA	0x40
+
+ErrCode clock_open(Clock *c)
+/* Set up clock and store speed of clock.  */
+{
+    c->speed = 4608;        /* Our peculiar speed.  */
+    outportb(CMODE, 0x34);  /* Change from divide by two to linear. */
+    outportb(CDATA, 0);     /* Set period to highest available. */
+    outportb(CDATA, 0);
+    return Success;
+}
+
+void clock_close(Clock *c)
+/* Return clock to normal. */
+{
+    outportb(CMODE, 0x36);  /* Change from linear to divide by two. */
+    outportb(CDATA, 0);     /* Set period to highest available. */
+    outportb(CDATA, 0);
+}
+
+Ulong clock_ticks(Clock *c)
+/* Get current clock tick. */
+{
+    /* This routine returns a clock with occassional spikes where time will
+     * look like its running backwards 1/18th of a second.  The resolution
+     * of the clock is 1/(18*256) = 1/4608 second.  The spikes are ok for
+     * our purposes since the wait loop will just ignore them. */
+    union REGS regs;
+    Uchar chip_time;
+    Ulong time;
+
+    regs.h.ah = 0;				/* Go ask BIOS timer services */
+    int86(0x1A, &regs, &regs);	/* for time in 1/18ths second. */
+    outportb(CMODE,0);			/* Latch time at timer chip. */
+    inportb(CDATA);				/* Read in LSB of chip time and discard. */
+    chip_time = inportb(CDATA);	/* Read in MSB of chip time and save. */
+    chip_time = -(signed char)chip_time;
+    /* We calculate the time using 3 bytes from the BIOS 18hz counter
+     * and one byte from the timer chip itself.  We discard the hi
+     * byte of the BIOS time,  shift the rest left by 8, and
+     * fill in the low byte with the MSB from the chip timer.
+     * This looks a little more complicated than this because
+     * the bios time is in various registers - cx for the hi word
+     * and dx for the low word. */
+    time = (Ulong)regs.h.cl << 24L;		/* Get MSB of our final time. */
+    time += (Ulong)regs.w.dx << 8L;     /* Fold in middle two bytes. */
+    time += (Ulong)chip_time;			/* Add in LSB from chip. */
+    return time;
+}
+
+
+/** Keyboard oriented stuff. **/
+
+ErrCode key_open(Key *key)
+/* Set up keyboard. */
+{
+    return Success;		/* Pretty easy on a PC. */
+}
+
+void key_close(Key *key)
+/* Close keyboard. */
+{
+    return;				/* Also very easy under DOS. */
+}
+
+Boolean key_ready(Key *key)
+/* See if a key is ready. */
+{
+    unsigned val;
+
+    if ((val = _bios_keybrd(_KEYBRD_READY)) == 0)
+        return FALSE;
+    else
+    {
+        key->ascii = val;
+        key->scancode = val;
+        return TRUE;
+    }
+}
+
+Uchar key_read(Key *key)
+/* Get next key. */
+{
+    unsigned val;
+
+    val = _bios_keybrd(_KEYBRD_READ);
+    key->ascii = val;
+    key->scancode = val;
+    return key->ascii;
+}
+
+#endif
+
+/** MemPtr stuff - to allocate and free blocks of memory > 64K. */
+
+ErrCode big_alloc(MemPtr *bb, Ulong size)
+/* Allocate a big block. */
+{
+    (*bb) = SafeMalloc (size);
+    return Success;
+}
+
+void big_free(MemPtr *bb)
+/* Free up a big block. */
+{
+    SafeFree(*bb);
+}
+
+/** Stuff for reading files - regular and over 64k blocks at a time. **/
+
+ErrCode file_open_to_read(FileHandle *phandle, char *name)
+/* Open a binary file to read. */
+{
+    *phandle = SafeOpenRead(name);
+    return Success;
+}
+
+ErrCode file_read_big_block(FileHandle handle, MemPtr bb, Ulong size)
+/* Read in a big block.  Could be bigger than 64K. */
+{
+    SafeRead (handle,bb,size);
+    return Success;
+}
+
+
+/** Machine oriented stuff - open and close the whole banana. **/
+
+ErrCode machine_open(Machine *machine)
+/* Open up machine: keyboard, clock, and screen. */
+{
+    ErrCode err;
+
+    ClearStruct(machine);	/* Start it in a known state. */
+//if ((err = key_open(&machine->key)) >= Success)
+    {
+//   if ((err = clock_open(&machine->clock)) >= Success)
+        {
+            if ((err = screen_open(&machine->screen)) >= Success)
+                return Success;
+//      clock_close(&machine->clock);
+        }
+//   key_close(&machine->key);
+    }
+    return err;
+}
+
+void machine_close(Machine *machine)
+/* Close down machine. */
+{
+    screen_close(&machine->screen);
+//clock_close(&machine->clock);
+//key_close(&machine->key);
+}
--- /dev/null
+++ b/rott/fli_util.h
@@ -1,0 +1,164 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+/* pcclone.h - machine specific parts of readflic.  Structures and
+ * prototypes for polling the keyboard,  checking the time,
+ * writing to the video screen, allocating large blocks of memory
+ * and reading files.
+ *
+ * Copyright (c) 1992 Jim Kent.  This file may be freely used, modified,
+ * copied and distributed.  This file was first published as part of
+ * an article for Dr. Dobb's Journal March 1993 issue.
+ */
+
+#ifndef PCCLONE_H	/* Prevent file from being included twice. */
+#define PCCLONE_H
+
+typedef Uchar Pixel;			/* Pixel type. */
+
+typedef struct
+{
+    Uchar r,g,b;
+} Color;					/* One color map entry r,g,b 0-255. */
+
+typedef struct
+{
+    Pixel pixels[2];
+} Pixels2;					/* For word-oriented run length encoding */
+
+typedef struct
+{
+    Pixel  *pixels;   /* Set to AOOO:0000 for hardware. */
+    int width, height;	/* Dimensions of screen. (320x200) */
+    int old_mode;		/* Mode screen was in originally. */
+    Boolean is_open;	/* Is screen open? */
+} Screen;					/* Device specific screen type. */
+
+
+/* Prototypes for routines that work on display screen. */
+
+ErrCode screen_open(Screen *s);
+/* Put machine into graphics mode and fill out screen structure. */
+
+void screen_close(Screen *s);
+/* Close screen.  Restore original display mode. */
+
+int screen_width(Screen *s);
+/* Return width of screen. */
+
+int screen_height(Screen *s);
+/* Return height of screen. */
+
+void screen_put_dot(Screen *s, int x, int y, Pixel color);
+/* Set one dot. */
+
+void screen_copy_seg(Screen *s, int x, int y, Pixel  *pixels, int count);
+/* Copy pixels from memory into screen. */
+
+void screen_repeat_one(Screen *s, int x, int y, Pixel color, int count);
+/* Draw a horizontal line of a solid color */
+
+void screen_repeat_two(Screen *s, int x,int y, Pixels2 pixels2, int count);
+/* Repeat 2 pixels count times on screen. */
+
+void screen_put_colors(Screen *s, int start, Color  *colors, int count);
+/* Set count colors in color map starting at start.  RGB values
+ * go from 0 to 255. */
+
+void screen_put_colors_64(Screen *s, int start, Color  *colors, int count);
+/* Set count colors in color map starting at start.  RGB values
+ * go from 0 to 64. */
+
+
+/* Clock structure and routines. */
+
+typedef struct
+{
+    Ulong speed;	/* Number of clock ticks per second. */
+} Clock;
+
+ErrCode clock_open(Clock *clock);
+/* Set up millisecond clock. */
+
+void clock_close(Clock *clock);
+/* Return clock to normal. */
+
+Ulong clock_ticks(Clock *clock);
+/* Get time in terms of clock->speed. */
+
+/* Keyboard structure and routines. */
+
+typedef struct
+{
+    Uchar ascii;
+    Ushort scancode;
+} Key;
+
+ErrCode key_open(Key *key);
+/* Set up keyboard. */
+
+void key_close(Key *key);
+/* Close keyboard. */
+
+Boolean key_ready(Key *key);
+/* See if a key is ready. */
+
+Uchar key_read(Key *key);
+/* Get next key. */
+
+
+/** MemPtr - handles allocating big blocks of memory (>64K) on the
+ ** PC.  On other machines may be much simpler. */
+
+typedef Uchar * MemPtr;
+
+ErrCode big_alloc(MemPtr *bb, Ulong size);
+/* Allocate a big block. */
+
+void big_free(MemPtr *bb);
+/* Free up a big block. */
+
+/** Stuff for reading files - regular and over 64k blocks at a time. **/
+
+ErrCode file_open_to_read(FileHandle *phandle, char *name);
+/* Open a binary file to read. */
+
+ErrCode file_read_block(FileHandle handle, void  *block, unsigned size);
+/* Read in a block.  If read less than size return error code. */
+
+ErrCode file_read_big_block(FileHandle handle, MemPtr bb, Ulong size);
+/* Read in a big block.  Could be bigger than 64K. */
+
+
+
+/** Machine structure - contains all the machine dependent stuff. **/
+
+typedef struct
+{
+    Screen screen;
+    Clock clock;
+    Key key;
+} Machine;
+
+ErrCode machine_open(Machine *machine);
+/* Open up machine: keyboard, clock, screen. */
+
+void machine_close(Machine *machine);
+/* Close down machine. */
+#endif /* PCCLONE_H */
--- /dev/null
+++ b/rott/fx_man.c
@@ -1,0 +1,1307 @@
+/*
+ * A reimplementation of Jim Dose's FX_MAN routines, using  SDL_mixer 1.2.
+ *   Whee. FX_MAN is also known as the "Apogee Sound System", or "ASS" for
+ *   short. How strangely appropriate that seems.
+ *
+ * Written by Ryan C. Gordon. (icculus@clutteredmind.org)
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <assert.h>
+
+#if (defined __WATCOMC__)
+#include "dukesnd_watcom.h"
+#endif
+
+#if (!defined __WATCOMC__)
+#define cdecl
+#endif
+
+#include "SDL.h"
+#include "SDL_mixer.h"
+#include "rt_def.h"      // ROTT music hack
+#include "rt_cfg.h"      // ROTT music hack
+#include "rt_util.h"     // ROTT music hack
+#include "fx_man.h"
+#include "music.h"
+
+#define __FX_TRUE  (1 == 1)
+#define __FX_FALSE (!__FX_TRUE)
+
+#define DUKESND_DEBUG       "DUKESND_DEBUG"
+
+#ifndef min
+#define min(a, b)  (((a) < (b)) ? (a) : (b))
+#endif
+
+#ifndef max
+#define max(a, b)  (((a) > (b)) ? (a) : (b))
+#endif
+
+typedef struct __DUKECHANINFO
+{
+    int in_use;                 // 1 or 0.
+    int priority;               // priority, defined by application.
+    Uint32 birthday;            // ticks when channel was grabbed.
+    unsigned long callbackval;  // callback value from application.
+} duke_channel_info;
+
+
+static char warningMessage[80];
+static char errorMessage[80];
+static int fx_initialized = 0;
+static int numChannels = MIX_CHANNELS;
+static void (*callback)(unsigned long);
+static int reverseStereo = 0;
+static int reverbDelay = 256;
+static int reverbLevel = 0;
+static int fastReverb = 0;
+static FILE *debug_file = NULL;
+static int initialized_debugging = 0;
+static int maxReverbDelay = 256;
+static int mixerIsStereo = 1;
+static duke_channel_info *chaninfo = NULL;
+
+#define HandleOffset       1
+
+/* these come from the real ASS */
+#define MV_MaxPanPosition  31
+#define MV_NumPanPositions ( MV_MaxPanPosition + 1 )
+#define MV_MaxVolume       63
+
+#define MIX_VOLUME( volume ) \
+   ( ( max( 0, min( ( volume ), 255 ) ) * ( MV_MaxVolume + 1 ) ) >> 8 )
+
+typedef struct
+{
+    unsigned char left;
+    unsigned char right;
+} Pan;
+
+static Pan MV_PanTable[ MV_NumPanPositions ][ MV_MaxVolume + 1 ];
+
+static void MV_CalcPanTable
+(
+    void
+)
+
+{
+    int   level;
+    int   angle;
+    int   distance;
+    int   HalfAngle;
+    int   ramp;
+
+    HalfAngle = ( MV_NumPanPositions / 2 );
+
+    for( distance = 0; distance <= MV_MaxVolume; distance++ )
+    {
+        level = ( 255 * ( MV_MaxVolume - distance ) ) / MV_MaxVolume;
+        for( angle = 0; angle <= HalfAngle / 2; angle++ )
+        {
+            ramp = level - ( ( level * angle ) /
+                             ( MV_NumPanPositions / 4 ) );
+
+            MV_PanTable[ angle ][ distance ].left = ramp;
+            MV_PanTable[ HalfAngle - angle ][ distance ].left = ramp;
+            MV_PanTable[ HalfAngle + angle ][ distance ].left = level;
+            MV_PanTable[ MV_MaxPanPosition - angle ][ distance ].left = level;
+
+            MV_PanTable[ angle ][ distance ].right = level;
+            MV_PanTable[ HalfAngle - angle ][ distance ].right = level;
+            MV_PanTable[ HalfAngle + angle ][ distance ].right = ramp;
+            MV_PanTable[ MV_MaxPanPosition - angle ][ distance ].right = ramp;
+        }
+    }
+}
+/* end ASS copy-pastage */
+
+#ifdef __WATCOMC__
+#pragma aux (__cdecl) channelDoneCallback;
+#endif
+
+// This function is called whenever an SDL_mixer channel completes playback.
+//  We use this for state management and calling the application's callback.
+static void channelDoneCallback(int channel)
+{
+    Mix_FreeChunk(Mix_GetChunk(channel));
+    if (callback)
+    {
+        callback(chaninfo[channel].callbackval);
+        chaninfo[channel].in_use = 0;
+    } // if
+} // channelDoneCallback
+
+
+// This gets called all over the place for information and debugging messages.
+//  If the user set the DUKESND_DEBUG environment variable, the messages
+//  go to the file that is specified in that variable. Otherwise, they
+//  are ignored for the expense of the function call. If DUKESND_DEBUG is
+//  set to "-" (without the quotes), then the output goes to stdout.
+static void snddebug(const char *fmt, ...) __attribute__((format(printf,1,2)));
+static void snddebug(const char *fmt, ...)
+{
+    va_list ap;
+
+    if (debug_file)
+    {
+        fprintf(debug_file, "DUKESND: ");
+        va_start(ap, fmt);
+        vfprintf(debug_file, fmt, ap);
+        va_end(ap);
+        fprintf(debug_file, "\n");
+        fflush(debug_file);
+    } // if
+} // snddebug
+
+
+// FIXME: Consolidate this code.
+// Same as snddebug(), but a different tag is put on each line.
+static void musdebug(const char *fmt, ...) __attribute__((format(printf,1,2)));
+static void musdebug(const char *fmt, ...)
+{
+    va_list ap;
+
+    if (debug_file)
+    {
+        fprintf(debug_file, "DUKEMUS: ");
+        va_start(ap, fmt);
+        vfprintf(debug_file, fmt, ap);
+        va_end(ap);
+        fprintf(debug_file, "\n");
+        fflush(debug_file);
+    } // if
+} // snddebug
+
+
+static void init_debugging(void)
+{
+    const char *envr;
+
+    if (initialized_debugging)
+        return;
+
+    envr = getenv(DUKESND_DEBUG);
+    if (envr != NULL)
+    {
+        if (strcmp(envr, "-") == 0)
+            debug_file = stdout;
+        else
+            debug_file = fopen(envr, "w");
+
+        if (debug_file == NULL)
+            fprintf(stderr, "DUKESND: -WARNING- Could not open debug file!\n");
+        else
+            setbuf(debug_file, NULL);
+    } // if
+
+    initialized_debugging = 1;
+} // init_debugging
+
+
+// find an available SDL_mixer channel, and reserve it.
+//  This would be a race condition, but hey, it's for a DOS game.  :)
+static int grabMixerChannel(int priority)
+{
+    int replaceable = -1;
+    int i;
+
+    for (i = 0; i < numChannels; i++)
+    {
+        if (chaninfo[i].in_use == 0)
+        {
+            chaninfo[i].in_use = 1;
+            chaninfo[i].priority = priority;
+            chaninfo[i].birthday = SDL_GetTicks();
+            return(i);
+        } // if
+
+        // !!! FIXME: Should this just be lower priority, or equal too?
+        if (chaninfo[i].priority <= priority)
+        {
+            if ((replaceable == -1) ||
+                    (chaninfo[i].birthday < chaninfo[replaceable].birthday))
+            {
+                replaceable = i;
+            } // if
+        } // if
+    } // for
+
+    // if you land here, all mixer channels are playing...
+    if (replaceable != -1)  // nothing expendable right now.
+    {
+        chaninfo[replaceable].in_use = 1;
+        chaninfo[replaceable].priority = priority;
+        chaninfo[replaceable].birthday = SDL_GetTicks();
+    } // if
+
+    return(replaceable);
+} // grabMixerChannel
+
+
+// !!! FIXME: Is this correct behaviour?
+char *FX_ErrorString( int ErrorNumber )
+{
+    switch (ErrorNumber)
+    {
+    case FX_Warning:
+        return(warningMessage);
+
+    case FX_Error:
+        return(errorMessage);
+
+    case FX_Ok:
+        return("OK; no error.");
+
+    case FX_ASSVersion:
+        return("Incorrect sound library version.");
+
+    case FX_BlasterError:
+        return("SoundBlaster Error.");
+
+    case FX_SoundCardError:
+        return("General sound card error.");
+
+    case FX_InvalidCard:
+        return("Invalid sound card.");
+
+    case FX_MultiVocError:
+        return("Multiple voc error.");
+
+    case FX_DPMI_Error:
+        return("DPMI error.");
+
+    default:
+        return("Unknown error.");
+    } // switch
+
+    assert(0);    // shouldn't hit this point.
+    return(NULL);
+} // FX_ErrorString
+
+
+static void setWarningMessage(const char *msg)
+{
+    strncpy(warningMessage, msg, sizeof (warningMessage));
+    // strncpy() doesn't add the null char if there isn't room...
+    warningMessage[sizeof (warningMessage) - 1] = '\0';
+    snddebug("Warning message set to [%s].", warningMessage);
+} // setErrorMessage
+
+
+static void setErrorMessage(const char *msg)
+{
+    strncpy(errorMessage, msg, sizeof (errorMessage));
+    // strncpy() doesn't add the null char if there isn't room...
+    errorMessage[sizeof (errorMessage) - 1] = '\0';
+    snddebug("Error message set to [%s].", errorMessage);
+} // setErrorMessage
+
+int FX_SetupCard( int SoundCard, fx_device *device )
+{
+    init_debugging();
+
+    snddebug("FX_SetupCard looking at card id #%d...", SoundCard);
+
+    if (device == NULL)  // sanity check.
+    {
+        setErrorMessage("fx_device is NULL in FX_SetupCard!");
+        return(FX_Error);
+    } // if
+
+    // Since the actual hardware is abstracted out on modern operating
+    //  systems, we just pretend that the system's got a SoundScape.
+    //  I always liked that card, even though Ensoniq screwed me on OS/2
+    //  drivers back in the day.  :)
+    if (SoundCard != SoundScape)
+    {
+        setErrorMessage("Card not found.");
+        snddebug("We pretend to be an Ensoniq SoundScape only.");
+        return(FX_Error);
+    } // if
+
+    device->MaxVoices = 8;
+    device->MaxSampleBits = 16;       // SDL_mixer downsamples if needed.
+    device->MaxChannels = 2;          // SDL_mixer converts to mono if needed.
+
+    return(FX_Ok);
+} // FX_SetupCard
+
+
+static void output_versions(const char *libname, const SDL_version *compiled,
+                            const SDL_version *linked)
+{
+    snddebug("This program was compiled against %s %d.%d.%d,\n"
+             " and is dynamically linked to %d.%d.%d.\n", libname,
+             compiled->major, compiled->minor, compiled->patch,
+             linked->major, linked->minor, linked->patch);
+}
+
+
+static void output_version_info(void)
+{
+    SDL_version compiled;
+    const SDL_version *linked;
+
+    snddebug("Library check...");
+
+    SDL_VERSION(&compiled);
+    linked = SDL_Linked_Version();
+    output_versions("SDL", &compiled, linked);
+
+    MIX_VERSION(&compiled);
+    linked = Mix_Linked_Version();
+    output_versions("SDL_mixer", &compiled, linked);
+} // output_version_info
+
+
+int FX_Init(int SoundCard, int numvoices, int numchannels,
+            int samplebits, unsigned mixrate)
+{
+    Uint16 audio_format = 0;
+    int blocksize;
+
+    init_debugging();
+
+    snddebug("INIT! card=>%d, voices=>%d, chan=>%d, bits=>%d, rate=>%du...",
+             SoundCard, numvoices, numchannels, samplebits, mixrate);
+
+    if (fx_initialized)
+    {
+        setErrorMessage("Sound system is already initialized.");
+        return(FX_Error);
+    } // if
+
+    if (SoundCard != SoundScape) // We pretend there's a SoundScape installed.
+    {
+        setErrorMessage("Card not found.");
+        snddebug("We pretend to be an Ensoniq SoundScape only.");
+        return(FX_Error);
+    } // if
+
+    // other sanity checks...
+    if ((numvoices < 0) || (numvoices > 8))
+    {
+        setErrorMessage("Invalid number of voices to mix (must be 0-8).");
+        return(FX_Error);
+    } // if
+
+    if ((numchannels != MonoFx) && (numchannels != StereoFx))
+    {
+        setErrorMessage("Invalid number of channels (must be 1 or 2).");
+        return(FX_Error);
+    } // if
+
+    if ((samplebits != 8) && (samplebits != 16))
+    {
+        setErrorMessage("Invalid sample size (must be 8 or 16).");
+        return(FX_Error);
+    } // if
+
+    // build pan tables
+    MV_CalcPanTable();
+
+    SDL_ClearError();
+    if (SDL_Init(SDL_INIT_AUDIO) < 0)
+    {
+        setErrorMessage("SDL_Init(SDL_INIT_AUDIO) failed!");
+        snddebug("SDL_GetError() reports: [%s].", SDL_GetError());
+        return(FX_Error);
+    } // if
+
+    audio_format = (samplebits == 8) ? AUDIO_U8 : AUDIO_S16SYS;
+    if (Mix_OpenAudio(mixrate, audio_format, numchannels, 256) < 0)
+    {
+        setErrorMessage(SDL_GetError());
+        return(FX_Error);
+    } // if
+
+    output_version_info();
+
+    numChannels = Mix_AllocateChannels(numvoices);
+    if (numChannels != numvoices)
+    {
+        setErrorMessage(SDL_GetError());
+        Mix_CloseAudio();
+        return(FX_Error);
+    } // if
+
+    blocksize = sizeof (duke_channel_info) * numvoices;
+    chaninfo = malloc(blocksize);
+    if (chaninfo == NULL)  // uhoh.
+    {
+        setErrorMessage("Out of memory");
+        Mix_CloseAudio();
+        return(FX_Error);
+    } // if
+    memset(chaninfo, '\0', blocksize);
+
+    Mix_ChannelFinished(channelDoneCallback);
+    maxReverbDelay = (int) (((float) mixrate) * 0.5);
+
+    Mix_QuerySpec(NULL, NULL, &mixerIsStereo);
+    mixerIsStereo = (mixerIsStereo == 2);
+
+    fx_initialized = 1;
+    return(FX_Ok);
+} // FX_Init
+
+
+int FX_Shutdown( void )
+{
+    snddebug("shutting down sound subsystem.");
+
+    if (!fx_initialized)
+    {
+        setErrorMessage("Sound system is not currently initialized.");
+        return(FX_Error);
+    } // if
+
+    Mix_CloseAudio();
+    callback = NULL;
+    free(chaninfo);
+    chaninfo = NULL;
+    reverseStereo = 0;
+    reverbLevel = 0;
+    fastReverb = 0;
+    fx_initialized = 0;
+    maxReverbDelay = 256;
+    return(FX_Ok);
+} // FX_Shutdown
+
+
+int FX_SetCallBack(void (*func)(unsigned long))
+{
+    callback = func;
+    return(FX_Ok);
+} // FX_SetCallBack
+
+
+void FX_SetVolume(int volume)
+{
+    snddebug("setting master volume to %f.2 percent.", (volume / 255.0) * 100);
+    Mix_Volume(-1, volume >> 1);  // it's 0-128 in SDL_mixer, not 0-255.
+} // FX_SetVolume
+
+
+int FX_GetVolume(void)
+{
+    return(Mix_Volume(-1, -1) << 1);
+} // FX_GetVolume
+
+
+void FX_SetReverseStereo(int setting)
+{
+    snddebug("Reverse stereo set to %s.\n", setting ? "ON" : "OFF");
+    Mix_SetReverseStereo(MIX_CHANNEL_POST, setting);
+    reverseStereo = setting;
+} // FX_SetReverseStereo
+
+
+int FX_GetReverseStereo(void)
+{
+    return(reverseStereo);
+} // FX_GetReverseStereo
+
+
+void FX_SetReverb(int reverb)
+{
+    reverbLevel = reverb;
+    fastReverb = 0;
+
+#if 1
+    // !!! FIXME
+    if (reverbLevel)
+        setWarningMessage("reverb filter is not yet implemented!");
+#endif
+} // FX_SetReverb
+
+
+void FX_SetFastReverb(int reverb)
+{
+    reverbLevel = reverb;
+    fastReverb = 1;
+
+#if 1
+    // !!! FIXME
+    if (reverbLevel)
+        setWarningMessage("fast reverb filter is not yet implemented!");
+#endif
+} // FX_SetFastReverb
+
+
+int FX_GetMaxReverbDelay(void)
+{
+    return(maxReverbDelay);
+} // FX_GetMaxReverbDelay
+
+
+int FX_GetReverbDelay(void)
+{
+    return(reverbDelay);
+} // FX_GetReverbDelay
+
+
+void FX_SetReverbDelay(int delay)
+{
+    // !!! FIXME: Should I be clamping these values?
+    if (delay < 256)
+        delay = 256;
+
+    if (delay > maxReverbDelay)
+        delay = maxReverbDelay;
+
+    reverbDelay = delay;
+
+#if 1
+    // !!! FIXME
+    setWarningMessage("reverb delay is not yet implemented!");
+#endif
+} // FX_SetReverbDelay
+
+
+int FX_VoiceAvailable(int priority)
+{
+    int chan = grabMixerChannel(priority);
+    int rc = (chan != -1);
+
+    if (rc)
+        chaninfo[chan].in_use = 0;
+
+    return(rc);
+} // FX_VoiceAvailable
+
+
+static int doSetPan(int handle, int vol, int left,
+                    int right, int checkIfPlaying)
+{
+    int retval = FX_Warning;
+
+    if ((handle < 0) || (handle >= numChannels))
+        setWarningMessage("Invalid handle in doSetPan().");
+    else if ((checkIfPlaying) && (!Mix_Playing(handle)))
+        setWarningMessage("voice is no longer playing in doSetPan().");
+    else
+    {
+        if (mixerIsStereo)
+        {
+            if ((left < 0) || (left > 255) ||
+                    (right < 0) || (right > 255))
+            {
+                setErrorMessage("Invalid argument to FX_SetPan().");
+                retval = FX_Error;
+            } // if
+
+            else
+            {
+                Mix_SetPanning(handle, left, right);
+            } // else
+        } // if
+        else
+        {
+            if ((vol < 0) || (vol > 255))
+            {
+                setErrorMessage("Invalid argument to FX_SetPan().");
+                retval = FX_Error;
+            } // if
+            else
+            {
+                // volume must be from 0-128, so the ">> 1" converts.
+                Mix_Volume(handle, vol >> 1);
+            } // else
+        } // else
+
+        retval = FX_Ok;
+    } // else
+
+    return(retval);
+} // doSetPan
+
+
+int FX_SetPan(int handle, int vol, int left, int right)
+{
+    return(doSetPan(handle - HandleOffset, vol, left, right, 1));
+} // FX_SetPan
+
+
+int FX_SetPitch(int handle, int pitchoffset)
+{
+    snddebug("FX_SetPitch() ... NOT IMPLEMENTED YET!");
+    return(FX_Ok);
+} // FX_SetPitch
+
+
+int FX_SetFrequency(int handle, int frequency)
+{
+    snddebug("FX_SetFrequency() ... NOT IMPLEMENTED YET!");
+    return(FX_Ok);
+} // FX_SetFrequency
+
+
+
+// If this returns FX_Ok, then chunk and chan will be filled with the
+//  the block of audio data in the format desired by the audio device
+//  and the SDL_mixer channel it will play on, respectively.
+//  If the value is not FX_Ok, then the warning or error message is set,
+//  and you should bail.
+// size added by SBF for ROTT
+static int setupVocPlayback(char *ptr, int size, int priority, unsigned long callbackval,
+                            int *chan, Mix_Chunk **chunk)
+{
+    SDL_RWops *rw;
+
+    *chan = grabMixerChannel(priority);
+    if (*chan == -1)
+    {
+        setErrorMessage("No available channels");
+        return(FX_Error);
+    } // if
+
+    if (size == -1) {
+        // !!! FIXME: This could be a problem...SDL/SDL_mixer wants a RWops, which
+        // !!! FIXME:  is an i/o abstraction. Since we already have the VOC data
+        // !!! FIXME:  in memory, we fake it with a memory-based RWops. None of
+        // !!! FIXME:  this is a problem, except the RWops wants to know how big
+        // !!! FIXME:  its memory block is (so it can do things like seek on an
+        // !!! FIXME:  offset from the end of the block), and since we don't have
+        // !!! FIXME:  this information, we have to give it SOMETHING. My VOC
+        // !!! FIXME:  decoder never does seeks from EOF, nor checks for
+        // !!! FIXME:  end-of-file, so we should be fine. However, we've got a
+        // !!! FIXME:  limit of 10 megs for one file. I hope that'll cover it. :)
+
+        rw = SDL_RWFromMem((void *) ptr, (10 * 1024) * 1024);  /* yikes. */
+    } else {
+        // A valid file size! Excellent.
+        rw = SDL_RWFromMem((void *) ptr, size);
+    }
+
+    *chunk = Mix_LoadWAV_RW(rw, 1);
+    if (*chunk == NULL)
+    {
+        setErrorMessage("Couldn't decode voice sample.");
+        chaninfo[*chan].in_use = 0;
+        return(FX_Error);
+    } // if
+
+    chaninfo[*chan].callbackval = callbackval;
+    return(FX_Ok);
+} // setupVocPlayback
+
+static int _FX_SetPosition(int chan, int angle, int distance)
+{
+    int left;
+    int right;
+    int mid;
+    int volume;
+    int status;
+
+    if ( distance < 0 ) {
+        distance  = -distance;
+        angle    += MV_NumPanPositions / 2;
+    }
+
+    volume = MIX_VOLUME( distance );
+
+    // Ensure angle is within 0 - 31
+    angle &= MV_MaxPanPosition;
+
+    left  = MV_PanTable[ angle ][ volume ].left;
+    right = MV_PanTable[ angle ][ volume ].right;
+    mid   = max( 0, 255 - distance );
+
+    status = doSetPan( chan, mid, left, right, 0 );
+
+    return status;
+}
+
+int FX_PlayVOC(char *ptr, int pitchoffset,
+               int vol, int left, int right,
+               int priority, unsigned long callbackval)
+{
+    int rc;
+    int chan;
+    Mix_Chunk *chunk;
+
+    snddebug("Playing voice: mono (%d), left (%d), right (%d), priority (%d).\n",
+             vol, left, right, priority);
+
+    rc = setupVocPlayback(ptr, -1, priority, callbackval, &chan, &chunk);
+    if (rc != FX_Ok)
+        return(rc);
+
+    // !!! FIXME: Need to do something with pitchoffset.
+
+    rc = doSetPan(chan, vol, left, right, 0);
+    if (rc != FX_Ok)
+    {
+        chaninfo[chan].in_use = 0;
+        return(rc);
+    } // if
+
+    Mix_PlayChannel(chan, chunk, 0);
+    return(HandleOffset + chan);
+} // FX_PlayVOC
+
+
+// get the size of a single sample, in bytes.
+static int getSampleSize(void)
+{
+    Uint16 format;
+    int channels;
+
+    Mix_QuerySpec(NULL, &format, &channels);
+    return( ((format & 0xFF) / 8) * channels );
+} // getSampleSize
+
+
+int FX_PlayLoopedVOC(char *ptr, long loopstart, long loopend,
+                     int pitchoffset, int vol, int left, int right, int priority,
+                     unsigned long callbackval)
+{
+    int rc;
+    int chan;
+    int samplesize = getSampleSize();
+    Uint32 totalsamples;
+    Mix_Chunk *chunk;
+
+    snddebug("Playing voice: mono (%d), left (%d), right (%d), priority (%d).\n",
+             vol, left, right, priority);
+    snddebug("Looping: start (%ld), end (%ld).\n", loopstart, loopend);
+
+    rc = setupVocPlayback(ptr, -1, priority, callbackval, &chan, &chunk);
+    if (rc != FX_Ok)
+        return(rc);
+
+    // !!! FIXME: Need to do something with pitchoffset.
+
+    totalsamples = chunk->alen / samplesize;
+
+    if ((loopstart >= 0) && ((unsigned int)loopstart < totalsamples))
+    {
+        if (loopend < 0) loopend = 0;
+        if ((unsigned int)loopend > totalsamples) loopend = totalsamples;
+
+        if (loopend < loopstart)
+        {
+            Mix_FreeChunk(chunk);
+            chaninfo[chan].in_use = 0;
+            setErrorMessage("Loop end is before loop start.");
+            return(FX_Error);
+        } // if
+
+        chunk->alen = loopend * samplesize;
+
+        if (loopstart > 0)
+        {
+            loopstart *= samplesize;
+            memcpy(chunk->abuf, ((Uint8 *) chunk->abuf) + loopstart,
+                   chunk->alen - loopstart);
+            chunk->alen -= loopstart;
+        } // if
+    } // if
+
+    Mix_PlayChannel(chan, chunk, -1);  /* -1 == looping. */
+    return(HandleOffset + chan);
+} // FX_PlayLoopedVOC
+
+int FX_PlayVOC3D(char *ptr, int pitchoffset, int angle, int distance,
+                 int priority, unsigned long callbackval)
+{
+    int rc;
+    int chan;
+    Mix_Chunk *chunk;
+
+    snddebug("Playing voice at angle (%d), distance (%d), priority (%d).\n",
+             angle, distance, priority);
+
+    rc = setupVocPlayback(ptr, -1, priority, callbackval, &chan, &chunk);
+    if (rc != FX_Ok)
+        return(rc);
+
+    // !!! FIXME: Need to do something with pitchoffset.
+
+    _FX_SetPosition(chan, angle, distance);
+
+    Mix_PlayChannel(chan, chunk, 0);
+    return(HandleOffset + chan);
+} // FX_PlayVOC3D
+
+// ROTT Special - SBF
+int FX_PlayVOC3D_ROTT(char *ptr, int size, int pitchoffset, int angle, int distance,
+                      int priority, unsigned long callbackval)
+{
+    int rc;
+    int chan;
+    Mix_Chunk *chunk;
+
+    snddebug("Playing voice at angle (%d), distance (%d), priority (%d).\n",
+             angle, distance, priority);
+
+    rc = setupVocPlayback(ptr, size, priority, callbackval, &chan, &chunk);
+    if (rc != FX_Ok)
+        return(rc);
+
+    // !!! FIXME: Need to do something with pitchoffset.
+
+    _FX_SetPosition(chan, angle, distance);
+
+    Mix_PlayChannel(chan, chunk, 0);
+
+    return(HandleOffset + chan);
+} // FX_PlayVOC3D_ROTT
+
+
+// it's all the same to SDL_mixer.  :)
+int FX_PlayWAV( char *ptr, int pitchoffset, int vol, int left, int right,
+                int priority, unsigned long callbackval )
+{
+    return(FX_PlayVOC(ptr, pitchoffset, vol, left, right, priority, callbackval));
+} // FX_PlayWAV
+
+
+int FX_PlayLoopedWAV( char *ptr, long loopstart, long loopend,
+                      int pitchoffset, int vol, int left, int right, int priority,
+                      unsigned long callbackval )
+{
+    return(FX_PlayLoopedVOC(ptr, loopstart, loopend, pitchoffset, vol, left,
+                            right, priority, callbackval));
+} // FX_PlayLoopedWAV
+
+
+int FX_PlayWAV3D( char *ptr, int pitchoffset, int angle, int distance,
+                  int priority, unsigned long callbackval )
+{
+    return(FX_PlayVOC3D(ptr, pitchoffset, angle, distance, priority, callbackval));
+} // FX_PlayWAV3D
+
+// ROTT Special - SBF
+int FX_PlayWAV3D_ROTT( char *ptr, int size, int pitchoffset, int angle, int distance,
+                       int priority, unsigned long callbackval )
+{
+    return(FX_PlayVOC3D_ROTT(ptr, size, pitchoffset, angle, distance, priority, callbackval));
+} // FX_PlayWAV3D_ROTT
+
+
+int FX_PlayRaw( char *ptr, unsigned long length, unsigned rate,
+                int pitchoffset, int vol, int left, int right, int priority,
+                unsigned long callbackval )
+{
+    setErrorMessage("FX_PlayRaw() ... NOT IMPLEMENTED!");
+    return(FX_Error);
+} // FX_PlayRaw
+
+
+int FX_PlayLoopedRaw( char *ptr, unsigned long length, char *loopstart,
+                      char *loopend, unsigned rate, int pitchoffset, int vol, int left,
+                      int right, int priority, unsigned long callbackval )
+{
+    setErrorMessage("FX_PlayLoopedRaw() ... NOT IMPLEMENTED!");
+    return(FX_Error);
+} // FX_PlayLoopedRaw
+
+
+int FX_Pan3D(int handle, int angle, int distance)
+{
+    int retval = FX_Warning;
+
+    handle -= HandleOffset;
+
+    if ((handle < 0) || (handle >= numChannels))
+        setWarningMessage("Invalid handle in FX_Pan3D().");
+    else if (!Mix_Playing(handle))
+        setWarningMessage("voice is no longer playing in FX_Pan3D().");
+    else
+    {
+        _FX_SetPosition(handle, angle, distance);
+
+        retval = FX_Ok;
+    } // else
+
+    return(retval);
+} // FX_Pan3D
+
+
+int FX_SoundActive(int handle)
+{
+    handle -= HandleOffset;
+
+    if (chaninfo == NULL)
+        return(__FX_FALSE);
+
+    if ((handle < 0) || (handle >= numChannels))
+    {
+        setWarningMessage("Invalid handle in FX_SoundActive().");
+        return(__FX_FALSE);
+    } // if
+
+    return(chaninfo[handle].in_use != 0);
+} // FX_SoundActive
+
+
+int FX_SoundsPlaying(void)
+{
+    return(Mix_Playing(-1));
+} // FX_SoundsPlaying
+
+
+int FX_StopSound(int handle)
+{
+    int retval = FX_Ok;
+
+    snddebug("explicitly halting channel (%d).", handle);
+    // !!! FIXME: Should the user callback fire for this?
+
+    handle -= HandleOffset;
+
+    if ((handle < 0) || (handle >= numChannels))
+    {
+        setWarningMessage("Invalid handle in FX_Pan3D().");
+        retval = FX_Warning;
+    } // if
+    else
+    {
+        Mix_HaltChannel(handle);
+    } // else
+
+    return(retval);
+} // FX_StopSound
+
+
+int FX_StopAllSounds(void)
+{
+    snddebug("halting all channels.");
+    // !!! FIXME: Should the user callback fire for this?
+    Mix_HaltGroup(-1);
+    return(FX_Ok);
+} // FX_StopAllSounds
+
+
+int FX_StartDemandFeedPlayback( void ( *function )( char **ptr, unsigned long *length ),
+                                int rate, int pitchoffset, int vol, int left, int right,
+                                int priority, unsigned long callbackval )
+{
+    setErrorMessage("FX_StartDemandFeedPlayback() ... NOT IMPLEMENTED!");
+    return(FX_Error);
+}
+
+
+int FX_StartRecording(int MixRate, void (*function)(char *ptr, int length))
+{
+    setErrorMessage("FX_StartRecording() ... NOT IMPLEMENTED!");
+    return(FX_Error);
+} // FX_StartRecording
+
+
+void FX_StopRecord( void )
+{
+    setErrorMessage("FX_StopRecord() ... NOT IMPLEMENTED!");
+} // FX_StopRecord
+
+
+
+// The music functions...
+
+
+char *MUSIC_ErrorString(int ErrorNumber)
+{
+    switch (ErrorNumber)
+    {
+    case MUSIC_Warning:
+        return(warningMessage);
+
+    case MUSIC_Error:
+        return(errorMessage);
+
+    case MUSIC_Ok:
+        return("OK; no error.");
+
+    case MUSIC_ASSVersion:
+        return("Incorrect sound library version.");
+
+    case MUSIC_SoundCardError:
+        return("General sound card error.");
+
+    case MUSIC_InvalidCard:
+        return("Invalid sound card.");
+
+    case MUSIC_MidiError:
+        return("MIDI error.");
+
+    case MUSIC_MPU401Error:
+        return("MPU401 error.");
+
+    case MUSIC_TaskManError:
+        return("Task Manager error.");
+
+    case MUSIC_FMNotDetected:
+        return("FM not detected error.");
+
+    case MUSIC_DPMI_Error:
+        return("DPMI error.");
+
+    default:
+        return("Unknown error.");
+    } // switch
+
+    assert(0);    // shouldn't hit this point.
+    return(NULL);
+} // MUSIC_ErrorString
+
+
+static int music_initialized = 0;
+static int music_context = 0;
+static int music_loopflag = MUSIC_PlayOnce;
+static char *music_songdata = NULL;
+static Mix_Music *music_musicchunk = NULL;
+
+int MUSIC_Init(int SoundCard, int Address)
+{
+    init_debugging();
+
+    musdebug("INIT! card=>%d, address=>%d...", SoundCard, Address);
+
+    if (music_initialized)
+    {
+        setErrorMessage("Music system is already initialized.");
+        return(MUSIC_Error);
+    } // if
+
+    if (SoundCard != SoundScape) // We pretend there's a SoundScape installed.
+    {
+        setErrorMessage("Card not found.");
+        musdebug("We pretend to be an Ensoniq SoundScape only.");
+        return(MUSIC_Error);
+    } // if
+
+    music_initialized = 1;
+    return(MUSIC_Ok);
+} // MUSIC_Init
+
+
+int MUSIC_Shutdown(void)
+{
+    musdebug("shutting down sound subsystem.");
+
+    if (!music_initialized)
+    {
+        setErrorMessage("Music system is not currently initialized.");
+        return(MUSIC_Error);
+    } // if
+
+    MUSIC_StopSong();
+    music_context = 0;
+    music_initialized = 0;
+    music_loopflag = MUSIC_PlayOnce;
+
+    return(MUSIC_Ok);
+} // MUSIC_Shutdown
+
+
+void MUSIC_SetMaxFMMidiChannel(int channel)
+{
+    musdebug("STUB ... MUSIC_SetMaxFMMidiChannel(%d).\n", channel);
+} // MUSIC_SetMaxFMMidiChannel
+
+
+void MUSIC_SetVolume(int volume)
+{
+    Mix_VolumeMusic(volume >> 1);  // convert 0-255 to 0-128.
+} // MUSIC_SetVolume
+
+
+void MUSIC_SetMidiChannelVolume(int channel, int volume)
+{
+    musdebug("STUB ... MUSIC_SetMidiChannelVolume(%d, %d).\n", channel, volume);
+} // MUSIC_SetMidiChannelVolume
+
+
+void MUSIC_ResetMidiChannelVolumes(void)
+{
+    musdebug("STUB ... MUSIC_ResetMidiChannelVolumes().\n");
+} // MUSIC_ResetMidiChannelVolumes
+
+
+int MUSIC_GetVolume(void)
+{
+    return(Mix_VolumeMusic(-1) << 1);  // convert 0-128 to 0-255.
+} // MUSIC_GetVolume
+
+
+void MUSIC_SetLoopFlag(int loopflag)
+{
+    music_loopflag = loopflag;
+} // MUSIC_SetLoopFlag
+
+
+int MUSIC_SongPlaying(void)
+{
+    return((Mix_PlayingMusic()) ? __FX_TRUE : __FX_FALSE);
+} // MUSIC_SongPlaying
+
+
+void MUSIC_Continue(void)
+{
+    if (Mix_PausedMusic())
+        Mix_ResumeMusic();
+    else if (music_songdata)
+        MUSIC_PlaySong(music_songdata, MUSIC_PlayOnce);
+} // MUSIC_Continue
+
+
+void MUSIC_Pause(void)
+{
+    Mix_PauseMusic();
+} // MUSIC_Pause
+
+
+int MUSIC_StopSong(void)
+{
+    if (!fx_initialized)
+    {
+        setErrorMessage("Need FX system initialized, too. Sorry.");
+        return(MUSIC_Error);
+    } // if
+
+    if ( (Mix_PlayingMusic()) || (Mix_PausedMusic()) )
+        Mix_HaltMusic();
+
+    if (music_musicchunk)
+        Mix_FreeMusic(music_musicchunk);
+
+    music_songdata = NULL;
+    music_musicchunk = NULL;
+    return(MUSIC_Ok);
+} // MUSIC_StopSong
+
+
+int MUSIC_PlaySong(unsigned char *song, int loopflag)
+{
+    //SDL_RWops *rw;
+
+    MUSIC_StopSong();
+
+    music_songdata = song;
+
+    // !!! FIXME: This could be a problem...SDL/SDL_mixer wants a RWops, which
+    // !!! FIXME:  is an i/o abstraction. Since we already have the MIDI data
+    // !!! FIXME:  in memory, we fake it with a memory-based RWops. None of
+    // !!! FIXME:  this is a problem, except the RWops wants to know how big
+    // !!! FIXME:  its memory block is (so it can do things like seek on an
+    // !!! FIXME:  offset from the end of the block), and since we don't have
+    // !!! FIXME:  this information, we have to give it SOMETHING.
+
+    /* !!! ARGH! There's no LoadMUS_RW  ?!
+    rw = SDL_RWFromMem((void *) song, (10 * 1024) * 1024);  // yikes.
+    music_musicchunk = Mix_LoadMUS_RW(rw);
+    Mix_PlayMusic(music_musicchunk, (loopflag == MUSIC_PlayOnce) ? 0 : -1);
+    */
+
+    return(MUSIC_Ok);
+} // MUSIC_PlaySong
+
+// ROTT Special - SBF
+int MUSIC_PlaySongROTT(unsigned char *song, int size, int loopflag)
+{
+    char filename[MAX_PATH];
+    int handle;
+
+    MUSIC_StopSong();
+
+    // save the file somewhere, so SDL_mixer can load it
+    GetPathFromEnvironment(filename, ApogeePath, "tmpsong.mid");
+    handle = SafeOpenWrite(filename);
+
+    SafeWrite(handle, song, size);
+    close(handle);
+
+    music_songdata = song;
+
+    // finally, we can load it with SDL_mixer
+    music_musicchunk = Mix_LoadMUS(filename);
+    if (music_musicchunk == NULL) {
+        return MUSIC_Error;
+    }
+
+    Mix_PlayMusic(music_musicchunk, (loopflag == MUSIC_PlayOnce) ? 0 : -1);
+
+    return(MUSIC_Ok);
+} // MUSIC_PlaySongROTT
+
+void MUSIC_SetContext(int context)
+{
+    musdebug("STUB ... MUSIC_SetContext().\n");
+    music_context = context;
+} // MUSIC_SetContext
+
+
+int MUSIC_GetContext(void)
+{
+    return(music_context);
+} // MUSIC_GetContext
+
+
+void MUSIC_SetSongTick(unsigned long PositionInTicks)
+{
+    musdebug("STUB ... MUSIC_SetSongTick().\n");
+} // MUSIC_SetSongTick
+
+
+void MUSIC_SetSongTime(unsigned long milliseconds)
+{
+    musdebug("STUB ... MUSIC_SetSongTime().\n");
+}// MUSIC_SetSongTime
+
+
+void MUSIC_SetSongPosition(int measure, int beat, int tick)
+{
+    musdebug("STUB ... MUSIC_SetSongPosition().\n");
+} // MUSIC_SetSongPosition
+
+
+void MUSIC_GetSongPosition(songposition *pos)
+{
+    musdebug("STUB ... MUSIC_GetSongPosition().\n");
+} // MUSIC_GetSongPosition
+
+
+void MUSIC_GetSongLength(songposition *pos)
+{
+    musdebug("STUB ... MUSIC_GetSongLength().\n");
+} // MUSIC_GetSongLength
+
+
+int MUSIC_FadeVolume(int tovolume, int milliseconds)
+{
+    Mix_FadeOutMusic(milliseconds);
+    return(MUSIC_Ok);
+} // MUSIC_FadeVolume
+
+
+int MUSIC_FadeActive(void)
+{
+    return((Mix_FadingMusic() == MIX_FADING_OUT) ? __FX_TRUE : __FX_FALSE);
+} // MUSIC_FadeActive
+
+
+void MUSIC_StopFade(void)
+{
+    musdebug("STUB ... MUSIC_StopFade().\n");
+} // MUSIC_StopFade
+
+
+void MUSIC_RerouteMidiChannel(int channel, int cdecl function( int event, int c1, int c2 ))
+{
+    musdebug("STUB ... MUSIC_RerouteMidiChannel().\n");
+} // MUSIC_RerouteMidiChannel
+
+
+void MUSIC_RegisterTimbreBank(unsigned char *timbres)
+{
+    musdebug("STUB ... MUSIC_RegisterTimbreBank().\n");
+} // MUSIC_RegisterTimbreBank
+
+
+// end of fx_man.c ...
--- /dev/null
+++ b/rott/fx_man.h
@@ -1,0 +1,132 @@
+
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+/**********************************************************************
+   module: FX_MAN.H
+
+   author: James R. Dose
+   date:   March 17, 1994
+
+   Public header for FX_MAN.C
+
+   (c) Copyright 1994 James R. Dose.  All Rights Reserved.
+**********************************************************************/
+
+#ifndef __FX_MAN_H
+#define __FX_MAN_H
+
+#include "sndcards.h"
+
+typedef struct
+{
+    int MaxVoices;
+    int MaxSampleBits;
+    int MaxChannels;
+} fx_device;
+
+#define MonoFx   1
+#define StereoFx 2
+
+enum FX_ERRORS
+{
+    FX_Warning = -2,
+    FX_Error = -1,
+    FX_Ok = 0,
+    FX_ASSVersion,
+    FX_BlasterError,
+    FX_SoundCardError,
+    FX_InvalidCard,
+    FX_MultiVocError,
+    FX_DPMI_Error
+};
+
+#ifdef DOS
+enum fx_BLASTER_Types
+{
+    fx_SB     = 1,
+    fx_SBPro  = 2,
+    fx_SB20   = 3,
+    fx_SBPro2 = 4,
+    fx_SB16   = 6
+};
+#endif
+
+
+char *FX_ErrorString( int ErrorNumber );
+int   FX_SetupCard( int SoundCard, fx_device *device );
+int   FX_Init( int SoundCard, int numvoices, int numchannels, int samplebits, unsigned mixrate );
+int   FX_Shutdown( void );
+int   FX_SetCallBack( void ( *function )( unsigned long ) );
+void  FX_SetVolume( int volume );
+int   FX_GetVolume( void );
+
+void  FX_SetReverseStereo( int setting );
+int   FX_GetReverseStereo( void );
+void  FX_SetReverb( int reverb );
+void  FX_SetFastReverb( int reverb );
+int   FX_GetMaxReverbDelay( void );
+int   FX_GetReverbDelay( void );
+void  FX_SetReverbDelay( int delay );
+
+int FX_VoiceAvailable( int priority );
+int FX_EndLooping( int handle );
+int FX_SetPan( int handle, int vol, int left, int right );
+int FX_SetPitch( int handle, int pitchoffset );
+int FX_SetFrequency( int handle, int frequency );
+
+int FX_PlayVOC( char *ptr, int pitchoffset, int vol, int left, int right,
+                int priority, unsigned long callbackval );
+int FX_PlayLoopedVOC( char *ptr, long loopstart, long loopend,
+                      int pitchoffset, int vol, int left, int right, int priority,
+                      unsigned long callbackval );
+int FX_PlayWAV( char *ptr, int pitchoffset, int vol, int left, int right,
+                int priority, unsigned long callbackval );
+int FX_PlayLoopedWAV( char *ptr, long loopstart, long loopend,
+                      int pitchoffset, int vol, int left, int right, int priority,
+                      unsigned long callbackval );
+int FX_PlayVOC3D( char *ptr, int pitchoffset, int angle, int distance,
+                  int priority, unsigned long callbackval );
+int FX_PlayWAV3D( char *ptr, int pitchoffset, int angle, int distance,
+                  int priority, unsigned long callbackval );
+int FX_PlayRaw( char *ptr, unsigned long length, unsigned rate,
+                int pitchoffset, int vol, int left, int right, int priority,
+                unsigned long callbackval );
+int FX_PlayLoopedRaw( char *ptr, unsigned long length, char *loopstart,
+                      char *loopend, unsigned rate, int pitchoffset, int vol, int left,
+                      int right, int priority, unsigned long callbackval );
+int FX_Pan3D( int handle, int angle, int distance );
+int FX_SoundActive( int handle );
+int FX_SoundsPlaying( void );
+int FX_StopSound( int handle );
+int FX_StopAllSounds( void );
+int FX_StartDemandFeedPlayback( void ( *function )( char **ptr, unsigned long *length ),
+                                int rate, int pitchoffset, int vol, int left, int right,
+                                int priority, unsigned long callbackval );
+int  FX_StartRecording( int MixRate, void ( *function )( char *ptr, int length ) );
+void FX_StopRecord( void );
+
+// ROTT Special - SBF
+int FX_PlayVOC3D_ROTT( char *ptr, int size, int pitchoffset, int angle, int distance,
+                       int priority, unsigned long callbackval );
+int FX_PlayWAV3D_ROTT( char *ptr, int size, int pitchoffset, int angle, int distance,
+                       int priority, unsigned long callbackval );
+// End ROTT hacks
+
+#endif
--- /dev/null
+++ b/rott/gmove.h
@@ -1,0 +1,25 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+#ifndef _gmove
+#define _gmove
+
+#define GMOVE 8
+
+#endif
--- /dev/null
+++ b/rott/isr.c
@@ -1,0 +1,842 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+
+
+
+/*
+============================================================================
+
+													 TIMER INTERRUPT
+
+============================================================================
+*/
+#include <stdlib.h>
+#include <stdio.h>
+
+#ifdef DOS
+#include <dos.h>
+#include <mem.h>
+#include <conio.h>
+#endif
+
+#include "rt_def.h"
+#include "task_man.h"
+#include "isr.h"
+#include "_isr.h"
+#include "rt_in.h"
+#include "rt_util.h"
+#include "profile.h"
+#include "develop.h"
+#include "rt_main.h"
+
+#if (DEVELOPMENT == 1)
+
+#include "rt_vid.h"
+
+#endif
+//MED
+#include "memcheck.h"
+
+// Global Variables
+
+static volatile boolean ExtendedKeyFlag;
+
+volatile int Keyboard[MAXKEYBOARDSCAN];
+volatile int KeyboardQueue[KEYQMAX];
+volatile int Keystate[MAXKEYBOARDSCAN];
+volatile int Keyhead;
+volatile int Keytail;
+
+#ifdef DOS
+volatile int ticcount;
+volatile int fasttics;
+#endif
+
+volatile boolean PausePressed = false;
+volatile boolean PanicPressed = false;
+int KeyboardStarted=false;
+
+const int ASCIINames[] =          // Unshifted ASCII for scan codes
+{
+//       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','-','=',8,9,               // 0
+    'q','w','e','r','t','y','u','i','o','p','[',']',13,0,'a','s',           // 1
+    'd','f','g','h','j','k','l',';',39,'`',0,92,'z','x','c','v',            // 2
+    'b','n','m',',','.','/',0,'*',0,' ',0,0,0,0,0,0,                        // 3
+    0,0,0,0,0,0,0,'7','8','9','-','4','5','6','+','1',                      // 4
+    '2','3','0',127,0,0,0,0,0,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
+};
+
+const int ShiftNames[] =              // Shifted ASCII for scan codes
+{
+//       0   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F
+    0,27,'!','@','#','$','%','^','&','*','(',')','_','+',8,9,               // 0
+    'Q','W','E','R','T','Y','U','I','O','P','{','}',13,0,'A','S',           // 1
+    'D','F','G','H','J','K','L',':',34,'~',0,'|','Z','X','C','V',           // 2
+    'B','N','M','<','>','?',0,'*',0,' ',0,0,0,0,0,0,                        // 3
+    0,0,0,0,0,0,0,'7','8','9','-','4','5','6','+','1',                      // 4
+    '2','3','0',127,0,0,0,0,0,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
+};
+
+#ifdef DOS
+
+// Local Variables
+
+static task * timertask;
+#if (DEVELOPMENT == 1)
+static task * fasttimertask;
+#endif
+static int TimerStarted=false;
+static volatile int pausecount=0;
+static struct dostime_t starttime;
+
+void (__interrupt __far *oldtimerisr) ();
+void (__interrupt __far *oldkeyboardisr) () = NULL;
+
+static int LEDs;
+static volatile int KBFlags;
+
+/*
+================
+=
+= I_TimerISR
+=
+================
+*/
+
+void __interrupt I_TimerISR (void)
+{
+// acknowledge the interrupt
+
+    OUTP(0x20,0x20);
+    ticcount++;
+}
+
+/*
+================
+=
+= ISR_Timer
+=
+================
+*/
+#if 0
+#if (DEVELOPMENT == 1)
+static int time=0;
+static int t1=0;
+static int t2=0;
+static int t3=0;
+static int insettime=0;
+#endif
+#endif
+/*
+================
+=
+= ISR_SetTime
+=
+================
+*/
+void ISR_SetTime(int settime)
+{
+#if 0
+#if (DEVELOPMENT == 1)
+    int i;
+    int t;
+    int savetime;
+#endif
+#endif
+
+    ticcount=settime;
+#if 0
+#if (DEVELOPMENT == 1)
+    {
+        insettime=1;
+        savetime=time;
+        t1=0;
+        t2=0;
+        t3=0;
+        t=0;
+
+        for (i=0; i<settime; i++)
+        {
+            t++;
+            if (t==VBLCOUNTER)
+            {
+                t=0;
+                t1++;
+                if (t1==2)
+                {
+                    t1=0;
+                    t2++;
+                    if (t2==2)
+                    {
+                        t2=0;
+                        t3++;
+                        if (t3==2)
+                            t3=0;
+                    }
+                }
+            }
+        }
+        time=t+(time-savetime);
+        if (time>=VBLCOUNTER)
+        {
+            time-=VBLCOUNTER;
+            t1++;
+            if (t1==2)
+            {
+                t1=0;
+                t2++;
+                if (t2==2)
+                {
+                    t2=0;
+                    t3++;
+                    if (t3==2)
+                        t3=0;
+                }
+            }
+        }
+        insettime=0;
+    }
+#endif
+#endif
+}
+
+static void ISR_Timer (task *Task)
+{
+//	(*(int *)(Task->data))=((*(int *)(Task->data))+1)&0xffff;
+    (*(int *)(Task->data))++;
+
+#if 0
+#if (DEVELOPMENT == 1)
+    {
+        if (Task==timertask)
+        {
+            time++;
+            if ((time==VBLCOUNTER) && (insettime==0))
+            {
+                time=0;
+                VL_SetColor(0,(t1<<5)+20,(t2<<5)+20,(t3<<5)+20);
+                t1++;
+                if (t1==2)
+                {
+                    t1=0;
+                    t2++;
+                    if (t2==2)
+                    {
+                        t2=0;
+                        t3++;
+                        if (t3==2)
+                            t3=0;
+                    }
+                }
+            }
+        }
+    }
+#endif
+#endif
+}
+
+
+/*
+=====================
+=
+= I_SetTimer0
+=
+= Sets system timer 0 to the specified speed
+=
+=====================
+*/
+
+void I_SetTimer0(int speed)
+{
+    unsigned s;
+    if (!((speed > 0 && speed < 150)))
+        Error ("INT_SetTimer0: %i is a bad value",speed);
+    s=1192030U/(unsigned)speed;
+    OUTP(0x43,0x36);                            // Change timer 0
+    OUTP(0x40,s);
+    OUTP(0x40,s >> 8);
+}
+
+/*
+================
+=
+= I_Delay
+=
+================
+*/
+
+void I_Delay ( int delay )
+{
+    int time;
+
+    delay=(VBLCOUNTER*delay)/10;
+    IN_ClearKeysDown();
+    time=ticcount;
+    while (ticcount<time+delay)
+    {
+        if (LastScan)
+            break;
+    }
+}
+
+/*
+===============
+=
+= I_StartupTimer
+=
+===============
+*/
+
+void I_StartupTimer (void)
+{
+#if PROFILE
+    return;
+#else
+    struct dostime_t cmostime;
+
+    if (TimerStarted==true)
+        return;
+    TimerStarted=true;
+
+    I_GetCMOSTime ( &cmostime );
+    _dos_settime  ( &cmostime );
+
+//      I_SetTimer0(VBLCOUNTER);
+//      oldtimerisr = _dos_getvect(TIMERINT);
+//      _dos_setvect (TIMERINT, I_TimerISR);
+
+    timertask=TS_ScheduleTask( &ISR_Timer, VBLCOUNTER, 10, &ticcount);
+#if (DEVELOPMENT == 1)
+    fasttimertask=TS_ScheduleTask( &ISR_Timer, VBLCOUNTER*4, 10, &fasttics);
+#endif
+    TS_Dispatch();
+    I_GetCMOSTime ( &cmostime );
+    memcpy(&starttime,&cmostime,sizeof(starttime));
+    ticcount=0;
+    if (!quiet)
+        printf("I_StartupTimer: Timer Started\n");
+#endif
+}
+
+void I_ShutdownTimer (void)
+{
+#if PROFILE
+    return;
+#else
+    struct dostime_t dostime;
+    struct dostime_t cmostime;
+#if (DEVELOPMENT == 1)
+    int totaltime;
+#endif
+
+    if (TimerStarted==false)
+        return;
+    TimerStarted=false;
+
+//      OUTP(0x43,0x36);                            // Change timer 0
+//      OUTP(0x40,0);
+//      OUTP(0x40,0);
+//      _dos_setvect (TIMERINT, oldtimerisr);
+
+    I_GetCMOSTime ( &cmostime );
+    _dos_gettime  ( &dostime  );
+
+#if (DEVELOPMENT == 1)
+    SoftError("Time difference in seconds (DOS-CMOS) %ld\n",dostime.second-cmostime.second);
+    SoftError("Time difference in minutes (DOS-CMOS) %ld\n",dostime.minute-cmostime.minute);
+    SoftError("Time difference in hour (DOS-CMOS) %ld\n",dostime.hour-cmostime.hour);
+    totaltime=( ((cmostime.hour-starttime.hour)*3600) +
+                ((cmostime.minute-starttime.minute)*60) +
+                (cmostime.second-starttime.second)
+              );
+    SoftError("Total seconds = %ld Total Tics = %ld Game Tics = %ld\n",totaltime,totaltime*VBLCOUNTER,ticcount);
+#endif
+
+    TS_Terminate( timertask );
+#if (DEVELOPMENT == 1)
+    TS_Terminate( fasttimertask );
+#endif
+    TS_Shutdown();
+//   TS_Halt();
+    /*
+       if (oldtimerisr)
+          {
+          OUTP(0x43,0x36);                            // Change timer 0
+          OUTP(0x40,0);
+          OUTP(0x40,0);
+          _dos_setvect (TIMERINT, oldtimerisr);
+          // Set Date and Time from CMOS
+
+          OUTP(0x70,0);
+          time.second=inp(0x71);
+          OUTP(0x70,2);
+          time.minute=inp(0x71);
+          OUTP(0x70,4);
+          time.hour=inp(0x71);
+          time.second=(time.second&0x0f)+((time.second>>4)*10);
+          time.minute=(time.minute&0x0f)+((time.minute>>4)*10);
+          time.hour=(time.hour&0x0f)+((time.hour>>4)*10);
+          _dos_settime(&time);
+
+          OUTP(0x70,7);
+          date.day=inp(0x71);
+          OUTP(0x70,8);
+          date.month=inp(0x71);
+          OUTP(0x70,9);
+          date.year=inp(0x71);
+          date.day=(date.day&0x0f)+((date.day>>4)*10);
+          date.month=(date.month&0x0f)+((date.month>>4)*10);
+          date.year=(date.year&0x0f)+((date.year>>4)*10);
+          _dos_setdate(&date);
+    //      }
+    */
+#endif
+}
+
+/*
+===============
+=
+= I_GetCMOSTime
+=
+===============
+*/
+void I_GetCMOSTime ( struct dostime_t * cmostime )
+{
+    OUTP(0x70,0);
+    cmostime->second=inp(0x71);
+    OUTP(0x70,2);
+    cmostime->minute=inp(0x71);
+    OUTP(0x70,4);
+    cmostime->hour=inp(0x71);
+    cmostime->second=(cmostime->second&0x0f)+((cmostime->second>>4)*10);
+    cmostime->minute=(cmostime->minute&0x0f)+((cmostime->minute>>4)*10);
+    cmostime->hour=(cmostime->hour&0x0f)+((cmostime->hour>>4)*10);
+}
+
+/*
+============================================================================
+
+																KEYBOARD
+
+============================================================================
+*/
+#define ena_kbd           0xae
+#define caps_state        0x40
+#define num_state         0x20
+#define scroll_state      0x10
+
+#define kb_resend         0xfe
+#define kb_ack            0xfa
+#define kb_pr_led         0x40
+#define kb_error          0x80
+#define kb_fe             0x20
+#define kb_fa             0x10
+
+#define porta             0x60
+#define kb_status_port    0x64
+#define input_buffer_full 0x02
+#define led_cmd           0xed
+#define kb_enable         0xf4
+#define leds_off          0
+#define caps_led_on       0x04
+#define num_led_on        0x02
+#define scroll_led_on     0x01
+
+/*
+================
+=
+= I_SendKeyboardData
+=
+================
+*/
+
+void I_SendKeyboardData
+(
+    int val
+)
+
+{
+    int retry;
+    volatile int count;
+
+    _disable();
+
+    KBFlags &= ~( kb_fe | kb_fa );
+
+    count = 0xffff;
+    while( count-- )
+    {
+        if ( !( inp( kb_status_port ) & input_buffer_full ) )
+        {
+            break;
+        }
+    }
+
+    outp( porta, val );
+
+    _enable();
+
+    retry = 3;
+    while( retry-- )
+    {
+        count = 0x1a00;
+        while( count-- )
+        {
+            if ( KBFlags & kb_fe )
+            {
+                break;
+            }
+
+            if ( KBFlags & kb_fa )
+            {
+                return;
+            }
+        }
+    }
+
+    KBFlags |= kb_error;
+}
+
+/*
+================
+=
+= I_SetKeyboardLEDs
+=
+================
+*/
+
+void I_SetKeyboardLEDs
+(
+    int which,
+    boolean val
+)
+
+{
+    int mask;
+    int count;
+
+    _disable();
+    KBFlags |= kb_pr_led;
+
+    switch( which )
+    {
+    case scroll_lock :
+        mask = scroll_led_on;
+        break;
+
+    case num_lock :
+        mask = num_led_on;
+        break;
+
+    case caps_lock :
+        mask = caps_led_on;
+        break;
+
+    default :
+        mask = 0;
+        break;
+    }
+
+    if ( val )
+    {
+        LEDs |= mask;
+    }
+    else
+    {
+        LEDs &= ~mask;
+    }
+
+    count = 0;
+    do
+    {
+        if ( count > 3 )
+        {
+            break;
+        }
+
+        I_SendKeyboardData( led_cmd );
+        _disable();
+        I_SendKeyboardData( LEDs );
+        _disable();
+        I_SendKeyboardData( kb_enable );
+        _disable();
+        count++;
+    }
+    while( KBFlags & kb_error );
+
+    _enable();
+    KBFlags &= ~(kb_pr_led|kb_error);
+}
+
+
+/*
+================
+=
+= I_KeyboardISR
+=
+================
+*/
+void __interrupt I_KeyboardISR (void)
+{
+    int k;
+    int temp;
+    int keyon;
+    int strippedkey;
+
+    // Get the scan code
+    k = inp( 0x60 );
+
+    // Tell the XT keyboard controller to clear the key
+    temp = inp( 0x61 );
+    OUTP ( 0x61, temp | 0x80 );
+    OUTP ( 0x61, temp );
+
+    if ( KBFlags & kb_pr_led )
+    {
+        if ( k == kb_resend )
+        {
+            // Handle resend
+            KBFlags |= kb_fe;
+        }
+        else if (k == kb_ack)
+        {
+            // Handle ack
+            KBFlags |= kb_fa;
+        }
+    }
+    else if ( pausecount )
+    {
+        pausecount--;
+    }
+    else if ( k == 0xe1 )         // Handle Pause key
+    {
+        PausePressed = true;
+        pausecount = 5;
+    }
+    else if ( k == 0x46 )         // Handle Panic key (Scroll Lock)
+    {
+        PanicPressed = true;
+    }
+    else
+    {
+        if ( k == 0xE0 )
+        {
+            ExtendedKeyFlag = true;
+        }
+        else
+        {
+            keyon = k & 0x80;
+            strippedkey = k & 0x7f;
+
+            if ( ExtendedKeyFlag )
+            {
+                if ( ( strippedkey == sc_LShift ) ||
+                        ( strippedkey == sc_RShift ) )
+                {
+                    k = sc_None;
+                }
+                /*
+                            else
+                               {
+                               if ( strippedkey == sc_Alt )
+                                  {
+                                  k = sc_RightAlt | keyon;
+                                  }
+                               if ( strippedkey == sc_Control )
+                                  {
+                                  k = sc_RightCtrl | keyon;
+                                  }
+                               }
+                */
+            }
+
+            if ( k != sc_None )
+            {
+                if ( strippedkey == sc_LShift )
+                {
+                    k = sc_RShift | keyon;
+                }
+
+                if ( !keyon )
+                {
+                    LastScan = k;
+                }
+
+                if (k & 0x80)        // Up event
+                {
+                    Keystate[k&0x7f]=0;
+                }
+                else                 // Down event
+                {
+                    Keystate[k]=1;
+                }
+
+                KeyboardQueue[ Keytail ] = k;
+                Keytail = ( Keytail + 1 )&( KEYQMAX - 1 );
+            }
+
+            ExtendedKeyFlag = false;
+        }
+    }
+
+    // acknowledge the interrupt
+    OUTP ( 0x20, 0x20 );
+}
+
+
+/*
+===============
+=
+= I_StartupKeyboard
+=
+===============
+*/
+
+void I_StartupKeyboard (void)
+{
+    if (KeyboardStarted==true)
+        return;
+    KeyboardStarted=true;
+
+    LEDs = 0;
+    KBFlags = 0;
+    ExtendedKeyFlag = false;
+
+    oldkeyboardisr = _dos_getvect(KEYBOARDINT);
+    _dos_setvect (0x8000 | KEYBOARDINT, I_KeyboardISR);
+
+//   I_SetKeyboardLEDs( scroll_lock, 0 );
+
+    Keyhead = Keytail = 0;
+    memset(Keystate,0,sizeof(Keystate));
+    if (!quiet)
+        printf("I_StartupKeyboard: Keyboard Started\n");
+}
+
+void I_ShutdownKeyboard (void)
+{
+    if (KeyboardStarted==false)
+        return;
+    KeyboardStarted=false;
+
+    // Clear LEDS
+//   *( (byte *)0x417 ) &= ~0x70;
+
+    _dos_setvect (KEYBOARDINT, oldkeyboardisr);
+    *(short *)0x41c = *(short *)0x41a;      // clear bios key buffer
+}
+#else
+
+#include "SDL.h"
+
+static int ticoffset;    /* offset for SDL_GetTicks() */
+static int ticbase;      /* game-supplied base */
+
+int GetTicCount (void)
+{
+    return ((SDL_GetTicks() - ticoffset) * VBLCOUNTER) / 1000 + ticbase;
+}
+
+/*
+================
+=
+= ISR_SetTime
+=
+================
+*/
+void ISR_SetTime(int settime)
+{
+    ticoffset = SDL_GetTicks();
+    ticbase = settime;
+}
+
+/* developer-only */
+
+int GetFastTics (void)
+{
+    /* STUB_FUNCTION; */
+
+    return 0;
+}
+
+void SetFastTics (int settime)
+{
+    /* STUB_FUNCTION; */
+}
+
+/*
+================
+=
+= I_Delay
+=
+================
+*/
+
+void I_Delay ( int delay )
+{
+    int time;
+
+    delay=(VBLCOUNTER*delay)/10;
+    IN_ClearKeysDown();
+    time=GetTicCount();
+    while (!LastScan && !IN_GetMouseButtons() && GetTicCount()<time+delay)
+    {
+        IN_UpdateKeyboard();
+    }
+}
+
+/*
+===============
+=
+= I_StartupTimer
+=
+===============
+*/
+
+void I_StartupTimer (void)
+{
+}
+
+void I_ShutdownTimer (void)
+{
+}
+
+/*
+===============
+=
+= I_StartupKeyboard
+=
+===============
+*/
+
+void I_StartupKeyboard (void)
+{
+}
+
+
+void I_ShutdownKeyboard (void)
+{
+}
+#endif
--- /dev/null
+++ b/rott/isr.h
@@ -1,0 +1,89 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+#ifndef _isr_public
+#define _isr_public
+
+#include "keyb.h"
+
+//***************************************************************************
+//
+//    ISR.C - Interrupt Service Routines (Keyboard, timer)
+//
+//***************************************************************************
+
+//***************************************************************************
+//
+//    ISR Constants
+//
+//***************************************************************************
+
+#define VBLCOUNTER   35
+
+
+#define KEYQMAX      256
+#define MAXKEYBOARDSCAN         128
+
+#define scroll_lock  0
+#define num_lock     1
+#define caps_lock    2
+
+extern volatile int KeyboardQueue[KEYQMAX];
+extern volatile int Keyhead;
+extern volatile int Keytail;
+
+extern volatile int Keyboard[MAXKEYBOARDSCAN];   // Keyboard status array
+extern volatile int Keystate[MAXKEYBOARDSCAN];   // Keyboard state array
+
+#ifdef DOS
+extern volatile int ticcount;     // Current ticcount (usually 70Hz)
+extern volatile int fasttics;
+
+#define GetTicCount()	ticcount
+#define GetFastTics()	fasttics
+
+#define SetFastTics(a) {fasttics=a;}
+#else
+int GetTicCount (void);
+int GetFastTics (void);
+
+void SetFastTics(int);
+#endif
+
+extern int KeyboardStarted;
+
+extern const int ASCIINames[];   // Ascii -> scan code conversion
+extern const int ShiftNames[];   // Shifted Ascii->scancode conversion
+extern volatile boolean PausePressed;  //Game paused variable
+extern volatile boolean PanicPressed;  //Panic key variable
+
+void I_StartupTimer (void);        // Start up timer isr
+void I_SetTimer0(int speed);       // Set the timer to a given speed
+void I_ShutdownTimer (void);       // Shutdown timer isr
+void I_SetKeyboardLEDs( int which, boolean val ); // Turns LED's on or off
+void I_StartupKeyboard (void);     // Startup Keyboard isr
+void I_ShutdownKeyboard (void);    // Shutdown keyboard isr
+void I_Delay ( int delay );
+void ISR_SetTime(int settime);
+void I_SendKeyboardData
+(
+    int val
+);
+
+#endif
--- /dev/null
+++ b/rott/keyb.h
@@ -1,0 +1,106 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+#ifndef _keyb
+#define _keyb
+
+#define	sc_None			0
+#define	sc_Bad			0xff
+#define	sc_Comma    	0x33
+#define	sc_Period		0x34
+#define	sc_Return		0x1c
+#define	sc_Enter		   sc_Return
+#define	sc_Escape		0x01
+#define	sc_Space		   0x39
+#define	sc_BackSpace	0x0e
+#define	sc_Tab			0x0f
+#define	sc_Alt			0x38
+#define	sc_Control		0x1d
+#define	sc_CapsLock		0x3a
+#define	sc_LShift		0x2a
+#define	sc_RShift		0x36
+#define	sc_UpArrow		0x48
+#define	sc_DownArrow	0x50
+#define	sc_LeftArrow	0x4b
+#define	sc_RightArrow	0x4d
+#define	sc_Insert		0x52
+#define	sc_Delete		0x53
+#define	sc_Home			0x47
+#define	sc_End			0x4f
+#define	sc_PgUp			0x49
+#define	sc_PgDn			0x51
+#define	sc_F1				0x3b
+#define	sc_F2				0x3c
+#define	sc_F3				0x3d
+#define	sc_F4				0x3e
+#define	sc_F5				0x3f
+#define	sc_F6				0x40
+#define	sc_F7				0x41
+#define	sc_F8				0x42
+#define	sc_F9				0x43
+#define	sc_F10			0x44
+#define	sc_F11			0x57
+#define	sc_F12			0x58
+#define  sc_PrintScreen 0x37
+
+#define  sc_OpenBracket      0x1a
+#define  sc_CloseBracket     0x1b
+
+#define  sc_1           0x02
+#define	sc_2				0x03
+#define	sc_3				0x04
+#define	sc_4				0x05
+#define	sc_5				0x06
+#define	sc_6				0x07
+#define	sc_7				0x08
+#define	sc_8				0x09
+#define	sc_9				0x0a
+#define	sc_0				0x0b
+#define	sc_Minus       0x0c
+#define	sc_Equals      0x0d
+#define	sc_Plus        0x0d
+
+#define	sc_A				0x1e
+#define	sc_B				0x30
+#define	sc_C				0x2e
+#define	sc_D				0x20
+#define	sc_E				0x12
+#define	sc_F				0x21
+#define	sc_G				0x22
+#define	sc_H				0x23
+#define	sc_I				0x17
+#define	sc_J				0x24
+#define	sc_K				0x25
+#define	sc_L				0x26
+#define	sc_M				0x32
+#define	sc_N				0x31
+#define	sc_O				0x18
+#define	sc_P				0x19
+#define	sc_Q				0x10
+#define	sc_R				0x13
+#define	sc_S				0x1f
+#define	sc_T				0x14
+#define	sc_U				0x16
+#define	sc_V				0x2f
+#define	sc_W				0x11
+#define	sc_X				0x2d
+#define	sc_Y				0x15
+#define	sc_Z				0x2c
+
+#endif
--- /dev/null
+++ b/rott/lookups.c
@@ -1,0 +1,223 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+#include "rt_def.h"
+#include "rt_util.h"
+#include "rt_view.h"
+#include <math.h>
+#include <dos.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <conio.h>
+#include <string.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <io.h>
+#include <stdlib.h>
+#include <sys\stat.h>
+
+//MED
+#include "memcheck.h"
+
+#define PANGLES 512
+#define NUMSINANGLES FINEANGLES+FINEANGLEQUAD+1
+
+fixed  pangle[PANGLES];
+long   sintable[NUMSINANGLES];
+short  tantable[FINEANGLES];
+byte   gammatable[GAMMAENTRIES];
+
+extern  int      _argc;
+extern  char **  _argv;
+
+/*
+=================
+=
+= Error
+=
+= For abnormal program terminations
+=
+=================
+*/
+
+void Error (char *error, ...)
+{
+    va_list	argptr;
+
+    va_start (argptr,error);
+    vprintf (error,argptr);
+    va_end (argptr);
+    printf ("\n");
+    exit (1);
+}
+
+
+int SafeOpenWrite (char *_filename)
+{
+    int	handle;
+    char filename[MAX_PATH];
+    strncpy(filename, _filename, sizeof (filename));
+    filename[sizeof (filename) - 1] = '\0';
+    FixFilePath(filename);
+
+    handle = open(filename,O_RDWR | O_BINARY | O_CREAT | O_TRUNC
+                  , S_IREAD | S_IWRITE);
+
+    if (handle == -1)
+        Error ("Error opening %s: %s",filename,strerror(errno));
+
+    return handle;
+}
+
+
+void SafeWrite (int handle, void *buffer, long count)
+{
+    unsigned	iocount;
+
+    while (count)
+    {
+        iocount = count > 0x8000 ? 0x8000 : count;
+        if (write (handle,buffer,iocount) != iocount)
+            Error ("File write failure");
+        buffer = (void *)( (byte *)buffer + iocount );
+        count -= iocount;
+    }
+}
+
+
+
+
+void CalcPixelAngles ( void )
+{
+    int   i;
+    long  intang;
+    double  angle;
+    double  tang;
+
+    const   double radtoint = (double)FINEANGLES/2/PI;
+
+
+    for (i=0; i<PANGLES; i++)
+    {
+        // start 1/2 pixel over, so viewangle bisects two middle pixels
+        //tang = ((((double)i*160.0)+80.0)/(FPFOCALWIDTH*(double)PANGLES));
+        tang = ((((double)i*160.0)+80.0)/(dGLOBAL_FPFOCALWIDTH*(double)PANGLES));
+        angle = atan(tang);
+        intang = ((long)(angle*radtoint));
+        pangle[i] = intang;
+    }
+}
+
+
+
+void BuildSinTable (void)
+{
+    int   i;
+    double  angle,anglestep;
+    double  sinangle;
+    fixed  value;
+
+    angle = 0;
+    anglestep = (double)(PI/2/FINEANGLEQUAD);
+    for (i=0; i<=FINEANGLEQUAD; i++)
+    {
+        sinangle=sin(angle);
+        value=(fixed)((double)GLOBAL1*sinangle);
+        sintable[i]     =
+            sintable[i+FINEANGLES]  =
+                sintable[FINEANGLES/2-i] = value;
+        sintable[FINEANGLES-i] = -value;
+        sintable[FINEANGLES/2+i] = -value;
+        angle += anglestep;
+    }
+}
+
+void BuildTanTable (void)
+{
+    int   i;
+    double  angle,anglestep;
+    double  tanangle;
+    fixed  value;
+
+    angle = 0;
+    anglestep = (double)(PI*2/FINEANGLES);
+    for (i=0; i<FINEANGLES; i++)
+    {
+        tanangle=tan(angle);
+        value=(fixed)((double)GLOBAL1*tanangle);
+        tantable[i] =(short) (value>>1);
+        angle += anglestep;
+    }
+}
+
+void BuildGammaTable (void)
+{
+    int     l, i, inf;
+    int     j;
+    int     gGamma=0x100;
+    j=0;
+    for (l=0 ; l<NUMGAMMALEVELS ; l++,gGamma+=32)
+    {
+        double nGamma = (double)256 / gGamma;
+        double nScale = (double)63  / pow(63, nGamma);
+
+        for ( i = 0; i < 64; i++ )
+        {
+            inf = pow(i, nGamma) * nScale;
+            if (inf < 0)
+                inf = 0;
+            if (inf > 63)
+                inf = 63;
+            gammatable[j++]=inf;
+        }
+    }
+}
+
+void main ()
+{
+    int handle;
+    int size;
+
+    if (_argc!=2)
+    {
+        printf("LOOKUPS -- Apogee Software (c) 1994\n");
+        printf("\n USAGE:    lookups <name.dat>\n");
+        exit(0);
+    }
+    handle=SafeOpenWrite (_argv[1]);
+    CalcPixelAngles();
+    BuildSinTable();
+    BuildTanTable();
+    BuildGammaTable();
+    size=PANGLES;
+    SafeWrite(handle,&size,sizeof(int));
+    SafeWrite(handle,&pangle[0],sizeof(fixed)*size);
+    size=NUMSINANGLES;
+    SafeWrite(handle,&size,sizeof(int));
+    SafeWrite(handle,&sintable[0],sizeof(fixed)*size);
+    size=FINEANGLES;
+    SafeWrite(handle,&size,sizeof(int));
+    SafeWrite(handle,&tantable[0],sizeof(short)*size);
+    size=GAMMAENTRIES;
+    SafeWrite(handle,&size,sizeof(int));
+    SafeWrite(handle,&gammatable[0],sizeof(byte)*size);
+    close (handle);
+}
--- /dev/null
+++ b/rott/lumpy.h
@@ -1,0 +1,151 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+#ifndef _lumpy_
+#define _lumpy_
+
+//****************************************************************************
+//
+// Public header for LUMPY typedefs
+//
+//****************************************************************************
+
+
+typedef struct
+{
+    byte     width,height;
+    byte     data;
+} pic_t;
+
+#define CONVERT_ENDIAN_pic_t(pp) { }
+
+typedef struct
+{
+    short     width,height;
+    short     orgx,orgy;
+    byte     data;
+} lpic_t;
+
+#define CONVERT_ENDIAN_lpic_t(lp)            \
+    {                                        \
+        SwapIntelShort(&lp->width);          \
+        SwapIntelShort(&lp->height);         \
+        SwapIntelShort(&lp->orgx);           \
+        SwapIntelShort(&lp->orgy);           \
+    }
+
+typedef struct
+{
+    short height;
+    char  width[256];
+    short charofs[256];
+    byte  data;       // as much as required
+} font_t;
+
+#define CONVERT_ENDIAN_font_t(fp)            \
+    {                                        \
+        int i;                               \
+        SwapIntelShort(&fp->height);         \
+        for (i = 0; i < 256; i++) {          \
+            SwapIntelShort(&fp->charofs[i]); \
+        }                                    \
+    }
+
+typedef struct
+{
+    short width;
+    short height;
+    byte palette[768];
+    byte data;
+} lbm_t;
+
+#define CONVERT_ENDIAN_lbm_t(lp)             \
+    {                                        \
+        SwapIntelShort(&lp->width);          \
+        SwapIntelShort(&lp->height);         \
+    }
+
+typedef struct
+{
+    short          origsize;         // the orig size of "grabbed" gfx
+    short          width;            // bounding box size
+    short          height;
+    short          leftoffset;       // pixels to the left of origin
+    short          topoffset;        // pixels above the origin
+    unsigned short collumnofs[320];  // only [width] used, the [0] is &collumnofs[width]
+} patch_t;
+
+#define CONVERT_ENDIAN_patch_t(pp)           \
+    {                                        \
+        int i;                               \
+        SwapIntelShort(&pp->origsize);       \
+        SwapIntelShort(&pp->width);          \
+        SwapIntelShort(&pp->height);         \
+        SwapIntelShort(&pp->leftoffset);     \
+        SwapIntelShort(&pp->topoffset);      \
+        for (i = 0; i < pp->width; i++) {          \
+            SwapIntelShort((short*)&pp->collumnofs[i]); \
+        }                                    \
+    }
+
+typedef struct
+{
+    short origsize;         // the orig size of "grabbed" gfx
+    short width;            // bounding box size
+    short height;
+    short leftoffset;       // pixels to the left of origin
+    short topoffset;        // pixels above the origin
+    short translevel;
+    short collumnofs[320];  // only [width] used, the [0] is &collumnofs[width]
+} transpatch_t;
+
+#define CONVERT_ENDIAN_transpatch_t(pp)      \
+    {                                        \
+        int i;                               \
+        SwapIntelShort(&pp->origsize);       \
+        SwapIntelShort(&pp->width);          \
+        SwapIntelShort(&pp->height);         \
+        SwapIntelShort(&pp->leftoffset);     \
+        SwapIntelShort(&pp->topoffset);      \
+        SwapIntelShort(&pp->translevel);     \
+        for (i = 0; i < pp->width; i++) {          \
+            SwapIntelShort((short*)&pp->collumnofs[i]); \
+        }                                    \
+    }
+
+typedef struct
+{
+    byte  color;
+    short height;
+    char  width[256];
+    short charofs[256];
+    byte  pal[0x300];
+    byte  data;       // as much as required
+} cfont_t;
+
+#define CONVERT_ENDIAN_cfont_t(pp)           \
+    {                                        \
+        int i;                               \
+        SwapIntelShort(&pp->height);         \
+        for (i = 0; i < 256; i++) {          \
+            SwapIntelShort(&pp->charofs[i]); \
+        }                                    \
+    }
+
+#endif
--- /dev/null
+++ b/rott/memcheck.h
@@ -1,0 +1,1 @@
+/* old header removed */
--- /dev/null
+++ b/rott/modexlib.c
@@ -1,0 +1,847 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+
+#include <stdarg.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+#include <ctype.h>
+
+#ifdef DOS
+#include <malloc.h>
+#include <dos.h>
+#include <conio.h>
+#include <io.h>
+#endif
+
+#include <stdlib.h>
+#include <sys/stat.h>
+#include "modexlib.h"
+//MED
+#include "memcheck.h"
+#include "rt_util.h"
+#include "rt_net.h" // for GamePaused
+#include "myprint.h"
+
+static void StretchMemPicture ();
+// GLOBAL VARIABLES
+
+boolean StretchScreen=0;//bn�++
+extern boolean iG_aimCross;
+extern boolean sdl_fullscreen;
+extern int iG_X_center;
+extern int iG_Y_center;
+char 	   *iG_buf_center;
+
+int    linewidth;
+//int    ylookup[MAXSCREENHEIGHT];
+int    ylookup[600];//just set to max res
+byte  *page1start;
+byte  *page2start;
+byte  *page3start;
+int    screensize;
+byte  *bufferofs;
+byte  *displayofs;
+boolean graphicsmode=false;
+char        *bufofsTopLimit;
+char        *bufofsBottomLimit;
+
+void DrawCenterAim ();
+
+#ifdef DOS
+
+/*
+====================
+=
+= GraphicsMode
+=
+====================
+*/
+void GraphicsMode ( void )
+{
+    union REGS regs;
+
+    regs.w.ax = 0x13;
+    int386(0x10,&regs,&regs);
+    graphicsmode=true;
+}
+
+/*
+====================
+=
+= SetTextMode
+=
+====================
+*/
+void SetTextMode ( void )
+{
+
+    union REGS regs;
+
+    regs.w.ax = 0x03;
+    int386(0x10,&regs,&regs);
+    graphicsmode=false;
+
+}
+
+/*
+====================
+=
+= TurnOffTextCursor
+=
+====================
+*/
+void TurnOffTextCursor ( void )
+{
+
+    union REGS regs;
+
+    regs.w.ax = 0x0100;
+    regs.w.cx = 0x2000;
+    int386(0x10,&regs,&regs);
+
+}
+
+#if 0
+/*
+====================
+=
+= TurnOnTextCursor
+=
+====================
+*/
+void TurnOnTextCursor ( void )
+{
+
+    union REGS regs;
+
+    regs.w.ax = 0x03;
+    int386(0x10,&regs,&regs);
+
+}
+#endif
+
+/*
+====================
+=
+= WaitVBL
+=
+====================
+*/
+void WaitVBL( void )
+{
+    unsigned char i;
+
+    i=inp(0x03da);
+    while ((i&8)==0)
+        i=inp(0x03da);
+    while ((i&8)==1)
+        i=inp(0x03da);
+}
+
+
+/*
+====================
+=
+= VL_SetLineWidth
+=
+= Line witdh is in WORDS, 40 words is normal width for vgaplanegr
+=
+====================
+*/
+
+void VL_SetLineWidth (unsigned width)
+{
+    int i,offset;
+
+//
+// set wide virtual screen
+//
+    outpw (CRTC_INDEX,CRTC_OFFSET+width*256);
+
+//
+// set up lookup tables
+//
+    linewidth = width*2;
+
+    offset = 0;
+
+    for (i=0; i<iGLOBAL_SCREENHEIGHT; i++)
+    {
+        ylookup[i]=offset;
+        offset += linewidth;
+    }
+}
+
+/*
+=======================
+=
+= VL_SetVGAPlaneMode
+=
+=======================
+*/
+
+void VL_SetVGAPlaneMode ( void )
+{
+    GraphicsMode();
+    VL_DePlaneVGA ();
+    VL_SetLineWidth (48);
+    screensize=208*iGLOBAL_SCREENBWIDE*2;//bna++ *2
+    page1start=0xa0200;
+    page2start=0xa0200+screensize;
+    page3start=0xa0200+(2u*screensize);
+    displayofs = page1start;
+    bufferofs = page2start;
+    XFlipPage ();
+}
+
+/*
+=======================
+=
+= VL_CopyPlanarPage
+=
+=======================
+*/
+void VL_CopyPlanarPage ( byte * src, byte * dest )
+{
+    int plane;
+
+    for (plane=0; plane<4; plane++)
+    {
+        VGAREADMAP(plane);
+        VGAWRITEMAP(plane);
+        memcpy(dest,src,screensize);
+    }
+}
+
+/*
+=======================
+=
+= VL_CopyPlanarPageToMemory
+=
+=======================
+*/
+void VL_CopyPlanarPageToMemory ( byte * src, byte * dest )
+{
+    byte * ptr;
+    int plane,a,b;
+
+    for (plane=0; plane<4; plane++)
+    {
+        ptr=dest+plane;
+        VGAREADMAP(plane);
+        for (a=0; a<200; a++)
+            for (b=0; b<80; b++,ptr+=4)
+                *(ptr)=*(src+(a*linewidth)+b);
+    }
+}
+
+/*
+=======================
+=
+= VL_CopyBufferToAll
+=
+=======================
+*/
+void VL_CopyBufferToAll ( byte *buffer )
+{
+    int plane;
+
+    for (plane=0; plane<4; plane++)
+    {
+        VGAREADMAP(plane);
+        VGAWRITEMAP(plane);
+        if (page1start!=buffer)
+            memcpy((byte *)page1start,(byte *)buffer,screensize);
+        if (page2start!=buffer)
+            memcpy((byte *)page2start,(byte *)buffer,screensize);
+        if (page3start!=buffer)
+            memcpy((byte *)page3start,(byte *)buffer,screensize);
+    }
+}
+
+/*
+=======================
+=
+= VL_CopyDisplayToHidden
+=
+=======================
+*/
+void VL_CopyDisplayToHidden ( void )
+{
+    VL_CopyBufferToAll ( displayofs );
+}
+
+/*
+=================
+=
+= VL_ClearBuffer
+=
+= Fill the entire video buffer with a given color
+=
+=================
+*/
+
+void VL_ClearBuffer (unsigned buf, byte color)
+{
+    VGAMAPMASK(15);
+    memset((byte *)buf,color,screensize);
+}
+
+/*
+=================
+=
+= VL_ClearVideo
+=
+= Fill the entire video buffer with a given color
+=
+=================
+*/
+
+void VL_ClearVideo (byte color)
+{
+    VGAMAPMASK(15);
+    memset((byte *)(0xa000<<4),color,0x10000);
+}
+
+/*
+=================
+=
+= VL_DePlaneVGA
+=
+=================
+*/
+
+void VL_DePlaneVGA (void)
+{
+
+//
+// change CPU addressing to non linear mode
+//
+
+//
+// turn off chain 4 and odd/even
+//
+    outp (SC_INDEX,SC_MEMMODE);
+    outp (SC_DATA,(inp(SC_DATA)&~8)|4);
+
+    outp (SC_INDEX,SC_MAPMASK);         // leave this set throughout
+
+//
+// turn off odd/even and set write mode 0
+//
+    outp (GC_INDEX,GC_MODE);
+    outp (GC_DATA,inp(GC_DATA)&~0x13);
+
+//
+// turn off chain
+//
+    outp (GC_INDEX,GC_MISCELLANEOUS);
+    outp (GC_DATA,inp(GC_DATA)&~2);
+
+//
+// clear the entire buffer space, because int 10h only did 16 k / plane
+//
+    VL_ClearVideo (0);
+
+//
+// change CRTC scanning from doubleword to byte mode, allowing >64k scans
+//
+    outp (CRTC_INDEX,CRTC_UNDERLINE);
+    outp (CRTC_DATA,inp(CRTC_DATA)&~0x40);
+
+    outp (CRTC_INDEX,CRTC_MODE);
+    outp (CRTC_DATA,inp(CRTC_DATA)|0x40);
+}
+
+
+/*
+=================
+=
+= XFlipPage
+=
+=================
+*/
+
+void XFlipPage ( void )
+{
+    displayofs=bufferofs;
+
+//   _disable();
+
+    outp(CRTC_INDEX,CRTC_STARTHIGH);
+    outp(CRTC_DATA,((displayofs&0x0000ffff)>>8));
+
+//   _enable();
+
+    bufferofs += screensize;
+    if (bufferofs > page3start)
+        bufferofs = page1start;
+}
+
+#else
+
+#include "SDL.h"
+
+#ifndef STUB_FUNCTION
+
+/* rt_def.h isn't included, so I just put this here... */
+#if !defined(ANSIESC)
+#define STUB_FUNCTION fprintf(stderr,"STUB: %s at " __FILE__ ", line %d, thread %d\n",__FUNCTION__,__LINE__,getpid())
+#else
+#define STUB_FUNCTION
+#endif
+
+#endif
+
+/*
+====================
+=
+= GraphicsMode
+=
+====================
+*/
+static SDL_Surface *sdl_surface = NULL;
+static SDL_Surface *unstretch_sdl_surface = NULL;
+
+void GraphicsMode ( void )
+{
+    Uint32 flags = 0;
+
+    if (SDL_InitSubSystem (SDL_INIT_VIDEO | SDL_INIT_AUDIO) < 0)
+    {
+        Error ("Could not initialize SDL\n");
+    }
+
+#if defined(PLATFORM_WIN32) || defined(PLATFORM_MACOSX)
+    // FIXME: remove this.  --ryan.
+    flags = SDL_FULLSCREEN;
+    SDL_WM_GrabInput(SDL_GRAB_ON);
+#endif
+
+    SDL_WM_SetCaption ("Rise of the Triad", "ROTT");
+    SDL_ShowCursor (0);
+//    sdl_surface = SDL_SetVideoMode (320, 200, 8, flags);
+    if (sdl_fullscreen)
+        flags = SDL_FULLSCREEN;
+    sdl_surface = SDL_SetVideoMode (iGLOBAL_SCREENWIDTH, iGLOBAL_SCREENHEIGHT, 8, flags);
+    if (sdl_surface == NULL)
+    {
+        Error ("Could not set video mode\n");
+    }
+}
+
+/*
+====================
+=
+= SetTextMode
+=
+====================
+*/
+void SetTextMode ( void )
+{
+    if (SDL_WasInit(SDL_INIT_VIDEO) == SDL_INIT_VIDEO) {
+        if (sdl_surface != NULL) {
+            SDL_FreeSurface(sdl_surface);
+
+            sdl_surface = NULL;
+        }
+
+        SDL_QuitSubSystem (SDL_INIT_VIDEO);
+    }
+}
+
+/*
+====================
+=
+= TurnOffTextCursor
+=
+====================
+*/
+void TurnOffTextCursor ( void )
+{
+}
+
+/*
+====================
+=
+= WaitVBL
+=
+====================
+*/
+void WaitVBL( void )
+{
+    SDL_Delay (16667/1000);
+}
+
+/*
+=======================
+=
+= VL_SetVGAPlaneMode
+=
+=======================
+*/
+
+void VL_SetVGAPlaneMode ( void )
+{
+    int i,offset;
+
+    GraphicsMode();
+
+//
+// set up lookup tables
+//
+//bna--   linewidth = 320;
+    linewidth = iGLOBAL_SCREENWIDTH;
+
+    offset = 0;
+
+    for (i=0; i<iGLOBAL_SCREENHEIGHT; i++)
+    {
+        ylookup[i]=offset;
+        offset += linewidth;
+    }
+
+//    screensize=MAXSCREENHEIGHT*MAXSCREENWIDTH;
+    screensize=iGLOBAL_SCREENHEIGHT*iGLOBAL_SCREENWIDTH;
+
+
+
+    page1start=sdl_surface->pixels;
+    page2start=sdl_surface->pixels;
+    page3start=sdl_surface->pixels;
+    displayofs = page1start;
+    bufferofs = page2start;
+
+    iG_X_center = iGLOBAL_SCREENWIDTH / 2;
+    iG_Y_center = (iGLOBAL_SCREENHEIGHT / 2)+10 ;//+10 = move aim down a bit
+
+    iG_buf_center = bufferofs + (screensize/2);//(iG_Y_center*iGLOBAL_SCREENWIDTH);//+iG_X_center;
+
+    bufofsTopLimit =  bufferofs + screensize - iGLOBAL_SCREENWIDTH;
+    bufofsBottomLimit = bufferofs + iGLOBAL_SCREENWIDTH;
+
+    // start stretched
+    EnableScreenStretch();
+    XFlipPage ();
+}
+
+/*
+=======================
+=
+= VL_CopyPlanarPage
+=
+=======================
+*/
+void VL_CopyPlanarPage ( byte * src, byte * dest )
+{
+#ifdef DOS
+    int plane;
+
+    for (plane=0; plane<4; plane++)
+    {
+        VGAREADMAP(plane);
+        VGAWRITEMAP(plane);
+        memcpy(dest,src,screensize);
+    }
+#else
+    memcpy(dest,src,screensize);
+#endif
+}
+
+/*
+=======================
+=
+= VL_CopyPlanarPageToMemory
+=
+=======================
+*/
+void VL_CopyPlanarPageToMemory ( byte * src, byte * dest )
+{
+#ifdef DOS
+    byte * ptr;
+    int plane,a,b;
+
+    for (plane=0; plane<4; plane++)
+    {
+        ptr=dest+plane;
+        VGAREADMAP(plane);
+        for (a=0; a<200; a++)
+            for (b=0; b<80; b++,ptr+=4)
+                *(ptr)=*(src+(a*linewidth)+b);
+    }
+#else
+    memcpy(dest,src,screensize);
+#endif
+}
+
+/*
+=======================
+=
+= VL_CopyBufferToAll
+=
+=======================
+*/
+void VL_CopyBufferToAll ( byte *buffer )
+{
+#ifdef DOS
+    int plane;
+
+    for (plane=0; plane<4; plane++)
+    {
+        VGAREADMAP(plane);
+        VGAWRITEMAP(plane);
+        if (page1start!=buffer)
+            memcpy((byte *)page1start,(byte *)buffer,screensize);
+        if (page2start!=buffer)
+            memcpy((byte *)page2start,(byte *)buffer,screensize);
+        if (page3start!=buffer)
+            memcpy((byte *)page3start,(byte *)buffer,screensize);
+    }
+#endif
+}
+
+/*
+=======================
+=
+= VL_CopyDisplayToHidden
+=
+=======================
+*/
+void VL_CopyDisplayToHidden ( void )
+{
+    VL_CopyBufferToAll ( displayofs );
+}
+
+/*
+=================
+=
+= VL_ClearBuffer
+=
+= Fill the entire video buffer with a given color
+=
+=================
+*/
+
+void VL_ClearBuffer (byte *buf, byte color)
+{
+#ifdef DOS
+    VGAMAPMASK(15);
+    memset((byte *)buf,color,screensize);
+#else
+    memset((byte *)buf,color,screensize);
+#endif
+}
+
+/*
+=================
+=
+= VL_ClearVideo
+=
+= Fill the entire video buffer with a given color
+=
+=================
+*/
+
+void VL_ClearVideo (byte color)
+{
+#ifdef DOS
+    VGAMAPMASK(15);
+    memset((byte *)(0xa000<<4),color,0x10000);
+#else
+    memset (sdl_surface->pixels, color, iGLOBAL_SCREENWIDTH*iGLOBAL_SCREENHEIGHT);
+#endif
+}
+
+/*
+=================
+=
+= VL_DePlaneVGA
+=
+=================
+*/
+
+void VL_DePlaneVGA (void)
+{
+}
+
+
+/* C version of rt_vh_a.asm */
+
+void VH_UpdateScreen (void)
+{
+
+    if (StretchScreen) { //bna++
+        StretchMemPicture ();
+    } else {
+        DrawCenterAim ();
+    }
+    SDL_UpdateRect (SDL_GetVideoSurface (), 0, 0, 0, 0);
+}
+
+
+/*
+=================
+=
+= XFlipPage
+=
+=================
+*/
+
+void XFlipPage ( void )
+{
+#ifdef DOS
+    displayofs=bufferofs;
+
+//   _disable();
+
+    outp(CRTC_INDEX,CRTC_STARTHIGH);
+    outp(CRTC_DATA,((displayofs&0x0000ffff)>>8));
+
+//   _enable();
+
+    bufferofs += screensize;
+    if (bufferofs > page3start)
+        bufferofs = page1start;
+#else
+    if (StretchScreen) { //bna++
+        StretchMemPicture ();
+    } else {
+        DrawCenterAim ();
+    }
+    SDL_UpdateRect (sdl_surface, 0, 0, 0, 0);
+
+#endif
+}
+
+#endif
+
+
+void EnableScreenStretch(void)
+{
+    int i,offset;
+
+    if (iGLOBAL_SCREENWIDTH <= 320 || StretchScreen) return;
+
+    if (unstretch_sdl_surface == NULL)
+    {
+        /* should really be just 320x200, but there is code all over the
+           places which crashes then */
+        unstretch_sdl_surface = SDL_CreateRGBSurface(SDL_SWSURFACE,
+                                iGLOBAL_SCREENWIDTH, iGLOBAL_SCREENHEIGHT, 8, 0, 0, 0, 0);
+    }
+
+    displayofs = unstretch_sdl_surface->pixels +
+                 (displayofs - (byte *)sdl_surface->pixels);
+    bufferofs  = unstretch_sdl_surface->pixels;
+    page1start = unstretch_sdl_surface->pixels;
+    page2start = unstretch_sdl_surface->pixels;
+    page3start = unstretch_sdl_surface->pixels;
+    StretchScreen = 1;
+}
+
+void DisableScreenStretch(void)
+{
+    if (iGLOBAL_SCREENWIDTH <= 320 || !StretchScreen) return;
+
+    displayofs = sdl_surface->pixels +
+                 (displayofs - (byte *)unstretch_sdl_surface->pixels);
+    bufferofs  = sdl_surface->pixels;
+    page1start = sdl_surface->pixels;
+    page2start = sdl_surface->pixels;
+    page3start = sdl_surface->pixels;
+    StretchScreen = 0;
+}
+
+
+// bna section -------------------------------------------
+static void StretchMemPicture ()
+{
+    SDL_Rect src;
+    SDL_Rect dest;
+
+    src.x = 0;
+    src.y = 0;
+    src.w = 320;
+    src.h = 200;
+
+    dest.x = 0;
+    dest.y = 0;
+    dest.w = iGLOBAL_SCREENWIDTH;
+    dest.h = iGLOBAL_SCREENHEIGHT;
+    SDL_SoftStretch(unstretch_sdl_surface, &src, sdl_surface, &dest);
+}
+
+// bna function added start
+extern	boolean ingame;
+extern exit_t playstate;
+int		iG_playerTilt;
+
+void DrawCenterAim ()
+{
+    int x;
+
+    int percenthealth = (locplayerstate->health * 10) / MaxHitpointsForCharacter(locplayerstate);
+    int color = percenthealth < 3 ? egacolor[RED] : percenthealth < 4 ? egacolor[YELLOW] : egacolor[GREEN];
+
+    if (iG_aimCross && !GamePaused && playstate != ex_died) {
+        if (( ingame == true )&&(iGLOBAL_SCREENWIDTH>320)) {
+            if ((iG_playerTilt <0 )||(iG_playerTilt >iGLOBAL_SCREENHEIGHT/2)) {
+                iG_playerTilt = -(2048 - iG_playerTilt);
+            }
+            if (iGLOBAL_SCREENWIDTH == 640) {
+                x = iG_playerTilt;
+                iG_playerTilt=x/2;
+            }
+            iG_buf_center = bufferofs + ((iG_Y_center-iG_playerTilt)*iGLOBAL_SCREENWIDTH);//+iG_X_center;
+
+            for (x=iG_X_center-10; x<=iG_X_center-4; x++) {
+                if ((iG_buf_center+x < bufofsTopLimit)&&(iG_buf_center+x > bufofsBottomLimit)) {
+                    *(iG_buf_center+x) = color;
+                }
+            }
+            for (x=iG_X_center+4; x<=iG_X_center+10; x++) {
+                if ((iG_buf_center+x < bufofsTopLimit)&&(iG_buf_center+x > bufofsBottomLimit)) {
+                    *(iG_buf_center+x) = color;
+                }
+            }
+            for (x=10; x>=4; x--) {
+                if (((iG_buf_center-(x*iGLOBAL_SCREENWIDTH)+iG_X_center) < bufofsTopLimit)&&((iG_buf_center-(x*iGLOBAL_SCREENWIDTH)+iG_X_center) > bufofsBottomLimit)) {
+                    *(iG_buf_center-(x*iGLOBAL_SCREENWIDTH)+iG_X_center) = color;
+                }
+            }
+            for (x=4; x<=10; x++) {
+                if (((iG_buf_center+(x*iGLOBAL_SCREENWIDTH)+iG_X_center) < bufofsTopLimit)&&((iG_buf_center+(x*iGLOBAL_SCREENWIDTH)+iG_X_center) > bufofsBottomLimit)) {
+                    *(iG_buf_center+(x*iGLOBAL_SCREENWIDTH)+iG_X_center) = color;
+                }
+            }
+        }
+    }
+}
+// bna function added end
+
+
+
+
+// bna section -------------------------------------------
+
+
+
--- /dev/null
+++ b/rott/modexlib.h
@@ -1,0 +1,173 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+//***************************************************************************
+//
+//    MODEXLIB.C - various utils palette funcs and modex stuff
+//
+//***************************************************************************
+
+#ifndef _modexlib_public
+#define _modexlib_public
+
+#include "WinRott.h"
+#include "rt_def.h"
+/*
+int iGLOBAL_SCREENWIDTH;//bna val 800
+int iGLOBAL_SCREENHEIGHT;//bna val 600
+
+
+#define MAXSCREENHEIGHT    600//     200*2
+#define MAXSCREENWIDTH     800//     320*2
+#define SCREENBWIDE        800*(96/320)//     96*2
+#define MAXVIEWWIDTH       800//     320*2
+#define SCREENWIDTH        800*(96/320)//     96*2              // default screen width in bytes
+*/
+//***************************************************************************
+//
+//    Video (ModeX) Constants
+//
+//***************************************************************************
+
+#ifdef DOS
+#define SC_INDEX                0x3C4
+#define SC_DATA                 0x3C5
+#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_DATA               0x3D5
+#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_DATA                 0x3CF
+#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
+#endif
+
+extern  boolean StretchScreen;//bn�++
+
+//extern  int      ylookup[MAXSCREENHEIGHT];      // Table of row offsets
+extern  int      ylookup[600];      // just set to max res
+extern  int      linewidth;
+extern  byte    *page1start;
+extern  byte    *page2start;
+extern  byte    *page3start;
+extern  int      screensize;
+extern  byte    *bufferofs;
+extern  byte    *displayofs;
+extern  boolean  graphicsmode;
+
+
+void  GraphicsMode ( void );
+void  SetTextMode ( void );
+void  VL_SetVGAPlaneMode ( void );
+void  VL_ClearBuffer (byte *buf, byte color);
+void  VL_ClearVideo (byte color);
+void  VL_DePlaneVGA (void);
+void  VL_CopyDisplayToHidden ( void );
+void  VL_CopyBufferToAll ( byte *buffer );
+void  VL_CopyPlanarPage ( byte * src, byte * dest );
+void  VL_CopyPlanarPageToMemory ( byte * src, byte * dest );
+void  XFlipPage ( void );
+void  WaitVBL( void );
+void  TurnOffTextCursor ( void );
+
+#ifdef __WATCOMC__
+#pragma aux VGAWRITEMAP =      \
+        "mov    eax,01H"       \
+        "mov    edx,03c5h"     \
+        "shl    eax,cl"        \
+        "out    dx,al"         \
+        parm    [ecx]          \
+        modify exact [eax edx]
+
+#pragma aux VGAMAPMASK =       \
+        "mov    edx,03c5h"     \
+        "out    dx,al"         \
+        parm    [eax]          \
+        modify exact [edx]
+
+#pragma aux VGAREADMAP =      \
+        "shl    eax,08H"      \
+        "mov    edx,03ceh"    \
+        "add    eax,04H"      \
+        "out    dx,ax"        \
+        parm    [eax]         \
+        modify exact [eax edx]
+#endif
+
+#ifdef DOS
+void  VGAMAPMASK (int x);
+void  VGAREADMAP (int x);
+void  VGAWRITEMAP(int x);
+#else
+#define VGAMAPMASK(a)
+#define VGAREADMAP(a)
+#define VGAWRITEMAP(a)
+#endif
+
+#endif
--- /dev/null
+++ b/rott/music.h
@@ -1,0 +1,96 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+/**********************************************************************
+   module: MUSIC.H
+
+   author: James R. Dose
+   date:   March 25, 1994
+
+   Public header for MUSIC.C
+
+   (c) Copyright 1994 James R. Dose.  All Rights Reserved.
+**********************************************************************/
+
+#ifndef __MUSIC_H
+#define __MUSIC_H
+
+#include "sndcards.h"
+
+extern int MUSIC_ErrorCode;
+
+enum MUSIC_ERRORS
+{
+    MUSIC_Warning = -2,
+    MUSIC_Error   = -1,
+    MUSIC_Ok      = 0,
+    MUSIC_ASSVersion,
+    MUSIC_SoundCardError,
+    MUSIC_MPU401Error,
+    MUSIC_InvalidCard,
+    MUSIC_MidiError,
+    MUSIC_TaskManError,
+    MUSIC_FMNotDetected,
+    MUSIC_DPMI_Error
+};
+
+typedef struct
+{
+    unsigned long tickposition;
+    unsigned long milliseconds;
+    unsigned int  measure;
+    unsigned int  beat;
+    unsigned int  tick;
+} songposition;
+
+#define MUSIC_LoopSong ( 1 == 1 )
+#define MUSIC_PlayOnce ( !MUSIC_LoopSong )
+
+char *MUSIC_ErrorString( int ErrorNumber );
+int   MUSIC_Init( int SoundCard, int Address );
+int   MUSIC_Shutdown( void );
+void  MUSIC_SetMaxFMMidiChannel( int channel );
+void  MUSIC_SetVolume( int volume );
+void  MUSIC_SetMidiChannelVolume( int channel, int volume );
+void  MUSIC_ResetMidiChannelVolumes( void );
+int   MUSIC_GetVolume( void );
+void  MUSIC_SetLoopFlag( int loopflag );
+int   MUSIC_SongPlaying( void );
+void  MUSIC_Continue( void );
+void  MUSIC_Pause( void );
+int   MUSIC_StopSong( void );
+int   MUSIC_PlaySong( unsigned char *song, int loopflag );
+
+// ROTT Special - SBF
+int   MUSIC_PlaySongROTT(unsigned char *song, int size, int loopflag);
+
+void  MUSIC_SetContext( int context );
+int   MUSIC_GetContext( void );
+void  MUSIC_SetSongTick( unsigned long PositionInTicks );
+void  MUSIC_SetSongTime( unsigned long milliseconds );
+void  MUSIC_SetSongPosition( int measure, int beat, int tick );
+void  MUSIC_GetSongPosition( songposition *pos );
+void  MUSIC_GetSongLength( songposition *pos );
+int   MUSIC_FadeVolume( int tovolume, int milliseconds );
+int   MUSIC_FadeActive( void );
+void  MUSIC_StopFade( void );
+void  MUSIC_RerouteMidiChannel( int channel, int cdecl ( *function )( int event, int c1, int c2 ) );
+void  MUSIC_RegisterTimbreBank( unsigned char *timbres );
+
+#endif
--- /dev/null
+++ b/rott/myprint.h
@@ -1,0 +1,43 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+#ifndef __MYPRINT_H
+#define __MYPRINT_H
+
+enum COLORS
+{
+    BLACK, BLUE, GREEN, CYAN, RED, MAGENTA, BROWN, LIGHTGRAY, DARKGRAY,
+    LIGHTBLUE, LIGHTGREEN, LIGHTCYAN, LIGHTRED, LIGHTMAGENTA, YELLOW, WHITE
+};
+
+#define NONE         -1
+#define SINGLE_FRAME -1
+#define DOUBLE_FRAME -2
+
+void DrawRottText( int x, int y, int ch, int foreground, int background );
+void TextBox( int x1, int y1, int x2, int y2, int ch, int foreground, int background );
+void TextFrame( int x1, int y1, int x2, int y2, int type, int foreground, int background );
+void mysetxy( int x, int y );
+void myputch( char ch );
+int  printstring( char *string );
+int  printnum( int number );
+int  printunsigned( unsigned long number, int radix );
+int  myprintf( char *fmt, ... ) __attribute__((format(printf,1,2)));
+
+#endif
--- /dev/null
+++ b/rott/profile.h
@@ -1,0 +1,26 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+#ifndef _profile
+#define _profile
+
+#define PROFILE 0
+#define PROFILETICS 2
+
+#endif
--- /dev/null
+++ b/rott/rottnet.h
@@ -1,0 +1,102 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+// rottnet.h
+#ifndef rottnet_public
+#define rottnet_public
+
+#include "develop.h"
+
+#ifdef DOS
+#define PEL_WRITE_ADR   0x3c8
+#define PEL_DATA        0x3c9
+
+#define I_ColorBlack(r,g,b) {outp(PEL_WRITE_ADR,0);outp(PEL_DATA,r);outp(PEL_DATA,g);outp(PEL_DATA,b);};
+#endif
+
+#define	MAXNETNODES		14			// max computers in a game
+
+#if ( SHAREWARE == 1 )
+#define  MAXPLAYERS     5        // 5 players max + drones
+#else
+#define	MAXPLAYERS		11			// 11 players max + drones
+#endif
+
+#define	CMD_SEND	   1
+#define	CMD_GET		2
+#define  CMD_OUTQUEBUFFERSIZE 3
+#define  CMD_INQUEBUFFERSIZE  4
+
+#define	ROTTCOM_ID		0x12345678l
+
+#define  MAXPACKETSIZE 2048
+#define	MAXCOMBUFFERSIZE 2048
+
+#if __WATCOMC__
+#pragma pack (1)
+#endif
+
+typedef struct
+{
+    short	intnum;			// ROTT executes an int to send commands
+
+// communication between ROTT 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 rottdata to be sent / bytes read
+
+// info specific to this node
+    short	consoleplayer;	// 0-3 = player number
+    short	numplayers;		// 1-4
+    short   client;         // 0 = server 1 = client
+    short   gametype;       // 0 = modem  1 = network
+    short   ticstep;        // 1 for every tic 2 for every other tic ...
+    short   remoteridicule; // 0 = remote ridicule is off 1= rr is on
+
+// packet data to be sent
+    char	data[MAXPACKETSIZE];
+} rottcom_t;
+
+#if __WATCOMC__
+#pragma pack (4)
+#endif
+
+#define  MODEM_GAME   0
+#define	NETWORK_GAME 1
+
+#define	ROTTLAUNCHER ("ROTT.EXE")
+
+#if defined(DOS) && (__WATCOMC__ == 0)
+
+extern   rottcom_t   rottcom;
+extern   boolean     pause;
+
+void ShutdownROTTCOM ( void );
+int  CheckParm (char *check);
+void LaunchROTT (void);
+void NetISR (void);
+long GetVector (void);
+
+#else
+
+extern   rottcom_t   * rottcom;
+
+#endif
+
+#endif
--- /dev/null
+++ b/rott/rt_actor.c
@@ -1,0 +1,14028 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+
+
+#include <string.h>
+#include <stdlib.h>
+#include "rt_def.h"
+#include "rt_sound.h"
+#include "rt_door.h"
+#include "rt_ted.h"
+#include "rt_draw.h"
+#include "watcom.h"
+#include "z_zone.h"
+#include "w_wad.h"
+#include "lumpy.h"
+#include "gmove.h"
+#include "states.h"
+#include "rt_sqrt.h"
+#include "rt_stat.h"
+#include "sprites.h"
+#include "rt_actor.h"
+#include "rt_game.h"
+#include "rt_main.h"
+#include "rt_playr.h"
+#include "rt_util.h"
+#include "rt_rand.h"
+#include "rt_menu.h"
+#include "rt_swift.h"
+#include "_rt_acto.h"
+#include "rt_cfg.h"
+#include "rt_floor.h"
+#include "engine.h"
+#include "develop.h"
+#include "rt_view.h"
+#include "isr.h"
+#include "rt_com.h"
+#include "rt_scale.h"
+#include "modexlib.h"
+#include "rt_net.h"
+#include "rt_msg.h"
+#include "fx_man.h"
+//MED
+#include "memcheck.h"
+
+
+
+
+#define SGN(x)  (((x) > 0)?(1):(-1))
+
+
+
+#define WILEYBLITZCHANCE  20
+#define GIBSOUND       SD_GIBSPLASHSND
+#define ACTORTHUDSND   SD_BODYLANDSND
+#define ACTORLANDSND   SD_PLAYERLANDSND
+
+//========================== Global Variables ===================================================
+
+#define SHP(difficulty,ob)  (starthitpoints[difficulty][ob->obclass])
+
+#define CAP_OSCUROS_HITPOINTS(ob)                         \
+   {                                                      \
+   if (ob->hitpoints > (SHP(gamestate.difficulty,ob)<<1)) \
+      ob->hitpoints = (SHP(gamestate.difficulty,ob)<<1);  \
+   }
+
+
+boolean           ludicrousgibs=false;
+
+short             colheight[15];
+
+byte              deathshapeoffset[8] = {0,7,7,8,8,9,8,7};
+
+unsigned long     MAXFUNCTION,MINFUNCTION,MAXSTATE,MINSTATE;
+
+objtype           *PLAYER0MISSILE;
+objtype           *SCREENEYE;
+objtype           *FIRSTACTOR,*LASTACTOR;
+
+objtype           *FIRSTFREE,*LASTFREE;
+objtype           *lastactive,*firstactive,**objlist;
+objtype           *firstareaactor[NUMAREAS+1],*lastareaactor[NUMAREAS+1];
+int               objcount;
+
+byte              RANDOMACTORTYPE[10];
+
+#if (SHAREWARE == 0)
+_2Dpoint          SNAKEPATH[512];
+#endif
+misc_stuff        mstruct,*MISCVARS = &mstruct;
+int               angletodir[ANGLES];
+objtype           *new;
+
+void              *actorat[MAPSIZE][MAPSIZE];
+#if (DEVELOPMENT == 1)
+FILE *            williamdebug;
+#endif
+exit_t            playstate;
+
+void              T_SlideDownScreen(objtype*);
+
+basic_actor_sounds  BAS[NUMCLASSES+3] =
+{   {0,0,0,0,0},
+    {0,0,0,0,0},
+    {0,SD_LOWGUARD1SEESND,SD_LOWGUARDFIRESND,SD_LOWGUARDOUCHSND,SD_LOWGUARD1DIESND},
+    {0,SD_HIGHGUARD1SEESND,SD_HIGHGUARDFIRESND,SD_HIGHGUARDOUCHSND,SD_HIGHGUARDDIESND},
+    {0,SD_OVERP1SEESND,SD_OVERPFIRESND,SD_OVERPOUCHSND,SD_OVERPDIESND},
+    {0,SD_STRIKE1SEESND,SD_STRIKEFIRESND,SD_STRIKEOUCHSND,SD_STRIKEDIESND},
+    {0,SD_BLITZ1SEESND,SD_BLITZFIRESND,SD_BLITZOUCHSND,SD_BLITZDIESND},
+    {0,SD_ENFORCERSEESND,SD_ENFORCERFIRESND,SD_ENFORCEROUCHSND,SD_ENFORCERDIESND},
+    {0,SD_MONKSEESND,SD_MONKGRABSND,SD_MONKOUCHSND,SD_MONKDIESND},
+    {0,SD_FIREMONKSEESND,SD_FIREMONKFIRESND,SD_FIREMONKOUCHSND,SD_FIREMONKDIESND},
+    {0,SD_ROBOTSEESND,SD_ROBOTFIRESND,0,SD_ROBOTDIESND},
+
+    //bosses
+    {SD_DARIANSAY1,SD_DARIANSEESND,SD_DARIANFIRESND,0,SD_DARIANDIESND},
+    {SD_KRISTSAY1,SD_KRISTSEESND,SD_KRISTFIRESND,0,SD_KRISTDIESND},
+    {0,SD_NMESEESND,SD_NMEFIRE1SND,0,SD_NMEDIESND},
+    {SD_DARKMONKSAY1,SD_DARKMONKSEESND,SD_DARKMONKFIRE1SND,0,SD_DARKMONKDIESND},
+    {SD_SNAKESAY1,SD_SNAKESEESND,SD_SNAKESPITSND,0,SD_SNAKEDIESND},
+
+    //specials
+    {0,SD_EMPLACEMENTSEESND,SD_EMPLACEMENTFIRESND,0,0},
+    {0,SD_ROBOTSEESND,SD_ROBOTFIRESND,0,SD_ROBOTDIESND}, //wallop
+    {0,0,0,0,0}, //pillar
+    {SD_FIREJETSND,0,0,0,0}, //firejet
+    {SD_BLADESPINSND,0,0,0,0}, //blade
+    {SD_CYLINDERMOVESND,0,0,0,0}, //crushcol
+    {SD_BOULDERROLLSND,0,0,SD_BOULDERHITSND,0}, //boulder
+    {SD_SPEARSTABSND,0,0,0,0}, //spear
+    {0,0,0,0,0}, //gasgrate
+    {SD_SPRINGBOARDSND,0,0,0,0}, //spring
+    {0,0,0,0,0}, //shuriken
+    {SD_FIREBALLSND,0,0,SD_FIREBALLHITSND,0}, //wallfire
+    {0,0,0,0,0}, //net
+    {SD_KRISTMINEBEEPSND,0,0,0,0}, //h_mine
+    {0,0,0,0,0}, //grenade
+    {0,0,0,0,0}, //fireball
+    {0,0,0,0,0}, //dmfball
+    {0,0,0,0,0}, //bigshuriken
+    {0,0,0,0,0}, //missile
+    {0,0,0,0,0}, //NMEsaucer
+    {0,0,0,0,0}, //dm_weapon
+    {0,0,0,0,0}, //dm_heatseek
+    {0,0,0,0,0}, //dm_spit
+    {SD_MISSILEFLYSND,0,SD_BAZOOKAFIRESND,SD_MISSILEHITSND,0},
+    {SD_MISSILEFLYSND,0,SD_FIREBOMBFIRESND,SD_MISSILEHITSND,0},
+    {SD_MISSILEFLYSND,0,SD_HEATSEEKFIRESND,SD_MISSILEHITSND,0},
+    {SD_MISSILEFLYSND,0,SD_DRUNKFIRESND,SD_MISSILEHITSND,0},
+    {SD_FLAMEWALLSND,0,SD_FLAMEWALLFIRESND,SD_FIREHITSND,0},
+    {SD_MISSILEFLYSND,0,SD_SPLITFIRESND,SD_MISSILEHITSND,0},
+    {SD_GRAVSND,0,SD_GRAVFIRESND,SD_GRAVHITSND,0},
+    {SD_GRAVSND,0,SD_GODMODEFIRESND,SD_GRAVHITSND,0}
+
+};
+
+
+//========================== Local Variables ==================================================
+
+extern boolean dopefish;
+
+
+boolean Masterdisk;
+
+static objtype    *SNAKEHEAD,*SNAKEEND,*PARTICLE_GENERATOR,*EXPLOSIONS;
+#if (SHAREWARE == 0)
+static int        OLDTILEX,OLDTILEY;
+#endif
+
+
+static char *debugstr[] = {
+
+    "inerttype",
+    "player",
+    "lowguard",
+    "highguard",
+    "overpatrol",
+    "strikeguard",
+    "blitzguard",
+    "triadenforcer",
+    "deathmonk",
+    "dfiremonk",
+    "roboguard",
+    "b_darian",
+    "b_heinrich",
+    "b_darkmonk",
+    "b_roboboss",
+    "b_darksnake",
+    "patrolgun",
+    "wallop",
+    "pillar",
+    "firejet",
+    "blade",
+    "crushcol",
+    "boulder",
+    "spear",
+    "gasgrate",
+    "spring",
+    "shuriken",
+    "wallfire",
+    "net",
+    "h_mine",
+    "grenade",
+    "fireball",
+    "dmfball",
+    "bigshuriken",
+    "missile",
+    "NMEsaucer",
+    "dm_weapon",
+    "dm_heatseek",
+    "dm_spit",
+    "p_bazooka",
+    "p_firebomb",
+    "p_heatseek",
+    "p_drunkmissile",
+    "p_firewall",
+    "p_splitmissile",
+    "p_kes",
+    "p_godball",
+    "collectorobj"
+};
+
+
+
+
+
+
+
+static int        starthitpoints[4][NUMENEMIES+2] =
+
+{   {0,0,30,35,50,40,45,425,200,200,100,1500,2500,3000,3000,-1,200,2},
+    {0,0,40,50,55,50,50,475,250,250,125,2300,3400,4500,3600,-1,250,2},
+    {0,0,50,65,60,60,60,525,275,300,150,2400,3600,5000,4500,-1,300,2},
+    {0,0,60,80,70,70,75,525,300,350,175,2800,3800,5900,4800,-1,350,2}
+};
+
+
+static statobj_t  *touchsprite = NULL;
+
+
+static const byte dirdiff[8][8] = {{0,1,2,3,4,3,2,1},{1,0,1,2,3,4,3,2},
+    {2,1,0,1,2,3,4,3},{3,2,1,0,1,2,3,4},
+    {4,3,2,1,0,1,2,3},{3,4,3,2,1,0,1,2},
+    {2,3,4,3,2,1,0,1},{1,2,3,4,3,2,1,0}
+};
+
+static const byte dirorder[8][2] = {{southeast,northeast},{east,north},
+    {northeast,northwest},{north,west},
+    {northwest,southwest},{west,south},
+    {southwest,southeast},{south,east}
+};
+
+#if (SHAREWARE == 0)
+
+static const byte dirdiff16[16][16] = {
+    {0,1,2,3,4,5,6,7,8,7,6,5,4,3,2,1},
+    {1,0,1,2,3,4,5,6,7,8,7,6,5,4,3,2},
+    {2,1,0,1,2,3,4,5,6,7,8,7,6,5,4,3},
+    {3,2,1,0,1,2,3,4,5,6,7,8,7,6,5,4},
+    {4,3,2,1,0,1,2,3,4,5,6,7,8,7,6,5},
+    {5,4,3,2,1,0,1,2,3,4,5,6,7,8,7,6},
+    {6,5,4,3,2,1,0,1,2,3,4,5,6,7,8,7},
+    {7,6,5,4,3,2,1,0,1,2,3,4,5,6,7,8},
+    {8,7,6,5,4,3,2,1,0,1,2,3,4,5,6,7},
+    {7,8,7,6,5,4,3,2,1,0,1,2,3,4,5,6},
+    {6,7,8,7,6,5,4,3,2,1,0,1,2,3,4,5},
+    {5,6,7,8,7,6,5,4,3,2,1,0,1,2,3,4},
+    {4,5,6,7,8,7,6,5,4,3,2,1,0,1,2,3},
+    {3,4,5,6,7,8,7,6,5,4,3,2,1,0,1,2},
+    {2,3,4,5,6,7,8,7,6,5,4,3,2,1,0,1},
+    {1,2,3,4,5,6,7,8,7,6,5,4,3,2,1,0}
+};
+#endif
+
+static const byte dirorder16[16][2] = {
+    {15,1},   {0,2},   {1,3},   {2,4},
+    {3,5},   {4,6},   {5,7},   {6,8},
+    {7,9},  {8,10},  {9,11}, {10,12},
+    {11,13}, {12,14}, {13,15},  {14,0}
+};
+
+//static byte opposite16[16] = {8,9,10,11,12,13,14,15,0,1,2,3,4,5,6,7};
+
+#if (SHAREWARE == 0)
+
+static statetype * UPDATE_STATES[NUMSTATES][NUMENEMIES] =
+
+{   {   &s_lowgrdstand,&s_highgrdstand,&s_opstand,&s_strikestand,
+        &s_blitzstand,&s_enforcerstand,&s_dmonkstand,&s_firemonkstand,
+        &s_robogrdstand,&s_darianstand,&s_heinrichstand,NULL,
+        &s_darkmonkstand,NULL,&s_gunstand,&s_wallstand
+    },
+
+    {   &s_lowgrdpath1,&s_highgrdpath1,&s_oppath1,&s_strikepath1,
+        &s_blitzpath1,&s_enforcerpath1,&s_dmonkpath1,&s_firemonkpath1,
+        &s_robogrdpath1,NULL,NULL,NULL,
+        NULL,NULL,NULL,&s_wallpath
+    },
+
+    {   &s_lowgrdcollide,&s_highgrdcollide,&s_opcollide,&s_strikecollide,
+        &s_blitzcollide,&s_enforcercollide,&s_dmonkcollide,&s_firemonkcollide,
+        &s_robogrdcollide,&s_dariancollide,NULL,NULL,
+        NULL,NULL,NULL,&s_wallcollide
+    },
+
+    {   &s_lowgrdcollide2,&s_highgrdcollide2,&s_opcollide2,&s_strikecollide2,
+        &s_blitzcollide2,&s_enforcercollide2,&s_dmonkcollide2,&s_firemonkcollide2,
+        &s_robogrdcollide2,&s_dariancollide2,NULL,NULL,
+        NULL,NULL,NULL,&s_wallcollide
+    },
+
+    {   &s_lowgrdchase1,&s_highgrdchase1,&s_opchase1,&s_strikechase1,
+        &s_blitzchase1,&s_enforcerchase1,&s_dmonkchase1,&s_firemonkchase1,
+        NULL/*se1*/,&s_darianchase1,&s_heinrichchase,&s_NMEchase,
+        &s_darkmonkchase1,NULL,&s_gunstand,&s_wallpath
+    },
+
+    /*
+    {&s_lowgrduse1,&s_highgrduse1,&s_opuse1,&s_strikeuse1,
+     &s_blitzuse,&s_enforceruse1,NULL,NULL,
+     NULL,&s_darianuse1,NULL,NULL,
+     NULL,NULL,NULL,NULL},*/
+    {0},
+
+    {   &s_lowgrdshoot1,&s_highgrdshoot1,&s_opshoot1,&s_strikeshoot1,
+        &s_blitzshoot1,&s_enforcershoot1,NULL,&s_firemonkcast1,
+        &s_robogrdshoot1,&s_darianshoot1,&s_heinrichshoot1,NULL,
+        NULL,NULL,&s_gunfire1,&s_wallshoot
+    },
+
+    {   &s_lowgrddie1,&s_highgrddie1,&s_opdie1,&s_strikedie1,
+        &s_blitzdie1,&s_enforcerdie1,&s_dmonkdie1,&s_firemonkdie1,
+        &s_robogrddie1,&s_dariandie1,&s_heinrichdie1,&s_NMEdie,
+        &s_darkmonkdie1,NULL,&s_gundie1,NULL
+    },
+
+    {0},
+
+    {   NULL,NULL,NULL,&s_strikewait,
+        &s_blitzstand,&s_enforcerdie1,&s_dmonkdie1,&s_firemonkdie1,
+        &s_robogrddie1,&s_dariandie1,&s_heinrichdie1,NULL,
+        &s_darkmonkdie1,NULL,NULL,NULL
+    },
+
+    {   &s_lowgrdcrushed1,&s_highgrdcrushed1,&s_opcrushed1,&s_strikecrushed1,
+        &s_blitzcrushed1,&s_enforcercrushed1,&s_dmonkcrushed1,&s_firemonkcrushed1,
+        &s_robogrddie1,NULL,NULL,NULL,
+        NULL,NULL,NULL,NULL
+    }
+
+};
+
+#else
+
+static statetype * UPDATE_STATES[NUMSTATES][NUMENEMIES] =
+
+{   {   &s_lowgrdstand,&s_highgrdstand,NULL,&s_strikestand,
+        &s_blitzstand,&s_enforcerstand,NULL,NULL,
+        &s_robogrdstand,NULL,NULL,NULL,
+        NULL,NULL,NULL,NULL
+    },
+
+    {   &s_lowgrdpath1,&s_highgrdpath1,NULL,&s_strikepath1,
+        &s_blitzpath1,&s_enforcerpath1,NULL,NULL,
+        &s_robogrdpath1,NULL,NULL,NULL,
+        NULL,NULL,NULL,NULL
+    },
+
+    {   &s_lowgrdcollide,&s_highgrdcollide,NULL,&s_strikecollide,
+        &s_blitzcollide,&s_enforcercollide,NULL,NULL,
+        NULL,NULL,NULL,NULL,
+        NULL,NULL,NULL,NULL
+    },
+
+    {   &s_lowgrdcollide2,&s_highgrdcollide2,NULL,&s_strikecollide2,
+        &s_blitzcollide2,&s_enforcercollide2,NULL,NULL,
+        &s_robogrdcollide2,NULL,NULL,NULL,
+        NULL,NULL,NULL,NULL
+    },
+
+    {   &s_lowgrdchase1,&s_highgrdchase1,NULL,&s_strikechase1,
+        &s_blitzchase1,&s_enforcerchase1,NULL,NULL,
+        NULL,NULL,NULL,NULL,
+        NULL,NULL,NULL,NULL
+    },
+
+    /*
+    {&s_lowgrduse1,&s_highgrduse1,&s_opuse1,&s_strikeuse1,
+     &s_blitzuse,&s_enforceruse1,NULL,NULL,
+     NULL,&s_darianuse1,NULL,NULL,
+     NULL,NULL,NULL,NULL},*/
+    {0},
+
+    {   &s_lowgrdshoot1,&s_highgrdshoot1,NULL,&s_strikeshoot1,
+        &s_blitzshoot1,&s_enforcershoot1,NULL,NULL,
+        &s_robogrdshoot1,NULL,NULL,NULL,
+        NULL,NULL,NULL,NULL
+    },
+
+    {   &s_lowgrddie1,&s_highgrddie1,NULL,&s_strikedie1,
+        &s_blitzdie1,&s_enforcerdie1,NULL,NULL,
+        &s_robogrddie1,NULL,NULL,NULL,
+        NULL,NULL,NULL,NULL
+    },
+
+    {0},
+
+    {   NULL,NULL,NULL,&s_strikewait,
+        &s_blitzstand,&s_enforcerdie1,NULL,NULL,
+        &s_robogrddie1,NULL,NULL,NULL,
+        NULL,NULL,NULL,NULL
+    },
+
+    {   &s_lowgrdcrushed1,&s_highgrdcrushed1,NULL,&s_strikecrushed1,
+        &s_blitzcrushed1,&s_enforcercrushed1,NULL,NULL,
+        &s_robogrddie1,NULL,NULL,NULL,
+        NULL,NULL,NULL,NULL
+    }
+
+};
+
+#endif
+
+
+
+#define TABLE_ACTOR(ob)  ((ob->obclass >= lowguardobj) && (ob->obclass <= wallopobj))
+
+
+void T_Reset(objtype*ob);
+void ApplyGravity(objtype *ob);
+void BeginEnemyHurt(objtype *ob);
+void T_PlayDead(objtype *ob);
+void SpawnFirewall(objtype*ob,int which,int newz);
+void SelectKristChaseDir(objtype*ob);
+void ExplodeStatic(statobj_t*tempstat);
+void AvoidPlayerMissile(objtype*ob);
+int EnvironmentDamage(objtype *ob);
+
+static int     STOPSPEED         =    0x200;
+static int     PLAYERFRICTION    =    0xe000;
+static int     ACTORFRICTION     =    0xf000;
+static int     DIAGADJUST        =    0xb504;
+static boolean MissileSound      =    true;
+
+
+
+
+boolean FirstExplosionState(statetype *state)
+{
+    if (DoPanicMapping())
+    {
+        if (state == &s_altexplosion1)
+            return true;
+        else
+            return false;
+    }
+    else
+    {
+        if ((state == &s_explosion1) ||
+                (state == &s_grexplosion1) ||
+                (state == &s_staticexplosion1)
+           )
+            return true;
+        else
+            return false;
+    }
+
+}
+
+
+
+
+
+void SetGibSpeed(int speed)
+{
+    MISCVARS->gibspeed = speed;
+}
+
+void ResetGibSpeed(void)
+{
+    MISCVARS->gibspeed = NORMALGIBSPEED;
+}
+
+int ValidAreanumber (int areanumber)
+{   if ((areanumber >=0) && (areanumber <= NUMAREAS))
+        return 1;
+    return 0;
+}
+
+int GetIndexForState (statetype * state)
+{
+    int i;
+
+    if (state == NULL)
+        return -1;
+
+    for (i=0; i<MAXSTATES; i++)
+    {
+        if (statetable[i]==state)
+            return i;
+    }
+    Error("Cannot find the state in 'GetIndexForState', state->shapenum = %d\n",state->shapenum);
+    return -1;
+}
+
+
+
+statetype * GetStateForIndex (int index)
+{
+    if (index == -1)
+        return NULL;
+
+    return statetable[index];
+}
+
+
+statobj_t* GetStaticForIndex(int index)
+{   statobj_t* temp;
+
+    for(temp=FIRSTSTAT; temp; temp=temp->statnext)
+        if (index == temp->whichstat)
+            return temp;
+
+    Error("Cannot find the static in 'GetStaticForIndex', statindex %d\n",index);
+    return NULL;
+
+}
+
+
+
+void SaveActors(byte **buffer,int*size)
+{   objtype*temp,*tact;
+    saved_actor_type dummy;
+    byte*tptr;
+    int actorcount;
+
+
+    for(actorcount=0,temp=FIRSTACTOR; temp; temp=temp->next)
+        temp->whichactor = actorcount++;
+
+
+
+    *size = sizeof(int) + sizeof(numplayers) + sizeof(misc_stuff) + objcount*sizeof(saved_actor_type);
+    *buffer = (byte*)SafeMalloc(*size);
+    tptr = *buffer;
+
+    memcpy(tptr,MISCVARS,sizeof(misc_stuff));
+    tptr += sizeof(misc_stuff);
+
+    memcpy(tptr,&numplayers,sizeof(numplayers));
+    tptr += sizeof(numplayers);
+
+    memcpy(tptr,&consoleplayer,sizeof(consoleplayer));
+    tptr += sizeof(consoleplayer);
+
+    for(temp=FIRSTACTOR; temp; temp=temp->next)
+    {   dummy.x = temp->x;
+        dummy.y = temp->y;
+        dummy.z = temp->z;
+        dummy.flags = temp->flags;
+        dummy.areanumber = temp->areanumber;
+        //dummy.whichactor = temp->whichactor;
+        dummy.hitpoints = temp->hitpoints;
+        dummy.ticcount = temp->ticcount;
+        dummy.obclass = (byte)(temp->obclass);
+        dummy.stateindex = GetIndexForState(temp->state);
+        dummy.shapeoffset = temp->shapeoffset;
+        dummy.dirchoosetime = temp->dirchoosetime;
+        dummy.door_to_open = temp->door_to_open;
+        dummy.targetx = temp->targettilex;
+        dummy.targety = temp->targettiley;
+        dummy.dir = (signed char)temp->dir;
+        dummy.angle = temp->angle;
+        dummy.yzangle = temp->yzangle;
+        dummy.speed = temp->speed;
+        dummy.momentumx = temp->momentumx;
+        dummy.momentumy = temp->momentumy;
+        dummy.momentumz = temp->momentumz;
+
+        dummy.temp1 = temp->temp1;
+        dummy.temp2 = temp->temp2;
+        dummy.temp3 = temp->temp3;
+        if (temp->whatever)
+        {   /*if ((temp->flags & FL_USE) && (temp!=player))
+              {dummy.whateverindex = (GetIndexForState((statetype*)(temp->whatever))|SG_PSTATE);
+            	if ((dummy.whateverindex < 0) && (dummy.whateverindex != -1))
+            	  Error("Bad actor whatever save value of %d\n",dummy.whateverindex);
+              }
+            else*/
+            {   tact = (objtype*)(temp->whatever);
+                if (tact->which == ACTOR)
+                    dummy.whateverindex = tact->whichactor;
+                else
+                {   statobj_t *tstat;
+
+                    tstat = (statobj_t*)(temp->whatever);
+                    dummy.whateverindex = (tstat->whichstat|SG_PSTAT);
+
+                }
+            }
+        }
+        else
+            dummy.whateverindex = -1;
+
+
+        if (temp->target)
+        {   tact = (objtype*)(temp->target);
+            if (tact->which == ACTOR)
+            {   dummy.targetindex = tact->whichactor;
+                Debug("\nsave actor %d, type %d has target %d",temp->whichactor,temp->obclass,tact->whichactor);
+            }
+            else if (tact->which == SPRITE)
+            {   statobj_t *tstat;
+
+                tstat = (statobj_t*)(temp->target);
+                dummy.targetindex = (tstat->whichstat|SG_PSTAT);
+            }
+            else // It must be a push wall, and we don't save that
+                dummy.targetindex=-1;
+        }
+        else
+            dummy.targetindex = -1;
+
+
+        memcpy(tptr,&(dummy.x),sizeof(saved_actor_type));
+        tptr += sizeof(saved_actor_type);
+
+    }
+
+}
+
+
+
+void LoadActors(byte *buffer,int size)
+{
+    int numactors,i,playerindex;
+    saved_actor_type dummy;
+    objtype *temp;
+    short *targetindices,*whateverindices;
+
+    InitActorList();
+
+    memcpy(MISCVARS,buffer,sizeof(misc_stuff));
+    buffer += sizeof(misc_stuff);
+
+    memcpy(&numplayers,buffer,sizeof(numplayers));
+    buffer += sizeof(numplayers);
+
+    memcpy(&playerindex,buffer,sizeof(playerindex));
+    buffer += sizeof(playerindex);
+
+    size -= (sizeof(misc_stuff)+sizeof(numplayers)+sizeof(playerindex));
+    numactors = size/sizeof(saved_actor_type);
+
+
+    objlist = (objtype**)SafeMalloc(numactors*sizeof(objtype*));
+    targetindices = (short*)SafeMalloc(numactors*sizeof(short));
+    whateverindices = (short*)SafeMalloc(numactors*sizeof(short));
+
+    for(i=0; i<numactors; i++)
+    {
+        targetindices[i] = 0;
+        whateverindices[i] = 0;
+        objlist[i] = NULL;
+    }
+
+
+    for(i=0; i<numactors; i++)
+    {
+        GetNewActor();
+        objlist[i] = new;
+        if (i < numplayers)
+        {
+            PLAYER[i]=new;
+            if (i==playerindex)
+                player=new;
+        }
+
+        memcpy(&(dummy.x),buffer,sizeof(saved_actor_type));
+
+        //new->x = dummy.x;
+        //new->y = dummy.y;
+        SetFinePosition(new,dummy.x,dummy.y);
+        SetVisiblePosition(new,dummy.x,dummy.y);
+        new->z = dummy.z;
+        new->flags = dummy.flags;
+        new->hitpoints = dummy.hitpoints;
+        new->ticcount = dummy.ticcount;
+        new->shapeoffset = dummy.shapeoffset;
+        new->obclass = (classtype)(dummy.obclass);
+
+
+        new->state = GetStateForIndex(dummy.stateindex);
+        if (new->state == &s_superparticles)
+            PARTICLE_GENERATOR = new;
+        else if
+        (new->state->think == T_SlideDownScreen)
+            SCREENEYE = new;
+        new->dirchoosetime = dummy.dirchoosetime;
+        new->door_to_open = dummy.door_to_open;
+        new->targettilex = dummy.targetx;
+        new->targettiley = dummy.targety;
+        new->dir = (dirtype)(dummy.dir);
+        new->angle = dummy.angle;
+        new->yzangle = dummy.yzangle;
+        new->speed = dummy.speed;
+        new->momentumx = dummy.momentumx;
+        new->momentumy = dummy.momentumy;
+        new->momentumz = dummy.momentumz;
+        new->temp1 = dummy.temp1;
+        new->temp2 = dummy.temp2;
+        new->temp3 = dummy.temp3;
+        if (dummy.whateverindex == -1)
+            new->whatever = NULL;
+
+        else if (dummy.whateverindex & SG_PSTAT)
+            new->whatever = GetStaticForIndex(dummy.whateverindex & ~SG_PSTAT);
+        else
+            whateverindices[i] = dummy.whateverindex+1;
+
+
+        if (dummy.targetindex == -1)
+            new->target = NULL;
+        else if (dummy.targetindex & SG_PSTAT)
+            new->target = GetStaticForIndex(dummy.targetindex & ~SG_PSTAT);
+        else
+        {
+            targetindices[i] = dummy.targetindex+1;
+            Debug("\nload actor %d, type %d has target %d",i,new->obclass,dummy.targetindex);
+        }
+
+
+        new->areanumber = dummy.areanumber;
+        new->shapenum = new->state->shapenum + new->shapeoffset;
+        new->which = ACTOR;
+        if (new->flags & FL_ABP)
+            MakeActive(new);
+        if (new->obclass != inertobj)
+            MakeLastInArea(new);
+
+        if (!(new->flags & (FL_NEVERMARK|FL_NONMARK)))
+            actorat[new->tilex][new->tiley] = new;
+
+        PreCacheActor(new->obclass,-1);
+        buffer += sizeof(saved_actor_type);
+    }
+
+
+    // find unique links between actors,
+    // searching list AFTER all have been spawned
+
+    for(i=0; i<numactors; i++)
+    {   temp=objlist[i];
+        if (whateverindices[i])
+            temp->whatever = objlist[whateverindices[i]-1];
+        if (targetindices[i])
+            temp->target = objlist[targetindices[i]-1];
+    }
+
+
+    for(temp=FIRSTACTOR; temp; temp=temp->next)
+    {   if (temp->obclass == b_darksnakeobj)
+        {   if (!SNAKEHEAD)
+                SNAKEHEAD = temp;
+            else if (!temp->whatever)
+                SNAKEEND = temp;
+        }
+
+    }
+
+    if (SNAKEHEAD)
+        for(temp=FIRSTACTOR; temp; temp=temp->next)
+        {   if (temp->state == &s_megaexplosions)
+                EXPLOSIONS = temp;
+        }
+
+    //SafeFree(objlist);
+    SafeFree(targetindices);
+    SafeFree(whateverindices);
+
+}
+
+
+
+int RandomSign(void)
+{
+    if (GameRandomNumber("random sign",0) < 128)
+        return -1;
+    return 1;
+
+
+}
+
+
+void AddToFreeList(objtype*ob)
+{   if (!FIRSTFREE)
+        FIRSTFREE = ob;
+    else
+    {   ob->prev = LASTFREE;
+        LASTFREE->next = ob;
+    }
+    LASTFREE = ob;
+
+}
+
+void RemoveFromFreeList(objtype*ob)
+{
+    if (ob == LASTFREE)
+        LASTFREE = ob->prev;
+    else
+        ob->next->prev = ob->prev;
+
+    if (ob == FIRSTFREE)
+        FIRSTFREE = ob->next;
+    else
+        ob->prev->next = ob->next;
+
+    ob->prev = NULL;
+    ob->next = NULL;
+
+}
+
+
+void MakeActive(objtype *ob)
+{   if ((ob == firstactive) || (ob->prevactive) || (ob->nextactive))
+    {
+        SoftError("\ndouble make active try");
+        //AddEndGameCommand ();
+        return;
+    }
+
+    if (!firstactive)
+        firstactive = ob;
+    else
+    {   ob->prevactive = lastactive;
+        lastactive->nextactive = ob;
+    }
+    lastactive = ob;
+
+#if ((DEVELOPMENT == 1))
+#if ((LOADSAVETEST == 1))
+    if (!lastactive)
+        Debug("\nlastactive = NULL !");
+    else
+        Debug("\nlastactive = %8x",lastactive);
+
+#endif
+#endif
+}
+
+
+
+void MakeLastInArea(objtype *ob)
+{
+    if (!ValidAreanumber(ob->areanumber))
+        Error("\n ob type %s at %d,%d has illegal areanumber of %d",
+              debugstr[ob->obclass],ob->tilex,ob->tiley,ob->areanumber);
+
+
+    if ((ob == firstareaactor[ob->areanumber]) || (ob->previnarea) || (ob->nextinarea))
+    {
+        SoftError("\ndouble make last in area try");
+        //AddEndGameCommand ();
+        return;
+    }
+    if (!firstareaactor[ob->areanumber])
+        firstareaactor[ob->areanumber]	= ob;
+    else
+    {   ob->previnarea = lastareaactor[ob->areanumber];
+        lastareaactor[ob->areanumber]->nextinarea = ob;
+    }
+    lastareaactor[ob->areanumber] = ob;
+}
+
+
+
+void RemoveFromArea(objtype*ob)
+{
+    if (!((ob == firstareaactor[ob->areanumber]) || (ob->previnarea) || (ob->nextinarea)))
+    {
+        SoftError("\ndouble remove from area try");
+        //AddEndGameCommand ();
+        return;
+    }
+
+    if (ob == lastareaactor[ob->areanumber])     // remove from master list
+        lastareaactor[ob->areanumber] = ob->previnarea;
+    else
+        ob->nextinarea->previnarea = ob->previnarea;
+
+    if (ob == firstareaactor[ob->areanumber])
+        firstareaactor[ob->areanumber] = ob->nextinarea;
+    else
+        ob->previnarea->nextinarea = ob->nextinarea;
+
+    ob->previnarea = NULL;
+    ob->nextinarea = NULL;
+}
+
+
+void MakeInactive(objtype*ob)
+{
+    if (!ACTIVE(ob))
+//  if (!((ob == firstactive) || (ob->prevactive) || (ob->nextactive)))
+    {
+        SoftError("\n trying to remove inactive object");
+        //AddEndGameCommand ();
+        return;
+    }
+
+    //if (ob->flags & FL_ABP)
+    {
+
+        if (ob == lastactive)     // remove from master list
+            lastactive = ob->prevactive;
+        else
+            ob->nextactive->prevactive = ob->prevactive;
+
+        if (ob == firstactive)
+            firstactive = ob->nextactive;
+        else
+            ob->prevactive->nextactive = ob->nextactive;
+
+
+        ob->prevactive = NULL;
+        ob->nextactive = NULL;
+    }
+
+}
+
+
+
+void A_Steal(objtype*ob)
+{
+    int dx,dy,dz;
+
+    ActorMovement(ob);
+
+    dx = abs(ob->x - PLAYER[0]->x);
+    dy = abs(ob->y - PLAYER[0]->y);
+    dz = abs(ob->z - PLAYER[0]->z);
+
+    if ((dx > TOUCHDIST) || (dy > TOUCHDIST) || (dz > (TOUCHDIST >> 10)))
+    {
+        NewState(ob,&s_blitzchase1);
+        return;
+    }
+
+    if (ob->ticcount)
+        return;
+    //"Gimme That!"
+    SD_PlaySoundRTP(SD_BLITZSTEALSND,ob->x,ob->y);
+    if (PLAYER[0]->flags & FL_GASMASK)
+    {
+        PLAYER[0]->flags &= ~FL_GASMASK;
+        PLAYERSTATE[0].protectiontime = 1;
+        ob->temp3 = stat_gasmask;
+        GM_UpdateBonus (PLAYERSTATE[0].poweruptime, true);
+
+    }
+    else if(PLAYER[0]->flags & FL_BPV)
+    {
+        PLAYER[0]->flags &= ~FL_BPV;
+        PLAYERSTATE[0].protectiontime = 1;
+        ob->temp3 = stat_bulletproof;
+        GM_UpdateBonus (PLAYERSTATE[0].poweruptime, true);
+
+    }
+    else if(PLAYER[0]->flags & FL_AV)
+    {
+        PLAYER[0]->flags &= ~FL_AV;
+        PLAYERSTATE[0].protectiontime = 1;
+        ob->temp3 = stat_asbesto;
+        GM_UpdateBonus (PLAYERSTATE[0].poweruptime, true);
+
+    }
+    else if (PLAYERSTATE[0].missileweapon != -1)
+    {
+        NewState(PLAYER[0],&s_player);
+        PLAYERSTATE[0].attackframe = PLAYERSTATE[0].weaponframe = 0;
+        PLAYERSTATE[0].new_weapon = PLAYERSTATE[0].bulletweapon;
+        ob->temp3 = GetItemForWeapon(PLAYERSTATE[0].missileweapon);
+        ob->temp2 = PLAYERSTATE[0].ammo;
+        //ob->temp1 = oldpolltime;
+        PLAYERSTATE[0].ammo = -1;
+
+        if (PLAYERSTATE[0].weapon == PLAYERSTATE[0].missileweapon)
+            PLAYERSTATE[0].weapondowntics = WEAPONS[PLAYERSTATE[0].weapon].screenheight/GMOVE;
+        PLAYERSTATE[0].missileweapon = -1;
+
+        if ( SHOW_BOTTOM_STATUS_BAR() )
+            DrawBarAmmo (false);
+
+    }
+}
+
+
+void FindAddresses(void)
+{
+    int i;
+    unsigned long tstate,tfunct;
+
+    MINFUNCTION = -1l;
+    MAXFUNCTION = 0x00000000;
+    MINSTATE = -1l;
+    MAXSTATE = 0x00000000;
+
+    for(i=0; i<MAXSTATES; i++)
+    {
+        tstate = (unsigned long)(statetable[i]);
+        if (tstate < MINSTATE)
+            MINSTATE = tstate;
+
+        if (tstate > MAXSTATE)
+            MAXSTATE = tstate;
+        if (statetable[i]!=NULL)
+        {
+            tfunct = (unsigned long)(statetable[i]->think);
+            if (tfunct < MINFUNCTION)
+                MINFUNCTION = tfunct;
+
+            if (tfunct > MAXFUNCTION)
+                MAXFUNCTION = tfunct;
+        }
+    }
+}
+
+void CheckBounds(objtype*ob)
+{
+    unsigned long tstate,tfunct;
+
+    tstate = (unsigned long)(ob->state);
+    tfunct = (unsigned long)(ob->state->think);
+
+    if ((tfunct < MINFUNCTION) || (tfunct > MAXFUNCTION) ||
+            (tstate < MINSTATE) || (tstate > MAXSTATE))
+    {
+        if (tfunct < MINFUNCTION)
+            Error("%s has thinking function less than MINFUNCTION",debugstr[ob->obclass]);
+
+        else if (tfunct > MAXFUNCTION)
+            Error("%s has thinking function greater than MAXFUNCTION",debugstr[ob->obclass]);
+
+        if (tstate < MINSTATE)
+            Error("%s has state less than MINSTATE",debugstr[ob->obclass]);
+
+        else if (tstate > MAXSTATE)
+            Error("%s has state greater than MAXSTATE",debugstr[ob->obclass]);
+
+    }
+
+
+}
+
+/*************************************************************/
+
+
+/*
+=====================
+=
+= DoActor
+=
+=====================
+*/
+
+void DoActor (objtype *ob)
+{
+    void (*think)(objtype *);
+    int door;
+
+
+//  for(i=0;i<tics;i++)
+//	{
+
+#if (BNACRASHPREVENT == 1)//
+    if (ob->state == 0) {
+        return;
+    }
+#endif
+    ApplyGravity(ob);
+    M_CheckDoor(ob);
+    M_CheckBossSounds(ob);
+    if ((ob->obclass >= b_darianobj) &&
+            (ob->obclass < b_darksnakeobj) &&
+            MISCVARS->REDTIME
+       )
+    {
+        MISCVARS->REDTIME --;
+        MISCVARS->redindex = (MISCVARS->REDTIME  & 15);
+    }
+
+    if (ob->obclass == playerobj)
+        ControlPlayerObj(ob);
+
+    think = ob->state->think;
+    if (think)
+    {
+        //CheckBounds(ob);
+        think (ob);
+
+        if (!ob->state)
+        {
+            RemoveObj (ob);
+            return;
+        }
+    }
+
+    if (ob->ticcount)
+        ob->ticcount --;
+
+    else
+    {
+        if (!(ob->state->next))
+        {
+            RemoveObj (ob);
+            return;
+        }
+        else
+            NewState(ob,ob->state->next);
+    }
+
+
+    if (ob->flags&FL_NEVERMARK)
+        return;
+
+    if ((ob->flags&FL_NONMARK) && actorat[ob->tilex][ob->tiley])
+        return;
+
+    actorat[ob->tilex][ob->tiley] = ob;
+}
+
+
+
+
+
+void ApplyGravity(objtype *ob)
+{
+    int oldmomentumz;
+
+    if (((ob->momentumz) || (ob->z != nominalheight)) &&
+            (ob->obclass > playerobj) &&
+            ((ob->obclass <= roboguardobj) || (ob->obclass == collectorobj) ||
+             (ob->obclass == b_heinrichobj)) &&
+            (ob->state->think != T_Stand)
+       )
+    {
+        ob->z += (ob->momentumz>>16);
+        ob->momentumz += GRAVITY;
+        if (ob->z >= nominalheight)
+        {
+            ob->z = nominalheight;
+            oldmomentumz = ob->momentumz;
+            ob->momentumz = 0;
+            if (oldmomentumz > 2*GRAVITY)
+            {
+                if (ob->flags & FL_DYING)
+                    SD_PlaySoundRTP(ACTORTHUDSND,ob->x,ob->y);
+                else
+                {
+                    int oldviolence = gamestate.violence;
+
+                    SD_PlaySoundRTP(ACTORLANDSND,ob->x,ob->y);
+                    gamestate.violence = vl_low;
+                    BeginEnemyHurt(ob);
+                    gamestate.violence = oldviolence;
+                }
+            }
+            if (ob->flags&FL_FALLINGOBJECT)
+            {
+                RemoveObj(ob);
+                return;
+            }
+        }
+    }
+}
+
+
+
+/*
+===================
+=
+= NewState
+=
+= Changes ob to a new state, setting ticcount to the max for that state
+=
+===================
+*/
+
+void NewState (objtype *ob, statetype *newstate)
+{
+    if (DoPanicMapping() &&
+            ((newstate == &s_explosion1) ||
+             (newstate == &s_grexplosion1) ||
+             (newstate == &s_staticexplosion1)
+            )
+       )
+        ob->state = &s_altexplosion1;
+    else {
+#if (BNACRASHPREVENT == 1)//crashed here when oscuro and larves were all killed
+        if (ob == 0) {
+            return;
+        }
+#endif
+        ob->state = newstate;
+    }
+    SetVisiblePosition(ob,ob->x,ob->y);
+#if (BNACRASHPREVENT == 1)
+    if (ob->state == 0) {
+        return;
+    }
+#endif
+
+    ob->ticcount = (ob->state->tictime>>1);
+    ob->shapenum = ob->state->shapenum + ob->shapeoffset;
+
+}
+
+
+/*
+=========================
+=
+= InitActorList
+=
+= Call to clear out the actor object lists returning them all to the free
+= list.  Allocates a special spot for the player.
+=
+=========================
+*/
+
+
+
+void InitActorList (void)
+{
+    //====== NETWORK STUFF =======================================
+    memset(&DEADPLAYER[0],0,sizeof(DEADPLAYER));
+    NUMDEAD = 0;
+
+
+
+    //======= NULLIFY GLOBAL POINTERS ============================
+
+    LASTACTOR=FIRSTACTOR=NULL;
+    FIRSTFREE = LASTFREE = NULL;
+    firstactive = lastactive = NULL;
+    memset(firstareaactor,0,sizeof(firstareaactor));
+    memset(lastareaactor,0,sizeof(lastareaactor));
+    NUMSPAWNLOCATIONS = 0;
+
+
+    PARTICLE_GENERATOR = NULL;
+    EXPLOSIONS = NULL;
+    SNAKEEND=SNAKEHEAD=NULL;
+    SCREENEYE = NULL;
+    PLAYER0MISSILE = NULL;
+
+    //============================================================
+
+    objcount = 0;
+    memset(MISCVARS,0,sizeof(misc_stuff));
+    MISCVARS->gibgravity = -1;
+    MISCVARS->gibspeed = NORMALGIBSPEED;
+
+    memset(&RANDOMACTORTYPE[0],0,sizeof(RANDOMACTORTYPE));
+    FindAddresses();
+    MissileSound = true;
+    Masterdisk = false;
+
+}
+
+//===========================================================================
+
+/*
+=========================
+=
+= GetNewActor
+=
+= Sets the global variable new to point to a free spot in objlist.
+= The free spot is inserted at the end of the liked list
+=
+= When the object list is full, the caller can either have it bomb out ot
+= return a dummy object pointer that will never get used
+=
+=========================
+*/
+
+void GetNewActor (void)
+{
+    objtype *temp;
+
+    if (!FIRSTFREE)
+    {
+        temp = (objtype*)Z_LevelMalloc(sizeof(objtype),PU_LEVELSTRUCT,NULL);
+        //SoftError("\nMalloc-ing actor");
+        //if (insetupgame)
+        //  SoftError("in setup");
+    }
+
+    else
+    {
+        temp = LASTFREE;
+        //SoftError("\nfree actor available");
+        RemoveFromFreeList(LASTFREE);
+    }
+
+    if (temp)
+    {
+        new = temp;
+        memset(new,0,sizeof(*new));
+
+        if (FIRSTACTOR)
+        {
+            new->prev = LASTACTOR;
+            LASTACTOR->next = new;
+        }
+        else
+            FIRSTACTOR = new;
+        LASTACTOR = new;
+
+        new->door_to_open = -1;
+        new->soundhandle = -1;
+        objcount ++;
+    }
+    else
+        Error("Z_LevelMalloc failed in GetNewActor");
+}
+
+
+
+
+//===========================================================================
+
+
+
+
+/*
+=========================
+=
+= RemoveObj
+=
+= Add the given object back into the free list, and unlink it from it's
+= neighbors
+=
+=========================
+*/
+
+
+void RemoveObj (objtype *gone)
+{
+    if (gone == PLAYER[0])
+        Error ("RemoveObj: Tried to remove the player!");
+
+    gone->state=NULL;
+
+    MakeInactive(gone);
+
+    if (gone->obclass!=inertobj) {
+        if (ValidAreanumber(gone->areanumber))
+            RemoveFromArea(gone);
+        else
+            Error("tried to remove an instance of %s with invalid areanumber %d",debugstr[gone->obclass],gone->areanumber);
+    }
+
+    if (gone == LASTACTOR)
+        LASTACTOR = gone->prev;
+    else
+        gone->next->prev = gone->prev;
+
+    if (gone == FIRSTACTOR)
+        FIRSTACTOR = gone->next;
+    else
+        gone->prev->next = gone->next;
+
+    if (gone == EXPLOSIONS)
+        EXPLOSIONS = NULL;
+    gone->next = NULL;
+    gone->prev = NULL;
+//	SoftError("\nremoving instance of %s",debugstr[gone->obclass]);
+    if (actorat[gone->tilex][gone->tiley] == (void*)gone)
+        actorat[gone->tilex][gone->tiley] = NULL;
+
+    gone->flags |= FL_NEVERMARK;
+
+    if (gone->flags & FL_TARGET)
+        UnTargetActor(gone);
+
+    //Add_To_Delete_Array(gone);
+    //Z_Free(gone);
+    AddToFreeList(gone);
+
+    objcount--;
+}
+
+
+//============== World Physics Model Functions =========================
+
+
+void ParseMomentum(objtype *ob,int angle)
+{
+    ob->momentumx += FixedMul(ob->speed,costable[angle]);
+    ob->momentumy -= FixedMul(ob->speed,sintable[angle]);
+}
+
+void Set_3D_Momenta(objtype *ob, int speed, int theta, int phi)
+{
+    int _2Ddiag;
+
+    ob->momentumz = -FixedMul(speed,sintable[phi]);
+    _2Ddiag = FixedMul(speed,costable[phi]);
+    ob->momentumx = FixedMul(_2Ddiag,costable[theta]);
+    ob->momentumy = -FixedMul(_2Ddiag,sintable[theta]);
+
+
+}
+
+
+int AngleBetween(objtype *source,objtype*target)
+{
+    int dx,dy;
+
+    dx = target->x - source->x;
+    dy = source->y - target->y;
+    return (atan2_appx(dx,dy));
+}
+
+
+void GetMomenta(objtype *target, objtype *source, int *newmomx,
+                int *newmomy, int *newmomz, int magnitude
+               )
+{
+    int angle,dx,dy,dz,yzangle,xydist,_2Ddiag;
+
+    dx = target->x - source->x;
+    dy = source->y - target->y;
+    dz = source->z - target->z;
+    xydist = FindDistance(dx,dy);
+    angle = atan2_appx(dx,dy);
+    yzangle = atan2_appx(xydist,(dz<<10));
+    _2Ddiag = FixedMul(magnitude,costable[yzangle]);
+
+    *newmomz = -FixedMul(magnitude,sintable[yzangle]);
+    *newmomx = FixedMul(_2Ddiag,costable[angle]);
+    *newmomy = -FixedMul(_2Ddiag,sintable[angle]);
+}
+
+//=======================================================================
+
+
+
+
+
+void SpawnNewObj (unsigned tilex, unsigned tiley, statetype *state, classtype which)
+{
+    int newarea;
+
+    GetNewActor ();
+    new->obclass = which;
+    SetTilePosition(new,tilex,tiley);
+    SetVisiblePosition(new,new->x,new->y);
+    new->dir = nodir;
+    new->which = ACTOR;
+    if (FirstExplosionState(state))
+        new->flags |= (FL_NEVERMARK|FL_NOFRICTION);
+
+    if ((which != inertobj) && (which != diskobj))
+        actorat[tilex][tiley] = new;
+
+    newarea = AREANUMBER(tilex,tiley);
+    if ((which <= springobj) && (which != inertobj))
+    {
+        if (ValidAreanumber(newarea))
+            new->areanumber = newarea;
+        else
+            Error("illegal initial areanumber of %d for actor type %s"
+                  "trying to spawn at %d, %d",newarea,debugstr[which],tilex,tiley);
+    }
+    else
+        new->areanumber = newarea;
+
+    if ((which != inertobj) && (!Masterdisk))
+        MakeLastInArea(new);
+    NewState(new,state);
+    new->z = nominalheight;
+    if (which==springobj)
+        new->z+=2;
+
+}
+
+
+//====================================================================
+
+void ConsiderAlternateActor(objtype *ob,classtype which)
+{
+    if (((which >= lowguardobj) && (which <= blitzguardobj)) ||
+            (which == dfiremonkobj))
+    {   if (GameRandomNumber("SpawnStand",which) < 128)
+        {   switch(which)
+            {
+            case lowguardobj:
+                ob->shapeoffset =  W_GetNumForName("MARSHOO1") -
+                                   W_GetNumForName("LWGSHOO1");
+                break;
+            case highguardobj:
+                ob->shapeoffset =  W_GetNumForName("HIGSHOO1") -
+                                   W_GetNumForName("HG2SHOO1");
+                break;
+            case overpatrolobj:
+                ob->shapeoffset =  W_GetNumForName("PATSHOO1") -
+                                   W_GetNumForName("OBPSHOO1");
+                break;
+            case strikeguardobj:
+                ob->shapeoffset =  W_GetNumForName("XYGSHOO1") -
+                                   W_GetNumForName("ANGSHOO1");
+                break;
+            /*case blitzguardobj:
+            altstartlabel = "WIGSHOO1";
+            new->shapeoffset = 80;
+            break;*/
+            case dfiremonkobj:
+                ob->shapeoffset =  W_GetNumForName("MRKKSH1") -
+                                   W_GetNumForName("ALLKSH1");
+                break;
+            default:
+                ;
+            }
+        }
+
+    }
+
+    //if (new->shapeoffset)
+    //  {if (W_CheckNumForName(altstartlabel) == -1)
+    //     new->shapeoffset = 0;
+    //  }
+
+}
+
+
+
+
+
+/*
+===================
+=
+= StandardEnemyInit
+=
+===================
+*/
+
+void StandardEnemyInit(objtype *ob,int dir)
+{
+    int zoffset;
+
+    if ((ob->obclass == deathmonkobj) || (ob->obclass == dfiremonkobj))
+        ob->temp2 = DRAINTIME;
+
+    else if ((ob->obclass == highguardobj) || (ob->obclass == triadenforcerobj))
+        ob->flags |= FL_HASAUTO;
+
+    ob->hitpoints = starthitpoints[gamestate.difficulty][ob->obclass];
+    ob->dir = dir*2;
+    ob->flags |= (FL_SHOOTABLE|FL_BLOCK);
+    ob->speed = ENEMYRUNSPEED;
+    ob->dirchoosetime = 0;
+    ob->door_to_open = -1;
+
+    zoffset = MAPSPOT(ob->tilex,ob->tiley,2);
+    if ((zoffset&0xff00)==0xb000)
+        Set_NewZ_to_MapValue(&(ob->z),zoffset,"standard enemy",ob->tilex,ob->tiley);
+    else
+        ob->z = PlatformHeight(ob->tilex,ob->tiley);
+
+}
+
+
+//LT added
+//if under ext actor options BLITZ RANDOM WEP is enabled, this will decide what missile weapon a blitzguard will get
+void OutfitBlitzguardWith(objtype *ob)
+{
+    int number = GameRandomNumber("outfitting blitzguard",0);
+
+    if (number < 100)
+    {
+        ob->temp3 = stat_bazooka;
+        ob->temp2 = 3;
+    }
+    else if (number > 100 && number <= 150)
+    {
+        ob->temp3 = stat_heatseeker;
+        ob->temp2 = 3;
+    }
+    else if (number > 150 && number <= 200)
+    {
+        ob->temp3 = stat_drunkmissile;
+        ob->temp2 = 3;
+    }
+    else if (number > 200 && number <= 225)
+    {
+        ob->temp3 = stat_firewall;
+        ob->temp2 = 3;
+    }
+    else if (number > 225 && number <= 250)
+    {
+        ob->temp3 = stat_firebomb;
+        ob->temp2 = 3;
+    }
+#if (SHAREWARE == 0)
+    else if (number > 250)
+    {
+        //dark staff
+        ob->temp3 = stat_kes;
+        ob->temp2 = 3;
+    }
+    //TODO: Figure out a way to allow biltzguards to attack with excalibat w/o crashing the game
+
+#endif
+    else
+    {
+        ob->temp3 = stat_bazooka;
+        ob->temp2 = 3;
+    }
+}
+
+extern boolean allowBlitzMoreMissileWeps;
+
+//This decides if a Blitzguard (green dude) gets a rocket launcher
+void ConsiderOutfittingBlitzguard(objtype *ob)
+{
+    //WILEYBLITZCHANCE is defined to be 20
+    if ((GameRandomNumber("wiley blitzguard",0) < WILEYBLITZCHANCE) &&
+            (gamestate.difficulty >= gd_medium)
+       )
+    {
+        if (allowBlitzMoreMissileWeps)
+        {
+            OutfitBlitzguardWith(ob);
+        }
+        else {
+            ob->temp3 = stat_bazooka;
+            ob->temp2 = 3;
+        }
+    }
+}
+
+
+/*
+===============
+=
+= SpawnStand
+=
+===============
+*/
+
+
+void SpawnStand (classtype which, int tilex, int tiley, int dir, int ambush)
+{   statetype *temp;
+
+#if (SHAREWARE == 1)
+    switch(which)
+    {
+    case overpatrolobj:
+    case wallopobj:
+    case deathmonkobj:
+    case dfiremonkobj:
+    case b_darianobj:
+    case b_heinrichobj:
+    case b_darkmonkobj:
+        Error("\n%s actor at %d,%d not allowed in shareware !",debugstr[which],tilex,tiley);
+        break;
+    default:
+        ;
+    }
+
+
+
+#endif
+
+    if ((which == lowguardobj) && (GameRandomNumber("SpawnStand",which) < 128))
+        which = blitzguardobj;
+
+
+    if ((temp = UPDATE_STATES[STAND][which-lowguardobj]) != NULL)
+    {
+        SpawnNewObj(tilex,tiley,temp,which);
+        if (!loadedgame)
+            gamestate.killtotal++;
+
+
+        if (ambush)
+            new->flags |= FL_AMBUSH;
+
+
+#if 0
+        if (gamestate.Product == ROTT_SUPERCD)
+            ConsiderAlternateActor(new,which);
+#endif
+
+        StandardEnemyInit(new,dir);
+
+        if (which == b_darkmonkobj)
+        {
+            new->flags |= (FL_NOFRICTION);//|FL_INVULNERABLE);
+            new->speed = ENEMYRUNSPEED*2;
+        }
+
+        if (which == blitzguardobj)
+            ConsiderOutfittingBlitzguard(new);
+
+
+        if ((new->obclass >= lowguardobj) && (new->obclass <= dfiremonkobj))
+            RANDOMACTORTYPE[new->obclass]++;
+
+        if (MAPSPOT(tilex,tiley,2) == 0xdead)
+        {
+            new->flags |= FL_KEYACTOR;
+            MISCVARS->KEYACTORSLEFT++;
+        }
+
+        PreCacheActor(which,0);
+    }
+//else
+    //Error("NULL initialization error");
+}
+
+
+
+
+
+/*
+===============
+=
+= SpawnPatrol
+=
+===============
+*/
+
+void SpawnPatrol (classtype which, int tilex, int tiley, int dir)
+{   statetype *temp;
+    int path=PATH;
+#if 0
+    if (gamestate.Product == ROTT_SUPERCD)
+        char *altstartlabel;
+#endif
+
+
+
+#if (SHAREWARE==1)
+    switch(which)
+    {
+    case overpatrolobj:
+    case wallopobj:
+    case deathmonkobj:
+    case dfiremonkobj:
+    case b_darianobj:
+    case b_heinrichobj:
+    case b_darkmonkobj:
+        Error("\n%s actor at %d,%d not allowed in shareware !",debugstr[which],tilex,tiley);
+        break;
+    default:
+        ;
+    }
+
+#endif
+
+    if ((which == lowguardobj) && (GameRandomNumber("SpawnStand",which) < 128))
+        which = blitzguardobj;
+
+
+
+
+    if ((temp= UPDATE_STATES[path][(int)(which-lowguardobj)]) != NULL)
+    {
+        SpawnNewObj(tilex,tiley,temp,which);
+
+        if (!loadedgame)
+            gamestate.killtotal++;
+
+
+#if 0
+        if (gamestate.Product == ROTT_SUPERCD)
+            ConsiderAlternateActor(new,which);
+#endif
+
+        StandardEnemyInit(new,dir);
+
+        if ((which == wallopobj) || (which == roboguardobj))
+        {   new->flags |= FL_NOFRICTION;
+            //new->flags &= ~FL_SHOOTABLE;
+            new->dir <<= 1;
+            ParseMomentum(new,dirangle16[new->dir]);
+        }
+        else
+            ParseMomentum(new,dirangle8[new->dir]);
+
+
+        if (which == blitzguardobj)
+            ConsiderOutfittingBlitzguard(new);
+
+
+        if (MAPSPOT(tilex,tiley,2) == 0xdead)
+        {   new->flags |= FL_KEYACTOR;
+            MISCVARS->KEYACTORSLEFT++;
+        }
+
+        PreCacheActor(which,0);
+    }
+
+}
+
+
+
+
+//==========================================================================
+
+
+
+void SpawnDisk(int tilex, int tiley, int type, boolean master)
+{   int zoffset;
+
+
+
+    if (master == true)
+    {
+        Masterdisk = true;
+        SpawnNewObj(tilex,tiley,&s_diskmaster,diskobj);
+        Masterdisk = false;
+        new->flags |= FL_MASTER;
+        new->momentumz = -(DISKMOMZ << 16);
+        new->flags |= FL_SYNCED;
+        new->flags |= FL_NEVERMARK;
+        new->temp1 = 1;
+        //RemoveFromArea(new);
+
+    }
+
+    else
+    {
+        if (!type)
+        {
+            SpawnNewObj(tilex,tiley,&s_elevdisk,diskobj);
+            new->momentumz = -(DISKMOMZ << 16);
+            //new->flags |= FL_SYNCED;
+            zoffset = MAPSPOT(tilex,tiley,2);
+            if ((zoffset&0xff00)==0xb000)
+                Set_NewZ_to_MapValue((fixed*)(&(new->temp2)),zoffset,"elev disk",tilex,tiley);
+            else
+                new->temp2 = 32;
+            new->temp1 = 1;
+        }
+        else
+        {
+            SpawnNewObj(tilex,tiley,&s_pathdisk,diskobj);
+            zoffset = MAPSPOT(tilex,tiley,2);
+            if ((zoffset&0xff00)==0xb000)
+                Set_NewZ_to_MapValue((fixed*)(&(new->z)),zoffset,"path disk",tilex,tiley);
+
+            new->dir = (type-1) << 1;
+            new->speed = 0x1000;
+
+            //ParseMomentum(new,dirangle8[new->dir]);
+        }
+        actorat[tilex][tiley] = NULL;
+        new->flags |= FL_BLOCK;
+        new->flags |= (FL_NOFRICTION|FL_ACTIVE|FL_NEVERMARK);
+    }
+}
+
+
+
+
+objtype* DiskAt(int tilex,int tiley)
+{   int area;
+    objtype *temp;
+    statobj_t *tstat;
+
+    area = AREANUMBER(tilex,tiley);
+    for(temp = firstareaactor[area]; temp; temp = temp->nextinarea)
+    {   if ((temp->tilex != tilex) || (temp->tiley != tiley) ||
+                (temp->obclass != diskobj))
+            continue;
+        return temp;
+
+    }
+
+    for(tstat = firstactivestat; tstat; tstat = tstat->nextactive)
+    {
+        if ((tstat->tilex != tilex) || (tstat->tiley != tiley) ||
+                (tstat->itemnumber != stat_disk))
+            continue;
+        return (objtype*)tstat;
+    }
+
+
+    return NULL;
+
+}
+
+
+void SetElevatorDiskVariables(objtype *ob,int newz, int newmomentumz,
+                              int newtemp1,int newtemp3,int newdirchoose)
+{
+    ob->z = newz;
+    ob->momentumz = newmomentumz;
+    ob->temp1 = newtemp1;
+    ob->temp3 = newtemp3;
+    ob->dirchoosetime = newdirchoose;
+}
+
+
+void T_ElevDisk(objtype*ob)
+{
+    objtype *temp = (objtype*)(actorat[ob->tilex][ob->tiley]);
+    objtype *master;
+
+    if (ob->flags & FL_MASTER)
+        goto masterlabel;
+
+    master = (objtype*)(ob->target);
+    if (!master)
+        Error("disk without master !");
+
+
+    //SoftError("\n ob->z:%d %s, master z:%d",ob->z,
+    //        (ob->flags & FL_SYNCED)?("SYNCED"):("UNSYNCED"),master->z);
+
+
+    if (M_ISACTOR(temp) && (temp != ob) && (!(temp->flags & FL_DYING)))
+    {
+        int dz = abs(ob->z - temp->z),
+            dx = abs(ob->x - temp->x),
+            dy = abs(ob->y - temp->y);
+
+        if ((dx < 0x7000) && (dy < 0x7000) && (dz < 68) && (temp->z > ob->z))
+        {
+            ob->flags &= ~FL_SYNCED;
+            return;
+        }
+    }
+
+    if (master && (!(ob->flags & FL_SYNCED)))
+    {
+        int dz;
+
+        dz = abs(master->z - ob->z);
+        if ((dz > 0) && (dz < 8))
+        {
+            SetElevatorDiskVariables(ob,master->z,master->momentumz,master->temp1,
+                                     master->temp3,master->dirchoosetime);
+            ob->flags |= FL_SYNCED;
+            //return;
+        }
+        return;
+    }
+
+
+masterlabel:
+
+    if (ob->dirchoosetime)
+    {
+        ob->dirchoosetime --;
+        return;
+    }
+
+
+    if (ob->temp1) // moving
+    {
+        ob->z += (ob->momentumz >> 16);
+        if (ob->momentumz > 0) // down
+        {
+            if (ob->z >= nominalheight + 40 + DISKMOMZ)
+                SetElevatorDiskVariables(ob,ob->z - (ob->momentumz>>16),0,0,0,35);
+        }
+        else
+        {
+            if (ob->z < ob->temp2) // temp2 has max height
+                SetElevatorDiskVariables(ob,ob->z - (ob->momentumz>>16),0,0,1,35);
+        }
+    }
+    else
+    {
+        if (ob->temp3)
+            ob->momentumz = (DISKMOMZ << 16);
+        else
+            ob->momentumz = -(DISKMOMZ << 16);
+        ob->temp1 = 1;
+    }
+}
+
+
+
+
+void SpawnInertActor(int newx,int newy, int newz)
+{
+    GetNewActor ();
+    MakeActive(new);
+
+    new->obclass = inertobj;
+    new->which = ACTOR;
+    SetFinePosition(new,newx,newy);
+    SetVisiblePosition(new,new->x,new->y);
+    new->z = newz;
+    new->dir = 0;
+    new->speed = 0;
+    new->flags = (FL_NEVERMARK|FL_ABP);
+
+}
+
+
+
+
+#if (SHAREWARE == 0)
+void SpawnGroundExplosion(int x, int y, int z)
+{
+    SpawnInertActor(x,y,z);
+    NewState(new,&s_grexplosion1);
+    new->temp2 = GameRandomNumber("SpawnGroundExplosion",0)>>2;
+
+}
+#endif
+
+void SpawnSlowParticles(int which, int numgibs, int x,int y,int z)
+{   objtype *prevlast,*temp;
+    int tilex,tiley;
+
+    tilex = x>>16;
+    tiley = y>>16;
+
+    SpawnNewObj(tilex,tiley,&s_gibs1,inertobj);
+    SetFinePosition(new,x,y);
+    SetVisiblePosition(new,x,y);
+    prevlast = new;
+    prevlast->flags |= FL_ABP;
+    MakeActive(prevlast);
+    SpawnParticles(new,which,numgibs);
+
+    for(temp = prevlast->next; temp; temp=temp->next)
+    {   temp->z = z;
+        temp->momentumx >>= 1;
+        temp->momentumy >>= 1;
+        temp->momentumz >>= 1;
+    }
+    RemoveObj(prevlast);
+
+}
+
+
+void ResolveDoorSpace(int tilex,int tiley)
+{
+    statobj_t* tstat,*temp;
+
+    for(tstat = firstactivestat; tstat;)
+    {
+        temp = tstat->nextactive;
+
+        if (tstat->flags & FL_DEADBODY)
+        {
+            if ((tstat->tilex == tilex) && (tstat->tiley == tiley))
+            {
+                if ((tstat->flags & FL_DEADBODY) && (tstat->linked_to != -1))
+                    DEADPLAYER[tstat->linked_to] = NULL;
+                RemoveStatic(tstat);
+                if (tstat->flags & FL_DEADBODY)
+                    SpawnSlowParticles(GUTS,8,tstat->x,tstat->y,tstat->z);
+                else
+                    SpawnSlowParticles(gt_sparks,8,tstat->x,tstat->y,tstat->z);
+                SD_PlaySoundRTP(SD_ACTORSQUISHSND,tstat->x,tstat->y);
+            }
+        }
+        tstat = temp;
+    }
+}
+
+
+void SpawnSpear(int tilex,int tiley,int up)
+{
+    int count,i;
+    statetype *tstate;
+
+
+    if (BATTLEMODE && (!gamestate.BattleOptions.SpawnDangers))
+        return;
+
+    if (!up)
+    {
+#if (SHAREWARE == 1)
+        Error("\ndownspear at %d,%d in shareware!",tilex,tiley);
+#else
+        SpawnNewObj(tilex,tiley,&s_speardown1,spearobj);
+        new->z = 0;
+#endif
+    }
+    else
+
+        SpawnNewObj(tilex,tiley,&s_spearup1,spearobj);
+
+    count = (int)(GameRandomNumber("Spawn Spear",0) % 16);
+    for(i=0,tstate = new->state; i<count; i++,tstate=tstate->next);
+    NewState(new,tstate);
+
+    PreCacheActor(spearobj,up);
+    new->flags |= (FL_ABP);//|FL_INVULNERABLE);
+    MakeActive(new);
+}
+
+
+
+void SpawnSpring(int tilex,int tiley)
+{
+    int iconvalue;
+
+    iconvalue = MAPSPOT(tilex,tiley,2);
+    if (iconvalue == 3)
+    {
+        SpawnNewObj(tilex,tiley,&s_autospring1,springobj);
+        new->ticcount = (GameRandomNumber("Spawn Spring",0) % new->ticcount)+1;
+        new->temp1 = iconvalue;
+    }
+    else
+    {
+        SpawnNewObj(tilex,tiley,&s_spring1,springobj);
+        if (iconvalue == 2)
+            new->temp1 = iconvalue;
+    }
+
+    PreCacheActor(springobj,0);
+    new->flags &= ~(FL_SHOOTABLE|FL_BLOCK);
+}
+
+
+
+
+void T_Spring(objtype*ob)
+{
+    objtype *temp;
+    int op,dx,dy,dz;
+
+
+    if ((ob->state->condition & SF_DOWN) && (ob->temp1))
+    {
+        if (ob->ticcount)
+            return;
+        ob->shapenum++;
+        TurnActorIntoSprite(ob);
+        return;
+    }
+
+    for(temp=firstareaactor[ob->areanumber]; temp; temp=temp->nextinarea)
+    {
+        if (temp == ob)
+            continue;
+
+        if (temp->obclass >= roboguardobj)
+            continue;
+
+        dx = abs(ob->x-temp->x);
+        dy = abs(ob->y-temp->y);
+        dz = abs(ob->z-temp->z);
+        if ((dx > ACTORSIZE+0x2800) || (dy > ACTORSIZE+0x2800) || (dz > 40))
+            continue;
+        if (!temp->momentumz)
+        {
+            op = FixedMul(GRAVITY,(temp->z-5)<<16) << 1;
+            temp->momentumz = -FixedSqrtHP(op);
+            SD_PlaySoundRTP(SD_SPRINGBOARDSND,ob->x,ob->y);
+        }
+    }
+}
+
+
+
+void T_Count(objtype*ob)
+{
+    int index;
+    wall_t* tswitch;
+    touchplatetype *temp;
+    objtype* tempactor;
+
+    if (ob->dirchoosetime)
+    {
+        ob->dirchoosetime --;
+        if (ob->dirchoosetime>980)
+            MISCVARS->gasindex=((1050-ob->dirchoosetime)<<4)/70;
+        else if (ob->dirchoosetime<35)
+            MISCVARS->gasindex=(ob->dirchoosetime<<4)/35;
+        if (ob->temp3)
+        {
+            ob->temp3 --;
+            if (ob->temp3 & 1)
+                SD_PlaySoundRTP(SD_GASHISSSND,ob->x,ob->y);
+        }
+        else
+        {
+            ob->temp3 = 105;
+            for(tempactor=firstareaactor[ob->areanumber]; tempactor; tempactor=tempactor->nextinarea)
+            {
+                if (tempactor == ob)
+                    continue;
+                if (!(tempactor->flags & FL_SHOOTABLE))
+                    continue;
+                if (tempactor->obclass != playerobj)
+                {
+                    if ((tempactor->obclass >= lowguardobj) &&
+                            (tempactor->obclass <= dfiremonkobj))
+                    {
+                        int oldviolence = gamestate.violence;
+
+                        gamestate.violence = vl_low;
+                        DamageThing(tempactor,EnvironmentDamage(ob));
+                        Collision(tempactor,ob,-(tempactor->momentumx),-(tempactor->momentumy));
+                        gamestate.violence = oldviolence;
+
+                    }
+                }
+                else if (!(tempactor->flags & FL_GASMASK))
+                {
+                    DamageThing(tempactor,EnvironmentDamage(ob));
+                    Collision(tempactor,ob,0,0);
+                    M_CheckPlayerKilled(tempactor);
+                }
+            }
+        }
+    }
+
+    else
+    {
+        int i;
+        playertype *pstate;
+
+        for(i=0; i<numplayers; i++)
+        {
+            M_LINKSTATE(PLAYER[i],pstate);
+            PLAYER[i]->flags &= ~FL_GASMASK;
+            pstate->protectiontime = 1;
+        }
+
+        NewState(ob,&s_gas1);
+        SD_PlaySoundRTP(SD_GASENDSND,ob->x,ob->y);
+        ob->flags &= ~FL_ACTIVE;
+        MISCVARS->gasindex=0;
+        MU_StartSong(song_level);
+        MU_RestoreSongPosition();
+        MISCVARS->GASON = 0;
+
+        index = touchindices[ob->temp1][ob->temp2]-1;
+        TRIGGER[index] = 0;
+        for(temp = touchplate[index]; temp; temp = temp->nextaction)
+            if (temp->action == EnableObject)
+            {
+                tempactor = (objtype*)(temp->whichobj);
+                tempactor->flags &= ~FL_ACTIVE;
+            }
+
+        tswitch = (wall_t*)actorat[ob->temp1][ob->temp2];
+        /*
+        if (tswitch && (tswitch->which != ACTOR))
+           {
+           tilemap[ob->temp1][ob->temp2]--;
+           tswitch->flags &= ~FL_ON;
+           }
+        */
+
+    }
+}
+
+
+
+
+void SpawnBlade(int tilex, int tiley,int dir,int upordown,int moving)
+{   int count,i;
+    statetype *nstate;
+
+#if (SHAREWARE == 1)
+    if (!upordown)
+        Error("\ndown spinblade at %d,%d not allowed in shareware !",tilex,tiley);
+    if (moving)
+        Error("\nupdown spinblade at %d,%d not allowed in shareware !",tilex,tiley);
+
+#endif
+
+
+    if (BATTLEMODE && (!gamestate.BattleOptions.SpawnDangers))
+        return;
+
+    if (moving)
+
+    {
+#if (SHAREWARE == 0)
+
+        if (upordown)
+            SpawnNewObj(tilex,tiley,&s_spinupblade1,bladeobj);
+        else
+        {   SpawnNewObj(tilex,tiley,&s_spindownblade1,bladeobj);
+            new->z = 0;
+        }
+#endif
+    }
+    else
+    {   if (upordown)
+            SpawnNewObj(tilex,tiley,&s_upblade1,bladeobj);
+
+#if (SHAREWARE == 0)
+
+        else
+        {   SpawnNewObj(tilex,tiley,&s_downblade1,bladeobj);
+            new->z = 0;
+        }
+#endif
+    }
+
+
+    count = (int)(GameRandomNumber("SpawnBlade",0) % 16);
+    for(nstate=new->state,i=0; i<count; nstate = nstate->next,i++);
+    NewState(new,nstate);
+
+    new->flags |= (FL_BLOCK);
+    new->flags &= ~FL_SHOOTABLE;
+    new->dir = dir;
+    if (dir != nodir)
+    {   new->flags |= FL_NOFRICTION;
+        new->speed = ENEMYRUNSPEED;
+
+    }
+    if (!MAPSPOT(tilex,tiley,2))
+    {   new->flags |= FL_ACTIVE;
+        ParseMomentum(new,dirangle8[new->dir]);
+    }
+    PreCacheActor(bladeobj,(moving<<1)+upordown);
+}
+
+
+void SpawnCrushingColumn(int tilex, int tiley, int upordown)
+{   int i,count;
+    statetype * nstate;
+
+
+#if (SHAREWARE == 1)
+    if (!upordown)
+        Error("\ncrush-up column at %d,%d not allowed in shareware!",tilex,tiley);
+#endif
+
+
+    if (BATTLEMODE && (!gamestate.BattleOptions.SpawnDangers))
+        return;
+#if (SHAREWARE == 0)
+    if (!upordown)
+        SpawnNewObj(tilex,tiley,&s_columnupup1,crushcolobj);
+    else
+#endif
+    {   SpawnNewObj(tilex,tiley,&s_columndowndown1,crushcolobj);
+        new->z = 0;
+    }
+
+    count = (int)(GameRandomNumber("SpawnCrushingColumn",0) % 8);
+    for(nstate=new->state,i=0; i<count; nstate = nstate->next,i++)
+    {   if ((!upordown) && (nstate->condition & SF_UP))
+            new->temp1 += (((nstate->tictime>>1) + 1)<<2);
+
+    }
+    NewState(new,nstate);
+    new->flags |= (FL_BLOCK);
+
+    new->flags &= ~FL_SHOOTABLE;
+    PreCacheActor(crushcolobj,upordown);
+}
+
+
+
+void SpawnFirejet(int tilex, int tiley, int dir, int upordown)
+{
+    int statecount,i;
+    statetype *tstate;
+
+
+    statecount = (int)(GameRandomNumber("SpawnFirejet",0) % 22);
+
+    if (upordown)
+    {
+        for(i=0,tstate=&s_firejetup1; i<statecount; i++,tstate=tstate->next);
+        SpawnNewObj(tilex,tiley,tstate,firejetobj);
+    }
+    else
+    {
+#if (SHAREWARE == 1)
+        Error("\ndown firejet at %d,%d not allowed in shareware",tilex,tiley);
+#else
+        for(i=0,tstate=&s_firejetdown1; i<statecount; i++,tstate=tstate->next);
+        SpawnNewObj(tilex,tiley,tstate,firejetobj);
+        new->z = 0;
+#endif
+    }
+
+    PreCacheActor(firejetobj,upordown);
+
+    new->flags &= ~FL_SHOOTABLE;
+
+    if (dir != nodir)
+    {
+        new->dir = dir*2;
+        new->flags |= FL_NOFRICTION;
+        new->speed = ENEMYRUNSPEED;
+        ParseMomentum(new,dirangle8[new->dir]);
+    }
+    else
+        new->dir = dir;
+}
+
+
+void SpawnFirebomb(objtype*ob,int damage,int which)
+{
+    int i,low,high,doorat;
+    wall_t *tempwall;
+    doorobj_t*tempdoor;
+
+    if (which == 0)
+    {
+        low = (ob->dir>>1);
+        high = low;
+    }
+    else
+    {
+        low = 0;
+        high = which-1;
+
+        if ((FindDistance((ob->x-player->x), (ob->y-player->y))<0x120000) &&
+                (player->z==nominalheight)
+           )
+            SHAKETICS = 35;
+    }
+
+    for (i=low; i<=high; i++)
+    {
+        MissileSound = false;
+        /*
+        if (((which == 0) && ((low == 5) || (low == 6))) ||
+            ((which == 6) && ((i==4) || (i==5)))
+           )
+           {
+
+           if (((which == 0) && (low == 5)) ||
+               ((which == 6) && (i == 4))
+              )
+              {
+              newz = ob->z + 64;
+              if (newz > maxheight)
+                 continue;
+              SpawnMissile(ob,p_firebombobj,0,0,&s_grexplosion1,0);
+              new->z = newz;
+              new->dir = 10;
+
+
+              }
+           else
+              {
+              newz = ob->z - 64;
+              if ((sky == 0) && (newz < 0))
+                 continue;
+              SpawnMissile(ob,p_firebombobj,0,0,&s_grexplosion1,0);
+              new->z = newz;
+              new->dir = 12;
+
+              }
+
+
+           }
+        else */
+        {
+            SpawnMissile(ob,p_firebombobj,0,dirangle8[2*i],&s_grexplosion1,0x10000);
+            new->z = ob->z;
+            new->dir = (i<<1);
+
+        }
+
+        MissileSound = true;
+
+
+        SD_PlaySoundRTP(SD_EXPLODEFLOORSND,ob->x,ob->y);
+        new->temp2 = FixedMul(damage,DIAGADJUST);
+
+
+        tempwall = (wall_t*)actorat[new->tilex][new->tiley];
+        doorat= 0;
+        if (M_ISDOOR(new->tilex,new->tiley))
+        {
+            tempdoor = doorobjlist[tilemap[new->tilex][new->tiley]&0x3ff];
+            if (tempdoor->position<0x8000)
+                doorat = 1;
+        }
+
+        if ((tempwall && M_ISWALL(tempwall)) || doorat ||
+                (new->tilex <=0) || (new->tilex > MAPSIZE-1) ||
+                (new->tiley <=0) || (new->tiley > MAPSIZE-1)
+           )
+        {
+            new->z = ob->z;
+            SetFinePosition(new,ob->x,ob->y);
+            SetVisiblePosition(new,ob->x,ob->y);
+        }
+        new->whatever = ob->whatever;
+        new->temp3 = ob->temp3 - 1;
+    }
+}
+
+
+
+
+
+
+void MissileHitActor(objtype *owner, objtype *missile, objtype *victim,
+                     int damage, int hitmomx, int hitmomy
+                    )
+{
+    int tcl = victim->obclass;
+    int ocl = missile->obclass;
+
+    if (
+        (victim->flags & FL_DYING) || // hey, they're dying already;
+        (victim->flags & FL_HEAD)  || // don't hurt overrobot's head, wheels
+        (tcl == wallopobj)            || // bcraft is invulnerable
+        (tcl == b_darkmonkobj)        || // darkmonk is invulnerable
+        (!(victim->flags & FL_SHOOTABLE)) || // don't hurt environment dangers, dead guys
+        ((tcl == b_darksnakeobj) &&
+         ((SNAKELEVEL != 3) || (!victim->temp3))// return for non-red snake
+        )
+    )
+        return;
+
+
+    if ((tcl == playerobj) || (tcl == b_heinrichobj))
+        victim->target = owner;
+
+
+    if (tcl == NMEsaucerobj)  // can shoot over's saucer
+    {
+        NewState(victim,&s_explosion1);
+        victim->flags &= ~FL_SHOOTABLE;
+        victim->temp2 = damage;
+        return;
+    }
+
+    else if (tcl == roboguardobj)       // check roboguard
+    {
+        DamageThing(victim,damage);
+        Collision(victim,owner,0,0);
+    }
+
+    else if (tcl == collectorobj)
+    {
+        if (gamestate.SpawnEluder)
+            return;
+
+        DamageThing(victim,damage);
+        Collision(victim,owner,0,0);
+    }
+
+    else if (tcl == patrolgunobj)
+    {
+        DamageThing(victim,damage);
+        if (victim->hitpoints <= 0)
+        {
+            victim->momentumx = victim->momentumy = victim->momentumz = 0;
+            victim->flags |= FL_DYING;
+            if (victim->temp1 == -1)  // this is 4-way gun
+                NewState(victim,&s_robogrddie1);
+#if (SHAREWARE == 0)
+            else                         // this is normal
+                NewState(victim,&s_gundie1);
+#endif
+        }
+    }
+
+// bosses are "special" ==========================
+
+    else if ((tcl >= b_darianobj) && (tcl < b_darkmonkobj))
+
+    {
+        DamageThing(victim,damage);
+        if (!(victim->flags & FL_ATTACKMODE))
+            FirstSighting (victim);     // put into combat mode
+        if (victim->hitpoints <= 0)
+        {
+            victim->momentumx = victim->momentumy = victim->momentumz = 0;
+            victim->flags |= FL_DYING;
+            NewState(victim,UPDATE_STATES[DIE][victim->obclass-lowguardobj]);
+            switch (victim->obclass)
+            {
+            case b_darianobj:
+                AddMessage("Darian defeated!",MSG_CHEAT);
+                break;
+
+            case b_heinrichobj:
+                AddMessage("Krist defeated!",MSG_CHEAT);
+                break;
+
+            case b_robobossobj:
+                AddMessage("NME defeated!",MSG_CHEAT);
+                break;
+            default:
+                ;
+            }
+            MU_StartSong(song_bossdie);
+        }
+#if (SHAREWARE == 0)
+        else
+        {
+            MISCVARS->REDTIME = (damage >> 1);
+            if (victim->obclass == b_heinrichobj)
+            {
+                NewState(victim,&s_heinrichdefend);
+                if (Near(victim,PLAYER[0],3))
+                {
+                    MISCVARS->HRAMMING = 1;
+                    MISCVARS->HMINING = 0;
+                    victim->dirchoosetime = 0;
+                }
+                else
+                {
+                    MISCVARS->HMINING = 1;
+                    MISCVARS->HRAMMING = 0;
+                    victim->dirchoosetime = 5;//10;
+                }
+                victim->targettilex = victim->targettiley = 0;
+                victim->target = NULL;
+            }
+        }
+#endif
+    }
+
+#if (SHAREWARE == 0)
+    else if ((tcl == b_darksnakeobj) && (victim->temp3)) // red snake
+    {
+        DamageThing(SNAKEEND,damage);
+        if (victim->state->think == T_DarkSnakeChase)
+            NewState(victim,&s_redheadhit);
+        else
+            NewState(victim,&s_redlinkhit);
+        victim->temp3 = 0;
+    }
+#endif
+
+//===============================================
+    else // all other actors
+    {
+
+        if ((tcl == playerobj) &&
+                (victim->flags & FL_AV) &&
+                (ocl != p_godballobj)
+           )
+        {
+            playertype *pstate;
+
+            M_LINKSTATE(victim,pstate);
+            pstate->protectiontime -= ((damage<<1) + damage);
+            if (pstate->protectiontime < 1)
+                pstate->protectiontime = 1;
+            if (victim==player)
+                GM_UpdateBonus (pstate->protectiontime, false);
+
+            return;  // asbestos vest prevents victim damage
+        }
+
+        DamageThing(victim,damage);
+
+
+
+        if ((tcl < roboguardobj) && (victim->hitpoints <= 0))
+        {
+            if (ocl != p_godballobj)
+                victim->flags |= FL_HBM;
+            else
+                victim->flags |= (FL_GODSTRUCK | FL_FULLLIGHT);
+        }
+
+        if (tcl == playerobj)
+        {
+            playertype *pstate;
+
+            M_LINKSTATE(victim,pstate);
+            if (pstate->health <= 0)
+            {
+                if (ocl != p_godballobj)
+                    victim->flags |= FL_HBM;
+                else
+                    victim->flags |= (FL_GODSTRUCK | FL_FULLLIGHT);
+
+                if (M_ISACTOR(owner))
+                {
+                    if (owner->obclass == playerobj)
+                    {
+                        if (!victim->momentumz)
+                            BATTLE_PlayerKilledPlayer(battle_kill_with_missile,owner->dirchoosetime,victim->dirchoosetime);
+                        else
+                            BATTLE_PlayerKilledPlayer(battle_kill_with_missile_in_air,owner->dirchoosetime,victim->dirchoosetime);
+                    }
+                    else
+                        BATTLE_CheckGameStatus(battle_player_killed,missile->dirchoosetime);
+                }
+                else
+                    BATTLE_CheckGameStatus(battle_player_killed,missile->dirchoosetime);
+            }
+        }
+
+
+
+        if ((owner->obclass == playerobj) && (victim->flags & FL_HBM))
+        {
+            MISCVARS->supergibflag = true;
+            //GivePoints(starthitpoints[gamestate.difficulty][victim->obclass]*5);
+        }
+
+        Collision(victim,owner,hitmomx,hitmomy);
+        MISCVARS->supergibflag = false;
+        if ((tcl == blitzguardobj) && (owner->obclass == playerobj))
+            victim->flags |= FL_TARGET;
+
+    }
+
+}
+
+
+
+void MissileHit (objtype *ob,void *hitwhat)
+{
+    int damage=0, random,tcl=0,ocl,fireweapon=0,sound,hitmomx,hitmomy;
+    objtype* tempactor=NULL,*owner;
+
+
+
+    if (ob==missobj)
+        missobj=NULL;
+
+    if (ob == PLAYER0MISSILE)
+        PLAYER0MISSILE = NULL;
+
+
+    ob->momentumz = 0;
+    hitmomx = ob->momentumx;
+    hitmomy = ob->momentumy;
+    if (ob->soundhandle != -1)
+        SD_StopSound(ob->soundhandle);
+
+    ob->flags &= ~FL_SHOOTABLE;
+    if (FirstExplosionState(ob->state))
+        return;
+
+    /*
+    if ((ob->z < -28) || (IsWindow(ob->tilex,ob->tiley)))
+       {
+       NewState(ob,&s_megaremove);
+       return;
+       }
+    */
+
+    tempactor = (objtype*)hitwhat;
+    owner = (objtype*)(ob->whatever);
+
+    random = GameRandomNumber("MissileHit",0);
+    ocl = ob->obclass;
+    if (tempactor)
+    {
+        if (tempactor->which == ACTOR)
+            tcl = tempactor->obclass;
+        else if (tempactor->which == SPRITE)
+            tcl = -1;
+    }
+
+    if ((!tcl) && (ob->z < -30))
+    {
+        if (ob->soundhandle != -1)
+            SD_StopSound(ob->soundhandle);
+
+        NewState(ob,&s_megaremove);
+        return;
+
+    }
+
+
+    if (((ocl != p_kesobj) && (ocl != p_godballobj)) || (!tcl))
+        ZEROMOM;
+
+    if (tcl == b_darianobj)
+        MISCVARS->ESAU_SHOOTING  = false;
+
+    switch(ocl)
+    {
+
+
+    case p_bazookaobj:
+        NewState(ob,&s_explosion1);
+        if (M_ISACTOR(owner) && (owner->obclass == blitzguardobj))
+            damage = 30 + (random >> 4);
+        else
+            damage = 2*((random>>3)+80);
+        break;
+
+    case p_heatseekobj:
+        NewState(ob,&s_explosion1);
+        damage = 2*((random>>3)+50);
+        break;
+
+
+    case p_drunkmissileobj:
+        NewState(ob,&s_explosion1);
+        damage = ((random>>3)+25);
+        break;
+
+    case p_firebombobj:
+        NewState(ob,&s_explosion1);
+        damage = 2*((random>>3)+90);
+        ob->temp3 = 4;
+        SpawnFirebomb(ob,damage,4);
+        break;
+
+    case p_firewallobj:
+
+        if (tcl == playerobj)
+            gamestate.DOGROUNDZEROBONUS = true;
+        NewState(ob,&s_explosion1);
+        damage = 2*((random>>3)+50);
+        break;
+
+
+    case p_godballobj:
+        if ((tcl >= pillarobj) || (!tcl) || ((tcl == -1) && (!(tempactor->flags & FL_SHOOTABLE))))
+            NewState(ob,&s_explosion1);
+        ob->target = NULL;
+        damage = 500;
+        break;
+
+
+    case shurikenobj:
+        NewState(ob,&s_explosion1);
+        damage = ((random >>3) + 30)>>2;
+        break;
+
+
+    case grenadeobj:
+        NewState(ob,&s_explosion1);
+        damage = (random >>3) + 20;
+        break;
+
+    case fireballobj:
+        NewState(ob,&s_explosion1);
+        damage = (random >> 3) + 10;
+        fireweapon = 1;
+        break;
+
+    case missileobj:
+        NewState(ob,&s_explosion1);
+        if (M_ISACTOR(owner) && (owner->obclass == wallopobj))
+            damage = (random >> 5);
+        else
+            damage = (random >>3) + 30;
+        if (tcl && (tcl != b_heinrichobj))
+            damage = 3*damage>>3;
+        break;
+
+    case wallfireobj:
+        if ((!tempactor) ||
+                (tempactor->which == ACTOR) ||
+                (tempactor->which == SPRITE)
+           )
+            NewState(ob,&s_explosion1);
+        else if (M_ISWALL(tempactor) || (tempactor->which == DOOR))
+            NewState(ob,&s_crossdone1);
+        damage = EnvironmentDamage(ob);
+        fireweapon = 1;
+        break;
+
+
+
+    case inertobj:
+        ob->state = NULL;
+        return;
+        break;
+
+
+#if (SHAREWARE == 0)
+
+
+    case p_splitmissileobj:
+        NewState(ob,&s_explosion1);
+        damage = 2*((random>>3)+50);
+        break;
+
+
+    case p_kesobj:
+        if ((tcl >= pillarobj) ||
+                (!tcl) ||
+                ((tcl == -1) && (!(tempactor->flags & FL_SHOOTABLE)))
+           )
+            NewState(ob,&s_explosion1);
+        damage = 2*((random>>3)+140);
+        break;
+
+
+    case netobj:
+        ob->state=NULL;
+        MISCVARS->NET_IN_FLIGHT = false;
+        if (tempactor == PLAYER[0])
+        {
+            if ((tempactor->flags & FL_GODMODE) ||
+                    (tempactor->flags & FL_DOGMODE) ||
+                    godmode
+               )
+                damage = 0;
+            else
+            {
+                damage = (random >>4) + 5;
+                PLAYERSTATE[0].NETCAPTURED = -1;
+                PLAYERSTATE[0].weapondowntics = WEAPONS[PLAYERSTATE[0].weapon].screenheight/GMOVE;
+                NewState(PLAYER[0],&s_player);
+                PLAYERSTATE[0].attackframe = PLAYERSTATE[0].weaponframe = 0;
+                PLAYERSTATE[0].batblast = 0;
+                if (PLAYERSTATE[0].HASKNIFE == false)
+                    AddMessage("Wiggle left and right to get out of net!",
+                               MSG_GAME);
+            }
+        }
+        break;
+
+
+    case bigshurikenobj:
+        NewState(ob,&s_oshurikenhit1);
+        if (owner->obclass == wallopobj)
+            damage = (random >> 5);
+        else
+            damage = 4*((random >>3) + 30)/10;
+
+        break;
+
+
+    case dm_spitobj:
+        NewState(ob,&s_spithit1);
+        damage = 30;
+        if (gamestate.difficulty == gd_hard)
+            damage += 15;
+        break;
+
+    case dm_weaponobj:
+        damage = 20;
+        NewState(ob,&s_explosion1);
+        break;
+
+    case dm_heatseekobj:
+        damage = 20;
+        NewState(ob,&s_explosion1);
+        break;
+
+    case dmfballobj:
+        NewState(ob,&s_explosion1);
+        damage = (random >>3) + 20;
+        fireweapon = 1;
+        break;
+
+    case h_mineobj:
+        NewState(ob,&s_explosion1);
+        damage = (random >>3) + 20;
+        break;
+
+    case NMEsaucerobj:
+        NewState(ob,&s_explosion1);
+        damage = 2*((random>>3)+30);
+        break;
+
+
+#endif
+
+
+        //default:
+        //Error("Unknown ob %d called MissileHit",ob->obclass);
+    }
+
+    //if (!ob->state)
+    //return;
+    if ((sound = BAS[ob->obclass].hit)!=0)
+        SD_PlaySoundRTP(sound,ob->x,ob->y);
+
+
+    if (FirstExplosionState(ob->state))
+        SD_PlaySoundRTP(SD_EXPLODESND,ob->x,ob->y);
+
+
+    if (tcl>0) // actors
+    {
+        MissileHitActor(owner,ob,tempactor,damage,hitmomx,hitmomy);
+        if ((ocl == p_kesobj) && (tcl < roboguardobj))
+        {
+            tempactor->momentumx = hitmomx; // kes gives wus targets its momentum
+            tempactor->momentumy = hitmomy;
+            //missile->flags |= FL_NOFRICTION;
+        }
+    }
+
+    else if (tcl < 0)  // static
+    {
+        DamageThing(hitwhat,damage);
+        if (FirstExplosionState(new->state))
+            new->whatever = ob->whatever;
+    }
+
+
+}
+
+
+
+
+void T_Spears(objtype*ob)
+{   int dx,dy,dz,i;
+
+
+    for(i=0; i<numplayers; i++)
+    {   if (PLAYER[i]->flags & FL_DYING)
+            continue;
+
+        dx = abs(PLAYER[i]->x - ob->x);
+        dy = abs(PLAYER[i]->y - ob->y);
+        dz = abs(PLAYER[i]->z - ob->z);
+
+
+        if ((!ob->ticcount)&&(ob->state->condition&SF_SOUND) &&
+                areabyplayer[ob->areanumber])
+            SD_PlaySoundRTP(BAS[ob->obclass].operate,ob->x,ob->y);
+
+        if ((dx < STANDDIST) && (dy < STANDDIST) && (dz < 20))
+        {   ob->flags &= ~FL_BLOCK;
+            if ((!ob->ticcount) && (ob->state->condition & SF_CRUSH))
+            {   DamageThing(PLAYER[i],EnvironmentDamage(ob));
+                Collision(PLAYER[i],ob,0,0);
+                M_CheckPlayerKilled(PLAYER[i]);
+                return;
+            }
+        }
+        else
+        {   if (ob->state->condition & SF_DOWN)
+                ob->flags &= ~FL_BLOCK;
+            else
+                ob->flags |= FL_BLOCK;
+        }
+    }
+}
+
+
+
+void T_CrushUp(objtype*ob)
+{   int dx, dy,dist,dz,i,playeron;
+
+
+    if ((!ob->ticcount) && (ob->state->condition & SF_SOUND) &&
+            areabyplayer[ob->areanumber])
+        SD_PlaySoundRTP(BAS[ob->obclass].operate,ob->x,ob->y);
+    dist = ACTORSIZE+0x2000;
+    if (ob->state->condition & SF_UP)
+    {   ob->temp1 += 4;
+//	  Debug("\ncol momz = 4");
+    }
+    else if (ob->state->condition & SF_DOWN)
+    {   ob->temp1 -= 4;
+//      Debug("\ncol mom z = -4");
+    }
+    else
+    {   //ob->momentumz = 0;
+        //	  Debug("\ncol mom z = 0");
+    }
+
+    ob->temp2 = maxheight - ob->temp1 + 32;
+
+
+    playeron = 0;
+    for(i=0; i<numplayers; i++)
+    {   dx = abs(PLAYER[i]->x - ob->x);
+        dy = abs(PLAYER[i]->y - ob->y);
+        dz = abs(ob->temp2-PLAYER[i]->z);
+
+        if ((dx < dist) && (dy < dist) && (dz < 65))
+        {   ob->flags &= ~FL_BLOCK;
+            //player->temp2 = 0;
+            playeron  = 1;
+            if ((!ob->ticcount) && (ob->state->condition & SF_CRUSH) &&
+                    (levelheight<2) && (!(ob->flags & FL_DYING)))
+            {   DamageThing(PLAYER[i],EnvironmentDamage(ob));
+                if (PLAYER[i]->hitpoints <= 0)
+                    PLAYER[i]->flags |= FL_HBM;
+                Collision(PLAYER[i],ob,0,0);
+                M_CheckPlayerKilled(PLAYER[i]);
+                //NewState(ob,ob->state); //reset ticcount
+                return;
+            }
+            if (ob->state->condition & SF_UP)
+            {
+                PLAYER[i]->momentumz = -(4<<16);
+                if (PLAYER[i]->z < -30)
+                    PLAYER[i]->z = -30;
+            }
+            else if (ob->state->condition & SF_DOWN)
+            {   PLAYER[i]->momentumz = (4<<16);
+                if (PLAYER[i]->z >= nominalheight)
+                    PLAYER[i]->z = nominalheight;
+            }
+            else
+                PLAYER[i]->momentumz = 0;
+            PLAYER[i]->whatever = ob;
+            ob->whatever = PLAYER[i];
+            //PLAYER[i]->flags |= FL_RIDING;
+
+        }
+
+    }
+
+    //if (!playeron)
+    {   if (ob->state->condition & SF_BLOCK)
+            ob->flags |= FL_BLOCK;
+        else
+            ob->flags &= ~FL_BLOCK;
+
+    }
+
+
+}
+
+
+void T_CrushDown(objtype*ob)
+{   int dx,dy,dz,i,playeron;
+
+
+    if ((!ob->ticcount) && (ob->state->condition & SF_SOUND)&&
+            areabyplayer[ob->areanumber])
+        SD_PlaySoundRTP(BAS[ob->obclass].operate,ob->x,ob->y);
+
+    ob->temp2 = ob->z;
+    playeron = 0;
+    for(i=0; i<numplayers; i++)
+    {   dx = abs(PLAYER[i]->x - ob->x);
+        dy = abs(PLAYER[i]->y - ob->y);
+        dz = abs(PLAYER[i]->z - ob->z);
+
+        if ((dx < STANDDIST) && (dy < STANDDIST) && (dz < 20))
+        {   //PLAYER[i]->temp2 = 0;
+            playeron = 1;
+            ob->flags &= ~FL_BLOCK;
+            if ((!ob->ticcount) && (ob->state->condition & SF_CRUSH) &&
+                    (!(ob->flags & FL_DYING)))
+            {   DamageThing(PLAYER[i],EnvironmentDamage(ob));
+                if (PLAYER[i]->hitpoints <= 0)
+                    PLAYER[i]->flags |= FL_HBM;
+                Collision(PLAYER[i],ob,0,0);
+                M_CheckPlayerKilled(PLAYER[i]);
+                //NewState(ob,ob->state); //reset ticcount
+                return;
+            }
+            if ((ob->state->condition & SF_DOWN) &&
+                    ((ob->state != &s_columndowndown1) &&
+                     (ob->state != s_columndowndown1.next)))
+            {   PLAYER[i]->temp2 = COLUMNCRUSH;
+                PLAYER[i]->whatever = ob;
+            }
+        }
+
+    }
+    //if (!playeron)
+    {   if (ob->state->condition & SF_BLOCK)
+            ob->flags |= FL_BLOCK;
+        else
+            ob->flags &= ~FL_BLOCK;
+    }
+
+
+}
+
+
+void T_Explosion(objtype* ob)
+{
+    int momx,momy,momz;
+    int dx,dy,dz;
+    int pdamage,dist,blastradius=0x20000,
+                     fatalradius=0x9000,impulse,damage,
+                     scalefactor;
+
+
+
+    statobj_t* checkstat;
+    objtype* check,*owner;
+
+    if (ob->ticcount)
+        return;
+
+    damage = EXPLOSION_DAMAGE;
+    owner = (objtype*)(ob->whatever);
+    if ((ob->temp3) && (ob->obclass == p_firebombobj))
+    {
+        SpawnFirebomb(ob,damage,0);
+        ob->temp3 = 0;
+    }
+//================== check surrounding actors ============================//
+
+
+    for(check = firstactive; check; check=check->nextactive)
+    {
+        if (check == ob)
+            continue;
+
+//	  if (check == owner)
+//		continue;
+
+        dx = abs(check->x - ob->x);
+        if (dx > blastradius)
+            continue;
+
+        dy = abs(ob->y - check->y);
+        if (dy > blastradius)
+            continue;
+
+        dz = ((abs(ob->z - check->z))<<10);
+        if (dz > blastradius)
+            continue;
+
+
+        if (check->flags & FL_HEAD)
+            continue;
+
+        if (check->flags & FL_DYING)
+            continue;
+
+        if (!(check->flags & FL_SHOOTABLE))
+            continue;
+
+
+
+        if ((check->obclass >= roboguardobj) && (check->obclass != b_darkmonkobj))
+            //(check->obclass <= wallopobj))
+            continue;
+
+
+        if (!CheckLine(ob,check,SIGHT))
+            continue;
+
+
+        if (check->obclass == NMEsaucerobj)
+        {
+            NewState(check,&s_explosion1);
+            check->flags &= ~FL_SHOOTABLE;
+            return;
+        }
+#if 0
+        dist = FindDistance(dx,dy);
+        scalefactor = (blastradius-dist)>>4;
+        if (scalefactor > 0xffff)
+            scalefactor = 0xffff;
+        pdamage = FixedMul(damage,scalefactor);
+#endif
+//#if 0
+        //magdx = abs(dx);
+        //magdy = abs(dy);
+
+        dist = Find_3D_Distance(dx,dy,dz);
+        SoftError("\ndist: %x\n",dist);
+
+
+        //if (dist < 0x10000)
+        // dist = 0x10000;
+
+        scalefactor = FixedDiv2(1<<16,FixedMul(dist,dist));
+        //scalefactor = FixedDiv2(1<<16,dist);
+
+        if (scalefactor > 0x12000)
+            scalefactor = 0x12000;
+        pdamage = FixedMul(damage,scalefactor);
+        SoftError("\ndamage: %d, scalefactor: %x\n",pdamage,scalefactor);
+//#endif
+        impulse = FixedMul(EXPLOSION_IMPULSE,scalefactor);
+        if (check->obclass == playerobj)
+        {
+            check->target = owner;
+            if (check->flags & FL_AV)
+                pdamage = 0;
+        }
+
+        if (check->obclass < roboguardobj)
+        {
+            SoftError("\nhitpoints before: %d",check->hitpoints);
+            DamageThing(check,pdamage);
+            SoftError("\nhitpoints after: %d",check->hitpoints);
+            if ((check->hitpoints <= 0) && (gamestate.violence == vl_excessive) &&
+                    ((ob->obclass == p_firebombobj) ||
+                     ((dx < fatalradius) && (dy < fatalradius) && (dz < 20)))
+               )
+                check->flags |= FL_HBM;
+
+            GetMomenta(check,ob,&momx,&momy,&momz,impulse);
+            //Debug("\nhitmomx = %d, hitmomy = %d",momx,momy);
+
+            /*if (M_ISACTOR(owner) &&
+                (owner->obclass == playerobj) &&
+                (check->hitpoints <=0)
+               )
+               GivePoints(starthitpoints[gamestate.difficulty][check->obclass]*5);
+            */
+            Collision(check,owner,momx,momy);
+            check->momentumz += (momz<<6);
+            if ((check->obclass == playerobj) && (check->flags & FL_DYING) &&
+                    M_ISACTOR(owner))
+            {
+                if (owner->obclass == playerobj)
+                {
+                    if (check->z != nominalheight)
+                        BATTLE_PlayerKilledPlayer(battle_kill_with_missile_in_air,owner->dirchoosetime,check->dirchoosetime);
+                    else
+                        BATTLE_PlayerKilledPlayer(battle_kill_with_missile,owner->dirchoosetime,check->dirchoosetime);
+                }
+                else
+                    BATTLE_CheckGameStatus(battle_player_killed,check->dirchoosetime);
+            }
+
+        }
+        else
+        {
+            if (check->obclass != b_darkmonkobj) {
+                SoftError("non-darkmonk actor %d being helped by explosion",check->obclass);
+            }
+            check->hitpoints += pdamage;
+        }
+    }
+
+//======================== check surrounding statics ================
+
+
+    for(checkstat = firstactivestat; checkstat; checkstat=checkstat->nextactive)
+    {
+
+        if ((!(checkstat->flags & FL_SHOOTABLE)) && (checkstat->itemnumber != stat_priestporridge))
+            continue;
+
+        if ((checkstat->itemnumber >= stat_lifeitem1) &&
+                (checkstat->itemnumber <= stat_lifeitem4))
+            continue;
+
+        dx = abs(checkstat->x - ob->x);
+        dy = abs(checkstat->y - ob->y);
+        dz = ((abs(checkstat->z - ob->z))<<10);
+
+        if ((dx < blastradius) && (dy < blastradius) && (dz < blastradius))
+        {
+            dist = Find_3D_Distance(dx,dy,dz)+0xc00;
+
+            if (dist < 0x10000)
+                dist = 0x10000;
+
+            scalefactor = FixedDiv2(1<<16,FixedMul(dist,dist));
+            pdamage = FixedMul(damage,scalefactor);
+
+            if (checkstat->itemnumber != stat_priestporridge)
+                DamageThing(checkstat,pdamage);
+            else if (!(checkstat->flags & FL_ACTIVE))
+            {
+                checkstat->flags |= FL_ACTIVE;
+                checkstat->count = 1;
+                //checkstat->numanims = 6;
+                SD_PlaySoundRTP(SD_COOKHEALTHSND,ob->x,ob->y);
+            }
+        }
+    }
+
+//======================== check surrounding walls ================
+    {
+        int tilexlow,tilexhigh;
+        int tileylow,tileyhigh;
+        int radius =0x10000;
+        int x,y;
+
+        tilexlow = (int)((ob->x-radius) >>TILESHIFT);
+        tileylow = (int)((ob->y-radius) >>TILESHIFT);
+
+        tilexhigh = (int)((ob->x+radius) >>TILESHIFT);
+        tileyhigh = (int)((ob->y+radius) >>TILESHIFT);
+
+        for (y=tileylow; y<=tileyhigh; y++)
+        {
+            for (x=tilexlow; x<=tilexhigh; x++)
+            {
+                if ((tilemap[x][y]&0x8000) && (tilemap[x][y]&0x4000) && (abs(ob->z - nominalheight) < 32))
+                {
+                    maskedwallobj_t * mw;
+
+                    mw=maskobjlist[tilemap[x][y]&0x3ff];
+                    if (mw->flags&MW_SHOOTABLE)
+                        UpdateMaskedWall(tilemap[x][y]&0x3ff);
+                }
+            }
+        }
+    }
+
+}
+
+
+
+void SpawnScreenEye(objtype *ob)
+{
+    SpawnNewObj(ob->tilex,ob->tiley,&s_eye1,inertobj);
+    new->targettiley = 0;
+    new->targettilex = GameRandomNumber("eye position",0) + 20;
+    SCREENEYE = new;
+    //RemoveFromArea(new);
+    new->flags |= FL_ABP;
+    MakeActive(new);
+
+}
+
+
+
+
+
+
+void SpawnSuperFatalityGibs(objtype *ob,objtype *attacker)
+{
+    int crazygibs = (GameRandomNumber("crazy gibs",0) % 6) + 4;
+    int i;
+
+
+    if ((MISCVARS->supergibflag == true) &&
+            ((crazygibs == 9) || (ludicrousgibs == true))
+       )
+
+    {
+        int olddirect = MISCVARS->directgibs;
+
+        MISCVARS->directgibs = false;
+        if (ludicrousgibs == false)
+        {
+            if (attacker == player)
+            {
+                AddMessage("Ludicrous Gibs!",MSG_GAME);
+                if (!(attacker->flags&FL_DOGMODE))
+                    SD_Play(PlayerSnds[locplayerstate->player]);
+            }
+        }
+        else
+        {
+            MISCVARS->randgibspeed = true;
+
+#ifdef MEDGIBS
+            SpawnParticles(ob,GUTS,150);
+#else
+            SpawnParticles(ob,GUTS,75);
+#endif
+
+            MISCVARS->randgibspeed = false;
+        }
+        SpawnParticles(ob,GUTS,40);
+        MISCVARS->directgibs = olddirect;
+
+    }
+
+    for (i=gt_head; i<=crazygibs; i++)
+    {
+
+        if (((ob->obclass == dfiremonkobj) || (ob->obclass == deathmonkobj)) &&
+                (i == gt_leg)
+           )
+            SpawnParticles(ob,gt_arm,1);
+        else
+            SpawnParticles(ob,i,1);
+    }
+
+
+}
+
+
+
+
+
+boolean Vicious_Annihilation(objtype *ob, objtype *attacker)
+{
+    if ((ob->flags & FL_HBM) && (gamestate.violence >= vl_high))
+    {
+        ob->shapeoffset = 0;
+        ob->flags &= ~FL_FULLLIGHT;
+        NewState(ob,(ob->obclass == playerobj)?(&s_remoteguts1):(&s_guts1));
+        SD_PlaySoundRTP(SD_ACTORSQUISHSND,ob->x,ob->y);
+        if (gamestate.violence == vl_excessive)
+        {
+            int numgibs;
+            objtype *prevlast;
+
+            numgibs = (GameRandomNumber("excessive guts",0) & 7) + 4;
+            //SoftError("\nnumgibs = %d,gamestate.difficulty = %d",numgibs,gamestate.difficulty);
+            prevlast = LASTACTOR;
+            MISCVARS->fulllightgibs = true;
+            SpawnParticles(ob,GUTS,numgibs);
+            MISCVARS->fulllightgibs = false;
+            for(prevlast = prevlast->next; prevlast; prevlast = prevlast->next)
+                prevlast->momentumz += (prevlast->momentumz >> 1);
+
+            if ((GameRandomNumber("super gib chance",0) < 100) ||
+                    (ludicrousgibs == true)
+               )
+            {
+                MISCVARS->directgibs = true;
+//MED
+                MISCVARS->gibgravity = GRAVITY/2;
+//            MISCVARS->gibgravity = GRAVITY*2;
+                MISCVARS->fulllightgibs = true;
+                SpawnSuperFatalityGibs(ob,attacker);
+                MISCVARS->fulllightgibs = false;
+                MISCVARS->gibgravity = -1;
+                MISCVARS->directgibs = false;
+            }
+        }
+        return true;
+
+    }
+
+
+    if (ob->flags & FL_GODSTRUCK)
+    {
+        ob->shapeoffset = 0;
+        ob->flags |= (FL_FULLLIGHT);
+        ob->flags &= ~FL_COLORED;
+        ob->momentumx = ob->momentumy = ob->momentumz = 0;
+        KillActor(ob);
+        NewState(ob,&s_vaporized1);
+        return true;
+    }
+
+    if (ob->flags & FL_SKELETON)
+    {
+        KillActor(ob);
+        ob->shapeoffset = 0;
+        ob->flags &= ~FL_COLORED;
+        ob->momentumx = ob->momentumy = ob->momentumz = 0;
+        NewState(ob,&s_skeleton1);
+        SD_PlaySoundRTP(SD_ACTORBURNEDSND,ob->x,ob->y);
+        return true;
+    }
+
+    return false;
+
+}
+
+void SetReverseDeathState(objtype * actor)
+{
+    switch(actor->obclass)
+    {
+        case lowguardobj:
+            NewState(actor, &s_lowgrddie4rev);
+            //actor->state = &s_lowgrddie4rev;
+            break;
+        case highguardobj:
+            NewState(actor, &s_highgrddie5rev);
+            break;
+        case strikeguardobj:
+            NewState(actor, &s_strikedie4rev);
+            //actor->state = &s_strikedie4rev;
+            break;
+        case blitzguardobj:
+            NewState(actor, &s_blitzdie4rev);
+            //actor->state = &s_blitzdie4rev;
+            break;
+        case triadenforcerobj:
+            NewState(actor, &s_enforcerdie4rev);
+            //actor->state = &s_enforcerdie4rev;
+            break;
+        case overpatrolobj:
+            NewState(actor, &s_opdie5rev);
+            //actor->state = &s_opdie5rev;
+            break;
+        case deathmonkobj:
+            NewState(actor, &s_dmonkdie4rev);
+            //actor->state = &s_dmonkdie4rev;
+            break;
+        case dfiremonkobj:
+            NewState(actor, &s_firemonkdie4rev);
+            //actor->state = &s_firemonkdie4rev;
+            break;
+        default:
+            Error("SetReverseDeathState was called with something that can't be handled!");
+            break;
+    }
+}
+
+extern objtype* enemiesToRes;
+extern unsigned int freeSlot;
+void AddEnemyToResurrectList(objtype * ob)
+{
+    SetReverseDeathState(ob);
+    enemiesToRes[freeSlot] = *ob;
+    freeSlot++;
+}
+
+void CleanUpResurrectList()
+{
+    memset(enemiesToRes, 0, sizeof(*enemiesToRes));
+    freeSlot = 0;
+}
+
+void FreeUpResurrectList()
+{
+    free(enemiesToRes);
+}
+
+void SetAfterResurrectState(objtype * actor, statetype * doWhat)
+{
+    statetype * state = actor->state;
+    
+    while(state->next != NULL)
+    {
+         state = state->next;
+    }
+    state->next = doWhat;
+}
+
+void SpawnDuringGameWithState (classtype which, int tilex, int tiley, int dir, int ambush, statetype * temp)
+{
+    //statetype *temp;
+
+#if (SHAREWARE == 1)
+    switch(which)
+    {
+    case overpatrolobj:
+    case wallopobj:
+    case deathmonkobj:
+    case dfiremonkobj:
+    case b_darianobj:
+    case b_heinrichobj:
+    case b_darkmonkobj:
+        Error("\n%s actor at %d,%d not allowed in shareware !",debugstr[which],tilex,tiley);
+        break;
+    default:
+        ;
+    }
+
+#endif
+    if (which > dfiremonkobj)
+    {
+        return;
+    }
+    
+    if (!CheckTile(tilex,tiley))
+        FindEmptyTile(&tilex, &tiley);
+        
+    SpawnNewObj(tilex,tiley,temp,which);
+
+    if (ambush)
+        new->flags |= FL_AMBUSH;
+
+    StandardEnemyInit(new,dir);
+
+    if (which == b_darkmonkobj)
+    {
+        new->flags |= (FL_NOFRICTION);//|FL_INVULNERABLE);
+        new->speed = ENEMYRUNSPEED*2;
+    }
+
+    ConnectAreas();
+}
+
+void ResurrectEnemies()
+{   
+    objtype * actor;
+    
+    for (actor = &enemiesToRes[0]; actor < &enemiesToRes[freeSlot]; actor++)
+    {
+        SD_PlaySoundRTP(SD_PLAYERSPAWNSND, actor->x, actor->y);
+        SpawnDuringGameWithState (actor->obclass,actor->tilex,actor->tiley,actor->dir, 1, actor->state);
+    }
+    
+    CleanUpResurrectList();
+    
+}
+
+/*
+void SetStandAfterResurrect(objtype * actor)
+{
+    switch(actor->obclass)
+    {
+        case lowguardobj:
+            SetAfterResurrectState(actor, &s_lowgrdstand);
+            //actor->state = &s_lowgrdchase1;
+            break;
+        case highguardobj:
+            SetAfterResurrectState(actor, &s_highgrdstand);
+            //actor->state = &s_highgrdchase1;
+            break;
+        case strikeguardobj:
+            SetAfterResurrectState(actor, &s_strikestand);
+            //actor->state = &s_strikechase1;
+            break;
+        case blitzguardobj:
+            SetAfterResurrectState(actor, &s_blitzstand);
+            //actor->state = &s_blitzchase1;
+            break;
+        case triadenforcerobj:
+            SetAfterResurrectState(actor, &s_enforcerstand);
+            //actor->state = &s_enforcerchase1;
+            break;
+        case overpatrolobj:
+            SetAfterResurrectState(actor, &s_opstand);
+            //actor->state = &s_opchase1;
+            break;
+        case deathmonkobj:
+            SetAfterResurrectState(actor, &s_dmonkstand);
+            //actor->state = &s_dmonkchase1;
+            break;
+        case dfiremonkobj:
+            SetAfterResurrectState(actor, &s_firemonkstand);
+            //actor->state = &s_firemonkchase1;
+            break;
+        default:
+            Error("SetStandAfterResurrect was called with something that can't be handled!");
+            break;
+    }
+}
+*/
+
+
+
+void SpawnDuringGame (classtype which, int tilex, int tiley, int dir, int ambush)
+{   
+    statetype *temp;
+
+#if (SHAREWARE == 1)
+    switch(which)
+    {
+    case overpatrolobj:
+    case wallopobj:
+    case deathmonkobj:
+    case dfiremonkobj:
+    case b_darianobj:
+    case b_heinrichobj:
+    case b_darkmonkobj:
+        Error("\n%s actor at %d,%d not allowed in shareware !",debugstr[which],tilex,tiley);
+        break;
+    default:
+        ;
+    }
+
+#endif
+    if (which > dfiremonkobj)
+    {
+        return;
+    }
+    
+    if ((temp = UPDATE_STATES[STAND][which-lowguardobj]) != NULL)
+    {       
+        if (!CheckTile(tilex, tiley))
+            FindEmptyTile(&tilex, &tiley);
+        
+        SpawnNewObj(tilex,tiley,temp,which);
+
+        if (ambush)
+            new->flags |= FL_AMBUSH;
+
+        StandardEnemyInit(new,dir);
+
+        if (which == b_darkmonkobj)
+        {
+            new->flags |= (FL_NOFRICTION);//|FL_INVULNERABLE);
+            new->speed = ENEMYRUNSPEED*2;
+        }
+    }
+    ConnectAreas();
+}
+
+void SaveResurrectList(byte ** buffer, int *size)
+{
+    byte*tptr;
+    
+    *size = sizeof(enemiesToRes);
+    *buffer = (byte*)SafeMalloc(*size);
+    tptr = *buffer;
+    
+    memcpy(tptr, enemiesToRes, sizeof(*enemiesToRes));
+    tptr += sizeof(enemiesToRes);
+
+}
+
+/*
+========================
+=
+= BeginEnemyFatality
+=
+========================
+*/
+
+extern boolean enableZomROTT;
+
+void BeginEnemyFatality(objtype *ob,objtype *attacker)
+{
+    if ((attacker == player) && (ob->obclass < (NUMENEMIES + 2)))
+    {
+        GivePoints(starthitpoints[gamestate.difficulty][ob->obclass]*5);
+        if (timelimitenabled)
+            timelimit+=VBLCOUNTER;
+    }
+
+    ob->flags |= FL_DYING;
+    ob->soundhandle = -1;
+
+#if 0
+    if ((ob->obclass == blitzguardobj) &&
+            (ob->state->condition & SF_DOWN)
+       )
+
+        SD_Play(PlayerSnds[locplayerstate->player]);
+#endif
+
+    if (Vicious_Annihilation(ob,attacker))
+        return;
+    else if (enableZomROTT)
+    {
+        objtype * copyOfObject = malloc(sizeof(objtype));
+        
+        memcpy(copyOfObject, ob, sizeof(objtype));
+        
+        AddEnemyToResurrectList(copyOfObject);
+    }
+
+    if ((ob->obclass == patrolgunobj) && (ob->temp1 == -1))
+        NewState(ob,&s_robogrddie1);
+    else if (ob->obclass == collectorobj)
+    {
+        if ((!M_ISACTOR(attacker)) || (attacker->obclass != playerobj))
+            RespawnEluder();
+        else
+            BATTLE_CheckGameStatus(battle_shot_deluder,attacker->dirchoosetime);
+
+        NewState(ob,&s_explosion1);
+        MISCVARS->gibgravity = GRAVITY/2;
+        MISCVARS->fulllightgibs = true;
+        SpawnParticles(ob,gt_sparks,100);
+        MISCVARS->fulllightgibs = false;
+        MISCVARS->gibgravity = -1;
+    }
+    else
+    {
+        statetype *temp;
+
+        if ((ob->obclass == blitzguardobj) &&
+                (ob->state->condition & SF_FAKING)
+           )
+        {
+            NewState(ob,&s_blitzstruggledie1);
+            ob->flags &= ~FL_FULLLIGHT;
+        }
+        else if
+        ((ob->obclass == blitzguardobj) &&
+                (ob->state->condition & SF_DOWN)
+        )
+        {
+            NewState(ob,&s_blitzplead7);
+            ob->flags &= ~FL_FULLLIGHT;
+        }
+
+        else if
+        ((temp= M_S(DIE)) != NULL)
+        {
+            if (LOW_VIOLENCE_DEATH_SHOULD_BE_SET(ob))
+                SET_DEATH_SHAPEOFFSET(ob);
+            NewState(ob,temp);
+            ob->flags &= ~FL_FULLLIGHT;
+        }
+        else
+            Error("Null dead state called in Collision, obclass %d",ob->obclass);
+    }
+
+
+}
+
+
+
+/*
+========================
+=
+= BeginPlayerFatality
+=
+========================
+*/
+
+
+
+
+void BeginPlayerFatality(objtype *ob,objtype *attacker)
+{
+    playertype *pstate;
+    M_LINKSTATE(ob,pstate);
+
+
+    ob->flags &= ~(FL_ELASTO|FL_GODMODE|FL_DOGMODE|FL_NOFRICTION|FL_RIDING);
+
+    ob->flags |= FL_DYING;
+    pstate->weapon = -1;
+
+
+    if (BATTLEMODE)
+        SD_PlaySoundRTP (SD_PLAYERTCDEATHSND+(pstate->player),ob->x,ob->y);
+
+    if (Vicious_Annihilation(ob,attacker) == false)
+    {
+        if (LOW_VIOLENCE_DEATH_SHOULD_BE_SET(ob))
+            SET_DEATH_SHAPEOFFSET(ob);
+
+        NewState(ob,&s_remotedie1);
+        ob->flags &= ~FL_FULLLIGHT;
+    }
+
+
+
+}
+
+
+
+/*
+========================
+=
+= BeginEnemyHurt
+=
+========================
+*/
+
+
+void BeginEnemyHurt(objtype *ob)
+{
+    statetype *temp;
+
+    if ((temp= M_S(COLLIDE1)) != NULL)
+    {
+
+
+        if ((ob->obclass == blitzguardobj) &&
+                (ob->state->condition & SF_FAKING)
+           )
+        {
+            ob->temp1 = 1;
+            ob->dirchoosetime = 0;
+            T_PlayDead(ob);
+
+        }
+
+        else
+        {
+            if ((ob->obclass == triadenforcerobj) &&
+                    (GameRandomNumber("george pain chance",0) <
+                     (50 + (gamestate.difficulty<<6))
+                    )
+               )
+            {
+                ob->flags &= ~FL_FULLLIGHT;
+                return;
+
+            }
+
+
+            if (LOW_VIOLENCE_PAIN_SHOULD_BE_SET(ob))
+                SET_PAIN_SHAPEOFFSET(ob);
+
+            if (GameRandomNumber("Collision",0) < 128)
+                NewState(ob,temp);
+            else
+                NewState(ob,M_S(COLLIDE2));
+        }
+
+        ob->flags &= ~FL_FULLLIGHT;
+        ob->ticcount = PAINTIME;
+        if (ob->obclass == strikeguardobj)
+            ob->ticcount >>= 1;
+    }
+}
+
+
+void  Collision(objtype*ob,objtype *attacker,int hitmomentumx,int hitmomentumy)
+{
+    int ocl;
+
+    if ((!(ob->flags & FL_SHOOTABLE)) || (ob->flags & FL_DYING))
+        return;
+
+    ocl = ob->obclass;
+
+    ob->momentumx += hitmomentumx;
+    ob->momentumy += hitmomentumy;
+
+    if ((ocl == playerobj) && (gamestate.battlemode == battle_Eluder))
+        return;
+
+    //insertion 5
+
+    if (ocl != playerobj)
+    {
+        if ((!(ob->flags & FL_ATTACKMODE)) && (TABLE_ACTOR(ob)))
+            ActivateEnemy(ob);
+
+
+        if (ob->hitpoints <= 0)
+            BeginEnemyFatality(ob,attacker);
+
+        else if (ocl != roboguardobj)// && (ob->state->think != T_Collide))
+            BeginEnemyHurt(ob);
+    }
+    else
+    {
+        playertype *pstate;
+
+        if ((ob->flags & FL_GODMODE) || (ob->flags & FL_DOGMODE) || godmode)
+            return;
+
+        M_LINKSTATE(ob,pstate);
+        if (pstate->health<=0)
+            BeginPlayerFatality(ob,attacker);
+        else
+            ob->flags |= FL_PAIN;
+
+    }
+
+}
+
+
+
+
+void T_BossExplosions(objtype*ob)
+{
+
+    if (ob->temp1)
+    {   if (ob->dirchoosetime)
+            ob->dirchoosetime --;
+        else
+        {   int randtime,randangle,randdist,sound;
+            statetype *nstate;
+
+            ob->temp1 --;
+            randtime = GameRandomNumber("Boss Explosion Time",0);
+            ob->dirchoosetime = 10;
+            if (randtime < 128)
+                ob->dirchoosetime >>= 1;
+            randangle = (GameRandomNumber("Boss Explosion Angle",0) << 3);
+            randdist = (GameRandomNumber("Boss Explosion Distance",0) << 7)+0x4000;
+            sound = SD_EXPLODEFLOORSND;
+            if (randtime < 128)
+            {   nstate = &s_explosion1;
+                sound++;
+            }
+#if (SHAREWARE == 0)
+            else
+                nstate = &s_grexplosion1;
+#endif
+
+
+            SpawnMissile(ob,inertobj,0,randangle,nstate,randdist);
+            SD_PlaySoundRTP(sound,new->x,new->y);
+        }
+    }
+}
+
+
+
+
+gib_t RandomGutsType(void)
+{
+    int rand = GameRandomNumber("gut random",0);
+
+
+    if (rand < 128)
+        return gt_organ;
+
+    //if (rand < 160)
+    return gt_rib;
+
+    //return gt_pinkorgan;
+
+
+}
+
+
+//MED
+void SpawnParticles(objtype*ob,int which,int numparticles)
+{
+    int randphi,randtheta,i,nspeed;
+    boolean eyespawned = false;
+    int gibtype;
+    int randadj;
+
+
+    if ((ob->z <= -64) && (sky == 0)) //shouldn't happen
+        return;
+
+
+    if (((which == GUTS) || (which == RANDOM)) && (gamestate.violence < vl_high))
+        which = gt_sparks;
+
+    gibtype = which;
+
+
+    for(i=0; i<numparticles; i++)
+    {
+        int ordertemp;	/* DDOI - Watcom evaluates the mult order diff */
+        randphi = (GameRandomNumber("particle generate phi",0) << 3);
+        // randadj = RandomSign() * (GameRandomNumber("rand gib adjust",0) >> 4);
+        ordertemp = (GameRandomNumber("rand gib adjust",0) >> 4);
+        randadj = RandomSign() * ordertemp;
+
+
+
+        if (ob->z > (nominalheight - 32))
+            randphi &= ((ANGLES/2) - 1);
+
+        randtheta = (GameRandomNumber("particle generate theta",0) << 3);
+        nspeed = MISCVARS->gibspeed;
+
+
+        if (which == RANDOM)
+        {
+            if (GameRandomNumber("random gib",0) < 128)
+                gibtype = RandomGutsType();
+            else
+                gibtype = gt_sparks;
+
+        }
+
+        if ((which == GUTS) || (which == DISEMBOWEL))
+        {
+
+            gibtype = RandomGutsType();
+            if (which == DISEMBOWEL)
+            {
+                randphi>>=2;
+                randtheta=ob->temp1+(randtheta>>3)-(randtheta>>4);
+            }
+
+        }
+
+        if (lowmemory && (gibtype >= gt_rib) && (gibtype <= gt_limb))
+            gibtype = gt_organ;
+
+        if
+        (
+            // (gibtype >= gt_organ) && (gibtype <= gt_limb) &&
+            (MISCVARS->numgibs >= MAXGIBS)
+        )
+            return;
+
+
+
+        if (gibtype == gt_lsoul)
+        {
+            SpawnNewObj(ob->tilex,ob->tiley,&s_littlesoul,inertobj);
+            randphi = 0;
+        }
+
+
+#if (SHAREWARE == 0)
+        else if (gibtype == gt_spit)
+
+            SpawnNewObj(ob->tilex,ob->tiley,&s_slop1,inertobj);
+#endif
+        else
+        {
+            SpawnNewObj(ob->tilex,ob->tiley,&s_gibs1,inertobj);
+            new->shapeoffset = gibtype*12;
+            NewState(new,new->state);
+        }
+
+        if (MISCVARS->directgibs == true)
+        {
+            int dx,dy,dz;
+
+            dx = PLAYER[0]->x - ob->x;
+            dy = ob->y - PLAYER[0]->y;
+            randtheta = AngleBetween(ob,PLAYER[0]) +
+                        (randadj<<4);
+            dz = 100 + (randadj<<3);
+
+#ifdef MEDGIBS
+            nspeed = 0x2800;
+#else
+            nspeed = 0x2800 + (randadj<<7);
+#endif
+
+            randphi = atan2_appx(FindDistance(dx,dy),dz<<10);
+        }
+
+
+        if ((eyespawned == false) && (which == GUTS) &&
+                (ob->obclass != playerobj)
+           )
+        {
+            eyespawned = true;
+            new->flags |= FL_EYEBALL;
+        }
+
+        if ((gibtype >= gt_organ) && (gibtype <= gt_limb))
+        {
+            new->dirchoosetime = GIBVALUE;
+            MISCVARS->numgibs ++;
+        }
+        new->temp2 = gibtype;
+        new->temp3 = (MISCVARS->gibgravity == -1)?(GRAVITY):(MISCVARS->gibgravity);
+
+        new->speed = nspeed>>1;
+
+#ifndef MEDGIBS
+        if (MISCVARS->randgibspeed == true)
+            new->speed += (randadj << 11);
+#endif
+
+//      if (ob->state == &s_snakefireworks)
+        new->z = ob->z;
+
+        Fix(randphi);
+        Fix(randtheta);
+
+        Set_3D_Momenta(new,new->speed,randtheta,randphi);
+        new->momentumz <<= 6;
+        new->flags |= (FL_NOFRICTION|FL_CRAZY|FL_ABP|FL_NEVERMARK);
+        if (MISCVARS->fulllightgibs == true)
+            new->flags |= FL_FULLLIGHT;
+        new->dir = west;
+        new->whatever = ob;
+        MakeActive(new);
+    }
+}
+
+
+
+void T_SlideDownScreen(objtype *ob)
+{
+
+    ob->targettiley += 12;
+    if (ob->targettiley > 300)
+    {
+        NewState(ob,&s_megaremove);
+        SCREENEYE = NULL;
+    }
+
+}
+
+void T_SpawnSoul(objtype*ob)
+{
+    if (ob->ticcount)
+        return;
+
+    SpawnNewObj(ob->tilex,ob->tiley,&s_bigsoul,inertobj);
+    new->momentumz = -4000;
+    new->flags |= (FL_NOFRICTION|FL_CRAZY|FL_ABP|FL_NEVERMARK);
+    new->z = ob->z;
+    new->dir = west;
+    MakeActive(new);
+
+    SpawnParticles(ob,gt_lsoul,6);
+
+
+}
+
+
+void BloodDrip(objtype *ob,int tilex,int tiley)
+{   int dx,dy,x,y,scale;
+
+    dx = ob->tilex - tilex;
+    dy = ob->tiley - tiley;
+
+    if (!dy)
+    {
+        scale = (ob->momentumx)?(FixedDiv2(ob->momentumy,ob->momentumx)):(0);
+        x = (dx < 0)?(tilex << 16):((tilex+1) << 16);
+        y = FixedMul(x - ob->x,scale) + ob->y;
+    }
+
+    else if (!dx)
+    {
+        scale = (ob->momentumy)?(FixedDiv2(ob->momentumx,ob->momentumy)):(0);
+        y = (dy < 0)?(tiley << 16):((tiley+1) << 16);
+        x = FixedMul(y - ob->y,scale) + ob->x;
+    }
+
+    ob->temp2 = (GameRandomNumber("BloodDrip",0) << 9) + 0xc000;
+    ob->temp1 = (ob->z<<16);
+    SetFinePosition(ob,x,y);
+    ob->shapeoffset = 0;
+    NewState(ob,&s_blooddrip1);
+
+}
+
+
+
+void T_BloodFall(objtype*ob)
+{
+    ob->temp1 += ob->temp2;
+    ob->z = (ob->temp1 >> 16);
+    if (ob->z >= maxheight)
+    {
+        ob->shapeoffset = 12;
+        MISCVARS->numgibs--;
+        NewState(ob,&s_gibsdone1);
+        ob->z = nominalheight;
+    }
+
+}
+
+
+
+
+void T_Xylophone(objtype*ob)
+{
+    if (!ob->ticcount)
+        SD_PlaySoundRTP(SD_ACTORSKELETONSND,ob->x,ob->y);
+}
+
+
+
+void T_ParticleGenerate(objtype*ob)
+{
+
+    if (ob->dirchoosetime)
+        ob->dirchoosetime--;
+    else
+    {
+        SetGibSpeed(0x3000);
+        SpawnParticles(ob,gt_sparks,(GameRandomNumber("particle count",0) % 10) + 7);
+        ResetGibSpeed();
+        ob->dirchoosetime = 10;
+        if (GameRandomNumber("particle generator choose time",0) < 128)
+            ob->dirchoosetime >>= 1;
+    }
+
+}
+
+
+
+void T_Particle(objtype*ob)
+{   int dx,dy,dz;
+
+    ob->z += (ob->momentumz>>16);
+
+    if ((ob->z >= nominalheight) || (!ob->momentumz))
+
+    {
+        if (ob->z >= nominalheight)
+            ob->z = nominalheight;
+//done:
+        if (ob->temp2 == gt_spit)
+            ob->state = NULL;
+        else
+        {
+            if (ob->dirchoosetime == GIBVALUE)
+            {
+                MISCVARS->numgibs--;
+                SD_PlaySoundRTP(GIBSOUND,ob->x,ob->y);
+            }
+            NewState(ob,&s_gibsdone1);
+        }
+        return;
+    }
+    else if ((ob->z < -64) && (sky == 0))
+    {
+        ob->momentumz = 1; //any positive value will do
+        ob->z = -64;
+
+    }
+
+
+    ob->momentumz += ob->temp3;
+    ActorMovement(ob);
+
+
+    if (!BATTLEMODE)
+    {
+        dx = abs(ob->x - PLAYER[0]->x);
+        dy = abs(ob->y - PLAYER[0]->y);
+        dz = abs(ob->z - PLAYER[0]->z);
+
+#if (SHAREWARE==0)
+        if ((ob->flags & FL_EYEBALL) && (dx < 0x20000) && (dy < 0x20000) &&
+                (dz < 64) && (GameRandomNumber("eye chance",0) < 15) &&
+                (SCREENEYE == NULL) && (locplayerstate->weapon != wp_dog)
+           )
+#else
+        if ((ob->flags & FL_EYEBALL) && (dx < 0x20000) && (dy < 0x20000) &&
+                (dz < 64) && (GameRandomNumber("eye chance",0) < 15) &&
+                (SCREENEYE == NULL)
+           )
+#endif
+            SpawnScreenEye(ob);
+    }
+
+//MoveActor(ob);
+//if ((!ob->momentumx) && (!ob->momentumy))
+    //goto done;
+
+
+}
+
+
+
+void DropItemInEmptyTile(int item,int tilex,int tiley)
+{
+    int stilex = tilex;
+    int stiley = tiley;
+
+    FindEmptyTile(&stilex,&stiley);
+    SpawnStatic(stilex,stiley,item,9);
+    LASTSTAT->flags |= FL_ABP;
+    MakeStatActive(LASTSTAT);
+
+}
+
+extern boolean enableExtraPistolDrops;
+
+void KillActor(objtype*ob)
+{   int ocl;
+
+    ocl = ob->obclass;
+
+
+//GivePoints(starthitpoints[gamestate.difficulty][ob->obclass]*5);
+    if ((ocl == highguardobj) &&
+            (GameRandomNumber("Drop mp40 chance",0) < 25))
+    {
+        DropItemInEmptyTile(stat_mp40,ob->tilex,ob->tiley);
+    }
+
+    else if ((ocl == blitzguardobj) && (ob->temp3))
+    {
+        DropItemInEmptyTile(ob->temp3,ob->tilex,ob->tiley);
+        LASTSTAT->ammo = ob->temp2;
+    }
+    else if ((ocl >= lowguardobj && ocl != highguardobj && ocl <= blitzguardobj) &&
+            (GameRandomNumber("Drop extra pistol chance", 0) < 25) && enableExtraPistolDrops)
+    {
+        DropItemInEmptyTile(stat_twopistol, ob->tilex, ob->tiley);
+    }
+    
+
+    if (actorat[ob->tilex][ob->tiley] == (void*)ob)
+        actorat[ob->tilex][ob->tiley] = NULL;
+
+    gamestate.killcount++;
+    ob->flags &= ~FL_SHOOTABLE;
+    ob->flags &= ~FL_BLOCK;
+    ob->flags |= FL_NEVERMARK;
+#if (SHAREWARE == 0)
+    if (ocl == b_darksnakeobj)
+    {   if (ob == SNAKEHEAD)
+        {   SpawnNewObj(ob->tilex,ob->tiley,&s_megaexplosions,inertobj);
+            new->temp1 = 7000;
+            new->flags |= FL_ABP;
+            EXPLOSIONS = new;
+            NewState(ob,&s_darkmonkheaddie1);
+            MakeActive(new);
+            ob->dirchoosetime = 0;
+
+        }
+        else
+        {   objtype *temp;
+
+            SNAKEEND = (objtype*)(ob->target);
+            SNAKEEND->whatever = NULL;
+            NewState(ob,&s_explosion1);
+            for(temp=SNAKEHEAD; temp; temp = (objtype*)(temp->whatever))
+                temp->speed += 0x500;
+        }
+    }
+    else
+#endif
+    {   ob->whatever = NULL;
+        if (ob->obclass!=playerobj)
+            ob->target   = NULL;
+    }
+
+    if ((ob->flags & FL_KEYACTOR) && (ocl!=playerobj) && (ocl != blitzguardobj))
+    {   MISCVARS->KEYACTORSLEFT --;
+        if (!MISCVARS->KEYACTORSLEFT)
+        {   SpawnNewObj(ob->tilex,ob->tiley,&s_timekeeper,inertobj);
+            new->flags |= FL_ABP;
+            MakeActive(new);
+        }
+    }
+
+}
+
+
+void T_End(objtype *ob)
+{
+    if (ob->ticcount)
+        return;
+
+    if (MAPSPOT(0,5,2) == LASTLEVELVALUE)
+        playstate = ex_gameover;
+    else
+        playstate = ex_bossdied;
+
+}
+
+
+
+void T_Convert(objtype*ob)
+{
+    if (ob->ticcount)
+        return;
+
+    if (ob->obclass == playerobj)
+    {
+        if (ob->state == &s_vaporized8)
+        {
+            T_SpawnSoul(ob);
+            NewState(ob,&s_voidwait);
+        }
+        else if (ob->state == &s_skeleton48)
+        {
+            playertype *pstate;
+
+            M_LINKSTATE(ob,pstate);
+            if ((pstate->falling == true) ||
+                    (!ob->momentumz)
+               )
+                NewState(ob,&s_ashwait);
+            else
+                CheckPlayerSpecials(ob);
+
+
+        }
+    }
+    else
+    {
+        if (ob->state == &s_vaporized8)
+            T_SpawnSoul(ob);
+        else if (ob->state == &s_skeleton48)
+            TurnActorIntoSprite(ob);
+    }
+}
+
+void TurnActorIntoSprite(objtype *ob)
+{   statobj_t*temp;
+    objtype *tactor;
+
+
+    if (!firstemptystat)
+        temp = (statobj_t*)Z_LevelMalloc(sizeof(statobj_t),PU_LEVELSTRUCT,NULL);
+
+    else
+    {   temp = lastemptystat;
+        //SoftError("\nfree actor available");
+        RemoveFromFreeStaticList(lastemptystat);
+    }
+
+
+    if (temp)
+    {
+        if ((ob->obclass == blitzguardobj) &&
+                ((ob->flags & FL_PLEADING) || (ob->flags & FL_UNDEAD))
+           )
+            MISCVARS->NUMBEGGINGKEVINS = 0;
+
+
+        if (ob->obclass == roboguardobj)
+        {   for(tactor=firstareaactor[ob->areanumber]; tactor; tactor=tactor->nextinarea)
+            {   if (tactor == ob)
+                    continue;
+                if (tactor->obclass != ob->obclass)
+                    continue;
+
+                if (tactor->flags & FL_DYING)
+                    continue;
+                if (!tactor->state->think)
+                    NewState(tactor,UPDATE_STATES[PATH][tactor->obclass-lowguardobj]);
+
+            }
+        }
+
+        memset(temp,0,sizeof(*temp));
+        temp->shapenum = ob->shapenum;
+        temp->linked_to = -1;
+        temp->whichstat = statcount ++;
+        SetFinePosition(temp,ob->x,ob->y);
+        temp->areanumber = MAPSPOT(temp->tilex,temp->tiley,0)-AREATILE;
+//	if ((temp->areanumbers<=0) || (temp->areanumber>NUMAREAS))
+        //		  Error ("Sprite at x=%ld y=%ld type=%ld has an illegal areanumber\n",tilex,tiley,mtype);
+
+        temp->visspot = &spotvis[temp->tilex][temp->tiley];
+        temp->which = SPRITE;
+        temp->itemnumber = -1;
+        temp->flags = FL_DEADBODY;
+        if (ob->flags & FL_COLORED)
+        {   playertype *pstate;
+
+            M_LINKSTATE(ob,pstate);
+            temp->flags |= FL_COLORED;
+            temp->hitpoints = pstate->uniformcolor;
+        }
+        temp->z = ob->z;
+        AddStatic(temp);
+//	sprites[temp->tilex][temp->tiley] = temp;
+
+        if (areabyplayer[temp->areanumber])
+        {   temp->flags |= FL_ABP;
+            MakeStatActive(temp);
+        }
+        if (ob->state != &s_guts12)
+            actorat[ob->tilex][ob->tiley] = temp;
+        ob->state = NULL; // say goodbye actor
+    }
+    else
+        Error("Z_LevelMalloc failed in TurnActorIntoSprite!");
+
+}
+
+
+void T_Blood(objtype*ob)
+{
+    if (ob->dirchoosetime)
+    {   ob->dirchoosetime --;
+        return;
+    }
+
+    ob->dirchoosetime = 35 + (GameRandomNumber("blood time",0) % 20);
+    NewState(ob,&s_deadblood1);
+
+}
+
+
+
+
+void ActorDeath(objtype*ob)
+{
+#if (SHAREWARE == 0)
+    if (ob->obclass == b_heinrichobj)
+    {
+        KillActor(ob);
+        ob->temp1 = ob->dirchoosetime = 5;//10; // init. spin counter for heinrich
+        ob->temp3 = 7; //number of times to stay at fast spin
+        ob->temp2 = ob->dir; //temp2 holds orig. dir.
+    }
+
+    else if (ob->obclass == b_robobossobj)
+    {
+        objtype *wheels,*head;
+
+
+        head = (objtype*)(ob->whatever);
+        wheels = (objtype*)(ob->target);
+        head->flags &= ~(FL_HEAD|FL_SHOOTABLE|FL_BLOCK);
+        head->temp2 = 5;
+        head->flags |= (FL_NOFRICTION|FL_CRAZY);
+//      head->obclass = inertobj;
+        //RemoveObj(wheels);   // remove wheels
+        KillActor(ob);
+        ob->whatever = head;
+        ob->target = wheels;
+        //ob->temp1 = 25;
+        //ob->shapeoffset = 0;
+        SpawnNewObj(ob->tilex,ob->tiley,&s_megaexplosions,inertobj);
+        new->temp1 = 18;
+        new->flags |= FL_ABP;
+        MakeActive(new);
+        //ob->state = NULL;
+        NewState(ob,&s_NMEdeathbuildup);
+    }
+    else
+#endif
+        if ((ob->state == ob->state->next) &&
+                (ob->flags & FL_DYING)
+           )
+        {
+            KillActor(ob);
+            TurnActorIntoSprite(ob);
+            if (LASTSTAT->z < nominalheight)
+            {
+                if ((!IsPlatform(LASTSTAT->tilex,LASTSTAT->tiley)) &&
+                        (DiskAt(LASTSTAT->tilex,LASTSTAT->tiley) == NULL)
+                   )
+                {
+                    SpawnParticles(ob,GUTS,10 + gamestate.difficulty);
+                    RemoveStatic(LASTSTAT);
+                }
+            }
+            /*
+            else if ((GameRandomNumber("blood spray",0) < 300) && areabyplayer[ob->areanumber])
+               {ob->shapeoffset = 0;
+               ob->temp2 = ob->temp3 = 0;
+               ob->temp1 = 10;
+               NewState(ob,&s_deadblood1);
+               return;
+               }
+               */
+        }
+}
+
+
+
+
+void BeginPostPainAction(objtype *ob)
+{
+
+    if ((ob->obclass == strikeguardobj) &&
+            (ob->target == (void*)PLAYER[0])
+       )
+    {   //ob->target = NULL;
+        if (LOW_VIOLENCE_DEATH_IS_SET(ob))
+            RESET_DEATH_SHAPEOFFSET(ob);
+
+        if (GameRandomNumber("T_Collide",0) < 128)
+            NewState(ob,&s_strikerollright1);
+        else
+            NewState(ob,&s_strikerollleft1);
+
+        SelectRollDir(ob);
+
+        if (ob->dirchoosetime)
+        {
+            SD_PlaySoundRTP(SD_STRIKEROLLSND,ob->x,ob->y);
+            return;
+        }
+
+    }
+
+    if (LOW_VIOLENCE_PAIN_IS_SET(ob))
+        RESET_PAIN_SHAPEOFFSET(ob);
+
+    if (ob->obclass < roboguardobj)
+        ob->flags &= ~FL_NOFRICTION;
+
+    if (
+        (ob->obclass == blitzguardobj) &&
+        (gamestate.violence == vl_excessive) &&
+        (GameRandomNumber("blitzplead",0) < 128) &&
+        (MISCVARS->NUMBEGGINGKEVINS == 0) &&
+        (ob->flags & FL_TARGET) &&
+
+        (ob->hitpoints < (starthitpoints[gamestate.difficulty][ob->obclass] >> 1)) &&
+        (ob->momentumz == 0) &&
+        (!(ob->flags & FL_UNDEAD))
+    )
+
+    {
+        NewState(ob,&s_blitzplead1);
+        MISCVARS->NUMBEGGINGKEVINS = 1;
+        ob->momentumx = ob->momentumy = 0;
+        ob->flags |= FL_PLEADING;
+        ob->flags &= ~FL_TARGET;
+        ob->dirchoosetime = 165;
+        ob->hitpoints = 1;
+    }
+
+    else
+    {
+        NewState(ob,M_S(CHASE));
+        ob->targettilex = ob->targettiley = 0;
+        ob->dirchoosetime = 0;
+    }
+
+}
+
+
+
+void T_Collide(objtype*ob)
+{
+    if (!(ob->flags & FL_SHOOTABLE))
+        return;
+
+    ActorMovement(ob);
+
+    if (ob->state == NULL)
+        return;
+
+    if (ob->ticcount)
+        return;
+
+    if (ob->hitpoints <= 0)
+    {
+
+        if ((ob->soundhandle == -1) &&
+                (!ob->ticcount) &&
+                (ob->state->next->tictime == 0)
+           )
+        {
+            ob->soundhandle = SD_PlaySoundRTP(ACTORTHUDSND,ob->x,ob->y);
+
+        }
+
+        if (ob->momentumx || ob->momentumy || ob->momentumz)
+            return;
+
+        ActorDeath(ob);
+        return;
+    }
+
+    BeginPostPainAction(ob);
+
+}
+
+
+
+/*
+=========================================================================
+=
+=                Special Blitzguard Functions
+=
+=========================================================================
+*/
+
+
+/*
+=================
+=
+=   T_Plead
+=
+=================
+*/
+
+
+
+void T_Plead(objtype*ob)
+{
+    int handle;
+
+    ActorMovement(ob);
+    if (ob->dirchoosetime)
+    {
+        if (!(ob->dirchoosetime & 31))
+        {
+            int random = GameRandomNumber("blitz plead sound",0);
+            if (random < 80)
+                SD_PlaySoundRTP(SD_BLITZPLEADSND,ob->x,ob->y);
+            else if (random < 160)
+                SD_PlaySoundRTP(SD_BLITZPLEAD1SND,ob->x,ob->y);
+            else
+                SD_PlaySoundRTP(SD_BLITZPLEAD2SND,ob->x,ob->y);
+        }
+        ob->dirchoosetime --;
+        return;
+    }
+    ob->hitpoints = (starthitpoints[gamestate.difficulty][blitzguardobj]>>1);
+//ob->flags |= FL_DYING;
+    ob->flags |= FL_UNDEAD;
+    SET_DEATH_SHAPEOFFSET(ob);
+    NewState(ob,&s_blitzfakedie1);
+    ob->flags &= ~FL_PLEADING;
+    ob->dirchoosetime = (GameRandomNumber("blitz fake time",0) >> 2) + 70;
+    handle = SD_PlaySoundRTP(SD_BLITZOUCHSND,ob->x,ob->y);
+    SD_SetSoundPitch (handle,-500);
+    ob->temp1 = 0;
+    ob->temp1 = (GameRandomNumber("blitz visible rise",0) < 60);
+
+}
+
+
+
+/*
+=================
+=
+=   T_ReallyDead
+=
+=================
+*/
+
+
+void T_ReallyDead(objtype *ob)
+{
+    ActorMovement(ob);
+    if ((!ob->ticcount) && (LOW_VIOLENCE_DEATH_SHOULD_BE_SET(ob)))
+        SET_DEATH_SHAPEOFFSET(ob);
+
+
+}
+
+
+
+/*
+=================
+=
+=   T_PlayDead
+=
+=================
+*/
+
+
+
+void T_PlayDead(objtype *ob)
+{
+    int dangle;
+
+    ob->flags &= ~FL_DYING;
+
+    ActorMovement(ob);
+    if (ob->dirchoosetime)
+    {
+        ob->dirchoosetime--;
+        return;
+    }
+
+    dangle = abs(player->angle - AngleBetween(player,ob));
+    if (dangle > ANGLES/2)
+        dangle = ANGLES - dangle;
+
+    if (ob->temp1 || (dangle > ANGLES/4))
+    {
+        if (LOW_VIOLENCE_DEATH_IS_SET(ob))
+            RESET_DEATH_SHAPEOFFSET(ob);
+        ob->temp1 = 0;
+
+        NewState(ob,&s_blitzrise2);
+
+    }
+
+}
+
+
+void AdjustAngle(int maxadjust, short int *currangle,int targetangle)
+{
+    int dangle,i,magangle;
+
+    for(i=0; i<maxadjust; i++)
+    {
+        dangle = *currangle - targetangle;
+
+        if (dangle)
+        {
+            magangle = abs(dangle);
+            if (magangle > (ANGLES/2))
+            {
+                if (dangle > 0)
+                    (*currangle) ++;
+                else
+                    (*currangle) --;
+            }
+            else
+            {
+                if (dangle > 0)
+                    (*currangle) --;
+                else
+                    (*currangle) ++;
+            }
+            Fix(*currangle);
+        }
+    }
+}
+
+
+void ResolveMinimumDistance(objtype *heatseeker, objtype *potential_target,
+                            int *currmin)
+{
+    int currdist,angle,magangle;
+
+
+    currdist = FindDistance((heatseeker->x-potential_target->x),
+                            (heatseeker->y-potential_target->y));
+    angle = AngleBetween(heatseeker,potential_target);
+
+
+    if (heatseeker->obclass != p_godballobj)
+    {
+        magangle = abs(heatseeker->angle - angle);
+        if (magangle > VANG180)
+            magangle = ANGLES - magangle;
+        if (magangle > ANGLESDIV8)
+            return;
+    }
+
+    if (currdist > LOOKAHEAD)
+        return;
+
+    if (currdist < (*currmin))
+    {
+        *currmin = currdist;
+        heatseeker->target = potential_target;
+    }
+}
+
+
+
+
+void HeatSeek(objtype*ob)
+{   int        xydist;
+
+    int        mindist;
+    objtype*   tactor;
+    objtype*   owner;
+    statobj_t* tstat;
+    int        angle,dz,yzangle,adjust;
+    int        dx,dy;
+
+
+    owner=(objtype *)ob->whatever;
+
+    if (ob->dirchoosetime)
+        ob->dirchoosetime --;
+
+    else
+    {
+        if (!ob->target)
+        {   mindist = 0x7fffffff;
+
+            for (tactor=firstactive; tactor; tactor=tactor->nextactive)
+            {
+                if (tactor == owner)
+                    continue;
+
+                if (tactor->flags & FL_HEAD)
+                    continue;
+
+                if ((tactor == ob) ||
+                        (!(tactor->flags & FL_SHOOTABLE)) ||
+                        (tactor->flags & FL_DYING))
+                    continue;
+
+                if (!CheckLine(ob,tactor,SIGHT))
+                    continue;
+
+                if ((tactor->obclass == bladeobj) || (tactor->obclass == NMEsaucerobj))
+                    continue;
+
+
+                ResolveMinimumDistance(ob,tactor,&mindist);
+
+            }
+
+            if (ob->obclass != p_godballobj)
+            {
+                for(tstat=firstactivestat; tstat; tstat=tstat->nextactive)
+                {
+                    if (!(tstat->flags & FL_HEAT))
+                        continue;
+
+                    if (!CheckLine(ob,tstat,SHOOT))
+                        continue;
+
+                    ResolveMinimumDistance(ob,(objtype*)tstat,&mindist);
+                }
+            }
+
+
+            if (!ob->target)
+                ob->dirchoosetime = 5;
+        }
+
+        else //if (ob->target != owner)
+        {
+            tactor = (objtype*)ob->target;
+
+            if ((!tactor->nextactive) && (!tactor->prevactive))
+            {
+                ob->target = NULL;
+                return;
+            }
+            dx = tactor->x - ob->x;
+            dy = ob->y - tactor->y;
+            dz = ob->z - tactor->z;
+            //xydist = FixedSqrtHP((FixedMul(dx,dx) + FixedMul(dy,dy))>>16);
+            xydist = FindDistance(dx,dy);
+            angle = atan2_appx(dx,dy);
+            adjust = (ob->obclass == p_godballobj)?(GODHAPT):(HAAPT);
+            AdjustAngle(adjust,&(ob->angle),angle);
+            ob->dir = angletodir[ob->angle];
+            ob->momentumx = FixedMul(ob->speed,costable[ob->angle]);
+            ob->momentumy = -FixedMul(ob->speed,sintable[ob->angle]);
+
+            yzangle = atan2_appx(xydist,(dz<<10));
+            adjust = (ob->obclass == p_godballobj)?(GODVAPT):(VAAPT);
+            AdjustAngle(adjust,&(ob->yzangle),yzangle);
+            ob->momentumz = -(FixedMul(ob->speed,sintable[ob->yzangle]));
+
+        }
+    }
+
+}
+
+
+void Stagger(objtype*ob)
+{
+    int randadj;
+
+
+    randadj = (int)(GameRandomNumber("Stagger",1) >> 3);
+
+    if (!ob->dirchoosetime)
+    {
+        ob->momentumz = ob->temp1 + (RandomSign() << 12);
+        ob->dirchoosetime = 6;
+    }
+    else
+        ob->dirchoosetime --;
+
+    if ((ob->z + (ob->momentumz >> 10)) > (maxheight-12))
+        ob->momentumz = -ob->momentumz;
+    else if ((ob->z < 5) && (!sky))
+        ob->z = 5;
+
+    ob->angle += (RandomSign()*randadj);
+    Fix(ob->angle);
+    ob->momentumx = FixedMul(ob->speed,costable[ob->angle]);
+    ob->momentumy = -FixedMul(ob->speed,sintable[ob->angle]);
+    ob->dir = angletodir[ob->angle];
+
+}
+
+
+
+
+void SpawnSplit(objtype *ob,int angle)
+{
+    Fix(angle);
+    SpawnMissile(ob,p_heatseekobj,ob->speed,angle,&s_p_bazooka1,0x4000);
+    new->momentumz = ob->momentumz;
+    new->whatever = ob->whatever;
+
+}
+
+
+
+void SplitMissile(objtype*ob)
+{
+
+    SD_PlaySoundRTP(SD_SPLITSND,ob->x,ob->y);
+    if (ob->soundhandle != -1)
+        SD_StopSound(ob->soundhandle);
+
+    SpawnSplit(ob,ob->angle + ANGLES/12);
+    SpawnSplit(ob,ob->angle - ANGLES/12);
+
+    if (missobj == ob)
+    {
+        if (GameRandomNumber("split misscam",0)<128)
+            missobj = LASTACTOR;
+        else
+            missobj = LASTACTOR->prev;
+    }
+
+    ob->state=NULL; // get rid of current missile
+
+}
+
+
+
+
+void SpawnMissileSmoke(objtype *ob)
+{
+    if (!ValidAreanumber(AREANUMBER(ob->tilex,ob->tiley)))
+        return;
+
+    SpawnStatic(ob->tilex,ob->tiley,stat_missmoke,-1);
+    LASTSTAT->flags |= FL_ABP;
+    MakeStatActive(LASTSTAT);
+    SetFinePosition(LASTSTAT,ob->x,ob->y);
+    LASTSTAT->z = ob->z+3;
+
+}
+
+
+void T_Projectile (objtype *ob)
+{
+    objtype *owner;
+    playertype * pstate;
+
+    owner = (objtype*)(ob->whatever);
+
+    if (owner->obclass == playerobj)
+        M_LINKSTATE(owner,pstate);
+
+    if ((ob->soundhandle != -1) &&
+            (!(oldpolltime & 7))
+       )
+        SD_PanRTP(ob->soundhandle,ob->x,ob->y);
+#if (SHAREWARE == 0)
+    if (ob->obclass == h_mineobj)
+    {
+        if (!ob->dirchoosetime)
+        {
+            NewState(ob,&s_grexplosion1);
+            SD_PlaySoundRTP(SD_KRISTMINEHITSND,ob->x,ob->y);
+        }
+        else
+            ob->dirchoosetime --;
+        if (
+            (ob->state == &s_mine1) &&
+            (!ob->ticcount)
+        )
+            SD_PlaySoundRTP(BAS[ob->obclass].operate,ob->x,ob->y);
+
+    }
+#endif
+
+
+    if (!ob->ticcount)
+    {
+        if (ob->state == &s_p_grenade)
+            ob->momentumz += (GRAVITY>>6);
+        else if
+        (ob->state == &s_grenade_fall6)
+        {
+            NewState(ob,&s_explosion1);
+            return;
+        }
+    }
+
+
+
+
+    if (ob->obclass == p_drunkmissileobj)
+    {
+        if (ob->temp3 > 0)
+        {
+            ob->temp3 --;
+            Stagger(ob);
+        }
+        else
+        {
+            if (ob->target == NULL)
+                Stagger(ob);
+            HeatSeek(ob);
+        }
+
+    }
+
+    else if (ob->temp1 == NME_DRUNKTYPE)
+
+        Stagger(ob);
+
+
+    else if ((ob->obclass == p_heatseekobj) ||
+             (ob->obclass == dm_heatseekobj) ||
+             (ob->temp1 == NME_HEATSEEKINGTYPE) ||
+             (ob->obclass == p_godballobj)
+            )
+        HeatSeek(ob);
+
+
+    else if
+    ((ob->obclass == p_splitmissileobj) &&
+            (!pstate->buttonstate[bt_attack])
+    )
+    {
+        SplitMissile(ob);
+        return;
+    }
+
+
+
+
+    if ((!BATTLEMODE) &&
+            (!(ob->ticcount & 7)) &&
+            (ob->obclass != p_firewallobj) &&
+            (ob->obclass != p_kesobj) &&
+            (ob->obclass != p_godballobj) &&
+            ((ob->obclass >= p_bazookaobj) ||  (ob->obclass == missileobj))
+       )// &&
+
+        SpawnMissileSmoke(ob);
+
+    MissileMovement(ob);
+
+    if (ob->obclass == grenadeobj)
+
+    {
+        if (ob->temp1 > 0)
+            ob->temp1 -= ob->speed;
+        else if (!(ob->flags & FL_DONE))
+        {
+            NewState(ob,&s_grenade_fall1);
+            ob->flags |= FL_DONE;
+        }
+    }
+}
+
+
+
+void StartFirewall(objtype*ob, int newz)
+{
+    objtype *owner = (objtype*)(ob->whatever);
+
+    MISCVARS->firespawned = 0;
+    owner->temp1 = 0;
+    SpawnFirewall(ob,2,newz);
+    if (missobj == ob)
+        missobj = LASTACTOR;
+    NewState(ob,&s_megaremove);
+
+}
+
+
+
+void MissileMovement(objtype*ob)
+{   int tryx, tryy,tryz;
+
+    tryx = ob->x + ob->momentumx;
+    tryy = ob->y + ob->momentumy;
+    tryz = ob->z + (ob->momentumz >> 10);
+    if (!MissileTryMove (ob, tryx, tryy, tryz))
+        return;
+    ob->z += (ob->momentumz >> 10);
+    MoveActor(ob);
+}
+
+
+
+#define DetonateMissile(x,y) \
+{MissileHit(x,y);             \
+ return false;                 \
+}                                \
+
+#define QuietDetonate(ob)            \
+   {                                 \
+   if (ob->soundhandle != -1)        \
+      SD_StopSound(ob->soundhandle); \
+   if (ob == missobj)                \
+      missobj = NULL;                \
+   NewState(ob,&s_megaremove);       \
+   return false;                     \
+   }
+
+extern boolean ricochetingRocketsEnabled = 0;
+
+boolean MissileTryMove(objtype*ob,int tryx,int tryy,int tryz)
+{
+    int             tilexlow,tileylow,tilexhigh,tileyhigh,x,y,
+                    trytilex,trytiley,dx,dy,dzt,dztp1,radius,
+                    sprrad,actrad,tcl,ocl,oldsrad,area,zdist,
+                    wall;
+
+    objtype         *temp;
+    wall_t          *tempwall;
+    doorobj_t       *tempdoor;
+    int             doorn;
+    statobj_t       *tempstat;
+    boolean         areatried[NUMAREAS] = {0};
+
+    sprrad = 0x4500;
+    actrad = ACTORSIZE+0x2800;
+    ocl = ob->obclass;
+    radius = PROJSIZE-0x2200;
+    if (ocl==wallfireobj)
+        radius-=0x3000;
+    trytilex = (tryx >> TILESHIFT);
+    trytiley = (tryy >> TILESHIFT);
+
+
+    if (IsWindow(trytilex,trytiley) || (!InMapBounds((tryx>>16),(tryy>>16))))
+    {
+        QuietDetonate(ob);
+    }
+
+
+
+    /*
+    */
+//==== ceiling/floor clipping =================//
+
+    if (tryz < -30)
+    {   if ((sky==0) || (ocl == inertobj))
+        {
+            DetonateMissile(ob,NULL);
+        }
+        /*
+        else
+           return true;
+           */
+        /*
+        else
+           {
+           NewState(ob,&s_megaremove);
+           if (missobj == ob)
+              missobj = NULL;
+
+           return false;
+           }
+         */
+    }
+
+
+    if (tryz > (maxheight-10))
+    {
+        if ((ocl == p_firewallobj) && (!(ob->flags & FL_ISFIRE)))
+            StartFirewall(ob,nominalheight);
+        else
+            MissileHit(ob,NULL);
+        return false;
+    }
+
+//=============================================//
+
+    sprrad = PROJSIZE+0x1000;
+
+
+    tilexlow = (int)((tryx-radius) >>TILESHIFT);
+    tileylow = (int)((tryy-radius) >>TILESHIFT);
+
+    tilexhigh = (int)((tryx+radius) >>TILESHIFT);
+    tileyhigh = (int)((tryy+radius) >>TILESHIFT);
+
+    oldsrad = sprrad;
+
+
+    if (ocl == inertobj)
+        goto walls;
+
+    area = ob->areanumber;
+    areatried[area] = true;
+actors:
+    for(temp=firstareaactor[area]; temp; temp=temp->nextinarea)
+    {
+        if (temp == ob)
+            continue;
+
+        dx = abs(tryx - temp->x);
+        dy = abs(tryy - temp->y);
+        if ((dx > actrad) || (dy > actrad))
+            continue;
+
+        if (temp->flags & FL_HEAD)
+            continue;
+
+        if ((!(temp->flags & FL_BLOCK)) || (temp->flags & FL_DYING))
+            continue;
+
+        tcl = temp->obclass;
+
+
+        zdist = 32;
+        dzt = abs(tryz - temp->z);
+
+        if ((tcl == playerobj) && (temp->flags & FL_DOGMODE))
+        {
+            dzt = abs(tryz - (temp->z + 30));
+            zdist = 10;
+        }
+        else if (tcl == diskobj)
+        {
+            zdist = 50;
+        }
+
+        if (dzt > zdist)
+            continue;
+
+
+
+        //if ((ocl==wallfireobj) && (tcl==playerobj) && (temp->flags&FL_DOGMODE) && (dz>15))
+        // continue;
+
+        //if ((ocl==playerobj) &&
+        //  (ob->whatever == (void*)temp))
+        //continue;
+
+        if (ob->whatever && (ob->whatever == temp->whatever))// &&
+            //      (ocl == tcl))// missiles with same owner
+            // go through each other
+            continue;
+
+        if (!(ob->flags & FL_ISFIRE))
+        {
+
+            int random;
+
+            if (tcl != b_darkmonkobj)
+            {
+                MissileHit(ob,temp);
+                ob->target = NULL;
+                if (tcl == wallfireobj)
+                    MissileHit(temp,NULL);
+                if (((ocl == p_kesobj) || (ocl == p_godballobj)) && (tcl < pillarobj))
+                    continue;
+                else
+                    return false;
+            }
+            random = GameRandomNumber("empower darkmonk",0);
+#if (SHAREWARE == 0)
+
+            if (ocl == p_kesobj)
+            {
+                NewState(ob,&s_megaremove);
+                //ob->state = NULL;
+                temp->hitpoints += (((random>>3)+140)<<1);
+                CAP_OSCUROS_HITPOINTS(temp);
+            }
+            else if (ocl == p_firebombobj)
+            {
+                NewState(ob,&s_explosion1);
+                temp->hitpoints += (((random>>3)+70)<<1);
+                CAP_OSCUROS_HITPOINTS(temp);
+
+                ob->target = NULL;
+            }
+            else
+            {
+                NewState(ob,&s_explosion1);
+                temp->hitpoints += (((random>>3)+50)<<1);
+                CAP_OSCUROS_HITPOINTS(temp);
+
+                ob->target = NULL;
+            }
+            temp->temp3 = ocl;
+            temp->speed = 5*SPDPATROL;
+            NewState(temp,&s_darkmonkreact);
+#endif
+            return false;
+        }
+
+        else if (tcl < roboguardobj)
+        {   if ((temp->z == nominalheight) &&
+                    (!((tcl == playerobj) && ((temp->flags & FL_GODMODE) || (temp->flags & FL_DOGMODE) || godmode))))
+            {
+                if (tcl == playerobj)
+                {
+                    playertype *pstate;
+                    objtype *owner = (objtype*)(ob->whatever);
+
+                    M_LINKSTATE(temp,pstate);
+                    if (temp->flags & FL_AV)
+                    {   pstate->protectiontime = 1;
+                        if (temp==player)
+                            GM_UpdateBonus (pstate->protectiontime, false);
+                        continue;
+                    }
+
+
+                    //temp->flags &= ~FL_COLORED;
+                    pstate->health = 0;
+                    pstate->weapon = -1;
+                    if (owner->obclass == playerobj)
+                        BATTLE_PlayerKilledPlayer(battle_kill_with_missile,owner->dirchoosetime,temp->dirchoosetime);
+
+
+                }
+
+
+                temp->flags |= FL_SKELETON;
+                temp->hitpoints = 0;
+                Collision(temp,ob->whatever,-temp->momentumx,-temp->momentumy);
+            }
+            continue;
+        }
+
+
+
+        else
+        {
+            NewState(ob,&s_megaremove);
+            ob->target = NULL;
+#if (SHAREWARE == 0)
+            if (tcl == b_darkmonkobj)
+                NewState(temp,&s_darkmonkfspark1);
+#endif
+        }
+
+        return false;
+
+    }
+
+
+    for (y=tileylow; y<=tileyhigh; y++)
+        for (x=tilexlow; x<=tilexhigh; x++)
+        {
+            area = AREANUMBER(x,y);
+            if (ValidAreanumber(area) && (areatried[area]==false))
+            {
+                areatried[area] = true;
+                goto actors;
+            }
+        }
+
+
+    /******************* WALLS/PWALLS *****************************************/
+
+walls:
+
+    for (y=tileylow; y<=tileyhigh; y++)
+        for (x=tilexlow; x<=tilexhigh; x++)
+        {
+
+
+            tempwall = (wall_t*)actorat[x][y];
+            wall=tilemap[x][y];
+
+            if (tempwall && M_ISWALL(tempwall) && (tempwall->which!=MWALL))
+            {   if (ocl == h_mineobj)
+                {
+                    if (WallCheck(ob->x-ob->momentumx, tryy))
+                    {   ob->momentumx = -ob->momentumx;
+                        continue;
+                    }
+                    else if (WallCheck(tryx, ob->y-ob->momentumy))
+                    {   ob->momentumy = -ob->momentumy;
+                        continue;
+                    }
+                }
+                //richocheting rockets stuff
+                if ((ocl == p_bazookaobj ||
+                        ocl == p_firebombobj ||
+                        ocl == p_heatseekobj ||
+                        ocl == p_drunkmissileobj ||
+                        ocl == p_firewallobj ||
+                        ocl == p_splitmissileobj ||
+                        ocl == p_kesobj) && ricochetingRocketsEnabled)
+                {
+                    if (WallCheck(ob->x-ob->momentumx, tryy))
+                    {
+                        ob->momentumx = -ob->momentumx;
+                        int rand;
+
+                        rand = RandomNumber("Spawn Ricochet Sound in SpawnGunSmoke",0);
+                        if (rand < 80)
+                            SD_PlaySoundRTP(SD_RICOCHET1SND,ob->x,ob->y);
+                        else if (rand < 160)
+                            SD_PlaySoundRTP(SD_RICOCHET2SND,ob->x,ob->y);
+                        else
+                            SD_PlaySoundRTP(SD_RICOCHET3SND,ob->x,ob->y);
+                        continue;
+                    }
+                    else if (WallCheck(tryx, ob->y-ob->momentumy))
+                    {
+                        ob->momentumy = -ob->momentumy;
+                        int rand;
+
+                        rand = RandomNumber("Spawn Ricochet Sound in SpawnGunSmoke",0);
+                        if (rand < 80)
+                            SD_PlaySoundRTP(SD_RICOCHET1SND,ob->x,ob->y);
+                        else if (rand < 160)
+                            SD_PlaySoundRTP(SD_RICOCHET2SND,ob->x,ob->y);
+                        else
+                            SD_PlaySoundRTP(SD_RICOCHET3SND,ob->x,ob->y);
+                        
+                        continue;
+                    }
+                    else
+                    {
+                        DetonateMissile(ob,tempwall);
+                    }
+                }
+                else {
+                    DetonateMissile(ob,tempwall);
+                }
+                //MissileHit(ob,tempwall);
+                //return false;
+            }
+
+
+            tempstat = sprites[x][y];
+            sprrad = oldsrad;
+
+            if (tempstat &&
+                    ((tempstat->flags & FL_SHOOTABLE) || (tempstat->flags & FL_BLOCK)))
+            {
+
+                if ((tempstat->itemnumber >= stat_bcolumn) &&
+                        (tempstat->itemnumber <= stat_icolumn))
+                    sprrad += 0x5000;
+
+                dx = tryx - tempstat->x;
+                if ((dx < -sprrad) || (dx > sprrad))
+                    continue;
+
+                dy = tryy - tempstat->y;
+                if ((dy < -sprrad) || (dy > sprrad))
+                    continue;
+
+//#define MINSTATZDIFF 60
+
+                dzt = abs(ob->z - tempstat->z);
+                dztp1 = abs(tryz - tempstat->z);
+                /*
+                  if (ocl == p_firewallobj)// && (dztp1 <= MINSTATZDIFF))
+                     {
+                     if (ob->flags & FL_ISFIRE)
+                        {
+                        int cz = (ob->z - tempstat->z + MINSTATZDIFF);
+
+                        if ((cz >= -MAXSTEPHEIGHT) && (cz <= 0))
+                           {
+                           ob->z = tempstat->z - MINSTATZDIFF;
+                           tryz = ob->z + (ob->momentumz >> 16);
+                           dzt = MINSTATZDIFF;
+                           }
+                        }
+
+                     if ((dztp1 >= MINSTATZDIFF) || (dzt >= MINSTATZDIFF))
+                        continue;
+
+                     if (!(ob->flags & FL_ISFIRE))
+                        {
+                        StartFirewall(ob,tempstat->z - MINSTATZDIFF);
+                        return false;
+                        }
+                     }
+
+
+                  else*/
+                {
+                    if (dztp1 > 50)
+                        continue;
+
+                    DetonateMissile(ob,tempstat);
+                }
+                //MissileHit(ob,tempstat);
+                //return false;
+            }
+        }
+
+
+//mwalls:
+
+
+
+    if (M_ISMWALL(trytilex,trytiley))
+    {
+        maskedwallobj_t * mw;
+
+        wall=tilemap[trytilex][trytiley];
+        //tempwall = (wall_t*)actorat[trytilex][trytiley];
+
+
+        mw=maskobjlist[wall&0x3ff];
+
+        if (!(mw->flags&MW_BLOCKING))
+        {
+
+            if ((levelheight > 1) &&
+                    (((!(mw->flags & MW_ABOVEPASSABLE)) && (tryz <= 32)) ||
+                     ((!(mw->flags & MW_MIDDLEPASSABLE)) && (tryz > 25) && (tryz < nominalheight-32)) ||
+                     ((!(mw->flags & MW_BOTTOMPASSABLE)) && (tryz > maxheight - 74))
+                    )
+               )
+                DetonateMissile(ob,NULL);
+
+        }
+
+        else if (mw->flags&MW_SHOOTABLE)
+        {
+            if (ob->z >= maxheight-64)
+            {
+                UpdateMaskedWall(tilemap[trytilex][trytiley]&0x3ff);
+            }
+            else
+                DetonateMissile(ob,NULL);
+
+        }
+
+        else
+            DetonateMissile(ob,NULL);
+        //MissileHit(ob,tempwall);
+        //return false;
+    }
+
+
+
+    /******************* DOOR STUFF ******************************************/
+
+
+    else if (M_ISDOOR(trytilex,trytiley))
+    {
+        doorn = tilemap[trytilex][trytiley];
+        tempdoor = doorobjlist[doorn&0x3ff];
+        if (tempdoor->position>=0x8000)
+        {
+            if (ob->z>maxheight-64)
+                return true;
+        }
+        DetonateMissile(ob,tempdoor);
+    }
+
+    return true;
+
+
+}
+
+
+
+void SpawnFirewall(objtype*ob,int which,int newz)
+{   int i,j,count,newx,newy;
+    objtype* owner;
+    wall_t*tempwall;
+    statetype* frame;
+    int offset;
+
+    owner = (objtype*)(ob->whatever);
+
+    if ((owner->temp1 < 2) && (MISCVARS->firespawned < 14))
+    {   for(i=0; i<=which; i++)
+        {
+            GetNewActor ();
+            MakeActive(new);
+            MISCVARS->firespawned ++;
+            new->obclass = p_firewallobj;
+            new->which = ACTOR;
+            new->areanumber = ob->areanumber;
+            MakeLastInArea(new);
+            offset = 0x6000;
+            if (!which)
+                new->temp1 = ob->temp1;
+            else if (i==1)
+                new->temp1 = ob->angle + ANGLES/4;
+            else if (i==2)
+                new->temp1 = ob->angle - ANGLES/4;
+            else
+            {
+                new->temp1 = 0;
+                offset = 0;
+                new->flags |= FL_DONE;
+            }
+
+            Fix(new->temp1);
+
+            new->speed = 0x8000;
+            new->angle = ob->angle;
+            ParseMomentum(new,new->angle);
+            newx = ob->x + FixedMul(offset,costable[new->temp1]);
+            newy = ob->y - FixedMul(offset,sintable[new->temp1]);
+            SetFinePosition(new,newx,newy);
+            SetVisiblePosition(new,newx,newy);
+            new->whatever = ob->whatever;
+            new->dirchoosetime = 2;
+            new->flags |= (FL_NEVERMARK|FL_ABP|FL_NOFRICTION);
+            count = (int)(GameRandomNumber("SpawFireWall",0) & 15);
+
+            for(frame = &s_fireunit1,j=0; j<count; frame = frame->next,j++);
+
+            NewState(new,frame);
+            new->flags |= FL_ISFIRE;
+            //SD_Play(SD_EXPL);
+            tempwall = (wall_t*)actorat[new->tilex][new->tiley];
+            new->z = newz;
+            if (tempwall && M_ISWALL(tempwall))
+            {
+                SetFinePosition(new,ob->x,ob->y);
+                SetVisiblePosition(new,ob->x,ob->y);
+                owner->temp1++;
+            }
+        }
+    }
+
+}
+
+
+void T_Firethink(objtype*ob)
+{
+
+    if (ob->dirchoosetime)
+        ob->dirchoosetime--;
+    else if (!(ob->flags & FL_DONE))
+    {
+        SpawnFirewall(ob,0,ob->z);
+        ob->flags |= FL_DONE;
+    }
+
+    MissileMovement(ob);
+
+}
+
+
+
+void ResolveRide(objtype *ob)
+{
+    objtype *ride = (objtype*)(ob->whatever);
+
+    if (M_ISACTOR(ride) && (ob->obclass != playerobj))
+    {
+        if (ob->flags & FL_RIDING)
+        {
+            int dx,dy;
+
+            dx = ob->x - ride->x;
+            dy = ob->y - ride->y;
+            if ((dx < -MINACTORDIST) || (dx > MINACTORDIST) ||
+                    (dy < -MINACTORDIST) || (dy > MINACTORDIST) )
+            {
+                ride->whatever = NULL;
+                ob->whatever = NULL;
+                ob->flags &= ~FL_RIDING;
+            }
+        }
+    }
+
+}
+
+
+
+
+void MoveActor(objtype*ob)
+{
+    int linked,oldarea,newarea,
+        tilex,tiley,oldtilex,oldtiley;
+
+    linked = 0;
+
+    ResolveRide(ob);
+
+    oldtilex = ob->tilex;
+    oldtiley = ob->tiley;
+
+    SetFinePosition(ob,ob->x+ob->momentumx,ob->y+ob->momentumy);
+    /*
+    if (ob->state == &s_explosion1)
+     Error("moving explosion"); */
+
+    if ((ob->obclass == playerobj) || (ob->flags & FL_NOFRICTION) || (ob->state->think == T_Collide) ||
+            (ob->obclass == b_heinrichobj) || (ob->obclass == h_mineobj))
+
+        SetVisiblePosition(ob,ob->x,ob->y);
+
+
+
+    if (ob->obclass == inertobj)
+        return;
+
+    if ((ob->obclass == b_darksnakeobj) && (ob != SNAKEHEAD))
+    {
+        oldarea = ob->areanumber;
+        newarea = SNAKEHEAD->areanumber;
+        if (oldarea != newarea)
+        {
+            RemoveFromArea(ob);
+            ob->areanumber = newarea;
+            MakeLastInArea(ob);
+        }
+        return;
+
+    }
+
+
+    oldarea = ob->areanumber;
+    newarea = AREANUMBER(ob->tilex,ob->tiley);
+    if (!(ob->flags & (FL_NONMARK|FL_NEVERMARK)))
+    {
+        if ((oldtilex != ob->tilex) || (oldtiley != ob->tiley))
+        {
+            if (actorat[oldtilex][oldtiley] == (void*)ob)
+                actorat[oldtilex][oldtiley] = NULL;
+            if (actorat[ob->tilex][ob->tiley])
+            {
+                objtype* temp;
+
+                temp = (objtype*)actorat[ob->tilex][ob->tiley];
+                if (temp->which != SPRITE)
+                    actorat[ob->tilex][ob->tiley] = ob;
+            }
+            else
+                actorat[ob->tilex][ob->tiley] = ob;
+        }
+    }
+
+
+#define CheckAdjacentArea(x,y)        \
+   {                                  \
+   if (InMapBounds(x,y))              \
+      {                               \
+      temparea = AREANUMBER(x,y);     \
+      if (ValidAreanumber(temparea))  \
+         newarea = temparea;          \
+      }                               \
+   }
+
+
+    if (!ValidAreanumber(newarea)) //find empty tile
+    {
+        int temparea;
+        tilex = ob->tilex;
+        tiley = ob->tiley;
+
+        CheckAdjacentArea(tilex+1,tiley);
+        CheckAdjacentArea(tilex-1,tiley);
+        CheckAdjacentArea(tilex,tiley+1);
+        CheckAdjacentArea(tilex,tiley-1);
+
+    }
+    //Error("new area invalid for actor %d, class %d",
+    //	  ob-&objlist[0],ob->obclass);
+
+
+//======================  swap in linked lists =====================
+    if (oldarea != newarea)
+    {
+        RemoveFromArea(ob);
+        ob->areanumber = newarea;
+        MakeLastInArea(ob);
+    }
+}
+
+
+
+void SpawnPushColumn(int tilex,int tiley,int which,int dir, int linked)
+{
+    if (which==0)
+    {
+        SpawnNewObj(tilex,tiley,&s_pushcolumn1,pillarobj);
+//     for (i=0;i<(levelheight-1);i++)
+//        SpawnStatic(tilex,tiley,stat_bcolumn,-(i<<6));
+    }
+    else if (which==1)
+    {
+        SpawnNewObj(tilex,tiley,&s_pushcolumn2,pillarobj);
+//     for (i=0;i<(levelheight-1);i++)
+//        SpawnStatic(tilex,tiley,stat_gcolumn,-(i<<6));
+    }
+    else
+    {
+        SpawnNewObj(tilex,tiley,&s_pushcolumn3,pillarobj);
+//     for (i=0;i<(levelheight-1);i++)
+//        SpawnStatic(tilex,tiley,stat_icolumn,-(i<<6));
+    }
+    PreCacheActor(pillarobj,which);
+
+    gamestate.secrettotal++;
+    new->speed = PILLARMOM;
+    new->temp1 = 0x20000;
+    new->temp2 = linked;
+    new->flags |= (FL_BLOCK|FL_NOFRICTION);
+    new->flags &= ~FL_SHOOTABLE;
+    new->flags |= FL_HEIGHTFLIPPABLE;
+    new->dir = dir;
+    if (dir != nodir)
+        ParseMomentum(new,dirangle8[new->dir]);
+
+
+}
+
+
+
+void SpawnWallfire(int tilex, int tiley, int dir)
+{   int offx,offy;
+
+
+    GetNewActor();
+    new->speed = 0x2000;
+    SetTilePosition(new,tilex,tiley);
+    SetVisiblePosition(new,new->x,new->y);
+    new->obclass = wallfireobj;
+    new->dir = dir*2;
+    new->flags |= (FL_BLOCK|FL_NOFRICTION|FL_NEVERMARK);
+    new->flags &= ~FL_SHOOTABLE;
+    new->which = ACTOR;
+    new->angle = dirangle8[new->dir];
+    offx = FixedMul(0x10000,costable[new->angle])>>TILESHIFT;
+    offy = -(FixedMul(0x10000,sintable[new->angle])>>TILESHIFT);
+
+    new->areanumber = MAPSPOT(new->tilex+offx,new->tiley+offy,0)-AREATILE;
+    MakeLastInArea(new);
+
+    NewState(new,&s_wallfireball);
+
+}
+
+
+
+void SpawnSneaky(int tilex,int tiley)
+{
+
+    SpawnNewObj(tilex,tiley,&s_sneakydown,lowguardobj);
+    new->temp3 = SNEAKY;
+    if (!loadedgame)
+        gamestate.killtotal++;
+    StandardEnemyInit(new,north>>1);
+
+    PreCacheActor(lowguardobj,0);
+}
+
+
+void RespawnEluder(void)
+{
+    int rand,count;
+    int nx,ny;
+
+    rand = (GameRandomNumber("eluder respawn",0) % NUMSPAWNLOCATIONS);
+
+    for(count=0; count < NUMSPAWNLOCATIONS; count++)
+    {
+        if (!actorat[SPAWNLOC[rand].x][SPAWNLOC[rand].y])
+        {
+            SpawnCollector(SPAWNLOC[rand].x,SPAWNLOC[rand].y);
+            return;
+        }
+        rand= ((rand + 1) % NUMSPAWNLOCATIONS);
+
+    }
+
+//MED
+    nx = SPAWNLOC[rand].x;
+    ny = SPAWNLOC[rand].y;
+    FindEmptyTile(&nx,&ny);
+    SpawnCollector(nx,ny);
+}
+
+//****************************************************************************
+//
+//
+//
+//****************************************************************************
+
+void SpawnCollector(int tilex, int tiley)
+{
+#if (SHAREWARE == 0)
+    if ( dopefish==true )
+    {
+        SpawnNewObj(tilex,tiley,&s_scottwander1,collectorobj);
+    }
+    else
+#endif
+    {
+        SpawnNewObj(tilex,tiley,&s_collectorwander1,collectorobj);
+    }
+
+    new->flags |= (FL_SHOOTABLE|FL_BLOCK|FL_NOFRICTION|FL_FULLLIGHT);
+    new->hitpoints = 500;
+    new->speed = 0x3000;
+    new->dir = north;
+    new->dirchoosetime = 175;
+    new->z = PlatformHeight(tilex,tiley);
+    if (new->z == -10)
+        new->z = 0;
+    if (areabyplayer[new->areanumber])
+    {   new->flags |= FL_ABP;
+        MakeActive(new);
+    }
+
+}
+
+
+
+void SelectDoorDir(objtype*ob)
+{   int dx,dy,actrad;
+    dirtype dtry1,dtry2,tdir,olddir;
+
+    dx= ob->targettilex - ob->x;
+    dy= ob->y - ob->targettiley;
+    olddir = ob->dir;
+    if ((abs(dx) < 0x4000) && (abs(dy) < 0x4000))
+    {   ZEROMOM;
+        SetFinePosition(ob,ob->targettilex,ob->targettiley);
+        SetVisiblePosition(ob,ob->x,ob->y);
+        ParseMomentum(ob,dirangle8[ob->temp2]);
+        ActorMovement(ob);
+        ob->temp2 = 0;
+        ob->temp1 = 20;
+#if (SHAREWARE == 0)
+        if ( dopefish==true )
+        {
+            NewState(ob,&s_scottwander1);
+        }
+        else
+#endif
+        {
+            NewState(ob,&s_collectorwander1);
+        }
+        ob->targettilex = ob->targettiley = 0;
+        ob->dirchoosetime = 165;
+        return;
+    }
+
+
+    ZEROMOM;
+
+    ParseMomentum(ob,atan2_appx(dx,dy));
+    ActorMovement(ob);
+    if (ob->momentumx || ob->momentumy)
+        return;
+    actrad = ACTORSIZE;
+    dtry1=nodir;
+    dtry2=nodir;
+
+    if (dx> actrad)
+        dtry1= east;
+    else if (dx< -actrad)
+        dtry1= west;
+    if (dy> actrad)
+        dtry2= north;
+    else if (dy < -actrad)
+        dtry2= south;
+
+
+    if (abs(dy)>abs(dx))
+    {   tdir=dtry1;
+        dtry1=dtry2;
+        dtry2=tdir;
+    }
+
+
+    if (dtry1 != nodir)
+        M_CHECKDIR(ob,dtry1);
+
+    if (dtry2 != nodir)
+        M_CHECKDIR(ob,dtry2);
+
+    if (dtry1 != nodir)
+        M_CHECKDIR(ob,dirorder[dtry1][NEXT]);
+
+    if (dtry2 != nodir)
+        M_CHECKDIR(ob,dirorder[dtry2][NEXT]);
+
+    for(tdir = dirorder[olddir][NEXT]; tdir != olddir; tdir = dirorder[tdir][NEXT])
+        M_CHECKDIR(ob,tdir);
+    ob->dir = olddir;
+
+}
+
+
+boolean EluderCaught(objtype*ob)
+{
+    objtype *temp;
+    int dx,dy,dz;
+    playertype *pstate;
+    int dist = 0xc000;
+
+    for(temp = PLAYER[0]; temp != PLAYER[numplayers-1]->next; temp=temp->next)
+    {
+#if (SHAREWARE == 0)
+        if (temp->state != &s_doguse)
+            continue;
+#endif
+
+        dx = M_ABS(temp->x - ob->x);
+        if (dx > dist)
+            continue;
+
+        dy = M_ABS(temp->y - ob->y);
+        if (dy > dist)
+            continue;
+
+        dz = M_ABS(temp->z - ob->z);
+        if (dz > (dist>>10))
+            continue;
+
+        M_LINKSTATE(temp,pstate);
+        //if (DOGSCRATCH.attackinfo[pstate->attackframe].attack == at_pulltrigger)
+        {   BATTLE_CheckGameStatus(battle_caught_eluder,temp->dirchoosetime);
+            SpawnNewObj(ob->tilex,ob->tiley,&s_itemspawn1,inertobj);
+            new->flags |= FL_ABP;
+            SetFinePosition(new,ob->x,ob->y);
+            SetVisiblePosition(new,ob->x,ob->y);
+            new->z = ob->z;
+            SD_PlaySoundRTP(SD_GETBONUSSND,ob->x,ob->y);
+            MakeActive(new);
+            NewState(ob,&s_megaremove);
+            return true;
+        }
+
+    }
+
+    return false;
+}
+
+
+void T_CollectorFindDoor(objtype*ob)
+{
+
+    if (EluderCaught(ob))
+        return;
+
+    if (!(gamestate.TimeCount % 17))
+        SD_PlaySoundRTP(SD_MONKGRABSND,ob->x,ob->y);
+
+
+    if ((ob->z != nominalheight) && (!IsPlatform(ob->tilex,ob->tiley)))
+        ZEROMOM;
+
+
+
+    if (ob->dirchoosetime)
+        ob->dirchoosetime --;
+    else
+    {
+#if (SHAREWARE == 0)
+        if ( dopefish==true )
+        {
+            NewState(ob,&s_scottwander1);
+        }
+        else
+#endif
+        {
+            NewState(ob,&s_collectorwander1);
+        }
+        ob->dirchoosetime = 165;
+        ob->targettilex = ob->targettiley = 0;
+        return;
+    }
+
+    if (ob->temp1)
+    {   int dx,dy;
+
+        ob->temp1 --;
+        ActorMovement(ob);
+        dx = ob->targettilex-ob->x;
+        dy = ob->targettiley-ob->y;
+        if ((abs(dx) < 0x4000) && (abs(dy) < 0x4000))
+        {   ZEROMOM;
+            SetFinePosition(ob,ob->targettilex,ob->targettiley);
+            SetVisiblePosition(ob,ob->x,ob->y);
+
+            ParseMomentum(ob,dirangle8[ob->temp2]);
+            ActorMovement(ob);
+            ob->temp2 = 0;
+            ob->temp1 = 35;
+#if (SHAREWARE == 0)
+            if ( dopefish==true )
+            {
+                NewState(ob,&s_scottwander1);
+            }
+            else
+#endif
+            {
+                NewState(ob,&s_collectorwander1);
+            }
+            ob->targettilex = ob->targettiley = 0;
+            ob->dirchoosetime = 165;
+            return;
+        }
+        if (NOMOM)
+            ob->temp1 = 0;
+        return;
+    }
+
+
+
+    ob->temp1 = 5;
+
+    if (ob->targettilex || ob->targettiley)
+        SelectDoorDir(ob);
+
+    else
+    {   int i;
+        doorobj_t* dptr;
+
+//==========================================================================
+#define SetCollectorTarget(xoffset,yoffset,newdir)                         \
+   {                                                                       \
+   ob->targettilex = ((dptr->tilex + (xoffset)) << TILESHIFT) + HALFGLOBAL1; \
+   ob->targettiley = ((dptr->tiley + (yoffset)) << TILESHIFT) + HALFGLOBAL1; \
+   ob->temp2 = newdir;                                                     \
+   if (GameRandomNumber("collector door search",0) < 100)                  \
+      return;                                                              \
+   }
+//==========================================================================
+
+        for(i=0; i<doornum; i++)
+        {   dptr = doorobjlist[i];
+            if (dptr->vertical)
+            {
+                int area1 = AREANUMBER(dptr->tilex-1,dptr->tiley),
+                    area2 = AREANUMBER(dptr->tilex+1,dptr->tiley);
+
+                if (area1 == ob->areanumber)
+                    SetCollectorTarget(-1,0,east)
+
+                    else if (area2 == ob->areanumber)
+                        SetCollectorTarget(1,0,west);
+
+            }
+            else
+            {
+                int area1 = AREANUMBER(dptr->tilex,dptr->tiley-1),
+                    area2 = AREANUMBER(dptr->tilex,dptr->tiley+1);
+
+                if (area1 == ob->areanumber)
+                    SetCollectorTarget(0,-1,south)
+
+                    else if (area2 == ob->areanumber)
+                        SetCollectorTarget(0,1,north);
+
+            }
+        }
+    }
+
+}
+
+
+void T_CollectorWander(objtype*ob)
+{
+
+    int newtilex,newtiley;
+
+    if (EluderCaught(ob))
+        return;
+
+    if ((ob->z != nominalheight) && (!IsPlatform(ob->tilex,ob->tiley)))
+        ZEROMOM;
+
+    if (!(gamestate.TimeCount & 15))//%17
+        SD_PlaySoundRTP(SD_MONKGRABSND,ob->x,ob->y);
+
+    if (ob->dirchoosetime)
+    {
+        if (doornum > 0)
+            ob->dirchoosetime --;
+    }
+
+    else
+    {
+#if (SHAREWARE == 0)
+        if ( dopefish==true )
+        {
+            NewState(ob,&s_scottwanderdoor1);
+        }
+        else
+#endif
+        {
+            NewState(ob,&s_collectorfdoor1);
+        }
+        ob->temp1 = 0;
+        ob->dirchoosetime = 165;
+        ob->targettilex = ob->targettiley = 0;
+        return;
+    }
+
+    if (ob->temp1) // temp1 holds direction time
+        ob->temp1 --;
+    else
+    {
+        dirtype bestdir,tempdir;
+
+        bestdir = angletodir[GameRandomNumber("collector theta",0) << 3];
+
+        for(tempdir = bestdir; tempdir != dirorder[bestdir][PREV]; tempdir = dirorder[tempdir][NEXT])
+        {
+            ParseMomentum(ob,dirangle8[tempdir]);
+            newtilex = ((ob->x + ob->momentumx)>>16);
+            newtiley = ((ob->y + ob->momentumy)>>16);
+            if (IsWindow(newtilex,newtiley))
+                continue;
+            ActorMovement(ob);
+            if (ob->momentumx || ob->momentumy)
+            {
+                ob->temp1 = (GameRandomNumber("collector choose time",0) >> 2);
+                return;
+            }
+        }
+
+    }
+
+    newtilex = ((ob->x + ob->momentumx)>>16);
+    newtiley = ((ob->y + ob->momentumy)>>16);
+
+
+    if (IsWindow(newtilex,newtiley))
+    {
+        ob->temp1 = 0;
+        return;
+    }
+
+
+    ActorMovement(ob);
+
+    if (NOMOM)
+        ob->temp1 = 0;
+}
+
+
+
+
+
+boolean CheckDoor(objtype *ob,doorobj_t * door,int trytilex,int trytiley)
+{   boolean doorok=false;
+
+
+    switch(ob->dir)
+    {
+    case north:
+        if ((ob->tiley == (door->tiley + 1)) && (trytilex == ob->tilex))
+            doorok = true;
+        break;
+
+    case east:
+        if ((ob->tilex == (door->tilex - 1)) &&	(trytiley == ob->tiley))
+            doorok = true;
+        break;
+
+    case south:
+        if ((ob->tiley == (door->tiley - 1)) &&	(trytilex == ob->tilex))
+            doorok = true;
+        break;
+
+    case west:
+        if ((ob->tilex == (door->tilex + 1)) &&	(trytiley == ob->tiley))
+            doorok = true;
+        break;
+    default:
+        ;
+    }
+
+
+    if (doorok)
+    {   SetTilePosition(ob,ob->tilex,ob->tiley);
+        SetVisiblePosition(ob,ob->x,ob->y);
+        return true;
+    }
+    return false;
+}
+
+
+boolean WallCheck(int tryx,int tryy)
+{   int tilexlow,tilexhigh,tileylow,tileyhigh,y,x;
+
+    tilexlow = (int)((tryx -PLAYERSIZE) >>TILESHIFT);
+    tileylow = (int)((tryy -PLAYERSIZE) >>TILESHIFT);
+
+    tilexhigh = (int)((tryx + PLAYERSIZE) >>TILESHIFT);
+    tileyhigh = (int)((tryy + PLAYERSIZE) >>TILESHIFT);
+
+
+    for (y=tileylow; y<=tileyhigh; y++)
+        for (x=tilexlow; x<=tilexhigh; x++)
+        {   //tempwall = (wall_t*)actorat[x][y];
+            //if (tempwall && M_ISWALL(tempwall))
+            if (tilemap[x][y])
+                return false;
+        }
+
+    return true;
+
+}
+
+
+boolean QuickSpaceCheck(objtype*ob,int tryx, int tryy)
+{   int xlow,xhigh,ylow,yhigh,x,y,dx,dy;
+    objtype* temp;
+
+    xlow = (int)((tryx-ACTORSIZE) >>TILESHIFT);
+    ylow = (int)((tryy-ACTORSIZE) >>TILESHIFT);
+
+    xhigh = (int)((tryx+ACTORSIZE) >>TILESHIFT);
+    yhigh = (int)((tryy+ACTORSIZE) >>TILESHIFT);
+    /******************* WALLS/PWALLS *****************************************/
+
+    for (y=ylow; y<=yhigh; y++)
+        for (x=xlow; x<=xhigh; x++)
+        {   temp = (objtype*)actorat[x][y];
+            if ((temp && (temp->which != ACTOR)) ||
+                    (sprites[x][y] && (sprites[x][y]->flags & FL_BLOCK))
+
+                    || tilemap[x][y])
+                return false;
+        }
+
+    for(temp=firstareaactor[ob->areanumber]; temp; temp=temp->nextinarea)
+    {   if (temp == ob)
+            continue;
+        if ((temp->flags & FL_NONMARK) || (temp->flags & FL_NEVERMARK))
+            continue;
+        dx = tryx - temp->x;
+        if ((dx < -MINACTORDIST) || (dx > MINACTORDIST))
+            continue;
+        dy = tryy - temp->y;
+        if ((dy < -MINACTORDIST) || (dy > MINACTORDIST))
+            continue;
+        if (ob->whatever == (void*)temp)
+            continue;
+        if (temp->whatever == ob->whatever)
+            continue;
+        return false;
+    }
+
+    return true;
+
+
+}
+
+
+//=========================================================================
+//
+//                    ACTOR TRY MOVE MADNESS
+//
+//=========================================================================
+
+typedef enum
+{
+    NO_MOVEMENT,
+    Z_MOVEMENT_ONLY,
+    OK_TO_CONTINUE
+
+} movement_status;
+
+
+
+//==================== Some ActorTryMove macros ==============================
+
+#define CheckProximitySpecials(ob,temp)                             \
+{                                                                   \
+   if (ocl == b_heinrichobj)                                       \
+      {                                                            \
+      if (tcl == playerobj)                                        \
+         {                                                         \
+         playertype *pstate;                                      \
+                                                                     \
+         M_LINKSTATE(temp,pstate);                                \
+         DamageThing(temp,5);                                     \
+         temp->whatever = ob;                                     \
+         temp->temp2 = COLUMNCRUSH;                               \
+         pstate->heightoffset += 4;                               \
+         if (pstate->heightoffset >= 30)                          \
+            pstate->heightoffset = 30;                           \
+         pstate->oldheightoffset = pstate->heightoffset;          \
+         }                                                         \
+      else                                                         \
+         {                                                         \
+         temp->momentumx = temp->momentumy = temp->momentumz = 0; \
+         temp->hitpoints = 0;                                     \
+         }                                                         \
+      if (temp->hitpoints <= 0)                                    \
+         temp->flags |= FL_HBM;                                     \
+      Collision(temp,ob,0,0);                                      \
+      continue;                                                    \
+      }                                                             \
+                                                                    \
+   else if ((ocl == b_darksnakeobj) && (tcl == playerobj)) \
+      {                                                     \
+      DamageThing(temp,1);                                      \
+      Collision(temp,ob,0,0);     \
+      M_CheckPlayerKilled(temp);                                   \
+      } \
+        \
+   if ((ocl == boulderobj) && (tcl >= lowguardobj) && (tcl < roboguardobj))\
+      {temp->momentumx = temp->momentumy = temp->momentumz = 0;     \
+       temp->hitpoints = 0;                                         \
+       temp->flags |= FL_HBM;                                       \
+       Collision(temp,ob,0,0);                                      \
+       SD_PlaySoundRTP(SD_ACTORSQUISHSND,temp->x,temp->y);          \
+       continue;                                                    \
+      }                                                             \
+                                                                    \
+   if (pusher && (ocl != tcl) && (!(temp->flags & FL_DYING))  &&    \
+       (tcl < roboguardobj)                                         \
+      )                                                             \
+      {if ((!ob->ticcount) && (ocl != collectorobj) && (ocl != diskobj))\
+          DamageThing(temp,5);                                      \
+                                                                    \
+       if (tcl == playerobj)                                        \
+         temp->flags |= FL_PUSHED;                                  \
+       Collision(temp,ob,ob->momentumx-temp->momentumx,ob->momentumy-temp->momentumy);\
+       M_CheckPlayerKilled(temp);                                   \
+       continue;                                                    \
+      }                                                             \
+                                                                    \
+   if (bouncer)                                                    \
+      {ob->momentumx = -ob->momentumx;                              \
+       continue;                                                    \
+      }                                                             \
+   }
+
+
+
+#define CheckStepping(ob,step,minzdiff)                         \
+{                                                               \
+ int cz = (ob->z - step->z + minzdiff);                         \
+                                                                \
+ if ((cz >= -MAXSTEPHEIGHT) && (cz <= MAXSTEPHEIGHT))           \
+      {if ((ob->obclass == playerobj) && (ob->temp2 == 0) &&    \
+           (ob->z != (step->z - minzdiff))                      \
+          )                                                     \
+         {                                                      \
+         playertype *pstate;                                    \
+                                                                \
+         M_LINKSTATE(ob,pstate);                                \
+                                                                \
+         pstate->heightoffset = pstate->oldheightoffset + cz;   \
+         ob->temp2 = (cz >= 0)?(STEPUP):(STEPDOWN);             \
+         }                                                      \
+      ob->z = step->z - minzdiff;                               \
+      tryz = ob->z + (ob->momentumz >> 16);                     \
+      dzt = minzdiff;                                           \
+      }                                                         \
+}                                                               \
+
+
+
+
+//============ Players crushing other players =====================
+
+void BattleCrushCheck(objtype *ob,objtype *listrover)                              \
+{
+    if ((ob->obclass == playerobj) && (listrover->obclass == playerobj))
+    {
+        playertype * pstate;
+
+        M_LINKSTATE(listrover,pstate);
+        if (pstate->health <= 0)
+            BATTLE_PlayerKilledPlayer(battle_kill_by_crushing,ob->dirchoosetime,
+                                      listrover->dirchoosetime);
+    }
+}
+
+
+//=================================================================
+
+
+
+
+
+movement_status CheckOtherActors(objtype*ob,int tryx,int tryy,int tryz)
+{
+    objtype *listrover;
+    int area;
+    int op;
+    int areatried[NUMAREAS]= {0};
+    int tilexlow,tilexhigh,tileylow,tileyhigh;
+    int radius,actrad,oldrad;
+    boolean bouncer,pusher,thinkingactor,zstoppable,ACTORSTOP;
+    int dzt,dztp1,checkz;
+    int x,y,dx,dy;
+    int ocl,tcl;
+    int ISPLAYER = 0;
+    int hoffset;
+
+    ocl = ob->obclass;
+
+    actrad = MINACTORDIST;//ACTORSIZE+0x2800;
+    pusher =  ((ocl == wallopobj) || (ocl == pillarobj) ||
+               (ocl == roboguardobj) || (ocl == collectorobj) ||
+               (ocl == boulderobj) || (ocl == diskobj)
+              );
+
+    thinkingactor = ((ocl != playerobj) && (ob->state->think != T_Collide) &&
+                     (ocl < roboguardobj)
+                    );
+
+    zstoppable = (!(ob->flags & FL_DYING));
+    bouncer = ((ocl == playerobj) && (ob->flags & FL_ELASTO));
+    radius = ACTORSIZE;
+
+
+    if (ocl != playerobj)
+    {
+        //actrad = MINACTORDIST;
+        //if ((ob->dir == nodir) && (ocl != b_robobossobj) &&
+        //   (ocl != wallopobj) && (ocl != roboguardobj) && (ocl != diskobj)
+        // )
+        // Error("ob called with nodir");
+        if (ocl == boulderobj)
+            radius += (ACTORSIZE/4);
+        else if (ocl == b_darksnakeobj)
+            radius -= 6000;
+        else if (ocl == inertobj)
+            radius -= 0x2000;
+    }
+
+    else
+    {
+        ISPLAYER = 1;
+        if (ob->flags & FL_DOGMODE)
+            hoffset = 10;
+    }
+
+
+
+    tilexlow = (int)((tryx-radius) >>TILESHIFT);
+    tileylow = (int)((tryy-radius) >>TILESHIFT);
+
+    tilexhigh = (int)((tryx+radius) >>TILESHIFT);
+    tileyhigh = (int)((tryy+radius) >>TILESHIFT);
+
+    area = ob->areanumber;
+    areatried[area] = 1;
+    ACTORSTOP = false;
+    oldrad = actrad;
+
+actors:
+    for(listrover=firstareaactor[area]; listrover; listrover=listrover->nextinarea)
+    {
+        actrad = oldrad;
+
+        if (listrover == ob)
+            continue;
+
+
+        tcl = listrover->obclass;
+
+        if ((tcl == b_darksnakeobj) && (listrover != SNAKEHEAD))
+            continue;
+
+        if (((tcl == bladeobj) || (tcl == firejetobj)) && thinkingactor)
+
+            actrad += 0x3000;
+
+
+        dx = tryx - listrover->x;
+        if ((dx < -actrad) || (dx > actrad))
+            continue;
+
+        dy = tryy - listrover->y;
+        if ((dy < -actrad) || (dy > actrad))
+            continue;
+
+
+        if ((ocl == b_darksnakeobj) && (tcl == ocl))
+            continue;
+
+        if ((tcl == springobj) && (listrover->state->condition & SF_UP) &&
+                (listrover->temp1!=3) && (levelheight > 1) &&
+                (abs(listrover->z - ob->z) < 5) && (!ob->momentumz)
+           )
+        {
+            {
+                op = (FixedMul((int)GRAVITY,(int)((ob->z-10)<<16))<<1);
+                ob->momentumz = -FixedSqrtHP(op);
+            }
+            SD_PlaySoundRTP(SD_SPRINGBOARDSND,listrover->x,listrover->y);
+            NewState(listrover,&s_spring2);
+
+        }
+
+
+
+        if ((tcl == firejetobj) && (ob->z < listrover->z))
+            continue;
+
+        if ((!(listrover->flags & FL_BLOCK)) && (actrad == oldrad)) // if not blocking
+            // and actor not avoiding
+            // env. danger
+            continue;
+
+
+
+        if (tcl == crushcolobj)
+            checkz = listrover->temp2;
+        else
+            checkz = listrover->z;
+
+#define  MINACTORZDIFF 58
+
+        dzt = abs(checkz - ob->z);
+        dztp1 = abs(checkz - tryz);
+
+        if ((tcl == diskobj) && (dztp1 <= MINACTORZDIFF) && zstoppable &&
+                (ocl != b_heinrichobj)
+           )
+            CheckStepping(ob,listrover,MINACTORZDIFF);
+
+        dztp1 = abs(checkz - tryz);
+
+
+
+        if ((dzt > (MINACTORZDIFF - 25)) && (dzt < MINACTORZDIFF) &&
+                (dztp1 < MINACTORZDIFF) && (tcl < roboguardobj) &&
+                (ocl < roboguardobj)
+           )
+        {
+            int rdx,rdy;
+
+            rdx = abs(ob->x - listrover->x);
+            rdy = abs(ob->y - listrover->y);
+            if ((rdx < actrad) && (rdy < actrad))
+            {
+                if (ob->z > listrover->z)
+                    listrover->z = ob->z - MINACTORZDIFF;
+                else
+                    ob->z = listrover->z - MINACTORZDIFF;
+
+                dzt = dztp1 = MINACTORZDIFF;
+            }
+
+        }
+
+
+        if ((dztp1 >= MINACTORZDIFF) || (dzt >= MINACTORZDIFF))
+        {
+            if ((dzt >= MINACTORZDIFF) && (dztp1 <= MINACTORZDIFF) &&
+                    zstoppable
+               )
+            {   //ob->momentumz = 0;
+                if (ob->z < listrover->z)
+                {
+                    ob->z = listrover->z - MINACTORZDIFF;
+                    ob->momentumz = 0;
+                }
+                else
+                    ob->momentumz = 2*GRAVITY;
+                if ((listrover->z > ob->z) && (tcl < roboguardobj) && (ocl < roboguardobj) &&
+                        (!(listrover->flags & FL_DYING))
+                   )
+
+                {
+                    DamageThing(listrover,5);
+                    BattleCrushCheck(ob,listrover);
+                    Collision(listrover,ob,listrover->momentumx,listrover->momentumy);
+                    /*
+                    if ((ocl == playerobj) && (listrover->flags & FL_DYING))
+                       GivePoints(starthitpoints[gamestate.difficulty][tcl]);
+                    */
+                }
+
+                if (((tcl == bladeobj) || (tcl == diskobj)) && (ob->z < listrover->z))
+                {
+                    ob->whatever = listrover;
+                    if (listrover->flags & FL_ACTIVE)
+                        ob->flags |= FL_RIDING;
+                    listrover->whatever = ob;
+                }
+
+                //Debug("\nplayerz %d, tryz %d momz zeroed at %d, clearances %d and %d",
+                //   ob->z,tryz,listrover->z-64 + (listrover->momentumz >> 16),dzt,dztp1);
+
+            }
+
+            continue;
+        }
+
+
+        CheckProximitySpecials(ob,listrover);
+
+
+        ACTORSTOP = true;
+        if (!ob->momentumz)
+            return NO_MOVEMENT;
+
+    }
+
+
+    for (y=tileylow; y<=tileyhigh; y++)
+        for (x=tilexlow; x<=tilexhigh; x++)
+        {
+            area = AREANUMBER(x,y);
+            if (ValidAreanumber(area) && (areatried[area]==0))
+            {
+                areatried[area] = 1;
+                goto actors;
+            }
+        }
+
+
+
+    if (ACTORSTOP==true)
+        return Z_MOVEMENT_ONLY;
+
+    return OK_TO_CONTINUE;
+}
+
+
+
+movement_status CheckRegularWalls(objtype *ob,int tryx,int tryy,int tryz)
+{
+    int tilexlow,tilexhigh,tileylow,tileyhigh,x,y,radius;
+    classtype ocl;
+    boolean WALLSTOP,ISPLAYER=false;
+
+    ocl = ob->obclass;
+    tryz=tryz;
+
+
+    if (ocl != playerobj)
+    {
+        radius = ACTORSIZE - 0x1000;
+        //actrad = MINACTORDIST;
+        //if ((ob->dir == nodir) && (ocl != b_robobossobj) &&
+        //   (ocl != wallopobj) && (ocl != roboguardobj) && (ocl != diskobj)
+        //  )
+        // Error("ob called with nodir");
+        if (ocl == boulderobj)
+            radius += (ACTORSIZE/4);
+        else if (ocl == b_darksnakeobj)
+            radius -= 6000;
+        else if (ocl == inertobj)
+            radius -= 0x2000;
+    }
+
+    else
+    {
+        radius = PLAYERSIZE;
+        ISPLAYER = true;
+    }
+
+
+    tilexlow = (int)((tryx-radius) >>TILESHIFT);
+    tileylow = (int)((tryy-radius) >>TILESHIFT);
+
+    tilexhigh = (int)((tryx+radius) >>TILESHIFT);
+    tileyhigh = (int)((tryy+radius) >>TILESHIFT);
+
+
+    WALLSTOP = false;
+
+    for (y=tileylow; y<=tileyhigh; y++)
+        for (x=tilexlow; x<=tilexhigh; x++)
+        {
+            wall_t          *tempwall;
+            int             wall;
+
+            tempwall = (wall_t*)actorat[x][y];
+            wall=tilemap[x][y];
+            if (tempwall)
+            {
+                if (tempwall->which==WALL)// && IsWindow(x,y)==false)
+                {
+                    if (ocl == boulderobj)
+                    {
+#if (SHAREWARE == 0)
+                        NewState(ob,&s_bouldersink1);
+#endif
+                        SD_PlaySoundRTP(SD_BOULDERHITSND,ob->x,ob->y);
+                    }
+                    else if (ISPLAYER && (!(ob->flags & FL_DYING)) &&
+                             (!(ob->flags & FL_AV)) &&
+                             (tempwall->flags & FL_W_DAMAGE))
+                    {
+                        DamageThing(ob,5);
+                        Collision(ob,(objtype*)tempwall,0,0);
+                        M_CheckPlayerKilled(ob);
+                        SD_PlaySoundRTP(SD_PLAYERBURNEDSND,ob->x,ob->y);
+                    }
+
+                    //return false;
+                    WALLSTOP = true;
+                    if ((ocl == inertobj) &&
+                            (ob->dirchoosetime == GIBVALUE) &&
+
+                            (((ob->tilex - x) == 0) != ((ob->tiley - y) == 0)) &&
+                            (ob->z > -28)
+
+                       )
+                    {
+                        //                SoftError ("Blood Dripping oldpolltime=%ld\n",oldpolltime);
+                        BloodDrip(ob,x,y);
+                        return NO_MOVEMENT;
+                    }
+
+                    if (!ob->momentumz)
+                        return NO_MOVEMENT;
+                    else// if (ocl != inertobj)
+                        return Z_MOVEMENT_ONLY;
+                    //else
+                    //goto doors;
+                }
+
+                else if (tempwall->which==PWALL)
+                {
+                    pwallobj_t*pw;
+                    int dx,dy;
+
+                    pw=(pwallobj_t *)tempwall;
+                    dx = abs(pw->x - tryx);
+                    if (dx > PWALLRAD+0x5000)
+                        continue;
+
+                    dy = abs(pw->y - tryy);
+                    if (dy > PWALLRAD+0x5000)
+                        continue;
+
+                    return NO_MOVEMENT;
+                }
+
+            }
+        }
+
+    return OK_TO_CONTINUE;
+
+}
+
+
+
+movement_status CheckStaticObjects(objtype *ob,int tryx,int tryy,int tryz)
+{
+    int dx,dy,dzt,dztp1,x,y;
+    statobj_t*tempstat;
+    int sprrad,oldsrad,sprtrad;
+    boolean specialstat=false,widestat=false,zstoppable;
+    int sprxlow,sprxhigh,sprylow,spryhigh;
+    boolean SPRSTOP;
+    classtype ocl;
+
+    ocl = ob->obclass;
+
+    if (ocl != playerobj)
+        sprtrad = ACTORSIZE - 0x1000;
+    else
+        sprtrad = ACTORSIZE - 0x1000 + 0x10000;
+
+
+
+    sprxlow = (int)((tryx-sprtrad) >>TILESHIFT);
+    sprylow = (int)((tryy-sprtrad) >>TILESHIFT);
+
+    sprxhigh = (int)((tryx+sprtrad) >>TILESHIFT);
+    spryhigh = (int)((tryy+sprtrad) >>TILESHIFT);
+
+    if (sprxlow < 0)
+        sprxlow = 0;
+
+    if (sprxhigh > (MAPSIZE-1))
+        sprxhigh = MAPSIZE-1;
+
+    if (sprylow < 0)
+        sprylow = 0;
+
+    if (spryhigh > (MAPSIZE-1))
+        spryhigh = MAPSIZE-1;
+
+    SPRSTOP = false;
+    sprrad = 0x4500;
+    zstoppable = (!(ob->flags & FL_DYING));
+    oldsrad = sprrad;
+
+    for (y=sprylow; y<=spryhigh; y++)
+        for (x=sprxlow; x<=sprxhigh; x++)
+        {
+            tempstat = sprites[x][y];
+            sprrad = oldsrad;
+
+            if (tempstat)
+            {
+                specialstat = ((tempstat->itemnumber == stat_heatgrate) ||
+                               (tempstat->itemnumber == stat_pit)
+                              );
+
+                widestat = (((tempstat->itemnumber >= stat_bcolumn) &&
+                             (tempstat->itemnumber <= stat_icolumn)) ||
+                            (tempstat->itemnumber == stat_disk)
+                           );
+
+                if ((tempstat->flags & FL_BLOCK) || (specialstat==true))
+                {
+                    if ((specialstat==true) && (ocl !=playerobj) &&
+                            (ob->state->think != T_Collide)
+                       )
+                        sprrad += 0x5000;
+
+                    if (widestat==true)
+                        sprrad += 0x3b00;
+
+
+                    if ((tempstat->itemnumber == stat_ironbarrel) ||
+                            (tempstat->itemnumber == stat_bonusbarrel))
+                        sprrad += 0x5000;
+
+                    dx = abs(tryx - tempstat->x);
+                    if (dx > sprrad)
+                        continue;
+                    dy = abs(tryy - tempstat->y);
+                    if (dy > sprrad)
+                        continue;
+
+#define MINSTATZDIFF 58
+
+                    dzt = abs(ob->z - tempstat->z);
+                    dztp1 = abs(tryz - tempstat->z);
+
+                    if (widestat && (dztp1 <= MINSTATZDIFF) && zstoppable &&
+                            (ocl != b_heinrichobj)
+                       )
+                        CheckStepping(ob,tempstat,MINSTATZDIFF);
+
+
+                    dztp1 = abs(tryz - tempstat->z);
+
+#if (SHAREWARE == 0)
+                    if ((ocl == b_darksnakeobj) && (tempstat->itemnumber == stat_heatgrate))
+                    {
+                        if (ob->state->think == T_DarkSnakeChase)
+                            NewState(ob,&s_darkmonkredhead);
+                        else
+                            NewState(ob,&s_darkmonkredlink);
+                        ob->temp3 ++; // make shootable
+                    }
+#endif
+
+                    if (specialstat==true)
+                        continue;
+
+
+                    if ((dztp1 >= MINSTATZDIFF) || (dzt >= MINSTATZDIFF))
+                    {   if ((dzt >= MINSTATZDIFF) && (dztp1 <= MINSTATZDIFF) && zstoppable)
+                        {   //ob->momentumz = 0;
+                            if (ob->z <= tempstat->z)
+                            {
+                                ob->z = tempstat->z - MINSTATZDIFF;
+                                ob->momentumz = 0;
+                            }
+                            else
+                                ob->momentumz = 2*GRAVITY; // ((2*GRAVITY + GRAVITY) >> 16) = 1
+                        }
+                        continue;
+                    }
+
+
+                    if (ocl == boulderobj)
+                    {   if ((tempstat->itemnumber < stat_bcolumn) ||
+                                (tempstat->itemnumber > stat_icolumn)
+                           )
+                        {
+                            tempstat->flags |= FL_SHOOTABLE;
+                            DamageThing(tempstat,tempstat->hitpoints);
+                            continue;
+                        }
+#if (SHAREWARE == 0)
+                        else
+                            NewState(ob,&s_bouldersink1);
+#endif
+                    }
+                    //ob->momentumz=0;
+                    //return false;
+                    SPRSTOP=true;
+                    if (!ob->momentumz)
+                        return NO_MOVEMENT;
+                }
+            }
+        }
+    if (SPRSTOP == true)
+        return Z_MOVEMENT_ONLY;
+
+    return OK_TO_CONTINUE;
+
+}
+
+
+
+
+
+//============== Platform craziness ======================================
+
+
+#define ClipHeight(ob,clipz)                                \
+{  ob->momentumz = 0;                                       \
+                                                            \
+   if (ISPLAYER && (ob->z != clipz) && (ob->temp2 == 0))    \
+      {playertype *pstate;                                  \
+       int dz = ob->z - clipz;                              \
+                                                            \
+       M_LINKSTATE(ob,pstate);                              \
+                                                            \
+       pstate->heightoffset = pstate->oldheightoffset + dz; \
+       ob->temp2 = (dz >= 0)?(STEPUP):(STEPDOWN);           \
+      }                                                     \
+                                                            \
+   ob->z = clipz;                                           \
+}
+
+//======================
+
+#define CheckSpecialGibMovement(blocker)            \
+   {                                                \
+   int centerx = ((trytilex<<16) + 0x8000);         \
+   int centery = ((trytiley<<16) + 0x8000);         \
+                                                    \
+   if (blocker->vertical==false)                    \
+      {                                             \
+      int dyt = centery - ob->y;                    \
+      int dytp1 = centery - tryy;                   \
+                                                    \
+      if ((abs(dytp1) > abs(dyt)) &&                \
+         (SGN(dyt) == SGN(dytp1))                   \
+         )                                          \
+         return OK_TO_CONTINUE;                     \
+                                                    \
+      }                                             \
+   else                                             \
+      {                                             \
+      int dxt = centerx - ob->x;                    \
+      int dxtp1 = centerx - tryx;                   \
+                                                    \
+      if ((abs(dxtp1) > abs(dxt)) &&                \
+         (SGN(dxt) == SGN(dxtp1))                   \
+         )                                          \
+         return OK_TO_CONTINUE;                     \
+                                                    \
+      }                                             \
+   }
+
+
+movement_status CheckMaskedWalls(objtype *ob,int tryx,int tryy,int tryz)
+{
+    int trytilex,trytiley;
+    boolean MWALLSTOP;
+    int ISPLAYER = (ob->obclass == playerobj);
+    classtype ocl = ob->obclass;
+
+    trytilex = (tryx >> TILESHIFT);
+    trytiley = (tryy >> TILESHIFT);
+    MWALLSTOP = false;
+//for (y=tileylow;y<=tileyhigh;y++)
+// for (x=tilexlow;x<=tilexhigh;x++)
+
+    if (M_ISMWALL(trytilex,trytiley))
+    {
+        int wall = tilemap[trytilex][trytiley];
+        maskedwallobj_t * mw;
+
+        mw=maskobjlist[wall&0x3ff];
+
+        if (ocl == inertobj)
+            CheckSpecialGibMovement(mw);
+
+        if (!(mw->flags&MW_BLOCKING))
+        {
+            if (mw->flags&MW_NONDOGBLOCKING)
+            {
+                if ((ocl==playerobj)&&(ob->flags&FL_DOGMODE))
+                {
+                    if (ob->z < nominalheight)
+                    {
+                        MWALLSTOP = true;
+                        if (!ob->momentumz)
+                            return NO_MOVEMENT;
+                    }
+                }
+                else
+                {
+                    MWALLSTOP = true;
+                    if (!ob->momentumz)
+                        return NO_MOVEMENT;
+                }
+            }
+
+
+            else
+            {
+                if (mw->flags & MW_ABOVEPASSABLE)
+                {   if (mw->flags & MW_MIDDLEPASSABLE) // ==> not bottom
+                    {   if (ob->z > LOWFALLCLIPZ+MAXSTEPHEIGHT)
+                            MWALLSTOP = true;
+                        else if (tryz >= LOWFALLCLIPZ)
+                            ClipHeight(ob,LOWFALLCLIPZ);
+                    }
+                    else if (mw->flags & MW_BOTTOMPASSABLE)
+                    {   if ((ob->z > HIGHFALLCLIPZ+MAXSTEPHEIGHT) && (ob->z < LOWRISECLIPZ))
+                            MWALLSTOP = true;
+                        else if (ob->z <= HIGHFALLCLIPZ+MAXSTEPHEIGHT)
+                        {   if (tryz >= HIGHFALLCLIPZ)
+                                ClipHeight(ob,HIGHFALLCLIPZ);
+                        }
+                        else if (tryz <= LOWRISECLIPZ)
+                            ob->momentumz = 0;
+
+                    }
+                    else // ==> above only
+                    {   if (ob->z > HIGHFALLCLIPZ+MAXSTEPHEIGHT)
+                            MWALLSTOP = true;
+                        else if (tryz >= HIGHFALLCLIPZ)
+                            ClipHeight(ob,HIGHFALLCLIPZ);
+                    }
+
+                }
+                else if (mw->flags & MW_MIDDLEPASSABLE)
+                {   if (mw->flags & MW_BOTTOMPASSABLE) //==> not above passable
+                    {   if (ob->z >= HIGHRISECLIPZ)
+                        {   if (tryz <= HIGHRISECLIPZ)
+                                ob->momentumz = 0;
+                        }
+                        else if (tryz <= HIGHRISECLIPZ)
+                            MWALLSTOP = true;
+                    }
+
+                    else  //==> middle only
+                    {   if (ob->z > LOWFALLCLIPZ+MAXSTEPHEIGHT)
+                            MWALLSTOP = true;
+                        else if (tryz >= LOWFALLCLIPZ)
+                            ClipHeight(ob,LOWFALLCLIPZ)
+                            else
+                            {   if (ob->z >= HIGHRISECLIPZ)
+                                {   if (tryz <= HIGHRISECLIPZ)
+                                        ob->momentumz = 0;
+                                }
+                                else if (tryz <= HIGHRISECLIPZ)
+                                    MWALLSTOP = true;
+                            }
+                    }
+
+                }
+                else // ==> bottompassable only
+                {   if (ob->z < LOWRISECLIPZ)
+                        MWALLSTOP = true;
+                    else if (tryz < LOWRISECLIPZ)
+                        ob->momentumz = 0;
+                }
+
+            }
+        }
+        else
+        {
+            if ( (mw->flags&MW_SHOOTABLE) &&
+                    (mw->flags&MW_BLOCKINGCHANGES) &&
+                    (ob->z >= nominalheight)
+
+               )
+            {
+                int speed=FindDistance(ob->momentumx,ob->momentumy);
+                if ((speed>0x2800) && (!(ob->flags & FL_DYING)))
+                {
+                    if (ob->obclass == playerobj)
+                    {
+                        DamageThing(ob,10);
+                        Collision(ob,(objtype*)mw,0,0);
+                    }
+                    UpdateMaskedWall(wall&0x3ff);
+                    if (tryz < nominalheight)
+                        ob->momentumz = 0;
+                }
+                else
+                {
+                    MWALLSTOP = true;
+                    if (!ob->momentumz)
+                        return NO_MOVEMENT;
+                }
+            }
+            else
+            {
+                MWALLSTOP = true;
+                if (!ob->momentumz)
+                    return NO_MOVEMENT;
+            }
+        }
+    }
+
+    if (MWALLSTOP == true)
+        return Z_MOVEMENT_ONLY;
+
+    return OK_TO_CONTINUE;
+
+}
+
+
+
+movement_status CheckDoors(objtype *ob,int tryx,int tryy,int tryz)
+{
+    int trytilex,trytiley;
+    int ocl;
+
+
+    trytilex = (tryx >> TILESHIFT);
+    trytiley = (tryy >> TILESHIFT);
+    ocl = ob->obclass;
+
+
+    if (M_ISDOOR(trytilex,trytiley))
+    {
+        doorobj_t*tempdoor;
+        int doorn;
+
+        doorn = tilemap[trytilex][trytiley];
+
+        tempdoor = doorobjlist[doorn&0x3ff];
+        if (tempdoor->action == dr_open)
+        {
+
+            if (ob->z >= nominalheight)
+            {
+                if (tryz < nominalheight)
+                    ob->momentumz = 0;
+                return OK_TO_CONTINUE;
+            }
+
+        }
+        if (ocl == inertobj)
+        {
+            CheckSpecialGibMovement(tempdoor);
+        }
+        else if ((ocl == playerobj) || (ocl > b_darksnakeobj))
+            return NO_MOVEMENT;
+        else if (ob->state->think != T_Collide)
+        {
+
+#define DOOR_LOCKED(door)                                      \
+           (((door->flags & DF_ELEVLOCKED) || (door->lock)) && \
+             (ob->obclass != b_darianobj)                       \
+           )
+#define GAS_DOOR(x,y) (MISCVARS->GASON && (MAPSPOT(x,y,1) == GASVALUE))
+
+            if ((!DOOR_LOCKED(tempdoor)) &&
+                    (!GAS_DOOR(trytilex,trytiley))
+               )
+
+
+                //)
+            {
+                ob->door_to_open = doorn&0x3ff;
+                LinkedOpenDoor(ob->door_to_open);
+                if (tempdoor->eindex != -1)
+                    OperateElevatorDoor(doorn&0x3ff);
+            }
+
+            //if ((nstate = M_S(USE)) != NULL)
+            //{ob->whatever = ob->state;
+            //	NewState(ob,nstate);
+            //	ob->flags |= FL_USE;
+            // }
+            return NO_MOVEMENT;
+        }
+        else
+            return NO_MOVEMENT;
+    }
+
+    return OK_TO_CONTINUE;
+}
+
+
+
+boolean ActorTryMove(objtype*ob,int tryx, int tryy, int tryz)
+{
+
+    movement_status (*reduced_movement_check[3])(objtype*,int,int,int)=
+    {
+        CheckRegularWalls,
+        CheckMaskedWalls,
+        CheckDoors,
+    };
+
+
+    movement_status (*complete_movement_check[5])(objtype*,int,int,int)=
+    {
+        CheckOtherActors,
+        CheckRegularWalls,
+        CheckStaticObjects,
+        CheckMaskedWalls,
+        CheckDoors,
+    };
+
+    movement_status (**movement_function)(objtype*,int,int,int);
+    movement_status movement_check_result;
+    int             numcheckfunctions;
+    int             i;
+    boolean         xyblocked;
+
+
+
+
+    if ((tryz < -30) && (sky==0) && (ob->obclass != inertobj))
+    {
+        ob->z = -28;
+        ob->momentumz = 0;
+        return false;
+    }
+
+    if ((!InMapBounds(tryx>>16,tryy>>16)) ||
+            ((ob->obclass != playerobj) && (IsWindow((tryx>>16),(tryy>>16))))
+       )
+        return false;
+
+    switch(ob->obclass)
+    {
+    case inertobj:
+    case bladeobj:
+    case firejetobj:
+        movement_function = &reduced_movement_check[0];
+        numcheckfunctions = 3;
+        break;
+
+    default:
+        movement_function = &complete_movement_check[0];
+        numcheckfunctions = 5;
+        break;
+    }
+
+
+    for(xyblocked=false,i=0; i<numcheckfunctions; i++)
+    {
+        movement_check_result = movement_function[i](ob,tryx,tryy,tryz);
+        if (movement_check_result == Z_MOVEMENT_ONLY)
+            xyblocked = true;
+
+        else if (movement_check_result == NO_MOVEMENT)
+            return false;
+    }
+
+    if (xyblocked == true)
+        return false;
+
+
+    return true;
+
+}
+
+
+void PushWallMove(int num)
+{
+    int             tcl;
+    pwallobj_t      *pwall;
+    int             dx,dy;
+    int             actrad;
+    objtype         *temp;
+    boolean         pushem;
+    int             tryx,tryy,areanumber,trytilex,trytiley;
+
+
+    pwall=pwallobjlist[num];
+
+    actrad = PWALLRAD + 0x5000;
+    tryx = (pwall->x + pwall->momentumx);
+    tryy = (pwall->y + pwall->momentumy);
+    trytilex = (tryx >> 16);
+    trytiley = (tryy >> 16);
+
+    areanumber = AREANUMBER(trytilex,trytiley);
+
+
+    for(temp=firstareaactor[areanumber]; temp; temp=temp->nextinarea)
+    {
+        tcl = temp->obclass;
+
+        if (temp->flags & FL_HEAD)  //ignore NME's head and wheels
+            continue;
+
+        if ((temp->flags & FL_DYING) || (!(temp->flags & FL_SHOOTABLE)))
+            continue;
+
+        if (tcl > b_darianobj)
+            continue;
+
+
+        dx = abs(tryx - temp->x);
+        if (dx > actrad)
+            continue;
+
+        dy = abs(tryy - temp->y);
+        if (dy > actrad)
+            continue;
+
+        if (pwall->flags&PW_DAMAGE)
+        {   if (!((tcl == playerobj) && (temp->flags & FL_AV)))
+                DamageThing(temp,5);
+
+            Collision(temp,(objtype*)pwall,0,0);
+            M_CheckPlayerKilled(temp);
+            if (temp->flags & FL_DYING)
+                return;
+
+        }
+
+        pushem=false;
+        switch (pwall->dir)
+        {
+
+#define PWALLTOL (0xc000)
+
+        case north:
+            if ((temp->y<pwall->y) && (dx<PWALLTOL))
+                pushem=true;
+            break;
+        case east:
+            if ((temp->x>pwall->x) && (dy<PWALLTOL))
+                pushem=true;
+            break;
+        case northeast:
+            if ((temp->y<pwall->y) && (dx<PWALLTOL))
+                pushem=true;
+            else if ((temp->x>pwall->x) && (dy<PWALLTOL))
+                pushem=true;
+            break;
+        case northwest:
+            if ((temp->y<pwall->y) && (dx<PWALLTOL))
+                pushem=true;
+            else if ((temp->x<pwall->x) && (dy<PWALLTOL))
+                pushem=true;
+            break;
+        case south:
+            if ((temp->y>pwall->y) && (dx<PWALLTOL))
+                pushem=true;
+            break;
+        case west:
+            if ((temp->x<pwall->x) && (dy<PWALLTOL))
+                pushem=true;
+            break;
+        case southeast:
+            if ((temp->y>pwall->y) && (dx<PWALLTOL))
+                pushem=true;
+            else if ((temp->x>pwall->x) && (dy<PWALLTOL))
+                pushem=true;
+            break;
+        case southwest:
+            if ((temp->y>pwall->y) && (dx<PWALLTOL))
+                pushem=true;
+            else if ((temp->x<pwall->x) && (dy<PWALLTOL))
+                pushem=true;
+            break;
+        default:
+            //Error ("Pushwall #%d has an illegal direction %d \n",num,pwall->dir);
+            break;
+        }
+
+
+        //if (!pushem)
+        //continue;
+
+        //temp->momentumx = temp->momentumy = 0;
+        if (temp->obclass==playerobj)
+            temp->flags|=FL_PUSHED;
+
+        if (!pushem)
+        {
+            Collision(temp,(objtype*)pwall,-temp->momentumx,-temp->momentumy);
+            continue;
+        }
+
+        if ((temp->obclass >= lowguardobj) && (temp->obclass < roboguardobj))
+        {
+
+            temp->momentumx = temp->momentumy = temp->momentumz = 0;
+            temp->hitpoints = 0;
+
+            if (gamestate.violence >= vl_high)
+                temp->flags |= FL_HBM;
+            Collision(temp,(objtype*)pwall,0,0);
+            /*
+            	 if (gamestate.violence < vl_high)
+            		{if ((tstate = UPDATE_STATES[CRUSH][temp->obclass - lowguardobj])!=NULL)
+            			 NewState(temp,tstate);
+
+            		 else
+            			 Error("\n\Null low-violence crush state in push wall crush, instance of %s",debugstr[temp->obclass]);
+            		}
+            	 else
+            		{temp->shapeoffset = 0;
+            		 //tactor->flags|=FL_HBM;
+            		 NewState(temp,&s_guts1);
+            		 //KillActor(temp);
+            		}*/
+
+            SD_PlaySoundRTP(SD_ACTORSQUISHSND,temp->x,temp->y);
+        }
+        else
+        {
+            if (!ActorTryMove(temp,temp->x + temp->momentumx,temp->y + temp->momentumy,
+                              temp->z + (temp->momentumz >> 16))
+               )
+            {
+                DamageThing(temp,30);
+                if ((temp->obclass==playerobj) && (temp->hitpoints <= 0))
+                    temp->target = (objtype *)pwall;
+            }
+
+            Collision(temp,(objtype*)pwall,pwall->momentumx-temp->momentumx,pwall->momentumy-temp->momentumy);
+            M_CheckPlayerKilled(temp);
+        }
+
+
+
+    }
+}
+
+void ActorMovement (objtype *ob)
+{   int tryx,tryy,tryz,limitok,max,friction,ocl;
+
+
+
+    if ((ob->obclass == strikeguardobj) && (!(ob->flags & FL_DYING)) &&
+            (gamestate.difficulty > gd_easy)
+       )
+    {
+        AvoidPlayerMissile(ob);
+        ob->flags &= ~FL_FULLLIGHT;
+    }
+
+
+    if ((!ob->momentumx) && (!ob->momentumy) && (!ob->momentumz))
+    {   if (ob->flags & FL_RIDING)
+            goto ride;
+        else
+            return;
+    }
+
+
+    limitok = 1;
+
+    friction = ACTORFRICTION;
+    if (!(ob->flags & FL_DYING))
+        friction >>= 1;
+    ocl = ob->obclass;
+    if (ocl == playerobj)
+    {
+        playertype *pstate;
+
+        M_LINKSTATE(ob,pstate);
+        max = pstate->topspeed;
+        friction = PLAYERFRICTION;
+        if ((ob->temp2 == PITFALL) || (ob->temp2 == PITRISE))
+            friction >>= 4;
+    }
+
+
+    else if (/*(ob->state->think != T_Collide) &&*/ (ocl != b_robobossobj) &&
+            (ocl != boulderobj) && (ocl !=b_darkmonkobj) && (ocl != b_darksnakeobj) &&
+            (ocl != inertobj) && (ocl != collectorobj))
+        max = MAXMOVE;
+
+    else
+        limitok = 0;
+
+    if (limitok)
+    {   if (ocl == playerobj)
+        {   int dist,scale;
+
+            dist = FindDistance(ob->momentumx,ob->momentumy);
+            if (dist > max)
+            {   scale = FixedDiv2(max,dist);
+                ob->momentumx = FixedMul(ob->momentumx,scale);
+                ob->momentumy = FixedMul(ob->momentumy,scale);
+            }
+        }
+        else
+        {
+            if (ob->momentumx > max)
+                ob->momentumx = max;
+            else if (ob->momentumx < -max)
+                ob->momentumx = -max;
+            if (ob->momentumy > max)
+                ob->momentumy = max;
+            else if (ob->momentumy < -max)
+                ob->momentumy = -max;
+        }
+
+    }
+
+    tryx = ob->x + ob->momentumx;
+    tryy = ob->y + ob->momentumy;
+    tryz = ob->z + (ob->momentumz >> 16);
+
+    if (ocl != playerobj)
+        ob->flags &= ~FL_STUCK;
+
+
+    if (!ActorTryMove (ob, tryx, tryy, tryz))
+    {   if (ocl == playerobj)
+        {   if (!(ob->flags & FL_ELASTO))
+                PlayerSlideMove (ob);
+            else
+            {   if (ActorTryMove(ob,tryx, ob->y-ob->momentumy,tryz))
+                    ob->momentumy = -(ob->momentumy);
+                else if (ActorTryMove(ob,ob->x-ob->momentumx,tryy,tryz))
+                    ob->momentumx = -(ob->momentumx);
+                else
+                    ZEROMOM;
+            }
+        }
+
+        else
+        {   ZEROMOM;
+            ob->flags |= FL_STUCK;
+            return;
+        }
+    }
+
+    MoveActor(ob);
+
+
+ride:
+
+    if (ob->flags & FL_RIDING)
+    {
+        objtype *ride = (objtype*)(ob->whatever);
+
+        ob->z += (ride->momentumz >> 16);
+
+        if ((ride->momentumx || ride->momentumy) &&
+                ActorTryMove(ob,ob->x+ride->momentumx,ob->y+ride->momentumy,tryz)
+           )
+            SetFinePosition(ob,ob->x+ride->momentumx,ob->y+ride->momentumy);
+    }
+
+
+#define SLIDER(ob)  ((ob->flags & FL_NOFRICTION) && (ob->state->think != T_Collide))
+#define AIRBORNE(ob) ((ob->obclass != playerobj) && (ob->z != nominalheight) &&\
+                      (!IsPlatform(ob->tilex,ob->tiley)) && \
+                      (DiskAt(ob->tilex,ob->tiley) == NULL) \
+                     )
+
+    if (SLIDER(ob) || AIRBORNE(ob))
+        return;
+
+    if ( (abs(ob->momentumx) < STOPSPEED) &&
+            (abs(ob->momentumy) < STOPSPEED)
+       )
+    {
+        ZEROMOM;
+    }
+
+    else if ((ob->flags & FL_DYING) && (ob->state == ob->state->next))
+    {   ob->momentumx = FixedMul (ob->momentumx, DEADFRICTION);
+        ob->momentumy = FixedMul (ob->momentumy, DEADFRICTION);
+
+    }
+
+    else
+    {   ob->momentumx = FixedMul (ob->momentumx, friction);
+        ob->momentumy = FixedMul (ob->momentumy, friction);
+
+    }
+
+
+
+}
+
+
+
+
+void T_Guts(objtype*ob)
+{   if (ob->ticcount)
+        return;
+    SpawnParticles(ob,GUTS,50);
+
+}
+
+
+void T_Special(objtype*ob)
+{
+    if (ob->ticcount)
+        return;
+
+#if (SHAREWARE == 0)
+    if (ob->state == &s_NMEheadexplosion)
+    {
+        ob->z -= 42;
+        SetGibSpeed(0x4000);
+        SpawnParticles(ob,gt_sparks,100);
+        ResetGibSpeed();
+        SD_PlaySoundRTP(SD_EXPLODESND,ob->x,ob->y);
+        return;
+    }
+#endif
+    if (ob->obclass != b_robobossobj)
+        return;
+
+    NewState(ob,&s_bossdeath);
+}
+
+
+
+
+void SpawnBoulder(int tilex,int tiley,int dir)
+{
+#if (SHAREWARE == 1)
+    tilex = tilex;
+    tiley = tiley;
+    dir = dir;
+    Error("Boulders aren't allowed in shareware!");
+#endif
+#if (SHAREWARE == 0)
+    SpawnNewObj(tilex,tiley,&s_boulderspawn,inertobj);
+    new->z = 0;
+    PreCacheActor(boulderobj,0);
+    new->dir = 2*dir;
+#endif
+
+}
+
+
+
+#define InitSprayPart(newflags)                                          \
+   {                                                                     \
+   new->hitpoints = starthitpoints[gamestate.difficulty][b_robobossobj]; \
+   new->dir = dir*4;                                                     \
+   new->speed = 7*SPDPATROL;                                             \
+   new->door_to_open = -1;                                               \
+   new->flags |= (newflags);                                             \
+   }                                                                     \
+
+
+void SpawnMultiSpriteActor(classtype actorclass, int tilex,int tiley,int dir)
+{
+
+
+
+#if (SHAREWARE==1)
+
+    actorclass = actorclass;
+    tilex = tilex;
+    tiley = tiley;
+    dir  = dir;
+    Error("\nSPRAY not allowed in shareware !");
+
+#else
+
+    {
+        objtype *temp;
+
+        gamestate.killtotal++;
+
+        SpawnNewObj(tilex,tiley,&s_NMEstand,actorclass);
+        InitSprayPart(FL_BLOCK|FL_NOFRICTION|FL_SHOOTABLE);
+
+        new->temp1 = -1; // temp1 used as one-event queue for directions when chasing
+        // -1 when isn't waiting to try new dir, dirnumber when waiting
+        temp = new;
+
+        SpawnNewObj(tilex,tiley,&s_NMEhead1,actorclass);
+        InitSprayPart(FL_NOFRICTION|FL_SHOOTABLE|FL_HEAD|FL_NEVERMARK);
+
+        //new->whatever = temp;  // head points to body
+
+        temp->whatever = new;  // body points to head
+
+        SpawnNewObj(tilex,tiley,&s_NMEwheels2,actorclass);
+        InitSprayPart(FL_NOFRICTION|FL_SHOOTABLE|FL_HEAD|FL_NEVERMARK);
+
+
+        //new->whatever = temp;  // head points to body
+        temp->target = new;     // body also points to wheels
+        actorat[tilex][tiley] = NULL;
+        PreCacheActor(b_robobossobj,0);
+    }
+#endif
+}
+
+
+void SpawnSnake(int tilex,int tiley)
+{
+
+#if (SHAREWARE == 1)
+    tilex = tilex;
+    tiley = tiley;
+    Error("snake not allowed in shareware!");
+#else
+
+    GetNewActor();
+    MakeActive(new);
+    new->flags |= (FL_DONE|FL_ABP|FL_NEVERMARK);
+    SetTilePosition(new,tilex,tiley);
+    SetVisiblePosition(new,new->x,new->y);
+    new->obclass = b_darkmonkobj;
+    new->which = ACTOR;
+    new->z = nominalheight;
+    if (SNAKELEVEL == 2)
+        NewState(new,&s_darkmonkfastspawn);
+    else
+        NewState(new,&s_darkmonkhspawn);
+#endif
+
+}
+
+void SpawnGunThingy(classtype which, int tilex, int tiley, int dir)
+{
+#if (SHAREWARE == 1)
+    which = which;
+    tilex = tilex;
+    tiley = tiley;
+    dir  = dir;
+
+    Error("no emplacements allowed in shareware!");
+#else
+    SpawnNewObj(tilex,tiley,&s_gunstand,which);
+
+
+    if (!loadedgame)
+        gamestate.killtotal++;
+
+    PreCacheActor(patrolgunobj,0);
+
+    new->hitpoints = starthitpoints[gamestate.difficulty][which];
+    new->dir = dir*2;
+//  new->speed = 0x500;
+//  ParseMomentum(new,dirangle8[new->dir]);
+    new->flags |= (FL_BLOCK|FL_SHOOTABLE);
+#endif
+}
+
+
+void SpawnFourWayGun(int tilex, int tiley)
+{
+#if (SHAREWARE == 1)
+    tilex = tilex;
+    tiley = tiley;
+    Error("no 4-way emplacements allowed in shareware!");
+#else
+
+
+    SpawnNewObj(tilex,tiley,&s_4waygun,patrolgunobj);
+    if (!loadedgame)
+        gamestate.killtotal++;
+
+    PreCacheActor(patrolgunobj,0);
+    new->temp1 = -1;
+    new->hitpoints = starthitpoints[gamestate.difficulty][patrolgunobj]*3;
+    new->flags |= (FL_BLOCK|FL_SHOOTABLE);
+#endif
+}
+
+
+
+
+/*
+=======================================================================
+=
+=                          NON-SHAREWARE CODE
+=
+=======================================================================
+*/
+
+#if (SHAREWARE == 0)
+
+void T_BoulderSpawn(objtype*ob)
+{   objtype *tactor;
+    int dx,dy,cl;
+
+    if (!(ob->flags & FL_ACTIVE))
+        return;
+
+    else if (!ob->ticcount)
+    {   for(tactor = firstareaactor[ob->areanumber]; tactor; tactor = tactor->nextinarea)
+        {   cl = tactor->obclass;
+            if (tactor == ob)
+                continue;
+
+            if (!(tactor->flags & FL_SHOOTABLE))
+                continue;
+            dx = abs(tactor->x - ob->x);
+            if (dx > MINACTORDIST)
+                continue;
+            dy = abs(tactor->y - ob->y);
+            if (dy > MINACTORDIST)
+                continue;
+            if ((cl == b_heinrichobj) || (cl== b_darkmonkobj) ||
+                    (cl == b_darianobj) || (cl == b_robobossobj) ||
+                    (cl == pillarobj) || (cl == wallopobj) ||
+                    (cl == boulderobj))
+                return;
+            else break;
+        }
+
+
+        SpawnNewObj(ob->tilex,ob->tiley,&s_boulderdrop1,boulderobj);
+        new->z = 0;
+        new->dir = ob->dir;
+        //new->angle = dirangle8[new->dir];
+        new->speed = 0x4000;
+        ParseMomentum(new,dirangle8[new->dir]);
+        new->flags |= (FL_BLOCK|FL_NOFRICTION);
+        new->flags &= ~FL_SHOOTABLE;
+        new->whatever = ob;
+        if (tactor)
+            new->target = tactor;
+        MakeActive(new);
+        new->flags |= FL_ABP;
+
+    }
+
+}
+
+void T_BoulderDrop(objtype*ob)
+{   int dx,dy,dz;
+    objtype * tactor;
+    statetype *tstate;
+
+
+    if (ob->state == &s_boulderdrop12)
+    {
+
+        if (ob->z == nominalheight)
+            NewState(ob,&s_boulderroll1);
+        else if (ob->momentumz)
+        {   ob->z += (ob->momentumz>>16);
+            ob->momentumz += (GRAVITY<<1);
+            if (ob->z > nominalheight)
+            {   ob->z = nominalheight;
+                ob->momentumz = 0;
+                //ob->flags &= ~FL_NOFRICTION;
+            }
+        }
+        else if (!ob->temp1)
+        {   ob->momentumz = (GRAVITY<<6);
+            ob->temp1  = 1;
+        }
+
+    }
+
+    if (ob->ticcount)
+        return;
+    if (ob->state->condition & SF_SOUND)
+
+        SD_PlaySoundRTP(SD_BOULDERFALLSND,ob->x,ob->y);
+    tactor = (objtype*)(ob->target);
+    if (tactor && (!(tactor->flags & FL_DYING)))
+    {   dx = tactor->x - ob->x;
+        dy = tactor->y - ob->y;
+        dz = tactor->z - ob->z;
+        if ((abs(dx) < MINACTORDIST) && (abs(dy) < MINACTORDIST) &&
+                (abs(dz) < 50))
+        {   if (tactor->obclass != playerobj)
+            {   tactor->momentumx = tactor->momentumy = tactor->momentumz = 0;
+                tactor->flags |= FL_DYING;
+                tactor->hitpoints = 0;
+                if (gamestate.violence < vl_high)
+                {   if ((tstate = UPDATE_STATES[CRUSH][tactor->obclass - lowguardobj])!=NULL)
+                        NewState(tactor,tstate);
+
+                    //else
+                    //Error("\n\Null low-violence crush state in boulder drop, instance of %s",debugstr[tactor->obclass]);
+                }
+                else
+                {   tactor->shapeoffset = 0;
+                    //tactor->flags|=FL_HBM;
+                    NewState(tactor,&s_guts1);
+                }
+            }
+            else
+            {   DamageThing(tactor,200);
+                Collision(tactor,ob,0,0);
+                M_CheckPlayerKilled(tactor);
+            }
+            SD_PlaySoundRTP(SD_ACTORSQUISHSND,tactor->x,tactor->y);
+            ob->target = NULL;
+        }
+
+    }
+}
+
+
+void CheckCrush(objtype*ob)
+{
+    objtype *temp;
+    int dx,dy,dz;
+
+    for(temp = PLAYER[0]; temp != PLAYER[numplayers-1]->next; temp=temp->next)
+    {
+        if (ob->flags & FL_DYING)
+            continue;
+
+        dx = abs(temp->x - ob->x);
+        if (dx > MINACTORDIST)
+            continue;
+
+        dy = abs(temp->y - ob->y);
+        if (dy > MINACTORDIST)
+            continue;
+
+        dz = abs(temp->z - ob->z);
+        if (dz > (MINACTORDIST>>10))
+            continue;
+
+        if (!ob->ticcount)
+            DamageThing(temp,EnvironmentDamage(ob));
+        Collision(temp,ob,ob->momentumx-temp->momentumx,ob->momentumy-temp->momentumy);
+        M_CheckPlayerKilled(temp);
+    }
+}
+
+
+void T_BoulderMove(objtype*ob)
+{
+
+
+    if (MAPSPOT(ob->tilex,ob->tiley,1) == 395)
+    {   NewState(ob,&s_bouldersink1);
+        return;
+    }
+    if (NOMOM)
+        ParseMomentum(ob,dirangle8[ob->dir]);
+    if ((!ob->ticcount) && (ob->state->condition & SF_SOUND) &&
+            areabyplayer[ob->areanumber])
+        SD_PlaySoundRTP(BAS[ob->obclass].operate,ob->x,ob->y);
+    SelectPathDir(ob);
+
+}
+
+
+/*
+=========================================================================
+=
+=                           Boss Functions
+=
+=========================================================================
+*/
+
+//***************************** Esau ************************************
+
+
+enum {
+    ESAU_USING_HOLES=1,
+    ESAU_LEAVING_CONTROL_ROOM,
+    ESAU_USING_TOUCH_PEDASTALS,
+    ESAU_CHASING_PLAYER
+};
+
+
+
+
+void T_EsauWait(objtype*ob)
+{
+    int dist;
+
+    dist = FindDistance(ob->tilex-PLAYER[0]->tilex,ob->tiley-PLAYER[0]->tiley);
+    MISCVARS->ESAU_SHOOTING = false;
+
+    if (ob->dirchoosetime)
+        ob->dirchoosetime --;
+
+    if ((dist>81) || (dist<36))
+    {
+        if (CheckLine(ob,PLAYER[0],MISSILE))
+        {
+            NewState(ob,&s_darianshoot1);
+            ob->momentumx = ob->momentumy = 0;
+        }
+        return;
+    }
+    else if ((!ob->dirchoosetime) && (CheckLine(ob,PLAYER[0],SHOOT)))
+    {
+        NewState(ob,&s_dariandefend1);
+        ob->dirchoosetime = (GameRandomNumber("T_EsauWait",0) % 35) + 17;//35;
+        return;
+    }
+}
+
+
+void T_EsauRise(objtype*ob)
+{
+    int newarea,oldarea;
+
+    // if (gamestate.victoryflag)
+    // return;
+
+    if (!ob->ticcount)
+    {   //Debug("\n tx before: %d, ty before: %d",
+        //         ob->targettilex,ob->targettiley);
+
+        SelectTouchDir(ob);
+        if (ob->targettilex || ob->targettiley)
+        {   //Debug("\n ob->tilex: %d, ob->tiley: %d, targettilex: %d, targettiley: %d",
+            //         ob->tilex, ob->tiley, ob->targettilex, ob->targettiley);
+
+            SetTilePosition(ob,ob->targettilex,ob->targettiley);
+            SetVisiblePosition(ob,ob->x,ob->y);
+            oldarea = ob->areanumber;
+            newarea = AREANUMBER(ob->tilex,ob->tiley);
+            if (oldarea != newarea)
+            {
+                RemoveFromArea(ob);
+                ob->areanumber = newarea;
+                MakeLastInArea(ob);
+            }
+        }
+        else
+            MISCVARS->EPOP[ob->temp3].x = MISCVARS->EPOP[ob->temp3].y = 0;
+
+        ob->dirchoosetime= (GameRandomNumber("T_EsauRise",0) % 35) + 17;
+        MISCVARS->ESAU_HIDING = false;
+        MISCVARS->ESAU_SHOOTING = true;
+        ob->flags |= FL_SHOOTABLE;
+    }
+}
+
+
+
+void T_EsauChase(objtype*ob)
+{
+    int dx,dy,chance,dist;
+    statetype *temp;
+
+
+
+    if ((ob->tilex == ob->targettilex) && (ob->tiley == ob->targettiley))
+    {
+        if (MISCVARS->DSTATE == ESAU_USING_HOLES)
+        {
+            MISCVARS->ESAU_HIDING = true;
+            MISCVARS->ESAU_SHOOTING = false;
+            SD_PlaySoundRTP(SD_DARIANHIDESND,ob->x,ob->y);
+            NewState(ob,&s_dariansink1);
+            ob->flags &= ~FL_SHOOTABLE;
+            return;
+        }
+        else if (MISCVARS->DSTATE == ESAU_LEAVING_CONTROL_ROOM)
+        {
+            if (!MISCVARS->doorcount)
+            {
+                SetTilePosition(ob,ob->tilex,ob->tiley);
+                SetVisiblePosition(ob,ob->x,ob->y);
+            }
+            MISCVARS->doorcount ++;
+            if (MISCVARS->doorcount == 4)
+                MISCVARS->DSTATE = ESAU_USING_HOLES;
+            else // hack to FORCE esau to walk through door
+            {
+                switch (ob->temp1)
+                {
+                case east:
+                    ob->targettilex ++;
+                    break;
+                case west:
+                    ob->targettilex --;
+                    break;
+                case north:
+                    ob->targettiley --;
+                    break;
+                case south:
+                    ob->targettiley ++;
+                    break;
+                }
+            }
+            SelectTouchDir(ob);
+            return;
+        }
+    }
+
+    if (touchsprite && (touchsprite->itemnumber == stats[stat_dariantouch].type))
+    {
+        dx = touchsprite->x - ob->x;
+        dy = touchsprite->y - ob->y;
+
+        if (((dx > -0x5000) && (dx < 0x5000)) &&
+                ((dy > -0x5000) && (dy < 0x5000)))
+        {
+            SD_PlaySoundRTP(SD_DARIANGONNAUSESND,ob->x,ob->y);
+            NewState(ob,&s_darianuse1);
+            return;
+        }
+    }
+
+    if (ob->dirchoosetime)
+        ob->dirchoosetime --;
+
+    if (NOMOM || (!ob->dirchoosetime))
+    {
+        SelectTouchDir(ob);
+        ob->dirchoosetime = M_CHOOSETIME(ob);
+    }
+    else
+        ActorMovement(ob);
+
+
+    if (!ob->ticcount)
+    {
+        if (CheckLine(ob,PLAYER[0],MISSILE))   // got a shot at player?
+        {
+            if (Near(ob,PLAYER[0],1))
+                chance = 300;
+            else
+            {
+                dx = abs(PLAYER[0]->tilex-ob->tilex);
+                dy = abs(PLAYER[0]->tiley-ob->tiley);
+                dist = (dx>dy)?dx:dy;
+                chance = 400/dist;
+            }
+            if (GameRandomNumber("T_EsauChase",0) <chance)
+            {
+                if ((temp=M_S(AIM)) != NULL)
+                {
+                    NewState(ob,temp);
+                    ob->dirchoosetime = 0;
+                    ob->momentumx = ob->momentumy = 0;
+                    SetVisiblePosition(ob,ob->x,ob->y);
+                    return;
+                }
+            }
+            if (MISCVARS->ESAU_SHOOTING)
+            {
+                SetVisiblePosition(ob,ob->x,ob->y);
+                return;
+            }
+        }
+    }
+}
+
+
+void T_EsauSpears(objtype*ob)
+{
+
+    if (ob->ticcount == (ob->state->tictime>>1)-1)
+    {
+        OLDTILEX = PLAYER[0]->tilex;
+        OLDTILEY = PLAYER[0]->tiley;
+    }
+
+    else if (!ob->ticcount)
+    {
+        SpawnNewObj(OLDTILEX,OLDTILEY,&s_speardown1,spearobj);
+        new->flags |= FL_ABP;
+        MakeActive(new);
+    }
+}
+
+
+
+void FindDoor(objtype*ob)
+{
+    int i,area1,area2,min,curr,
+        dest1x,dest1y,dest2x,dest2y,
+        d1,d2;
+
+    dirtype tdir1,tdir2;
+    doorobj_t*dr;
+
+    min = 0x7fffffff;
+    for(i=0; i<doornum; i++)
+    {
+        dr = doorobjlist[i];
+        if (dr->vertical)
+        {
+            area1 = MAPSPOT(dr->tilex-1,dr->tiley,0)-AREATILE;
+            dest1x = dr->tilex-1;
+            dest1y = dr->tiley;
+            tdir1 = east;
+            area2 = MAPSPOT(dr->tilex+1,dr->tiley,0)-AREATILE;
+            dest2x = dr->tilex+1;
+            dest2y = dr->tiley;
+            tdir2 = west;
+        }
+        else
+        {
+            area1 = MAPSPOT(dr->tilex,dr->tiley-1,0)-AREATILE;
+            dest1x = dr->tilex;
+            dest1y = dr->tiley-1;
+            tdir1 = south;
+            area2 = MAPSPOT(dr->tilex,dr->tiley+1,0)-AREATILE;
+            dest2x = dr->tilex;
+            dest2y = dr->tiley+1;
+            tdir2 = north;
+        }
+
+//============================================================
+#define CheckMinDist(destx,desty,dir)                    \
+   {                                                     \
+   curr = FindDistance(destx-ob->tilex,desty-ob->tiley); \
+   if (curr < min)                                       \
+      {                                                  \
+      min = curr;                                        \
+      ob->targettilex = destx;                           \
+      ob->targettiley = desty;                           \
+      ob->temp1 = dir;                                   \
+      }                                                  \
+   }
+//============================================================
+
+        if (area1 == ob->areanumber)
+        {
+            if (area1 == area2)
+            {
+                d1 = FindDistance(dest1x-ob->tilex,dest1y-ob->tiley);
+                d2 = FindDistance(dest2x-ob->tilex,dest2y-ob->tiley);
+                if (d2 < d1) //swap areas
+                {
+                    CheckMinDist(dest2x,dest2y,tdir2);
+                    continue;
+                }
+            }
+
+            CheckMinDist(dest1x,dest1y,tdir1);
+
+        }
+        else if (area2 == ob->areanumber)
+            CheckMinDist(dest2x,dest2y,tdir2);
+
+    }
+}
+
+
+int FindTouch(objtype *ob)
+{
+    int i,curr,min,tx,ty,noneleft;
+    statobj_t* tempstat;
+
+
+    min = 0x7fffffff;
+    noneleft = 1;
+    for(i=0; i<MISCVARS->nexttouch; i++)
+    {
+        if (MISCVARS->ETOUCH[i].x || MISCVARS->ETOUCH[i].y)
+        {
+            noneleft = 0;
+            tx = MISCVARS->ETOUCH[i].x;
+            ty = MISCVARS->ETOUCH[i].y;
+            tempstat = sprites[tx][ty];
+            curr = FindDistance(tx-ob->tilex,ty-ob->tiley);
+
+            if (curr < min)
+            {
+                min = curr;
+                ob->targettilex = tx;
+                ob->targettiley = ty;
+                touchsprite = tempstat;
+            }
+        }
+    }
+    return (!noneleft);
+}
+
+
+
+
+typedef enum
+{
+    down_in_a_hole=-1,
+    no_holes_available=0,
+    holes_unreachable=1,
+    hole_targetted=2
+
+} hiding_status;
+
+
+
+hiding_status HoleStatus(objtype*ob)
+{
+    int i,tx,ty,dist,noneleft,invisible,curr,min;
+    tpoint dummy,*dptr = &dummy;
+    objtype *tactor;
+    _2Dpoint *tdptr;
+
+    min = 0x7fffffff;
+    noneleft = 1;
+
+
+
+    for(i=0; i<MISCVARS->nextpop; i++)
+    {
+        tdptr = &(MISCVARS->EPOP[i]);
+
+        if (tdptr->x || tdptr->y)
+        {
+            tactor = (objtype*)actorat[tdptr->x][tdptr->y];
+            if (tactor && (tactor->obclass == pillarobj))
+            {
+                tdptr->x = 0;
+                tdptr->y = 0;
+                MISCVARS->popsleft --;
+            }
+        }
+    }
+
+
+    if (MISCVARS->popsleft > 1)
+    {
+        for(i=0; i<MISCVARS->nextpop; i++)
+        {
+            tdptr = &(MISCVARS->EPOP[i]);
+
+            if (tdptr->x || tdptr->y)
+            {
+                tx = tdptr->x;
+                ty = tdptr->y;
+
+                if ((PLAYER[0]->tilex == tx) || (PLAYER[0]->tiley == ty))
+                    continue;
+
+                if (MISCVARS->ESAU_HIDING)
+                {
+                    dist = FindDistance(PLAYER[0]->tilex-tx,PLAYER[0]->tiley-ty);
+                    if ((ob->tilex == tx) && (ob->tiley == ty) && (MISCVARS->popsleft != 1))
+                        continue;
+                    noneleft = 0;
+                    if ((MAPSPOT(tx,ty,0)-AREATILE) == ob->areanumber)
+                    {
+                        ob->targettilex = tx;
+                        ob->targettiley = ty;
+                        ob->temp3 = i;
+                        if ((dist < 81) && (dist > 36))
+                            return down_in_a_hole;
+                    }
+                }
+
+                else if (!MISCVARS->ESAU_SHOOTING)
+                {
+                    curr = FindDistance(tx-ob->tilex,ty-ob->tiley);
+                    if (curr < min)
+                    {
+                        min = curr;
+                        noneleft = 0;
+                        dptr->which = ACTOR;
+                        SetTilePosition(dptr,tx,ty);
+                        //dptr->x = (tx << TILESHIFT) + TILEGLOBAL/2;
+                        //dptr->y = (ty << TILESHIFT) + TILEGLOBAL/2;
+                        dptr->z = ob->z;
+                        invisible = 0;
+                        if ((!CheckLine(ob,dptr,SHOOT)) && (MISCVARS->DSTATE != ESAU_USING_HOLES))
+                        {
+                            invisible = 1;
+                            MISCVARS->DSTATE = ESAU_LEAVING_CONTROL_ROOM;
+                        }
+                        else
+                            MISCVARS->DSTATE = ESAU_USING_HOLES;
+                        ob->targettilex = tx;
+                        ob->targettiley = ty;
+                    }
+                }
+            }
+        }
+    }
+
+    if (MISCVARS->ESAU_HIDING)
+        return down_in_a_hole;
+
+    if (noneleft)
+    {
+        MISCVARS->DSTATE = ESAU_CHASING_PLAYER;
+        return  no_holes_available;
+    }
+
+    if (invisible) //leave present room
+        return holes_unreachable;
+
+    return hole_targetted;
+}
+
+
+void SelectTouchDir (objtype *ob)
+{
+    int dx,dy,noneleft,invisible;
+    hiding_status hole;
+
+
+    dirtype d[3];
+    dirtype tdir, olddir, turnaround;
+
+
+    olddir=ob->dir;
+    turnaround= opposite[olddir];
+
+
+    invisible = 0;
+    noneleft = 1;
+
+    if (!MISCVARS->notouch)
+    {
+        if (!FindTouch(ob))
+            MISCVARS->notouch = 1;
+        else
+            MISCVARS->DSTATE = ESAU_USING_TOUCH_PEDASTALS;
+    }
+
+    else if ((!MISCVARS->noholes) && (MISCVARS->DSTATE != ESAU_LEAVING_CONTROL_ROOM))
+    {
+        hole = HoleStatus(ob);
+
+        switch(hole)
+        {
+        case down_in_a_hole:
+            return;
+
+        case no_holes_available:
+            MISCVARS->noholes = 1;
+            break;
+
+        case holes_unreachable:
+            FindDoor(ob);
+            break;
+
+        default:
+            break;
+        }
+    }
+
+    else if (MISCVARS->DSTATE == ESAU_CHASING_PLAYER)
+
+        // only gets here if all gimmicks (touch tables,
+        // holes) are inoperative
+    {
+        ob->flags |= FL_SHOOTABLE;
+        ob->targettilex = PLAYER[0]->tilex;
+        ob->targettiley = PLAYER[0]->tiley;
+    }
+    /*
+    if (DSTATE == SDOOR)
+    {dx = ((ob->targettilex<<16)+TILEGLOBAL/2) - ob->x;
+       dy = ob->y - ((ob->targettiley<<16)+TILEGLOBAL/2);
+       angle = atan2_appx(dx,dy);
+       ZEROMOM;
+       ParseMomentum(ob,angle);
+       ActorMovement(ob);
+       if (ob->momentumx || ob->momentumy)
+       {ob->angle = angle;
+       ob->dir = angletodir[ob->angle];
+       return;
+       }
+    }
+    else */
+    dx = ob->targettilex - ob->tilex;
+    dy = ob->tiley - ob->targettiley;
+
+
+
+
+    d[1]=nodir;
+    d[2]=nodir;
+
+
+    if (dx>0)
+        d[1]= east;
+    else if (dx<0)
+        d[1]= west;
+    if (dy>0)
+        d[2]=north;
+    else if (dy<0)
+        d[2]=south;
+
+
+    if (GameRandomNumber("SelectTouchDir",0)<128)
+    {
+        tdir=d[1];
+        d[1]=d[2];
+        d[2]=tdir;
+    }
+
+    ZEROMOM;
+
+
+    if (d[1]!=nodir)
+        M_CHECKDIR(ob,d[1]);
+
+
+    if (d[2]!=nodir)
+        M_CHECKDIR(ob,d[2]);
+
+
+
+    if (GameRandomNumber("SelectTouchDir",ob->obclass)>128)   //randomly determine direction of search
+    {
+        for (tdir=north; tdir<=west; tdir++)
+        {
+            if (tdir!=turnaround)
+                M_CHECKDIR(ob,tdir);
+        }
+    }
+    else
+    {
+        for (tdir=west; tdir>=north; tdir--)
+        {
+            if (tdir!=turnaround)
+                M_CHECKDIR(ob,tdir);
+        }
+    }
+
+    if (turnaround !=  nodir)
+        M_CHECKDIR(ob,turnaround);
+
+
+    if (olddir!=nodir)
+        M_CHECKDIR(ob,olddir);
+
+}
+
+
+
+
+//************** Krist ****************************************************
+
+
+
+void CheckRunover(objtype*ob)
+{   int dx,dy,dz;
+
+    dx = abs(PLAYER[0]->x - ob->x);
+    if (dx > MINACTORDIST)
+        return;
+
+    dy = abs(PLAYER[0]->y - ob->y);
+    if (dy > MINACTORDIST)
+        return;
+
+    dz = abs(PLAYER[0]->z - ob->z);
+    if (dz > 10)
+        return;
+
+    locplayerstate->heightoffset = 18 + locplayerstate->playerheight;
+    locplayerstate->oldheightoffset = locplayerstate->heightoffset;
+    PLAYER[0]->temp2 = RENORMALIZE;
+    DamageThing(PLAYER[0],30);
+    Collision(PLAYER[0],ob,0,0);
+    M_CheckPlayerKilled(PLAYER[0]);
+
+}
+
+
+void T_HeinrichChase(objtype*ob)
+{
+    int   dx,dy,dist,chance,perpangle;
+// statetype *temp;
+    boolean doorok;
+
+    CheckRunover(ob);
+
+    //	ob->flags &= ~FL_DODGE;
+    if (CheckLine(ob,PLAYER[0],SIGHT))
+    {   ob->targettilex = PLAYER[0]->x;
+        ob->targettiley = PLAYER[0]->y;
+    }
+
+    if (!ob->ticcount)
+    {
+
+//	  if (gamestate.victoryflag)
+//		return;
+
+
+        if (CheckLine(ob,PLAYER[0],SHOOT))   // got a shot at PLAYER[0]?
+        {   dx = abs(ob->tilex - PLAYER[0]->tilex);
+            dy = abs(ob->tiley - PLAYER[0]->tiley);
+            dist = dx>dy ? dx : dy;
+            if (!dist || dist==1)
+                chance = 300;
+            else
+                chance = 2400/dist;
+
+            if (GameRandomNumber("T_HeinrichChase",0) <chance)
+            {   tpoint dummy,*dptr=&dummy;
+
+                if (Near(ob,PLAYER[0],2))
+                    goto cdoor;
+
+
+                perpangle = AngleBetween(ob,PLAYER[0]) + ANGLES/4;
+                Fix(perpangle);
+                dptr->which = ACTOR;
+                dptr->x = ob->x + FixedMul(0x10000l,costable[perpangle]);
+                dptr->y = ob->y - FixedMul(0x10000l,sintable[perpangle]);
+
+                dptr->z = ob->z;
+                if (!CheckLine(dptr,PLAYER[0],SHOOT))
+                    goto cdoor;
+
+                ob->target = PLAYER[0];
+                NewState(ob,M_S(AIM));
+                ob->dirchoosetime = 0;
+                return;
+
+
+            }
+        }
+
+    }
+
+cdoor:
+    doorok = NextToDoor(ob);
+
+
+    if (ob->dirchoosetime)
+        ob->dirchoosetime--;
+
+    if ((ob->flags & FL_STUCK) || (!ob->dirchoosetime) || doorok)
+    {   /*if ((ob->flags & FL_DODGE) && (!doorok))
+         SelectKristDodgeDir (ob);
+        else */
+        SD_PlaySoundRTP(SD_KRISTMOTORSND,ob->x,ob->y);
+        SelectKristChaseDir(ob);
+
+        ob->dirchoosetime = 4*M_CHOOSETIME(ob);
+
+    }
+
+    else
+    {   if (NOMOM)
+            ParseMomentum(ob,dirangle8[ob->dir]);
+        ActorMovement(ob);
+
+    }
+
+}
+
+void T_Heinrich_Defend (objtype*ob)
+{
+    CheckRunover(ob);
+
+    if (ob->dirchoosetime)
+        ob->dirchoosetime--;
+
+
+    if (MISCVARS->HRAMMING)
+        ParseMomentum(ob,dirangle8[ob->dir]);
+
+
+    if ((ob->flags & FL_STUCK) || (!ob->dirchoosetime))
+    {   if (MISCVARS->HRAMMING)
+        {   if (!Near(ob,PLAYER[0],3))
+            {   NewState(ob,M_S(CHASE));
+                ob->dirchoosetime = 0;
+                return;
+            }
+            SelectKristChaseDir(ob);
+        }
+        else if (MISCVARS->HMINING)
+        {   SelectMineDir(ob);
+            if (!MISCVARS->HMINING)
+                goto hchase;
+            ob->dirchoosetime = 5;//10;
+            return;
+        }
+        else
+hchase:
+            NewState(ob,M_S(CHASE));
+        ob->dirchoosetime = 0;
+    }
+    else
+    {   if (NOMOM)
+            ParseMomentum(ob,dirangle8[ob->dir]);
+        ActorMovement(ob);
+    }
+}
+
+
+void T_Heinrich_Out_of_Control(objtype*ob)
+{
+    if (ob->dirchoosetime)
+        ob->dirchoosetime --;
+    else
+    {
+        if (!ob->temp1)
+        {
+            SetGibSpeed(0x4000);
+            SpawnParticles(ob,RANDOM,120);
+            ResetGibSpeed();
+
+            NewState(ob,&s_dexplosion1);
+            SD_PlaySoundRTP(SD_EXPLODESND,ob->x,ob->y);
+        }
+        else
+        {
+            ob->dir = dirorder[ob->dir][PREV];
+            ob->angle = dirangle8[ob->dir];
+            if (ob->dir == (unsigned)ob->temp2)
+            {
+                if (ob->temp1 > 1)
+                    ob->temp1--;
+                else
+                {
+                    if (ob->temp3 == 7)
+                    {
+                        SpawnNewObj(ob->tilex,ob->tiley,&s_megaexplosions,inertobj);
+                        new->temp1 = 25;
+                        new->flags |= FL_ABP;
+                        MakeActive(new);
+                        SpawnNewObj(ob->tilex,ob->tiley,&s_superparticles,inertobj);
+                        new->flags |= FL_ABP;
+                        PARTICLE_GENERATOR = new;
+                        MakeActive(new);
+                    }
+                    if (ob->temp3)
+                        ob->temp3 --;
+                    else
+                        ob->temp1 --;
+                }
+            }
+
+            if (ob->temp1)
+                ob->dirchoosetime = ob->temp1;
+            else
+            {
+                ob->dirchoosetime = 70; // end of spin wait for megaexplosion
+                if (PARTICLE_GENERATOR)
+                {
+                    NewState(PARTICLE_GENERATOR,&s_megaremove);
+                    PARTICLE_GENERATOR = NULL;
+                }
+            }
+        }
+    }
+}
+
+
+
+
+void SelectKristChaseDir(objtype*ob)
+{   int dx,dy,tx,ty,angle;
+    dirtype dtry1,dtry2,tdir,olddir,next,prev,straight;
+//tpoint dummy,*dptr=&dummy;
+
+    olddir=ob->dir;
+
+
+//dptr->which = ACTOR;
+//dptr->z = ob->z;
+    if (ob->targettilex || ob->targettiley)
+    {   tx = ob->targettilex;
+        ty = ob->targettiley;
+        dx= tx - ob->x;
+        dy= ob->y - ty;
+        // SetFinePosition(dptr,tx,ty);
+        if ( ((dx < 0x20000) && (dx > -0x20000)) &&
+                ((dy < 0x20000) && (dy > -0x20000)))
+        {
+            dx= PLAYER[0]->x-ob->x;
+            dy= ob->y-PLAYER[0]->y;
+            // SetFinePosition(dptr,PLAYER[0]->x,PLAYER[0]->y);
+        }
+    }
+    else
+    {
+        dx= PLAYER[0]->x-ob->x;
+        dy= ob->y-PLAYER[0]->y;
+        //SetFinePosition(dptr,PLAYER[0]->x,PLAYER[0]->y);
+
+    }
+
+    angle = atan2_appx(dx,dy);
+    straight = angletodir[angle];
+    /*
+    if (ob->areanumber == PLAYER[0]->areanumber)
+      {//tpoint newpos1,newpos2;
+    	//dirtype leftdir;
+    	//int leftangle1,leftangle2;
+
+    	if (CheckLine(ob,&dummy,DIRCHECK))
+    	  {//Debug("\ntrying straight dir %d",straight);
+    		M_CHECKTURN(ob,straight);
+    		//Debug("\nstraight dir %d failed",straight);
+    	  }
+    	//leftdir = dirorder[straight][PREV];
+    	//leftangle1 = dirangle8[leftdir];
+    	//newpos1.which = ACTOR;
+    	//rightangle = dirangle[dirorder[straight][NEXT]];
+    	//newpos1.x = ob->x + FixedMul(0x10000,costable[leftangle1]);
+    	//newpos1.y = ob->y - FixedMul(0x10000,sintable[leftangle1]);
+    	//newpos1.z = ob->z;
+
+    	//leftangle2 = dirangle8[dirorder[leftdir][PREV]];
+    	//newpos2.which = ACTOR;
+    	//rightangle = dirangle[dirorder[straight][NEXT]];
+    	//newpos2.x = ob->x + FixedMul(0x10000,costable[leftangle2]);
+    	//newpos2.y = ob->y - FixedMul(0x10000,sintable[leftangle2]);
+    	//newpos2.z = ob->z;
+    	//if (CheckLine(&newpos1,&dummy,SHOOT))// || CheckLine(&newpos2,&dummy,SHOOT))
+    		{for(tdir = dirorder[straight][PREV];tdir != dirorder[straight][NEXT];tdir = dirorder[tdir][PREV])
+    			{//Debug("\ntried left-hand rule dir %d",tdir);
+    			 M_CHECKTURN(ob,tdir);
+    			}
+    		}
+    	//else
+    	  //{for(tdir = dirorder[straight][NEXT];tdir != dirorder[straight][PREV];tdir = dirorder[tdir][NEXT])
+    		 // {//Debug("\ntrying right-hand rule dir %d",tdir);
+    		 //	M_CHECKTURN(ob,tdir);
+    			//Debug("\nright-hand rule dir %d failed\n",tdir);
+    	  //	  }
+    	 // }
+      }
+    else*/
+    {   dtry1=nodir;
+        dtry2=nodir;
+
+        if (dx> ACTORSIZE)
+            dtry1= east;
+        else if (dx< -ACTORSIZE)
+            dtry1= west;
+        if (dy> ACTORSIZE)
+            dtry2=north;
+        else if (dy < -ACTORSIZE)
+            dtry2= south;
+
+
+        if (abs(dy)>abs(dx))
+        {   tdir=dtry1;
+            dtry1=dtry2;
+            dtry2=tdir;
+        }
+
+        //	ZEROMOM;
+        ob->momentumx = FixedMul (ob->momentumx, DEADFRICTION>>gamestate.difficulty);
+        ob->momentumy = FixedMul (ob->momentumy, DEADFRICTION>>gamestate.difficulty);
+
+
+        M_CHECKTURN(ob,straight);
+
+        if (dtry1 != nodir)
+            M_CHECKTURN(ob,dtry1);
+
+        if (dtry2 != nodir)
+            M_CHECKTURN(ob,dtry2);
+
+        if (dtry1 != nodir)
+        {   M_CHECKTURN(ob,dirorder[dtry1][NEXT]);
+            M_CHECKTURN(ob,dirorder[dtry1][PREV]);
+        }
+
+        for(tdir = dirorder[olddir][NEXT]; tdir != olddir; tdir = dirorder[tdir][NEXT])
+            M_CHECKTURN(ob,tdir);
+
+        ob->dir = olddir;
+    }
+
+
+
+}
+
+
+
+void T_KristLeft(objtype*ob)
+{   CheckRunover(ob);
+    ActorMovement(ob);
+    if (!ob->ticcount)
+    {   SD_PlaySoundRTP(SD_KRISTTURNSND,ob->x,ob->y);
+        if (ob->dir != (unsigned)ob->temp1)
+            ob->dir = dirorder[ob->dir][NEXT];
+        else
+        {   ob->temp1 = 0;
+            NewState(ob,&s_heinrichchase);
+        }
+    }
+
+}
+
+void T_KristRight(objtype*ob)
+{   CheckRunover(ob);
+    ActorMovement(ob);
+    if (!ob->ticcount)
+    {   SD_PlaySoundRTP(SD_KRISTTURNSND,ob->x,ob->y);
+        if (ob->dir != (unsigned)ob->temp1)
+            ob->dir = dirorder[ob->dir][PREV];
+        else
+        {   ob->temp1 = 0;
+            NewState(ob,&s_heinrichchase);
+        }
+    }
+}
+
+
+void T_KristCheckFire(objtype*ob)
+{   int perpangle,angle;
+    tpoint dummy;
+
+    if (!ob->ticcount)
+    {   angle = AngleBetween(ob,PLAYER[0]);
+
+        if (ob->state == &s_heinrichshoot1)
+            perpangle = angle + ANGLES/4;
+        else
+            perpangle = angle - ANGLES/4;
+
+        Fix(perpangle);
+
+
+        dummy.which = ACTOR;
+        dummy.x = ob->x + FixedMul(0x4000,costable[angle]) + FixedMul(0x4000l,costable[perpangle]) +
+                  FixedMul(PROJSIZE,costable[perpangle]); // offset ahead plus
+        // offset for left/right missile plus offset for missile
+        // radius (will missile reach player without hitting wall,etc.)
+
+        dummy.y = ob->y - FixedMul(0x4000,sintable[angle]) - FixedMul(0x4000l,sintable[perpangle]) -
+                  FixedMul(PROJSIZE,sintable[perpangle]);
+
+        dummy.x -= (FixedMul(PROJSIZE,costable[perpangle])<<1);
+
+        dummy.y += (FixedMul(PROJSIZE,sintable[perpangle])<<1);
+        dummy.z = ob->z;
+
+        if (!CheckLine(&dummy,PLAYER[0],SHOOT))
+        {   NewState(ob,&s_heinrichchase);
+            return;
+        }
+
+
+    }
+}
+
+
+
+void SelectMineDir(objtype*ob)
+{   int angle,missangle;
+    dirtype olddir,tdir,next,prev,destdir;
+    static int nummines=0;
+
+    if (!CheckLine(ob,PLAYER[0],SIGHT))
+    {   NewState(ob,M_S(CHASE));
+        MISCVARS->HMINING = 0;
+        return;
+    }
+
+    olddir = ob->dir;
+
+    angle = AngleBetween(ob,PLAYER[0]);
+    tdir = angletodir[angle];
+    destdir = opposite[tdir];
+
+    if (destdir != olddir)
+    {   next = dirorder[olddir][NEXT];
+        prev = dirorder[olddir][PREV];
+        if (dirdiff[destdir][next] < dirdiff[destdir][prev])
+            ob->dir = next;
+        else
+            ob->dir = prev;
+        return;
+    }
+
+    nummines ++;
+    missangle  = angle;
+    if (nummines == 2)
+        missangle -= (ANGLES/36);
+    else if (nummines == 3)
+        missangle += (ANGLES/36);
+
+    Fix(missangle);
+// if (missangle > (ANGLES - 1))
+//  missangle -= ANGLES;
+// else if (missangle < 0)
+//  missangle += ANGLES;
+
+
+    SpawnMissile(ob,h_mineobj,0x2000,missangle,&s_mine1,0xa000);
+    new->dirchoosetime = 140;
+    SD_PlaySoundRTP(SD_KRISTDROPSND,ob->x,ob->y);
+
+    if (nummines == 3)
+    {   MISCVARS->HMINING = 0;
+        nummines = 0;
+    }
+}
+
+
+
+void  A_HeinrichShoot(objtype* ob)
+{   int angle,perpangle;
+
+    if (!ob->ticcount)
+    {   angle = AngleBetween(ob,PLAYER[0]);
+        if (ob->state == &s_heinrichshoot4)
+            perpangle = angle + ANGLES/4;
+        else
+            perpangle = angle - ANGLES/4;
+
+        Fix(perpangle);
+
+        SpawnMissile(ob,missileobj,0x4000,angle,&s_missile1,0x8000);
+        SD_PlaySoundRTP(BAS[ob->obclass].fire,ob->x,ob->y);
+
+        SetFinePosition(new,new->x + FixedMul(0x4000l,costable[perpangle]),
+                        new->y - FixedMul(0x4000l,sintable[perpangle]));
+        SetVisiblePosition(new,new->x,new->y);
+    }
+
+
+}
+
+
+//***************************///////**************************************
+//***************************/ NME /**************************************
+//***************************///////**************************************
+
+
+
+
+
+void UpdateNMELinkedActors(objtype*ob)
+{
+    objtype *head,*wheels;
+    int oldarea;
+
+
+    head = (objtype*)(ob->whatever);
+    wheels = (objtype*)(ob->target);
+
+    oldarea = head->areanumber;
+
+    SetFinePosition(head,ob->x,ob->y);
+    SetFinePosition(wheels,ob->x,ob->y);
+    SetVisiblePosition(head,ob->x,ob->y);
+    SetVisiblePosition(wheels,ob->x,ob->y);
+
+    if (oldarea != ob->areanumber)
+    {
+        RemoveFromArea(head);
+        head->areanumber = ob->areanumber;
+        MakeLastInArea(head);
+        RemoveFromArea(wheels);
+        wheels->areanumber = ob->areanumber;
+        MakeLastInArea(wheels);
+    }
+
+}
+
+
+void T_OrobotChase(objtype*ob)
+{
+    int dx,dy;
+
+
+    if (CheckLine(ob,PLAYER[0],SIGHT))
+    {
+
+        ob->targettilex = PLAYER[0]->tilex;
+        ob->targettiley = PLAYER[0]->tiley;
+    }
+
+
+
+    if (!ob->ticcount)
+    {
+        if (NMEspincheck(ob))
+            return;
+
+        dx = PLAYER[0]->x - ob->x;
+        dy = ob->y - PLAYER[0]->y;
+        /*
+        if ((dx > -0x18000) && (dx < 0x18000) && (dy > -0x18000) && (dy < 0x18000))
+           {NewState(ob,&s_NMEavoid);
+           return;
+           }
+        */
+
+        if (CheckLine(ob,PLAYER[0],SIGHT))
+        {
+            int inrange;
+
+            switch(gamestate.difficulty)
+            {
+            case gd_baby:
+                inrange = Near(ob,PLAYER[0],6);
+                break;
+            case gd_easy:
+                inrange = Near(ob,PLAYER[0],9);
+                break;
+            case gd_medium:
+                inrange = Near(ob,PLAYER[0],12);
+                break;
+            case gd_hard:
+                inrange = 1;
+                break;
+            }
+
+            if ((!Near(ob,PLAYER[0],3)) && inrange)
+            {
+                SD_PlaySoundRTP(SD_NMEREADYSND,ob->x,ob->y);
+                if ((ob->hitpoints < 2000) && (GameRandomNumber("NME special attack",0) < 120))
+                {
+                    int next,prev;
+
+                    next = dirorder16[ob->dir][NEXT];
+                    prev = dirorder16[ob->dir][PREV];
+                    ob->targettilex = (angletodir[atan2_appx(dx,dy)]<<1);
+
+                    if (dirdiff16[prev][ob->targettilex] < dirdiff16[next][ob->targettiley])
+                        ob->temp3 = PREV;
+                    else
+                        ob->temp3 = NEXT;
+                    NewState(ob,&s_NMEspinfire);
+                }
+                else
+                {
+                    NewState(ob,&s_NMEwindup);
+                    ob->temp3 = 0;
+                }
+                //NewState((objtype*)(ob->target),&s_NMEwheelspin);
+
+                NewState((objtype*)(ob->target),&s_NMEwheels120);
+                return;
+            }
+        }
+    }
+
+    if (ob->dirchoosetime)
+        ob->dirchoosetime --;
+
+    if ((ob->flags & FL_STUCK) || (!ob->dirchoosetime))
+    {
+        SelectOrobotChaseDir(ob);
+        ob->dirchoosetime = 4;//8;
+    }
+
+    else
+    {
+        ActorMovement(ob);
+        UpdateNMELinkedActors(ob);
+    }
+}
+
+
+
+void T_Saucer(objtype*ob)
+{   int angle,dangle;
+
+    if (!ob->ticcount)  // if on track at end of each state, accelerate
+        // towards PLAYER[0]
+    {   if (ob->state->condition & SF_SOUND)
+            SD_PlaySoundRTP(SD_NMEREADYSND,ob->x,ob->y);
+        angle = AngleBetween(ob,PLAYER[0]);
+        dangle = ob->angle - angle;
+        if ((dangle > -(ANGLES/72)) && (dangle < (ANGLES/72)))
+        {   if (ob->speed < 0x10000)
+            {   ob->speed += 0x200;
+                ZEROMOM;
+                ParseMomentum(ob,ob->angle);
+            }
+        }
+        else // off track; zero mom. and select new dir.
+        {   ob->speed = 0x1000;
+            ZEROMOM;
+            ob->angle = angle;
+            ParseMomentum(ob,ob->angle);
+        }
+    }
+    MissileMovement(ob);
+
+
+}
+
+
+void T_NME_WindUp(objtype*ob)
+{   objtype *head,*wheels;
+
+    head = (objtype*)(ob->whatever);
+    wheels = (objtype*)(ob->target);
+
+    if (ob->dirchoosetime)
+    {   ob->dirchoosetime--;
+        return;
+    }
+
+    ob->dirchoosetime = 0;//3;
+
+    if (MISCVARS->NMErotate < 3)
+    {   head->dir = dirorder16[head->dir][NEXT];
+        MISCVARS->NMErotate ++;
+    }
+    else if (MISCVARS->NMErotate < 6)
+    {   head->dir = dirorder16[head->dir][PREV];
+        MISCVARS->NMErotate ++;
+    }
+    else if (MISCVARS->NMErotate < 9)
+    {   ob->dir = dirorder16[ob->dir][NEXT];
+        wheels->dir = ob->dir;
+        MISCVARS->NMErotate++;
+    }
+    else if (MISCVARS->NMErotate < 12)
+    {   ob->dir = dirorder16[ob->dir][PREV];
+        wheels->dir = ob->dir;
+        MISCVARS->NMErotate ++;
+    }
+    else
+    {   MISCVARS->NMErotate = 0;
+
+        NewState(ob,&s_NMEattack);
+        ob->dirchoosetime = 0;
+        //ob->dirchoosetime = 50 - (ob->shapeoffset >> 2) - (gamestate.difficulty << 2);//70;
+        if (!ob->temp2)
+            NewState((objtype*)(ob->whatever),&s_NMEhead1rl);
+        else
+            NewState((objtype*)(ob->whatever),&s_NMEhead2rl);
+        NewState(wheels,&s_NMEwheels2);
+    }
+
+}
+
+#define SPRAYDIST 0x12000
+
+void SelectOrobotChaseDir(objtype*ob)     // this code is for head
+{
+    int dx,dy,angle,tx,ty;
+    int tdir,olddir,nextdir,prevdir;
+    objtype* head,*wheels;
+
+
+
+    head = (objtype*)(ob->whatever);
+    wheels = (objtype*)(ob->target);
+    olddir=head->dir;
+
+findplayer:
+    if (ob->temp1 == -1)
+    {
+        if (ob->targettilex || ob->targettiley)
+        {
+            tx = (int)((ob->targettilex << TILESHIFT) + HALFGLOBAL1);
+            ty = (int)((ob->targettiley << TILESHIFT) + HALFGLOBAL1);
+            dx= tx - ob->x;
+            dy= ob->y - ty;
+            if (((dx <SPRAYDIST ) && (dx > -SPRAYDIST)) &&
+                    ((dy <SPRAYDIST ) && (dy > -SPRAYDIST)))
+            {
+                dx= PLAYER[0]->x-ob->x;
+                dy= ob->y - PLAYER[0]->y;
+            }
+        }
+        else
+        {
+            dx= PLAYER[0]->x - ob->x;
+            dy= ob->y - PLAYER[0]->y;
+        }
+
+        angle = atan2_appx(dx,dy);
+
+        tdir = (((angletodir[angle])<<1) & 0xf);
+    }
+    else
+    {
+        tdir = (ob->temp1 & 0xf);
+
+        if ((head->dir == (unsigned)tdir) && (ob->dir == (unsigned)tdir)) // increment
+            // tried dir if robot will attempt to move at tdir =>
+            // head and body are at move try dir
+        {   //Debug("\ntrying next queue dir %d",tdir);
+            MISCVARS->NMEdirstried ++;
+            if (MISCVARS->NMEdirstried == MISCVARS->NMEqueuesize) //gone through all queue entries
+            {   //Debug("\nqueue exhausted");
+                ob->temp1 = -1;
+                MISCVARS->NMEdirstried = 0;
+                goto findplayer;
+            }
+        }
+    }
+
+
+    if (tdir != olddir) //rotate head to new chase direction
+    {
+        nextdir = dirorder16[olddir][NEXT];
+        prevdir = dirorder16[olddir][PREV];
+        if (dirdiff16[tdir][nextdir] < dirdiff16[tdir][prevdir])
+            head->dir = nextdir;
+        else
+            head->dir = prevdir;
+        return;
+    }
+    //Debug("\nhead aligned to dir %d",tdir);
+
+    //oddir = ob->dir;
+    if (ob->dir != head->dir)   // align body and wheels with head
+    {
+        ZEROMOM;
+        NewState(wheels,&s_NMEwheels120);  //rotate wheels for spinning
+        nextdir = dirorder16[ob->dir][NEXT];
+        prevdir = dirorder16[ob->dir][PREV];
+        if (dirdiff16[head->dir][nextdir] < dirdiff16[head->dir][prevdir])
+            ob->dir = nextdir;
+        else
+            ob->dir = prevdir;
+        wheels->dir = ob->dir;
+        return;
+    }
+
+    // Debug("\nbody aligned to head at dir %d",ob->dir);
+
+    ZEROMOM;
+    ParseMomentum(ob,dirangle16[head->dir]);
+    // Debug("\ntrying to move at dir %d",head->dir);
+    ActorMovement(ob);
+    UpdateNMELinkedActors(ob);
+
+    if (ob->momentumx || ob->momentumy)
+    {
+        NewState(wheels,&s_NMEwheels2); // align wheels for movement
+        //Debug("\nmove at dir %d succesful, resetting queue",head->dir);
+        ob->temp1 = -1; //clear direction queue
+        return;
+    }
+    else if (ob->temp1 == -1) // if queue is empty
+        //make a queue of directions (byte packed)
+    {
+        //Debug("\nmove at dir %d failed and queue empty",head->dir);
+        ob->temp1 = 0;
+        MISCVARS->NMEdirstried = 0;
+        MISCVARS->NMEqueuesize = 0;
+
+        nextdir = ((tdir + 6) & 0xf);
+        prevdir = ((tdir - 6) & 0xf);
+
+        for(; MISCVARS->NMEqueuesize < 6; MISCVARS->NMEqueuesize += 2)
+        {
+            ob->temp1 <<= 4;
+            ob->temp1 += nextdir;
+            ob->temp1 <<= 4;
+            ob->temp1 += prevdir;
+            nextdir = ((nextdir-2) & 0xf);
+            prevdir = ((prevdir+2) & 0xf);
+
+        }
+#if 0
+        SoftError("\n straight dir: %d\n queue dirs ",tdir);
+        for(count = 0; count < MISCVARS->NMEqueuesize; count++)
+        {
+            SoftError("\n dir %d: %d",MISCVARS->NMEqueuesize-count,
+                      ((ob->temp1 >> (4*count)) &0xf)
+                     );
+
+        }
+#endif
+    }
+    else             // else goto next queue dir;
+    {
+        ob->temp1 >>= 4;
+    }
+
+}
+
+
+
+void T_NME_Explode(objtype*ob)
+{
+
+    if (ob->ticcount == 35)
+    {   objtype*head;
+        int op;
+
+        head = (objtype*)(ob->whatever);
+
+        op = FixedMul(GRAVITY,(head->z-25)<<16) << 1;
+        head->momentumz = -FixedSqrtHP(op);
+        head->momentumx = (GameRandomNumber("NME head momx",0) << 2);
+        head->momentumy = (GameRandomNumber("NME head momy",0) << 2);
+        head->hitpoints = 0;
+        head->flags |= FL_DYING;
+        NewState(head,&s_shootinghead);
+
+        //RemoveObj((objtype*)(ob->whatever)); // remove head
+    }
+    else if (!ob->ticcount)
+    {   ob->shapeoffset = 0;
+        NewState(ob,&s_explosion1);
+        SetGibSpeed(0x4000);
+        SpawnParticles(ob,gt_sparks,200);
+        ResetGibSpeed();
+        RemoveObj((objtype*)(ob->target));
+    }
+
+}
+
+void T_NME_HeadShoot(objtype*ob)
+{   //int randtheta,i,offx,offy;
+
+    ob->z += (ob->momentumz>>16);
+
+    /*if (ob->momentumz < 0)
+     {for(i=0;i<3;i++)
+     {randtheta = (GameRandomNumber("NME spark drop",0) << 3);
+      SpawnNewObj(ob->tilex,ob->tiley,&s_particle1,inertobj);
+      new->temp2 = 1;
+      offx = FixedMul(0x400,costable[randtheta]);
+      offy = -FixedMul(0x400,sintable[randtheta]);
+      new->x = new->drawx = ob->x + offx;
+      new->y = new->drawy = ob->y + offy;
+      new->z = ob->z-15;
+      new->flags |= (FL_NOFRICTION|FL_CRAZY|FL_ABP);
+      new->dir = west;
+      MakeActive(new);
+     }
+     }*/
+
+    ob->momentumz += GRAVITY;
+    if (ob->z >= (nominalheight+45))
+    {   ob->z = nominalheight+45;
+        if (ob->temp2)
+        {   ob->momentumz = -30000*ob->temp2;
+            ob->temp2--;
+        }
+        else
+        {   ob->momentumx = ob->momentumy = ob->momentumz = 0;
+            ob->shapeoffset = 0;
+            NewState(ob,&s_NMEheadexplosion);
+
+            return;
+        }
+    }
+    ActorMovement(ob);
+
+}
+
+
+boolean NMEspincheck(objtype*ob)
+{
+    int dx,dy,dz;
+
+    dx = abs(PLAYER[0]->x - ob->x);
+    dy = abs(PLAYER[0]->y - ob->y);
+    dz = abs(PLAYER[0]->z - ob->z);
+    if ((dx < 0x10000) && (dy < 0x10000) && (dz < 32))
+    {
+        NewState(ob,&s_NMEspinattack);
+        NewState((objtype*)(ob->target),&s_NMEwheelspin);
+        if (!ob->temp2)
+            NewState((objtype*)(ob->whatever),&s_NMEhead1);
+        else
+            NewState((objtype*)(ob->whatever),&s_NMEhead2);
+        ob->dirchoosetime = 1;
+        return true;
+    }
+    return false;
+}
+
+
+
+
+
+void T_NME_SpinAttack(objtype* ob)
+{   int mx,my,mz;
+    objtype*head,*wheels;
+
+
+
+    if (ob->ticcount == 30)  // knock player back
+    {   GetMomenta(PLAYER[0],ob,&mx,&my,&mz,0x4000);
+        DamageThing(PLAYER[0],20);
+        Collision(PLAYER[0],ob,mx,my);
+        M_CheckPlayerKilled(PLAYER[0]);
+    }
+    if (ob->dirchoosetime)
+        ob->dirchoosetime --;
+    else
+    {   head = (objtype*)(ob->whatever);
+        wheels = (objtype*)(ob->target);
+        wheels->dir = head->dir = ob->dir = dirorder16[dirorder16[ob->dir][NEXT]][NEXT];
+
+        ob->dirchoosetime = 1;
+    }
+
+
+}
+
+
+void T_NME_SpinFire(objtype*ob)
+{
+    int randtheta,oldyzangle,dx,dy,xydist,dz;
+    objtype *head,*wheels;
+
+
+    head = (objtype*)(ob->whatever);
+    wheels = (objtype*)(ob->target);
+
+    if (ob->dir != (unsigned)ob->targettilex)
+    {   ob->dir = head->dir = wheels->dir = dirorder16[ob->dir][ob->temp3];
+        return;
+    }
+
+    if (ob->dirchoosetime)
+    {   ob->dirchoosetime --;
+        return;
+    }
+
+    if (ob->temp3 < 20)
+    {   //randphi = (GameRandomNumber("NME generate phi",0) << 3) & ((ANGLES/2) -1);
+        if (GameRandomNumber("NME generate theta",0) < 128)
+            randtheta = (GameRandomNumber("NME generate theta",0)>>4);
+        else
+            randtheta = -(GameRandomNumber("NME generate theta",0)>>4);
+        dx = PLAYER[0]->x-ob->x;
+        dy = ob->y-PLAYER[0]->y;
+        if (GameRandomNumber("bcraft shoot up/down",0) < 128)
+            dz = 5;
+        else
+            dz = -5;
+        xydist = FindDistance(dx,dy);
+        randtheta += atan2_appx(dx,dy);
+        Fix(randtheta);
+        oldyzangle = ob->yzangle;
+        ob->yzangle = atan2_appx(xydist,dz<<10);
+        //ob->yzangle = randphi;
+        SD_PlaySoundRTP(BAS[ob->obclass].fire+1,ob->x,ob->y);
+        //wheels->dir = head->dir = ob->dir = dirorder16[dirorder16[ob->dir][NEXT]][NEXT];
+        SpawnMissile(ob,fireballobj,0x6000,randtheta,&s_NMEminiball1,0x10000);
+        ob->dirchoosetime = 1;
+        ob->yzangle = oldyzangle;
+        ob->temp3 ++;
+    }
+    else
+    {   ob->temp3 = 0;
+        NewState(ob,&s_NMEchase);
+        NewState((objtype*)(ob->target),&s_NMEwheels2);
+        if (!ob->temp2)
+            NewState((objtype*)(ob->whatever),&s_NMEhead1);
+        else
+            NewState((objtype*)(ob->whatever),&s_NMEhead2);
+
+
+    }
+
+
+}
+
+void T_NME_Attack(objtype*ob)
+{   int angle,perpangle,i;
+
+
+
+    if (NMEspincheck(ob))
+    {   //ob->temp3 = 0;
+        return;
+    }
+    if (ob->dirchoosetime)
+    {   ob->dirchoosetime --;
+        return;
+    }
+
+
+    if (!CheckLine(ob,PLAYER[0],SIGHT))
+    {   //ob->temp3 = 0;
+        //#if ((DEVELOPMENT == 1))
+        //Debug("\nCheckLine failed in NME Attack");
+        //#endif
+        NewState(ob,&s_NMEchase);
+        NewState((objtype*)(ob->target),&s_NMEwheels2);
+        if (!ob->temp2)
+            NewState((objtype*)(ob->whatever),&s_NMEhead1);
+        else
+            NewState((objtype*)(ob->whatever),&s_NMEhead2);
+        return;
+    }
+    //sound = BAS[ob->obclass].fire;
+    angle = AngleBetween(ob,PLAYER[0]);
+
+
+
+    if ((ob->temp3 == 0) || (ob->temp3 == 1)) //heatseek
+
+    {   SD_PlaySoundRTP(BAS[ob->obclass].fire+2,ob->x,ob->y);
+        angle = AngleBetween(ob,PLAYER[0]);
+        SpawnMissile(ob,missileobj,0x6000,angle,&s_missile1,0x8000);
+        if (ob->temp3 == 3)
+            perpangle = angle + ANGLES/4;
+        else
+            perpangle = angle - ANGLES/4;
+        Fix(perpangle);
+
+        new->temp1 = NME_HEATSEEKINGTYPE;
+        SetFinePosition(new,new->x + FixedMul(0x8000l,costable[perpangle]),
+                        new->y - FixedMul(0x8000l,sintable[perpangle]));
+        SetVisiblePosition(new,new->x,new->y);
+        if (!ob->temp3)
+            ob->dirchoosetime = 20;
+        else
+        {   ob->dirchoosetime = 35 - (ob->shapeoffset >> 2) - (gamestate.difficulty << 2);//70;
+            if (!ob->temp2)
+                NewState((objtype*)(ob->whatever),&s_NMEhead1);
+            else
+                NewState((objtype*)(ob->whatever),&s_NMEhead2);
+        }
+        ob->temp3 ++;
+
+    }
+
+    else if (ob->temp3 == 2)          // saucer
+    {   SpawnMissile(ob,NMEsaucerobj,0x1000,angle,&s_NMEsaucer1,0xc000);
+        new->flags |= FL_SHOOTABLE;
+        ob->temp3++;
+        ob->dirchoosetime = 35 - (ob->shapeoffset >> 2) - (gamestate.difficulty << 2);//70;
+        if (!ob->temp2)
+            NewState((objtype*)(ob->whatever),&s_NMEhead1rl);
+        else
+            NewState((objtype*)(ob->whatever),&s_NMEhead2rl);
+    }
+
+    else if ((ob->temp3 == 3) || (ob->temp3 == 4))    // drunk
+    {   SD_PlaySoundRTP(BAS[ob->obclass].fire+2,ob->x,ob->y);
+        if (!ob->temp3)
+            perpangle = angle + ANGLES/4;
+        else
+            perpangle = angle - ANGLES/4;
+        Fix(perpangle);
+        for(i=0; i<(2+gamestate.difficulty); i++)
+        {
+            SpawnMissile(ob,missileobj,0x6000,angle,&s_missile1,0x8000);
+            new->temp1 = NME_DRUNKTYPE;
+            SetFinePosition(new,new->x + FixedMul(0x8000l,costable[perpangle]),
+                            new->y - FixedMul(0x8000l,sintable[perpangle]));
+            SetVisiblePosition(new,new->x,new->y);
+        }
+
+        if (ob->temp3 == 3)
+            ob->dirchoosetime = 20;
+        else
+        {   ob->temp3 = 0;
+            NewState(ob,&s_NMEchase);
+            if (!ob->temp2)
+                NewState((objtype*)(ob->whatever),&s_NMEhead1);
+            else
+                NewState((objtype*)(ob->whatever),&s_NMEhead2);
+        }
+
+        ob->temp3 ++;
+
+    }
+
+
+
+}
+
+
+
+//================== Tom/Snake ============================================
+
+
+
+
+
+void T_DarkSnakeSpawn(objtype*ob)
+{
+    objtype * linkinfront;
+
+    if (((ob->state == &s_darkmonkhspawn) && (!(ob->ticcount%8))) ||
+            ((ob->state == &s_darkmonkfastspawn) && (!(ob->ticcount%4))))
+    {
+        GetNewActor();
+        MakeActive(new);
+        SetFinePosition(new,ob->x,ob->y);
+        SetVisiblePosition(new,ob->x,ob->y);
+        new->z = nominalheight;
+        new->areanumber = MAPSPOT(new->tilex,new->tiley,0)-AREATILE;
+        MakeLastInArea(new);
+        new->obclass = b_darksnakeobj;
+        new->which = ACTOR;
+        new->angle = AngleBetween(ob,PLAYER[0]);
+        new->dir = angletodir[new->angle];
+        if (SNAKELEVEL == 1)
+            new->speed = 0x5000;
+        else if (SNAKELEVEL == 2)
+            new->speed = 0x5800;
+        else
+            new->speed = 0x2000;
+
+
+        new->hitpoints = 1000;
+        new->dirchoosetime = 0;
+        new->door_to_open = -1;
+
+        new->flags |= (FL_ABP|FL_NOFRICTION|FL_SHOOTABLE|FL_BLOCK);
+
+        if (ob->whatever)
+        {
+            linkinfront = (objtype*)(ob->whatever);
+            linkinfront->whatever = new;
+            new->target = linkinfront;
+            new->targettilex = linkinfront->x;
+            new->targettiley = linkinfront->y;
+            new->angle = AngleBetween(new,linkinfront);
+            new->dir = angletodir[new->angle];
+            new->flags |= FL_NEVERMARK;
+            ParseMomentum(new,new->angle);
+            NewState(new,&s_darkmonksnakelink);
+        }
+
+        else
+        {
+            SNAKEHEAD = new;
+            if (SNAKELEVEL == 3)
+                NewState(new,&s_darkmonkhead);
+            else if (SNAKELEVEL == 1)
+            {
+                NewState(new,&s_snakefindpath);
+                new->flags |= FL_ATTACKMODE;
+            }
+            else if (SNAKELEVEL == 2)
+            {
+                NewState(new,&s_snakepath);
+                new->angle = 3*ANGLES/4;
+                new->dir = angletodir[new->angle];
+                new->flags |= FL_ATTACKMODE;
+
+            }
+            ob->targettilex = ob->targettiley = 0;
+            ParseMomentum(new,new->angle);
+        }
+
+        if (!ob->ticcount)
+            SNAKEEND = new;
+
+        ob->whatever = new;
+
+    }
+}
+
+
+void T_GenericMove(objtype*ob)
+{   int dx,dy;
+
+    if (ob->temp3 == -1)
+        return;
+
+
+    if (!(SNAKEHEAD->flags & FL_ATTACKMODE))
+        return;
+
+    if (ob->hitpoints <= 0)
+    {   KillActor(ob);
+        ob->temp3 = 0;
+        return;
+    }
+
+    if (!ob->ticcount)
+    {   if (ob->state == &s_darkmonkredlink)
+            ob->temp3 = 0;
+        else if ((ob!=SNAKEEND) && (ob->state == &s_redlinkhit))
+            NewState((objtype*)(ob->whatever),&s_redlinkhit);
+    }
+
+    dx = ob->targettilex-ob->x;
+    dy = ob->y-ob->targettiley;
+    if ((dx > -0xa000) && (dx < 0xa000) && (dy > -0xa000) && (dy < 0xa000))
+    {   if (ob->temp1 && ob->temp2)
+        {   dx = ob->temp1 - ob->x;
+            dy = ob->y - ob->temp2;
+            ZEROMOM;
+            /*
+            if ((ob->targettilex == ob->temp1) && (ob->targettiley == ob->temp2))
+            return; */
+            //ob->x = ob->drawx = ob->targettilex;
+            //ob->y = ob->drawy = ob->targettiley;
+            //ob->tilex = ob->x >> TILESHIFT;
+            //ob->tiley = ob->y >> TILESHIFT;
+            //#if ((DEVELOPMENT == 1))
+            //	Debug("\nfollower %d being moved to targetx %4x and targety %4x",
+            //	  ob-SNAKEHEAD,ob->x,ob->y);
+            // #endif
+            ob->targettilex = ob->temp1;
+            ob->targettiley = ob->temp2;
+#if (0)
+            Debug("\nfollower %d's new targetx %4x, targety %4x",
+                  ob-SNAKEHEAD,ob->temp1,ob->temp2);
+#endif
+            ob->angle = atan2_appx(dx,dy);
+            ob->dir = angletodir[ob->angle];
+            ParseMomentum(ob,ob->angle);
+        }
+    }
+    else if (NOMOM)
+    {   //SNAKEHEAD->dirchoosetime = 0;
+        ParseMomentum(ob,ob->angle);
+    }
+    if (ob->momentumx || ob->momentumy)
+        MoveActor(ob);
+
+// ActorMovement(ob);
+
+}
+
+
+/*
+===============
+=
+= SelectSnakeDir
+=
+===============
+*/
+
+
+void SelectSnakeDir (objtype *ob)
+{
+    int spot,centerx,centery,dx,dy;
+
+    spot = MAPSPOT(ob->tilex,ob->tiley,1)-ICONARROWS;
+
+    if ((spot >= 0) && (spot<= 7) && ((ob->dir!=(unsigned)spot)||(!(ob->flags & FL_DONE))))
+    {   centerx= (ob->tilex << 16) + HALFGLOBAL1;
+        centery= (ob->tiley << 16) + HALFGLOBAL1;
+        dx = abs(centerx - ob->x);
+        dy = abs(centery - ob->y);
+
+        if ((dx < SNAKERAD) && (dy < SNAKERAD))
+            // new direction
+        {   ZEROMOM;
+            ob->dir = spot;
+            ob->flags |= FL_DONE;
+            ParseMomentum(ob,dirangle8[ob->dir]);
+            SetFinePosition(ob,centerx,centery);
+            SetVisiblePosition(ob,ob->x,ob->y);
+
+            if (ob==SNAKEHEAD) {
+                SoftError("\n path changed at %d, %d",ob->tilex,ob->tiley);
+            }
+        }
+    }
+
+    MoveActor(ob);
+
+}
+
+
+void T_SnakePath(objtype*ob)
+{   objtype*temp,*follower;
+
+    if (SNAKEEND && (SNAKELEVEL == 2))
+    {   if (CheckLine(SNAKEEND,PLAYER[0],SIGHT))
+        {   if (ob->temp3 == -1)               //if snake can see player
+                //and he's presently stopped, restart
+            {   for(temp=ob; temp; temp=(objtype*)(temp->whatever))
+                {   temp->temp3 = 0;
+                    temp->momentumx = temp->temp1;
+                    temp->momentumy = temp->temp2;
+                }
+                ob->dirchoosetime = 0;
+            }
+        }
+        else if (ob->temp3 != -1)     //else if he hasn't been stopped, stop him
+        {   for(temp=ob; temp; temp = (objtype*)(temp->whatever))
+            {   temp->temp1 = temp->momentumx;
+                temp->temp2 = temp->momentumy;
+                temp->temp3 = -1;
+                temp->momentumx = temp->momentumy = 0;
+            }
+        }
+        else
+            return;
+    }
+
+
+    if (ob->dirchoosetime)
+        ob->dirchoosetime--;
+
+    else
+    {   int count = 0;
+
+        for(temp=ob; temp->whatever; temp=(objtype*)(temp->whatever))
+        {   follower = (objtype*)(temp->whatever);
+            follower->temp1 = temp->x;
+            follower->temp2 = temp->y;
+
+            SoftError("\n follower %d temp1 set to %4x, temp2 set to %4x",
+                      count,temp->x,temp->y);
+            count ++;
+        }
+        ob->dirchoosetime = 2 ;//15
+    }
+
+    if (ob->momentumx || ob->momentumy)
+        SelectSnakeDir(ob);
+//else
+// {ParseMomentum(ob,ob->angle);
+//	MoveActor(ob);
+// }
+
+
+}
+
+void FindClosestPath(objtype*ob)
+{   int tx,ty,dx,dy,angle;
+
+
+    tx = (ob->targettilex << 16) + TILEGLOBAL/2;
+    ty = (ob->targettiley << 16) + TILEGLOBAL/2;
+
+    dx= tx - ob->x;
+    dy= ob->y - ty;
+    angle = atan2_appx(dx,dy);
+
+    ZEROMOM;
+    ParseMomentum(ob,angle);
+    MoveActor(ob);
+
+}
+
+
+void T_SnakeFindPath(objtype*ob)
+{   int i,dx,dy,currdist,mindist,map;
+    tpoint dstruct,*dummy=&dstruct;
+    objtype*temp,*follower;
+
+    if (ob->targettilex || ob->targettiley)
+    {   FindClosestPath(ob);
+        dx = ob->targettilex - ob->tilex;
+        dy = ob->targettiley - ob->tiley;
+        if ((!dx) && (!dy))
+        {   SetTilePosition(ob,ob->tilex,ob->tiley);
+            SetVisiblePosition(ob,ob->x,ob->y);
+            ob->y = ob->drawy = (ob->tiley << TILESHIFT) + TILEGLOBAL/2;
+            NewState(ob,&s_snakepath);
+            return;
+        }
+    }
+
+    else
+    {   dummy->which = ACTOR;
+        mindist = 0x7fffffff;
+        for(i=0; i<whichpath; i++)
+        {
+            SetTilePosition(dummy,SNAKEPATH[i].x,SNAKEPATH[i].y);
+            dummy->z = ob->z;
+            if (CheckLine(ob,dummy,SIGHT))
+            {   currdist = FindDistance(ob->tilex-dummy->tilex,ob->tiley-dummy->tiley);
+                map = MAPSPOT(ob->tilex,ob->tiley,0)-AREATILE;
+                if ((currdist < mindist) && (map >= 0) && (map <= NUMAREAS))
+                {   ob->targettilex = dummy->tilex;
+                    ob->targettiley = dummy->tiley;
+                    mindist = currdist;
+                }
+            }
+        }
+    }
+
+    if (ob->dirchoosetime)
+        ob->dirchoosetime--;
+    else
+    {   for(temp=ob; temp->whatever; temp=(objtype*)(temp->whatever))
+        {   follower = (objtype*)(temp->whatever);
+            follower->temp1 = temp->x;
+            follower->temp2 = temp->y;
+        }
+        ob->dirchoosetime = 2 ;//15
+    }
+}
+
+
+
+void T_SnakeFinale(objtype*ob)
+{
+
+    if ((ob->state == &s_snakefireworks1)||(ob->state == &s_snakefireworks2))
+    {
+        if (ob->z != (maxheight-200))
+        {
+            ob->z --;
+            return;
+        }
+        SetGibSpeed(0x4500);
+        SpawnParticles(ob,RANDOM,100);
+
+        SpawnParticles(ob,gt_spit,100);
+        ResetGibSpeed();
+        NewState(ob,&s_dexplosion1);
+    }
+
+    else
+    {
+        if (!ob->ticcount)
+        {
+            NewState(EXPLOSIONS,&s_megaremove);
+            //  SpawnParticles(ob,RANDOM,100);
+            // SpawnParticles(ob,SPIT,100);
+            return;
+        }
+
+        if (ob->dirchoosetime)
+            ob->dirchoosetime --;
+        else
+        {
+            ob->dirchoosetime = (GameRandomNumber("snake finale choose",0) % 7) + 15;
+            SetGibSpeed(0x3000);
+            SpawnParticles(ob,RANDOM,30);
+            SpawnParticles(ob,gt_spit,20);
+            ResetGibSpeed();
+        }
+    }
+}
+
+
+
+void T_DarkSnakeChase(objtype*ob)
+{
+    objtype* temp,*follower;
+    int tdir,angle;
+
+
+    if (!(ob->flags & FL_ATTACKMODE))
+    {
+        if (!(CheckSight(ob,player) || Near(ob,player,4)))
+            return;
+        else
+        {
+            ob->flags |= FL_ATTACKMODE;
+            MU_StartSong(song_bosssee);
+        }
+
+    }
+
+
+
+    if (ob->hitpoints <= 0)
+    {
+        MU_StartSong(song_bossdie);
+        KillActor(ob);
+        AddMessage("Oscuro defeated!",MSG_CHEAT);
+        return;
+    }
+
+    angle = AngleBetween(ob,PLAYER[0]);
+    tdir = angletodir[angle];
+    if (Near(ob,PLAYER[0],6) && (ob->dir == (unsigned)tdir) && (!(ob->state->condition & SF_DOWN)))
+    {
+        NewState(ob,&s_snakefire1);
+        SD_PlaySoundRTP(SD_SNAKEREADYSND,ob->x,ob->y);
+    }
+
+    if (!ob->ticcount)
+    {
+        if (ob->state == &s_darkmonkredhead)
+            ob->temp3 = 0; // no longer hitable
+        else if ((ob->state == &s_redheadhit) && (ob != SNAKEEND))
+            NewState((objtype*)(ob->whatever),&s_redlinkhit);
+        else if (ob->state->condition & SF_UP)
+        {
+            SpawnMissile(ob,dm_spitobj,0x6000,angle,&s_spit1,0x6000);
+            SD_PlaySoundRTP(BAS[ob->obclass].fire,ob->x,ob->y);
+            //new->z -= 5;
+        }
+        //spawn spit;
+    }
+
+    if (CheckLine(ob,PLAYER[0],SIGHT))
+    {
+        ob->targettilex = PLAYER[0]->x;
+        ob->targettiley = PLAYER[0]->y;
+    }
+
+    if (ob->dirchoosetime)
+    {
+        ob->dirchoosetime--;
+        ActorMovement(ob);
+        if (NOMOM)
+            ob->dirchoosetime = 0;
+    }
+
+    else
+    {   //if (ob)
+        for(temp=ob; temp->whatever; temp=(objtype*)(temp->whatever))
+        {
+            follower = (objtype*)(temp->whatever);
+            follower->temp1 = temp->x;
+            follower->temp2 = temp->y;
+        }
+        SelectChaseDir(ob);
+        ob->dirchoosetime = 7 ;//15
+    }
+}
+
+
+
+void T_DarkmonkReact(objtype*ob)
+{
+    if (ob->z < nominalheight)
+    {   MISCVARS->monkz += MZADJUST;
+        ob->z = nominalheight + (MISCVARS->monkz >> 16);
+        //ob->z++;
+        return;
+    }
+
+    else
+    {   int ocl;
+
+        ocl = ob->temp3;
+
+        if (ocl == p_kesobj)
+            NewState(ob,&s_darkmonkabsorb1);
+        else if (ocl == p_heatseekobj)
+            NewState(ob,&s_darkmonkhball1);
+        else if (ocl == p_firebombobj)
+            NewState(ob,&s_darkmonkbreathe1);
+        else
+            NewState(ob,&s_darkmonkchase1);
+        ob->dirchoosetime = 0;
+    }
+
+}
+
+
+
+void T_DarkmonkCharge(objtype*ob)
+{   int dx,dy;
+
+    dx = abs(PLAYER[0]->x - ob->x);
+    dy = abs(PLAYER[0]->y - ob->y);
+    if ((dx < 0xa000) && (dy < 0xa000))
+    {   DamageThing(PLAYER[0],10);
+        Collision(PLAYER[0],ob,0,0);
+        M_CheckPlayerKilled(PLAYER[0]);
+    }
+
+    if (!ob->ticcount)
+        ob->speed >>= 1;
+
+    if (ob->dirchoosetime)
+        ob->dirchoosetime --;
+
+    if (NOMOM || (!ob->dirchoosetime))
+    {   ob->angle = AngleBetween(ob,PLAYER[0]);
+        ob->dir = angletodir[ob->angle];
+        ParseMomentum(ob,ob->angle);
+        ob->dirchoosetime = 5;
+    }
+
+    ActorMovement(ob);
+
+
+}
+
+
+void T_DarkmonkLandAndFire(objtype*ob)
+{
+
+    if (ob->z < nominalheight)
+    {   MISCVARS->monkz += MZADJUST;
+        ob->z = nominalheight + (MISCVARS->monkz >> 16);
+        //ob->z++;
+        return;
+    }
+    if (Near(ob,PLAYER[0],3))
+    {   if (GameRandomNumber("darkmonkland",0)<128)
+            NewState(ob,&s_darkmonkbball1);
+        else
+        {   ob->angle = AngleBetween(ob,PLAYER[0]);
+            ob->dir = angletodir[ob->angle];
+            ob->speed <<= 1;       // goes twice as fast
+            ZEROMOM;
+            ParseMomentum(ob,ob->angle);
+            ob->dirchoosetime = 5; // change dir every 5 tics
+            ob->hitpoints -= 200; // big penalty for charging
+            if (ob->hitpoints <= 0)
+            {   objtype*column = (objtype*)(ob->whatever);
+
+                EnableObject((long)column);
+                ob->whatever = NULL;
+
+                KillActor(ob);
+                NewState(ob,&s_darkmonkfastspawn);
+                AddMessage("Oscuro flees!",MSG_CHEAT);
+                return;
+            }
+            NewState(ob,&s_darkmonkcharge1);
+        }
+
+    }
+    else if (ob->temp1)
+        NewState(ob,&s_darkmonklightning1);
+    else
+        NewState(ob,&s_dmgreenthing1);
+    ob->temp1 ^= 1;
+    ob->dirchoosetime = 0;
+
+}
+
+
+void T_DarkmonkChase(objtype*ob)
+{   int chance,dx,dy,dist;
+
+
+    if (!Near(ob,PLAYER[0],2))
+    {   if (ob->z > (maxheight - 100))
+        {   MISCVARS->monkz -= MZADJUST;
+            ob->z = nominalheight + (MISCVARS->monkz >> 16);
+            //ob->z--;
+            return;
+        }
+    }
+    else if (ob->z < nominalheight)
+    {   MISCVARS->monkz += MZADJUST;
+        ob->z = nominalheight + (MISCVARS->monkz >> 16);
+        //ob->z++;
+        return;
+    }
+
+
+    if (CheckLine(ob,PLAYER[0],SIGHT))
+    {   ob->targettilex = PLAYER[0]->x;
+        ob->targettiley = PLAYER[0]->y;
+    }
+
+    if (!ob->ticcount)
+    {
+        if (CheckLine(ob,PLAYER[0],SHOOT))   // got a shot at player?
+        {   dx = abs(ob->tilex - PLAYER[0]->tilex);
+            dy = abs(ob->tiley - PLAYER[0]->tiley);
+            dist = dx>dy ? dx : dy;
+            if (!dist || dist==1)
+                chance = 300;//300;
+            else
+                chance = 400/dist;//300/dist;
+
+            if (GameRandomNumber("T_DarkMonkChase",0) < chance)
+            {   NewState(ob,&s_dmlandandfire);
+                return;
+            }
+        }
+    }
+
+    if (ob->dirchoosetime)
+        ob->dirchoosetime--;
+
+    if ((ob->flags & FL_STUCK) || (!ob->dirchoosetime))
+    {   SelectChaseDir(ob);
+        ob->dirchoosetime = M_CHOOSETIME(ob);
+    }
+
+    else
+    {   if (NOMOM)
+            ParseMomentum(ob,dirangle8[ob->dir]);
+        ActorMovement(ob);
+
+    }
+
+}
+
+
+//====================== End of Boss Functions ===========================//
+
+
+
+
+
+
+void T_GunStand(objtype*ob)
+{   int dy,dx,infrontof,dz;
+    objtype* temp;
+
+// if (ob->target)
+//  Error("gun reset with non-null target");
+    for(temp = firstareaactor[ob->areanumber]; temp; temp= temp->nextinarea)
+    {   if (temp == ob)
+            continue;
+        if (temp->obclass == ob->obclass)
+            continue;
+        if ((!(temp->flags & FL_SHOOTABLE)) || (temp->flags & FL_DYING))
+            continue;
+
+        dy = ob->y - temp->y;
+        dx = ob->x - temp->x;
+        dz = ob->z - temp->z;
+        if ((abs(dy)>0x40000) || (abs(dx)>0x40000) || (abs(dz) > 20))
+            continue;
+
+
+        infrontof = 0;
+
+        switch (ob->dir)
+        {
+        case north:
+            if ((dy > 0) && (abs(dx)<0x8000))
+                infrontof = 1;
+            break;
+
+        case east:
+            if ((dx < 0) && (abs(dy)<0x8000))
+                infrontof = 1;
+            break;
+
+        case south:
+            if ((dy < 0) && (abs(dx)<0x8000))
+                infrontof = 1;
+            break;
+
+        case west:
+            if ((dx > 0) && (abs(dy)<0x8000))
+                infrontof = 1;
+            break;
+
+        default:
+            break;
+        }
+
+        if (infrontof && CheckLine(ob,temp,SHOOT))
+        {   ob->target = temp;
+            NewState(ob,&s_gunraise1);
+            return;
+        }
+    }
+
+}
+
+
+void T_4WayGunStand(objtype*ob)
+{
+    int dy,dx,dz;
+    objtype* temp;
+
+    if (ob->target)
+        Error("gun reset with non-null target");
+    for(temp = firstareaactor[ob->areanumber]; temp; temp= temp->nextinarea)
+    {
+        if (temp == ob)
+            continue;
+
+        if (temp->obclass == ob->obclass)
+            continue;
+
+        if ((!(temp->flags & FL_SHOOTABLE)) || (temp->flags & FL_DYING))
+            continue;
+
+        dy = abs(ob->x-temp->x);
+        dx = abs(ob->y-temp->y);
+        dz = abs(ob->z-temp->z);
+        if ((dx < 0x40000) && (dy < 0x40000) && (dz< 20) && CheckLine(ob,temp,SHOOT))
+        {   //if ((dx < 0x8000) || (dy <0x8000))
+            ob->target = temp;
+            NewState(ob,&s_4waygunfire1);
+            return;
+        }
+    }
+}
+
+
+void A_GunShoot(objtype*ob)
+{   int   dx,dy,dz,damage,infrontof,tnear,savedangle;
+    objtype * target;
+
+    if (!ob->ticcount)
+    {   target = (objtype*)(ob->target);
+        if (!target)
+            Error("an instance of %s called gunshoot without a target\n",debugstr[ob->obclass]);
+        if ((!(target->flags & FL_SHOOTABLE)) || (target->flags & FL_DYING))
+        {   NewState(ob,&s_gunlower1);
+            ob->target = NULL;
+            return;
+        }
+
+        dx = target->x-ob->x;
+        dy = ob->y-target->y;
+        dz = ob->z-target->z;
+
+
+        tnear = ((abs(dy)<0x40000) && (abs(dx)<0x40000) && (abs(dz) < 20));
+        infrontof = 0;
+
+        switch (ob->dir)
+        {
+        case north:
+            if ((dy > 0) && (abs(dx)<0x8000))
+                infrontof = 1;
+            break;
+
+        case east:
+            if ((dx < 0) && (abs(dy)<0x8000))
+                infrontof = 1;
+            break;
+
+        case south:
+            if ((dy < 0) && (abs(dx)<0x8000))
+                infrontof = 1;
+            break;
+
+        case west:
+            if ((dx > 0) && (abs(dy)<0x8000))
+                infrontof = 1;
+            break;
+
+        default:
+            break;
+        }
+
+        if ((!infrontof) || (!CheckLine(ob,target,SHOOT)) ||
+                (!tnear))
+        {   NewState(ob,&s_gunlower1);
+            ob->target = NULL;
+            return;
+        }
+
+        //SD_PlaySoundRTP(SD_FIRE,PLAYER[0]->x,PLAYER[0]->y,ob->x,ob->y);
+        //hitchance = 128;
+
+//	if (!target)
+        //		Error("object called shoot without a target\n");
+
+
+        damage = DMG_AHGUN;
+
+
+        if (target->obclass == playerobj)
+        {   target->target = ob;
+            if (target->flags & FL_BPV)
+                damage >>= 1;
+
+        }
+        savedangle = ob->angle;
+        ob->angle = atan2_appx(dx,dy);
+        RayShoot(ob,damage,GameRandomNumber("A_GunShoot Accuracy",0) % 20);
+        ob->angle = savedangle;
+        SD_PlaySoundRTP(SD_BIGEMPLACEFIRESND,ob->x,ob->y);
+    }
+
+}
+
+
+void A_4WayGunShoot(objtype*ob)
+{
+    int   dx,dy,dz,damage,savedangle;
+    objtype * target;
+
+    if (ob->ticcount == (ob->state->tictime >> 1))
+    {
+        target = (objtype*)(ob->target);
+        if (!target)
+            Error("an instance of %s called 4waygunshoot without a target\n",debugstr[ob->obclass]);
+        dx = abs(target->x-ob->x);
+        dy = abs(ob->y-target->y);
+        dz = abs(ob->z-target->z);
+        if ((dx > 0x40000) || (dy > 0x40000) || (dz > 20) ||
+                (!CheckLine(ob,target,SHOOT)) ||
+                (!(target->flags & FL_SHOOTABLE)) ||
+                (target->flags & FL_DYING)
+           )
+        {
+            ob->target = NULL;
+            NewState(ob,&s_4waygun);
+            return;
+        }
+
+
+        //SD_PlaySoundRTP(SD_FIRE,PLAYER[0]->x,PLAYER[0]->y,ob->x,ob->y);
+        //hitchance = 128;
+
+        // if (!target)
+        //     Error("object called shoot without a target\n");
+
+
+        damage = DMG_AHGUN;
+        SD_PlaySoundRTP(BAS[ob->obclass].fire,ob->x,ob->y);
+
+        if (target->obclass == playerobj)
+        {
+            target->target = ob;
+            if (target->flags & FL_BPV)
+                damage >>= 1;
+        }
+
+        savedangle = ob->angle;
+        ob->angle = 0;
+        RayShoot(ob,damage,GameRandomNumber("A_4WayGunShoot Accuracy",0) % 20);
+        ob->angle = ANG90;
+        RayShoot(ob,damage,GameRandomNumber("A_4WayGunShoot Accuracy",0) % 20);
+        ob->angle = ANG180;
+        RayShoot(ob,damage,GameRandomNumber("A_4WayGunShoot Accuracy",0) % 20);
+        ob->angle = ANG270;
+        RayShoot(ob,damage,GameRandomNumber("A_4WayGunShoot Accuracy",0) % 20);
+        ob->angle = savedangle;
+    }
+}
+
+
+void A_Drain (objtype *ob)
+{
+    int dx,dy,dz,damage;
+
+    dx = abs(PLAYER[0]->x - ob->x);
+    dy = abs(PLAYER[0]->y - ob->y);
+    dz = abs(PLAYER[0]->z - ob->z);
+
+    if ((dx > TOUCHDIST) || (dy > TOUCHDIST) || (dz > (TOUCHDIST>>10)))
+    {
+        NewState(ob,&s_dmonkshoot5);
+        return;
+    }
+
+    if (ob->ticcount)
+        return;
+
+    else
+    {
+        damage = (GameRandomNumber("A_Drain",ob->obclass) >> 3);
+        DamageThing (PLAYER[0],damage);
+        ob->hitpoints += damage;
+        if (ob->hitpoints > starthitpoints[gamestate.difficulty][ob->obclass])
+            ob->hitpoints = starthitpoints[gamestate.difficulty][ob->obclass];
+
+        Collision(PLAYER[0],ob,0,0);
+        if (PLAYER[0]->flags & FL_DYING)
+            PLAYER[0]->target = ob;
+        M_CheckPlayerKilled(PLAYER[0]);
+        SD_PlaySoundRTP(SD_MONKGRABSND,ob->x,ob->y);
+    }
+}
+
+
+
+
+
+
+void  A_DmonkAttack(objtype*ob)
+{   int angle,nobclass,nspeed,altangle1=0,altangle2=0,zoff=0,sound;
+    statetype *nstate;
+
+
+    if (!ob->ticcount)
+    {
+        ob->hitpoints -= 120;//120;
+        if (ob->hitpoints <= 0)
+        {
+            objtype*column = (objtype*)(ob->whatever);
+
+            EnableObject((long)column);
+            ob->whatever = NULL;
+
+            KillActor(ob);
+            NewState(ob,&s_darkmonkfastspawn);
+            return;
+        }
+    }
+
+
+    if (ob->dirchoosetime)
+        ob->dirchoosetime --;
+
+    else
+    {   sound = BAS[ob->obclass].fire;
+        angle = AngleBetween(ob,PLAYER[0]);
+        nspeed = 0x6000;
+
+        if (ob->state == &s_darkmonksphere8)
+        {   nstate = &s_kessphere1;
+            nobclass = p_kesobj;
+            ob->dirchoosetime = 70;
+        }
+
+        else if (ob->state == &s_darkmonkhball7)
+        {   nstate = &s_handball1;
+            nobclass = dm_heatseekobj;
+            nspeed = 0x3000;
+            ob->dirchoosetime = 5;
+        }
+
+        else if (ob->state == &s_darkmonkbball7)
+        {   nstate = &s_faceball1;
+            nobclass = dm_weaponobj;
+            nspeed = 0x3000;
+            ob->dirchoosetime = 5;
+        }
+
+        else if (ob->state == &s_darkmonklightning9)
+        {   nstate = &s_lightning;
+            nobclass = dm_weaponobj;
+            ob->dirchoosetime = 3;
+            sound++;
+        }
+
+        else if (ob->state == &s_dmgreenthing8)
+        {   nstate = &s_energysphere1;
+            nobclass = dm_weaponobj;
+            sound +=2;
+            ob->dirchoosetime = 70;
+        }
+
+        else if (ob->state == &s_darkmonkfspark5)
+        {   nstate = &s_floorspark1;
+
+            altangle1 = angle + ANGLES/24;
+            altangle2 = angle - ANGLES/24;
+            Fix(altangle1);
+            Fix(altangle2);
+            nobclass = dm_weaponobj;
+            ob->dirchoosetime = 3;
+            sound += 3;
+        }
+
+        else if (ob->state == &s_darkmonkbreathe6)
+        {   nstate = &s_crossfire1;
+            ob->dirchoosetime = 3;
+            nobclass = dm_weaponobj;
+            zoff = -15;
+            sound += 3;
+        }
+
+        SpawnMissile(ob,nobclass,nspeed,angle,nstate,0xb000);
+        SD_PlaySoundRTP(sound,ob->x,ob->y);
+
+        new->z = ob->z+zoff;
+        if (altangle1)
+        {
+            SpawnMissile(ob,nobclass,nspeed,altangle1,nstate,0xb000);
+            SpawnMissile(ob,nobclass,nspeed,altangle2,nstate,0xb000);
+        }
+    }
+
+
+
+}
+
+
+
+#endif // SHAREWARE endif
+
+
+
+
+//=====================================================================//
+
+
+
+
+/*
+===============
+=
+= T_Stand
+=
+===============
+*/
+
+void T_Stand (objtype *ob)
+{
+    if (!ob->ticcount)
+        SightPlayer (ob);
+    else
+        SoftError("\n ob type %s ticcount of %d in T_Stand",debugstr[ob->obclass],
+                  ob->ticcount);
+}
+
+
+
+
+
+void DamagePlayerActor(objtype *ob, int damage)
+
+{
+    playertype *pstate;
+
+    switch (gamestate.difficulty)
+    {
+    case 0:
+        damage >>= 1;
+        break;
+    case 1:
+        damage -= (damage >> 2);
+        break;
+    case 2:
+        break;
+    case 3:  //damage += (damage>>2);
+        break;
+        //default: Error("Um, Gamestate.Difficulty, uh, has problems.\n");
+    }
+
+    if (!damage) damage++;
+
+    M_LINKSTATE(ob,pstate);
+
+
+    pstate->health -= damage;
+    ob->hitpoints = pstate->health;
+
+    SD_PlaySoundRTP(SD_PLAYERTCHURTSND+(pstate->player),ob->x,ob->y);
+    if (ob==player)
+    {
+        damagecount += damage;
+        if (cybermanenabled)
+            SWIFT_TactileFeedback (10*damage, 15, 15);
+        if ( SHOW_BOTTOM_STATUS_BAR() )
+            DrawBarHealth (false);
+    }
+
+    if (pstate->health<=0)
+    {
+        pstate->health = 0;
+        ob->hitpoints = 0;
+    }
+}
+
+
+
+
+void DamageNonPlayerActor(objtype *ob,int damage)
+{
+    //if ((ob->obclass == b_darksnakeobj) && (!ob->temp3))
+    // return;
+
+    if (!(ob->flags & FL_ATTACKMODE))
+        damage <<= 1;
+
+    ob->hitpoints -= damage;
+    if (ob->hitpoints <= 0)
+    {
+        int sound;
+
+        sound = BAS[ob->obclass].die;
+        if (ob->obclass == lowguardobj)
+        {
+            if (ob->shapeoffset)
+                sound ++;
+        }
+        SD_PlaySoundRTP(sound,ob->x,ob->y);
+    }
+    else
+        SD_PlaySoundRTP(BAS[ob->obclass].hit,ob->x,ob->y);
+
+#if (SHAREWARE == 0)
+    if ((ob->obclass == b_robobossobj) && (ob->temp2 <= 2))
+    {
+        if (ob->hitpoints <
+                ((3-ob->temp2)*starthitpoints[gamestate.difficulty][ob->obclass]>>2)
+           )
+        {
+            SD_PlaySoundRTP(SD_NMEAPARTSND,ob->x,ob->y);
+            ob->temp2++;
+            ob->shapeoffset += 16;
+            ob->speed += 0x500;
+            SpawnNewObj(ob->tilex,ob->tiley,&s_megaexplosions,inertobj);
+            new->temp1 = 3;
+            new->flags |= FL_ABP;
+            MakeActive(new);
+        }
+        if (ob->temp2 == 1)
+            NewState((objtype*)(ob->whatever),&s_NMEhead2);
+    }
+#endif
+    MISCVARS->madenoise = true;
+}
+
+
+
+void DamageStaticObject(statobj_t*tempstat,int damage)
+{
+
+
+    tempstat->hitpoints -= damage;
+    if (tempstat->hitpoints <= 0)
+    {
+        sprites[tempstat->tilex][tempstat->tiley]=NULL;
+        tempstat->flags |= FL_NONMARK;
+        if (tempstat->flags&FL_LIGHT)
+        {
+
+            if (MAPSPOT(tempstat->tilex,tempstat->tiley,2))
+            {   touchplatetype *tplate;
+
+                for(tplate=touchplate[tempstat->linked_to]; tplate; tplate = tplate->nextaction)
+                    if (tplate->whichobj == (long)(tempstat))
+                        RemoveTouchplateAction(tplate,tempstat->linked_to);
+            }
+
+            if (tempstat->flags & FL_LIGHTON)
+                TurnOffLight(tempstat->tilex,tempstat->tiley);
+
+
+            if (tempstat->itemnumber<=stat_chandelier)
+                //SpawnFallingDebris(tempstat->x,tempstat->y,tempstat->z-32);
+            {
+                objtype *prevlast = LASTACTOR;
+
+                SpawnSlowParticles(gt_sparks,4,tempstat->x,tempstat->y,tempstat->z-32);
+                for(prevlast = prevlast->next; prevlast; prevlast= prevlast->next)
+                {
+                    prevlast->momentumz = 1; // any positive value will do
+                    prevlast->momentumx >>= 1;
+                    prevlast->momentumy >>= 1;
+                }
+            }
+            else
+            {
+
+                SpawnStatic(tempstat->tilex,tempstat->tiley,stat_metalshards,-1);
+                LASTSTAT->flags |= (FL_ABP|FL_NONMARK);
+                sprites[tempstat->tilex][tempstat->tiley] = NULL;
+                MakeStatActive(LASTSTAT);
+                switch (tempstat->itemnumber)
+                {
+                case stat_lamp:
+                case stat_altbrazier1:
+                case stat_altbrazier2:
+                case stat_torch:
+                    SpawnSlowParticles(gt_sparks,5,tempstat->x,tempstat->y,tempstat->z-32);
+                    break;
+                case stat_floorfire:
+                    SpawnSlowParticles(gt_sparks,5,tempstat->x,tempstat->y,tempstat->z);
+                    break;
+                default:
+                    ;
+                }
+            }
+            SpawnSolidStatic(tempstat);
+            SD_PlaySoundRTP(SD_ITEMBLOWSND,tempstat->x,tempstat->y);
+        }
+        else
+        {
+            switch (tempstat->itemnumber)
+            {
+            case stat_dariantouch:
+                MISCVARS->ETOUCH[tempstat->linked_to].x = MISCVARS->ETOUCH[tempstat->linked_to].y = 0;
+            case stat_tntcrate:
+            case stat_bonusbarrel:
+                SpawnNewObj(tempstat->tilex,tempstat->tiley,&s_staticexplosion1,inertobj);
+                MakeActive(new);
+                new->flags |= FL_ABP;
+                new->whatever = tempstat;
+                new->temp2 = damage;
+
+                if (tempstat->itemnumber == stat_bonusbarrel)
+                {
+                    int rand = GameRandomNumber("DamageThing",0);
+
+                    if (rand < 80)
+                    {
+                        if (rand & 1)
+                            SpawnStatic(tempstat->tilex,tempstat->tiley,stat_monkmeal,-1);
+                        else
+                            SpawnStatic(tempstat->tilex,tempstat->tiley,stat_priestporridge,-1);
+                        gamestate.healthtotal ++;
+                    }
+                    else if (rand < 160)
+                    {
+                        if (rand & 1)
+                            SpawnStatic(tempstat->tilex,tempstat->tiley,stat_lifeitem1,-1);
+                        else
+                            SpawnStatic(tempstat->tilex,tempstat->tiley,stat_lifeitem3,-1);
+                    }
+                    else
+                    {
+                        if (rand & 1)
+                            SpawnStatic(tempstat->tilex,tempstat->tiley,stat_mp40,-1);
+                        else
+                        {
+                            SpawnStatic(tempstat->tilex,tempstat->tiley,stat_heatseeker,-1);
+                            gamestate.missiletotal ++;
+                        }
+                        LASTSTAT->flags &= ~FL_RESPAWN;
+                    }
+                    //LASTSTAT->flags &= ~FL_SHOOTABLE;
+                    LASTSTAT->flags |= FL_ABP;
+                    MakeStatActive(LASTSTAT);
+                    SD_PlaySoundRTP(SD_BONUSBARRELSND,tempstat->x,tempstat->y);
+                }
+                else
+                {
+                    ExplodeStatic(tempstat);
+                    if (tempstat == touchsprite)
+                        touchsprite = NULL;
+                }
+                SpawnSolidStatic(tempstat);
+                //SD_Play(SD_EXPL);
+                break;
+#if (SHAREWARE == 0)
+            case stat_mine:
+                SpawnNewObj(tempstat->tilex,tempstat->tiley,&s_grexplosion1,inertobj);
+                MakeActive(new);
+                new->flags |= FL_ABP;
+                new->whatever = tempstat;
+                new->temp2 = damage;
+                RemoveStatic(tempstat);
+                break;
+
+            case stat_tomlarva:
+                SD_PlaySoundRTP(SD_ACTORSQUISHSND,tempstat->x,tempstat->y);
+                SpawnGroundExplosion(tempstat->x,tempstat->y,tempstat->z);
+                //MISCVARS->gibgravity = GRAVITY/2;
+                MISCVARS->fulllightgibs = true;
+                SetGibSpeed(0x4000);
+                SpawnSlowParticles(GUTS,30,tempstat->x, tempstat->y,tempstat->z);
+                ResetGibSpeed();
+                MISCVARS->fulllightgibs = false;
+                //MISCVARS->gibgravity = -1;
+                RemoveStatic(tempstat);
+                break;
+#endif
+
+            case stat_lifeitem1:
+            case stat_lifeitem2:
+            case stat_lifeitem3:
+            case stat_lifeitem4:
+                SD_PlaySoundRTP(SD_ITEMBLOWSND,tempstat->x,tempstat->y);
+                gamestate.treasurecount ++;
+                SpawnSlowParticles(gt_sparks,10,tempstat->x,tempstat->y,tempstat->z);
+                SpawnSolidStatic(tempstat);
+                break;
+
+            default:
+
+                if ((tempstat->itemnumber == stat_plant) ||
+                        (tempstat->itemnumber == stat_tree))
+                    gamestate.plantcount++;
+
+                //tempstat->shapenum = -1;
+                //tempstat->flags &= ~FL_SHOOTABLE;
+                ExplodeStatic(tempstat);
+                SpawnSolidStatic(tempstat);
+                break;
+            }
+        }
+    }
+}
+
+
+void DamageThing (void *thing, int damage)
+{
+    objtype* tempactor;
+    statobj_t* tempstat;
+
+
+    tempactor = (objtype*)thing;
+    if (!tempactor)
+        return;
+
+    if ((tempactor->which == ACTOR) && (!(tempactor->flags & FL_SHOOTABLE)))
+        return;
+
+    if ((tempactor->which == ACTOR) || (tempactor->which == SPRITE))
+    {
+        if (tempactor->which == ACTOR)
+        {
+            if (tempactor->obclass == playerobj)
+            {
+                if ((tempactor->flags & FL_GODMODE) ||
+                        (tempactor->flags & FL_DOGMODE) ||
+                        godmode ||
+                        (gamestate.battlemode == battle_Eluder)
+                   )
+                    return;
+                DamagePlayerActor(tempactor,damage);
+            }
+
+            else
+            {
+                if ((tempactor->obclass == collectorobj) && (gamestate.SpawnEluder))
+                    return;
+                if (tempactor->hitpoints <= 0)
+                    return;
+                DamageNonPlayerActor(tempactor,damage);
+            }
+        }
+        else
+        {
+            tempstat = (statobj_t*)thing;
+
+            MISCVARS->madenoise = true;
+            if (!(tempstat->flags & FL_SHOOTABLE))
+                return;
+            DamageStaticObject(tempstat,damage);
+        }
+    }
+}
+
+
+void ExplodeStatic(statobj_t*tempstat)
+{
+//SpawnSolidStatic(tempstat);
+
+    if (tempstat->flags & FL_WOODEN)
+    {
+        SpawnStatic(tempstat->tilex,tempstat->tiley,stat_woodfrag,-1);
+        if ((gamestate.BattleOptions.RespawnItems) &&
+                (tempstat->itemnumber == stat_tntcrate)
+           )
+        {
+            tempstat->linked_to = (long)(LASTSTAT);
+            tempstat->flags |= FL_RESPAWN;
+        }
+
+    }
+    else if (tempstat->flags & FL_METALLIC)
+        SpawnStatic(tempstat->tilex,tempstat->tiley,stat_metalfrag,-1);
+    else
+        SpawnStatic(tempstat->tilex,tempstat->tiley,stat_rubble,-1);
+    LASTSTAT->flags |= (FL_ABP|FL_NONMARK);
+    sprites[tempstat->tilex][tempstat->tiley] = NULL;
+    MakeStatActive(LASTSTAT);
+    SD_PlaySoundRTP(SD_ITEMBLOWSND,tempstat->x,tempstat->y);
+
+
+}
+
+
+
+
+
+void EnableObject(long object)
+{
+    objtype* ob;
+    int i,gasicon;
+    doorobj_t*tdoor;
+
+    ob = (objtype*)object;
+
+#if (BNACRASHPREVENT == 1)//
+    if (ob == 0) {
+        return;
+    }
+#endif
+
+    ob->flags |= FL_ACTIVE;
+    if (ob->obclass == bladeobj)
+    {
+        ParseMomentum(ob,dirangle8[ob->dir]);
+        if (ob->whatever)
+        {
+            objtype *passenger=(objtype*)(ob->whatever);
+
+            passenger->momentumx += ob->momentumx;
+            passenger->momentumy += ob->momentumy;
+        }
+    }
+
+    if (ob->obclass == gasgrateobj)
+    {
+        NewState(ob,&s_gas2);
+        SD_PlaySoundRTP(SD_GASSTARTSND,ob->x,ob->y);
+        ob->dirchoosetime = GASTICS;
+        for(i=0; i<doornum; i++)
+        {
+
+            tdoor = doorobjlist[i];
+            gasicon = MAPSPOT(tdoor->tilex,tdoor->tiley,1);
+            if (gasicon == GASVALUE)
+                LinkedCloseDoor(i);
+        }
+
+        MU_StoreSongPosition();
+        MU_StartSong(song_gason);
+        MISCVARS->GASON = 1;
+        ob->temp3 = 105;
+    }
+    else if (ob->obclass == pillarobj)
+    {
+        ob->flags |= FL_FLIPPED;
+        gamestate.secretcount++;
+    }
+    if (!(ob->flags & FL_ABP))
+    {
+        ob->flags |= FL_ABP;
+        MakeActive(ob);
+    }
+}
+
+void DisableObject(long object)
+{   objtype*ob;
+
+    ob = (objtype*)object;
+    ob->flags &= ~FL_ACTIVE;
+}
+
+
+void T_MoveColumn(objtype* ob)
+{   int spot,index;
+
+
+    if (!(ob->flags & FL_ACTIVE))
+        return;
+    /*
+     switch (ob->dir)
+      {case north:
+    	 ob->momentumy = -PILLARMOM;
+    	 break;
+    	case south:
+    	 ob->momentumy =  PILLARMOM;
+    	 break;
+    	case east:
+    	 ob->momentumx =  PILLARMOM;
+    	 break;
+    	case west:
+    	 ob->momentumx = -PILLARMOM;
+    	 break;
+      }
+
+    */
+    ActorMovement(ob);
+    index = touchindices[ob->tilex][ob->tiley];
+    if (index)
+        TRIGGER[index-1] = 1;
+    ob->temp1 -= PILLARMOM;
+
+    if ((ob->temp1 <= 0) || NOMOM)
+    {   ZEROMOM;
+        ob->temp1 = 0x20000;
+        ob->flags &= ~FL_ACTIVE;
+        spot = MAPSPOT(ob->tilex,ob->tiley,1)-ICONARROWS;
+        if ((spot >= 0) && (spot <= 7))
+        {   ob->dir = spot;
+            if (!ob->temp2)
+            {
+                gamestate.secrettotal++;
+            }
+            else
+            {
+                ob->flags |= FL_ACTIVE;
+            }
+            ParseMomentum(ob,dirangle8[ob->dir]);
+        }
+        else
+            ob->flags |= FL_DONE;
+
+    }
+}
+
+
+
+boolean NextToDoor(objtype*ob)
+{
+    int tilex,tiley,centerx,centery,dx,dy;
+
+    tilex = ob->tilex;
+    tiley = ob->tiley;
+
+
+    if (M_ISDOOR(tilex+1,tiley) || M_ISDOOR(tilex-1,tiley))
+    {   centery = (tiley << TILESHIFT) + HALFGLOBAL1;
+        dy = abs(ob->y - centery);
+        if (dy < 0x2000)
+            return true;
+    }
+
+    if (M_ISDOOR(tilex,tiley+1) || M_ISDOOR(tilex,tiley-1))
+    {   centerx = (tilex << TILESHIFT) + HALFGLOBAL1;
+        dx = abs(ob->x - centerx);
+        if (dx < 0x2000)
+            return true;
+    }
+
+    return false;
+}
+
+
+/*
+=================
+=
+= T_Use
+=
+=================
+*/
+
+
+void T_Use(objtype*ob)
+{   if (ob->ticcount)
+        return;
+
+    switch (ob->obclass)
+    {
+#if (SHAREWARE == 0)
+    case b_darianobj:
+        if (touchsprite && !DoPanicMapping())
+            touchsprite->flags |= FL_ACTIVE;
+        if ((!sprites[PLAYER[0]->tilex][PLAYER[0]->tiley]) && (ob->areanumber == PLAYER[0]->areanumber))
+        {   SpawnNewObj(PLAYER[0]->tilex,PLAYER[0]->tiley,&s_dspear1,spearobj);
+            new->flags |= (FL_ABP);//|FL_INVULNERABLE);
+            new->z = 0;
+            MakeActive(new);
+        }
+        ZEROMOM;
+        ob->flags |= FL_STUCK;
+        SD_PlaySoundRTP(SD_DARIANUSESND,ob->x,ob->y);
+        //NewState(ob,&s_darianspears);
+        break;
+#endif
+    default:
+        ;
+    }
+
+
+}
+
+
+
+
+
+#define RollStart(ob,state,angle)     \
+   {                                  \
+   int oldspeed = ob->speed;          \
+                                      \
+   ob->speed = ROLLMOMENTUM+0x200;    \
+   NewState(ob,state);                \
+   ParseMomentum(ob,angle);           \
+   ob->speed = oldspeed;              \
+   }                                  \
+
+
+
+
+
+void AvoidPlayerMissile(objtype*ob)
+{
+    objtype *temp;
+    int dx,dy,dz;
+    int magangle,angle1,rollangle1,rollangle2,dangle1,dangle2;
+
+    if (PLAYER0MISSILE == NULL)
+        return;
+
+    if (GameRandomNumber("scott missile avoid",0) > 160)
+        return;
+
+    if (ob->momentumz)
+        return;
+
+    if ((ob->state->think == T_Roll) || (ob->state->think == T_Reset))
+        return;
+
+    temp = PLAYER0MISSILE;
+
+    dx = abs(temp->x - ob->x);
+    dy = abs(ob->y - temp->y);
+    dz = abs(ob->z - temp->z);
+    angle1 = AngleBetween(temp,ob);
+    magangle = abs(temp->angle - angle1);
+
+    if (magangle > VANG180)
+        magangle = ANGLES - magangle;
+
+
+    if ((magangle > ANGLES/48) || (dx > 0x50000) || (dy > 0x50000) ||
+            (dz > 32))
+        return;
+
+    rollangle1 = angle1 + ANGLES/4;
+    Fix(rollangle1);
+    dangle1 = abs(temp->angle - rollangle1);
+    if (dangle1 > VANG180)
+        dangle1 = ANGLES - dangle1;
+
+    rollangle2 = angle1 - ANGLES/4;
+    Fix(rollangle2);
+    dangle2 = abs(temp->angle - rollangle2);
+    if (dangle2 > VANG180)
+        dangle2 = ANGLES - dangle2;
+
+    ob->momentumx = ob->momentumy = 0;
+
+    if (dangle1 > dangle2)
+    {
+        RollStart(ob,&s_strikerollleft1,rollangle1);
+    }
+    else
+    {
+        RollStart(ob,&s_strikerollright1,rollangle2);
+    }
+    ob->flags |= FL_NOFRICTION;
+
+    ob->target = PLAYER[0];
+    //SelectRollDir(ob);
+
+
+}
+
+
+
+
+/*
+=================
+=
+= T_Chase
+=
+=================
+*/
+
+void T_Chase (objtype *ob)
+{
+    int   dx,dy,dz,dist,chance;
+    classtype ocl;
+    statetype *temp;
+    boolean doorok;
+
+    ocl = ob->obclass;
+
+
+    if ((ocl == deathmonkobj) || (ocl == blitzguardobj))
+    {   dx = abs(PLAYER[0]->x - ob->x);
+        dy = abs(ob->y - PLAYER[0]->y);
+        dz = abs(ob->z - PLAYER[0]->z);
+
+        if ((dx < TOUCHDIST) && (dy < TOUCHDIST) && (dz < (TOUCHDIST >> 10)))
+        {
+#if (SHAREWARE == 0)
+            if (ocl == deathmonkobj)
+            {   NewState(ob,&s_dmonkshoot1);
+                STOPACTOR(ob);
+                return;
+
+            }
+            else
+#endif
+                if ((!ob->temp3) && (PLAYERSTATE[0].missileweapon != -1) &&
+                        (PLAYERSTATE[0].missileweapon < wp_godhand))
+                {   NewState(ob,&s_blitzsteal1);
+                    STOPACTOR(ob);
+                    return;
+                }
+        }
+    }
+
+    ob->flags &= ~FL_DODGE;
+
+    //if (CheckLine(ob,PLAYER[0],DIRCHECK) && (ocl != roboguardobj))
+
+    if (!ob->ticcount)
+    {   if (CheckLine(ob,PLAYER[0],SIGHT))   // got a shot at player?
+        {   if (ocl != roboguardobj)
+            {   ob->targettilex = PLAYER[0]->x;
+                ob->targettiley = PLAYER[0]->y;
+            }
+        }
+
+        if (CheckLine(ob,PLAYER[0],SHOOT) && (!(player->flags&FL_DYING)))   // got a shot at player?
+        {
+            dx = abs(ob->tilex - PLAYER[0]->tilex);
+            dy = abs(ob->tiley - PLAYER[0]->tiley);
+            dist = (dx>dy)?(dx):(dy);
+            if ((!dist) || (dist==1))
+                chance = 300;
+            else if (ocl >= b_darianobj)
+                chance = 400/dist;
+            else
+                chance = 300/dist;
+
+            if (GameRandomNumber("T_Chase",ocl) <chance)
+            {   if ((ocl == b_heinrichobj) && (Near(ob,PLAYER[0],4)))
+                    goto cdoor;
+
+                ob->dir = angletodir[AngleBetween(ob,PLAYER[0])];
+                STOPACTOR(ob);
+#if (SHAREWARE == 0)
+                if ((ocl == overpatrolobj) && (!Near(ob,PLAYER[0],3)) &&
+                        (!PLAYERSTATE[0].NETCAPTURED) && (!MISCVARS->NET_IN_FLIGHT))
+                {   NewState(ob,&s_opbolo1);
+                    MISCVARS->NET_IN_FLIGHT = true;
+                    return;
+                }
+#endif
+                if ((ocl == triadenforcerobj) && (!Near(ob,PLAYER[0],3)))
+                {   NewState(ob,&s_enforcerthrow1);
+                    return;
+                }
+
+                if ((temp=M_S(AIM)) != NULL)
+                {   if ((ob->flags & FL_HASAUTO) && (!ob->temp3))
+                        ob->temp3 = (GameRandomNumber("T_Chase FL_HASAUTO",ocl) % 5) + 3;
+                    ob->target = PLAYER[0];
+                    NewState(ob,temp);
+                    return;
+                }
+
+            }
+            //if ((CheckSight(ob,PLAYER[0])) && (!ob->angle))// &&
+            //(ocl != b_heinrichobj))
+            //ob->flags |= FL_DODGE;
+        }
+
+    }
+cdoor:
+    doorok = NextToDoor(ob);
+
+
+    if (ob->dirchoosetime)
+        ob->dirchoosetime--;
+
+    if ((ob->flags & FL_STUCK) || (!ob->dirchoosetime) || doorok)
+    {   //if (ob->flags & FL_DODGE)
+        // SelectDodgeDir(ob);
+        //else
+        SelectChaseDir(ob);
+        ob->dirchoosetime = M_CHOOSETIME(ob);
+    }
+
+    else
+    {   if (NOMOM)
+            ParseMomentum(ob,dirangle8[ob->dir]);
+        ActorMovement(ob);
+    }
+}
+
+
+
+void SpawnMissile(objtype* shooter,classtype nobclass,int nspeed,int nangle,statetype*nstate,int offset)
+{
+    GetNewActor();
+    MakeActive(new);
+    new->which = ACTOR;
+    new->obclass = nobclass;
+    new->angle = nangle;
+    new->speed = nspeed;
+    if (shooter->obclass == playerobj)
+        offset += FindDistance(shooter->momentumx,shooter->momentumy);
+
+    SetFinePosition(new,shooter->x + FixedMul(offset,costable[nangle]),
+                    shooter->y - FixedMul(offset,sintable[nangle]));
+    SetVisiblePosition(new,new->x,new->y);
+    //SoftError("\n missx:%d, missy:%d, speed:%d, offset:%d, angle%d, drawx:%d, drawy:%d",
+    //         new->x,new->y,nspeed,offset,nangle,new->drawx,new->drawy);
+
+    new->z = shooter->z;
+    new->areanumber = shooter->areanumber;
+    new->soundhandle = -1;
+    if (nobclass != inertobj)
+    {
+        MakeLastInArea(new);
+        if (MissileSound == true)
+            new->soundhandle = SD_PlaySoundRTP(BAS[new->obclass].operate,new->x,new->y);
+    }
+
+    if ((shooter->obclass == playerobj) || (shooter->obclass == wallopobj) ||
+            (shooter->obclass == b_robobossobj))
+    {
+        Set_3D_Momenta(new,new->speed,new->angle,shooter->yzangle);
+
+        if (nobclass == p_drunkmissileobj)
+            new->temp1 = new->momentumz;
+
+        new->z -= FixedMulShift(offset,sintable[shooter->yzangle],26);
+        if ((shooter->obclass == playerobj) && (shooter->flags & FL_GODMODE))
+            new->z -= 10;
+    }
+    else
+        ParseMomentum(new,new->angle);
+
+    if (nobclass == p_drunkmissileobj)
+        new->temp3 = VBLCOUNTER/3;
+
+
+    new->flags |= (FL_NEVERMARK|FL_ABP|FL_NOFRICTION|FL_FULLLIGHT);
+    new->whatever = shooter; // keep track of missile possession
+    NewState(new,nstate);
+}
+
+
+
+/*
+=================
+=
+= T_Roll
+=
+=================
+*/
+
+
+void T_Roll (objtype *ob)
+{
+    ActorMovement(ob);
+
+}
+
+
+
+
+/*
+===============
+=
+= T_Path
+=
+===============
+*/
+
+void T_Path (objtype *ob)
+{   int dx,dy,dz,ocl,damage=1;
+    objtype*temp,*ttarg,*twhat;
+
+
+    ocl = ob->obclass;
+
+    if (((ocl == firejetobj) || (ocl == bladeobj)) && (!ob->ticcount))
+    {
+        if (ocl == bladeobj)
+        {
+            if (ob->state->condition & SF_DOWN )
+                ob->flags &= ~FL_BLOCK;
+            else if (ob->state->condition & SF_UP)
+            {
+                ob->flags |= FL_BLOCK;
+                damage = 0;
+            }
+        }
+
+        if ((ob->state->condition & SF_SOUND) && areabyplayer[ob->areanumber])
+            SD_PlaySoundRTP(BAS[ob->obclass].operate,ob->x,ob->y);
+
+        if (damage)
+        {
+            for(temp=firstareaactor[ob->areanumber]; temp; temp=temp->nextinarea)
+            {
+                if (temp == ob)
+                    continue;
+
+                if (temp->obclass >= roboguardobj)
+                    continue;
+
+                //WAS
+                ttarg = (objtype*)(temp->target);
+                twhat = (objtype*)(temp->whatever);
+
+                if ((M_ISACTOR(ttarg) && (ttarg->obclass == b_robobossobj)) ||
+                        (M_ISACTOR(twhat) && (twhat->obclass == b_robobossobj))
+                   )
+                    continue;
+
+                if ((!(temp->flags & FL_SHOOTABLE)) || (temp->flags & FL_DYING))
+                    continue;
+
+                if (temp->obclass == playerobj)
+                {
+                    if ((temp->flags & FL_GODMODE) || (temp->flags & FL_DOGMODE))
+                        continue;
+                    if ((temp->flags & FL_AV) && (ocl == firejetobj))
+                        continue;
+                }
+                dx = temp->x - ob->x;
+                if (abs(dx) > 0xa000)
+                    continue;
+                dy = temp->y - ob->y;
+                if (abs(dy) > 0xa000)
+                    continue;
+
+                //if (temp->obclass == playerobj)
+                //Collision(temp,-temp->momentumx+ob->momentumx,-temp->momentumy + ob->momentumy);
+                dz = temp->z - ob->z;
+                if (abs(dz) > 32)
+                    continue;
+
+                DamageThing(temp,EnvironmentDamage(ob));
+                if ((ocl == firejetobj) && (temp->obclass < roboguardobj))
+                    SD_PlaySoundRTP(SD_PLAYERBURNEDSND,temp->x,temp->y);
+
+                if ((gamestate.violence == vl_excessive) && (temp->obclass < roboguardobj))
+                {
+                    if (ocl == bladeobj)
+                    {
+                        SpawnParticles(temp,GUTS,1);
+                        if (temp->hitpoints <= 0)
+                            temp->flags |= FL_HBM;
+                    }
+                    else if (ocl == firejetobj)
+                    {
+                        if ((temp->hitpoints <= 0) && (temp->z == nominalheight))
+                        {
+
+                            temp->hitpoints = 0;
+                            temp->flags |= FL_SKELETON;
+                            if (temp->obclass == playerobj)
+                            {
+                                playertype *pstate;
+
+                                temp->flags &= ~FL_COLORED;
+                                M_LINKSTATE(temp,pstate);
+                                pstate->health = 0;
+                                pstate->weapon = -1;
+                            }
+
+                            Collision(temp,ob,-temp->momentumx,-temp->momentumy);
+                            M_CheckPlayerKilled(temp);
+
+                            continue;
+                        }
+                    }
+                }
+                //SD_PlaySoundRTP(SD_ACTORBURNEDSND,temp->x,temp->y);
+
+                //        if ((ocl == bladeobj) || (ob->state->condition == SF_CRUSH))
+                Collision(temp,ob,-temp->momentumx,-temp->momentumy);
+                M_CheckPlayerKilled(temp);
+
+            }
+        }
+    }
+
+
+    if (ob->dir == nodir)
+        return;
+
+    if ((ocl != firejetobj) && (ocl != bladeobj) && (ocl != diskobj))
+    {
+        if (!ob->ticcount)
+        {
+            if (SightPlayer (ob))
+                return;
+        }
+        else
+            SoftError("\n ob type %s with ticcount %d in T_Path",
+                      debugstr[ob->obclass],ob->ticcount);
+    }
+
+    SelectPathDir (ob);
+    if (NOMOM)
+        ParseMomentum(ob,dirangle8[ob->dir]);
+}
+
+
+
+int EnvironmentDamage(objtype *ob)
+{
+    if (BATTLEMODE && (gamestate.BattleOptions.DangerDamage != bo_danger_normal))
+    {
+        return(gamestate.BattleOptions.DangerDamage);
+    }
+    else
+    {
+        int damage = 1;
+
+        switch(ob->obclass)
+        {
+        case firejetobj:
+        case bladeobj:
+            damage = 6;
+            break;
+
+        case boulderobj:
+            damage = 50;
+            break;
+
+        case spearobj:
+            damage = 7;
+            break;
+
+        case gasgrateobj:
+            damage = 20;
+            break;
+
+        case wallfireobj:
+            damage = ((GameRandomNumber("wallfire damage",0) >>3) + 10);
+            break;
+
+        case crushcolobj:
+            damage = 10;
+            break;
+        default:
+            ;
+        }
+
+        if (gamestate.difficulty < gd_hard)
+            damage >>= 1;
+
+        return damage;
+    }
+    //SoftError("unknown environment danger");
+
+}
+
+
+
+
+void T_AutoShootAlign(objtype*ob)
+{
+    if (ob->dir != (dirtype)ob->temp1)
+        ob->dir = dirorder16[ob->dir][NEXT];
+    else
+        NewState(ob,M_S(AIM));
+
+}
+
+
+void T_AutoRealign(objtype*ob)
+{
+    if (ob->dir != (dirtype)ob->targettilex)
+        ob->dir = dirorder16[ob->dir][NEXT];
+    else
+    {   objtype *temp;
+
+        NewState(ob,M_S(PATH));
+        for(temp=firstareaactor[ob->areanumber]; temp; temp=temp->nextinarea)
+        {   if (temp == ob)
+                continue;
+            if (temp->obclass != ob->obclass)
+                continue;
+            if (!temp->state->think)
+                NewState(temp,UPDATE_STATES[PATH][temp->obclass-lowguardobj]);
+        }
+    }
+}
+
+
+/*
+===============
+=
+= T_AutoPath
+=
+===============
+*/
+
+void T_AutoPath (objtype *ob)
+{   objtype *temp;
+
+    // ob->temp3 holds random number of shots before resuming path
+
+    if (CheckLine(ob,PLAYER[0],SIGHT) && (Near(ob,PLAYER[0],4) || MISCVARS->madenoise))
+
+    {   int dx,dy,destdir,ocl;
+        statetype *align,*wait;
+
+        ocl = ob->obclass;
+        dx = player->x - ob->x;
+        dy = ob->y - player->y;
+        destdir = (angletodir[atan2_appx(dx,dy)] << 1);
+        ob->temp1 = destdir;
+        ob->targettilex = ob->dir; //save old dir
+#if (SHAREWARE == 0)
+        if (ocl == wallopobj)
+        {   //if (ob->temp3)
+            // Error("may be writing over temp3");
+            ob->temp3 = (GameRandomNumber("T_WallPath",0)%4) + 1;
+            align = &s_wallalign;
+            wait = &s_wallwait;
+        }
+        else
+#endif
+        {   align = &s_roboalign;
+            wait = &s_robowait;
+        }
+
+        NewState(ob,align);
+        for(temp=firstareaactor[ob->areanumber]; temp; temp=temp->nextinarea)
+        {   if (temp == ob)
+                continue;
+
+            if (temp->obclass != ob->obclass)
+                continue;
+
+            if (temp->flags & FL_DYING)
+                continue;
+
+            if (CheckLine(temp,PLAYER[0],SIGHT) && (Near(temp,PLAYER[0],4) || MISCVARS->madenoise))
+            {   dx = PLAYER[0]->x - temp->x;
+                dy = temp->y - PLAYER[0]->y;
+                destdir = (angletodir[atan2_appx(dx,dy)] << 1);
+
+                temp->temp1 = destdir;
+                temp->targettilex = temp->dir;
+                NewState(temp,align);
+                temp->temp3 = ob->temp3;
+            }
+            else
+                NewState(temp,wait);
+        }
+        return;
+    }
+
+    SD_PlaySoundRTP(SD_ROBOTMOVESND,ob->x,ob->y);
+
+    SelectPathDir(ob);
+
+}
+
+
+
+
+/*
+===============
+=
+= A_Shoot
+=
+= Try to damage the player, based on skill level and player's speed
+=
+===============
+*/
+
+void A_Shoot (objtype *ob)
+{
+    int   dx,dy,dz,dist;
+    int   accuracy,damage,sound;
+    objtype * target;
+    int   num;
+    int   savedangle;
+
+    ActorMovement(ob);
+
+    ob->flags |= FL_FULLLIGHT;
+//if (!(ob->flags & FL_SHOOTABLE))
+    //Error("\na dead instance of %s is shooting at you",debugstr[ob->obclass]);
+
+    if (!ob->ticcount)
+    {   if (ob->obclass == strikeguardobj)
+            ob->flags &= ~FL_NOFRICTION;
+
+        target = (objtype*)(ob->target);
+        if (!target)
+            Error("an instance of %s called shoot without a target\n",debugstr[ob->obclass]);
+
+
+        ob->flags &= ~FL_FULLLIGHT;
+
+
+        dx = (target->x - ob->x);
+        dy = (ob->y - target->y);
+        dz = target->z-ob->z;
+
+
+        if ((ob->obclass == blitzguardobj) && (ob->temp3) &&
+                (ob->temp3 != stat_gasmask) && (ob->temp3 != stat_asbesto) &&
+                (ob->temp3 != stat_bulletproof) &&
+                (gamestate.difficulty >= gd_medium) &&
+                ((abs(dx) > 0xc000) || (abs(dy) > 0xc000))
+           )
+        {
+            int i;
+            missile_stats* newmissiledata;
+
+            newmissiledata = &PlayerMissileData[GetWeaponForItem(ob->temp3)];
+
+            // ready to annihilate this poor bastard
+
+            SpawnMissile(ob,newmissiledata->obclass,newmissiledata->speed,
+                         AngleBetween(ob,player), newmissiledata->state,
+                         newmissiledata->offset);
+
+            if (newmissiledata->obclass == p_drunkmissileobj)
+            {
+                for(i=0; i<4; i++)
+                {
+                    SpawnMissile(ob,newmissiledata->obclass,newmissiledata->speed,
+                                 AngleBetween(ob,player), newmissiledata->state,
+                                 newmissiledata->offset);
+                }
+            }
+            ob->target = NULL;
+            ob->temp2 --;
+            if (ob->temp2 == 0)
+                ob->temp3 = 0;
+            return;
+        }
+
+
+        if ((!areabyplayer[ob->areanumber]) && (target->obclass ==  playerobj))
+            return;
+
+        //if (!CheckLine(ob,target,SHOOT))       // player is behind a wall
+        //return;
+
+
+        savedangle=ob->angle;
+        ob->angle = atan2_appx (dx,dy);
+        dist = FindDistance(dx,dy);
+        ob->yzangle = FINEANGLES-atan2_appx(dist, dz<<10);
+
+        if ((ob->yzangle>MAXYZANGLE) && (ob->yzangle<FINEANGLES-MAXYZANGLE))
+            ob->yzangle=MAXYZANGLE;
+
+        dist>>=16;
+
+        accuracy=(WHICHACTOR<<4)+((gamestate.difficulty) << 6);
+
+        num = GameRandomNumber("A_Shoot3",ob->obclass);
+
+        if (num<128) num=128; // Don't let accuracy fall below 50% original
+
+        accuracy=FixedMulShift(num,accuracy,8); // scale accuracy based off randomness
+
+        // check for maximum accuracy;
+
+        if (accuracy>255) accuracy=255;
+
+        if (ob->obclass==highguardobj)
+            damage=DMG_MP40;
+        else if (ob->obclass == triadenforcerobj)
+            damage=DMG_MP40;
+        else
+            damage=DMG_ENEMYBULLETWEAPON;
+
+
+        RayShoot (ob, damage, 255-accuracy);
+
+        ob->angle=savedangle;
+        sound = BAS[ob->obclass].fire;
+        SD_PlaySoundRTP(sound,ob->x,ob->y);
+        MISCVARS->madenoise = true;
+        if ((!(ob->flags& FL_HASAUTO)) || (!ob->temp3))
+            ob->target = NULL;
+    }
+}
+
+
+
+
+void A_Repeat(objtype*ob)
+{
+    ActorMovement(ob);
+
+    if (!ob->ticcount)
+    {   ob->temp3 --;
+        if (ob->temp3 <= 0)
+            NewState(ob,M_S(CHASE));
+    }
+
+}
+
+
+void  A_MissileWeapon(objtype *ob)
+{
+    int    sound,nspeed,noffset,zoffset;
+
+#if (SHAREWARE == 0)
+    int oldyzangle;
+#endif
+    classtype nobclass;
+    statetype*nstate;
+
+
+    if ((ob->obclass == wallopobj) || (ob->obclass == roboguardobj));
+    //SelectPathDir(ob);
+    else
+        ActorMovement(ob);
+
+    if (!ob->ticcount)
+    {
+#if (SHAREWARE == 0)
+        if ((ob->obclass == wallopobj) && (!ob->temp3))
+        {
+            NewState(ob,&s_wallrestore);
+            return;
+        }
+#endif
+        if ((ob->obclass == b_darianobj) && (!CheckLine(ob,PLAYER[0],SHOOT)))
+        {   NewState(ob,M_S(CHASE));
+            return;
+        }
+// Move sounds, flags into switch cases
+
+        sound = BAS[ob->obclass].fire;
+        nspeed = 0x4000;
+        noffset = 0x8000;
+        zoffset = 0;
+        switch (ob->obclass)
+        {
+
+        case triadenforcerobj:
+            nobclass = grenadeobj;
+            nstate= &s_grenade1;
+            sound++;
+            break;
+
+
+        case roboguardobj:
+            nobclass = shurikenobj;
+            nspeed = 0x2000;
+            noffset = 0x10000;
+            nstate = &s_robogrdshuriken1;
+            break;
+
+            /*
+             case b_darkmonkobj:
+            nobclass = dmfballobj;
+            nstate = &s_dmfball1;
+            break;
+             */
+            /*
+            case b_robobossobj:
+            nobclass = bigshurikenobj;
+            nstate = &s_oshuriken1;
+            break;
+             */
+#if (SHAREWARE == 0)
+        case b_darianobj:
+            nobclass = missileobj;
+            //nspeed = 0x100;
+            //noffset = 0x18000;
+            nstate = &s_missile1;
+            zoffset = -20;
+            break;
+
+
+        case dfiremonkobj:
+            nobclass = fireballobj;
+            nstate = &s_monkfire1;
+            break;
+
+
+        case overpatrolobj:
+            nobclass = netobj;
+            nstate = &s_bolocast1;
+            sound ++;
+            break;
+
+
+        case wallopobj:
+        {   int dx,dy,dz,xydist;
+
+            ob->temp2 ^= 1; // increment numfired
+            ob->temp3 --; // decrement random fire no.
+
+
+            dx = PLAYER[0]->x-ob->x;
+            dy = ob->y-PLAYER[0]->y;
+            if (GameRandomNumber("bcraft shoot up/down",0) < 128)
+                dz = 10;
+            else
+                dz = -10;
+            xydist = FindDistance(dx,dy);
+            oldyzangle = ob->yzangle;
+            ob->yzangle = atan2_appx(xydist,dz<<10);
+            if (ob->temp2)
+            {   nobclass = missileobj;
+                nstate = &s_missile1;
+            }
+            else
+            {   nobclass = bigshurikenobj;
+                nstate = &s_bstar1;
+            }
+        }
+        break;
+#endif
+        default:
+            ;
+        }
+
+        SpawnMissile(ob,nobclass,nspeed,AngleBetween(ob,PLAYER[0]),nstate,noffset);
+        new->z += zoffset;
+        SD_PlaySoundRTP(sound,ob->x,ob->y);
+        MISCVARS->madenoise = true;
+        if (ob->obclass == triadenforcerobj)
+        {   //new->flags |= (FL_SHOOTABLE);
+            new->temp1 = 0x50000;
+        }
+#if (SHAREWARE == 0)
+        else if (ob->obclass == wallopobj)
+            ob->yzangle = oldyzangle;
+#endif
+
+
+    }
+}
+
+
+void   A_Wallfire(objtype *ob)
+{
+    if (!(ob->flags & FL_ACTIVE))
+        return;
+
+    if (!ob->ticcount)
+    {   SpawnMissile(ob,wallfireobj,0x4000,ob->angle,&s_crossfire1,0xa000);
+        if (areabyplayer[ob->areanumber])
+            SD_PlaySoundRTP(SD_FIRECHUTESND,ob->x,ob->y);
+        new->dir = angletodir[new->angle];
+        new->z = nominalheight;
+    }
+
+}
+
+
+void T_Reset(objtype *ob)
+{
+    ActorMovement(ob);
+
+    if (ob->ticcount)
+        return;
+
+    ob->momentumx = ob->momentumy = ob->dirchoosetime = 0;
+    ob->flags &= ~FL_NOFRICTION;
+
+
+
+}
+
+void SelectRollDir(objtype *ob)
+{   int angle,tryx,tryy;
+
+
+    if (ob->state == &s_strikerollright1)
+        angle = AngleBetween(ob,PLAYER[0]) + ANGLES/4;
+    else
+        angle = AngleBetween(ob,PLAYER[0]) - ANGLES/4;
+
+    Fix(angle);
+    tryx = ob->x + FixedMul(0x20000l,costable[angle]);
+    tryy = ob->y - FixedMul(0x20000l,sintable[angle]);
+    ZEROMOM;
+    if (QuickSpaceCheck(ob,tryx,tryy))
+    {   int oldspeed;
+
+        oldspeed = ob->speed;
+        ob->speed = ROLLMOMENTUM;
+        ParseMomentum(ob,angle);
+        ob->speed = oldspeed;
+        ob->dirchoosetime = 5;
+        ob->flags |= FL_NOFRICTION;
+    }
+    else
+        ob->dirchoosetime = 0;
+
+
+}
+
+
+void SelectDodgeDir (objtype *ob)
+{
+    int      dx,dy,i,tx,ty;
+    unsigned absdx,absdy;
+    dirtype  dirtry[5];
+    dirtype  turnaround,tdir,olddir;
+
+
+    olddir = ob->dir;
+    if (ob->flags & FL_FIRSTATTACK)
+    {
+        //
+        // turning around is only ok the very first time after noticing the
+        // player
+        //
+        turnaround = nodir;
+        ob->flags &= ~FL_FIRSTATTACK;
+    }
+    else
+        turnaround=opposite[ob->dir];
+
+
+    if (ob->targettilex || ob->targettiley)
+    {   tx = ob->targettilex;
+        ty = ob->targettiley;
+        dx= tx - ob->x;
+        dy= ty - ob->y;
+        if ( ((dx < MINACTORDIST) && (dx > -MINACTORDIST)) &&
+                ((dy < MINACTORDIST) && (dy > -MINACTORDIST)))
+        {   dx= PLAYER[0]->x-ob->x;
+            dy= PLAYER[0]->y-ob->y;
+        }
+    }
+    else
+    {   dx= PLAYER[0]->x-ob->x;
+        dy= PLAYER[0]->y-ob->y;
+    }
+
+
+
+//
+// arange 5 direction choices in order of preference
+// the four cardinal directions plus the diagonal straight towards
+// the player
+//
+    if (dx>ACTORSIZE)
+    {
+        dirtry[1]= east;
+        dirtry[3]= west;
+    }
+    else if (dx < -ACTORSIZE)
+    {
+        dirtry[1]= west;
+        dirtry[3]= east;
+    }
+
+    if (dy>ACTORSIZE)
+    {
+        dirtry[2]= south; // south
+        dirtry[4]= north; // north
+    }
+    else if (dy <-ACTORSIZE)
+    {
+        dirtry[2]= north; // north
+        dirtry[4]= south; // south
+    }
+
+//
+// randomize a bit for dodging
+//
+    absdx = abs(dx);
+    absdy = abs(dy);
+
+    if (absdx > absdy)
+    {
+        tdir = dirtry[1];
+        dirtry[1] = dirtry[2];
+        dirtry[2] = tdir;
+        tdir = dirtry[3];
+        dirtry[3] = dirtry[4];
+        dirtry[4] = tdir;
+    }
+
+    if (GameRandomNumber("SelectDogeDir",ob->obclass) < 128)
+    {
+        tdir = dirtry[1];
+        dirtry[1] = dirtry[2];
+        dirtry[2] = tdir;
+        tdir = dirtry[3];
+        dirtry[3] = dirtry[4];
+        dirtry[4] = tdir;
+    }
+
+    dirtry[0] = diagonal [dirtry[1]] [dirtry[2]];
+
+    ZEROMOM;
+
+    for (i=0; i<5; i++)
+    {   if ((dirtry[i] == nodir) || (dirdiff[dirtry[i]][olddir] > 1))
+            continue;
+
+        M_CHECKDIR(ob,dirtry[i]);
+    }
+
+//
+// turn around only as a last resort
+//
+//	for(tdir = east;tdir<=southeast;tdir++)
+    //if (tdir != turnaround)
+//	 M_CHECKDIR(ob,tdir);
+
+    if (turnaround != nodir)
+        M_CHECKDIR(ob,turnaround);
+
+}
+
+
+
+
+#define TryAbruptProximalDirections(trydir)             \
+   {                                                    \
+   next = dirorder[trydir][NEXT];                       \
+   prev = dirorder[trydir][PREV];                       \
+   if (GameRandomNumber("actor choose dir",0) < 128)    \
+      {                                                 \
+      dirtype temp = next;                              \
+                                                        \
+      next = prev;                                      \
+      prev = temp;                                      \
+      }                                                 \
+                                                        \
+   if (!dirtried[next])                                 \
+      {                                                 \
+      M_CHECKDIR(ob,next);                              \
+      dirtried[next]=1;                                 \
+      }                                                 \
+                                                        \
+   if (!dirtried[prev])                                 \
+      {                                                 \
+      M_CHECKDIR(ob,prev);                              \
+      dirtried[prev]=1;                                 \
+      }                                                 \
+                                                        \
+   }
+
+
+#define TrySmoothProximalDirections(trydir)                        \
+   {                                                               \
+                                                                   \
+   if (((trydir == olddir) || (dirdiff[trydir][olddir] < 2)) &&    \
+      (!dirtried[trydir]))                                         \
+      {                                                            \
+      M_CHECKDIR(ob,trydir);                                       \
+      dirtried[trydir] = 1;                                        \
+      }                                                            \
+   next = dirorder[olddir][NEXT];                                  \
+   prev = dirorder[olddir][PREV];                                  \
+                                                                   \
+   if (dirdiff[trydir][next] <= dirdiff[trydir][prev])             \
+      {                                                            \
+      start = next;                                                \
+      whichway = NEXT;                                             \
+      }                                                            \
+   else                                                            \
+      {                                                            \
+      start = prev;                                                \
+      whichway = PREV;                                             \
+      }                                                            \
+                                                                   \
+   for (tdir= start; tdir != dirorder[trydir][whichway];           \
+        tdir = dirorder[tdir][whichway]                            \
+       )                                                           \
+      {                                                            \
+      if (dirtried[tdir])                                          \
+         continue;                                                 \
+      M_CHECKDIR(ob,tdir);                                         \
+      dirtried[tdir]=1;                                            \
+      }                                                            \
+                                                                   \
+   }
+
+
+
+#define ChasePlayer(ob)                          \
+   {                                             \
+   dx= player->x-ob->x;                          \
+   dy= ob->y-player->y;                          \
+   if ((abs(dx) < 0xb000) && (abs(dy) < 0xb000)) \
+      return;                                    \
+   dummy.x = player->x;                          \
+   dummy.y = player->y;                          \
+   }
+
+
+void SelectChaseDir (objtype *ob)
+{
+    int dx,dy,whichway,tx,ty,actrad,visible,
+        realdiff;
+    dirtype dtry1,dtry2,tdir,olddir,next,prev,start,straight;
+    tpoint dummy;
+    byte dirtried[9] = {0};
+
+    olddir=ob->dir;
+    visible = CheckLine(ob,PLAYER[0],SIGHT);
+
+    /*
+    if (ob->flags & FL_FIRSTATTACK)
+    {
+    //
+    // turning around is only ok the very first time after noticing the
+    // player
+    //
+    	turnaround = opposite[ob->dir];
+    	ob->flags &= ~FL_FIRSTATTACK;
+    }
+    else
+    	turnaround=nodir;
+    */
+    dummy.which = ACTOR;
+    dummy.z = ob->z;
+    if (ob->targettilex || ob->targettiley)
+    {
+        tx = ob->targettilex;
+        ty = ob->targettiley;
+        dx= tx - ob->x;
+        dy= ob->y - ty;
+        dummy.x = tx;
+        dummy.y = ty;
+        if ((abs(dx) < 0x2000) && (abs(dy) < 0x2000))
+            ChasePlayer(ob);
+    }
+    else
+        ChasePlayer(ob);
+
+    //if ((abs(dx) < 0x10000) && (abs(dy) < 0x10000))
+    //return;
+    straight = angletodir[atan2_appx(dx,dy)];
+    realdiff = dirdiff[straight][ob->dir];
+    ZEROMOM;
+
+    //insertion 20
+
+    actrad = ACTORSIZE;
+    dtry1=nodir;
+    dtry2=nodir;
+
+    if (dx> actrad)
+        dtry1= east;
+    else if (dx< -actrad)
+        dtry1= west;
+    if (dy> actrad)
+        dtry2=north;
+    else if (dy < -actrad)
+        dtry2= south;
+
+
+    if (abs(dy)>abs(dx))
+    {
+        tdir=dtry1;
+        dtry1=dtry2;
+        dtry2=tdir;
+    }
+
+    if (GameRandomNumber("chase minor",0) < 80)
+    {
+        tdir=dtry1;
+        dtry1=dtry2;
+        dtry2=tdir;
+    }
+
+    ZEROMOM;
+
+    if ((!visible) || (realdiff > 2))  // don't worry about abrupt or unrealistic turns if player
+        // can't see guards
+    {
+        M_CHECKDIR(ob,straight);
+        dirtried[straight]=1;
+        next = dirorder[straight][NEXT];
+        prev = dirorder[straight][PREV];
+
+        if ((dtry1 != nodir) && (dtry1 != straight))
+        {
+            M_CHECKDIR(ob,dtry1);
+            dirtried[dtry1]=1;
+        }
+
+
+        if ((dtry2 != nodir) && (!dirtried[dtry2]))
+        {
+            M_CHECKDIR(ob,dtry2);
+            dirtried[dtry2]=1;
+        }
+
+        if (dtry1 != nodir)
+            TryAbruptProximalDirections(dtry1);
+
+        if (dtry2 != nodir)
+            TryAbruptProximalDirections(dtry2);
+    }
+
+    else
+    {
+        if (realdiff < 2)
+        {
+            M_CHECKDIR(ob,straight);
+            dirtried[straight]=1;
+        }
+
+        if (dtry1 != nodir)
+            TrySmoothProximalDirections(dtry1);
+
+        if (dtry2 != nodir)
+            TrySmoothProximalDirections(dtry2);
+
+    }
+
+    if ((dtry1!=nodir) || (dtry2!=nodir))
+    {
+        if (GameRandomNumber("actor choose dir",0) < 128)
+            whichway = NEXT;
+        else
+            whichway = PREV;
+
+        for(tdir = dirorder[olddir][whichway]; tdir != olddir; tdir = dirorder[tdir][whichway])
+        {
+            if (dirtried[tdir])
+                continue;
+            M_CHECKDIR(ob,tdir);
+        }
+    }
+
+    ob->dir = olddir;
+}
+
+
+
+int Near(objtype *ob,void* what,int distance)
+
+{
+    objtype *aw;
+
+    aw = (objtype*) what;
+
+    if (FindDistance((aw->x - ob->x),(aw->y - ob->y)) <= (distance<<16))
+        return 1;
+    return 0;
+
+}
+
+
+
+/*
+===============
+=
+= SelectPathDir
+=
+===============
+*/
+
+void SelectPathDir (objtype *ob)
+{
+    int spot,centerx,centery,dx,dy,set,done,radius,ocl;
+
+    ocl = ob->obclass;
+
+
+    if ((ocl == bladeobj) && (!(ob->flags & FL_ACTIVE)))
+        return;
+
+    spot = MAPSPOT(ob->tilex,ob->tiley,1)-ICONARROWS;
+    set = ((ocl == wallopobj) || (ocl == roboguardobj));
+    done = (((!set) && (ob->dir == (dirtype)spot)) ||
+            (set && (ob->dir == (dirtype)(spot<<1))));
+
+    if ((spot >= 0) && (spot<= 7) && (!done))
+    {
+        centerx= (ob->tilex << 16) + HALFGLOBAL1;
+        centery= (ob->tiley << 16) + HALFGLOBAL1;
+        dx = abs(centerx - ob->x);
+        dy = abs(centery - ob->y);
+        //radius = (ob->speed > 0x4800)?(0xb000):(0x4000);
+        radius = 0x4000;
+
+        if ((dx < radius) && (dy < radius))
+            // new direction
+        {
+            ZEROMOM;
+            if ((ocl == wallopobj) || (ocl == roboguardobj))
+            {
+                ob->dir = spot<<1;
+                ParseMomentum(ob,dirangle16[ob->dir]);
+            }
+            else
+            {
+                ob->dir = spot;
+                ParseMomentum(ob,dirangle8[ob->dir]);
+            }
+            dx = centerx - ob->x;
+            dy = centery - ob->y;
+            SetFinePosition(ob,centerx,centery);
+            SetVisiblePosition(ob,centerx,centery);
+            /*
+            if (((ocl == bladeobj) || (ocl == diskobj)) && ob->whatever)
+            {objtype*passenger = (objtype*)(ob->whatever);
+
+             passenger->x += dx;
+             passenger->y += dy;
+             passenger->drawx = passenger->x;
+             passenger->drawy = passenger->y;
+             passenger->tilex = passenger->x >> 16;
+             passenger->tiley = passenger->y >> 16;
+            }*/
+//		 if (ob==SNAKEHEAD)
+//		  Debug("\n path changed at %d, %d",
+//			ob->tilex,ob->tiley);
+        }
+    }
+    if (NOMOM)
+    {
+        if ((ocl == wallopobj) || (ocl == roboguardobj))
+            ParseMomentum(ob,dirangle16[ob->dir]);
+        else
+            ParseMomentum(ob,dirangle8[ob->dir]);
+    }
+
+    //if ((ob->obclass == firejetobj) || (ob->obclass == bladeobj))
+    //MoveActor(ob);
+    //else
+    ActorMovement(ob);
+
+}
+
+
+
+/*
+================
+=
+= CheckSight
+=
+= Checks a straight line between player and current object
+=
+= If the sight is ok, check alertness and angle to see if they notice
+=
+= returns true if the player has been spoted
+=
+================
+*/
+
+
+boolean CheckSight (objtype *ob,void *atwhat)
+{
+    long     deltax,deltay;
+    objtype * what;
+//
+// don't bother tracing a line if the area isn't connected to the player's
+//
+    if (!areabyplayer[ob->areanumber])
+        return false;
+
+//
+// if the player is real close, sight is automatic
+//
+    what = (objtype*)atwhat;
+    deltax = what->x - ob->x;
+    deltay = what->y - ob->y;
+
+    if ((deltax > -MINSIGHT) && (deltax < MINSIGHT)	&&
+            (deltay > -MINSIGHT) && (deltay < MINSIGHT))
+        return true;
+
+//
+// see if they are looking in the right direction
+//
+    switch (ob->dir)
+    {
+    case north:
+        if (deltay > 0)
+            return false;
+        break;
+
+    case east:
+        if (deltax < 0)
+            return false;
+        break;
+
+    case south:
+        if (deltay < 0)
+            return false;
+        break;
+
+    case west:
+        if (deltax > 0)
+            return false;
+        break;
+    default:
+        ;
+    }
+
+//
+// trace a line to check for blocking tiles (corners)
+//
+    return CheckLine (ob,atwhat,SIGHT);
+
+}
+
+
+
+void ActivateEnemy(objtype*ob)
+{   statetype *temp;
+
+
+    ob->flags |= (FL_ATTACKMODE|FL_FIRSTATTACK);
+    if (ob->obclass == roboguardobj)
+        return;
+
+    if (ob->temp3 == SNEAKY)
+    {   NewState(ob,&s_sneakyrise1);
+        ob->temp3=0;
+    }
+    else if ((temp = M_S(CHASE)) != NULL)
+        NewState(ob,temp);
+    /*
+    ob->speed = ENEMYRUNSPEED;
+    */
+    if (ob->obclass == b_heinrichobj)
+        ob->speed = 7*ob->speed/2;
+    else if (ob->obclass == b_darianobj)
+        ob->speed = 3*SPDPATROL;
+    if (ob->door_to_open != -1)
+        ob->door_to_open = -1; // ignore the door opening command
+    ob->dirchoosetime = 0;
+
+
+}
+
+
+/*
+===============
+=
+= FirstSighting
+=
+= Puts an actor into attack mode and possibly reverses the direction
+= if the player is behind it
+=
+===============
+*/
+
+void FirstSighting (objtype *ob)
+{
+    statetype *temp;
+    int sound;
+
+    if (ob->temp3 == SNEAKY)
+    {
+        NewState(ob,&s_sneakyrise1);
+        ob->temp3=0;
+        if (ob->shapeoffset==0)
+            SD_PlaySoundRTP(SD_SNEAKYSPRINGMSND,ob->x,ob->y);
+        else
+            SD_PlaySoundRTP(SD_SNEAKYSPRINGFSND,ob->x,ob->y);
+    }
+    else if ((temp = M_S(CHASE)) != NULL)
+    {
+        int rand;
+
+        NewState(ob,temp);
+        sound = BAS[ob->obclass].see;
+        rand = GameRandomNumber("FirstSighting low",0);
+        if ((ob->obclass > lowguardobj) && (ob->obclass <= blitzguardobj) && (rand < 128)) //hack for alternate
+            sound++;
+        //if ((ob->obclass == lowguardobj) && (rand < 80))
+        //sound ++;
+        else if (ob->obclass == lowguardobj)
+        {   if (rand < 128)
+            {   if ((PLAYERSTATE[0].player == 1) || (PLAYERSTATE[0].player == 3))
+                    sound++;
+            }
+            else
+                sound += 2;
+
+            if (ob->shapeoffset)
+                sound += 4;
+
+        }
+        SD_PlaySoundRTP(sound,ob->x,ob->y);
+        if ((ob->obclass>=b_darianobj) && (ob->obclass<=b_darksnakeobj))
+        {
+            MU_StartSong(song_bosssee);
+        }
+    }
+
+    /*
+    ob->speed = ENEMYRUNSPEED;*/
+    if (ob->obclass == b_heinrichobj)
+        ob->speed = 7*ob->speed/2;
+    else if (ob->obclass == b_darianobj)
+        ob->speed = 3*SPDPATROL;
+    if (ob->door_to_open != -1)
+        ob->door_to_open = -1; // ignore the door opening command
+    ob->dirchoosetime = 0;
+    ob->flags |= (FL_ATTACKMODE|FL_FIRSTATTACK);
+
+}
+
+
+/*
+===============
+=
+= SightPlayer
+=
+= Called by actors that ARE NOT chasing the player.  If the player
+= is detected (by sight, noise, or proximity), the actor is put into
+= it's combat frame and true is returned.
+=
+= Incorporates a random reaction delay
+=
+===============
+*/
+
+boolean SightPlayer (objtype *ob)
+{
+    //if (ob->flags & FL_ATTACKMODE)
+    //Error ("An instance of %s in ATTACKMODE called SightPlayer!",debugstr[ob->obclass]);
+
+    if (!areabyplayer[ob->areanumber])
+        return false;
+
+    if (ob->obclass == b_robobossobj)
+    {
+        if (!(CheckSight(ob,player) || Near(ob,player,6)))
+            return false;
+
+    }
+
+
+    else if (ob->flags & FL_AMBUSH)
+    {
+        if (!CheckSight (ob,PLAYER[0]))
+        {
+            //SoftError("\n failed from ambush in SightPlayer");
+            return false;
+        }
+        ob->flags &= ~FL_AMBUSH;
+    }
+    else
+    {
+        if (ob->temp3 == SNEAKY)
+        {
+            if (!Near(ob,PLAYER[0],2))
+                return false;
+        }
+        else if (!((MISCVARS->madenoise) ||
+                   (CheckSight (ob,player)) ||
+                   (Near(ob,player,4))
+                  )
+                )
+        {
+            //SoftError("\n failed from SightPlayer");
+            return false;
+        }
+    }
+
+    FirstSighting (ob);
+
+    return true;
+}
+
+
+/*
+=====================
+=
+= CheckLine
+=
+= Returns true if a straight line between two obs is unobstructed
+=
+=====================
+*/
+
+
+
+boolean CheckLine (void *from, void *to, int condition)
+{
+    objtype   *tempactor,*ob,*orig;
+    statobj_t *checksprite;
+    int destx,desty,destz;
+    int desttilex,desttiley;
+    int snx,sny;
+    int incr[2];
+    int thedir[2];
+    int cnt;
+    int grid[2];
+    int index;
+    int vx,vy;
+    int yzangle;
+    int value;
+    int dx,dy,dz;
+    int xydist;
+    int otx,oty,count=0;
+
+
+
+    ob = (objtype*)to;
+    orig = (objtype*)from;
+    if (ob->which == SPRITE)
+    {
+        destx = ((statobj_t*)to)->x;
+        desty = ((statobj_t*)to)->y;
+        destz = ((statobj_t*)to)->z;
+    }
+    else
+    {
+        destx = ob->x;
+        desty = ob->y;
+        destz = ob->z;
+    }
+
+    desttilex=destx>>16;
+    desttiley=desty>>16;
+
+    if ((desttilex == orig->tilex) && (desttiley == orig->tiley))
+        return true;
+
+
+    dx=destx-orig->x;
+    dy=orig->y-desty;
+    dz=orig->z-destz;
+    xydist = FindDistance(dx,dy);
+    yzangle = atan2_appx(xydist,dz<<10);
+
+    if ((yzangle>MAXYZANGLE) && (yzangle<FINEANGLES-MAXYZANGLE))
+    {
+#if (0)
+        Debug("\nfailed from yzangle");
+#endif
+        return false;
+    }
+
+    //angle = atan2_appx(dx,dy);
+    otx = orig->x >> TILESHIFT;
+    oty = orig->y >> TILESHIFT;
+
+    if (xydist==0)
+    {
+        /*
+        SoftError("\nCheckLine:xydist=0");
+        if (orig->which == ACTOR)
+          SoftError("shooter: %s",debugstr[orig->obclass]);
+        if (ob->which == ACTOR)
+          SoftError("target: %s",debugstr[ob->obclass]);*/
+        vy=-dy;
+        vx=dx;
+    }
+    else
+    {
+        vy = -FixedDiv2(dy,xydist);
+        vx = FixedDiv2(dx,xydist);
+    }
+    snx=orig->x&0xffff;
+    sny=orig->y&0xffff;
+
+    grid[0]=otx;
+    grid[1]=oty;
+
+    if (vx>0)
+    {
+        thedir[0]=1;
+        snx^=0xffff;
+        incr[1]=-vx;
+    }
+    else
+    {
+        thedir[0]=-1;
+        incr[1]=vx;
+    }
+    if (vy>0)
+    {
+        thedir[1]=1;
+        sny^=0xffff;
+        incr[0]=vy;
+    }
+    else
+    {
+        thedir[1]=-1;
+        incr[0]=-vy;
+    }
+    cnt=FixedMul(snx,incr[0])+FixedMul(sny,incr[1]);
+
+
+    do
+    {   count ++;
+        /*
+        if (count > 1000)
+          Error("possible infinite loop in CheckLine");
+         if ((grid[0] < 0) || (grid[0] > (MAPSIZE-1)) ||
+        	  (grid[1] < 0) || (grid[1] > (MAPSIZE-1)))
+        	Error("out of bounds in check line, grid[0] = %d, grid[1] = %d",grid[0],grid[1]);
+         */
+        if ((grid[0]==desttilex) && (grid[1]==desttiley))
+            return true;
+        tempactor = (objtype*)actorat[grid[0]][grid[1]];
+        value = tilemap[grid[0]][grid[1]];
+        checksprite = sprites[grid[0]][grid[1]];
+        if (value)
+        {
+            if (value&0x8000)
+            {
+                if (!(value&0x4000))
+                {
+                    doorobj_t*dptr = doorobjlist[value&0x3ff];
+
+                    if (dptr->position < 0x8000)
+                    {
+
+                        int x = (grid[0] << 16) + 0x8000;
+                        int y = (grid[1] << 16) + 0x8000;
+
+                        if (dptr->vertical)
+                        {
+                            if (abs(dx) > abs(x-orig->x))
+                                return false;
+                        }
+                        else
+                        {
+                            if (abs(dy) > abs(orig->y-y))
+                                return false;
+                        }
+                    }
+                }
+                else
+                {
+                    if (condition == SHOOT)
+                    {
+                        if ( maskobjlist[value&0x3ff]->flags & MW_SHOOTABLE )
+                        {
+#if (0)
+                            SoftError("\nfailed from shootable mask");
+#endif
+                            return false;
+                        }
+                        else if ( maskobjlist[value&0x3ff]->flags & MW_WEAPONBLOCKING )
+                        {
+#if (0)
+                            SoftError("\nfailed from block mask");
+#endif
+                            return false;
+                        }
+                    }
+                    else if ((condition == MISSILE) &&
+                             ( maskobjlist[value&0x3ff]->flags & MW_BLOCKING )
+                            )
+                        return false;
+                }
+            }
+            else
+            {
+#if (0)
+                SoftError("\n obx %d, oby %d, origx %d, origy %d"
+                          "\n xydist %d, vx %d, vy %d",ob->x,ob->y,orig->x,
+                          orig->y,xydist,vx,vy);
+
+                SoftError("\nfailed from normal wall");
+#endif
+                return false;
+            }
+        }
+        if (condition == SHOOT)
+        {
+            if (tempactor && (tempactor->which == ACTOR) &&
+                    (tempactor->flags & FL_BLOCK) && (tempactor != orig) &&
+                    (tempactor != ob)) //&&
+//   			(InRange(orig,tempactor,
+//             FindDistance(orig->x-tempactor->x,orig->y-tempactor->y) )
+//             ==true) )
+            {
+#if (0)
+                SoftError("\nfailed from actor");
+#endif
+                return false;
+            }
+        }
+
+        if (checksprite && (checksprite->flags & FL_BLOCK) && (condition == SHOOT) &&
+                ((void *)checksprite != to) &&
+                (checksprite->itemnumber!=stat_disk) &&
+                (InRange(orig,(objtype *)checksprite,
+                         FindDistance(orig->x-checksprite->x,orig->y-checksprite->y) )
+                 ==true) )
+
+        {
+#if (0)
+            SoftError("\nfailed from sprite");
+#endif
+            return false;
+        }
+
+        if (tempactor && (tempactor->which == PWALL))
+        {
+#if (0)
+            SoftError("\nfailed from pushwall");
+#endif
+            return false;
+        }
+        index=(cnt>=0);
+        cnt+=incr[index];
+        grid[index]+=thedir[index];
+    }
+    while (1);
+}
+
+
+
+
+
+
+
+/*
+=====================
+=
+= ShootActor
+=
+= Shoot an actor.
+=
+=====================
+*/
+void ShootActor(objtype * shooter, objtype * target, int damage, int accuracy, int angle)
+{
+    int dx,dy,dist;
+    int newmomx, newmomy;
+    int tcl;
+
+
+    if (target->flags & FL_DYING)
+        return;
+
+    dx = abs(shooter->x - target->x);
+    dy = abs(shooter->y - target->y);
+    dist = FindDistance(dx,dy)>>16;
+
+    tcl=target->obclass;
+
+    if (tcl==playerobj)
+    {
+        target->target=shooter;
+        if (target->flags&FL_BPV)
+        {
+            playertype *pstate;
+
+            M_LINKSTATE(target,pstate);
+            pstate->protectiontime -= (damage<<1);
+            if (pstate->protectiontime < 1)
+                pstate->protectiontime = 1;
+            if (target==player)
+                GM_UpdateBonus (pstate->protectiontime, false);
+            return;
+        }
+        else if ((target->flags&FL_GODMODE) || (target->flags&FL_DOGMODE) || godmode)
+            return;
+        //damage=FixedMulShift((gamestate.difficulty+1),damage,2); // player object difficulty
+    }
+
+    else if (tcl == NMEsaucerobj)
+    {
+        target->momentumx = target->momentumy = 0;
+        NewState(target,&s_explosion1);
+        target->flags &= ~FL_SHOOTABLE;
+        return;
+    }
+    else if (tcl == b_darianobj)
+        MISCVARS->ESAU_SHOOTING = false;
+    else if ((tcl == strikeguardobj) || (tcl == b_heinrichobj))
+        target->target = shooter;
+
+    if ((  (!(target->flags & FL_SHOOTABLE)) ||
+            (tcl == roboguardobj) || (tcl == wallopobj) ||
+            (tcl == patrolgunobj) ) &&
+            (tcl!=playerobj)  )
+        SpawnMetalSparks(target,angle);
+
+    else if ((tcl < b_darianobj) || (tcl > b_darksnakeobj))
+    {
+
+        //target->flags &= ~FL_USE;
+
+        damage=FixedMulShift(511-accuracy,damage,9); // Min half damage
+        if (dist<64)
+        {
+            if (dist>2)
+                damage=FixedMulShift(63-dist,damage,6);
+            if (damage<1)
+                damage=1;
+        }
+        else
+            damage=1;
+
+        if (damage>MAXDAMAGE) damage=MAXDAMAGE; // absolutely clip it
+
+        DamageThing(target,damage);
+        if ((tcl == collectorobj) && gamestate.SpawnDeluder)
+        {
+            Collision(target,shooter,0,0);
+            if (target->hitpoints <= 0)
+                BATTLE_CheckGameStatus(battle_shot_deluder,shooter->dirchoosetime);
+        }
+
+        else
+        {   newmomx = FixedMul(damage<<7,costable[angle]);
+            newmomy = -FixedMul(damage<<7,sintable[angle]);
+            Collision(target,shooter,-(target->momentumx)+newmomx,-(target->momentumy)+newmomy);
+            if (tcl == playerobj)
+            {
+                playertype * pstate;
+
+                M_LINKSTATE(target,pstate);
+                if (pstate->health <= 0)
+                {
+
+                    if (shooter->obclass == playerobj) {
+                        if (!target->momentumz)
+                            BATTLE_PlayerKilledPlayer(battle_kill_with_bullet,shooter->dirchoosetime,target->dirchoosetime);
+                        else
+                            BATTLE_PlayerKilledPlayer(battle_kill_with_bullet_in_air,shooter->dirchoosetime,target->dirchoosetime);
+                    }
+                }
+            }
+//      SoftError("ShootActor: damage=%ld dist=%ld\n",damage,dist);
+
+            if ((GameRandomNumber("disembowel",0)<64) && (gamestate.violence == vl_excessive))
+            {
+                int temp;
+                temp=target->temp1;
+                target->temp1=angle;
+
+                SpawnParticles(target,DISEMBOWEL,damage>>3);
+                target->temp1=temp;
+            }
+            else if (gamestate.violence > 0)
+                SpawnBlood(target,angle);
+        }
+    }
+}
+
+
+/*
+=====================
+=
+= ShootSprite
+=
+= Shoot a sprite.
+=
+=====================
+*/
+void ShootSprite(objtype * shooter, statobj_t * target, int damage, int accuracy, int angle)
+{
+    int dx,dy,dist;
+
+
+    if (!(target->flags & FL_SHOOTABLE))
+// Watchout for sprite being passed in as actor WARNING
+        SpawnMetalSparks((objtype *)target,angle);
+
+    else
+    {
+        dx = abs(shooter->x - target->x);
+        dy = abs(shooter->y - target->y);
+        dist = FindDistance(dx,dy)>>16;
+
+        damage=FixedMulShift(511-accuracy,damage,9); // Min half damage
+        if (dist<64)
+        {
+            if (dist>2)
+                damage=FixedMulShift(63-dist,damage,6);
+            if (damage<1)
+                damage=1;
+        }
+        else
+            damage=1;
+
+        if (damage>MAXDAMAGE) damage=MAXDAMAGE; // absolutely clip it
+
+        //   SoftError("ShootSprite: damage=%ld dist=%ld\n",damage,dist);
+
+        DamageThing((objtype *)target,damage);
+        if (FirstExplosionState(new->state))
+            new->whatever = shooter;
+
+        SpawnStaticDamage(target, angle);
+    }
+}
+
+
+/*
+=====================
+=
+= RayShoot
+=
+= Cast a ray out at the shooter's angle and yzangle, return
+=
+=====================
+*/
+
+
+
+void RayShoot (objtype * shooter, int damage, int accuracy)
+{
+    objtype   *tempactor;
+    statobj_t *checksprite;
+    int snx,sny;
+    int incr[2];
+    int zincr[2];
+    int thedir[2];
+    int cnt;
+    int grid[2];
+    int index;
+    int vx,vy;
+    int angle;
+    int yzangle;
+    int value;
+    int offset;
+    int z;
+    int lastcnt;
+    int bullethole=0;
+    enum {gs_door, gs_wall, gs_floor, gs_ceiling, gs_pushwall};
+    int smokecondition=0;
+
+
+    if ((shooter->areanumber==player->areanumber) && (Near(shooter,player,3)))
+        SetIllumination(2);
+
+    offset = ((GameRandomNumber("RayShoot",0)-128)>>MAXSHOOTSHIFT);
+    offset = FixedMulShift(accuracy,offset,8);
+
+    if (offset>MAXSHOOTOFFSET)
+        offset=MAXSHOOTOFFSET;
+
+    else if (offset<-MAXSHOOTOFFSET)
+        offset=-MAXSHOOTOFFSET;
+
+    angle=(shooter->angle+offset)&(FINEANGLES-1);
+
+    offset = ((GameRandomNumber("RayShoot",1)-128)>>MAXSHOOTSHIFT);
+    offset = FixedMulShift(accuracy,offset,8);
+
+    if (offset>MAXSHOOTOFFSET)
+        offset=MAXSHOOTOFFSET;
+
+    else if (offset<-MAXSHOOTOFFSET)
+        offset=-MAXSHOOTOFFSET;
+
+    yzangle=(shooter->yzangle+offset)&(FINEANGLES-1);
+
+    vy = -sintable[angle];
+    vx = costable[angle];
+    snx=shooter->x&0xffff;
+    sny=shooter->y&0xffff;
+    grid[0]=shooter->tilex;
+    grid[1]=shooter->tiley;
+    if (shooter->obclass==playerobj)
+    {
+        playertype * pstate;
+
+        M_LINKSTATE(shooter,pstate);
+        z=shooter->z+pstate->playerheight-32;
+    }
+    else
+        z=shooter->z-7;
+    if (vx>0)
+    {
+        thedir[0]=1;
+        snx^=0xffff;
+        incr[1]=-vx;
+    }
+    else
+    {
+        thedir[0]=-1;
+        incr[1]=vx;
+    }
+    if (vy>0)
+    {
+        thedir[1]=1;
+        sny^=0xffff;
+        incr[0]=vy;
+    }
+    else
+    {
+        thedir[1]=-1;
+        incr[0]=-vy;
+    }
+    zincr[0]=-FixedMulShift(sintable[yzangle],abs(vx),26);
+    zincr[1]=-FixedMulShift(sintable[yzangle],abs(vy),26);
+
+    cnt=FixedMul(snx,incr[0])+FixedMul(sny,incr[1]);
+    index= (cnt >= 0);
+    do
+    {
+        tempactor = (objtype*)actorat[grid[0]][grid[1]];
+        value = tilemap[grid[0]][grid[1]];
+        checksprite = sprites[grid[0]][grid[1]];
+        if (value)
+        {
+            if (value&0x8000)
+            {
+                if (!(value&0x4000))
+                {
+                    if ((doorobjlist[value&0x3ff]->action==dr_closed) || (z<maxheight-64))
+                    {
+                        smokecondition=gs_door;
+                        break;
+                    }
+                    else if (doorobjlist[value&0x3ff]->position<=0x8000)
+                    {
+                        smokecondition=gs_door;
+                        break;
+                    }
+                }
+                else
+                {
+                    if ( maskobjlist[value&0x3ff]->flags & MW_SHOOTABLE )
+                    {
+                        if (z>maxheight-64) // Are we shooting above the glass
+                        {
+                            UpdateMaskedWall(value&0x3ff);
+                            return;
+                        }
+                    }
+                    else if ( maskobjlist[value&0x3ff]->flags & MW_WEAPONBLOCKING )
+                    {
+                        smokecondition=gs_door;
+                        break;
+                    }
+                }
+            }
+            else
+            {
+                smokecondition=gs_wall;
+                break;
+            }
+        }
+
+        if (checksprite &&
+                ((checksprite->flags & FL_BLOCK)||(checksprite->flags & FL_SHOOTABLE)) &&
+                (abs(checksprite->z-z)<32) &&
+                (InRange(shooter,(objtype *)checksprite,
+                         FindDistance(shooter->x-checksprite->x,shooter->y-checksprite->y) )
+                 ==true
+                )
+           )
+        {
+            ShootSprite(shooter, checksprite, damage, accuracy, angle);
+            return;
+        }
+
+
+        if (tempactor)
+        {   if (tempactor->which == ACTOR)
+            {   if ((abs(tempactor->z-z)<32 ) && (!(tempactor->flags & FL_DYING)) &&
+                        (tempactor->flags & FL_BLOCK) && (tempactor != shooter) &&
+                        (tempactor->obclass!=diskobj) &&
+                        (InRange(shooter,tempactor,
+                                 FindDistance(shooter->x-tempactor->x,shooter->y-tempactor->y) )
+                         ==true
+                        )
+                   )
+                {   ShootActor(shooter, tempactor, damage, accuracy, angle);
+                    return;
+                }
+            }
+            else if (tempactor->which == PWALL)
+                return;
+        }
+
+        if (z<-32)
+        {
+            smokecondition=gs_ceiling;
+            break;
+        }
+        else if (z>maxheight)
+        {
+            smokecondition=gs_floor;
+            break;
+        }
+        index= (cnt >= 0);
+        cnt+=incr[index];
+        z  +=zincr[index];
+        grid[index]+=thedir[index];
+    }
+    while (1);
+
+    if (IsWindow(grid[0],grid[1]))
+        return;
+
+    lastcnt=cnt-incr[index];
+
+    if (smokecondition==gs_floor)
+    {
+        int dist;
+        int tangentangle;
+
+        tangentangle=tantable[yzangle];
+        if (tangentangle!=0)
+        {
+            dist=FixedDiv2(((shooter->z-maxheight)<<10),(tangentangle<<1));
+            xintercept=shooter->x+FixedMul(dist,costable[angle]);
+            yintercept=shooter->y-FixedMul(dist,sintable[angle]);
+        }
+        z=maxheight;
+//      bullethole=5;
+    }
+    else if (smokecondition==gs_ceiling)
+    {
+        int dist;
+        int tangentangle;
+
+        if (sky!=0)
+            return;
+        tangentangle=tantable[yzangle];
+        if (tangentangle!=0)
+        {
+            dist=FixedDiv2(((shooter->z+32)<<10),(tangentangle<<1));
+            xintercept=shooter->x+FixedMul(dist,costable[angle]);
+            yintercept=shooter->y-FixedMul(dist,sintable[angle]);
+        }
+        z=-32;
+//      bullethole=5;
+    }
+    else
+    {
+        int dx,dy,xydist;
+
+
+#define CORNERVALUE  0x500
+
+
+        if (IsWindow(grid[0],grid[1]))
+            return;
+        if (lastcnt<0)
+        {
+            xintercept=grid[0]<<16;
+            if (smokecondition==gs_door)
+            {
+                if (thedir[0]<0)
+                    xintercept+=0x9fff;
+                else
+                    xintercept+=0x5fff;
+                yintercept=FixedScale(xintercept-shooter->x,vy,vx)+shooter->y;
+                if ((yintercept>>16)!=grid[1])
+                {
+                    if ((yintercept>>16)>grid[1])
+                        yintercept=(grid[1]<<16)+0xffff;
+                    else
+                        yintercept=(grid[1]<<16);
+                }
+            }
+            else if (smokecondition==gs_wall)
+            {
+                if (thedir[0]<0)
+                {
+                    objtype * ta;
+
+                    xintercept += 0x10000;
+                    yintercept=FixedScale(xintercept-shooter->x,vy,vx)+shooter->y;
+
+                    xintercept += SMOKEWALLOFFSET;
+                    bullethole=1;
+                    if (yintercept < ((grid[1] << 16) + CORNERVALUE))
+                        bullethole = 0;
+                    else if (yintercept > ((grid[1] << 16) + 0x10000 - CORNERVALUE))
+                        bullethole = 0;
+
+                    ta = (objtype*)actorat[grid[0]][grid[1]];
+                    if ((ta) && (ta->which==PWALL))
+                        bullethole=0;
+                }
+                else
+                {
+                    objtype * ta;
+
+                    yintercept=FixedScale(xintercept-shooter->x,vy,vx)+shooter->y;
+                    xintercept-=SMOKEWALLOFFSET;
+                    bullethole=2;
+                    if (yintercept < ((grid[1] << 16) + CORNERVALUE))
+                        bullethole = 0;
+                    else if (yintercept > ((grid[1] << 16) + 0x10000 - CORNERVALUE))
+                        bullethole = 0;
+
+                    ta = (objtype*)actorat[grid[0]][grid[1]];
+                    if ((ta) && (ta->which==PWALL))
+                        bullethole=0;
+                }
+            }
+        }
+        else
+        {
+            yintercept=grid[1]<<16;
+            if (smokecondition==gs_door)
+            {
+                if (thedir[1]<0)
+                    yintercept+=0x9fff;
+                else
+                    yintercept+=0x5fff;
+                xintercept=FixedScale(yintercept-shooter->y,vx,vy)+shooter->x;
+                if ((xintercept>>16)!=grid[0])
+                {
+                    if ((xintercept>>16)>grid[0])
+                        xintercept=(grid[0]<<16)+0xffff;
+                    else
+                        xintercept=(grid[0]<<16);
+                }
+            }
+            else if (smokecondition==gs_wall)
+            {
+                if (thedir[1]<0)
+                {
+                    objtype * ta;
+
+
+                    yintercept += 0x10000;
+                    xintercept=FixedScale(yintercept-shooter->y,vx,vy)+shooter->x;
+
+                    yintercept += SMOKEWALLOFFSET;
+                    bullethole=3;
+                    if (xintercept < ((grid[0] << 16) + CORNERVALUE))
+                        bullethole = 0;
+                    else if (xintercept > ((grid[0] << 16) + 0x10000 - CORNERVALUE))
+                        bullethole = 0;
+
+                    ta = (objtype*)actorat[grid[0]][grid[1]];
+                    if ((ta) && (ta->which==PWALL))
+                        bullethole=0;
+                }
+                else
+                {
+                    objtype * ta;
+
+                    xintercept=FixedScale(yintercept-shooter->y,vx,vy)+shooter->x;
+                    yintercept-=SMOKEWALLOFFSET;
+                    bullethole=4;
+                    if (xintercept < ((grid[0] << 16) + CORNERVALUE))
+                        bullethole = 0;
+                    else if (xintercept > ((grid[0] << 16) + 0x10000 - CORNERVALUE))
+                        bullethole = 0;
+
+                    ta = (objtype*)actorat[grid[0]][grid[1]];
+                    if ((ta) && (ta->which==PWALL))
+                        bullethole=0;
+                }
+            }
+        }
+        dx = xintercept - shooter->x;
+        dy = shooter->y - yintercept;
+        xydist = FindDistance(dx,dy);
+        if (shooter->obclass==playerobj)
+        {
+            playertype * pstate;
+
+            M_LINKSTATE(shooter,pstate);
+            z=shooter->z-FixedMulShift(xydist,tantable[yzangle],25)+pstate->playerheight-32;
+        }
+        else
+            z=shooter->z-FixedMulShift(xydist,tantable[yzangle],25);
+        if (smokecondition==gs_wall)
+        {
+            if (z<-32)
+                z=-32;
+        }
+    }
+    SpawnGunSmoke(xintercept,yintercept,z,angle,bullethole);
+}
+
+
+/*
+=====================
+=
+= T_BossDied ()
+=
+=====================
+*/
+
+void T_BossDied (objtype *ob)
+{
+
+    if (ob->ticcount)
+        return;
+
+    switch (ob->obclass)
+    {
+    case b_darianobj:
+    case b_heinrichobj:
+    case b_darkmonkobj:
+    case b_robobossobj:
+    case b_darksnakeobj:
+        playstate = ex_bossdied;
+        break;
+    default:
+        ;
+    }
+}
+
+
+/*
+=====================
+=
+= T_Wind ()
+=
+=====================
+*/
+
+static int WindDistance = 1000;
+static int WindCurrentDistance = 1000;
+static int WindHandle = -1;
+static int WindLastTic = -1;
+static int WindPlaying = false;
+static int WindPitch = 0;
+static int WindDestPitch = 0;
+static int WindPitchRate = 0;
+
+void T_Wind
+(
+    objtype *ob
+)
+
+{
+    int distance;
+    int dx;
+    int dy;
+
+    if ( ( GetTicCount() - WindLastTic ) > 0 )
+    {
+        WindDistance = 1000;
+
+        WindPitch += WindPitchRate;
+        if ( WindPitch == WindDestPitch )
+        {
+            WindDestPitch = ( RandomNumber( "Wind Pitch", 0 ) - 128 ) << 3;
+            WindPitchRate = 1;
+            if ( WindDestPitch < WindPitch )
+            {
+                WindPitchRate = -WindPitchRate;
+            }
+        }
+    }
+    WindLastTic = GetTicCount();
+
+    dx = ( ob->x - PLAYER[0]->x );
+    dy = ( PLAYER[0]->y - ob->y );
+
+    distance = 1000;
+    if ( areabyplayer[ ob->areanumber ] )
+    {
+        distance = ( FindDistance( dx, dy ) ) >> 13;
+    }
+
+    if ( distance < WindDistance )
+    {
+        WindDistance = distance;
+    }
+
+    if ( WindDistance < 255 )
+    {
+        WindPlaying = true;
+        WindCurrentDistance = WindDistance;
+    }
+    else
+    {
+        if ( WindPlaying )
+        {
+            WindCurrentDistance += 3;
+        }
+    }
+
+    if ( WindPlaying )
+    {
+        if ( WindCurrentDistance < 255 )
+        {
+            if ( !SD_SoundActive( WindHandle ) )
+            {
+                WindHandle = SD_PlayPitchedSound( SD_WINDSND,
+                                                  255 - WindCurrentDistance, WindPitch );
+            }
+            else
+            {
+                SD_SetSoundPitch( WindHandle, WindPitch );
+                SD_SetPan( WindHandle, 255 - WindCurrentDistance, 255 - WindCurrentDistance,
+                           255 - WindCurrentDistance );
+            }
+        }
+        else
+        {
+            SD_StopSound( WindHandle );
+            WindPlaying = false;
+        }
+    }
+}
+
+/*
+=====================
+=
+= StopWind ()
+=
+=====================
+*/
+
+void StopWind
+(
+    void
+)
+
+{
+    objtype *temp;
+
+    FX_SetReverb( 0 );
+
+    SD_StopSound( WindHandle );
+    WindDistance        = 1000;
+    WindCurrentDistance = 1000;
+    WindHandle          = -1;
+    WindLastTic         = -1;
+    WindPlaying         = false;
+    WindPitch           = 0;
+    WindDestPitch       = 0;
+    WindPitchRate       = 0;
+
+
+    for(temp=FIRSTACTOR; temp; temp=temp->next)
+    {
+        if (temp->soundhandle != -1)
+            SD_StopSound(temp->soundhandle);
+    }
+}
+
--- /dev/null
+++ b/rott/rt_actor.h
@@ -1,0 +1,438 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+#ifndef _rt_actor_public
+#define _rt_actor_public
+
+//***************************************************************************
+//
+//                            RT_ACTOR.C (actor functions)
+//
+//***************************************************************************
+
+#include "states.h"
+
+
+#define FL_SYNCED          0x400
+#define FL_MASTER          0x800
+#define FL_SKELETON        0x02
+#define GASTICS            1050
+
+
+#define M_ISACTOR(x)     ((x!=NULL) && (x->which == ACTOR))
+
+#define SF_GUTS          0x20
+
+#define NUMENEMIES       16
+#define NUMCLASSES       51
+#define MAXTOUCH         10
+#define MAXPOP           32
+#define MAXDELETE        512
+
+#define InMapBounds(x,y) (((x) >= 0) && ((x) < MAPSIZE) && ((y) >= 0) && ((y) < MAPSIZE))
+
+
+#define ACTIVE(ob)       ((ob == firstactive) || (ob->prevactive) || (ob->nextactive))
+
+enum {SHOOT,SIGHT,DIRCHECK,EXPLOSION,MISSILE};
+
+
+typedef enum
+{
+    gt_sparks,
+    gt_organ,
+    gt_rib,
+    gt_pinkorgan,
+    gt_head,
+    gt_arm,
+    gt_leg,
+    gt_humerus,
+    gt_pelvis,
+    gt_limb,
+    gt_bsoul,
+    gt_lsoul,
+    gt_spit,
+    NumGibTypes
+} gib_t;
+
+#define GUTS         (NumGibTypes)
+#define RANDOM       (NumGibTypes + 1)
+#define DISEMBOWEL   (NumGibTypes + 2)
+
+
+#define GASVALUE               192
+
+#define PAINOFFSET             2
+#define PMFOFFSET              50
+#define REMOTEOFFSET           86
+
+#define ACTORSIZE              0x5800
+#define PWALLRAD               0xa000
+
+#ifdef __WATCOMC__
+int M_ABS(int value);
+#pragma aux M_ABS =  \
+		  "test eax,eax",                     \
+		  "jge done", \
+		  "neg eax",\
+		  "done: "         \
+		  parm    [eax] \
+		  value   [eax]           \
+		  modify exact [eax]
+#else
+#define M_ABS abs
+#endif
+
+#define M_CheckPlayerKilled(ob) \
+{ if ((ob->obclass == playerobj) && (ob->flags & FL_DYING)) \
+	 BATTLE_CheckGameStatus(battle_player_killed,ob->dirchoosetime);\
+}
+
+
+
+#define SetTilePosition(ob, newtilex, newtiley)    \
+  {                                                \
+  ob->tilex = newtilex;                            \
+  ob->tiley = newtiley;                            \
+  ob->x = (ob->tilex << TILESHIFT) + TILEGLOBAL/2; \
+  ob->y = (ob->tiley << TILESHIFT) + TILEGLOBAL/2; \
+  }
+
+
+#define SetFinePosition(ob, newx, newy)            \
+  {                                                \
+  ob->x = newx;                                    \
+  ob->y = newy;                                    \
+  ob->tilex = (ob->x >> TILESHIFT);                \
+  ob->tiley = (ob->y >> TILESHIFT);                \
+  }
+
+#define SetVisiblePosition(ob, x, y)               \
+  {                                                \
+  ob->drawx = x;                                   \
+  ob->drawy = y;                                   \
+  }
+
+
+//***************************************************************************
+//
+//    WeaponDamages
+//
+//***************************************************************************
+#define DMG_PISTOL    13
+#define DMG_MP40      10
+#define DMG_AHGUN     10
+#define DMG_ENEMYBULLETWEAPON     10
+
+
+
+
+typedef struct bas
+{
+    short operate,
+          see,
+          fire,
+          hit,
+          die;
+} basic_actor_sounds;
+
+extern basic_actor_sounds  BAS[NUMCLASSES+3];
+
+
+typedef struct
+{   int x,y;
+} _2Dpoint;
+
+typedef enum {
+    inertobj,
+    playerobj,
+    lowguardobj,
+    highguardobj,
+    overpatrolobj,
+    strikeguardobj,
+    blitzguardobj,
+    triadenforcerobj,
+    deathmonkobj,
+    dfiremonkobj,
+    roboguardobj,
+
+    b_darianobj,
+    b_heinrichobj,
+    b_robobossobj,
+    b_darkmonkobj,
+    b_darksnakeobj,
+    patrolgunobj,
+    wallopobj,
+
+
+    //specials
+
+    pillarobj,
+    firejetobj,
+    bladeobj,
+    crushcolobj,
+    boulderobj,
+    spearobj,
+    gasgrateobj,
+    springobj,
+
+    // Missile weapon types
+
+    shurikenobj,
+    wallfireobj,
+    netobj,
+    h_mineobj,
+    grenadeobj,
+    fireballobj,
+    dmfballobj,
+    bigshurikenobj,
+    missileobj,
+    NMEsaucerobj,
+    dm_weaponobj,
+    dm_heatseekobj,
+    dm_spitobj,
+    p_bazookaobj,
+    p_firebombobj,
+    p_heatseekobj,
+    p_drunkmissileobj,
+    p_firewallobj,
+    p_splitmissileobj,
+    p_kesobj,
+    p_godballobj,
+    collectorobj,
+    diskobj,
+    rainobj
+
+
+} classtype;
+
+
+typedef struct objstruct
+{
+    thingtype                     which;
+    byte                     tilex,tiley;
+    fixed                    x,y,z;
+    int                      shapenum;
+    unsigned                 flags;
+    short                    ticcount;
+    signed short             hitpoints;
+    word                     whichactor;
+
+    signed short             dirchoosetime;
+    fixed                    drawx,drawy;
+    classtype                obclass;
+    statetype *              state;
+    signed char              door_to_open;
+    byte                     areanumber;
+    signed short             shapeoffset;
+    int                      targettilex,targettiley;
+
+
+    dirtype                  dir;
+    short int                angle;
+    short int                yzangle;
+
+    int                      soundhandle;
+    int                      speed;
+    int                      momentumx, momentumy, momentumz;
+    int                      temp1,temp2,temp3;
+    void                     *whatever,*target;
+    struct objstruct         *next, *prev;
+    struct objstruct         *nextactive, *prevactive;
+    struct objstruct         *nextinarea, *previnarea;
+
+} objtype;
+
+
+
+
+typedef struct b_struct
+{   int   NMErotate;
+    int   NMEdirstried;
+    int   NMEqueuesize;
+    int   ESAU_HIDING,ESAU_SHOOTING;
+    int   HRAMMING, HMINING;
+    int   SOUNDTIME;
+    int   redindex,REDTIME;
+    int   monkz;
+    int   monkup;
+    int   firespawned;
+    int   notouch,noholes;
+    int   nexttouch,nextpop;
+    int   popsleft;
+    int   DSTATE;
+    int   doorcount;
+    int   KEYACTORSLEFT;
+    int      GASON;
+    int      gasindex;
+    boolean  NET_IN_FLIGHT;
+    boolean  madenoise;
+    _2Dpoint ETOUCH[MAXTOUCH],EPOP[MAXPOP],TOMLOC;
+    int   NUMWEAPONS;
+    int   BulletHoleNum;
+    int   NUMBEGGINGKEVINS;
+    boolean fulllightgibs;
+    boolean directgibs;
+    int     gibgravity;
+    int     gibspeed;
+    boolean supergibflag;
+    boolean randgibspeed;
+    int     numgibs;
+    boolean elevatormusicon;
+} misc_stuff;
+
+
+extern  boolean          ludicrousgibs;
+extern  objtype*         PLAYER0MISSILE;
+extern  byte             deathshapeoffset[8];
+extern  byte             RANDOMACTORTYPE[10];
+extern  objtype*         FIRSTACTOR,*LASTACTOR;
+extern  objtype          *FIRSTRAIN,*LASTRAIN;
+extern  objtype*         SCREENEYE;
+extern  objtype          *firstareaactor[NUMAREAS+1],*lastareaactor[NUMAREAS+1];
+extern  misc_stuff       mstruct,*MISCVARS;
+extern  int              actorstart,actorstop;
+extern  exit_t           playstate;
+extern  objtype          *lastactive,*firstactive;
+extern  objtype          *new,**objlist,
+        *killerobj;
+extern  void             *actorat[MAPSIZE][MAPSIZE];
+extern  int              angletodir[ANGLES];
+extern _2Dpoint          SNAKEPATH[512];
+/* extern  int              STOPSPEED; */
+extern  int              FRICTION;
+
+extern  int              objcount;
+
+void     SpawnInertActor(int,int,int);
+objtype* DiskAt(int tilex,int tiley);
+void     GetRainActors(void);
+void     DoRain(void);
+void     SpawnDisk(int,int,int,boolean);
+void     T_ElevDisk(objtype*);
+void     Add_To_Delete_Array(void*);
+void     Remove_Delete_Array_Entries(void);
+void     MakeInactive(objtype*ob);
+void     RespawnEluder(void);
+void     SpawnCollector(int,int);
+void     MakeLastInArea(objtype*);
+void     RemoveFromArea(objtype*);
+void     GetMomenta(objtype*,objtype*,int*,int*,int*,int);
+int      AngleBetween(objtype*,objtype*);
+void     TurnActorIntoSprite(objtype*);
+void     ResolveDoorSpace(int,int);
+void     RemoveObj(objtype*);
+void     SpawnParticles(objtype*,int,int);
+void     MakeActive(objtype*);
+void     SpawnSpear(int,int,int);
+void     SpawnBoulder(int,int,int);
+void     SpawnCrushingColumn(int,int,int);
+void     SpawnFirejet(int,int,int,int);
+void     T_Firethink(objtype*);
+void     SpawnBlade(int,int,int,int,int);
+void     T_OrobotChase(objtype*);
+void     SpawnMultiSpriteActor(classtype,int,int,int);
+boolean  ActorTryMove(objtype*,int,int,int);
+void     A_Repeat(objtype*);
+void     T_Heinrich_Defend(objtype*);
+void     T_Heinrich_Out_of_Control(objtype*);
+void     A_HeinrichShoot(objtype*);
+void     T_EsauWait(objtype*);
+void     T_EsauRise(objtype*);
+void     A_Drain(objtype*ob);
+void     T_Explosion(objtype*ob);
+void     T_MoveColumn(objtype*);
+void     EnableObject(long object);
+void     DisableObject(long object);
+
+void     T_Collide(objtype*);
+void  Collision(objtype*ob,objtype *attacker,int hitmomentumx,int hitmomentumy);
+void     ActorMovement (objtype *);
+void     MoveActor(objtype*);
+
+void     InitActorList(void);
+void     NewState(objtype*,statetype*);
+void     DoActor(objtype*);
+
+void     SpawnPushColumn(int tilex,int tiley,int which,int dir, int linked);
+void     SpawnGunThingy(classtype which, int tilex, int tiley, int dir);
+void     SpawnStand (classtype which, int tilex, int tiley, int dir, int ambush);
+void     SpawnPatrol (classtype which, int tilex, int tiley, int dir);
+void     SpawnDeadGuard (int tilex, int tiley);
+void     SpawnWallfire(int tilex, int tiley, int dir);
+void     SpawnMissile(objtype*,classtype,int,int,statetype*,int);
+
+void     InitHitRect (objtype *ob, unsigned radius);
+void     NewState (objtype *ob, statetype *state);
+void     SelectPathDir(objtype*);
+void     SelectChaseDir (objtype *ob);
+boolean  SightPlayer (objtype *ob);
+boolean  CheckLine (void*,void *,int);
+boolean  CheckSight (objtype *ob,void*);
+void     KillActor (objtype *ob);
+void     DamageThing (void *, int);
+void     MissileHit (objtype *,void*);
+void     GetNewActor(void);
+
+void     T_WallPath(objtype*);
+void     T_Path (objtype *ob);   //done
+void     T_RoboChase(objtype*ob);
+void     T_RoboPath(objtype*ob);
+void     T_Chase (objtype *ob);      //done
+void     T_EsauChase(objtype*ob); //done
+void     T_Spears(objtype*);
+void     T_Projectile (objtype *ob); //done
+void     T_Stand (objtype *ob);      //done
+void     T_GunStand(objtype *ob); //done
+void     T_Use(objtype *ob);         // done
+void     A_Shoot (objtype *ob);        // done
+void     A_MissileWeapon(objtype*);    // done
+void     A_Wallfire(objtype*);
+
+void     A_Steal(objtype*);
+
+void     T_Roll(objtype*);
+void     T_BossDied (objtype *ob);
+boolean  QuickSpaceCheck(objtype*,int,int);
+void     PushWallMove(int num);
+void     SpawnNewObj(unsigned,unsigned,statetype*,classtype);
+void     SpawnSpring(int,int);
+void     SpawnFourWayGun(int,int);
+void     SpawnSnake(int tilex,int tiley);
+void     SpawnSneaky(int,int);
+boolean  MissileTryMove(objtype*ob,int,int,int);
+
+void     SaveActors(byte ** buf, int * size);
+void     LoadActors(byte * buf, int size);
+
+boolean  TurnOffLight0 (int tilex, int tiley);
+boolean  TurnOffLight1 (int tilex, int tiley, int i, int j);
+boolean  TurnOffLight2 (int tilex, int tiley, int j);
+boolean  TurnOffLight3 (int tilex, int tiley, int i);
+
+void     ParseMomentum(objtype *ob,int angle);
+void     SpawnGroundExplosion(int x, int y, int z);
+void     RayShoot (objtype * shooter, int damage, int accuracy);
+void FindEmptyTile(int *stilex, int *stiley);
+void T_Wind( objtype *ob );
+void StopWind( void );
+
+void ResurrectEnemies();
+
+#endif
--- /dev/null
+++ b/rott/rt_battl.c
@@ -1,0 +1,1129 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+/**********************************************************************
+   module: RT_BATTL.C
+
+   author: James R. Dose
+   phone:  (214)-271-1365 Ext #221
+   date:   September 8, 1994
+
+   Battle mode support routines for Rise of the Triad.
+
+   (c) Copyright 1994 Apogee Software.  All Rights Reserved.
+**********************************************************************/
+
+#include <string.h>
+#include "rt_def.h"
+#include "rottnet.h"
+#include "isr.h"
+#include "rt_battl.h"
+#include "rt_actor.h"
+#include "rt_rand.h"
+#include "rt_playr.h"
+#include "rt_game.h"
+#include "rt_sound.h"
+#include "rt_com.h"
+#include "rt_msg.h"
+#include "rt_view.h"
+
+#include "rt_util.h"
+#include "rt_main.h"
+//MED
+#include "memcheck.h"
+
+#define INFINITE -1
+
+static battle_status BATTLE_StartRound( void );
+
+static int Timer;
+static int TimeLimit;
+static int NumberOfPlayers;
+static int BattleRound;
+static int BattleMode;
+
+static boolean RoundOver;
+static boolean KillsEndGame;
+static boolean KeepTrackOfKills;
+boolean UpdateKills;
+
+static boolean SwapFlag;
+
+static battle_type BattleOptions;
+
+specials BattleSpecialsTimes =
+{
+    60, // god
+    60, // dog
+    20, // shrooms
+    20, // elasto
+    60, // asbestos vest
+    60, // bullet proof vest
+    GASTICS / VBLCOUNTER, // gas mask
+    60, // mercury mode
+
+    300, // god respawn
+    60, // dog respawn
+    60, // shrooms respawn
+    60, // elasto respawn
+    60, // asbestos vest respawn
+    60, // bullet proof vest respawn
+    60, // gas mask respawn
+    60  // mercury mode respawn
+};
+
+short WhoKilledWho[ MAXPLAYERS ][ MAXPLAYERS ];
+short BATTLE_Points[ MAXPLAYERS ];
+short BATTLE_PlayerOrder[ MAXPLAYERS ];
+short BATTLE_Team[ MAXPLAYERS ];
+short BATTLE_TeamLeader[ MAXPLAYERS ];
+int   BATTLE_NumberOfTeams;
+int   BATTLE_NumCollectorItems;
+int   PointGoal;
+int   DisplayPoints;
+int   BATTLE_It;
+
+boolean BATTLE_ShowKillCount;
+
+boolean BATTLEMODE = false;
+
+/*---------------------------------------------------------------------
+	Function Prototypes:
+---------------------------------------------------------------------*/
+
+static int BATTLE_CheckKills
+(
+    battle_event reason,
+    int player
+);
+
+/*---------------------------------------------------------------------
+	Function: BATTLE_Init
+
+	Initializes the battle information.
+---------------------------------------------------------------------*/
+
+void BATTLE_Init
+(
+    int battlemode,
+    int numplayers
+)
+
+{
+    int index;
+    int index2;
+    int team;
+    int TeamNumber[ MAXPLAYERCOLORS ];
+
+#if (BATTLECHECK == 1)
+    if ( ( gamestate.teamplay ) && ( BattleMode == battle_Tag ) )
+    {
+        Error( "BATTLE_Init : Cannot play Tag in team mode.\n" );
+    }
+
+    if ( ( gamestate.teamplay ) && ( BattleMode == battle_CaptureTheTriad ) )
+    {
+        Error( "BATTLE_Init : Can only play Capture the Triad in team mode.\n" );
+    }
+#endif
+
+    Timer   = 0;
+    RoundOver = false;
+
+    BattleRound = -1;
+    BATTLE_It = 0;
+
+    BattleMode = battlemode;
+
+    BATTLEMODE = false;
+
+    UpdateKills = true;
+
+    gamestate.BattleOptions.Gravity       = NORMAL_GRAVITY;
+    gamestate.BattleOptions.Speed         = bo_normal_speed;
+    gamestate.BattleOptions.Ammo          = bo_normal_shots;
+    gamestate.BattleOptions.HitPoints     = bo_character_hitpoints;
+    gamestate.BattleOptions.LightLevel    = bo_light_normal;
+    gamestate.BattleOptions.Kills         = bo_kills_default;
+    gamestate.BattleOptions.DangerDamage  = bo_danger_normal;
+    gamestate.BattleOptions.TimeLimit     = bo_time_infinite;
+    gamestate.BattleOptions.RespawnTime   = bo_normal_respawn_time;
+    gamestate.BattleOptions.RandomWeapons = false;
+    gamestate.BattleOptions.FriendlyFire  = true;
+    gamestate.BattleOptions.WeaponPersistence = false;
+    gamestate.BattleOptions.SpawnMines    = false;
+
+    if ( BattleMode != battle_StandAloneGame )
+    {
+        BATTLEMODE = true;
+
+        if ( gamestate.Product == ROTT_SHAREWARE )
+        {
+            switch( battlemode )
+            {
+            case battle_Normal :
+            case battle_Collector :
+            case battle_Hunter :
+                break;
+
+            default :
+                Error( "Shareware version can only play Normal, Collector, "
+                       "or Hunter in Comm-bat game." );
+            }
+        }
+
+        gamestate.BattleOptions.Gravity       = BattleOptions.Gravity;
+        gamestate.BattleOptions.Speed         = BattleOptions.Speed;
+        gamestate.BattleOptions.Ammo          = BattleOptions.Ammo;
+        gamestate.BattleOptions.HitPoints     = BattleOptions.HitPoints;
+        gamestate.BattleOptions.LightLevel    = BattleOptions.LightLevel;
+        gamestate.BattleOptions.Kills         = BattleOptions.Kills;
+        gamestate.BattleOptions.DangerDamage  = BattleOptions.DangerDamage;
+        gamestate.BattleOptions.TimeLimit     = BattleOptions.TimeLimit;
+        gamestate.BattleOptions.RespawnTime   = BattleOptions.RespawnTime;
+        gamestate.BattleOptions.RandomWeapons = BattleOptions.RandomWeapons;
+        gamestate.BattleOptions.FriendlyFire  = BattleOptions.FriendlyFire;
+        gamestate.BattleOptions.SpawnMines    = BattleOptions.SpawnMines;
+        gamestate.BattleOptions.WeaponPersistence = BattleOptions.WeaponPersistence;
+    }
+
+    gamestate.ShowScores                 = true;
+    gamestate.BattleOptions.SpawnHealth  = true;
+    gamestate.BattleOptions.SpawnWeapons = true;
+    gamestate.BattleOptions.SpawnDangers = true;
+    gamestate.SpawnCollectItems          = false;
+    gamestate.SpawnEluder                = false;
+    gamestate.SpawnDeluder               = false;
+    gamestate.BattleOptions.RespawnItems = false;
+
+    NumberOfPlayers = numplayers;
+
+
+    BATTLE_NumberOfTeams = numplayers;
+    for( index = 0; index < MAXPLAYERS; index++ )
+    {
+        BATTLE_PlayerOrder[ index ] = index;
+        BATTLE_Points[ index ] = 0;
+        for( index2 = 0; index2 < MAXPLAYERS; index2++ )
+        {
+            WhoKilledWho[ index ][ index2 ] = 0;
+        }
+
+        BATTLE_Team[ index ] = index;
+        BATTLE_TeamLeader[ index ] = index;
+    }
+
+
+    if ( gamestate.teamplay )
+    {
+        for( index = 0; index < MAXPLAYERCOLORS; index++ )
+        {
+            TeamNumber[ index ] = -1;
+        }
+
+        BATTLE_NumberOfTeams = 0;
+
+        for( index = 0; index < numplayers; index++ )
+        {
+            team = PLAYERSTATE[ index ].uniformcolor;
+            if ( TeamNumber[ team ] == -1 )
+            {
+                TeamNumber[ team ] = BATTLE_NumberOfTeams;
+                BATTLE_TeamLeader[ BATTLE_NumberOfTeams ] = index;
+                BATTLE_NumberOfTeams++;
+            }
+            BATTLE_Team[ index ] = TeamNumber[ team ];
+        }
+    }
+
+    PointGoal = gamestate.BattleOptions.Kills;
+    if ( ( gamestate.BattleOptions.Kills == bo_kills_random ) ||
+            ( gamestate.BattleOptions.Kills == bo_kills_blind ) )
+    {
+        // Possibility of playing from 5 to 50 kills
+        PointGoal = ( GameRandomNumber( "BATTLE_Init", 0 ) % 46 ) + 5;
+    }
+
+    DisplayPoints = PointGoal;
+
+    for( index = 0; index < MAXPLAYERS; index++ )
+    {
+        gamestate.PlayerHasGun[ index ] = true;
+    }
+
+    KillsEndGame = true;
+    KeepTrackOfKills = true;
+
+    switch( BattleMode )
+    {
+    case battle_StandAloneGame :
+        KillsEndGame      = false;
+        KeepTrackOfKills  = false;
+        break;
+
+    case battle_Normal :
+        break;
+
+    case battle_ScoreMore :
+        break;
+
+    case battle_Collector :
+        for( index = 0; index < MAXPLAYERS; index++ )
+        {
+            gamestate.PlayerHasGun[ index ] = false;
+        }
+        KillsEndGame     = false;
+        KeepTrackOfKills = false;
+        gamestate.BattleOptions.SpawnHealth  = false;
+        gamestate.BattleOptions.SpawnWeapons = false;
+        gamestate.SpawnCollectItems          = true;
+        break;
+
+    case battle_Scavenger :
+        KillsEndGame     = false;
+        KeepTrackOfKills = false;
+        gamestate.BattleOptions.SpawnWeapons = true;
+        gamestate.BattleOptions.SpawnHealth  = true;
+        gamestate.SpawnCollectItems          = true;
+        break;
+
+    case battle_Hunter :
+        PointGoal *= BATTLE_NumberOfTeams;
+        KillsEndGame      = false;
+        KeepTrackOfKills  = true;
+        BATTLE_It = 0;
+        for( index = 0; index < NumberOfPlayers; index++ )
+        {
+            if ( BATTLE_Team[ index ] == 0 )
+            {
+                gamestate.PlayerHasGun[ index ] = false;
+            }
+        }
+        break;
+
+    case battle_Tag :
+        for( index = 0; index < MAXPLAYERS; index++ )
+        {
+            gamestate.PlayerHasGun[ index ] = false;
+        }
+
+        gamestate.BattleOptions.SpawnHealth  = false;
+        gamestate.BattleOptions.SpawnWeapons = false;
+        gamestate.BattleOptions.SpawnDangers = true;
+        KeepTrackOfKills = true;
+        KillsEndGame     = true;
+        break;
+
+    case battle_Eluder :
+        KeepTrackOfKills   = false;
+        KillsEndGame       = false;
+
+        for( index = 0; index < MAXPLAYERS; index++ )
+        {
+            gamestate.PlayerHasGun[ index ] = false;
+        }
+
+        gamestate.BattleOptions.SpawnWeapons = false;
+        gamestate.SpawnEluder                = true;
+        break;
+
+    case battle_Deluder :
+        KeepTrackOfKills    = false;
+        KillsEndGame        = false;
+        gamestate.SpawnDeluder = true;
+        break;
+
+    case battle_CaptureTheTriad :
+        KillsEndGame     = false;
+        KeepTrackOfKills = false;
+        break;
+    }
+
+    if ( BattleMode != battle_StandAloneGame )
+    {
+        if ( BattleOptions.RespawnItems )
+        {
+            gamestate.BattleOptions.RespawnItems = true;
+        }
+
+        if ( !BattleOptions.SpawnDangers )
+        {
+            gamestate.BattleOptions.SpawnDangers = false;
+        }
+
+        if ( !BattleOptions.SpawnHealth )
+        {
+            gamestate.BattleOptions.SpawnHealth = false;
+        }
+
+        if ( !BattleOptions.SpawnWeapons )
+        {
+            gamestate.BattleOptions.SpawnWeapons = false;
+        }
+
+        if ( gamestate.BattleOptions.Kills == bo_kills_blind )
+        {
+            gamestate.ShowScores = false;
+        }
+
+        GRAVITY = gamestate.BattleOptions.Gravity;
+
+        if ( gamestate.BattleOptions.Kills == bo_kills_infinite )
+        {
+            KillsEndGame = false;
+        }
+    }
+
+    BATTLE_StartRound();
+
+#if (BATTLEINFO == 1)
+    SoftError( "GRAVITY      = %d\n", GRAVITY );
+    SoftError( "BO_Gravity   = %d\n", BattleOptions.Gravity );
+    SoftError( "BO_Speed     = %d\n", BattleOptions.Speed );
+    SoftError( "BO_Ammo      = %d\n", BattleOptions.Ammo );
+    SoftError( "BO_HitPoints = %d\n", BattleOptions.HitPoints );
+    SoftError( "BO_Dangers   = %d\n", BattleOptions.SpawnDangers );
+    SoftError( "BO_Health    = %d\n", BattleOptions.SpawnHealth );
+    SoftError( "BO_Weapons   = %d\n", BattleOptions.SpawnWeapons );
+    SoftError( "BO_Respawn   = %d\n", BattleOptions.RespawnItems );
+    SoftError( "BO_Light     = %d\n", BattleOptions.LightLevel );
+    SoftError( "BO_Kills     = %d\n", BattleOptions.Kills );
+    SoftError( "BO_DangerDam = %d\n", BattleOptions.DangerDamage );
+    SoftError( "BO_TimeLimit = %d\n", BattleOptions.TimeLimit );
+#endif
+}
+
+
+/*---------------------------------------------------------------------
+   Function: BATTLE_GetSpecials
+
+   Set the battle special times.
+---------------------------------------------------------------------*/
+
+void BATTLE_GetSpecials
+(
+    void
+)
+
+{
+    int *src;
+    int *dest;
+
+    src  = ( int * )&BattleSpecialsTimes;
+    dest = ( int * )&gamestate.SpecialsTimes;
+
+    while( src < ( int * )( &BattleSpecialsTimes + 1 ) )
+    {
+        *dest = *src * VBLCOUNTER;
+        dest++;
+        src++;
+    }
+}
+
+
+/*---------------------------------------------------------------------
+	Function: BATTLE_SetOptions
+
+	Set the battle options.
+---------------------------------------------------------------------*/
+
+void BATTLE_SetOptions
+(
+    battle_type *options
+)
+
+{
+    memcpy( &BattleOptions, options, sizeof( battle_type ) );
+}
+
+
+/*---------------------------------------------------------------------
+   Function: BATTLE_GetOptions
+
+   Returns the battle options.
+---------------------------------------------------------------------*/
+
+void BATTLE_GetOptions
+(
+    battle_type *options
+)
+
+{
+    memcpy( options, &BattleOptions, sizeof( battle_type ) );
+}
+
+
+/*---------------------------------------------------------------------
+   Function: BATTLE_Shutdown
+
+   Shutsdown the battle information.
+---------------------------------------------------------------------*/
+
+void BATTLE_Shutdown
+(
+    void
+)
+
+{
+    int index;
+    int index2;
+
+    Timer             = 0;
+    RoundOver         = false;
+    BattleRound       = 0;
+    BattleMode        = battle_StandAloneGame;
+    BATTLEMODE        = false;
+    NumberOfPlayers   = 1;
+    BATTLE_NumberOfTeams = 1;
+    PointGoal         = 0;
+    KillsEndGame      = false;
+    KeepTrackOfKills  = false;
+
+    for( index = 0; index < MAXPLAYERS; index++ )
+    {
+        BATTLE_Points[ index ] = 0;
+        for( index2 = 0; index2 < MAXPLAYERS; index2++ )
+        {
+            WhoKilledWho[ index ][ index2 ] = 0;
+        }
+        gamestate.PlayerHasGun[ index ] = true;
+    }
+    gamestate.BattleOptions.SpawnHealth  = true;
+    gamestate.BattleOptions.SpawnWeapons = true;
+    gamestate.BattleOptions.SpawnDangers = true;
+    gamestate.BattleOptions.RandomWeapons = false;
+    gamestate.BattleOptions.FriendlyFire  = true;
+    gamestate.BattleOptions.WeaponPersistence = false;
+    gamestate.BattleOptions.SpawnMines    = false;
+
+    gamestate.ShowScores        = true;
+    gamestate.SpawnCollectItems = false;
+    gamestate.SpawnEluder       = false;
+    gamestate.SpawnDeluder      = false;
+}
+
+
+
+/*---------------------------------------------------------------------
+	Function: BATTLE_StartRound
+
+	Begins a round of battle.
+---------------------------------------------------------------------*/
+
+static battle_status BATTLE_StartRound
+(
+    void
+)
+
+{
+    int index;
+
+    Timer     = 0;
+    TimeLimit = INFINITE;
+    RoundOver = false;
+
+    if ( !BATTLEMODE )
+    {
+        return( battle_no_event );
+    }
+
+    BattleRound++;
+
+    if ( gamestate.BattleOptions.TimeLimit == bo_time_infinite )
+    {
+        if ( BattleMode == battle_Hunter )
+        {
+            TimeLimit = MINUTES_TO_GAMECOUNT( 99 );
+        }
+        else
+        {
+            TimeLimit = INFINITE;
+        }
+    }
+    else
+    {
+        TimeLimit = MINUTES_TO_GAMECOUNT( gamestate.BattleOptions.TimeLimit );
+    }
+
+    if ( BattleMode == battle_Hunter )
+    {
+        for( index = 0; index < MAXPLAYERS; index++ )
+        {
+            gamestate.PlayerHasGun[ index ] = true;
+        }
+
+        if ( ( gamestate.BattleOptions.Kills != bo_kills_infinite ) &&
+                ( BattleRound >= PointGoal ) )
+        {
+            return( battle_end_game );
+        }
+
+        BATTLE_It = BattleRound % BATTLE_NumberOfTeams;
+        for( index = 0; index < NumberOfPlayers; index++ )
+        {
+            if ( BATTLE_Team[ index ] == BATTLE_It )
+            {
+                gamestate.PlayerHasGun[ index ] = false;
+            }
+        }
+    }
+
+    return( battle_no_event );
+}
+
+/*---------------------------------------------------------------------
+	Function: BATTLE_CheckGameStatus
+
+	Checks if certain battle mode conditions have been met and
+	determines the appropriate response.
+---------------------------------------------------------------------*/
+
+battle_status BATTLE_CheckGameStatus
+(
+    battle_event reason,
+    int player
+)
+
+{
+    battle_status status;
+    int team;
+
+    if ( ( player < 0 ) || ( player >= MAXPLAYERS ) )
+    {
+#if (BATTLECHECK == 1)
+        Error( "BATTLE_CheckGameStatus - reason %d : Player out of range!\n",
+               reason );
+#else
+        return( battle_no_event );
+#endif
+    }
+
+    if ( !BATTLEMODE )
+    {
+        return( battle_no_event );
+    }
+
+    team = BATTLE_Team[ player ];
+
+    status = battle_no_event;
+
+    switch( reason )
+    {
+    case battle_refresh :
+        Timer++;
+        if ( ( TimeLimit != INFINITE ) &&
+                ( Timer > TimeLimit ) )
+        {
+            RoundOver = true;
+
+            if ( BattleMode == battle_Hunter )
+            {
+                status = BATTLE_StartRound();
+                if ( status == battle_no_event )
+                {
+                    status = battle_end_round;
+                }
+            }
+            else
+            {
+                status = battle_out_of_time;
+            }
+
+            UpdateKills = true;
+        }
+
+        if ( UpdateKills )
+        {
+            BATTLE_SortPlayerRanks();
+            if ( gamestate.ShowScores )
+            {
+                DrawKills (false);
+            }
+            UpdateKills = false;
+        }
+
+        if ( RoundOver )
+        {
+            return( battle_end_game );
+        }
+        break;
+
+    case battle_player_killed :
+#if (BATTLEINFO == 1)
+        SoftError( "BATTLE_CheckGameStatus: Player %d Died", player );
+        SoftError( "---ticks = %d\n", Timer );
+#endif
+
+        switch( BattleMode )
+        {
+        case battle_Normal :
+        case battle_ScoreMore :
+        case battle_Hunter :
+            if ( BattleOptions.FriendlyFire )
+            {
+                BATTLE_Points[ team ]--;
+                UpdateKills = true;
+            }
+            break;
+
+        case battle_Tag :
+            // Same as being tagged
+            if ( BattleOptions.FriendlyFire )
+            {
+                BATTLE_Points[ team ]++;
+                UpdateKills = true;
+            }
+            break;
+        }
+
+        WhoKilledWho[ player ][ player ]++;
+        break;
+
+    case battle_get_collector_item :
+
+        if ( ( BattleMode != battle_Collector ) &&
+                ( BattleMode != battle_Scavenger ) )
+        {
+#if (BATTLECHECK == 1)
+            Error( "BATTLE_CheckGameStatus : Got collector item on wrong battle mode!" );
+#else
+            return( battle_no_event );
+#endif
+        }
+        BATTLE_Points[ team ]++;
+        UpdateKills = true;
+
+        BATTLE_NumCollectorItems--;
+        if ( BATTLE_NumCollectorItems <= 0 )
+        {
+            RoundOver = true;
+            return( battle_end_game );
+        }
+        break;
+
+    case battle_caught_eluder :
+        if ( BattleMode == battle_Deluder )
+        {
+            return( battle_no_event );
+        }
+
+        if ( BattleMode != battle_Eluder )
+        {
+#if (BATTLECHECK == 1)
+            Error( "BATTLE_CheckGameStatus : Caught Eluder on non-Eluder battle mode!" );
+#else
+            return( battle_no_event );
+#endif
+        }
+
+        BATTLE_Points[ team ]++;
+        UpdateKills = true;
+
+        if ( ( gamestate.BattleOptions.Kills != bo_kills_infinite ) &&
+                ( BATTLE_Points[ team ] >= PointGoal ) )
+        {
+            RoundOver = true;
+            return( battle_end_game );
+        }
+        RespawnEluder();
+        break;
+
+    case battle_shot_deluder :
+        if ( BattleMode == battle_Eluder )
+        {
+            return( battle_no_event );
+        }
+
+        if ( BattleMode != battle_Deluder )
+        {
+#if (BATTLECHECK == 1)
+            Error( "BATTLE_CheckGameStatus : Shot Eluder on non-Eluder battle mode!" );
+#else
+            return( battle_no_event );
+#endif
+        }
+
+        BATTLE_Points[ team ]++;
+        UpdateKills = true;
+
+        if ( ( gamestate.BattleOptions.Kills != bo_kills_infinite ) &&
+                ( BATTLE_Points[ team ] >= PointGoal ) )
+        {
+            RoundOver = true;
+            return( battle_end_game );
+        }
+        RespawnEluder();
+        break;
+
+    case battle_captured_triad :
+        if ( BattleMode != battle_CaptureTheTriad )
+        {
+#if (BATTLECHECK == 1)
+            Error( "BATTLE_CheckGameStatus : Triad Captured on invalid battle mode!" );
+#else
+            return( battle_no_event );
+#endif
+        }
+
+        if ( consoleplayer == player )
+        {
+            AddMessage( "You captured a triad!  You rule!", MSG_GAME );
+        }
+
+        BATTLE_Points[ team ]++;
+        UpdateKills = true;
+
+        if ( ( gamestate.BattleOptions.Kills != bo_kills_infinite ) &&
+                ( BATTLE_Points[ team ] >= PointGoal ) )
+        {
+            RoundOver = true;
+            return( battle_end_game );
+        }
+        break;
+
+    default :
+#if (BATTLECHECK == 1)
+        Error( "BATTLE_CheckGameStatus called with a reason of %d.",
+               reason );
+#else
+        return( battle_no_event );
+#endif
+        break;
+    }
+
+    return( status );
+}
+
+/*---------------------------------------------------------------------
+   Function: BATTLE_SortPlayerRanks
+
+   Sorts the players in order of score.
+---------------------------------------------------------------------*/
+
+void BATTLE_SortPlayerRanks
+(
+    void
+)
+
+{
+    int i;
+    int j;
+    int temp;
+
+    SwapFlag = false;
+
+    if ( BattleMode == battle_Tag )
+    {
+        for( i = 0; i < BATTLE_NumberOfTeams - 1; i++ )
+        {
+            for( j = i + 1; j < BATTLE_NumberOfTeams; j++ )
+            {
+                if ( BATTLE_Points[ BATTLE_PlayerOrder[ i ] ] >
+                        BATTLE_Points[ BATTLE_PlayerOrder[ j ] ] )
+                {
+                    SwapFlag = true;
+                    temp = BATTLE_PlayerOrder[ i ];
+                    BATTLE_PlayerOrder[ i ] = BATTLE_PlayerOrder[ j ];
+                    BATTLE_PlayerOrder[ j ] = temp;
+                }
+            }
+        }
+    }
+    else
+    {
+        for( i = 0; i < BATTLE_NumberOfTeams - 1; i++ )
+        {
+            for( j = i + 1; j < BATTLE_NumberOfTeams; j++ )
+            {
+                if ( BATTLE_Points[ BATTLE_PlayerOrder[ i ] ] <
+                        BATTLE_Points[ BATTLE_PlayerOrder[ j ] ] )
+                {
+                    SwapFlag = true;
+                    temp = BATTLE_PlayerOrder[ i ];
+                    BATTLE_PlayerOrder[ i ] = BATTLE_PlayerOrder[ j ];
+                    BATTLE_PlayerOrder[ j ] = temp;
+                }
+            }
+
+            if ( BattleMode != battle_Hunter )
+            {
+                BATTLE_It = BATTLE_PlayerOrder[ 0 ];
+            }
+        }
+    }
+
+#if (BATTLEINFO == 1)
+    for( i = 0; i < BATTLE_NumberOfTeams; i++ )
+    {
+        SoftError( "Sorted rank %d = player %d : Score = %d\n", i,
+                   BATTLE_PlayerOrder[ i ], BATTLE_Points[ BATTLE_PlayerOrder[ i ] ] );
+    }
+#endif
+
+    if ( ( SwapFlag == true ) && ( gamestate.ShowScores ) &&
+            ( SHOW_TOP_STATUS_BAR() || SHOW_KILLS() ) )
+    {
+        SD_Play ( SD_ENDBONUS1SND );
+    }
+}
+
+
+/*---------------------------------------------------------------------
+   Function: BATTLE_PlayerKilledPlayer
+
+   Increases the number of kills a player has.
+---------------------------------------------------------------------*/
+
+battle_status BATTLE_PlayerKilledPlayer
+(
+    battle_event reason,
+    int killer,
+    int victim
+)
+
+{
+    int points;
+    int status;
+    int killerteam;
+    int victimteam;
+
+#if (BATTLEINFO == 1)
+    SoftError( "PlayerKilledPlayer:\nMode = %d\n", BattleMode );
+    SoftError( "Reason = %d\n", reason );
+    SoftError( "killer = %d, team = %d\n", killer, killerteam );
+    SoftError( "victim = %d, team = %d\n", victim, victimteam );
+    SoftError( "---ticks = %d\n", Timer );
+#endif
+
+    if ( ( killer < 0 ) || ( killer >= MAXPLAYERS ) )
+    {
+#if (BATTLECHECK == 1)
+        Error( "BATTLE_PlayerKilledPlayer - reason %d : Killer out of range!\n",
+               reason );
+#else
+        return( battle_no_event );
+#endif
+    }
+    if ( ( victim < 0 ) || ( victim >= MAXPLAYERS ) )
+    {
+#if (BATTLECHECK == 1)
+        Error( "BATTLE_PlayerKilledPlayer - reason %d : Victim out of range!\n",
+               reason );
+#else
+        return( battle_no_event );
+#endif
+    }
+
+    if ( ( killer == victim ) && ( reason != battle_kill_with_missile ) &&
+            ( reason != battle_kill_with_missile_in_air ) )
+    {
+#if (BATTLECHECK == 1)
+        Error( "BATTLE_PlayerKilledPlayer : Player "
+               "killed self with illegal reason of %d.", reason );
+#else
+        return( battle_no_event );
+#endif
+    }
+
+    killerteam = BATTLE_Team[ killer ];
+    victimteam = BATTLE_Team[ victim ];
+
+    if ( ( killerteam < 0 ) || ( killerteam >= BATTLE_NumberOfTeams ) ||
+            ( victimteam < 0 ) || ( victimteam >= BATTLE_NumberOfTeams ) )
+    {
+#if (BATTLECHECK == 1)
+        Error( "BATTLE_PlayerKilledPlayer - reason %d : Team out of range!\n",
+               reason );
+#else
+        return( battle_no_event );
+#endif
+    }
+
+    if ( !BATTLEMODE )
+    {
+        return( battle_no_event );
+    }
+
+    if ( ( consoleplayer == victim ) &&
+            ( reason == battle_kill_by_crushing ) )
+    {
+        AddMessage( "Oh yeah.  You've been crushed.", MSG_GAME );
+    }
+
+    status = battle_no_event;
+    if ( BattleMode == battle_ScoreMore )
+    {
+        points = 0;
+        switch( reason )
+        {
+        case battle_kill_with_missile :
+            points = 1;
+            break;
+
+        case battle_kill_with_bullet :
+            points = 2;
+            break;
+
+        case battle_kill_with_missile_in_air :
+            points = 2;
+            break;
+
+        case battle_kill_with_bullet_in_air :
+            points = 3;
+            break;
+
+        case battle_kill_by_crushing :
+            points = 4;
+            break;
+
+        default :
+#if (BATTLECHECK == 1)
+            Error( "BATTLE_PlayerKilledPlayer called with a reason of %d.",
+                   reason );
+#else
+            return( battle_no_event );
+#endif
+        }
+
+        if ( killerteam == victimteam )
+        {
+            if ( BattleOptions.FriendlyFire )
+            {
+                BATTLE_Points[ killerteam ]--;
+                WhoKilledWho[ killer ][ victim ]++;
+            }
+        }
+        else
+        {
+            BATTLE_Points[ killerteam ]      += points;
+            WhoKilledWho[ killer ][ victim ] += points;
+        }
+        UpdateKills = true;
+    }
+    else if ( BattleMode == battle_Tag )
+    {
+        if ( reason == battle_player_tagged )
+        {
+            WhoKilledWho[ killer ][ victim ]++;
+            BATTLE_Points[ victimteam ]++;
+            UpdateKills = true;
+            BATTLE_It   = victimteam;
+
+            if ( ( gamestate.BattleOptions.Kills != bo_kills_infinite ) &&
+                    ( BATTLE_Points[ victimteam ] >= PointGoal ) )
+            {
+                RoundOver = true;
+                status = battle_end_game;
+            }
+        }
+#if (BATTLECHECK == 1)
+        else if ( reason != battle_kill_by_crushing )
+        {
+            Error( "BATTLE_PlayerKilledPlayer - reason %d : "
+                   "Illegal reason in Tag!\n", reason );
+        }
+#endif
+
+        return( status );
+    }
+    else if ( BattleMode == battle_Hunter )
+    {
+        switch( reason )
+        {
+        case battle_kill_with_missile :
+        case battle_kill_with_bullet :
+        case battle_kill_with_missile_in_air :
+        case battle_kill_with_bullet_in_air :
+        case battle_kill_by_crushing :
+            if ( victimteam == BATTLE_It )
+            {
+                WhoKilledWho[ killer ][ victim ]++;
+                if ( killerteam == victimteam )
+                {
+                    if ( BattleOptions.FriendlyFire )
+                    {
+                        BATTLE_Points[ killerteam ]--;
+                        UpdateKills = true;
+                    }
+                }
+                else
+                {
+                    BATTLE_Points[ killerteam ]++;
+                    UpdateKills = true;
+                }
+            }
+            break;
+        default :
+#if (BATTLECHECK == 1)
+            Error( "BATTLE_PlayerKilledPlayer called with a "
+                   "reason of %d in Hunter.", reason );
+#else
+            ;
+#endif
+        }
+    }
+    else
+    {
+        switch( reason )
+        {
+        case battle_kill_with_missile :
+        case battle_kill_with_bullet :
+        case battle_kill_with_missile_in_air :
+        case battle_kill_with_bullet_in_air :
+        case battle_kill_by_crushing :
+            WhoKilledWho[ killer ][ victim ]++;
+            if ( KeepTrackOfKills )
+            {
+                if ( killerteam == victimteam )
+                {
+                    if ( BattleMode == battle_Normal )
+                    {
+                        if ( BattleOptions.FriendlyFire )
+                        {
+                            BATTLE_Points[ killerteam ]--;
+                            UpdateKills = true;
+                        }
+                    }
+                }
+                else
+                {
+                    BATTLE_Points[ killerteam ]++;
+                    UpdateKills = true;
+                }
+            }
+            break;
+
+        default :
+#if (BATTLECHECK == 1)
+            Error( "BATTLE_PlayerKilledPlayer called with a reason of %d.",
+                   reason );
+#else
+            return( battle_no_event );
+#endif
+        }
+    }
+
+    if ( ( KillsEndGame ) && ( BATTLE_Points[ killerteam ] >= PointGoal ) )
+    {
+        RoundOver = true;
+        status = battle_end_game;
+    }
+
+    return( status );
+}
--- /dev/null
+++ b/rott/rt_battl.h
@@ -1,0 +1,224 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+/**********************************************************************
+   module: RT_BATTL.H
+
+   author: James R. Dose
+   phone:  (214)-271-1365 Ext #221
+   date:   September 8, 1994
+
+   Public header for RT_BATTL.C
+
+   (c) Copyright 1994 Apogee Software.  All Rights Reserved.
+**********************************************************************/
+
+#ifndef __RT_BATTLE_public
+#define __RT_BATTLE_public
+
+
+#define BIT_MASK( bit_number )   ( 1 << ( bit_number ) )
+#define MINUTES_TO_GAMECOUNT( minutes ) \
+   ( ( minutes ) * 60 * VBLCOUNTER )
+
+//
+// Return codes
+//
+
+typedef enum
+{
+    battle_no_event,
+    battle_end_game,
+    battle_end_round,
+    battle_out_of_time
+} battle_status;
+
+//
+// Types of battle events
+//
+
+typedef enum
+{
+    battle_refresh,
+    battle_player_killed,
+    battle_player_tagged,
+    battle_kill_with_missile,
+    battle_kill_with_bullet,
+    battle_kill_with_missile_in_air,
+    battle_kill_with_bullet_in_air,
+    battle_kill_by_crushing,
+    battle_get_collector_item,
+    battle_caught_eluder,
+    battle_shot_deluder,
+    battle_captured_triad
+} battle_event;
+
+//
+// Battle modes
+//
+
+enum
+{
+    battle_StandAloneGame,
+    battle_Normal,
+    battle_ScoreMore,
+    battle_Collector,
+    battle_Scavenger,
+    battle_Hunter,
+    battle_Tag,
+    battle_Eluder,
+    battle_Deluder,
+    battle_CaptureTheTriad,
+    battle_NumBattleModes
+};
+
+//
+// Battle mode option : Gravity
+//
+
+//enum
+//   {
+//   bo_low_gravity,
+//   bo_normal_gravity,
+//   bo_high_gravity
+//   };
+
+//
+// Battle mode option : Speed
+//
+
+enum
+{
+    bo_normal_speed,
+    bo_fast_speed
+};
+
+//
+// Battle mode option : Ammo
+//
+
+enum
+{
+    bo_one_shot,
+    bo_normal_shots,
+    bo_infinite_shots
+};
+
+//
+// Battle mode option : Hit points
+//
+
+#define bo_character_hitpoints 0
+#define bo_default_hitpoints   250
+
+//
+// Battle mode option : Light levels
+//
+
+enum
+{
+    bo_light_dark,
+    bo_light_normal,
+    bo_light_bright,
+    bo_light_fog,
+    bo_light_periodic,
+    bo_light_lightning
+};
+
+//
+// Battle mode option : Number of kills
+//
+
+enum
+{
+    bo_kills_random   = -2,
+    bo_kills_blind    = -1,
+    bo_kills_infinite = 0,
+    bo_kills_default  = 21
+};
+
+//
+// Battle mode option : Environment danger damage
+//
+
+enum
+{
+    bo_danger_normal = -1,
+    bo_danger_low    = 1,
+    bo_danger_kill   = 30000
+};
+
+//
+// Battle mode option : Time limit
+//
+#define bo_time_infinite 0
+
+//
+// Battle mode configuration
+//
+typedef struct
+{
+    unsigned Gravity;
+    unsigned Speed;
+    unsigned Ammo;
+    unsigned HitPoints;
+    unsigned SpawnDangers;
+    unsigned SpawnHealth;
+    unsigned SpawnWeapons;
+    unsigned SpawnMines;
+    unsigned RespawnItems;
+    unsigned WeaponPersistence;
+    unsigned RandomWeapons;
+    unsigned FriendlyFire;
+    unsigned LightLevel;
+    int      Kills;
+    int      DangerDamage;
+    unsigned TimeLimit;
+    unsigned RespawnTime;
+} battle_type;
+
+#define bo_normal_respawn_time 30
+
+extern boolean  BATTLEMODE;
+extern short    WhoKilledWho[ MAXPLAYERS ][ MAXPLAYERS ];
+extern short    BATTLE_Points[ MAXPLAYERS ];
+extern short    BATTLE_PlayerOrder[ MAXPLAYERS ];
+extern int      BATTLE_NumCollectorItems;
+extern int      PointGoal;
+extern int      DisplayPoints;
+extern int      BATTLE_It;
+extern boolean  BATTLE_ShowKillCount;
+extern short    BATTLE_Team[ MAXPLAYERS ];
+extern short    BATTLE_TeamLeader[ MAXPLAYERS ];
+extern int      BATTLE_NumberOfTeams;
+extern boolean  UpdateKills;
+
+// Located in RT_MENU.C
+extern battle_type    BATTLE_Options[ battle_NumBattleModes ];
+
+void          BATTLE_Init( int battlemode, int numplayers );
+void          BATTLE_GetSpecials( void );
+void          BATTLE_SetOptions( battle_type *options );
+void          BATTLE_GetOptions( battle_type *options );
+battle_status BATTLE_CheckGameStatus( battle_event reason, int player );
+void          BATTLE_SortPlayerRanks( void );
+battle_status BATTLE_PlayerKilledPlayer( battle_event reason, int killer, int victim );
+void          BATTLE_Shutdown( void );
+
+#endif
--- /dev/null
+++ b/rott/rt_build.c
@@ -1,0 +1,1572 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+// RT_BUILD.C
+
+#include "rt_def.h"
+#include <string.h>
+#include "watcom.h"
+#include <stdio.h>
+#include <stdlib.h>
+
+#ifdef DOS
+#include <dos.h>
+#include <conio.h>
+#endif
+
+#include "rt_build.h"
+#include "_rt_buil.h"
+#include "rt_dr_a.h"
+#include "rt_draw.h"
+#include "rt_scale.h"
+#include "rt_menu.h"
+#include "rt_main.h"
+#include "isr.h"
+#include "rt_util.h"
+#include "engine.h"
+#include "lumpy.h"
+#include "rt_fc_a.h"
+#include "z_zone.h"
+#include "w_wad.h"
+#include "rt_view.h"
+#include "rt_cfg.h"
+#include "rt_vid.h"
+
+#include "rt_sound.h"
+#include "modexlib.h"
+#include "rt_str.h"
+//MED
+#include "memcheck.h"
+
+byte * intensitytable;
+
+
+// LOCAL VARIABLES
+
+static byte * menubuf;
+static byte * menubuffers[2];
+static char menutitles[2][40];
+static int alternatemenubuf=0;
+static int titleshade=16;
+static int titleshadedir=1;
+static int titleyoffset=0;
+static char titlestring[40]="\0";
+static int readytoflip;
+static boolean MenuBufStarted=false;
+static int mindist=0x2700;
+static boolean BackgroundDrawn=false;
+
+static plane_t planelist[MAXPLANES],*planeptr;
+
+static int StringShade=16;
+
+extern void (*USL_MeasureString)(const char *, int *, int *, font_t *);
+
+static char strbuf[MaxString];
+
+//******************************************************************************
+//
+// DrawRotPost
+//
+//******************************************************************************
+
+void DrawRotPost ( int height, byte * src, byte * buf, int origheight)
+{
+    int y1;
+    int y2;
+
+    hp_srcstep=(origheight<<18)/height;
+    y1 = (((centery<<8)-(height<<5)+(MENUOFFY<<8)));
+    y2 = (((height<<6)+y1)>>8);
+
+    if (((y1>>8)>=200) || (y2<0))
+        return;
+    if (y1<0)
+    {
+        hp_startfrac=FixedMulShift(-y1,hp_srcstep,8);
+        y2 = (((height<<6)+y1)>>8);
+        y1=0;
+    }
+    else
+    {
+        hp_startfrac=FixedMulShift(255-(y1&0xff),hp_srcstep,8);
+        y1>>=8;
+    }
+    if (y2>200)
+    {
+        DrawMenuPost(200-y1, src, buf+ylookup[y1]);
+    }
+    else
+    {
+        DrawMenuPost(y2-y1, src, buf+ylookup[y1]);
+    }
+}
+
+
+
+/*
+========================
+=
+= GetPoint
+=
+========================
+*/
+
+void GetPoint (int x1, int y1, int px, int py, int * screenx, int * height, int angle)
+{
+
+    fixed gxt,gyt,nx,ny;
+    fixed gxtt,gytt;
+    int gx,gy;
+
+
+//
+// translate point to view centered coordinates
+//
+    gx = x1-px;
+    gy = y1-py;
+
+//
+// calculate newx
+//
+    gxt = FixedMul(gx,costable[angle]);
+    gyt = FixedMul(gy,sintable[angle]);
+    nx =gxt-gyt;
+
+    if (nx<mindist)
+        nx=mindist;
+
+
+//
+// calculate newy
+//
+    gxtt = FixedMul(gx,sintable[angle]);
+    gytt = FixedMul(gy,costable[angle]);
+    ny = gytt+gxtt;
+
+// too close, don't overflow the divid'
+
+
+    *screenx = 160 + ((ny*NORMALWIDTHMULTIPLIER)/nx);            // DEBUG: use assembly divide
+
+    *height = NORMALHEIGHTDIVISOR/nx;
+
+    if (*screenx<0) *screenx=0;
+
+}
+
+
+/*
+========================
+=
+= InterpolatePlane
+=
+========================
+*/
+
+void InterpolatePlane (visobj_t * plane)
+{
+    int d1,d2;
+    int top;
+    int topinc;
+    int bot;
+    int botinc;
+    int i;
+    int texture;
+    int dh;
+    int dx;
+    int height;
+
+
+    dx=(plane->x2-plane->x1+1);
+    if (plane->h1<=0 || plane->h2<=0 || (dx==0))
+        return;
+    d1=65536/plane->h1;
+    d2=65536/plane->h2;
+    dh=((plane->h2-plane->h1)<<8)/dx;
+    top=0;
+    topinc=(d1)*((plane->textureend-plane->texturestart)>>4);
+    bot=d2*dx;
+    botinc=d1-d2;
+    height=(plane->h1<<8);
+    if (plane->x1>=viewwidth)
+        return;
+    for (i=plane->x1; i<=plane->x2; i++)
+    {
+        if ((i>=0 && i<viewwidth)&&(posts[i].wallheight<(height>>8)))
+        {
+            if (bot)
+            {
+                texture=((top/bot)+(plane->texturestart>>4))>>6;
+                posts[i].texture=texture*plane->viewx;
+                posts[i].lump=plane->shapenum;
+                posts[i].wallheight=(height>>8);
+                posts[i].offset=plane->viewx;
+            }
+        }
+        top+=topinc;
+        bot+=botinc;
+        height+=dh;
+    }
+}
+
+//******************************************************************************
+//
+// DrawPlanePosts
+//
+//******************************************************************************
+
+void   DrawPlanePosts (void)
+{
+    int height;
+    char * buf;
+    byte * shape;
+    int lastwall=-2;
+    int plane;
+    int i;
+
+    shadingtable=colormap+(16<<8);
+
+#ifdef DOS
+    for (plane=0; plane<4; plane++)
+#endif
+
+    {
+        VGAWRITEMAP(plane);
+        buf=(byte *)(bufferofs);
+
+#ifdef DOS
+        for (i=plane; i<viewwidth; i+=4,buf++)
+#else
+        for (i=0; i<viewwidth; i++,buf++)
+#endif
+        {
+            height=(posts[i].wallheight);
+            if (height<=4)
+                continue;
+            if (lastwall!=posts[i].lump)
+            {
+                lastwall=posts[i].lump;
+                if (lastwall==-1)
+                    shape=menubuf;
+                else
+                    shape=W_CacheLumpNum(lastwall,PU_CACHE, Cvt_patch_t, 1);
+            }
+            DrawRotPost (height,shape+posts[i].texture,buf,posts[i].offset);
+        }
+    }
+}
+
+//******************************************************************************
+//
+// NextPlaneptr
+//
+//******************************************************************************
+
+void NextPlaneptr ( void )
+{
+    if (planeptr < &planelist[MAXPLANES-1]) // don't let it overflo'
+        planeptr++;
+}
+
+//******************************************************************************
+//
+// RestPlaneptr
+//
+//******************************************************************************
+
+void ResetPlaneptr ( void )
+{
+    planeptr = &planelist[0];
+}
+
+//******************************************************************************
+//
+// NextVisptr
+//
+//******************************************************************************
+
+void NextVisptr ( void )
+{
+    if (visptr < &vislist[MAXVISIBLE-1]) // don't let it overflo'
+        visptr++;
+}
+
+//******************************************************************************
+//
+// ResetVisptr
+//
+//******************************************************************************
+
+void ResetVisptr ( void )
+{
+    visptr = &vislist[0];
+}
+
+//******************************************************************************
+//
+// SetupPlanes
+//
+//******************************************************************************
+
+void SetupPlanes ( void )
+{
+    int i;
+
+    for (i=0; i<320; i++)
+        posts[i].wallheight=-1;
+}
+
+
+
+//******************************************************************************
+//
+// CalcPlanes
+//
+//******************************************************************************
+
+void CalcPlanes ( int px, int py, int angle )
+{
+    plane_t * pptr;
+
+    ResetVisptr();
+    for (pptr = &planelist[0]; pptr<planeptr; pptr++)
+    {
+        if (SideOfLine(pptr->x1,pptr->y1,pptr->x2,pptr->y2,px,py)<0)
+        {
+            GetPoint (pptr->x1,pptr->y1,px,py,&visptr->x1,&visptr->h1,angle);
+            GetPoint (pptr->x2,pptr->y2,px,py,&visptr->x2,&visptr->h2,angle);
+            visptr->textureend=0x0;
+            visptr->texturestart=pptr->texturewidth;
+        }
+        else
+        {
+            GetPoint (pptr->x2,pptr->y2,px,py,&visptr->x1,&visptr->h1,angle);
+            GetPoint (pptr->x1,pptr->y1,px,py,&visptr->x2,&visptr->h2,angle);
+            visptr->texturestart=0x0;
+            visptr->textureend=pptr->texturewidth;
+        }
+        visptr->shapenum=pptr->texture;
+        visptr->viewx=pptr->origheight;
+        visptr->viewheight=MAX(visptr->h1,visptr->h2);
+        NextVisptr();
+    }
+}
+
+
+//******************************************************************************
+//
+// DrawTransformedPlanes
+//
+//******************************************************************************
+
+void DrawTransformedPlanes ( void )
+{
+    int numvisible;
+    int greatest;
+    int height;
+    int i;
+    visobj_t * closest;
+
+    numvisible = visptr-&vislist[0];
+    if (!numvisible)
+        return;                                     // no visible objects
+    for (i = 0; i<numvisible; i++)
+    {
+        greatest = 0;
+        for (visstep=&vislist[0] ; visstep<visptr ; visstep++)
+        {
+            height = visstep->viewheight;
+            if (height > greatest)
+            {
+                greatest = height;
+                closest = visstep;
+            }
+        }
+        InterpolatePlane(closest);
+        closest->viewheight = 0;
+    }
+}
+
+
+//******************************************************************************
+//
+// ClearMenuBuf
+//
+//******************************************************************************
+
+void ClearMenuBuf ( void )
+{
+    byte * shape;
+
+    if (MenuBufStarted==false)
+        Error("Called ClearMenuBuf without menubuf started\n");
+
+    shape=W_CacheLumpName(MENUBACKNAME,PU_CACHE, Cvt_patch_t, 1);
+    shape+=8;
+    memcpy (menubuf,shape,TEXTUREW*TEXTUREHEIGHT);
+}
+
+//******************************************************************************
+//
+// ShutdownMenuBuf
+//
+//******************************************************************************
+
+void ShutdownMenuBuf ( void )
+{
+    if (MenuBufStarted==false)
+        return;
+    MenuBufStarted=false;
+    SafeFree(menubuffers[0]);
+    SafeFree(menubuffers[1]);
+    if (loadedgame==false)
+        SetViewSize(viewsize);
+}
+
+//******************************************************************************
+//
+// SetupMenuBuf
+//
+//******************************************************************************
+
+void SetupMenuBuf ( void )
+{
+#define SRCH 148
+#define SRCW 258
+#define PLANEX1 (-0x24000)
+#define PLANEX2 (0x23fff)
+#define PLANEW (16<<10)
+#define PLANEY (0x40000)
+#define PLANEW2 (0x5a827)
+
+    if (MenuBufStarted==true)
+        return;
+    MenuBufStarted=true;
+
+    // No top offsets like in game
+
+    centery=100;
+    centeryfrac=centery<<16;
+
+    strcpy(titlestring,menutitles[0]);
+
+    screenofs=0;
+    viewwidth=320;
+    viewheight=200;
+
+    alternatemenubuf=0;
+
+    ResetPlaneptr();
+    planeptr->texture=-1;
+    planeptr->y1=PLANEX1;
+    planeptr->x1=PLANEW;
+    planeptr->y2=PLANEX2;
+    planeptr->x2=PLANEW;
+    planeptr->origheight=TEXTUREHEIGHT;
+    planeptr->texturewidth=TEXTUREWIDTH;
+    NextPlaneptr();
+    planeptr->texture=-1;
+    planeptr->y1=PLANEX1;
+    planeptr->x1=-PLANEW;
+    planeptr->y2=PLANEX2;
+    planeptr->x2=-PLANEW;
+    planeptr->origheight=TEXTUREHEIGHT;
+    planeptr->texturewidth=TEXTUREWIDTH;
+    NextPlaneptr();
+    planeptr->texture=W_GetNumForName(MENUBACKNAME);
+    planeptr->y1=PLANEX1;
+    planeptr->x1=PLANEW;
+    planeptr->y2=PLANEX1;
+    planeptr->x2=-PLANEW;
+    planeptr->origheight=TEXTUREHEIGHT;
+    planeptr->texturewidth=TEXTUREWIDTH;
+    NextPlaneptr();
+    planeptr->texture=W_GetNumForName(MENUBACKNAME);
+    planeptr->y1=PLANEX2;
+    planeptr->x1=PLANEW;
+    planeptr->y2=PLANEX2;
+    planeptr->x2=-PLANEW;
+    planeptr->origheight=TEXTUREHEIGHT;
+    planeptr->texturewidth=TEXTUREWIDTH;
+    NextPlaneptr();
+
+    menubuffers[0]=SafeMalloc(TEXTUREW*TEXTUREHEIGHT);
+    menubuffers[1]=SafeMalloc(TEXTUREW*TEXTUREHEIGHT);
+    menubuf=menubuffers[0];
+    ClearMenuBuf();
+    BackgroundDrawn=false;
+}
+
+
+//******************************************************************************
+//
+// PositionMenuBuf
+//
+//******************************************************************************
+
+void PositionMenuBuf( int angle, int distance, boolean drawbackground )
+{
+    int px,py;
+    font_t * oldfont;
+    int width,height;
+
+
+    if (MenuBufStarted==false)
+        Error("Called PositionMenuBuf without menubuf started\n");
+    CalcTics();
+    SetupPlanes();
+    if ((drawbackground==true) || (BackgroundDrawn==false))
+    {
+        VL_DrawPostPic (W_GetNumForName("trilogo"));
+    }
+    px=FixedMulShift(distance,costable[angle&(FINEANGLES-1)],16);
+    py=FixedMulShift(-distance,sintable[angle&(FINEANGLES-1)],16);
+    CalcPlanes(px,py,(angle+ANG180)&(FINEANGLES-1));
+    DrawTransformedPlanes();
+    DrawPlanePosts();
+    oldfont=CurrentFont;
+    CurrentFont = (font_t *)W_CacheLumpName ("newfnt1", PU_CACHE, Cvt_font_t, 1);
+    US_MeasureStr (&width, &height, "%s", titlestring);
+    US_ClippedPrint ((320-width)>>1, MENUTITLEY-titleyoffset, titlestring);
+    CurrentFont=oldfont;
+    FlipPage();
+    titleshade+=titleshadedir;
+    if (abs(titleshade-16)>6)
+        titleshadedir=-titleshadedir;
+    if (BackgroundDrawn==false)
+    {
+        VL_CopyDisplayToHidden();
+        BackgroundDrawn=true;
+    }
+}
+
+//******************************************************************************
+//
+// RefreshMenuBuf
+//
+//******************************************************************************
+
+void RefreshMenuBuf( int time )
+{
+    int i;
+
+    if (MenuBufStarted==false)
+        Error("Called RefreshMenuBuf without menubuf started\n");
+
+    if (readytoflip)
+        return;
+
+    for (i=0; i<=time; i+=tics)
+    {
+        //PositionMenuBuf (0,NORMALVIEW,false);
+        PositionMenuBuf (0,NORMALVIEW,true);//bna++ in not true bg in menu is no redrawn
+    }
+}
+
+//******************************************************************************
+//
+// ScaleMenuBufPost
+//
+//******************************************************************************
+
+void ScaleMenuBufPost (byte * src, int topoffset, byte * buf)
+{
+    int  d;
+    int  offset;
+    int  length;
+    int  s;
+
+
+    while (1)
+    {
+        offset=*(src++);
+        if (offset==0xff)
+            return;
+        else
+        {
+            d=offset-topoffset;
+            length=*(src++);
+            for (s=0; s<length; s++,d++)
+                *(buf+d)=*(src+s);
+            src+=length;
+        }
+    }
+}
+
+//******************************************************************************
+//
+// SetAlternateMenuBuf
+//
+//******************************************************************************
+
+void SetAlternateMenuBuf ( void )
+{
+    if (MenuBufStarted==false)
+        Error("Called SetAlternateMenuBuf without menubuf started\n");
+
+    alternatemenubuf^=1;
+    readytoflip=1;
+    menubuf=menubuffers[alternatemenubuf];
+}
+
+//******************************************************************************
+//
+// SetMenuTitle
+//
+//******************************************************************************
+
+void SetMenuTitle ( const char * menutitle )
+{
+    if (MenuBufStarted==false)
+        Error("Called SetMenuTitle without menubuf started\n");
+    strcpy(menutitles[alternatemenubuf],menutitle);
+    if (readytoflip==0)
+        strcpy(titlestring,menutitle);
+}
+
+//******************************************************************************
+//
+// DrawMenuBufPicture
+//
+//******************************************************************************
+
+void DrawMenuBufPicture (int x, int y, const byte * pic, int w, int h)
+{
+    byte *buffer;
+    int i;
+
+    if (MenuBufStarted==false)
+        Error("Called DrawMenuBufPictoure without menubuf started\n");
+
+    if ((x<0) || (x+w>=TEXTUREW))
+        Error ("DrawMenuBufPicture: x is out of range\n");
+    if ((y<0) || (y+h>=TEXTUREHEIGHT))
+        Error ("DrawMenuBufPicture: y is out of range\n");
+
+    for (i=0; i<w; i++)
+    {
+        buffer = (byte*)menubuf+y+((x+i)*TEXTUREHEIGHT);
+        memcpy(buffer,pic,h);
+        pic+=h;
+    }
+}
+
+//******************************************************************************
+//
+// DrawMenuBufItem
+//
+//******************************************************************************
+
+void DrawMenuBufItem (int x, int y, int shapenum)
+{
+    byte *buffer;
+    int cnt;
+    byte *shape;
+    patch_t *p;
+
+    if (MenuBufStarted==false)
+        Error("Called DrawMenuBufItem without menubuf started\n");
+
+    shape = W_CacheLumpNum (shapenum, PU_CACHE, Cvt_patch_t, 1);
+    p = (patch_t *)shape;
+
+    if (((x-p->leftoffset)<0) || ((x-p->leftoffset+p->width)>=TEXTUREW))
+        Error ("DrawMenuBufItem: x is out of range\n");
+    if (((y-p->topoffset)<0) || ((y-p->topoffset+p->height)>=TEXTUREHEIGHT))
+        Error ("DrawMenuBufItem: y is out of range\n");
+
+    buffer = (byte*)menubuf+y+((x-p->leftoffset)*TEXTUREHEIGHT);
+
+    for (cnt = 0; cnt < p->width; cnt++,buffer+=TEXTUREHEIGHT)
+        ScaleMenuBufPost ((byte *)(p->collumnofs[cnt]+shape),
+                          p->topoffset, buffer);
+}
+
+//******************************************************************************
+//
+// IScaleMenuBufPost
+//
+//******************************************************************************
+
+void IScaleMenuBufPost (byte * src, int topoffset, byte * buf, int color)
+{
+    int  d;
+    int  offset;
+    int  length;
+    int  s;
+
+
+    while (1)
+    {
+        offset=*(src++);
+        if (offset==0xff)
+            return;
+        else
+        {
+            d=offset-topoffset;
+            length=*(src++);
+            for (s=0; s<length; s++,d++)
+                *(buf+d)=*(intensitytable+((*(src+s))<<8)+color);
+            src+=length;
+        }
+    }
+}
+
+
+//******************************************************************************
+//
+// DrawIMenuBufItem
+//
+//******************************************************************************
+
+void DrawIMenuBufItem (int x, int y, int shapenum, int color)
+{
+    byte *buffer;
+    int cnt;
+    byte *shape;
+    patch_t *p;
+
+
+    if (MenuBufStarted==false)
+        Error("Called DrawIMenuBufItem without menubuf started\n");
+
+    shape = W_CacheLumpNum (shapenum, PU_CACHE, Cvt_patch_t, 1);
+    p = (patch_t *)shape;
+
+    if (((x-p->leftoffset)<0) || ((x-p->leftoffset+p->width)>=TEXTUREW))
+        Error ("DrawIMenuBufItem: x is out of range\n");
+    if (((y-p->topoffset)<0) || ((y-p->topoffset+p->height)>=TEXTUREHEIGHT))
+        Error ("DrawIMenuBufItem: y is out of range\n");
+
+    buffer = (byte*)menubuf+y+((x-p->leftoffset)*TEXTUREHEIGHT);
+
+    for (cnt = 0; cnt < p->width; cnt++,buffer+=TEXTUREHEIGHT)
+        IScaleMenuBufPost ((byte *)(p->collumnofs[cnt]+shape),
+                           p->topoffset, buffer, color);
+}
+
+
+//******************************************************************************
+//
+// TScaleMenuBufPost
+//
+//******************************************************************************
+void TScaleMenuBufPost (byte * src, int topoffset, byte * buf)
+{
+    int  d;
+    int  offset;
+    int  length;
+    byte pixel;
+    int  s;
+
+
+    while (1)
+    {
+        offset=*(src++);
+        if (offset==0xff)
+            return;
+        else
+        {
+            d=offset-topoffset;
+            length=*(src++);
+            for (s=0; s<length; s++,d++)
+            {
+                pixel = *(buf+d);
+                pixel = *(shadingtable+pixel);
+                *(buf+d) = pixel;
+            }
+            src+=length;
+        }
+    }
+}
+
+
+//******************************************************************************
+//
+// CScaleMenuBufPost
+//
+//******************************************************************************
+void CScaleMenuBufPost (byte * src, int topoffset, byte * buf)
+{
+    int  d;
+    int  offset;
+    int  length;
+    byte pixel;
+    int  s;
+
+
+    while (1)
+    {
+        offset=*(src++);
+        if (offset==0xff)
+            return;
+        else
+        {
+            d=offset-topoffset;
+            length=*(src++);
+            for (s=0; s<length; s++,d++)
+            {
+                pixel = *(src+s);
+                pixel = *(shadingtable+pixel);
+                *(buf+d) = pixel;
+            }
+            src+=length;
+        }
+    }
+}
+
+
+//******************************************************************************
+//
+// EraseMenuBufRegion
+//
+//******************************************************************************
+
+void EraseMenuBufRegion (int x, int y, int width, int height)
+{
+    byte *buffer;
+    int xx,yy;
+    byte * shape;
+
+    if (MenuBufStarted==false)
+        Error("Called EraseMenuBufRegion without menubuf started\n");
+
+    if ((x<0) || (x+width>=TEXTUREW))
+        Error ("EraseMenuBufRegion: x is out of range\n");
+    if ((y<0) || (y+height>=TEXTUREHEIGHT))
+        Error ("EraseMenuBufRegion: y is out of range\n");
+
+    shape=W_CacheLumpName(MENUBACKNAME,PU_CACHE, Cvt_patch_t, 1);
+    shape+=8;
+    shape+=(x*TEXTUREHEIGHT)+y;
+    buffer = (byte*)menubuf+(x*TEXTUREHEIGHT)+y;
+
+    for (xx = 0; xx < width; xx++)
+    {
+        for (yy = 0; yy < height; yy++)
+            *(buffer+yy)=*(shape+yy);
+        buffer+=TEXTUREHEIGHT;
+        shape+=TEXTUREHEIGHT;
+    }
+}
+
+
+//******************************************************************************
+//
+// DrawTMenuBufPic
+//
+//******************************************************************************
+
+void DrawTMenuBufPic (int x, int y, int shapenum)
+{
+    byte *buffer;
+    byte *buf;
+    int xx,yy;
+    int plane;
+    int pixel;
+    byte *shape;
+    byte *src;
+    pic_t *p;
+
+    if (MenuBufStarted==false)
+        Error("Called DrawTMenuBufPic without menubuf started\n");
+
+    shadingtable=colormap+(25<<8);
+
+    shape = W_CacheLumpNum (shapenum, PU_CACHE, Cvt_pic_t, 1);
+    p = (pic_t *)shape;
+
+    if ((x<0) || ((x+(p->width<<2))>=TEXTUREW))
+        Error ("DrawTMenuBufPic: x is out of range\n");
+    if ((y<0) || ((y+p->height)>=TEXTUREHEIGHT))
+        Error ("DrawTMenuBufPic: y is out of range\n");
+
+    buffer = (byte*)menubuf+(x*TEXTUREHEIGHT)+y;
+
+    src=(byte *)&p->data;
+    for (plane=0; plane<4; plane++,buffer+=TEXTUREHEIGHT)
+    {
+        for (yy = 0; yy < p->height; yy++)
+        {
+            buf=buffer+yy;
+            for (xx = 0; xx < p->width; xx++,buf+=TEXTUREHEIGHT<<2)
+            {
+                pixel = *(buf);
+                pixel = *(shadingtable+pixel);
+                *(buf) = pixel;
+            }
+        }
+    }
+}
+
+
+//******************************************************************************
+//
+// DrawTMenuBufItem
+//
+//******************************************************************************
+
+void DrawTMenuBufItem (int x, int y, int shapenum)
+{
+    byte *buffer;
+    int cnt;
+    byte *shape;
+    patch_t *p;
+
+
+    if (MenuBufStarted==false)
+        Error("Called DrawTMenuBufItem without menubuf started\n");
+
+    shape = W_CacheLumpNum (shapenum, PU_CACHE, Cvt_patch_t, 1);
+    p = (patch_t *)shape;
+
+    shadingtable=colormap+(25<<8);
+
+    if (((x-p->leftoffset)<0) || ((x-p->leftoffset+p->width)>=TEXTUREW))
+        Error ("DrawTMenuBufItem: x is out of range\n");
+    if (((y-p->topoffset)<0) || ((y-p->topoffset+p->height)>=TEXTUREHEIGHT))
+        Error ("DrawTMenuBufItem: y is out of range\n");
+
+    buffer = (byte*)menubuf+y+((x-p->leftoffset)*TEXTUREHEIGHT);
+
+    for (cnt = 0; cnt < p->width; cnt++,buffer+=TEXTUREHEIGHT)
+        TScaleMenuBufPost ((byte *)(p->collumnofs[cnt]+shape),
+                           p->topoffset, buffer);
+}
+
+//******************************************************************************
+//
+// DrawColoredMenuBufItem
+//
+//******************************************************************************
+
+void DrawColoredMenuBufItem (int x, int y, int shapenum, int color)
+{
+    byte *buffer;
+    int cnt;
+    byte *shape;
+    patch_t *p;
+
+
+    if (MenuBufStarted==false)
+        Error("Called DrawColoredMenuBufItem without menubuf started\n");
+
+    shape = W_CacheLumpNum (shapenum, PU_CACHE, Cvt_patch_t, 1);
+    p = (patch_t *)shape;
+
+    shadingtable=playermaps[color]+(16<<8);
+
+    if (((x-p->leftoffset)<0) || ((x-p->leftoffset+p->width)>=TEXTUREW))
+        Error ("DrawColoredMenuBufItem: x is out of range\n");
+    if (((y-p->topoffset)<0) || ((y-p->topoffset+p->height)>=TEXTUREHEIGHT))
+        Error ("DrawColoredMenuBufItem: y is out of range\n");
+
+    buffer = (byte*)menubuf+y+((x-p->leftoffset)*TEXTUREHEIGHT);
+
+    for (cnt = 0; cnt < p->width; cnt++,buffer+=TEXTUREHEIGHT)
+        CScaleMenuBufPost ((byte *)(p->collumnofs[cnt]+shape),
+                           p->topoffset, buffer);
+}
+
+//******************************************************************************
+//
+// DrawMenuBufPic
+//
+//******************************************************************************
+
+void DrawMenuBufPic (int x, int y, int shapenum)
+{
+    byte *buffer;
+    byte *buf;
+    int xx,yy;
+    int plane;
+    byte *shape;
+    byte *src;
+    pic_t *p;
+
+    if (MenuBufStarted==false)
+        Error("Called DrawMenuBufPic without menubuf started\n");
+
+    shape = W_CacheLumpNum (shapenum, PU_CACHE, Cvt_pic_t, 1);
+    p = (pic_t *)shape;
+
+    if ((x<0) || ((x+(p->width<<2))>=TEXTUREW))
+        Error ("DrawTMenuBufPic: x is out of range\n");
+    if ((y<0) || ((y+p->height)>=TEXTUREHEIGHT))
+        Error ("DrawTMenuBufPic: y is out of range\n");
+
+
+    buffer = (byte*)menubuf+(x*TEXTUREHEIGHT)+y;
+
+    src=(byte *)&p->data;
+    for (plane=0; plane<4; plane++,buffer+=TEXTUREHEIGHT)
+    {
+        for (yy = 0; yy < p->height; yy++)
+        {
+            buf=buffer+yy;
+            for (xx = 0; xx < p->width; xx++,buf+=TEXTUREHEIGHT<<2)
+                *(buf)=*(src++);
+        }
+    }
+}
+
+
+
+
+//******************************************************************************
+//
+// DrawTMenuBufBox
+//
+//******************************************************************************
+
+
+void DrawTMenuBufBox ( int x, int y, int width, int height )
+{
+    byte *buffer;
+    int   xx;
+    int   yy;
+    int   pixel;
+
+    if (MenuBufStarted==false)
+        Error("Called DrawTMenuBufBox without menubuf started\n");
+
+    shadingtable = colormap + ( 25 << 8 );
+
+    if ( ( x < 0 ) || ( ( x + width ) >= TEXTUREW ) )
+        Error ("DrawTMenuBar : x is out of range\n");
+    if ( ( y < 0 ) || ( y + height ) >= TEXTUREHEIGHT )
+        Error ("DrawTMenuBar : y is out of range\n");
+
+    buffer = ( byte * )menubuf + ( x * TEXTUREHEIGHT ) + y;
+
+    for ( xx = 0; xx < width; xx++ )
+    {
+        for ( yy = 0; yy < height; yy++ )
+        {
+            pixel = *( buffer + yy );
+            pixel = *( shadingtable + pixel );
+            *( buffer + yy ) = pixel;
+        }
+
+        buffer += TEXTUREHEIGHT;
+    }
+}
+
+
+//******************************************************************************
+//
+// DrawTMenuBufHLine
+//
+//******************************************************************************
+
+void DrawTMenuBufHLine (int x, int y, int width, boolean up)
+{
+    byte *buffer;
+    byte *buf;
+    int xx;
+    int plane;
+    int pixel;
+    int w = width>>2;
+    int ww = w;
+
+    if ((x<0) || ((x+(width))>=TEXTUREW))
+        Error ("DrawTMenuBufBox: x is out of range\n");
+    if (y<0)
+        Error ("DrawTMenuBufBox: y is out of range\n");
+
+    buffer = (byte*)menubuf+(x*TEXTUREHEIGHT)+y;
+
+    if (up)
+        shadingtable=colormap+(13<<8);
+    else
+        shadingtable=colormap+(25<<8);
+
+    for (plane = 0; plane < 4; plane++, buffer += TEXTUREHEIGHT)
+    {
+        w = ww;
+        switch (plane)
+        {
+        case 0:
+            if (width % 4)
+                w++;
+            break;
+        case 1:
+            if ((width % 4) > 1)
+                w++;
+            break;
+        case 2:
+            if ((width % 4) > 2)
+                w++;
+            break;
+        }
+
+
+        buf = buffer;
+        for (xx = 0; xx < w; xx++, buf += (TEXTUREHEIGHT<<2))
+        {
+            pixel = *(buf);
+            pixel = *(shadingtable+pixel);
+            *(buf) = pixel;
+        }
+    }
+}
+
+//******************************************************************************
+//
+// DrawTMenuBufVLine
+//
+//******************************************************************************
+
+void DrawTMenuBufVLine (int x, int y, int height, boolean up)
+{
+    byte *buffer;
+    byte *buf;
+    int yy;
+    int pixel;
+
+    if (x<0)
+        Error ("DrawTMenuBufBox: x is out of range\n");
+    if ((y<0) || ((y+height)>=TEXTUREHEIGHT))
+        Error ("DrawTMenuBufBox: y is out of range\n");
+
+    buffer = (byte*)menubuf+(x*TEXTUREHEIGHT)+y;
+
+    if (up)
+        shadingtable=colormap+(13<<8);
+    else
+        shadingtable=colormap+(25<<8);
+
+    for (yy = 0; yy < height; yy++)
+    {
+        buf = buffer+yy;
+        pixel = *(buf);
+        pixel = *(shadingtable+pixel);
+        *(buf) = pixel;
+    }
+}
+
+//******************************************************************************
+//******************************************************************************
+//
+// STRING ROUTINES
+//
+//******************************************************************************
+//******************************************************************************
+
+
+//******************************************************************************
+//
+// DrawMenuBufPropString ()
+//
+//******************************************************************************
+
+void DrawMenuBufPropString (int px, int py, const char *string)
+{
+    byte  pix;
+    int   width,height,ht;
+    byte  *source, *dest, *origdest;
+    int   ch;
+
+
+    if (MenuBufStarted==false)
+        Error("Called DrawMenuBufPropString without menubuf started\n");
+
+    ht = CurrentFont->height;
+    dest = origdest = (byte*)menubuf+(px*TEXTUREHEIGHT)+py;
+
+    while ((ch = (unsigned char)*string++)!=0)
+    {
+        ch -= 31;
+        width = CurrentFont->width[ch];
+        source = ((byte *)CurrentFont)+CurrentFont->charofs[ch];
+        while (width--)
+        {
+            height = ht;
+            while (height--)
+            {
+                pix = *source;
+                if (pix)
+                    *dest = pix;
+
+                source++;
+                dest ++;
+            }
+
+            PrintX++;
+            origdest+=TEXTUREHEIGHT;
+            dest = origdest;
+        }
+    }
+
+}
+
+
+//******************************************************************************
+//
+// DrawMenuBufIString ()
+//
+//******************************************************************************
+
+void DrawMenuBufIString (int px, int py, const char *string, int color)
+{
+    byte  pix;
+    int   width,height,ht;
+    byte  *source, *dest, *origdest;
+    int   ch;
+
+    if (MenuBufStarted==false)
+        Error("Called DrawMenuBufPropString without menubuf started\n");
+
+    if ( ( color < 0 ) || ( color > 255 ) )
+    {
+        Error( "Intensity Color out of range\n" );
+    }
+
+    ht = IFont->height;
+    dest = origdest = (byte*)menubuf+(px*TEXTUREHEIGHT)+py;
+
+    PrintX = px;
+    PrintY = py;
+
+    while ((ch = (unsigned char)*string++)!=0)
+    {
+        // Tab
+        if ( ch == '\x9' )
+        {
+            int offset;
+
+            PrintX   -= px;
+            offset    = 4 * 5 - PrintX % ( 4 * 5 );
+            PrintX   += offset + px;
+            origdest += offset * TEXTUREHEIGHT;
+            dest      = origdest;
+            continue;
+        }
+
+        ch -= 31;
+        width = IFont->width[ ch ];
+
+        source = ( ( byte * )IFont ) + IFont->charofs[ ch ];
+
+        while (width--)
+        {
+            height = ht;
+            while (height--)
+            {
+                pix = *source;
+                if ( pix != 0xFE )
+                {
+                    *dest = ( ( byte )intensitytable[ ( pix << 8 ) + color ] );
+                    GetIntensityColor( pix );
+                }
+
+                source++;
+                dest ++;
+            }
+
+            PrintX++;
+            origdest+=TEXTUREHEIGHT;
+            dest = origdest;
+        }
+    }
+
+}
+
+
+//******************************************************************************
+//
+// DrawTMenuBufPropString ()
+//
+// Draws a string at px, py to bufferofs
+//
+//******************************************************************************
+
+void DrawTMenuBufPropString (int px, int py, const char *string)
+{
+    byte  pix;
+    int   width,height,ht;
+    byte  *source, *dest, *origdest;
+    int   ch;
+
+
+    if (MenuBufStarted==false)
+        Error("Called DrawTMenuBufPropString without menubuf started\n");
+
+    ht = CurrentFont->height;
+    dest = origdest = (byte*)menubuf+(px*TEXTUREHEIGHT)+py;
+
+    shadingtable=colormap+(StringShade<<8);
+    while ((ch = (unsigned char)*string++)!=0)
+    {
+        ch -= 31;
+        width = CurrentFont->width[ch];
+        source = ((byte *)CurrentFont)+CurrentFont->charofs[ch];
+        while (width--)
+        {
+            height = ht;
+            while (height--)
+            {
+                pix = *source;
+                if (pix)
+                {
+                    pix = *dest;
+                    pix = *(shadingtable+pix);
+                    *dest = pix;
+                }
+                source++;
+                dest ++;
+            }
+
+            PrintX++;
+            origdest+=TEXTUREHEIGHT;
+            dest = origdest;
+        }
+    }
+}
+
+
+//******************************************************************************
+//
+// MenuBufCPrintLine() - Prints a string centered on the current line and
+//    advances to the next line. Newlines are not supported.
+//
+//******************************************************************************
+
+void MenuBufCPrintLine (const char *s)
+{
+    int w, h;
+
+    USL_MeasureString (s, &w, &h, CurrentFont);
+
+    if (w > WindowW)
+        Error("MenuBufCPrintLine() - String exceeds width");
+
+    PrintX = WindowX + ((WindowW - w) / 2);
+    DrawMenuBufPropString (PrintX, PrintY, s);
+    PrintY += h;
+}
+
+//******************************************************************************
+//
+// MenuBufCPrint() - Prints a string in the current window. Newlines are
+//    supported.
+//
+//******************************************************************************
+
+void MenuBufCPrint (const char *string)
+{
+    char  c,
+          *se,
+          *s;
+
+    /* !!! FIXME: this is lame. */
+    if (strlen(string) >= sizeof (strbuf))
+    {
+        fprintf(stderr, "buffer overflow!\n");
+        return;
+    }
+
+    /* prevent writing to literal strings... ( MenubufCPrint("feh"); ) */
+    strcpy(strbuf, string);
+    s = strbuf;
+
+    while (*s)
+    {
+        se = s;
+        while ((c = *se) && (c != '\n'))
+            se++;
+        *se = '\0';
+
+        MenuBufCPrintLine(s);
+
+        s = se;
+        if (c)
+        {
+            *se = c;
+            s++;
+        }
+    }
+}
+
+//******************************************************************************
+//
+// MenuBufPrintLine() - Prints a string on the current line and
+//    advances to the next line. Newlines are not supported.
+//
+//******************************************************************************
+
+void MenuBufPrintLine (const char *s)
+{
+    int w, h;
+
+    USL_MeasureString (s, &w, &h, CurrentFont);
+
+    if (w > WindowW)
+        Error("MenuBufCPrintLine() - String exceeds width");
+
+    PrintX = WindowX;
+    DrawMenuBufPropString (PrintX, PrintY, s);
+    PrintY += h;
+}
+
+//******************************************************************************
+//
+// MenuBufPrint() - Prints a string in the current window. Newlines are
+//    supported.
+//
+//******************************************************************************
+
+void MenuBufPrint (const char *string)
+{
+    char  c,
+          *se,
+          *s;
+
+    strcpy(strbuf, string);
+    s = strbuf;
+
+    while (*s)
+    {
+        se = s;
+        while ((c = *se) && (c != '\n'))
+            se++;
+        *se = '\0';
+
+        MenuBufPrintLine(s);
+
+        s = se;
+        if (c)
+        {
+            *se = c;
+            s++;
+        }
+    }
+}
+
+//******************************************************************************
+//
+// MenuTBufPrintLine() - Prints a string on the current line and
+//    advances to the next line. Newlines are not supported.
+//
+//******************************************************************************
+
+void MenuTBufPrintLine (const char *s, int shade)
+{
+    int w, h;
+
+    USL_MeasureString (s, &w, &h, CurrentFont);
+
+    if (w > WindowW)
+        Error("MenuBufCPrintLine() - String exceeds width");
+
+    PrintX = WindowX;
+    StringShade=shade;
+    DrawTMenuBufPropString (PrintX, PrintY, s);
+    PrintY += h;
+}
+
+//******************************************************************************
+//
+// FlipMenuBuf
+//
+//******************************************************************************
+
+void FlipMenuBuf ( void )
+{
+    int i;
+    int dh;
+    int h;
+    int y;
+    int dy;
+    int time;
+    int flip;
+
+    if (MenuBufStarted==false)
+        Error("Called FlipMenuBuf without menubuf started\n");
+
+    if (!readytoflip)
+        Error("FlipMenuBuf called without SetAlternateMenuBuf beforehand");
+    readytoflip=0;
+    if (Menuflipspeed<=5)
+    {
+        menubuf=menubuffers[alternatemenubuf];
+        strcpy(titlestring,menutitles[alternatemenubuf]);
+        RefreshMenuBuf(0);
+    }
+    else
+    {
+        menubuf=menubuffers[alternatemenubuf^1];
+        strcpy(titlestring,menutitles[alternatemenubuf^1]);
+        time=Menuflipspeed-5;
+        dh=(1024<<8)/time;
+        h=0;
+        dy=((MENUTITLEY*6)<<8)/time;
+        y=0;
+        flip=0;
+        titleyoffset=0;
+        for (i=0; i<time; i+=tics)
+        {
+            PositionMenuBuf(h>>8,NORMALVIEW,true);
+            h+=dh*tics;
+            y+=dy*tics;
+            titleyoffset=y>>8;
+            if ((h>=512<<8) && (flip==0))
+            {
+                MN_PlayMenuSnd (SD_MENUFLIP);
+                h=1536<<8;
+                dy=-dy;
+                menubuf=menubuffers[alternatemenubuf];
+                strcpy(titlestring,menutitles[alternatemenubuf]);
+                flip=1;
+            }
+        }
+    }
+    titleyoffset=0;
+    BackgroundDrawn=false;
+}
+
+
+
+//******************************************************************************
+//
+// RotatePlane
+//
+//******************************************************************************
+
+void RotatePlane ( void )
+{
+    SetupMenuBuf();
+
+    while (!(Keyboard[0x01]))
+    {
+        RefreshMenuBuf(100);
+        SetAlternateMenuBuf();
+        ClearMenuBuf();
+        DrawMenuBufPic  (0,0,W_GetNumForName("newg11"));
+        DrawMenuBufItem (0,0,W_GetNumForName("apogee"));
+        FlipMenuBuf();
+        EraseMenuBufRegion(30,30,30,30);
+        RefreshMenuBuf(100);
+        SetAlternateMenuBuf();
+        ClearMenuBuf();
+        FlipMenuBuf();
+    }
+    ShutdownMenuBuf();
+}
--- /dev/null
+++ b/rott/rt_build.h
@@ -1,0 +1,65 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+#ifndef _rt_build_public
+#define _rt_build_public
+
+//***************************************************************************
+//
+// RT_BUILD.C
+//
+//***************************************************************************
+
+extern int Menuflipspeed;
+extern byte * intensitytable;
+
+void SetupMenuBuf ( void );
+void ShutdownMenuBuf ( void );
+
+void ClearMenuBuf ( void );
+void SetAlternateMenuBuf ( void );
+void SetMenuTitle ( const char * menutitle );
+
+void PositionMenuBuf( int angle, int distance, boolean drawbackground );
+void RefreshMenuBuf( int time );
+void FlipMenuBuf ( void );
+
+void DrawMenuBufItem (int x, int y, int shapenum);
+void DrawMenuBufIString (int px, int py, const char *string, int color);
+void DrawTMenuBufItem (int x, int y, int shapenum);
+void DrawIMenuBufItem (int x, int y, int shapenum, int color);
+void DrawColoredMenuBufItem (int x, int y, int shapenum, int color);
+void DrawMenuBufPic (int x, int y, int shapenum);
+void DrawTMenuBufPic (int x, int y, int shapenum);
+void EraseMenuBufRegion (int x, int y, int width, int height);
+
+void DrawMenuBufPropString (int px, int py, const char *string);
+void DrawTMenuBufPropString (int px, int py, const char *string);
+
+void DrawTMenuBufBox (int x, int y, int width, int height);
+void DrawTMenuBufHLine (int x, int y, int width, boolean up);
+void DrawTMenuBufVLine (int x, int y, int height, boolean up);
+void MenuBufCPrintLine (const char *s);
+void MenuBufCPrint (const char *s);
+void MenuBufPrint (const char *s);
+void MenuTBufPrintLine (const char *s, int shade);
+
+void DrawMenuBufPicture (int x, int y, const byte * pic, int w, int h);
+
+#endif
--- /dev/null
+++ b/rott/rt_cfg.c
@@ -1,0 +1,2239 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+//****************************************************************************
+//
+// RT_CFG.C
+//
+//****************************************************************************
+
+#define _ROTT_
+
+#ifdef DOS
+#include <io.h>
+#include <bios.h>
+#include <conio.h>
+#include <process.h>
+#else
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#endif
+
+#include <stdlib.h>
+#include <fcntl.h>
+#include <string.h>
+#include <ctype.h>
+
+#ifdef _ROTT_
+#include "rt_def.h"
+#else
+#include "st_def.h"
+#endif
+
+#include "rt_cfg.h"
+#include "version.h"
+
+#ifdef _ROTT_
+
+#include "scriplib.h"
+#include "rt_playr.h"
+#include "rt_menu.h"
+#include "rt_game.h"
+#include "rt_in.h"
+#include "z_zone.h"
+#include "w_wad.h"
+#include "rt_crc.h"
+#include "rt_sound.h"
+#include "rt_util.h"
+#include "rt_main.h"
+#include "rt_view.h"
+#include "rt_msg.h"
+#include "rt_battl.h"
+#include "rt_net.h"
+#include "isr.h"
+#include "fx_man.h"
+#include "develop.h"
+
+#else
+
+#include "st_def.h"
+#include "rt_cfg.h"
+#include "scriplib.h"
+#include "rt_sound.h"
+#include "st_util.h"
+
+#endif
+//MED
+#include "memcheck.h"
+
+
+//******************************************************************************
+//
+// GLOBALS
+//
+//******************************************************************************
+
+extern int G_weaponscale;
+extern boolean iG_aimCross;
+
+boolean WriteSoundFile   = true;
+
+int     FXMode           = 0;
+int     MusicMode        = 0;
+
+int     MUvolume         = 196;
+int     FXvolume         = 196;
+
+#ifdef DOS
+fx_blaster_config SBSettings =
+{
+    0x220, fx_SB, 7, 1, 5, 0x330, 0x620
+};
+#endif
+
+boolean mouseenabled     = 1;
+boolean usemouselook     = 0;
+int     inverse_mouse    = 1; //set  to -1 to invert mouse
+boolean usejump          = 0;
+boolean sdl_fullscreen   = 1;
+
+boolean allowBlitzMoreMissileWeps = 0;
+boolean enableAmmoPickups = 0;
+boolean autoAimMissileWeps = 0;
+boolean autoAim = 1;
+
+boolean joystickenabled  = 0;
+boolean joypadenabled    = 0;
+int     joystickport     = 0;
+int     mouseadjustment  = 5;
+int     threshold        = 1;
+int     NumVoices        = 4;
+int     NumChannels      = 1;
+int     NumBits          = 8;
+#ifdef DOS
+int     MidiAddress      = 0x330;
+#endif
+boolean cybermanenabled  = false;
+boolean assassinenabled  = false;
+boolean spaceballenabled = false;
+boolean AutoDetailOn     = true;
+int     DoubleClickSpeed = 20;
+boolean BobbinOn         = true;
+int     Menuflipspeed    = 15;
+int     DetailLevel      = 2;         //HI DETAIL
+int     fandc            = 1;
+int     blanktime        = (2*60*VBLCOUNTER);
+boolean ConfigLoaded     = false;
+boolean stereoreversed   = false;
+
+int     DefaultDifficulty      = 2;
+int     DefaultPlayerCharacter = 0;
+int     DefaultPlayerColor     = 0;
+byte    passwordstring[20];
+
+#ifndef _ROTT_
+
+int     fulllight        = 0;
+int     viewsize         = 7;
+
+#endif
+MacroList CommbatMacros[MAXMACROS];
+
+#ifdef DOS
+char *ApogeePath = "APOGEECD";
+#else
+char ApogeePath[256];
+#endif
+
+//******************************************************************************
+//
+// LOCALS
+//
+//******************************************************************************
+
+static char SoundName[13]  = "sound.rot";
+
+#ifdef _ROTT_
+
+static char *ConfigName = "config.rot";
+static char *ScoresName = "scores.rot";
+static char *ROTT       = "rott.rot";
+static char *CONFIG     = "setup.rot";
+static char *BattleName = "battle.rot";
+
+AlternateInformation RemoteSounds;
+//AlternateInformation PlayerGraphics;
+AlternateInformation GameLevels;
+AlternateInformation BattleLevels;
+char CodeName[MAXCODENAMELENGTH];
+
+#endif
+
+
+#ifdef _ROTT_
+
+//******************************************************************************
+//
+// ReadScores ()
+//
+//******************************************************************************
+
+void ReadScores (void)
+{
+    int file;
+    char filename[ 128 ];
+
+    GetPathFromEnvironment( filename, ApogeePath, ScoresName );
+    if (access (filename, F_OK) == 0)
+    {
+        file = SafeOpenRead (filename);
+        SafeRead (file, &Scores, sizeof (Scores));
+        close(file);
+    }
+    else
+        gamestate.violence = 0;
+}
+
+#endif
+
+//******************************************************************************
+//
+// ReadInt
+//
+//******************************************************************************
+
+void ReadInt (const char * s1, int * val)
+{
+    GetToken (true);
+    if (!strcmpi (token,s1))
+    {
+        if (TokenAvailable()==true)
+        {
+            GetToken(false);
+            *val=ParseNum(token);
+        }
+    }
+}
+
+//******************************************************************************
+//
+// ReadBoolean
+//
+//******************************************************************************
+
+void ReadBoolean (const char * s1, boolean * val)
+{
+    int temp;
+
+    temp = (int)(*val);
+    ReadInt (s1,&temp);
+    *val = (boolean) temp;
+}
+
+//******************************************************************************
+//
+// ReadUnsigned
+//
+//******************************************************************************
+
+void ReadUnsigned (const char * s1, unsigned long * val)
+{
+    int temp;
+
+    temp = (int)(*val);
+    ReadInt (s1,&temp);
+    *val = (unsigned) temp;
+}
+
+//******************************************************************************
+//
+// ParseSoundFile ()
+//
+//******************************************************************************
+
+boolean ParseSoundFile (void)
+{
+    boolean retval = true;
+    int version    = 0;
+
+    ReadInt("Version",&version);
+
+    if (version == ROTTVERSION)
+    {
+        // Read in Music Mode
+
+        ReadInt ("MusicMode",&MusicMode);
+
+        // Read in FX Mode
+
+        ReadInt ("FXMode",&FXMode);
+
+        // Read in Music Volume
+
+        ReadInt ("MusicVolume", &MUvolume);
+
+        // Read in FX Volume
+
+        ReadInt ("FXVolume", &FXvolume);
+
+        // Read in numvoices
+
+        ReadInt ("NumVoices",&NumVoices);
+
+        // Read in numchannels
+
+        ReadInt ("NumChannels",&NumChannels);
+
+        // Read in numbits
+
+        ReadInt ("NumBits",&NumBits);
+
+#ifdef DOS
+        // Read in Midi Address
+
+        ReadInt ("MidiAddress",&MidiAddress);
+#endif
+
+        // Read in stereo reversal
+
+        ReadBoolean ("StereoReverse",&stereoreversed);
+
+#ifdef DOS
+        // Read in Sound Blaster info
+        ReadUnsigned ("SBType",  &SBSettings.Type );
+        ReadUnsigned ("SBPort",  &SBSettings.Address );
+        ReadUnsigned ("SBIrq",   &SBSettings.Interrupt );
+        ReadUnsigned ("SBDma8",  &SBSettings.Dma8 );
+        ReadUnsigned ("SBDma16", &SBSettings.Dma16 );
+        ReadUnsigned ("SBMidi",  &SBSettings.Midi );
+        ReadUnsigned ("SBEmu",   &SBSettings.Emu );
+#endif
+    }
+    else
+        retval = false;
+
+    return (retval);
+}
+
+
+
+//******************************************************************************
+//
+// SetSoundDefaultValues ()
+//
+//******************************************************************************
+void SetSoundDefaultValues
+(
+    void
+)
+
+{
+#ifdef DOS
+    fx_blaster_config blaster;
+#endif
+    int status;
+
+    //
+    //  no config file, so select default values
+    //
+#if !defined(PLATFORM_DOS)
+    // icculus' SDL_mixer driver looks like a soundscape to us
+    MusicMode   = 6;
+    FXMode      = 6;
+    NumVoices   = 8;
+    NumChannels = 2;
+    NumBits     = 16;
+    stereoreversed = false;
+#else
+    MusicMode   = 0;
+    FXMode      = 0;
+    NumVoices   = 4;
+    NumChannels = 1;
+    NumBits     = 8;
+    MidiAddress = 0x330;
+    stereoreversed = false;
+
+    status = FX_GetBlasterSettings( &blaster );
+    if ( status == FX_Ok )
+    {
+        SBSettings.Type      = blaster.Type;
+        SBSettings.Address   = blaster.Address;
+        SBSettings.Interrupt = blaster.Interrupt;
+        SBSettings.Dma8      = blaster.Dma8;
+        SBSettings.Dma16     = blaster.Dma16;
+        SBSettings.Midi      = blaster.Midi;
+        SBSettings.Emu       = blaster.Emu;
+    }
+#endif
+}
+
+
+#ifdef _ROTT_
+
+extern char    pword[ 13 ];
+//******************************************************************************
+//
+// ConvertStringToPasswordString ()
+//
+//******************************************************************************
+
+#define PASSWORDENCRYPTER "7d7e4a2d3b6a0319554654231f6d2a"
+
+void ConvertStringToPasswordString ( char * string )
+{
+    int i;
+    unsigned int j;
+    char temp[3];
+
+    memset(temp,0,sizeof(temp));
+
+    for (i=0; i<13; i++)
+    {
+        memcpy(&temp[0],&string[i<<1],2);
+        sscanf(&temp[0],"%x",&j);
+        passwordstring[i+0] = j & 0xff;
+        j >>= 8;
+        passwordstring[i+1] = j & 0xff;
+        j >>= 8;
+        passwordstring[i+2] = j & 0xff;
+        j >>= 8;
+        passwordstring[i+3] = j & 0xff;
+    }
+}
+
+//******************************************************************************
+//
+// ConvertPasswordStringToPassword ()
+//
+//******************************************************************************
+
+void ConvertPasswordStringToPassword ( void )
+{
+    int i;
+    int x;
+    char temp[3];
+    char key[40];
+
+    memset(temp,0,sizeof(temp));
+    strcpy(&key[0],PASSWORDENCRYPTER);
+
+    for (i=0; i<12; i++)
+    {
+        memcpy(&temp[0],&key[i<<1],2);
+        sscanf(&temp[0],"%x",&x);
+        pword[i]=passwordstring[i]^x;
+    }
+    memcpy(&temp[0],&key[i<<1],2);
+    sscanf(&temp[0],"%x",&x);
+    gamestate.violence=passwordstring[i]^x;
+    if (
+        (gamestate.violence<0) ||
+        (gamestate.violence>3)
+    )
+        gamestate.violence=0;
+}
+
+//******************************************************************************
+//
+// ConvertPasswordStringToString ()
+//
+//******************************************************************************
+
+void ConvertPasswordStringToString ( char * string )
+{
+    int i;
+    char temp[8];
+
+    memset(temp,0,sizeof(temp));
+
+    for (i=0; i<13; i++)
+    {
+        itoa((passwordstring[i]>>4),&temp[0],16);
+        string[(i<<1)+0]=temp[0];
+        itoa((passwordstring[i]&0xf),&temp[0],16);
+        string[(i<<1)+1]=temp[0];
+    }
+}
+
+//******************************************************************************
+//
+// ConvertPasswordToPasswordString ()
+//
+//******************************************************************************
+
+void ConvertPasswordToPasswordString ( void )
+{
+    int i;
+    int x;
+    char temp[3];
+    char key[40];
+
+    memset(temp,0,sizeof(temp));
+    strcpy(&key[0],PASSWORDENCRYPTER);
+
+    for (i=0; i<12; i++)
+    {
+        memcpy(&temp[0],&key[i<<1],2);
+        sscanf(&temp[0],"%x",&x);
+        passwordstring[i]=pword[i]^x;
+    }
+    memcpy(&temp[0],&key[i<<1],2);
+    sscanf(&temp[0],"%x",&x);
+    passwordstring[i]=gamestate.violence^x;
+}
+
+//******************************************************************************
+//
+// ParseConfigFile ()
+//
+//******************************************************************************
+
+boolean ParseConfigFile (void)
+{
+//   int temp;
+    boolean retval = true;
+    int version    = 0;
+
+    ReadInt("Version",&version);
+
+    if (version == ROTTVERSION)
+    {
+        //Read in allowBlitzguardMoreMissileWeps
+
+        ReadBoolean("AllowBlitzguardMoreMissileWeps", &allowBlitzMoreMissileWeps);
+
+        //Read in enableAmmoPickups
+
+        ReadBoolean("EnableAmmoPickups", &enableAmmoPickups);
+
+        //Read in AutoAim
+
+        ReadBoolean("AutoAim", &autoAim);
+
+        //Read in AutoAimMissileWeps
+
+        ReadBoolean("AutoAimMissileWeps", &autoAimMissileWeps);
+
+        // Read in MouseEnabled
+        ReadBoolean("MouseEnabled",&mouseenabled);
+
+        // Read in UseMouseLook
+        ReadBoolean("UseMouseLook",&usemouselook);
+
+        ReadInt("InverseMouse",&inverse_mouse);
+
+        // Read in UseJump
+        ReadBoolean("UseJump",&usejump);
+
+        // Read in CrossHair
+        ReadBoolean("CrossHair",&iG_aimCross);
+
+        // Read in JoystickEnabled
+        ReadBoolean("JoystickEnabled",&joystickenabled);
+
+        // Read in JoypadEnabled
+        ReadBoolean("JoypadEnabled",&joypadenabled);
+
+        // Read in JoystickPort
+
+        ReadInt("JoystickPort",&joystickport);
+
+        // Read in fullscreen
+        ReadBoolean("FullScreen", &sdl_fullscreen);
+
+        // Read in resolution
+        ReadInt("ScreenWidth", &iGLOBAL_SCREENWIDTH);
+        ReadInt("ScreenHeight", &iGLOBAL_SCREENHEIGHT);
+
+        // Read in ViewSize
+
+        ReadInt("ViewSize",&viewsize);
+
+        // Read in Weaponscale
+
+        ReadInt("Weaponscale",&G_weaponscale);//bna added
+        if ((G_weaponscale <150)||(G_weaponscale>600)) {
+            if (iGLOBAL_SCREENWIDTH == 320) {
+                G_weaponscale=168;
+            } else if (iGLOBAL_SCREENWIDTH == 640) {
+                G_weaponscale=299;
+            } else if (iGLOBAL_SCREENWIDTH == 800) {
+                G_weaponscale=376;
+            }
+        }
+
+        // Read in MouseAdjustment
+
+        ReadInt("MouseAdjustment",&mouseadjustment);
+
+        // Read in threshold
+
+        ReadInt("Threshold",&threshold);
+
+        // Read in Auto Detail
+
+        ReadBoolean ("AutoDetail", &AutoDetailOn);
+
+        // Read in Light Dim
+
+        ReadInt ("LightDim", &fulllight);
+
+        // Read in Bobbin' On
+
+        ReadBoolean ("BobbingOn", &BobbinOn);
+
+        // Read in Double Click Speed
+
+        ReadInt ("DoubleClickSpeed", &DoubleClickSpeed);
+
+        // Read in Menu Flip Speed
+
+        ReadInt ("MenuFlipSpeed", &Menuflipspeed);
+
+        // Read in Detail Level
+
+        ReadInt ("DetailLevel", &DetailLevel);
+
+        // Read in Floor and Ceiling
+
+        ReadInt ("FloorCeiling", &fandc);
+
+        // Read in MessagesEnabled
+
+        ReadBoolean ("Messages", &MessagesEnabled );
+
+        // Read in Autorun
+
+        ReadInt ("AutoRun", &gamestate.autorun );
+
+        // Read in GammaIndex
+
+        ReadInt ("GammaIndex", &gammaindex);
+
+        // Read screen blanking time
+
+        ReadInt ("BlankTime", &blanktime);
+
+        blanktime=blanktime*60*VBLCOUNTER;
+
+        // Read keys
+
+        ReadInt ("Fire",        &buttonscan[0]);
+        ReadInt ("Strafe",      &buttonscan[1]);
+        ReadInt ("Run",         &buttonscan[2]);
+        ReadInt ("Use",         &buttonscan[3]);
+        ReadInt ("LookUp",      &buttonscan[4]);
+        ReadInt ("LookDn",      &buttonscan[5]);
+        ReadInt ("Swap",        &buttonscan[6]);
+        ReadInt ("Drop",        &buttonscan[7]);
+        ReadInt ("TargetUp",    &buttonscan[8]);
+        ReadInt ("TargetDn",    &buttonscan[9]);
+        ReadInt ("SelPistol",   &buttonscan[10]);
+        ReadInt ("SelDualPistol",&buttonscan[11]);
+        ReadInt ("SelMP40",     &buttonscan[12]);
+        ReadInt ("SelMissile",  &buttonscan[13]);
+        ReadInt ("AutoRun",     &buttonscan[14]);
+        ReadInt ("LiveRemRid",  &buttonscan[15]);
+        ReadInt ("StrafeLeft",  &buttonscan[16]);
+        ReadInt ("StrafeRight", &buttonscan[17]);
+        ReadInt ("VolteFace",   &buttonscan[18]);
+        ReadInt ("Aim",         &buttonscan[19]);
+        ReadInt ("Forward",     &buttonscan[20]);
+        ReadInt ("Right",       &buttonscan[21]);
+        ReadInt ("Backward",    &buttonscan[22]);
+        ReadInt ("Left",        &buttonscan[23]);
+        ReadInt ("Map",         &buttonscan[24]);
+        ReadInt ("SendMessage", &buttonscan[25]);
+        ReadInt ("DirectMessage",&buttonscan[26]);
+
+        ReadInt ("MouseButton0",&buttonmouse[0]);
+        ReadInt ("MouseButton1",&buttonmouse[1]);
+        ReadInt ("MouseButton2",&buttonmouse[2]);
+        ReadInt ("DblClickB0",  &buttonmouse[3]);
+        ReadInt ("DblClickB1",  &buttonmouse[4]);
+        ReadInt ("DblClickB2",  &buttonmouse[5]);
+
+        ReadInt ("JoyButton0",  &buttonjoy[0]);
+        ReadInt ("JoyButton1",  &buttonjoy[1]);
+        ReadInt ("JoyButton2",  &buttonjoy[2]);
+        ReadInt ("JoyButton3",  &buttonjoy[3]);
+        ReadInt ("DblClickJB0", &buttonjoy[4]);
+        ReadInt ("DblClickJB1", &buttonjoy[5]);
+        ReadInt ("DblClickJB2", &buttonjoy[6]);
+        ReadInt ("DblClickJB3", &buttonjoy[7]);
+
+        ReadInt ("JoyMaxX",     &joyxmax);
+        ReadInt ("JoyMaxY",     &joyymax);
+        ReadInt ("JoyMinX",     &joyxmin);
+        ReadInt ("JoyMinY",     &joyymin);
+
+        ReadInt( "DefaultDifficulty", &DefaultDifficulty );
+        ReadInt( "DefaultPlayerCharacter", &DefaultPlayerCharacter );
+        ReadInt( "DefaultPlayerColor", &DefaultPlayerColor );
+
+        // Get Password string
+        GetToken (true);
+        if (!stricmp (token, "SecretPassword"))
+        {
+            GetTokenEOL (false);
+            ConvertStringToPasswordString ( &name[0] );
+        }
+
+        if (!CybermanPresent)
+            cybermanenabled = false;
+
+        if (!AssassinPresent)
+            assassinenabled = false;
+
+        if (!SpaceBallPresent)
+            spaceballenabled = false;
+
+        if (!MousePresent)
+            mouseenabled = false;
+
+        if (!JoysPresent[joystickport])
+            joystickenabled = false;
+
+        // precaution
+
+        if (!joyxmin || !joyxmax || !joyymin || !joyymax)
+            joystickenabled = false;
+
+        if (joystickenabled)
+            IN_SetupJoy (joystickport, joyxmin, joyxmax, joyymin, joyymax);
+    }
+    else
+        retval = false;
+
+    return (retval);
+}
+
+
+//******************************************************************************
+//
+// ParseBattleFile ()
+//
+//******************************************************************************
+boolean ParseBattleFile (void)
+{
+    boolean retval = true;
+    int version    = 0;
+    int index;
+    int temp;
+    extern specials BattleSpecialsTimes;
+
+    ReadInt("Version",&version);
+    if (version != ROTTVERSION)
+        retval = false;
+    else
+    {
+        ReadBoolean( "ShowKillCount", &BATTLE_ShowKillCount );
+
+        ReadInt( "GodModeTime",                &BattleSpecialsTimes.GodModeTime );
+        ReadInt( "DogModeTime",                &BattleSpecialsTimes.DogModeTime );
+        ReadInt( "ShroomsModeTime",            &BattleSpecialsTimes.ShroomsModeTime );
+        ReadInt( "ElastoModeTime",             &BattleSpecialsTimes.ElastoModeTime );
+        ReadInt( "AsbestosVestTime",           &BattleSpecialsTimes.AsbestosVestTime );
+        ReadInt( "BulletProofVestTime",        &BattleSpecialsTimes.BulletProofVestTime );
+        ReadInt( "GasMaskTime",                &BattleSpecialsTimes.GasMaskTime );
+        ReadInt( "MercuryModeTime",            &BattleSpecialsTimes.MercuryModeTime );
+        ReadInt( "GodModeRespawnTime",         &BattleSpecialsTimes.GodModeRespawnTime );
+        ReadInt( "DogModeRespawnTime",         &BattleSpecialsTimes.DogModeRespawnTime );
+        ReadInt( "ShroomsModeRespawnTime",     &BattleSpecialsTimes.ShroomsModeRespawnTime );
+        ReadInt( "ElastoModeRespawnTime",      &BattleSpecialsTimes.ElastoModeRespawnTime );
+        ReadInt( "AsbestosVestRespawnTime",    &BattleSpecialsTimes.AsbestosVestRespawnTime );
+        ReadInt( "BulletProofVestRespawnTime", &BattleSpecialsTimes.BulletProofVestRespawnTime );
+        ReadInt( "GasMaskRespawnTime",         &BattleSpecialsTimes.GasMaskRespawnTime );
+        ReadInt( "MercuryModeRespawnTime",     &BattleSpecialsTimes.MercuryModeRespawnTime );
+
+        ReadBoolean( "EKG", &battlegibs );
+
+        for( index = battle_Normal; index < battle_NumBattleModes; index++ )
+        {
+            // Read Gravity
+            temp = BATTLE_Options[ index ].Gravity;
+            ReadInt( "Gravity", &temp );
+            BATTLE_Options[ index ].Gravity = temp;
+
+            // Read Speed
+            temp = bo_normal_speed;
+            ReadInt( "Speed", &temp );
+            if ( ( temp >= bo_normal_speed ) &&
+                    ( temp <= bo_fast_speed ) )
+            {
+                BATTLE_Options[ index ].Speed = temp;
+            }
+
+            if ( ( index != battle_Collector ) && ( index != battle_Tag ) &&
+                    ( index != battle_Eluder ) )
+            {
+                // Read Ammo
+                temp = bo_normal_shots;
+                BATTLE_Options[ index ].Ammo = bo_normal_shots;
+                ReadInt( "Ammo", &temp );
+                if ( ( temp >= bo_one_shot ) &&
+                        ( temp <= bo_infinite_shots ) )
+                {
+                    BATTLE_Options[ index ].Ammo = temp;
+                }
+            }
+
+            if ( index != battle_Eluder )
+            {
+                // Read Hitpoints
+                temp = BATTLE_Options[ index ].HitPoints;
+                ReadInt( "Hitpoints", &temp );
+                BATTLE_Options[ index ].HitPoints = temp;
+            }
+
+            // Read Spawn Dangers
+            temp = 1;
+            ReadInt( "SpawnDangers", &temp );
+            BATTLE_Options[ index ].SpawnDangers = temp;
+
+            if ( index != battle_Eluder )
+            {
+                // Read Spawn Health
+                temp = 1;
+                ReadInt( "SpawnHealth", &temp );
+                BATTLE_Options[ index ].SpawnHealth = temp;
+
+                // Read Spawn Mines
+                temp = 0;
+                ReadInt( "SpawnMines", &temp );
+                BATTLE_Options[ index ].SpawnMines = temp;
+            }
+
+            if ( ( index != battle_Collector ) && ( index != battle_Tag ) &&
+                    ( index != battle_Eluder ) )
+            {
+                // Read Spawn Weapons
+                temp = 1;
+                ReadInt( "SpawnWeapons", &temp );
+                BATTLE_Options[ index ].SpawnWeapons = temp;
+
+                // Read Random Weapons
+                temp = 0;
+                ReadInt( "RandomWeapons", &temp );
+                BATTLE_Options[ index ].RandomWeapons = temp;
+
+                // Read Weapon Persistence
+                temp = 0;
+                ReadInt( "WeaponPersistence", &temp );
+                BATTLE_Options[ index ].WeaponPersistence = temp;
+            }
+
+            if ( ( index == battle_Normal ) || ( index == battle_ScoreMore ) ||
+                    ( index == battle_Hunter ) || ( index == battle_Tag ) )
+            {
+                // Read Friendly Fire
+                temp = 1;
+                ReadInt( "FriendlyFire", &temp );
+                BATTLE_Options[ index ].FriendlyFire = temp;
+            }
+
+            if ( index != battle_Eluder )
+            {
+                // Read Respawn Items
+                temp = 1;
+                ReadInt( "RespawnItems", &temp );
+                BATTLE_Options[ index ].RespawnItems = temp;
+            }
+
+            // Read Light Level
+            temp = bo_light_normal;
+            ReadInt( "LightLevel", &temp );
+            if ( ( temp >= bo_light_dark ) &&
+                    ( temp <= bo_light_lightning ) )
+            {
+                BATTLE_Options[ index ].LightLevel = temp;
+            }
+
+            if ( ( index != battle_Collector ) && ( index != battle_Scavenger ) )
+            {
+                // Read Point Goal
+                temp = bo_kills_default;
+                ReadInt( "PointGoal", &temp );
+                BATTLE_Options[ index ].Kills = temp;
+                if ( temp < bo_kills_random )
+                {
+                    BATTLE_Options[ index ].Kills = bo_kills_default;
+                }
+            }
+
+            if ( index != battle_Eluder )
+            {
+                // Read Danger Damage
+                temp = bo_danger_normal;
+                ReadInt( "DangerDamage", &temp );
+                BATTLE_Options[ index ].DangerDamage = temp;
+            }
+
+            // Read Time Limit
+            temp = bo_time_infinite;
+            ReadInt( "TimeLimit", &temp );
+            if ( ( index == battle_Hunter ) && ( temp == bo_time_infinite ) )
+            {
+                temp = 99;
+            }
+            BATTLE_Options[ index ].TimeLimit = temp;
+
+            // Read Respawn time
+            temp = bo_normal_respawn_time;
+            ReadInt( "RespawnTime", &temp );
+            BATTLE_Options[ index ].RespawnTime = temp;
+        }
+    }
+
+    return (retval);
+}
+
+//******************************************************************************
+//
+// SetBattleDefaultValues ()
+//
+//******************************************************************************
+
+void SetBattleDefaultValues (void)
+{
+    int index;
+
+    //
+    //  no config file, so select default values
+    //
+    for( index = battle_StandAloneGame; index < battle_NumBattleModes;
+            index++ )
+    {
+        BATTLE_Options[ index ].Gravity      = NORMAL_GRAVITY;
+        BATTLE_Options[ index ].Speed        = bo_normal_speed;
+        BATTLE_Options[ index ].Ammo         = bo_normal_shots;
+        BATTLE_Options[ index ].HitPoints    = bo_default_hitpoints;
+        BATTLE_Options[ index ].SpawnDangers = 1;
+        BATTLE_Options[ index ].SpawnHealth  = 1;
+        BATTLE_Options[ index ].SpawnMines   = 0;
+        BATTLE_Options[ index ].SpawnWeapons = 1;
+        BATTLE_Options[ index ].RespawnItems = 1;
+        BATTLE_Options[ index ].RandomWeapons = 0;
+        BATTLE_Options[ index ].WeaponPersistence = 0;
+        BATTLE_Options[ index ].FriendlyFire = 1;
+        BATTLE_Options[ index ].LightLevel   = bo_light_normal;
+        BATTLE_Options[ index ].Kills        = bo_kills_default;
+        BATTLE_Options[ index ].DangerDamage = bo_danger_normal;
+        BATTLE_Options[ index ].TimeLimit    = bo_time_infinite;
+        BATTLE_Options[ index ].RespawnTime  = bo_normal_respawn_time;
+    }
+
+    BATTLE_Options[ battle_CaptureTheTriad ].Kills  = 1;
+    BATTLE_Options[ battle_Hunter ].TimeLimit       = 1;
+    BATTLE_Options[ battle_Eluder ].SpawnHealth     = 0;
+    BATTLE_Options[ battle_Eluder ].RespawnItems    = 0;
+    BATTLE_Options[ battle_Eluder ].SpawnWeapons    = 0;
+    BATTLE_Options[ battle_Eluder ].FriendlyFire    = 0;
+    BATTLE_Options[ battle_Collector ].SpawnWeapons = 0;
+    BATTLE_Options[ battle_Collector ].FriendlyFire = 0;
+    BATTLE_Options[ battle_Tag ].SpawnWeapons       = 0;
+    battlegibs=false;
+    BATTLE_ShowKillCount = true;
+}
+
+//******************************************************************************
+//
+// SetConfigDefaultValues ()
+//
+//******************************************************************************
+
+void SetConfigDefaultValues (void)
+{
+    //
+    //  no config file, so select default values
+    //
+    if (MousePresent)
+        mouseenabled = true;
+
+    joystickenabled = false;
+    joypadenabled   = false;
+    joystickport    = 0;
+    viewsize        = 7;
+    mouseadjustment = 5;
+    gammaindex      = 0;
+    gamestate.violence = 3;
+    passwordstring[0]=0x7d;
+    passwordstring[1]=0x7e;
+    passwordstring[2]=0x4a;
+    passwordstring[3]=0x2d;
+    passwordstring[4]=0x3b;
+    passwordstring[5]=0x6a;
+    passwordstring[6]=0x03;
+    passwordstring[7]=0x19;
+    passwordstring[8]=0x55;
+    passwordstring[9]=0x46;
+    passwordstring[10]=0x54;
+    passwordstring[11]=0x23;
+    passwordstring[12]=0x1c;
+}
+#endif
+
+//******************************************************************************
+//
+// DeleteSoundFile ()
+//
+//******************************************************************************
+void DeleteSoundFile ( void )
+{
+    char filename[ 128 ];
+
+    GetPathFromEnvironment( filename, ApogeePath, SoundName );
+    unlink (filename);          // Delete SOUND.ROT
+}
+
+//******************************************************************************
+//
+// ReadConfig ()
+//
+//******************************************************************************
+
+
+void ReadConfig (void)
+{
+    char filename[ 128 ];
+
+    GetPathFromEnvironment( filename, ApogeePath, SoundName );
+    SetSoundDefaultValues ();
+
+    if (access (filename, F_OK) == 0)
+    {
+        LoadScriptFile (filename);
+
+        if (ParseSoundFile () == false)
+        {
+            DeleteSoundFile();
+        }
+
+        Z_Free (scriptbuffer);
+    }
+#ifdef DOS
+    else if ( !SOUNDSETUP )
+    {
+        Error( "Could not find SOUND.ROT.  Please run SNDSETUP to configure "
+               "your sound hardware." );
+    }
+#endif
+
+
+#ifdef _ROTT_
+    ReadScores();
+
+    GetPathFromEnvironment( filename, ApogeePath, ConfigName );
+    SetConfigDefaultValues ();
+    if (access(filename,F_OK)==0)
+    {
+        LoadScriptFile(filename);
+
+        if (ParseConfigFile () == false)
+        {
+            unlink (filename);          // Delete CONFIG.ROT
+        }
+
+        Z_Free(scriptbuffer);
+    }
+
+    GetPathFromEnvironment( filename, ApogeePath, BattleName );
+    SetBattleDefaultValues ();
+    if (access(filename,F_OK)==0)
+    {
+        LoadScriptFile(filename);
+
+        if (ParseBattleFile() == false)
+        {
+            unlink (filename);          // Delete BATTLE.ROT
+        }
+
+        Z_Free(scriptbuffer);
+    }
+#endif
+    ConfigLoaded = true;
+}
+
+//******************************************************************************
+//
+// CheckVendor ()
+//
+//******************************************************************************
+
+#if (SHAREWARE==1)
+#define VENDORDOC ("VENDOR.DOC")
+#define VENDORLUMP ("VENDOR")
+#else
+#define VENDORDOC ("LICENSE.DOC")
+#define VENDORLUMP ("LICENSE")
+#endif
+
+void CheckVendor (void)
+{
+    boolean saveout=false;
+    int wadcrc;
+    int filecrc;
+    int size;
+    int lump;
+    byte * vendor;
+    char filename[ 128 ];
+
+    GetPathFromEnvironment( filename, ApogeePath, VENDORDOC );
+    if (access (filename, F_OK) == 0)
+    {
+        size = LoadFile(filename,(void **)&vendor);
+        filecrc = CalculateCRC (vendor, size);
+        SafeFree(vendor);
+        lump=W_GetNumForName(VENDORLUMP);
+        vendor = W_CacheLumpNum(lump,PU_CACHE, CvtNull, 1);
+        size=W_LumpLength(lump);
+        wadcrc = CalculateCRC (vendor, size);
+        if (wadcrc != filecrc)
+            saveout=true;
+    }
+    else
+        saveout=true;
+
+    if (saveout==true)
+    {
+        lump=W_GetNumForName(VENDORLUMP);
+        vendor = W_CacheLumpNum(lump,PU_CACHE, CvtNull, 1);
+        size = W_LumpLength(lump);
+        SaveFile (filename,vendor,size);
+    }
+}
+
+//******************************************************************************
+//
+// WriteParameter
+//
+//******************************************************************************
+
+void WriteParameter (int file, const char * s1, int val)
+{
+    char s[50];
+
+    // Write out Header
+    SafeWriteString (file, (char *)s1);
+
+    // Write out space character
+    strcpy (&s[0],(const char *)"  ");
+    SafeWriteString (file, &s[0]);
+
+    // Write out value
+    itoa(val,&s[0],10);
+    SafeWriteString (file, &s[0]);
+
+    // Write out EOL character
+    strcpy (&s[0],(const char *)"\n");
+    SafeWriteString (file, &s[0]);
+}
+
+
+//******************************************************************************
+//
+// WriteParameterHex
+//
+//******************************************************************************
+
+void WriteParameterHex (int file, const char * s1, int val)
+{
+    char s[50];
+
+    // Write out Header
+    SafeWriteString (file, (char *)s1);
+
+    // Write out space character
+    strcpy (&s[0],(const char *)"  $");
+    SafeWriteString (file, &s[0]);
+
+    // Write out value
+    itoa(val,&s[0],16);
+    SafeWriteString (file, &s[0]);
+
+    // Write out EOL character
+    strcpy (&s[0],(const char *)"\n");
+    SafeWriteString (file, &s[0]);
+}
+
+
+
+#ifdef _ROTT_
+
+//******************************************************************************
+//
+// WriteScores ()
+//
+//******************************************************************************
+
+void WriteScores (void)
+{
+    int file;
+    char filename[ 128 ];
+
+    GetPathFromEnvironment( filename, ApogeePath, ScoresName );
+    file=SafeOpenWrite( filename );
+    SafeWrite (file, &Scores, sizeof (Scores));
+    close(file);
+}
+
+
+//******************************************************************************
+//
+// WriteBattleConfig ()
+//
+//******************************************************************************
+
+void WriteBattleConfig
+(
+    void
+)
+
+{
+    int  file;
+    int  index;
+    char filename[ 128 ];
+    extern specials BattleSpecialsTimes;
+
+    // Write Battle File
+    GetPathFromEnvironment( filename, ApogeePath, BattleName );
+    file = open( filename, O_RDWR | O_TEXT | O_CREAT | O_TRUNC,
+                 S_IREAD | S_IWRITE );
+
+    if ( file == -1 )
+    {
+        Error( "Error opening %s: %s", filename, strerror( errno ) );
+    }
+
+    // Write out BATTLECONFIG header
+    SafeWriteString( file,
+                     ";Rise of the Triad Battle Configuration File\n"
+                     ";                  (c) 1995\n"
+                     ";\n"
+                     ";You may change these options at you own risk.  Using any values\n"
+                     ";other than the ones documented may make the game unplayable.\n"
+                     ";If this happens, you may delete this file (BATTLE.ROT) and ROTT\n"
+                     ";will recreate it with the default values selected.\n"
+                     ";\n"
+                     ";With that in mind, have fun!\n"
+                     ";\n"
+                     "\n" );
+
+    // Write out Version
+    WriteParameter( file, "Version                        ", ROTTVERSION );
+
+    // Write out BATTLE_ShowKillPics
+    SafeWriteString(file, "\n;\n");
+    WriteParameter( file, "; Yes                        - ", 1 );
+    WriteParameter( file, "; No                         - ", 0 );
+    WriteParameter( file, "ShowKillCount                  ", BATTLE_ShowKillCount );
+
+    // Write out specials' times
+    SafeWriteString(file, "\n;\n"
+                    "; These are the time in seconds of the various powerups.\n"
+                    "; You could modify these to give you infinite Mercury mode,\n"
+                    "; stronger vests, or to make them persistent.\n;\n" );
+
+    WriteParameter( file, "GodModeTime                ", BattleSpecialsTimes.GodModeTime );
+    WriteParameter( file, "DogModeTime                ", BattleSpecialsTimes.DogModeTime );
+    WriteParameter( file, "ShroomsModeTime            ", BattleSpecialsTimes.ShroomsModeTime );
+    WriteParameter( file, "ElastoModeTime             ", BattleSpecialsTimes.ElastoModeTime );
+    WriteParameter( file, "AsbestosVestTime           ", BattleSpecialsTimes.AsbestosVestTime );
+    WriteParameter( file, "BulletProofVestTime        ", BattleSpecialsTimes.BulletProofVestTime );
+    WriteParameter( file, "GasMaskTime                ", BattleSpecialsTimes.GasMaskTime );
+    WriteParameter( file, "MercuryModeTime            ", BattleSpecialsTimes.MercuryModeTime );
+    WriteParameter( file, "GodModeRespawnTime         ", BattleSpecialsTimes.GodModeRespawnTime );
+    WriteParameter( file, "DogModeRespawnTime         ", BattleSpecialsTimes.DogModeRespawnTime );
+    WriteParameter( file, "ShroomsModeRespawnTime     ", BattleSpecialsTimes.ShroomsModeRespawnTime );
+    WriteParameter( file, "ElastoModeRespawnTime      ", BattleSpecialsTimes.ElastoModeRespawnTime );
+    WriteParameter( file, "AsbestosVestRespawnTime    ", BattleSpecialsTimes.AsbestosVestRespawnTime );
+    WriteParameter( file, "BulletProofVestRespawnTime ", BattleSpecialsTimes.BulletProofVestRespawnTime );
+    WriteParameter( file, "GasMaskRespawnTime         ", BattleSpecialsTimes.GasMaskRespawnTime );
+    WriteParameter( file, "MercuryModeRespawnTime     ", BattleSpecialsTimes.MercuryModeRespawnTime );
+
+    // Write out battlegibs
+    SafeWriteString(file, "\n;\n");
+    WriteParameter( file, "; Yes                        - ", 1 );
+    WriteParameter( file, "; No                         - ", 0 );
+    WriteParameter( file, "EKG                            ", battlegibs );
+
+    // Describe options
+
+    // Write out Gravity
+    SafeWriteString(file, "\n"
+                    ";\n"
+                    "; Here is a description of the possible values for"
+                    " each option:\n"
+                    ";\n"
+                    "; Gravity options:\n" );
+    WriteParameter( file, ";    Low Gravity             - ", LOW_GRAVITY );
+    WriteParameter( file, ";    Normal Gravity          - ", NORMAL_GRAVITY );
+    WriteParameter( file, ";    High Gravity            - ", HIGH_GRAVITY );
+
+    // Write out Speed
+    SafeWriteString(file, ";\n"
+                    "; Speed options:\n" );
+    WriteParameter( file, ";    Normal Speed            - ", bo_normal_speed );
+    WriteParameter( file, ";    Fast Speed              - ", bo_fast_speed );
+
+    // Write out Ammo
+    SafeWriteString(file, ";\n"
+                    "; Ammo options:\n" );
+    WriteParameter( file, ";    One Shot                - ", bo_one_shot );
+    WriteParameter( file, ";    Normal Shots            - ", bo_normal_shots );
+    WriteParameter( file, ";    Infinite Shots          - ", bo_infinite_shots );
+
+    // Write out Hit Points
+    SafeWriteString(file, ";\n"
+                    "; Hitpoint options:\n" );
+    WriteParameter( file, ";    Character Hitpoints     - ", bo_character_hitpoints );
+    WriteParameter( file, ";       1 Hitpoint           - ", 1 );
+    WriteParameter( file, ";      25 Hitpoints          - ", 25 );
+    WriteParameter( file, ";     100 Hitpoints          - ", 100 );
+    WriteParameter( file, ";     500 Hitpoints          - ", 500 );
+    WriteParameter( file, ";     250 Hitpoints          - ", 250 );
+    WriteParameter( file, ";    4000 Hitpoints          - ", 4000 );
+
+    // Write out Danger Spawning
+    SafeWriteString(file, ";\n"
+                    "; SpawnDangers options:\n"
+                    ";    Spawn Dangers           -   1\n"
+                    ";    Don't Spawn Dangers     -   0\n" );
+
+    // Write out Health Spawning
+    SafeWriteString(file, ";\n"
+                    "; SpawnHealth options:\n"
+                    ";    Spawn Health            -   1\n"
+                    ";    Don't Spawn Health      -   0\n" );
+
+    // Write out Mine Spawning
+    SafeWriteString(file, ";\n"
+                    "; SpawnMines options:\n"
+                    ";    Spawn Mines             -   1\n"
+                    ";    Don't Spawn Mines       -   0\n" );
+
+    // Write out Weapon Spawning
+    SafeWriteString(file, ";\n"
+                    "; SpawnWeapons options:\n"
+                    ";    Spawn Weapons           -   1\n"
+                    ";    Don't Spawn Weapons     -   0\n" );
+
+    // Write out Random Weapons
+    SafeWriteString(file, ";\n"
+                    "; RandomWeapons options:\n"
+                    ";    Randomize Weapons       -   1\n"
+                    ";    Don't Randomize Weapons -   0\n" );
+
+    // Write out Weapon Persistence
+    SafeWriteString(file, ";\n"
+                    "; WeaponPersistence options:\n"
+                    ";    Weapons Persist         -   1\n"
+                    ";    Weapons don't Persist   -   0\n" );
+
+    // Write out Friendly Fire
+    SafeWriteString(file, ";\n"
+                    "; FriendlyFire options:\n"
+                    ";    Penalize Friendly Fire  -   1\n"
+                    ";    No penalty              -   0\n" );
+
+    // Write out Respawn Items
+    SafeWriteString(file, ";\n"
+                    "; RespawnItems options:\n"
+                    ";    Respawn Items           -   1\n"
+                    ";    Don't Respawn Items     -   0\n" );
+
+    // Write out Light Level
+    SafeWriteString(file, ";\n"
+                    "; LightLevel options:\n" );
+    WriteParameter( file, ";    Dark                    - ", bo_light_dark );
+    WriteParameter( file, ";    Normal Light Levels     - ", bo_light_normal );
+    WriteParameter( file, ";    Bright                  - ", bo_light_bright );
+    WriteParameter( file, ";    Fog                     - ", bo_light_fog );
+    WriteParameter( file, ";    Periodic light          - ", bo_light_periodic );
+    WriteParameter( file, ";    Lightning               - ", bo_light_lightning );
+
+    // Write out Point Goal
+    SafeWriteString(file, ";\n"
+                    "; PointGoal options:\n" );
+    WriteParameter( file, ";           1 Point          - ", 1 );
+    WriteParameter( file, ";           5 Points         - ", 5 );
+    WriteParameter( file, ";          11 Points         - ", 11 );
+    WriteParameter( file, ";          21 Points         - ", 21 );
+    WriteParameter( file, ";          50 Points         - ", 50 );
+    WriteParameter( file, ";         100 Points         - ", 100 );
+    WriteParameter( file, ";      Random Points         - ", bo_kills_random );
+    WriteParameter( file, ";       Blind Points         - ", bo_kills_blind );
+    WriteParameter( file, ";    Infinite Points         - ", bo_kills_infinite );
+
+    // Write out Danger Damage
+    SafeWriteString(file, ";\n"
+                    "; DangerDamage options:\n" );
+    WriteParameter( file, ";    Normal Damage           - ", bo_danger_normal );
+    WriteParameter( file, ";    Low Damage              - ", bo_danger_low );
+    WriteParameter( file, ";    Kill                    - ", bo_danger_kill );
+
+    // Write out TimeLimit
+    SafeWriteString(file, ";\n"
+                    "; TimeLimit options:\n" );
+    WriteParameter( file, ";     1 minute               - ", 1 );
+    WriteParameter( file, ";     2 minute               - ", 2 );
+    WriteParameter( file, ";     5 minutes              - ", 5 );
+    WriteParameter( file, ";    10 minutes              - ", 10 );
+    WriteParameter( file, ";    21 minutes              - ", 21 );
+    WriteParameter( file, ";    30 minutes              - ", 30 );
+    WriteParameter( file, ";    99 minutes              - ", 99 );
+    WriteParameter( file, ";    No limit                - ", bo_time_infinite );
+
+    // Write out RespawnTime
+    SafeWriteString(file, ";\n"
+                    "; RespawnTime options:\n" );
+    WriteParameter( file, ";     1 second               - ", 1 );
+    WriteParameter( file, ";     1 minute               - ", 60 );
+    WriteParameter( file, ";     2 minutes              - ", 120 );
+    WriteParameter( file, ";       normal               - ", bo_normal_respawn_time );
+
+    for( index = battle_Normal; index < battle_NumBattleModes; index++ )
+    {
+        SafeWriteString(file, "\n;\n");
+        switch( index )
+        {
+        case battle_Normal :
+            SafeWriteString( file, "; Standard battle options\n;\n" );
+            break;
+
+        case battle_ScoreMore :
+            SafeWriteString( file, "; Score More battle options\n;\n" );
+            break;
+
+        case battle_Collector :
+            SafeWriteString( file, "; Collector battle options\n;\n" );
+            break;
+
+        case battle_Scavenger :
+            SafeWriteString( file, "; Scavenger battle options\n;\n" );
+            break;
+
+        case battle_Hunter :
+            SafeWriteString( file, "; Hunter battle options\n;\n" );
+            break;
+
+        case battle_Tag :
+            SafeWriteString( file, "; Tag battle options\n;\n" );
+            break;
+
+        case battle_Eluder :
+            SafeWriteString( file, "; Eluder battle options\n;\n" );
+            break;
+
+        case battle_Deluder :
+            SafeWriteString( file, "; Deluder battle options\n;\n" );
+            break;
+
+        case battle_CaptureTheTriad :
+            SafeWriteString( file, "; Capture the Triad battle options\n;\n" );
+            break;
+        }
+
+        // Write out Gravity
+        WriteParameter( file, "Gravity          ",
+                        BATTLE_Options[ index ].Gravity );
+
+        // Write out Speed
+        WriteParameter( file, "Speed            ",
+                        BATTLE_Options[ index ].Speed );
+
+        if ( ( index != battle_Collector ) && ( index != battle_Tag ) &&
+                ( index != battle_Eluder ) )
+        {
+            // Write out Ammo
+            WriteParameter( file, "Ammo             ",
+                            BATTLE_Options[ index ].Ammo );
+        }
+
+        if ( index != battle_Eluder )
+        {
+            // Write out Hit Points
+            WriteParameter( file, "Hitpoints        ",
+                            BATTLE_Options[ index ].HitPoints );
+        }
+
+        // Write out Danger Spawning
+        WriteParameter( file, "SpawnDangers     ",
+                        BATTLE_Options[ index ].SpawnDangers );
+
+        if ( index != battle_Eluder )
+        {
+            // Write out Health Spawning
+            WriteParameter( file, "SpawnHealth      ",
+                            BATTLE_Options[ index ].SpawnHealth );
+
+            // Write out Mine Spawning
+            WriteParameter( file, "SpawnMines       ",
+                            BATTLE_Options[ index ].SpawnMines );
+        }
+
+        if ( ( index != battle_Collector ) && ( index != battle_Tag ) &&
+                ( index != battle_Eluder ) )
+        {
+            // Write out Weapon Spawning
+            WriteParameter( file, "SpawnWeapons     ",
+                            BATTLE_Options[ index ].SpawnWeapons );
+
+            // Write out Random Weapons
+            WriteParameter( file, "RandomWeapons    ",
+                            BATTLE_Options[ index ].RandomWeapons );
+
+            // Write out Weapon Persistence
+            WriteParameter( file, "WeaponPersistence",
+                            BATTLE_Options[ index ].WeaponPersistence );
+        }
+
+        if ( ( index == battle_Normal ) || ( index == battle_ScoreMore ) ||
+                ( index == battle_Hunter ) || ( index == battle_Tag ) )
+        {
+            // Write out Friendly Fire
+            WriteParameter( file, "FriendlyFire     ",
+                            BATTLE_Options[ index ].FriendlyFire );
+        }
+
+        if ( index != battle_Eluder )
+        {
+            // Write out Respawn Items
+            WriteParameter( file, "RespawnItems     ",
+                            BATTLE_Options[ index ].RespawnItems );
+        }
+
+        // Write out Light Level
+        WriteParameter( file, "LightLevel       ",
+                        BATTLE_Options[ index ].LightLevel );
+
+        if ( ( index != battle_Collector ) && ( index != battle_Scavenger ) )
+        {
+            // Write out Point Goal
+            WriteParameter( file, "PointGoal        ",
+                            BATTLE_Options[ index ].Kills );
+        }
+
+        if ( index != battle_Eluder )
+        {
+            // Write out Danger Damage
+            WriteParameter( file, "DangerDamage     ",
+                            BATTLE_Options[ index ].DangerDamage );
+        }
+
+        // Write out TimeLimit
+        WriteParameter( file, "TimeLimit        ",
+                        BATTLE_Options[ index ].TimeLimit );
+
+        // Write out RespawnTime
+        WriteParameter( file, "RespawnTime      ",
+                        BATTLE_Options[ index ].RespawnTime );
+    }
+
+    close( file );
+}
+
+#endif
+
+//******************************************************************************
+//
+// WriteSoundConfig ()
+//
+//******************************************************************************
+
+void WriteSoundConfig
+(
+    void
+)
+
+{
+    int file;
+    char filename[ 128 ];
+
+    if ( !WriteSoundFile )
+    {
+        return;
+    }
+
+    GetPathFromEnvironment( filename, ApogeePath, SoundName );
+    file = open ( filename, O_RDWR | O_TEXT | O_CREAT | O_TRUNC,
+                  S_IREAD | S_IWRITE);
+
+    if (file == -1)
+        Error ("Error opening %s: %s", filename, strerror(errno));
+
+    // Write out ROTTSOUND header
+
+    SafeWriteString (file, ";Rise of the Triad Sound File\n");
+    SafeWriteString (file, ";                  (c) 1995\n\n");
+
+    // Write out Version
+
+    WriteParameter(file,"Version          ",ROTTVERSION);
+
+    // Write out Music Mode
+
+    SafeWriteString(file,"\n;\n");
+    SafeWriteString(file,"; Music Modes\n");
+    SafeWriteString(file,"; 0  -  Off\n");
+#ifdef DOS
+    SafeWriteString(file,"; 1  -  UltraSound\n");
+    SafeWriteString(file,"; 2  -  Sound Blaster\n");
+    SafeWriteString(file,"; 3  -  Sound Man 16\n");
+    SafeWriteString(file,"; 4  -  Pro Audio Spectrum\n");
+    SafeWriteString(file,"; 5  -  Awe32\n");
+    SafeWriteString(file,"; 6  -  SoundScape\n");
+    SafeWriteString(file,"; 7  -  Wave Blaster\n");
+    SafeWriteString(file,"; 8  -  General Midi\n");
+    SafeWriteString(file,"; 9  -  Sound Canvas\n");
+    SafeWriteString(file,"; 10 -  Adlib\n");
+#else
+    SafeWriteString(file,"; 6  -  On\n");
+#endif
+    WriteParameter(file,"MusicMode        ",MusicMode);
+
+    // Write out FX Mode
+
+    SafeWriteString(file,"\n;\n");
+    SafeWriteString(file,"; FX Modes\n");
+    SafeWriteString(file,"; 0  -  Off\n");
+#ifdef DOS
+    SafeWriteString(file,"; 1  -  UltraSound\n");
+    SafeWriteString(file,"; 2  -  Sound Blaster\n");
+    SafeWriteString(file,"; 3  -  Sound Man 16\n");
+    SafeWriteString(file,"; 4  -  Pro Audio Spectrum\n");
+    SafeWriteString(file,"; 5  -  Awe32\n");
+    SafeWriteString(file,"; 6  -  SoundScape\n");
+    SafeWriteString(file,"; 7  -  Adlib\n");
+    SafeWriteString(file,"; 8  -  Disney Sound Source\n");
+    SafeWriteString(file,"; 9  -  Tandy Sound Source\n");
+    SafeWriteString(file,"; 10 -  PC Speaker\n");
+#else
+    SafeWriteString(file,"; 6  -  On\n");
+#endif
+    WriteParameter(file,"FXMode           ",FXMode);
+
+    // Write in Music Volume
+
+    SafeWriteString(file,"\n;\n");
+    SafeWriteString(file,"; Music Volume\n");
+    SafeWriteString(file,"; (low) 0 - 255 (high)\n");
+    WriteParameter (file, "MusicVolume    ", MUvolume);
+
+    // Write in FX Volume
+
+    SafeWriteString(file,"\n;\n");
+    SafeWriteString(file,"; FX Volume\n");
+    SafeWriteString(file,"; (low) 0 - 255 (high)\n");
+    WriteParameter (file, "FXVolume       ", FXvolume);
+
+    // Write out numvoices
+
+    SafeWriteString(file,"\n;\n");
+    SafeWriteString(file,"; Number of Voices\n");
+    SafeWriteString(file,"; 1 - 8\n");
+    WriteParameter(file,"NumVoices        ",NumVoices);
+
+    // Write out numchannels
+
+    SafeWriteString(file,"\n;\n");
+    SafeWriteString(file,"; Stereo or Mono\n");
+    SafeWriteString(file,"; 1 - Mono\n");
+    SafeWriteString(file,"; 2 - Stereo\n");
+    WriteParameter(file,"NumChannels      ",NumChannels);
+
+    // Write out numbits
+
+    SafeWriteString(file,"\n;\n");
+    SafeWriteString(file,"; Resolution\n");
+    SafeWriteString(file,"; 8 bit\n");
+    SafeWriteString(file,"; 16 bit\n");
+    WriteParameter(file,"NumBits          ",NumBits);
+
+#ifdef DOS
+    // Write out Midi Address
+
+    SafeWriteString(file,"\n;\n");
+    SafeWriteString(file,"; Midi Addresses\n");
+    SafeWriteString(file,"; $300\n");
+    SafeWriteString(file,"; $310\n");
+    SafeWriteString(file,"; $320\n");
+    SafeWriteString(file,"; $330\n");
+    SafeWriteString(file,"; $340\n");
+    SafeWriteString(file,"; $350\n");
+    SafeWriteString(file,"; $360\n");
+    SafeWriteString(file,"; $370\n");
+    SafeWriteString(file,"; $380\n");
+    WriteParameterHex(file,"MidiAddress      ",MidiAddress);
+#endif
+
+    // Write out stereo reversal
+
+    SafeWriteString(file,"\n;\n");
+    SafeWriteString(file,"; ReverseStereo\n");
+    SafeWriteString(file,"; 0 no reversal\n");
+    SafeWriteString(file,"; 1 reverse stereo\n");
+    WriteParameter (file,"StereoReverse      ",stereoreversed);
+
+#ifdef DOS
+    // Write out Sound Blaster info
+
+    SafeWriteString(file,"\n;\n");
+    SafeWriteString(file,"; Sound Blaster Settings\n");
+    WriteParameter(file, "SBType           ", SBSettings.Type );
+    WriteParameterHex(file, "SBPort           ", SBSettings.Address );
+    WriteParameter(file, "SBIrq            ", SBSettings.Interrupt );
+    WriteParameter(file, "SBDma8           ", SBSettings.Dma8 );
+    WriteParameter(file, "SBDma16          ", SBSettings.Dma16 );
+    WriteParameterHex(file, "SBMidi           ", SBSettings.Midi );
+    WriteParameterHex(file, "SBEmu            ", SBSettings.Emu );
+#endif
+
+    close (file);
+}
+
+
+//******************************************************************************
+//
+// WriteConfig ()
+//
+//******************************************************************************
+
+void WriteConfig (void)
+{
+    int file;
+    char filename[ 128 ];
+    char passwordtemp[50];
+    static int inconfig = 0;
+
+    if (inconfig > 0)
+        return;
+
+    inconfig++ ;
+
+    if ( !ConfigLoaded )
+    {
+        return;
+    }
+
+    // Write Sound File
+    WriteSoundConfig();
+
+    // Write Config, Battle and Score files
+#ifdef _ROTT_
+    WriteScores();
+    WriteBattleConfig();
+
+    GetPathFromEnvironment( filename, ApogeePath, ConfigName );
+    file = open( filename,O_RDWR | O_TEXT | O_CREAT | O_TRUNC
+                 , S_IREAD | S_IWRITE);
+
+    if (file == -1)
+        Error ("Error opening %s: %s",filename,strerror(errno));
+
+    // Write out ROTTCONFIG header
+
+    SafeWriteString (file, ";Rise of the Triad Configuration File\n");
+    SafeWriteString (file, ";                  (c) 1995\n\n");
+
+    // Write out Version
+
+    WriteParameter(file,"Version          ",ROTTVERSION);
+
+    //Write out AllowBlitzguardMoreMissileWeps
+
+    SafeWriteString(file,"\n;\n");
+    SafeWriteString(file, "; 1 - Allows Blitzguards to have Random Missile weapons\n");
+    SafeWriteString(file, "; 0 - Disallows the above (ROTT Default)\n");
+    WriteParameter(file, "AllowBlitzguardMoreMissileWeps    ", allowBlitzMoreMissileWeps);
+
+    //Write out enableAmmoPickups
+
+    SafeWriteString(file,"\n;\n");
+    SafeWriteString(file, "; 1 - Allows players to refill their missile weapons by running over one a matching one on the ground\n");
+    SafeWriteString(file, "; 0 - Disables the above (ROTT default)\n");
+    WriteParameter(file, "EnableAmmoPickups     ", enableAmmoPickups);
+
+    //Write out autoAim
+
+    SafeWriteString(file, "\n;\n");
+    SafeWriteString(file, "; 1 - Bullet weapons will automatically target enemies. (ROTT default)\n");
+    SafeWriteString(file, "; 0 - Disables the above.\n");
+    WriteParameter(file, "AutoAim   ", autoAim);
+
+    //Write out autoAimMissileWeps
+
+    SafeWriteString(file, "\n;\n");
+    SafeWriteString(file, "; 1 - Missile weapons will be automatically aimed at targets like bullet weapons.\n");
+    SafeWriteString(file, "; 0 - Missile weapons are not automatically aimed at targets. (ROTT default)\n");
+    WriteParameter(file, "AutoAimMissileWeps    ", autoAimMissileWeps);
+
+    // Write out MouseEnabled
+
+    SafeWriteString(file,"\n;\n");
+    SafeWriteString(file,"; 1 - Mouse Enabled\n");
+    SafeWriteString(file,"; 0 - Mouse Disabled\n");
+    WriteParameter(file,"MouseEnabled     ",mouseenabled);
+
+    // Write out UseMouseLook
+    SafeWriteString(file,"\n;\n");
+    SafeWriteString(file,"; 1 - UseMouseLook Enabled\n");
+    SafeWriteString(file,"; 0 - UseMouseLook Disabled\n");
+    WriteParameter(file,"UseMouseLook     ",usemouselook);
+
+    // Write out InverseMouse
+    SafeWriteString(file,"\n;\n");
+    SafeWriteString(file,"; 1 - Normal Mouse Enabled\n");
+    SafeWriteString(file,"; -1 - Inverse Mouse Enabled\n");
+    WriteParameter(file,"InverseMouse     ",inverse_mouse);
+
+    // Write out UseJump
+    SafeWriteString(file,"\n;\n");
+    SafeWriteString(file,"; 1 - usejump Enabled\n");
+    SafeWriteString(file,"; 0 - usejump Disabled\n");
+    WriteParameter(file,"UseJump          ",usejump);
+
+    // Write out CrossHair
+    SafeWriteString(file,"\n;\n");
+    SafeWriteString(file,"; 1 - CrossHair Enabled\n");
+    SafeWriteString(file,"; 0 - CrossHair Disabled\n");
+    WriteParameter(file,"CrossHair        ", iG_aimCross);
+
+    // Write out JoystickEnabled
+
+    SafeWriteString(file,"\n;\n");
+    SafeWriteString(file,"; 1 - Joystick Enabled\n");
+    SafeWriteString(file,"; 0 - Joystick Disabled\n");
+    WriteParameter(file,"JoystickEnabled  ",joystickenabled);
+
+    // Write out JoypadEnabled
+
+    SafeWriteString(file,"\n;\n");
+    SafeWriteString(file,"; 1 - Joypad Enabled\n");
+    SafeWriteString(file,"; 0 - Joypad Disabled\n");
+    WriteParameter(file,"JoypadEnabled    ",joypadenabled);
+
+    // Write out JoystickPort
+
+    SafeWriteString(file,"\n;\n");
+    SafeWriteString(file,"; 0 - Use Joystick Port 1\n");
+    SafeWriteString(file,"; 1 - Use Joystick Port 2\n");
+    WriteParameter(file,"JoystickPort     ",joystickport);
+
+    // Write out fullscreen
+    SafeWriteString(file,"\n;\n");
+    SafeWriteString(file,"; 0 - Start in windowed mode\n");
+    SafeWriteString(file,"; 1 - Start in fullscreen mode\n");
+    WriteParameter(file,"FullScreen       ",sdl_fullscreen);
+
+    // Write out resolution
+    SafeWriteString(file,"\n;\n");
+    SafeWriteString(file,"; Screen Resolution, supported resolutions: \n");
+    SafeWriteString(file,"; 320x200, 640x480 and 800x600\n");
+    WriteParameter(file,"ScreenWidth      ",iGLOBAL_SCREENWIDTH);
+    WriteParameter(file,"ScreenHeight     ",iGLOBAL_SCREENHEIGHT);
+
+    // Write out ViewSize
+
+    SafeWriteString(file,"\n;\n");
+    SafeWriteString(file,"; Size of View port.\n");
+    SafeWriteString(file,"; (smallest) 0 - 10 (largest)\n");
+    WriteParameter(file,"ViewSize         ",viewsize);
+
+    // Write out WEAPONSCALE  bna added
+
+    SafeWriteString(file,"\n;\n");
+    SafeWriteString(file,"; Size of Weaponscale.\n");
+    SafeWriteString(file,"; (smallest) 150 - 600 (largest)\n");
+    G_weaponscale = (weaponscale * 168 )/65536;
+
+    if ((G_weaponscale <150)||(G_weaponscale>600)) {
+        if (iGLOBAL_SCREENWIDTH == 320) {
+            G_weaponscale=168;
+        } else if (iGLOBAL_SCREENWIDTH == 640) {
+            G_weaponscale=299;
+        } else if (iGLOBAL_SCREENWIDTH == 800) {
+            G_weaponscale=376;
+        }
+    }
+    WriteParameter(file,"Weaponscale         ",G_weaponscale);
+
+
+    // Write out MouseAdjustment
+
+    SafeWriteString(file,"\n;\n");
+    SafeWriteString(file,"; Sensitivity of Mouse\n");
+    SafeWriteString(file,"; (lowest) 0 - 11 (highest)\n");
+    WriteParameter(file,"MouseAdjustment  ",mouseadjustment);
+
+    // Write out threshold
+
+    SafeWriteString(file,"\n;\n");
+    SafeWriteString(file,"; Threshold of Mouse and Joystick\n");
+    SafeWriteString(file,"; (smallest) 1 - 15 (largest)\n");
+    WriteParameter(file,"Threshold        ",threshold);
+
+    // Write in Cyberman Enabled
+
+//   SafeWriteString(file,"\n;\n");
+//   SafeWriteString(file,"; 1 - Cyberman Enabled\n");
+//   SafeWriteString(file,"; 0 - Cyberman Disabled\n");
+//   WriteParameter(file,"CybermanEnabled  ",cybermanenabled);
+
+    // Write in Spaceball Enabled
+
+//   SafeWriteString(file,"\n;\n");
+//   SafeWriteString(file,"; 1 - Spaceball Enabled\n");
+//   SafeWriteString(file,"; 0 - Spaceball Disabled\n");
+//   WriteParameter(file,"SpaceballEnabled ",spaceballenabled);
+
+    // Write in Auto Detail
+
+    SafeWriteString(file,"\n;\n");
+    SafeWriteString(file,"; 1 - Auto Detail on\n");
+    SafeWriteString(file,"; 0 - Auto Detail off\n");
+    WriteParameter (file,"AutoDetail       ", AutoDetailOn);
+
+    // Write in Light Dim
+
+    SafeWriteString(file,"\n;\n");
+    SafeWriteString(file,"; 1 - Light Diminishing on\n");
+    SafeWriteString(file,"; 0 - Light Diminishing off\n");
+    WriteParameter (file,"LightDim         ", fulllight);
+
+    // Write in Bobbin' On
+
+    SafeWriteString(file,"\n;\n");
+    SafeWriteString(file,"; 1 - Bobbing on\n");
+    SafeWriteString(file,"; 0 - Bobbing off\n");
+    WriteParameter (file,"BobbingOn        ", BobbinOn);
+
+    // Write in Double Click Speed
+
+    SafeWriteString(file,"\n;\n");
+    SafeWriteString(file,"; (slowest) 50 - 5 (fastest)\n");
+    WriteParameter (file,"DoubleClickSpeed ", DoubleClickSpeed);
+
+    // Write in Menu Flip Speed
+
+    SafeWriteString(file,"\n;\n");
+    SafeWriteString(file,"; Menu Flip Speed\n");
+    SafeWriteString(file,"; (slowest) 100 - 5 (fastest)\n");
+    WriteParameter (file,"MenuFlipSpeed    ", Menuflipspeed);
+
+    // Write in Detail Level
+
+    SafeWriteString(file,"\n;\n");
+    SafeWriteString(file,"; 0 - Detail Level Low\n");
+    SafeWriteString(file,"; 1 - Detail Level Medium\n");
+    SafeWriteString(file,"; 2 - Detail Level High\n");
+    WriteParameter (file,"DetailLevel      ", DetailLevel);
+
+    // Write in Floor and Ceiling
+
+    SafeWriteString(file,"\n;\n");
+    SafeWriteString(file,"; 1 - Floor and Ceiling on\n");
+    SafeWriteString(file,"; 0 - Floor and Ceiling off\n");
+    WriteParameter (file,"FloorCeiling     ", fandc);
+
+    // Write in DisableMessages
+
+    SafeWriteString(file,"\n;\n");
+    SafeWriteString(file,"; 1 - Messages on\n");
+    SafeWriteString(file,"; 0 - Messages off\n");
+    WriteParameter (file,"Messages         ", MessagesEnabled );
+
+    // Write in AutoRun
+
+    SafeWriteString(file,"\n;\n");
+    SafeWriteString(file,"; 1 - AutoRun on\n");
+    SafeWriteString(file,"; 0 - AutoRun off\n");
+    WriteParameter (file,"AutoRun          ", gamestate.autorun );
+
+    // Write in GammaIndex
+
+    SafeWriteString(file,"\n;\n");
+    SafeWriteString(file,"; 0 - Gamma Correction level 1\n");
+    SafeWriteString(file,"; 1 - Gamma Correction level 2\n");
+    SafeWriteString(file,"; 2 - Gamma Correction level 3\n");
+    SafeWriteString(file,"; 3 - Gamma Correction level 4\n");
+    SafeWriteString(file,"; 4 - Gamma Correction level 5\n");
+    WriteParameter (file,"GammaIndex       ", gammaindex);
+
+    // Write out screen saver time
+    SafeWriteString(file,"\n;\n");
+    SafeWriteString(file,"; Minutes before screen blanking\n");
+    WriteParameter (file,"BlankTime        ", blanktime/(VBLCOUNTER*60));
+
+
+    // Write out keys
+
+    SafeWriteString(file,"\n;\n");
+    SafeWriteString(file,"; Scan codes for keyboard buttons\n");
+    WriteParameter (file,"Fire             ", buttonscan[0]);
+    WriteParameter (file,"Strafe           ", buttonscan[1]);
+    WriteParameter (file,"Run              ", buttonscan[2]);
+    WriteParameter (file,"Use              ", buttonscan[3]);
+    WriteParameter (file,"LookUp           ", buttonscan[4]);
+    WriteParameter (file,"LookDn           ", buttonscan[5]);
+    WriteParameter (file,"Swap             ", buttonscan[6]);
+    WriteParameter (file,"Drop             ", buttonscan[7]);
+    WriteParameter (file,"TargetUp         ", buttonscan[8]);
+    WriteParameter (file,"TargetDn         ", buttonscan[9]);
+    WriteParameter (file,"SelPistol        ", buttonscan[10]);
+    WriteParameter (file,"SelDualPistol    ", buttonscan[11]);
+    WriteParameter (file,"SelMP40          ", buttonscan[12]);
+    WriteParameter (file,"SelMissile       ", buttonscan[13]);
+    WriteParameter (file,"AutoRun          ", buttonscan[14]);
+    WriteParameter (file,"LiveRemRid       ", buttonscan[15]);
+    WriteParameter (file,"StrafeLeft       ", buttonscan[16]);
+    WriteParameter (file,"StrafeRight      ", buttonscan[17]);
+    WriteParameter (file,"VolteFace        ", buttonscan[18]);
+    WriteParameter (file,"Aim              ", buttonscan[19]);
+    WriteParameter (file,"Forward          ", buttonscan[20]);
+    WriteParameter (file,"Right            ", buttonscan[21]);
+    WriteParameter (file,"Backward         ", buttonscan[22]);
+    WriteParameter (file,"Left             ", buttonscan[23]);
+    WriteParameter (file,"Map              ", buttonscan[24]);
+    WriteParameter (file,"SendMessage      ", buttonscan[25]);
+    WriteParameter (file,"DirectMessage    ", buttonscan[26]);
+
+    SafeWriteString(file,"\n;\n");
+    SafeWriteString(file,"; Mouse buttons\n");
+
+    WriteParameter (file,"MouseButton0     ", buttonmouse[0]);
+    WriteParameter (file,"MouseButton1     ", buttonmouse[1]);
+    WriteParameter (file,"MouseButton2     ", buttonmouse[2]);
+    WriteParameter (file,"DblClickB0       ", buttonmouse[3]);
+    WriteParameter (file,"DblClickB1       ", buttonmouse[4]);
+    WriteParameter (file,"DblClickB2       ", buttonmouse[5]);
+
+    SafeWriteString(file,"\n;\n");
+    SafeWriteString(file,"; Joystick buttons\n");
+
+    WriteParameter (file,"JoyButton0       ", buttonjoy[0]);
+    WriteParameter (file,"JoyButton1       ", buttonjoy[1]);
+    WriteParameter (file,"JoyButton2       ", buttonjoy[2]);
+    WriteParameter (file,"JoyButton3       ", buttonjoy[3]);
+    WriteParameter (file,"DblClickJB0      ", buttonjoy[4]);
+    WriteParameter (file,"DblClickJB1      ", buttonjoy[5]);
+    WriteParameter (file,"DblClickJB2      ", buttonjoy[6]);
+    WriteParameter (file,"DblClickJB3      ", buttonjoy[7]);
+
+    SafeWriteString(file,"\n;\n");
+    SafeWriteString(file,"; Joystick calibration coordinates\n");
+
+    WriteParameter (file,"JoyMaxX          ", joyxmax);
+    WriteParameter (file,"JoyMaxY          ", joyymax);
+    WriteParameter (file,"JoyMinX          ", joyxmin);
+    WriteParameter (file,"JoyMinY          ", joyymin);
+
+    // Write out DefaultDifficulty
+    SafeWriteString(file,"\n;\n");
+    WriteParameter(file,"; Easy             - ", gd_baby );
+    WriteParameter(file,"; Medium           - ", gd_easy );
+    WriteParameter(file,"; Hard             - ", gd_medium );
+    WriteParameter(file,"; Crezzy           - ", gd_hard );
+    WriteParameter(file,"DefaultDifficulty    ", DefaultDifficulty );
+
+    // Write out DefaultPlayerCharacter
+    SafeWriteString(file,"\n;\n");
+    WriteParameter(file,"; Taradino Cassatt   - ", 0 );
+    WriteParameter(file,"; Thi Barrett        - ", 1 );
+    WriteParameter(file,"; Doug Wendt         - ", 2 );
+    WriteParameter(file,"; Lorelei Ni         - ", 3 );
+    WriteParameter(file,"; Ian Paul Freeley   - ", 4 );
+    WriteParameter(file,"DefaultPlayerCharacter ", DefaultPlayerCharacter );
+
+    // Write out DefaultPlayerColor
+    SafeWriteString(file,"\n;\n");
+    WriteParameter(file,"; Gray             - ", 0 );
+    WriteParameter(file,"; Brown            - ", 1 );
+    WriteParameter(file,"; Black            - ", 2 );
+    WriteParameter(file,"; Tan              - ", 3 );
+    WriteParameter(file,"; Red              - ", 4 );
+    WriteParameter(file,"; Olive            - ", 5 );
+    WriteParameter(file,"; Blue             - ", 6 );
+    WriteParameter(file,"; White            - ", 7 );
+    WriteParameter(file,"; Green            - ", 8 );
+    WriteParameter(file,"; Purple           - ", 9 );
+    WriteParameter(file,"; Orange           - ", 10 );
+    WriteParameter(file,"DefaultPlayerColor   ", DefaultPlayerColor );
+
+    // Writeout password Password string
+    SafeWriteString(file,"\n;\nSecretPassword         ");
+    memset(passwordtemp,0,sizeof(passwordtemp));
+    ConvertPasswordStringToString ( &passwordtemp[0] );
+    SafeWriteString(file,&passwordtemp[0]);
+
+    close (file);
+#endif
+    inconfig--;
+}
+
+#ifdef _ROTT_
+
+
+//****************************************************************************
+//
+// GetAlternatePath ()
+//
+//****************************************************************************
+
+void GetAlternatePath (char * tokenstr, AlternateInformation *info)
+{
+    strcpy (&info->path[0], ".\0");
+    GetToken (true);
+    if (!stricmp (token, tokenstr))
+    {
+        GetTokenEOL (false);
+        memset (&info->path[0], 0, sizeof (info->path));
+        strcpy (&info->path[0], &name[0]);
+    }
+}
+
+
+//****************************************************************************
+//
+// GetAlternateFile ()
+//
+//****************************************************************************
+
+void GetAlternateFile (char * tokenstr, AlternateInformation *info)
+{
+    // Read in remote sound file
+    //
+    strcpy (&info->file[0], "foo.foo\0");
+    GetToken (true);
+    if (!stricmp (token, tokenstr))
+    {
+        if (TokenAvailable()==true)
+        {
+            GetToken (false);
+            if (stricmp (token, "~"))
+            {
+#if (SHAREWARE == 0)
+                info->avail = true;
+                memset (&info->file[0], 0, sizeof (info->file));
+                strcpy (&info->file[0], &token[0]);
+#else
+                printf("Alternate file %s ignored.\n",token);
+                memset (&info->file[0], 0, sizeof (info->file));
+#endif
+            }
+        }
+    }
+}
+
+
+//****************************************************************************
+//
+// ReadSETUPFiles ()
+//
+//****************************************************************************
+
+void ReadSETUPFiles (void)
+{
+    char filename[ 128 ];
+    int i;
+
+    RemoteSounds.avail   = false;
+//   PlayerGraphics.avail = false;
+    GameLevels.avail     = false;
+    BattleLevels.avail   = false;
+
+    GetPathFromEnvironment( filename, ApogeePath, CONFIG );
+    if (access (filename, F_OK) == 0)
+    {
+        LoadScriptFile (filename);
+
+        GetTokenEOL (true);     //MODEMNAME
+        GetTokenEOL (true);     //MODEMINITSTR
+        GetTokenEOL (true);     //MODEMHANGUP
+        GetTokenEOL (true);     //RATE
+        GetTokenEOL (true);     //COMPORT
+        GetTokenEOL (true);     //IRQ
+        GetTokenEOL (true);     //UART
+        GetTokenEOL (true);     //PULSE
+        GetTokenEOL (true);     //AUTOMATICDIALOUT
+
+        GetAlternatePath ("REMOTESOUNDPATH", &RemoteSounds);
+//      GetAlternatePath ("PLAYERGRAPHICSPATH", &PlayerGraphics);
+        GetAlternatePath ("GAMELEVELPATH", &GameLevels);
+        GetAlternatePath ("BATTLELEVELPATH", &BattleLevels);
+
+        // Get CodeName
+        GetToken (true);
+        if (stricmp (token, "CODENAME"))
+            Error ("Can't find %s token.\n", "CODENAME");
+
+        GetTokenEOL (false);
+        memset (&CodeName[0], 0, sizeof (CodeName));
+        if (stricmp (name, "~"))
+        {
+
+            // Get First (MAXCODENAMELENGTH-1) characters
+            for (i=0; i<MAXCODENAMELENGTH-1; i++)
+                CodeName[i]=name[i];
+        }
+        GetTokenEOL (true);     //NUMPLAYERS
+        GetTokenEOL (true);     //NETWORKSOCKET
+        GetTokenEOL (true);     //DEFAULT
+        for (i=0; i<14; i++)
+            GetTokenEOL (true);  //NUMBERLIST
+
+        memset (CommbatMacros, 0, sizeof(CommbatMacros) );
+
+        for (i=0; i<MAXMACROS; i++)
+        {
+            GetToken (true);
+
+            GetTokenEOL (true);
+
+            if (name[0] != '~')
+            {
+                memcpy (&CommbatMacros[i].macro[0], &name[0], strlen (name));
+                CommbatMacros[i].avail = 1;
+            }
+        }
+
+        Z_Free (scriptbuffer);
+    }
+
+    GetPathFromEnvironment( filename, ApogeePath, ROTT );
+    if (access (filename, F_OK) == 0)
+    {
+        LoadScriptFile (filename);
+
+        GetTokenEOL (true);     //PHONENUMBER
+
+        GetAlternateFile ("REMOTESOUNDFILE", &RemoteSounds);
+//      GetAlternateFile ("PLAYERGRAPHICSFILE", &PlayerGraphics);
+        GetAlternateFile ("GAMELEVELFILE", &GameLevels);
+        GetAlternateFile ("COMMBATLEVELFILE", &BattleLevels);
+
+        Z_Free (scriptbuffer);
+
+        unlink (filename);          // Delete ROTT.ROT
+    }
+}
+
+#endif
+
--- /dev/null
+++ b/rott/rt_cfg.h
@@ -1,0 +1,125 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+#ifndef _rt_cfg_public
+#define _rt_cfg_public
+
+//****************************************************************************
+//
+// Public header for RT_CFG.C
+//
+//****************************************************************************
+
+
+//****************************************************************************
+//
+// GLOBALS
+//
+//****************************************************************************
+
+extern int     FXMode;
+extern int     MusicMode;
+extern int     MUvolume;
+extern int     FXvolume;
+extern boolean mouseenabled;
+extern boolean joystickenabled;
+extern boolean joypadenabled;
+extern boolean allowBlitzMoreMissileWeps;
+extern boolean enableAmmoPickups;
+extern boolean autoAimMissileWeps;
+extern boolean autoAim;
+
+extern int     joystickport;
+extern int     mouseadjustment;
+extern int     threshold;
+extern int     NumVoices;
+extern int     NumChannels;
+extern int     NumBits;
+#ifdef DOS
+extern int     MidiAddress;
+#endif
+extern boolean stereoreversed;
+extern boolean cybermanenabled;
+extern boolean assassinenabled;
+extern boolean spaceballenabled;
+extern boolean AutoDetailOn;
+extern int     DoubleClickSpeed;
+extern int     fulllight;
+extern boolean BobbinOn;
+extern int     Menuflipspeed;
+extern int     DetailLevel;
+extern int     fandc;
+extern int     blanktime;
+extern char    CodeName[9];
+#ifdef DOS
+extern char   *ApogeePath;
+#else
+extern char   ApogeePath[256];
+#endif
+
+extern int     DefaultDifficulty;
+extern int     DefaultPlayerCharacter;
+extern int     DefaultPlayerColor;
+extern byte    passwordstring[20];
+
+typedef struct
+{
+    char * path;
+    boolean avail;
+    char * file;
+} AlternateInformation;
+
+extern AlternateInformation RemoteSounds;
+extern AlternateInformation PlayerGraphics;
+extern AlternateInformation GameLevels;
+extern AlternateInformation BattleLevels;
+
+#define MAXMACROLENGTH 32
+#define MAXMACROS      10
+
+typedef struct {
+    byte avail;
+    char macro[MAXMACROLENGTH+1];
+} MacroList;
+
+extern MacroList CommbatMacros[MAXMACROS];
+
+//****************************************************************************
+//
+// PROTOTYPES
+//
+//****************************************************************************
+
+void WriteBattleConfig(void);
+void ReadScores (void);
+void ReadInt (const char * s1, int * val);
+void ReadBoolean (const char * s1, boolean * val);
+void ReadConfig (void);
+void WriteParameter (int file, const char * s1, int val);
+void WriteScores (void);
+void WriteConfig (void);
+void ReadSETUPFiles (void);
+void DeleteSoundFile ( void );
+void CheckVendor (void);
+void ConvertStringToPasswordString ( char * string );
+void ConvertPasswordStringToPassword ( void );
+void ConvertPasswordStringToString ( char * string );
+void ConvertPasswordToPasswordString ( void );
+
+#endif
--- /dev/null
+++ b/rott/rt_com.c
@@ -1,0 +1,799 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdarg.h>
+
+#ifdef DOS
+#include <conio.h>
+#include <dos.h>
+#include <process.h>
+#include <bios.h>
+#endif
+
+#include "rt_def.h"
+#include "_rt_com.h"
+#include "rt_com.h"
+#include "rt_util.h"
+#include "rt_in.h"
+#include "rt_crc.h"
+#include "rt_playr.h"
+#include "isr.h"
+#include "rt_msg.h"
+#include "rottnet.h"
+#include "rt_main.h"
+#include "rt_net.h"
+#include "rt_draw.h"
+//#include "rt_ser.h"
+//MED
+#include "memcheck.h"
+
+// GLOBAL VARIABLES
+
+// Same as in real mode
+rottcom_t   *	rottcom;
+int badpacket;
+int consoleplayer;
+byte ROTTpacket[MAXCOMBUFFERSIZE];
+int controlsynctime;
+
+// LOCAL VARIABLES
+#ifdef DOS
+static union  REGS   comregs;
+#endif
+
+static int    ComStarted=false;
+static int    transittimes[MAXPLAYERS];
+
+void SyncTime( int client );
+void SetTransitTime( int client, int time );
+
+#ifdef PLATFORM_UNIX
+
+static int sock = -1;
+
+static void ReadUDPPacket()
+{
+    rottcom->remotenode = -1;
+}
+
+static void WriteUDPPacket()
+{
+}
+
+#endif
+
+/*
+===============
+=
+= InitROTTNET
+=
+===============
+*/
+
+void InitROTTNET (void)
+{
+    int netarg;
+    long netaddress;
+
+    if (ComStarted==true)
+        return;
+    ComStarted=true;
+
+#ifdef DOS
+    netarg=CheckParm ("net");
+    netarg++;
+
+    netaddress=atol(_argv[netarg]);
+    rottcom=(rottcom_t *)netaddress;
+#elif defined(PLATFORM_UNIX)
+    /*
+    server-specific options:
+    -net: enables netplay
+    -server: run as rott server (default port 34858)
+    -port: select a non-default port for server
+    -host: select a non-default ip address to bind to
+    -standalone: run as standalone server
+    -remoteridicule: enable remote ridicule
+    -players: number of players to expect
+
+    client-specific options:
+    -master: request to have control
+    -net: specifies the host to connect to
+    -port: select a non-default port to connect to
+    */
+
+    rottcom = (rottcom_t *) malloc (sizeof(rottcom_t));
+    memset(rottcom, 0, sizeof(rottcom_t));
+
+    rottcom->ticstep = 1;
+    rottcom->gametype = 1;
+    rottcom->remotenode = -1;
+
+    if (CheckParm("server")) {
+        if (CheckParm("standalone")) {
+            rottcom->consoleplayer = 0;
+        } else {
+            rottcom->consoleplayer = 1;
+        }
+
+        if (CheckParm("remoteridicule")) {
+            rottcom->remoteridicule = 1;
+        } else {
+            rottcom->remoteridicule = 0;
+        }
+
+        netarg = CheckParm("players");
+        if (netarg && netarg < _argc-1) {
+            rottcom->numplayers = atoi(_argv[netarg+1]);
+        } else {
+            rottcom->numplayers = 2;
+        }
+
+        rottcom->client = 0;
+    } else {
+        rottcom->client = 1;
+
+        /* consoleplayer will be initialized after connecting */
+        /* numplayers will be initialized after connecting */
+        /* remoteridicule will be initialized after connecting */
+    }
+
+    /* client-server negotiation protocol, as inspired by ipxsetup.c */
+    /*
+      Best case:
+      client sends a HereIAm packet.
+      server replies with a YouAre packet, and broadcasts an Info packet
+        to the rest, indicating that the new player has joined.
+      client replies with an IAm packet
+      until all players have joined, the server broadcasts an Info packet
+        to the rest, indicating that another player is needed.
+      once server has enough players, it broadcasts an AllDone packet.
+
+      In detail:
+      Client state: HereIAm (initial connection)
+      Client sends HereIAm packet, waits for YouAre from server.
+      At timeout, Client resends HereIam
+      When client receives YouAre, client switches to IAm state
+
+      Client state: IAm
+      Client sends IAm packet, waits for IAmAck from server.
+      At timeout, Client resends IAm
+      When client receives IAmAck, client switches to WaitForDone state.
+
+      Client state: WaitForDone
+      Client waits for AllDone packet.
+      When client receives AllDone, it sends an AllDoneAck.
+     */
+
+#endif
+
+    remoteridicule = false;
+    remoteridicule = rottcom->remoteridicule;
+    if (rottcom->ticstep != 1)
+        remoteridicule = false;
+    if (remoteridicule == true)
+    {
+        if (!quiet)
+            printf("ROTTNET: LIVE Remote Ridicule Enabled\n");
+    }
+
+    if (!quiet)
+    {
+#ifdef DOS
+        printf("ROTTNET: Communicating on vector %ld\n",(long int)rottcom->intnum);
+#endif
+        printf("ROTTNET: consoleplayer=%ld\n",(long int)rottcom->consoleplayer);
+    }
+}
+
+/*
+================
+=
+= ReadPacket
+=
+================
+*/
+
+boolean ReadPacket (void)
+{
+    word   crc;
+    word   sentcrc;
+
+    // Set command (Get Packet)
+    rottcom->command=CMD_GET;
+
+    badpacket = 0;
+
+    // Check to see if a packet is ready
+
+#ifdef DOS
+    int386(rottcom->intnum,&comregs,&comregs);
+#elif PLATFORM_UNIX
+    ReadUDPPacket();
+#endif
+
+    // Is it ready?
+
+    if (rottcom->remotenode!=-1)
+    {
+        // calculate crc on packet
+        crc=CalculateCRC (&rottcom->data[0], rottcom->datalength-sizeof(word));
+
+        // get crc inside packet
+        sentcrc=*((word *)(&rottcom->data[rottcom->datalength-sizeof(word)]));
+
+        // are the crcs the same?
+        if (crc!=sentcrc)
+        {
+            badpacket=1;
+            SoftError("BADPKT at %d\n",GetTicCount());
+        }
+        if (networkgame==false)
+        {
+            rottcom->remotenode=server;
+        }
+        else
+        {
+            if ((IsServer==true) && (rottcom->remotenode>0))
+                rottcom->remotenode--;
+        }
+        memcpy(&ROTTpacket[0], &rottcom->data[0], rottcom->datalength);
+
+//      SoftError( "ReadPacket: time=%ld size=%ld src=%ld type=%d\n",GetTicCount(), rottcom->datalength,rottcom->remotenode,rottcom->data[0]);
+
+#if 0
+        rottcom->command=CMD_OUTQUEBUFFERSIZE;
+        int386(rottcom->intnum,&comregs,&comregs);
+        SoftError( "outque size=%ld\n",*((short *)&(rottcom->data[0])));
+        rottcom->command=CMD_INQUEBUFFERSIZE;
+        int386(rottcom->intnum,&comregs,&comregs);
+        SoftError( "inque size=%ld\n",*((short *)&(rottcom->data[0])));
+#endif
+        return true;
+    }
+    else // Not ready yet....
+        return false;
+}
+
+
+/*
+=============
+=
+= WritePacket
+=
+=============
+*/
+
+void WritePacket (void * buffer, int len, int destination)
+{
+    word      crc;
+
+    // set send command
+    rottcom->command=CMD_SEND;
+
+    // set destination
+    rottcom->remotenode=destination;
+
+    if (len>(int)(MAXCOMBUFFERSIZE-sizeof(word)))
+    {
+        Error("WritePacket: Overflowed buffer\n");
+    }
+
+    // copy local buffer into realmode buffer
+    memcpy((byte *)&(rottcom->data[0]),(byte *)buffer,len);
+
+    // calculate CRC
+    crc=CalculateCRC (buffer, len);
+
+    // put CRC into realmode buffer packet
+    *((word *)&rottcom->data[len])=crc;
+
+    // set size of realmode packet including crc
+    rottcom->datalength=len+sizeof(word);
+
+    if (*((byte *)buffer)==0)
+        Error("Packet type = 0\n");
+
+    if (networkgame==true)
+    {
+        if (IsServer==true)
+            rottcom->remotenode++; // server fix-up
+    }
+
+//   SoftError( "WritePacket: time=%ld size=%ld src=%ld type=%d\n",GetTicCount(),rottcom->datalength,rottcom->remotenode,rottcom->data[0]);
+    // Send It !
+#ifdef DOS
+    int386(rottcom->intnum,&comregs,&comregs);
+#elif PLATFORM_UNIX
+    WriteUDPPacket();
+#endif
+
+#if 0
+    rottcom->command=CMD_OUTQUEBUFFERSIZE;
+    int386(rottcom->intnum,&comregs,&comregs);
+    SoftError( "outque size=%ld\n",*((short *)&(rottcom->data[0])));
+    rottcom->command=CMD_INQUEBUFFERSIZE;
+    int386(rottcom->intnum,&comregs,&comregs);
+    SoftError( "inque size=%ld\n",*((short *)&(rottcom->data[0])));
+#endif
+}
+
+
+
+
+/*
+=============
+=
+= ValidSyncPacket
+=
+=============
+*/
+boolean ValidSyncPacket ( synctype * sync )
+{
+    if (ReadPacket() && (badpacket==0))
+    {
+        if (((syncpackettype *)&(ROTTpacket[0]))->type==COM_SYNC)
+        {
+            memcpy(&(sync->pkt),&(ROTTpacket[0]),sizeof(sync->pkt));
+            return true;
+        }
+    }
+    return false;
+}
+
+/*
+=============
+=
+= SendSyncPacket
+=
+=============
+*/
+void SendSyncPacket ( synctype * sync, int dest)
+{
+    sync->pkt.type=COM_SYNC;
+    sync->sendtime=GetTicCount();
+    WritePacket( &(sync->pkt.type), sizeof(syncpackettype), dest );
+}
+
+
+/*
+=============
+=
+= SlavePhaseHandler
+=
+=============
+*/
+
+boolean SlavePhaseHandler( synctype * sync )
+{
+    boolean done;
+
+    done=false;
+
+    switch (sync->pkt.phase)
+    {
+    case SYNC_PHASE1:
+        break;
+    case SYNC_PHASE2:
+        ISR_SetTime(sync->pkt.clocktime);
+        break;
+    case SYNC_PHASE3:
+        sync->pkt.clocktime=GetTicCount();
+        break;
+    case SYNC_PHASE4:
+        ISR_SetTime(GetTicCount()-sync->pkt.delta);
+        sync->pkt.clocktime=GetTicCount();
+        break;
+    case SYNC_PHASE5:
+        ISR_SetTime(GetTicCount()-sync->pkt.delta);
+        sync->sendtime=sync->pkt.clocktime;
+        done=true;
+        break;
+    }
+    return done;
+}
+
+
+
+/*
+=============
+=
+= MasterPhaseHandler
+=
+=============
+*/
+
+boolean MasterPhaseHandler( synctype * sync )
+{
+    boolean done;
+
+    done=false;
+
+    switch (sync->pkt.phase)
+    {
+    case SYNC_PHASE1:
+        sync->pkt.phase=SYNC_PHASE2;
+        sync->pkt.clocktime=GetTicCount()+(sync->deltatime>>1);
+        break;
+    case SYNC_PHASE2:
+        sync->pkt.phase=SYNC_PHASE3;
+        break;
+    case SYNC_PHASE3:
+        sync->pkt.delta=sync->pkt.clocktime-GetTicCount()+(sync->deltatime>>1);
+        sync->pkt.phase=SYNC_PHASE4;
+        break;
+    case SYNC_PHASE4:
+        sync->pkt.phase=SYNC_PHASE5;
+        sync->pkt.delta=sync->pkt.clocktime-GetTicCount()+(sync->deltatime>>1);
+        sync->sendtime=GetTicCount()+SYNCTIME;
+        sync->pkt.clocktime=sync->sendtime;
+        done=true;
+        break;
+    }
+    return done;
+}
+
+
+/*
+=============
+=
+= ComSetTime
+=
+=============
+*/
+
+void ComSetTime ( void )
+{
+    int i;
+    syncpackettype * syncpacket;
+    boolean done=false;
+
+    syncpacket=(syncpackettype *)SafeMalloc(sizeof(syncpackettype));
+
+
+    // Sync clocks
+
+    if (networkgame==true)
+    {
+        if (IsServer==true)
+        {
+            for (i=0; i<numplayers; i++)
+            {
+                if (PlayerInGame(i)==false)
+                    continue;
+                if (standalone==true)
+                    SyncTime(i);
+                else if (i!=consoleplayer)
+                    SyncTime(i);
+                if (standalone==true)
+                    printf("ComSetTime: player#%ld\n",(long int)i);
+            }
+        }
+        else
+        {
+            SyncTime(0);
+        }
+    }
+    else // Modem 2-player game
+    {
+        if (consoleplayer==0)
+            SyncTime(server);
+        else
+            SyncTime(server);
+    }
+
+    if ( ( (networkgame==true) && (IsServer==true) ) ||
+            ( (networkgame==false) && (consoleplayer==0) )
+       ) // Master/Server
+    {
+        int nump;
+        int time;
+
+        syncpacket->type=COM_START;
+        syncpacket->clocktime=GetTicCount();
+        controlsynctime=syncpacket->clocktime;
+        if (networkgame==true)
+            nump=numplayers;
+        else
+            nump=1;
+
+        time = GetTicCount();
+
+        for (i=0; i<nump; i++)
+        {
+            WritePacket( &(syncpacket->type), sizeof(syncpackettype), i );
+        }
+
+        while (GetTicCount()<time+(VBLCOUNTER/4)) ;
+
+        for (i=0; i<nump; i++)
+        {
+            WritePacket( &(syncpacket->type), sizeof(syncpackettype), i );
+        }
+
+        if (standalone==true)
+            printf("ComSetTime: Start packets sent\n");
+    }
+    else // Slave/Client
+    {
+        while (done==false)
+        {
+            AbortCheck("ComSetTime aborted as client");
+
+            if (ReadPacket() && (badpacket==0))
+            {
+                memcpy(syncpacket,&(ROTTpacket[0]),sizeof(syncpackettype));
+                if (syncpacket->type==COM_START)
+                {
+                    controlsynctime=syncpacket->clocktime;
+                    done=true;
+                }
+            }
+        }
+    }
+    if (standalone==false)
+    {
+        AddMessage("All players synched.",MSG_SYSTEM);
+        ThreeDRefresh();
+    }
+    SafeFree(syncpacket);
+
+//
+// flush out any extras
+//
+    while (GetTicCount()<controlsynctime+VBLCOUNTER)
+    {
+        ReadPacket ();
+    }
+}
+
+/*
+=============
+=
+= InitialMasterSync
+=
+=============
+*/
+void InitialMasterSync ( synctype * sync, int client )
+{
+    boolean done=false;
+    int i;
+
+    if (networkgame==true)
+    {
+        for (i=0; i<numplayers; i++)
+        {
+            if (i<=client)
+                continue;
+            sync->pkt.type=COM_SYNC;
+            sync->pkt.phase=SYNC_MEMO;
+            sync->pkt.clocktime=client;
+            SendSyncPacket(sync,i);
+        }
+    }
+
+    // Initialize send time so as soon as we enter the loop, we send
+
+    sync->sendtime=GetTicCount()-SYNCTIME;
+
+    while (done==false)
+    {
+        sync->pkt.phase=SYNC_PHASE0;
+
+        AbortCheck("Initial sync aborted as master");
+        if ((sync->sendtime+SYNCTIME) <= GetTicCount())
+            SendSyncPacket(sync,client);
+        if (ValidSyncPacket(sync)==true)
+        {
+            if (sync->pkt.phase==SYNC_PHASE0)
+            {
+                int time=GetTicCount();
+
+                while (time+SYNCTIME>GetTicCount())
+                {
+                    ReadPacket();
+                }
+                time=GetTicCount();
+                while (time+SYNCTIME>GetTicCount()) {}
+                done=true;
+            }
+        }
+    }
+}
+
+/*
+=============
+=
+= InitialSlaveSync
+=
+=============
+*/
+void InitialSlaveSync ( synctype * sync )
+{
+    boolean done=false;
+
+    while (done==false)
+    {
+        AbortCheck("Initial sync aborted as slave");
+        if (ValidSyncPacket(sync)==true)
+        {
+            if (sync->pkt.phase==SYNC_MEMO)
+            {
+                char str[50]="Server is synchronizing player ";
+                char str2[10];
+
+                strcat(str,itoa(sync->pkt.clocktime+1,str2,10));
+                AddMessage(str,MSG_SYSTEM);
+                ThreeDRefresh();
+            }
+            if (sync->pkt.phase==SYNC_PHASE0)
+            {
+                int time=GetTicCount();
+
+                SendSyncPacket(sync,server);
+                while (time+SYNCTIME>GetTicCount())
+                {
+                    ReadPacket();
+                }
+                done=true;
+            }
+        }
+    }
+    AddMessage("Server is synchronizing your system",MSG_SYSTEM);
+    ThreeDRefresh();
+}
+
+
+/*
+=============
+=
+= SyncTime
+=
+=============
+*/
+
+void SyncTime( int client )
+{
+    int dtime[NUMSYNCPHASES];
+    boolean done;
+    int i;
+    synctype * sync;
+
+    sync=(synctype *)SafeMalloc(sizeof(synctype));
+
+    if ( ((networkgame==true) && (IsServer==true)) ||
+            ((networkgame==false) && (consoleplayer==0)) )
+    {
+        // Master
+
+        InitialMasterSync ( sync, client );
+
+        done=false;
+
+        // Initial setup for Master
+        // Initialize send time so as soon as we enter the loop, we send
+
+        sync->pkt.phase=SYNC_PHASE1;
+        sync->sendtime=GetTicCount()-SYNCTIME;
+
+        while (done==false)
+        {
+            // Master
+
+            AbortCheck("SyncTime aborted as master");
+
+            if ((sync->sendtime+SYNCTIME) <= GetTicCount())
+                SendSyncPacket(sync,client);
+
+            while (ValidSyncPacket(sync)==true)
+            {
+
+                // find average delta
+
+                sync->deltatime=0;
+
+                // calculate last delta
+
+                dtime[sync->pkt.phase]=GetTicCount()-sync->sendtime;
+
+                for (i=0; i<=sync->pkt.phase; i++)
+                    sync->deltatime+=dtime[i];
+                if (i!=0)
+                    sync->deltatime/=i;
+                else
+                    Error("SyncTime: this should not happen\n");
+
+                done = MasterPhaseHandler( sync );
+
+                SendSyncPacket(sync,client);
+
+            }
+        }
+    }
+    else
+    {
+        // Slave
+
+        InitialSlaveSync ( sync );
+
+        done=false;
+
+        while (done==false)
+        {
+            // Slave
+
+            AbortCheck("SyncTime aborted as slave");
+
+            while (ValidSyncPacket(sync)==true)
+            {
+                done = SlavePhaseHandler( sync );
+
+                if (done==false)
+                    SendSyncPacket(sync,server);
+
+            }
+        }
+    }
+
+    while (sync->sendtime > GetTicCount())
+    {
+        while (ReadPacket()) {}
+    }
+    while ((sync->sendtime+SYNCTIME) > GetTicCount())
+    {
+    }
+
+    if ( ((networkgame==true) && (IsServer==true)) ||
+            ((networkgame==false) && (consoleplayer==0)) )
+        SetTransitTime( client, (sync->deltatime>>1));
+
+    SafeFree(sync);
+}
+
+/*
+=============
+=
+= SetTransitTime
+=
+=============
+*/
+
+void SetTransitTime( int client, int time )
+{
+    transittimes[client]=time;
+}
+
+/*
+=============
+=
+= GetTransitTime
+=
+=============
+*/
+
+int GetTransitTime( int client )
+{
+    return transittimes[client];
+}
+
--- /dev/null
+++ b/rott/rt_com.h
@@ -1,0 +1,48 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+#ifndef _rt_com_public
+#define _rt_com_public
+
+//***************************************************************************
+//
+// RT_COM.C
+//
+//***************************************************************************
+
+#define MAXPACKET	512
+
+#include "rottnet.h"
+
+extern int badpacket;
+extern int consoleplayer;
+extern byte ROTTpacket[MAXCOMBUFFERSIZE];
+
+extern int controlsynctime;
+
+
+//#define consoleplayer (rottcom->consoleplayer)
+
+void InitROTTNET (void);
+boolean ReadPacket (void);
+void WritePacket (void * buffer, int len, int destination);
+void ComSetTime (void);
+int GetTransitTime( int client );
+
+#endif
--- /dev/null
+++ b/rott/rt_crc.c
@@ -1,0 +1,134 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+// CRC lib
+
+#include	<stdio.h>
+#include	<stdlib.h>
+#include	<string.h>
+#include "rt_crc.h"
+//MED
+#include "memcheck.h"
+
+/* variables */
+static const unsigned short int crc16tab[256] =
+{
+    0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241,
+    0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440,
+    0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40,
+    0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841,
+    0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40,
+    0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41,
+    0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641,
+    0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040,
+    0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240,
+    0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441,
+    0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41,
+    0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840,
+    0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41,
+    0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40,
+    0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640,
+    0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041,
+    0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240,
+    0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441,
+    0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41,
+    0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840,
+    0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41,
+    0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40,
+    0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640,
+    0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041,
+    0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241,
+    0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440,
+    0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40,
+    0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841,
+    0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40,
+    0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41,
+    0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641,
+    0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040
+};
+
+/* driver */
+#if 0
+main(argc,argv)
+int argc;
+char **argv;
+{
+    if(argc>2) perr("Usage:  crcfast [filename]");
+    if(argc==2) strcpy(filename,argv[1]);
+    else
+    {
+        printf("\nEnter filename:  ");
+        gets(filename);
+    }
+    if((fp=fopen(filename,"rb"))==NULL) perr("Can't open file");
+    num=0L;
+    crc16=crctt=0;
+    while((ch=fgetc(fp))!=EOF)
+    {
+        num++;
+        crc16=updatecrc(crc16,ch);
+//		crctt=updcrc(crctt,ch);
+    }
+    fclose(fp);
+    printf("\nNumber of bytes = %lu\nCRC16 = %04X\nCRCTT = %04X",
+           num,crc16,crctt);
+}
+
+#endif
+
+/* update crc reverse */
+int updatecrc(int crc, int c)
+{
+    int tmp;
+    tmp=crc^c;
+    crc=(crc>>8)^crc16tab[tmp & 0xff];
+    return crc;
+}
+
+//******************************************************************************
+//
+// CalculateCRC ()
+//
+//******************************************************************************
+
+word CalculateCRC (byte *source, unsigned size)
+{
+    unsigned i;
+    int checksum;
+    int tmp;
+
+    checksum=0;
+
+    for (i = 0; i < size; i++)
+    {
+        tmp=checksum^(*(source++));
+        checksum=(checksum>>8)^crc16tab[tmp & 0xff];
+    }
+
+    return ((word)checksum);
+
+}
+
+
+
+
+
+
+
+
--- /dev/null
+++ b/rott/rt_crc.h
@@ -1,0 +1,24 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+#include "rt_def.h"
+
+int updatecrc(int,int);
+word CalculateCRC (byte *source, unsigned size);
+
--- /dev/null
+++ b/rott/rt_debug.c
@@ -1,0 +1,1695 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+#include "rt_def.h"
+#include "rt_debug.h"
+#include "isr.h"
+#include "rt_game.h"
+#include "rt_menu.h"
+#include "rt_build.h"
+#include "rt_str.h"
+#include "rt_vid.h"
+#include "rt_playr.h"
+#include "rt_main.h"
+#include "rt_util.h"
+#include "rt_draw.h"
+#include "rt_in.h"
+#include "z_zone.h"
+#include "rt_ted.h"
+#include "rt_view.h"
+#include "develop.h"
+#include "rt_msg.h"
+#include "rt_net.h"
+#include "rt_sound.h"
+#include "rt_stat.h"
+#include "rt_map.h"
+
+#include <stdlib.h>
+#include <ctype.h>
+//MED
+#include "memcheck.h"
+#include "w_wad.h"
+
+extern int		iDemoNames;
+extern boolean iG_aimCross;
+
+
+extern void DisplayMessage   (int num,int position);
+
+
+typedef struct {
+    char code[15];
+    byte length;
+} CodeStruct;
+
+enum
+{
+    RICOCHETING,               //richocheting rockets
+    RICOCHETINGALT,            //richocheting rockets alt
+    ENABLECHEAT,               // enable cheats
+    ENABLECHEATALT,            // enable cheats
+    SOMEITEMS,                 // three keys, more health
+    SOMEITEMSALT,              // three keys, more health
+    INVULNERABLE,              // normal god mode
+    INVULNERABLEALT,           // normal god mode
+    WARP,                      // warp
+    WARPALT,                   // warp
+    ITEMS,                     // all keys, armor, 100% health
+    ITEMSALT,                  // all keys, armor, 100% health
+    GODMODEPWUP,               // god mode powerup
+    GODMODEPWUPALT,            // god mode powerup
+#if (SHAREWARE == 0)
+    DOGMODEPWUP,               // dog mode powerup
+    DOGMODEPWUPALT,            // dog mode powerup
+#endif
+    MERCURYPWUP,               // mercury mode powerup
+    MERCURYPWUPALT,            // mercury mode powerup
+    SHROOMSPWUP,               // shrooms mode powerup
+    SHROOMSPWUPALT,            // shrooms mode powerup
+    ELASTOPWUP,                // elasto mode powerup
+    ELASTOPWUPALT,             // elasto mode powerup
+    RESTARTGAME,               // warp to level 1, start with pistol
+    RESTARTGAMEALT,            // warp to level 1, start with pistol
+    HURTPLAYER,                // hurt player 10%
+    HURTPLAYERALT,             // hurt player 10%
+    TOMHALLMODE,               // run fast all the time
+    TOMHALLMODEALT,            // run fast all the time
+    NORMAL,                    // back to normal
+    NORMALALT,                 // back to normal
+    LIGHTDIMON,                // light diminishing on
+    LIGHTDIMONALT,             // light diminishing on
+    LIGHTDIMOFF,               // light diminishing off
+    LIGHTDIMOFFALT,            // light diminishing off
+    FOGON,                     // fog on (0x00 - 0x80 minmax)
+    FOGONALT,                  // fog on (0x00 - 0x80 minmax)
+    FOGOFF,                    // fog off (0x80 - 0xFF minmax)
+    FOGOFFALT,                 // fog off (0x80 - 0xFF minmax)
+    QUITGAME,                  // blow out of game
+    QUITGAMEALT,               // blow out of game
+    ENDLEVEL,                  // end the current level
+    ENDLEVELALT,               // end the current level
+    FANDCOFF,                  // floor and ceiling off
+    FANDCOFFALT,               // floor and ceiling off
+    FANDCON,                   // floor and ceiling on
+    FANDCONALT,                // floor and ceiling on
+    BULLETARMOR,               // bullet proof armor
+    BULLETARMORALT,            // bullet proof armor
+    FIREARMOR,                 // fire proof armor
+    FIREARMORALT,              // fire proof armor
+    GASMASK,                   // gas mask
+    GASMASKALT,                // gas mask
+    OUTFIT,                    // all keys, armor, 100% health, MP40, heatseek
+    OUTFITALT,                 // all keys, armor, 100% health, MP40, heatseek
+    KILLPLAYER,                // kill player
+    KILLPLAYERALT,             // kill player
+    RESTARTLEVEL,              // re-enter level
+    RESTARTLEVELALT,           // re-enter level
+    WEAPONTWOPISTOL,           // give double pistol
+    WEAPONTWOPISTOLALT,        // give double pistol
+    WEAPONMP40,                // give mp40
+    WEAPONMP40ALT,             // give mp40
+    WEAPONBAZOOKA,             // give bazooka
+    WEAPONBAZOOKAALT,          // give bazooka
+    WEAPONHEAT,                // give heatseeker
+    WEAPONHEATALT,             // give heatseeker
+    WEAPONDRUNK,               // give drunk missile
+    WEAPONDRUNKALT,            // give drunk missile
+    WEAPONFIREBOMB,            // give firebomb
+    WEAPONFIREBOMBALT,         // give firebomb
+    WEAPONFIREWALL,            // give firewall
+    WEAPONFIREWALLALT,         // give firewall
+    WEAPONGOD,                 // give godhand
+    WEAPONGODALT,              // give godhand
+    AIMCROSS,                 // bna++
+    AIMCROSSALT,              // give bna++
+
+#if (SHAREWARE == 0)
+
+    WEAPONSPLIT,               // give split missile
+    WEAPONSPLITALT,            // give split missile
+    WEAPONKES,                 // give kes
+    WEAPONKESALT,              // give kes
+    WEAPONBAT,                 // give bat
+    WEAPONBATALT,              // give bat
+    WEAPONDOG,                 // give dogmode
+    WEAPONDOGALT,              // give dogmode
+#endif
+
+    MISSILECAMTOGGLE,          // Turn missile cam on/off
+    MISSILECAMTOGGLEALT,       // Turn missile cam on/off
+    HUDTOGGLE,                 // Turn HUD on/off
+    HUDTOGGLEALT,              // Turn HUD on/off
+    ROTATIONFUN,               // Rotation fun
+    DEMORECORD,                // Start recording demo
+    DEMOEND,                   // End recording demo
+    DEMOPLAYBACK,              // Playback demo
+    CRAZYGIBS,                 // Engine Killing Gibs
+    JUKEBOX,                   // JukeBox
+    JUKEBOXALT,                // JukeBox
+    MAPCHEAT,                  // Map Cheat
+    MAPCHEATALT,               // Map Cheat Alt,
+    MAXCODES
+};
+
+CodeStruct Codes[MAXCODES + 6] =
+{
+    {"TIHSHO",      6},         //richocheting rockets LT++
+    {"SIHTTNAWTNOD",     12}, //ricocheting rockets   LT++
+    {"KCITSPID",    8},        // enable cheats
+    {"CCE\\",       4},        // enable cheats
+    {"REKCALS",     7},        // three keys, more health
+    {"MUB\\",       4},        // three keys, more health
+    {"NIJOHC",      6},        // normal god mode
+    {"WWW\\",       4},        // normal god mode
+    {"OTOG",        4},        // warp
+    {"LTG\\",       4},        // warp
+    {"SYOTXIS",     7},        // all keys, armor, 100% health
+    {"IAG\\",       4},        // all keys, armor, 100% health
+    {"DASOOT",      6},        // god mode powerup
+    {"DOG\\",       4},        // god mode powerup
+#if (SHAREWARE == 0)
+    {"FOOW",        4},        // dog mode powerup
+    {"GOD\\",       4},        // dog mode powerup
+#endif
+    {"YOBYLF",      6},        // mercury mode powerup
+    {"REM\\",       4},        // mercury mode powerup
+    {"PIRTDAB",     7},        // shrooms mode powerup
+    {"RHS\\",       4},        // shrooms mode powerup
+    {"GNIOB",       5},        // elasto mode powerup
+    {"ALE\\",       4},        // elasto mode powerup
+    {"SREBOOG",     7},        // warp to level 1, start with pistol
+    {"OOG\\",       4},        // warp to level 1, start with pistol
+    {"KCAHW",       5},        // hurt player 10%
+    {"FOO\\",       4},        // hurt player 10%
+    {"DEEPS",       5},        // run fast all the time
+    {"AFR\\",       4},        // run fast all the time
+    {"CINAP",       5},        // back to normal
+    {"NAP\\",       4},        // back to normal
+    {"NOMID",       5},        // light diminishing on
+    {"NOD\\",       4},        // light diminishing on
+    {"FFOMID",      6},        // light diminishing off
+    {"FOD\\",       4},        // light diminishing off
+    {"NODNOL",      6},        // fog on (0x00 - 0x80 minmax)
+    {"NOF\\",       4},        // fog on (0x00 - 0x80 minmax)
+    {"LONDON",      6},        // fog off (0x80 - 0xFF minmax)
+    {"FOF\\",       4},        // fog off (0x80 - 0xFF minmax)
+    {"SETAGOG",     7},        // blow out of game
+    {"R8L\\",       4},        // blow out of game
+    {"HCRAOG",      6},        // end the current level
+    {"LCE\\",       4},        // end the current level
+    {"683ATOG",     7},        // floor and ceiling off
+    {"NOC\\",       4},        // floor and ceiling off
+    {"684ATOG",     7},        // floor and ceiling on
+    {"FOC\\",       4},        // floor and ceiling on
+    {"EMTOOHS",     7},        // bullet proof armor
+    {"RAB\\",       4},        // bullet proof armor
+    {"EMNRUB",      6},        // fire proof armor
+    {"RAF\\",       4},        // fire proof armor
+    {"GNUDGNUL",    8},        // gas mask
+    {"RAG\\",       4},        // gas mask
+    {"KCAPTNUH",    8},        // all keys, armor, 100% health, MP40, heatseek
+    {"PFO\\",       4},        // all keys, armor, 100% health, MP40, heatseek
+    {"EM68",        4},        // kill player
+    {"EID\\",       4},        // kill player
+    {"REEN",        4},        // re-enter level
+    {"LER\\",       4},        // re-enter level
+    {"OOWNHOJ",     7},        // give double pistol
+    {"2WG\\",       4},        // give double pistol
+    {"EMGULP",      6},        // give mp40
+    {"3WG\\",       4},        // give mp40
+    {"ALLINAV",     7},        // give bazooka
+    {"4WG\\",       4},        // give bazooka
+    {"SEMITTOH",    8},        // give heatseeker
+    {"5WG\\",       4},        // give heatseeker
+    {"EZOOB",       5},        // give drunk missile
+    {"6WG\\",       4},        // give drunk missile
+    {"BMOBERIF",    8},        // give firebomb
+    {"7WG\\",       4},        // give firebomb
+    {"SENOB",       5},        // give firewall
+    {"8WG\\",       4},        // give firewall
+    {"AYEES",       5},        // give god hand
+    {"9WG\\",       4},        // give god hand
+    {"MIA",       3},        // give aim bna++
+    {"MIA\\",       4},        // give aim bna++
+
+
+
+#if (SHAREWARE == 0)
+
+    {"TILPS",       5},        // give split missile
+    {"AWG\\",       4},        // give split missile
+    {"HTAEDFOSEK", 10},        // give kes
+    {"BWG\\",       4},        // give kes
+    {"NUREMOH",     8},        // give bat
+    {"CWG\\",       4},        // give bat
+    {"OJUC",        4},        // give dog weapon
+    {"DWG\\",       4},        // give dog weapon
+#endif
+    {"EDIR",        4},        // give MISSILE CAM
+    {"MAC\\",       4},        // give Missile Cam
+    {"EREHW",       5},        // turn where am i on/off
+    {"DUH\\",       4},        // give hud
+    {"NUF\\",       4},        // Rotation fun
+    {"DROCER",      6},        // Demo RECORD
+    {"POTS",        4},        // Demo stop recording
+    {"YALP",        4},        // Demo Playback
+    {"GKE\\",       4},        // Engine Killing Gibs
+    {"ORTSEAM",     7},        // JukeBox
+    {"EEL\\",       4},        // JukeBox
+    {"REITRAC",     7},        // Map Cheat
+    {"PAM\\",       4},        // Map Cheat
+    {"UOY\\",       4},        // Secret Message
+    {"EVAH",        4},        // Secret Message
+    {"ON\\",        3},        // Secret Message
+    {"EFIL",        4}        // Secret Message
+
+};
+
+
+
+
+/*
+================
+=
+= CheatSpawnItem
+=
+================
+*/
+
+void CheatSpawnItem (int item)
+{
+    SpawnStatic(player->tilex, player->tiley, item,-1);
+    LASTSTAT->z = player->z;
+    MakeStatActive(LASTSTAT);
+    LASTSTAT->flags|=FL_ABP;
+}
+
+
+/*
+================
+=
+= FixupPowerupsY
+=
+================
+*/
+
+void FixupPowerupsY (void)
+{
+    player->z   = nominalheight;
+}
+
+
+/*
+================
+=
+= EnableCheatCodes
+=
+================
+*/
+
+void EnableCheatCodes (void)
+{
+    DebugOk ^= 1;
+
+    if (DebugOk)
+        AddMessage ("Cheat Codes \\cENABLED!", MSG_CHEAT);
+    else
+        AddMessage ("Cheat Codes \\cDISABLED!", MSG_CHEAT);
+}
+
+
+/*
+================
+=
+= ResetCheatCodes
+=
+================
+*/
+
+void ResetCheatCodes (void)
+{
+//	godmode = false;
+}
+
+/*
+================
+=
+= DoMapCheat
+=
+================
+*/
+
+void DoMapCheat (void)
+{
+    AddMessage ("Entire Map Revealed!", MSG_CHEAT);
+    CheatMap ();
+}
+
+/*
+================
+=
+= DoGodMode
+=
+================
+*/
+
+void DoGodMode (void)
+{
+    if (godmode)
+        AddMessage ("Woundless With Weapons \\cOFF", MSG_CHEAT);
+    else
+        AddMessage ("Woundless With Weapons \\cON", MSG_CHEAT);
+
+    godmode ^= 1;
+}
+
+
+/*
+================
+=
+= DoWarp
+=
+================
+*/
+#include "byteordr.h"//bna++
+void DoWarp (void)
+{
+    /*
+    	char str[10];
+    	boolean esc;
+    	int level;
+
+       CurrentFont = smallfont;
+
+       US_CenterWindow(26,3);
+    	PrintY+=6;
+
+       US_Print(" Warp to level(1-99):");
+
+       VW_UpdateScreen();
+
+       ShutdownClientControls();
+
+       esc = !US_LineInput (px, py, str, NULL, true, 2, 25, 13);
+
+       if (!esc)
+       {
+          level = ParseNum (str);
+          if (level>0 && level<=99)
+          {
+             gamestate.mapon = level-1;
+             playstate = ex_warped;
+             gamestate.episode = GetEpisode (gamestate.mapon);
+          }
+       }
+
+       while (Keyboard[sc_Escape])
+    		IN_UpdateKeyboard ();
+       IN_ClearKeyboardQueue ();
+
+    */
+
+    int level;
+
+
+    EnableScreenStretch();//bna++ shut on streech mode
+
+
+    MU_StoreSongPosition();
+    MU_StartSong( song_secretmenu);
+    StopWind();
+    ShutdownClientControls();
+
+    SetupMenuBuf();
+    SetUpControlPanel ();
+
+    level = CP_LevelSelectionMenu();
+
+    CleanUpControlPanel();
+    ShutdownMenuBuf();
+
+    //bna++ section
+    if (( playstate == ex_stillplaying )&&(iGLOBAL_SCREENWIDTH > 320)) {
+        pic_t *shape;
+        shape =  ( pic_t * )W_CacheLumpName( "backtile", PU_CACHE, Cvt_pic_t, 1 );
+        DrawTiledRegion( 0, 16, iGLOBAL_SCREENWIDTH, iGLOBAL_SCREENHEIGHT - 32, 0, 16, shape );
+        DisableScreenStretch();//dont strech when we go BACK TO GAME
+        DrawPlayScreen(true);//repaint ammo and life stat
+        VW_UpdateScreen ();//update screen
+    }
+    //bna section end
+
+    EnableScreenStretch();//bna++ shut on streech mode
+    while( Keyboard[ sc_Escape ] )
+    {
+        IN_UpdateKeyboard();
+    }
+    IN_ClearKeyboardQueue();
+
+    if ((level == -1) || (level == gamestate.mapon))
+    {
+        MU_StartSong(song_level);
+        MU_RestoreSongPosition();
+    }
+
+    if ( level >= 0 )
+    {
+        playstate = ex_warped;
+        gamestate.mapon   = level;
+
+        GetEpisode( gamestate.mapon );
+
+        VL_FadeOut (0, 255, 0, 0, 0, 20);
+    }
+    else
+    {
+        DisableScreenStretch();//dont strech when we go BACK TO GAME
+        SetupScreen(true);
+    }
+
+    StartupClientControls();
+}
+
+/*
+================
+=
+= DoJukeBox
+=
+================
+*/
+
+void DoJukeBox  (void)
+
+{
+    if (iGLOBAL_SCREENWIDTH > 320) {
+        EnableScreenStretch();//bna++ shut on streech mode
+    }
+    StopWind();
+    ShutdownClientControls();
+
+    SetupMenuBuf();
+    SetUpControlPanel ();
+
+    MU_JukeBoxMenu();
+
+    CleanUpControlPanel();
+    ShutdownMenuBuf();
+
+    //bna++ section
+    if (( playstate == ex_stillplaying )&&(iGLOBAL_SCREENWIDTH > 320)) {
+        pic_t *shape;
+        shape =  ( pic_t * )W_CacheLumpName( "backtile", PU_CACHE, Cvt_pic_t, 1 );
+        DrawTiledRegion( 0, 16, iGLOBAL_SCREENWIDTH, iGLOBAL_SCREENHEIGHT - 32, 0, 16, shape );
+        DisableScreenStretch();//dont strech when we go BACK TO GAME
+        DrawPlayScreen(true);//repaint ammo and life stat
+        VW_UpdateScreen ();//update screen
+    }
+    //bna section end
+
+    SetupScreen(true);
+
+    while( Keyboard[ sc_Escape ] )
+    {
+        IN_UpdateKeyboard();
+    }
+    IN_ClearKeyboardQueue();
+
+    StartupClientControls();
+}
+
+
+
+/*
+================
+=
+= DoNormalThing
+=
+================
+*/
+
+void DoNormalThing (void)
+{
+    AddMessage ("BACK TO NORMAL.  AH.", MSG_CHEAT);
+
+    player->flags &= ~(FL_BPV|FL_AV|FL_GASMASK);
+    locplayerstate->protectiontime = 0;
+
+    if (player->flags & FL_ELASTO)
+        player->flags &= ~FL_NOFRICTION;
+    player->flags &= ~(FL_SHROOMS|FL_ELASTO|FL_FLEET);
+    locplayerstate->poweruptime = 0;
+
+    InitializeWeapons(locplayerstate);
+    locplayerstate->keys = 0;
+
+    DrawPlayScreen (false);
+}
+
+
+
+/*
+================
+=
+= DoItemCheat
+=
+================
+*/
+
+void DoItemCheat (void)
+{
+    AddMessage ("Items Aplenty!", MSG_CHEAT);
+
+    GivePoints (100000);
+    HealPlayer (99, player);
+
+    locplayerstate->keys = 0xF;
+    DrawKeys (false);
+
+    player->flags &= ~(FL_GASMASK|FL_BPV|FL_AV);
+    CheatSpawnItem(stat_bulletproof);
+
+    /*
+    player->flags |= FL_BPV;
+    player->flags &= ~(FL_GASMASK|FL_AV);
+    locplayerstate->protectiontime = POWERUPTICS;
+    GM_DrawBonus (stat_bulletproof);
+    */
+}
+
+/*
+================
+=
+= DoSomeItemCheat
+=
+================
+*/
+
+void DoSomeItemCheat (void)
+{
+    AddMessage ("Slacker pack!", MSG_CHEAT);
+
+    HealPlayer (40, player);
+
+    locplayerstate->keys = 0x7;
+    DrawKeys (false);
+}
+
+
+/*
+================
+=
+= DoGodModePowerup
+=
+================
+*/
+
+void DoGodModePowerup (void)
+{
+
+    if (PLAYER[0]->flags & FL_GODMODE)
+        return;
+
+    CheatSpawnItem(stat_godmode);
+}
+
+
+/*
+================
+=
+= DoDogModePowerup
+=
+================
+*/
+
+void DoDogModePowerup (void)
+{
+
+    if (PLAYER[0]->flags & FL_DOGMODE)
+        return;
+
+    CheatSpawnItem(stat_dogmode);
+}
+
+
+/*
+================
+=
+= DoMercuryModePowerup
+=
+================
+*/
+
+void DoMercuryModePowerup (void)
+{
+
+    if (PLAYER[0]->flags & FL_FLEET)
+        return;
+
+    CheatSpawnItem(stat_fleetfeet);
+}
+
+
+/*
+================
+=
+= DoElastoModePowerup
+=
+================
+*/
+
+void DoElastoModePowerup (void)
+{
+    if (PLAYER[0]->flags & FL_ELASTO)
+        return;
+
+    CheatSpawnItem(stat_elastic);
+}
+
+
+/*
+================
+=
+= DoShroomsModePowerup
+=
+================
+*/
+
+void DoShroomsModePowerup (void)
+{
+    if (PLAYER[0]->flags & FL_SHROOMS)
+        return;
+
+    AddMessage ("SHROOMS MODE POWERDOWN!", MSG_CHEAT);
+
+    CheatSpawnItem(stat_mushroom);
+}
+
+
+/*
+================
+=
+= RestartNormal
+=
+================
+*/
+
+void RestartNormal (void)
+{
+    EnableScreenStretch();//bna
+    DoNormalThing ();
+
+    AddMessage ("Restart to level 1", MSG_CHEAT);
+    gamestate.mapon   = 0;
+    playstate         = ex_warped;
+
+    GetEpisode (gamestate.mapon);
+}
+
+
+/*
+================
+=
+= HurtPlayer
+=
+================
+*/
+
+void HurtPlayer (void)
+{
+    int oldhitpoints;
+
+    oldhitpoints = player->hitpoints;
+    DamageThing (player, MaxHitpointsForCharacter(locplayerstate) / 10);
+    if (player->hitpoints < oldhitpoints)
+        AddMessage ("OUCH!!!!", MSG_CHEAT);
+
+    Collision(player,player,0,0);
+}
+
+
+/*
+================
+=
+= SetLightDiminish
+=
+================
+*/
+
+void SetLightDiminish (boolean off)
+{
+    if (off)
+    {
+        AddMessage ("Light Diminishing \\cOff", MSG_CHEAT);
+        fulllight = 1;
+    }
+    else
+    {
+        AddMessage ("Light Diminishing \\cOn", MSG_CHEAT);
+        fulllight = 0;
+    }
+}
+
+
+/*
+================
+=
+= SetFog
+=
+================
+*/
+
+void SetFog (boolean on)
+{
+    if (on)
+    {
+        AddMessage ("Fog \\cOn", MSG_CHEAT);
+        MAPSPOT(2,0,1)=105;
+        MAPSPOT(3,0,1)=0;
+        SetupLightLevels ();
+
+    }
+    else
+    {
+        AddMessage ("Fog \\cOff", MSG_CHEAT);
+        MAPSPOT(2,0,1)=104;
+        SetupLightLevels ();
+    }
+}
+
+
+
+/*
+================
+=
+= ToggleMissileCam
+=
+================
+*/
+
+void ToggleMissileCam (void)
+{
+    if (missilecam==false)
+    {
+        missilecam=true;
+        AddMessage ("Missile Cam \\cOn", MSG_CHEAT);
+    }
+    else
+    {
+        missilecam=false;
+        AddMessage ("Missile Cam \\cOff", MSG_CHEAT);
+    }
+}
+
+/*
+================
+=
+= ToggleHUD
+=
+================
+*/
+
+void ToggleHUD (void)
+{
+    if (HUD==false)
+    {
+        HUD=true;
+        AddMessage ("HUD \\cOn", MSG_CHEAT);
+    }
+    else
+    {
+        HUD=false;
+        AddMessage ("HUD \\cOff", MSG_CHEAT);
+    }
+}
+
+
+
+/*
+================
+=
+= EndLevel
+=
+================
+*/
+
+void EndLevel (void)
+{
+    AddMessage ("End Level", MSG_CHEAT);
+    playstate = ex_skiplevel;
+}
+
+
+/*
+================
+=
+= FloorandCeiling
+=
+================
+*/
+
+void FloorandCeiling (boolean off)
+{
+    if (off)
+    {
+        AddMessage ("Floor and Ceiling \\cON", MSG_CHEAT);
+        fandc = 1;
+    }
+    else
+    {
+        AddMessage ("Floor and Ceiling \\cOFF", MSG_CHEAT);
+        fandc = 0;
+    }
+}
+
+
+/*
+================
+=
+= GiveGasMask
+=
+================
+*/
+
+void GiveGasMask ()
+{
+
+    if (PLAYER[0]->flags & FL_GASMASK)
+        return;
+
+    CheatSpawnItem(stat_gasmask);
+}
+
+/*
+================
+=
+= GiveBulletProofArmor
+=
+================
+*/
+
+void GiveBulletProofArmor ()
+{
+    if (PLAYER[0]->flags & FL_BPV)
+        return;
+
+
+    CheatSpawnItem(stat_bulletproof);
+}
+
+/*
+================
+=
+= GiveAsbestoArmor
+=
+================
+*/
+
+void GiveAsbestoArmor ()
+{
+    if (PLAYER[0]->flags & FL_AV)
+        return;
+
+    CheatSpawnItem(stat_asbesto);
+}
+
+
+/*
+================
+=
+= OutfitPlayer
+=
+================
+*/
+void OutfitPlayer ()
+{
+    AddMessage ("Outfit Player!", MSG_CHEAT);
+
+    locplayerstate->keys = 0xF;
+    DrawKeys (false);
+    HealPlayer (99, player);
+
+    /*
+    player->flags |= FL_BPV;
+    player->flags &= ~(FL_GASMASK|FL_AV);
+    locplayerstate->protectiontime = POWERUPTICS;
+    GM_DrawBonus (stat_bulletproof);
+
+    GiveWeapon (player,wp_mp40);
+    */
+
+#if (SHAREWARE == 0)
+    CheatSpawnItem(stat_splitmissile);
+#else
+    CheatSpawnItem(stat_heatseeker);
+#endif
+
+
+}
+
+/*
+================
+=
+= KillPlayer
+=
+================
+*/
+
+void KillPlayer ()
+{
+    AddMessage ("Say Goodnight.", MSG_CHEAT);
+    playstate = ex_died;
+}
+
+
+
+/*
+================
+=
+= RestartCurrentLevel
+=
+================
+*/
+
+void RestartCurrentLevel (void)
+{
+    playstate = ex_warped;
+
+    GetEpisode (gamestate.mapon);
+}
+
+/*
+================
+=
+= EndDemo
+=
+================
+*/
+void EndDemo ( void )
+{
+    char str[10];
+    boolean esc;
+    int demonumber;
+
+    if (demorecord==false)
+        return;
+
+    ShutdownClientControls();
+
+    CurrentFont = smallfont;
+
+    demorecord = false;
+    US_CenterWindow (26, 4);
+    US_CPrint ("Save demo as:");
+    US_Print  ("\n");
+    US_CPrint ("Demo Number (1-4):");
+
+    VW_UpdateScreen();
+
+    esc = !US_LineInput (px, py, str, NULL, true, 1, 25, 13);
+
+    if (!esc)
+    {
+        demonumber = ParseNum (str);
+        if ((demonumber > 0) && (demonumber < 5))
+        {
+            SaveDemo (demonumber);
+        }
+    }
+
+    IN_ClearKeysDown ();
+
+    while (Keyboard[sc_Enter])
+        IN_UpdateKeyboard ();
+    while (Keyboard[sc_Escape])
+        IN_UpdateKeyboard ();
+    IN_ClearKeyboardQueue ();
+
+    StartupClientControls();
+    DisableScreenStretch();
+}
+
+
+/*
+================
+=
+= RecordDemoQuery
+=
+================
+*/
+void RecordDemoQuery ( void )
+{
+    char str[10];
+    boolean esc;
+    int level;
+
+    ShutdownClientControls();
+
+    CurrentFont = smallfont;
+
+    US_CenterWindow (26, 5);
+    PrintY += 6;
+
+    US_CPrint ("Record Demo");
+    US_Print  ("\n");
+#if (SHAREWARE==0)
+    US_CPrint ("Which level (1-36):");
+#else
+    US_CPrint ("Which level (1-8):");
+#endif
+
+    VW_UpdateScreen();
+
+    esc = !US_LineInput (px, py, str, NULL, true, 2, 25, 13);
+
+    if (!esc)
+    {
+        level = ParseNum (str);
+#if (SHAREWARE==0)
+        if ((level > 0) && (level < 37))
+#else
+        if ((level > 0) && (level < 9))
+#endif
+        {
+            EnableScreenStretch();//bna
+            gamestate.mapon = level-1;
+            playstate = ex_demorecord;
+        }
+    }
+
+    while (Keyboard[sc_Enter])
+        IN_UpdateKeyboard ();
+    while (Keyboard[sc_Escape])
+        IN_UpdateKeyboard ();
+    IN_ClearKeyboardQueue ();
+
+    StartupClientControls();
+}
+
+/*
+================
+=
+= PlaybackDemoQuery
+=
+================
+*/
+void PlaybackDemoQuery ( void )
+{
+    char str[10];
+    boolean esc;
+    int level;
+
+    ShutdownClientControls();
+
+    CurrentFont = smallfont;
+    US_CenterWindow (33, 4);
+    US_CPrint ("Playback demo");
+    US_Print ("\n");
+    US_CPrint ("Enter demo number (1-4):");
+
+    VW_UpdateScreen ();
+
+    esc = !US_LineInput (px, py, str, NULL, true, 1, 25, 13);
+
+    if (!esc)
+    {
+        level = ParseNum (str);
+        if ((level > 0) && (level < 5))
+        {
+            if (DemoExists (level) == true)
+                LoadDemo (level);
+        }
+    }
+
+    while (Keyboard[sc_Enter])
+        IN_UpdateKeyboard ();
+    while (Keyboard[sc_Escape])
+        IN_UpdateKeyboard ();
+    IN_ClearKeyboardQueue ();
+
+    StartupClientControls();
+
+    EnableScreenStretch();
+}
+
+/*
+================
+=
+= DebugKeys
+=
+================
+*/
+
+int DebugKeys (void)
+{
+#if (DEVELOPMENT == 1)
+    char str[10];
+    boolean esc;
+    int level;
+    int i,f,temp;
+    static int whichpowerup    = 0;
+    static int whichprotection = 0;
+
+    if (Keyboard[sc_G])     // G = god mode
+    {
+        DoGodMode ();
+        while (Keyboard[sc_G])
+            IN_UpdateKeyboard ();
+        return 1;
+    }
+    else if (Keyboard[sc_Q])         // Q = fast quit
+        QuitGame ();
+    else if (Keyboard[sc_W])         // W = warp to level
+    {
+        DoWarp ();
+        return 1;
+    }
+    else if (Keyboard[sc_F])     // F = FPS
+    {
+        f=0;
+        for (i=0; i<VBLCOUNTER*10; i+=tics)
+        {
+            ThreeDRefresh();
+            DoSprites();
+            CalcTics ();
+            f++;
+        }
+
+        CurrentFont = smallfont;
+
+        US_CenterWindow (12,2);
+        temp=f*10;
+        SoftError("fps  = %2ld.%2ld\n",temp/100,temp%100);
+
+        US_Print ("FPS=");
+        US_PrintUnsigned (temp/100);
+        US_Print (".");
+        US_PrintUnsigned (temp%100);
+
+        VW_UpdateScreen();
+        IN_Ack();
+
+        return 1;
+    }
+    else if (Keyboard[sc_H])     // H = hurt self
+    {
+        IN_ClearKeysDown ();
+        HurtPlayer ();
+    }
+    else if (Keyboard[sc_Z])     // Z = end level
+    {
+        EndLevel ();
+    }
+    else if (Keyboard[sc_P])     // P = step through powerups
+    {
+        whichpowerup++;
+        if (whichpowerup == 6)
+            whichpowerup = 0;
+
+        switch (whichpowerup)
+        {
+        case 0:  // nothing
+            if (player->flags & FL_ELASTO)
+                player->flags &= ~FL_NOFRICTION;
+            player->flags &= ~(FL_SHROOMS|FL_ELASTO|FL_FLEET|FL_GODMODE|FL_DOGMODE);
+            locplayerstate->poweruptime = 0;
+            GM_UpdateBonus (0, true);
+            break;
+
+        case 1:  // god mode
+            DoGodModePowerup ();
+            break;
+
+        case 2:  // dog mode
+            DoDogModePowerup ();
+            break;
+
+        case 3:  // fleet feet
+            DoMercuryModePowerup ();
+            break;
+
+        case 4:  // elasto
+            DoElastoModePowerup ();
+            break;
+
+        case 5:  // shrooms
+            DoShroomsModePowerup ();
+            break;
+        }
+
+        while (Keyboard[sc_P])
+            IN_UpdateKeyboard ();
+    }
+    else if (Keyboard[sc_A])     // step through armor
+    {
+        whichprotection++;
+        if (whichprotection == 4)
+            whichprotection = 0;
+
+        switch (whichprotection)
+        {
+        case 0:  // nothing
+            player->flags &= ~(FL_BPV|FL_AV|FL_GASMASK);
+            locplayerstate->protectiontime = 0;
+            GM_UpdateBonus (0, false);
+            break;
+
+        case 1:  // gas mask
+            GiveGasMask ();
+            break;
+
+        case 2:  // armor
+            GiveBulletProofArmor ();
+            break;
+
+        case 3:  // fire vest
+            GiveAsbestoArmor ();
+            break;
+        }
+
+        while (Keyboard[sc_A])
+            IN_UpdateKeyboard ();
+    }
+    else if (Keyboard[sc_O])     // O = outfit player
+    {
+        OutfitPlayer ();
+
+        IN_ClearKeysDown ();
+        IN_Ack ();
+        return 1;
+    }
+    else if (Keyboard[sc_K])     // K = kill self
+    {
+        IN_ClearKeysDown ();
+        locplayerstate->lives = -1;
+        KillPlayer ();
+    }
+    else if (Keyboard[sc_I])        // I = item cheat
+    {
+        DoItemCheat ();
+        return 1;
+    }
+    else if (Keyboard[53])        // \ = back to normal
+    {
+        DoNormalThing ();
+        return 1;
+    }
+    else if (Keyboard[sc_R])
+    {
+        RecordDemoQuery();
+    }
+    else if (Keyboard[sc_E])
+    {
+        EndDemo();
+    }
+    else if (Keyboard[sc_D])
+    {
+        PlaybackDemoQuery();
+    }
+#endif
+    return (0);
+}
+
+
+/*
+================
+=
+= WeaponCheat
+=
+================
+*/
+
+void WeaponCheat (int weapon)
+{
+    if ((player->flags & FL_GODMODE) || (player->flags & FL_DOGMODE))
+        return;
+
+    if ((weapon <= wp_mp40) && (PLAYERSTATE[0].HASBULLETWEAPON[weapon]))
+        return;
+
+    CheatSpawnItem(GetItemForWeapon(weapon));
+
+}
+
+
+
+/*
+================
+=
+= CheckCode ()
+=
+================
+*/
+
+extern boolean ricochetingRocketsEnabled;
+
+void CheckCode (int which)
+{
+    int pos = (LastLetter-1)&(MAXLETTERS-1);
+    int num = 0;
+    int start;
+
+    start = pos;
+
+    while ((toupper(LetterQueue[pos]) == Codes[which].code[num]) &&
+            (num < Codes[which].length))
+    {
+        pos = (pos-1)&(MAXLETTERS-1);
+        num++;
+    }
+
+    if (num == Codes[which].length)
+    {
+        // Kill last letter so the debug rtn will not keep triggering
+        LetterQueue[start] = 0;
+
+        switch (which)
+        {
+        case ENABLECHEAT:
+        case ENABLECHEATALT:
+            EnableCheatCodes ();
+            break;
+
+        case INVULNERABLE:
+        case INVULNERABLEALT:
+            DoGodMode ();
+            break;
+
+        case WARP:
+        case WARPALT:
+            DoWarp ();
+            break;
+
+        case ITEMS:
+        case ITEMSALT:
+            DoItemCheat ();
+            break;
+
+        case SOMEITEMS:
+        case SOMEITEMSALT:
+            DoSomeItemCheat ();
+            break;
+
+        case GODMODEPWUP:
+        case GODMODEPWUPALT:
+            DoGodModePowerup ();
+            break;
+
+#if (SHAREWARE == 0)
+        case DOGMODEPWUP:
+        case DOGMODEPWUPALT:
+            DoDogModePowerup ();
+            break;
+#endif
+
+        case MERCURYPWUP:
+        case MERCURYPWUPALT:
+            DoMercuryModePowerup ();
+            break;
+
+        case SHROOMSPWUP:
+        case SHROOMSPWUPALT:
+            DoShroomsModePowerup ();
+            break;
+
+        case ELASTOPWUP:
+        case ELASTOPWUPALT:
+            DoElastoModePowerup ();
+            break;
+
+        case RESTARTGAME:
+        case RESTARTGAMEALT:
+            RestartNormal ();
+            break;
+
+        case HURTPLAYER:
+        case HURTPLAYERALT:
+            HurtPlayer ();
+            break;
+
+        case TOMHALLMODE:
+        case TOMHALLMODEALT:
+            gamestate.autorun = true;
+            AddMessage("Autorun enabled!",MSG_CHEAT);
+            break;
+
+        case NORMAL:
+        case NORMALALT:
+            DoNormalThing ();
+            break;
+
+        case LIGHTDIMON:
+        case LIGHTDIMONALT:
+            SetLightDiminish (false);
+            break;
+
+        case LIGHTDIMOFF:
+        case LIGHTDIMOFFALT:
+            SetLightDiminish (true);
+            break;
+
+        case FOGON:
+        case FOGONALT:
+            SetFog (true);
+            break;
+
+        case FOGOFF:
+        case FOGOFFALT:
+            SetFog (false);
+            break;
+
+        case QUITGAME:
+        case QUITGAMEALT:
+            QuitGame ();
+            break;
+
+        case ENDLEVEL:
+        case ENDLEVELALT:
+            EndLevel ();
+            break;
+
+        case FANDCOFF:
+        case FANDCOFFALT:
+            FloorandCeiling (false);
+            break;
+
+        case FANDCON:
+        case FANDCONALT:
+            FloorandCeiling (true);
+            break;
+
+
+        case AIMCROSS:
+        case AIMCROSSALT:
+            if (iG_aimCross == 0) {
+                iG_aimCross = 1;
+                AddMessage("Crosshair on",MSG_GAME);
+            } else {
+                iG_aimCross = 0;
+                AddMessage("Crosshair off",MSG_GAME);
+            }
+            break;
+
+
+        case BULLETARMOR:
+        case BULLETARMORALT:
+            GiveBulletProofArmor ();
+            break;
+
+        case FIREARMOR:
+        case FIREARMORALT:
+            GiveAsbestoArmor ();
+            break;
+
+        case GASMASK:
+        case GASMASKALT:
+            GiveGasMask ();
+            break;
+
+        case OUTFIT:
+        case OUTFITALT:
+            OutfitPlayer ();
+            break;
+
+        case KILLPLAYER:
+        case KILLPLAYERALT:
+            KillPlayer ();
+            break;
+
+        case RESTARTLEVEL:
+        case RESTARTLEVELALT:
+            RestartCurrentLevel ();
+            break;
+
+
+        case WEAPONTWOPISTOL:
+        case WEAPONTWOPISTOLALT:
+            WeaponCheat(wp_twopistol);
+            break;
+
+        case WEAPONMP40:
+        case WEAPONMP40ALT:
+            WeaponCheat(wp_mp40);
+            break;
+
+        case WEAPONBAZOOKA:
+        case WEAPONBAZOOKAALT:
+            WeaponCheat(wp_bazooka);
+            break;
+        case WEAPONFIREBOMB:
+        case WEAPONFIREBOMBALT:
+            WeaponCheat(wp_firebomb);
+            break;
+
+        case WEAPONHEAT:
+        case WEAPONHEATALT:
+            WeaponCheat(wp_heatseeker);
+            break;
+
+        case WEAPONDRUNK:
+        case WEAPONDRUNKALT:
+            WeaponCheat(wp_drunk);
+            break;
+
+        case WEAPONFIREWALL:
+        case WEAPONFIREWALLALT:
+            WeaponCheat(wp_firewall);
+            break;
+
+        case WEAPONGOD:
+        case WEAPONGODALT:
+            WeaponCheat(wp_godhand);
+            break;
+
+
+#if (SHAREWARE == 0)
+
+        case WEAPONSPLIT:
+        case WEAPONSPLITALT:
+            WeaponCheat(wp_split);
+            break;
+
+        case WEAPONKES:
+        case WEAPONKESALT:
+            WeaponCheat(wp_kes);
+            break;
+
+        case WEAPONBAT:
+        case WEAPONBATALT:
+            WeaponCheat(wp_bat);
+            break;
+
+        case WEAPONDOG:
+        case WEAPONDOGALT:
+            WeaponCheat(wp_dog);
+            break;
+#endif
+
+        case MISSILECAMTOGGLE:
+        case MISSILECAMTOGGLEALT:
+            ToggleMissileCam();
+            break;
+
+        case HUDTOGGLE:
+        case HUDTOGGLEALT:
+            ToggleHUD();
+            break;
+
+        case ROTATIONFUN:
+            ShutdownClientControls();
+            RotationFun();
+            StartupClientControls();
+            SetupScreen( true );
+            break;
+        case DEMORECORD:
+            RecordDemoQuery();
+            break;
+        case DEMOEND:
+            EndDemo();
+            break;
+        case DEMOPLAYBACK:
+            PlaybackDemoQuery();
+            break;
+        case CRAZYGIBS:
+            if (gamestate.violence == vl_excessive)
+            {
+
+                ludicrousgibs ^= 1;
+                if (ludicrousgibs == true)
+                    AddMessage("EKG mode on!",MSG_GAME);
+                else
+                    AddMessage("EKG mode off!",MSG_GAME);
+            }
+            break;
+
+        case JUKEBOX:
+        case JUKEBOXALT:
+            DoJukeBox();
+            break;
+        case MAPCHEAT:
+        case MAPCHEATALT:
+            DoMapCheat();
+            break;
+        case RICOCHETING:
+        case RICOCHETINGALT:
+            ricochetingRocketsEnabled ^= 1;
+            if (ricochetingRocketsEnabled)
+                AddMessage("Ricocheting Rockets \\cEnabled!", MSG_CHEAT);                
+            else
+                AddMessage("Ricocheting Rockets \\cDisabled!", MSG_CHEAT);
+        }
+    }
+}
+
+
+/*
+================
+=
+= CheckDebug ()
+=
+================
+*/
+
+void CheckDebug (void)
+{
+    int which;
+    if (DebugOk == false)
+    {
+        CheckCode (0);      // Check for Debug switch only
+        CheckCode (1);      // Check for Debug switch only
+        CheckCode (2);      // Check for Slacker pack
+        CheckCode (3);      // Check for Slacker pack
+    }
+    else
+    {
+        if (demoplayback==true)
+        {
+            return;
+        }
+        else if (demorecord==true)
+        {
+            CheckCode (DEMORECORD);
+            CheckCode (DEMOEND);
+        }
+        else
+        {
+            for (which = 0; which < MAXCODES; which++) // Check all debug codes
+                CheckCode (which);
+        }
+    }
+}
--- /dev/null
+++ b/rott/rt_debug.h
@@ -1,0 +1,34 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+#ifndef _rt_debug_public
+#define _rt_debug_public
+
+//***************************************************************************
+//
+// RT_DEBUG.C
+//
+//***************************************************************************
+
+void ResetCheatCodes (void);
+int  DebugKeys (void);
+void CheckDebug (void);
+void EndDemo ( void );
+
+#endif
--- /dev/null
+++ b/rott/rt_def.h
@@ -1,0 +1,544 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+#ifndef _rt_def_public
+#define _rt_def_public
+
+
+// RT_DEF.H Zee big one
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "develop.h"
+#define SAVE_SCREEN  1
+
+#if PLATFORM_UNIX
+#include <unistd.h>
+#include <sys/types.h>
+#include <limits.h>
+#include <dirent.h>
+#include <ctype.h>
+#endif
+
+#if (defined _MSC_VER)
+/* __int64 is built in. */
+#include <malloc.h>
+#include <fcntl.h>
+#include <io.h>
+//#define alloca(x) _alloca(x)
+#define access(x, y) _access(x, y)
+#define F_OK  0
+#elif (defined __GNUC__)
+#define __int64 long long
+#else
+#error please define your platform.
+#endif
+
+#if PLATFORM_DOS || PLATFORM_WIN32
+#define PATH_SEP_CHAR '\\'
+#define PATH_SEP_STR  "\\"
+#elif PLATFORM_UNIX
+#define PATH_SEP_CHAR '/'
+#define PATH_SEP_STR  "/"
+#define ROOTDIR       "/"
+#define CURDIR        "./"
+#elif PLATFORM_MACCLASSIC
+#define PATH_SEP_CHAR ':'
+#define PATH_SEP_STR  ":"
+#else
+#error please define your platform.
+#endif
+
+#if (!defined MAX_PATH)
+#if (defined MAXPATHLEN)
+#define MAX_PATH MAXPATHLEN
+#elif (defined PATH_MAX)
+#define MAX_PATH PATH_MAX
+#else
+#define MAX_PATH 256
+#endif
+#endif
+
+//
+//
+//
+//***************************************************************************
+//
+//    Global Constants
+//
+//***************************************************************************
+
+#ifndef DATADIR
+#define DATADIR	""
+#endif
+
+#undef PI
+#undef M_PI
+
+#ifndef NULL
+#define NULL       0
+#endif
+
+#define PI      3.141592657
+#define LONG(a) ((int)a)
+#define M_PI            3.14159
+
+#ifndef O_BINARY
+#define O_BINARY 0
+#endif
+
+#ifndef O_TEXT
+#define O_TEXT 0
+#endif
+
+#ifndef min
+#define min(a, b)  (((a) < (b)) ? (a) : (b))
+#endif
+
+#ifndef max
+#define max(a, b)  (((a) > (b)) ? (a) : (b))
+#endif
+
+#if !PLATFORM_DOS
+#if PLATFORM_WIN32
+#define strcmpi(x, y) stricmp(x, y)
+#define _fstricmp(x, y) stricmp(x, y)
+#elif PLATFORM_UNIX
+#ifndef strcmpi
+#define strcmpi(x, y) strcasecmp(x, y)
+#endif
+
+#ifndef stricmp
+#define stricmp(x, y) strcasecmp(x, y)
+#endif
+
+#ifndef _fstricmp
+#define _fstricmp(x, y) strcasecmp(x, y)
+#endif
+
+char *strupr(char *);
+char *itoa(int, char *, int);
+char *ltoa(long, char *, int);
+char *ultoa(unsigned long, char *, int);
+char getch(void);
+long filelength(int handle);
+#else
+#error please define for your platform.
+#endif
+
+#if !defined(ANSIESC)
+#define STUB_FUNCTION fprintf(stderr,"STUB: %s at " __FILE__ ", line %d, thread %d\n",__FUNCTION__,__LINE__,getpid())
+#else
+#define STUB_FUNCTION
+#endif
+
+#define far
+#define cdecl
+#endif
+
+//***************************************************************************
+//
+//    Screen Constants
+//
+//***************************************************************************
+#define VIEWGLOBAL              0x10000         // globals visable flush to wall
+/*
+#define VIEWWIDTH               MAXSCREENWIDTH//320*2             // size of view window
+#define VIEWHEIGHT              MAXSCREENHEIGHT//200*2
+#define MAXSCANLINES            MAXSCREENHEIGHT//200*2             // size of ylookup table
+*/
+#define CHARWIDTH               2
+#define TILEWIDTH               4
+#define STATUSLINES             16
+
+
+
+//***************************************************************************
+//
+//    Engine Constants
+//
+//***************************************************************************
+
+#define ANGLES                            2048 // must be divisible by 4
+#define ANGLEQUAD                         (ANGLES/4)
+#define FINEANGLES                        2048
+#define FINEANGLEQUAD                     (FINEANGLES/4)
+#define ANG90                             (FINEANGLES/4)
+#define ANG180                            (ANG90*2)
+#define ANG270                            (ANG90*3)
+#define ANG360                            (ANG90*4)
+#define VANG90                            (ANGLES/4)
+#define VANG180                           (VANG90*2)
+#define VANG270                           (VANG90*3)
+#define VANG360                           (VANG90*4)
+#define ANGLESDIV8                        (ANGLES/8)
+#define MINDIST                           (0x5800l)
+#define PIXRADIUS                         512
+#define FOCALLENGTH                       (0x5700l)             // in global coordinates
+#define MAXTICS                           10
+
+//***************************************************************************
+//
+//    Map Constants/ macros
+//
+//***************************************************************************
+
+
+#define GLOBAL1                           (1l<<16)
+#define TILEGLOBAL                        GLOBAL1
+#define PIXGLOBAL                         (GLOBAL1/64)
+#define TILESHIFT                         16l
+#define UNSIGNEDSHIFT                     8
+#define PLAYERSIZE                        0x5700l                       // player radius
+#define MAPSIZE                           128                         // maps are 64*64 max
+#define NUMAREAS                          47
+#define MAPSPOT(x,y,plane)                (mapplanes[plane][MAPSIZE*(y)+(x)])
+#define AREATILE                          107
+#define ICONARROWS                        72
+#define PUSHABLETILE                      80
+#define ELEVATORTILE                      72
+#define ALTELEVATORTILE                   106
+#define LASTLEVELVALUE                    459
+
+#define AREANUMBER(x,y)                   (MAPSPOT((x),(y),0)-AREATILE)
+
+//***************************************************************************
+//
+//    Scale Constants
+//
+//***************************************************************************
+
+#define SFRACBITS 16
+#define SFRACUNIT (0x10000)
+#define FRACUNIT (0x100)
+
+//***************************************************************************
+//
+//    Actor Constants
+//
+//***************************************************************************
+
+#define RUNSPEED                6000
+#define MINACTORDIST            0x9000l
+#define MAXSTATS                400                           // max number of lamps, bonus, etc
+
+#define MAXWALLTILES            105          // max number of wall tiles
+#define MAXACTORS               600
+#define NORTH                   0
+#define EAST                    1
+#define SOUTH                   2
+#define WEST                    3
+
+//***************************************************************************
+//
+//    Input Defines - joystick, keyboard and mouse
+//
+//***************************************************************************
+
+#define MaxJoys            2
+#define MaxKbds            2
+#define MaxJoys            2
+#define NumCodes           128
+
+// Key definitions
+
+#define  key_None    0
+#define  key_Return     0x0d
+#define  key_Enter      key_Return
+#define  key_Escape     0x1b
+#define  key_Space      0x20
+#define  key_BackSpace  0x08
+#define  key_Tab        0x09
+#define  key_Delete     0x7f
+
+#define  ANGLEBITS      16
+#define  ANGLEFRACMAX   (FINEANGLES<<ANGLEBITS)
+
+
+//***************************************************************************
+//
+//    SWIFT Constants
+//
+//***************************************************************************
+
+//
+// device type codes, returned in deviceType field (SWIFT_StaticData)
+//
+#define SWIFT_DEV_NONE		0
+#define SWIFT_DEV_CYBERMAN	1
+
+//
+// Dynamic device data
+//
+#define SDD_EXTERNAL_POWER_CONNECTED	1
+#define SDD_EXTERNAL_POWER_TOO_HIGH	   2
+
+#define AX(r) ((r).x.eax)
+#define BX(r) ((r).x.ebx)
+#define CX(r) ((r).x.ecx)
+#define DX(r) ((r).x.edx)
+#define SI(r) ((r).x.esi)
+#define DI(r) ((r).x.edi)
+
+//***************************************************************************
+//
+//    Global Types
+//
+//***************************************************************************
+
+///////////////////      GLOBAL DATA TYPES ///////////////////////////////
+
+
+typedef unsigned char           byte;
+typedef unsigned short int      word;
+typedef unsigned int            longword;
+typedef int fixed;
+
+
+//////////////////////////////////////////////////////////////////////////
+
+
+//////////////////      GLOBAL ENUMERATED TYPES    ///////////////////////
+
+#ifdef __WATCOMC__
+typedef enum
+{   false,
+    true
+}
+boolean;
+#else
+/* boolean is serialized at the moment, and watcomc made it a byte. */
+
+typedef unsigned char boolean;
+enum {
+    false, true
+};
+#endif
+
+
+
+
+typedef enum {
+    east,
+    northeast,
+    north,
+    northwest,
+    west,
+    southwest,
+    south,
+    southeast,
+    nodir
+} dirtype;
+
+typedef enum
+{   SPRITE,
+    WALL,
+    ACTOR,
+    DOOR,
+    PWALL,
+    MWALL
+}
+thingtype;
+
+#define NUMTXBUTTONS    16
+enum    {
+    bt_nobutton=-1,
+    bt_attack=0,
+    bt_strafe=1,
+    bt_run=2,
+    bt_use=3,
+    bt_lookup=4,
+    bt_lookdown=5,
+    bt_swapweapon=6,
+    bt_dropweapon=7,
+    bt_horizonup=8,
+    bt_horizondown=9,
+    bt_pistol=10,
+    bt_dualpistol=11,
+    bt_mp40=12,
+    bt_missileweapon=13,
+    bt_autorun=14,
+    bt_recordsound=15,
+    bt_strafeleft=16,
+    bt_straferight=17,
+    bt_turnaround=18,
+    bt_aimbutton=19,
+    di_north=20,
+    di_east=21,
+    di_south=22,
+    di_west=23,
+    bt_map=24,
+    bt_message=25,
+    bt_directmsg=26,
+    NUMBUTTONS
+};
+
+
+#if (SHAREWARE == 0)
+#define MAXWEAPONS  13
+#else
+#define MAXWEAPONS  9
+#endif
+
+
+typedef enum    { wp_pistol,
+                  wp_twopistol,
+                  wp_mp40,
+                  wp_bazooka,
+                  wp_heatseeker,
+                  wp_drunk,
+                  wp_firebomb,
+                  wp_firewall,
+                  wp_godhand,
+
+#if (SHAREWARE == 0)
+                  wp_split,
+                  wp_kes,
+                  wp_bat,
+                  wp_dog
+#endif
+
+                } weapontype;
+
+
+
+enum    {
+    gd_baby,
+    gd_easy,
+    gd_medium,
+    gd_hard
+};
+
+
+typedef enum    {
+    ex_stillplaying,
+    ex_completed,
+    ex_died,
+    ex_warped,
+    ex_resetgame,
+    ex_loadedgame,
+    ex_victorious,
+    ex_abort,
+    ex_demodone,
+    ex_skiplevel,
+    ex_secretlevel,
+    ex_secretdone,
+    ex_titles,
+    ex_demorecord,
+    ex_demoplayback,
+
+    ex_bossdied,
+    ex_gameover,
+    ex_battledone
+} exit_t;
+
+// Types for cache lumps (for endian converters)
+enum    {
+    cache_other,
+    cache_pic_t,
+    cache_lpic_t,
+    cache_font_t,
+    cache_lbm_t,
+    cache_patch_t,
+    cache_transpatch_t,
+    cache_cfont_t
+};
+
+////////////////////////////////////////////////////////////////////////////
+
+/////////////////      GLOBAL STRUCTURE TYPES     //////////////////////////
+
+
+//=================== SHARED FLAGS =====================================//
+
+#define FL_SHOOTABLE            0x01
+#define FL_ACTIVE               0x02
+#define FL_VISIBLE              0x08
+#define FL_NOFRICTION           0x100 //
+#define FL_DYING                0x1000
+#define FL_ALTERNATE            0x20000
+#define FL_GODSTRUCK            0x80000
+#define FL_ABP                  0x400000
+#define FL_BLOCK                0x800000
+#define FL_HBM                  0x1000000
+#define FL_RIDING               0x2000000
+#define FL_SOLIDCOLOR           0x4000000
+#define FL_SEEN                 0x8000000
+#define FL_COLORED              0x10000000
+#define FL_FULLLIGHT       0x80000000
+
+//=================== ACTOR FLAGS =====================================//
+
+#define FL_NEVERMARK            4
+#define FL_ATTACKMODE           0x10
+#define FL_FIRSTATTACK          0x20
+#define FL_ISFIRE               0x20
+#define FL_AMBUSH               0x40
+#define FL_NONMARK              0x80
+#define FL_DONE                 0x200 // used by push column
+#define FL_DODGE                0x400 // "
+#define FL_STUCK                0x800 //
+#define FL_HASAUTO              0x2000
+#define FL_FALLINGOBJECT        0x4000
+#define FL_KEYACTOR             0x8000
+#define FL_HEAD                 0x40000
+#define FL_TARGET               0x200000
+#define FL_FLIPPED              0x40000000
+#define FL_CRAZY                0x40000000
+
+
+//================== PLAYER FLAGS ======================================//
+
+#define FL_BPV                  0x10
+#define FL_SHROOMS              0x20
+#define FL_AV                   0x40
+#define FL_ELASTO               0x200
+#define FL_FLEET                0x400
+#define FL_PUSHED               0x2000
+#define FL_PAIN                 0x4000
+#define FL_GODMODE              0x8000
+#define FL_DOGMODE              0x10000
+#define FL_GASMASK              0x100000
+#define FL_DESIGNATED           0x20000000
+#define FL_DIDTAG               0x40000000
+
+//================== SPRITE FLAGS ======================================//
+
+#define NOTHING                 -1
+#define FL_BONUS                0x04
+#define FL_LIGHT                0x20
+#define FL_CHANGES              0x40
+#define FL_BACKWARDS            0x100
+#define FL_BANDF                0x200
+#define FL_HEAT                 0x400
+#define FL_LIGHTOFF             0x800
+#define FL_ACTOR                0x1000
+#define FL_ROTATING             0x2000
+#define FL_RESPAWN              0x4000
+#define FL_WOODEN               0x8000
+#define FL_METALLIC             0x10000
+#define FL_EARTHEN              0x20000
+#define FL_LIGHTON              0x40000
+#define FL_FADING               0x80000
+#define FL_DEADBODY             0x100000
+#define FL_WEAPON               0x200000
+#define FL_TRANSLUCENT          0x2000000
+#define FL_HEIGHTFLIPPABLE      0x40000000
+
+#endif
--- /dev/null
+++ b/rott/rt_dmand.c
@@ -1,0 +1,400 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+
+#ifdef DOS
+#include <mem.h>
+#endif
+
+#include "rt_def.h"
+#include "rt_util.h"
+#include "rt_sound.h"
+#include "rt_net.h"
+#include "rt_dmand.h"
+#include "_rt_dman.h"
+#include "fx_man.h"
+#include "develop.h"
+//MED
+#include "memcheck.h"
+
+static boolean Recording=false;
+static boolean Feeder=false;
+static byte * RecordingBuffer;
+static int Playingvoice;
+static int RecordingPointer;
+static int FeederPointer;
+static boolean Playback=false;
+static boolean Playing=false;
+static byte * PlaybackBuffer;
+static int PlaybackPointer;
+static int PlayingPointer;
+static boolean RecordingSemaphore=false;
+
+//#define FX_StartDemandFeedPlayback MV_StartDemandFeedPlayback
+//#define FX_StartRecording          MV_StartRecording
+//#define FX_StopRecord              MV_StopRecord
+//#include "multivoc.h"
+
+//***************************************************************************
+//
+// SD_UpdatePlaybackSound - Update playback of a sound in chunks
+//
+//***************************************************************************
+void SD_UpdatePlaybackSound ( char ** ptr, unsigned long * length )
+{
+    if ( Playing==false )
+    {
+        *ptr = NULL;
+        *length = 0;
+        return;
+    }
+    if (PlayingPointer==PlaybackPointer)
+    {
+        *ptr = NULL;
+        *length = 0;
+        if (Playback==false)
+        {
+            FX_StopSound( Playingvoice );
+            SafeFree ( PlaybackBuffer );
+            Playing=false;
+        }
+        return;
+    }
+
+    *length=PLAYBACKDELTASIZE;
+
+    if (PlayingPointer==-1)
+    {
+        *ptr = NULL;
+        *length = 0;
+        return;
+    }
+
+    *ptr=&PlaybackBuffer[PlayingPointer];
+
+    PlayingPointer = (PlayingPointer + *length) &
+                     (PLAYBACKBUFFERSIZE - 1);
+}
+
+//***************************************************************************
+//
+// SD_StartIncomingSound - Setup to receive an incoming sound in chunks
+//
+//***************************************************************************
+
+void SD_StartIncomingSound ( void )
+{
+    if (SD_Started==false)
+        return;
+    if ( ( Recording==true ) || ( Playback==true ) )
+    {
+        return;
+    }
+
+    Playback=true;
+    PlaybackBuffer = SafeMalloc (PLAYBACKBUFFERSIZE);
+    Playing = false;
+    PlayingPointer = -1;
+    PlaybackPointer = 0;
+
+    Playingvoice = FX_StartDemandFeedPlayback ( SD_UpdatePlaybackSound,
+                   RECORDINGSAMPLERATE,
+                   0, 255, 255, 255, 255, -1);
+    if (Playingvoice==0)
+    {
+        SafeFree(PlaybackBuffer);
+        Playback=false;
+    }
+}
+
+//***************************************************************************
+//
+// SD_StopIncomingSound - Stop receiving an incoming sound and playback
+//
+//***************************************************************************
+
+void SD_StopIncomingSound ( void )
+{
+    if (SD_Started==false)
+        return;
+    Playback=false;
+}
+
+
+//***************************************************************************
+//
+// SD_UpdateIncomingSound - Update an incoming sound
+//
+//***************************************************************************
+
+void SD_UpdateIncomingSound ( byte * ptr, word length )
+{
+    int amount;
+
+    if (SD_Started==false)
+        return;
+
+    if ( Playback==false )
+    {
+        return;
+    }
+    amount=length;
+    if (PlaybackPointer+length > PLAYBACKBUFFERSIZE)
+        amount=PLAYBACKBUFFERSIZE-PlaybackPointer;
+    memcpy ( &PlaybackBuffer[PlaybackPointer],
+             ptr, amount);
+    PlaybackPointer = (PlaybackPointer + amount) &
+                      (PLAYBACKBUFFERSIZE - 1);
+
+    ptr+=amount;
+
+    if (length!=amount)
+    {
+        amount=length-amount;
+        memcpy ( &PlaybackBuffer[PlaybackPointer],
+                 ptr, amount);
+        PlaybackPointer = (PlaybackPointer + amount) &
+                          (PLAYBACKBUFFERSIZE - 1);
+    }
+
+    if (PlayingPointer==-1)
+    {
+        Playing=true;
+        PlayingPointer=0;
+    }
+    if (PlaybackPointer==PlayingPointer)
+    {
+        Playback=false;
+    }
+}
+
+//***************************************************************************
+//
+// SD_UpdateRecordingSound - Update recording a sound in chunks
+//
+//***************************************************************************
+extern int whereami;
+void SD_UpdateRecordingSound ( char * ptr, int length )
+{
+    int amount;
+
+    whereami = 69;
+    if ( Recording==false )
+    {
+        return;
+    }
+    whereami = 70;
+    amount=length;
+    if (RecordingPointer+length > RECORDINGBUFFERSIZE)
+        amount=RECORDINGBUFFERSIZE-RecordingPointer;
+    memcpy ( &RecordingBuffer[RecordingPointer],
+             ptr, amount);
+    whereami = 71;
+    RecordingPointer = (RecordingPointer + amount) &
+                       (RECORDINGBUFFERSIZE - 1);
+
+    if (length!=amount)
+    {
+        ptr += amount;
+        amount=length-amount;
+        memcpy ( &RecordingBuffer[RecordingPointer],
+                 ptr, amount);
+        RecordingPointer = (RecordingPointer + amount) &
+                           (RECORDINGBUFFERSIZE - 1);
+    }
+    whereami = 72;
+    if (Feeder == false)
+    {
+        Feeder = true;
+    }
+
+    whereami = 73;
+    if (RecordingPointer==FeederPointer)
+    {
+        Recording=false;
+    }
+    whereami = 74;
+}
+
+//***************************************************************************
+//
+// SD_StartRecordingSound - Start recording a sound in chunks
+//
+//***************************************************************************
+
+boolean SD_StartRecordingSound ( void )
+{
+    int status;
+
+    if (SD_Started==false)
+        return false;
+    if (remoteridicule == false)
+        return false;
+    if ( ( Recording==true ) || ( Playback==true ) || (Feeder==true))
+    {
+        return false;
+    }
+    Recording=true;
+    RecordingBuffer = SafeMalloc (RECORDINGBUFFERSIZE);
+    Feeder = false;
+    FeederPointer = -1;
+    RecordingPointer = 0;
+
+    status=FX_StartRecording( RECORDINGSAMPLERATE, SD_UpdateRecordingSound);
+
+    if (status!=FX_Ok)
+    {
+        Recording=false;
+        SafeFree(RecordingBuffer);
+        return false;
+    }
+
+    return true;
+}
+
+//***************************************************************************
+//
+// SD_StopRecordingSound - Stop recording a sound
+//
+//***************************************************************************
+
+void SD_StopRecordingSound ( void )
+{
+    if (SD_Started==false)
+        return;
+    if (Recording == true)
+    {
+        FX_StopRecord();
+        Recording=false;
+    }
+}
+
+//***************************************************************************
+//
+// SD_SetRecordingActive - Set the recording active flag
+//
+//***************************************************************************
+
+void SD_SetRecordingActive ( void )
+{
+    RecordingSemaphore=true;
+}
+
+//***************************************************************************
+//
+// SD_ClearRecordingActive - Clear the recording active flag
+//
+//***************************************************************************
+
+void SD_ClearRecordingActive ( void )
+{
+    RecordingSemaphore=false;
+}
+
+//***************************************************************************
+//
+// SD_RecordingActive - Check if recording is active on some system
+//
+//***************************************************************************
+
+boolean SD_RecordingActive ( void )
+{
+    return RecordingSemaphore;
+}
+
+//***************************************************************************
+//
+// SD_GetSoundData - Returns next piece of sound data, returns:
+//
+//                   nodata if no sound data is ready
+//                   newsound if it is the start of a new sound
+//                            data is also returned;
+//                   endsound if the sound is finished
+//                   data if data is ready
+//
+//***************************************************************************
+
+recordstate SD_GetSoundData ( byte * data, word length )
+{
+    recordstate status=rs_data;
+    int amount;
+
+    if (SD_Started==false)
+        return rs_nodata;
+
+    if (Feeder==false)
+        return rs_nodata;
+
+    if (FeederPointer==RecordingPointer)
+    {
+        if (Recording==false)
+        {
+            SafeFree(RecordingBuffer);
+            Feeder=false;
+            return rs_endsound;
+        }
+        else
+        {
+            return rs_nodata;
+        }
+    }
+
+    if (FeederPointer==-1)
+    {
+        status=rs_newsound;
+        FeederPointer=0;
+    }
+
+    amount=length;
+
+    if (FeederPointer+length > RECORDINGBUFFERSIZE)
+        amount=RECORDINGBUFFERSIZE-FeederPointer;
+    memcpy ( data, &RecordingBuffer[FeederPointer], amount);
+
+    FeederPointer = (FeederPointer + amount) &
+                    (RECORDINGBUFFERSIZE - 1);
+
+    data += amount;
+
+    if (length!=amount)
+    {
+        amount=length-amount;
+        memcpy ( data, &RecordingBuffer[FeederPointer], amount);
+        FeederPointer = (FeederPointer + amount) &
+                        (RECORDINGBUFFERSIZE - 1);
+    }
+
+    return status;
+}
+
+//***************************************************************************
+//
+// SD_SoundDataReady - Returns true if data is ready
+//
+//***************************************************************************
+
+boolean SD_SoundDataReady ( void )
+{
+    if (SD_Started==false)
+        return false;
+    return Feeder;
+}
+
+
+
--- /dev/null
+++ b/rott/rt_dmand.h
@@ -1,0 +1,114 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+#ifndef _rt_dmand_public
+#define _rt_dmand_public
+
+typedef enum {
+    rs_nodata,
+    rs_newsound,
+    rs_endsound,
+    rs_data
+} recordstate;
+
+//***************************************************************************
+//
+// SD_StartIncomingSound - Setup to receive an incoming sound in chunks
+//
+//***************************************************************************
+
+void SD_StartIncomingSound ( void );
+
+//***************************************************************************
+//
+// SD_StopIncomingSound - Stop receiving an incoming sound and playback
+//
+//***************************************************************************
+
+void SD_StopIncomingSound ( void );
+
+//***************************************************************************
+//
+// SD_UpdateIncomingSound - Update an incoming sound
+//
+//***************************************************************************
+
+void SD_UpdateIncomingSound ( byte * data, word length );
+
+//***************************************************************************
+//
+// SD_GetSoundData - Returns next piece of sound data, returns:
+//
+//                   nodata if no sound data is ready
+//                   newsound if it is the start of a new sound
+//                            data is also returned;
+//                   data if data is ready
+//
+//***************************************************************************
+
+recordstate SD_GetSoundData ( byte * data, word length );
+
+//***************************************************************************
+//
+// SD_SoundDataReady - Returns true if data is ready
+//
+//***************************************************************************
+
+boolean SD_SoundDataReady ( void );
+
+//***************************************************************************
+//
+// SD_SetRecordingActive - Set the recording active flag
+//
+//***************************************************************************
+
+void SD_SetRecordingActive ( void );
+
+//***************************************************************************
+//
+// SD_ClearRecordingActive - Clear the recording active flag
+//
+//***************************************************************************
+
+void SD_ClearRecordingActive ( void );
+
+//***************************************************************************
+//
+// SD_RecordingActive - Check if recording is active on some system
+//
+//***************************************************************************
+
+boolean SD_RecordingActive ( void );
+
+//***************************************************************************
+//
+// SD_StartRecordingSound - Start recording a sound in chunks
+//
+//***************************************************************************
+
+boolean SD_StartRecordingSound ( void );
+
+//***************************************************************************
+//
+// SD_StopRecordingSound - Stop recording a sound
+//
+//***************************************************************************
+void SD_StopRecordingSound ( void );
+
+#endif
--- /dev/null
+++ b/rott/rt_door.c
@@ -1,0 +1,4421 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+#include "rt_def.h"
+#include "rt_sound.h"
+#include "rt_door.h"
+#include "rt_actor.h"
+#include "rt_stat.h"
+#include "_rt_door.h"
+#include "z_zone.h"
+#include "w_wad.h"
+#include "rt_ted.h"
+#include "rt_draw.h"
+#include "rt_main.h"
+#include "rt_playr.h"
+#include "rt_util.h"
+#include "rt_menu.h"
+#include "rt_ted.h"
+#include "rt_msg.h"
+#include "rt_game.h"
+#include "rt_vid.h"
+#include "rt_net.h"
+#include "isr.h"
+#include "develop.h"
+#include "rt_rand.h"
+#include "engine.h"
+#include <stdlib.h>
+#include <string.h>
+//MED
+#include "memcheck.h"
+
+/*=============================================================================
+
+							DOORS
+
+doorobjlist[] holds most of the information for the doors
+
+Open doors conect two areas, so sounds will travel between them and sight
+	will be checked when the player is in a connected area.
+
+Areaconnect is incremented/decremented by each door. If >0 they connect
+
+Every time a door opens or closes the areabyplayer matrix gets recalculated.
+	An area is true if it connects with the player's current spor.
+
+=============================================================================
+*/
+
+
+// Global Variables
+
+
+#define ELEVATORMUSICTIME   560
+
+elevator_t     ELEVATOR[MAXELEVATORS];
+int            _numelevators;
+animmaskedwallobj_t* FIRSTANIMMASKEDWALL,*LASTANIMMASKEDWALL;
+maskedwallobj_t* FIRSTMASKEDWALL,*LASTMASKEDWALL;
+byte             touchindices[MAPSIZE][MAPSIZE],lasttouch;
+touchplatetype   *touchplate[MAXTOUCHPLATES],*lastaction[MAXTOUCHPLATES];
+
+byte             numactions[MAXTOUCHPLATES];
+int              totalactions;
+
+byte             TRIGGER[MAXTOUCHPLATES];
+doorobj_t	   *doorobjlist[MAXDOORS];
+int			   doornum;
+maskedwallobj_t *maskobjlist[MAXMASKED];
+int            maskednum;
+
+pwallobj_t     *pwallobjlist[MAXPWALLS];
+int            pwallnum;
+
+byte	         areaconnect[NUMAREAS][NUMAREAS];
+
+boolean	      areabyplayer[NUMAREAS];
+
+
+// Local Variables
+
+static void (*touchactions[NUMTOUCHPLATEACTIONS])(long) =
+{   ActivatePushWall,
+    ActivateMoveWall,
+    LinkedOpenDoor,
+    LinkedCloseDoor,
+    EnableObject,
+    DisableObject,
+    ActivateLight,
+    DeactivateLight
+};
+
+#if ((DEVELOPMENT == 1))
+#if ((LOADSAVETEST == 1))
+static char*touchstrings[NUMTOUCHPLATEACTIONS] =
+{   "ActivatePushWall",
+    "ActivateMoveWall",
+    "LinkedOpenDoor",
+    "LinkedCloseDoor",
+    "EnableObject",
+    "DisableObject",
+    "ActivateLight",
+    "DeactivateLight"
+};
+#endif
+#endif
+#if ((DEVELOPMENT == 1))
+#if ((ELEVATORTEST == 1))
+
+static char*elevstring[NUMELEVATORACTIONS] =
+{   "ready at source",
+    "ready at destination",
+    "moving to source",
+    "moving to destination",
+    "doorclosing"
+};
+#endif
+#endif
+
+void UtilizeDoor (int door,void (*action)(int));
+void UseDoor (int door);
+void Teleport(elevator_t*eptr,int destination);
+void ConnectPushWall (int pwall);
+void SetupPushWall (int pwall);
+void WallMoving (int pwall);
+int SetNextAction(elevator_t*eptr,int action);
+
+/*
+===============
+=
+= MakeMaskedWallActive
+=
+===============
+*/
+
+void MakeMaskedWallActive(maskedwallobj_t* tmwall)
+{   if (!FIRSTMASKEDWALL)
+        FIRSTMASKEDWALL	= tmwall;
+    else
+    {   tmwall->prev = LASTMASKEDWALL;
+        LASTMASKEDWALL->next = tmwall;
+    }
+    LASTMASKEDWALL = tmwall;
+}
+
+/*
+===============
+=
+= MakeMaskedWallInactive
+=
+===============
+*/
+
+
+void MakeMaskedWallInactive(maskedwallobj_t* tmwall)
+{
+    if (tmwall == LASTMASKEDWALL)
+        LASTMASKEDWALL = tmwall->prev;
+    else
+        tmwall->next->prev = tmwall->prev;
+
+    if (tmwall == FIRSTMASKEDWALL)
+        FIRSTMASKEDWALL = tmwall->next;
+    else
+        tmwall->prev->next = tmwall->next;
+
+    tmwall->prev = NULL;
+    tmwall->next = NULL;
+
+}
+
+
+/*
+===============
+=
+= ActivateAnimMaskedWall
+=
+===============
+*/
+
+void ActivateAnimMaskedWall(animmaskedwallobj_t* amwall)
+{
+    if (!FIRSTANIMMASKEDWALL)
+        FIRSTANIMMASKEDWALL	= amwall;
+    else
+    {
+        amwall->prev = LASTANIMMASKEDWALL;
+        LASTANIMMASKEDWALL->next = amwall;
+    }
+    LASTANIMMASKEDWALL = amwall;
+}
+
+/*
+===============
+=
+= DeactivateAnimMaskedWall
+=
+===============
+*/
+
+
+void DeactivateAnimMaskedWall(animmaskedwallobj_t* amwall)
+{
+    if (amwall == LASTANIMMASKEDWALL)
+        LASTANIMMASKEDWALL = amwall->prev;
+    else
+        amwall->next->prev = amwall->prev;
+
+    if (amwall == FIRSTANIMMASKEDWALL)
+        FIRSTANIMMASKEDWALL = amwall->next;
+    else
+        amwall->prev->next = amwall->next;
+
+    amwall->prev = NULL;
+    amwall->next = NULL;
+
+}
+
+
+int PlatformHeight(int tilex,int tiley)
+{
+    int platform;
+
+    if (!IsPlatform(tilex,tiley))
+        return nominalheight;
+
+    platform = MAPSPOT(tilex,tiley,2);
+
+    switch(platform)
+    {
+    case 1:
+        return -10;
+    case 4:
+        return nominalheight;
+    case 5:
+    case 6:
+        return nominalheight - 64;
+    case 7:
+        return nominalheight;
+    case 8:
+    case 9:
+        return -10;
+    }
+
+    return -1000;
+}
+
+void SpawnAnimatedMaskedWall ( int num )
+{
+    animmaskedwallobj_t * temp;
+
+    temp = (animmaskedwallobj_t *)Z_LevelMalloc(sizeof(animmaskedwallobj_t),PU_LEVELSTRUCT,NULL);
+    if (!temp)
+        Error("SpawnAnimatedMaskedWall: Failed on allocation of animated masked wall");
+    temp->num=num;
+    temp->count=AMW_NUMFRAMES;
+    temp->ticcount=AMW_TICCOUNT;
+    temp->next=NULL;
+    temp->prev=NULL;
+    ActivateAnimMaskedWall(temp);
+}
+
+void KillAnimatedMaskedWall ( animmaskedwallobj_t * temp )
+{
+    DeactivateAnimMaskedWall(temp);
+    Z_Free(temp);
+}
+
+
+void DoAnimatedMaskedWalls ( void )
+{
+    boolean done;
+    animmaskedwallobj_t * temp;
+
+    for(temp=FIRSTANIMMASKEDWALL; temp;)
+    {
+        done=false;
+        temp->ticcount-=tics;
+        while (temp->ticcount<0)
+        {
+            temp->ticcount+=AMW_TICCOUNT;
+            temp->count--;
+            maskobjlist[temp->num]->bottomtexture++;
+            if (temp->count==0)
+            {
+                done=true;
+                break;
+            }
+        }
+        if (done==true)
+        {
+            animmaskedwallobj_t * temp2;
+
+            temp2=temp->next;
+            KillAnimatedMaskedWall(temp);
+            temp=temp2;
+        }
+        else
+            temp=temp->next;
+    }
+}
+
+
+int GetIndexForAction(void (*action)(long))
+{   int i;
+
+    for(i=0; i<NUMTOUCHPLATEACTIONS; i++)
+        if (action == touchactions[i])
+            return i;
+
+    Error("Touchplate Action Not Matched");
+    return -1;
+}
+
+
+void SaveTouchPlates(byte ** buffer,int *size)
+{   int i,k;
+    byte * tptr;
+    touchplatetype *temp;
+    saved_touch_type dummy;
+
+    *size = sizeof(TRIGGER);
+    *size += sizeof(numactions);
+    *size += sizeof(saved_touch_type)*totalactions;
+
+    *buffer = (byte *)SafeMalloc(*size);
+    tptr = *buffer;
+    memcpy(tptr,&TRIGGER[0],sizeof(TRIGGER));
+    tptr+=sizeof(TRIGGER);
+
+    memcpy(tptr,&numactions[0],sizeof(numactions));
+    tptr+=sizeof(numactions);
+
+#if ((DEVELOPMENT == 1))
+#if (LOADSAVETEST == 1)
+    Debug("\n\nSAVE INFO\n");
+    Debug("---------");
+
+    Debug("\n\nTOUCHINDICES\n");
+    Debug("------------\n\n");
+    for(i=0; i<MAPSIZE; i++)
+        for(j=0; j< MAPSIZE; j++)
+            if (touchindices[i][j])
+                Debug("\ntouchindices[%3d][%3d]: %d",i,j,touchindices[i][j]);
+
+    Debug("\n\nTRIGGER: ");
+    for(i=0; i<(sizeof(TRIGGER)/sizeof(TRIGGER[0])); i++)
+        if (TRIGGER[i])
+            Debug("%1d",TRIGGER[i]);
+    Debug("\n\nNUMACTIONS PER TOUCHPLATE\n");
+    Debug("-------------------------\n\n");
+    for(i=0; i<(sizeof(numactions)/sizeof(numactions[0])); i++)
+        if (numactions[i])
+            Debug("\n %2d: %2d",i,numactions[i]);
+#endif
+#endif
+
+    for(i=0; i<lasttouch; i++)
+    {
+#if ((DEVELOPMENT == 1))
+#if (LOADSAVETEST == 1)
+        Debug("\n\nTOUCHPLATE[%2d]\n",i);
+        Debug("--------------\n\n");
+#endif
+#endif
+
+        for(k=0,temp=touchplate[i]; temp; k++,temp = temp->nextaction)
+        {
+            dummy.tictime = temp->tictime;
+            dummy.ticcount = temp->ticcount;
+            dummy.triggered = temp->triggered;
+            dummy.done = temp->done;
+            dummy.complete = temp->complete;
+
+            if (temp->action)
+                dummy.actionindex = GetIndexForAction(temp->action);
+            else
+                dummy.actionindex = -1;
+
+            if (temp->swapaction)
+                dummy.swapactionindex = GetIndexForAction(temp->swapaction);
+            else
+                dummy.swapactionindex = -1;
+            if ((dummy.actionindex > 5) || (dummy.swapactionindex > 5)) // means whichobj holds pointer to actor
+            {
+                statobj_t *tstat;
+
+                tstat = (statobj_t*)(temp->whichobj);
+                dummy.whichobj = (tstat->whichstat|FL_TSTAT);
+            }
+
+            else if ((dummy.actionindex > 3) || (dummy.swapactionindex > 3))
+
+            {
+                objtype *tactor;
+
+                tactor = (objtype*)(temp->whichobj);
+                dummy.whichobj = (tactor->whichactor|FL_TACT);
+            }
+
+            else
+                dummy.whichobj = temp->whichobj;
+
+#if ((DEVELOPMENT == 1))
+#if (LOADSAVETEST == 1)
+            Debug("action node %d: tictime: %d, ticcount: %d ",k,dummy.tictime,dummy.ticcount);
+            if (dummy.actionindex == -1)
+                Debug("action: -1,");
+            else
+                Debug("action: %13s,",touchstrings[dummy.actionindex]);
+
+            if (dummy.swapactionindex == -1)
+                Debug("swapaction: -1,");
+            else
+                Debug("swapaction: %13s,",touchstrings[dummy.swapactionindex]);
+
+            if (dummy.whichobj & FL_TACT)
+                Debug("whichobj (actor): %4x\n",(dummy.whichobj & ~FL_TACT));
+            else
+                Debug("whichobj (nonactor): %4x\n",dummy.whichobj);
+#endif
+#endif
+
+
+            memcpy(tptr,&dummy,sizeof(saved_touch_type));
+            tptr+=sizeof(saved_touch_type);
+        }
+    }
+}
+
+statobj_t* GetStatForIndex(int index)
+{   statobj_t *temp;
+
+    for(temp = FIRSTSTAT; temp; temp=temp->statnext)
+        if (temp->whichstat == index)
+            return temp;
+
+    SoftError("\nstat not found in GetStatForIndex");
+    return NULL;
+
+}
+
+
+void LoadTouchPlates(byte * buffer, int size)
+{   touchplatetype *temp;
+    int i,savedactions,loadedactions,index=0;
+    saved_touch_type dummy;
+
+    savedactions = (size-sizeof(TRIGGER)-sizeof(numactions))/sizeof(saved_touch_type);
+    memset(touchplate,0,sizeof(touchplate));
+    memset(lastaction,0,sizeof(lastaction));
+    memset(numactions,0,sizeof(numactions));
+    totalactions = 0;
+
+    memcpy(&TRIGGER[0],buffer,sizeof(TRIGGER));
+    buffer += sizeof(TRIGGER);
+
+    memcpy(&numactions[0],buffer,sizeof(numactions));
+    buffer += sizeof(numactions);
+
+    for(loadedactions=0,index=0,i=0; i<savedactions; i++)
+    {   memcpy(&dummy,buffer,sizeof(saved_touch_type));
+        temp = (touchplatetype*)Z_LevelMalloc(sizeof(touchplatetype),PU_LEVELSTRUCT,NULL);
+        if (!temp)
+            Error("LoadTouchplates: Failed on allocation of touchplates %d of %d",i,savedactions);
+        memset(temp,0,sizeof(*temp));
+
+        temp->tictime = dummy.tictime;
+        temp->ticcount = dummy.ticcount;
+        temp->triggered = dummy.triggered;
+        temp->done = dummy.done;
+        temp->complete = dummy.complete;
+
+        if (dummy.whichobj & FL_TACT)
+            temp->whichobj = (long)(objlist[dummy.whichobj & ~FL_TACT]);
+
+        else if (dummy.whichobj & FL_TSTAT)
+            temp->whichobj = (long)(GetStatForIndex(dummy.whichobj & ~FL_TSTAT));
+        else
+            temp->whichobj = dummy.whichobj;
+        if (dummy.actionindex != -1)
+            temp->action = touchactions[dummy.actionindex];
+        else
+            temp->action = NULL;
+
+        if (dummy.swapactionindex != -1)
+            temp->swapaction = touchactions[dummy.swapactionindex];
+        else
+            temp->swapaction = NULL;
+
+        buffer+=sizeof(saved_touch_type);
+
+        while (!numactions[index])
+            index ++;
+
+        AddTouchplateAction(temp,index);
+
+        /*if (touchplate[index])
+          lastaction[index]->nextaction = temp;
+        else
+          touchplate[index] = temp;
+        lastaction[index] = temp;*/
+
+        totalactions ++;
+
+        loadedactions++;
+        if (loadedactions == numactions[index]) // found end of a touchplate's actions, goto next touch.
+        {   loadedactions = 0;
+            index++;
+        }
+    }
+
+
+#if ((DEVELOPMENT == 1))
+#if (LOADSAVETEST == 1)
+    Debug("\n\nLOAD INFO\n");
+    Debug("---------");
+
+    Debug("\n\nTOUCHINDICES\n");
+    Debug("------------\n\n");
+    for(i=0; i<MAPSIZE; i++)
+        for(j=0; j< MAPSIZE; j++)
+            if (touchindices[i][j])
+                Debug("\ntouchindices[%3d][%3d]: %d",i,j,touchindices[i][j]);
+
+    Debug("\n\nTRIGGER: ");
+    for(i=0; i<(sizeof(TRIGGER)/sizeof(TRIGGER[0])); i++)
+        if (TRIGGER[i])
+            Debug("%1d",TRIGGER[i]);
+    Debug("\n\nNUMACTIONS PER TOUCHPLATE\n");
+    Debug("-------------------------\n\n");
+    for(i=0; i<(sizeof(numactions)/sizeof(numactions[0])); i++)
+        if (numactions[i])
+            Debug("\n %2d: %2d",i,numactions[i]);
+
+    for(i=0; i<lasttouch; i++)
+    {
+        Debug("\n\nTOUCHPLATE[%2d]\n",i);
+        Debug("--------------\n\n");
+
+        for(k=0,temp=touchplate[i]; temp; k++,temp = temp->nextaction)
+        {
+            Debug("action node %d: tictime: %d, ticcount: %d ",k,temp->tictime,temp->ticcount);
+            if (!temp->action)
+                Debug("action: NULL,");
+            else
+                Debug("action: %13s,",touchstrings[GetIndexForAction(temp->action)]);
+
+            if (!temp->swapaction)
+                Debug("swapaction: NULL,");
+            else
+                Debug("swapaction: %13s,",touchstrings[GetIndexForAction(temp->swapaction)]);
+
+            Debug("whichobj: %4x\n",(int)temp->whichobj);
+        }
+    }
+#endif
+#endif
+
+    SafeFree(objlist);
+
+}
+
+
+
+
+void AddTouchplateAction(touchplatetype *tplate,int index)
+{
+    if (touchplate[index])
+    {   tplate->prevaction = lastaction[index];
+        lastaction[index]->nextaction = tplate;
+    }
+    else
+        touchplate[index] = tplate;
+    lastaction[index] = tplate;
+
+}
+
+
+
+
+void  RemoveTouchplateAction(touchplatetype *tplate,int index)
+{
+    if (tplate == lastaction[index])     // remove from master list
+        lastaction[index] = tplate->prevaction;
+    else
+        tplate->nextaction->prevaction = tplate->prevaction;
+
+    if (tplate == touchplate[index])
+        touchplate[index] = tplate->nextaction;
+    else
+        tplate->prevaction->nextaction = tplate->nextaction;
+
+    Z_Free(tplate);
+    numactions[index]--;
+    totalactions--;
+
+}
+
+
+
+void  Link_To_Touchplate(word touchlocx, word touchlocy, void (*maction)(long), void (*swapaction)(long), long wobj, int delaytime)
+{   touchplatetype *temp;
+    int index;
+
+    index = touchindices[touchlocx][touchlocy]-1;
+
+    temp = (touchplatetype*)Z_LevelMalloc(sizeof(touchplatetype),PU_LEVELSTRUCT,NULL);
+    if (!temp)
+        Error("Link_To_Touchplate: Failed on allocation of touchplate\n");
+    memset(temp,0,sizeof(*temp));
+    temp->action = maction;
+    temp->swapaction = swapaction;
+    temp->whichobj = wobj;
+    temp->tictime = temp->ticcount = delaytime;
+
+    AddTouchplateAction(temp,index);
+    /*if(touchplate[index])
+    lastaction[index]->nextaction=temp;
+    else
+    touchplate[index] = temp;
+    lastaction[index] = temp;*/
+    numactions[index]++;
+    totalactions++;
+}
+
+
+
+void ClockLink (void (*saction)(long), void (*eaction)(long), long wobj,int whichclock)
+{   touchplatetype*temp;
+
+
+// adding two actions per clock
+    temp = (touchplatetype*)Z_LevelMalloc(sizeof(touchplatetype),PU_LEVELSTRUCT,NULL);
+    if (!temp)
+        Error("ClockLink: Failed on allocation of clock");
+    memset(temp,0,sizeof(*temp));
+    temp->action = saction;
+    temp->swapaction = eaction;
+    temp->whichobj = wobj;
+    temp->clocktype = 1;
+
+    AddTouchplateAction(temp,whichclock);
+    /*  if(touchplate[whichclock])
+    	lastaction[whichclock]->nextaction = temp;
+      else
+    	touchplate[whichclock] = temp;
+      lastaction[whichclock]=temp;*/
+
+    numactions[whichclock]++;
+    totalactions ++;
+}
+
+
+void DisplayMessageForAction(touchplatetype *temp, boolean *wallmessage,
+                             boolean *doormessage, boolean*columnmessage)
+{
+
+    if ((temp->action == ActivatePushWall) ||
+            (temp->action == ActivateMoveWall)
+       )
+    {
+        if (*wallmessage == false)
+        {
+            if (temp->clocktype)
+                AddMessage("Time-delay wall moves.",MSG_GAME);
+            else
+                AddMessage("A wall moves.",MSG_GAME);
+            *wallmessage = true;
+        }
+    }
+
+    else if (temp->action == LinkedCloseDoor)
+    {
+        if (*doormessage == false)
+        {
+            if (temp->clocktype)
+                AddMessage("Time-delay door closes.",MSG_GAME);
+            else
+                AddMessage("A door closes.",MSG_GAME);
+            *doormessage = true;
+        }
+    }
+
+    else if (temp->action == LinkedOpenDoor)
+    {
+        if (*doormessage == false)
+        {
+            if (temp->clocktype)
+                AddMessage("Time-delay door opens.",MSG_GAME);
+            else
+                AddMessage("A door opens.",MSG_GAME);
+            *doormessage = true;
+        }
+    }
+
+    else if (temp->action == EnableObject)
+    {
+        objtype *tempactor = (objtype*)(temp->whichobj);
+
+        if (M_ISACTOR(tempactor) && (tempactor->obclass == pillarobj))
+        {
+            if (*columnmessage == false)
+            {
+                if (temp->clocktype)
+                    AddMessage("Time-delay column moves.",MSG_GAME);
+                else
+                    AddMessage("A column moves.",MSG_GAME);
+                *columnmessage = true;
+            }
+        }
+    }
+}
+
+void TriggerStuff(void)
+{
+    touchplatetype *temp;
+    int i,touchcomplete,j;
+    int playeron;
+    void (*tempact)(long);
+    boolean wallmessage,doormessage,columnmessage;
+
+    for(i=0; i<lasttouch; i++)
+    {
+        playeron = false;
+        for( j = 0; j < numplayers; j++ )
+        {
+            if ( i == touchindices[ PLAYER[ j ]->tilex ][ PLAYER[ j ]->tiley ] - 1 )
+            {
+                playeron = true;
+                break;
+            }
+        }
+#if (BNACRASHPREVENT == 1)
+        //SetTextMode (  ); qwert
+        //	CRASH IN SHAREWARE 'ride em cowboy' BNA FIX
+        // DONT ALLOW BAD touchplate ( == 0 ) see rt_playr.c
+        if (touchplate[i] == 0) {
+            continue;
+        }
+#endif
+
+        if (!TRIGGER[i])
+            continue;
+
+        else if (touchplate[i]->complete)
+        {
+            if (!playeron)
+                TRIGGER[i] = 0;
+            continue;
+        }
+
+        if (touchplate[i]->done)
+        {
+            if (!playeron)
+            {
+                for(temp = touchplate[i]; temp; temp = temp->nextaction)
+                    temp->triggered=false;
+                TRIGGER[i] = 0;
+                touchplate[i]->done = false;
+            }
+        }
+
+        else
+        {
+            wallmessage = false;
+            doormessage = false;
+            columnmessage = false;
+
+            for(temp = touchplate[i]; temp; temp = temp->nextaction)
+            {
+                if (temp->action && (!temp->triggered))
+                {
+                    if (!temp->ticcount)
+                    {
+                        temp->action(temp->whichobj);
+                        if (temp->action == ActivateMoveWall)
+                        {
+                            int tilex,tiley;
+
+                            tilex = pwallobjlist[temp->whichobj]->tilex;
+                            tiley = pwallobjlist[temp->whichobj]->tiley;
+                            tilemap[tilex][tiley] = 0;
+
+                        }
+                        if (gamestate.difficulty == gd_baby)
+                        {
+                            DisplayMessageForAction(temp,&wallmessage,&doormessage,&columnmessage);
+                        }
+
+                        tempact = temp->action;
+                        temp->action = temp->swapaction;
+                        temp->swapaction = tempact;
+                        temp->ticcount = temp->tictime;
+                        temp->triggered = true;
+                    }
+
+                    else
+                        temp->ticcount --;
+                }
+            }
+            //done:
+
+            // check to see if any actions will ever be triggered by this
+            // touchplate again; if not, null touchplate out; else,
+            // check status of other actions
+
+            touchcomplete = 1;
+            for(temp = touchplate[i]; temp; temp = temp->nextaction)
+            {
+                if (temp->action)
+                {
+                    touchcomplete = 0;
+                    break;
+                }
+            }
+
+            if (touchcomplete)
+                touchplate[i]->complete = 1; // this touchplate is out of commission
+            else
+            {
+                touchplate[i]->done = true;
+                for(temp = touchplate[i]; temp; temp = temp->nextaction)
+                {
+                    if (temp->action && (!temp->triggered))
+                    {
+                        touchplate[i]->done = false;
+                        break;
+                    }
+                }
+            }
+        }
+    }
+}
+
+
+//==================== Tile stuff ====================================
+
+boolean CheckTile(int x, int y)
+{
+
+    if ((x < 2) || (x > (MAPSIZE-1)) || (y < 2) || (y > (MAPSIZE - 1)))
+        return false;
+
+    if (actorat[x][y])
+    {   objtype *check = (objtype*)(actorat[x][y]);
+        if (insetupgame)
+            return false;
+        if (!(M_ISACTOR(check) && (check->obclass == playerobj)))
+            return false;
+    }
+    if (DiskAt(x,y))
+        return false;
+    if (sprites[x][y])
+        return false;
+    if ((tilemap[x][y]) && (IsPlatform(x,y)==false))
+        return false;
+    if ((AREANUMBER(x,y)<=0) || (AREANUMBER(x,y)>NUMAREAS))
+        return false;
+    if (IsWindow(x,y))
+        return false;
+    return true;
+}
+
+
+#define CountTile(x,y) \
+{                       \
+ if (oldarea == AREANUMBER(x,y))\
+    {if (CheckTile(x,y))         \
+        numemptytiles ++;                   \
+                                             \
+     areanumbercount++;                       \
+     if (areanumbercount == numareatiles[oldarea])\
+        return numemptytiles;                     \
+    }                                              \
+                                                    \
+}                                                   \
+
+
+int Number_of_Empty_Tiles_In_Area_Around(int x, int y)
+{   int roverx,rovery,areanumbercount=0,
+                          numemptytiles=0,oldarea,i,limit,j;
+
+    oldarea = AREANUMBER(x,y);
+
+    for (i=1;; i++)
+    {   roverx = x-i;
+        rovery = y-i;
+
+        CountTile(roverx,rovery);
+        limit = i<<1;
+
+        for(j=0; j<limit; j++)
+        {   roverx++;
+            CountTile(roverx,rovery);
+        }
+
+        for(j=0; j<limit; j++)
+        {   rovery++;
+            CountTile(roverx,rovery);
+        }
+
+        for(j=0; j<limit; j++)
+        {   roverx--;
+            CountTile(roverx,rovery);
+        }
+
+        for(j=0; j<limit-1; j++)
+        {   rovery--;
+            CountTile(roverx,rovery);
+        }
+    }
+}
+
+
+
+#define CheckSet(x,y)      \
+{if (CheckTile(x,y) && (oldarea == AREANUMBER(x,y))) \
+   {*stilex = x;    \
+    *stiley = y;    \
+    return;              \
+   } \
+}                     \
+
+
+
+void FindEmptyTile(int *stilex, int *stiley)
+{
+    int i,j,x,y,oldarea,roverx,rovery,limit;
+
+    oldarea = AREANUMBER(*stilex,*stiley);
+
+    x = *stilex;
+    y = *stiley;
+
+    if (CheckTile(x,y) && (oldarea == AREANUMBER(x,y)))
+        return;
+
+    for (i=1;; i++)
+    {   roverx = x-i;
+        rovery = y-i;
+
+        CheckSet(roverx,rovery);
+        limit = i<<1;
+
+        for(j=0; j<limit; j++)
+        {   roverx++;
+            CheckSet(roverx,rovery);
+        }
+
+        for(j=0; j<limit; j++)
+        {   rovery++;
+            CheckSet(roverx,rovery);
+        }
+
+        for(j=0; j<limit; j++)
+        {   roverx--;
+            CheckSet(roverx,rovery);
+        }
+
+        for(j=0; j<limit-1; j++)
+        {   rovery--;
+            CheckSet(roverx,rovery);
+        }
+    }
+}
+
+//================================================================
+
+
+
+
+void RecursiveConnect (int areanumber)
+{
+    int	i;
+
+    for (i=0; i<NUMAREAS; i++)
+    {
+        if (areaconnect[areanumber][i] && !areabyplayer[i])
+        {
+            areabyplayer[i] = true;
+            RecursiveConnect (i);
+        }
+    }
+}
+
+
+/*
+==============
+=
+= ConnectAreas
+=
+= Scans outward from playerarea, marking all connected areas
+=
+==============
+*/
+
+void ConnectAreas (void)
+{   objtype*temp;
+    statobj_t*tstat;
+    int i;
+#define MASTER_DISK(ob) ((ob->obclass == diskobj) && (ob->flags & FL_MASTER))
+
+    memset (areabyplayer,0,sizeof(areabyplayer));
+    for (i=0; i<numplayers; i++)
+    {
+        areabyplayer[PLAYER[i]->areanumber] = true;
+        RecursiveConnect (PLAYER[i]->areanumber);
+    }
+    for(temp=FIRSTACTOR; temp; temp=temp->next)
+    {
+        if (MASTER_DISK(temp))
+            continue;
+        if (!areabyplayer[temp->areanumber])
+            continue;
+        if (!(temp->flags & FL_ABP))
+        {   temp->flags |= FL_ABP;
+            MakeActive(temp);
+        }
+    }
+
+    for(tstat=FIRSTSTAT; tstat; tstat=tstat->statnext)
+    {   if (areabyplayer[tstat->areanumber])
+        {   if (!(tstat->flags & FL_ABP))
+            {   tstat->flags |= FL_ABP;
+                MakeStatActive(tstat);
+            }
+        }
+        else if (tstat->flags & FL_ABP)
+        {   MakeStatInactive(tstat);
+            tstat->flags &= ~FL_ABP;
+        }
+    }
+
+    for(i=0; i<maskednum; i++)
+    {   if (areabyplayer[maskobjlist[i]->areanumber])
+        {   if (!(maskobjlist[i]->flags & MW_ABP))
+            {   maskobjlist[i]->flags |= MW_ABP;
+                MakeMaskedWallActive(maskobjlist[i]);
+            }
+        }
+        else if (maskobjlist[i]->flags & MW_ABP)
+        {   MakeMaskedWallInactive(maskobjlist[i]);
+            maskobjlist[i]->flags &= ~MW_ABP;
+        }
+    }
+}
+
+
+void InitAreas (void)
+{
+    memset (areabyplayer,0,sizeof(areabyplayer));
+    memset (areaconnect,0,sizeof(areaconnect));
+}
+
+
+/*
+===============
+=
+= InitDoorList
+=
+===============
+*/
+
+void InitDoorList (void)
+{
+    doornum=0;
+    pwallnum=0;
+    maskednum=0;
+    lasttouch = 0;
+    numclocks=0;
+
+    memset(touchindices,0,sizeof(touchindices));
+    memset(touchplate,0,sizeof(touchplate));
+    memset(lastaction,0,sizeof(lastaction));
+    memset(numactions,0,sizeof(numactions));
+    totalactions = 0;
+    memset(TRIGGER,0,sizeof(TRIGGER));
+    memset(Clocks,0,sizeof(Clocks));
+    FIRSTMASKEDWALL=NULL;
+    LASTMASKEDWALL=NULL;
+    FIRSTANIMMASKEDWALL=NULL;
+    LASTANIMMASKEDWALL=NULL;
+}
+
+/*
+===============
+=
+= IsWall
+=
+===============
+*/
+
+int IsWall (int tilex, int tiley)
+{
+    int map;
+
+    map=MAPSPOT(tilex,tiley,0);
+
+    if ((map>=1) && (map<=89))
+        return 1;
+
+    else if ((map>=106) && (map<=107))
+        return 1;
+
+    else if ((map>=224) && (map<=233))
+        return 1;
+
+    else if ((map>=242) && (map<=244))
+        return 1;
+
+    return 0;
+}
+
+
+
+/*
+===============
+=
+= InitElevators
+=
+===============
+*/
+
+void InitElevators(void)
+{   _numelevators = 0;
+    memset(ELEVATOR,0,sizeof(ELEVATOR));
+
+}
+
+
+
+/*
+===============
+=
+= IsDoor
+=
+===============
+*/
+
+int IsDoor (int tilex, int tiley)
+{
+    int map;
+
+    map=MAPSPOT(tilex,tiley,0);
+
+    if ((map>=33) && (map<=35))
+        return 1;
+
+    if ((map>=90) && (map<=104))
+        return 1;
+
+    if ((map>=154) && (map<=156))
+        return 1;
+
+    if (M_ISDOOR(tilex,tiley))
+        return 1;
+
+    return 0;
+}
+
+
+/*
+===============
+=
+= SpawnDoor
+=
+===============
+*/
+
+void SpawnDoor (int tilex, int tiley, int lock, int texture)
+{
+    int i;
+    doorobj_t * lastdoorobj;
+    int up,dn,lt,rt;
+    int abovewallstart;
+    int swallstart;
+    int basetexture;
+
+    abovewallstart=W_GetNumForName("ABVWSTRT")+1;
+    swallstart=W_GetNumForName("SIDESTRT")+1;
+
+    doorobjlist[doornum]=(doorobj_t*)Z_LevelMalloc(sizeof(doorobj_t),PU_LEVELSTRUCT,NULL);
+    if (!doorobjlist[doornum])
+        Error("SpawnDoor: Failed on allocation of door %d ",doornum);
+    memset(doorobjlist[doornum],0,sizeof(doorobj_t));
+    lastdoorobj=doorobjlist[doornum];
+
+    if (
+        ( MAPSPOT(tilex,tiley,1) >= 29 ) &&
+        ( MAPSPOT(tilex,tiley,1) <= 32 )
+    )
+    {
+        lock = MAPSPOT(tilex,tiley,1) - 28;
+    }
+
+    lastdoorobj->position = 0;
+    lastdoorobj->tilex = tilex;
+    lastdoorobj->tiley = tiley;
+    lastdoorobj->lock = lock;
+    lastdoorobj->action = dr_closed;
+    lastdoorobj->which = DOOR;
+    lastdoorobj->flags = 0;
+    lastdoorobj->eindex = -1;
+
+    //
+    // make the door space solid
+    //
+
+    if (loadedgame==false)
+        actorat[tilex][tiley] = lastdoorobj;
+
+    if (IsDoor(tilex,tiley-1)) up=2;
+    else if (IsWall(tilex,tiley-1)) up=1;
+    else up=0;
+
+    if (IsDoor(tilex,tiley+1)) dn=2;
+    else if (IsWall(tilex,tiley+1)) dn=1;
+    else dn=0;
+
+    if (IsDoor(tilex-1,tiley)) lt=2;
+    else if (IsWall(tilex-1,tiley)) lt=1;
+    else lt=0;
+
+    if (IsDoor(tilex+1,tiley)) rt=2;
+    else if (IsWall(tilex+1,tiley)) rt=1;
+    else rt=0;
+
+    if ((up==1) && (dn==1))
+        lastdoorobj->vertical = true;
+    else if ((lt==1) && (rt==1))
+        lastdoorobj->vertical = false;
+    else if ((up>0) && (dn>0))
+        lastdoorobj->vertical = true;
+    else if ((lt>0) && (rt>0))
+        lastdoorobj->vertical = false;
+    else if (up>0)
+        lastdoorobj->vertical = true;
+    else if (dn>0)
+        lastdoorobj->vertical = true;
+    else if (lt>0)
+        lastdoorobj->vertical = false;
+    else if (rt>0)
+        lastdoorobj->vertical = false;
+
+    switch (texture)
+    {
+
+    case 0:
+    case 8:
+        basetexture = W_GetNumForName("RAMDOOR1\0");
+        break;
+
+    case 1:
+    case 9:
+        basetexture = W_GetNumForName("DOOR2\0");
+        break;
+
+
+    case 2:
+    case 3:
+    case 13:
+        basetexture = W_GetNumForName("TRIDOOR1\0");
+        break;
+
+    case 10:
+    case 11:
+    case 14:
+        basetexture = W_GetNumForName("SDOOR4\0");
+        break;
+
+
+
+    case 12:
+        basetexture = W_GetNumForName("EDOOR\0");
+        break;
+    case 15:
+        basetexture = W_GetNumForName("SNDOOR\0");
+        break;
+    case 16:
+        basetexture = W_GetNumForName("SNADOOR\0");
+        break;
+    case 17:
+        basetexture = W_GetNumForName("SNKDOOR\0");
+        break;
+
+    case 18:
+        basetexture = W_GetNumForName("TNDOOR\0");
+        break;
+    case 19:
+        basetexture = W_GetNumForName("TNADOOR\0");
+        break;
+    case 20:
+        basetexture = W_GetNumForName("TNKDOOR\0");
+        break;
+    default:
+        Error("Illegal door value encountered\n");
+        break;
+    }
+    lastdoorobj->basetexture = basetexture;
+    lastdoorobj->texture = lastdoorobj->basetexture;
+
+    SD_PreCacheSoundGroup(SD_OPENDOORSND,SD_CLOSEDOORSND);
+
+//
+// make the door tile a special tile, and mark the adjacent tiles
+// for door sides
+//
+    tilemap[tilex][tiley] = doornum | 0x8000;
+
+    switch (texture)
+    {
+    case 0:
+    case 1:
+    case 2:
+    case 3:
+    case 8:
+    case 9:
+    case 10:
+    case 11:
+    case 12:
+    case 13:
+    case 14:
+        lastdoorobj->sidepic    = W_GetNumForName("SIDE8");
+        lastdoorobj->alttexture = W_GetNumForName("ABOVEW3");
+        break;
+
+    case 15:
+    case 16:
+    case 17:
+#if (SHAREWARE == 1)
+        lastdoorobj->sidepic = W_GetNumForName("SIDE8");
+
+#else
+        lastdoorobj->sidepic    = W_GetNumForName("SIDE16");
+#endif
+
+        lastdoorobj->alttexture = W_GetNumForName("ABOVEW16");
+        break;
+
+    case 18:
+    case 19:
+    case 20:
+#if (SHAREWARE == 1)
+        lastdoorobj->sidepic = W_GetNumForName("SIDE8");
+        lastdoorobj->alttexture = W_GetNumForName("ABOVEW3");
+
+#else
+        lastdoorobj->sidepic    = W_GetNumForName("SIDE17");
+        lastdoorobj->alttexture = W_GetNumForName("ABOVEW17");
+
+#endif
+
+        break;
+    default:
+        Error("Illegal door value encountered\n");
+        break;
+    }
+
+
+
+    if ((lock>0) && (lock<5))
+        lastdoorobj->sidepic    = W_GetNumForName("lock1")+lock-1;
+
+    PreCacheLump(lastdoorobj->sidepic,PU_CACHEWALLS,cache_pic_t);
+    PreCacheLump(lastdoorobj->alttexture,PU_CACHEWALLS,cache_pic_t);
+
+    if (lastdoorobj->vertical==true)
+    {
+        if (up==1)
+            tilemap[tilex][tiley-1] |= 0x4000;
+        else if (up==2)
+            lastdoorobj->flags|=DF_MULTI;
+        if (dn==1)
+            tilemap[tilex][tiley+1] |= 0x4000;
+        else if (dn==2)
+            lastdoorobj->flags|=DF_MULTI;
+    }
+    else
+    {
+        if (lt==1)
+            tilemap[tilex-1][tiley] |= 0x4000;
+        else if (lt==2)
+            lastdoorobj->flags|=DF_MULTI;
+        if (rt==1)
+            tilemap[tilex+1][tiley] |= 0x4000;
+        else if (rt==2)
+            lastdoorobj->flags|=DF_MULTI;
+    }
+
+    PreCacheLump(lastdoorobj->texture,PU_CACHEWALLS,cache_pic_t);
+    for (i=1; i<9; i++) // only first texture is pic_t!
+        PreCacheLump(lastdoorobj->texture+i,PU_CACHEWALLS,cache_patch_t);
+    doornum++;
+    lastdoorobj++;
+    if (doornum==MAXDOORS)
+        Error ("Too many doors on level!");
+
+}
+
+/*
+===============
+=
+= MakeWideDoorVisible
+=
+===============
+*/
+void MakeWideDoorVisible ( int doornum )
+{
+    int dx,dy;
+    doorobj_t * dr2;
+    doorobj_t * dr;
+    int tx,ty;
+
+    dr=doorobjlist[doornum];
+
+    dx=0;
+    dy=0;
+    if (dr->vertical==true)
+        dy=1;
+    else
+        dx=1;
+    spotvis[dr->tilex][dr->tiley]=1;
+    tx=dr->tilex+dx;
+    ty=dr->tiley+dy;
+    while (M_ISDOOR(tx,ty))
+    {
+        int num;
+
+        num=tilemap[tx][ty]&0x3ff;
+        dr2=doorobjlist[num];
+        if (!(dr2->flags&DF_MULTI))
+            break;
+        spotvis[tx][ty]=1;
+
+        tx+=dx;
+        ty+=dy;
+    }
+    tx=dr->tilex-dx;
+    ty=dr->tiley-dy;
+    while (M_ISDOOR(tx,ty))
+    {
+        int num;
+
+        num=tilemap[tx][ty]&0x3ff;
+        dr2=doorobjlist[num];
+        if (!(dr2->flags&DF_MULTI))
+            break;
+        spotvis[tx][ty]=1;
+
+        tx-=dx;
+        ty-=dy;
+    }
+}
+
+/*
+=====================
+=
+= LockLinkedDoor
+=
+=====================
+*/
+
+void LockLinkedDoor (int door)
+{
+    doorobj_t*dptr;
+
+    dptr = doorobjlist[door];
+    if (!dptr->lock)
+        dptr->lock=5;
+}
+
+/*
+=====================
+=
+= IsDoorLinked
+=
+=====================
+*/
+
+boolean IsDoorLinked (int door)
+{
+    doorobj_t*dptr;
+
+    dptr = doorobjlist[door];
+    if (dptr->lock==5)
+        return true;
+    return false;
+}
+
+
+/*
+===============
+=
+= FixDoorAreaNumbers
+=
+===============
+*/
+void FixDoorAreaNumbers ( void )
+{
+    int i;
+    int up,dn,lt,rt;
+    int tilex,tiley;
+
+    for (i=0; i<doornum; i++)
+    {
+        tilex=doorobjlist[i]->tilex;
+        tiley=doorobjlist[i]->tiley;
+        up=MAPSPOT(tilex,tiley-1,0)-AREATILE;
+        dn=MAPSPOT(tilex,tiley+1,0)-AREATILE;
+        lt=MAPSPOT(tilex-1,tiley,0)-AREATILE;
+        rt=MAPSPOT(tilex+1,tiley,0)-AREATILE;
+
+        up = ((up>0) && (up<=NUMAREAS));
+        dn = ((dn>0) && (dn<=NUMAREAS));
+        lt = ((lt>0) && (lt<=NUMAREAS));
+        rt = ((rt>0) && (rt<=NUMAREAS));
+
+
+        if (doorobjlist[i]->vertical==true)
+        {
+            if (rt)
+                MAPSPOT(tilex,tiley,0) = MAPSPOT(tilex+1,tiley,0);
+            else if (lt)
+                MAPSPOT(tilex,tiley,0) = MAPSPOT(tilex-1,tiley,0);
+            else
+                Error("FixDoors: Couldn't fix up area at x=%d y=%d\n",tilex,tiley);
+        }
+        else
+        {
+            if (dn)
+                MAPSPOT(tilex,tiley,0) = MAPSPOT(tilex,tiley+1,0);
+            else if (up)
+                MAPSPOT(tilex,tiley,0) = MAPSPOT(tilex,tiley-1,0);
+            else
+                Error("FixDoors: Couldn't fix up area at x=%d y=%d\n",tilex,tiley);
+        }
+        if (IsDoorLinked(i))
+            UtilizeDoor(i,LockLinkedDoor);
+    }
+}
+
+
+//===========================================================================
+
+/*
+=====================
+=
+= OpenDoor
+=
+=====================
+*/
+
+void OpenDoor (int door)
+{
+    if (doorobjlist[door]->action == dr_open)
+        doorobjlist[door]->ticcount = 0;			// reset open time
+    else
+    {
+        doorobjlist[door]->action = dr_opening;	// start it opening
+    }
+}
+
+/*
+=====================
+=
+= DoorUnBlocked
+=
+=====================
+*/
+
+boolean DoorUnBlocked (int door)
+{
+    int	tilex,tiley;
+    objtype *check;
+    doorobj_t*dptr;
+
+    dptr = doorobjlist[door];
+
+//
+// don't close on anything solid
+//
+
+    tilex = dptr->tilex;
+    tiley = dptr->tiley;
+    check = (objtype*)actorat[tilex][tiley];
+
+    if (check && (check->which == ACTOR))
+        return false;
+
+    if (dptr->vertical==true)
+    {
+        check = (objtype*)actorat[tilex-1][tiley];
+        if (check && (check->which==ACTOR) && ((check->x+MINDIST) >> TILESHIFT) == tilex )
+            return false;
+        check = (objtype*)actorat[tilex+1][tiley];
+        if (check && (check->which==ACTOR) && ((check->x-MINDIST) >> TILESHIFT) == tilex )
+            return false;
+    }
+    else if (dptr->vertical==false)
+    {
+        check = (objtype*)actorat[tilex][tiley-1];
+        if (check && (check->which==ACTOR) && ((check->y+MINDIST) >> TILESHIFT) == tiley )
+            return false;
+        check = (objtype*)actorat[tilex][tiley+1];
+        if (check && (check->which==ACTOR) && ((check->y-MINDIST) >> TILESHIFT) == tiley )
+            return false;
+    }
+    return true;
+}
+
+
+/*
+=====================
+=
+= DoorReadyToClose
+=
+= Alter the door's state
+=
+=====================
+*/
+
+boolean DoorReadyToClose(int door)
+{
+    doorobj_t*dptr;
+    int dx,dy;
+    doorobj_t * dr2;
+    int tx,ty;
+
+
+    dptr = doorobjlist[door];
+
+    if (dptr->action==dr_closed)
+        return true;
+
+    if (DoorUnBlocked(door)==false)
+        return false;
+
+    dx=0;
+    dy=0;
+    if (dptr->vertical==true)
+        dy=1;
+    else
+        dx=1;
+    tx=dptr->tilex+dx;
+    ty=dptr->tiley+dy;
+    while (M_ISDOOR(tx,ty))
+    {
+        int num;
+
+        num=tilemap[tx][ty]&0x3ff;
+        dr2=doorobjlist[num];
+        if (!(dr2->flags&DF_MULTI))
+            break;
+        if (DoorUnBlocked(num)==false)
+            return false;
+        tx+=dx;
+        ty+=dy;
+    }
+    tx=dptr->tilex-dx;
+    ty=dptr->tiley-dy;
+    while (M_ISDOOR(tx,ty))
+    {
+        int num;
+
+        num=tilemap[tx][ty]&0x3ff;
+        dr2=doorobjlist[num];
+        if (!(dr2->flags&DF_MULTI))
+            break;
+        if (DoorUnBlocked(num)==false)
+            return false;
+        tx-=dx;
+        ty-=dy;
+    }
+    return true;
+}
+
+
+/*
+=====================
+=
+= CloseDoor
+=
+=====================
+*/
+
+void CloseDoor (int door)
+{
+    int	tilex,tiley,area;
+    doorobj_t*dptr;
+
+    dptr = doorobjlist[door];
+    if (dptr->action == dr_closed)
+        return;
+    tilex = dptr->tilex;
+    tiley = dptr->tiley;
+
+//
+// play door sound
+//
+    area = MAPSPOT(tilex,tiley,0)-AREATILE;
+    if (areabyplayer[area])
+    {
+        dptr->soundhandle=SD_PlaySoundRTP ( SD_CLOSEDOORSND, dptr->tilex<<16, dptr->tiley<<16 );
+    }
+
+    dptr->action = dr_closing;
+//
+// make the door space solid
+//
+    actorat[tilex][tiley] = dptr;
+}
+
+
+
+/*
+=====================
+=
+= OperateDoor
+=
+= The player wants to change the door's direction
+=
+=====================
+*/
+
+void OperateDoor (int keys, int door, boolean localplayer )
+{
+    int	lock;
+    doorobj_t*dptr;
+
+    dptr = doorobjlist[door];
+    if ( ( dptr->flags & DF_ELEVLOCKED ) ||
+            ( MISCVARS->GASON && ( MAPSPOT( dptr->tilex,
+                                            dptr->tiley, 1 ) == GASVALUE ) ) )
+    {
+        if ( localplayer )
+        {
+            // locked
+            SD_Play ( SD_NOITEMSND );
+        }
+        return;
+    }
+
+    lock = dptr->lock;
+    if ( lock && !( keys & ( 1 << ( lock - 1 ) ) ) )
+    {
+        if ( localplayer )
+        {
+            // locked
+            switch (lock)
+            {
+            case 1:
+                AddMessage("You need the \\EGOLD key",MSG_DOOR);
+                break;
+
+            case 2:
+                AddMessage("You need the \\FSILVER key",MSG_DOOR);
+                break;
+
+            case 3:
+                AddMessage("You need the \\8IRON key",MSG_DOOR);
+                break;
+
+            case 4:
+                AddMessage("You need the \\AOSCURO key",MSG_DOOR);
+                break;
+
+            default:
+                AddMessage("This door appears to be locked",MSG_DOOR);
+                break;
+            }
+
+            SD_Play( SD_NOITEMSND );
+        }
+        return;
+    }
+    UseDoor(door);
+}
+
+/*
+=====================
+=
+= LinkedOpenDoor
+=
+=====================
+*/
+
+void LinkedOpenDoor (long door)
+{
+    UtilizeDoor(door,OpenDoor);
+}
+
+/*
+=====================
+=
+= LinkedCloseDoor
+=
+=====================
+*/
+
+void LinkedCloseDoor (long door)
+{
+    if (DoorReadyToClose(door)==true)
+        UtilizeDoor(door,CloseDoor);
+}
+
+/*
+=====================
+=
+= UtilizeDoor
+=
+= Alter the door's state
+=
+=====================
+*/
+
+void UtilizeDoor (int door,void (*action)(int))
+{
+    doorobj_t*dptr;
+    int dx,dy;
+    doorobj_t * dr2;
+    int tx,ty;
+
+    dptr = doorobjlist[door];
+
+    action(door);
+
+    dx=0;
+    dy=0;
+    if (dptr->vertical==true)
+        dy=1;
+    else
+        dx=1;
+    tx=dptr->tilex+dx;
+    ty=dptr->tiley+dy;
+    while (M_ISDOOR(tx,ty))
+    {
+        int num;
+
+        num=tilemap[tx][ty]&0x3ff;
+        dr2=doorobjlist[num];
+        if (!(dr2->flags&DF_MULTI))
+            break;
+        action(num);
+        tx+=dx;
+        ty+=dy;
+    }
+    tx=dptr->tilex-dx;
+    ty=dptr->tiley-dy;
+    while (M_ISDOOR(tx,ty))
+    {
+        int num;
+
+        num=tilemap[tx][ty]&0x3ff;
+        dr2=doorobjlist[num];
+        if (!(dr2->flags&DF_MULTI))
+            break;
+        action(num);
+        tx-=dx;
+        ty-=dy;
+    }
+}
+
+/*
+=====================
+=
+= UseDoor
+=
+= Alter the door's state
+=
+=====================
+*/
+
+void UseDoor (int door)
+{
+    switch (doorobjlist[door]->action)
+    {
+    case dr_closing:
+        SD_StopSound(doorobjlist[door]->soundhandle);
+    case dr_closed:
+        UtilizeDoor(door,OpenDoor);
+        break;
+    case dr_opening:
+        SD_StopSound(doorobjlist[door]->soundhandle);
+    case dr_open:
+        if (DoorReadyToClose(door)==true)
+            UtilizeDoor(door,CloseDoor);
+        break;
+    }
+}
+
+//===========================================================================
+
+/*
+===============
+=
+= DoorOpen
+=
+= Close the door after three seconds
+=
+===============
+*/
+
+void DoorOpen (int door)
+{   doorobj_t* dptr;
+
+    dptr = doorobjlist[door];
+    dptr->ticcount += 1;
+    if ((dptr->ticcount >= OPENTICS) &&
+            (!(dptr->flags & DF_TIMED)) &&
+            (DoorReadyToClose(door)==true))
+        UtilizeDoor(door,CloseDoor);
+}
+
+
+
+/*
+===============
+=
+= DoorOpening
+=
+===============
+*/
+
+void DoorOpening (int door)
+{
+    int		area1,area2;
+    word  	*map;
+    long	   position;
+    int      tilex,tiley;
+
+    position = doorobjlist[door]->position;
+    tilex = doorobjlist[door]->tilex;
+    tiley = doorobjlist[door]->tiley;
+    if (!position)
+    {
+        //
+        // door is just starting to open, so connect the areas
+        //
+        map = &MAPSPOT(tilex,tiley,0);
+
+        if (doorobjlist[door]->vertical==true)
+        {
+            area1 =	*(map+1);
+            area2 =	*(map-1);
+        }
+        else
+        {
+            area1 =	*(map-mapwidth);
+            area2 =	*(map+mapwidth);
+        }
+        area1 -= AREATILE;
+        area2 -= AREATILE;
+        areaconnect[area1][area2]++;
+        areaconnect[area2][area1]++;
+        if ((insetupgame==false) && (loadedgame==false))
+            ConnectAreas ();
+        if (areabyplayer[area1])
+        {
+            doorobjlist[door]->soundhandle=SD_PlaySoundRTP ( SD_OPENDOORSND, doorobjlist[door]->tilex<<16, doorobjlist[door]->tiley<<16 );
+        }
+    }
+
+//
+// slide the door by an adaptive amount
+//
+    position += 1<<12;
+    if (position >= 0xffff)
+    {
+        //
+        // door is all the way open
+        //
+        position = 0xffff;
+        doorobjlist[door]->ticcount = 0;
+        doorobjlist[door]->action = dr_open;
+        if (doorobjlist[door] == actorat[tilex][tiley])
+            actorat[tilex][tiley] = 0;
+    }
+
+    doorobjlist[door]->position = position;
+    doorobjlist[door]->texture=doorobjlist[door]->basetexture+((position+1)>>13);
+}
+
+
+/*
+===============
+=
+= DoorClosing
+=
+===============
+*/
+
+void DoorClosing (int door)
+{
+    int		area1,area2;
+    word	   *map;
+    long	   position;
+    int		tilex,tiley;
+    doorobj_t *dptr;
+
+    dptr = doorobjlist[door];
+
+    tilex = dptr->tilex;
+    tiley = dptr->tiley;
+
+    position = dptr->position;
+
+//
+// slide the door by an adaptive amount
+//
+    position -= 1<<12;
+    if (position < (0xffff >> 1))
+        ResolveDoorSpace(tilex,tiley);
+
+
+    if (position <= 0)
+    {
+        //
+        // door is closed all the way, so disconnect the areas
+        //
+        position = 0;
+
+        dptr->action = dr_closed;
+
+
+
+        map = &MAPSPOT(tilex,tiley,0);
+
+        if (areabyplayer[(*map-AREATILE)])
+        {
+            dptr->soundhandle=SD_PlaySoundRTP ( SD_DOORHITSND, dptr->tilex<<16, dptr->tiley<<16 );
+        }
+
+        if (dptr->vertical==true)
+        {
+            area1 =	*(map+1);
+            area2 =	*(map-1);
+        }
+        else
+        {
+            area1 =	*(map-mapwidth);
+            area2 =	*(map+mapwidth);
+        }
+        area1 -= AREATILE;
+        area2 -= AREATILE;
+        areaconnect[area1][area2]--;
+        areaconnect[area2][area1]--;
+
+        ConnectAreas ();
+    }
+
+    dptr->position = position;
+    dptr->texture=dptr->basetexture+((position+1)>>13);
+}
+
+/*
+===============
+=
+= IsMaskedWall
+=
+===============
+*/
+
+int IsMaskedWall (int tilex, int tiley)
+{
+    int map;
+
+    if (IsPlatform(tilex,tiley))
+        return 1;
+
+    map=MAPSPOT(tilex,tiley,0);
+
+    if ((map>=157) && (map<=160))
+        return 1;
+
+    if ((map>=162) && (map<=179))
+        return 1;
+
+    if (M_ISMWALL(tilex,tiley))
+        return 1;
+
+    return 0;
+}
+
+/*
+===============
+=
+= SpawnMaskedWall
+=
+===============
+*/
+
+
+void SpawnMaskedWall (int tilex, int tiley, int which, int flags)
+{   word *map;
+    int area1, area2;
+    int up,dn,lt,rt;
+    int himask;
+    boolean sidepic;
+    int side, middle, above, bottom;
+    maskedwallobj_t * lastmaskobj;
+    boolean metal;
+    int maskedstart;
+    int abovemaskedwallstart;
+    int swallstart;
+
+    himask=W_GetNumForName("HMSKSTRT")+1;
+    maskedstart=W_GetNumForName("MASKSTRT");
+    abovemaskedwallstart=W_GetNumForName("ABVMSTRT");
+    swallstart=W_GetNumForName("SIDESTRT");
+
+    maskobjlist[maskednum]=(maskedwallobj_t*)Z_LevelMalloc(sizeof(maskedwallobj_t),PU_LEVELSTRUCT,NULL);
+    memset(maskobjlist[maskednum],0,sizeof(maskedwallobj_t));
+    lastmaskobj=maskobjlist[maskednum];
+
+    sidepic=true;
+
+    lastmaskobj->tilex = tilex;
+    lastmaskobj->tiley = tiley;
+    lastmaskobj->which = MWALL;
+    up=MAPSPOT(tilex,tiley-1,0)-AREATILE;
+    dn=MAPSPOT(tilex,tiley+1,0)-AREATILE;
+    lt=MAPSPOT(tilex-1,tiley,0)-AREATILE;
+    rt=MAPSPOT(tilex+1,tiley,0)-AREATILE;
+
+    if (IsMaskedWall(tilex,tiley-1)) up=2;
+    else if (IsWall(tilex,tiley-1)) up=1;
+    else up=0;
+
+    if (IsMaskedWall(tilex,tiley+1)) dn=2;
+    else if (IsWall(tilex,tiley+1)) dn=1;
+    else dn=0;
+
+    if (IsMaskedWall(tilex-1,tiley)) lt=2;
+    else if (IsWall(tilex-1,tiley)) lt=1;
+    else lt=0;
+
+    if (IsMaskedWall(tilex+1,tiley)) rt=2;
+    else if (IsWall(tilex+1,tiley)) rt=1;
+    else rt=0;
+
+    if ((up==1) && (dn==1))
+        lastmaskobj->vertical = true;
+    else if ((lt==1) && (rt==1))
+        lastmaskobj->vertical = false;
+    else if ((up>0) && (dn>0))
+        lastmaskobj->vertical = true;
+    else if ((lt>0) && (rt>0))
+        lastmaskobj->vertical = false;
+    else if (up>0)
+        lastmaskobj->vertical = true;
+    else if (dn>0)
+        lastmaskobj->vertical = true;
+    else if (lt>0)
+        lastmaskobj->vertical = false;
+    else if (rt>0)
+        lastmaskobj->vertical = false;
+
+    tilemap[tilex][tiley] = maskednum | 0xc000;
+    map = &MAPSPOT(tilex,tiley,0);
+
+    if (lastmaskobj->vertical==true)
+    {
+        area1 =	*(map+1);
+        area2 =	*(map-1);
+        area1 -= AREATILE;
+        area2 -= AREATILE;
+        if (lt==0 && rt==0)
+        {
+            areaconnect[area1][area2]++;
+            areaconnect[area2][area1]++;
+        }
+    }
+    else
+    {
+        area1 =	*(map-mapwidth);
+        area2 =	*(map+mapwidth);
+        area1 -= AREATILE;
+        area2 -= AREATILE;
+        if (up==0 && dn==0)
+        {
+            areaconnect[area1][area2]++;
+            areaconnect[area2][area1]++;
+        }
+    }
+    lastmaskobj->flags=flags;
+
+    if (IsPlatform(tilex,tiley))
+    {
+        if (MAPSPOT(tilex,tiley,0)==21)
+        {
+            metal=true;
+            actorat[tilex][tiley]=0;
+        }
+        else
+            metal=false;
+    }
+
+
+
+    switch (which)
+    {
+    case mw_peephole:
+
+        //#if (SHAREWARE == 1)
+        side = W_GetNumForName("SIDE21");
+        middle = W_GetNumForName("ABOVEM4A") ;
+        above  = W_GetNumForName("ABOVEM4") ;
+        /*
+        #else
+           side   = W_GetNumForName("SIDE16");
+           middle = W_GetNumForName("ABOVEM3A") ;
+           above  = W_GetNumForName("ABOVEM2A") ;
+
+        #endif
+        */
+        bottom = W_GetNumForName("PEEPMASK");
+        break;
+
+
+    case mw_dogwall:
+
+        side = W_GetNumForName("SIDE21");
+        above  = W_GetNumForName("ABOVEM4") ;
+
+#if (SHAREWARE == 1)
+        middle = W_GetNumForName("ABOVEM4A") ;
+#else
+        middle = W_GetNumForName("ABOVEM9") ;
+
+#endif
+        bottom = W_GetNumForName("DOGMASK");
+        break;
+
+    case mw_multi1:
+
+        /*
+            #if (SHAREWARE == 1)
+               side = W_GetNumForName("SIDE21");
+               middle = W_GetNumForName("ABOVEM4A") ;
+               above  = W_GetNumForName("ABOVEM4") ;
+
+            #else
+        */
+        //side   = W_GetNumForName("SIDE23") ;
+        side   = W_GetNumForName("SIDE21") ;
+        middle = W_GetNumForName("ABOVEM5A") ;
+        above  = W_GetNumForName("ABOVEM5") ;
+
+        // #endif
+
+        bottom = W_GetNumForName("MULTI1");
+        break;
+
+    case mw_multi2:
+        /*
+        #if (SHAREWARE == 1)
+           side = W_GetNumForName("SIDE21");
+           middle = W_GetNumForName("ABOVEM4A");
+           above  = W_GetNumForName("ABOVEM4") ;
+
+        #else
+        */
+        //side   = W_GetNumForName("SIDE23") ;
+        side   = W_GetNumForName("SIDE21") ;
+        middle = W_GetNumForName("ABOVEM5B");
+        above  = W_GetNumForName("ABOVEM5") ;
+
+
+        //#endif
+
+        bottom = W_GetNumForName("MULTI2");
+        break;
+
+    case mw_multi3:
+
+        /*
+        #if (SHAREWARE == 1)
+           side = W_GetNumForName("SIDE21");
+           middle = W_GetNumForName("ABOVEM4A") ;
+           above  = W_GetNumForName("ABOVEM4")  ;
+
+        #else
+        */
+        //side   = W_GetNumForName("SIDE23") ;
+        side   = W_GetNumForName("SIDE21") ;
+        middle = W_GetNumForName("ABOVEM5C") ;
+        above  = W_GetNumForName("ABOVEM5")  ;
+
+
+        //#endif
+
+        bottom = W_GetNumForName("MULTI3");
+        break;
+
+    case mw_singlepane:
+
+        //   #if (SHAREWARE == 1)
+        side = W_GetNumForName("SIDE21");
+
+        //   #else
+        //      side   = W_GetNumForName("SIDE22") ;
+        //   #endif
+
+        middle = W_GetNumForName("ABOVEM4A") ;
+        above  = W_GetNumForName("ABOVEM4")  ;
+        bottom = W_GetNumForName("MASKED4");
+        break;
+
+    case mw_normal1:
+        side = W_GetNumForName("SIDE21");
+
+
+        // #if (SHAREWARE == 1)
+        middle = W_GetNumForName("ABOVEM4A") ;
+        above  = W_GetNumForName("ABOVEM4")  ;
+
+        //#else
+        //  middle = W_GetNumForName("ABOVEM1A") ;
+        //  above  = W_GetNumForName("ABOVEM1")  ;
+
+
+        //#endif
+
+        bottom = W_GetNumForName("MASKED1");
+        break;
+
+    case mw_normal2:
+        side = W_GetNumForName("SIDE21");
+
+        //#if (SHAREWARE == 1)
+        middle = W_GetNumForName("ABOVEM4A") ;
+        above  = W_GetNumForName("ABOVEM4")  ;
+
+        //#else
+        //   middle = W_GetNumForName("ABOVEM2A") ;
+        //   above  = W_GetNumForName("ABOVEM2")  ;
+
+        //#endif
+
+        bottom = W_GetNumForName("MASKED2");
+        break;
+
+    case mw_normal3:
+        side = W_GetNumForName("SIDE21");
+
+        //#if (SHAREWARE == 1)
+        middle = W_GetNumForName("ABOVEM4A") ;
+        above  = W_GetNumForName("ABOVEM4")  ;
+
+        //#else
+        //   middle = W_GetNumForName("ABOVEM3A") ;
+        //   above  = W_GetNumForName("ABOVEM3")  ;
+
+        //#endif
+
+        bottom = W_GetNumForName("MASKED3");
+        break;
+
+    case mw_exitarch:
+
+        side = W_GetNumForName("SIDE21");
+
+        //#if (SHAREWARE == 1)
+        middle = W_GetNumForName("ABOVEM4A") ;
+        above  = W_GetNumForName("ABOVEM4")  ;
+
+        //#else
+        //   middle = W_GetNumForName("ABOVEM6A") ;
+        //   above  = W_GetNumForName("ABOVEM6")  ;
+
+        //#endif
+
+        bottom = W_GetNumForName("EXITARCH");
+        break;
+
+    case mw_secretexitarch:
+
+        side = W_GetNumForName("SIDE21");
+
+        //#if (SHAREWARE == 1)
+        middle = W_GetNumForName("ABOVEM4A") ;
+        above  = W_GetNumForName("ABOVEM4")  ;
+
+        //#else
+        //   middle = W_GetNumForName("ABOVEM8A") ;
+        //   above  = W_GetNumForName("ABOVEM8")  ;
+
+        //#endif
+
+        bottom = W_GetNumForName("EXITARCA");
+        break;
+
+    case mw_railing:
+        sidepic = false;
+        middle = -1;
+        above  = -1;
+        bottom = W_GetNumForName("RAILING");
+        break;
+
+    case mw_hiswitchon:
+        sidepic = false;
+        middle = himask+1;
+        above = himask+3;
+        bottom = himask;
+        break;
+
+    case mw_hiswitchoff:
+        sidepic = false;
+        middle = himask+1;
+        above = himask+2;
+        bottom = himask;
+        break;
+
+    case mw_entrygate:
+        side = W_GetNumForName("SIDE21");
+
+        //#if (SHAREWARE == 1)
+        //side = W_GetNumForName("SIDE21");
+        middle = W_GetNumForName("ABOVEM4A") ;
+        above  = W_GetNumForName("ABOVEM4")  ;
+
+        //#else
+        //side   = W_GetNumForName("SIDE20") ;
+        //   middle = W_GetNumForName("ABOVEM7A") ;
+        //   above  = W_GetNumForName("ABOVEM7")  ;
+
+
+        //#endif
+
+        bottom = W_GetNumForName("ENTRARCH");
+        break;
+
+    case mw_platform1:
+        sidepic = false;
+        bottom = -1;
+        middle = -1;
+        above  = himask+10;
+        if (metal==true)
+        {
+            bottom = -1;
+            middle = -1;
+            above  = himask+15;
+        }
+        break;
+    case mw_platform2:
+        sidepic = false;
+        bottom = himask+8;
+        middle = -1;
+        above = -1;
+        if (metal==true)
+        {
+            bottom = himask+14;
+            middle = -1;
+            above = -1;
+        }
+        else
+            lastmaskobj->flags|=MW_BOTTOMFLIPPING;
+        break;
+    case mw_platform3:
+        sidepic = false;
+        bottom = himask+8;
+        middle = -1;
+        above = himask+10;
+        if (metal==true)
+        {
+            bottom = himask+14;
+            middle = -1;
+            above = himask+15;
+        }
+        else
+            lastmaskobj->flags|=MW_BOTTOMFLIPPING;
+        break;
+    case mw_platform4:
+        sidepic = false;
+        bottom = himask+12;
+        middle = himask+7;
+        above = himask+7;
+        if (metal==true)
+        {
+            bottom = -1;
+            middle = himask+15;
+            above = himask+15;
+        }
+        break;
+    case mw_platform5:
+        sidepic = false;
+        bottom = himask+12;
+        middle = himask+7;
+        above = himask+5;
+        if (metal==true)
+        {
+            bottom = -1;
+            middle = himask+15;
+            above = -1;
+        }
+        else
+            lastmaskobj->flags|=MW_TOPFLIPPING;
+        break;
+    case mw_platform6:
+        sidepic = false;
+        bottom = himask+4;
+        middle = himask+7;
+        above = himask+5;
+        if (metal==true)
+        {
+            bottom = himask+14;
+            middle = himask+15;
+            above = -1;
+        }
+        else
+            lastmaskobj->flags|=MW_TOPFLIPPING;
+        break;
+    case mw_platform7:
+        sidepic = false;
+        bottom = himask+4;
+        middle = himask+7;
+        above = himask+5;
+        if ((up==1) || (dn==1))
+            lastmaskobj->vertical=true;
+        else if ((lt==1) || (rt==1))
+            lastmaskobj->vertical=false;
+        else
+            Error("Perpendicular platform used with no wall near it\n");
+        if (metal==true)
+        {
+            bottom = himask+14;
+            middle = himask+15;
+            above = -1;
+        }
+        else
+            lastmaskobj->flags|=MW_TOPFLIPPING;
+        break;
+    }
+
+    switch (which)
+    {
+    case mw_multi1:
+    case mw_multi2:
+    case mw_multi3:
+    case mw_singlepane:
+    case mw_normal1:
+    case mw_normal2:
+    case mw_normal3:
+        if (!(flags & MW_SHOOTABLE))
+            bottom+=9;
+        break;
+    }
+    lastmaskobj->midtexture=middle;
+    lastmaskobj->toptexture=above;
+    lastmaskobj->bottomtexture=bottom;
+
+    if (sidepic == true)
+    {
+        lastmaskobj->sidepic=side;
+        if (lastmaskobj->vertical==true)
+        {
+            if (up==1)
+                tilemap[tilex][tiley-1] |= 0x4000;
+            if (dn==1)
+                tilemap[tilex][tiley+1] |= 0x4000;
+        }
+        else
+        {
+            if (lt==1)
+                tilemap[tilex-1][tiley] |= 0x4000;
+            if (rt==1)
+                tilemap[tilex+1][tiley] |= 0x4000;
+        }
+    }
+
+    // Cache in the broken version
+
+    if (lastmaskobj->flags & MW_SHOOTABLE)
+    {
+        int i;
+
+        for (i=1; i<AMW_NUMFRAMES; i++)
+        {
+            PreCacheLump(lastmaskobj->bottomtexture+i,PU_CACHEWALLS,cache_transpatch_t);
+        }
+        SD_PreCacheSound(SD_GLASSBREAKSND);
+    }
+    if (sidepic==true)
+    {
+        PreCacheLump(lastmaskobj->sidepic,PU_CACHEWALLS,cache_pic_t);
+    }
+    if (lastmaskobj->bottomtexture>=0)
+        PreCacheLump(lastmaskobj->bottomtexture,PU_CACHEWALLS,cache_transpatch_t);
+    if (lastmaskobj->toptexture>=0)
+        PreCacheLump(lastmaskobj->toptexture,PU_CACHEWALLS,cache_patch_t);
+    if (lastmaskobj->midtexture>=0)
+        PreCacheLump(lastmaskobj->midtexture,PU_CACHEWALLS,cache_patch_t);
+    maskednum++;
+    lastmaskobj++;
+    if (maskednum==MAXMASKED)
+        Error ("Too many masked walls\n");
+}
+
+/*
+===============
+=
+= FixMaskedWallAreaNumbers
+=
+===============
+*/
+void FixMaskedWallAreaNumbers ( void )
+{
+    int i;
+    int up,dn,lt,rt;
+    int tilex,tiley;
+
+    for (i=0; i<maskednum; i++)
+    {
+        int tile;
+        tilex=maskobjlist[i]->tilex;
+        tiley=maskobjlist[i]->tiley;
+        tile=MAPSPOT(tilex,tiley,0)-AREATILE;
+        if ((tile<=NUMAREAS) && (tile>0))
+        {
+            maskobjlist[i]->areanumber = tile;
+            continue;
+        }
+        up=MAPSPOT(tilex,tiley-1,0)-AREATILE;
+        dn=MAPSPOT(tilex,tiley+1,0)-AREATILE;
+        lt=MAPSPOT(tilex-1,tiley,0)-AREATILE;
+        rt=MAPSPOT(tilex+1,tiley,0)-AREATILE;
+
+
+
+        up = ((up>0) && (up<=NUMAREAS));
+        dn = ((dn>0) && (dn<=NUMAREAS));
+        lt = ((lt>0) && (lt<=NUMAREAS));
+        rt = ((rt>0) && (rt<=NUMAREAS));
+
+        if (maskobjlist[i]->vertical==true)
+        {
+            if (rt)
+                MAPSPOT(tilex,tiley,0) = MAPSPOT(tilex+1,tiley,0);
+            else if (lt)
+                MAPSPOT(tilex,tiley,0) = MAPSPOT(tilex-1,tiley,0);
+            else if (up)
+                MAPSPOT(tilex,tiley,0) = MAPSPOT(tilex,tiley-1,0);
+            else if (dn)
+                MAPSPOT(tilex,tiley,0) = MAPSPOT(tilex,tiley+1,0);
+            else
+                Error("FixMaskedWalls: Couldn't fix up area at x=%d y=%d\n",tilex,tiley);
+        }
+        else
+        {
+            if (dn)
+                MAPSPOT(tilex,tiley,0) = MAPSPOT(tilex,tiley+1,0);
+            else if (up)
+                MAPSPOT(tilex,tiley,0) = MAPSPOT(tilex,tiley-1,0);
+            else if (rt)
+                MAPSPOT(tilex,tiley,0) = MAPSPOT(tilex+1,tiley,0);
+            else if (lt)
+                MAPSPOT(tilex,tiley,0) = MAPSPOT(tilex-1,tiley,0);
+            else
+                Error("FixMaskedWalls: Couldn't fix up area at x=%d y=%d\n",tilex,tiley);
+        }
+        maskobjlist[i]->areanumber = MAPSPOT(tilex,tiley,0)-AREATILE;
+        if ((maskobjlist[i]->areanumber <0) || (maskobjlist[i]->areanumber > NUMAREAS))
+            Error("Bad masked wall areanumber of %d",maskobjlist[i]->areanumber);
+    }
+}
+
+
+/*
+===============
+=
+= CheckMaskedWall
+=
+===============
+*/
+
+int CheckMaskedWall( maskedwallobj_t * mw )
+{
+    int result;
+
+    result=0;
+    if (mw->flags & MW_SHOOTABLE)
+    {
+        if (mw->flags & MW_BLOCKINGCHANGES)
+        {
+            mw->flags&=~MW_BLOCKINGCHANGES;
+            mw->flags&=~MW_BLOCKING;
+            mw->flags|=MW_BOTTOMPASSABLE;
+        }
+        mw->flags&=~MW_SHOOTABLE;
+//      mw->bottomtexture++;
+        result=1;
+    }
+    return result;
+}
+
+
+/*
+===============
+=
+= UpdateMaskedWall
+=
+===============
+*/
+
+int UpdateMaskedWall (int num)
+{
+    maskedwallobj_t * mw;
+    int result;
+
+
+    mw=maskobjlist[num];
+    result=CheckMaskedWall(mw);
+    if (result==1)
+    {
+        SpawnAnimatedMaskedWall(num);
+        if (loadedgame==false)
+            SD_PlaySoundRTP(SD_GLASSBREAKSND,mw->tilex<<16,mw->tiley<<16);
+        if (mw->flags&MW_MULTI)
+        {
+            int i;
+            int dx,dy;
+            int r;
+            maskedwallobj_t * mw2;
+
+            dx=0;
+            dy=0;
+            if (mw->vertical==true)
+                dy=1;
+            else
+                dx=1;
+            i=1;
+            while (M_ISMWALL(mw->tilex+(dx*i),mw->tiley+(dy*i)))
+            {
+                int num;
+
+                num=tilemap[mw->tilex+(dx*i)][mw->tiley+(dy*i)]&0x3ff;
+                mw2=maskobjlist[num];
+                if (!(mw2->flags&MW_MULTI))
+                    break;
+                r=CheckMaskedWall(mw2);
+                if (r==1)
+                {
+                    SpawnAnimatedMaskedWall(num);
+                    if (loadedgame==false)
+                        SD_PlaySoundRTP(SD_GLASSBREAKSND,mw2->tilex<<16,mw2->tiley<<16);
+                }
+                i++;
+            }
+            i=1;
+            while (M_ISMWALL(mw->tilex-(dx*i),mw->tiley-(dy*i)))
+            {
+                int num;
+
+                num=tilemap[mw->tilex-(dx*i)][mw->tiley-(dy*i)]&0x3ff;
+                mw2=maskobjlist[num];
+                if (!(mw2->flags&MW_MULTI))
+                    break;
+                r=CheckMaskedWall(mw2);
+                if (r==1)
+                {
+                    SpawnAnimatedMaskedWall(num);
+                    if (loadedgame==false)
+                        SD_PlaySoundRTP(SD_GLASSBREAKSND,mw2->tilex<<16,mw2->tiley<<16);
+                }
+                i++;
+            }
+        }
+    }
+    return result;
+}
+
+
+
+/*
+============================
+=
+= ExecuteElevatorStopActions
+=
+============================
+*/
+
+
+void ExecuteElevatorStopActions(elevator_t *eptr, int teleport_location,
+                                int desttilex,int desttiley)
+{
+    eptr->state = ev_doorclosing;
+    eptr->doorclosing = eptr->doortoopen;
+    doorobjlist[eptr->doortoopen]->flags &= ~DF_ELEVLOCKED;
+    OpenDoor(eptr->doortoopen);
+    SD_PlaySoundRTP(SD_ELEVATORENDSND,desttilex,desttiley);
+    Teleport(eptr,teleport_location);
+    eptr->ticcount = OPENTICS;
+    eptr->doortoopen = -1;
+    if (MISCVARS->elevatormusicon == true)
+    {
+        MU_StartSong(song_level);
+        MU_RestoreSongPosition();
+        MISCVARS->elevatormusicon = false;
+
+    }
+}
+
+
+boolean PlayerInElevator(elevator_t *eptr)
+{
+    if (eptr->state == ev_mts)
+    {
+        if ((eptr->dx == player->tilex) && (eptr->dy == player->tiley))
+            return true;
+    }
+    else if (eptr->state == ev_mtd)
+    {
+        if ((eptr->sx == player->tilex) && (eptr->sy == player->tiley))
+            return true;
+    }
+
+    return false;
+
+}
+
+#define SHOULD_START_ELEVATOR_MUSIC(eptr)                              \
+        ((demoplayback == false) && (demorecord == false) &&           \
+         (MusicStarted() == true) &&                                   \
+         (!BATTLEMODE) && \
+         (!(player->flags & FL_GODMODE)) &&\
+         (GameRandomNumber("elevator music",0) < 25) && \
+         (PlayerInElevator(eptr))                                      \
+        )                                                              \
+
+
+/*
+==========================
+=
+= SetElevatorOperationTime
+=
+==========================
+*/
+
+
+void SetElevatorOperationTime(elevator_t*eptr)
+{
+    if (SHOULD_START_ELEVATOR_MUSIC(eptr))
+    {
+        MU_StoreSongPosition();
+        MU_StartSong(song_elevator);
+        MISCVARS->elevatormusicon = true;
+        eptr->ticcount = ELEVATORMUSICTIME;
+    }
+
+    else if (AREANUMBER(eptr->sx,eptr->sy) == AREANUMBER(eptr->dx,eptr->dy))
+        eptr->ticcount = 70;
+    else
+        eptr->ticcount = 170;
+
+}
+
+
+/*
+=====================
+=
+= CheckElevatorStart
+=
+=====================
+*/
+
+void CheckElevatorStart (elevator_t*eptr)
+{
+    doorobj_t *dptr = doorobjlist[eptr->doorclosing];
+
+    if (dptr->action == dr_closed)
+    {
+
+        if (eptr->nextaction!=-1)
+        {
+            eptr->state = eptr->nextaction;
+            eptr->nextaction = -1;
+            switch (eptr->state)
+            {
+            case ev_mtd:
+                eptr->doortoopen = eptr->door2;
+                SD_PlaySoundRTP(SD_ELEVATORONSND,eptr->sx<<16,eptr->sy<<16);
+                //eptr->doorclosing = eptr->door1;
+
+                SetElevatorOperationTime(eptr);
+                break;
+
+            case ev_mts:
+                eptr->doortoopen = eptr->door1;
+
+                SD_PlaySoundRTP(SD_ELEVATORONSND,eptr->dx<<16,eptr->dy<<16);
+
+                SetElevatorOperationTime(eptr);
+                break;
+            }
+        }
+
+        else if (eptr->doorclosing == eptr->door1)
+            eptr->state = ev_ras;
+
+
+        else if (eptr->doorclosing == eptr->door2)
+            eptr->state = ev_rad;
+
+
+        eptr->doorclosing = -1;
+    }
+}
+
+
+/*
+=====================
+=
+= ProcessElevators
+=
+= Called from PlayLoop
+=
+=====================
+*/
+
+void ProcessElevators (void)
+{
+    int		  ectr;
+    elevator_t *eptr;
+
+    for (ectr = 0 ; ectr < _numelevators ; ectr++)
+    {
+        eptr = &ELEVATOR[ectr];
+        if (eptr->ticcount)
+            eptr->ticcount --;
+        else
+        {
+            switch (eptr->state)
+            {
+            /*
+            case ev_ras:
+               break;
+
+            case ev_rad:
+               break;
+            */
+            case ev_mts:
+                ExecuteElevatorStopActions(eptr,0,(eptr->sx << 16),(eptr->sy << 16));
+                break;
+
+            case ev_mtd:
+                ExecuteElevatorStopActions(eptr,1,(eptr->dx << 16),(eptr->dy << 16));
+                break;
+
+            case ev_doorclosing:
+                CheckElevatorStart(eptr);
+                break;
+            }
+        }
+    }
+}
+
+
+
+void Teleport(elevator_t*eptr,int destination)
+{   statobj_t*tstat;
+    objtype*temp;
+    int startx,starty,destx,desty;
+
+    if (destination) // move to dest
+    {   startx = eptr->sx;
+        starty = eptr->sy;
+        destx = eptr->dx;
+        desty = eptr->dy;
+        tilemap[eptr->esx][eptr->esy] = (elevatorstart + 5) | 0x2000;
+
+    }
+    else
+    {   startx = eptr->dx;
+        starty = eptr->dy;
+        destx = eptr->sx;
+        desty = eptr->sy;
+        tilemap[eptr->edx][eptr->edy] = (elevatorstart + 5) | 0x2000;
+    }
+
+    for(tstat=firstactivestat; tstat; tstat=tstat->nextactive)
+    {   if ((tstat->tilex == startx) && (tstat->tiley == starty))
+        {
+            tstat->x += ((destx - tstat->tilex) << TILESHIFT);
+            tstat->y += ((desty - tstat->tiley) << TILESHIFT);
+            tstat->tilex = tstat->x >> TILESHIFT;
+            tstat->tiley = tstat->y >> TILESHIFT;
+            tstat->visspot = &spotvis[tstat->tilex][tstat->tiley];
+            if (sprites[startx][starty] == tstat)
+            {   sprites[startx][starty] = NULL;
+                sprites[destx][desty] = tstat;
+
+            }
+
+        }
+    }
+
+    for(temp=firstactive; temp; temp=temp->nextactive)
+    {   if ((temp->tilex == startx) && (temp->tiley == starty))
+        {   temp->x += ((destx - temp->tilex) << TILESHIFT);
+            temp->y += ((desty - temp->tiley) << TILESHIFT);
+            temp->tilex = temp->x >> TILESHIFT;
+            temp->tiley = temp->y >> TILESHIFT;
+            if (temp->obclass!=inertobj)
+            {
+                RemoveFromArea (temp);
+                temp->areanumber = AREANUMBER(temp->tilex,temp->tiley);
+                MakeLastInArea (temp);
+            }
+            if (temp == player)
+                SHAKETICS = 10;
+        }
+    }
+
+
+
+}
+
+
+
+void OperateElevatorDoor(int dnum)
+{
+    elevator_t*eptr;
+    doorobj_t *dptr,*door1,*door2;
+
+    dptr = doorobjlist[dnum];
+    eptr = &ELEVATOR[dptr->eindex];
+    door1 = doorobjlist[eptr->door1];
+    door2 = doorobjlist[eptr->door2];
+
+    switch(eptr->state)
+    {   /*
+    case ev_mtd:               // if already on the way to request,
+    								 // ignore; else, put request in
+    if (dnum == eptr->door1)
+      {eptr->nextaction = ev_mts;
+    	//eptr->doortoopen = eptr->door1;
+        #if (DEVELOPMENT == 1)
+        #if (ELEVATORTEST == 1)
+    	Debug("\nplayer at source requesting elev %d mtd",dptr->eindex);
+    	#endif
+    	#endif
+      }
+    break;
+
+    case ev_mts:
+    if (dnum == eptr->door2)
+      {eptr->nextaction = ev_mtd;
+    	//eptr->doortoopen = eptr->door2;
+        #if (DEVELOPMENT == 1)
+        #if (ELEVATORTEST == 1)
+    	Debug("\nplayer at dest requesting elev %d mts",dptr->eindex);
+    	#endif
+    	#endif
+      }
+    break;
+    */
+    case ev_rad:                          // if ready at other place,
+        if ((dnum == eptr->door1) && (eptr->nextaction != ev_mts))  // process request, lock doors,
+
+        {
+#if (DEVELOPMENT == 1)
+#if (ELEVATORTEST == 1)
+            Debug("\nplayer at source requesting elev %d rad",dptr->eindex);
+#endif
+#endif
+            // start moving to current loc;
+            SetNextAction(eptr,0);		// if already there, do nothing
+
+        }
+        break;
+
+    case ev_ras:
+        if ((dnum == eptr->door2) && (eptr->nextaction != ev_mtd))
+        {
+#if (DEVELOPMENT == 1)
+#if (ELEVATORTEST == 1)
+            Debug("\nplayer at dest requesting elev %d ras",dptr->eindex);
+#endif
+#endif
+            SetNextAction(eptr,1);
+
+        }
+        break;
+
+    case ev_doorclosing:
+        if (eptr->doorclosing == dnum)      // if opening door at current loc,
+            // reset elev state to ready
+        {   //if (eptr->door1 == dnum)
+            // eptr->nextaction = ev_ras;
+            //else
+            //eptr->nextaction = ev_rad;
+        }
+        else                                //else prepare for movement
+        {   if ((eptr->door1 == dnum) && (eptr->nextaction != ev_mts))
+            {
+#if ((DEVELOPMENT == 1))
+#if ((ELEVATORTEST == 1))
+                Debug("\nplayer at source requesting elev %d dc",dptr->eindex);
+#endif
+#endif
+                SetNextAction(eptr,0);
+
+            }
+            else if ((eptr->door2 == dnum) && (eptr->nextaction != ev_mtd))
+            {
+#if ((DEVELOPMENT == 1))
+#if ((ELEVATORTEST == 1))
+                Debug("\nplayer at dest requesting elev %d dc",dptr->eindex);
+#endif
+#endif
+                SetNextAction(eptr,1);
+
+            }
+        }
+        break;
+
+
+    }
+
+}
+
+
+int SetNextAction(elevator_t*eptr,int action)
+{   int dn;
+
+    if (action)
+    {   if (!DoorReadyToClose(eptr->door1))
+            return false;
+
+        eptr->nextaction = ev_mtd;
+        dn = eptr->door1;
+    }
+    else
+    {   if (!DoorReadyToClose(eptr->door2))
+            return false;
+
+        eptr->nextaction = ev_mts;
+        dn = eptr->door2;
+    }
+    eptr->state = ev_doorclosing;
+
+    eptr->doorclosing = dn;
+#if (DEVELOPMENT == 1)
+#if (ELEVATORTEST == 1)
+    Debug("\nCloseDoor %d",dn);
+#endif
+#endif
+    if (doorobjlist[dn]->action != dr_closed)
+        CloseDoor(dn);
+    doorobjlist[dn]->flags |= DF_ELEVLOCKED;
+
+    return true;
+}
+
+
+void OperateElevatorSwitch(objtype*ob,int elevnum,int checkx,int checky)
+{   elevator_t*eptr;
+    doorobj_t *door1,*door2;
+
+    eptr = &ELEVATOR[elevnum];
+
+    if ((eptr->state == ev_mts) ||
+            (eptr->state == ev_mtd))
+    {
+#if (DEVELOPMENT == 1)
+#if (ELEVATORTEST == 1)
+        Debug("\nobj %d tried to use elevator %d switch while in use",ob->obclass,elevnum);
+#endif
+#endif
+        return;
+    }
+
+    door1 = doorobjlist[eptr->door1];
+    door2 = doorobjlist[eptr->door2];
+
+    if ((abs(ob->tilex-door1->tilex)<=1) && //switch at source
+            (abs(ob->tiley-door1->tiley)<=1))
+    {   if (!SetNextAction(eptr,1)) // set next to dest
+            return;
+#if (DEVELOPMENT == 1)
+#if (ELEVATORTEST == 1)
+        Debug("\nswitch at src %d flipped",elevnum);
+#endif
+#endif
+        eptr->ticcount = 0;
+    }
+    else //switch at dest
+    {   if (!SetNextAction(eptr,0)) // set next to src
+            return;
+#if (DEVELOPMENT == 1)
+#if (ELEVATORTEST == 1)
+        Debug("\nswitch at dest %d flipped",elevnum);
+#endif
+#endif
+        eptr->ticcount = 0;
+    }
+
+    tilemap[checkx][checky] = (elevatorstart + 6) | 0x2000;
+    SD_PlaySoundRTP(SD_TOUCHPLATESND,ob->x,ob->y);
+
+}
+
+
+
+
+/*
+=====================
+=
+= MoveDoors
+=
+= Called from PlayLoop
+=
+=====================
+*/
+
+void MoveDoors (void)
+{
+    int		door;
+
+    for (door = 0 ; door < doornum ; door++)
+        switch (doorobjlist[door]->action)
+        {
+        case dr_open:
+            DoorOpen (door);
+            break;
+
+        case dr_opening:
+            DoorOpening(door);
+            SD_PanRTP ( doorobjlist[door]->soundhandle, doorobjlist[door]->tilex<<16, doorobjlist[door]->tiley<<16 );
+            break;
+
+        case dr_closing:
+            DoorClosing(door);
+            SD_PanRTP ( doorobjlist[door]->soundhandle, doorobjlist[door]->tilex<<16, doorobjlist[door]->tiley<<16 );
+            break;
+        default:
+            ;
+        }
+}
+
+
+//===========================================================
+//
+//                   PUSHWALLS
+//
+//===========================================================
+
+
+/*
+===============
+=
+= GetAreaNumber
+=
+===============
+*/
+int GetAreaNumber ( int tilex, int tiley, int dir )
+{
+    int up,dn,lt,rt;
+
+    up=MAPSPOT(tilex,tiley-1,0)-AREATILE;
+    dn=MAPSPOT(tilex,tiley+1,0)-AREATILE;
+    lt=MAPSPOT(tilex-1,tiley,0)-AREATILE;
+    rt=MAPSPOT(tilex+1,tiley,0)-AREATILE;
+    if ((up<=0) || (up>NUMAREAS)) up=0;
+    if ((dn<=0) || (dn>NUMAREAS)) dn=0;
+    if ((lt<=0) || (lt>NUMAREAS)) lt=0;
+    if ((rt<=0) || (rt>NUMAREAS)) rt=0;
+    switch (dir)
+    {
+    case north:
+        if (up)
+            return up;
+        else if (dn)
+            return dn;
+        break;
+    case south:
+        if (dn)
+            return dn;
+        else if (up)
+            return up;
+        break;
+    case east:
+        if (rt)
+            return rt;
+        else if (lt)
+            return lt;
+        break;
+    case west:
+        if (lt)
+            return lt;
+        else if (rt)
+            return rt;
+        break;
+    }
+    if (up)
+        return up;
+    else if (dn)
+        return dn;
+    else if (lt)
+        return lt;
+    else if (rt)
+        return rt;
+    else
+        Error("Cannot find an area number for tile at x=%d y=%d\n",tilex,tiley);
+    return -1;
+}
+
+/*
+===============
+=
+= SpawnPushWall
+=
+===============
+*/
+
+void SpawnPushWall (int tilex, int tiley, int lock, int texture, int dir, int type)
+{
+    pwallobj_t * lastpwallobj;
+
+    if (pwallnum==MAXPWALLS)
+        Error ("MAXPWALLS on level!");
+
+    pwallobjlist[pwallnum]=(pwallobj_t*)Z_LevelMalloc(sizeof(pwallobj_t),PU_LEVELSTRUCT,NULL);
+    memset(pwallobjlist[pwallnum],0,sizeof(pwallobj_t));
+    lastpwallobj=pwallobjlist[pwallnum];
+
+    lastpwallobj->x = (tilex<<16)+0x8000;
+    lastpwallobj->y = (tiley<<16)+0x8000;
+    lastpwallobj->momentumx=0;
+    lastpwallobj->momentumy=0;
+    lastpwallobj->tilex = tilex;
+    lastpwallobj->tiley = tiley;
+    lastpwallobj->lock = lock;
+    lastpwallobj->action = pw_npushed;
+    lastpwallobj->which = PWALL;
+    lastpwallobj->dir = dir;
+    lastpwallobj->num = pwallnum;
+    actorat[tilex][tiley] = (pwallobj_t*)(lastpwallobj);	// consider it a solid wall
+
+    if ( (MAPSPOT(tilex,tiley,0)==44) ||
+            (MAPSPOT(tilex,tiley,0)==233)
+       )
+        lastpwallobj->flags=PW_DAMAGE;
+
+    lastpwallobj->texture = texture;
+    if (!texture&0x1000)
+        PreCacheLump(texture,PU_CACHEWALLS,cache_pic_t);
+    lastpwallobj->areanumber = GetAreaNumber(tilex,tiley,lastpwallobj->dir);
+
+    MAPSPOT (tilex, tiley, 0)=(word)(lastpwallobj->areanumber+AREATILE);
+
+    switch(type)
+    {
+    case 0:
+    case 1:
+    case 3:
+        lastpwallobj->speed = 2;
+        break;
+    case 2:
+    case 4:
+        lastpwallobj->speed = 4;
+        break;
+    default:
+        Error("Illegal PushWall type passed into SpawnPushWall\n");
+        break;
+    }
+    if (type>2)
+    {
+        tilemap[tilex][tiley] = 0;
+        ActivateMoveWall(pwallnum);
+    }
+    else
+    {
+        tilemap[tilex][tiley] = texture|0x800;
+        if ((loadedgame==false) && (type==0))
+            gamestate.secrettotal++;
+    }
+
+    pwallnum++;
+    lastpwallobj++;
+
+    SD_PreCacheSoundGroup(SD_PUSHWALLSND,SD_TURBOWALLSND);
+}
+
+
+
+/*
+=====================
+=
+= OperatePushWall
+=
+= The player wants to change the pushwall's direction
+=
+=====================
+*/
+void OperatePushWall (int pwall, int dir, boolean localplayer )
+{
+    pwallobj_t * pw;
+
+    pw=pwallobjlist[pwall];
+
+    if (pw->lock)
+    {
+        if ( localplayer )
+        {
+            // Can't push
+            AddMessage("This push wall appears to be locked...",MSG_DOOR);
+            PlayNoWaySound();
+        }
+        return;
+    }
+    switch (pw->action)
+    {
+    case pw_npushed:
+        if ((dir!=pw->dir) && (pw->dir!=nodir))
+        {
+            // Can't push
+            if ( localplayer )
+            {
+                PlayNoWaySound();
+            }
+            return;
+        }
+        else if (localplayer && (gamestate.difficulty == gd_baby))
+            AddMessage("Push Wall Activated.",MSG_GAME);
+
+        pw->action=pw_pushing;
+        pw->dir=dir;
+        SD_PlaySoundRTP ( SD_TOUCHPLATESND, pw->x, pw->y );
+        ConnectPushWall(pwall);
+        SetupPushWall(pwall);
+        gamestate.secretcount++;
+        break;
+    default:
+        // Can't push
+        if ( localplayer )
+        {
+            PlayNoWaySound();
+        }
+        break;
+    }
+}
+
+/*
+=====================
+=
+= ActivateAllPushWalls
+=
+= A Push wall has beeen activated by a touch plate
+=
+=====================
+*/
+
+void ActivateAllPushWalls(void)
+{
+    int i;
+
+    for(i=0; i<pwallnum; i++)
+    {
+        if (pwallobjlist[i]->dir != nodir)
+        {
+            ActivatePushWall(i);
+        }
+    }
+}
+
+/*
+=====================
+=
+= ActivatePushWall
+=
+= A Push wall has beeen activated by a touch plate
+=
+=====================
+*/
+
+void ActivatePushWall (long pwall)
+{
+    pwallobj_t * pw;
+
+    pw=pwallobjlist[pwall];
+
+    switch (pw->action)
+    {
+    case pw_npushed:
+        pw->action=pw_pushing;
+        ConnectPushWall(pwall);
+        SetupPushWall(pwall);
+        gamestate.secretcount++;
+        break;
+    default:
+        // Can't push
+        SD_Play( SD_BADTOUCHSND );
+        break;
+    }
+}
+
+/*
+=====================
+=
+= ActivateMoveWall
+=
+= A Push wall has beeen activated by a touch plate
+=
+=====================
+*/
+
+void ActivateMoveWall (long pwall)
+{
+    pwallobj_t * pw;
+
+    pw=pwallobjlist[pwall];
+
+    switch (pw->action)
+    {
+    case pw_npushed:
+        pw->action=pw_moving;
+        SetupPushWall(pwall);
+        break;
+    default:
+        SD_Play( SD_BADTOUCHSND );
+        break;
+    }
+}
+
+
+
+/*
+===============
+=
+= ConnectPushWall
+=
+===============
+*/
+
+void ConnectPushWall (int pwall)
+{
+    int      checkx;
+    int      checky;
+    int		area1,area2;
+    int		area3,area4;
+    word  	*map;
+    pwallobj_t * pw;
+
+    pw=pwallobjlist[pwall];
+
+    checkx=pw->tilex;
+    checky=pw->tiley;
+    tilemap[checkx][checky] = 0;
+    map = &MAPSPOT (checkx, checky, 0);
+
+    area1 =	*(map-mapwidth);
+    area2 =	*(map+mapwidth);
+    area3 =  *(map+1);
+    area4 =  *(map-1);
+
+    area1 -= AREATILE;
+    area2 -= AREATILE;
+    area3 -= AREATILE;
+    area4 -= AREATILE;
+    if (((area1>0) && (area1<NUMAREAS)) &&
+            ((area2>0) && (area2<NUMAREAS)))
+    {
+        areaconnect[area1][area2]++;
+        areaconnect[area2][area1]++;
+
+        if ((insetupgame==false) && (loadedgame==false))
+            ConnectAreas ();
+    }
+    if (((area3>0) && (area3<NUMAREAS)) &&
+            ((area4>0) && (area4<NUMAREAS)))
+    {
+        areaconnect[area3][area4]++;
+        areaconnect[area4][area3]++;
+
+        if ((insetupgame==false) && (loadedgame==false))
+            ConnectAreas ();
+    }
+}
+
+/*
+===============
+=
+= SetupPushWall
+=
+===============
+*/
+
+void SetupPushWall (int pwall)
+{
+    pwallobj_t * pw;
+    int speed;
+
+    pw=pwallobjlist[pwall];
+    speed=pw->speed<<PUSHWALLSPEED;
+    switch (pw->dir)
+    {
+    case north:
+        pw->momentumx=0;
+        pw->momentumy=-speed;
+        break;
+
+    case east:
+        pw->momentumx=speed;
+        pw->momentumy=0;
+        break;
+
+    case northeast:
+        pw->momentumx=speed;
+        pw->momentumy=-speed;
+        break;
+
+    case southeast:
+        pw->momentumx=speed;
+        pw->momentumy=speed;
+        break;
+
+    case south:
+        pw->momentumx=0;
+        pw->momentumy=speed;
+        break;
+
+    case west:
+        pw->momentumx=-speed;
+        pw->momentumy=0;
+        break;
+
+    case northwest:
+        pw->momentumx=-speed;
+        pw->momentumy=-speed;
+        break;
+
+    case southwest:
+        pw->momentumx=-speed;
+        pw->momentumy=speed;
+        break;
+    }
+    if (pw->action==pw_pushing)
+    {
+        if (loadedgame==false)
+            pw->soundhandle=SD_PlaySoundRTP ( SD_PUSHWALLSND, pw->x, pw->y );
+        pw->state=(0x20000L/speed);
+    }
+    if (pw->action==pw_moving)
+        pw->state=(0x10000L/speed);
+}
+
+
+/*
+=====================
+=
+= MovePWalls
+=
+= Called from PlayLoop
+=
+=====================
+*/
+
+void MovePWalls (void)
+{
+    int		pwall;
+
+    for (pwall = 0 ; pwall < pwallnum ; pwall++)
+    {
+        if (pwallobjlist[pwall]->action==pw_pushing)
+        {
+            WallPushing (pwall);
+            SD_PanRTP (pwallobjlist[pwall]->soundhandle, pwallobjlist[pwall]->x, pwallobjlist[pwall]->y );
+        }
+        if (pwallobjlist[pwall]->action==pw_moving)
+        {
+            WallMoving (pwall);
+            SD_PanRTP (pwallobjlist[pwall]->soundhandle, pwallobjlist[pwall]->x, pwallobjlist[pwall]->y );
+        }
+    }
+}
+
+
+void ClearActorat(pwallobj_t*pw)
+{   int txhigh,txlow,tyhigh,tylow;
+    int tryx,tryy,x,y;
+    int pwrad = 0x6fff;
+
+
+    tryx = pw->x;
+    tryy = pw->y;
+    txlow = (tryx - pwrad) >> 16;
+    txhigh = (tryx + pwrad) >> 16;
+    tylow = (tryy - pwrad) >> 16;
+    tyhigh = (tryy + pwrad) >> 16;
+    for(y=tylow; y<=tyhigh; y++)
+        for(x=txlow; x<=txhigh; x++)
+        {   if (actorat[x][y] == pw)
+                actorat[x][y] = NULL;
+        }
+}
+
+void SetActorat(pwallobj_t*pw)
+{   int txhigh,txlow,tyhigh,tylow;
+    int tryx,tryy,x,y;
+    int pwrad = 0x6fff;
+
+    tryx = pw->x;
+    tryy = pw->y;
+    txlow = (tryx - pwrad) >> 16;
+    txhigh = (tryx + pwrad) >> 16;
+    tylow = (tryy - pwrad) >> 16;
+    tyhigh = (tryy + pwrad) >> 16;
+
+    for(y=tylow; y<=tyhigh; y++)
+        for(x=txlow; x<=txhigh; x++)
+            actorat[x][y] = pw;
+}
+
+/*
+=================
+=
+= FinishPushWall
+=
+=================
+*/
+void FinishPushWall (pwallobj_t * pw)
+{
+    pw->action = pw_pushed;
+    actorat[pw->tilex][pw->tiley] = (wall_t*)&walls[GetWallIndex(pw->texture)];
+    tilemap[pw->tilex][pw->tiley] = pw->texture;
+}
+
+/*
+=================
+=
+= ResetPushWall
+=
+=================
+*/
+void ResetPushWall (pwallobj_t * pw)
+{
+    SetActorat(pw);
+    tilemap[pw->tilex][pw->tiley] = pw->texture|0x800;
+}
+
+/*
+=================
+=
+= WallPushing
+=
+=================
+*/
+void WallPushing (int pwall)
+{
+    int      checkx,checky;
+    int      spot;
+    pwallobj_t * pw;
+
+    pw=pwallobjlist[pwall];
+
+    ClearActorat(pw);
+
+    PushWallMove(pwall);
+    pw->x+=pw->momentumx;
+    pw->y+=pw->momentumy;
+
+    pw->state--;
+
+    checkx=pw->tilex;
+    checky=pw->tiley;
+
+    pw->tilex=pw->x>>16;
+    pw->tiley=pw->y>>16;
+
+    if ((pw->tilex!=checkx) || (pw->tiley!=checky))
+    {
+        int x,y;
+        int area = MAPSPOT(pw->tilex,pw->tiley,0)-AREATILE;
+
+        if ((area<=0) || (area>NUMAREAS))
+        {
+            area=pw->areanumber;
+            MAPSPOT (pw->tilex, pw->tiley, 0)=(word)(pw->areanumber+AREATILE);
+        }
+        // block crossed into a new block
+        //
+        // the tile can now be walked into
+        //
+        mapseen[checkx][checky] = 0;
+        pw->areanumber = area;
+        if (pw->momentumx>0)
+            x=1;
+        else if (pw->momentumx<0)
+            x=-1;
+        else
+            x=0;
+        if (pw->momentumy>0)
+            y=1;
+        else if (pw->momentumy<0)
+            y=-1;
+        else
+            y=0;
+        if (tilemap[pw->tilex+x][pw->tiley+y])
+        {
+            pw->state=(0x8000L/(pw->speed<<PUSHWALLSPEED));
+        }
+        if (actorat[pw->tilex+x][pw->tiley+y])
+            ResolveDoorSpace(pw->tilex+x,pw->tiley+y);
+    }
+
+
+    if (pw->state==0)
+    {
+        pw->x=(pw->tilex<<16)+0x8000;
+        pw->y=(pw->tiley<<16)+0x8000;
+        spot = MAPSPOT(pw->tilex,pw->tiley,1)-ICONARROWS;
+        if ((spot >= 0) && (spot <= 7))
+        {
+            pw->action = pw_npushed;
+            pw->dir = spot;
+            ResetPushWall (pw);
+            if (pw->lock)
+            {
+                pw->action=pw_pushing;
+                ConnectPushWall(pwall);
+                SetupPushWall(pwall);
+            }
+            else
+            {
+                gamestate.secrettotal++;
+            }
+        }
+        else
+        {
+            FinishPushWall (pw);
+        }
+    }
+    else
+        SetActorat(pw);
+}
+
+
+/*
+=================
+=
+= WallMoving
+=
+=================
+*/
+void WallMoving (int pwall)
+{
+    int      checkx,checky;
+    int      spot;
+    pwallobj_t * pw;
+
+    pw=pwallobjlist[pwall];
+
+    ClearActorat(pw);
+
+    PushWallMove(pwall);
+    pw->x+=pw->momentumx;
+    pw->y+=pw->momentumy;
+
+    pw->state--;
+
+    checkx=pw->tilex;
+    checky=pw->tiley;
+
+    pw->tilex=pw->x>>16;
+    pw->tiley=pw->y>>16;
+
+    if ((pw->tilex!=checkx) || (pw->tiley!=checky))
+    {
+        int area = MAPSPOT(pw->tilex,pw->tiley,0)-AREATILE;
+
+        if ((area<=0) || (area>NUMAREAS))
+        {
+            area=pw->areanumber;
+            MAPSPOT (pw->tilex, pw->tiley, 0)=(word)(pw->areanumber+AREATILE);
+        }
+        // block crossed into a new block
+        //
+        // the tile can now be walked into
+        //
+        if (areabyplayer[area])
+        {
+            if (pw->speed==2)
+                pw->soundhandle=SD_PlaySoundRTP ( SD_GOWALLSND, pw->x, pw->y );
+            else
+                pw->soundhandle=SD_PlaySoundRTP ( SD_TURBOWALLSND, pw->x, pw->y );
+        }
+
+        if (actorat[pw->tilex][pw->tilex])
+            ResolveDoorSpace(pw->tilex,pw->tiley);
+        mapseen[checkx][checky] = 0;
+        pw->areanumber = MAPSPOT (pw->tilex, pw->tiley, 0)-AREATILE;
+        //actorat[pw->tilex][pw->tiley]=pw;
+        if ( (pw->tilex==0) || (pw->tilex==127) ||
+                (pw->tiley==0) || (pw->tiley==127) )
+        {
+            if (W_CheckNumForName("imfree")>=0)
+            {
+                lbm_t *LBM;
+
+                LBM = (lbm_t *) W_CacheLumpNum (W_GetNumForName ("imfree"), PU_CACHE, Cvt_lbm_t, 1);
+                VL_DecompressLBM (LBM,true);
+                VW_UpdateScreen ();
+                I_Delay (2000);
+            }
+            Error ("PushWall Attempting to escape off the edge of the map\nIt is located at x=%d y=%d\nI'm Free!!!!\n",
+                   pw->tilex, pw->tiley);
+        }
+    }
+    if (pw->state==0)
+    {
+        pw->x=(pw->tilex<<16)+0x8000;
+        pw->y=(pw->tiley<<16)+0x8000;
+        spot = MAPSPOT(pw->tilex,pw->tiley,1)-ICONARROWS;
+        if ((spot >= 0) && (spot <= 7))
+        {
+            int area = MAPSPOT(pw->tilex,pw->tiley,0)-AREATILE;
+
+            if ((area<=0) || (area>NUMAREAS))
+            {
+                area=pw->areanumber;
+                MAPSPOT (pw->tilex, pw->tiley, 0)=(word)(pw->areanumber+AREATILE);
+            }
+
+            if (areabyplayer[area] && (abs(spot-pw->dir)==4))
+                SD_PlaySoundRTP ( SD_PUSHWALLHITSND, pw->x, pw->y );
+            pw->dir = spot;
+        }
+        SetupPushWall(pwall);
+    }
+    else
+        SetActorat(pw);
+}
+
+
+
+/*
+=================
+=
+= SavePushWalls
+=
+=================
+*/
+void SavePushWalls(byte ** buf, int * sz)
+{
+    int unitsize;
+    pwallobj_t * pw;
+    byte * bufptr;
+    int i;
+    int size;
+
+    if (pwallnum==0)
+    {
+        *sz=0;
+        *buf=SafeMalloc(16);
+        return;
+    }
+    pw=pwallobjlist[0];
+    unitsize=0;
+    unitsize+=sizeof(pw->state);
+    unitsize+=sizeof(pw->x);
+    unitsize+=sizeof(pw->y);
+    unitsize+=sizeof(pw->dir);
+    unitsize+=sizeof(pw->speed);
+    unitsize+=sizeof(pw->action);
+
+    *sz=pwallnum*unitsize;
+
+    *buf=SafeMalloc(*sz);
+    bufptr=*buf;
+
+    for (i=0; i<pwallnum; i++)
+    {
+        pw=pwallobjlist[i];
+        size=sizeof(pw->state);
+        memcpy(bufptr,&(pw->state),size);
+        bufptr+=size;
+
+        size=sizeof(pw->x);
+        memcpy(bufptr,&(pw->x),size);
+        bufptr+=size;
+
+        size=sizeof(pw->y);
+        memcpy(bufptr,&(pw->y),size);
+        bufptr+=size;
+
+        size=sizeof(pw->dir);
+        memcpy(bufptr,&(pw->dir),size);
+        bufptr+=size;
+
+        size=sizeof(pw->speed);
+        memcpy(bufptr,&(pw->speed),size);
+        bufptr+=size;
+
+        size=sizeof(pw->action);
+        memcpy(bufptr,&(pw->action),size);
+        bufptr+=size;
+    }
+}
+
+/*
+=================
+=
+= LoadPushWalls
+=
+=================
+*/
+void LoadPushWalls(byte * bufptr, int sz)
+{
+    int unitsize;
+    pwallobj_t * pw;
+    pwallobj_t new;
+    int i;
+    int num;
+    int size;
+    int area;
+
+    if (sz==0)
+        return;
+    SetupPushWalls();
+    pw=pwallobjlist[0];
+    unitsize=0;
+    unitsize+=sizeof(pw->state);
+    unitsize+=sizeof(pw->x);
+    unitsize+=sizeof(pw->y);
+    unitsize+=sizeof(pw->dir);
+    unitsize+=sizeof(pw->speed);
+    unitsize+=sizeof(pw->action);
+
+    num=sz/unitsize;
+    if (pwallnum!=num)
+        Error("Different number of Push Walls when trying to load a game\npwallnum=%d num=%d",pwallnum,num);
+
+    for (i=0; i<pwallnum; i++)
+    {
+        pw=pwallobjlist[i];
+
+        size=sizeof(new.state);
+        memcpy(&(new.state),bufptr,size);
+        bufptr+=size;
+
+        size=sizeof(new.x);
+        memcpy(&(new.x),bufptr,size);
+        bufptr+=size;
+
+        size=sizeof(new.y);
+        memcpy(&(new.y),bufptr,size);
+        bufptr+=size;
+
+        size=sizeof(new.dir);
+        memcpy(&(new.dir),bufptr,size);
+        bufptr+=size;
+
+        size=sizeof(new.speed);
+        memcpy(&(new.speed),bufptr,size);
+        bufptr+=size;
+
+        size=sizeof(new.action);
+        memcpy(&(new.action),bufptr,size);
+        bufptr+=size;
+
+        actorat[pw->tilex][pw->tiley] = 0;
+        mapseen[pw->tilex][pw->tiley] = 0;
+
+        new.tilex=new.x>>16;
+        new.tiley=new.y>>16;
+
+        if ((new.tilex!=pw->tilex) || (new.tiley!=pw->tiley))
+        {
+            ClearActorat(pw);
+            tilemap[pw->tilex][pw->tiley] = 0;
+            if (pw->state!=pw_moving)
+            {
+#if 0
+                if (pw->dir==nodir)
+                {
+                    if (tilemap[pw->tilex+1][pw->tiley]==0)
+                        pw->dir=east;
+                    else if (tilemap[pw->tilex-1][pw->tiley]==0)
+                        pw->dir=west;
+                    else if (tilemap[pw->tilex][pw->tiley+1]==0)
+                        pw->dir=south;
+                    else
+                        pw->dir=north;
+                }
+#endif
+                ConnectPushWall(i);
+            }
+        }
+
+//   fixup area if needed
+
+        area = MAPSPOT(new.tilex,new.tiley,0)-AREATILE;
+        if ((area<=0) || (area>NUMAREAS))
+        {
+            MAPSPOT (new.tilex, new.tiley, 0)=(word)(pw->areanumber+AREATILE);
+        }
+
+        pw->tilex=new.tilex;
+        pw->tiley=new.tiley;
+        pw->x=new.x;
+        pw->y=new.y;
+        pw->action=new.action;
+        pw->dir=new.dir;
+        pw->speed=new.speed;
+        SetupPushWall(i);
+        pw->state=new.state;
+
+        pw->areanumber = MAPSPOT (pw->tilex, pw->tiley, 0)-AREATILE;
+
+        if (pw->action==pw_pushed)
+        {
+            FinishPushWall (pw);
+        }
+        else if (pw->action==pw_npushed)
+        {
+            ResetPushWall (pw);
+        }
+        else
+        {
+            SetActorat(pw);
+        }
+    }
+}
+
+
+
+
+
+/*
+=================
+=
+= SaveMaskedWalls
+=
+=================
+*/
+void SaveMaskedWalls(byte ** buf, int * size)
+{
+    int unitsize;
+    maskedwallobj_t * mw;
+    byte * bufptr;
+    int i;
+    int sz;
+
+    if (maskednum==0)
+    {
+        *size=0;
+        *buf=SafeMalloc(16);
+        return;
+    }
+    mw=maskobjlist[0];
+    unitsize=0;
+    unitsize+=sizeof(mw->flags);
+
+    *size=maskednum*unitsize;
+
+    *buf=SafeMalloc(*size);
+    bufptr=*buf;
+
+    for (i=0; i<maskednum; i++)
+    {
+        mw=maskobjlist[i];
+        sz=sizeof(mw->flags);
+        memcpy(bufptr,&(mw->flags),sz);
+        bufptr+=sz;
+    }
+}
+
+/*
+=================
+=
+= LoadMaskedWalls
+=
+=================
+*/
+void LoadMaskedWalls(byte * bufptr, int sz)
+{
+    int unitsize;
+    maskedwallobj_t * mw;
+    int i;
+    int size;
+    int num;
+
+    if (sz==0)
+        return;
+
+    SetupMaskedWalls();
+    FixMaskedWallAreaNumbers();
+
+    mw=maskobjlist[0];
+    unitsize=0;
+    unitsize+=sizeof(mw->flags);
+
+    num=sz/unitsize;
+    if (maskednum!=num)
+        Error("Different number of Masked Walls when trying to load a game\nmaskednum=%d num=%d",maskednum,num);
+
+    for (i=0; i<maskednum; i++)
+    {
+        word flags;	// Endianness fix thanks to DrLex - DDOI
+
+        mw=maskobjlist[i];
+        size=sizeof(mw->flags);
+        memcpy(&flags,bufptr,size);
+        bufptr+=size;
+        if ((flags&0xff)!=mw->flags)	// Preserves original behavior
+            UpdateMaskedWall(i);
+        if (mw->flags&MW_SWITCHON)
+            mw->toptexture--;
+    }
+}
+
+
+/*
+=================
+=
+= SaveDoors
+=
+=================
+*/
+
+void SaveDoors (byte ** buf, int * size)
+{
+    int door;
+    int doorsave;
+    byte doorflag;
+    byte doorlocked;
+    signed char dooreindex;
+    short int doortime;
+    int unitsize;
+    byte *ptr;
+
+    if (doornum==0)
+    {
+        *size=0;
+        *buf=SafeMalloc(16);
+        return;
+    }
+
+    //
+    // Size = (int + byte + byte) * numdoors
+    //
+
+    unitsize=0;
+    unitsize+=sizeof(doorsave);
+    unitsize+=sizeof(doorflag);
+    unitsize+=sizeof(doorlocked);
+    unitsize+=sizeof(doortime);
+    unitsize+=sizeof(dooreindex);
+
+    *size = unitsize*doornum;
+    *buf = (byte *) SafeMalloc (*size);
+
+    ptr = *buf;
+
+    for (door = 0; door < doornum ; door++)
+    {
+        doorsave   = doorobjlist[door]->position & ~3;
+        doorsave  |= doorobjlist[door]->action;
+        doorflag   = doorobjlist[door]->flags;
+        doorlocked = doorobjlist[door]->lock;
+        doortime   = doorobjlist[door]->ticcount;
+        dooreindex = doorobjlist[door]->eindex;
+
+        memcpy (ptr, &doorsave, sizeof (doorsave));
+        ptr += sizeof (doorsave);
+        memcpy (ptr, &doorflag, sizeof (doorflag));
+        ptr += sizeof (doorflag);
+        memcpy (ptr, &doorlocked, sizeof (doorlocked));
+        ptr += sizeof (doorlocked);
+        memcpy (ptr, &doortime, sizeof (doortime));
+        ptr += sizeof (doortime);
+        memcpy (ptr, &dooreindex, sizeof (dooreindex));
+        ptr += sizeof (dooreindex);
+    }
+}
+
+
+/*
+=================
+=
+= LoadDoors
+=
+=================
+*/
+
+void LoadDoors (byte * buf, int size)
+{
+    int door;
+    int doorsave;
+    byte doorflag;
+    byte doorlocked;
+    signed char dooreindex;
+    short int doortime;
+    byte *ptr;
+    int unitsize;
+    int num;
+
+    SetupDoors ();
+    FixDoorAreaNumbers();
+    ptr  = buf;
+
+    unitsize=0;
+    unitsize+=sizeof(doorsave);
+    unitsize+=sizeof(doorflag);
+    unitsize+=sizeof(doorlocked);
+    unitsize+=sizeof(doortime);
+    unitsize+=sizeof(dooreindex);
+
+    num=size/unitsize;
+    if (doornum!=num)
+        Error("Different number of Doors when trying to load a game\ndoornum=%d num=%d",doornum,num);
+
+    for (door = 0; door < doornum; door++)
+    {
+        memcpy (&doorsave, ptr, sizeof (doorsave));
+        ptr += sizeof (doorsave);
+        memcpy (&doorflag, ptr, sizeof (doorflag));
+        ptr += sizeof (doorflag);
+        memcpy (&doorlocked, ptr, sizeof (doorlocked));
+        ptr += sizeof (doorlocked);
+        memcpy (&doortime, ptr, sizeof (doortime));
+        ptr += sizeof (doortime);
+        memcpy (&dooreindex, ptr, sizeof (dooreindex));
+        ptr += sizeof (dooreindex);
+
+        doorobjlist[door]->action    = doorsave & 3;
+
+        // Update Areas
+
+        if (doorobjlist[door]->action != dr_closed)
+            DoorOpening(door);
+
+        doorobjlist[door]->action    = doorsave & 3;
+        doorobjlist[door]->position = doorsave;
+        doorobjlist[door]->flags     = doorflag;
+        doorobjlist[door]->lock      = doorlocked;
+        doorobjlist[door]->ticcount  = doortime;
+        doorobjlist[door]->eindex    = dooreindex;
+
+        if (doorobjlist[door]->action == dr_open)
+            doorobjlist[door]->position = 0xFFFF;
+
+        else if (doorobjlist[door]->action == dr_closed)
+            doorobjlist[door]->position = 0;
+
+        if (
+            (doorobjlist[door]->action == dr_closing) ||
+            (doorobjlist[door]->action == dr_closed)
+        )
+        {
+            actorat[doorobjlist[door]->tilex][doorobjlist[door]->tiley] = doorobjlist[door];
+        }
+        doorobjlist[door]->texture = doorobjlist[door]->basetexture +
+                                     ((doorobjlist[door]->position+1)>>13);
+    }
+}
+
+
+/*
+=====================
+=
+= SaveElevators
+=
+=
+=====================
+*/
+
+void SaveElevators(byte ** buffer,int *size)
+{   int i;
+    byte * tptr;
+
+    *size = _numelevators*sizeof(elevator_t);
+
+    *buffer = (byte *)SafeMalloc(*size);
+    tptr = *buffer;
+
+    for(i=0; i<_numelevators; i++)
+    {   memcpy(tptr,&ELEVATOR[i],sizeof(elevator_t));
+        tptr += sizeof(elevator_t);
+    }
+}
+
+
+/*
+=====================
+=
+= LoadElevators
+=
+=
+=====================
+*/
+
+void LoadElevators(byte * buffer,int size)
+{   int i;
+
+    _numelevators = size/sizeof(elevator_t);
+
+
+    for(i=0; i<_numelevators; i++)
+    {   memcpy(&ELEVATOR[i],buffer,sizeof(elevator_t));
+        buffer += sizeof(elevator_t);
+    }
+}
+
--- /dev/null
+++ b/rott/rt_door.h
@@ -1,0 +1,270 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+#ifndef _rt_door_public
+#define _rt_door_public
+
+//***************************************************************************
+//
+//   RT_DOOR.C - doors
+//
+//***************************************************************************
+
+#define MAXTOUCHPLATES 64
+#define MAXMASKED      300  // max masked walls
+#define MAXDOORS       150  // max number of sliding doors
+#define MAXPWALLS      150  // max number of pushwalls
+#define DF_TIMED       0x01
+#define DF_ELEVLOCKED  0x02
+#define DF_MULTI       0x04
+#define MAXELEVATORS   16
+
+#define PW_DAMAGE      0x01
+
+#define NUMELEVATORACTIONS 5
+
+typedef enum
+{   ev_ras, //ready at source
+    ev_rad, //ready at destination
+    ev_mts, //moving to source
+    ev_mtd,  //moving to destination
+    //door at elevator location open
+    ev_doorclosing //door at elevator location closed
+} estate;
+
+typedef enum
+{
+    mw_peephole,
+    mw_dogwall,
+    mw_multi1,
+    mw_multi2,
+    mw_multi3,
+    mw_singlepane,
+    mw_normal1,
+    mw_normal2,
+    mw_normal3,
+    mw_exitarch,
+    mw_secretexitarch,
+    mw_railing,
+    mw_hiswitchon,
+    mw_hiswitchoff,
+    mw_platform1,
+    mw_platform2,
+    mw_platform3,
+    mw_platform4,
+    mw_platform5,
+    mw_platform6,
+    mw_platform7,
+    mw_entrygate
+} masked_walls;
+
+typedef struct elevator
+{   short sx,sy;
+    short dx,dy;
+    short esx,esy,edx,edy;
+    short door1,door2;
+    signed char state;
+    short doortoopen;
+    short doorclosing;
+    short ticcount;
+    short nextaction;
+} elevator_t;
+
+
+typedef struct doorstruct
+{
+    thingtype   which;
+    byte        tilex,tiley;
+    word        texture;
+    word        alttexture;
+    word        sidepic;
+    word        basetexture;
+    byte        lock;
+    byte        flags;
+    short int   ticcount;
+    signed char eindex;
+    boolean     vertical;
+    int         soundhandle;
+    int         position;
+    enum    {dr_open,dr_closed,dr_opening,dr_closing}       action;
+} doorobj_t;
+
+typedef struct pwallstruct
+{
+    thingtype      which;
+    int       x,y;
+    int       momentumx,momentumy;
+    byte      areanumber;
+    byte      lock;
+    byte      dir;
+    byte      tilex,tiley;
+    byte      num;
+    byte      speed;
+    word      texture;
+    int       soundhandle;
+    enum      {pw_npushed,pw_pushing,pw_pushed,pw_moving}       action;
+    int       state;
+    byte      flags;
+} pwallobj_t;
+
+typedef struct tplate
+{   void (*action)(long);
+    void (*swapaction)(long);
+    struct tplate * nextaction;
+    struct tplate * prevaction;
+    long whichobj;
+    byte tictime;
+    byte ticcount;
+    byte triggered;
+    byte done;
+    byte complete;
+    byte clocktype;
+} touchplatetype;
+
+#define MW_SHOOTABLE       0x01
+#define MW_BLOCKING        0x02
+#define MW_MULTI           0x04
+#define MW_BLOCKINGCHANGES 0x08
+#define MW_ABOVEPASSABLE   0x10
+#define MW_NONDOGBLOCKING  0x20
+#define MW_WEAPONBLOCKING  0x40
+#define MW_BOTTOMPASSABLE  0x80
+#define MW_MIDDLEPASSABLE  0x100
+#define MW_ABP             0x200
+#define MW_SWITCHON        0x400
+#define MW_BOTTOMFLIPPING  0x800
+#define MW_TOPFLIPPING     0x1000
+#define M_ISDOOR(x,y) ((tilemap[x][y] & 0x8000) && (!(tilemap[x][y] & 0x4000)))
+#define M_ISMWALL(x,y) ((tilemap[x][y] & 0x8000) && (tilemap[x][y] & 0x4000))
+
+
+typedef struct mwall
+{
+    thingtype      which;
+    byte      tilex,tiley;
+    signed char areanumber;
+    signed short toptexture;
+    signed short midtexture;
+    signed short bottomtexture;
+    word      flags;
+    boolean   vertical;
+    int       sidepic;
+
+    struct mwall *next;
+    struct mwall *prev;
+
+} maskedwallobj_t;
+
+typedef struct animmwall
+{
+    word     num;
+    byte     count;
+    signed char ticcount;
+    struct animmwall *next;
+    struct animmwall *prev;
+
+} animmaskedwallobj_t;
+
+extern elevator_t          ELEVATOR[MAXELEVATORS];
+extern int                 _numelevators;
+extern animmaskedwallobj_t *FIRSTANIMMASKEDWALL,*LASTANIMMASKEDWALL;
+extern maskedwallobj_t     *FIRSTMASKEDWALL,*LASTMASKEDWALL;
+extern byte                touchindices[MAPSIZE][MAPSIZE],lasttouch;
+extern touchplatetype      *touchplate[MAXTOUCHPLATES],*lastaction[MAXTOUCHPLATES];
+extern byte                TRIGGER[MAXTOUCHPLATES];
+
+extern doorobj_t           *doorobjlist[MAXDOORS];
+extern int                 doornum;
+extern maskedwallobj_t     *maskobjlist[MAXMASKED];
+extern int                 maskednum;
+extern pwallobj_t          *pwallobjlist[MAXPWALLS];
+extern int                 pwallnum;
+// 0xffff = fully open
+extern byte                areaconnect[NUMAREAS][NUMAREAS];
+extern boolean             areabyplayer[NUMAREAS];
+
+
+void ActivateAllPushWalls(void);
+boolean CheckTile(int,int);
+void FindEmptyTile(int*,int*);
+int  Number_of_Empty_Tiles_In_Area_Around(int,int);
+void AddTouchplateAction(touchplatetype*,int);
+void RemoveTouchplateAction(touchplatetype*,int);
+
+void InitElevators(void);
+void ProcessElevators(void);
+void OperateElevatorDoor(int);
+
+
+int  PlatformHeight(int,int);
+void Link_To_Touchplate(word, word, void (*)(long), void (*)(long), long, int);
+void TriggerStuff(void);
+void ClockLink(void (*)(long),void(*)(long),long,int);
+void RecursiveConnect(int);
+void ConnectAreas(void);
+void InitAreas(void);
+void InitDoorList(void);
+void SpawnDoor(int,int,int,int);
+void SpawnMaskedWall (int tilex, int tiley, int which, int flags);
+void OpenDoor(int);
+void CloseDoor(int);
+void OperateDoor (int keys, int door, boolean localplayer );
+void DoorOpen(int);
+void DoorOpening(int);
+void DoorClosing(int door);
+void MoveDoors(void);
+void SpawnPushWall (int tilex, int tiley, int lock, int texture, int dir, int type);
+void MovePWalls(void);
+void WallPushing (int pwall);
+void PushWall (int pwall, int dir);
+void OperatePushWall (int pwall, int dir, boolean localplayer );
+void ActivatePushWall (long pwall);
+void ActivateMoveWall (long pwall);
+int  UpdateMaskedWall (int num);
+
+void FixDoorAreaNumbers ( void );
+void FixMaskedWallAreaNumbers ( void );
+void SaveMaskedWalls(byte ** buf, int * size);
+void LoadMaskedWalls(byte * buf, int size);
+void SaveDoors(byte ** buf, int * size);
+void SaveTouchPlates(byte ** buf, int * size);
+void LoadDoors(byte * buf, int size);
+void LoadTouchPlates(byte * buf, int size);
+void SavePushWalls(byte ** buf, int * sz);
+void LoadPushWalls(byte * bufptr, int sz);
+
+void DeactivateAnimMaskedWall(animmaskedwallobj_t* amwall);
+void ActivateAnimMaskedWall(animmaskedwallobj_t* amwall);
+
+void SpawnAnimatedMaskedWall ( int num );
+void KillAnimatedMaskedWall ( animmaskedwallobj_t * temp );
+
+void DoAnimatedMaskedWalls ( void );
+
+void SaveElevators(byte ** buffer,int *size);
+
+void LoadElevators(byte * buffer,int size);
+
+void MakeWideDoorVisible ( int doornum );
+void LinkedCloseDoor (long door);
+void LinkedOpenDoor (long door);
+int IsWall (int tilex, int tiley);
+int IsDoor (int tilex, int tiley);
+int IsMaskedWall (int tilex, int tiley);
+#endif
--- /dev/null
+++ b/rott/rt_dr_a.h
@@ -1,0 +1,45 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+#ifndef _rt_dr_a_public
+#define _rt_dr_a_public
+
+//***************************************************************************
+//
+//    RT_DR_A.ASM - Low level draw stuff, DrawPost
+//
+//***************************************************************************
+
+void SetMode240(void);
+void RefreshClear(void);
+void DrawPost (int height, char * column, char * buf);
+void  DrawHeightPost (int height, byte * src, byte * buf); // IN rt_dr_a.asm
+void R_DrawWallColumn (byte * buf);
+void  DrawMenuPost (int height, byte * src, byte * buf); // IN rt_dr_a.asm
+void  DrawMapPost (int height, byte * src, byte * buf); // IN rt_dr_a.asm
+
+#if defined(__WATCOMC__)
+#pragma aux DrawPost parm [ECX] [ESI] [EDI] modify exact [eax ebx ecx edx esi edi]
+#pragma aux DrawHeightPost parm [ECX] [ESI] [EDI] modify exact [eax ebx ecx edx edi]
+#pragma aux R_DrawWallColumn parm [EDI] modify exact [eax ebx ecx edx esi edi]
+#pragma aux DrawMenuPost parm [ECX] [ESI] [EDI] modify exact [eax ebx ecx edx edi]
+#pragma aux DrawMapPost parm [ECX] [ESI] [EDI] modify exact [eax ebx ecx edx edi]
+#endif
+
+#endif
--- /dev/null
+++ b/rott/rt_draw.c
@@ -1,0 +1,6520 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+// RT_DRAW.C
+
+#include "profile.h"
+#include "rt_def.h"
+#include <string.h>
+
+#ifdef DOS
+#include <dos.h>
+#include <conio.h>
+#endif
+
+#include "watcom.h"
+#include "sprites.h"
+#include "rt_actor.h"
+#include "rt_stat.h"
+#include "rt_draw.h"
+#include "_rt_draw.h"
+#include "rt_dr_a.h"
+#include "rt_fc_a.h"
+#include "rt_scale.h"
+#include "rt_floor.h"
+#include "rt_main.h"
+#include "rt_playr.h"
+#include "rt_door.h"
+#include "rt_ted.h"
+#include "isr.h"
+#include "rt_util.h"
+#include "engine.h"
+#include "z_zone.h"
+#include "w_wad.h"
+#include "lumpy.h"
+#include "rt_menu.h"
+#include "rt_game.h"
+#include "rt_vid.h"
+#include "rt_view.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include "rt_cfg.h"
+#include "rt_str.h"
+#include "develop.h"
+#include "rt_sound.h"
+#include "rt_msg.h"
+#include "modexlib.h"
+#include "rt_rand.h"
+#include "rt_net.h"
+#include "rt_sc_a.h"
+//MED
+#include "memcheck.h"
+
+
+extern void VH_UpdateScreen (void);
+
+
+
+//int testval;
+/*
+=============================================================================
+
+Global Variables                                                                                                                                 GLOBAL VARIABLES
+
+=============================================================================
+*/
+
+int iG_masked;
+
+int whereami=-1;
+
+byte * shadingtable;
+
+word   tilemap[MAPSIZE][MAPSIZE]; // wall values only
+byte   spotvis[MAPSIZE][MAPSIZE];
+byte   mapseen[MAPSIZE][MAPSIZE];
+unsigned long * lights;
+
+int         wstart;
+
+
+const int dirangle8[9] = {0,FINEANGLES/8,2*FINEANGLES/8,3*FINEANGLES/8,4*FINEANGLES/8,
+                          5*FINEANGLES/8,6*FINEANGLES/8,7*FINEANGLES/8,8*FINEANGLES/8
+                         };
+
+const int dirangle16[16] = {0,FINEANGLES/16,2*FINEANGLES/16,3*FINEANGLES/16,
+                            4*FINEANGLES/16,5*FINEANGLES/16,6*FINEANGLES/16,
+                            7*FINEANGLES/16,8*FINEANGLES/16,9*FINEANGLES/16,
+                            10*FINEANGLES/16,11*FINEANGLES/16,12*FINEANGLES/16,
+                            13*FINEANGLES/16,14*FINEANGLES/16,15*FINEANGLES/16
+                           };
+
+//
+// math tables
+//
+
+short   tantable[FINEANGLES];
+int     sintable[FINEANGLES+FINEANGLEQUAD+1],
+        *costable = sintable+(FINEANGLES/4);
+
+//
+// refresh variables
+//
+
+fixed   viewx,viewy;                                                     // the focal point
+int     viewangle;
+int     c_startx, c_starty;
+fixed   viewsin,viewcos;
+int     tics;
+
+//
+// ray tracing variables
+//
+
+long    xintercept,yintercept;
+
+int doublestep=0;
+int hp_startfrac;
+int hp_srcstep;
+
+int levelheight;
+
+int actortime=0;
+int drawtime=0;
+
+visobj_t vislist[MAXVISIBLE],*visptr,*visstep,*farthest;
+
+int firstcoloffset=0;
+
+/*
+==================
+=
+= Local Variables
+=
+==================
+*/
+static int nonbobpheight;
+
+static visobj_t * sortedvislist[MAXVISIBLE];
+
+static const fixed mindist = 0x1000;
+
+static int walltime=0;
+
+static int weaponbobx, weaponboby;
+
+static int      pretics[3];
+static int      preindex;
+static int      netlump;
+static int      gmasklump;
+
+int      G_gmasklump;
+
+static const int weaponshape[NUMWEAPGRAPHICS] =
+{
+#if (SHAREWARE == 0)
+
+    W_KNIFE,
+#endif
+
+    W_MALEPISTOL1,
+    W_MRIGHTPISTOL1,
+    W_MP40,
+    W_BAZOOKA,
+    W_HEATSEEKER,
+    W_DRUNK,
+    W_FIREBOMB,
+    W_FIREWALL,
+    W_GODHAND,
+
+
+#if (SHAREWARE == 0)
+    W_SPLIT,
+    W_KES,
+    W_BAT,
+    W_DOG,
+    W_FEMALEPISTOL1,
+    W_BMALEPISTOL1
+#endif
+};
+
+void SetColorLightLevel (int x, int y, visobj_t * sprite, int dir, int color, int fullbright);
+void DrawRotatedScreen(int cx, int cy, byte *destscreen, int angle, int scale, int masked);
+void InterpolateMaskedWall (visobj_t * plane);
+void InterpolateDoor (visobj_t * plane);
+void InterpolateWall (visobj_t * plane);
+
+/*
+==================
+=
+= BuildTables
+=
+==================
+*/
+
+void BuildTables (void)
+{
+    byte * table;
+    byte * ptr;
+    int   length;
+    int   i;
+
+//
+// load in tables file
+//
+
+    table=W_CacheLumpName("tables",PU_STATIC, CvtNull, 1);
+    ptr=table;
+
+//
+// get size of first table
+//
+
+    memcpy(&length,ptr,sizeof(int));
+    SwapIntelLong(&length);
+
+//
+// skip first table
+//
+
+    ptr+=(length+1)*sizeof(int);
+
+//
+// get size of sin/cos table
+//
+
+    memcpy(&length,ptr,sizeof(int));
+    SwapIntelLong(&length);
+    ptr+=sizeof(int);
+
+//
+// get sin/cos table
+//
+    memcpy(&sintable[0],ptr,length*sizeof(int));
+    SwapIntelLongArray(&sintable[0], length);
+    ptr+=(length)*sizeof(int);
+
+//
+// get size of tangent table
+//
+
+    memcpy(&length,ptr,sizeof(int));
+    SwapIntelLong(&length);
+    ptr+=sizeof(int);
+
+//
+// get tangent table
+//
+    memcpy(tantable,ptr,length*sizeof(short));
+    SwapIntelShortArray(tantable, length);
+    ptr+=(length)*sizeof(short);
+
+//
+// get size of gamma table
+//
+
+    memcpy(&length,ptr,sizeof(int));
+    SwapIntelLong(&length);
+    ptr+=sizeof(int);
+
+//
+// get gamma table
+//
+    memcpy(&gammatable[0],ptr,length*sizeof(byte));
+    table=W_CacheLumpName("tables",PU_CACHE, CvtNull, 1);
+
+    costable = (fixed *)&(sintable[FINEANGLES/4]);
+
+    wstart=W_GetNumForName("WALLSTRT");
+#if (SHAREWARE==0)
+    netlump=W_GetNumForName("net1");
+#endif
+    gmasklump=W_GetNumForName("p_gmask");
+    G_gmasklump = gmasklump;
+
+    preindex=0;
+    pretics[0]=0x10000;
+    pretics[2]=0x10000;
+    pretics[1]=0x10000;
+
+    for(i=0; i<ANGLES; i++)
+    {   angletodir[i] = (i + (ANGLES/16))/(ANGLES/8);
+        if (angletodir[i] == 8)
+            angletodir[i] = 0;
+    }
+
+    // Check out VENDOR.DOC file
+    CheckVendor();
+
+    if (!quiet)
+        printf("RT_DRAW: Tables Initialized\n");
+}
+
+
+/*
+========================
+=
+= TransformObject
+=
+========================
+*/
+
+boolean TransformObject (int x, int y, int *dispx, int *dispheight)
+{
+
+    fixed gx,gy,gxt,gyt,nx,ny;
+
+
+//
+// translate point to view centered coordinates
+//
+    gx = x-viewx;
+    gy = y-viewy;
+
+//
+// calculate newx
+//
+    gxt = FixedMul(gx,viewcos);
+    gyt = FixedMul(gy,viewsin);
+    nx = gxt-gyt;
+
+    if (nx<MINZ)
+        return false;
+
+    // the midpoint could put parts of the shape
+    // into an adjacent wall
+    //
+    // calculate newy
+    //
+    gxt = FixedMul(gx,viewsin);
+    gyt = FixedMul(gy,viewcos);
+    ny = gyt+gxt;
+
+
+//
+// calculate perspective ratio
+//
+
+    *dispx = centerx + ny*scale/nx;            // DEBUG: use assembly divide
+
+    *dispheight = heightnumerator/nx;
+
+    return true;
+}
+
+
+/*
+========================
+=
+= TransformPoint
+=
+========================
+*/
+
+void TransformPoint (int x, int y, int * screenx, int * height, int * texture, int vertical)
+{
+
+    fixed gxt,gyt,nx,ny;
+    fixed gxtt,gytt;
+    int gx,gy;
+    int vx,vy;
+    int svs,svc;
+
+
+//
+// translate point to view centered coordinates
+//
+    gx = x-viewx;
+    gy = y-viewy;
+
+//
+// calculate newx
+//
+    gxt = FixedMul(gx,viewcos);
+    gyt = FixedMul(gy,viewsin);
+    nx =gxt-gyt;
+
+    if (nx<10)
+        nx=10;
+
+
+//
+// calculate newy
+//
+    gxtt = FixedMul(gx,viewsin);
+    gytt = FixedMul(gy,viewcos);
+    ny = gytt+gxtt;
+
+// too close, don't overflow the divid'
+
+
+    *screenx = centerx + ((ny*scale)/nx);            // DEBUG: use assembly divide
+
+    *height = heightnumerator/nx;
+
+
+    if (*screenx<0)
+    {
+        svc=(-centerx)*viewcos;
+        svs=(-centerx)*viewsin;
+        vx=(scale*viewcos)+svs;
+        vy=(-scale*viewsin)+svc;
+        if (vertical)
+        {
+            if ((viewcos-viewsin)==0)
+            {
+                *height=20000<<HEIGHTFRACTION;
+                return;
+            }
+            gy=FixedScale(gx,vy,vx);
+            y=gy+viewy;
+            gyt = FixedMul(gy,viewsin);
+            nx =gxt-gyt;
+            if (nx<10)
+                nx=10;
+            *screenx = 0;
+            *height = heightnumerator/nx;
+        }
+        else
+        {
+            if ((-viewsin-viewcos)==0)
+            {
+                *height=20000<<HEIGHTFRACTION;
+                return;
+            }
+            gx=FixedScale(gy,vx,vy);
+            x=gx+viewx;
+            gxt = FixedMul(gx,viewcos);
+            nx =gxt-gyt;
+            if (nx<10)
+                nx=10;
+            *screenx = 0;
+            *height = heightnumerator/nx;
+        }
+    }
+    else if (*screenx>=viewwidth)
+    {
+        svc=(centerx)*viewcos;
+        svs=(centerx)*viewsin;
+        vx=(scale*viewcos)+svs;
+        vy=(-scale*viewsin)+svc;
+        if (vertical)
+        {
+            if ((viewcos+viewsin)==0)
+            {
+                *height=20000<<HEIGHTFRACTION;
+                return;
+            }
+            gy=FixedScale(gx,vy,vx);
+            y=gy+viewy;
+            gyt = FixedMul(gy,viewsin);
+            nx =gxt-gyt;
+            if (nx<10)
+                nx=10;
+            *screenx = viewwidth-1;
+            *height = heightnumerator/nx;
+        }
+        else
+        {
+            if ((-viewsin+viewcos)==0)
+            {
+                *height=20000<<HEIGHTFRACTION;
+                return;
+            }
+            gx=FixedScale(gy,vx,vy);
+            x=gx+viewx;
+            gxt = FixedMul(gx,viewcos);
+            nx =gxt-gyt;
+            if (nx<10)
+                nx=10;
+            *screenx = viewwidth-1;
+            *height = heightnumerator/nx;
+        }
+    }
+    if (vertical)
+        *texture=(y-*texture)&0xffff;
+    else
+        *texture=(x-*texture)&0xffff;
+}
+
+/*
+========================
+=
+= TransformSimplePoint
+=
+========================
+*/
+
+boolean TransformSimplePoint (int x, int y, int * screenx, int * height, int * texture, int vertical)
+{
+
+    fixed gxt,gyt,nx,ny;
+    fixed gxtt,gytt;
+    int gx,gy;
+
+
+//
+// translate point to view centered coordinates
+//
+    gx = x-viewx;
+    gy = y-viewy;
+
+//
+// calculate newx
+//
+    gxt = FixedMul(gx,viewcos);
+    gyt = FixedMul(gy,viewsin);
+    nx =gxt-gyt;
+
+    if (nx<MINZ)
+        return false;
+
+
+//
+// calculate newy
+//
+    gxtt = FixedMul(gx,viewsin);
+    gytt = FixedMul(gy,viewcos);
+    ny = gytt+gxtt;
+
+// too close, don't overflow the divid'
+
+
+    *screenx = centerx + ((ny*scale)/nx);            // DEBUG: use assembly divide
+
+    *height = heightnumerator/nx;
+
+    if (vertical)
+        *texture=(y-*texture)&0xffff;
+    else
+        *texture=(x-*texture)&0xffff;
+
+    return true;
+}
+
+
+/*
+========================
+=
+= TransformPlane
+=
+========================
+*/
+
+boolean TransformPlane (int x1, int y1, int x2, int y2, visobj_t * plane)
+{
+    boolean result2;
+    boolean result1;
+    boolean vertical;
+    int txstart,txend;
+
+    vertical=((x2-x1)==0);
+    plane->viewx=vertical;
+    txstart=plane->texturestart;
+    txend=plane->textureend;
+    result1=TransformSimplePoint(x1,y1,&(plane->x1),&(plane->h1),&(plane->texturestart),vertical);
+    result2=TransformSimplePoint(x2,y2,&(plane->x2),&(plane->h2),&(plane->textureend),vertical);
+    if (result1==true)
+    {
+        if (plane->x1>=viewwidth)
+            return false;
+        if (result2==false)
+        {
+            plane->textureend=txend;
+            TransformPoint(x2,y2,&(plane->x2),&(plane->h2),&(plane->textureend),vertical);
+        }
+    }
+    else
+    {
+        if (result2==false)
+            return false;
+        else
+        {
+            if (plane->x2<0)
+                return false;
+            plane->texturestart=txstart;
+            TransformPoint(x1,y1,&(plane->x1),&(plane->h1),&(plane->texturestart),vertical);
+        }
+    }
+    if (plane->x1<0)
+    {
+        plane->texturestart=txstart;
+        TransformPoint(x1,y1,&(plane->x1),&(plane->h1),&(plane->texturestart),vertical);
+    }
+    if (plane->x2>=viewwidth)
+    {
+        plane->textureend=txend;
+        TransformPoint(x2,y2,&(plane->x2),&(plane->h2),&(plane->textureend),vertical);
+    }
+
+    plane->viewheight=(plane->h1+plane->h2)>>1;
+
+    if ((plane->viewheight>=(2000<<HEIGHTFRACTION)) || (plane->x1>=viewwidth-1) || (plane->x2<=0))
+        return false;
+
+    return true;
+}
+
+//==========================================================================
+
+/*
+====================
+=
+= CalcHeight
+=
+= Calculates the height of xintercept,yintercept from viewx,viewy
+=
+====================
+*/
+
+int       CalcHeight (void)
+{
+    fixed  gxt,gyt,nx;
+    long            gx,gy;
+
+    whereami=0;
+
+    gx = xintercept-viewx;
+    gxt = FixedMul(gx,viewcos);
+
+    gy = yintercept-viewy;
+    gyt = FixedMul(gy,viewsin);
+
+    nx = gxt-gyt;
+
+    if (nx<mindist)
+        nx=mindist; // don't let divide overflo'
+
+    return (heightnumerator/nx);
+}
+
+
+
+#if 0
+//==========================================================================
+
+//******************************************************************************
+//
+// NextPlaneptr
+//
+//******************************************************************************
+
+void NextPlaneptr ( void )
+{
+    if (planeptr < &planelist[MAXPLANES-1]) // don't let it overflo'
+        planeptr++;
+}
+
+//******************************************************************************
+//
+// RestPlaneptr
+//
+//******************************************************************************
+
+void ResetPlaneptr ( void )
+{
+    planeptr = &planelist[0];
+}
+
+//******************************************************************************
+//
+// NextVisptr
+//
+//******************************************************************************
+
+void NextVisptr ( void )
+{
+    if (visptr < &vislist[MAXVISIBLE-1]) // don't let it overflo'
+        visptr++;
+}
+
+//******************************************************************************
+//
+// ResetVisptr
+//
+//******************************************************************************
+
+void ResetVisptr ( void )
+{
+    visptr = &vislist[0];
+}
+
+#endif
+
+//==========================================================================
+
+
+
+/*
+=====================
+=
+= StatRotate
+=
+=====================
+*/
+
+int  StatRotate (statobj_t *temp)
+{
+    int    angle;
+    int    dx,dy;
+
+    whereami=2;
+
+    dx = temp->x - player->x;
+    dy = player->y - temp->y;
+    angle = atan2_appx(dx,dy);
+
+    angle = angle-VANG180-dirangle8[temp->count];
+    angle+=ANGLES/16;
+    while (angle>=ANGLES)
+        angle-=ANGLES;
+    while (angle<0)
+        angle+=ANGLES;
+
+    return angle/(ANGLES/8);
+
+}
+
+
+
+
+/*
+=====================
+=
+= CalcRotate
+=
+=====================
+*/
+
+int   CalcRotate (objtype *ob)
+{
+    int    angle,viewangle;
+    int    dx,dy;
+    int    rotation;
+
+    whereami=1;
+
+    // this isn't exactly correct, as it should vary by a trig value'
+    // but it is close enough with only eight rotations
+    /*
+    if (ob->obclass == b_robobossobj)
+    	viewangle = player->angle;
+    else
+    	viewangle = player->angle + (centerx - ob->viewx)/8;*/
+    dx = ob->x - player->x;
+    dy = player->y - ob->y;
+    viewangle = atan2_appx(dx,dy);
+
+    if ((ob->obclass >= p_bazookaobj) || (ob->obclass == missileobj))
+    {   angle = viewangle - ob->angle;
+#if (0)
+        Debug("\nviewangle: %d, angle: %d",viewangle,angle);
+#endif
+    }
+    else if ((ob->obclass > wallopobj) && (ob->obclass != b_darksnakeobj))
+        angle =  (viewangle-ANG180)- ob->angle;
+    else if (ob->state->rotate == 16)
+        angle =  (viewangle-ANG180)- dirangle16[ob->dir];
+    else
+        angle =  (viewangle-ANG180)- dirangle8[ob->dir];
+
+    if (ob->state->rotate == true)
+        angle += ANGLES/16;
+    else if (ob->state->rotate == 16)
+        angle += ANGLES/32;
+
+    while (angle>=ANGLES)
+        angle-=ANGLES;
+    while (angle<0)
+        angle+=ANGLES;
+
+    if (ob->state->rotate == 2)        // 2 rotation pain frame
+    {   rotation = 4*(angle/(ANG180));
+        return rotation;
+    }
+
+    if (ob->state->rotate == 16)
+    {   rotation = angle/(ANGLES/16);
+#if (0)
+        Debug("\nrotation: %d", rotation);
+#endif
+        return rotation;
+    }
+    rotation = angle/(ANGLES/8);
+    return rotation;
+
+}
+
+
+
+#if 0
+/*
+=====================
+=
+= DrawMaskedWalls
+=
+=====================
+*/
+
+void DrawMaskedWalls (void)
+{
+
+
+    int   i,numvisible;
+    int   gx,gy;
+    unsigned short int  *tilespot;
+    byte   *visspot;
+    boolean result;
+    statobj_t *statptr;
+    objtype   *obj;
+    maskedwallobj_t* tmwall;
+
+    whereami=6;
+
+//
+// place maskwall objects
+//
+    for(tmwall=FIRSTMASKEDWALL; tmwall; tmwall=tmwall->next)
+    {
+        if (spotvis[tmwall->tilex][tmwall->tiley])
+        {
+            mapseen[tmwall->tilex][tmwall->tiley]=1;
+            if (tmwall->vertical)
+            {
+                gx=(tmwall->tilex<<16)+0x8000;
+                gy=(tmwall->tiley<<16);
+                visptr->texturestart=0;
+                visptr->textureend=0;
+                if (viewx<gx)
+                    result=TransformPlane(gx,gy,gx,gy+0xffff,visptr);
+                else
+                    result=TransformPlane(gx,gy+0xffff,gx,gy,visptr);
+                visptr->shapenum=tmwall->bottomtexture;
+                visptr->altshapenum=tmwall->midtexture;
+                visptr->viewx=tmwall->toptexture;
+                visptr->shapesize=2;
+            }
+            else
+            {
+                gx=(tmwall->tilex<<16);
+                gy=(tmwall->tiley<<16)+0x8000;
+                visptr->texturestart=0;
+                visptr->textureend=0;
+                if (viewy<gy)
+                    result=TransformPlane(gx+0xffff,gy,gx,gy,visptr);
+                else
+                    result=TransformPlane(gx,gy,gx+0xffff,gy,visptr);
+                visptr->shapenum=tmwall->bottomtexture;
+                visptr->altshapenum=tmwall->midtexture;
+                visptr->viewx=tmwall->toptexture;
+                visptr->shapesize=2;
+            }
+            if ((tmwall->flags&MW_TOPFLIPPING) &&
+                    (nonbobpheight>64)
+               )
+            {
+                visptr->viewx++;
+            }
+            else if ((tmwall->flags&MW_BOTTOMFLIPPING) &&
+                     (nonbobpheight>maxheight-32)
+                    )
+            {
+                visptr->shapenum++;
+            }
+            if ((visptr < &vislist[MAXVISIBLE-1]) && (result==true)) // don't let it overflo'
+                visptr++;
+        }
+    }
+}
+#endif
+
+/*
+======================
+=
+= SortScaleds
+= Sort the scaleds using a HEAPSORT
+=
+======================
+*/
+
+#define SGN(x)          ((x>0) ? (1) : ((x==0) ? (0) : (-1)))
+
+/*--------------------------------------------------------------------------*/
+int CompareHeights(s1p,s2p) visobj_t **s1p,**s2p;
+{
+    whereami=3;
+    return SGN((*s1p)->viewheight-(*s2p)->viewheight);
+}
+
+void SwitchPointers(s1p,s2p) visobj_t **s1p,**s2p;
+{
+    visobj_t * temp;
+
+    whereami=4;
+    temp=*s1p;
+    *s1p=*s2p;
+    *s2p=temp;
+}
+
+
+void SortVisibleList( int numvisible, visobj_t * vlist )
+{
+    int i;
+
+    whereami=5;
+    for (i=0; i<numvisible; i++)
+        sortedvislist[i]=&(vlist[i]);
+    hsort((char *)&(sortedvislist[0]),numvisible,sizeof(visobj_t *),&CompareHeights,&SwitchPointers);
+}
+
+/*
+=====================
+=
+= DrawScaleds
+=
+= Draws all objects that are visible
+=
+=====================
+*/
+
+#define HF_1 (24)
+#define HF_2 (72)
+
+void DrawScaleds (void)
+{
+
+
+    int   i,numvisible;
+    int   gx,gy;
+    unsigned short int  *tilespot;
+    byte   *visspot;
+    boolean result;
+    statobj_t *statptr;
+    objtype   *obj;
+    maskedwallobj_t* tmwall;
+
+    whereami=6;
+
+//
+// place maskwall objects
+//
+    for(tmwall=FIRSTMASKEDWALL; tmwall; tmwall=tmwall->next)
+    {
+        if (spotvis[tmwall->tilex][tmwall->tiley])
+        {
+            mapseen[tmwall->tilex][tmwall->tiley]=1;
+            if (tmwall->vertical)
+            {
+                gx=(tmwall->tilex<<16)+0x8000;
+                gy=(tmwall->tiley<<16);
+                visptr->texturestart=0;
+                visptr->textureend=0;
+                if (viewx<gx)
+                    result=TransformPlane(gx,gy,gx,gy+0xffff,visptr);
+                else
+                    result=TransformPlane(gx,gy+0xffff,gx,gy,visptr);
+                visptr->shapenum=tmwall->bottomtexture;
+                visptr->altshapenum=tmwall->midtexture;
+                visptr->viewx=tmwall->toptexture;
+                visptr->shapesize=2;
+            }
+            else
+            {
+                gx=(tmwall->tilex<<16);
+                gy=(tmwall->tiley<<16)+0x8000;
+                visptr->texturestart=0;
+                visptr->textureend=0;
+                if (viewy<gy)
+                    result=TransformPlane(gx+0xffff,gy,gx,gy,visptr);
+                else
+                    result=TransformPlane(gx,gy,gx+0xffff,gy,visptr);
+                visptr->shapenum=tmwall->bottomtexture;
+                visptr->altshapenum=tmwall->midtexture;
+                visptr->viewx=tmwall->toptexture;
+                visptr->shapesize=2;
+            }
+            if ((tmwall->flags&MW_TOPFLIPPING) &&
+                    (nonbobpheight>64)
+               )
+            {
+                visptr->viewx++;
+            }
+            else if ((tmwall->flags&MW_BOTTOMFLIPPING) &&
+                     (nonbobpheight>maxheight-32)
+                    )
+            {
+                visptr->shapenum++;
+            }
+            if ((visptr < &vislist[MAXVISIBLE-1]) && (result==true)) // don't let it overflo'
+                visptr++;
+        }
+    }
+//
+// place static objects
+//
+    UpdateClientControls();
+    for (statptr = firstactivestat ; statptr; statptr=statptr->nextactive)
+    {   //redraw:
+        if((visptr->shapenum = statptr->shapenum) == NOTHING)
+            continue;
+
+        visptr->shapenum += shapestart;
+        if ((visptr->shapenum <= shapestart) ||
+                (visptr->shapenum >= shapestop))
+            Error("actor shapenum %d out of range (%d-%d)",visptr->shapenum,shapestart,shapestop);
+
+        visspot = statptr->visspot;
+        if (!((*(visspot-0)) ||
+                (*(visspot-1)) ||
+                (*(visspot+1)) ||
+                (*(visspot-129)) ||
+                (*(visspot-128)) ||
+                (*(visspot-127)) ||
+                (*(visspot+129)) ||
+                (*(visspot+128)) ||
+                (*(visspot+127))))
+        {   statptr->flags &= ~FL_VISIBLE;
+            continue;     // not visible
+        }
+
+        result = TransformObject (statptr->x,statptr->y,&(visptr->viewx),&(visptr->viewheight));
+
+        if ((result==false) || (visptr->viewheight< (1<<(HEIGHTFRACTION+2))))
+            continue;                         // to close to the object
+        statptr->flags |= FL_SEEN;
+
+        statptr->flags |= FL_VISIBLE;
+
+        if (statptr->flags & FL_ROTATING)
+            visptr->shapenum += StatRotate(statptr);
+
+        if (statptr->flags&FL_TRANSLUCENT)
+        {
+            visptr->shapesize=1;
+            if (statptr->flags&FL_FADING)
+                visptr->h2=transparentlevel;
+            else
+                visptr->h2=FIXEDTRANSLEVEL;
+            SetSpriteLightLevel(statptr->x,statptr->y,visptr,0,(statptr->flags&FL_FULLLIGHT));
+        }
+        else if (statptr->flags&FL_SOLIDCOLOR)
+        {
+            visptr->shapesize=4;
+            visptr->h2=statptr->hitpoints;
+        }
+        else if (statptr->flags&FL_COLORED)
+        {
+            visptr->shapesize=0;
+#if (DEVELOPMENT == 1)
+            if ((statptr->hitpoints>=0) &&
+                    (statptr->hitpoints<MAXPLAYERCOLORS))
+            {
+#endif
+                SetColorLightLevel(statptr->x,statptr->y,visptr,
+                                   0,statptr->hitpoints,
+                                   (statptr->flags&FL_FULLLIGHT));
+#if (DEVELOPMENT == 1)
+            }
+            else
+            {
+                Error("Illegal color map for sprite type %d\n",statptr->itemnumber);
+            }
+#endif
+        }
+        else
+        {
+            visptr->shapesize=0;
+            SetSpriteLightLevel(statptr->x,statptr->y,visptr,0,(statptr->flags&FL_FULLLIGHT));
+        }
+
+        visptr->h1=pheight-statptr->z;
+
+        if ((statptr->itemnumber != (unsigned int)-1) &&
+                (statptr->flags&FL_HEIGHTFLIPPABLE)
+           )
+        {
+            if (statptr->itemnumber==stat_disk)
+            {
+                int value;
+                value=nonbobpheight-statptr->z-32;
+                if ((value<=HF_2) && (value>HF_1))
+                {
+                    visptr->shapenum++;
+                }
+                else if ((value<=HF_1) && (value>=-HF_1))
+                {
+                    visptr->shapenum+=2;
+                }
+                else if ((value<-HF_1) && (value>=-HF_2))
+                {
+                    visptr->shapenum+=3;
+                }
+                else if (value<-HF_2)
+                {
+                    visptr->shapenum+=4;
+                }
+            }
+            else if ((nonbobpheight-statptr->z)<-16)
+            {
+                visptr->shapenum++;
+            }
+        }
+
+        if (visptr < &vislist[MAXVISIBLE-1]) // don't let it overflo'
+            visptr++;
+
+
+    }
+//
+// place active objects
+//
+    UpdateClientControls();
+    for (obj = firstactive; obj; obj=obj->nextactive)
+    {
+        if (obj==player)
+            continue;
+
+        if ((visptr->shapenum = obj->shapenum) == NOTHING)
+            continue;                         // no shape
+
+        visptr->shapenum += shapestart;
+        if ((visptr->shapenum <= shapestart) ||
+                (visptr->shapenum >= shapestop))
+            Error("actor shapenum %d out of range (%d-%d)",visptr->shapenum,shapestart,shapestop);
+        visspot = &spotvis[obj->tilex][obj->tiley];
+        tilespot = &tilemap[obj->tilex][obj->tiley];
+
+        //
+        // could be in any of the nine surrounding tiles
+        //
+        if (*visspot
+                || ( *(visspot-1))
+                || ( *(visspot+1))
+                || ( *(visspot-129))
+                || ( *(visspot-128))
+                || ( *(visspot-127))
+                || ( *(visspot+129))
+                || ( *(visspot+128))
+                || ( *(visspot+127)) )
+        {
+
+//        result = TransformObject (obj->drawx, obj->drawy,&(visptr->viewx),&(visptr->viewheight));
+            result = TransformObject (obj->x, obj->y,&(visptr->viewx),&(visptr->viewheight));
+            if ((result==false) || (visptr->viewheight< (1<<(HEIGHTFRACTION+2))))
+                continue;                         // to close to the object
+            if (obj->state->rotate)
+                visptr->shapenum += CalcRotate (obj);
+
+            visptr->shapesize=0;
+
+            if (player->flags&FL_SHROOMS)
+            {
+                visptr->shapesize=4;
+                visptr->h2=(GetTicCount()&0xff);
+            }
+            if (obj->obclass==playerobj)
+            {
+                if (obj->flags&FL_GODMODE)
+                {
+                    visptr->shapesize=4;
+                    visptr->h2=240+(GetTicCount()&0x7);
+                }
+                else if (obj->flags & FL_COLORED)
+                {
+                    playertype *pstate;
+
+                    M_LINKSTATE(obj,pstate);
+#if (DEVELOPMENT == 1)
+                    if ((pstate->uniformcolor>=0) &&
+                            (pstate->uniformcolor<MAXPLAYERCOLORS))
+                    {
+#endif
+                        SetColorLightLevel(obj->x,obj->y,visptr,
+                                           obj->dir,pstate->uniformcolor,
+                                           (obj->flags&FL_FULLLIGHT) );
+#if (DEVELOPMENT == 1)
+                    }
+                    else
+                    {
+                        Error("Illegal color map for players\n");
+                    }
+#endif
+                }
+                else
+                    SetSpriteLightLevel(obj->x,obj->y,visptr,obj->dir,(obj->flags&FL_FULLLIGHT));
+
+            }
+            else
+            {
+                if ((obj->obclass >= b_darianobj) && (obj->obclass <= b_robobossobj) &&
+                        MISCVARS->redindex)
+                {
+                    visptr->colormap=redmap+((MISCVARS->redindex-1)<<8);
+                }
+                else
+                {
+                    SetSpriteLightLevel(obj->x,obj->y,visptr,obj->dir,(obj->flags&FL_FULLLIGHT));
+                }
+            }
+
+            visptr->h1= pheight - obj->z;
+
+            if (obj->obclass==diskobj)
+            {
+                int value;
+                value=nonbobpheight-obj->z-32;
+                if ((value<=HF_2) && (value>HF_1))
+                {
+                    visptr->shapenum++;
+                }
+                else if ((value<=HF_1) && (value>=-HF_1))
+                {
+                    visptr->shapenum+=2;
+                }
+                else if ((value<-HF_1) && (value>=-HF_2))
+                {
+                    visptr->shapenum+=3;
+                }
+                else if (value<-HF_2)
+                {
+                    visptr->shapenum+=4;
+                }
+            }
+            else if ( (obj->obclass==pillarobj) &&
+                      ((nonbobpheight-obj->z)<-16)
+                    )
+            {
+                visptr->shapenum++;
+            }
+
+            if (visptr < &vislist[MAXVISIBLE-1]) // don't let it overflo'
+                visptr++;
+            obj->flags |= FL_SEEN;
+            obj->flags |= FL_VISIBLE;
+        }
+        else
+            obj->flags &= ~FL_VISIBLE;
+    }
+//
+// draw from back to front
+//
+    numvisible = visptr-&vislist[0];
+    if (!numvisible)
+        return;                                     // no visible objects
+    SortVisibleList( numvisible, &vislist[0] );
+    UpdateClientControls();
+    for (i = 0; i<numvisible; i++)
+    {
+        //
+        // draw farthest
+        //
+
+        if (sortedvislist[i]->shapesize==4) {
+
+            ScaleSolidShape(sortedvislist[i]);
+
+        } else if (sortedvislist[i]->shapesize==3) {
+
+            InterpolateDoor (sortedvislist[i]);
+
+        } else if (sortedvislist[i]->shapesize==2) {
+
+            InterpolateMaskedWall (sortedvislist[i]);
+
+        } else if (sortedvislist[i]->shapesize==1) {
+
+            ScaleTransparentShape(sortedvislist[i]);
+
+        } else {
+
+            ScaleShape(sortedvislist[i]);
+
+        }
+
+    }
+}
+
+//==========================================================================
+
+
+
+
+
+/*
+==============
+=
+= DrawPlayerWeapon
+=
+= Draw the player's hand'
+=
+==============
+*/
+
+void DrawPlayerWeapon (void)
+{
+    int shapenum,index;
+    int xdisp=0;
+    int ydisp=0;
+    int female,black;
+    int altshape=0;
+
+    whereami=7;
+
+    SoftError("\n attackframe: %d, weaponframe: %d, weapondowntics: %d"
+              " weaponuptics: %d",locplayerstate->attackframe,
+              locplayerstate->weaponframe,locplayerstate->weapondowntics,
+              locplayerstate->weaponuptics);
+
+    if ((locplayerstate->NETCAPTURED == 1) && (!locplayerstate->HASKNIFE))
+        return;
+
+    if (locplayerstate->weapon != -1)
+    {   female = ((locplayerstate->player == 1) || (locplayerstate->player == 3));
+        black = (locplayerstate->player == 2);
+
+        if (((locplayerstate->NETCAPTURED >= 1) || (locplayerstate->NETCAPTURED == -2)) && (locplayerstate->HASKNIFE == 1)) // if raising or lowering
+        {   index = 0;
+            shapenum = gunsstart + weaponshape[index] + locplayerstate->weaponframe;
+        }
+        else if  (locplayerstate->weapon != wp_twopistol)
+        {   if (locplayerstate->weapon==wp_pistol)
+            {   if (female)
+                    index = NUMWEAPGRAPHICS-2;
+                else if (black)
+                    index = NUMWEAPGRAPHICS-1;
+                else
+#if (SHAREWARE == 0)
+                    index = 1;
+#else
+                    index = 0;
+#endif
+            }
+            else
+#if (SHAREWARE == 0)
+
+                index = locplayerstate->weapon + 1;
+#else
+                index = locplayerstate->weapon;
+#endif
+
+            if ((index<0) || (index>=NUMWEAPGRAPHICS))
+                Error ("Weapon shapenum out of range\n");
+            shapenum = gunsstart + weaponshape[index] + locplayerstate->weaponframe;
+
+#if (SHAREWARE == 0)
+            if ((shapenum < W_GetNumForName("KNIFE1")) ||
+                    (shapenum > W_GetNumForName("DOGPAW4"))
+               )
+#else
+            if ((shapenum < W_GetNumForName("MPIST11")) ||
+                    (shapenum > W_GetNumForName("GODHAND8"))
+               )
+#endif
+                Error("\n illegal weapon shapenum %d, index %d, weaponframe %d",
+                      shapenum,index,locplayerstate->weaponframe);
+        }
+
+        else
+        {
+#if (SHAREWARE == 0)
+            if (female)
+            {   altshape = W_FLEFTPISTOL1;
+                shapenum = W_FRIGHTPISTOL1;
+            }
+            else if (black)
+            {   altshape = W_BMLEFTPISTOL1;
+                shapenum = W_BMRIGHTPISTOL1;
+            }
+            else
+#endif
+            {   altshape = W_MLEFTPISTOL1;
+                shapenum = W_MRIGHTPISTOL1;
+            }
+
+            altshape += gunsstart;
+            shapenum += gunsstart;
+            if (locplayerstate->weaponframe > 2)
+                altshape += (locplayerstate->weaponframe - 3);
+            else
+                shapenum += locplayerstate->weaponframe;
+        }
+
+        if (!(locplayerstate->NETCAPTURED) ||
+                (locplayerstate->NETCAPTURED == -1) ||
+                (locplayerstate->HASKNIFE == 0))
+        {   switch (locplayerstate->weapon)
+            {
+
+            case wp_godhand:
+                break;
+
+            case wp_mp40:
+                break;
+
+            case wp_firewall:
+                ydisp = 10;
+                break;
+
+            case wp_bazooka:
+                break;
+
+            case wp_heatseeker:
+                ydisp = 20;
+                break;
+
+            case wp_pistol:
+                break;
+
+            case wp_twopistol:
+                xdisp = 80;
+                break;
+
+            case wp_drunk:
+                ydisp = 10;
+                break;
+
+            case wp_firebomb:
+                break;
+
+
+
+#if (SHAREWARE == 0)
+
+            case wp_kes:
+                break;
+
+            case wp_bat:
+                xdisp = 20;
+                break;
+
+            case wp_split:
+                ydisp = 20;
+                break;
+
+
+            case wp_dog:
+                break;
+
+
+#endif
+
+            default:
+                Error("Illegal weapon value = %d\n",locplayerstate->weapon);
+                break;
+            }
+        }
+        else
+            xdisp = 60;
+
+
+
+
+        if (altshape)
+        {
+            int temp;
+            int delta;
+
+            temp = weaponscale;
+            delta = FixedMul((weaponbobx<<9),weaponscale);
+            weaponscale += delta;
+            ScaleWeapon(xdisp - weaponbobx,ydisp + weaponboby + locplayerstate->weaponheight,shapenum);
+            weaponscale -= delta;
+            ScaleWeapon(weaponbobx - 80,ydisp + weaponboby + locplayerstate->weaponheight,altshape);
+            weaponscale = temp;
+        }
+        else
+        {
+            int temp;
+            int delta;
+
+            temp = weaponscale;
+            delta = FixedMul((weaponbobx<<9),weaponscale);
+            weaponscale -= delta;
+            ScaleWeapon(xdisp + weaponbobx,ydisp + weaponboby + locplayerstate->weaponheight,shapenum);
+            weaponscale = temp;
+        }
+    }
+}
+
+void AdaptDetail ( void )
+{
+#if PROFILE
+    return;
+#else
+
+    whereami=8;
+    if ((preindex<0) || (preindex>2))
+        Error("preindex out of range\n");
+    pretics[preindex]=(pretics[0]+pretics[1]+pretics[2]+(tics<<16)+0x8000)>>2;
+    if (pretics[preindex]>GOLOWER)
+    {
+        pretics[0]=GOHIGHER;
+        pretics[1]=GOHIGHER;
+        pretics[2]=GOHIGHER;
+        doublestep++;
+        if (doublestep>2) doublestep=2;
+    }
+    else if (pretics[preindex]<GOHIGHER)
+    {
+        if (doublestep>0)
+            doublestep--;
+    }
+    preindex++;
+    if (preindex>2)
+        preindex=0;
+#endif
+}
+
+
+
+/*
+=====================
+=
+= CalcTics
+=
+=====================
+*/
+
+void CalcTics (void)
+{
+
+#if PROFILE
+    tics=PROFILETICS;
+    GetTicCount()+=PROFILETICS;
+    oldtime=GetTicCount();
+    return;
+#else
+#if (DEVELOPMENT == 1)
+    int i;
+#endif
+    volatile int tc;
+
+    whereami=9;
+//   SoftError("InCalcTics\n");
+//   SoftError("CT GetTicCount()=%ld\n",GetTicCount());
+//   SoftError("CT oldtime=%ld\n",oldtime);
+
+//
+// calculate tics since last refresh for adaptive timing
+//
+
+    tc=GetTicCount();
+    while (tc==oldtime) {
+        tc=GetTicCount();    /* endwhile */
+    }
+    tics=tc-oldtime;
+
+//   SoftError("CT GetTicCount()=%ld\n",GetTicCount());
+//   if (tics>MAXTICS)
+//      {
+//      tc-=(tics-MAXTICS);
+//      GetTicCount() = tc;
+//     tics = MAXTICS;
+//      }
+
+    if (demoplayback || demorecord)
+    {
+        if (tics>MAXTICS)
+        {
+            tc=oldtime+MAXTICS;
+            tics=MAXTICS;
+            ISR_SetTime(tc);
+        }
+    }
+    oldtime=tc;
+#if (DEVELOPMENT == 1)
+    if (graphicsmode==true)
+    {
+        int drawntics;
+
+        VGAWRITEMAP(1);
+        drawntics=tics;
+        if (drawntics>MAXDRAWNTICS)
+            drawntics=MAXDRAWNTICS;
+        for (i=0; i<drawntics; i++)
+            *((byte *)displayofs+screenofs+(SCREENBWIDE*3)+i)=egacolor[15];
+    }
+    /*
+          if (drawtime>MAXDRAWNTICS)
+             drawtime=MAXDRAWNTICS;
+          for (i=0;i<drawtime;i++)
+             *((byte *)displayofs+screenofs+(SCREENBWIDE*5)+i)=egacolor[2];
+          if (walltime>MAXDRAWNTICS)
+             walltime=MAXDRAWNTICS;
+          for (i=0;i<walltime;i++)
+             *((byte *)displayofs+screenofs+(SCREENBWIDE*7)+i)=egacolor[14];
+          if (actortime>MAXDRAWNTICS)
+             actortime=MAXDRAWNTICS;
+          for (i=0;i<actortime;i++)
+             *((byte *)displayofs+screenofs+(SCREENBWIDE*9)+i)=egacolor[4];
+          }
+    */
+#endif
+#endif
+
+}
+
+/*
+==========================
+=
+= SetSpriteLightLevel
+=
+==========================
+*/
+
+void SetSpriteLightLevel (int x, int y, visobj_t * sprite, int dir, int fullbright)
+{
+    int i;
+    int lv;
+    int intercept;
+
+    whereami=10;
+
+    if (MISCVARS->GASON==1)
+    {
+        sprite->colormap=greenmap+(MISCVARS->gasindex<<8);
+        return;
+    }
+
+    if (fulllight || fullbright)
+    {
+        sprite->colormap=colormap+(1<<12);
+        return;
+    }
+
+    if (fog)
+    {
+        i=((sprite->viewheight*200/iGLOBAL_SCREENHEIGHT)>>normalshade)+minshade;
+        if (i>maxshade) i=maxshade;
+        sprite->colormap=colormap+(i<<8);
+    }
+    else
+    {
+        if (lightsource)
+        {
+            if (dir==east || dir==west)
+                intercept=(x>>11)&0x1c;
+            else
+                intercept=(y>>11)&0x1c;
+
+            lv=(((LightSourceAt(x>>16,y>>16)>>intercept)&0xf)>>1);
+            i=maxshade-(sprite->viewheight>>normalshade)-lv;
+            if (i<minshade) i=minshade;
+            sprite->colormap=colormap+(i<<8);
+        }
+        else
+        {
+            i=maxshade-(sprite->viewheight>>normalshade);
+            if (i<minshade) i=minshade;
+            sprite->colormap=colormap+(i<<8);
+        }
+    }
+}
+
+/*
+==========================
+=
+= SetColorLightLevel
+=
+==========================
+*/
+
+void SetColorLightLevel (int x, int y, visobj_t * sprite, int dir, int color, int fullbright)
+{
+    int i;
+    int lv;
+    int intercept;
+    int height;
+    byte * map;
+
+
+    whereami=11;
+    height=sprite->viewheight<<1;
+    map=playermaps[color];
+    if (MISCVARS->GASON==1)
+    {
+        sprite->colormap=greenmap+(MISCVARS->gasindex<<8);
+        return;
+    }
+
+    if ((fulllight) || (fullbright))
+    {
+        sprite->colormap=map+(1<<12);
+        return;
+    }
+
+    if (fog)
+    {
+        i=((height*200/iGLOBAL_SCREENHEIGHT)>>normalshade)+minshade;
+        if (i>maxshade) i=maxshade;
+        sprite->colormap=map+(i<<8);
+    }
+    else
+    {
+        if (lightsource)
+        {
+            if (dir==east || dir==west)
+                intercept=(x>>11)&0x1c;
+            else
+                intercept=(y>>11)&0x1c;
+
+            lv=(((LightSourceAt(x>>16,y>>16)>>intercept)&0xf)>>1);
+            i=maxshade-(height>>normalshade)-lv;
+            if (i<minshade) i=minshade;
+            sprite->colormap=map+(i<<8);
+        }
+        else
+        {
+            i=maxshade-(height>>normalshade);
+            if (i<minshade) i=minshade;
+            sprite->colormap=map+(i<<8);
+        }
+    }
+}
+
+/*
+==========================
+=
+= SetWallLightLevel
+=
+==========================
+*/
+
+void SetWallLightLevel (wallcast_t * post)
+{
+    int la;
+    int lv;
+    int i;
+
+    whereami=12;
+    if (MISCVARS->GASON==1)
+    {
+        shadingtable=greenmap+(MISCVARS->gasindex<<8);
+        return;
+    }
+
+    switch (post->posttype)
+    {
+    case 0:
+        la=0;
+        break;
+    case 1:
+        la=4;
+        break;
+    case 2:
+        la=(4-gamestate.difficulty);
+        break;
+    case 3:
+        la=3+(4-gamestate.difficulty);
+        break;
+    }
+
+    if (lightsource)
+    {
+        int x,y;
+        int intercept;
+
+        x=post->offset>>7;
+        y=post->offset&0x7f;
+        intercept=(post->texture>>11)&0x1c;
+        lv=(((LightSourceAt(x,y)>>intercept)&0xf)>>1);
+    }
+    else
+        lv=0;
+    if (fulllight)
+    {
+        if (fog)
+        {
+            i =16+minshade-lv+la;
+            if (i>maxshade+la) i=maxshade+la;
+            shadingtable=colormap+(i<<8);
+        }
+        else
+        {
+            i =maxshade-16-lv+la;
+            if (i>=maxshade) i=maxshade;
+            if (i<minshade+la) i=minshade+la;
+            shadingtable=colormap+(i<<8);
+        }
+        return;
+    }
+    if (fog)
+    {
+        i =((post->wallheight*200/iGLOBAL_SCREENHEIGHT)>>normalshade)+minshade-lv+la;
+        if (i>maxshade+la) i=maxshade+la;
+        shadingtable=colormap+(i<<8);
+    }
+    else
+    {
+        i =maxshade-(post->wallheight>>normalshade)-lv+la;
+        if (i>=maxshade) i=maxshade;
+        if (i<minshade+la) i=minshade+la;
+        shadingtable=colormap+(i<<8);
+    }
+}
+
+
+
+/*
+====================
+=
+= DrawWallPost
+=
+====================
+*/
+
+void DrawWallPost ( wallcast_t * post, byte * buf)
+{
+    int ht;
+    int topscreen;
+    int bottomscreen;
+    byte * src;
+    byte * src2;
+
+    whereami=42;
+    if (post->lump)
+        src=W_CacheLumpNum(post->lump,PU_CACHE, CvtNull, 1);
+    if (post->alttile!=0)
+    {
+        if (post->alttile==-1)
+        {
+            ht=maxheight+32;
+            dc_invscale   = post->wallheight<<(10-HEIGHTFRACTION);
+            dc_texturemid = (pheight<<SFRACBITS)+(SFRACUNIT>>1);
+            topscreen     = centeryfrac - FixedMul(dc_texturemid,dc_invscale);
+            bottomscreen  = topscreen + (dc_invscale*ht);
+            dc_yh = ((bottomscreen-1)>>SFRACBITS)+1;
+            if (dc_yh < 0)
+            {
+                post->floorclip=-1;
+                post->ceilingclip=0;
+            }
+            else if (dc_yh >= viewheight)
+            {
+                post->floorclip=viewheight-1;
+                post->ceilingclip=viewheight;
+            }
+            else
+            {
+                post->floorclip=dc_yh-1;
+                post->ceilingclip=dc_yh;
+            }
+            return;
+        }
+        else
+        {
+            ht=nominalheight;
+            src2=W_CacheLumpNum(post->alttile,PU_CACHE, CvtNull, 1);
+        }
+    }
+    else
+    {
+        ht=maxheight+32;
+        src2=src;
+    }
+
+    dc_invscale   = post->wallheight<<(10-HEIGHTFRACTION);
+    dc_texturemid = (pheight<<SFRACBITS)+(SFRACUNIT>>1);
+    topscreen     = centeryfrac - FixedMul(dc_texturemid,dc_invscale);
+    bottomscreen  = topscreen + (dc_invscale*ht);
+    dc_yl = (topscreen+SFRACUNIT-1)>>SFRACBITS;
+    dc_yh = ((bottomscreen-1)>>SFRACBITS)+1;
+
+    if (dc_yl >= viewheight)
+    {
+        post->ceilingclip=viewheight;
+        post->floorclip=viewheight-1;
+        return;
+    }
+    else if (dc_yl < 0)
+        dc_yl = 0;
+
+    dc_iscale     = (64<<(16+HEIGHTFRACTION))/post->wallheight;
+
+    if (dc_yh < 0)
+    {
+        post->floorclip=-1;
+        post->ceilingclip=0;
+        goto bottomcheck;
+    }
+    else if (dc_yh > viewheight)
+        dc_yh = viewheight;
+
+    post->ceilingclip=dc_yl;
+    post->floorclip=dc_yh-1;
+    dc_source=src2+((post->texture>>4)&0xfc0);
+    R_DrawWallColumn (buf);
+
+bottomcheck:
+
+    if (ht!=nominalheight)
+        return;
+
+    dc_texturemid-=(nominalheight<<SFRACBITS);
+    topscreen     = centeryfrac - FixedMul(dc_texturemid,dc_invscale);
+    bottomscreen  = topscreen + (dc_invscale<<6);
+    dc_yl = (topscreen+SFRACUNIT-1)>>SFRACBITS;
+    dc_yh = ((bottomscreen-1)>>SFRACBITS);
+
+    if (dc_yl >= viewheight)
+        return;
+    else if (dc_yl < 0)
+        dc_yl = 0;
+    if (dc_yh < 0)
+        return;
+    else if (dc_yh > viewheight)
+        dc_yh = viewheight;
+    post->floorclip=dc_yh-1;
+    dc_source=src+((post->texture>>4)&0xfc0);
+    R_DrawWallColumn (buf);
+}
+
+/*
+====================
+=
+= DrawWalls
+=
+====================
+*/
+
+void   DrawWalls (void)
+{
+    char * buf;
+    int plane;
+    wallcast_t * post;
+
+    whereami=13;
+
+    plane = 0;
+
+    if (doublestep>1)
+    {
+#ifdef DOS
+        for (plane=0; plane<4; plane+=2)
+#endif
+        {
+            VGAMAPMASK((1<<plane)+(1<<(plane+1)));
+            buf=(byte *)(bufferofs);
+#ifdef DOS
+            for (post=&posts[plane]; post<&posts[viewwidth]; post+=4,buf++)
+#else
+            for (post=&posts[plane]; post<&posts[viewwidth]; post+=2,buf+=2)
+#endif
+            {
+                SetWallLightLevel(post);
+                DrawWallPost(post,buf);
+#ifndef DOS
+                DrawWallPost(post,buf+1);
+#endif
+                (post+1)->ceilingclip=post->ceilingclip;
+                (post+1)->floorclip=post->floorclip;
+            }
+        }
+    }
+    else
+    {
+#ifdef DOS
+        for (plane=0; plane<4; plane++)
+#endif
+        {
+            VGAWRITEMAP(plane);
+            buf=(byte *)(bufferofs);
+#ifdef DOS
+            for (post=&posts[plane]; post<&posts[viewwidth]; post+=4,buf++)
+#else
+            for (post=&posts[plane]; post<&posts[viewwidth]; post++,buf++)
+#endif
+            {
+                SetWallLightLevel(post);
+                DrawWallPost(post,buf);
+            }
+        }
+    }
+}
+
+
+/*
+====================
+=
+= TransformDoors
+=
+====================
+*/
+
+void TransformDoors( void )
+{
+    int i;
+    int numvisible;
+    boolean result;
+    int gx,gy;
+    visobj_t visdoorlist[MAXVISIBLEDOORS],*doorptr;
+
+    whereami=14;
+    doorptr=&visdoorlist[0];
+//
+// place door objects
+//
+
+    for (i = 0; i<doornum; i++)
+    {
+        if (spotvis[doorobjlist[i]->tilex][doorobjlist[i]->tiley])
+        {
+            mapseen[doorobjlist[i]->tilex][doorobjlist[i]->tiley]=1;
+            doorptr->texturestart=0;
+            doorptr->textureend=0;
+            if (doorobjlist[i]->vertical)
+            {
+                gx=(doorobjlist[i]->tilex<<16)+0x8000;
+                gy=(doorobjlist[i]->tiley<<16);
+                if (viewx<gx)
+                    result=TransformPlane(gx,gy,gx,gy+0xffff,doorptr);
+                else
+                    result=TransformPlane(gx,gy+0xffff,gx,gy,doorptr);
+            }
+            else
+            {
+                gx=(doorobjlist[i]->tilex<<16);
+                gy=(doorobjlist[i]->tiley<<16)+0x8000;
+                if (viewy<gy)
+                    result=TransformPlane(gx+0xffff,gy,gx,gy,doorptr);
+                else
+                    result=TransformPlane(gx,gy,gx+0xffff,gy,doorptr);
+            }
+            if (result==true)
+            {
+                doorptr->viewx=0;
+                doorptr->shapenum=doorobjlist[i]->texture;
+                doorptr->altshapenum=doorobjlist[i]->alttexture;
+                if (doorobjlist[i]->texture==doorobjlist[i]->basetexture)
+                {
+                    doorptr->shapesize=(doorobjlist[i]->tilex<<7)+doorobjlist[i]->tiley;
+                    if (doorptr < &visdoorlist[MAXVISIBLEDOORS-1]) // don't let it overflo'
+                        doorptr++;
+                }
+                else
+                {
+                    doorptr->shapesize=3;
+                    memcpy(visptr,doorptr,sizeof(visobj_t));
+                    if (visptr < &vislist[MAXVISIBLE-1])
+                        visptr++;
+                }
+            }
+        }
+    }
+//
+// draw from back to front
+//
+    numvisible = doorptr-&visdoorlist[0];
+    if (!numvisible)
+        return;
+    SortVisibleList( numvisible, &visdoorlist[0] );
+    for (i = 0; i<numvisible; i++)
+    {
+        //
+        // draw farthest
+        //
+        InterpolateWall (sortedvislist[i]);
+    }
+}
+
+
+/*
+====================
+=
+= TransformPushWalls
+=
+====================
+*/
+
+void TransformPushWalls( void )
+{
+    int   i;
+    int   gx,gy;
+    byte   *visspot;
+    visobj_t *savedptr;
+    int numvisible;
+    boolean result;
+
+    whereami=15;
+    savedptr=visptr;
+    //
+    // place pwall objects
+    //
+    for (i = 0; i<pwallnum; i++)
+    {
+        if ((pwallobjlist[i]->action==pw_pushed) || (pwallobjlist[i]->action==pw_npushed))
+            continue;
+        visspot = &spotvis[pwallobjlist[i]->x>>16][pwallobjlist[i]->y>>16];
+        if (*visspot
+                || ( *(visspot-1))
+                || ( *(visspot+1))
+                || ( *(visspot-128))
+                || ( *(visspot+128)))
+        {
+            gx=pwallobjlist[i]->x;
+            gy=pwallobjlist[i]->y;
+            mapseen[gx>>16][gy>>16]=1;
+            if (viewx<gx)
+            {
+                if (viewy<gy)
+                {
+                    visptr->texturestart=(gx-0x8000)&0xffff;
+                    visptr->textureend=visptr->texturestart;
+                    result=TransformPlane(gx+0x7fff,gy-0x8000,gx-0x8000,gy-0x8000,visptr);
+                    visptr->texturestart^=0xffff;
+                    visptr->textureend^=0xffff;
+                    visptr->shapenum=pwallobjlist[i]->texture;
+                    visptr->shapesize=((pwallobjlist[i]->x>>16)<<7)+(pwallobjlist[i]->y>>16);
+                    visptr->viewx+=2;
+                    if ((visptr < &vislist[MAXVISIBLE-1]) && (result==true)) // don't let it overflo'
+                        visptr++;
+                    visptr->texturestart=(gy-0x8000)&0xffff;
+                    visptr->textureend=visptr->texturestart;//-0xffff;
+                    result=TransformPlane(gx-0x8000,gy-0x8000,gx-0x8000,gy+0x7fff,visptr);
+                }
+                else
+                {
+                    visptr->texturestart=(gy-0x8000)&0xffff;
+                    visptr->textureend=visptr->texturestart;//-0xffff;
+                    result=TransformPlane(gx-0x8000,gy-0x8000,gx-0x8000,gy+0x7fff,visptr);
+                    visptr->shapenum=pwallobjlist[i]->texture;
+                    visptr->shapesize=((pwallobjlist[i]->x>>16)<<7)+(pwallobjlist[i]->y>>16);
+                    visptr->viewx+=2;
+                    if ((visptr < &vislist[MAXVISIBLE-1]) && (result==true)) // don't let it overflo'
+                        visptr++;
+                    visptr->texturestart=(gx-0x8000)&0xffff;
+                    visptr->textureend=visptr->texturestart;//-0xffff;
+                    result=TransformPlane(gx-0x8000,gy+0x7fff,gx+0x7fff,gy+0x7fff,visptr);
+                }
+            }
+            else
+            {
+                if (viewy<gy)
+                {
+                    visptr->texturestart=(gy-0x8000)&0xffff;
+                    visptr->textureend=visptr->texturestart;
+                    result=TransformPlane(gx+0x7fff,gy+0x7fff,gx+0x7fff,gy-0x8000,visptr);
+                    visptr->texturestart^=0xffff;
+                    visptr->textureend^=0xffff;
+                    visptr->shapenum=pwallobjlist[i]->texture;
+                    visptr->shapesize=((pwallobjlist[i]->x>>16)<<7)+(pwallobjlist[i]->y>>16);
+                    visptr->viewx+=2;
+                    if ((visptr < &vislist[MAXVISIBLE-1]) && (result==true)) // don't let it overflo'
+                        visptr++;
+                    visptr->texturestart=(gx-0x8000)&0xffff;
+                    visptr->textureend=visptr->texturestart;
+                    result=TransformPlane(gx+0x7fff,gy-0x8000,gx-0x8000,gy-0x8000,visptr);
+                    visptr->texturestart^=0xffff;
+                    visptr->textureend^=0xffff;
+                }
+                else
+                {
+                    visptr->texturestart=(gx-0x8000)&0xffff;
+                    visptr->textureend=visptr->texturestart;//-0xffff;
+                    result=TransformPlane(gx-0x8000,gy+0x7fff,gx+0x7fff,gy+0x7fff,visptr);
+                    visptr->shapenum=pwallobjlist[i]->texture;
+                    visptr->shapesize=((pwallobjlist[i]->x>>16)<<7)+(pwallobjlist[i]->y>>16);
+                    visptr->viewx+=2;
+                    if ((visptr < &vislist[MAXVISIBLE-1]) && (result==true)) // don't let it overflo'
+                        visptr++;
+                    visptr->texturestart=(gy-0x8000)&0xffff;
+                    visptr->textureend=visptr->texturestart;
+                    result=TransformPlane(gx+0x7fff,gy+0x7fff,gx+0x7fff,gy-0x8000,visptr);
+                    visptr->texturestart^=0xffff;
+                    visptr->textureend^=0xffff;
+                }
+            }
+            visptr->viewx+=2;
+            visptr->shapenum=pwallobjlist[i]->texture;
+            visptr->shapesize=((pwallobjlist[i]->x>>16)<<7)+(pwallobjlist[i]->y>>16);
+            if ((visptr < &vislist[MAXVISIBLE-1]) && (result==true)) // don't let it overflo'
+                visptr++;
+        }
+    }
+
+
+//
+// draw from back to front
+//
+    numvisible = visptr-savedptr;
+    if (!numvisible)
+        return;
+    SortVisibleList( numvisible, savedptr );
+    for (i = 0; i<numvisible; i++)
+    {
+        //
+        // draw farthest
+        //
+        if (sortedvislist[i]->shapenum & 0x1000)
+            sortedvislist[i]->shapenum=animwalls[sortedvislist[i]->shapenum&0x3ff].texture;
+        sortedvislist[i]->altshapenum=0;
+        InterpolateWall (sortedvislist[i]);
+    }
+    visptr=savedptr;
+}
+
+/*
+====================
+=
+= WallRefresh
+=
+====================
+*/
+
+void WallRefresh (void)
+{
+    volatile int dtime;
+    int mag;
+    int yzangle;
+
+    whereami=16;
+    firstcoloffset=(firstcoloffset+(tics<<8))&65535;
+
+    dtime=GetFastTics();
+    if (missobj)
+    {
+        viewangle=missobj->angle;
+        viewx=missobj->x-costable[viewangle];
+        viewy=missobj->y+sintable[viewangle];
+        pheight = missobj->z + 32;
+        nonbobpheight=pheight;
+        spotvis[missobj->tilex][missobj->tiley]=1;
+        yzangle=missobj->yzangle;
+    }
+    else
+    {
+        if (player->flags&FL_SHROOMS)
+        {
+            viewangle = (player->angle + FixedMulShift(FINEANGLES,sintable[(GetTicCount()<<5)&(FINEANGLES-1)],(16+4)))&(FINEANGLES-1);
+            ChangeFocalWidth(FixedMulShift(40,sintable[(GetTicCount()<<5)&(FINEANGLES-1)],16));
+        }
+        else
+            viewangle = player->angle;
+        if ((viewangle<0) && (viewangle>=FINEANGLES))
+            Error ("View angle out of range = %d\n",viewangle);
+        viewx = player->x;
+        viewy = player->y;
+        pheight = player->z + locplayerstate->playerheight + locplayerstate->heightoffset;
+        nonbobpheight=pheight;
+        if (
+            (
+                (player->z == nominalheight) ||
+                (IsPlatform(player->tilex,player->tiley)) ||
+                (DiskAt(player->tilex,player->tiley))
+            ) &&
+            (!(player->flags & FL_DOGMODE)) &&
+            (BobbinOn==true) &&
+            (GamePaused==false)
+        )
+        {
+            int mag;
+
+            mag=(player->speed>MAXBOB ? MAXBOB : player->speed);
+
+            pheight+=FixedMulShift(mag,sintable[(GetTicCount()<<7)&2047],28);
+
+            weaponbobx=FixedMulShift(mag,costable[((GetTicCount()<<5))&(FINEANGLES-1)],27);
+            weaponboby=FixedMulShift(mag,sintable[((GetTicCount()<<5))&((FINEANGLES/2)-1)],26);
+        }
+        else
+        {
+            weaponbobx=0;
+            weaponboby=0;
+        }
+        yzangle=player->yzangle;
+        spotvis[player->tilex][player->tiley]=1;
+    }
+
+    if (yzangle > ANG180)
+        pheight -= (sintable[yzangle&2047] >> 14);
+    else
+        pheight += (sintable[yzangle&2047] >> 14);
+
+    viewx -= (FixedMul(sintable[yzangle&2047],costable[viewangle&2047])>>1);
+    viewy += (FixedMul(sintable[yzangle&2047],sintable[viewangle&2047])>>1);
+
+// Set YZ angle
+
+    centery=viewheight>>1;
+
+    if (yzangle>ANG180)
+        centery-=FixedMul(FINEANGLES-yzangle,yzangleconverter);
+    else
+        centery+=FixedMul(yzangle,yzangleconverter);
+
+    centeryfrac=(centery<<16);
+
+    if (pheight < 1)
+        pheight = 1;
+    else if (pheight > maxheight+30)
+        pheight = maxheight+30;
+
+    if (nonbobpheight < 1)
+        nonbobpheight = 1;
+    else if (nonbobpheight > maxheight+30)
+        nonbobpheight = maxheight+30;
+
+    // Set light level of touchplates etc.
+
+    mag=7+((3-gamestate.difficulty)<<2);
+
+    transparentlevel=FixedMul(mag,sintable[(GetTicCount()<<5)&(FINEANGLES-1)])+mag;
+
+    viewsin = sintable[viewangle];
+    viewcos = costable[viewangle];
+    c_startx=(scale*viewcos)-(centerx*viewsin);
+    c_starty=(-scale*viewsin)-(centerx*viewcos);
+    Refresh ();
+    UpdateClientControls();
+    TransformPushWalls();
+    TransformDoors();
+    UpdateClientControls();
+    DrawWalls();
+    UpdateClientControls();
+    walltime=GetFastTics()-dtime;
+
+}
+
+
+/*
+====================
+=
+= GetRainBoundingBox
+=
+====================
+*/
+
+void GetRainBoundingBox (int * xmin, int * xmax, int * ymin, int * ymax)
+{
+    wallcast_t * post;
+    int x,y;
+
+    // zero out all boundaries by default
+
+    *xmax=0;
+    *ymax=0;
+    *xmin=127<<16;
+    *ymin=127<<16;
+
+    // check player's x and y
+
+    if (viewx<(*xmin))
+        (*xmin)=viewx;
+    else if (viewx>(*xmax))
+        (*xmax)=viewx;
+
+    if (viewy<(*ymin))
+        (*ymin)=viewy;
+    else if (viewy>(*ymax))
+        (*ymax)=viewy;
+
+    for (post=&posts[0]; post<&posts[viewwidth]; post+=(viewwidth>>2))
+    {
+        x=(post->offset>>7)<<16;
+        y=(post->offset&0x7f)<<16;
+
+        if (x<(*xmin))
+            (*xmin)=x;
+        else if (x>(*xmax))
+            (*xmax)=x;
+
+        if (y<(*ymin))
+            (*ymin)=y;
+        else if (y>(*ymax))
+            (*ymax)=y;
+    }
+}
+
+/*
+========================
+=
+= InterpolateWall
+=
+========================
+*/
+
+void InterpolateWall (visobj_t * plane)
+{
+    int d1,d2;
+    int top;
+    int topinc;
+    int bot;
+    int botinc;
+    int i;
+    int texture;
+    int dh;
+    int dx;
+    int height;
+    byte * buf;
+
+    whereami=17;
+    dx=(plane->x2-plane->x1+1);
+    if (plane->h1<=0 || plane->h2<=0 || dx==0)
+        return;
+    d1=(1<<(16+HEIGHTFRACTION)) / plane->h1;
+    d2=(1<<(16+HEIGHTFRACTION)) / plane->h2;
+    dh=(((plane->h2-plane->h1)<<DHEIGHTFRACTION)+(1<<(DHEIGHTFRACTION-1)))/dx;
+    top=0;
+    topinc=FixedMulShift(d1,plane->textureend-plane->texturestart,4);
+    bot=d2*dx;
+    botinc=d1-d2;
+    height=plane->h1<<DHEIGHTFRACTION;
+    buf=(byte *)bufferofs;
+    if (plane->x1>=viewwidth)
+        return;
+    for (i=plane->x1; i<=plane->x2; i++)
+    {
+        if ((i>=0 && i<viewwidth)&&(posts[i].wallheight<=(height>>DHEIGHTFRACTION)))
+        {
+            if (bot)
+            {
+                texture=((top/bot)+(plane->texturestart>>4))&0xfc0;
+                posts[i].texture=texture<<4;
+                posts[i].lump=plane->shapenum;
+                posts[i].alttile=plane->altshapenum;
+                posts[i].posttype=plane->viewx;
+                posts[i].offset=plane->shapesize;
+                posts[i].wallheight=height>>DHEIGHTFRACTION;
+            }
+        }
+        top+=topinc;
+        bot+=botinc;
+        height+=dh;
+    }
+}
+
+
+/*
+========================
+=
+= InterpolateDoor
+=
+========================
+*/
+
+void InterpolateDoor (visobj_t * plane)
+{
+    int d1,d2;
+    int top;
+    int topinc;
+    int bot;
+    int botinc;
+    int i;
+    int texture;
+    int dh;
+    int dx;
+    int height;
+    int bottomscreen;
+    byte * shape;
+    byte * shape2;
+    byte * buf;
+    patch_t *p;
+    int pl;
+
+    whereami=18;
+    dx=(plane->x2-plane->x1+1);
+    if (plane->h1<=0 || plane->h2<=0 || dx==0)
+        return;
+    shape=W_CacheLumpNum(plane->shapenum,PU_CACHE, Cvt_patch_t, 1);
+    shape2=W_CacheLumpNum(plane->altshapenum,PU_CACHE, Cvt_patch_t, 1);
+    p=(patch_t *)shape;
+    d1=(1<<(16+HEIGHTFRACTION)) / plane->h1;
+    d2=(1<<(16+HEIGHTFRACTION)) / plane->h2;
+    dh=(((plane->h2-plane->h1)<<DHEIGHTFRACTION)+(1<<(DHEIGHTFRACTION-1)))/dx;
+    topinc=FixedMulShift(d1,plane->textureend-plane->texturestart,4);
+    botinc=d1-d2;
+    if (plane->x1>=viewwidth)
+        return;
+#ifdef DOS
+    for (pl=0; pl<4; pl++)
+#endif
+    {
+#ifdef DOS
+        top=topinc*pl;
+        bot=(d2*dx)+(pl*botinc);
+        height=(plane->h1<<DHEIGHTFRACTION)+(dh*pl);
+        buf=(byte *)bufferofs+((pl+plane->x1)>>2);
+        VGAWRITEMAP((plane->x1+pl)&3);
+
+        for (i=plane->x1+pl; i<=plane->x2; i+=4,buf++)
+#else
+        top=0;
+        bot=(d2*dx);
+        height=(plane->h1<<DHEIGHTFRACTION);
+        buf=(byte *)bufferofs+(plane->x1);
+
+        for (i=plane->x1; i<=plane->x2; i++,buf++)
+#endif
+        {
+            if ((i>=0 && i<viewwidth) && (bot!=0) && (posts[i].wallheight<=(height>>DHEIGHTFRACTION)) )
+            {
+                dc_invscale=height>>(HEIGHTFRACTION+DHEIGHTFRACTION-10);
+                dc_iscale = 0xffffffffu/(unsigned)dc_invscale;
+                dc_texturemid=((pheight-nominalheight+p->topoffset)<<SFRACBITS)+(SFRACUNIT>>1);
+                sprtopoffset=centeryfrac - FixedMul(dc_texturemid,dc_invscale);
+
+                texture=((top/bot)+(plane->texturestart>>4))>>6;
+                SetLightLevel(height>>DHEIGHTFRACTION);
+                ScaleMaskedPost (p->collumnofs[texture]+shape,buf);
+
+                if (levelheight>1)
+                {
+                    sprtopoffset-=(dc_invscale<<6)*(levelheight-1);
+                    bottomscreen =sprtopoffset + (dc_invscale*nominalheight);
+                    dc_yl = (sprtopoffset+SFRACUNIT-1)>>SFRACBITS;
+                    dc_yh = ((bottomscreen-1)>>SFRACBITS)+1;
+                    if (dc_yl >= viewheight)
+                        continue;
+                    else if (dc_yl < 0)
+                        dc_yl = 0;
+                    if (dc_yh > viewheight)
+                        dc_yh = viewheight;
+
+                    dc_source=shape2+((texture<<6)&0xfc0);
+                    R_DrawWallColumn (buf);
+                }
+            }
+
+#ifdef DOS
+            top+=topinc<<2;
+            bot+=botinc<<2;
+            height+=dh<<2;
+#else
+            top+=topinc;
+            bot+=botinc;
+            height+=dh;
+#endif
+        }
+    }
+}
+
+
+/*
+========================
+=
+= InterpolateMaskedWall
+=
+========================
+*/
+
+void InterpolateMaskedWall (visobj_t * plane)
+{
+    int d1,d2;
+    int top;
+    int topinc;
+    int bot;
+    int botinc;
+    int i;
+    int j;
+    int texture;
+    int dh;
+    int dx;
+    int height;
+    byte * shape;
+    byte * shape2;
+    byte * shape3;
+    byte * buf;
+    transpatch_t *p;
+    patch_t *p2;
+    patch_t *p3;
+    int pl;
+    boolean drawbottom,drawmiddle,drawtop;
+    int topoffset;
+
+    whereami=19;
+    dx=(plane->x2-plane->x1+1);
+    if (plane->h1<=0 || plane->h2<=0 || dx==0)
+        return;
+    if (plane->altshapenum>=0)
+    {
+        drawmiddle=true;
+        shape2=W_CacheLumpNum(plane->altshapenum,PU_CACHE, Cvt_patch_t, 1);
+        p2=(patch_t *)shape2;
+        topoffset=p2->topoffset;
+    }
+    else
+    {
+        drawmiddle=false;
+    }
+    if (plane->viewx>=0)
+    {
+        drawtop=true;
+        shape3=W_CacheLumpNum(plane->viewx,PU_CACHE, Cvt_patch_t, 1);
+        p3=(patch_t *)shape3;
+        topoffset=p3->topoffset;
+    }
+    else
+    {
+        drawtop=false;
+    }
+    if (plane->shapenum>=0)
+    {
+        drawbottom=true;
+        shape=W_CacheLumpNum(plane->shapenum,PU_CACHE, Cvt_transpatch_t, 1);
+        p = (transpatch_t *)shape;
+        topoffset=p->topoffset;
+    }
+    else
+    {
+        drawbottom=false;
+    }
+
+    d1=(1<<(16+HEIGHTFRACTION)) / plane->h1;
+    d2=(1<<(16+HEIGHTFRACTION)) / plane->h2;
+    dh=(((plane->h2-plane->h1)<<DHEIGHTFRACTION)+(1<<(DHEIGHTFRACTION-1)))/dx;
+    topinc=FixedMulShift(d1,plane->textureend-plane->texturestart,4);
+    botinc=d1-d2;
+    if (plane->x1>=viewwidth)
+        return;
+#ifdef DOS
+    for (pl=0; pl<4; pl++)
+#endif
+    {
+#ifdef DOS
+        int planenum;
+
+        top=topinc*pl;
+        bot=(d2*dx)+(pl*botinc);
+        height=(plane->h1<<DHEIGHTFRACTION)+(dh*pl);
+        buf=(byte *)bufferofs+((pl+plane->x1)>>2);
+        planenum=((plane->x1+pl)&3);
+        VGAWRITEMAP(planenum);
+        VGAREADMAP(planenum);
+        for (i=plane->x1+pl; i<=plane->x2; i+=4,buf++)
+#else
+        top=0;
+        bot=(d2*dx);
+        height=(plane->h1<<DHEIGHTFRACTION);
+        buf=(byte *)bufferofs+(plane->x1);
+        for (i=plane->x1; i<=plane->x2; i++,buf++)
+#endif
+        {
+            if ((i>=0 && i<viewwidth) && (bot!=0) && (posts[i].wallheight<=(height>>DHEIGHTFRACTION)) )
+            {
+                dc_invscale=height>>(HEIGHTFRACTION+DHEIGHTFRACTION-10);
+                dc_iscale = 0xffffffffu/(unsigned)dc_invscale;
+                dc_texturemid=((pheight-nominalheight+topoffset)<<SFRACBITS)+(SFRACUNIT>>1);
+                sprtopoffset=centeryfrac - FixedMul(dc_texturemid,dc_invscale);
+
+                texture=((top/bot)+(plane->texturestart>>4))>>6;
+                SetLightLevel(height>>DHEIGHTFRACTION);
+                if (drawbottom==true)
+                    ScaleTransparentPost (p->collumnofs[texture]+shape,buf,(p->translevel+8));
+                for (j=0; j<levelheight-2; j++)
+                {
+                    sprtopoffset-=(dc_invscale<<6);
+                    dc_texturemid+=(1<<22);
+                    if (drawmiddle==true)
+                        ScaleMaskedPost (p2->collumnofs[texture]+shape2,buf);
+                }
+                if (levelheight>1)
+                {
+                    sprtopoffset-=(dc_invscale<<6);
+                    dc_texturemid+=(1<<22);
+                    if (drawtop==true)
+                        ScaleMaskedPost (p3->collumnofs[texture]+shape3,buf);
+                }
+            }
+#ifdef DOS
+            top+=topinc<<2;
+            bot+=botinc<<2;
+            height+=dh<<2;
+#else
+            top+=topinc;
+            bot+=botinc;
+            height+=dh;
+#endif
+        }
+    }
+}
+
+/*
+========================
+=
+= DrawPlayerLocation
+=
+========================
+*/
+#define PLX  (320-24)
+#define PLY  16
+void DrawPlayerLocation ( void )
+{
+    int i;
+    char buf[30];
+
+    CurrentFont=tinyfont;
+
+    whereami=20;
+    VGAMAPMASK(15);
+    for (i=0; i<18; i++)
+#ifdef DOS
+        memset((byte *)bufferofs+(ylookup[i+PLY])+(PLX>>2),0,6);
+#else
+        memset((byte *)bufferofs+(ylookup[i+PLY])+PLX,0,6);
+#endif
+    px=PLX;
+    py=PLY;
+    VW_DrawPropString(strupr(itoa(player->x,&buf[0],16)));
+    px=PLX;
+    py=PLY+6;
+    VW_DrawPropString(strupr(itoa(player->y,&buf[0],16)));
+    px=PLX;
+    py=PLY+12;
+    VW_DrawPropString(strupr(itoa(player->angle,&buf[0],16)));
+}
+
+
+
+/*
+========================
+=
+= ThreeDRefresh
+=
+========================
+*/
+
+
+int playerview=0;
+void      ThreeDRefresh (void)
+{
+    objtype * tempptr;
+
+    whereami=21;
+    tempptr=player;
+#if (DEVELOPMENT == 1)
+    if (Keyboard[sc_9])
+    {
+        while (Keyboard[sc_9])
+        {
+            IN_UpdateKeyboard();
+        }
+        playerview++;
+        if (playerview>numplayers)
+            playerview=1;
+    }
+    if (playerview!=0)
+    {
+        player=PLAYER[playerview-1];
+    }
+#endif
+
+//
+// Erase old messages
+//
+
+    RestoreMessageBackground();
+
+    bufferofs += screenofs;
+
+    RefreshClear();
+
+    UpdateClientControls ();
+
+//
+// follow the walls from there to the right, drawwing as we go
+//
+
+    visptr = &vislist[0];
+    WallRefresh ();
+
+    UpdateClientControls ();
+
+    if (fandc)
+        DrawPlanes();
+
+    UpdateClientControls ();
+
+//
+// draw all the scaled images
+//
+    DrawScaleds();                                         // draw scaled stuff
+
+    UpdateClientControls ();
+
+    if (!missobj)
+    {
+        if (locplayerstate->NETCAPTURED && (locplayerstate->NETCAPTURED != -2))
+        {
+            int value;
+
+            if (locplayerstate->NETCAPTURED < 0)
+                value = -locplayerstate->NETCAPTURED;
+            else
+                value = locplayerstate->NETCAPTURED;
+            DrawScreenSizedSprite(netlump+value-1);
+        }
+        DrawPlayerWeapon ();    // draw player's hand'
+
+        if (SCREENEYE)
+            DrawScreenSprite(SCREENEYE->targettilex,SCREENEYE->targettiley,SCREENEYE->state->condition + GIBEYE1 + shapestart);
+        UpdateClientControls ();
+
+        if (player->flags&FL_GASMASK)
+            DrawScreenSizedSprite(gmasklump);
+
+
+        if ( SHOW_PLAYER_STATS() )
+        {
+            DrawStats ();
+        }
+
+        DoBorderShifts ();
+
+        UpdateClientControls ();
+    }
+
+    bufferofs -= screenofs;
+    DrawMessages();
+    bufferofs += screenofs;
+
+    if ( ((GamePaused==true) && (!Keyboard[sc_LShift])) ||
+            (controlupdatestarted==0)
+       )
+        DrawPause ();
+
+//
+// show screen and time last cycle
+//
+    if ((fizzlein==true) && (modemgame==false))
+    {
+        if (newlevel==true)
+            ShutdownClientControls();
+        bufferofs-=screenofs;
+        DrawPlayScreen (true);
+        RotateBuffer(0,FINEANGLES,FINEANGLES*8,FINEANGLES,(VBLCOUNTER*3)/4);
+        bufferofs+=screenofs;
+        fizzlein = false;
+        StartupClientControls();
+    }
+
+    bufferofs -= screenofs;
+
+    UpdateClientControls ();
+
+    if (HUD == true)
+        DrawPlayerLocation();
+
+    FlipPage();
+    gamestate.frame++;
+
+    player=tempptr;
+}
+
+
+//******************************************************************************
+//
+// FlipPage
+//
+//******************************************************************************
+
+void FlipPage ( void )
+{
+#ifdef DOS
+    unsigned displaytemp;
+
+    whereami=22;
+    displayofs = bufferofs;
+
+    displaytemp = displayofs;
+    if ( ( SHAKETICS != 0xFFFF ) && ( !inmenu ) && ( !GamePaused ) &&
+            ( !fizzlein ) )
+    {
+        ScreenShake ();
+    }
+
+
+//   _disable();
+    OUTP(CRTC_INDEX,CRTC_STARTHIGH);
+    OUTP(CRTC_DATA,((displayofs&0x0000ffff)>>8));
+
+
+    if (SHAKETICS != 0xFFFF)
+    {
+        if (SHAKETICS > 0)
+        {
+            OUTP (CRTC_INDEX, CRTC_STARTLOW);
+            OUTP (CRTC_DATA, (displayofs&0x000000FF));
+            displayofs = displaytemp;
+        }
+        else
+        {
+            displayofs = displaytemp;
+            OUTP(CRTC_INDEX,CRTC_STARTHIGH);
+            OUTP(CRTC_DATA,((displayofs&0x0000ffff)>>8));
+            OUTP (CRTC_INDEX, CRTC_STARTLOW);
+            OUTP (CRTC_DATA, (displayofs&0x000000FF));
+            SHAKETICS = 0xFFFF;
+        }
+    }
+//   _enable();
+
+    bufferofs += screensize;
+    if (bufferofs > page3start)
+        bufferofs = page1start;
+#else
+
+    whereami=22;
+
+    if ( ( SHAKETICS != 0xFFFF ) && ( !inmenu ) && ( !GamePaused ) &&
+            ( !fizzlein ) )
+    {
+        ScreenShake ();
+    }
+
+    /* TODO some shake thing */
+
+    /* just call the one in modexlib.c */
+    XFlipPage();
+
+#endif
+}
+
+
+//******************************************************************************
+//
+// TurnShakeOff
+//
+//******************************************************************************
+void TurnShakeOff
+(
+    void
+)
+
+{
+//   _disable();
+    OUTP (CRTC_INDEX, CRTC_STARTHIGH );
+    OUTP (CRTC_DATA, ( ( displayofs & 0x0000ffff ) >> 8 ) );
+    OUTP (CRTC_INDEX, CRTC_STARTLOW);
+    OUTP (CRTC_DATA, (displayofs&0x000000FF));
+//   _enable();
+    SHAKETICS = 0xFFFF;
+}
+
+//******************************************************************************
+//
+// DrawScaledScreen
+// draw sreen after reentering fro restore game
+//******************************************************************************
+
+void DrawScaledScreen(int x, int y, int step, byte * src)
+{
+    int     xfrac;
+    int     yfrac;
+//    int     plane;
+    int     i,j;
+    byte    * p;
+    byte    * buf;
+    int     xsize;
+    int     ysize;
+
+    xsize=(iGLOBAL_SCREENWIDTH<<16)/step;
+    if (xsize>iGLOBAL_SCREENWIDTH) xsize=iGLOBAL_SCREENWIDTH;
+    ysize=(iGLOBAL_SCREENHEIGHT<<16)/step;
+    if (ysize>iGLOBAL_SCREENHEIGHT) ysize=iGLOBAL_SCREENHEIGHT;
+
+#ifdef DOS
+    for (plane=x; plane<x+4; plane++)
+#endif
+    {
+        yfrac=0;
+#ifdef DOS
+        VGAWRITEMAP(plane&3);
+#endif
+        for (j=y; j<y+ysize; j++)
+        {
+            p=src+(iGLOBAL_SCREENWIDTH*(yfrac>>16));
+#ifdef DOS
+            buf=(byte *)bufferofs+ylookup[j]+(plane>>2);
+#else
+            buf=(byte *)bufferofs+ylookup[j]+x;
+#endif
+#ifdef DOS
+            xfrac=(plane-x)*step;
+#else
+            xfrac=0;
+#endif
+            yfrac+=step;
+#ifdef DOS
+            for (i=plane; i<x+xsize; i+=4)
+#else
+            for (i=x; i<x+xsize; i++)
+#endif
+            {
+                *buf=*(p+(xfrac>>16));
+                buf++;
+#ifdef DOS
+                xfrac+=(step<<2);
+#else
+                xfrac+=step;
+#endif
+            }
+        }
+    }
+}
+
+
+//******************************************************************************
+//
+// DoLoadGameSequence
+//
+//******************************************************************************
+
+void DoLoadGameSequence ( void )
+{
+    int x;
+    int y;
+    int dx;
+    int dy;
+    int s;
+    int ds;
+    int time;
+    int i;
+    byte * destscreen;
+    pic_t *shape;//bna++
+
+
+
+
+
+    fizzlein=false;
+    x=(18+SaveGamePicX)<<16;
+    y=(30+SaveGamePicY)<<16;
+    time=VBLCOUNTER;
+    s=0x2000000;
+    dx=(-x)/time;
+    dy=(-y)/time;
+    ds=-((s-0x1000000)/time);
+
+    destscreen=SafeMalloc(64000*8);//bna fixme
+
+    SetupScreen(false);
+    ThreeDRefresh();
+
+    FlipPage();
+    FlipPage();
+
+    VL_CopyPlanarPageToMemory ( (byte *)bufferofs,  destscreen );
+    VL_CopyDisplayToHidden ();
+
+    CalcTics();
+    for (i=0; i<time; i+=tics)
+    {
+        CalcTics();
+        DrawScaledScreen((x>>16),(y>>16),(s>>8),destscreen);
+        FlipPage();
+        x+=(dx*tics);
+        if (x<0) x=0;
+        y+=(dy*tics);
+        if (y<0) y=0;
+        s+=(ds*tics);
+    }
+
+    DrawScaledScreen(0,0,0x10000,destscreen);
+    FlipPage();
+    VL_CopyDisplayToHidden ();
+    SafeFree(destscreen);
+    CalcTics();
+    CalcTics();
+    //bna++ section
+    shape =  ( pic_t * )W_CacheLumpName( "backtile", PU_CACHE, Cvt_pic_t, 1 );
+    DrawTiledRegion( 0, 16, iGLOBAL_SCREENWIDTH, iGLOBAL_SCREENHEIGHT - 32, 0, 16, shape );//bna++
+    DrawPlayScreen(false);
+    DisableScreenStretch();
+    SHAKETICS = 0xFFFF;
+    //bna section end
+}
+
+//******************************************************************************
+//
+// StartupRotateBuffer
+//
+//******************************************************************************
+byte * RotatedImage;
+boolean RotateBufferStarted = false;
+void StartupRotateBuffer ( int masked)
+{
+    int k;////zxcv
+    int a,b;
+
+//   int Xres = 320;//org
+//   int Yres = 200;//org
+    int   Xres =   iGLOBAL_SCREENWIDTH;//bna val 800
+    int   Yres = iGLOBAL_SCREENHEIGHT;//bna val 600
+
+
+    iG_masked = masked;
+
+    if (RotateBufferStarted == true)
+        return;
+
+    RotateBufferStarted = true;
+
+    //   RotatedImage=SafeMalloc(131072);org
+    //RotatedImage=SafeMalloc(131072*8);
+    if (iGLOBAL_SCREENWIDTH == 320) {
+        RotatedImage=SafeMalloc(131072);
+    } else if (iGLOBAL_SCREENWIDTH == 640) {
+        RotatedImage=SafeMalloc(131072*4);
+    } else if (iGLOBAL_SCREENWIDTH == 800) {
+        RotatedImage=SafeMalloc(131072*8);
+    }
+//SetupScreen(false);//used these 2 to test screen size
+//VW_UpdateScreen ();
+    if (masked==0) {
+        if (iGLOBAL_SCREENWIDTH == 320) {
+            memset(RotatedImage,0,131072);
+        } else if (iGLOBAL_SCREENWIDTH == 640) {
+            memset(RotatedImage,0,131072*4);
+        } else if (iGLOBAL_SCREENWIDTH == 800) {
+            //memset(RotatedImage,0,131072);//org
+            memset(RotatedImage,0,131072*8);
+        }
+    } else {
+        if (iGLOBAL_SCREENWIDTH == 320) {
+            memset(RotatedImage,0xff,131072);
+        } else if (iGLOBAL_SCREENWIDTH == 640) {
+            memset(RotatedImage,0xff,131072*4);
+        } else if (iGLOBAL_SCREENWIDTH == 800) {
+            memset(RotatedImage,0xff,131072*8);
+        }
+    }
+    //memset(RotatedImage,0xff,131072);//org
+    //memset(RotatedImage,0xff,131072*8);
+
+    if ((masked == false)&&(iGLOBAL_SCREENWIDTH == 800)) {
+        DisableScreenStretch();
+        // SetTextMode (  );
+
+        k=(28*512);//14336;
+        //k=((0+28)<<10);//28672
+        for (a=0; a<iGLOBAL_SCREENHEIGHT; a++) {
+            for (b=0; b<iGLOBAL_SCREENWIDTH; b++) {
+                //*(RotatedImage+99+((a+28)<<9)+b)   =   *((byte *)bufferofs+(a*linewidth)+b);
+                // 99 is some offset value
+                k = ((a+28)<<10);
+                *(RotatedImage+(k)+b)   =   *((byte *)bufferofs+(a*linewidth)+b);
+                //*(RotatedImage+b)   =   *((byte *)bufferofs+(a*linewidth)+b);
+            }
+            //k+=512*2;
+        }
+    } else if ((masked == false)&&(iGLOBAL_SCREENWIDTH == 640)) {
+        DisableScreenStretch();
+        k=(28*512);//14336;
+        for (a=0; a<iGLOBAL_SCREENHEIGHT; a++) {
+            for (b=0; b<iGLOBAL_SCREENWIDTH; b++) {
+                k = ((a+28)<<10);
+                *(RotatedImage+(k)+b)   =   *((byte *)bufferofs+(a*linewidth)+b);
+            }
+        }
+
+    } else if ((masked == true)||(iGLOBAL_SCREENWIDTH == 320)) {
+        for (a=0; a<200; a++) {
+            for (b=0; b<320; b++)
+                *(RotatedImage+99+((a+28)<<9)+b)=*((byte *)bufferofs+(a*linewidth)+b);
+        }
+    }
+
+}
+/* copier liner af 1024 bredde
+a=0=14436 a=1=14848 a=2=15360 a=3=15872  -> 512 i difference
+*(RotatedImage+(512)+0) = bufferofs+(0*800)+0);
+*(RotatedImage+(512)+100) = bufferofs+(100*800)+0);
+*/
+
+//******************************************************************************
+//
+// ShutdownRotateBuffer
+//
+//******************************************************************************
+
+void ShutdownRotateBuffer ( void )
+{
+    if (RotateBufferStarted == false)
+        return;
+
+    RotateBufferStarted = false;
+    SafeFree(RotatedImage);
+}
+
+//******************************************************************************
+//
+// ScaleAndRotateBuffer
+//
+//******************************************************************************
+
+void ScaleAndRotateBuffer (int startangle, int endangle, int startscale, int endscale, int time)
+{
+    int anglestep;
+    int scalestep;
+    int angle;
+    int scale;
+    int i;
+
+
+//bna section
+//   int Xh = 160;//org
+//   int Yh = 100;//org
+
+    int Xh = iGLOBAL_SCREENWIDTH/2;
+    int Yh = iGLOBAL_SCREENHEIGHT/2;
+//  Xh = 259;
+//  Yh = 109;
+
+    time = time;
+////zxcv
+    DisableScreenStretch();//bna++
+
+
+    anglestep=((endangle-startangle)<<16)/time;
+    scalestep=((endscale-startscale)<<6)/time;
+
+    angle=(startangle<<16);
+
+    scale=(startscale<<6);
+
+    CalcTics();
+    CalcTics();
+    for (i=0; i<time; i+=tics)
+    {   //zxcv
+        DrawRotatedScreen(Xh,Yh, (byte *)bufferofs,(angle>>16)&(FINEANGLES-1),scale>>6,0);
+        FlipPage();
+        scale+=(scalestep*tics);
+        angle+=(anglestep*tics);
+        CalcTics();
+    }
+
+    DrawRotatedScreen(Xh,Yh, (byte *)bufferofs,endangle&(FINEANGLES-1),endscale,0);
+    FlipPage();
+    DrawRotatedScreen(Xh,Yh, (byte *)bufferofs,endangle&(FINEANGLES-1),endscale,0);
+    FlipPage();
+    DrawRotatedScreen(Xh,Yh, (byte *)bufferofs,endangle&(FINEANGLES-1),endscale,0);
+    CalcTics();
+    CalcTics();
+    //I_Delay (240);//bna++
+    //bna++ section
+    if ( playstate == ex_stillplaying )	  {//bna++
+        pic_t *shape;
+        shape =  ( pic_t * )W_CacheLumpName( "backtile", PU_CACHE, Cvt_pic_t, 1 );
+        DrawTiledRegion( 0, 16, iGLOBAL_SCREENWIDTH, iGLOBAL_SCREENHEIGHT - 32, 0, 16, shape );//bna++
+        DisableScreenStretch();//dont strech when we go BACK TO GAME
+        DrawPlayScreen(true);//repaint ammo and life stat
+    }
+}
+//bna section end
+
+
+
+//******************************************************************************
+//
+// RotateBuffer
+//
+//******************************************************************************
+
+void RotateBuffer (int startangle, int endangle, int startscale, int endscale, int time)
+{
+    int savetics;
+
+    //save off fastcounter
+
+    savetics=GetFastTics();
+
+    StartupRotateBuffer (0);
+
+    ScaleAndRotateBuffer (startangle, endangle, startscale, endscale, time);
+
+    ShutdownRotateBuffer ();
+
+    // restore fast counter
+    SetFastTics(savetics);
+}
+
+
+//******************************************************************************
+//
+// DrawRotatedScreen
+//
+//******************************************************************************
+
+void DrawRotatedScreen(int cx, int cy, byte *destscreen, int angle, int scale, int masked)
+{   //ZXCV
+    int     c, s;
+    int     xst, xct;
+    int     y;
+
+    byte    * screen;
+    //int Xres = 320;//old value
+    //int Yres = 200;//old val
+
+    int Xr = iGLOBAL_SCREENWIDTH;//640;
+    int Yr = (iGLOBAL_SCREENHEIGHT);//400; //bna aaaa fix
+
+//	   SetTextMode (  );
+    c = FixedMulShift(scale,costable[angle],11);
+    s = FixedMulShift(scale,sintable[angle],11);
+
+//   c = c/2; //these values are to rotate degres or?
+//   s = s/2;
+//   xst & xct= start center values ;
+    if ((iGLOBAL_SCREENWIDTH == 320 )||(masked == true)) {
+        xst = (((-cx)*s)+(128<<16))-(cy*c);
+        xct = (((-cx)*c)+(256<<16)+(1<<18)-(1<<16))+(cy*s);
+    }
+    else if ((iGLOBAL_SCREENWIDTH == 640 )&&(masked == false)) {
+        xst = (((-cx)*s)+((268)<<16))-(cy*c);
+        xct = (((-cx)*c)+((317)<<16)+(1<<18)-(1<<16))+(cy*s);
+    }//y=268;x=317
+    else if ((iGLOBAL_SCREENWIDTH == 800 )&&(masked == false)) {
+        xst = (((-cx)*s)+((328)<<16))-(cy*c);
+        xct = (((-cx)*c)+((397)<<16)+(1<<18)-(1<<16))+(cy*s);
+    }//328 397
+
+    mr_xstep=s;
+    mr_ystep=c;
+
+
+    if ((iGLOBAL_SCREENWIDTH == 800)&&(masked==0)) {
+        screen=destscreen+iGLOBAL_SCREENWIDTH;//bna aaaa fix
+    } else {
+        screen=destscreen;
+    }
+
+    if (masked==0)
+    {
+        // paint hole 800x600 screen
+        {
+            mr_yfrac=xct;
+            mr_xfrac=xst;
+            VGAWRITEMAP(plane);
+            for (y=0; y<Yr; y++,mr_xfrac+=c,mr_yfrac-=s)
+                DrawRotRow(Xr,screen+ylookup[y],RotatedImage);
+        }
+    }
+    else
+    {
+        {
+            mr_yfrac=xct;
+            mr_xfrac=xst;
+            VGAWRITEMAP(plane);
+            for (y=0; y<Yr; y++,mr_xfrac+=c,mr_yfrac-=s)
+                DrawMaskedRotRow(Xr,screen+ylookup[y],RotatedImage);
+        }
+    }
+
+}
+
+
+//******************************************************************************
+//
+// DrawScaledPost
+//
+//******************************************************************************
+
+void DrawScaledPost ( int height, byte * src, int offset, int x)
+{
+    patch_t *p;
+
+    p=(patch_t *)src;
+    dc_invscale=(height<<16)/p->origsize;
+    dc_iscale=(p->origsize<<16)/height;
+    dc_texturemid=(((p->origsize>>1)+p->topoffset)<<SFRACBITS)+(SFRACUNIT>>1);
+    sprtopoffset=centeryfrac - FixedMul(dc_texturemid,dc_invscale);
+    shadingtable=colormap+(1<<12);
+    VGAWRITEMAP(x&3);
+#ifdef DOS
+    ScaleMaskedPost(((p->collumnofs[offset])+src), (byte *)bufferofs+(x>>2));
+#else
+    ScaleMaskedPost(((p->collumnofs[offset])+src), (byte *)bufferofs+x);
+#endif
+}
+
+
+
+void ApogeeTitle (void)
+{
+    byte pal[768];
+    int   angle;
+    int   scale;
+    int   x,y;
+    int   danglex;
+    int   anglex;
+    int   dy,dangle,dscale;
+    int   time;
+
+    CalcTics();
+    CalcTics();
+    IN_ClearKeysDown();
+    viewwidth=320;
+    viewheight=200;
+    memcpy(&pal[0],W_CacheLumpName("ap_pal",PU_CACHE, CvtNull, 1),768);
+    shadingtable=colormap+(1<<12);
+    VL_NormalizePalette(&pal[0]);
+    SwitchPalette(&pal[0],35);
+//   DrawWorld();
+//   RotateBuffer(0,FINEANGLES*6,FINEANGLES*48,FINEANGLES,(VBLCOUNTER*2));
+//   DoLaserShoot("apogee");
+//   DoZIntro();
+
+    VL_ClearBuffer (bufferofs, 255);
+    DrawNormalSprite (0, 0, W_GetNumForName("ap_titl"));
+
+    StartupRotateBuffer (1);
+
+    //save off fastcounter
+
+#define APOGEEXANGLE 913
+#define APOGEEXMAG   180
+#define APOGEESTARTY 0
+#define APOGEEENDY   100
+
+#define APOGEESCALESTART (FINEANGLES<<4)
+#define APOGEESCALEEND (FINEANGLES)
+#define APOGEESONGTIME (124-1)
+
+    time = APOGEESONGTIME;
+
+    anglex=0;
+    danglex=(APOGEEXANGLE<<16)/time;
+
+    y=APOGEESTARTY<<16;
+    dy=((APOGEEENDY-APOGEESTARTY)<<16)/time;
+
+    dscale=((APOGEESCALEEND-APOGEESCALESTART)<<16)/time;
+    scale=APOGEESCALESTART<<16;
+
+    angle=0;
+    dangle=(FINEANGLES<<17)/time;
+
+    MU_StartSong(song_apogee);
+
+    CalcTics();
+
+    while (time>=0)
+    {
+        VL_DrawPostPic (W_GetNumForName("ap_wrld"));
+        IN_PumpEvents();
+
+        x=100+FixedMul(APOGEEXMAG,sintable[anglex>>16]);
+
+        DrawRotatedScreen(x,y>>16,(byte *)bufferofs,(angle>>16)&(FINEANGLES-1),scale>>16,1);
+        FlipPage();
+        CalcTics();
+        angle+=dangle*tics;
+        scale+=dscale*tics;
+        y+=dy*tics;
+        anglex+=danglex*tics;
+        time-=tics;
+        if ((LastScan) || IN_GetMouseButtons())
+            goto apogeeexit;
+    }
+    CalcTics();
+    CalcTics();
+    VL_DrawPostPic (W_GetNumForName("ap_wrld"));
+    DrawRotatedScreen(x,y>>16,(byte *)bufferofs,0,APOGEESCALEEND,1);
+    FlipPage();
+
+    while (MU_SongPlaying())
+    {
+        IN_PumpEvents();
+        if ((LastScan) || IN_GetMouseButtons())
+            goto apogeeexit;
+    }
+
+//  I_Delay(65); //bna added
+apogeeexit:
+
+    VL_ClearBuffer (bufferofs, 0); //bna added
+    MenuFadeOut(); //bna added
+    VH_UpdateScreen (); //bna added
+    ShutdownRotateBuffer ();
+
+}
+
+#if (SHAREWARE==0)
+
+void DopefishTitle (void)
+{
+    int shapenum;
+    int height;
+
+    shapenum=W_GetNumForName("scthead1");
+    CalcTics();
+    CalcTics();
+    IN_ClearKeysDown();
+    MU_StartSong( song_secretmenu);
+    viewwidth=320;
+    viewheight=200;
+    SwitchPalette(origpal,35);
+    oldtime=GetTicCount();
+    FlipPage();
+    for (height=1; height<200; height+=(tics<<2))
+    {
+        DrawPositionedScaledSprite (160, 100, shapenum, height, 0);
+        FlipPage();
+        CalcTics();
+        if ((LastScan) || IN_GetMouseButtons())
+            break;
+    }
+    SD_Play ( SD_DOPEFISHSND );
+    oldtime=GetTicCount();
+    for (height=0; height<FINEANGLES<<1; height+=(tics<<5))
+    {
+        DrawPositionedScaledSprite (160+FixedMul(60,costable[height&(FINEANGLES-1)]), 100+FixedMul(60,sintable[height&(FINEANGLES-1)]), shapenum, 200, 0);
+        FlipPage();
+        VL_CopyPlanarPage ( (byte *) displayofs, (byte *) bufferofs );
+        CalcTics();
+        if ((LastScan) || IN_GetMouseButtons())
+            break;
+    }
+    SD_Play ( SD_DOPEFISHSND );
+    FlipPage();
+}
+
+#endif
+
+//******************************************************************************
+//
+// RotationFun
+//
+//******************************************************************************
+
+void RotationFun ( void )
+{
+    int   angle;
+    int   scale;
+    int   x,y;
+    word  buttons;
+
+    //save off fastcounter
+
+
+    angle=0;
+    scale=FINEANGLES;
+
+    StartupRotateBuffer (0);
+
+    CalcTics();
+    CalcTics();
+    while (!Keyboard[sc_Escape])
+    {
+        IN_UpdateKeyboard ();
+        DrawRotatedScreen(160,100,(byte *)bufferofs,angle,scale,0);
+        FlipPage();
+        CalcTics();
+        INL_GetMouseDelta(&x, &y);
+        buttons=IN_GetMouseButtons ();
+        angle=(angle-x)&(FINEANGLES-1);
+        if (buttons & (1 << 0))
+        {
+            if (scale>0)
+                scale-=30;
+        }
+        else if (buttons & (1 << 1))
+        {
+            scale+=30;
+        }
+    }
+    CalcTics();
+    CalcTics();
+    Keyboard[sc_Escape]=0;
+
+    ShutdownRotateBuffer ();
+}
+
+boolean ScreenSaverStarted=false;
+screensaver_t * ScreenSaver;
+#define PAUSETIME  (70)
+
+//******************************************************************************
+//
+// SetupScreenSaverPhase
+//
+//******************************************************************************
+void SetupScreenSaverPhase ( void )
+{
+    if (ScreenSaverStarted==false)
+        return;
+
+    if (ScreenSaver->phase==0)
+    {
+        ScreenSaver->x=160;
+        ScreenSaver->y=100;
+        ScreenSaver->angle=0;
+        ScreenSaver->scale=FINEANGLES;
+        ScreenSaver->dangle=FINEANGLES/VBLCOUNTER;
+        ScreenSaver->dx=0;
+        ScreenSaver->dy=0;
+        ScreenSaver->dscale=((FINEANGLES<<2)-(FINEANGLES))/VBLCOUNTER;
+        ScreenSaver->time=VBLCOUNTER;
+    }
+    else if (ScreenSaver->phase==1)
+    {
+        ScreenSaver->x=160;
+        ScreenSaver->y=100;
+        ScreenSaver->angle=0;
+        ScreenSaver->scale=FINEANGLES<<2;
+        ScreenSaver->dangle=FINEANGLES/VBLCOUNTER;
+        ScreenSaver->dx=RandomNumber("StartupScreen",0)>>5;
+        ScreenSaver->dy=RandomNumber("StartupScreen",0)>>5;
+        ScreenSaver->dscale=0;
+        ScreenSaver->time=-1;
+    }
+}
+
+//******************************************************************************
+//
+// StartupScreenSaver
+//
+//******************************************************************************
+void StartupScreenSaver ( void )
+{
+    if (ScreenSaverStarted==true)
+        return;
+
+    ScreenSaverStarted=true;
+
+    StartupRotateBuffer (0);
+
+    ScreenSaver=(screensaver_t *)SafeMalloc(sizeof(screensaver_t));
+    ScreenSaver->phase=0;
+    ScreenSaver->pausetime=PAUSETIME;
+    if (iGLOBAL_SCREENWIDTH == 320) {
+        ScreenSaver->pausex=120;
+        ScreenSaver->pausey=84;
+    } else if (iGLOBAL_SCREENWIDTH == 640) {
+        ScreenSaver->pausex=240;
+        ScreenSaver->pausey=201;
+    } else if (iGLOBAL_SCREENWIDTH == 800) {
+        ScreenSaver->pausex=300;
+        ScreenSaver->pausey=252;
+    }
+    ScreenSaver->pausex=120;
+    ScreenSaver->pausey=84;
+    SetupScreenSaverPhase();
+}
+
+//******************************************************************************
+//
+// ShutdownScreenSaver
+//
+//******************************************************************************
+void ShutdownScreenSaver ( void )
+{
+    if (ScreenSaverStarted==false)
+        return;
+
+    ScreenSaverStarted=false;
+
+    ShutdownRotateBuffer ();
+    SafeFree(ScreenSaver);
+    //bna section
+    StartupClientControls();
+
+}
+
+//******************************************************************************
+//
+// UpdateScreenSaver
+//
+//******************************************************************************
+
+#define SPINSIZE  40
+#define MAXSPEED  8
+void UpdateScreenSaver ( void )
+{
+    //EnableScreenStretch();
+    if (ScreenSaver->time!=-1)
+    {
+        ScreenSaver->time-=tics;
+        if (ScreenSaver->time<0)
+        {
+            ScreenSaver->phase++;
+            SetupScreenSaverPhase();
+        }
+    }
+    ScreenSaver->x+=ScreenSaver->dx*tics;
+    ScreenSaver->y+=ScreenSaver->dy*tics;
+    ScreenSaver->angle=(ScreenSaver->angle+(ScreenSaver->dangle*tics))&(FINEANGLES-1);
+    ScreenSaver->scale+=ScreenSaver->dscale*tics;
+    if (ScreenSaver->x<SPINSIZE)
+    {
+        ScreenSaver->x=SPINSIZE;
+        ScreenSaver->dx=abs(ScreenSaver->dx);
+        ScreenSaver->dy+=(RandomNumber("Rotate",0)>>6)-2;
+    }
+    else if (ScreenSaver->x>iGLOBAL_SCREENWIDTH-SPINSIZE)
+    {
+        ScreenSaver->x=iGLOBAL_SCREENWIDTH-SPINSIZE;
+        ScreenSaver->dx=-(abs(ScreenSaver->dx));
+        ScreenSaver->dy+=(RandomNumber("Rotate",0)>>6)-2;
+    }
+    if (ScreenSaver->y<SPINSIZE)
+    {
+        ScreenSaver->y=SPINSIZE;
+        ScreenSaver->dy=abs(ScreenSaver->dy);
+        ScreenSaver->dx+=(RandomNumber("Rotate",0)>>6)-2;
+    }
+    else if (ScreenSaver->y>iGLOBAL_SCREENHEIGHT-SPINSIZE)
+    {
+        ScreenSaver->y=iGLOBAL_SCREENHEIGHT-SPINSIZE;
+        ScreenSaver->dy=-(abs(ScreenSaver->dy));
+        ScreenSaver->dx+=(RandomNumber("Rotate",0)>>6)-2;
+    }
+
+    if (abs(ScreenSaver->dx)>MAXSPEED)
+        ScreenSaver->dx=SGN(ScreenSaver->dx)*MAXSPEED;
+
+    if (abs(ScreenSaver->dy)>MAXSPEED)
+        ScreenSaver->dy=SGN(ScreenSaver->dy)*MAXSPEED;
+
+    DrawRotatedScreen(ScreenSaver->x,ScreenSaver->y, (byte *)bufferofs,ScreenSaver->angle,ScreenSaver->scale,0);
+
+    ScreenSaver->pausetime-=tics;
+    if (ScreenSaver->pausetime<=0)
+    {
+        ScreenSaver->pausetime=PAUSETIME;
+        if (iGLOBAL_SCREENWIDTH == 320) {
+            ScreenSaver->pausex=RandomNumber ("pausex",0)%240;
+            ScreenSaver->pausey=RandomNumber ("pausey",0)%168;
+        } else if (iGLOBAL_SCREENWIDTH == 640) {
+            ScreenSaver->pausex=RandomNumber ("pausex",0)%480;
+            ScreenSaver->pausey=RandomNumber ("pausey",0)%403;
+        } else if (iGLOBAL_SCREENWIDTH == 800) {
+            ScreenSaver->pausex=RandomNumber ("pausex",0)%600;
+            ScreenSaver->pausey=RandomNumber ("pausey",0)%504;
+        }
+    }
+    DrawPauseXY (ScreenSaver->pausex, ScreenSaver->pausey);
+
+    FlipPage();
+}
+#if 0
+
+//******************************************************************************
+//
+// DoLaserShoot
+//
+//******************************************************************************
+void DoLaserShoot (char * name)
+{
+
+    int sourcex;
+    int lastx;
+    int sourceheight;
+    int destheight;
+    int sourcestep;
+    int xstep;
+    int hstep;
+    int midx;
+    int startx;
+    int dx;
+    int f;
+    int s;
+    int height;
+    int x;
+    int sx;
+    int size;
+    patch_t *p;
+    byte * shape;
+
+    DrawWorld();
+    midx=160;
+    shape=W_CacheLumpName(name,PU_CACHE);
+    p=(patch_t *)shape;
+    size=p->origsize;
+
+    startx=midx-(size>>1)-(p->leftoffset);
+
+    sourcex=0;
+    lastx=startx+p->width;
+    sourcestep=(320*65536)/p->width;
+    sourceheight=p->origsize<<3;
+    destheight=p->origsize;
+    CalcTics();
+    CalcTics();
+
+
+    for (x=startx; x<lastx; x+=tics,sourcex+=(sourcestep*tics))
+    {
+        for (f=startx; f<=x; f++)
+            DrawScaledPost(destheight,shape,f-startx,f);
+        height=sourceheight<<16;
+        if (x<=midx)
+        {
+            dx=x-(sourcex>>16);
+            xstep=1;
+        }
+        else
+        {
+            dx=(sourcex>>16)-x;
+            xstep=-1;
+        }
+        sx=sourcex>>16;
+        if (dx)
+            hstep=((-destheight+sourceheight)<<16)/dx;
+        else
+            hstep=0;
+        for (s=0; s<dx; s++,height-=hstep,sx+=xstep)
+            DrawScaledPost(height>>16,shape,x-startx,sx);
+        FlipPage();
+        CalcTics();
+        DrawWorld();
+        break;
+    }
+
+    // Write out one more time so that the rest of the screen is clear
+
+    for (f=startx; f<lastx; f++)
+        DrawScaledPost(destheight,shape,f-startx,f);
+    FlipPage();
+}
+
+//******************************************************************************
+//
+// DoIntro
+//
+//******************************************************************************
+
+#define MAXMAG (80)
+#define OSCTIME (5*VBLCOUNTER)
+#define OSCXSHIFT (4)
+#define OSCTSHIFT (4)
+
+void DoIntro (void)
+{
+    byte * shape;
+    byte * origshape;
+    int mag;
+    int currentmag;
+    int magstep;
+    int time;
+    int x;
+    int t;
+
+    shadingtable=colormap+(1<<12);
+
+    origshape=W_CacheLumpName("ap_wrld",PU_CACHE);
+
+    mag=MAXMAG<<16;
+    magstep = (MAXMAG<<16)/OSCTIME;
+    time = OSCTIME;
+    t=0;
+
+    CalcTics();
+
+    while (time>0)
+    {
+        int yoffset;
+        int ylow;
+        int yhigh;
+        int offset;
+        int postheight;
+        byte * src;
+
+        shape=origshape;
+        VL_ClearBuffer (bufferofs, 0);
+        currentmag=mag>>16;
+        for (x=0; x<320; x++,shape+=200)
+        {
+            VGAWRITEMAP(x&3);
+            src=shape;
+            offset=(t+(x<<OSCXSHIFT))&(FINEANGLES-1);
+            yoffset=FixedMul(currentmag,sintable[offset]);
+            ylow=yoffset;
+            if (ylow<0)
+            {
+                src-=ylow;
+                ylow=0;
+            }
+            if (ylow>199)
+                ylow=199;
+            yhigh=yoffset+200;
+            if (yhigh>199)
+            {
+                yhigh=199;
+            }
+            if (yhigh<0)
+                yhigh=0;
+            postheight=yhigh-ylow+1;
+            if (postheight>0)
+#ifdef DOS
+                DrawSkyPost((byte *)bufferofs + (x>>2) + ylookup[ylow],src,postheight);
+#else
+                DrawSkyPost((byte *)bufferofs + x + ylookup[ylow],src,postheight);
+#endif
+        }
+        FlipPage();
+        CalcTics();
+        mag  -= (magstep * tics);
+        time -= tics;
+        t    += (tics<<OSCTSHIFT);
+        if (mag<0) mag = 0;
+    }
+}
+
+
+//******************************************************************************
+//
+// DoZIntro
+//
+//******************************************************************************
+
+#define ZMAXMAG (199)
+#define ZOSCTIME (3*VBLCOUNTER)
+#define ZOSCXSHIFT (2)
+#define ZOSCXSTEP ( (FINEANGLES<<(ZOSCXSHIFT+16))/320 )
+#define ZOSCTSHIFT (2)
+
+void DoZIntro (void)
+{
+    byte * shape;
+    int mag;
+    int currentmag;
+    int magstep;
+    int time;
+    int x;
+    int t;
+
+    SetViewSize (MAXVIEWSIZES-1);
+
+    shadingtable=colormap+(1<<12);
+
+    shape=W_CacheLumpName("ap_wrld",PU_CACHE);
+
+    mag=ZMAXMAG<<16;
+    magstep = (ZMAXMAG<<16)/ZOSCTIME;
+    time = ZOSCTIME;
+    t=0;
+
+    CalcTics();
+
+
+    while (time>0)
+    {
+        int zoffset;
+        int hoffset;
+        int offset;
+        int srcoffset;
+        int bottomscreen;
+        int src;
+//      int i;
+
+
+        VL_ClearBuffer (bufferofs, 0);
+        currentmag=mag>>16;
+
+        srcoffset=0;
+        for (x=0; x<320;)
+        {
+            VGAWRITEMAP(x&3);
+
+            offset=(t+(FixedMul(x,ZOSCXSTEP)))&(FINEANGLES-1);
+            zoffset=FixedMul(currentmag,sintable[offset]);
+//         hoffset=FixedMulShift(currentmag,sintable[offset],17);
+            hoffset=0;
+            dc_texturemid=((100+hoffset)<<SFRACBITS)+(SFRACUNIT>>1);
+
+            dc_invscale=((200+zoffset)<<16)/200;
+            dc_iscale=0xffffffffu/(unsigned)dc_invscale;
+
+            srcoffset+=dc_invscale;
+            sprtopoffset=centeryfrac -  FixedMul(dc_texturemid,dc_invscale);
+            bottomscreen = sprtopoffset + (dc_invscale*200);
+            dc_yl = (sprtopoffset+SFRACUNIT-1)>>SFRACBITS;
+            dc_yh = ((bottomscreen-1)>>SFRACBITS);
+            if (dc_yh >= viewheight)
+                dc_yh = viewheight-1;
+            if (dc_yl < 0)
+                dc_yl = 0;
+            if (dc_yl <= dc_yh)
+            {
+                src=srcoffset>>16;
+                if (src>319)
+                    src=319;
+                if (src<0)
+                    src=0;
+                dc_source=shape+(src * 200);
+//            if (RandomNumber("hello",0)<128)
+#ifdef DOS
+                R_DrawColumn ((byte *)bufferofs+(x>>2));
+#else
+                R_DrawColumn ((byte *)bufferofs+x);
+#endif
+            }
+//         srcoffset+=0x10000;
+            x++;
+            if ((LastScan) || IN_GetMouseButtons())
+                return;
+        }
+        FlipPage();
+        CalcTics();
+        mag  -= (magstep * tics);
+//      mag  += FixedMulShift((magstep * tics),sintable[time&(FINEANGLES-1)],19);
+        time -= tics;
+        t    += (tics<<ZOSCTSHIFT);
+        if (mag<0) mag = 0;
+    }
+}
+#endif
+
+
+
+// Old Stuff
+
+/*
+   int y1;
+   int y2;
+
+   if (post->alttile!=0)
+      {
+      ht=nominalheight;
+      src2=W_CacheLumpNum(1+post->alttile,PU_CACHE);
+//      src2+=8;
+      }
+   else
+      {
+      ht=maxheight;
+      src2=src;
+      }
+   hp_srcstep=(64<<(16+HEIGHTFRACTION))/post->wallheight;
+   y1 = (((centery<<HFRACTION)-(post->wallheight*pheight)+(1<<(HFRACTION-1))));
+   y2 = (((post->wallheight*ht)+y1)>>HFRACTION);
+
+   if ((y1>>HFRACTION)>=viewheight)
+      {
+      post->ceilingclip=viewheight-1;
+      post->floorclip=viewheight-1;
+      return;
+      }
+   else if (y1<0)
+      {
+      hp_startfrac=FixedMulShift(-y1,hp_srcstep,HFRACTION);
+      y1=0;
+      post->ceilingclip=0;
+      }
+   else
+      {
+      hp_startfrac=FixedMulShift(255-(y1&0xff),hp_srcstep,HFRACTION);
+      y1>>=HFRACTION;
+      post->ceilingclip=y1;
+      }
+   if (y2<0)
+      {
+      post->floorclip=0;
+      post->ceilingclip=0;
+      }
+   else if (y2>viewheight)
+      {
+      DrawHeightPost(viewheight-y1, src2+((post->texture>>4)&0xfc0), buf+ylookup[y1]);
+      post->floorclip=viewheight-1;
+      }
+   else
+      {
+      DrawHeightPost(y2-y1, src2+((post->texture>>4)&0xfc0), buf+ylookup[y1]);
+      post->floorclip=y2-1;
+      }
+
+   if (ht==maxheight)
+      return;
+
+   y1 = (((centery<<HFRACTION)-(post->wallheight*(pheight-ht))+(1<<(HFRACTION-1))));
+   y2 = (((post->wallheight<<6)+y1)>>HFRACTION);
+
+   if ((y1>>HFRACTION)>=viewheight)
+      return;
+   else if (y1<0)
+      {
+      hp_startfrac=FixedMulShift(-y1,hp_srcstep,HFRACTION);
+      y1=0;
+      }
+   else
+      {
+      hp_startfrac=FixedMulShift(255-(y1&0xff),hp_srcstep,HFRACTION);
+      y1>>=HFRACTION;
+      }
+   if (y2<0)
+      return;
+   else if (y2>viewheight)
+      {
+      DrawHeightPost(viewheight-y1, src+((post->texture>>4)&0xfc0), buf+ylookup[y1]);
+      post->floorclip=viewheight-1;
+      }
+   else
+      {
+      DrawHeightPost(y2-y1, src+((post->texture>>4)&0xfc0), buf+ylookup[y1]);
+      post->floorclip=y2-1;
+      }
+}
+*/
+
+
+
+
+
+
+//******************************************************************************
+//
+// DrawBackground
+//
+//******************************************************************************
+
+void DrawBackground ( byte * bkgnd )
+{
+//   int plane;
+    int size;
+
+    size=linewidth*200;
+
+#ifdef DOS
+    for (plane=0; plane<4; plane++)
+#endif
+    {
+        VGAWRITEMAP(plane);
+        memcpy((byte *)bufferofs,bkgnd,size);
+        bkgnd+=size;
+    }
+}
+
+
+//******************************************************************************
+//
+// PrepareBackground
+//
+//******************************************************************************
+
+void PrepareBackground ( byte * bkgnd )
+{
+//   int plane;
+    int size;
+
+    size=linewidth*200;
+
+#ifdef DOS
+    for (plane=0; plane<4; plane++)
+#endif
+    {
+        VGAREADMAP(plane);
+        memcpy(bkgnd,(byte *)bufferofs,size);
+        bkgnd+=size;
+    }
+}
+
+//******************************************************************************
+//
+// WarpString
+//
+//******************************************************************************
+
+void WarpString (
+    int x, int y, int endx, int endy,
+    int time, byte * back, char * str
+)
+{
+    int dx;
+    int dy;
+    int cx;
+    int cy;
+    int starttime;
+
+
+    LastScan = 0;
+
+
+    dx=((endx-x)<<16)/time;
+    dy=((endy-y)<<16)/time;
+    cx=x<<16;
+    cy=y<<16;
+    starttime=time;
+
+    CalcTics();
+
+    while (time>0)
+    {
+
+        DrawBackground ( back );
+        US_ClippedPrint (cx>>16, cy>>16, str);
+        FlipPage();
+
+        CalcTics();
+        cx+=dx*tics;
+        cy+=dy*tics;
+        time-=tics;
+        if (LastScan != 0)
+            break;
+    }
+
+    // DrawBackground ( back );
+    // US_ClippedPrint (endx, endy, str);
+    // FlipPage();
+
+}
+
+
+#if (SHAREWARE==1)
+//******************************************************************************
+//
+// DoEndCinematic
+//
+//******************************************************************************
+
+//******************************************************************************
+//
+// WarpSprite
+//
+//******************************************************************************
+
+void WarpSprite (
+    int x, int y, int endx, int endy,
+    int time, byte * back, int shape
+)
+{
+    int dx;
+    int dy;
+    int cx;
+    int cy;
+    int starttime;
+
+    LastScan = 0;
+
+    dx=((endx-x)<<16)/time;
+    dy=((endy-y)<<16)/time;
+    cx=x<<16;
+    cy=y<<16;
+    starttime=time;
+
+    CalcTics();
+
+    while (time>0)
+    {
+        DrawBackground ( back );
+        DrawUnScaledSprite (cx>>16, cy>>16, shape, 16);
+        FlipPage();
+        CalcTics();
+        cx+=dx*tics;
+        cy+=dy*tics;
+        time-=tics;
+        if (LastScan != 0)
+            break;
+    }
+}
+
+
+char *EndCinematicPicNames[5] =
+{
+    "lwgshoo2",
+    "hg2shoo2",
+    "ankshoo1",
+    "ligrise4",
+    "tritoss5",
+
+};
+
+#define NUMENDMESSAGES 24
+
+
+char *EndCinematicText[NUMENDMESSAGES] =
+{
+    "You've won the battle, Cassatt.\n"
+    "But when the Oscuridos return,\n"
+    "will you be ready as they wage\n"
+    "their Dark War?",
+
+    "Armed with only a pistol and 30\n"
+    "bucks, you must stop the minions of\n"
+    "El Oscuro before they kill millions\n"
+    "of innocent people.",
+
+    "But for now, hey, enjoy the medal\n"
+    "you received and take a vacation.\n"
+    "You've earned it. Maybe on \n"
+    "San Nicolas Island . . .",
+
+    "Thanks for playing. If you liked\n"
+    "\"The HUNT Begins\", check Ordering\n"
+    "Info for information about \n"
+    "continuing your adventure.",
+
+    "Okay, you can stop reading now.",
+
+    "Press a key. That's all there is.\n"
+    "Thanks.",
+
+    "Are you lazy, or illiterate?\n"
+    "PRESS A KEY.",
+
+    "Look, this is pointless. You\n"
+    "are done. Push off.",
+
+    "Okay, show's over.  Nothing\n"
+    "more to see here.",
+
+    "Wow, you must like this fine\n"
+    "background screen.",
+
+    "For waiting this long, you get . . .\n"
+    "nothing!  Go away!",
+
+    "I mean, I like you as a friend,\n"
+    "but . . .",
+
+    "\"Bob\"",
+
+    "All right, um . . . you found the\n"
+    "secret message! Congratulations!",
+
+    "Didn't work, huh?  Okay, how about\n"
+    "this . . .",
+
+    "THE END",
+
+    "Dang. Thought I had you there.",
+
+    "Stop watching.",
+
+    "You know that if you registered,\n"
+    "there would be a lot more cool\n"
+    "stuff happening right now.",
+
+    "Episode IV: A New Hope\n",
+
+    "Just think of all the new secret\n"
+    "messages you could find hidden\n"
+    "in the registered version!",
+
+    "Someone right now is probably\n"
+    "enjoying the really exciting\n"
+    "ending of the registered version.",
+
+    "ROTT was filmed before\n"
+    "a live audience.",
+
+    "No animals were harmed during the\n"
+    "creation of this video game, although\n"
+    "one dog did get its butt spanked\n"
+    "when it peed on the carpet.\n",
+
+
+};
+char NextGameString1[] = "The Developers of Incredible Power";
+char NextGameString2[] = "shall return";
+
+void DoEndCinematic ( void )
+{
+    int trilogo;
+    int group;
+    int world;
+    int width;
+    int height;
+    int x,y;
+    int shape;
+    int time1,time2;
+    byte * tmp;
+    byte * sky;
+    byte * bkgnd;
+    int i;
+
+    byte pal[768];
+    EnableScreenStretch();
+
+    viewwidth = 320;//MAXSCREENWIDTH;
+    viewheight = 200;//MAXSCREENHEIGHT;
+
+    MU_StartSong(song_youwin);
+
+    bkgnd=SafeMalloc(800*linewidth);
+
+    trilogo=W_GetNumForName("trilogo");
+    world=W_GetNumForName("ap_wrld");
+    group=W_GetNumForName("mmbk");
+    VL_DrawPostPic (trilogo);
+    PrepareBackground ( bkgnd );
+
+    WarpSprite (160, -100, 160, 100, (VBLCOUNTER*3), bkgnd, W_GetNumForName("youwin"));
+    if (LastScan !=0)
+        goto fadelogo;
+
+    I_Delay(30);
+fadelogo:
+    MenuFadeOut();
+    ClearGraphicsScreen();
+    memcpy(&pal[0],W_CacheLumpName("ap_pal",PU_CACHE,CvtNull,1),768);
+    VL_NormalizePalette(&pal[0]);
+    SwitchPalette(&pal[0],35);
+
+    VL_DrawPostPic (world);
+    PrepareBackground ( bkgnd );
+
+    WarpSprite (160, 250, 160, 100, (VBLCOUNTER*3), bkgnd, W_GetNumForName("wrldsafe"));
+    if (LastScan !=0)
+        goto fadeworld;
+
+    I_Delay(10);
+    if (LastScan !=0)
+        goto fadeworld;
+
+    WarpSprite (160, 100, 160, -50, (VBLCOUNTER*3), bkgnd, W_GetNumForName("wrldsafe"));
+    if (LastScan !=0)
+        goto fadeworld;
+
+    I_Delay(20);
+
+fadeworld:
+    MenuFadeOut();
+    ClearGraphicsScreen();
+    MenuFadeIn();
+
+
+    sky=W_CacheLumpNum(W_GetNumForName("SKYSTART")+2,PU_CACHE,CvtNull,1);
+    tmp=sky;
+    for (x=0; x<256; x++)
+    {
+        VGAWRITEMAP(x&3);
+        for (y=0; y<200; y++)
+        {
+#ifdef DOS
+            *((byte *)bufferofs+ylookup[y]+(x>>2))=*tmp++;
+#else
+            *((byte *)bufferofs+ylookup[y]+x)=*tmp++;
+#endif
+        }
+    }
+    tmp=sky;
+    for (x=256; x<320; x++)
+    {
+        VGAWRITEMAP(x&3);
+        for (y=0; y<200; y++)
+        {
+#ifdef DOS
+            *((byte *)bufferofs+ylookup[y]+(x>>2))=*tmp++;
+#else
+            *((byte *)bufferofs+ylookup[y]+x)=*tmp++;
+#endif
+        }
+    }
+
+    for(i=0; i<5; i++)
+    {
+        int tx,ty;
+
+        tx = 32 + (i << 6);
+        ty = 100;
+        shape = W_GetNumForName(EndCinematicPicNames[i]);
+        DrawUnScaledSprite (tx, ty, shape,16);
+    }
+
+    PrepareBackground ( bkgnd );
+
+    //CurrentFont = (font_t *)W_CacheLumpName ("newfnt1", PU_CACHE);
+    CurrentFont = smallfont;
+    LastScan = 0;
+
+    for(i=0; i<NUMENDMESSAGES; i++)
+    {
+        if (i>3)
+            I_Delay(50);
+
+        US_MeasureStr (&width, &height, "%s", &(EndCinematicText[i][0]));
+        if (LastScan !=0)
+            break;
+
+        x=(320-width)>>1;
+        y=(200-height)>>1;
+        time1 = (300 - y)*(VBLCOUNTER*4)/300;
+        time2 = VBLCOUNTER*4-time1;
+
+        WarpString (x, 250, x, y-50,time1, bkgnd, EndCinematicText[i]);
+        if (LastScan !=0)
+            break;
+        I_Delay(40);
+        if (LastScan !=0)
+            break;
+
+        if (i<=3)
+            I_Delay(40);
+        if (LastScan !=0)
+            break;
+
+        WarpString (x, y-50, x, -50, time2, bkgnd, EndCinematicText[i]);
+        if (LastScan !=0)
+            break;
+
+
+    }
+
+    if (LastScan!=0)
+        goto finalfade;
+
+    sky=W_CacheLumpNum(W_GetNumForName("SKYSTART")+2,PU_CACHE,CvtNull,1);
+    tmp=sky;
+    for (x=0; x<256; x++)
+    {
+        VGAWRITEMAP(x&3);
+        for (y=0; y<200; y++)
+        {
+#ifdef DOS
+            *((byte *)bufferofs+ylookup[y]+(x>>2))=*tmp++;
+#else
+            *((byte *)bufferofs+ylookup[y]+x)=*tmp++;
+#endif
+        }
+    }
+    tmp=sky;
+    for (x=256; x<320; x++)
+    {
+        VGAWRITEMAP(x&3);
+        for (y=0; y<200; y++)
+        {
+#ifdef DOS
+            *((byte *)bufferofs+ylookup[y]+(x>>2))=*tmp++;
+#else
+            *((byte *)bufferofs+ylookup[y]+x)=*tmp++;
+#endif
+        }
+    }
+
+    for(i=0; i<5; i++)
+    {
+        int tx,ty;
+
+        tx = 32 + (i << 6);
+        ty = 100;
+        shape = W_GetNumForName(EndCinematicPicNames[i]);
+        DrawUnScaledSprite (tx, ty, shape,16);
+    }
+
+
+    shape = W_GetNumForName("robogrd3");
+    PrepareBackground ( bkgnd );
+    WarpSprite (420,100,300,100,VBLCOUNTER*3,bkgnd,shape);
+    if (LastScan !=0)
+        goto finalfade;
+
+    PrepareBackground ( bkgnd );
+    WarpString (200,80,200,80,VBLCOUNTER*3,bkgnd, "Am I late?");
+    if (LastScan !=0)
+        goto finalfade;
+
+
+    I_Delay(20);
+finalfade:
+
+    MenuFadeOut();
+    VL_ClearVideo (0);
+    I_Delay(10);
+
+    if (LastScan == 0)
+    {
+        US_MeasureStr (&width, &height, "%s", NextGameString1);
+        x=(320-width)>>1;
+        y=(200-height)>>1;
+        US_ClippedPrint (x,y-6, NextGameString1);
+        US_MeasureStr (&width, &height, "%s", NextGameString2);
+        x=(320-width)>>1;
+        y=(200-height)>>1;
+        US_ClippedPrint (x,y+6, NextGameString2);
+        FlipPage();
+        VL_FadeIn(0,255,origpal,150);
+        I_Delay(50);
+        VL_FadeOut(0,255,0,0,0,150);
+        VL_ClearVideo (0);
+        I_Delay(10);
+    }
+
+    SafeFree(bkgnd);
+}
+#else
+
+// REGISTERED VERSION ======================================================
+
+static char    burnCastle1Msg []=
+    "The monastery burns.\n"
+    "\n"
+    "El Oscuro is dead.\n"
+    "\n"
+    "The world is safe.\n";
+
+// If all Snake Eggs not destroyed on final level:
+
+
+static char    notDoneMsg[] =
+    "Unfortunately not all\n"
+    "of El Oscuro's larvae\n"
+    "were destroyed.\n"
+    "\n"
+    "Thirty years later,\n"
+    "a descendant of\n"
+    "El Oscuro wiped out\n"
+    "the entire world,\n"
+    "but nice job anyway.\n";
+
+static char    tryAgainMsg[] =
+    "Try Again.\n"
+    "\n"
+    "The world will not be\n"
+    "safe until all of El\n"
+    "Oscuro's larvae are\n"
+    "destroyed. Find them.\n";
+
+// If all snake eggs destroyed:
+static char    doneMsg[] =
+    "You have destroyed\n"
+    "El Oscuro and all his\n"
+    "descendants.  Well done!\n";
+
+// On Triad background, in bigger font.
+static char    youWin1Msg[] =
+    "So, HUNT Members, how\n"
+    "do you think the\n"
+    "mission went?\n";
+
+// Place menu pix of characters here (maybe modem frame too?)
+static char    youWin2Msg[] =
+    "Barrett: Well, I think\n"
+    "I got shin splints from\n"
+    "all those jump pads.\n"
+    "But hey, action-wise,\n"
+    "I've been in tougher\n"
+    "bar fights, for crying\n"
+    "out loud.\n";
+
+static char    youWin3Msg[] =
+    "Cassatt: Apart from\n"
+    "the other HUNT members\n"
+    "saying I look like\n"
+    "Richard Mulligan, it\n"
+    "was quite a success.\n"
+    "And some of the\n"
+    "monastery's ironwork\n"
+    "was very nice.\n";
+
+static char    youWin4Msg[] =
+    "Ni: it was quite easy,\n"
+    "actually.  I just\n"
+    "pictured the enemy\n"
+    "having the face of\n"
+    "my ex-husband, and\n"
+    "man, I was a force\n"
+    "of Nature.\n";
+
+static char    youWin5Msg[] =
+    "Wendt: I was kind of\n"
+    "disappointed. I think\n"
+    "I used the missile\n"
+    "weapons way too much.\n"
+    "Next time, bullets\n"
+    "only.  Nothing sweeter\n"
+    "than a head shot from\n"
+    "a hundred feet.\n";
+
+static char    youWin6Msg[] =
+    "Freeley: I'm still\n"
+    "trying to adjust in\n"
+    "the aftermath.  It's\n"
+    "kinda tough.  I mean,\n"
+    "I save the damn world,\n"
+    "and all people ask\n"
+    "about is my name.\n"
+    "Sheesh.\n";
+
+// On caching screen
+
+static char     youWin7Msg[] =
+    "The HUNT is victorious!\n"
+    "\n"
+    "         THE END\n";
+
+
+static char     youWin8Msg[] =
+    "Now go and celebrate!\n"
+    "\n"
+    "      THE REAL END";
+
+#define NUMEXPLOSIONTYPES 4
+
+typedef struct {
+    char  name[11];
+    byte  numframes;
+} ExplosionInfoType;
+
+ExplosionInfoType ExplosionInfo[NUMEXPLOSIONTYPES]=
+{
+    {"EXPLOS1\0",20},
+    {"EXP1\0",20},
+    {"GREXP1\0",25},
+    {"PART1\0",12},
+#if 0
+    {"GUTS1\0",12},
+    {"ORGAN1\0",12},
+    {"RIB1\0",12},
+    {"GPINK1\0",12},
+    {"GHEAD1\0",12},
+    {"GARM1\0",12},
+    {"GLEG1\0",12},
+    {"GHUM1\0",12},
+    {"GHIP1\0",12},
+    {"GLIMB1\0",12},
+#endif
+};
+
+
+typedef struct {
+    byte  which;
+    byte  frame;
+    byte  x;
+    byte  y;
+} ExplosionType;
+
+#define MAXTRANSMITTEREXPLOSIONS 30
+
+static ExplosionType Explosions[MAXTRANSMITTEREXPLOSIONS];
+
+void ResetTransmitterExplosion ( ExplosionType * Explosion )
+{
+    Explosion->which=RandomNumber("Explosion",0)%NUMEXPLOSIONTYPES;
+    Explosion->frame=0;
+    Explosion->x=(RandomNumber("Explosion",2)>>1)+(160-64);
+    Explosion->y=(RandomNumber("Explosion",3)>>1);
+}
+
+void CacheTransmitterExplosions ( void )
+{
+    int i,j,num;
+
+    for (i=0; i<NUMEXPLOSIONTYPES; i++)
+    {
+        num=W_GetNumForName(ExplosionInfo[i].name);
+        for (j=0; j<ExplosionInfo[i].numframes; j++)
+        {
+            W_CacheLumpNum(num+j, PU_CACHE, Cvt_patch_t, 1);
+        }
+    }
+}
+
+void SetupTransmitterExplosions ( void )
+{
+    int i;
+
+    for (i=0; i<MAXTRANSMITTEREXPLOSIONS; i++)
+    {
+        ResetTransmitterExplosion(&Explosions[i]);
+    }
+}
+void UpdateTransmitterExplosions ( void )
+{
+    int i;
+    for (i=0; i<MAXTRANSMITTEREXPLOSIONS; i++)
+    {
+        Explosions[i].frame+=tics;
+        if (Explosions[i].frame>=(ExplosionInfo[Explosions[i].which].numframes<<1))
+        {
+            ResetTransmitterExplosion(&Explosions[i]);
+            SD_Play(SD_EXPLODEFLOORSND+(RandomNumber("Explosion",4)>>7));
+        }
+    }
+}
+
+void DrawTransmitterExplosions ( void )
+{
+    int i;
+    for (i=0; i<MAXTRANSMITTEREXPLOSIONS; i++)
+    {
+        DrawUnScaledSprite (
+            Explosions[i].x,
+            Explosions[i].y,
+            (W_GetNumForName(ExplosionInfo[Explosions[i].which].name) +
+             (Explosions[i].frame>>1)),
+            16
+        );
+    }
+}
+
+void DoTransmitterExplosion ( void )
+{
+    byte * back;
+    int i;
+
+    VL_ClearVideo(0);
+    back=SafeMalloc(800*linewidth);
+
+    CalcTics();
+    CalcTics();
+    DrawNormalSprite(0,0,W_GetNumForName("transmit"));
+    PrepareBackground ( back );
+    SetupTransmitterExplosions ();
+    CacheTransmitterExplosions ();
+    DrawBackground ( back );
+    FlipPage();
+    VL_FadeIn (0, 255, origpal, 30);
+    SHAKETICS=VBLCOUNTER*15;
+    for (i=0; i<(VBLCOUNTER*15); i+=tics)
+    {
+        DrawBackground ( back );
+        DrawTransmitterExplosions ();
+        FlipPage();
+        CalcTics();
+        UpdateTransmitterExplosions ();
+    }
+    VL_FadeOut (0, 255, 63, 63, 63, 150);
+    screenfaded=false;
+    SD_Play(SD_PLAYERTCSND);
+    SD_Play(SD_PLAYERTBSND);
+    SD_Play(SD_PLAYERDWSND);
+    SD_Play(SD_PLAYERLNSND);
+    SD_Play(SD_PLAYERIPFSND);
+    VL_FadeOut (0, 255, 0, 0, 0, 30);
+    TurnShakeOff();
+
+    SafeFree(back);
+}
+
+void ShowTransmitter ( void )
+{
+    MenuFadeOut();
+    DrawNormalSprite(0,0,W_GetNumForName("transmit"));
+    FlipPage();
+    VL_FadeIn (0, 255, origpal, 30);
+    I_Delay(30);
+    VL_FadeOut (0, 255, 0, 0, 0, 30);
+}
+
+void ShowFinalDoor ( void )
+{
+    byte pal[768];
+
+    MenuFadeOut();
+
+    VL_ClearBuffer (bufferofs, 0);
+    DrawNormalSprite (0, (200-120)>>1, W_GetNumForName("finldoor"));
+    FlipPage();
+    memcpy(&pal[0],W_CacheLumpName("findrpal",PU_CACHE,CvtNull, 1),768);
+    VL_NormalizePalette(&pal[0]);
+    SD_Play(SD_OPENDOORSND);
+    VL_FadeIn (0, 255, pal, 30);
+    I_Delay(30);
+    VL_FadeOut (0, 255, 0, 0, 0, 30);
+}
+
+void ShowFinalFire ( void )
+{
+    byte pal[768];
+
+    MenuFadeOut();
+
+    VL_ClearBuffer (bufferofs, 0);
+    DrawNormalSprite (0, (200-120)>>1, W_GetNumForName("finlfire"));
+    FlipPage();
+    memcpy(&pal[0],W_CacheLumpName("finfrpal",PU_CACHE,CvtNull, 1),768);
+    VL_NormalizePalette(&pal[0]);
+    SD_Play(SD_BAZOOKAFIRESND);
+    VL_FadeIn (0, 255, pal, 30);
+    SD_Play(SD_FIREBOMBFIRESND);
+    I_Delay(2);
+    SD_Play(SD_HEATSEEKFIRESND);
+    I_Delay(2);
+    SD_Play(SD_DRUNKFIRESND);
+    SD_Play(SD_HEATSEEKFIRESND);
+    I_Delay(2);
+    SD_Play(SD_ATKMP40SND);
+    SD_Play(SD_ATKMP40SND);
+    I_Delay(2);
+    SD_Play(SD_HEATSEEKFIRESND);
+    SD_Play(SD_FIREBOMBFIRESND);
+    I_Delay(2);
+    SD_Play(SD_ATKMP40SND);
+    SD_Play(SD_HEATSEEKFIRESND);
+    I_Delay(2);
+    SD_Play(SD_DRUNKFIRESND);
+    I_Delay(2);
+    SD_Play(SD_FIREBOMBFIRESND);
+    I_Delay(2);
+    SD_Play(SD_HEATSEEKFIRESND);
+    SD_Play(SD_ATKMP40SND);
+    I_Delay(2);
+    SD_Play(SD_DRUNKFIRESND);
+    SD_Play(SD_HEATSEEKFIRESND);
+    I_Delay(2);
+    SD_Play(SD_FIREBOMBFIRESND);
+    SD_Play(SD_ATKMP40SND);
+    I_Delay(2);
+    SD_Play(SD_DRUNKFIRESND);
+    I_Delay(2);
+    SD_Play(SD_HEATSEEKFIRESND);
+    SD_Play(SD_FIREBOMBFIRESND);
+    I_Delay(2);
+    SD_Play(SD_ATKMP40SND);
+    SD_Play(SD_HEATSEEKFIRESND);
+    I_Delay(2);
+    SD_Play(SD_DRUNKFIRESND);
+    SD_Play(SD_FIREBOMBFIRESND);
+    I_Delay(2);
+    SD_Play(SD_HEATSEEKFIRESND);
+    SD_Play(SD_DRUNKFIRESND);
+    SD_Play(SD_BAZOOKAFIRESND);
+    I_Delay(4);
+    VL_FadeOut (0, 255, 0, 0, 0, 30);
+}
+
+void ScrollString ( int cy, char * string, byte * bkgnd, int scrolltime, int pausetime )
+{
+    int x,y;
+    int width,height;
+    int time1,time2;
+
+    LastScan=0;
+    US_MeasureStr (&width, &height, "%s", string);
+
+    x=(320-width)>>1;
+    y=cy-(height>>1);
+    time1 = ((220 - y)*scrolltime)/(220+height);
+    time2 = scrolltime-time1;
+
+    WarpString (x, 210, x, y, time1, bkgnd, string);
+
+    if (LastScan !=0)
+        return;
+
+    I_Delay(pausetime);
+
+    if (LastScan !=0)
+        return;
+
+    WarpString (x, y, x, -10-height, time2, bkgnd, string);
+}
+
+void DoBurningCastle ( void )
+{
+    byte * back;
+
+    LastScan=0;
+    VL_ClearVideo(0);
+    back=SafeMalloc(800*linewidth);
+
+    DrawNormalSprite(0,0,W_GetNumForName("finale"));
+    PrepareBackground ( back );
+    CurrentFont = smallfont;
+    FlipPage();
+    VL_FadeIn (0, 255, origpal, 30);
+    CurrentFont = (font_t *)W_CacheLumpName ("newfnt1", PU_STATIC, Cvt_font_t, 1 );
+    ScrollString ( 150, &burnCastle1Msg[0], back, 4*VBLCOUNTER, 80);
+    W_CacheLumpName ("newfnt1", PU_CACHE, Cvt_font_t, 1);
+    VL_FadeOut (0, 255, 0, 0, 0, 80);
+    SafeFree(back);
+}
+
+void DoFailedScreen ( void )
+{
+    byte * back;
+
+    back=SafeMalloc(800*linewidth);
+
+    VL_DrawPostPic (W_GetNumForName("trilogo"));
+    PrepareBackground ( back );
+    CurrentFont = smallfont;
+    FlipPage();
+    VL_FadeIn (0, 255, origpal, 30);
+    ScrollString ( 100, &notDoneMsg[0], back, 4*VBLCOUNTER, 100);
+    VL_FadeOut (0, 255, 0, 0, 0, 80);
+    SafeFree(back);
+}
+
+void DoTryAgainScreen ( void )
+{
+    byte * back;
+
+    back=SafeMalloc(800*linewidth);
+
+    VL_DrawPostPic (W_GetNumForName("trilogo"));
+    PrepareBackground ( back );
+    CurrentFont = smallfont;
+    FlipPage();
+    VL_FadeIn (0, 255, origpal, 30);
+    ScrollString ( 100, tryAgainMsg, back, 4*VBLCOUNTER, 80);
+    VL_FadeOut (0, 255, 0, 0, 0, 80);
+    SafeFree(back);
+}
+
+void ResetWorldExplosion ( ExplosionType * Explosion )
+{
+    Explosion->which=RandomNumber("Explosion",0)%NUMEXPLOSIONTYPES;
+    Explosion->frame=0;
+//   RandomNumber("Explosion",1)%ExplosionInfo[Explosions[i].which].numframes;
+    Explosion->x=(RandomNumber("Explosion",2))+64;
+    Explosion->y=(RandomNumber("Explosion",3)%180);
+}
+
+void SetupWorldExplosions ( void )
+{
+    int i;
+
+    for (i=0; i<MAXTRANSMITTEREXPLOSIONS; i++)
+    {
+        ResetWorldExplosion(&Explosions[i]);
+    }
+}
+void UpdateWorldExplosions ( void )
+{
+    int i;
+    for (i=0; i<MAXTRANSMITTEREXPLOSIONS; i++)
+    {
+        Explosions[i].frame+=tics;
+        if (Explosions[i].frame>=(ExplosionInfo[Explosions[i].which].numframes<<1))
+        {
+            ResetWorldExplosion(&Explosions[i]);
+            SD_Play(SD_EXPLODEFLOORSND+(RandomNumber("Explosion",4)>>7));
+        }
+    }
+}
+
+void DestroyEarth ( void )
+{
+    byte * back;
+    int i;
+
+    VL_ClearVideo(0);
+    back=SafeMalloc(800*linewidth);
+
+    CalcTics();
+    CalcTics();
+    DrawNormalSprite(0,0,W_GetNumForName("ourearth"));
+    PrepareBackground ( back );
+    SetupWorldExplosions ();
+    CacheTransmitterExplosions ();
+    DrawBackground ( back );
+    FlipPage();
+    VL_FadeIn (0, 255, origpal, 30);
+    SHAKETICS=VBLCOUNTER*10;
+    for (i=0; i<(VBLCOUNTER*10); i+=tics)
+    {
+        DrawBackground ( back );
+        DrawTransmitterExplosions ();
+        FlipPage();
+        CalcTics();
+        UpdateWorldExplosions ();
+    }
+    VL_FadeOut (0, 255, 63, 63, 63, 150);
+    screenfaded=false;
+    if (gamestate.violence==vl_excessive)
+        SD_Play(SD_YOUSUCKSND);
+    VL_FadeOut (0, 255, 0, 0, 0, 50);
+    TurnShakeOff();
+
+    SafeFree(back);
+}
+
+boolean DestroyedAllEggs ( void )
+{
+    statobj_t * temp;
+
+    for(temp=FIRSTSTAT; temp; temp=temp->statnext)
+    {
+        if (temp->itemnumber==stat_tomlarva)
+            return false;
+    }
+    return true;
+}
+
+void DoSanNicolas ( void )
+{
+    byte pal[768];
+
+    LastScan=0;
+    VL_ClearVideo(0);
+    DrawNormalSprite(0,16,W_GetNumForName("nicolas"));
+    DrawNormalSprite(10,200-58,W_GetNumForName("budgcut"));
+    FlipPage();
+    memcpy(&pal[0],W_CacheLumpName("nicpal",PU_CACHE, CvtNull, 1),768);
+    VL_NormalizePalette(&pal[0]);
+    VL_FadeIn (0, 255, pal, 30);
+    I_Delay(60);
+    VL_FadeOut (0, 255, 0, 0, 0, 80);
+}
+
+void PlayerQuestionScreen ( void )
+{
+    byte * back;
+
+    back=SafeMalloc(800*linewidth);
+
+    VL_DrawPostPic (W_GetNumForName("trilogo"));
+    PrepareBackground ( back );
+    CurrentFont = smallfont;
+    FlipPage();
+    VL_FadeIn (0, 255, origpal, 30);
+    CurrentFont = (font_t *)W_CacheLumpName ("newfnt1", PU_STATIC, Cvt_font_t, 1);
+    ScrollString ( 100, &doneMsg[0], back, 4*VBLCOUNTER, 40);
+    ScrollString ( 100, &youWin1Msg[0], back, 4*VBLCOUNTER, 50);
+    VL_DrawPostPic (W_GetNumForName("trilogo"));
+    DrawXYPic ( 8, 100-24, W_GetNumForName("player2"));
+    PrepareBackground ( back );
+    CurrentFont = smallfont;
+    SD_Play(SD_PLAYERTBSND);
+    ScrollString ( 100, &youWin2Msg[0], back, 4*VBLCOUNTER, 100);
+    VL_DrawPostPic (W_GetNumForName("trilogo"));
+    DrawXYPic ( 8, 100-24, W_GetNumForName("player1"));
+    PrepareBackground ( back );
+    SD_Play(SD_PLAYERTCSND);
+    ScrollString ( 100, &youWin3Msg[0], back, 4*VBLCOUNTER, 100);
+    VL_DrawPostPic (W_GetNumForName("trilogo"));
+    DrawXYPic ( 8, 100-24, W_GetNumForName("player4"));
+    PrepareBackground ( back );
+    SD_Play(SD_PLAYERLNSND);
+    ScrollString ( 100, &youWin4Msg[0], back, 4*VBLCOUNTER, 100);
+    VL_DrawPostPic (W_GetNumForName("trilogo"));
+    DrawXYPic ( 8, 100-24, W_GetNumForName("player3"));
+    PrepareBackground ( back );
+    SD_Play(SD_PLAYERDWSND);
+    ScrollString ( 100, &youWin5Msg[0], back, 4*VBLCOUNTER, 100);
+    VL_DrawPostPic (W_GetNumForName("trilogo"));
+    DrawXYPic ( 8, 100-24, W_GetNumForName("player5"));
+    PrepareBackground ( back );
+    SD_Play(SD_PLAYERIPFSND);
+    ScrollString ( 100, &youWin6Msg[0], back, 4*VBLCOUNTER, 100);
+    W_CacheLumpName ("newfnt1", PU_CACHE, Cvt_font_t, 1);
+    VL_FadeOut (0, 255, 0, 0, 0, 80);
+    SafeFree(back);
+}
+
+void DoYouWin ( void )
+{
+    pic_t * pic;
+    byte * back;
+
+    back=SafeMalloc(800*linewidth);
+    LastScan=0;
+    VL_ClearVideo(0);
+    pic = (pic_t *) W_CacheLumpNum (W_GetNumForName ("mmbk"), PU_CACHE, Cvt_pic_t, 1);
+    VWB_DrawPic (0, 0, pic);
+    PrepareBackground ( back );
+    FlipPage();
+    VL_FadeIn (0, 255, origpal, 30);
+    CurrentFont = (font_t *)W_CacheLumpName ("newfnt1", PU_STATIC, Cvt_font_t, 1);
+    ScrollString ( 100, &youWin7Msg[0], back, 4*VBLCOUNTER, 300);
+    W_CacheLumpName ("newfnt1", PU_CACHE, Cvt_font_t, 1);
+    VL_FadeOut (0, 255, 0, 0, 0, 80);
+    SafeFree(back);
+}
+
+void DoFinalEnd ( void )
+{
+    pic_t * pic;
+    byte * back;
+
+    back=SafeMalloc(800*linewidth);
+    LastScan=0;
+    VL_ClearVideo(0);
+    pic = (pic_t *) W_CacheLumpNum (W_GetNumForName ("mmbk"), PU_CACHE, Cvt_pic_t, 1);
+    VWB_DrawPic (0, 0, pic);
+    DrawNormalSprite(0,0,W_GetNumForName("sombrero"));
+    DrawNormalSprite(0,0,W_GetNumForName("amflag"));
+    DrawNormalSprite(0,0,W_GetNumForName("witchhat"));
+    DrawNormalSprite(0,0,W_GetNumForName("esterhat"));
+    DrawNormalSprite(0,0,W_GetNumForName("santahat"));
+    PrepareBackground ( back );
+    FlipPage();
+    VL_FadeIn (0, 255, origpal, 30);
+    CurrentFont = (font_t *)W_CacheLumpName ("newfnt1", PU_STATIC, Cvt_font_t, 1);
+    ScrollString ( 100, &youWin8Msg[0], back, 4*VBLCOUNTER, 100);
+    W_CacheLumpName ("newfnt1", PU_CACHE, Cvt_font_t, 1);
+    VL_FadeOut (0, 255, 0, 0, 0, 80);
+    SafeFree(back);
+    VL_ClearVideo(0);
+}
+
+static char     dipMsg[] =
+    "The Developers of Incredible Power!\n"
+    "\n"
+    "Susan  Tom  Jim  Stephen\n"
+    "Mark  William  Chuck\n";
+
+static char     creditsMsg[] =
+    "Rise of the Triad Credits\n";
+
+static char     credits1Msg[] =
+    "Programmers\n"
+    "\n"
+    "Mark Dochtermann\n"
+    "William Scarboro\n"
+    "Jim Dose'\n"
+    "Nolan Martin\n";
+
+static char     credits2Msg[] =
+    "Creative Director\n"
+    "\n"
+    "Tom Hall\n";
+
+static char     credits3Msg[] =
+    "Artists\n"
+    "\n"
+    "Stephen Hornback\n"
+    "Tim Neveu\n"
+    "Chuck Jones\n"
+    "Susan Singer\n"
+    "James Storey\n"
+    "Cygnus Multimedia\n";
+
+static char     credits4Msg[] =
+    "Level Designers\n"
+    "\n"
+    "Tom Hall\n"
+    "Joseph Selinske\n"
+    "Marianna Vayntrub\n"
+    "Joe Siegler\n";
+static char     credits5Msg[] =
+    "Music\n"
+    "\n"
+    "Lee Jackson\n"
+    "Bobby Prince\n";
+
+static char     credits6Msg[] =
+    "Robot Models\n"
+    "\n"
+    "Gregor Punchatz\n";
+
+static char     credits7Msg[] =
+    "Special Thanks\n"
+    "\n"
+    "George Broussard\n"
+    "Scott Miller\n"
+    "Steven Blackburn\n"
+    "Apogee Technical Support\n"
+    "Apogee Support Staff\n"
+    "John Carmack\n"
+    "Ken Silverman\n";
+
+static char     credits8Msg[] =
+    "The Hand of God\n"
+    "\n"
+    "Tim Neveu's Hand\n";
+
+static char     credits9Msg[] =
+    "Dog Snout and Paw\n"
+    "\n"
+    "Loki\n"
+    "The Carpet Wetting Maestro\n";
+
+static char     credits10Msg[] =
+    "Krist's chair\n"
+    "\n"
+    "Stephen Blackburn's Comfy Chair\n"
+    "Marianna's Paper and Glue\n";
+
+static char     credits11Msg[] =
+    "Character Voices\n"
+    "\n"
+    "Darian - Mark Dochtermann\n"
+    "Krist - Joe Siegler\n"
+    "NME - Sound CD#4005\n"
+    "Oscuro - Tom Hall\n"
+    "Low Guard - Steve Quarrella\n"
+    "High Guard - Steven Blackburn\n"
+    "Over Patrol - Chuck Jones\n";
+
+static char     credits12Msg[] =
+    "Character Voices Continued\n"
+    "\n"
+    "Strike Team - Scott Miller\n"
+    "Lightning Guard - William Scarboro\n"
+    "Triad Enforcer - George Broussard\n"
+    "All Monks - Tom Hall\n"
+    "Taradino - Joe Selinske\n"
+    "Lorelei - Pau Suet Ying\n"
+    "Ian Paul - Jim Dose'\n"
+    "Doug - Lee Jackson\n"
+    "Thi - Susan Singer\n";
+
+static char     actorsMsg[] =
+    "The Actors\n";
+
+static char     actors1Msg[] =
+    "Low Guard\n"
+    "\n"
+    "Steve Quarrella\n";
+
+static char     actors2Msg[] =
+    "High Guard\n"
+    "\n"
+    "Steven Blackburn\n";
+
+static char     actors3Msg[] =
+    "Over Patrol\n"
+    "\n"
+    "Nolan Martin\n";
+
+static char     actors4Msg[] =
+    "Strike Team\n"
+    "\n"
+    "Scott Miller\n";
+
+static char     actors5Msg[] =
+    "Lightning Guard\n"
+    "\n"
+    "Kevin Green\n";
+
+static char     actors6Msg[] =
+    "Triad Enforcer\n"
+    "\n"
+    "George Broussard\n";
+
+static char     actors7Msg[] =
+    "Death Monk\n"
+    "\n"
+    "Lee Jackson\n";
+
+static char     actors8Msg[] =
+    "Deathfire Monk\n"
+    "\n"
+    "Allen Blum III\n";
+
+static char     actors9Msg[] =
+    "Robot Guard\n"
+    "\n"
+    "Himself\n";
+
+static char     actors10Msg[] =
+    "General Darian\n"
+    "\n"
+    "Steve Maines\n";
+
+static char     actors11Msg[] =
+    "Sebastian Krist\n"
+    "\n"
+    "Joe Siegler\n";
+
+static char     actors12Msg[] =
+    "The NME\n"
+    "\n"
+    "Himself\n";
+
+static char     actors13Msg[] =
+    "El Oscuro\n"
+    "\n"
+    "Tom Hall\n";
+
+
+static char     cut1Msg[] =
+    "Deathfire Monk\n"
+    "\n"
+    "Mark Dochtermann\n";
+
+
+static char     cut2Msg[] =
+    "Over Patrol\n"
+    "\n"
+    "Pat Miller\n";
+
+
+static char     cut3Msg[] =
+    "Low Guard\n"
+    "\n"
+    "Marianna Vayntrub\n";
+
+
+static char     cut4Msg[] =
+    "Strike Team\n"
+    "\n"
+    "Ann Grauerholz\n";
+
+static char     cut5Msg[] =
+    "Lightning Guard\n"
+    "\n"
+    "William Scarboro\n";
+
+
+static char     cut6Msg[] =
+    "High Guard\n"
+    "\n"
+    "Stephen Hornback\n";
+
+
+
+static char     playersCutMsg[] =
+    "Actors who were\n"
+    "cut from the game\n";
+
+void DIPCredits ( void )
+{
+    byte * back;
+
+    back=SafeMalloc(800*linewidth);
+
+    VL_DrawPostPic (W_GetNumForName("trilogo"));
+    PrepareBackground ( back );
+    FlipPage();
+    VL_FadeIn (0, 255, origpal, 30);
+    CurrentFont = (font_t *)W_CacheLumpName ("newfnt1", PU_STATIC, Cvt_font_t, 1);
+    ScrollString ( 100, &creditsMsg[0], back, 4*VBLCOUNTER, 30);
+    CurrentFont = smallfont;
+    ScrollString ( 100, &credits1Msg[0], back, 4*VBLCOUNTER, 50);
+    ScrollString ( 100, &credits2Msg[0], back, 4*VBLCOUNTER, 50);
+    ScrollString ( 100, &credits3Msg[0], back, 4*VBLCOUNTER, 50);
+    ScrollString ( 100, &credits4Msg[0], back, 4*VBLCOUNTER, 50);
+    ScrollString ( 100, &credits5Msg[0], back, 4*VBLCOUNTER, 50);
+    ScrollString ( 100, &credits6Msg[0], back, 4*VBLCOUNTER, 50);
+    ScrollString ( 100, &credits7Msg[0], back, 4*VBLCOUNTER, 50);
+    ScrollString ( 100, &credits8Msg[0], back, 4*VBLCOUNTER, 50);
+    ScrollString ( 100, &credits9Msg[0], back, 4*VBLCOUNTER, 50);
+    ScrollString ( 100, &credits10Msg[0], back, 4*VBLCOUNTER, 50);
+    ScrollString ( 100, &credits11Msg[0], back, 4*VBLCOUNTER, 80);
+    ScrollString ( 100, &credits12Msg[0], back, 4*VBLCOUNTER, 80);
+
+    CurrentFont = (font_t *)W_CacheLumpName ("newfnt1", PU_STATIC, Cvt_font_t, 1);
+    ScrollString ( 100, &actorsMsg[0], back, 4*VBLCOUNTER, 50);
+
+    CurrentFont = smallfont;
+    VL_DrawPostPic (W_GetNumForName("trilogo"));
+    DrawNormalSprite(0,(200-128)>>1,W_GetNumForName("lwgshoo2"));
+    PrepareBackground ( back );
+    ScrollString ( 100, &actors1Msg[0], back, 4*VBLCOUNTER, 50);
+
+    VL_DrawPostPic (W_GetNumForName("trilogo"));
+    DrawNormalSprite(0,(200-128)>>1,W_GetNumForName("hg2shoo2"));
+    PrepareBackground ( back );
+    ScrollString ( 100, &actors2Msg[0], back, 4*VBLCOUNTER, 50);
+
+    VL_DrawPostPic (W_GetNumForName("trilogo"));
+    DrawNormalSprite(0,(200-128)>>1,W_GetNumForName("obpshoo1"));
+    PrepareBackground ( back );
+    ScrollString ( 100, &actors3Msg[0], back, 4*VBLCOUNTER, 50);
+
+    VL_DrawPostPic (W_GetNumForName("trilogo"));
+    DrawNormalSprite(0,(200-128)>>1,W_GetNumForName("ankshoo1"));
+    PrepareBackground ( back );
+    ScrollString ( 100, &actors4Msg[0], back, 4*VBLCOUNTER, 50);
+
+    VL_DrawPostPic (W_GetNumForName("trilogo"));
+    DrawNormalSprite(0,(200-128)>>1,W_GetNumForName("ligrise4"));
+    PrepareBackground ( back );
+    ScrollString ( 100, &actors5Msg[0], back, 4*VBLCOUNTER, 50);
+
+    VL_DrawPostPic (W_GetNumForName("trilogo"));
+    DrawNormalSprite(0,(200-128)>>1,W_GetNumForName("tritoss5"));
+    PrepareBackground ( back );
+    ScrollString ( 100, &actors6Msg[0], back, 4*VBLCOUNTER, 50);
+
+    VL_DrawPostPic (W_GetNumForName("trilogo"));
+    DrawNormalSprite(0,(200-128)>>1,W_GetNumForName("monkdr4"));
+    PrepareBackground ( back );
+    ScrollString ( 100, &actors7Msg[0], back, 4*VBLCOUNTER, 50);
+
+    VL_DrawPostPic (W_GetNumForName("trilogo"));
+    DrawNormalSprite(0,(200-128)>>1,W_GetNumForName("allksh4"));
+    PrepareBackground ( back );
+    ScrollString ( 100, &actors8Msg[0], back, 4*VBLCOUNTER, 50);
+
+    VL_DrawPostPic (W_GetNumForName("trilogo"));
+    DrawNormalSprite(0,(200-128)>>1,W_GetNumForName("robogrd1"));
+    PrepareBackground ( back );
+    ScrollString ( 100, &actors9Msg[0], back, 4*VBLCOUNTER, 50);
+
+    VL_DrawPostPic (W_GetNumForName("trilogo"));
+    DrawNormalSprite(0,(200-128)>>1,W_GetNumForName("darshoo1"));
+    PrepareBackground ( back );
+    ScrollString ( 100, &actors10Msg[0], back, 4*VBLCOUNTER, 50);
+
+    VL_DrawPostPic (W_GetNumForName("trilogo"));
+    DrawNormalSprite(0,(200-128)>>1,W_GetNumForName("hdope8"));
+    PrepareBackground ( back );
+    ScrollString ( 100, &actors11Msg[0], back, 4*VBLCOUNTER, 50);
+
+    VL_DrawPostPic (W_GetNumForName("trilogo"));
+    DrawNormalSprite(0,(200-128)>>1,W_GetNumForName("rbody101"));
+    DrawNormalSprite(0,(200-128)>>1,W_GetNumForName("rhead101"));
+    DrawNormalSprite(0,(200-128)>>1,W_GetNumForName("rsw01"));
+    PrepareBackground ( back );
+    ScrollString ( 100, &actors12Msg[0], back, 4*VBLCOUNTER, 50);
+
+    VL_DrawPostPic (W_GetNumForName("trilogo"));
+    DrawNormalSprite(0,(200-128)>>1,W_GetNumForName("tomfly21"));
+    PrepareBackground ( back );
+    ScrollString ( 100, &actors13Msg[0], back, 4*VBLCOUNTER, 50);
+
+    VL_DrawPostPic (W_GetNumForName("trilogo"));
+    PrepareBackground ( back );
+    CurrentFont = (font_t *)W_CacheLumpName ("newfnt1", PU_STATIC, Cvt_font_t, 1);
+    ScrollString ( 100, &playersCutMsg[0], back, 4*VBLCOUNTER, 40);
+
+    CurrentFont = smallfont;
+    VL_DrawPostPic (W_GetNumForName("trilogo"));
+    DrawNormalSprite(0,(200-128)>>1,W_GetNumForName("cutmark"));
+    PrepareBackground ( back );
+    ScrollString ( 100, &cut1Msg[0], back, 4*VBLCOUNTER, 50);
+
+    VL_DrawPostPic (W_GetNumForName("trilogo"));
+    DrawNormalSprite(0,(200-128)>>1,W_GetNumForName("cutpat"));
+    PrepareBackground ( back );
+    ScrollString ( 100, &cut2Msg[0], back, 4*VBLCOUNTER, 50);
+
+    VL_DrawPostPic (W_GetNumForName("trilogo"));
+    DrawNormalSprite(0,(200-128)>>1,W_GetNumForName("cutmari"));
+    PrepareBackground ( back );
+    ScrollString ( 100, &cut3Msg[0], back, 4*VBLCOUNTER, 50);
+
+    VL_DrawPostPic (W_GetNumForName("trilogo"));
+    DrawNormalSprite(0,(200-128)>>1,W_GetNumForName("cutann"));
+    PrepareBackground ( back );
+    ScrollString ( 100, &cut4Msg[0], back, 4*VBLCOUNTER, 50);
+
+    VL_DrawPostPic (W_GetNumForName("trilogo"));
+    DrawNormalSprite(0,(200-128)>>1,W_GetNumForName("cutwill"));
+    PrepareBackground ( back );
+    ScrollString ( 100, &cut5Msg[0], back, 4*VBLCOUNTER, 50);
+
+    VL_DrawPostPic (W_GetNumForName("trilogo"));
+    DrawNormalSprite(0,(200-128)>>1,W_GetNumForName("cutstev"));
+    PrepareBackground ( back );
+    ScrollString ( 100, &cut6Msg[0], back, 4*VBLCOUNTER, 50);
+
+    VL_FadeOut (0, 255, 0, 0, 0, 80);
+
+    DrawNormalSprite(0,0,W_GetNumForName("grouppic"));
+    PrepareBackground ( back );
+    FlipPage();
+    VL_FadeIn (0, 255, origpal, 30);
+    ScrollString ( 175, &dipMsg[0], back, 4*VBLCOUNTER, 140);
+    VL_FadeOut (0, 255, 0, 0, 0, 80);
+
+    W_CacheLumpName ("newfnt1", PU_CACHE, Cvt_font_t, 1);
+    SafeFree(back);
+}
+
+void DoEndCinematic ( void )
+{
+    EnableScreenStretch();
+
+    viewwidth = 320;//MAXSCREENWIDTH;
+    viewheight = 200;//MAXSCREENHEIGHT;
+    MU_FadeOut ( 1000 );
+    MU_StopSong ();
+
+    ShowFinalDoor();
+    ShowTransmitter ();
+    ShowFinalFire();
+    DoTransmitterExplosion();
+    MU_StartSong(song_youwin);
+    DoBurningCastle ();
+    DoSanNicolas();
+    if (DestroyedAllEggs () == true)
+    {
+        PlayerQuestionScreen();
+        DIPCredits();
+        DoYouWin();
+        if (LastScan !=0)
+        {
+            IN_UpdateKeyboard();
+            return;
+        }
+        DoFinalEnd();
+    }
+    else
+    {
+        MU_StartSong(song_gameover);
+        DoFailedScreen();
+        DestroyEarth();
+        DoTryAgainScreen ();
+        playstate=ex_warped;
+        gamestate.mapon=33;
+    }
+    IN_UpdateKeyboard();
+}
+
+void DoInBetweenCinematic (int yoffset, int lump, int delay, char * string )
+{
+    int width,height;
+    int x,y;
+
+    VL_FadeOut (0, 255, 0, 0, 0, 20);
+    VL_ClearBuffer (bufferofs, 0);
+    DrawNormalSprite(0,yoffset,lump);
+
+    CurrentFont=smallfont;
+    US_MeasureStr (&width, &height, "%s", string);
+    x=(320-width)>>1;
+    y=190-height;
+    US_ClippedPrint (x, y, string);
+    FlipPage();
+    VL_FadeIn(0,255,origpal,20);
+    I_Delay (delay);
+    VL_FadeOut (0, 255, 0, 0, 0, 20);
+}
+#endif
+
+
+//******************************************************************************
+//
+// DoCreditScreen
+//
+//******************************************************************************
+
+#define NUMFIRSTCREDITMESSAGES 22
+#define NUMSECONDCREDITMESSAGES 28
+
+typedef struct CreditType {
+    char  text[80];
+    byte  font;
+    byte  endy;
+} CreditType;
+
+CreditType FirstCredits[NUMFIRSTCREDITMESSAGES] =
+{
+    {"Rise of the Triad Credits",0,0},
+    {"COPYRIGHT (c) 1995 Apogee Software Ltd.",1,10},
+    {"Apogee's Developers of Incredible Power",1,20},
+    {"Creative Director",0,30},
+    {"Tom Hall",1,40},
+    {"Programmers",0,50},
+    {"Mark Dochtermann  William Scarboro",1,60},
+    {"Jim Dose'  Nolan Martin",1,66},
+    {"Artists",0,76},
+    {"Stephen Hornback  Chuck Jones",1,86},
+    {"Susan Singer  Tim Neveu",1,92},
+    {"James Storey  Cygnus Multimedia",1,98},
+    {"Level Designers",0,108},
+    {"Joseph Selinske  Tom Hall",1,118},
+    {"Marianna Vayntrub  Joe Siegler",1,124},
+    {"Musicians",0,134},
+    {"Lee Jackson  Robert Prince",1,144},
+    {"Uniforms",0,154},
+    {"D.J. Goodwin  Matt McKinney",1,164},
+    {"Special Thanks",0,174},
+    {"John Carmack  Ken Silverman  Gregor Punchatz",1,184},
+};
+
+CreditType SecondCredits[NUMSECONDCREDITMESSAGES] =
+{
+    {"Rise of the Triad Credits",0,0},
+    {"COPYRIGHT (c) 1995 Apogee Software Ltd.",1,10},
+    {"Executive Producers",0,20},
+    {"George Broussard  Scott Miller",1,30},
+    {"Manual Design",0,40},
+    {"Robert Atkins",1,50},
+    {"Beta Testers",0,60},
+    {"Steven Blackburn",1,70},
+    {"Todd Aubin  Mike Bartelt",1,76},
+    {"Wayne Benner  Neil Bonner",1,82},
+    {"Glenn Brensinger  Douglas Brewer",1,88},
+    {"David Butler  Daniel Creeron",1,94},
+    {"Scott Darling  Jason Ewasiuk",1,100},
+    {"Craig Hamilton  Ken Heckbert",1,106},
+    {"Terry Herrin  Greg Hively",1,112},
+    {"John Howard  Douglas Howell",1,118},
+    {"Dennis Kurek  Hank Leukart",1,124},
+    {"Jim Lietzan  Ken Mayer",1,130},
+    {"Wayne Millard  Penny Plant",1,136},
+    {"Brian Prinner  Jeff Rausch",1,142},
+    {"Kelly Rogers  Neil Rubenking",1,148},
+    {"Steven Salter  Chris White",1,154},
+    {"Special Thanks",0,162},
+    {"Apogee Technical Support  Pau Suet Ying",1,172},
+    {"Anthony, Zach, Rajan, Miki, Loki",1,178},
+    {"Nathan, Petro, Tim, Jake, MacKay",1,184},
+    {"Loyal, Ric, Teller, Amano",1,190},
+};
+
+void DrawPreviousCredits ( int num, CreditType * Credits )
+{
+    int width;
+    int height;
+    int x,y;
+    int i;
+
+    for(i=0; i<num; i++)
+    {
+        if (Credits[i].font==0)
+            CurrentFont=smallfont;
+        else
+            CurrentFont=tinyfont;
+        US_MeasureStr (&width, &height, "%s", &(Credits[i].text[0]));
+        x=(320-width)>>1;
+        y=Credits[i].endy;
+        US_ClippedPrint (x, y+4, &Credits[i].text[0]);
+    }
+}
+
+#define CREDITSTARTY 220
+//******************************************************************************
+//
+// WarpCreditString
+//
+//******************************************************************************
+
+extern boolean dopefish;
+void WarpCreditString ( int time, byte * back, int num, CreditType * Credits)
+{
+    int dy;
+    int cy;
+    int x;
+    int y;
+    int width;
+    int height;
+    boolean soundplayed;
+
+
+    LastScan = 0;
+
+    if (Credits[num].font==0)
+        CurrentFont=smallfont;
+    else
+        CurrentFont=tinyfont;
+    US_MeasureStr (&width, &height, "%s", &(Credits[num].text[0]));
+
+    x=(320-width)>>1;
+    y=Credits[num].endy;
+    dy=((y-CREDITSTARTY)<<16)/time;
+    cy=CREDITSTARTY<<16;
+
+    CalcTics();
+
+    soundplayed=false;
+
+    while (time>0)
+    {
+        DrawBackground ( back );
+        DrawPreviousCredits ( num, Credits );
+        if (Credits[num].font==0)
+            CurrentFont=smallfont;
+        else
+            CurrentFont=tinyfont;
+        US_ClippedPrint (x, (cy>>16)+4, &Credits[num].text[0]);
+        if ( ((cy>>16)<196) && (soundplayed==false))
+        {
+            if ((dopefish==true) && (SD_Started==true))
+            {
+                int snd;
+
+                do
+                {
+                    snd=(RandomNumber("DoCredits",0)+RandomNumber("DoCredits",0))%MAXSOUNDS;
+                }
+                while (SD_SoundOkay ( snd ) == false);
+                SD_Play ( snd );
+            }
+            else
+            {
+//            SD_Play ( SD_BAZOOKAFIRESND );
+#if (SHAREWARE == 0)
+                SD_Play ( SD_BAZOOKAFIRESND + (RandomNumber("DoCredits",1)%13) );
+#else
+                SD_Play ( SD_BAZOOKAFIRESND + (RandomNumber("DoCredits",1)%6) );
+#endif
+                soundplayed=true;
+            }
+        }
+        FlipPage();
+        CalcTics();
+        cy+=dy*tics;
+        time-=tics;
+        if (LastScan != 0)
+            break;
+    }
+}
+
+void DoCreditScreen ( void )
+{
+    int trilogo;
+    int time;
+    byte * bkgnd;
+    font_t * oldfont;
+    int i;
+    EnableScreenStretch();
+    viewwidth = 320;//MAXSCREENWIDTH;
+    viewheight = 200;//MAXSCREENHEIGHT;
+
+    bkgnd=SafeMalloc(800*linewidth);
+
+    trilogo=W_GetNumForName("trilogo");
+    VL_DrawPostPic (trilogo);
+//  SetTextMode (  );
+
+    PrepareBackground ( bkgnd );
+
+    oldfont=CurrentFont;
+
+    for(i=0; i<NUMFIRSTCREDITMESSAGES; i++)
+    {
+        time = (CREDITSTARTY - FirstCredits[i].endy)*(VBLCOUNTER*1)/CREDITSTARTY;
+//      time = VBLCOUNTER;
+        WarpCreditString ( time, bkgnd, i, FirstCredits );
+        IN_PumpEvents();
+//      SD_Play ( SD_EXPLODESND );
+        if (LastScan !=0)
+            break;
+    }
+    i=NUMFIRSTCREDITMESSAGES;
+    DrawBackground ( bkgnd );
+    DrawPreviousCredits ( i, FirstCredits );
+    FlipPage();
+    IN_PumpEvents();
+
+    I_Delay(40);
+
+    for(i=0; i<NUMSECONDCREDITMESSAGES; i++)
+    {
+        time = (CREDITSTARTY - SecondCredits[i].endy)*(VBLCOUNTER/2)/CREDITSTARTY;
+//      time = VBLCOUNTER;
+        WarpCreditString ( time, bkgnd, i, SecondCredits );
+        IN_PumpEvents();
+//      SD_Play ( SD_EXPLODESND );
+        if (LastScan !=0)
+            break;
+    }
+    i=NUMSECONDCREDITMESSAGES;
+    DrawBackground ( bkgnd );
+    DrawPreviousCredits ( i, SecondCredits );
+    FlipPage();
+    IN_PumpEvents();
+
+    I_Delay(40);
+    MenuFadeOut();
+    VL_ClearVideo (0);
+
+    SafeFree(bkgnd);
+    CurrentFont=oldfont;
+}
+
+
+#define NUMSTORYLINES 16
+
+char * MicroStory[NUMSTORYLINES] =
+{
+    "You are a member of HUNT, the",
+    "High-Risk United Nations Taskforce.",
+    "Stranded on an island in the",
+    "Pacific, you must battle a master",
+    "of pyrotechnics, hundreds of",
+    "members of a death cult, and their",
+    "leader, El Oscuro.",
+    "\0",
+    "You must reach the transmitter",
+    "that is signalling the systematic",
+    "destruction of Los Angeles.",
+    "\0",
+    "If you fail, millions will die",
+    "and you will be tortured.",
+    "\0",
+    "So, you know, don't fail."
+};
+
+void DoMicroStoryScreen ( void )
+{
+    pic_t * pic;
+    int x,y;
+    int i;
+
+    VL_FadeOut (0, 255, 0, 0, 0, 20);
+
+    pic=(pic_t *)W_CacheLumpName("mmbk",PU_CACHE,Cvt_pic_t,1);
+    VWB_DrawPic (0, 0, pic);
+    CheckHolidays();
+
+    x=15;
+    y=30;
+
+    IFont = ( cfont_t * )W_CacheLumpName( "sifont", PU_CACHE, Cvt_cfont_t, 1);
+    for(i=0; i<NUMSTORYLINES; i++)
+    {
+        DrawIntensityString (x, y, MicroStory[i], 241);
+        y += 9;
+    }
+
+    FlipPage();
+    MenuFadeIn();
+    I_Delay (100);//240
+
+    VL_FadeOut (0, 255, 0, 0, 0, 20);
+}
+
+#ifndef DOS
+
+void  DrawMenuPost (int height, byte * src, byte * buf)
+{
+    int frac = hp_startfrac;
+    while (height--) {
+        *buf = src[frac >> 16];
+
+        buf += linewidth;
+        frac += hp_srcstep;
+    }
+}
+
+void  DrawMapPost (int height, byte * src, byte * buf)
+{
+    int frac = 0;
+    while (height--) {
+        *buf = src[frac >> 16];
+
+        buf += linewidth;
+        frac += hp_srcstep;
+    }
+}
+
+void DrawRotRow(int count, byte * dest, byte * src)
+{
+    unsigned eax, ecx, edx;
+//	unsigned a, b, c,d;
+    byte * srctmp;
+    byte * desttmp;
+
+    ecx = mr_yfrac;
+    edx = mr_xfrac;
+
+    if ((iGLOBAL_SCREENWIDTH == 320)||(iG_masked==true))
+    {
+        while (count--) {
+            eax = edx >> 16;
+            if (eax < 256 && (ecx >> 16) < 512) {
+                eax = (eax << 9) | ((ecx << 7) >> (32-9));
+            } else {
+                eax = 0;
+            }
+
+            *dest++ = src[eax];
+
+            edx += mr_xstep;
+            ecx += mr_ystep;
+        }
+    } else if (iGLOBAL_SCREENWIDTH == 640) {
+        while (count--) {
+            eax = edx >> 16;
+            if (eax < (256*2.0) && (ecx >> 16) < (512*1.8)) {
+                eax = (eax << 10) | ((ecx << 6) >> (32-10));
+            } else {
+                eax = 0;
+            }
+
+            *dest++ = src[eax];
+
+            edx += mr_xstep;
+            ecx += mr_ystep;
+        }
+    } else if (iGLOBAL_SCREENWIDTH == 800) {
+
+
+
+        srctmp = src;
+        desttmp = dest;
+
+        desttmp -= (iGLOBAL_SCREENWIDTH*1);
+
+        ecx = mr_yfrac;
+        edx = mr_xfrac;
+        //count = 800
+//zxcv
+        while (count--) {
+            eax = edx >> 16;//edx=4146069504 eax=63264  edx/eax = 65536->0x10000
+
+            //a=(eax << 9); //=eax*512
+            //a=(eax << 7); //=eax*128
+            //a=512|128; = 640;
+            //SetTextMode (  );
+            //a=(ecx >> 16);//ecx=4102225920 a=62595   ecx/65536 = 62595
+
+            //         Y-dir                    x-dir
+            if (eax < (256*2.5) && (ecx >> 16) < (512*2)) {
+                //eax = (eax << 9) | ((ecx << 7) >> (32-9));
+                eax = (eax << 10) | ((ecx << 6) >> (32-10));
+                /*		eax = (eax * 512*2) ;
+                							//(23)
+                		eax += 	 ((ecx ) >> (32-9));//ecx=196608
+                		*/
+            } else {
+                eax = 0;
+
+
+            }
+            //desttmp -= centeroffset;
+            *desttmp++ = srctmp[eax];
+            //*desttmp++ = srctmp[eax];
+
+            edx += mr_xstep;
+            ecx += mr_ystep;
+        }
+
+    }
+}
+
+void DrawMaskedRotRow(int count, byte * dest, byte * src)
+{
+    unsigned eax;
+    unsigned xfrac, yfrac;
+
+    xfrac = mr_xfrac;
+    yfrac = mr_yfrac;
+
+    while (count--) {
+        eax = xfrac >> 16;
+        if (eax < 256 && (yfrac >> 16) < 512) {
+            eax = (eax << 9) | ((yfrac << 7) >> (32-9));
+        } else {
+            eax = 0;
+        }
+
+        if (src[eax] != 0xff) *dest = src[eax];
+        dest++;
+
+        xfrac += mr_xstep;
+        yfrac += mr_ystep;
+    }
+}
+
+void DrawSkyPost (byte * buf, byte * src, int height)
+{
+#if 0
+// bna fix for missing sky by high res eg 800x600
+// when sky is >400 (max skyheight) then reverse mouintain to missing spot
+// there should be 200 line of mouintain (400+200) = 600 height lines
+// not the best solution but what it works
+
+    if (iGLOBAL_SCREENWIDTH > 320) {
+        // bna section start
+        //int n = 0;
+        int orgh = 0;//height;
+        if (height > 400) {
+            orgh=height;
+        }
+
+        while (height--) {
+            if ((orgh > 0)&&( height<(orgh-400))) {
+                src-=2;
+                *buf = shadingtable[*src];
+            } else {
+
+                *buf = shadingtable[*src];
+            }
+            buf += linewidth;
+            src++;
+        }
+        // bna section end
+    }
+    else
+#endif
+    {
+        int i = 0;
+        const byte *orig_src = src;
+        // org code
+        while (height--) {
+            *buf = shadingtable[*src];
+
+            buf += linewidth;
+            src = orig_src + (++i*200/iGLOBAL_SCREENHEIGHT);
+        }
+        //
+    }
+
+    /*
+    int lw = linewidth * 2;
+    int h  = height;
+
+    while (h--) {
+    	*(buf) = shadingtable[*src];
+    	buf += lw;
+    	*(buf) = shadingtable[*src];
+    	buf += lw;
+
+    	//buf += lw;
+    	src++;
+
+    }*/
+}
+
+#define CEILINGCOLOR 24 //default color when no sky or floor
+#define FLOORCOLOR 32
+
+void RefreshClear (void)
+{
+    int start, base;
+
+    memset(spotvis, 0, sizeof(spotvis));
+
+    if (fandc) {
+        return;
+    }
+
+    start = min(centery, viewheight);
+
+    if (start > 0) {
+        VL_Bar(0, 0, iGLOBAL_SCREENHEIGHT, start, CEILINGCOLOR);
+    } else {
+        start = 0;
+    }
+
+    base = start;
+
+    start = min(viewheight-start, viewheight);
+    if (start > 0) {
+        VL_Bar(0, base, iGLOBAL_SCREENHEIGHT, start, FLOORCOLOR);
+    }
+}
+
+#endif
+
+#if 0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+typedef struct {
+    int   x;
+    int   y;
+    int   angle;
+    int   speed;
+    int   color;
+    int   endx;
+    int   endy;
+    int   plane;
+    int   time;
+} ParticleType;
+
+#define NUMPARTICLES 300
+#define PARTICLETHINKTIME 5
+#define Fix(a)        (a &= (FINEANGLES-1))
+ParticleType * Particle;
+int numparticles;
+
+//******************************************************************************
+//
+// InitializeParticles
+//
+//******************************************************************************
+
+void InitializeParticles (void)
+{
+    int i;
+    ParticleType * part;
+
+    Particle=(ParticleType *)SafeMalloc ( sizeof(ParticleType) * numparticles );
+    memset ( Particle, 0, sizeof(ParticleType) * numparticles );
+
+    for (i=0; i<numparticles; i++)
+    {
+        part=&Particle[i];
+        part->x=((RandomNumber("hello",0)*RandomNumber("hello",0))%viewwidth)<<16;
+        part->y=((RandomNumber("hello",0)*RandomNumber("hello",0))%viewheight)<<16;
+//      part->x=(((RandomNumber("hello",0)*RandomNumber("hello",0))%(viewwidth-40)+20)<<16);
+//      part->y=(((RandomNumber("hello",0)*RandomNumber("hello",0))%(viewheight-40)+20)<<16);
+        part->angle=(RandomNumber("hello",0)*RandomNumber("hello",0))%FINEANGLES;
+//      part->speed=(RandomNumber("hello",0)%2)<<16;
+        part->speed=(1<<16)-1;
+        part->color=RandomNumber("hello",0);
+        part->endx=-1;
+        part->endy=-1;
+        part->plane=(part->x>>16)&3;
+        part->time=(RandomNumber("",0)%PARTICLETHINKTIME)+1;
+//      part->color=255;
+    }
+}
+
+//******************************************************************************
+//
+// ShutdownParticles
+//
+//******************************************************************************
+
+void ShutdownParticles (void)
+{
+    SafeFree(Particle);
+}
+
+
+void AdjustParticleAngle(int maxadjust, int *currangle,int targetangle)
+{
+    int dangle,i,magangle;
+
+    for(i=0; i<maxadjust; i++)
+    {
+        dangle = *currangle - targetangle;
+
+        if (dangle)
+        {
+            magangle = abs(dangle);
+            if (magangle > (ANGLES/2))
+            {
+                if (dangle > 0)
+                    (*currangle) ++;
+                else
+                    (*currangle) --;
+            }
+            else
+            {
+                if (dangle > 0)
+                    (*currangle) --;
+                else
+                    (*currangle) ++;
+            }
+            Fix(*currangle);
+        }
+    }
+}
+
+//******************************************************************************
+//
+// UpdateParticles
+//
+//******************************************************************************
+
+//#define MAXADJUST (FINEANGLES/40)
+#define MAXADJUST (FINEANGLES/20)
+void UpdateParticles (int type)
+{
+    int i;
+    int dx,dy;
+    ParticleType * target;
+    ParticleType * part;
+
+    if (type==0)
+    {
+        for (i=0; i<numparticles-1; i++)
+        {
+            int angle;
+
+            part=&Particle[i];
+//         target=&Particle[numparticles-1];
+//         target=&Particle[i+1];
+            target=&Particle[(RandomNumber("",0)*RandomNumber("",0))%numparticles];
+            part->x+=-FixedMul (part->speed, costable[part->angle]);
+            part->y+= FixedMul (part->speed, sintable[part->angle]);
+            part->plane=(part->x>>16)&3;
+
+            dx = part->x - target->x;
+            dy = target->y - part->y;
+            if (dx && dy)
+            {
+                angle = atan2_appx(dx,dy);
+                AdjustParticleAngle(MAXADJUST,&(part->angle),angle);
+            }
+        }
+        part=&Particle[numparticles-1];
+        part->x+=-FixedMul (part->speed, costable[part->angle]);
+        part->y+= FixedMul (part->speed, sintable[part->angle]);
+        part->plane=(part->x>>16)&3;
+
+        dx=part->x>>16;
+        dy=part->y>>16;
+
+        if ( (dx<20) || (dx>(viewwidth-20)) )
+        {
+            if ( part->angle < (FINEANGLES/2) )
+            {
+                part->angle=FINEANGLES/2-part->angle;
+                Fix(part->angle);
+            }
+            else
+            {
+                part->angle=FINEANGLES-part->angle;
+                Fix(part->angle);
+            }
+        }
+        if ( (dy<20) || (dy>(viewheight-20)) )
+        {
+            part->angle=FINEANGLES-part->angle;
+            Fix(part->angle);
+        }
+    }
+    else
+    {
+        for (i=0; i<numparticles; i++)
+        {
+            int angle;
+
+            part=&Particle[i];
+            if ((part->x>>16)!=part->endx)
+                part->x+=-FixedMul (part->speed, costable[part->angle]);
+            else
+                part->x=part->endx<<16;
+            if ((part->y>>16)!=part->endy)
+                part->y+= FixedMul (part->speed, sintable[part->angle]);
+            else
+                part->y=part->endy<<16;
+            part->plane=(part->x>>16)&3;
+
+            part->time--;
+            if (part->time==0)
+            {
+                part->time=PARTICLETHINKTIME;
+                dx = part->x - (part->endx<<16);
+                dy = (part->endy<<16) - part->y;
+                if (dx && dy)
+                {
+                    angle = atan2_appx(dx,dy);
+                    AdjustParticleAngle(MAXADJUST,&(part->angle),angle);
+                }
+            }
+        }
+    }
+}
+
+//******************************************************************************
+//
+// DrawParticles
+//
+//******************************************************************************
+
+void DrawParticles (void)
+{
+    int i;
+    int dx,dy;
+    int plane;
+    ParticleType * part;
+
+    VL_ClearBuffer (bufferofs, 0);
+#ifdef DOS
+    for (plane=0; plane<4; plane++)
+#endif
+    {
+        VGAWRITEMAP(plane);
+        for (i=0; i<numparticles; i++)
+        {
+            part=&Particle[i];
+            if (part->plane!=plane)
+                continue;
+            dx=part->x>>16;
+            dy=part->y>>16;
+            if (dx<0) dx=0;
+            if (dx>=viewwidth) dx=viewwidth-1;
+            if (dy<0) dy=0;
+            if (dy>=viewheight) dy=viewheight-1;
+#ifdef DOS
+            *( (byte *) bufferofs + (dx>>2) + ylookup[dy] ) = part->color;
+#else
+            *( (byte *) bufferofs + dx + ylookup[dy] ) = part->color;
+#endif
+        }
+    }
+}
+
+void DrawParticleTemplate (void)
+{
+    byte pal[768];
+
+    viewwidth=320;
+    viewheight=200;
+    memcpy(&pal[0],W_CacheLumpName("ap_pal",PU_CACHE),768);
+    VL_NormalizePalette(&pal[0]);
+    SwitchPalette(&pal[0],35);
+    VL_ClearBuffer (bufferofs, 255);
+    DrawNormalSprite (0, 0, W_GetNumForName("ap_titl"));
+}
+
+void DrawAlternateParticleTemplate (void)
+{
+    viewwidth=320;
+    viewheight=200;
+    VL_ClearBuffer (bufferofs, 255);
+    DrawNormalSprite (0, 0, W_GetNumForName("LIFE_C1"));
+}
+
+int CountParticles (void)
+{
+    int plane,a,b;
+    int count;
+
+    count=0;
+#ifdef DOS
+    for (plane=0; plane<4; plane++)
+#endif
+    {
+        VGAREADMAP(plane);
+        for (a=0; a<200; a++)
+        {
+#ifdef DOS
+            for (b=0; b<80; b++)
+#else
+            for (b=0; b<320; b++)
+#endif
+            {
+                if (*((byte *)bufferofs+(a*linewidth)+b)!=255)
+                    count++;
+            }
+        }
+    }
+    return count;
+}
+
+void AssignParticles (void)
+{
+    int plane,a,b;
+    byte pixel;
+    ParticleType * part;
+
+    part=&Particle[0];
+
+#ifdef DOS
+    for (plane=0; plane<4; plane++)
+#endif
+    {
+        VGAREADMAP(plane);
+        for (a=0; a<200; a++)
+        {
+#ifdef DOS
+            for (b=0; b<80; b++)
+#else
+            for (b=0; b<320; b++)
+#endif
+            {
+                pixel = *((byte *)bufferofs+(a*linewidth)+b);
+                if (pixel!=255)
+                {
+#ifdef DOS
+                    part->endx=plane+(b<<2);
+#else
+                    part->endx=b;
+#endif
+                    part->endy=a;
+                    part->color=pixel;
+                    part++;
+                }
+            }
+        }
+    }
+}
+
+//******************************************************************************
+//
+// ParticleIntro
+//
+//******************************************************************************
+
+void ParticleIntro (void)
+{
+    int i,j;
+
+
+    SetViewSize (MAXVIEWSIZES-1);
+    numparticles=NUMPARTICLES;
+    DrawAlternateParticleTemplate ();
+//   DrawParticleTemplate ();
+    numparticles=CountParticles ();
+    InitializeParticles ();
+    AssignParticles();
+//   numparticles>>=1;
+
+    CalcTics();
+    CalcTics();
+    LastScan=0;
+    for (i=0; i<VBLCOUNTER*15; i+=tics)
+    {
+        DrawParticles();
+        FlipPage();
+        for (j=0; j<tics; j++)
+        {
+            UpdateParticles(0);
+        }
+        CalcTics();
+        if ((LastScan) || IN_GetMouseButtons())
+            break;;
+    }
+    LastScan=0;
+    for (i=0; i<VBLCOUNTER*15; i+=tics)
+    {
+        DrawParticles();
+        FlipPage();
+        for (j=0; j<tics; j++)
+        {
+            UpdateParticles(1);
+        }
+        CalcTics();
+        if ((LastScan) || IN_GetMouseButtons())
+            break;;
+    }
+    ShutdownParticles ();
+}
+
+#endif
+
--- /dev/null
+++ b/rott/rt_draw.h
@@ -1,0 +1,127 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+#ifndef _rt_draw_public
+#define _rt_draw_public
+
+//***************************************************************************
+//
+//    RT_DRAW.C - Draw-o-rama
+//
+//***************************************************************************
+
+
+#define MAXVISIBLE              256
+
+extern int whereami;
+
+extern byte * shadingtable;            // Shading table for DrawPost
+
+typedef struct
+{
+    int viewheight;
+    int viewx;
+    int shapenum;
+    int altshapenum;
+    int shapesize;
+    int x1,x2,h1,h2;
+    int texturestart;
+    int textureend;
+    byte * colormap;
+
+} visobj_t;
+
+
+extern  word             tilemap[MAPSIZE][MAPSIZE];    // wall values only
+extern  byte             spotvis[MAPSIZE][MAPSIZE];
+
+extern int tics;
+extern int wstart;
+extern int fandc;
+
+//
+// math tables
+//
+extern short    tantable[FINEANGLES];
+extern fixed    sintable[FINEANGLES+FINEANGLEQUAD+1];
+extern fixed    *costable;
+
+//
+// refresh variables
+//
+
+extern fixed   viewx,viewy;             // the focal point
+extern int     viewangle;
+extern fixed   viewsin,viewcos;
+
+//
+// ray tracing variables
+//
+
+extern visobj_t vislist[MAXVISIBLE];
+extern visobj_t *visptr,*visstep,*farthest;
+
+extern long     xintercept,yintercept;
+extern byte     mapseen[MAPSIZE][MAPSIZE];
+extern unsigned long * lights;
+
+extern int hp_startfrac;
+extern int hp_srcstep;
+extern int levelheight;
+extern int maxheight;
+extern int nominalheight;
+
+extern int actortime;
+extern int drawtime;
+extern int c_startx;
+extern int c_starty;
+
+extern const int dirangle8[9];
+extern const int dirangle16[16];
+extern  int firstcoloffset;
+
+//=========================== macros =============================
+
+#define LightSourceAt(x,y)    (*(lights+((x)<<7)+(y)))
+#define SetLight(x,y,level)   (LightSourceAt((x),(y))|=(unsigned long)(level))
+
+//=========================== functions =============================
+
+void  BuildTables (void);
+void  CalcTics (void);
+void  ThreeDRefresh (void);
+void  FlipPage ( void );
+void  TurnShakeOff( void );
+void  AdaptDetail ( void );
+int   CalcHeight (void);
+void  DoLoadGameSequence( void );
+void RotateBuffer (int startangle, int endangle, int startscale, int endscale, int time);
+void ApogeeTitle (void);
+void DopefishTitle (void);
+void RotationFun (void);
+void GetRainBoundingBox (int * xmin, int * xmax, int * ymin, int * ymax);
+void StartupScreenSaver ( void );
+void ShutdownScreenSaver ( void );
+void UpdateScreenSaver ( void );
+void DoEndCinematic ( void );
+void DoCreditScreen ( void );
+void DoMicroStoryScreen ( void );
+void DoInBetweenCinematic (int yoffset, int lump, int delay, char * string );
+
+#endif
--- /dev/null
+++ b/rott/rt_err.c
@@ -1,0 +1,336 @@
+const unsigned char ROTT_ERR[4000] = {
+    0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04,
+    0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04,
+    0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04,
+    0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04,
+    0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04,
+    0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04,
+    0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04,
+    0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04,
+    0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04,
+    0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04,
+    0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04,
+    0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04,
+    0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04,
+    0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04,
+    0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC9, 0x1B, 0xCD, 0x1B, 0xB5, 0x1B,
+    0x1E, 0x9C, 0x52, 0x1E, 0x69, 0x1E, 0x73, 0x1E, 0x65, 0x1E, 0x20, 0x1E,
+    0x6F, 0x1E, 0x66, 0x1E, 0x20, 0x1E, 0x74, 0x1E, 0x68, 0x1E, 0x65, 0x1E,
+    0x20, 0x1E, 0x54, 0x1E, 0x72, 0x1E, 0x69, 0x1E, 0x61, 0x1E, 0x64, 0x1E,
+    0x20, 0x1E, 0x45, 0x1E, 0x72, 0x1E, 0x72, 0x1E, 0x6F, 0x1E, 0x72, 0x1E,
+    0x21, 0x1E, 0x1E, 0x9C, 0xC6, 0x1B, 0xCD, 0x1B, 0xCD, 0x1B, 0xCD, 0x1B,
+    0xCD, 0x1B, 0xCD, 0x1B, 0xCD, 0x1B, 0xCD, 0x1B, 0xCD, 0x1B, 0xCD, 0x1B,
+    0xCD, 0x1B, 0xCD, 0x1B, 0xCD, 0x1B, 0xCD, 0x1B, 0xCD, 0x1B, 0xCD, 0x1B,
+    0xCD, 0x1B, 0xCD, 0x1B, 0xCD, 0x1B, 0xCD, 0x1B, 0xCD, 0x1B, 0xCD, 0x1B,
+    0xCD, 0x1B, 0xCD, 0x1B, 0xCD, 0x1B, 0xCD, 0x1B, 0xCD, 0x1B, 0xCD, 0x1B,
+    0xB5, 0x1B, 0x76, 0x19, 0x53, 0x19, 0x31, 0x19, 0x2E, 0x19, 0x30, 0x19,
+    0xC6, 0x1B, 0xCD, 0x1B, 0xBB, 0x1B, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04,
+    0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04,
+    0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xBA, 0x1B,
+    0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B,
+    0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B,
+    0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B,
+    0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B,
+    0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B,
+    0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B,
+    0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B,
+    0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B,
+    0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B,
+    0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B,
+    0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0xBA, 0x1B, 0xC4, 0x04,
+    0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04,
+    0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04,
+    0xC4, 0x04, 0xBA, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B,
+    0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B,
+    0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B,
+    0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B,
+    0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B,
+    0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B,
+    0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B,
+    0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B,
+    0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B,
+    0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B,
+    0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B,
+    0xBA, 0x1B, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04,
+    0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04,
+    0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xBA, 0x1B, 0x20, 0x1B, 0x50, 0x1B,
+    0x6C, 0x1B, 0x65, 0x1B, 0x61, 0x1B, 0x73, 0x1B, 0x65, 0x1B, 0x20, 0x1B,
+    0x72, 0x1B, 0x75, 0x1B, 0x6E, 0x1B, 0x20, 0x1B, 0x52, 0x1B, 0x4F, 0x1B,
+    0x54, 0x1B, 0x54, 0x1B, 0x48, 0x1B, 0x45, 0x1B, 0x4C, 0x1B, 0x50, 0x1B,
+    0x2E, 0x1B, 0x45, 0x1B, 0x58, 0x1B, 0x45, 0x1B, 0x20, 0x1B, 0x66, 0x1B,
+    0x6F, 0x1B, 0x72, 0x1B, 0x20, 0x1B, 0x6D, 0x1B, 0x6F, 0x1B, 0x72, 0x1B,
+    0x65, 0x1B, 0x2C, 0x1B, 0x20, 0x1B, 0x77, 0x1B, 0x65, 0x1B, 0x6C, 0x1B,
+    0x6C, 0x1B, 0x2C, 0x1B, 0x20, 0x1B, 0x68, 0x1F, 0x65, 0x1F, 0x6C, 0x1F,
+    0x70, 0x1F, 0x66, 0x1F, 0x75, 0x1F, 0x6C, 0x1F, 0x20, 0x1B, 0x69, 0x1B,
+    0x6E, 0x1B, 0x66, 0x1B, 0x6F, 0x1B, 0x72, 0x1B, 0x6D, 0x1B, 0x61, 0x1B,
+    0x74, 0x1B, 0x69, 0x1B, 0x6F, 0x1B, 0x6E, 0x1B, 0x2E, 0x1B, 0x20, 0x1B,
+    0x20, 0x1B, 0x20, 0x1B, 0xBA, 0x1B, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04,
+    0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04,
+    0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC8, 0x1B,
+    0xCD, 0x1B, 0xCD, 0x1B, 0xCD, 0x1B, 0xCD, 0x1B, 0xCD, 0x1B, 0xCD, 0x1B,
+    0xCD, 0x1B, 0xCD, 0x1B, 0xCD, 0x1B, 0xCD, 0x1B, 0xCD, 0x1B, 0xCD, 0x1B,
+    0xCD, 0x1B, 0xCD, 0x1B, 0xCD, 0x1B, 0xCD, 0x1B, 0xCD, 0x1B, 0xCD, 0x1B,
+    0xCD, 0x1B, 0xCD, 0x1B, 0xCD, 0x1B, 0xCD, 0x1B, 0xCD, 0x1B, 0xCD, 0x1B,
+    0xCD, 0x1B, 0xCD, 0x1B, 0xCD, 0x1B, 0xCD, 0x1B, 0xCD, 0x1B, 0xCD, 0x1B,
+    0xCD, 0x1B, 0xCD, 0x1B, 0xCD, 0x1B, 0xCD, 0x1B, 0xCD, 0x1B, 0xCD, 0x1B,
+    0xCD, 0x1B, 0xCD, 0x1B, 0xCD, 0x1B, 0xCD, 0x1B, 0xCD, 0x1B, 0xCD, 0x1B,
+    0xCD, 0x1B, 0xCD, 0x1B, 0xCD, 0x1B, 0xCD, 0x1B, 0xCD, 0x1B, 0xCD, 0x1B,
+    0xCD, 0x1B, 0xCD, 0x1B, 0xCD, 0x1B, 0xCD, 0x1B, 0xCD, 0x1B, 0xCD, 0x1B,
+    0xCD, 0x1B, 0xCD, 0x1B, 0xCD, 0x1B, 0xCD, 0x1B, 0xCD, 0x1B, 0xCD, 0x1B,
+    0xCD, 0x1B, 0xCD, 0x1B, 0xCD, 0x1B, 0xCD, 0x1B, 0xBC, 0x1B, 0xC4, 0x04,
+    0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04,
+    0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04,
+    0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04,
+    0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04,
+    0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04,
+    0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04,
+    0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04,
+    0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04,
+    0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04,
+    0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04,
+    0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04,
+    0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04,
+    0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04,
+    0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04,
+    0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04,
+    0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04,
+    0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04,
+    0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04,
+    0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04,
+    0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04,
+    0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04,
+    0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04,
+    0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04,
+    0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04,
+    0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04,
+    0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04,
+    0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04,
+    0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04,
+    0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC9, 0x1B,
+    0xCD, 0x1B, 0xB5, 0x1B, 0x1E, 0x9C, 0x55, 0x1E, 0x68, 0x1E, 0x2C, 0x1E,
+    0x20, 0x1E, 0x6F, 0x1E, 0x68, 0x1E, 0x2E, 0x1E, 0x20, 0x1E, 0x4D, 0x1E,
+    0x65, 0x1E, 0x6D, 0x1E, 0x6F, 0x1E, 0x72, 0x1E, 0x79, 0x1E, 0x20, 0x1E,
+    0x70, 0x1E, 0x72, 0x1E, 0x6F, 0x1E, 0x62, 0x1E, 0x6C, 0x1E, 0x65, 0x1E,
+    0x6D, 0x1E, 0x73, 0x1E, 0x2E, 0x1E, 0x1E, 0x9C, 0xC6, 0x1B, 0xCD, 0x1B,
+    0xCD, 0x1B, 0xCD, 0x1B, 0xCD, 0x1B, 0xCD, 0x1B, 0xCD, 0x1B, 0xCD, 0x1B,
+    0xCD, 0x1B, 0xCD, 0x1B, 0xCD, 0x1B, 0xCD, 0x1B, 0xCD, 0x1B, 0xCD, 0x1B,
+    0xCD, 0x1B, 0xCD, 0x1B, 0xCD, 0x1B, 0xCD, 0x1B, 0xCD, 0x1B, 0xCD, 0x1B,
+    0xCD, 0x1B, 0xCD, 0x1B, 0xCD, 0x1B, 0xCD, 0x1B, 0xCD, 0x1B, 0xCD, 0x1B,
+    0xCD, 0x1B, 0xCD, 0x1B, 0xB5, 0x1B, 0x76, 0x19, 0x53, 0x19, 0x31, 0x19,
+    0x2E, 0x19, 0x30, 0x19, 0xC6, 0x1B, 0xCD, 0x1B, 0xBB, 0x1B, 0xC4, 0x04,
+    0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04,
+    0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04,
+    0xC4, 0x04, 0xBA, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B,
+    0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B,
+    0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B,
+    0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B,
+    0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B,
+    0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B,
+    0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B,
+    0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B,
+    0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B,
+    0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B,
+    0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B,
+    0xBA, 0x1B, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04,
+    0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04,
+    0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xBA, 0x1B, 0x20, 0x1B, 0x20, 0x1B,
+    0x20, 0x1B, 0x59, 0x1B, 0x6F, 0x1B, 0x75, 0x1B, 0x20, 0x1B, 0x64, 0x1B,
+    0x6F, 0x1B, 0x20, 0x1B, 0x6E, 0x1B, 0x6F, 0x1B, 0x74, 0x1B, 0x20, 0x1B,
+    0x68, 0x1B, 0x61, 0x1B, 0x76, 0x1B, 0x65, 0x1B, 0x20, 0x1B, 0x65, 0x1B,
+    0x6E, 0x1B, 0x6F, 0x1B, 0x75, 0x1B, 0x67, 0x1B, 0x68, 0x1B, 0x20, 0x1B,
+    0x6D, 0x1B, 0x65, 0x1B, 0x6D, 0x1B, 0x6F, 0x1B, 0x72, 0x1B, 0x79, 0x1B,
+    0x20, 0x1B, 0x74, 0x1B, 0x6F, 0x1B, 0x20, 0x1B, 0x72, 0x1B, 0x75, 0x1B,
+    0x6E, 0x1B, 0x20, 0x1B, 0x52, 0x1F, 0x69, 0x1F, 0x73, 0x1F, 0x65, 0x1F,
+    0x20, 0x1F, 0x6F, 0x1F, 0x66, 0x1F, 0x20, 0x1F, 0x74, 0x1F, 0x68, 0x1F,
+    0x65, 0x1F, 0x20, 0x1F, 0x54, 0x1F, 0x72, 0x1F, 0x69, 0x1F, 0x61, 0x1F,
+    0x64, 0x1F, 0x2E, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B,
+    0x20, 0x1B, 0x20, 0x1B, 0xBA, 0x1B, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04,
+    0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04,
+    0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xBA, 0x1B,
+    0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x53, 0x1B, 0x6F, 0x1B, 0x6D, 0x1B,
+    0x65, 0x1B, 0x20, 0x1B, 0x74, 0x1B, 0x68, 0x1B, 0x69, 0x1B, 0x6E, 0x1B,
+    0x67, 0x1B, 0x73, 0x1B, 0x20, 0x1B, 0x79, 0x1B, 0x6F, 0x1B, 0x75, 0x1B,
+    0x20, 0x1B, 0x6D, 0x1B, 0x69, 0x1B, 0x67, 0x1B, 0x68, 0x1B, 0x74, 0x1B,
+    0x20, 0x1B, 0x74, 0x1B, 0x72, 0x1B, 0x79, 0x1B, 0x20, 0x1B, 0x74, 0x1B,
+    0x6F, 0x1B, 0x20, 0x1B, 0x63, 0x1B, 0x6F, 0x1B, 0x72, 0x1B, 0x72, 0x1B,
+    0x65, 0x1B, 0x63, 0x1B, 0x74, 0x1B, 0x20, 0x1B, 0x74, 0x1B, 0x68, 0x1B,
+    0x69, 0x1B, 0x73, 0x1B, 0x20, 0x1B, 0x73, 0x1B, 0x69, 0x1B, 0x74, 0x1B,
+    0x75, 0x1B, 0x61, 0x1B, 0x74, 0x1B, 0x69, 0x1B, 0x6F, 0x1B, 0x6E, 0x1B,
+    0x3A, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B,
+    0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0xBA, 0x1B, 0xC4, 0x04,
+    0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04,
+    0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04,
+    0xC4, 0x04, 0xBA, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B,
+    0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B,
+    0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B,
+    0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B,
+    0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B,
+    0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B,
+    0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B,
+    0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B,
+    0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B,
+    0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B,
+    0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B,
+    0xBA, 0x1B, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04,
+    0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04,
+    0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xBA, 0x1B, 0x20, 0x1B, 0x20, 0x1B,
+    0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x07, 0x1B, 0x20, 0x1B,
+    0x75, 0x1B, 0x6E, 0x1B, 0x6C, 0x1B, 0x6F, 0x1B, 0x61, 0x1B, 0x64, 0x1B,
+    0x20, 0x1B, 0x61, 0x1B, 0x6E, 0x1B, 0x79, 0x1B, 0x20, 0x1B, 0x54, 0x1B,
+    0x53, 0x1B, 0x52, 0x1B, 0x73, 0x1B, 0x20, 0x1B, 0x79, 0x1B, 0x6F, 0x1B,
+    0x75, 0x1B, 0x20, 0x1B, 0x68, 0x1B, 0x61, 0x1B, 0x76, 0x1B, 0x65, 0x1B,
+    0x20, 0x1B, 0x69, 0x1B, 0x6E, 0x1B, 0x20, 0x1B, 0x6D, 0x1B, 0x65, 0x1B,
+    0x6D, 0x1B, 0x6F, 0x1B, 0x72, 0x1B, 0x79, 0x1B, 0x20, 0x1B, 0x20, 0x1B,
+    0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B,
+    0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B,
+    0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B,
+    0x20, 0x1B, 0x20, 0x1B, 0xBA, 0x1B, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04,
+    0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04,
+    0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xBA, 0x1B,
+    0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B,
+    0x07, 0x1B, 0x20, 0x1B, 0x64, 0x1B, 0x6F, 0x1B, 0x20, 0x1B, 0x6E, 0x1B,
+    0x6F, 0x1B, 0x74, 0x1B, 0x20, 0x1B, 0x6C, 0x1B, 0x6F, 0x1B, 0x61, 0x1B,
+    0x64, 0x1B, 0x20, 0x1B, 0x53, 0x1B, 0x4D, 0x1B, 0x41, 0x1B, 0x52, 0x1B,
+    0x54, 0x1B, 0x44, 0x1B, 0x52, 0x1B, 0x56, 0x1B, 0x2E, 0x1B, 0x45, 0x1B,
+    0x58, 0x1B, 0x45, 0x1B, 0x20, 0x1B, 0x69, 0x1B, 0x6E, 0x1B, 0x20, 0x1B,
+    0x79, 0x1B, 0x6F, 0x1B, 0x75, 0x1B, 0x72, 0x1B, 0x20, 0x1B, 0x41, 0x1B,
+    0x55, 0x1B, 0x54, 0x1B, 0x4F, 0x1B, 0x45, 0x1B, 0x58, 0x1B, 0x45, 0x1B,
+    0x43, 0x1B, 0x2E, 0x1B, 0x42, 0x1B, 0x41, 0x1B, 0x54, 0x1B, 0x20, 0x1B,
+    0x66, 0x1B, 0x69, 0x1B, 0x6C, 0x1B, 0x65, 0x1B, 0x20, 0x1B, 0x20, 0x1B,
+    0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0xBA, 0x1B, 0xC4, 0x04,
+    0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04,
+    0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04,
+    0xC4, 0x04, 0xBA, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B,
+    0x20, 0x1B, 0x20, 0x1B, 0x07, 0x1B, 0x20, 0x1B, 0x64, 0x1B, 0x6F, 0x1B,
+    0x20, 0x1B, 0x6E, 0x1B, 0x6F, 0x1B, 0x74, 0x1B, 0x20, 0x1B, 0x62, 0x1B,
+    0x6F, 0x1B, 0x6F, 0x1B, 0x74, 0x1B, 0x20, 0x1B, 0x77, 0x1B, 0x69, 0x1B,
+    0x74, 0x1B, 0x68, 0x1B, 0x20, 0x1B, 0x61, 0x1B, 0x20, 0x1B, 0x6D, 0x1B,
+    0x65, 0x1B, 0x6D, 0x1B, 0x6F, 0x1B, 0x72, 0x1B, 0x79, 0x1B, 0x20, 0x1B,
+    0x6D, 0x1B, 0x61, 0x1B, 0x6E, 0x1B, 0x61, 0x1B, 0x67, 0x1B, 0x65, 0x1B,
+    0x72, 0x1B, 0x20, 0x1B, 0x28, 0x1B, 0x6C, 0x1B, 0x69, 0x1B, 0x6B, 0x1B,
+    0x65, 0x1B, 0x20, 0x1B, 0x45, 0x1B, 0x4D, 0x1B, 0x4D, 0x1B, 0x33, 0x1B,
+    0x38, 0x1B, 0x36, 0x1B, 0x29, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B,
+    0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B,
+    0xBA, 0x1B, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04,
+    0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04,
+    0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xBA, 0x1B, 0x20, 0x1B, 0x20, 0x1B,
+    0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x07, 0x1B, 0x20, 0x1B,
+    0x64, 0x1B, 0x6F, 0x1B, 0x20, 0x1B, 0x6E, 0x1B, 0x6F, 0x1B, 0x74, 0x1B,
+    0x20, 0x1B, 0x6C, 0x1B, 0x6F, 0x1B, 0x61, 0x1B, 0x64, 0x1B, 0x20, 0x1B,
+    0x61, 0x1B, 0x6E, 0x1B, 0x79, 0x1B, 0x20, 0x1B, 0x64, 0x1B, 0x69, 0x1B,
+    0x73, 0x1B, 0x6B, 0x1B, 0x20, 0x1B, 0x63, 0x1B, 0x6F, 0x1B, 0x6D, 0x1B,
+    0x70, 0x1B, 0x72, 0x1B, 0x65, 0x1B, 0x73, 0x1B, 0x73, 0x1B, 0x69, 0x1B,
+    0x6F, 0x1B, 0x6E, 0x1B, 0x20, 0x1B, 0x64, 0x1B, 0x72, 0x1B, 0x69, 0x1B,
+    0x76, 0x1B, 0x65, 0x1B, 0x72, 0x1B, 0x73, 0x1B, 0x20, 0x1B, 0x20, 0x1B,
+    0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B,
+    0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B,
+    0x20, 0x1B, 0x20, 0x1B, 0xBA, 0x1B, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04,
+    0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04,
+    0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xBA, 0x1B,
+    0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B,
+    0x07, 0x1B, 0x20, 0x1B, 0x72, 0x1B, 0x75, 0x1B, 0x6E, 0x1B, 0x20, 0x1B,
+    0x52, 0x1B, 0x4F, 0x1B, 0x54, 0x1B, 0x54, 0x1B, 0x48, 0x1B, 0x45, 0x1B,
+    0x4C, 0x1B, 0x50, 0x1B, 0x2E, 0x1B, 0x45, 0x1B, 0x58, 0x1B, 0x45, 0x1B,
+    0x20, 0x1B, 0x66, 0x1B, 0x6F, 0x1B, 0x72, 0x1B, 0x20, 0x1B, 0x69, 0x1B,
+    0x6E, 0x1B, 0x66, 0x1B, 0x6F, 0x1B, 0x72, 0x1B, 0x6D, 0x1B, 0x61, 0x1B,
+    0x74, 0x1B, 0x69, 0x1B, 0x6F, 0x1B, 0x6E, 0x1B, 0x20, 0x1B, 0x6F, 0x1B,
+    0x6E, 0x1B, 0x20, 0x1B, 0x68, 0x1B, 0x6F, 0x1B, 0x77, 0x1B, 0x20, 0x1B,
+    0x74, 0x1B, 0x6F, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B,
+    0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B,
+    0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0xBA, 0x1B, 0xC4, 0x04,
+    0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04,
+    0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04,
+    0xC4, 0x04, 0xBA, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B,
+    0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x61, 0x1B, 0x6C, 0x1B,
+    0x6C, 0x1B, 0x65, 0x1B, 0x76, 0x1B, 0x69, 0x1B, 0x61, 0x1B, 0x74, 0x1B,
+    0x65, 0x1B, 0x20, 0x1B, 0x74, 0x1B, 0x68, 0x1B, 0x69, 0x1B, 0x73, 0x1B,
+    0x20, 0x1B, 0x70, 0x1B, 0x72, 0x1B, 0x6F, 0x1B, 0x62, 0x1B, 0x6C, 0x1B,
+    0x65, 0x1B, 0x6D, 0x1B, 0x20, 0x1B, 0x28, 0x1B, 0x73, 0x1B, 0x65, 0x1B,
+    0x61, 0x1B, 0x72, 0x1B, 0x63, 0x1B, 0x68, 0x1B, 0x20, 0x1B, 0x66, 0x1B,
+    0x6F, 0x1B, 0x72, 0x1B, 0x20, 0x1B, 0x22, 0x1B, 0x4D, 0x1B, 0x65, 0x1B,
+    0x6D, 0x1B, 0x6F, 0x1B, 0x72, 0x1B, 0x79, 0x1B, 0x20, 0x1B, 0x50, 0x1B,
+    0x72, 0x1B, 0x6F, 0x1B, 0x62, 0x1B, 0x6C, 0x1B, 0x65, 0x1B, 0x6D, 0x1B,
+    0x73, 0x1B, 0x22, 0x1B, 0x29, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B,
+    0xBA, 0x1B, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04,
+    0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04,
+    0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xBA, 0x1B, 0x20, 0x1B, 0x20, 0x1B,
+    0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B,
+    0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B,
+    0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B,
+    0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B,
+    0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B,
+    0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B,
+    0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B,
+    0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B,
+    0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B,
+    0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B,
+    0x20, 0x1B, 0x20, 0x1B, 0xBA, 0x1B, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04,
+    0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04,
+    0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xBA, 0x1B,
+    0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x54, 0x1B, 0x68, 0x1B, 0x61, 0x1B,
+    0x74, 0x1B, 0x27, 0x1B, 0x73, 0x1B, 0x20, 0x1B, 0x61, 0x1B, 0x62, 0x1B,
+    0x6F, 0x1B, 0x75, 0x1B, 0x74, 0x1B, 0x20, 0x1B, 0x61, 0x1B, 0x6C, 0x1B,
+    0x6C, 0x1B, 0x20, 0x1B, 0x77, 0x1B, 0x65, 0x1B, 0x20, 0x1B, 0x63, 0x1B,
+    0x61, 0x1B, 0x6E, 0x1B, 0x20, 0x1B, 0x66, 0x1B, 0x69, 0x1B, 0x74, 0x1B,
+    0x20, 0x1B, 0x69, 0x1B, 0x6E, 0x1B, 0x20, 0x1B, 0x74, 0x1B, 0x68, 0x1B,
+    0x69, 0x1B, 0x73, 0x1B, 0x20, 0x1B, 0x73, 0x1B, 0x71, 0x1B, 0x75, 0x1B,
+    0x61, 0x1B, 0x72, 0x1B, 0x65, 0x1B, 0x2E, 0x1B, 0x20, 0x1B, 0x20, 0x1B,
+    0x54, 0x1B, 0x72, 0x1B, 0x79, 0x1B, 0x20, 0x1B, 0x52, 0x1B, 0x4F, 0x1B,
+    0x54, 0x1B, 0x54, 0x1B, 0x48, 0x1B, 0x45, 0x1B, 0x4C, 0x1B, 0x50, 0x1B,
+    0x21, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0xBA, 0x1B, 0xC4, 0x04,
+    0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04,
+    0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04,
+    0xC4, 0x04, 0xBA, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B,
+    0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B,
+    0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B,
+    0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B,
+    0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B,
+    0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B,
+    0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B,
+    0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B,
+    0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B,
+    0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B,
+    0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B, 0x20, 0x1B,
+    0xBA, 0x1B, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04,
+    0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04,
+    0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC8, 0x1B, 0xCD, 0x1B, 0xCD, 0x1B,
+    0xCD, 0x1B, 0xCD, 0x1B, 0xCD, 0x1B, 0xCD, 0x1B, 0xCD, 0x1B, 0xCD, 0x1B,
+    0xCD, 0x1B, 0xCD, 0x1B, 0xCD, 0x1B, 0xCD, 0x1B, 0xCD, 0x1B, 0xCD, 0x1B,
+    0xCD, 0x1B, 0xCD, 0x1B, 0xCD, 0x1B, 0xCD, 0x1B, 0xCD, 0x1B, 0xCD, 0x1B,
+    0xCD, 0x1B, 0xCD, 0x1B, 0xCD, 0x1B, 0xCD, 0x1B, 0xCD, 0x1B, 0xCD, 0x1B,
+    0xCD, 0x1B, 0xCD, 0x1B, 0xCD, 0x1B, 0xCD, 0x1B, 0xCD, 0x1B, 0xCD, 0x1B,
+    0xCD, 0x1B, 0xCD, 0x1B, 0xCD, 0x1B, 0xCD, 0x1B, 0xCD, 0x1B, 0xCD, 0x1B,
+    0xCD, 0x1B, 0xCD, 0x1B, 0xCD, 0x1B, 0xCD, 0x1B, 0xCD, 0x1B, 0xCD, 0x1B,
+    0xCD, 0x1B, 0xCD, 0x1B, 0xCD, 0x1B, 0xCD, 0x1B, 0xCD, 0x1B, 0xCD, 0x1B,
+    0xCD, 0x1B, 0xCD, 0x1B, 0xCD, 0x1B, 0xCD, 0x1B, 0xCD, 0x1B, 0xCD, 0x1B,
+    0xCD, 0x1B, 0xCD, 0x1B, 0xCD, 0x1B, 0xCD, 0x1B, 0xCD, 0x1B, 0xCD, 0x1B,
+    0xCD, 0x1B, 0xCD, 0x1B, 0xBC, 0x1B, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04,
+    0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04,
+    0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04,
+    0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04,
+    0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04,
+    0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04,
+    0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04,
+    0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04,
+    0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04,
+    0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04,
+    0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04,
+    0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04,
+    0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04,
+    0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04,
+    0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04, 0xC4, 0x04,
+    0x20, 0x07, 0x20, 0x07, 0x20, 0x07, 0x20, 0x07, 0x20, 0x07, 0x20, 0x07,
+    0x20, 0x07, 0x20, 0x07, 0x20, 0x07, 0x20, 0x07, 0x20, 0x07, 0x20, 0x07,
+    0x20, 0x07, 0x20, 0x07, 0x20, 0x07, 0x20, 0x07, 0x20, 0x07, 0x20, 0x07,
+    0x20, 0x07, 0x20, 0x07, 0x20, 0x07, 0x20, 0x07, 0x20, 0x07, 0x20, 0x07,
+    0x20, 0x07, 0x20, 0x07, 0x20, 0x07, 0x20, 0x07, 0x20, 0x07, 0x20, 0x07,
+    0x20, 0x07, 0x20, 0x07, 0x20, 0x07, 0x20, 0x07, 0x20, 0x07, 0x20, 0x07,
+    0x20, 0x07, 0x20, 0x07, 0x20, 0x07, 0x20, 0x07, 0x20, 0x07, 0x20, 0x07,
+    0x20, 0x07, 0x20, 0x07, 0x20, 0x07, 0x20, 0x07, 0x20, 0x07, 0x20, 0x07,
+    0x20, 0x07, 0x20, 0x07, 0x20, 0x07, 0x20, 0x07, 0x20, 0x07, 0x20, 0x07,
+    0x20, 0x07, 0x20, 0x07, 0x20, 0x07, 0x20, 0x07, 0x20, 0x07, 0x20, 0x07,
+    0x20, 0x07, 0x20, 0x07, 0x20, 0x07, 0x20, 0x07, 0x20, 0x07, 0x20, 0x07,
+    0x20, 0x07, 0x20, 0x07, 0x20, 0x07, 0x20, 0x07, 0x20, 0x07, 0x20, 0x07,
+    0x20, 0x07, 0x20, 0x07, 0x20, 0x07, 0x20, 0x07, 0x20, 0x07, 0x20, 0x07,
+    0x20, 0x07, 0x20, 0x07
+};
--- /dev/null
+++ b/rott/rt_error.c
@@ -1,0 +1,412 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+#include <dos.h>
+#include <errno.h>
+#include <io.h>
+#include <stdio.h>
+#include <conio.h>
+#include <stdarg.h>
+#include <mem.h>
+#include <ctype.h>
+#include "rt_def.h"
+#include "rt_str.h"
+#include "rt_error.h"
+#include "rt_menu.h"
+#include "isr.h"
+#include "w_wad.h"
+#include "z_zone.h"
+#include "rt_vid.h"
+#include "rt_util.h"
+#include "modexlib.h"
+//MED
+#include "memcheck.h"
+
+
+//*****************************************************************************
+//
+//                          HARD ERROR ROUTINES
+//
+//****************************************************************************
+
+#define WINDOWUX           7
+#define WINDOWUY           76
+#define WINDOWLX           138
+#define WINDOWLY           158
+
+#define MESSAGEBOXCOLOR    166
+
+
+#define DISKERROR          0x4000         // bit 15 (of deverr)
+#define IGNOREAVAILABLE    0x1000         // bit 13   (bit 14 isn't used)
+#define RETRYAVAILABLE     0x800          // bit 12
+#define FAILAVAILABLE      0x400          // bit 11
+#define LOCATION           0x300          // bit 10 and 9
+#define READWRITEERROR     0x80           // bit 8
+#define DRIVEOFERROR       0x0F           // low-order byte
+
+#define DIVISIONINT                0x00
+
+// Globals
+
+boolean DivisionError = false;
+
+// Statics
+
+
+static char ErrorCodes[13][25] =
+{
+    "Write-protected disk\0",
+    "Unknown unit\0",
+    "Drive not ready\0",
+    "Unknown command\0",
+    "CRC error in data\0",
+    "Bad drive struct length\0",
+    "Seek error\0",
+    "Unknown media type\0",
+    "Sector not found\0",
+    "Printer out of paper\0",
+    "Write fault\0",
+    "Read fault\0",
+    "General failure\0"
+};
+
+static char Drives[7][3] =
+{
+    "A\0",
+    "B\0",
+    "C\0",
+    "D\0",
+    "E\0",
+    "F\0",
+    "G\0"
+};
+
+static char Locations[4][11] =
+{
+    "MS-DOS\0",
+    "FAT\0",
+    "Directory\0",
+    "Data area\0"
+};
+
+static char ReadWrite[2][6] =
+{
+    "Read\0",
+    "Write\0"
+};
+
+static boolean ErrorHandlerStarted=false;
+void (__interrupt __far *olddivisr) () = NULL;
+
+//******************************************************************************
+//
+// UL_UserMessage ()
+//
+//******************************************************************************
+
+void UL_UserMessage (int x, int y, char *str, ...) __attribute__((format(printf,3,4)))
+{
+    va_list strptr;
+    char buf[128];
+    int width, height;
+
+    memset (&buf[0], 0, sizeof (buf));
+    va_start (strptr, str);
+    vsprintf (&buf[0], str, strptr);
+    va_end (strptr);
+
+    if ( *(byte *)0x449 == 0x13)
+    {
+        CurrentFont = tinyfont;
+
+        WindowW=160;
+        WindowH=100;
+        WindowX=80;
+        WindowY=50;
+
+        US_MeasureStr (&width, &height, &buf[0]);
+
+        width  += (CurrentFont->width[1] << 1);
+        height += (CurrentFont->height << 1);
+
+        VL_Bar (x, y, WindowW-2, WindowH, MESSAGEBOXCOLOR);
+
+        PrintX = x+CurrentFont->width[1];
+        PrintY = y+CurrentFont->height;
+
+        US_CPrint (&buf[0]);
+
+        displayofs=bufferofs;
+
+        OUTP(CRTC_INDEX, CRTC_STARTHIGH);
+        OUTP(CRTC_DATA,((displayofs&0x0000ffff)>>8));
+
+
+        bufferofs += screensize;
+        if (bufferofs > page3start)
+            bufferofs = page1start;
+    }
+    else
+        printf("%s\n",&buf[0]);
+}
+
+//****************************************************************************
+//
+// UL_GeneralError ()
+//
+//****************************************************************************
+
+int UL_GeneralError (int code)
+{
+    boolean done = false;
+    int retval = 0;
+
+    UL_UserMessage (80, 50, "Device Error!\n%s.\n \n(A)bort  (R)etry\n",
+                    ErrorCodes[code]);
+
+    if (KeyboardStarted==true)
+    {
+        while (!done)
+        {
+            if (Keyboard[sc_A])
+            {
+                retval = 1;
+                done = true;
+
+                while (Keyboard[sc_A])
+                    ;
+            }
+            else if (Keyboard[sc_R])
+            {
+                retval = 0;
+                done = true;
+
+                while (Keyboard[sc_R])
+                    ;
+            }
+        }
+    }
+    else
+    {
+        while (!done)
+        {
+            if (kbhit())
+            {
+                char ch;
+
+                ch=toupper(getch());
+                if (ch=='A')
+                {
+                    retval = 1;
+                    done = true;
+                }
+                else if (ch=='R')
+                {
+                    retval = 0;
+                    done = true;
+                }
+            }
+        }
+    }
+
+
+    return (retval);
+}
+
+
+//****************************************************************************
+//
+// UL_DriveError ()
+//
+//****************************************************************************
+
+int UL_DriveError (int code, int location, int rwerror, int whichdrive)
+{
+    boolean done = false;
+    int retval   = 0;
+
+    UL_UserMessage (80, 50,
+                    "Drive Error!\n%s.\nOn drive %s.\nLocation: %s.\n%s error.\n(A)bort  (R)etry\n",
+                    ErrorCodes[code], Drives[whichdrive],
+                    Locations[location], ReadWrite[rwerror]);
+
+    if (KeyboardStarted==true)
+    {
+        while (!done)
+        {
+            if (Keyboard[sc_A])
+            {
+                retval = 1;
+                done = true;
+
+                while (Keyboard[sc_A])
+                    ;
+            }
+            else if (Keyboard[sc_R])
+            {
+                retval = 0;
+                done = true;
+
+                while (Keyboard[sc_R])
+                    ;
+            }
+        }
+    }
+    else
+    {
+        while (!done)
+        {
+            if (kbhit())
+            {
+                char ch;
+
+                ch=toupper(getch());
+                if (ch=='A')
+                {
+                    retval = 1;
+                    done = true;
+                }
+                else if (ch=='R')
+                {
+                    retval = 0;
+                    done = true;
+                }
+            }
+        }
+    }
+
+    return (retval);
+}
+
+
+//****************************************************************************
+//
+//	UL_harderr ()
+//
+//****************************************************************************
+
+int __far UL_harderr (unsigned deverr, unsigned errcode, unsigned far *devhdr)
+{
+    int DiskError      = 0;    // Indicates if it was a disk error
+    int IgnoreAvail    = 0;    // if "ignore" response is available
+    int RetryAvail     = 0;    // if "retry" response is available
+    int FailAvail      = 0;    // if "fail" response is available
+    byte ErrorLocation = 0;    // Location of error
+    byte RWerror       = 0;    // Read/Write error (0 == read, 1 == write)
+    byte whichDrive    = 0;    // Drive the error is on (0 == A, 1 == B, ...)
+    int action;
+
+    unsigned temp;
+    temp = *devhdr;
+
+    // Check errors
+    DiskError     = (deverr & DISKERROR);
+    IgnoreAvail   = (deverr & IGNOREAVAILABLE);
+    RetryAvail    = (deverr & RETRYAVAILABLE);
+    FailAvail     = (deverr & FAILAVAILABLE);
+    ErrorLocation = ((deverr & LOCATION) >> 8);
+    RWerror       = (deverr & READWRITEERROR);
+
+    if (DiskError == 0)
+        action = UL_GeneralError (errcode);
+    else
+        action = UL_DriveError (errcode, ErrorLocation, RWerror, whichDrive);
+
+    if (action)
+        Error ("USER BREAK : ROTT aborted.\n");
+    return (_HARDERR_RETRY);
+}
+
+
+//****************************************************************************
+//
+//	UL_DivisionISR ()
+//
+//****************************************************************************
+
+extern byte * colormap;
+
+void __interrupt __far UL_DivisionISR ( void )
+{
+// acknowledge the interrupt
+
+    SetBorderColor (*(colormap+(((100-10)>>2)<<8)+160));
+    DivisionError = true;
+    OUTP (0x20, 0x20);
+}
+
+
+//****************************************************************************
+//
+//	UL_ErrorStartup ()
+//
+//****************************************************************************
+
+void UL_ErrorStartup ( void )
+{
+    if (ErrorHandlerStarted==true)
+        return;
+    ErrorHandlerStarted=true;
+    _harderr (UL_harderr);     // Install hard error handler
+    UL_StartupDivisionByZero();
+}
+
+//****************************************************************************
+//
+//	UL_ErrorShutdown ()
+//
+//****************************************************************************
+
+void UL_ErrorShutdown ( void )
+{
+    if (ErrorHandlerStarted==false)
+        return;
+    ErrorHandlerStarted=false;
+    UL_ShutdownDivisionByZero();
+}
+
+
+/*
+===============
+=
+= UL_StartupDivisionByZero
+=
+===============
+*/
+
+void UL_StartupDivisionByZero ( void )
+{
+    olddivisr = _dos_getvect(DIVISIONINT);
+    _dos_setvect (DIVISIONINT, UL_DivisionISR);
+}
+
+/*
+===============
+=
+= UL_ShutdownDivisionByZero
+=
+===============
+*/
+
+void UL_ShutdownDivisionByZero ( void )
+{
+    _dos_setvect (DIVISIONINT, olddivisr);
+}
+
--- /dev/null
+++ b/rott/rt_error.h
@@ -1,0 +1,28 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+#ifndef _rt_error_public
+#define _rt_error_public
+
+extern boolean DivisionError;
+
+void UL_ErrorStartup ( void );
+void UL_ErrorShutdown ( void );
+
+#endif
--- /dev/null
+++ b/rott/rt_fc_a.h
@@ -1,0 +1,42 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+#ifndef _rt_fc_a_public
+#define _rt_fc_a_public
+
+//***************************************************************************
+//
+//    RT_FC_A.ASM - Maprow stuff for floor and ceiling
+//
+//***************************************************************************
+
+void DrawSkyPost (byte * buf, byte * src, int height);
+void DrawRow(int count, byte * dest, byte * src);
+void DrawRotRow(int count, byte * dest, byte * src);
+void DrawMaskedRotRow(int count, byte * dest, byte * src);
+
+#if (defined __WATCOMC__)
+#pragma aux DrawSkyPost parm [EDI] [ESI] [ECX] modify exact [eax ecx edx edi esi ebx]
+#pragma aux DrawRow parm [ECX] [EDI] [ESI] modify exact [eax ebx ecx edx esi edi]
+#pragma aux DrawRotRow parm [ECX] [EDI] [ESI] modify exact [eax ebx ecx edx esi edi]
+#pragma aux DrawMaskedRotRow parm [ECX] [EDI] [ESI] modify exact [eax ebx ecx edx esi edi]
+#endif
+
+#endif
+
--- /dev/null
+++ b/rott/rt_floor.c
@@ -1,0 +1,749 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+// RT_FLOOR.C
+
+#ifdef DOS
+#include <conio.h>
+#endif
+
+#include "rt_def.h"
+#include "watcom.h"
+#include "rt_floor.h"
+#include "rt_fc_a.h"
+#include "_rt_floo.h"
+#include "rt_draw.h"
+#include "rt_util.h"
+#include "engine.h"
+#include "rt_main.h"
+#include "w_wad.h"
+#include "z_zone.h"
+#include "rt_view.h"
+#include "rt_ted.h"
+#include "rt_cfg.h"
+#include "rt_actor.h"
+#include <string.h>
+#include "isr.h"
+#include "modexlib.h"
+#include "rt_playr.h"
+#include "rt_sound.h"
+#include "rt_rand.h"
+//MED
+#include "memcheck.h"
+
+/*
+=============================================================================
+
+Global Variables                                                                                                                                 GLOBAL VARIABLES
+
+=============================================================================
+*/
+
+int      sky;
+int		mr_rowofs;
+int		mr_count;
+int		mr_xstep;
+int		mr_ystep;
+int		mr_xfrac;
+int		mr_yfrac;
+byte *   mr_dest;
+byte *   mr_src;
+
+/*
+==================
+=
+= Local Variables
+=
+==================
+*/
+
+static byte     *floor;
+static byte     *ceiling;
+//static int xstarts[MAXVIEWHEIGHT];
+static int xstarts[600];//set to max hight res
+static byte * skysegs[MAXSKYSEGS];
+static byte * skydata[MAXSKYDATA];
+static int      horizonheight;
+static int      centerskypost;
+static int      oldsky=-1;
+
+
+//bna fixit skyerror by 800x600 clouds not big enough
+
+void DrawSky( void )
+{
+
+    byte * src;
+    int dest;
+//   int plane;
+    int height;
+//   int height2;
+    int ang;
+    int angle;
+    int ofs;
+
+    angle=viewangle;
+
+    if ((fog==0) && (lightning==true))
+        shadingtable=colormap+((basemaxshade-6-lightninglevel)<<8);
+    else
+        shadingtable=colormap+(1<<12);
+
+    ofs=(((maxheight)-(player->z))>>3)+(centery*200/iGLOBAL_SCREENHEIGHT-((viewheight*200/iGLOBAL_SCREENHEIGHT)>>1));
+
+    if (ofs>centerskypost)
+    {
+        ofs=centerskypost;
+    }
+    else if (((centerskypost-ofs)+viewheight*200/iGLOBAL_SCREENHEIGHT)>1799)
+    {
+        ofs=-(1799-(centerskypost+viewheight*200/iGLOBAL_SCREENHEIGHT));
+    }
+//ofs=centerskypost;
+#ifdef DOS
+    if (doublestep>0)
+    {
+#ifdef DOS
+        for (plane=0; plane<4; plane+=2)
+#endif
+        {
+#ifdef DOS
+            VGAMAPMASK((1<<plane)+(1<<(plane+1)));
+            for (dest=plane; dest<viewwidth; dest+=4)
+#else
+            for (dest=0; dest<viewwidth; dest+=2)
+#endif
+            {
+                height=posts[dest].ceilingclip;
+                height2=posts[dest+1].ceilingclip;
+                if (height<height2)
+                    height=height2;
+                if (height<=0)
+                    continue;
+                ang=(angle+pixelangle[dest])&(FINEANGLES-1);
+                src=skysegs[ang]-ofs;
+#ifdef DOS
+                DrawSkyPost((byte *)bufferofs + (dest>>2),src,height);
+#else
+                /* TODO: this isn't right since it's not really optimized */
+                DrawSkyPost((byte *)bufferofs + dest,src,height);
+                DrawSkyPost((byte *)bufferofs + dest + 1,src,height);
+#endif
+            }
+        }
+    }
+    else
+#endif
+    {
+#ifdef DOS
+        for (plane=0; plane<4; plane++)
+#endif
+        {
+#ifdef DOS
+            VGAWRITEMAP(plane);
+            for (dest=plane; dest<viewwidth; dest+=4)
+#else
+            for (dest=0; dest<viewwidth; dest++)
+#endif
+            {
+                if ((height=posts[dest].ceilingclip)<=0)
+                    continue;
+                ang=(angle+pixelangle[dest])&(FINEANGLES-1);
+                src=skysegs[ang]-ofs;
+#ifdef DOS
+                DrawSkyPost((byte *)bufferofs + (dest>>2),src,height);
+#else
+                DrawSkyPost((byte *)bufferofs + dest,src,height);
+#endif
+            }
+        }
+    }
+}
+
+/*
+===================
+=
+= DrawFullSky
+=
+===================
+*/
+void DrawFullSky( void )
+{
+
+    byte * src;
+    int dest;
+    int plane;
+    int ang;
+    int angle;
+    int ofs;
+
+    angle=viewangle;
+
+    if ((fog==0) && (lightning==true))
+        shadingtable=colormap+((basemaxshade-5-lightninglevel)<<8);
+    else
+        shadingtable=colormap+(1<<12);
+
+    ofs=(((maxheight)-(player->z))>>3)+(centery-(viewheight>>1));
+    if (ofs>centerskypost)
+    {
+        ofs=centerskypost;
+    }
+    else if (((centerskypost-ofs)+viewheight)>599)
+    {
+        ofs=-(599-(centerskypost+viewheight));
+    }
+
+    bufferofs+=screenofs;
+
+#ifdef DOS
+    for (plane=0; plane<4; plane++)
+#endif
+    {
+#ifdef DOS
+        VGAWRITEMAP(plane);
+        for (dest=plane; dest<viewwidth; dest+=4)
+#else
+        for (dest=0; dest<viewwidth; dest++)
+#endif
+        {
+            ang=(angle+pixelangle[dest])&(FINEANGLES-1);
+            src=skysegs[ang]-ofs;
+#ifdef DOS
+            DrawSkyPost((byte *)bufferofs + (dest>>2),src,viewheight);
+#else
+            DrawSkyPost((byte *)bufferofs + dest,src,viewheight);
+#endif
+        }
+    }
+
+    bufferofs-=screenofs;
+}
+
+/*
+===================
+=
+= MakeSkyTile
+=
+===================
+*/
+void MakeSkyTile (byte * tile)
+{
+    int i,j;
+    int srcstep;
+    int src;
+
+    srcstep=200<<10;
+    for (i=0; i<64; i++)
+    {
+        src=0;
+        for (j=0; j<64; j++)
+        {
+            *(tile + (i<<6) + j)=*(skysegs[(i<<2)]+(src>>16));
+            src+=srcstep;
+        }
+    }
+}
+
+/*
+===================
+=
+= MakeSkyData
+=
+===================
+*/
+void MakeSkyData ( void )
+{
+    byte * temp;
+    byte * ptr;
+    int c;
+
+    temp=SafeMalloc(256*800);
+
+    ptr=temp;
+
+    for (c=0; c<256; c++)
+    {
+
+        memcpy(ptr,skydata[1]+(c*200),200);
+        ptr+=200;
+
+        memcpy(ptr,skydata[0]+(c*200),200);
+        ptr+=200;
+
+        //memcpy(ptr,skydata[1]+(c*200),200);
+        //ptr+=200;
+        //memcpy(ptr,skydata[0]+(c*200),200);
+        //ptr+=200;
+    }
+    skydata[0]=temp;
+}
+
+/*
+===================
+=
+= GetFloorCeilingLump
+=
+===================
+*/
+
+int GetFloorCeilingLump ( int num )
+{
+    int lump;
+
+    switch (num)
+    {
+    case 1:
+        lump=W_GetNumForName("FLRCL1\0");
+        break;
+    case 2:
+        lump=W_GetNumForName("FLRCL2\0");
+        break;
+    case 3:
+        lump=W_GetNumForName("FLRCL3\0");
+        break;
+    case 4:
+        lump=W_GetNumForName("FLRCL4\0");
+        break;
+    case 5:
+        lump=W_GetNumForName("FLRCL5\0");
+        break;
+    case 6:
+        lump=W_GetNumForName("FLRCL6\0");
+        break;
+    case 7:
+        lump=W_GetNumForName("FLRCL7\0");
+        break;
+    case 8:
+        lump=W_GetNumForName("FLRCL8\0");
+        break;
+    case 9:
+        lump=W_GetNumForName("FLRCL9\0");
+        break;
+    case 10:
+        lump=W_GetNumForName("FLRCL10\0");
+        break;
+    case 11:
+        lump=W_GetNumForName("FLRCL11\0");
+        break;
+    case 12:
+        lump=W_GetNumForName("FLRCL12\0");
+        break;
+    case 13:
+        lump=W_GetNumForName("FLRCL13\0");
+        break;
+    case 14:
+        lump=W_GetNumForName("FLRCL14\0");
+        break;
+    case 15:
+        lump=W_GetNumForName("FLRCL15\0");
+        break;
+    case 16:
+        lump=W_GetNumForName("FLRCL16\0");
+        break;
+    default:
+        Error("Illegal Floor/Ceiling Tile = %d\n",num);
+        break;
+    }
+    return lump;
+}
+
+/*
+===================
+=
+= SkyExists
+=
+===================
+*/
+
+boolean SkyExists (void)
+{
+    if (MAPSPOT(1,0,0) >= 234)
+    {
+        return true;
+    }
+    else
+    {
+        return false;
+    }
+
+}
+
+/*
+===================
+=
+= SetPlaneViewSize
+=
+===================
+*/
+
+void SetPlaneViewSize (void)
+{
+    int      x;
+    int      i;
+    int      s;
+    int      floornum;
+    int      ceilingnum;
+    int      skytop;
+    int      skybottom;
+
+    sky=0;
+
+    if (oldsky>0)
+    {
+        SafeFree(skydata[0]);
+        oldsky=-1;
+    }
+
+    lightning=false;
+
+    if (MAPSPOT(1,0,0) >= 234)
+    {
+        word crud;
+        sky = (MAPSPOT(1,0,0) - 233);
+        if ((sky<1) || (sky>6))
+            Error("Illegal Sky Tile = %d\n",sky);
+        ceilingnum=1;
+        crud=(word)MAPSPOT(1,0,1);
+        if ((crud>=90) && (crud<=97))
+            horizonheight=crud-89;
+        else if ((crud>=450) && (crud<=457))
+            horizonheight=crud-450+9;
+        else
+            Error("You must specify a valid horizon height sprite icon over the sky at (2,0) on map %d\n",gamestate.mapon);
+
+        // Check for lightnign icon
+
+        crud=(word)MAPSPOT(4,0,1);
+        if (crud==377)
+            lightning=true;
+    }
+    else
+        ceilingnum = MAPSPOT(1,0,0)-197;
+
+    floornum = MAPSPOT(0,0,0)-(179);
+
+    floornum = GetFloorCeilingLump ( floornum );
+    //ceilingnum = GetFloorCeilingLump ( ceilingnum );
+
+    floor = W_CacheLumpNum(floornum,PU_LEVELSTRUCT, Cvt_patch_t, 1);
+    floor +=8;
+
+    if (sky==0)  // Don't cache in if not used
+    {
+        ceilingnum = GetFloorCeilingLump ( ceilingnum );
+        ceiling = W_CacheLumpNum(ceilingnum,PU_LEVELSTRUCT, Cvt_patch_t, 1);
+        ceiling +=8;
+    } else {
+        ceiling = NULL;
+    }
+
+    s = W_GetNumForName("SKYSTART");
+
+    switch (sky)
+    {
+    case 1:
+        skytop=s+1;
+        skybottom=s+2;
+        break;
+    case 2:
+        skytop=s+3;
+        skybottom=s+4;
+        break;
+    case 3:
+        skytop=s+5;
+        skybottom=s+6;
+        break;
+    case 4:
+        skytop=s+7;
+        skybottom=s+8;
+        break;
+    case 5:
+        skytop=s+9;
+        skybottom=s+10;
+        break;
+    case 6:
+        skytop=s+11;
+        skybottom=s+12;
+        break;
+    }
+    if (sky!=0)
+    {
+        skydata[0]=W_CacheLumpNum(skytop,PU_STATIC, CvtNull, 1);
+        skydata[1]=W_CacheLumpNum(skybottom,PU_STATIC, CvtNull, 1);
+        centerskypost=MINSKYHEIGHT-(horizonheight*6);
+        oldsky=sky;
+        MakeSkyData();
+        W_CacheLumpNum(skytop,PU_CACHE, CvtNull, 1);
+        W_CacheLumpNum(skybottom,PU_CACHE, CvtNull, 1);
+        x=511;
+        for (i=0; i<MAXSKYSEGS; i++)
+        {
+            skysegs[i]=skydata[0]+((x>>1)*400)+centerskypost;
+            x--;
+            if (x==-1)
+            {
+                x=511;
+            }
+        } /* endfor */
+    }
+}
+
+/*
+==========================
+=
+= SetFCLightLevel
+=
+==========================
+*/
+void SetFCLightLevel (int height)
+{
+    int i;
+
+    if (MISCVARS->GASON==1)
+    {
+        shadingtable=greenmap+(MISCVARS->gasindex<<8);
+        return;
+    }
+    if (fulllight)
+    {
+        shadingtable=colormap+(1<<12);
+        return;
+    }
+    if (fog)
+    {
+        i=((height*200/iGLOBAL_SCREENHEIGHT)>>normalshade)+minshade;
+        if (i>maxshade) i=maxshade;
+        shadingtable=colormap+(i<<8);
+    }
+    else
+    {
+        i=maxshade-(height>>normalshade);
+        if (i<minshade) i=minshade;
+        shadingtable=colormap+(i<<8);
+    }
+}
+
+
+
+void DrawHLine (int xleft, int xright, int yp)
+{
+    int plane;
+    byte * buf;
+    byte * dest;
+    int startxfrac;
+    int startyfrac;
+    int height;
+//   int length;
+    int ofs;
+
+    if (yp==centery)
+        return;
+    if (yp>centery)
+    {
+        int hd;
+
+        buf=floor;
+        hd=yp-centery;
+        height=(hd<<13)/(maxheight-pheight+32);
+    }
+    else
+    {
+        int hd;
+
+        /* ROTT bug? It'd draw when there was no ceiling. - SBF */
+        if (ceiling == NULL) return;
+
+        buf=ceiling;
+
+        hd=centery-yp;
+        height=(hd<<13)/pheight;
+    }
+    SetFCLightLevel(height>>(8-HEIGHTFRACTION-1));
+    mr_xstep = ((viewsin<<8)/(height));
+    mr_ystep = ((viewcos<<8)/(height));
+
+    startxfrac = ((viewx>>1) + FixedMulShift(mr_ystep,scale,2))-
+                 FixedMulShift(mr_xstep,(centerx-xleft),2);
+
+    startyfrac = ((viewy>>1) - FixedMulShift(mr_xstep,scale,2))-
+                 FixedMulShift(mr_ystep,(centerx-xleft),2);
+
+    dest=(byte *)bufferofs+ylookup[yp];
+
+    /* TODO: horizontal isn't as easy as vertical in packed */
+#ifdef DOS
+    if (doublestep>0)
+    {
+        if (xleft&1)
+            xleft--;
+
+#ifdef DOS
+        for (plane=xleft; plane<xleft+4; plane+=2)
+#endif
+        {
+
+#ifdef DOS
+            mr_dest=dest+(plane>>2);
+#else
+            mr_dest=dest+xleft;
+#endif
+
+            mr_xfrac = startxfrac;
+            mr_yfrac = startyfrac;
+
+#ifdef DOS
+            startxfrac+=mr_xstep>>1;
+            startyfrac+=mr_ystep>>1;
+
+            mr_count=((xright-plane)>>2)+1;
+#else
+            mr_count = xright - xleft;
+#endif
+
+            if (mr_count)
+            {
+#ifdef DOS
+                int p;
+                ofs=((plane&3)<<3)+(plane&3)+1;
+//          VGAMAPMASK(*((byte *)mapmasks1+ofs));
+                p=plane&3;
+                VGAMAPMASK((1<<p) + (1<<(p+1)));
+#endif
+                DrawRow(mr_count,mr_dest,buf);
+
+#if 0
+                ofs=(byte)*((byte *)mapmasks2+ofs);
+                if (ofs!=0)
+                {
+                    VGAMAPMASK(ofs);
+                    DrawRow(mr_count,mr_dest+1,buf);
+                }
+#endif
+            }
+        }
+    }
+    else
+#endif
+    {
+#ifdef DOS
+        for (plane=xleft; plane<xleft+4; plane++)
+#endif
+        {
+#ifdef DOS
+            mr_dest=dest+(plane>>2);
+            VGAWRITEMAP(plane&3);
+#else
+            mr_dest=dest+xleft;
+#endif
+
+            mr_xfrac = startxfrac;
+            mr_yfrac = startyfrac;
+
+#ifdef DOS
+            startxfrac+=mr_xstep>>2;
+            startyfrac+=mr_ystep>>2;
+
+            mr_count=((xright-plane)>>2)+1;
+#else
+            // back off the pixel increment (orig. is 4x)
+            mr_xstep >>= 2;
+            mr_ystep >>= 2;
+
+            mr_count = xright-xleft+1;
+#endif
+
+            if (mr_count)
+                DrawRow(mr_count,mr_dest,buf);
+        }
+    }
+
+}
+
+void DrawPlanes( void )
+{
+    int x,y;
+    int twall;
+    int bwall;
+
+    if (sky)
+        DrawSky();
+    else
+    {
+        y=0;
+        for (x=0; x<viewwidth; x++)
+        {
+            twall=posts[x].ceilingclip;
+            while (y<twall)
+            {
+                xstarts[y]=x;
+                y++;
+            }
+            while (y>twall)
+            {
+                y--;
+                DrawHLine(xstarts[y],x-1,y);
+            }
+        }
+        while (y>0)
+        {
+            y--;
+            DrawHLine(xstarts[y],viewwidth-1,y);
+        }
+    }
+    y=viewheight-1;
+    for (x=0; x<viewwidth; x++)
+    {
+        bwall=posts[x].floorclip;
+        while (y>bwall)
+        {
+            xstarts[y]=x;
+            y--;
+        }
+        while (y<bwall)
+        {
+            y++;
+            DrawHLine(xstarts[y],x-1,y);
+        }
+    }
+    while (y<viewheight-1)
+    {
+        y++;
+        DrawHLine(xstarts[y],viewwidth-1,y);
+    }
+}
+
+#ifndef DOS
+void DrawRow(int count, byte * dest, byte * src)
+{
+    unsigned frac, fracstep;
+    int coord;
+
+    frac = (mr_yfrac<<16) + (mr_xfrac&0xffff);
+    fracstep = (mr_ystep<<16) + (mr_xstep&0xffff);
+
+    while (count--) {
+        /* extract the x/y coordinates */
+        coord = ((frac >> (32-7)) | ((frac >> (32-23)) << 7)) & 16383;
+
+        *dest++ = shadingtable[src[coord]];
+        frac += fracstep;
+    }
+}
+#endif
--- /dev/null
+++ b/rott/rt_floor.h
@@ -1,0 +1,44 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+#ifndef _rt_floor_public
+#define _rt_floor_public
+
+//***************************************************************************
+//
+//    RT_FLOOR.C - Floor and Ceiling stuff
+//
+//***************************************************************************
+
+extern int		mr_xstep;
+extern int		mr_ystep;
+extern int		mr_xfrac;
+extern int		mr_yfrac;
+
+extern int     sky;      //Whether Parallax is on or off
+void DrawPlanes (void);
+void SetPlaneViewSize( void );
+void MakeSkyTile (byte * tile);
+void DrawFullSky( void );
+boolean SkyExists (void);
+
+#endif
+
+
+
--- /dev/null
+++ b/rott/rt_game.c
@@ -1,0 +1,5772 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+
+#ifdef DOS
+#include <dos.h>
+#include <io.h>
+#include <conio.h>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <ctype.h>
+
+#include "rt_def.h"
+#include "rt_main.h"
+#include "rt_game.h"
+#include "_rt_game.h"
+#include "rt_menu.h"
+#include "z_zone.h"
+#include "w_wad.h"
+#include "lumpy.h"
+#include "rt_playr.h"
+#include "rt_util.h"
+#include "rt_ted.h"
+#include "rt_draw.h"
+#include "rt_view.h"
+#include "rt_vid.h"
+#include "rt_door.h"
+#include "rt_in.h"
+#include "rt_str.h"
+#include "isr.h"
+#include "rt_build.h"
+#include "rt_rand.h"
+#include "rt_cfg.h"
+#include "rt_sound.h"
+#include "version.h"
+#include "rt_crc.h"
+#include "modexlib.h"
+#include "engine.h"
+#include "gmove.h"
+#include "rt_com.h"
+#include "rt_net.h"
+#include "watcom.h"
+#include "rt_floor.h"
+#include "rt_msg.h"
+#include "rt_scale.h"
+#include "develop.h"
+//MED
+#include "memcheck.h"
+
+#if (SHAREWARE == 1)
+#define NUMAMMOGRAPHICS 10
+#else
+#define NUMAMMOGRAPHICS 20
+#endif
+
+//******************************************************************************
+//
+// GLOBALS
+//
+//******************************************************************************
+
+int PlayerSnds[5] = {SD_PLAYERTCSND, SD_PLAYERTBSND, SD_PLAYERDWSND,
+                     SD_PLAYERLNSND, SD_PLAYERIPFSND
+                    };
+
+
+unsigned short SHAKETICS = 0xFFFF;//bna++
+//int SHAKETICS   = 0xFFFF;
+int damagecount = 0;
+HighScore   Scores[MaxScores] =
+{
+    {"Tom",70000,7,1},
+    {"Chuck",60000,6,1},
+    {"Mark",50000,5,1},
+    {"The Joes",40000,4,1},
+    {"William",30000,3,1},
+    {"Jim",20000,2,1},
+    {"Steve",10000,1,1},
+};
+
+//******************************************************************************
+//
+// LOCALS
+//
+//******************************************************************************
+
+static int KeyX[4]  = {KEY1_X, KEY2_X, KEY3_X, KEY4_X};
+
+static const char *Names[ 5 ] =
+{
+    "Taradino", "Thi",     "Doug",  "Lorelei", "Ian Paul"
+};
+
+static const char *LastNames[ 5 ] =
+{
+    "Cassatt",  "Barrett", "Wendt", "Ni",      "Freeley"
+};
+
+static STR ScoreStr;
+static STR LivesStr;
+static STR TriadStr;
+static STR KillStr;
+
+static pic_t *lifeptnums[10];
+static pic_t *lifenums[10];
+static pic_t *timenums[10];
+static pic_t *scorenums[10];
+static pic_t *keys[4];
+static pic_t *men[5];
+
+static pic_t *health[6];
+static pic_t *ammo[26];
+static pic_t *erase;
+static pic_t *eraseb;
+static pic_t *fragpic[ 5 ];
+static pic_t *frag100pic[ 5 ];
+static pic_t *negfragpic[ 5 ];
+static pic_t *menneg[ 5 ];
+static pic_t *blankfragpic;
+
+static int powerpics;
+static int poweradjust;
+
+static int poweruptime;
+static int powerupheight;
+static int protectiontime;
+static int protectionheight;
+
+
+static boolean EndLevelStuff = false;
+static boolean borderset     = false;
+static int oldsec            = -1;
+
+static pic_t *BkPic;
+int SaveTime = 0;
+int oldhealth;
+
+static int oldplayerhealth;
+static int oldpercenthealth;
+
+static int playeruniformcolor;
+
+#define NUMBONUSES   11
+#define BONUSBONUS   100000
+
+
+extern void VL_MemToScreenClipped (byte *source, int width, int height, int x, int y);
+void DrawPPic (int xpos, int ypos, int width, int height, byte *src, int num, boolean up, boolean bufferofsonly);
+extern void    MoveScreenUpLeft();
+extern void    MoveScreenUpRight();
+extern void    MoveScreenDownLeft();
+extern void    MoveScreenDownRight();
+//******************************************************************************
+//
+// V_ReDrawBkgnd ()
+//
+//******************************************************************************
+
+void V_ReDrawBkgnd (int x, int y, int width, int height, boolean shade)
+{
+    byte *src;
+    byte *dest;
+    byte *origdest;
+    int j,
+        k,
+        planes,
+        mask,
+        m;
+
+    m = (x&3);
+    mask = (1 << m);
+
+#ifdef DOS
+    origdest = (byte *)(bufferofs+ylookup[y]+(x>>2));
+#else
+    origdest = (byte *)(bufferofs+ylookup[y]+x);
+#endif
+
+    if (VW_MarkUpdateBlock (x, y, x+width-1, y+height-1))
+    {
+        for (planes = 0; planes < 4; planes++)
+        {
+            src = (&(BkPic->data)+((80*200)*m)+(80*y)+(x>>2));
+            dest = origdest;
+
+#ifdef DOS
+            VGAMAPMASK (mask);
+#else
+            dest += planes;
+#endif
+
+            for (j = 0; j < height; j++)
+            {
+                for (k = 0; k < (width/4); k++) {
+                    if (shade) {
+                        *dest = *(colormap + ((MENUSHADELEVEL>>2)<<8) + *src++);
+                    } else {
+                        *dest = *src++;
+                    }
+#ifdef DOS
+                    dest++;
+#else
+                    dest += 4;
+#endif
+                }
+
+#ifndef DOS
+                // draw the remainder.  did the DOS version even bother? - SBF
+                if ((width & 3) > planes) {
+                    if (shade) {
+                        *dest = *(colormap + ((MENUSHADELEVEL>>2)<<8) + *src);
+                    } else {
+                        *dest = *src;
+                    }
+                }
+#endif
+
+                src += (80-(width/4));
+#ifdef DOS
+                dest += (linewidth-(width/4));
+#else
+                dest += (linewidth-(width&~3));
+#endif
+            }
+
+            m++;
+
+            mask <<= 1;
+
+            if (mask == 16)
+            {
+                x+=4;
+                mask = 1;
+                m = 0;
+#ifdef DOS
+                origdest++;
+#endif
+            }
+        }
+    }
+}
+
+
+//******************************************************************************
+//
+// CacheLumpGroup ()
+//
+//******************************************************************************
+void CacheLumpGroup
+(
+    char   *startlump,
+    pic_t **lumparray,
+    int     numberoflumps
+)
+
+{
+    int lumpnum;
+    int i;
+
+    lumpnum = W_GetNumForName( startlump );
+
+    for( i = 0; i < numberoflumps; i++ )
+    {
+        lumparray[ i ] = ( pic_t * )W_CacheLumpNum( lumpnum + i, PU_LEVEL, Cvt_pic_t, 1 );
+    }
+}
+
+//******************************************************************************
+//
+// SetupPlayScreen ()
+//
+//******************************************************************************
+void SetupPlayScreen
+(
+    void
+)
+
+{
+    int i;
+    int j;
+    int num;
+
+    erase  = ( pic_t * )W_CacheLumpName( "erase", PU_LEVEL, Cvt_pic_t, 1 );
+    eraseb = ( pic_t * )W_CacheLumpName( "eraseb", PU_LEVEL, Cvt_pic_t, 1 );
+
+    CacheLumpGroup( "tmnum0", timenums, 10 );
+    CacheLumpGroup( "lfnum0", lifeptnums, 10 );
+    CacheLumpGroup( "lvnum0", lifenums, 10 );
+    CacheLumpGroup( "health1b", health, 6 );
+    CacheLumpGroup( "key1", keys, 4 );
+
+    if ( !BATTLEMODE )
+    {
+        CacheLumpGroup( "scnum0", scorenums, 10 );
+
+        num = locplayerstate->player;
+        men[ num ] = ( pic_t * )W_CacheLumpNum( W_GetNumForName( "MAN1" ) +
+                                                num, PU_LEVEL, Cvt_pic_t, 1 );
+    }
+    else
+    {
+        int  man;
+        int  num100;
+        int  negnum;
+        int  negman;
+
+        CacheLumpGroup( "kilnum0", scorenums, 10 );
+
+        negnum  = W_GetNumForName( "botnpic1" );
+        num     = W_GetNumForName( "botpic0" );
+        num100  = W_GetNumForName( "botopic1" );
+        negman  = W_GetNumForName( "negman1" );
+        man     = W_GetNumForName( "man1" );
+
+        blankfragpic = ( pic_t * )W_CacheLumpNum( num, PU_LEVEL, Cvt_pic_t, 1 );
+        num++;
+
+        for( i = 0; i < numplayers; i++ )
+        {
+            j = PLAYERSTATE[ i ].player;
+            if ( !gamestate.teamplay )
+            {
+                fragpic[ j ]    = ( pic_t * )W_CacheLumpNum( num + j, PU_LEVEL, Cvt_pic_t, 1 );
+                frag100pic[ j ] = ( pic_t * )W_CacheLumpNum( num100 + j, PU_LEVEL, Cvt_pic_t, 1 );
+                negfragpic[ j ] = ( pic_t * )W_CacheLumpNum( negnum + j, PU_LEVEL, Cvt_pic_t, 1 );
+            }
+            else
+            {
+                negfragpic[ j ] = ( pic_t * )W_CacheLumpName( "teamnpic", PU_LEVEL, Cvt_pic_t, 1 );
+                fragpic[ j ]    = ( pic_t * )W_CacheLumpName( "teampic", PU_LEVEL, Cvt_pic_t, 1 );
+                frag100pic[ j ] = fragpic[ j ];
+            }
+
+            menneg[ j ]     = ( pic_t * )W_CacheLumpNum( negman + j, PU_LEVEL, Cvt_pic_t, 1 );
+            men[ j ]        = ( pic_t * )W_CacheLumpNum( man + j, PU_LEVEL, Cvt_pic_t, 1 );
+        }
+    }
+
+    powerpics   = W_GetNumForName( "GDMODEP" );
+    poweradjust = POWERUPTICS / 16;
+
+    num   = W_GetNumForName( "INF_B" );
+
+    // bullet weapons
+    ammo[0] = ( pic_t * )W_CacheLumpNum( num, PU_LEVEL, Cvt_pic_t, 1 );
+    ammo[1] = ( pic_t * )W_CacheLumpNum( num, PU_LEVEL, Cvt_pic_t, 1 );
+    ammo[2] = ( pic_t * )W_CacheLumpNum( num++, PU_LEVEL, Cvt_pic_t, 1 );
+
+
+    for(i=3; i < 13; i++ )
+    {
+        ammo[ i ] = ( pic_t * )W_CacheLumpNum( num++, PU_LEVEL, Cvt_pic_t, 1 );
+    }
+
+    ammo[13] = ( pic_t * )W_CacheLumpNum( num, PU_LEVEL, Cvt_pic_t, 1 );
+    ammo[14] = ( pic_t * )W_CacheLumpNum( num, PU_LEVEL, Cvt_pic_t, 1 );
+    ammo[15] = ( pic_t * )W_CacheLumpNum( num++, PU_LEVEL, Cvt_pic_t, 1 );
+
+
+    for(i=16; i < 26; i++ )
+    {
+        ammo[ i ] = ( pic_t * )W_CacheLumpNum( num++, PU_LEVEL, Cvt_pic_t, 1 );
+    }
+
+
+    oldplayerhealth  = -1;
+    oldpercenthealth = -1;
+}
+
+
+
+//******************************************************************************
+//
+// GameMemToScreen()
+//
+//******************************************************************************
+
+void GameMemToScreen(pic_t *source, int x, int y, int bufferofsonly)
+{
+    if ( bufferofsonly )
+    {
+        VL_MemToScreen( ( byte * )&source->data, source->width,
+                        source->height, x, y );
+    }
+    else
+    {
+        GM_MemToScreen( ( byte * )&source->data, source->width,
+                        source->height, x, y );
+    }
+}
+int topBarCenterOffsetX;
+//int topBarCenterOffsetX = (iGLOBAL_SCREENWIDTH - 320) >> 1;
+
+//******************************************************************************
+//
+// DrawPlayScreen ()
+//
+//******************************************************************************
+void DrawPlayScreen (boolean bufferofsonly)
+{
+    pic_t *shape;
+    int    shapenum;
+    int ShowKillsYoffset = 0;//bna++
+
+//return;
+    //figure out where the middle point of the status bar should be for top bar
+    topBarCenterOffsetX = (iGLOBAL_SCREENWIDTH - 320) >> 1;
+    
+    if ( SHOW_TOP_STATUS_BAR() )
+    {
+        if (iGLOBAL_SCREENWIDTH == 640) {
+            //use this as dummy pic to fill out missing bar
+            shape = ( pic_t * ) W_CacheLumpName( "bottbar", PU_CACHE, Cvt_pic_t, 1 );
+            GameMemToScreen( shape, 0, 0, bufferofsonly );
+            GameMemToScreen( shape, 320, 0, bufferofsonly );
+            // delete heart in middle of topbar
+            DrawPPic( 3,1, 8 >> 2, 16,
+                      ( byte * )&erase->data, 2, true, bufferofsonly );
+            // delete bullet in end of topbar
+            DrawPPic( 620,1, 8 >> 2, 16,
+                      ( byte * )&erase->data, 2, true, bufferofsonly );
+            shape = ( pic_t * )W_CacheLumpName( "stat_bar", PU_CACHE, Cvt_pic_t, 1 );
+            GameMemToScreen( shape, topBarCenterOffsetX, 0, bufferofsonly );
+        } else if (iGLOBAL_SCREENWIDTH == 800) {
+            //use this as dummy pic to fill out missing bar
+            shape = ( pic_t * ) W_CacheLumpName( "bottbar", PU_CACHE, Cvt_pic_t, 1 );
+            GameMemToScreen( shape, 0, 0, bufferofsonly );
+            GameMemToScreen( shape, 260, 0, bufferofsonly );
+            GameMemToScreen( shape, 800-320, 0, bufferofsonly );
+            // delete heart in middle of topbar
+            DrawPPic( 480+3,1, 8 >> 2, 16,
+                      ( byte * )&erase->data, 2, true, bufferofsonly );
+            // delete bullet in end of topbar
+            DrawPPic( 780,1, 8 >> 2, 16,
+                      ( byte * )&erase->data, 2, true, bufferofsonly );
+            
+            //delete heart in left side of topbar
+            DrawPPic( 3,1, 8 >> 2, 16,
+                      ( byte * )&erase->data, 2, true, bufferofsonly );
+            
+            shape = ( pic_t * )W_CacheLumpName( "stat_bar", PU_CACHE, Cvt_pic_t, 1 );
+            GameMemToScreen( shape, topBarCenterOffsetX, 0, bufferofsonly );
+            
+            //shape = ( pic_t * ) W_CacheLumpName( "bottbar", PU_CACHE, Cvt_pic_t, 1 );
+        } else if (iGLOBAL_SCREENWIDTH == 320) {
+
+            //SetTextMode (  );
+            shape = ( pic_t * )W_CacheLumpName( "stat_bar", PU_CACHE, Cvt_pic_t, 1 );
+            GameMemToScreen( shape, 0, 0, bufferofsonly );
+        }
+    }
+
+    if ( BATTLEMODE )
+    {
+        DrawKills( bufferofsonly );
+    }
+
+    if ( SHOW_BOTTOM_STATUS_BAR() )
+    {
+        shape = ( pic_t * ) W_CacheLumpName( "bottbar", PU_CACHE, Cvt_pic_t, 1 );
+
+        if ( SHOW_KILLS() )
+        {
+            ShowKillsYoffset = KILLS_HEIGHT;
+            //shape =  ( pic_t * )W_CacheLumpName( "backtile", PU_CACHE, Cvt_pic_t, 1 );
+            //DrawTiledRegion( 0, 584, iGLOBAL_SCREENWIDTH, 32-16, 0, 16, shape );//bna++
+
+
+            //	     health_y = iGLOBAL_HEALTH_Y;
+//  if (        SHOW_KILLS() )
+            //   {
+            // health_y -= KILLS_HEIGHT;
+            //GameMemToScreen( shape, 0, (iGLOBAL_SCREENHEIGHT-40)+16, bufferofsonly );
+
+            //GameMemToScreen( shape, 0, 160, bufferofsonly );bna++
+        }
+        //else
+        //{
+
+            if (iGLOBAL_SCREENWIDTH == 640) {
+                //bna fix - not to good? but no one has 286 any more
+                //statusbar dosent cover hole screen, because its a lump picture width max 320
+                //first write dummy shape and next over it
+                GameMemToScreen( shape, 320, (224*2)+16-ShowKillsYoffset, bufferofsonly );
+                //copy next shape to mem
+                GameMemToScreen( shape, 0, (224*2)+16-ShowKillsYoffset, bufferofsonly );
+                // delete bullet in middle of shape picture
+                DrawPPic( 310, (224*2)+17-ShowKillsYoffset, 8 >> 2, 16,
+                          ( byte * )&erase->data, 2, true, bufferofsonly );
+                // delete hart in middle of shape picture
+                DrawPPic( 324, (224*2)+17-ShowKillsYoffset, 8 >> 2, 16,
+                          ( byte * )&erase->data, 2, true, bufferofsonly );
+
+            } else if (iGLOBAL_SCREENWIDTH == 800) {
+                GameMemToScreen( shape, 800-320, 584-ShowKillsYoffset, bufferofsonly );
+                //copy next shape to mem
+                GameMemToScreen( shape, 300, 584-ShowKillsYoffset, bufferofsonly );
+                //copy next shape to mem
+                GameMemToScreen( shape, 0, 584-ShowKillsYoffset, bufferofsonly );
+                // delete 2 bullets in middle of shape picture
+                DrawPPic( 305, 584+1-ShowKillsYoffset, 8 >> 2, 16,
+                          ( byte * )&erase->data, 2, true, bufferofsonly );
+                // delete hart in middle of shape picture
+                DrawPPic( 610, 584+1-ShowKillsYoffset, 8 >> 2, 16,
+                          ( byte * )&erase->data, 2, true, bufferofsonly );
+
+            } else {
+                GameMemToScreen( shape, 0, 184, bufferofsonly );
+            }
+        //}
+
+        DrawBarAmmo( bufferofsonly );
+        DrawBarHealth( bufferofsonly );
+
+        if ( demoplayback )
+        {
+            shape = ( pic_t * )W_CacheLumpName( "demo", PU_CACHE, Cvt_pic_t, 1 );
+            if (iGLOBAL_SCREENWIDTH == 640) {
+                //DrawPPic( 148, 185, shape->width, shape->height,
+                //   ( byte * )&shape->data, 1, true, bufferofsonly );bna
+                DrawPPic( 148*2, 465, shape->width, shape->height,
+                          ( byte * )&shape->data, 1, true, bufferofsonly );
+            } else if (iGLOBAL_SCREENWIDTH == 800) {
+                DrawPPic( 380, 585, shape->width, shape->height,
+                          ( byte * )&shape->data, 1, true, bufferofsonly );
+            } else {
+                DrawPPic( 148, 185, shape->width, shape->height,
+                          ( byte * )&shape->data, 1, true, bufferofsonly );
+            }
+        }
+    }
+
+    if ( !SHOW_TOP_STATUS_BAR() )
+    {
+        return;
+    }
+
+//draws small player picture and name in topbar
+    oldsec = -1;
+
+    //DrawTime( bufferofsonly );
+
+    if ( !BATTLEMODE )
+    {
+        int character;
+        int width;
+        int height;
+
+        character = locplayerstate->player;
+        GameMemToScreen( men[ character ], MEN_X + topBarCenterOffsetX, MEN_Y,bufferofsonly );
+
+        CurrentFont = tinyfont;
+
+        // Draw player's name
+        
+        if (iGLOBAL_SCREENWIDTH == 800)
+        {
+            DrawGameString ( MEN_X + 3 + topBarCenterOffsetX, MEN_Y + 2, Names[ character ], bufferofsonly );
+            VW_MeasurePropString( LastNames[ character ], &width, &height );
+            DrawGameString ( MEN_X + 44 - width + topBarCenterOffsetX, MEN_Y + 8,
+                         LastNames[ character ], bufferofsonly );
+        }
+        else
+        {
+/*
+            DrawGameString ( MEN_X + 3, MEN_Y + 2, Names[ character ], bufferofsonly );
+
+            VW_MeasurePropString( LastNames[ character ], &width, &height );
+
+            DrawGameString ( MEN_X + 44 - width, MEN_Y + 8,
+                         LastNames[ character ], bufferofsonly );
+*/
+            
+            
+            DrawGameString ( MEN_X + 3 + topBarCenterOffsetX, MEN_Y + 2, Names[ character ], bufferofsonly );
+            VW_MeasurePropString( LastNames[ character ], &width, &height );
+            DrawGameString ( MEN_X + 44 - width + topBarCenterOffsetX, MEN_Y + 8,
+                         LastNames[ character ], bufferofsonly );
+        
+        }
+        UpdateLives( locplayerstate->lives );
+        UpdateScore( gamestate.score );
+        DrawTriads( bufferofsonly );
+        DrawLives( bufferofsonly );
+        DrawScore( bufferofsonly );
+    }
+
+    DrawKeys( bufferofsonly );
+
+    if ( locplayerstate->poweruptime )
+    {
+        if ( player->flags & FL_GODMODE )
+        {
+            shapenum = powerpics;
+        }
+        else if ( player->flags & FL_DOGMODE )
+        {
+            shapenum = powerpics + 1;
+        }
+        else if ( player->flags & FL_FLEET )
+        {
+            shapenum = powerpics + 2;
+        }
+        else if ( player->flags & FL_ELASTO )
+        {
+            shapenum = powerpics + 3;
+        }
+        else if ( player->flags & FL_SHROOMS )
+        {
+            shapenum = powerpics + 4;
+        }
+
+        shape = ( pic_t * )W_CacheLumpNum ( shapenum, PU_CACHE, Cvt_pic_t, 1 );
+
+        GameMemToScreen( eraseb, POWERUP1X + topBarCenterOffsetX, POWERUPY, bufferofsonly );
+
+        DrawMPPic( POWERUP1X + topBarCenterOffsetX, POWERUPY + powerupheight, shape->width,
+                   shape->height - powerupheight, powerupheight,
+                   ( byte * )&shape->data, bufferofsonly );
+    }
+
+
+    if ( locplayerstate->protectiontime )
+    {
+        if ( player->flags & FL_BPV )
+        {
+            shapenum = powerpics + 6;
+        }
+        else if ( player->flags & FL_GASMASK )
+        {
+            shapenum = powerpics + 5;
+        }
+        else if ( player->flags & FL_AV )
+        {
+            shapenum = powerpics + 7;
+        }
+
+        shape = ( pic_t * )W_CacheLumpNum( shapenum, PU_CACHE, Cvt_pic_t, 1 );
+
+        GameMemToScreen( eraseb, POWERUP2X + topBarCenterOffsetX, POWERUPY, bufferofsonly );
+
+        DrawMPPic( POWERUP2X + topBarCenterOffsetX, POWERUPY + protectionheight, shape->width,
+                   shape->height - protectionheight, protectionheight,
+                   ( byte * )&shape->data, bufferofsonly );
+    }
+}
+
+
+//******************************************************************************
+//
+// ShortenCodeName()
+//
+//******************************************************************************
+void GetShortCodeName
+(
+    char *dest,
+    char *source,
+    int  maxwidth
+)
+
+{
+    int width;
+    int height;
+    int length;
+
+    strcpy( dest, source );
+
+    // Shorten name to fit
+    length = strlen( dest );
+    VW_MeasurePropString( dest, &width, &height );
+    while( width > maxwidth )
+    {
+        dest[ length ] = 0;
+        length--;
+        VW_MeasurePropString( dest, &width, &height );
+    }
+}
+
+
+//******************************************************************************
+//
+// DrawKills ()
+//
+//******************************************************************************
+void DrawKills
+(
+    boolean bufferofsonly
+)
+{
+    int  rank;
+    int  xpos;
+    char codename[ MAXCODENAMELENGTH ];
+    int  width;
+    int  playernum;
+    int  playerimage;
+    int  temp;
+    int  iKILLS_Y;
+    pic_t *pic;
+
+    CurrentFont = tinyfont;
+
+    if ( SHOW_TOP_STATUS_BAR() )
+    {
+        playernum   = BATTLE_Team[ consoleplayer ];
+        playerimage = BATTLE_TeamLeader[ playernum ];
+
+        // Set uniformcolor
+        playeruniformcolor = PLAYERSTATE[ playerimage ].uniformcolor;
+
+        // Draw player's point box
+        pic = men[ PLAYERSTATE[ playerimage ].player ];
+        if ( ( gamestate.ShowScores ) && ( BATTLE_Points[ playernum ] < 0 ) )
+        {
+            pic = menneg[ PLAYERSTATE[ playerimage ].player ];
+        }
+
+        DrawPPic( MEN_X, MEN_Y, pic->width, pic->height,
+                  ( byte * )&pic->data, 1, true, bufferofsonly );
+
+        // Draw player's name
+        if ( gamestate.teamplay )
+        {
+            GetShortCodeName( codename, colorname[ playeruniformcolor ],
+                              42 );
+        }
+        else
+        {
+            GetShortCodeName( codename, PLAYERSTATE[ playerimage ].codename,
+                              42 );
+        }
+
+        DrawGameString ( MEN_X + 2, MEN_Y + 2, codename, bufferofsonly );
+        // Draw "It" if player is 'it'
+        if ( ( ( gamestate.battlemode == battle_Tag ) ||
+                ( gamestate.battlemode == battle_Hunter ) ) &&
+                ( BATTLE_It == BATTLE_Team[ consoleplayer ] ) )
+        {
+            DrawGameString ( MEN_X + 22, MEN_Y + 8,
+                             "It", bufferofsonly);
+        }
+
+        // Draw triad if player is 'it' or has caught a triad
+        if ( PLAYER[ consoleplayer ]->flags & FL_DESIGNATED )
+        {
+            pic = W_CacheLumpName( "smalltri", PU_CACHE, Cvt_pic_t, 1 );
+            DrawPPic( TRIAD_X - 1, TRIAD_Y - 2, pic->width, pic->height,
+                      ( byte * )&pic->data, 1, true, bufferofsonly );
+        }
+        else if ( ( gamestate.ShowScores ) &&
+                  ( DisplayPoints != bo_kills_infinite ) )
+        {
+            // Draw Kill goal
+            if ( ( gamestate.battlemode == battle_Collector ) ||
+                    ( gamestate.battlemode == battle_StandAloneGame ) )
+            {
+                temp = BATTLE_NumCollectorItems;
+            }
+            else
+            {
+                temp = DisplayPoints;
+            }
+
+            ltoa ( temp % 1000, KillStr.str, 10);
+            KillStr.length = strlen (KillStr.str);
+            DrawNumber (TRIAD_X - 6, TRIAD_Y, 3, 5, bufferofsonly);
+        }
+
+        // Set uniformcolor
+        playeruniformcolor = PLAYERSTATE[ consoleplayer ].uniformcolor;
+
+        if ( gamestate.ShowScores )
+        {
+            // Draw local player's points
+            temp = BATTLE_Points[ playernum ] % 1000;
+            if ( temp < 0 )
+            {
+                temp = -temp;
+            }
+            ltoa ( temp, KillStr.str, 10);
+            KillStr.length = strlen (KillStr.str);
+
+            DrawNumber( LIVES_X - 12, LIVES_Y, 3, 4, bufferofsonly);
+        }
+        else
+        {
+            pic = W_CacheLumpName( "minus", PU_CACHE, Cvt_pic_t, 1 );
+            StatusDrawColoredPic( LIVES_X - 12, LIVES_Y, pic, bufferofsonly, playeruniformcolor );
+            StatusDrawColoredPic( LIVES_X - 4, LIVES_Y, pic, bufferofsonly, playeruniformcolor );
+        }
+
+        // Draw whoever is 'It'
+        playernum   = BATTLE_It;
+        playerimage = BATTLE_TeamLeader[ playernum ];
+
+        // Set uniformcolor
+        playeruniformcolor = PLAYERSTATE[ playerimage ].uniformcolor;
+
+        // Draw player's point box
+        pic = men[ PLAYERSTATE[ playerimage ].player ];
+        if ( ( gamestate.ShowScores ) && ( BATTLE_Points[ playernum ] < 0 ) )
+        {
+            pic = menneg[ PLAYERSTATE[ playerimage ].player ];
+        }
+
+        DrawPPic( LEADER_X, LEADER_Y, pic->width, pic->height,
+                  (byte *)&pic->data, 1, true, bufferofsonly );
+
+        if ( ( gamestate.battlemode == battle_Tag ) ||
+                ( gamestate.battlemode == battle_Hunter ) )
+        {
+            DrawGameString ( LEADER_X + 22, LEADER_Y + 8,
+                             "It", bufferofsonly);
+        }
+
+        if ( gamestate.ShowScores )
+        {
+            // Draw number of points
+            temp = BATTLE_Points[ playernum ] % 1000;
+            if ( temp < 0 )
+            {
+                temp = -temp;
+            }
+            ltoa ( temp, KillStr.str, 10);
+            KillStr.length = strlen (KillStr.str);
+            DrawNumber ( LEADER_NUM_X, LEADER_NUM_Y, 3, 4, bufferofsonly);
+        }
+        else
+        {
+            pic = W_CacheLumpName( "minus", PU_CACHE, Cvt_pic_t, 1 );
+            StatusDrawColoredPic( LEADER_NUM_X, LEADER_NUM_Y, pic, bufferofsonly, playeruniformcolor );
+            StatusDrawColoredPic( LEADER_NUM_X + 8, LEADER_NUM_Y, pic, bufferofsonly, playeruniformcolor );
+        }
+
+        // Draw name
+        if ( gamestate.teamplay )
+        {
+            DrawGameString ( LEADER_NAME_X, LEADER_NAME_Y - 1,
+                             colorname[ playeruniformcolor ], bufferofsonly);
+        }
+        else
+        {
+            GetShortCodeName( codename, PLAYERSTATE[ playerimage ].codename,
+                              42 );
+            DrawGameString ( LEADER_NAME_X - 1, LEADER_NAME_Y,
+                             codename, bufferofsonly);
+        }
+    }
+
+    // Only draw the rest of the rifraff when the kill count is selected
+
+    if ( !SHOW_KILLS() )
+    {
+        return;
+    }
+//	 SetTextMode (  );
+    // Draw all the other losers
+    //#define KILLS_Y      176
+    iKILLS_Y = iGLOBAL_SCREENHEIGHT - 24;
+    //draw blank status  pic->width = 8;pic->height = 24
+    pic = blankfragpic;
+    for (temp = iGLOBAL_SCREENWIDTH-pic->width-24; temp > pic->width; temp -= pic->width) {
+        DrawPPic( temp, iKILLS_Y, pic->width, pic->height,
+                  (byte *)&pic->data, 1, true, bufferofsonly );
+
+    }
+
+    xpos = KILLS_X;
+    for( rank = 0; rank < BATTLE_NumberOfTeams; rank++ )
+    {
+        playernum   = BATTLE_PlayerOrder[ rank ];
+        playerimage = BATTLE_TeamLeader[ playernum ];
+
+        if ( ( playernum == BATTLE_It ) && SHOW_TOP_STATUS_BAR() )
+        {
+            continue;
+        }
+
+        // Set uniformcolor
+        playeruniformcolor = PLAYERSTATE[ playerimage ].uniformcolor;
+
+        // Draw player's point box
+        pic = fragpic[ PLAYERSTATE[ playerimage ].player ];
+        if ( gamestate.ShowScores )
+        {
+            if ( BATTLE_Points[ playernum ] < 0 )
+            {
+                pic = negfragpic[ PLAYERSTATE[ playerimage ].player ];
+            }
+            else if ( BATTLE_Points[ playernum ] >= 100 )
+            {
+                pic = frag100pic[ PLAYERSTATE[ playerimage ].player ];
+            }
+        }
+        DrawPPic( xpos, iKILLS_Y, pic->width, pic->height,
+                  (byte *)&pic->data, 1, true, bufferofsonly );
+
+        // Draw number of points
+        if ( gamestate.ShowScores )
+        {
+            temp = BATTLE_Points[ playernum ] % 1000;
+            if ( temp < 0 )
+            {
+                temp = -temp;
+            }
+            ltoa ( temp, KillStr.str, 10);
+            KillStr.length = strlen (KillStr.str);
+            width = 2;
+            if ( temp > 99 )
+            {
+                width = 3;
+            }
+            DrawNumber( xpos + KILLS_OFFSET + 16 - ( 8 * width ), iKILLS_Y, width, 4, bufferofsonly);
+        }
+        else
+        {
+            pic =  ( pic_t * )W_CacheLumpName( "minus", PU_CACHE, Cvt_pic_t, 1 );
+            StatusDrawColoredPic( ( xpos + KILLS_OFFSET ), iKILLS_Y, pic, bufferofsonly, playeruniformcolor );
+            StatusDrawColoredPic( ( xpos + KILLS_OFFSET + 8 ), iKILLS_Y, pic, bufferofsonly, playeruniformcolor );
+        }
+
+        // Get codename
+        if ( gamestate.teamplay )
+        {
+            GetShortCodeName( codename, colorname[ playeruniformcolor ],
+                              KILLS_WIDTH - 2 );
+        }
+        else
+        {
+            GetShortCodeName( codename, PLAYERSTATE[ playerimage ].codename,
+                              KILLS_WIDTH - 2 );
+        }
+
+        // Draw name
+        DrawGameString (xpos + 1, KILLS_NAME_Y, codename, bufferofsonly);
+
+        // Advance to next position
+        xpos += KILLS_WIDTH;
+
+        if ( xpos >= iGLOBAL_SCREENWIDTH )
+        {
+            break;
+        }
+    }
+
+    for( rank = BATTLE_NumberOfTeams; rank <= MAXKILLBOXES; rank++ )
+    {
+        if ( xpos >= iGLOBAL_SCREENWIDTH )
+        {
+            break;
+        }
+
+        pic = blankfragpic;
+        DrawPPic( xpos, iKILLS_Y, pic->width, pic->height,
+                  (byte *)&pic->data, 1, true, bufferofsonly );
+
+        // Advance to next position
+        xpos += KILLS_WIDTH;
+    }
+}
+
+
+//******************************************************************************
+//
+// DrawPlayers ()
+//
+//******************************************************************************
+void DrawPlayers
+(
+    void
+)
+
+{
+    int    num;
+    int    xpos;
+    char   codename[ MAXCODENAMELENGTH ];
+    int    length;
+    int    width;
+    int    height;
+    int    team;
+    int    player;
+    int    character;
+    pic_t *pic;
+    pic_t *enemy;
+    pic_t *friend;
+
+    num = W_GetNumForName( "botpic1" );
+
+    scorenums[ 0 ]= ( pic_t * )W_CacheLumpName( "kilnum0", PU_CACHE, Cvt_pic_t, 1 );
+    friend = ( pic_t * )W_CacheLumpName( "t_friend", PU_CACHE, Cvt_pic_t, 1 );
+    enemy  = ( pic_t * )W_CacheLumpName( "t_enemy", PU_CACHE, Cvt_pic_t, 1 );
+
+    // Draw all the losers
+    CurrentFont = tinyfont;
+
+    xpos = (iGLOBAL_SCREENWIDTH  - min( numplayers, MAXKILLBOXES ) * KILLS_WIDTH ) / 2;
+//SetTextMode (  );//PLAYERSTATE
+    for( team = 0; team < BATTLE_NumberOfTeams; team++ )
+    {
+        for( player = 0; player < numplayers; player++ )
+        {
+            if ( BATTLE_Team[ player ] == team )
+            {
+                character = PLAYERSTATE[ player ].player;
+
+                fragpic[ character ] = ( pic_t * )W_CacheLumpNum( num +
+                                       character, PU_CACHE, Cvt_pic_t, 1 );
+
+                if ( ( numplayers <= MAXKILLBOXES ) ||
+                        ( player != consoleplayer ) )
+                {
+                    // Set uniformcolor
+                    playeruniformcolor = PLAYERSTATE[ player ].uniformcolor;
+
+                    // Draw player's point box
+                    pic = fragpic[ PLAYERSTATE[ player ].player ];
+
+                    VWB_DrawPic ( xpos, PLAYERS_Y, pic );
+                    if ( gamestate.teamplay )
+                    {
+                        if ( BATTLE_Team[ player ] == BATTLE_Team[ consoleplayer ] )
+                        {
+                            VWB_DrawPic ( xpos, PLAYERS_TEAM_Y, friend );
+                        }
+                        else
+                        {
+                            VWB_DrawPic ( xpos, PLAYERS_TEAM_Y, enemy );
+                        }
+                    }
+
+                    strcpy( KillStr.str, "00" );
+                    KillStr.length = strlen ( KillStr.str );
+                    DrawNumber( xpos + KILLS_OFFSET, PLAYERS_Y, 2, 4, true );
+
+                    // Get codename
+                    strcpy( codename, PLAYERSTATE[ player ].codename );
+
+                    // Shorten name to fit into point count
+                    length = strlen( codename );
+                    US_MeasureStr( &width, &height, "%s", codename );
+                    while( width > KILLS_WIDTH )
+                    {
+                        codename[ length ] = 0;
+                        length--;
+                        US_MeasureStr( &width, &height, "%s", codename );
+                    }
+
+                    // Draw name
+                    PrintX = xpos;
+                    PrintY = PLAYERS_NAME_Y;
+                    US_Print( codename );
+
+                    // Advance to next position
+                    xpos += KILLS_WIDTH;
+                }
+            }
+            if ( xpos >= iGLOBAL_SCREENWIDTH )
+            {
+                break;
+            }
+        }
+        if ( xpos >= iGLOBAL_SCREENWIDTH )
+        {
+            break;
+        }
+    }
+}
+
+//******************************************************************************
+//
+// StatusDrawPic ()
+//
+//******************************************************************************
+
+void StatusDrawPic (unsigned x, unsigned y, pic_t *nums, boolean bufferofsonly)
+{
+    DrawMPPic (x, y, nums->width, nums->height, 0,
+               (byte *)&nums->data, bufferofsonly);
+}
+
+//******************************************************************************
+//
+// StatusDrawColoredPic ()
+//
+//******************************************************************************
+
+void StatusDrawColoredPic (unsigned x, unsigned y, pic_t *nums, boolean bufferofsonly, int color)
+{
+    DrawColoredMPPic (x, y, nums->width, nums->height, 0,
+                      (byte *)&nums->data, bufferofsonly, color);
+}
+
+//******************************************************************************
+//
+// DrawGameString ()
+//
+// draw string to game screen at x,y
+//
+//******************************************************************************
+
+void DrawGameString (int x, int y, const char * str, boolean bufferofsonly)
+{
+    byte *tempbuf;
+
+    px=x;
+    py=y;
+
+    if (bufferofsonly==true)
+        VW_DrawPropString (str);
+    else
+    {
+        tempbuf=bufferofs;
+        bufferofs=page1start;
+        VW_DrawPropString (str);
+#ifdef DOS
+        px=x;
+        py=y;
+        bufferofs=page2start;
+        VW_DrawPropString (str);
+        px=x;
+        py=y;
+        bufferofs=page3start;
+        VW_DrawPropString (str);
+#endif
+        bufferofs=tempbuf;
+    }
+}
+
+
+//******************************************************************************
+//
+// DrawNumber ()
+//
+// right justifies and pads with zeros
+//
+//******************************************************************************
+
+void DrawNumber (int x, int y, int width, int which, boolean bufferofsonly)
+{
+    unsigned length,c;
+    char  *str;
+    byte z;
+
+    switch (which)
+    {
+    case 1:
+        str = ScoreStr.str;
+        length = ScoreStr.length;
+        break;
+
+    case 2:
+        str = LivesStr.str;
+        length = LivesStr.length;
+        break;
+
+    case 3:
+        str = TriadStr.str;
+        length = TriadStr.length;
+        break;
+
+    case 4:
+    case 5:
+    case 6:
+        str = KillStr.str;
+        length = KillStr.length;
+        break;
+    }
+
+    z = width - length;     // Num zeros
+
+    while (z)
+    {
+        switch (which)
+        {
+        case 1:
+            StatusDrawPic (x, y, scorenums[0], bufferofsonly);
+            x+=8;
+            break;
+        case 2:
+            StatusDrawPic (x, y, lifenums[0], bufferofsonly);
+            x+=8;
+            break;
+        case 3:
+            StatusDrawPic (x, y, lifeptnums[0], bufferofsonly);
+            x+=6;
+            break;
+        case 4:
+            StatusDrawColoredPic (x, y, scorenums[0], bufferofsonly, playeruniformcolor);
+            x+=8;
+            break;
+        case 5:
+            StatusDrawPic (x, y, lifeptnums[0], bufferofsonly);
+            x+=6;
+            break;
+        case 6:
+            StatusDrawPic (x, y, lifenums[0], bufferofsonly);
+            x+=8;
+            break;
+        }
+        z--;
+    }
+
+    c = length <= (unsigned)width ? 0 : length-width;
+    while (c < length)
+    {
+        switch (which)
+        {
+        case 1:
+            StatusDrawPic (x, y, scorenums[str[c]-'0'], bufferofsonly);
+            x+=8;
+            break;
+        case 2:
+            StatusDrawPic (x, y, lifenums[str[c]-'0'], bufferofsonly);
+            x+=8;
+            break;
+        case 3:
+            StatusDrawPic (x, y, lifeptnums[str[c]-'0'], bufferofsonly);
+            x+=6;
+            break;
+        case 4:
+            StatusDrawColoredPic (x, y, scorenums[str[c]-'0'], bufferofsonly, playeruniformcolor);
+            x+=8;
+            break;
+        case 5:
+            StatusDrawPic (x, y, lifeptnums[str[c]-'0'], bufferofsonly);
+            x+=6;
+            break;
+        case 6:
+            StatusDrawPic (x, y, lifenums[str[c]-'0'], bufferofsonly);
+            x+=8;
+            break;
+        }
+        c++;
+    }
+}
+
+
+
+//******************************************************************************
+//
+// HealPlayer ()
+//
+//******************************************************************************
+
+void HealPlayer
+(
+    int      points,
+    objtype *ob
+)
+
+{
+    playertype *pstate;
+    int maxhitpoints;
+
+    M_LINKSTATE( ob, pstate );
+
+    pstate->health += points;
+    maxhitpoints = MaxHitpointsForCharacter( pstate );
+    if ( pstate->health > maxhitpoints )
+    {
+        pstate->health = maxhitpoints;
+    }
+
+    if ( ( SHOW_BOTTOM_STATUS_BAR() ) && ( ob == player ) )
+    {
+        DrawBarHealth( false );
+    }
+}
+
+//******************************************************************************
+//
+// DrawLives ()
+//
+//******************************************************************************
+
+void DrawLives
+(
+    boolean bufferofsonly
+)
+
+{
+    if ( !SHOW_TOP_STATUS_BAR() )
+    {
+        return;
+    }
+
+    if ( !EndLevelStuff )
+    {
+        DrawNumber( LIVES_X + topBarCenterOffsetX, LIVES_Y, 2, 2, bufferofsonly );
+    }
+}
+
+
+//******************************************************************************
+//
+// GiveExtraMan ()
+//
+//******************************************************************************
+
+void  GiveExtraMan (void)
+{
+    if (locplayerstate->lives < 99)
+        locplayerstate->lives++;
+    UpdateLives (locplayerstate->lives);
+    DrawLives (false);
+//   SD_PlaySound (BONUS1UPSND);
+}
+
+
+
+//******************************************************************************
+//
+// DrawScore ()
+//
+//******************************************************************************
+
+void DrawScore
+(
+    boolean bufferofsonly
+)
+
+{
+    if ( !SHOW_TOP_STATUS_BAR() )
+    {
+        return;
+    }
+
+    if ( !BATTLEMODE )
+    {
+        DrawNumber( SCORE_X + topBarCenterOffsetX, SCORE_Y, 10, 1, bufferofsonly );
+    }
+}
+
+
+//******************************************************************************
+//
+// GivePoints ()
+//
+//******************************************************************************
+
+void  GivePoints (long points)
+{
+    gamestate.score += points;
+
+    UpdateScore (gamestate.score);
+
+    if (!EndLevelStuff)
+        DrawScore (false);
+}
+
+
+//******************************************************************************
+//
+// GiveKey ()
+//
+//******************************************************************************
+
+void GiveKey (int key)
+{
+    locplayerstate->keys |= (1<<key);
+    DrawKeys (false);
+}
+
+
+//******************************************************************************
+//
+// GiveLives ()
+//
+//******************************************************************************
+
+void GiveLives (int newlives)
+{
+    if ((locplayerstate->lives + newlives) <= 99)
+        locplayerstate->lives += newlives;
+    else
+        locplayerstate->lives = 99;
+    UpdateLives (locplayerstate->lives);
+    DrawLives (false);
+}
+
+
+#define EnableOldWeapon(pstate)    \
+   {                               \
+   LASTSTAT->flags |= FL_ABP;      \
+   LASTSTAT->flags &= ~FL_RESPAWN; \
+   MakeStatActive(LASTSTAT);       \
+   pstate->weaponx = ob->tilex;    \
+   pstate->weapony = ob->tiley;    \
+   }
+
+
+//******************************************************************************
+//
+// GiveWeapon ()
+//
+//******************************************************************************
+
+void GiveWeapon
+(
+    objtype *ob,
+    int weapon
+)
+
+{
+    playertype *pstate;
+
+    M_LINKSTATE( ob, pstate );
+
+    if ( pstate->weapon == weapon )
+    {
+        return;
+    }
+
+    pstate->HASBULLETWEAPON[ weapon ] = 1;
+    if ( ( pstate->weapon == pstate->bulletweapon ) &&
+            ( pstate->weapon < weapon ) )
+    {
+        pstate->new_weapon = weapon;
+        pstate->weapondowntics = WEAPONS[ pstate->weapon ].screenheight / GMOVE;
+        if ( ( ob == player ) && ( SHOW_BOTTOM_STATUS_BAR() ) )
+        {
+            DrawBarAmmo( false );
+        }
+    }
+
+    if ( gamestate.BattleOptions.WeaponPersistence )
+    {
+        SpawnStatic(ob->tilex,ob->tiley,GetItemForWeapon(weapon),9);
+        EnableOldWeapon(pstate);
+    }
+
+    if ( weapon > pstate->bulletweapon )
+    {
+        pstate->bulletweapon = weapon;
+    }
+}
+
+//LT added
+//******************************************************************************
+//
+// GivePlayerAmmo ()
+//
+//******************************************************************************
+
+
+void GivePlayerAmmo(objtype *ob, statobj_t *item_pickup, int which)
+{
+    playertype * pstate;
+
+    M_LINKSTATE(ob, pstate);
+
+    signed char * playerCurrentAmmo = pstate->ammo;
+    signed char * ammoInItem = item_pickup->ammo;
+    signed char * maxAmmoInWeapon = stats[item_pickup->itemnumber].ammo;
+    signed char newAmmoAmount = (signed char)((int)ammoInItem + (int)playerCurrentAmmo);
+
+    if (newAmmoAmount > maxAmmoInWeapon)
+    {
+        ammoInItem = (signed char)((int)newAmmoAmount - (int)maxAmmoInWeapon);
+        if (ammoInItem < 0)
+        {
+            Error("Ammo in item cannot be set to a negative number!");
+        }
+        item_pickup->ammo = ammoInItem;
+        newAmmoAmount = maxAmmoInWeapon;
+    }
+    else
+    {
+        ammoInItem = 0;
+    }
+    pstate->ammo = newAmmoAmount;
+
+    //if (!gamestate.BattleOptions.WeaponPersistence)
+    //{
+    if (pstate->ammo &&
+        (pstate->missileweapon != -1) &&
+        (!(WEAPON_IS_MAGICAL(which))) &&
+        (!(WEAPON_IS_MAGICAL(pstate->missileweapon))))
+        {
+            int nx,ny;
+
+
+            nx = ob->tilex;
+            ny = ob->tiley;
+
+            //If the missile weapon still has ammo in it after taking ammo from it, spawn it on the ground
+            if (ammoInItem)
+            {
+                if (IsPlatform(nx,ny))
+                    SpawnStatic(nx,ny,GetItemForWeapon(pstate->missileweapon),9);
+                else
+                {
+                    int newz = sprites[ob->tilex][ob->tiley]->z;
+                    SpawnStatic(nx,ny,GetItemForWeapon(pstate->missileweapon),-1);
+                    LASTSTAT->z = newz;
+                }
+
+                //update ammo count on missile weapon on ground
+                LASTSTAT->ammo = ammoInItem;
+                EnableOldWeapon(pstate);
+            }
+
+
+        }
+    //}
+}
+
+//******************************************************************************
+//
+// GiveMissileWeapon ()
+//
+//******************************************************************************
+
+void GiveMissileWeapon(objtype * ob, int which)
+{
+    playertype * pstate;
+
+
+    //pstate = (ob==player)?(&playerstate):(&remoteplayerstate);
+    M_LINKSTATE(ob,pstate);
+
+    if (!gamestate.BattleOptions.WeaponPersistence)
+    {
+        if (pstate->ammo &&
+                (pstate->missileweapon != -1) &&
+                (!(WEAPON_IS_MAGICAL(which))) &&
+                (!(WEAPON_IS_MAGICAL(pstate->missileweapon)))
+           )
+        {
+            int nx,ny;
+
+
+            nx = ob->tilex;
+            ny = ob->tiley;
+            //FindEmptyTile(&nx,&ny);
+
+            if (IsPlatform(nx,ny))
+                SpawnStatic(nx,ny,GetItemForWeapon(pstate->missileweapon),9);
+            else
+            {
+                int newz = sprites[ob->tilex][ob->tiley]->z;
+                SpawnStatic(nx,ny,GetItemForWeapon(pstate->missileweapon),-1);
+                LASTSTAT->z = newz;
+            }
+            LASTSTAT->ammo = pstate->ammo;
+            EnableOldWeapon(pstate);
+
+        }
+    }
+
+    else if (!WEAPON_IS_MAGICAL(which))
+    {
+        int newz = sprites[ob->tilex][ob->tiley]->z;
+        SpawnStatic(ob->tilex,ob->tiley,GetItemForWeapon(which),9);
+        LASTSTAT->z = newz;
+        EnableOldWeapon(pstate);
+
+    }
+    pstate->new_weapon = pstate->missileweapon = which;
+    pstate->weapondowntics = WEAPONS[pstate->weapon].screenheight/GMOVE;
+
+
+}
+
+
+//******************************************************************************
+//
+// DrawKeys ()
+//
+//******************************************************************************
+
+void DrawKeys(boolean bufferofsonly)
+{
+    if ( !SHOW_TOP_STATUS_BAR() )
+    {
+        return;
+    }
+
+    if ( locplayerstate->keys & 1 )
+    {
+        GameMemToScreen( keys[ 0 ], KeyX[ 0 ] + topBarCenterOffsetX, KEY_Y, bufferofsonly );
+    }
+
+    if ( locplayerstate->keys & 2 )
+    {
+        GameMemToScreen( keys[ 1 ], KeyX[ 1 ] + topBarCenterOffsetX, KEY_Y, bufferofsonly );
+    }
+
+    if ( locplayerstate->keys & 4 )
+    {
+        GameMemToScreen( keys[ 2 ], KeyX[ 2 ] + topBarCenterOffsetX, KEY_Y, bufferofsonly );
+    }
+
+    if ( locplayerstate->keys & 8 )
+    {
+        GameMemToScreen( keys[ 3 ], KeyX[ 3 ] + topBarCenterOffsetX, KEY_Y, bufferofsonly );
+    }
+}
+
+
+//******************************************************************************
+//
+// StatusDrawTime ()
+//
+//******************************************************************************
+
+void StatusDrawTime
+(
+    unsigned x,
+    unsigned y,
+    unsigned num,
+    boolean  bufferofsonly
+)
+
+{
+    DrawMPPic( x, y, timenums[ num ]->width, timenums[ num ]->height, 0,
+               ( byte * )&timenums[ num ]->data, bufferofsonly );
+}
+
+
+//******************************************************************************
+//
+// DrawTimeNumber ()
+//
+// right justifies and pads with blanks
+//
+//******************************************************************************
+
+void DrawTimeNumber (int x, int y, int number, boolean seconds, boolean bufferofsonly)
+{
+    char  str[20];
+
+    ltoa (number,str,10);
+
+    if (seconds)
+    {
+        if (number < 10)
+        {
+            StatusDrawTime (x,   y, 0, bufferofsonly);
+            StatusDrawTime (x+8, y, str[0]-'0', bufferofsonly);
+        }
+        else
+        {
+            StatusDrawTime (x,   y, str[0]-'0', bufferofsonly);
+            StatusDrawTime (x+8, y, str[1]-'0', bufferofsonly);
+        }
+    }
+    else
+    {
+        if (number < 10)
+            StatusDrawTime (x+8, y, str[0]-'0', bufferofsonly);
+        else
+        {
+            StatusDrawTime (x,   y, str[0]-'0', bufferofsonly);
+            StatusDrawTime (x+8, y, str[1]-'0', bufferofsonly);
+        }
+    }
+}
+
+
+//******************************************************************************
+//
+// DrawTimeXY ()
+//
+//******************************************************************************
+
+void DrawTimeXY
+(
+    int x,
+    int y,
+    int sec,
+    boolean bufferofsonly
+)
+
+{
+    int min;
+    int hour;
+
+    while (sec > ( ( 9 * 3600 ) + 3599 ) )
+    {
+        sec -= ( ( 9 * 3600 ) + 3599 );
+    }
+
+    hour  = sec / 3600;
+    min   = ( sec / 60 ) - ( hour * 60 );
+    sec  %= 60;
+
+    DrawTimeNumber ( x + HOUR_X, y, hour, false, bufferofsonly );
+    DrawTimeNumber ( x + MIN_X, y, min, true, bufferofsonly );
+    DrawTimeNumber ( x + SEC_X, y, sec, true, bufferofsonly );
+}
+
+
+//******************************************************************************
+//
+// DrawTime ()
+//
+//******************************************************************************
+
+void DrawTime
+(
+    boolean bufferofsonly
+)
+
+{
+    int sec;
+
+    if ( !SHOW_TOP_STATUS_BAR() )
+    {
+        return;
+    }
+
+    if (timelimitenabled == true)
+    {
+        sec = (timelimit-gamestate.TimeCount) / VBLCOUNTER;
+    }
+    else
+    {
+        sec = gamestate.TimeCount / VBLCOUNTER;
+    }
+
+    if ( oldsec != sec )
+    {
+        oldsec = sec;
+        DrawTimeXY( GAMETIME_X + topBarCenterOffsetX, GAMETIME_Y, sec, bufferofsonly) ;
+    }
+}
+
+
+//******************************************************************************
+//
+// DrawMPPic ()
+//
+// Purpose
+//    Draws a masked, planer pic at xpos, ypos.
+//
+// Parms
+//    xpos   - x position.
+//    ypos   - y position.
+//    width  - width of pic : should be << 2.
+//    height - height of pic.
+//    src    - data to draw.
+//
+// Returns
+//    Nothing.
+//
+//******************************************************************************
+
+void DrawMPPic (int xpos, int ypos, int width, int height, int heightmod, byte *src, boolean bufferofsonly)
+{
+    int olddest;
+    int dest;
+    int x;
+    int y;
+    int planes;
+    byte mask;
+    byte pixel;
+
+    mask = 1 << (xpos&3);
+
+#ifdef DOS
+    olddest = ylookup[ypos] + (xpos>>2);
+#else
+    olddest = ylookup[ypos] + xpos;
+#endif
+
+    for (planes = 0; planes < 4; planes++)
+    {
+        VGAMAPMASK (mask);
+
+        dest = olddest;
+
+#ifndef DOS
+        dest += planes;
+#endif
+
+        for (y = 0; y < height; y++)
+        {
+            for (x = 0; x < width; x++)
+            {
+                pixel = *src++;
+
+                if (pixel != 255)
+                {
+                    if (bufferofsonly)
+                        *(dest+bufferofs) = pixel;
+                    else
+                    {
+                        *(dest+page1start) = pixel;
+                        *(dest+page2start) = pixel;
+                        *(dest+page3start) = pixel;
+                    }
+                }
+
+#ifdef DOS
+                dest++;
+#else
+                dest += 4;
+#endif
+            }
+
+#ifdef DOS
+            dest += (linewidth-width);
+#else
+            dest += (linewidth-width*4);
+#endif
+        }
+
+        if (heightmod)
+            src += (heightmod*width);
+
+#ifdef DOS
+        mask <<= 1;
+        if (mask == 16)
+        {
+            mask = 1;
+            olddest++;
+        }
+#endif
+    }
+}
+
+
+//******************************************************************************
+//
+// DrawColoredMPPic ()
+//
+// Purpose
+//    Draws a masked, planer pic at xpos, ypos.
+//
+// Parms
+//    xpos   - x position.
+//    ypos   - y position.
+//    width  - width of pic : should be << 2.
+//    height - height of pic.
+//    src    - data to draw.
+//
+// Returns
+//    Nothing.
+//
+//******************************************************************************
+
+void DrawColoredMPPic (int xpos, int ypos, int width, int height, int heightmod, byte *src, boolean bufferofsonly, int color)
+{
+    int olddest;
+    int dest;
+    int x;
+    int y;
+    int planes;
+    byte mask;
+    byte pixel;
+    byte * cmap;
+
+    cmap=playermaps[color]+(1<<12);
+
+    mask = 1 << (xpos&3);
+
+#ifdef DOS
+    olddest = ylookup[ypos] + (xpos>>2);
+#else
+    olddest = ylookup[ypos] + xpos;
+#endif
+
+    for (planes = 0; planes < 4; planes++)
+    {
+        VGAMAPMASK (mask);
+
+        dest = olddest;
+
+#ifndef DOS
+        dest += planes;
+#endif
+
+        for (y = 0; y < height; y++)
+        {
+            for (x = 0; x < width; x++)
+            {
+                pixel = *src++;
+
+                pixel = *(cmap+pixel);
+
+                if (pixel != 255)
+                {
+                    if (bufferofsonly)
+                        *(dest+bufferofs) = pixel;
+                    else
+                    {
+                        *(dest+page1start) = pixel;
+                        *(dest+page2start) = pixel;
+                        *(dest+page3start) = pixel;
+                    }
+                }
+
+#ifdef DOS
+                dest++;
+#else
+                dest += 4;
+#endif
+            }
+
+#ifdef DOS
+            dest += (linewidth-width);
+#else
+            dest += (linewidth-width*4);
+#endif
+        }
+
+        if (heightmod)
+            src += (heightmod*width);
+
+#ifdef DOS
+        mask <<= 1;
+        if (mask == 16)
+        {
+            mask = 1;
+            olddest++;
+        }
+#endif
+    }
+}
+
+
+//******************************************************************************
+//
+// UpdateScore ()
+//
+//******************************************************************************
+
+void UpdateScore (unsigned int num)
+{
+    if (num > 999999999)
+    {
+        num = 999999999;
+        gamestate.score = 999999999;
+    }
+
+    ltoa (num, ScoreStr.str, 10);
+    ScoreStr.length = strlen (ScoreStr.str);
+}
+
+
+//******************************************************************************
+//
+// UpdateLives ()
+//
+//******************************************************************************
+
+void UpdateLives (int num)
+{
+    ltoa (num, LivesStr.str, 10);
+    LivesStr.length = strlen (LivesStr.str);
+}
+
+//****************************************************************************
+//
+// ClearTriads ()
+//
+//****************************************************************************
+void ClearTriads (playertype * pstate)
+{
+    pstate->triads = 0;
+    ltoa (pstate->triads, TriadStr.str, 10);
+    TriadStr.length = strlen (TriadStr.str);
+}
+
+//****************************************************************************
+//
+// UpdateTriads ()
+//
+//****************************************************************************
+
+void UpdateTriads (objtype * ob, int num)
+{
+    playertype * pstate;
+
+    M_LINKSTATE(ob,pstate);
+
+    pstate->triads += num;
+
+    if (pstate->triads >= 100)
+    {
+        GiveLives(1);
+        if (ob==player)
+        {
+            AddMessage("100 Life Item Points!  Extra Life!",MSG_BONUS);
+            SD_PlaySoundRTP (SD_GET1UPSND, player->x, player->y);
+        }
+        pstate->triads -= 100;
+    }
+
+    if (ob==player)
+    {
+        ltoa (pstate->triads, TriadStr.str, 10);
+        TriadStr.length = strlen (TriadStr.str);
+    }
+}
+
+//****************************************************************************
+//
+// DrawTriads ()
+//
+//****************************************************************************
+
+void DrawTriads(boolean bufferofsonly)
+
+{
+    if ( !SHOW_TOP_STATUS_BAR() )
+    {
+        return;
+    }
+
+    if ( !EndLevelStuff )
+    {
+        DrawNumber( TRIAD_X + topBarCenterOffsetX, TRIAD_Y, 2, 3, bufferofsonly );
+    }
+}
+
+
+//******************************************************************************
+//
+// DrawPPic ()
+//
+//******************************************************************************
+
+void DrawPPic (int xpos, int ypos, int width, int height, byte *src, int num, boolean up, boolean bufferofsonly)
+{
+    int olddest;
+    int dest;
+    int x;
+    int y;
+    int planes;
+    byte mask;
+    byte pixel;
+    int k;
+    int amt;
+
+#ifdef DOS
+    if (up)
+        amt = 2;
+    else
+        amt = -2;
+#else
+    if (up)
+        amt = 8;
+    else
+        amt = -8;
+#endif
+
+    mask = 1;
+
+#ifdef DOS
+    olddest = ylookup[ypos] + (xpos>>2);
+#else
+    olddest = ylookup[ypos] + xpos;
+#endif
+
+    for (planes = 0; planes < 4; planes++)
+    {
+        VGAMAPMASK (mask);
+
+        dest = olddest;
+
+#ifndef DOS
+        dest += planes;
+#endif
+
+        for (y = 0; y < height; y++)
+        {
+            for (x = 0; x < width; x++)
+            {
+                pixel = *src++;
+
+                if (pixel != 255)
+                {
+                    for (k = 0; k < num; k++)
+                    {
+                        if (bufferofsonly)
+                            *(dest+bufferofs+(amt*k)) = pixel;
+                        else
+                        {
+                            *(dest+page1start+(amt*k)) = pixel;
+                            *(dest+page2start+(amt*k)) = pixel;
+                            *(dest+page3start+(amt*k)) = pixel;
+                        }
+                    }
+                }
+
+#ifdef DOS
+                dest++;
+#else
+                dest += 4;
+#endif
+            }
+
+#ifdef DOS
+            dest += (linewidth-width);
+#else
+            dest += (linewidth-width*4);
+#endif
+        }
+
+        mask <<= 1;
+    }
+}
+
+
+//****************************************************************************
+//
+// DrawBarHealth ()
+//
+//****************************************************************************
+
+void DrawBarHealth
+(
+    boolean bufferofsonly
+)
+
+{
+    int percenthealth;
+    int health_y;
+
+    if ( !SHOW_BOTTOM_STATUS_BAR() )
+    {
+        return;
+    }
+
+    health_y = iGLOBAL_HEALTH_Y;
+    if ( SHOW_KILLS() )
+    {
+        health_y -= KILLS_HEIGHT;
+    }
+
+    percenthealth = ( locplayerstate->health * 10 ) /
+                    MaxHitpointsForCharacter( locplayerstate );
+
+    oldpercenthealth = percenthealth + 1;
+
+    if ( playstate == ex_died )
+    {
+        DrawPPic( iGLOBAL_HEALTH_X, health_y, 8 >> 2, 16, ( byte * )&erase->data,
+                  10, true, bufferofsonly );
+
+        return;
+    }
+
+    if ( locplayerstate->health <= 0 )
+    {
+        oldpercenthealth = 0;
+    }
+
+    if ( oldpercenthealth >= 11 )
+    {
+        oldpercenthealth = 10;
+    }
+
+    if ( oldpercenthealth < 4 )
+    {
+        DrawPPic( iGLOBAL_HEALTH_X, health_y, 8 >> 2, 16,
+                  ( byte * )&health[ 0 ]->data, oldpercenthealth,
+                  true, bufferofsonly );
+    }
+    else if ( oldpercenthealth < 5 )
+    {
+        DrawPPic( iGLOBAL_HEALTH_X, health_y, 8 >> 2, 16,
+                  (byte *)&health[ 1 ]->data, oldpercenthealth,
+                  true, bufferofsonly );
+    }
+    else
+    {
+        DrawPPic( iGLOBAL_HEALTH_X, health_y, 8 >> 2, 16,
+                  ( byte * )&health[ 2 ]->data, oldpercenthealth,
+                  true, bufferofsonly );
+    }
+
+    if ( oldpercenthealth < 10 )
+    {
+        DrawPPic( iGLOBAL_HEALTH_X + ( 8 * oldpercenthealth ), health_y,
+                  8 >> 2, 16, ( byte * )&erase->data, 10 - oldpercenthealth,
+                  true, bufferofsonly );
+    }
+}
+
+
+//****************************************************************************
+//
+// DrawBarAmmo ()
+//
+//****************************************************************************
+
+void DrawBarAmmo(boolean bufferofsonly)
+{
+    int ammo_y;
+
+    if ( ( !SHOW_BOTTOM_STATUS_BAR() ) || ( playstate == ex_died ) )
+    {
+        return;
+    }
+
+    ammo_y = iGLOBAL_AMMO_Y;
+    if ( SHOW_KILLS() )
+    {
+        ammo_y -= KILLS_HEIGHT;
+    }
+
+    DrawPPic ( iGLOBAL_AMMO_X, ammo_y + 1, 8 >> 2, 16, ( byte * )&erase->data,
+               10, false, bufferofsonly );
+
+    if ( !ARMED( player->dirchoosetime ) )
+    {
+        return;
+    }
+    if ((locplayerstate->new_weapon < wp_bazooka) ||
+            (locplayerstate->new_weapon == wp_godhand) ||
+            ( gamestate.BattleOptions.Ammo == bo_infinite_shots )
+       )
+    {
+        DrawPPic( iGLOBAL_AMMO_X - 16, ammo_y, 24 >> 2, 16,
+                  ( byte * )&ammo[ 0 ]->data, 1, true, bufferofsonly);
+
+        DrawPPic( iGLOBAL_AMMO_X - 32, ammo_y + 1, 8 >> 2, 16,
+                  ( byte * )&erase->data, 2, true, bufferofsonly );
+    }
+#if (SHAREWARE == 0)
+    else if ( locplayerstate->new_weapon == wp_dog )
+    {
+        DrawPPic( iGLOBAL_AMMO_X - 16, ammo_y, 24 >> 2, 16,
+                  ( byte * )&ammo[12]->data, 1, true, bufferofsonly );
+
+        DrawPPic( iGLOBAL_AMMO_X - 32, ammo_y + 1, 8 >> 2, 16,
+                  ( byte * )&erase->data, 2, true, bufferofsonly );
+    }
+#endif
+    else
+    {
+        DrawPPic( iGLOBAL_AMMO_X, ammo_y + 1, 8 >> 2, 16,
+                  ( byte * )&ammo[ locplayerstate->new_weapon]->data,
+                  locplayerstate->ammo, false, bufferofsonly );
+    }
+}
+
+
+//******************************************************************************
+//
+// SingleDrawPPic ()
+//
+//******************************************************************************
+
+void SingleDrawPPic (int xpos, int ypos, int width, int height, byte *src, int num, boolean up)
+{
+    byte *olddest;
+    byte *dest;
+    int x;
+    int y;
+    int planes;
+    byte mask;
+    byte pixel;
+    int k;
+    int amt;
+
+#ifdef DOS
+    if (up)
+        amt = 2;
+    else
+        amt = -2;
+#else
+    if (up)
+        amt = 8;
+    else
+        amt = -8;
+#endif
+
+    mask = 1;
+
+#ifdef DOS
+    olddest = (byte *)(bufferofs - screenofs + ylookup[ypos] + (xpos>>2));
+#else
+    olddest = (byte *)(bufferofs - screenofs + ylookup[ypos] + xpos);
+#endif
+
+    for (planes = 0; planes < 4; planes++)
+    {
+        VGAMAPMASK (mask);
+
+        dest = olddest;
+
+#ifndef DOS
+        dest += planes;
+#endif
+
+        for (y = 0; y < height; y++)
+        {
+            for (x = 0; x < width; x++)
+            {
+                pixel = *src++;
+
+                if (pixel != 255)
+                {
+                    for (k = 0; k < num; k++)
+                    {
+                        *(dest+(amt*k)) = pixel;
+                    }
+                }
+
+#ifdef DOS
+                dest++;
+#else
+                dest += 4;
+#endif
+            }
+
+#ifdef DOS
+            dest += (linewidth-width);
+#else
+            dest += (linewidth-width*4);
+#endif
+        }
+
+        mask <<= 1;
+    }
+}
+
+
+
+//****************************************************************************
+//
+// DrawStats ()
+//
+//****************************************************************************
+
+void DrawStats
+(
+    void
+)
+
+{
+    int percenthealth;
+    int health_y;
+    int ammo_y;
+
+    if ( ( !SHOW_PLAYER_STATS() ) || ( playstate == ex_died ) ||
+            ( locplayerstate->health <= 0 ) )
+    {
+        return;
+    }
+
+// Uncomment this if we want transparent health only on sizes < 16
+//   if ( viewsize < 16 )
+//      {
+//      pic_t *shape;
+//
+//      shape = W_CacheLumpName( "backtile", PU_CACHE );
+//      DrawTiledRegion( 0, 160, 320, 24, shape );
+//      }
+
+    health_y = iGLOBAL_HEALTH_Y;
+    ammo_y   = iGLOBAL_AMMO_Y;
+
+    if ( SHOW_KILLS() )
+    {
+        health_y -= KILLS_HEIGHT;
+        ammo_y   -= KILLS_HEIGHT;
+    }
+
+    if ( oldplayerhealth != locplayerstate->health )
+    {
+        oldplayerhealth = locplayerstate->health;
+
+        percenthealth = ( locplayerstate->health * 10 ) /
+                        MaxHitpointsForCharacter( locplayerstate );
+
+        oldpercenthealth = percenthealth + 1;
+    }
+
+    if ( oldpercenthealth > 10 )
+    {
+        oldpercenthealth = 10;
+    }
+
+    if ( oldpercenthealth < 4 )
+    {
+        SingleDrawPPic( iGLOBAL_HEALTH_X - 16, health_y, 8 >> 2, 16,
+                        ( byte * )&health[ 3 ]->data, oldpercenthealth, true);
+    }
+    else if ( oldpercenthealth < 5 )
+    {
+        SingleDrawPPic( iGLOBAL_HEALTH_X - 16, health_y, 8 >> 2, 16,
+                        ( byte * )&health[ 4 ]->data, oldpercenthealth, true );
+    }
+    else
+    {
+        SingleDrawPPic( iGLOBAL_HEALTH_X - 16, health_y, 8 >> 2, 16,
+                        ( byte * )&health[ 5 ]->data, oldpercenthealth, true );
+    }
+
+    if ( ARMED( consoleplayer ) )
+    {
+        if ((locplayerstate->new_weapon < wp_bazooka) ||
+                (locplayerstate->new_weapon == wp_godhand) ||
+                (gamestate.BattleOptions.Ammo == bo_infinite_shots )
+           )
+
+        {
+            SingleDrawPPic( iGLOBAL_AMMO_X - 16, ammo_y, 24 >> 2, 16,
+                            ( byte * )&ammo[13]->data, 1, true );
+        }
+#if (SHAREWARE == 0)
+        else if ( locplayerstate->new_weapon == wp_dog )
+        {
+            SingleDrawPPic( iGLOBAL_AMMO_X - 16, ammo_y + 1, 24 >> 2, 16,
+                            ( byte * )&ammo[25]->data, 1, true );
+        }
+#endif
+        else
+        {
+            SingleDrawPPic( iGLOBAL_AMMO_X, ammo_y + 1, 8 >> 2, 16,
+                            ( byte * )&ammo[13 + locplayerstate->new_weapon]->data,
+                            locplayerstate->ammo, false );
+        }
+    }
+}
+
+
+//****************************************************************************
+//
+// DrawPauseXY ()
+//
+//****************************************************************************
+
+void DrawPauseXY (int x, int y)
+{
+    pic_t *p;
+    byte *buftmp;
+
+    buftmp = bufferofs;
+
+    if (GamePaused == true)
+    {
+        p = (pic_t *) W_CacheLumpNum (W_GetNumForName ("paused"), PU_CACHE, Cvt_pic_t, 1);
+        VL_MemToScreen ((byte *)&p->data, p->width, p->height,x, y);
+        //VWB_DrawPic (x, y, p);
+        bufferofs = buftmp;
+        DrawEpisodeLevel (x,y);
+        //VL_MemToScreen ((byte *)&p->data, p->width, p->height,x, y);
+
+    }
+    else
+    {
+        p = (pic_t *) W_CacheLumpNum (W_GetNumForName ("wait"), PU_CACHE, Cvt_pic_t, 1);
+        VL_MemToScreen ((byte *)&p->data, p->width, p->height,x, y);
+        //VWB_DrawPic (x, y, p);
+    }
+    bufferofs = buftmp;
+}
+
+//****************************************************************************
+//
+// DrawPause ()
+//
+//****************************************************************************
+
+void DrawPause (void)
+{
+    pic_t *p;
+    byte *bufftemp = bufferofs;
+
+    bufferofs -= screenofs;
+
+    if (GamePaused == true)
+    {
+        bufferofs = bufftemp;
+        p = (pic_t *) W_CacheLumpNum (W_GetNumForName ("paused"), PU_CACHE, Cvt_pic_t, 1);
+        DrawPauseXY( (iGLOBAL_SCREENWIDTH-(p->width<<2) ) >>1, (iGLOBAL_SCREENHEIGHT-p->height)>>1);//bna++
+        //DrawPauseXY( (320-(p->width<<2) ) >>1, (200-p->height)>>1);
+        /*
+        	  //buf = (byte *) SafeMalloc (64000);
+        	  w = p->width;
+        	  h = p->height;
+        	  x = (iGLOBAL_SCREENWIDTH-((p->width)<<2) ) >>1;
+        	  y = (iGLOBAL_SCREENHEIGHT-(p->height))>>1;
+
+        	  x1 = (iGLOBAL_SCREENWIDTH-((p->width*2)<<2) ) >>1;
+        	  y1 = (iGLOBAL_SCREENHEIGHT-(p->height*2))>>1;
+
+        	  source = bufferofs + (iGLOBAL_SCREENWIDTH*y)+x;
+        	  target = bufferofs + (iGLOBAL_SCREENWIDTH*y1)+x1;
+
+        	 // memcpy(tmpPICbuf,bufftemp,iGLOBAL_SCREENWIDTH*iGLOBAL_SCREENHEIGHT);
+
+        	  bufferofs = bufftemp;//(byte *)tmpPICbuf;//buf;//write picture in tmpbuf
+        	  VL_MemToScreen ((byte *)&p->data, p->width, p->height,x, y);
+        	  bufferofs = bufftemp;
+        	  DrawEpisodeLevel (x,y);
+
+
+        	  //VL_MemStrechedToScreen ((byte *)&p->data, p->width, p->height,(iGLOBAL_SCREENWIDTH-((p->width*2)<<2) ) >>1, (iGLOBAL_SCREENHEIGHT-(p->height*2))>>1);
+              //DrawEpisodeLevel (x,y);
+
+        	  //VL_MemToScreen ((byte *)&p->data, p->width, p->height,0, 0);
+        	  //bufferofs = bufftemp;//move ptr back
+        	  //write it back to bufferofs while streching
+
+        	  //buf = bufftemp;
+        	  //b = tmpPICbuf ;
+
+        	  source = bufferofs + (iGLOBAL_SCREENWIDTH*y)+x+(w*4);
+        	  target = bufferofs + (iGLOBAL_SCREENWIDTH*y1)+x+(2*w*4);
+
+        	  //first strech lines in x direction
+        	  for (y=0;y<h;y++){
+                c=target;t2=source;
+        		for (x=0;x<w*4;x++){
+        			*target-- = *source;
+        			*target-- = *source--;
+        		}
+        		target=c;source=t2;
+        		target += iGLOBAL_SCREENWIDTH;
+        		source += iGLOBAL_SCREENWIDTH;
+        	  }
+        	  //strech then lines in y direction
+        	  source -= ((iGLOBAL_SCREENWIDTH*(y/2))+(w*4));//bufferofs + (iGLOBAL_SCREENWIDTH*y)+x+(iGLOBAL_SCREENWIDTH*(y));
+        	  target = (source+(iGLOBAL_SCREENWIDTH*(y))+1);//bufferofs + (iGLOBAL_SCREENWIDTH*y)+x+(iGLOBAL_SCREENWIDTH*(y1));
+
+        	  for (y=0;y<h;y++){
+        		memcpy(target,source,(w*4*2));
+        		memcpy(target+iGLOBAL_SCREENWIDTH,source,(w*4*2));
+
+        		target -= iGLOBAL_SCREENWIDTH*2;
+        		source -= iGLOBAL_SCREENWIDTH;
+        	  }
+
+        / *
+        	  for (y=0;y<h;y++){
+                c=target;t2=source;
+        		for (x=0;x<w*4;x++){
+        			*target = *source;
+        			*(target+++iGLOBAL_SCREENWIDTH) = *source;
+        			*target = *source;
+        			*(target+++iGLOBAL_SCREENWIDTH) = *source;
+        			source++;
+        		}
+        		target=c;source=t2;
+        		target += iGLOBAL_SCREENWIDTH*2;
+        		source += iGLOBAL_SCREENWIDTH;
+        	  }
+        */
+
+//	  memcpy( bufftemp,tmpPICbuf,iGLOBAL_SCREENWIDTH*iGLOBAL_SCREENHEIGHT);
+
+    }
+    else
+    {
+        p = (pic_t *) W_CacheLumpNum (W_GetNumForName ("wait"), PU_CACHE, Cvt_pic_t, 1);
+        DrawPauseXY( (iGLOBAL_SCREENWIDTH-(p->width<<2) ) >>1, (iGLOBAL_SCREENHEIGHT-p->height)>>1);//bna++
+        //DrawPauseXY( (320-(p->width<<2) ) >>1, (200-p->height)>>1);
+    }
+//   VH_UpdateScreen () ;
+
+    bufferofs = bufftemp;
+}
+
+//****************************************************************************
+//
+// GM_DrawBonus ()
+//
+//****************************************************************************
+
+void GM_DrawBonus
+(
+    int which
+)
+
+{
+    int    x;
+
+    if ( which < stat_gasmask )
+    {
+        x = POWERUP1X;
+        poweruptime = GetBonusTimeForItem(which);
+        poweradjust = (poweruptime >> 4);
+        powerupheight  = 0;
+        GM_UpdateBonus(poweruptime-poweradjust - 1,true);
+
+    }
+    else
+    {
+        x = POWERUP2X;
+        protectiontime = GetBonusTimeForItem(which);
+        poweradjust = (protectiontime >> 4);
+        protectionheight = 0;
+        GM_UpdateBonus(protectiontime-poweradjust-1,false);
+
+    }
+
+}
+
+
+//******************************************************************************
+//
+// GM_UpdateBonus ()
+//
+//******************************************************************************
+
+void GM_UpdateBonus
+(
+    int time,
+    int powerup
+)
+
+{
+    pic_t *shape;
+    int    shapenum;
+
+    if ( powerup )
+    {
+        if ( time < ( poweruptime - poweradjust ) )
+        {
+            powerupheight++;
+            if ( !SHOW_TOP_STATUS_BAR() )
+            {
+                poweruptime = time;
+            }
+        }
+    }
+    else
+    {
+        if ( time < ( protectiontime - poweradjust ) )
+        {
+            protectionheight++;
+            if ( !SHOW_TOP_STATUS_BAR() )
+            {
+                protectiontime = time;
+            }
+        }
+    }
+
+
+    if ( !SHOW_TOP_STATUS_BAR() )
+    {
+        return;
+    }
+
+    if ( !time )
+    {
+        if ( powerup == 1 )
+        {
+            shapenum = POWERUP1X;
+        }
+        else
+        {
+            shapenum = POWERUP2X;
+        }
+
+        GM_MemToScreen( ( byte * )&eraseb->data, eraseb->width,
+                        eraseb->height, shapenum + topBarCenterOffsetX, POWERUPY );
+
+        return;
+    }
+
+    if ( powerup )
+    {
+        if ( time < ( poweruptime - poweradjust ) )
+        {
+            if ( player->flags & FL_GODMODE )
+            {
+                shapenum = powerpics;
+            }
+            else if ( player->flags & FL_DOGMODE )
+            {
+                shapenum = powerpics + 1;
+            }
+            else if ( player->flags & FL_FLEET )
+            {
+                shapenum = powerpics + 2;
+            }
+            else if ( player->flags & FL_ELASTO )
+            {
+                shapenum = powerpics + 3;
+            }
+            else if ( player->flags & FL_SHROOMS )
+            {
+                shapenum = powerpics + 4;
+            }
+            else
+            {
+                GM_MemToScreen( ( byte * )&eraseb->data,
+                                eraseb->width, eraseb->height, POWERUP1X + topBarCenterOffsetX, POWERUPY );
+
+                return;
+            }
+
+            poweruptime = time;
+
+            shape = ( pic_t * )W_CacheLumpNum( shapenum, PU_CACHE, Cvt_pic_t, 1 );
+
+            GM_MemToScreen( ( byte * )&eraseb->data, eraseb->width,
+                            eraseb->height, POWERUP1X + topBarCenterOffsetX, POWERUPY );
+
+            DrawMPPic( POWERUP1X + topBarCenterOffsetX, POWERUPY + powerupheight, shape->width,
+                       shape->height - powerupheight, powerupheight,
+                       ( byte * )&shape->data, false );
+        }
+    }
+    else
+    {
+        if ( time < ( protectiontime - poweradjust ) )
+        {
+            if ( player->flags & FL_BPV )
+            {
+                shapenum = powerpics + 6;
+            }
+            else if ( player->flags & FL_GASMASK )
+            {
+                shapenum = powerpics + 5;
+            }
+            else if ( player->flags & FL_AV )
+            {
+                shapenum = powerpics + 7;
+            }
+
+            protectiontime = time;
+
+            shape = ( pic_t * )W_CacheLumpNum( shapenum, PU_CACHE, Cvt_pic_t, 1 );
+
+            GM_MemToScreen( ( byte * )&eraseb->data, eraseb->width,
+                            eraseb->height, POWERUP2X + topBarCenterOffsetX, POWERUPY );
+
+            DrawMPPic( POWERUP2X + topBarCenterOffsetX, POWERUPY + protectionheight,
+                       shape->width, shape->height - protectionheight,
+                       protectionheight, ( byte * )&shape->data, false );
+        }
+    }
+}
+
+
+//******************************************************************************
+//
+// Drawpic ()
+//
+// Purpose
+//    Draws a masked, planer pic at xpos, ypos.
+//
+// Parms
+//    xpos   - x position.
+//    ypos   - y position.
+//    width  - width of pic : should be << 2.
+//    height - height of pic.
+//    src    - data to draw.
+//
+// Returns
+//    Nothing.
+//
+//******************************************************************************
+
+void Drawpic (int xpos, int ypos, int width, int height, byte *src)
+{
+    byte *olddest;
+    byte *dest;
+    int x;
+    int y;
+    int planes;
+    byte mask;
+    byte pixel;
+
+
+    mask = 1 << (xpos&3);
+
+#ifdef DOS
+    olddest = (byte *)(bufferofs + ylookup[ypos] + (xpos>>2));
+#else
+    olddest = (byte *)(bufferofs + ylookup[ypos] + xpos);
+#endif
+    for (planes = 0; planes < 4; planes++)
+    {
+        VGAMAPMASK (mask);
+
+        dest = olddest;
+
+#ifdef DOS
+        dest += planes;
+#endif
+
+        for (y = 0; y < height; y++)
+        {
+            for (x = 0; x < width; x++)
+            {
+                pixel = *src++;
+
+                if (pixel != 255)
+                    *(dest) = pixel;
+
+#ifdef DOS
+                dest++;
+#else
+                dest += 4;
+#endif
+            }
+
+#ifdef DOS
+            dest += (linewidth-width);
+#else
+            dest += (linewidth-width*4);
+#endif
+        }
+
+#ifdef DOS
+        mask <<= 1;
+        if (mask == 16)
+        {
+            mask = 1;
+            olddest++;
+        }
+#endif
+    }
+}
+
+
+//******************************************************************************
+//
+// DrawEpisodeLevel ()
+//
+// right justifies and pads with blanks
+//
+//******************************************************************************
+
+void  DrawEpisodeLevel (int x, int y)
+{
+    int level;
+    char  str[20];
+    pic_t *p;
+
+    if (!BATTLEMODE)
+    {
+        ltoa (gamestate.episode, str, 10);
+
+        //bna-- Drawpic (x+29, y+16, 8>>2, 16, (byte *)&timenums[str[0]-'0']->data);
+        VL_MemToScreenClipped ((byte *)&timenums[str[0]-'0']->data,  8>>2, 16, x+29, y+16);
+
+        if ((gamestate.mapon == 6) || (gamestate.mapon == 14) ||
+                (gamestate.mapon == 22) || (gamestate.mapon == 32) ||
+                (gamestate.mapon == 33))
+        {
+            p = (pic_t *) W_CacheLumpName ("tnumb", PU_CACHE, Cvt_pic_t, 1);
+            //Drawpic (x+40, y+16, 8>>2, 16, (byte *)&p->data);
+            VL_MemToScreenClipped ((byte *)&p->data, 8>>2, 16, x+40, y+16);
+
+            if (gamestate.mapon == 6)
+                level = 1;
+            else if (gamestate.mapon == 14)
+                level = 2;
+            else if (gamestate.mapon == 22)
+                level = 3;
+            else if (gamestate.mapon == 32)
+                level = 4;
+            else
+                level = 5;
+        }
+        else
+            level = GetLevel (gamestate.episode, gamestate.mapon);
+
+        level = abs(level);
+        ltoa (level, str, 10);
+
+        if (level < 10) {
+            //Drawpic (x+49, y+16, 8>>2, 16, (byte *)&timenums[str[0]-'0']->data);
+            VL_MemToScreenClipped ((byte *)&timenums[str[0]-'0']->data, 8>>2, 16, x+49, y+16);
+        } else {
+            //Drawpic (x+49, y+16, 8>>2, 16, (byte *)&timenums[str[0]-'0']->data);
+            VL_MemToScreenClipped ((byte *)&timenums[str[0]-'0']->data, 8>>2, 16, x+49, y+16);
+            //Drawpic (x+57, y+16, 8>>2, 16, (byte *)&timenums[str[1]-'0']->data);
+            VL_MemToScreenClipped ((byte *)&timenums[str[1]-'0']->data, 8>>2, 16, x+57, y+16);
+
+        }
+    }
+    else
+    {
+        p = (pic_t *) W_CacheLumpName ("battp", PU_CACHE, Cvt_pic_t, 1);
+        //Drawpic (x+16, y+15, 32>>2, 16, (byte *)&p->data);
+        VL_MemToScreenClipped ((byte *)&p->data, 32>>2, 16, x+16, y+15);
+
+        level = abs(gamestate.mapon + 1);
+        ltoa (level, str, 10);
+
+        if (level < 10) {
+            //Drawpic (x+49, y+16, 8>>2, 16, (byte *)&timenums[str[0]-'0']->data);
+            VL_MemToScreenClipped ((byte *)&timenums[str[0]-'0']->data, 8>>2, 16, x+49, y+16);
+        } else {
+            //Drawpic (x+49, y+16, 8>>2, 16, (byte *)&timenums[str[0]-'0']->data);
+            VL_MemToScreenClipped ((byte *)&timenums[str[0]-'0']->data, 8>>2, 16, x+49, y+16);
+            //Drawpic (x+57, y+16, 8>>2, 16, (byte *)&timenums[str[1]-'0']->data);
+            VL_MemToScreenClipped ((byte *)&timenums[str[1]-'0']->data, 8>>2, 16, x+57, y+16);
+        }
+    }
+}
+
+
+//******************************************************************************
+//
+// GM_MemToScreen ()
+//
+//******************************************************************************
+
+void GM_MemToScreen (byte *source, int width, int height, int x, int y)
+{
+    int dest;
+    byte *dest1, *dest2, *dest3, mask;
+    byte *screen1, *screen2, *screen3;
+    int  plane;
+    int w;
+
+#ifdef DOS
+    dest = ylookup[y]+(x>>2);
+#else
+    dest = ylookup[y]+x;
+#endif
+    mask = 1 << (x&3);
+
+    dest1 = (byte *)(dest+page1start);
+    dest2 = (byte *)(dest+page2start);
+    dest3 = (byte *)(dest+page3start);
+
+    for (plane = 0; plane<4; plane++)
+    {
+        VGAMAPMASK (mask);
+
+        screen1 = dest1;
+        screen2 = dest2;
+        screen3 = dest3;
+        for (y = 0; y < height; y++, screen1 += linewidth,
+                screen2 += linewidth,
+                screen3 += linewidth, source+=width)
+        {
+#ifdef DOS
+            memcpy (screen1, source, width);
+            memcpy (screen2, source, width);
+            memcpy (screen3, source, width);
+#else
+            for (x = 0; x < width; x++) {
+                screen1[x*4+plane] = source[x];
+                screen2[x*4+plane] = source[x];
+                screen3[x*4+plane] = source[x];
+            }
+#endif
+        }
+
+#ifdef DOS
+        mask <<= 1;
+
+        if (mask == 16)
+        {
+            mask = 1;
+            dest1++;
+            dest2++;
+            dest3++;
+        }
+#endif
+    }
+}
+
+
+//==========================================================================
+
+/*
+==================
+=
+= ScreenShake
+=
+==================
+*/
+
+void ScreenShake (void)
+{
+    static int which = 0;
+//	   SetTextMode (  );
+    if (SHAKETICS != 0xFFFF)
+    {
+        SHAKETICS -= tics;
+        if (SHAKETICS >= 0xFF00) {
+            SHAKETICS = 0xFFFF;   //bna safety val check
+        }
+
+        which = (RandomNumber ("ScreenShake",0) & 3);
+
+        switch (which)
+        {
+        case 0:
+            displayofs += 1;
+            MoveScreenUpLeft();//SetTextMode (  );
+            DrawPlayScreen(true);//repaint ammo and life stat
+            break;
+
+        case 1:
+            displayofs -= 1;
+            MoveScreenUpRight();
+            DrawPlayScreen(true);//repaint ammo and life stat
+            break;
+
+        case 2:
+            displayofs += 3*iGLOBAL_SCREENBWIDE;
+            MoveScreenDownLeft();
+            DrawPlayScreen(true);//repaint ammo and life stat
+            break;
+
+        case 3:
+            displayofs -= 3*iGLOBAL_SCREENBWIDE;
+            MoveScreenDownRight();
+            DrawPlayScreen(true);//repaint ammo and life stat
+            break;
+        }
+
+    }
+}
+
+//******************************************************************************
+//
+// DoBorderShifts ()
+//
+//******************************************************************************
+
+void DoBorderShifts (void)
+{
+    if (damagecount)
+    {
+        if (damagecount > 100)
+            damagecount = 100;
+
+        damagecount -= 6;
+
+        if (damagecount < 0)
+            damagecount = 0;
+
+        SetBorderColor (*(colormap+(((100-damagecount)>>2)<<8)+48));
+
+        borderset = true;
+    }
+    else if (borderset)
+    {
+        SetBorderColor (0);
+        borderset = false;
+    }
+}
+
+
+//******************************************************************************
+//
+// DrawHighScores ()
+//
+//******************************************************************************
+
+void DrawHighScores (void)
+{
+    char buffer[16];
+#if (SHAREWARE == 0)
+    char buffer1[5];
+#endif
+    int  i,
+         w,
+         h;
+    HighScore *s;
+
+    for (i = 0, s = Scores; i < MaxScores; i++, s++)
+    {
+        PrintY = 25 + (16 * i);
+
+        //
+        // name
+        //
+        PrintX = 3*8;
+        DrawMenuBufPropString (PrintX, PrintY, s->name);
+
+        //
+        // level
+        //
+        ultoa (s->completed, buffer, 10);
+
+        PrintX = (17 * 8)-10;
+#if (SHAREWARE == 0)
+        itoa (s->episode, buffer1, 10);
+
+        DrawMenuBufPropString (PrintX, PrintY, buffer1);
+#else
+        DrawMenuBufPropString (PrintX, PrintY, "S");
+#endif
+
+        DrawMenuBufPropString (PrintX, PrintY, "-");
+
+#if (SHAREWARE == 0)
+        if (s->completed == 7)
+            DrawMenuBufPropString (PrintX, PrintY, "B");
+        else if (s->completed == 8)
+            DrawMenuBufPropString (PrintX, PrintY, "S");
+        else if (s->completed == 9)
+            DrawMenuBufPropString (PrintX, PrintY, "C");
+        else if (s->completed == 10)
+            DrawMenuBufPropString (PrintX, PrintY, "D");
+        else
+            DrawMenuBufPropString (PrintX, PrintY, buffer);
+#else
+        DrawMenuBufPropString (PrintX, PrintY, buffer);
+#endif
+
+        //
+        // score
+        //
+        ultoa(s->score,buffer,10);
+
+        VW_MeasurePropString (buffer, &w, &h);
+        PrintX = (33 * 8) - w;
+        DrawMenuBufPropString (PrintX, PrintY, buffer);
+    }
+}
+
+
+
+//******************************************************************************
+//
+// CheckHighScore ()
+//
+//******************************************************************************
+
+void CheckHighScore (long score, word other, boolean INMENU)
+{
+    word        i,j;
+    int         n;
+    HighScore   myscore;
+    int         level;
+
+    MenuFadeIn();
+    if (!INMENU)
+        SetupMenuBuf ();
+
+    strcpy (myscore.name,"");
+    myscore.score     = score;
+
+    level = GetLevel (gamestate.episode, other-1);
+
+    myscore.episode   = gamestate.episode;
+    myscore.completed = level;
+
+    CurrentFont = smallfont;
+
+    for (i = 0, n = -1; i < MaxScores; i++)
+    {
+        if ((myscore.score > Scores[i].score)  ||
+                ((myscore.score == Scores[i].score) &&
+                 (myscore.completed > Scores[i].completed)))
+        {
+            for (j = MaxScores; --j > i;)
+                Scores[j] = Scores[j - 1];
+            Scores[i] = myscore;
+            n = i;
+            break;
+        }
+    }
+
+    if (INMENU)
+    {
+        SetAlternateMenuBuf();
+        SetMenuTitle ("High Scores");
+        ClearMenuBuf();
+        DrawHighScores ();
+        if (n != -1)
+            DisplayInfo (6);
+        else
+            DisplayInfo (5);
+        FlipMenuBuf ();
+    }
+    else
+    {
+        ClearMenuBuf ();
+        SetMenuTitle ("High Scores");
+        DrawHighScores ();
+        if (n != -1)
+            DisplayInfo (6);
+        else
+            DisplayInfo (5);
+        RefreshMenuBuf (0);
+    }
+
+    if (n != -1)
+    {
+        PrintY = 25 + (16 * n);
+        PrintX = 3*8;
+        US_LineInput (PrintX, PrintY, Scores[n].name, NULL,
+                      true, 10, 98, 0);
+    }
+    else
+    {
+        IN_ClearKeysDown ();
+        if ( INMENU )
+        {
+            while( !IN_CheckAck () )
+            {
+                RefreshMenuBuf (0);
+            }
+        }
+        else
+        {
+            for( i = 0; i <= 150; i += tics )
+            {
+                RefreshMenuBuf (0);
+                if (IN_CheckAck ())
+                {
+                    break;
+                }
+            }
+        }
+    }
+
+    if (INMENU)
+    {
+        SD_Play (SD_ESCPRESSEDSND);
+    }
+    else
+    {
+        ShutdownMenuBuf ();
+    }
+}
+
+
+//===========================================================================
+
+//#define HEADERX      140
+//#define BONERNAMEX   170
+#define HEADERX      152
+#define BONERNAMEX   166
+
+
+/*
+==================
+=
+= DrawEOLHeader ()
+=
+==================
+*/
+void DrawEOLHeader
+(
+    int playstate
+)
+
+{
+    int  health;
+    char tempstr[ 15 ];
+    char *string;
+    int  level;
+    int  w;
+    int  h;
+
+    VWB_TBar( 30, 5, 250, 75 );
+
+    switch( playstate )
+    {
+    case ex_skiplevel :
+        if ( ( gamestate.violence >= vl_high ) &&
+                ( gamestate.difficulty >= gd_hard ) )
+        {
+            string = "LEVEL WUSSED OUT ON!";
+        }
+        else
+        {
+            string = "LEVEL SKIPPED.";
+        }
+        break;
+
+    case ex_secretdone :
+        string = "SECRET LEVEL COMPLETED!";
+        break;
+
+    case ex_secretlevel :
+        string = "SECRET EXIT TAKEN!";
+        break;
+
+    case ex_gameover :
+        string = "GAME COMPLETED!";
+        break;
+
+    case ex_bossdied :
+        string = "BOSS DEFEATED!";
+        break;
+
+    default :
+        string = "LEVEL COMPLETED!";
+        break;
+    }
+
+    VW_MeasurePropString( string, &w, &h );
+
+    px = ( 320 - w ) / 2;
+    py = 10;
+    VWB_DrawPropString( string );
+
+    // draw episode number
+    string = "EPISODE";
+    VW_MeasurePropString( string, &w, &h );
+    px = HEADERX - w;
+    py = 25;
+    VWB_DrawPropString( string );
+
+    itoa( gamestate.episode, tempstr, 10 );
+    px = BONERNAMEX;
+    VWB_DrawPropString( tempstr );
+
+    // draw area number
+    level = GetLevel( gamestate.episode, gamestate.mapon );
+    itoa( level, tempstr, 10 );
+
+    py = 35;
+
+    if ( playstate == ex_secretdone )
+    {
+        string = "SECRET AREA";
+    }
+    else if ( playstate == ex_bossdied )
+    {
+        string = "BOSS AREA";
+    }
+    else if ( gamestate.mapon == 32 )
+    {
+        string = "CHASE AREA";
+    }
+    else
+    {
+        string = "AREA";
+    }
+
+    VW_MeasurePropString( string, &w, &h);
+    px = HEADERX - w;
+    VWB_DrawPropString( string );
+
+    if ( gamestate.mapon != 33 )
+    {
+        px = BONERNAMEX;
+        VWB_DrawPropString( tempstr );
+    }
+
+    string = "SCORE";
+    VW_MeasurePropString( string, &w, &h);
+    px = HEADERX - w;
+    py = 45;
+    VWB_DrawPropString( string );
+
+    px = BONERNAMEX;
+    itoa( gamestate.score, tempstr, 10 );
+    VWB_DrawPropString( tempstr );
+
+    string = "HEALTH";
+    VW_MeasurePropString( string, &w, &h );
+    px = HEADERX - w;
+    py = 55;
+    VWB_DrawPropString( string );
+
+    px = BONERNAMEX;
+    health = ( ( locplayerstate->health * 100 ) /
+               MaxHitpointsForCharacter( locplayerstate ) );
+
+    itoa( health, tempstr, 10 );
+    VWB_DrawPropString( tempstr );
+    VWB_DrawPropString( "%" );
+
+    //
+    // Secret count
+    //
+
+    {
+        char str1[10];
+        char str2[10];
+
+        itoa(gamestate.secretcount,&(str1[0]),10);
+        strcat(str1," / ");
+        itoa(gamestate.secrettotal,&(str2[0]),10);
+        strcat(str1,str2);
+        string = "SECRET WALLS";
+        VW_MeasurePropString( string, &w, &h );
+        px = HEADERX - w;
+        py = 65;
+        VWB_DrawPropString( string );
+
+        px = BONERNAMEX;
+        VWB_DrawPropString( str1 );
+    }
+
+    VW_UpdateScreen ();
+}
+
+boolean EndBonusFirst;
+boolean EndBonusSkip;
+int     EndBonusNumBonuses;
+int     EndBonusVoice;
+int     EndBonusStartY;
+
+void DrawEndBonus
+(
+    char *string,
+    char *bonusstring,
+    int   type
+)
+
+{
+    int w;
+    int h;
+    int  health;
+    char tempstr[ 15 ];
+
+    if ( EndBonusFirst )
+    {
+        VWB_TBar( 5, EndBonusStartY - 2, 310, 4 );
+        EndBonusFirst = false;
+    }
+
+    VWB_TBar( 5, EndBonusStartY + 2, 310, 10 );
+    VW_MeasurePropString( string, &w, &h );
+
+    py = EndBonusStartY;
+    if ( bonusstring == NULL )
+    {
+        px = ( 320 - w ) / 2;
+        VWB_DrawPropString( string );
+    }
+    else
+    {
+        px = BONERNAMEX - w;
+        VWB_DrawPropString( string );
+
+        EndBonusNumBonuses++;
+        VW_MeasurePropString( bonusstring, &w, &h );
+        px = 310 - w;
+        py = EndBonusStartY;
+        VWB_DrawPropString( bonusstring );
+    }
+
+    // Update Score
+    py = 45;
+    px = BONERNAMEX;
+    V_ReDrawBkgnd( px, py, 107, 11, false );
+    VWB_TBar( px, py, 107, 11 );
+    itoa( gamestate.score, tempstr, 10 );
+    VWB_DrawPropString( tempstr );
+
+    // Update Health
+    py = 55;
+    px = BONERNAMEX;
+    V_ReDrawBkgnd( px, py, 107, 11, false );
+    VWB_TBar( px, py, 107, 11 );
+    health = ( ( locplayerstate->health * 100 ) /
+               MaxHitpointsForCharacter( locplayerstate ) );
+    itoa( health, tempstr, 10 );
+    VWB_DrawPropString( tempstr );
+    VWB_DrawPropString( "%" );
+
+    switch( type )
+    {
+    case 0 :
+        EndBonusVoice = SD_Play( SD_ENDBONUS1SND );
+        break;
+
+    case 1 :
+        EndBonusVoice = SD_Play( SD_NOBONUSSND );
+        break;
+
+    case 2 :
+        VL_FillPalette(255,255,255);
+        //bna--VW_UpdateScreen();
+        VL_FadeIn(0,255,origpal,10);
+        EndBonusVoice = SD_Play( SD_LIGHTNINGSND );
+        break;
+    }
+
+    EndBonusStartY += 10;
+
+    //bna--VW_UpdateScreen();
+    while( SD_SoundActive( EndBonusVoice ) && !EndBonusSkip )
+    {
+        if ( IN_CheckAck() )
+        {
+            EndBonusSkip = true;
+        }
+    }
+}
+
+
+
+/*
+==================
+=
+= LevelCompleted
+=
+= Exit with the screen faded out
+=
+==================
+*/
+
+extern int OLDLMWEAPON;
+extern int OLDLWEAPON;
+
+void LevelCompleted
+(
+    exit_t playstate
+)
+
+{
+    objtype *obj;
+    boolean dobonus;
+    int i;
+    int kr;
+    int sr;
+    int tr;
+    int missileratio;
+    int superratio;
+    int healthratio;
+    int democraticratio;
+    int plantratio;
+    int cnt;
+
+    pic_t *tmpPic;
+//   byte *picbuf;
+
+    EndBonusNumBonuses = 0;
+    EndBonusFirst      = true;
+    EndBonusSkip       = false;
+    EndBonusStartY     = 90;
+
+    EnableScreenStretch();
+    tmpPic = ( pic_t * )W_CacheLumpName( "mmbk", PU_CACHE, Cvt_pic_t, 1 );
+    VWB_DrawPic( 0, 0, tmpPic );
+    VW_UpdateScreen();
+//   DisableScreenStretch();
+
+    IN_StartAck();
+    EndBonusVoice = 0;
+
+
+    if ( playstate != ex_bossdied )
+    {
+        EndBonusVoice = SD_Play( SD_LEVELDONESND );
+        VL_FillPalette( 255, 255, 255 );
+        VL_FadeIn( 0, 255, origpal, 10 );
+        if ( player->flags & FL_DOGMODE )
+        {
+            MU_StartSong( song_dogend );
+        }
+        else
+        {
+            MU_StartSong( song_endlevel );
+        }
+    }
+
+    BkPic = ( pic_t * )W_CacheLumpName( "mmbk", PU_CACHE, Cvt_pic_t, 1 );
+    VWB_DrawPic( 0, 0, BkPic );
+
+    CheckHolidays();
+    CurrentFont = smallfont;
+
+    // Kill powerups
+    if ( player->flags & FL_ELASTO )
+    {
+        player->flags &= ~FL_NOFRICTION;
+    }
+
+    player->flags &= ~( FL_FLEET | FL_SHROOMS | FL_ELASTO | FL_GODMODE |
+                        FL_DOGMODE | FL_BPV | FL_AV | FL_GASMASK );
+
+    // Turn off quickload for next level
+    pickquick = false;
+
+    //
+    // FIGURE RATIOS OUT BEFOREHAND
+    //
+    kr = 0;
+    tr = 0;
+    tr = 0;
+    superratio      = 0;
+    missileratio    = 0;
+    healthratio     = 0;
+    democraticratio = 0;
+    plantratio      = 0;
+
+    if ( gamestate.killtotal )
+    {
+        kr = ( int )( ( ( int )gamestate.killcount ) * 100 ) /
+             ( ( int )gamestate.killtotal );
+    }
+
+    if ( gamestate.secrettotal )
+    {
+        sr = ( int )( ( ( int )gamestate.secretcount ) * 100 ) /
+             ( ( int )gamestate.secrettotal );
+    }
+
+    if ( gamestate.treasuretotal )
+    {
+        tr = ( int )( ( ( int )gamestate.treasurecount ) * 100 ) /
+             ( ( int )gamestate.treasuretotal );
+    }
+
+    if ( gamestate.supertotal )
+    {
+        superratio = ( int )( ( ( int )gamestate.supercount ) * 100 ) /
+                     ( ( int )gamestate.supertotal );
+    }
+
+    if ( gamestate.missiletotal )
+    {
+        missileratio = ( int )( ( ( int )gamestate.missilecount ) * 100 ) /
+                       ( ( int )gamestate.missiletotal );
+    }
+
+    if ( gamestate.healthtotal )
+    {
+        healthratio = ( int )( ( ( int )gamestate.healthcount ) * 100 ) /
+                      ( ( int )gamestate.healthtotal );
+    }
+
+    if ( gamestate.democratictotal )
+    {
+        democraticratio = ( int )( ( ( int )gamestate.democraticcount ) *
+                                   100 ) / ( ( int )gamestate.democratictotal );
+    }
+
+    if ( gamestate.planttotal )
+    {
+        plantratio = ( int )( ( ( int )gamestate.plantcount ) * 100 ) /
+                     ( ( int )gamestate.planttotal );
+    }
+
+    DrawEOLHeader( playstate );
+    /*
+    	//bna section  store picture  because its written on again
+       // store screen first
+       picbuf = (byte *)SafeMalloc (64000);
+       memcpy(picbuf ,bufferofs ,64000);
+
+       EnableScreenStretch();
+       VW_UpdateScreen();//tmpPICbuf is destroyed here
+       DisableScreenStretch();
+       //copy it back
+
+       memcpy(bufferofs ,picbuf , 64000);
+    	//bna section end
+    */
+
+    EndBonusSkip = true;
+
+    while( SD_SoundActive( EndBonusVoice ) && !EndBonusSkip )
+    {
+
+        //bna--VW_UpdateScreen();
+
+        if ( IN_CheckAck() )
+        {
+            EndBonusSkip = true;
+        }
+    }
+//  tmpPic = ( pic_t * )W_CacheLumpName( "mmbk", PU_CACHE, Cvt_pic_t, 1 );
+//  VWB_DrawPic( 0, 0, tmpPic );
+
+    if ( GetNextMap(player->tilex,player->tiley) == -1)
+    {
+        if ( gamestate.dipballs == 3 )
+        {
+            gamestate.score += 100000;
+            DrawEndBonus( "DIP BONUS", "100000 POINTS", 0 );
+            EndBonusStartY += 10;
+        }
+
+        if ( locplayerstate->lives > 0 )
+        {
+            char str[20];
+            char str2[60];
+
+            DrawEndBonus( "EXTRA LIVES BONUS", "\0", 0 );
+            itoa(locplayerstate->lives,str,10);
+            strcpy(str2,str);
+            strcat(str2," EXTRA LIVES =");
+            DrawEndBonus( "\0", str2, 0 );
+            itoa(locplayerstate->lives,str,10);
+            strcpy(str2,str);
+            strcat(str2," X 10000 = ");
+            itoa(locplayerstate->lives*10000,str,10);
+            strcat(str2,str);
+            strcat(str2," POINTS");
+            gamestate.score += 10000*locplayerstate->lives;
+            DrawEndBonus( "\0", str2, 0 );
+        }
+    }
+    else
+    {
+        //
+        // Check for SKIN OF YO TEETH
+        //
+        if ( locplayerstate->health <= 10 )
+        {
+            locplayerstate->health = MaxHitpointsForCharacter( locplayerstate );
+            DrawEndBonus( "SKIN OF YOUR TEETH", "100% HEALTH", 0 );
+        }
+
+        // BULL IN CHINA SHOP BONUS
+        if ( tr == 100 )
+        {
+            gamestate.score += 10000;
+            DrawEndBonus( "BULL IN CHINA SHOP", "10000 POINTS", 0 );
+        }
+
+        // SUPERCHARE BONUS
+        if ( superratio == 100 )
+        {
+            gamestate.score += 10000;
+            DrawEndBonus( "SUPERCHARGE BONUS", "10000 POINTS", 0 );
+        }
+
+        // BLEEDER BONUS
+        if ( healthratio == 100 )
+        {
+            gamestate.score += 10000;
+            DrawEndBonus( "BLEEDER BONUS", "10000 POINTS", 0 );
+        }
+
+        // ADRENALINE BONUS
+        if ( kr == 100 )
+        {
+            gamestate.score += 10000;
+            DrawEndBonus( "ADRENALINE BONUS", "10000 POINTS", 0 );
+        }
+
+        // CURIOSITY BONUS
+        dobonus = true;
+
+        //
+        // Check switches
+        cnt = lastswitch - &switches[ 0 ];
+        if ( cnt != 0 )
+        {
+            for ( i = 0; i < cnt; i++ )
+            {
+                if ( ( switches[ i ].flags & FL_S_FLIPPED ) == 0 )
+                {
+                    dobonus = false;
+                    break;
+                }
+            }
+        }
+
+        //
+        // Check pillars
+        for ( obj = FIRSTACTOR; obj != NULL; obj = obj->next )
+        {
+            if ( ( obj->obclass == pillarobj ) &&
+                    ( ( obj->flags & FL_FLIPPED ) == 0 ) )
+            {
+                dobonus = false;
+            }
+        }
+
+        if ( ( gamestate.secrettotal ) && ( sr != 100 ) )
+        {
+            dobonus = false;
+        }
+
+        if ( dobonus )
+        {
+            gamestate.score += 10000;
+            DrawEndBonus( "CURIOSITY BONUS", "10000 POINTS", 0 );
+        }
+
+        // GROUND ZERO BONUS
+        if ( gamestate.DOGROUNDZEROBONUS )
+        {
+            gamestate.score += 10000;
+            DrawEndBonus( "GROUND ZERO BONUS", "10000 POINTS", 0 );
+        }
+
+        // REPUBLICAN BONUS 1
+        if ( missileratio == 100 )
+        {
+            gamestate.score += 5000;
+            DrawEndBonus( "REPUBLICAN BONUS 1", " 5000 POINTS", 0 );
+        }
+
+        // REPUBLICAN BONUS 2
+        if (plantratio == 100)
+        {
+            gamestate.score += 5000;
+            DrawEndBonus( "REPUBLICAN BONUS 2", " 5000 POINTS", 0 );
+        }
+
+        // DEMOCRATIC BONUS 1
+        if ( gamestate.DODEMOCRATICBONUS1 )
+        {
+            gamestate.score += 5000;
+            DrawEndBonus( "DEMOCRATIC BONUS 1", " 5000 POINTS", 0 );
+        }
+
+        // DEMOCRATIC BONUS 2
+        if (democraticratio == 100)
+        {
+            gamestate.score += 5000;
+            DrawEndBonus( "DEMOCRATIC BONUS 2", " 5000 POINTS", 0 );
+        }
+    }
+
+    if ( EndBonusNumBonuses == 0 )
+    {
+        DrawEndBonus( "NO BONUS!", NULL, 1 );
+    }
+
+    if ( ( EndBonusNumBonuses != 0 ) || ( playstate == ex_gameover ) )
+    {
+        SD_Play( PlayerSnds[ locplayerstate->player ] );
+
+        // DO BONUS BONUS
+        if ( EndBonusNumBonuses == NUMBONUSES )
+        {
+            IN_StartAck();
+            while( !IN_CheckAck() )
+            {
+                ;
+            }
+
+            BkPic = ( pic_t * )W_CacheLumpName( "mmbk", PU_CACHE, Cvt_pic_t, 1 );
+            VWB_DrawPic( 0, 0, BkPic );
+
+            gamestate.score += BONUSBONUS;
+            DrawEOLHeader( playstate );
+            EndBonusFirst = true;
+            EndBonusStartY = 110;
+            EndBonusSkip = true;
+            DrawEndBonus( "BONUS BONUS!  1,000,000 POINTS!", NULL, 2 );
+        }
+        else if ( ( kr == 100 ) && ( dobonus ) )
+        {
+            IN_StartAck();
+            while( !IN_CheckAck() )
+            {
+                ;
+            }
+
+            BkPic = ( pic_t * )W_CacheLumpName( "mmbk", PU_CACHE, Cvt_pic_t, 1 );
+            VWB_DrawPic( 0, 0, BkPic );
+
+            DrawEOLHeader( playstate );
+            EndBonusFirst = true;
+            EndBonusStartY = 110;
+            DrawEndBonus( "You have done well.", NULL, 3 );
+
+#if (SHAREWARE==1)
+            EndBonusVoice = SD_Play( SD_RICOCHET3SND );
+#else
+            EndBonusVoice = SD_Play( SD_PERCENT100SND );
+#endif
+
+            EndBonusSkip = false;
+            DrawEndBonus( "This level is toast.", NULL, 3 );
+
+        }
+    }
+
+
+
+    //bna section
+//    EnableScreenStretch();//bna++
+    VW_UpdateScreen();//bna++
+//    DisableScreenStretch();//bna++
+    //bna section end
+
+
+    IN_StartAck();
+    while( !IN_CheckAck() )
+    {
+        ;
+    }
+
+    EndLevelStuff = false;
+    CurrentFont = smallfont;
+}
+
+
+void DrawTallyHeader
+(
+    int which
+)
+
+{
+    pic_t *Name;
+    pic_t *KillCount;
+    pic_t *TimesYouKilledPerson;
+    pic_t *TimesPersonKilledYou;
+    pic_t *Suicides;
+    pic_t *Score;
+    pic_t *Blank;
+    pic_t *TopBar;
+
+    Name                 = ( pic_t * )W_CacheLumpName( "t_name",    PU_CACHE, Cvt_pic_t, 1 );
+    Blank                = ( pic_t * )W_CacheLumpName( "t_blnk",    PU_CACHE, Cvt_pic_t, 1 );
+    KillCount            = ( pic_t * )W_CacheLumpName( "t_kcount",  PU_CACHE, Cvt_pic_t, 1 );
+    TimesYouKilledPerson = ( pic_t * )W_CacheLumpName( "t_kilper",  PU_CACHE, Cvt_pic_t, 1 );
+    TimesPersonKilledYou = ( pic_t * )W_CacheLumpName( "t_perkil", PU_CACHE, Cvt_pic_t, 1 );
+    Suicides             = ( pic_t * )W_CacheLumpName( "t_suicid",  PU_CACHE, Cvt_pic_t, 1 );
+    Score                = ( pic_t * )W_CacheLumpName( "t_score",   PU_CACHE, Cvt_pic_t, 1 );
+    TopBar               = ( pic_t * )W_CacheLumpName( "t_bar",     PU_CACHE, Cvt_pic_t, 1 );
+
+    IFont = ( cfont_t * )W_CacheLumpName( "sifont", PU_CACHE, Cvt_cfont_t, 1 );
+
+    switch( which )
+    {
+    case 0 :
+        VWB_DrawPic (   8,  8, TopBar );
+        DrawIntensityString( 12, 11, "FINAL SCORE", 20 );
+        VWB_DrawPic (   8, 24, Name );
+        VWB_DrawPic ( 136, 24, KillCount );
+        VWB_DrawPic ( 184, 24, Suicides );
+        VWB_DrawPic ( 272, 24, Score );
+        break;
+
+    case 1 :
+        VWB_DrawPic (   8,  8, TopBar );
+        DrawIntensityString( 12, 11, "FINAL SCORE", 20 );
+        VWB_DrawPic (   8, 24, Name );
+        VWB_DrawPic ( 136, 24, Blank );
+        VWB_DrawPic ( 272, 24, Score );
+        break;
+
+    case 2 :
+        VWB_DrawPic (   8,  8, TopBar );
+        DrawIntensityString( 12, 11, "YOUR KILLS", 20 );
+        VWB_DrawPic (   8, 24, Name );
+        VWB_DrawPic ( 136, 24, KillCount );
+        VWB_DrawPic ( 184, 24, TimesYouKilledPerson );
+        break;
+
+    case 3 :
+        VWB_DrawPic (   8,  8, TopBar );
+        DrawIntensityString( 12, 11, "YOUR DEATHS", 20 );
+        VWB_DrawPic (   8, 24, Name );
+        VWB_DrawPic ( 136, 24, TimesPersonKilledYou );
+        break;
+//bna added
+    case 4 :
+        VWB_DrawPic ( 198+48, 8, Blank );
+        VWB_DrawPic (   8,  8, TopBar );
+        DrawIntensityString( 12, 11, "FINAL SCORE", 20 );
+        VWB_DrawPic (   8, 24, TopBar );//used to blank
+        VWB_DrawPic (   8, 24, Name );
+        VWB_DrawPic ( 136, 24, KillCount);
+        VWB_DrawPic ( 198, 24, TimesPersonKilledYou);
+        VWB_DrawPic ( 198+48, 24, Blank );
+        VWB_DrawPic ( 272, 24, Score );
+        break;
+//bna added end
+    }
+
+    DrawTimeXY( TALLYTIME_X, TALLYTIME_Y, gamestate.TimeCount / VBLCOUNTER,
+                true );
+}
+
+
+#define BT_RANK_X    23
+#define BT_PLAYER_X  30
+#define BT_KILLS_X   ( 139 + ( ( 40 + 20 ) / 2 ) )
+#define BT_DEATHS_X  ( 193 + ( ( 56 + 20 ) / 2 ) )
+//#define BT_SCORE_X   ( 263 + ( ( 46 + 20 ) / 2 ) )
+#define BT_SCORE_X   ( 273 + ( ( 46 + 20 ) / 2 ) )
+
+
+void ShowKills( int localplayer )
+{
+    int  w;
+    int  h;
+    int  i;
+    int  j;
+    int  temp;
+    int  rank;
+    int  player;
+    int  killer;
+    int  victim;
+    int  color;
+    char tempstr[15];
+    int  KillCount[ MAXPLAYERS ];
+    int  Order[ MAXPLAYERS ];
+    int  NumPlayers;
+
+    // show at the most 11 players
+    NumPlayers = min( numplayers, 11 );
+
+    // Count kills
+    for( killer = 0; killer < NumPlayers; killer++ )
+    {
+        Order[ killer ] = killer;
+        KillCount[ killer ] = 0;
+        for( victim = 0; victim < NumPlayers; victim++ )
+        {
+            if ( BATTLE_Team[ victim ] != BATTLE_Team[ killer ] )
+            {
+                KillCount[ killer ] += WhoKilledWho[ killer ][ victim ];
+            }
+        }
+    }
+
+    for( i = 0; i < NumPlayers - 1; i++ )
+    {
+        for( j = i + 1; j < NumPlayers; j++ )
+        {
+            if ( KillCount[ Order[ i ] ] < KillCount[ Order[ j ] ] )
+            {
+                temp = Order[ i ];
+                Order[ i ] = Order[ j ];
+                Order[ j ] = temp;
+            }
+        }
+    }
+
+    DrawTallyHeader( 2 );
+
+    IFont = (cfont_t * )W_CacheLumpNum (W_GetNumForName ("sifont"), PU_CACHE, Cvt_cfont_t, 1);
+    CurrentFont = smallfont;
+    py = 43;
+
+    for( rank = 0; rank < NumPlayers; rank++ )
+    {
+        player = Order[ rank ];
+
+        color = 21;
+
+        // Highlight the your score
+        if ( player == localplayer )
+        {
+            // Change to Intensity
+            color = 241;
+        }
+
+        // Draw rank if not tied with previous rank
+        if ( ( rank == 0 ) || ( KillCount[ player ] !=
+                                KillCount[ Order[ rank - 1 ] ] ) )
+        {
+            itoa( rank + 1, tempstr, 10 );
+        }
+        else
+        {
+            strcpy( tempstr, "Tie" );
+        }
+
+        VW_MeasureIntensityPropString ( tempstr, &w, &h);
+        DrawIntensityString( BT_RANK_X - w, py, tempstr, color );
+
+        // Draw name
+        DrawIntensityString( BT_PLAYER_X, py, PLAYERSTATE[ player ].codename, color );
+
+        // Draw kills
+        itoa( KillCount[ player ], tempstr, 10 );
+        VW_MeasureIntensityPropString ( tempstr, &w, &h);
+        DrawIntensityString( BT_KILLS_X - w, py, tempstr, color );
+
+        // Draw times you killed that person
+        if ( player != localplayer )
+        {
+            itoa( WhoKilledWho[ localplayer ][ player ], tempstr, 10 );
+        }
+        else
+        {
+            strcpy( tempstr, "-" );
+        }
+
+        VW_MeasureIntensityPropString ( tempstr, &w, &h);
+        DrawIntensityString( BT_DEATHS_X - w, py, tempstr, color );
+
+        if ( gamestate.teamplay )
+        {
+            DrawIntensityString( BT_DEATHS_X + 16, py,
+                                 colorname[ PLAYERSTATE[ player ].uniformcolor ], color );
+        }
+
+        py += h;
+    }
+}
+
+
+void ShowDeaths( int localplayer )
+{
+    int  w;
+    int  h;
+    int  i;
+    int  j;
+    int  temp;
+    int  rank;
+    int  player;
+    int  killer;
+    int  victim;
+    int  color;
+    char tempstr[15];
+    int  DeathCount[ MAXPLAYERS ];
+    int  Order[ MAXPLAYERS ];
+    int  NumPlayers;
+
+    // show at the most 11 players
+    NumPlayers = min( numplayers, 11 );
+
+    // Count Deaths
+    for( victim = 0; victim < NumPlayers; victim++ )
+    {
+        Order[ victim ] = victim;
+        DeathCount[ victim ] = 0;
+        for( killer = 0; killer < NumPlayers; killer++ )
+        {
+            DeathCount[ victim ] += WhoKilledWho[ killer ][ victim ];
+        }
+    }
+
+    for( i = 0; i < NumPlayers - 1; i++ )
+    {
+        for( j = i + 1; j < NumPlayers; j++ )
+        {
+            if ( DeathCount[ Order[ i ] ] < DeathCount[ Order[ j ] ] )
+            {
+                temp = Order[ i ];
+                Order[ i ] = Order[ j ];
+                Order[ j ] = temp;
+            }
+        }
+    }
+
+    DrawTallyHeader( 3 );
+
+    IFont = (cfont_t * )W_CacheLumpNum (W_GetNumForName ("sifont"), PU_CACHE, Cvt_cfont_t, 1);
+    CurrentFont = smallfont;
+    py = 43;
+
+    for( rank = 0; rank < NumPlayers; rank++ )
+    {
+        player = Order[ rank ];
+        color = 21;
+
+        // Highlight the your score
+        if ( player == localplayer )
+        {
+            // Change to Intensity
+            color = 241;
+        }
+
+        // Draw rank if not tied with previous rank
+        if ( ( rank == 0 ) || ( DeathCount[ player ] !=
+                                DeathCount[ Order[ rank - 1 ] ] ) )
+        {
+            itoa( rank + 1, tempstr, 10 );
+        }
+        else
+        {
+            strcpy( tempstr, "Tie" );
+        }
+
+        VW_MeasureIntensityPropString ( tempstr, &w, &h);
+        DrawIntensityString( BT_RANK_X - w, py, tempstr, color );
+
+        // Draw name
+        DrawIntensityString( BT_PLAYER_X, py, PLAYERSTATE[ player ].codename, color );
+
+        // Draw deaths
+        itoa( DeathCount[ player ], tempstr, 10 );
+        VW_MeasureIntensityPropString ( tempstr, &w, &h);
+        DrawIntensityString( BT_KILLS_X - w, py, tempstr, color );
+
+        // Draw times you were killed by that person
+        itoa( WhoKilledWho[ player ][ localplayer ], tempstr, 10 );
+        VW_MeasureIntensityPropString ( tempstr, &w, &h);
+        DrawIntensityString( BT_DEATHS_X - w, py, tempstr, color );
+
+        if ( gamestate.teamplay )
+        {
+            DrawIntensityString( BT_DEATHS_X + 16, py,
+                                 colorname[ PLAYERSTATE[ player ].uniformcolor ], color );
+        }
+
+        py += h;
+    }
+}
+
+
+void ShowEndScore( int localplayer )
+{
+    int  w;
+    int  h;
+    int  rank;
+    int  leader;
+    int  team;
+    int  color;
+    int  killer;
+    int  victim;
+    int  killcount;
+    int  suicidecount;
+    char tempstr[15];
+    boolean dofullstats;
+    int  NumPlayers;
+
+    // show at the most 11 players
+    NumPlayers = min( numplayers, 11 );
+
+    dofullstats = false;
+    switch( gamestate.battlemode )
+    {
+    case battle_Normal :
+    case battle_ScoreMore :
+    case battle_Hunter :
+        dofullstats = true;
+        DrawTallyHeader( 0 );
+        break;
+
+    case battle_Collector :
+    case battle_Scavenger :
+    case battle_Tag :
+    case battle_Eluder :
+    case battle_Deluder :
+    case battle_CaptureTheTriad :
+        dofullstats = false;
+        DrawTallyHeader( 1 );
+        break;
+    }
+
+    IFont = (cfont_t * )W_CacheLumpNum (W_GetNumForName ("sifont"), PU_CACHE, Cvt_cfont_t, 1);
+    CurrentFont = smallfont;
+    py = 43;
+
+    for( rank = 0; rank < BATTLE_NumberOfTeams; rank++ )
+    {
+        team = BATTLE_PlayerOrder[ rank ];
+
+        color = 21;
+        if ( team == BATTLE_Team[ localplayer ] )
+        {
+            // Change to Intensity
+            color = 241;
+        }
+
+        // Draw rank if not tied with previous rank
+        if ( ( rank == 0 ) || ( BATTLE_Points[ team ] !=
+                                BATTLE_Points[ BATTLE_PlayerOrder[ rank - 1 ] ] ) )
+        {
+            itoa( rank + 1, tempstr, 10 );
+        }
+        else
+        {
+            strcpy( tempstr, "Tie" );
+        }
+
+        VW_MeasureIntensityPropString ( tempstr, &w, &h);
+        DrawIntensityString( BT_RANK_X - w, py, tempstr, color );
+
+        // Draw name of team leader
+        leader = BATTLE_TeamLeader[ team ];
+        if ( gamestate.teamplay )
+        {
+            DrawIntensityString( BT_PLAYER_X, py,
+                                 colorname[ PLAYERSTATE[ leader ].uniformcolor ], color );
+        }
+        else
+        {
+            DrawIntensityString( BT_PLAYER_X, py,
+                                 PLAYERSTATE[ leader ].codename, color );
+        }
+
+        if ( dofullstats )
+        {
+            // Count how many kills each person on the team got
+            killcount = 0;
+            suicidecount = 0;
+            for( killer = 0; killer < NumPlayers; killer++ )
+            {
+                if ( BATTLE_Team[ killer ] == team )
+                {
+                    for( victim = 0; victim < NumPlayers; victim++ )
+                    {
+                        if ( BATTLE_Team[ victim ] != team )
+                        {
+                            killcount += WhoKilledWho[ killer ][ victim ];
+                        }
+                        else
+                        {
+                            suicidecount += WhoKilledWho[ killer ][ victim ];
+                        }
+                    }
+                }
+            }
+
+            // Draw kills
+            itoa( killcount, tempstr, 10 );
+            VW_MeasureIntensityPropString ( tempstr, &w, &h);
+            DrawIntensityString( BT_KILLS_X - w, py, tempstr, color );
+
+            // Draw suicides
+            itoa( suicidecount, tempstr, 10 );
+            VW_MeasureIntensityPropString ( tempstr, &w, &h);
+            DrawIntensityString( BT_DEATHS_X - w, py, tempstr, color );
+        }
+
+        // Draw Score
+        itoa( BATTLE_Points[ team ], tempstr, 10 );
+        VW_MeasureIntensityPropString ( tempstr, &w, &h);
+        DrawIntensityString( BT_SCORE_X - w, py, tempstr, color );
+
+        py += h;
+    }
+}
+
+
+void BattleLevelCompleted ( int localplayer )
+{
+    ControlInfo ci;
+    int w;
+    int h;
+    int key;
+    int Screen;
+    int LastScreen;
+    int Player;
+    char text[80];
+
+    EnableScreenStretch();
+
+    IN_ClearKeysDown ();
+
+    Player = localplayer;
+    Screen = 1;
+    LastScreen = 0;
+    key = -1;
+    while( 1 )
+    {
+        if ( Screen != LastScreen )
+        {
+            VL_DrawPostPic (W_GetNumForName("trilogo"));
+
+            switch( Screen )
+            {
+            case 1 :
+                ShowEndScore( Player );
+                break;
+
+            case 2 :
+                ShowKills( Player );
+                break;
+
+            case 3 :
+                ShowDeaths( Player );
+                break;
+            }
+
+            CurrentFont = tinyfont;
+
+            sprintf ( text, "Page %d of 3.  Use arrows to switch stats.  "
+                      "Press Esc to quit.", Screen );
+            VW_MeasurePropString ( text, &w, &h);
+            py = 192;
+            px = ( 320 - w ) / 2;
+            VWB_DrawPropString ( text );
+            VW_UpdateScreen ();
+
+            do
+            {
+                ReadAnyControl (&ci);
+            }
+            while( ci.dir == (dirtype)key );
+        }
+
+        LastScreen = Screen;
+        ReadAnyControl ( &ci );
+        key = ci.dir;
+        if ( ( Screen > 1 ) && ( key == dir_West ) )
+        {
+            Screen--;
+            MN_PlayMenuSnd (SD_MOVECURSORSND);
+        }
+        else if ( ( Screen < 3 ) && ( key == dir_East ) )
+        {
+            Screen++;
+            MN_PlayMenuSnd (SD_MOVECURSORSND);
+        }
+        // Allow us to select which player to view
+        if ( Keyboard[ sc_RShift ] && ( key == dir_South ) )
+        {
+            Player++;
+            if ( Player >= numplayers )
+            {
+                Player = 0;
+            }
+            LastScreen = 0;
+            MN_PlayMenuSnd (SD_SELECTSND);
+        }
+
+        if ( Keyboard[ sc_RShift ] && ( key == dir_North ) )
+        {
+            Player--;
+            if ( Player < 0 )
+            {
+                Player = numplayers - 1;
+            }
+            LastScreen = 0;
+            MN_PlayMenuSnd (SD_SELECTSND);
+        }
+
+        if ( Keyboard[sc_Escape] )
+        {
+            break;
+        }
+    }
+
+    while ( Keyboard[sc_Escape] )
+    {
+        IN_UpdateKeyboard ();
+    }
+
+    MN_PlayMenuSnd (SD_ESCPRESSEDSND);
+
+    CurrentFont = smallfont;
+}
+
+//==========================================================================
+
+/*
+==================
+=
+= FindAngleToWindow
+=
+==================
+*/
+int FindAngleToWindow ( int tx, int ty )
+{
+    if (!IsWindow(tx+1,ty))
+        return ANG180;
+    else if (!IsWindow(tx-1,ty))
+        return 0;
+    else if (!IsWindow(tx,ty+1))
+        return ANG90;
+    else
+        return ANG270;
+}
+
+#define STARTRADIUS (0xa000)
+#define STOPRADIUS (0x14000)
+#define DEATHRADIUS (STOPRADIUS-STARTRADIUS)
+#define ROTRATE      (5)
+#define TOTALDEATHROT (FINEANGLES<<1)
+#define RADIUSINC   ((DEATHRADIUS)/(TOTALDEATHROT))
+
+/*
+==================
+=
+= ZoomDeathOkay
+=
+==================
+*/
+boolean ZoomDeathOkay ( void )
+{
+    int x,y;
+    int radius;
+
+    if (
+        !(
+            (player->state==&s_ashwait) ||
+            ((player->flags & FL_HBM) && (gamestate.violence >= vl_high))
+        )
+    )
+        return false;
+
+    radius=STOPRADIUS;
+    x=player->x;
+    y=player->y;
+    while (radius>0)
+    {
+        if (tilemap[x>>16][(y+radius)>>16])
+            return false;
+        if (tilemap[x>>16][(y-radius)>>16])
+            return false;
+        if (tilemap[(x-radius)>>16][y>>16])
+            return false;
+        if (tilemap[(x+radius)>>16][y>>16])
+            return false;
+        if (tilemap[(x+radius)>>16][(y+radius)>>16])
+            return false;
+        if (tilemap[(x+radius)>>16][(y-radius)>>16])
+            return false;
+        if (tilemap[(x-radius)>>16][(y+radius)>>16])
+            return false;
+        if (tilemap[(x-radius)>>16][(y-radius)>>16])
+            return false;
+        radius-=0x10000;
+    }
+    return true;
+}
+
+/*
+==================
+=
+= Died
+=
+==================
+*/
+
+#define DEATHROTATE 6
+
+extern boolean dopefish;
+void Died (void)
+{
+    long  dx,dy;
+    int      iangle,curangle,clockwise,change;
+    int   da;
+    int   rate;
+    lbm_t *LBM;
+    int   slowrate;
+    playertype *pstate;
+    objtype * killerobj=(objtype *)player->target;
+    player->yzangle=0;
+
+    if (killerobj == NULL)
+        killerobj = player;
+
+    if (CheckParm("slowdeath"))
+        slowrate=3;
+    else
+        slowrate=0;
+
+    M_LINKSTATE (player, pstate);
+
+    if ( (ZoomDeathOkay()==true) && (pstate->falling==false))
+    {
+        int x,y,z,radius,heightoffset;
+        int endangle,startangle,killangle;
+        boolean deadflagset;
+        objtype * dummy;
+
+        x=player->x;
+        y=player->y;
+        z=player->z;
+        dummy=player;
+        SpawnPlayerobj (x>>16, y>>16, 0, 0);
+        player=dummy;
+        dummy=new;
+        dummy->x=x;
+        dummy->drawx=x;
+        dummy->y=y;
+        dummy->z=z;
+        dummy->drawy=y;
+        dummy->flags=player->flags;
+        player->momentumx=0;
+        player->momentumy=0;
+        player->speed=0;
+        radius=STARTRADIUS;
+        heightoffset=pstate->heightoffset;
+        deadflagset=false;
+        startangle=(player->angle+ANG180)&(FINEANGLES-1);
+        endangle=startangle+TOTALDEATHROT;
+        killangle=startangle+(TOTALDEATHROT>>1);
+        if (dopefish==true)
+        {
+            AddMessage("Dopefish Death Cam",MSG_SYSTEM);
+        }
+        for (iangle=startangle;;)
+        {
+            if ( iangle > killangle )
+            {
+                if ( deadflagset==false )
+                {
+                    dummy->hitpoints=0;
+                    pstate->health=0;
+                    dummy->flags &= ~FL_DYING;
+                    dummy->flags |= FL_SHOOTABLE;
+                    if (player->state==&s_ashwait)
+                        dummy->flags |= FL_SKELETON;
+                    Collision(dummy,(objtype*)NULL,0,0);
+                    deadflagset=true;
+                    if ( ( killerobj==player ) && ( gamestate.violence >=
+                                                    vl_high ) && ( gamestate.difficulty >= gd_hard ) )
+                    {
+                        SD_Play( SD_YOUSUCKSND );
+                    }
+                    else
+                    {
+                        SD_Play (SD_PLAYERTCDEATHSND+(pstate->player));
+                    }
+                }
+            }
+            else
+            {
+                dummy->flags &= ~FL_DYING;
+            }
+            if (dopefish==true)
+            {
+                dummy->momentumx+=(RandomNumber("Died",0)<<6)-(256<<5);
+                dummy->momentumy+=(RandomNumber("Died",0)<<6)-(256<<5);
+            }
+            player->x=x+FixedMul(radius,costable[iangle&(FINEANGLES-1)]);
+            player->y=y-FixedMul(radius,sintable[iangle&(FINEANGLES-1)]);
+            player->z=dummy->z;
+            player->angle=(iangle+ANG180)&(FINEANGLES-1);
+            if (dopefish==true)
+            {
+                int dx,dy;
+
+                dx = dummy->x - player->x;
+                dy = player->y - dummy->y;
+
+                if (dx && dy)
+                    player->angle = atan2_appx (dx,dy);
+            }
+            pstate->heightoffset=heightoffset;
+            player->yzangle=0;
+            UpdateGameObjects();
+            player->momentumx=0;
+            player->momentumy=0;
+            player->speed=0;
+            ThreeDRefresh ();
+            AnimateWalls();
+            DoSprites();
+            DoAnimatedMaskedWalls();
+            UpdatePlayers();
+            UpdateLightLevel(player->areanumber);
+
+            if (iangle<endangle)
+            {
+                iangle+=(tics<<ROTRATE);
+                radius+=tics*(RADIUSINC<<ROTRATE);
+            }
+            if ( (dummy->state==dummy->state->next) && (iangle>=endangle) )
+                break;
+        }
+    }
+    else if (pstate->falling==false)
+    {
+
+        //
+        // swing around to face attacker
+        //
+
+        rate=DEATHROTATE-slowrate;
+        {
+            if (killerobj==player)
+            {
+                iangle=player->angle;
+                if ( ( gamestate.violence >= vl_high ) &&
+                        ( gamestate.difficulty >= gd_hard ) )
+                {
+                    SD_Play( SD_YOUSUCKSND );
+                }
+            }
+            else
+            {
+                SD_Play (SD_PLAYERTCDEATHSND+(pstate->player));
+                if (killerobj->which==PWALL)
+                {
+                    dx = ((pwallobj_t *)killerobj)->x - player->x;
+                    dy = player->y - ((pwallobj_t *)killerobj)->y;
+                }
+                else
+                {
+                    dx = killerobj->x - player->x;
+                    dy = player->y - killerobj->y;
+                }
+
+                iangle = atan2_appx (dx,dy);       // returns -pi to pi
+            }
+        }
+
+        da = iangle-player->angle;
+
+        if (da>0)
+            clockwise=1;
+        else
+            clockwise=0;
+        da=abs(da);
+        if (da>ANG180)
+        {
+            clockwise^=1;
+            da=ANGLES-da;
+        }
+
+        curangle = player->angle;
+
+        do
+        {
+            DoBorderShifts ();
+            change = tics<<rate;
+            if (clockwise==1)
+                curangle+=change;
+            else
+                curangle-=change;
+            da-=change;
+            if (curangle >= ANGLES)
+                curangle -= ANGLES;
+            if (curangle < 0)
+                curangle += ANGLES;
+            player->angle = (curangle & (FINEANGLES-1));
+            ThreeDRefresh ();
+            CalcTics ();
+        } while (da>0);
+    }
+    else
+    {
+        DrawFullSky();
+        FlipPage();
+    }
+
+    while (damagecount)
+        DoBorderShifts ();
+    DoBorderShifts ();
+
+    locplayerstate->weapon = -1;        // take away weapon
+
+    if (
+        (tedlevel == false) && // SO'S YA DON'T GET KILLED WHILE LAUNCHING!
+        (timelimitenabled == false)
+    )
+        locplayerstate->lives--;
+
+    if (pstate->falling==false)
+    {
+        ThreeDRefresh ();
+    }
+
+    FlipPage();
+    FlipPage();
+
+    if (locplayerstate->lives > -1)
+    {
+        int rng;
+
+        rng = RandomNumber ("Died",0);
+
+        if (pstate->falling==true)
+        {
+            RotateBuffer (0, 0, (FINEANGLES), (FINEANGLES>>6), (VBLCOUNTER*(1+slowrate)));
+            SD_Play (SD_PLAYERTCDEATHSND+(pstate->player));
+            pstate->falling=false;
+        }
+
+        else if (rng < 64)
+            RotateBuffer (0, 0, (FINEANGLES), (FINEANGLES*64), (VBLCOUNTER*(2+slowrate)));
+        else if (rng < 128)
+        {
+            RotateBuffer (0, 0, (FINEANGLES), (FINEANGLES>>6), (VBLCOUNTER*(1+slowrate)));
+        }
+        else if (rng < 192)
+            RotateBuffer(0, (FINEANGLES*4), (FINEANGLES), (FINEANGLES*64), (VBLCOUNTER*(3+slowrate)));
+        else
+            VL_FadeToColor (VBLCOUNTER*2, 100, 0, 0);
+
+        screenfaded=false;
+
+        VL_FadeOut (0, 255, 0,0,0,VBLCOUNTER>>1);
+        gamestate.episode = 1;
+        player->flags &= ~FL_DONE;
+
+        InitializeWeapons (locplayerstate);
+        ResetPlayerstate(locplayerstate);
+
+        UpdateLives (locplayerstate->lives);
+        UpdateScore (gamestate.score);
+
+        DrawTriads(true);
+        DrawLives (true);
+        DrawKeys (true);
+        DrawScore (true);
+    }
+    else
+    {
+        int rng;
+
+        SD_Play (SD_GAMEOVERSND);
+        rng=RandomNumber("Died",0);
+        if (rng<64)
+            RotateBuffer(0,(FINEANGLES>>1),(FINEANGLES),(FINEANGLES*64),(VBLCOUNTER*(3+slowrate)));
+        else if (rng<128)
+            VL_FadeToColor (VBLCOUNTER*3, 255, 255, 255);
+        else if (rng<192)
+            RotateBuffer(0,(FINEANGLES*2),(FINEANGLES),(FINEANGLES*64),(VBLCOUNTER*(3+slowrate)));
+        else
+            RotateBuffer(0,(FINEANGLES*2),(FINEANGLES),(FINEANGLES*64),(VBLCOUNTER*(3+slowrate)));
+
+        screenfaded=false;
+
+        VL_FadeOut (0, 255, 0,0,0,VBLCOUNTER>>1);
+
+        MU_StartSong(song_gameover);
+
+#if (SHAREWARE==0)
+        if (gamestate.violence==vl_excessive)
+            LBM = (lbm_t *) W_CacheLumpNum (W_GetNumForName ("bootblod"), PU_CACHE, Cvt_lbm_t, 1);
+        else
+            LBM = (lbm_t *) W_CacheLumpNum (W_GetNumForName ("bootnorm"), PU_CACHE, Cvt_lbm_t, 1);
+#else
+        LBM = (lbm_t *) W_CacheLumpNum (W_GetNumForName ("bootblod"), PU_CACHE, Cvt_lbm_t, 1);
+#endif
+        VL_DecompressLBM (LBM,true);
+
+        StopWind();
+
+        IN_UserInput (VBLCOUNTER*60);
+
+        MainMenu[savegame].active = 0;
+        MainMenu[viewscores].routine = (void *)CP_ViewScores;
+        MainMenu[viewscores].texture[6] = '7';
+        MainMenu[viewscores].texture[7] = '\0';
+        MainMenu[viewscores].letter     = 'V';
+    }
+    ClearGraphicsScreen();
+
+    VL_FadeIn (0, 255, origpal, 15);
+}
+
+
+//******************************************************************************
+//
+// DoLoadGameAction ()
+//
+//******************************************************************************
+
+static byte whichstr = 0;
+
+void DoLoadGameAction (void)
+{
+    if ((SaveTime+1) < GetTicCount())
+    {
+        byte *temp = bufferofs;
+
+        bufferofs = displayofs;
+        SaveTime = GetTicCount();
+
+        CurrentFont=tinyfont;
+
+        px = 92;
+        py = 152;
+        if (whichstr)
+        {
+//         VW_DrawPropString ("�");
+            VW_DrawPropString (".");
+            whichstr = 0;
+        }
+        else
+        {
+//         VW_DrawPropString ("�");
+            VW_DrawPropString (".");
+            whichstr = 1;
+        }
+        bufferofs = temp;
+    }
+}
+
+//******************************************************************************
+//
+// DoCheckSum ()
+//
+//******************************************************************************
+
+long DoCheckSum (byte *source, int size, long csum)
+{
+    int i;
+    long checksum;
+
+    checksum = csum;
+
+    for (i = 0; i < size; i++)
+        checksum=updatecrc(checksum,*(source+i));
+
+    return checksum;
+}
+
+//******************************************************************************
+//
+// CaculateSaveGameCheckSum ()
+//
+//******************************************************************************
+
+#define SAVECHECKSUMSIZE (10000)
+long CalculateSaveGameCheckSum (char * filename)
+{
+    int handle;
+    int lengthleft;
+    int length;
+    byte * altbuffer;
+    long checksum;
+
+    altbuffer=SafeMalloc(SAVECHECKSUMSIZE);
+
+    checksum = 0;
+
+    // Open the savegame file
+
+    handle = SafeOpenRead (filename);
+    lengthleft = filelength (handle);
+
+    while (lengthleft>0)
+    {
+        length=SAVECHECKSUMSIZE;
+        if (length>lengthleft)
+            length=lengthleft;
+
+        SafeRead(handle,altbuffer,length);
+        checksum = DoCheckSum (altbuffer, length, checksum);
+
+        lengthleft-=length;
+    }
+
+    SafeFree(altbuffer);
+
+    close (handle);
+
+    return checksum;
+}
+
+//******************************************************************************
+//
+// StoreBuffer
+//
+//******************************************************************************
+void StoreBuffer (int handle, byte * src, int size)
+{
+    SafeWrite(handle,&size,sizeof(size));
+    SafeWrite(handle,src,size);
+}
+
+//******************************************************************************
+//
+// SaveTag
+//
+//******************************************************************************
+void SaveTag (int handle, char * tag, int size)
+{
+    SafeWrite(handle,tag,size);
+}
+
+
+//******************************************************************************
+//
+// SaveTheGame ()
+//
+// Expects game to be premalloced
+//
+//******************************************************************************
+
+extern boolean enableZomROTT;
+extern boolean allowBlitzMoreMissileWeps;
+extern boolean enableAmmoPickups;
+
+boolean SaveTheGame (int num, gamestorage_t * game)
+{
+    char   loadname[MAX_PATH]="rottgam0.rot";
+    char   filename[MAX_PATH];
+    byte   * altbuffer;
+    int    size;
+    int    avail;
+    int    savehandle;
+    int    crc;
+    int    i;
+    char   letter;
+    int myticcount;
+
+    if (num > 15 || num < 0)
+        Error("Illegal Saved game value=%d\n",num);
+
+    //
+    // Save Alternate Game Level information for reloading game
+    //
+    memset (&game->info, 0, sizeof (game->info));
+    if (GameLevels.avail == true)
+    {
+        game->info.path = GameLevels.path;
+        game->info.file = GameLevels.file;
+        game->info.avail = true;
+    }
+
+    game->mapcrc=GetMapCRC (gamestate.mapon);
+
+    // Create the proper file name
+
+    itoa(num,&loadname[7],16);
+    loadname[8]='.';
+
+
+    GetPathFromEnvironment( filename, ApogeePath, loadname );
+
+#if PLATFORM_DOS
+    {
+        struct diskfree_t dfree;
+        // Determine available disk space
+        letter = toupper(filename[0]);
+        if (
+            (letter >= 'A') &&
+            (letter <= 'Q')
+        )
+        {
+            if (_dos_getdiskfree ((letter-'A'+1), &dfree))
+                Error ("Error in _dos_getdiskfree call\n");
+        }
+        else
+        {
+            if (_dos_getdiskfree (0, &dfree))
+                Error ("Error in _dos_getdiskfree call\n");
+        }
+
+        avail = (int) dfree.avail_clusters *
+                dfree.bytes_per_sector *
+                dfree.sectors_per_cluster;
+        avail -= 8192;
+
+        // Check to see if we have enough
+
+        if (avail < MAXSAVEDGAMESIZE)
+        {
+            CP_DisplayMsg ("There is not enough\nspace on your disk\nto Save Game!\nPress any key to continue", 13);
+            return (false);
+        }
+    }
+#endif
+
+    // Open the savegame file
+
+    savehandle = SafeOpenWrite (filename);
+
+    // Save out file tag
+
+    size=4;
+    SaveTag(savehandle,"ROTT",size);
+
+    // Save out header
+
+    size=sizeof(*game);
+
+    SafeWrite(savehandle,game,size);
+
+/////////////////////////////////////////////////////////////////////////////
+// Save out rest of save game file beyond this point
+/////////////////////////////////////////////////////////////////////////////
+
+    // Door Tag
+
+    size=4;
+    SaveTag(savehandle,"DOOR",size);
+
+    // Doors
+
+    SaveDoors(&altbuffer,&size);
+    StoreBuffer(savehandle,altbuffer,size);
+    SafeFree(altbuffer);
+
+    // Elevator Tag
+
+    size = 9;
+    SaveTag(savehandle,"ELEVATORS",size);
+
+    // Elevators
+
+    SaveElevators(&altbuffer,&size);
+    StoreBuffer(savehandle,altbuffer,size);
+    SafeFree(altbuffer);
+
+    // Pushwall Tag
+
+    size=5;
+    SaveTag(savehandle,"PWALL",size);
+
+    // PushWalls
+
+    SavePushWalls(&altbuffer,&size);
+    StoreBuffer(savehandle,altbuffer,size);
+    SafeFree(altbuffer);
+
+    // MaskedWalls Tag
+
+    size=5;
+    SaveTag(savehandle,"MWALL",size);
+
+    // Masked Walls
+
+    SaveMaskedWalls(&altbuffer,&size);
+    StoreBuffer(savehandle,altbuffer,size);
+    SafeFree(altbuffer);
+
+    // Switches Tag
+
+    size=6;
+    SaveTag(savehandle,"SWITCH",size);
+
+    // Switches
+
+    SaveSwitches(&altbuffer,&size);
+    StoreBuffer(savehandle,altbuffer,size);
+    SafeFree(altbuffer);
+
+    // Statics Tag
+
+    size=6;
+    SaveTag(savehandle,"STATIC",size);
+
+    // Statics
+
+    SaveStatics(&altbuffer,&size);
+    StoreBuffer(savehandle,altbuffer,size);
+    SafeFree(altbuffer);
+
+    // Actors Tag
+
+    size=5;
+    SaveTag(savehandle,"ACTOR",size);
+
+    // Actors
+
+    SaveActors(&altbuffer,&size);
+    StoreBuffer(savehandle,altbuffer,size);
+    SafeFree(altbuffer);
+
+    // TouchPlates Tag
+
+    size=5;
+    SaveTag(savehandle,"TOUCH",size);
+
+    // TouchPlates
+
+    SaveTouchPlates(&altbuffer,&size);
+    StoreBuffer(savehandle,altbuffer,size);
+    SafeFree(altbuffer);
+
+    // GameState Tag
+
+    size=9;
+    SaveTag(savehandle,"GAMESTATE",size);
+
+    // GameState
+
+    size=sizeof(gamestate);
+    SafeWrite(savehandle,&gamestate,size);
+
+    // PlayerState Tag
+
+    size=12;
+    SaveTag(savehandle,"PLAYERSTATES",size);
+
+    // PlayerStates
+    size=sizeof(playertype);
+    for(i=0; i<numplayers; i++)
+    {
+        SafeWrite(savehandle,&PLAYERSTATE[i],size);
+    }
+
+    // Mapseen Tag
+
+    size=7;
+    SaveTag(savehandle,"MAPSEEN",size);
+
+    // MapSeen
+
+    size=sizeof(mapseen);
+    SafeWrite(savehandle,&mapseen,size);
+
+    // Song Tag
+
+    size=4;
+    SaveTag(savehandle,"SONG",size);
+
+    // Song info
+
+    MU_SaveMusic(&altbuffer,&size);
+    StoreBuffer(savehandle,altbuffer,size);
+    SafeFree(altbuffer);
+
+    // Misc Tag
+
+    size=4;
+    SaveTag(savehandle,"MISC",size);
+
+    // Misc
+
+    // ticcount
+    myticcount = GetTicCount();
+    size=sizeof(myticcount);
+    SafeWrite(savehandle,&myticcount,size);
+
+    // shaketics
+    size=sizeof(SHAKETICS);
+    SafeWrite(savehandle,&SHAKETICS,size);
+
+    // damagecount
+    size=sizeof(damagecount);
+    SafeWrite(savehandle,&damagecount,size);
+
+    // viewsize
+    size=sizeof(viewsize);
+    SafeWrite(savehandle,&viewsize,size);
+
+    // poweruptimes
+    size = sizeof (poweruptime);
+    SafeWrite(savehandle,&poweruptime,size);
+
+    size = sizeof (protectiontime);
+    SafeWrite(savehandle,&protectiontime,size);
+
+    size = sizeof (powerupheight);
+    SafeWrite(savehandle,&powerupheight,size);
+
+    size = sizeof (protectionheight);
+    SafeWrite(savehandle,&protectionheight,size);
+
+    size = sizeof (poweradjust);
+    SafeWrite(savehandle,&poweradjust,size);
+    
+    size = sizeof (allowBlitzMoreMissileWeps);
+    SafeWrite(savehandle, &allowBlitzMoreMissileWeps, size);
+    
+    size = sizeof (enableAmmoPickups);
+    SafeWrite(savehandle, &enableAmmoPickups, size);
+    
+    size = sizeof(enableZomROTT);
+    SafeWrite(savehandle, &enableZomROTT, size);
+    
+    //ZomROTT Stuff
+    if(enableZomROTT)
+    {
+        SaveResurrectList(&altbuffer, &size);
+        StoreBuffer(savehandle,altbuffer,size);
+        SafeFree(altbuffer);
+    }
+
+    close (savehandle);
+
+    // Calculate CRC
+
+    crc = CalculateSaveGameCheckSum (filename);
+
+    // Append the crc
+
+    savehandle = SafeOpenAppend (filename);
+
+    size=sizeof(crc);
+    SafeWrite(savehandle,&crc,size);
+
+    close (savehandle);
+
+    pickquick = true;
+    return (true);
+}
+
+
+//******************************************************************************
+//
+// LoadTag
+//
+//******************************************************************************
+
+void LoadTag (byte ** src, char * tag, int size)
+{
+    if (StringsNotEqual((char *)*src,(char *)tag,size)==true)
+        Error("Could not locate %s header in saved game file\n",tag);
+    *src+=size;
+}
+
+//******************************************************************************
+//
+// LoadBuffer
+//
+//******************************************************************************
+int LoadBuffer (byte ** dest, byte ** src)
+{
+    int size;
+
+    memcpy(&size,*src,sizeof(size));
+    *src+=sizeof(size);
+    *dest=SafeMalloc(size);
+    memcpy(*dest,*src,size);
+    *src+=size;
+    return size;
+}
+
+
+//******************************************************************************
+//
+// LoadTheGame ()
+//
+// Expects game to be premalloced
+//
+//******************************************************************************
+
+extern objtype* enemiesToRes;
+extern unsigned int freeSlot;
+
+boolean LoadTheGame (int num, gamestorage_t * game)
+{
+    char   loadname[45]="rottgam0.rot";
+    char   filename[128];
+    byte   * loadbuffer;
+    byte   * bufptr;
+    byte   * altbuffer;
+    int    size;
+    int    totalsize;
+    int    checksum;
+    int    savedchecksum;
+    int    i;
+    word   mapcrc;
+    int myticcount;
+
+    if (num>15 || num<0)
+        Error("Illegal Load game value=%d\n",num);
+
+    // Create the proper file name
+
+    itoa(num,&loadname[7],16);
+    loadname[8]='.';
+
+    GetPathFromEnvironment( filename, ApogeePath, loadname );
+
+    // Load the file
+
+    totalsize=LoadFile(filename,(void **)&loadbuffer);
+    bufptr=loadbuffer;
+
+    // Calculate checksum
+
+    checksum = DoCheckSum (loadbuffer, totalsize-sizeof(checksum), 0);
+
+    // Retrieve saved checksum
+
+    memcpy (&savedchecksum,loadbuffer+(totalsize-sizeof(savedchecksum)),sizeof(savedchecksum));
+
+    // Compare the two checksums;
+
+    if (checksum!=savedchecksum)
+    {
+        if (CP_DisplayMsg ("Your Saved Game file is\n"
+                           "shall we say, \"corrupted\".\n"
+                           "Would you like to\n"
+                           "continue anyway (Y/N)?\n", 12)==false)
+        {
+            return false;
+        }
+    }
+
+    // Load in file tag
+
+    size=4;
+    LoadTag(&bufptr,"ROTT",size);
+
+    // Load in header
+
+    size=sizeof(*game);
+    memcpy(game,bufptr,size);
+    bufptr+=size;
+
+    if (game->version!=ROTTVERSION)
+        return false;
+
+    memcpy (&GameLevels, &game->info, sizeof (GameLevels));
+
+    gamestate.episode=game->episode;
+    gamestate.mapon=game->area;
+
+    mapcrc=GetMapCRC (gamestate.mapon);
+
+    if (mapcrc!=game->mapcrc)
+        return false;
+
+/////////////////////////////////////////////////////////////////////////////
+// Load in rest of saved game file beyond this point
+/////////////////////////////////////////////////////////////////////////////
+
+    // Free up the current level
+    Z_FreeTags (PU_LEVELSTRUCT, PU_LEVELEND);       // Free current level
+
+    gamestate.battlemode = battle_StandAloneGame;
+    BATTLE_SetOptions( &BATTLE_Options[ battle_StandAloneGame ] );
+    BATTLE_Init( gamestate.battlemode, 1 );
+
+    DoLoadGameAction ();
+    SetupGameLevel();
+
+    // This prevents a nasty glitch when loading some saved games
+    PreCacheGroup(W_GetNumForName("BULLETHO"),W_GetNumForName("ALTBHO"),cache_transpatch_t);
+
+    // Door Tag
+
+    size=4;
+    LoadTag(&bufptr,"DOOR",size);
+
+    // Doors
+
+    DoLoadGameAction ();
+    size=LoadBuffer(&altbuffer,&bufptr);
+    LoadDoors(altbuffer,size);
+    SafeFree(altbuffer);
+
+    // Elevator Tag
+
+    size = 9;
+    LoadTag(&bufptr,"ELEVATORS",size);
+
+
+    // Elevators
+
+    DoLoadGameAction ();
+    size=LoadBuffer(&altbuffer,&bufptr);
+    LoadElevators(altbuffer,size);
+    SafeFree(altbuffer);
+
+    // Pushwall Tag
+
+    size=5;
+    LoadTag(&bufptr,"PWALL",size);
+
+    // PushWalls
+
+    DoLoadGameAction ();
+    size=LoadBuffer(&altbuffer,&bufptr);
+    LoadPushWalls(altbuffer,size);
+    SafeFree(altbuffer);
+#if 0
+    // Animated Walls Tag
+
+    size=5;
+    LoadTag(&bufptr,"AWALL",size);
+
+    // Animated Walls
+    size=LoadBuffer(&altbuffer,&bufptr);
+    LoadAnimWalls(altbuffer,size);
+    SafeFree(altbuffer);
+#endif
+
+    // MaskedWalls Tag
+
+    size=5;
+    LoadTag(&bufptr,"MWALL",size);
+
+    // Masked Walls
+
+    DoLoadGameAction ();
+    size=LoadBuffer(&altbuffer,&bufptr);
+    LoadMaskedWalls(altbuffer,size);
+    SafeFree(altbuffer);
+
+    // Switches Tag
+
+    size=6;
+    LoadTag(&bufptr,"SWITCH",size);
+
+    // Switches
+
+    DoLoadGameAction ();
+    size=LoadBuffer(&altbuffer,&bufptr);
+    LoadSwitches(altbuffer,size);
+    SafeFree(altbuffer);
+
+
+    // Statics Tag
+
+    size=6;
+    LoadTag(&bufptr,"STATIC",size);
+
+    // Statics
+
+    DoLoadGameAction ();
+    size=LoadBuffer(&altbuffer,&bufptr);
+    LoadStatics(altbuffer,size);
+    SafeFree(altbuffer);
+
+    // Actors Tag
+
+    size=5;
+    LoadTag(&bufptr,"ACTOR",size);
+
+    // Actors
+
+    DoLoadGameAction ();
+    size=LoadBuffer(&altbuffer,&bufptr);
+    LoadActors(altbuffer,size);
+    SafeFree(altbuffer);
+
+    // TouchPlates Tag
+
+    size=5;
+    LoadTag(&bufptr,"TOUCH",size);
+
+    // TouchPlates
+
+    DoLoadGameAction ();
+    size=LoadBuffer(&altbuffer,&bufptr);
+    LoadTouchPlates(altbuffer,size);
+    SafeFree(altbuffer);
+
+    // SetupWindows
+
+    SetupWindows();
+
+    // GameState Tag
+
+    size=9;
+    LoadTag(&bufptr,"GAMESTATE",size);
+
+    // GameState
+
+    DoLoadGameAction ();
+    size=sizeof(gamestate);
+    memcpy(&gamestate,bufptr,size);
+    bufptr+=size;
+
+    // PlayerState Tag
+
+    size=12;
+    LoadTag(&bufptr,"PLAYERSTATES",size);
+
+    // PlayerState
+
+    DoLoadGameAction ();
+    size=sizeof(playertype);
+    for(i=0; i<numplayers; i++)
+    {   memcpy(&PLAYERSTATE[i],bufptr,size);
+        bufptr+=size;
+    }
+
+    // Zero out player targets
+
+    locplayerstate->guntarget=0;
+    locplayerstate->targettime=0;
+
+    // Mapseen Tag
+
+    size=7;
+    LoadTag(&bufptr,"MAPSEEN",size);
+
+    // MapSeen
+
+    DoLoadGameAction ();
+    size=sizeof(mapseen);
+    memcpy(&mapseen,bufptr,size);
+    bufptr+=size;
+
+    // Song Tag
+
+    size=4;
+    LoadTag(&bufptr,"SONG",size);
+
+    // Song info
+
+    DoLoadGameAction ();
+    size=LoadBuffer(&altbuffer,&bufptr);
+    MU_LoadMusic(altbuffer,size);
+    SafeFree(altbuffer);
+
+    // Misc Tag
+
+    size=4;
+    LoadTag(&bufptr,"MISC",size);
+
+    // Misc
+
+    // ticcount
+    DoLoadGameAction ();
+    size=sizeof(myticcount);
+    memcpy((void *)&myticcount,bufptr,size);
+    bufptr+=size;
+    SaveTime = myticcount;
+    ISR_SetTime(myticcount);
+
+    // shaketics
+    DoLoadGameAction ();
+    size=sizeof(SHAKETICS);
+    memcpy(&SHAKETICS,bufptr,size);
+    bufptr+=size;
+
+    // damagecount
+    DoLoadGameAction ();
+    size=sizeof(damagecount);
+    memcpy(&damagecount,bufptr,size);
+    bufptr+=size;
+
+    // viewsize
+    DoLoadGameAction ();
+    size=sizeof(viewsize);
+    memcpy(&viewsize,bufptr,size);
+    bufptr+=size;
+
+    // powerup times
+    DoLoadGameAction ();
+    size = sizeof (poweruptime);
+    memcpy (&poweruptime, bufptr, size);
+    bufptr += size;
+    size = sizeof (protectiontime);
+    memcpy (&protectiontime, bufptr, size);
+    bufptr += size;
+    size = sizeof (powerupheight);
+    memcpy (&powerupheight, bufptr, size);
+    bufptr += size;
+    size = sizeof (protectionheight);
+    memcpy (&protectionheight, bufptr, size);
+    bufptr += size;
+    size = sizeof (poweradjust);
+    memcpy (&poweradjust, bufptr, size);
+    bufptr += size;
+    
+    size = sizeof(allowBlitzMoreMissileWeps);
+    memcpy (&allowBlitzMoreMissileWeps, bufptr, size);
+    bufptr += size;
+    
+    size = sizeof(enableAmmoPickups);
+    memcpy (&enableAmmoPickups, bufptr, size);
+    bufptr += size;
+    
+    size = sizeof(enableZomROTT);
+    memcpy(&enableZomROTT, bufptr, size);
+    bufptr += size;
+    
+    
+    //ZomROTT Stuff
+    if(enableZomROTT)
+    {
+        enemiesToRes = calloc(sizeof(objtype), gamestate.killtotal);
+        memset(enemiesToRes, 0, sizeof(enemiesToRes));
+        size = sizeof(enemiesToRes);
+        memcpy(enemiesToRes, bufptr, size);
+        bufptr += size;
+        
+        objtype * findFreeSlotPtr;
+        //find index of free
+        for (findFreeSlotPtr = &enemiesToRes[0]; findFreeSlotPtr != 0; findFreeSlotPtr++)
+        {
+            freeSlot++;
+        }
+    }
+
+    // Set the viewsize
+
+    SetViewSize(viewsize);
+    DoLoadGameAction ();
+
+    // Connect areas
+
+    ConnectAreas ();
+    DoLoadGameAction ();
+
+    // Free up the loadbuffer
+
+    SafeFree (loadbuffer);
+    DoLoadGameAction ();
+
+    Illuminate();
+
+    IN_UpdateKeyboard ();
+    LoadPlayer ();
+    DoLoadGameAction ();
+    SetupPlayScreen();
+    UpdateScore (gamestate.score);
+    UpdateLives (locplayerstate->lives);
+    UpdateTriads (player, 0);
+    PreCache ();
+    InitializeMessages();
+
+    for (i=0; i<100; i++)
+        UpdateLightLevel(player->areanumber);
+
+    CalcTics();
+    CalcTics();
+
+    pickquick = true;
+
+    return (true);
+}
+
+
+//******************************************************************************
+//
+// GetSavedMessage ()
+//
+// Expects message to be premalloced
+//
+//******************************************************************************
+
+void GetSavedMessage (int num, char * message)
+{
+    gamestorage_t game;
+    char   loadname[45]="rottgam0.rot";
+    char   filename[128];
+    byte   * loadbuffer;
+    byte   * bufptr;
+    int    size;
+
+    if (num>15 || num<0)
+        Error("Illegal Load game value=%d\n",num);
+
+    // Create the proper file name
+
+    itoa(num,&loadname[7],16);
+    loadname[8]='.';
+
+    GetPathFromEnvironment( filename, ApogeePath, loadname );
+
+    // Load the file
+
+    size=LoadFile(filename,(void **)&loadbuffer);
+    bufptr=loadbuffer;
+
+    size=4;
+    LoadTag(&bufptr,"ROTT",size);
+
+    // Load in header
+
+    size=sizeof(game);
+    memcpy(&game,bufptr,size);
+    strcpy(message,game.message);
+    SafeFree(loadbuffer);
+}
+
+//******************************************************************************
+//
+// GetSavedHeader ()
+//
+// Expects game to be premalloced
+//
+//******************************************************************************
+
+void GetSavedHeader (int num, gamestorage_t * game)
+{
+    char   loadname[45]="rottgam0.rot";
+    char   filename[128];
+    byte   * loadbuffer;
+    byte   * bufptr;
+    int    size;
+
+    if (num>15 || num<0)
+        Error("Illegal Load game value=%d\n",num);
+
+    // Create the proper file name
+
+    itoa(num,&loadname[7],16);
+    loadname[8]='.';
+
+    GetPathFromEnvironment( filename, ApogeePath, loadname );
+
+    // Load the file
+
+    size=LoadFile(filename, (void **)&loadbuffer);
+    bufptr=loadbuffer;
+
+    size=4;
+    LoadTag(&bufptr,"ROTT",size);
+
+    // Load in header
+
+    size=sizeof(*game);
+    memcpy(game,bufptr,size);
+    SafeFree(loadbuffer);
+}
+
+
+
+//******************************************************************************
+//
+// GetLevel ()
+//
+//******************************************************************************
+
+int GetLevel (int episode, int mapon)
+{
+    int level;
+
+    level = (mapon+1) - ((episode-1) << 3);
+
+    return (level);
+}
--- /dev/null
+++ b/rott/rt_game.h
@@ -1,0 +1,148 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+#ifndef _rt_game_public
+#define _rt_game_public
+
+//***************************************************************************
+//
+// Public header for RT_GAME.C
+//
+//***************************************************************************
+
+#include "rt_actor.h"
+#include "lumpy.h"
+#include "rt_cfg.h"
+#include "rt_playr.h"
+
+//***************************************************************************
+//
+// DEFINES
+//
+//***************************************************************************
+
+#define  MaxHighName 57
+#define  MaxScores   7
+
+
+//***************************************************************************
+//
+// TYPEDEFS
+//
+//***************************************************************************
+
+typedef struct
+{
+    char  message[30];
+    byte  episode;
+    byte  area;
+    byte  version;
+    byte  picture[16000];
+    word  mapcrc;
+    AlternateInformation info;
+} gamestorage_t;
+
+typedef  struct
+{
+    char  name[MaxHighName + 1];
+    long  score;
+    word  completed,episode;
+} HighScore;
+
+
+//***************************************************************************
+//
+// GLOBALS
+//
+//***************************************************************************
+
+extern int PlayerSnds[5];
+
+//extern int SHAKETICS;
+extern unsigned short SHAKETICS;//bna++
+extern int damagecount;
+
+extern HighScore   Scores[MaxScores];
+extern int SaveTime;
+
+//***************************************************************************
+//
+// PROTOTYPES
+//
+//***************************************************************************
+
+void SetupPlayScreen (void);
+void SD_PreCache (void);
+void GameMemToScreen( pic_t *source, int x, int y, int bufferofsonly );
+void DrawPlayScreen (boolean bufferofsonly);
+
+void DrawKills (boolean bufferofsonly);
+void DrawPlayers ( void );
+void DrawGameString (int x, int y, const char * str, boolean bufferofsonly);
+void DrawNumber (int x, int y, int width, int which, boolean bufferofsonly);
+void TakeDamage (int points, objtype *attacker);
+void HealPlayer (int points, objtype * ob);
+void DrawLives (boolean bufferofsonly);
+void GiveExtraMan (void);
+void DrawScore (boolean bufferofsonly);
+void GivePoints (long points);
+void DrawKeys (boolean bufferofsonly);
+void GiveKey (int key);
+void GiveWeapon (objtype * ob, int weapon);
+void GiveMissileWeapon(objtype * ob, int which);
+void GiveLives (int newlives);
+
+void UpdateScore (unsigned int num);
+void UpdateLives (int num);
+
+void DrawTimeXY( int x, int y, int sec, boolean bufferofsonly );
+void DrawTime (boolean bufferofsonly);
+
+boolean SaveTheGame (int num, gamestorage_t * game);
+boolean LoadTheGame (int num, gamestorage_t * game);
+void GetSavedMessage (int num, char * message);
+void GetSavedHeader (int num, gamestorage_t * game);
+
+void DrawHighScores (void);
+void CheckHighScore (long score, word other, boolean INMENU);
+void LevelCompleted ( exit_t playstate );
+void BattleLevelCompleted ( int localplayer );
+void Died (void);
+void ScreenShake (void);
+void UpdateTriads (objtype * ob, int num);
+void DrawTriads (boolean bufferofsonly);
+void DrawStats (void);
+void DrawBarHealth (boolean bufferonly);
+void DrawBarAmmo (boolean bufferonly);
+void GM_DrawBonus (int which);
+
+void DrawEpisodeLevel ( int x, int y );
+void DoBorderShifts (void);
+void GM_UpdateBonus (int time, int powerup);
+void DoLoadGameAction (void);
+int GetLevel (int episode, int mapon);
+void DrawPause (void);
+void DrawPauseXY (int x, int y);
+void GivePlayerAmmo(objtype *ob, statobj_t *item_pickup, int which);
+
+void DrawColoredMPPic (int xpos, int ypos, int width, int height, int heightmod, byte *src, boolean bufferofsonly, int color);
+void StatusDrawColoredPic (unsigned x, unsigned y, pic_t *nums, boolean bufferofsonly, int color);
+
+void ClearTriads (playertype * pstate);
+#endif
--- /dev/null
+++ b/rott/rt_in.c
@@ -1,0 +1,1957 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#if PLATFORM_DOS
+#include <conio.h>
+#include <dos.h>
+#include <i86.h>
+#endif
+
+#if USE_SDL
+#include "SDL.h"
+#endif
+
+#include "rt_main.h"
+#include "rt_spbal.h"
+#include "rt_def.h"
+#include "rt_in.h"
+#include "_rt_in.h"
+#include "isr.h"
+#include "rt_util.h"
+#include "rt_swift.h"
+#include "rt_vh_a.h"
+#include "rt_cfg.h"
+#include "rt_msg.h"
+#include "rt_playr.h"
+#include "rt_net.h"
+#include "rt_com.h"
+#include "rt_cfg.h"
+//MED
+#include "memcheck.h"
+#include "keyb.h"
+
+#define MAXMESSAGELENGTH      (COM_MAXTEXTSTRINGLENGTH-1)
+
+//****************************************************************************
+//
+// GLOBALS
+//
+//****************************************************************************]
+
+//
+// Used by menu routines that need to wait for a button release.
+// Sometimes the mouse driver misses an interrupt, so you can't wait for
+// a button to be released.  Instead, you must ignore any buttons that
+// are pressed.
+//
+int IgnoreMouse = 0;
+
+// configuration variables
+//
+boolean  SpaceBallPresent;
+boolean  CybermanPresent;
+boolean  AssassinPresent;
+boolean  MousePresent;
+boolean  JoysPresent[MaxJoys];
+boolean  JoyPadPresent     = 0;
+
+//    Global variables
+//
+boolean  Paused;
+char LastASCII;
+volatile int LastScan;
+
+byte Joy_xb,
+     Joy_yb,
+     Joy_xs,
+     Joy_ys;
+word Joy_x,
+     Joy_y;
+
+
+int LastLetter = 0;
+char LetterQueue[MAXLETTERS];
+ModemMessage MSG;
+
+
+#if USE_SDL
+static SDL_Joystick* sdl_joysticks[MaxJoys];
+static int sdl_mouse_delta_x = 0;
+static int sdl_mouse_delta_y = 0;
+static word sdl_mouse_button_mask = 0;
+static int sdl_total_sticks = 0;
+static word *sdl_stick_button_state = NULL;
+static word sdl_sticks_joybits = 0;
+static int sdl_mouse_grabbed = 0;
+static unsigned int scancodes[SDLK_LAST];
+extern boolean sdl_fullscreen;
+#endif
+
+
+//   'q','w','e','r','t','y','u','i','o','p','[',']','\\', 0 ,'a','s',
+
+const char ScanChars[128] =    // Scan code names with single chars
+{
+    0, 0,'1','2','3','4','5','6','7','8','9','0','-','=', 0, 0,
+    'q','w','e','r','t','y','u','i','o','p','[',']', 0, 0,'a','s',
+    'd','f','g','h','j','k','l',';','\'','`', 0,'\\','z','x','c','v',
+    'b','n','m',',','.','/', 0, 0, 0,' ', 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'-', 0,'5', 0,'+', 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+const char ShiftedScanChars[128] =    // Shifted Scan code names with single chars
+{
+    0, 0,'!','@','#','$','%','^','&','*','(',')','_','+', 0, 0,
+    'Q','W','E','R','T','Y','U','I','O','P','{','}', 0, 0,'A','S',
+    'D','F','G','H','J','K','L',':','"','~', 0,'|','Z','X','C','V',
+    'B','N','M','<','>','?', 0, 0, 0,' ', 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'-', 0,'5', 0,'+', 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+#if 0
+const char ScanChars[128] =    // Scan code names with single chars
+{
+    '?','?','1','2','3','4','5','6','7','8','9','0','-','+','?','?',
+    'Q','W','E','R','T','Y','U','I','O','P','[',']','|','?','A','S',
+    'D','F','G','H','J','K','L',';','\'','?','?','?','Z','X','C','V',
+    'B','N','M',',','.','/','?','?','?',' ','?','?','?','?','?','?',
+    '?','?','?','?','?','?','?','?','?','?','-','?','5','?','+','?',
+    '?','?','?','?','?','?','?','?','?','?','?','?','?','?','?','?',
+    '?','?','?','?','?','?','?','?','?','?','?','?','?','?','?','?',
+    '?','?','?','?','?','?','?','?','?','?','?','?','?','?','?','?'
+};
+#endif
+
+
+
+//****************************************************************************
+//
+// LOCALS
+//
+//****************************************************************************]
+
+static KeyboardDef KbdDefs = {0x1d,0x38,0x47,0x48,0x49,0x4b,0x4d,0x4f,0x50,0x51};
+static JoystickDef JoyDefs[MaxJoys];
+static ControlType Controls[MAXPLAYERS];
+
+
+static boolean  IN_Started;
+
+static   Direction   DirTable[] =      // Quick lookup for total direction
+{
+    dir_NorthWest, dir_North,  dir_NorthEast,
+    dir_West,      dir_None,   dir_East,
+    dir_SouthWest, dir_South,  dir_SouthEast
+};
+
+int (far *function_ptr)();
+
+static char *ParmStrings[] = {"nojoys","nomouse","spaceball","cyberman","assassin",NULL};
+
+
+#if USE_SDL
+#define sdldebug printf
+
+static int sdl_mouse_button_filter(SDL_Event const *event)
+{
+    /*
+     * What DOS games expect:
+     *  0	left button pressed if 1
+     *  1	right button pressed if 1
+     *  2	middle button pressed if 1
+     *
+     *   (That is, this is what Int 33h (AX=0x05) returns...)
+     */
+
+    Uint8 bmask = SDL_GetMouseState(NULL, NULL);
+    sdl_mouse_button_mask = 0;  /* this is a static var. */
+    if (bmask & SDL_BUTTON_LMASK) sdl_mouse_button_mask |= 1;
+    if (bmask & SDL_BUTTON_RMASK) sdl_mouse_button_mask |= 2;
+    if (bmask & SDL_BUTTON_MMASK) sdl_mouse_button_mask |= 4;
+    return(0);
+} /* sdl_mouse_up_filter */
+
+
+static int sdl_mouse_motion_filter(SDL_Event const *event)
+{
+    static int mouse_x = 0;
+    static int mouse_y = 0;
+    int mouse_relative_x = 0;
+    int mouse_relative_y = 0;
+
+    if (event->type == SDL_JOYBALLMOTION)
+    {
+        mouse_relative_x = event->jball.xrel/100;
+        mouse_relative_y = event->jball.yrel/100;
+        mouse_x += mouse_relative_x;
+        mouse_y += mouse_relative_y;
+    } /* if */
+    else
+    {
+        if (sdl_mouse_grabbed || sdl_fullscreen)
+        {
+            mouse_relative_x = event->motion.xrel;
+            mouse_relative_y = event->motion.yrel;
+            mouse_x += mouse_relative_x;
+            mouse_y += mouse_relative_y;
+        } /* if */
+        else
+        {
+            mouse_relative_x = event->motion.x - mouse_x;
+            mouse_relative_y = event->motion.y - mouse_y;
+            mouse_x = event->motion.x;
+            mouse_y = event->motion.y;
+        } /* else */
+    } /* else */
+
+#if 0
+    if (mouse_x < 0) mouse_x = 0;
+    if (mouse_x > surface->w) mouse_x = surface->w;
+    if (mouse_y < 0) mouse_y = 0;
+    if (mouse_y > surface->h) mouse_y = surface->h;
+#endif
+
+    /* set static vars... */
+    sdl_mouse_delta_x += mouse_relative_x;
+    sdl_mouse_delta_y += mouse_relative_y;
+
+    return(0);
+} /* sdl_mouse_motion_filter */
+
+
+/**
+ * Attempt to flip the video surface to fullscreen or windowed mode.
+ *  Attempts to maintain the surface's state, but makes no guarantee
+ *  that pointers (i.e., the surface's pixels field) will be the same
+ *  after this call.
+ *
+ * Caveats: Your surface pointers will be changing; if you have any other
+ *           copies laying about, they are invalidated.
+ *
+ *          Do NOT call this from an SDL event filter on Windows. You can
+ *           call it based on the return values from SDL_PollEvent, etc, just
+ *           not during the function you passed to SDL_SetEventFilter().
+ *
+ *          Thread safe? Likely not.
+ *
+ *   @param surface pointer to surface ptr to toggle. May be different
+ *                  pointer on return. MAY BE NULL ON RETURN IF FAILURE!
+ *   @param flags   pointer to flags to set on surface. The value pointed
+ *                  to will be XOR'd with SDL_FULLSCREEN before use. Actual
+ *                  flags set will be filled into pointer. Contents are
+ *                  undefined on failure. Can be NULL, in which case the
+ *                  surface's current flags are used.
+ *  @return non-zero on success, zero on failure.
+ */
+static int attempt_fullscreen_toggle(SDL_Surface **surface, Uint32 *flags)
+{
+    long framesize = 0;
+    void *pixels = NULL;
+    SDL_Rect clip;
+    Uint32 tmpflags = 0;
+    int w = 0;
+    int h = 0;
+    int bpp = 0;
+    int grabmouse = (SDL_WM_GrabInput(SDL_GRAB_QUERY) == SDL_GRAB_ON);
+    int showmouse = SDL_ShowCursor(-1);
+    SDL_Color *palette = NULL;
+    int ncolors = 0;
+
+    /*
+    sdldebug("attempting to toggle fullscreen flag...");
+    */
+
+    if ( (!surface) || (!(*surface)) )  /* don't try if there's no surface. */
+    {
+        /*
+        sdldebug("Null surface (?!). Not toggling fullscreen flag.");
+        */
+        return(0);
+    } /* if */
+
+    if (SDL_WM_ToggleFullScreen(*surface))
+    {
+        /*
+        sdldebug("SDL_WM_ToggleFullScreen() seems to work on this system.");
+        */
+        if (flags)
+            *flags ^= SDL_FULLSCREEN;
+        return(1);
+    } /* if */
+
+    if ( !(SDL_GetVideoInfo()->wm_available) )
+    {
+        /*
+        sdldebug("No window manager. Not toggling fullscreen flag.");
+        */
+        return(0);
+    } /* if */
+
+    /*
+    sdldebug("toggling fullscreen flag The Hard Way...");
+    */
+    tmpflags = (*surface)->flags;
+    w = (*surface)->w;
+    h = (*surface)->h;
+    bpp = (*surface)->format->BitsPerPixel;
+
+    if (flags == NULL)  /* use the surface's flags. */
+        flags = &tmpflags;
+
+    SDL_GetClipRect(*surface, &clip);
+
+    /* save the contents of the screen. */
+    if ( (!(tmpflags & SDL_OPENGL)) && (!(tmpflags & SDL_OPENGLBLIT)) )
+    {
+        framesize = (w * h) * ((*surface)->format->BytesPerPixel);
+        pixels = malloc(framesize);
+        if (pixels == NULL)
+            return(0);
+        memcpy(pixels, (*surface)->pixels, framesize);
+    } /* if */
+
+#if 1
+    STUB_FUNCTION;   /* palette is broken. FIXME !!! --ryan. */
+#else
+    if ((*surface)->format->palette != NULL)
+    {
+        ncolors = (*surface)->format->palette->ncolors;
+        palette = malloc(ncolors * sizeof (SDL_Color));
+        if (palette == NULL)
+        {
+            free(pixels);
+            return(0);
+        } /* if */
+        memcpy(palette, (*surface)->format->palette->colors,
+               ncolors * sizeof (SDL_Color));
+    } /* if */
+#endif
+
+    if (grabmouse)
+        SDL_WM_GrabInput(SDL_GRAB_OFF);
+
+    SDL_ShowCursor(1);
+
+    *surface = SDL_SetVideoMode(w, h, bpp, (*flags) ^ SDL_FULLSCREEN);
+
+    if (*surface != NULL)
+        *flags ^= SDL_FULLSCREEN;
+
+    else  /* yikes! Try to put it back as it was... */
+    {
+        *surface = SDL_SetVideoMode(w, h, bpp, tmpflags);
+        if (*surface == NULL)  /* completely screwed. */
+        {
+            if (pixels != NULL)
+                free(pixels);
+            if (palette != NULL)
+                free(palette);
+            return(0);
+        } /* if */
+    } /* if */
+
+    /* Unfortunately, you lose your OpenGL image until the next frame... */
+
+    if (pixels != NULL)
+    {
+        memcpy((*surface)->pixels, pixels, framesize);
+        free(pixels);
+    } /* if */
+
+#if 1
+    STUB_FUNCTION;   /* palette is broken. FIXME !!! --ryan. */
+#else
+    if (palette != NULL)
+    {
+        /* !!! FIXME : No idea if that flags param is right. */
+        SDL_SetPalette(*surface, SDL_LOGPAL, palette, 0, ncolors);
+        free(palette);
+    } /* if */
+#endif
+
+    SDL_SetClipRect(*surface, &clip);
+
+    if (grabmouse)
+        SDL_WM_GrabInput(SDL_GRAB_ON);
+
+    SDL_ShowCursor(showmouse);
+
+#if 0
+    STUB_FUNCTION;  /* pull this out of buildengine/sdl_driver.c ... */
+    output_surface_info(*surface);
+#endif
+
+    return(1);
+} /* attempt_fullscreen_toggle */
+
+
+/*
+ * The windib driver can't alert us to the keypad enter key, which
+ *  Ken's code depends on heavily. It sends it as the same key as the
+ *  regular return key. These users will have to hit SHIFT-ENTER,
+ *  which we check for explicitly, and give the engine a keypad enter
+ *  enter event.
+ */
+static int handle_keypad_enter_hack(const SDL_Event *event)
+{
+    static int kp_enter_hack = 0;
+    int retval = 0;
+
+    if (event->key.keysym.sym == SDLK_RETURN)
+    {
+        if (event->key.state == SDL_PRESSED)
+        {
+            if (event->key.keysym.mod & KMOD_SHIFT)
+            {
+                kp_enter_hack = 1;
+                retval = scancodes[SDLK_KP_ENTER];
+            } /* if */
+        } /* if */
+
+        else  /* key released */
+        {
+            if (kp_enter_hack)
+            {
+                kp_enter_hack = 0;
+                retval = scancodes[SDLK_KP_ENTER];
+            } /* if */
+        } /* if */
+    } /* if */
+
+    return(retval);
+} /* handle_keypad_enter_hack */
+
+
+static int sdl_key_filter(const SDL_Event *event)
+{
+    int k;
+    int keyon;
+    int strippedkey;
+    SDL_GrabMode grab_mode = SDL_GRAB_OFF;
+    int extended;
+
+    if ( (event->key.keysym.sym == SDLK_g) &&
+            (event->key.state == SDL_PRESSED) &&
+            (event->key.keysym.mod & KMOD_CTRL) )
+    {
+        if (!sdl_fullscreen)
+        {
+            sdl_mouse_grabbed = ((sdl_mouse_grabbed) ? 0 : 1);
+            if (sdl_mouse_grabbed)
+                grab_mode = SDL_GRAB_ON;
+            SDL_WM_GrabInput(grab_mode);
+        }
+        return(0);
+    } /* if */
+
+    else if ( ( (event->key.keysym.sym == SDLK_RETURN) ||
+                (event->key.keysym.sym == SDLK_KP_ENTER) ) &&
+              (event->key.state == SDL_PRESSED) &&
+              (event->key.keysym.mod & KMOD_ALT) )
+    {
+        if (SDL_WM_ToggleFullScreen(SDL_GetVideoSurface()))
+            sdl_fullscreen ^= 1;
+        return(0);
+    } /* if */
+
+    /* HDG: put this above the scancode lookup otherwise it is never reached */
+    if ( (event->key.keysym.sym == SDLK_PAUSE) &&
+            (event->key.state == SDL_PRESSED))
+    {
+        PausePressed = true;
+        return(0);
+    }
+
+    k = handle_keypad_enter_hack(event);
+    if (!k)
+    {
+        k = scancodes[event->key.keysym.sym];
+        if (!k)   /* No DOS equivalent defined. */
+            return(0);
+    } /* if */
+
+    /* Fix elweirdo SDL capslock/numlock handling, always treat as press */
+    if ( (event->key.keysym.sym != SDLK_CAPSLOCK) &&
+            (event->key.keysym.sym != SDLK_NUMLOCK)  &&
+            (event->key.state == SDL_RELEASED) )
+        k += 128;  /* +128 signifies that the key is released in DOS. */
+
+    if (event->key.keysym.sym == SDLK_SCROLLOCK)
+        PanicPressed = true;
+
+    else
+    {
+        extended = ((k & 0xFF00) >> 8);
+
+        keyon = k & 0x80;
+        strippedkey = k & 0x7f;
+
+        if (extended != 0)
+        {
+            KeyboardQueue[ Keytail ] = extended;
+            Keytail = ( Keytail + 1 )&( KEYQMAX - 1 );
+            k = scancodes[event->key.keysym.sym] & 0xFF;
+            if (event->key.state == SDL_RELEASED)
+                k += 128;  /* +128 signifies that the key is released in DOS. */
+        }
+
+        if (keyon)        // Up event
+            Keystate[strippedkey]=0;
+        else                 // Down event
+        {
+            Keystate[strippedkey]=1;
+            LastScan = k;
+        }
+
+        KeyboardQueue[ Keytail ] = k;
+        Keytail = ( Keytail + 1 )&( KEYQMAX - 1 );
+    }
+
+    return(0);
+} /* sdl_key_filter */
+
+
+static int root_sdl_event_filter(const SDL_Event *event)
+{
+    switch (event->type)
+    {
+    case SDL_KEYUP:
+    case SDL_KEYDOWN:
+        return(sdl_key_filter(event));
+    case SDL_JOYBALLMOTION:
+    case SDL_MOUSEMOTION:
+        return(sdl_mouse_motion_filter(event));
+    case SDL_MOUSEBUTTONUP:
+    case SDL_MOUSEBUTTONDOWN:
+        return(sdl_mouse_button_filter(event));
+    case SDL_QUIT:
+        /* !!! rcg TEMP */
+        fprintf(stderr, "\n\n\nSDL_QUIT!\n\n\n");
+        SDL_Quit();
+        exit(42);
+    } /* switch */
+
+    return(1);
+} /* root_sdl_event_filter */
+
+
+static void sdl_handle_events(void)
+{
+    SDL_Event event;
+    while (SDL_PollEvent(&event))
+        root_sdl_event_filter(&event);
+} /* sdl_handle_events */
+#endif
+
+
+//******************************************************************************
+//
+// IN_PumpEvents () - Let platform process an event queue.
+//
+//******************************************************************************
+void IN_PumpEvents(void)
+{
+#if USE_SDL
+    sdl_handle_events();
+
+#elif PLATFORM_DOS
+    /* no-op. */
+
+#else
+#error please define for your platform.
+#endif
+}
+
+
+
+//******************************************************************************
+//
+// INL_GetMouseDelta () - Gets the amount that the mouse has moved from the
+//                        mouse driver
+//
+//******************************************************************************
+
+void INL_GetMouseDelta(int *x,int *y)
+{
+    IN_PumpEvents();
+
+#ifdef PLATFORM_DOS
+    union REGS inregs;
+    union REGS outregs;
+
+    if (!MousePresent)
+        *x = *y = 0;
+    else
+    {
+        inregs.w.ax = MDelta;
+        int386 (MouseInt, &inregs, &outregs);
+        *x = outregs.w.cx;
+        *y = outregs.w.dx;
+    }
+
+#elif USE_SDL
+    *x = sdl_mouse_delta_x;
+    *y = sdl_mouse_delta_y;
+
+    sdl_mouse_delta_x = sdl_mouse_delta_y = 0;
+
+#else
+#error please define for your platform.
+#endif
+}
+
+
+
+//******************************************************************************
+//
+// IN_GetMouseButtons () - Gets the status of the mouse buttons from the
+//                         mouse driver
+//
+//******************************************************************************
+
+word IN_GetMouseButtons
+(
+    void
+)
+
+{
+    word buttons = 0;
+
+    IN_PumpEvents();
+
+#if USE_SDL
+    buttons = sdl_mouse_button_mask;
+
+#elif PLATFORM_DOS
+    union REGS inregs;
+    union REGS outregs;
+
+    if (!MousePresent || !mouseenabled)
+        return (0);
+
+    inregs.w.ax = MButtons;
+    int386 (MouseInt, &inregs, &outregs);
+
+    buttons = outregs.w.bx;
+
+#else
+#  error please define for your platform.
+#endif
+
+// Used by menu routines that need to wait for a button release.
+// Sometimes the mouse driver misses an interrupt, so you can't wait for
+// a button to be released.  Instead, you must ignore any buttons that
+// are pressed.
+
+    IgnoreMouse &= buttons;
+    buttons &= ~IgnoreMouse;
+
+    return (buttons);
+}
+
+
+//******************************************************************************
+//
+// IN_IgnoreMouseButtons () -
+//    Tells the mouse to ignore the currently pressed buttons.
+//
+//******************************************************************************
+
+void IN_IgnoreMouseButtons
+(
+    void
+)
+
+{
+    IgnoreMouse |= IN_GetMouseButtons();
+}
+
+
+//******************************************************************************
+//
+// IN_GetJoyAbs () - Reads the absolute position of the specified joystick
+//
+//******************************************************************************
+
+void IN_GetJoyAbs (word joy, word *xp, word *yp)
+{
+    Joy_x  = Joy_y = 0;
+    Joy_xs = joy? 2 : 0;       // Find shift value for x axis
+    Joy_xb = 1 << Joy_xs;      // Use shift value to get x bit mask
+    Joy_ys = joy? 3 : 1;       // Do the same for y axis
+    Joy_yb = 1 << Joy_ys;
+
+#ifdef DOS
+    JoyStick_Vals ();
+#else
+    if (joy < sdl_total_sticks)
+    {
+        Joy_x = SDL_JoystickGetAxis (sdl_joysticks[joy], 0);
+        Joy_y = SDL_JoystickGetAxis (sdl_joysticks[joy], 1);
+    } else {
+        Joy_x = 0;
+        Joy_y = 0;
+    }
+#endif
+
+    *xp = Joy_x;
+    *yp = Joy_y;
+}
+
+void JoyStick_Vals (void)
+{
+
+}
+
+
+//******************************************************************************
+//
+// INL_GetJoyDelta () - Returns the relative movement of the specified
+//                     joystick (from +/-127)
+//
+//******************************************************************************
+
+void INL_GetJoyDelta (word joy, int *dx, int *dy)
+{
+    word        x, y;
+    JoystickDef *def;
+    static longword lasttime;
+
+    IN_GetJoyAbs (joy, &x, &y);
+    def = JoyDefs + joy;
+
+    if (x < def->threshMinX)
+    {
+        if (x < def->joyMinX)
+            x = def->joyMinX;
+
+        x = -(x - def->threshMinX);
+        x *= def->joyMultXL;
+        x >>= JoyScaleShift;
+        *dx = (x > 127)? -127 : -x;
+    }
+    else if (x > def->threshMaxX)
+    {
+        if (x > def->joyMaxX)
+            x = def->joyMaxX;
+
+        x = x - def->threshMaxX;
+        x *= def->joyMultXH;
+        x >>= JoyScaleShift;
+        *dx = (x > 127)? 127 : x;
+    }
+    else
+        *dx = 0;
+
+    if (y < def->threshMinY)
+    {
+        if (y < def->joyMinY)
+            y = def->joyMinY;
+
+        y = -(y - def->threshMinY);
+        y *= def->joyMultYL;
+        y >>= JoyScaleShift;
+        *dy = (y > 127)? -127 : -y;
+    }
+    else if (y > def->threshMaxY)
+    {
+        if (y > def->joyMaxY)
+            y = def->joyMaxY;
+
+        y = y - def->threshMaxY;
+        y *= def->joyMultYH;
+        y >>= JoyScaleShift;
+        *dy = (y > 127)? 127 : y;
+    }
+    else
+        *dy = 0;
+
+    lasttime = GetTicCount();
+}
+
+
+
+//******************************************************************************
+//
+// INL_GetJoyButtons () - Returns the button status of the specified
+//                        joystick
+//
+//******************************************************************************
+
+word INL_GetJoyButtons (word joy)
+{
+    word  result = 0;
+
+#if USE_SDL
+    if (joy < sdl_total_sticks)
+        result = sdl_stick_button_state[joy];
+
+#elif PLATFORM_DOS
+    result = inp (0x201);   // Get all the joystick buttons
+    result >>= joy? 6 : 4;  // Shift into bits 0-1
+    result &= 3;            // Mask off the useless bits
+    result ^= 3;
+
+#else
+#error please define for your platform.
+#endif
+
+    return result;
+}
+
+#if 0
+//******************************************************************************
+//
+// IN_GetJoyButtonsDB () - Returns the de-bounced button status of the
+//                         specified joystick
+//
+//******************************************************************************
+
+word IN_GetJoyButtonsDB (word joy)
+{
+    longword lasttime;
+    word result1,result2;
+
+    do
+    {
+        result1 = INL_GetJoyButtons (joy);
+        lasttime = GetTicCount();
+        while (GetTicCount() == lasttime)
+            ;
+        result2 = INL_GetJoyButtons (joy);
+    } while (result1 != result2);
+
+    return(result1);
+}
+#endif
+
+//******************************************************************************
+//
+// INL_StartMouse () - Detects and sets up the mouse
+//
+//******************************************************************************
+
+boolean INL_StartMouse (void)
+{
+
+    boolean retval = false;
+
+#if USE_SDL
+    /* no-op. */
+    retval = true;
+
+#elif PLATFORM_DOS
+    union REGS inregs;
+    union REGS outregs;
+
+    inregs.w.ax = 0;
+    int386 (MouseInt, &inregs, &outregs);
+
+    retval = ((outregs.w.ax == 0xffff) ? true : false);
+
+#else
+#error please define your platform.
+#endif
+
+    return (retval);
+}
+
+
+
+//******************************************************************************
+//
+// INL_SetJoyScale () - Sets up scaling values for the specified joystick
+//
+//******************************************************************************
+
+void INL_SetJoyScale (word joy)
+{
+    JoystickDef *def;
+
+    def = &JoyDefs[joy];
+    def->joyMultXL = JoyScaleMax / (def->threshMinX - def->joyMinX);
+    def->joyMultXH = JoyScaleMax / (def->joyMaxX - def->threshMaxX);
+    def->joyMultYL = JoyScaleMax / (def->threshMinY - def->joyMinY);
+    def->joyMultYH = JoyScaleMax / (def->joyMaxY - def->threshMaxY);
+}
+
+
+
+//******************************************************************************
+//
+// IN_SetupJoy () - Sets up thresholding values and calls INL_SetJoyScale()
+//                  to set up scaling values
+//
+//******************************************************************************
+
+void IN_SetupJoy (word joy, word minx, word maxx, word miny, word maxy)
+{
+    word     d,r;
+    JoystickDef *def;
+
+    def = &JoyDefs[joy];
+
+    def->joyMinX = minx;
+    def->joyMaxX = maxx;
+    r = maxx - minx;
+    d = r / 3;
+    def->threshMinX = ((r / 2) - d) + minx;
+    def->threshMaxX = ((r / 2) + d) + minx;
+
+    def->joyMinY = miny;
+    def->joyMaxY = maxy;
+    r = maxy - miny;
+    d = r / 3;
+    def->threshMinY = ((r / 2) - d) + miny;
+    def->threshMaxY = ((r / 2) + d) + miny;
+
+    INL_SetJoyScale (joy);
+}
+
+
+//******************************************************************************
+//
+// INL_StartJoy () - Detects & auto-configures the specified joystick
+//                   The auto-config assumes the joystick is centered
+//
+//******************************************************************************
+
+
+boolean INL_StartJoy (word joy)
+{
+    word x,y;
+
+#if USE_SDL
+    if (!SDL_WasInit(SDL_INIT_JOYSTICK))
+    {
+        SDL_Init(SDL_INIT_JOYSTICK);
+        sdl_total_sticks = SDL_NumJoysticks();
+        if (sdl_total_sticks > MaxJoys) sdl_total_sticks = MaxJoys;
+
+        if ((sdl_stick_button_state == NULL) && (sdl_total_sticks > 0))
+        {
+            sdl_stick_button_state = (word *) malloc(sizeof (word) * sdl_total_sticks);
+            if (sdl_stick_button_state == NULL)
+                SDL_QuitSubSystem(SDL_INIT_JOYSTICK);
+            else
+                memset(sdl_stick_button_state, '\0', sizeof (word) * sdl_total_sticks);
+        }
+        SDL_JoystickEventState(SDL_ENABLE);
+    }
+
+    if (joy >= sdl_total_sticks) return (false);
+    sdl_joysticks[joy] = SDL_JoystickOpen (joy);
+#endif
+
+    IN_GetJoyAbs (joy, &x, &y);
+
+    if
+    (
+        ((x == 0) || (x > MaxJoyValue - 10))
+        || ((y == 0) || (y > MaxJoyValue - 10))
+    )
+        return(false);
+    else
+    {
+        IN_SetupJoy (joy, 0, x * 2, 0, y * 2);
+        return (true);
+    }
+}
+
+
+
+//******************************************************************************
+//
+// INL_ShutJoy() - Cleans up the joystick stuff
+//
+//******************************************************************************
+
+void INL_ShutJoy (word joy)
+{
+    JoysPresent[joy] = false;
+#ifndef DOS
+    if (joy < sdl_total_sticks) SDL_JoystickClose (sdl_joysticks[joy]);
+#endif
+}
+
+
+
+//******************************************************************************
+//
+// IN_Startup() - Starts up the Input Mgr
+//
+//******************************************************************************
+
+
+void IN_Startup (void)
+{
+    boolean checkjoys,
+            checkmouse,
+            checkcyberman,
+            checkspaceball,
+            swiftstatus,
+            checkassassin;
+
+    word    i;
+
+    if (IN_Started==true)
+        return;
+
+#if USE_SDL
+
+#if PLATFORM_WIN32
+// fixme: remove this.
+    sdl_mouse_grabbed = 1;
+#endif
+
+    /*
+      all keys are now mapped to the wolf3d-style names,
+      except where no such name is available.
+     */
+    memset(scancodes, '\0', sizeof (scancodes));
+    scancodes[SDLK_ESCAPE]          = sc_Escape;
+    scancodes[SDLK_1]               = sc_1;
+    scancodes[SDLK_2]               = sc_2;
+    scancodes[SDLK_3]               = sc_3;
+    scancodes[SDLK_4]               = sc_4;
+    scancodes[SDLK_5]               = sc_5;
+    scancodes[SDLK_6]               = sc_6;
+    scancodes[SDLK_7]               = sc_7;
+    scancodes[SDLK_8]               = sc_8;
+    scancodes[SDLK_9]               = sc_9;
+    scancodes[SDLK_0]               = sc_0;
+
+    //scancodes[SDLK_EQUALS]          = 0x4E;
+    scancodes[SDLK_EQUALS]          = sc_Equals;
+
+    scancodes[SDLK_BACKSPACE]       = sc_BackSpace;
+    scancodes[SDLK_TAB]             = sc_Tab;
+    scancodes[SDLK_q]               = sc_Q;
+    scancodes[SDLK_w]               = sc_W;
+    scancodes[SDLK_e]               = sc_E;
+    scancodes[SDLK_r]               = sc_R;
+    scancodes[SDLK_t]               = sc_T;
+    scancodes[SDLK_y]               = sc_Y;
+    scancodes[SDLK_u]               = sc_U;
+    scancodes[SDLK_i]               = sc_I;
+    scancodes[SDLK_o]               = sc_O;
+    scancodes[SDLK_p]               = sc_P;
+    scancodes[SDLK_LEFTBRACKET]     = sc_OpenBracket;
+    scancodes[SDLK_RIGHTBRACKET]    = sc_CloseBracket;
+    scancodes[SDLK_RETURN]          = sc_Return;
+    scancodes[SDLK_LCTRL]           = sc_Control;
+    scancodes[SDLK_a]               = sc_A;
+    scancodes[SDLK_s]               = sc_S;
+    scancodes[SDLK_d]               = sc_D;
+    scancodes[SDLK_f]               = sc_F;
+    scancodes[SDLK_g]               = sc_G;
+    scancodes[SDLK_h]               = sc_H;
+    scancodes[SDLK_j]               = sc_J;
+    scancodes[SDLK_k]               = sc_K;
+    scancodes[SDLK_l]               = sc_L;
+    scancodes[SDLK_SEMICOLON]       = 0x27;
+    scancodes[SDLK_QUOTE]           = 0x28;
+    scancodes[SDLK_BACKQUOTE]       = 0x29;
+
+    /* left shift, but ROTT maps it to right shift in isr.c */
+    scancodes[SDLK_LSHIFT]          = sc_RShift; /* sc_LShift */
+
+    scancodes[SDLK_BACKSLASH]       = 0x2B;
+    /* Accept the German eszett as a backslash key */
+    scancodes[SDLK_WORLD_63]        = 0x2B;
+    scancodes[SDLK_z]               = sc_Z;
+    scancodes[SDLK_x]               = sc_X;
+    scancodes[SDLK_c]               = sc_C;
+    scancodes[SDLK_v]               = sc_V;
+    scancodes[SDLK_b]               = sc_B;
+    scancodes[SDLK_n]               = sc_N;
+    scancodes[SDLK_m]               = sc_M;
+    scancodes[SDLK_COMMA]           = sc_Comma;
+    scancodes[SDLK_PERIOD]          = sc_Period;
+    scancodes[SDLK_SLASH]           = 0x35;
+    scancodes[SDLK_RSHIFT]          = sc_RShift;
+    scancodes[SDLK_KP_DIVIDE]       = 0x35;
+
+    /* 0x37 is printscreen */
+    //scancodes[SDLK_KP_MULTIPLY]     = 0x37;
+
+    scancodes[SDLK_LALT]            = sc_Alt;
+    scancodes[SDLK_RALT]            = sc_Alt;
+    scancodes[SDLK_MODE]            = sc_Alt;
+    scancodes[SDLK_RCTRL]           = sc_Control;
+    scancodes[SDLK_SPACE]           = sc_Space;
+    scancodes[SDLK_CAPSLOCK]        = sc_CapsLock;
+    scancodes[SDLK_F1]              = sc_F1;
+    scancodes[SDLK_F2]              = sc_F2;
+    scancodes[SDLK_F3]              = sc_F3;
+    scancodes[SDLK_F4]              = sc_F4;
+    scancodes[SDLK_F5]              = sc_F5;
+    scancodes[SDLK_F6]              = sc_F6;
+    scancodes[SDLK_F7]              = sc_F7;
+    scancodes[SDLK_F8]              = sc_F8;
+    scancodes[SDLK_F9]              = sc_F9;
+    scancodes[SDLK_F10]             = sc_F10;
+    scancodes[SDLK_F11]             = sc_F11;
+    scancodes[SDLK_F12]             = sc_F12;
+    scancodes[SDLK_NUMLOCK]         = 0x45;
+    scancodes[SDLK_SCROLLOCK]       = 0x46;
+
+    //scancodes[SDLK_MINUS]           = 0x4A;
+    scancodes[SDLK_MINUS]           = sc_Minus;
+
+    scancodes[SDLK_KP7]             = sc_Home;
+    scancodes[SDLK_KP8]             = sc_UpArrow;
+    scancodes[SDLK_KP9]             = sc_PgUp;
+    scancodes[SDLK_HOME]            = sc_Home;
+    scancodes[SDLK_UP]              = sc_UpArrow;
+    scancodes[SDLK_PAGEUP]          = sc_PgUp;
+    // Make this a normal minus, for viewport changing
+    //scancodes[SDLK_KP_MINUS]        = 0xE04A;
+    scancodes[SDLK_KP_MINUS]        = sc_Minus;
+    scancodes[SDLK_KP4]             = sc_LeftArrow;
+    scancodes[SDLK_KP5]             = 0x4C;
+    scancodes[SDLK_KP6]             = sc_RightArrow;
+    scancodes[SDLK_LEFT]            = sc_LeftArrow;
+    scancodes[SDLK_RIGHT]           = sc_RightArrow;
+
+    //scancodes[SDLK_KP_PLUS]         = 0x4E;
+    scancodes[SDLK_KP_PLUS]         = sc_Plus;
+
+    scancodes[SDLK_KP1]             = sc_End;
+    scancodes[SDLK_KP2]             = sc_DownArrow;
+    scancodes[SDLK_KP3]             = sc_PgDn;
+    scancodes[SDLK_END]             = sc_End;
+    scancodes[SDLK_DOWN]            = sc_DownArrow;
+    scancodes[SDLK_PAGEDOWN]        = sc_PgDn;
+    scancodes[SDLK_DELETE]          = sc_Delete;
+    scancodes[SDLK_KP0]             = sc_Insert;
+    scancodes[SDLK_INSERT]          = sc_Insert;
+    scancodes[SDLK_KP_ENTER]        = sc_Return;
+#endif
+
+    checkjoys        = true;
+    checkmouse       = true;
+    checkcyberman    = false;
+    checkassassin    = false;
+    checkspaceball   = false;
+    SpaceBallPresent = false;
+    CybermanPresent  = false;
+    AssassinPresent  = false;
+
+    for (i = 1; i < _argc; i++)
+    {
+        switch (US_CheckParm (_argv[i], ParmStrings))
+        {
+        case 0:
+            checkjoys = false;
+            break;
+
+        case 1:
+            checkmouse = false;
+            break;
+
+        case 2:
+            checkspaceball = true;
+            break;
+
+        case 3:
+            checkcyberman = true;
+            checkmouse = false;
+            break;
+
+        case 4:
+            checkassassin = true;
+            checkmouse = false;
+            break;
+        }
+    }
+
+    MousePresent = checkmouse ? INL_StartMouse() : false;
+
+    if (!MousePresent)
+        mouseenabled = false;
+    else
+    {
+        if (!quiet)
+            printf("IN_Startup: Mouse Present\n");
+    }
+
+    for (i = 0; i < MaxJoys; i++)
+    {
+        JoysPresent[i] = checkjoys ? INL_StartJoy(i) : false;
+        if (INL_StartJoy(i))
+        {
+            if (!quiet)
+                printf("IN_Startup: Joystick Present\n");
+        }
+    }
+
+    if (checkspaceball)
+    {
+        OpenSpaceBall ();
+        spaceballenabled=true;
+    }
+
+    if ((checkcyberman || checkassassin) && (swiftstatus = SWIFT_Initialize ()))
+    {
+        int dynamic;
+
+        if (checkcyberman)
+        {
+            CybermanPresent = swiftstatus;
+            cybermanenabled = true;
+        }
+        else if (checkassassin)
+        {
+            AssassinPresent = checkassassin & swiftstatus;
+            assassinenabled = true;
+        }
+
+        dynamic = SWIFT_GetDynamicDeviceData ();
+
+        SWIFT_TactileFeedback (40, 20, 20);
+
+        if (SWIFT_GetDynamicDeviceData () == 2)
+            Error ("SWIFT ERROR : External Power too high!\n");
+
+        SWIFT_TactileFeedback (100, 10, 10);
+        if (!quiet)
+            printf("IN_Startup: Swift Device Present\n");
+    }
+
+    IN_Started = true;
+}
+
+
+#if 0
+//******************************************************************************
+//
+// IN_Default() - Sets up default conditions for the Input Mgr
+//
+//******************************************************************************
+
+void IN_Default (boolean gotit, ControlType in)
+{
+    if
+    (
+        (!gotit)
+        ||    ((in == ctrl_Joystick1) && !JoysPresent[0])
+        ||    ((in == ctrl_Joystick2) && !JoysPresent[1])
+        ||    ((in == ctrl_Mouse) && !MousePresent)
+    )
+        in = ctrl_Keyboard1;
+    IN_SetControlType (0, in);
+}
+#endif
+
+//******************************************************************************
+//
+// IN_Shutdown() - Shuts down the Input Mgr
+//
+//******************************************************************************
+
+void IN_Shutdown (void)
+{
+    word  i;
+
+    if (IN_Started==false)
+        return;
+
+//   INL_ShutMouse();
+
+    for (i = 0; i < MaxJoys; i++)
+        INL_ShutJoy(i);
+
+    if (CybermanPresent || AssassinPresent)
+        SWIFT_Terminate ();
+
+    CloseSpaceBall ();
+
+    IN_Started = false;
+}
+
+
+//******************************************************************************
+//
+// IN_ClearKeysDown() - Clears the keyboard array
+//
+//******************************************************************************
+
+void IN_ClearKeysDown (void)
+{
+    LastScan = sc_None;
+    memset ((void *)Keyboard, 0, sizeof (Keyboard));
+}
+
+
+//******************************************************************************
+//
+// IN_ReadControl() - Reads the device associated with the specified
+//    player and fills in the control info struct
+//
+//******************************************************************************
+
+void IN_ReadControl (int player, ControlInfo *info)
+{
+    boolean     realdelta;
+    word        buttons;
+    int         dx,dy;
+    Motion      mx,my;
+    ControlType type;
+
+    KeyboardDef *def;
+
+    dx = dy = 0;
+    mx = my = motion_None;
+    buttons = 0;
+
+
+    switch (type = Controls[player])
+    {
+    case ctrl_Keyboard:
+        def = &KbdDefs;
+
+#if 0
+        if (Keyboard[def->upleft])
+            mx = motion_Left,my = motion_Up;
+        else if (Keyboard[def->upright])
+            mx = motion_Right,my = motion_Up;
+        else if (Keyboard[def->downleft])
+            mx = motion_Left,my = motion_Down;
+        else if (Keyboard[def->downright])
+            mx = motion_Right,my = motion_Down;
+#endif
+        if (Keyboard[sc_UpArrow])
+            my = motion_Up;
+        else if (Keyboard[sc_DownArrow])
+            my = motion_Down;
+
+        if (Keyboard[sc_LeftArrow])
+            mx = motion_Left;
+        else if (Keyboard[sc_RightArrow])
+            mx = motion_Right;
+
+        if (Keyboard[def->button0])
+            buttons += 1 << 0;
+        if (Keyboard[def->button1])
+            buttons += 1 << 1;
+        realdelta = false;
+        break;
+
+#if 0
+    case ctrl_Joystick1:
+    case ctrl_Joystick2:
+        INL_GetJoyDelta (type - ctrl_Joystick, &dx, &dy);
+        buttons = INL_GetJoyButtons (type - ctrl_Joystick);
+        realdelta = true;
+        break;
+
+    case ctrl_Mouse:
+        INL_GetMouseDelta (&dx,&dy);
+        buttons = IN_GetMouseButtons ();
+        realdelta = true;
+        break;
+
+#endif
+    default:
+        ;
+    }
+
+    if (realdelta)
+    {
+        mx = (dx < 0)? motion_Left : ((dx > 0)? motion_Right : motion_None);
+        my = (dy < 0)? motion_Up : ((dy > 0)? motion_Down : motion_None);
+    }
+    else
+    {
+        dx = mx * 127;
+        dy = my * 127;
+    }
+
+    info->x = dx;
+    info->xaxis = mx;
+    info->y = dy;
+    info->yaxis = my;
+    info->button0 = buttons & (1 << 0);
+    info->button1 = buttons & (1 << 1);
+    info->button2 = buttons & (1 << 2);
+    info->button3 = buttons & (1 << 3);
+    info->dir = DirTable[((my + 1) * 3) + (mx + 1)];
+}
+
+
+//******************************************************************************
+//
+// IN_WaitForKey() - Waits for a scan code, then clears LastScan and
+//    returns the scan code
+//
+//******************************************************************************
+
+ScanCode IN_WaitForKey (void)
+{
+    ScanCode result;
+
+    while (!(result = LastScan))
+        IN_PumpEvents();
+    LastScan = 0;
+    return (result);
+}
+
+
+//******************************************************************************
+//
+// IN_Ack() - waits for a button or key press.  If a button is down, upon
+// calling, it must be released for it to be recognized
+//
+//******************************************************************************
+
+boolean  btnstate[8];
+
+void IN_StartAck (void)
+{
+    unsigned i,
+             buttons = 0;
+
+//
+// get initial state of everything
+//
+    LastScan = 0;
+
+    IN_ClearKeysDown ();
+    memset (btnstate, 0, sizeof(btnstate));
+
+    IN_PumpEvents();
+
+    buttons = IN_JoyButtons () << 4;
+
+    buttons |= IN_GetMouseButtons();
+
+    if (SpaceBallPresent && spaceballenabled)
+    {
+        buttons |= GetSpaceBallButtons ();
+    }
+
+    for (i=0; i<8; i++,buttons>>=1)
+        if (buttons&1)
+            btnstate[i] = true;
+}
+
+
+
+//******************************************************************************
+//
+// IN_CheckAck ()
+//
+//******************************************************************************
+
+boolean IN_CheckAck (void)
+{
+    unsigned i,
+             buttons = 0;
+
+//
+// see if something has been pressed
+//
+    if (LastScan)
+        return true;
+
+    IN_PumpEvents();
+
+    buttons = IN_JoyButtons () << 4;
+
+    buttons |= IN_GetMouseButtons();
+
+    for (i=0; i<8; i++,buttons>>=1)
+        if ( buttons&1 )
+        {
+            if (!btnstate[i])
+                return true;
+        }
+        else
+            btnstate[i]=false;
+
+    return false;
+}
+
+
+
+//******************************************************************************
+//
+// IN_Ack ()
+//
+//******************************************************************************
+
+void IN_Ack (void)
+{
+    IN_StartAck ();
+
+    while (!IN_CheckAck ())
+        ;
+}
+
+
+
+//******************************************************************************
+//
+// IN_UserInput() - Waits for the specified delay time (in ticks) or the
+//    user pressing a key or a mouse button. If the clear flag is set, it
+//    then either clears the key or waits for the user to let the mouse
+//    button up.
+//
+//******************************************************************************
+
+boolean IN_UserInput (long delay)
+{
+    long lasttime;
+
+    lasttime = GetTicCount();
+
+    IN_StartAck ();
+    do
+    {
+        if (IN_CheckAck())
+            return true;
+    } while ((GetTicCount() - lasttime) < delay);
+
+    return (false);
+}
+
+//===========================================================================
+
+
+/*
+===================
+=
+= IN_JoyButtons
+=
+===================
+*/
+
+byte IN_JoyButtons (void)
+{
+    unsigned joybits = 0;
+
+#if USE_SDL
+    joybits = sdl_sticks_joybits;
+
+#elif PLATFORM_DOS
+    joybits = inp (0x201);  // Get all the joystick buttons
+    joybits >>= 4;          // only the high bits are useful
+    joybits ^= 15;          // return with 1=pressed
+
+#else
+#error define your platform.
+#endif
+
+    return (byte) joybits;
+}
+
+
+//******************************************************************************
+//
+// IN_UpdateKeyboard ()
+//
+//******************************************************************************
+
+/* HACK HACK HACK */
+static int queuegotit=0;
+
+void IN_UpdateKeyboard (void)
+{
+    int tail;
+    int key;
+
+    if (!queuegotit)
+        IN_PumpEvents();
+
+    queuegotit=0;
+
+    if (Keytail != Keyhead)
+    {
+        tail = Keytail;
+
+        while (Keyhead != tail)
+        {
+            if (KeyboardQueue[Keyhead] & 0x80)        // Up event
+            {
+                key = KeyboardQueue[Keyhead] & 0x7F;   // AND off high bit
+
+//            if (keysdown[key])
+//            {
+//               KeyboardQueue[Keytail] = KeyboardQueue[Keyhead];
+//               Keytail = (Keytail+1)&(KEYQMAX-1);
+//            }
+//            else
+                Keyboard[key] = 0;
+            }
+            else                                      // Down event
+            {
+                Keyboard[KeyboardQueue[Keyhead]] = 1;
+//            keysdown[KeyboardQueue[Keyhead]] = 1;
+            }
+
+            Keyhead = (Keyhead+1)&(KEYQMAX-1);
+
+        }        // while
+    }           // if
+
+    // Carry over movement keys from the last refresh
+//   keysdown[sc_RightArrow] = Keyboard[sc_RightArrow];
+//   keysdown[sc_LeftArrow]  = Keyboard[sc_LeftArrow];
+//   keysdown[sc_UpArrow]    = Keyboard[sc_UpArrow];
+//   keysdown[sc_DownArrow]  = Keyboard[sc_DownArrow];
+}
+
+
+
+//******************************************************************************
+//
+// IN_InputUpdateKeyboard ()
+//
+//******************************************************************************
+
+int IN_InputUpdateKeyboard (void)
+{
+    int key;
+    int returnval = 0;
+    boolean done = false;
+
+//   _disable ();
+
+    if (Keytail != Keyhead)
+    {
+        int tail = Keytail;
+
+        while (!done && (Keyhead != tail))
+        {
+            if (KeyboardQueue[Keyhead] & 0x80)        // Up event
+            {
+                key = KeyboardQueue[Keyhead] & 0x7F;   // AND off high bit
+
+                Keyboard[key] = 0;
+            }
+            else                                      // Down event
+            {
+                Keyboard[KeyboardQueue[Keyhead]] = 1;
+                returnval = KeyboardQueue[Keyhead];
+                done = true;
+            }
+
+            Keyhead = (Keyhead+1)&(KEYQMAX-1);
+        }
+    }           // if
+
+//   _enable ();
+
+    return (returnval);
+}
+
+
+//******************************************************************************
+//
+// IN_ClearKeyboardQueue ()
+//
+//******************************************************************************
+
+void IN_ClearKeyboardQueue (void)
+{
+    return;
+
+//   IN_ClearKeysDown ();
+
+//   Keytail = Keyhead = 0;
+//   memset (KeyboardQueue, 0, sizeof (KeyboardQueue));
+//   I_SendKeyboardData(0xf6);
+//   I_SendKeyboardData(0xf4);
+}
+
+
+#if 0
+//******************************************************************************
+//
+// IN_DumpKeyboardQueue ()
+//
+//******************************************************************************
+
+void IN_DumpKeyboardQueue (void)
+{
+    int head = Keyhead;
+    int tail = Keytail;
+    int key;
+
+    if (tail != head)
+    {
+        SoftError( "START DUMP\n");
+
+        while (head != tail)
+        {
+            if (KeyboardQueue[head] & 0x80)        // Up event
+            {
+                key = KeyboardQueue[head] & 0x7F;   // AND off high bit
+
+//            if (keysdown[key])
+//            {
+//               SoftError( "%s - was put in next refresh\n",
+//                                 IN_GetScanName (key));
+//            }
+//            else
+//            {
+                if (Keyboard[key] == 0)
+                    SoftError( "%s %ld - was lost\n", IN_GetScanName (key), key);
+                else
+                    SoftError( "%s %ld - up\n", IN_GetScanName (key), key);
+//            }
+            }
+            else                                      // Down event
+                SoftError( "%s %ld - down\n", IN_GetScanName (KeyboardQueue[head]), KeyboardQueue[head]);
+
+            head = (head+1)&(KEYQMAX-1);
+        }        // while
+
+        SoftError( "END DUMP\n");
+
+    }           // if
+}
+#endif
+
+
+//******************************************************************************
+//
+// QueueLetterInput ()
+//
+//******************************************************************************
+
+void QueueLetterInput (void)
+{
+    int head = Keyhead;
+    int tail = Keytail;
+    char c;
+    int scancode;
+    boolean send = false;
+
+#ifndef PLATFORM_DOS
+    /* HACK HACK HACK */
+    /*
+      OK, we want the new keys NOW, and not when the update gets them.
+      Since this called before IN_UpdateKeyboard in PollKeyboardButtons,
+      we shall update here.  The hack is there to prevent IN_UpdateKeyboard
+      from stealing any keys... - SBF
+     */
+    IN_PumpEvents();
+    head = Keyhead;
+    tail = Keytail;
+    queuegotit=1;
+    /* HACK HACK HACK */
+#endif
+
+    while (head != tail)
+    {
+        if (!(KeyboardQueue[head] & 0x80))        // Down event
+        {
+            scancode = KeyboardQueue[head];
+
+            if (Keyboard[sc_RShift] || Keyboard[sc_LShift])
+            {
+                c = ShiftedScanChars[scancode];
+            }
+            else
+            {
+                c = ScanChars[scancode];
+            }
+
+            // If "is printable char", queue the character
+            if (c)
+            {
+                LetterQueue[LastLetter] = c;
+                LastLetter = (LastLetter+1)&(MAXLETTERS-1);
+
+                // If typing a message, update the text with 'c'
+
+                if ( MSG.messageon )
+                {
+                    Keystate[scancode]=0;
+                    KeyboardQueue[head] = 0;
+                    if ( MSG.inmenu )
+                    {
+                        if ( ( c == 'A' ) || ( c == 'a' ) )
+                        {
+                            MSG.towho = MSG_DIRECTED_TO_ALL;
+                            send      = true;
+                        }
+
+                        if ( ( gamestate.teamplay ) &&
+                                ( ( c == 'T' ) || ( c == 't' ) ) )
+                        {
+                            MSG.towho = MSG_DIRECTED_TO_TEAM;
+                            send      = true;
+                        }
+
+                        if ( ( c >= '0' ) && ( c <= '9' ) )
+                        {
+                            int who;
+
+                            if ( c == '0' )
+                            {
+                                who = 10;
+                            }
+                            else
+                            {
+                                who = c - '1';
+                            }
+
+                            // Skip over local player
+                            if ( who >= consoleplayer )
+                            {
+                                who++;
+                            }
+
+                            if ( who < numplayers )
+                            {
+                                MSG.towho = who;
+                                send      = true;
+                            }
+                        }
+
+                        if ( send )
+                        {
+                            MSG.messageon = false;
+                            KeyboardQueue[ head ] = 0;
+                            Keyboard[ scancode ]  = 0;
+                            LastScan              = 0;
+                            FinishModemMessage( MSG.textnum, true );
+                        }
+                    }
+                    else if ( ( scancode >= sc_1 ) && ( scancode <= sc_0 ) &&
+                              ( Keyboard[ sc_Alt ] ) )
+                    {
+                        int msg;
+
+                        msg = scancode - sc_1;
+
+                        if ( CommbatMacros[ msg ].avail )
+                        {
+                            MSG.length = strlen( CommbatMacros[ msg ].macro ) + 1;
+                            strcpy( Messages[ MSG.textnum ].text,
+                                    CommbatMacros[ msg ].macro );
+
+                            MSG.messageon = false;
+                            FinishModemMessage( MSG.textnum, true );
+                            KeyboardQueue[ head ] = 0;
+                            Keyboard[ sc_Enter ]  = 0;
+                            Keyboard[ sc_Escape ] = 0;
+                            LastScan              = 0;
+                        }
+                        else
+                        {
+                            MSG.messageon = false;
+                            MSG.directed  = false;
+
+                            FinishModemMessage( MSG.textnum, false );
+                            AddMessage( "No macro.", MSG_MACRO );
+                            KeyboardQueue[ head ] = 0;
+                            Keyboard[ sc_Enter ]  = 0;
+                            Keyboard[ sc_Escape ] = 0;
+                            LastScan              = 0;
+                        }
+                    }
+                    else if ( MSG.length < MAXMESSAGELENGTH )
+                    {
+                        UpdateModemMessage (MSG.textnum, c);
+                    }
+                }
+            }
+            else
+            {
+                // If typing a message, check for special characters
+
+                if ( MSG.messageon && MSG.inmenu )
+                {
+                    if ( scancode == sc_Escape )
+                    {
+                        MSG.messageon = false;
+                        MSG.directed  = false;
+                        FinishModemMessage( MSG.textnum, false );
+                        KeyboardQueue[head] = 0;
+                        Keyboard[sc_Enter]  = 0;
+                        Keyboard[sc_Escape] = 0;
+                        LastScan            = 0;
+                    }
+                }
+                else if ( MSG.messageon && !MSG.inmenu )
+                {
+                    if ( ( scancode >= sc_F1 ) &&
+                            ( scancode <= sc_F10 ) )
+                    {
+                        MSG.remoteridicule = scancode - sc_F1;
+                        MSG.messageon = false;
+                        FinishModemMessage(MSG.textnum, true);
+                        KeyboardQueue[head] = 0;
+                        Keyboard[sc_Enter]  = 0;
+                        Keyboard[sc_Escape] = 0;
+                        LastScan            = 0;
+                    }
+
+                    switch (scancode)
+                    {
+                    case sc_BackSpace:
+                        KeyboardQueue[head] = 0;
+                        if (MSG.length > 1)
+                        {
+                            ModemMessageDeleteChar (MSG.textnum);
+                        }
+                        Keystate[scancode]=0;
+                        break;
+
+                    case sc_Enter:
+                        MSG.messageon = false;
+                        FinishModemMessage(MSG.textnum, true);
+                        KeyboardQueue[head] = 0;
+                        Keyboard[sc_Enter]  = 0;
+                        Keyboard[sc_Escape] = 0;
+                        LastScan            = 0;
+                        Keystate[scancode]=0;
+                        break;
+
+                    case sc_Escape:
+                        MSG.messageon = false;
+                        MSG.directed  = false;
+                        FinishModemMessage(MSG.textnum, false);
+                        KeyboardQueue[head] = 0;
+                        Keyboard[sc_Enter]  = 0;
+                        Keyboard[sc_Escape] = 0;
+                        LastScan            = 0;
+                        break;
+                    }
+                }
+            }
+        }
+
+        head = (head+1)&(KEYQMAX-1);
+    }        // while
+}
--- /dev/null
+++ b/rott/rt_in.h
@@ -1,0 +1,212 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+//***************************************************************************
+//
+// Public header for RT_IN.C.
+//
+//***************************************************************************
+
+#ifndef _rt_in_public
+#define _rt_in_public
+
+#include "develop.h"
+#include "rottnet.h"
+
+//***************************************************************************
+//
+// DEFINES
+//
+//***************************************************************************
+
+#define MAXLETTERS   32
+
+
+//***************************************************************************
+//
+// TYPEDEFS
+//
+//***************************************************************************
+
+typedef  enum
+{
+    motion_Left  = -1,
+    motion_Up    = -1,
+    motion_None  = 0,
+    motion_Right = 1,
+    motion_Down  = 1
+} Motion;
+
+
+typedef  enum
+{
+    dir_North,
+    dir_NorthEast,
+    dir_East,
+    dir_SouthEast,
+    dir_South,
+    dir_SouthWest,
+    dir_West,
+    dir_NorthWest,
+    dir_None
+} Direction;
+
+typedef byte ScanCode;
+
+typedef  enum
+{
+    ctrl_Keyboard,
+    ctrl_Keyboard1 = ctrl_Keyboard, ctrl_Keyboard2,
+    ctrl_Joystick,
+    ctrl_Joystick1 = ctrl_Joystick, ctrl_Joystick2,
+    ctrl_Mouse
+} ControlType;
+
+typedef  struct
+{
+    boolean     button0,
+                button1,
+                button2,
+                button3;
+    int         x,
+                y;
+    Motion      xaxis,
+                yaxis;
+    Direction   dir;
+} CursorInfo;
+
+
+typedef  CursorInfo  ControlInfo;
+
+
+typedef  struct
+{
+    ScanCode button0,
+             button1,
+             upleft,
+             up,
+             upright,
+             left,
+             right,
+             downleft,
+             down,
+             downright;
+} KeyboardDef;
+
+
+typedef struct
+{
+    word  joyMinX,joyMinY,
+          threshMinX,threshMinY,
+          threshMaxX,threshMaxY,
+          joyMaxX,joyMaxY,
+          joyMultXL,joyMultYL,
+          joyMultXH,joyMultYH;
+} JoystickDef;
+
+
+typedef struct
+{
+    boolean messageon;
+    boolean directed;
+    boolean inmenu;
+    int     remoteridicule;
+    int     towho;
+    int     textnum;
+    int     length;
+} ModemMessage;
+
+
+//***************************************************************************
+//
+// GLOBALS
+//
+//***************************************************************************
+
+extern boolean MousePresent;
+extern boolean JoysPresent[MaxJoys];
+extern boolean JoyPadPresent;
+extern int     mouseadjustment;
+extern int     threshold;
+
+extern boolean  Paused;
+extern volatile int LastScan;
+/* extern KeyboardDef KbdDefs;
+extern JoystickDef JoyDefs[];
+extern ControlType Controls[MAXPLAYERS]; */
+
+extern boolean  SpaceBallPresent;
+extern boolean  CybermanPresent;
+extern boolean  AssassinPresent;
+extern char LastASCII;
+extern volatile int LastScan;
+
+extern byte Joy_xb,
+       Joy_yb,
+       Joy_xs,
+       Joy_ys;
+extern word Joy_x,
+       Joy_y;
+
+extern int LastLetter;
+extern char LetterQueue[MAXLETTERS];
+extern ModemMessage MSG;
+
+extern const char ScanChars[128];
+
+//***************************************************************************
+//
+// PROTOTYPES
+//
+//***************************************************************************
+
+void INL_GetMouseDelta(int *x,int *y);
+word IN_GetMouseButtons (void);
+void IN_IgnoreMouseButtons( void );
+boolean INL_StartMouse (void);
+void INL_ShutMouse (void);
+void IN_Startup(void);
+void IN_Default (boolean gotit, ControlType in);
+void IN_Shutdown (void);
+void IN_SetKeyHook(void (*hook)());
+void IN_ClearKeysDown (void);
+void IN_ReadControl (int player, ControlInfo *info);
+void IN_SetControlType (int player, ControlType type);
+ScanCode IN_WaitForKey (void);
+char IN_WaitForASCII (void);
+void IN_StartAck (void);
+boolean IN_CheckAck (void);
+void IN_Ack (void);
+boolean IN_UserInput (long delay);
+void IN_GetJoyAbs (word joy, word *xp, word *yp);
+void INL_GetJoyDelta (word joy, int *dx, int *dy);
+word INL_GetJoyButtons (word joy);
+//word IN_GetJoyButtonsDB (word joy);
+void INL_SetJoyScale (word joy);
+void IN_SetupJoy (word joy, word minx, word maxx, word miny, word maxy);
+boolean INL_StartJoy (word joy);
+void INL_ShutJoy (word joy);
+byte IN_JoyButtons (void);
+void IN_UpdateKeyboard (void);
+void IN_ClearKeyboardQueue (void);
+int IN_InputUpdateKeyboard (void);
+void IN_PumpEvents (void);
+void QueueLetterInput (void);
+
+#endif
--- /dev/null
+++ b/rott/rt_main.c
@@ -1,0 +1,3549 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+#include "rt_def.h"
+#include "lumpy.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <fcntl.h>
+#include <string.h>
+
+#ifdef DOS
+#include <malloc.h>
+#include <dos.h>
+#include <io.h>
+#include <conio.h>
+#include <graph.h>
+#include <process.h>
+#include <direct.h>
+#include <bios.h>
+#else
+#include <signal.h>
+#endif
+
+#if USE_SDL
+/* Need to redefine main to SDL_main on some platforms... */
+#include "SDL.h"
+#endif
+
+#include "rt_actor.h"
+#include "rt_stat.h"
+#include "rt_vid.h"
+#include "rt_menu.h"
+#include "rt_sound.h"
+#include "watcom.h"
+#include "scriplib.h"
+#include "rt_main.h"
+#include "_rt_main.h"
+#include "rt_com.h"
+#include "rt_util.h"
+#include "z_zone.h"
+#include "w_wad.h"
+#include "rt_game.h"
+#include "rt_floor.h"
+#include "rt_playr.h"
+#include "rt_draw.h"
+#include "rt_str.h"
+#include "rt_view.h"
+#include "rt_door.h"
+#include "rt_ted.h"
+#include "rt_in.h"
+#include "rt_map.h"
+#include "rt_rand.h"
+#include "rt_debug.h"
+#include "isr.h"
+#include "rt_cfg.h"
+#include "develop.h"
+#include "version.h"
+#include "rt_menu.h"
+#include "rt_dr_a.h"
+#include "rt_msg.h"
+#include "rt_build.h"
+#include "rt_error.h"
+#include "modexlib.h"
+#include "rt_net.h"
+#include "cin_main.h"
+#include "rottnet.h"
+#include "rt_scale.h"
+
+#include "music.h"
+#include "fx_man.h"
+//MED
+#include "memcheck.h"
+
+volatile int    oldtime;
+volatile int    gametime;
+
+boolean         tedlevel;
+int             tedlevelnum;
+int             tedx=0;
+int             tedy=0;
+boolean         warp;
+int             warpx=0;
+int             warpy=0;
+int             warpa=0;
+int             NoSound;
+int             polltime;
+int             oldpolltime;
+boolean         fizzlein = false;
+int             pheight;
+
+boolean SCREENSHOTS             = false;
+boolean MONOPRESENT             = false;
+boolean MAPSTATS                = false;
+boolean TILESTATS               = false;
+boolean HUD                     = false;
+boolean IS8250                  = false;
+
+boolean dopefish;
+
+boolean newlevel = false;
+boolean infopause;
+#ifdef DOS
+boolean SOUNDSETUP=false;
+#endif
+boolean quiet = false;
+
+#if (DEVELOPMENT == 1)
+boolean DebugOk = true;
+#else
+boolean DebugOk = false;
+#endif
+
+#if (WHEREAMI==1)
+int programlocation=-1;
+#endif
+
+#if SAVE_SCREEN
+static char savename[13] = "ROTT0000.LBM";
+static int totalbytes;
+static byte *bptr;
+#endif
+static boolean turbo;
+
+static int NoWait;
+static int startlevel=0;
+static int demonumber=-1;
+
+char CWD[40];                          // curent working directory
+static boolean quitactive = false;
+
+int timelimit;
+int maxtimelimit;
+boolean timelimitenabled;
+boolean demoexit;
+boolean noecho;
+
+void CheckCommandLineParameters( void );
+void PlayTurboGame( void );
+void Init_Tables (void);
+void CheckRemoteRidicule ( int scancode );
+void SetRottScreenRes (int Width, int Height);
+
+#ifndef DOS
+extern void crash_print (int);
+extern int setup_homedir (void);
+#endif
+
+//extern int G_argc;
+//extern char G_argv[30][80];
+int G_weaponscale;
+extern int iDropDemo;
+extern boolean iG_aimCross;
+extern boolean sdl_fullscreen;
+
+extern void ComSetTime ( void );
+extern void VH_UpdateScreen (void);
+extern void RottConsole ( void );
+extern void	ReadDelay(long delay);
+extern void RecordDemoQuery ( void );
+
+
+int main (int argc, char *argv[])
+{
+    char *macwd;
+    extern char *BATTMAPS;
+#ifndef DOS
+    _argc = argc;
+    _argv = argv;
+#endif
+
+#if defined(PLATFORM_MACOSX)
+    {
+        /* OS X will give us a path in the form '/Applications/Rise of the Triad.app/Contents/MacOS/Rise of the Triad'.
+           Our data is in Contents/Resources. */
+        char *path;
+        const char suffix[] = "/Resources/";
+        int end;
+        path = (char *)malloc(strlen(argv[0]) + strlen(suffix) + 1);
+        if (path == NULL) return 1;
+        strcpy(path, argv[0]);
+        /* Back up two '/'s. */
+        for (end = strlen(path)-1; end >= 0 && path[end] != '/'; end--);
+        if (end >= 0) for (--end; end >= 0 && path[end] != '/'; end--);
+        strcpy(&path[end], suffix);
+        printf("Changing to working directory: %s\n", path);
+        chdir(path);
+        free(path);
+    }
+#endif
+
+#ifndef DOS
+    signal (11, crash_print);
+
+    if (setup_homedir() == -1) return 1;
+#endif
+
+    // Set which release version we're on
+    gamestate.Version = ROTTVERSION;
+
+#if ( SHAREWARE == 1 )
+    BATTMAPS = strdup(STANDARDBATTLELEVELS);
+    FixFilePath(BATTMAPS);
+    gamestate.Product = ROTT_SHAREWARE;
+#else
+    BATTMAPS = strdup(SITELICENSEBATTLELEVELS);
+    FixFilePath(BATTMAPS);
+    if (!access(BATTMAPS, R_OK))
+    {
+        gamestate.Product = ROTT_SITELICENSE;
+    }
+    else
+    {
+        free(BATTMAPS);
+        BATTMAPS = strdup(SUPERROTTBATTLELEVELS);
+        FixFilePath(BATTMAPS);
+        if (!access(BATTMAPS, R_OK))
+        {
+            gamestate.Product = ROTT_SUPERCD;
+        }
+        else
+        {
+            free(BATTMAPS);
+            BATTMAPS = strdup(STANDARDBATTLELEVELS);
+            FixFilePath(BATTMAPS);
+            gamestate.Product = ROTT_REGISTERED;
+        }
+    }
+#endif
+
+    DrawRottTitle ();
+    gamestate.randomseed=-1;
+
+    gamestate.autorun = 0;
+    StartupSoftError();
+//   UL_ErrorStartup ();
+
+    CheckCommandLineParameters();
+
+    // Start up Memory manager with a certain amount of reserved memory
+
+    Z_Init(50000,1000000);
+
+    IN_Startup ();
+
+    InitializeGameCommands();
+    if (standalone==false)
+    {
+        ReadConfig ();
+        ReadSETUPFiles ();
+        doublestep=0;
+        SetupWads();
+        BuildTables ();
+        GetMenuInfo ();
+    }
+
+    SetRottScreenRes (iGLOBAL_SCREENWIDTH, iGLOBAL_SCREENHEIGHT);
+
+//   if (modemgame==true)
+//      {
+//      SCREENSHOTS=true;
+//      if (standalone==false)
+//         {
+//         MenuFixup ();
+//         }
+//      MAPSTATS=true;
+//      }
+    if (standalone==false)
+    {
+        int status1 = 0;
+        int status2 = 0;
+        int status3 = 0;
+
+        if ( !NoSound && !IS8250 )
+        {
+            if (!quiet)
+                printf( "MU_Startup: " );
+            status1 = MU_Startup(false);
+            if (!quiet)
+                printf( "%s\n", MUSIC_ErrorString( MUSIC_Error ) );
+        }
+        else if ( IS8250 )
+        {
+            printf( "==============================================================================\n");
+            printf( "WARNING: 8250 detected.\n" );
+            printf( "Music has been disabled.  This is necessary to maintain high interrupt\n" );
+            printf( "rates with the 8250 UART which will improve overall game performance.\n");
+            printf( "                      < Press any key to continue >\n");
+            printf( "==============================================================================\n");
+            getch();
+        }
+
+        if (!NoSound)
+        {
+            int nv, nb, nc;
+
+            if (!quiet)
+                printf( "SD_SetupFXCard: " );
+            status2 = SD_SetupFXCard (&nv, &nb, &nc);
+            if (!quiet)
+                printf( "%s\n", FX_ErrorString( FX_Error ) );
+
+            if ( !status2 )
+            {
+                if (!quiet)
+                    printf( "SD_Startup: " );
+                status3 = SD_Startup(false);
+                if (!quiet)
+                    printf( "%s\n", FX_ErrorString( FX_Error ) );
+            }
+        }
+        else
+        {
+            if (!quiet)
+                printf( "Sound FX disabled.\n" );
+        }
+
+#ifdef DOS
+        if ( status1 || status2 || status3 )
+        {
+            printf( "\n\nROTT was unable to initialize your " );
+            if ( status1 )
+            {
+                printf( "music " );
+                MusicMode = 0;
+            }
+            if ( status2 || status3 )
+            {
+                if ( status1 )
+                {
+                    printf( "or " );
+                }
+                printf( "sound fx " );
+
+                FXMode = 0;
+            }
+
+            printf( "hardware.\n"
+                    "Now entering sound setup.\n" );
+            SOUNDSETUP = true;
+        }
+#endif
+
+        Init_Tables ();
+        InitializeRNG ();
+        InitializeMessages();
+        LoadColorMap();
+    }
+    if (infopause==true)
+    {
+        printf("\n< Press any key to continue >\n");
+        getch();
+    }
+    I_StartupTimer();
+    I_StartupKeyboard();
+#if 0
+#if (SHAREWARE == 1)
+    if ((!SOUNDSETUP) && (standalone==false))
+    {
+        byte * txtscn;
+        int i;
+
+        for (i=0; i<20; i++)
+            printf("\n");
+        txtscn = (byte *) W_CacheLumpNum (W_GetNumForName ("rotts10"), PU_CACHE);
+        memcpy ((byte *)0xB8000, txtscn, 4000);
+        I_Delay (600);
+    }
+#endif
+#endif
+    locplayerstate = &PLAYERSTATE[consoleplayer];
+
+    if (standalone==true)
+        ServerLoop();
+
+    VL_SetVGAPlaneMode();
+    VL_SetPalette(origpal);
+
+//   SetTextMode();
+//   GraphicsMode();
+//   SetTextMode();
+//   VL_SetVGAPlaneMode();
+//   VL_SetPalette(origpal);
+//   SetBorderColor(155);
+    SetViewSize(8);
+
+#ifdef DOS
+    if ( SOUNDSETUP )
+    {
+        SwitchPalette( origpal, 35 );
+        CP_SoundSetup();
+    }
+#endif
+
+    playstate = ex_titles;
+
+//   I_SetKeyboardLEDs( caps_lock, 0 );
+
+    gamestate.battlemode = battle_StandAloneGame;
+
+    BATTLE_SetOptions( &BATTLE_Options[ battle_StandAloneGame ] );
+
+    if (turbo || tedlevel)
+    {
+        if (modemgame == true)
+        {
+            turbo = false;
+            NoWait = true;
+        }
+        else
+        {
+            PlayTurboGame();
+        }
+    }
+    else
+    {
+#if (SHAREWARE == 0)
+        if ( dopefish == true )
+        {
+            DopefishTitle();
+        }
+        else if ( NoWait == false )
+        {
+            ApogeeTitle();
+        }
+#else
+        if ( NoWait == false )
+        {
+            if (W_CheckNumForName("svendor") != -1)
+            {
+                lbm_t * LBM;
+
+                LBM = (lbm_t *) W_CacheLumpName( "svendor", PU_CACHE, Cvt_lbm_t, 1);
+                VL_DecompressLBM (LBM,true);
+                I_Delay(40);
+                MenuFadeOut();
+            }
+//         ParticleIntro ();
+            ApogeeTitle();
+        }
+#endif
+    }
+
+    GameLoop();
+
+
+    QuitGame();
+
+    return 0;
+}
+
+void DrawRottTitle ( void )
+{
+    char title[80];
+    char buf[5];
+
+    SetTextMode();
+    TurnOffTextCursor ();
+
+    if (CheckParm("QUIET") == 0)
+    {
+        SetTextMode();
+        TurnOffTextCursor ();
+#ifdef DOS
+        if (CheckParm ("SOUNDSETUP") == 0)
+        {
+#endif
+#ifdef ANSIESC
+            printf("\n\n\n");
+#endif
+            strcpy (title,"Rise of the Triad Startup  Version ");
+            strcat (title,itoa(ROTTMAJORVERSION,&buf[0],10));
+            strcat (title,".");
+//MED
+#if (SHAREWARE==1)||(DOPEFISH==0)
+            strcat (title,itoa(ROTTMINORVERSION,&buf[0],10));
+#else
+            strcat (title,"DFISH");
+#endif
+#ifndef ANSIESC
+            strcat (title,"\n");
+#endif
+
+            px=(80-strlen(title))>>1;
+            py=0;
+
+            UL_printf(title);
+
+            memset (title,0,sizeof(title));
+
+            if (gamestate.Product == ROTT_SHAREWARE)
+            {
+#if (DELUXE==1)
+                strcpy(title,"Lasersoft Deluxe Version");
+#elif (LOWCOST==1)
+                strcpy(title,"Episode One");
+#else
+                strcpy(title,"Shareware Version");
+#endif
+            }
+            else if (gamestate.Product == ROTT_SUPERCD)
+                strcpy(title,"CD Version");
+            else if (gamestate.Product == ROTT_SITELICENSE)
+                strcpy(title,"Site License CD Version");
+            else
+                strcpy(title,"Commercial Version");
+
+            px=(80-strlen(title))>>1;
+            py=1;
+
+            UL_printf(title);
+#ifndef ANSIESC
+            printf ("\n");
+#endif
+
+            UL_ColorBox (0, 0, 80, 2, 0x1e);
+#ifdef DOS
+        }
+        else
+        {
+            printf("\n\n");
+            strcpy (title,"Rise of the Triad Sound Setup  Version ");
+            strcat (title,itoa(ROTTMAJORVERSION,&buf[0],10));
+            strcat (title,".");
+            strcat (title,itoa(ROTTMINORVERSION,&buf[0],10));
+
+            px=(80-strlen(title))>>1;
+            py=0;
+
+            UL_printf(title);
+
+            UL_ColorBox (0, 0, 80, 1, 0x1e);
+        }
+#endif
+    }
+    else
+    {
+        TurnOffTextCursor ();
+    }
+
+}
+
+void CheckCommandLineParameters( void )
+{
+    char *PStrings[] = {"TEDLEVEL","NOWAIT","NOSOUND","NOW",
+                        "TRANSPORT","DOPEFISH","SCREENSHOTS",
+                        "MONO","MAPSTATS","TILESTATS","VER","net",
+                        "PAUSE","SOUNDSETUP","WARP","IS8250","ENABLEVR",
+                        "TIMELIMIT","MAXTIMELIMIT","NOECHO","DEMOEXIT","QUIET",NULL
+                       };
+    int i,n;
+
+    infopause=false;
+#ifdef DOS
+    SOUNDSETUP = false;
+#endif
+    tedlevel=false;
+    NoWait=false;
+    NoSound=false;
+    turbo=false;
+    warp=false;
+    dopefish=false;
+    modemgame=false;
+    SCREENSHOTS=false;
+    MONOPRESENT=false;
+    MAPSTATS=false;
+    TILESTATS=false;
+    IS8250 = false;
+    vrenabled = false;
+    demoexit = false;
+
+    modemgame=false;
+    networkgame=false;
+    consoleplayer=0;
+    numplayers = 1;
+    timelimit=-1;
+    timelimitenabled=false;
+    noecho = false;
+    quiet = false;
+
+    if (
+        (CheckParm("?\0")) ||
+        (CheckParm("HELP")) ||
+        (
+            (_argc>1) &&
+            (_argv[1][0]=='?')
+        )
+    )
+    {
+        SetTextMode ();
+        printf ("Rise of the Triad  (c) 1995 Apogee Software\n\n");
+        printf ("COMMAND LINE PARAMETERS\n");
+        printf ("   AIM        - Give Aim Crosshair.\n");
+        printf ("   FULLSCREEN - Start in fullscreen mode\n");
+        printf ("   WINDOW     - Start in windowed mode\n");
+        printf ("   RESOLUTION - Specify the screen resolution to use\n");
+        printf ("              - next param is <widthxheight>, valid resolutions are:\n");
+        printf ("              - 320x200, 640x480 and 800x600\n");
+#if (SHAREWARE==0)
+        printf ("   FILERTL    - used to load Userlevels (RTL files)\n");
+        printf ("              - next parameter is RTL filename\n");
+        printf ("   FILERTC    - used to load Battlelevels (RTC files)\n");
+        printf ("              - next parameter is RTC filename\n");
+        printf ("   FILE       - used to load Extern WAD files\n");
+        printf ("              - next parameter is WAD filename\n");
+#endif
+        printf ("   SPACEBALL  - Enable check for Spaceball.\n");
+        printf ("   NOJOYS     - Disable check for joystick.\n");
+        printf ("   NOMOUSE    - Disable check for mouse.\n");
+        printf ("   CYBERMAN   - Enable check for Cyberman.\n");
+        printf ("   ASSASSIN   - Enable check for Wingman Assassin.\n");
+        printf ("   VER        - Version number.\n");
+        printf ("   MAPSTATS   - Dump Map statistics to ERROR.\n");
+        printf ("   TILESTATS  - Dump Tile statistics to ERROR.\n");
+        printf ("   MONO       - Enable mono-monitor support.\n");
+        printf ("   SCREENSHOTS- Clean screen capture for shots.\n");
+        printf ("   PAUSE      - Pauses startup screen information.\n");
+#ifdef DOS
+        printf ("   SOUNDSETUP - Setup sound for ROTT\n");
+#endif
+        printf ("   ENABLEVR   - Enable VR helmet input devices\n");
+        printf ("   NOECHO     - Turn off sound reverb\n");
+        printf ("   DEMOEXIT   - Exit program when demo is terminated\n");
+        printf ("   WARP       - Warp to specific ROTT level\n");
+        printf ("                next parameter is level to start on\n");
+        printf ("   TIMELIMIT  - Play ROTT in time limit mode\n");
+        printf ("                next parameter is time in seconds\n");
+        printf ("   MAXTIMELIMIT - Maximimum time to count down from\n");
+        printf ("                next parameter is time in seconds\n");
+        printf ("   DOPEFISH   - ?\n");
+        printf (" \n");
+        printf ("CONTROLS\n");
+        printf ("         Arrows           - Move\n");
+        printf ("         Ctrl             - Fire\n");
+        printf ("         Comma/Alt+left   - Sidestep Left\n");
+        printf ("         Period/Alt+right - Sidestep Right\n");
+        printf ("         Shift            - Run/Turn faster\n");
+        printf ("         Space            - Use/Open\n");
+        printf ("         1-4              - Choose Weapon\n");
+        printf ("         5-6              - Scale Weapon Up/Down\n");
+        printf ("         Enter            - Swap Weapon\n");
+        printf ("         Backspace        - Turn 180\n");
+        printf ("         Delete           - Drop Weapon\n");
+        printf ("         +/-              - Change Viewsize\n");
+        printf ("         PgUp/PgDn        - Look Up/Down\n");
+        printf ("         Home/End         - Aim Up/Down\n");
+        printf ("         [ ]              - Sound Volumen\n");
+        printf ("         ( )              - Music Volumen\n");
+        printf ("         Tab              - Enter Automapper\n");
+        printf (" \n");
+        printf ("AUTO-MAPPER\n");
+        printf ("         Arrows           - Scroll around\n");
+        printf ("         PgUp             - Zoom Out\n");
+        printf ("         PgDn             - Zoom In\n");
+        printf ("         Tab              - Exit Auto-Mapper\n");
+        printf (" \n");
+        printf ("HOTKEYS\n");
+        printf ("         F1               - Help\n");
+        printf ("         F2               - Save Game\n");
+        printf ("         F3               - Restore Game\n");
+        printf ("         F4               - Controls/Sound/Music\n");
+        printf ("         F5               - Change Detail Level\n");
+        printf ("         F6               - Quick Save\n");
+        printf ("         F7               - Messages On/Off\n");
+        printf ("         F8               - End Game\n");
+        printf ("         F9               - Quick Load\n");
+        printf ("         F10              - Quit\n");
+        printf ("         F11              - Gamma Correction\n");
+        printf (" \n");
+        printf ("COMM-BAT\n");
+        printf ("         F1 - F10         - RemoteRidicule(tm) sounds\n");
+        printf ("         F12              - Live RemoteRidicule\n");
+        printf ("         T                - Type message to all\n");
+        printf ("         Z                - Type directed message\n");
+        printf ("         Tab              - Toggle KillCount display\n");
+        printf (" \n");
+        printf ("SCREENSHOOT\n");
+#ifdef DOS /* makes no sense under Linux as there are no lbm viewers there */
+        printf ("         Alt+V            - Screenshoot in LBM format\n");
+#endif
+        printf ("         Alt+C            - Screenshoot in PCX format\n");
+        exit (0);
+    }
+
+    // Check For command line parameters
+
+    for (i = 1; i < _argc; i++)
+    {
+        n = US_CheckParm(_argv[i],PStrings);
+        switch(n)
+        {
+#if (TEDLAUNCH==1)
+        case 0:
+            tedlevelnum = ParseNum(_argv[i + 1]);
+            tedlevel=true;
+            if (i+3>=_argc)
+            {
+                tedx=0;
+                tedy=0;
+            }
+            else
+            {
+                tedx=ParseNum(_argv[i + 2]);
+                tedy=ParseNum(_argv[i + 3]);
+            }
+            MenuFixup ();
+            break;
+#endif
+        case 1:
+            NoWait = true;
+            break;
+        case 2:
+            NoSound = true;
+            break;
+        case 3:
+            turbo = true;
+            break;
+        case 4:
+            warp = true;
+            warpx=ParseNum(_argv[i + 1]);
+            warpy=ParseNum(_argv[i + 2]);
+            warpa=ParseNum(_argv[i + 3]);
+            break;
+        case 5:
+            dopefish=true;
+            break;
+        case 6:
+            SCREENSHOTS = true;
+            break;
+        case 7:
+            MONOPRESENT = true;
+            break;
+        case 8:
+            MAPSTATS = true;
+            break;
+        case 9:
+            TILESTATS = true;
+            break;
+        case 10:
+            SetTextMode ();
+            printf ("Rise of the Triad  (c) 1995 Apogee Software\n");
+//MED
+            if (gamestate.Product == ROTT_SHAREWARE)
+            {
+#if (DELUXE==1)
+                printf("Lasersoft Deluxe ");
+#elif (LOWCOST==1)
+                printf("Episode One ");
+#else
+                printf("Shareware ");
+#endif
+            }
+            else if (gamestate.Product == ROTT_SUPERCD)
+                printf("CD ");
+            else if (gamestate.Product == ROTT_SITELICENSE)
+                printf("Site License ");
+            else
+                printf("Commercial ");
+            printf ("Version %d.%d\n", ROTTMAJORVERSION,ROTTMINORVERSION);
+            exit (0);
+            break;
+        case 11:
+            InitROTTNET();
+            numplayers = rottcom->numplayers;
+            if (numplayers>MAXPLAYERS)
+                Error("Too many players.\n");
+            if (!quiet)
+                printf("Playing %ld player ROTT\n",(long int)numplayers);
+            modemgame=true;
+            if (rottcom->gametype==NETWORK_GAME)
+            {
+                if (!quiet)
+                    printf("NETWORK GAME\n");
+                networkgame=true;
+            }
+            else
+            {
+                if (!quiet)
+                    printf("MODEM GAME\n");
+            }
+            break;
+        case 12:
+            infopause=true;
+            break;
+        case 13:
+#ifdef DOS
+            SOUNDSETUP = true;
+#endif
+            break;
+        case 14:
+            startlevel = (ParseNum(_argv[i + 1])-1);
+            break;
+        case 15:
+            IS8250 = true;
+            break;
+        case 16:
+            vrenabled = true;
+            if (!quiet)
+                printf("Virtual Reality Mode enabled\n");
+            break;
+        case 17:
+            timelimitenabled = true;
+            timelimit = ParseNum(_argv[i + 1]);
+            if (!quiet)
+                printf("Time Limit = %ld Seconds\n",(long int)timelimit);
+            timelimit *= VBLCOUNTER;
+            break;
+
+        case 18:
+            maxtimelimit = ParseNum(_argv[i + 1]);
+            maxtimelimit *= VBLCOUNTER;
+            break;
+        case 19:
+            noecho = true;
+            break;
+        case 20:
+            demoexit = true;
+            break;
+        case 21:
+            quiet = true;
+            break;
+        }
+    }
+}
+
+void SetupWads( void )
+{
+    char  *newargs[99];
+    int i, arg, argnum = 0;
+    char *tempstr = NULL;
+    char *PStrings[] = {"AIM", "FULLSCREEN", "WINDOW", "RESOLUTION", NULL };
+
+    // These must be checked here so that they can override the cfg file
+    for (i = 1; i < _argc; i++)
+    {
+        arg = US_CheckParm(_argv[i],PStrings);
+        switch(arg)
+        {
+        case 0:
+            iG_aimCross = 1;
+            break;
+        case 1:
+            sdl_fullscreen = 1;
+            break;
+        case 2:
+            sdl_fullscreen = 0;
+            break;
+        case 3:
+            i++;
+            if (i < _argc)
+            {
+                int width, height;
+                if ( (sscanf(_argv[i], "%dx%d", &width, &height) == 2) &&
+                        ( ( (width == 320) && (height == 200) ) ||
+                          ( (width == 640) && (height == 480) ) ||
+                          ( (width == 800) && (height == 600) ) ) )
+                {
+                    iGLOBAL_SCREENWIDTH  = width;
+                    iGLOBAL_SCREENHEIGHT = height;
+                }
+                else
+                    printf("Invalid resolution parameter: %s\n", _argv[i]);
+            }
+            else
+                printf("Missing resolution parameter\n");
+            break;
+        }
+    }
+
+
+#if (SHAREWARE==0)
+    // Check for rtl files
+    arg = CheckParm ("filertl");
+    if (arg!=0)
+    {
+        FILE *f;
+        char *buf = malloc(32);
+        if (_argv[arg+1] != 0) { //are there a filename included
+            tempstr = realloc(tempstr, 129 + strlen(_argv[arg+1]));
+            strcpy (tempstr,_argv[arg+1]);//copy it to tempstr
+            if (strlen (tempstr) < MAX_PATH) {
+                if (access (tempstr, 0) != 0) { //try open
+                    strcat (tempstr,".rtc");//non exists, try add .rtc
+                    if (access (tempstr, 0) != 0) { //try open again
+                        //stil no useful filename
+                        strcat (tempstr," not found, skipping RTL file ");
+                        printf("%s", tempstr);
+                        goto NoRTL;
+                    }
+                }
+                if((f = fopen( tempstr, "r" )) == NULL ) { //try opnong file
+                    strcat (tempstr," not could not be opened, skipping RTL file ");
+                    printf("%s", tempstr);
+                    goto NoRTL;
+                } else {
+                    fread(buf,3,3,f);//is the 3 first letters RTL (RTC)
+                    if (((strstr(buf,"RTL") != 0)||strstr(buf,"RTC") != 0)) {
+                        GameLevels.file = strdup(tempstr);
+                        GameLevels.avail++;
+                        buf = realloc(buf, 32 + strlen(tempstr));
+                        strcpy (buf,"Adding ");
+                        strcat (buf,tempstr);
+                        printf("%s", buf);
+                    }
+                    fclose(f);
+                }
+            }
+        } else {
+            printf("Missing RTL filename");
+        }
+        free(buf);
+    }
+NoRTL:
+    ;
+    // Check for rtc files
+    arg = CheckParm ("filertc");
+    if (arg!=0)
+    {
+        FILE *f;
+        char *buf = malloc(32);
+        if (_argv[arg+1] != 0) { //are there a filename included
+            tempstr = realloc(tempstr, 129 + strlen(_argv[arg+1]));
+            strcpy (tempstr,_argv[arg+1]);//copy it to tempstr
+            if (strlen (tempstr) < MAX_PATH) {
+                if (access (tempstr, 0) != 0) { //try open
+                    strcat (tempstr,".rtc");//non exists, try add .rtc
+                    if (access (tempstr, 0) != 0) { //try open again
+                        //stil no useful filename
+                        strcat (tempstr," not found, skipping RTC file ");
+                        printf("%s", tempstr);
+                        goto NoRTL;
+                    }
+                }
+                if((f = fopen( tempstr, "r" )) == NULL ) { //try opening file
+                    strcat (tempstr," not could not be opened, skipping RTC file ");
+                    printf("%s", tempstr);
+                    goto NoRTL;
+                } else {
+                    fread(buf,3,3,f);//is the 3 first letters RTL (RTC)
+                    if (((strstr(buf,"RTL") != 0)||strstr(buf,"RTC") != 0)) {
+                        BattleLevels.file = strdup(tempstr);
+                        BattleLevels.avail++;
+                        buf = realloc(buf, 32 + strlen(tempstr));
+                        strcpy (buf,"Adding ");
+                        strcat (buf,tempstr);
+                        printf("%s", buf);
+                    }
+                    fclose(f);
+                }
+            }
+        } else {
+            printf("Missing RTC filename");
+        }
+        free(buf);
+    }
+NoRTC:
+    ;
+
+    // Check for User wads
+    arg = CheckParm ("file");
+    if (arg!=0)
+    {
+        newargs [argnum++] = _argv[arg+1];
+    }
+
+    arg = CheckParm ("file1");
+    if (arg!=0)
+    {
+        newargs [argnum++] = _argv[arg+1];
+    }
+
+    arg = CheckParm ("file2");
+    if (arg!=0)
+    {
+        newargs [argnum++] = _argv[arg+1];
+    }
+
+#else
+    if (
+        (CheckParm ("file") > 0) ||
+        (CheckParm ("file1") > 0) ||
+        (CheckParm ("file2") > 0)
+    )
+        printf("External wads ignored.\n");
+
+#endif
+
+    // Normal ROTT wads
+
+#if (SHAREWARE)
+    newargs [argnum++] = DATADIR "HUNTBGIN.WAD";
+#else
+    newargs [argnum++] = DATADIR "DARKWAR.WAD";
+#endif
+
+//   newargs [argnum++] = "credits.wad";
+
+    // Check for Remote Ridicule WAD
+
+    if (RemoteSounds.avail == true)
+    {
+        char  *src;
+
+        tempstr = realloc(tempstr, strlen(RemoteSounds.path) + strlen(RemoteSounds.file) + 2);
+        strcpy (tempstr,RemoteSounds.path);
+        src = RemoteSounds.path + strlen(RemoteSounds.path) - 1;
+        if (*src != '\\')
+            strcat (tempstr,"\\\0");
+        strcat (tempstr,RemoteSounds.file);
+        newargs [argnum++] = strdup(tempstr);
+    }
+    else
+    {
+        newargs [argnum++] = DATADIR "REMOTE1.RTS";
+    }
+
+    if (tempstr)
+        free(tempstr);
+
+    newargs [argnum++] = NULL;
+
+    W_InitMultipleFiles(newargs);
+}
+
+void PlayTurboGame
+(
+    void
+)
+
+{
+    NewGame = true;
+    locplayerstate->player = DefaultPlayerCharacter;
+    playstate = ex_resetgame;
+    GameLoop();
+}
+
+
+//***************************************************************************
+//
+// Init_Tables () - Init tables needed for double buffering
+//
+//***************************************************************************
+
+void Init_Tables (void)
+{
+    int i;
+    int x,
+        y;
+    unsigned *blockstart;
+    byte * shape;
+
+    memset (&CWD[0], 0, 40);
+    getcwd (CWD, 40);                      // get the current directory
+
+    origpal=SafeMalloc(768);
+    memcpy (origpal, W_CacheLumpName("pal",PU_CACHE, CvtNull, 1), 768);
+
+    FindEGAColors();
+
+    for (i=0; i<PORTTILESHIGH; i++)
+        uwidthtable[i] = UPDATEWIDE*i;
+
+    updateptr = &update[0];
+
+    blockstart = &blockstarts[0];
+    for (y=0; y<UPDATEHIGH; y++)
+        for (x=0; x<UPDATEWIDE; x++)
+            *blockstart++ = iG_SCREENWIDTH*16*y+x*TILEWIDTH;
+
+    for (i = 0; i < 0x300; i++)
+        *(origpal+(unsigned int)i) = (*(origpal+(unsigned int)i))>>2;
+
+    // Cache in fonts
+    shape = W_CacheLumpNum (W_GetNumForName ("smallfont"), PU_STATIC, Cvt_font_t, 1);
+    smallfont = (font_t *)shape;
+    CurrentFont = smallfont;
+
+    // Cache in tiny font
+    shape = W_CacheLumpNum (W_GetNumForName ("tinyfont"), PU_STATIC, Cvt_font_t, 1);
+    tinyfont = (font_t *)shape;
+
+    intensitytable=W_CacheLumpNum(W_GetNumForName("menucmap"),PU_STATIC, CvtNull, 1);
+    fontcolor = egacolor[4];
+
+    if (!quiet)
+        printf("RT_MAIN: Fonts Initialized\n");
+}
+
+
+
+
+int NumberOfTeams
+(
+    void
+)
+
+{
+    int index;
+    int team[ MAXPLAYERCOLORS ];
+    int count;
+    int color;
+
+    memset( team, 0, sizeof( team ) );
+
+    count = 0;
+    for( index = 0; index < numplayers; index++ )
+    {
+        color = PLAYERSTATE[ index ].uniformcolor;
+        if ( !team[ color ] )
+        {
+            team[ color ] = true;
+            count++;
+        }
+    }
+
+    return( count );
+}
+
+extern boolean allowBlitzMoreMissileWeps;
+extern boolean enableZomROTT;
+
+void GameLoop (void)
+{
+    boolean done   = false;
+    boolean loadit = false;
+    int NextLevel;
+
+    wami(1);
+
+    while (1)
+    {
+        if ( playstate == ex_battledone )
+        {
+            while( damagecount > 0 )
+            {
+                DoBorderShifts();
+            }
+            damagecount = 0;
+            SetBorderColor (0);
+
+            StopWind();
+
+            ShutdownClientControls();
+
+            SD_Play (SD_LEVELDONESND);
+
+            if ( ( player->flags & FL_DOGMODE ) ||
+                    ( gamestate.battlemode == battle_Eluder ) )
+                MU_StartSong(song_dogend);
+            else
+                MU_StartSong(song_endlevel);
+
+
+            VL_FillPalette(255,255,255);
+            VL_FadeIn(0,255,origpal,10);
+
+            BattleLevelCompleted( consoleplayer );
+
+            BATTLE_Shutdown();
+
+            Z_FreeTags (PU_LEVELSTRUCT, PU_LEVELEND);       // Free current level
+
+            ingame = false;
+
+            if ( networkgame == true )
+            {
+                AddGameEndCommand ();
+            }
+
+            AdjustMenuStruct ();
+
+            CalcTics();
+            CalcTics();
+
+
+            playstate = ex_titles;
+        }
+
+        switch (playstate)
+        {
+        case ex_titles:
+
+            BATTLE_Shutdown();
+            MU_StartSong(song_title);
+            EnableScreenStretch();
+            if ((NoWait==false)&&(!modemgame))
+            {
+                byte dimpal[768];
+                int i;
+
+                for (i = 0; i < 0x300; i++)
+                    dimpal[i] = origpal[i]>>2;
+                CalcTics();
+                CalcTics();
+                IN_ClearKeysDown ();
+                while (IN_GetMouseButtons()) {}
+                while ((!LastScan) && (!IN_GetMouseButtons()))
+                {
+                    int i;
+                    byte *tempbuf;
+                    MenuFadeOut();
+                    ClearGraphicsScreen();
+                    SetPalette(&dimpal[0]);
+                    PlayMovie ("shartitl", true);
+                    if ( ( LastScan ) || ( IN_GetMouseButtons() ) )
+                    {
+                        break;
+                    }
+
+                    PlayMovie ("shartit2", true);
+
+                    if ( ( LastScan ) || ( IN_GetMouseButtons() ) )
+                    {
+                        break;
+                    }
+                    SD_Play (SD_LIGHTNINGSND);
+                    MenuFadeIn();
+                    I_Delay(30);
+                    SD_Play (SD_ACTORSQUISHSND);
+                    tempbuf=bufferofs;
+                    bufferofs=page1start; // fixed, was displayofs
+                    DrawNormalSprite(320-94,200-41,W_GetNumForName("rsac"));
+                    VW_UpdateScreen(); // fixed, was missing
+                    bufferofs=tempbuf;
+                    I_Delay(30);
+
+                    if ( ( LastScan ) || ( IN_GetMouseButtons() ) )
+                    {
+                        break;
+                    }
+
+                    DoCreditScreen ();
+                    if ((!LastScan) && (!IN_GetMouseButtons()))
+                        CheckHighScore (0, 0, false);
+#if (SHAREWARE==0)
+                    if ((!LastScan) && (!IN_GetMouseButtons()))
+                    {
+                        DoMicroStoryScreen ();
+                    }
+#endif
+                    if (
+                        (!LastScan) &&
+                        (!IN_GetMouseButtons()) &&
+                        (lowmemory==0) &&
+                        (GameLevels.avail==false)
+                    )
+                    {
+                        if (demonumber==-1)
+                            demonumber=RandomNumber("GameLoop",0);
+                        for (i=0; i<4; i++)
+                        {
+                            demonumber=(demonumber+1)%4;
+                            if (DemoExists (demonumber+1) == true)
+                                break;
+                        }
+                        if (DemoExists (demonumber+1) == true)
+                        {
+                            ingame=true;
+                            LoadDemo (demonumber+1);
+                            break;
+                        }
+                    }
+                }
+            }
+
+            if (playstate != ex_demoplayback)
+            {
+                if (demoexit == true)
+                {
+                    QuitGame();
+                }
+                NoWait = false;
+                SwitchPalette(origpal,35);
+                CP_MainMenu();
+
+            }
+            break;
+
+        case ex_resetgame:
+
+            // SetTextMode (  ); //12345678
+            EnableScreenStretch();//bna++ shut on streech mode
+            InitCharacter();
+
+            InitializeMessages();
+
+            fizzlein = true;
+            BATTLE_GetSpecials();
+            BATTLE_SetOptions( &BATTLE_Options[ gamestate.battlemode ] );
+
+            if ( modemgame == true )
+            {
+                fizzlein = false;
+
+                if ( consoleplayer == 0 )
+                {
+                    // Setup Master
+                    SetupGameMaster();
+                }
+                else
+                {
+                    // Setup slave
+                    SetupGamePlayer();
+                }
+
+                if ( gamestate.Version < ROTTVERSION )
+                {
+                    Error( "This version of Rise of the Triad (%d.%d) is incompatible with\n"
+                           "version %d.%d.", ROTTMAJORVERSION, ROTTMINORVERSION,
+                           gamestate.Version / 10, gamestate.Version % 10 );
+                }
+                if ( gamestate.teamplay )
+                {
+                    int teams;
+
+                    teams = NumberOfTeams();
+                    if ( gamestate.battlemode == battle_CaptureTheTriad )
+                    {
+                        if ( teams != 2 )
+                        {
+                            CP_CaptureTheTriadError();
+                            playstate = ex_titles;
+                            continue;
+                        }
+                    }
+                    else if ( teams < 2 )
+                    {
+                        CP_TeamPlayErrorMessage();
+                        playstate = ex_titles;
+                        continue;
+                    }
+                }
+            }
+
+            InitCharacter();
+
+            BATTLE_Init( gamestate.battlemode, numplayers );
+
+            NewGame = true;
+
+            if ( ( BATTLEMODE ) && ( BATTLE_ShowKillCount ) )
+            {
+                StatusBar |= STATUS_KILLS;
+            }
+            else
+            {
+                StatusBar &= ~STATUS_KILLS;
+            }
+
+            if (loadedgame == false)
+            {
+                if ( !BATTLEMODE )
+                {
+                    PlayCinematic();
+                }
+                
+                SetupGameLevel();
+            }
+
+            IN_ClearKeyboardQueue();
+
+            SetupScreen (true);
+
+            MenuFixup ();
+            playstate=ex_stillplaying;
+
+            DisableScreenStretch();//bna++ shut off streech mode
+
+            break;
+
+        case ex_stillplaying:
+            InitializeMessages();
+
+            SHAKETICS = 0xFFFF;
+            if (modemgame==true)
+            {
+                ComSetTime();
+                turbo = false;
+            }
+            else if (turbo==true)
+                turbo=false;
+            else
+                newlevel=true;
+            PlayLoop ();
+            break;
+
+        case ex_died:
+            loadit = done = false;
+//		   SetTextMode (  ); //12345678
+            Died ();
+            StopWind();
+            DisableScreenStretch();//bna++ shut off streech mode
+            while (damagecount>0)
+                DoBorderShifts();
+
+            damagecount = 0;
+            SetBorderColor (0);
+            if (demorecord)
+            {
+                FreeDemo ();
+            }
+            if (demoplayback)
+            {
+                FreeDemo ();
+                playstate=ex_demodone;
+            }
+            else
+            {
+                ShutdownClientControls();
+
+                Z_FreeTags (PU_LEVELSTRUCT, PU_LEVELEND);       // Free current level
+
+                if (CheckForQuickLoad()==false)
+                {
+                    if (locplayerstate->lives < 0)
+                    {
+                        if (timelimitenabled == false)
+                        {
+                            CheckHighScore (gamestate.score, gamestate.mapon+1, false);
+                            playstate = ex_titles;
+                            AdjustMenuStruct ();
+                            ingame = false;
+                            locplayerstate->health     = MaxHitpointsForCharacter(locplayerstate);
+                            gamestate.score            = 0;
+                            locplayerstate->lives      = 3;
+                            locplayerstate->weapon     = wp_pistol;
+                            locplayerstate->triads     = 0;
+                            UpdateLives (locplayerstate->lives);
+                            UpdateScore (gamestate.score);
+                        }
+                        else
+                        {
+                            QuitGame();
+                        }
+                    }
+                    else
+                    {
+                        fizzlein = true;
+                        SetupGameLevel ();
+                        UpdateTriads(player,0);
+                        playstate = ex_stillplaying;
+                    }
+                }
+            }
+            break;
+
+        case ex_warped:
+            StopWind();
+            TurnShakeOff();
+            SHAKETICS = 0xffff;
+            gamestate.TimeCount = 0;
+            gamestate.frame=0;
+
+            Z_FreeTags (PU_LEVELSTRUCT, PU_LEVELEND);       // Free current level
+
+            fizzlein = true;
+            SetupGameLevel ();
+
+            playstate = ex_stillplaying;
+            break;
+
+        case ex_skiplevel:
+        case ex_secretdone:
+        case ex_secretlevel:
+        case ex_completed:
+        case ex_bossdied:
+            ShutdownClientControls();
+            TurnShakeOff();
+            SHAKETICS = 0xffff;
+            if (timelimitenabled == false)
+            {
+                gamestate.TimeCount = 0;
+                gamestate.frame=0;
+            }
+            StopWind();
+#if (SHAREWARE==0)
+            if ((playstate==ex_bossdied) && (gamestate.mapon!=30))
+            {
+                int shape;
+                lbm_t * LBM;
+                byte *s;
+                patch_t *p;
+                char str[50];
+                int width, height;
+
+                LBM = (lbm_t *) W_CacheLumpName( "deadboss", PU_CACHE, Cvt_lbm_t, 1);
+                VL_DecompressLBM (LBM,false);
+                MenuFadeOut();
+                switch (gamestate.mapon)
+                {
+                case 6:
+                    shape = W_GetNumForName("deadstev");
+                    break;
+                case 14:
+                    shape = W_GetNumForName("deadjoe");
+                    break;
+                case 22:
+                    shape = W_GetNumForName("deadrobo");
+                    break;
+                case 33:
+                    shape = W_GetNumForName("deadtom");
+                    break;
+//                  default:
+//                     Error("Boss died on an illegal level\n");
+//                     break;
+                }
+                s = W_CacheLumpNum (shape, PU_CACHE, Cvt_patch_t, 1);
+                p = (patch_t *)s;
+                DrawNormalSprite ((320-p->origsize)>>1, (230-(p->height-p->topoffset))>>1, shape);
+                switch (gamestate.mapon)
+                {
+                case 6:
+                    strcpy(&str[0],"\"General\" John Darian");
+                    break;
+                case 14:
+                    strcpy(&str[0],"Sebastian \"Doyle\" Krist");
+                    break;
+                case 22:
+                    strcpy(&str[0],"the NME");
+                    break;
+                case 33:
+                    strcpy(&str[0],"El Oscuro");
+                    break;
+//                  default:
+//                     Error("Boss died on an illegal level\n");
+//                     break;
+                }
+                CurrentFont=smallfont;
+                US_MeasureStr (&width, &height, "%s", str);
+                US_ClippedPrint ((320-width)>>1, 180, str);
+                VW_UpdateScreen();
+                MenuFadeIn();
+
+                WaitKeyUp();
+                LastScan = 0;
+                while (!LastScan) IN_UpdateKeyboard();	// Thanks again DrLex
+                LastScan=0;
+            }
+#endif
+            
+            LevelCompleted ( playstate );
+
+            NextLevel = GetNextMap(player->tilex,player->tiley);
+
+            demoplayback = false;
+
+            Z_FreeTags (PU_LEVELSTRUCT, PU_LEVELEND);       // Free current level
+            if (NextLevel != -1 )
+            {
+                gamestate.mapon = NextLevel;
+                PlayCinematic();
+                fizzlein = true;
+                SetupGameLevel ();
+                playstate = ex_stillplaying;
+            }
+            else
+            {
+                playstate = ex_gameover;
+            }
+            break;
+
+        case ex_demodone:
+            ingame=false;
+            ShutdownClientControls();
+            TurnShakeOff();
+            SHAKETICS = 0xffff;
+            gamestate.TimeCount = 0;
+            gamestate.frame=0;
+
+            demoplayback = false;
+
+            Z_FreeTags (PU_LEVELSTRUCT, PU_LEVELEND);       // Free current level
+            if (predemo_violence != -1)
+            {
+                gamestate.violence = predemo_violence;
+                predemo_violence = -1;
+            }
+            playstate=ex_titles;
+            break;
+
+        case ex_gameover:
+            StopWind();
+            DoEndCinematic();
+            if (playstate==ex_gameover)
+            {
+                CheckHighScore (gamestate.score, gamestate.mapon+1, false);
+
+                ingame = false;
+                AdjustMenuStruct ();
+                playstate = ex_titles;
+            }
+            break;
+
+        case ex_demorecord:
+            ShutdownClientControls();
+            Z_FreeTags (PU_LEVELSTRUCT, PU_LEVELEND);       // Free current level
+
+            RecordDemo();
+            SetupGameLevel ();
+
+            fizzlein = true;
+            playstate = ex_stillplaying;
+            break;
+
+        case ex_demoplayback:
+            ShutdownClientControls();
+            Z_FreeTags (PU_LEVELSTRUCT, PU_LEVELEND);       // Free current level
+
+            SetupDemo();
+            SetupGameLevel ();
+
+            fizzlein = true;
+            playstate = ex_stillplaying;
+            break;
+        default:
+            ;
+        }
+    }
+    waminot();
+}
+
+boolean CheckForQuickLoad  (void )
+
+{
+
+    EnableScreenStretch();//bna++
+
+    if ( pickquick )
+    {
+        SetupMenuBuf();
+
+        pickquick = CP_DisplayMsg( "\nQuick load saved game?\n", 12 );
+        if ( pickquick )
+        {
+            AllocateSavedScreenPtr();
+            CP_LoadGame( 1, 1 );
+            FreeSavedScreenPtr();
+        }
+        else
+        {
+            // Erase the quick load message
+            VL_FadeOut( 0, 255, 0, 0, 0, 20 );
+        }
+
+        ShutdownMenuBuf();
+    }
+
+    return( pickquick );
+}
+
+//===========================================================================
+
+void ShutDown ( void )
+{
+    if ( ( standalone == false )
+#ifdef DOS
+            || ( SOUNDSETUP )
+#endif
+       )
+    {
+        WriteConfig ();
+    }
+
+//   if (
+//       (networkgame==false) &&
+//       (modemgame==true)
+//      )
+//      {
+//      ShutdownModemGame ();
+//      }
+
+    ShutdownClientControls();
+    I_ShutdownKeyboard();
+#ifdef DOS /* the UL_ErrorStartup() call is commented out... */
+    UL_ErrorShutdown ();
+#endif
+    ShutdownGameCommands();
+    MU_Shutdown();
+    I_ShutdownTimer();
+    SD_Shutdown();
+    IN_Shutdown ();
+    ShutdownSoftError ();
+    Z_ShutDown();
+//   _settextcursor (0x0607);
+}
+
+//===========================================================================
+
+#if (DEVELOPMENT == 1)
+extern int totallevelsize;
+#endif
+
+void QuitGame ( void )
+{
+#if (DEBUG == 1)
+    char buf[5];
+#endif
+
+#if (DEVELOPMENT == 1)
+    int temp;
+#else
+    byte *txtscn;
+#endif
+    int k;
+
+    MU_FadeOut(200);
+    while (MU_FadeActive())
+    {
+        int time=GetTicCount();
+        while (GetTicCount()==time) {}
+    }
+
+    PrintMapStats();
+    PrintTileStats();
+    SetTextMode();
+
+#if (DEVELOPMENT == 1)
+    printf("Clean Exit\n");
+    if (gamestate.TimeCount)
+    {
+        temp=(gamestate.frame*VBLCOUNTER*100)/gamestate.TimeCount;
+        printf("fps  = %2ld.%2ld\n",temp/100,temp%100);
+    }
+    printf("argc=%ld\n",_argc);
+    for (k=0; k<_argc; k++) printf("%s\n",_argv[k]);
+    switch( _heapchk() )
+    {
+    case _HEAPOK:
+        printf( "OK - heap is good\n" );
+        break;
+    case _HEAPEMPTY:
+        printf( "OK - heap is empty\n" );
+        break;
+    case _HEAPBADBEGIN:
+        printf( "ERROR - heap is damaged\n" );
+        break;
+    case _HEAPBADNODE:
+        printf( "ERROR - bad node in heap\n" );
+        break;
+    }
+    printf("\nLight Characteristics\n");
+    printf("---------------------\n");
+    if (fog)
+        printf("FOG is ON\n");
+    else
+        printf("FOG is OFF\n");
+    printf("LIGHTLEVEL=%ld\n",GetLightLevelTile());
+    printf("LIGHTRATE =%ld\n",GetLightRateTile());
+    printf("\nCENTERY=%ld\n",centery);
+#else
+#ifdef DOS
+    if ( !SOUNDSETUP )
+    {
+#endif
+#if (SHAREWARE==0)
+        txtscn = (byte *) W_CacheLumpNum (W_GetNumForName ("regend"), PU_CACHE, CvtNull, 1);
+#else
+        txtscn = (byte *) W_CacheLumpNum (W_GetNumForName ("shareend"), PU_CACHE, CvtNull, 1);
+#endif
+#if DOS
+        for (k = 0; k < 23; k++)
+            printf ("\n");
+        memcpy ((byte *)0xB8000, txtscn, 4000);
+#elif defined (ANSIESC)
+        DisplayTextSplash (txtscn, 25);
+#endif
+
+#if (DEBUG == 1)
+        px = ERRORVERSIONCOL;
+        py = ERRORVERSIONROW;
+#if (BETA == 1)
+        UL_printf ("�");
+#else
+        UL_printf (itoa(ROTTMAJORVERSION,&buf[0],10));
+#endif
+        // Skip the dot
+        px++;
+
+        UL_printf (itoa(ROTTMINORVERSION,&buf[0],10));
+#endif
+#ifdef DOS
+    }
+#endif
+#endif
+
+#ifdef DOS
+    if ( SOUNDSETUP )
+    {
+        printf( "\nSound setup complete.\n"
+                "Type ROTT to run the game.\n" );
+    }
+    ShutDown();
+#endif
+
+    exit(0);
+}
+
+void InitCharacter
+(
+    void
+)
+
+{
+    locplayerstate->health = MaxHitpointsForCharacter( locplayerstate );
+    if (timelimitenabled == true)
+    {
+        locplayerstate->lives  = 1;
+    }
+    else
+    {
+        locplayerstate->lives  = 3;
+    }
+
+    ClearTriads (locplayerstate);
+    locplayerstate->playerheight = characters[ locplayerstate->player ].height;
+//   locplayerstate->stepwhich = 0;
+//   locplayerstate->steptime = 0;
+
+    gamestate.score = 0;
+
+    if ( gamestate.battlemode == battle_StandAloneGame )
+    {
+        gamestate.mapon = startlevel;
+        gamestate.difficulty = DefaultDifficulty;
+    }
+    else
+    {
+        gamestate.difficulty = gd_hard;
+    }
+
+    gamestate.dipballs = 0;
+    gamestate.TimeCount = 0;
+
+    godmode = 0;
+    damagecount = 0;
+
+    UpdateScore( gamestate.score );
+}
+
+
+
+extern boolean enableZomROTT;
+void UpdateGameObjects ( void )
+{
+    int j;
+    volatile int atime;
+    objtype * ob,*temp;
+    battle_status BattleStatus;
+
+    wami(2);
+
+    if (controlupdatestarted==0)
+    {
+        return;
+        waminot();
+    }
+
+    atime=GetFastTics();
+
+    UpdateClientControls ();
+
+    if (demoplayback == false)
+        PollControls ();
+
+    CalcTics ();
+
+    UpdateClientControls ();
+
+
+    while (oldpolltime<oldtime)
+    {
+        UpdateClientControls ();
+        MoveDoors();
+        ProcessElevators();
+        MovePWalls();
+        UpdateLightning ();
+        TriggerStuff();
+        CheckCriticalStatics();
+        if (((gamestate.TimeCount/VBLCOUNTER) % 60 == 0) && gamestate.TimeCount/VBLCOUNTER >= 60 && enableZomROTT)
+        {
+            ResurrectEnemies();
+        }
+        
+        for(j=0; j<numclocks; j++)
+            if (Clocks[j].time1 &&
+                    ((gamestate.TimeCount == Clocks[j].time1) ||
+                     (gamestate.TimeCount == Clocks[j].time2)))
+                TRIGGER[Clocks[j].linkindex]=1;
+        for (ob = firstactive; ob;)
+        {
+            temp = ob->nextactive;
+            DoActor (ob);
+#if (DEVELOPMENT == 1)
+            if ((ob->x<=0) || (ob->y<=0))
+                Error("object xy below zero obj->x=%ld obj->y=%ld obj->obclass=%ld\n",ob->x,ob->y,ob->obclass);
+            if ((ob->angle<0) || (ob->angle>=FINEANGLES))
+                Error("object angle below zero obj->angle=%ld obj->obclass=%ld\n",ob->angle,ob->obclass);
+#endif
+            ob = temp;
+        }
+
+        BattleStatus = BATTLE_CheckGameStatus( battle_refresh, 0 );
+        if ( BattleStatus != battle_no_event )
+        {
+            switch( BattleStatus )
+            {
+            case battle_end_game :
+            case battle_out_of_time :
+                playstate = ex_battledone;
+                break;
+
+            case battle_end_round :
+                SetWhoHaveWeapons();
+                break;
+            default:
+                ;
+            }
+            if ( playstate == ex_battledone )
+            {
+                break;
+            }
+        }
+#if (SYNCCHECK == 1)
+        CheckForSyncCheck();
+#endif
+        if (timelimitenabled == true)
+        {
+            if (timelimit-gamestate.TimeCount>maxtimelimit)
+                timelimit = maxtimelimit+gamestate.TimeCount;
+            if (gamestate.TimeCount == timelimit)
+            {
+                locplayerstate->lives=-1;
+                playstate=ex_died;
+            }
+        }
+
+        gamestate.TimeCount ++;
+
+        ResetCurrentCommand();
+
+        oldpolltime++;
+        if (GamePaused==true)
+            break;
+    }
+    actortime=GetFastTics()-atime;
+
+    UpdateClientControls ();
+
+    if (noecho == false)
+    {
+        if ( player->flags & FL_SHROOMS )
+        {
+            FX_SetReverb( 230 );
+        }
+        else if (sky == 0)
+        {
+            FX_SetReverb( min( numareatiles[ player->areanumber ] >> 1, 90 ) );
+        }
+    }
+
+    waminot();
+
+}
+
+
+void PauseLoop ( void )
+{
+    StopWind();
+
+    UpdateClientControls ();
+
+    while (oldpolltime<oldtime)
+    {
+        CheckUnPause();
+#if (SYNCCHECK == 1)
+        CheckForSyncCheck();
+#endif
+        oldpolltime++;
+        if (GamePaused==false)
+        {
+            //bna++ section
+            if (( playstate == ex_stillplaying )&&(iGLOBAL_SCREENWIDTH > 320)) {
+                pic_t *shape;
+                shape =  ( pic_t * )W_CacheLumpName( "backtile", PU_CACHE, Cvt_pic_t, 1 );
+                DrawTiledRegion( 0, 16, iGLOBAL_SCREENWIDTH, iGLOBAL_SCREENHEIGHT - 32, 0, 16, shape );
+                DisableScreenStretch();//dont strech when we go BACK TO GAME
+                DrawPlayScreen(true);//repaint ammo and life stat
+                VW_UpdateScreen ();//update screen
+            }
+            StartupClientControls();
+            //bna section end
+            break;
+        }
+    }
+
+    CalcTics ();
+    if (demoplayback==false)
+        PollControls ();
+
+    if ((RefreshPause == true) &&
+            (GamePaused == true) &&
+            ((GetTicCount() - pausedstartedticcount) >= blanktime))
+    {
+        RefreshPause = false;
+        StartupScreenSaver();
+    }
+}
+
+
+
+void PlayLoop
+(
+    void
+)
+
+{
+    volatile int atime;
+
+    boolean canquit = true;
+    int     quittime = 0;
+
+    wami(3);
+
+
+    if ( (loadedgame == false) && (timelimitenabled == false) )
+    {
+        gamestate.TimeCount = 0;
+        gamestate.frame = 0;
+    }
+
+fromloadedgame:
+
+    GamePaused = false;
+
+    if ( loadedgame == false )
+    {
+        DrawPlayScreen( true );
+        missobj = NULL;
+    }
+    else
+    {
+        loadedgame = false;
+        DoLoadGameSequence();
+    }
+
+    drawtime  = 0;
+    actortime = 0;
+    tics      = 0;
+    SetFastTics(0);
+
+    if ( fizzlein == false )
+    {
+        StartupClientControls();
+    }
+    else
+    {
+        ShutdownClientControls();
+    }
+
+    // set detail level
+    doublestep = 2 - DetailLevel;
+
+    ResetMessageTime();
+    DeletePriorityMessage( MSG_SYSTEM );
+
+    if ( ( gamestate.battlemode == battle_Normal ) &&
+            ( numplayers == 1 ) )
+    {
+        AddMessage( "Comm-bat is for Modem and Network games.", MSG_GAME );
+        AddMessage( "You will not be facing any", MSG_GAME );
+        AddMessage( "opponents.  Have fun and explore.", MSG_GAME );
+    }
+
+
+    while( playstate == ex_stillplaying )
+    {
+        UpdateClientControls();
+
+        if ( GamePaused )
+        {
+            PauseLoop();
+
+            atime = GetFastTics();
+
+            if ( RefreshPause )
+            {
+                ThreeDRefresh();
+            }
+            else
+            {
+                UpdateScreenSaver();
+            }
+        }
+        else
+        {
+            if (controlupdatestarted == 1)
+                UpdateGameObjects();
+
+            atime = GetFastTics();
+
+            ThreeDRefresh();
+        }
+
+        SyncToServer();
+
+        drawtime = GetFastTics() - atime;
+
+        // Don't allow player to quit if entering message
+        canquit = !MSG.messageon;
+
+        PollKeyboard();
+
+        MISCVARS->madenoise = false;
+
+        AnimateWalls();
+
+        UpdateClientControls();
+
+#if (DEVELOPMENT == 1)
+        Z_CheckHeap();
+#endif
+
+        if ( AutoDetailOn == true )
+        {
+            AdaptDetail();
+        }
+
+        UpdateClientControls();
+
+        DoSprites();
+        DoAnimatedMaskedWalls();
+
+        UpdatePlayers();
+
+        DrawTime( false );
+
+        UpdateClientControls();
+
+        if ( ( !BATTLEMODE ) && ( CP_CheckQuick( LastScan ) ) )
+        {
+            boolean escaped=false;
+
+            if (LastScan == sc_Escape)
+            {
+                MU_StoreSongPosition();
+                MU_StartSong(song_menu);
+                escaped = true;
+            }
+            TurnShakeOff();
+            StopWind();
+            SetBorderColor( 0 );
+            ShutdownClientControls();
+            if (demoplayback==true)
+            {
+                FreeDemo();
+                playstate = ex_demodone;
+                if (demoexit==true)
+                {
+                    QuitGame();
+                }
+                return;
+            }
+
+            ControlPanel( LastScan );
+
+            // set detail level
+            doublestep = 2 - DetailLevel;
+
+            inmenu = false;
+
+            if ( playstate == ex_titles )
+            {
+                return;
+            }
+
+            if ( playstate == ex_stillplaying )
+            {
+                SetupScreen( false );
+            }
+
+            if ( loadedgame == true )
+            {
+                goto fromloadedgame;
+            }
+
+            if (
+                ( playstate == ex_stillplaying ) &&
+                ( ( fizzlein == false ) ||
+                  ( GamePaused )
+                )
+            )
+            {
+                StartupClientControls();
+            }
+
+            if (
+                (playstate == ex_stillplaying) &&
+                (GamePaused == false) &&
+                (escaped == true)
+            )
+            {
+                MU_StartSong(song_level);
+                MU_RestoreSongPosition();
+            }
+        }
+
+        if ( BATTLEMODE )
+        {
+            if ( MSG.messageon == false )
+            {
+                CheckRemoteRidicule( LastScan );
+            }
+            if ( quitactive == false )
+            {
+                if ( ( LastScan == sc_Escape ) && ( canquit ) )
+                {
+                    quitactive = true;
+                    quittime   = GetTicCount() + QUITTIMEINTERVAL;
+
+                    if ( (consoleplayer == 0) || (networkgame == false) )
+                    {
+                        AddMessage( "Do you want to end this game? "
+                                    "(\\FY\\O/\\FN\\O)", MSG_QUIT );
+                    }
+                    else
+                    {
+                        AddMessage( "Do you want to exit to DOS? "
+                                    "(\\FY\\O/\\EN\\O)", MSG_QUIT );
+                    }
+                }
+            }
+            else
+            {
+                if ( GetTicCount() > quittime )
+                {
+                    quitactive = false;
+                }
+                else if ( LastScan == sc_N )
+                {
+                    DeletePriorityMessage( MSG_QUIT );
+                    quitactive = false;
+                }
+                else if ( LastScan == sc_Y )
+                {
+                    DeletePriorityMessage( MSG_QUIT );
+                    if ( (consoleplayer == 0) || (networkgame==false) )
+                    {
+                        AddEndGameCommand();
+                    }
+                    else
+                    {
+                        AddQuitCommand();
+                    }
+                }
+            }
+        }
+    }
+    waminot();
+}
+
+//******************************************************************************
+//
+// CheckRemoteRidicule ()
+//
+//******************************************************************************
+
+void CheckRemoteRidicule ( int scancode )
+{
+    int num=-1;
+
+    wami(4);
+    switch (scancode)
+    {
+    case sc_F1:
+        num=0;
+        break;
+    case sc_F2:
+        num=1;
+        break;
+    case sc_F3:
+        num=2;
+        break;
+    case sc_F4:
+        num=3;
+        break;
+    case sc_F5:
+        if ( !Keyboard[ sc_RShift ] )
+        {
+            num=4;
+        }
+        break;
+    case sc_F6:
+        num=5;
+        break;
+    case sc_F7:
+        if ( !Keyboard[ sc_RShift ] )
+        {
+            num=6;
+        }
+        break;
+    case sc_F8:
+        num=7;
+        break;
+    case sc_F9:
+        num=8;
+        break;
+    case sc_F10:
+        num=9;
+        break;
+    }
+    if (num>=0)
+    {
+        AddRemoteRidiculeCommand ( consoleplayer, MSG_DIRECTED_TO_ALL, num );
+        LastScan=0;
+    }
+    waminot();
+}
+
+//******************************************************************************
+//
+// DoBossKey ()
+//
+//******************************************************************************
+
+void DoBossKey ( void )
+{
+#ifdef DOS
+    union REGS regs;
+    ShutdownClientControls();
+
+    SetTextMode();
+
+    // move cursor to the row 0 column 4
+    regs.w.ax = 0x0200;
+    regs.w.bx = 0;
+    regs.w.dx = 0x0004;
+    int386(0x10,&regs,&regs);
+    px=0;
+    py=0;
+    UL_printf("C:\\>\n");
+
+    LastScan = 0;
+    IN_WaitForKey ();
+    VL_SetVGAPlaneMode();
+    VL_SetPalette(origpal);
+    SetBorderColor(0);
+    TurnShakeOff();
+    SetupScreen(true);
+    ThreeDRefresh();
+
+    StartupClientControls();
+#else
+    STUB_FUNCTION;
+#endif
+}
+
+
+//******************************************************************************
+//
+// PollKeyboard ()
+//
+//******************************************************************************
+
+void PollKeyboard
+(
+    void
+)
+
+{
+    static char autopressed = false;
+
+    wami(5);
+
+    if (demoplayback==true)
+    {
+        IN_UpdateKeyboard();
+    }
+
+    if ( !BATTLEMODE )
+    {
+        CheckDebug ();
+        if (
+            ( Keyboard[ sc_CapsLock ] ) &&
+            ( DebugOk )
+        )
+        {
+            DebugKeys ();
+        }
+    }
+
+    if ( locplayerstate->buttonstate[ bt_autorun ] )
+    {
+        if ( !autopressed )
+        {
+            autopressed = true;
+            gamestate.autorun ^= 1;
+            if ( gamestate.autorun == 0 )
+            {
+                AddMessage( "AutoRun is \\cOFF", MSG_SYSTEM );
+            }
+            else
+            {
+                AddMessage( "AutoRun is \\cON", MSG_SYSTEM );
+            }
+        }
+    }
+    else
+    {
+        autopressed = false;
+    }
+
+#if 0
+    if ( modemgame == false )
+    {
+        CheckDevelopmentKeys();
+    }
+#endif
+
+    if ( ( MSG.messageon == false ) && ( !quitactive ) )
+    {
+        if ( ( Keyboard[ buttonscan[ bt_message ] ] ) && ( BATTLEMODE ) )
+        {
+            // Send message to all
+            MSG.messageon = true;
+            MSG.directed  = false;
+            MSG.inmenu    = false;
+            MSG.remoteridicule = -1;
+            MSG.towho     = MSG_DIRECTED_TO_ALL;
+            MSG.textnum   = AddMessage( "_", MSG_MODEM );
+            MSG.length    = 1;
+            DeletePriorityMessage( MSG_MACRO );
+        }
+        else if ( ( Keyboard[ buttonscan[ bt_directmsg ] ] ) && ( BATTLEMODE ) )
+        {
+            // Send directed message
+            MSG.messageon = true;
+            MSG.directed  = true;
+            MSG.inmenu    = false;
+            MSG.remoteridicule = -1;
+            MSG.towho     = 0;
+            MSG.textnum   = AddMessage( "_", MSG_MODEM );
+            MSG.length    = 1;
+            DeletePriorityMessage( MSG_MACRO );
+        }
+        if ( buttonpoll[ bt_map ] )
+        {
+            if ( !BATTLEMODE )
+            {
+                // Automap
+                StopWind();
+                DoMap( player->tilex, player->tiley );
+            }
+            else
+            {
+                // Show kill counts
+                if ( SHOW_KILLS() )
+                {
+                    BATTLE_ShowKillCount = false;
+                    StatusBar &= ~STATUS_KILLS;
+                }
+                else
+                {
+                    StatusBar |= STATUS_KILLS;
+                    BATTLE_ShowKillCount = true;
+                }
+
+                SetupScreen( true );
+            }
+        }
+
+        // Shrink screen
+        if ( Keyboard[ sc_Minus ] )
+        {
+            Keyboard[ sc_Minus ] = false; // HDG debounce
+            if ( viewsize > 0 )
+            {
+                viewsize--;
+                SetupScreen( true );
+            }
+        }
+
+        // Expand screen
+        if ( Keyboard[ sc_Plus ] )
+        {
+            Keyboard[ sc_Plus ] = false; // HDG debounce
+            if ( viewsize < MAXVIEWSIZES - 1 )
+            {
+                viewsize++;
+                SetupScreen( true );
+            }
+        }
+
+        // Set detail
+        if ( ( Keyboard[ sc_F5 ] ) && ( ( !BATTLEMODE ) ||
+                                        ( Keyboard[ sc_RShift ] ) ) )
+        {
+            Keyboard[ sc_F5 ] = false;
+            LastScan = 0;
+            DetailLevel++;
+            if ( DetailLevel > 2 )
+            {
+                DetailLevel = 0;
+            }
+
+            switch( DetailLevel )
+            {
+            case 0 :
+                AddMessage( "Low detail", MSG_SYSTEM );
+                break;
+
+            case 1 :
+                AddMessage( "Medium detail", MSG_SYSTEM );
+                break;
+
+            case 2 :
+                AddMessage( "High detail", MSG_SYSTEM );
+                break;
+            }
+            doublestep = 2 - DetailLevel;
+        }
+
+        // Turn messages on/off
+
+        if ( ( Keyboard[ sc_F7 ] ) && ( ( !BATTLEMODE ) ||
+                                        ( Keyboard[ sc_RShift ] ) ) )
+        {
+            Keyboard[ sc_F7 ] = false;
+            LastScan = 0;
+            MessagesEnabled = !MessagesEnabled;
+            if ( !MessagesEnabled )
+            {
+                AddMessage( "Messages disabled.", MSG_MSGSYSTEM );
+            }
+            else
+            {
+                AddMessage( "Messages enabled.", MSG_MSGSYSTEM );
+            }
+        }
+
+        if ( ( Keyboard[ sc_F6 ] ) && ( !BATTLEMODE ) )
+        {
+            Keyboard[ sc_F6 ] = false;
+            if (Keyboard[sc_RShift])
+            {
+                ShutdownClientControls();
+                UndoQuickSaveGame();
+                StartupClientControls();
+            }
+            else if (quicksaveslot==-1)
+            {
+                ShutdownClientControls();
+                LastScan=sc_F2;
+                inmenu = true;
+                ControlPanel( LastScan );
+                StartupClientControls();
+            }
+            else
+            {
+                LastScan = 0;
+                ShutdownClientControls();
+                ThreeDRefresh();
+                QuickSaveGame();
+                StartupClientControls();
+            }
+        }
+
+//#if 0
+        if ( ( Keyboard[ sc_F12 ] ) && ( !BATTLEMODE ) )
+        {
+            Keyboard[ sc_F12 ] = false;
+            LastScan = 0;
+            DoBossKey();
+        }
+//#endif
+
+        // Gamma correction
+        if ( Keyboard[ sc_F11 ] )
+        {
+            char str[ 50 ] = "Gamma Correction Level ";
+            char str2[ 10 ];
+
+            gammaindex++;
+            if ( gammaindex == NUMGAMMALEVELS )
+            {
+                gammaindex = 0;
+            }
+            VL_SetPalette( origpal );
+            itoa( gammaindex, str2, 10 );
+            strcat( str, str2 );
+            AddMessage( str, MSG_SYSTEM );
+
+            while( Keyboard[ sc_F11 ] )
+            {
+                IN_UpdateKeyboard();
+            }
+        }
+#if 0
+        if ( Keyboard[ sc_M ] )
+        {
+            char str[ 50 ] = "Mouse Y-Rotation Input Scale ";
+            char str2[ 10 ];
+
+            if ( Keyboard[ sc_RShift ] )
+                mouse_ry_input_scale += 50;
+            else
+                mouse_ry_input_scale -= 50;
+
+            itoa(mouse_ry_input_scale,str2,10);
+            strcat( str, str2 );
+            AddMessage( str, MSG_SYSTEM );
+
+        }
+#endif
+        // Increase volume
+        if ( Keyboard[ sc_CloseBracket ] )
+        {
+            if ( Keyboard[ sc_RShift ] )
+            {
+                char str[ 50 ] = "Music Volume Level ";
+                char str2[ 10 ];
+
+                if ( MUvolume < 255 )
+                {
+                    MUvolume++;
+                }
+                MU_SetVolume( MUvolume );
+
+                itoa( MUvolume, str2, 10 );
+                strcat( str, str2 );
+                AddMessage( str, MSG_SYSTEM );
+            }
+            else
+            {
+                char str[ 50 ] = "Sound FX Volume Level ";
+                char str2[ 10 ];
+
+                if ( FXvolume < 255 )
+                {
+                    FXvolume++;
+                }
+                FX_SetVolume( FXvolume );
+
+                itoa( FXvolume, str2, 10 );
+                strcat( str, str2 );
+                AddMessage( str, MSG_SYSTEM );
+            }
+        }
+
+        // Decrease volume
+        if ( Keyboard[ sc_OpenBracket ] )
+        {
+            if ( Keyboard[ sc_RShift ] )
+            {
+                char str[ 50 ] = "Music Volume Level ";
+                char str2[ 10 ];
+
+                if ( MUvolume > 0 )
+                {
+                    MUvolume--;
+                }
+                MU_SetVolume( MUvolume );
+
+                itoa( MUvolume, str2, 10 );
+                strcat( str, str2 );
+                AddMessage( str, MSG_SYSTEM );
+            }
+            else
+            {
+                char str[ 50 ] = "Sound FX Volume Level ";
+                char str2[ 10 ];
+
+                if ( FXvolume > 0 )
+                {
+                    FXvolume--;
+                }
+                FX_SetVolume( FXvolume );
+
+                itoa( FXvolume, str2, 10 );
+                strcat( str, str2 );
+                AddMessage( str, MSG_SYSTEM );
+            }
+        }
+
+#if SAVE_SCREEN
+#if (DEVELOPMENT == 1)
+        if ( Keyboard[ sc_CapsLock ] && Keyboard[ sc_C ] )
+        {
+            SaveScreen( true );
+        }
+        else if ( Keyboard[ sc_CapsLock ] && Keyboard[ sc_X ] )
+        {
+            SaveScreen( false );
+        }
+#endif
+        else if ( Keyboard[ sc_Alt] && Keyboard[ sc_C ] )
+        {
+            SaveScreen( false );
+        }
+#ifdef DOS /* makes no sense under Linux as there are no lbm viewers there */
+        else if ( Keyboard[ sc_Alt] && Keyboard[ sc_V ] )
+        {
+            SaveScreen( true );
+        }
+#endif
+#endif
+    }
+#ifdef USE_SDL
+    /* SDL doesn't send proper release events for these */
+    if (Keystate[sc_CapsLock])
+    {
+        Keystate[sc_CapsLock]++;
+        if (Keystate[sc_CapsLock] == 3)
+            Keystate[sc_CapsLock] = 0;
+    }
+    if (Keystate[0x45]) /* numlock */
+    {
+        Keystate[0x45]++;
+        if (Keystate[0x45] == 3)
+            Keystate[0x45] = 0;
+    }
+#endif
+    waminot();
+}
+
+
+//******************************************************************************
+//
+// CheckDevelopmentKeys ()
+//
+//******************************************************************************
+#if 0
+void CheckDevelopmentKeys
+(
+    void
+)
+
+{
+#if (DEBUG == 1)
+    if ( Keyboard[ sc_CapsLock ] && Keyboard[ sc_T ] )
+    {
+        if ( warp == true )
+        {
+            player->x     = warpx;
+            player->y     = warpy;
+            player->angle = warpa;
+            locplayerstate->anglefrac = warpa << ANGLEBITS;
+            player->momentumx = 0;
+            player->momentumy = 0;
+            player->momentumz = 0;
+        }
+        return;
+    }
+#endif
+
+    // Lower wall height
+    if ( Keyboard[ sc_5 ] )
+    {
+        if ( levelheight > 1 )
+        {
+            levelheight--;
+        }
+
+        while( Keyboard[ sc_5 ] )
+        {
+            IN_UpdateKeyboard ();
+        }
+
+        maxheight = ( levelheight << 6 ) - 32;
+        nominalheight = maxheight - 32;
+    }
+
+    // Raise wall height
+    if ( Keyboard[ sc_6 ] )
+    {
+        levelheight++;
+
+        while( Keyboard[ sc_6 ] )
+        {
+            IN_UpdateKeyboard();
+        }
+
+        maxheight = ( levelheight << 6 ) - 32;
+        nominalheight = maxheight - 32;
+    }
+
+    if ( Keyboard[ sc_8 ] )
+    {
+        char str[ 50 ] = "You are now player ";
+        char str2[ 10 ];
+
+        locplayerstate->player++;
+        if ( locplayerstate->player == 5 )
+        {
+            locplayerstate->player = 0;
+        }
+
+        while( Keyboard[ sc_8 ] )
+        {
+            IN_UpdateKeyboard ();
+        }
+
+        itoa( locplayerstate->player, str2, 10 );
+        strcat( str, str2 );
+        AddMessage( str, MSG_SYSTEM );
+    }
+
+#if 0
+    // Cycle forward through wall textures
+    if (Keyboard[sc_W] && (modemgame==false))
+    {   int i,j;
+
+        for(i=0; i<128; i++)
+            for(j=0; j<128; j++)
+            {   if (IsWall(i,j))
+                {   if (tilemap[i][j] ==
+                            (W_GetNumForName("WALLSTOP")-W_GetNumForName("WALLSTRT")-1))
+                        tilemap[i][j] = 1;
+                    else
+                        tilemap[i][j] ++;
+                }
+            }
+        while(Keyboard[sc_W])
+            IN_UpdateKeyboard ();
+
+    }
+
+
+
+    if (Keyboard[sc_Q] && (modemgame==false))
+    {   int i,j;
+
+        for(i=0; i<128; i++)
+            for(j=0; j<128; j++)
+            {   if (IsWall(i,j))
+                {   if (tilemap[i][j] == 1)
+                        tilemap[i][j] = 74;
+                    else
+                        tilemap[i][j] --;
+                }
+            }
+        while(Keyboard[sc_Q])
+            IN_UpdateKeyboard ();
+
+    }
+
+#endif
+    // Step through cieling/skies
+    if ( Keyboard[ sc_K ] )
+    {
+        if ( sky > 0 )
+        {
+            MAPSPOT( 1, 0, 0 )++;
+            if ( MAPSPOT( 1, 0, 0 ) > 239 )
+            {
+                MAPSPOT( 1, 0, 0 ) = 234;
+            }
+        }
+        else
+        {
+            MAPSPOT( 1, 0, 0 )++;
+            if ( MAPSPOT( 1, 0, 0 ) > 198 + 15 )
+            {
+                MAPSPOT( 1, 0, 0 ) = 198;
+            }
+        }
+
+        SetPlaneViewSize();
+
+        while( Keyboard[ sc_K ] )
+        {
+            IN_UpdateKeyboard();
+        }
+    }
+
+    // Step through floors
+    if ( Keyboard[ sc_L ] )
+    {
+        MAPSPOT( 0, 0, 0 )++;
+        if ( MAPSPOT( 0, 0, 0 ) > 180 + 15 )
+        {
+            MAPSPOT( 0, 0, 0 ) = 180;
+            SetPlaneViewSize();
+
+            while( Keyboard[ sc_L ] )
+            {
+                IN_UpdateKeyboard();
+            }
+        }
+    }
+
+    // Increase darkness level
+    if ( Keyboard[ sc_M ] )
+    {
+        if ( darknesslevel < 7 )
+        {
+            darknesslevel++;
+        }
+
+        SetLightLevels( darknesslevel );
+
+        while( Keyboard[ sc_M ] )
+        {
+            IN_UpdateKeyboard();
+        }
+    }
+
+    // Decrease darkness level
+    if ( Keyboard[ sc_N ] )
+    {
+        if ( darknesslevel > 0 )
+        {
+            darknesslevel--;
+        }
+
+        SetLightLevels( darknesslevel );
+
+        while( Keyboard[ sc_N ] )
+        {
+            IN_UpdateKeyboard();
+        }
+    }
+
+    // Increase light rate
+    if ( Keyboard[ sc_B ] )
+    {
+        SetLightRate( GetLightRate() + 1 );
+        myprintf( "normalshade = %ld\n", normalshade );
+
+        while( Keyboard[ sc_B ] )
+        {
+            IN_UpdateKeyboard();
+        }
+    }
+
+    // Decrease light rate
+    if ( Keyboard[ sc_V ] )
+    {
+        SetLightRate( GetLightRate() - 1 );
+        myprintf( "normalshade = %ld\n", normalshade );
+
+        while( Keyboard[ sc_V ] )
+        {
+            IN_UpdateKeyboard();
+        }
+    }
+
+    // Toggle light diminishing on/off
+    if ( Keyboard[ sc_T ] )
+    {
+        fulllight ^= 1;
+
+        while( Keyboard[ sc_T ] )
+        {
+            IN_UpdateKeyboard();
+        }
+    }
+}
+#endif
+
+
+#if SAVE_SCREEN
+
+
+short   BigShort (short l)
+{
+    byte    b1,b2;
+
+    b1 = l&255;
+    b2 = (l>>8)&255;
+
+    return (b1<<8) + b2;
+}
+
+long    BigLong (long l)
+{
+    byte    b1,b2,b3,b4;
+
+    b1 = l&255;
+    b2 = (l>>8)&255;
+    b3 = (l>>16)&255;
+    b4 = (l>>24)&255;
+
+    return ((long)b1<<24) + ((long)b2<<16) + ((long)b3<<8) + b4;
+}
+
+/*
+==============
+=
+= WriteLBMfile
+=
+==============
+*/
+
+void WriteLBMfile (char *filename, byte *data, int width, int height)
+{
+    byte    *lbm, *lbmptr;
+    long    *formlength, *bmhdlength, *cmaplength, *bodylength;
+    long    length;
+    bmhd_t  basebmhd;
+    int     handle;
+    int     i;
+
+    lbm = lbmptr = (byte *) SafeMalloc ((iGLOBAL_SCREENWIDTH*iGLOBAL_SCREENHEIGHT)+4000);
+
+//
+// start FORM
+//
+    *lbmptr++ = 'F';
+    *lbmptr++ = 'O';
+    *lbmptr++ = 'R';
+    *lbmptr++ = 'M';
+
+    formlength = (long*)lbmptr;
+    lbmptr+=4;                      // leave space for length
+
+    *lbmptr++ = 'P';
+    *lbmptr++ = 'B';
+    *lbmptr++ = 'M';
+    *lbmptr++ = ' ';
+
+//
+// write BMHD
+//
+    *lbmptr++ = 'B';
+    *lbmptr++ = 'M';
+    *lbmptr++ = 'H';
+    *lbmptr++ = 'D';
+
+    bmhdlength = (long *)lbmptr;
+    lbmptr+=4;                      // leave space for length
+
+    memset (&basebmhd,0,sizeof(basebmhd));
+    basebmhd.w = BigShort(width);
+    basebmhd.h = BigShort(height);
+    basebmhd.nPlanes = BigShort(8);
+    basebmhd.xAspect = BigShort(5);
+    basebmhd.yAspect = BigShort(6);
+    basebmhd.pageWidth = BigShort(width);
+    basebmhd.pageHeight = BigShort(height);
+
+    memcpy (lbmptr,&basebmhd,sizeof(basebmhd));
+    lbmptr += sizeof(basebmhd);
+
+    length = lbmptr-(byte *)bmhdlength-4;
+    *bmhdlength = BigLong(length);
+    if (length&1)
+        *lbmptr++ = 0;          // pad chunk to even offset
+
+//
+// write CMAP
+//
+    *lbmptr++ = 'C';
+    *lbmptr++ = 'M';
+    *lbmptr++ = 'A';
+    *lbmptr++ = 'P';
+
+    cmaplength = (long *)lbmptr;
+    lbmptr+=4;                      // leave space for length
+
+    for (i = 0; i < 0x300; i++)
+        *lbmptr++ = (*(origpal+i))<<2;
+
+// memcpy (lbmptr,&origpal[0],768);
+// lbmptr += 768;
+
+    length = lbmptr-(byte *)cmaplength-4;
+    *cmaplength = BigLong(length);
+    if (length&1)
+        *lbmptr++ = 0;          // pad chunk to even offset
+
+//
+// write BODY
+//
+    *lbmptr++ = 'B';
+    *lbmptr++ = 'O';
+    *lbmptr++ = 'D';
+    *lbmptr++ = 'Y';
+
+    bodylength = (long *)lbmptr;
+    lbmptr+=4;                      // leave space for length
+
+    memcpy (lbmptr,data,width*height);
+    lbmptr += width*height;
+
+    length = lbmptr-(byte *)bodylength-4;
+    *bodylength = BigLong(length);
+    if (length&1)
+        *lbmptr++ = 0;          // pad chunk to even offset
+
+//
+// done
+//
+    length = lbmptr-(byte *)formlength-4;
+    *formlength = BigLong(length);
+    if (length&1)
+        *lbmptr++ = 0;          // pad chunk to even offset
+
+//
+// write output file
+//
+    handle = SafeOpenWrite (filename);
+
+    SafeWrite (handle, lbm, lbmptr-lbm);
+
+    close (handle);
+    SafeFree(lbm);
+}
+
+
+//****************************************************************************
+//
+// GetFileName ()
+//
+//****************************************************************************
+
+void GetFileName (boolean saveLBM)
+{
+#ifdef DOS
+    char num[4];
+    int cnt = 0;
+    struct find_t fblock;
+
+    if (saveLBM)
+        memcpy (savename, "ROTT0000.LBM\0", 13);
+    else
+        memcpy (savename, "ROTT0000.PCX\0", 13);
+
+    if (_dos_findfirst (savename, 0, &fblock) != 0)
+        return;
+
+    do
+    {
+        cnt++;
+        memset (&num[0], 0, 4);
+        itoa (cnt, num, 10);
+
+        if (cnt > 99)
+        {
+            savename[5] = num[0];
+            savename[6] = num[1];
+            savename[7] = num[2];
+        }
+        else if (cnt > 9)
+        {
+            savename[6] = num[0];
+            savename[7] = num[1];
+        }
+        else
+            savename[7] = num[0];
+    }
+    while (_dos_findfirst (savename, 0, &fblock) == 0);
+#else
+    int i;
+
+    for (i = 0; i < 9999; i++) {
+        char filename[128];
+
+        if (saveLBM) {
+            sprintf(savename, "rott%04d.lbm", i);
+        } else {
+            sprintf(savename, "rott%04d.pcx", i);
+        }
+
+        GetPathFromEnvironment( filename, ApogeePath, savename );
+
+        if (access(filename, F_OK) != 0) {
+            return;
+        }
+    }
+#endif
+}
+
+//****************************************************************************
+//
+// SaveScreen ()
+//
+//****************************************************************************
+
+boolean inhmenu;
+
+#if (BETA == 1)
+#define SSX (160-(46*2))
+#define SSY (17)
+#endif
+void SaveScreen (boolean saveLBM)
+{
+    byte *buffer;
+    byte * screen;
+    boolean oldHUD;
+    char filename[ 128 ];
+
+#if (BETA == 1)
+    unsigned tmp;
+    char buf[30];
+    int i;
+#endif
+
+
+    oldHUD=HUD;
+    HUD=false;
+    doublestep=0;
+    if (inhmenu==false)
+        screen = (byte *) bufferofs;
+    else
+        screen = (byte *) displayofs;
+
+    if (inhmenu==false)
+        ThreeDRefresh ();
+    doublestep = 2 - DetailLevel;
+
+    //buffer = (byte *) SafeMalloc (65000);
+    buffer = (byte *) SafeMalloc ((iGLOBAL_SCREENHEIGHT*iGLOBAL_SCREENWIDTH)+4000);
+
+#if (BETA == 1)
+    if (SCREENSHOTS == false)
+    {
+        if (screen!=(byte *)bufferofs)
+        {
+            tmp=bufferofs;
+            bufferofs=displayofs;
+        }
+        CurrentFont=tinyfont;
+
+        VGAMAPMASK(15);
+        for (i=-1; i<6; i++)
+            memset((byte *)bufferofs+(ylookup[i+SSY])+(SSX>>2),0,46);
+        px=SSX;
+        py=SSY;
+        VW_DrawPropString(" Rise of the Triad (c) 1995 Apogee  Version ");
+        VW_DrawPropString(itoa(ROTTMAJORVERSION,&buf[0],10));
+        VW_DrawPropString(".");
+        VW_DrawPropString(itoa(ROTTMINORVERSION,&buf[0],10));
+        px=SSX+13;
+        py=SSY+8;
+        VW_DrawPropString(" Episode ");
+        VW_DrawPropString(itoa(gamestate.episode,&buf[0],10));
+        VW_DrawPropString(" Area ");
+        VW_DrawPropString(itoa(GetLevel(gamestate.episode, gamestate.mapon),&buf[0],10));
+
+        if (screen!=(byte *)bufferofs)
+            bufferofs=tmp;
+    }
+#endif
+
+
+
+    GetFileName (saveLBM);
+    GetPathFromEnvironment( filename, ApogeePath, savename );
+    //
+    memcpy(buffer,screen, iGLOBAL_SCREENWIDTH*iGLOBAL_SCREENHEIGHT); //bna
+    //bna--VL_CopyPlanarPageToMemory(screen,buffer);
+
+    if (saveLBM)
+    {
+        WriteLBMfile (filename, buffer, iGLOBAL_SCREENWIDTH, iGLOBAL_SCREENHEIGHT);
+#if (DEVELOPMENT == 1)
+        while (Keyboard[sc_CapsLock] && Keyboard[sc_C])
+#else
+        while (Keyboard[sc_Alt] && Keyboard[sc_V])
+#endif
+            IN_UpdateKeyboard ();
+    }
+    else
+    {
+        WritePCX (filename, buffer);
+#if (DEVELOPMENT == 1)
+        while (Keyboard[sc_CapsLock] && Keyboard[sc_X])
+#else
+        while (Keyboard[sc_Alt] && Keyboard[sc_C])
+#endif
+            IN_UpdateKeyboard ();
+    }
+
+    SafeFree(buffer);
+    HUD=oldHUD;
+}
+
+//****************************************************************************
+//
+// WritePCX ()
+//
+//****************************************************************************
+
+void WritePCX (char * file, byte * source)
+{
+    PCX_HEADER pcxHDR;
+    byte *tempbuffer;
+    byte pal[0x300];
+    int pcxhandle;
+    int i, j, y;
+    unsigned char c;
+    unsigned char buffer1[GAP_SIZE];
+
+    pcxhandle = SafeOpenWrite (file);
+
+    /* --- init the header that we'll write.
+     *    Note: since DPaint never reads & writes at the same time,
+     *    it is okay to share the same read & write structure,
+     *    unlike in CONVERT.EXE.
+     */
+
+    memset (&pcxHDR, 0, sizeof(PCX_HEADER));
+
+    pcxHDR.manufacturer  = 10;
+    pcxHDR.version       = 5;
+    pcxHDR.encoding      = 1;
+
+    pcxHDR.bitsperpixel  = 8;           //bpp;
+    pcxHDR.xmin          = pcxHDR.ymin = 0;
+    pcxHDR.xmax          = iGLOBAL_SCREENWIDTH - 1;
+    pcxHDR.ymax          = iGLOBAL_SCREENHEIGHT - 1;
+    pcxHDR.hres          = iGLOBAL_SCREENWIDTH;         //N_COLUMNS;
+    pcxHDR.vres          = iGLOBAL_SCREENHEIGHT;         //N_LINES;
+
+    // bytesperline doesn't take into account multiple planes.
+    // Output in same format as bitmap (planar vs packed).
+    //
+    pcxHDR.bytesperline  = iGLOBAL_SCREENWIDTH;         //bitmap->width;
+
+    pcxHDR.nplanes       = 1;           //bitmap->planes;
+    pcxHDR.reserved      = 0;
+
+    // First 16 colors of our palette info.
+    for (i = 0, j = 0; i < 16; ++i, j += 3) {
+        pcxHDR.colormap[i][0] = (unsigned char)(origpal[j]);
+        pcxHDR.colormap[i][1] = (unsigned char)(origpal[j]+2);
+        pcxHDR.colormap[i][2] = (unsigned char)(origpal[j]+3);
+    }
+
+    //
+    // Write the 128-byte header
+    //
+    SafeWrite(pcxhandle,&pcxHDR, sizeof (PCX_HEADER));
+
+    memset (buffer1, 0, GAP_SIZE);
+
+    SafeWrite (pcxhandle, &buffer1, GAP_SIZE);
+
+    tempbuffer = (byte *) SafeMalloc ((iGLOBAL_SCREENHEIGHT*iGLOBAL_SCREENWIDTH)+4000);
+    bptr = tempbuffer;
+    totalbytes = 0;
+
+    //
+    // Write to a bit-packed file.
+    //
+    for (y = 0;  y < iGLOBAL_SCREENHEIGHT;  ++y) 		// for each line in band
+        if (PutBytes (((unsigned char *) (source+(y*iGLOBAL_SCREENWIDTH))),
+                      pcxHDR.bytesperline))
+            Error ("Error writing PCX bit-packed line!\n");
+
+    SafeWrite (pcxhandle, tempbuffer, totalbytes);
+
+    //
+    // Write out PCX palette
+    //
+    c = 0x0C;
+
+    for (i = 0; i < 0x300; i++)
+        pal[i] = (*(origpal+i))<<2;
+
+    SafeWrite (pcxhandle, &c, 1);
+    SafeWrite (pcxhandle, &pal[0], 768);
+
+    close (pcxhandle);
+    SafeFree (tempbuffer);
+}
+
+
+//****************************************************************************
+//
+// PutBytes ()
+//
+// Write bytes to a file, handling packing as it goes.
+// Returns :  0 == SUCCESS
+//            1 == FAIL.
+//
+//****************************************************************************
+
+int PutBytes (unsigned char *ptr, unsigned int bytes)
+{
+    unsigned int startbyte, count;
+    char b;
+
+    while (bytes > 0) {
+        // check for a repeating byte value
+        startbyte = *ptr;
+        *ptr++ = 0;
+        --bytes;
+        count = 1;
+        while (*ptr == startbyte && bytes > 0 && count < 63)
+        {
+            *ptr = 0;
+            ++ptr;
+            --bytes;
+            ++count;
+        }
+        // If we can pack the sequence, or if we have to add a
+        //	byte before it because the top 2 bits of the value
+        //	are 1's, write a packed sequence of 2 bytes.
+        //	Otherwise, just write the byte value.
+        //
+        if (count > 1  ||  (startbyte & 0xc0) == 0xc0)
+        {
+            b = 0xc0 | count;
+
+            *bptr++ = b;
+            totalbytes++;
+        }
+        b = startbyte;
+
+        *bptr++ = b;
+        totalbytes++;
+    }
+    return (0);
+}
+
+
+#endif
+
+
+//****************************************************************************
+//
+// PlayCinematic () - Play intro cinematics
+//
+//****************************************************************************
+
+void PlayCinematic (void)
+{
+
+    if ((tedlevel == true) || (turbo == true))
+        return;
+
+    switch (gamestate.mapon)
+    {
+#if (SHAREWARE == 0)
+        byte pal[768];
+    case 0:        // Start of EPISODE 1
+
+        MU_StartSong ( song_cinematic1 );
+        VL_FadeOut (0, 255, 0, 0, 0, 20);
+        VL_ClearBuffer (bufferofs, 0);
+        DrawNormalSprite(0,30,W_GetNumForName("nicolas"));
+        DrawNormalSprite(0,168,W_GetNumForName("oneyear"));
+        FlipPage();
+        memcpy(&pal[0],W_CacheLumpName("nicpal",PU_CACHE, CvtNull, 1),768);
+        VL_NormalizePalette(&pal[0]);
+        VL_FadeIn(0,255,pal,20);
+        I_Delay (60);
+        VL_FadeOut (0, 255, 0, 0, 0, 20);
+        IN_UpdateKeyboard();
+        if (LastScan!=0)
+        {
+            LastScan=0;
+            return;
+        }
+        SD_PlayPitchedSound(SD_LIGHTNINGSND,255,-1500);
+        DoInBetweenCinematic (20, W_GetNumForName("binoculr"), 80,
+                              "The HUNT cases an\n"
+                              "ancient monastery."
+                             );
+        IN_UpdateKeyboard();
+        if (LastScan!=0)
+        {
+            LastScan=0;
+            return;
+        }
+        SD_Play(SD_NMESEESND);
+        DoInBetweenCinematic (20, W_GetNumForName("binosee"), 80,
+                              "\"There they are,\" says\n"
+                              "Cassatt. \"Let's get back\n"
+                              "to the boat and inform HQ.\""
+                             );
+        IN_UpdateKeyboard();
+        if (LastScan!=0)
+        {
+            LastScan=0;
+            return;
+        }
+        SD_Play(SD_HIGHGUARD1SEESND);
+        DoInBetweenCinematic (20, W_GetNumForName("boatgard"), 80,
+                              "\"The intruders, on that hill!\""
+                             );
+        IN_UpdateKeyboard();
+        if (LastScan!=0)
+        {
+            LastScan=0;
+            return;
+        }
+        SD_Play(SD_EXPLODESND);
+        DoInBetweenCinematic (20, W_GetNumForName("boatblow"), 80,
+                              "\"There goes our ride home,\"\n"
+                              "says Barrett.  \"Looks like\n"
+                              "the only way out is in....\""
+                             );
+        IN_UpdateKeyboard();
+        LastScan=0;
+        break;
+
+    case 8:        // Start of EPISODE 2
+        MU_StartSong ( song_cinematic2 );
+        DoInBetweenCinematic (0, W_GetNumForName("epi12"), 1200,
+                              "The HUNT makes their way\n"
+                              "into the main keep."
+                             );
+        IN_UpdateKeyboard();
+        LastScan=0;
+        break;
+
+    case 16:       // Start of EPISODE 3
+        MU_StartSong ( song_cinematic1 );
+        DoInBetweenCinematic (20, W_GetNumForName("epi23"), 1200,
+                              "The HUNT stands before a pair\n"
+                              "of ominous wooden doors.\n"
+                              "The sounds of machinery and\n"
+                              "servomotors fill the air.\n"
+                             );
+        IN_UpdateKeyboard();
+        LastScan=0;
+        break;
+
+    case 24:       // Start of EPISODE 4
+        MU_StartSong ( song_cinematic2 );
+        DoInBetweenCinematic (0, W_GetNumForName("epi34"), 1200,
+                              "Stairs lead down beneath the\n"
+                              "keep.  From behind the doors\n"
+                              "come the moans of the undead."
+                             );
+        IN_UpdateKeyboard();
+        LastScan=0;
+        break;
+#endif
+    }
+}
--- /dev/null
+++ b/rott/rt_main.h
@@ -1,0 +1,178 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+//***************************************************************************
+//
+//                  RT_MAIN.H
+//
+//***************************************************************************
+
+#ifndef _rt_main_public
+#define _rt_main_public
+
+#include "develop.h"
+#include "rt_def.h"
+#include "rottnet.h"
+#include "rt_battl.h"
+
+#if (SHAREWARE==0)
+#define  STANDARDGAMELEVELS   (DATADIR "DARKWAR.RTL")
+#define  STANDARDBATTLELEVELS (DATADIR "DARKWAR.RTC")
+#define  SUPERROTTBATTLELEVELS (DATADIR "ROTTCD.RTC")
+#define  SITELICENSEBATTLELEVELS (DATADIR "ROTTSITE.RTC")
+#else
+#define  STANDARDGAMELEVELS   (DATADIR "HUNTBGIN.RTL")
+#define  STANDARDBATTLELEVELS (DATADIR "HUNTBGIN.RTC")
+#endif
+
+enum
+{   vl_low,
+    vl_medium,
+    vl_high,
+    vl_excessive
+};
+
+// Enum for each version of the game
+typedef enum
+{
+    ROTT_SHAREWARE,
+    ROTT_REGISTERED,
+    ROTT_SUPERCD,
+    ROTT_SITELICENSE
+} version_type;
+
+typedef struct
+{
+    int GodModeTime;
+    int DogModeTime;
+    int ShroomsModeTime;
+    int ElastoModeTime;
+    int AsbestosVestTime;
+    int BulletProofVestTime;
+    int GasMaskTime;
+    int MercuryModeTime;
+
+    int GodModeRespawnTime;
+    int DogModeRespawnTime;
+    int ShroomsModeRespawnTime;
+    int ElastoModeRespawnTime;
+    int AsbestosVestRespawnTime;
+    int BulletProofVestRespawnTime;
+    int GasMaskRespawnTime;
+    int MercuryModeRespawnTime;
+
+} specials;
+
+
+typedef struct
+{
+    unsigned Version;
+    // Variable for which version of the game can be played
+    version_type Product;
+
+    int     TimeCount;
+    int     frame;
+    int     secrettotal,treasuretotal,killtotal;
+    int     secretcount,treasurecount,killcount;
+    int     supertotal,healthtotal,missiletotal;
+    int     supercount,healthcount,missilecount;
+    int     democratictotal,planttotal;
+    int     democraticcount,plantcount;
+    int     dipballs;
+    int     difficulty;
+    int     violence;
+    int     mapon;
+    int     score;
+    int     episode;
+    int     battlemode;
+    int     battleoption;
+    int     randomseed;
+    boolean teamplay;
+    boolean DODEMOCRATICBONUS1;
+    boolean DOGROUNDZEROBONUS;
+    int     autorun;
+
+    // Battle Options
+    battle_type BattleOptions;
+
+    boolean SpawnCollectItems;
+    boolean SpawnEluder;
+    boolean SpawnDeluder;
+    boolean ShowScores;
+    boolean PlayerHasGun[ MAXPLAYERS ];
+    specials SpecialsTimes;
+    
+} gametype;
+
+
+extern  int      doublestep;
+extern  boolean  tedlevel;
+extern  int      tedlevelnum;
+extern  int      tedx;
+extern  int      tedy;
+extern  boolean  fizzlein;
+extern  int      pheight;
+extern  int      NoSound;
+extern  int      timelimit;
+extern  boolean  timelimitenabled;
+extern  boolean  noecho;
+extern  boolean  demoexit;
+extern  boolean  quiet;
+
+extern gametype  gamestate;
+extern boolean DebugOk;
+extern  boolean newlevel;
+
+void QuitGame( void );
+void PlayCinematic (void);
+void InitCharacter(void);
+void ShutDown ( void );
+void UpdateGameObjects ( void );
+
+#if (WHEREAMI==1)
+extern int programlocation;
+#endif
+
+extern  int polltime;
+extern  int oldpolltime;
+extern  volatile int oldtime;
+void PauseLoop ( void );
+#if SAVE_SCREEN
+extern boolean inhmenu;
+void SaveScreen (boolean saveLBM);
+#endif
+void SetupWads( void );
+
+extern boolean SCREENSHOTS;
+extern boolean MEMORYTEST;
+extern boolean MODEMTEST;
+extern boolean STATICMEMORYTEST;
+extern boolean STATICMEMORYPREVIEWTEST;
+extern boolean COMPUTELEVELSIZE;
+extern boolean MONOPRESENT;
+extern boolean MAPSTATS;
+extern boolean TILESTATS;
+extern boolean HUD;
+#ifdef DOS
+extern boolean SOUNDSETUP;
+#endif
+
+extern char CWD[40];
+
+#endif
--- /dev/null
+++ b/rott/rt_map.c
@@ -1,0 +1,1075 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+#include "rt_def.h"
+#include <string.h>
+
+#ifdef DOS
+#include <conio.h>
+#include <dos.h>
+#endif
+
+#include "sprites.h"
+#include "rt_map.h"
+#include "rt_dr_a.h"
+#include "_rt_map.h"
+#include "isr.h"
+#include "rt_util.h"
+#include "modexlib.h"
+#include "rt_draw.h"
+#include "rt_stat.h"
+#include "z_zone.h"
+#include "w_wad.h"
+#include "rt_main.h"
+#include "rt_playr.h"
+#include "lumpy.h"
+#include "rt_door.h"
+#include "rt_scale.h"
+#include "rt_vid.h"
+#include "rt_in.h"
+#include "rt_ted.h"
+#include "rt_game.h"
+#include "rt_rand.h"
+#include "rt_view.h"
+#include "rt_floor.h"
+#include "engine.h"
+#include "develop.h"
+#include "rt_spbal.h"
+#include "rt_menu.h"
+#include "rt_net.h"
+#include "rt_str.h"
+#include "watcom.h"
+//MED
+#include "memcheck.h"
+
+//===========================================================================
+
+
+static int tilesize;
+static fixed xscale;
+static fixed yscale;
+static int mapscale=2;
+static int oldw,oldh;
+static byte * skytile;
+static int mapcolor=8;
+
+typedef struct PType {
+    int   x;
+    int   y;
+} Ptype;
+
+static Ptype arrows[8][7]=
+{
+    { {4,2}, {2,4}, {2,3}, {0,3}, {0,1}, {2,1}, {2,0} },
+    { {4,0}, {4,3}, {3,2}, {1,4}, {0,3}, {2,1}, {1,0} },
+    { {2,0}, {4,2}, {3,2}, {3,4}, {1,4}, {1,2}, {0,2} },
+    { {0,0}, {3,0}, {2,1}, {4,3}, {3,4}, {1,2}, {0,3} },
+    { {0,2}, {2,0}, {2,1}, {4,1}, {4,3}, {2,3}, {2,4} },
+    { {0,4}, {0,1}, {1,2}, {3,0}, {4,1}, {2,3}, {3,4} },
+    { {2,4}, {0,2}, {1,2}, {1,0}, {3,0}, {3,2}, {4,2} },
+    { {4,4}, {1,4}, {2,3}, {0,1}, {1,0}, {3,2}, {4,1} },
+};
+
+void DrawMap_MaskedShape (int x, int y, int lump, int type);
+
+void CheatMap( void )
+{
+    int i;
+    int j;
+    statobj_t * temp;
+    objtype * a;
+
+    for(temp=FIRSTSTAT; temp; temp=temp->statnext)
+        temp->flags|=FL_SEEN;
+
+    for(a=FIRSTACTOR; a; a=a->next)
+        a->flags|=FL_SEEN;
+
+
+    for (j=0; j<MAPSIZE; j++)
+        for (i=0; i<MAPSIZE; i++)
+            mapseen[i][j]=1;
+}
+
+
+void FixMapSeen( void )
+{
+    int i;
+    int j;
+
+    for (j=0; j<MAPSIZE; j++)
+        for (i=0; i<MAPSIZE; i++)
+            if (!mapseen[i][j])
+            {
+                if (i==0 && ((mapseen[i][j+1] && j<MAPSIZE-1) || (mapseen[i][j-1] && j>0)) && mapseen[i+1][j])
+                    mapseen[i][j]=1;
+                else if (i==MAPSIZE-1 && mapseen[i-1][j] && ((mapseen[i][j+1] && j<MAPSIZE-1) || (mapseen[i][j-1] && j>0)))
+                    mapseen[i][j]=1;
+                else if (j==0 && ((mapseen[i+1][j] && i<MAPSIZE-1) || (mapseen[i-1][j] && i>0)) && mapseen[i][j+1])
+                    mapseen[i][j]=1;
+                else if (j==MAPSIZE-1 && mapseen[i][j-1] && ((mapseen[i+1][j] && i<MAPSIZE-1) || (mapseen[i-1][j] && i>0)))
+                    mapseen[i][j]=1;
+                else if (
+                    (  ((mapseen[i-1][j]) && (mapseen[i][j+1]) && (!(tilemap[i-1][j+1])))
+                       ||
+                       ((mapseen[i-1][j]) && (mapseen[i][j-1]) && (!(tilemap[i-1][j-1])))
+                       ||
+                       ((mapseen[i+1][j]) && (mapseen[i][j+1]) && (!(tilemap[i+1][j+1])))
+                       ||
+                       ((mapseen[i+1][j]) && (mapseen[i][j-1]) && (!(tilemap[i+1][j-1])))
+                    ) &&
+                    tilemap[i][j])
+                    mapseen[i][j]=1;
+            }
+}
+
+
+/*
+=======================
+=
+= DrawMap_Wall
+=
+=======================
+*/
+
+void DrawMap_Wall (int x, int y, int tile)
+{
+    byte * buf;
+    int p;
+    byte * b;
+    byte * source;
+    byte * s;
+    int i;
+
+    x*=tilesize;
+    y*=tilesize;
+
+#ifdef DOS
+    buf=(byte *)bufferofs+ylookup[y]+(x>>2);
+#else
+    buf=(byte *)bufferofs+ylookup[y]+x;
+#endif
+
+    source=W_CacheLumpNum(tile,PU_CACHE, CvtNull, 1);
+
+#ifdef DOS
+    for (p=0; p<4; p++)
+#endif
+    {
+#ifdef DOS
+        VGAWRITEMAP(p);
+        s=source+((p*hp_srcstep)>>10);
+#else
+        s=source;
+#endif
+        b=buf;
+
+#ifdef DOS
+        for (i=p; i<tilesize; i+=4,b++)
+#else
+        for (i=0; i<tilesize; i++,b++)
+#endif
+        {
+            DrawMapPost(tilesize,s,b);
+#ifdef DOS
+            s+=(hp_srcstep>>8);
+#else
+            s+=(hp_srcstep>>10);
+#endif
+        }
+    }
+}
+
+/*
+=======================
+=
+= DrawMap_AnimatedWall
+=
+=======================
+*/
+
+void DrawMap_AnimatedWall (int x, int y, int tile)
+{
+    DrawMap_Wall(x,y,animwalls[tile].texture);
+}
+
+/*
+=======================
+=
+= DrawMap_SkyTile
+=
+=======================
+*/
+
+void DrawMap_SkyTile (int x, int y)
+{
+    byte * buf;
+    int p;
+    byte * b;
+    byte * s;
+    int i;
+
+    x*=tilesize;
+    y*=tilesize;
+
+#ifdef DOS
+    buf=(byte *)bufferofs+ylookup[y]+(x>>2);
+#else
+    buf=(byte *)bufferofs+ylookup[y]+x;
+#endif
+
+#ifdef DOS
+    for (p=0; p<4; p++)
+#endif
+    {
+#ifdef DOS
+        VGAWRITEMAP(p);
+        s=skytile+((p*hp_srcstep)>>10);
+#else
+        s=skytile;
+#endif
+
+        b=buf;
+#ifdef DOS
+        for (i=p; i<tilesize; i+=4,b++)
+#else
+        for (i=0; i<tilesize; i++,b++)
+#endif
+        {
+            DrawMapPost(tilesize,s,b);
+#ifdef DOS
+            s+=(hp_srcstep>>8);
+#else
+            s+=(hp_srcstep>>10);
+#endif
+        }
+    }
+}
+
+/*
+=======================
+=
+= DrawMap_MaskedWall
+=
+=======================
+*/
+
+void DrawMap_MaskedWall (int x, int y, int tile)
+{
+    if (IsPlatform(maskobjlist[tile]->tilex,maskobjlist[tile]->tiley))
+    {
+        if (!(maskobjlist[tile]->flags&MW_ABOVEPASSABLE))
+            DrawMap_MaskedShape(x,y,maskobjlist[tile]->toptexture,0);
+        else if (!(maskobjlist[tile]->flags&MW_BOTTOMPASSABLE))
+            DrawMap_MaskedShape(x,y,maskobjlist[tile]->bottomtexture,1);
+        else
+            DrawMap_MaskedShape(x,y,maskobjlist[tile]->midtexture,0);
+    }
+    else
+    {
+        DrawMap_MaskedShape(x,y,maskobjlist[tile]->bottomtexture,1);
+    }
+}
+
+/*
+=======================
+=
+= DrawMap_Door
+=
+=======================
+*/
+
+void DrawMap_Door (int x, int y, int tile)
+{
+    if (
+        (doorobjlist[tile]->lock > 0) &&
+        (doorobjlist[tile]->lock <= 4)
+    )
+        DrawMap_Wall(x,y,W_GetNumForName("lock1")+doorobjlist[tile]->lock-1);
+    else if (doorobjlist[tile]->texture==doorobjlist[tile]->basetexture)
+        DrawMap_Wall(x,y,doorobjlist[tile]->texture);
+    else
+        DrawMap_MaskedShape(x,y,doorobjlist[tile]->texture,0);
+}
+
+/*
+=======================
+=
+= DrawMap_PushWall
+=
+=======================
+*/
+
+void DrawMap_PushWall (int x, int y, pwallobj_t * pw)
+{
+    if (pw->texture&0x1000)
+        DrawMap_AnimatedWall(x,y,pw->texture&0x3ff);
+    else
+        DrawMap_Wall(x,y,pw->texture&0x3ff);
+}
+
+/*
+=======================
+=
+= DrawMap_Actor
+=
+=======================
+*/
+
+void DrawMap_Actor (int x, int y, objtype * a)
+{
+    int translucent;
+
+    if (!(a->flags&FL_SEEN))
+        return;
+
+    translucent=0;
+    if (a->flags&FL_TRANSLUCENT)
+        translucent=1;
+    DrawMap_MaskedShape(x,y,a->shapenum+shapestart,translucent);
+}
+
+/*
+=======================
+=
+= DrawMap_Sprite
+=
+=======================
+*/
+
+void DrawMap_Sprite (int x, int y, statobj_t * s)
+{
+    int translucent;
+
+    if (!(s->flags&FL_SEEN))
+        return;
+
+    translucent=0;
+    if (s->flags&FL_TRANSLUCENT)
+        translucent=1;
+    DrawMap_MaskedShape(x,y,s->shapenum+shapestart,translucent);
+}
+
+/*
+=======================
+=
+= DrawMap_MaskedShape
+=
+=======================
+*/
+
+void DrawMap_MaskedShape (int x, int y, int lump, int type)
+{
+
+    // Calculate center coordinates for sprites
+
+    x*=tilesize;
+    y*=tilesize;
+    x+=tilesize>>1;
+    y+=tilesize>>1;
+    DrawPositionedScaledSprite(x,y,lump,tilesize,type);
+}
+
+/*
+=======================
+=
+= DrawMap_PlayerArrow
+=
+=======================
+*/
+
+/* Indices: mapscale, reduced coordinate */
+static const int arrowscale[4][5] =
+{   { 1,17,32,47,63},  /* Mapscale 0: 64 pixels/sprite */
+    { 1, 9,16,23,31},  /* Mapscale 1: 32 pixels/sprite */
+    { 1, 5, 8,11,15},  /* Mapscale 2: 16 pixels/sprite */
+    { 1, 3, 4, 5, 7}
+}; /* Mapscale 3:  8 pixels/sprite */
+
+void DrawMap_PlayerArrow (int x, int y, int dir)
+{
+    int i;
+
+    x*=tilesize;
+    y*=tilesize;
+
+    /* You can't draw a 4x4 arrow */
+    if(mapscale == 4)
+    {
+        VL_Bar(x+1,y+1,2,2,244);
+        return;
+    }
+
+    for (i=0; i<6; i++)
+    {
+        VL_DrawLine (arrowscale[mapscale][arrows[dir][i].x]+x,
+                     arrowscale[mapscale][arrows[dir][i].y]+y,
+                     arrowscale[mapscale][arrows[dir][i+1].x]+x,
+                     arrowscale[mapscale][arrows[dir][i+1].y]+y,
+                     244
+                    );
+    }
+    VL_DrawLine (  arrowscale[mapscale][arrows[dir][6].x]+x,
+                   arrowscale[mapscale][arrows[dir][6].y]+y,
+                   arrowscale[mapscale][arrows[dir][0].x]+x,
+                   arrowscale[mapscale][arrows[dir][0].y]+y,
+                   244
+                );
+}
+
+/*
+=======================
+=
+= DrawMap_Player
+=
+=======================
+*/
+
+void DrawMap_Player (int x, int y)
+{
+    if (player->flags&FL_SHROOMS)
+        DrawMap_PlayerArrow(x,y,( RandomNumber("DrawMap_PLAYER",0)>>5) );
+    else
+        DrawMap_PlayerArrow(x,y,( ( (player->angle+(FINEANGLES/16)) & (FINEANGLES-1) ) >>8) );
+    DrawMap_MaskedShape(x,y,player->shapenum+shapestart,0);
+}
+
+/*
+=======================
+=
+= DrawMap
+=
+=======================
+*/
+
+void DrawMap( int cx, int cy )
+{
+    fixed x,y;
+    statobj_t * s;
+    objtype * a;
+    int i,j;
+    int mapx,mapy;
+    int wall;
+
+    // Clear buffer
+
+    VL_ClearBuffer (bufferofs, egacolor[mapcolor]);
+
+    x=cx>>16;
+    y=cy>>16;
+
+    // Draw Walls,Doors,maskedwalls,animatingwalls
+
+    for (j=0; j<yscale; j++)
+    {
+
+        // Don't go off the bottom of the map
+
+        mapy=j+y;
+
+        if (mapy<0)
+            continue;
+
+        if (mapy>127)
+            break;
+
+        for (i=0; i<xscale; i++)
+        {
+
+            // Don't go off the right side of the map
+
+            mapx=i+x;
+
+            if (mapx<0)
+                continue;
+
+            if (mapx>127)
+                break;
+
+            if ((mapx==player->tilex ) && (mapy==player->tiley))
+            {
+                DrawMap_Player(i,j);
+                continue;
+            }
+
+            wall=tilemap[mapx][mapy];
+
+            // Check for absence of wall
+
+            if (wall)
+            {
+
+                if (!mapseen[mapx][mapy])
+                    continue;
+
+                // Check to see if it is a door or masked wall
+
+                if (wall&0x8000)
+                {
+                    if (wall&0x4000)
+                    {
+                        // Must be a masked wall
+                        DrawMap_MaskedWall(i,j,wall&0x3ff);
+                    }
+                    else
+                    {
+                        // Must be a door
+                        DrawMap_Door(i,j,wall&0x3ff);
+                    }
+                }
+
+                // Check to see if it is an animating wall
+
+                else if (wall&0x1000)
+                {
+                    DrawMap_AnimatedWall(i,j,wall&0x3ff);
+                }
+                else if (IsWindow(mapx,mapy))
+                {
+                    if (sky!=0)
+                        DrawMap_SkyTile(i,j);
+                    else
+                        Error("Trying to draw a sky on a level without sky\n");
+                }
+                else
+                {
+                    // Must be a normal wall or a wall with something above
+                    DrawMap_Wall(i,j,wall&0x3ff);
+                }
+            }
+            else
+            {
+                a=actorat[mapx][mapy];
+
+                // Check for absence of actor
+
+                if (a)
+                {
+                    switch(a->which)
+                    {
+                    case PWALL:
+                        if (!mapseen[mapx][mapy])
+                            continue;
+                        DrawMap_PushWall(i,j,(pwallobj_t *)a);
+                        break;
+                    case ACTOR:
+                        DrawMap_Actor(i,j,a);
+                        break;
+                    case SPRITE:
+                        DrawMap_Actor(i,j,a);
+                        break;
+                    default:
+                        SoftError("Unable to resolve actorat at x=%d y=%d which=%d\n",mapx,mapy,a->which);
+                        break;
+                    }
+                }
+                else
+                {
+                    s=sprites[mapx][mapy];
+
+                    // Check for absence of sprite
+
+                    if (s)
+                    {
+                        DrawMap_Sprite(i,j,s);
+                    }
+                }
+            }
+        }
+    }
+}
+
+
+
+
+/*
+=======================
+=
+= SetupFullMap
+=
+=======================
+*/
+
+void SetupFullMap( void )
+{
+    int ty;
+    pic_t *pic;
+
+    // Fill in backgrounds
+
+    pic = (pic_t *) W_CacheLumpNum (W_GetNumForName ("mmbk"), PU_CACHE, Cvt_pic_t, 1);
+    VWB_DrawPic (0, 0, pic);
+    CheckHolidays();
+
+    // Clear area for map
+
+#ifdef DOS
+    VGAMAPMASK(15);
+    for (ty=37; ty<37+127; ty++)
+        memset((byte *)bufferofs+ylookup[ty]+24,0,32);
+#else
+    for (ty=37; ty<37+127; ty++)
+        memset((byte *)bufferofs+ylookup[ty]+96,0,128);
+#endif
+}
+
+/*
+=======================
+=
+= DrawFullMap
+=
+=======================
+*/
+
+void DrawFullMap( void )
+{
+    statobj_t * s;
+    objtype * a;
+    int mapx,mapy;
+    int wall;
+    byte * buf;
+
+    SetupFullMap();
+
+    // Draw Walls,Doors,maskedwalls,animatingwalls
+
+    for (mapx=0; mapx<mapwidth; mapx++)
+    {
+#ifdef DOS
+        VGAWRITEMAP(mapx&3);
+        buf=(byte *)bufferofs+ylookup[37]+((96+mapx)>>2);
+#else
+        buf=(byte *)bufferofs+ylookup[37]+((96+mapx));
+#endif
+
+#ifdef DOS
+        for (mapy=0; mapy<mapheight; mapy++,buf+=iGLOBAL_SCREENBWIDE)
+#else
+        for (mapy=0; mapy<mapheight; mapy++,buf+=iGLOBAL_SCREENWIDTH)
+#endif
+        {
+            if ((mapx==player->tilex ) && (mapy==player->tiley))
+            {
+                *buf=egacolor[MAP_PLAYERCOLOR];
+                continue;
+            }
+
+            wall=tilemap[mapx][mapy];
+
+            // Check for absence of wall
+
+            if (wall)
+            {
+
+                if (!mapseen[mapx][mapy])
+                    continue;
+
+                // Check to see if it is a door or masked wall
+
+                if (wall&0x8000)
+                {
+                    if (wall&0x4000)
+                    {
+                        // Must be a maskedwall
+                        *(buf)=egacolor[MAP_MWALLCOLOR];
+                    }
+                    else
+                    {
+                        // Must be a door
+                        *(buf)=egacolor[MAP_DOORCOLOR];
+                    }
+                }
+
+                // Check to see if it is an animating wall
+
+                else if (wall&0x1000)
+                {
+                    *(buf)=egacolor[MAP_AWALLCOLOR];
+                }
+                else if (IsWindow(mapx,mapy))
+                {
+                    if (sky!=0)
+                        *(buf)=egacolor[MAP_SKYCOLOR];
+                    else
+                        Error("Trying to draw a sky on a level without sky\n");
+                }
+                else
+                {
+                    // Must be a normal wall or a wall with something above
+                    *(buf)=egacolor[MAP_WALLCOLOR];
+                }
+            }
+            else
+            {
+                a=actorat[mapx][mapy];
+
+                // Check for absence of actor
+
+                if (a)
+                {
+                    switch(a->which)
+                    {
+                    case PWALL:
+                        if (!mapseen[mapx][mapy])
+                            continue;
+                        *(buf)=egacolor[MAP_PWALLCOLOR];
+                        break;
+                    case ACTOR:
+                        if (a->flags&FL_SEEN)
+                        {
+                            if (a->obclass==inertobj)
+                                *(buf)=egacolor[MAP_SPRITECOLOR];
+                            else
+                                *(buf)=egacolor[MAP_ACTORCOLOR];
+                        }
+                        break;
+                    case SPRITE:
+                        if (a->flags&FL_SEEN)
+                            *(buf)=egacolor[MAP_SPRITECOLOR];
+                        break;
+                    default:
+                        SoftError("Unable to resolve actorat at x=%d y=%d which=%d\n",mapx,mapy,a->which);
+                        break;
+                    }
+                }
+                else
+                {
+                    s=sprites[mapx][mapy];
+
+                    // Check for absence of sprite
+
+                    if (s && (s->flags&FL_SEEN))
+                    {
+                        *(buf)=egacolor[MAP_SPRITECOLOR];
+                    }
+                }
+            }
+        }
+    }
+    FlipPage();
+}
+
+/*
+=======================
+=
+= DrawMapInfo
+=
+=======================
+*/
+
+void DrawMapInfo ( void )
+{
+    char temp[80];
+    int width,height;
+
+    CurrentFont=tinyfont;
+
+    PrintX = 2;
+    PrintY = 2;
+    strcpy (&temp[0], &(LevelName[0]));
+    US_MeasureStr (&width, &height, "%s", &temp[0]);
+
+    VWB_TBar (0, 0, 320, height+4);
+
+    US_BufPrint (&temp[0]);
+
+    strcpy (&temp[0], "TAB=EXIT");
+    US_MeasureStr (&width, &height, "%s", &temp[0]);
+
+    PrintX = 316-width;
+    PrintY = 2;
+
+    US_BufPrint (&temp[0]);
+
+    strcpy (&temp[0], "< > CHANGE BACKGROUND COLOR");
+    US_MeasureStr (&width, &height, "%s", &temp[0]);
+
+    PrintX = (320-width)>>1;
+    PrintY = 2;
+
+    US_BufPrint (&temp[0]);
+}
+
+/*
+=======================
+=
+= SetupMapScale
+=
+=======================
+*/
+
+void SetupMapScale( int s )
+{
+    mapscale=s;
+    tilesize=64>>mapscale;
+    xscale=320/tilesize;
+    yscale=200/tilesize;
+    hp_srcstep=0x10000<<mapscale;
+}
+
+
+/*
+=======================
+=
+= ChangeMapScale
+=
+=======================
+*/
+
+void ChangeMapScale( int * newx, int * newy, int newmapscale )
+{
+    if (newmapscale<0)
+        return;
+    if (newmapscale>FULLMAP_SCALE)
+        return;
+
+    if (newmapscale==FULLMAP_SCALE)
+        DrawFullMap();
+
+    *newx=*newx+(xscale<<15);
+    *newy=*newy+(yscale<<15);
+
+    SetupMapScale(newmapscale);
+
+    *newx=*newx-(xscale<<15);
+    *newy=*newy-(yscale<<15);
+}
+
+
+/*
+=======================
+=
+= SetupMapper
+=
+=======================
+*/
+void SetupMapper ( void )
+{
+    FixMapSeen();
+
+    tics=0;
+    oldw=viewwidth;
+    oldh=viewheight;
+    viewwidth=320;
+    viewheight=200;
+
+    if (sky!=0)
+    {
+        skytile=SafeMalloc(64*64);
+        MakeSkyTile(skytile);
+    }
+}
+
+/*
+=======================
+=
+= ShutdownMapper
+=
+=======================
+*/
+void ShutdownMapper ( void )
+{
+    VL_ClearVideo (0);
+    viewwidth=oldw;
+    viewheight=oldh;
+    SetupScreen (true);
+
+    if (sky!=0)
+        SafeFree(skytile);
+    if (mouseenabled && MousePresent)
+        PollMouseMove();
+}
+
+/*
+=======================
+=
+= DoMap
+=
+=======================
+*/
+
+void DoMap (int cx, int cy)
+{
+    int x,y;
+    int dx;
+    int dy;
+    boolean done;
+    int quitkey;
+    ControlInfo control;
+
+    EnableScreenStretch();//bna++
+
+    ShutdownClientControls();
+
+    done=false;
+
+    while (Keyboard[sc_Tab])
+        IN_UpdateKeyboard ();
+    if (SpaceBallPresent && spaceballenabled)
+    {
+        while (GetSpaceBallButtons()) ;
+    }
+
+    x=(cx-(xscale>>1))<<16;
+    y=(cy-(yscale>>1))<<16;
+
+    SetupMapper();
+
+    transparentlevel=25;
+
+    ChangeMapScale(&x, &y, mapscale);
+
+    while (done==false)
+    {
+        IN_UpdateKeyboard ();
+        if ((Keyboard[sc_Tab]) || (Keyboard[sc_Escape]))
+        {
+            if (Keyboard[sc_Tab])
+                quitkey=sc_Tab;
+            else
+                quitkey=sc_Escape;
+            done=true;
+        }
+        if (SpaceBallPresent && spaceballenabled)
+        {
+            if (GetSpaceBallButtons()!=0)
+                done=true;
+        }
+        if ( Keyboard[ sc_Home ] )
+        {
+            x=(cx-(xscale>>1))<<16;
+            y=(cy-(yscale>>1))<<16;
+        }
+        dx=0;
+        dy=0;
+        if (mapscale==FULLMAP_SCALE)
+            CalcTics();
+        else
+        {
+            DrawMap(x,y);
+            DrawMapInfo ();
+            FlipPage();
+            CalcTics();
+            DoSprites();
+            AnimateWalls();
+        }
+        ReadAnyControl (&control);
+        if ((Keyboard[sc_PgUp]) ||
+                (Keyboard[sc_Plus])  ||
+                (control.button1))
+        {
+            ChangeMapScale(&x, &y, mapscale+1);
+            while(Keyboard[sc_PgUp])
+                IN_UpdateKeyboard ();
+            while(Keyboard[sc_Plus])
+                IN_UpdateKeyboard ();
+            while(control.button1)
+                ReadAnyControl (&control);
+        }
+        if ((Keyboard[sc_PgDn]) ||
+                (Keyboard[sc_Minus])  ||
+                (control.button0))
+        {
+            ChangeMapScale(&x, &y, mapscale-1);
+            while(Keyboard[sc_PgDn])
+                IN_UpdateKeyboard ();
+            while(Keyboard[sc_Minus])
+                IN_UpdateKeyboard ();
+            while(control.button0)
+                ReadAnyControl (&control);
+        }
+        if (Keyboard[sc_CapsLock] && Keyboard[sc_C])
+        {
+            inhmenu=true;
+            SaveScreen (true);
+            inhmenu=false;
+        }
+        if (Keyboard[sc_CapsLock] && Keyboard[sc_X])
+        {
+            inhmenu=true;
+            SaveScreen (false);
+            inhmenu=false;
+        }
+        if (Keyboard[sc_Comma])
+        {
+            if (mapcolor>0)
+                mapcolor--;
+            while(Keyboard[sc_Comma])
+                IN_UpdateKeyboard ();
+        }
+        if (Keyboard[sc_Period])
+        {
+            if (mapcolor<15)
+                mapcolor++;
+            while(Keyboard[sc_Period])
+                IN_UpdateKeyboard ();
+        }
+        if (mapscale!=FULLMAP_SCALE)
+        {
+            if (control.dir==dir_East)
+                dx=(tics<<17)/(5-mapscale);
+            if (control.dir==dir_West)
+                dx=-(tics<<17)/(5-mapscale);
+            if (control.dir==dir_South)
+                dy=(tics<<17)/(5-mapscale);
+            if (control.dir==dir_North)
+                dy=-(tics<<17)/(5-mapscale);
+        }
+#if (DEVELOPMENT == 1)
+        if (Keyboard[sc_M])
+        {
+            CheatMap();
+            ChangeMapScale( &x, &y, mapscale );
+        }
+#endif
+
+        x+=dx;
+        y+=dy;
+
+        if (x>0x7effff)
+            x=0x7effff;
+        else if (x<-(xscale<<15))
+            x=-(xscale<<15);
+        if (y>0x7effff)
+            y=0x7effff;
+        else if (y<-(yscale<<15))
+            y=-(yscale<<15);
+    }
+
+    if ( playstate == ex_stillplaying )	  {//bna++
+        pic_t *shape;
+        shape =  ( pic_t * )W_CacheLumpName( "backtile", PU_CACHE, Cvt_pic_t, 1 );
+        DrawTiledRegion( 0, 16, iGLOBAL_SCREENWIDTH, iGLOBAL_SCREENHEIGHT - 32, 0, 16, shape );//bna++
+        DisableScreenStretch();//dont strech when we go BACK TO GAME
+        VW_UpdateScreen ();
+        DrawPlayScreen(true);//repaint ammo and life stat
+
+    }
+    while (Keyboard[quitkey])
+        IN_UpdateKeyboard ();
+
+    LastScan=0;
+    Keyboard[sc_Escape]=0;
+    Keyboard[sc_Tab]=0;
+
+    ShutdownMapper();
+
+    StartupClientControls();
+}
+
--- /dev/null
+++ b/rott/rt_map.h
@@ -1,0 +1,32 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+//***************************************************************************
+//
+// RT_MAP.C
+//
+//***************************************************************************
+
+#ifndef _rt_map_public
+#define _rt_map_public
+
+void DoMap(int x, int y);
+void CheatMap( void );
+
+#endif
--- /dev/null
+++ b/rott/rt_menu.c
@@ -1,0 +1,10510 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+//******************************************************************************
+//
+// RT_MENU.C
+//    Contains the menu stuff!
+//
+//******************************************************************************
+
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <string.h>
+#include <ctype.h>
+
+#if PLATFORM_DOS
+#include <conio.h>
+#include <dos.h>
+#include <io.h>
+#elif PLATFORM_UNIX
+#include <unistd.h>
+#include "SDL.h"
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "rt_def.h"
+#include "_rt_menu.h"
+#include "rt_menu.h"
+#include "rt_sound.h"
+#include "fx_man.h"
+#include "rt_build.h"
+#include "rt_in.h"
+#include "isr.h"
+#include "z_zone.h"
+#include "w_wad.h"
+#include "rt_util.h"
+#include "rt_main.h"
+#include "rt_playr.h"
+#include "rt_rand.h"
+#include "rt_game.h"
+#include "rt_floor.h"
+#include "rt_draw.h"
+#include "rt_view.h"
+#include "rt_str.h"
+#include "rt_vid.h"
+#include "rt_ted.h"
+#include "rt_com.h"
+#include "lumpy.h"
+#include "rt_cfg.h"
+#include "version.h"
+#include "modexlib.h"
+#include "rt_msg.h"
+#include "rt_net.h"
+#include "rt_spbal.h"
+#include "rt_scale.h"
+
+#include "rt_battl.h"
+#include "develop.h"
+//MED
+#include "memcheck.h"
+
+
+//******************************************************************************
+//
+// GLOBALS
+//
+//******************************************************************************
+
+#define DELAYAMT  2
+
+#define SNDCARDS  12
+
+#define CP_NO     0
+#define CP_ESC    -1
+#define CP_YES    1
+
+int CP_Acknowledge;
+
+boolean POK = false;
+char    pword[ 13 ];
+
+boolean ingame    = false;
+boolean inmenu    = false;
+boolean pickquick = false;
+boolean NewGame   = false;
+
+//
+// Global window coords
+//
+int PrintX;
+int PrintY;
+int WindowX;
+int WindowY;
+int WindowH = 160;
+int WindowW;
+
+int px;
+int py;
+int bufferheight;
+int bufferwidth;
+
+cfont_t *IFont;
+font_t  *CurrentFont;
+font_t  *newfont1;
+font_t  *smallfont;
+font_t  *bigfont;
+font_t  *tinyfont;
+
+boolean loadedgame = false;
+
+battle_type BATTLE_Options[ battle_NumBattleModes ];
+
+int quicksaveslot=-1;
+
+//******************************************************************************
+//
+// LOCALS
+//
+//******************************************************************************
+
+char order[ 21 ] = {
+    di_west, di_east, di_north, di_south, bt_run, bt_use, bt_attack,
+    bt_strafe, bt_strafeleft, bt_straferight, bt_lookup, bt_lookdown,
+    bt_aimbutton, bt_horizonup, bt_horizondown, bt_swapweapon, bt_dropweapon,
+    bt_turnaround, bt_autorun, bt_message, bt_directmsg
+};
+
+// bt_pistol, bt_dualpistol, bt_mp40, bt_missileweapon, bt_recordsound,
+
+#define RETURNVAL    100
+
+static boolean loadsavesound = false;
+static int numdone;
+
+static char *endStrings[ 7 ] =
+{
+    "Press Y to reformat \nand install Windows.\0\0",
+    "Press Y to activate \nguillotine.\0\0",
+    "Press Y to release \nthe cyanide gas.\0\0",
+    "Press Y to open \ntrap door.\0\0",
+    "Press Y to drive your \ncar off the cliff.\0\0",
+    "Press Y to pull \nyour plug.\0\0",
+    "Press Y to activate \nelectric chair.\0\0"
+};
+
+static char *BattleModeDescriptions[ battle_NumBattleModes - 1 ] =
+{
+    "Kill your enemies!  Don't get killed!  Kill some more!",
+    "Score more points for more difficult kills.",
+    "Collect the most triads to win the game.  Whoopee!",
+    "Collect triads to win the game--this time with weapons!",
+    "Armed hunters vs. unarmed prey--then the tables are turned!",
+    "Tag your enemies.  Run away.  Lowest points wins.",
+    "Chase roving 'Eluders'--tag them for points.",
+    "Use weapons to destroy roving Eluder triads for points.",
+    "Capture the opposing team's triad while guarding your own."
+};
+
+static char *BattleOptionDescriptions[ 9 ] =
+{
+    "Adjust the Gravitational Constant of the game universe!",
+    "Adjust the top speed for all players in the game",
+    "Adjust the amount of ammo in all missile weapons",
+    "Adjust the hit points of all players in the game",
+    "Radically change the way the game plays",
+    "Adjust the light characteristics of the game",
+    "Adjust the point goal of the game",
+    "Adjust the damage done by environment dangers",
+    "Adjust the time limit for the game"
+};
+
+static char *GravityOptionDescriptions[ 3 ] =
+{
+    "Similar to gravity on the moon",
+    "Normal Gravity (9.81 m/s^2 !)",
+    "Similar to gravity on Jupiter"
+};
+
+static char *SpeedOptionDescriptions[ 2 ] =
+{
+    "Player speeds are determined by character",
+    "All players can move at the fastest possible speed"
+};
+
+static char *AmmoOptionDescriptions[ 3 ] =
+{
+    "One piece of ammo per missile weapon",
+    "Normal ammo for all missile weapons",
+    "Infinite ammo for all missile weapons"
+};
+
+static char *HitPointsOptionDescriptions[ 7 ] =
+{
+    "One hit point for each player",
+    "25 hit points for each player",
+    "Hit points determined by character",
+    "100 hit points for each player",
+    "250 hit points for each player (default)",
+    "500 hit points for each player",
+    "4000 hit points for each player",
+};
+
+static char *RadicalOptionDescriptions[ 8 ] =
+{
+    "Control spawning of environment dangers",
+    "Control spawning of health items",
+    "Control spawning of missile weapons",
+    "Spawn mines instead of health items",
+    "Objects reappear a short time after being picked up",
+    "Missile weapons remain when picked up",
+    "Weapons are chosen randomly at the start of the game",
+    "Killing yourself or a team member counts as a suicide"
+};
+
+static char *LightLevelOptionDescriptions[ 6 ] =
+{
+    "Very dark, cave-like",
+    "Lighting determined by level design",
+    "Full brightness",
+    "Bright with fog",
+    "Periodic lighting (voobing)",
+    "Dark with lightning"
+};
+
+static char *PointGoalOptionDescriptions[ 9 ] =
+{
+    "One Point/Kill",
+    "5 Points/Kills",
+    "11 Points/Kills",
+    "21 Points/Kills",
+    "50 Points/Kills",
+    "100 Points/Kills",
+    "Random Points/Kills",
+    "Random Points/Kills but goal is not revealed",
+    "Infinite Points/Kills"
+};
+
+static char *DangerDamageOptionDescriptions[ 3 ] =
+{
+    "Environmental dangers' damage is relatively low",
+    "Environmental dangers' damage normal",
+    "One touch and you are dead!"
+};
+
+static char *TimeLimitOptionDescriptions[ 8 ] =
+{
+    "One Minute",
+    "2 Minutes",
+    "5 Minutes",
+    "10 Minutes",
+    "21 Minutes",
+    "30 Minutes",
+    "99 Minutes",
+    "No Time Limit"
+};
+
+
+static char *BattleModeNames[ battle_NumBattleModes - 1 ] =
+{
+    "NORMAL COMM-BAT", "SCORE MORE", "COLLECTOR", "SCAVENGER",
+    "HUNTER", "TAG", "ELUDER", "DELUDER", "CAPTURE THE TRIAD"
+};
+
+static int OptionNums[ 12 ] =
+{
+    0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
+};
+
+static int HitPointNums[ 7 ] =
+{
+    1, 25, bo_character_hitpoints, 100, 250, 500, 4000
+};
+
+static int KillNums[ 9 ] =
+{
+    1, 5, 11, 21, 50, 100, bo_kills_random,
+    bo_kills_blind, bo_kills_infinite
+};
+
+static int GravityNums[ 3 ] =
+{
+    LOW_GRAVITY, NORMAL_GRAVITY, HIGH_GRAVITY
+};
+
+static int TimeLimitNums[ 8 ] =
+{
+    1, 2, 5, 10, 21, 30, 99, bo_time_infinite
+};
+
+static int DangerNums[ 3 ] =
+{
+    bo_danger_low, bo_danger_normal, bo_danger_kill
+};
+
+static int MenuNum = 0;
+static int handlewhich;
+static int CSTactive = 0;
+static boolean INFXSETUP = false;
+static int MaxVoices;
+static int MaxBits;
+static int MaxChannels;
+
+//
+// MENU CURSOR SHAPES
+//
+
+#define MAXCURSORNUM 24
+
+static int cursorwidth;
+static int cursorheight;
+static int yinc;
+
+static char *FontNames[] = { "itnyfont", "ifnt", "sifont", "lifont" };
+static int   FontSize[]  = { 6, 7, 9, 14 };
+static char *SmallCursor = "smallc01";
+static char *LargeCursor = "cursor01";
+static char *CursorLump  = "cursor01";
+static int CursorNum = 0;
+static int CursorFrame[ MAXCURSORNUM ] =
+{
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3,
+    4, 5, 6, 7, 8, 7, 6, 5, 4, 3, 2, 1
+};
+
+typedef enum
+{
+    MOUSEENABLE,
+    JOYENABLE,
+    USEPORT2,
+    PADENABLE,
+    SPACEBALLENABLE,
+    CYBERMANENABLE,
+    THRESSENS,
+    MOUSESENS,
+    CUSTOMIZE
+} controltypes;
+
+
+static char *playerwadname[] =
+{
+    "cass1", "bars1", "wens1", "lnis1", "ipfs1"
+};
+
+char *colorname[] =
+{
+    "Gray", "Brown", "Black", "Tan", "Red", "Olive",
+    "Blue", "White", "Green", "Purple", "Orange"
+};
+
+//
+// MENU ITEMS
+//
+CP_MenuNames MainMenuNames[] =
+{
+    "NEW GAME",
+    "COMM-BAT� GAME",
+    "RESTORE GAME",
+    "SAVE GAME",
+    "OPTIONS",
+    "ORDERING INFO",
+    "VIEW SCORES", //"END GAME"
+    "BACK TO DEMO", //"BACK TO GAME"
+    "QUIT"
+};
+
+CP_iteminfo MainItems  = { MENU_X, MENU_Y + 1, 9, STARTITEM, 32, MainMenuNames, mn_largefont };
+CP_itemtype MainMenu[] =
+{
+    { CP_CursorLocation, "mm_opt1\0",  'N', (menuptr)CP_NewGame },
+    { CP_Active,         "battle\0",   'C', (menuptr)CP_BattleModes },
+    { CP_Active,         "mm_opt2\0",  'R', (menuptr)CP_LoadGame },
+    { CP_Inactive,       "mm_opt3\0",  'S', (menuptr)CP_SaveGame },
+    { CP_Active,         "mm_opt5\0",  'O', (menuptr)CP_ControlMenu },
+    { CP_Active,         "ordrinfo\0", 'O', (menuptr)CP_OrderInfo },
+    { CP_Active,         "mm_opt7\0",  'V', (menuptr)CP_ViewScores },
+    { CP_Active,         "mm_opt8\0",  'B', (menuptr)NULL },
+    { CP_Active,         "mm_opt9\0",  'Q', (menuptr)CP_Quit }
+};
+
+
+CP_iteminfo LSItems  = { LSM_X, LSM_Y, NUMSAVEGAMES, 0, 10, NULL, mn_largefont };
+CP_itemtype LSMenu[] =
+{
+    { CP_Active, "", 'a', NULL },
+    { CP_Active, "", 'b', NULL },
+    { CP_Active, "", 'c', NULL },
+    { CP_Active, "", 'd', NULL },
+    { CP_Active, "", 'e', NULL },
+    { CP_Active, "", 'f', NULL },
+    { CP_Active, "", 'g', NULL },
+    { CP_Active, "", 'h', NULL },
+    { CP_Active, "", 'i', NULL },
+    { CP_Active, "", 'j', NULL },
+    { CP_Active, "", 'k', NULL },
+    { CP_Active, "", 'l', NULL },
+    { CP_Active, "", 'm', NULL },
+    { CP_Active, "", 'n', NULL },
+    { CP_Active, "", 'o', NULL }
+};
+
+CP_MenuNames CtlMenuNames[] =
+{
+    "MOUSE ENABLED",
+    "JOYSTICK ENABLED",
+    "USE JOYSTICK PORT 2",
+    "GAMEPAD ENABLED",
+    "SPACEBALL ENABLED",
+    "CYBERMAN ENABLED",
+    "ADJUST THRESHOLD",
+    "MOUSE SENSITIVITY",
+    "CUSTOMIZE CONTROLS"
+};
+
+CP_iteminfo CtlItems  = { CTL_X, MENU_Y, 9, -1, 36, CtlMenuNames, mn_largefont };
+CP_itemtype CtlMenu[] =
+{
+    { CP_Inactive, "ctl_mic\0", 'M', NULL },
+    { CP_Inactive, "ctl_jen\0", 'J', NULL },
+    { CP_Inactive, "ctl_jp2\0", 'U', NULL },
+    { CP_Inactive, "ctl_gpd\0", 'G', NULL },
+    { CP_Inactive, "spball\0",  'S', NULL },
+    { CP_Inactive, "cyberman\0",'C', NULL },
+    { CP_Inactive, "ctl_thr\0", 'A', (menuptr)DoThreshold },
+    { CP_Inactive, "ctl_mse\0", 'M', (menuptr)MouseSensitivity },
+    { CP_Active,   "ctl_cus\0", 'C', (menuptr)CP_Custom }
+};
+
+CP_iteminfo CusItems  = { 32, CST_Y + 13 * 2, 9, -1, 0, NULL, mn_largefont };
+CP_itemtype CusMenu[] =
+{
+    { CP_Active,   "ctl_mic\0", 'a', NULL },
+    { CP_Inactive, "ctl_mic\0", 'a', NULL },
+    { CP_Inactive, "ctl_mic\0", 'a', NULL },
+    { CP_Active,   "ctl_mic\0", 'a', NULL },
+    { CP_Inactive, "ctl_mic\0", 'a', NULL },
+    { CP_Inactive, "ctl_mic\0", 'a', NULL },
+    { CP_Active,   "ctl_mic\0", 'a', NULL },
+    { CP_Inactive, "ctl_mic\0", 'a', NULL },
+    { CP_Active,   "ctl_mic\0", 'a', NULL }
+};
+
+
+CP_iteminfo TufItems = { TUF_X, TUF_Y, 7, 0, 80, NULL, mn_largefont };
+CP_itemtype TufMenu[ 4 ][ 7 ] =
+{
+    {
+        { 2, "new11\0", 'a', NULL },
+        { 3, "new11\0", 'a', NULL },
+        { 1, "new12\0", 'a', NULL },
+        { 3, "new12\0", 'a', NULL },
+        { 1, "new13\0", 'a', NULL },
+        { 3, "new13\0", 'a', NULL },
+        { 1, "new14\0", 'a', NULL },
+    },
+
+    {
+        { 2, "new21\0", 'a', NULL },
+        { 3, "new21\0", 'a', NULL },
+        { 1, "new22\0", 'a', NULL },
+        { 3, "new22\0", 'a', NULL },
+        { 1, "new23\0", 'a', NULL },
+        { 3, "new23\0", 'a', NULL },
+        { 1, "new24\0", 'a', NULL },
+    },
+
+    {
+        { 2, "new31\0", 'a', NULL },
+        { 3, "new31\0", 'a', NULL },
+        { 1, "new32\0", 'a', NULL },
+        { 3, "new32\0", 'a', NULL },
+        { 1, "new33\0", 'a', NULL },
+        { 3, "new33\0", 'a', NULL },
+        { 1, "new34\0", 'a', NULL },
+    },
+
+    {
+        { 2, "stk_1\0", 'a', NULL },
+        { 3, "stk_1\0", 'a', NULL },
+        { 1, "stk_2\0", 'a', NULL },
+        { 3, "stk_2\0", 'a', NULL },
+        { 1, "stk_3\0", 'a', NULL },
+        { 3, "stk_3\0", 'a', NULL },
+        { 1, "stk_4\0", 'a', NULL },
+    }
+};
+
+CP_MenuNames CustomMenuNames[] =
+{
+    "CUSTOMIZE KEYBOARD",
+    "CUSTOMIZE MOUSE",
+    "CUSTOMIZE JOYSTICK"
+};
+
+CP_iteminfo CustomItems = {32, 64, 3, 0, 24, CustomMenuNames, mn_largefont };
+
+CP_itemtype CustomMenu[] =
+{
+    {2, "custom1\0", 'C', (menuptr)CP_Keyboard},
+    {1, "custom2\0", 'C', (menuptr)CP_Mouse},
+    {1, "custom3\0", 'C', (menuptr)CP_Joystick}
+};
+
+#define KEYNAMEINDEX 21
+
+CP_MenuNames NormalKeyNames[] =
+{
+    "LEFT               \x9      ",
+    "RIGHT              \x9      ",
+    "FORWARD            \x9      ",
+    "BACKWARD           \x9      ",
+    "RUN                \x9      ",
+    "OPEN               \x9      ",
+    "FIRE               \x9      ",
+    "STRAFE             \x9      ",
+    "STRAFE LEFT        \x9      ",
+    "STRAFE RIGHT       \x9      ",
+    "LOOK/FLY UP        \x9      ",
+    "LOOK/FLY DOWN      \x9      ",
+    "AIM                \x9      ",
+    "AIM UP             \x9      ",
+    "AIM DOWN           \x9      ",
+    "TOGGLE WEAPON      \x9      ",
+    "DROP WEAPON        \x9      ",
+    "VOLTE-FACE         \x9      ",
+    "AUTORUN            \x9      ",
+    "SEND MESSAGE       \x9      ",
+    "DIRECT MESSAGE     \x9      "
+};
+
+#define NORMALKEY_X  74
+#define NORMALKEY_Y  16
+CP_iteminfo NormalKeyItems = { NORMALKEY_X, 17, 21, 0, 16, NormalKeyNames, mn_tinyfont };
+
+CP_itemtype NormalKeyMenu[] =
+{
+    { 2, "\0", 'L', (menuptr)DefineKey },
+    { 1, "\0", 'R', (menuptr)DefineKey },
+    { 1, "\0", 'F', (menuptr)DefineKey },
+    { 1, "\0", 'B', (menuptr)DefineKey },
+    { 1, "\0", 'R', (menuptr)DefineKey },
+    { 1, "\0", 'O', (menuptr)DefineKey },
+    { 1, "\0", 'F', (menuptr)DefineKey },
+    { 1, "\0", 'S', (menuptr)DefineKey },
+    { 1, "\0", 'S', (menuptr)DefineKey },
+    { 1, "\0", 'S', (menuptr)DefineKey },
+    { 1, "\0", 'L', (menuptr)DefineKey },
+    { 1, "\0", 'L', (menuptr)DefineKey },
+    { 1, "\0", 'A', (menuptr)DefineKey },
+    { 1, "\0", 'A', (menuptr)DefineKey },
+    { 1, "\0", 'T', (menuptr)DefineKey },
+    { 1, "\0", 'D', (menuptr)DefineKey },
+    { 1, "\0", 'V', (menuptr)DefineKey },
+    { 1, "\0", 'A', (menuptr)DefineKey },
+    { 1, "\0", 'A', (menuptr)DefineKey },
+    { 1, "\0", 'S', (menuptr)DefineKey },
+    { 1, "\0", 'D', (menuptr)DefineKey }
+};
+
+#define NUMCONTROLNAMES 21
+
+CP_MenuNames ControlNames[] =
+{
+    "NONE",
+    "LEFT",
+    "RIGHT",
+    "FORWARD",
+    "BACKWARD",
+    "RUN",
+    "OPEN",
+    "FIRE",
+    "STRAFE",
+    "STRAFE LEFT",
+    "STRAFE RIGHT",
+    "LOOK/FLY UP",
+    "LOOK/FLY DOWN",
+    "AIM",
+    "AIM UP",
+    "AIM DOWN",
+    "TOGGLE WEAPON",
+    "DROP WEAPON",
+    "VOLTE-FACE",
+    "AUTORUN",
+    "MAP"
+};
+
+int controlorder[ NUMCONTROLNAMES ] = {
+    bt_nobutton, di_west, di_east, di_north, di_south, bt_run, bt_use,
+    bt_attack, bt_strafe, bt_strafeleft, bt_straferight, bt_lookup,
+    bt_lookdown, bt_aimbutton, bt_horizonup, bt_horizondown,
+    bt_swapweapon, bt_dropweapon, bt_turnaround, bt_autorun, bt_map
+};
+
+#define CONTROLSELECT_X  106
+CP_iteminfo ControlSelectItems = { CONTROLSELECT_X, 17, NUMCONTROLNAMES, 0, 16, ControlNames, mn_tinyfont };
+
+CP_itemtype ControlSelectMenu[] =
+{
+    { 2, "\0", 'N', NULL },
+    { 1, "\0", 'L', NULL },
+    { 1, "\0", 'R', NULL },
+    { 1, "\0", 'F', NULL },
+    { 1, "\0", 'B', NULL },
+    { 1, "\0", 'R', NULL },
+    { 1, "\0", 'O', NULL },
+    { 1, "\0", 'F', NULL },
+    { 1, "\0", 'S', NULL },
+    { 1, "\0", 'S', NULL },
+    { 1, "\0", 'S', NULL },
+    { 1, "\0", 'L', NULL },
+    { 1, "\0", 'L', NULL },
+    { 1, "\0", 'A', NULL },
+    { 1, "\0", 'A', NULL },
+    { 1, "\0", 'A', NULL },
+    { 1, "\0", 'T', NULL },
+    { 1, "\0", 'D', NULL },
+    { 1, "\0", 'V', NULL },
+    { 1, "\0", 'A', NULL },
+    { 1, "\0", 'M', NULL }
+};
+
+#define MOUSEBTNINDEX 17
+
+CP_MenuNames MouseBtnNames[] =
+{
+    "             B0  \x9             ",
+    "             B1  \x9             ",
+    "             B2  \x9             ",
+    "DOUBLE-CLICK B0  \x9             ",
+    "DOUBLE-CLICK B1  \x9             ",
+    "DOUBLE-CLICK B2  \x9             "
+};
+
+CP_iteminfo MouseBtnItems = { 19, 52, 6, 0, 11, MouseBtnNames, mn_8x8font };
+
+CP_itemtype MouseBtnMenu[] =
+{
+    { 2, "\0", 'B', (menuptr)DefineMouseBtn },
+    { 1, "\0", 'B', (menuptr)DefineMouseBtn },
+    { 1, "\0", 'B', (menuptr)DefineMouseBtn },
+    { 1, "\0", 'D', (menuptr)DefineMouseBtn },
+    { 1, "\0", 'D', (menuptr)DefineMouseBtn },
+    { 1, "\0", 'D', (menuptr)DefineMouseBtn }
+};
+
+
+#define JOYBTNINDEX 17
+
+CP_MenuNames JoyBtnNames[] =
+{
+    "             B0  \x9             ",
+    "             B1  \x9             ",
+    "             B2  \x9             ",
+    "             B3  \x9             ",
+    "DOUBLE-CLICK B0  \x9             ",
+    "DOUBLE-CLICK B1  \x9             ",
+    "DOUBLE-CLICK B2  \x9             ",
+    "DOUBLE-CLICK B3  \x9             "
+};
+
+CP_iteminfo JoyBtnItems = { 19, 48, 8, 0, 11, JoyBtnNames, mn_8x8font };
+
+CP_itemtype JoyBtnMenu[] =
+{
+    { 2, "\0", 'B', (menuptr)DefineJoyBtn },
+    { 1, "\0", 'B', (menuptr)DefineJoyBtn },
+    { 1, "\0", 'B', (menuptr)DefineJoyBtn },
+    { 1, "\0", 'B', (menuptr)DefineJoyBtn },
+    { 1, "\0", 'D', (menuptr)DefineJoyBtn },
+    { 1, "\0", 'D', (menuptr)DefineJoyBtn },
+    { 1, "\0", 'D', (menuptr)DefineJoyBtn },
+    { 1, "\0", 'D', (menuptr)DefineJoyBtn }
+};
+
+CP_MenuNames PlayerMenuNames[] =
+{
+    "TARADINO CASSATT",
+    "THI BARRETT",
+    "DOUG WENDT",
+    "LORELEI NI",
+    "IAN PAUL FREELEY"
+};
+
+CP_iteminfo PlayerItems = {TUF_X, 48, 5, 0, 80, PlayerMenuNames, mn_largefont };
+
+CP_itemtype PlayerMenu[] =
+{
+    {2, "name1\0", 'T', NULL},
+    {1, "name2\0", 'T', NULL},
+    {1, "name3\0", 'D', NULL},
+    {1, "name4\0", 'L', NULL},
+    {1, "name5\0", 'I', NULL},
+};
+
+CP_MenuNames ControlMMenuNames[] =
+{
+    "CONTROLS",
+    "USER OPTIONS",
+    "EXT USER OPTIONS",//bna added
+    "EXT GAME OPTIONS", //added by LT
+    "MUSIC VOLUME",
+    "SOUND FX VOLUME"
+
+};
+CP_iteminfo ControlMItems = {32, 48-8, 6, 0, 32, ControlMMenuNames, mn_largefont };//bna added
+//CP_iteminfo ControlMItems = {32, 48, 4, 0, 32, ControlMMenuNames, mn_largefont };
+
+CP_itemtype ControlMMenu[] =
+{
+    {2, "cntl\0",     'C', (menuptr)CP_Control},
+    {1, "uopt\0",     'U', (menuptr)CP_OptionsMenu},
+    {1, "euopt\0", 'E', (menuptr)CP_ExtOptionsMenu},//bna added
+    {1, "eaopt\0", 'A', (menuptr)CP_ExtGameOptionsMenu},
+    {1, "muvolumn\0", 'M', (menuptr)MusicVolume},
+    {1, "fxvolumn\0", 'S', (menuptr)FXVolume}
+
+};
+
+CP_MenuNames OptionsNames[] =
+{
+    "AUTO DETAIL ADJUST",
+    "LIGHT DIMINISHING",
+    "BOBBIN'",
+    "FLOOR AND CEILING",
+    "DOUBLE-CLICK SPEED",
+    "MENU FLIP SPEED",
+    "DETAIL LEVELS",
+    "VIOLENCE LEVEL",
+    "SCREEN SIZE"
+};
+//bna added
+CP_MenuNames ExtOptionsNames[] =
+{
+    "MOUSELOOK",
+    "INVERSE MOUSE",
+    "CROSS HAIR",
+    "JUMPING",
+    "FULLSCREEN",
+    "AUTOAIM MISSILE WEPS",
+    "ENABLE AUTOAIM"
+};
+
+CP_MenuNames ExtGameOptionsNames[] =
+{
+    "BLITZ RANDOM WEPS",
+    "ENABLE AMMO PICKUP",
+    "EXTRA PISTOL DROPS",
+    "ENABLE ZOMROTT"
+}; //LT added
+
+CP_iteminfo ExtOptionsItems = { 20, MENU_Y, 7, 0, 43, ExtOptionsNames, mn_largefont };
+
+CP_iteminfo ExtGameOptionsItems = { 20, MENU_Y, 4, 0, 43, ExtGameOptionsNames, mn_largefont }; //LT added
+
+CP_itemtype ExtOptionsMenu[] =
+{
+    {1, "", 'M', NULL},
+    {1, "", 'I', NULL},
+    {1, "", 'C', NULL},
+    {1, "", 'J', NULL},
+    {1, "", 'F', NULL},
+    {1, "", 'A', NULL},
+    {1, "", 'U', NULL}
+};
+
+CP_itemtype ExtGameMenu[] =
+{
+    {1, "", 'A', NULL},
+    {1, "", 'P', NULL},
+    {1, "", 'E', NULL},
+    {1, "", 'Z', NULL},
+}; //LT added
+
+//bna added end
+
+CP_iteminfo OptionsItems = { 20, MENU_Y, 9, 0, 43, OptionsNames, mn_largefont };
+
+CP_itemtype OptionsMenu[] =
+{
+    {2, "autoadj\0", 'A', NULL},
+    {1, "lightdim\0",'L', NULL},
+    {1, "bobbin\0",  'B', NULL},
+    {1, "fandc\0",   'F', NULL},
+    {1, "double\0",  'D', (menuptr)CP_DoubleClickSpeed},
+    {1, "menuspd\0", 'M', (menuptr)MenuFlipSpeed},
+    {1, "detail\0",  'D', (menuptr)CP_DetailMenu},
+    {1, "vlevel\0",  'V', (menuptr)CP_ViolenceMenu},
+    {1, "\0",        'S', (menuptr)CP_ScreenSize}
+};
+
+CP_MenuNames DetailMenuNames[] =
+{
+    "LOW DETAIL",
+    "MEDIUM DETAIL",
+    "HIGH DETAIL"
+};
+
+CP_iteminfo DetailItems = { 32, 64, 3, 0, 43, DetailMenuNames, mn_largefont };
+
+CP_itemtype DetailMenu[] =
+{
+    {2, "lowdtl\0", 'L', NULL},
+    {1, "meddtl\0", 'M', NULL},
+    {1, "hidtl\0",  'H', NULL}
+};
+
+CP_MenuNames BattleMenuNames[] =
+{
+    "PLAY GAME",
+    "PLAY TEAM GAME",
+    "COMM-BAT OPTIONS"
+};
+
+CP_iteminfo BattleItems = { 32, 19, 3, 0, 24, BattleMenuNames, mn_largefont };
+
+CP_itemtype BattleMenu[] =
+{
+    {2, "bplay\0",    'P', (menuptr)BattleNoTeams},
+    {1, "playteam\0", 'P', (menuptr)BattleTeams},
+    {1, "comopt\0",   'C', (menuptr)CP_BattleOptions}
+};
+
+CP_MenuNames ViolenceMenuNames[] =
+{
+    "NONE",
+    "SOME",
+    "A LOT",
+    "EXCESSIVE"
+};
+
+CP_iteminfo ViolenceItems = { 32, 64, 4, 0, 45, ViolenceMenuNames, mn_largefont };
+
+CP_itemtype ViolenceMenu[] =
+{
+    {2, "vnone\0",   'N', NULL},
+    {1, "vsome\0",   'S', NULL},
+    {1, "valot\0",   'A', NULL},
+    {1, "vexcess\0", 'E', NULL}
+};
+
+CP_MenuNames VMenuNames[] =
+{
+    "SET VIOLENCE LEVEL",
+    "" // "ENTER PASSWORD" // "CHANGE PASSWORD"
+};
+
+CP_iteminfo VItems = { 32, MP_Y, 2, 0, 24, VMenuNames, mn_largefont };
+
+CP_itemtype VMenu[] =
+{
+    {2, "msetv\0",  'S',  (menuptr)CP_ViolenceLevel},
+    {1, "mepass\0", 'E', (menuptr)CP_PWMenu}
+};
+
+CP_MenuNames ModeMenuNames[] =
+{
+    "NORMAL",
+    "SCORE MORE",
+    "COLLECTOR",
+    "SCAVENGER",
+    "HUNTER",
+    "TAG",
+    "ELUDER",
+    "DELUDER",
+    "CAPTURE THE TRIAD"
+};
+
+CP_iteminfo ModeItems = { MENU_X, MENU_Y + 1, 9, 0, 24, ModeMenuNames, mn_largefont };
+
+CP_itemtype ModeMenu[] =
+{
+    {CP_CursorLocation, "normal\0",   'N', (menuptr)CP_BattleMenu},
+    {CP_Active,         "scorem\0",   'S', (menuptr)CP_BattleMenu},
+    {CP_Active,         "collect\0",  'C', (menuptr)CP_BattleMenu},
+    {CP_Active,         "scaven\0",   'S', (menuptr)CP_BattleMenu},
+    {CP_Active,         "hunter\0",   'H', (menuptr)CP_BattleMenu},
+    {CP_Active,         "tag\0",      'T', (menuptr)CP_BattleMenu},
+    {CP_Active,         "eluder\0",   'E', (menuptr)CP_BattleMenu},
+    {CP_Active,         "deluder\0",  'D', (menuptr)CP_BattleMenu},
+    {CP_Active,         "captriad\0", 'C', (menuptr)CP_BattleMenu}
+};
+
+CP_MenuNames BOptNames[] =
+{
+    "GRAVITY",
+    "SPEED",
+    "AMMO PER WEAPON",
+    "HIT POINTS",
+    "RADICAL OPTIONS",
+    "LIGHT LEVELS",
+    "POINT GOAL",
+    "DANGER DAMAGE",
+    "TIME LIMIT"
+};
+
+CP_iteminfo BOptItems = { MENU_X, MENU_Y + 1, 9, 0, 24, BOptNames, mn_largefont };
+
+CP_itemtype BOptMenu[] =
+{
+    {2, "gravity\0",  'G', (menuptr)CP_GravityOptions},
+    {1, "speed\0",    'S', (menuptr)CP_SpeedOptions},
+    {1, "ammoper\0",  'A', (menuptr)CP_AmmoPerWeaponOptions},
+    {1, "hitp\0",     'H', (menuptr)CP_HitPointsOptions},
+    {1, "radical\0",  'R', (menuptr)CP_SpawnControlOptions},
+    {1, "lightl\0",   'L', (menuptr)CP_LightLevelOptions},
+    {1, "pntgoal\0",  'P', (menuptr)CP_PointGoalOptions},
+    {1, "danger\0",   'D', (menuptr)CP_DangerOptions},
+    {1, "timel\0",    'T', (menuptr)CP_TimeLimitOptions}
+};
+
+CP_MenuNames GravityMenuNames[] =
+{
+    "LOW",
+    "NORMAL",
+    "HIGH"
+};
+
+CP_iteminfo GravityItems = { 32, 26, 3, 0, 45, GravityMenuNames, mn_largefont };
+
+CP_itemtype GravityMenu[] =
+{
+    {2, "b_low\0",    'L', NULL},
+    {1, "b_normal\0", 'N', NULL},
+    {1, "b_high\0",   'H', NULL}
+};
+
+CP_MenuNames SpeedMenuNames[] =
+{
+    "NORMAL",
+    "FAST"
+};
+
+CP_iteminfo SpeedItems = { 32, MP_Y, 2, 0, 45, SpeedMenuNames, mn_largefont };
+
+CP_itemtype SpeedMenu[] =
+{
+    {2, "b_normal\0", 'N', NULL},
+    {1, "b_fast\0",   'F', NULL}
+};
+
+CP_MenuNames AmmoPerWeaponMenuNames[] =
+{
+    "ONE",
+    "NORMAL",
+    "GUNFINITY"
+};
+
+CP_iteminfo AmmoPerWeaponItems = { 32, 26, 3, 0, 45, AmmoPerWeaponMenuNames, mn_largefont };
+
+CP_itemtype AmmoPerWeaponMenu[] =
+{
+    {2, "b_one\0",    'O', NULL},
+    {1, "b_normal\0", 'N', NULL},
+    {1, "b_gunf\0",   'G', NULL}
+};
+
+CP_MenuNames HitPointMenuNames[] =
+{
+    "ONE",
+    "25",
+    "BY CHARACTER",
+    "100",
+    "250",
+    "500",
+    "4000"
+};
+
+CP_iteminfo HitPointItems = { 32, 32, 7, 0, 45, HitPointMenuNames, mn_largefont };
+
+CP_itemtype HitPointMenu[] =
+{
+    {2, "b_one\0",  'O', NULL},
+    {1, "b_25\0",   'a', NULL},
+    {1, "b_char\0", 'C', NULL},
+    {1, "b_100\0",  'a', NULL},
+    {1, "b_250\0",  'a', NULL},
+    {1, "b_500\0",  'a', NULL},
+    {1, "b_4000\0", 'a', NULL}
+};
+
+CP_MenuNames SpawnMenuNames[] =
+{
+    "SPAWN DANGERS",
+    "SPAWN HEALTH",
+    "SPAWN WEAPONS",
+    "SPAWN MINES",
+    "RESPAWN ITEMS",
+    "WEAPON PERSISTENCE",
+    "RANDOM WEAPONS",
+    "FRIENDLY FIRE"
+};
+
+CP_iteminfo SpawnItems = { 20, 24, 8, 0, 35, SpawnMenuNames, mn_largefont };
+
+CP_itemtype SpawnMenu[] =
+{
+    {2, "b_danger\0", 'S', NULL},
+    {1, "b_health\0", 'S', NULL},
+    {1, "b_weap\0",   'S', NULL},
+    {1, "b_mines\0",  'S', NULL},
+    {1, "b_rpawn\0",  'R', NULL},
+    {1, "b_persis\0", 'W', NULL},
+    {1, "b_rndwpn\0", 'R', NULL},
+    {1, "b_friend\0", 'F', NULL}
+};
+
+CP_MenuNames LightLevelMenuNames[] =
+{
+    "DARK",
+    "NORMAL",
+    "BRIGHT",
+    "FOG",
+    "PERIODIC",
+    "LIGHTNING"
+};
+
+CP_iteminfo LightLevelItems = { 32, 40, 6, 0, 45, LightLevelMenuNames, mn_largefont };
+
+CP_itemtype LightLevelMenu[] =
+{
+    {2, "b_dark\0",   'D', NULL},
+    {1, "b_normal\0", 'N', NULL},
+    {1, "b_bright\0", 'B', NULL},
+    {1, "b_fog\0",    'F', NULL},
+    {1, "b_period\0", 'P', NULL},
+    {1, "b_light\0",  'L', NULL}
+};
+
+CP_MenuNames PointGoalMenuNames[] =
+{
+    "1",
+    "5",
+    "11",
+    "21",
+    "50",
+    "100",
+    "RANDOM",
+    "RANDOM BLIND",
+    "INFINITE"
+};
+
+CP_iteminfo PointGoalItems = { 32, 16, 9, 0, 45, PointGoalMenuNames, mn_largefont };
+
+CP_itemtype PointGoalMenu[] =
+{
+    {2, "b_1\0",      'a', NULL},
+    {1, "b_5\0",      'a', NULL},
+    {1, "b_11\0",     'a', NULL},
+    {1, "b_21\0",     'a', NULL},
+    {1, "b_50\0",     'a', NULL},
+    {1, "b_100\0",    'a', NULL},
+    {1, "b_random\0", 'R', NULL},
+    {1, "b_randb\0",  'R', NULL},
+    {1, "b_inf\0",    'I', NULL}
+};
+
+CP_MenuNames DangerMenuNames[] =
+{
+    "LOW",
+    "NORMAL",
+    "KILL"
+};
+
+CP_iteminfo DangerItems = { 32, 56, 3, 0, 45, DangerMenuNames, mn_largefont };
+
+CP_itemtype DangerMenu[] =
+{
+    {2, "b_low\0",    'L', NULL},
+    {1, "b_normal\0", 'N', NULL},
+    {1, "b_kill\0",   'K', NULL}
+};
+
+CP_MenuNames TimeLimitMenuNames[] =
+{
+    "1",
+    "2",
+    "5",
+    "10",
+    "21",
+    "30",
+    "99",
+    "NONE"
+};
+
+CP_iteminfo TimeLimitItems = { 32, 24, 8, 0, 45, TimeLimitMenuNames, mn_largefont };
+
+CP_itemtype TimeLimitMenu[] =
+{
+    {2, "b_1\0",    'a', NULL},
+    {1, "b_2\0",    'a', NULL},
+    {1, "b_5\0",    'a', NULL},
+    {1, "b_10\0",   'a', NULL},
+    {1, "b_21\0",   'a', NULL},
+    {1, "b_30\0",   'a', NULL},
+    {1, "b_99\0",   'a', NULL},
+    {1, "vnone\0",  'N', NULL}
+};
+
+CP_MenuNames MultiPageCustomNames[ MAXCUSTOM + 2 ] =
+{
+    "NEXT PAGE",
+    "PREVIOUS PAGE"
+};
+
+CP_iteminfo MultiPageCustomItems = { 18, 17, 0, 0, 12, MultiPageCustomNames, mn_smallfont };
+CP_itemtype MultiPageCustomMenu[] =
+{
+    {1, "", 'N', NULL},
+    {1, "", 'P', NULL},
+    {1, "", 'a', NULL},
+    {1, "", 'a', NULL},
+    {1, "", 'a', NULL},
+    {1, "", 'a', NULL},
+    {1, "", 'a', NULL},
+    {1, "", 'a', NULL},
+    {1, "", 'a', NULL},
+    {1, "", 'a', NULL},
+    {1, "", 'a', NULL},
+    {1, "", 'a', NULL},
+    {1, "", 'a', NULL},
+    {1, "", 'a', NULL},
+};
+
+#define COLORX 113
+#define COLORY 43
+#define COLORW 60
+#define COLORH 96
+
+// Custom menu stuff
+static int CUSTOM_y[ 7 ] = { 31, 0, 63, 0, 94, 0, 126 };
+
+//
+// Save globals
+//
+static boolean StartGame = false;
+
+static int  SaveGamesAvail[ NUMSAVEGAMES ];
+static char SaveGameNames[ NUMSAVEGAMES ][ 32 ];
+static char SaveName[ 13 ] = "rottgam?.rot\0";
+
+static byte *savedscreen;
+static mapfileinfo_t * mapinfo;
+
+static void HideCursor
+(
+    CP_iteminfo *item_i,
+    CP_itemtype *items,
+    int x,
+    int y,
+    int which
+);
+static void ShowCursor
+(
+    CP_iteminfo *item_i,
+    CP_itemtype *items,
+    int x,
+    int *y,
+    int which,
+    int basey
+);
+void CP_DrawSelectedGame (int w);
+int HandleMenu (CP_iteminfo *item_i, CP_itemtype *items, void (*routine)(int w));
+void DrawStoredGame ( byte * pic, int episode, int area );
+void DrawCustomKeyboard (void);
+void DrawBattleModeName( int which );
+void DrawBattleModeDescription( int w );
+void DrawSoundSetupMainMenu( void );
+int ColorMenu(void);
+
+//******************************************************************************
+//
+// MN_DrawButtons
+//
+//******************************************************************************
+
+void MN_DrawButtons
+(
+    CP_iteminfo *item_i,
+    CP_itemtype *items,
+    int check,
+    int *nums
+)
+
+{
+    int i;
+    int button_on;
+    int button_off;
+
+    button_on  = W_GetNumForName( "snd_on" );
+    button_off = W_GetNumForName( "snd_off" );
+
+    for( i = 0; i < item_i->amount; i++ )
+    {
+        if ( items[ i ].active != CP_Active3 )
+        {
+            if ( nums[ i ] == check )
+            {
+                DrawMenuBufItem( item_i->x + 27, item_i->y + i *
+                                 FontSize[ item_i->fontsize ] - 1, button_on);
+            }
+            else
+            {
+                DrawMenuBufItem( item_i->x + 27, item_i->y + i *
+                                 FontSize[ item_i->fontsize ] - 1, button_off);
+            }
+        }
+    }
+}
+
+
+//****************************************************************************
+//
+// MN_GetCursorLocation()
+//
+//****************************************************************************
+
+void MN_GetCursorLocation
+(
+    CP_iteminfo *item_i,
+    CP_itemtype *items
+)
+
+{
+    int i;
+    int position;
+
+    position = -1;
+    for( i = 0; i < item_i->amount; i++ )
+    {
+        if ( items[ i ].active == CP_CursorLocation )
+        {
+            position = i;
+            break;
+        }
+
+        if ( ( items[ i ].active == CP_Active ) && ( position == -1 ) )
+        {
+            position = i;
+        }
+    }
+
+    if ( position != -1 )
+    {
+        item_i->curpos = position;
+        items[ position ].active = CP_CursorLocation;
+    }
+}
+
+
+//****************************************************************************
+//
+// MN_GetActive ()
+//
+//****************************************************************************
+
+int MN_GetActive
+(
+    CP_iteminfo *item_i,
+    CP_itemtype *items,
+    int check,
+    int *nums
+)
+
+{
+    int i;
+    int returnval;
+
+    returnval = 0;
+    for( i = 0; i < item_i->amount; i++ )
+    {
+        items[ i ].active = CP_Active;
+        if ( nums[ i ] == check )
+        {
+            item_i->curpos    = i;
+            items[ i ].active = CP_CursorLocation;
+            returnval = i;
+        }
+    }
+
+    return( returnval );
+}
+
+
+//****************************************************************************
+//
+// MN_MakeActive ()
+//
+//****************************************************************************
+
+void MN_MakeActive
+(
+    CP_iteminfo *item_i,
+    CP_itemtype *items,
+    int which
+)
+
+{
+    int i;
+
+    for( i = 0; i < item_i->amount; i++ )
+        if (i == which)
+        {
+            items[i].active = CP_CursorLocation;
+            item_i->curpos    = i;
+        }
+        else
+            items[i].active = CP_Active;
+}
+
+
+//******************************************************************************
+//
+// DrawMenu ()
+//
+// Purpose - Draws a menu
+//
+//******************************************************************************
+void DrawMenu
+(
+    CP_iteminfo *item_i,
+    CP_itemtype *items
+)
+
+{
+    int i;
+    int active;
+    int color;
+    int posx;
+    int posy;
+
+    posx = item_i->x + item_i->indent;
+    posy = item_i->y;
+    WindowX = posx;
+    WindowY = posy;
+    WindowW = 320;
+    WindowH = 200;
+
+    for ( i = 0; i < item_i->amount; i++ )
+    {
+        posy   = item_i->y + i * FontSize[ item_i->fontsize ];
+        active = items[ i ].active;
+
+        color = -1;
+        switch( active )
+        {
+        case CP_CursorLocation :
+            color = ACTIVECOLOR;
+            break;
+
+        case CP_Inactive :
+            color = NOTAVAILABLECOLOR;
+            break;
+
+        case CP_Active :
+            color = NORMALCOLOR;
+            break;
+
+        case CP_SemiActive :
+            color = DIMMEDCOLOR;
+            break;
+
+        case CP_Highlight :
+            color = HIGHLIGHTCOLOR;
+            break;
+        }
+
+        if ( color != -1 )
+        {
+            if ( item_i->names == NULL )
+            {
+                DrawIMenuBufItem( posx, posy, W_GetNumForName( items[ i ].texture ),
+                                  color );
+            }
+            else
+            {
+                IFont = ( cfont_t * )W_CacheLumpName( FontNames[ item_i->fontsize ],
+                                                      PU_CACHE, Cvt_cfont_t, 1 );
+                if ( item_i->fontsize == mn_tinyfont )
+                {
+                    DrawMenuBufIString( posx + 1, posy, item_i->names[ i ], 0 );
+                }
+                DrawMenuBufIString( posx, posy - 1, item_i->names[ i ], color );
+            }
+        }
+    }
+}
+
+
+//******************************************************************************
+//
+// getASCII () - Gets info from Keyboard.
+//
+//******************************************************************************
+
+int getASCII ( void )
+{
+    int i;
+    int LS;
+    int RS;
+    int returnvalue = 0;
+    int scancode = 0;
+
+#ifdef DOS
+    _disable ();      // must disable for SHIFT purposes
+#endif
+
+    IN_UpdateKeyboard ();
+
+    LS = Keyboard[sc_LShift];
+    RS = Keyboard[sc_RShift];
+
+    Keyboard[sc_LShift] = Keyboard[sc_RShift] = 0;
+
+    scancode = 0;
+
+    for (i = 0; i < 127; i++)
+        if (Keyboard[i])
+        {
+            scancode = i;
+            break;
+        }
+
+    if (scancode)
+    {
+        if (LS || RS)
+            returnvalue = ShiftNames[scancode];
+        else
+            returnvalue = ASCIINames[scancode];
+    }
+
+    Keyboard[sc_LShift] = LS;
+    Keyboard[sc_RShift] = RS;
+
+#ifdef DOS
+    _enable ();
+#endif
+
+    return (returnvalue);
+}
+
+
+//******************************************************************************
+//
+// ScanForSavedGames ()
+//
+//******************************************************************************
+
+void ScanForSavedGames ()
+{
+    struct find_t f;
+    char filename[256];
+    char str[45];
+    int which;
+    boolean found = false;
+#ifndef DOS
+    char *pathsave;
+#endif
+
+    //
+    // SEE WHICH SAVE GAME FILES ARE AVAILABLE & READ STRING IN
+    //
+    memset (&SaveGamesAvail[0], 0, sizeof (SaveGamesAvail));
+#if PLATFORM_DOS || PLATFORM_WIN32
+    GetPathFromEnvironment( filename, ApogeePath, SaveName );
+#else
+    strncpy (filename, SaveName, 256);
+    pathsave = getcwd (NULL, 0);
+    chdir (ApogeePath);
+#endif
+
+    if (!_dos_findfirst (filename, 0, &f))
+        do
+        {
+            strcpy(str,&f.name[7]);
+            sscanf((const char *)&str[0],"%x",&which);
+
+            if (which < NUMSAVEGAMES)
+            {
+                found = true;
+                SaveGamesAvail[which] = 1;
+                GetSavedMessage (which, &SaveGameNames[which][0]);
+            }
+
+        } while (!_dos_findnext (&f));
+
+    if (found)
+    {
+        if (MainMenu[loadgame].active == CP_Inactive)
+            MainMenu[loadgame].active = CP_Active;
+    }
+    else
+        MainMenu[loadgame].active = CP_Inactive;
+#if ((!PLATFORM_DOS) && (!PLATFORM_WIN32))
+    chdir (pathsave);
+    free (pathsave);
+#endif
+}
+
+
+//******************************************************************************
+//
+// SetUpControlPanel ()
+//
+//******************************************************************************
+
+void SetUpControlPanel (void)
+{
+    int i;
+    int j;
+    byte * b;
+    byte * s;
+
+//   int Xres = 320;//org
+//   int Yres = 200;//org
+    int Xres = 640;
+    int Yres = 400;
+
+    //dont work in 800x600 until we get a better screen schrinker
+    //  int Xres = iGLOBAL_SCREENWIDTH;//640;
+//  int Yres = iGLOBAL_SCREENHEIGHT;//400;
+
+    Xres = 640;
+    Yres = 400;
+
+
+
+    // Save the current game screen
+
+    //bna--savedscreen = SafeMalloc (16000);
+    savedscreen = SafeMalloc (16000*8);
+
+    // Copy the current save game screen (� size) to this buffer
+
+    if (RefreshPause==false)
+    {
+        GamePaused=false;
+        ThreeDRefresh();
+        FlipPage();
+        FlipPage();
+        GamePaused=true;
+    }
+
+
+    s=savedscreen;
+
+
+
+    if (iGLOBAL_SCREENWIDTH == 320) {
+        for (i=0; i<Xres; i+=2)	{
+            b=(byte *)bufferofs+i;
+            for (j=0; j<100; j++,s++,b+=(iGLOBAL_SCREENWIDTH<<1))
+                *s=*b;
+        }
+    }
+    if (iGLOBAL_SCREENWIDTH >= 640) {
+        for (i=0; i<Xres; i+=4)	{
+            b=(byte *)bufferofs+i;//schrink screen to 1/2 size
+            for (j=0; j<(Yres/4); j++,s++,b+=(iGLOBAL_SCREENWIDTH<<1)*2)
+                *s=*b;
+        }
+    }/*
+      if (iGLOBAL_SCREENWIDTH == 800) {
+		  for (i=0;i<Xres;i+=8)		{
+			  b=(byte *)bufferofs+i;//schrink screen to 1/3 size
+			  for (j=0;j<(Yres/8);j++,s++,b+=(iGLOBAL_SCREENWIDTH<<1)*3)
+				 *s=*b;
+		  }
+
+      }*/
+
+    ScanForSavedGames ();
+
+
+
+    if (modemgame == true)
+    {
+        // Make battle mode active
+        //
+        MainMenu[battlemode].active = CP_Active;
+
+        // No save or load game in modem game
+        //
+        MainMenu[newgame].active    = CP_Inactive;
+        MainMenu[backtodemo].active = CP_Inactive;
+        MainMenu[loadgame].active   = CP_Inactive;
+        MainMenu[savegame].active   = CP_Inactive;
+
+        if ( MainMenu[ MainItems.curpos ].active == CP_Inactive )
+        {
+            MainItems.curpos = battlemode;
+        }
+
+        MainMenu[MainItems.curpos].active = CP_CursorLocation;
+
+        if ( consoleplayer != 0 )
+        {
+            MainMenu[battlemode].routine = ( void (*)(int) )BattleGamePlayerSetup;
+        }
+    }
+}
+
+//******************************************************************************
+//
+// GetMenuInfo ()
+//
+// Gets the user's password
+//
+//******************************************************************************
+
+void GetMenuInfo (void)
+{
+    ConvertPasswordStringToPassword ();
+
+    POK=true;
+    if (pword[0]==0)
+        POK=false;
+}
+
+
+//******************************************************************************
+//
+// WriteMenuInfo ()
+//
+// Writes out password
+//
+//******************************************************************************
+
+void WriteMenuInfo (void)
+{
+    ConvertPasswordToPasswordString ();
+}
+
+//******************************************************************************
+//
+// AllocateSavedScreenPtr ()
+//
+//******************************************************************************
+
+void AllocateSavedScreenPtr (void)
+{
+    // Save the current game screen
+
+    savedscreen = SafeMalloc(16000);
+    inmenu  = true;
+    numdone = 0;
+}
+
+
+//******************************************************************************
+//
+// FreeSavedScreenPtr ()
+//
+//******************************************************************************
+
+void FreeSavedScreenPtr (void)
+{
+    SafeFree (savedscreen);
+    inmenu  = false;
+}
+
+
+//******************************************************************************
+//
+// CleanUpControlPanel ()
+//
+//******************************************************************************
+
+void CleanUpControlPanel (void)
+{
+    int   joyx, joyy;
+
+    if ((playstate==ex_resetgame) || (loadedgame==true))
+        ShutdownClientControls();
+
+    // Free up saved screen image
+
+    FreeSavedScreenPtr ();
+
+    WriteConfig ();
+
+    INL_GetJoyDelta (joystickport, &joyx, &joyy);
+
+    if (mouseenabled)
+        PollMouseMove ();    // Trying to kill movement
+
+    if (cybermanenabled)
+        PollCyberman ();
+
+    RefreshPause = true;
+}
+
+
+//******************************************************************************
+//
+// CP_CheckQuick ()
+//
+//******************************************************************************
+boolean CP_CheckQuick
+(
+    byte scancode
+)
+
+{
+    if (demoplayback==true)
+    {
+        switch ( scancode )
+        {
+        case sc_Escape:
+            inmenu = true;
+            return( true );
+            break;
+        }
+    }
+    else
+    {
+        switch ( scancode )
+        {
+        case sc_Escape:
+        case sc_F1:
+        case sc_F2:
+        case sc_F3:
+        case sc_F4:
+        case sc_F8:
+        case sc_F9:
+        case sc_F10:
+            inmenu = true;
+            return( true );
+            break;
+        }
+    }
+
+    return( false );
+}
+
+
+//******************************************************************************
+//
+// ControlPanel
+//
+//    ROTT Control Panel!
+//
+//******************************************************************************
+void ControlPanel
+(
+    byte scancode
+)
+
+{
+    if ( scancode == sc_Escape )
+    {
+        CP_MainMenu();
+        if ( ( playstate == ex_stillplaying ) && ( loadedgame == false ) )
+        {
+            fizzlein = true;
+        }
+        return;
+    }
+
+    SetupMenuBuf();
+
+    numdone = 0;
+    StartGame = false;
+
+    SetUpControlPanel();
+    EnableScreenStretch();
+    //
+    // F-KEYS FROM WITHIN GAME
+    //
+    switch( scancode )
+    {
+    case sc_F1:
+        CP_F1Help();
+        break;
+
+    case sc_F2:
+        CP_SaveGame();
+        break;
+
+    case sc_F3:
+        CP_LoadGame( 0, 0 );
+        break;
+
+    case sc_F4:
+        CP_ControlMenu();
+        break;
+
+    case sc_F8:
+        LastScan          = 0;
+        Keyboard[ sc_F8 ] = 0;
+        CP_EndGame();
+        break;
+
+    case sc_F9:
+        LastScan          = 0;
+        Keyboard[ sc_F9 ] = 0;
+
+        loadsavesound = true;
+        CP_LoadGame( 1, 0 );
+        break;
+
+    case sc_F10:
+        SetMenuTitle ("Quit");
+
+        LastScan           = 0;
+        Keyboard[ sc_F10 ] = 0;
+        CP_Quit( -1 );
+        break;
+
+    }
+
+    CleanUpControlPanel();
+    ShutdownMenuBuf();
+
+    if ( loadedgame == false )
+    {
+        SetupScreen( false );
+        fizzlein = true;
+        inmenu = false;
+    }
+
+    loadsavesound = false;
+}
+
+
+//******************************************************************************
+//
+// CP_MainMenu
+//
+//******************************************************************************
+menuitems CP_MainMenu
+(
+    void
+)
+
+{
+    int which;
+
+    SetupMenuBuf();
+
+    numdone = 0;
+
+    SetUpControlPanel();
+
+    DrawMainMenu();
+
+    //
+    // Main menu loop.  "Exit options" or "New game" exits
+    //
+    StartGame = false;
+    EnableScreenStretch();
+
+    while( !StartGame )
+    {
+        StartGame = false;
+
+        IN_ClearKeysDown();
+
+        which = HandleMenu( &MainItems, &MainMenu[ 0 ], NULL );
+
+        switch( which )
+        {
+        case backtodemo:
+            if ( !ingame )
+            {
+                playstate = ex_titles;
+            }
+
+            StartGame = true;
+            DisableScreenStretch();//bna++ shut off streech mode
+            break;
+
+        case -1:
+            CP_Quit( 0 );
+            break;
+
+        default:
+            if ( !StartGame )
+            {
+                DoMainMenu();
+            }
+        }
+    }
+
+    // Deallocate everything
+    CleanUpControlPanel();
+    ShutdownMenuBuf();
+
+    return( which );
+}
+
+
+//******************************************************************************
+//
+// DrawMainMenu ()
+//
+//******************************************************************************
+
+void DrawMainMenu(void)
+{
+
+    MenuNum = 1;
+    EnableScreenStretch();//bna++ shut off streech mode
+    //
+    // CHANGE "GAME" AND "DEMO"
+    //
+    if ( ingame )
+    {
+        MainMenu[ backtodemo ].texture[ 6 ] = '1';
+        MainMenu[ backtodemo ].texture[ 7 ] = '1';
+        MainMenu[ backtodemo ].texture[ 8 ] = '\0';
+        strcpy (MainMenuNames[ backtodemo ], "BACK TO GAME");
+    }
+    else
+    {
+        MainMenu[ backtodemo ].texture[ 6 ] = '8';
+        MainMenu[ backtodemo ].texture[ 7 ] = '\0';
+        strcpy (MainMenuNames[ backtodemo ], "BACK TO DEMO");
+    }
+
+    MN_GetCursorLocation( &MainItems, &MainMenu[ 0 ] );
+    SetMenuTitle ("Main Menu");
+    DrawMenu (&MainItems, &MainMenu[0]);
+
+    numdone ++;
+    DisplayInfo (0);
+}
+
+
+//******************************************************************************
+//
+// Handle moving triad around a menu
+//
+//******************************************************************************
+
+int HandleMenu (CP_iteminfo *item_i, CP_itemtype *items, void (*routine)(int w))
+{
+
+    char        key;
+    int         i,
+                x,
+                y,
+                basey,
+                exit,
+                numactive,
+                count;
+    int         newpos;
+    volatile int timer;
+    ControlInfo ci;
+    boolean     playsnd = false;
+
+    handlewhich = item_i->curpos;
+    x     = item_i->x;
+    if ((MenuNum == 4) || (MenuNum == 6) ||
+            ( item_i->fontsize == mn_smallfont ) )
+    {
+        basey = item_i->y;
+
+        CursorLump = SmallCursor;
+        yinc = 9;
+        cursorwidth = cursorheight = 8;
+    }
+    else if ( item_i->fontsize == mn_8x8font )
+    {
+        basey = item_i->y - 1;
+
+        CursorLump = SmallCursor;
+        yinc = 7;
+        cursorwidth = cursorheight = 8;
+    }
+    else if ( item_i->fontsize == mn_tinyfont )
+    {
+        basey = item_i->y - 2;
+
+        CursorLump = SmallCursor;
+        yinc = 6;
+        cursorwidth = cursorheight = 8;
+    }
+    else
+    {
+        basey = item_i->y-2;
+
+        CursorLump = LargeCursor;
+        yinc = 14;
+        cursorwidth = cursorheight = 16;
+    }
+
+
+    if (MenuNum)
+        y = basey + handlewhich*yinc;
+    else
+        y = CUSTOM_y[handlewhich];
+
+
+    if (MenuNum != 5)
+        DrawMenuBufItem (x, y, W_GetNumForName( CursorLump ) +
+                         CursorFrame[ CursorNum ] );
+
+    if (routine)
+        routine (handlewhich);
+
+    count    = 2;
+    exit     = 0;
+    timer    = GetTicCount();
+    IN_ClearKeysDown ();
+
+    numactive = GetNumActive (item_i, items);
+
+    do
+    {
+        ReadAnyControl (&ci);
+        RefreshMenuBuf (0);
+        // Change Cursor Shape
+        if ((GetTicCount() > (timer+count)) && (MenuNum != 5))
+        {
+            timer = GetTicCount();
+
+            CursorNum++;
+            if (CursorNum > (MAXCURSORNUM-1))
+                CursorNum = 0;
+
+            EraseMenuBufRegion(x, y, cursorwidth, cursorheight);
+            DrawMenuBufItem (x, y, W_GetNumForName( CursorLump ) +
+                             CursorFrame[ CursorNum ] );
+
+        }
+
+        // Initial char - pass 1
+        key = getASCII ();
+        if (key)
+        {
+            int ok = 0;
+
+            key = toupper (key);
+
+            for (i = (handlewhich + 1); i < item_i->amount; i++)
+                if ((items+i)->active && (items+i)->letter == key)
+                {
+                    HideCursor (item_i, items, x, y, handlewhich);
+                    MN_PlayMenuSnd (SD_MOVECURSORSND);
+                    handlewhich = i;
+
+
+                    if (routine)
+                        routine (handlewhich);
+
+                    ShowCursor (item_i, items, x, &y, handlewhich, basey);
+                    ok = 1;
+                    IN_ClearKeysDown();
+                    break;
+                }
+
+            // Initial char - pass 2
+            if (!ok)
+            {
+                for (i = 0; i < handlewhich; i++)
+                    if ((items+i)->active && (items+i)->letter == key)
+                    {
+                        HideCursor (item_i, items, x, y, handlewhich);
+                        MN_PlayMenuSnd (SD_MOVECURSORSND);
+                        handlewhich = i;
+
+
+                        if (routine)
+                            routine (handlewhich);
+
+                        ShowCursor (item_i, items, x,& y, handlewhich, basey);
+                        IN_ClearKeysDown ();
+                        break;
+                    }
+            }
+        }
+
+        ReadAnyControl (&ci);
+
+        if (numactive > 1)
+        {
+            switch (ci.dir)
+            {
+            case dir_North:
+                HideCursor (item_i, items, x, y, handlewhich);
+
+
+                CursorNum++;
+                if (CursorNum > (MAXCURSORNUM-1))
+                    CursorNum = 0;
+
+
+                // Do a half step if possible
+                if ((handlewhich) &&
+                        (((items+handlewhich-1)->active == CP_CursorLocation) ||
+                         ((items+handlewhich-1)->active == CP_Active)))
+                {
+                    y -= 6;
+                    DrawHalfStep (x, y);
+                    playsnd = false;
+
+                    RefreshMenuBuf (0);
+
+                    CursorNum++;
+                    if (CursorNum > (MAXCURSORNUM-1))
+                        CursorNum = 0;
+                }
+                else
+                {
+                    playsnd = true;
+                    RefreshMenuBuf (0);
+                }
+
+                do
+                {
+                    if (!handlewhich)
+                        handlewhich = item_i->amount-1;
+                    else
+                        handlewhich--;
+                } while (((items+handlewhich)->active == CP_Inactive) || ((items+handlewhich)->active == CP_Active3));
+
+                if (playsnd)
+                    MN_PlayMenuSnd (SD_MOVECURSORSND);
+                ShowCursor (item_i, items, x, &y, handlewhich, basey);
+
+                if (routine)
+                    routine (handlewhich);
+
+                RefreshMenuBuf(0);
+                break;
+
+            case dir_South:
+                HideCursor (item_i, items, x, y, handlewhich);
+
+                CursorNum++;
+                if (CursorNum > (MAXCURSORNUM-1))
+                    CursorNum = 0;
+
+                // Do a half step if possible
+                if ((handlewhich != item_i->amount-1) &&
+                        (((items+handlewhich+1)->active == CP_CursorLocation) ||
+                         ((items+handlewhich+1)->active == CP_Active)))
+                {
+                    y += 6;
+                    DrawHalfStep(x,y);
+                    playsnd = false;
+
+                    RefreshMenuBuf (0);
+
+                    CursorNum++;
+                    if (CursorNum > (MAXCURSORNUM-1))
+                        CursorNum = 0;
+                }
+                else
+                {
+                    playsnd = true;
+                    RefreshMenuBuf (0);
+                }
+
+                do
+                {
+                    if (handlewhich==item_i->amount-1)
+                        handlewhich=0;
+                    else
+                        handlewhich++;
+                } while (((items+handlewhich)->active == CP_Inactive) || ((items+handlewhich)->active == CP_Active3));
+
+                if (playsnd)
+                    MN_PlayMenuSnd (SD_MOVECURSORSND);
+                ShowCursor(item_i,items,x,&y,handlewhich,basey);
+
+                if (routine)
+                    routine (handlewhich);
+
+                RefreshMenuBuf (0);
+                break;
+            default:
+                ;
+            }
+        }
+
+        ReadAnyControl (&ci);
+        if (ci.button0 || Keyboard[sc_Space] || Keyboard[sc_Enter])
+        {
+            exit = 1;
+            WaitKeyUp ();
+            MN_PlayMenuSnd (SD_SELECTSND);
+        }
+
+        if (ci.button1 || Keyboard[sc_Escape])
+        {
+            WaitKeyUp ();
+            exit = 2;
+        }
+
+        if ( ( Keyboard[ sc_Home ] ) && ( numactive > 1 ) )
+        {
+            newpos = 0;
+            while( ( items[ newpos ].active == CP_Inactive ) ||
+                    ( items[ newpos ].active == CP_Active3 ) )
+            {
+                newpos++;
+            }
+
+            if ( newpos != handlewhich )
+            {
+                HideCursor( item_i, items, x, y, handlewhich );
+
+                CursorNum++;
+                if ( CursorNum > ( MAXCURSORNUM - 1 ) )
+                {
+                    CursorNum = 0;
+                }
+
+                RefreshMenuBuf( 0 );
+
+                handlewhich = newpos;
+
+                MN_PlayMenuSnd( SD_MOVECURSORSND );
+
+                ShowCursor( item_i, items, x, &y, handlewhich, basey );
+
+                if ( routine )
+                {
+                    routine( handlewhich );
+                }
+
+                RefreshMenuBuf( 0 );
+            }
+        }
+        else if ( ( Keyboard[ sc_End ] ) && ( numactive > 1 ) )
+        {
+            newpos = item_i->amount - 1;
+            while( ( items[ newpos ].active == CP_Inactive ) ||
+                    ( items[ newpos ].active == CP_Active3 ) )
+            {
+                newpos--;
+            }
+
+            if ( newpos != handlewhich )
+            {
+                HideCursor( item_i, items, x, y, handlewhich );
+
+                CursorNum++;
+                if ( CursorNum > ( MAXCURSORNUM - 1 ) )
+                {
+                    CursorNum = 0;
+                }
+
+                RefreshMenuBuf( 0 );
+
+                handlewhich = newpos;
+
+                MN_PlayMenuSnd( SD_MOVECURSORSND );
+
+                ShowCursor( item_i, items, x, &y, handlewhich, basey );
+
+                if ( routine )
+                {
+                    routine( handlewhich );
+                }
+
+                RefreshMenuBuf( 0 );
+            }
+        }
+
+        // Page Up/Down
+        if ( MenuNum == 11 )
+        {
+            if ( ( Keyboard[ sc_PgUp ] ) &&
+                    ( ( items + 1 )->active != CP_Inactive ) )
+            {
+                item_i->curpos = handlewhich;
+                handlewhich = PAGEUP;
+                exit = 3;
+                MN_PlayMenuSnd( SD_SELECTSND );
+            }
+            else if ( ( Keyboard[ sc_PgDn ] ) &&
+                      ( ( items + 0 )->active != CP_Inactive ) )
+            {
+                item_i->curpos = handlewhich;
+                handlewhich = PAGEDOWN;
+                exit = 3;
+                MN_PlayMenuSnd( SD_SELECTSND );
+            }
+        }
+
+        // Delete save games
+        if ((MenuNum == 4) || (MenuNum == 6))
+        {
+            if (Keyboard[sc_Delete] && SaveGamesAvail[handlewhich])
+            {
+                if (CP_DisplayMsg ("Delete saved game?\nAre you sure?", 12) == true)
+                {
+                    char loadname[45] = "rottgam0.rot";
+                    char filename[128];
+
+                    // Create the proper file name
+                    itoa (handlewhich, &loadname[7], 16);
+                    loadname[8]='.';
+
+                    GetPathFromEnvironment( filename, ApogeePath, loadname );
+
+                    // Delete the file
+
+                    unlink (filename);
+
+                    memset (&SaveGameNames[handlewhich][0], 0, 32);
+                    SaveGamesAvail[handlewhich] = 0;
+                    if (handlewhich==quicksaveslot)
+                        quicksaveslot=-1;
+
+                    PrintX = LSM_X+LSItems.indent+2;
+                    PrintY = LSM_Y+handlewhich*9+2;
+                }
+                ScanForSavedGames ();
+
+                LSItems.curpos = handlewhich;
+                if (MenuNum == 4)
+                    DrawLoadSaveScreenAlt (1);
+                else
+                    DrawLoadSaveScreenAlt (0);
+                CP_DrawSelectedGame (handlewhich);
+            }
+        }
+
+
+#if SAVE_SCREEN
+        if (Keyboard[sc_CapsLock] && Keyboard[sc_C])
+        {
+            inhmenu=true;
+            SaveScreen (true);
+            inhmenu=false;
+        }
+        else if (Keyboard[sc_CapsLock] && Keyboard[sc_X])
+        {
+            inhmenu=true;
+            SaveScreen (false);
+            inhmenu=false;
+        }
+        else if (Keyboard[sc_CapsLock] && Keyboard[sc_Q])
+            Error ("Insta-Menu Quit!\n");
+#endif
+
+    } while (!exit);
+
+
+    IN_ClearKeysDown();
+
+    if (routine)
+        routine (handlewhich);
+
+    if ( exit != 3 )
+    {
+        item_i->curpos = handlewhich;
+    }
+
+    if (MenuNum == 3)
+    {
+        if (exit != 2)
+            CSTactive = handlewhich;
+        else
+            CSTactive = -1;
+    }
+
+    switch (exit)
+    {
+    case 1:
+        if ((items+handlewhich)->routine!=NULL)
+            (items+handlewhich)->routine(0);
+        return (handlewhich);
+
+    case 2:
+        MN_PlayMenuSnd (SD_ESCPRESSEDSND);
+        return (-1);
+
+    case 3:
+        return( handlewhich );
+    }
+
+
+    return (0);
+}
+
+//******************************************************************************
+//
+// HideCursor
+//
+//******************************************************************************
+void HideCursor
+(
+    CP_iteminfo *item_i,
+    CP_itemtype *items,
+    int x,
+    int y,
+    int which
+)
+
+{
+    int time = GetTicCount();
+    int color;
+    int delay;
+    int posx;
+    int posy;
+
+    if ( MenuNum != 5 )
+    {
+        EraseMenuBufRegion( x, y, cursorwidth, cursorheight );
+    }
+
+    if ( MenuNum && ( MenuNum != 4 ) && ( MenuNum != 6 ) )
+    {
+        posx = item_i->x + item_i->indent;
+        posy = item_i->y + ( which * yinc );
+
+        color = -1;
+        switch( items[ which ].active )
+        {
+        case CP_Inactive :
+            color = NOTAVAILABLECOLOR;
+            break;
+
+        case CP_CursorLocation :
+        case CP_Active :
+            color = NORMALCOLOR;
+            break;
+
+        case CP_SemiActive :
+            color = DIMMEDCOLOR;
+            break;
+
+        case CP_Highlight :
+            color = HIGHLIGHTCOLOR;
+            break;
+        }
+
+        if ( color != -1 )
+        {
+            if ( item_i->names == NULL )
+            {
+                DrawIMenuBufItem( posx, posy,
+                                  W_GetNumForName( items[ which ].texture ), color );
+            }
+            else
+            {
+                IFont = ( cfont_t * )W_CacheLumpName( FontNames[ item_i->fontsize ],
+                                                      PU_CACHE, Cvt_cfont_t, 1 );
+                if ( item_i->fontsize == mn_tinyfont )
+                {
+                    DrawMenuBufIString( posx + 1, posy, item_i->names[ which ], 0 );
+                }
+                DrawMenuBufIString( posx, posy - 1, item_i->names[ which ],
+                                    color );
+            }
+        }
+    }
+
+    if ( ( items[ which ].active != CP_Inactive ) &&
+            ( items[ which ].active != CP_SemiActive ) )
+    {
+        items[ which ].active = CP_Active;
+    }
+
+    delay = DELAYAMT - tics;
+    while( ( time + delay ) > GetTicCount() )
+    {
+        RefreshMenuBuf (0);
+    }
+}
+
+
+//******************************************************************************
+//
+// DrawHalfStep
+//
+//******************************************************************************
+
+void DrawHalfStep (int x, int y)
+{
+    MN_PlayMenuSnd (SD_MOVECURSORSND);
+    if (MenuNum == 5)
+        return;
+
+    DrawMenuBufItem (x, y, W_GetNumForName( CursorLump ) +
+                     CursorFrame[ CursorNum ] );
+}
+
+
+//******************************************************************************
+//
+// GetNumActive ()
+//
+//******************************************************************************
+
+int GetNumActive (CP_iteminfo *item_i, CP_itemtype *items)
+{
+    int cnt;
+    int num = 0;
+
+    for (cnt = 0; cnt < item_i->amount; cnt ++)
+    {
+        if ((items+cnt)->active != CP_Inactive)
+            num++;
+    }
+
+    return (num);
+}
+
+
+//******************************************************************************
+//
+// ShowCursor
+//    Draw triad at new position.
+//
+//******************************************************************************
+void ShowCursor
+(
+    CP_iteminfo *item_i,
+    CP_itemtype *items,
+    int x,
+    int *y,
+    int which,
+    int basey
+)
+
+{
+    int time = GetTicCount();
+    int delay;
+    int posx;
+    int posy;
+
+    if ( MenuNum )
+    {
+        EraseMenuBufRegion( x, *y, cursorwidth, cursorheight );
+        *y = basey + which * yinc;
+    }
+    else
+    {
+        *y = CUSTOM_y[ which ];
+    }
+
+    if ( MenuNum != 5 )
+    {
+        DrawMenuBufItem( x, *y, W_GetNumForName( CursorLump ) +
+                         CursorFrame[ CursorNum ] );
+    }
+
+    if ( items[ which ].active != CP_SemiActive )
+    {
+        if ( MenuNum && ( MenuNum != 4 ) && ( MenuNum != 6 ) )
+        {
+            posx = item_i->x + item_i->indent;
+            posy = item_i->y + which * yinc;
+
+            if ( item_i->names == NULL )
+            {
+                DrawIMenuBufItem( posx, posy,
+                                  W_GetNumForName( items[ which ].texture ), ACTIVECOLOR);
+            }
+            else
+            {
+                IFont = ( cfont_t * )W_CacheLumpName( FontNames[ item_i->fontsize ],
+                                                      PU_CACHE, Cvt_cfont_t, 1 );
+                if ( item_i->fontsize == mn_tinyfont )
+                {
+                    DrawMenuBufIString( posx + 1, posy, item_i->names[ which ], 0 );
+                }
+                DrawMenuBufIString( posx, posy - 1, item_i->names[ which ],
+                                    ACTIVECOLOR );
+            }
+        }
+
+        items[ which ].active = CP_CursorLocation;
+    }
+
+    delay = DELAYAMT - tics;
+    while( ( time + delay ) > GetTicCount() )
+    {
+        RefreshMenuBuf( 0 );
+    }
+}
+
+//******************************************************************************
+//
+// DrawOrderInfo()
+//
+//******************************************************************************
+
+void DrawOrderInfo
+(
+    int which
+)
+
+{
+    int start;
+    char *lumpname;
+
+    start = W_GetNumForName( "ORDRSTRT" ) + 1;
+
+    lumpname = W_GetNameForNum( start + which );
+
+    // Screen shots are grabbed as pics
+    if ( lumpname[ 0 ] == 'S' )
+    {
+        VWB_DrawPic( 0, 0, ( pic_t * )W_CacheLumpNum( start + which, PU_CACHE, Cvt_pic_t, 1 ) );
+    }
+    else
+    {
+        VL_DrawPostPic( W_GetNumForName( "trilogo" ) );
+        DrawNormalSprite( 0, 0, start );
+        DrawNormalSprite( 0, 0, start + which );
+    }
+
+    VW_UpdateScreen();
+}
+
+
+//******************************************************************************
+//
+// CP_OrderInfo()
+//
+//******************************************************************************
+
+void CP_OrderInfo
+(
+    void
+)
+
+{
+    int maxpage;
+    int page;
+    int key;
+    boolean newpage;
+
+
+
+    maxpage = W_GetNumForName( "ORDRSTOP" ) - W_GetNumForName( "ORDRSTRT" ) - 2;
+    newpage = false;
+    page = 1;
+
+    do
+    {
+        EnableScreenStretch();//bna++
+        DrawOrderInfo( page );
+        DisableScreenStretch();//bna++ turn off or screen will be strected every time it passes VW_UpdateScreen
+        if ( newpage )
+        {
+            while( Keyboard[ key ] )
+            {
+                VW_UpdateScreen();
+                IN_UpdateKeyboard ();
+            }
+        }
+
+        LastScan=0;
+        while( LastScan == 0 )
+        {
+            VW_UpdateScreen();
+            IN_UpdateKeyboard ();
+        }
+
+        key = LastScan;
+        switch( key )
+        {
+        case sc_Home :
+            if ( page != 1 )
+            {
+                page = 1;
+                newpage = true;
+                MN_PlayMenuSnd( SD_MOVECURSORSND );
+            }
+            break;
+
+        case sc_End :
+            if ( page != maxpage )
+            {
+                page = maxpage;
+                newpage = true;
+                MN_PlayMenuSnd( SD_MOVECURSORSND );
+            }
+            break;
+
+        case sc_PgUp :
+        case sc_UpArrow :
+        case sc_LeftArrow :
+            if ( page > 1 )
+            {
+                page--;
+                newpage = true;
+                MN_PlayMenuSnd( SD_MOVECURSORSND );
+            }
+            break;
+
+        case sc_PgDn :
+        case sc_DownArrow :
+        case sc_RightArrow :
+            if ( page < maxpage )
+            {
+                page++;
+                newpage = true;
+                MN_PlayMenuSnd( SD_MOVECURSORSND );
+            }
+            break;
+        }
+    }
+    while( key != sc_Escape );
+
+    Keyboard[ key ] = 0;
+    LastScan = 0;
+    EnableScreenStretch();//bna++
+    MN_PlayMenuSnd( SD_ESCPRESSEDSND );
+}
+
+
+//******************************************************************************
+//
+// CP_ViewScores ()
+//
+//******************************************************************************
+
+void CP_ViewScores (void)
+{
+    CheckHighScore (0, 0, true);
+}
+
+
+//******************************************************************************
+//
+// CP_Quit () - QUIT THIS INFERNAL GAME!
+//
+//******************************************************************************
+void CP_Quit ( int which )
+{
+    int num = 100;
+    static int oldnum;
+
+    while ((num >= 7) || (oldnum == num))
+        num = (RandomNumber ("CP_QUIT", 0) & 7);
+
+    oldnum = num;
+
+    if (CP_DisplayMsg (endStrings[num], num))
+    {
+        int handle;
+
+        MU_FadeOut(310);
+        handle=SD_Play(SD_QUIT1SND+num);
+        VL_FadeOut (0, 255, 0, 0, 0, 10);
+        CleanUpControlPanel();
+        SD_WaitSound (handle);
+        QuitGame ();
+    }
+
+    if ( which != -1 )
+    {
+        ClearMenuBuf();
+        DrawMainMenu();
+        DrawMenuBufItem (MainItems.x,  ((MainItems.curpos*14)+(MainItems.y-2)),
+                         W_GetNumForName ( LargeCursor ) + CursorFrame[ CursorNum ] );
+        RefreshMenuBuf (0);
+    }
+}
+
+//******************************************************************************
+//
+// CP_DisplayMsg ()
+//
+//******************************************************************************
+
+boolean CP_DisplayMsg
+(
+    char *s,
+    int number
+)
+
+{
+#define Q_W    184
+#define Q_H    72
+#define Q_X    ((320-Q_W)/2)-18
+#define Q_Y    ((200-Q_H)/2)-33
+
+#define Q_b1X  (Q_X+85)
+#define Q_b2X  (Q_X+135)
+#define Q_bY   (Q_Y+45)
+#define Q_bW   33
+#define Q_bH   10
+
+#define W_X    72
+#define W_Y    11
+#define W_W    102
+
+#define YES    "q_yes\0"
+#define NO     "q_no\0"
+
+    ControlInfo ci;
+    boolean retval;
+    boolean done;
+    boolean YESON;
+    boolean redraw;
+    boolean blowout;
+    char   *temp;
+    char   *active;
+    char   *inactive;
+    int     activex;
+    int     inactivex;
+    int     W_H = 0;
+    int     L_Y = 0;
+    int     tri;
+    int     QUITPIC;
+    int     t;
+
+    W_H = 1;
+    retval  = false;
+    done    = false;
+    YESON   = true;
+    redraw  = false;
+    blowout = false;
+
+    IN_ClearKeysDown();
+    IN_IgnoreMouseButtons();
+
+
+    QUITPIC = W_GetNumForName( "quitpic" );
+
+    if ( number < 11 )
+    {
+        tri = W_GetNumForName( "QUIT01" ) + number;
+        MN_PlayMenuSnd( SD_WARNINGBOXSND );
+    }
+    else
+    {
+        if ( number == 11 )
+        {
+            tri = W_GetNumForName( "tri1pic" );
+            MN_PlayMenuSnd( SD_INFOBOXSND );
+        }
+        else
+        {
+            if ( number == 12 )
+            {
+                tri = W_GetNumForName( "tri2pic" );
+                MN_PlayMenuSnd( SD_QUESTIONBOXSND );
+            }
+            if ( number == 13 )
+            {
+                tri = W_GetNumForName( "tri1pic" );
+                MN_PlayMenuSnd( SD_WARNINGBOXSND );
+            }
+        }
+    }
+
+    DrawMenuBufPic( Q_X, Q_Y, QUITPIC );
+    DrawMenuBufPic( Q_X + 12, Q_Y + 11, tri );
+
+    temp = s;
+    while( *temp )
+    {
+        if ( *temp == '\n' )
+        {
+            W_H++;
+        }
+        temp++;
+    }
+
+    CurrentFont = tinyfont;
+    W_H = ( W_H * CurrentFont->height ) + 3;
+
+    WindowX = Q_X + W_X;
+    WindowY = L_Y + 2;
+    L_Y     = Q_Y + W_Y;
+    PrintX  = WindowX;
+    PrintY  = WindowY;
+
+    WindowW = W_W;
+    WindowH = W_H;
+
+    redraw = true;
+
+    IFont = ( cfont_t * )W_CacheLumpName( FontNames[ mn_smallfont ],
+                                          PU_CACHE, Cvt_cfont_t, 1 );
+    /*
+       DrawSTMenuBuf( WindowX, L_Y, W_W, W_H, false );
+       MenuBufCPrint( s );
+
+       DrawSTMenuBuf( Q_b1X, Q_bY, Q_bW, Q_bH, false );
+       DrawMenuBufIString( Q_b1X + 3, Q_Y + 46, "YES", NORMALCOLOR );
+    //   DrawIMenuBufItem (PrintX, PrintY, W_GetNumForName (YES), NORMALCOLOR);
+
+       DrawSTMenuBuf( Q_b2X, Q_bY, Q_bW, Q_bH, true );
+       DrawMenuBufIString( Q_b2X + 2, Q_Y + 45, "NO", ACTIVECOLOR );
+    //   DrawIMenuBufItem (PrintX, PrintY, W_GetNumForName (NO), ACTIVECOLOR);
+    */
+    if (number != 13)
+    {
+        while ( !done )
+        {
+            RefreshMenuBuf( 0 );
+
+            ReadAnyControl( &ci );
+
+            if ( ( ci.dir == dir_West ) && ( !YESON ) )
+            {
+                MN_PlayMenuSnd( SD_MOVECURSORSND );
+                YESON = 1;
+                redraw = true;
+            }
+            else if ( ( ci.dir == dir_East ) && ( YESON ) )
+            {
+                MN_PlayMenuSnd( SD_MOVECURSORSND );
+                YESON = 0;
+                redraw = true;
+            }
+
+            if ( Keyboard[ sc_Y ] )
+            {
+                YESON  = 1;
+                redraw = true;
+                Keyboard[ sc_Enter ] = true;
+                blowout = true;
+            }
+            else if ( Keyboard[ sc_N ] )
+            {
+                YESON  = 0;
+                redraw = true;
+                Keyboard[ sc_Enter ] = true;
+                blowout = true;
+            }
+
+            if ( redraw )
+            {
+                redraw = false;
+
+                DrawMenuBufPic( Q_X, Q_Y, QUITPIC );
+                DrawMenuBufPic( Q_X + 12, Q_Y + 11, tri );
+
+                PrintX = Q_X + W_X;
+                PrintY = Q_Y + W_Y + 2;
+                DrawSTMenuBuf( WindowX, L_Y, W_W, W_H, false );
+                CurrentFont = tinyfont;
+                MenuBufCPrint( s );
+
+                if ( YESON )
+                {
+                    active    = "YES";
+                    inactive  = "NO";
+                    activex   = Q_b1X;
+                    inactivex = Q_b2X;
+                }
+                else
+                {
+                    active    = "NO";
+                    inactive  = "YES";
+                    activex   = Q_b2X;
+                    inactivex = Q_b1X;
+                }
+
+                DrawSTMenuBuf( activex, Q_bY, Q_bW, Q_bH, false );
+                DrawMenuBufIString( activex + 3, Q_Y + 46, active, ACTIVECOLOR );
+//         DrawIMenuBufItem (PrintX, PrintY, W_GetNumForName (YES), NORMALCOLOR);
+
+                DrawSTMenuBuf( inactivex, Q_bY, Q_bW, Q_bH, true );
+                DrawMenuBufIString( inactivex + 2, Q_Y + 45, inactive, NORMALCOLOR );
+//         DrawIMenuBufItem (PrintX, PrintY, W_GetNumForName (NO), ACTIVECOLOR);
+
+                for( t = 0; t < 5; t++ )
+                {
+                    RefreshMenuBuf( 0 );
+                }
+            }
+
+            if ( ( Keyboard[ sc_Space ] || Keyboard[ sc_Enter ] ||
+                    ci.button0 ) && YESON )
+            {
+                done   = true;
+                retval = true;
+                MN_PlayMenuSnd( SD_SELECTSND );
+                CP_Acknowledge = CP_YES;
+            }
+            else if ( Keyboard[ sc_Escape ] || ci.button1 )
+            {
+                done   = true;
+                retval = false;
+                CP_Acknowledge = CP_ESC;
+                MN_PlayMenuSnd( SD_ESCPRESSEDSND );
+            }
+            else if ( ( Keyboard[ sc_Space ] || Keyboard[ sc_Enter ] ||
+                        ci.button0 ) && !YESON )
+            {
+                done   = true;
+                retval = false;
+                CP_Acknowledge = CP_NO;
+
+                if ( Keyboard[ sc_N ] )
+                {
+                    MN_PlayMenuSnd( SD_SELECTSND );
+                }
+                else
+                {
+                    MN_PlayMenuSnd( SD_ESCPRESSEDSND );
+                }
+            }
+        }
+
+        while( ( Keyboard[ sc_Enter ] || Keyboard[ sc_Space ] ||
+                 Keyboard[ sc_Escape ] ) && !blowout )
+        {
+            IN_UpdateKeyboard();
+            RefreshMenuBuf( 0 );
+        }
+    }
+    else
+    {
+        PrintX = Q_X + W_X;
+        PrintY = Q_Y + W_Y + 2;
+        DrawSTMenuBuf( WindowX, L_Y, W_W, W_H, false );
+        CurrentFont = tinyfont;
+        MenuBufCPrint( s );
+        LastScan=0;
+        while (LastScan == 0)
+        {
+            IN_UpdateKeyboard();
+            RefreshMenuBuf( 0 );
+        }
+        LastScan = 0;
+    }
+    IN_ClearKeysDown();
+    return( retval );
+}
+
+
+//******************************************************************************
+//
+// EndGameStuff ()
+//
+//******************************************************************************
+
+void EndGameStuff (void)
+{
+    Z_FreeTags( PU_LEVELSTRUCT, PU_LEVELEND );
+
+    pickquick = false;
+    CheckHighScore (gamestate.score, gamestate.mapon+1, true);
+    locplayerstate->lives = 0;
+    playstate = ex_died;
+    damagecount = 0;
+    SetBorderColor (0);
+
+    AdjustMenuStruct ();
+    ingame = false;
+
+    GamePaused  = false;
+}
+
+
+//******************************************************************************
+//
+// START A NEW GAME
+//
+//******************************************************************************
+
+#define CURGAME   "You are currently in\n"\
+      "a game. Continuing will\n"\
+      "erase old game. Ok?\0"
+
+int ToughMenuNum;
+
+void CP_NewGame
+(
+    void
+)
+
+{
+    int which;
+
+#if ( SHAREWARE == 1 )
+    ToughMenuNum = 0;
+#else
+    int temp;
+
+    temp = ToughMenuNum;
+
+    while( ToughMenuNum == temp )
+    {
+        temp = ( ( RandomNumber( "TOUGH MENU", 0 ) ) & 3 );
+        if ( temp == 3 )
+        {
+            temp = 1;
+        }
+    }
+
+    ToughMenuNum = temp;
+#endif
+
+    //
+    // ALREADY IN A GAME?
+    //
+    if ( ingame )
+    {
+        if ( !CP_DisplayMsg( CURGAME, 12 ) )
+        {
+            return;
+        }
+        else
+        {
+            EndGameStuff();
+        }
+    }
+    else
+    {
+        handlewhich = 100;
+    }
+
+    if ( CP_PlayerSelection() == 0 )
+    {
+        return;
+    }
+
+    TufMenu[ ToughMenuNum ][ 0 ].active = CP_Active;
+    TufMenu[ ToughMenuNum ][ 2 ].active = CP_Active;
+    TufMenu[ ToughMenuNum ][ 4 ].active = CP_Active;
+    TufMenu[ ToughMenuNum ][ 6 ].active = CP_Active;
+
+    switch( DefaultDifficulty )
+    {
+    case gd_baby :
+        TufItems.curpos = 0;
+        break;
+
+    case gd_easy :
+        TufItems.curpos = 2;
+        break;
+
+    case gd_medium :
+        TufItems.curpos = 4;
+        break;
+
+    case gd_hard :
+        TufItems.curpos = 6;
+        break;
+
+    default :
+        TufItems.curpos = 0;
+        break;
+    }
+
+    TufMenu[ ToughMenuNum ][ TufItems.curpos ].active = CP_CursorLocation;
+
+    DrawNewGame();
+
+    which = HandleMenu( &TufItems, &TufMenu[ ToughMenuNum ][ 0 ],
+                        DrawNewGameDiff );
+
+    if ( which < 0 )
+    {
+        handlewhich = 1;
+        return;
+    }
+
+    handlewhich = 0;
+
+    switch( which )
+    {
+    case 0 :
+        DefaultDifficulty = gd_baby;
+        break;
+
+    case 2 :
+        DefaultDifficulty = gd_easy;
+        break;
+
+    case 4 :
+        DefaultDifficulty = gd_medium;
+        break;
+
+    case 6 :
+        DefaultDifficulty = gd_hard;
+        break;
+    }
+
+    MainMenu[ savegame ].active = CP_Active;
+
+    gamestate.battlemode = battle_StandAloneGame;
+    StartGame = true;
+    DisableScreenStretch();
+    playstate = ex_resetgame;
+
+
+}
+
+//******************************************************************************
+//
+// CP_EndGame ()
+//
+//******************************************************************************
+
+#define ENDGAMESTR   "Are you sure you want\n"\
+               "to end the game you\n"\
+               "are playing? (Y or N):"
+
+void CP_EndGame
+(
+    void
+)
+
+{
+    boolean action;
+
+    SetMenuTitle( "End Game" );
+    action = CP_DisplayMsg( ENDGAMESTR, 12 );
+
+    StartGame = false;
+    EnableScreenStretch();
+    if ( action )
+    {
+        EndGameStuff ();
+        pickquick = false;
+    }
+}
+
+//******************************************************************************
+//
+// AdjustMenuStruct ()
+//
+//******************************************************************************
+void AdjustMenuStruct
+(
+    void
+)
+
+{
+    MainMenu[ savegame ].active         = CP_Inactive;
+    MainMenu[ viewscores ].routine      = ( void * )CP_ViewScores;
+    MainMenu[ viewscores ].texture[ 6 ] = '7';
+    MainMenu[ viewscores ].texture[ 7 ] = '\0';
+    MainMenu[ viewscores ].letter       = 'V';
+    strcpy (MainMenuNames[ viewscores ], "VIEW SCORES");
+}
+
+//******************************************************************************
+//
+// CP_DrawSelectedGame
+//
+//******************************************************************************
+
+void CP_DrawSelectedGame (int w)
+{
+    gamestorage_t game;
+
+    if (SaveGamesAvail[w])
+    {
+        GetSavedHeader(w,&game);
+
+        DrawStoredGame(&game.picture[0],game.episode,game.area);
+    }
+    else
+        EraseMenuBufRegion(SaveGamePicX,SaveGamePicY,160,124);
+}
+
+//******************************************************************************
+//
+// DrawStoredGame
+//
+//******************************************************************************
+
+void DrawStoredGame ( byte * pic, int episode, int area )
+{
+    char str[3];
+    int level;
+    byte *shape;
+
+    shape = W_CacheLumpNum (W_GetNumForName ("newfnt1"), PU_CACHE, Cvt_font_t, 1);
+    newfont1 = (font_t *)shape;
+    CurrentFont = newfont1;
+    EraseMenuBufRegion (74, 128, 85, 14);
+
+    DrawMenuBufPropString (74, 128, "E");
+
+    itoa (episode, str, 10);
+    DrawMenuBufPropString (87, 128, str);
+
+    DrawMenuBufPropString (103, 128, "A");
+
+    if (episode > 1)
+        level = (area+1) - ((episode-1) << 3);
+    else
+        level = area+1;
+
+    ltoa (level, str, 10);
+    DrawMenuBufPropString (117, 128, str);
+    CurrentFont = tinyfont;
+
+    DrawMenuBufPicture(SaveGamePicX,SaveGamePicY,pic,160,100);
+}
+
+
+
+//******************************************************************************
+//
+// DoLoad ()
+//
+//******************************************************************************
+
+int DoLoad (int which)
+{
+    gamestorage_t game;
+    int exit = 0;
+
+    if ((which >= 0) && SaveGamesAvail[which])
+    {
+        loadedgame = true;
+
+        if (loadsavesound)
+            MN_PlayMenuSnd (SD_SELECTSND);
+
+        if (LoadTheGame (which, &game) == true)
+        {
+            MenuFixup ();
+            DisableScreenStretch();
+            StartGame = true;
+            exit      = 1;
+        }
+        else
+        {
+            if (CP_DisplayMsg ("Saved Game is\n old or incompatible\nDelete it?", 12)==true)
+            {
+                char loadname[45] = "rottgam0.rot";
+                char filename[128];
+
+                // Create the proper file name
+                itoa (which, &loadname[7], 16);
+                loadname[8]='.';
+
+                GetPathFromEnvironment( filename, ApogeePath, loadname );
+
+                // Delete the file
+
+                unlink (filename);
+
+                memset (&SaveGameNames[which][0], 0, 32);
+                SaveGamesAvail[which] = 0;
+            }
+
+            loadedgame = false;
+            DrawLoadSaveScreenAlt (0);
+        }
+    }
+
+    return (exit);
+}
+
+
+//******************************************************************************
+//
+// LOAD SAVED GAMES
+//
+//******************************************************************************
+
+int CP_LoadGame (int quick, int dieload)
+{
+    int which,
+        exit = 0;
+
+
+    MenuNum = 6;
+
+    SaveTime = GetTicCount();
+
+    //
+    // QUICKLOAD?
+    //
+    if (quick)
+    {
+        which = LSItems.curpos;
+
+        if (SaveGamesAvail[which])
+        {
+            if (dieload)
+            {
+                DrawLoadSaveScreenAlt (0);
+                CP_DrawSelectedGame (which);
+                RefreshMenuBuf (0);
+                DoLoad (which);
+
+                return (1);
+            }
+            else
+            {
+                DrawLoadSaveScreen (0);
+                if (CP_DisplayMsg ("Quick load saved game?\nAre you sure?", 12) == true)
+                {
+                    DrawLoadSaveScreen (0);
+                    CP_DrawSelectedGame (which);
+                    RefreshMenuBuf (0);
+                    DoLoad (which);
+
+                    return (1);
+                }
+                else
+                {
+                    return (0);
+                }
+            }
+        }
+    }
+
+    DrawLoadSaveScreen (0);
+    do
+    {
+        which = HandleMenu (&LSItems, &LSMenu[0], CP_DrawSelectedGame);
+
+        if ((exit = DoLoad (which)))
+            break;
+
+    } while (which >= 0);
+
+    handlewhich = OUTOFRANGE;
+
+    if (MainMenu[loadgame].active == CP_Inactive)    // If all the saved games have been
+    {
+        MainItems.curpos = 0;               //  deleted dehighlight LOADGAME
+        MainMenu[newgame].active = CP_CursorLocation;
+    }
+
+    return exit;
+}
+
+//******************************************************************************
+//
+// QuickSaveGame ()
+//
+//******************************************************************************
+
+void QuickSaveGame (void)
+{
+    int i;
+    int j;
+    byte * b;
+    byte * s;
+    int which;
+    gamestorage_t game;
+    byte * buf;
+    int length;
+
+    char   loadname[45]="rottgam0.rot";
+    char   filename[128];
+
+    // Create the proper file name
+
+    itoa(quicksaveslot,&loadname[7],16);
+    loadname[8]='.';
+
+    GetPathFromEnvironment( filename, ApogeePath, loadname );
+    length=LoadFile(filename,(void **)&buf);
+    GetPathFromEnvironment( filename, ApogeePath, QUICKSAVEBACKUP );
+    SaveFile(filename,buf,length);
+    SafeFree(buf);
+
+    s=&game.picture[0];
+    for (i=0; i<320; i+=2)
+    {
+#ifdef DOS
+        VGAREADMAP(i&3);
+        b=(byte *)bufferofs+(i>>2);
+        for (j=0; j<100; j++,s++,b+=iGLOBAL_SCREENBWIDE<<1)
+            *s=*b;
+#else
+        b=(byte *)bufferofs+i;
+        for (j=0; j<100; j++,s++,b+=(iGLOBAL_SCREENWIDTH<<1))
+            *s=*b;
+#endif
+    }
+
+    ScanForSavedGames ();
+    which = quicksaveslot;
+
+    if (SaveGamesAvail[which])
+    {
+        game.episode = gamestate.episode;
+        game.area    = gamestate.mapon;
+        game.version = ROTTVERSION;
+        strcpy (game.message, &SaveGameNames[which][0]);
+
+        if (SaveTheGame (which, &game) == true)
+        {
+            char str[50];
+
+            strcpy (str, "Game Saved: ");
+            strcat (str, &SaveGameNames[which][0]);
+            AddMessage(str,MSG_SYSTEM);
+        }
+        else
+        {
+            AddMessage("Game Not Saved.",MSG_SYSTEM);
+        }
+    }
+    else
+    {
+        AddMessage("No Quick Save Slot.",MSG_SYSTEM);
+    }
+
+}
+
+//******************************************************************************
+//
+// UndoQuickSaveGame ()
+//
+//******************************************************************************
+
+void UndoQuickSaveGame (void)
+{
+    byte * buf;
+    char   loadname[45]="rottgam0.rot";
+    char   filename[128];
+    int length;
+
+    if (quicksaveslot!=-1)
+    {
+        // Create the proper file name
+
+        itoa(quicksaveslot,&loadname[7],16);
+        loadname[8]='.';
+        GetPathFromEnvironment( filename, ApogeePath, QUICKSAVEBACKUP );
+        length=LoadFile(filename,(void **)&buf);
+        GetPathFromEnvironment( filename, ApogeePath, loadname );
+        SaveFile(filename,buf,length);
+        SafeFree(buf);
+        AddMessage("Previous Quicksave Game Restored.",MSG_SYSTEM);
+    }
+    else
+    {
+        AddMessage("No Quick Save Slot Selected.",MSG_SYSTEM);
+    }
+}
+
+
+//******************************************************************************
+//
+// SAVE CURRENT GAME
+//
+//******************************************************************************
+int CP_SaveGame ( void )
+{
+    int  which,
+         exit=0;
+
+    char input[32];
+    gamestorage_t game;
+
+
+    MenuNum = 4;
+
+
+    DrawLoadSaveScreen (1);
+
+    do
+    {
+        which = HandleMenu (&LSItems, &LSMenu[0], CP_DrawSelectedGame);
+        if (which >= 0)
+        {
+            //
+            // OVERWRITE EXISTING SAVEGAME?
+            //
+            if (SaveGamesAvail[which]) {
+                if (!CP_DisplayMsg (GAMESVD, 12))
+                {
+                    DrawLoadSaveScreenAlt (1);
+                    continue;
+                }
+                else
+                {
+                    DrawLoadSaveScreenAlt (1);
+                    EraseMenuBufRegion (LSM_X+LSItems.indent, LSM_Y+1+which*9, 80, 8);
+                    PrintLSEntry (which);
+                }
+            }
+            quicksaveslot=which;
+
+            DrawStoredGame (savedscreen, gamestate.episode, gamestate.mapon);
+
+            strcpy (input, &SaveGameNames[which][0]);
+
+            if (!SaveGamesAvail[which])
+                EraseMenuBufRegion (LSM_X+LSItems.indent+1, LSM_Y+which*9+2,
+                                    77, 6);
+
+            if (US_LineInput (LSM_X+LSItems.indent+2, LSM_Y+which*9+2,
+                              input, input, true, 22, 75, 0))
+            {
+                SaveGamesAvail[which] = 1;
+                memcpy(&game.picture[0],savedscreen,16000);
+                game.episode=gamestate.episode;
+                game.area=gamestate.mapon;
+                game.version=ROTTVERSION;
+                strcpy (game.message, input);
+                strcpy (&SaveGameNames[which][0], input);
+
+                if (SaveTheGame(which,&game)==true)
+                {
+                    MainMenu[loadgame].active=CP_Active;
+
+//               MN_PlayMenuSnd (SD_SELECTSND);
+                    exit = 1;
+                }
+                WaitKeyUp ();
+            }
+            else
+            {
+                EraseMenuBufRegion (LSM_X+LSItems.indent+1, LSM_Y+which*9+2,
+                                    77, 6);
+
+                PrintX = LSM_X+LSItems.indent+2;
+                PrintY = LSM_Y+which*9+2;
+
+                if (SaveGamesAvail[which])
+                    DrawMenuBufPropString (PrintX, PrintY, SaveGameNames[which]);
+                else
+                    DrawMenuBufPropString (PrintX, PrintY, "     - � -");
+
+//            MN_PlayMenuSnd (SD_ESCPRESSEDSND);
+                continue;
+            }
+            break;
+        }
+
+    } while (which >= 0);
+
+    handlewhich = OUTOFRANGE;
+
+    return (exit);
+}
+
+
+
+//******************************************************************************
+//
+// DEFINE CONTROLS
+//
+//******************************************************************************
+
+void CP_Control (void)
+{
+#define CTL_SPC   70
+
+    int which;
+
+    DrawCtlScreen ();
+    WaitKeyUp ();
+
+    do
+    {
+        which = HandleMenu (&CtlItems, &CtlMenu[0], NULL);
+
+        switch (CSTactive)
+        {
+        case MOUSEENABLE:
+            if (MousePresent)
+            {
+                mouseenabled^=1;
+                DrawCtlButtons ();
+                CusItems.curpos=-1;
+            }
+            else
+                mouseenabled = 0;
+            break;
+
+        case JOYENABLE:
+            joystickenabled^=1;
+            if ( joystickenabled )
+            {
+                if ( !CalibrateJoystick() )
+                {
+                    joystickenabled = 0;
+                    joypadenabled = 0;
+                }
+            }
+            else
+            {
+                joypadenabled = 0;
+            }
+            DrawCtlScreen();
+            break;
+
+        case USEPORT2:
+            joystickport^=1;
+            if ( joystickport )
+            {
+                joypadenabled = 0;
+            }
+
+            joystickenabled = 1;
+            if ( !CalibrateJoystick() )
+            {
+                joystickenabled = 0;
+                joystickport = 0;
+            }
+
+            if ( joystickport )
+            {
+                CtlMenu[ 3 ].active = CP_Inactive;
+                joypadenabled = 0;
+            }
+            else
+            {
+                CtlMenu[ 3 ].active = CP_Active;
+            }
+
+            DrawCtlScreen();
+            break;
+
+        case PADENABLE:
+            joypadenabled^=1;
+            if ( ( joypadenabled ) && ( !joystickenabled ) )
+            {
+                joystickenabled=1;
+                if ( !CalibrateJoystick() )
+                {
+                    joystickenabled = 0;
+                    joypadenabled = 0;
+                }
+
+                DrawCtlScreen();
+            }
+            else
+            {
+                DrawCtlButtons ();
+            }
+            break;
+
+        case SPACEBALLENABLE:
+            spaceballenabled ^= 1;
+            DrawCtlButtons ();
+            break;
+
+        case CYBERMANENABLE:
+            cybermanenabled ^= 1;
+            DrawCtlButtons ();
+            break;
+
+        case THRESSENS:
+        case MOUSESENS:
+        case CUSTOMIZE:
+            DrawCtlScreen ();
+            break;
+        }
+
+    } while (which >= 0);
+
+    DrawControlMenu ();
+
+    if (which < 0)
+    {
+        handlewhich = 1;
+        return;
+    }
+}
+
+
+//****************************************************************************
+//
+// CP_Custom ()
+//
+//****************************************************************************
+
+void CP_Custom (void)
+{
+    int which;
+
+    DrawCustomMenu();
+
+    do
+    {
+        which = HandleMenu (&CustomItems, &CustomMenu[0], NULL);
+    } while (which >= 0);
+
+    DrawCtlScreen ();
+}
+
+
+//******************************************************************************
+//
+// CUSTOMIZE CONTROLS
+//
+//******************************************************************************
+
+//****************************************************************************
+//
+// CP_Keyboard ()
+//
+//****************************************************************************
+void CP_Keyboard
+(
+    void
+)
+
+{
+    int which;
+
+    MenuNum = 1;
+
+    DrawCustomKeyboard ();
+
+    do
+    {
+        which = HandleMenu( &NormalKeyItems, &NormalKeyMenu[ 0 ], NULL );
+    }
+    while( which >= 0 );
+
+    DrawCustomMenu();
+}
+
+
+//******************************************************************************
+//
+// DEFINE THE KEYBOARD BUTTONS
+//
+//******************************************************************************
+
+void DefineKey
+(
+    void
+)
+
+{
+    boolean tick;
+    boolean picked;
+    int     timer;
+    int     x;
+    int     y;
+
+    tick   = false;
+    picked = false;
+    timer  = GetTicCount();
+
+    x = NORMALKEY_X + 97;
+    y = NORMALKEY_Y + ( handlewhich * FontSize[ NormalKeyItems.fontsize ] );
+
+    strcpy( &NormalKeyNames[ handlewhich ][ KEYNAMEINDEX ],
+            "     " );
+
+//   SetMenuTitle ( "Select which key to use" );
+    ClearMenuBuf();
+    DrawMenu( &NormalKeyItems, &NormalKeyMenu[ 0 ] );
+    DisplayInfo( 0 );
+
+    DrawMenuBufIString( x + 3, y, "?", 0 );
+    DrawMenuBufIString( x + 2, y - 1, "?", HIGHLIGHTCOLOR );
+
+    RefreshMenuBuf( 0 );
+
+    do
+    {
+
+        IN_PumpEvents();
+
+        //
+        // FLASH CURSOR
+        //
+        if ( ( GetTicCount() - timer ) > 10 )
+        {
+            int color;
+
+            if ( tick )
+            {
+                color = HIGHLIGHTCOLOR;
+            }
+            else
+            {
+                color = DIMMEDCOLOR;
+            }
+
+            DrawMenuBufIString( x + 3, y, "?", 0 );
+            DrawMenuBufIString( x + 2, y - 1, "?", color );
+
+            tick  = !tick;
+            timer = GetTicCount();
+        }
+
+        RefreshMenuBuf( 0 );
+
+
+        if ( LastScan )
+        {
+            int key;
+
+            key = LastScan;
+            LastScan = 0;
+
+            buttonscan[ (unsigned int)order[ handlewhich ] ] = key;
+
+            strcpy( &NormalKeyNames[ handlewhich ][ KEYNAMEINDEX ],
+                    IN_GetScanName( key ) );
+
+            picked = true;
+
+            WaitKeyUp();
+            Keyboard[ key ] = 0;
+
+            IN_ClearKeysDown();
+        }
+    }
+    while( !picked );
+
+    ClearMenuBuf();
+    SetMenuTitle( "Customize Keyboard" );
+
+    DrawMenu( &NormalKeyItems, &NormalKeyMenu[ 0 ] );
+    DisplayInfo( 0 );
+    RefreshMenuBuf (0);
+}
+
+//****************************************************************************
+//
+// DrawControlSelect ()
+//
+//****************************************************************************
+
+void DrawControlSelect
+(
+    void
+)
+
+{
+    MenuNum = 1;
+
+    SetAlternateMenuBuf();
+    ClearMenuBuf();
+    SetMenuTitle ("Select Button Function");
+
+    MN_GetCursorLocation( &ControlSelectItems, &ControlSelectMenu[ 0 ] );
+    DrawMenu( &ControlSelectItems, &ControlSelectMenu[ 0 ] );
+
+    DisplayInfo( 0 );
+    FlipMenuBuf();
+}
+
+
+//****************************************************************************
+//
+// DefineMouseBtn()
+//
+//****************************************************************************
+
+void DefineMouseBtn
+(
+    void
+)
+
+{
+    int button;
+    int which;
+
+    button = handlewhich;
+
+    MN_GetActive( &ControlSelectItems, &ControlSelectMenu[ 0 ],
+                  buttonmouse[ button ], controlorder );
+
+    DrawControlSelect();
+
+    which = HandleMenu( &ControlSelectItems, &ControlSelectMenu[ 0 ], NULL );
+    if ( which != -1 )
+    {
+        buttonmouse[ button ] = controlorder[ which ];
+    }
+
+    handlewhich = OUTOFRANGE;
+}
+
+//****************************************************************************
+//
+// CP_Mouse ()
+//
+//****************************************************************************
+void CP_Mouse
+(
+    void
+)
+
+{
+    int which;
+
+    MenuNum = 1;
+
+    do
+    {
+        DrawCustomMouse();
+        which = HandleMenu( &MouseBtnItems, &MouseBtnMenu[ 0 ], NULL );
+    }
+    while( which >= 0 );
+
+    handlewhich = OUTOFRANGE;
+
+    DrawCustomMenu();
+}
+
+
+//****************************************************************************
+//
+// DrawCustomMouse ()
+//
+//****************************************************************************
+
+void DrawCustomMouse
+(
+    void
+)
+
+{
+    int i;
+    int j;
+    int num;
+    int button;
+
+    SetAlternateMenuBuf();
+    ClearMenuBuf();
+    SetMenuTitle ("Customize Mouse");
+
+    for( i = 0; i < 6; i++ )
+    {
+        num = 0;
+        button = buttonmouse[ i ];
+        buttonmouse[ i ] = bt_nobutton;
+        MouseBtnNames[ i ][ MOUSEBTNINDEX ] = 0;
+
+        for( j = 0; j < NUMCONTROLNAMES; j++ )
+        {
+            if ( button == controlorder[ j ] )
+            {
+                buttonmouse[ i ] = button;
+                num = j;
+                break;
+            }
+        }
+
+        strcpy( &MouseBtnNames[ i ][ MOUSEBTNINDEX ],
+                ControlNames[ num ] );
+    }
+
+    MN_GetCursorLocation( &MouseBtnItems, &MouseBtnMenu[ 0 ] );
+    DrawMenu( &MouseBtnItems, &MouseBtnMenu[ 0 ] );
+
+    DisplayInfo( 0 );
+    FlipMenuBuf();
+}
+
+
+//****************************************************************************
+//
+// DefineJoyBtn()
+//
+//****************************************************************************
+
+void DefineJoyBtn
+(
+    void
+)
+
+{
+    int button;
+    int which;
+
+    button = handlewhich;
+
+    MN_GetActive( &ControlSelectItems, &ControlSelectMenu[ 0 ],
+                  buttonjoy[ button ], controlorder );
+
+    DrawControlSelect();
+
+    which = HandleMenu( &ControlSelectItems, &ControlSelectMenu[ 0 ], NULL );
+    if ( which != -1 )
+    {
+        buttonjoy[ button ] = controlorder[ which ];
+    }
+
+    handlewhich = OUTOFRANGE;
+}
+
+
+//****************************************************************************
+//
+// DrawCustomJoystick ()
+//
+//****************************************************************************
+
+void DrawCustomJoystick
+(
+    void
+)
+
+{
+    int i;
+    int j;
+    int num;
+    int button;
+    int active;
+
+    SetAlternateMenuBuf();
+    ClearMenuBuf();
+    SetMenuTitle ("Customize Joystick");
+
+    for( i = 0; i < 8; i++ )
+    {
+        num = 0;
+        button = buttonjoy[ i ];
+        buttonjoy[ i ] = bt_nobutton;
+        JoyBtnNames[ i ][ JOYBTNINDEX ] = 0;
+
+        for( j = 0; j < NUMCONTROLNAMES; j++ )
+        {
+            if ( button == controlorder[ j ] )
+            {
+                buttonjoy[ i ] = button;
+                num = j;
+                break;
+            }
+        }
+
+        strcpy( &JoyBtnNames[ i ][ JOYBTNINDEX ], ControlNames[ num ] );
+    }
+
+    JoyBtnMenu[ 0 ].active = CP_Active;
+    JoyBtnMenu[ 1 ].active = CP_Active;
+    JoyBtnMenu[ 4 ].active = CP_Active;
+    JoyBtnMenu[ 5 ].active = CP_Active;
+
+    if ( joypadenabled )
+    {
+        active = CP_Active;
+    }
+    else
+    {
+        active = CP_Inactive;
+    }
+
+    JoyBtnMenu[ 2 ].active = active;
+    JoyBtnMenu[ 3 ].active = active;
+    JoyBtnMenu[ 6 ].active = active;
+    JoyBtnMenu[ 7 ].active = active;
+
+    if ( JoyBtnMenu[ JoyBtnItems.curpos ].active == CP_Inactive )
+    {
+        MN_GetCursorLocation( &JoyBtnItems, &JoyBtnMenu[ 0 ] );
+    }
+    else
+    {
+        JoyBtnMenu[ JoyBtnItems.curpos ].active = CP_CursorLocation;
+    }
+
+    DrawMenu( &JoyBtnItems, &JoyBtnMenu[ 0 ] );
+
+    DisplayInfo( 0 );
+    FlipMenuBuf();
+}
+
+
+//****************************************************************************
+//
+// CP_Joystick ()
+//
+//****************************************************************************
+
+void CP_Joystick
+(
+    void
+)
+
+{
+    int which;
+
+    MenuNum = 1;
+
+    do
+    {
+        DrawCustomJoystick();
+        which = HandleMenu( &JoyBtnItems, &JoyBtnMenu[ 0 ], NULL );
+    }
+    while( which >= 0 );
+
+    handlewhich = OUTOFRANGE;
+
+    DrawCustomMenu();
+}
+
+
+//******************************************************************************
+//
+// PRINT A MESSAGE IN A WINDOW
+//
+//******************************************************************************
+
+void Message (char *string)
+{
+    int   h = 0,
+          w = 0,
+          mw = 0,
+          i;
+    byte *shape;
+
+    shape = W_CacheLumpNum (W_GetNumForName ("newfnt1"), PU_CACHE, Cvt_font_t, 1);
+    newfont1 = (font_t *)shape;
+    CurrentFont = newfont1;
+    h = CurrentFont->height;
+
+    for (i = 0; i < (int)strlen (string); i++)
+        if (string[i] == '\n')
+        {
+            if (w > mw)
+                mw = w;
+            w = 0;
+            h += CurrentFont->height;
+        }
+        else
+            w += CurrentFont->width[string[i]-31];
+
+    if ((w + 10) > mw)
+        mw = w+10;
+
+    PrintY = 78 - (h / 2);
+    PrintX = WindowX = 143 - (mw / 2);
+    WindowW = mw;
+
+    EraseMenuBufRegion (WindowX-5, PrintY-5, (mw+14)&0xFFFC, h+10);
+    DrawSTMenuBuf (WindowX-5, PrintY-5, (mw+14)&0xFFFC, h+10, true);
+
+    MenuBufCPrint (string);
+    RefreshMenuBuf (0);
+}
+
+
+
+//******************************************************************************
+//
+// DRAW NEW GAME MENU
+//
+//******************************************************************************
+
+void DrawNewGame (void)
+{
+    MenuNum = 5;
+
+    SetAlternateMenuBuf ();
+    ClearMenuBuf ();
+    SetMenuTitle ("Choose Difficulty");
+    DrawMenu (&TufItems, &TufMenu[ToughMenuNum][0]);
+    DrawNewGameDiff (TufItems.curpos);
+    DisplayInfo (0);
+    FlipMenuBuf();
+
+}
+
+//******************************************************************************
+//
+// DRAW NEW GAME GRAPHIC
+//
+//******************************************************************************
+
+int newgameY[7] = {19, 0, 42, 0, 74, 0, 93};
+char *DifficultyStrings[ 4 ] =
+{
+    "Easy", "Medium", "Hard", "Crezzy Man"
+};
+
+void DrawNewGameDiff
+(
+    int w
+)
+
+{
+    int x;
+
+    switch ( w )
+    {
+    case 0:
+        x = 0;
+        break;
+
+    case 2:
+        x = 1;
+        break;
+
+    case 4:
+        x = 2;
+        break;
+
+    case 6:
+        x = 3;
+        break;
+    }
+
+    EraseMenuBufRegion( 25, 18, 52, 125 );
+    DrawMenuBufPic( 25, newgameY[ w ], W_GetNumForName( "NEWG1" ) +
+                    ( ToughMenuNum * 4 ) + x );
+    EraseMenuBufRegion( 25, 149, 64, 8 );
+//   DrawMenuBufPic (25, 149, W_GetNumForName( "O_EASY" ) + x );
+
+    CurrentFont = tinyfont;
+    DrawMenuBufPropString( 25, 149, DifficultyStrings[ x ] );
+}
+
+
+//******************************************************************************
+//
+// DRAW THE LOAD/SAVE SCREEN
+//
+//******************************************************************************
+
+void DrawLoadSaveScreen (int loadsave)
+{
+    int i;
+    byte *shape;
+
+    shape = W_CacheLumpNum (W_GetNumForName ("newfnt1"), PU_CACHE, Cvt_font_t, 1);
+    newfont1 = (font_t *)shape;
+    CurrentFont = newfont1;
+
+    if (numdone || (!ingame) || (!inmenu))
+        SetAlternateMenuBuf();
+
+    ClearMenuBuf();
+    if (loadsave)
+    {
+        SetMenuTitle ("Save Game");
+    }
+    else
+    {
+        SetMenuTitle ("Load Game");
+    }
+
+    for (i = 0; i < NUMSAVEGAMES; i++)
+        PrintLSEntry (i);
+    DrawMenuBufItem (LSItems.x, ((LSItems.curpos*9)+(LSItems.y)),
+                     W_GetNumForName( SmallCursor ) + CursorFrame[ CursorNum ] );
+    DisplayInfo (7);
+    if ((!numdone) && ingame && inmenu)
+        RefreshMenuBuf (0);
+    else
+        FlipMenuBuf();
+
+    WaitKeyUp ();
+
+    numdone++;
+}
+
+//******************************************************************************
+//
+// DRAW THE LOAD/SAVE SCREEN - no flip
+//
+//******************************************************************************
+
+void DrawLoadSaveScreenAlt (int loadsave)
+{
+    int i;
+    byte *shape;
+
+    shape = W_CacheLumpNum (W_GetNumForName ("newfnt1"), PU_CACHE, Cvt_font_t, 1);
+    newfont1 = (font_t *)shape;
+    CurrentFont = newfont1;
+
+    ClearMenuBuf();
+    if (loadsave)
+    {
+        SetMenuTitle ("Save Game");
+    }
+    else
+    {
+        SetMenuTitle ("Load Game");
+    }
+
+    for (i = 0; i < NUMSAVEGAMES; i++)
+        PrintLSEntry (i);
+    DrawMenuBufItem (LSItems.x, ((LSItems.curpos*9)+(LSItems.y)),
+                     W_GetNumForName( SmallCursor ) + CursorFrame[ CursorNum ] );
+    DisplayInfo (7);
+    RefreshMenuBuf (0);
+
+    WaitKeyUp ();
+
+    numdone++;
+}
+
+
+//******************************************************************************
+//
+// PRINT LOAD/SAVE GAME ENTRY W/BOX OUTLINE
+//
+//******************************************************************************
+
+void PrintLSEntry (int w)
+{
+
+    DrawSTMenuBuf (LSM_X+LSItems.indent, LSM_Y+1+w*9, 80, 7, false);
+
+    PrintX = LSM_X+LSItems.indent+2;
+    PrintY = LSM_Y+(w*9)+2;
+
+    CurrentFont = tinyfont;
+
+    if (SaveGamesAvail[w])
+        DrawMenuBufPropString (PrintX, PrintY, SaveGameNames[w]);
+    else
+        DrawMenuBufPropString (PrintX, PrintY, "     - � -");
+}
+
+
+
+//******************************************************************************
+//
+// CALIBRATE JOYSTICK
+//
+//******************************************************************************
+int CalibrateJoystick
+(
+    void
+)
+
+{
+#define CALX   45
+#define CALY   22
+
+    word xmax, ymax, xmin, ymin, jb;
+    int  checkbits;
+    int  status;
+    boolean done;
+
+    if ( joypadenabled )
+    {
+        // Gravis GamePad : Check all buttons
+        checkbits = ( 1 << 0 ) + ( 1 << 1 ) + ( 1 << 2 ) + ( 1 << 3 );
+    }
+    else if ( joystickport )
+    {
+        // Joystick port 2 : check only buttons 2 and 3
+        checkbits = ( 1 << 2 ) + ( 1 << 3 );
+    }
+    else
+    {
+        // Joystick port 1 : check only buttons 0 and 1
+        checkbits = ( 1 << 0 ) + ( 1 << 1 );
+    }
+
+    status = 0;
+    done = false;
+    while( !done )
+    {
+        SetAlternateMenuBuf();
+        ClearMenuBuf();
+        SetMenuTitle ("Calibrate Joystick");
+        //DrawMenuBufItem( CALX, CALY, W_GetNumForName( "joystk2" ) );
+        WindowW = 288;
+        WindowH = 158;
+        PrintX = WindowX = 0;
+        PrintY = WindowY = 50;
+
+        newfont1 = (font_t *)W_CacheLumpName( "newfnt1", PU_CACHE, Cvt_font_t, 1 );
+        CurrentFont = newfont1;
+        MenuBufCPrint( "MOVE JOYSTICK TO\nUPPER LEFT AND\nPRESS A BUTTON." );
+
+        DisplayInfo( 2 );
+        FlipMenuBuf();
+
+        do
+        {
+            RefreshMenuBuf( 0 );
+            jb = IN_JoyButtons();
+            IN_UpdateKeyboard();
+
+            if ( Keyboard[ sc_Escape ] )
+            {
+                return( 0 );
+            }
+        }
+        while( !( jb & checkbits ) );
+
+        IN_GetJoyAbs( joystickport, &xmin, &ymin );
+        MN_PlayMenuSnd( SD_SELECTSND );
+
+        while( IN_JoyButtons() & checkbits )
+        {
+            IN_UpdateKeyboard();
+
+            if ( Keyboard[ sc_Escape ] )
+            {
+                return( 0 );
+            }
+        }
+
+        ClearMenuBuf();
+//      DrawMenuBufItem( CALX, CALY, W_GetNumForName( "joystk1" ) );
+        WindowW = 288;
+        WindowH = 158;
+        PrintX = WindowX = 0;
+        PrintY = WindowY = 50;
+
+        newfont1 = (font_t *)W_CacheLumpName( "newfnt1", PU_CACHE, Cvt_font_t, 1 );
+        CurrentFont = newfont1;
+        MenuBufCPrint( "MOVE JOYSTICK TO\nLOWER RIGHT AND\nPRESS A BUTTON." );
+
+        DisplayInfo( 2 );
+
+        do
+        {
+            RefreshMenuBuf( 0 );
+            jb = IN_JoyButtons();
+            IN_UpdateKeyboard();
+
+            if ( Keyboard[ sc_Escape ] )
+            {
+                return( 0 );
+            }
+        }
+        while( !( jb & checkbits ) );
+
+        IN_GetJoyAbs( joystickport, &xmax, &ymax );
+        MN_PlayMenuSnd( SD_SELECTSND );
+
+        while( IN_JoyButtons() & checkbits )
+        {
+            IN_UpdateKeyboard();
+
+            if ( Keyboard[ sc_Escape ] )
+            {
+                return( 0 );
+            }
+        }
+
+        //
+        // ASSIGN ACTUAL VALUES HERE
+        //
+        if ( ( xmin < xmax ) && ( ymin < ymax ) )
+        {
+            IN_SetupJoy( joystickport, xmin, xmax, ymin, ymax );
+            joyxmin = xmin;
+            joyxmax = xmax;
+            joyymin = ymin;
+            joyymax = ymax;
+
+            status = 1;
+            done = true;
+        }
+        else
+        {
+            CP_ErrorMsg( "Joystick Error",
+                         "Calibration failed.  The joystick must be moved "
+                         "to the upper-left first and then the lower-right.",
+                         mn_smallfont );
+        }
+    }
+
+    return( status );
+}
+
+
+//******************************************************************************
+//
+// ADJUST MOUSE SENSITIVITY
+//
+//******************************************************************************
+
+void MouseSensitivity
+(
+    void
+)
+
+{
+    SliderMenu( &mouseadjustment, 11, 0, 21, 81, 240, 1, "block1", NULL,
+                "Mouse Sensitivity", "Slow", "Fast" );
+}
+
+//******************************************************************************
+//
+// ADJUST MOUSE AND JOYSTICK THRESHOLD
+//
+//******************************************************************************
+
+void DoThreshold
+(
+    void
+)
+
+{
+    SliderMenu (&threshold, 15, 1, 44, 81, 194, 1, "block2", NULL,
+                "Adjust Threshold", "Small", "Large" );
+}
+
+//******************************************************************************
+//
+// DRAW CONTROL MENU SCREEN
+//
+//******************************************************************************
+
+void DrawCtlScreen (void)
+{
+    MenuNum = 3;
+
+    if (numdone || (!ingame) || (!inmenu))
+        SetAlternateMenuBuf();
+
+    ClearMenuBuf();
+    SetMenuTitle ("Options");
+
+
+    DrawCtlButtons ();
+
+    DisplayInfo (0);
+    DrawMenu (&CtlItems, &CtlMenu[0]);
+    DrawMenuBufItem (CtlItems.x, ((CtlItems.curpos*14)+(CtlItems.y-2)),
+                     W_GetNumForName( LargeCursor ) + CursorFrame[ CursorNum ] );
+
+    if (ingame && inmenu && (!numdone))
+        RefreshMenuBuf (0);
+    else
+        FlipMenuBuf();
+
+    numdone++;
+}
+
+
+//******************************************************************************
+//
+// DrawCtlButtons ()
+//
+//******************************************************************************
+
+void DrawCtlButtons (void)
+{
+    int i,
+        x,
+        y;
+    static boolean first = true;
+    int button_on;
+    int button_off;
+
+    button_on  = W_GetNumForName ("snd_on");
+    button_off = W_GetNumForName ("snd_off");
+
+    WindowX = 0;
+    WindowW = 320;
+
+    if (first)
+    {
+        if (JoysPresent[0] || JoysPresent[1])
+        {
+            CtlMenu[JOYENABLE].active = CP_Active;
+            CtlMenu[USEPORT2].active  = CP_Active;
+            CtlMenu[PADENABLE].active = CP_Active;
+            CtlMenu[THRESSENS].active = CP_Active;
+        }
+        else
+        {
+            joystickenabled = 0;
+            joypadenabled   = 0;
+            joystickport    = 0;
+        }
+
+        if (MousePresent)
+        {
+            CtlMenu[THRESSENS].active = CP_Active;
+            CtlMenu[MOUSESENS].active = CP_Active;
+            CtlMenu[MOUSEENABLE].active = CP_Active;
+        }
+        else
+        {
+            CtlMenu[0].active = CP_Inactive;
+            mouseenabled = 0;
+        }
+
+        if (SpaceBallPresent)
+            CtlMenu[SPACEBALLENABLE].active = CP_Active;
+
+        if (CybermanPresent)
+            CtlMenu[CYBERMANENABLE].active = CP_Active;
+
+        for (x = 0; x < CtlItems.amount; x++)
+        {
+            if (CtlMenu[x].active)
+            {
+                CtlMenu[x].active = CP_CursorLocation;
+                break;
+            }
+        }
+        first = false;
+    }
+
+    x = CTL_X+CtlItems.indent-18;
+    y = MENU_Y-1;
+
+    if (mouseenabled)
+        DrawMenuBufItem (x, y, button_on);
+    else
+    {
+        EraseMenuBufRegion (x, y, 16, 16);
+        DrawMenuBufItem  (x, y, button_off);
+    }
+
+    y += 14;
+    if (joystickenabled)
+        DrawMenuBufItem (x, y, button_on);
+    else
+    {
+        EraseMenuBufRegion (x, y, 16, 16);
+        DrawMenuBufItem (x, y, button_off);
+    }
+
+    y += 14;
+    if (joystickport)
+        DrawMenuBufItem (x, y, button_on);
+    else
+    {
+        EraseMenuBufRegion (x, y, 16, 16);
+        DrawMenuBufItem (x, y, button_off);
+    }
+
+    y += 14;
+    if (joypadenabled)
+        DrawMenuBufItem (x, y, button_on);
+    else
+    {
+        EraseMenuBufRegion (x, y, 16, 16);
+        DrawMenuBufItem (x, y, button_off);
+    }
+
+    y += 14;
+    if (spaceballenabled)
+        DrawMenuBufItem (x, y, button_on);
+    else
+    {
+        EraseMenuBufRegion (x, y, 16, 16);
+        DrawMenuBufItem (x, y, button_off);
+    }
+
+    y += 14;
+    if (cybermanenabled)
+        DrawMenuBufItem (x, y, button_on);
+    else
+    {
+        EraseMenuBufRegion (x, y, 16, 16);
+        DrawMenuBufItem (x, y, button_off);
+    }
+
+
+    if ((CtlItems.curpos < 0) || (!CtlMenu[CtlItems.curpos].active))
+        for (i = 0; i < CtlItems.amount; i++)
+            if (CtlMenu[i].active)
+            {
+                CtlItems.curpos = i;
+                break;
+            }
+
+}
+
+//******************************************************************************
+//
+// WAIT FOR CTRLKEY-UP OR BUTTON-UP
+//
+//******************************************************************************
+
+void WaitKeyUp (void)
+{
+    ControlInfo ci;
+
+    IN_IgnoreMouseButtons();
+    ReadAnyControl (&ci);
+
+    while (ci.button0 || ci.button1 || ci.button2 || ci.button3 ||
+            Keyboard[sc_Space] || Keyboard[sc_Enter] || Keyboard[sc_Escape])
+    {
+        ReadAnyControl (&ci);
+        RefreshMenuBuf (0);
+        if (Keystate[sc_CapsLock] && Keystate[sc_Q])
+            Error("Stuck in WaitKeyUp\n");
+    }
+}
+
+#define PMOUSE    3
+#define SMOUSE    4
+
+//******************************************************************************
+//
+// READ KEYBOARD, JOYSTICK AND MOUSE FOR INPUT
+//
+//******************************************************************************
+
+void ReadAnyControl (ControlInfo *ci)
+{
+
+#if PLATFORM_DOS
+    union REGS inregs;
+    union REGS outregs;
+#endif
+
+    int mouseactive = 0;
+    word buttons = 0;
+//   struct Spw_IntPacket packet;
+
+
+    IN_UpdateKeyboard ();  /* implies IN_PumpEvents() ... */
+    IN_ReadControl (0, ci);
+
+    if (MousePresent && mouseenabled)
+    {
+        int mousey,
+            mousex;
+
+#if USE_SDL
+        INL_GetMouseDelta(&mousex, &mousey);
+        if (mousex >= SENSITIVE)
+        {
+            ci->dir = dir_East;
+            mouseactive = 1;
+        }
+        else if (mousex <= -SENSITIVE)
+        {
+            ci->dir = dir_West;
+            mouseactive = 1;
+        }
+
+        if (mousey >= SENSITIVE)
+        {
+            ci->dir = dir_South;
+            mouseactive = 1;
+        }
+        else if (mousey <= -SENSITIVE)
+        {
+            ci->dir = dir_North;
+            mouseactive = 1;
+        }
+
+#elif PLATFORM_DOS
+        // READ MOUSE MOTION COUNTERS
+        // RETURN DIRECTION
+        // HOME MOUSE
+        // CHECK MOUSE BUTTONS
+
+        inregs.w.ax = PMOUSE;
+        int386 (MouseInt, &inregs, &outregs);
+
+        mousex = outregs.w.cx;
+        mousey = outregs.w.dx;
+
+
+        if (mousey < (CENTER-SENSITIVE))
+        {
+            ci->dir = dir_North;
+
+            inregs.w.cx = CENTER;
+            inregs.w.dx = CENTER;
+
+            inregs.w.ax = SMOUSE;
+            int386 (MouseInt, &inregs, &outregs);
+
+            mouseactive = 1;
+
+        }
+        else if (mousey > (CENTER+SENSITIVE))
+        {
+            ci->dir = dir_South;
+
+            inregs.w.cx = CENTER;
+            inregs.w.dx = CENTER;
+
+            inregs.w.ax = SMOUSE;
+            int386 (MouseInt, &inregs, &outregs);
+
+            mouseactive = 1;
+        }
+
+        if (mousex < (CENTER-SENSITIVE))
+        {
+            ci->dir = dir_West;
+
+            inregs.w.cx = CENTER;
+            inregs.w.dx = CENTER;
+
+            inregs.w.ax = SMOUSE;
+            int386 (MouseInt, &inregs, &outregs);
+
+
+            mouseactive = 1;
+        }
+        else if (mousex > (CENTER+SENSITIVE))
+        {
+            ci->dir = dir_East;
+
+            inregs.w.cx = CENTER;
+            inregs.w.dx = CENTER;
+
+            inregs.w.ax = SMOUSE;
+            int386 (MouseInt, &inregs, &outregs);
+
+            mouseactive = 1;
+        }
+#else
+#error please define your platform.  /* or maybe just nuke the DOS section? */
+#endif
+
+        buttons = IN_GetMouseButtons();
+        if ( buttons )
+        {
+            ci->button0 = buttons & 1;
+            ci->button1 = buttons & 2;
+            ci->button2 = buttons & 4;
+            ci->button3 = false;
+            mouseactive = 1;
+        }
+    }
+
+    if (joystickenabled && !mouseactive)
+    {
+        int jx,jy,jb;
+
+
+        INL_GetJoyDelta (joystickport, &jx, &jy);
+
+        if (jy<-SENSITIVE)
+            ci->dir=dir_North;
+        else if (jy>SENSITIVE)
+            ci->dir=dir_South;
+
+        if (jx<-SENSITIVE)
+            ci->dir=dir_West;
+        else if (jx>SENSITIVE)
+            ci->dir=dir_East;
+
+        jb = IN_JoyButtons();
+        if (jb)
+        {
+            ci->button0=jb&1;
+            ci->button1=jb&2;
+            if (joypadenabled)
+            {
+                ci->button2=jb&4;
+                ci->button3=jb&8;
+            }
+            else
+                ci->button2=ci->button3=false;
+        }
+    }
+
+
+#if 0
+    if (SpaceBallPresent && spaceballenabled)
+    {
+        SP_Get(&packet);
+
+        if (packet.button)
+        {
+            if (packet.button & SP_BTN_1)
+                ci->button0 = true;
+
+            if (packet.button & SP_BTN_2)
+                ci->button1 = true;
+        }
+
+        if (packet.ty >  MENU_AMT)
+            ci->dir = dir_North;
+        else if (packet.ty < -MENU_AMT)
+            ci->dir = dir_South;
+
+        if (packet.tx < (-MENU_AMT* 6))
+            ci->dir = dir_West;
+        else if (packet.tx > (MENU_AMT * 6))
+            ci->dir = dir_East;
+    }
+#endif
+}
+
+
+//******************************************************************************
+//
+// IN_GetScanName () - Returns a string containing the name of the
+//                     specified scan code
+//
+//******************************************************************************
+
+byte * IN_GetScanName (ScanCode scan)
+{
+    byte     **p;
+    ScanCode *s;
+
+    for (s = ExtScanCodes, p = ExtScanNames; *s; p++, s++)
+        if (*s == scan)
+            return (*p);
+
+    return(ScanNames[scan]);
+}
+
+
+//******************************************************************************
+//
+// DisplayInfo ()
+//
+//******************************************************************************
+
+void DisplayInfo (int which)
+{
+    patch_t *p;
+    int x;
+    int num;
+
+    num = W_GetNumForName ( "info1" ) + which;
+    p = (patch_t *) W_CacheLumpNum (num, PU_CACHE, Cvt_patch_t, 1);
+
+    x = (288 - p->width) >> 1;
+
+    DrawMenuBufItem (x, 149, num);
+}
+
+
+//******************************************************************************
+//
+// DrawSTMenuBuf()
+//
+//******************************************************************************
+
+void DrawSTMenuBuf (int x, int y, int w, int h, boolean up)
+{
+    if (!up)
+    {
+        DrawTMenuBufHLine (x,   y,   w+1, false);
+        DrawTMenuBufVLine (x,   y+1, h-1, false);
+        DrawTMenuBufHLine (x,   y+h, w+1, true);
+        DrawTMenuBufVLine (x+w, y+1, h-1, true);
+    }
+    else
+    {
+        DrawTMenuBufHLine (x,   y,   w+1, true);
+        DrawTMenuBufVLine (x,   y+1, h-1, true);
+        DrawTMenuBufHLine (x,   y+h, w+1, false);
+        DrawTMenuBufVLine (x+w, y+1, h-1, false);
+    }
+}
+
+
+//****************************************************************************
+//
+// DoMainMenu ()
+//
+//****************************************************************************
+
+void DoMainMenu (void)
+{
+    EnableScreenStretch();//bna++ shut on streech mode
+    SetAlternateMenuBuf();
+    ClearMenuBuf();
+    DrawMainMenu();
+    DrawMenuBufItem (MainItems.x,  ((MainItems.curpos*14)+(MainItems.y-2)),
+                     W_GetNumForName( LargeCursor ) + CursorFrame[ CursorNum ] );
+    FlipMenuBuf();
+}
+
+
+//****************************************************************************
+//
+// DrawCustomMenu ()
+//
+//****************************************************************************
+
+void DrawCustomMenu (void)
+{
+    MenuNum = 3;
+    SetAlternateMenuBuf();
+    ClearMenuBuf();
+    SetMenuTitle ("Customize Menu");
+    MN_GetCursorLocation( &CustomItems, &CustomMenu[ 0 ] );
+    DrawMenu (&CustomItems, &CustomMenu[0]);
+    DrawMenuBufItem (CustomItems.x, ((CustomItems.curpos*14)+(CustomItems.y-2)),
+                     W_GetNumForName( LargeCursor ) + CursorFrame[ CursorNum ] );
+    DisplayInfo (0);
+    FlipMenuBuf();
+}
+
+
+
+//****************************************************************************
+//
+// DrawCustomKeyboard ()
+//
+//****************************************************************************
+void DrawCustomKeyboard (void)
+{
+    int i;
+
+    SetAlternateMenuBuf();
+    ClearMenuBuf();
+    SetMenuTitle ("Customize Keyboard");
+
+    for( i = 0; i < NormalKeyItems.amount; i++ )
+    {
+        strcpy( &NormalKeyNames[ i ][ KEYNAMEINDEX ],
+                IN_GetScanName( buttonscan[ (unsigned int)order[ i ] ] ) );
+    }
+
+    MN_GetCursorLocation( &NormalKeyItems, &NormalKeyMenu[ 0 ] );
+    DrawMenu( &NormalKeyItems, &NormalKeyMenu[ 0 ] );
+
+    DisplayInfo( 0 );
+    FlipMenuBuf();
+}
+
+
+//****************************************************************************
+//
+// MusicVolume ()
+//
+//****************************************************************************
+
+void MusicVolume
+(
+    void
+)
+
+{
+#ifdef DOS
+    extern boolean SOUNDSETUP;
+#endif
+
+    SliderMenu( &MUvolume, 254, 0, 33, 81, 225, 8, "block3", MUSIC_SetVolume,
+                "Music Volume", "Low", "High" );
+
+#ifdef DOS
+    if ( SOUNDSETUP )
+    {
+        DrawSoundSetupMainMenu();
+    }
+    else
+    {
+#endif
+        DrawControlMenu();
+#ifdef DOS
+    }
+#endif
+}
+
+
+//****************************************************************************
+//
+// FXVolume ()
+//
+//****************************************************************************
+
+void FXVolume
+(
+    void
+)
+
+{
+#ifdef DOS
+    extern boolean SOUNDSETUP;
+#endif
+    int oldvolume;
+
+    oldvolume = FXvolume;
+
+    SliderMenu( &FXvolume, 254, 0, 33, 81, 225, 8, "block3", FX_SetVolume,
+                "Sound Volume", "Low", "High" );
+
+#ifdef DOS
+    if ( SOUNDSETUP )
+    {
+        DrawSoundSetupMainMenu();
+    }
+    else
+    {
+#endif
+        DrawControlMenu();
+#ifdef DOS
+    }
+#endif
+}
+
+
+
+//****************************************************************************
+//
+// DrawPlayerMenu ()
+//
+//****************************************************************************
+
+void DrawPlayerMenu (void)
+{
+    MenuNum = 5;
+
+
+    MN_MakeActive( &PlayerItems, &PlayerMenu[0], DefaultPlayerCharacter );
+
+#if ( SHAREWARE == 1 )
+    PlayerMenu[ 1 ].active = CP_SemiActive; // Thi Barrett
+    PlayerMenu[ 2 ].active = CP_SemiActive; // Doug Wendt
+    PlayerMenu[ 3 ].active = CP_SemiActive; // Lorelei Ni
+    PlayerMenu[ 4 ].active = CP_SemiActive; // Ian Paul Freeley
+#endif
+
+    if (numdone || (!ingame) || (!inmenu))
+        SetAlternateMenuBuf();
+    ClearMenuBuf();
+    SetMenuTitle ("Choose Player");
+
+    DrawMenu (&PlayerItems, &PlayerMenu[0]);
+    DrawNewPlayerDiff (PlayerItems.curpos);
+
+    DisplayInfo (0);
+
+
+    if ( ( gamestate.battlemode != battle_StandAloneGame ) &&
+            ( consoleplayer == 0 ) )
+    {
+        DrawBattleModeName( gamestate.battlemode );
+    }
+
+    if (ingame && inmenu && (!numdone))
+        RefreshMenuBuf (0);
+    else
+        FlipMenuBuf();
+}
+
+//******************************************************************************
+//
+// DRAW NEW PLAYER GRAPHIC
+//
+//******************************************************************************
+
+int newplayerY[5] = {28, 42, 56, 70, 84};
+
+void DrawNewPlayerDiff (int w)
+{
+    EraseMenuBufRegion (25, 18, 52, 125);
+    DrawMenuBufPic (25, newplayerY[w], W_GetNumForName( "PLAYER1" ) + w );
+}
+
+
+//******************************************************************************
+//
+// MenuFixup ()
+//
+//******************************************************************************
+void MenuFixup
+(
+    void
+)
+
+{
+    MainMenu[ viewscores ].texture[ 6 ] = '1';
+    MainMenu[ viewscores ].texture[ 7 ] = '0';
+    MainMenu[ viewscores ].texture[ 8 ] = '\0';
+    MainMenu[ viewscores ].routine      = ( void * )CP_EndGame;
+    MainMenu[ viewscores ].letter       = 'E';
+    strcpy (MainMenuNames[ viewscores ], "END GAME");
+    MainMenu[ savegame ].active         = CP_Active;
+    ingame = true;
+}
+
+//******************************************************************************
+//
+// GetEpisode ()
+//
+//******************************************************************************
+
+void GetEpisode (int level)
+{
+    if (level < 8)
+        gamestate.episode = 1;
+    else if (level < 16)
+        gamestate.episode = 2;
+    else if (level < 24)
+        gamestate.episode = 3;
+    else
+        gamestate.episode = 4;
+}
+
+
+//****************************************************************************
+//
+// DrawControlMenu ()
+//
+//****************************************************************************
+
+void DrawControlMenu (void)
+{
+    MenuNum = 1;
+
+    if (numdone || (!ingame) || (!inmenu))
+        SetAlternateMenuBuf();
+
+    ClearMenuBuf();
+    SetMenuTitle ("Options");
+
+    MN_GetCursorLocation( &ControlMItems, &ControlMMenu[ 0 ] );
+    DrawMenu (&ControlMItems, &ControlMMenu[0]);
+    DisplayInfo (0);
+
+    if (ingame && inmenu && (!numdone))
+        RefreshMenuBuf (0);
+    else
+        FlipMenuBuf();
+
+    numdone ++;
+}
+
+//****************************************************************************
+//
+//  CP_ControlMenu ()
+//
+//****************************************************************************
+
+void CP_ControlMenu (void)
+{
+    int which;
+
+    DrawControlMenu();
+
+    do
+    {
+        which = HandleMenu (&ControlMItems, &ControlMMenu[0], NULL);
+
+    } while (which >= 0);
+
+    handlewhich = OUTOFRANGE;
+}
+
+
+
+//****************************************************************************
+//
+// DrawOptionsMenu ()
+//
+//****************************************************************************
+
+void DrawOptionsMenu (void)
+{
+    MenuNum = 1;
+
+    SetAlternateMenuBuf();
+    ClearMenuBuf();
+    SetMenuTitle ("User Options");
+
+    MN_GetCursorLocation( &OptionsItems, &OptionsMenu[ 0 ] );
+    DrawMenu (&OptionsItems, &OptionsMenu[0]);
+    DrawOptionsButtons ();
+    DisplayInfo (0);
+    FlipMenuBuf();
+}
+//****************************************************************************
+//
+// DrawExtOptionsMenu ()  () bna added
+//
+//****************************************************************************
+
+void DrawExtOptionsMenu (void)
+{
+    MenuNum = 1;
+
+    SetAlternateMenuBuf();
+    ClearMenuBuf();
+    SetMenuTitle ("Extended User Options");
+
+    MN_GetCursorLocation( &ExtOptionsItems, &ExtOptionsMenu[ 0 ] );
+    DrawMenu (&ExtOptionsItems, &ExtOptionsMenu[0]);
+    DrawExtOptionsButtons ();
+    DisplayInfo (0);
+
+    FlipMenuBuf();
+}
+extern int inverse_mouse;
+extern boolean usemouselook;
+extern boolean iG_aimCross;
+extern boolean usejump;
+extern boolean sdl_fullscreen;
+extern boolean autoAimMissileWeps;
+extern boolean autoAim;
+
+void CP_ExtOptionsMenu (void)
+{
+    int which;
+
+    DrawExtOptionsMenu();
+
+    do
+    {
+        which = HandleMenu (&ExtOptionsItems, &ExtOptionsMenu[0], NULL);
+
+        switch (which)
+        {
+        case 0:
+            usemouselook  ^= 1;
+            DrawExtOptionsButtons ();
+            break;
+        case 1:
+            if (inverse_mouse == 1) {
+                inverse_mouse = -1;
+            } else {
+                inverse_mouse = 1;
+            }
+            DrawExtOptionsButtons ();
+            break;
+        case 2:
+            iG_aimCross   ^= 1;
+            DrawExtOptionsButtons ();
+            break;
+        case 3:
+            usejump       ^= 1;
+            DrawExtOptionsButtons ();
+            break;
+        case 4:
+            if (SDL_WM_ToggleFullScreen(SDL_GetVideoSurface()))
+            {
+                sdl_fullscreen ^= 1;
+                DrawExtOptionsButtons ();
+            }
+            break;
+        case 5:
+            autoAimMissileWeps ^= 1;
+            DrawExtOptionsButtons();
+            break;
+        case 6:
+            autoAim ^= 1;
+            DrawExtOptionsButtons();
+            break;
+        }
+
+    } while (which >= 0);
+
+    DrawControlMenu();
+}
+void DrawExtOptionsButtons (void)
+{
+    int i,
+        on;
+    int button_on;
+    int button_off;
+
+    button_on  = W_GetNumForName ("snd_on");
+    button_off = W_GetNumForName ("snd_off");
+
+    for (i = 0; i < ExtOptionsItems.amount; i++)
+        if (ExtOptionsMenu[i].active != CP_Active3)
+        {
+            //
+            // DRAW SELECTED/NOT SELECTED GRAPHIC BUTTONS
+            //
+
+            on = 0;
+
+            switch (i)
+            {
+            case 0:
+                if (usemouselook  == 1) on = 1;
+                break;
+            case 1:
+                if (inverse_mouse == -1)on = 1;
+                break;
+            case 2:
+                if (iG_aimCross   == 1) on = 1;
+                break;
+            case 3:
+                if (usejump       == 1) on = 1;
+                break;
+            case 4:
+                if (sdl_fullscreen== 1) on = 1;
+                break;
+            case 5:
+                if (autoAimMissileWeps == 1) on = 1;
+                break;
+            case 6:
+                if (autoAim == 1) on = 1;
+                break;
+            }
+
+            if (on)
+                DrawMenuBufItem (20+22, ExtOptionsItems.y+i*14-1, button_on);
+            else
+                DrawMenuBufItem (20+22, ExtOptionsItems.y+i*14-1, button_off);
+        }
+}
+extern boolean allowBlitzMoreMissileWeps;
+extern boolean enableAmmoPickups;
+extern boolean enableZomROTT = 0;
+extern boolean enableExtraPistolDrops = 0;
+
+void DrawExtGameOptionsButtons (void)
+{
+    int i,
+        on;
+    int button_on;
+    int button_off;
+
+    button_on  = W_GetNumForName ("snd_on");
+    button_off = W_GetNumForName ("snd_off");
+
+    for (i = 0; i < ExtGameOptionsItems.amount; i++)
+        if (ExtGameMenu[i].active != CP_Active3)
+        {
+            //
+            // DRAW SELECTED/NOT SELECTED GRAPHIC BUTTONS
+            //
+
+            on = 0;
+
+            switch (i)
+            {
+            case 0:
+                if (allowBlitzMoreMissileWeps  == 1) on = 1;
+                break;
+            case 1:
+                if (enableAmmoPickups == 1) on = 1;
+                break;
+            case 2:
+                if (enableExtraPistolDrops == 1) on = 1;
+                break;
+            case 3:
+                if (enableZomROTT == 1) on = 1;
+                break;
+            }
+
+
+            if (on)
+                DrawMenuBufItem (20+22, ExtGameOptionsItems.y+i*14-1, button_on);
+            else
+                DrawMenuBufItem (20+22, ExtGameOptionsItems.y+i*14-1, button_off);
+        }
+
+}
+
+
+
+
+void DrawExtGameMenu (void)
+{
+    MenuNum = 1;
+    SetAlternateMenuBuf();
+    ClearMenuBuf();
+    SetMenuTitle ("Extended Game Options");
+
+    MN_GetCursorLocation( &ExtGameOptionsItems, &ExtGameOptionsNames[0]);
+
+    DrawMenu(&ExtGameOptionsItems, &ExtGameMenu[0]);
+
+    DrawExtGameOptionsButtons();
+
+    DisplayInfo(0);
+
+    FlipMenuBuf();
+
+}
+//****************************************************************************
+//
+// DrawExtGameOptionsMenu ()  () LT added
+//
+//****************************************************************************
+
+void CP_ExtGameOptionsMenu (void)
+{
+    int which;
+
+    DrawExtGameMenu();
+
+    do
+    {
+        which = HandleMenu (&ExtGameOptionsItems, &ExtGameMenu[0], NULL);
+
+        switch (which)
+        {
+        case 0:
+            allowBlitzMoreMissileWeps  ^= 1;
+            DrawExtGameOptionsButtons ();
+            break;
+        case 1:
+            enableAmmoPickups ^= 1;
+            DrawExtGameOptionsButtons();
+            break;
+        case 2:
+            enableExtraPistolDrops ^= 1;
+            DrawExtGameOptionsButtons();
+            break;
+        case 3:
+            enableZomROTT ^= 1;
+            DrawExtGameOptionsButtons();
+            break;
+        }
+    } while (which >= 0);
+
+    DrawControlMenu();
+}
+
+
+//****************************************************************************
+//
+// CP_OptionsMenu ()
+//
+//****************************************************************************
+
+void CP_OptionsMenu (void)
+{
+    int which;
+
+    DrawOptionsMenu();
+
+    do
+    {
+        which = HandleMenu (&OptionsItems, &OptionsMenu[0], NULL);
+
+        switch (which)
+        {
+        case 0:
+            AutoDetailOn  ^= 1;
+            DrawOptionsButtons ();
+            break;
+        case 1:
+            fulllight     ^= 1;
+            DrawOptionsButtons ();
+            break;
+        case 2:
+            BobbinOn      ^= 1;
+            DrawOptionsButtons ();
+            break;
+        case 3:
+            fandc         ^= 1;
+            DrawOptionsButtons ();
+            break;
+        }
+
+    } while (which >= 0);
+
+    DrawControlMenu();
+}
+
+//****************************************************************************
+//
+// DrawOptionsButtons
+//
+//****************************************************************************
+
+void DrawOptionsButtons (void)
+{
+    int i,
+        on;
+    int button_on;
+    int button_off;
+
+    button_on  = W_GetNumForName ("snd_on");
+    button_off = W_GetNumForName ("snd_off");
+
+    for (i = 0; i < OptionsItems.amount-5; i++)
+        if (OptionsMenu[i].active != CP_Active3)
+        {
+            //
+            // DRAW SELECTED/NOT SELECTED GRAPHIC BUTTONS
+            //
+
+            on = 0;
+
+            switch (i)
+            {
+            case 0:
+                if (AutoDetailOn  == 1) on = 1;
+                break;
+            case 1:
+                if (fulllight     == 0) on = 1;
+                break;
+            case 2:
+                if (BobbinOn      == 1) on = 1;
+                break;
+            case 3:
+                if (fandc         == 1) on = 1;
+                break;
+            }
+
+            if (on)
+                DrawMenuBufItem (20+22, OptionsItems.y+i*14-1, button_on);
+            else
+                DrawMenuBufItem (20+22, OptionsItems.y+i*14-1, button_off);
+        }
+}
+
+
+//****************************************************************************
+//
+// CP_DoubleClickSpeed()
+//
+//****************************************************************************
+
+void CP_DoubleClickSpeed
+(
+    void
+)
+
+{
+    int temp;
+
+    temp = 50 - ( DoubleClickSpeed - 5 );
+    SliderMenu( &temp, 50, 5, 31, 81, 225, 3, "block1", NULL,
+                "Double-Click Speed", "Slow", "Fast" );
+    DoubleClickSpeed = 50 - ( temp - 5 );
+
+    handlewhich = 100;
+    DrawOptionsMenu();
+}
+
+//****************************************************************************
+//
+// MenuFlipSpeed ()
+//
+//****************************************************************************
+
+void MenuFlipSpeed
+(
+    void
+)
+
+{
+    int temp;
+
+    temp = 50 - ( Menuflipspeed - 5 );
+
+    SliderMenu( &temp, 50, 5, 31, 81, 225, 3, "block1", NULL,
+                "Menu Flip Speed", "Slow", "Fast" );
+
+    Menuflipspeed = 50 - ( temp - 5 );
+
+    DrawOptionsMenu ();
+    handlewhich = 10;
+}
+
+
+//****************************************************************************
+//
+// DrawDetailMenu ()
+//
+//****************************************************************************
+
+void DrawDetailMenu (void)
+{
+    MenuNum = 1;
+
+    SetAlternateMenuBuf();
+    ClearMenuBuf();
+    SetMenuTitle ("Detail Menu");
+
+    MN_DrawButtons (&DetailItems, &DetailMenu[0], DetailLevel, OptionNums);
+    MN_GetCursorLocation( &DetailItems, &DetailMenu[ 0 ] );
+    DrawMenu (&DetailItems, &DetailMenu[0]);
+    DisplayInfo (0);
+    FlipMenuBuf();
+}
+
+//****************************************************************************
+//
+// CP_DetailMenu ()
+//
+//****************************************************************************
+
+void CP_DetailMenu (void)
+{
+    int which;
+
+    DrawDetailMenu();
+
+    do
+    {
+        which = HandleMenu (&DetailItems, &DetailMenu[0], NULL);
+
+        switch (which)
+        {
+        case 0:
+            DetailLevel = 0;
+            MN_DrawButtons (&DetailItems, &DetailMenu[0], DetailLevel, OptionNums);
+            break;
+
+        case 1:
+            DetailLevel = 1;
+            MN_DrawButtons (&DetailItems, &DetailMenu[0], DetailLevel, OptionNums);
+            break;
+
+        case 2:
+            DetailLevel = 2;
+            MN_DrawButtons (&DetailItems, &DetailMenu[0], DetailLevel, OptionNums);
+            break;
+        }
+
+    } while (which >= 0);
+
+    handlewhich = 10;
+    DrawOptionsMenu();
+}
+
+
+//****************************************************************************
+//
+// DrawBattleMenu ()
+//
+//****************************************************************************
+
+void DrawBattleMenu (void)
+{
+    MenuNum = 1;
+
+    if (numdone || (!ingame) || (!inmenu))
+        SetAlternateMenuBuf();
+
+    ClearMenuBuf();
+    SetMenuTitle ("Battle Menu");
+
+    DrawBattleModeName( gamestate.battlemode );
+
+    MN_GetCursorLocation( &BattleItems, &BattleMenu[ 0 ] );
+    DrawMenu (&BattleItems, &BattleMenu[0]);
+    DisplayInfo (0);
+
+    BATTLE_SetOptions( &BATTLE_Options[ gamestate.battlemode ] );
+    ShowBattleOptions( true, MENU_X, MENU_Y + 49 );
+
+    if (ingame && inmenu && (!numdone))
+        RefreshMenuBuf (0);
+    else
+        FlipMenuBuf();
+}
+
+
+//****************************************************************************
+//
+// BattleGamePlayerSetup()
+//
+//****************************************************************************
+
+void BattleGamePlayerSetup( void )
+{
+    int status;
+    int pos;
+
+    pos = 1;
+    if ( consoleplayer == 0 )
+    {
+        pos = 0;
+    }
+
+    while( 1 )
+    {
+        switch( pos )
+        {
+        case 0 :
+            // Select level to play on
+            status = CP_LevelSelectionMenu ();
+            if ( status >= 0  )
+            {
+                gamestate.mapon=status;
+                pos = 1;
+            }
+            else
+            {
+                DrawBattleMenu();
+                return;
+            }
+            break;
+
+        case 1 :
+            // Select CodeName
+            status = CP_EnterCodeNameMenu();
+            pos = 2;
+            if ( !status )
+            {
+                if ( consoleplayer == 0 )
+                {
+                    pos = 0;
+                }
+                else
+                {
+                    return;
+                }
+            }
+            break;
+
+        case 2 :
+            // Select character
+            status = CP_PlayerSelection ();
+            pos = 1;
+            if ( status )
+            {
+                pos = 3;
+            }
+            break;
+
+        case 3 :
+            // Select color/team
+            status = CP_ColorSelection();
+            pos = 2;
+            if ( status )
+            {
+                StartGame   = true;
+                DisableScreenStretch();
+                handlewhich = -2;
+                playstate   = ex_resetgame;
+                BATTLEMODE  = true;
+                // Show please wait
+                CP_ModemGameMessage( consoleplayer );
+                return;
+            }
+            break;
+        }
+    }
+}
+
+
+//****************************************************************************
+//
+// BattleNoTeams()
+//
+//****************************************************************************
+
+void BattleNoTeams( void )
+{
+    BattleGamePlayerSetup();
+    if ( StartGame )
+    {
+        gamestate.teamplay = false;
+    }
+}
+
+
+//****************************************************************************
+//
+// BattleTeams()
+//
+//****************************************************************************
+
+void BattleTeams( void )
+{
+    BattleGamePlayerSetup();
+    if ( StartGame )
+    {
+        gamestate.teamplay = true;
+    }
+}
+
+
+//****************************************************************************
+//
+// CP_BattleMenu ()
+//
+//****************************************************************************
+
+void CP_BattleMenu (void)
+{
+    int which;
+
+    gamestate.battlemode = handlewhich + battle_Normal;
+
+    BattleMenu[0].active = CP_Active;
+    BattleMenu[1].active = CP_Active;
+
+
+    // Tag can't be played in team mode
+    // Also, can't play teams if only 1 person is playing
+    if ( ( gamestate.battlemode == battle_Tag ) ||
+            ( numplayers < 2 ) )
+    {
+        BattleMenu[1].active = CP_Inactive;
+        if ( BattleItems.curpos == 1 )
+        {
+            BattleItems.curpos = 0;
+        }
+    }
+
+    // Capture the Triad can only be played in team mode
+    if ( gamestate.battlemode == battle_CaptureTheTriad )
+    {
+        BattleMenu[0].active = CP_Inactive;
+        if ( BattleItems.curpos == 0 )
+        {
+            BattleItems.curpos = 1;
+        }
+    }
+
+    BattleMenu[ BattleItems.curpos ].active = CP_CursorLocation;
+    DrawBattleMenu();
+
+    do
+    {
+        which = HandleMenu (&BattleItems, &BattleMenu[0], NULL);
+    }
+    while (which >= 0);
+
+    if ( which == -1 )
+    {
+        DrawBattleModes ();
+        handlewhich = OUTOFRANGE;
+    }
+}
+
+
+//****************************************************************************
+//
+// MN_PlayMenuSnd ()
+//
+//****************************************************************************
+
+extern boolean dopefish;
+void MN_PlayMenuSnd (int which)
+{
+    if (INFXSETUP || (SD_Started == false))
+        return;
+#if (SHAREWARE==0)
+    if (dopefish==true)
+    {
+        switch (which)
+        {
+        case SD_ESCPRESSEDSND:
+            which = SD_SOUNDESCSND;
+            break;
+        case SD_MOVECURSORSND:
+            which = SD_SILLYMOVESND;
+            break;
+        case SD_SELECTSND:
+            which = SD_SOUNDSELECTSND;
+            break;
+        }
+    }
+#endif
+    SD_Play (which);
+}
+
+
+//******************************************************************************
+//
+// SliderMenu ()
+//
+//******************************************************************************
+
+boolean SliderMenu
+(
+    int *number,
+    int upperbound,
+    int lowerbound,
+    int erasex,
+    int erasey,
+    int erasew,
+    int numadjust,
+    char *blockname,
+    void ( *routine )( int w ),
+    char *title,
+    char *left,
+    char *right
+)
+
+{
+    ControlInfo ci;
+    Direction   lastdir;
+    patch_t    *shape;
+    boolean     returnval;
+    boolean     moved;
+    unsigned long scale;
+    int         exit;
+    int         range;
+    int         timer;
+    int         width;
+    int         height;
+    int         blkx;
+    int         eraseh;
+    int         block;
+
+    SetAlternateMenuBuf();
+    ClearMenuBuf();
+    SetMenuTitle( title );
+
+    newfont1 = (font_t *)W_CacheLumpName( "newfnt1", PU_CACHE, Cvt_font_t, 1);
+    CurrentFont = newfont1;
+    PrintX = 25;
+    PrintY = 62;
+    DrawMenuBufPropString( PrintX, PrintY, left );
+
+    VW_MeasurePropString( right, &width, &height );
+    DrawMenuBufPropString( 263 - width, PrintY, right );
+
+    block = W_GetNumForName( blockname );
+    shape = ( patch_t * )W_CacheLumpNum( block, PU_CACHE, Cvt_patch_t, 1 );
+    blkx  = erasex - shape->leftoffset;
+    eraseh =  shape->height;
+    scale = ( erasew + shape->leftoffset - shape->width ) << 16;
+    range = upperbound - lowerbound;
+
+    DrawSTMenuBuf( erasex - 1, erasey - 1, erasew + 1, eraseh + 1, false );
+
+    DrawMenuBufItem( blkx + ( ( ( ( *number - lowerbound ) *
+                                  scale ) / range ) >> 16 ), erasey, block );
+
+    DisplayInfo( 1 );
+    FlipMenuBuf();
+
+    exit  = 0;
+    moved = false;
+    timer = GetTicCount();
+    lastdir = dir_None;
+
+    do
+    {
+        RefreshMenuBuf( 0 );
+
+        ReadAnyControl( &ci );
+        if ( ( ( GetTicCount() - timer ) > 5 ) || ( ci.dir != lastdir ) )
+        {
+            timer = GetTicCount();
+
+            switch( ci.dir )
+            {
+            case dir_North:
+            case dir_West:
+                if ( *number > lowerbound )
+                {
+                    *number = *number - numadjust;
+
+                    if ( *number < lowerbound )
+                    {
+                        *number = lowerbound;
+                    }
+
+                    moved = true;
+                }
+                break;
+
+            case dir_South:
+            case dir_East:
+                if ( *number < upperbound )
+                {
+                    *number = *number + numadjust;
+
+                    if ( *number > upperbound )
+                    {
+                        *number = upperbound;
+                    }
+
+                    moved = true;
+                }
+                break;
+            default:
+                ;
+            }
+
+            lastdir = ci.dir;
+        }
+
+        if ( moved )
+        {
+            moved = false;
+
+            EraseMenuBufRegion( erasex, erasey, erasew, eraseh );
+
+            DrawMenuBufItem( blkx + ( ( ( ( *number - lowerbound ) *
+                                          scale ) / range ) >> 16 ), erasey, block );
+
+            if ( routine )
+            {
+                routine( *number );
+            }
+
+            MN_PlayMenuSnd( SD_MOVECURSORSND );
+        }
+
+        if ( ci.button0 || Keyboard[ sc_Space ] || Keyboard[ sc_Enter ] )
+        {
+            exit = 1;
+        }
+        else if ( ci.button1 || Keyboard[ sc_Escape ] )
+        {
+            exit = 2;
+        }
+    }
+    while( !exit );
+
+    if ( exit == 2 )
+    {
+        MN_PlayMenuSnd( SD_ESCPRESSEDSND );
+        returnval = false;
+    }
+    else
+    {
+        MN_PlayMenuSnd( SD_SELECTSND );
+        returnval = true;
+    }
+
+    WaitKeyUp ();
+    return( returnval );
+}
+
+
+//******************************************************************************
+//
+// DrawF1Help ()
+//
+//******************************************************************************
+
+void DrawF1Help (void)
+{
+
+    VL_DrawPostPic (W_GetNumForName("trilogo"));
+
+    DrawNormalSprite (0, 0, W_GetNumForName("help"));
+
+    VW_UpdateScreen ();
+}
+
+//******************************************************************************
+//
+// CP_F1Help ()
+//
+//******************************************************************************
+
+void CP_F1Help (void)
+{
+    LastScan=0;
+
+    DrawF1Help ();
+
+    while (LastScan == 0)
+    {
+        IN_UpdateKeyboard ();
+    }
+
+    LastScan=0;
+#if (SHAREWARE==1)
+    {
+        DrawOrderInfo( 2 );
+        while (LastScan == 0)
+        {
+            IN_UpdateKeyboard ();
+        }
+
+        LastScan=0;
+    }
+#endif
+}
+
+
+//****************************************************************************
+//
+// CP_ScreenSize()
+//
+//****************************************************************************
+
+void CP_ScreenSize
+(
+    void
+)
+
+{
+    SliderMenu( &viewsize, MAXVIEWSIZES - 1, 0, 33, 81, 225, 1, "block1",
+                NULL, "Screen Size", "Small", "Large" );
+
+    handlewhich = 100;
+    DrawOptionsMenu();
+}
+
+
+//****************************************************************************
+//
+// DrawViolenceMenu ()
+//
+//****************************************************************************
+
+void DrawViolenceMenu (void)
+{
+    MenuNum = 1;
+    if ( POK )
+    {
+        memcpy( &VMenu[ 1 ].texture, "mcpass\0", 7 );
+        VMenu[ 1 ].letter = 'C';
+        strcpy (VMenuNames[ 1 ], "CHANGE PASSWORD");
+    }
+    else
+    {
+        memcpy( &VMenu[ 1 ].texture, "mepass\0", 7 );
+        VMenu[ 1 ].letter = 'E';
+        strcpy (VMenuNames[ 1 ], "ENTER PASSWORD");
+    }
+
+    if (VMenu[0].active != CP_CursorLocation)
+        VMenu[0].active = CP_Active;
+
+    SetAlternateMenuBuf();
+    ClearMenuBuf();
+    SetMenuTitle ("Violence Level");
+
+    MN_GetCursorLocation( &VItems, &VMenu[ 0 ] );
+    DrawMenu (&VItems, &VMenu[0]);
+    DisplayInfo (0);
+    FlipMenuBuf();
+}
+
+
+//****************************************************************************
+//
+// CP_ViolenceMenu ()
+//
+//****************************************************************************
+
+void CP_ViolenceMenu (void)
+{
+    int which;
+
+    CurrentFont = smallfont;
+    DrawViolenceMenu ();
+
+    do
+    {
+        which = HandleMenu (&VItems, &VMenu[0], NULL);
+
+    } while (which >= 0);
+
+    handlewhich = 100;
+    DrawOptionsMenu();
+}
+
+
+//****************************************************************************
+//
+// DrawViolenceLevel ()
+//
+//****************************************************************************
+
+void DrawViolenceLevel (void)
+{
+    MenuNum = 1;
+
+    SetAlternateMenuBuf();
+    ClearMenuBuf();
+    SetMenuTitle ("Change Violence Level");
+
+    MN_DrawButtons (&ViolenceItems, &ViolenceMenu[0], gamestate.violence, OptionNums);
+    MN_GetActive (&ViolenceItems, &ViolenceMenu[0], gamestate.violence, OptionNums);
+
+//   DrawMenuBufItem (58, 24, W_GetNumForName ("blood"));
+    IFont = ( cfont_t * )W_CacheLumpName( FontNames[ mn_largefont ],
+                                          PU_CACHE, Cvt_cfont_t, 1 );
+    DrawMenuBufIString( 58, 24, "HOW MUCH ", NORMALCOLOR );
+    DrawMenuBufIString( PrintX, PrintY, "BLOOD", 51 );
+    DrawMenuBufIString( 71, 37, "DO YOU WANT?", NORMALCOLOR );
+
+    DrawMenu (&ViolenceItems, &ViolenceMenu[0]);
+    DisplayInfo (0);
+    FlipMenuBuf();
+}
+
+
+//****************************************************************************
+//
+// CP_ViolenceLevel ()
+//
+//****************************************************************************
+
+void CP_ViolenceLevel (void)
+{
+    int which;
+    char p1[13];
+    boolean passok=false;
+
+    if (ingame)
+    {
+        CP_ErrorMsg( "Change Violence Level",
+                     "The current game must be ended to change the Violence Level.",
+                     mn_largefont );
+    }
+    else if ( POK )
+    {
+        memset (p1, 0, 13);
+
+        CurrentFont = smallfont;
+        DrawViolenceLevelPWord ();
+
+        if (US_lineinput (PBOXX+2, PBOXY+1, p1, NULL, true, 12, 110, 0))
+        {
+            //compare user entered to password
+            if (StringsNotEqual (p1, pword, StringLength (p1)) == false)
+                passok=true;
+            else
+            {
+                CP_ErrorMsg( "Violence Password", "Incorrect Password.",
+                             mn_largefont );
+            }
+        }
+    }
+    else
+        passok=true;
+    if (passok==true)
+    {
+        DrawViolenceLevel ();
+        do
+        {
+            which = HandleMenu (&ViolenceItems, &ViolenceMenu[0], NULL);
+
+            if (which >= 0)
+                gamestate.violence = which;
+
+            MN_DrawButtons (&ViolenceItems, &ViolenceMenu[0], gamestate.violence, OptionNums);
+
+        } while (which >= 0);
+
+        WriteMenuInfo ();
+    }
+
+    handlewhich = 100;
+    DrawViolenceMenu();
+}
+
+
+
+//****************************************************************************
+//
+// DrawViolenceLevelPWord ();
+//
+//****************************************************************************
+
+void DrawViolenceLevelPWord
+(
+    void
+)
+
+{
+    MenuNum = 1;
+
+    SetAlternateMenuBuf();
+    ClearMenuBuf();
+    SetMenuTitle( "Violence Password" );
+
+//   CurrentFont = newfont1;
+//   DrawMenuBufPropString( PWORDX, PWORDY, "ENTER PASSWORD" );
+
+    IFont = ( cfont_t * )W_CacheLumpName( FontNames[ mn_largefont ],
+                                          PU_CACHE, Cvt_cfont_t, 1 );
+    DrawMenuBufIString( PWORDX, PWORDY, "ENTER PASSWORD", NORMALCOLOR );
+
+    DrawSTMenuBuf( PBOXX, PBOXY, PBOXW, PBOXH, false );
+    FlipMenuBuf();
+}
+
+
+
+//****************************************************************************
+//
+// DrawPWMenu ()
+//
+//****************************************************************************
+
+void DrawPWMenu
+(
+    void
+)
+
+{
+    MenuNum = 1;
+
+    SetAlternateMenuBuf();
+    ClearMenuBuf();
+    SetMenuTitle( "Violence Password" );
+
+//   CurrentFont = newfont1;
+    IFont = ( cfont_t * )W_CacheLumpName( FontNames[ mn_largefont ],
+                                          PU_CACHE, Cvt_cfont_t, 1 );
+
+    if ( POK )
+    {
+//      DrawMenuBufPropString( PWORDX - 24, PWORDY, "ENTER OLD PASSWORD" );
+        DrawMenuBufIString( PWORDX - 24, PWORDY, "ENTER OLD PASSWORD", NORMALCOLOR );
+    }
+    else
+    {
+//      DrawMenuBufPropString( PWORDX - 24, PWORDY, "ENTER PASSWORD" );
+        DrawMenuBufIString( PWORDX - 24, PWORDY, "ENTER PASSWORD", NORMALCOLOR );
+    }
+
+    DrawSTMenuBuf( PBOXX, PBOXY, PBOXW, PBOXH, false );
+    FlipMenuBuf();
+}
+
+
+//****************************************************************************
+//
+// CP_PWMenu ()
+//
+//****************************************************************************
+
+void CP_PWMenu (void)
+{
+    char p1[13];
+    char p2[13];
+    boolean EnterNewPassword;
+    boolean AskForNew;
+    boolean RetypePassword;
+
+    memset (p1, 0, 13);
+    memset (p2, 0, 13);
+
+    CurrentFont = smallfont;
+
+    EnterNewPassword = true;
+    if ( POK )
+    {
+        DrawPWMenu ();
+
+        // get old password
+        //
+        EnterNewPassword = false;
+        if (US_lineinput (PBOXX+2, PBOXY+1, p1, NULL, true, 12, PSTRW, 0))
+        {
+            //compare user entered to old
+            //
+            if (StringsNotEqual (p1, pword, StringLength (p1))==false)
+            {
+
+                // Password was correct so they may change it.
+                EnterNewPassword = true;
+            }
+            else
+            {
+                CP_ErrorMsg( "Violence Password", "Incorrect Password.",
+                             mn_largefont );
+            }
+        }
+    }
+
+    if ( EnterNewPassword )
+    {
+        MenuNum = 1;
+
+        // get new password
+        //
+        AskForNew = true;
+        RetypePassword = false;
+        while( AskForNew )
+        {
+            CurrentFont = smallfont;
+
+            SetAlternateMenuBuf ();
+            ClearMenuBuf();
+            SetMenuTitle ("Violence Password");
+
+            IFont = ( cfont_t * )W_CacheLumpName( FontNames[ mn_largefont ],
+                                                  PU_CACHE, Cvt_cfont_t, 1 );
+            DrawMenuBufIString( PWORDX - 24, PWORDY, "ENTER NEW PASSWORD", NORMALCOLOR );
+
+//         CurrentFont = newfont1;
+//         DrawMenuBufPropString( PWORDX - 24, PWORDY, "ENTER NEW PASSWORD" );
+//         DrawMenuBufItem (PWORDX-24, PWORDY, W_GetNumForName ("mnewpass"));
+
+            DrawSTMenuBuf (PBOXX, PBOXY, PBOXW, PBOXH, false);
+            FlipMenuBuf();
+
+            memset (p1, 0, 13);
+
+            AskForNew = false;
+            if (US_lineinput (PBOXX+2, PBOXY+1, p1, NULL, true, 12, PSTRW, 0))
+            {
+                // Check for blank password
+                if ( p1[ 0 ] == 0 )
+                {
+                    if ( CP_DisplayMsg ( "Clear Password?\nAre you sure?", 12 ) )
+                    {
+                        AskForNew = false;
+                        memset (pword, 0, 13);
+                        WriteMenuInfo ();
+                        POK = false;
+                    }
+                    else
+                    {
+                        AskForNew = true;
+                    }
+                }
+                else
+                {
+                    RetypePassword = true;
+                }
+            }
+        }
+
+        if ( RetypePassword )
+        {
+            SetAlternateMenuBuf();
+            ClearMenuBuf();
+            SetMenuTitle ("Violence Password");
+
+//         CurrentFont = newfont1;
+//         DrawMenuBufPropString( PWORDX, PWORDY, "RETYPE PASSWORD" );
+
+            IFont = ( cfont_t * )W_CacheLumpName( FontNames[ mn_largefont ],
+                                                  PU_CACHE, Cvt_cfont_t, 1 );
+            DrawMenuBufIString( PWORDX, PWORDY, "RETYPE PASSWORD", NORMALCOLOR );
+
+            DrawSTMenuBuf (PBOXX, PBOXY, PBOXW, PBOXH, false);
+
+            FlipMenuBuf();
+
+            // reenter password
+            //
+            if ( US_lineinput (PBOXX+2, PBOXY+1, p2, NULL, true, 12, PSTRW, 0) )
+            {
+                // compare password and retyped password
+                //
+                if (stricmp (p1, p2) == 0)
+                {
+                    memset (pword, 0, 13);
+                    strcpy (pword, p1);
+                    WriteMenuInfo ();
+
+                    // If we have a null password, then we don't need to
+                    // ask for one.
+                    POK = true;
+                    if ( pword[ 0 ] == 0 )
+                    {
+                        POK = false;
+                    }
+                }
+                else
+                {
+                    CP_ErrorMsg( "Violence Password", "Passwords did not match.",
+                                 mn_largefont );
+                }
+            }
+        }
+    }
+
+    DrawViolenceMenu ();
+}
+
+//****************************************************************************
+//
+// DrawOptionDescription()
+//
+//****************************************************************************
+
+void DrawOptionDescription( char ** options, int w )
+{
+    int     width;
+    int     height;
+    char   *string;
+    font_t *temp;
+
+    EraseMenuBufRegion (25, 4, 287 - 25, 10 );
+
+    temp = CurrentFont;
+    CurrentFont = tinyfont;
+
+    string = options[ w ];
+
+    VW_MeasurePropString ( string, &width, &height );
+    DrawMenuBufPropString ( ( 288 - width) / 2, 4, string );
+
+    CurrentFont = temp;
+}
+
+//****************************************************************************
+//
+// DrawBattleOptionDescription()
+//
+//****************************************************************************
+
+void DrawBattleOptionDescription( int w )
+{
+    DrawOptionDescription( BattleOptionDescriptions, w );
+}
+//****************************************************************************
+//
+// DrawGravityOptionDescription()
+//
+//****************************************************************************
+
+void DrawGravityOptionDescription( int w )
+{
+    DrawOptionDescription( GravityOptionDescriptions, w );
+}
+//****************************************************************************
+//
+// DrawSpeedOptionDescription()
+//
+//****************************************************************************
+
+void DrawSpeedOptionDescription( int w )
+{
+    DrawOptionDescription( SpeedOptionDescriptions, w );
+}
+//****************************************************************************
+//
+// DrawAmmoOptionDescription()
+//
+//****************************************************************************
+
+void DrawAmmoOptionDescription( int w )
+{
+    DrawOptionDescription( AmmoOptionDescriptions, w );
+}
+//****************************************************************************
+//
+// DrawHitPointsOptionDescription()
+//
+//****************************************************************************
+
+void DrawHitPointsOptionDescription( int w )
+{
+    DrawOptionDescription( HitPointsOptionDescriptions, w );
+}
+//****************************************************************************
+//
+// DrawRadicalOptionDescription()
+//
+//****************************************************************************
+
+void DrawRadicalOptionDescription( int w )
+{
+    DrawOptionDescription( RadicalOptionDescriptions, w );
+}
+//****************************************************************************
+//
+// DrawLightLevelOptionDescription()
+//
+//****************************************************************************
+
+void DrawLightLevelOptionDescription( int w )
+{
+    DrawOptionDescription( LightLevelOptionDescriptions, w );
+}
+//****************************************************************************
+//
+// DrawPointGoalOptionDescription()
+//
+//****************************************************************************
+
+void DrawPointGoalOptionDescription( int w )
+{
+    DrawOptionDescription( PointGoalOptionDescriptions, w );
+}
+//****************************************************************************
+//
+// DrawDangerDamageOptionDescription()
+//
+//****************************************************************************
+
+void DrawDangerDamageOptionDescription( int w )
+{
+    DrawOptionDescription( DangerDamageOptionDescriptions, w );
+}
+
+//****************************************************************************
+//
+// DrawTimeLimitOptionDescription()
+//
+//****************************************************************************
+
+void DrawTimeLimitOptionDescription( int w )
+{
+    DrawOptionDescription( TimeLimitOptionDescriptions, w );
+}
+
+
+
+#define TURN_OFF_BATTLE_MODE( x ) \
+   ModeMenu[ ( x ) - 1 ].active  = CP_SemiActive; \
+   ModeMenu[ ( x ) - 1 ].routine = NULL;
+
+
+//****************************************************************************
+//
+// DrawBattleModes ()
+//
+//****************************************************************************
+void DrawBattleModes
+(
+    void
+)
+
+{
+    int i;
+
+    MenuNum = 1;
+
+    SetAlternateMenuBuf();
+    ClearMenuBuf();
+    SetMenuTitle ("Battle Modes");
+
+
+    MN_GetActive( &ModeItems, &ModeMenu[ 0 ], gamestate.battlemode -
+                  battle_Normal, OptionNums );
+
+#if ( SHAREWARE == 1 )
+    TURN_OFF_BATTLE_MODE( battle_ScoreMore );
+    TURN_OFF_BATTLE_MODE( battle_Scavenger );
+    TURN_OFF_BATTLE_MODE( battle_Tag );
+    TURN_OFF_BATTLE_MODE( battle_Eluder );
+    TURN_OFF_BATTLE_MODE( battle_Deluder );
+    TURN_OFF_BATTLE_MODE( battle_CaptureTheTriad );
+#endif
+
+    // Capture the Triad, Tag, ScoreMore, and Hunter can only be
+    // played with 2 or more players
+    if ( numplayers < 2 )
+    {
+        TURN_OFF_BATTLE_MODE( battle_ScoreMore );
+        TURN_OFF_BATTLE_MODE( battle_Tag );
+        TURN_OFF_BATTLE_MODE( battle_Hunter );
+        TURN_OFF_BATTLE_MODE( battle_CaptureTheTriad );
+    }
+
+    if ( ModeMenu[ ModeItems.curpos ].active != CP_CursorLocation )
+    {
+        for( i = 0; i < ModeItems.amount; i++ )
+        {
+            if ( ModeMenu[ i ].active == CP_Active )
+            {
+                ModeItems.curpos = i;
+                ModeMenu[ i ].active = CP_CursorLocation;
+                break;
+            }
+        }
+    }
+
+    DrawMenu( &ModeItems, &ModeMenu[ 0 ] );
+    DisplayInfo( 0 );
+    DrawBattleModeDescription( ModeItems.curpos );
+
+    FlipMenuBuf();
+}
+
+
+
+//****************************************************************************
+//
+// DrawBattleModeName()
+//
+//****************************************************************************
+
+void DrawBattleModeName( int which )
+{
+    int     width;
+    int     height;
+    char   *string;
+    font_t *temp;
+
+
+    if ( ( which < battle_Normal ) || ( which > battle_CaptureTheTriad ) )
+    {
+        return;
+    }
+
+    string = BattleModeNames[ which - battle_Normal ];
+
+    temp = CurrentFont;
+    CurrentFont = tinyfont;
+
+    VW_MeasurePropString ( string, &width, &height );
+    DrawMenuBufPropString ( ( 288 - width ) / 2, 4, string );
+//   DrawMenuBufPropString ( 270-width, 4, string );
+
+    CurrentFont = temp;
+}
+
+
+//****************************************************************************
+//
+// DrawBattleModeDescription()
+//
+//****************************************************************************
+
+void DrawBattleModeDescription( int w )
+{
+    int     width;
+    int     height;
+    char   *string;
+    font_t *temp;
+
+    EraseMenuBufRegion (25, 4, 287 - 25, 10 );
+
+    temp = CurrentFont;
+    CurrentFont = tinyfont;
+
+    string = BattleModeDescriptions[ w ];
+
+    // Capture the Triad, Tag, ScoreMore, and Hunter can only be
+    // played with 2 or more players
+    if ( numplayers < 2 )
+    {
+        switch( w + 1 )
+        {
+        case battle_ScoreMore :
+        case battle_Tag :
+        case battle_Hunter :
+        case battle_CaptureTheTriad :
+            string = "This mode can only be played with 2 or more players.";
+            break;
+        }
+    }
+
+#if ( SHAREWARE == 1 )
+    switch( w + 1 )
+    {
+    case battle_ScoreMore :
+    case battle_Scavenger :
+    case battle_Tag :
+    case battle_Eluder :
+    case battle_Deluder :
+    case battle_CaptureTheTriad :
+        string = "See Ordering Info to find out how to get this game.";
+        break;
+    }
+#endif
+
+    VW_MeasurePropString ( string, &width, &height );
+    DrawMenuBufPropString ( ( 288 - width ) / 2, 4, string );
+
+    CurrentFont = temp;
+}
+
+
+//****************************************************************************
+//
+// CP_BattleModes ()
+//
+//****************************************************************************
+
+void CP_BattleModes ( void )
+{
+    int which;
+    static char Warning = 0;
+
+    //
+    // ALREADY IN A GAME?
+    //
+    if ( ingame )
+    {
+        if ( !CP_DisplayMsg( CURGAME, 12 ) )
+        {
+            return;
+        }
+        else
+        {
+            EndGameStuff();
+        }
+    }
+
+    if ( ( numplayers==1 ) && ( Warning == 0 ) )
+    {
+        Warning = 1;
+        CP_OnePlayerWarningMessage();
+    }
+
+    DrawBattleModes ();
+
+    damagecount = 0;
+    BATTLEMODE  = true;
+
+    do
+    {
+        which = HandleMenu( &ModeItems, &ModeMenu[ 0 ],
+                            DrawBattleModeDescription );
+    }
+    while ( which >= 0 );
+
+    handlewhich = 100;
+
+    if ( !StartGame )
+    {
+        BATTLEMODE = false;
+        gamestate.battlemode = battle_StandAloneGame;
+    }
+}
+
+//****************************************************************************
+//
+// DrawBattleOptions ()
+//
+//****************************************************************************
+
+void DrawBattleOptions (void)
+{
+    int i;
+
+    MenuNum = 1;
+
+    SetAlternateMenuBuf();
+    ClearMenuBuf();
+    SetMenuTitle ("Battle Mode Options");
+
+    MN_MakeActive ( &BOptItems, &BOptMenu[0], BOptItems.curpos );
+
+    switch( gamestate.battlemode )
+    {
+    case battle_Collector :
+        BOptMenu[2].active = CP_Inactive; // Ammo
+        BOptMenu[6].active = CP_Inactive; // Point Goal
+        break;
+
+    case battle_Scavenger :
+        BOptMenu[6].active = CP_Inactive; // Point Goal
+        break;
+
+    case battle_Tag :
+        BOptMenu[2].active = CP_Inactive; // Ammo
+        break;
+
+    case battle_Eluder :
+        BOptMenu[2].active = CP_Inactive; // Ammo
+        BOptMenu[3].active = CP_Inactive; // Hit points
+        BOptMenu[7].active = CP_Inactive; // Danger damage
+        break;
+    }
+
+    if ( BOptMenu[ BOptItems.curpos ].active == CP_Inactive )
+    {
+        // Find an available cursor position
+        for( i = 0; i < BOptItems.amount; i++ )
+        {
+            if ( BOptMenu[ i ].active == CP_Active )
+            {
+                BOptMenu[ i ].active = CP_CursorLocation;
+                BOptItems.curpos = i;
+                break;
+            }
+        }
+    }
+
+    DrawBattleModeName( gamestate.battlemode );
+    DrawBattleOptionDescription( BOptItems.curpos );
+    DrawMenu (&BOptItems, &BOptMenu[0]);
+    DisplayInfo (0);
+    FlipMenuBuf();
+}
+
+
+//****************************************************************************
+//
+// CP_BattleOptions ()
+//
+//****************************************************************************
+
+void CP_BattleOptions (void)
+{
+    int which;
+
+    DrawBattleOptions ();
+
+    do
+    {
+        which = HandleMenu (&BOptItems, &BOptMenu[0], DrawBattleOptionDescription);
+
+    } while (which >= 0);
+
+    handlewhich = 100;
+//   WriteBattleConfig();
+    CalcTics();
+
+    DrawBattleMenu ();
+}
+
+
+
+//****************************************************************************
+//
+// DrawColorMenu ()
+//
+//****************************************************************************
+
+
+void DrawColorMenu( void )
+{
+    int   width;
+    int   height;
+    char *text;
+
+    SetAlternateMenuBuf();
+    ClearMenuBuf();
+    SetMenuTitle ("Uniform Color");
+
+    CurrentFont = smallfont;
+
+    text = colorname[ locplayerstate->uniformcolor ];
+    VW_MeasurePropString ( text, &width, &height );
+    DrawMenuBufPropString ( ( 320 - width ) / 2 - 16, MENU_Y + 5, text );
+    DisplayInfo( 8 );
+    EraseMenuBufRegion( COLORX, COLORY, COLORW, COLORH );
+    DrawTMenuBufBox( COLORX, COLORY, COLORW, COLORH );
+    DrawColoredMenuBufItem( COLORX - 36, COLORY - 33,
+                            W_GetNumForName( playerwadname[ locplayerstate->player ] ),
+                            locplayerstate->uniformcolor);
+
+
+    if ( ( gamestate.battlemode != battle_StandAloneGame ) &&
+            ( consoleplayer == 0 ) )
+    {
+        DrawBattleModeName( gamestate.battlemode );
+    }
+
+    FlipMenuBuf();
+}
+
+
+//****************************************************************************
+//
+// CP_ColorSelection ()
+//
+//****************************************************************************
+
+int CP_ColorSelection (void)
+{
+    int status;
+
+    locplayerstate->uniformcolor = DefaultPlayerColor;
+
+    DrawColorMenu ();
+    status = ColorMenu();
+    return( status );
+}
+
+int ColorMenu
+(
+    void
+)
+
+{
+    ControlInfo ci;
+    int colorindex;
+    char *text;
+    int width;
+    int height;
+    int timer;
+    int baseshape;
+    int status;
+    boolean update;
+    boolean done;
+
+    colorindex = DefaultPlayerColor;
+    timer      = GetTicCount();
+    baseshape  = W_GetNumForName( playerwadname[ locplayerstate->player ] );
+
+    update = false;
+    done   = false;
+    while( !done )
+    {
+        ReadAnyControl( &ci );
+        if ( ( ci.dir == dir_East ) && ( ( GetTicCount() - timer ) > 5 ) )
+        {
+            update = true;
+            timer = GetTicCount();
+
+            colorindex++;
+            if ( colorindex >= MAXPLAYERCOLORS )
+            {
+                colorindex = 0;
+            }
+
+            MN_PlayMenuSnd( SD_MOVECURSORSND );
+        }
+
+        if ( ( ci.dir == dir_West ) && ( ( GetTicCount() - timer ) > 5 ) )
+        {
+            update = true;
+            timer = GetTicCount();
+
+            colorindex--;
+            if ( colorindex < 0 )
+            {
+                colorindex = MAXPLAYERCOLORS - 1;
+            }
+            MN_PlayMenuSnd( SD_MOVECURSORSND );
+        }
+
+        if ( update )
+        {
+            update = false;
+            DefaultPlayerColor = colorindex;
+            locplayerstate->uniformcolor = colorindex;
+            text = colorname[ locplayerstate->uniformcolor ];
+
+            EraseMenuBufRegion( 0, MENU_Y + 5, 200, 10 );
+            EraseMenuBufRegion( COLORX, COLORY, COLORW, COLORH );
+            VW_MeasurePropString( text, &width, &height );
+            DrawMenuBufPropString( ( 320 - width ) / 2 - 16, MENU_Y + 5, text );
+            DrawTMenuBufBox( COLORX, COLORY, COLORW, COLORH );
+            DrawColoredMenuBufItem( COLORX - 36, COLORY - 33,
+                                    baseshape, locplayerstate->uniformcolor );
+        }
+
+        if ( ci.button0 || Keyboard[ sc_Space ] || Keyboard[sc_Enter ] )
+        {
+            Keyboard[ sc_Space ] = 0;
+            Keyboard[ sc_Enter ] = 0;
+            MN_PlayMenuSnd( SD_SELECTSND );
+            status = 1;
+            done = true;
+        }
+        else if ( ci.button1 || Keyboard[ sc_Escape ] )
+        {
+            MN_PlayMenuSnd( SD_ESCPRESSEDSND );
+            status = 0;
+            done = true;
+        }
+
+        RefreshMenuBuf( 0 );
+    }
+
+    IN_ClearKeysDown();
+    return( status );
+}
+
+
+//****************************************************************************
+//
+// CP_PlayerSelection ()
+//
+//****************************************************************************
+int CP_PlayerSelection
+(
+    void
+)
+
+{
+    int which;
+
+    // Do Pick-A-Player menu
+    DrawPlayerMenu();
+
+    do
+    {
+        which = HandleMenu( &PlayerItems, &PlayerMenu[ 0 ], DrawNewPlayerDiff );
+        if ( which < 0 )
+        {
+            handlewhich = 1;
+            return( 0 );
+        }
+
+#if ( SHAREWARE == 1 )
+        if ( PlayerMenu[ which ].active == CP_SemiActive )
+        {
+            CP_ErrorMsg( "Choose Player",
+                         "Read the Ordering Info section from the Main Menu to "
+                         "find out how to get the other characters.",
+                         mn_smallfont );
+
+            DrawPlayerMenu();
+        }
+#endif
+    }
+    while( PlayerMenu[ which ].active == CP_SemiActive );
+
+
+#if ( SHAREWARE == 1 )
+    DefaultPlayerCharacter = 0;
+    locplayerstate->player = 0;
+#else
+    DefaultPlayerCharacter = which;
+    locplayerstate->player = which;
+#endif
+
+    return (1);
+}
+
+//****************************************************************************
+//
+// CP_OnePlayerWarningMessage ()
+//
+//****************************************************************************
+
+void CP_OnePlayerWarningMessage
+(
+    void
+)
+
+{
+    CP_ErrorMsg( "Comm-bat Warning",
+                 "Comm-bat is designed for modem and network play.  "
+                 "One player mode is provided for exploration.  The "
+                 "Collector battle mode is still fun on your own.",
+                 mn_smallfont );
+}
+
+
+//****************************************************************************
+//
+// CP_CaptureTheTriadError()
+//
+//****************************************************************************
+
+void CP_CaptureTheTriadError
+(
+    void
+)
+
+{
+    SetupMenuBuf();
+    SetUpControlPanel();
+
+    CP_ErrorMsg( "Comm-bat Warning",
+                 "Capture the Traid can only be played with 2 teams."
+                 "  All players must return to the menu to choose their "
+                 "team colors.", mn_largefont );
+
+    CleanUpControlPanel();
+    ShutdownMenuBuf();
+}
+
+
+//****************************************************************************
+//
+// CP_TeamPlayErrorMessage()
+//
+//****************************************************************************
+
+void CP_TeamPlayErrorMessage
+(
+    void
+)
+
+{
+    SetupMenuBuf();
+    SetUpControlPanel();
+
+    CP_ErrorMsg( "Comm-bat Warning",
+                 "Team play can only be played with 2 or more teams."
+                 "  All players must return to the menu to choose their "
+                 "team colors.", mn_largefont );
+
+    CleanUpControlPanel();
+    ShutdownMenuBuf();
+}
+
+
+//****************************************************************************
+//
+// CP_ModemGameMessage ()
+//
+//****************************************************************************
+
+#define SITELINES 8
+
+char *sitemessage[] =
+{
+    "HEY! ARE YOU PLAYING ON AN ILLEGAL COPY?",
+    "Network players: it's easy to play legally!",
+    "Just get a site license.  For a little over",
+    "the price of two games, you get 10 more battle",
+    "levels, 11 command cards, and a signed Site",
+    "License.  We don't charge you for 11 copies--",
+    "just for two!  Call 1-800-APOGEE1 to order.",
+    "For more on site licenses, see ORDERING INFO."
+};
+
+void CP_ModemGameMessage (int player  )
+
+{
+    int i;
+    EnableScreenStretch();
+    // SetTextMode (  );
+
+    SetAlternateMenuBuf();
+    ClearMenuBuf();
+    SetMenuTitle ("Game Message");
+
+    newfont1 = (font_t *)W_CacheLumpName( "newfnt1", PU_CACHE, Cvt_font_t, 1);
+    CurrentFont = newfont1;
+    if ( modemgame == false )
+    {
+        WindowW = 288;
+        WindowH = 158;
+        PrintX = WindowX = 0;
+        PrintY = WindowY = 60;
+        MenuBufCPrint ("Please wait.\nLoading game.");
+    }
+    else
+    {
+        WindowW = 288;
+        WindowH = 158;
+        PrintX = WindowX = 0;
+        PrintY = WindowY = 50;
+
+        if (networkgame==true)
+        {
+            PrintY = WindowY = 28;
+        }
+
+        if ( player == 0 )
+        {
+            MenuBufCPrint ("Please wait for\nplayers to choose\ntheir characters.");
+        }
+        else
+        {
+            MenuBufCPrint ("Please wait while\nMaster selects\nCOMM-BAT options.");
+        }
+
+        if (gamestate.Product != ROTT_SITELICENSE)
+        {
+            if (networkgame==true)
+            {
+                for( i = 0; i < SITELINES; i++ )
+                {
+                    PrintBattleOption( true, 68, 77 + i * 8,
+                                       sitemessage[ i ] );
+                }
+            }
+        }
+    }
+
+    FlipMenuBuf();
+    RefreshMenuBuf (0);
+
+    DisableScreenStretch();
+}
+
+
+//****************************************************************************
+//
+// DrawGravityMenu ()
+//
+//****************************************************************************
+
+void DrawGravityMenu (void)
+{
+    MenuNum = 1;
+
+    SetAlternateMenuBuf ();
+    ClearMenuBuf();
+    SetMenuTitle ("Gravity");
+
+
+    if ( ( gamestate.battlemode != battle_StandAloneGame ) &&
+            ( consoleplayer == 0 ) )
+    {
+        DrawBattleModeName( gamestate.battlemode );
+    }
+
+    MN_DrawButtons (&GravityItems, &GravityMenu[0],
+                    BATTLE_Options[gamestate.battlemode].Gravity, GravityNums);
+    MN_GetActive (&GravityItems, &GravityMenu[0],
+                  BATTLE_Options[gamestate.battlemode].Gravity, GravityNums);
+
+    DrawMenu (&GravityItems, &GravityMenu[0]);
+    DrawGravityOptionDescription( GravityItems.curpos );
+    PrintBattleOption( true, 32, 79,
+                       "WARNING: High gravity has an unfortunate side effect in" );
+    PrintBattleOption( true, 32, 87,
+                       "some levels.  It is possible to jump into an area that is" );
+    PrintBattleOption( true, 32, 95,
+                       "impossible, or at least extremely difficult to get out" );
+    PrintBattleOption( true, 32, 103,
+                       "of.  In these situations, the only thing you can do is" );
+    PrintBattleOption( true, 32, 111,
+                       "kill your character, or find some kindly soul to do it" );
+    PrintBattleOption( true, 32, 119,
+                       "for you.  If this fails, you'll just have to end your game." );
+
+    DisplayInfo( 0 );
+
+    FlipMenuBuf();
+}
+
+
+//****************************************************************************
+//
+// CP_GravityOptions ()
+//
+//****************************************************************************
+
+void CP_GravityOptions (void)
+{
+    int which;
+
+    DrawGravityMenu ();
+
+    do
+    {
+        which = HandleMenu (&GravityItems, &GravityMenu[0], DrawGravityOptionDescription);
+
+        if (which >= 0)
+            BATTLE_Options[gamestate.battlemode].Gravity = GravityNums[ which ];
+
+        MN_DrawButtons (&GravityItems, &GravityMenu[0],
+                        BATTLE_Options[gamestate.battlemode].Gravity, GravityNums);
+
+    } while (which >= 0);
+
+    handlewhich = 100;
+    DrawBattleOptions ();
+}
+
+
+//****************************************************************************
+//
+// DrawSpeedMenu ()
+//
+//****************************************************************************
+
+void DrawSpeedMenu (void)
+{
+    MenuNum = 1;
+
+    SetAlternateMenuBuf ();
+    ClearMenuBuf();
+    SetMenuTitle ("Speed");
+
+
+    if ( ( gamestate.battlemode != battle_StandAloneGame ) &&
+            ( consoleplayer == 0 ) )
+    {
+        DrawBattleModeName( gamestate.battlemode );
+    }
+
+    MN_DrawButtons (&SpeedItems, &SpeedMenu[0],
+                    BATTLE_Options[gamestate.battlemode].Speed, OptionNums );
+    MN_GetActive (&SpeedItems, &SpeedMenu[0],
+                  BATTLE_Options[gamestate.battlemode].Speed, OptionNums );
+
+    DrawMenu (&SpeedItems, &SpeedMenu[0]);
+    DrawSpeedOptionDescription( SpeedItems.curpos );
+    DisplayInfo (0);
+    FlipMenuBuf();
+}
+
+
+//****************************************************************************
+//
+// CP_SpeedOptions ()
+//
+//****************************************************************************
+
+void CP_SpeedOptions (void)
+{
+    int which;
+
+    DrawSpeedMenu ();
+
+    do
+    {
+        which = HandleMenu (&SpeedItems, &SpeedMenu[0], DrawSpeedOptionDescription);
+
+        if (which >= 0)
+            BATTLE_Options[gamestate.battlemode].Speed = which;
+
+        MN_DrawButtons (&SpeedItems, &SpeedMenu[0],
+                        BATTLE_Options[gamestate.battlemode].Speed, OptionNums );
+    } while (which >= 0);
+
+    handlewhich = 100;
+    DrawBattleOptions ();
+}
+
+
+//****************************************************************************
+//
+// DrawAmmoPerWeaponMenu ()
+//
+//****************************************************************************
+void DrawAmmoPerWeaponMenu
+(
+    void
+)
+
+{
+    MenuNum = 1;
+
+    SetAlternateMenuBuf();
+    ClearMenuBuf();
+    SetMenuTitle ("Ammo Per Weapon");
+
+    if ( ( gamestate.battlemode != battle_StandAloneGame ) &&
+            ( consoleplayer == 0 ) )
+    {
+        DrawBattleModeName( gamestate.battlemode );
+    }
+
+    MN_DrawButtons( &AmmoPerWeaponItems, &AmmoPerWeaponMenu[ 0 ],
+                    BATTLE_Options[ gamestate.battlemode ].Ammo, OptionNums );
+
+    MN_GetActive( &AmmoPerWeaponItems, &AmmoPerWeaponMenu[ 0 ],
+                  BATTLE_Options[ gamestate.battlemode ].Ammo, OptionNums );
+
+    DrawMenu( &AmmoPerWeaponItems, &AmmoPerWeaponMenu[ 0 ] );
+
+    PrintBattleOption( true, 32, 79,
+                       "WARNING: Infinite ammo can seriously alter the balance of" );
+    PrintBattleOption( true, 32, 87,
+                       "the game.  We recommend that you only use it occasionally." );
+    PrintBattleOption( true, 32, 95,
+                       "It tends to only work well on small levels with lots of" );
+    PrintBattleOption( true, 32, 103,
+                       "weapons, where the action is far more intense.  On large" );
+    PrintBattleOption( true, 32, 111,
+                       "levels, you may find it causes people to wait in easily" );
+    PrintBattleOption( true, 32, 119,
+                       "guardable areas and pick off anyone that comes in the room" );
+    PrintBattleOption( true, 32, 127,
+                       "(creating an unfair advantage)." );
+
+    if ( AmmoPerWeaponItems.curpos == 2 )
+    {
+        PrintBattleOption( true, 102, 136, "You have been warned." );
+    }
+
+    DrawAmmoOptionDescription( AmmoPerWeaponItems.curpos );
+    DisplayInfo( 0 );
+    FlipMenuBuf();
+}
+
+
+//****************************************************************************
+//
+// CP_AmmoPerWeaponOptions ()
+//
+//****************************************************************************
+void CP_AmmoPerWeaponOptions
+(
+    void
+)
+
+{
+    int which;
+
+    DrawAmmoPerWeaponMenu();
+
+    do
+    {
+        which = HandleMenu( &AmmoPerWeaponItems, &AmmoPerWeaponMenu[ 0 ], DrawAmmoOptionDescription);
+
+        if (which >= 0)
+        {
+            if ( AmmoPerWeaponItems.curpos == 2 )
+            {
+                MN_PlayMenuSnd( SD_LIGHTNINGSND );
+                PrintBattleOption( true, 102, 136, "You have been warned." );
+                VL_FillPalette(255,255,255);
+                VL_FadeIn(0,255,origpal,10);
+            }
+            else if ( BATTLE_Options[ gamestate.battlemode ].Ammo == 2 )
+            {
+                EraseMenuBufRegion( 102, 136, 84, 8 );
+                MN_PlayMenuSnd( SD_PLAYERTCSND );
+            }
+
+            BATTLE_Options[ gamestate.battlemode ].Ammo = which;
+        }
+
+        MN_DrawButtons( &AmmoPerWeaponItems, &AmmoPerWeaponMenu[ 0 ],
+                        BATTLE_Options[ gamestate.battlemode ].Ammo, OptionNums );
+    }
+    while( which >= 0 );
+
+    handlewhich = 100;
+    DrawBattleOptions();
+}
+
+
+//****************************************************************************
+//
+// DrawHitPointsMenu ()
+//
+//****************************************************************************
+void DrawHitPointsMenu
+(
+    void
+)
+
+{
+    MenuNum = 1;
+
+    SetAlternateMenuBuf ();
+    ClearMenuBuf();
+    SetMenuTitle ("Player Hitpoints");
+
+    if ( ( gamestate.battlemode != battle_StandAloneGame ) &&
+            ( consoleplayer == 0 ) )
+    {
+        DrawBattleModeName( gamestate.battlemode );
+    }
+
+    MN_DrawButtons( &HitPointItems, &HitPointMenu[ 0 ],
+                    BATTLE_Options[ gamestate.battlemode ].HitPoints, HitPointNums );
+
+    MN_GetActive( &HitPointItems, &HitPointMenu[ 0 ],
+                  BATTLE_Options[ gamestate.battlemode ].HitPoints, HitPointNums );
+
+    DrawMenu( &HitPointItems, &HitPointMenu[ 0 ] );
+    DrawHitPointsOptionDescription( HitPointItems.curpos );
+    DisplayInfo( 0 );
+    FlipMenuBuf();
+}
+
+
+//****************************************************************************
+//
+// CP_HitPointsOptions ()
+//
+//****************************************************************************
+
+void CP_HitPointsOptions (void)
+{
+    int which;
+
+    DrawHitPointsMenu ();
+
+    do
+    {
+        which = HandleMenu (&HitPointItems, &HitPointMenu[0], DrawHitPointsOptionDescription);
+
+        if (which >= 0)
+            BATTLE_Options[gamestate.battlemode].HitPoints = HitPointNums[ which ];
+
+        MN_DrawButtons (&HitPointItems, &HitPointMenu[0],
+                        BATTLE_Options[gamestate.battlemode].HitPoints, HitPointNums);
+
+    } while (which >= 0);
+
+    handlewhich = 100;
+    DrawBattleOptions ();
+}
+
+
+
+//****************************************************************************
+//
+// DrawSpawnControlMenu ()
+//
+//****************************************************************************
+void DrawSpawnControlMenu
+(
+    void
+)
+
+{
+    int i;
+
+    MenuNum = 1;
+
+    SetAlternateMenuBuf();
+    ClearMenuBuf();
+    SetMenuTitle ("Radical Options");
+
+    MN_MakeActive( &SpawnItems, &SpawnMenu[ 0 ], SpawnItems.curpos );
+
+#if ( SHAREWARE == 1 )
+    BATTLE_Options[ gamestate.battlemode ].SpawnMines = false;
+    SpawnMenu[ 3 ].active = CP_Inactive; // Mines
+#endif
+
+    switch( gamestate.battlemode )
+    {
+    case battle_Normal :
+        break;
+
+    case battle_ScoreMore :
+        break;
+
+    case battle_Collector :
+        SpawnMenu[ 2 ].active = CP_Inactive; // Weapons
+        SpawnMenu[ 5 ].active = CP_Inactive; // Persistence
+        SpawnMenu[ 6 ].active = CP_Inactive; // Random Weapons
+        SpawnMenu[ 7 ].active = CP_Inactive; // Friendly Fire
+        break;
+
+    case battle_Scavenger :
+        SpawnMenu[ 7 ].active = CP_Inactive; // Friendly Fire
+        break;
+
+    case battle_Hunter :
+        break;
+
+    case battle_Tag :
+        SpawnMenu[ 2 ].active = CP_Inactive; // Weapons
+        SpawnMenu[ 5 ].active = CP_Inactive; // Persistence
+        SpawnMenu[ 6 ].active = CP_Inactive; // Random Weapons
+        break;
+
+    case battle_Eluder :
+        SpawnMenu[ 1 ].active = CP_Inactive; // Health
+        SpawnMenu[ 2 ].active = CP_Inactive; // Weapons
+        SpawnMenu[ 4 ].active = CP_Inactive; // Respawn
+        SpawnMenu[ 5 ].active = CP_Inactive; // Persistence
+        SpawnMenu[ 6 ].active = CP_Inactive; // Random Weapons
+        SpawnMenu[ 7 ].active = CP_Inactive; // Friendly Fire
+        break;
+
+    case battle_Deluder :
+        SpawnMenu[ 7 ].active = CP_Inactive; // Friendly Fire
+        break;
+
+    case battle_CaptureTheTriad :
+        SpawnMenu[ 7 ].active = CP_Inactive; // Friendly Fire
+        break;
+    }
+
+    if ( SpawnMenu[ SpawnItems.curpos ].active == CP_Inactive )
+    {
+        // Find an available cursor position
+        for( i = 0; i < SpawnItems.amount; i++ )
+        {
+            if ( SpawnMenu[ i ].active == CP_Active )
+            {
+                SpawnMenu[ i ].active = CP_CursorLocation;
+                SpawnItems.curpos = i;
+                break;
+            }
+        }
+    }
+
+    if ( ( gamestate.battlemode != battle_StandAloneGame ) &&
+            ( consoleplayer == 0 ) )
+    {
+        DrawBattleModeName( gamestate.battlemode );
+    }
+
+    DrawSpawnControlButtons();
+
+    MN_GetCursorLocation( &SpawnItems, &SpawnMenu[ 0 ] );
+
+    DrawMenu( &SpawnItems, &SpawnMenu[ 0 ] );
+    DrawRadicalOptionDescription( SpawnItems.curpos );
+    DisplayInfo( 0 );
+    FlipMenuBuf();
+}
+
+
+//****************************************************************************
+//
+// DrawSpawnControlButtons ()
+//
+//****************************************************************************
+void DrawSpawnControlButtons
+(
+    void
+)
+
+{
+    int x;
+    int y;
+    int button_on;
+    int button_off;
+
+    button_on  = W_GetNumForName( "snd_on" );
+    button_off = W_GetNumForName( "snd_off" );
+
+    x = SpawnItems.x + 18;
+    y = SpawnItems.y - 1;
+
+    if ( BATTLE_Options[ gamestate.battlemode ].SpawnDangers )
+    {
+        DrawMenuBufItem( x, y, button_on );
+    }
+    else
+    {
+        EraseMenuBufRegion( x, y, 16, 16 );
+        DrawMenuBufItem( x, y, button_off );
+    }
+
+    y += 14;
+    if ( BATTLE_Options[ gamestate.battlemode ].SpawnHealth )
+    {
+        DrawMenuBufItem( x, y, button_on );
+    }
+    else
+    {
+        EraseMenuBufRegion( x, y, 16, 16 );
+        DrawMenuBufItem( x, y, button_off );
+    }
+
+    y += 14;
+    if ( BATTLE_Options[ gamestate.battlemode ].SpawnWeapons )
+    {
+        DrawMenuBufItem( x, y, button_on );
+    }
+    else
+    {
+        EraseMenuBufRegion( x, y, 16, 16 );
+        DrawMenuBufItem( x, y, button_off );
+    }
+
+    y += 14;
+    if ( BATTLE_Options[ gamestate.battlemode ].SpawnMines )
+    {
+        DrawMenuBufItem( x, y, button_on );
+    }
+    else
+    {
+        EraseMenuBufRegion( x, y, 16, 16 );
+        DrawMenuBufItem( x, y, button_off );
+    }
+
+    y += 14;
+    if ( BATTLE_Options[ gamestate.battlemode ].RespawnItems )
+    {
+        DrawMenuBufItem( x, y, button_on );
+    }
+    else
+    {
+        EraseMenuBufRegion( x, y, 16, 16 );
+        DrawMenuBufItem( x, y, button_off );
+    }
+
+    y += 14;
+    if ( BATTLE_Options[ gamestate.battlemode ].WeaponPersistence )
+    {
+        DrawMenuBufItem( x, y, button_on );
+    }
+    else
+    {
+        EraseMenuBufRegion( x, y, 16, 16 );
+        DrawMenuBufItem( x, y, button_off );
+    }
+
+    y += 14;
+    if ( BATTLE_Options[ gamestate.battlemode ].RandomWeapons )
+    {
+        DrawMenuBufItem( x, y, button_on );
+    }
+    else
+    {
+        EraseMenuBufRegion( x, y, 16, 16 );
+        DrawMenuBufItem( x, y, button_off );
+    }
+
+    y += 14;
+    if ( BATTLE_Options[ gamestate.battlemode ].FriendlyFire )
+    {
+        DrawMenuBufItem( x, y, button_on );
+    }
+    else
+    {
+        EraseMenuBufRegion( x, y, 16, 16 );
+        DrawMenuBufItem( x, y, button_off );
+    }
+}
+
+
+//****************************************************************************
+//
+// CP_SpawnControlOptions ()
+//
+//****************************************************************************
+void CP_SpawnControlOptions
+(
+    void
+)
+
+{
+    int which;
+
+    DrawSpawnControlMenu();
+
+    do
+    {
+        which = HandleMenu( &SpawnItems, &SpawnMenu[ 0 ], DrawRadicalOptionDescription );
+        switch( which )
+        {
+        case 0 :
+            BATTLE_Options[ gamestate.battlemode ].SpawnDangers =
+                !BATTLE_Options[ gamestate.battlemode ].SpawnDangers;
+            break;
+
+        case 1 :
+            BATTLE_Options[ gamestate.battlemode ].SpawnHealth =
+                !BATTLE_Options[ gamestate.battlemode ].SpawnHealth;
+            break;
+
+        case 2 :
+            BATTLE_Options[ gamestate.battlemode ].SpawnWeapons =
+                !BATTLE_Options[ gamestate.battlemode ].SpawnWeapons;
+            break;
+
+        case 3 :
+            BATTLE_Options[ gamestate.battlemode ].SpawnMines =
+                !BATTLE_Options[ gamestate.battlemode ].SpawnMines;
+            break;
+
+        case 4 :
+            BATTLE_Options[ gamestate.battlemode ].RespawnItems =
+                !BATTLE_Options[ gamestate.battlemode ].RespawnItems;
+            break;
+
+        case 5 :
+            BATTLE_Options[ gamestate.battlemode ].WeaponPersistence =
+                !BATTLE_Options[ gamestate.battlemode ].WeaponPersistence;
+            break;
+
+        case 6 :
+            BATTLE_Options[ gamestate.battlemode ].RandomWeapons =
+                !BATTLE_Options[ gamestate.battlemode ].RandomWeapons;
+            break;
+
+        case 7 :
+            BATTLE_Options[ gamestate.battlemode ].FriendlyFire =
+                !BATTLE_Options[ gamestate.battlemode ].FriendlyFire;
+            break;
+        }
+
+        DrawSpawnControlButtons();
+    }
+    while( which >= 0 );
+
+    handlewhich = 100;
+    DrawBattleOptions();
+}
+
+
+
+//****************************************************************************
+//
+// DrawLightLevelMenu ()
+//
+//****************************************************************************
+
+void DrawLightLevelMenu (void)
+{
+    MenuNum = 1;
+
+    SetAlternateMenuBuf ();
+    ClearMenuBuf();
+    SetMenuTitle ("Light Levels");
+
+
+    if ( ( gamestate.battlemode != battle_StandAloneGame ) &&
+            ( consoleplayer == 0 ) )
+    {
+        DrawBattleModeName( gamestate.battlemode );
+    }
+
+    MN_DrawButtons (&LightLevelItems, &LightLevelMenu[0],
+                    BATTLE_Options[gamestate.battlemode].LightLevel, OptionNums );
+    MN_GetActive (&LightLevelItems, &LightLevelMenu[0],
+                  BATTLE_Options[gamestate.battlemode].LightLevel, OptionNums );
+
+    DrawMenu (&LightLevelItems, &LightLevelMenu[0]);
+    DrawLightLevelOptionDescription( LightLevelItems.curpos );
+    DisplayInfo (0);
+    FlipMenuBuf();
+}
+
+
+//****************************************************************************
+//
+// CP_LightLevelOptions ()
+//
+//****************************************************************************
+
+void CP_LightLevelOptions (void)
+{
+    int which;
+
+    DrawLightLevelMenu ();
+
+    do
+    {
+        which = HandleMenu (&LightLevelItems, &LightLevelMenu[0], DrawLightLevelOptionDescription);
+
+        if (which >= 0)
+            BATTLE_Options[gamestate.battlemode].LightLevel = which;
+
+        MN_DrawButtons (&LightLevelItems, &LightLevelMenu[0],
+                        BATTLE_Options[gamestate.battlemode].LightLevel, OptionNums );
+
+    } while (which >= 0);
+
+    handlewhich = 100;
+    DrawBattleOptions ();
+}
+
+
+
+//****************************************************************************
+//
+// DrawPointGoalMenu()
+//
+//****************************************************************************
+
+void DrawPointGoalMenu
+(
+    void
+)
+
+{
+    MenuNum = 1;
+
+    SetAlternateMenuBuf();
+    ClearMenuBuf();
+    SetMenuTitle ("Point Goal");
+
+    if ( ( gamestate.battlemode != battle_StandAloneGame ) &&
+            ( consoleplayer == 0 ) )
+    {
+        DrawBattleModeName( gamestate.battlemode );
+    }
+
+    MN_DrawButtons( &PointGoalItems, &PointGoalMenu[ 0 ],
+                    BATTLE_Options[ gamestate.battlemode ].Kills, KillNums );
+
+    MN_GetActive( &PointGoalItems, &PointGoalMenu[ 0 ],
+                  BATTLE_Options[ gamestate.battlemode ].Kills, KillNums );
+
+    DrawMenu( &PointGoalItems, &PointGoalMenu[ 0 ] );
+    DrawPointGoalOptionDescription( PointGoalItems.curpos );
+    DisplayInfo( 0 );
+    FlipMenuBuf();
+}
+
+
+//****************************************************************************
+//
+// CP_PointGoalOptions()
+//
+//****************************************************************************
+
+void CP_PointGoalOptions
+(
+    void
+)
+
+{
+    int which;
+
+    DrawPointGoalMenu();
+
+    do
+    {
+        which = HandleMenu( &PointGoalItems, &PointGoalMenu[ 0 ], DrawPointGoalOptionDescription );
+
+        if ( which >= 0 )
+        {
+            BATTLE_Options[ gamestate.battlemode ].Kills = KillNums[ which ];
+
+            MN_DrawButtons( &PointGoalItems, &PointGoalMenu[ 0 ],
+                            BATTLE_Options[ gamestate.battlemode ].Kills, KillNums );
+        }
+    }
+    while( which >= 0 );
+
+    handlewhich = 100;
+    DrawBattleOptions();
+}
+
+
+//****************************************************************************
+//
+// DrawDangerMenu ()
+//
+//****************************************************************************
+
+void DrawDangerMenu (void)
+{
+    MenuNum = 1;
+
+    SetAlternateMenuBuf ();
+    ClearMenuBuf();
+    SetMenuTitle ("Danger Damage");
+
+
+    if ( ( gamestate.battlemode != battle_StandAloneGame ) &&
+            ( consoleplayer == 0 ) )
+    {
+        DrawBattleModeName( gamestate.battlemode );
+    }
+    MN_DrawButtons (&DangerItems, &DangerMenu[0],
+                    BATTLE_Options[gamestate.battlemode].DangerDamage, DangerNums);
+    MN_GetActive (&DangerItems, &DangerMenu[0],
+                  BATTLE_Options[gamestate.battlemode].DangerDamage, DangerNums);
+
+    DrawMenu (&DangerItems, &DangerMenu[0]);
+    DrawDangerDamageOptionDescription( DangerItems.curpos );
+    DisplayInfo (0);
+    FlipMenuBuf();
+}
+
+
+//****************************************************************************
+//
+// CP_DangerOptions ()
+//
+//****************************************************************************
+
+void CP_DangerOptions (void)
+{
+    int which;
+
+    DrawDangerMenu ();
+
+    do
+    {
+        which = HandleMenu (&DangerItems, &DangerMenu[0], DrawDangerDamageOptionDescription);
+
+        if (which >= 0)
+            BATTLE_Options[gamestate.battlemode].DangerDamage = DangerNums[which];
+
+        MN_DrawButtons (&DangerItems, &DangerMenu[0],
+                        BATTLE_Options[gamestate.battlemode].DangerDamage, DangerNums);
+
+    } while (which >= 0);
+
+    handlewhich = 100;
+    DrawBattleOptions ();
+}
+
+
+//****************************************************************************
+//
+// DrawTimeLimitMenu ()
+//
+//****************************************************************************
+
+void DrawTimeLimitMenu (void)
+{
+    MenuNum = 1;
+
+    SetAlternateMenuBuf ();
+    ClearMenuBuf();
+    SetMenuTitle ("Time Limit");
+
+
+    if ( ( gamestate.battlemode != battle_StandAloneGame ) &&
+            ( consoleplayer == 0 ) )
+    {
+        DrawBattleModeName( gamestate.battlemode );
+    }
+    MN_DrawButtons (&TimeLimitItems, &TimeLimitMenu[0],
+                    BATTLE_Options[gamestate.battlemode].TimeLimit, TimeLimitNums);
+    MN_GetActive (&TimeLimitItems, &TimeLimitMenu[0],
+                  BATTLE_Options[gamestate.battlemode].TimeLimit, TimeLimitNums);
+
+    if ( gamestate.battlemode == battle_Hunter )
+    {
+        TimeLimitMenu[7].active = CP_Inactive; // No time limit
+        if ( TimeLimitItems.curpos == 7 )
+        {
+            TimeLimitMenu[0].active = CP_CursorLocation;
+            TimeLimitItems.curpos = 0;
+        }
+    }
+
+    DrawMenu (&TimeLimitItems, &TimeLimitMenu[0]);
+    DrawTimeLimitOptionDescription( TimeLimitItems.curpos );
+    DisplayInfo (0);
+    FlipMenuBuf();
+}
+
+
+//****************************************************************************
+//
+// CP_TimeLimitOptions ()
+//
+//****************************************************************************
+
+void CP_TimeLimitOptions (void)
+{
+    int which;
+
+    DrawTimeLimitMenu ();
+
+    do
+    {
+        which = HandleMenu (&TimeLimitItems, &TimeLimitMenu[0], DrawTimeLimitOptionDescription);
+
+        if (which >= 0)
+            BATTLE_Options[gamestate.battlemode].TimeLimit = TimeLimitNums[which];
+
+        MN_DrawButtons (&TimeLimitItems, &TimeLimitMenu[0],
+                        BATTLE_Options[gamestate.battlemode].TimeLimit, TimeLimitNums);
+
+    } while (which >= 0);
+
+    handlewhich = 100;
+    DrawBattleOptions ();
+}
+
+void PrintBattleOption
+(
+    boolean inmenu,
+    int x,
+    int y,
+    char *text
+)
+
+{
+    if ( inmenu )
+    {
+        IFont = ( cfont_t * )W_CacheLumpName( "itnyfont", PU_CACHE, Cvt_cfont_t, 1 );
+        DrawMenuBufIString( x + 1, y + 1, text, 0 );
+        DrawMenuBufIString( x, y, text, ACTIVECOLOR );
+    }
+    else
+    {
+        PrintX = x;
+        PrintY = y;
+        US_BufPrint( text );
+    }
+}
+
+void ShowBattleOption
+(
+    boolean inmenu,
+    int PosX,
+    int PosY,
+    int column,
+    int Line,
+    char *text1,
+    char *text2
+)
+
+{
+    char text[ 80 ];
+    int x;
+    int y;
+
+    y = PosY + ( Line * 7 );
+    x = PosX + column * 120;
+
+    PrintBattleOption( inmenu, x, y, text1 );
+
+    strcpy( text, ": " );
+    strcat( text, text2 );
+
+    PrintBattleOption( inmenu, x + 60, y, text );
+}
+
+void ShowBattleOptions
+(
+    boolean inmenu,
+    int PosX,
+    int PosY
+)
+
+{
+    battle_type *options;
+    battle_type BatOps;
+    char *string;
+    char text[ 80 ];
+    int  width;
+    int  height;
+    int  temp;
+
+    CurrentFont = tinyfont;
+
+    strcpy( text, "CURRENT OPTIONS FOR " );
+    strcat( text, BattleModeNames[ gamestate.battlemode - battle_Normal ] );
+    VW_MeasurePropString ( text, &width, &height );
+    if ( inmenu )
+    {
+        temp = 288;
+    }
+    else
+    {
+        temp = 320;
+    }
+    PrintBattleOption( inmenu, (temp - width)/2, PosY, text );
+
+    PosY++;
+
+    BATTLE_GetOptions( &BatOps );
+    options = &BatOps;
+
+    ShowBattleOption( inmenu, PosX, PosY, 0, 1, "Friendly Fire",
+                      ( options->FriendlyFire ) ? "On" : "Off" );
+
+    ShowBattleOption( inmenu, PosX, PosY, 0, 2, "Weapon Persist",
+                      ( options->WeaponPersistence ) ? "On" : "Off" );
+
+    ShowBattleOption( inmenu, PosX, PosY, 0, 3, "Random Weapons",
+                      ( options->RandomWeapons ) ? "On" : "Off" );
+
+    ShowBattleOption( inmenu, PosX, PosY, 0, 4, "Respawn Items",
+                      ( options->RespawnItems ) ? "On" : "Off" );
+
+    ShowBattleOption( inmenu, PosX, PosY, 0, 5, "Spawn Health",
+                      ( options->SpawnHealth ) ? "On" : "Off" );
+
+    ShowBattleOption( inmenu, PosX, PosY, 0, 6, "Spawn Weapons",
+                      ( options->SpawnWeapons ) ? "On" : "Off" );
+
+    ShowBattleOption( inmenu, PosX, PosY, 0, 7, "Spawn Mines",
+                      ( options->SpawnMines ) ? "On" : "Off" );
+
+    ShowBattleOption( inmenu, PosX, PosY, 0, 8, "Spawn Dangers",
+                      ( options->SpawnDangers ) ? "On" : "Off" );
+
+    switch( options->DangerDamage )
+    {
+    case bo_danger_low :
+        string = "Low";
+        break;
+
+    case bo_danger_normal :
+        string = "Normal";
+        break;
+
+    case bo_danger_kill :
+        string = "Kill";
+        break;
+
+    default :
+        itoa( options->DangerDamage, text, 10 );
+        string = text;
+    }
+    ShowBattleOption( inmenu, PosX, PosY, 0, 9, "Danger Damage", string );
+
+    GetMapFileName ( text );
+    ShowBattleOption( inmenu, PosX, PosY, 0, 10, "Filename", text );
+
+    itoa( numplayers, text, 10 );
+    ShowBattleOption( inmenu, PosX, PosY, 1, 1, "Players", text );
+
+    if ( options->TimeLimit == bo_time_infinite )
+    {
+        string = "None";
+    }
+    else
+    {
+        itoa( options->TimeLimit, text, 10 );
+        string = text;
+    }
+    ShowBattleOption( inmenu, PosX, PosY, 1, 2, "Time Limit", string );
+
+    if ( ( gamestate.battlemode == battle_Collector ) ||
+            ( gamestate.battlemode == battle_Scavenger ) )
+    {
+        string = "?";
+    }
+    else
+    {
+        switch( options->Kills )
+        {
+        case bo_kills_random :
+            string = "Random";
+            break;
+
+        case bo_kills_blind :
+            string = "Blind";
+            break;
+
+        case bo_kills_infinite :
+            string = "Infinite";
+            break;
+
+        default :
+            itoa( options->Kills, text, 10 );
+            string = text;
+        }
+    }
+    ShowBattleOption( inmenu, PosX, PosY, 1, 3, "Point Goal", string );
+
+    switch( options->Ammo )
+    {
+    case bo_one_shot :
+        string = "One shot";
+        break;
+
+    case bo_normal_shots :
+        string = "Normal";
+        break;
+
+    case bo_infinite_shots :
+        string = "Gunfinity";
+        break;
+    }
+    ShowBattleOption( inmenu, PosX, PosY, 1, 4, "Ammo", string );
+
+    if ( options->HitPoints == bo_character_hitpoints )
+    {
+        string = "Character";
+    }
+    else
+    {
+        itoa( options->HitPoints, text, 10 );
+        string = text;
+    }
+    ShowBattleOption( inmenu, PosX, PosY, 1, 5, "Hit Points", string );
+
+    itoa( options->RespawnTime, text, 10 );
+    ShowBattleOption( inmenu, PosX, PosY, 1, 6, "Respawn Time", text );
+
+    switch( options->Speed )
+    {
+    case bo_normal_speed :
+        string = "Normal";
+        break;
+
+    case bo_fast_speed :
+        string = "Fast";
+        break;
+    }
+    ShowBattleOption( inmenu, PosX, PosY, 1, 7, "Speed", string );
+
+    switch( options->LightLevel )
+    {
+    case bo_light_dark :
+        string = "Dark";
+        break;
+
+    case bo_light_normal :
+        string = "Normal";
+        break;
+
+    case bo_light_bright :
+        string = "Bright";
+        break;
+
+    case bo_light_fog :
+        string = "Fog";
+        break;
+
+    case bo_light_periodic :
+        string = "Periodic";
+        break;
+
+    case bo_light_lightning :
+        string = "Lightning";
+        break;
+    }
+    ShowBattleOption( inmenu, PosX, PosY, 1, 8, "Light", string );
+
+    if ( options->Gravity == NORMAL_GRAVITY )
+    {
+        string = "Normal";
+        temp = NORMAL_GRAVITY;
+    }
+    else if ( options->Gravity < NORMAL_GRAVITY )
+    {
+        string = "Low";
+        temp = LOW_GRAVITY;
+    }
+    else
+    {
+        string = "High";
+        temp = HIGH_GRAVITY;
+    }
+
+    strcpy( text, string );
+    if ( options->Gravity < (unsigned int)temp )
+    {
+        strcat( text, "-" );
+    }
+
+    if ( options->Gravity > (unsigned int)temp )
+    {
+        strcat( text, "+" );
+    }
+    ShowBattleOption( inmenu, PosX, PosY, 1, 9, "Gravity", text );
+}
+
+
+//****************************************************************************
+//
+// SetMenuHeader()
+//
+//****************************************************************************
+
+void SetMenuHeader
+(
+    char *header
+)
+
+{
+    int width;
+    int height;
+
+    EraseMenuBufRegion( 16, 0, 256, 16 );
+
+    CurrentFont = tinyfont;
+    VW_MeasurePropString ( header, &width, &height );
+    DrawMenuBufPropString ( ( 288 - width ) / 2, 4, header );
+
+    RefreshMenuBuf( 0 );
+}
+
+
+//****************************************************************************
+//
+// DrawMultiPageCustomMenu()
+//
+//****************************************************************************
+
+void DrawMultiPageCustomMenu
+(
+    char *title,
+    void ( *redrawfunc )( void )
+)
+
+{
+    SetAlternateMenuBuf();
+    ClearMenuBuf();
+    SetMenuTitle( title );
+
+    DrawMenu( &MultiPageCustomItems, &MultiPageCustomMenu[ 0 ] );
+
+    DisplayInfo( 0 );
+
+    if ( redrawfunc != NULL )
+    {
+        redrawfunc();
+    }
+
+    CalcTics();
+    FlipMenuBuf();
+    RefreshMenuBuf( 0 );
+}
+
+
+//****************************************************************************
+//
+// HandleMultiPageCustomMenu()
+//
+//****************************************************************************
+
+int HandleMultiPageCustomMenu
+(
+    char **names,
+    int   amount,
+    int   curpos,
+    char *title,
+    void  ( *routine )( int w ),
+    void ( *redrawfunc )( void ),
+    boolean exitonselect
+)
+
+{
+    boolean redraw;
+    int  page;
+    int  cursorpos;
+    int  maxpos;
+    int  numpos;
+    int  which;
+    int  selection;
+    int  i;
+    char letter;
+
+    MenuNum = 11;
+
+    cursorpos = curpos % MAXCUSTOM;
+    page      = curpos - cursorpos;
+    MultiPageCustomItems.curpos = cursorpos + 2;
+
+    redraw = true;
+
+    do
+    {
+        if ( redraw )
+        {
+            redraw = false;
+            MultiPageCustomMenu[ 0 ].active = CP_Active;
+            MultiPageCustomMenu[ 1 ].active = CP_Active;
+            if ( page == 0 )
+            {
+                MultiPageCustomMenu[ 1 ].active = CP_Inactive;
+            }
+
+            maxpos = page + MAXCUSTOM;
+            if ( maxpos >= amount )
+            {
+                MultiPageCustomMenu[ 0 ].active = CP_Inactive;
+                maxpos = amount;
+            }
+
+            numpos = maxpos - page + 2;
+            MultiPageCustomItems.amount = numpos;
+
+            for( i = 2; i < numpos; i++ )
+            {
+                MultiPageCustomMenu[ i ].active = CP_Active;
+
+                // Set the name of the level
+                strcpy (MultiPageCustomNames[ i ], names[ page + i - 2 ]);
+
+                // Set the quick key
+                letter = *names[ page + i - 2 ];
+
+                // Force it to upper case
+                if ( ( letter >= 'a' ) && ( letter <= 'z' ) )
+                {
+                    letter = letter - 'a' + 'A';
+                }
+
+                // Only use letters
+                if ( ( letter < 'A' ) || ( letter > 'Z' ) )
+                {
+                    letter = 'a';
+                }
+                MultiPageCustomMenu[ i ].letter = letter;
+            }
+
+            // If the cursor is at an invalid position, find a valid one
+            cursorpos = MultiPageCustomItems.curpos;
+            if ( cursorpos >= numpos )
+            {
+                cursorpos = numpos - 1;
+            }
+            else
+            {
+                while( MultiPageCustomMenu[ cursorpos ].active == CP_Inactive )
+                {
+                    cursorpos++;
+                }
+            }
+            MultiPageCustomItems.curpos = cursorpos;
+            MultiPageCustomMenu[ cursorpos ].active = CP_CursorLocation;
+
+            DrawMultiPageCustomMenu( title, redrawfunc );
+        }
+
+        which = HandleMenu( &MultiPageCustomItems, &MultiPageCustomMenu[ 0 ],
+                            NULL );
+
+        switch( which )
+        {
+        case ESCPRESSED :
+            selection = -1;
+            break;
+
+        case PAGEDOWN :
+        case 0 :
+            page += MAXCUSTOM;
+            which = 0;
+            redraw = true;
+            break;
+
+        case PAGEUP :
+        case 1 :
+            page -= MAXCUSTOM;
+            which = 0;
+            redraw = true;
+            break;
+
+        default :
+            selection = page + which - 2;
+            if ( routine )
+            {
+                routine( selection );
+            }
+
+            if ( exitonselect )
+            {
+                which = -1;
+            }
+            break;
+        }
+    }
+    while( which >= 0 );
+
+    return( selection );
+}
+
+
+//****************************************************************************
+//
+// CP_LevelSelectionRedraw()
+//
+//****************************************************************************
+
+void CP_LevelSelectionRedraw
+(
+    void
+)
+
+{
+    if ( gamestate.battlemode >= battle_Normal )
+    {
+        SetMenuHeader( BattleModeNames[ gamestate.battlemode - battle_Normal ] );
+    }
+}
+
+
+//****************************************************************************
+//
+// CP_LevelSelectionMenu ()
+//
+//****************************************************************************
+int CP_LevelSelectionMenu
+(
+    void
+)
+
+{
+    static char levelcursorpos[ 2 ] = { 0 };
+
+    char *LevelNames[ 100 ];
+    int   whichlevels;
+    int   numlevels;
+    int   level;
+    int   i;
+
+    whichlevels = 0;
+    if ( BATTLEMODE )
+    {
+        whichlevels = 1;
+    }
+
+    mapinfo = ( mapfileinfo_t * )SafeMalloc( sizeof( mapfileinfo_t ) );
+    GetMapInfo( mapinfo );
+
+    numlevels = mapinfo->nummaps;
+    if ( numlevels <= 0 )
+    {
+        Error( "CP_LevelSelectionMenu : No maps found in RTL/RTC file." );
+    }
+
+    for( i = 0; i < numlevels; i++ )
+    {
+        LevelNames[ i ] = mapinfo->maps[ i ].mapname;
+    }
+
+    level = HandleMultiPageCustomMenu( LevelNames, numlevels,
+                                       levelcursorpos[ whichlevels ], "Level Selection", NULL,
+                                       CP_LevelSelectionRedraw, true );
+
+    SafeFree( mapinfo );
+
+    if ( level >= 0 )
+    {
+        levelcursorpos[ whichlevels ] = level;
+    }
+
+    return( level );
+}
+
+
+//****************************************************************************
+//
+// DrawEnterCodeNameMenu ()
+//
+//****************************************************************************
+void DrawEnterCodeNameMenu
+(
+    void
+)
+
+{
+    SetAlternateMenuBuf();
+    ClearMenuBuf();
+    SetMenuTitle ("Enter CodeName");
+
+    if ( consoleplayer == 0 )
+    {
+        DrawBattleModeName( gamestate.battlemode );
+    }
+
+    WindowW = 288;
+    WindowH = 158;
+    WindowX = 0;
+    WindowY = 50;
+    PrintX  = 0;
+    PrintY  = 50;
+
+    CurrentFont = smallfont;
+
+    MenuBufCPrint( "Enter CodeName\n" );
+    MenuBufCPrint( "maximum 8 letters\n" );
+
+    DrawSTMenuBuf( ( 288 - 92 ) / 2 - 2, 80 - 2, 92 + 4, 10 + 4, false );
+
+    DrawMenuBufPropString( ( 288 - 92 ) / 2, 80, CodeName );
+
+    WindowX = 144 - ( 9 * 4 );
+    PrintX  = WindowX;
+
+    FlipMenuBuf();
+    RefreshMenuBuf( 0 );
+}
+
+//****************************************************************************
+//
+// CP_EnterCodeNameMenu ()
+//
+//****************************************************************************
+int CP_EnterCodeNameMenu
+(
+    void
+)
+
+{
+    char input[10];
+
+    DrawEnterCodeNameMenu();
+
+    memset(input,0,sizeof(input));
+    strcpy(input,CodeName);
+
+
+    if (US_LineInput ((288-92)/2, 80, input, input, true, 8, 92, 0))
+    {
+        strcpy (&locplayerstate->codename[0], input);
+        strcpy (CodeName, input);
+        WaitKeyUp();
+        return 1;
+    }
+    else
+    {
+        WaitKeyUp();
+        return 0;
+    }
+}
+
+#ifdef DOS
+void SS_DrawSBTypeMenu( void );
+void SS_SBTypeMenu( void );
+void SS_DrawPortMenu( void );
+void SS_PortMenu( void );
+void SS_Draw8BitDMAMenu( void );
+void SS_8BitDMAMenu( void );
+void SS_Draw16BitDMAMenu( void );
+void SS_16BitDMAMenu( void );
+void SS_DrawIrqMenu( void );
+void SS_IrqMenu( void );
+void SS_Quit( void );
+void DrawSoundSetupMainMenu( void );
+void CP_SoundSetup( void );
+void SS_MusicMenu( void );
+void SS_DrawMusicMenu( void );
+void SS_SoundMenu( void );
+void SS_DrawSoundMenu( void );
+void SS_SetupMusicCardMenu( void );
+void DrawMusicCardMenu( void );
+void SS_SetupSoundBlaster( int sbmenu );
+void SS_SetupSoundCardMenu( void );
+void SS_VoiceMenu( int sbmenu );
+void SS_DrawVoiceMenu( void );
+void SS_ChannelMenu( void );
+void SS_DrawChannelMenu( void );
+void SS_BitMenu( void );
+void SS_DrawBitMenu( void );
+
+extern int musicnums[ 11 ];
+extern int fxnums[ 11 ];
+
+static int midinums[ 12 ]  = {
+    0x220, 0x230, 0x240, 0x250, 0x300, 0x320,
+    0x330, 0x332, 0x334, 0x336, 0x340, 0x360
+};
+static int voicenums[8] = {1, 2, 3, 4, 5, 6, 7, 8};
+static int resnums[2]   = {8, 16};
+static int smnums[2]    = {1, 2};
+
+//
+// MENU ITEMS
+//
+CP_MenuNames SoundSetupMenuNames[] =
+{
+    "SETUP SOUND FX",
+    "SETUP MUSIC",
+    "SOUND FX VOLUME",
+    "MUSIC VOLUME",
+    "QUIT"
+};
+
+CP_iteminfo SoundSetupMenuItems  = { MENU_X, 48, 5, STARTITEM, 32, SoundSetupMenuNames, mn_largefont };
+CP_itemtype SoundSetupMenu[] =
+{
+    { CP_CursorLocation, "\0",  'S', (menuptr)SS_SoundMenu },
+    { CP_Active,         "\0",  'S', (menuptr)SS_MusicMenu },
+    { CP_Active,         "\0",  'S', (menuptr)FXVolume },
+    { CP_Active,         "\0",  'M', (menuptr)MusicVolume },
+    { CP_Active,         "\0",  'Q', (menuptr)SS_Quit }
+};
+
+CP_MenuNames SoundSetupMusicNames[] =
+{
+    "None",
+    "Ultrasound",
+    "Sound Blaster",
+    "Sound Man 16",
+    "Pro Audio Spectrum",
+    "AWE 32",
+    "Soundscape",
+    "Wave Blaster",
+    "General Midi",
+    "Sound Canvas",
+    "Adlib"
+};
+
+CP_iteminfo SoundSetupMusicItems  = { 44, MENU_Y + 15, 11, STARTITEM, 16, SoundSetupMusicNames, mn_smallfont };
+CP_itemtype SoundSetupMusic[] =
+{
+    { CP_CursorLocation, "\0",  'N', (menuptr)SS_SetupMusicCardMenu },
+    { CP_Active,         "\0",  'U', (menuptr)SS_SetupMusicCardMenu },
+    { CP_Active,         "\0",  'S', (menuptr)SS_SetupMusicCardMenu },
+    { CP_Active,         "\0",  'S', (menuptr)SS_SetupMusicCardMenu },
+    { CP_Active,         "\0",  'P', (menuptr)SS_SetupMusicCardMenu },
+    { CP_Active,         "\0",  'A', (menuptr)SS_SetupMusicCardMenu },
+    { CP_Active,         "\0",  'S', (menuptr)SS_SetupMusicCardMenu },
+    { CP_Active,         "\0",  'W', (menuptr)SS_SetupMusicCardMenu },
+    { CP_Active,         "\0",  'G', (menuptr)SS_SetupMusicCardMenu },
+    { CP_Active,         "\0",  'S', (menuptr)SS_SetupMusicCardMenu },
+    { CP_Active,         "\0",  'A', (menuptr)SS_SetupMusicCardMenu }
+};
+
+
+CP_MenuNames SoundSetupSoundNames[] =
+{
+    "None",
+    "Ultrasound",
+    "Sound Blaster",
+    "Sound Man 16",
+    "Pro Audio Spectrum",
+    "AWE 32",
+    "Soundscape",
+    "Adlib",
+    "Disney Sound Source",
+    "Tandy Sound Source",
+    "PC Speaker"
+};
+
+CP_iteminfo SoundSetupSoundItems  = { MENU_X, MENU_Y + 15, 11, STARTITEM, 16, SoundSetupSoundNames, mn_smallfont };
+CP_itemtype SoundSetupSound[] =
+{
+    { CP_CursorLocation, "\0",  'N', (menuptr)SS_SetupSoundCardMenu },
+    { CP_Active,         "\0",  'U', (menuptr)SS_SetupSoundCardMenu },
+    { CP_Active,         "\0",  'S', (menuptr)SS_SetupSoundCardMenu },
+    { CP_Active,         "\0",  'S', (menuptr)SS_SetupSoundCardMenu },
+    { CP_Active,         "\0",  'P', (menuptr)SS_SetupSoundCardMenu },
+    { CP_Active,         "\0",  'A', (menuptr)SS_SetupSoundCardMenu },
+    { CP_Active,         "\0",  'S', (menuptr)SS_SetupSoundCardMenu },
+    { CP_Active,         "\0",  'A', (menuptr)SS_SetupSoundCardMenu },
+    { CP_Active,         "\0",  'S', (menuptr)SS_SetupSoundCardMenu },
+    { CP_Active,         "\0",  'T', (menuptr)SS_SetupSoundCardMenu },
+    { CP_Active,         "\0",  'P', (menuptr)SS_SetupSoundCardMenu }
+};
+
+CP_MenuNames SoundSetupMidiPortNames[] =
+{
+    "220", "230", "240", "250", "300", "320",
+    "330", "332", "334", "336", "340", "360"
+};
+
+CP_iteminfo SoundSetupMidiPortItems = { 108, MENU_Y + 10, 12, STARTITEM, 16, SoundSetupMidiPortNames, mn_smallfont };
+CP_itemtype SoundSetupMidiPort[] =
+{
+    { CP_Active,         "\0",  'a', NULL },
+    { CP_Active,         "\0",  'a', NULL },
+    { CP_Active,         "\0",  'a', NULL },
+    { CP_Active,         "\0",  'a', NULL },
+    { CP_Active,         "\0",  'a', NULL },
+    { CP_CursorLocation, "\0",  'a', NULL },
+    { CP_Active,         "\0",  'a', NULL },
+    { CP_Active,         "\0",  'a', NULL },
+    { CP_Active,         "\0",  'a', NULL },
+    { CP_Active,         "\0",  'a', NULL },
+    { CP_Active,         "\0",  'a', NULL },
+    { CP_Active,         "\0",  'a', NULL }
+};
+
+CP_MenuNames SoundSetupVoiceNames[] =
+{
+    "1 voice",
+    "2 voices",
+    "3 voices",
+    "4 voices",
+    "5 voices",
+    "6 voices",
+    "7 voices",
+    "8 voices"
+};
+
+CP_iteminfo SoundSetupVoiceItems  = { MENU_X + 36, 24, 8, STARTITEM, 32, SoundSetupVoiceNames, mn_largefont };
+CP_itemtype SoundSetupVoice[] =
+{
+    { CP_CursorLocation, "\0",  'a', NULL },
+    { CP_Active,         "\0",  'a', NULL },
+    { CP_Active,         "\0",  'a', NULL },
+    { CP_Active,         "\0",  'a', NULL },
+    { CP_Active,         "\0",  'a', NULL },
+    { CP_Active,         "\0",  'a', NULL },
+    { CP_Active,         "\0",  'a', NULL },
+    { CP_Active,         "\0",  'a', NULL }
+};
+
+CP_MenuNames SoundSetupChannelNames[] =
+{
+    "  Mono Sound FX",
+    "Stereo Sound FX"
+};
+
+CP_iteminfo SoundSetupChannelItems  = { MENU_X, MP_Y, 2, STARTITEM, 32, SoundSetupChannelNames, mn_largefont };
+CP_itemtype SoundSetupChannel[] =
+{
+    { CP_CursorLocation, "\0",  'M', NULL },
+    { CP_Active,         "\0",  'S', NULL }
+};
+
+CP_MenuNames SoundSetupResolutionNames[] =
+{
+    "8 Bit Mixing",
+    "16 Bit Mixing"
+};
+
+CP_iteminfo SoundSetupResolutionItems  = { MENU_X, MP_Y, 2, STARTITEM, 32, SoundSetupResolutionNames, mn_largefont };
+CP_itemtype SoundSetupResolution[] =
+{
+    { CP_CursorLocation, "\0",  'a', NULL },
+    { CP_Active,         "\0",  'b', NULL }
+};
+
+static int typenums[ 5 ] =
+{
+    fx_SB, fx_SB20, fx_SBPro, fx_SBPro2, fx_SB16
+};
+
+static char typetostring[ 6 ] =
+{
+    5, 0, 2, 1, 3, 4
+};
+
+#define UNDEFINED -1
+
+CP_MenuNames TypeNames[] =
+{
+    "Sound Blaster or compatible",
+    "Sound Blaster 2.0",
+    "Sound Blaster Pro (old)",
+    "Sound Blaster Pro 2.0 (new)",
+    "Sound Blaster 16 or AWE32",
+    "Undefined"
+};
+
+CP_iteminfo TypeItems  = { MENU_X - 13, MENU_Y + 36, 5, STARTITEM, 10, TypeNames, mn_smallfont };
+CP_itemtype TypeMenu[] =
+{
+    { CP_CursorLocation, "\0",  'S', NULL },
+    { CP_Active,         "\0",  'S', NULL },
+    { CP_Active,         "\0",  'S', NULL },
+    { CP_Active,         "\0",  'S', NULL },
+    { CP_Active,         "\0",  'S', NULL }
+};
+
+static int portnums[ 7 ] =
+{
+    0x210, 0x220, 0x230, 0x240, 0x250, 0x260, 0x280
+};
+
+CP_MenuNames PortNames[] =
+{
+    "210", "220", "230", "240", "250", "260", "280"
+};
+
+CP_iteminfo PortItems = { 92, 32, 7, STARTITEM, 32, PortNames, mn_largefont };
+CP_itemtype PortMenu [] =
+{
+    { CP_CursorLocation, "\0",  '2', NULL },
+    { CP_Active,         "\0",  '2', NULL },
+    { CP_Active,         "\0",  '2', NULL },
+    { CP_Active,         "\0",  '2', NULL },
+    { CP_Active,         "\0",  '2', NULL },
+    { CP_Active,         "\0",  '2', NULL },
+    { CP_Active,         "\0",  '2', NULL }
+};
+
+static int _8BitDMAnums[ 3 ] =
+{
+    0, 1, 3
+};
+
+CP_MenuNames _8BitDMANames[] =
+{
+    "DMA channel 0",
+    "DMA channel 1",
+    "DMA channel 3"
+};
+
+CP_iteminfo _8BitDMAItems = { 32, 60, 3, STARTITEM, 32, _8BitDMANames, mn_largefont };
+CP_itemtype _8BitDMAMenu [] =
+{
+    { CP_CursorLocation, "\0",  '0', NULL },
+    { CP_Active,         "\0",  '1', NULL },
+    { CP_Active,         "\0",  '3', NULL }
+};
+
+static int _16BitDMAnums[ 3 ] =
+{
+    5, 6, 7
+};
+
+CP_MenuNames _16BitDMANames[] =
+{
+    "DMA channel 5",
+    "DMA channel 6",
+    "DMA channel 7"
+};
+
+CP_iteminfo _16BitDMAItems = { 32, 60, 3, STARTITEM, 32, _16BitDMANames, mn_largefont };
+CP_itemtype _16BitDMAMenu [] =
+{
+    { CP_CursorLocation, "\0",  '5', NULL },
+    { CP_Active,         "\0",  '6', NULL },
+    { CP_Active,         "\0",  '7', NULL }
+};
+
+static int irqnums[ 8 ] =
+{
+    2, 3, 5, 7, 10, 11, 12, 15
+};
+
+CP_MenuNames IrqNames[] =
+{
+    "IRQ 2",
+    "IRQ 3",
+    "IRQ 5",
+    "IRQ 7",
+    "IRQ 10",
+    "IRQ 11",
+    "IRQ 12",
+    "IRQ 15"
+};
+
+CP_iteminfo IrqItems = { 82, 24, 8, STARTITEM, 32, IrqNames, mn_largefont };
+CP_itemtype IrqMenu [] =
+{
+    { CP_CursorLocation, "\0",  'a', NULL },
+    { CP_Active,         "\0",  'a', NULL },
+    { CP_Active,         "\0",  'a', NULL },
+    { CP_Active,         "\0",  'a', NULL },
+    { CP_Active,         "\0",  'a', NULL },
+    { CP_Active,         "\0",  'a', NULL },
+    { CP_Active,         "\0",  'a', NULL },
+    { CP_Active,         "\0",  'a', NULL }
+};
+
+CP_MenuNames SBSetupNames[] =
+{
+    "Use Current Settings",
+    "Custom Setup"
+};
+
+CP_iteminfo SBSetupItems  = { MENU_X - 11, MENU_Y + 76, 2, STARTITEM, 19, SBSetupNames, mn_largefont };
+CP_itemtype SBSetupMenu[] =
+{
+    { CP_CursorLocation, "\0",  'U', SS_SetupSoundBlaster },
+    { CP_Active,         "\0",  'C', (menuptr)SS_SBTypeMenu },
+};
+
+extern fx_blaster_config SBSettings;
+
+//******************************************************************************
+//
+// SS_DrawSBSetupMenu()
+//
+//******************************************************************************
+
+void SS_DrawSBSetupMenu
+(
+    void
+)
+
+{
+    char text[ 80 ];
+    char num[ 10 ];
+    char *undefined;
+
+    MenuNum = SNDCARDS;
+    SetAlternateMenuBuf();
+    ClearMenuBuf();
+    SetMenuTitle( "Sound Blaster Setup" );
+
+    WindowW = 288;
+    WindowH = 158;
+    WindowX = 96;
+    WindowY = 32;
+    PrintX  = 0;
+    PrintY  = 32;
+
+    CurrentFont = tinyfont;
+
+    undefined = "Undefined";
+
+    SBSetupMenu[ 0 ].active = CP_Active;
+
+    PrintBattleOption( true, WindowX + 16, PrintY, "Current Settings:" );
+    PrintY += 9;
+
+    strcpy( text, "Card Type : " );
+
+    if ( ( SBSettings.Type < fx_SB ) || ( SBSettings.Type > fx_SB16 ) )
+    {
+        SBSettings.Type = UNDEFINED;
+        strcat( text, undefined );
+        SBSetupMenu[ 0 ].active = CP_Inactive;
+    }
+    else
+    {
+        strcat( text, TypeNames[ (unsigned int)typetostring[ SBSettings.Type ] ] );
+    }
+
+    PrintBattleOption( true, WindowX, PrintY, text );
+    PrintY += 6;
+
+    strcpy( text, "Port : " );
+    if ( SBSettings.Address != (unsigned long)UNDEFINED )
+    {
+        itoa( SBSettings.Address, num, 16 );
+        strcat( text, num );
+    }
+    else
+    {
+        strcat( text, undefined );
+        SBSetupMenu[ 0 ].active = CP_Inactive;
+    }
+
+    PrintBattleOption( true, WindowX + 19, PrintY, text );
+    PrintY += 6;
+
+    strcpy( text, "IRQ : " );
+    if ( SBSettings.Interrupt != (unsigned long)UNDEFINED )
+    {
+        itoa( SBSettings.Interrupt, num, 10 );
+        strcat( text, num );
+    }
+    else
+    {
+        strcat( text, undefined );
+        SBSetupMenu[ 0 ].active = CP_Inactive;
+    }
+    PrintBattleOption( true, WindowX + 23, PrintY, text );
+    PrintY += 6;
+
+    strcpy( text, "DMA : " );
+    if ( SBSettings.Dma8 != (unsigned long)UNDEFINED )
+    {
+        itoa( SBSettings.Dma8, num, 10 );
+        strcat( text, num );
+    }
+    else
+    {
+        strcat( text, undefined );
+        SBSetupMenu[ 0 ].active = CP_Inactive;
+    }
+    PrintBattleOption( true, WindowX + 21, PrintY, text );
+    PrintY += 6;
+
+    strcpy( text, "16-Bit DMA : " );
+    if ( SBSettings.Dma16 != (unsigned long)UNDEFINED )
+    {
+        itoa( SBSettings.Dma16, num, 10 );
+        strcat( text, num );
+    }
+    else
+    {
+        strcat( text, undefined );
+    }
+    PrintBattleOption( true, WindowX - 4, PrintY, text );
+    PrintY += 6;
+
+    MN_GetCursorLocation( &SBSetupItems, &SBSetupMenu[ 0 ] );
+    DrawMenu( &SBSetupItems, &SBSetupMenu[ 0 ] );
+    DisplayInfo( 0 );
+
+    FlipMenuBuf();
+    RefreshMenuBuf( 0 );
+}
+
+
+//******************************************************************************
+//
+// SS_DrawSBTypeMenu()
+//
+//******************************************************************************
+
+void SS_DrawSBTypeMenu
+(
+    void
+)
+
+{
+    MenuNum = SNDCARDS;
+    SetAlternateMenuBuf();
+    ClearMenuBuf();
+    SetMenuTitle( "Select Sound Blaster Type" );
+    MN_GetActive( &TypeItems, &TypeMenu[ 0 ], SBSettings.Type, typenums );
+    DrawMenu( &TypeItems, &TypeMenu[ 0 ] );
+    DisplayInfo( 0 );
+
+    FlipMenuBuf();
+}
+
+//******************************************************************************
+//
+// SS_SBTypeMenu()
+//
+//******************************************************************************
+
+void SS_SBTypeMenu
+(
+    void
+)
+
+{
+    int which;
+
+    do
+    {
+        SS_DrawSBTypeMenu();
+        which = HandleMenu( &TypeItems, &TypeMenu[0], NULL );
+        if ( which >= 0 )
+        {
+            SBSettings.Type = typenums[ which ];
+            SS_PortMenu();
+            if ( handlewhich == -1 )
+            {
+                continue;
+            }
+            return;
+        }
+    }
+    while( which >= 0 );
+
+    handlewhich = -2;
+}
+
+//******************************************************************************
+//
+// SS_DrawPortMenu()
+//
+//******************************************************************************
+
+void SS_DrawPortMenu
+(
+    void
+)
+
+{
+    MenuNum = SNDCARDS;
+    SetAlternateMenuBuf();
+    ClearMenuBuf();
+    SetMenuTitle( "Select Sound Blaster Port" );
+    MN_GetActive( &PortItems, &PortMenu[ 0 ], SBSettings.Address, portnums );
+    DrawMenu( &PortItems, &PortMenu[ 0 ] );
+    DisplayInfo( 0 );
+
+    FlipMenuBuf();
+}
+
+//******************************************************************************
+//
+// SS_PortMenu()
+//
+//******************************************************************************
+
+void SS_PortMenu
+(
+    void
+)
+
+{
+    int which;
+
+    do
+    {
+        SS_DrawPortMenu();
+        which = HandleMenu( &PortItems, &PortMenu[0], NULL );
+        if ( which >= 0 )
+        {
+            SBSettings.Address = portnums[ which ];
+            SBSettings.Emu = SBSettings.Address;
+            SS_8BitDMAMenu();
+            if ( handlewhich == -1 )
+            {
+                continue;
+            }
+            return;
+        }
+    }
+    while( which >= 0 );
+
+    handlewhich = -1;
+}
+
+//******************************************************************************
+//
+// SS_Draw8BitDMAMenu()
+//
+//******************************************************************************
+
+void SS_Draw8BitDMAMenu
+(
+    void
+)
+
+{
+    MenuNum = SNDCARDS;
+    SetAlternateMenuBuf();
+    ClearMenuBuf();
+    SetMenuTitle( "Select 8-bit DMA Channel" );
+    MN_GetActive( &_8BitDMAItems, &_8BitDMAMenu[ 0 ], SBSettings.Dma8, _8BitDMAnums );
+    DrawMenu( &_8BitDMAItems, &_8BitDMAMenu[ 0 ] );
+    DisplayInfo( 0 );
+
+    FlipMenuBuf();
+}
+
+//******************************************************************************
+//
+// SS_8BitDMAMenu()
+//
+//******************************************************************************
+
+void SS_8BitDMAMenu
+(
+    void
+)
+
+{
+    int which;
+
+    do
+    {
+        SS_Draw8BitDMAMenu();
+        which = HandleMenu( &_8BitDMAItems, &_8BitDMAMenu[0], NULL );
+        if ( which >= 0 )
+        {
+            SBSettings.Dma8 = _8BitDMAnums[ which ];
+            SS_16BitDMAMenu();
+            if ( handlewhich == -1 )
+            {
+                continue;
+            }
+            return;
+        }
+    }
+    while( which >= 0 );
+
+    handlewhich = -1;
+}
+
+//******************************************************************************
+//
+// SS_Draw16BitDMAMenu()
+//
+//******************************************************************************
+
+void SS_Draw16BitDMAMenu
+(
+    void
+)
+
+{
+    MenuNum = SNDCARDS;
+    SetAlternateMenuBuf();
+    ClearMenuBuf();
+    SetMenuTitle( "Select 16-bit DMA Channel" );
+    MN_GetActive( &_16BitDMAItems, &_16BitDMAMenu[ 0 ], SBSettings.Dma16, _16BitDMAnums );
+    DrawMenu( &_16BitDMAItems, &_16BitDMAMenu[ 0 ] );
+    DisplayInfo( 0 );
+
+    FlipMenuBuf();
+}
+
+//******************************************************************************
+//
+// SS_16BitDMAMenu()
+//
+//******************************************************************************
+
+void SS_16BitDMAMenu
+(
+    void
+)
+
+{
+    int which;
+
+    if ( SBSettings.Type != fx_SB16 )
+    {
+        SS_IrqMenu();
+        return;
+    }
+
+    do
+    {
+        SS_Draw16BitDMAMenu();
+        which = HandleMenu( &_16BitDMAItems, &_16BitDMAMenu[0], NULL );
+        if ( which >= 0 )
+        {
+            SBSettings.Dma16 = _16BitDMAnums[ which ];
+            SS_IrqMenu();
+            if ( handlewhich == -1 )
+            {
+                continue;
+            }
+            return;
+        }
+    }
+    while( which >= 0 );
+
+    handlewhich = -1;
+}
+
+//******************************************************************************
+//
+// SS_DrawIrqMenu()
+//
+//******************************************************************************
+
+void SS_DrawIrqMenu
+(
+    void
+)
+
+{
+    MenuNum = SNDCARDS;
+    SetAlternateMenuBuf();
+    ClearMenuBuf();
+    SetMenuTitle( "Select Sound Blaster IRQ" );
+    MN_GetActive( &IrqItems, &IrqMenu[ 0 ], SBSettings.Interrupt, irqnums );
+    DrawMenu( &IrqItems, &IrqMenu[ 0 ] );
+    DisplayInfo( 0 );
+
+    FlipMenuBuf();
+}
+
+//******************************************************************************
+//
+// SS_IrqMenu()
+//
+//******************************************************************************
+
+void SS_IrqMenu
+(
+    void
+)
+
+{
+    int which;
+
+    do
+    {
+        SS_DrawIrqMenu();
+        which = HandleMenu( &IrqItems, &IrqMenu[0], NULL );
+
+        if ( which >= 0 )
+        {
+            SBSettings.Interrupt = irqnums[ which ];
+            SS_SetupSoundBlaster( true );
+
+            if ( handlewhich == -1 )
+            {
+                continue;
+            }
+
+            return;
+        }
+    }
+    while( which >= 0 );
+
+    handlewhich = -1;
+}
+#endif
+
+
+//******************************************************************************
+//
+// GetNextWord()
+//
+//******************************************************************************
+char *GetNextWord
+(
+    char *dest,
+    char *source,
+    int  length
+)
+
+{
+    while( ( *source != 0 ) && ( isspace( *source ) ) && ( length > 0 ) )
+    {
+        *dest = *source;
+        length--;
+        dest++;
+        source++;
+    }
+
+    while( ( *source != 0 ) && ( !isspace( *source ) ) && ( length > 0 ) )
+    {
+        *dest = *source;
+        length--;
+        dest++;
+        source++;
+    }
+
+    *dest = 0;
+    return( source );
+}
+
+//******************************************************************************
+//
+// CP_ErrorMsg()
+//
+//******************************************************************************
+
+void CP_ErrorMsg
+(
+    char *title,
+    char *error,
+    int font
+)
+
+{
+    char wordtext[ 80 ];
+    char text[ 10 ][ 80 ];
+    int  pos;
+    int  length;
+    int  line;
+    int  w;
+    int  h;
+    int  y;
+    extern void VWL_MeasureIntensityString (char *s, int *width, int *height, cfont_t *font);
+
+    SetAlternateMenuBuf();
+    ClearMenuBuf();
+    SetMenuTitle( title );
+
+    WindowW = 288;
+    WindowH = 158;
+    WindowX = 0;
+    WindowY = 40;
+
+    IFont = ( cfont_t * )W_CacheLumpName( FontNames[ font ], PU_CACHE, Cvt_cfont_t, 1 );
+
+    pos = 0;
+    line = 0;
+
+    text[ 0 ][ 0 ] = 0;
+
+    while( *error != 0 )
+    {
+        error = GetNextWord( wordtext, error, 79 );
+
+        pos = 0;
+        while( ( wordtext[ pos ] != 0 ) && ( isspace( wordtext[ pos ] ) ) )
+        {
+            pos++;
+        }
+
+        length = strlen( text[ line ] );
+        if ( length == 0 )
+        {
+            strcat( text[ line ], &wordtext[ pos ] );
+        }
+        else
+        {
+            strcat( text[ line ], wordtext );
+        }
+
+        VWL_MeasureIntensityString( text[ line ], &w, &h, IFont );
+
+        if ( w > WindowW - 32 )
+        {
+            text[ line ][ length ] = 0;
+            if ( line >= 10 )
+            {
+                break;
+            }
+            line++;
+            strcpy( text[ line ], &wordtext[ pos ] );
+        }
+    }
+
+    if ( strlen( text[ line ] ) == 0 )
+    {
+        line--;
+    }
+
+    VWL_MeasureIntensityString( text[ 0 ], &w, &h, IFont );
+
+    y = ( WindowH - ( line + 1 ) * h ) / 2;
+
+    for( pos = 0; pos <= line; pos++ )
+    {
+        VWL_MeasureIntensityString( text[ pos ], &w, &h, IFont );
+        DrawMenuBufIString( ( 288 - w ) / 2, y, text[ pos ], ACTIVECOLOR );
+        y += h;
+    }
+
+    DisplayInfo( 5 );
+    FlipMenuBuf();
+    RefreshMenuBuf( 0 );
+
+    IN_Ack();
+    WaitKeyUp();
+
+    MN_PlayMenuSnd( SD_ESCPRESSEDSND );
+}
+
+#ifdef DOS
+
+//****************************************************************************
+//
+// DrawSoundSetupMainMenu ()
+//
+//****************************************************************************
+void DrawSoundSetupMainMenu
+(
+    void
+)
+
+{
+    MenuNum = 1;
+
+    SetAlternateMenuBuf();
+    ClearMenuBuf();
+    SetMenuTitle( "Sound Setup" );
+    if ( FXMode == 0 )
+    {
+        SoundSetupMenu[ 2 ].active = CP_Inactive;
+    }
+    else if ( SoundSetupMenu[ 2 ].active == CP_Inactive )
+    {
+        SoundSetupMenu[ 2 ].active = CP_Active;
+    }
+
+    if ( MusicMode == 0 )
+    {
+        SoundSetupMenu[ 3 ].active = CP_Inactive;
+    }
+    else if ( SoundSetupMenu[ 3 ].active == CP_Inactive )
+    {
+        SoundSetupMenu[ 3 ].active = CP_Active;
+    }
+
+    MN_GetCursorLocation( &SoundSetupMenuItems, &SoundSetupMenu[ 0 ] );
+    DrawMenu( &SoundSetupMenuItems, &SoundSetupMenu[ 0 ] );
+    DisplayInfo( 0 );
+
+    FlipMenuBuf();
+}
+
+
+//******************************************************************************
+//
+// Sound Setup Quit
+//
+//******************************************************************************
+
+void SS_Quit
+(
+    void
+)
+
+{
+    extern boolean WriteSoundFile;
+
+    CP_DisplayMsg( "Do you wish to\nsave your changes?\n"
+                   "Press ESC to return\nto sound setup.", 12 );
+
+    if ( CP_Acknowledge != CP_ESC )
+    {
+        WriteSoundFile = true;
+        if ( CP_Acknowledge == CP_NO )
+        {
+            WriteSoundFile = false;
+        }
+
+        MU_FadeOut(310);
+        VL_FadeOut (0, 255, 0, 0, 0, 10);
+        ShutdownMenuBuf();
+        QuitGame ();
+    }
+
+    DrawSoundSetupMainMenu();
+}
+
+//******************************************************************************
+//
+// Sound Setup
+//
+//******************************************************************************
+
+void CP_SoundSetup ( void )
+{
+    int which;
+    extern boolean WriteSoundFile;
+
+    WriteSoundFile = false;
+
+    SetupMenuBuf();
+    DrawSoundSetupMainMenu();
+    IN_ClearKeysDown();
+
+    if ( MusicMode != 0 )
+    {
+        MU_StartSong( song_title );
+    }
+
+    while( 1 )
+    {
+        which = HandleMenu( &SoundSetupMenuItems, SoundSetupMenu, NULL );
+        if ( which == -1 )
+        {
+            SS_Quit();
+        }
+    }
+}
+
+//******************************************************************************
+//
+// SS_MusicMenu ()
+//
+//******************************************************************************
+
+void SS_MusicMenu
+(
+    void
+)
+
+{
+    int which;
+
+    MN_MakeActive( &SoundSetupMusicItems, &SoundSetupMusic[ 0 ], MusicMode );
+
+    SS_DrawMusicMenu ();
+    IN_ClearKeysDown();
+
+    do
+    {
+        which = HandleMenu( &SoundSetupMusicItems, &SoundSetupMusic[ 0 ], NULL );
+    }
+    while( which > 0 );
+
+    DrawSoundSetupMainMenu();
+    handlewhich = RETURNVAL;
+}
+
+
+//******************************************************************************
+//
+// SS_DrawMusicMenu ()
+//
+//******************************************************************************
+
+void SS_DrawMusicMenu
+(
+    void
+)
+
+{
+    MenuNum = SNDCARDS;
+
+    SetAlternateMenuBuf();
+    ClearMenuBuf();
+    SetMenuTitle( "Select Music Card" );
+
+    MN_GetCursorLocation( &SoundSetupMusicItems, &SoundSetupMusic[ 0 ] );
+    DrawMenu( &SoundSetupMusicItems, &SoundSetupMusic[ 0 ] );
+    DisplayInfo( 0 );
+
+    FlipMenuBuf();
+}
+
+
+//******************************************************************************
+//
+// SS_SetupMusicCardMenu()
+//
+//******************************************************************************
+
+void SS_SetupMusicCardMenu
+(
+    void
+)
+
+{
+    int status;
+    int select;
+    if ( ( ( musicnums[ handlewhich ] == SoundBlaster ) ||
+            ( musicnums[ handlewhich ] == WaveBlaster ) ||
+            ( musicnums[ handlewhich ] == Awe32 ) ) &&
+            ( fxnums[ FXMode ] != SoundBlaster ) &&
+            ( fxnums[ FXMode ] != Awe32 ) )
+    {
+        CP_ErrorMsg( "Music Error",
+                     "Please set your Sound FX card to Sound Blaster before "
+                     "selecting this card for music.", mn_smallfont );
+
+        handlewhich = -1;
+        return;
+    }
+
+    MusicMode = handlewhich;
+
+    MU_Shutdown();
+
+    if ( ( musicnums[ MusicMode ] == GenMidi ) ||
+            ( musicnums[ MusicMode ] == SoundCanvas ) ||
+            ( musicnums[ MusicMode ] == WaveBlaster ) ||
+            ( musicnums[ MusicMode ] == Awe32 ) )
+    {
+        DrawMusicCardMenu();
+
+        IN_ClearKeysDown ();
+
+        select = HandleMenu( &SoundSetupMidiPortItems,
+                             &SoundSetupMidiPort[0], NULL );
+
+        if ( select > -1 )
+        {
+            MidiAddress = midinums[ select ];
+        }
+        else
+        {
+            SS_DrawMusicMenu ();
+            handlewhich = RETURNVAL;
+            MusicMode = 0;
+            return;
+        }
+    }
+
+    if ( MusicMode != 0 )
+    {
+        if ( ( musicnums[ handlewhich ] == WaveBlaster ) ||
+                ( musicnums[ handlewhich ] == Awe32 ) )
+        {
+            SD_Shutdown();
+        }
+
+        SetAlternateMenuBuf();
+        ClearMenuBuf();
+        SetMenuTitle( "Music Card Initialization" );
+        WindowW = 288;
+        WindowH = 158;
+        PrintX = WindowX = 0;
+        PrintY = WindowY = 65;
+        newfont1 = (font_t *)W_CacheLumpName( "newfnt1", PU_CACHE, Cvt_font_t, 1 );
+        CurrentFont = newfont1;
+        MenuBufCPrint( "Initializing card.\nPlease wait." );
+        FlipMenuBuf();
+        RefreshMenuBuf( 0 );
+
+        status = MU_Startup( false );
+        if ( status )
+        {
+            MusicMode = 0;
+
+            CP_ErrorMsg( "Music Error", MUSIC_ErrorString( MUSIC_Error ),
+                         mn_smallfont );
+            SS_DrawMusicMenu ();
+            handlewhich = RETURNVAL;
+        }
+        else
+        {
+            handlewhich = -1;
+            MU_StartSong( song_title );
+        }
+
+        if ( ( musicnums[ MusicMode ] == WaveBlaster ) ||
+                ( musicnums[ MusicMode ] == Awe32 ) )
+        {
+            status = SD_Startup( false );
+            if ( status != FX_Ok )
+            {
+                CP_ErrorMsg( "Sound FX Error", FX_ErrorString( FX_Error ),
+                             mn_smallfont );
+
+                handlewhich = -2;
+            }
+        }
+    }
+    else
+    {
+        handlewhich = -1;
+        MU_Shutdown();
+    }
+}
+
+
+//******************************************************************************
+//
+// DrawMusicCardMenu()
+//
+//******************************************************************************
+
+void DrawMusicCardMenu
+(
+    void
+)
+
+{
+    MenuNum = SNDCARDS;
+    SetAlternateMenuBuf();
+    ClearMenuBuf();
+    SetMenuTitle( "Select MIDI Port Address" );
+    MN_GetActive( &SoundSetupMidiPortItems, &SoundSetupMidiPort[ 0 ],
+                  MidiAddress, midinums );
+    DrawMenu( &SoundSetupMidiPortItems, &SoundSetupMidiPort[ 0 ] );
+    DisplayInfo( 0 );
+
+    FlipMenuBuf();
+}
+
+//******************************************************************************
+//
+// SS_SoundMenu ()
+//
+//******************************************************************************
+
+void SS_SoundMenu
+(
+    void
+)
+
+{
+    int which;
+
+    MN_MakeActive( &SoundSetupSoundItems, &SoundSetupSound[0], FXMode );
+
+    SS_DrawSoundMenu ();
+    IN_ClearKeysDown();
+
+    do {
+        which = HandleMenu( &SoundSetupSoundItems, &SoundSetupSound[ 0 ], NULL );
+    }
+    while( which >= 0 );
+
+    DrawSoundSetupMainMenu();
+    handlewhich = RETURNVAL;
+}
+
+
+//******************************************************************************
+//
+// SS_DrawSoundMenu ()
+//
+//******************************************************************************
+
+void SS_DrawSoundMenu
+(
+    void
+)
+
+{
+    MenuNum = SNDCARDS;
+
+    SetAlternateMenuBuf();
+    ClearMenuBuf();
+    SetMenuTitle ("Select Sound FX Card");
+
+    MN_GetCursorLocation( &SoundSetupSoundItems, &SoundSetupSound[0] );
+
+    DrawMenu( &SoundSetupSoundItems, &SoundSetupSound[ 0 ] );
+    DisplayInfo( 0 );
+
+    FlipMenuBuf();
+}
+
+
+//******************************************************************************
+//
+// SS_SetupSoundBlaster()
+//
+//******************************************************************************
+
+void SS_SetupSoundBlaster
+(
+    int sbmenu
+)
+
+{
+    int status;
+
+    status = FX_SetupSoundBlaster( SBSettings, &MaxVoices,
+                                   &MaxBits, &MaxChannels );
+
+    if ( status == FX_Ok )
+    {
+        SS_VoiceMenu( sbmenu );
+
+        if ( handlewhich < 0 )
+        {
+            return;
+        }
+        SetAlternateMenuBuf();
+        ClearMenuBuf();
+        SetMenuTitle( "Sound Card Initialization" );
+        WindowW = 288;
+        WindowH = 158;
+        PrintX = WindowX = 0;
+        PrintY = WindowY = 65;
+        newfont1 = (font_t *)W_CacheLumpName( "newfnt1", PU_CACHE, Cvt_font_t, 1 );
+        CurrentFont = newfont1;
+        MenuBufCPrint( "Initializing card.\nPlease wait." );
+        FlipMenuBuf();
+        RefreshMenuBuf( 0 );
+
+        status = SD_Startup( false );
+
+        RefreshMenuBuf( 0 );
+    }
+
+    if ( status != FX_Ok )
+    {
+        CP_ErrorMsg( "Sound FX Error", FX_ErrorString( FX_Error ),
+                     mn_smallfont );
+
+        handlewhich = -2;
+    }
+}
+
+
+//******************************************************************************
+//
+// SS_SetupSoundCardMenu()
+//
+//******************************************************************************
+
+void SS_SetupSoundCardMenu
+(
+    void
+)
+
+{
+    int which;
+    int FXstatus;
+    extern int fxnums[];
+
+    INFXSETUP = true;
+
+    FXMode = handlewhich;
+
+    SD_Shutdown();
+
+    if ( FXMode == 0 )
+    {
+        handlewhich = -1;
+    }
+    else
+    {
+        if ( ( fxnums[ FXMode ] == SoundBlaster ) ||
+                ( fxnums[ FXMode ] == Awe32 ) )
+        {
+            do
+            {
+                SS_DrawSBSetupMenu();
+                which = HandleMenu( &SBSetupItems, &SBSetupMenu[ 0 ], NULL );
+            }
+            while( which == -2 );
+
+            if ( which == -1 )
+            {
+                FXMode = 0;
+                handlewhich = 0;
+                SS_DrawSoundMenu();
+            }
+            else
+            {
+                handlewhich = -1;
+            }
+
+            INFXSETUP = false;
+            return;
+        }
+
+        FXstatus = SD_SetupFXCard( &MaxVoices, &MaxBits, &MaxChannels );
+        if ( FXstatus == FX_Ok )
+        {
+            SS_VoiceMenu( true );
+
+            if ( handlewhich == -1 )
+            {
+                SS_DrawSoundMenu ();
+                handlewhich = RETURNVAL;
+                FXMode = 0;
+                SD_Shutdown ();
+                INFXSETUP = false;
+                return;
+            }
+
+            SetAlternateMenuBuf();
+            ClearMenuBuf();
+            SetMenuTitle( "Sound Card Initialization" );
+            WindowW = 288;
+            WindowH = 158;
+            PrintX = WindowX = 0;
+            PrintY = WindowY = 65;
+            newfont1 = (font_t *)W_CacheLumpName( "newfnt1", PU_CACHE, Cvt_font_t, 1 );
+            CurrentFont = newfont1;
+            MenuBufCPrint( "Initializing card.\nPlease wait." );
+            FlipMenuBuf();
+            RefreshMenuBuf( 0 );
+
+            FXstatus = SD_Startup( false );
+
+            RefreshMenuBuf( 0 );
+        }
+
+        if ( FXstatus != FX_Ok )
+        {
+            FXMode = 0;
+            handlewhich = RETURNVAL;
+
+            CP_ErrorMsg( "Sound FX Error", FX_ErrorString( FX_Error ),
+                         mn_smallfont );
+            SS_DrawSoundMenu();
+        }
+        else
+        {
+            handlewhich = -1;
+        }
+    }
+
+    INFXSETUP = false;
+}
+
+
+//******************************************************************************
+//
+// SS_VoiceMenu ()
+//
+//******************************************************************************
+
+void SS_VoiceMenu
+(
+    int sbmenu
+)
+
+{
+    int which;
+
+    if ( MaxVoices < 2 )
+    {
+        NumVoices = 1;
+        SS_ChannelMenu();
+        return;
+    }
+
+    do
+    {
+        SS_DrawVoiceMenu ();
+
+        which = HandleMenu( &SoundSetupVoiceItems, &SoundSetupVoice[0],
+                            NULL );
+        if ( which >= 0 )
+        {
+            NumVoices = voicenums[ which ];
+            SS_ChannelMenu();
+            if ( handlewhich == -1 )
+            {
+                continue;
+            }
+            return;
+        }
+    }
+    while( which >= 0 );
+
+    if ( sbmenu )
+    {
+        handlewhich = -1;
+    }
+    else
+    {
+        handlewhich = -2;
+    }
+}
+
+//******************************************************************************
+//
+// SS_DrawVoiceMenu()
+//
+//******************************************************************************
+
+void SS_DrawVoiceMenu
+(
+    void
+)
+
+{
+    MenuNum = SNDCARDS;
+
+    SetAlternateMenuBuf();
+    ClearMenuBuf();
+    SetMenuTitle ("Number of Voices");
+
+    MN_GetActive( &SoundSetupVoiceItems, &SoundSetupVoice[0],
+                  NumVoices, voicenums );
+
+    DrawMenu( &SoundSetupVoiceItems, &SoundSetupVoice[ 0 ] );
+    DisplayInfo( 0 );
+
+    FlipMenuBuf();
+}
+
+//******************************************************************************
+//
+// SS_ChannelMenu ()
+//
+//******************************************************************************
+
+void SS_ChannelMenu
+(
+    void
+)
+
+{
+    int which;
+
+    if ( MaxChannels < 2 )
+    {
+        NumChannels = 1;
+        SS_BitMenu();
+        return;
+    }
+
+    do
+    {
+        SS_DrawChannelMenu ();
+        which = HandleMenu( &SoundSetupChannelItems, &SoundSetupChannel[0],
+                            NULL );
+        if ( which >= 0 )
+        {
+            NumChannels = smnums[ which ];
+            SS_BitMenu();
+            if ( handlewhich == -1 )
+            {
+                continue;
+            }
+            return;
+        }
+    }
+    while( which >= 0 );
+
+    handlewhich = -1;
+}
+
+//******************************************************************************
+//
+// SS_DrawChannelMenu()
+//
+//******************************************************************************
+
+void SS_DrawChannelMenu
+(
+    void
+)
+
+{
+    MenuNum = SNDCARDS;
+
+    SetAlternateMenuBuf();
+    ClearMenuBuf();
+    SetMenuTitle ("Number of Channels");
+
+    MN_GetActive( &SoundSetupChannelItems, &SoundSetupChannel[0],
+                  NumChannels, smnums );
+
+    DrawMenu( &SoundSetupChannelItems, &SoundSetupChannel[ 0 ] );
+    DisplayInfo( 0 );
+
+    FlipMenuBuf();
+}
+
+//******************************************************************************
+//
+// SS_BitMenu ()
+//
+//******************************************************************************
+
+void SS_BitMenu
+(
+    void
+)
+
+{
+    int which;
+
+    if ( MaxBits < 16 )
+    {
+        NumBits = 8;
+        return;
+    }
+
+    SS_DrawBitMenu ();
+
+    which = HandleMenu( &SoundSetupResolutionItems,
+                        &SoundSetupResolution[0], NULL );
+
+    if ( which >= 0 )
+    {
+        NumBits = resnums[ which ];
+        return;
+    }
+
+    handlewhich = -1;
+}
+
+
+//******************************************************************************
+//
+// SS_DrawBitMenu()
+//
+//******************************************************************************
+
+void SS_DrawBitMenu
+(
+    void
+)
+
+{
+    MenuNum = SNDCARDS;
+
+    SetAlternateMenuBuf();
+    ClearMenuBuf();
+    SetMenuTitle ("Playback Resolution");
+
+    MN_GetActive( &SoundSetupResolutionItems, &SoundSetupResolution[0],
+                  NumBits, resnums );
+
+    DrawMenu( &SoundSetupResolutionItems, &SoundSetupResolution[ 0 ] );
+    DisplayInfo( 0 );
+
+    FlipMenuBuf();
+}
+#endif
--- /dev/null
+++ b/rott/rt_menu.h
@@ -1,0 +1,217 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+#ifndef _rt_menu_public
+#define _rt_menu_public
+
+//******************************************************************************
+//
+// Public header for RT_MENU.C.
+//
+//******************************************************************************
+
+#include "lumpy.h"
+#include "rt_in.h"
+
+#define MaxX            320
+#define MaxY            200
+#define MaxString       128
+
+#define SaveGamePicX    18
+#define SaveGamePicY    18
+
+//******************************************************************************
+//
+// TYPEDEFS
+//
+//******************************************************************************
+
+typedef enum
+{
+    mn_tinyfont,
+    mn_8x8font,
+    mn_smallfont,
+    mn_largefont
+} mn_fontsize;
+
+typedef char CP_MenuNames[64];
+
+typedef struct
+{
+    int x;
+    int y;
+    int amount;
+    int curpos;
+    int indent;
+    CP_MenuNames *names;
+    mn_fontsize  fontsize;
+} CP_iteminfo;
+
+
+//MED
+typedef void (*menuptr)(int);
+
+typedef struct
+{
+    int active;
+    char texture[9];
+    char letter;
+    void (* routine)(int temp1);
+} CP_itemtype;
+
+enum
+{
+    CP_Inactive,
+    CP_Active,
+    CP_CursorLocation,
+    CP_Active3
+};
+
+//******************************************************************************
+//
+// GLOBALS
+//
+//******************************************************************************
+
+extern char*colorname[];
+extern boolean NewGame;
+
+extern CP_itemtype MainMenu[];
+extern boolean pickquick;
+
+extern cfont_t *IFont;
+extern font_t *CurrentFont;
+extern font_t *tinyfont;
+
+//
+// Global window coords
+//
+extern int PrintX;
+extern int PrintY;
+extern int WindowX;
+extern int WindowY;
+extern int WindowH;
+extern int WindowW;
+
+extern int px;
+extern int py;
+extern int bufferheight;
+extern int bufferwidth;
+extern boolean loadedgame;
+extern int FXMode;
+extern int MusicMode;
+
+extern font_t *newfont1;
+extern font_t *smallfont;
+extern font_t *bigfont;
+
+
+extern boolean AutoDetailOn;
+extern boolean DoubleClickOn;
+extern boolean BobbinOn;
+extern int     Menuflipspeed;
+extern int     DetailLevel;
+
+extern boolean          ingame;
+extern boolean          inmenu;
+extern int              scancode;
+
+extern int quicksaveslot;
+
+//****************************************************************************
+//
+// TYPEDEFS
+//
+//****************************************************************************
+typedef enum
+{
+    newgame,
+    battlemode,
+    loadgame,
+    savegame,
+    control,
+    orderinfo,
+    viewscores,
+    backtodemo,
+    quit
+} menuitems;
+
+
+
+//****************************************************************************
+//
+// PROTOTYPES
+//
+//****************************************************************************
+
+int  CP_ColorSelection(void);
+void CP_BattleMode(void);
+void DisplayInfo (int which);
+boolean CP_DisplayMsg (char *s, int number);
+void Message (char *string);
+void DrawMenu (CP_iteminfo *item_i, CP_itemtype *items);
+void DrawMainMenu(void);
+void AllocateSavedScreenPtr (void);
+void FreeSavedScreenPtr (void);
+void CleanUpControlPanel (void);
+void SetUpControlPanel (void);
+void ControlPanel (byte scancode);
+menuitems CP_MainMenu( void );
+int getASCII ( void );
+void DoMainMenu (void);
+boolean CP_CheckQuick (byte scancode);
+void AdjustMenuStruct (void);
+void MenuFixup (void);
+void GetEpisode (int level);
+void MN_PlayMenuSnd (int which);
+void CP_ViewScores (void);
+void ReadAnyControl (ControlInfo *ci);
+void WaitKeyUp (void);
+
+void GetMenuInfo (void);
+void WriteMenuInfo (void);
+int GetNumActive (CP_iteminfo *item_i, CP_itemtype *items);
+int MN_GetActive (CP_iteminfo *item_i, CP_itemtype *items, int check, int *nums);
+void MN_MakeActive (CP_iteminfo *item_i, CP_itemtype *items, int which);
+void MN_PlayMenuSnd (int which);
+
+int CP_LoadGame (int quick, int dieload);
+
+int CP_PlayerSelection (void);
+void BattleGamePlayerSetup( void );
+void BattleNoTeams( void );
+void BattleTeams( void );
+void CP_BattleMenu (void);
+void CP_BattleModes (void);
+void CP_ModemGameMessage ( int player );
+void ShowBattleOptions( boolean inmenu, int PosX, int PosY );
+void SetMenuHeader( char *header );
+int  HandleMultiPageCustomMenu( char **names, int amount, int curpos, char *title, void ( *routine )( int w ), void ( *redrawfunc )( void ), boolean exitonselect );
+int CP_LevelSelectionMenu ( void );
+int CP_EnterCodeNameMenu ( void );
+#ifdef DOS
+void CP_SoundSetup( void );
+#endif
+void QuickSaveGame (void);
+void UndoQuickSaveGame (void);
+void CP_CaptureTheTriadError( void );
+void CP_TeamPlayErrorMessage( void );
+void CP_ExtGameOptionsMenu( void );
+
+#endif
--- /dev/null
+++ b/rott/rt_msg.c
@@ -1,0 +1,812 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+#include "rt_def.h"
+#include "rt_view.h"
+#include "z_zone.h"
+#include "w_wad.h"
+#include "lumpy.h"
+#include "rt_util.h"
+#include "rt_vid.h"
+#include "rt_str.h"
+#include "rt_menu.h"
+#include "_rt_msg.h"
+#include "rt_msg.h"
+#include "rt_playr.h"
+#include "isr.h"
+#include "rt_main.h"
+#include "rt_net.h"
+#include "rt_com.h"
+
+#ifdef DOS
+#include <mem.h>
+#endif
+
+#include <stdlib.h>
+//MED
+#include "memcheck.h"
+
+
+/*
+=============================================================================
+
+                               GLOBALS
+
+=============================================================================
+*/
+messagetype Messages[MAXMSGS];
+
+/*
+=============================================================================
+
+                               LOCAL
+
+=============================================================================
+*/
+
+static int  UpdateMessageBackground;
+static int  MessageSystemStarted=0;
+static int  LastMessageTime;
+static boolean EraseMessage[ MAXMSGS ];
+static int     MessageOrder[ MAXMSGS ];
+static int     TotalMessages = 0;
+static int     MsgPos = 0;
+
+boolean MessagesEnabled = true;
+
+int StringLength (char *string)
+{
+    int length=0;
+
+    while ((*string)!=0)
+    {
+        length++;
+        string++;
+    }
+
+    length++;
+
+    return length;
+}
+
+/*
+====================
+=
+= ResetMessageTime
+=
+====================
+*/
+
+void ResetMessageTime ( void )
+{
+    LastMessageTime=GetTicCount();
+}
+
+/*
+====================
+=
+= InitializeMessages
+=
+====================
+*/
+void InitializeMessages
+(
+    void
+)
+
+{
+    int i;
+    boolean start;
+
+    start = false;
+
+    if ( MessageSystemStarted == 0 )
+    {
+        start = true;
+        MessageSystemStarted = 1;
+        memset( Messages, 0, sizeof( Messages ) );
+    }
+
+    for ( i = 0; i < MAXMSGS; i++ )
+    {
+        if ( Messages[ i ].active == 1 )
+        {
+            SafeFree( Messages[ i ].text );
+            Messages[ i ].active  = 0;
+            Messages[ i ].tictime = 0;
+            Messages[ i ].flags   = 0;
+            Messages[ i ].text    = NULL;
+        }
+    }
+
+    MSG.messageon = false;
+
+    LastMessageTime = 0;
+    UpdateMessageBackground = 0;
+    TotalMessages = 0;
+    memset( EraseMessage,  0, sizeof( EraseMessage ) );
+    memset( MessageOrder, -1, sizeof( MessageOrder ) );
+
+    // Only print startup message if it's the first time in
+    if ( start && !quiet )
+    {
+        printf( "RT_MSG: Message System Started\n" );
+    }
+}
+
+
+/*
+====================
+=
+= GetMessageOrder
+=
+====================
+*/
+void GetMessageOrder
+(
+    void
+)
+
+{
+    int  i;
+    int  lowest;
+    int  lowesttime;
+    byte done[ MAXMSGS ];
+    boolean found;
+
+    memset( &done[ 0 ],    0, sizeof( done ) );
+    memset( MessageOrder, -1, sizeof( MessageOrder ) );
+
+    for( TotalMessages = 0; TotalMessages < MAXMSGS; TotalMessages++ )
+    {
+        found = false;
+        lowesttime = 1000;
+        lowest = 0;
+
+        for( i = 0; i < MAXMSGS; i++ )
+        {
+            if ( ( Messages[ i ].active == 1 ) && ( done[ i ] == 0 ) &&
+                    ( Messages[ i ].tictime < lowesttime ) )
+            {
+                lowesttime = Messages[ i ].tictime;
+                lowest = i;
+                found = true;
+            }
+        }
+
+        if ( !found )
+        {
+            break;
+        }
+
+        done[ lowest ] = 1;
+        MessageOrder[ TotalMessages ] = lowest;
+    }
+}
+
+
+/*
+====================
+=
+= DeleteMessage
+=
+====================
+*/
+void DeleteMessage
+(
+    int num
+)
+
+{
+    int i;
+    int msg;
+    boolean found;
+
+    found = false;
+    for( i = 0; i < TotalMessages; i++ )
+    {
+        msg = MessageOrder[ i ];
+
+        if ( msg == num )
+        {
+            found = true;
+        }
+
+        if ( found )
+        {
+            UpdateMessageBackground -= EraseMessage[ i ];
+            UpdateMessageBackground += 3;
+            EraseMessage[ i ] = 3;
+        }
+    }
+
+    SafeFree( Messages[ num ].text );
+    memset( &Messages[ num ], 0, sizeof( messagetype ) );
+
+    GetMessageOrder();
+}
+
+
+/*
+====================
+=
+= DeletePriorityMessage
+=
+====================
+*/
+void DeletePriorityMessage ( int flags )
+{
+    int i;
+
+    for (i=0; i<MAXMSGS; i++)
+    {
+        if (Messages[i].active==1)
+        {
+            if (Messages[i].flags==flags)
+                DeleteMessage(i);
+        }
+    }
+}
+
+
+/*
+====================
+=
+= GetFreeMessage
+=
+====================
+*/
+int GetFreeMessage
+(
+    void
+)
+
+{
+    int i;
+    int found;
+
+    for( i = 0; i < MAXMSGS; i++ )
+    {
+        if ( Messages[ i ].active == 0 )
+        {
+            return( i );
+        }
+    }
+
+    found = -1;
+
+    for( i = 0; i < MAXMSGS; i++ )
+    {
+        if ( Messages[ i ].tictime >= 0 )
+        {
+            if ( found == -1 )
+            {
+                found = i;
+            }
+            else
+            {
+                if ( Messages[ i ].tictime < Messages[ found ].tictime )
+                {
+                    found = i;
+                }
+            }
+        }
+    }
+
+    DeleteMessage( found );
+
+    return( found );
+}
+
+
+/*
+====================
+=
+= SetMessage
+=
+====================
+*/
+void SetMessage
+(
+    int   num,
+    char *text,
+    int   flags
+)
+
+{
+    int i;
+    int msg;
+    int length;
+    boolean found;
+
+    if (iGLOBAL_SCREENWIDTH >= 640) {
+        CurrentFont = newfont1;//smallfont;
+    } else {
+        CurrentFont = smallfont;
+    }
+
+
+    length = StringLength( text );
+
+    Messages[ num ].active = 1;
+    Messages[ num ].flags  = flags;
+
+    if ( PERMANENT_MSG( flags ) )
+    {
+        int l;
+
+        l = COM_MAXTEXTSTRINGLENGTH + 1;
+        Messages[ num ].text = SafeMalloc( l );
+        memset( Messages[ num ].text, 0, l );
+
+        // Hack so that we can place menu in certain order
+        Messages[ num ].tictime = -100 + MsgPos;
+    }
+    else
+    {
+        Messages[ num ].text = SafeMalloc( length );
+
+        memset( Messages[ num ].text, 0, length );
+        Messages[ num ].tictime = MESSAGETIME;
+    }
+
+    memcpy( Messages[ num ].text, text, length );
+
+    GetMessageOrder();
+    found = false;
+    for( i = 0; i < TotalMessages; i++ )
+    {
+        msg = MessageOrder[ i ];
+        if ( msg == num )
+        {
+            found = true;
+        }
+        else if ( found )
+        {
+            UpdateMessageBackground -= EraseMessage[ i - 1 ];
+            UpdateMessageBackground += 3;
+            EraseMessage[ i - 1 ] = 3;
+        }
+    }
+}
+
+
+/*
+====================
+=
+= AddMessage
+=
+====================
+*/
+int AddMessage
+(
+    char *text,
+    int flags
+)
+
+{
+    int new;
+
+    if ( MessageSystemStarted == 0 )
+    {
+        Error( "Called AddMessage without starting Message system\n" );
+    }
+
+    if ( !( flags & MSG_NODELETE ) )
+    {
+        DeletePriorityMessage( flags );
+    }
+
+    new = GetFreeMessage();
+    SetMessage( new, text, flags );
+
+    return( new );
+}
+
+/*
+====================
+=
+= UpdateMessages
+=
+====================
+*/
+void UpdateMessages
+(
+    void
+)
+
+{
+    int messagetics;
+    int i;
+
+    messagetics = GetTicCount() - LastMessageTime;
+    LastMessageTime = GetTicCount();
+
+    if ( GamePaused == true )
+    {
+        return;
+    }
+
+    for( i = 0; i < MAXMSGS; i++ )
+    {
+        if ( ( Messages[ i ].active == 1 ) &&
+                ( !PERMANENT_MSG( Messages[ i ].flags ) ) )
+        {
+            Messages[ i ].tictime -= messagetics;
+            if ( Messages[ i ].tictime <= 0 )
+            {
+                DeleteMessage( i );
+            }
+        }
+    }
+}
+
+
+/*
+====================
+=
+= DisplayMessage
+=
+====================
+*/
+
+void DisplayMessage   (int num,int position)
+{
+    PrintX = 1;
+    if (iGLOBAL_SCREENWIDTH > 320) {
+        PrintY = 2 + ( position * (9*2) );
+    } else {
+        PrintY = 2 + ( position * (9*1) );
+    }
+
+
+    if ( SHOW_TOP_STATUS_BAR() )
+    {
+        PrintY += 16;
+    }
+    if ( !MessagesEnabled )
+    {
+        switch ( Messages[ num ].flags )
+        {
+        case MSG_QUIT:
+        case MSG_MACRO:
+        case MSG_MODEM:
+        case MSG_NAMEMENU:
+        case MSG_MSGSYSTEM:
+            break;
+
+        case MSG_REMOTERIDICULE:
+        case MSG_REMOTE:
+        case MSG_GAME:
+        case MSG_DOOR:
+        case MSG_BONUS:
+        case MSG_BONUS1:
+        case MSG_CHEAT:
+        case MSG_SYSTEM:
+        default :
+            DeleteMessage( num );
+            return;
+        }
+    }
+
+    switch ( Messages[ num ].flags )
+    {
+    case MSG_REMOTERIDICULE:
+    case MSG_REMOTE:
+        fontcolor = egacolor[ WHITE ];
+        break;
+
+    case MSG_MODEM:
+        fontcolor = egacolor[ LIGHTBLUE ];
+        DrawIString( PrintX, PrintY, "Message>", Messages[ num ].flags );
+        if ( iGLOBAL_SCREENWIDTH == 320) {
+            PrintX += 8 * 8;
+        } else if ( iGLOBAL_SCREENWIDTH == 640) {
+            PrintX += 8 * 8*2;
+        } else if ( iGLOBAL_SCREENWIDTH == 800) {
+            PrintX += 8 * 8*2;
+        }
+
+        fontcolor = egacolor[ LIGHTGRAY ];
+        break;
+
+    case MSG_GAME:
+    case MSG_DOOR:
+    case MSG_BONUS:
+    case MSG_BONUS1:
+    case MSG_NAMEMENU:
+        fontcolor = egacolor[ GREEN ];
+        break;
+
+    case MSG_CHEAT:
+        fontcolor = egacolor[ YELLOW ];
+        break;
+    case MSG_MSGSYSTEM:
+    case MSG_SYSTEM:
+    case MSG_QUIT:
+    case MSG_MACRO:
+        fontcolor = egacolor[ RED ];
+        break;
+
+    default :
+#if ((DEVELOPMENT == 1))
+        Error( "DisplayMessage called with invalid priority number." );
+#else
+        fontcolor = egacolor[ LIGHTGREEN ];
+#endif
+    }
+
+    DrawIString( PrintX, PrintY, Messages[ num ].text, Messages[ num ].flags );
+}
+
+
+
+/*
+====================
+=
+= RestoreMessageBackground
+=
+====================
+*/
+void RestoreMessageBackground
+(
+    void
+)
+
+{
+    pic_t *shape;
+    int i;
+    int y;
+
+    if ( UpdateMessageBackground > 0 )
+    {
+        y = 18;
+        for( i = 0; i < MAXMSGS; i++ )
+        {
+            if ( EraseMessage[ i ] )
+            {
+                UpdateMessageBackground--;
+                EraseMessage[ i ]--;
+                if ( viewsize < 15 )
+                {
+                    shape =  ( pic_t * )W_CacheLumpName( "backtile", PU_CACHE, Cvt_pic_t, 1 );//w=32 h=8
+                    //SetTextMode (  );
+                    //DrawTiledRegion( 0, y, 320, 9, 0, y, shape );KILLS_HEIGHT bna--
+                    DrawTiledRegion( 0, y, iGLOBAL_SCREENWIDTH, 9, 0, y, shape );
+                    DrawTiledRegion( 0, y+8, iGLOBAL_SCREENWIDTH, 9, 0, y, shape );
+                    DrawTiledRegion( 0, y+16, iGLOBAL_SCREENWIDTH, 9, 0, y, shape );
+
+                    //DrawTiledRegion( 0, y, iGLOBAL_SCREENWIDTH, 212, 0, y, shape );
+                }
+                if ( viewsize == 0 )
+                {
+                    if ( ( y + 9 > YOURCPUSUCKS_Y ) &&
+                            ( y < ( YOURCPUSUCKS_Y + YOURCPUSUCKS_HEIGHT ) ) )
+                    {
+                        DrawCPUJape();
+                    }
+                }
+            }
+
+            y += 9;
+        }
+    }
+}
+
+
+/*
+====================
+=
+= DrawMessages
+=
+====================
+*/
+void DrawMessages
+(
+    void
+)
+
+{
+    int i;
+
+    if ( TotalMessages > 0 )
+    {
+        IFont = ( cfont_t * )W_CacheLumpName( "ifnt", PU_CACHE, Cvt_cfont_t, 1 );
+
+        for( i = 0; i < TotalMessages; i++ )
+        {
+            DisplayMessage( MessageOrder[ i ], i );
+        }
+    }
+    UpdateMessages();
+}
+
+
+/*
+====================
+=
+= UpdateModemMessage
+=
+====================
+*/
+void UpdateModemMessage
+(
+    int num,
+    char c
+)
+
+{
+    int i;
+
+    Messages[ num ].text[ MSG.length - 1 ] = ( byte )c;
+    Messages[ num ].text[ MSG.length ]     = ( byte )'_';
+    MSG.length++;
+
+    for( i = 0; i < TotalMessages; i++ )
+    {
+        if ( MessageOrder[ i ] == num )
+        {
+            UpdateMessageBackground -= EraseMessage[ i ];
+            UpdateMessageBackground += 3;
+            EraseMessage[ i ] = 3;
+            break;
+        }
+    }
+}
+
+
+/*
+====================
+=
+= ModemMessageDeleteChar
+=
+====================
+*/
+void ModemMessageDeleteChar
+(
+    int num
+)
+
+{
+    int i;
+
+    MSG.length--;
+    Messages[ num ].text[ MSG.length ]     = ( byte )0;
+    Messages[ num ].text[ MSG.length - 1 ] = ( byte )'_';
+
+    for( i = 0; i < TotalMessages; i++ )
+    {
+        if ( MessageOrder[ i ] == num )
+        {
+            UpdateMessageBackground -= EraseMessage[ i ];
+            UpdateMessageBackground += 3;
+            EraseMessage[ i ] = 3;
+            break;
+        }
+    }
+}
+
+
+/*
+====================
+=
+= DrawPlayerSelectionMenu
+=
+====================
+*/
+
+void DrawPlayerSelectionMenu
+(
+    void
+)
+
+{
+    int i;
+    int p;
+    char str[ 20 ];
+
+    p = 1;
+    MsgPos = 1;
+    AddMessage( "Press a key from 0 to 9 to select", MSG_NAMEMENU );
+    MsgPos++;
+    AddMessage( "who to send your message to:", MSG_NAMEMENU );
+    MsgPos++;
+
+    for( i = 0; i < numplayers; i++ )
+    {
+        if ( i != consoleplayer )
+        {
+            strcpy( str, "0 - " );
+            strcat( str, PLAYERSTATE[ i ].codename );
+            str[ 0 ] = '0' + p;
+            p++;
+            if ( p > 9 )
+            {
+                p = 0;
+            }
+
+            AddMessage( str, MSG_NAMEMENU );
+            MsgPos++;
+        }
+    }
+
+    if ( ( MsgPos < MAXMSGS - 1 ) && ( gamestate.teamplay ) )
+    {
+        AddMessage( "T - All team members", MSG_NAMEMENU );
+        MsgPos++;
+    }
+
+    if ( MsgPos < MAXMSGS - 1 )
+    {
+        AddMessage( "A - All players", MSG_NAMEMENU );
+    }
+
+    MsgPos = 0;
+}
+
+
+/*
+====================
+=
+= FinishModemMessage
+=
+====================
+*/
+void FinishModemMessage
+(
+    int num,
+    boolean send
+)
+{
+    if ( ( !MSG.inmenu ) && ( MSG.length > 0 ) )
+    {
+        Messages[ num ].text[ MSG.length - 1 ] = ( byte )0;
+        MSG.length--;
+    }
+
+    if ( ( send == true ) && ( ( MSG.length > 0 ) ||
+                               ( MSG.remoteridicule != -1 ) ) )
+    {
+        if ( ( MSG.directed ) && ( !MSG.inmenu ) )
+        {
+            DrawPlayerSelectionMenu();
+            MSG.messageon = true;
+            MSG.inmenu = true;
+            return;
+        }
+
+        MSG.messageon = false;
+        if ( MSG.remoteridicule != -1 )
+        {
+            AddRemoteRidiculeCommand( consoleplayer, MSG.towho,
+                                      MSG.remoteridicule );
+        }
+        if ( MSG.length > 0 )
+        {
+            AddTextMessage( Messages[ num ].text, MSG.length, MSG.towho );
+        }
+    }
+
+    if ( MSG.inmenu )
+    {
+        DeletePriorityMessage( MSG_NAMEMENU );
+    }
+
+    DeleteMessage( num );
+}
--- /dev/null
+++ b/rott/rt_msg.h
@@ -1,0 +1,71 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+#ifndef _rt_msg_public
+#define _rt_msg_public
+
+#define MSG_PERMANENT     0x80
+#define MSG_NODELETE      0x40
+#define MSG_PRIORITY( x ) ( ( x ) & 0x3f )
+
+#define PERMANENT_MSG( x ) ( ( x ) & MSG_PERMANENT )
+#define DELETABLE_MSG( x ) ( ( x ) & MSG_NODELETE )
+
+#define MSG_MODEM          ( 1 | MSG_PERMANENT )
+#define MSG_SYSTEM         ( 2 )
+#define MSG_REMOTERIDICULE ( 3 )
+#define MSG_REMOTE         ( 4 | MSG_NODELETE )
+#define MSG_GAME           ( 5 | MSG_NODELETE )
+#define MSG_DOOR           ( 6 )
+#define MSG_CHEAT          ( 7 )
+#define MSG_NAMEMENU       ( 8 | MSG_PERMANENT | MSG_NODELETE )
+#define MSG_QUIT           ( 9 )
+#define MSG_MACRO          ( 10 )
+#define MSG_BONUS1         ( 11 )
+#define MSG_BONUS          ( 12 )
+#define MSG_MSGSYSTEM      ( 13 )
+
+#define MAXMSGS 15
+
+typedef struct msgt
+{
+    byte active;
+    byte flags;
+    int  tictime;
+    char * text;
+} messagetype;
+
+extern messagetype Messages[MAXMSGS];
+
+extern boolean MessagesEnabled;
+
+
+void RestoreMessageBackground( void );
+void DrawMessages ( void );
+int AddMessage (char * text, int flags);
+void InitializeMessages ( void );
+void ResetMessageTime ( void );
+int StringLength (char *string);
+void UpdateModemMessage (int num, char c);
+void ModemMessageDeleteChar (int num);
+void DeleteMessage ( int num );
+void FinishModemMessage( int num, boolean send );
+void DeletePriorityMessage( int flags );
+
+#endif
--- /dev/null
+++ b/rott/rt_net.c
@@ -1,0 +1,3338 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+
+#ifdef DOS
+#include <dos.h>
+#include <io.h>
+#endif
+
+#include "rt_def.h"
+#include "rt_main.h"
+#include "rt_net.h"
+#include "rt_com.h"
+#include "_rt_net.h"
+#include "rt_actor.h"
+#include "rt_playr.h"
+#include "isr.h"
+#include "z_zone.h"
+#include "develop.h"
+#include "rottnet.h"
+#include "rt_msg.h"
+#include "rt_sound.h"
+#include "rt_menu.h"
+#include "rt_util.h"
+#include "rt_rand.h"
+#include "rt_game.h"
+#include "rt_draw.h"
+#include "myprint.h"
+#include "rt_debug.h"
+#include "rt_view.h"
+#include "rt_battl.h"
+#include "rt_dmand.h"
+//MED
+#include "memcheck.h"
+
+#if (SYNCCHECK == 1)
+int            lastsynccheck;
+COM_CheckSyncType PlayerSync[MAXPLAYERS];
+#endif
+
+
+CommandType * LocalCmds;
+CommandType * ServerCmds;
+
+
+int        controlupdatestartedtime=-1;
+int        controlupdatetime=-1;
+int        serverupdatetime=-1;
+int        controlupdatestarted=0;
+boolean    GamePaused=false;
+
+boolean    modemgame;
+boolean    networkgame;
+int        numplayers;
+int        server;
+boolean    IsServer;
+boolean    standalone;
+boolean    restartgame=false;
+boolean    respawnactive=false;
+boolean    playerdead=false;
+boolean    controlschanged=true;
+boolean    battlegibs=false;
+boolean    remoteridicule = false;
+/*
+=============================================================================
+
+					LOCAL FUNCTION PROTOTYPES and VARIABLES
+
+=============================================================================
+*/
+boolean  demorecord,
+         demoplayback;
+byte     *demoptr,
+         *lastdemoptr,
+         *demobuffer=NULL;
+boolean  demodone = false;
+int      predemo_violence = -1;
+int oldmomx;
+int oldmomy;
+int oldspdang;
+
+static boolean GameCommandsStarted=false;
+
+static int oldcontrolbuf[3];
+static int oldbuttonbits;
+static CommandType * PlayerCmds[MAXPLAYERS];
+static CommandType * ClientCmds[MAXPLAYERS];
+
+static boolean GotPlayersDesc[MAXPLAYERS];
+static boolean PlayersReady[MAXPLAYERS];
+static int     LastCommandTime[MAXPLAYERS];
+
+static CommandStatusType * CommandState[MAXPLAYERS+1];
+
+static boolean InProcessServer=false;
+static int lastcontrolupdatetime;
+static int largesttime;
+static int PlayerStatus[MAXPLAYERS];
+//static int syncservertime;
+//static boolean FixingPackets;
+static int controldivisor=1;
+static int nextupdatetime;
+static boolean UpdateServer=true;
+
+void CheckForPacket ( void );
+void PrepareLocalPacket ( void );
+void SendSyncCheckPacket ( void );
+void AddModemSubPacket(void * incoming);
+void SetPlayerDescription( void * pkt );
+void UpdateDemoPlayback (int time);
+int GetTypeSize (int type);
+int MaxSpeedForCharacter(playertype *pstate);
+
+/*
+=============================================================================
+
+						  Game Command Section
+
+=============================================================================
+*/
+
+//****************************************************************************
+//
+// ComError ()
+//
+//****************************************************************************
+
+#define ComError SoftError
+#if 0
+void ComError (char *error, ...)
+{
+#if 0
+    va_list	argptr;
+#endif
+
+    SoftError(error);
+#if 0
+    if (standalone==true)
+    {
+        va_start (argptr, error);
+        vprintf (error, argptr);
+        va_end (argptr);
+    }
+#endif
+}
+#endif
+
+//****************************************************************************
+//
+// ConsoleIsServer()
+//
+//****************************************************************************
+boolean ConsoleIsServer ( void )
+{
+    if (modemgame==true)
+    {
+        if (networkgame==true)
+        {
+            if (rottcom->client==0)
+            {
+                return true;
+            }
+        }
+    }
+    return false;
+}
+
+//****************************************************************************
+//
+// GamePacketSize()
+//
+//****************************************************************************
+int GamePacketSize( void )
+{
+    if ((remoteridicule == true) || (ConsoleIsServer() == true))
+    {
+        return GetTypeSize(COM_SOUNDANDDELTA);
+    }
+    else
+        return GetTypeSize(COM_TEXT);
+}
+
+//****************************************************************************
+//
+// InitializeGameCommands()
+//
+//****************************************************************************
+void InitializeGameCommands( void )
+{
+    int i;
+    int j;
+
+    // default to player 0
+
+    if (GameCommandsStarted==true)
+        return;
+
+    GameCommandsStarted=true;
+
+    if ((modemgame==true))
+        controldivisor=rottcom->ticstep;
+
+    standalone=false;
+    IsServer=false;
+
+    if (modemgame==true)
+    {
+        consoleplayer=rottcom->consoleplayer;
+
+        if (networkgame==true)
+        {
+            if (rottcom->client==0)
+            {
+                IsServer=true;
+                // turn it on absolutely for the server
+                remoteridicule = true;
+                if (consoleplayer==0)
+                    standalone=true;
+            }
+            if (consoleplayer>0)
+                consoleplayer--; // playernumber fixup
+        }
+    }
+
+    if (standalone==false)
+    {
+        int size;
+
+        size = GamePacketSize ();
+
+        for (i=0; i<numplayers; i++)
+        {
+            PlayerCmds[i]=(CommandType *)SafeLevelMalloc(sizeof(CommandType));
+            for (j=0; j<MAXCMDS; j++)
+            {
+                PlayerCommand(i,j)=SafeLevelMalloc(size);
+            }
+        }
+    }
+
+
+    // allocate local commands
+
+    LocalCmds=(CommandType *)SafeLevelMalloc(sizeof(CommandType));
+    for (j=0; j<MAXCMDS; j++)
+    {
+        int size;
+
+        size = GamePacketSize();
+
+        LocalCommand(j)=SafeLevelMalloc(size);
+        memset(LocalCommand(j),COM_DELTANULL,size);
+    }
+
+    CommandState[0]=(CommandStatusType *)SafeLevelMalloc(sizeof(CommandStatusType));
+
+    if (modemgame==true)
+    {
+        for (i=0; i<numplayers; i++)
+        {
+            PlayerStatus[i]=player_ingame;
+        }
+        if (networkgame==true)
+        {
+            server=1;
+
+            // initialize the Server
+
+            if (IsServer==true)
+            {
+                server=0;
+                ServerCmds=(CommandType *)SafeMalloc(sizeof(CommandType));
+                for (j=0; j<MAXCMDS; j++)
+                {
+                    int size;
+                    size=( (numplayers * GetTypeSize(COM_TEXT)) +
+                           GetTypeSize(COM_SOUNDANDDELTA) +
+                           sizeof(COM_ServerHeaderType) -
+                           sizeof(byte)
+                         );
+                    ServerCommand(j)=SafeMalloc( size );
+                    memset(ServerCommand(j),COM_DELTANULL,size);
+                }
+                for (i=1; i<=numplayers; i++)
+                {
+                    CommandState[i]=(CommandStatusType *)
+                                    SafeMalloc(sizeof(CommandStatusType));
+                }
+                for (i=0; i<numplayers; i++)
+                {
+                    ClientCmds[i]=(CommandType *)SafeMalloc(sizeof(CommandType));
+                    for (j=0; j<MAXCMDS; j++)
+                    {
+                        int size;
+
+                        size=GetTypeSize(COM_SOUNDANDDELTA);
+                        ClientCommand(i,j)=SafeMalloc(size);
+                        memset(ClientCommand(i,j),COM_DELTANULL,size);
+                    }
+                }
+            }
+        }
+        else // must be a two player game
+        {
+            server=consoleplayer^1;
+        }
+    }
+#if 0
+#if (DEVELOPMENT == 1)
+    if (IsServer)
+        ComError("I am the server\n");
+    ComError("consoleplayer=%ld\n",consoleplayer);
+    ComError("server=%ld mynumber=%ld\n",server,consoleplayer);
+#endif
+#endif
+}
+
+
+//****************************************************************************
+//
+// ShutdownGameCommands()
+//
+//****************************************************************************
+void ShutdownGameCommands( void )
+{
+    int i;
+    int j;
+
+    if (GameCommandsStarted==false)
+        return;
+
+    GameCommandsStarted=false;
+
+    // free up playercmds;
+    if (standalone==false)
+    {
+        for (i=0; i<numplayers; i++)
+        {
+            for (j=0; j<MAXCMDS; j++)
+            {
+                if (PlayerCommand(i,j))
+                {
+                    SafeFree(PlayerCommand(i,j));
+                    PlayerCommand(i,j)=NULL;
+                }
+            }
+            SafeFree( PlayerCmds[i] );
+            PlayerCmds[i]=NULL;
+        }
+    }
+
+    // free up command status
+
+    SafeFree(CommandState[0]);
+    CommandState[0]=NULL;
+
+    if (modemgame==true)
+    {
+
+        // free up local commands
+
+        for (j=0; j<MAXCMDS; j++)
+        {
+            if (LocalCommand(j))
+            {
+                SafeFree(LocalCommand(j));
+                LocalCommand(j)=NULL;
+            }
+        }
+        SafeFree(LocalCmds);
+        LocalCmds=NULL;
+
+
+        // free up Server
+
+        if (networkgame==true)
+        {
+            if (IsServer==true)
+            {
+                for (j=0; j<MAXCMDS; j++)
+                {
+                    if (ServerCommand(j))
+                    {
+                        SafeFree(ServerCommand(j));
+                        ServerCommand(j)=NULL;
+                    }
+                }
+                SafeFree(ServerCmds);
+                ServerCmds=NULL;
+                for (i=1; i<=numplayers; i++)
+                {
+                    SafeFree(CommandState[i]);
+                    CommandState[i]=NULL;
+                }
+                for (i=0; i<numplayers; i++)
+                {
+                    for (j=0; j<MAXCMDS; j++)
+                    {
+                        if (ClientCommand(i,j))
+                        {
+                            SafeFree(ClientCommand(i,j));
+                            ClientCommand(i,j)=NULL;
+                        }
+                    }
+                    SafeFree( ClientCmds[i] );
+                    ClientCmds[i]=NULL;
+                }
+            }
+        }
+    }
+}
+
+
+
+
+/*
+=============================================================================
+
+						  Client Controls Section
+
+=============================================================================
+*/
+
+
+//****************************************************************************
+//
+// ShutdownClientControls ()
+//
+//****************************************************************************
+
+void ShutdownClientControls ( void )
+{
+    int i;
+#if (DEVELOPMENT == 1)
+    SoftError ("LARGEST time difference=%ld\n",largesttime);
+#endif
+    controlupdatestarted=0;
+    for (i=0; i<numplayers; i++)
+    {
+        if (PlayerStatus[i] == player_leftgame)
+            PlayerStatus[i]=player_ingame;
+    }
+}
+
+
+//****************************************************************************
+//
+// StartupClientControls ()
+//
+//****************************************************************************
+
+void StartupClientControls ( void )
+{
+    int i,j;
+
+    if (controlupdatestarted==1)
+        return;
+
+    controlupdatestarted=1;
+
+    memset(oldcontrolbuf,-1,sizeof(oldcontrolbuf));
+    oldbuttonbits=-1;
+    controlschanged=true;
+
+    INL_GetMouseDelta(&i,&i);
+
+
+    locplayerstate->dmomx = 0;
+    locplayerstate->dmomy = 0;
+    locplayerstate->angle = 0;
+    locplayerstate->topspeed=MaxSpeedForCharacter(locplayerstate);
+
+
+    CalcTics();
+    CalcTics();
+
+//   FixingPackets=false;
+
+    memset (controlbuf, 0, sizeof (controlbuf));
+    buttonbits = 0;
+    lastpolltime=-1;
+    IN_ClearKeyboardQueue ();
+
+    if (modemgame==true)
+    {
+        controlupdatetime=controlsynctime+(VBLCOUNTER*2);
+        SoftError("Controls started at %d\n",controlupdatetime);
+    }
+    else if (demoplayback || demorecord)
+    {
+        ISR_SetTime(20);
+        oldtime = 20;
+        controlupdatetime=20;
+    }
+    else
+        controlupdatetime=GetTicCount();
+
+    controlupdatetime-=(controlupdatetime%controldivisor);
+
+    serverupdatetime=controlupdatetime;
+    oldpolltime=controlupdatetime;
+    nextupdatetime=oldpolltime;
+#if (SYNCCHECK == 1)
+    lastsynccheck=oldpolltime+CHECKSYNCTIME;
+#endif
+    controlupdatestartedtime=controlupdatetime;
+
+    for( j = 0; j < numplayers; j++ )
+    {
+        memset( PLAYERSTATE[ j ].buttonheld, 0,
+                sizeof( PLAYERSTATE[ j ].buttonheld ) );
+        memset( PLAYERSTATE[ j ].buttonstate, 0,
+                sizeof( PLAYERSTATE[ j ].buttonstate ) );
+    }
+
+    for (i=0; i<MAXCMDS; i++)
+    {
+        ServerCommandNumberStatus( i ) = cs_notarrived;
+    }
+
+    LastCommandTime[0]=controlupdatetime-controldivisor;
+    if (IsServer==true)
+    {
+        int size;
+
+        UpdateServer=true;
+        size=( (numplayers * GetTypeSize(COM_TEXT)) +
+               GetTypeSize(COM_SOUNDANDDELTA) +
+               sizeof(COM_ServerHeaderType) -
+               sizeof(byte)
+             );
+
+        for (j=0; j<numplayers; j++)
+        {
+            for (i=0; i<MAXCMDS; i++)
+            {
+                ClientCommandNumberStatus( j, i ) = cs_notarrived;
+            }
+            LastCommandTime[j]=controlupdatetime-controldivisor;
+        }
+        for (i=0; i<MAXCMDS; i++)
+            memset(ServerCommand(i),COM_DELTANULL,size);
+    }
+    else if (modemgame==true)
+    {
+        int nump;
+
+        nump=numplayers;
+        if (nump<2) nump=2;
+
+        for (i=0; i<nump; i++)
+        {
+            LastCommandTime[i]=controlupdatetime-controldivisor;
+        }
+    }
+
+
+#if (DEVELOPMENT == 1)
+//   ComError("StartupClientControls: GetTicCount()=%ld oldtime=%ld controlupdatetime=%ld\n",GetTicCount(),oldtime,controlupdatetime);
+#endif
+
+    if ((demoplayback==false) && (standalone==false))
+    {
+        if (modemgame==true)
+        {
+            while (GetTicCount()<(controlupdatetime-10))
+            {
+                CalcTics();
+            }
+        }
+        lastcontrolupdatetime=GetTicCount();
+        largesttime=0;
+        PollControls();
+    }
+    if (standalone==true)
+        printf("Packet Server started\n");
+}
+
+
+
+//****************************************************************************
+//
+// UpdateClientControls ()
+//
+//****************************************************************************
+
+static boolean InUCC=false;
+void UpdateClientControls ( void )
+{
+    int time;
+//   int delta;
+
+    if (controlupdatestarted==0)
+        return;
+
+    if (InUCC)
+        return;
+    else
+        InUCC = true;
+
+    wami(6);
+
+#if 0
+
+    delta=GetTicCount()-lastcontrolupdatetime;
+    if (delta>largesttime)
+    {
+        if (delta>10)
+            largesttime=delta;
+        largesttime=delta;
+    }
+
+#endif
+    lastcontrolupdatetime=GetTicCount();
+
+    if (standalone==false)
+    {
+        time=GetTicCount();
+
+        // if we are a fixing the current packet stop update of deltas
+        // in non-network games.
+        if (
+            (networkgame == false) &&
+            (ServerCommandStatus(oldpolltime)==cs_fixing)
+        )
+        {
+            time=controlupdatetime-controldivisor;
+        }
+
+        while (time>=controlupdatetime)
+        {
+            MoveType * Delta;
+            boolean soundready;
+
+            soundready = SD_SoundDataReady();
+
+            if (demoplayback==true)
+            {
+                UpdateDemoPlayback(controlupdatetime);
+            }
+//         else
+//            {
+//            PollControls();
+//            }
+
+            if (
+                (memcmp(&controlbuf[0],&oldcontrolbuf[0],sizeof(controlbuf))!=0) ||
+                (buttonbits!=oldbuttonbits)
+            )
+            {
+                controlschanged=true;
+                memcpy(&oldcontrolbuf[0],&controlbuf[0],sizeof(controlbuf));
+                oldbuttonbits=buttonbits;
+            }
+            else
+            {
+                controlschanged=false;
+            }
+
+            if ((controlschanged==false) && (soundready==false))
+            {
+                NullMoveType * NullDelta;
+
+                NullDelta=(NullMoveType *)NextLocalCommand();
+                NullDelta->type=COM_DELTANULL;
+            }
+            else
+            {
+                Delta=(MoveType *)NextLocalCommand();
+                Delta->type=COM_DELTA;
+                Delta->momx=(controlbuf[0]>>1);
+                Delta->momy=(controlbuf[1]>>1);
+                Delta->dangle=controlbuf[2]>>11;
+                Delta->buttons=buttonbits;
+
+                // See if we need to update sound packet
+
+                if (soundready==true)
+                {
+                    COM_SoundType * sndpkt;
+                    recordstate status;
+
+                    if (remoteridicule == false)
+                        Error("Attempt to record Remote Ridicule without adequate storage");
+                    sndpkt=(COM_SoundType *)Delta->Sounddata;
+
+                    // Turn the packet into a COM_SOUNDANDDELTA packet
+
+                    Delta->type=COM_SOUNDANDDELTA;
+                    status = SD_GetSoundData ( &(sndpkt->data[0]),
+                                               COM_SOUND_BUFFERSIZE );
+                    switch (status)
+                    {
+                    case rs_nodata:
+                        Delta->type=COM_DELTA;
+                        break;
+                    case rs_newsound:
+                        sndpkt->type=COM_SOUND_START_TRANSMISSION;
+                        break;
+                    case rs_endsound:
+                        sndpkt->type=COM_SOUND_END_TRANSMISSION;
+                        break;
+                    case rs_data:
+                        sndpkt->type=COM_SOUND_NORMAL_TRANSMISSION;
+                        break;
+                    default:
+                        Error("Illegal return value for SD_GetSoundData");
+                        break;
+                    }
+                }
+                if (demorecord==true)
+                    RecordDemoCmd();
+            }
+            PrepareLocalPacket();
+
+            if (
+                (controlupdatetime != -1) &&
+                (controlupdatetime > (lastpolltime+MAXPOLLTICS)) &&
+                (demoplayback==false)
+            )
+            {
+                controlbuf[0] = controlbuf[1] = controlbuf[2] = 0;
+            }
+        }
+    }
+    if (modemgame==true)
+    {
+        CheckForPacket ();
+    }
+
+    if ((standalone == false) && (IsServer==true) && (UpdateServer==true))
+        ProcessServer();
+
+// take out
+    if (modemgame==true)
+    {
+//#if (DEVELOPMENT == 1)
+        if (PanicPressed==true)
+        {
+            Error("Game Aborted. Scroll Lock pressed\n");
+        }
+//#endif
+        if (Keyboard[sc_Insert] && Keyboard[sc_Q])
+            Error("Game Aborted. Insert->Q pressed\n");
+    }
+
+    InUCC = false;
+
+    waminot();
+}
+
+//****************************************************************************
+//
+// PlayerInGame()
+//
+//****************************************************************************
+boolean PlayerInGame ( int p )
+{
+    if (PlayerStatus[p]!=player_ingame)
+        return false;
+    return true;
+}
+
+/*
+=============================================================================
+
+						  Packet Section
+
+=============================================================================
+*/
+
+//****************************************************************************
+//
+// CheckForPacket()
+//
+//****************************************************************************
+void CheckForPacket ( void )
+{
+    wami(7);
+    while (ReadPacket()==true)
+    {
+        if (badpacket==0)
+        {
+            ProcessPacket(&ROTTpacket[0], rottcom->remotenode);
+#if (DEVELOPMENT == 1)
+//         ComError("CheckForPacket: from=%ld\n",rottcom->remotenode);
+#endif
+        }
+        else
+            RequestPacket (LastCommandTime[rottcom->remotenode]+controldivisor, rottcom->remotenode, controldivisor);
+    }
+    waminot();
+}
+
+
+//****************************************************************************
+//
+// AddRemoteRidiculeCommand()
+//
+//****************************************************************************
+void AddRemoteRidiculeCommand ( int player, int towho, int num )
+{
+    ((COM_RemoteRidiculeType *)NextLocalCommand())->type=COM_REMRID;
+    ((COM_RemoteRidiculeType *)NextLocalCommand())->num=num;
+    ((COM_RemoteRidiculeType *)NextLocalCommand())->player=player;
+    ((COM_RemoteRidiculeType *)NextLocalCommand())->towho=towho;
+
+    PrepareLocalPacket();
+}
+
+//****************************************************************************
+//
+// ProcessRemoteRidicule()
+//
+//****************************************************************************
+void ProcessRemoteRidicule ( void * pkt )
+{
+    COM_RemoteRidiculeType * remrot;
+    char name[ 50 ];
+    int from;
+    int who;
+
+    remrot = (COM_RemoteRidiculeType *)pkt;
+    from   = remrot->player;
+    who    = remrot->towho;
+    if ( ( who == consoleplayer ) || ( who == MSG_DIRECTED_TO_ALL ) ||
+            ( ( who == MSG_DIRECTED_TO_TEAM ) && ( BATTLE_Team[ from ] ==
+                    BATTLE_Team[ consoleplayer ] ) ) )
+    {
+        strcpy( name, "(� RR from " );
+        strcat( name, PLAYERSTATE[from].codename );
+        strcat( name, ")" );
+        AddMessage( name, MSG_REMOTERIDICULE );
+
+        SD_Play( SD_REMOTEM1SND + remrot->num );
+    }
+}
+
+//****************************************************************************
+//
+// AddEndGameCommand()
+//
+//****************************************************************************
+void AddEndGameCommand ( void )
+{
+    ((COM_EndGameType *)NextLocalCommand())->type=COM_ENDGAME;
+
+    PrepareLocalPacket();
+}
+
+//****************************************************************************
+//
+// AddGameEndCommand()
+//
+//****************************************************************************
+void AddGameEndCommand ( void )
+{
+    ((COM_GameEndType *)NextLocalCommand())->type=COM_GAMEEND;
+
+    PrepareLocalPacket();
+}
+
+//****************************************************************************
+//
+// AddQuitCommand()
+//
+//****************************************************************************
+void AddQuitCommand ( void )
+{
+    ((COM_QuitType *)NextLocalCommand())->type=COM_QUIT;
+    PrepareLocalPacket();
+}
+
+//****************************************************************************
+//
+// AddExitCommand()
+//
+//****************************************************************************
+void AddExitCommand ( void )
+{
+    ((COM_ExitType *)NextLocalCommand())->type=COM_EXIT;
+    PrepareLocalPacket();
+}
+
+//****************************************************************************
+//
+// AddPauseStateCommand()
+//
+//****************************************************************************
+void AddPauseStateCommand ( int type )
+{
+    ((COM_PauseType *)NextLocalCommand())->type=type;
+
+    PrepareLocalPacket();
+}
+
+
+//****************************************************************************
+//
+// AddRespawnCommand()
+//
+//****************************************************************************
+void AddRespawnCommand ( void )
+{
+    if (respawnactive==true)
+        return;
+
+    respawnactive=true;
+
+    ((COM_RespawnType *)NextLocalCommand())->type=COM_RESPAWN;
+
+    PrepareLocalPacket();
+}
+
+
+//****************************************************************************
+//
+// AddTextMessage()
+//
+//****************************************************************************
+void AddTextMessage
+(
+    char *message,
+    int   length,
+    int   towho
+)
+
+{
+    COM_TextType *Text;
+
+    Text = ( COM_TextType * )NextLocalCommand();
+
+    Text->type = COM_TEXT;
+    memset( &Text->string[ 0 ], 0, COM_MAXTEXTSTRINGLENGTH );
+
+    if ( length >= COM_MAXTEXTSTRINGLENGTH )
+    {
+        length = COM_MAXTEXTSTRINGLENGTH - 1;
+    }
+
+    memcpy( &Text->string[ 0 ], message, length );
+
+    Text->towho = towho;
+
+    PrepareLocalPacket();
+}
+
+
+//****************************************************************************
+//
+// PrepareLocalPacket
+//
+//****************************************************************************
+
+void PrepareLocalPacket ( void )
+{
+    MoveType * pkt;
+
+    wami(8);
+
+    pkt=(MoveType *)NextLocalCommand();
+
+    pkt->time=controlupdatetime;
+
+    if (networkgame==false) // Whether it is a modem game or not we do this
+    {
+        AddClientPacket (pkt, consoleplayer);
+        if (modemgame==false)
+        {
+            ServerCommandStatus ( controlupdatetime ) = cs_ready;
+        }
+    }
+
+    if (modemgame==true)
+        SendPacket (pkt, server);
+
+#if (DEVELOPMENT == 1)
+//   ComError("packet sent: realtime=%ld time=%ld type=%ld dest=%ld\n",GetTicCount(),pkt->time,pkt->type,server);
+#endif
+
+    controlupdatetime+=controldivisor;
+    waminot();
+}
+
+
+
+//****************************************************************************
+//
+// GetPacketSize ()
+//
+//****************************************************************************
+
+int GetPacketSize (void * pkt)
+{
+    int size;
+
+    switch (((MoveType *)pkt)->type)
+    {
+    case COM_DELTA:
+        size=sizeof(MoveType);
+        break;
+    case COM_DELTANULL:
+        size=sizeof(NullMoveType);
+        break;
+    case COM_REQUEST:
+        size=sizeof(COM_RequestType);
+        break;
+    case COM_FIXUP:
+        size=sizeof(COM_FixupType);
+        break;
+    case COM_TEXT:
+        size=sizeof(COM_TextType);
+        break;
+    case COM_PAUSE:
+        size=sizeof(COM_PauseType);
+        break;
+    case COM_QUIT:
+        size=sizeof(COM_QuitType);
+        break;
+    case COM_EXIT:
+        size=sizeof(COM_ExitType);
+        break;
+    case COM_REMRID:
+        size=sizeof(COM_RemoteRidiculeType);
+        break;
+    case COM_RESPAWN:
+        size=sizeof(COM_RespawnType);
+        break;
+    case COM_UNPAUSE:
+        size=sizeof(COM_UnPauseType);
+        break;
+    case COM_SERVER:
+        size=sizeof(COM_ServerHeaderType);
+        size-=sizeof(byte);
+        break;
+    case COM_GAMEDESC:
+        size=sizeof(COM_GamePlayerType);
+        break;
+    case COM_GAMEEND:
+        size=sizeof(COM_GameEndType);
+        break;
+    case COM_GAMEPLAY:
+        size=DUMMYPACKETSIZE;
+        break;
+    case COM_GAMEACK:
+        size=sizeof(COM_GameAckType);
+        break;
+    case COM_GAMEMASTER:
+        size=sizeof(COM_GameMasterType);
+        break;
+    case COM_ENDGAME:
+        size=sizeof(COM_EndGameType);
+        break;
+    case COM_SYNCTIME:
+        size=sizeof(COM_SyncType);
+        break;
+#if (SYNCCHECK == 1)
+    case COM_SYNCCHECK:
+        size=sizeof(COM_CheckSyncType);
+        break;
+#endif
+    case COM_SOUNDANDDELTA:
+        size=sizeof(MoveType)+sizeof(COM_SoundType);
+        break;
+    default:
+        Error("Unhandled packet type in GetPacketSize type=%d",((MoveType *)pkt)->type);
+        break;
+    }
+
+    return size;
+}
+
+//****************************************************************************
+//
+// GetTypeSize ()
+//
+//****************************************************************************
+
+int GetTypeSize (int type)
+{
+    byte pkt[2];
+
+    pkt[0]=(byte)type;
+    return ( GetPacketSize(&(pkt[0])) );
+}
+
+//****************************************************************************
+//
+// GetServerPacketSize ()
+//
+//****************************************************************************
+
+int GetServerPacketSize (void * pkt)
+{
+    int i;
+    byte * ptr;
+    COM_ServerHeaderType * serverpkt;
+
+    serverpkt=(COM_ServerHeaderType *)pkt;
+    if (serverpkt->type==COM_SERVER)
+    {
+        ptr=&serverpkt->data;
+
+        for (i=0; i<serverpkt->numpackets; i++)
+        {
+            ptr+=GetPacketSize(ptr);
+        }
+        return ((byte *)ptr-(byte *)pkt);
+    }
+    else
+        return GetPacketSize(pkt);
+}
+
+//****************************************************************************
+//
+// SendPacket ()
+//
+//****************************************************************************
+
+void SendPacket (void * pkt, int dest)
+{
+    if ((networkgame==false) && (PlayerStatus[dest]!=player_ingame))
+        return;
+    if ((IsServer==true) && (dest==server) && (standalone==false)) // must be client on top of server
+        ProcessPacket(pkt,dest);
+    else if ((IsServer==false) && (dest!=server) && (standalone==false)) // We shouldn't be sending as client to anyone else
+        ComError("SendPacket:Problems\n");
+    else
+        WritePacket(pkt,GetPacketSize(pkt),dest);
+#if (DEVELOPMENT == 1)
+//   ComError( "SendPacket: time=%ld dest=%ld\n",((MoveType *)pkt)->time,dest);
+#endif
+}
+
+//****************************************************************************
+//
+// ResetCurrentCommand ()
+//
+//****************************************************************************
+
+void ResetCurrentCommand ( void )
+{
+    ServerCommandStatus(oldpolltime)=cs_notarrived;
+}
+
+//****************************************************************************
+//
+// BroadcastServerPacket ()
+//
+//****************************************************************************
+
+void BroadcastServerPacket (void * pkt, int size)
+{
+    int i;
+
+
+    for (i=0; i<numplayers; i++)
+    {
+        if (PlayerStatus[i]!=player_ingame)
+            continue;
+//      if ((standalone==false) && (i==consoleplayer))
+//         ProcessPacket(pkt,i);
+//      else
+        WritePacket((byte *)pkt,size,i);
+    }
+}
+
+
+//****************************************************************************
+//
+// ResendLocalPackets ()
+//
+//****************************************************************************
+
+void ResendLocalPackets (int time, int dest, int numpackets)
+{
+    int cmd;
+    MoveType * pkt;
+
+    cmd = CommandAddress(time);
+
+#if 0
+    if (networkgame==false)
+    {
+        int nump;
+        nump=controlupdatetime-time;
+        if (nump>numpackets)
+            numpackets=nump;
+    }
+#endif
+
+    if (controlupdatetime<=time)
+        return;
+
+    pkt = (MoveType *)LocalCommand(cmd);
+
+    if (pkt->time!=time)
+    {
+        Error( "CLIENT: Could not find packet to resend\ntime=%d packettime=%d controlupdatetime=%d\n",
+               time, pkt->time, controlupdatetime);
+    }
+    else
+    {
+        byte * tempbuf;
+        byte * tempptr;
+        byte * tempstart;
+        COM_FixupType * fixup;
+        int i;
+        int starti;
+        int size;
+        boolean done;
+
+        // allocate some space
+
+        tempbuf=SafeMalloc(MAXCOMBUFFERSIZE);
+
+        fixup=(COM_FixupType *)tempbuf;
+
+        fixup->type=COM_FIXUP;
+        tempstart=&(fixup->data);
+
+        done=false;
+        i=0;
+        while (done==false)
+        {
+            tempptr=tempstart;
+            starti=i;
+            fixup->time=( (MoveType *)LocalCommand(cmd) )->time;
+            for (; i<numpackets; i++)
+            {
+                pkt = (MoveType *)LocalCommand(cmd);
+                size=GetPacketSize(pkt);
+
+                if (((tempptr+size)-tempbuf)>MAXCOMBUFFERSIZE)
+                {
+                    break;
+                }
+                memcpy(tempptr,pkt,size);
+                tempptr+=size;
+                cmd = (cmd + controldivisor) & (MAXCMDS-1);
+            }
+            fixup->numpackets=i-starti;
+            WritePacket(tempbuf,tempptr-tempbuf,dest);
+            if (i==numpackets)
+                done=true;
+        }
+
+        SafeFree(tempbuf);
+    }
+}
+
+//****************************************************************************
+//
+// ResendServerPackets ()
+//
+//****************************************************************************
+
+void ResendServerPackets (int time, int dest, int numpackets)
+{
+    int cmd;
+    COM_ServerHeaderType * serverpkt;
+
+
+    cmd = CommandAddress(time);
+
+    if (serverupdatetime<=time)
+        return;
+
+    serverpkt = (COM_ServerHeaderType *)ServerCommand(cmd);
+
+    if (serverpkt->time!=time)
+    {
+        Error( "SERVER: Could not find packet to resend\ntime=%d packettime=%d serverupdatetime=%d\n",
+               time, serverpkt->time,serverupdatetime);
+    }
+    else
+    {
+        byte * tempbuf;
+        byte * tempptr;
+        byte * tempstart;
+        COM_FixupType * fixup;
+        int i;
+        int starti;
+        int size;
+        boolean done;
+
+        // allocate some space
+
+        tempbuf=SafeMalloc(MAXCOMBUFFERSIZE);
+
+        fixup=(COM_FixupType *)tempbuf;
+
+        fixup->type=COM_FIXUP;
+        tempstart=&(fixup->data);
+
+        done=false;
+        i=0;
+        while (done==false)
+        {
+            tempptr=tempstart;
+            starti=i;
+            fixup->time=( (MoveType *)ServerCommand(cmd) )->time;
+            for (; i<numpackets; i++)
+            {
+                serverpkt = (COM_ServerHeaderType *)ServerCommand(cmd);
+                size=GetServerPacketSize(serverpkt);
+
+                if (((tempptr+size)-tempbuf)>MAXCOMBUFFERSIZE)
+                {
+                    break;
+                }
+                memcpy(tempptr,serverpkt,size);
+                tempptr+=size;
+                cmd = (cmd + controldivisor) & (MAXCMDS-1);
+            }
+            fixup->numpackets=i-starti;
+            WritePacket(tempbuf,tempptr-tempbuf,dest);
+            if (i==numpackets)
+                done=true;
+        }
+
+        SafeFree(tempbuf);
+    }
+}
+
+
+//****************************************************************************
+//
+// ResendPacket (incoming packet, whoever requested it)
+//
+//****************************************************************************
+
+void ResendPacket (void * pkt, int dest)
+{
+    int time;
+    COM_RequestType * request;
+
+    if ((networkgame==false) && (PlayerStatus[dest]!=player_ingame))
+        return;
+
+    request=(COM_RequestType * )pkt;
+    time=request->time;
+
+    ComError( "RESEND request received at %d\n packet time=%d dest=%d numpackets=%d\n",
+              GetTicCount(), time, dest, request->numpackets);
+
+    if (IsServer==true)
+    {
+        if ((dest==server) && (standalone==false))
+            Error("Trying to resend packets to client on top of server\n");
+        ComError( "RESEND SERVER serverupdatetime=%d\n",serverupdatetime);
+        if (IsServerCommandReady ( time ) == true)
+            ResendServerPackets(time,dest,request->numpackets);
+        else
+            ComError( "RESEND SERVER time=%d is not ready\n",time);
+    }
+    else
+    {
+        ResendLocalPackets(time,dest,request->numpackets);
+    }
+}
+
+//****************************************************************************
+//
+// FixupPacket ()
+//
+//****************************************************************************
+
+void FixupPacket (void * pkt, int src)
+{
+    COM_FixupType * fix;
+    int i;
+    int time;
+    byte * ptr;
+
+    fix=(COM_FixupType *)pkt;
+
+    ComError( "Fixup received at %d, time=%d numpackets=%d\n", GetTicCount(), fix->time, fix->numpackets);
+#if 0
+    if (networkgame==false)
+        FixingPackets=false;
+#endif
+    time=fix->time;
+    ptr=&(fix->data);
+
+    for (i=0; i<fix->numpackets; i++,time+=controldivisor)
+    {
+        if (time == (LastCommandTime[src]+controldivisor))
+            LastCommandTime[src]=time;
+
+        if (IsServer==true)
+        {
+            if (ClientCommandStatus(src, time)!=cs_fixing)
+            {
+                ComError("Server Received fixup with no bad packet time=%d from %d\n",time,src);
+            }
+            else
+            {
+                AddSubPacket(ptr, src);
+            }
+            ptr+=GetPacketSize(ptr);
+        }
+        else
+        {
+            if (ServerCommandStatus(time)!=cs_fixing)
+            {
+                ComError("Client Received fixup with no bad packet time=%d from %d\n",time,src);
+            }
+            else
+            {
+                if (networkgame==true)
+                {
+                    AddServerSubPacket( (COM_ServerHeaderType *)ptr );
+                }
+                else
+                {
+                    AddModemSubPacket(ptr);
+                }
+            }
+            ptr+=GetServerPacketSize(ptr);
+        }
+    }
+}
+
+#if (SYNCCHECK == 1)
+//****************************************************************************
+//
+// CheckForSyncCheck
+//
+//****************************************************************************
+
+void CheckForSyncCheck ( void )
+{
+    int i;
+
+
+    if (modemgame==true)
+    {
+        if (oldpolltime==lastsynccheck)
+        {
+            for (i=0; i<numplayers; i++)
+            {
+                PlayerSync[i].x=PLAYER[i]->x;
+                PlayerSync[i].y=PLAYER[i]->y;
+                PlayerSync[i].z=PLAYER[i]->z;
+                PlayerSync[i].angle=PLAYER[i]->angle;
+            }
+            PlayerSync[0].randomindex=GetRNGindex();
+            PlayerSync[0].synctime=lastsynccheck;
+            SendSyncCheckPacket();
+            lastsynccheck+=CHECKSYNCTIME;
+        }
+        if (oldpolltime>lastsynccheck)
+        {
+            Error("Missed a player sync check time=%d\n",oldpolltime);
+        }
+    }
+}
+#endif
+
+//****************************************************************************
+//
+// ProcessSyncTimePacket
+//
+//****************************************************************************
+
+void ProcessSyncTimePacket (void * pkt)
+{
+    COM_SyncType * sync;
+
+    sync=(COM_SyncType *)pkt;
+    ISR_SetTime(sync->synctime);
+}
+
+#if (SYNCCHECK == 1)
+//****************************************************************************
+//
+// ProcessSyncCheckPacket
+//
+//****************************************************************************
+
+void ProcessSyncCheckPacket (void * pkt, int src)
+{
+    COM_CheckSyncType * sync;
+
+    sync=(COM_CheckSyncType *)pkt;
+//   SoftError("Sync packet time=%ld\n",sync->synctime);
+    if (sync->synctime!=PlayerSync[0].synctime)
+    {
+        SoftError("Old sync packet received\n");
+        return;
+    }
+    if (sync->randomindex!=PlayerSync[0].randomindex)
+    {
+        Error("Player %d is unsynced localindex=%d remoteindex=%d\n"
+              "Unsynced Player x=%x y=%x a=%d z=%d name=%s\n",
+              src, PlayerSync[0].randomindex, sync->randomindex,
+              PlayerSync[src].x, PlayerSync[src].y, PlayerSync[src].angle,
+              PlayerSync[src].z,PLAYERSTATE[src].codename);
+    }
+    if (sync->x!=PlayerSync[src].x)
+    {
+        Error("Player %d is unsynced local x=%d remote x=%d\n"
+              "Unsynced Player x=%x y=%x a=%d z=%d name=%s\n",
+              src,PlayerSync[src].x,sync->x,
+              PlayerSync[src].x, PlayerSync[src].y, PlayerSync[src].angle,
+              PlayerSync[src].z,PLAYERSTATE[src].codename);
+    }
+    if (sync->y!=PlayerSync[src].y)
+    {
+        Error("Player %d is unsynced local y=%d remote y=%d\n"
+              "Unsynced Player x=%x y=%x a=%d z=%d name=%s\n",
+              src,PlayerSync[src].y,sync->y,
+              PlayerSync[src].x, PlayerSync[src].y, PlayerSync[src].angle,
+              PlayerSync[src].z,PLAYERSTATE[src].codename);
+    }
+    if (sync->z!=PlayerSync[src].z)
+    {
+        Error("Player %d is unsynced local z=%d remote z=%d\n"
+              "Unsynced Player x=%x y=%x a=%d z=%d name=%s\n",
+              src,PlayerSync[src].z,sync->z,
+              PlayerSync[src].x, PlayerSync[src].y, PlayerSync[src].angle,
+              PlayerSync[src].z,PLAYERSTATE[src].codename);
+    }
+    if (sync->angle!=PlayerSync[src].angle)
+    {
+        Error("Player %d is unsynced local angle=%d remote angle=%d\n"
+              "Unsynced Player x=%x y=%x a=%d z=%d name=%s\n",
+              src,PlayerSync[src].angle,sync->angle,
+              PlayerSync[src].x, PlayerSync[src].y, PlayerSync[src].angle,
+              PlayerSync[src].z,PLAYERSTATE[src].codename);
+    }
+}
+
+//****************************************************************************
+//
+// SendSyncCheckPacket
+//
+//****************************************************************************
+
+void SendSyncCheckPacket ( void )
+{
+    ((COM_CheckSyncType *)NextLocalCommand())->type=COM_SYNCCHECK;
+    ((COM_CheckSyncType *)NextLocalCommand())->synctime=PlayerSync[0].synctime;
+    ((COM_CheckSyncType *)NextLocalCommand())->x=PlayerSync[consoleplayer].x;
+    ((COM_CheckSyncType *)NextLocalCommand())->y=PlayerSync[consoleplayer].y;
+    ((COM_CheckSyncType *)NextLocalCommand())->z=PlayerSync[consoleplayer].z;
+    ((COM_CheckSyncType *)NextLocalCommand())->angle=PlayerSync[consoleplayer].angle;
+    ((COM_CheckSyncType *)NextLocalCommand())->randomindex=PlayerSync[0].randomindex;
+
+    PrepareLocalPacket();
+}
+#endif
+
+#if 0
+
+//****************************************************************************
+//
+// CheckForSyncTime
+//
+//****************************************************************************
+
+void CheckForSyncTime ( void )
+{
+    if ((modemgame==true) && (networkgame==false) && (consoleplayer==0))
+    {
+        if (controlupdatetime>=syncservertime)
+        {
+            SendSyncTimePacket();
+            syncservertime+=MODEMSYNCSERVERTIME;
+        }
+    }
+}
+#endif
+
+#if 0
+//****************************************************************************
+//
+// SendSyncTimePacket
+//
+//****************************************************************************
+
+void SendSyncTimePacket ( void )
+{
+    int i;
+    COM_SyncType sync;
+
+    return;
+
+    sync.type=COM_SYNCTIME;
+
+    if (networkgame==true)
+    {
+        for (i=0; i<numplayers; i++)
+        {
+            if ((PlayerStatus[i]!=player_ingame) || ( (i==consoleplayer) && (standalone==false) ) )
+                continue;
+            sync.synctime=GetTicCount()+GetTransitTime(i);
+            WritePacket ( &sync.type, GetPacketSize(&sync.type), i);
+        }
+    }
+    else
+    {
+        if (PlayerStatus[server]==player_ingame)
+        {
+            sync.synctime=GetTicCount()+GetTransitTime(server);
+            WritePacket ( &sync.type, GetPacketSize(&sync.type), server);
+        }
+    }
+}
+#endif
+
+//****************************************************************************
+//
+// ProcessSoundAndDeltaPacket
+//
+//****************************************************************************
+
+void ProcessSoundAndDeltaPacket (void * pkt, int src)
+{
+    MoveType * packet;
+    COM_SoundType * sndpkt;
+    byte oldtype;
+
+    packet = (MoveType *)pkt;
+
+    // Trick packet into being a normal delta packet
+
+    oldtype=packet->type;
+    packet->type=COM_DELTA;
+    AddClientPacket (pkt,src);
+    packet->type=oldtype;
+
+    // Don't process sound if it is from us
+    if (src==consoleplayer)
+        return;
+
+    sndpkt = (COM_SoundType *) (packet->Sounddata);
+
+    if (sndpkt->type==COM_SOUND_START_TRANSMISSION)
+    {
+        SD_StartIncomingSound ();
+    }
+    if (sndpkt->type==COM_SOUND_END_TRANSMISSION)
+    {
+        SD_StopIncomingSound();
+    }
+    else
+    {
+        SD_UpdateIncomingSound (&(sndpkt->data[0]), COM_SOUND_BUFFERSIZE);
+    }
+}
+//****************************************************************************
+//
+// SyncToServer
+//
+//****************************************************************************
+#define NETWORKTIMEAHEADOFSERVER (1)
+#define MODEMTIMEAHEADOFSERVER (2)
+void SyncToServer( void )
+{
+    int diff;
+
+    if ((networkgame==false) && (consoleplayer==0))
+        return;
+    if (IsServer==true)
+        return;
+//   if (networkgame==true)
+//      {
+//      diff = (GetTicCount()-controldivisor-LastCommandTime[0])/controldivisor;
+//      SoftError("diff=%ld\n",diff);
+//      if (abs(diff)>1)
+//         ISR_SetTime(GetTicCount()-diff);
+#if 0
+    diff = controlupdatetime-LastCommandTime[0];
+    if (diff>3)
+    {
+        ISR_SetTime(GetTicCount()-1);
+    }
+    else if (diff<-3)
+    {
+        ISR_SetTime(GetTicCount()+1);
+    }
+#endif
+//      }
+//   else
+//      {
+    diff = (GetTicCount()-controldivisor-LastCommandTime[server])/controldivisor;
+    if (abs(diff)>0)
+        ISR_SetTime(GetTicCount()-diff);
+//      }
+}
+
+//****************************************************************************
+//
+// ProcessPacket
+//
+//****************************************************************************
+
+void ProcessPacket (void * pkt, int src)
+{
+    switch (((MoveType *)pkt)->type)
+    {
+    case COM_DELTA:
+    case COM_DELTANULL:
+    case COM_TEXT:
+    case COM_PAUSE:
+    case COM_QUIT:
+    case COM_EXIT:
+    case COM_REMRID:
+    case COM_RESPAWN:
+    case COM_UNPAUSE:
+    case COM_ENDGAME:
+#if (SYNCCHECK == 1)
+    case COM_SYNCCHECK:
+#endif
+//         if (FixingPackets==false)
+        AddPacket(pkt,src);
+        break;
+    case COM_SOUNDANDDELTA:
+        if (remoteridicule == false )
+        {
+            ((MoveType *)pkt)->type = COM_DELTA;
+        }
+        AddPacket(pkt,src);
+        break;
+    case COM_SERVER:
+        AddServerPacket(pkt,src);
+        break;
+
+    case COM_REQUEST:
+        ResendPacket(pkt, src);
+        break;
+
+    case COM_FIXUP:
+        FixupPacket(pkt, src);
+        break;
+
+    case COM_SYNCTIME:
+        ProcessSyncTimePacket(pkt);
+        break;
+
+    case COM_GAMEEND:
+    case COM_GAMEDESC:
+    case COM_GAMEACK:
+    case COM_GAMEMASTER:
+        if (standalone==true)
+            restartgame=true;
+        break;
+
+    case COM_START:
+        break;
+
+    default:
+        Error("ProcessPacket: Unknown packet type=%d\n",((MoveType *)pkt)->type);
+    }
+}
+
+
+//****************************************************************************
+//
+// AddServerSubPacket
+//
+//****************************************************************************
+
+void AddServerSubPacket(COM_ServerHeaderType * serverpkt)
+{
+    byte * pkt;
+    int i;
+
+    ServerCommandStatus(serverpkt->time)=cs_ready;
+
+    pkt=&serverpkt->data;
+    for (i=0; i<serverpkt->numpackets; i++)
+    {
+        AddClientPacket(pkt,i);
+        pkt+=GetPacketSize(pkt);
+    }
+}
+
+//****************************************************************************
+//
+// AddModemSubPacket
+//
+//****************************************************************************
+
+void AddModemSubPacket(void * incoming)
+{
+    MoveType * pkt;
+
+    pkt=(MoveType *)incoming;
+    ServerCommandStatus(pkt->time)=cs_ready;
+
+    AddClientPacket(incoming,server);
+}
+
+//****************************************************************************
+//
+// AddServerPacket
+//
+//****************************************************************************
+
+void AddServerPacket(void * pkt, int src)
+{
+    COM_ServerHeaderType * serverpkt;
+
+    // The server uses the client's lgts for communicating
+
+    // Last good time can be set even for the client/server combo
+
+    if (standalone==true)
+    {
+        Error("standalone should not be here\n");
+    }
+
+    if (src!=server)
+    {
+        Error("Received server packet from non-server src=%d\n",src);
+    }
+
+    serverpkt=(COM_ServerHeaderType *)pkt;
+
+//   if (networkgame==false)
+//      SyncToServer(serverpkt->time);
+
+    LastCommandTime[src]+=controldivisor;
+
+    if (serverpkt->time != LastCommandTime[src])
+    {
+        int numpackets;
+
+        numpackets=serverpkt->time-LastCommandTime[src];
+        if (ServerCommandStatus(LastCommandTime[src])!=cs_fixing)
+        {
+            RequestPacket ( LastCommandTime[src], src, numpackets );
+
+            ComError("AddServerPacket: Request packet time=%d lct=%d numpackets=%d\n",
+                     serverpkt->time, LastCommandTime[src], numpackets
+                    );
+        }
+
+        LastCommandTime[src]+=numpackets;
+    }
+
+    AddServerSubPacket( serverpkt );
+}
+
+//****************************************************************************
+//
+// AddClientPacket
+//
+//****************************************************************************
+
+void AddClientPacket (void * pkt, int src)
+{
+    int size;
+    MoveType * packet;
+
+    packet=(MoveType *)pkt;
+
+    switch (packet->type)
+    {
+    case COM_DELTA:
+    case COM_DELTANULL:
+    case COM_TEXT:
+    case COM_REMRID:
+    case COM_PAUSE:
+    case COM_QUIT:
+    case COM_EXIT:
+    case COM_RESPAWN:
+    case COM_UNPAUSE:
+#if (SYNCCHECK == 1)
+    case COM_SYNCCHECK:
+#endif
+    case COM_ENDGAME:
+        size=GetPacketSize(packet);
+        memcpy(PlayerCommand(src,CommandAddress(packet->time)),packet,size);
+        break;
+    case COM_SOUNDANDDELTA:
+        ProcessSoundAndDeltaPacket(packet, src);
+        break;
+    default:
+        Error("AddClientPacket: Unknown packet type = %d\n",packet->type);
+    }
+}
+
+//****************************************************************************
+//
+// AddSubPacket
+//
+//****************************************************************************
+
+void AddSubPacket (void * pkt, int src)
+{
+    MoveType * packet;
+
+    if (networkgame==false)
+        Error("Modem game should not be here in AddSubPacket\n");
+
+    packet = (MoveType *) pkt;
+
+    ClientCommandStatus(src, packet->time)=cs_ready;
+
+    memcpy (
+        ClientTimeCommand(src,packet->time),
+        pkt,
+        GetPacketSize(packet)
+    );
+}
+
+//****************************************************************************
+//
+// AddPacket
+//
+//****************************************************************************
+
+void AddPacket (void * pkt, int src)
+{
+    MoveType * packet;
+
+    // should only be called by server in network game
+    // in modem game we fall through the first condition
+    // all packets should be sequential
+
+    if ((IsServer==true) && (PlayerStatus[src]!=player_ingame))
+        return;
+    packet = (MoveType *) pkt;
+
+//   if ((networkgame==false) && (consoleplayer!=0))
+//      SyncToServer();
+
+    if (!((src==server) && (standalone==false) && (IsServer==true)))
+    {
+        LastCommandTime[src]+=controldivisor;
+
+        if (packet->time != LastCommandTime[src])
+        {
+            int numpackets;
+
+            numpackets=packet->time-LastCommandTime[src];
+            if ( ( (networkgame==false) &&
+                    (ServerCommandStatus(LastCommandTime[src])!=cs_fixing)
+                 )
+                    ||
+                    ( (networkgame==true) &&
+                      (ClientCommandStatus(src,LastCommandTime[src])!=cs_fixing)
+                    )
+               )
+            {
+                RequestPacket ( LastCommandTime[src], src, numpackets );
+
+                ComError("AddPacket: Request packet time=%d lct=%d numpackets=%d\n",
+                         packet->time, LastCommandTime[src], numpackets
+                        );
+            }
+
+            LastCommandTime[src]+=numpackets;
+        }
+    }
+
+    if (networkgame==true)
+    {
+        AddSubPacket ( packet, src );
+    }
+    else
+    {
+        AddModemSubPacket(packet);
+    }
+}
+
+
+//****************************************************************************
+//
+// RequestPacket ( int time, int dest )
+//
+//****************************************************************************
+
+void RequestPacket (int time, int dest, int numpackets)
+{
+    COM_RequestType request;
+    int i;
+
+
+#if (DEVELOPMENT == 1)
+    if (modemgame==false)
+        Error("Called Request Packet outside of modem game\n");
+#endif
+
+    request.type=COM_REQUEST;
+    request.time=time;
+    request.numpackets=numpackets/controldivisor;
+
+    if (IsServer==true)
+    {
+        if ((dest==server) && (standalone==false))
+        {
+            Error("Requesting packet from client on top of server\n");
+        }
+        if (PlayerStatus[dest]!=player_ingame)
+            return;
+        for (i=0; i<numpackets; i+=controldivisor)
+        {
+            ClientCommandStatus( dest, (time+i) ) = cs_fixing;
+        }
+    }
+    else
+    {
+        if ((networkgame==false) && (PlayerStatus[dest]!=player_ingame))
+            return;
+        for (i=0; i<numpackets; i+=controldivisor)
+        {
+            ServerCommandStatus( (time+i) ) = cs_fixing;
+        }
+    }
+//   if (networkgame==false)
+//      FixingPackets=true;
+
+    // send out the packet
+
+    WritePacket (&request, GetPacketSize(&request), dest);
+
+#if (DEVELOPMENT == 1)
+//   ComError( "BADPKT, request sent at %ld lgt=%ld dest=%ld\n",GetTicCount(),time,dest);
+#endif
+}
+
+//****************************************************************************
+//
+// IsServerCommandReady ()
+//
+//****************************************************************************
+boolean IsServerCommandReady ( int time )
+{
+
+    if (
+        (
+            (COM_ServerHeaderType *)
+            ServerCommand(CommandAddress (time) ) )->time==time)
+        return true;
+    else
+    {
+        return false;
+    }
+}
+
+//****************************************************************************
+//
+// AreClientsReady ()
+//
+//****************************************************************************
+boolean AreClientsReady ( void )
+{
+    int i;
+    int timeindex;
+    int status;
+
+    timeindex=CommandAddress(serverupdatetime);
+
+    for (i=0; i<numplayers; i++)
+    {
+        if (PlayerStatus[i]!=player_ingame)
+            continue;
+        status=ClientCommandStatus(i, serverupdatetime);
+        if (status==cs_notarrived)
+            return false;
+        else if (status==cs_fixing)
+        {
+//         RequestPacket ( serverupdatetime , i , controldivisor );
+            return false;
+        }
+        else if (((MoveType *)ClientCommand(i, timeindex))->time != serverupdatetime)
+            return false;
+    }
+    return true;
+}
+
+//****************************************************************************
+//
+// IsPlayerCommandReady ()
+//
+//****************************************************************************
+boolean IsPlayerCommandReady (int num, int time)
+{
+    MoveType * cmd;
+
+    cmd=(MoveType *)PlayerCommand(num,CommandAddress(time));
+
+    if (cmd->time==time)
+        return true;
+    else
+        return false;
+}
+
+//****************************************************************************
+//
+// ResetClientCommands ()
+//
+//****************************************************************************
+void ResetClientCommands ( int player )
+{
+    int j;
+
+    for (j=0; j<MAXCMDS; j++)
+    {
+        memset(ClientCommand(player,j),COM_DELTA,GamePacketSize());
+    }
+}
+
+//****************************************************************************
+//
+// SendFullServerPacket ()
+//
+//****************************************************************************
+void SendFullServerPacket ( void )
+{
+    int i;
+    int size;
+    byte * pkt;
+    COM_ServerHeaderType * spkt;
+    int timeindex;
+    int playerstatus[MAXPLAYERS];
+
+    timeindex=CommandAddress(serverupdatetime);
+
+    spkt=(COM_ServerHeaderType *)ServerCommand(timeindex);
+
+    pkt=&spkt->data;
+    spkt->time=serverupdatetime;
+    spkt->type=COM_SERVER;
+    spkt->numpackets=numplayers;
+
+
+    memset(playerstatus,-1,sizeof(playerstatus));
+    for (i=0; i<numplayers; i++)
+    {
+        size=GetPacketSize(ClientCommand(i,timeindex));
+        if (((MoveType *)ClientCommand(i,timeindex))->type == COM_QUIT)
+        {
+            playerstatus[i]=player_quitgame;
+        }
+        if (((MoveType *)ClientCommand(i,timeindex))->type == COM_ENDGAME)
+        {
+            playerstatus[i]=player_leftgame;
+        }
+        memcpy(pkt,
+               ClientCommand(i,timeindex),
+               size
+              );
+        pkt+=size;
+        ClientCommandNumberStatus(i,timeindex)=cs_notarrived;
+    }
+    BroadcastServerPacket((void *)spkt,(pkt-(byte *)spkt));
+    serverupdatetime+=controldivisor;
+
+    for (i=0; i<numplayers; i++)
+    {
+        if (playerstatus[i]!=-1)
+        {
+            if ((standalone==false) && (consoleplayer==i))
+            {
+                UpdateServer=false;
+            }
+            else
+            {
+                ResetClientCommands(i);
+                PlayerStatus[i]=playerstatus[i];
+            }
+        }
+    }
+}
+
+
+
+//****************************************************************************
+//
+// ProcessServer ()
+//
+//****************************************************************************
+
+void ProcessServer ( void )
+{
+    boolean done;
+    boolean exit;
+    int i;
+    int time;
+    int quittime;
+
+    if (InProcessServer==true)
+        return;
+
+    InProcessServer=true;
+
+    if (GetTicCount()<serverupdatetime)
+        goto exitProcessServer;
+
+    time=GetTicCount();
+    quittime=GetTicCount()+SERVERTIMEOUT;
+    exit=false;
+
+    while (time>=serverupdatetime)
+    {
+        int savetime;
+
+        savetime=GetTicCount()+NETWORKTIMEOUT;
+        done = false;
+        while (done == false)
+        {
+            if (standalone==true)
+                AbortCheck("GameServer aborted\n");
+
+            done = AreClientsReady ();
+
+            if ( (standalone==false) && (serverupdatetime>=(controlupdatetime-controldivisor)) && (done==false) )
+                break;
+
+            CheckForPacket ();
+
+            if (standalone==false)
+                UpdateClientControls();
+
+            if (restartgame==true)
+                break;
+            if (GetTicCount()>savetime)
+            {
+                for (i=0; i<numplayers; i++)
+                {
+                    int val;
+
+                    val=ClientCommandStatus(i, serverupdatetime);
+                    if ((val!=cs_ready) && (PlayerStatus[i]==player_ingame))
+                    {
+                        SoftError("Server timeout\n");
+                        RequestPacket(serverupdatetime, i, controldivisor);
+                    }
+                }
+                savetime=GetTicCount()+NETWORKTIMEOUT;
+            }
+//         if (GetTicCount()>quittime)
+//            {
+//            Error("Server aborting after %ld seconds\n",SERVERTIMEOUT/VBLCOUNTER);
+//            }
+            if ((standalone==false) && (done==false))
+            {
+                exit=true;
+                done=true;
+            }
+        }
+        if (exit==true)
+            break;
+        if ( (serverupdatetime>=(controlupdatetime-controldivisor)) && (standalone==false))
+            break;
+        if (restartgame==true)
+            break;
+        SendFullServerPacket();
+#if 0
+        if (serverupdatetime>=syncservertime)
+        {
+            SendSyncTimePacket();
+            syncservertime+=NETSYNCSERVERTIME;
+        }
+#endif
+    }
+exitProcessServer:
+    InProcessServer=false;
+}
+
+
+//****************************************************************************
+//
+// SetupCheckForPacket()
+//
+//****************************************************************************
+int SetupCheckForPacket ( void )
+{
+    int retval=scfp_nodata;
+
+    if ((ReadPacket()==true) && (badpacket==0))
+    {
+        MoveType * pkt;
+
+        retval=scfp_data;
+        pkt=(MoveType *)&ROTTpacket[0];
+        if ((IsServer==true) && (standalone==true))
+        {
+            switch (pkt->type)
+            {
+            case COM_GAMEEND:
+                break;
+            case COM_GAMEDESC:
+                if (standalone==true)
+                    printf("Received GameDescription from player#%ld\n",(long int)rottcom->remotenode);
+                WritePacket(&ROTTpacket[0],GetPacketSize(pkt),0); // Send to player 0
+                break;
+            case COM_GAMEACK:
+                if (standalone==true)
+                    printf("Received GameAcknowledgement from player#%ld\n",(long int)rottcom->remotenode);
+                WritePacket(&ROTTpacket[0],GetPacketSize(pkt),0); // Send to player 0
+                break;
+            case COM_GAMEMASTER:
+                if (standalone==true)
+                    printf("Received GameMasterPacket from player#%ld\n",(long int)rottcom->remotenode);
+                BroadcastServerPacket(&ROTTpacket[0],GetPacketSize(pkt)); // Send to all
+                break;
+            case COM_GAMEPLAY:
+                if (standalone==true)
+                    printf("Received StartGamePacket from player#%ld\n",(long int)rottcom->remotenode);
+                BroadcastServerPacket(&ROTTpacket[0],GetPacketSize(pkt)); // Send to all
+                retval=scfp_done;
+                break;
+            default:
+                ComError("Server received unknown packet in Game preamble\n");
+                break;
+            }
+        }
+        else
+        {
+            switch (pkt->type)
+            {
+            case COM_GAMEPLAY:
+                retval=scfp_done;
+                break;
+            case COM_GAMEMASTER:
+                SetGameDescription(pkt);
+                retval=scfp_gameready;
+                break;
+            case COM_GAMEACK:
+                PlayersReady[((COM_GameAckType *)pkt)->player]=true;
+                break;
+            case COM_GAMEDESC:
+                GotPlayersDesc[((COM_GamePlayerType *)pkt)->player]=true;
+                SetPlayerDescription(pkt);
+                break;
+            }
+        }
+    }
+    return retval;
+}
+
+
+//****************************************************************************
+//
+// ServerLoop ()
+//
+//****************************************************************************
+void ServerLoop( void )
+{
+    boolean done;
+
+    while (1)
+    {
+        ShutdownClientControls();
+        restartgame=false;
+
+        done=false;
+        while (done==false)
+        {
+            AbortCheck("SetupGameServer aborted\n");
+
+            if (SetupCheckForPacket()==scfp_done)
+                done=true;
+        }
+        ComSetTime();
+        StartupClientControls();
+        while(1)
+        {
+            ProcessServer();
+#if (DEVELOPMENT == 1)
+            Z_CheckHeap();
+#endif
+            CalcTics();
+            if (restartgame==true)
+                break;
+        }
+    }
+}
+
+//****************************************************************************
+//
+// ProcessPlayerCommand()
+//
+//****************************************************************************
+void ProcessPlayerCommand( int player )
+{
+    MoveType * cmd;
+
+    cmd=(MoveType *)PlayerCommand(player,CommandAddress(oldpolltime));
+
+    if (cmd->type==COM_DELTA)
+    {
+        UpdatePlayerObj(player);
+    }
+    else if (cmd->type==COM_RESPAWN)
+    {
+        if (player==consoleplayer) // reset spawn state
+            respawnactive=false;
+        RespawnPlayerobj(PLAYER[player]);
+    }
+    else if (cmd->type==COM_ENDGAME)
+    {
+        playstate = ex_battledone;
+    }
+    else if (cmd->type==COM_QUIT)
+    {
+        if (player==consoleplayer)
+            QuitGame();
+        else
+        {
+            char str[50]="Player #";
+            char str2[10];
+
+            strcat(str,itoa(player+1,str2,10));
+            strcat(str,", ");
+            strcat(str,PLAYERSTATE[player].codename);
+            strcat(str," has left the game.");
+            AddMessage(str,MSG_REMOTE);
+            PlayerStatus[player]=player_quitgame;
+        }
+    }
+    else if (cmd->type==COM_EXIT)
+    {
+        QuitGame();
+    }
+    else if (cmd->type==COM_REMRID)
+    {
+        ProcessRemoteRidicule (cmd);
+    }
+    else if (cmd->type==COM_TEXT)
+    {
+        int who;
+
+        who = ( ( COM_TextType * )cmd )->towho;
+        if ( ( who == consoleplayer ) ||
+                ( who == MSG_DIRECTED_TO_ALL ) ||
+                ( ( who == MSG_DIRECTED_TO_TEAM ) &&
+                  ( BATTLE_Team[ player ] == BATTLE_Team[ consoleplayer ] ) ) )
+        {
+            char string[ 50 ];
+
+            strcpy( string, "\\N9" );
+            strcat( string, PLAYERSTATE[player].codename );
+            strcat( string, ":\\NF" );
+            strcat( string, ((COM_TextType *)cmd)->string );
+            SD_PlayPitchedSound ( SD_ENDBONUS1SND, 255, 1200 );
+
+            AddMessage( string, MSG_REMOTE );
+        }
+    }
+#if (SYNCCHECK == 1)
+    else if (cmd->type==COM_SYNCCHECK)
+    {
+        ProcessSyncCheckPacket(cmd, player);
+    }
+#endif
+    else if (cmd->type==COM_PAUSE)
+    {
+        MUSIC_Pause();
+        GamePaused=true;
+        pausedstartedticcount = oldpolltime;
+    }
+    else if (cmd->type==COM_UNPAUSE)
+    {
+        GamePaused=false;
+        MUSIC_Continue ();
+        if (RefreshPause == false)       // screen is blanked
+        {
+            ShutdownScreenSaver();
+            SetupScreen (true);
+            RefreshPause = true;
+        }
+    }
+}
+
+//****************************************************************************
+//
+// CheckUnPause ()
+//
+//****************************************************************************
+void CheckUnPause ( void )
+{
+    if (oldpolltime==nextupdatetime)
+    {
+        nextupdatetime=oldpolltime+controldivisor;
+        while (1)
+        {
+            if (ServerCommandStatus(oldpolltime)==cs_ready)
+            {
+                int j;
+
+                for (j=0; j<numplayers; j++)
+                {
+                    if (PlayerStatus[j]==player_ingame)
+                        ProcessPlayerCommand( j );
+                }
+                break;
+            }
+            else
+            {
+                UpdateClientControls();
+            }
+        }
+    }
+}
+
+
+//****************************************************************************
+//
+// ControlPlayerObj ()
+//
+//****************************************************************************
+void ControlPlayerObj (objtype * ob)
+{
+    playertype * pstate;
+    int num;
+    int savetime;
+//   boolean asked;
+
+//   if (GamePaused==true)
+//      return;
+
+    M_LINKSTATE(ob,pstate);
+
+    // get player number
+
+    num=ob->dirchoosetime;
+
+    memcpy (pstate->buttonheld, pstate->buttonstate, sizeof(pstate->buttonstate));
+
+    if (oldpolltime==nextupdatetime)
+    {
+        if (num==numplayers-1)
+            nextupdatetime=oldpolltime+controldivisor;
+        if (networkgame==true)
+            savetime=GetTicCount()+NETWORKTIMEOUT;
+        else
+            savetime=GetTicCount()+MODEMTIMEOUT;
+
+        if (PlayerStatus[num]!=player_ingame)
+            return;
+
+        //   asked=false;
+
+        // copy previous state of buttons
+
+
+        while (1)
+        {
+            if (ServerCommandStatus(oldpolltime)==cs_ready)
+            {
+                ProcessPlayerCommand (num);
+                if (demoplayback||demorecord) {
+                    SoftError("x=%4x y=%4x a=%4x time=%5d\n",player->x,player->y,player->angle,oldpolltime);
+                }
+                break;
+            }
+            //      else if ((ServerCommandStatus(oldpolltime)==cs_fixing) &&
+            //               (networkgame==false) &&
+            //               (asked==false)
+            //              )
+            //         {
+            //         asked=true;
+            //         RequestPacket(oldpolltime, server, controldivisor);
+            //         }
+            else
+            {
+                UpdateClientControls();
+            }
+
+            if (GetTicCount()>savetime)
+            {
+                SoftError("Client timeout oldpolltime=%d\n",oldpolltime);
+                if (IsServer==false)
+                    RequestPacket(oldpolltime, server, controldivisor);
+                if (networkgame==true)
+                    savetime=GetTicCount()+NETWORKTIMEOUT;
+                else
+                    savetime=GetTicCount()+MODEMTIMEOUT;
+            }
+        }
+    }
+
+    if (!(ob->flags&FL_DYING))
+    {
+        if (ob->flags&FL_PUSHED)
+        {
+            ob->flags&=~FL_PUSHED;
+#if 0
+            if (abs(ob->momentumx)>0)
+            {
+                if (abs(ob->momentumx+pstate->dmomx)>=abs(ob->momentumx))
+                {
+                    ob->momentumx += pstate->dmomx;
+                    ob->momentumy += pstate->dmomy;
+                }
+            }
+            else if (abs(ob->momentumy+pstate->dmomy)>=abs(ob->momentumy))
+            {
+                ob->momentumx += pstate->dmomx;
+                ob->momentumy += pstate->dmomy;
+            }
+#endif
+            if (abs(ob->momentumx+pstate->dmomx)>=abs(ob->momentumx))
+            {
+                ob->momentumx += pstate->dmomx;
+            }
+            if (abs(ob->momentumy+pstate->dmomy)>=abs(ob->momentumy))
+            {
+                ob->momentumy += pstate->dmomy;
+            }
+        }
+        else
+        {
+            ob->momentumx += pstate->dmomx;
+            ob->momentumy += pstate->dmomy;
+        }
+    }
+}
+
+//****************************************************************************
+//
+// MaxSpeedForCharacter ()
+//
+//****************************************************************************
+
+int MaxSpeedForCharacter(playertype*pstate)
+{
+    if (BATTLEMODE && (gamestate.BattleOptions.Speed == bo_fast_speed))
+    {
+        return( FASTSPEED );
+    }
+    else
+    {
+        if (pstate->buttonstate[bt_run])
+            return (characters[pstate->player].toprunspeed);
+        else
+            return (characters[pstate->player].topspeed);
+    }
+}
+
+//****************************************************************************
+//
+// UpdatePlayerObj ()
+//
+//****************************************************************************
+
+void UpdatePlayerObj ( int player )
+{
+    int i, buttonbits;
+    playertype * pstate;
+    MoveType * MoveCmd;
+
+    MoveCmd=(MoveType *)PlayerCommand(player,CommandAddress(oldpolltime));
+
+    pstate=&PLAYERSTATE[player];
+
+    buttonbits = MoveCmd->buttons;
+    for (i = 0; i < NUMTXBUTTONS; i++)
+    {
+        pstate->buttonstate[i] = buttonbits & 1;
+        buttonbits   >>= 1;
+    }
+
+    pstate->dmomx = (int)(MoveCmd->momx)<<1;
+    pstate->dmomy = (int)(MoveCmd->momy)<<1;
+    pstate->angle = MoveCmd->dangle;
+    pstate->angle <<= 11;
+    pstate->topspeed=MaxSpeedForCharacter(pstate);
+
+    if (demoplayback||demorecord) {
+        SoftError("  dmx=%4x dmy=%4x da=%4x time=%5d\n",pstate->dmomx,pstate->dmomy,pstate->angle>>11,oldpolltime);
+    }
+#if 0
+#if (DEVELOPMENT == 1)
+    if ((modemgame==true) || (demoplayback==true) || (demorecord==true))
+    {
+        ComError( "player#%2ld\n",player);
+        ComError( "momx = %6ld\n", PLAYER[player]->momentumx);
+        ComError( "momy = %6ld\n", PLAYER[player]->momentumy);
+        ComError( "   x = %6ld\n", PLAYER[player]->x);
+        ComError( "   y = %6ld\n", PLAYER[player]->y);
+        ComError( "   z = %6ld\n", PLAYER[player]->z);
+        ComError( "   a = %6ld\n", PLAYER[player]->angle);
+        if (pstate->buttonstate[bt_attack])
+            ComError( "FIRING\n");
+    }
+#endif
+#endif
+}
+
+
+//****************************************************************************
+//
+// SendPlayerDescription ()
+//
+//****************************************************************************
+
+void SendPlayerDescription( void )
+{
+    byte * temp;
+    COM_GamePlayerType * desc;
+    int length;
+
+    length=sizeof(COM_GamePlayerType);
+    temp=SafeMalloc(length);
+
+    memset(temp,0,length);
+
+    desc=(COM_GamePlayerType *)temp;
+    desc->type=(byte)COM_GAMEDESC;
+    desc->player=consoleplayer;
+    desc->violence=gamestate.violence;
+    desc->Version = gamestate.Version;
+    desc->Product = gamestate.Product;
+    desc->playerdescription.character=locplayerstate->player;
+    desc->playerdescription.uniformcolor=locplayerstate->uniformcolor;
+    strcpy(&(desc->playerdescription.codename[0]),
+           &locplayerstate->codename[0]);
+
+    WritePacket(temp,length,server);
+
+    SafeFree(temp);
+}
+
+//****************************************************************************
+//
+// SendGameDescription ()
+//
+//****************************************************************************
+
+void SendGameDescription( void )
+{
+    byte * temp;
+    COM_GameMasterType * desc;
+    int length;
+    int i;
+
+    length=sizeof(COM_GameMasterType);
+    temp=SafeMalloc(length);
+
+    memset(temp,0,length);
+
+    desc=(COM_GameMasterType *)temp;
+    desc->type=(byte)COM_GAMEMASTER;
+    desc->level=gamestate.mapon;
+    desc->mapcrc=GetMapCRC (gamestate.mapon);
+    desc->mode=gamestate.battlemode;
+    desc->violence=gamestate.violence;
+    desc->Version = gamestate.Version;
+    desc->Product = gamestate.Product;
+    desc->teamplay = gamestate.teamplay;
+    memcpy( &desc->SpecialsTimes, &gamestate.SpecialsTimes, sizeof( specials ) );
+    BATTLE_GetOptions( &( desc->options ) );
+    GetMapFileName( &(desc->battlefilename[0]) );
+    desc->randomseed=GetRNGindex ( );
+    gamestate.randomseed=desc->randomseed;
+    desc->ludicrousgibs=battlegibs;
+    ludicrousgibs=battlegibs;
+//   SetRNGindex ( gamestate.randomseed );
+    for (i=0; i<numplayers; i++)
+    {
+        if (gamestate.Product == ROTT_SHAREWARE)
+            PLAYERSTATE[i].player = 0;
+        desc->players[i].character    =PLAYERSTATE[i].player;
+        desc->players[i].uniformcolor =PLAYERSTATE[i].uniformcolor;
+        strcpy ( &(desc->players[i].codename[0]),&(PLAYERSTATE[i].codename[0]));
+    }
+
+    if (!networkgame)
+        AssignTeams();
+
+    if (IsServer==false)
+    {
+        WritePacket(temp,length,server);
+    }
+    else
+    {
+        BroadcastServerPacket(temp,length); // Send to all
+    }
+
+    SafeFree(temp);
+}
+
+//****************************************************************************
+//
+// SetGameDescription ()
+//
+//****************************************************************************
+
+void SetGameDescription( void * pkt )
+{
+    COM_GameMasterType * desc;
+    word localcrc;
+    int i;
+
+    desc=(COM_GameMasterType *)pkt;
+    gamestate.mapon=desc->level;
+    gamestate.battlemode=desc->mode;
+    gamestate.violence=desc->violence;
+    gamestate.Version = desc->Version;
+    gamestate.Product = desc->Product;
+    gamestate.teamplay = desc->teamplay;
+    memcpy( &gamestate.SpecialsTimes, &desc->SpecialsTimes, sizeof( specials ) );
+    BATTLE_SetOptions( &( desc->options ) );
+    gamestate.randomseed=desc->randomseed;
+    SetRNGindex ( gamestate.randomseed );
+    SetBattleMapFileName( &(desc->battlefilename[0]) );
+    localcrc=GetMapCRC (gamestate.mapon);
+    ludicrousgibs=desc->ludicrousgibs;
+    if (localcrc!=desc->mapcrc)
+        Error("You have different maps on your system\n");
+    for (i=0; i<numplayers; i++)
+    {
+        PLAYERSTATE[i].player=desc->players[i].character;
+        PLAYERSTATE[i].uniformcolor=desc->players[i].uniformcolor;
+        strcpy ( &(PLAYERSTATE[i].codename[0]),
+                 &(desc->players[i].codename[0])
+               );
+    }
+    AssignTeams();
+}
+
+//****************************************************************************
+//
+// SetPlayerDescription ()
+//
+//****************************************************************************
+
+void SetPlayerDescription( void * pkt )
+{
+    COM_GamePlayerType * desc;
+
+    desc=(COM_GamePlayerType *)pkt;
+    PLAYERSTATE[desc->player].player=desc->playerdescription.character;
+    PLAYERSTATE[desc->player].uniformcolor=desc->playerdescription.uniformcolor;
+    strcpy ( &(PLAYERSTATE[desc->player].codename[0]),
+             &(desc->playerdescription.codename[0])
+           );
+    if ( gamestate.Version != desc->Version )
+    {
+        Error("Player %s is using a different version of ROTT\n",PLAYERSTATE[desc->player].codename);
+//      gamestate.Version = desc->Version;
+    }
+
+    if ( gamestate.violence > desc->violence )
+    {
+        gamestate.violence = desc->violence;
+    }
+
+    if ( gamestate.Product > desc->Product )
+    {
+        gamestate.Product = desc->Product;
+    }
+}
+
+//****************************************************************************
+//
+// SendGameAck ()
+//
+//****************************************************************************
+
+void SendGameAck( void )
+{
+    byte * temp;
+    int length;
+    COM_GameAckType * desc;
+
+    length=sizeof(COM_GameAckType);
+    temp=SafeMalloc(length);
+    desc=(COM_GameAckType *)temp;
+    desc->type=COM_GAMEACK;
+    desc->player=consoleplayer;
+
+    WritePacket(temp,length,server);
+
+    SafeFree(temp);
+}
+
+//****************************************************************************
+//
+// SendGameStart ()
+//
+//****************************************************************************
+
+void SendGameStart( void )
+{
+    byte * temp;
+    int length;
+
+    length=DUMMYPACKETSIZE;
+    temp=SafeMalloc(length);
+    *(temp)=(byte)COM_GAMEPLAY;
+
+    if (IsServer==false)
+    {
+        WritePacket(temp,length,server);
+    }
+    else
+    {
+        BroadcastServerPacket(temp,length); // Send to all
+    }
+
+    SafeFree(temp);
+}
+
+//****************************************************************************
+//
+// SetupGamePlayer ()
+//
+//****************************************************************************
+void SetupGamePlayer ( void )
+{
+    int savetime;
+    boolean done;
+    boolean gameready;
+
+    savetime=GetTicCount();
+
+    done=false;
+    gameready=false;
+
+    while (done==false)
+    {
+        // Setup individual player
+        AbortCheck("SetupGamePlayer aborted\n");
+
+        // send Player Description
+        if (GetTicCount() >= savetime)
+        {
+            savetime=GetTicCount()+SETUPTIME;
+            if (gameready==false)
+                SendPlayerDescription();
+            else
+                SendGameAck();
+        }
+        switch (SetupCheckForPacket())
+        {
+        case scfp_done:
+            done=true;
+            break;
+        case scfp_gameready:
+            gameready=true;
+            break;
+        }
+    }
+    savetime=GetTicCount()+(VBLCOUNTER/2);
+
+    while (GetTicCount()<savetime)
+    {
+        SetupCheckForPacket ();
+    }
+}
+
+//****************************************************************************
+//
+// AllPlayersReady ()
+//
+//****************************************************************************
+boolean AllPlayersReady ( void )
+{
+    int i;
+
+    for (i=0; i<numplayers; i++)
+        if ((PlayersReady[i]==false) && (PlayerStatus[i]==player_ingame))
+            return false;
+
+    return true;
+}
+
+//****************************************************************************
+//
+// GotAllPlayerDescriptions ()
+//
+//****************************************************************************
+boolean GotAllPlayerDescriptions ( void )
+{
+    int i;
+
+    for (i=0; i<numplayers; i++)
+        if ((GotPlayersDesc[i]==false) && (PlayerStatus[i]==player_ingame))
+            return false;
+
+    return true;
+}
+
+//****************************************************************************
+//
+// SetupGameMaster ()
+//
+//****************************************************************************
+void SetupGameMaster ( void )
+{
+    int savetime;
+    boolean done;
+
+    memset(GotPlayersDesc,false,sizeof(GotPlayersDesc));
+    GotPlayersDesc[consoleplayer]=true;
+
+    memset(PlayersReady,false,sizeof(PlayersReady));
+    PlayersReady[consoleplayer]=true;
+
+    savetime=GetTicCount();
+
+    done=false;
+
+    InitializeRNG ();
+
+    while (done==false)
+    {
+        // Setup individual player
+
+        AbortCheck("SetupGameMaster aborted\n");
+
+        // send Game Description
+        if (GetTicCount() >= savetime)
+        {
+            savetime=GetTicCount()+SETUPTIME;
+            if (GotAllPlayerDescriptions()==true)
+                SendGameDescription();
+        }
+        if (AllPlayersReady ()==true)
+        {
+            SendGameStart();
+            SendGameStart();
+            done=true;
+        }
+        SetupCheckForPacket();
+    }
+    savetime=GetTicCount()+(VBLCOUNTER/2);
+
+    while (GetTicCount()<savetime)
+    {
+        SetupCheckForPacket ();
+    }
+}
+
+
+
+
+
+
+
+
+
+
+/*
+=============================================================================
+
+   DEMO CODE
+
+=============================================================================
+*/
+//****************************************************************************
+//
+// GetDemoFilename ()
+//
+//****************************************************************************
+
+void GetDemoFilename (int demonumber, char * filename)
+{
+    strcpy(filename,DATADIR "DEMO0_0.DMO\0");
+
+    filename[4 + strlen(DATADIR)] = (char)('0' + (byte)demonumber);
+    filename[6 + strlen(DATADIR)] = (char)('0' + (byte)gamestate.violence);
+    FixFilePath(filename);
+}
+//****************************************************************************
+//
+// DemoExists ()
+//
+//****************************************************************************
+
+boolean DemoExists (int demonumber)
+{
+    char demo[20 + sizeof(DATADIR)];
+
+    GetDemoFilename (demonumber, &demo[0]);
+    if (access (demo, F_OK) == 0)
+        return true;
+    else
+    {
+        /* Saves the users violence level, only do this once, otherwise
+           we might override the saved level with one already modified by us */
+        if (predemo_violence == -1)
+            predemo_violence = gamestate.violence;
+        /* The demos distributed with rott are all for a violence level of 3 */
+        gamestate.violence = 3;
+        GetDemoFilename (demonumber, &demo[0]);
+        if (access (demo, F_OK) == 0)
+            return true;
+        else
+            return false;
+    }
+}
+
+//****************************************************************************
+//
+// SaveDemo ()
+//
+//****************************************************************************
+
+void SaveDemo (int demonumber)
+{
+    char demo[20 + sizeof(DATADIR)];
+
+    RecordDemoCmd ();
+    GetDemoFilename (demonumber, &demo[0]);
+    SaveFile (demo, demobuffer, (demoptr-demobuffer));
+    FreeDemo();
+}
+
+//****************************************************************************
+//
+// LoadDemo ()
+//
+//****************************************************************************
+
+void LoadDemo (int demonumber)
+{
+    char demo[20 + sizeof(DATADIR)];
+    int size;
+
+    GetDemoFilename (demonumber, demo);
+    if (demobuffer!=NULL)
+        FreeDemo();
+    size = LoadFile (demo, (void **)&demobuffer);
+    playstate = ex_demoplayback;
+    demoptr = demobuffer;
+    lastdemoptr = (demoptr+size);
+    locplayerstate->player=0;
+    InitializeWeapons(locplayerstate);
+    ResetPlayerstate(locplayerstate);
+    InitCharacter();
+}
+
+//****************************************************************************
+//
+// RecordDemo ()
+//
+//****************************************************************************
+
+void RecordDemo ( void )
+{
+    DemoHeaderType * DemoHeader;
+    int level;
+
+    if (demobuffer!=NULL)
+        FreeDemo();
+    godmode=0;
+    demobuffer = SafeMalloc (DEMOBUFFSIZE);
+    demoptr = demobuffer;
+    lastdemoptr = demobuffer+DEMOBUFFSIZE;
+
+    // Save off level number
+
+    DemoHeader=(DemoHeaderType *)demoptr;
+    demoptr+=sizeof(gamestate);
+    memcpy(&(DemoHeader->demostate),&gamestate,sizeof(gamestate));
+    demorecord = true;
+    locplayerstate->player=0;
+    InitializeWeapons(locplayerstate);
+    ResetPlayerstate(locplayerstate);
+    level=gamestate.mapon;
+    InitCharacter();
+    gamestate.mapon=level;
+    SoftError(">>>>>>>>>>>>Start demo record\n");
+}
+
+//****************************************************************************
+//
+// SetupDemo ()
+//
+//****************************************************************************
+
+void SetupDemo ( void )
+{
+    DemoHeaderType * DemoHeader;
+
+    demoplayback = true;
+    godmode=0;
+
+    DemoHeader=(DemoHeaderType *)demoptr;
+    demoptr+=sizeof(gamestate);
+//   if (gamestate.violence!=DemoHeader->demostate.violence)
+//      Error ("This demo has a different difficulty level than your current settings\n");
+    memcpy(&gamestate,&(DemoHeader->demostate),sizeof(gamestate));
+    SoftError(">>>>>>>>>>>>Start demo playback\n");
+}
+
+//****************************************************************************
+//
+// FreeDemo ()
+//
+//****************************************************************************
+
+void FreeDemo ( void )
+{
+    demoplayback = false;
+    demorecord = false;
+    SafeFree (demobuffer);
+    demobuffer=NULL;
+}
+
+//****************************************************************************
+//
+// CheckForDemoDone ()
+//
+//****************************************************************************
+
+void CheckForDemoDone ( void )
+{
+    if ((demoplayback==true) && (demoptr >= lastdemoptr))
+    {
+        FreeDemo();
+        playstate = ex_demodone;
+    }
+}
+
+//****************************************************************************
+//
+// CheckForDemoOverflowed ()
+//
+//****************************************************************************
+
+void CheckForDemoOverflowed ( void )
+{
+    if (demoptr >= (lastdemoptr-sizeof(DemoType)))
+    {
+        playstate = ex_completed;     // demo is done
+        EndDemo();
+    }
+}
+
+//****************************************************************************
+//
+// RecordDemoCmd ()
+//
+//****************************************************************************
+
+void RecordDemoCmd (void)
+{
+    DemoType * dtime;
+
+    SoftError("Demo command recorded at %d\n",controlupdatetime);
+    dtime=(DemoType *)demoptr;
+    dtime->time = controlupdatetime;
+    dtime->momx = (controlbuf[0]>>1);
+    dtime->momy = (controlbuf[1]>>1);
+    dtime->dangle = controlbuf[2]>>11;
+    dtime->buttons = buttonbits;
+
+    demoptr+=sizeof(DemoType);
+
+    CheckForDemoOverflowed();
+}
+
+//****************************************************************************
+//
+// AddDemoCmd ()
+//
+//****************************************************************************
+
+void AddDemoCmd (void)
+{
+    DemoType * dtime;
+
+    //
+    // get info from demo buffer
+    //
+
+    SoftError("Demo command played at %d\n",controlupdatetime);
+    if (demoplayback==true)
+    {
+        dtime=(DemoType *)demoptr;
+        controlbuf[0]=dtime->momx<<1;
+        controlbuf[1]=dtime->momy<<1;
+        controlbuf[2]=dtime->dangle<<11;
+        buttonbits   =dtime->buttons;
+        demoptr+=sizeof(DemoType);
+    }
+}
+
+//****************************************************************************
+//
+// GetNextDemoTime ()
+//
+//****************************************************************************
+
+int GetNextDemoTime (void)
+{
+    DemoType * dtime;
+
+    CheckForDemoDone();
+    dtime=(DemoType *)demoptr;
+    if (demoplayback)
+        return dtime->time;
+    else
+        return -1;
+}
+
+//****************************************************************************
+//
+// UpdateDemoPlayback ()
+//
+//****************************************************************************
+
+void UpdateDemoPlayback (int time)
+{
+    if (demoplayback)
+    {
+        if (GetNextDemoTime()==time)
+            AddDemoCmd();
+    }
+}
+
+
+
+
+
--- /dev/null
+++ b/rott/rt_net.h
@@ -1,0 +1,331 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+//***************************************************************************
+//
+//   RT_NET.H - Network stuff
+//
+//***************************************************************************
+
+#ifndef _rt_net_public
+#define _rt_net_public
+
+#include "develop.h"
+#include "rottnet.h"
+#include "rt_actor.h"
+#include "rt_battl.h"
+#include "rt_playr.h"
+#include "rt_main.h"
+
+
+#define MAXCMDS  256
+
+#define COM_DELTA   1
+#define COM_REQUEST 2
+#define COM_FIXUP   3
+#define COM_TEXT    4
+#define COM_PAUSE   5
+#define COM_QUIT    6
+#define COM_SYNC    7
+#define COM_REMRID  8
+#define COM_RESPAWN 10
+#define COM_UNPAUSE 11
+#define COM_SERVER  12
+#define COM_START   13
+#define COM_GAMEDESC 15
+#define COM_GAMEPLAY 16
+#define COM_GAMEMASTER 17
+#define COM_GAMEACK 18
+#define COM_ENDGAME  19
+#define COM_SYNCTIME 20
+#if (SYNCCHECK==1)
+#define COM_SYNCCHECK 21
+#endif
+#define COM_SOUNDANDDELTA  22
+#define COM_EXIT    23
+#define COM_GAMEEND 24
+#define COM_DELTANULL 25
+
+#define CHECKSYNCTIME  (VBLCOUNTER<<2)
+
+#define NETSYNCSERVERTIME (VBLCOUNTER)
+#define MODEMSYNCSERVERTIME (VBLCOUNTER/4)
+
+#define DUMMYPACKETSIZE 20
+
+
+#define COM_MAXTEXTSTRINGLENGTH 33
+
+// Sound defines for Remote ridicule
+
+#define COM_SOUND_START_TRANSMISSION  (0xff)
+#define COM_SOUND_END_TRANSMISSION    (0xfe)
+#define COM_SOUND_NORMAL_TRANSMISSION (0xfd)
+#define COM_SOUND_BUFFERSIZE 256
+
+// Demo Delta Structure
+typedef struct DemoType {
+    int   time;
+    short momx;
+    short momy;
+    word  dangle;
+    word  buttons;
+} DemoType;
+
+// Demo Header Structure
+typedef struct DemoHeaderType {
+    gametype demostate;
+} DemoHeaderType;
+
+// Movement Queue Structure
+typedef struct MoveType {
+    byte  type;
+    int   time;
+    short momx;
+    short momy;
+    word  dangle;
+    word  buttons;
+    char  Sounddata[0];
+} MoveType;
+
+typedef struct NullMoveType {
+    byte  type;
+    int   time;
+} NullMoveType;
+
+typedef struct {
+
+    void * Commands[MAXCMDS];
+
+} CommandType;
+
+typedef struct {
+
+    byte CommandStates[MAXCMDS];
+
+} CommandStatusType;
+
+typedef MoveType COM_SoundAndDeltaType;
+
+// uncomment for live remote ridicule
+typedef struct {
+    byte  type;
+    byte  data[COM_SOUND_BUFFERSIZE];
+//  char  data[COM_MAXTEXTSTRINGLENGTH];
+} COM_SoundType;
+
+typedef struct {
+    byte  type;
+    int   synctime;
+} COM_SyncType;
+
+typedef struct {
+    byte  type;
+    int   time;
+    int   synctime;
+    int   x;
+    int   y;
+    int   z;
+    word  angle;
+    word  randomindex;
+} COM_CheckSyncType;
+
+typedef struct {
+    byte  type;
+    int   time;
+    byte  numpackets;
+    byte  data;
+} COM_ServerHeaderType;
+
+typedef struct {
+    byte  type;
+    int   time;
+    byte   numpackets;
+} COM_RequestType;
+
+typedef struct {
+    byte  type;
+    int   time;
+    byte  towho;
+    char  string[COM_MAXTEXTSTRINGLENGTH];
+} COM_TextType;
+
+#define MSG_DIRECTED_TO_ALL  255
+#define MSG_DIRECTED_TO_TEAM 254
+
+typedef struct {
+    byte  type;
+    int   time;
+    byte  player;
+    byte  num;
+    byte  towho;
+} COM_RemoteRidiculeType;
+
+typedef struct {
+    byte  type;
+    int   time;
+    byte  numpackets;
+    byte  data;
+} COM_FixupType;
+
+typedef struct {
+    byte  type;
+    int   time;
+} COM_QuitType;
+
+typedef struct {
+    byte  type;
+    int   time;
+} COM_ExitType;
+
+typedef struct {
+    byte  type;
+    int   time;
+} COM_GameEndType;
+
+typedef struct {
+    byte  character;    // which character
+    byte  uniformcolor; // which color
+    char  codename[MAXCODENAMELENGTH];  // codename
+} COM_PlayerDescriptionType;
+
+typedef struct {
+    byte  type;
+    byte  player;    // which player
+    byte  violence;
+    byte  Product;
+    unsigned Version;
+
+    COM_PlayerDescriptionType playerdescription;
+} COM_GamePlayerType;
+
+typedef struct {
+    byte  type;
+    byte  level;
+    word  mapcrc;
+    byte  violence;
+    byte  Product;
+    byte  mode;
+    unsigned Version;
+    boolean teamplay;
+    specials SpecialsTimes;
+    battle_type options;
+    char  battlefilename[20];
+    int   randomseed;
+    boolean ludicrousgibs;
+    COM_PlayerDescriptionType players[MAXPLAYERS];
+} COM_GameMasterType;
+
+typedef struct {
+    byte  type;
+    byte  player; // which player
+} COM_GameAckType;
+
+typedef struct {
+    byte  type;
+    int   time;
+} COM_EndGameType;
+
+typedef struct {
+    byte  type;
+    int   time;
+} COM_RespawnType;
+
+typedef struct {
+    byte  type;
+    int   time;
+} COM_PauseType;
+
+typedef struct {
+    byte  type;
+    int   time;
+} COM_UnPauseType;
+
+extern boolean  demorecord,
+       demoplayback;
+extern byte     *demoptr,
+       *lastdemoptr,
+       *demobuffer;
+extern boolean  demodone;
+extern int      predemo_violence;
+
+void     ControlPlayer (void);
+void     ControlRemote (objtype * ob);
+void     ControlPlayerObj (objtype * ob);
+void InitializeGameCommands( void );
+void ShutdownGameCommands( void );
+void UpdateClientControls ( void );
+void StartupClientControls ( void );
+void ShutdownClientControls ( void );
+void ProcessServer ( void );
+void ServerLoop( void );
+void SendPlayerDescription( void );
+void SetGameDescription( void * pkt );
+void SendGameDescription( void );
+void SendGameAck( void );
+void SendGameStart( void );
+void SetupGamePlayer ( void );
+void SetupGameMaster ( void );
+void SetNormalHorizon (objtype * ob);
+void SaveDemo (int demonumber);
+void LoadDemo (int demonumber);
+void RecordDemo ( void );
+void SetupDemo ( void );
+void FreeDemo ( void );
+boolean DemoExists (int demonumber);
+
+void AddEndGameCommand ( void );
+void AddTextMessage ( char * message, int length, int towho );
+void AddEndGameCommand ( void );
+void AddPauseStateCommand ( int type );
+void AddRespawnCommand ( void );
+void RecordDemoCmd (void);
+void ResetCurrentCommand ( void );
+void AddRemoteRidiculeCommand ( int player, int towho, int num );
+void ProcessRemoteRidicule ( void * pkt );
+void SyncToServer( void );
+void AddQuitCommand ( void );
+void AddExitCommand ( void );
+void AddGameEndCommand ( void );
+boolean PlayerInGame ( int p );
+boolean ConsoleIsServer ( void );
+
+extern boolean IsServer;
+extern boolean standalone;
+extern boolean    playerdead;
+
+extern boolean    modemgame;
+extern boolean    networkgame;
+extern int        numplayers;
+extern int        server;
+
+extern boolean    GamePaused;
+extern boolean    battlegibs;
+
+extern boolean    remoteridicule;
+
+#if (SYNCCHECK==1)
+extern int        lastsynccheck;
+extern COM_CheckSyncType PlayerSync[MAXPLAYERS];
+void CheckForSyncCheck ( void );
+#endif
+
+int GamePacketSize( void );
+
+#endif
--- /dev/null
+++ b/rott/rt_playr.c
@@ -1,0 +1,6497 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+
+#ifdef DOS
+#include <dos.h>
+#endif
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+
+#include "rt_def.h"
+#include "watcom.h"
+#include "rt_sound.h"
+#include "gmove.h"
+#include "states.h"
+#include "rt_sqrt.h"
+#include "rt_actor.h"
+#include "rt_main.h"
+#include "rt_playr.h"
+#include "isr.h"
+#include "rt_draw.h"
+#include "rt_ted.h"
+#include "rt_door.h"
+#include "rt_menu.h"
+#include "rt_view.h"
+#include "rt_com.h"
+#include "rt_in.h"
+#include "rt_util.h"
+#include "rt_game.h"
+#include "rt_rand.h"
+#include "z_zone.h"
+#include "rt_swift.h"
+#include "engine.h"
+#include "_rt_play.h"
+#include "rt_cfg.h"
+#include "rt_spbal.h"
+#include "rt_floor.h"
+#include "develop.h"
+#include "rt_msg.h"
+#include "rt_debug.h"
+#include "sprites.h"
+#include "rt_net.h"
+#include "rt_dmand.h"
+//MED
+#include "memcheck.h"
+
+
+#define FLYINGZMOM  350000
+
+
+#if (DEVELOPMENT == 1)
+#include "rt_str.h"
+#endif
+
+extern boolean usejump;
+
+
+specials CurrentSpecialsTimes =
+{
+    60*VBLCOUNTER, // god
+    60*VBLCOUNTER, // dog
+    20*VBLCOUNTER, // shrooms
+    20*VBLCOUNTER, // elasto
+    60*VBLCOUNTER, // asbestos vest
+    60*VBLCOUNTER, // bullet proof vest
+    GASTICS, // gas mask
+    60*VBLCOUNTER, // mercury mode
+
+    300*VBLCOUNTER, // god respawn
+    60*VBLCOUNTER, // dog respawn
+    60*VBLCOUNTER, // shrooms respawn
+    60*VBLCOUNTER, // elasto respawn
+    60*VBLCOUNTER, // asbestos vest respawn
+    60*VBLCOUNTER, // bullet proof vest respawn
+    60*VBLCOUNTER, // gas mask respawn
+    60*VBLCOUNTER  // mercury mode respawn
+};
+
+int GRAVITY = NORMAL_GRAVITY;
+
+ROTTCHARS characters[5]= {
+    {0x2100,0x4800,100,2,25},  // Taradino Cassatt
+    {0x2200,0x5200,85,3,32},   // Thi Barrett
+    {0x1f00,0x4000,150,3,20},  // Doug Wendt
+    {0x2300,0x5500,70,2,33},   // Lorelei Ni
+    {0x2000,0x4400,120,3,25}
+}; // Ian Paul Freeley
+
+static const int TD = MINACTORDIST+0x1000;
+static const int STRAFEAMOUNT = ((KEYBOARDNORMALTURNAMOUNT >> 10) + (KEYBOARDNORMALTURNAMOUNT >> 12));
+
+
+static const int GODYZANGLE     = -(9*FINEANGLES/360);
+static const int DOGYZANGLE     =  (4*FINEANGLES/360);
+static const int SHROOMYZANGLE  =  (15*FINEANGLES/360);
+static const int FALLINGYZANGLE = -(15*FINEANGLES/360);
+static const int NORMALYZANGLE  = 0;
+
+
+/*
+=============================================================================
+
+			GLOBAL VARIABLES
+
+=============================================================================
+*/
+
+int controlbuf[3];
+int buttonbits;
+extern _2Dpoint LASTSOUND;
+//
+// player state info
+//
+
+statobj_t      *DEADPLAYER[MAXDEAD];
+int            NUMDEAD;
+int            lastpolltime;
+
+statobj_t      *BulletHoles[MAXBULLETS];
+int            BulletHoleNum;
+
+objtype        *PLAYER[MAXPLAYERS],*player;
+playertype     PLAYERSTATE[MAXPLAYERS],*locplayerstate;
+
+gametype       gamestate;
+
+boolean        godmode = false;
+
+boolean       missilecam=false;
+objtype       * missobj=NULL;
+// Player control variables
+
+int KX = 0;
+int KY = 0;
+int MX = 0;
+int MY = 0;
+int JX = 0;
+int JY = 0;
+int CX = 0;
+int CY = 0;
+boolean vrenabled = false;
+int VX = 0;
+int VY = 0;
+
+int oldcyberx = 0;
+int oldcybery = 0;
+int CYBERDEADRANGE = 6000;
+boolean CYBERLOOKUP,CYBERLOOKDOWN;
+
+int leftmom = 0;
+int rightmom = 0;
+int lastmom = 0;
+int first    = 1;
+
+int pausedstartedticcount;
+boolean RefreshPause = true;
+
+boolean  buttonpoll[NUMBUTTONS];
+
+int      buttonscan[NUMBUTTONS] = {sc_Control, sc_Alt, sc_RShift, sc_Space,
+                                   sc_PgUp,sc_PgDn,sc_Enter,sc_Delete,
+                                   sc_Home,sc_End,sc_1,sc_2,sc_3,sc_4,
+                                   sc_CapsLock, sc_F12,
+                                   sc_Comma,sc_Period,sc_BackSpace,sc_A,
+                                   sc_UpArrow, sc_RightArrow,
+                                   sc_DownArrow, sc_LeftArrow,
+                                   sc_Tab, sc_T, sc_Z
+                                  };
+
+int      joyxmax = 0, joyymax = 0, joyxmin = 0, joyymin = 0;
+
+int      buttonmouse[6] = {bt_attack, bt_strafe, di_north,
+                           bt_nobutton, bt_use, bt_nobutton
+                          };
+
+int      buttonjoy[8] = {bt_attack, bt_strafe, bt_run, bt_use,
+                         bt_nobutton, bt_nobutton, bt_nobutton, bt_nobutton
+                        };
+
+williamdidthis FREE = {84,5,0,0,9,{{done,2,1},{done,2,2},{done,2,3},
+        {done,2,4},{done,2,5},{done,2,6},{done,2,7},{done,2,8},
+        {reset,2,9}
+    }
+};
+
+williamdidthis DOGSCRATCH = {128,5,0,0,4,{{done,2,8},{at_pulltrigger,2,9},{done,2,10},
+        {reset,2,11}
+    }
+};
+
+williamdidthis DOGLICK =    {128,5,0,0,4,{{done,2,4},{done,2,5},{done,2,6},
+        {reset,2,7}
+    }
+};
+
+
+williamdidthis WEAPONS[MAXWEAPONS] =
+
+{
+    {100,-1,10,0x2000l,3,{{at_pulltrigger,4,1},{done,4,2},{reset,4,0}}}, //single pistol
+    {   100,-1,10,0x2000l,6,{{at_pulltrigger,2,1},{done,2,2},{done,2,3},
+            {at_pulltrigger,2,4},{done,2,5},{reset,2,3}
+        }
+    }, // double pistol
+    {70,-1,10,0x2000l,2,{{at_pulltrigger,2,1},{reset,1,2}}}, //mp 40
+    {80,5,10,0x50000l,4,{{at_missileweapon,2,1},{done,2,2},{reset,2,3},{reset2,6,0}}}, //bazooka
+    {80,5,10,0x10000l,4,{{at_missileweapon,2,1},{done,2,2},{reset,2,3},{reset2,6,0}}}, //firebomb
+    {80,5,10,0x50000l,4,{{at_missileweapon,2,1},{done,2,2},{reset,2,3},{reset2,6,0}}}, //heatseeker
+    {80,5,10,0x10000l,4,{{at_missileweapon,2,1},{done,2,2},{reset,2,3},{reset2,6,0}}}, //drunk
+    {80,5,7,0x10000l,4,{{at_missileweapon,2,1},{done,2,2},{reset,2,2},{reset2,6,0}}}, // firewall
+    {   125,5,7,0x10000l,7,{{done,3,1},{done,3,2},{done,3,3},{done,3,4},
+            {at_missileweapon,3,5},{done,3,6},{reset,3,7}
+        }
+    },	//GODHAND
+
+#if (SHAREWARE == 0)
+    {80,5,7,0x10000l,4,{{at_missileweapon,2,1},{done,2,2},{reset,2,3},{reset2,6,0}}}, //split
+    {   80,5,7,0x10000l,9,{{done,5,1},{done,5,2},{done,5,3},{done,5,4},
+            {at_missileweapon,10,5},{done,5,4},{done,5,3}, // kes
+            {done,5,2},{reset,5,1}
+        }
+    },
+    {   200,5,7,0x10000l,6,{{done,1,1},{done,1,2},{at_pulltrigger,1,3},{at_pulltrigger,1,4},
+            {at_pulltrigger,1,5},{reset,1,6}
+        }
+    },	//BAT
+    {128,5,7,0x10000l,3,{{done,2,1},{at_pulltrigger,2,2},{reset,2,3}}}
+#endif
+};
+
+
+
+/*
+=============================================================================
+
+					LOCAL FUNCTION PROTOTYPES and VARIABLES
+
+=============================================================================
+*/
+
+void     CheckPlayerSpecials(objtype * ob);
+void     CheckWeaponStates(objtype * ob);
+boolean  CheckSprite (statobj_t*,int *);
+void     T_Tag (objtype *ob);
+void     T_Player (objtype *ob);
+void     T_BatBlast(objtype*ob);
+void     T_Attack (objtype *ob);
+void     T_Free (objtype *ob);
+void     T_DogUse (objtype *ob);
+void     PlayerMove(objtype * ob);
+void     Thrust (objtype * ob);
+void     CheckWeaponChange (objtype * ob);
+void     PlayerMissileAttack(objtype* );
+void     Cmd_Use(objtype*);
+//void     ComError (char *error, ...);
+int      FinddTopYZANGLELIMITvalue(objtype *ob);
+
+statetype s_free = {false,0,0,T_Free,0,&s_free};
+statetype s_inelevator = {false,0,420,T_Player,0,&s_player};
+
+#if (SHAREWARE == 0)
+statetype s_dogwait = {true,SERIALDOG_W11,50,T_Player,SF_DOGSTATE,&s_serialdog};
+
+statetype s_doguse = {true,SERIALDOG_W11,140,T_DogUse,SF_DOGSTATE,&s_serialdog};
+statetype s_doglick = {true,SERIALDOG_W11,0,T_DogLick,SF_DOGSTATE,&s_doglick};
+#endif
+
+statetype s_tag = {false,CASSATT_S1,20,T_Tag,0,&s_player};
+
+static SWIFT_3DStatus SWIFTStatus;
+
+//
+// curent user input
+//
+
+static int turnheldtime;
+static int turnaround = 0;
+static int turnaroundtime;
+
+//
+// Double Click variables
+//
+
+static int  DoubleClickTimer[ 3 ]   = { 0 };
+static byte DoubleClickCount[ 3 ]   = { 0 };
+static byte DoubleClickPressed[ 3 ] = { false };
+static int  JoyDblClickTimer[ 4 ]   = { 0 };
+static byte JoyDblClickCount[ 4 ]   = { 0 };
+static byte JoyDblClickPressed[ 4 ] = { false };
+
+
+static int PlayerRecording=-1;
+static int nettics;
+
+void Move_Player_From_Exit_To_Start(objtype *ob);
+void CheckTagGame(objtype *actor1,objtype*actor2);
+void CheckFlying(objtype*ob,playertype *pstate);
+
+/*
+===============
+=
+= LoadPlayer
+=
+===============
+*/
+void LoadPlayer ( void )
+{
+    memset (locplayerstate->buttonstate, 0, sizeof(locplayerstate->buttonstate));
+    locplayerstate->anglefrac=player->angle<<ANGLEBITS;
+    areabyplayer[player->areanumber]=true;
+    ConnectAreas();
+}
+
+
+int MaxHitpointsForCharacter(playertype*pstate)
+{
+    if (BATTLEMODE && (gamestate.BattleOptions.HitPoints != bo_character_hitpoints))
+    {
+        return( gamestate.BattleOptions.HitPoints );
+    }
+    return characters[pstate->player].hitpoints;
+}
+
+void InitializeWeapons(playertype*pstate)
+{
+
+
+#if (SHAREWARE == 0)
+    if (gamestate.SpawnEluder)
+    {   pstate->new_weapon = pstate->weapon = pstate->missileweapon = wp_dog;
+        pstate->oldweapon = pstate->oldmissileweapon = wp_dog;
+        pstate->bulletweapon = -1;
+        pstate->HASBULLETWEAPON[wp_pistol] = 0;
+        pstate->HASBULLETWEAPON[wp_twopistol] = 0;
+        pstate->HASBULLETWEAPON[wp_mp40] = 0;
+    }
+    else
+#endif
+    {   if (gamestate.PlayerHasGun[pstate-&PLAYERSTATE[0]])
+        {   pstate->new_weapon = pstate->weapon = pstate->oldweapon =
+                    pstate->bulletweapon = wp_pistol;
+            pstate->HASBULLETWEAPON[wp_pistol] = 1;
+            pstate->HASBULLETWEAPON[wp_twopistol] = 0;
+            pstate->HASBULLETWEAPON[wp_mp40] = 0;
+            pstate->missileweapon = pstate->oldmissileweapon = -1;
+        }
+        else
+        {   pstate->new_weapon = pstate->weapon = pstate->oldweapon =
+                    pstate->bulletweapon = -1;
+            pstate->HASBULLETWEAPON[wp_pistol] = 0;
+            pstate->HASBULLETWEAPON[wp_twopistol] = 0;
+            pstate->HASBULLETWEAPON[wp_mp40] = 0;
+            pstate->missileweapon = pstate->oldmissileweapon = -1;
+        }
+    }
+
+
+    pstate->ammo = -1;
+}
+
+void ResetPlayerstate(playertype*pstate)
+{
+
+    pstate->batblast = 0;
+    pstate->poweruptime = pstate->protectiontime = 0;
+    pstate->NETCAPTURED = 0;
+    MISCVARS->NET_IN_FLIGHT = 0;
+    pstate->weaponuptics = 0;
+    pstate->weapondowntics = 0;
+    if ((insetupgame==false) || NewGame)
+        pstate->health = MaxHitpointsForCharacter(pstate);
+    pstate->keys = 0;
+
+// Give players all the keys in battle game
+
+    if ( BATTLEMODE )
+    {
+        pstate->keys = 0x0f;
+    }
+    pstate->attackframe = pstate->attackcount =
+                              pstate->weaponframe = 0;
+    if (gamestate.battlemode == battle_Tag)
+        pstate->weaponheight = TAGHANDHEIGHT;
+    else
+        pstate->weaponheight = 0;
+    pstate->heightoffset = pstate->oldheightoffset = 0;
+    if (gamestate.SpawnEluder)
+        pstate->playerheight = 40;
+    else
+        pstate->playerheight = characters[pstate->player].height;
+    pstate->falling = false;
+    memset (pstate->buttonstate, 0, sizeof(pstate->buttonstate));
+    SetPlayerHorizon(pstate,NORMALYZANGLE);
+}
+
+
+
+
+/*
+===============
+=
+= SetupPlayerobj
+=
+===============
+*/
+void SetupPlayerobj (int tilex, int tiley, int dir, objtype * ob)
+{
+    playertype *pstate;
+
+    M_LINKSTATE(ob,pstate);
+
+    ob->obclass = playerobj;
+    ob->tilex = tilex;
+    ob->tiley = tiley;
+    actorat[tilex][tiley] = ob;
+    ob->areanumber = MAPSPOT(tilex,tiley,0)-AREATILE;
+    MakeLastInArea(ob);
+    ob->x = ((long)tilex<<TILESHIFT)+TILEGLOBAL/2;
+    ob->y = ((long)tiley<<TILESHIFT)+TILEGLOBAL/2;
+    ob->z = PlatformHeight(tilex,tiley);
+    if ((ob->z == -10) || DiskAt(tilex,tiley))
+        ob->z = 0;
+
+    ob->angle = (1-dir)*ANG90;
+    ob->which = ACTOR;
+    Fix(ob->angle);
+    ob->yzangle = 0;
+
+    ob->dir   = angletodir[ob->angle];
+    ob->flags = (FL_SHOOTABLE|FL_ABP|FL_BLOCK|FL_COLORED);
+    ob->drawx=ob->x;
+    ob->drawy=ob->y;
+    ob->hitpoints = pstate->health;
+    pstate->anglefrac= (ob->angle<<ANGLEBITS);
+    pstate->angle=0;
+    areabyplayer[ob->areanumber]=true;
+
+
+    if (ob == player)
+    {
+        playerdead=false; // local player dead flag
+    }
+    if (!gamestate.SpawnEluder)
+        ob->shapeoffset = pstate->player*REMOTEOFFSET;
+
+    memset (pstate->buttonstate, 0, sizeof(pstate->buttonstate));
+    if (SCREENEYE != NULL)
+    {
+        NewState(SCREENEYE,&s_megaremove);
+        SCREENEYE = NULL;
+    }
+}
+
+
+
+void SetShapeoffset(objtype*ob)
+{   playertype *pstate;
+
+    M_LINKSTATE(ob,pstate);
+    ob->shapeoffset = pstate->player*REMOTEOFFSET;
+    ob->flags |= FL_COLORED;
+    ob->flags &= ~FL_DYING;
+
+}
+
+
+/*
+===============
+=
+= RevivePlayerobj
+=
+===============
+*/
+void RevivePlayerobj (int tilex, int tiley, int dir, objtype*ob)
+{
+    playertype *pstate;
+    statetype *tstate;
+
+    M_LINKSTATE(ob,pstate);
+    tstate = ob->state;
+    RemoveFromArea(ob);
+    TurnActorIntoSprite(ob);
+    if ((LASTSTAT->z < nominalheight) && (!IsPlatform(LASTSTAT->tilex,LASTSTAT->tiley)))
+    {
+        SpawnParticles(ob,GUTS,10 + gamestate.difficulty);
+        RemoveStatic(LASTSTAT);
+    }
+    else
+    {   if (DEADPLAYER[NUMDEAD])
+            RemoveStatic(DEADPLAYER[NUMDEAD]);
+        DEADPLAYER[NUMDEAD] = LASTSTAT;
+        LASTSTAT->linked_to = NUMDEAD;
+        NUMDEAD = (NUMDEAD+1)&(MAXDEAD-1);
+    }
+
+    ob->state = tstate;
+
+    SetupPlayerobj (tilex, tiley, dir, ob);
+    ConnectAreas();
+
+    ResetPlayerstate(pstate);
+    InitializeWeapons(pstate);
+    SD_PlaySoundRTP(SD_PLAYERSPAWNSND,ob->x,ob->y);
+    if (!gamestate.SpawnEluder)
+    {
+        ob->shapeoffset = 0;
+        ob->flags &= ~FL_COLORED;
+        ob->flags |= FL_DYING;
+        NewState(ob,&s_respawn1);
+        if (gamestate.battlemode == battle_Tag)
+        {
+            if (BATTLE_Team[ob->dirchoosetime] == BATTLE_It)
+
+            {
+                pstate->missileweapon = pstate->oldweapon = pstate->new_weapon =
+                                            pstate->oldmissileweapon = pstate->weapon = wp_godhand;
+                pstate->bulletweapon = -1;
+                ob->flags |= FL_DESIGNATED;
+            }
+            else
+            {
+                pstate->weaponheight = 0;
+            }
+        }
+    }
+#if (SHAREWARE == 0)
+    else
+        NewState(ob,&s_serialdog);
+#endif
+    if (ob==player)
+        DrawPlayScreen(false);
+    ob->momentumx = ob->momentumy = ob->momentumz = 0;
+}
+
+
+/*
+===============
+=
+= SpawnPlayerobj
+=
+===============
+*/
+void SpawnPlayerobj (int tilex, int tiley, int dir, int playerindex)
+{
+    playertype *pstate;
+
+    pstate = &PLAYERSTATE[playerindex];
+
+    GetNewActor();
+    MakeActive(new);
+
+    // Set player number
+
+    new->dirchoosetime = playerindex;
+
+    // Save off if local player
+
+    if (playerindex==consoleplayer)
+        player=new;
+
+    PLAYER[playerindex] = new;
+
+    SetupPlayerobj (tilex, tiley, dir, new);
+
+    if (!gamestate.SpawnEluder)
+        NewState(new,&s_player);
+#if (SHAREWARE == 0)
+    else
+        NewState(new,&s_serialdog);
+#endif
+
+
+}
+
+/*
+===============
+=
+= SetupBulletHoleLink
+=
+===============
+*/
+void SetupBulletHoleLink (int num, statobj_t * item)
+{
+    BulletHoles[num] = item;
+}
+
+/*
+===============
+=
+= SpawnBulletHole
+=
+===============
+*/
+void SpawnBulletHole (int x, int y, int z)
+{
+    if (M_ISDOOR(x>>16,y>>16))
+        return;
+    if (BulletHoles[MISCVARS->BulletHoleNum])
+        RemoveStatic(BulletHoles[MISCVARS->BulletHoleNum]);
+    SpawnInertStatic(x,y,z,stat_bullethole);
+    BulletHoles[MISCVARS->BulletHoleNum]=LASTSTAT;
+    LASTSTAT->linked_to=MISCVARS->BulletHoleNum;
+    MISCVARS->BulletHoleNum = (MISCVARS->BulletHoleNum+1)&(MAXBULLETS-1);
+}
+
+
+
+
+void SpawnGunSmoke(int x, int y, int z, int angle, int bullethole)
+
+{
+    int chance;
+
+    if ((x<=0) || (y<=0))
+    {
+        SoftError("SpawnGunSmoke: xy below angle=%d\n",angle);
+        return;
+    }
+
+    if ((bullethole!=0) && (z>=-32) && (z<=maxheight))
+        switch (bullethole)
+        {
+        case 1:
+            SpawnBulletHole(x-BULLETHOLEOFFSET,y,z);
+            break;
+        case 2:
+            SpawnBulletHole(x+BULLETHOLEOFFSET,y,z);
+            break;
+        case 3:
+            SpawnBulletHole(x,y-BULLETHOLEOFFSET,z);
+            break;
+        case 4:
+            SpawnBulletHole(x,y+BULLETHOLEOFFSET,z);
+            break;
+        case 5:
+            SpawnBulletHole(x,y,z);
+            break;
+        default:
+            Error("Invalid bullethole value\n");
+            break;
+        }
+
+    SpawnInertActor(x,y,z);
+
+    NewState(new,&s_gunsmoke1);
+
+    if (angle < ANGLES/4)
+    {   if ((angle < (3*ANGLES/16)) && (angle > (ANGLES/16)))
+            chance = 128;
+        else
+            chance = 20;
+    }
+    else if (angle < ANGLES/2)
+    {   if ((angle < (7*ANGLES/16)) && (angle > (5*ANGLES/16)))
+            chance = 128;
+        else
+            chance = 20;
+    }
+    else if (angle < 3*ANGLES/4)
+    {   if ((angle < (11*ANGLES/16)) && (angle > (9*ANGLES/16)))
+            chance = 128;
+        else
+            chance = 20;
+    }
+    else
+    {   if ((angle < (15*ANGLES/16)) && (angle > (13*ANGLES/16)))
+            chance = 128;
+        else
+            chance = 20;
+    }
+
+    if (RandomNumber("Wall ricochet check",0)<chance)
+    {   int rand;
+
+        rand = RandomNumber("Spawn Ricochet Sound in SpawnGunSmoke",0);
+        if (rand < 80)
+            SD_PlaySoundRTP(SD_RICOCHET1SND,new->x,new->y);
+        else if (rand < 160)
+            SD_PlaySoundRTP(SD_RICOCHET2SND,new->x,new->y);
+        else
+            SD_PlaySoundRTP(SD_RICOCHET3SND,new->x,new->y);
+    }
+}
+
+void  SpawnBlood(objtype * ob, int angle)
+{
+
+    SpawnInertActor(ob->x-(costable[angle]>>5),
+                    ob->y+(sintable[angle]>>5),ob->z);
+
+    NewState(new,&s_bloodspurt1);
+
+    if ((new->x<=0) || (new->y<=0))
+        Error("SpawnBlood: bad x,y obj->obclass=%d\n",ob->obclass);
+}
+
+void  SpawnMetalSparks(objtype * ob, int angle)
+{
+    int rand,dispx=0,dispy=0;
+
+
+    if (ob->which == ACTOR)
+    {
+        dispx = ob->momentumx;
+        dispy = ob->momentumy;
+    }
+
+    SpawnInertActor(ob->x-(costable[angle]>>3)+dispx,
+                    ob->y+(sintable[angle]>>3)+dispy,ob->z);
+
+    if (GameRandomNumber("Spawn Metal Sparks",0)<128)
+        NewState(new,&s_hitmetalactor1);
+    else
+        NewState(new,&s_hitmetalwall1);
+
+    rand = RandomNumber("Spawn Ricochet Sound",0);
+    if (rand < 80)
+        SD_PlaySoundRTP(SD_RICOCHET1SND,new->x,new->y);
+    else if (rand < 160)
+        SD_PlaySoundRTP(SD_RICOCHET2SND,new->x,new->y);
+    else
+        SD_PlaySoundRTP(SD_RICOCHET3SND,new->x,new->y);
+    if ((new->x<=0) || (new->y<=0))
+        Error("SpawnMetalSparks: bad x,y obj->obclass=%d\n",ob->obclass);
+}
+
+/*
+===============
+=
+= UnTargetActor ( objtype * target )
+=
+===============
+*/
+void UnTargetActor ( objtype * target )
+{
+    int i;
+
+    for (i=0; i<numplayers; i++)
+    {
+        if (PLAYERSTATE[i].guntarget==target)
+        {
+            PLAYERSTATE[i].guntarget=NULL;
+            SetNormalHorizon(PLAYER[i]);
+        }
+    }
+}
+
+
+
+//=============================================================
+
+int GetWeaponForItem(int itemnumber)
+{
+    switch (itemnumber)
+    {
+
+
+    case  stat_twopistol:
+        return wp_twopistol;
+
+    case  stat_mp40:
+        return wp_mp40;
+
+    case  stat_bazooka:
+        return wp_bazooka;
+
+    case  stat_heatseeker:
+        return wp_heatseeker;
+
+    case  stat_drunkmissile:
+        return wp_drunk;
+
+    case  stat_firebomb:
+        return wp_firebomb;
+
+    case  stat_firewall:
+        return wp_firewall;
+
+    case  stat_godmode:
+        return wp_godhand;
+
+#if (SHAREWARE == 0)
+
+
+    case  stat_splitmissile:
+        return wp_split;
+
+    case  stat_kes:
+        return wp_kes;
+
+    case  stat_bat:
+        return wp_bat;
+
+
+    case  stat_dogmode:
+        return wp_dog;
+#endif
+    }
+    return 0;
+}
+
+
+int GetItemForWeapon(int weapon)
+{
+    switch (weapon)
+    {
+
+    case wp_twopistol:
+        return stat_twopistol;
+
+    case  wp_mp40:
+        return stat_mp40;
+
+    case  wp_bazooka:
+        return stat_bazooka;
+
+    case  wp_heatseeker:
+        return stat_heatseeker;
+
+    case  wp_drunk:
+        return stat_drunkmissile;
+
+    case  wp_firebomb:
+        return stat_firebomb;
+
+    case  wp_firewall:
+        return stat_firewall;
+
+    case  wp_godhand:
+        return stat_godmode;
+
+#if (SHAREWARE == 0)
+
+    case  wp_split:
+        return stat_splitmissile;
+
+    case  wp_kes:
+        return stat_kes;
+
+    case  wp_bat:
+        return stat_bat;
+
+
+    case  wp_dog:
+        return stat_dogmode;
+#endif
+    }
+    return -1;
+}
+
+
+
+#define MF_SINGULAR 0x01
+
+missile_stats PlayerMissileData[13] =
+
+{
+    {0,0,0,0,0},
+    {0,0,0,0,0},
+    {0,0,0,0,0},
+
+    {&s_p_bazooka1,0x6000,p_bazookaobj,0x7000,MF_SINGULAR},
+    {&s_p_bazooka1,0x8000,p_heatseekobj,0x7000,MF_SINGULAR},
+    {&s_p_bazooka1,0x6000,p_drunkmissileobj,0x7000,0},
+    {&s_p_bazooka1,0x8000,p_firebombobj,0x7000,MF_SINGULAR},
+    {&s_p_grenade,0x4000,p_firewallobj,0x8000,0},
+    {&s_godfire1,0x3800,p_godballobj,0x8000,0},
+    {&s_p_bazooka1,0x8000,p_splitmissileobj,0x7000,MF_SINGULAR},
+#if (SHAREWARE == 0)
+    {&s_kessphere1,0xc000,p_kesobj,0x5000,MF_SINGULAR},
+#else
+    {0,0,0,0,0},
+#endif
+    {0,0,0,0,0},
+    {0,0,0,0,0}
+
+};
+
+
+void MissileAutoTarget(objtype *ob,missile_stats *mdata)
+{
+    int dx,dy,angle,mindist,currdist,magangle,saveangle,
+        xydist,dz,yzangle,oldyzangle,saveyzangle;
+    objtype *target,*temp;
+
+    mindist = 0x7fffffff;
+    target = NULL;
+    for(temp = firstactive; temp; temp=temp->nextactive)
+    {
+        if (temp == ob)
+            continue;
+        if ((!(temp->flags & FL_SHOOTABLE)) || (temp->flags & FL_DYING))
+            continue;
+        if (!CheckLine(ob,temp,SHOOT))
+            continue;
+
+        dx = temp->x-ob->x;
+        dy = ob->y-temp->y;
+        dz = ob->z-temp->z;
+        xydist = FindDistance(dx,dy);
+        yzangle = atan2_appx(xydist,dz<<10);
+
+        angle = atan2_appx(dx,dy);
+
+        magangle = abs(ob->angle - angle);
+        if (magangle > VANG180)
+            magangle = ANGLES - magangle;
+
+        if (magangle > ANGLESDIV8)
+            continue;
+
+        currdist = FindDistance(ob->x-temp->x,ob->y-temp->y);
+        if (currdist < mindist)
+        {
+            mindist = currdist;
+            target = temp;
+            saveangle = angle;
+            saveyzangle = yzangle;
+        }
+    }
+
+    if (target)
+    {
+        oldyzangle = ob->yzangle;
+        ob->yzangle = saveyzangle;
+        SpawnMissile(ob,mdata->obclass,mdata->speed,saveangle,
+                     mdata->state,mdata->offset);
+        ob->yzangle = oldyzangle;
+    }
+
+    else if (ob->flags&FL_GODMODE)
+    {
+        int saveangle;
+
+        saveangle=ob->yzangle;
+        ob->yzangle -= GODYZANGLE;
+        Fix(ob->yzangle);
+        SpawnMissile(ob,mdata->obclass,mdata->speed,
+                     ob->angle,mdata->state,mdata->offset);
+        ob->yzangle=saveangle;
+    }
+    else
+        SpawnMissile(ob,mdata->obclass,mdata->speed,ob->angle,
+                     mdata->state,mdata->offset);
+
+}
+
+
+void PlayerMissileAttack(objtype*ob)
+
+{
+    playertype * pstate;
+    missile_stats *newmissiledata;
+    M_LINKSTATE(ob,pstate);
+
+
+    MISCVARS->madenoise = true;
+    newmissiledata = &PlayerMissileData[pstate->missileweapon];
+
+    // ready to annihilate this poor bastard
+
+    if ((newmissiledata->obclass == p_godballobj) ||
+            (newmissiledata->obclass == p_kesobj))
+        MissileAutoTarget(ob,newmissiledata);
+
+    else
+    {
+        //LT added: if autoAimMissileWeps is true (as well as autoAim), then missile weapons will be aimed similarly to bullet weapons
+        if (autoAimMissileWeps && autoAim)
+            AutoTargetHorizon(ob);
+        SpawnMissile(ob,newmissiledata->obclass,newmissiledata->speed,ob->angle,
+                     newmissiledata->state,newmissiledata->offset);
+
+        if (newmissiledata->obclass == p_drunkmissileobj)
+        {
+            int i;
+
+            for(i=0; i<4; i++)
+            {
+                if (!MissileTryMove(new,new->x+new->momentumx,new->y+new->momentumy,new->z))
+                {
+                    new->x = new->drawx = ob->x + (costable[new->angle]>>3);
+                    new->y = new->drawy = ob->y - (sintable[new->angle]>>3);
+
+                    ob->momentumx = -FixedMul(0x5000l,costable[ob->angle]);
+                    ob->momentumy = FixedMul(0x5000l,sintable[ob->angle]);
+                }
+
+                SpawnMissile(ob,newmissiledata->obclass,newmissiledata->speed,ob->angle,
+                             newmissiledata->state,newmissiledata->offset);
+
+
+            }
+        }
+    }
+
+
+    if (newmissiledata->flags & MF_SINGULAR)
+        PLAYER0MISSILE = new;
+
+    SD_PlaySoundRTP(BAS[new->obclass].fire,ob->x,ob->y);
+
+    // if (new->obclass == p_godballobj)
+    //   new->z += 10;
+
+    new->dirchoosetime = 5;
+    if (missilecam==true)
+        missobj=new;
+    if (!MissileTryMove(new,new->x+new->momentumx,new->y+new->momentumy,new->z))
+    {
+        new->x = new->drawx = ob->x + (costable[new->angle]>>3);
+        new->y = new->drawy = ob->y - (sintable[new->angle]>>3);
+
+        ob->momentumx = -FixedMul(0x5000l,costable[ob->angle]);
+        ob->momentumy = FixedMul(0x5000l,sintable[ob->angle]);
+    }
+
+}
+
+//====================================================================
+
+
+boolean InRange (objtype *p, objtype *victim, int distance)
+{
+    int dx,dy;
+    int angle;
+    int magangle;
+
+    if (victim->which==SPRITE)
+    {
+        dx = ((statobj_t *)victim)->x - p->x;
+        dy = p->y - ((statobj_t *)victim)->y;
+    }
+    else
+    {
+        dx = victim->x - p->x;
+        dy = p->y - victim->y;
+    }
+    angle = atan2_appx (dx,dy);
+
+    magangle = abs(p->angle - angle);
+    if (magangle > VANG180)
+        magangle = ANGLES - magangle;
+    if (magangle<(75-(distance>>16)))
+        return true;
+    else
+        return false;
+}
+
+
+void DogAttack(objtype*ob)
+{
+    objtype *temp;
+    int dx,dy,dz;
+
+    SD_PlaySoundRTP(SD_DOGMODEBITE1SND+(RandomNumber("DogAttack",0)>>7),ob->x,ob->y);
+    for(temp=firstareaactor[ob->areanumber]; temp; temp=temp->nextinarea)
+    {
+
+        if (temp->obclass > b_heinrichobj)
+            continue;
+
+
+        if ((temp == ob) || (temp->obclass == roboguardobj))
+            continue;
+
+        if ((!(temp->flags & FL_SHOOTABLE)) || (temp->flags & FL_DYING))
+            continue;
+        if (temp->obclass == collectorobj)
+            continue;
+
+
+        dx = abs(temp->x - ob->x);
+        if (dx > 0xc000)
+            continue;
+
+        dy = abs(temp->y - ob->y);
+        if (dy > 0xc000)
+            continue;
+
+        dz = abs(temp->z - ob->z);
+        if (dz > (0xc000>>10))
+            continue;
+
+        DamageThing(temp,30);
+        if (gamestate.violence == vl_excessive)
+            SpawnParticles(temp,GUTS,15);
+        Collision(temp,ob,-temp->momentumx,-temp->momentumy);
+        if ((temp->obclass == playerobj) && (temp->flags & FL_DYING))
+            BATTLE_PlayerKilledPlayer(battle_kill_with_missile,ob->dirchoosetime,temp->dirchoosetime);
+
+        return;
+    }
+}
+
+
+void DogBlast(objtype*ob)
+{
+    int txl,txh,tyl,tyh,radius = 0x70000,x,y,tile;
+    objtype*temp;
+    statobj_t*tstat;
+
+    txl = ((ob->x - radius)>>TILESHIFT);
+    tyl = ((ob->y - radius)>>TILESHIFT);
+
+    txh = ((ob->x + radius)>>TILESHIFT);
+    tyh = ((ob->y + radius)>>TILESHIFT);
+
+    if (txl < 1)
+        txl = 1;
+    if (txh > MAPSIZE-1)
+        txh = MAPSIZE-1;
+    if (tyl < 1)
+        tyl = 1;
+    if (tyh > MAPSIZE-1)
+        tyh = MAPSIZE-1;
+
+    for(x=txl; x<=txh; x++)
+        for(y=tyl; y<=tyh; y++)
+        {
+            temp = (objtype*)actorat[x][y];
+
+            if (temp && (temp->which == ACTOR) && (temp->flags & FL_SHOOTABLE) &&
+                    (temp != ob) && (temp->obclass < roboguardobj) &&
+                    (temp->flags & FL_ABP)
+               )
+            {
+                DamageThing(temp,100);
+                if ((temp->hitpoints<=0) && (temp->obclass < roboguardobj))
+                {
+                    MISCVARS->supergibflag = true;
+                    temp->flags |= FL_HBM;
+                }
+                Collision(temp,ob,0,0);
+                MISCVARS->supergibflag = false;
+
+                if ((temp->obclass == playerobj) && (temp->flags & FL_DYING))
+                    BATTLE_PlayerKilledPlayer(battle_kill_with_missile,ob->dirchoosetime,temp->dirchoosetime);
+
+            }
+
+            tile = tilemap[x][y];
+            if ((tile & 0x4000) && (tile & 0x8000))
+            {
+                maskedwallobj_t * mw;
+
+                mw=maskobjlist[tile&0x3ff];
+                if ((mw->flags & MW_SHOOTABLE) && (mw->flags & MW_ABP))
+                    UpdateMaskedWall(tile&0x3ff);
+            }
+
+            tstat = sprites[x][y];
+            if (tstat && (tstat->flags & FL_SHOOTABLE) && (tstat->flags & FL_ABP))
+                DamageThing(tstat,50);
+        }
+}
+/*
+void DogBlast(objtype*ob)
+   {
+   int txl,txh,tyl,tyh,radius = 0x70000,x,y,tile;
+   objtype*temp;
+   statobj_t*tstat;
+
+   txl = ((ob->x - radius)>>TILESHIFT);
+   tyl = ((ob->y - radius)>>TILESHIFT);
+
+   txh = ((ob->x + radius)>>TILESHIFT);
+   tyh = ((ob->y + radius)>>TILESHIFT);
+
+   if (txl < 1)
+      txl = 1;
+   if (txh > MAPSIZE-1)
+      txh = MAPSIZE-1;
+   if (tyl < 1)
+      tyl = 1;
+   if (tyh > MAPSIZE-1)
+      tyh = MAPSIZE-1;
+
+   for(x=txl;x<=txh;x++)
+      for(y=tyl;y<=tyh;y++)
+         {
+         temp = (objtype*)actorat[x][y];
+
+         if (temp && (temp->which == ACTOR) && (temp->flags & FL_SHOOTABLE) &&
+            (temp != ob) && (temp->obclass < roboguardobj))
+            {
+            DamageThing(temp,100);
+            if ((temp->hitpoints<=0) && (temp->obclass < roboguardobj))
+               {
+               MISCVARS->supergibflag = true;
+               temp->flags |= FL_HBM;
+               }
+            Collision(temp,ob,0,0);
+            MISCVARS->supergibflag = false;
+
+            if ((temp->obclass == playerobj) && (temp->flags & FL_DYING))
+               BATTLE_PlayerKilledPlayer(battle_kill_with_missile,ob->dirchoosetime,temp->dirchoosetime);
+
+            }
+
+         tile = tilemap[x][y];
+         if ((tile & 0x4000) && (tile & 0x8000))
+            {
+            maskedwallobj_t * mw;
+
+            mw=maskobjlist[tile&0x3ff];
+            if (mw->flags & MW_SHOOTABLE)
+               UpdateMaskedWall(tile&0x3ff);
+            }
+
+         tstat = sprites[x][y];
+         if (tstat && (tstat->flags & FL_SHOOTABLE))
+            DamageThing(tstat,50);
+         }
+   }
+*/
+
+void BatBlast(objtype*ob)
+{   int angle;
+    playertype *pstate;
+
+    M_LINKSTATE(ob,pstate);
+
+    angle = ob->angle - ANGLES/8 + ((++pstate->batblast)*ANGLES/48);
+    Fix(angle);
+#if (SHAREWARE == 0)
+    SpawnMissile(ob,p_bazookaobj,0x6000,angle,&s_batblast1,0xa000);
+#endif
+
+}
+
+
+
+void BatAttack(objtype*ob)
+{   objtype *temp,*temp2;
+    objtype *grenadetarget;
+    statobj_t*tstat;
+    int dx,dy,dz,angle,momx,momy,op,magangle;
+    int tilexlow,tilexhigh;
+    int tileylow,tileyhigh;
+    int radius =0x10000;
+    int x,y;
+
+    SD_PlaySoundRTP(SD_EXCALISWINGSND,ob->x,ob->y);
+    for(temp=firstareaactor[ob->areanumber]; temp; temp=temp->nextinarea)
+    {   if (temp == ob)
+            continue;
+
+        if (temp->flags & FL_DYING)
+            continue;
+
+        if ((temp->obclass != grenadeobj) &&
+                (!((temp->obclass >= grenadeobj) && (temp->obclass <= p_godballobj))) &&
+                (!(temp->flags & FL_SHOOTABLE) ||
+                 (temp->obclass >= roboguardobj))
+           )
+            continue;
+
+        dx = abs(temp->x - ob->x);
+        dy = abs(temp->y - ob->y);
+        dz = abs(temp->z - ob->z);
+        if ((dx > 0x10000) || (dy > 0x10000) || (dz > 20))
+            continue;
+
+        magangle = abs(ob->angle - AngleBetween(ob,temp));
+        if (magangle > VANG180)
+            magangle = ANGLES - magangle;
+
+        if (magangle > ANGLES/8)
+            continue;
+
+
+        angle= ob->angle+ANGLES/16;
+        Fix(angle);
+
+        if ((temp->obclass >= grenadeobj) && (temp->obclass <= p_godballobj))
+        {
+            temp->angle += ANGLES/2;
+            Fix(temp->angle);
+            temp->momentumx = temp->momentumy = temp->momentumz = 0;
+            ParseMomentum(temp,temp->angle);
+            temp->whatever = ob;
+            temp->target = NULL;
+            continue;
+        }
+
+
+        else if (temp->obclass != grenadeobj)
+        {   momx = FixedMul(0x3000l,costable[angle]);
+            momy = -FixedMul(0x3000l,sintable[angle]);
+            if (levelheight > 2)
+            {   op = FixedMul(GRAVITY,(maxheight-100)<<16) << 1;
+                temp->momentumz = -FixedSqrtHP(op);
+            }
+            temp->flags |= FL_NOFRICTION;
+            SD_PlaySoundRTP(SD_EXCALIHITSND,ob->x,ob->y);
+            if ((gamestate.violence == vl_excessive) && (GameRandomNumber("Bat Gibs",0) < 150))
+            {   temp->flags |= FL_HBM;
+                DamageThing(temp,50);
+            }
+            else
+                DamageThing(temp,10);
+            if ((temp->flags & FL_HBM) && (temp->hitpoints > 0))
+                temp->flags &= ~FL_HBM;
+            Collision(temp,ob,momx,momy);
+            if ((temp->obclass == blitzguardobj) && (temp->state == &s_blitzplead7))
+            {   temp->shapeoffset += deathshapeoffset[temp->obclass];
+                temp->flags |= FL_ALTERNATE;
+                NewState(temp,&s_blitzdie3);
+                temp->momentumx = temp->momentumy = 0;
+            }
+        }
+        else // find target to hit grenade back at
+        {   int rand;
+
+            rand = GameRandomNumber("bat/grenade target",0);
+            if (rand < 80)
+            {   grenadetarget = (objtype*)(temp->whatever); // hit back at george
+                GetMomenta(grenadetarget,ob,&(temp->momentumx),&(temp->momentumy),&(temp->momentumz),0x3000);
+            }
+            else if (rand < 160) // hit back at first eligible
+            {
+
+                for(temp2 = firstareaactor[ob->areanumber]; temp2; temp2 = temp2->nextinarea)
+                {   magangle = abs(ob->angle-AngleBetween(ob,temp2));
+                    if (magangle > VANG180)
+                        magangle = ANGLES - magangle;
+
+                    if (magangle > ANGLES/8)
+                        continue;
+                    GetMomenta(temp2,ob,&(temp->momentumx),&(temp->momentumy),&(temp->momentumz),0x3000);
+                    break;
+                }
+            }
+            else // hit wherever
+            {   ob->angle += (rand >> 1);
+                Fix(ob->angle);
+                ob->momentumx = ob->momentumy = 0;
+                ParseMomentum(ob,ob->angle);
+            }
+
+
+            temp->temp1 = 0x70000;
+            NewState(temp,&s_grenade1);
+        }
+        break;
+    }
+
+    for(tstat=firstactivestat; tstat; tstat=tstat->statnext)
+    {
+        if (!(tstat->flags & FL_SHOOTABLE))
+            continue;
+
+        dx = abs(tstat->x - ob->x);
+        dy = abs(tstat->y - ob->y);
+        dz = abs(tstat->z - ob->z);
+
+        if ((dx > 0xc000) || (dy > 0xc000) || (dz > 20))
+            continue;
+
+        magangle = abs(ob->angle - AngleBetween(ob,(objtype*)tstat));
+        if (magangle > VANG180)
+            magangle = ANGLES - magangle;
+
+        if (magangle > ANGLES/8)
+            continue;
+
+        DamageThing(tstat,50);
+
+
+    }
+
+    tilexlow = (int)((ob->x-radius) >>TILESHIFT);
+    tileylow = (int)((ob->y-radius) >>TILESHIFT);
+
+    tilexhigh = (int)((ob->x+radius) >>TILESHIFT);
+    tileyhigh = (int)((ob->y+radius) >>TILESHIFT);
+
+    for (y=tileylow; y<=tileyhigh; y++)
+        for (x=tilexlow; x<=tilexhigh; x++)
+        {   if ((tilemap[x][y]&0x8000) && (tilemap[x][y]&0x4000))
+            {   maskedwallobj_t * mw;
+
+                mw=maskobjlist[tilemap[x][y]&0x3ff];
+                if (mw->flags&MW_SHOOTABLE)
+                    UpdateMaskedWall(tilemap[x][y]&0x3ff);
+            }
+        }
+
+}
+
+void AutoTargetHorizon(objtype *ob)
+{
+    int dx,dy,angle,mindist,magangle,
+        xydist,dz;
+    objtype *temp;
+    playertype * pstate;
+
+    M_LINKSTATE(ob,pstate);
+
+    mindist = 0x7fffffff;
+    for(temp = firstactive; temp; temp=temp->nextactive)
+    {
+        if (temp == ob)
+            continue;
+        if ((!(temp->flags & FL_SHOOTABLE)) || (temp->flags & FL_DYING))
+            continue;
+        if (!CheckLine(ob,temp,SHOOT))
+            continue;
+
+        dx = temp->x-ob->x;
+        dy = ob->y-temp->y;
+        dz = ob->z-temp->z;//-pstate->playerheight+32;
+
+        xydist = FindDistance(dx,dy);
+        if (abs(dz<<10)>xydist)
+            continue;
+
+
+        angle = atan2_appx(dx,dy);
+
+        magangle = ob->angle - angle;
+        Fix(magangle);
+
+        if (
+            (magangle>=(ANGLESDIV8/4)) &&
+            (magangle<=(FINEANGLES-(ANGLESDIV8/4)))
+        )
+        {
+            continue;
+        }
+
+        if (xydist < mindist)
+        {
+            mindist = xydist;
+            pstate->guntarget=temp;
+            temp->flags |= FL_TARGET;
+            pstate->targettime=oldpolltime+(VBLCOUNTER);
+        }
+    }
+}
+
+void  GunAttack (objtype *ob)
+{
+    playertype * pstate;
+    int      damage;
+
+    M_LINKSTATE(ob,pstate);
+
+    MISCVARS->madenoise = true;
+
+    switch (pstate->weapon)
+    {
+    case wp_pistol:
+        SD_PlaySoundRTP(SD_ATKPISTOLSND,ob->x,ob->y);
+        damage=DMG_PISTOL;
+        break;
+
+    case wp_mp40:
+        SD_PlaySoundRTP(SD_ATKMP40SND,ob->x,ob->y);
+        damage=DMG_MP40;
+        break;
+
+    case wp_twopistol:
+        SD_PlaySoundRTP(SD_ATKTWOPISTOLSND,ob->x,ob->y);
+        damage=DMG_PISTOL;
+        break;
+    }
+    if(autoAim)
+        AutoTargetHorizon(ob);
+    RayShoot (ob, damage, (characters[pstate->player].accuracy+gamestate.difficulty)<<3);
+
+}
+
+
+/*
+===============
+=
+= Cmd_Fire
+=
+===============
+*/
+void Cmd_Fire (objtype*ob)
+{
+    playertype *pstate;
+
+    M_LINKSTATE(ob,pstate);
+
+//   pstate->buttonheld[bt_attack] = true;
+
+    if (pstate->NETCAPTURED && (!pstate->HASKNIFE))
+        return;
+
+    if (W_CHANGE(pstate))
+        return;
+
+    pstate->attackframe = 0;
+
+    if ((ob==player) && (pstate->weapon < wp_mp40) && (!pstate->NETCAPTURED))
+        gamestate.DODEMOCRATICBONUS1 = false;
+
+    if (!pstate->NETCAPTURED)
+    {
+        if (pstate->weapon <= wp_mp40)
+            NewState(ob,&s_pgunattack1);
+#if (SHAREWARE == 0)
+        else if ((pstate->weapon == wp_bat) && (pstate->batblast >= BBTIME))
+        {
+            pstate->batblast = 0;
+            NewState(ob,&s_pbatblast);
+        }
+        else if (pstate->weapon == wp_dog)
+            NewState(ob,&s_serialdogattack);
+#endif
+        else
+            NewState(ob,&s_pmissattack1);
+
+#if (SHAREWARE == 0)
+
+        if ((pstate->weapon == wp_dog) && (!ob->momentumz))
+            ob->momentumz = -0x50000;
+#endif
+        pstate->attackcount = WEAPONS[pstate->weapon].attackinfo[0].mtics;
+        pstate->weaponframe = WEAPONS[pstate->weapon].attackinfo[0].frame;
+    }
+
+    else if (pstate->NETCAPTURED == 1)
+    {
+        NewState(player,&s_free);
+        pstate->attackcount = FREE.attackinfo[0].mtics;
+        pstate->weaponframe = FREE.attackinfo[0].frame;
+    }
+
+}
+
+void PlayNoWaySound ( void )
+{
+    if (player->flags & FL_DOGMODE)
+        SD_Play(SD_DOGMODEBITE2SND);
+    else if ((locplayerstate->player == 1) || (locplayerstate->player == 3))
+        SD_Play(SD_PLAYERTBHURTSND);
+    else
+        SD_Play(SD_NOWAYSND);
+}
+
+
+/*
+===============
+=
+= Cmd_Use
+=
+===============
+*/
+
+boolean AreJumping = false;//bna added
+int		oldzval;
+int donttilt=0;
+
+
+
+void Cmd_Use (objtype*ob)
+{
+    int             checkx,checky,doorn,
+                    /*newtilex,newtiley,oldtilex,oldtiley,*/elevnum,
+                    wallx,wally;
+//      statobj_t*      tempsprite=NULL;
+    objtype*        tempactor= NULL;
+    doorobj_t*      tempdoor=NULL;
+    pwallobj_t*      temppwall=NULL;
+    wall_t*         tempwall=NULL;
+    int             index;
+    playertype * pstate;
+
+
+
+    M_LINKSTATE(ob,pstate);
+
+#if (SHAREWARE == 0)
+
+    if ((pstate->weapon == wp_dog) && (ob->state != &s_doguse) &&
+            (ob->state != &s_dogwait) && (!W_CHANGE(pstate))
+       )
+    {
+        pstate->attackframe = 0;
+        NewState(ob,&s_doguse);
+        pstate->attackcount = DOGSCRATCH.attackinfo[0].mtics;
+        pstate->weaponframe = DOGSCRATCH.attackinfo[0].frame;
+        ob->momentumz = -0x40000;
+        return;
+
+    }
+
+    else
+#endif
+        if ((ob->flags & FL_DESIGNATED) && (BATTLEMODE) && (gamestate.battlemode == battle_Tag))
+        {
+            NewState(ob,&s_tag);
+            //return;
+        }
+//
+// find which cardinal direction the player is facing
+//
+    if (ob->angle < FINEANGLES/8 || ob->angle > 7*FINEANGLES/8)
+    {
+        checkx = ob->tilex + 1;
+        checky = ob->tiley;
+        ob->dir = east;
+        wallx = (checkx << TILESHIFT);
+        wally = (checky << TILESHIFT) + TILEGLOBAL/2;
+    }
+    else if (ob->angle < 3*FINEANGLES/8)
+    {
+        checkx = ob->tilex;
+        checky = ob->tiley-1;
+        ob->dir = north;
+        wally = (checky << TILESHIFT) + TILEGLOBAL;
+        wallx = (checkx << TILESHIFT) + TILEGLOBAL/2;
+    }
+    else if (ob->angle < 5*FINEANGLES/8)
+    {
+        checkx = ob->tilex - 1;
+        checky = ob->tiley;
+        ob->dir = west;
+        wallx = (checkx << TILESHIFT) + TILEGLOBAL;
+        wally = (checky << TILESHIFT) + TILEGLOBAL/2;
+    }
+    else
+    {
+        checkx = ob->tilex;
+        checky = ob->tiley + 1;
+        ob->dir = south;
+        wally = (checky << TILESHIFT);
+        wallx = (checkx << TILESHIFT) + TILEGLOBAL/2;
+    }
+
+
+    if (actorat[checkx][checky])
+    {
+        tempdoor=(doorobj_t*)actorat[checkx][checky];
+        tempactor = (objtype*)actorat[checkx][checky];
+        tempwall = (wall_t*)actorat[checkx][checky];
+    }
+    doorn = tilemap[checkx][checky] & ~0x2000;
+//      if (sprites[checkx][checky])
+//       tempsprite = sprites[checkx][checky];
+    if (doorn == (elevatorstart + 6))
+        return;
+
+    //bna ++ jumpmode
+    //SetTextMode (  );
+    if (!BATTLEMODE) { //dont use jump in battle, spoils sync
+        if (usejump == true) {
+            if (pstate->buttonheld[bt_use]) {
+                if ((AreJumping == false)&&(ob->z > 0)&&(doorn==0)) {
+                    oldzval = ob->z;
+                    ob->z -= 15;
+                    ob->momentumz += GRAVITY;
+                    AreJumping = true;
+                    donttilt=10;
+                    return;
+                }
+                AreJumping = false;
+                return;
+            }
+        }
+    }
+    //bna
+
+
+    if (pstate->buttonheld[bt_use])
+        return;
+
+    if (doorn == (elevatorstart + 1))
+    {
+        tilemap[checkx][checky]++;              // flip switch
+        if (MAPSPOT(ob->tilex,ob->tiley,1) == ALTELEVATORTILE);
+        // playstate = ex_secretlevel;
+        else if (ob==player)
+            playstate = ex_completed;
+    }
+
+
+    else if (doorn == (elevatorstart + 5))
+
+    {
+        elevnum = MAPSPOT(ob->tilex,ob->tiley,1) - 90;
+        tempwall->flags |= FL_S_FLIPPED;
+        OperateElevatorSwitch(ob,elevnum,checkx,checky);
+    }
+    else if (tempdoor && tempdoor->which==PWALL)
+    {
+        temppwall=(pwallobj_t *)tempdoor;
+        OperatePushWall (temppwall->num,ob->dir, ob == player );
+    }
+    else if ((doorn&0x8000) && (!(doorn&0x4000)))
+    {
+        doorobj_t* dptr = doorobjlist[doorn&0x3ff];
+        int dnum = doorn&0x3ff;
+        int lock;
+
+        OperateDoor (pstate->keys, dnum, (ob == player));
+        if (dptr->eindex != -1)
+        {
+            elevator_t*eptr;
+
+
+            lock = dptr->lock;
+            if ( lock && !( pstate->keys & ( 1 << ( lock - 1 ) ) ) )
+            {
+                if (ob==player)
+                {
+                    // locked
+                    switch (lock)
+                    {
+                    case 1:
+                        AddMessage("You need the \\EGOLD key",MSG_DOOR);
+                        break;
+
+                    case 2:
+                        AddMessage("You need the \\FSILVER key",MSG_DOOR);
+                        break;
+
+                    case 3:
+                        AddMessage("You need the \\8IRON key",MSG_DOOR);
+                        break;
+
+                    case 4:
+                        AddMessage("You need the \\AOSCURO key",MSG_DOOR);
+                        break;
+
+                    default:
+                        AddMessage("This door appears to be locked",MSG_DOOR);
+                        break;
+                    }
+
+                    SD_Play( SD_NOITEMSND );
+                }
+                return;
+            }
+
+            eptr = &ELEVATOR[dptr->eindex];
+            if (((dnum == eptr->door1) && (eptr->state == ev_rad)) ||
+                    ((dnum == eptr->door2) && (eptr->state == ev_ras))
+               )
+                if (ob == player)
+                    AddMessage("Elevator is on the way.",MSG_GAME);
+
+            OperateElevatorDoor(dnum);
+        }
+
+    }
+
+    else if ((tempactor) && (tempactor->which == ACTOR) &&
+             (tempactor->obclass == pillarobj) &&
+             DISTOK(ob->x,tempactor->x,TD) &&
+             DISTOK(ob->y,tempactor->y,TD) &&
+             (!(tempactor->flags & FL_DONE)) &&
+             (!MAPSPOT(tempactor->tilex,tempactor->tiley,2))
+            )
+
+    {   if ((tempactor->dir == nodir) ||
+                (tempactor->dir == ob->dir))
+        {   if (tempactor->dir == nodir)
+            {
+                tempactor->dir = ob->dir;
+                ParseMomentum(tempactor,dirangle8[tempactor->dir]);
+            }
+            SD_PlaySoundRTP ( SD_PUSHWALLSND, tempactor->x, tempactor->y );
+            tempactor->flags |= FL_ACTIVE;
+            tempactor->flags |= FL_FLIPPED;
+//               MakeActive(tempactor);
+            tempactor->whatever = ob;
+            gamestate.secretcount++;
+        }
+
+    }
+    else if ((tempwall) && (tempwall->which == WALL) &&
+             (tempwall->flags & FL_SWITCH) )
+    {
+        tempwall->flags |= FL_S_FLIPPED;
+        if ((tempwall->flags & FL_W_INVERTED) &&
+                DISTOK(ob->x,wallx,TD) &&
+                DISTOK(ob->y,wally,TD) &&
+                DISTOK(ob->z,0,32)
+           )
+        {
+            index = touchindices[checkx][checky]-1;
+            if (!(tempwall->flags & FL_ON))
+            {
+                maskobjlist[tilemap[checkx][checky]&0x3ff]->toptexture++;
+                tempwall->flags |= FL_ON;
+                TRIGGER[index] = 1;
+                SD_PlaySoundRTP(SD_TOUCHPLATESND,ob->x,ob->y);
+                if (ob==player)
+                    AddMessage("Switch turned on.",MSG_GAME);
+            }
+            else if (tempwall->flags & FL_REVERSIBLE)
+            {
+                maskobjlist[tilemap[checkx][checky]&0x3ff]->toptexture--;
+                tempwall->flags &= ~FL_ON;
+                TRIGGER[index] = 1;
+                SD_PlaySoundRTP(SD_TOUCHPLATESND,ob->x,ob->y);
+                if (ob==player)
+                    AddMessage("Switch turned off.",MSG_GAME);
+            }
+
+        }
+        else if (DISTOK(ob->x,wallx,TD) &&
+                 DISTOK(ob->y,wally,TD) &&
+                 !(tempwall->flags & FL_W_INVERTED)
+                )
+        {
+            index = touchindices[checkx][checky]-1;
+            if (!(tempwall->flags & FL_ON))
+            {
+                tilemap[checkx][checky]++;
+                tempwall->flags |= FL_ON;
+                TRIGGER[index] = 1;
+                SD_PlaySoundRTP(SD_TOUCHPLATESND,ob->x,ob->y);
+                if (ob==player)
+                    AddMessage("Switch turned on.",MSG_GAME);
+            }
+            else if (tempwall->flags & FL_REVERSIBLE)
+            {
+                tilemap[checkx][checky]--;
+                tempwall->flags &= ~FL_ON;
+                TRIGGER[index] = 1;
+                SD_PlaySoundRTP(SD_TOUCHPLATESND,ob->x,ob->y);
+                if (ob==player)
+                    AddMessage("Switch turned off.",MSG_GAME);
+            }
+
+        }
+    }
+    else if ((tempwall) && (tempwall->which == WALL) && (ob==player)) {
+        PlayNoWaySound();
+        //bna ++ jumpmode
+        //SetTextMode (  );
+        if (!BATTLEMODE) { //dint use jump in battle, spoils sync
+            if (usejump == true) {
+                if (pstate->buttonheld[bt_use]) {
+                    if ((AreJumping == false)&&(ob->z > 0)&&(doorn==0)) {
+                        oldzval = ob->z;
+                        ob->z -= 15;
+                        ob->momentumz += GRAVITY;
+                        AreJumping = true;
+                        donttilt=10;
+                        return;
+                    }
+                    AreJumping = false;
+                    return;
+                }
+            }
+        }
+        //bna
+    }
+//      else
+//         SD_PlaySoundRTP (SD_NOWAYSND,ob->x,ob->y);
+//   pstate->buttonheld[bt_use] = true;
+}
+
+
+/*
+=============================================================================
+
+						  USER CONTROL
+
+=============================================================================
+*/
+
+
+//******************************************************************************
+//
+// PollKeyboardButtons
+//
+//******************************************************************************
+
+void PollKeyboardButtons (void)
+{
+    int i;
+
+    QueueLetterInput ();
+    IN_UpdateKeyboard();
+
+    for (i = 0; i < NUMBUTTONS; i++)
+    {
+        if (Keystate[buttonscan[i]])
+        {
+            buttonpoll[i] = true;
+        }
+    }
+}
+
+//******************************************************************************
+//
+// PollMouseButtons
+//
+//******************************************************************************
+extern boolean usemouselook;
+void PollMouseButtons (void)
+{
+    int i;
+    int buttons;
+    int mask;
+    int press;
+
+    buttons = IN_GetMouseButtons();
+
+    mask = 1;
+    for( i = 0; i < 3; i++, mask <<= 1 )
+    {
+        press = buttons & mask;
+
+        if ( press )
+        {   //SetTextMode (  );
+//         if ( ( buttonmouse[ i ] != bt_nobutton ) &&
+//            ( DoubleClickCount[ i ] != 2 ) )
+            if ( buttonmouse[ i ] != bt_nobutton )
+            {
+                buttonpoll[ buttonmouse[ i ] ] = true;
+                //bna added
+                if ((i == 1)&&(usemouselook == true)) {
+                    //if rightclick set horizon to 512 (normall)
+                    playertype * pstate;
+                    pstate=&PLAYERSTATE[consoleplayer];
+                    pstate->horizon = 512;
+                    // SetNormalHorizon(PLAYER[0]);
+                }
+                //bna added
+
+            }
+        }
+
+        // Check double-click
+        if ( buttonmouse[ i + 3 ] != bt_nobutton )
+        {
+            if ( press )
+            {
+                // Was the button pressed last tic?
+                if ( !DoubleClickPressed[ i ] )
+                {
+                    // Yes, take note of it
+                    DoubleClickPressed[ i ] = true;
+
+                    // Is this the first click, or a really late click?
+                    if ( ( DoubleClickCount[ i ] == 0 ) ||
+                            ( GetTicCount() >= DoubleClickTimer[ i ] ) )
+                    {
+                        // Yes, now wait for a second click
+                        DoubleClickTimer[ i ] = GetTicCount() + DoubleClickSpeed;
+
+                        //( tics << 5 );
+                        DoubleClickCount[ i ] = 1;
+                    }
+                    else
+                    {
+                        // Second click
+                        buttonpoll[ buttonmouse[ i + 3 ] ] = true;
+                        DoubleClickTimer[ i ] = 0;
+                        DoubleClickCount[ i ] = 2;
+                    }
+                }
+                else
+                {
+                    // After second click, button remains pressed
+                    // until user releases it
+                    if ( DoubleClickCount[ i ] == 2 )
+                    {
+                        buttonpoll[ buttonmouse[ i + 3 ] ] = true;
+                    }
+                }
+            }
+            else
+            {
+                if ( DoubleClickCount[ i ] == 2 )
+                {
+                    DoubleClickCount[ i ] = 0;
+                }
+                DoubleClickPressed[ i ] = false;
+            }
+        }
+    }
+}
+
+
+//******************************************************************************
+//
+// PollJoystickButtons
+//
+//******************************************************************************
+void PollJoystickButtons
+(
+    void
+)
+
+{
+    int i;
+    int buttons;
+    int mask;
+    int num;
+    int press;
+
+    buttons = IN_JoyButtons ();
+
+    if ( joypadenabled )
+    {
+        num = 4;
+        mask = 1;
+    }
+    else
+    {
+        num = 2;
+        if ( joystickport )
+        {
+            mask = 4;
+        }
+        else
+        {
+            mask = 1;
+        }
+    }
+
+    for( i = 0; i < num; i++, mask <<= 1 )
+    {
+        press = buttons & mask;
+
+        if ( press )
+        {
+//         if ( ( buttonjoy[ i ] != bt_nobutton ) &&
+//            ( JoyDblClickCount[ i ] != 2 ) )
+            if ( buttonjoy[ i ] != bt_nobutton )
+            {
+                buttonpoll[ buttonjoy[ i ] ] = true;
+            }
+        }
+
+        // Check double-click
+        if ( buttonjoy[ i + 4 ] != bt_nobutton )
+        {
+            if ( press )
+            {
+                // Was the button pressed last tic?
+                if ( !JoyDblClickPressed[ i ] )
+                {
+                    // Yes, take note of it
+                    JoyDblClickPressed[ i ] = true;
+
+                    // Is this the first click, or a really late click?
+                    if ( ( JoyDblClickCount[ i ] == 0 ) ||
+                            ( GetTicCount() >= JoyDblClickTimer[ i ] ) )
+                    {
+                        // Yes, now wait for a second click
+                        JoyDblClickTimer[ i ] = GetTicCount() + DoubleClickSpeed;
+
+                        //( tics << 5 );
+                        JoyDblClickCount[ i ] = 1;
+                    }
+                    else
+                    {
+                        // Second click
+                        buttonpoll[ buttonjoy[ i + 4 ] ] = true;
+                        JoyDblClickTimer[ i ] = 0;
+                        JoyDblClickCount[ i ] = 2;
+                    }
+                }
+                else
+                {
+                    // After second click, button remains pressed
+                    // until user releases it
+                    if ( JoyDblClickCount[ i ] == 2 )
+                    {
+                        buttonpoll[ buttonjoy[ i + 4 ] ] = true;
+                    }
+                }
+            }
+            else
+            {
+                if ( JoyDblClickCount[ i ] == 2 )
+                {
+                    JoyDblClickCount[ i ] = 0;
+                }
+                JoyDblClickPressed[ i ] = false;
+            }
+        }
+    }
+}
+
+
+//===========================================================================
+
+//******************************************************************************
+//
+// PollKeyboardMove
+//
+//******************************************************************************
+
+void PollKeyboardMove
+(
+    void
+)
+
+{
+    if ( ( buttonpoll[ bt_turnaround ] ) && ( turnaround == 0 ) )
+    {
+        turnaround = 1;
+        turnaroundtime = 15 + tics;
+        turnheldtime = 0;
+    }
+    if ( turnaround == 0 )
+    {
+        if ( buttonpoll[ di_east ] )
+        {
+            turnheldtime+=tics;
+            if (turnheldtime>=TURBOTURNTIME)
+            {
+                KX = -KEYBOARDNORMALTURNAMOUNT;
+            }
+            else
+            {
+                KX = -KEYBOARDPREAMBLETURNAMOUNT;
+            }
+        }
+        else if ( buttonpoll[ di_west ] )
+        {
+            turnheldtime+=tics;
+            if (turnheldtime>=TURBOTURNTIME)
+            {
+                KX = KEYBOARDNORMALTURNAMOUNT;
+            }
+            else
+            {
+                KX = KEYBOARDPREAMBLETURNAMOUNT;
+            }
+        }
+        else
+        {
+            KX = 0;
+            turnheldtime=0;
+        }
+        if ( (buttonpoll[bt_run]) &&
+                ( (turnheldtime>=TURBOTURNTIME) || (turnheldtime==0) )
+           )
+            KX = FixedMul(KX,TURBOTURNAMOUNT);
+    }
+    else
+    {
+        KX=TURNAROUNDSPEED;
+        turnaroundtime-=tics;
+        if (turnaroundtime<=0)
+        {
+            turnaround=0;
+            KX=((turnaroundtime*TURNAROUNDSPEED)>>1);
+        }
+    }
+
+    if ( buttonpoll[ di_north ] )
+    {
+        KY = -BASEMOVE;
+    }
+    else if ( buttonpoll[ di_south ] )
+    {
+        KY = BASEMOVE;
+    }
+    else
+        KY = 0;
+
+    if (buttonpoll[bt_run])
+    {
+        KY <<= 1;
+    }
+}
+
+//******************************************************************************
+//
+// PollMouseMove
+//
+//******************************************************************************
+
+//#define MOUSE_RY_SHIFT 12
+//#define MOUSE_TZ_SHIFT 3
+#define MOUSE_TZ_SENSITIVITY_SCALE 65535
+#define MOUSE_RY_SENSITIVITY_SCALE 18725*2
+//#define MOUSE_RY_INPUT_SCALE 6000
+#define MOUSE_TZ_INPUT_SCALE 20
+int mouse_ry_input_scale = 5000;
+
+int sensitivity_scalar[15] =
+{
+    0,1,2,3,4,5,6,8,11,13,15,18,12,13,14
+};
+//#define MOUSE_RY_SCALE 65535
+//#define MOUSE_TZ_SCALE 65535
+#define MAXMOUSETURN 7000000
+
+/* use SDL mouse */
+#define USESDLMOUSE 1
+
+
+extern int inverse_mouse;
+double Y_MouseSpeed=70;
+
+void PollMouseMove (void)
+{
+    int  mousexmove, mouseymove;
+    double Ys;
+//SetTextMode();
+
+    Ys=(Y_MouseSpeed/100);
+//
+
+// const long inverse_mouse  = 1; //set  to -1 to invert mouse
+// inverse_mouse def moved to RT_CFG.C
+
+#ifdef USESDLMOUSE
+    INL_GetMouseDelta(&mousexmove, &mouseymove);
+#else
+    PollMouse();//Uses DirectInput mouse in DInput.cpp
+    mousexmove=MX;
+    mouseymove=MY;
+#endif
+
+    if (abs(mousexmove)>abs(mouseymove))
+        mouseymove/=2;
+    else
+        mousexmove/=2;
+    MX = 0;
+    MY = 0;
+
+
+    if ((abs (mouseymove)) >= threshold)
+    {   //
+        MY =  MOUSE_TZ_INPUT_SCALE*mouseymove;
+        MY *= inverse_mouse;
+        if (usemouselook == true) {
+            if (MY > 0) {
+                playertype * pstate;
+                pstate=&PLAYERSTATE[consoleplayer];
+                //if (pstate->horizon > 512){
+                pstate->horizon -= Ys * (2*sensitivity_scalar[mouseadjustment]);
+                //}
+            }
+            else if (MY < 0) {
+                playertype * pstate;
+                pstate=&PLAYERSTATE[consoleplayer];
+                //SetTextMode (  );
+                pstate->horizon += Ys * (2*sensitivity_scalar[mouseadjustment]);
+                //buttonpoll[ bt_horizonup ] = true;
+            }
+            MY = 0;
+        } else {
+            // MY += FixedMul(MY,mouseadjustment*MOUSE_TZ_SENSITIVITY_SCALE);
+            if (abs(mouseymove)>200)
+            {
+                buttonpoll[bt_run]=true;
+                // buttonpoll[ bt_lookup ] = true;
+            }
+        }
+    }
+
+
+
+
+
+    if ((abs (mousexmove)) >= threshold)
+    {
+        //MX = -MOUSE_RY_INPUT_SCALE*mousexmove;
+        MX = -mouse_ry_input_scale*mousexmove;
+        MX += FixedMul(MX,sensitivity_scalar[mouseadjustment]*MOUSE_RY_SENSITIVITY_SCALE);
+        //   if (abs(MX) > MAXMOUSETURN)
+        //   MX = MAXMOUSETURN*SGN(MX);
+        if (usemouselook == true) {
+            if (abs(mouseymove)>10)
+            {
+                buttonpoll[bt_run]=true;
+                //buttonpoll[ bt_lookdown ] = true;
+            }
+        }
+    }
+//   if (MY > 0)
+//      MX -= (MX/2);
+
+//   MX=0;
+//   MY=0;
+
+}
+
+
+//******************************************************************************
+//
+// PollJoystickMove
+//
+//******************************************************************************
+
+void PollJoystickMove (void)
+{
+    int   joyx,joyy;
+
+    INL_GetJoyDelta (joystickport, &joyx, &joyy);
+    if ( joypadenabled )
+    {
+        if (joyx >= threshold)
+        {
+            buttonpoll[ di_east ] = true;
+        }
+        if (-joyx >= threshold)
+        {
+            buttonpoll[ di_west ] = true;
+        }
+        if ( joyy >= threshold )
+        {
+            buttonpoll[ di_south ] = true;
+        }
+        if ( -joyy >= threshold )
+        {
+            buttonpoll[ di_north ] = true;
+        }
+    }
+    else
+    {
+        if ((abs (joyx)) >= threshold)
+        {
+            JX = ((-joyx)<<13)+((-joyx)<<11);
+            turnheldtime += tics;
+        }
+        else
+            JX = 0;
+
+        if ((abs (joyy)) >= threshold)
+        {
+            JY = joyy<<4;
+        }
+        else
+            JY = 0;
+        if (buttonpoll[bt_run])
+        {
+            JX <<= 1;
+            JY <<= 1;
+        }
+    }
+}
+
+//******************************************************************************
+//
+// StartVRFeedback
+//
+//******************************************************************************
+
+void StartVRFeedback (int guntype)
+{
+#ifdef DOS
+    union REGS inregs;
+    union REGS outregs;
+
+    inregs.x.eax = VR_FEEDBACK_SERVICE;
+    inregs.x.ebx = 1;
+    inregs.x.ecx = guntype;
+    int386 (0x33, &inregs, &outregs);
+#else
+    STUB_FUNCTION;
+#endif
+}
+
+//******************************************************************************
+//
+// StopVRFeedback
+//
+//******************************************************************************
+
+void StopVRFeedback (void)
+{
+#ifdef DOS
+    union REGS inregs;
+    union REGS outregs;
+
+    inregs.x.eax = VR_FEEDBACK_SERVICE;
+    inregs.x.ebx = 0;
+    int386 (0x33, &inregs, &outregs);
+#else
+    STUB_FUNCTION;
+#endif
+}
+
+//******************************************************************************
+//
+// PollVirtualReality
+//
+//******************************************************************************
+
+#define VR_BUTTON(x) ((vr_buttons>>x) & 1)
+
+void PollVirtualReality (void)
+{
+#ifdef DOS
+    union REGS inregs;
+    union REGS outregs;
+    short int  mousexmove,
+          mouseymove;
+    word vr_buttons;
+
+    inregs.x.eax = VR_INPUT_SERVICE;
+
+    inregs.x.ebx = player->angle;
+    inregs.x.ecx = player->yzangle;
+
+    int386 (0x33, &inregs, &outregs);
+
+    vr_buttons = outregs.w.bx;
+
+    buttonpoll[bt_run          ] |= VR_BUTTON(VR_RUNBUTTON          );
+    buttonpoll[bt_strafeleft   ] |= VR_BUTTON(VR_STRAFELEFTBUTTON   );
+    buttonpoll[bt_straferight  ] |= VR_BUTTON(VR_STRAFERIGHTBUTTON  );
+    buttonpoll[bt_attack       ] |= VR_BUTTON(VR_ATTACKBUTTON       );
+    buttonpoll[bt_lookup       ] |= VR_BUTTON(VR_LOOKUPBUTTON       );
+    buttonpoll[bt_lookdown     ] |= VR_BUTTON(VR_LOOKDOWNBUTTON     );
+    buttonpoll[bt_swapweapon   ] |= VR_BUTTON(VR_SWAPWEAPONBUTTON   );
+    buttonpoll[bt_use          ] |= VR_BUTTON(VR_USEBUTTON          );
+    buttonpoll[bt_horizonup    ] |= VR_BUTTON(VR_HORIZONUPBUTTON    );
+    buttonpoll[bt_horizondown  ] |= VR_BUTTON(VR_HORIZONDOWNBUTTON  );
+    buttonpoll[bt_map          ] |= VR_BUTTON(VR_MAPBUTTON          );
+    buttonpoll[bt_pistol       ] |= VR_BUTTON(VR_PISTOLBUTTON       );
+    buttonpoll[bt_dualpistol   ] |= VR_BUTTON(VR_DUALPISTOLBUTTON   );
+    buttonpoll[bt_mp40         ] |= VR_BUTTON(VR_MP40BUTTON         );
+    buttonpoll[bt_missileweapon] |= VR_BUTTON(VR_MISSILEWEAPONBUTTON);
+    buttonpoll[bt_recordsound  ] |= VR_BUTTON(VR_RECORDBUTTON       );
+
+    mousexmove = outregs.w.cx;
+    mouseymove = outregs.w.dx;
+
+    VX = 0;
+    VY = 0;
+
+
+    if ((abs (mouseymove)) >= threshold)
+    {
+        VY =  MOUSE_TZ_INPUT_SCALE*mouseymove;
+        if (abs(mouseymove)>200)
+        {
+            buttonpoll[bt_run]=true;
+        }
+    }
+
+    if ((abs (mousexmove)) >= threshold)
+    {
+        VX = -mouse_ry_input_scale*mousexmove;
+        VX += FixedMul(MX,sensitivity_scalar[mouseadjustment]*MOUSE_RY_SENSITIVITY_SCALE);
+        if (abs(mousexmove)>10)
+        {
+            buttonpoll[bt_run]=true;
+        }
+    }
+#else
+    STUB_FUNCTION;
+#endif
+}
+
+
+//******************************************************************************
+//
+// PollMove ()
+//
+//******************************************************************************
+
+boolean aimbuttonpressed=false;
+void PollMove (void)
+{
+    int angle;
+    int x, y;
+
+
+    x = KX + MX + JX + CX + VX;
+    y = KY + MY + JY + CY + VY;
+
+    if (buttonpoll[bt_aimbutton])
+    {
+        if (y>0)
+        {
+            buttonpoll[bt_horizonup]=1;
+            y=0;
+            aimbuttonpressed=true;
+        }
+        else if (y<0)
+        {
+            buttonpoll[bt_horizondown]=1;
+            y=0;
+            aimbuttonpressed=true;
+        }
+        else if (aimbuttonpressed==false)
+        {
+            buttonpoll[bt_lookup]=1;
+            buttonpoll[bt_lookdown]=1;
+        }
+    }
+    else
+    {
+        aimbuttonpressed=false;
+    }
+
+    if (player->flags & FL_FLEET)
+        y += y>>1;
+
+    if ((locplayerstate->NETCAPTURED == 1) && (!locplayerstate->HASKNIFE))
+    {
+        if (first)
+        {
+            nettics = GetTicCount() + (VBLCOUNTER * 4);
+            first = 0;
+        }
+
+        if (x > 0)
+        {
+            rightmom += NETMOM;
+            if (lastmom!=0)
+                controlbuf[2]=x<<1;
+            lastmom=0;
+        }
+        else if (x < 0)
+        {
+            leftmom += NETMOM;
+            if (lastmom!=1)
+                controlbuf[2]=x<<1;
+            lastmom=1;
+        }
+        else
+        {
+            rightmom -= (NETMOM >> 2);
+            if (rightmom < 0)
+                rightmom = 0;
+            leftmom  -= (NETMOM >> 2);
+            if (leftmom < 0)
+                leftmom = 0;
+        }
+
+        if ((GetTicCount() > nettics) && (rightmom > (NETMOM * 2)) &&
+                (leftmom > (NETMOM * 2)))
+        {
+            rightmom = 0;
+            leftmom  = 0;
+            first    = 1;
+            lastmom^=1;
+            locplayerstate->NETCAPTURED = 0;
+            MISCVARS->NET_IN_FLIGHT = false;
+            NewState(player, &s_player);
+            locplayerstate->weaponuptics = WEAPONS[locplayerstate->weapon].screenheight/GMOVE;
+            locplayerstate->weaponheight = locplayerstate->weaponuptics*GMOVE ;
+        }
+    }
+    else if ((buttonpoll[bt_strafe]) && (turnaround==0))
+    {
+        // strafing
+        if (x < 0)
+        {
+            angle = (player->angle - FINEANGLES/4)&(FINEANGLES-1);
+
+            x = (x>>10) + (x >> 11);
+
+            controlbuf[0] = -(FixedMul (x, costable[angle]));
+            controlbuf[1] = FixedMul (x, sintable[angle]);
+        }
+        else if (x > 0)
+        {
+            angle = (player->angle + FINEANGLES/4)&(FINEANGLES-1);
+
+            x = (x>>10) + (x >> 11);
+
+            controlbuf[0] = FixedMul (x, costable[angle]);
+            controlbuf[1] = -(FixedMul (x, sintable[angle]));
+        }
+        if (y != 0)
+        {
+            controlbuf[0] += -(FixedMul (y, viewcos));
+            controlbuf[1] += (FixedMul (y, viewsin));
+        }
+    }
+    else
+    {
+        if (y != 0)
+        {
+            controlbuf[0] = -FixedMul (y, viewcos);
+            controlbuf[1] = FixedMul (y, viewsin);
+        }
+
+        if (x != 0)
+            controlbuf[2] = x;
+    }
+
+    if (buttonpoll[bt_strafeleft])
+    {
+        angle = (player->angle - FINEANGLES/4)&(FINEANGLES-1);
+        controlbuf[0] += -(FixedMul (STRAFEAMOUNT, costable[angle]));
+        controlbuf[1] +=   FixedMul (STRAFEAMOUNT, sintable[angle]);
+    }
+    else if (buttonpoll[bt_straferight])
+    {
+        angle = (player->angle + FINEANGLES/4)&(FINEANGLES-1);
+        controlbuf[0] += -(FixedMul (STRAFEAMOUNT, costable[angle]));
+        controlbuf[1] +=   FixedMul (STRAFEAMOUNT, sintable[angle]);
+    }
+}
+
+
+//******************************************************************************
+//
+// PollCyberman ()
+//
+//******************************************************************************
+
+void PollCyberman (void)
+{
+    int i;
+    int mask;
+    int press;
+
+    SWIFT_Get3DStatus (&SWIFTStatus);
+
+    mask = 4;
+    for( i = 0; i < 3; i++, mask >>= 1 )
+    {
+        press = SWIFTStatus.buttons & mask;
+
+        if ( press )
+        {
+//         if ( ( buttonmouse[ i ] != bt_nobutton ) &&
+//            ( DoubleClickCount[ i ] != 2 ) )
+            if ( buttonmouse[ i ] != bt_nobutton )
+            {
+                buttonpoll[ buttonmouse[ i ] ] = true;
+            }
+        }
+
+        // Check double-click
+        if ( buttonmouse[ i + 3 ] != bt_nobutton )
+        {
+            if ( press )
+            {
+                // Was the button pressed last tic?
+                if ( !DoubleClickPressed[ i ] )
+                {
+                    // Yes, take note of it
+                    DoubleClickPressed[ i ] = true;
+
+                    // Is this the first click, or a really late click?
+                    if ( ( DoubleClickCount[ i ] == 0 ) ||
+                            ( GetTicCount() >= DoubleClickTimer[ i ] ) )
+                    {
+                        // Yes, now wait for a second click
+                        DoubleClickTimer[ i ] = GetTicCount() + DoubleClickSpeed;
+
+                        //( tics << 5 );
+                        DoubleClickCount[ i ] = 1;
+                    }
+                    else
+                    {
+                        // Second click
+                        buttonpoll[ buttonmouse[ i + 3 ] ] = true;
+                        DoubleClickTimer[ i ] = 0;
+                        DoubleClickCount[ i ] = 2;
+                    }
+                }
+                else
+                {
+                    // After second click, button remains pressed
+                    // until user releases it
+                    if ( DoubleClickCount[ i ] == 2 )
+                    {
+                        buttonpoll[ buttonmouse[ i + 3 ] ] = true;
+                    }
+                }
+            }
+            else
+            {
+                if ( DoubleClickCount[ i ] == 2 )
+                {
+                    DoubleClickCount[ i ] = 0;
+                }
+                DoubleClickPressed[ i ] = false;
+            }
+        }
+    }
+
+    if (SWIFTStatus.pitch > 0)
+        CYBERLOOKUP = true;
+    else if (SWIFTStatus.pitch < 0)
+        CYBERLOOKDOWN = true;
+
+    if ((abs (SWIFTStatus.x)) > CYBERDEADRANGE)
+    {
+        CX = -(SGN (SWIFTStatus.x) * (( (abs(SWIFTStatus.x)-CYBERDEADRANGE) ) << 10));
+        turnheldtime += tics;
+    }
+    else if (SWIFTStatus.x != oldcyberx)
+    {
+        turnheldtime += tics;
+        if (SWIFTStatus.x > oldcyberx)
+            CX = -(0xB8000);
+        else
+            CX = 0xB8000;
+
+        oldcyberx = SWIFTStatus.x;
+    }
+    else
+        CX = 0;
+
+    if ((abs (SWIFTStatus.y)) > CYBERDEADRANGE)
+    {
+        CY = SWIFTStatus.y >> 2;
+    }
+    else
+        CY = 0;
+}
+
+//******************************************************************************
+//
+// PollAssassin ()
+//
+//******************************************************************************
+
+#define MAXRAMPS 5
+typedef struct
+{
+    int  min;
+    int  factor;
+} RampType;
+void PollAssassin (void)
+{
+    int i;
+    int mask;
+    int press;
+    int yaw;
+    int strafeAngle;
+    int acc;
+    int numramps=4;
+    RampType ramp[MAXRAMPS]= {
+        {0,280000},
+        {4,380000},
+        {10,480000},
+        {25,680000},
+//                              {25,( (1<<26)/80  )}
+    };
+
+    SWIFT_Get3DStatus (&SWIFTStatus);
+
+    mask = 4;
+    for( i = 0; i < 3; i++, mask >>= 1 )
+    {
+        press = SWIFTStatus.buttons & mask;
+
+        if ( press )
+        {
+//         if ( ( buttonmouse[ i ] != bt_nobutton ) &&
+//            ( DoubleClickCount[ i ] != 2 ) )
+            if ( buttonmouse[ i ] != bt_nobutton )
+            {
+                buttonpoll[ buttonmouse[ i ] ] = true;
+            }
+        }
+
+        // Check double-click
+        if ( buttonmouse[ i + 3 ] != bt_nobutton )
+        {
+            if ( press )
+            {
+                // Was the button pressed last tic?
+                if ( !DoubleClickPressed[ i ] )
+                {
+                    // Yes, take note of it
+                    DoubleClickPressed[ i ] = true;
+
+                    // Is this the first click, or a really late click?
+                    if ( ( DoubleClickCount[ i ] == 0 ) ||
+                            ( GetTicCount() >= DoubleClickTimer[ i ] ) )
+                    {
+                        // Yes, now wait for a second click
+                        DoubleClickTimer[ i ] = GetTicCount() + DoubleClickSpeed;
+
+                        //( tics << 5 );
+                        DoubleClickCount[ i ] = 1;
+                    }
+                    else
+                    {
+                        // Second click
+                        buttonpoll[ buttonmouse[ i + 3 ] ] = true;
+                        DoubleClickTimer[ i ] = 0;
+                        DoubleClickCount[ i ] = 2;
+                    }
+                }
+                else
+                {
+                    // After second click, button remains pressed
+                    // until user releases it
+                    if ( DoubleClickCount[ i ] == 2 )
+                    {
+                        buttonpoll[ buttonmouse[ i + 3 ] ] = true;
+                    }
+                }
+            }
+            else
+            {
+                if ( DoubleClickCount[ i ] == 2 )
+                {
+                    DoubleClickCount[ i ] = 0;
+                }
+                DoubleClickPressed[ i ] = false;
+            }
+        }
+    }
+
+    buttonpoll[bt_horizonup] |=   ((SWIFTStatus.buttons>>7) & 1);
+    buttonpoll[bt_horizondown] |= ((SWIFTStatus.buttons>>8) & 1);
+
+    if ( abs(SWIFTStatus.pitch) < (20<<6) )
+    {
+        SWIFTStatus.pitch = 0;
+    }
+    else
+    {
+        SWIFTStatus.pitch -= SGN(SWIFTStatus.pitch)*(20<<6);
+    }
+
+    if ( abs(SWIFTStatus.pitch) > (60<<6) )
+    {
+        buttonpoll[bt_run] = 1;
+    }
+
+    if ( abs(SWIFTStatus.roll) > (80<<6) )
+    {
+        buttonpoll[bt_run] = 1;
+    }
+
+
+    if ( abs(SWIFTStatus.roll) < (20<<6) )
+    {
+        SWIFTStatus.roll = 0;
+    }
+    else
+    {
+        SWIFTStatus.roll -= SGN(SWIFTStatus.roll)*(20<<6);
+    }
+
+    strafeAngle = (player->angle - FINEANGLES/4)&(FINEANGLES-1);
+
+    controlbuf[0] += -(FixedMulShift (SWIFTStatus.pitch, viewcos,16))+
+                     FixedMulShift (-SWIFTStatus.roll, costable[strafeAngle], 16);
+
+    controlbuf[1] +=  FixedMulShift (SWIFTStatus.pitch, viewsin,16) -
+                      FixedMulShift (-SWIFTStatus.roll, sintable[strafeAngle], 16);
+
+    yaw = abs(SWIFTStatus.yaw);
+    acc = 0;
+    for (i=0; i<numramps; i++)
+    {
+        if (yaw > ramp[i].min)
+        {
+            if (i>0)
+            {
+                acc += ramp[i].min*(ramp[i].factor-ramp[i-1].factor);
+            }
+        }
+        else
+        {
+            i++;
+            break;
+        }
+    }
+    controlbuf[2]= SWIFTStatus.yaw * ramp[i-1].factor - acc;
+}
+
+
+//******************************************************************************
+//
+// PollControls
+//
+// Gets user or demo input, call once each frame
+//
+// controlx     set between -100 and 100 per tic
+// controly
+//
+//******************************************************************************
+
+
+void PollControls (void)
+{
+    int   i;
+
+    if (standalone==true)
+        return;
+
+    lastpolltime=controlupdatetime;
+
+    memset (buttonpoll, 0, sizeof(buttonpoll));
+
+    controlbuf[0] = controlbuf[1] = controlbuf[2] = 0;
+    CYBERLOOKUP = CYBERLOOKDOWN = false;
+
+    if (gamestate.autorun==1)
+        buttonpoll[bt_run] = true;
+
+
+//
+// get button states
+//
+    PollKeyboardButtons ();
+
+    if (mouseenabled && !cybermanenabled)
+        PollMouseButtons ();
+
+    if (joystickenabled)
+        PollJoystickButtons ();
+
+
+//
+// get movements
+//
+    if (joystickenabled)
+        PollJoystickMove ();
+
+    if (cybermanenabled)
+        PollCyberman ();
+
+    else if (mouseenabled && MousePresent)
+        PollMouseMove ();
+
+    PollKeyboardMove ();
+
+    if (vrenabled)
+        PollVirtualReality ();
+
+    PollMove ();
+
+    if (spaceballenabled)
+        PollSpaceBall ();
+
+    else if (assassinenabled)
+        PollAssassin ();
+
+
+    buttonbits = 0;
+    if (player->flags & FL_DYING) // Player has died
+    {
+        if ((playerdead==true) &&
+                ( buttonpoll[ bt_strafe ] ||
+                  buttonpoll[ bt_attack ] ||
+                  buttonpoll[ bt_use ] ||
+                  ((gamestate.battlemode == battle_Hunter) &&
+                   (BATTLE_Team[player->dirchoosetime] == BATTLE_It)
+                  )
+                )
+           )
+        {
+            AddRespawnCommand();
+        }
+        memset (buttonpoll, 0, sizeof(buttonpoll));
+        controlbuf[0] = controlbuf[1] = controlbuf[2] = 0;
+    }
+
+    if ((PausePressed==true) && (modemgame==false))
+    {
+        PausePressed=false;
+        if (GamePaused==true)
+            AddPauseStateCommand(COM_UNPAUSE);
+        else
+        {
+            AddPauseStateCommand(COM_PAUSE);
+        }
+    }
+    if (Keyboard[sc_Insert] && Keyboard[sc_X]) {
+        AddExitCommand();
+    }
+//bna section
+    if (Keyboard[sc_5]) {
+        //	 SetTextMode (  );
+        weaponscale +=  1000;
+        //testval++;
+    }
+    if (Keyboard[sc_6]) {
+        //	 SetTextMode (  );
+        weaponscale -=  1000;
+        //  testval--;
+    }
+//bna section end
+
+    for (i = (NUMTXBUTTONS-1); i >= 0; i--)
+    {
+        buttonbits <<= 1;
+        if (buttonpoll[i])
+            buttonbits |= 1;
+    }
+
+    UpdateClientControls();
+}
+
+
+void ResetWeapons(objtype *ob)
+{   playertype *pstate;
+
+    M_LINKSTATE(ob,pstate);
+
+    pstate->weapondowntics = WEAPONS[pstate->weapon].screenheight/GMOVE;
+    pstate->new_weapon = pstate->oldweapon;
+    pstate->missileweapon = pstate->oldmissileweapon;
+    ob->shapeoffset = pstate->oldshapeoffset;
+    pstate->attackframe = pstate->weaponframe = 0;
+
+    if ((ob==player) && SHOW_BOTTOM_STATUS_BAR() )
+        DrawBarAmmo (false);
+}
+
+
+
+
+void SaveWeapons(objtype*ob)
+{   playertype *pstate;
+
+    if ((ob->flags&FL_DOGMODE) || (ob->flags&FL_GODMODE))
+        return;
+
+//pstate = (ob==player)?(&playerstate):(&remoteplayerstate);
+    M_LINKSTATE(ob,pstate);
+
+    pstate->weapondowntics = WEAPONS[pstate->weapon].screenheight/GMOVE;
+    pstate->oldweapon = pstate->new_weapon;
+    pstate->oldmissileweapon = pstate->missileweapon;
+    pstate->oldshapeoffset = ob->shapeoffset;
+
+}
+
+/*
+void SaveWeapons(objtype*ob)
+{playertype *pstate;
+
+ if ((ob->flags&FL_DOGMODE) || (ob->flags&FL_GODMODE))
+    return;
+
+ //pstate = (ob==player)?(&playerstate):(&remoteplayerstate);
+ M_LINKSTATE(ob,pstate);
+
+ pstate->weapondowntics = WEAPONS[pstate->weapon].screenheight/GMOVE;
+ pstate->oldweapon = pstate->weapon;
+ pstate->oldmissileweapon = pstate->missileweapon;
+ pstate->oldshapeoffset = ob->shapeoffset;
+
+}
+*/
+
+
+#define GiveProtection(flag,time,sound)                  \
+   {                                                     \
+   if ((ob->flags & flag) || (ob->flags & FL_GODMODE) || \
+       (ob->flags & FL_DOGMODE))                         \
+      return;                                            \
+   ob->flags &= ~(FL_BPV|FL_GASMASK|FL_AV);              \
+   ob->flags |= flag;                                    \
+   SD_PlaySoundRTP(sound,ob->x, ob->y);                  \
+   pstate->protectiontime = time;                        \
+   gamestate.supercount ++;                              \
+   }
+
+
+
+
+boolean GivePowerup(objtype *ob,int flag,int time,int sound)
+{
+    playertype *pstate;
+
+
+    if ((ob->flags & flag) ||
+            (ob->flags & FL_GODMODE) ||
+            (ob->flags & FL_DOGMODE)
+       )
+        return false;
+
+
+    M_LINKSTATE(ob,pstate);
+
+    /*
+    if (ob->flags & FL_DOGMODE)
+       {
+       ob->temp2 = DOGMODERISE;
+       ResetWeapons(ob);
+       if (ob->state->condition & SF_DOGSTATE)
+          NewState(ob,&s_player);
+       }
+    else if (ob->flags & FL_GODMODE)
+       {
+       ob->temp2 = GODMODEFALL;
+       ResetWeapons(ob);
+       }
+    */
+    ob->flags &= ~(FL_SHROOMS|FL_FLEET|FL_ELASTO|FL_GODMODE|FL_DOGMODE);
+    ob->flags |= flag;
+    pstate->poweruptime = time;
+    pstate->soundtime = 0;
+    SD_PlaySoundRTP(sound,ob->x, ob->y);
+    gamestate.supercount ++;
+    return true;
+
+}
+
+
+
+void GiveLifePoints(objtype *ob,int points)
+{
+    SD_PlaySoundRTP(SD_GETBONUSSND,ob->x, ob->y);
+
+    UpdateTriads (ob,points);
+    if (ob==player)
+        DrawTriads (false);
+
+}
+
+
+boolean GiveBulletWeapon(objtype *ob,int bulletweapon,statobj_t*check)
+{
+    playertype *pstate;
+
+    M_LINKSTATE(ob,pstate);
+
+    if ((ob->flags & FL_DOGMODE) || (ob->flags & FL_GODMODE))
+        return false;
+
+    if (!ARMED(ob->dirchoosetime))
+        return false;
+
+    if (pstate->HASBULLETWEAPON[bulletweapon])
+        return false;
+
+    GiveWeapon(ob,bulletweapon);
+    if ( gamestate.BattleOptions.WeaponPersistence )
+    {
+        LASTSTAT->z = check->z;
+    }
+    SD_PlaySoundRTP(SD_GETWEAPONSND,ob->x, ob->y);
+    return true;
+
+}
+
+inline boolean DetermineAmmoPickup(playertype *pstate, statobj_t *check)
+{
+    if ((GetWeaponForItem(check->itemnumber) == pstate->missileweapon) &&
+            (pstate->ammo < stats[check->itemnumber].ammo))
+    {
+        return true;
+    }
+    else
+    {
+        return false;
+    }
+}
+
+extern boolean enableAmmoPickups;
+boolean wasAmmoPickup = false;
+
+boolean GivePlayerMissileWeapon(objtype *ob, playertype *pstate,
+                                statobj_t *check)
+{
+    if  ((ob->flags & FL_DOGMODE) || (ob->flags & FL_GODMODE))
+        return false;
+
+
+    if (!ARMED(ob->dirchoosetime))
+        return false;
+
+    if ((GetWeaponForItem(check->itemnumber) == pstate->missileweapon) &&
+            (check->ammo == stats[check->itemnumber].ammo) &&
+            (pstate->ammo == stats[check->itemnumber].ammo)
+       )
+        return false;
+    
+    else if ((GetWeaponForItem(check->itemnumber) == pstate->missileweapon) &&
+            (check->ammo == stats[check->itemnumber].ammo) &&
+            (pstate->ammo >= stats[check->itemnumber].ammo)
+       )
+        return false;
+
+    
+
+    //LT added, this bit here handles ammo pickups if that option's enabled
+    if (enableAmmoPickups && DetermineAmmoPickup(pstate, check))
+    {
+        wasAmmoPickup = true;
+        GivePlayerAmmo(ob, check, GetWeaponForItem(check->itemnumber));
+        if ((ob==player) && SHOW_BOTTOM_STATUS_BAR() )
+            DrawBarAmmo (false);
+        SD_PlaySoundRTP(SD_GETWEAPONSND,ob->x, ob->y);
+        return true;
+    }
+
+    else if ((GetWeaponForItem(check->itemnumber) == pstate->missileweapon) &&
+            (pstate->ammo >= check->ammo) && enableAmmoPickups)
+        return false;
+    
+    SD_PlaySoundRTP(SD_GETWEAPONSND,ob->x, ob->y);
+    
+    GiveMissileWeapon(ob,GetWeaponForItem(check->itemnumber));
+    if (gamestate.BattleOptions.WeaponPersistence)
+        LASTSTAT->z = check->z;
+
+    gamestate.missilecount ++;
+
+    if (BATTLEMODE && (gamestate.BattleOptions.Ammo != bo_normal_shots))
+    {   if (gamestate.BattleOptions.Ammo == bo_one_shot)
+            pstate->ammo = 1;
+        else
+            pstate->ammo = -1;
+    }
+    else
+        pstate->ammo = check->ammo;
+    if ((ob==player) && SHOW_BOTTOM_STATUS_BAR() )
+        DrawBarAmmo (false);
+
+    return true;
+
+}
+
+
+#define LocalBonusMessage(string)  \
+   {                               \
+   if (ob == player)               \
+     AddMessage(string,MSG_BONUS); \
+   }
+#define LocalBonus1Message(string)  \
+   {                               \
+   if (ob == player)               \
+     AddMessage(string,MSG_BONUS1); \
+   }
+
+
+/*
+=================================
+=
+=   GetBonusTimeForItem
+=
+=================================
+*/
+
+int GetBonusTimeForItem(int itemnumber)
+{
+    specials *which;
+
+    if ( BATTLEMODE )
+    {
+        which = &gamestate.SpecialsTimes;
+    }
+    else
+    {
+        which = &CurrentSpecialsTimes;
+    }
+
+    switch(itemnumber)
+    {
+    case stat_godmode:
+        return which->GodModeTime;
+
+    case stat_dogmode:
+        return which->DogModeTime;
+
+    case stat_mushroom:
+        return which->ShroomsModeTime;
+
+    case stat_elastic:
+        return which->ElastoModeTime;
+
+    case stat_asbesto:
+        return which->AsbestosVestTime;
+
+    case stat_bulletproof:
+        return which->BulletProofVestTime;
+
+    case stat_gasmask:
+        return which->GasMaskTime;
+
+    case stat_fleetfeet:
+        return which->MercuryModeTime;
+    }
+
+    return -1;
+
+}
+
+
+
+
+/*
+=================================
+=
+=   GetRespawnTimeForItem
+=
+=================================
+*/
+
+
+
+int GetRespawnTimeForItem(int itemnumber)
+{
+    switch(itemnumber)
+    {
+    case stat_godmode:
+        return gamestate.SpecialsTimes.GodModeRespawnTime;
+
+    case stat_dogmode:
+        return gamestate.SpecialsTimes.DogModeRespawnTime;
+
+    case stat_mushroom:
+        return gamestate.SpecialsTimes.ShroomsModeRespawnTime;
+
+    case stat_elastic:
+        return gamestate.SpecialsTimes.ElastoModeRespawnTime;
+
+    case stat_asbesto:
+        return gamestate.SpecialsTimes.AsbestosVestRespawnTime;
+
+    case stat_bulletproof:
+        return gamestate.SpecialsTimes.BulletProofVestRespawnTime;
+
+    case stat_gasmask:
+        return gamestate.SpecialsTimes.GasMaskRespawnTime;
+
+    case stat_fleetfeet:
+        return gamestate.SpecialsTimes.MercuryModeRespawnTime;
+
+    }
+
+    return gamestate.BattleOptions.RespawnTime * VBLCOUNTER;
+
+
+}
+
+
+/*
+===================
+=
+= GetBonus
+=
+===================
+*/
+void GetBonus (objtype*ob,statobj_t *check)
+{
+    int heal;
+    playertype * pstate;
+    boolean randompowerup;
+
+    M_LINKSTATE(ob,pstate);
+
+    randompowerup=false;
+
+randomlabel:
+    switch (check->itemnumber)
+    {
+
+    case    stat_knifestatue:
+        SD_PlaySoundRTP(SD_GETKNIFESND,ob->x, ob->y);
+        if (ob==player)
+            locplayerstate->HASKNIFE = 1;
+        SD_PlaySoundRTP(PlayerSnds[locplayerstate->player], ob->x, ob->y);
+        LocalBonusMessage("You found a knife.");
+        break;
+    case    stat_pedgoldkey:
+        LocalBonusMessage("You found the \\EGold key.");
+        goto keys;
+    case    stat_pedsilverkey:
+        LocalBonusMessage("You got the \\FSilver key.");
+        goto keys;
+    case    stat_pedironkey:
+        LocalBonusMessage("You got the \\8Iron key.");
+        goto keys;
+    case    stat_pedcrystalkey:
+        LocalBonusMessage("You got the \\4Oscuro key.");
+keys:
+        GiveKey (check->itemnumber - stat_pedgoldkey);
+        SD_PlaySoundRTP (SD_GETKEYSND,ob->x, ob->y);
+        break;
+    case    stat_monkmeal:
+        if (pstate->health == MaxHitpointsForCharacter(pstate))
+            return;
+        SD_PlaySoundRTP (SD_GETHEALTH1SND,ob->x, ob->y);
+        LocalBonusMessage("You ate some Monk Meal.");
+        HealPlayer (10,ob);
+        gamestate.healthcount ++;
+        break;
+    case    stat_monkcrystal1:
+        if (pstate->health == MaxHitpointsForCharacter(pstate))
+            return;
+        SD_PlaySoundRTP (SD_GETHEALTH2SND,ob->x, ob->y);
+        LocalBonusMessage("You picked up a small Monk Crystal.");
+
+        HealPlayer (10,ob);
+        gamestate.healthcount ++;
+        break;
+    case   stat_monkcrystal2:
+        if (pstate->health == MaxHitpointsForCharacter(pstate))
+            return;
+        SD_PlaySoundRTP (SD_GETHEALTH2SND,ob->x, ob->y);
+        LocalBonusMessage("You picked up a large Monk Crystal.");
+
+        HealPlayer (50,ob);
+        gamestate.healthcount ++;
+        break;
+    case    stat_priestporridge:
+        if (pstate->health == MaxHitpointsForCharacter(pstate))
+            return;
+        SD_PlaySoundRTP (SD_GETHEALTH1SND,ob->x, ob->y);
+        if (check->flags & FL_ACTIVE)
+        {
+            HealPlayer (50,ob);
+            LocalBonusMessage("You ate some Priest Porridge Hot.");
+        }
+        else
+        {
+            HealPlayer (20,ob);
+
+            LocalBonusMessage("You ate some Priest Porridge.");
+        }
+        gamestate.healthcount ++;
+        break;
+
+    case   stat_healingbasin:
+        if (pstate->health == MaxHitpointsForCharacter(pstate))
+            return;
+        SD_PlaySoundRTP (SD_GETHEALTH2SND,ob->x, ob->y);
+        heal = 25 + (GameRandomNumber("GetBonus",0) >> 2);
+        HealPlayer (heal,ob);
+        LocalBonusMessage("You drank from the healing basin.");
+
+        gamestate.healthcount ++;
+        gamestate.democraticcount ++;
+        break;
+
+    case stat_oneup:
+        if (abs(pstate->health - MaxHitpointsForCharacter(pstate))
+                < (MaxHitpointsForCharacter(pstate)>>2) )
+        {
+            GiveLives(1);
+            LocalBonusMessage("Extra Life!");
+        }
+        else
+        {
+            HealPlayer(MaxHitpointsForCharacter(pstate),ob);
+            LocalBonusMessage("Full Health!");
+        }
+        SD_PlaySoundRTP(SD_GET1UPSND,ob->x, ob->y);
+        break;
+    case stat_threeup:
+        if (abs(pstate->health - MaxHitpointsForCharacter(pstate))
+                < (MaxHitpointsForCharacter(pstate)>>2) )
+        {
+            GiveLives(3);
+            LocalBonusMessage("Three Extra Lives!");
+
+        }
+        else
+        {
+            HealPlayer(MaxHitpointsForCharacter(pstate),ob);
+            GiveLives(2);
+            LocalBonusMessage("Full Health AND Two Extra Lives!");
+
+        }
+        SD_PlaySoundRTP(SD_GET3UPSND,ob->x, ob->y);
+        break;
+
+    case stat_scotthead:
+        // Give Apogee's phone number as points
+        GivePoints( 2764331 );
+        LocalBonusMessage( "Whoa...Scott's Mystical Head!");
+        LocalBonus1Message( "You get 2,764,331 points!");
+        SD_PlaySoundRTP(SD_GETHEADSND,ob->x, ob->y);
+        break;
+
+    case stat_twopistol:
+        if (GiveBulletWeapon(ob,wp_twopistol,check)==false)
+            return;
+        LocalBonusMessage("You got an extra pistol.");
+
+        break;
+    case stat_mp40:
+        if (GiveBulletWeapon(ob,wp_mp40,check)==false)
+            return;
+        LocalBonusMessage("You picked up an MP40.");
+
+        break;
+
+    case stat_bazooka:
+        if (GivePlayerMissileWeapon(ob,pstate,check)==false)
+            return;
+        if (wasAmmoPickup)
+        {
+            LocalBonusMessage("You bagged more Bazooka rounds!");
+        }
+        else {
+            LocalBonusMessage("You bagged a bazooka!");
+        }
+        wasAmmoPickup = false;
+        break;
+
+    case stat_firebomb:
+        if (GivePlayerMissileWeapon(ob,pstate,check)==false)
+            return;
+        if(wasAmmoPickup)
+        {
+            LocalBonusMessage("You got more Firebomb rounds!");
+        }
+        else
+        {
+            LocalBonusMessage("You found a Firebomb!");
+        }
+        wasAmmoPickup = false;
+        break;
+
+
+    case stat_heatseeker:
+        if (GivePlayerMissileWeapon(ob,pstate,check)==false)
+            return;
+        if(wasAmmoPickup)
+        {
+            LocalBonusMessage("You got more Heatseeker rounds!");
+        }
+        else
+        {
+            LocalBonusMessage("You have a Heat-seeker!");
+        }
+        wasAmmoPickup = false;
+        break;
+
+
+    case stat_drunkmissile:
+        if (GivePlayerMissileWeapon(ob,pstate,check)==false)
+            return;
+        if (wasAmmoPickup)
+        {
+            LocalBonusMessage("You recovered more Drunk missiles!");
+        }
+        else
+        {
+            LocalBonusMessage("You recovered a Drunk Missile!");
+        }
+        wasAmmoPickup = false;
+        break;
+
+    case stat_firewall:
+        if (GivePlayerMissileWeapon(ob,pstate,check)==false)
+            return;
+        if(wasAmmoPickup)
+        {
+            LocalBonusMessage("You filched more FlameWalls!");
+        }
+        else
+        {
+            LocalBonusMessage("You filched a FlameWall!");
+        }
+        wasAmmoPickup = false;
+        break;
+
+    case stat_splitmissile:
+        if (GivePlayerMissileWeapon(ob,pstate,check)==false)
+            return;
+        if (wasAmmoPickup)
+        {
+            LocalBonusMessage("You snagged more Split Missiles!");
+        }
+        else
+        {
+            LocalBonusMessage("You snagged a Split Missile!");
+        }
+        wasAmmoPickup = false;
+        break;
+
+    case stat_kes:
+        if (GivePlayerMissileWeapon(ob,pstate,check)==false)
+            return;
+        if(wasAmmoPickup)
+        {
+            LocalBonusMessage("You got more Dark Staff rounds!");
+        }
+        else
+        {
+            LocalBonusMessage("You wield the Dark Staff!");
+        }
+        wasAmmoPickup = false;
+        break;
+
+    case stat_bat:
+        if (GivePlayerMissileWeapon(ob,pstate,check)==false)
+            return;
+        if (wasAmmoPickup) {
+            LocalBonusMessage("You got more bat blast rounds!");
+        }
+        else
+        {
+            LocalBonusMessage("You picked up the Excalibat.");
+        }
+        wasAmmoPickup = false;
+        break;
+
+
+    case stat_lifeitem1:
+        GiveLifePoints(ob,1);
+        if (timelimitenabled)
+            timelimit+=(VBLCOUNTER);
+
+        break;
+
+    case stat_lifeitem2:
+        GiveLifePoints(ob,5);
+        if (timelimitenabled)
+            timelimit+=(2*VBLCOUNTER);
+        break;
+
+    case stat_lifeitem3:
+        GiveLifePoints(ob,10);
+        if (timelimitenabled)
+            timelimit+=(5*VBLCOUNTER);
+        break;
+
+    case stat_lifeitem4:
+        GiveLifePoints(ob,25);
+        if (timelimitenabled)
+            timelimit+=(10*VBLCOUNTER);
+        break;
+
+    case stat_random:
+        switch (GameRandomNumber("GetBonus",0)>>6)
+        {
+        case 0:
+            check->itemnumber=stat_godmode;
+            break;
+        case 1:
+            check->itemnumber=stat_elastic;
+            break;
+        case 2:
+            check->itemnumber=stat_dogmode;
+            break;
+        case 3:
+            check->itemnumber=stat_mushroom;
+            break;
+        }
+        randompowerup=true;
+        LocalBonus1Message("Random powerup gives you . . .");
+        goto randomlabel;
+        break;
+
+    case stat_bulletproof:
+        GiveProtection(FL_BPV, GetBonusTimeForItem(stat_bulletproof),
+                       SD_GETBVESTSND);
+        LocalBonusMessage("Bulletproof Armor!");
+
+        goto drw;
+
+    case stat_gasmask:
+        GiveProtection(FL_GASMASK, GetBonusTimeForItem(stat_gasmask),
+                       SD_GETMASKSND);
+        LocalBonusMessage("You put on a Gas Mask.");
+
+        goto drw;
+
+    case stat_asbesto:
+        GiveProtection(FL_AV,GetBonusTimeForItem(stat_asbesto),
+                       SD_GETAVESTSND);
+        LocalBonusMessage("Asbestos Armor! Oh so itchy!");
+
+        goto drw;
+
+    case stat_elastic:
+        if (GivePowerup(ob,FL_ELASTO,GetBonusTimeForItem(stat_elastic),
+                        SD_GETELASTSND) == false)
+            return;
+        LocalBonusMessage("Elasto Mode!");
+
+        ob->flags |= FL_NOFRICTION;
+        goto drw;
+
+    case stat_fleetfeet:
+        if (GivePowerup(ob,FL_FLEET,GetBonusTimeForItem(stat_fleetfeet),
+                        SD_GETFLEETSND) == false)
+            return;
+
+        LocalBonus1Message("Mercury Mode!");
+        LocalBonusMessage("Press Look Up and Down to fly.");
+
+        ob->flags &= ~FL_NOFRICTION;
+        goto drw;
+
+
+    case stat_mushroom:
+        if (GivePowerup(ob,FL_SHROOMS,GetBonusTimeForItem(stat_mushroom),
+                        SD_GETSHROOMSSND) == false)
+            return;
+        LocalBonusMessage("Shrooms Mode!");
+
+        ob->flags &= ~FL_NOFRICTION;
+        gamestate.democraticcount ++;
+        goto drw;
+
+
+    case stat_godmode:
+
+        if (ob->flags & FL_GODMODE)
+            return;
+
+        if (!ARMED(ob->dirchoosetime))
+            return;
+
+        ob->flags &= ~FL_NOFRICTION;
+
+        if (ob->flags & FL_DOGMODE)
+        {
+            ob->temp2 = DOGMODERISE;
+            ResetWeapons(ob);
+            if (ob->state->condition & SF_DOGSTATE)
+                NewState(ob,&s_player);
+        }
+
+        SaveWeapons(ob);
+        SpawnNewObj(ob->tilex,ob->tiley,&s_flash1,inertobj);
+        new->flags |= FL_ABP;
+        new->x = new->drawx = ob->x;
+        new->y = new->drawy = ob->y;
+        MakeActive(new);
+        new->z = ob->z;
+
+
+        SetPlayerHorizon(pstate,GODYZANGLE);
+
+        ob->flags &= ~(FL_GODMODE|FL_SHROOMS|FL_ELASTO|FL_FLEET|FL_DOGMODE);
+        ob->flags |= FL_GODMODE;
+        ob->temp2 = GODMODERISE;
+        pstate->poweruptime = GetBonusTimeForItem(stat_godmode);
+        pstate->soundtime = 0;
+        GiveMissileWeapon(ob,wp_godhand);
+        SD_PlaySoundRTP(SD_GETGODSND,ob->x, ob->y);
+        gamestate.supercount ++;
+        LocalBonusMessage("God Mode!");
+
+        goto drw;
+
+
+#if (SHAREWARE == 0)
+    case stat_dogmode:
+        if (ob->flags & FL_DOGMODE)
+            return;
+
+        if (!ARMED(ob->dirchoosetime))
+            return;
+
+        ob->flags &= ~FL_NOFRICTION;
+
+        if (ob->flags & FL_GODMODE)
+        {
+            ob->temp2 = GODMODEFALL;
+            ResetWeapons(ob);
+        }
+
+
+        SaveWeapons(ob);
+        ob->shapeoffset = 0;
+        NewState(ob,&s_serialdog);
+
+        SpawnNewObj(ob->tilex,ob->tiley,&s_flash1,inertobj);
+        new->flags |= FL_ABP;
+        new->x = new->drawx = ob->x;
+        new->y = new->drawy = ob->y;
+        MakeActive(new);
+        new->z = ob->z;
+
+        SetPlayerHorizon(pstate,DOGYZANGLE);
+
+        ob->flags &= ~(FL_DOGMODE|FL_SHROOMS|FL_ELASTO|FL_FLEET|FL_GODMODE);
+        ob->flags |= FL_DOGMODE;
+        ob->temp2 = DOGMODEFALL;
+        pstate->poweruptime = GetBonusTimeForItem(stat_dogmode);
+        pstate->soundtime = 0;
+        GiveMissileWeapon(ob,wp_dog);
+        SD_PlaySoundRTP(SD_GETDOGSND,ob->x, ob->y);
+        gamestate.supercount ++;
+        LocalBonusMessage("Dog Mode!");
+
+        goto drw;
+#endif
+
+drw:
+
+        if (ob==player)
+            GM_DrawBonus (check->itemnumber);
+
+        break;
+
+    case stat_dipball1:
+    case stat_dipball2:
+    case stat_dipball3:
+        SD_PlaySoundRTP(SD_GETBONUSSND,ob->x, ob->y);
+        gamestate.dipballs++;
+        LocalBonusMessage("You discovered a Developer Ball!");
+
+        break;
+
+    case stat_collector:
+        if (gamestate.battlemode==battle_CaptureTheTriad)
+        {   if (pstate->team == check->hitpoints)
+                return;
+            ob->flags |= FL_DESIGNATED;
+            UpdateKills = true;
+            LocalBonusMessage( "You picked up a triad!  RUN!!!");
+        }
+        else
+            BATTLE_CheckGameStatus(battle_get_collector_item,ob->dirchoosetime);
+
+        SD_PlaySoundRTP(SD_GETBONUSSND,ob->x, ob->y);
+        break;
+#if (SHAREWARE == 0)
+    case stat_mine:
+        SpawnNewObj(check->tilex,check->tiley,&s_grexplosion1,inertobj);
+        new->flags |= FL_ABP;
+        new->whatever = check;
+        new->temp2 = 100;
+        MakeActive(new);
+        SD_PlaySoundRTP(SD_EXPLODESND,check->x,check->y);
+        break;
+#endif
+    default:
+        SD_PlaySoundRTP(SD_GETHEADSND,ob->x, ob->y);
+        break;
+    }
+    //StartBonusFlash ();
+    if (check->flags & FL_CHANGES)
+    {
+        switch (check->itemnumber)
+        {
+        case stat_pedgoldkey:
+        case stat_pedsilverkey:
+        case stat_pedironkey:
+        case stat_pedcrystalkey:
+            check->itemnumber = stat_emptypedestal;
+            check->shapenum = stats[stat_emptypedestal].picnum;
+            check->flags = stats[stat_emptypedestal].flags|FL_ABP;
+            check->count = 0;
+            check->numanims = 0;
+            break;
+        case stat_healingbasin:
+            check->itemnumber = stat_emptybasin;
+            check->shapenum = stats[stat_emptybasin].picnum;
+            check->flags = stats[stat_emptybasin].flags|FL_ABP;
+            check->count = 0;
+            check->numanims = 0;
+            break;
+        /*
+        	case stat_tablebullets:
+        	check->itemnumber = stat_emptytable;
+        	check->shapenum = stats[stat_emptytable].picnum;
+        	check->flags = stats[stat_emptytable].flags|FL_ABP;
+        	break;
+        case stat_statuewithpole:
+        	check->itemnumber = stat_armornopole;
+        	check->shapenum = stats[stat_armornopole].picnum;
+        	check->flags = stats[stat_armornopole].flags|FL_ABP;
+        	break; */
+        case stat_pit:
+            check->shapenum ++;
+            check->flags &= ~FL_CHANGES;
+            check->flags &= ~FL_BONUS;
+            break;
+        case stat_knifestatue:
+            check->itemnumber = stat_emptystatue;
+            check->shapenum = stats[stat_emptystatue].picnum;
+            check->flags = stats[stat_emptystatue].flags|FL_ABP;
+            break;
+
+        default:
+            ;
+        }
+    }
+    else
+    {   if (check == sprites[check->tilex][check->tiley])
+        {
+            statobj_t *checkstat;
+
+            checkstat = (statobj_t*)DiskAt(check->tilex,check->tiley);
+            if (checkstat && (checkstat->which == SPRITE))
+                sprites[check->tilex][check->tiley] = checkstat;
+            else
+                sprites[check->tilex][check->tiley] = NULL;
+        }
+
+        if (randompowerup==true)
+            check->itemnumber = stat_random;
+        RemoveStatic(check);
+    }
+}
+
+
+/*
+===================
+=
+= DropWeapon
+=
+===================
+*/
+
+void DropWeapon(objtype *ob)
+{   playertype *pstate;
+    int dtilex,dtiley;
+
+
+
+    M_LINKSTATE(ob,pstate);
+
+    if ((pstate->missileweapon == -1) || (pstate->missileweapon == wp_godhand)
+#if (SHAREWARE == 0)
+            || (pstate->missileweapon == wp_dog)
+#endif
+       )
+        return;
+
+    pstate->weapondowntics = WEAPONS[pstate->weapon].screenheight/3;
+    pstate->new_weapon = pstate->bulletweapon;
+
+    dtilex = ob->tilex;
+    dtiley = ob->tiley;
+
+    FindEmptyTile(&dtilex, &dtiley);
+
+
+    SpawnStatic(dtilex,dtiley,GetItemForWeapon(pstate->missileweapon),9);
+    gamestate.missiletotal ++;
+
+    LASTSTAT->ammo = pstate->ammo;
+    LASTSTAT->flags |= FL_ABP;
+    LASTSTAT->flags &= ~FL_RESPAWN;
+    MakeStatActive(LASTSTAT);
+    pstate->weaponx = ob->tilex;
+    pstate->weapony = ob->tiley;
+    pstate->ammo = -1;
+    pstate->missileweapon = -1;
+    if ((ob==player) && SHOW_BOTTOM_STATUS_BAR() )
+        DrawBarAmmo (false);
+}
+
+
+/*
+===================
+=
+= Thrust
+=
+===================
+*/
+
+void Thrust ( objtype * ob )
+{   statobj_t *tstat;
+    int dx,dy,dz,rad,index,otherteam;
+    objtype*temp;
+    playertype * pstate;
+
+    PlayerMove(ob);
+    M_LINKSTATE(ob,pstate);
+
+    if ((gamestate.battlemode == battle_CaptureTheTriad) &&
+            (ob->flags & FL_DESIGNATED) &&
+            (ob->tilex == TEAM[pstate->team].tilex) &&
+            (ob->tiley == TEAM[pstate->team].tiley))
+    {   if (ob == player)
+            SD_Play(PlayerSnds[locplayerstate->player]);
+
+        if (BATTLE_CheckGameStatus(battle_captured_triad,ob->dirchoosetime)==
+                battle_no_event)
+        {
+            ob->flags &= ~FL_DESIGNATED;
+            UpdateKills = true;
+            otherteam = (pstate->team ^ 1);
+            SpawnStatic(TEAM[otherteam].tilex,TEAM[otherteam].tiley,stat_collector,9);
+            LASTSTAT->flags |= FL_COLORED;
+            LASTSTAT->hitpoints = otherteam;
+            LASTSTAT->flags |= FL_ABP;
+            MakeStatActive(LASTSTAT);
+        }
+        return;
+    }
+
+    if ((ob->tilex != pstate->weaponx) || (ob->tiley != pstate->weapony))
+        pstate->weaponx = pstate->weapony = 0;
+
+    index = touchindices[ob->tilex][ob->tiley];
+    if (index && (abs(ob->z - nominalheight) < 5))
+    {   if (!TRIGGER[index-1]) {
+#if (BNACRASHPREVENT == 1)
+            if (touchplate[index-1] != 0) { //	CRASH IN SHAREWARE 'ride em cowboy' BNA FIX
+                //SetTextMode (  ); qwert  // DONT ALLOW BAD touchplate ( == 0 ) see rt_door.c
+#endif
+                if (touchplate[index-1]->complete)
+                    SD_PlaySoundRTP(SD_BADTOUCHSND,ob->x,ob->y);
+                else {
+                    SD_PlaySoundRTP(SD_TOUCHPLATESND,ob->x,ob->y);
+                    if (ob == player)
+                        AddMessage("Touchplate triggered.",MSG_GAME);
+                }
+#if (BNACRASHPREVENT == 1)
+            } else {
+                SD_PlaySoundRTP(SD_BADTOUCHSND,ob->x,ob->y);
+            }
+            //	CRASH IN SHAREWARE 'ride em cowboy' BNA FIX
+#endif
+        }
+        TRIGGER[index-1] = 1;
+    }
+
+    tstat = sprites[ob->tilex][ob->tiley];
+    if (tstat)
+
+    {   dx = abs(ob->x - tstat->x);
+        dy = abs(ob->y - tstat->y);
+        dz = abs(ob->z - tstat->z);
+        if ((dx < 0x8000) && (dy < 0x8000) && (dz<=35))
+        {
+#define OBJECT_IS_BONUS( tstat )                  ( ( tstat )->flags & FL_BONUS )
+#define PLAYER_IS_SWITCHING_WEAPONS( pstate )     ( W_CHANGE( pstate ) )
+//#define IS_ATTACKING( ob )                        ( ( ( ob )->state->think == T_Attack ) || ( ( ob )->state->think == T_BatBlast ) )
+#define IS_WEAPON( tstat )                        ( ( tstat )->flags & FL_WEAPON )
+#define PLAYER_MAY_NOT_GET_WEAPON( pstate, ob )   ( PLAYER_IS_SWITCHING_WEAPONS( pstate ))// || IS_ATTACKING( ob ) )
+#define OK_TO_PICK_UP( tstat, pstate, ob )        ( !( IS_WEAPON( tstat ) && PLAYER_MAY_NOT_GET_WEAPON( pstate, ob ) ) )
+#define WHERE_PLAYER_DROPPED_WEAPON( ob, pstate ) ( ( ( ob )->tilex == ( pstate )->weaponx ) && ( ( ob )->tiley == ( pstate )->weapony ) )
+
+            if ( OBJECT_IS_BONUS( tstat ) &&
+                    OK_TO_PICK_UP( tstat, pstate, ob ) &&
+                    (!WHERE_PLAYER_DROPPED_WEAPON( ob, pstate ))
+               )
+            {
+                GetBonus(ob,tstat);
+                if (PLAYER_IS_SWITCHING_WEAPONS( pstate ))
+                {   statetype *nstate;
+#if (SHAREWARE == 0)
+                    if (ob->state->condition & SF_DOGSTATE)
+                        nstate = &s_serialdog;
+                    else
+#endif
+                        nstate = &s_player;
+                    pstate->attackframe = pstate->weaponframe = pstate->batblast = 0;
+                    NewState(ob,nstate);
+                }
+
+
+            }
+            else if ((tstat->itemnumber == stat_pit) &&
+                     (ob->temp2 != PITFALL) &&
+                     (!(ob->flags & FL_FLEET))
+                    )
+            {   ob->temp2 = PITFALL;
+                ob->momentumx = ob->momentumy = 0;
+                //ob->momentumz = 4;
+                ob->momentumz = GRAVITY;
+
+                if (ob->whatever == NULL)
+                {   ob->whatever = tstat;
+                    SD_PlaySoundRTP(SD_PITTRAPSND,ob->x,ob->y);
+                    tstat->shapenum = stats[tstat->itemnumber].picnum + 1;
+                    MakeStatInactive(tstat);
+                    //tstat->flags &= ~FL_ABP;
+                }
+            }
+            else if ((tstat->itemnumber == stat_heatgrate) &&
+                     (!(ob->flags & FL_DYING)) && (!(ob->flags & FL_AV))
+                    )
+            {   DamageThing(ob,1);
+                Collision(ob,(objtype*)tstat,0,0);
+                M_CheckPlayerKilled(ob);
+            }
+
+
+        }
+    }
+
+//================ Check special player/actor links ======================
+
+    if (ob->whatever)
+    {   temp = (objtype*)(ob->whatever);
+
+        dx = abs(ob->x - temp->x);
+        dy = abs(ob->y - temp->y);
+        dz = abs(ob->z - temp->z);
+        if (ob->flags & FL_RIDING)
+            rad = MINACTORDIST;
+        else
+            rad = 0x8000;
+
+        if ((dx >rad) || (dy > rad) || (dz > 64))
+        {
+            if ((temp->obclass == bladeobj) || (temp->obclass == diskobj))
+            {   temp->whatever = NULL;
+                ob->flags &= ~FL_RIDING;
+            }
+
+            else if (ob->temp2 == COLUMNCRUSH)
+                ob->temp2 = RENORMALIZE;
+            else if (ob->z < nominalheight)
+                ob->momentumz = 40000;
+            else if (temp->which == SPRITE)
+            {   tstat = (statobj_t*)(ob->whatever);
+                MakeStatActive(tstat);
+                SetNormalHorizon(ob);
+            }
+            ob->whatever = NULL;
+        }
+    }
+
+//=========================================================================
+
+
+    if (BATTLEMODE && (MAPSPOT(ob->tilex,ob->tiley,1) == EXITTILE))
+    {
+        Move_Player_From_Exit_To_Start(ob);
+        return;
+    }
+
+    if (ob==player)
+    {
+        if (MAPSPOT(ob->tilex,ob->tiley,1) == EXITTILE)
+            playstate=ex_completed;
+        else if ( ( MAPSPOT( ob->tilex, ob->tiley, 2 ) & 0xff00 ) == 0xe400 )
+            playstate = ex_secretdone;
+        else if (MAPSPOT(ob->tilex,ob->tiley,1) == SECRETEXITTILE)
+            playstate=ex_secretlevel;
+    }
+}
+
+
+
+void Move_Player_From_Exit_To_Start(objtype *ob)
+{
+    int i = 0,oldarea,newarea;
+    objtype *tplayer;
+    int travelangle,dangle;
+    playertype *pstate;
+
+    M_LINKSTATE(ob,pstate);
+
+
+    oldarea = ob->areanumber;
+    newarea = AREANUMBER(FIRST.x,FIRST.y);
+    if (oldarea != newarea)
+    {
+        RemoveFromArea(ob);
+        ob->areanumber = newarea;
+        MakeLastInArea(ob);
+    }
+
+    SetTilePosition(ob,FIRST.x,FIRST.y);
+    ob->z = PlatformHeight(ob->tilex,ob->tiley);
+    if ((ob->z == -10) || DiskAt(ob->tilex,ob->tiley))
+        ob->z = 0;
+
+    ConnectAreas();
+    travelangle = atan2_appx(ob->momentumx,ob->momentumy);
+    dangle = ob->angle - travelangle;
+
+    ob->angle = (1-FIRST.dir)*ANG90 + dangle;
+    Fix(ob->angle);
+
+    ob->dir   = angletodir[ob->angle];
+    pstate->anglefrac= (ob->angle<<ANGLEBITS);
+    pstate->angle=0;
+
+
+    for(i=0; i<numplayers; i++)
+    {
+        tplayer = PLAYER[i];
+
+        if (ob == tplayer)
+            continue;
+
+        if (
+            (tplayer->tilex == FIRST.x) &&
+            (tplayer->tiley == FIRST.y) &&
+            (!(tplayer->flags & FL_DYING))
+        )
+        {
+            playertype *pstate;
+
+            M_LINKSTATE(tplayer,pstate);
+
+            pstate->health = tplayer->hitpoints = 0;
+            tplayer->flags |= FL_HBM;
+            Collision(tplayer,ob,0,0);
+            BATTLE_PlayerKilledPlayer(battle_kill_by_crushing,ob->dirchoosetime,tplayer->dirchoosetime);
+            \
+
+        }
+    }
+
+
+}
+
+
+
+void PlayerSlideMove(objtype * ob)
+{   int tryx, tryy, tryz;
+
+    tryx = ob->x + ob->momentumx;
+    tryy = ob->y + ob->momentumy;
+    tryz = ob->z + (ob->momentumz >> 16);
+
+    if (ActorTryMove(ob,ob->x,tryy,tryz))
+    {
+        if (ob->momentumx>HITWALLSPEED)
+            SD_PlaySoundRTP(SD_HITWALLSND,ob->x,ob->y);
+        ob->momentumx=0;
+    }
+    else if (ActorTryMove(ob,tryx,ob->y,tryz))
+    {
+        if (ob->momentumy>HITWALLSPEED)
+            SD_PlaySoundRTP(SD_HITWALLSND,ob->x,ob->y);
+        ob->momentumy=0;
+    }
+    else
+    {
+        if (FindDistance(ob->momentumx,ob->momentumy)>(HITWALLSPEED*3/2))
+            SD_PlaySoundRTP(SD_HITWALLSND,ob->x,ob->y);
+        ob->momentumx=0;
+        ob->momentumy=0;
+    }
+}
+
+/*
+===================
+=
+= SetNormalHorizon
+=
+===================
+*/
+
+void SetNormalHorizon (objtype * ob)
+{
+    playertype * pstate;
+
+    M_LINKSTATE(ob,pstate);
+
+    if (ob->flags&FL_DOGMODE)
+    {
+        SetPlayerHorizon(pstate,DOGYZANGLE);
+    }
+    else if (ob->flags&FL_GODMODE)
+    {
+        SetPlayerHorizon(pstate,GODYZANGLE);
+    }
+    else
+    {
+        SetPlayerHorizon(pstate,NORMALYZANGLE);
+    }
+}
+
+/*
+===================
+=
+= PlayerTiltHead
+=
+===================
+*/
+extern int iG_playerTilt;
+extern double dTopYZANGLELIMIT;
+void PlayerTiltHead (objtype * ob)
+{
+    playertype * pstate;
+    int dyz=0;
+    int yzangle;
+
+//bna++   jumpmode
+    if ((donttilt > 0)) {
+        donttilt--;
+        return;
+    }
+
+    M_LINKSTATE(ob,pstate);
+
+    yzangle=ob->yzangle+HORIZONYZOFFSET;
+    Fix(yzangle);
+
+    if (
+        (pstate->lastmomz!=ob->momentumz) &&
+        (ob->momentumz==0) &&
+        (
+            (!(ob->flags&FL_FLEET)) ||
+            (
+                (ob->flags&FL_FLEET) &&
+                (ob->z==nominalheight)
+            )
+        )
+    )
+        SetNormalHorizon(ob);
+
+    pstate->lastmomz=ob->momentumz;
+
+    if (ob->flags&FL_SHROOMS)
+    {
+        ob->yzangle = FixedMulShift(SHROOMYZANGLE,sintable[(oldpolltime<<6)&(FINEANGLES-1)],16);
+        Fix(ob->yzangle);
+        return;
+    }
+    else if (pstate->guntarget)
+    {
+        int dx,dy,dz;
+        int xydist;
+        int yzangle;
+
+        dx = ob->x - pstate->guntarget->x;
+        dy = ob->y - pstate->guntarget->y;
+        xydist = FindDistance(dx,dy)-0x8000;
+        if (ob->z==pstate->guntarget->z)
+            dz = 0;
+        else
+        {
+            dz = (ob->z-pstate->guntarget->z)<<10;
+        }
+        yzangle = atan2_appx(xydist,dz);
+
+        yzangle += HORIZONYZOFFSET;
+        Fix(yzangle);
+        SetPlayerHorizon(pstate,yzangle-HORIZONYZOFFSET);
+
+        if (oldpolltime>pstate->targettime)
+        {
+            if (pstate->guntarget)
+                pstate->guntarget->flags &= ~FL_TARGET;
+            pstate->guntarget=NULL;
+            SetNormalHorizon(ob);
+        }
+    }
+    else
+    {
+        if (pstate->buttonstate[bt_horizonup])
+        {
+            if (yzangle!=pstate->horizon)
+            {
+                SetPlayerHorizon(pstate,yzangle-HORIZONYZOFFSET);
+            }
+            else
+            {
+                SetPlayerHorizon(pstate,(pstate->horizon-HORIZONYZOFFSET+YZHORIZONSPEED));
+            }
+        }
+        else if (pstate->buttonstate[bt_horizondown])
+        {
+            if (yzangle!=pstate->horizon)
+            {
+                SetPlayerHorizon(pstate,yzangle-HORIZONYZOFFSET);
+            }
+            else
+            {
+                SetPlayerHorizon(pstate,(pstate->horizon-HORIZONYZOFFSET-YZHORIZONSPEED));
+            }
+        }
+        if (pstate->buttonstate[bt_lookup] || CYBERLOOKUP)
+        {
+            if (!(ob->flags & FL_FLEET))
+            {
+                dyz=YZTILTSPEED;
+                if (pstate->buttonstate[bt_lookdown] || CYBERLOOKDOWN)
+                {
+                    dyz=0;
+                }
+
+                SetNormalHorizon(ob);
+            }
+        }
+        if (pstate->buttonstate[bt_lookdown] || CYBERLOOKDOWN)
+        {
+            if (!(ob->flags & FL_FLEET))
+            {
+                dyz=-YZTILTSPEED;
+                if (pstate->buttonstate[bt_lookup] || CYBERLOOKUP)
+                {
+                    dyz=0;
+                }
+                SetNormalHorizon(ob);
+            }
+        }
+        if (!(ob->flags&FL_DOGMODE) &&
+                !(ob->flags&FL_GODMODE) &&
+                !(ob->flags&FL_FLEET)   &&
+                !(ob->flags&FL_RIDING)  &&
+                (ob->momentumz > (GRAVITY<<1))//(ob->momentumz>0x1000)
+           )
+        {
+            SetPlayerHorizon(pstate,FALLINGYZANGLE);
+        }
+    }
+
+
+
+    if ((yzangle!=pstate->horizon) && (dyz==0))
+    {
+        int speed;
+
+        speed=SNAPBACKSPEED;
+        if (yzangle<pstate->horizon)
+            yzangle+=speed;
+        else
+            yzangle-=speed;
+        if ((abs(yzangle-pstate->horizon))<SNAPBACKSPEED)
+            yzangle=pstate->horizon;
+    }
+//SetTextMode();
+
+    if (yzangle != 512) {
+        FinddTopYZANGLELIMITvalue(ob);
+    }
+
+
+    yzangle+=dyz;
+    if (yzangle-HORIZONYZOFFSET>YZANGLELIMIT)
+        yzangle=HORIZONYZOFFSET+YZANGLELIMIT;
+    /*   else if (yzangle-HORIZONYZOFFSET<-TopYZANGLELIMIT)//bnafix
+           yzangle=HORIZONYZOFFSET-TopYZANGLELIMIT;//bnafix
+    dTopYZANGLELIMIT*/
+    else if (yzangle-HORIZONYZOFFSET<-dTopYZANGLELIMIT)//bnafix
+        yzangle=HORIZONYZOFFSET-dTopYZANGLELIMIT;//bnafix
+    ob->yzangle=yzangle-HORIZONYZOFFSET;
+    Fix(ob->yzangle);
+
+    iG_playerTilt = ob->yzangle;
+
+}
+
+//----------------------------------------------------------------------
+// bna added function
+// if a player is to close to wall, looking down max
+//,this func limit the dTopYZANGLELIMIT value when
+// facing a wall
+#define SMALLANGLE 90
+//there is small angles where didnt work
+//so we check for them to = 90/2048 = aprox, 15 degrees
+int FinddTopYZANGLELIMITvalue(objtype *ob)
+{   /*
+
+
+    checkx = ob->tilex + 1;
+    checky = ob->tiley + 1;
+    if (actorat[checkx][checky]){
+    return 0;
+    }
+    return 1;
+
+    checkx = ob->tilex ;
+    checky = ob->tiley;
+
+    // find which direction the player is facing
+    //and check if it is a wall
+
+    */
+
+    //use lowest down angle
+    dTopYZANGLELIMIT = (26*FINEANGLES/360);
+
+    if (ob->angle < 256 || ob->angle > 1792) {
+        if ((tilemap[ob->tilex + 1][ob->tiley])!=0) {
+
+            return 0;
+        }
+        //ob->dir = east;
+    } else if (ob->angle < 768) {
+        if ((tilemap[ob->tilex][ob->tiley-1])!=0) {
+            return 0;
+        }
+    } else if (ob->angle < 1280) {
+        if ((tilemap[ob->tilex-1][ob->tiley])!=0) {
+            return 0;
+        }
+    } else {
+        if ((tilemap[ob->tilex][ob->tiley+1])!=0) {
+            return 0;
+        }
+    }
+
+
+    //use middle down angle
+    dTopYZANGLELIMIT = (42*FINEANGLES/360);
+
+    if ((ob->angle > 768-SMALLANGLE)&&(ob->angle <= 768)) {
+        if ((tilemap[ob->tilex -1][ob->tiley])!=0) { //ob->tiley-1
+            return 0;
+        }
+    }
+    if ((ob->angle < 1280+SMALLANGLE)&&(ob->angle >= 1280)) {
+        if ((tilemap[ob->tilex - 1][ob->tiley])!=0) { //ob->tiley+1
+            return 0;
+        }
+    }
+    if ((ob->angle > 256)&&(ob->angle <= 256+SMALLANGLE)) {
+        if ((tilemap[ob->tilex + 1][ob->tiley])!=0) { //ob->tiley-1
+            return 0;
+        }
+    }
+    if ((ob->angle < 1792)&&(ob->angle >= 1792-SMALLANGLE)) {
+        if ((tilemap[ob->tilex + 1][ob->tiley])!=0) { //ob->tiley+1
+            return 0;
+        }
+    }
+    if ((ob->angle < 1280)&&(ob->angle >= 1280-SMALLANGLE)) {
+        if ((tilemap[ob->tilex ][ob->tiley+1])!=0) { //ob->tilex-1
+            return 0;
+        }
+    }
+    if ((ob->angle > 1792)&&(ob->angle <= 1792+SMALLANGLE)) {
+        if ((tilemap[ob->tilex ][ob->tiley+1])!=0) { //ob->tiley+1
+            return 0;
+        }
+    }
+    if ((ob->angle > 768)&&(ob->angle <= 768+SMALLANGLE)) {
+        if ((tilemap[ob->tilex][ob->tiley-1])!=0) { //ob->tiley-1
+            return 0;
+        }
+    }
+    if ((ob->angle < 256)&&(ob->angle >= 256-SMALLANGLE)) {
+        if ((tilemap[ob->tilex][ob->tiley-1])!=0) { //ob->tiley-1
+            return 0;
+        }
+    }
+
+    //use max down angle
+    dTopYZANGLELIMIT = (90*FINEANGLES/360);
+    return 1;
+}
+// bna added function end
+//----------------------------------------------------------------------
+
+
+
+
+/*
+===================
+=
+= UpdatePlayers
+=
+=================== QWERTYU
+*/
+void UpdatePlayers ( void )
+{
+    objtype * obj;
+//   playertype * pstate;
+
+    for (obj = FIRSTACTOR; obj->obclass==playerobj; obj = obj->next)
+    {
+
+//ErrorDontQuit("obj->next = ",obj->next);
+#if (BNACRASHPREVENT == 1)//crashed here when oscuro and larves were all killed
+        if (obj->next == 0) {
+            return;
+        }
+#endif
+        obj->speed=FindDistance(obj->momentumx, obj->momentumy);
+//       M_LINKSTATE(obj,pstate);
+//       pstate->steptime-=obj->speed;
+//       if (pstate->steptime<0)
+//          {
+//          while (pstate->steptime<0)
+//             pstate->steptime+=PLAYERSTEPTIME;
+//          pstate->stepwhich^=1;
+//          SD_PlaySoundRTP(SD_WALK1SND+pstate->stepwhich,obj->x,obj->y);
+//          }
+    }
+}
+
+
+/*
+===================
+=
+= PlayerMove
+=
+===================
+*/
+
+void PlayerMove ( objtype * ob )
+{   playertype *pstate;
+
+    M_LINKSTATE(ob,pstate);
+    if (ob->flags & FL_FLEET)
+        CheckFlying(ob,pstate);
+    ActorMovement(ob);
+    pstate->anglefrac = (pstate->anglefrac+pstate->angle)&((FINEANGLES<<ANGLEBITS)-1);
+    ob->angle = (pstate->anglefrac >> ANGLEBITS);
+    ob->dir = angletodir[ob->angle];
+    if (ob==player)
+        UpdateLightLevel(player->areanumber);
+
+    PlayerTiltHead(ob);
+
+    if (IsWindow(ob->tilex,ob->tiley))
+    {
+        if (!(ob->flags & FL_DYING))
+        {
+            pstate->health = 0;
+            pstate->falling=true;
+            if ((ob->flags & FL_GODMODE) || (ob->flags & FL_DOGMODE) ||
+                    (gamestate.battlemode == battle_Eluder) || (godmode==true))
+            {
+                KillActor(ob);
+                NewState(ob,&s_remotedie1);
+            }
+            else
+                Collision(ob,(objtype*)NULL,0,0);
+            ob->flags |= FL_DYING;
+            M_CheckPlayerKilled(ob);
+        }
+    }
+}
+
+/*
+===============
+=
+= T_Tag
+=
+===============
+*/
+
+void  T_Tag (objtype *ob)
+{
+    playertype *pstate;
+
+    CheckPlayerSpecials(ob);
+    //CheckWeaponStates(ob);
+    M_LINKSTATE(ob,pstate);
+    Thrust(ob);
+
+    if (ob->ticcount > 4)
+        pstate->weaponheight -= GMOVE;
+    else
+        pstate->weaponheight += GMOVE;
+
+    if ((ob->ticcount > 1) && (ob->ticcount < 8) && (!(ob->flags & FL_DIDTAG)))
+    {   int i,dx,dy,magangle;
+
+        for(i=0; i<numplayers; i++)
+        {   if (PLAYER[i] == ob)
+                continue;
+
+            dx = abs(PLAYER[i]->x - ob->x);
+            dy = abs(PLAYER[i]->y - ob->y);
+            if ((dx > 0xc000) || (dy > 0xc000))
+                continue;
+            magangle = abs(ob->angle - AngleBetween(ob,PLAYER[i]));
+            if (magangle > VANG180)
+                magangle = ANGLES - magangle;
+
+            if (magangle > ANGLES/8)
+                continue;
+            CheckTagGame(ob,PLAYER[i]);
+            break;
+        }
+
+    }
+
+
+//Commented out until we find if it's valid
+    /*
+    	if (!ob->ticcount)
+    	  {if ( pstate->buttonstate[bt_use] && !pstate->buttonheld[bt_use] )
+    			pstate->buttonstate[bt_use] = false;
+    		if ( pstate->buttonstate[bt_attack] && !pstate->buttonheld[bt_attack])
+    			pstate->buttonstate[bt_attack] = false;
+    	  }
+    */
+}
+
+#if (SHAREWARE == 0)
+#define GET_RESETSTATE(ob,resetstate)      \
+   {                                       \
+   if (ob->state->condition & SF_DOGSTATE) \
+      resetstate = &s_serialdog;           \
+   else                                    \
+      resetstate = &s_player;              \
+   }
+#else
+#define GET_RESETSTATE(ob,resetstate)      \
+   {                                       \
+   resetstate = &s_player;                 \
+   }
+#endif
+
+/*
+===============
+=
+= T_Attack
+=
+===============
+*/
+
+void  T_Attack (objtype *ob)
+{
+    attack_t   *cur;
+
+    playertype *pstate;
+    statetype *resetstate;
+
+
+    Thrust(ob);
+    if (ob->flags & FL_DYING)
+        return;
+
+    resetstate = ob->state;
+    CheckPlayerSpecials(ob);
+    if (resetstate != ob->state)
+    {
+        return;
+    }
+
+
+    if ((ob->flags & FL_PAIN) && (!ob->ticcount))
+        ob->flags &= ~FL_PAIN;
+
+    CheckWeaponStates(ob);
+    M_LINKSTATE(ob,pstate);
+    GET_RESETSTATE(ob,resetstate);
+
+
+    if (ARMED(ob->dirchoosetime)
+            //(gamestate.battlemode != battle_Tag)
+       )
+
+    {
+        if (pstate->weapondowntics == 1)  // change to up; during change, up and down
+            // are never zero at the same time
+        {
+#if (SHAREWARE == 0)
+            if (pstate->weapon == wp_kes)
+            {
+                pstate->weapondowntics = 0;
+                pstate->weaponuptics = KESTICS/(2*GMOVE);
+            }
+            else
+#endif
+            {
+                pstate->weapondowntics = 0;
+                pstate->weaponframe = pstate->attackframe = 0;
+
+                if (pstate->NETCAPTURED == -1)
+                {
+                    pstate->weaponuptics = FREE.screenheight/GMOVE;
+                    pstate->weaponheight = pstate->weaponuptics*GMOVE ;
+                    pstate->NETCAPTURED = 1;
+                    //          return;
+                }
+                else if (pstate->NETCAPTURED == -2)
+                {
+                    pstate->weaponuptics = WEAPONS[pstate->weapon].screenheight/GMOVE;
+                    pstate->weaponheight = pstate->weaponuptics*GMOVE ;
+                    pstate->NETCAPTURED = 0;
+
+                    //return;
+                }
+                else
+                {
+                    pstate->weaponuptics = WEAPONS[pstate->new_weapon].screenheight/GMOVE;
+                    pstate->weapon = pstate->new_weapon;
+                    pstate->weaponheight = pstate->weaponuptics*GMOVE ;
+                }
+            }
+        }
+    }
+    else if (gamestate.battlemode == battle_Hunter)
+    {
+        if (pstate->weapondowntics == 1)
+
+        {
+            pstate->weapondowntics = 0;
+            pstate->weaponframe = pstate->attackframe = pstate->batblast = 0;
+            pstate->weapon = pstate->new_weapon;
+            NewState(ob,resetstate);
+            return;
+        }
+    }
+
+
+
+
+#if (SHAREWARE==0)
+    if ((pstate->buttonstate[bt_use]) &&
+            (pstate->weapon != wp_dog)
+       )
+#else
+    if (pstate->buttonstate[bt_use])
+#endif
+        Cmd_Use (ob);
+
+    if (pstate->attackframe >= WEAPONS[pstate->weapon].numattacks)
+        Error("\n attackframe %d for weapon %d gt numattacks %d",
+              pstate->attackframe,pstate->weapon,
+              WEAPONS[pstate->weapon].numattacks
+             );
+
+    cur = &(WEAPONS[pstate->weapon].attackinfo[pstate->attackframe]);
+    if (! pstate->attackcount)
+    {
+        switch (cur->attack)
+        {
+        case reset:
+            if (vrenabled && (ob==player))
+            {
+                StopVRFeedback();
+            }
+            ob->flags &= ~FL_FULLLIGHT;
+            if (pstate->ammo)
+            {
+                if (BATTLEMODE && (pstate->weapon == wp_firewall))
+                    break;
+                if (BATTLEMODE && (pstate->weapon == wp_firebomb))
+                    break;
+                if ((pstate->buttonstate[bt_attack]) && (pstate->weapon <= wp_firewall))
+                {
+                    if (pstate->weapon <= wp_mp40)
+                    {
+                        if (pstate->weapon == wp_twopistol)
+                            pstate->attackframe -= 6;
+                        else if (pstate->weapon == wp_pistol)
+                            pstate->attackframe -= 3;
+                        else if (pstate->weapon == wp_mp40)
+                            pstate->attackframe -= 2;
+
+                        if (ob->state == &s_pmissattack2)
+                            NewState(ob,&s_pmissattack1);
+                        else if (ob->state == &s_pgunattack2)
+                            NewState(ob,&s_pgunattack1);
+
+                    }
+
+                }
+                else
+                {
+                    NewState(ob,resetstate);
+                    pstate->attackframe = pstate->weaponframe = 0;
+                    pstate->batblast = 0;
+                    return;
+                }
+            }
+            else
+            {
+                NewState(ob,resetstate);
+                pstate->attackframe = pstate->weaponframe = 0;
+                pstate->new_weapon = pstate->bulletweapon;
+                pstate->batblast = 0;
+                pstate->ammo = -1;
+                pstate->missileweapon = -1;
+                pstate->weapondowntics = WEAPONS[pstate->weapon].screenheight/GMOVE;
+
+                if ((ob==player) && SHOW_BOTTOM_STATUS_BAR() )
+                    DrawBarAmmo (false);
+
+                return;
+            }
+            break;
+
+        case reset2:
+            if (vrenabled && (ob==player))
+            {
+                StopVRFeedback();
+            }
+            ob->flags &= ~FL_FULLLIGHT;
+            if (pstate->buttonstate[bt_attack] && pstate->ammo)
+            {
+                pstate->attackframe -= 4;
+                if (ob->state == &s_pmissattack2)
+                    NewState(ob,&s_pmissattack1);
+                else if (ob->state == &s_pgunattack2)
+                    NewState(ob,&s_pgunattack1);
+            }
+            else
+            {
+                NewState(ob,resetstate);
+                pstate->attackframe = pstate->weaponframe = 0;
+                pstate->batblast = 0;
+                return;
+            }
+
+            break;
+
+
+        case at_pulltrigger:
+            if (vrenabled && (ob==player))
+            {
+                StartVRFeedback(1);
+            }
+            ob->flags |= FL_FULLLIGHT;
+
+#if (SHAREWARE == 0)
+
+            if (pstate->batblast >= BBTIME)
+                DogBlast(ob);
+
+            else if (pstate->weapon == wp_dog)
+                DogAttack(ob);
+            else if (pstate->weapon == wp_bat)
+                BatAttack (ob);
+            else
+#endif
+                GunAttack(ob);
+
+            break;
+
+        case at_missileweapon:
+            if (!pstate->ammo)
+            {
+                pstate->attackframe = pstate->weaponframe = 0;
+                pstate->batblast = 0;
+                return;
+            }
+
+            if (vrenabled && (ob==player))
+            {
+                StartVRFeedback(1);
+            }
+            ob->flags |= FL_FULLLIGHT;
+            if (ob==player)
+                SetIllumination(2);
+            PlayerMissileAttack(ob);
+
+
+            if (!(ob->flags & FL_GODMODE) && !godmode)
+            {
+                if (!BATTLEMODE || (gamestate.BattleOptions.Ammo != bo_infinite_shots))
+                    pstate->ammo--;
+
+                if ((ob==player) && SHOW_BOTTOM_STATUS_BAR() )
+                    DrawBarAmmo (false);
+            }
+#if (SHAREWARE == 0)
+            if (pstate->weapon == wp_kes)
+                pstate->weapondowntics = KESTICS/(2*GMOVE);
+#endif
+            break;
+
+        default:
+            ;
+        }
+
+        pstate->attackframe++;
+        cur = &(WEAPONS[pstate->weapon].attackinfo[pstate->attackframe]);
+        pstate->weaponframe = cur->frame;
+        pstate->attackcount = cur->mtics;
+
+    }
+    else
+        pstate->attackcount --;
+}
+
+/*
+===============
+=
+= T_BatBlast
+=
+===============
+*/
+
+void  T_BatBlast (objtype *ob)
+{
+    attack_t   *cur;
+    playertype *pstate;
+
+
+    Thrust(ob);
+    CheckPlayerSpecials(ob);
+    M_LINKSTATE(ob,pstate);
+
+
+//Commented out until we find if it's valid
+    /*
+    	if (!ob->ticcount)
+    	 {if ( pstate->buttonstate[bt_use] && !pstate->buttonheld[bt_use] )
+    		pstate->buttonstate[bt_use] = false;
+
+    	  if ( pstate->buttonstate[bt_attack] && !pstate->buttonheld[bt_attack])
+    		pstate->buttonstate[bt_attack] = false;
+    	 }
+    */
+//
+// change frame and fire
+//
+
+    BatBlast(ob);
+
+
+
+    if (pstate->attackframe >= WEAPONS[pstate->weapon].numattacks)
+        Error("\n attackframe %d for weapon %d gt numattacks %d",
+              pstate->attackframe,pstate->weapon,
+              WEAPONS[pstate->weapon].numattacks
+             );
+
+
+
+    cur = &(WEAPONS[pstate->weapon].attackinfo[pstate->attackframe]);
+    if (! pstate->attackcount)
+    {   if (cur->attack == reset)
+        {
+            if (!(ob->flags & FL_GODMODE) && (!godmode))
+            {   pstate->ammo --;
+                if ((ob==player) && SHOW_BOTTOM_STATUS_BAR() )
+                    DrawBarAmmo (false);
+            }
+
+            if (!pstate->ammo)
+            {   pstate->new_weapon = pstate->bulletweapon;
+                pstate->ammo = -1;
+                pstate->missileweapon = -1;
+                pstate->weapondowntics = WEAPONS[pstate->weapon].screenheight/GMOVE;
+
+            }
+
+            NewState(ob,&s_player);
+            pstate->attackframe = pstate->weaponframe = 0;
+            pstate->batblast = 0;
+            return;
+        }
+        pstate->attackframe++;
+        pstate->weaponframe = WEAPONS[pstate->weapon].attackinfo[pstate->attackframe].frame;
+        cur = &(WEAPONS[pstate->weapon].attackinfo[pstate->attackframe]);
+        pstate->attackcount = cur->mtics;
+    }
+    else
+        pstate->attackcount --;
+
+}
+
+
+
+
+void  T_Free (objtype *ob)
+{
+    attack_t   *cur;
+
+
+    if (!ob->ticcount)
+    {
+
+
+//Commented out until we find if it's valid
+        /*
+        	if ( locplayerstate->buttonstate[bt_use] && !locplayerstate->buttonheld[bt_use] )
+        		locplayerstate->buttonstate[bt_use] = false;
+
+        	if ( locplayerstate->buttonstate[bt_attack] && !locplayerstate->buttonheld[bt_attack])
+        		locplayerstate->buttonstate[bt_attack] = false;
+        */
+        Thrust(ob);
+
+    }
+    CheckPlayerSpecials(ob);
+
+
+
+
+
+
+    cur = &(FREE.attackinfo[locplayerstate->attackframe]);
+
+    if (!locplayerstate->attackcount)
+    {
+        if ((locplayerstate->weaponframe > 3) && (locplayerstate->weaponframe < 8))
+            locplayerstate->NETCAPTURED ++;
+        else if (locplayerstate->weaponframe == 8)
+        {
+            locplayerstate->NETCAPTURED = -2;
+            MISCVARS->NET_IN_FLIGHT = false;
+            NewState(ob,&s_player);
+            locplayerstate->weapondowntics = FREE.screenheight/GMOVE;
+            return;
+        }
+
+        locplayerstate->attackframe++;
+        cur = &(FREE.attackinfo[locplayerstate->attackframe]);
+        locplayerstate->weaponframe = cur->frame;
+
+        locplayerstate->attackcount = cur->mtics;
+
+    }
+    else
+        locplayerstate->attackcount --;
+}
+
+
+
+void Switch_Who_Is_It_For_Tag(objtype *actor1,objtype *actor2)
+{
+    playertype *pstate;
+
+    M_LINKSTATE(actor1,pstate);
+    if (pstate->buttonstate[bt_use])
+    {   playertype *pstate2;
+
+        M_LINKSTATE(actor2,pstate2);
+        pstate2->oldmissileweapon = pstate2->oldweapon = pstate2->new_weapon =
+                                        pstate2->missileweapon = pstate2->weapon = wp_godhand;
+        pstate2->weaponheight = 144;
+        pstate2->weaponuptics = (144 - TAGHANDHEIGHT)/GMOVE;
+        pstate2->weapondowntics = 0;
+        actor1->flags |= FL_DIDTAG;
+        actor2->flags |= FL_DESIGNATED;
+        UpdateKills = true;
+
+        actor1->flags &= ~FL_DESIGNATED;
+        BATTLE_PlayerKilledPlayer(battle_player_tagged,
+                                  actor1->dirchoosetime, actor2->dirchoosetime);
+    }
+
+}
+
+
+
+void CheckTagGame(objtype *actor1,objtype*actor2)
+{
+//if ((actor1->obclass != playerobj) || (actor2->obclass != playerobj))
+    //return;
+
+    if (!BATTLEMODE)
+        return;
+
+    if (gamestate.battlemode != battle_Tag)
+        return;
+
+    SD_PlaySoundRTP(SD_GETBONUSSND,actor1->x,actor1->y);
+
+    if (actor1->flags & FL_DESIGNATED)
+        Switch_Who_Is_It_For_Tag(actor1,actor2);
+    else if (actor2->flags & FL_DESIGNATED)
+        Switch_Who_Is_It_For_Tag(actor2,actor1);
+
+}
+
+
+
+
+
+
+/*
+======================
+=
+= CheckWeaponChange
+=
+= Keys 1-4 change weapons
+=
+======================
+*/
+
+void CheckWeaponChange (objtype * ob)
+{
+//   int     i;
+
+    playertype * pstate;
+
+
+    M_LINKSTATE(ob,pstate);
+    //pstate = (ob == player)?(&playerstate):(&remoteplayerstate);
+    if (W_CHANGE(pstate))
+        return;
+
+    if (!ARMED(ob->dirchoosetime))
+        return;
+
+    if ((ob->flags & FL_DOGMODE) || (ob->flags & FL_GODMODE))
+        return;
+
+#if (WEAPONCHEAT==1)
+    if (godmode && Keyboard[sc_Insert])
+    {
+        SD_Play(SD_SELECTWPNSND);
+
+        // FOR DEBUG only
+        /*
+        if (pstate->buttonstate[bt_run])
+         {
+         if (pstate->weapon == 0)
+          pstate->new_weapon = wp_bat;
+         else
+          pstate->new_weapon --;
+         }
+        else
+         {*/
+        if (pstate->weapon == MAXWEAPONS-1)
+            pstate->new_weapon = 0;
+        else
+            pstate->new_weapon ++;
+        //}
+        if (pstate->new_weapon <= wp_mp40)
+        {   pstate->bulletweapon = pstate->new_weapon;
+            pstate->HASBULLETWEAPON[pstate->new_weapon] = 1;
+        }
+        else
+            pstate->missileweapon = pstate->new_weapon;
+
+        pstate->ammo = stats[GetItemForWeapon(pstate->missileweapon)].ammo;
+        if (pstate->ammo<1)
+            pstate->ammo=5;
+        StartWeaponChange;
+        //pstate->weapondowntics = WEAPONS[pstate->weapon].screenheight/GMOVE;
+        //if ((ob==player) && SHOW_BOTTOM_STATUS_BAR() )
+        //		DrawBarAmmo (false);
+    }
+    else if (pstate->buttonstate[bt_swapweapon])
+#else
+    if (pstate->buttonstate[bt_swapweapon])
+#endif
+    {
+        if ((pstate->weapon == pstate->bulletweapon) &&
+                (pstate->missileweapon != -1))
+        {   pstate->new_weapon = pstate->missileweapon;
+            StartWeaponChange;
+        }
+
+        else if (pstate->weapon != pstate->bulletweapon)
+        {   pstate->new_weapon = pstate->bulletweapon;
+            StartWeaponChange;
+        }
+    }
+    else if ((pstate->buttonstate[bt_dropweapon]) &&
+             (!gamestate.BattleOptions.WeaponPersistence))
+    {
+        if (pstate->weapon==pstate->bulletweapon)
+        {
+            if ((ob==player) && (!(pstate->buttonheld[bt_dropweapon])))
+                PlayNoWaySound();
+        }
+        else
+        {
+            if (sprites[ob->tilex][ob->tiley])
+            {
+                if ((ob==player) && (!(pstate->buttonheld[bt_dropweapon])))
+                    PlayNoWaySound();
+            }
+            else
+            {
+                DropWeapon(ob);
+            }
+        }
+    }
+
+
+
+    if (pstate->buttonstate[bt_pistol])
+    {   if (pstate->weapon != wp_pistol)
+        {   pstate->new_weapon = pstate->bulletweapon = wp_pistol;
+            StartWeaponChange;
+        }
+    }
+
+    else if (pstate->buttonstate[bt_dualpistol])
+    {   if ((pstate->weapon != wp_twopistol) && pstate->HASBULLETWEAPON[wp_twopistol])
+        {   pstate->new_weapon = pstate->bulletweapon = wp_twopistol;
+            StartWeaponChange;
+        }
+    }
+    else if (pstate->buttonstate[bt_mp40])
+    {   if ((pstate->weapon != wp_mp40) && pstate->HASBULLETWEAPON[wp_mp40])
+        {   pstate->new_weapon = pstate->bulletweapon = wp_mp40;
+            StartWeaponChange;
+        }
+    }
+    else if (pstate->buttonstate[bt_missileweapon])
+    {   if ((pstate->weapon != pstate->missileweapon) && (pstate->missileweapon != -1))
+        {   pstate->new_weapon = pstate->missileweapon;
+            StartWeaponChange;
+        }
+    }
+}
+
+
+void SetWhoHaveWeapons(void)
+{
+    playertype *pstate;
+    objtype    *ob;
+    int        i;
+
+    for ( i = 0; i < numplayers; i++ )
+    {
+        ob = PLAYER[ i ];
+        M_LINKSTATE( ob, pstate );
+
+        if ( ARMED( ob->dirchoosetime ))
+        {
+            if (pstate->weapon == -1)
+            {
+                if (( pstate->missileweapon != -1 ) && (pstate->ammo>0))
+                    pstate->new_weapon = pstate->missileweapon;
+
+                else
+                {
+                    if ( pstate->bulletweapon == -1 )
+                    {
+                        pstate->HASBULLETWEAPON[ wp_pistol ] = 1;
+                        pstate->bulletweapon = wp_pistol;
+                    }
+                    pstate->new_weapon = pstate->bulletweapon;
+                    pstate->ammo = -1;
+                }
+
+                pstate->weapon = pstate->new_weapon;
+                pstate->weapondowntics = 0;
+                pstate->weaponuptics = WEAPONS[pstate->new_weapon].screenheight/GMOVE;
+                pstate->weaponheight = pstate->weaponuptics*GMOVE ;
+                pstate->attackframe = pstate->weaponframe =
+                                          pstate->batblast = 0;
+                if (i == consoleplayer)
+                    DrawBarAmmo(false);
+            }
+        }
+        else
+        {
+            if (ob->flags & FL_DOGMODE)
+            {
+                ob->temp2 = DOGMODERISE;
+                pstate->oldweapon = -1;
+                ResetWeapons(ob);
+                if (ob->state->condition & SF_DOGSTATE)
+                    NewState(ob,&s_player);
+            }
+            else if (ob->flags & FL_GODMODE)
+            {
+                ob->temp2 = GODMODEFALL;
+                pstate->oldweapon = -1;
+                ResetWeapons(ob);
+            }
+            else
+            {
+                pstate->new_weapon = -1;
+                StartWeaponChange;
+            }
+            pstate->attackframe = pstate->weaponframe =
+                                      pstate->batblast = 0;
+        }
+    }
+}
+
+
+
+
+
+
+
+
+void CheckWeaponStates(objtype*ob)
+{   playertype *pstate;
+
+    M_LINKSTATE(ob,pstate);
+
+    if (gamestate.battlemode == battle_Tag)
+    {   if (pstate->weapondowntics)
+        {   pstate->weaponheight += GMOVE;
+            pstate->weapondowntics --;
+            if (!pstate->weapondowntics)
+                pstate->weapon = pstate->missileweapon = pstate->bulletweapon =
+                                     pstate->new_weapon = pstate->oldweapon = pstate->oldmissileweapon = -1;
+
+        }
+
+
+        if (pstate->weaponuptics)
+        {   pstate->weaponheight -= GMOVE;
+            pstate->weaponuptics --;
+        }
+        return;
+    }
+
+    if (pstate->weapondowntics)
+    {   pstate->weaponheight += GMOVE;
+#if (SHAREWARE == 0)
+        if ((pstate->weapon == wp_kes) && pstate->attackframe)
+            pstate->weaponheight += GMOVE;
+#endif
+        pstate->weapondowntics --;
+    }
+    else if (pstate->weaponuptics)
+    {   pstate->weaponheight -= GMOVE;
+#if (SHAREWARE == 0)
+        if ((pstate->weapon == wp_kes) && pstate->attackframe)
+            pstate->weaponheight -= GMOVE;
+#endif
+
+        pstate->weaponuptics --;
+    }
+    else if ((pstate->weapon == pstate->new_weapon) && (!pstate->NETCAPTURED))
+        pstate->weaponheight = 0;
+
+}
+
+
+/*
+=============================
+=
+= CheckSpecialSounds
+=
+=============================
+*/
+
+#define REGDOGSTATE(ob) \
+   ((ob->state == &s_serialdog) || (ob->state == &s_serialdog2) || \
+    (ob->state == &s_serialdog3) || (ob->state == &s_serialdog4)   \
+   )
+
+static int dyingvolume=255;
+void CheckSpecialSounds(objtype *ob, playertype *pstate)
+{
+    int shift;
+
+    if ((!BATTLEMODE) && (ob == player))
+    {
+        if (pstate->health < MaxHitpointsForCharacter(locplayerstate)/5)
+        {
+            pstate->healthtime ++;
+            if (pstate->healthtime > 2*VBLCOUNTER)
+            {
+                pstate->healthtime = 0;
+                SD_PlayPitchedSound ( SD_PLAYERDYINGSND, dyingvolume, 0 );
+                if (dyingvolume>80)
+                    dyingvolume-=40;
+            }
+        }
+        else
+        {
+            dyingvolume=255;
+        }
+    }
+
+    if (((ob->flags & FL_GODMODE) || (ob->flags & FL_DOGMODE)) &&
+            (!W_CHANGE(pstate))
+       )
+    {
+        pstate->soundtime++;
+        if (pstate->soundtime > (2*VBLCOUNTER))
+        {
+            int rand;
+
+            rand = GameRandomNumber("player special sound",0);
+            shift = (pstate->soundtime>>5);
+            if ((rand << shift) > 3500)
+            {
+                int sound;
+
+                pstate->soundtime = 0;
+
+                rand = GameRandomNumber("player god scare",0);
+
+                if (ob->flags & FL_GODMODE)
+                {
+                    sound = SD_GODMODE1SND;
+                    if (rand < 160)
+                        sound++;
+                    if (rand < 80)
+                        sound ++;
+                    SD_PlaySoundRTP(sound,ob->x,ob->y);
+                }
+#if (SHAREWARE == 0)
+                else if ((!pstate->batblast) && (!ob->momentumz) &&
+                         (REGDOGSTATE(ob))
+                        )
+                {
+                    sound = SD_DOGMODEPANTSND;
+                    if (rand < 128)
+                        sound += 2;
+                    NewState(ob,&s_doglick);
+                    pstate->attackframe = pstate->weaponframe =
+                                              pstate->batblast = 0;
+                    SD_PlaySoundRTP(sound,ob->x,ob->y);
+                }
+#endif
+            }
+        }
+    }
+
+
+
+
+    else if (ob->flags & FL_GASMASK)
+    {
+        pstate->soundtime ++;
+
+        if (pstate->soundtime > (3*VBLCOUNTER))
+        {
+            pstate->soundtime = 0;
+            SD_PlaySoundRTP(SD_GASMASKSND,ob->x,ob->y);
+        }
+    }
+
+
+    else if (MISCVARS->GASON)
+    {
+        pstate->soundtime ++;
+        if (pstate->soundtime > (2*VBLCOUNTER))
+        {
+            int rand;
+
+            rand = GameRandomNumber("player cough sound",0);
+            shift = (pstate->soundtime>>5);
+            if ((rand << shift) > 2000)
+            {
+                pstate->soundtime = 0;
+                if ((pstate->player == 1) || (pstate->player == 3))
+                    SD_PlaySoundRTP(SD_PLAYERCOUGHFSND,ob->x,ob->y);
+                else
+                    SD_PlaySoundRTP(SD_PLAYERCOUGHMSND,ob->x,ob->y);
+            }
+        }
+    }
+}
+
+/*
+static int dyingvolume=255;
+void CheckSpecialSounds(objtype *ob, playertype *pstate)
+   {
+   int shift;
+
+   if ((!BATTLEMODE) && (ob == player))
+      {
+      if (pstate->health < MaxHitpointsForCharacter(locplayerstate)/5)
+         {
+         pstate->healthtime ++;
+         if (pstate->healthtime > 2*VBLCOUNTER)
+            {
+            pstate->healthtime = 0;
+            SD_PlayPitchedSound ( SD_PLAYERDYINGSND, dyingvolume, 0 );
+            if (dyingvolume>80)
+               dyingvolume-=40;
+            }
+         }
+      else
+         {
+         dyingvolume=255;
+         }
+      }
+
+   if (((ob->flags & FL_GODMODE) || (ob->flags & FL_DOGMODE)) &&
+       (!W_CHANGE(pstate))
+      )
+      {
+      pstate->soundtime++;
+      if (pstate->soundtime > (2*VBLCOUNTER))
+         {
+         int rand;
+
+         rand = GameRandomNumber("player special sound",0);
+         shift = (pstate->soundtime>>5);
+         if ((rand << shift) > 3500)
+            {
+            int sound;
+
+            pstate->soundtime = 0;
+
+            rand = GameRandomNumber("player god scare",0);
+
+            if (ob->flags & FL_GODMODE)
+               {
+               sound = SD_GODMODE1SND;
+               if (rand < 160)
+                  sound++;
+               if (rand < 80)
+                  sound ++;
+               SD_PlaySoundRTP(sound,ob->x,ob->y);
+               }
+#if (SHAREWARE == 0)
+            else if (!pstate->batblast)
+               {
+               sound = SD_DOGMODEPANTSND;
+               if (rand < 128)
+                  sound += 2;
+               NewState(ob,&s_doglick);
+               pstate->attackframe = pstate->weaponframe =
+               pstate->batblast = 0;
+               SD_PlaySoundRTP(sound,ob->x,ob->y);
+               }
+#endif
+            }
+         }
+      }
+
+
+
+
+   else if (ob->flags & FL_GASMASK)
+      {
+      pstate->soundtime ++;
+
+      if (pstate->soundtime > (3*VBLCOUNTER))
+         {
+         pstate->soundtime = 0;
+			SD_PlaySoundRTP(SD_GASMASKSND,ob->x,ob->y);
+         }
+      }
+
+
+   else if (MISCVARS->GASON)
+      {
+      pstate->soundtime ++;
+      if (pstate->soundtime > (2*VBLCOUNTER))
+         {
+         int rand;
+
+         rand = GameRandomNumber("player cough sound",0);
+         shift = (pstate->soundtime>>5);
+         if ((rand << shift) > 2000)
+            {
+            pstate->soundtime = 0;
+            if ((pstate->player == 1) || (pstate->player == 3))
+               SD_PlaySoundRTP(SD_PLAYERCOUGHFSND,ob->x,ob->y);
+            else
+               SD_PlaySoundRTP(SD_PLAYERCOUGHMSND,ob->x,ob->y);
+            }
+         }
+      }
+   }
+
+*/
+
+
+/*
+=============================
+=
+= CheckProtectionsAndPowerups
+=
+=============================
+*/
+
+
+
+void CheckProtectionsAndPowerups(objtype *ob, playertype *pstate)
+{
+    if (pstate->poweruptime)
+    {
+        pstate->poweruptime --;
+        if (pstate->poweruptime < 0)
+            pstate->poweruptime = 0;
+        if (ob==player)
+            GM_UpdateBonus (pstate->poweruptime, true);
+    }
+    else
+    {
+        if (ob->flags & FL_ELASTO)
+        {
+            ob->flags &= ~FL_NOFRICTION;
+            if (ob==player)
+                GM_UpdateBonus (pstate->poweruptime, true);
+            SD_PlaySoundRTP(SD_LOSEMODESND,ob->x, ob->y);
+        }
+        else if (ob->flags & FL_GODMODE)
+        {   ob->temp2 = GODMODEFALL;
+            if ((pstate->player == 1) || (pstate->player == 3))
+                SD_PlaySoundRTP(SD_GODWOMANSND,ob->x, ob->y);
+            else
+                SD_PlaySoundRTP(SD_GODMANSND,ob->x, ob->y);
+            ResetWeapons(ob);
+        }
+        else if (ob->flags & FL_DOGMODE)
+        {   int wall;
+
+            wall = tilemap[ob->tilex][ob->tiley];
+            if ((wall & 0x4000) && (wall & 0x8000))
+            {   maskedwallobj_t * mw;
+
+                mw=maskobjlist[wall&0x3ff];
+                if (mw->flags&MW_NONDOGBLOCKING)
+                    return;
+            }
+
+
+            ob->temp2 = DOGMODERISE;
+            if ((pstate->player == 1) || (pstate->player == 3))
+                SD_PlaySoundRTP(SD_DOGWOMANSND,ob->x, ob->y);
+            else
+                SD_PlaySoundRTP(SD_DOGMANSND,ob->x, ob->y);
+            ResetWeapons(ob);
+            if (ob->state->condition & SF_DOGSTATE)
+            {
+                NewState(ob,&s_player);
+                pstate->attackframe = pstate->weaponframe = pstate->batblast = 0;
+            }
+        }
+        else if (ob->flags & FL_SHROOMS)
+        {
+            ResetFocalWidth ();
+            SD_PlaySoundRTP(SD_LOSEMODESND,ob->x, ob->y);
+        }
+        else if (ob->flags & FL_FLEET)
+            SD_PlaySoundRTP(SD_LOSEMODESND,ob->x, ob->y);
+
+        ob->flags &= ~(FL_SHROOMS|FL_ELASTO|FL_FLEET|FL_GODMODE|FL_DOGMODE);
+    }
+
+    if (pstate->protectiontime)
+    {
+        pstate->protectiontime --;
+        if (pstate->protectiontime <= 0)
+        {
+            SD_PlaySoundRTP(SD_LOSEMODESND,ob->x, ob->y);
+            pstate->protectiontime = 0;
+        }
+        if (ob==player)
+            GM_UpdateBonus (pstate->protectiontime, false);
+    }
+    else
+        ob->flags &= ~(FL_BPV|FL_AV|FL_GASMASK);
+
+}
+
+
+
+/*
+=============================
+=
+= CheckFlying
+=
+=============================
+*/
+
+void CheckFlying(objtype*ob,playertype *pstate)
+{
+
+
+    if (pstate->buttonstate[bt_lookup] || CYBERLOOKUP)
+    {
+        ob->momentumz = -FLYINGZMOM;
+    }
+    if (pstate->buttonstate[bt_lookdown] || CYBERLOOKDOWN)
+    {
+        ob->momentumz = FLYINGZMOM;
+    }
+
+    /*
+    if (!M_ISDOOR(((ob->x + costable[ob->angle])>>16),
+          ((ob->y - sintable[ob->angle])>>16)) &&
+          (pstate->buttonstate[bt_use]) &&
+          (!pstate->buttonheld[bt_use])
+       )
+       {
+       int op;
+       int dist;
+
+       dist=JETPACKTHRUST;
+       if (ob->z-dist<-15)
+          dist=ob->z+15;
+       if (dist>0)
+          {
+          op = FixedMul(GRAVITY,(dist<<16)) << 1;
+          ob->momentumz = -FixedSqrtHP(op);
+          SD_PlaySoundRTP(SD_FLYINGSND,ob->x,ob->y);
+          }
+       }
+    */
+}
+
+
+
+/*
+=============================
+=
+= CheckTemp2Codes
+=
+=============================
+*/
+
+
+#define IN_AIR(ob) \
+             (!((ob->z == nominalheight) ||              \
+                (IsPlatform(ob->tilex,ob->tiley)) ||    \
+                (DiskAt(ob->tilex,ob->tiley))           \
+               )                                        \
+             )                                          \
+
+
+void CheckTemp2Codes(objtype *ob,playertype *pstate)
+{
+    int pitheight;
+    int godheight;
+    int dogheight;
+    int height;
+    int oldz;
+    int destheightoffset;
+
+
+    pitheight    = maxheight - 8;
+    height = ob->z + pstate->playerheight;
+    dogheight    = ob->z + DOGOFFSET;
+    godheight    = ob->z + GODOFFSET;
+
+    //SoftError("\nheightoffset: %d, temp2: %d",pstate->heightoffset,ob->temp2);
+
+
+    if (!((ob->temp2 == PITFALL) || (ob->temp2 == PITRISE)))
+    {
+
+        oldz = ob->z;
+        //SoftError("\n zmom %d, oldz %d, newz %d",ob->momentumz,oldz,ob->z);
+
+        if (ob->flags & FL_FLEET)
+        {
+            if (IN_AIR(ob))
+                pstate->heightoffset = FixedMulShift(0x4000,sintable[(oldpolltime<<6)&2047],28);
+
+            ob->z += ((ob->momentumz+0x8000)>>16);
+            ob->momentumz = 0;
+
+        }
+        else
+        {
+            ob->z += (ob->momentumz>>16);
+            ob->momentumz += GRAVITY;
+        }
+
+
+        if (ob->z >= nominalheight)
+        {
+            ob->z = nominalheight;
+            ob->momentumz = 0;
+            //if (platform == nominalheight)
+            //{//ob->temp2 = 0;
+            //ob->momentumz = 0;
+            if ((oldz < nominalheight) && (!(ob->flags & FL_RIDING)))
+            {
+                SD_PlaySoundRTP(SD_PLAYERLANDSND,ob->x,ob->y);
+            }
+
+            if (!(ob->flags & FL_ELASTO))
+                ob->flags &= ~FL_NOFRICTION;
+            //  }
+        }
+        else if (height < 1)
+        {
+            ob->momentumz = 0;
+            ob->z = 1-pstate->playerheight;
+        }
+
+
+
+        switch (ob->temp2)
+        {
+        case RENORMALIZE:
+            pstate->heightoffset --;
+
+            if (ob->flags & FL_DOGMODE)
+                destheightoffset = DOGOFFSET-pstate->playerheight;
+            else
+                destheightoffset = 0;
+
+            if (pstate->heightoffset <= destheightoffset)
+            {
+                ob->temp2 = 0;
+                pstate->heightoffset = 0;
+            }
+            pstate->oldheightoffset = pstate->heightoffset;
+
+            break;
+
+        case COLUMNCRUSH:
+            pstate->heightoffset += 4;
+            if (pstate->heightoffset >= 30)
+                pstate->heightoffset = 30;
+
+            pstate->oldheightoffset = pstate->heightoffset;
+            break;
+
+        case GODMODERISE:
+            pstate->heightoffset --;
+            pstate->oldheightoffset = pstate->heightoffset;
+            if ((height+pstate->heightoffset) <= godheight)
+            {
+                ob->temp2 = 0;
+                pstate->poweruptime = POWERUPTICS;
+            }
+            break;
+
+
+        case GODMODEFALL:
+            pstate->heightoffset ++;
+            pstate->oldheightoffset = pstate->heightoffset;
+            SetPlayerHorizon(pstate,NORMALYZANGLE);
+            if (pstate->heightoffset >= 0)
+            {
+                ob->temp2 = 0;
+                ob->flags &= ~FL_GODMODE;
+                SetNormalHorizon(ob);
+            }
+            break;
+
+        case DOGMODERISE:
+            pstate->heightoffset --;
+            pstate->oldheightoffset = pstate->heightoffset;
+            SetPlayerHorizon(pstate,NORMALYZANGLE);
+            if (pstate->heightoffset <= 0)
+            {
+                ob->temp2 = 0;
+                ob->flags &= ~FL_DOGMODE;
+                SetNormalHorizon(ob);
+            }
+            break;
+
+
+        case DOGMODEFALL:
+            pstate->heightoffset ++;
+            pstate->oldheightoffset = pstate->heightoffset;
+            if (pstate->heightoffset >= (DOGOFFSET-pstate->playerheight))
+            {
+                ob->temp2 = 0;
+                pstate->poweruptime = POWERUPTICS;
+            }
+            break;
+
+        case STEPUP:
+            //Debug("\n\n heightoffset adjusted from %d to %d",
+            //	 pstate->heightoffset,pstate->heightoffset - STEPADJUST);
+            pstate->heightoffset -= STEPADJUST;
+            if (pstate->heightoffset <= pstate->oldheightoffset)
+            {   ob->temp2 = 0;
+                //Debug("\n done adjusting heightoffset");
+                pstate->heightoffset = pstate->oldheightoffset;
+            }
+            break;
+
+        case STEPDOWN:
+            pstate->heightoffset += STEPADJUST;
+            if (pstate->heightoffset >= pstate->oldheightoffset)
+            {   ob->temp2 = 0;
+                pstate->heightoffset = pstate->oldheightoffset;
+            }
+            break;
+
+        case 0:
+            if (!((ob->flags & FL_FLEET) ||
+                    (ob->flags & FL_DOGMODE) ||
+                    (ob->flags & FL_GODMODE)
+                 )
+               )
+                pstate->heightoffset = 0;
+            break;
+
+        }
+
+
+    }
+
+
+    else if (ob->temp2 == PITFALL)
+    {
+        if (ob->z != pitheight)
+        {
+            ob->z += (ob->momentumz>>16);
+            ob->momentumz += GRAVITY;
+            if (ob->z >= pitheight)
+            {
+                ob->z = pitheight;
+                ob->momentumz = 0;
+                if (!(ob->flags & FL_DYING))
+                {   DamageThing(ob,10);
+                    Collision(ob,(objtype*)NULL,0,0);
+                    M_CheckPlayerKilled(ob);
+                }
+            }
+        }
+        else if (ob->momentumx || ob->momentumy)
+        {
+            ob->temp2 = PITRISE;
+            ob->momentumz = -2;
+        }
+    }
+
+    else if (ob->temp2 == PITRISE)
+    {   ob->z += ob->momentumz;
+        if (ob->z <= nominalheight)
+        {   ob->z = nominalheight;
+            ob->temp2 = 0;
+            ob->momentumz = 0;
+            if (pstate->heightoffset)
+                ob->temp2 = RENORMALIZE;
+        }
+    }
+
+
+
+
+
+
+}
+
+
+
+/*
+=============================
+=
+= CheckRemoteRecording
+=
+=============================
+*/
+
+void CheckRemoteRecording(objtype *ob,playertype *pstate)
+{
+    if (networkgame==true)
+    {
+        if ( (pstate->buttonstate[bt_recordsound]) &&
+                (!pstate->buttonheld[bt_recordsound])
+           )
+        {
+            if (SD_RecordingActive()==false)
+            {
+                SD_SetRecordingActive ();
+                PlayerRecording=ob->dirchoosetime;
+                if (ob==player)
+                {
+                    SD_StartRecordingSound();
+                    UpdateClientControls();
+                }
+            }
+        }
+        else if ( (pstate->buttonheld[bt_recordsound]) &&
+                  (!pstate->buttonstate[bt_recordsound])
+                )
+        {
+            if (SD_RecordingActive()==true)
+            {
+                if (ob->dirchoosetime==PlayerRecording)
+                {
+                    if (ob==player)
+                        SD_StopRecordingSound();
+                    SD_ClearRecordingActive();
+                    PlayerRecording=-1;
+                    UpdateClientControls();
+                }
+            }
+        }
+    }
+}
+
+
+/*
+=============================
+=
+= CheckPlayerSpecials
+=
+=============================
+*/
+
+
+void CheckPlayerSpecials(objtype * ob)
+{
+    playertype * pstate;
+
+    M_LINKSTATE(ob,pstate);
+
+    // Check for recording of sound
+
+    CheckRemoteRecording(ob,pstate);
+    CheckTemp2Codes(ob,pstate);
+
+    if (ob->flags & FL_DYING)
+        return;
+
+    CheckSpecialSounds(ob,pstate);
+    CheckProtectionsAndPowerups(ob,pstate);
+}
+
+#if (SHAREWARE == 0)
+/*
+===============
+=
+= T_DogUse
+=
+===============
+*/
+
+void  T_DogUse (objtype *ob)
+{
+    attack_t   *cur;
+    playertype *pstate;
+    statetype *oldstate;
+
+    M_LINKSTATE(ob,pstate);
+
+    Thrust(ob);
+    oldstate = ob->state;
+    CheckPlayerSpecials(ob);
+    if (ob->state != oldstate)
+    {
+        return;
+    }
+
+
+
+
+//Commented out until we find if it's valid
+    /*
+      if (!ob->ticcount)
+    	{if ( pstate->buttonstate[bt_use] && !pstate->buttonheld[bt_use] )
+    		pstate->buttonstate[bt_use] = false;
+    	}
+    */
+
+    if (pstate->attackframe >= DOGSCRATCH.numattacks)
+        Error("\n attackframe %d for DOGSCRATCH gt numattacks %d",
+              pstate->attackframe,DOGSCRATCH.numattacks
+             );
+
+
+
+    cur = &(DOGSCRATCH.attackinfo[pstate->attackframe]);
+    if (! pstate->attackcount)
+    {   switch (cur->attack)
+        {
+        case reset:
+        {
+            NewState(ob,&s_dogwait);
+            pstate->attackframe = pstate->weaponframe = pstate->batblast = 0;
+            return;
+        }
+        break;
+        case at_pulltrigger:
+            pstate->buttonheld[bt_use]=false;
+            Cmd_Use(ob);
+            break;
+        default:
+            break;
+        }
+        pstate->attackframe++;
+        cur = &(DOGSCRATCH.attackinfo[pstate->attackframe]);
+        pstate->weaponframe = cur->frame;
+        pstate->attackcount = cur->mtics;
+
+    }
+    else
+        pstate->attackcount --;
+
+
+
+}
+
+/*
+===============
+=
+= T_DogLick
+=
+===============
+*/
+
+
+
+void  T_DogLick (objtype *ob)
+{
+    attack_t   *cur;
+    playertype *pstate;
+    statetype *oldstate;
+
+    M_LINKSTATE(ob,pstate);
+
+    Thrust(ob);
+    oldstate = ob->state;
+    CheckPlayerSpecials(ob);
+    if (ob->state != oldstate)
+    {
+        return;
+    }
+
+
+
+//Commented out until we find if it's valid
+    /*
+      if (!ob->ticcount)
+    	{if ( pstate->buttonstate[bt_use] && !pstate->buttonheld[bt_use] )
+    		pstate->buttonstate[bt_use] = false;
+    	}
+    */
+
+
+    if (pstate->attackframe >= DOGLICK.numattacks)
+        Error("\n attackframe %d for DOGLICK gt numattacks %d",
+              pstate->attackframe,DOGLICK.numattacks
+             );
+
+
+    cur = &(DOGLICK.attackinfo[pstate->attackframe]);
+    if (! pstate->attackcount)
+    {   if (cur->attack == reset)
+        {
+            NewState(ob,&s_serialdog);
+            pstate->attackframe = pstate->weaponframe = 0;
+            return;
+        }
+        pstate->attackframe++;
+        cur = &(DOGLICK.attackinfo[pstate->attackframe]);
+        pstate->weaponframe = cur->frame;
+        pstate->attackcount = cur->mtics;
+
+    }
+    else
+        pstate->attackcount --;
+
+//	if ( playerstate.buttonstate[bt_attack] && (!playerstate.buttonheld[bt_attack]) && (!W_CHANGE))
+    //		Cmd_Fire (ob);
+
+
+}
+
+#endif
+
+void T_DeadWait(objtype*ob)
+{
+    playertype *pstate;
+
+    M_LINKSTATE(ob,pstate);
+    if ((ob->flags & FL_DESIGNATED) && (gamestate.battlemode == battle_CaptureTheTriad))
+    {   int otherteam = (pstate->team ^ 1);
+
+        ob->flags &= ~FL_DESIGNATED;
+        UpdateKills = true;
+        SpawnStatic(TEAM[otherteam].tilex,TEAM[otherteam].tiley,stat_collector,9);
+        LASTSTAT->flags |= FL_COLORED;
+        LASTSTAT->hitpoints = otherteam;
+        LASTSTAT->flags |= FL_ABP;
+        MakeStatActive(LASTSTAT);
+
+    }
+    //ob->momentumx=0;
+    //ob->momentumy=0;
+
+    if (pstate->heightoffset<36)
+    {   pstate->heightoffset++;
+        pstate->oldheightoffset = pstate->heightoffset;
+    }
+
+    if (ob==player)
+    {
+        UpdateLightLevel(player->areanumber);
+        if ((pstate->falling==true) || (ob->momentumz==0))
+        {
+            if (BATTLEMODE)
+                playerdead=true;
+            else
+                playstate = ex_died;
+        }
+    }
+    /*
+    if (BATTLEMODE)
+    	{
+    	objtype * killer=(objtype *)ob->target;
+
+    	dx = killer->x - ob->x;
+    	dy = ob->y - killer->y;
+
+    	if (dx && dy)
+    		ob->angle = atan2_appx (dx,dy);
+    	}
+    */
+    //CheckPlayerSpecials(ob);
+}
+
+/*
+===============
+=
+= T_Player
+=
+===============
+*/
+
+void  T_Player (objtype *ob)
+{
+    playertype *pstate;
+    statetype *oldstate;
+
+#if (SHAREWARE == 0)
+    int eluder;
+#endif
+
+    M_LINKSTATE(ob,pstate);
+
+
+
+#if (SHAREWARE == 0)
+    eluder = ((pstate->weapon == wp_dog) && gamestate.SpawnEluder);
+#endif
+
+    oldstate = ob->state;
+
+    if (ob->flags&FL_DYING)
+    {
+
+        CheckPlayerSpecials(ob);
+        PlayerMove(ob);
+        if (
+            (pstate->falling==true) ||
+            (
+                (!ob->momentumx) &&
+                (!ob->momentumy) &&
+                (!ob->momentumz) &&
+                (!ob->state->tictime)
+            )
+        )
+        {
+            KillActor(ob);
+            if (ob->state == &s_remoteguts12)
+                NewState(ob,&s_gutwait);
+            else
+                NewState(ob,&s_deadwait);
+        }
+        return;
+    }
+
+    Thrust(ob);
+    if (ob->flags & FL_DYING)
+        return;
+
+    oldstate = ob->state;
+    CheckPlayerSpecials(ob);
+    if (ob->state != oldstate)
+    {
+        if (ob->flags & FL_DYING)
+            return;
+    }
+
+    if (!(ob->flags & FL_PAIN))
+    {   if (!(ob->state->condition & SF_DOGSTATE))
+        {   if ((ob->momentumx || ob->momentumy) && (ob->state->condition != SF_DOWN))
+                NewState(ob,&s_remotemove1);
+            else if (NOMOM && (ob->state != &s_player))
+                NewState(ob,&s_player);
+        }
+        else if (NOMOM
+#if (SHAREWARE == 0)
+
+                 && (ob->state != &s_dogwait)
+#endif
+
+                )
+
+            NewState(ob,ob->state);
+
+    }
+    else if (!ob->ticcount)
+    {   if (!(ob->state->condition & SF_DOGSTATE))
+            NewState(ob,&s_player);
+
+        ob->flags &= ~FL_PAIN;
+
+    }
+
+    if (ob->flags & FL_DIDTAG)
+    {   ob->flags &= ~FL_DIDTAG;
+        pstate->weapondowntics = (144 - TAGHANDHEIGHT)/GMOVE;
+    }
+
+
+    CheckWeaponStates(ob);
+
+
+    if (ARMED(ob->dirchoosetime)
+            //(gamestate.battlemode != battle_Tag)
+       )
+    {
+        if (pstate->weapondowntics == 1)  // change to up; during change, up and down
+            // are never zero at the same time
+        {
+            pstate->weapondowntics = 0;
+            pstate->weaponframe = pstate->attackframe = 0;
+
+            if (pstate->NETCAPTURED == -1)
+            {
+                pstate->weaponuptics = FREE.screenheight/GMOVE;
+                pstate->weaponheight = pstate->weaponuptics*GMOVE ;
+                pstate->NETCAPTURED = 1;
+                //          return;
+            }
+            else if (pstate->NETCAPTURED == -2)
+            {
+                pstate->weaponuptics = WEAPONS[pstate->weapon].screenheight/GMOVE;
+                pstate->weaponheight = pstate->weaponuptics*GMOVE ;
+                pstate->NETCAPTURED = 0;
+
+                //return;
+            }
+            else
+            {
+                pstate->weaponuptics = WEAPONS[pstate->new_weapon].screenheight/GMOVE;
+                pstate->weapon = pstate->new_weapon;
+
+                pstate->weaponheight = pstate->weaponuptics*GMOVE ;
+            }
+        }
+
+        else
+            CheckWeaponChange (ob);
+    }
+
+    else if (gamestate.battlemode == battle_Hunter)
+    {
+        if (pstate->weapondowntics == 1)
+
+        {
+            pstate->weapondowntics = 0;
+            pstate->weaponframe = pstate->attackframe = pstate->batblast = 0;
+            pstate->weapon = pstate->new_weapon;
+        }
+    }
+
+//   if ( pstate->buttonstate[bt_use] && (!W_CHANGE(pstate)) )
+
+    if ( pstate->buttonstate[bt_use] )
+        Cmd_Use (ob);
+
+
+    if (W_CHANGE(pstate))
+        return;
+
+
+
+
+    if ((!ARMED(ob->dirchoosetime))
+#if (SHAREWARE == 0)
+            && (pstate->weapon != wp_dog)
+#endif
+       )
+        return;
+
+    if (pstate->buttonstate[bt_attack])
+    {
+#if (SHAREWARE == 0)
+
+        if (eluder)
+            Cmd_Fire(ob);
+
+        else if ((pstate->weapon == wp_bat) ||
+                 (pstate->weapon == wp_dog)
+                )
+        {
+            int oldblast=pstate->batblast;
+
+            pstate->batblast ++;
+
+            if (pstate->weapon==wp_bat)
+            {
+                if (pstate->batblast == 20)
+                    SD_PlaySoundRTP(SD_EXCALIBUILDSND,ob->x,ob->y);
+            }
+            else
+            {
+                if ((pstate->batblast>>4)!=(oldblast>>4))
+                {
+                    int handle;
+
+                    handle=SD_PlaySoundRTP(SD_DOGMODEPREPBLASTSND,ob->x,ob->y);
+                    SD_SetSoundPitch(handle,-(BBTIME<<3)+(pstate->batblast<<3));
+                }
+            }
+            if (pstate->batblast < BBTIME)
+                return;
+
+            if (pstate->weapon == wp_bat)
+                SD_PlaySoundRTP(SD_EXCALIBLASTSND,ob->x,ob->y);
+            else
+                SD_PlaySoundRTP(SD_DOGMODEBLASTSND,ob->x,ob->y);
+        }
+
+        if ((pstate->weapon != wp_split) || (!pstate->buttonheld[bt_attack]))
+#endif
+            //    if (!pstate->buttonheld[bt_attack])
+//#endif
+        {
+
+#if (SHAREWARE == 0)
+
+            if (pstate->weapon == wp_kes)
+                SD_PlaySoundRTP(SD_GRAVBUILDSND,ob->x,ob->y);
+#endif
+
+            Cmd_Fire (ob);
+        }
+    }
+
+#if (SHAREWARE == 0)
+
+    else if (
+        ((pstate->weapon == wp_bat) ||
+         ((pstate->weapon == wp_dog) && (!eluder))
+        ) &&
+        (pstate->buttonheld[bt_attack])
+    )
+    {
+        if (pstate->weapon == wp_bat)
+            SD_StopSound(SD_EXCALIBUILDSND);
+        pstate->batblast = 0;
+        Cmd_Fire(ob);
+    }
+#endif
+
+}
+
+
+
--- /dev/null
+++ b/rott/rt_playr.h
@@ -1,0 +1,295 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+//***************************************************************************
+//
+//   RT_PLAYR.C - Player movement and stuff
+//
+//***************************************************************************
+
+#ifndef _rt_playr_public
+#define _rt_playr_public
+
+#include "rt_actor.h"
+#include "rt_stat.h"
+#include "states.h"
+#include "rottnet.h"
+#include "rt_battl.h"
+#include "develop.h"
+
+
+
+extern int mouse_ry_input_scale;
+
+#define LOW_GRAVITY    10000
+#define NORMAL_GRAVITY 30000
+#define HIGH_GRAVITY   250000
+#define TAGHANDHEIGHT  40
+
+#define MAXDEAD        32
+#define MAXBULLETS     64
+
+#define MAXCODENAMELENGTH 9
+
+#define ARMED(x)   ( \
+                     (gamestate.PlayerHasGun[x]) || \
+                     (!BATTLEMODE) \
+                   )
+
+
+typedef struct
+{
+    statetype *state;
+    int       speed;
+    classtype obclass;
+    int       offset;
+    int       flags;
+
+} missile_stats;
+
+extern missile_stats PlayerMissileData[13];
+
+extern int GetWeaponForItem(int itemnumber);
+extern int GetItemForWeapon(int weapon);
+
+
+typedef enum
+{   reset,
+    reset2,
+    done,
+    at_knife,
+    at_pulltrigger,
+    at_automatic,
+    at_dryheaving,
+    at_missileweapon
+} attack_action;
+
+
+typedef struct atkinf
+{
+    attack_action attack;
+    char  mtics,frame;      // attack is 1 for gun, 2 for knife, 3 for machine guns,
+    // 4 for chaingun (orig. game)
+} attack_t;
+
+typedef struct weaptype
+{   const int screenheight;
+    int startammo;
+    int base_damage;
+    int impulse;
+    int numattacks;
+    attack_t attackinfo[14];
+} williamdidthis;
+
+//
+// Interactive input status of device, returned by SWIFT_Get3DStatus
+//
+typedef struct {
+    short	x;
+    short	y;
+    short	z;
+    short	pitch;
+    short	roll;
+    short	yaw;
+    short	buttons;
+} SWIFT_3DStatus;
+
+
+//
+// Static data about device, returned by SWIFT_GetStaticDeviceInfo
+//
+typedef struct
+{
+    unsigned char	deviceType;
+    unsigned char	majorVersion;
+    unsigned char	minorVersion;
+    unsigned char	coordDescriptor[6];
+    unsigned char	reserved[1];
+} SWIFT_StaticData;
+
+typedef struct
+{
+    int                lives;
+    int                health;
+    int                triads;
+    signed char        ammo;
+    short              poweruptime;
+    short              protectiontime;
+    int                new_weapon;
+    int                keys;
+    int                weapon;
+    int                missileweapon;
+    int                bulletweapon;
+    signed char        HASBULLETWEAPON[3];
+    int                attackframe,attackcount,weaponframe;
+    byte               player;
+    int                topspeed;
+    int                dmomx;
+    int                dmomy;
+    int                angle;
+    int                anglefrac;
+    boolean            buttonheld[NUMBUTTONS];
+    boolean            buttonstate[NUMBUTTONS];
+    int                horizon;
+    int                lastmomz;
+    signed short       playerheight;
+    signed short       heightoffset;
+    signed short       weaponheight;
+    byte               weaponx,weapony;
+    word               batblast;
+    signed char        NETCAPTURED;
+    signed char        HASKNIFE;
+    int                oldweapon, oldmissileweapon;
+    signed short       weapondowntics,weaponuptics;
+    int                soundtime;
+    int                healthtime;
+    objtype*           guntarget;
+    int                targettime;
+//        int                steptime;
+//        int                stepwhich;
+    boolean            falling;
+    int                oldshapeoffset;
+    int                uniformcolor;
+    char               codename[MAXCODENAMELENGTH];
+    int                oldheightoffset;
+    int                team;
+} playertype;
+
+
+typedef struct
+{   int topspeed;
+    int toprunspeed;
+    int hitpoints;
+    int accuracy;
+    int height;
+} ROTTCHARS;
+
+
+#define M_LINKSTATE(x,y) \
+{ y = &PLAYERSTATE[x->dirchoosetime];\
+}
+
+
+extern williamdidthis  DOGSCRATCH;
+extern int        GRAVITY;
+extern int        controlupdatetime;
+extern int        controlupdatestarted;
+extern statobj_t  *DEADPLAYER[MAXDEAD];
+extern int        NUMDEAD;
+extern objtype    *PLAYER[MAXPLAYERS];
+extern objtype    *player;
+extern playertype PLAYERSTATE[MAXPLAYERS],*locplayerstate;
+
+extern ROTTCHARS  characters[5];
+
+extern williamdidthis FREE;
+extern statetype s_player;
+extern williamdidthis WEAPONS[MAXWEAPONS];
+extern boolean cybermanenabled;
+extern boolean spaceballenabled;
+extern boolean SpaceBallPresent;
+extern boolean CybermanPresent;
+extern boolean mouseenabled;
+extern boolean joystickenabled;
+extern boolean joypadenabled;
+extern boolean joystickprogressive;
+extern int joystickport;
+extern int joyxmax, joyymax, joyxmin, joyymin;
+extern int buttonscan[NUMBUTTONS];
+extern int buttonmouse[6];
+extern int buttonjoy[8];
+extern boolean  buttonpoll[NUMBUTTONS];
+extern boolean godmode;
+extern boolean missilecam;
+extern objtype       * missobj;
+extern int lastpolltime;
+
+extern int controlbuf[3];
+extern int buttonbits;
+
+extern int pausedstartedticcount;
+extern boolean RefreshPause;
+
+
+void     PlayNoWaySound(void);
+int      GetBonusTimeForItem(int);
+int      GetRespawnTimeForItem(int);
+int      GetItemForWeapon(int);
+void     SetWhoHaveWeapons(void);
+int      MaxHitpointsForCharacter(playertype*);
+void     RespawnPlayerobj(objtype*);
+void     RevivePlayerobj(int,int,int,objtype*);
+void     OperateElevatorSwitch(objtype*,int,int,int);
+void     ResetPlayerstate(playertype*);
+void     InitializeWeapons(playertype*);
+void     DropWeapon(objtype*ob);
+void     PollKeyboardButtons (void);
+void     PollMouseButtons (void);
+void     PollJoystickButtons (void);
+void     PollKeyboardMove (void);
+void     PollCyberman (void);
+void     PollMouseMove (void);
+void     PollJoystickMove (void);
+void     PollControls (void);
+void     AddDemoCmd (void);
+void     AddRemoteCmd (void);
+void     PlayerSlideMove(objtype * ob);
+void     SpawnSmoke(objtype*);
+void     GetBonus(objtype*,statobj_t*);
+void     SpawnPlayerobj(int,int,int,int);
+void     ClipPlayer(void);
+void     PlayerMove ( objtype * ob );
+void     Cmd_Use(objtype*);
+void     Cmd_Fire (objtype*ob);
+void     SpawnGunSmoke(int x, int y, int z, int angle, int bullethole);
+void     SpawnBlood(objtype * ob, int angle);
+void     SpawnMetalSparks(objtype * ob, int angle);
+void     CheckPlayerSpecials(objtype * ob);
+void     LoadPlayer ( void );
+void     PlayerTiltHead (objtype * ob);
+boolean  InRange (objtype *p, objtype *victim, int distance);
+void     CheckUnPause ( void );
+void     UpdatePlayers ( void );
+void UnTargetActor ( objtype * target );
+
+
+enum
+{   RENORMALIZE = 1,
+    PITFALL,
+    PITRISE,
+    COLUMNCRUSH,
+    GODMODERISE,
+    GODMODEFALL,
+    DOGMODEFALL,
+    DOGMODERISE,
+    STEPUP,
+    STEPDOWN
+};
+
+extern void ResetWeapons(objtype *);
+extern void SaveWeapons(objtype*);
+
+extern int whichpath;
+extern statobj_t *BulletHoles[MAXBULLETS];
+
+extern boolean vrenabled;
+
+void SetupBulletHoleLink (int num, statobj_t * item);
+
+#endif
--- /dev/null
+++ b/rott/rt_rand.c
@@ -1,0 +1,147 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+#include "rt_def.h"
+#include "_rt_rand.h"
+#include "rt_rand.h"
+#include "develop.h"
+#include "rt_util.h"
+#include <time.h>
+
+#if (DEVELOPMENT == 1)
+#include "rt_main.h"
+#endif
+//MED
+#include "memcheck.h"
+
+//****************************************************************************
+//
+// GLOBALS
+//
+//****************************************************************************
+
+static int rndindex;
+static int sndindex = 0;
+
+
+//****************************************************************************
+//
+// GetRandomSeed ()
+//
+//****************************************************************************
+
+int GetRandomSeed ( void )
+{
+    return ( time (NULL) % (SIZE_OF_RANDOM_TABLE) );
+}
+
+//****************************************************************************
+//
+// InitializeRNG ()
+//
+//****************************************************************************
+
+void  InitializeRNG ( void )
+{
+    SetRNGindex(GetRandomSeed());
+    sndindex=GetRandomSeed();
+}
+
+//****************************************************************************
+//
+// SetRNGindex ()
+//
+//****************************************************************************
+
+void  SetRNGindex ( int i )
+{
+    rndindex=i;
+//#if (DEVELOPMENT == 1)
+    SoftError("RNG index set at %d\n",i);
+//#endif
+}
+
+//****************************************************************************
+//
+// GetRNGindex ()
+//
+//****************************************************************************
+
+int GetRNGindex ( void )
+{
+    return rndindex;
+}
+
+
+#if (RANDOMTEST==1)
+//****************************************************************************
+//
+// int GameRNG ( char * string, int val )
+//
+//****************************************************************************
+int   GameRNG ( char * string, int val )
+{
+    rndindex = (rndindex+1)&(SIZE_OF_RANDOM_TABLE-1);
+    SoftError("RNG - num=%3d called from=%s val=%d\n",RandomTable[rndindex],string,val);
+    return RandomTable[rndindex];
+}
+#else
+//****************************************************************************
+//
+// int GameRNG (void)
+//
+//****************************************************************************
+int   GameRNG ( void )
+{
+    rndindex = (rndindex+1)&(SIZE_OF_RANDOM_TABLE-1);
+
+    return RandomTable[rndindex];
+}
+#endif
+
+
+
+#if (RANDOMTEST==1)
+//****************************************************************************
+//
+// int RNG ( char * string, int val )
+//
+//****************************************************************************
+
+int   RNG ( char * string, int val )
+{
+    sndindex = (sndindex+1)&(SIZE_OF_RANDOM_TABLE-1);
+//   SoftError("SRNG - num=%3ld called from=%s val=%ld\n",RandomTable[sndindex],string,val);
+    return RandomTable[sndindex];
+}
+#else
+//****************************************************************************
+//
+// int RNG (void)
+//
+//****************************************************************************
+
+int   RNG( void )
+{
+    sndindex = (sndindex+1)&(SIZE_OF_RANDOM_TABLE-1);
+
+    return RandomTable[sndindex];
+}
+#endif
+
--- /dev/null
+++ b/rott/rt_rand.h
@@ -1,0 +1,51 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+#ifndef _rt_rand_public
+#define _rt_rand_public
+
+#include "develop.h"
+
+void  InitializeRNG ( void );
+int   GetRandomSeed ( void );
+
+
+#if RANDOMTEST
+
+int   GameRNG ( char * string, int val );
+#define GameRandomNumber(string,val)   GameRNG(string, val)
+
+int   RNG ( char * string, int val );
+#define RandomNumber(string,val)   RNG(string, val)
+
+#else
+
+int   GameRNG ( void );
+#define GameRandomNumber(string,val)   GameRNG()
+
+int   RNG ( void );
+#define RandomNumber(string,val)   RNG()
+
+#endif
+
+
+
+void  SetRNGindex ( int i );
+int   GetRNGindex ( void );
+#endif
--- /dev/null
+++ b/rott/rt_sc_a.h
@@ -1,0 +1,41 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+//***************************************************************************
+//
+//    RT_SC_A.ASM - Low level DrawColumn for masked post
+//
+//***************************************************************************
+
+#ifndef _rt_sc_a_public
+#define _rt_sc_a_public
+
+void R_DrawColumn (byte * buf);
+void R_DrawSolidColumn (int color, byte * buf);
+void R_TransColumn (byte * buf);
+void R_DrawClippedColumn (byte * buf);
+
+#if defined(__WATCOMC__)
+#pragma aux R_DrawColumn parm [EDI] modify exact [eax ebx ecx edx esi edi]
+#pragma aux R_DrawSolidColumn parm [EBX] [EDI]  modify exact [eax ecx edi]
+#pragma aux R_TransColumn parm [EDI] modify exact [eax ebx esi edi]
+#pragma aux R_DrawClippedColumn parm [EDI] modify exact [eax ebx ecx edx esi edi]
+#endif
+
+#endif
--- /dev/null
+++ b/rott/rt_scale.c
@@ -1,0 +1,1463 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+#include "rt_def.h"
+#include "watcom.h"
+#include <stdio.h>
+#include <string.h>
+
+#ifdef DOS
+#include <malloc.h>
+#include <dos.h>
+#include <conio.h>
+#endif
+
+#include "modexlib.h"
+#include "rt_util.h"
+#include "rt_draw.h"
+#include "rt_scale.h"
+#include "_rt_scal.h"
+#include "rt_sc_a.h"
+#include "engine.h"
+#include "w_wad.h"
+#include "z_zone.h"
+#include "lumpy.h"
+#include "rt_main.h"
+#include "rt_ted.h"
+#include "rt_vid.h"
+#include "rt_view.h"
+#include "rt_playr.h"
+//MED
+#include "memcheck.h"
+
+/*
+=============================================================================
+
+                               GLOBALS
+
+=============================================================================
+*/
+
+// Draw Column vars
+
+int dc_texturemid;
+int dc_iscale;
+int dc_invscale;
+int sprtopoffset;
+int dc_yl;
+int dc_yh;
+//byte * dc_firstsource;
+byte * dc_source;
+int centeryclipped;
+int transparentlevel=0;
+
+/*
+==========================
+=
+= SetPlayerLightLevel
+=
+==========================
+*/
+
+void SetPlayerLightLevel (void)
+{
+    int i;
+    int lv;
+    int intercept;
+    int height;
+
+    whereami=23;
+    if (MISCVARS->GASON==1)
+    {
+        shadingtable=greenmap+(MISCVARS->gasindex<<8);
+        return;
+    }
+
+    if (fulllight || fog)
+    {
+        shadingtable=colormap+(1<<12);
+        return;
+    }
+
+    height=PLAYERHEIGHT;
+
+    if (player->angle < FINEANGLES/8 || player->angle > 7*FINEANGLES/8)
+        intercept=(player->x>>11)&0x1c;
+    else if (player->angle < 3*FINEANGLES/8)
+        intercept=(player->y>>11)&0x1c;
+    else if (player->angle < 5*FINEANGLES/8)
+        intercept=(player->x>>11)&0x1c;
+    else
+        intercept=(player->y>>11)&0x1c;
+
+    if (lightsource)
+    {
+        lv=(((LightSourceAt(player->x>>16,player->y>>16)>>intercept)&0xf)>>1);
+        i=maxshade-(height>>normalshade)-lv;
+        if (i<minshade) i=minshade;
+        shadingtable=colormap+(i<<8);
+    }
+    else
+    {
+        i=maxshade-(height>>normalshade);
+        if (i<minshade) i=minshade;
+        shadingtable=colormap+(i<<8);
+    }
+}
+
+
+
+/*
+==========================
+=
+= SetLightLevel
+=
+==========================
+*/
+
+void SetLightLevel (int height)
+{
+    int i;
+
+    whereami=24;
+    if (MISCVARS->GASON==1)
+    {
+        shadingtable=greenmap+(MISCVARS->gasindex<<8);
+        return;
+    }
+
+    if (fulllight)
+    {
+        shadingtable=colormap+(1<<12);
+        return;
+    }
+    if (fog)
+    {
+        i=((height*200/iGLOBAL_SCREENHEIGHT)>>normalshade)+minshade;
+        if (i>maxshade) i=maxshade;
+        shadingtable=colormap+(i<<8);
+    }
+    else
+    {
+        i=maxshade-(height>>normalshade);
+        if (i<minshade) i=minshade;
+        shadingtable=colormap+(i<<8);
+    }
+}
+
+/*
+==========================
+=
+= ScaleTransparentPost
+=
+==========================
+*/
+void ScaleTransparentPost (byte * src, byte * buf, int level)
+{
+    int  offset;
+    int  length;
+    int  topscreen;
+    int  bottomscreen;
+    byte * oldlevel;
+    byte * seelevel;
+#if (DEVELOPMENT == 1)
+    boolean found=false;
+    int  i;
+#endif
+
+    whereami=25;
+#if (DEVELOPMENT == 1)
+    if ((shadingtable>=colormap) && (shadingtable<=(colormap+(31*256))))
+    {
+        found=true;
+    }
+    else if ((shadingtable>=redmap) && (shadingtable<=(redmap+(31*256))))
+    {
+        found=true;
+    }
+    else
+    {
+        for (i=0; i<MAXPLAYERCOLORS; i++)
+        {
+            if ((shadingtable>=playermaps[i]) || (shadingtable<=(playermaps[i]+(31*256))))
+                found=true;
+        }
+    }
+    if (found==false)
+    {
+        Error ("Shadingtable out of range\n");
+    }
+    if ((level<0) || (level>=64))
+    {
+        Error ("translucent level out of range\n");
+    }
+#endif
+
+    seelevel=colormap+(((level+64)>>2)<<8);
+    oldlevel=shadingtable;
+    offset=*(src++);
+    for (; offset!=255;)
+    {
+        length=*(src++);
+        topscreen = sprtopoffset + (dc_invscale*offset);
+        bottomscreen = topscreen + (dc_invscale*length);
+        dc_yl = (topscreen+SFRACUNIT)>>SFRACBITS;
+        dc_yh = ((bottomscreen-1)>>SFRACBITS);
+        if (dc_yh >= viewheight)
+            dc_yh = viewheight-1;
+        if (dc_yl < 0)
+            dc_yl = 0;
+        if ((*src)==254)
+        {
+            shadingtable=seelevel;
+            if (dc_yl <= dc_yh)
+                R_TransColumn (buf);
+            src++;
+            offset=*(src++);
+            shadingtable=oldlevel;
+        }
+        else
+        {
+            if (dc_yl <= dc_yh)
+            {
+                dc_source=src-offset;
+                R_DrawColumn (buf);
+            }
+            src+=length;
+            offset=*(src++);
+        }
+    }
+
+    whereami=-2;
+}
+
+
+void ScaleMaskedPost (byte * src, byte * buf)
+{
+    int  offset;
+    int  length;
+    int  topscreen;
+    int  bottomscreen;
+
+    whereami=26;
+    offset=*(src++);
+    for (; offset!=255;)
+    {
+        length=*(src++);
+        topscreen = sprtopoffset + (dc_invscale*offset);
+        bottomscreen = topscreen + (dc_invscale*length);
+        dc_yl = (topscreen+SFRACUNIT)>>SFRACBITS;
+        dc_yh = ((bottomscreen-1)>>SFRACBITS);
+        if (dc_yh >= viewheight)
+            dc_yh = viewheight-1;
+        if (dc_yl < 0)
+            dc_yl = 0;
+        if (dc_yl <= dc_yh)
+        {
+            dc_source=src-offset;
+            R_DrawColumn (buf);
+#if (DEVELOPMENT == 1)
+//         if (dc_firstsource<src)
+//            SoftError("dc_firstsource=%p src=%p\n",dc_firstsource,src);
+#endif
+        }
+        src+=length;
+        offset=*(src++);
+    }
+}
+
+void ScaleClippedPost (byte * src, byte * buf)
+{
+    int  offset;
+    int  length;
+    int  topscreen;
+    int  bottomscreen;
+
+    whereami=27;
+    offset=*(src++);
+    for (; offset!=255;)
+    {
+        length=*(src++);
+        topscreen = sprtopoffset + (dc_invscale*offset);
+        bottomscreen = topscreen + (dc_invscale*length);
+        dc_yl = (topscreen+SFRACUNIT-1)>>SFRACBITS;
+        dc_yh = ((bottomscreen-1)>>SFRACBITS);
+        if (dc_yh >= viewheight)
+            dc_yh = viewheight-1;
+        if (dc_yl < 0)
+            dc_yl = 0;
+        if (dc_yl <= dc_yh)
+        {
+            dc_source=src-offset;
+            R_DrawClippedColumn (buf);
+        }
+        src+=length;
+        offset=*(src++);
+    }
+}
+
+void ScaleSolidMaskedPost (int color, byte * src, byte * buf)
+{
+    int  offset;
+    int  length;
+    int  topscreen;
+    int  bottomscreen;
+
+    whereami=28;
+    offset=*(src++);
+    for (; offset!=255;)
+    {
+        length=*(src++);
+        topscreen = sprtopoffset + (dc_invscale*offset);
+        bottomscreen = topscreen + (dc_invscale*length);
+        dc_yl = (topscreen+SFRACUNIT)>>SFRACBITS;
+        dc_yh = ((bottomscreen-1)>>SFRACBITS);
+        if (dc_yh >= viewheight)
+            dc_yh = viewheight-1;
+        if (dc_yl < 0)
+            dc_yl = 0;
+        if (dc_yl <= dc_yh)
+        {
+            dc_source=src-offset;
+            R_DrawSolidColumn (color, buf);
+        }
+        src+=length;
+        offset=*(src++);
+    }
+
+}
+
+
+void ScaleTransparentClippedPost (byte * src, byte * buf, int level)
+{
+    int  offset;
+    int  length;
+    int  topscreen;
+    int  bottomscreen;
+    byte * oldlevel;
+    byte * seelevel;
+
+    whereami=29;
+
+    seelevel=colormap+(((level+64)>>2)<<8);
+    oldlevel=shadingtable;
+    offset=*(src++);
+    for (; offset!=255;)
+    {
+        length=*(src++);
+        topscreen = sprtopoffset + (dc_invscale*offset);
+        bottomscreen = topscreen + (dc_invscale*length);
+        dc_yl = (topscreen+SFRACUNIT)>>SFRACBITS;
+        dc_yh = ((bottomscreen-1)>>SFRACBITS);
+        if (dc_yh >= viewheight)
+            dc_yh = viewheight-1;
+        if (dc_yl < 0)
+            dc_yl = 0;
+        if ((*src)==254)
+        {
+            shadingtable=seelevel;
+            if (dc_yl <= dc_yh)
+                R_TransColumn (buf);
+            src++;
+            offset=*(src++);
+            shadingtable=oldlevel;
+        }
+        else
+        {
+            if (dc_yl <= dc_yh)
+            {
+                dc_source=src-offset;
+                R_DrawClippedColumn (buf);
+            }
+            src+=length;
+            offset=*(src++);
+        }
+    }
+
+}
+
+
+void ScaleMaskedWidePost (byte * src, byte * buf, int x, int width)
+{
+#ifdef DOS
+    int  ofs;
+    int  msk;
+
+    whereami=30;
+    buf+=x>>2;
+    ofs=((x&3)<<3)+(x&3)+width-1;
+    VGAMAPMASK(*((byte *)mapmasks1+ofs));
+    ScaleMaskedPost(src,buf);
+    msk=(byte)*((byte *)mapmasks2+ofs);
+    if (msk==0)
+        return;
+    buf++;
+    VGAMAPMASK(msk);
+    ScaleMaskedPost(src,buf);
+    msk=(byte)*((byte *)mapmasks3+ofs);
+    if (msk==0)
+        return;
+    buf++;
+    VGAMAPMASK(msk);
+    ScaleMaskedPost(src,buf);
+#else
+    buf += x;
+
+    while (width--) {
+        ScaleMaskedPost(src,buf);
+        buf++;
+    }
+#endif
+}
+
+void ScaleClippedWidePost (byte * src, byte * buf, int x, int width)
+{
+#ifdef DOS
+    int  ofs;
+    int  msk;
+
+    whereami=31;
+    buf+=x>>2;
+    ofs=((x&3)<<3)+(x&3)+width-1;
+    VGAMAPMASK(*((byte *)mapmasks1+ofs));
+    ScaleClippedPost(src,buf);
+    msk=(byte)*((byte *)mapmasks2+ofs);
+    if (msk==0)
+        return;
+    buf++;
+    VGAMAPMASK(msk);
+    ScaleClippedPost(src,buf);
+    msk=(byte)*((byte *)mapmasks3+ofs);
+    if (msk==0)
+        return;
+    buf++;
+    VGAMAPMASK(msk);
+    ScaleClippedPost(src,buf);
+#else
+    buf += x;
+
+    while (width--) {
+        ScaleClippedPost(src,buf);
+        buf++;
+    }
+#endif
+}
+
+
+/*
+=======================
+=
+= ScaleShape
+=
+=======================
+*/
+
+void ScaleShape (visobj_t * sprite)
+{
+    byte *shape;
+    int      frac;
+    patch_t *p;
+    int      x1,x2;
+    int      tx;
+    int      size;
+    int      plane;
+
+    whereami=32;
+    shape=W_CacheLumpNum(sprite->shapenum,PU_CACHE, Cvt_patch_t, 1);
+    p=(patch_t *)shape;
+    size=p->origsize>>7;
+//   sprite->viewheight<<=1;
+    dc_invscale=sprite->viewheight<<((10-HEIGHTFRACTION)-size);
+    tx=-p->leftoffset;
+    sprite->viewx=(sprite->viewx<<SFRACBITS)-(sprite->viewheight<<(SFRACBITS-HEIGHTFRACTION-1))+(SFRACUNIT>>1);
+//
+// calculate edges of the shape
+//
+    x1 = (sprite->viewx+(tx*dc_invscale))>>SFRACBITS;
+    if (x1 >= viewwidth)
+    {
+        return;               // off the right side
+    }
+    tx+=p->width;
+    x2 = ((sprite->viewx+(tx*dc_invscale)) >>SFRACBITS) - 1 ;
+    if (x2 < 0)
+    {
+        return;         // off the left side
+    }
+
+// dc_iscale=(1<<(16+6+HEIGHTFRACTION+size))/sprite->viewheight;
+    dc_iscale=0xffffffffu/(unsigned)dc_invscale;
+    dc_texturemid=(((sprite->h1<<size) + p->topoffset)<<SFRACBITS);//+(SFRACUNIT>>1);
+    sprtopoffset=centeryfrac -  FixedMul(dc_texturemid,dc_invscale);
+    shadingtable=sprite->colormap;
+
+    if (x1<0)
+    {
+        frac=dc_iscale*(-x1);
+        x1=0;
+    }
+    else
+        frac=0;
+    x2 = x2 >= viewwidth ? viewwidth-1 : x2;
+
+    if (sprite->viewheight>((1<<(HEIGHTFRACTION+6))<<size))
+    {
+        int      texturecolumn;
+        int      lastcolumn;
+        int      startx;
+        int      width;
+
+        width=1;
+        startx=0;
+        lastcolumn=-1;
+        for (; x1<=x2 ; x1++, frac += dc_iscale)
+        {
+            if (posts[x1].wallheight>sprite->viewheight)
+            {
+                if (lastcolumn>=0)
+                {
+                    ScaleMaskedWidePost(((p->collumnofs[lastcolumn])+shape),(byte *)bufferofs,startx,width);
+                    width=1;
+                    lastcolumn=-1;
+                }
+                continue;
+            }
+            texturecolumn = frac>>SFRACBITS;
+            if ((texturecolumn==lastcolumn)&&(width<9))
+            {
+                width++;
+                continue;
+            }
+            else
+            {
+                if (lastcolumn>=0)
+                {
+                    ScaleMaskedWidePost(((p->collumnofs[lastcolumn])+shape),(byte *)bufferofs,startx,width);
+                    width=1;
+                    startx=x1;
+                    lastcolumn=texturecolumn;
+                }
+                else
+                {
+                    startx=x1;
+                    lastcolumn=texturecolumn;
+                }
+            }
+        }
+        if (lastcolumn!=-1)
+            ScaleMaskedWidePost(((p->collumnofs[lastcolumn])+shape),(byte *)bufferofs,startx,width);
+    }
+    else
+    {
+        byte * b;
+        int    startfrac;
+        int    startx;
+
+        startx=x1;
+        startfrac=frac;
+        if (doublestep>1)
+        {
+#ifdef DOS
+            for (plane=startx; plane<startx+4; plane+=2,startfrac+=(dc_iscale<<1))
+#endif
+            {
+                frac=startfrac;
+//   VGAWRITEMAP(plane&3);
+#ifdef DOS
+                for (x1=plane; x1<=x2; x1+=4, frac += (dc_iscale<<2))
+#else
+                for (x1=startx; x1<=x2; x1+=2, frac += (dc_iscale<<1))
+#endif
+                {
+                    if (
+                        (posts[x1].wallheight>sprite->viewheight) &&
+                        (posts[x1+1].wallheight>sprite->viewheight)
+                    )
+                        continue;
+                    if (x1==viewwidth-1)
+                        ScaleMaskedWidePost(((p->collumnofs[frac>>SFRACBITS])+shape),(byte *)bufferofs,x1,1);
+                    else
+                        ScaleMaskedWidePost(((p->collumnofs[frac>>SFRACBITS])+shape),(byte *)bufferofs,x1,2);
+                }
+            }
+        }
+        else
+        {
+#ifdef DOS
+            for (plane=startx; plane<startx+4; plane++,startfrac+=dc_iscale)
+#endif
+            {
+                frac=startfrac;
+
+#ifdef DOS
+                b=(byte *)bufferofs+(plane>>2);
+                VGAWRITEMAP(plane&3);
+#else
+                b=(byte *)bufferofs+startx;
+#endif
+
+#ifdef DOS
+                for (x1=plane; x1<=x2; x1+=4, frac += (dc_iscale<<2),b++)
+#else
+                for (x1=startx; x1<=x2; x1++, frac += dc_iscale,b++)
+#endif
+                {
+                    if (posts[x1].wallheight>sprite->viewheight)
+                        continue;
+                    ScaleMaskedPost(((p->collumnofs[frac>>SFRACBITS])+shape),b);
+                }
+            }
+        }
+    }
+}
+
+
+/*
+=======================
+=
+= ScaleTranparentShape
+=
+=======================
+*/
+
+void ScaleTransparentShape (visobj_t * sprite)
+{
+    byte *shape;
+    int      frac;
+    transpatch_t *p;
+    int      x1,x2;
+    int      tx;
+    int      size;
+    byte * b;
+    int    startfrac;
+    int    startx;
+    int    plane;
+
+    whereami=33;
+    shape=W_CacheLumpNum(sprite->shapenum,PU_CACHE, Cvt_transpatch_t, 1);
+    p=(transpatch_t *)shape;
+    size=p->origsize>>7;
+    dc_invscale=sprite->viewheight<<((10-HEIGHTFRACTION)-size);
+    tx=-p->leftoffset;
+    sprite->viewx=(sprite->viewx<<SFRACBITS)-(sprite->viewheight<<(SFRACBITS-HEIGHTFRACTION-1));
+//
+// calculate edges of the shape
+//
+    x1 = (sprite->viewx+(tx*dc_invscale))>>SFRACBITS;
+    if (x1 >= viewwidth)
+    {
+        return;               // off the right side
+    }
+    tx+=p->width;
+    x2 = ((sprite->viewx+(tx*dc_invscale)) >>SFRACBITS) - 1 ;
+    if (x2 < 0)
+    {
+        return;         // off the left side
+    }
+
+//   dc_iscale=(1<<(16+6+HEIGHTFRACTION+size))/sprite->viewheight;
+    dc_iscale=0xffffffffu/(unsigned)dc_invscale;
+    dc_texturemid=(((sprite->h1<<size)+p->topoffset)<<SFRACBITS);//+(SFRACUNIT>>1);
+    sprtopoffset=centeryfrac - FixedMul(dc_texturemid,dc_invscale);
+    shadingtable=sprite->colormap;
+
+    if (x1<0)
+    {
+        frac=dc_iscale*(-x1);
+        x1=0;
+    }
+    else
+        frac=0;
+    x2 = x2 >= viewwidth ? viewwidth-1 : x2;
+
+#if 0
+    for (; x1<=x2 ; x1++, frac += dc_iscale)
+    {
+        if (posts[x1].wallheight>sprite->viewheight)
+            continue;
+        VGAWRITEMAP(x1&3);
+        VGAREADMAP(x1&3);
+        ScaleTransparentPost(((p->collumnofs[frac>>SFRACBITS])+shape),(byte *)bufferofs+(x1>>2),sprite->h2);
+    }
+#endif
+    startx=x1;
+    startfrac=frac;
+
+#ifdef DOS
+    for (plane=startx; plane<startx+4; plane++,startfrac+=dc_iscale)
+#endif
+
+    {
+        frac=startfrac;
+
+#ifdef DOS
+        b=(byte *)bufferofs+(plane>>2);
+        VGAWRITEMAP(plane&3);
+        VGAREADMAP(plane&3);
+#else
+        b=(byte *)bufferofs+startx;
+#endif
+
+#ifdef DOS
+        for (x1=plane; x1<=x2; x1+=4, frac += (dc_iscale<<2),b++)
+#else
+        for (x1=startx; x1<=x2; x1++, frac += dc_iscale,b++)
+#endif
+        {
+            if (posts[x1].wallheight>sprite->viewheight)
+                continue;
+            ScaleTransparentPost(((p->collumnofs[frac>>SFRACBITS])+shape),b,sprite->h2);
+        }
+    }
+}
+
+/*
+=======================
+=
+= ScaleSolidShape
+=
+=======================
+*/
+
+void ScaleSolidShape (visobj_t * sprite)
+{
+    byte *shape;
+    int      frac;
+    patch_t *p;
+    int      x1,x2;
+    int      tx;
+    int      size;
+    int      plane;
+    byte * b;
+    int    startfrac;
+    int    startx;
+
+    whereami=34;
+    shape=W_CacheLumpNum(sprite->shapenum,PU_CACHE, Cvt_patch_t, 1);
+    p=(patch_t *)shape;
+    size=p->origsize>>7;
+    dc_invscale=sprite->viewheight<<((10-HEIGHTFRACTION)-size);
+    tx=-p->leftoffset;
+    sprite->viewx=(sprite->viewx<<SFRACBITS)-(sprite->viewheight<<(SFRACBITS-HEIGHTFRACTION-1))+(SFRACUNIT>>1);
+//
+// calculate edges of the shape
+//
+    x1 = (sprite->viewx+(tx*dc_invscale))>>SFRACBITS;
+    if (x1 >= viewwidth)
+    {
+        return;               // off the right side
+    }
+    tx+=p->width;
+    x2 = ((sprite->viewx+(tx*dc_invscale)) >>SFRACBITS) - 1 ;
+    if (x2 < 0)
+    {
+        return;         // off the left side
+    }
+
+//   dc_iscale=(1<<(16+6+HEIGHTFRACTION+size))/sprite->viewheight;
+    dc_iscale=0xffffffffu/(unsigned)dc_invscale;
+    dc_texturemid=(((sprite->h1<<size)+p->topoffset)<<SFRACBITS);//+(SFRACUNIT>>1);
+    sprtopoffset=centeryfrac - FixedMul(dc_texturemid,dc_invscale);
+    shadingtable=sprite->colormap;
+
+    if (x1<0)
+    {
+        frac=dc_iscale*(-x1);
+        x1=0;
+    }
+    else
+        frac=0;
+    x2 = x2 >= viewwidth ? viewwidth-1 : x2;
+
+    startx=x1;
+    startfrac=frac;
+
+#ifdef DOS
+    for (plane=startx; plane<startx+4; plane++,startfrac+=dc_iscale)
+#endif
+
+    {
+        frac=startfrac;
+
+#ifdef DOS
+        b=(byte *)bufferofs+(plane>>2);
+        VGAWRITEMAP(plane&3);
+#else
+        b=(byte *)bufferofs+startx;
+#endif
+
+#ifdef DOS
+        for (x1=plane; x1<=x2; x1+=4, frac += (dc_iscale<<2),b++)
+#else
+        for (x1=startx; x1<=x2; x1++, frac += dc_iscale,b++)
+#endif
+        {
+            if (posts[x1].wallheight>sprite->viewheight)
+                continue;
+            ScaleSolidMaskedPost(sprite->h2,((p->collumnofs[frac>>SFRACBITS])+shape),b);
+        }
+    }
+}
+
+
+/*
+=======================
+=
+= ScaleWeapon
+=
+=======================
+*/
+
+void ScaleWeapon (int xoff, int y, int shapenum)
+{
+    byte *shape;
+    int      frac;
+    int      h;
+    patch_t *p;
+    int      x1,x2;
+    int      tx;
+    int      xcent;
+    byte * b;
+    int    startfrac;
+    int    startx;
+    int    plane;
+
+    whereami=35;
+    SetPlayerLightLevel();
+    shape=W_CacheLumpNum(shapenum,PU_CACHE, Cvt_patch_t, 1);
+    p=(patch_t *)shape;
+    h=((p->origsize*weaponscale)>>17);
+    centeryclipped=(viewheight-h)+FixedMul(y,weaponscale);
+    xcent=centerx+FixedMul(xoff,weaponscale);
+    dc_invscale=(h<<17)/p->origsize;
+
+    tx=-p->leftoffset;
+    xcent=(xcent<<SFRACBITS)-(h<<SFRACBITS);
+//
+// calculate edges of the shape
+//
+    x1 = (xcent+(tx*dc_invscale))>>SFRACBITS;
+    if (x1 >= viewwidth)
+        return;               // off the right side
+    tx+=p->width;
+    x2 = ((xcent+(tx*dc_invscale)) >>SFRACBITS) - 1 ;
+    if (x2 < 0)
+        return;         // off the left side
+
+    dc_iscale=0xffffffffu/(unsigned)dc_invscale;
+    dc_texturemid=(((p->origsize>>1)+p->topoffset)<<SFRACBITS)+(SFRACUNIT>>2);
+    sprtopoffset=(centeryclipped<<16) - FixedMul(dc_texturemid,dc_invscale);
+
+//
+// store information in a vissprite
+//
+    if (x1<0)
+    {
+        frac=dc_iscale*(-x1);
+        x1=0;
+    }
+    else
+        frac=0;
+
+    x2 = x2 >= viewwidth ? viewwidth-1 : x2;
+
+    startx=x1;
+    startfrac=frac;
+
+#ifdef DOS
+    for (plane=startx; plane<startx+4; plane++,startfrac+=dc_iscale)
+#endif
+    {
+        frac=startfrac;
+#ifdef DOS
+        b=(byte *)bufferofs+(plane>>2);
+#else
+        b=(byte *)bufferofs+startx;
+#endif
+        VGAWRITEMAP(plane&3);
+#ifdef DOS
+        for (x1=plane; x1<=x2 ; x1+=4, frac += dc_iscale<<2,b++)
+#else
+        for (x1=startx; x1<=x2 ; x1++, frac += dc_iscale,b++)
+#endif
+            ScaleClippedPost(((p->collumnofs[frac>>SFRACBITS])+shape),b);
+    }
+}
+
+
+
+
+/*
+=======================
+=
+= DrawUnScaledSprite
+=
+=======================
+*/
+
+void DrawUnScaledSprite (int x, int y, int shapenum, int shade)
+{
+    byte *shape;
+    int      frac;
+    patch_t *p;
+    int      x1,x2;
+    int      tx;
+    int      xcent;
+    byte * b;
+    int    startfrac;
+    int    startx;
+    int    plane;
+
+    whereami=36;
+    shadingtable=colormap+(shade<<8);
+    centeryclipped=y;
+    xcent=x;
+    shape=W_CacheLumpNum(shapenum,PU_CACHE, Cvt_patch_t, 1);
+    p=(patch_t *)shape;
+    dc_invscale=0x10000;
+
+    tx=-p->leftoffset;
+    xcent-=p->origsize>>1;
+//
+// calculate edges of the shape
+//
+    x1 = xcent+tx;
+    if (x1 >= viewwidth)
+        return;               // off the right side
+    tx+=p->width;
+    x2 = xcent+tx - 1;
+    if (x2 < 0)
+        return;         // off the left side
+
+    dc_iscale=0x10000;
+    dc_texturemid=(((p->height>>1)+p->topoffset)<<SFRACBITS);//+(SFRACUNIT>>1);
+    sprtopoffset=(centeryclipped<<16) - dc_texturemid;
+
+//
+// store information in a vissprite
+//
+    if (x1<0)
+    {
+        frac=dc_iscale*(-x1);
+        x1=0;
+    }
+    else
+        frac = 0;
+
+    x2 = x2 >= viewwidth ? viewwidth-1 : x2;
+
+    startx=x1;
+    startfrac=frac;
+
+#ifdef DOS
+    for (plane=startx; plane<startx+4; plane++,startfrac+=dc_iscale)
+#endif
+
+    {
+        frac=startfrac;
+
+#ifdef DOS
+        b=(byte *)bufferofs+(plane>>2);
+        VGAWRITEMAP(plane&3);
+#else
+        b=(byte *)bufferofs+startx;
+#endif
+
+#ifdef DOS
+        for (x1=plane; x1<=x2 ; x1+=4, frac += dc_iscale<<2,b++)
+#else
+        for (x1=startx; x1<=x2 ; x1++, frac += dc_iscale,b++)
+#endif
+            ScaleClippedPost(((p->collumnofs[frac>>SFRACBITS])+shape),b);
+    }
+}
+
+
+/*
+=======================
+=
+= DrawScreenSprite
+=
+=======================
+*/
+
+void DrawScreenSprite (int x, int y, int shapenum)
+{
+    whereami=37;
+    ScaleWeapon (x-160, y-200, shapenum);
+}
+
+/*
+=======================
+=
+= DrawPositionedScaledSprite
+=
+=======================
+*/
+
+void DrawPositionedScaledSprite (int x, int y, int shapenum, int height, int type)
+{
+    byte *shape;
+    int      frac;
+    patch_t *p;
+    transpatch_t *tp;
+    int      x1,x2;
+    int      tx;
+    int      xcent;
+    byte * b;
+    int    startfrac;
+    int    startx;
+    int    plane;
+    int    size;
+
+    whereami=38;
+    shadingtable=colormap+(1<<12);
+    centeryclipped=y;
+    xcent=x;
+    shape=W_CacheLumpNum(shapenum,PU_CACHE, Cvt_patch_t, 1); // was transpatch, fixed
+    p=(patch_t *)shape;
+    tp=(transpatch_t *)shape;
+
+    size=p->origsize>>7;
+    dc_invscale=height<<(10-size);
+
+    tx=-p->leftoffset;
+    xcent=(xcent<<SFRACBITS)-(height<<(SFRACBITS-1));
+
+//
+// calculate edges of the shape
+//
+    x1 = (xcent+(tx*dc_invscale))>>SFRACBITS;
+    if (x1 >= viewwidth)
+        return;               // off the right side
+    tx+=p->width;
+    x2 = ((xcent+(tx*dc_invscale)) >>SFRACBITS) - 1 ;
+    if (x2 < 0)
+        return;         // off the left side
+
+    dc_iscale=0xffffffffu/(unsigned)dc_invscale;
+//   dc_iscale=(1<<(16+6+size))/height;
+    dc_texturemid=(((32<<size)+p->topoffset)<<SFRACBITS)+(SFRACUNIT>>1);
+    sprtopoffset=(centeryclipped<<16) - FixedMul(dc_texturemid,dc_invscale);
+
+//
+// store information in a vissprite
+//
+    if (x1<0)
+    {
+        frac=dc_iscale*(-x1);
+        x1=0;
+    }
+    else
+        frac=0;
+
+    x2 = x2 >= viewwidth ? viewwidth-1 : x2;
+
+    startx=x1;
+    startfrac=frac;
+
+#ifdef DOS
+    for (plane=startx; plane<startx+4; plane++,startfrac+=dc_iscale)
+#endif
+
+    {
+        frac=startfrac;
+
+#ifdef DOS
+        b=(byte *)bufferofs+(plane>>2);
+        VGAWRITEMAP(plane&3);
+        VGAREADMAP(plane&3);
+#else
+        b=(byte *)bufferofs+startx;
+#endif
+
+#ifdef DOS
+        for (x1=plane; x1<=x2 ; x1+=4, frac += dc_iscale<<2,b++)
+#else
+        for (x1=startx; x1<=x2 ; x1++, frac += dc_iscale,b++)
+#endif
+            if (type==0)
+                ScaleClippedPost(((p->collumnofs[frac>>SFRACBITS])+shape),b);
+            else
+                ScaleTransparentClippedPost(((tp->collumnofs[frac>>SFRACBITS])+shape),b,transparentlevel);
+    }
+}
+
+
+/*
+=================
+=
+= DrawScreenSizedSprite
+=
+=================
+*/
+extern int G_gmasklump;
+void DrawScreenSizedSprite (int lump)
+{
+    //draws gasmask among other things zxcv
+    byte *shape,*src;
+    int      frac;
+    patch_t *p;
+    int      x1,x2;
+    int      tx;
+//   int      plane;
+    byte * b;
+    int    startfrac;
+
+    int  offset;
+    int  length;
+    int  topscreen;
+    int  bottomscreen;
+    byte  *cnt,*Ycnt;
+
+    // SetTextMode (  );
+    whereami=39;
+    shadingtable=colormap+(1<<12);
+    shape=W_CacheLumpNum(lump,PU_CACHE, Cvt_patch_t, 1);
+    p=(patch_t *)shape;
+    dc_invscale=(viewwidth<<16)/p->origsize;
+    tx=-p->leftoffset;
+    centeryclipped=viewheight>>1;
+    //centeryclipped=(viewheight>>1)+43;
+//
+// calculate edges of the shape
+//
+    x1 = (tx*dc_invscale)>>SFRACBITS;
+    if (x1 >= viewwidth)
+    {
+        return;               // off the right side
+    }
+    tx+=p->width;
+    x2 = ((tx*dc_invscale) >>SFRACBITS) - 1 ;
+    if (x2 < 0)
+    {
+        return;         // off the left side
+    }
+
+    dc_iscale=0xffffffffu/(unsigned)dc_invscale;
+    dc_texturemid=(((p->origsize>>1) + p->topoffset)<<SFRACBITS)+(SFRACUNIT>>1);
+    sprtopoffset=(centeryclipped<<16) -  FixedMul(dc_texturemid,dc_invscale);
+
+    x2 = (viewwidth-1);
+
+    startfrac=0;
+
+    {
+        frac=startfrac;
+        b=(byte *)bufferofs;
+
+        /////////////  BNA PATCH //////////////////////////////////////////////////////////
+        //gmasklump=W_GetNumForName("p_gmask"); //=783
+        //perhaps I should have painted the mask in a seperate buffer
+        //and streched it and copyet it back, but that would demand
+        //a new buffer (size=800x600) and slowed the game down so ?
+
+        // if its the gasmask, paint black patches at hires
+        if ((lump == G_gmasklump)&&(iGLOBAL_SCREENWIDTH>320)) {
+            src = ((p->collumnofs[frac>>SFRACBITS])+shape);
+            offset=*(src++);
+            length=*(src++);
+            topscreen = sprtopoffset + (dc_invscale*offset);
+            bottomscreen = topscreen + (dc_invscale*length);
+            dc_yl = (topscreen+SFRACUNIT-1)>>SFRACBITS;//=41  viewheight=584
+            dc_yh = ((bottomscreen-1)>>SFRACBITS);//=540      viewwidth =800
+            //paint upper black patch in gasmask
+            for (cnt=b; cnt<b+viewwidth; cnt++) {
+                for (Ycnt=cnt; Ycnt<cnt+(dc_yl*iGLOBAL_SCREENWIDTH); Ycnt+=iGLOBAL_SCREENWIDTH) {
+                    *Ycnt = 36;
+                }
+            }
+            //paint lower black patch in gasmask
+            for (cnt=b+(dc_yh*iGLOBAL_SCREENWIDTH); cnt<b+(dc_yh*iGLOBAL_SCREENWIDTH)+viewwidth; cnt++) {
+                for (Ycnt=cnt; Ycnt<b+(viewheight*iGLOBAL_SCREENWIDTH); Ycnt+=iGLOBAL_SCREENWIDTH) {
+                    *Ycnt = 36;
+                }
+            }
+        }
+        ///////////////////////////////////////////////////////////////////////////////////
+        for (x1=0; x1<=x2; x1++, frac += dc_iscale,b++)
+
+        {
+            ScaleClippedPost(((p->collumnofs[frac>>SFRACBITS])+shape),b);
+        }
+    }
+}
+
+#if 0
+byte *shape;
+int      frac;
+patch_t *p;
+int      x1,x2;
+int      tx;
+int      xdc_invscale;
+int      xdc_iscale;
+byte *   buf;
+byte *   b;
+int      plane;
+int      startx,startfrac;
+
+whereami=39;
+SetPlayerLightLevel();
+buf=(byte *)bufferofs;
+shape=W_CacheLumpNum(lump,PU_CACHE);
+p=(patch_t *)shape;
+dc_invscale=(viewheight<<16)/200;
+xdc_invscale=(viewwidth<<16)/320;
+
+tx=-p->leftoffset;
+centeryclipped=viewheight>>1;
+//
+// calculate edges of the shape
+//
+x1 = (tx*xdc_invscale)>>SFRACBITS;
+if (x1 >= viewwidth)
+    return;               // off the right side
+tx+=p->width;
+x2 = ((tx*xdc_invscale)>>SFRACBITS) - 1 ;
+if (x2 < 0)
+    return;         // off the left side
+
+dc_iscale=(200*65536)/viewheight;
+xdc_iscale=(320*65536)/viewwidth;
+dc_texturemid=(((p->height>>1)+p->topoffset)<<SFRACBITS)+(SFRACUNIT>>1);
+sprtopoffset=(centeryclipped<<16) - FixedMul(dc_texturemid,dc_invscale);
+
+//
+// store information in a vissprite
+//
+if (x1<0)
+{
+    frac=xdc_iscale*(-x1);
+    x1=0;
+}
+else
+    frac=0;
+x2 = x2 >= viewwidth ? viewwidth-1 : x2;
+
+startx=x1;
+startfrac=frac;
+for (plane=startx; plane<startx+4; plane++,startfrac+=xdc_iscale)
+{
+    frac=startfrac;
+    b=(byte *)bufferofs+(plane>>2);
+    VGAWRITEMAP(plane&3);
+    for (x1=plane; x1<=x2 ; x1+=4, frac += xdc_iscale<<2,b++)
+        ScaleClippedPost(((p->collumnofs[frac>>SFRACBITS])+shape),b);
+}
+}
+#endif
+
+
+
+//******************************************************************************
+//
+// DrawNormalPost
+//
+//******************************************************************************
+
+void DrawNormalPost (byte * src, byte * buf)
+{
+    int  offset;
+    int  length;
+    int  s;
+
+    whereami=40;
+
+    while (1)
+    {
+        offset=*(src++);
+        if (offset==0xff)
+            return;
+        else
+        {
+            length=*(src++);
+            for (s=0; s<length; s++) {
+                // Spaced out a little for tracking a bug. Should be equivalent.
+                byte *saddr = src+s;
+                byte *daddr = buf + ylookup[offset + s];
+                byte val = *saddr;
+                *daddr = val;
+//                *(buf+ylookup[offset+s])=*(src+s);
+            }
+            src+=length;
+        }
+    }
+}
+
+
+
+//******************************************************************************
+//
+// DrawNormalSprite
+//
+//******************************************************************************
+
+void DrawNormalSprite (int x, int y, int shapenum)
+{
+    byte *buffer;
+    int cnt;
+    byte *shape;
+    patch_t *p;
+    int plane;
+    byte * b;
+    int startx;
+
+    whereami=41;
+
+    shape = W_CacheLumpNum (shapenum, PU_CACHE, Cvt_patch_t, 1);
+    p = (patch_t *)shape;
+
+    if (((x-p->leftoffset)<0) || ((x-p->leftoffset+p->width)>iGLOBAL_SCREENWIDTH))
+        Error ("DrawNormalSprite: x is out of range x=%d\n",x-p->leftoffset+p->width);
+    if (((y-p->topoffset)<0) || ((y-p->topoffset+p->height)>iGLOBAL_SCREENHEIGHT))
+        Error ("DrawNormalSprite: y is out of range y=%d\n",y-p->topoffset+p->height);
+
+    startx=x-p->leftoffset;
+    buffer = (byte*)bufferofs+ylookup[y-p->topoffset];
+
+#ifdef DOS
+    for (plane=startx; plane<startx+4; plane++)
+#endif
+    {
+#ifdef DOS
+        b=buffer+(plane>>2);
+        VGAWRITEMAP(plane&3);
+#else
+        b=buffer+startx;
+#endif
+
+#ifdef DOS
+        for (cnt = plane-startx; cnt < p->width; cnt+=4,b++)
+#else
+        for (cnt = 0; cnt < p->width; cnt++,b++)
+#endif
+            DrawNormalPost ((byte *)(p->collumnofs[cnt]+shape), b);
+    }
+}
+
+#ifndef DOS
+
+void R_DrawColumn (byte * buf)
+{
+    // This is *NOT* 100% correct - DDOI
+    int count;
+    int frac, fracstep;
+    byte *dest;
+
+    count = dc_yh - dc_yl + 1;
+    if (count < 0) return;
+
+    dest = buf + ylookup[dc_yl];
+
+    fracstep = dc_iscale;
+    frac = dc_texturemid + (dc_yl-centery)*fracstep;
+
+    while (count--) {
+        //*dest = test++;
+        *dest = shadingtable[dc_source[(frac>>SFRACBITS)]];
+        dest += iGLOBAL_SCREENWIDTH;
+        frac += fracstep;
+    }
+}
+
+void R_TransColumn (byte * buf)
+{
+    int count;
+    byte *dest;
+
+    count = dc_yh - dc_yl + 1;
+    if (count < 0) return;
+
+    dest = buf + ylookup[dc_yl];
+
+    while (count--)
+    {
+        *dest = shadingtable[*dest];
+        dest += iGLOBAL_SCREENWIDTH;
+    }
+}
+
+void R_DrawWallColumn (byte * buf)
+{
+    // This is *NOT* 100% correct - DDOI
+    int count;
+    int frac, fracstep;
+    byte *dest;
+
+    count = dc_yh - dc_yl;
+    if (count < 0) return;
+
+    dest = buf + ylookup[dc_yl];
+
+    fracstep = dc_iscale;
+    frac = dc_texturemid + (dc_yl-centery)*fracstep;
+    frac <<= 10;
+    fracstep <<= 10;
+
+    while (count--) {
+        //*dest = 6;
+        *dest = shadingtable[dc_source[(((unsigned)frac)>>26)]];
+        dest += iGLOBAL_SCREENWIDTH;
+        frac += fracstep;
+    }
+}
+
+void R_DrawClippedColumn (byte * buf)
+{
+    // This is *NOT* 100% correct - DDOI zxcv
+    int count;
+    int frac, fracstep;
+    byte *dest;
+//		byte *b;int y;
+
+    count = dc_yh - dc_yl + 1;
+    if (count < 0) return;
+
+    dest = buf + ylookup[dc_yl];
+
+
+    fracstep = dc_iscale;
+    frac = dc_texturemid + (dc_yl-centeryclipped)*fracstep;
+
+    while (count--) {
+        *dest = shadingtable[dc_source[(((unsigned)frac)>>SFRACBITS)]];
+        dest += iGLOBAL_SCREENWIDTH;
+        frac += fracstep;
+    }
+}
+
+void R_DrawSolidColumn (int color, byte * buf)
+{
+    int count;
+    int frac, fracstep;
+    byte *dest;
+
+    count = dc_yh - dc_yl + 1;
+    if (count < 0) return;
+
+    dest = buf + ylookup[dc_yl];
+
+    while (count--)
+    {
+        *dest = (byte)color;
+        dest += iGLOBAL_SCREENWIDTH;
+    }
+}
+
+#endif
--- /dev/null
+++ b/rott/rt_scale.h
@@ -1,0 +1,53 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+//***************************************************************************
+//
+//    RT_SCALE.H - Scale-o-rama
+//
+//***************************************************************************
+#ifndef _rt_scale_public
+#define _rt_scale_public
+
+#include "rt_draw.h"
+
+extern  int dc_texturemid;
+extern  int dc_iscale;
+extern  int dc_invscale;
+extern  int centeryclipped;
+extern  int sprtopoffset;
+extern  int dc_yl;
+extern  int dc_yh;
+extern  byte * dc_source;
+extern  int transparentlevel;
+
+void ScaleShape (visobj_t * vis);
+void ScaleWeapon (int xcent, int yoffset, int shapenum);
+void DrawScreenSprite (int x, int y, int shapenum);
+void SetLightLevel (int height);
+void ScaleMaskedPost (byte * src, byte * buf);
+void DrawScreenSizedSprite (int lump);
+void ScaleTransparentPost (byte * src, byte * buf, int level);
+void ScaleTransparentShape (visobj_t * sprite);
+void ScaleSolidShape (visobj_t * sprite);
+void DrawUnScaledSprite (int x, int y, int shapenum, int shade);
+void DrawPositionedScaledSprite (int x, int y, int shapenum, int height, int type);
+void DrawNormalSprite (int x, int y, int shapenum);
+
+#endif
--- /dev/null
+++ b/rott/rt_sound.c
@@ -1,0 +1,1548 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+#include "rt_def.h"
+#include "rt_sound.h"
+#include "_rt_soun.h"
+#include "fx_man.h"
+#include "music.h"
+#include "z_zone.h"
+#include "w_wad.h"
+#include "rt_main.h"
+#include "rt_ted.h"
+#include "rt_menu.h"
+#include "rt_playr.h"
+#include "rt_util.h"
+#include "rt_rand.h"
+#include "watcom.h"
+#include <stdio.h>
+#include <stdlib.h>
+
+#if PLATFORM_DOS
+#include <mem.h>
+#include <io.h>
+#elif PLATFORM_UNIX
+#include <unistd.h>
+#endif
+
+#include "rt_cfg.h"
+#include "isr.h"
+#include "develop.h"
+#include "rt_net.h"
+
+#include "rt_str.h"
+
+#if (SHAREWARE==0)
+#include "snd_reg.h"
+#else
+#include "snd_shar.h"
+#endif
+//MED
+#include "memcheck.h"
+
+// Local Variables
+
+static int soundstart;
+static int soundtype;
+int SD_Started=false;
+static boolean PositionStored=false;
+static int NumBadSounds=0;
+static int remotestart;
+static boolean SoundsRemapped = false;
+
+#ifdef DOS
+int musicnums[ 11 ] = {
+    -1, UltraSound, SoundBlaster, SoundMan16, ProAudioSpectrum,
+    Awe32, SoundScape, WaveBlaster, GenMidi, SoundCanvas, Adlib
+};
+
+int fxnums[ 11 ] = {
+    -1, UltraSound, SoundBlaster, SoundMan16, ProAudioSpectrum,
+    Awe32, SoundScape, Adlib, SoundSource, TandySoundSource, PC
+};
+#else
+int musicnums[ 11 ] = {
+    -1, -1, -1, -1, -1, -1, SoundScape, -1, -1, -1, -1
+};
+
+int fxnums[ 11 ] = {
+    -1, -1, -1, -1, -1, -1, SoundScape, -1, -1, -1, -1
+};
+#endif
+
+#if 0
+void MU_SetupGUSInitFile( void );
+#endif
+
+int MUSIC_GetPosition( void ) {
+    songposition pos;
+
+    MUSIC_GetSongPosition( &pos );
+    return pos.milliseconds;
+}
+
+void MUSIC_SetPosition( int time ) {
+    MUSIC_SetSongTime( ( unsigned long )time );
+}
+
+
+//***************************************************************************
+//
+// SoundNumber
+//
+//***************************************************************************
+
+int SoundNumber ( int x )
+{
+    if ((x>=SD_REMOTEM1SND) && (x<=SD_REMOTEM10SND))
+        return remotestart + x - SD_REMOTEM1SND;
+//      sounds[x].snds[soundtype]+remotestart;
+    else
+        return sounds[x].snds[soundtype]+soundstart;
+}
+
+
+//***************************************************************************
+//
+// SD_MakeCacheable - Make a sound that has just finished playing cacheable again
+//
+//***************************************************************************
+void SD_MakeCacheable( unsigned long sndnum )
+{
+    if (sndnum == (unsigned long) -1)
+    {
+        return;
+    }
+
+    if (sndnum>=MAXSOUNDS)
+    {
+        SoftError ("Illegal sound value in SD_MakeCacheable value=%ld\n",sndnum);
+        return;
+    }
+    sounds[sndnum].count--;
+    if (sounds[sndnum].count>0)
+        return;
+    else
+        W_CacheLumpNum(SoundNumber(sndnum),PU_CACHE, CvtNull, 1);
+}
+
+#if 0
+//***************************************************************************
+//
+// SD_PrintActive
+//
+//***************************************************************************
+void SD_PrintActive ( void )
+{
+    int i;
+
+    myprintf("Active Sounds\n");
+    for (i=0; i<MAXSOUNDS; i++)
+    {
+        if (sounds[i].count>0)
+        {
+            myprintf("sound active #%ld\n",i);
+        }
+    }
+}
+#endif
+
+//***************************************************************************
+//
+// SD_SetupFXCard - Initialize sound Tables and start up sound card
+//
+//***************************************************************************
+
+int SD_SetupFXCard ( int * numvoices, int * numbits, int * numchannels)
+{
+    fx_device device;
+    int status;
+    int card;
+
+    if (SD_Started==true)
+        SD_Shutdown();
+
+    if ( ( FXMode < 0 ) || ( FXMode >= 11 ) )
+    {
+        return( 0 );
+    }
+
+    card = fxnums[ FXMode ];
+    if (card==-1) // Check if it is off
+        return (0);
+#ifdef DOS
+    if ( ( card == SoundBlaster ) || ( card == Awe32 ) )
+    {
+        extern fx_blaster_config SBSettings;
+
+        status = FX_SetupSoundBlaster( SBSettings, numvoices,
+                                       numbits, numchannels );
+    }
+    else
+    {
+#endif
+        status=FX_SetupCard( card, &device );
+        if ( status == FX_Ok )
+        {
+            *numvoices=device.MaxVoices;
+            *numbits=device.MaxSampleBits;
+            *numchannels=device.MaxChannels;
+        }
+#ifdef DOS
+    }
+#endif
+
+    return (status);
+}
+
+//***************************************************************************
+//
+// SD_Startup - Initialize sound Tables and start up sound card
+//
+//***************************************************************************
+
+int SD_Startup ( boolean bombonerror )
+{
+    int status;
+    int card;
+    int voices;
+    int channels;
+    int bits;
+    int i;
+    extern boolean IS8250;
+
+    if (SD_Started==true)
+        SD_Shutdown();
+
+    if ( ( FXMode < 0 ) || ( FXMode >= 11 ) )
+    {
+        return( 0 );
+    }
+    card = fxnums[ FXMode ];
+    if (card==-1) // Check if it is off
+        return (0);
+
+    switch (card)
+    {
+#ifdef DOS
+    case UltraSound:
+    case SoundBlaster:
+    case SoundMan16:
+    case ProAudioSpectrum:
+    case Awe32:
+    case SoundSource:
+    case TandySoundSource:
+#endif
+    case SoundScape:
+        soundstart=W_GetNumForName("digistrt")+1;
+        soundtype=fx_digital;
+        break;
+#ifdef DOS
+    case Adlib:
+        soundstart=W_GetNumForName("adstart")+1;
+        soundtype=fx_muse;
+        break;
+    case PC:
+        soundstart=W_GetNumForName("pcstart")+1;
+        soundtype=fx_muse;
+        break;
+#endif
+    default:
+        Error("FX: Unsupported Card number %d",FXMode);
+        break;
+    }
+
+    if ( soundtype == fx_digital )
+    {
+        if ( SoundsRemapped == false )
+        {
+            for( i = 0; i < SD_LASTSOUND; i++ )
+            {
+                int snd;
+
+                snd = sounds[ i ].snds[ fx_digital ];
+                if ( snd >= 0)
+                {
+                    sounds[ i ].snds[ fx_digital ] = W_GetNumForName(
+                                                         W_GetNameForNum( snd + soundstart ) );
+                }
+            }
+            SoundsRemapped = true;
+        }
+        soundstart = 0;
+    }
+
+    voices   = NumVoices;
+    channels = NumChannels;
+    bits     = NumBits;
+
+    if ( IS8250 )
+    {
+        voices   = max( voices, 4 );
+        channels = 1;
+        bits     = 8;
+    }
+
+#ifdef DOS
+    status=FX_Init( card, voices, channels, bits, 11000 );
+#else
+    status=FX_Init( card, voices, channels, bits, 11025 );
+#endif
+
+    if (status != FX_Ok)
+    {
+        if (bombonerror)
+        {
+            DeleteSoundFile ();
+            Error( "%s\n", FX_ErrorString( status ) );
+        }
+
+        return (status);
+    }
+
+    if (stereoreversed == true)
+    {
+        FX_SetReverseStereo(!FX_GetReverseStereo());
+    }
+
+    FX_SetCallBack( SD_MakeCacheable );
+
+    remotestart=W_GetNumForName("remostrt")+1;
+
+    SD_Started=true;
+
+    FX_SetVolume (FXvolume);
+
+    return (0);
+}
+
+//***************************************************************************
+//
+// SD_SoundOkay - checks to see if the sound is okay
+//
+//***************************************************************************
+
+boolean SD_SoundOkay ( int sndnum )
+{
+    if (SD_Started==false)
+        return false;
+
+    if (sndnum>=MAXSOUNDS)
+        Error ("Illegal sound number, sound number = %d\n",sndnum);
+
+    if (SoundOffset(sndnum)==-1)
+        return false;
+
+    if ( ( sounds[ sndnum ].flags & SD_PLAYONCE ) &&
+            ( SD_SoundActive( sounds[ sndnum ].prevhandle ) ) )
+    {
+        return false;
+    }
+
+    return true;
+}
+
+//***************************************************************************
+//
+// SD_PlayIt - Play a pre-setup sound
+//
+//***************************************************************************
+
+int SD_PlayIt ( int sndnum, int angle, int distance, int pitch )
+{
+    int voice;
+    byte * snd;
+
+#if (DEVELOPMENT == 1)
+#if (SOUNDTEST == 1)
+    SoftError("SOUND =%d \n",sndnum);
+#endif
+#endif
+
+    if (!(sounds[sndnum].flags & SD_WRITE))
+    {
+        if (sounds[sndnum].count)
+        {
+            if (distance<=sounds[sndnum].prevdistance)
+                FX_StopSound(sounds[sndnum].prevhandle);
+            else
+                return 0;
+        }
+    }
+
+    if ( !FX_VoiceAvailable( sounds[sndnum].priority ) )
+    {
+        return( 0 );
+    }
+
+    sounds[sndnum].count++;
+
+    snd=W_CacheLumpNum(SoundNumber(sndnum),PU_STATIC, CvtNull, 1);
+
+    if ( *snd == 'C' )
+    {
+        voice = FX_PlayVOC3D( snd, pitch, angle, distance,
+                              sounds[sndnum].priority, (unsigned long) sndnum );
+    }
+    else
+    {
+        voice = FX_PlayWAV3D( snd, pitch, angle, distance,
+                              sounds[sndnum].priority, (unsigned long) sndnum );
+    }
+
+    if ( voice < FX_Ok )
+    {
+#if (DEVELOPMENT == 1)
+        /*
+              if (MV_ErrorCode == MV_InvalidVOCFile)
+                 {
+                 Error("SD_PlayIt: Invalid VOC File snd=%p sndnum=%ld lump=%ld\n",snd,sndnum,SoundNumber(sndnum));
+                 }
+        */
+        NumBadSounds++;
+        SoftError("SD_PlayIt: Error/Warning %s\n",FX_ErrorString( FX_Error ));
+        SoftError("BadSoundNumber %ld time %ld\n",NumBadSounds,GetTicCount());
+#endif
+        SD_MakeCacheable( sndnum );
+
+        return 0;
+    }
+
+    NumBadSounds=0;
+
+    if (!(sounds[sndnum].flags & SD_WRITE))
+    {
+        sounds[sndnum].prevhandle=voice;
+        sounds[sndnum].prevdistance=distance;
+    }
+    return voice;
+}
+
+
+//***************************************************************************
+//
+// SD_Play - Play a sample
+//
+//***************************************************************************
+
+int SD_Play ( int sndnum )
+{
+    int voice;
+    int pitch;
+
+    if ( SD_SoundOkay ( sndnum ) == false )
+        return 0;
+
+    pitch = 0;
+
+    if ( !( sounds[ sndnum ].flags & SD_PITCHSHIFTOFF ) )
+    {
+        pitch = PitchOffset();
+    }
+
+    voice = SD_PlayIt ( sndnum, 0, 0, pitch );
+
+    return voice;
+
+}
+
+//***************************************************************************
+//
+// SD_Play3D - Play a positioned sample
+//
+//***************************************************************************
+
+int SD_Play3D ( int sndnum, int angle, int distance )
+{
+    int voice;
+    int pitch;
+
+    if ( SD_SoundOkay ( sndnum ) == false )
+        return 0;
+
+    pitch = 0;
+    if ( !( sounds[ sndnum ].flags & SD_PITCHSHIFTOFF ) )
+    {
+        pitch = PitchOffset();
+    }
+
+    voice = SD_PlayIt ( sndnum, angle, distance, pitch );
+
+    return voice;
+
+}
+
+//***************************************************************************
+//
+// SD_PlayPositionedSound - Play a positioned sample
+//
+//***************************************************************************
+
+int SD_PlayPositionedSound ( int sndnum, int px, int py, int x, int y )
+{
+    int voice;
+    int angle;
+    int distance;
+    int dx;
+    int dy;
+    int pitch;
+
+    if ( SD_SoundOkay ( sndnum ) == false )
+        return 0;
+
+    dx=(x-px);
+    dy=(py-y);
+
+    distance=FindDistance(dx,dy) >> SD_DISTANCESHIFT;
+
+    if (distance>255)
+        return 0;
+
+    if (distance!=0)
+    {
+        angle = ( atan2_appx(dx,dy) & (FINEANGLES-1) ) >> 6;
+    }
+    else
+    {
+        angle=0;
+    }
+
+    pitch = 0;
+
+    if ( !( sounds[ sndnum ].flags & SD_PITCHSHIFTOFF ) )
+    {
+        pitch = PitchOffset();
+    }
+
+    voice = SD_PlayIt ( sndnum, angle, distance, pitch );
+
+    return voice;
+
+}
+
+//***************************************************************************
+//
+// SD_PlaySoundRTP - Play a positioned sample relative to the player
+//
+//***************************************************************************
+
+int SD_PlaySoundRTP ( int sndnum, int x, int y )
+{
+    int voice;
+    int angle;
+    int distance;
+    int dx;
+    int dy;
+    int pitch;
+
+
+    if ( SD_SoundOkay ( sndnum ) == false )
+        return 0;
+
+    dx=(x-player->x);
+    dy=(player->y-y);
+
+    distance=FindDistance(dx,dy) >> SD_DISTANCESHIFT;
+
+    if (distance>255)
+        return 0;
+
+    if (distance!=0)
+    {
+        angle = ( (player->angle - atan2_appx(dx,dy)) & (FINEANGLES-1) ) >> 6;
+    }
+    else
+    {
+        angle=0;
+    }
+
+    pitch = 0;
+
+    if ( !( sounds[ sndnum ].flags & SD_PITCHSHIFTOFF ) )
+    {
+        pitch = PitchOffset();
+    }
+
+    voice = SD_PlayIt ( sndnum, angle, distance, pitch );
+
+    return voice;
+}
+
+//***************************************************************************
+//
+// SD_PlayPitchedSound - Play a pitched sample
+//
+//***************************************************************************
+
+int SD_PlayPitchedSound ( int sndnum, int volume, int pitch )
+{
+    int voice;
+    int distance;
+
+    if ( SD_SoundOkay ( sndnum ) == false )
+        return 0;
+
+    distance = 255 - volume;
+
+    voice = SD_PlayIt ( sndnum, 0, distance, pitch );
+
+    return voice;
+}
+
+//***************************************************************************
+//
+// SD_SetSoundPitch - sets the pitch of a sound
+//
+//***************************************************************************
+
+void SD_SetSoundPitch ( int sndnum, int pitch )
+{
+    int status;
+
+    if (SD_Started==false)
+        return;
+
+    if (!FX_SoundActive(sndnum))
+        return;
+
+    status=FX_SetPitch( sndnum, pitch );
+    if (status != FX_Ok)
+    {
+#if (DEVELOPMENT == 1)
+        SoftError("SD_SetSoundPitch : %s\n",FX_ErrorString( status ));
+#endif
+    }
+}
+
+//***************************************************************************
+//
+// SD_PanRTP Sound - pan a positioned sample relative to the player
+//
+//***************************************************************************
+
+void SD_PanRTP ( int handle, int x, int y )
+{
+    int angle;
+    int distance;
+    int dx;
+    int dy;
+    int status;
+
+    if (SD_Started==false)
+        return;
+
+    if (!FX_SoundActive(handle))
+        return;
+
+    dx=(x-player->x);
+    dy=(player->y-y);
+
+    distance=FindDistance(dx,dy) >> SD_DISTANCESHIFT;
+
+    if (distance>255)
+        return;
+
+    if (distance!=0)
+    {
+        angle = ( (player->angle - atan2_appx(dx,dy)) & (FINEANGLES-1) ) >> 6;
+    }
+    else
+    {
+        angle = 0;
+    }
+
+    status = FX_Pan3D ( handle, angle, distance );
+
+    if (status != FX_Ok)
+    {
+#if (DEVELOPMENT == 1)
+        SoftError("SD_PanPositionedSound: %s\n",FX_ErrorString( status ));
+#endif
+    }
+}
+
+//***************************************************************************
+//
+// SD_SetPan - set the pan of a sample
+//
+//***************************************************************************
+
+void SD_SetPan ( int handle, int vol, int left, int right )
+{
+    int status;
+
+    if (SD_Started==false)
+        return;
+
+    if (!FX_SoundActive(handle))
+        return;
+
+    status=FX_SetPan( handle, vol, left, right );
+
+    if (status != FX_Ok)
+    {
+#if (DEVELOPMENT == 1)
+        SoftError("SD_SetPan: %s\n",FX_ErrorString( status ));
+#endif
+    }
+}
+
+//***************************************************************************
+//
+// SD_PanPositioned Sound - pan a positioned sample
+//
+//***************************************************************************
+
+void SD_PanPositionedSound ( int handle, int px, int py, int x, int y )
+{
+    int angle;
+    int distance;
+    int dx;
+    int dy;
+    int status;
+
+    if (SD_Started==false)
+        return;
+
+    if (!FX_SoundActive(handle))
+        return;
+
+    dx=(x-px);
+    dy=(py-y);
+
+    distance=FindDistance(dx,dy) >> SD_DISTANCESHIFT;
+
+    if (distance>255)
+        return;
+
+    if (distance!=0)
+    {
+        angle = ( atan2_appx(dx,dy) & (FINEANGLES-1) ) >> 6;
+    }
+    else
+    {
+        angle = 0;
+    }
+
+    status=FX_Pan3D( handle, angle, distance );
+
+    if (status != FX_Ok)
+    {
+#if (DEVELOPMENT == 1)
+        SoftError("SD_PanPositionedSound: %s\n",FX_ErrorString( status ));
+#endif
+    }
+}
+
+
+//***************************************************************************
+//
+// SD_StopSound - Stop the current sound from playing
+//
+//***************************************************************************
+
+void SD_StopSound ( int handle )
+{
+    int status;
+
+    if (SD_Started==false)
+        return;
+
+    status=FX_StopSound( handle);
+
+    if (status != FX_Ok)
+    {
+#if (DEVELOPMENT == 1)
+        SoftError("SD_StopSound: %s\n",FX_ErrorString( status ));
+#endif
+    }
+}
+
+//***************************************************************************
+//
+// SD_StopAllSounds - Stop All the sounds currently playing
+//
+//***************************************************************************
+
+void  SD_StopAllSounds ( void )
+{
+    int status;
+
+    if (SD_Started==false)
+        return;
+
+    status=FX_StopAllSounds();
+
+    if (status != FX_Ok)
+    {
+#if (DEVELOPMENT == 1)
+        SoftError("SD_StopAllSounds: %s\n",FX_ErrorString( status ));
+#endif
+    }
+}
+
+//***************************************************************************
+//
+// SD_SoundActive - See if a sound is active
+//
+//***************************************************************************
+
+int SD_SoundActive ( int handle )
+{
+    if (SD_Started==false)
+    {
+        return false;
+    }
+    else
+    {
+        return (FX_SoundActive(handle));
+    }
+}
+
+//***************************************************************************
+//
+// SD_WaitSound - wait until a sound has finished
+//
+//***************************************************************************
+void SD_WaitSound ( int handle )
+{
+    int time;
+
+    IN_ClearKeysDown();
+
+    while (FX_SoundActive(handle)!=0)
+    {
+        time=GetTicCount()+1;
+        while (time>GetTicCount()) {}
+        if ((LastScan) || IN_GetMouseButtons())
+            break;
+    }
+}
+
+
+//***************************************************************************
+//
+// SD_Shutdown - Shutdown the sound system
+//
+//***************************************************************************
+
+void SD_Shutdown (void)
+{
+    if (SD_Started==false)
+        return;
+
+    FX_Shutdown();
+    SD_Started=false;
+}
+
+
+//***************************************************************************
+//
+// SD_PreCacheSound - PreCache sound
+//
+//***************************************************************************
+
+void SD_PreCacheSound ( int num )
+{
+    if ( SD_SoundOkay ( num ) == false )
+        return;
+
+    PreCacheLump(SoundNumber(num),PU_CACHESOUNDS+sounds[num].priority,cache_other);
+}
+
+//***************************************************************************
+//
+// SD_PreCacheSoundGroup - PreCache sound group
+//
+//***************************************************************************
+
+void SD_PreCacheSoundGroup ( int lo, int hi )
+{
+    int i;
+
+    if (SD_Started==false)
+        return;
+
+    for (i=lo; i<=hi; i++)
+        SD_PreCacheSound(i);
+}
+
+
+#if (SHAREWARE == 1)
+#define MAXSONGS 18
+static song_t rottsongs[MAXSONGS] = {
+    { loop_no,  song_apogee,"FANFARE2","Apogee Fanfare"},
+    { loop_yes, song_title,"RISE",    "Rise"},
+    { loop_yes, song_menu,"MMMENU",  "MMMenu"},
+    { loop_yes, song_christmas,"DEADLY", "Deadly Gentlemen"},
+    { loop_yes, song_elevator,"GOINGUP", "Going up?"},
+    { loop_yes, song_endlevel,"HOWDIDO", "How'd I do?"},
+    { loop_yes, song_secretmenu,"FISHPOLK","Fish Polka"},
+    { loop_yes, song_gameover,"YOUSUCK", "You Suck"},
+    { loop_yes, song_youwin,"WATZNEXT","Watz Next?"},
+    { loop_no,  song_gason,"GAZZ!",   "Gazz!"},
+    { loop_yes, song_level,"FASTWAY", "Goin' Down The Fast Way"},
+    { loop_yes, song_level,"MISTACHE","Mist Ache"},
+    { loop_yes, song_level,"OWW",     "Oww!!!"},
+    { loop_yes, song_level,"SMOKE",   "Smoke And Mirrors"},
+    { loop_yes, song_level,"SPRAY",   "Spray"},
+    { loop_yes, song_level,"RUNLIKE", "Run Like Smeg"},
+    { loop_yes, song_level,"SMOOTH",  "Havana Smooth"},
+    { loop_yes, song_level,"CHANT",   "Chant"},
+};
+#else
+#define MAXSONGS 34
+static song_t rottsongs[MAXSONGS] = {
+    { loop_no,  song_apogee,"FANFARE2","Apogee Fanfare"},
+    { loop_yes, song_title,"RISE",    "Rise"},
+    { loop_yes, song_menu,"MMMENU",  "MMMenu"},
+    { loop_yes, song_christmas,"DEADLY", "Deadly Gentlemen"},
+    { loop_yes, song_elevator,"GOINGUP", "Going up?"},
+    { loop_yes, song_secretmenu,"FISHPOLK","Fish Polka"},
+    { loop_yes, song_endlevel,"HOWDIDO", "How'd I do?"},
+    { loop_yes, song_gameover,"YOUSUCK", "You Suck"},
+    { loop_yes, song_cinematic2,"WATZNEXT","Watz Next?"},
+    { loop_no,  song_gason,"GAZZ!",   "Gazz!"},
+    { loop_yes, song_level,"FASTWAY", "Goin' Down The Fast Way"},
+    { loop_yes, song_level,"MISTACHE","Mist Ache"},
+    { loop_yes, song_level,"OWW",     "Oww!!!"},
+    { loop_yes, song_level,"SMOKE",   "Smoke And Mirrors"},
+    { loop_yes, song_level,"SPRAY",   "Spray"},
+    { loop_yes, song_level,"RUNLIKE", "Run Like Smeg"},
+    { loop_yes, song_level,"SMOOTH",  "Havana Smooth"},
+    { loop_yes, song_level,"CHANT",   "Chant"},
+    { loop_yes, song_level,"MEDIEV1A","Funeral of Queen Mary"},
+    { loop_yes, song_level,"TASKFORC","Task Force"},
+    { loop_yes, song_level,"KISSOFF", "KISS Off"},
+    { loop_yes, song_level,"RADAGIO", "Adagio For Strings"},
+    { loop_yes, song_level,"SHARDS",  "Shards"},
+    { loop_yes, song_level,"STAIRS",  "I Choose the Stairs"},
+    { loop_yes, song_level,"SUCKTHIS","Suck This"},
+    { loop_yes, song_level,"EXCALIBR","Excalibur"},
+    { loop_yes, song_level,"CCCOOL",   "CCCool"},
+    { loop_yes, song_level,"WORK_DAY","Work Day"},
+    { loop_yes, song_level,"WHERIZIT","Where Iz It?"},
+    { loop_no,  song_bossdie,"BOSSBLOW", "Boss Blow"},
+    { loop_yes, song_bosssee,"HELLERO", "Hellero"},
+    { loop_yes, song_cinematic1,"EVINRUDE","Evin Rude"},
+    { loop_yes, song_youwin,"VICTORY", "Victory!"},
+    { loop_yes, song_dogend,"HERE_BOY","Here Boy"}
+};
+#endif
+
+static byte * currentsong;
+static int MU_Started=false;
+static int lastsongnumber=-1;
+int storedposition=0;
+
+//****************************************************************************
+//
+// MU_JukeBoxMenu()
+//
+//****************************************************************************
+
+void MU_PlayJukeBoxSong
+(
+    int which
+)
+
+{
+    if ( ( MusicMode > 0 ) && ( MU_Started == true ) )
+    {
+        SetMenuHeader( rottsongs[ which ].songname );
+        MU_PlaySong( which );
+    }
+}
+
+
+//****************************************************************************
+//
+// MU_JukeBoxMenu()
+//
+//****************************************************************************
+
+void MU_JukeBoxRedraw
+(
+    void
+)
+
+{
+    if ( ( MusicMode > 0 ) && ( MU_Started == true ) )
+    {
+        SetMenuHeader( rottsongs[ lastsongnumber ].songname );
+    }
+}
+
+
+//****************************************************************************
+//
+// MU_JukeBoxMenu()
+//
+//****************************************************************************
+
+void MU_JukeBoxMenu
+(
+    void
+)
+
+{
+    char *SongNames[ MAXSONGS ];
+    int   i;
+
+    for( i = 0; i < MAXSONGS; i++ )
+    {
+        SongNames[ i ] = rottsongs[ i ].songname;
+    }
+
+    HandleMultiPageCustomMenu( SongNames, MAXSONGS, lastsongnumber,
+                               "Jukebox", MU_PlayJukeBoxSong, MU_JukeBoxRedraw, false );
+
+    if ( rottsongs[ lastsongnumber ].loopflag == loop_no )
+    {
+        MU_StartSong(song_level);
+    }
+}
+
+//***************************************************************************
+//
+// MusicStarted - see if the music is started
+//
+//***************************************************************************
+boolean MusicStarted( void )
+{
+    return MU_Started;
+}
+
+//***************************************************************************
+//
+// MU_Startup - Initialize music stuff
+//
+//***************************************************************************
+
+int MU_Startup ( boolean bombonerror )
+{
+    int status;
+    int card;
+
+    if (MU_Started==true)
+    {
+        MU_StopSong();
+        MU_Shutdown();
+    }
+    if ( ( MusicMode < 0 ) || ( MusicMode >= 11 ) )
+    {
+        return( 0 );
+    }
+    card = musicnums[ MusicMode ];
+    if (card==-1) // Check if it is off
+        return (0);
+
+#ifdef DOS
+    if ( ( card == SoundBlaster ) || ( card == Awe32 ) || ( card == WaveBlaster ) )
+    {
+        if ( SD_Started == false )
+        {
+            extern fx_blaster_config SBSettings;
+            int numvoices;
+            int numbits;
+            int numchannels;
+
+            FX_SetupSoundBlaster( SBSettings, &numvoices,
+                                  &numbits, &numchannels );
+        }
+    }
+
+    if (card== UltraSound)
+    {
+        MU_SetupGUSInitFile();
+    }
+
+    status=MUSIC_Init( card, MidiAddress );
+#else
+    /* Not DOS, no address config needed */
+    status=MUSIC_Init( card, 0 );
+#endif
+
+
+    if (status != MUSIC_Ok) {
+        if (bombonerror)
+        {
+            DeleteSoundFile ();
+            Error( "%s\n", MUSIC_ErrorString( status ) );
+        }
+        else
+            return (status);
+    }
+
+    currentsong=0;
+
+    MU_Started=true;
+
+    MU_SetVolume (MUvolume);
+
+    return (0);
+}
+
+//***************************************************************************
+//
+// MU_Shutdown - Shutdown the music system
+//
+//***************************************************************************
+
+void MU_Shutdown (void)
+{
+    if (MU_Started==false)
+        return;
+    MUSIC_Shutdown();
+    MU_Started=false;
+}
+
+#ifdef DOS
+//***************************************************************************
+//
+// MU_SetupGUSInitFile - initialize GUS stuff
+//
+//***************************************************************************
+
+void MU_SetupGUSInitFile( void )
+{
+    char filename[ 128 ];
+
+    GetPathFromEnvironment( filename, ApogeePath, GUSMIDIINIFILE );
+    if (access (filename, F_OK) != 0)
+    {
+        int lump;
+
+        lump=W_GetNumForName("gusmidi");
+
+        SaveFile (filename, W_CacheLumpNum(lump,PU_CACHE, CvtNull, 1), W_LumpLength(lump));
+    }
+}
+
+#endif
+
+//***************************************************************************
+//
+// MU_GetNumForType - returns number of song in rottsongs of specific type
+//
+//***************************************************************************
+int MU_GetNumForType ( int type )
+{
+    int i;
+
+    for (i=0; i<MAXSONGS; i++)
+    {
+        if (rottsongs[i].songtype == type)
+            return i;
+    }
+    Error("MU_GetNumForType: could not find song type in list\n");
+    return -1;
+}
+
+
+//***************************************************************************
+//
+// MU_PlaySong - Play a specific song number
+//
+//***************************************************************************
+
+void MU_PlaySong ( int num )
+{
+    int lump;
+    int size;
+
+    if (MU_Started==false)
+        return;
+
+    if (num<0)
+        return;
+
+    if (num>=MAXSONGS)
+        Error("Song number out of range\n");
+
+    MU_StopSong();
+
+    lastsongnumber=num;
+
+    lump = W_GetNumForName(rottsongs[num].lumpname);
+    size = W_LumpLength(lump);
+
+    currentsong=W_CacheLumpNum(lump,PU_STATIC, CvtNull, 1);
+
+#ifdef PLATFORM_DOS
+    if (rottsongs[num].loopflag == loop_yes)
+        MUSIC_PlaySong(currentsong,size,MUSIC_LoopSong);
+    else
+        MUSIC_PlaySong(currentsong,size,MUSIC_PlayOnce);
+#else
+    if (rottsongs[num].loopflag == loop_yes)
+        MUSIC_PlaySongROTT(currentsong,size,MUSIC_LoopSong);
+    else
+        MUSIC_PlaySongROTT(currentsong,size,MUSIC_PlayOnce);
+#endif
+
+    MU_SetVolume (MUvolume);
+}
+
+//***************************************************************************
+//
+// MU_StopSong - Play a specific song number
+//
+//***************************************************************************
+
+void MU_StopSong ( void )
+{
+    if (MU_Started==false)
+        return;
+
+    MUSIC_StopSong ();
+    if (currentsong)
+    {
+        W_CacheLumpName(rottsongs[lastsongnumber].lumpname,PU_CACHE, CvtNull, 1);
+        currentsong=0;
+    }
+}
+
+//***************************************************************************
+//
+// MU_GetSongNumber - get current song number
+//
+//***************************************************************************
+
+int MU_GetSongNumber ( void )
+{
+    return lastsongnumber;
+}
+
+
+//***************************************************************************
+//
+// MU_FadeToSong - Fade to a specific song in a certain time
+//
+//***************************************************************************
+
+void MU_FadeToSong ( int num, int time )
+{
+    int t;
+
+    if (MU_Started==false)
+        return;
+
+    MU_FadeOut(time>>1);
+
+    while (MU_FadeActive())
+    {
+        t=GetTicCount();
+        while (GetTicCount()==t) {}
+    }
+
+    MU_FadeIn (num,time>>1);
+}
+
+//***************************************************************************
+//
+// MU_FadeIn - Fade in
+//
+//***************************************************************************
+
+void MU_FadeIn ( int num, int time )
+{
+    if (MU_Started==false)
+        return;
+
+    MUSIC_SetVolume(0);
+    MU_PlaySong ( num );
+    MUSIC_FadeVolume (MUvolume, time);
+}
+
+//***************************************************************************
+//
+// MU_FadeOut - Fade out
+//
+//***************************************************************************
+
+void MU_FadeOut ( int time )
+{
+    if (MU_Started==false)
+        return;
+    if (!MUSIC_SongPlaying())
+    {
+#if (DEVELOPMENT == 1)
+        SoftError("Called FadeOut with no song playing\n");
+#endif
+        return;
+    }
+    MUSIC_FadeVolume(0,time);
+}
+
+
+//***************************************************************************
+//
+// MU_StartSong - Start a context sensitive song
+//
+//***************************************************************************
+
+void MU_StartSong ( int songtype )
+{
+    int songnum;
+
+    if (MU_Started==false)
+        return;
+
+    MU_StopSong();
+
+    songnum = MU_GetNumForType ( songtype );
+    switch (songtype)
+    {
+    case song_level:
+        if (IsChristmas())
+        {
+            songnum = MU_GetNumForType ( song_christmas );
+        }
+        else
+        {
+            songnum += GetSongForLevel ();
+        }
+        break;
+    }
+    MU_PlaySong (songnum);
+}
+
+//***************************************************************************
+//
+// MU_StoreSongPostition - Save off Song Position
+//
+//***************************************************************************
+
+void MU_StoreSongPosition ( void )
+{
+    if (MU_Started==false)
+        return;
+    PositionStored=true;
+    storedposition=MUSIC_GetPosition();
+}
+
+//***************************************************************************
+//
+// MU_RestoreSongPostition - Save off Song Position
+//
+//***************************************************************************
+
+void MU_RestoreSongPosition ( void )
+{
+    if (MU_Started==false)
+        return;
+    if (PositionStored==false)
+        return;
+    PositionStored=false;
+
+    MUSIC_SetPosition(storedposition);
+}
+
+//***************************************************************************
+//
+// MU_GetStoredPostition - Get Stored song Position
+//
+//***************************************************************************
+
+int MU_GetStoredPosition ( void )
+{
+    if (PositionStored)
+        return storedposition;
+    else
+        return -1;
+}
+
+//***************************************************************************
+//
+// MU_SetStoredPostition - Get Stored song Position
+//
+//***************************************************************************
+
+void MU_SetStoredPosition ( int position )
+{
+    if (MU_Started==false)
+        return;
+    if (position==-1)
+        return;
+    PositionStored=true;
+    storedposition=position;
+}
+
+
+
+//***************************************************************************
+//
+// MU_GetSongPostition - Get Song Position
+//
+//***************************************************************************
+
+int MU_GetSongPosition ( void )
+{
+    if (MU_Started==false)
+        return 0;
+    return MUSIC_GetPosition();
+}
+
+//***************************************************************************
+//
+// MU_SetSongPostition - Set Song Position
+//
+//***************************************************************************
+
+void MU_SetSongPosition ( int position )
+{
+    if (MU_Started==false)
+        return;
+    MUSIC_SetPosition(position);
+}
+
+//***************************************************************************
+//
+// MU_SaveMusic
+//
+//***************************************************************************
+
+void MU_SaveMusic (byte ** buf, int * size)
+{
+    int unitsize;
+    byte *ptr;
+    int vsize;
+    int i;
+
+    //
+    // Size
+    //
+
+    unitsize=0;
+
+    unitsize+=sizeof(i);
+    unitsize+=sizeof(i);
+    unitsize+=sizeof(i);
+
+
+    *size = unitsize;
+    *buf = (byte *) SafeMalloc (*size);
+
+    ptr = *buf;
+
+    i=MU_GetSongNumber();
+    if (rottsongs[i].songtype == song_menu)
+    {
+        i = MU_GetNumForType ( song_level );
+        if (IsChristmas())
+        {
+            i = MU_GetNumForType ( song_christmas );
+        }
+        else
+        {
+            i += GetSongForLevel ();
+        }
+        vsize=sizeof(i);
+        memcpy(ptr,&i,vsize);
+        ptr+=vsize;
+
+        i=MU_GetStoredPosition();
+        vsize=sizeof(i);
+        memcpy(ptr,&i,vsize);
+        ptr+=vsize;
+
+        i=-1;
+        vsize=sizeof(i);
+        memcpy(ptr,&i,vsize);
+        ptr+=vsize;
+    }
+    else
+    {
+        vsize=sizeof(i);
+        memcpy(ptr,&i,vsize);
+        ptr+=vsize;
+
+        i=MU_GetSongPosition();
+        vsize=sizeof(i);
+        memcpy(ptr,&i,vsize);
+        ptr+=vsize;
+
+        i=MU_GetStoredPosition();
+        vsize=sizeof(i);
+        memcpy(ptr,&i,vsize);
+        ptr+=vsize;
+    }
+}
+
+
+//***************************************************************************
+//
+// MU_LoadMusic
+//
+//***************************************************************************
+
+void MU_LoadMusic (byte * buf, int size)
+{
+    int unitsize;
+    byte *ptr;
+    int i;
+    int songnumber;
+    boolean differentsong=false;
+    int vsize;
+
+    //
+    // Size
+    //
+
+    unitsize=0;
+
+    unitsize+=sizeof(i);
+    unitsize+=sizeof(i);
+    unitsize+=sizeof(i);
+
+    if (size!=unitsize)
+        Error("LoadMusic: Different number of parameters\n");
+
+    ptr  = buf;
+
+    vsize=sizeof(songnumber);
+    memcpy(&songnumber,ptr,vsize);
+    ptr+=vsize;
+    if (MU_GetSongNumber () != songnumber)
+    {
+        MU_PlaySong(songnumber);
+        differentsong=true;
+    }
+
+    vsize=sizeof(i);
+    memcpy(&i,ptr,vsize);
+    ptr+=vsize;
+    if (differentsong==true)
+    {
+        MU_SetSongPosition(i);
+    }
+
+    vsize=sizeof(i);
+    memcpy(&i,ptr,vsize);
+    ptr+=vsize;
+    MU_SetStoredPosition(i);
+
+    // Check if game was saved with NOSOUND
+
+    if (MU_GetSongNumber () != songnumber)
+    {
+        MU_StartSong ( song_level );
+    }
+}
--- /dev/null
+++ b/rott/rt_sound.h
@@ -1,0 +1,689 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+#ifndef _rt_sound_public
+#define _rt_sound_public
+
+#include "music.h"
+#include "develop.h"
+
+typedef enum {
+
+//	MENU SOUNDS
+
+    SD_MENUFLIP,
+    SD_ESCPRESSEDSND,
+    SD_MOVECURSORSND,
+    SD_SELECTSND,
+    SD_WARNINGBOXSND,
+    SD_INFOBOXSND,
+    SD_QUESTIONBOXSND,
+    SD_NOPESND,
+    SD_QUIT1SND,
+    SD_QUIT2SND,
+    SD_QUIT3SND,
+    SD_QUIT4SND,
+    SD_QUIT5SND,
+    SD_QUIT6SND,
+    SD_QUIT7SND,
+
+
+//	GAME SOUNDS
+
+    SD_LEVELSTARTSND,
+    SD_LEVELDONESND,
+    SD_GAMEOVERSND,
+
+//	LEVEL END SCREEN
+
+    SD_ENDBONUS1SND,
+    SD_NOBONUSSND,
+    SD_PERCENT100SND,
+
+//	PLAYER SOUNDS
+
+    SD_HITWALLSND,
+    SD_SELECTWPNSND,
+    SD_NOWAYSND,
+    SD_DONOTHINGSND,
+    SD_NOITEMSND,
+    SD_PLAYERDYINGSND,
+
+    SD_PLAYERTCDEATHSND,
+    SD_PLAYERTBDEATHSND,
+    SD_PLAYERDWDEATHSND,
+    SD_PLAYERLNDEATHSND,
+    SD_PLAYERIPFDEATHSND,
+    SD_PLAYERTCHURTSND,
+    SD_PLAYERTBHURTSND,
+    SD_PLAYERDWHURTSND,
+    SD_PLAYERLNHURTSND,
+    SD_PLAYERIPFHURTSND,
+    SD_PLAYERTCSND,
+    SD_PLAYERTBSND,
+    SD_PLAYERDWSND,
+    SD_PLAYERLNSND,
+    SD_PLAYERIPFSND,
+//         SD_WALK1SND,
+//         SD_WALK2SND,
+    SD_PLAYERBURNEDSND,
+    SD_PLAYERLANDSND,
+    SD_PLAYERCOUGHMSND,
+    SD_PLAYERCOUGHFSND,
+    SD_NETWIGGLESND,
+    SD_NETFALLSND,
+
+//	PLAYER WEAPONS
+
+    SD_ATKPISTOLSND,
+    SD_ATKTWOPISTOLSND,
+    SD_ATKMP40SND,
+    SD_RICOCHET1SND,
+    SD_RICOCHET2SND,
+    SD_RICOCHET3SND,
+    SD_BAZOOKAFIRESND,
+    SD_FIREBOMBFIRESND,
+    SD_HEATSEEKFIRESND,
+    SD_DRUNKFIRESND,
+    SD_FLAMEWALLFIRESND,
+    SD_FLAMEWALLSND,
+    SD_SPLITFIRESND,
+    SD_SPLITSND,
+    SD_GRAVBUILDSND,
+    SD_GRAVFIRESND,
+    SD_GRAVSND,
+    SD_GRAVHITSND,
+    SD_FIREHITSND,
+    SD_MISSILEFLYSND,
+    SD_MISSILEHITSND,
+    SD_EXCALIBOUNCESND,
+    SD_EXCALISWINGSND,
+    SD_EXCALIHITSND,
+    SD_EXCALIBUILDSND,
+    SD_EXCALIBLASTSND,
+    SD_GODMODEFIRESND,
+    SD_GODMODE1SND,
+    SD_GODMODE2SND,
+    SD_GODMODE3SND,
+    SD_LOSEMODESND,
+    SD_DOGMODEPANTSND,
+    SD_DOGMODEBITE1SND,
+    SD_DOGMODEBITE2SND,
+    SD_DOGMODELICKSND,
+    SD_DOGMODEBLASTSND,
+    SD_DOGMODEPREPBLASTSND,
+    SD_DOGMANSND,
+    SD_DOGWOMANSND,
+    SD_GODMANSND,
+    SD_GODWOMANSND,
+    SD_FLYINGSND,
+
+//	PLAYER-CAUSED SOUNDS
+
+    SD_GLASSBREAKSND,
+    SD_ITEMBLOWSND,
+    SD_BONUSBARRELSND,
+    SD_TOUCHPLATESND,
+    SD_BADTOUCHSND,
+    SD_EXPLODEFLOORSND,
+    SD_EXPLODESND,
+    SD_GASSTARTSND,
+    SD_GASHISSSND,
+    SD_GASENDSND,
+    SD_GASMASKSND,
+
+//	GET ITEM SOUNDS
+
+    SD_GETKEYSND,
+    SD_GETBONUSSND,
+    SD_GETHEALTH1SND,
+    SD_GETHEALTH2SND,
+    SD_COOKHEALTHSND,
+
+    SD_GETWEAPONSND,
+    SD_GETKNIFESND,
+    SD_GETGODSND,
+    SD_GETDOGSND,
+    SD_GETFLEETSND,
+    SD_GETELASTSND,
+    SD_GETSHROOMSSND,
+    SD_GETBVESTSND,
+    SD_GETAVESTSND,
+    SD_GETMASKSND,
+    SD_GETBATSND,
+    SD_GETHEADSND,
+
+    SD_GET1UPSND,
+    SD_GET3UPSND,
+    SD_RESPAWNSND,
+    SD_PLAYERSPAWNSND,
+
+//	ACTOR SOUNDS
+
+    SD_LOWGUARD1SEESND,
+    SD_LOWGUARD1ASEESND,
+    SD_LOWGUARD1SEE3SND,
+    SD_LOWGUARD2SEESND,
+    SD_LOWGUARD2ASEESND,
+    SD_LOWGUARD2SEE3SND,
+    SD_LOWGUARDFIRESND,
+    SD_LOWGUARDOUCHSND,
+    SD_LOWGUARD1DIESND,
+    SD_LOWGUARD2DIESND,
+    SD_SNEAKYSPRINGMSND,
+    SD_SNEAKYSPRINGFSND,
+
+    SD_HIGHGUARD1SEESND,
+    SD_HIGHGUARD2SEESND,
+    SD_HIGHGUARDFIRESND,
+    SD_HIGHGUARDOUCHSND,
+    SD_HIGHGUARDDIESND,
+
+    SD_OVERP1SEESND,
+    SD_OVERP2SEESND,
+    SD_OVERPFIRESND,
+    SD_OVERPNETSND,
+    SD_OVERPOUCHSND,
+    SD_OVERPDIESND,
+
+    SD_STRIKE1SEESND,
+    SD_STRIKE2SEESND,
+    SD_STRIKEFIRESND,
+    SD_STRIKEROLLSND,
+    SD_STRIKEOUCHSND,
+    SD_STRIKEDIESND,
+
+    SD_BLITZ1SEESND,
+    SD_BLITZ2SEESND,
+    SD_BLITZFIRESND,
+    SD_BLITZSTEALSND,
+    SD_BLITZOUCHSND,
+    SD_BLITZDIESND,
+    SD_BLITZPLEADSND,
+    SD_BLITZPLEAD1SND,
+    SD_BLITZPLEAD2SND,
+
+    SD_ENFORCERSEESND,
+    SD_ENFORCERFIRESND,
+    SD_ENFORCERTHROWSND,
+    SD_ENFORCEROUCHSND,
+    SD_ENFORCERDIESND,
+
+    SD_MONKSEESND,
+    SD_MONKGRABSND,
+    SD_MONKOUCHSND,
+    SD_MONKDIESND,
+
+    SD_FIREMONKSEESND,
+    SD_FIREMONKFIRESND,
+    SD_FIREMONKOUCHSND,
+    SD_FIREMONKDIESND,
+
+    SD_ROBOTSEESND,
+    SD_ROBOTFIRESND,
+    SD_ROBOTDIESND,
+    SD_ROBOTMOVESND,
+
+    SD_BALLISTIKRAFTSEESND,
+    SD_BALLISTIKRAFTFIRESND,
+
+    SD_DARIANSEESND,
+    SD_DARIANFIRESND,
+    SD_DARIANGONNAUSESND,
+    SD_DARIANUSESND,
+    SD_DARIANHIDESND,
+    SD_DARIANDIESND,
+    SD_DARIANSAY1,
+    SD_DARIANSAY2,
+    SD_DARIANSAY3,
+
+    SD_KRISTSEESND,
+    SD_KRISTFIRESND,
+    SD_KRISTMOTORSND,
+    SD_KRISTTURNSND,
+    SD_KRISTDROPSND,
+    SD_KRISTMINEBEEPSND,
+    SD_KRISTMINEHITSND,
+    SD_KRISTDIESND,
+    SD_KRISTSAY1,
+    SD_KRISTSAY2,
+    SD_KRISTSAY3,
+
+    SD_NMESEESND,
+    SD_NMEREADYSND,
+    SD_NMEFIRE1SND,
+    SD_NMEAPARTSND,
+    SD_NMEUFOSND,
+    SD_NMEDIESND,
+
+    SD_DARKMONKSEESND,
+    SD_DARKMONKFIRE1SND,
+    SD_DARKMONKFIRE2SND,
+    SD_DARKMONKFIRE3SND,
+    SD_DARKMONKFIRE4SND,
+    SD_DARKMONKRECHARGESND,
+    SD_DARKMONKFLOATSND,
+    SD_DARKMONKDIESND,
+    SD_DARKMONKSAY1,
+    SD_DARKMONKSAY2,
+    SD_DARKMONKSAY3,
+
+    SD_SNAKESEESND,
+    SD_SNAKEREADYSND,
+    SD_SNAKECHARGESND,
+    SD_SNAKEOUCHSND,
+    SD_SNAKEDIESND,
+    SD_SNAKESPITSND,
+    SD_SNAKESAY1,
+    SD_SNAKESAY2,
+    SD_SNAKESAY3,
+
+    SD_EMPLACEMENTSEESND,
+    SD_EMPLACEMENTFIRESND,
+    SD_BIGEMPLACEFIRESND,
+
+
+//	ENVIRONMENT SOUNDS
+
+    SD_OPENDOORSND,
+    SD_CLOSEDOORSND,
+    SD_DOORHITSND,
+    SD_FIRECHUTESND,
+    SD_FIREBALLSND,
+    SD_FIREBALLHITSND,
+    SD_BLADESPINSND,
+    SD_PUSHWALLSND,
+    SD_PUSHWALLHITSND,
+    SD_GOWALLSND,
+    SD_TURBOWALLSND,
+    SD_BOULDERHITSND,
+    SD_BOULDERROLLSND,
+    SD_BOULDERFALLSND,
+    SD_PITTRAPSND,
+    SD_FIREJETSND,
+    SD_ACTORSQUISHSND,
+    SD_ACTORBURNEDSND,
+    SD_ACTORSKELETONSND,
+
+    SD_SPEARSTABSND,
+    SD_CYLINDERMOVESND,
+    SD_ELEVATORONSND,
+    SD_ELEVATORENDSND,
+
+    SD_SPRINGBOARDSND,
+    SD_LIGHTNINGSND,
+    SD_WINDSND,
+    SD_WATERSND,
+    SD_BODYLANDSND,
+    SD_GIBSPLASHSND,
+    SD_ACTORLANDSND,
+
+//	SECRET SOUNDS
+
+    SD_DOPEFISHSND,
+    SD_YOUSUCKSND,
+
+    SD_SILLYMOVESND,
+    SD_SOUNDSELECTSND,
+    SD_SOUNDESCSND,
+
+//	REMOTE SOUNDS (shift number row)
+
+    SD_REMOTEM1SND,
+    SD_REMOTEM2SND,
+    SD_REMOTEM3SND,
+    SD_REMOTEM4SND,
+    SD_REMOTEM5SND,
+    SD_REMOTEM6SND,
+    SD_REMOTEM7SND,
+    SD_REMOTEM8SND,
+    SD_REMOTEM9SND,
+    SD_REMOTEM10SND,
+
+    SD_LASTSOUND,
+
+    MAXSOUNDS
+
+} game_sounds;
+
+
+typedef enum
+{
+// REMOTE SOUNDS (shift number row)
+
+    D_REMOTEM1SND,
+    D_REMOTEM2SND,
+    D_REMOTEM3SND,
+    D_REMOTEM4SND,
+    D_REMOTEM5SND,
+    D_REMOTEM6SND,
+    D_REMOTEM7SND,
+    D_REMOTEM8SND,
+    D_REMOTEM9SND,
+    D_REMOTEM10SND,
+} remotesounds;
+
+typedef enum {
+    MUSE_MENUFLIPSND,             // 0
+    MUSE_ESCPRESSEDSND,           // 1
+    MUSE_MOVECURSORSND,           // 2
+    MUSE_SELECTSND,               // 3
+    MUSE_WARNINGBOXSND,           // 4
+    MUSE_INFOBOXSND,              // 5
+    MUSE_QUESTIONBOXSND,          // 6
+    MUSE_NOPESND,                 // 7
+    MUSE_LEVELSTARTSND,           // 8
+    MUSE_LEVELENDSND,             // 9
+    MUSE_GAMEOVERSND,             // 10
+    MUSE_ENDBONUS1SND,            // 11
+    MUSE_ENDBONUS2SND,            // 12
+    MUSE_NOBONUSSND,              // 13
+    MUSE_PERCENT100SND,           // 14
+    MUSE_HITWALLSND,              // 15
+    MUSE_SELECTWPNSND,            // 16
+    MUSE_NOWAYSND,                // 17
+    MUSE_DONOTHINGSND,            // 18
+    MUSE_NOITEMSND,               // 19
+    MUSE_PLAYERDYINGSND,          // 20
+    MUSE_PLAYERDEATHSND,          // 21
+    MUSE_PLAYERHURTSND,           // 22
+    MUSE_PLAYERYESSND,            // 23
+    MUSE_WALK1SND,                // 24
+    MUSE_WALK2SND,                // 25
+    MUSE_PLAYERLANDSND,           // 26
+    MUSE_NETFALLSND,              // 27
+    MUSE_ATKKNIFESND,             // 28
+    MUSE_ATKPISTOLSND,            // 29
+    MUSE_ATKMP40SND,              // 30
+    MUSE_RICOCHETSND,             // 31
+    MUSE_MISSILEFIRESND,          // 32
+    MUSE_FLAMEWALLSND,            // 33
+    MUSE_MISSILEHITSND,           // 34
+    MUSE_WEAPONBUILDSND,          // 35
+    MUSE_STABBERSND,              // 36
+    MUSE_ENERGYFIRESND,           // 37
+    MUSE_GAINMODESND,             // 38
+    MUSE_LOSEMODESND,             // 39
+    MUSE_DOGLICKSND,              // 40
+    MUSE_DOGBITESND,              // 41
+    MUSE_GLASSBREAKSND,           // 42
+    MUSE_EXPLOSIONSND,            // 43
+    MUSE_TOUCHPLATESND,           // 44
+    MUSE_BADTOUCHSND,             // 45
+    MUSE_SWITCHSND,               // 46
+    MUSE_GETKEYSND,               // 47
+    MUSE_GETBONUSSND,             // 48
+    MUSE_GETHEALTHSND,            // 49
+    MUSE_GETWEAPONSND,            // 50
+    MUSE_GETMWEAPONSND,           // 51
+    MUSE_GETPOWERUPSND,           // 52
+    MUSE_GETPOWERDOWNSND,         // 53
+    MUSE_GETARMORSND,             // 54
+    MUSE_GETWEIRDSND,             // 55
+    MUSE_GETLIFESND,              // 56
+    MUSE_ACTORSEESND,             // 57
+    MUSE_ACTORFIRESND,            // 58
+    MUSE_ACTOROUCHSND,            // 59
+    MUSE_ACTORDIESND,             // 60
+    MUSE_ACTORTHROWSND,           // 61
+    MUSE_ACTORROLLSND,            // 62
+    MUSE_ACTORDOITSND,            // 63
+    MUSE_ACTORUSESND,             // 64
+    MUSE_BOSSSEESND,              // 65
+    MUSE_BOSSOUCHSND,             // 66
+    MUSE_BOSSDIESND,              // 67
+    MUSE_BOSSDOSND,               // 68
+    MUSE_BOSSBEEPSND,             // 69
+    MUSE_BOSSHEYSND,              // 70
+    MUSE_BOSSFIRESND,             // 71
+    MUSE_BOSSWARNSND,             // 72
+    MUSE_BOSSFIRE2SND,            // 73
+    MUSE_EMPFIRESND,              // 74
+    MUSE_OPENDOORSND,             // 75
+    MUSE_CLOSEDOORSND,            // 76
+    MUSE_SPINBLADESND,            // 77
+    MUSE_PUSHWALLSND,             // 78
+    MUSE_BOULDERSND,              // 79
+    MUSE_PITTRAPSND,              // 80
+    MUSE_FIREJETSND,              // 81
+    MUSE_ACTORSQUISHSND,          // 82
+    MUSE_CYLINDERHITSND,          // 83
+    MUSE_ELEVATORSND,             // 84
+    MUSE_SPRINGBOARDSND,          // 85
+    MUSE_LASTSOUND=-1
+} musesounds;
+
+#define NUMCARDS 6
+
+typedef enum {
+    fx_digital,
+    fx_muse
+} fxtypes;
+
+typedef enum {
+    ASS_UltraSound,
+    ASS_SoundBlaster,
+    ASS_SoundMan16,
+    ASS_PAS,
+    ASS_AWE32,
+    ASS_SoundScape,
+    ASS_WaveBlaster,
+    ASS_Adlib,
+    ASS_GeneralMidi,
+    ASS_SoundCanvas,
+    ASS_SoundSource,
+    ASS_TandySoundSource,
+    ASS_PCSpeaker,
+    ASS_Off
+} ASSTypes;
+
+
+extern int SD_Started;
+
+int SD_SetupFXCard ( int * numvoices, int * numbits, int * numchannels);
+int SD_Startup ( boolean bombonerror );
+int SD_Play ( int sndnum );
+void SD_Shutdown (void);
+
+int SD_PlayPositionedSound ( int sndnum, int px, int py, int x, int y );
+int SD_PlaySoundRTP        ( int sndnum, int x, int y );
+void SD_PanPositionedSound ( int handle, int px, int py, int x, int y );
+void SD_PanRTP ( int handle, int x, int y );
+void SD_SetPan ( int handle, int vol, int left, int right );
+int SD_Play3D ( int sndnum, int angle, int distance );
+int SD_PlayPitchedSound ( int sndnum, int volume, int pitch );
+void SD_SetSoundPitch ( int sndnum, int pitch );
+boolean SD_SoundOkay ( int sndnum );
+
+//***************************************************************************
+//
+// SD_WaitSound - wait until a sound has finished
+//
+//***************************************************************************
+void SD_WaitSound ( int handle );
+
+//***************************************************************************
+//
+// SD_StopSound
+//
+//***************************************************************************
+void  SD_StopSound ( int handle );
+
+//***************************************************************************
+//
+// SD_SoundActive
+//
+//***************************************************************************
+int SD_SoundActive ( int handle );
+
+//***************************************************************************
+//
+// SD_StopAllSounds
+//
+//***************************************************************************
+void  SD_StopAllSounds ( void );
+
+
+typedef enum {
+    song_gason,
+    song_bosssee,
+    song_bossdie,
+    song_endlevel,
+    song_dogend,
+    song_title,
+    song_apogee,
+    song_youwin,
+    song_level,
+    song_elevator,
+    song_secretmenu,
+    song_cinematic1,
+    song_cinematic2,
+    song_cinematic3,
+    song_gameover,
+    song_christmas,
+    song_snakechase,
+    song_menu
+} songtypes;
+
+
+
+void MU_Shutdown ( void );
+int MU_Startup ( boolean bombonerror );
+void MU_PlaySong ( int num );
+void MU_StopSong ( void );
+
+//***************************************************************************
+//
+// MU_Continue
+//
+//***************************************************************************
+#define MU_Continue() MUSIC_Continue()
+
+//***************************************************************************
+//
+// MU_Pause
+//
+//***************************************************************************
+#define MU_Pause() MUSIC_Pause()
+
+//***************************************************************************
+//
+// MU_GetVolume
+//
+//***************************************************************************
+#define MU_GetVolume() MUSIC_GetVolume()
+
+//***************************************************************************
+//
+// MU_SetVolume
+//
+//***************************************************************************
+#define MU_SetVolume(x) MUSIC_SetVolume(x)
+
+//***************************************************************************
+//
+// MU_SongPlaying
+//
+//***************************************************************************
+#define MU_SongPlaying() MUSIC_SongPlaying()
+
+//***************************************************************************
+//
+// MU_FadeVolume
+//
+//***************************************************************************
+#define MU_FadeVolume(v,m) MUSIC_FadeVolume(v,m)
+
+//***************************************************************************
+//
+// MU_FadeActive
+//
+//***************************************************************************
+#define MU_FadeActive() MUSIC_FadeActive()
+
+//***************************************************************************
+//
+// MU_StopFade
+//
+//***************************************************************************
+#define MU_StopFade() MUSIC_StopFade()
+
+
+//***************************************************************************
+//
+// MU_FadeIn
+//
+//***************************************************************************
+void MU_FadeIn ( int num, int time );
+
+//***************************************************************************
+//
+// MU_FadeOut
+//
+//***************************************************************************
+void MU_FadeOut ( int time );
+
+//***************************************************************************
+//
+// MU_FadeToSong
+//
+//***************************************************************************
+void MU_FadeToSong ( int num, int time );
+
+//***************************************************************************
+//
+// SD_PreCacheSoundGroup
+//
+//***************************************************************************
+void SD_PreCacheSoundGroup ( int lo, int hi );
+
+//***************************************************************************
+//
+// SD_PreCacheSound
+//
+//***************************************************************************
+
+void SD_PreCacheSound ( int num );
+
+void MU_StartSong ( int songtype );
+
+void MU_JukeBoxMenu( void );
+
+void MU_StoreSongPosition ( void );
+
+void MU_RestoreSongPosition ( void );
+
+int MU_GetSongPosition ( void );
+
+void MU_SetSongPosition ( int position );
+
+int MU_GetSongNumber ( void );
+
+int MU_GetNumForType ( int songtype );
+
+int MU_GetStoredPosition ( void );
+
+void MU_SetStoredPosition ( int position );
+
+void MU_LoadMusic (byte * buf, int size);
+
+void MU_SaveMusic (byte ** buf, int * size);
+
+boolean MusicStarted( void );
+#endif
--- /dev/null
+++ b/rott/rt_spbal.c
@@ -1,0 +1,507 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+#include "rt_def.h"
+#include "watcom.h"
+#include "splib.h"
+#include "rt_draw.h"
+#include "rt_playr.h"
+#include "isr.h"
+#include <stdlib.h>
+#include "rt_spbal.h"
+#include "_rt_spba.h"
+#include "sbconfig.h"
+#include "rt_main.h"
+#include "rt_map.h"
+
+#include "rt_debug.h"
+#include "rt_game.h"
+#include "rt_str.h"
+#include "rt_vid.h"
+#include "rt_playr.h"
+#include "rt_actor.h"
+#include "rt_main.h"
+#include "rt_util.h"
+#include "rt_draw.h"
+#include "rt_in.h"
+#include "z_zone.h"
+#include "rt_ted.h"
+#include "rt_view.h"
+#include "develop.h"
+#include "version.h"
+#include "scriplib.h"
+#include <stdlib.h>
+
+#ifdef DOS
+#include <conio.h>
+#include <io.h>
+#include <fcntl.h>
+#include <dos.h>
+#include <mem.h>
+#endif
+//MED
+#include "memcheck.h"
+
+#ifdef DOS
+/* This file and associated .h files and Spaceball libraries:
+   Copyright 1995 Spacetec IMC Corporation
+*/
+//static char c[]="Copyright 1995 Spacetec IMC Corporation";
+
+
+#define MSGN(x)    (((x)>0)?1:-1)
+#define MABS(x)    ((x<0)?(-x):(x))
+
+#define FF(n) FLOAT_TO_FIXED(n)
+
+#define MAX_WARPS 1  // maximum number of ranges in all warps in defaultWarps
+static WarpRange defaultWarps[][MAX_WARPS]= {
+    {{  0, 511, FF(0.00013)}},   // Tx
+    {{  0, 511, FF(0.0075 )}},   // Ty
+    {{  0, 511, FF(0.0005 )}},   // Tz
+    {{150, 511, FF(0.0075 )}},   // Rx
+    {{  0, 511, FF(0.15   )}}	   // Ry
+};
+
+#undef FF
+
+
+static WarpRecord defaultRecords[]= {
+    {"Tx",  defaultWarps[0], 1},
+    {"Ty",  defaultWarps[1], 1},
+    {"Tz",  defaultWarps[2], 1},
+    {"Rx",  defaultWarps[3], 1},
+    {"Ry",  defaultWarps[4], 1},
+};
+
+WarpRecord *WarpTx, *WarpTy, *WarpTz, *WarpRx, *WarpRy;
+
+static char *SpaceBallConfigName = "spwrott.cfg";
+static char *ApogeePath = "APOGEECD";
+
+#define    TURBO_LIMIT          1000000
+static int turbo_increment    = 500000,
+           turbo_count        = 0,
+           turboFire          = false;
+
+
+// sbbuttons mask: 00FE DCBA
+
+#define BUTTON_A    0x01
+#define BUTTON_B    0x02
+#define BUTTON_C    0x04
+#define BUTTON_D    0x08
+#define BUTTON_E    0x10
+#define BUTTON_F    0x20
+
+// All possible button assignment masks (with defaults)
+static
+short turboFireMask      = BUTTON_A,
+      attackMask         = BUTTON_B,
+      useMask            = BUTTON_C,
+      mapMask            = 0,
+      swapWeaponMask     = BUTTON_D,
+      singleAxisMask     = 0,
+      planarMask         = 0,
+      aimMask            = BUTTON_E,
+      pauseMask          = BUTTON_F;
+
+// Array exists just to make sure two tasks are not assigned to same button
+static short *masks[6]= {&turboFireMask,  &attackMask, &useMask,
+                         &swapWeaponMask, &aimMask,    &pauseMask
+                        };
+
+
+
+//******************************************************************************
+//
+// ShiftTowardZero ()
+//
+//******************************************************************************
+
+static short
+ShiftTowardZero(short n, short amount)
+{
+    if (MABS(n) >= amount)
+        return n-((n>0)?amount:-amount);
+    else
+        return 0;
+}
+
+
+//******************************************************************************
+//
+// SPW_SingleAxisFilter
+//
+//  Zeroes all but the largest (in absolute value) element in a RawPacket
+//
+//   returns: nothing
+//
+//******************************************************************************
+
+static void
+SPW_SingleAxisFilter(SpwRawData *p)
+{
+    short *array   = &(p->tx),  // hope the data are in contigous locations
+           *largest = array,
+            newabs, large, array_length = 6;
+
+    large = MABS( *array );
+    while (--array_length > 0) {
+        ++array;
+        newabs = MABS(*array);
+        if (newabs > large) {
+            *largest = 0;
+            large = newabs;
+            largest = array;
+        } else
+            *array = 0;
+    }
+
+} /* end of SPW_SingleAxisFilter */
+
+
+
+//******************************************************************************
+//
+// HandleSpaceBallMotion ()
+//
+//******************************************************************************
+
+static void HandleSpaceBallMotion (SpwRawData * npacket, int controlbuf[])
+{
+
+    int    strafeAngle;
+    short  tx, ty, tz, rx, ry;
+    long   sbtx, sbty, sbtz, sbrx, sbry;
+    static short ButtonState;
+
+    // If they are really cranking on it, limit them to one axis at a time
+    if ((MABS(npacket->tx) > 450) ||
+            (MABS(npacket->ty) > 450) ||
+            (MABS(npacket->tz) > 450) ||
+            (MABS(npacket->rx) > 450) ||
+            (MABS(npacket->ry) > 450)) SPW_SingleAxisFilter(npacket);
+
+    // Don't want to lose the low end that the sb null_region calc is losing
+    tx=ShiftTowardZero(npacket->tx,30);   // range now approximately +/- 0-480
+    ty=ShiftTowardZero(npacket->ty,30);   // range now approximately +/- 0-480
+    tz=ShiftTowardZero(npacket->tz,50);   // range now approximately +/- 0-460
+    rx=ShiftTowardZero(npacket->rx,60);   // range now approximately +/- 0-450
+    ry=ShiftTowardZero(npacket->ry,60);   // range now approximately +/- 0-450
+
+    sbtx = SbFxConfigWarp( WarpTx, tx );
+    sbty = SbFxConfigWarp( WarpTy, ty );
+    sbtz = SbFxConfigWarp( WarpTz, tz );
+    sbrx = SbFxConfigWarp( WarpRx, rx );
+    sbry = SbFxConfigWarp( WarpRy, ry );
+
+    strafeAngle = (player->angle - FINEANGLES/4)&(FINEANGLES-1);
+
+    // check for turboFire
+    if (turboFire)
+    {
+        if (MABS(turbo_count) > TURBO_LIMIT)
+            turbo_increment *= -1;
+        turbo_count += turbo_increment;
+        sbry += turbo_increment;
+    }
+
+    controlbuf[0] += -(FixedMul (sbtz, viewcos))+
+                     FixedMul (sbtx, costable[strafeAngle]);
+
+    controlbuf[1] +=  FixedMul (sbtz, viewsin) -
+                      FixedMul (sbtx, sintable[strafeAngle]);
+
+    controlbuf[2] += sbry;
+
+
+
+    // Handle looking up and down ^ flying
+
+    ButtonState=npacket->buttons.cur;
+
+    // should the user be running?
+    buttonpoll[bt_run] = true; //((MABS(tx)+MABS(tz)+MABS(ry)) > 320) ? true : false ;
+
+
+    // TY does flying if the user has acquired the ability to fly.
+    // Currently this is ^'ed with looking up and down
+    if (player->flags & FL_FLEET)
+    {
+        if (sbty != 0)
+        {
+            if (sbty > 0)
+                buttonpoll[bt_lookup  ] = true;
+            else
+                buttonpoll[bt_lookdown] = true;
+        }
+    }
+    else  // Lookup/down || aim up/down ?
+    {
+        if ( sbrx != 0 )
+        {
+            if (sbrx > 0)
+            {
+                if (ButtonState & aimMask)
+                    buttonpoll[bt_horizonup] = true;
+                else
+                    buttonpoll[bt_lookup] = true;
+            }
+            else
+            {
+                if (ButtonState & aimMask)
+                    buttonpoll[bt_horizondown] = true;
+                else
+                    buttonpoll[bt_lookdown] = true;
+            }
+        }
+    }
+
+
+}
+
+//******************************************************************************
+//
+// PollSpaceBall ()
+//
+//******************************************************************************
+
+void PollSpaceBall (void)
+{
+    SpwRawData rawpacket;
+    short buttonsChanged;
+    static short buttonState=0;
+    static int reusePacketNTimes=0;
+    static SpwRawData lastPacket;
+
+    memset(&rawpacket,0,sizeof(rawpacket));
+    if (SpwSimpleGet(0,&rawpacket))
+    {
+        lastPacket=rawpacket;
+        reusePacketNTimes=6;
+    }
+    else if (reusePacketNTimes > 0)
+    {
+        rawpacket=lastPacket;
+        --reusePacketNTimes;
+    }
+    else if (buttonState) // did not get a packet but a button is down
+        rawpacket.buttons.cur=lastPacket.buttons.cur;
+    else
+        return;
+
+
+    buttonsChanged=buttonState ^ rawpacket.buttons.cur;
+    buttonState=rawpacket.buttons.cur;
+
+    buttonpoll[bt_attack] = (turboFire = (buttonState & turboFireMask) ? true : false );
+
+    if (buttonState & mapMask)          DoMap(player->tilex,player->tiley);
+    if (buttonState & useMask)          buttonpoll[bt_use]        = true;
+    if (buttonState & attackMask)       buttonpoll[bt_attack]     = true;
+    if (buttonState & swapWeaponMask)   buttonpoll[bt_swapweapon] = true;
+    if (buttonState & singleAxisMask)   SPW_SingleAxisFilter(&rawpacket);
+    if (buttonState & planarMask)       rawpacket.ty=rawpacket.rz=rawpacket.rx=0;
+    if (buttonState & pauseMask)        PausePressed=true;
+    if (!PausePressed)                  HandleSpaceBallMotion(&rawpacket,controlbuf);
+}
+
+
+//******************************************************************************
+//
+// OpenSpaceBall ()
+//
+//******************************************************************************
+
+void OpenSpaceBall (void)
+{
+    int  btn;
+    char filename[ 128 ];
+
+    if (SpwSimpleOpen(0))
+    {
+        SpwRawData sp;
+
+        SpaceBallPresent = true;
+        printf("Test the Spaceball by moving the ball and/or pressing buttons.\n");
+        printf("Exit test by pressing any keyboard key...\n");
+        while(!kbhit())
+        {
+
+            if (SpwSimpleGet(0,&sp))
+                printf("\r# tx: %4d ty: %4d tz: %4d # rx: %4d ry: %4d rz: %4d # b:  %1c-%1c-%1c-%1c-%1c-%1c",
+                       sp.tx, sp.ty, sp.tz,
+                       sp.rx,  sp.ry,  sp.rz,
+                       sp.buttons.cur &  1 ? 'A':' ', sp.buttons.cur &  2 ? 'B':' ',
+                       sp.buttons.cur &  4 ? 'C':' ', sp.buttons.cur &  8 ? 'D':' ',
+                       sp.buttons.cur & 16 ? 'E':' ', sp.buttons.cur & 32 ? 'F':' ');
+        }
+
+        // Check for configuration file, set defaults if none
+
+        GetPathFromEnvironment( filename, ApogeePath, SpaceBallConfigName );
+
+        SbConfigParse(filename);
+
+        // Check for warp records
+        WarpTx = SbConfigGetWarpRange("Tx");
+        WarpTy = SbConfigGetWarpRange("Ty");
+        WarpTz = SbConfigGetWarpRange("Tz");
+        WarpRx = SbConfigGetWarpRange("Rx");
+        WarpRy = SbConfigGetWarpRange("Ry");
+
+        if(!WarpTx) WarpTx = &defaultRecords[0];
+        if(!WarpTy) WarpTy = &defaultRecords[1];
+        if(!WarpTz) WarpTz = &defaultRecords[2];
+        if(!WarpRx) WarpRx = &defaultRecords[3];
+        if(!WarpRy) WarpRy = &defaultRecords[4];
+
+        // Check for button assignments
+        if((btn=SbConfigGetButtonNumber("TURBO_FIRE"))!=-1)
+        {
+            if (masks[btn])
+                *(masks[btn]) = 0; // zero out mask previously assigned to button
+            masks[btn]= &turboFireMask;
+            turboFireMask=(short)(1<<btn);
+        }
+
+        if((btn=SbConfigGetButtonNumber("ATTACK"))!=-1)
+        {
+            if (masks[btn])
+                *masks[btn] = 0; // zero out mask previously assigned to button
+            masks[btn]= &attackMask;
+            attackMask=(short)(1<<btn);
+        }
+
+        if((btn=SbConfigGetButtonNumber("USE"))!=-1)
+        {
+            if (masks[btn])
+                *masks[btn] = 0; // zero out mask previously assigned to button
+            masks[btn]= &useMask;
+            useMask=(short)(1<<btn);
+        }
+
+        if((btn=SbConfigGetButtonNumber("MAP"))!=-1)
+        {
+            if (masks[btn])
+                *masks[btn] = 0; // zero out mask previously assigned to button
+            masks[btn]= &mapMask;
+            mapMask=(short)(1<<btn);
+        }
+
+        if((btn=SbConfigGetButtonNumber("SWAP_WEAPON"))!=-1)
+        {
+            if (masks[btn])
+                *masks[btn] = 0; // zero out mask previously assigned to button
+            masks[btn]= &swapWeaponMask;
+            swapWeaponMask=(short)(1<<btn);
+        }
+
+        if((btn=SbConfigGetButtonNumber("SINGLE_AXIS_FILTER"))!=-1)
+        {
+            if (masks[btn])
+                *masks[btn] = 0; // zero out mask previously assigned to button
+            masks[btn]= &singleAxisMask;
+            singleAxisMask=(short)(1<<btn);
+        }
+
+        if((btn=SbConfigGetButtonNumber("PLANAR_FILTER"))!=-1)
+        {
+            if (masks[btn])
+                *masks[btn] = 0; // zero out mask previously assigned to button
+            masks[btn]= &planarMask;
+            planarMask=(short)(1<<btn);
+        }
+
+        if((btn=SbConfigGetButtonNumber("AIM"))!=-1)
+        {
+            if (masks[btn])
+                *masks[btn] = 0; // zero out mask previously assigned to button
+            masks[btn]= &aimMask;
+            aimMask=(short)(1<<btn);
+        }
+
+        if((btn=SbConfigGetButtonNumber("PAUSE"))!=-1)
+        {
+            if (masks[btn])
+                *masks[btn] = 0; // zero out mask previously assigned to button
+            masks[btn]= &pauseMask;
+            pauseMask=(short)(1<<btn);
+        }
+    }
+    else
+    {
+        SpaceBallPresent = false;
+    }
+}
+
+//******************************************************************************
+//
+// CloseSpaceBall ()
+//
+//******************************************************************************
+
+void CloseSpaceBall (void)
+{
+    if (SpaceBallPresent)
+    {
+        SpwSimpleClose(0);
+    }
+}
+
+//******************************************************************************
+//
+// GetSpaceBallButtons ()
+//
+//******************************************************************************
+
+unsigned GetSpaceBallButtons (void)
+{
+    SpwRawData sp;
+
+    return ((SpwSimpleGet(0,&sp) & SPW_BUTTON_DOWN));
+}
+
+#else
+
+/* This isn't of much use in Linux. */
+
+void PollSpaceBall (void)
+{
+    STUB_FUNCTION;
+}
+
+void OpenSpaceBall (void)
+{
+    STUB_FUNCTION;
+}
+
+void CloseSpaceBall (void)
+{
+}
+
+unsigned GetSpaceBallButtons (void)
+{
+    STUB_FUNCTION;
+
+    return 0;
+}
+
+#endif
--- /dev/null
+++ b/rott/rt_spbal.h
@@ -1,0 +1,34 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+//***************************************************************************
+//
+//   RT_spbal.h - SpaceBall stuff
+//
+//***************************************************************************
+
+#ifndef _rt_spbal_public
+#define _rt_spbal_public
+
+
+unsigned GetSpaceBallButtons (void);
+void OpenSpaceBall (void);
+void CloseSpaceBall (void);
+void PollSpaceBall (void);
+#endif
--- /dev/null
+++ b/rott/rt_sqrt.c
@@ -1,0 +1,82 @@
+#include "rt_def.h"
+
+#include "rt_sqrt.h"
+
+/*
+  C version of fixed-point Square Root functions
+ */
+
+long FixedSqrtLP(long n)  // Low  Precision (8.8)
+{
+    /*
+       Not used, so unimplemented.
+       If it matters, just copy the first half of the HP version,
+       and multiply the answer by 256.
+     */
+    STUB_FUNCTION;
+
+    return 0;
+}
+
+long FixedSqrtHP(long n)  // High Precision (8.16)
+{
+    /* This is more or less a direct C transliteration of the asm code.
+       I've replaced right shifting with division, since right shifting
+       signed values is undefined in ANSI C (though it usually works).
+       ROTT does not use this routine heavily. */
+    unsigned long root, mask, val;
+    signed long d;
+
+    root = 0;
+    mask = 0x40000000;
+    val = (unsigned long)n;
+hp1:
+    d = val;
+    d -= mask;
+    if (d < 0)
+        goto hp2;
+    d -= root;
+    if (d < 0)
+        goto hp2;
+
+    val = d;
+    root /= 2;
+    root |= mask;
+    mask /= 4;
+    if (mask != 0)
+        goto hp1;
+    else
+        goto hp5;
+hp2:
+    root /= 2;
+    mask /= 4;
+    if (mask != 0)
+        goto hp1;
+
+hp5:
+    mask = 0x00004000;
+    root <<= 16;
+    val <<= 16;
+hp3:
+    /* use add here to properly emulate the asm - SBF */
+    if ((root+mask) > val)
+        goto hp4;
+
+    val -= (root+mask);
+
+    root /= 2;
+    root |= mask;
+    mask /= 4;
+    if (mask != 0)
+        goto hp3;
+    else
+        goto hp6;
+hp4:
+    root /= 2;
+    mask /= 4;
+    if (mask != 0)
+        goto hp3;
+hp6:
+
+    return (long)root;
+}
--- /dev/null
+++ b/rott/rt_sqrt.h
@@ -1,0 +1,109 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+#ifndef _rt_sqrt_public
+#define _rt_sqrt_public
+
+/*
+FUNCTION:
+    Fixed32 FixedSqrtHP(Fixed32 n);
+DESCRIPTION:
+    This does a high-precision square root of a Fixed32.  It has
+    8.16 bit accuracy.  For more speed use FixedSqrtLP().
+
+
+FUNCTION:
+    Fixed32 FixedSqrtLP(Fixed32 n);
+DESCRIPTION:
+    This does a low-precision square root of a Fixed32.  It has
+    8.8 bit accuracy.  For more accuracy use FixedSqrtHP().
+*/
+
+
+
+long FixedSqrtLP(long n);  // Low  Precision (8.8)
+long FixedSqrtHP(long n);  // High Precision (8.16)
+
+#ifdef __WATCOMC__
+#pragma aux FixedSqrtLP =            \
+    "         xor eax, eax"          \
+    "         mov ebx, 40000000h"    \
+    "sqrtLP1: mov edx, ecx"          \
+    "         sub edx, ebx"          \
+    "         jl  sqrtLP2"           \
+    "         sub edx, eax"          \
+    "         jl  sqrtLP2"           \
+    "         mov ecx,edx"           \
+    "         shr eax, 1"            \
+    "         or  eax, ebx"          \
+    "         shr ebx, 2"            \
+    "         jnz sqrtLP1"           \
+    "         shl eax, 8"            \
+    "         jmp sqrtLP3"           \
+    "sqrtLP2: shr eax, 1"            \
+    "         shr ebx, 2"            \
+    "         jnz sqrtLP1"           \
+    "         shl eax, 8"            \
+    "sqrtLP3: nop"                   \
+    parm caller [ecx]                \
+    value [eax]                      \
+    modify [eax ebx ecx edx];
+
+
+#pragma aux FixedSqrtHP =            \
+    "         xor eax, eax"          \
+    "         mov ebx, 40000000h"    \
+    "sqrtHP1: mov edx, ecx"          \
+    "         sub edx, ebx"          \
+    "         jb  sqrtHP2"           \
+    "         sub edx, eax"          \
+    "         jb  sqrtHP2"           \
+    "         mov ecx,edx"           \
+    "         shr eax, 1"            \
+    "         or  eax, ebx"          \
+    "         shr ebx, 2"            \
+    "         jnz sqrtHP1"           \
+    "         jz  sqrtHP5"           \
+    "sqrtHP2: shr eax, 1"            \
+    "         shr ebx, 2"            \
+    "         jnz sqrtHP1"           \
+    "sqrtHP5: mov ebx, 00004000h"    \
+    "         shl eax, 16"           \
+    "         shl ecx, 16"           \
+    "sqrtHP3: mov edx, ecx"          \
+    "         sub edx, ebx"          \
+    "         jb  sqrtHP4"           \
+    "         sub edx, eax"          \
+    "         jb  sqrtHP4"           \
+    "         mov ecx, edx"          \
+    "         shr eax, 1"            \
+    "         or  eax, ebx"          \
+    "         shr ebx, 2"            \
+    "         jnz sqrtHP3"           \
+    "         jmp sqrtHP6"           \
+    "sqrtHP4: shr eax, 1"            \
+    "         shr ebx, 2"            \
+    "         jnz sqrtHP3"           \
+    "sqrtHP6: nop"                   \
+    parm caller [ecx]                \
+    value [eax]                      \
+    modify [eax ebx ecx edx];
+#endif
+
+#endif
--- /dev/null
+++ b/rott/rt_stat.c
@@ -1,0 +1,1940 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+
+#include "rt_def.h"
+
+#ifdef DOS
+#include <malloc.h>
+#include <dos.h>
+#endif
+
+#include <string.h>
+#include "sprites.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include "rt_stat.h"
+#include "z_zone.h"
+#include "lumpy.h"
+#include "rt_util.h"
+#include "rt_draw.h"
+#include "rt_ted.h"
+#include "rt_door.h"
+#include "rt_main.h"
+#include "w_wad.h"
+#include "rt_main.h"
+#include "rt_rand.h"
+#include "rt_menu.h"
+#include "rt_sound.h"
+#include "_rt_stat.h"
+#include "rt_net.h"
+#include "rt_view.h"
+#include "isr.h"
+//MED
+#include "memcheck.h"
+
+
+
+/*
+=============================================================================
+
+Global Variables                                                                                                                                 GLOBAL VARIABLES
+
+=============================================================================
+*/
+
+statobj_t   *firstactivestat,*lastactivestat;
+statobj_t   *firstemptystat,*lastemptystat;
+
+wall_t      switches[MAXSWITCHES],*lastswitch;
+respawn_t   *firstrespawn,*lastrespawn;
+statobj_t	*FIRSTSTAT,*LASTSTAT,*sprites[MAPSIZE][MAPSIZE];
+animwall_t  animwalls[MAXANIMWALLS];
+
+dirtype opposite[9] =
+{west,southwest,south,southeast,east,northeast,north,northwest,nodir};
+
+
+
+
+
+
+statinfo stats[NUMSTATS] =
+{
+    {0,SPR0_YLIGHT, stat_ylight,FL_LIGHT|FL_SHOOTABLE,0,0,2,0,0},
+    {0,SPR1_RLIGHT, stat_rlight,FL_LIGHT|FL_SHOOTABLE,0,0,2,0,0},
+    {0,SPR2_GLIGHT, stat_glight,FL_LIGHT|FL_SHOOTABLE,0,0,2,0,0},
+    {0,SPR3_BLIGHT, stat_blight,FL_LIGHT|FL_SHOOTABLE,0,0,2,0,0},
+    {0,SPR4_CHAND, stat_chandelier,FL_LIGHT|FL_SHOOTABLE,0,0,2,0,0},
+    {0,SPR5_LAMPOFF, stat_lamp,FL_LIGHT|FL_BLOCK|FL_SHOOTABLE,0,0,2,0,0},
+    {0,SPR73_GKEY1, stat_pedgoldkey,FL_COLORED|FL_BONUS|FL_CHANGES|FL_BLOCK|FL_ACTIVE,2,16,pc_orange,0,0},
+    {0,SPR73_GKEY1,stat_pedsilverkey,FL_COLORED|FL_BONUS|FL_CHANGES|FL_BLOCK|FL_ACTIVE,2,16,pc_gray,0,0},
+    {0,SPR73_GKEY1, stat_pedironkey,FL_COLORED|FL_BONUS|FL_CHANGES|FL_BLOCK|FL_ACTIVE,2,16,pc_olive,0,0},
+    {0,SPR73_GKEY1,stat_pedcrystalkey,FL_COLORED|FL_BONUS|FL_CHANGES|FL_BLOCK|FL_ACTIVE,2,16,pc_red,0,0},
+    {0,SPR6_GIBS1,  stat_gibs1,0,0,0,0,0,0},
+    {0,SPR7_GIBS2,  stat_gibs2,0,0,0,0,0,0},
+    {0,SPR8_GIBS3,  stat_gibs3,0,0,0,0,0,0},
+    {0,SPR9_MONKMEAL, stat_monkmeal,FL_BONUS|FL_RESPAWN,0,0,0,0,0},
+    {0,PORRIDGE1, stat_priestporridge,FL_BONUS|FL_RESPAWN,2,6,0,0,0},
+    {0,MONKCRYSTAL11,stat_monkcrystal1,FL_BONUS|FL_ACTIVE|FL_RESPAWN,2,6,0,0,0},
+    {0,MONKCRYSTAL21,stat_monkcrystal2,FL_BONUS|FL_ACTIVE|FL_RESPAWN,2,7,0,0,0},
+    {0,ONEUP01,stat_oneup,FL_BONUS|FL_ACTIVE|FL_FULLLIGHT,2,8,0,0,0},
+    {0,THREEUP01,stat_threeup,FL_BONUS|FL_ACTIVE|FL_FULLLIGHT,2,8,0,0,0},
+    {0,TORCH1,stat_altbrazier1,FL_HEAT|FL_BLOCK|FL_ACTIVE|FL_LIGHT|FL_SHOOTABLE,2,15,2,0,0},
+    {0,SPR_ABRAZIER2,stat_altbrazier2,FL_HEAT|FL_BLOCK|FL_LIGHT|FL_SHOOTABLE,0,0,2,0,0},
+    {0,FBASIN1,stat_healingbasin,FL_BONUS|FL_CHANGES|FL_ACTIVE|FL_BLOCK,2,3,0,0,0},
+    {20,EBASIN,stat_emptybasin,FL_BLOCK|FL_SHOOTABLE,0,0,0,0,0},
+    {0,BAT1,stat_bat,FL_BONUS|FL_ACTIVE|FL_RESPAWN|FL_WEAPON,1,16,0,0,10},
+    {0,KNIFE_STATUE1,stat_knifestatue,FL_BONUS|FL_CHANGES|FL_BLOCK,0,0,0,0,0},
+    {0,SPR_TWOPIST,stat_twopistol,FL_BONUS|FL_RESPAWN|FL_WEAPON,0,0,0,0,5},
+    {0,SPR_MP40,stat_mp40,FL_BONUS|FL_RESPAWN|FL_WEAPON,0,0,0,0,5},
+    {0,SPR_BAZOOKA,stat_bazooka,FL_BONUS|FL_RESPAWN|FL_WEAPON,0,0,0,0,10},
+    {0,SPR_FIREBOMB,stat_firebomb,FL_BONUS|FL_RESPAWN|FL_WEAPON,0,0,0,0,5},
+    {0,SPR_HEATSEEK,stat_heatseeker,FL_BONUS|FL_RESPAWN|FL_WEAPON,0,0,0,0,7},
+    {0,SPR_DRUNK,stat_drunkmissile,FL_BONUS|FL_RESPAWN|FL_WEAPON,0,0,0,0,7},
+    {0,SPR_FIREWALL,stat_firewall,FL_BONUS|FL_RESPAWN|FL_WEAPON,0,0,0,0,5},
+    {0,SPR_SPLIT,stat_splitmissile,FL_BONUS|FL_RESPAWN|FL_WEAPON,0,0,0,0,7},
+    {0,SPR_KES,stat_kes,FL_BONUS|FL_RESPAWN|FL_WEAPON,0,0,0,0,7},
+    {0,LIFEITEMA01,stat_lifeitem1,FL_BONUS|FL_ACTIVE|FL_SHOOTABLE|FL_FULLLIGHT,2,8, 2,0,0},
+    {0,LIFEITEMB01,stat_lifeitem2,FL_BONUS|FL_ACTIVE|FL_SHOOTABLE|FL_FULLLIGHT,2,8, 2,0,0},
+    {0,LIFEITEMD01,stat_lifeitem3,FL_BONUS|FL_ACTIVE|FL_SHOOTABLE|FL_FULLLIGHT,2,8, 2,0,0},
+    {0,LIFEITEMC01,stat_lifeitem4,FL_BONUS|FL_ACTIVE|FL_SHOOTABLE|FL_FULLLIGHT,2,15, 2,0,0},
+    {24,SPR32_EXPLOS,stat_tntcrate,FL_SHOOTABLE|FL_BLOCK|FL_WOODEN,0,0,3,10,0},
+    {12,SPR33_CBARREL,stat_bonusbarrel,FL_METALLIC|FL_SHOOTABLE|FL_BLOCK,0,0,3,10,0},
+    {0,TORCH1,stat_torch,FL_BLOCK|FL_LIGHT|FL_ACTIVE|FL_HEAT|FL_SHOOTABLE,2,15,2,0,0},
+    {30,FFLAME1,stat_floorfire,FL_HEAT|FL_BLOCK|FL_LIGHT|FL_ACTIVE|FL_SHOOTABLE,2,7,30,0,0},
+    {0,DIP11,stat_dipball1,FL_BONUS|FL_FULLLIGHT,0,0,0,0,0},
+    {0,DIP21,stat_dipball2,FL_BONUS|FL_FULLLIGHT,0,0,0,0,0},
+    {0,DIP31,stat_dipball3,FL_BONUS|FL_FULLLIGHT,0,0,0,0,0},
+    {0,SPR34_TOUCH1,stat_touch1,0|FL_TRANSLUCENT|FL_FADING,0,0,0,0,0},
+    {0,SPR35_TOUCH2,stat_touch2,0|FL_TRANSLUCENT|FL_FADING,0,0,0,0,0},
+    {0,SPR36_TOUCH3,stat_touch3,0|FL_TRANSLUCENT|FL_FADING,0,0,0,0,0},
+    {0,SPR37_TOUCH4,stat_touch4,0|FL_TRANSLUCENT|FL_FADING,0,0,0,0,0},
+    {20,SPR62_ETOUCH1,stat_dariantouch,FL_METALLIC|FL_BANDF|FL_SHOOTABLE|FL_BLOCK,10,3,50,0,0},
+    {0,SCOTHEAD1, stat_scotthead,FL_BONUS|FL_ACTIVE|FL_FULLLIGHT,4,7,0,0,0},
+    {0,SPR38_GARBAGE1,stat_garb1,0,0,0,0,0,0},
+    {0,SPR39_GARBAGE2,stat_garb2,0,0,0,0,0,0},
+    {0,SPR40_GARBAGE3,stat_garb3,0,0,0,0,0,0},
+    {0,SPR41_SHIT,stat_shit,0,0,0,0,0,0},
+    {0,SPR42_GRATE,stat_grate,0,0,0,0,0,0},
+    {0,SPR43_MSHARDS,stat_metalshards,0,0,0,0,0,0},
+    {20,SPR44_PEDESTAL,stat_emptypedestal,FL_BLOCK|FL_SHOOTABLE|FL_WOODEN,0,0,60,0,0},
+    {20,SPR45_ETABLE,stat_emptytable,FL_BLOCK|FL_SHOOTABLE|FL_WOODEN,0,0,100,0,0},
+    {16,SPR46_STOOL,stat_stool,FL_BLOCK|FL_SHOOTABLE|FL_WOODEN,0,0,25,0,0},
+    {0,SPR_PUSHCOLUMN1,stat_bcolumn,FL_BLOCK|FL_HEIGHTFLIPPABLE,0,0,0,0,0},
+    {0,SPR_PUSHCOLUMN1,stat_gcolumn,FL_BLOCK|FL_HEIGHTFLIPPABLE,0,0,0,0,0},
+    {0,SPR_PUSHCOLUMN1,stat_icolumn,FL_BLOCK|FL_HEIGHTFLIPPABLE,0,0,0,0,0},
+    {20,SPR50_TREE,stat_tree,FL_SHOOTABLE|FL_BLOCK,0,0,0,0,0},
+    {20,SPR51_PLANT,stat_plant,FL_SHOOTABLE|FL_BLOCK,0,0,0,0,0},
+    {20,BLUEVASE,stat_urn,FL_SHOOTABLE|FL_BLOCK,0,0,0,0,0},
+    {0,SPR54_HAY,stat_haystack,FL_SHOOTABLE|FL_BLOCK,0,0,20,0,0},
+    {12,SPR55_IBARREL,stat_ironbarrel,FL_METALLIC|FL_BLOCK|FL_SHOOTABLE,0,0,50,0,0},
+    {0,HGRATE1,stat_heatgrate,FL_LIGHT|FL_ACTIVE,2,4,0,5,0},
+    {-10,STNPOLE1,stat_standardpole,FL_SHOOTABLE|FL_BLOCK,0,0,25,0,0},
+    {0,PREPIT,stat_pit,FL_CHANGES,0,0,0,0,0},
+    {0,GODPOWERUP1,stat_godmode,FL_WEAPON|FL_BONUS|FL_ACTIVE|FL_RESPAWN|FL_FULLLIGHT,2,8,0,0,0},
+    {0,DOGPOWERUP1,stat_dogmode,FL_WEAPON|FL_BONUS|FL_ACTIVE|FL_RESPAWN|FL_FULLLIGHT,2,8,0,0,0},
+    {0,FLEETFEETPOWERUP1,stat_fleetfeet,FL_BONUS|FL_ACTIVE|FL_RESPAWN|FL_FULLLIGHT,2,8,0,0,0},
+    {0,ELASTICPOWERUP1, stat_elastic, FL_BONUS|FL_ACTIVE|FL_RESPAWN|FL_FULLLIGHT,2,8,0,0,0},
+    {0,MUSHROOMPOWERUP1, stat_mushroom, FL_BONUS|FL_ACTIVE|FL_RESPAWN|FL_FULLLIGHT,2,8,0,0,0},
+    {0,GASMASKPOWERUP, stat_gasmask, FL_BONUS|FL_RESPAWN,0,0,0,0,0},
+    {0,BULLETPROOFPOWERUP, stat_bulletproof, FL_BONUS|FL_RESPAWN,0,0,0,0,0},
+    {0,ASBESTOSPOWERUP, stat_asbesto, FL_BONUS|FL_RESPAWN,0,0,0,0,0},
+    {0,RANDOMPOWERUP1, stat_random, FL_BONUS|FL_ACTIVE|FL_RESPAWN,2,8,0,0,0},
+    {0,RUBBLE1, stat_rubble, FL_ACTIVE,2,10,0,0,0},
+    {0,WOODFRAG1, stat_woodfrag, FL_ACTIVE,2,14,0,0,0},
+    {0,ROBOGRDDIE1, stat_metalfrag, FL_ACTIVE,2,10,0,0,0},
+    {0,EMPTY_STATUE1,stat_emptystatue,FL_BLOCK|FL_SHOOTABLE,0,0,50,0,0},
+    {16,TOMLARVA1,stat_tomlarva,FL_ACTIVE|FL_SHOOTABLE|FL_BLOCK,2,4,150,0,0},
+    {0,BULLETHOLE,stat_bullethole,FL_TRANSLUCENT,0,0,0,0,0},
+//MED
+#if (SHAREWARE == 1)
+    {0,COLLECTOR1,stat_collector,FL_ACTIVE|FL_BONUS,2,8,-1,0,0},
+#else
+    {0,DOPE1,stat_collector,FL_ACTIVE|FL_BONUS,2,8,-1,0,0},
+#endif
+    {0,SPR_MINE1,stat_mine,FL_BONUS|FL_SHOOTABLE|FL_RESPAWN,0,0,10,0,0},
+    {0,MISSMOKE1,stat_missmoke,FL_ACTIVE,6,4,0,0,0},
+    {0,PLATFORM1,stat_disk,FL_BLOCK|FL_HEIGHTFLIPPABLE,0,0,0,0,0},
+    {-1,0,0,0,0,0,0,0,0}
+};
+
+
+dirtype diagonal[9][9] =
+{
+    /* east */  {nodir,nodir,northeast,nodir,nodir,nodir,southeast,nodir,nodir},
+    {nodir,nodir,nodir,nodir,nodir,nodir,nodir,nodir,nodir},
+    /* north */ {northeast,nodir,nodir,nodir,northwest,nodir,nodir,nodir,nodir},
+    {nodir,nodir,nodir,nodir,nodir,nodir,nodir,nodir,nodir},
+    /* west */  {nodir,nodir,northwest,nodir,nodir,nodir,southwest,nodir,nodir},
+    {nodir,nodir,nodir,nodir,nodir,nodir,nodir,nodir,nodir},
+    /* south */ {southeast,nodir,nodir,nodir,southwest,nodir,nodir,nodir,nodir},
+    {nodir,nodir,nodir,nodir,nodir,nodir,nodir,nodir,nodir},
+    {nodir,nodir,nodir,nodir,nodir,nodir,nodir,nodir,nodir}
+};
+
+/*
+=============================================================================
+
+Local Variables                                                                                                                                 GLOBAL VARIABLES
+
+=============================================================================
+*/
+static awallinfo_t animwallsinfo[MAXANIMWALLS] =
+{   {3,4,"FPLACE1\0"}, //lava wall
+    {3,6,"ANIMY1\0"}, //anim red
+    {3,6,"ANIMR1\0"}, //anim yellow
+    {40,4,"ANIMFAC1\0"}, //anim face
+    {3,4,"ANIMONE1\0"}, //anim one
+    {3,4,"ANIMTWO1\0"}, //anim two
+    {3,4,"ANIMTHR1\0"}, //anim three
+    {3,4,"ANIMFOR1\0"}, //anim four
+    {3,6,"ANIMGW1\0"}, //anim grey water
+    {3,6,"ANIMYOU1\0"}, //anim you do not belong
+    {3,6,"ANIMBW1\0"}, //anim brown water
+    {3,6,"ANIMBP1\0"}, //anim brown piston
+    {3,6,"ANIMCHN1\0"}, //anim chain
+    {3,6,"ANIMFW1\0"}, //anim firewall
+    {3,6,"ANIMLAT1\0"}, //anim little blips
+    {3,6,"ANIMST1\0"}, //anim light streams left
+    {3,6,"ANIMRP1\0"}
+};//anim light streams right
+
+int statcount;
+
+void AddRespawnStatic(respawn_t*stat);
+void DoLights (int tilex, int tiley);
+
+void AddToFreeStaticList(statobj_t*stat)
+{   if (!firstemptystat)
+        firstemptystat = stat;
+    else
+    {   stat->statprev = lastemptystat;
+        lastemptystat->statnext = stat;
+    }
+    lastemptystat = stat;
+
+}
+
+
+void RemoveFromFreeStaticList(statobj_t*stat)
+{
+    if (stat == lastemptystat)
+        lastemptystat = stat->statprev;
+    else
+        stat->statnext->statprev = stat->statprev;
+
+    if (stat == firstemptystat)
+        firstemptystat = stat->statnext;
+    else
+        stat->statprev->statnext = stat->statnext;
+
+    stat->statprev = NULL;
+    stat->statnext = NULL;
+
+}
+
+
+
+
+/*
+===============
+=
+= MakeStatActive
+=
+===============
+*/
+
+void MakeStatActive(statobj_t*x)
+{   if (!firstactivestat)
+        firstactivestat	= x;
+    else
+    {   x->prevactive = lastactivestat;
+        lastactivestat->nextactive = x;
+    }
+    lastactivestat = x;
+}
+
+
+/*
+===============
+=
+= MakeStatInactive
+=
+===============
+*/
+
+void MakeStatInactive(statobj_t*stat)
+{
+    if (stat == lastactivestat)
+        lastactivestat = stat->prevactive;
+    else
+        stat->nextactive->prevactive = stat->prevactive;
+
+    if (stat == firstactivestat)
+        firstactivestat = stat->nextactive;
+    else
+        stat->prevactive->nextactive = stat->nextactive;
+
+    stat->prevactive = NULL;
+    stat->nextactive = NULL;
+
+}
+/*
+===============
+=
+= AddStatic
+=
+===============
+*/
+
+void AddStatic(statobj_t *stat)
+{   if (FIRSTSTAT)
+    {   stat->statprev = LASTSTAT;
+        LASTSTAT->statnext = stat;
+    }
+    else
+        FIRSTSTAT = stat;
+    LASTSTAT = stat;
+}
+
+
+
+void RemoveStatic(statobj_t*stat)
+{
+    if (stat->flags & FL_ABP) //remove from active list
+        MakeStatInactive(stat);
+
+    if (stat == LASTSTAT)     // remove from master list
+        LASTSTAT = stat->statprev;
+    else
+        stat->statnext->statprev = stat->statprev;
+
+    if (stat == FIRSTSTAT)
+        FIRSTSTAT = stat->statnext;
+    else
+        stat->statprev->statnext = stat->statnext;
+
+    stat->statprev = NULL;
+    stat->statnext = NULL;
+
+    if (stat->flags & FL_WEAPON)
+        MISCVARS->NUMWEAPONS --;
+
+    if ((stat->flags & FL_RESPAWN) &&
+            gamestate.BattleOptions.RespawnItems &&
+            (!((stat->flags & FL_WEAPON ) &&
+               (gamestate.BattleOptions.WeaponPersistence)
+              )
+            )
+       )
+    {
+        respawn_t*temp;
+        //    if ( !( (stat->flags & FL_WEAPON) &&
+        //          (MISCVARS->NUMWEAPONS >= (numplayers+10))
+        //      )
+        // )
+        {
+            temp = (respawn_t*)Z_LevelMalloc(sizeof(respawn_t),PU_LEVELSTRUCT,NULL);
+
+            memset (temp,0,sizeof(*temp));
+            temp->ticcount = GetRespawnTimeForItem(stat->itemnumber);
+            temp->tilex = stat->tilex;
+            temp->tiley = stat->tiley;
+            temp->itemnumber = stat->itemnumber;
+            temp->spawnz = stat->z;
+            temp->linked_to = stat->linked_to;
+            //SoftError("\nrespawn obj created for stattype %d with z = %d",stat->itemnumber,temp->spawnz);
+            AddRespawnStatic(temp);
+        }
+    }
+    //Z_Free(stat);
+    AddToFreeStaticList(stat);
+
+    //Add_To_Delete_Array(stat);
+    statcount --;
+}
+
+
+void RemoveRespawnStatic(respawn_t*stat)
+{
+    if (stat == lastrespawn)
+        lastrespawn = stat->prev;
+    else
+        stat->next->prev = stat->prev;
+
+    if (stat == firstrespawn)
+        firstrespawn = stat->next;
+    else
+        stat->prev->next = stat->next;
+
+    stat->prev = NULL;
+    stat->next = NULL;
+    Z_Free(stat);
+}
+
+
+void TurnOffLight(int tilex,int tiley)
+{
+    DoLights(tilex,tiley);
+    LightsInArea[MAPSPOT(tilex,tiley,0)-AREATILE]--;
+
+}
+
+
+void ActivateLight(long light)
+{   statobj_t*tstat;
+
+    tstat = (statobj_t*)light;
+
+    tstat->shapenum ++;
+    tstat->flags |= FL_LIGHTON;
+    TurnOnLight(tstat->tilex,tstat->tiley);
+
+}
+
+
+void DeactivateLight(long light)
+{   statobj_t*tstat;
+
+    tstat = (statobj_t*)light;
+
+    tstat->shapenum --;
+    tstat->flags &= ~(FL_LIGHTON);
+    TurnOffLight(tstat->tilex,tstat->tiley);
+
+}
+
+void TurnOnLight(int i,int j)
+{
+
+    LightsInArea[MAPSPOT(i,j,0)-AREATILE]++;
+
+    if (lightsource==0)
+        return;
+
+    if ((!(tilemap[i+1][j])) && (!(tilemap[i-1][j])))
+    {
+        SetLight(i,j,0xcdeffedc);
+        SetLight(i+1,j,0x135789ab);
+        SetLight(i-1,j,0xba987351);
+        SetLight(i,j+1,0xcdeffedc);
+        SetLight(i,j-1,0xcdeffedc);
+        SetLight(i-1,j-1,0xba987351);
+        SetLight(i+1,j+1,0xba987351);
+        SetLight(i+1,j-1,0x135789ab);
+        SetLight(i-1,j+1,0x135789ab);
+    }
+    else if ((!(tilemap[i][j+1])) && (!(tilemap[i][j-1])))
+    {
+        SetLight(i,j,0xcdeffedc);
+        SetLight(i+1,j,0xcdeffedc);
+        SetLight(i-1,j,0xcdeffedc);
+        SetLight(i,j+1,0x135789ab);
+        SetLight(i,j-1,0xba987531);
+        SetLight(i-1,j-1,0x135789ab);
+        SetLight(i+1,j-1,0xba987531);
+        SetLight(i+1,j+1,0x135789ab);
+        SetLight(i-1,j+1,0xba987531);
+    }
+    //  |
+    //__|
+    else if ((tilemap[i][j+1]) && (tilemap[i+1][j]))
+    {
+        SetLight(i,j,0xcdeffedc);
+        SetLight(i+1,j,0xcdeffedc);
+        SetLight(i-1,j,0xcdeffedc);
+        SetLight(i,j+1,0xcdeffedc);
+        SetLight(i,j-1,0xcdeffedc);
+        SetLight(i-1,j-1,0xba987351);
+        SetLight(i+1,j-1,0xba987351);
+        SetLight(i+1,j+1,0xba987351);
+        SetLight(i-1,j+1,0x135789ab);
+    }
+    //|
+    //|_
+    else if ((tilemap[i][j+1]) && (tilemap[i-1][j]))
+    {
+        SetLight(i,j,0xcdeffedc);
+        SetLight(i+1,j,0xcdeffedc);
+        SetLight(i-1,j,0xcdeffedc);
+        SetLight(i,j+1,0xcdeffedc);
+        SetLight(i,j-1,0xcdeffedc);
+        SetLight(i-1,j-1,0x135789ab);
+        SetLight(i+1,j-1,0xba987531);
+        SetLight(i+1,j+1,0xba987531);
+        SetLight(i-1,j+1,0xba987531);
+    }
+    //_
+    // |
+    else if ((tilemap[i][j-1]) && (tilemap[i+1][j]))
+    {
+        SetLight(i,j,0xcdeffedc);
+        SetLight(i+1,j,0xcdeffedc);
+        SetLight(i-1,j,0xcdeffedc);
+        SetLight(i,j+1,0xcdeffedc);
+        SetLight(i,j-1,0xcdeffedc);
+        SetLight(i-1,j-1,0xba987531);
+        SetLight(i+1,j-1,0x135789ab);
+        SetLight(i+1,j+1,0x135789ab);
+        SetLight(i-1,j+1,0xba987531);
+    }
+    //__
+    //|
+    else if ((tilemap[i][j-1]) && (tilemap[i-1][j]))
+    {
+        SetLight(i,j,0xcdeffedc);
+        SetLight(i+1,j,0xcdeffedc);
+        SetLight(i-1,j,0xcdeffedc);
+        SetLight(i,j+1,0xcdeffedc);
+        SetLight(i,j-1,0xcdeffedc);
+        SetLight(i-1,j-1,0x135789ab);
+        SetLight(i+1,j-1,0x135789ab);
+        SetLight(i+1,j+1,0xba987531);
+        SetLight(i-1,j+1,0xba987531);
+    }
+    else if (tilemap[i][j])
+    {
+        SetLight(i,j,0x58bffb85);
+    }
+    else
+    {
+        SetLight(i,j,0xcdeffedc);
+        SetLight(i+1,j,0xba987654);
+        SetLight(i-1,j,0x456789ab);
+        SetLight(i,j+1,0xba987654);
+        SetLight(i,j-1,0x456789ab);
+        SetLight(i-1,j+1,0x33322211);
+        SetLight(i+1,j+1,0x33322211);
+        SetLight(i+1,j-1,0x11222333);
+        SetLight(i-1,j-1,0x11222333);
+    }
+
+
+}
+
+
+
+
+/*===============
+=
+= AddRespawnStatic
+=
+===============
+*/
+
+void AddRespawnStatic(respawn_t*stat)
+{
+    if (firstrespawn)
+    {   stat->prev = lastrespawn;
+        lastrespawn->next = stat;
+    }
+    else
+        firstrespawn = stat;
+    lastrespawn = stat;
+}
+
+
+/*
+===============
+=
+= InitStaticList
+=
+===============
+*/
+
+void InitStaticList (void)
+{
+    FIRSTSTAT = NULL;
+    LASTSTAT = NULL;
+    lastactivestat = NULL;
+    firstactivestat = NULL;
+    firstrespawn = NULL;
+    lastrespawn = NULL;
+    lastemptystat = NULL;
+    firstemptystat = NULL;
+
+    memset(&BulletHoles[0],0,sizeof(BulletHoles));
+    MISCVARS->BulletHoleNum = 0;
+
+
+    memset(sprites,0,sizeof(sprites));
+    if (loadedgame==false)
+    {
+        memset(switches,0,sizeof(switches));
+        lastswitch = &switches[0];
+    }
+    statcount = 0;
+
+}
+
+
+/*
+===============
+=
+= InitAnimatedWallList
+=
+===============
+*/
+
+void InitAnimatedWallList(void)
+{
+    int i;
+
+    for (i=0; i<MAXANIMWALLS; i++)
+        animwalls[i].active=0;
+}
+
+/*
+===============
+=
+= SetupAnimatedWall
+=
+===============
+*/
+
+void SetupAnimatedWall(int which)
+{
+    animwall_t * aw;
+    int i;
+    int texture;
+
+    aw = &animwalls[which];
+
+    aw->active=1;
+    aw->ticcount=animwallsinfo[which].tictime;
+    aw->count = 1;
+
+    texture=W_GetNumForName(animwallsinfo[which].firstlump);
+
+    aw->basetexture=texture;
+    aw->texture=texture;
+
+    if (DoPanicMapping()==true)
+    {
+        PreCacheLump(aw->basetexture,PU_CACHEWALLS,cache_pic_t);
+    }
+    else
+    {
+        for (i=aw->basetexture; i<aw->basetexture+animwallsinfo[which].numanims; i++)
+            PreCacheLump(i,PU_CACHEWALLS,cache_pic_t);
+    }
+}
+
+
+/*
+===============
+=
+= SaveStatics
+=
+===============
+*/
+
+void SaveStatics (byte **buffer, int * size)
+{   statobj_t * temp;
+    saved_stat_type dummy;
+    byte * tptr;
+    int count;
+
+    if (statcount==0)
+    {
+        *size=0;
+        *buffer=SafeMalloc(16);
+        return;
+    }
+    *size = statcount*sizeof(saved_stat_type);
+    *buffer = (byte *)SafeMalloc(*size);
+    tptr = *buffer;
+
+    for(count=0,temp=FIRSTSTAT; temp; temp=temp->statnext)
+    {   dummy.x = temp->x;
+        dummy.y = temp->y;
+        dummy.z = temp->z;
+        dummy.flags = temp->flags;
+        dummy.ticcount = temp->ticcount;
+        dummy.hitpoints = temp->hitpoints;
+        dummy.shapenum = temp->shapenum;
+        dummy.ammo = temp->ammo;
+        dummy.count = temp->count;
+        dummy.numanims = temp->numanims;
+        dummy.itemnumber = temp->itemnumber;
+        dummy.areanumber = temp->areanumber;
+        temp->whichstat = count;
+        dummy.whichstat = count++;
+        dummy.linked_to = temp->linked_to;
+
+        memcpy(tptr,&(dummy.x),sizeof(saved_stat_type));
+        tptr += sizeof(saved_stat_type);
+
+    }
+
+}
+
+/*
+===============
+=
+= DoLights
+=
+===============
+*/
+
+void DoLights (int tilex, int tiley)
+{
+    if (lightsource==0)
+        return;
+    if (TurnOffLight0 (tilex, tiley))
+        LightSourceAt(tilex,tiley) = 0;
+
+    if (TurnOffLight1 (tilex, tiley, -1, -1))
+        LightSourceAt(tilex-1,tiley-1) = 0;
+
+    if (TurnOffLight2 (tilex, tiley, -1))
+        LightSourceAt(tilex,tiley-1) = 0;
+
+    if (TurnOffLight1 (tilex, tiley, 1, -1))
+        LightSourceAt(tilex+1,tiley-1) = 0;
+
+    if (TurnOffLight3 (tilex, tiley, 1))
+        LightSourceAt(tilex+1,tiley) = 0;
+
+    if (TurnOffLight1 (tilex, tiley, 1, 1))
+        LightSourceAt(tilex+1,tiley+1) = 0;
+
+    if (TurnOffLight2 (tilex, tiley, 1))
+        LightSourceAt(tilex,tiley+1) = 0;
+
+    if (TurnOffLight1 (tilex, tiley, -1, 1))
+        LightSourceAt(tilex-1,tiley+1) = 0;
+
+    if (TurnOffLight3 (tilex, tiley, -1))
+        LightSourceAt(tilex-1,tiley) = 0;
+}
+
+
+/*
+===============
+=
+= TurnOffLight0
+=
+===============
+*/
+
+boolean TurnOffLight0 (int tilex, int tiley)
+{
+    if ( IsLight(tilex-1,tiley  ) ||
+            IsLight(tilex-1,tiley-1) ||
+            IsLight(tilex,tiley-1) ||
+            IsLight(tilex+1,tiley-1) ||
+            IsLight(tilex+1,tiley  ) ||
+            IsLight(tilex+1,tiley+1) ||
+            IsLight(tilex,tiley+1) ||
+            IsLight(tilex-1,tiley+1) )
+        return (false);
+    else
+        return (true);
+}
+
+/*
+===============
+=
+= TurnOffLight1
+=
+===============
+*/
+
+boolean TurnOffLight1 (int tilex, int tiley, int i, int j)
+{
+    int tempi = 2*i;
+    int tempy = 2*j;
+
+    if ( IsLight(tilex+i,tiley  ) ||
+            IsLight(tilex+i,tiley+j) ||
+            IsLight(tilex,tiley+j) ||
+            IsLight(tilex,tiley+tempy) ||
+            IsLight(tilex+i,tiley+tempy) ||
+            IsLight(tilex+tempi,tiley+tempy) ||
+            IsLight(tilex+tempi,tiley+j) ||
+            IsLight(tilex+tempi,tiley))
+        return (false);
+    else
+        return (true);
+}
+
+
+/*
+===============
+=
+= TurnOffLight2
+=
+===============
+*/
+
+boolean TurnOffLight2 (int tilex, int tiley, int j)
+{
+    int tempy = 2*j;
+
+    if ( IsLight(tilex-1,tiley  ) ||
+            IsLight(tilex-1,tiley+j) ||
+            IsLight(tilex-1,tiley+tempy) ||
+            IsLight(tilex,tiley+j) ||
+            IsLight(tilex,tiley+tempy) ||
+            IsLight(tilex+1,tiley) ||
+            IsLight(tilex+1,tiley+j) ||
+            IsLight(tilex+1,tiley+tempy))
+        return (false);
+    else
+        return (true);
+}
+
+
+/*
+===============
+=
+= TurnOffLight3
+=
+===============
+*/
+
+boolean TurnOffLight3 (int tilex, int tiley, int i)
+{
+    int tempx = 2*i;
+
+    if ( IsLight(tilex,tiley-1) ||
+            IsLight(tilex+1,tiley-1) ||
+            IsLight(tilex+tempx,tiley-1) ||
+            IsLight(tilex+i,tiley) ||
+            IsLight(tilex+tempx,tiley) ||
+            IsLight(tilex,tiley+1) ||
+            IsLight(tilex+i,tiley+1) ||
+            IsLight(tilex+tempx,tiley+1))
+        return (false);
+    else
+        return (true);
+}
+
+
+
+
+/*
+======================
+=
+= PreCacheStaticFrames
+=
+======================
+*/
+
+
+
+
+void PreCacheStaticFrames(statobj_t*temp)
+{
+    int z,start,stop;
+    int female=0,black=0;
+
+    if (temp->itemnumber != stat_bullethole &&
+            ((temp->itemnumber < stat_touch1) || (temp->itemnumber > stat_touch4)))
+        PreCacheLump(temp->shapenum+shapestart,PU_CACHESPRITES,cache_patch_t);
+    else
+        PreCacheLump(temp->shapenum+shapestart,PU_CACHESPRITES,cache_transpatch_t);
+    for (z=0; z<temp->numanims; z++)
+        PreCacheLump(temp->shapenum+shapestart+z,PU_CACHESPRITES,cache_patch_t);
+
+    if (temp->flags & FL_ROTATING)
+    {
+        for (z=1; z<8; z++)
+            PreCacheLump(temp->shapenum+shapestart+z,PU_CACHESPRITES,cache_patch_t);
+    }
+
+    if (temp->flags & FL_WOODEN)
+    {
+        start = W_GetNumForName("WFRAG1");
+        stop = W_GetNumForName("WFRAG14");
+        PreCacheGroup(start,stop,cache_patch_t);
+    }
+
+    if (temp->flags & FL_METALLIC)
+    {
+        PreCacheLump(W_GetNumForName("MSHARDS"),PU_CACHESPRITES,cache_patch_t);
+        start = W_GetNumForName("ROBODIE1");
+        stop = W_GetNumForName("ROBODEAD");
+        PreCacheGroup(start,stop,cache_patch_t);
+    }
+
+    female = ((locplayerstate->player == 1) || (locplayerstate->player == 3));
+    black = (locplayerstate->player == 2);
+
+    if (female)
+    {
+        start = W_GetNumForName("FPIST11");
+        stop = W_GetNumForName("FPIST13");
+    }
+    else if (black)
+    {
+        start = W_GetNumForName("BMPIST1");
+        stop = W_GetNumForName("BMPIST3");
+    }
+    else
+    {
+        start = W_GetNumForName("MPIST11");
+        stop = W_GetNumForName("MPIST13");
+    }
+
+    PreCacheGroup(start,stop,cache_patch_t);
+
+    switch (temp->itemnumber)
+    {
+
+    case stat_pedgoldkey:
+    case stat_pedsilverkey:
+    case stat_pedironkey:
+    case stat_pedcrystalkey:
+        PreCacheLump(W_GetNumForName("PEDESTA"),PU_CACHESPRITES,cache_patch_t);
+        break;
+
+    case stat_bat:
+        start = W_GetNumForName("EXBAT1");
+        stop = W_GetNumForName("EXBAT7");
+        PreCacheGroup(start,stop,cache_patch_t);
+        break;
+    case stat_knifestatue:
+        start = W_GetNumForName("KNIFE1");
+        stop = W_GetNumForName("KNIFE10");
+        PreCacheGroup(start,stop,cache_patch_t);
+        break;
+    case stat_twopistol:
+        if (female)
+        {
+            start = W_GetNumForName("RFPIST1");
+            stop = W_GetNumForName("LFPIST3");
+        }
+        else if (black)
+        {
+            start = W_GetNumForName("RBMPIST1");
+            stop = W_GetNumForName("LBMPIST3");
+        }
+        else
+        {
+            start = W_GetNumForName("RMPIST1");
+            stop = W_GetNumForName("LMPIST3");
+        }
+        PreCacheGroup(start,stop,cache_patch_t);
+        break;
+    case stat_mp40:
+        start = W_GetNumForName("MP401");
+        stop = W_GetNumForName("MP403");
+        PreCacheGroup(start,stop,cache_patch_t);
+        break;
+    case stat_bazooka:
+        start = W_GetNumForName("BAZOOKA1");
+        stop = W_GetNumForName("BAZOOKA4");
+        PreCacheGroup(start,stop,cache_patch_t);
+        break;
+    case stat_firebomb:
+        start = W_GetNumForName("FBOMB1");
+        stop = W_GetNumForName("FBOMB4");
+        PreCacheGroup(start,stop,cache_patch_t);
+        break;
+    case stat_heatseeker:
+        start = W_GetNumForName("HSEEK1");
+        stop = W_GetNumForName("HSEEK4");
+        PreCacheGroup(start,stop,cache_patch_t);
+        break;
+    case stat_drunkmissile:
+        start = W_GetNumForName("DRUNK1");
+        stop = W_GetNumForName("DRUNK4");
+        PreCacheGroup(start,stop,cache_patch_t);
+        break;
+    case stat_firewall:
+        start = W_GetNumForName("FIREW1");
+        stop = W_GetNumForName("FIREW3");
+        PreCacheGroup(start,stop,cache_patch_t);
+        break;
+    case stat_splitmissile:
+        start = W_GetNumForName("SPLIT1");
+        stop = W_GetNumForName("SPLIT4");
+        PreCacheGroup(start,stop,cache_patch_t);
+        break;
+    case stat_kes:
+        start = W_GetNumForName("KES1");
+        stop = W_GetNumForName("KES6");
+        PreCacheGroup(start,stop,cache_patch_t);
+        break;
+    case stat_godmode:
+        start = W_GetNumForName("GODHAND1");
+        stop = W_GetNumForName("GODHAND8");
+        PreCacheGroup(start,stop,cache_patch_t);
+
+        PreCacheGroup(W_GetNumForName("VAPO1"),
+                      W_GetNumForName("LITSOUL"),
+                      cache_patch_t);
+
+        PreCacheGroup(W_GetNumForName("GODFIRE1"),
+                      W_GetNumForName("GODFIRE4"),
+                      cache_patch_t);
+
+        break;
+    case stat_dogmode:
+        start = W_GetNumForName("DOGNOSE1");
+        stop = W_GetNumForName("DOGPAW4");
+        PreCacheGroup(start,stop,cache_patch_t);
+        break;
+
+    default:
+        ;
+    }
+
+
+
+}
+
+
+
+/*
+===============
+=
+= LoadStatics
+=
+===============
+*/
+
+
+
+
+void LoadStatics( byte * buffer, int size)
+{   saved_stat_type dummy;
+    int stcount,i;
+    statobj_t*temp;
+
+    stcount = size/sizeof(saved_stat_type);
+    InitStaticList();
+
+    for(i=0; i<stcount; i++)
+    {
+        temp = (statobj_t*)Z_LevelMalloc(sizeof(statobj_t),PU_LEVELSTRUCT,NULL);
+        if (!temp)
+            Error("LoadStatics: Failed on allocation of static %d of %d",i,stcount);
+        memset(temp,0,sizeof(*temp));
+        memcpy(&(dummy.x),buffer,sizeof(saved_stat_type));
+        temp->whichstat = statcount++;
+        temp->x = dummy.x;
+        temp->y = dummy.y;
+        temp->z = dummy.z;
+        temp->flags = dummy.flags;
+        temp->ticcount = dummy.ticcount;
+        temp->hitpoints = dummy.hitpoints;
+        temp->shapenum = dummy.shapenum;
+        temp->ammo = dummy.ammo;
+        temp->count = dummy.count;
+        temp->numanims = dummy.numanims;
+        temp->itemnumber = dummy.itemnumber;
+        temp->areanumber = dummy.areanumber;
+        temp->linked_to = dummy.linked_to;
+
+        temp->which = SPRITE;
+        temp->tilex = temp->x >> TILESHIFT;
+        temp->tiley = temp->y >> TILESHIFT;
+        temp->flags &= ~FL_ABP;
+        temp->visspot = &spotvis[temp->tilex][temp->tiley];
+
+        if ((temp->itemnumber >= stat_touch1) &&
+                (temp->itemnumber <= stat_touch4))
+        {   touchindices[temp->tilex][temp->tiley] = lasttouch + 1;
+            lasttouch ++;
+            SD_PreCacheSoundGroup(SD_TOUCHPLATESND,SD_BADTOUCHSND);
+        }
+
+        AddStatic(temp);
+        if (temp->shapenum != -1)
+        {
+            if (temp->itemnumber == stat_bullethole)
+            {
+                SetupBulletHoleLink(temp->linked_to,temp);
+            }
+
+            else if (temp->flags & FL_DEADBODY)
+            {
+                if ( actorat[temp->tilex][temp->tiley] == NULL )
+                    actorat[temp->tilex][temp->tiley] = temp;
+            }
+
+            else if (!(temp->flags & FL_NONMARK))
+            {
+                sprites[temp->tilex][temp->tiley] = temp;
+            }
+
+            PreCacheStaticFrames(temp);
+
+
+        }
+        PreCacheStaticSounds(temp->itemnumber);
+
+        buffer += sizeof(saved_stat_type);
+    }
+}
+
+
+void Set_NewZ_to_MapValue(fixed *newz,int zoffset,const char*errorstr,int tilex,int tiley)
+{
+    int zf,z;
+
+    zoffset&=0xff;
+    z=zoffset>>4;
+    zf=zoffset&0xf;
+    if (z==0xf)
+        *newz = nominalheight+64-(zf<<2);
+    else
+    {
+        if (z>levelheight)
+            Error ("You specified a height of %x for the %s at tilex=%d tiley=%d when\n the level is only %d high\n",
+                   zoffset,errorstr,tilex,tiley,levelheight);
+        else
+            *newz = nominalheight-(z<<6)-(zf<<2);
+    }
+
+}
+
+
+
+/*
+===============
+=
+= SpawnStatic
+=
+===============
+*/
+
+
+int BaseMarkerZ;//bna++
+
+void SpawnStatic (int tilex, int tiley, int mtype, int zoffset)
+{   statobj_t * temp;
+    boolean onetimer;
+
+
+
+#if (SHAREWARE == 1)
+    switch(mtype)
+    {
+    case stat_rlight:
+    case stat_glight:
+    case stat_ylight:
+    case stat_chandelier:
+        mtype = stat_blight;
+        break;
+
+    case stat_garb1:
+    case stat_garb2:
+    case stat_garb3:
+    case stat_shit:
+        mtype = stat_metalshards;
+        break;
+
+    case stat_lamp:
+        mtype = stat_altbrazier2;
+        break;
+
+    }
+#endif
+
+
+
+    if ( BATTLEMODE )
+    {
+        if ( !gamestate.BattleOptions.SpawnWeapons )
+        {
+            if ( stats[ mtype ].flags & FL_WEAPON )
+            {
+                return;
+            }
+        }
+
+        if (mtype == stat_pit)
+            return;
+
+        // Change lifeitems and extra lives to health
+        switch( mtype )
+        {
+        case stat_lifeitem1 :
+        case stat_lifeitem2 :
+            mtype = stat_monkcrystal1;
+            break;
+
+        case stat_lifeitem3 :
+        case stat_lifeitem4 :
+        case stat_oneup :
+        case stat_threeup :
+            mtype = stat_monkcrystal2;
+            break;
+        }
+
+        switch( mtype )
+        {
+        case stat_monkmeal :
+        case stat_priestporridge :
+        case stat_monkcrystal1 :
+        case stat_monkcrystal2 :
+        case stat_healingbasin :
+            if ( ( gamestate.Product != ROTT_SHAREWARE ) &&
+                    ( gamestate.BattleOptions.SpawnMines ) &&
+                    ( !IsPlatform( tilex, tiley ) &&
+                      ( ( zoffset & 0xff00 ) != 0xb000 ) ) &&
+                    ( zoffset == -1 ) )
+            {
+                mtype = stat_mine;
+            }
+            else if ( !gamestate.BattleOptions.SpawnHealth )
+            {
+                return;
+            }
+            break;
+        }
+    }
+
+    if (!firstemptystat)
+    {   temp = (statobj_t*)Z_LevelMalloc(sizeof(statobj_t),PU_LEVELSTRUCT,NULL);
+        //SoftError("\nMalloc-ing actor");
+        //if (insetupgame)
+        //	SoftError("in setup");
+    }
+
+    else
+    {   temp = lastemptystat;
+        //SoftError("\nfree actor available");
+        RemoveFromFreeStaticList(lastemptystat);
+    }
+
+// Standard pole hack
+
+    if ((zoffset>=14) && (zoffset<=17))
+        zoffset=-1;
+
+    if (temp)
+    {   memset(temp,0,sizeof(*temp));
+        temp->shapenum = stats[mtype].picnum;
+        temp->whichstat = statcount ++;
+        temp->tilex = tilex;
+        temp->tiley = tiley;
+        temp->x = ((long)tilex << TILESHIFT) + 0x8000;
+        temp->y = ((long)tiley << TILESHIFT) + 0x8000;
+        temp->areanumber = MAPSPOT(tilex,tiley,0)-AREATILE;
+        temp->linked_to = -1;
+        if ((temp->areanumber<=0) || (temp->areanumber>NUMAREAS))
+            Error ("Sprite at x=%d y=%d type=%d has an illegal areanumber\n",tilex,tiley,mtype);
+        if ( mtype == stat_mine )
+        {
+            temp->z = nominalheight;
+        }
+        else if (zoffset!=-1)
+        {
+            if ((zoffset&0xff00)==0xb000)
+                Set_NewZ_to_MapValue(&(temp->z),zoffset,"static",tilex,tiley);
+            else if (IsPlatform(tilex,tiley))
+                temp->z = PlatformHeight(tilex,tiley);
+            else if (zoffset==11)
+                temp->z=-65;
+            else if (zoffset==12)
+                temp->z=-66;
+            else
+                temp->z = nominalheight;
+            // Error ("You didn't specify a valid height over the sprite at tilex=%ld tiley=%ld\n",tilex,tiley);
+        }
+        else if (mtype>stat_chandelier)
+            temp->z = nominalheight;
+
+        temp->visspot = &spotvis[tilex][tiley];
+        temp->which = SPRITE;
+        temp->ticcount = stats[mtype].tictime;
+        temp->hitpoints = stats[mtype].hitpoints;
+        temp->itemnumber = stats[mtype].type;
+        temp->flags = stats[mtype].flags;
+        temp->ammo = stats[mtype].ammo;
+        temp->numanims = stats[mtype].numanims;
+
+
+
+
+        if (temp->flags & FL_BONUS)
+            switch  (stats[mtype].type)
+            {
+            case stat_lifeitem1:
+            case stat_lifeitem2:
+            case stat_lifeitem3:
+            case stat_lifeitem4:
+                gamestate.treasuretotal++;
+                break;
+            default:
+                ;
+            }
+
+
+
+
+        AddStatic(temp);
+
+        onetimer = ((mtype == stat_rubble) || (mtype == stat_woodfrag) ||
+                    (mtype == stat_metalfrag) || (mtype == stat_missmoke)
+                   );
+
+        if (DoPanicMapping())
+        {
+            if (temp->numanims && (!onetimer))
+            {
+                temp->flags &= ~FL_ACTIVE;
+                temp->numanims = 0;
+                GameRandomNumber("SpawnStatic",mtype);
+            }
+        }
+
+        else
+        {
+            if (temp->numanims)
+            {
+                if (!onetimer)
+                    temp->count = (int)(((int)GameRandomNumber("SpawnStatic",mtype) % stats[mtype].numanims) + 1);
+                else
+                    temp->count = 0;
+            }
+            else if (temp->itemnumber == stat_standardpole)
+            {
+                if (MAPSPOT(temp->tilex,temp->tiley,2))
+                    temp->count = 2*(MAPSPOT(temp->tilex,temp->tiley,2)-14);
+                else
+                    temp->count = 0;
+            }
+
+            if ((temp->itemnumber == stat_knifestatue) ||
+                    (temp->itemnumber == stat_emptystatue) ||
+                    (temp->itemnumber == stat_standardpole))
+                temp->flags|=FL_ROTATING;
+        }
+
+
+
+
+        if (mtype != stat_missmoke)
+            sprites[tilex][tiley] = temp;
+        else
+            temp->flags |= FL_NONMARK;
+
+
+//================ check special junk ==================================//
+
+        if (temp->itemnumber == stat_dariantouch)
+        {   _2Dpoint *tdptr;
+
+            tdptr = &(MISCVARS->ETOUCH[MISCVARS->nexttouch]);
+
+            tdptr->x = tilex;
+            tdptr->y = tiley;
+            sprites[tilex][tiley]->linked_to = MISCVARS->nexttouch;
+            MISCVARS->nexttouch ++;
+        }
+        else if ((temp->itemnumber >= stat_touch1) &&
+                 (temp->itemnumber <= stat_touch4))
+        {   touchindices[tilex][tiley] = lasttouch + 1;
+            SD_PreCacheSoundGroup(SD_TOUCHPLATESND,SD_BADTOUCHSND);
+            lasttouch ++;
+        }
+
+//=====================================================================//
+        //bna added
+        // BaseMarkerZ used to adjust height in s_basemarker1
+        // in SpawnNewObj(i,j,&s_basemarker1,inertobj);
+        BaseMarkerZ=temp->z;//bna++	BaseMarkerZ = spawnz;
+
+        PreCacheStaticFrames(temp);
+
+        PreCacheStaticSounds(temp->itemnumber);
+
+        if (temp->flags & FL_WEAPON)
+            MISCVARS->NUMWEAPONS ++;
+    }
+    else
+        Error("Z_LevelMalloc failed in SpawnStatic!");
+
+}
+
+/*
+===============
+=
+= SpawnInertStatic
+=
+===============
+*/
+
+void SpawnInertStatic (int x, int y, int z, int mtype)
+{   statobj_t * temp;
+
+
+
+
+    if (!firstemptystat)
+    {   temp = (statobj_t*)Z_LevelMalloc(sizeof(statobj_t),PU_LEVELSTRUCT,NULL);
+        //SoftError("\nMalloc-ing actor");
+        //if (insetupgame)
+        //	SoftError("in setup");
+    }
+
+    else
+    {   temp = lastemptystat;
+        //SoftError("\nfree actor available");
+        RemoveFromFreeStaticList(lastemptystat);
+    }
+
+    if (temp)
+    {   memset(temp,0,sizeof(*temp));
+        temp->shapenum = stats[mtype].picnum;
+
+        temp->whichstat = statcount ++;
+        temp->tilex = x>>16;
+        temp->tiley = y>>16;
+        temp->x = x;
+        temp->y = y;
+        temp->areanumber = MAPSPOT(temp->tilex,temp->tiley,0)-AREATILE;
+        temp->linked_to = -1;
+        if ((temp->areanumber<=0) || (temp->areanumber>NUMAREAS))
+        {
+            int tilex=temp->tilex;
+            int tiley=temp->tiley;
+
+            FindEmptyTile(&tilex,&tiley);
+            temp->areanumber = MAPSPOT(tilex,tiley,0)-AREATILE;
+        }
+        temp->z=z;
+        temp->visspot = &spotvis[temp->tilex][temp->tiley];
+        temp->which = SPRITE;
+        temp->ticcount = stats[mtype].tictime;
+        temp->hitpoints = stats[mtype].hitpoints;
+        temp->itemnumber = stats[mtype].type;
+        temp->flags = (stats[mtype].flags|FL_ABP|FL_NONMARK);
+        if (fog)
+        {   temp->shapenum++;
+            temp->flags &= ~FL_TRANSLUCENT;
+        }
+
+        temp->ammo = stats[mtype].ammo;
+        temp->numanims = stats[mtype].numanims;
+        AddStatic(temp);
+        MakeStatActive(temp);
+    }
+    else
+        Error("Z_LevelMalloc failed in SpawnStatic!");
+
+}
+
+/*
+===============
+=
+= SpawnSolidStatic
+=
+===============
+*/
+
+void SpawnSolidStatic (statobj_t * temp)
+{
+    if (temp->flags & FL_ACTIVE)
+        temp->flags &= ~FL_ACTIVE;
+    temp->hitpoints = INITIALFIRECOLOR;
+    temp->flags = FL_SOLIDCOLOR|FL_SEEN|FL_ABP;
+    if ((gamestate.BattleOptions.RespawnItems) &&
+            (temp->itemnumber == stat_tntcrate)
+       )
+        temp->flags |= FL_RESPAWN;
+
+    temp->ticcount = SOLIDCOLORTICTIME;
+}
+
+
+/*
+======================
+=
+= PreCacheStaticSounds
+=
+======================
+*/
+
+
+
+void PreCacheStaticSounds (int itemnumber)
+{
+
+    if (stats[itemnumber].flags & FL_SHOOTABLE)
+        SD_PreCacheSound(SD_ITEMBLOWSND);
+
+
+    switch(itemnumber)
+
+    {
+    case    stat_pit:
+        SD_PreCacheSound(SD_PITTRAPSND);
+        break;
+
+    case    stat_bonusbarrel:
+        SD_PreCacheSound(SD_BONUSBARRELSND);
+        break;
+
+    case    stat_knifestatue:
+        SD_PreCacheSound(SD_GETKNIFESND);
+        break;
+    case    stat_gibs1:
+    case    stat_gibs2:
+    case    stat_gibs3:
+        SD_PreCacheSound (SD_ACTORSQUISHSND);
+        break;
+    case    stat_pedgoldkey:
+    case    stat_pedsilverkey:
+    case    stat_pedironkey:
+    case    stat_pedcrystalkey:
+        SD_PreCacheSound (SD_GETKEYSND);
+
+        break;
+    case    stat_monkmeal:
+        SD_PreCacheSound (SD_GETHEALTH1SND);
+        break;
+    case    stat_monkcrystal1:
+        SD_PreCacheSound (SD_GETHEALTH2SND);
+        break;
+    case   stat_monkcrystal2:
+        SD_PreCacheSound (SD_GETHEALTH2SND);
+        break;
+    case    stat_priestporridge:
+        SD_PreCacheSound (SD_GETHEALTH1SND);
+        SD_PreCacheSound(SD_COOKHEALTHSND);
+
+        break;
+
+    case   stat_healingbasin:
+        SD_PreCacheSound (SD_GETHEALTH2SND);
+        break;
+
+    case stat_oneup:
+        SD_PreCacheSound(SD_GET1UPSND);
+        break;
+    case stat_threeup:
+        SD_PreCacheSound(SD_GET3UPSND);
+        break;
+
+    case stat_scotthead:
+        SD_PreCacheSound(SD_GETHEADSND);
+        break;
+
+    case stat_twopistol:
+    case stat_mp40:
+    case stat_bazooka:
+    case stat_firebomb:
+    case stat_heatseeker:
+    case stat_drunkmissile:
+    case stat_firewall:
+    case stat_splitmissile:
+    case stat_kes:
+        SD_PreCacheSound(SD_GETWEAPONSND);
+        break;
+
+    case stat_bat:
+        SD_PreCacheSound(SD_GETBATSND);
+        break;
+
+    case stat_lifeitem1:
+    case stat_lifeitem2:
+    case stat_lifeitem3:
+    case stat_lifeitem4:
+        SD_PreCacheSound(SD_GETBONUSSND);
+        break;
+
+
+    case stat_random:
+        SD_PreCacheSound(SD_GETGODSND);
+        SD_PreCacheSound(SD_GETDOGSND);
+        SD_PreCacheSound(SD_GETELASTSND);
+        SD_PreCacheSound(SD_GETSHROOMSSND);
+        SD_PreCacheSound(SD_LOSEMODESND);
+
+        break;
+    case stat_bulletproof:
+        SD_PreCacheSound(SD_GETBVESTSND);
+        SD_PreCacheSound(SD_LOSEMODESND);
+        break;
+
+    case stat_gasmask:
+        SD_PreCacheSound(SD_GETMASKSND);
+        SD_PreCacheSound(SD_LOSEMODESND);
+        break;
+
+    case stat_asbesto:
+        SD_PreCacheSound(SD_GETAVESTSND);
+        SD_PreCacheSound(SD_LOSEMODESND);
+        break;
+
+    case stat_elastic:
+        SD_PreCacheSound(SD_GETELASTSND);
+        SD_PreCacheSound(SD_LOSEMODESND);
+        break;
+
+    case stat_fleetfeet:
+        SD_PreCacheSound(SD_GETFLEETSND);
+        SD_PreCacheSound(SD_LOSEMODESND);
+        break;
+
+    case stat_godmode:
+        SD_PreCacheSound(SD_GETGODSND);
+        SD_PreCacheSound(SD_GODMODE1SND);
+
+        break;
+
+    case stat_dogmode:
+        SD_PreCacheSound(SD_GETDOGSND);
+        break;
+
+    case stat_mushroom:
+        SD_PreCacheSound(SD_GETSHROOMSSND);
+        SD_PreCacheSound(SD_LOSEMODESND);
+
+        break;
+
+    case stat_dipball1:
+    case stat_dipball2:
+    case stat_dipball3:
+        SD_PreCacheSound(SD_GETBONUSSND);
+        break;
+
+    default:
+        SD_PreCacheSound(SD_GETBONUSSND);
+        break;
+    }
+
+}
+
+
+
+
+
+/*
+===============
+=
+= SaveSwitches
+=
+===============
+*/
+
+void SaveSwitches(byte ** buffer, int * size)
+{   int numswitches,i;
+    byte * tptr;
+
+    numswitches = lastswitch-&switches[0];
+    if (numswitches==0)
+    {
+        *size=0;
+        *buffer=SafeMalloc(16);
+        return;
+    }
+    *size = numswitches*sizeof(wall_t);
+
+    *buffer = (byte *)SafeMalloc(*size);
+    tptr = *buffer;
+
+    for(i=0; i<numswitches; i++)
+    {   memcpy(tptr,&switches[i],sizeof(wall_t));
+        tptr += sizeof(wall_t);
+    }
+
+}
+
+
+/*
+===============
+=
+= LoadSwitches
+=
+===============
+*/
+
+void LoadSwitches (byte * buffer, int size)
+{   int numswitches,i,tilex,tiley;
+
+    numswitches = size/sizeof(wall_t);
+
+    for(i=0; i<numswitches; i++)
+    {   memcpy(&switches[i],buffer,sizeof(wall_t));
+        tilex = switches[i].tilex;
+        tiley = switches[i].tiley;
+        actorat[tilex][tiley]=&switches[i];
+        if (MAPSPOT(tilex,tiley,0) == 79) // On by default
+        {
+            if (!(switches[i].flags & FL_ON))
+                tilemap[tilex][tiley]--;
+        }
+        else if (switches[i].flags & FL_W_INVERTED) // Hi masked wall
+        {
+            maskedwallobj_t * lastmaskobj;
+
+            lastmaskobj=maskobjlist[tilemap[tilex][tiley]&0x3ff];
+            if (switches[i].flags & FL_ON)
+                lastmaskobj->toptexture++;
+        }
+        else if (switches[i].flags & FL_ON)
+            tilemap[tilex][tiley]++;
+        buffer += sizeof(wall_t);
+        touchindices[tilex][tiley] = lasttouch + 1;
+        lasttouch ++;
+    }
+    lastswitch=&switches[numswitches];
+
+}
+
+
+
+/*
+===============
+=
+= SpawnSwitchThingy
+=
+===============
+*/
+
+void SpawnSwitchThingy(int tilex, int tiley)
+{
+    lastswitch->flags |= FL_SWITCH;
+    lastswitch->which = WALL;
+    lastswitch->tilex = tilex;
+    lastswitch->tiley = tiley;
+    touchindices[tilex][tiley] = lasttouch + 1;
+    lasttouch ++;
+    actorat[tilex][tiley] = lastswitch;
+    lastswitch ++;
+
+}
+
+/*
+===============
+=
+= AnimateWalls
+=
+===============
+*/
+
+void AnimateWalls(void)
+{
+    int i;
+    animwall_t * aw;
+
+    if (DoPanicMapping()==true)
+        return;
+
+    for(i=0; i<MAXANIMWALLS; i++)
+    {
+        aw=&animwalls[i];
+        if (aw->active==0)
+            continue;
+        if (aw->ticcount <= 0)
+        {
+            if (aw->count < animwallsinfo[i].numanims)
+            {
+                aw->texture = aw->basetexture + aw->count;
+                aw->count++;
+            }
+            else
+            {
+                aw->texture = aw->basetexture;
+                aw->count = 1;
+            }
+
+            while (aw->ticcount<=0)
+                aw->ticcount+=animwallsinfo[i].tictime;
+        }
+        else
+            aw->ticcount -= tics;
+    }
+}
+
+
+#define M_ResetSprites(x)  \
+  { if ((index == stat_dariantouch) && (!x->count))\
+		 {x->shapenum = stats[index].picnum;               \
+		  x->count = 1;                                     \
+		  x->ticcount = stats[index].tictime;         \
+		  x->flags &= ~FL_BACKWARDS;                   \
+		  x->flags &= ~FL_ACTIVE;                       \
+		 }                                               \
+	}
+
+
+
+
+void CheckCriticalStatics(void)
+{   respawn_t *rtemp,*ddt;
+    int i,stilex,stiley;
+    statobj_t*temp,*stat;
+
+    for(rtemp = firstrespawn; rtemp;)
+    {   rtemp->ticcount --;
+        ddt = rtemp->next;
+
+        if (rtemp->ticcount <=0)
+        {   int stype;
+
+            stilex = rtemp->tilex;
+            stiley = rtemp->tiley;
+
+            // if another weapon is there, nuke it
+            if (sprites[stilex][stiley])
+            {   RemoveStatic(sprites[stilex][stiley]);
+                sprites[stilex][stiley] = NULL;
+            }
+
+            if (rtemp->itemnumber == stat_tntcrate)
+            {
+                RemoveStatic((statobj_t*)(rtemp->linked_to));
+                stype = stat_tntcrate;
+            }
+            else
+            {
+                for(i=0; i<NUMSTATS; i++)
+                {
+                    if (rtemp->itemnumber == stats[i].type)
+                    {
+                        stype = i;
+                        break;
+                    }
+                }
+
+            }
+
+            SpawnStatic(stilex,stiley,stype,-1);
+            LASTSTAT->z = rtemp->spawnz;
+            LASTSTAT->flags |= FL_ABP;
+            MakeStatActive(LASTSTAT);
+            SpawnNewObj(stilex,stiley,&s_itemspawn1,inertobj);
+            SD_PlaySoundRTP(SD_RESPAWNSND,new->x,new->y);
+            new->flags |= FL_ABP;
+            MakeActive(new);
+            new->z = LASTSTAT->z;
+            RemoveRespawnStatic(rtemp);
+        }
+
+        rtemp = ddt;
+    }
+
+    for (temp = firstactivestat ; temp; )
+    {   stat = temp->nextactive;
+
+        if (temp->flags & FL_SOLIDCOLOR)
+        {   temp->ticcount--;
+            if (temp->ticcount<=0)
+            {   temp->hitpoints+=SOLIDCOLORINCREMENT;
+                if (temp->hitpoints>MAXFIRECOLOR)
+                    RemoveStatic(temp);
+                else
+                    temp->ticcount = SOLIDCOLORTICTIME;
+            }
+        }
+        temp = stat;
+    }
+
+
+}
+
+
+
+/*
+===============
+=
+= DoSprites
+=
+===============
+*/
+
+void DoSprites(void)
+{   int index,i;
+    statobj_t *temp,*tempnext;
+
+
+#if (0)
+    Debug("\n");
+#endif
+    i=0;
+    for(temp = firstactivestat; temp;)
+    {   tempnext = temp->nextactive;
+
+#if (0)
+        Debug("\nid: %d, shapenum: %d, numanims: %d",i++,temp->shapenum,temp->numanims);
+#endif
+
+        if ((temp->shapenum != NOTHING) && (temp->flags & FL_ACTIVE))
+        {   index = temp->itemnumber;
+            temp->ticcount -= tics;
+            while (temp->ticcount <= 0)
+            {   if (temp->count < temp->numanims)
+                {   temp->shapenum = stats[index].picnum + temp->count;
+                    if (index == stat_missmoke)
+                    {   RemoveStatic(temp);
+                        break;
+                    }
+
+                    if (((index == stat_rubble) && (temp->count == 9)) ||
+                            ((index == stat_woodfrag) && (temp->count == 13)) ||
+                            ((index == stat_metalfrag) && (temp->count == 9)))
+                    {   temp->flags &= ~FL_ACTIVE;
+                        break;
+                    }
+
+                    if (temp->flags & FL_BACKWARDS)
+                    {   temp->count--;
+                        M_ResetSprites(temp);
+                    }
+                    else
+                        temp->count ++;
+                }
+                else if (!(temp->flags & FL_BANDF))
+                {   temp->shapenum = stats[index].picnum;
+                    temp->count=1;
+                }
+                else
+                {   temp->flags |= FL_BACKWARDS;
+                    temp->count --;
+                }
+                temp->ticcount += stats[index].tictime;
+            }
+        }
+        temp = tempnext;
+
+    }
+
+}
+
+void  SpawnStaticDamage(statobj_t * stat, int angle)
+{
+    GetNewActor ();
+    MakeActive(new);
+    NewState(new,&s_gunsmoke1);
+
+    new->obclass = inertobj;
+    new->which = ACTOR;
+    new->x = (stat->x)-(costable[angle]>>4);
+    new->y = (stat->y)+(sintable[angle]>>4);
+    new->z = (stat->z)+stats[stat->itemnumber].heightoffset;
+    new->drawx = new->x;
+    new->drawy = new->y;
+    new->tilex = (new->x >> TILESHIFT);
+    new->tiley = (new->y >> TILESHIFT);
+    new->dir = 0;
+    new->speed = 0;
+    new->flags = (FL_NEVERMARK|FL_ABP);
+    if ((new->x<=0) || (new->y<=0))
+        Error("SpawnStaticDamage: bad x,y itemnumber=%d\n",stat->itemnumber);
+}
--- /dev/null
+++ b/rott/rt_stat.h
@@ -1,0 +1,238 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+//***************************************************************************
+//
+//                  RT_STAT.C (static object functions)
+//
+//***************************************************************************
+#ifndef _rt_stat_public
+#define _rt_stat_public
+
+#include "rt_ted.h"
+
+#define MAXSWITCHES     64
+#define MAXANIMWALLS    17
+#define NUMSTATS        91
+
+typedef enum {
+    stat_ylight,
+    stat_rlight,
+    stat_glight,
+    stat_blight,
+    stat_chandelier,
+    stat_lamp,
+    stat_pedgoldkey,
+    stat_pedsilverkey,
+    stat_pedironkey,
+    stat_pedcrystalkey,
+    stat_gibs1,
+    stat_gibs2,
+    stat_gibs3,
+    stat_monkmeal,
+    stat_priestporridge,
+    stat_monkcrystal1,
+    stat_monkcrystal2,
+    stat_oneup,
+    stat_threeup,
+    stat_altbrazier1,
+    stat_altbrazier2,
+    stat_healingbasin,
+    stat_emptybasin,
+    stat_bat,
+    stat_knifestatue,
+    stat_twopistol,
+    stat_mp40,
+    stat_bazooka,
+    stat_firebomb,
+    stat_heatseeker,
+    stat_drunkmissile,
+    stat_firewall,
+    stat_splitmissile,
+    stat_kes,
+    stat_lifeitem1,
+    stat_lifeitem2,
+    stat_lifeitem3,
+    stat_lifeitem4,
+    stat_tntcrate,
+    stat_bonusbarrel,
+    stat_torch,
+    stat_floorfire,
+    stat_dipball1,
+    stat_dipball2,
+    stat_dipball3,
+    stat_touch1,
+    stat_touch2,
+    stat_touch3,
+    stat_touch4,
+    stat_dariantouch,
+    stat_scotthead,
+    stat_garb1,
+    stat_garb2,
+    stat_garb3,
+    stat_shit,
+    stat_grate,
+    stat_metalshards,
+    stat_emptypedestal,
+    stat_emptytable,
+    stat_stool,
+    stat_bcolumn,
+    stat_gcolumn,
+    stat_icolumn,
+    stat_tree,
+    stat_plant,
+    stat_urn,
+    stat_haystack,
+    stat_ironbarrel,
+    stat_heatgrate,
+    stat_standardpole,
+    stat_pit,
+    stat_godmode,
+    stat_dogmode,
+    stat_fleetfeet,
+    stat_elastic,
+    stat_mushroom,
+    stat_gasmask,
+    stat_bulletproof,
+    stat_asbesto,
+    stat_random,
+    stat_rubble,
+    stat_woodfrag,
+    stat_metalfrag,
+    stat_emptystatue,
+    stat_tomlarva,
+    stat_bullethole,
+    stat_collector,
+    stat_mine,
+    stat_missmoke,
+    stat_disk,
+    stat_badstatic
+} stat_t;
+
+typedef struct awall
+{
+    byte active;
+    byte count;
+    signed char ticcount;
+    int  texture;
+    int  basetexture;
+} animwall_t;
+
+typedef struct statstruct
+{
+    thingtype         which;
+    byte              tilex,tiley;
+    fixed             x,y,z;
+    int               shapenum;
+    unsigned          flags;
+    signed char       ticcount;
+    signed char       ammo;
+    byte              *visspot;
+    signed char       count;
+    byte              numanims;
+    stat_t            itemnumber;
+    short int         hitpoints;
+    short int         whichstat;
+    short int         areanumber;
+
+    long              linked_to;
+    struct statstruct *statnext;
+    struct statstruct *statprev;
+    struct statstruct *nextactive;
+    struct statstruct *prevactive;
+
+} statobj_t;
+
+typedef struct respstruct
+{
+    byte              tilex,tiley;
+    int               ticcount;
+    stat_t            itemnumber;
+    int               spawnz;
+    struct respstruct *next;
+    struct respstruct *prev;
+    long              linked_to;
+} respawn_t;
+
+
+typedef struct
+{
+    short      heightoffset;
+    int        picnum;
+    stat_t     type;
+    unsigned   flags;
+    byte       tictime;
+    byte       numanims;
+    byte       hitpoints;
+    byte       damage;
+    signed char  ammo;
+} statinfo;
+
+extern  statobj_t       *lastactivestat,*firstactivestat;
+extern  statobj_t       *firstemptystat,*lastemptystat;
+extern  int             spritestart;
+extern  wall_t          switches[MAXSWITCHES],*lastswitch;
+
+extern  respawn_t       *firstrespawn,*lastrespawn;
+extern  statobj_t       *FIRSTSTAT,*LASTSTAT,*sprites[MAPSIZE][MAPSIZE];
+extern  statinfo        stats[NUMSTATS];
+extern  dirtype         diagonal[9][9];
+extern  dirtype         opposite[9];
+
+extern  int             statcount;
+
+extern   int            animwallstart;
+extern   animwall_t     animwalls[MAXANIMWALLS];
+
+
+void Set_NewZ_to_MapValue(fixed*,int,const char*,int,int);
+void RemoveFromFreeStaticList(statobj_t*);
+void CheckCriticalStatics(void);
+void ActivateLight(long);
+void DeactivateLight(long);
+void TurnOnLight(int,int);
+void TurnOffLight(int,int);
+void MakeStatActive(statobj_t*);
+void MakeStatInactive(statobj_t*);
+void AddStatic(statobj_t *);
+void RemoveStatic(statobj_t *);
+
+
+void SpawnSwitchThingy(int,int);
+void InitStaticList (void);
+void InitAnimatedWallList(void);
+void SetupAnimatedWall(int which);
+void SpawnStatic (int tilex, int tiley, int mtype, int zoffset);
+void SpawnSolidStatic (statobj_t * temp);
+void AnimateWalls(void);
+void DoSprites(void);
+
+void SaveAnimWalls(byte ** buf, int * size);
+void SaveStatics(byte ** buf, int * size);
+
+void LoadAnimWalls(byte * buf, int size);
+void LoadStatics(byte * buf, int size);
+
+void SaveSwitches(byte ** buf, int * size);
+void LoadSwitches(byte * buf, int size);
+
+void SpawnInertStatic (int x, int y, int z, int mtype);
+void SpawnStaticDamage(statobj_t * stat, int angle);
+
+#endif
--- /dev/null
+++ b/rott/rt_state.c
@@ -1,0 +1,2031 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+#include "rt_def.h"
+#include "sprites.h"
+#include "states.h" //HEADER FILE FOR rt_state.c
+#include "rt_actor.h"
+#include "develop.h"
+#define SPRINGDELAY 3
+//MED
+#include "memcheck.h"
+
+
+extern void T_ReallyDead(objtype*ob);
+extern void T_PlayDead(objtype*ob);
+extern void T_Xylophone(objtype*ob);
+extern void T_BloodFall(objtype*ob);
+extern void SetShapeoffset(objtype*ob);
+extern void RespawnPlayerobj(objtype*ob);
+extern void T_ElevDisk(objtype*ob);
+extern void T_Plead(objtype*ob);
+extern void T_Blood(objtype*ob);
+extern void T_Convert(objtype*ob);
+extern void T_SlideDownScreen(objtype*ob);
+extern void T_End(objtype*ob);
+extern void T_Reset(objtype*ob);
+extern void T_CollectorWander(objtype*ob);
+extern void T_CollectorFindDoor(objtype*ob);
+extern void T_AutoPath(objtype*);
+extern void T_AutoRealign(objtype*);
+extern void T_AutoShootAlign(objtype*);
+extern void T_NME_SpinFire(objtype*);
+extern void MissileMovement(objtype*);
+extern void T_BatBlast(objtype*);
+extern void T_DeadWait(objtype*);
+extern void ActorMovement(objtype*);
+extern void T_Spring(objtype*);
+extern void T_SnakeFinale(objtype*);
+extern void T_Special(objtype*);
+extern void T_NME_Explode(objtype*);
+extern void T_Guts(objtype*);
+extern void T_Player(objtype*);
+extern void T_ParticleGenerate(objtype*);
+extern void T_Particle(objtype*);
+extern void T_SpawnSoul(objtype*);
+extern void T_NME_WindUp(objtype*);
+extern void T_NME_Attack(objtype*);
+extern void T_Saucer(objtype*);
+extern void T_NMErocket(objtype*);
+extern void T_NME_SpinAttack(objtype*);
+extern void T_NME_HeadShoot(objtype*);
+extern void T_CrushUp(objtype*);
+extern void T_CrushDown(objtype*);
+extern void T_HeinrichChase(objtype*);
+extern void T_KristLeft(objtype*);
+extern void T_KristRight(objtype*);
+extern void T_KristCheckFire(objtype*);
+extern void T_BoulderSpawn(objtype*);
+extern void T_BoulderDrop(objtype*);
+extern void T_BoulderMove(objtype*);
+extern void T_DarkmonkChase(objtype*);
+extern void T_DarkSnakeChase(objtype*);
+extern void T_DarkSnakeSpawn(objtype*);
+extern void A_DmonkAttack(objtype*);
+extern void T_GenericMove(objtype*);
+extern void T_Count(objtype*);
+extern void T_Spears(objtype*);
+extern void T_EsauSpears(objtype*);
+extern void T_Spring(objtype*);
+extern void T_4WayGunStand(objtype*);
+extern void A_GunShoot(objtype*);
+extern void A_4WayGunShoot(objtype*);
+extern void T_Attack(objtype*);
+extern void T_SnakePath(objtype*);
+extern void T_SnakeFindPath(objtype*);
+extern void T_DarkmonkLandAndFire(objtype*ob);
+extern void T_DarkmonkCharge(objtype*ob);
+extern void T_DarkmonkReact(objtype*ob);
+extern void T_BossExplosions(objtype*ob);
+
+
+/*
+=============================================================================
+
+					  LOW GUARD (includes sneaky)
+
+=============================================================================
+*/
+
+
+statetype s_lowgrdstand	   = {true,SPR_LOWGRD_S1,0,T_Stand,0,&s_lowgrdstand};
+
+
+statetype s_lowgrdpath4    = {true,SPR_LOWGRD_W41,12,T_Path,0,&s_lowgrdpath1};
+statetype s_lowgrdpath3    = {true,SPR_LOWGRD_W31,12,T_Path,SF_CLOSE,&s_lowgrdpath4};
+statetype s_lowgrdpath2    = {true,SPR_LOWGRD_W21,12,T_Path,0,&s_lowgrdpath3};
+statetype s_lowgrdpath1    = {true,SPR_LOWGRD_W11,12,T_Path,SF_CLOSE,&s_lowgrdpath2};
+
+statetype s_lowgrdcollide  = {false,SPR_LOWGRD_PAIN1,0,T_Collide,0,&s_lowgrdcollide};
+statetype s_lowgrdcollide2 = {false,SPR_LOWGRD_PAIN2,0,T_Collide,0,&s_lowgrdcollide2};
+
+
+//statetype s_lowgrduse2     = {true,SPR_LOWGRD_USE21,5,T_Use,0,&s_lowgrdpath1};
+//statetype s_lowgrduse1     = {true,SPR_LOWGRD_USE11,5,T_Use,0,&s_lowgrduse2};
+
+statetype s_lowgrdshoot4 	= {false,SPR_LOWGRD_SHOOT4,8,ActorMovement,0,&s_lowgrdchase1};
+statetype s_lowgrdshoot3   = {false,SPR_LOWGRD_SHOOT3,5,A_Shoot,0,&s_lowgrdshoot4};
+statetype s_lowgrdshoot2   = {false,SPR_LOWGRD_SHOOT2,20,ActorMovement,0,&s_lowgrdshoot3};
+statetype s_lowgrdshoot1 	= {false,SPR_LOWGRD_SHOOT1,6,ActorMovement,0,&s_lowgrdshoot2};
+
+statetype s_lowgrdchase4   = {true,SPR_LOWGRD_W41,12,T_Chase,0,&s_lowgrdchase1};
+statetype s_lowgrdchase3   = {true,SPR_LOWGRD_W31,12,T_Chase,SF_CLOSE,&s_lowgrdchase4};
+statetype s_lowgrdchase2   = {true,SPR_LOWGRD_W21,12,T_Chase,0,&s_lowgrdchase3};
+statetype s_lowgrdchase1   = {true,SPR_LOWGRD_W11,12,T_Chase,SF_CLOSE,&s_lowgrdchase2};
+
+
+
+statetype s_lowgrddead     = {false,SPR_LOWGRD_DEAD,0,T_Collide,0,&s_lowgrddead};
+
+statetype s_lowgrddie4     = {false,SPR_LOWGRD_DIE4,8,T_Collide,0,&s_lowgrddead};
+statetype s_lowgrddie3     = {false,SPR_LOWGRD_DIE3,8,T_Collide,0,&s_lowgrddie4};
+statetype s_lowgrddie2     = {false,SPR_LOWGRD_DIE2,8,T_Collide,0,&s_lowgrddie3};
+statetype s_lowgrddie1		= {false,SPR_LOWGRD_DIE1,15,T_Collide,0,&s_lowgrddie2};
+
+//LT added
+
+
+statetype s_lowgrddie1rev = {false, SPR_LOWGRD_DIE1,8,T_Collide,0,&s_lowgrdstand};
+statetype s_lowgrddie2rev = {false, SPR_LOWGRD_DIE2,8,T_Collide,0,&s_lowgrddie1rev};
+statetype s_lowgrddie3rev = {false, SPR_LOWGRD_DIE3,8,T_Collide,0,&s_lowgrddie2rev};
+statetype s_lowgrddie4rev = {false, SPR_LOWGRD_DIE4,8,T_Collide,0,&s_lowgrddie3rev};
+statetype s_lowgrddeadrev = {false,SPR_LOWGRD_DEAD,0,T_Collide,0,&s_lowgrddie4rev};
+
+
+
+statetype s_lowgrdcrushed2		= {false,SPR_LOWGRD_DIE3,2,NULL,0,&s_lowgrddead};
+statetype s_lowgrdcrushed1		= {false,SPR_LOWGRD_DIE1,2,NULL,0,&s_lowgrdcrushed2};
+
+/************** Sneaky stuff *******************************************/
+
+statetype s_sneakydown     = {false,SPR_SNEAKY_DEAD,0,T_Stand,0,&s_sneakydown};
+statetype s_sneakyrise4    = {false,SPR_RISE4,6,ActorMovement,0,&s_lowgrdchase1};
+statetype s_sneakyrise3    = {false,SPR_RISE3,6,ActorMovement,0,&s_sneakyrise4};
+statetype s_sneakyrise2    = {false,SPR_RISE2,6,ActorMovement,0,&s_sneakyrise3};
+statetype s_sneakyrise1    = {false,SPR_RISE1,6,ActorMovement,0,&s_sneakyrise2};
+
+
+/*
+=============================================================================
+
+					  HIGH GUARD
+
+=============================================================================
+*/
+
+
+
+statetype s_highgrdstand	= {true,SPR_HIGHGRD_S1,0,T_Stand,0,&s_highgrdstand};
+
+
+statetype s_highgrdpath4   = {true,SPR_HIGHGRD_W41,12,T_Path,0,&s_highgrdpath1};
+statetype s_highgrdpath3   = {true,SPR_HIGHGRD_W31,12,T_Path,SF_CLOSE,&s_highgrdpath4};
+statetype s_highgrdpath2   = {true,SPR_HIGHGRD_W21,12,T_Path,0,&s_highgrdpath3};
+statetype s_highgrdpath1   = {true,SPR_HIGHGRD_W11,12,T_Path,SF_CLOSE,&s_highgrdpath2};
+
+
+//statetype s_highgrdpain1 	= {2,SPR_HIGHGRD_PAIN1,10,T_Collide,0,&s_highgrdchase1};
+//statetype s_highgrdpain2 	= {2,SPR_HIGHGRD_PAIN2,10,T_Collide,0,&s_highgrdchase1};
+
+
+statetype s_highgrdcollide  = {false,SPR_HIGHGRD_PAIN1,0,T_Collide,0,&s_highgrdcollide};
+statetype s_highgrdcollide2 = {false,SPR_HIGHGRD_PAIN2,0,T_Collide,0,&s_highgrdcollide2};
+
+
+//statetype s_highgrduse2 	 = {true,SPR_HIGHGRD_USE21,10,T_Use,0,&s_highgrdpath1};
+//statetype s_highgrduse1 	 = {true,SPR_HIGHGRD_USE11,10,T_Use,0,&s_highgrduse2};
+
+
+statetype s_highgrdshoot4  = {false,SPR_HIGHGRD_SHOOT4,3,A_Repeat,0,&s_highgrdshoot3};
+statetype s_highgrdshoot3  = {false,SPR_HIGHGRD_SHOOT3,5,A_Shoot,0,&s_highgrdshoot4};
+statetype s_highgrdshoot2  = {false,SPR_HIGHGRD_SHOOT2,6,ActorMovement,0,&s_highgrdshoot3};
+statetype s_highgrdshoot1 	= {false,SPR_HIGHGRD_SHOOT1,6,ActorMovement,0,&s_highgrdshoot2};
+
+
+statetype s_highgrdchase4  = {true,SPR_HIGHGRD_W41,12,T_Chase,0,&s_highgrdchase1};
+statetype s_highgrdchase3 = {true,SPR_HIGHGRD_W31,12,T_Chase,SF_CLOSE,&s_highgrdchase4};
+statetype s_highgrdchase2 = {true,SPR_HIGHGRD_W21,12,T_Chase,0,&s_highgrdchase3};
+statetype s_highgrdchase1 = {true,SPR_HIGHGRD_W11,12,T_Chase,SF_CLOSE,&s_highgrdchase2};
+
+
+statetype s_highgrddead    = {false,SPR_HIGHGRD_DEAD,0,T_Collide,0,&s_highgrddead};
+statetype s_highgrddie5    = {false,SPR_HIGHGRD_DIE5,0,T_Collide,0,&s_highgrddead};
+statetype s_highgrddie4    = {false,SPR_HIGHGRD_DIE4,8,T_Collide,0,&s_highgrddie5};
+statetype s_highgrddie3    = {false,SPR_HIGHGRD_DIE3,8,T_Collide,0,&s_highgrddie4};
+statetype s_highgrddie2    = {false,SPR_HIGHGRD_DIE2,8,T_Collide,0,&s_highgrddie3};
+statetype s_highgrddie1    = {false,SPR_HIGHGRD_DIE1,8,T_Collide,0,&s_highgrddie2};
+
+statetype s_highgrddie1rev  = {false,SPR_HIGHGRD_DIE1,8,T_Collide,0,&s_highgrdstand};
+statetype s_highgrddie2rev  = {false,SPR_HIGHGRD_DIE2,8,T_Collide,0,&s_highgrddie1rev};
+statetype s_highgrddie3rev  = {false,SPR_HIGHGRD_DIE3,8,T_Collide,0,&s_highgrddie2rev};
+statetype s_highgrddie4rev  = {false,SPR_HIGHGRD_DIE4,8,T_Collide,0,&s_highgrddie3rev};
+statetype s_highgrddie5rev  = {false,SPR_HIGHGRD_DIE5,0,T_Collide,0,&s_highgrddie4rev};
+
+statetype s_highgrdcrushed2		= {false,SPR_HIGHGRD_DIE3,2,NULL,0,&s_highgrddead};
+statetype s_highgrdcrushed1		= {false,SPR_HIGHGRD_DIE1,2,NULL,0,&s_highgrdcrushed2};
+
+/*
+===========================================================================
+
+										 STRIKEGUARD
+
+===========================================================================
+*/
+
+
+statetype s_strikestand	= {true,SPR_STRIKE_S1,0,T_Stand,0,&s_strikestand};
+
+
+statetype s_strikepath4    = {true,SPR_STRIKE_W41,12,T_Path,0,&s_strikepath1};
+statetype s_strikepath3    = {true,SPR_STRIKE_W31,12,T_Path,SF_CLOSE,&s_strikepath4};
+statetype s_strikepath2    = {true,SPR_STRIKE_W21,12,T_Path,0,&s_strikepath3};
+statetype s_strikepath1    = {true,SPR_STRIKE_W11,12,T_Path,SF_CLOSE,&s_strikepath2};
+
+statetype s_strikecollide  = {false,SPR_STRIKE_PAIN1,0,T_Collide,0,&s_strikecollide};
+statetype s_strikecollide2 = {false,SPR_STRIKE_PAIN2,0,T_Collide,0,&s_strikecollide2};
+
+statetype s_strikeshoot4 	= {false,SPR_STRIKE_SHOOT4,6,ActorMovement,0,&s_strikechase1};
+statetype s_strikeshoot3 	= {false,SPR_STRIKE_SHOOT3,6,ActorMovement,0,&s_strikeshoot4};
+statetype s_strikeshoot2   = {false,SPR_STRIKE_SHOOT2,5,A_Shoot,0,&s_strikeshoot3};
+statetype s_strikeshoot1   = {false,SPR_STRIKE_SHOOT1,20,ActorMovement,0,&s_strikeshoot2};
+
+
+//statetype s_strikeuse2      = {true,SPR_STRIKE_USE21,10,T_Use,0,&s_strikechase1};
+//statetype s_strikeuse1      = {true,SPR_STRIKE_USE11,10,NULL,0,&s_strikeuse2};
+
+statetype s_strikewait      = {true,SPR_STRIKE_S1,35,NULL,0,&s_strikechase1};
+
+statetype s_strikerollright6    = {false,SPR_STRIKE_LROLL6,8,T_Roll,0,&s_strikeshoot1};
+statetype s_strikerollright5    = {false,SPR_STRIKE_LROLL5,8,T_Roll,0,&s_strikerollright6};
+statetype s_strikerollright4    = {false,SPR_STRIKE_LROLL4,7,T_Reset,0,&s_strikerollright5};
+statetype s_strikerollright3    = {false,SPR_STRIKE_LROLL3,7,T_Roll,0,&s_strikerollright4};
+statetype s_strikerollright2    = {false,SPR_STRIKE_LROLL2,7,T_Roll,0,&s_strikerollright3};
+statetype s_strikerollright1    = {false,SPR_STRIKE_LROLL1,5,T_Roll,0,&s_strikerollright2};
+
+
+
+statetype s_strikerollleft6    = {false,SPR_STRIKE_RROLL6,8,T_Roll,0,&s_strikeshoot1};
+statetype s_strikerollleft5    = {false,SPR_STRIKE_RROLL5,8,T_Roll,0,&s_strikerollleft6};
+statetype s_strikerollleft4    = {false,SPR_STRIKE_RROLL4,7,T_Reset,0,&s_strikerollleft5};
+statetype s_strikerollleft3    = {false,SPR_STRIKE_RROLL3,7,T_Roll,0,&s_strikerollleft4};
+statetype s_strikerollleft2    = {false,SPR_STRIKE_RROLL2,7,T_Roll,0,&s_strikerollleft3};
+statetype s_strikerollleft1    = {false,SPR_STRIKE_RROLL1,5,T_Roll,0,&s_strikerollleft2};
+
+
+statetype s_strikechase4   = {true,SPR_STRIKE_W41,12,T_Chase,0,&s_strikechase1};
+statetype s_strikechase3   = {true,SPR_STRIKE_W31,12,T_Chase,SF_CLOSE,&s_strikechase4};
+statetype s_strikechase2   = {true,SPR_STRIKE_W21,12,T_Chase,0,&s_strikechase3};
+statetype s_strikechase1   = {true,SPR_STRIKE_W11,12,T_Chase,SF_CLOSE,&s_strikechase2};
+
+
+statetype s_strikedead3    = {false,SPR_STRIKE_DEAD3,0,T_Collide,0,&s_strikedead3};
+statetype s_strikedead2    = {false,SPR_STRIKE_DEAD2,0,T_Collide,0,&s_strikedead3};
+statetype s_strikedead     = {false,SPR_STRIKE_DEAD1,7,T_Collide,0,&s_strikedead2};
+statetype s_strikedie4     = {false,SPR_STRIKE_DIE4,7,T_Collide,0,&s_strikedead};
+statetype s_strikedie3     = {false,SPR_STRIKE_DIE3,7,T_Collide,0,&s_strikedie4};
+statetype s_strikedie2     = {false,SPR_STRIKE_DIE2,7,T_Collide,0,&s_strikedie3};
+statetype s_strikedie1     = {false,SPR_STRIKE_DIE1,7,T_Collide,0,&s_strikedie2};
+
+
+statetype s_strikedie1rev     = {false,SPR_STRIKE_DIE1,7,T_Collide,0,&s_strikestand};
+statetype s_strikedie2rev     = {false,SPR_STRIKE_DIE2,7,T_Collide,0,&s_strikedie1rev};
+statetype s_strikedie3rev     = {false,SPR_STRIKE_DIE3,7,T_Collide,0,&s_strikedie2rev};
+statetype s_strikedie4rev     = {false,SPR_STRIKE_DIE4,7,T_Collide,0,&s_strikedie3rev};
+
+statetype s_strikecrushed2		= {false,SPR_STRIKE_DIE3,2,NULL,0,&s_strikedead};
+statetype s_strikecrushed1		= {false,SPR_STRIKE_DIE1,2,NULL,0,&s_strikecrushed2};
+
+/*
+============================================================================
+
+								LIGHTNING GUARD
+
+============================================================================
+*/
+
+statetype s_blitzstand	= {true,SPR_BLITZ_S1,0,T_Stand,0,&s_blitzstand};
+
+statetype s_blitzpath4 = {true,SPR_BLITZ_W41,12,T_Path,0,&s_blitzpath1};
+statetype s_blitzpath3 = {true,SPR_BLITZ_W31,12,T_Path,SF_CLOSE,&s_blitzpath4};
+statetype s_blitzpath2 = {true,SPR_BLITZ_W21,12,T_Path,0,&s_blitzpath3};
+statetype s_blitzpath1 = {true,SPR_BLITZ_W11,12,T_Path,SF_CLOSE,&s_blitzpath2};
+
+
+
+statetype s_blitzcollide  = {false,SPR_BLITZ_PAIN1,0,T_Collide,0,&s_blitzcollide};
+statetype s_blitzcollide2 = {false,SPR_BLITZ_PAIN2,0,T_Collide,0,&s_blitzcollide2};
+
+statetype s_blitzshoot4 = {false,SPR_BLITZ_SHOOT4,10,ActorMovement,0,&s_blitzchase1};
+statetype s_blitzshoot3 = {false,SPR_BLITZ_SHOOT3,10,ActorMovement,0,&s_blitzshoot4};
+statetype s_blitzshoot2 = {false,SPR_BLITZ_SHOOT2,5,A_Shoot,0,&s_blitzshoot3};
+statetype s_blitzshoot1 = {false,SPR_BLITZ_SHOOT1,10,ActorMovement,0,&s_blitzshoot2};
+
+statetype s_blitzrise4 = {false,SPR_BLITZ_RISE4,8,ActorMovement,0,&s_blitzchase1};
+statetype s_blitzrise3 = {false,SPR_BLITZ_RISE3,8,ActorMovement,0,&s_blitzrise4};
+statetype s_blitzrise2 = {false,SPR_BLITZ_RISE2,8,ActorMovement,0,&s_blitzrise3};
+statetype s_blitzrise1 = {false,SPR_BLITZ_RISE1,8,ActorMovement,0,&s_blitzrise2};
+
+statetype s_blitzuse    = {true,SPR_BLITZ_USE,10,T_Use,0,&s_blitzpath1};
+
+
+statetype s_blitzsteal2 = {true,SPR_BLITZ_STEAL2,20,A_Steal,0,&s_blitzchase1};
+statetype s_blitzsteal1 = {true,SPR_BLITZ_STEAL1,20,ActorMovement,0,&s_blitzsteal2};
+
+statetype s_blitzchase4    = {true,SPR_BLITZ_W41,12,T_Chase,0,&s_blitzchase1};
+statetype s_blitzchase3    = {true,SPR_BLITZ_W31,12,T_Chase,SF_CLOSE,&s_blitzchase4};
+statetype s_blitzchase2    = {true,SPR_BLITZ_W21,12,T_Chase,0,&s_blitzchase3};
+statetype s_blitzchase1    = {true,SPR_BLITZ_W11,12,T_Chase,SF_CLOSE,&s_blitzchase2};
+
+
+statetype s_blitzdead2     = {false,SPR_BLITZ_DEAD2,0,T_Collide,0,&s_blitzdead2};
+statetype s_blitzdead      = {false,SPR_BLITZ_DEAD1,0,T_Collide,0,&s_blitzdead2};
+statetype s_blitzdie4      = {false,SPR_BLITZ_DIE4,7,T_Collide,0,&s_blitzdead};
+statetype s_blitzdie3      = {false,SPR_BLITZ_DIE3,7,T_Collide,0,&s_blitzdie4};
+statetype s_blitzdie2      = {false,SPR_BLITZ_DIE2,7,T_Collide,0,&s_blitzdie3};
+statetype s_blitzdie1      = {false,SPR_BLITZ_DIE1,7,T_Collide,0,&s_blitzdie2};
+
+statetype s_blitzdie1rev      = {false,SPR_BLITZ_DIE1,7,T_Collide,0,&s_blitzstand};
+statetype s_blitzdie2rev      = {false,SPR_BLITZ_DIE2,7,T_Collide,0,&s_blitzdie1rev};
+statetype s_blitzdie3rev      = {false,SPR_BLITZ_DIE3,7,T_Collide,0,&s_blitzdie2rev};
+statetype s_blitzdie4rev      = {false,SPR_BLITZ_DIE4,7,T_Collide,0,&s_blitzdie3rev};
+
+statetype s_blitzstruggledead  = {false,SPR_BLITZ_RISE2,0,T_Collide,0,&s_blitzstruggledead};
+statetype s_blitzstruggledie1  = {false,SPR_BLITZ_RISE2,20,T_ReallyDead,0,&s_blitzstruggledead};
+
+
+statetype s_blitzfakedead  = {false,SPR_BLITZ_DEAD2,0,T_PlayDead,SF_FAKING,&s_blitzfakedead};
+statetype s_blitzfakedie3  = {false,SPR_BLITZ_DEAD1,5,ActorMovement,0,&s_blitzfakedead};
+statetype s_blitzfakedie2  = {false,SPR_BLITZ_DIE4,5,ActorMovement,0,&s_blitzfakedie3};
+statetype s_blitzfakedie1  = {false,SPR_BLITZ_DIE3,5,ActorMovement,0,&s_blitzfakedie2};
+
+
+statetype s_blitzcrushed2     = {false,SPR_BLITZ_DIE3,2,NULL,0,&s_blitzdead};
+statetype s_blitzcrushed1		= {false,SPR_BLITZ_DIE1,2,NULL,0,&s_blitzcrushed2};
+
+statetype s_blitzplead11    = {false,SPR_BLITZ_PLEAD11,0,T_Collide,0,&s_blitzplead11};
+statetype s_blitzplead10    = {false,SPR_BLITZ_PLEAD10,6,NULL,0,&s_blitzplead11};
+statetype s_blitzplead9    = {false,SPR_BLITZ_PLEAD9,6,NULL,0,&s_blitzplead10};
+statetype s_blitzplead8    = {false,SPR_BLITZ_PLEAD8,6,NULL,0,&s_blitzplead9};
+statetype s_blitzplead7    = {false,SPR_BLITZ_PLEAD7,6,NULL,0,&s_blitzplead8};
+
+
+
+
+statetype s_blitzaplead4    = {false,SPR_BLITZ_PLEAD4,5,T_Plead,SF_DOWN,&s_blitzplead3};
+statetype s_blitzaplead5    = {false,SPR_BLITZ_PLEAD5,5,T_Plead,SF_DOWN,&s_blitzaplead4};
+
+statetype s_blitzplead6    = {false,SPR_BLITZ_PLEAD6,5,T_Plead,SF_DOWN,&s_blitzaplead5};
+statetype s_blitzplead5    = {false,SPR_BLITZ_PLEAD5,5,T_Plead,SF_DOWN,&s_blitzplead6};
+statetype s_blitzplead4    = {false,SPR_BLITZ_PLEAD4,5,T_Plead,SF_DOWN,&s_blitzplead5};
+statetype s_blitzplead3    = {false,SPR_BLITZ_PLEAD3,5,T_Plead,SF_DOWN,&s_blitzplead4};
+statetype s_blitzplead2    = {false,SPR_BLITZ_PLEAD2,6,ActorMovement,0,&s_blitzplead3};
+statetype s_blitzplead1    = {false,SPR_BLITZ_PLEAD1,6,ActorMovement,0,&s_blitzplead2};
+
+
+
+/*
+============================================================================
+
+								TRIAD ENFORCERS
+
+============================================================================
+*/
+
+
+statetype s_enforcerstand	= {true,SPR_ENFORCER_S1,0,T_Stand,0,&s_enforcerstand};
+
+
+statetype s_enforcerpath4  = {true,SPR_ENFORCER_W41,12,T_Path,0,&s_enforcerpath1};
+statetype s_enforcerpath3  = {true,SPR_ENFORCER_W31,12,T_Path,SF_CLOSE,&s_enforcerpath4};
+statetype s_enforcerpath2  = {true,SPR_ENFORCER_W21,12,T_Path,0,&s_enforcerpath3};
+statetype s_enforcerpath1  = {true,SPR_ENFORCER_W11,12,T_Path,SF_CLOSE,&s_enforcerpath2};
+
+
+statetype s_enforcerchase4    = {true,SPR_ENFORCER_W41,12,T_Chase,0,&s_enforcerchase1};
+statetype s_enforcerchase3    = {true,SPR_ENFORCER_W31,12,T_Chase,SF_CLOSE,&s_enforcerchase4};
+statetype s_enforcerchase2    = {true,SPR_ENFORCER_W21,12,T_Chase,0,&s_enforcerchase3};
+statetype s_enforcerchase1    = {true,SPR_ENFORCER_W11,12,T_Chase,SF_CLOSE,&s_enforcerchase2};
+
+statetype s_enforcercollide  = {false,SPR_ENFORCER_PAIN1,0,T_Collide,0,&s_enforcercollide};
+statetype s_enforcercollide2 = {false,SPR_ENFORCER_PAIN2,0,T_Collide,0,&s_enforcercollide2};
+
+
+//statetype s_enforceruse2    = {true,SPR_ENFORCER_USE21,10,T_Use,0,&s_enforcerchase1};
+//statetype s_enforceruse1    = {true,SPR_ENFORCER_USE11,10,T_Use,0,&s_enforceruse2};
+
+statetype s_enforcershoot4 = {false,SPR_ENFORCER_SHOOT4,6,A_Repeat,0,&s_enforcershoot3};
+statetype s_enforcershoot3 = {false,SPR_ENFORCER_SHOOT3,6,A_Shoot,0,&s_enforcershoot4};
+statetype s_enforcershoot2 = {false,SPR_ENFORCER_SHOOT2,6,ActorMovement,0,&s_enforcershoot3};
+statetype s_enforcershoot1 = {false,SPR_ENFORCER_SHOOT1,6,ActorMovement,0,&s_enforcershoot2};
+
+
+statetype s_enforcerthrow8 = {false,SPR_ENFORCER_THROW8,10,ActorMovement,0,&s_enforcerchase1};
+statetype s_enforcerthrow7 = {false,SPR_ENFORCER_THROW7,10,ActorMovement,0,&s_enforcerthrow8};
+statetype s_enforcerthrow6 = {false,SPR_ENFORCER_THROW6,10,ActorMovement,0,&s_enforcerthrow7};
+statetype s_enforcerthrow5 = {false,SPR_ENFORCER_THROW5,10,A_MissileWeapon,0,&s_enforcerthrow6};
+statetype s_enforcerthrow4 = {false,SPR_ENFORCER_THROW4,10,ActorMovement,0,&s_enforcerthrow5};
+statetype s_enforcerthrow3 = {false,SPR_ENFORCER_THROW3,10,ActorMovement,0,&s_enforcerthrow4};
+statetype s_enforcerthrow2 = {false,SPR_ENFORCER_THROW2,10,ActorMovement,0,&s_enforcerthrow3};
+statetype s_enforcerthrow1 = {false,SPR_ENFORCER_THROW1,10,ActorMovement,0,&s_enforcerthrow2};
+
+
+
+statetype s_grenade10      = {false,SPR_ENFORCER_GR10,2,T_Projectile,0,&s_grenade1};
+statetype s_grenade9       = {false,SPR_ENFORCER_GR9,2,T_Projectile,0,&s_grenade10};
+statetype s_grenade8       = {false,SPR_ENFORCER_GR8,2,T_Projectile,0,&s_grenade9};
+statetype s_grenade7       = {false,SPR_ENFORCER_GR7,2,T_Projectile,0,&s_grenade8};
+statetype s_grenade6       = {false,SPR_ENFORCER_GR6,2,T_Projectile,0,&s_grenade7};
+statetype s_grenade5       = {false,SPR_ENFORCER_GR5,2,T_Projectile,0,&s_grenade6};
+statetype s_grenade4       = {false,SPR_ENFORCER_GR4,2,T_Projectile,0,&s_grenade5};
+statetype s_grenade3       = {false,SPR_ENFORCER_GR3,2,T_Projectile,0,&s_grenade4};
+statetype s_grenade2       = {false,SPR_ENFORCER_GR2,2,T_Projectile,0,&s_grenade3};
+statetype s_grenade1       = {false,SPR_ENFORCER_GR1,2,T_Projectile,0,&s_grenade2};
+
+statetype s_grenade_fall6  = {false,SPR_ENFORCER_FALL6,6,T_Projectile,0,&s_grenade_fall6};
+statetype s_grenade_fall5  = {false,SPR_ENFORCER_FALL5,6,T_Projectile,0,&s_grenade_fall6};
+statetype s_grenade_fall4  = {false,SPR_ENFORCER_FALL4,6,T_Projectile,0,&s_grenade_fall5};
+statetype s_grenade_fall3  = {false,SPR_ENFORCER_FALL3,6,T_Projectile,0,&s_grenade_fall4};
+statetype s_grenade_fall2  = {false,SPR_ENFORCER_FALL1,6,T_Projectile,0,&s_grenade_fall3};
+statetype s_grenade_fall1  = {false,SPR_ENFORCER_FALL1,6,T_Projectile,0,&s_grenade_fall2};
+
+statetype s_grenadehit3     = {false,SPR_GRENADE_HIT3,5,NULL,0,NULL};
+statetype s_grenadehit2     = {false,SPR_GRENADE_HIT2,5,NULL,0,&s_grenadehit3};
+statetype s_grenadehit1     = {false,SPR_GRENADE_HIT1,5,NULL,0,&s_grenadehit2};
+
+
+statetype s_enforcerdead      = {false,SPR_ENFORCER_DEAD,0,T_Collide,0,&s_enforcerdead};
+statetype s_enforcerdie4      = {false,SPR_ENFORCER_DIE4,7,T_Collide,0,&s_enforcerdead};
+statetype s_enforcerdie3      = {false,SPR_ENFORCER_DIE3,7,T_Collide,0,&s_enforcerdie4};
+statetype s_enforcerdie2      = {false,SPR_ENFORCER_DIE2,7,T_Collide,0,&s_enforcerdie3};
+statetype s_enforcerdie1      = {false,SPR_ENFORCER_DIE1,7,T_Collide,0,&s_enforcerdie2};
+
+statetype s_enforcerdie1rev      = {false,SPR_ENFORCER_DIE1,7,T_Collide,0,&s_enforcerstand};
+statetype s_enforcerdie2rev      = {false,SPR_ENFORCER_DIE2,7,T_Collide,0,&s_enforcerdie1rev};
+statetype s_enforcerdie3rev      = {false,SPR_ENFORCER_DIE3,7,T_Collide,0,&s_enforcerdie2rev};
+statetype s_enforcerdie4rev      = {false,SPR_ENFORCER_DIE4,7,T_Collide,0,&s_enforcerdie3rev};
+
+
+statetype s_enforcercrushed2		= {false,SPR_ENFORCER_DIE3,2,NULL,0,&s_enforcerdead};
+statetype s_enforcercrushed1		= {false,SPR_ENFORCER_DIE1,2,NULL,0,&s_enforcercrushed2};
+
+/*
+============================================================================
+
+								 ROBOT GUARD
+
+============================================================================
+*/
+
+
+
+statetype s_robogrdstand	= {16,SPR_ROBOGRD_S11,0,T_Stand,0,&s_robogrdstand};
+
+statetype s_robogrdpath1 	= {16,SPR_ROBOGRD_S11,20,T_AutoPath,0,&s_robogrdpath1};
+
+statetype s_robowait = {16,SPR_ROBOGRD_S11,0,NULL,0,&s_robowait};
+statetype s_roborealign = {16,SPR_ROBOGRD_S11,0,T_AutoRealign,0,&s_roborealign};
+statetype s_roboalign = {16,SPR_ROBOGRD_S11,0,T_AutoShootAlign,0,&s_roboalign};
+
+statetype s_robogrdshoot1 	= {false,SPR_ROBOGRD_S11,35,A_MissileWeapon,0,&s_roborealign};
+
+statetype s_robogrdshuriken4 	= {false,SPR_ROBOGRD_SHURIKEN4,4,T_Projectile,0,&s_robogrdshuriken1};
+statetype s_robogrdshuriken3 	= {false,SPR_ROBOGRD_SHURIKEN3,4,T_Projectile,0,&s_robogrdshuriken4};
+statetype s_robogrdshuriken2 	= {false,SPR_ROBOGRD_SHURIKEN2,4,T_Projectile,0,&s_robogrdshuriken3};
+statetype s_robogrdshuriken1  = {false,SPR_ROBOGRD_SHURIKEN1,4,T_Projectile,0,&s_robogrdshuriken2};
+
+statetype s_shurikenhit3    = {false,SPR_SHURIKEN_HIT3,5,NULL,0,NULL};
+statetype s_shurikenhit2    = {false,SPR_SHURIKEN_HIT2,5,NULL,0,&s_shurikenhit3};
+statetype s_shurikenhit1    = {false,SPR_SHURIKEN_HIT1,5,NULL,0,&s_shurikenhit2};
+
+statetype s_robogrdcollide  = {16,SPR_ROBOGRD_S11,0,T_Collide,0,&s_robogrdcollide};
+statetype s_robogrdcollide2 = {16,SPR_ROBOGRD_S11,0,T_Collide,0,&s_robogrdcollide2};
+
+//statetype s_robogrdchase1 	= {16,SPR_ROBOGRD_S11,10,T_RoboChase,0,&s_robogrdchase1};
+
+statetype s_robogrddead		= {false,ROBOGRDDEAD,0,T_Collide,0,&s_robogrddead};
+statetype s_robogrddie9	   = {false,ROBOGRDDIE9,3,T_Collide,0,&s_robogrddead};
+statetype s_robogrddie8	   = {false,ROBOGRDDIE8,3,T_Collide,0,&s_robogrddie9};
+statetype s_robogrddie7	   = {false,ROBOGRDDIE7,3,T_Collide,0,&s_robogrddie8};
+statetype s_robogrddie6	   = {false,ROBOGRDDIE6,3,T_Collide,0,&s_robogrddie7};
+statetype s_robogrddie5	   = {false,ROBOGRDDIE5,3,T_Collide,0,&s_robogrddie6};
+statetype s_robogrddie4	   = {false,ROBOGRDDIE4,3,T_Collide,0,&s_robogrddie5};
+statetype s_robogrddie3	   = {false,ROBOGRDDIE3,3,T_Collide,0,&s_robogrddie4};
+statetype s_robogrddie2	   = {false,ROBOGRDDIE2,3,T_Collide,0,&s_robogrddie3};
+statetype s_robogrddie1	   = {false,ROBOGRDDIE1,3,T_Collide,0,&s_robogrddie2};
+
+
+statetype s_bstar4 = {false,SPR_BSTAR4,1,T_Projectile,0,&s_bstar1};
+statetype s_bstar3 = {false,SPR_BSTAR3,1,T_Projectile,0,&s_bstar4};
+statetype s_bstar2 = {false,SPR_BSTAR2,1,T_Projectile,0,&s_bstar3};
+statetype s_bstar1 = {false,SPR_BSTAR1,1,T_Projectile,0,&s_bstar2};
+
+
+
+/*
+==========================================================================
+=
+=                             Explosions
+=
+==========================================================================
+*/
+
+statetype s_altexplosion10 = {false,SPR_EXPLOSION19,3,NULL,0,NULL};
+statetype s_altexplosion9 = {false,SPR_EXPLOSION17,3,NULL,0,&s_altexplosion10};
+statetype s_altexplosion8 = {false,SPR_EXPLOSION15,3,NULL,0,&s_altexplosion9};
+statetype s_altexplosion7 = {false,SPR_EXPLOSION13,3,NULL,0,&s_altexplosion8};
+statetype s_altexplosion6 = {false,SPR_EXPLOSION11,3,NULL,0,&s_altexplosion7};
+statetype s_altexplosion5 = {false,SPR_EXPLOSION9,3,NULL,0,&s_altexplosion6};
+statetype s_altexplosion4 = {false,SPR_EXPLOSION7,3,NULL,0,&s_altexplosion5};
+statetype s_altexplosion3 = {false,SPR_EXPLOSION5,3,NULL,0,&s_altexplosion4};
+statetype s_altexplosion2 = {false,SPR_EXPLOSION3,3,T_Explosion,0,&s_altexplosion3};
+statetype s_altexplosion1 = {false,SPR_EXPLOSION1,3,NULL,0,&s_altexplosion2};
+
+
+
+
+
+statetype s_explosion20 = {false,SPR_EXPLOSION20,2,NULL,0,NULL};
+statetype s_explosion19 = {false,SPR_EXPLOSION19,2,NULL,0,&s_explosion20};
+statetype s_explosion18 = {false,SPR_EXPLOSION18,2,NULL,0,&s_explosion19};
+statetype s_explosion17 = {false,SPR_EXPLOSION17,2,NULL,0,&s_explosion18};
+statetype s_explosion16 = {false,SPR_EXPLOSION16,2,NULL,0,&s_explosion17};
+statetype s_explosion15 = {false,SPR_EXPLOSION15,2,NULL,0,&s_explosion16};
+statetype s_explosion14 = {false,SPR_EXPLOSION14,2,NULL,0,&s_explosion15};
+statetype s_explosion13 = {false,SPR_EXPLOSION13,2,NULL,0,&s_explosion14};
+statetype s_explosion12 = {false,SPR_EXPLOSION12,2,NULL,0,&s_explosion13};
+statetype s_explosion11 = {false,SPR_EXPLOSION11,2,NULL,0,&s_explosion12};
+statetype s_explosion10 = {false,SPR_EXPLOSION10,2,NULL,0,&s_explosion11};
+statetype s_explosion9 = {false,SPR_EXPLOSION9,2,NULL,0,&s_explosion10};
+statetype s_explosion8 = {false,SPR_EXPLOSION8,2,NULL,0,&s_explosion9};
+statetype s_explosion7 = {false,SPR_EXPLOSION7,2,NULL,0,&s_explosion8};
+statetype s_explosion6 = {false,SPR_EXPLOSION6,2,NULL,0,&s_explosion7};
+statetype s_explosion5 = {false,SPR_EXPLOSION5,2,NULL,0,&s_explosion6};
+statetype s_explosion4 = {false,SPR_EXPLOSION4,2,NULL,0,&s_explosion5};
+statetype s_explosion3 = {false,SPR_EXPLOSION3,2,T_Explosion,0,&s_explosion4};
+statetype s_explosion2 = {false,SPR_EXPLOSION2,2,NULL,0,&s_explosion3};
+statetype s_explosion1 = {false,SPR_EXPLOSION1,2,NULL,0,&s_explosion2};
+
+
+
+statetype s_grexplosion20 = {false,SPR_GROUNDEXPL20,2,T_Special,0,NULL};
+statetype s_grexplosion19 = {false,SPR_GROUNDEXPL19,2,NULL,0,&s_grexplosion20};
+statetype s_grexplosion18 = {false,SPR_GROUNDEXPL18,2,NULL,0,&s_grexplosion19};
+statetype s_grexplosion17 = {false,SPR_GROUNDEXPL17,2,NULL,0,&s_grexplosion18};
+statetype s_grexplosion16 = {false,SPR_GROUNDEXPL16,2,NULL,0,&s_grexplosion17};
+statetype s_grexplosion15 = {false,SPR_GROUNDEXPL15,2,NULL,0,&s_grexplosion16};
+statetype s_grexplosion14 = {false,SPR_GROUNDEXPL14,2,NULL,0,&s_grexplosion15};
+statetype s_grexplosion13 = {false,SPR_GROUNDEXPL13,2,NULL,0,&s_grexplosion14};
+statetype s_grexplosion12 = {false,SPR_GROUNDEXPL12,2,NULL,0,&s_grexplosion13};
+statetype s_grexplosion11 = {false,SPR_GROUNDEXPL11,2,NULL,0,&s_grexplosion12};
+statetype s_grexplosion10 = {false,SPR_GROUNDEXPL10,2,NULL,0,&s_grexplosion11};
+statetype s_grexplosion9 = {false,SPR_GROUNDEXPL9,2,NULL,0,&s_grexplosion10};
+statetype s_grexplosion8 = {false,SPR_GROUNDEXPL8,2,NULL,0,&s_grexplosion9};
+statetype s_grexplosion7 = {false,SPR_GROUNDEXPL7,2,NULL,0,&s_grexplosion8};
+statetype s_grexplosion6 = {false,SPR_GROUNDEXPL6,2,NULL,0,&s_grexplosion7};
+statetype s_grexplosion5 = {false,SPR_GROUNDEXPL5,2,NULL,0,&s_grexplosion6};
+statetype s_grexplosion4 = {false,SPR_GROUNDEXPL4,2,NULL,0,&s_grexplosion5};
+statetype s_grexplosion3 = {false,SPR_GROUNDEXPL3,2,T_Explosion,0,&s_grexplosion4};
+statetype s_grexplosion2 = {false,SPR_GROUNDEXPL2,2,NULL,0,&s_grexplosion3};
+statetype s_grexplosion1 = {false,SPR_GROUNDEXPL1,2,NULL,0,&s_grexplosion2};
+
+
+
+statetype s_staticexplosion25 = {false,SPR_STATICEXPL25,2,NULL,0,NULL};
+statetype s_staticexplosion24 = {false,SPR_STATICEXPL24,2,NULL,0,&s_staticexplosion25};
+statetype s_staticexplosion23 = {false,SPR_STATICEXPL23,2,NULL,0,&s_staticexplosion24};
+statetype s_staticexplosion22 = {false,SPR_STATICEXPL22,2,NULL,0,&s_staticexplosion23};
+statetype s_staticexplosion21 = {false,SPR_STATICEXPL21,2,NULL,0,&s_staticexplosion22};
+statetype s_staticexplosion20 = {false,SPR_STATICEXPL20,2,NULL,0,&s_staticexplosion21};
+statetype s_staticexplosion19 = {false,SPR_STATICEXPL19,2,NULL,0,&s_staticexplosion20};
+statetype s_staticexplosion18 = {false,SPR_STATICEXPL18,2,NULL,0,&s_staticexplosion19};
+statetype s_staticexplosion17 = {false,SPR_STATICEXPL17,2,NULL,0,&s_staticexplosion18};
+statetype s_staticexplosion16 = {false,SPR_STATICEXPL16,2,NULL,0,&s_staticexplosion17};
+statetype s_staticexplosion15 = {false,SPR_STATICEXPL15,2,NULL,0,&s_staticexplosion16};
+statetype s_staticexplosion14 = {false,SPR_STATICEXPL14,2,NULL,0,&s_staticexplosion15};
+statetype s_staticexplosion13 = {false,SPR_STATICEXPL13,2,NULL,0,&s_staticexplosion14};
+statetype s_staticexplosion12 = {false,SPR_STATICEXPL12,2,NULL,0,&s_staticexplosion13};
+statetype s_staticexplosion11 = {false,SPR_STATICEXPL11,2,NULL,0,&s_staticexplosion12};
+statetype s_staticexplosion10 = {false,SPR_STATICEXPL10,2,NULL,0,&s_staticexplosion11};
+statetype s_staticexplosion9 = {false,SPR_STATICEXPL9,2,NULL,0,&s_staticexplosion10};
+statetype s_staticexplosion8 = {false,SPR_STATICEXPL8,2,NULL,0,&s_staticexplosion9};
+statetype s_staticexplosion7 = {false,SPR_STATICEXPL7,2,NULL,0,&s_staticexplosion8};
+statetype s_staticexplosion6 = {false,SPR_STATICEXPL6,2,NULL,0,&s_staticexplosion7};
+statetype s_staticexplosion5 = {false,SPR_STATICEXPL5,2,NULL,0,&s_staticexplosion6};
+statetype s_staticexplosion4 = {false,SPR_STATICEXPL4,2,NULL,0,&s_staticexplosion5};
+statetype s_staticexplosion3 = {false,SPR_STATICEXPL3,2,T_Explosion,0,&s_staticexplosion4};
+statetype s_staticexplosion2 = {false,SPR_STATICEXPL2,2,NULL,0,&s_staticexplosion3};
+statetype s_staticexplosion1 = {false,SPR_STATICEXPL1,2,NULL,0,&s_staticexplosion2};
+
+
+
+statetype s_upblade16 = {false,UBLADE8,1,T_Path,0,&s_upblade1};
+statetype s_upblade15 = {false,UBLADE7,2,T_Path,0,&s_upblade16};
+statetype s_upblade14 = {false,UBLADE6,1,T_Path,0,&s_upblade15};
+statetype s_upblade13 = {false,UBLADE5,2,T_Path,0,&s_upblade14};
+statetype s_upblade12 = {false,UBLADE4,1,T_Path,0,&s_upblade13};
+statetype s_upblade11 = {false,UBLADE3,2,T_Path,0,&s_upblade12};
+statetype s_upblade10 = {false,UBLADE2,1,T_Path,0,&s_upblade11};
+statetype s_upblade9 = {false,UBLADE9,2,T_Path,0,&s_upblade10};
+statetype s_upblade8 = {false,UBLADE8,1,T_Path,0,&s_upblade9};
+statetype s_upblade7 = {false,UBLADE7,2,T_Path,0,&s_upblade8};
+statetype s_upblade6 = {false,UBLADE6,1,T_Path,0,&s_upblade7};
+statetype s_upblade5 = {false,UBLADE5,2,T_Path,0,&s_upblade6};
+statetype s_upblade4 = {false,UBLADE4,1,T_Path,0,&s_upblade5};
+statetype s_upblade3 = {false,UBLADE3,2,T_Path,0,&s_upblade4};
+statetype s_upblade2 = {false,UBLADE2,1,T_Path,0,&s_upblade3};
+statetype s_upblade1 = {false,UBLADE1,2,T_Path,SF_SOUND,&s_upblade2};
+
+
+statetype s_firejetup23 = {false,FIREJETUP23,3,T_Path,SF_CRUSH,&s_firejetup1};
+statetype s_firejetup22 = {false,FIREJETUP22,3,T_Path,SF_CRUSH,&s_firejetup23};
+statetype s_firejetup21 = {false,FIREJETUP21,3,T_Path,0,&s_firejetup22};
+statetype s_firejetup20 = {false,FIREJETUP20,3,T_Path,0,&s_firejetup21};
+statetype s_firejetup19 = {false,FIREJETUP19,3,T_Path,0,&s_firejetup20};
+statetype s_firejetup18 = {false,FIREJETUP18,3,T_Path,0,&s_firejetup19};
+statetype s_firejetup17 = {false,FIREJETUP17,3,T_Path,0,&s_firejetup18};
+statetype s_firejetup16 = {false,FIREJETUP16,3,T_Path,SF_CRUSH,&s_firejetup17};
+statetype s_firejetup15 = {false,FIREJETUP15,3,T_Path,SF_CRUSH,&s_firejetup16};
+statetype s_firejetup14 = {false,FIREJETUP14,3,T_Path,SF_CRUSH,&s_firejetup15};
+statetype s_firejetup13 = {false,FIREJETUP13,3,T_Path,0,&s_firejetup14};
+statetype s_firejetup12 = {false,FIREJETUP12,3,T_Path,0,&s_firejetup13};
+statetype s_firejetup11 = {false,FIREJETUP11,3,T_Path,0,&s_firejetup12};
+statetype s_firejetup10 = {false,FIREJETUP10,3,T_Path,0,&s_firejetup11};
+statetype s_firejetup9 = {false,FIREJETUP9,3,T_Path,0,&s_firejetup10};
+statetype s_firejetup8 = {false,FIREJETUP8,3,T_Path,SF_CRUSH,&s_firejetup9};
+statetype s_firejetup7 = {false,FIREJETUP7,3,T_Path,SF_CRUSH,&s_firejetup8};
+statetype s_firejetup6 = {false,FIREJETUP6,3,T_Path,SF_CRUSH,&s_firejetup7};
+statetype s_firejetup5 = {false,FIREJETUP5,3,T_Path,0,&s_firejetup6};
+statetype s_firejetup4 = {false,FIREJETUP4,3,T_Path,0,&s_firejetup5};
+statetype s_firejetup3 = {false,FIREJETUP3,3,T_Path,0,&s_firejetup4};
+statetype s_firejetup2 = {false,FIREJETUP2,3,T_Path,0,&s_firejetup3};
+statetype s_firejetup1 = {false,FIREJETUP1,70,T_Path,SF_SOUND,&s_firejetup2};
+
+
+
+statetype s_columndownup6 = {false,CRUSHDOWN7,5,NULL,0,&s_columndowndown1};
+statetype s_columndownup5 = {false,CRUSHDOWN6,5,NULL,0,&s_columndownup6};
+statetype s_columndownup4 = {false,CRUSHDOWN5,5,NULL,SF_BLOCK,&s_columndownup5};
+statetype s_columndownup3 = {false,CRUSHDOWN4,5,NULL,SF_BLOCK,&s_columndownup4};
+statetype s_columndownup2 = {false,CRUSHDOWN3,5,NULL,SF_BLOCK,&s_columndownup3};
+statetype s_columndownup1 = {false,CRUSHDOWN2,5,NULL,SF_BLOCK,&s_columndownup2};
+
+
+statetype s_columndowndown8 = {false,CRUSHDOWN1,5,T_CrushDown,SF_CRUSH|SF_DOWN|SF_BLOCK,&s_columndownup1};
+statetype s_columndowndown7 = {false,CRUSHDOWN2,5,T_CrushDown,SF_CRUSH|SF_DOWN|SF_BLOCK,&s_columndowndown8};
+statetype s_columndowndown6 = {false,CRUSHDOWN3,5,T_CrushDown,SF_DOWN|SF_BLOCK,&s_columndowndown7};
+statetype s_columndowndown5 = {false,CRUSHDOWN4,5,T_CrushDown,SF_DOWN|SF_BLOCK,&s_columndowndown6};
+statetype s_columndowndown4 = {false,CRUSHDOWN5,5,T_CrushDown,SF_DOWN,&s_columndowndown5};
+statetype s_columndowndown3 = {false,CRUSHDOWN6,5,T_CrushDown,SF_DOWN,&s_columndowndown4};
+statetype s_columndowndown2 = {false,CRUSHDOWN7,5,T_CrushDown,SF_DOWN,&s_columndowndown3};
+statetype s_columndowndown1 = {false,CRUSHDOWN8,30,T_CrushDown,SF_DOWN|SF_SOUND,&s_columndowndown2};
+
+
+statetype s_spearup16 = {false,SPEARUP16,2,T_Spears,SF_CRUSH,&s_spearup1};
+statetype s_spearup15 = {false,SPEARUP15,2,T_Spears,SF_CRUSH,&s_spearup16};
+statetype s_spearup14 = {false,SPEARUP14,2,T_Spears,SF_CRUSH,&s_spearup15};
+statetype s_spearup13 = {false,SPEARUP13,2,T_Spears,SF_CRUSH,&s_spearup14};
+statetype s_spearup12 = {false,SPEARUP12,2,T_Spears,SF_CRUSH,&s_spearup13};
+statetype s_spearup11 = {false,SPEARUP11,2,T_Spears,SF_CRUSH,&s_spearup12};
+statetype s_spearup10 = {false,SPEARUP10,2,T_Spears,SF_CRUSH,&s_spearup11};
+statetype s_spearup9 = {false,SPEARUP9,2,T_Spears,SF_DOWN,&s_spearup10};
+
+statetype s_spearup8 = {false,SPEARUP8,35,T_Spears,SF_DOWN|SF_SOUND,&s_spearup9};
+statetype s_spearup7 = {false,SPEARUP7,2,T_Spears,SF_DOWN,&s_spearup8};
+statetype s_spearup6 = {false,SPEARUP6,2,T_Spears,SF_CRUSH,&s_spearup7};
+statetype s_spearup5 = {false,SPEARUP5,2,T_Spears,SF_CRUSH,&s_spearup6};
+statetype s_spearup4 = {false,SPEARUP4,2,T_Spears,SF_CRUSH,&s_spearup5};
+statetype s_spearup3 = {false,SPEARUP3,2,T_Spears,SF_CRUSH,&s_spearup4};
+statetype s_spearup2 = {false,SPEARUP2,2,T_Spears,SF_CRUSH,&s_spearup3};
+statetype s_spearup1 = {false,SPEARUP1,2,T_Spears,SF_CRUSH,&s_spearup2};
+
+
+statetype s_dust = {false,NOTHING,0,NULL,0,&s_dust};
+
+
+
+statetype s_gas2 = {false,SPR42_GRATE,5,T_Count,0,&s_gas2};
+statetype s_gas1 = {false,SPR42_GRATE,0,NULL,0,&s_gas1};
+
+
+//================== player stuff =======================================/
+
+statetype s_p_bazooka1 = {16,SPR_BJMISS11,3,T_Projectile,0,&s_p_bazooka1};
+
+statetype s_p_grenade = {16,SPR_BJMISS11,3,T_Projectile,0,&s_p_grenade};
+
+/*
+statetype s_p_misssmoke4 = {false,MISSSMOKE4,7,NULL,0,NULL};
+statetype s_p_misssmoke3 = {false,MISSSMOKE3,7,NULL,0,&s_p_misssmoke4};
+statetype s_p_misssmoke2 = {false,MISSSMOKE2,7,NULL,0,&s_p_misssmoke3};
+statetype s_p_misssmoke1 = {false,MISSSMOKE1,3,NULL,0,&s_p_misssmoke2};
+*/
+
+
+statetype s_basemarker8 = {false,FLASH8,3,NULL,0,&s_basemarker1};
+statetype s_basemarker7 = {false,FLASH7,3,NULL,0,&s_basemarker8};
+statetype s_basemarker6 = {false,FLASH6,3,NULL,0,&s_basemarker7};
+statetype s_basemarker5 = {false,FLASH5,3,NULL,0,&s_basemarker6};
+statetype s_basemarker4 = {false,FLASH4,3,NULL,0,&s_basemarker5};
+statetype s_basemarker3 = {false,FLASH3,3,NULL,0,&s_basemarker4};
+statetype s_basemarker2 = {false,FLASH2,3,NULL,0,&s_basemarker3};
+statetype s_basemarker1 = {false,FLASH1,3,NULL,0,&s_basemarker2};
+
+
+
+statetype s_flash8 = {false,FLASH8,3,NULL,0,NULL};
+statetype s_flash7 = {false,FLASH7,3,NULL,0,&s_flash8};
+statetype s_flash6 = {false,FLASH6,3,NULL,0,&s_flash7};
+statetype s_flash5 = {false,FLASH5,3,NULL,0,&s_flash6};
+statetype s_flash4 = {false,FLASH4,3,NULL,0,&s_flash5};
+statetype s_flash3 = {false,FLASH3,3,NULL,0,&s_flash4};
+statetype s_flash2 = {false,FLASH2,3,NULL,0,&s_flash3};
+statetype s_flash1 = {false,FLASH1,3,NULL,0,&s_flash2};
+
+statetype s_gunsmoke8 = {false,GUNSMOKE8,3,NULL,0,NULL};
+statetype s_gunsmoke7 = {false,GUNSMOKE7,3,NULL,0,&s_gunsmoke8};
+statetype s_gunsmoke6 = {false,GUNSMOKE6,3,NULL,0,&s_gunsmoke7};
+statetype s_gunsmoke5 = {false,GUNSMOKE5,3,NULL,0,&s_gunsmoke6};
+statetype s_gunsmoke4 = {false,GUNSMOKE4,3,NULL,0,&s_gunsmoke5};
+statetype s_gunsmoke3 = {false,GUNSMOKE3,3,NULL,0,&s_gunsmoke4};
+statetype s_gunsmoke2 = {false,GUNSMOKE2,3,NULL,0,&s_gunsmoke3};
+statetype s_gunsmoke1 = {false,GUNSMOKE1,2,NULL,0,&s_gunsmoke2};
+
+statetype s_bloodspurt8 = {false,BLOODSPURT8,7,NULL,0,NULL};
+statetype s_bloodspurt7 = {false,BLOODSPURT7,7,NULL,0,&s_bloodspurt8};
+statetype s_bloodspurt6 = {false,BLOODSPURT6,7,NULL,0,&s_bloodspurt7};
+statetype s_bloodspurt5 = {false,BLOODSPURT5,7,NULL,0,&s_bloodspurt6};
+statetype s_bloodspurt4 = {false,BLOODSPURT4,7,NULL,0,&s_bloodspurt5};
+statetype s_bloodspurt3 = {false,BLOODSPURT3,7,NULL,0,&s_bloodspurt4};
+statetype s_bloodspurt2 = {false,BLOODSPURT2,7,NULL,0,&s_bloodspurt3};
+statetype s_bloodspurt1 = {false,BLOODSPURT1,5,NULL,0,&s_bloodspurt2};
+
+statetype s_hitmetalwall4 = {false,HITMETALWALL4,7,NULL,0,NULL};
+statetype s_hitmetalwall3 = {false,HITMETALWALL3,7,NULL,0,&s_hitmetalwall4};
+statetype s_hitmetalwall2 = {false,HITMETALWALL2,7,NULL,0,&s_hitmetalwall3};
+statetype s_hitmetalwall1 = {false,HITMETALWALL1,5,NULL,0,&s_hitmetalwall2};
+
+statetype s_hitmetalactor4 = {false,HITMETALACTOR4,7,NULL,0,NULL};
+statetype s_hitmetalactor3 = {false,HITMETALACTOR3,7,NULL,0,&s_hitmetalactor4};
+statetype s_hitmetalactor2 = {false,HITMETALACTOR2,7,NULL,0,&s_hitmetalactor3};
+statetype s_hitmetalactor1 = {false,HITMETALACTOR1,5,NULL,0,&s_hitmetalactor2};
+
+
+
+statetype s_fireunit15 = {false,FIREW15,3,T_Firethink,0,&s_fireunit1};
+statetype s_fireunit14 = {false,FIREW14,3,T_Firethink,0,&s_fireunit15};
+statetype s_fireunit13 = {false,FIREW13,3,T_Firethink,0,&s_fireunit14};
+statetype s_fireunit12 = {false,FIREW12,3,T_Firethink,0,&s_fireunit13};
+statetype s_fireunit11 = {false,FIREW11,3,T_Firethink,0,&s_fireunit12};
+statetype s_fireunit10 = {false,FIREW10,3,T_Firethink,0,&s_fireunit11};
+statetype s_fireunit9 = {false,FIREW9,3,T_Firethink,0,&s_fireunit10};
+statetype s_fireunit8 = {false,FIREW8,3,T_Firethink,0,&s_fireunit9};
+statetype s_fireunit7 = {false,FIREW7,3,T_Firethink,0,&s_fireunit8};
+statetype s_fireunit6 = {false,FIREW6,3,T_Firethink,0,&s_fireunit7};
+statetype s_fireunit5 = {false,FIREW5,3,T_Firethink,0,&s_fireunit6};
+statetype s_fireunit4 = {false,FIREW4,3,T_Firethink,0,&s_fireunit5};
+statetype s_fireunit3 = {false,FIREW3,3,T_Firethink,0,&s_fireunit4};
+statetype s_fireunit2 = {false,FIREW2,3,T_Firethink,0,&s_fireunit3};
+statetype s_fireunit1 = {false,FIREW1,3,T_Firethink,0,&s_fireunit2};
+
+
+
+statetype s_skeleton48 = {false,SKELETON48,0,T_Convert,0,&s_skeleton48};
+statetype s_skeleton47 = {false,SKELETON47,2,NULL,0,&s_skeleton48};
+statetype s_skeleton46 = {false,SKELETON46,2,NULL,0,&s_skeleton47};
+statetype s_skeleton45 = {false,SKELETON45,2,NULL,0,&s_skeleton46};
+statetype s_skeleton44 = {false,SKELETON44,2,NULL,0,&s_skeleton45};
+statetype s_skeleton43 = {false,SKELETON43,2,NULL,0,&s_skeleton44};
+statetype s_skeleton42 = {false,SKELETON42,2,NULL,0,&s_skeleton43};
+statetype s_skeleton41 = {false,SKELETON41,2,T_Xylophone,0,&s_skeleton42};
+statetype s_skeleton40 = {false,SKELETON40,2,NULL,0,&s_skeleton41};
+statetype s_skeleton39 = {false,SKELETON39,2,NULL,0,&s_skeleton40};
+statetype s_skeleton38 = {false,SKELETON38,2,NULL,0,&s_skeleton39};
+statetype s_skeleton37 = {false,SKELETON37,2,NULL,0,&s_skeleton38};
+statetype s_skeleton36 = {false,SKELETON36,2,NULL,0,&s_skeleton37};
+statetype s_skeleton35 = {false,SKELETON35,2,NULL,0,&s_skeleton36};
+statetype s_skeleton34 = {false,SKELETON34,2,NULL,0,&s_skeleton35};
+statetype s_skeleton33 = {false,SKELETON33,2,NULL,0,&s_skeleton34};
+statetype s_skeleton32 = {false,SKELETON32,2,NULL,0,&s_skeleton33};
+statetype s_skeleton31 = {false,SKELETON31,2,NULL,0,&s_skeleton32};
+statetype s_skeleton30 = {false,SKELETON30,2,NULL,0,&s_skeleton31};
+statetype s_skeleton29 = {false,SKELETON29,2,NULL,0,&s_skeleton30};
+statetype s_skeleton28 = {false,SKELETON28,2,NULL,0,&s_skeleton29};
+statetype s_skeleton27 = {false,SKELETON27,2,NULL,0,&s_skeleton28};
+statetype s_skeleton26 = {false,SKELETON26,2,NULL,0,&s_skeleton27};
+statetype s_skeleton25 = {false,SKELETON25,2,NULL,0,&s_skeleton26};
+statetype s_skeleton24 = {false,SKELETON24,2,NULL,0,&s_skeleton25};
+statetype s_skeleton23 = {false,SKELETON23,2,NULL,0,&s_skeleton24};
+statetype s_skeleton22 = {false,SKELETON22,2,NULL,0,&s_skeleton23};
+statetype s_skeleton21 = {false,SKELETON21,2,NULL,0,&s_skeleton22};
+statetype s_skeleton20 = {false,SKELETON20,2,NULL,0,&s_skeleton21};
+statetype s_skeleton19 = {false,SKELETON19,2,NULL,0,&s_skeleton20};
+statetype s_skeleton18 = {false,SKELETON18,2,NULL,0,&s_skeleton19};
+statetype s_skeleton17 = {false,SKELETON17,2,NULL,0,&s_skeleton18};
+statetype s_skeleton16 = {false,SKELETON16,2,NULL,0,&s_skeleton17};
+statetype s_skeleton15 = {false,SKELETON15,2,NULL,0,&s_skeleton16};
+statetype s_skeleton14 = {false,SKELETON14,2,NULL,0,&s_skeleton15};
+statetype s_skeleton13 = {false,SKELETON13,2,NULL,0,&s_skeleton14};
+statetype s_skeleton12 = {false,SKELETON12,2,NULL,0,&s_skeleton13};
+statetype s_skeleton11 = {false,SKELETON11,2,NULL,0,&s_skeleton12};
+statetype s_skeleton10 = {false,SKELETON10,2,NULL,0,&s_skeleton11};
+statetype s_skeleton9 = {false,SKELETON9,2,NULL,0,&s_skeleton10};
+statetype s_skeleton8 = {false,SKELETON8,2,NULL,0,&s_skeleton9};
+statetype s_skeleton7 = {false,SKELETON7,2,NULL,0,&s_skeleton8};
+statetype s_skeleton6 = {false,SKELETON6,2,NULL,0,&s_skeleton7};
+statetype s_skeleton5 = {false,SKELETON5,2,NULL,0,&s_skeleton6};
+statetype s_skeleton4 = {false,SKELETON4,2,NULL,0,&s_skeleton5};
+statetype s_skeleton3 = {false,SKELETON3,2,NULL,0,&s_skeleton4};
+statetype s_skeleton2 = {false,SKELETON2,2,NULL,0,&s_skeleton3};
+statetype s_skeleton1 = {false,SKELETON1,2,NULL,0,&s_skeleton2};
+
+
+
+statetype s_spring9 = {false,SPRING9,4,T_Spring,SF_DOWN,&s_spring1};
+statetype s_spring8 = {false,SPRING8,4,NULL,0,&s_spring9};
+statetype s_spring7 = {false,SPRING7,4,NULL,0,&s_spring8};
+statetype s_spring6 = {false,SPRING6,4,NULL,0,&s_spring7};
+statetype s_spring5 = {false,SPRING5,4,NULL,0,&s_spring6};
+statetype s_spring4 = {false,SPRING4,15,NULL,SF_UP,&s_spring5};
+statetype s_spring3 = {false,SPRING3,1,NULL,SF_UP,&s_spring4};
+statetype s_spring2 = {false,SPRING2,1,NULL,SF_UP,&s_spring3};
+statetype s_spring1 = {false,SPRING1,0,NULL,SF_UP,&s_spring1};
+
+
+statetype s_autospring9 = {false,SPRING9,4,NULL,0,&s_autospring1};
+statetype s_autospring8 = {false,SPRING8,4,NULL,0,&s_autospring9};
+statetype s_autospring7 = {false,SPRING7,4,NULL,0,&s_autospring8};
+statetype s_autospring6 = {false,SPRING6,4,NULL,0,&s_autospring7};
+statetype s_autospring5 = {false,SPRING5,4,NULL,0,&s_autospring6};
+statetype s_autospring4 = {false,SPRING4,15,NULL,SF_UP,&s_autospring5};
+statetype s_autospring3 = {false,SPRING3,1,T_Spring,SF_UP,&s_autospring4};
+statetype s_autospring2 = {false,SPRING2,1,T_Spring,SF_UP,&s_autospring3};
+statetype s_autospring1 = {false,SPRING1,70*SPRINGDELAY,NULL,0,&s_autospring2};
+
+//====================== remote player ==============================//
+
+statetype s_itemspawn8 = {false,ITEMSPAWN8,6,NULL,0,NULL};
+statetype s_itemspawn7 = {false,ITEMSPAWN7,6,NULL,0,&s_itemspawn8};
+statetype s_itemspawn6 = {false,ITEMSPAWN6,6,NULL,0,&s_itemspawn7};
+statetype s_itemspawn5 = {false,ITEMSPAWN5,6,NULL,0,&s_itemspawn6};
+statetype s_itemspawn4 = {false,ITEMSPAWN4,6,NULL,0,&s_itemspawn5};
+statetype s_itemspawn3 = {false,ITEMSPAWN3,6,NULL,0,&s_itemspawn4};
+statetype s_itemspawn2 = {false,ITEMSPAWN2,6,NULL,0,&s_itemspawn3};
+statetype s_itemspawn1 = {false,ITEMSPAWN1,6,NULL,0,&s_itemspawn2};
+
+
+statetype s_player = {true,CASSATT_S1,0,T_Player,0,&s_player};
+
+statetype s_pgunattack2 = {true,CASSATT_SHOOT11,0,T_Attack,0,&s_pgunattack2};
+statetype s_pgunattack1 = {true,CASSATT_SHOOT21,5,T_Attack,0,&s_pgunattack2};
+
+statetype s_pmissattack2 = {true,CASSATTM_SHOOT11,0,T_Attack,0,&s_pmissattack2};
+statetype s_pmissattack1 = {true,CASSATTM_SHOOT21,5,T_Attack,0,&s_pmissattack2};
+
+statetype s_pbatblast = {true,CASSATT_SHOOT21,0,T_BatBlast,0,&s_pbatblast};
+
+
+
+
+statetype s_remotemove4 = {true,CASSATT_W41,5,T_Player,SF_DOWN,&s_remotemove1};
+statetype s_remotemove3 = {true,CASSATT_W31,5,T_Player,SF_DOWN,&s_remotemove4};
+statetype s_remotemove2 = {true,CASSATT_W21,5,T_Player,SF_DOWN,&s_remotemove3};
+statetype s_remotemove1 = {true,CASSATT_W11,5,T_Player,SF_DOWN,&s_remotemove2};
+
+statetype s_remoteinelev = {true,CASSATT_S1,700,T_Player,0,&s_remoteinelev};
+
+statetype s_remotedead = {false,CASSATT_VDEAD,0,T_Player,0,&s_remotedead};
+
+
+
+statetype s_remotedie6 = {false,CASSATT_VDIE6,3,T_Player,0,&s_remotedead};
+statetype s_remotedie5 = {false,CASSATT_VDIE5,3,T_Player,0,&s_remotedie6};
+statetype s_remotedie4 = {false,CASSATT_VDIE4,3,T_Player,0,&s_remotedie5};
+statetype s_remotedie3 = {false,CASSATT_VDIE3,3,T_Player,0,&s_remotedie4};
+statetype s_remotedie2 = {false,CASSATT_VDIE2,3,T_Player,0,&s_remotedie3};
+statetype s_remotedie1 = {false,CASSATT_VDIE1,3,T_Player,0,&s_remotedie2};
+
+
+statetype s_voidwait = {false,NOTHING,0,T_DeadWait,0,&s_voidwait};
+statetype s_ashwait = {false,SKELETON48,0,T_DeadWait,0,&s_ashwait};
+statetype s_deadwait = {false,CASSATT_VDEAD,0,T_DeadWait,0,&s_deadwait};
+statetype s_gutwait = {false,GUTS12,0,T_DeadWait,0,&s_gutwait};
+statetype s_remoteguts12 = {false,GUTS12,0,T_Player,0,&s_remoteguts12};
+statetype s_remoteguts11 = {false,GUTS11,3,T_Player,0,&s_remoteguts12};
+statetype s_remoteguts10 = {false,GUTS10,3,T_Player,0,&s_remoteguts11};
+statetype s_remoteguts9 = {false,GUTS9,3,T_Player,0,&s_remoteguts10};
+statetype s_remoteguts8 = {false,GUTS8,3,T_Player,0,&s_remoteguts9};
+statetype s_remoteguts7 = {false,GUTS7,3,T_Player,0,&s_remoteguts8};
+statetype s_remoteguts6 = {false,GUTS6,3,T_Player,0,&s_remoteguts7};
+statetype s_remoteguts5 = {false,GUTS5,3,T_Player,0,&s_remoteguts6};
+statetype s_remoteguts4 = {false,GUTS4,3,T_Player,0,&s_remoteguts5};
+statetype s_remoteguts3 = {false,GUTS3,3,T_Player,0,&s_remoteguts4};
+statetype s_remoteguts2 = {false,GUTS2,3,T_Player,0,&s_remoteguts3};
+statetype s_remoteguts1 = {false,GUTS1,3,T_Player,0,&s_remoteguts2};
+
+//========================================================================//
+
+statetype s_godfire4 = {false,GODFIRE4,3,T_Projectile,0,&s_godfire1};
+statetype s_godfire3 = {false,GODFIRE3,3,T_Projectile,0,&s_godfire4};
+statetype s_godfire2 = {false,GODFIRE2,3,T_Projectile,0,&s_godfire3};
+statetype s_godfire1 = {false,GODFIRE1,3,T_Projectile,0,&s_godfire2};
+
+
+
+
+statetype s_guts12 = {false,GUTS12,0,T_Collide,SF_GUTS,&s_guts12};
+statetype s_guts11 = {false,GUTS11,3,T_Collide,SF_GUTS,&s_guts12};
+statetype s_guts10 = {false,GUTS10,3,T_Collide,SF_GUTS,&s_guts11};
+statetype s_guts9 = {false,GUTS9,3,T_Collide,SF_GUTS,&s_guts10};
+statetype s_guts8 = {false,GUTS8,3,T_Collide,SF_GUTS,&s_guts9};
+statetype s_guts7 = {false,GUTS7,3,T_Collide,SF_GUTS,&s_guts8};
+statetype s_guts6 = {false,GUTS6,3,T_Collide,SF_GUTS,&s_guts7};
+statetype s_guts5 = {false,GUTS5,3,T_Collide,SF_GUTS,&s_guts6};
+statetype s_guts4 = {false,GUTS4,3,T_Collide,SF_GUTS,&s_guts5};
+statetype s_guts3 = {false,GUTS3,3,T_Collide,SF_GUTS,&s_guts4};
+statetype s_guts2 = {false,GUTS2,3,T_Collide,SF_GUTS,&s_guts3};
+statetype s_guts1 = {false,GUTS1,3,T_Collide,SF_GUTS,&s_guts2};
+
+//MED
+#if (SHAREWARE == 1) || (DOPEFISH == 0)
+statetype s_collectorwander8 = {false,COLLECTOR15,0,T_CollectorWander,0,&s_collectorwander1};
+statetype s_collectorwander7 = {false,COLLECTOR13,1,T_CollectorWander,0,&s_collectorwander8};
+statetype s_collectorwander6 = {false,COLLECTOR11,0,T_CollectorWander,0,&s_collectorwander7};
+statetype s_collectorwander5 = {false,COLLECTOR9,1,T_CollectorWander,0,&s_collectorwander6};
+statetype s_collectorwander4 = {false,COLLECTOR7,0,T_CollectorWander,0,&s_collectorwander5};
+statetype s_collectorwander3 = {false,COLLECTOR5,1,T_CollectorWander,0,&s_collectorwander4};
+statetype s_collectorwander2 = {false,COLLECTOR3,0,T_CollectorWander,0,&s_collectorwander3};
+statetype s_collectorwander1 = {false,COLLECTOR1,1,T_CollectorWander,0,&s_collectorwander2};
+#else
+
+statetype s_collectorwander8 = {false,DOPE8,2,T_CollectorWander,0,&s_collectorwander1};
+statetype s_collectorwander7 = {false,DOPE7,2,T_CollectorWander,0,&s_collectorwander8};
+statetype s_collectorwander6 = {false,DOPE6,2,T_CollectorWander,0,&s_collectorwander7};
+statetype s_collectorwander5 = {false,DOPE5,2,T_CollectorWander,0,&s_collectorwander6};
+statetype s_collectorwander4 = {false,DOPE4,2,T_CollectorWander,0,&s_collectorwander5};
+statetype s_collectorwander3 = {false,DOPE3,2,T_CollectorWander,0,&s_collectorwander4};
+statetype s_collectorwander2 = {false,DOPE2,2,T_CollectorWander,0,&s_collectorwander3};
+statetype s_collectorwander1 = {false,DOPE1,2,T_CollectorWander,0,&s_collectorwander2};
+#endif
+
+
+//MED
+#if (SHAREWARE == 1) || (DOPEFISH == 0)
+statetype s_collectorfdoor8 = {false,COLLECTOR15,0,T_CollectorFindDoor,0,&s_collectorfdoor1};
+statetype s_collectorfdoor7 = {false,COLLECTOR13,1,T_CollectorFindDoor,0,&s_collectorfdoor8};
+statetype s_collectorfdoor6 = {false,COLLECTOR11,0,T_CollectorFindDoor,0,&s_collectorfdoor7};
+statetype s_collectorfdoor5 = {false,COLLECTOR9,1,T_CollectorFindDoor,0,&s_collectorfdoor6};
+statetype s_collectorfdoor4 = {false,COLLECTOR7,0,T_CollectorFindDoor,0,&s_collectorfdoor5};
+statetype s_collectorfdoor3 = {false,COLLECTOR5,1,T_CollectorFindDoor,0,&s_collectorfdoor4};
+statetype s_collectorfdoor2 = {false,COLLECTOR3,0,T_CollectorFindDoor,0,&s_collectorfdoor3};
+statetype s_collectorfdoor1 = {false,COLLECTOR1,1,T_CollectorFindDoor,0,&s_collectorfdoor2};
+#else
+
+statetype s_collectorfdoor8 = {false,DOPE8,2,T_CollectorFindDoor,0,&s_collectorfdoor1};
+statetype s_collectorfdoor7 = {false,DOPE7,2,T_CollectorFindDoor,0,&s_collectorfdoor8};
+statetype s_collectorfdoor6 = {false,DOPE6,2,T_CollectorFindDoor,0,&s_collectorfdoor7};
+statetype s_collectorfdoor5 = {false,DOPE5,2,T_CollectorFindDoor,0,&s_collectorfdoor6};
+statetype s_collectorfdoor4 = {false,DOPE4,2,T_CollectorFindDoor,0,&s_collectorfdoor5};
+statetype s_collectorfdoor3 = {false,DOPE3,2,T_CollectorFindDoor,0,&s_collectorfdoor4};
+statetype s_collectorfdoor2 = {false,DOPE2,2,T_CollectorFindDoor,0,&s_collectorfdoor3};
+statetype s_collectorfdoor1 = {false,DOPE1,2,T_CollectorFindDoor,0,&s_collectorfdoor2};
+
+#endif
+
+statetype s_timekeeper = {false,NOTHING,140,T_End,0,NULL};
+
+statetype s_wind = {false,-1,10,T_Wind,0,&s_wind};
+
+
+statetype s_deadblood8 = {false,NOTHING,0,T_Blood,0,&s_deadblood8};
+statetype s_deadblood7 = {false,DEADBLOOD7,5,NULL,0,&s_deadblood8};
+statetype s_deadblood6 = {false,DEADBLOOD6,5,NULL,0,&s_deadblood7};
+statetype s_deadblood5 = {false,DEADBLOOD5,5,NULL,0,&s_deadblood6};
+statetype s_deadblood4 = {false,DEADBLOOD4,5,NULL,0,&s_deadblood5};
+statetype s_deadblood3 = {false,DEADBLOOD3,5,NULL,0,&s_deadblood4};
+statetype s_deadblood2 = {false,DEADBLOOD2,5,NULL,0,&s_deadblood3};
+statetype s_deadblood1 = {false,DEADBLOOD1,5,NULL,0,&s_deadblood2};
+
+/*
+statetype s_rain7 = {false,RAINDROP6,0,NULL,0,NULL};
+statetype s_rain6 = {false,RAINDROP5,3,NULL,0,&s_rain7};
+statetype s_rain5 = {false,RAINDROP4,0,NULL,0,&s_rain6};
+statetype s_rain4 = {false,RAINDROP3,3,NULL,0,&s_rain5};
+statetype s_rain3 = {false,RAINDROP2,0,NULL,0,&s_rain4};
+statetype s_rain2 = {false,RAINDROP1,0,T_RainFall,0,&s_rain2};
+statetype s_rain1 = {false,NOTHING,50,T_RainSpawn,0,&s_rain1};
+
+statetype s_rainmaster = {false,NOTHING,0,T_RainMaster,0,&s_rainmaster};
+*/
+
+statetype s_pathdisk = {false,PLATFORM1,0,T_Path,0,&s_pathdisk};
+statetype s_elevdisk = {false,PLATFORM1,0,T_ElevDisk,0,&s_elevdisk};
+
+statetype s_diskmaster = {false,NOTHING,0,T_ElevDisk,0,&s_diskmaster};
+
+
+
+statetype s_blooddrip4 = {false,WALLGIB4,3,T_BloodFall,0,&s_blooddrip1};
+statetype s_blooddrip3 = {false,WALLGIB3,3,T_BloodFall,0,&s_blooddrip4};
+statetype s_blooddrip2 = {false,WALLGIB2,3,T_BloodFall,0,&s_blooddrip3};
+statetype s_blooddrip1 = {false,WALLGIB1,3,T_BloodFall,0,&s_blooddrip2};
+
+
+
+//==================== Push column =====================================//
+
+
+statetype s_pushcolumn1 = {false,SPR_PUSHCOLUMN1,6,T_MoveColumn,0,&s_pushcolumn1};
+statetype s_pushcolumn2 = {false,SPR_PUSHCOLUMN1,6,T_MoveColumn,0,&s_pushcolumn2};
+statetype s_pushcolumn3 = {false,SPR_PUSHCOLUMN1,6,T_MoveColumn,0,&s_pushcolumn3};
+
+
+//=================== Wall Fire =======================================/
+
+statetype s_wallfireball = {false,NOTHING,50,A_Wallfire,0,&s_wallfireball};
+
+statetype s_crossfire2 = {true,SPR_CROSSFIRE31,6,T_Projectile,0,&s_crossfire1};
+statetype s_crossfire1 = {true,SPR_CROSSFIRE11,6,T_Projectile,0,&s_crossfire2};
+
+statetype s_crossdone5 = {false,SPR_CREXP5,6,NULL,0,NULL};
+statetype s_crossdone4 = {false,SPR_CREXP4,6,NULL,0,&s_crossdone5};
+statetype s_crossdone3 = {false,SPR_CREXP3,6,NULL,0,&s_crossdone4};
+statetype s_crossdone2 = {false,SPR_CREXP2,6,NULL,0,&s_crossdone3};
+statetype s_crossdone1 = {false,SPR_CREXP1,6,NULL,0,&s_crossdone2};
+
+
+
+//=============== gib/related states ===========================================//
+
+
+statetype s_bossdeath = {false,NOTHING,140,T_BossDied,0,NULL};
+
+statetype s_megaremove     = {false,NOTHING,0,NULL,0,NULL};
+statetype s_megaexplosions = {false,NOTHING,0,T_BossExplosions,0,&s_megaexplosions};
+statetype s_superparticles = {false,NOTHING,0,T_ParticleGenerate,0,&s_superparticles};
+
+
+statetype s_gibsdone8 = {false,PARTICLE12,2,NULL,0,NULL};
+statetype s_gibsdone7 = {false,PARTICLE11,2,NULL,0,&s_gibsdone8};
+//MED
+statetype s_gibsdone6 = {false,PARTICLE10,2,NULL,0,&s_gibsdone7};
+statetype s_gibsdone5 = {false,PARTICLE09,2,NULL,0,&s_gibsdone6};
+statetype s_gibsdone4 = {false,PARTICLE08,2,NULL,0,&s_gibsdone5};
+statetype s_gibsdone3 = {false,PARTICLE07,2,NULL,0,&s_gibsdone4};
+statetype s_gibsdone2 = {false,PARTICLE06,2,NULL,0,&s_gibsdone3};
+statetype s_gibsdone1 = {false,PARTICLE05,2,NULL,0,&s_gibsdone2};
+
+statetype s_gibs4 = {false,PARTICLE04,2,T_Particle,0,&s_gibs1};
+statetype s_gibs3 = {false,PARTICLE03,2,T_Particle,0,&s_gibs4};
+statetype s_gibs2 = {false,PARTICLE02,2,T_Particle,0,&s_gibs3};
+statetype s_gibs1 = {false,PARTICLE01,2,T_Particle,0,&s_gibs2};
+
+
+
+//statetype s_head = {false,DEADHEAD,4200,NULL,0,&s_gibsdone2};
+
+statetype s_eye3 = {false,NOTHING,7,T_SlideDownScreen,SF_EYE3,&s_eye1};
+statetype s_eye2 = {false,NOTHING,7,T_SlideDownScreen,SF_EYE2,&s_eye3};
+statetype s_eye1 = {false,NOTHING,7,T_SlideDownScreen,SF_EYE1,&s_eye2};
+
+statetype s_littlesoul = {false,LITTLESOUL,0,MissileMovement,0,&s_littlesoul};
+statetype s_bigsoul = {false,BIGSOUL,0,MissileMovement,0,&s_bigsoul};
+
+
+statetype s_vaporized8 = {false,VAPORIZED8,0,T_Convert,0,NULL};
+statetype s_vaporized7 = {false,VAPORIZED7,3,NULL,0,&s_vaporized8};
+statetype s_vaporized6 = {false,VAPORIZED6,3,NULL,0,&s_vaporized7};
+statetype s_vaporized5 = {false,VAPORIZED5,3,NULL,0,&s_vaporized6};
+statetype s_vaporized4 = {false,VAPORIZED4,3,NULL,0,&s_vaporized5};
+statetype s_vaporized3 = {false,VAPORIZED3,3,NULL,0,&s_vaporized4};
+statetype s_vaporized2 = {false,VAPORIZED2,3,NULL,0,&s_vaporized3};
+statetype s_vaporized1 = {false,VAPORIZED1,3,NULL,0,&s_vaporized2};
+
+statetype s_respawn8 = {false,VAPORIZED1,0,SetShapeoffset,0,&s_player};
+statetype s_respawn7 = {false,VAPORIZED2,3,NULL,0,&s_respawn8};
+statetype s_respawn6 = {false,VAPORIZED3,3,NULL,0,&s_respawn7};
+statetype s_respawn5 = {false,VAPORIZED4,3,NULL,0,&s_respawn6};
+statetype s_respawn4 = {false,VAPORIZED5,3,NULL,0,&s_respawn5};
+statetype s_respawn3 = {false,VAPORIZED6,3,NULL,0,&s_respawn4};
+statetype s_respawn2 = {false,VAPORIZED7,3,NULL,0,&s_respawn3};
+statetype s_respawn1 = {false,VAPORIZED8,3,NULL,0,&s_respawn2};
+
+
+
+#if (SHAREWARE == 0)
+
+
+//========================= NON-SHAREWARE STATES ============================
+
+
+statetype s_scottwander7 = {false,SCOTHEAD7,4,T_CollectorWander,0,&s_scottwander1};
+statetype s_scottwander6 = {false,SCOTHEAD6,4,T_CollectorWander,0,&s_scottwander7};
+statetype s_scottwander5 = {false,SCOTHEAD5,4,T_CollectorWander,0,&s_scottwander6};
+statetype s_scottwander4 = {false,SCOTHEAD4,4,T_CollectorWander,0,&s_scottwander5};
+statetype s_scottwander3 = {false,SCOTHEAD3,4,T_CollectorWander,0,&s_scottwander4};
+statetype s_scottwander2 = {false,SCOTHEAD2,4,T_CollectorWander,0,&s_scottwander3};
+statetype s_scottwander1 = {false,SCOTHEAD1,4,T_CollectorWander,0,&s_scottwander2};
+
+statetype s_scottwanderdoor7 = {false,SCOTHEAD7,4,T_CollectorWander,0,&s_scottwanderdoor1};
+statetype s_scottwanderdoor6 = {false,SCOTHEAD6,4,T_CollectorWander,0,&s_scottwanderdoor7};
+statetype s_scottwanderdoor5 = {false,SCOTHEAD5,4,T_CollectorWander,0,&s_scottwanderdoor6};
+statetype s_scottwanderdoor4 = {false,SCOTHEAD4,4,T_CollectorWander,0,&s_scottwanderdoor5};
+statetype s_scottwanderdoor3 = {false,SCOTHEAD3,4,T_CollectorWander,0,&s_scottwanderdoor4};
+statetype s_scottwanderdoor2 = {false,SCOTHEAD2,4,T_CollectorWander,0,&s_scottwanderdoor3};
+statetype s_scottwanderdoor1 = {false,SCOTHEAD1,4,T_CollectorWander,0,&s_scottwanderdoor2};
+
+
+
+/*
+===========================================================================
+
+							 OVERPATROLS (op)
+																			,
+===========================================================================
+*/
+
+statetype s_opstand	   = {true,SPR_OP_S1,0,T_Stand,0,&s_opstand};
+
+statetype s_oppath4 	   = {true,SPR_OP_W41,10,T_Path,0,&s_oppath1};
+statetype s_oppath3 	   = {true,SPR_OP_W31,10,T_Path,SF_CLOSE,&s_oppath4};
+statetype s_oppath2	   = {true,SPR_OP_W21,10,T_Path,0,&s_oppath3};
+statetype s_oppath1 	   = {true,SPR_OP_W11,10,T_Path,SF_CLOSE,&s_oppath2};
+
+
+statetype s_opcollide  = {false,SPR_OP_PAIN1,0,T_Collide,0,&s_opcollide};
+statetype s_opcollide2 = {false,SPR_OP_PAIN2,0,T_Collide,0,&s_opcollide2};
+
+
+//statetype s_opuse2 	   = {true,SPR_OP_USE21,10,T_Use,0,&s_oppath1};
+//statetype s_opuse1 	   = {true,SPR_OP_USE11,10,T_Use,0,&s_opuse2};
+
+
+statetype s_opshoot4 	= {false,SPR_OP_SHOOT4,10,ActorMovement,0,&s_opchase1};
+statetype s_opshoot3 	= {false,SPR_OP_SHOOT3,10,ActorMovement,0,&s_opshoot4};
+statetype s_opshoot2 	= {false,SPR_OP_SHOOT2,20,A_Shoot,0,&s_opshoot3};
+statetype s_opshoot1 	= {false,SPR_OP_SHOOT1,6,ActorMovement,0,&s_opshoot2};
+
+
+
+statetype s_opbolo5     = {false,SPR_OP_BOLOSHOOT5,6,ActorMovement,0,&s_opchase1};
+statetype s_opbolo4     = {false,SPR_OP_BOLOSHOOT4,6,ActorMovement,0,&s_opbolo5};
+statetype s_opbolo3     = {false,SPR_OP_BOLOSHOOT3,20,A_MissileWeapon,0,&s_opbolo4};
+statetype s_opbolo2     = {false,SPR_OP_BOLOSHOOT2,6,ActorMovement,0,&s_opbolo3};
+statetype s_opbolo1     = {false,SPR_OP_BOLOSHOOT1,6,ActorMovement,0,&s_opbolo2};
+
+
+statetype s_bolocast4   = {false,SPR_BOLO4,6,T_Projectile,0,&s_bolocast4};
+statetype s_bolocast3   = {false,SPR_BOLO3,6,T_Projectile,0,&s_bolocast4};
+statetype s_bolocast2   = {false,SPR_BOLO2,6,T_Projectile,0,&s_bolocast3};
+statetype s_bolocast1   = {false,SPR_BOLO1,6,T_Projectile,0,&s_bolocast2};
+
+
+statetype s_opchase4	   = {true,SPR_OP_W41,6,T_Chase,0,&s_opchase1};
+statetype s_opchase3	   = {true,SPR_OP_W31,6,T_Chase,SF_CLOSE,&s_opchase4};
+statetype s_opchase2	   = {true,SPR_OP_W21,6,T_Chase,0,&s_opchase3};
+statetype s_opchase1	   = {true,SPR_OP_W11,6,T_Chase,SF_CLOSE,&s_opchase2};
+
+
+statetype s_opdead		= {false,SPR_OP_ALTDEAD,0,T_Collide,0,&s_opdead};
+statetype s_opdie5		= {false,SPR_OP_ALTDIE5,5,T_Collide,0,&s_opdead};
+statetype s_opdie4		= {false,SPR_OP_ALTDIE4,5,T_Collide,0,&s_opdie5};
+statetype s_opdie3		= {false,SPR_OP_ALTDIE3,5,T_Collide,0,&s_opdie4};
+statetype s_opdie2		= {false,SPR_OP_ALTDIE2,5,T_Collide,0,&s_opdie3};
+statetype s_opdie1		= {false,SPR_OP_ALTDIE1,5,T_Collide,0,&s_opdie2};
+
+statetype s_opdie1rev		= {false,SPR_OP_ALTDIE1,5,T_Collide,0,&s_opstand};
+statetype s_opdie2rev		= {false,SPR_OP_ALTDIE2,5,T_Collide,0,&s_opdie1rev};
+statetype s_opdie3rev		= {false,SPR_OP_ALTDIE3,5,T_Collide,0,&s_opdie2rev};
+statetype s_opdie4rev		= {false,SPR_OP_ALTDIE4,5,T_Collide,0,&s_opdie3rev};
+statetype s_opdie5rev		= {false,SPR_OP_ALTDIE5,5,T_Collide,0,&s_opdie4rev};
+
+
+statetype s_opcrushed2		= {false,SPR_OP_DIE3,2,NULL,0,&s_opdead};
+statetype s_opcrushed1		= {false,SPR_OP_DIE1,2,NULL,0,&s_opcrushed2};
+
+
+
+/*
+============================================================================
+
+								DEATH MONKS
+
+============================================================================
+*/
+
+
+statetype s_dmonkstand	= {true,SPR_MONK_S1,0,T_Stand,0,&s_dmonkstand};
+
+statetype s_dmonkpath4	= {true,SPR_MONK_W41,10,T_Path,0,&s_dmonkpath1};
+statetype s_dmonkpath3  = {true,SPR_MONK_W31,10,T_Path,SF_CLOSE,&s_dmonkpath4};
+statetype s_dmonkpath2	= {true,SPR_MONK_W21,10,T_Path,0,&s_dmonkpath3};
+statetype s_dmonkpath1  = {true,SPR_MONK_W11,10,T_Path,SF_CLOSE,&s_dmonkpath2};
+
+
+statetype s_dmonkcollide  = {false,SPR_MONK_PAIN1,0,T_Collide,0,&s_dmonkcollide};
+statetype s_dmonkcollide2 = {false,SPR_MONK_PAIN2,0,T_Collide,0,&s_dmonkcollide2};
+
+
+statetype s_dmonkshoot6 = {false,SPR_MONK_DRAIN6,20,ActorMovement,0,&s_dmonkchase1};
+statetype s_dmonkshoot5 = {false,SPR_MONK_DRAIN5,20,ActorMovement,0,&s_dmonkshoot6};
+statetype s_dmonkshoot4 = {false,SPR_MONK_DRAIN4,20,ActorMovement,0,&s_dmonkshoot3};
+statetype s_dmonkshoot3 = {false,SPR_MONK_DRAIN3,20,A_Drain,0,&s_dmonkshoot4};
+statetype s_dmonkshoot2 = {false,SPR_MONK_DRAIN2,20,ActorMovement,0,&s_dmonkshoot3};
+statetype s_dmonkshoot1 = {false,SPR_MONK_DRAIN1,20,A_Drain,0,&s_dmonkshoot2};
+
+statetype s_dmonkchase4	   = {true,SPR_MONK_W41,6,T_Chase,0,&s_dmonkchase1};
+statetype s_dmonkchase3 	= {true,SPR_MONK_W31,6,T_Chase,SF_CLOSE,&s_dmonkchase4};
+statetype s_dmonkchase2	   = {true,SPR_MONK_W21,6,T_Chase,0,&s_dmonkchase3};
+statetype s_dmonkchase1 	= {true,SPR_MONK_W11,6,T_Chase,SF_CLOSE,&s_dmonkchase2};
+
+statetype s_dmonkdead		= {false,SPR_MONK_DEAD,0,T_Collide,0,&s_dmonkdead};
+statetype s_dmonkdie4		= {false,SPR_MONK_DIE4,5,T_Collide,0,&s_dmonkdead};
+statetype s_dmonkdie3		= {false,SPR_MONK_DIE3,5,T_Collide,0,&s_dmonkdie4};
+statetype s_dmonkdie2		= {false,SPR_MONK_DIE2,5,T_Collide,0,&s_dmonkdie3};
+statetype s_dmonkdie1		= {false,SPR_MONK_DIE1,5,T_Collide,0,&s_dmonkdie2};
+
+statetype s_dmonkdie1rev	= {false,SPR_MONK_DIE1,5,T_Collide,0, &s_dmonkstand};
+statetype s_dmonkdie2rev	= {false,SPR_MONK_DIE2,5,T_Collide,0,&s_dmonkdie1rev};
+statetype s_dmonkdie3rev	= {false,SPR_MONK_DIE3,5,T_Collide,0,&s_dmonkdie2rev};
+statetype s_dmonkdie4rev	= {false,SPR_MONK_DIE4,5,T_Collide,0,&s_dmonkdie3rev};
+
+statetype s_dmonkcrushed2		= {false,SPR_MONK_DIE3,2,NULL,0,&s_dmonkdead};
+statetype s_dmonkcrushed1		= {false,SPR_MONK_DIE1,2,NULL,0,&s_dmonkcrushed2};
+
+/*
+============================================================================
+
+								DEATH FIRE MONKS
+
+============================================================================
+*/
+
+statetype s_firemonkstand	= {true,SPR_FIREMONK_S1,0,T_Stand,0,&s_firemonkstand};
+
+statetype s_firemonkpath4	= {true,SPR_FIREMONK_W41,10,T_Path,0,&s_firemonkpath1};
+statetype s_firemonkpath3  = {true,SPR_FIREMONK_W31,10,T_Path,SF_CLOSE,&s_firemonkpath4};
+statetype s_firemonkpath2	= {true,SPR_FIREMONK_W21,10,T_Path,0,&s_firemonkpath3};
+statetype s_firemonkpath1  = {true,SPR_FIREMONK_W11,10,T_Path,SF_CLOSE,&s_firemonkpath2};
+
+
+statetype s_firemonkcollide  = {false,SPR_FIREMONK_PAIN1,0,T_Collide,0,&s_firemonkcollide};
+statetype s_firemonkcollide2 = {false,SPR_FIREMONK_PAIN2,0,T_Collide,0,&s_firemonkcollide2};
+
+statetype s_firemonkcast7 = {false,SPR_FIREMONK_CAST7,6,ActorMovement,0,&s_firemonkchase1};
+statetype s_firemonkcast6 = {false,SPR_FIREMONK_CAST6,40,A_MissileWeapon,0,&s_firemonkcast7};
+statetype s_firemonkcast5 = {false,SPR_FIREMONK_CAST5,6,ActorMovement,0,&s_firemonkcast6};
+statetype s_firemonkcast4 = {false,SPR_FIREMONK_CAST4,6,ActorMovement,0,&s_firemonkcast5};
+statetype s_firemonkcast3 = {false,SPR_FIREMONK_CAST3,6,ActorMovement,0,&s_firemonkcast4};
+statetype s_firemonkcast2 = {false,SPR_FIREMONK_CAST2,6,ActorMovement,0,&s_firemonkcast3};
+statetype s_firemonkcast1 = {false,SPR_FIREMONK_CAST1,6,ActorMovement,0,&s_firemonkcast2};
+
+statetype s_monkfire4 = {false,MONKFIRE4,3,T_Projectile,0,&s_monkfire1};
+statetype s_monkfire3 = {false,MONKFIRE3,3,T_Projectile,0,&s_monkfire4};
+statetype s_monkfire2 = {false,MONKFIRE2,3,T_Projectile,0,&s_monkfire3};
+statetype s_monkfire1 = {false,MONKFIRE1,3,T_Projectile,0,&s_monkfire2};
+
+
+statetype s_fireballhit3 = {false,SPR_FIREBALL_HIT3,5,NULL,0,NULL};
+statetype s_fireballhit2 = {false,SPR_FIREBALL_HIT2,5,NULL,0,&s_fireballhit3};
+statetype s_fireballhit1 = {false,SPR_FIREBALL_HIT1,5,NULL,0,&s_fireballhit2};
+
+statetype s_firemonkchase4 	= {true,SPR_FIREMONK_W41,6,T_Chase,0,&s_firemonkchase1};
+statetype s_firemonkchase3 	= {true,SPR_FIREMONK_W31,6,T_Chase,SF_CLOSE,&s_firemonkchase4};
+statetype s_firemonkchase2	   = {true,SPR_FIREMONK_W21,6,T_Chase,0,&s_firemonkchase3};
+statetype s_firemonkchase1 	= {true,SPR_FIREMONK_W11,6,T_Chase,SF_CLOSE,&s_firemonkchase2};
+
+
+statetype s_firemonkdead7		= {false,SPR_FIREMONK_DEAD7,0,T_Collide,0,&s_firemonkdead7};
+statetype s_firemonkdead6	   = {false,SPR_FIREMONK_DEAD6,5,T_Collide,0,&s_firemonkdead7};
+statetype s_firemonkdead5	   = {false,SPR_FIREMONK_DEAD5,5,T_Collide,0,&s_firemonkdead6};
+statetype s_firemonkdead4	   = {false,SPR_FIREMONK_DEAD4,5,T_Collide,0,&s_firemonkdead5};
+statetype s_firemonkdead3	   = {false,SPR_FIREMONK_DEAD3,5,T_Collide,0,&s_firemonkdead4};
+statetype s_firemonkdead2	   = {false,SPR_FIREMONK_DEAD2,5,T_Collide,0,&s_firemonkdead3};
+statetype s_firemonkdead		= {false,SPR_FIREMONK_DEAD1,5,T_Collide,0,&s_firemonkdead2};
+statetype s_firemonkdie4		= {false,SPR_FIREMONK_DIE3,5,T_Collide,0,&s_firemonkdead};
+statetype s_firemonkdie3		= {false,SPR_FIREMONK_DIE3,5,T_Collide,0,&s_firemonkdie4};
+statetype s_firemonkdie2		= {false,SPR_FIREMONK_DIE2,5,T_Collide,0,&s_firemonkdie3};
+statetype s_firemonkdie1		= {false,SPR_FIREMONK_DIE1,5,T_Collide,0,&s_firemonkdie2};
+
+
+statetype s_firemonkdie1rev	= {false,SPR_FIREMONK_DIE1,5,T_Collide,0,&s_firemonkstand};
+statetype s_firemonkdie2rev	= {false,SPR_FIREMONK_DIE2,5,T_Collide,0,&s_firemonkdie1rev};
+statetype s_firemonkdie3rev	= {false,SPR_FIREMONK_DIE3,5,T_Collide,0,&s_firemonkdie2rev};
+statetype s_firemonkdie4rev	= {false,SPR_FIREMONK_DIE3,5,T_Collide,0,&s_firemonkdie3rev};
+
+
+statetype s_firemonkcrushed2		= {false,SPR_FIREMONK_DIE3,2,NULL,0,&s_firemonkdead};
+statetype s_firemonkcrushed1		= {false,SPR_FIREMONK_DIE1,2,NULL,0,&s_firemonkcrushed2};
+
+/*===========================================================================
+
+								  INSANE WALL DUDE
+
+============================================================================*/
+
+
+statetype s_wallstand = {16,BCRAFT01,0,T_Stand,0,&s_wallstand};
+
+statetype s_wallpath = {16,BCRAFT01,20,T_AutoPath,0,&s_wallpath};
+
+statetype s_wallshoot = {16,BCRAFT01,15,A_MissileWeapon,0,&s_wallshoot};
+
+statetype s_wallalign = {16,BCRAFT01,0,T_AutoShootAlign,0,&s_wallalign};
+statetype s_wallwait = {16,BCRAFT01,0,NULL,0,&s_wallwait};
+statetype s_wallrestore = {16,BCRAFT01,0,T_AutoRealign,0,&s_wallrestore};
+
+
+
+statetype s_wallcollide  = {16,BCRAFT01,0,T_Collide,0,&s_wallcollide};
+
+
+/*
+===========================================================================
+
+									  ESAU GUDERIAN
+
+===========================================================================
+*/
+
+
+
+
+statetype s_darianstand = {true,SPR_DARIAN_S1,0,T_Stand,0,&s_darianstand};
+
+statetype s_darianchase4	= {true,SPR_DARIAN_W41,8,T_EsauChase,0,&s_darianchase1};
+statetype s_darianchase3	= {true,SPR_DARIAN_W31,8,T_EsauChase,SF_CLOSE,&s_darianchase4};
+statetype s_darianchase2	= {true,SPR_DARIAN_W21,8,T_EsauChase,0,&s_darianchase3};
+statetype s_darianchase1	= {true,SPR_DARIAN_W11,8,T_EsauChase,SF_CLOSE,&s_darianchase2};
+
+
+statetype s_darianrise8 = {false,SPR_DARIAN_SINK1,3,NULL,0,&s_darianwait};
+statetype s_darianrise7 = {false,SPR_DARIAN_SINK2,3,NULL,0,&s_darianrise8};
+statetype s_darianrise6 = {false,SPR_DARIAN_SINK3,3,NULL,0,&s_darianrise7};
+statetype s_darianrise5 = {false,SPR_DARIAN_SINK4,3,NULL,0,&s_darianrise6};
+statetype s_darianrise4 = {false,SPR_DARIAN_SINK5,3,NULL,0,&s_darianrise5};
+statetype s_darianrise3 = {false,SPR_DARIAN_SINK6,3,NULL,0,&s_darianrise4};
+statetype s_darianrise2 = {false,SPR_DARIAN_SINK7,3,NULL,0,&s_darianrise3};
+statetype s_darianrise1 = {false,SPR_DARIAN_SINK8,3,NULL,0,&s_darianrise2};
+
+
+statetype s_dariansink9 = {false,NOTHING,110,T_EsauRise,0,&s_darianrise1};
+statetype s_dariansink8 = {false,SPR_DARIAN_SINK8,3,NULL,0,&s_dariansink9};
+statetype s_dariansink7 = {false,SPR_DARIAN_SINK7,3,NULL,0,&s_dariansink8};
+statetype s_dariansink6 = {false,SPR_DARIAN_SINK6,3,NULL,0,&s_dariansink7};
+statetype s_dariansink5 = {false,SPR_DARIAN_SINK5,3,NULL,0,&s_dariansink6};
+statetype s_dariansink4 = {false,SPR_DARIAN_SINK4,3,NULL,0,&s_dariansink5};
+statetype s_dariansink3 = {false,SPR_DARIAN_SINK3,3,NULL,0,&s_dariansink4};
+statetype s_dariansink2 = {false,SPR_DARIAN_SINK2,3,NULL,0,&s_dariansink3};
+statetype s_dariansink1 = {false,SPR_DARIAN_SINK1,3,NULL,0,&s_dariansink2};
+
+
+statetype s_dariancollide  = {false,SPR_DARIAN_PAIN1,0,T_Collide,0,&s_dariancollide};
+statetype s_dariancollide2 = {false,SPR_DARIAN_PAIN2,0,T_Collide,0,&s_dariancollide2};
+
+
+statetype s_darianshoot4  = {false,SPR_DARIAN_SHOOT4,10,NULL,0,&s_darianchase1};
+statetype s_darianshoot3  = {false,SPR_DARIAN_SHOOT3,10,NULL,0,&s_darianshoot4};
+statetype s_darianshoot2  = {false,SPR_DARIAN_SHOOT2,20,A_MissileWeapon,0,&s_darianshoot3};
+statetype s_darianshoot1  = {false,SPR_DARIAN_SHOOT1,10,NULL,0,&s_darianshoot2};
+
+statetype s_dariandefend3  = {false,SPR_DARIAN_SHOOT3,10,NULL,0,&s_darianwait};
+statetype s_dariandefend2  = {false,SPR_DARIAN_SHOOT2,20,A_MissileWeapon,0,&s_dariandefend3};
+statetype s_dariandefend1  = {false,SPR_DARIAN_SHOOT1,10,NULL,0,&s_dariandefend2};
+
+
+statetype s_darianuse4  = {true,SPR_DARIAN_USE11,10,NULL,0,&s_darianspears};
+statetype s_darianuse3  = {true,SPR_DARIAN_USE21,10,T_Use,0,&s_darianuse4};
+statetype s_darianuse2  = {true,SPR_DARIAN_USE11,30,NULL,0,&s_darianuse3};
+statetype s_darianuse1  = {true,SPR_DARIAN_S1,40,NULL,0,&s_darianuse2};
+
+statetype s_darianwait = {false,SPR_DARIAN_SHOOT1,0,T_EsauWait,0,&s_darianwait};
+
+statetype s_darianspears  = {true,SPR_DARIAN_S1,280,NULL,0,&s_darianchase1};
+
+
+statetype s_dspear16 = {false,SPEARDOWN7,2,T_Spears,SF_DOWN,NULL};
+statetype s_dspear15 = {false,SPEARDOWN6,2,T_Spears,SF_CRUSH,&s_dspear16};
+statetype s_dspear14 = {false,SPEARDOWN5,2,T_Spears,SF_CRUSH,&s_dspear15};
+statetype s_dspear13 = {false,SPEARDOWN4,2,T_Spears,SF_CRUSH,&s_dspear14};
+statetype s_dspear12 = {false,SPEARDOWN3,2,T_Spears,SF_CRUSH,&s_dspear13};
+statetype s_dspear11 = {false,SPEARDOWN2,2,T_Spears,SF_CRUSH,&s_dspear12};
+statetype s_dspear10 = {false,SPEARDOWN1,2,T_Spears,SF_CRUSH,&s_dspear11};
+statetype s_dspear9 = {false,SPEARDOWN16,2,T_Spears,SF_CRUSH,&s_dspear10};
+statetype s_dspear8 = {false,SPEARDOWN15,2,T_Spears,SF_CRUSH,&s_dspear9};
+statetype s_dspear7 = {false,SPEARDOWN14,2,T_Spears,SF_CRUSH,&s_dspear8};
+statetype s_dspear6 = {false,SPEARDOWN13,2,T_Spears,SF_CRUSH,&s_dspear7};
+statetype s_dspear5 = {false,SPEARDOWN12,2,T_Spears,SF_CRUSH,&s_dspear6};
+statetype s_dspear4 = {false,SPEARDOWN11,2,T_Spears,SF_CRUSH,&s_dspear5};
+statetype s_dspear3 = {false,SPEARDOWN10,2,T_Spears,SF_CRUSH,&s_dspear4};
+statetype s_dspear2 = {false,SPEARDOWN9,2,T_Spears,SF_DOWN,&s_dspear3};
+statetype s_dspear1 = {false,SPEARDOWN8,2,T_Spears,SF_DOWN,&s_dspear2};
+
+
+statetype s_dariandead2 	= {false,SPR_DARIAN_DEAD,0,T_BossDied,0,&s_dariandead2};
+statetype s_dariandead1 	= {false,SPR_DARIAN_DEAD,140,NULL,0,&s_dariandead2};
+statetype s_dariandead 	= {false,SPR_DARIAN_DEAD,0,NULL,0,&s_dariandead1};
+
+statetype s_dariandie10 = {false,SPR_DARIAN_DIE10,5,NULL,0,&s_dariandead};
+statetype s_dariandie9 	= {false,SPR_DARIAN_DIE9,5,NULL,0,&s_dariandie10};
+statetype s_dariandie8 	= {false,SPR_DARIAN_DIE8,5,NULL,0,&s_dariandie9};
+statetype s_dariandie7 	= {false,SPR_DARIAN_DIE7,5,NULL,0,&s_dariandie8};
+statetype s_dariandie6 	= {false,SPR_DARIAN_DIE6,5,T_Guts,0,&s_dariandie7};
+statetype s_dariandie5 	= {false,SPR_DARIAN_DIE5,5,NULL,0,&s_dariandie6};
+statetype s_dariandie4 	= {false,SPR_DARIAN_DIE4,5,NULL,0,&s_dariandie5};
+statetype s_dariandie3 	= {false,SPR_DARIAN_DIE3,5,NULL,0,&s_dariandie4};
+statetype s_dariandie2 	= {false,SPR_DARIAN_DIE2,5,NULL,0,&s_dariandie3};
+statetype s_dariandie1 	= {false,SPR_DARIAN_DIE1,70,T_Collide,0,&s_dariandie2};
+
+
+
+/*
+===========================================================================
+
+									HEINRICH KRIST
+
+===========================================================================
+*/
+
+
+statetype s_heinrichstand	= {true,SPR_KRIST_S1,0,T_Stand,0,&s_heinrichstand};
+
+statetype s_heinrichchase 	= {true,SPR_KRIST_FOR1,10,T_HeinrichChase,0,&s_heinrichchase};
+
+
+statetype s_kristleft = {true,SPR_KRIST_LEFT1,10,T_KristLeft,0,&s_kristleft};
+
+statetype s_kristright = {true,SPR_KRIST_RIGHT1,10,T_KristRight,0,&s_kristright};
+
+statetype s_heinrichshoot11  = {false,SPR_KRIST_SHOOT11,8,NULL,0,&s_heinrichchase};
+statetype s_heinrichshoot10  = {false,SPR_KRIST_SHOOT10,8,NULL,0,&s_heinrichshoot11};
+statetype s_heinrichshoot9  = {false,SPR_KRIST_SHOOT9,8,A_HeinrichShoot,0,&s_heinrichshoot10};
+statetype s_heinrichshoot8  = {false,SPR_KRIST_SHOOT8,8,NULL,0,&s_heinrichshoot9};
+statetype s_heinrichshoot7  = {false,SPR_KRIST_SHOOT7,8,T_KristCheckFire,0,&s_heinrichshoot8};
+statetype s_heinrichshoot6  = {false,SPR_KRIST_SHOOT6,8,NULL,0,&s_heinrichshoot7};
+statetype s_heinrichshoot5  = {false,SPR_KRIST_SHOOT5,8,NULL,0,&s_heinrichshoot6};
+statetype s_heinrichshoot4  = {false,SPR_KRIST_SHOOT4,8,A_HeinrichShoot,0,&s_heinrichshoot5};
+statetype s_heinrichshoot3  = {false,SPR_KRIST_SHOOT3,8,NULL,0,&s_heinrichshoot4};
+statetype s_heinrichshoot2  = {false,SPR_KRIST_SHOOT2,8,NULL,0,&s_heinrichshoot3};
+statetype s_heinrichshoot1  = {false,SPR_KRIST_SHOOT1,8,T_KristCheckFire,0,&s_heinrichshoot2};
+
+statetype s_missile1       = {16,SPR_BJMISS11,6,T_Projectile,0,&s_missile1};
+
+
+statetype s_missilehit3    = {false,SPR_MISSILEHIT3,6,NULL,0,NULL};
+statetype s_missilehit2    = {false,SPR_MISSILEHIT2,6,NULL,0,&s_missilehit3};
+statetype s_missilehit1    = {false,SPR_MISSILEHIT1,6,NULL,0,&s_missilehit2};
+
+statetype s_mine4          = {false,SPR_MINE4,3,T_Projectile,0,&s_mine1};
+statetype s_mine3          = {false,SPR_MINE3,3,T_Projectile,0,&s_mine4};
+statetype s_mine2          = {false,SPR_MINE2,3,T_Projectile,0,&s_mine3};
+statetype s_mine1          = {false,SPR_MINE1,3,T_Projectile,0,&s_mine2};
+
+statetype s_heinrichdefend = {true,SPR_KRIST_MINERIGHT1,35,T_Heinrich_Defend,0,&s_heinrichdefend};
+
+
+statetype s_heinrichooc    = {true,SPR_KRIST_DEAD1,0,T_Heinrich_Out_of_Control,0,&s_heinrichooc};
+
+statetype s_heinrichdead 	= {false,SPR_KRIST_DEAD1,35,T_Collide,0,&s_heinrichooc};
+
+statetype s_heinrichdie2 	= {false,SPR_KRIST_DIE2,35,T_Collide,0,&s_heinrichdead};
+statetype s_heinrichdie1 	= {false,SPR_KRIST_DIE1,35,T_Collide,0,&s_heinrichdie2};
+
+statetype s_heindead2 = {false,-1,0,T_BossDied,0,NULL};
+statetype s_heindead1 = {false, -1, 140,NULL,0,&s_heindead2};
+statetype s_heinexp13 = {false,SPR_EXPLOSION13,2,NULL,0,&s_heindead1};
+statetype s_heinexp12 = {false,SPR_EXPLOSION12,2,NULL,0,&s_heinexp13};
+statetype s_heinexp11 = {false,SPR_EXPLOSION11,2,NULL,0,&s_heinexp12};
+statetype s_heinexp10 = {false,SPR_EXPLOSION10,2,NULL,0,&s_heinexp11};
+statetype s_heinexp9 = {false,SPR_EXPLOSION9,2,NULL,0,&s_heinexp10};
+statetype s_heinexp8 = {false,SPR_EXPLOSION8,2,NULL,0,&s_heinexp9};
+statetype s_heinexp7 = {false,SPR_EXPLOSION7,2,NULL,0,&s_heinexp8};
+statetype s_heinexp6 = {false,SPR_EXPLOSION6,2,NULL,0,&s_heinexp7};
+statetype s_heinexp5 = {false,SPR_EXPLOSION5,2,NULL,0,&s_heinexp6};
+statetype s_heinexp4 = {false,SPR_EXPLOSION4,2,NULL,0,&s_heinexp5};
+statetype s_heinexp3 = {false,SPR_EXPLOSION3,2,T_Explosion,0,&s_heinexp4};
+statetype s_heinexp2 = {false,SPR_EXPLOSION2,2,NULL,0,&s_heinexp3};
+statetype s_heinexp1 = {false,SPR_EXPLOSION1,0,NULL,0,&s_heinexp2};
+
+
+/*
+===========================================================================
+
+								  DARK MONK (TOM)
+
+===========================================================================
+*/
+
+
+statetype s_darkmonkstand	= {true,TOMS1,0,T_Stand,0,&s_darkmonkstand};
+
+statetype s_darkmonkland	= {true,TOMFLY11,6,NULL,0,&s_darkmonkstand};
+
+
+statetype s_darkmonkchase2	= {true,TOMFLY21,10,T_DarkmonkChase,0,&s_darkmonkchase2};
+statetype s_darkmonkchase1	= {true,TOMFLY11,3,T_DarkmonkChase,0,&s_darkmonkchase2};
+
+statetype s_dmlandandfire = {true,TOMFLY11,0,T_DarkmonkLandAndFire,0,&s_dmlandandfire};
+
+statetype s_darkmonkcover3	= {false,TAWAKEN1,1,NULL,0,&s_darkmonkawaken1};
+statetype s_darkmonkcover2	= {false,TAWAKEN2,1,NULL,0,&s_darkmonkcover3};
+statetype s_darkmonkcover1	= {false,TAWAKEN3,1,NULL,0,&s_darkmonkcover2};
+
+
+statetype s_darkmonkawaken5	= {false,TAWAKEN5,3,NULL,0,&s_darkmonkchase1};
+statetype s_darkmonkawaken4	= {false,TAWAKEN4,3,NULL,0,&s_darkmonkawaken5};
+statetype s_darkmonkawaken3	= {false,TAWAKEN3,3,NULL,0,&s_darkmonkawaken4};
+statetype s_darkmonkawaken2	= {false,TAWAKEN2,3,NULL,0,&s_darkmonkawaken3};
+statetype s_darkmonkawaken1 	= {false,TAWAKEN1,3,NULL,0,&s_darkmonkawaken2};
+
+
+statetype s_darkmonklightning11	= {false,TOMLG11,3,NULL,0,&s_darkmonkchase1};
+statetype s_darkmonklightning10	= {false,TOMLG10,3,NULL,0,&s_darkmonklightning11};
+statetype s_darkmonklightning9	= {false,TOMLG9,70,A_DmonkAttack,0,&s_darkmonklightning10};
+statetype s_darkmonklightning8	= {false,TOMLG8,3,NULL,0,&s_darkmonklightning9};
+statetype s_darkmonklightning7 	= {false,TOMLG7,3,NULL,0,&s_darkmonklightning8};
+statetype s_darkmonklightning6	= {false,TOMLG6,3,NULL,0,&s_darkmonklightning7};
+statetype s_darkmonklightning5	= {false,TOMLG5,3,NULL,0,&s_darkmonklightning6};
+statetype s_darkmonklightning4	= {false,TOMLG4,3,NULL,0,&s_darkmonklightning5};
+statetype s_darkmonklightning3	= {false,TOMLG3,3,NULL,0,&s_darkmonklightning4};
+statetype s_darkmonklightning2 	= {false,TOMLG2,3,NULL,0,&s_darkmonklightning3};
+statetype s_darkmonklightning1 	= {false,TOMLG1,3,NULL,0,&s_darkmonklightning2};
+
+statetype s_darkmonkfspark6	= {false,TOMFS6,3,NULL,0,&s_darkmonkchase1};
+statetype s_darkmonkfspark5	= {false,TOMFS5,70,A_DmonkAttack,0,&s_darkmonkfspark6};
+statetype s_darkmonkfspark4	= {false,TOMFS4,3,NULL,0,&s_darkmonkfspark5};
+statetype s_darkmonkfspark3	= {false,TOMFS3,3,NULL,0,&s_darkmonkfspark4};
+statetype s_darkmonkfspark2 	= {false,TOMFS2,3,NULL,0,&s_darkmonkfspark3};
+statetype s_darkmonkfspark1 	= {false,TOMFS1,3,NULL,0,&s_darkmonkfspark2};
+
+
+statetype s_darkmonkbreathe8	= {false,TOMBR8,3,NULL,0,&s_darkmonkchase1};
+statetype s_darkmonkbreathe7 	= {false,TOMBR7,3,NULL,0,&s_darkmonkbreathe8};
+statetype s_darkmonkbreathe6	= {false,TOMBR6,70,A_DmonkAttack,0,&s_darkmonkbreathe7};
+statetype s_darkmonkbreathe5	= {false,TOMBR5,3,NULL,0,&s_darkmonkbreathe6};
+statetype s_darkmonkbreathe4	= {false,TOMBR4,3,NULL,0,&s_darkmonkbreathe5};
+statetype s_darkmonkbreathe3	= {false,TOMBR3,3,NULL,0,&s_darkmonkbreathe4};
+statetype s_darkmonkbreathe2 	= {false,TOMBR2,3,NULL,0,&s_darkmonkbreathe3};
+statetype s_darkmonkbreathe1 	= {false,TOMBR1,70,NULL,0,&s_darkmonkbreathe2};
+
+statetype s_darkmonksummon3	= {false,TOMBR1,3,NULL,0,&s_darkmonkchase1};
+statetype s_darkmonksummon2 	= {false,TOMBR3,3,NULL,0,&s_darkmonksummon3};
+statetype s_darkmonksummon1 	= {false,TOMBR2,3,NULL,0,&s_darkmonksummon2};
+
+statetype s_snakepath = {true,TOMHEAD1,0,T_SnakePath,0,&s_snakepath};
+statetype s_snakefindpath = {true,TOMHEAD1,0,T_SnakeFindPath,0,&s_snakefindpath};
+
+statetype s_darkmonkhead	= {true,TOMHEAD1,0,T_DarkSnakeChase,0,&s_darkmonkhead};
+statetype s_darkmonksnakelink	= {true,TOMHEAD1,0,T_GenericMove,0,&s_darkmonksnakelink};
+
+
+statetype s_darkmonkhspawn = {false,NOTHING,78,T_DarkSnakeSpawn,0,NULL};
+statetype s_darkmonkfastspawn = {false,NOTHING,35,T_DarkSnakeSpawn,0,NULL};
+
+statetype s_darkmonkheaddead	= {false,THDIE2,0,NULL,0,&s_darkmonkheaddead};
+statetype s_darkmonkheaddie1	= {false,THDIE1,1400,T_SnakeFinale,0,&s_snakefireworks1};
+
+statetype s_snakefireworks2 = {false,THDIE2,10,T_SnakeFinale,0,&s_snakefireworks1};
+statetype s_snakefireworks1 = {false,THDIE1,10,T_SnakeFinale,0,&s_snakefireworks2};
+
+statetype s_darkmonkhball9	= {false,THBALL9,5,NULL,0,&s_darkmonkchase1};
+statetype s_darkmonkhball8	= {false,THBALL8,5,NULL,0,&s_darkmonkhball9};
+statetype s_darkmonkhball7 = {false,THBALL7,5,A_DmonkAttack,0,&s_darkmonkhball8};
+statetype s_darkmonkhball6	= {false,THBALL6,5,NULL,0,&s_darkmonkhball7};
+statetype s_darkmonkhball5	= {false,THBALL5,5,NULL,0,&s_darkmonkhball6};
+statetype s_darkmonkhball4	= {false,THBALL4,5,NULL,0,&s_darkmonkhball5};
+statetype s_darkmonkhball3	= {false,THBALL3,5,NULL,0,&s_darkmonkhball4};
+statetype s_darkmonkhball2 = {false,THBALL2,5,NULL,0,&s_darkmonkhball3};
+statetype s_darkmonkhball1 = {false,THBALL1,70,NULL,0,&s_darkmonkhball2};
+
+statetype s_darkmonkabsorb9	= {false,THBALL9,3,NULL,0,&s_darkmonksphere1};
+statetype s_darkmonkabsorb8	= {false,THBALL8,3,NULL,0,&s_darkmonkabsorb9};
+statetype s_darkmonkabsorb7 = {false,THBALL7,3,NULL,0,&s_darkmonkabsorb8};
+statetype s_darkmonkabsorb6	= {false,THBALL6,3,NULL,0,&s_darkmonkabsorb7};
+statetype s_darkmonkabsorb5	= {false,THBALL5,3,NULL,0,&s_darkmonkabsorb6};
+statetype s_darkmonkabsorb4	= {false,THBALL4,3,NULL,0,&s_darkmonkabsorb5};
+statetype s_darkmonkabsorb3	= {false,THBALL3,3,NULL,0,&s_darkmonkabsorb4};
+statetype s_darkmonkabsorb2 = {false,THBALL2,3,NULL,0,&s_darkmonkabsorb3};
+statetype s_darkmonkabsorb1 = {false,THBALL1,3,NULL,0,&s_darkmonkabsorb2};
+
+
+statetype s_darkmonksphere10 = {false,TSPHERE10,4,NULL,0,&s_darkmonkchase1};
+statetype s_darkmonksphere9 = {false,TSPHERE9,4,NULL,0,&s_darkmonksphere10};
+statetype s_darkmonksphere8 = {false,TSPHERE8,4,A_DmonkAttack,0,&s_darkmonksphere9};
+statetype s_darkmonksphere7 = {false,TSPHERE7,4,NULL,0,&s_darkmonksphere8};
+statetype s_darkmonksphere6 = {false,TSPHERE6,4,NULL,0,&s_darkmonksphere7};
+statetype s_darkmonksphere5 = {false,TSPHERE5,4,NULL,0,&s_darkmonksphere6};
+statetype s_darkmonksphere4 = {false,TSPHERE4,4,NULL,0,&s_darkmonksphere5};
+statetype s_darkmonksphere3 = {false,TSPHERE3,4,NULL,0,&s_darkmonksphere4};
+statetype s_darkmonksphere2 = {false,TSPHERE2,4,NULL,0,&s_darkmonksphere3};
+statetype s_darkmonksphere1 = {false,TSPHERE1,4,NULL,0,&s_darkmonksphere2};
+
+statetype s_dmgreenthing10 = {false,TSPHERE10,4,NULL,0,&s_darkmonkchase1};
+statetype s_dmgreenthing9 = {false,TSPHERE9,4,NULL,0,&s_dmgreenthing10};
+statetype s_dmgreenthing8 = {false,TSPHERE8,4,A_DmonkAttack,0,&s_dmgreenthing9};
+statetype s_dmgreenthing7 = {false,TSPHERE7,4,NULL,0,&s_dmgreenthing8};
+statetype s_dmgreenthing6 = {false,TSPHERE6,4,NULL,0,&s_dmgreenthing7};
+statetype s_dmgreenthing5 = {false,TSPHERE5,4,NULL,0,&s_dmgreenthing6};
+statetype s_dmgreenthing4 = {false,TSPHERE4,4,NULL,0,&s_dmgreenthing5};
+statetype s_dmgreenthing3 = {false,TSPHERE3,4,NULL,0,&s_dmgreenthing4};
+statetype s_dmgreenthing2 = {false,TSPHERE2,4,NULL,0,&s_dmgreenthing3};
+statetype s_dmgreenthing1 = {false,TSPHERE1,4,NULL,0,&s_dmgreenthing2};
+
+
+statetype s_energysphere4 = {false,TOMSPHERE4,4,T_Projectile,0,&s_energysphere1};
+statetype s_energysphere3 = {false,TOMSPHERE3,4,T_Projectile,0,&s_energysphere4};
+statetype s_energysphere2 = {false,TOMSPHERE2,4,T_Projectile,0,&s_energysphere3};
+statetype s_energysphere1 = {false,TOMSPHERE1,4,T_Projectile,0,&s_energysphere2};
+
+
+statetype s_lightning = {true,TOMLIGHTNING1,0,T_Projectile,0,&s_lightning};
+
+
+statetype s_handball2 = {false,TOMHANDBALL2,3,T_Projectile,0,&s_handball1};
+statetype s_handball1 = {false,TOMHANDBALL1,3,T_Projectile,0,&s_handball2};
+
+statetype s_faceball2 = {false,TOMFACEBALL2,3,T_Projectile,0,&s_faceball1};
+statetype s_faceball1 = {false,TOMFACEBALL1,3,T_Projectile,0,&s_faceball2};
+
+statetype s_floorspark4 = {false,TOMFLOORSPARK4,3,T_Projectile,0,&s_floorspark1};
+statetype s_floorspark3 = {false,TOMFLOORSPARK3,3,T_Projectile,0,&s_floorspark4};
+statetype s_floorspark2 = {false,TOMFLOORSPARK2,3,T_Projectile,0,&s_floorspark3};
+statetype s_floorspark1 = {false,TOMFLOORSPARK1,3,T_Projectile,0,&s_floorspark2};
+
+
+
+statetype s_darkmonkreact = {true,TOMFLY11,0,T_DarkmonkReact,0,&s_darkmonkreact};
+
+statetype s_darkmonkbball9	= {false,TBBALL9,4,NULL,0,&s_darkmonkchase1};
+statetype s_darkmonkbball8	= {false,TBBALL8,4,NULL,0,&s_darkmonkbball9};
+statetype s_darkmonkbball7 = {false,TBBALL7,4,A_DmonkAttack,0,&s_darkmonkbball8};
+statetype s_darkmonkbball6	= {false,TBBALL6,4,NULL,0,&s_darkmonkbball7};
+statetype s_darkmonkbball5	= {false,TBBALL5,4,NULL,0,&s_darkmonkbball6};
+statetype s_darkmonkbball4	= {false,TBBALL4,4,NULL,0,&s_darkmonkbball5};
+statetype s_darkmonkbball3	= {false,TBBALL3,4,NULL,0,&s_darkmonkbball4};
+statetype s_darkmonkbball2 = {false,TBBALL2,4,NULL,0,&s_darkmonkbball3};
+statetype s_darkmonkbball1 = {false,TBBALL1,70,NULL,0,&s_darkmonkbball2};
+
+
+statetype s_darkmonkcharge10 = {false,TSCAREB3,140,T_DarkmonkCharge,0,&s_darkmonkchase1};
+statetype s_darkmonkcharge9	= {false,TAWAKEN5,3,NULL,0,&s_darkmonkcharge10};
+statetype s_darkmonkcharge8	= {false,TAWAKEN4,3,NULL,0,&s_darkmonkcharge9};
+statetype s_darkmonkcharge7	= {false,TAWAKEN3,3,NULL,0,&s_darkmonkcharge8};
+statetype s_darkmonkcharge6 	= {false,TAWAKEN2,3,NULL,0,&s_darkmonkcharge7};
+statetype s_darkmonkcharge5	= {false,TAWAKEN1,3,NULL,0,&s_darkmonkcharge6};
+statetype s_darkmonkcharge4	= {false,TAWAKEN2,3,NULL,0,&s_darkmonkcharge5};
+statetype s_darkmonkcharge3	= {false,TAWAKEN3,3,NULL,0,&s_darkmonkcharge4};
+statetype s_darkmonkcharge2	= {false,TAWAKEN4,3,NULL,0,&s_darkmonkcharge3};
+statetype s_darkmonkcharge1 	= {false,TAWAKEN5,3,NULL,0,&s_darkmonkcharge2};
+
+
+statetype s_darkmonkscare5	= {false,TSCAREB5,3,NULL,0,&s_darkmonkcharge1};
+statetype s_darkmonkscare4	= {false,TSCAREB4,3,NULL,0,&s_darkmonkscare5};
+statetype s_darkmonkscare3	= {false,TSCAREB3,3,NULL,0,&s_darkmonkscare4};
+statetype s_darkmonkscare2 = {false,TSCAREB2,3,NULL,0,&s_darkmonkscare3};
+statetype s_darkmonkscare1 = {false,TSCAREB1,3,NULL,0,&s_darkmonkscare2};
+
+statetype s_darkmonkdead = {false,TOMDIE8,0,T_Collide,0,&s_darkmonkdead};
+statetype s_darkmonkdie7 = {false,TOMDIE7,3,T_Collide,0,&s_darkmonkdead};
+statetype s_darkmonkdie6 = {false,TOMDIE6,3,T_Collide,0,&s_darkmonkdie7};
+statetype s_darkmonkdie5 = {false,TOMDIE5,3,T_Collide,0,&s_darkmonkdie6};
+statetype s_darkmonkdie4 = {false,TOMDIE4,3,T_Collide,0,&s_darkmonkdie5};
+statetype s_darkmonkdie3 = {false,TOMDIE3,3,T_Collide,0,&s_darkmonkdie4};
+statetype s_darkmonkdie2 = {false,TOMDIE2,3,T_Collide,0,&s_darkmonkdie3};
+statetype s_darkmonkdie1 = {false,TOMDIE1,3,T_Collide,0,&s_darkmonkdie2};
+
+
+
+statetype s_darkmonkredhead = {true,TOMRH1,50,T_DarkSnakeChase,0,&s_darkmonkhead};
+statetype s_darkmonkredlink = {true,TOMRH1,50,T_GenericMove,0,&s_darkmonksnakelink};
+
+statetype s_redheadhit = {false,THDIE1,35,T_DarkSnakeChase,0,&s_darkmonkhead};
+statetype s_redlinkhit = {false,THDIE1,35,T_GenericMove,0,&s_darkmonksnakelink};
+
+
+statetype s_spithit4 = {false,SPITHIT4,3,NULL,0,NULL};
+statetype s_spithit3 = {false,SPITHIT3,3,NULL,0,&s_spithit4};
+statetype s_spithit2 = {false,SPITHIT2,3,NULL,0,&s_spithit3};
+statetype s_spithit1 = {false,SPITHIT1,3,NULL,0,&s_spithit2};
+
+statetype s_spit4 = {false,TOMSPIT4,3,T_Projectile,0,&s_spit1};
+statetype s_spit3 = {false,TOMSPIT3,3,T_Projectile,0,&s_spit4};
+statetype s_spit2 = {false,TOMSPIT2,3,T_Projectile,0,&s_spit3};
+statetype s_spit1 = {false,TOMSPIT1,3,T_Projectile,0,&s_spit2};
+
+statetype s_snakefire2 = {true,TOMHEAD1,1,T_DarkSnakeChase,SF_DOWN|SF_UP,&s_darkmonkhead};
+statetype s_snakefire1 = {false,TPREPARE,30,T_DarkSnakeChase,SF_DOWN,&s_snakefire2};
+
+statetype s_dexplosion22 = {false,-1,0,T_BossDied,0,NULL};
+statetype s_dexplosion21 = {false, -1, 240,NULL,0,&s_dexplosion22};
+statetype s_dexplosion20 = {false,SPR_EXPLOSION20,2,NULL,0,&s_dexplosion21};
+statetype s_dexplosion19 = {false,SPR_EXPLOSION19,2,NULL,0,&s_dexplosion20};
+statetype s_dexplosion18 = {false,SPR_EXPLOSION18,2,NULL,0,&s_dexplosion19};
+statetype s_dexplosion17 = {false,SPR_EXPLOSION17,2,NULL,0,&s_dexplosion18};
+statetype s_dexplosion16 = {false,SPR_EXPLOSION16,2,NULL,0,&s_dexplosion17};
+statetype s_dexplosion15 = {false,SPR_EXPLOSION15,2,NULL,0,&s_dexplosion16};
+statetype s_dexplosion14 = {false,SPR_EXPLOSION14,2,NULL,0,&s_dexplosion15};
+statetype s_dexplosion13 = {false,SPR_EXPLOSION13,2,NULL,0,&s_dexplosion14};
+statetype s_dexplosion12 = {false,SPR_EXPLOSION12,2,NULL,0,&s_dexplosion13};
+statetype s_dexplosion11 = {false,SPR_EXPLOSION11,2,NULL,0,&s_dexplosion12};
+statetype s_dexplosion10 = {false,SPR_EXPLOSION10,2,NULL,0,&s_dexplosion11};
+statetype s_dexplosion9 = {false,SPR_EXPLOSION9,2,NULL,0,&s_dexplosion10};
+statetype s_dexplosion8 = {false,SPR_EXPLOSION8,2,NULL,0,&s_dexplosion9};
+statetype s_dexplosion7 = {false,SPR_EXPLOSION7,2,NULL,0,&s_dexplosion8};
+statetype s_dexplosion6 = {false,SPR_EXPLOSION6,2,NULL,0,&s_dexplosion7};
+statetype s_dexplosion5 = {false,SPR_EXPLOSION5,2,NULL,0,&s_dexplosion6};
+statetype s_dexplosion4 = {false,SPR_EXPLOSION4,2,NULL,0,&s_dexplosion5};
+statetype s_dexplosion3 = {false,SPR_EXPLOSION3,2,T_Explosion,0,&s_dexplosion4};
+statetype s_dexplosion2 = {false,SPR_EXPLOSION2,2,NULL,0,&s_dexplosion3};
+statetype s_dexplosion1 = {false,SPR_EXPLOSION1,2,NULL,0,&s_dexplosion2};
+
+
+/*
+===========================================================================
+
+									OROBOT
+
+===========================================================================
+*/
+
+statetype s_NMEdeathbuildup = {16,NMEBODY1_01,210,T_NME_Explode,0,NULL};
+statetype s_NMEheadexplosion = {16,NMEHEAD1_01,140,T_Special,0,&s_grexplosion1};
+
+statetype s_NMEstand = {16,NMEBODY1_01,0,T_Stand,0,&s_NMEstand};
+statetype s_NMEhead1 = {16,NMEHEAD1_01,0,NULL,0,&s_NMEhead1};
+statetype s_NMEhead2 = {16,NMEHEAD2_01,0,NULL,0,&s_NMEhead2};
+statetype s_NMEchase = {16,NMEBODY1_01,20,T_OrobotChase,0,&s_NMEchase};
+statetype s_NMEwheels1 = {16,NMEWHEEL1_01,0,NULL,0,&s_NMEwheels1};
+statetype s_NMEwheels2 = {16,NMEWHEEL2_01,0,NULL,0,&s_NMEwheels2};
+statetype s_NMEwheels3 = {16,NMEWHEEL3_01,0,NULL,0,&s_NMEwheels3};
+statetype s_NMEwheels4 = {16,NMEWHEEL4_01,0,NULL,0,&s_NMEwheels4};
+statetype s_NMEwheels5 = {16,NMEWHEEL5_01,0,NULL,0,&s_NMEwheels5};
+
+statetype s_shootinghead = {16,NMEHEAD1_01,140,T_NME_HeadShoot,0,&s_shootinghead};
+
+statetype s_NMEspinattack = {16,NMEBODY1_01,70,T_NME_SpinAttack,0,&s_NMEchase};
+statetype s_NMEwheelspin = {16,NMEWHEEL1_01,70,NULL,0,&s_NMEwheels2};
+
+statetype s_NMEminiball4 = {false,NMEMINIBALL_04,4,T_Projectile,0,&s_NMEminiball1};
+statetype s_NMEminiball3 = {false,NMEMINIBALL_03,4,T_Projectile,0,&s_NMEminiball4};
+statetype s_NMEminiball2 = {false,NMEMINIBALL_02,4,T_Projectile,0,&s_NMEminiball3};
+statetype s_NMEminiball1 = {false,NMEMINIBALL_01,4,T_Projectile,0,&s_NMEminiball2};
+
+statetype s_NMEsaucer4 = {false,NMESAUCER_04,6,T_Saucer,0,&s_NMEsaucer1};
+statetype s_NMEsaucer3 = {false,NMESAUCER_03,6,T_Saucer,0,&s_NMEsaucer4};
+statetype s_NMEsaucer2 = {false,NMESAUCER_02,6,T_Saucer,0,&s_NMEsaucer3};
+statetype s_NMEsaucer1 = {false,NMESAUCER_01,6,T_Saucer,SF_SOUND,&s_NMEsaucer2};
+
+statetype s_NMEdie = {16,NMEBODY1_01,0,T_Collide,0,&s_NMEdie};
+
+
+statetype s_NMEspinfire = {16,NMEBODY1_01,0,T_NME_SpinFire,0,&s_NMEspinfire};
+statetype s_NMEattack = {16,NMEBODY1_01,0,T_NME_Attack,0,&s_NMEattack};
+statetype s_NMEhead1rl = {16,NMEROCKET_01,0,NULL,0,&s_NMEhead1rl};
+statetype s_NMEhead2rl = {16,NMEROCKET2_01,0,NULL,0,&s_NMEhead2rl};
+
+statetype s_NMEwindup = {16,NMEBODY1_01,0,T_NME_WindUp,0,&s_NMEwindup};
+
+statetype s_NMEwheels120 = {16,NMEWHEEL1_01,0,NULL,0,&s_NMEwheels120};
+
+statetype s_NMEwrotleft3 = {16,NMEWHEEL4_01,10,NULL,0,&s_NMEwrotleft3};
+statetype s_NMEwrotleft2 = {16,NMEWHEEL3_01,10,NULL,0,&s_NMEwrotleft3};
+statetype s_NMEwrotleft1 = {16,NMEWHEEL2_01,10,NULL,0,&s_NMEwrotleft2};
+
+statetype s_NMEwrotright3 = {16,NMEWHEEL4_01,10,NULL,0,&s_NMEwrotleft3};
+statetype s_NMEwrotright2 = {16,NMEWHEEL5_01,10,NULL,0,&s_NMEwrotleft3};
+statetype s_NMEwrotright1 = {16,NMEWHEEL2_01,10,NULL,0,&s_NMEwrotleft2};
+
+statetype  s_oshuriken4 = {false,SPR_OSHUR4,1,T_Projectile,0,&s_oshuriken1};
+statetype  s_oshuriken3 = {false,SPR_OSHUR3,1,T_Projectile,0,&s_oshuriken4};
+statetype  s_oshuriken2 = {false,SPR_OSHUR2,1,T_Projectile,0,&s_oshuriken3};
+statetype  s_oshuriken1 = {false,SPR_OSHUR1,1,T_Projectile,0,&s_oshuriken2};
+
+statetype  s_oshurikenhit3 = {false,SPR_OSHURHIT3,3,NULL,0,NULL};
+statetype  s_oshurikenhit2 = {false,SPR_OSHURHIT2,3,NULL,0,&s_oshurikenhit3};
+statetype  s_oshurikenhit1 = {false,SPR_OSHURHIT1,3,NULL,0,&s_oshurikenhit2};
+
+statetype s_speardown16 = {false,SPEARDOWN16,2,T_Spears,SF_CRUSH,&s_speardown1};
+statetype s_speardown15 = {false,SPEARDOWN15,2,T_Spears,SF_CRUSH,&s_speardown16};
+statetype s_speardown14 = {false,SPEARDOWN14,2,T_Spears,SF_CRUSH,&s_speardown15};
+statetype s_speardown13 = {false,SPEARDOWN13,2,T_Spears,SF_CRUSH,&s_speardown14};
+statetype s_speardown12 = {false,SPEARDOWN12,2,T_Spears,SF_CRUSH,&s_speardown13};
+statetype s_speardown11 = {false,SPEARDOWN11,2,T_Spears,SF_CRUSH,&s_speardown12};
+statetype s_speardown10 = {false,SPEARDOWN10,2,T_Spears,SF_CRUSH,&s_speardown11};
+statetype s_speardown9 = {false,SPEARDOWN9,2,T_Spears,SF_DOWN,&s_speardown10};
+
+statetype s_speardown8 = {false,SPEARDOWN8,35,T_Spears,SF_DOWN|SF_SOUND,&s_speardown9};
+statetype s_speardown7 = {false,SPEARDOWN7,2,T_Spears,SF_DOWN,&s_speardown8};
+statetype s_speardown6 = {false,SPEARDOWN6,2,T_Spears,SF_CRUSH,&s_speardown7};
+statetype s_speardown5 = {false,SPEARDOWN5,2,T_Spears,SF_CRUSH,&s_speardown6};
+statetype s_speardown4 = {false,SPEARDOWN4,2,T_Spears,SF_CRUSH,&s_speardown5};
+statetype s_speardown3 = {false,SPEARDOWN3,2,T_Spears,SF_CRUSH,&s_speardown4};
+statetype s_speardown2 = {false,SPEARDOWN2,2,T_Spears,SF_CRUSH,&s_speardown3};
+statetype s_speardown1 = {false,SPEARDOWN1,2,T_Spears,SF_CRUSH,&s_speardown2};
+
+
+
+statetype s_downblade16 = {false,DBLADE8,1,T_Path,0,&s_downblade1};
+statetype s_downblade15 = {false,DBLADE7,2,T_Path,0,&s_downblade16};
+statetype s_downblade14 = {false,DBLADE6,1,T_Path,0,&s_downblade15};
+statetype s_downblade13 = {false,DBLADE5,2,T_Path,0,&s_downblade14};
+statetype s_downblade12 = {false,DBLADE4,1,T_Path,0,&s_downblade13};
+statetype s_downblade11 = {false,DBLADE3,2,T_Path,0,&s_downblade12};
+statetype s_downblade10 = {false,DBLADE2,1,T_Path,0,&s_downblade11};
+statetype s_downblade9 = {false,DBLADE9,2,T_Path,0,&s_downblade10};
+statetype s_downblade8 = {false,DBLADE8,1,T_Path,0,&s_downblade9};
+statetype s_downblade7 = {false,DBLADE7,2,T_Path,0,&s_downblade8};
+statetype s_downblade6 = {false,DBLADE6,1,T_Path,0,&s_downblade7};
+statetype s_downblade5 = {false,DBLADE5,2,T_Path,0,&s_downblade6};
+statetype s_downblade4 = {false,DBLADE4,1,T_Path,0,&s_downblade5};
+statetype s_downblade3 = {false,DBLADE3,2,T_Path,0,&s_downblade4};
+statetype s_downblade2 = {false,DBLADE2,1,T_Path,0,&s_downblade3};
+statetype s_downblade1 = {false,DBLADE1,2,T_Path,SF_SOUND,&s_downblade2};
+
+
+statetype s_firejetdown23 = {false,FIREJETDOWN23,3,T_Path,SF_CRUSH,&s_firejetdown1};
+statetype s_firejetdown22 = {false,FIREJETDOWN22,3,T_Path,SF_CRUSH,&s_firejetdown23};
+statetype s_firejetdown21 = {false,FIREJETDOWN21,3,T_Path,0,&s_firejetdown22};
+statetype s_firejetdown20 = {false,FIREJETDOWN20,3,T_Path,0,&s_firejetdown21};
+statetype s_firejetdown19 = {false,FIREJETDOWN19,3,T_Path,0,&s_firejetdown20};
+statetype s_firejetdown18 = {false,FIREJETDOWN18,3,T_Path,0,&s_firejetdown19};
+statetype s_firejetdown17 = {false,FIREJETDOWN17,3,T_Path,0,&s_firejetdown18};
+statetype s_firejetdown16 = {false,FIREJETDOWN16,3,T_Path,SF_CRUSH,&s_firejetdown17};
+statetype s_firejetdown15 = {false,FIREJETDOWN15,3,T_Path,SF_CRUSH,&s_firejetdown16};
+statetype s_firejetdown14 = {false,FIREJETDOWN14,3,T_Path,SF_CRUSH,&s_firejetdown15};
+statetype s_firejetdown13 = {false,FIREJETDOWN13,3,T_Path,0,&s_firejetdown14};
+statetype s_firejetdown12 = {false,FIREJETDOWN12,3,T_Path,0,&s_firejetdown13};
+statetype s_firejetdown11 = {false,FIREJETDOWN11,3,T_Path,0,&s_firejetdown12};
+statetype s_firejetdown10 = {false,FIREJETDOWN10,3,T_Path,0,&s_firejetdown11};
+statetype s_firejetdown9 = {false,FIREJETDOWN9,3,T_Path,0,&s_firejetdown10};
+statetype s_firejetdown8 = {false,FIREJETDOWN8,3,T_Path,SF_CRUSH,&s_firejetdown9};
+statetype s_firejetdown7 = {false,FIREJETDOWN7,3,T_Path,SF_CRUSH,&s_firejetdown8};
+statetype s_firejetdown6 = {false,FIREJETDOWN6,3,T_Path,SF_CRUSH,&s_firejetdown7};
+statetype s_firejetdown5 = {false,FIREJETDOWN5,3,T_Path,0,&s_firejetdown6};
+statetype s_firejetdown4 = {false,FIREJETDOWN4,3,T_Path,0,&s_firejetdown5};
+statetype s_firejetdown3 = {false,FIREJETDOWN3,3,T_Path,0,&s_firejetdown4};
+statetype s_firejetdown2 = {false,FIREJETDOWN2,3,T_Path,0,&s_firejetdown3};
+statetype s_firejetdown1 = {false,FIREJETDOWN1,70,T_Path,SF_SOUND,&s_firejetdown2};
+
+
+
+statetype s_columnupdown6 = {false,CRUSHUP7,5,T_CrushUp,SF_DOWN,&s_columnupup1};
+statetype s_columnupdown5 = {false,CRUSHUP6,2,T_CrushUp,SF_DOWN,&s_columnupdown6};
+statetype s_columnupdown4 = {false,CRUSHUP5,5,T_CrushUp,SF_DOWN|SF_BLOCK,&s_columnupdown5};
+statetype s_columnupdown3 = {false,CRUSHUP4,5,T_CrushUp,SF_DOWN|SF_BLOCK,&s_columnupdown4};
+statetype s_columnupdown2 = {false,CRUSHUP3,5,T_CrushUp,SF_DOWN|SF_BLOCK,&s_columnupdown3};
+statetype s_columnupdown1 = {false,CRUSHUP2,2,T_CrushUp,SF_DOWN|SF_BLOCK,&s_columnupdown2};
+
+
+statetype s_columnupup8 = {false,CRUSHUP1,5,T_CrushUp,SF_CRUSH|SF_BLOCK,&s_columnupdown1};
+statetype s_columnupup7 = {false,CRUSHUP2,2,T_CrushUp,SF_CRUSH|SF_UP|SF_BLOCK,&s_columnupup8};
+statetype s_columnupup6 = {false,CRUSHUP3,5,T_CrushUp,SF_UP|SF_BLOCK,&s_columnupup7};
+statetype s_columnupup5 = {false,CRUSHUP4,5,T_CrushUp,SF_UP|SF_BLOCK,&s_columnupup6};
+statetype s_columnupup4 = {false,CRUSHUP5,5,T_CrushUp,SF_UP,&s_columnupup5};
+statetype s_columnupup3 = {false,CRUSHUP6,2,T_CrushUp,SF_UP,&s_columnupup4};
+statetype s_columnupup2 = {false,CRUSHUP7,5,T_CrushUp,SF_UP,&s_columnupup3};
+statetype s_columnupup1 = {false,CRUSHUP8,30,T_CrushUp,SF_SOUND,&s_columnupup2};
+
+
+
+statetype s_spinupblade16 = {false,SPINUBLADE_16,2,T_Path,SF_DOWN,&s_spinupblade1};
+statetype s_spinupblade15 = {false,SPINUBLADE_15,2,T_Path,0,&s_spinupblade16};
+statetype s_spinupblade14 = {false,SPINUBLADE_14,2,T_Path,0,&s_spinupblade15};
+statetype s_spinupblade13 = {false,SPINUBLADE_13,2,T_Path,0,&s_spinupblade14};
+statetype s_spinupblade12 = {false,SPINUBLADE_12,2,T_Path,0,&s_spinupblade13};
+statetype s_spinupblade11 = {false,SPINUBLADE_11,2,T_Path,0,&s_spinupblade12};
+statetype s_spinupblade10 = {false,SPINUBLADE_10,2,T_Path,0,&s_spinupblade11};
+statetype s_spinupblade9 = {false,SPINUBLADE_09,2,T_Path,0,&s_spinupblade10};
+
+statetype s_spinupblade8 = {false,SPINUBLADE_08,2,T_Path,0,&s_spinupblade9};
+statetype s_spinupblade7 = {false,SPINUBLADE_07,2,T_Path,0,&s_spinupblade8};
+statetype s_spinupblade6 = {false,SPINUBLADE_06,2,T_Path,0,&s_spinupblade7};
+statetype s_spinupblade5 = {false,SPINUBLADE_05,2,T_Path,0,&s_spinupblade6};
+statetype s_spinupblade4 = {false,SPINUBLADE_04,2,T_Path,0,&s_spinupblade5};
+statetype s_spinupblade3 = {false,SPINUBLADE_03,2,T_Path,0,&s_spinupblade4};
+statetype s_spinupblade2 = {false,SPINUBLADE_02,2,T_Path,0,&s_spinupblade3};
+statetype s_spinupblade1 = {false,SPINUBLADE_01,35,T_Path,SF_UP|SF_SOUND,&s_spinupblade2};
+
+
+statetype s_spindownblade16 = {false,SPINDBLADE_16,2,T_Path,SF_DOWN,&s_spindownblade1};
+statetype s_spindownblade15 = {false,SPINDBLADE_15,2,T_Path,0,&s_spindownblade16};
+statetype s_spindownblade14 = {false,SPINDBLADE_14,2,T_Path,0,&s_spindownblade15};
+statetype s_spindownblade13 = {false,SPINDBLADE_13,2,T_Path,0,&s_spindownblade14};
+statetype s_spindownblade12 = {false,SPINDBLADE_12,2,T_Path,0,&s_spindownblade13};
+statetype s_spindownblade11 = {false,SPINDBLADE_11,2,T_Path,0,&s_spindownblade12};
+statetype s_spindownblade10 = {false,SPINDBLADE_10,2,T_Path,0,&s_spindownblade11};
+statetype s_spindownblade9 = {false,SPINDBLADE_09,2,T_Path,0,&s_spindownblade10};
+
+statetype s_spindownblade8 = {false,SPINDBLADE_08,2,T_Path,0,&s_spindownblade9};
+statetype s_spindownblade7 = {false,SPINDBLADE_07,2,T_Path,0,&s_spindownblade8};
+statetype s_spindownblade6 = {false,SPINDBLADE_06,2,T_Path,0,&s_spindownblade7};
+statetype s_spindownblade5 = {false,SPINDBLADE_05,2,T_Path,0,&s_spindownblade6};
+statetype s_spindownblade4 = {false,SPINDBLADE_04,2,T_Path,0,&s_spindownblade5};
+statetype s_spindownblade3 = {false,SPINDBLADE_03,2,T_Path,0,&s_spindownblade4};
+statetype s_spindownblade2 = {false,SPINDBLADE_02,2,T_Path,0,&s_spindownblade3};
+statetype s_spindownblade1 = {false,SPINDBLADE_01,35,T_Path,SF_UP|SF_SOUND,&s_spindownblade2};
+
+
+statetype s_bouldersink9 = {false,BSINK9,2,NULL,0,NULL};
+statetype s_bouldersink8 = {false,BSINK8,2,NULL,0,&s_bouldersink9};
+statetype s_bouldersink7 = {false,BSINK7,2,NULL,0,&s_bouldersink8};
+statetype s_bouldersink6 = {false,BSINK6,2,NULL,0,&s_bouldersink7};
+statetype s_bouldersink5 = {false,BSINK5,2,NULL,0,&s_bouldersink6};
+statetype s_bouldersink4 = {false,BSINK4,2,NULL,0,&s_bouldersink5};
+statetype s_bouldersink3 = {false,BSINK3,2,NULL,0,&s_bouldersink4};
+statetype s_bouldersink2 = {false,BSINK2,2,NULL,0,&s_bouldersink3};
+statetype s_bouldersink1 = {false,BSINK1,2,NULL,0,&s_bouldersink2};
+
+
+statetype s_boulderroll8 = {false,BOULDER41,3,T_BoulderMove,0,&s_boulderroll1};
+statetype s_boulderroll7 = {false,BOULDER31,3,T_BoulderMove,0,&s_boulderroll8};
+statetype s_boulderroll6 = {false,BOULDER21,3,T_BoulderMove,0,&s_boulderroll7};
+statetype s_boulderroll5 = {false,BOULDER11,3,T_BoulderMove,0,&s_boulderroll6};
+statetype s_boulderroll4 = {false,BOULDER41,3,T_BoulderMove,0,&s_boulderroll5};
+statetype s_boulderroll3 = {false,BOULDER31,3,T_BoulderMove,0,&s_boulderroll4};
+statetype s_boulderroll2 = {false,BOULDER21,3,T_BoulderMove,0,&s_boulderroll3};
+statetype s_boulderroll1 = {false,BOULDER11,3,T_BoulderMove,SF_SOUND,&s_boulderroll2};
+
+
+
+
+statetype s_boulderdrop12 = {false,BOULDER11,0,T_BoulderDrop,0,&s_boulderdrop12};
+statetype s_boulderdrop11 = {false,BDROP11,1,T_BoulderDrop,0,&s_boulderdrop12};
+statetype s_boulderdrop10 = {false,BDROP10,1,T_BoulderDrop,0,&s_boulderdrop11};
+statetype s_boulderdrop9 = {false,BDROP9,2,T_BoulderDrop,0,&s_boulderdrop10};
+statetype s_boulderdrop8 = {false,BDROP8,1,T_BoulderDrop,0,&s_boulderdrop9};
+statetype s_boulderdrop7 = {false,BDROP7,1,T_BoulderDrop,0,&s_boulderdrop8};
+statetype s_boulderdrop6 = {false,BDROP6,2,T_BoulderDrop,0,&s_boulderdrop7};
+statetype s_boulderdrop5 = {false,BDROP5,3,T_BoulderDrop,0,&s_boulderdrop6};
+statetype s_boulderdrop4 = {false,BDROP4,4,T_BoulderDrop,0,&s_boulderdrop5};
+statetype s_boulderdrop3 = {false,BDROP3,5,T_BoulderDrop,SF_SOUND,&s_boulderdrop4};
+statetype s_boulderdrop2 = {false,BDROP2,6,NULL,0,&s_boulderdrop3};
+statetype s_boulderdrop1 = {false,BDROP1,6,NULL,0,&s_boulderdrop2};
+
+statetype s_boulderspawn = {false,NOTHING,70,T_BoulderSpawn,0,&s_boulderspawn};
+
+
+
+/*==========================================================================
+
+									GUN STUFF
+
+============================================================================*/
+
+statetype s_gunfire2 = {true,GUNRISE51,5,A_GunShoot,0,&s_gunfire1};
+statetype s_gunfire1 = {true,GUNFIRE1,5,A_GunShoot,0,&s_gunfire2};
+
+statetype s_gunstand = {true,GUNRISE11,0,T_GunStand,0,&s_gunstand};
+
+statetype s_gunraise4 = {true,GUNRISE51,2,NULL,0,&s_gunfire1};
+statetype s_gunraise3 = {true,GUNRISE41,2,NULL,0,&s_gunraise4};
+statetype s_gunraise2 = {true,GUNRISE31,2,NULL,0,&s_gunraise3};
+statetype s_gunraise1 = {true,GUNRISE21,2,NULL,0,&s_gunraise2};
+
+statetype s_gunlower3 = {true,GUNRISE21,2,NULL,0,&s_gunstand};
+statetype s_gunlower2 = {true,GUNRISE31,2,NULL,0,&s_gunlower3};
+statetype s_gunlower1 = {true,GUNRISE41,2,NULL,0,&s_gunlower2};
+
+
+statetype s_gundead = {false,GUNDEAD2,0,T_Collide,0,&s_gundead};
+statetype s_gundie1 = {false,GUNDEAD1,5,NULL,0,&s_gundead};
+
+
+
+//======================================================================//
+
+statetype s_4waygunfire1 = {true,FOURWAYFIRE01,5,A_4WayGunShoot,0,&s_4waygunfire2};
+statetype s_4waygunfire2 = {true,FOURWAY01,5,NULL,0,&s_4waygunfire1};
+
+statetype s_4waygun = {true,FOURWAY01,0,T_4WayGunStand,0,&s_4waygun};
+
+
+
+
+statetype s_kessphere8 = {false,KESSPHERE8,2,T_Projectile,0,&s_kessphere1};
+statetype s_kessphere7 = {false,KESSPHERE7,2,T_Projectile,0,&s_kessphere8};
+statetype s_kessphere6 = {false,KESSPHERE6,2,T_Projectile,0,&s_kessphere7};
+statetype s_kessphere5 = {false,KESSPHERE5,2,T_Projectile,0,&s_kessphere6};
+statetype s_kessphere4 = {false,KESSPHERE4,2,T_Projectile,0,&s_kessphere5};
+statetype s_kessphere3 = {false,KESSPHERE3,2,T_Projectile,0,&s_kessphere4};
+statetype s_kessphere2 = {false,KESSPHERE2,2,T_Projectile,0,&s_kessphere3};
+statetype s_kessphere1 = {false,KESSPHERE1,2,T_Projectile,0,&s_kessphere2};
+
+
+statetype s_slop4 = {false,TOMSPIT4,3,T_Particle,0,&s_slop1};
+statetype s_slop3 = {false,TOMSPIT3,3,T_Particle,0,&s_slop4};
+statetype s_slop2 = {false,TOMSPIT2,3,T_Particle,0,&s_slop3};
+statetype s_slop1 = {false,TOMSPIT1,3,T_Particle,0,&s_slop2};
+
+
+statetype s_batblast4 = {false,BATBLAST4,3,T_Projectile,SF_BAT,&s_batblast1};
+statetype s_batblast3 = {false,BATBLAST3,3,T_Projectile,SF_BAT,&s_batblast4};
+statetype s_batblast2 = {false,BATBLAST2,3,T_Projectile,SF_BAT,&s_batblast3};
+statetype s_batblast1 = {false,BATBLAST1,3,T_Projectile,SF_BAT,&s_batblast2};
+
+
+statetype s_serialdog4 = {true,SERIALDOG_W41,5,T_Player,SF_DOGSTATE,&s_serialdog};
+statetype s_serialdog3 = {true,SERIALDOG_W31,5,T_Player,SF_DOGSTATE,&s_serialdog4};
+statetype s_serialdog2 = {true,SERIALDOG_W21,5,T_Player,SF_DOGSTATE,&s_serialdog3};
+statetype s_serialdog = {true,SERIALDOG_W11,5,T_Player,SF_DOGSTATE,&s_serialdog2};
+statetype s_serialdogattack = {true,SERIALDOG_ATTACK1,0,T_Attack,SF_DOGSTATE,&s_serialdogattack };
+
+
+#endif
+
+
+#include "rt_table.h"
--- /dev/null
+++ b/rott/rt_str.c
@@ -1,0 +1,2055 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+//******************************************************************************
+//
+// RT_STR.C
+//    Contains the menu stuff!
+//
+//******************************************************************************
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+
+#include <string.h>
+#include <ctype.h>
+#include "rt_def.h"
+#include "rt_menu.h"
+#include "rt_util.h"
+#include "rt_vid.h"
+#include "rt_build.h"
+#include "lumpy.h"
+#include "rt_str.h"
+#include "_rt_str.h"
+#include "isr.h"
+#include "rt_in.h"
+#include "rt_menu.h"
+#include "rt_view.h"
+#include "w_wad.h"
+#include "z_zone.h"
+#include "modexlib.h"
+#include "rt_main.h"
+#include "rt_msg.h"
+#include "rt_playr.h"
+#include "rt_sound.h"
+#include "myprint.h"
+//MED
+#include "memcheck.h"
+
+
+//******************************************************************************
+//
+// GLOBALS
+//
+//******************************************************************************
+
+int fontcolor;
+
+//******************************************************************************
+//
+// LOCALS
+//
+//******************************************************************************
+
+static int BKw;
+static int BKh;
+
+static char strbuf[MaxString];
+
+//******************************************************************************
+//
+// VW_DrawClippedString ()
+//
+// Draws a string at x, y to bufferofs
+//
+//******************************************************************************
+
+void VW_DrawClippedString (int x, int y, const char *string)
+{
+    int   width,height,ht;
+    byte  *source;
+    int   ch;
+    int   oy;
+
+    ht = CurrentFont->height;
+
+    oy=y;
+
+    while ((ch = (unsigned char)*string++)!=0)
+    {
+        ch -= 31;
+        width = CurrentFont->width[ch];
+        source = ((byte *)CurrentFont)+CurrentFont->charofs[ch];
+        while (width--)
+        {
+            if ((x>=0) && (x<iGLOBAL_SCREENWIDTH))
+            {
+                y=oy;
+                VGAWRITEMAP(x&3);
+                height = ht;
+                while (height--)
+                {
+                    if ((y>=0) && (y<iGLOBAL_SCREENHEIGHT))
+                    {
+                        if (*source>0)
+#ifdef DOS
+                            *((byte *)(bufferofs+ylookup[y]+(x>>2))) = *source;
+#else
+                            *((byte *)(bufferofs+ylookup[y]+x)) = *source;
+#endif
+                    }
+                    source++;
+                    y++;
+                }
+            }
+            x++;
+        }
+    }
+}
+
+//******************************************************************************
+//
+// US_ClippedPrint() - Prints a string in bufferofs. Newlines are supported.
+//
+//******************************************************************************
+
+void US_ClippedPrint (int x, int y, const char *string)
+{
+    char  c,
+          *se;
+    char  *s;
+    int   startx;
+
+    strcpy(strbuf, string);
+    s = strbuf;
+
+    startx=x;
+    while (*s)
+    {
+        se = s;
+        while ((c = *se) && (c != '\n'))
+            se++;
+        *se = '\0';
+
+        VW_DrawClippedString ( x, y, s);
+
+        s = se;
+        if (c)
+        {
+            *se = c;
+            s++;
+            y += CurrentFont->height;
+        }
+    }
+}
+
+
+//******************************************************************************
+//
+// VW_DrawPropString ()
+//
+// Draws a string at px, py to bufferofs
+//
+//******************************************************************************
+
+void VW_DrawPropString (const char *string)
+{
+#ifdef DOS
+    byte  pix;
+    int   width,step,height,ht;
+    byte  *source, *dest, *origdest;
+    int   ch,mask;
+
+
+    ht = CurrentFont->height;
+    dest = origdest = (byte *)(bufferofs+ylookup[py]+(px>>2));
+
+
+    mask = 1<<(px&3);
+
+
+    while ((ch = *string++)!=0)
+    {
+        ch -= 31;
+        width = step = CurrentFont->width[ch];
+        source = ((byte *)CurrentFont)+CurrentFont->charofs[ch];
+        while (width--)
+        {
+            VGAMAPMASK(mask);
+
+            height = ht;
+            while (height--)
+            {
+                pix = *source;
+                if (pix)
+                    *dest = pix;
+
+                source++;
+                dest += linewidth;
+            }
+
+            px++;
+            mask <<= 1;
+            if (mask == 16)
+            {
+                mask = 1;
+                origdest++;
+            }
+            dest = origdest;
+        }
+    }
+    bufferheight = ht;
+    bufferwidth = ((dest+1)-origdest)*4;
+#else
+    byte  pix;
+    int   width,step,height,ht;
+    byte  *source, *dest, *origdest;
+    int   ch,mask;
+
+    ht = CurrentFont->height;
+    dest = origdest = (byte *)(bufferofs+ylookup[py]+px);
+
+    while ((ch = (unsigned char)*string++)!=0)
+    {
+        ch -= 31;
+        width = step = CurrentFont->width[ch];
+        source = ((byte *)CurrentFont)+CurrentFont->charofs[ch];
+        while (width--)
+        {
+            height = ht;
+            while (height--)
+            {
+                pix = *source;
+                if (pix)
+                    *dest = pix;
+
+                source++;
+                dest += linewidth;
+            }
+
+            px++;
+            origdest++;
+            dest = origdest;
+        }
+    }
+    bufferheight = ht;
+    bufferwidth = ((dest+1)-origdest);
+#endif
+}
+
+
+
+//******************************************************************************
+//
+// VWB_DrawPropString ()
+//
+// Calls VW_DrawPropString then updates the mark block.
+//
+//******************************************************************************
+
+void VWB_DrawPropString  (const char *string)
+{
+    int x;
+    x = px;
+    VW_DrawPropString (string);
+    VW_MarkUpdateBlock (x, py, px-1, py+bufferheight-1);
+}
+
+
+
+//******************************************************************************
+//
+// VW_DrawIPropString ()
+//
+// Draws a string at px, py to bufferofs
+//
+//******************************************************************************
+
+void VW_DrawIPropString (const char *string)
+{
+    byte  pix;
+    int   width,step,height,ht;
+    byte  *source, *dest, *origdest;
+    int   ch,mask;
+
+
+    ht = CurrentFont->height;
+#ifdef DOS
+    dest = origdest = (byte *)(bufferofs+ylookup[py]+(px>>2));
+#else
+    dest = origdest = (byte *)(bufferofs+ylookup[py]+px);
+#endif
+
+
+    mask = 1<<(px&3);
+
+
+    while ((ch = (unsigned char)*string++)!=0)
+    {
+        ch -= 31;
+        width = step = CurrentFont->width[ch];
+        source = ((byte *)CurrentFont)+CurrentFont->charofs[ch];
+        while (width--)
+        {
+            VGAMAPMASK(mask);
+
+            height = ht;
+            while (height--)
+            {
+                pix = *source;
+                if (pix)
+                    *dest = pix;
+
+                source++;
+                dest += linewidth;
+            }
+
+            px++;
+#ifdef DOS
+            mask <<= 1;
+            if (mask == 16)
+            {
+                mask = 1;
+                origdest++;
+            }
+#else
+            origdest++;
+#endif
+            dest = origdest;
+        }
+    }
+    bufferheight = ht;
+#ifdef DOS
+    bufferwidth = ((dest+1)-origdest)*4;
+#else
+    bufferwidth = ((dest+1)-origdest);
+#endif
+
+}
+
+
+
+//******************************************************************************
+//
+// VWB_DrawIPropString ()
+//
+// Calls VW_DrawIPropString then updates the mark block.
+//
+//******************************************************************************
+
+void VWB_DrawIPropString  (const char *string)
+{
+    int x;
+    x = px;
+    VW_DrawIPropString (string);
+    VW_MarkUpdateBlock (x, py, px-1, py+bufferheight-1);
+}
+
+
+
+//******************************************************************************
+//
+// VWL_MeasureString ()
+//
+//******************************************************************************
+
+void VWL_MeasureString (const char *s, int *width, int *height, const font_t *font)
+{
+    *height = font->height;
+
+    for (*width = 0; *s; s++)
+        *width += font->width[(*((byte *)s))-31];   // proportional width
+}
+
+//******************************************************************************
+//
+// VWL_MeasureIntensityString ()
+//
+//******************************************************************************
+
+void VWL_MeasureIntensityString (const char *s, int *width, int *height, const cfont_t *font)
+{
+    *height = font->height;
+
+    for (*width = 0; *s; s++)
+        *width += font->width[(*((byte *)s))-31];   // proportional width
+}
+
+//******************************************************************************
+//
+// VW_MeasureIntensityPropString ()
+//
+//******************************************************************************
+
+void VW_MeasureIntensityPropString (const char *string, int *width, int *height)
+{
+    VWL_MeasureIntensityString (string, width, height, IFont);
+}
+
+//******************************************************************************
+//
+// VW_MeasurePropString ()
+//
+//******************************************************************************
+
+void VW_MeasurePropString (const char *string, int *width, int *height)
+{
+    VWL_MeasureString (string, width, height, CurrentFont);
+}
+
+
+//******************************************************************************
+//
+// US_MeasureStr ()
+//
+//******************************************************************************
+
+void US_MeasureStr (int *width, int *height, const char * s, ...)
+{
+    char  c,
+          *se,
+          *ss;
+    int   w,h;
+    va_list strptr;
+    char buf[300];
+
+    *width  = 0;
+    *height = 0;
+
+    memset (&buf[0], 0, sizeof (buf));
+    va_start (strptr, s);
+    vsprintf (&buf[0], s, strptr);
+    va_end (strptr);
+
+    ss = &buf[0];
+
+    while (*ss)
+    {
+        se = ss;
+        while ((c = *se) && (c != '\n'))
+            se++;
+        *se = '\0';
+
+        VWL_MeasureString (ss, &w, &h, CurrentFont);
+
+        *height += h;
+
+        if (w > *width)
+            *width = w;
+
+        ss = se;
+        if (c)
+        {
+            *se = c;
+            ss++;
+        }
+    }
+}
+
+
+//******************************************************************************
+//
+// US_SetPrintRoutines() - Sets the routines used to measure and print
+//    from within the User Mgr. Primarily provided to allow switching
+//    between masked and non-masked fonts
+//
+//******************************************************************************
+
+void US_SetPrintRoutines (void (*measure)(const char *, int *, int *, font_t *),
+                          void (*print)(const char *))
+{
+    USL_MeasureString = measure;
+    USL_DrawString    = print;
+}
+
+
+//******************************************************************************
+//
+// US_Print() - Prints a string in the current window. Newlines are
+//    supported.
+//
+//******************************************************************************
+
+void US_Print (const char *string)
+{
+    char  c,
+          *se,
+          *s;
+    int   w,h;
+
+    strcpy(strbuf, string);
+    s = strbuf;
+
+    while (*s)
+    {
+        se = s;
+        while ((c = *se) && (c != '\n'))
+            se++;
+        *se = '\0';
+
+        USL_MeasureString (s, &w, &h, CurrentFont);
+        px = PrintX;
+        py = PrintY;
+        USL_DrawString (s);
+
+        s = se;
+        if (c)
+        {
+            *se = c;
+            s++;
+
+            PrintX = WindowX;
+            PrintY += h;
+        }
+        else
+            PrintX += w;
+    }
+}
+
+//******************************************************************************
+//
+// US_BufPrint() - Prints a string in bufferofs. Newlines are supported.
+//
+//******************************************************************************
+
+void US_BufPrint (const char *string)
+{
+    char  c,
+          *se,
+          *s;
+    int   startx;
+
+    strcpy(strbuf, string);
+    s = strbuf;
+
+    startx=PrintX;
+    while (*s)
+    {
+        se = s;
+        while ((c = *se) && (c != '\n'))
+            se++;
+        *se = '\0';
+
+        px = PrintX;
+        py = PrintY;
+        USL_DrawString (s);
+
+        PrintY = py;
+        PrintX = px;
+
+        s = se;
+        if (c)
+        {
+            *se = c;
+            s++;
+            PrintY += CurrentFont->height;
+            PrintX = startx;
+        }
+    }
+}
+
+
+//******************************************************************************
+//
+// US_PrintUnsigned () - Prints an unsigned long int
+//
+//******************************************************************************
+
+void US_PrintUnsigned (unsigned long int n)
+{
+    char  buffer[32];
+
+    US_Print (ultoa (n, buffer, 10));
+}
+
+//******************************************************************************
+//
+// US_PrintSigned() - Prints a signed long
+//
+//******************************************************************************
+
+void US_PrintSigned (long int n)
+{
+    char  buffer[32];
+
+    US_Print (ltoa (n, buffer, 10));
+}
+
+//******************************************************************************
+//
+// USL_PrintInCenter() - Prints a string in the center of the given rect
+//
+//******************************************************************************
+
+void USL_PrintInCenter (const char *s, Rect r)
+{
+    int   w,h,
+          rw,rh;
+
+    USL_MeasureString (s,&w,&h, CurrentFont);
+    rw = r.lr.x - r.ul.x;
+    rh = r.lr.y - r.ul.y;
+
+    px = r.ul.x + ((rw - w) / 2);
+    py = r.ul.y + ((rh - h) / 2);
+    USL_DrawString (s);
+}
+
+//******************************************************************************
+//
+// US_PrintCentered() - Prints a string centered in the current window.
+//
+//******************************************************************************
+
+void US_PrintCentered (const char *s)
+{
+    Rect  r;
+
+    r.ul.x = WindowX;
+    r.ul.y = WindowY;
+    r.lr.x = r.ul.x + WindowW;
+    r.lr.y = r.ul.y + WindowH;
+
+    USL_PrintInCenter (s, r);
+}
+
+//******************************************************************************
+//
+// US_CPrintLine() - Prints a string centered on the current line and
+//    advances to the next line. Newlines are not supported.
+//
+//******************************************************************************
+
+void US_CPrintLine (const char *s)
+{
+    int w, h;
+
+    USL_MeasureString (s, &w, &h, CurrentFont);
+
+    if (w > WindowW)
+        Error("US_CPrintLine() - String exceeds width");
+
+    px = WindowX + ((WindowW - w) / 2);
+    py = PrintY;
+    USL_DrawString (s);
+    PrintY += h;
+}
+
+//******************************************************************************
+//
+// US_CPrint() - Prints a string in the current window. Newlines are
+//    supported.
+//
+//******************************************************************************
+
+void US_CPrint (const char *string)
+{
+    char  c,
+          *se,
+          *s;
+
+    strcpy(strbuf, string);
+    s = strbuf;
+
+    while (*s)
+    {
+        se = s;
+        while ((c = *se) && (c != '\n'))
+            se++;
+        *se = '\0';
+
+        US_CPrintLine (s);
+
+        s = se;
+        if (c)
+        {
+            *se = c;
+            s++;
+        }
+    }
+}
+
+
+
+//
+//
+// Text Input routines
+//
+//
+//
+
+
+
+//******************************************************************************
+//
+// USL_XORICursor() - XORs the I-bar text cursor. Used by  US_LineInput()
+//
+//******************************************************************************
+
+static void USL_XORICursor (int x, int y, const char *s, int cursor, int color)
+{
+    static   boolean  status;     // VGA doesn't XOR...
+    char     buf[MaxString];
+
+    int      w,h;
+    int      oldx = px;
+    int      oldy = py;
+
+    strcpy (buf,s);
+    buf[cursor] = '\0';
+    USL_MeasureString (buf, &w, &h, CurrentFont);
+
+
+    if (status^=1)
+    {
+        px = x + w;
+        py = y;
+        if (color)
+            USL_DrawString ("\x80");
+        else
+            DrawMenuBufPropString (px, py, "\x80");
+    }
+    else
+    {
+        if (color)
+        {
+            VWB_Bar (px, py, BKw, BKh, color);
+            USL_DrawString (s);
+        }
+        else
+        {
+            EraseMenuBufRegion (px, py, BKw, BKh);
+//         EraseMenuBufRegion (px, py+1, BKw, BKh-2);
+            DrawMenuBufPropString (px, py, s);
+        }
+    }
+    px = oldx;
+    py = oldy;
+}
+
+
+
+
+
+
+//******************************************************************************
+//
+// US_LineInput() - Gets a line of user input at (x,y), the string defaults
+//    to whatever is pointed at by def. Input is restricted to maxchars
+//    chars or maxwidth pixels wide. If the user hits escape (and escok is
+//    true), nothing is copied into buf, and false is returned. If the
+//    user hits return, the current string is copied into buf, and true is
+//    returned
+//
+///******************************************************************************
+
+extern byte * IN_GetScanName (ScanCode scan);
+
+boolean US_LineInput (int x, int y, char *buf, const char *def, boolean escok,
+                      int maxchars, int maxwidth, int color)
+{
+    boolean  redraw,
+             cursorvis,
+             cursormoved,
+             done,
+             result;
+    char     s[MaxString],
+             olds[MaxString];
+    int      i,
+             cursor,
+             w,h,
+             len;
+
+    int      lasttime;
+
+
+    int      lastkey;
+    int      cursorwidth;
+
+    cursorwidth = CurrentFont->width[80-31];
+
+    memset (s, 0, MaxString);
+    memset (olds, 0, MaxString);
+    IN_ClearKeyboardQueue ();
+
+    BKw = maxwidth;
+    BKh = CurrentFont->height;
+
+
+    if (def)
+        strcpy (s, def);
+    else
+        *s = '\0';
+
+    *olds = '\0';
+
+    cursor      = strlen (s);
+    cursormoved = redraw = true;
+    cursorvis   = done   = false;
+
+    lasttime  = GetTicCount();
+
+
+    lastkey = getASCII ();
+
+    while (!done)
+    {
+//      if (GameEscaped==true)
+//         PauseLoop ();
+
+        IN_PumpEvents();
+
+        if (cursorvis)
+            USL_XORICursor (x, y, s, cursor, color);
+
+        LastScan = IN_InputUpdateKeyboard ();
+        if (Keyboard[sc_LShift] || Keyboard[sc_RShift])
+            lastkey = ShiftNames[LastScan];
+        else
+            lastkey = ASCIINames[LastScan];
+
+
+        switch (LastScan)
+        {
+        case sc_LeftArrow:
+
+            if (cursor)
+            {
+                cursor--;
+                cursormoved = true;
+                MN_PlayMenuSnd (SD_MOVECURSORSND);
+            }
+            lastkey = key_None;
+            Keyboard[sc_LeftArrow] = 0;
+            break;
+
+        case sc_RightArrow:
+
+            if (s[cursor])
+            {
+                cursor++;
+                cursormoved = true;
+                MN_PlayMenuSnd (SD_MOVECURSORSND);
+            }
+            lastkey = key_None;
+            Keyboard[sc_RightArrow] = 0;
+            break;
+
+        case sc_Home:
+
+            if ( cursor )
+            {
+                cursor = 0;
+                cursormoved = true;
+                MN_PlayMenuSnd (SD_MOVECURSORSND);
+            }
+            Keyboard[sc_Home] = 0;
+            lastkey = key_None;
+            break;
+
+        case sc_End:
+
+            if ( cursor != (int)strlen (s) )
+            {
+                cursor = strlen (s);
+                cursormoved = true;
+                MN_PlayMenuSnd (SD_MOVECURSORSND);
+            }
+            lastkey = key_None;
+            Keyboard[sc_End] = 0;
+            break;
+
+
+        case sc_Return:
+            strcpy (buf,s);
+            done = true;
+            result = true;
+            lastkey = key_None;
+            MN_PlayMenuSnd (SD_SELECTSND);
+            break;
+
+        case sc_Escape:
+            if (escok)
+            {
+                done = true;
+                result = false;
+                MN_PlayMenuSnd (SD_ESCPRESSEDSND);
+            }
+            lastkey = key_None;
+            break;
+
+        case sc_BackSpace:
+
+            if (cursor)
+            {
+                strcpy (s + cursor - 1,s + cursor);
+                cursor--;
+                redraw = true;
+                cursormoved = true;
+                MN_PlayMenuSnd (SD_MOVECURSORSND);
+            }
+            lastkey = key_None;
+            Keyboard[sc_BackSpace] = 0;
+            IN_ClearKeyboardQueue ();
+            break;
+
+        case sc_Delete:
+
+            if (s[cursor])
+            {
+                strcpy (s + cursor,s + cursor + 1);
+                redraw = true;
+                cursormoved = true;
+                MN_PlayMenuSnd (SD_MOVECURSORSND);
+            }
+            lastkey = key_None;
+            Keyboard[sc_Delete] = 0;
+            IN_ClearKeyboardQueue ();
+            break;
+
+        case 0x4c:  // Keypad 5
+        case sc_UpArrow:
+        case sc_DownArrow:
+        case sc_PgUp:
+        case sc_PgDn:
+        case sc_Insert:
+            lastkey = key_None;
+            break;
+        }
+
+//      if (GameEscaped==true)
+//         PauseLoop ();
+
+        if (lastkey)
+        {
+            len = strlen (s);
+            USL_MeasureString (s, &w, &h, CurrentFont);
+
+            if
+            (
+                isprint(lastkey)
+                && (len < MaxString - 1)
+                && ((!maxchars) || (len < maxchars))
+                && ((!maxwidth) || ((w+2) < (maxwidth-cursorwidth-2)))
+            )
+            {
+                int ls;
+                int rs;
+
+                for (i = len + 1; i > cursor; i--)
+                    s[i] = s[i - 1];
+                s[cursor++] = lastkey;
+                redraw = true;
+
+                ls = Keyboard[sc_LShift];
+                rs = Keyboard[sc_RShift];
+                memset ((void*)Keyboard, 0, 127*sizeof(int));       // Clear printable keys
+                Keyboard[sc_LShift] = ls;
+                Keyboard[sc_RShift] = rs;
+
+                MN_PlayMenuSnd (SD_MOVECURSORSND);
+            }
+        }
+
+//      if (GameEscaped==true)
+//         PauseLoop ();
+
+        if (redraw)
+        {
+            if (color)
+                VWB_Bar (x, y, BKw, BKh, color);
+            else
+                EraseMenuBufRegion (x, y, BKw, BKh);
+
+            strcpy (olds, s);
+
+            px = x;
+            py = y;
+            if (color)
+                USL_DrawString (s);
+            else
+                DrawMenuBufPropString (px, py, s);
+            px = x;
+            py = y;
+
+            redraw = false;
+        }
+
+        if (cursormoved)
+        {
+            cursorvis = false;
+            lasttime = GetTicCount() - VBLCOUNTER;
+
+            cursormoved = false;
+        }
+        if (GetTicCount() - lasttime > VBLCOUNTER / 2)
+        {
+            lasttime = GetTicCount();
+
+            cursorvis ^= true;
+        }
+        if (cursorvis)
+            USL_XORICursor (x, y, s, cursor, color);
+
+//      if (GameEscaped==true)
+//         PauseLoop ();
+
+        if (color)
+            VW_UpdateScreen ();
+        else
+            RefreshMenuBuf (0);
+    }
+
+    if (cursorvis)
+        USL_XORICursor (x, y, s, cursor, color);
+
+    if (!result)
+    {
+        px = x;
+        py = y;
+        if (color)
+            USL_DrawString (olds);
+        else
+            DrawMenuBufPropString (px, py, olds);
+    }
+
+//   if (GameEscaped==true)
+//      PauseLoop ();
+
+    if (color)
+        VW_UpdateScreen ();
+    else
+        RefreshMenuBuf (0);
+
+    IN_ClearKeyboardQueue ();
+    return (result);
+}
+
+
+//******************************************************************************
+//
+// US_lineinput() - Gets a line of user input at (x,y), the string defaults
+//    to whatever is pointed at by def. Input is restricted to maxchars
+//    chars or maxwidth pixels wide. If the user hits escape (and escok is
+//    true), nothing is copied into buf, and false is returned. If the
+//    user hits return, the current string is copied into buf, and true is
+//    returned - PASSWORD INPUT
+//
+///******************************************************************************
+
+boolean US_lineinput (int x, int y, char *buf, const char *def, boolean escok,
+                      int maxchars, int maxwidth, int color)
+{
+    boolean  redraw,
+             cursorvis,
+             cursormoved,
+             done,
+             result;
+    char     s[MaxString],
+             xx[MaxString],
+             olds[MaxString];
+    int      i,
+             cursor,
+             w,h,
+             len;
+
+    int      lasttime;
+
+
+    int      lastkey;
+    int      cursorwidth;
+
+    cursorwidth = CurrentFont->width[80-31];
+
+    memset (s, 0, MaxString);
+    memset (xx, 0, MaxString);
+    memset (olds, 0, MaxString);
+    IN_ClearKeyboardQueue ();
+
+    BKw = maxwidth;
+    BKh = CurrentFont->height;
+
+
+    if (def)
+        strcpy (s, def);
+    else
+        *s = '\0';
+
+    *olds = '\0';
+
+    cursor      = strlen (s);
+    cursormoved = redraw = true;
+    cursorvis   = done   = false;
+
+    lasttime  = GetTicCount();
+
+
+    lastkey = getASCII ();
+
+    while (!done)
+    {
+//      if (GameEscaped == true)
+//         PauseLoop ();
+
+        IN_PumpEvents();
+
+        if (cursorvis)
+            USL_XORICursor (x, y, xx, cursor, color);
+
+        LastScan = IN_InputUpdateKeyboard ();
+        if (Keyboard[sc_LShift] || Keyboard[sc_RShift])
+            lastkey = ShiftNames[LastScan];
+        else
+            lastkey = ASCIINames[LastScan];
+
+
+        switch (LastScan)
+        {
+        case sc_LeftArrow:
+
+            if (cursor)
+            {
+                cursor--;
+                cursormoved = true;
+                MN_PlayMenuSnd (SD_MOVECURSORSND);
+            }
+            lastkey = key_None;
+            Keyboard[sc_LeftArrow] = 0;
+            break;
+
+        case sc_RightArrow:
+
+            if (s[cursor])
+            {
+                cursor++;
+                cursormoved = true;
+                MN_PlayMenuSnd (SD_MOVECURSORSND);
+            }
+            lastkey = key_None;
+            Keyboard[sc_RightArrow] = 0;
+            break;
+
+        case sc_Home:
+
+            if ( cursor != 0 )
+            {
+                cursor = 0;
+                cursormoved = true;
+                MN_PlayMenuSnd (SD_MOVECURSORSND);
+            }
+            Keyboard[sc_Home] = 0;
+            lastkey = key_None;
+            break;
+
+        case sc_End:
+
+            if ( cursor != (int)strlen( s ) )
+            {
+                cursor = strlen (s);
+                cursormoved = true;
+                MN_PlayMenuSnd (SD_MOVECURSORSND);
+            }
+            lastkey = key_None;
+            Keyboard[sc_End] = 0;
+            break;
+
+        case sc_Return:
+            strcpy (buf,s);
+            done = true;
+            result = true;
+            lastkey = key_None;
+            MN_PlayMenuSnd (SD_SELECTSND);
+            break;
+
+        case sc_Escape:
+            if (escok)
+            {
+                done = true;
+                result = false;
+                MN_PlayMenuSnd (SD_ESCPRESSEDSND);
+            }
+            lastkey = key_None;
+            break;
+
+        case sc_BackSpace:
+
+            if (cursor)
+            {
+                strcpy (s + cursor - 1,s + cursor);
+                strcpy (xx + cursor - 1,xx + cursor);
+                cursor--;
+                redraw = true;
+                MN_PlayMenuSnd (SD_MOVECURSORSND);
+                cursormoved = true;
+            }
+            lastkey = key_None;
+            Keyboard[sc_BackSpace] = 0;
+            IN_ClearKeyboardQueue ();
+            break;
+
+        case sc_Delete:
+
+            if (s[cursor])
+            {
+                strcpy (s + cursor,s + cursor + 1);
+                strcpy (xx + cursor,xx + cursor + 1);
+                redraw = true;
+                cursormoved = true;
+                MN_PlayMenuSnd (SD_MOVECURSORSND);
+            }
+            lastkey = key_None;
+            Keyboard[sc_Delete] = 0;
+            IN_ClearKeyboardQueue ();
+            break;
+
+        case 0x4c:  // Keypad 5
+        case sc_UpArrow:
+        case sc_DownArrow:
+        case sc_PgUp:
+        case sc_PgDn:
+        case sc_Insert:
+            lastkey = key_None;
+            break;
+        }
+
+//      if (GameEscaped==true)
+//         PauseLoop ();
+
+        if (lastkey)
+        {
+            len = strlen (s);
+            USL_MeasureString (xx, &w, &h, CurrentFont);
+
+            if
+            (
+                isprint(lastkey)
+                && (len < MaxString - 1)
+                && ((!maxchars) || (len < maxchars))
+                && ((!maxwidth) || ((w+2) < (maxwidth-cursorwidth-2)))
+            )
+            {
+                int ls;
+                int rs;
+
+                for (i = len + 1; i > cursor; i--)
+                    s[i] = s[i - 1];
+                s[cursor]   = lastkey;
+                xx[cursor++] = '*';
+                redraw = true;
+
+                ls = Keyboard[sc_LShift];
+                rs = Keyboard[sc_RShift];
+                memset ((void*)Keyboard, 0, 127*sizeof(int));       // Clear printable keys
+                Keyboard[sc_LShift] = ls;
+                Keyboard[sc_RShift] = rs;
+                MN_PlayMenuSnd (SD_MOVECURSORSND);
+            }
+        }
+
+//      if (GameEscaped==true)
+//         PauseLoop ();
+
+        if (redraw)
+        {
+            if (color)
+                VWB_Bar (x, y, BKw, BKh, color);
+            else
+                EraseMenuBufRegion (x, y, BKw, BKh);
+
+            strcpy (olds, s);
+
+            px = x;
+            py = y;
+            if (color)
+                USL_DrawString (xx);
+            else
+                DrawMenuBufPropString (px, py, xx);
+            px = x;
+            py = y;
+
+            redraw = false;
+        }
+
+        if (cursormoved)
+        {
+            cursorvis = false;
+            lasttime = GetTicCount() - VBLCOUNTER;
+
+            cursormoved = false;
+        }
+        if (GetTicCount() - lasttime > VBLCOUNTER / 2)
+        {
+            lasttime = GetTicCount();
+
+            cursorvis ^= true;
+        }
+        if (cursorvis)
+            USL_XORICursor (x, y, xx, cursor, color);
+
+        if (color)
+            VW_UpdateScreen ();
+        else
+            RefreshMenuBuf (0);
+    }
+
+    if (cursorvis)
+        USL_XORICursor (x, y, xx, cursor, color);
+
+    if (!result)
+    {
+        px = x;
+        py = y;
+        if (color)
+            USL_DrawString (xx);
+        else
+            DrawMenuBufPropString (px, py, xx);
+    }
+
+//   if (GameEscaped==true)
+//      PauseLoop ();
+
+    if (color)
+        VW_UpdateScreen ();
+    else
+        RefreshMenuBuf (0);
+
+    IN_ClearKeyboardQueue ();
+    return (result);
+}
+
+
+
+//******************************************************************************
+//******************************************************************************
+//
+// WINDOWING ROUTINES
+//
+//******************************************************************************
+//******************************************************************************
+
+
+//******************************************************************************
+//
+// US_ClearWindow() - Clears the current window to white and homes the
+//    cursor
+//
+//******************************************************************************
+
+void US_ClearWindow (void)
+{
+    VWB_Bar (WindowX, WindowY, WindowW, WindowH, 13);
+    PrintX = WindowX;
+    PrintY = WindowY;
+}
+
+
+
+
+//******************************************************************************
+//
+// US_DrawWindow() - Draws a frame and sets the current window parms
+//
+//******************************************************************************
+
+void US_DrawWindow (int x, int y, int w, int h)
+{
+    int  i,
+         sx,
+         sy,
+         sw,
+         sh;
+    byte * shape;
+
+    pic_t *Win1;
+    pic_t *Win2;
+    pic_t *Win3;
+    pic_t *Win4;
+    pic_t *Win5;
+    pic_t *Win6;
+    pic_t *Win7;
+    pic_t *Win8;
+    pic_t *Win9;
+
+    // Cache in windowing shapes
+    shape = W_CacheLumpNum (W_GetNumForName ("window1"), PU_CACHE, Cvt_pic_t, 1);
+    Win1 = (pic_t *) shape;
+    shape = W_CacheLumpNum (W_GetNumForName ("window2"), PU_CACHE, Cvt_pic_t, 1);
+    Win2 = (pic_t *) shape;
+    shape = W_CacheLumpNum (W_GetNumForName ("window3"), PU_CACHE, Cvt_pic_t, 1);
+    Win3 = (pic_t *) shape;
+    shape = W_CacheLumpNum (W_GetNumForName ("window4"), PU_CACHE, Cvt_pic_t, 1);
+    Win4 = (pic_t *) shape;
+    shape = W_CacheLumpNum (W_GetNumForName ("window5"), PU_CACHE, Cvt_pic_t, 1);
+    Win5 = (pic_t *) shape;
+    shape = W_CacheLumpNum (W_GetNumForName ("window6"), PU_CACHE, Cvt_pic_t, 1);
+    Win6 = (pic_t *) shape;
+    shape = W_CacheLumpNum (W_GetNumForName ("window7"), PU_CACHE, Cvt_pic_t, 1);
+    Win7 = (pic_t *) shape;
+    shape = W_CacheLumpNum (W_GetNumForName ("window8"), PU_CACHE, Cvt_pic_t, 1);
+    Win8 = (pic_t *) shape;
+    shape = W_CacheLumpNum (W_GetNumForName ("window9"), PU_CACHE, Cvt_pic_t, 1);
+    Win9 = (pic_t *) shape;
+
+    WindowX = x * 8;
+    WindowY = y * 8;
+    WindowW = w * 8;
+    WindowH = h * 8;
+
+    PrintX = WindowX;
+    PrintY = WindowY;
+
+    sx = (x - 1) * 8;
+    sy = (y - 1) * 8;
+    sw = (w + 1) * 8;
+    sh = (h + 1) * 8;
+
+    US_ClearWindow ();
+
+
+    VWB_DrawPic (sx, sy, Win1);
+
+    VWB_DrawPic (sx, sy + sh, Win7);
+
+    for (i = sx + 8; i <= sx + sw - 8; i += 8)
+    {
+        VWB_DrawPic (i, sy, Win2);
+        VWB_DrawPic (i, sy + sh, Win8);
+    }
+
+    VWB_DrawPic (i, sy, Win3);
+    VWB_DrawPic (i, sy + sh, Win9);
+
+    for (i = sy + 8; i <= sy + sh - 8; i += 8)
+    {
+        VWB_DrawPic (sx, i, Win4);
+        VWB_DrawPic (sx + sw, i, Win6);
+    }
+}
+
+
+
+//******************************************************************************
+//
+// US_CenterWindow() - Generates a window of a given width & height in the
+//    middle of the screen
+//
+//******************************************************************************
+
+void US_CenterWindow (int w, int h)
+{
+    //HDG US_DrawWindow (((MaxX / 8) - w) / 2,  ((MaxY / 8) - h) / 2, w, h);
+    US_DrawWindow (((iGLOBAL_SCREENWIDTH / 8) - w) / 2,((iGLOBAL_SCREENHEIGHT / 8) - h) / 2, w, h);
+}
+
+
+
+//==============================================================================
+//
+// Intensity Font stuff
+//
+// TEXT FORMATTING COMMANDS - (Use EGA colors ONLY!)
+// -------------------------------------------------
+// /<hex digit> - Change the following word to <hex digit> color
+// `            - Highlights the following word with lighter color of fontcolor
+// /N<hex digit> - Change the fontcolor to a certain color
+//
+//==============================================================================
+
+//******************************************************************************
+//
+// GetIntensityColor ()
+//
+//******************************************************************************
+
+byte GetIntensityColor (byte pix)
+{
+    if ((fontcolor<0) || (fontcolor>255))
+        Error("Intensity Color out of range\n");
+    return ((byte) intensitytable[(pix<<8)+fontcolor]);
+}
+
+
+//******************************************************************************
+//
+// DrawIntensityChar ()
+//
+// Draws an intensity character at px, py
+//
+//******************************************************************************
+
+void DrawIntensityChar  ( char ch )
+{
+
+    byte  pix;
+    int   px1,py1;
+    int   width,w1;
+    int   height,h1;
+    int   ht;
+    byte  *source,*src1;
+    byte  *dest;
+    byte  *origdest,*orgdst1;
+    int   mask;
+
+    px1 = px;
+    py1 = py;
+
+    ht = IFont->height;
+
+    origdest = ( byte * )( bufferofs + ylookup[ py ] + px );
+
+    dest = origdest;
+
+    ch -= 31;
+    width = IFont->width[ (unsigned char)ch ];
+    source = ( ( byte * )IFont ) + IFont->charofs[ (unsigned char)ch ];
+
+    mask = 1 << ( px & 3 );
+
+    if ((iGLOBAL_SCREENWIDTH <= 320)||(StretchScreen == true)) {
+        while( width-- )
+        {
+            VGAMAPMASK( mask );
+
+            height = ht;
+            while( height-- )
+            {
+                pix = *source;
+                if ( pix != 0xFE )
+                {
+                    *dest = GetIntensityColor( pix );
+                }
+
+                source++;
+                dest += linewidth;
+            }
+
+            px++;
+            origdest++;
+            dest = origdest;
+        }
+    } else { //strech letter in x any direction
+        w1 = width;
+        h1 = ht;
+        orgdst1 = origdest;
+        src1 = source;
+        while( width-- )
+        {
+            VGAMAPMASK( mask );
+
+            height = ht;
+            while( height-- )
+            {
+                pix = *source;
+                if ( pix != 0xFE )
+                {
+                    *dest = GetIntensityColor( pix );
+                    *(dest+iGLOBAL_SCREENWIDTH) = GetIntensityColor( pix );
+
+                    *(dest+1) = GetIntensityColor( pix );
+                    *(dest+1+iGLOBAL_SCREENWIDTH) = GetIntensityColor( pix );
+                }
+
+                source++;
+                dest += linewidth*2;
+            }
+
+            px++;
+            px++;
+            origdest++;
+            origdest++;
+            dest = origdest;
+        }
+
+    }
+
+}
+
+
+//******************************************************************************
+//
+// GetColor ()
+//
+//******************************************************************************
+
+int GetColor (int num)
+{
+    int returnval;
+
+    if ((num >= '0') && (num <= '9'))
+        returnval = egacolor[num - '0'];
+    else if ((num >= 'A') && (num <= 'F'))
+        returnval = egacolor[((num - 'A') + 10)];
+
+    return (returnval);
+}
+
+//******************************************************************************
+//
+// DrawIString ()
+//
+//******************************************************************************
+
+static int oldfontcolor = 0;
+static boolean highlight = false;
+
+void DrawIString (unsigned short int x, unsigned short int y, const char *string, int flags)
+{
+    char ch;
+    char temp;
+
+    px = x;
+    py = y;
+
+    while ((ch = *string++) != 0)
+    {
+        if ( !PERMANENT_MSG( flags ) )
+        {
+            // Highlighting is done only for 1 word - if we get a "space"
+            //  and highlight is on ...., reset variables.
+            //
+            if ((ch == ' ') && (highlight == true))
+            {
+                highlight = false;
+                fontcolor = oldfontcolor;
+                DrawIntensityChar (ch);
+            }
+            else
+                // '\\' is color change to a specific EGA color (ie. egacolor)
+                //
+                if (ch == '\\')
+                {
+                    temp = *string++;
+                    temp = toupper (temp);
+
+                    // Force fontcolor to a specific color egacolor[ RED ];
+                    if (temp == 'N')
+                    {
+                        temp         = *string++;
+                        fontcolor    = GetColor (temp);
+                        oldfontcolor = fontcolor;
+                    }
+                    //bna added
+                    else if (temp == 'X')
+                    {
+                        temp         = *string;
+                        fontcolor    = egacolor[ RED ];
+                        oldfontcolor = fontcolor;
+                    }
+                    else if (temp == 'Y')
+                    {
+                        temp         = *string;
+                        fontcolor    = egacolor[ YELLOW ];
+                        oldfontcolor = fontcolor;
+                    }
+                    else if (temp == 'Z')
+                    {
+                        temp         = *string;
+                        fontcolor    = egacolor[ GREEN ];
+                        oldfontcolor = fontcolor;
+                    }
+                    //bna added end
+                    // Restore fontcolor to a previous color
+                    else if (temp == 'O')
+                    {
+                        fontcolor    = oldfontcolor;
+                    }
+                    else
+                    {
+                        oldfontcolor = fontcolor;           // save off old font color
+                        highlight    = true;                // set highlight
+                        fontcolor    = GetColor (temp);
+                    }
+                }
+                else
+                    // '`' is highlight the current fontcolor
+                    //
+                    if (ch == '`')
+                    {
+                        oldfontcolor = fontcolor;        // save off old font color
+                        highlight    = true;             // set highlight
+                        if (fontcolor < 8)               // only highlight the
+                            fontcolor    = fontcolor-10;  //  lower colors
+                    }
+                    else
+                        DrawIntensityChar (ch);
+        }
+        else
+            DrawIntensityChar (ch);
+    }
+
+    if (highlight == true)
+    {
+        highlight = false;
+        fontcolor = oldfontcolor;
+    }
+}
+
+
+//******************************************************************************
+//
+// DrawIntensityString ()
+//
+//******************************************************************************
+
+void DrawIntensityString (unsigned short int x, unsigned short int y, const char *string, int color)
+{
+    char ch;
+
+    px = x;
+    py = y;
+
+    fontcolor=color;
+
+    while ((ch = *string++) != 0)
+    {
+        DrawIntensityChar (ch);
+    }
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+static unsigned short disp_offset = 160 * 24;
+
+void DrawRottText
+(
+    int x,
+    int y,
+    int ch,
+    int foreground,
+    int background
+)
+
+{
+    char *vid;
+
+    vid  = ( char * )( 0xb0000 );
+    vid += y * 160;
+    vid += x * 2;
+
+    if ( ch != NONE )
+    {
+        *vid = ch;
+    }
+    vid++;
+    *vid = ( ( background & 0x0f ) << 4 ) | ( foreground & 0x0f );
+}
+
+void TextBox
+(
+    int  x1,
+    int  y1,
+    int  x2,
+    int  y2,
+    int ch,
+    int  foreground,
+    int  background
+)
+
+{
+    int x;
+    int y;
+
+    for( x = x1; x <= x2; x++ )
+    {
+        for( y = y1; y <= y2; y++ )
+        {
+            DrawRottText( x, y, ch, foreground, background );
+        }
+    }
+}
+
+void TextFrame
+(
+    int x1,
+    int y1,
+    int x2,
+    int y2,
+    int type,
+    int foreground,
+    int background
+)
+
+{
+    int x;
+    int y;
+
+    if ( type == 0 )
+    {
+        for( x = x1 + 1; x < x2; x++ )
+        {
+            DrawRottText( x, y1, type, foreground, background );
+            DrawRottText( x, y2, type, foreground, background );
+        }
+        for( y = y1 + 1; y < y2; y++ )
+        {
+            DrawRottText( x1, y, type, foreground, background );
+            DrawRottText( x2, y, type, foreground, background );
+        }
+    }
+    if ( type == SINGLE_FRAME )
+    {
+        DrawRottText( x1, y1, '�', foreground, background );
+        DrawRottText( x2, y1, '�', foreground, background );
+        DrawRottText( x1, y2, '�', foreground, background );
+        DrawRottText( x2, y2, '�', foreground, background );
+        for( x = x1 + 1; x < x2; x++ )
+        {
+            DrawRottText( x, y1, '�', foreground, background );
+            DrawRottText( x, y2, '�', foreground, background );
+        }
+        for( y = y1 + 1; y < y2; y++ )
+        {
+            DrawRottText( x1, y, '�', foreground, background );
+            DrawRottText( x2, y, '�', foreground, background );
+        }
+    }
+    if ( type == DOUBLE_FRAME )
+    {
+        DrawRottText( x1, y1, '�', foreground, background );
+        DrawRottText( x2, y1, '�', foreground, background );
+        DrawRottText( x1, y2, '�', foreground, background );
+        DrawRottText( x2, y2, '�', foreground, background );
+        for( x = x1 + 1; x < x2; x++ )
+        {
+            DrawRottText( x, y1, '�', foreground, background );
+            DrawRottText( x, y2, '�', foreground, background );
+        }
+        for( y = y1 + 1; y < y2; y++ )
+        {
+            DrawRottText( x1, y, '�', foreground, background );
+            DrawRottText( x2, y, '�', foreground, background );
+        }
+    }
+}
+
+void mysetxy
+(
+    int x,
+    int y
+)
+
+{
+    disp_offset = ( x * 2 ) + ( y * 160 );
+}
+
+void myputch
+(
+    char ch
+)
+
+{
+    int j;
+    char *disp_start = (char *)( 0xb0000 );
+
+    if ( disp_offset >= 160 * 24 )
+    {
+        for ( j = 160; j < 160 * 24; j += 2 )
+        {
+            *( disp_start + j - 160 ) = *( disp_start + j );
+        }
+
+        disp_offset = 160 * 23;
+
+        for ( j = disp_offset; j < ( 160 * 24 ); j += 2 )
+        {
+            *( disp_start + j ) = ' ';
+        }
+    }
+
+    if ( ch >= 32 )
+    {
+        *( disp_start + disp_offset ) = ch;
+        disp_offset = disp_offset + 2;
+    }
+
+    if ( ch == '\r' )
+    {
+        disp_offset = disp_offset / 160;
+        disp_offset = disp_offset * 160;
+    }
+
+    if ( ch == '\n' )
+    {
+        disp_offset = disp_offset + 160;
+        if ( disp_offset < 160 * 24 )
+        {
+            for ( j = disp_offset; j < ( ( ( disp_offset / 160 ) + 1 ) *
+                                         160 ); j += 2 )
+            {
+                *( disp_start + j ) = ' ';
+            }
+        }
+    }
+}
+
+int printstring
+(
+    char *string
+)
+
+{
+    int count;
+    char *ptr;
+
+    ptr = string;
+    count = 0;
+
+    while ( *ptr )
+    {
+        myputch( *ptr );
+        count++;
+        ptr++;
+    }
+
+    return( count );
+}
+
+
+int printnum
+(
+    int number
+)
+
+{
+    char string[ 100 ];
+    int  count;
+
+    itoa( number, string, 10 );
+    count = printstring( string );
+
+    return( count );
+}
+
+int printunsigned
+(
+    unsigned long number,
+    int radix
+)
+
+{
+    char string[ 100 ];
+    int  count;
+
+    ultoa( number, string, radix );
+    count = printstring( string );
+
+    return( count );
+}
+
+int myprintf
+(
+    char *fmt,
+    ...
+)
+
+{
+    va_list argptr;
+    int     count;
+    char    *ptr;
+    if (MONOPRESENT==false)
+    {
+        Debug("%s", fmt);
+        return 0;
+    }
+    va_start( argptr, fmt );
+    ptr = fmt;
+    count = 0;
+
+    while( *ptr != 0 )
+    {
+        if ( *ptr == '%' )
+        {
+            ptr++;
+            switch( *ptr )
+            {
+            case 0 :
+                return( EOF );
+                break;
+            case 'l' :
+                count += printnum( va_arg( argptr, int ) );
+                ptr++;
+                break;
+            case 'd' :
+                count += printnum( va_arg( argptr, int ) );
+                break;
+            case 's' :
+                count += printstring( va_arg( argptr, char * ) );
+                break;
+            case 'u' :
+                count += printunsigned( va_arg( argptr, int ), 10 );
+                break;
+            case 'x' :
+            case 'X' :
+                count += printunsigned( va_arg( argptr, int ), 16 );
+                break;
+            }
+            ptr++;
+        }
+        else
+        {
+            myputch( *ptr );
+            count++;
+            ptr++;
+        }
+    }
+
+    va_end( argptr );
+
+    return( count );
+}
--- /dev/null
+++ b/rott/rt_str.h
@@ -1,0 +1,125 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+//***************************************************************************
+//
+// Public header for RT_STR.C.
+//
+//***************************************************************************
+
+#ifndef _rt_str_public
+#define _rt_str_public
+
+#include "lumpy.h"
+
+
+//***************************************************************************
+//
+// GLOBALS
+//
+//***************************************************************************
+
+extern int fontcolor;
+
+
+//***************************************************************************
+//
+// TYPEDEFS
+//
+//***************************************************************************
+
+typedef  struct
+{
+    int   x,y;
+} Point;
+
+typedef  struct
+{
+    int   x, y,
+          w, h,
+          px, py;
+} WindowRec;            // Record used to save & restore screen windows
+
+typedef  struct
+{
+    Point ul,lr;
+} Rect;
+
+
+//***************************************************************************
+//
+// PROTOTYPES
+//
+//***************************************************************************
+
+//
+// String rtns
+//
+
+void VW_DrawClippedString (int x, int y, const char *string);
+void US_ClippedPrint (int x, int y, const char *s);
+
+void VWB_DrawPropString  (const char *string);
+void VW_MeasurePropString (const char *string, int *width, int *height);
+
+void US_MeasureStr (int *width, int *height, const char * s, ...) __attribute__((format(printf,3,4)));
+
+void VW_DrawPropString (const char *string);
+
+void US_SetPrintRoutines (void (*measure)(const char *, int *, int *, font_t *),
+                          void (*print)(const char *));
+void US_Print (const char *s);
+void US_BufPrint (const char *s);
+void US_PrintUnsigned (unsigned long int n);
+void US_PrintSigned (long int n);
+void USL_PrintInCenter (const char *s, Rect r);
+void US_PrintCentered (const char *s);
+void US_CPrintLine (const char *s);
+void US_CPrint (const char *s);
+
+
+//
+// Input rtns
+//
+
+boolean US_LineInput (int x, int y, char *buf, const char *def, boolean escok,
+                      int maxchars, int maxwidth, int color);
+boolean US_lineinput (int x, int y, char *buf, const char *def, boolean escok,
+                      int maxchars, int maxwidth, int color);
+int CalibrateJoystick(void);
+
+//
+// Window rtns
+//
+
+void US_DrawWindow (int x, int y, int w, int h);
+void US_CenterWindow (int w, int h);
+
+//
+// Intensity font rtns
+//
+
+void DrawIString (unsigned short int x, unsigned short int y, const char *string, int flags);
+void DrawIntensityString (unsigned short int x, unsigned short int y, const char *string, int color);
+void VW_MeasureIntensityPropString (const char *string, int *width, int *height);
+byte GetIntensityColor (byte pix);
+
+#include "myprint.h"
+
+#endif
--- /dev/null
+++ b/rott/rt_swift.c
@@ -1,0 +1,429 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+//****************************************************************************
+//
+// RT_SWIFT.C
+//
+// SWIFT services module - for CYBERMAN use in ROTT.
+//
+//****************************************************************************
+
+
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef DOS
+#include <dos.h>
+#endif
+
+#include "rt_def.h"
+#include "rt_swift.h"
+#include "_rt_swft.h"
+//MED
+#include "memcheck.h"
+
+
+#ifdef DOS
+
+//****************************************************************************
+//
+// SWIFT_Initialize ()
+//
+// Test for presence of SWIFT extensions and SWIFT device.
+// Returns 1 (TRUE) if SWIFT features are available, 0 otherwise.
+// Remember to call SWIFT_Terminate() if SWIFT_Initialize succeeds!
+//
+//****************************************************************************
+
+int SWIFT_Initialize (void)
+{
+    SWIFT_StaticData sdBuf;
+    int fSwift = 0;
+
+    if (fActive)                     // SWIFT extensions already active
+    {
+#ifdef DEGUB
+        SoftError( "SWIFT_Initialize: Already active.\n");
+        SoftError( "SWIFT_Initialize: returns TRUE\n");
+#endif
+        return (1);
+    }
+
+    nAttached = SWIFT_DEV_NONE;
+
+
+    if (_dos_getvect(0x33) == NULL)  // No mouse driver loaded
+    {
+#ifdef DBUG
+        SoftError( "SWIFT_Initialize: No mouse driver loaded.\n");
+        SoftError( "SWIFT_Initialize: returns FALSE\n");
+#endif
+        return (0);
+    }
+
+
+    // Reset the mouse and driver
+    AX (regs) = 0;
+    int386( 0x33, &regs, &regs);
+
+    if (AX (regs) == 0)
+    {   // no mouse
+#ifdef DBUG
+        SoftError( "SWIFT_Initialize: No pointing device attached.\n");
+        SoftError( "SWIFT_Initialize: returns FALSE\n");
+#endif
+        return (0);
+    }
+
+#ifdef DBUG
+    AX (regs) = 36;   // Get Mouse Information
+    BX (regs) = 0xffff;
+    CX (regs) = 0xffff;
+    DX (regs) = 0xffff;
+    int386 (0x33, &regs, &regs);
+    SoftError( "SWIFT_Initialize: driver version %d.%02d\n", regs.h.bh, regs.h.bl);
+    SoftError( "SWIFT_Initialize: %s mouse using IRQ %d\n",
+               (regs.h.ch==1) ? "bus" :
+               (regs.h.ch==2) ? "serial" :
+               (regs.h.ch==3) ? "inport" :
+               (regs.h.ch==4) ? "PS/2" :
+               "unknown", regs.h.cl);
+#endif
+
+
+    // allocate a DOS real-mode buffer
+    pdosmem = allocDOS(DOSMEMSIZE, &segment, &selector);
+    if (!pdosmem)
+    {
+#ifdef DBUG
+        SoftError( "SWIFT_Initialize: DOS Alloc failed!\n");
+        SoftError( "SWIFT_Initialize: returns FALSE\n");
+#endif
+        return (0);
+    }
+
+//
+// SWIFT device supported and attached
+//
+    if (SWIFT_GetStaticDeviceInfo (&sdBuf))
+        fSwift = 1;
+
+
+    if (!fSwift)
+    {   // SWIFT functions not present
+#ifdef DBUG
+        SoftError( "SWIFT_Initialize: no SWIFT support in mouse driver.\n");
+#endif
+    }
+    else if (sdBuf.deviceType == SWIFT_DEV_NONE)
+    {
+#ifdef DBUG
+        SoftError( "SWIFT_Initialize: no SWIFT device connected.\n");
+#endif
+    }
+    else
+    {
+        nAttached = sdBuf.deviceType;
+#ifdef DBUG
+        SoftError( "SWIFT_Initialize: ");
+
+        switch (nAttached)
+        {
+        case SWIFT_DEV_CYBERMAN:
+            SoftError( "CyberMan %d.%02d connected.\n",
+                       sdBuf.majorVersion, sdBuf.minorVersion);
+            break;
+
+        default:
+            SoftError( "Unknown SWIFT device (type %d) connected.\n",
+                       nAttached);
+            break;
+        }
+#endif
+        fActive = 1;
+    }
+
+    if (!fActive)
+    {   // activation of SWIFT module failed for some reason
+        if (pdosmem)
+        {   // if DOS buffer was allocated, free it
+            freeDOS(selector);
+            pdosmem = 0;
+        }
+    }
+
+#ifdef DBUG
+    SoftError( "SWIFT_Initialize: returns %s.\n", (fActive ? "TRUE" : "FALSE"));
+#endif
+    return fActive;
+}
+
+
+
+//****************************************************************************
+//
+// SWIFT_Terminate ()
+//
+// Free resources required for SWIFT support.  If SWIFT_Initialize has
+// not been called, or returned FALSE, this function does nothing.
+// SWIFT_Terminate should always be called at some time after a call to
+// SWIFT_Initialize has returned TRUE.
+//
+//****************************************************************************
+
+void SWIFT_Terminate (void)
+{
+#ifdef DBUG
+    SoftError( "SWIFT_Terminate called.\n");
+#endif
+
+    if (fActive)
+    {
+        // free DOS buffer
+        if (pdosmem)
+        {
+            freeDOS(selector);
+            pdosmem = 0;
+        }
+
+        fActive = 0;
+    }
+}
+
+
+//****************************************************************************
+//
+// SWIFT_GetAttachedDevice ()
+//
+// Returns the device-type code for the attached SWIFT device, if any.
+//
+//****************************************************************************
+
+int SWIFT_GetAttachedDevice (void)
+{
+    return (nAttached);
+}
+
+
+
+//****************************************************************************
+//
+// SWIFT_GetStaticDeviceInfo ()
+//
+// Reads static device data.
+//
+//****************************************************************************
+
+int SWIFT_GetStaticDeviceInfo (SWIFT_StaticData far *psd)
+{
+    memset (&RMI, 0, sizeof (RMI));
+    RMI.ax = 0x53C1;                       // SWIFT: Get Static Device Data
+    RMI.es = segment;                      // DOS buffer real-mode segment
+    RMI.dx = 0;                            //  "    "      "   "   offset
+    MouseInt (&RMI);                       // get data into DOS buffer
+
+    *psd = *(SWIFT_StaticData *)pdosmem;   // then copy into caller's buffer
+    return (RMI.ax == 1);                  // return success
+}
+
+
+
+//****************************************************************************
+//
+// SWIFT_Get3DStatus ()
+//
+// Read the current input state of the device.
+//
+//****************************************************************************
+
+
+void SWIFT_Get3DStatus (SWIFT_3DStatus far *pstat)
+{
+#ifdef DBUG
+    if (!fActive)
+    {
+        SoftError( "SWIFT_Get3DStatus: SWIFT module not active!\n");
+    }
+#endif
+
+    memset (&RMI, 0, sizeof (RMI));
+    RMI.ax = 0x5301;
+    RMI.es = segment;
+    RMI.dx = 0;
+    MouseInt(&RMI);
+    *pstat = *(SWIFT_3DStatus *)pdosmem;
+}
+
+
+
+
+//****************************************************************************
+//
+// SWIFT_TactileFeedback ()
+//
+// Generates tactile feedback to user.
+// d   = duration of tactile burst, in milliseconds.
+// on  = motor on-time per cycle, in milliseconds.
+// off = motor off-time per cycle, in milliseconds.
+//
+//****************************************************************************
+
+void SWIFT_TactileFeedback (int d, int on, int off)
+{
+    // Use DPMI call 300h to issue mouse interrupt
+    memset (&RMI, 0, sizeof(RMI));
+    RMI.ax = 0x5330;                    // SWIFT: Get Position & Buttons
+    RMI.bx = (on / 5) << 8 + (off / 5);
+    RMI.cx = d / 40;
+    MouseInt (&RMI);
+
+#ifdef DBUG
+    SoftError( "SWIFT_TactileFeedback (dur=%d ms, on=%d ms, off=%d ms)\n",
+               d / 40 * 40, on/5*5, off/5*5);
+#endif
+}
+
+
+
+//****************************************************************************
+//
+// SWIFT_GetDynamicDeviceData ()
+//
+// Returns Dynamic Device Data word - see SDD_* above
+//
+//****************************************************************************
+
+unsigned SWIFT_GetDynamicDeviceData (void)
+{
+    memset (&RMI, 0, sizeof(RMI));
+    RMI.ax = 0x53C2;                       // SWIFT: Get Dynamic Device Data
+    MouseInt (&RMI);
+    return ((unsigned)RMI.ax);
+}
+
+
+//****************************************************************************
+//
+// MouseInt ()
+//
+// Generate a call to the mouse driver (interrupt 33h) in real mode,
+// using the DPMI function 'Simulate Real-Mode Interrupt'.
+//
+//****************************************************************************
+
+void MouseInt (struct rminfo *prmi)
+{
+    memset (&sregs, 0, sizeof (sregs));
+    AX (regs) = 0x0300;                    // DPMI: simulate interrupt
+    BX (regs) = MOUSE_INT;
+    CX (regs) = 0;
+    DI (regs) = FP_OFF (prmi);
+    sregs.es = FP_SEG (prmi);
+    int386x( DPMI_INT, &regs, &regs, &sregs );
+}
+
+
+//****************************************************************************
+//
+// freeDOS ()
+//
+// Release real-mode DOS memory block via DPMI
+//
+//****************************************************************************
+
+void freeDOS (short sel)
+{
+    AX(regs) = 0x0101;      // DPMI free DOS memory
+    DX(regs) = sel;
+
+    int386( DPMI_INT, &regs, &regs);
+}
+
+
+//****************************************************************************
+//
+// allocDOS ()
+//
+// Allocate a real-mode DOS memory block via DPMI
+//
+//****************************************************************************
+
+void far *allocDOS (unsigned nbytes, short *pseg, short *psel)
+{
+    unsigned npara = (nbytes + 15) / 16;
+    void far *pprot;
+    pprot = NULL;
+    *pseg = 0;        // assume will fail
+    *psel = 0;
+
+    // DPMI call 100h allocates DOS memory
+    segread (&sregs);
+    AX (regs) = 0x0100;        // DPMI: Allocate DOS Memory
+    BX (regs) = npara;         // number of paragraphs to alloc
+    int386( DPMI_INT, &regs, &regs);
+
+    if (regs.w.cflag == 0)
+    {
+        *pseg = AX (regs);      // the real-mode segment
+        *psel = DX (regs);      // equivalent protected-mode selector
+        // pprot is the protected mode address of the same allocated block.
+        // The Rational extender maps the 1 MB physical DOS memory into
+        // the bottom of our virtual address space.
+        pprot = (void far *) ((unsigned)*pseg << 4);
+    }
+    return pprot;
+}
+
+#else
+
+/* This isn't of much use in Linux. */
+
+int SWIFT_Initialize (void)
+{
+    STUB_FUNCTION;
+
+    return 0;
+}
+
+void SWIFT_Terminate (void)
+{
+    STUB_FUNCTION;
+}
+
+void SWIFT_Get3DStatus (SWIFT_3DStatus far *pstat)
+{
+    STUB_FUNCTION;
+}
+
+void SWIFT_TactileFeedback (int d, int on, int off)
+{
+    STUB_FUNCTION;
+}
+
+unsigned SWIFT_GetDynamicDeviceData (void)
+{
+    STUB_FUNCTION;
+
+    return 0;
+}
+
+#endif
--- /dev/null
+++ b/rott/rt_swift.h
@@ -1,0 +1,81 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+#ifndef _rt_swift_public
+#define _rt_swift_public
+
+//***************************************************************************
+//
+// Public header for RT_SWIFT.C.
+//
+//***************************************************************************
+
+#include "rt_playr.h"
+
+//***************************************************************************
+//
+// PROTOTYPES
+//
+//***************************************************************************
+
+int SWIFT_Initialize (void);
+//
+// Test for presence of SWIFT extensions and SWIFT device
+// Returns 1 (TRUE) if SWIFT features are available, 0 otherwise.
+// Remember to call SWIFT_Terminate() if SWIFT_Initialize succeeds!
+//
+
+void SWIFT_Terminate (void);
+//
+// Free resources required for SWIFT support.  If SWIFT_Initialize has
+// not been called, or returned FALSE, this function does nothing.
+// SWIFT_Terminate should always be called at some time after a call to
+// SWIFT_Initialize has returned TRUE.
+//
+
+int SWIFT_GetAttachedDevice (void);
+//
+// Returns the device-type code for the attached SWIFT device, if any.
+//
+
+int SWIFT_GetStaticDeviceInfo (SWIFT_StaticData far *psd);
+//
+// Reads static device data.
+//
+
+void SWIFT_Get3DStatus (SWIFT_3DStatus far *pstat);
+//
+// Read the current input state of the device.
+//
+
+void SWIFT_TactileFeedback (int d, int on, int off);
+//
+// Generates tactile feedback to user.
+// d   = duration of tactile burst, in milliseconds.
+// on  = motor on-time per cycle, in milliseconds.
+// off = motor off-time per cycle, in milliseconds.
+//
+
+unsigned SWIFT_GetDynamicDeviceData (void);
+//
+// Returns Dynamic Device Data word - see SDD_* above
+//
+
+
+#endif
--- /dev/null
+++ b/rott/rt_table.h
@@ -1,0 +1,1331 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+#ifndef _rt_table_public
+#define _rt_table_public
+
+#include "states.h"
+
+statetype * statetable[MAXSTATES]=
+{
+    &s_lowgrdstand	,
+    &s_lowgrdpath4 	,
+    &s_lowgrdpath3 	,
+    &s_lowgrdpath2 	,
+    &s_lowgrdpath1 	,
+    &s_lowgrdcollide,
+    &s_lowgrdcollide2,
+    &s_lowgrdshoot4 	,
+    &s_lowgrdshoot3 	,
+    &s_lowgrdshoot2 	,
+    &s_lowgrdshoot1 	,
+    &s_lowgrdchase4 	,
+    &s_lowgrdchase3 	,
+    &s_lowgrdchase2 	,
+    &s_lowgrdchase1 	,
+    &s_lowgrddead		,
+    &s_lowgrddie4		,
+    &s_lowgrddie3		,
+    &s_lowgrddie2		,
+    &s_lowgrddie1		,
+    &s_lowgrdcrushed2		,
+    &s_lowgrdcrushed1		,
+    &s_sneakydown,
+    &s_sneakyrise4,
+    &s_sneakyrise3,
+    &s_sneakyrise2,
+    &s_sneakyrise1,
+    &s_highgrdstand	,
+    &s_highgrdpath4 	,
+    &s_highgrdpath3 	,
+    &s_highgrdpath2 	,
+    &s_highgrdpath1 	,
+    &s_highgrdcollide,
+    &s_highgrdcollide2,
+    &s_highgrdshoot4,
+    &s_highgrdshoot3,
+    &s_highgrdshoot2 	,
+    &s_highgrdshoot1 	,
+    &s_highgrdchase4 	,
+    &s_highgrdchase3 	,
+    &s_highgrdchase2 	,
+    &s_highgrdchase1 	,
+    &s_highgrddead		,
+    &s_highgrddie5		,
+    &s_highgrddie4		,
+    &s_highgrddie3		,
+    &s_highgrddie2		,
+    &s_highgrddie1		,
+    &s_highgrdcrushed2		,
+    &s_highgrdcrushed1		,
+    &s_strikestand	,
+    &s_strikepath4 	,
+    &s_strikepath3 	,
+    &s_strikepath2 	,
+    &s_strikepath1 	,
+    &s_strikecollide,
+    &s_strikecollide2,
+    &s_strikeshoot4 	,
+    &s_strikeshoot3 	,
+    &s_strikeshoot2 	,
+    &s_strikeshoot1 	,
+    &s_strikewait,
+    &s_strikerollright6,
+    &s_strikerollright5,
+    &s_strikerollright4,
+    &s_strikerollright3,
+    &s_strikerollright2,
+    &s_strikerollright1,
+    &s_strikerollleft6,
+    &s_strikerollleft5,
+    &s_strikerollleft4,
+    &s_strikerollleft3,
+    &s_strikerollleft2,
+    &s_strikerollleft1,
+    &s_strikechase4 	,
+    &s_strikechase3 	,
+    &s_strikechase2 	,
+    &s_strikechase1 	,
+    &s_strikedead3		,
+    &s_strikedead2		,
+    &s_strikedead		,
+    &s_strikedie4		,
+    &s_strikedie3		,
+    &s_strikedie2		,
+    &s_strikedie1		,
+    &s_strikecrushed2		,
+    &s_strikecrushed1		,
+    &s_blitzstand,
+    &s_blitzpath4,
+    &s_blitzpath3,
+    &s_blitzpath2,
+    &s_blitzpath1,
+    &s_blitzcollide,
+    &s_blitzcollide2,
+    &s_blitzshoot4,
+    &s_blitzshoot3,
+    &s_blitzshoot2,
+    &s_blitzshoot1,
+    &s_blitzrise4,
+    &s_blitzrise3,
+    &s_blitzrise2,
+    &s_blitzrise1,
+    &s_blitzuse,
+    &s_blitzsteal2,
+    &s_blitzsteal1,
+    &s_blitzchase4 	,
+    &s_blitzchase3 	,
+    &s_blitzchase2 	,
+    &s_blitzchase1 	,
+    &s_blitzdead2		,
+    &s_blitzdead		,
+    &s_blitzdie4		,
+    &s_blitzdie3		,
+    &s_blitzdie2		,
+    &s_blitzdie1		,
+    &s_blitzcrushed2		,
+    &s_blitzcrushed1		,
+    &s_blitzplead1,
+    &s_blitzplead2,
+    &s_blitzplead3,
+    &s_blitzplead4,
+    &s_blitzplead5,
+    &s_blitzplead6,
+    &s_blitzplead7,
+    &s_blitzplead8,
+    &s_blitzplead9,
+    &s_blitzplead10,
+    &s_blitzplead11,
+    &s_blitzaplead5,
+    &s_blitzaplead4,
+    &s_blitzfakedead,
+    &s_blitzfakedie3,
+    &s_blitzfakedie2,
+    &s_blitzfakedie1,
+    &s_blitzstruggledie1,
+    &s_blitzstruggledead,
+    &s_enforcerstand,
+    &s_enforcerpath4 	,
+    &s_enforcerpath3 	,
+    &s_enforcerpath2 	,
+    &s_enforcerpath1 	,
+    &s_enforcerchase4 	,
+    &s_enforcerchase3 	,
+    &s_enforcerchase2 	,
+    &s_enforcerchase1 	,
+    &s_enforcercollide,
+    &s_enforcercollide2,
+    &s_enforcershoot4,
+    &s_enforcershoot3,
+    &s_enforcershoot2,
+    &s_enforcershoot1,
+    &s_enforcerthrow8,
+    &s_enforcerthrow7,
+    &s_enforcerthrow6,
+    &s_enforcerthrow5,
+    &s_enforcerthrow4,
+    &s_enforcerthrow3,
+    &s_enforcerthrow2,
+    &s_enforcerthrow1,
+    &s_grenade10,
+    &s_grenade9,
+    &s_grenade8,
+    &s_grenade7,
+    &s_grenade6,
+    &s_grenade5,
+    &s_grenade4,
+    &s_grenade3,
+    &s_grenade2,
+    &s_grenade1,
+    &s_grenade_fall6,
+    &s_grenade_fall5,
+    &s_grenade_fall4,
+    &s_grenade_fall3,
+    &s_grenade_fall2,
+    &s_grenade_fall1,
+    &s_grenadehit3,
+    &s_grenadehit2,
+    &s_grenadehit1,
+    &s_enforcerdead		,
+    &s_enforcerdie4		,
+    &s_enforcerdie3		,
+    &s_enforcerdie2		,
+    &s_enforcerdie1		,
+    &s_enforcercrushed2		,
+    &s_enforcercrushed1		,
+
+
+    &s_robogrdstand	,
+    &s_robogrdpath1 	,
+    &s_robogrdshoot1 	,
+    &s_robogrdshuriken4 	,
+    &s_robogrdshuriken3 	,
+    &s_robogrdshuriken2 	,
+    &s_robogrdshuriken1 	,
+    &s_shurikenhit3,
+    &s_shurikenhit2,
+    &s_shurikenhit1,
+    &s_robogrdcollide,
+    &s_robogrdcollide2,
+    &s_robogrddead		,
+    &s_robogrddie9	,
+    &s_robogrddie8	,
+    &s_robogrddie7	,
+    &s_robogrddie6	,
+    &s_robogrddie5	,
+    &s_robogrddie4	,
+    &s_robogrddie3	,
+    &s_robogrddie2	,
+    &s_robogrddie1	,
+    &s_roboalign,
+    &s_roborealign,
+    &s_robowait,
+
+    &s_altexplosion10,
+    &s_altexplosion9,
+    &s_altexplosion8,
+    &s_altexplosion7,
+    &s_altexplosion6,
+    &s_altexplosion5,
+    &s_altexplosion4,
+    &s_altexplosion3,
+    &s_altexplosion2,
+    &s_altexplosion1,
+
+
+    &s_explosion20,
+    &s_explosion19,
+    &s_explosion18,
+    &s_explosion17,
+    &s_explosion16,
+    &s_explosion15,
+    &s_explosion14,
+    &s_explosion13,
+    &s_explosion12,
+    &s_explosion11,
+    &s_explosion10,
+    &s_explosion9,
+    &s_explosion8,
+    &s_explosion7,
+    &s_explosion6,
+    &s_explosion5,
+    &s_explosion4,
+    &s_explosion3,
+    &s_explosion2,
+    &s_explosion1,
+    &s_grexplosion20,
+    &s_grexplosion19,
+    &s_grexplosion18,
+    &s_grexplosion17,
+    &s_grexplosion16,
+    &s_grexplosion15,
+    &s_grexplosion14,
+    &s_grexplosion13,
+    &s_grexplosion12,
+    &s_grexplosion11,
+    &s_grexplosion10,
+    &s_grexplosion9,
+    &s_grexplosion8,
+    &s_grexplosion7,
+    &s_grexplosion6,
+    &s_grexplosion5,
+    &s_grexplosion4,
+    &s_grexplosion3,
+    &s_grexplosion2,
+    &s_grexplosion1,
+
+    &s_staticexplosion25,
+    &s_staticexplosion24,
+    &s_staticexplosion23,
+    &s_staticexplosion22,
+    &s_staticexplosion21,
+    &s_staticexplosion20,
+    &s_staticexplosion19,
+    &s_staticexplosion18,
+    &s_staticexplosion17,
+    &s_staticexplosion16,
+    &s_staticexplosion15,
+    &s_staticexplosion14,
+    &s_staticexplosion13,
+    &s_staticexplosion12,
+    &s_staticexplosion11,
+    &s_staticexplosion10,
+    &s_staticexplosion9,
+    &s_staticexplosion8,
+    &s_staticexplosion7,
+    &s_staticexplosion6,
+    &s_staticexplosion5,
+    &s_staticexplosion4,
+    &s_staticexplosion3,
+    &s_staticexplosion2,
+    &s_staticexplosion1,
+
+
+    &s_upblade16,
+    &s_upblade15,
+    &s_upblade14,
+    &s_upblade13,
+    &s_upblade12,
+    &s_upblade11,
+    &s_upblade10,
+    &s_upblade9,
+    &s_upblade8,
+    &s_upblade7,
+    &s_upblade6,
+    &s_upblade5,
+    &s_upblade4,
+    &s_upblade3,
+    &s_upblade2,
+    &s_upblade1,
+
+
+    &s_firejetup23,
+    &s_firejetup22,
+    &s_firejetup21,
+    &s_firejetup20,
+    &s_firejetup19,
+    &s_firejetup18,
+    &s_firejetup17,
+    &s_firejetup16,
+    &s_firejetup15,
+    &s_firejetup14,
+    &s_firejetup13,
+    &s_firejetup12,
+    &s_firejetup11,
+    &s_firejetup10,
+    &s_firejetup9,
+    &s_firejetup8,
+    &s_firejetup7,
+    &s_firejetup6,
+    &s_firejetup5,
+    &s_firejetup4,
+    &s_firejetup3,
+    &s_firejetup2,
+    &s_firejetup1,
+
+
+    &s_columndownup6,
+    &s_columndownup5,
+    &s_columndownup4,
+    &s_columndownup3,
+    &s_columndownup2,
+    &s_columndownup1,
+    &s_columndowndown8,
+    &s_columndowndown7,
+    &s_columndowndown6,
+    &s_columndowndown5,
+    &s_columndowndown4,
+    &s_columndowndown3,
+    &s_columndowndown2,
+    &s_columndowndown1,
+
+
+    &s_spearup16,
+    &s_spearup15,
+    &s_spearup14,
+    &s_spearup13,
+    &s_spearup12,
+    &s_spearup11,
+    &s_spearup10,
+    &s_spearup9,
+    &s_spearup8,
+    &s_spearup7,
+    &s_spearup6,
+    &s_spearup5,
+    &s_spearup4,
+    &s_spearup3,
+    &s_spearup2,
+    &s_spearup1,
+
+    &s_pushcolumn1,
+    &s_pushcolumn2,
+    &s_pushcolumn3,
+    &s_wallfireball,
+    &s_crossfire2,
+    &s_crossfire1,
+    &s_crossdone5,
+    &s_crossdone4,
+    &s_crossdone3,
+    &s_crossdone2,
+    &s_crossdone1,
+    &s_dust,
+    &s_gas2,
+    &s_gas1,
+    &s_p_bazooka1,
+    &s_p_grenade,
+    &s_gunsmoke8,
+    &s_gunsmoke7,
+    &s_gunsmoke6,
+    &s_gunsmoke5,
+    &s_gunsmoke4,
+    &s_gunsmoke3,
+    &s_gunsmoke2,
+    &s_gunsmoke1,
+    &s_bloodspurt8,
+    &s_bloodspurt7,
+    &s_bloodspurt6,
+    &s_bloodspurt5,
+    &s_bloodspurt4,
+    &s_bloodspurt3,
+    &s_bloodspurt2,
+    &s_bloodspurt1,
+    &s_hitmetalwall4,
+    &s_hitmetalwall3,
+    &s_hitmetalwall2,
+    &s_hitmetalwall1,
+    &s_hitmetalactor4,
+    &s_hitmetalactor3,
+    &s_hitmetalactor2,
+    &s_hitmetalactor1,
+    &s_fireunit15,
+    &s_fireunit14,
+    &s_fireunit13,
+    &s_fireunit12,
+    &s_fireunit11,
+    &s_fireunit10,
+    &s_fireunit9,
+    &s_fireunit8,
+    &s_fireunit7,
+    &s_fireunit6,
+    &s_fireunit5,
+    &s_fireunit4,
+    &s_fireunit3,
+    &s_fireunit2,
+    &s_fireunit1,
+    &s_skeleton48,
+    &s_skeleton47,
+    &s_skeleton46,
+    &s_skeleton45,
+    &s_skeleton44,
+    &s_skeleton43,
+    &s_skeleton42,
+    &s_skeleton41,
+    &s_skeleton40,
+    &s_skeleton39,
+    &s_skeleton38,
+    &s_skeleton37,
+    &s_skeleton36,
+    &s_skeleton35,
+    &s_skeleton34,
+    &s_skeleton33,
+    &s_skeleton32,
+    &s_skeleton31,
+    &s_skeleton30,
+    &s_skeleton29,
+    &s_skeleton28,
+    &s_skeleton27,
+    &s_skeleton26,
+    &s_skeleton25,
+    &s_skeleton24,
+    &s_skeleton23,
+    &s_skeleton22,
+    &s_skeleton21,
+    &s_skeleton20,
+    &s_skeleton19,
+    &s_skeleton18,
+    &s_skeleton17,
+    &s_skeleton16,
+    &s_skeleton15,
+    &s_skeleton14,
+    &s_skeleton13,
+    &s_skeleton12,
+    &s_skeleton11,
+    &s_skeleton10,
+    &s_skeleton9,
+    &s_skeleton8,
+    &s_skeleton7,
+    &s_skeleton6,
+    &s_skeleton5,
+    &s_skeleton4,
+    &s_skeleton3,
+    &s_skeleton2,
+    &s_skeleton1,
+    &s_spring9,
+    &s_spring8,
+    &s_spring7,
+    &s_spring6,
+    &s_spring5,
+    &s_spring4,
+    &s_spring3,
+    &s_spring2,
+    &s_spring1,
+    &s_pgunattack1,
+    &s_pmissattack1,
+    &s_pgunattack2,
+    &s_pmissattack2,
+    &s_pbatblast,
+    &s_remotemove4,
+    &s_remotemove3,
+    &s_remotemove2,
+    &s_remotemove1,
+    &s_remoteinelev,
+    &s_remotedead,
+    &s_remotedie5,
+    &s_remotedie4,
+    &s_remotedie3,
+    &s_remotedie2,
+    &s_remotedie1,
+    &s_godfire4,
+    &s_godfire3,
+    &s_godfire2,
+    &s_godfire1,
+    &s_guts12,
+    &s_guts11,
+    &s_guts10,
+    &s_guts9,
+    &s_guts8,
+    &s_guts7,
+    &s_guts6,
+    &s_guts5,
+    &s_guts4,
+    &s_guts3,
+    &s_guts2,
+    &s_guts1,
+    &s_player,
+    &s_free,
+    &s_megaexplosions,
+    &s_bossdeath,
+    &s_superparticles,
+    &s_littlesoul,
+    &s_bigsoul,
+    &s_vaporized8,
+    &s_vaporized7,
+    &s_vaporized6,
+    &s_vaporized5,
+    &s_vaporized4,
+    &s_vaporized3,
+    &s_vaporized2,
+    &s_vaporized1,
+
+    &s_autospring1,
+    &s_autospring2,
+    &s_autospring3,
+    &s_autospring4,
+    &s_autospring5,
+    &s_autospring6,
+    &s_autospring7,
+    &s_autospring8,
+    &s_autospring9,
+
+
+    &s_gibsdone8,
+    &s_gibsdone7,
+    &s_gibsdone6,
+    &s_gibsdone5,
+    &s_gibsdone4,
+    &s_gibsdone3,
+    &s_gibsdone2,
+    &s_gibsdone1,
+    &s_gibs4,
+    &s_gibs3,
+    &s_gibs2,
+    &s_gibs1,
+
+
+
+    &s_collectorwander8,
+    &s_collectorwander7,
+    &s_collectorwander6,
+    &s_collectorwander5,
+    &s_collectorwander4,
+    &s_collectorwander3,
+    &s_collectorwander2,
+    &s_collectorwander1,
+    &s_collectorfdoor8,
+    &s_collectorfdoor7,
+    &s_collectorfdoor6,
+    &s_collectorfdoor5,
+    &s_collectorfdoor4,
+    &s_collectorfdoor3,
+    &s_collectorfdoor2,
+    &s_collectorfdoor1,
+    &s_tag,
+    &s_wind,
+    &s_timekeeper,
+    &s_remoteguts1,
+    &s_remoteguts2,
+    &s_remoteguts3,
+    &s_remoteguts4,
+    &s_remoteguts5,
+    &s_remoteguts6,
+    &s_remoteguts7,
+    &s_remoteguts8,
+    &s_remoteguts9,
+    &s_remoteguts10,
+    &s_remoteguts11,
+    &s_remoteguts12,
+    &s_voidwait,
+    &s_ashwait,
+    &s_deadwait,
+    &s_gutwait,
+    &s_eye1,
+    &s_eye2,
+    &s_eye3,
+    &s_itemspawn1,
+    &s_itemspawn2,
+    &s_itemspawn3,
+    &s_itemspawn4,
+    &s_itemspawn5,
+    &s_itemspawn6,
+    &s_itemspawn7,
+    &s_itemspawn8,
+    &s_deadblood1,
+    &s_deadblood2,
+    &s_deadblood3,
+    &s_deadblood4,
+    &s_deadblood5,
+    &s_deadblood6,
+    &s_deadblood7,
+    &s_deadblood8,
+    &s_flash1,
+    &s_flash2,
+    &s_flash3,
+    &s_flash4,
+    &s_flash5,
+    &s_flash6,
+    &s_flash7,
+    &s_flash8,
+    &s_basemarker1,
+    &s_basemarker2,
+    &s_basemarker3,
+    &s_basemarker4,
+    &s_basemarker5,
+    &s_basemarker6,
+    &s_basemarker7,
+    &s_basemarker8,
+    &s_pathdisk,
+    &s_elevdisk,
+    &s_megaremove,
+    /*&s_rain7,
+    &s_rain6,
+    &s_rain5,
+    &s_rain4,
+    &s_rain3,
+    &s_rain2,
+    &s_rain1,
+    &s_rainmaster,*/
+    &s_respawn8,
+    &s_respawn7,
+    &s_respawn6,
+    &s_respawn5,
+    &s_respawn4,
+    &s_respawn3,
+    &s_respawn2,
+    &s_respawn1,
+    &s_blooddrip1,
+    &s_blooddrip2,
+    &s_blooddrip3,
+    &s_blooddrip4,
+    &s_diskmaster,
+    &s_bstar4,
+    &s_bstar3,
+    &s_bstar2,
+    &s_bstar1,
+
+
+
+#if (SHAREWARE == 0)
+    &s_scottwander7,
+    &s_scottwander6,
+    &s_scottwander5,
+    &s_scottwander4,
+    &s_scottwander3,
+    &s_scottwander2,
+    &s_scottwander1,
+    &s_scottwanderdoor7,
+    &s_scottwanderdoor6,
+    &s_scottwanderdoor5,
+    &s_scottwanderdoor4,
+    &s_scottwanderdoor3,
+    &s_scottwanderdoor2,
+    &s_scottwanderdoor1,
+
+
+    &s_opstand,
+    &s_oppath4 	,
+    &s_oppath3 	,
+    &s_oppath2 	,
+    &s_oppath1 	,
+    &s_opcollide,
+    &s_opcollide2,
+    &s_opshoot4 	,
+    &s_opshoot3 	,
+    &s_opshoot2 	,
+    &s_opshoot1 	,
+    &s_opbolo5,
+    &s_opbolo4,
+    &s_opbolo3,
+    &s_opbolo2,
+    &s_opbolo1,
+    &s_bolocast4,
+    &s_bolocast3,
+    &s_bolocast2,
+    &s_bolocast1,
+    &s_opchase4 	,
+    &s_opchase3 	,
+    &s_opchase2 	,
+    &s_opchase1 	,
+    &s_opdead		,
+    &s_opdie5		,
+    &s_opdie4		,
+    &s_opdie3		,
+    &s_opdie2		,
+    &s_opdie1		,
+    &s_opcrushed2		,
+    &s_opcrushed1		,
+
+
+
+    &s_dmonkstand,
+    &s_dmonkpath4 	,
+    &s_dmonkpath3 	,
+    &s_dmonkpath2 	,
+    &s_dmonkpath1 	,
+    &s_dmonkcollide,
+    &s_dmonkcollide2,
+    &s_dmonkshoot6,
+    &s_dmonkshoot5,
+    &s_dmonkshoot4,
+    &s_dmonkshoot3,
+    &s_dmonkshoot2,
+    &s_dmonkshoot1,
+    &s_dmonkchase4 	,
+    &s_dmonkchase3 	,
+    &s_dmonkchase2 	,
+    &s_dmonkchase1 	,
+    &s_dmonkdead		,
+    &s_dmonkdie4		,
+    &s_dmonkdie3		,
+    &s_dmonkdie2		,
+    &s_dmonkdie1		,
+    &s_dmonkcrushed2		,
+    &s_dmonkcrushed1		,
+    &s_firemonkstand	,
+    &s_firemonkpath4 	,
+    &s_firemonkpath3 	,
+    &s_firemonkpath2 	,
+    &s_firemonkpath1 	,
+    &s_firemonkcollide,
+    &s_firemonkcollide2,
+    &s_firemonkcast7,
+    &s_firemonkcast6,
+    &s_firemonkcast5,
+    &s_firemonkcast4,
+    &s_firemonkcast3,
+    &s_firemonkcast2,
+    &s_firemonkcast1,
+    &s_monkfire4,
+    &s_monkfire3,
+    &s_monkfire2,
+    &s_monkfire1,
+    &s_fireballhit3,
+    &s_fireballhit2,
+    &s_fireballhit1,
+    &s_firemonkchase4 	,
+    &s_firemonkchase3 	,
+    &s_firemonkchase2 	,
+    &s_firemonkchase1 	,
+    &s_firemonkdead7		,
+    &s_firemonkdead6	,
+    &s_firemonkdead5	,
+    &s_firemonkdead4	,
+    &s_firemonkdead3	,
+    &s_firemonkdead2	,
+    &s_firemonkdead		,
+    &s_firemonkdie4		,
+    &s_firemonkdie3		,
+    &s_firemonkdie2		,
+    &s_firemonkdie1		,
+    &s_firemonkcrushed2		,
+    &s_firemonkcrushed1		,
+
+
+    &s_wallstand,
+    &s_wallpath,
+    &s_wallshoot,
+    &s_wallcollide,
+    &s_wallalign,
+    &s_wallrestore,
+    &s_wallwait,
+
+
+
+
+    &s_darianstand,
+    &s_darianchase4 	,
+    &s_darianchase3 	,
+    &s_darianchase2 	,
+    &s_darianchase1 	,
+    &s_darianrise8,
+    &s_darianrise7,
+    &s_darianrise6,
+    &s_darianrise5,
+    &s_darianrise4,
+    &s_darianrise3,
+    &s_darianrise2,
+    &s_darianrise1,
+    &s_dariansink9,
+    &s_dariansink8,
+    &s_dariansink7,
+    &s_dariansink6,
+    &s_dariansink5,
+    &s_dariansink4,
+    &s_dariansink3,
+    &s_dariansink2,
+    &s_dariansink1,
+    &s_dariancollide,
+    &s_dariancollide2,
+    &s_darianshoot4,
+    &s_darianshoot3,
+    &s_darianshoot2,
+    &s_darianshoot1,
+    &s_dariandefend3,
+    &s_dariandefend2,
+    &s_dariandefend1,
+    &s_darianuse4,
+    &s_darianuse3,
+    &s_darianuse2,
+    &s_darianuse1,
+    &s_darianwait,
+    &s_darianspears,
+    &s_dspear16,
+    &s_dspear15,
+    &s_dspear14,
+    &s_dspear13,
+    &s_dspear12,
+    &s_dspear11,
+    &s_dspear10,
+    &s_dspear9,
+    &s_dspear8,
+    &s_dspear7,
+    &s_dspear6,
+    &s_dspear5,
+    &s_dspear4,
+    &s_dspear3,
+    &s_dspear2,
+    &s_dspear1,
+    &s_dariandead2 	,
+    &s_dariandead1 	,
+    &s_dariandead 	,
+    &s_dariandie10,
+    &s_dariandie9 	,
+    &s_dariandie8 	,
+    &s_dariandie7 	,
+    &s_dariandie6 	,
+    &s_dariandie5 	,
+    &s_dariandie4 	,
+    &s_dariandie3 	,
+    &s_dariandie2 	,
+    &s_dariandie1 	,
+    &s_heinrichstand	,
+    &s_heinrichchase 	,
+    &s_kristleft,
+    &s_kristright,
+    &s_heinrichshoot11,
+    &s_heinrichshoot10,
+    &s_heinrichshoot9,
+    &s_heinrichshoot8,
+    &s_heinrichshoot7,
+    &s_heinrichshoot6,
+    &s_heinrichshoot5,
+    &s_heinrichshoot4,
+    &s_heinrichshoot3,
+    &s_heinrichshoot2,
+    &s_heinrichshoot1,
+    &s_missile1,
+    &s_missilehit3,
+    &s_missilehit2,
+    &s_missilehit1,
+    &s_mine4,
+    &s_mine3,
+    &s_mine2,
+    &s_mine1,
+    &s_heinrichdefend,
+    &s_heinrichooc,
+    &s_heinrichdead 	,
+    &s_heinrichdie2 	,
+    &s_heinrichdie1 	,
+    &s_heindead2,
+    &s_heindead1,
+    &s_heinexp13,
+    &s_heinexp12,
+    &s_heinexp11,
+    &s_heinexp10,
+    &s_heinexp9,
+    &s_heinexp8,
+    &s_heinexp7,
+    &s_heinexp6,
+    &s_heinexp5,
+    &s_heinexp4,
+    &s_heinexp3,
+    &s_heinexp2,
+    &s_heinexp1,
+    &s_darkmonkstand	,
+    &s_darkmonkland	,
+    &s_darkmonkchase2	,
+    &s_darkmonkchase1	,
+    &s_dmlandandfire,
+    &s_darkmonkcover3	,
+    &s_darkmonkcover2	,
+    &s_darkmonkcover1	,
+    &s_darkmonkawaken5	,
+    &s_darkmonkawaken4	,
+    &s_darkmonkawaken3	,
+    &s_darkmonkawaken2	,
+    &s_darkmonkawaken1 	,
+    &s_darkmonklightning11	,
+    &s_darkmonklightning10	,
+    &s_darkmonklightning9	,
+    &s_darkmonklightning8	,
+    &s_darkmonklightning7 	,
+    &s_darkmonklightning6	,
+    &s_darkmonklightning5	,
+    &s_darkmonklightning4	,
+    &s_darkmonklightning3	,
+    &s_darkmonklightning2 	,
+    &s_darkmonklightning1 	,
+    &s_darkmonkfspark6	,
+    &s_darkmonkfspark5	,
+    &s_darkmonkfspark4	,
+    &s_darkmonkfspark3	,
+    &s_darkmonkfspark2 	,
+    &s_darkmonkfspark1 	,
+    &s_darkmonkbreathe8	,
+    &s_darkmonkbreathe7 	,
+    &s_darkmonkbreathe6	,
+    &s_darkmonkbreathe5	,
+    &s_darkmonkbreathe4	,
+    &s_darkmonkbreathe3	,
+    &s_darkmonkbreathe2 	,
+    &s_darkmonkbreathe1 	,
+    &s_darkmonksummon3	,
+    &s_darkmonksummon2 	,
+    &s_darkmonksummon1 	,
+    &s_snakepath,
+    &s_snakefindpath,
+    &s_darkmonkhead	,
+    &s_darkmonksnakelink	,
+    &s_darkmonkhspawn,
+    &s_darkmonkfastspawn,
+    &s_darkmonkheaddead	,
+    &s_darkmonkheaddie1	,
+    &s_darkmonkhball9	,
+    &s_darkmonkhball8	,
+    &s_darkmonkhball7,
+    &s_darkmonkhball6	,
+    &s_darkmonkhball5	,
+    &s_darkmonkhball4	,
+    &s_darkmonkhball3	,
+    &s_darkmonkhball2,
+    &s_darkmonkhball1,
+    &s_darkmonkabsorb9	,
+    &s_darkmonkabsorb8	,
+    &s_darkmonkabsorb7,
+    &s_darkmonkabsorb6	,
+    &s_darkmonkabsorb5	,
+    &s_darkmonkabsorb4	,
+    &s_darkmonkabsorb3	,
+    &s_darkmonkabsorb2,
+    &s_darkmonkabsorb1,
+    &s_darkmonksphere10,
+    &s_darkmonksphere9,
+    &s_darkmonksphere8,
+    &s_darkmonksphere7,
+    &s_darkmonksphere6,
+    &s_darkmonksphere5,
+    &s_darkmonksphere4,
+    &s_darkmonksphere3,
+    &s_darkmonksphere2,
+    &s_darkmonksphere1,
+    &s_dmgreenthing10,
+    &s_dmgreenthing9,
+    &s_dmgreenthing8,
+    &s_dmgreenthing7,
+    &s_dmgreenthing6,
+    &s_dmgreenthing5,
+    &s_dmgreenthing4,
+    &s_dmgreenthing3,
+    &s_dmgreenthing2,
+    &s_dmgreenthing1,
+    &s_energysphere4,
+    &s_energysphere3,
+    &s_energysphere2,
+    &s_energysphere1,
+    &s_lightning,
+    &s_handball2,
+    &s_handball1,
+    &s_faceball2,
+    &s_faceball1,
+    &s_floorspark4,
+    &s_floorspark3,
+    &s_floorspark2,
+    &s_floorspark1,
+    &s_darkmonkreact,
+    &s_darkmonkbball9	,
+    &s_darkmonkbball8	,
+    &s_darkmonkbball7,
+    &s_darkmonkbball6	,
+    &s_darkmonkbball5	,
+    &s_darkmonkbball4	,
+    &s_darkmonkbball3	,
+    &s_darkmonkbball2,
+    &s_darkmonkbball1,
+    &s_darkmonkcharge10,
+    &s_darkmonkcharge9	,
+    &s_darkmonkcharge8	,
+    &s_darkmonkcharge7	,
+    &s_darkmonkcharge6 	,
+    &s_darkmonkcharge5	,
+    &s_darkmonkcharge4	,
+    &s_darkmonkcharge3	,
+    &s_darkmonkcharge2	,
+    &s_darkmonkcharge1 	,
+    &s_darkmonkscare5	,
+    &s_darkmonkscare4	,
+    &s_darkmonkscare3	,
+    &s_darkmonkscare2,
+    &s_darkmonkscare1,
+    &s_darkmonkdead,
+    &s_darkmonkdie7,
+    &s_darkmonkdie6,
+    &s_darkmonkdie5,
+    &s_darkmonkdie4,
+    &s_darkmonkdie3,
+    &s_darkmonkdie2,
+    &s_darkmonkdie1,
+    &s_darkmonkredhead,
+    &s_darkmonkredlink,
+    &s_redheadhit,
+    &s_redlinkhit,
+    &s_spithit4,
+    &s_spithit3,
+    &s_spithit2,
+    &s_spithit1,
+    &s_spit4,
+    &s_spit3,
+    &s_spit2,
+    &s_spit1,
+    &s_snakefire2,
+    &s_snakefire1,
+    &s_snakefireworks1,
+    &s_snakefireworks2,
+
+    &s_dexplosion22,
+    &s_dexplosion21,
+    &s_dexplosion20,
+    &s_dexplosion19,
+    &s_dexplosion18,
+    &s_dexplosion17,
+    &s_dexplosion16,
+    &s_dexplosion15,
+    &s_dexplosion14,
+    &s_dexplosion13,
+    &s_dexplosion12,
+    &s_dexplosion11,
+    &s_dexplosion10,
+    &s_dexplosion9,
+    &s_dexplosion8,
+    &s_dexplosion7,
+    &s_dexplosion6,
+    &s_dexplosion5,
+    &s_dexplosion4,
+    &s_dexplosion3,
+    &s_dexplosion2,
+    &s_dexplosion1,
+    &s_NMEhead1,
+    &s_NMEhead2,
+    &s_NMEchase,
+    &s_NMEwheels1,
+    &s_NMEwheels2,
+    &s_NMEwheels3,
+    &s_NMEwheels4,
+    &s_NMEwheels5,
+    &s_NMEspinattack,
+    &s_NMEwheelspin,
+    &s_NMEminiball4,
+    &s_NMEminiball3,
+    &s_NMEminiball2,
+    &s_NMEminiball1,
+    &s_NMEsaucer4,
+    &s_NMEsaucer3,
+    &s_NMEsaucer2,
+    &s_NMEsaucer1,
+    &s_NMEdie,
+    &s_NMEattack,
+    &s_NMEhead1rl,
+    &s_NMEhead2rl,
+    &s_NMEwindup,
+    &s_NMEwheels120,
+    &s_NMEwrotleft3,
+    &s_NMEwrotleft2,
+    &s_NMEwrotleft1,
+    &s_NMEwrotright3,
+    &s_NMEwrotright2,
+    &s_NMEwrotright1,
+    &s_NMEdeathbuildup,
+    &s_NMEheadexplosion,
+    &s_NMEstand,
+    &s_NMEspinfire,
+    &s_oshuriken4,
+    &s_oshuriken3,
+    &s_oshuriken2,
+    &s_oshuriken1,
+    &s_oshurikenhit3,
+    &s_oshurikenhit2,
+    &s_oshurikenhit1,
+    &s_shootinghead,
+
+
+    &s_speardown16,
+    &s_speardown15,
+    &s_speardown14,
+    &s_speardown13,
+    &s_speardown12,
+    &s_speardown11,
+    &s_speardown10,
+    &s_speardown9,
+    &s_speardown8,
+    &s_speardown7,
+    &s_speardown6,
+    &s_speardown5,
+    &s_speardown4,
+    &s_speardown3,
+    &s_speardown2,
+    &s_speardown1,
+
+
+    &s_downblade16,
+    &s_downblade15,
+    &s_downblade14,
+    &s_downblade13,
+    &s_downblade12,
+    &s_downblade11,
+    &s_downblade10,
+    &s_downblade9,
+    &s_downblade8,
+    &s_downblade7,
+    &s_downblade6,
+    &s_downblade5,
+    &s_downblade4,
+    &s_downblade3,
+    &s_downblade2,
+    &s_downblade1,
+
+    &s_firejetdown23,
+    &s_firejetdown22,
+    &s_firejetdown21,
+    &s_firejetdown20,
+    &s_firejetdown19,
+    &s_firejetdown18,
+    &s_firejetdown17,
+    &s_firejetdown16,
+    &s_firejetdown15,
+    &s_firejetdown14,
+    &s_firejetdown13,
+    &s_firejetdown12,
+    &s_firejetdown11,
+    &s_firejetdown10,
+    &s_firejetdown9,
+    &s_firejetdown8,
+    &s_firejetdown7,
+    &s_firejetdown6,
+    &s_firejetdown5,
+    &s_firejetdown4,
+    &s_firejetdown3,
+    &s_firejetdown2,
+    &s_firejetdown1,
+
+    &s_columnupdown6,
+    &s_columnupdown5,
+    &s_columnupdown4,
+    &s_columnupdown3,
+    &s_columnupdown2,
+    &s_columnupdown1,
+    &s_columnupup8,
+    &s_columnupup7,
+    &s_columnupup6,
+    &s_columnupup5,
+    &s_columnupup4,
+    &s_columnupup3,
+    &s_columnupup2,
+    &s_columnupup1,
+
+
+    &s_spinupblade16,
+    &s_spinupblade15,
+    &s_spinupblade14,
+    &s_spinupblade13,
+    &s_spinupblade12,
+    &s_spinupblade11,
+    &s_spinupblade10,
+    &s_spinupblade9,
+    &s_spinupblade8,
+    &s_spinupblade7,
+    &s_spinupblade6,
+    &s_spinupblade5,
+    &s_spinupblade4,
+    &s_spinupblade3,
+    &s_spinupblade2,
+    &s_spinupblade1,
+
+
+    &s_spindownblade16,
+    &s_spindownblade15,
+    &s_spindownblade14,
+    &s_spindownblade13,
+    &s_spindownblade12,
+    &s_spindownblade11,
+    &s_spindownblade10,
+    &s_spindownblade9,
+    &s_spindownblade8,
+    &s_spindownblade7,
+    &s_spindownblade6,
+    &s_spindownblade5,
+    &s_spindownblade4,
+    &s_spindownblade3,
+    &s_spindownblade2,
+    &s_spindownblade1,
+
+
+    &s_bouldersink9,
+    &s_bouldersink8,
+    &s_bouldersink7,
+    &s_bouldersink6,
+    &s_bouldersink5,
+    &s_bouldersink4,
+    &s_bouldersink3,
+    &s_bouldersink2,
+    &s_bouldersink1,
+    &s_boulderroll8,
+    &s_boulderroll7,
+    &s_boulderroll6,
+    &s_boulderroll5,
+    &s_boulderroll4,
+    &s_boulderroll3,
+    &s_boulderroll2,
+    &s_boulderroll1,
+    &s_boulderdrop12,
+    &s_boulderdrop11,
+    &s_boulderdrop10,
+    &s_boulderdrop9,
+    &s_boulderdrop8,
+    &s_boulderdrop7,
+    &s_boulderdrop6,
+    &s_boulderdrop5,
+    &s_boulderdrop4,
+    &s_boulderdrop3,
+    &s_boulderdrop2,
+    &s_boulderdrop1,
+    &s_boulderspawn,
+
+
+    &s_gunfire2,
+    &s_gunfire1,
+    &s_gunstand,
+    &s_gunraise4,
+    &s_gunraise3,
+    &s_gunraise2,
+    &s_gunraise1,
+    &s_gunlower3,
+    &s_gunlower2,
+    &s_gunlower1,
+    &s_gundead,
+    &s_gundie1,
+    &s_4waygunfire1,
+    &s_4waygunfire2,
+    &s_4waygun,
+
+
+
+    &s_kessphere8,
+    &s_kessphere7,
+    &s_kessphere6,
+    &s_kessphere5,
+    &s_kessphere4,
+    &s_kessphere3,
+    &s_kessphere2,
+    &s_kessphere1,
+
+
+    &s_slop1,
+    &s_slop2,
+    &s_slop3,
+    &s_slop4,
+
+    &s_batblast1,
+    &s_batblast2,
+    &s_batblast3,
+    &s_batblast4,
+
+    &s_serialdog4,
+    &s_serialdog3,
+    &s_serialdog2,
+    &s_serialdog,
+    &s_serialdogattack,
+    &s_doguse,
+    &s_doglick,
+    &s_dogwait,
+
+
+
+
+#endif //SHAREWARE
+
+};
+#endif
--- /dev/null
+++ b/rott/rt_ted.c
@@ -1,0 +1,7089 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+// make sure word alignment is OFF!
+
+#include "rt_def.h"
+#include "rt_sound.h"
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <time.h>
+
+#ifdef DOS
+#include <io.h>
+#include <conio.h>
+#include <dos.h>
+#else
+#include <errno.h>
+#endif
+
+#include "states.h"
+#include "watcom.h"
+#include "rt_ted.h"
+#include "_rt_ted.h"
+#include "w_wad.h"
+#include "z_zone.h"
+#include "rt_util.h"
+#include "lumpy.h"
+#include "rt_vid.h"
+#include "rt_actor.h"
+#include "rt_stat.h"
+#include "rt_menu.h"
+#include "rt_draw.h"
+#include "rt_com.h"
+#include "rt_main.h"
+#include "rt_door.h"
+#include "rt_playr.h"
+#include "rt_view.h"
+#include "rt_str.h"
+#include "isr.h"
+#include "rt_floor.h"
+#include "rt_game.h"
+#include "rt_rand.h"
+#include "rt_cfg.h"
+#include "develop.h"
+#include "modexlib.h"
+#include "engine.h"
+#include "rt_debug.h"
+#include "rt_scale.h"
+#include "rt_net.h"
+//MED
+#include "memcheck.h"
+
+
+
+
+//========================================
+// GLOBAL VARIABLES
+//========================================
+
+extern boolean  UseBaseMarker;
+
+teamtype TEAM[MAXPLAYERS];
+int numareatiles[NUMAREAS+1];
+int shapestart,shapestop;
+_2dvec SPAWNLOC[MAXSPAWNLOCATIONS],FIRST,SECOND;
+int NUMSPAWNLOCATIONS,numteams=0;
+wall_t    walls[MAXWALLTILES];
+str_clock Clocks[MAXCLOCKS];
+int numclocks;
+int LightsInArea[NUMAREAS+1];
+
+int maxheight;
+int nominalheight;
+int elevatorstart;
+int gunsstart;
+int fog;
+int lightsource;
+int SNAKELEVEL;
+int whichpath;
+
+word *mapplanes[3];
+int  mapwidth;
+int  mapheight;
+int  lastlevelloaded=-1;
+
+boolean insetupgame;
+boolean ISRTL = false;
+
+unsigned MapSpecials = 0;
+
+char LevelName[80];
+
+//========================================
+// LOCAL VARIABLES
+//========================================
+
+static cachetype * cachelist;
+static word cacheindex;
+static boolean CachingStarted=false;
+static char * ROTTMAPS = STANDARDGAMELEVELS;
+char * BATTMAPS;
+
+static char NormalWeaponTiles[ 10 ] =
+{
+    46, 48, 49, 50, 51, 52, 53, 54, 55, 56
+};
+static char SharewareWeaponTiles[ 7 ] =
+{
+    48, 49, 50, 51, 52, 53, 54
+};
+
+static char CacheStrings[MAXSILLYSTRINGS][80]=
+{
+    {"Ready yourself\nfor destruction!\0\0"},
+    {"Here comes the enemy!\0\0"},
+    {"Hope you wrote\nyour will!\0\0"},
+    {"Did you bring your\nextra bullets?\0\0"},
+    {"Try not to bleed\non the rug.\0\0"},
+    {"Let's see...bandages,\ntape, splints,...\0\0"},
+    {"Couldn't we just\ntalk this over?\0\0"},
+    {"Cache as cache can...\0\0"},
+    {"You are smart.\nMake us strong.\0\0"},
+    {"Bleh!\0\0"},
+    {"I am as far\nabove you...\0\0"},
+    {"Just keep thinkin':\nBut it's loadin' COOL\nstuff...\0\0"},
+    {"Guess which line\nwill win!\0\0"},
+    {"Oh, no. Not again.\0\0"},
+    {"Wait! I'm not ready!\nToo late.\0\0"},
+    {"Hope this doesn't\ncrash.\0\0"},
+    {"Have a sandwich.\0\0"},
+    {"Smoke 'em if\nya got 'em...and\nif ya like cancer.\0\0"},
+    {"Ummmmm...\0\0"},
+    {"Bang! Bang! Bang!\nFreeze!\0\0"},
+    {"You have the right\nto...DIE.\0\0"},
+    {"Insert funny phrase\nhere.\0\0"},
+    {"Blood, bullets,\nnicely decorated\nhallways.\0\0"},
+    {"You are to be killed,\nnot hurt.\0\0"},
+    {"It's time for you to\ngo down the stairs!\0\0"},
+    {"This game, like,\nrules and stuff.\0\0"},
+    {"We get money for this!\nHa ha ha ha!\0\0"},
+    {"Let's not start any\nreligious wars...\0\0"},
+    {"I don't wanna start\nno ting...\0\0"},
+    {"Ah, another sacrifice!\0\0"},
+    {"If you were dead,\nyou'd be the\nsame thing.\0\0"},
+    {"This Game isn't\nhuman; it can't\nbe reasoned with!\0\0"}
+};
+
+void SetupGameLevel (void);
+void ScanInfoPlane(void);
+
+void DrawPreCache( void );
+void InitializePlayerstates(void);
+void SetupSnakePath(void);
+void SetupRandomActors(void);
+void SetupActors(void);
+void SetupStatics(void);
+void LoftSprites( void );
+int GetLumpForTile(int tile);
+
+//========================================
+
+/*
+======================
+=
+= SortPreCache
+= Sort the Precache for cachelevel precedence using a HEAPSORT
+=
+======================
+*/
+#define SGN(x)          ((x>0) ? (1) : ((x==0) ? (0) : (-1)))
+
+/*--------------------------------------------------------------------------*/
+int CompareTags(s1p,s2p) cachetype *s1p,*s2p;
+{
+// Sort according to lump
+    if (DoPanicMapping()==true)
+        return SGN(s1p->cachelevel-s2p->cachelevel);
+// Sort according to cachelevel
+    else
+        return SGN(s1p->lump-s2p->lump);
+}
+
+void SwitchCacheEntries(s1p,s2p) cachetype *s1p,*s2p;
+{
+    cachetype temp;
+
+    temp=*s1p;
+    *s1p=*s2p;
+    *s2p=temp;
+}
+
+
+
+void SortPreCache( void )
+{
+    hsort((char *)cachelist,cacheindex,sizeof(cachetype),&CompareTags,&SwitchCacheEntries);
+}
+
+//========================================
+
+
+/*
+======================
+=
+= SetupPreCache
+= Setup the cache for pre-cacheing
+=
+======================
+*/
+void SetupPreCache( void )
+{
+
+    CachingStarted=true;
+    cacheindex=0;
+    cachelist=(cachetype *)SafeMalloc(MAXPRECACHE*(sizeof(cachetype)));
+    DrawPreCache();
+}
+
+
+/*
+======================
+=
+= ShutdownPreCache
+= Setup the cache for pre-cacheing
+=
+======================
+*/
+void ShutdownPreCache( void )
+{
+
+    CachingStarted=false;
+    SafeFree((byte *)cachelist);
+}
+
+
+/*
+======================
+=
+= PreCacheLump
+= precache the lump and check to see if it is already tagged
+=
+======================
+*/
+void PreCacheLump( int lump, int level, int type ) // added type
+{
+    int i;
+
+    if (CachingStarted==false)
+        return;
+    if (!W_LumpLength(lump))
+    {
+#if (PRECACHETEST == 1)
+        SoftError("Tried to precache a label, lump = %ld tag=%ld maskednum=%ld\n",lump, level, maskednum);
+#endif
+        return;
+    }
+    for (i=1; i<cacheindex; i++)
+        if (cachelist[i].lump==lump)
+            return;
+    cachelist[cacheindex].lump=lump;
+    cachelist[cacheindex].cachelevel=level;
+    cachelist[cacheindex++].type=type;
+    if (cacheindex==MAXPRECACHE)
+        Error("MaxPreCache reached\n");
+}
+
+
+
+/*
+======================
+=
+= PreCacheGroup
+= precache the lump and check to see if it is already tagged
+=
+======================
+*/
+void PreCacheGroup( int start, int end, int type ) // added type
+{
+    int i;
+    int j;
+    int k;
+    int found;
+
+    if (CachingStarted==false)
+        return;
+    k=cacheindex;
+    for (j=start; j<=end; j++)
+    {
+        if (!W_LumpLength(j))
+        {
+#if (PRECACHETEST == 1)
+            SoftError("Tried to precache a label, lump = %ld\n",j);
+#endif
+            continue;
+        }
+        found=0;
+        for (i=1; i<k; i++)
+            if (cachelist[i].lump==j)
+            {
+                found=1;
+                break;
+            }
+        if (found==0)
+        {
+            cachelist[cacheindex].lump=j;
+            cachelist[cacheindex].cachelevel=PU_CACHEACTORS;
+            cachelist[cacheindex++].type=type;
+
+            if (cacheindex==MAXPRECACHE)
+                Error("MaxPreCache reached\n");
+        }
+    }
+
+}
+
+
+/*
+======================
+=
+= PreCachePlayers
+= precache the lump and check to see if it is already tagged
+=
+======================
+*/
+void PreCachePlayers(void )
+{
+    int start;
+    int end;
+    int i;
+    playertype*pstate;
+
+    for(i=0; i<numplayers; i++)
+    {   if (i!=consoleplayer) // don't cache consoleplayer
+        {   pstate = &PLAYERSTATE[i];
+            start=W_GetNumForName("CASSHO11")+(pstate->player*REMOTEOFFSET);
+            end  =W_GetNumForName("CASWDEAD")+(pstate->player*REMOTEOFFSET);
+            PreCacheGroup(start,end,cache_patch_t);
+        }
+    }
+}
+
+
+
+
+void PreCachePlayerSound(void)
+{
+    switch (locplayerstate->player)
+    {
+    case 0:
+        SD_PreCacheSound(SD_PLAYERTCSND);
+
+        break;
+    case 1:
+        SD_PreCacheSound(SD_PLAYERTBSND);
+
+        break;
+    case 2:
+        SD_PreCacheSound(SD_PLAYERDWSND);
+
+        break;
+    case 3:
+        SD_PreCacheSound(SD_PLAYERLNSND);
+
+        break;
+    case 4:
+        SD_PreCacheSound(SD_PLAYERIPFSND);
+        break;
+    }
+}
+
+
+#define IS_ALTERNATE_ACTOR(ob)                                 \
+        ((ob->shapeoffset - deathshapeoffset[ob->obclass]) > 0)\
+
+/*
+======================
+=
+= PreCacheActor
+= precache the lump and check to see if it is already tagged
+=
+======================
+*/
+void PreCacheActor( int actor, int which )
+{
+    int start;
+    int end;
+
+    switch (actor)
+    {
+    case lowguardobj:
+        if (IS_ALTERNATE_ACTOR(new))
+        {
+            start = SD_LOWGUARD2SEESND;
+            end = SD_LOWGUARD2SEE3SND;
+            SD_PreCacheSoundGroup(start,end);
+
+            start = SD_LOWGUARD2DIESND;
+            end = SD_LOWGUARD2DIESND;
+            SD_PreCacheSoundGroup(start,end);
+
+            start = SD_LOWGUARDFIRESND;
+            end = SD_SNEAKYSPRINGFSND;
+            SD_PreCacheSoundGroup(start,end);
+
+            start=W_GetNumForName("MARSHOO1");
+            end  =W_GetNumForName("MNGRISE4");
+            //end  =W_GetNumForName("MARUSE28");
+        }
+
+        else
+        {   start = SD_LOWGUARD1SEESND;
+            end = SD_LOWGUARD1SEE3SND;
+            SD_PreCacheSoundGroup(start,end);
+
+            start = SD_LOWGUARD1DIESND;
+            end = SD_LOWGUARD1DIESND;
+            SD_PreCacheSoundGroup(start,end);
+
+            start = SD_LOWGUARDFIRESND;
+            end = SD_SNEAKYSPRINGFSND;
+            SD_PreCacheSoundGroup(start,end);
+
+            start=W_GetNumForName("LWGSHOO1");
+            end = W_GetNumForName("SNGRISE4");
+            //end  =W_GetNumForName("LOWUSE28");
+        }
+
+        break;
+    case highguardobj:
+
+        start = SD_HIGHGUARD1SEESND;
+        end = SD_HIGHGUARDDIESND;
+        SD_PreCacheSoundGroup(start,end);
+
+        if (IS_ALTERNATE_ACTOR(new))
+        {
+            start=W_GetNumForName("HIGSHOO1");
+            end  =W_GetNumForName("HIGWDEAD");
+            //end  =W_GetNumForName("HIHUSE28");
+        }
+        else
+        {
+            start=W_GetNumForName("HG2SHOO1");
+            end  =W_GetNumForName("HG2WDEAD");
+            //end  =W_GetNumForName("H2HUSE28");
+        }
+        break;
+
+    case overpatrolobj:
+
+        start=W_GetNumForName("OBBOLO1");
+        end  =W_GetNumForName("OBBOLO4");
+        PreCacheGroup(start,end,cache_patch_t);
+        start=W_GetNumForName("NET1");
+        end  =W_GetNumForName("NET4");
+        PreCacheGroup(start,end,cache_patch_t);
+
+        start = SD_OVERP1SEESND;
+        end = SD_OVERPDIESND;
+        SD_PreCacheSoundGroup(start,end);
+        SD_PreCacheSoundGroup(SD_NETWIGGLESND,SD_NETFALLSND);
+
+        if (IS_ALTERNATE_ACTOR(new))
+        {
+            start=W_GetNumForName("PATSHOO1");
+            end  =W_GetNumForName("PATDEAD");
+
+            //end  =W_GetNumForName("OBPUSE28");
+        }
+
+        else
+        {
+            start=W_GetNumForName("OBPSHOO1");
+            end  =W_GetNumForName("OBPDEAD");
+
+            //end  =W_GetNumForName("PATUSE28");
+        }
+
+        break;
+    case strikeguardobj:
+
+
+        start = SD_STRIKE1SEESND;
+        end = SD_STRIKEDIESND;
+        SD_PreCacheSoundGroup(start,end);
+
+        if (IS_ALTERNATE_ACTOR(new))
+        {
+            start=W_GetNumForName("XYGSHOO1");
+            end  =W_GetNumForName("XYLROLL6");
+            //end  =W_GetNumForName("XYUSE28");
+        }
+
+        else
+        {
+            start=W_GetNumForName("ANGSHOO1");
+            end  =W_GetNumForName("ANLROLL6");
+            //end  =W_GetNumForName("ANUSE28");
+        }
+
+        break;
+
+    case blitzguardobj:
+
+        start = SD_BLITZ1SEESND;
+        end = SD_BLITZDIESND;
+        SD_PreCacheSoundGroup(start,end);
+
+        if (IS_ALTERNATE_ACTOR(new))
+        {
+            start=W_GetNumForName("WIGSHOO1");
+            end  =W_GetNumForName("WIHUSE28");
+        }
+
+        else
+        {
+            start=W_GetNumForName("LIGSHOO1");
+            end  =W_GetNumForName("LIPEAD11");
+        }
+
+        break;
+
+    case triadenforcerobj:
+
+        start = SD_ENFORCERSEESND;
+        end = SD_ENFORCERDIESND;
+        SD_PreCacheSoundGroup(start,end);
+
+        start=W_GetNumForName("TEGREN1");
+        end  =W_GetNumForName("TGRENF6");
+        PreCacheGroup(start,end,cache_patch_t);
+        start=W_GetNumForName("TRISHOO1");
+        end  =W_GetNumForName("TRIWDEAD");
+        //end  =W_GetNumForName("TRIUSE28");
+        break;
+    case deathmonkobj:
+
+
+        start = SD_MONKSEESND;
+        end = SD_MONKDIESND;
+        SD_PreCacheSoundGroup(start,end);
+
+        start=W_GetNumForName("MONKDR1");
+        end  =W_GetNumForName("MONDEAD");
+        //end  =W_GetNumForName("MONUSE28");
+        break;
+
+
+    case dfiremonkobj:
+
+        start = SD_FIREMONKSEESND;
+        end = SD_FIREMONKDIESND;
+        SD_PreCacheSoundGroup(start,end);
+
+        start = W_GetNumForName("MONFIRE1");
+        end = W_GetNumForName("MONFIRE4");
+        PreCacheGroup(start,end,cache_patch_t);
+
+
+        if (IS_ALTERNATE_ACTOR(new))
+        {
+            start=W_GetNumForName("MRKKSH1");
+            end  =W_GetNumForName("MRKDEAD7");
+        }
+
+        else
+        {
+            start=W_GetNumForName("ALLKSH1");
+            end  =W_GetNumForName("ALLDEAD7");
+        }
+
+        break;
+
+    case roboguardobj:
+
+        start = SD_ROBOTSEESND;
+        end = SD_ROBOTDIESND;
+        SD_PreCacheSoundGroup(start,end);
+        start=W_GetNumForName("ROBOGRD1");
+        end  =W_GetNumForName("ROBGRD16");
+        break;
+
+    case b_darianobj:
+
+        PreCachePlayerSound();
+
+        start = SD_DARIANSEESND;
+        end = SD_DARIANSAY3;
+        SD_PreCacheSoundGroup(start,end);
+
+
+        start=W_GetNumForName("DARSHOO1");
+        end  =W_GetNumForName("DARUSE28");
+        break;
+
+
+    case b_heinrichobj:
+
+        PreCachePlayerSound();
+
+        start = SD_KRISTSEESND;
+        end = SD_KRISTSAY3;
+        SD_PreCacheSoundGroup(start,end);
+
+        start=W_GetNumForName("MINE1");
+        end  =W_GetNumForName("MINE4");
+        PreCacheGroup(start,end,cache_patch_t);
+        start=W_GetNumForName("HSIT1");
+        end  =W_GetNumForName("HDOPE8");
+        break;
+
+    case b_darkmonkobj:
+
+        start = SD_DARKMONKSEESND;
+        end = SD_DARKMONKSAY3;
+        SD_PreCacheSoundGroup(start,end);
+
+        start=W_GetNumForName("LIGNING1");
+        end  =W_GetNumForName("FSPARK4");
+        PreCacheGroup(start,end,cache_patch_t);
+        start=W_GetNumForName("TOMS1");
+        end  =W_GetNumForName("TOHRH8");
+        break;
+
+    case b_darksnakeobj:
+
+        PreCachePlayerSound();
+
+        start = SD_SNAKESEESND;
+        end = SD_SNAKESAY3;
+        SD_PreCacheSoundGroup(start,end);
+
+        start=W_GetNumForName("TOMRH1");
+        end  =W_GetNumForName("TOHRH8");
+    case b_robobossobj:
+
+        PreCachePlayerSound();
+
+        start = SD_NMESEESND;
+        end = SD_NMESEESND;
+        SD_PreCacheSoundGroup(start,end);
+
+        start=W_GetNumForName("RHEAD101");
+        end  =W_GetNumForName("NMESAUC4");
+        break;
+    case patrolgunobj:
+
+        start = SD_EMPLACEMENTSEESND;
+        end = SD_BIGEMPLACEFIRESND;
+        SD_PreCacheSoundGroup(start,end);
+
+
+        start=W_GetNumForName("GUNEMP1");
+        end  =W_GetNumForName("GUNEMPF8");
+        PreCacheGroup(start,end,cache_patch_t);
+        start=W_GetNumForName("GRISE11");
+        end  =W_GetNumForName("GDEAD2");
+        break;
+
+    case wallopobj:
+        start=W_GetNumForName("BSTAR1");
+        end  =W_GetNumForName("BSTAR4");
+        PreCacheGroup(start,end,cache_patch_t);
+        start=W_GetNumForName("BCRAFT1");
+        end  =W_GetNumForName("BCRAFT16");
+        break;
+
+    case wallfireobj:
+
+        SD_PreCacheSound(SD_FIRECHUTESND);
+        SD_PreCacheSound(SD_FIREBALLSND);
+        SD_PreCacheSound(SD_FIREBALLHITSND);
+
+        start = W_GetNumForName("CRFIRE11");
+        end = W_GetNumForName("CREXP5");
+
+    case pillarobj:
+
+        start=W_GetNumForName("PUSHCOL1");
+        end  =W_GetNumForName("PSHCOL1A");
+        //end  =W_GetNumForName("PUSHCOL3");
+        break;
+
+    case firejetobj:
+
+        SD_PreCacheSound(SD_FIREJETSND);
+
+        if (which)
+        {
+            start=W_GetNumForName("FJUP0");
+            end  =W_GetNumForName("FJUP22");
+        }
+#if (SHAREWARE == 0)
+        else
+        {
+            start=W_GetNumForName("FJDOWN0");
+            end  =W_GetNumForName("FJDOWN22");
+        }
+#endif
+
+        break;
+
+    case bladeobj:
+
+        SD_PreCacheSound(SD_BLADESPINSND);
+
+
+#if (SHAREWARE == 0)
+
+
+        if (which&2)
+        {
+            if (which&1)
+            {
+                start=W_GetNumForName("SPSTUP1");
+                end  =W_GetNumForName("SPSTUP16");
+            }
+            else
+            {
+                start=W_GetNumForName("SPSTDN1");
+                end  =W_GetNumForName("SPSTDN16");
+            }
+        }
+        else
+        {
+            if (which&1)
+            {
+                start=W_GetNumForName("UBLADE1");
+                end  =W_GetNumForName("UBLADE9");
+            }
+            else
+            {
+                start=W_GetNumForName("DBLADE1");
+                end  =W_GetNumForName("DBLADE9");
+            }
+        }
+#else
+        start=W_GetNumForName("UBLADE1");
+        end  =W_GetNumForName("UBLADE9");
+#endif
+
+        break;
+    case crushcolobj:
+
+        SD_PreCacheSound(SD_CYLINDERMOVESND);
+        if (which)
+        {
+            start=W_GetNumForName("CRDOWN1");
+            end  =W_GetNumForName("CRDOWN8");
+        }
+#if (SHAREWARE == 0)
+        else
+        {
+            start=W_GetNumForName("CRUP1");
+            end  =W_GetNumForName("CRUP8");
+        }
+#endif
+        break;
+
+    case boulderobj:
+        start=W_GetNumForName("BOL11");
+        end  =W_GetNumForName("BSINK9");
+        SD_PreCacheSound(SD_BOULDERHITSND);
+        SD_PreCacheSound(SD_BOULDERROLLSND);
+        SD_PreCacheSound(SD_BOULDERFALLSND);
+
+        break;
+
+    case spearobj:
+        SD_PreCacheSound(SD_SPEARSTABSND);
+
+        if (which)
+        {
+            start=W_GetNumForName("SPEARUP1");
+            end  =W_GetNumForName("SPERUP16");
+        }
+#if (SHAREWARE == 0)
+        else
+        {
+            start=W_GetNumForName("SPEARDN1");
+            end  =W_GetNumForName("SPERDN16");
+        }
+#endif
+
+        break;
+
+    case gasgrateobj:
+
+        start = SD_GASSTARTSND;
+        end = SD_GASMASKSND;
+        SD_PreCacheSoundGroup(start,end);
+        if ((locplayerstate->player == 1) || (locplayerstate->player == 3))
+            SD_PreCacheSound(SD_PLAYERCOUGHFSND);
+        else
+            SD_PreCacheSound(SD_PLAYERCOUGHMSND);
+        start=-1;
+        end=-1;
+        break;
+
+    case springobj:
+
+        SD_PreCacheSound(SD_SPRINGBOARDSND);
+
+        start=W_GetNumForName("SPRING1");
+        end  =W_GetNumForName("SPRING9");
+        break;
+    default:
+        return;
+        break;
+    }
+    if ((start>=0) && (end>=0))
+        PreCacheGroup(start,end,cache_patch_t);
+}
+
+
+
+/*
+======================
+=
+= MiscPreCache
+= precache the lump and check to see if it is already tagged
+=
+======================
+*/
+void MiscPreCache( void )
+{
+    int start;
+    int end;
+
+    //essential sounds
+
+    SD_PreCacheSoundGroup(SD_HITWALLSND,SD_PLAYERDWHURTSND);
+    SD_PreCacheSoundGroup(SD_RICOCHET1SND,SD_RICOCHET3SND);
+    SD_PreCacheSound(SD_ATKPISTOLSND);
+    SD_PreCacheSoundGroup(SD_PLAYERBURNEDSND,SD_PLAYERLANDSND);
+    SD_PreCacheSoundGroup(SD_EXPLODEFLOORSND,SD_EXPLODESND);
+
+    if (lightning==true)
+        SD_PreCacheSound(SD_LIGHTNINGSND);
+
+    SD_PreCacheSound(SD_BODYLANDSND);
+    SD_PreCacheSound(SD_GIBSPLASHSND);
+    SD_PreCacheSound(SD_ACTORLANDSND);
+    SD_PreCacheSound(SD_ACTORSQUISHSND);
+
+
+    // cache in bullet hole graphics
+    start=W_GetNumForName("BULLETHO");
+    end=W_GetNumForName("ALTBHO");
+    PreCacheGroup(start,end,cache_transpatch_t);
+
+
+    // cache in explosions
+
+    if (DoPanicMapping()==true)
+    {
+        start=W_GetNumForName("EXPLOS1");
+        end  =W_GetNumForName("EXPLOS20");
+        PreCacheGroup(start,end,cache_patch_t);
+    }
+    else
+    {
+        start=W_GetNumForName("EXPLOS1");
+        end  =W_GetNumForName("GREXP25");
+        PreCacheGroup(start,end,cache_patch_t);
+    }
+
+    // cache in misc player sprites
+    start=W_GetNumForName("BLOODS1");
+    end  =W_GetNumForName("PLATFRM5");
+    PreCacheGroup(start,end,cache_patch_t);
+
+    // cache in missile smoke
+    start=W_GetNumForName("MISSMO11");
+    end  =W_GetNumForName("MISSMO14");
+    PreCacheGroup(start,end,cache_patch_t);
+
+#if (DEVELOPMENT == 1)
+    // cache in all weapon sounds
+    SD_PreCacheSoundGroup(SD_ATKPISTOLSND,SD_LOSEMODESND);
+
+    // cache in misc player weapons
+#if (SHAREWARE == 0)
+    start=W_GetNumForName("KNIFE1");
+    end  =W_GetNumForName("DOGPAW4");
+    PreCacheGroup(start,end,cache_patch_t);
+    // cache in kinetic sphere
+    start=W_GetNumForName("KSPHERE1");
+    end  =W_GetNumForName("KSPHERE4");
+    PreCacheGroup(start,end,cache_patch_t);
+
+#else
+    start=W_GetNumForName("MPIST11");
+    end  =W_GetNumForName("GODHAND8");
+    PreCacheGroup(start,end,cache_patch_t);
+#endif
+
+
+    // cache in god mode stuff
+
+    PreCacheGroup(W_GetNumForName("VAPO1"),
+                  W_GetNumForName("LITSOUL"),
+                  cache_patch_t);
+
+    PreCacheGroup(W_GetNumForName("GODFIRE1"),
+                  W_GetNumForName("GODFIRE4"),
+                  cache_patch_t);
+
+
+#endif
+    // cache in player's gun
+
+    // cache in rubble
+    start=W_GetNumForName("RUBBLE1");
+    end  =W_GetNumForName("RUBBLE10");
+    PreCacheGroup(start,end,cache_patch_t);
+
+    // cache in guts
+    start=W_GetNumForName("GUTS1");
+    end  =W_GetNumForName("GUTS12");
+    PreCacheGroup(start,end,cache_patch_t);
+
+    // cache in player missile
+    start=W_GetNumForName("BJMISS1");
+    end  =W_GetNumForName("BJMISS16");
+    PreCacheGroup(start,end,cache_patch_t);
+
+    if (gamestate.violence >= vl_high)
+    {   // cache in all gibs
+        if (DoPanicMapping()==true)
+        {
+            start = W_GetNumForName("ORGAN1");
+            end = W_GetNumForName("ORGAN12");
+        }
+        else
+        {
+            start = W_GetNumForName("PART1");
+            end = W_GetNumForName("GEYE3");
+        }
+        PreCacheGroup(start,end,cache_patch_t);
+    }
+}
+
+
+/*
+========================
+=
+= IsChristmas
+=
+========================
+*/
+
+boolean IsChristmas(void)
+{
+    struct dosdate_t date;
+
+    _dos_getdate(&date);
+
+    if (((date.day == 24) || (date.day == 25)) &&      //Christmas
+            (date.month == 12)
+       )
+        return true;
+
+    return false;
+
+}
+
+
+/*
+========================
+=
+= CheckHolidays
+=
+========================
+*/
+
+void CheckHolidays(void)
+{
+    struct dosdate_t date;
+
+    _dos_getdate(&date);
+
+
+    if (IsChristmas())
+        DrawNormalSprite(0,0,W_GetNumForName("santahat"));
+
+    else if ((date.month == 5) && (date.day == 5))    // Cinco de Mayo
+        DrawNormalSprite(0,0,W_GetNumForName("sombrero"));
+
+    else if ((date.month == 7) && (date.day == 4))     // 4th of July
+        DrawNormalSprite(0,0,W_GetNumForName("amflag"));
+
+    else if ((date.month == 10) && (date.day == 31))    // Halloween
+        DrawNormalSprite(0,0,W_GetNumForName("witchhat"));
+
+    else if ((date.month == 4) && (date.dayofweek == 0))   //Easter
+    {
+        int i;
+
+        for(i=15; i<=21; i++)
+        {
+            if (date.day == i)
+                DrawNormalSprite(0,0,W_GetNumForName("esterhat"));
+        }
+    }
+}
+
+
+/*
+======================
+=
+= DrawPreCache
+=
+======================
+*/
+extern boolean dopefish;
+void DrawPreCache( void )
+{
+    if (loadedgame==false)
+    {
+        char temp[80];
+        int width, height, num;
+        char buf[30];
+
+        if ( BATTLEMODE )
+        {
+            VL_DrawPostPic (W_GetNumForName("trilogo"));
+            VWB_TBar ( 30, 23, 260, 82 );
+            ShowBattleOptions( false, 56, 26 );
+
+            DrawPlayers ();
+        }
+        else
+        {
+            pic_t * pic;
+            pic=(pic_t *)W_CacheLumpName("mmbk",PU_CACHE, Cvt_pic_t, 1);
+            VWB_DrawPic (0, 0, pic);
+
+            CheckHolidays();
+        }
+
+        DrawNormalSprite (PRECACHEBARX, PRECACHEBARY, W_GetNumForName ("cachebar"));
+
+        CurrentFont=smallfont;
+
+        PrintY = PRECACHEESTRINGY;
+        PrintX = PRECACHEESTRINGX;
+
+        memset (&buf[0], 0, sizeof (buf));
+
+        if ( !BATTLEMODE )
+        {
+            memcpy (&buf[0], "EPISODE ", 8);
+            itoa (gamestate.episode,&buf[8],10);
+        }
+        else
+            memcpy (&buf[0], "COMM-BAT", 8);
+
+        US_MeasureStr (&width, &height, "%s", &buf[0]);
+        VWB_TBar (PrintX-2, PrintY-2, width+4, height+4);
+        US_BufPrint (&buf[0]);
+
+
+        PrintY = PRECACHEASTRINGY;
+
+        memset (&buf[0], 0, sizeof (buf));
+        memcpy (&buf[0], "AREA ", 5);
+
+        if ( !BATTLEMODE )
+        {
+            itoa( GetLevel( gamestate.episode, gamestate.mapon ),
+                  &buf[ 5 ], 10 );
+        }
+        else
+        {
+            itoa( gamestate.mapon + 1, &buf[ 5 ], 10 );
+        }
+        US_MeasureStr (&width, &height, "%s", &buf[0]);
+        PrintX = (300-width);
+        VWB_TBar (PrintX-2, PrintY-2, width+4, height+4);
+        US_BufPrint (&buf[0]);
+
+
+        PrintY = PRECACHESTRINGY;
+
+        num = (RandomNumber ("PreCacheString", 0)) % MAXSILLYSTRINGS;
+
+        if ((dopefish==true) || (tedlevel == true))
+            strcpy (temp, &(CacheStrings[num][0]));
+        else
+            strcpy (temp, &(LevelName[0]));
+
+        US_MeasureStr (&width, &height, "%s", &temp[0]);
+
+        PrintX = (320-width) >> 1;
+        PrintY = PRECACHESTRINGY;
+        VWB_TBar (PrintX-2, PrintY-2, width+4, height+4);
+
+        US_BufPrint (&temp[0]);
+
+        VW_UpdateScreen();
+
+        MenuFadeIn ();
+    }
+}
+
+#define CACHETICDELAY (6)
+/*
+======================
+=
+= PreCache
+= precache all the lumps for the level
+=
+======================
+*/
+void PreCache( void )
+{
+    int i;
+    int total;
+    byte * dummy;
+    int maxheapsize;
+    int newheap;
+
+    int currentmem;
+    int currentcache;
+    int lastmem=0;
+    int lastcache=0;
+    int ticdelay;
+    byte *tempbuf;
+
+    double Gs;
+    Gs = (iGLOBAL_SCREENWIDTH*100/320);
+    Gs = Gs / 100;
+
+//SetTextMode (  );
+
+    /*
+    #define  PRECACHEBARX 28
+    #define  PRECACHEBARY 178
+
+    #define  PRECACHELED1X 9
+    #define  PRECACHELED1Y 8
+
+    #define  PRECACHELED2X 9
+    #define  PRECACHELED2Y 12
+    */
+
+    if (CachingStarted==false)
+    {
+        if (loadedgame==false)
+        {
+            ClearGraphicsScreen();
+            MenuFadeIn ();
+        }
+        return;
+    }
+
+    MiscPreCache();
+
+    SortPreCache();
+
+    if (loadedgame==false)
+    {
+        maxheapsize=Z_HeapSize();
+        total=0;
+
+        tempbuf=bufferofs;
+        bufferofs=page1start; // fixed, was displayofs
+        ticdelay=CACHETICDELAY;
+        for (i=1; i<cacheindex; i++)
+        {
+            dummy=W_CacheLumpNum(cachelist[i].lump,cachelist[i].cachelevel, CvtForType(cachelist[i].type), 1);
+            total+=W_LumpLength(cachelist[i].lump);
+            newheap=Z_UsedHeap();
+            currentmem=(newheap*MAXLEDS)/maxheapsize;
+            while (lastmem<=currentmem)
+            {   //SetTextMode (  );
+                if ( iGLOBAL_SCREENWIDTH == 320) {
+                    DrawNormalSprite (PRECACHEBARX+PRECACHELED1X+(lastmem<<2),
+                                      PRECACHEBARY+PRECACHELED1Y,
+                                      W_GetNumForName ("led1"));//led1 progressbar
+                } else if ( iGLOBAL_SCREENWIDTH == 640) {
+                    DrawNormalSprite (72+(Gs*(lastmem<<2)),446,W_GetNumForName ("led1"));//led1 progressbar
+                    DrawNormalSprite (72+(Gs*(lastmem<<2)),446+3,W_GetNumForName ("led1"));//led1 progressbar
+                    DrawNormalSprite (72+3+(Gs*(lastmem<<2)),446,W_GetNumForName ("led1"));//led1 progressbar
+                    DrawNormalSprite (72+3+(Gs*(lastmem<<2)),446+3,W_GetNumForName ("led1"));//led1 progressbar
+                } else if ( iGLOBAL_SCREENWIDTH == 800) {
+                    DrawNormalSprite (91+(Gs*(lastmem<<2)),559,W_GetNumForName ("led1"));//led1 progressbar
+                    DrawNormalSprite (91+(Gs*(lastmem<<2)),559+3,W_GetNumForName ("led1"));//led1 progressbar
+                    DrawNormalSprite (91+3+(Gs*(lastmem<<2)),559,W_GetNumForName ("led1"));//led1 progressbar
+                    DrawNormalSprite (91+3+(Gs*(lastmem<<2)),559+3,W_GetNumForName ("led1"));//led1 progressbar
+                }
+
+                lastmem++;
+                VW_UpdateScreen (); // was missing, fixed
+            }
+            currentcache=(i*MAXLEDS)/(cacheindex+1);
+            while (lastcache<=currentcache)
+            {
+
+                if ( iGLOBAL_SCREENWIDTH == 320) {
+                    DrawNormalSprite (PRECACHEBARX+PRECACHELED2X+(lastcache<<2),
+                                      PRECACHEBARY+PRECACHELED2Y,
+                                      W_GetNumForName ("led2"));//led2 progressbar
+                } else if ( iGLOBAL_SCREENWIDTH == 640) {
+                    DrawNormalSprite (72+(Gs*(lastcache<<2)),458,W_GetNumForName ("led2"));//led2 progressbar
+                    DrawNormalSprite (72+(Gs*(lastcache<<2)),458+3,W_GetNumForName ("led2"));//led2 progressbar
+                    DrawNormalSprite (72+3+(Gs*(lastcache<<2)),458,W_GetNumForName ("led2"));//led2 progressbar
+                    DrawNormalSprite (72+3+(Gs*(lastcache<<2)),458+3,W_GetNumForName ("led2"));//led2 progressbar
+
+                } else if ( iGLOBAL_SCREENWIDTH == 800) {
+                    DrawNormalSprite (91+(Gs*(lastcache<<2)),573,W_GetNumForName ("led2"));//led2 progressbar
+                    DrawNormalSprite (91+(Gs*(lastcache<<2)),573+3,W_GetNumForName ("led2"));//led2 progressbar
+                    DrawNormalSprite (91+3+(Gs*(lastcache<<2)),573,W_GetNumForName ("led2"));//led2 progressbar
+                    DrawNormalSprite (91+3+(Gs*(lastcache<<2)),573+3,W_GetNumForName ("led2"));//led2 progressbar
+                }
+                DisableScreenStretch();//bna++
+                VW_UpdateScreen ();//bna++
+                lastcache++;
+                ticdelay--;
+                if (ticdelay==0)
+                {
+                    extern boolean dopefish;
+
+                    if ( dopefish==true )
+                    {
+                        SD_PlayPitchedSound ( SD_DOPEFISHSND, 255, 0 );
+                    }
+                    ticdelay=CACHETICDELAY;
+                }
+                VW_UpdateScreen (); // was missing, fixed
+            }
+        }
+        DisableScreenStretch();//bna++
+        VW_UpdateScreen ();//bna++
+        //I_Delay(200);
+        bufferofs=tempbuf;
+        ShutdownPreCache ();
+
+        if ( BATTLEMODE )
+        {
+            int width,height;
+            char buf[30];//byte * shape;
+            double WHratio = 16200/200;
+            WHratio = WHratio/100;
+///	iGLOBAL_SCREENWIDTH = 640;
+//	iGLOBAL_SCREENHEIGHT = 480;
+            DisableScreenStretch();
+
+            // Cache in fonts
+//	shape = W_CacheLumpNum (W_GetNumForName ("newfnt1"), PU_STATIC, Cvt_font_t, 1);
+//	bigfont = (font_t *)shape;
+            CurrentFont = newfont1;//smallfont;
+
+            strcpy( buf, "Press Any Key" );
+            US_MeasureStr (&width, &height, "%s", &buf[ 0 ] );
+            PrintX = (iGLOBAL_SCREENWIDTH-(width)) / 2;
+            PrintY = WHratio*iGLOBAL_SCREENHEIGHT;//162;
+            //VWB_TBar (PrintX-2, PrintY-2, width+4, height+4);
+            US_BufPrint (&buf[0]);
+
+            VW_UpdateScreen();
+
+            IN_StartAck();
+            while (!IN_CheckAck ())
+                ;
+        }
+//  EnableScreenStretch();
+#if (DEVELOPMENT == 1)
+        tempbuf=bufferofs;
+        bufferofs=displayofs;
+        CurrentFont = smallfont;
+        US_CenterWindow(30,6);
+        PrintY+=6;
+        US_Print("Max  Heap Size:");
+        US_PrintUnsigned(maxheapsize);
+        US_Print("\n");
+        US_Print("Used Heap Size:");
+        US_PrintUnsigned(newheap);
+        US_Print("\n");
+        US_Print("Percentage Used:");
+        US_PrintUnsigned(newheap*100/maxheapsize);
+        US_Print("\n");
+        US_Print("TotalPrecached:");
+        US_PrintUnsigned(total);
+        bufferofs=tempbuf;
+        I_Delay (40);
+#endif
+#if (PRECACHETEST == 1)
+        SoftError("Max  Heap Size: %ld\n",maxheapsize);
+        SoftError("Used Heap Size: %ld\n",newheap);
+        SoftError("TotalPrecached: %ld\n",total);
+#endif
+    }
+    else
+    {
+        for (i=1; i<cacheindex; i++)
+        {
+            dummy=W_CacheLumpNum(cachelist[i].lump,cachelist[i].cachelevel, CvtForType(cachelist[i].type), 1);
+            DoLoadGameAction ();
+        }
+        ShutdownPreCache ();
+    }
+    if (CheckParm("LEVELSIZE")!=0)
+    {
+        OpenMapDebug();
+
+        MapDebug("Map Number %d\n",gamestate.mapon);
+        MapDebug("sizeoflevel=%d\n",Z_UsedLevelHeap());
+    }
+#if (PRECACHETEST == 1)
+    SoftError("<<<<<<<<<<<<<<<<<<<<<<<Precaching done\n");
+#endif
+}
+
+
+
+/*
+======================
+=
+= CA_RLEWexpand
+= length is EXPANDED length
+=
+======================
+*/
+
+void CA_RLEWexpand (word *source, word *dest,long length, unsigned rlewtag)
+{
+    word  value,count,i;
+    word          *end;
+
+    end = dest + length;
+    //
+    // expand it
+    //
+    do
+    {
+        value = IntelShort(*source++);
+        if (value != rlewtag)
+            //
+            // uncompressed
+            //
+            *dest++=value;
+        else
+        {
+            //
+            // compressed string
+            //
+            count = IntelShort(*source++);
+            value = IntelShort(*source++);
+            for (i=1; i<=count; i++)
+                *dest++ = value;
+        }
+    } while (dest<end);
+}
+
+/*
+======================
+=
+= CheckRTLVersion
+=
+======================
+*/
+
+void CheckRTLVersion
+(
+    char *filename
+)
+
+{
+    int  filehandle;
+    char RTLSignature[ 4 ];
+    unsigned int RTLVersion;
+
+    filehandle = SafeOpenRead( filename );
+
+    //
+    // Load RTL signature
+    //
+    SafeRead( filehandle, RTLSignature, sizeof( RTLSignature ) );
+
+    if ( ( strcmp( RTLSignature, COMMBAT_SIGNATURE ) != 0 ) &&
+            ( strcmp( RTLSignature, NORMAL_SIGNATURE ) != 0 ) )
+    {
+        Error( "The file '%s' is not a valid level file.", filename );
+    }
+
+    //
+    // Check the version number
+    //
+    SafeRead( filehandle, &RTLVersion, sizeof( RTLVersion ) );
+    SwapIntelLong(&RTLVersion);
+    if ( RTLVersion > RTL_VERSION )
+    {
+        Error(
+            "The file '%s' is a version %d.%d %s file.\n"
+            "The highest this version of ROTT can load is %d.%d.", filename,
+            RTLVersion >> 8, RTLVersion & 0xff, RTLSignature,
+            RTL_VERSION >> 8, RTL_VERSION & 0xff );
+    }
+
+    close( filehandle );
+}
+
+
+/*
+======================
+=
+= ReadROTTMap
+=
+======================
+*/
+
+void ReadROTTMap
+(
+    char *filename,
+    int mapnum
+)
+
+{
+    RTLMAP RTLMap;
+    int    filehandle;
+    long   pos;
+    long   compressed;
+    long   expanded;
+    int    plane;
+    byte  *buffer;
+
+    CheckRTLVersion( filename );
+    filehandle = SafeOpenRead( filename );
+
+    //
+    // Load map header
+    //
+    lseek( filehandle, RTL_HEADER_OFFSET + mapnum * sizeof( RTLMap ),
+           SEEK_SET );
+    SafeRead( filehandle, &RTLMap, sizeof( RTLMap ) );
+
+    SwapIntelLong((int *)&RTLMap.used);
+    SwapIntelLong((int *)&RTLMap.CRC);
+    SwapIntelLong((int *)&RTLMap.RLEWtag);
+    SwapIntelLong((int *)&RTLMap.MapSpecials);
+    SwapIntelLongArray((int *)&RTLMap.planestart, NUMPLANES);
+    SwapIntelLongArray((int *)&RTLMap.planelength, NUMPLANES);
+
+    if ( !RTLMap.used )
+    {
+        Error( "ReadROTTMap: Tried to load a non existent map!" );
+    }
+
+#if ( SHAREWARE == 1 )
+    if ( RTLMap.RLEWtag == REGISTERED_TAG )
+    {
+        Error( "Can't use maps from the registered game in shareware version." );
+    }
+
+    if ( RTLMap.RLEWtag != SHAREWARE_TAG )
+    {
+        Error( "Can't use modified maps in shareware version." );
+    }
+#endif
+
+    mapwidth  = 128;
+    mapheight = 128;
+
+    // Get special map flags
+    MapSpecials = RTLMap.MapSpecials;
+
+    //
+    // load the planes in
+    //
+    expanded = mapwidth * mapheight * 2;
+
+    for( plane = 0; plane <= 2; plane++ )
+    {
+        pos        = RTLMap.planestart[ plane ];
+        compressed = RTLMap.planelength[ plane ];
+        buffer     = SafeMalloc( compressed );
+        lseek( filehandle, pos, SEEK_SET );
+        SafeRead( filehandle, buffer, compressed );
+
+        mapplanes[ plane ] = Z_Malloc( expanded, PU_LEVEL, &mapplanes[ plane ] );
+
+        //
+        // unRLEW, skipping expanded length
+        //
+#if ( SHAREWARE == 1 )
+        CA_RLEWexpand( ( word * )buffer, ( word * )mapplanes[ plane ],
+                       expanded >> 1, SHAREWARE_TAG );
+#else
+        CA_RLEWexpand( ( word * )buffer, ( word * )mapplanes[ plane ],
+                       expanded >> 1, RTLMap.RLEWtag );
+#endif
+
+        SafeFree( buffer );
+    }
+    close(filehandle);
+
+    //
+    // get map name
+    //
+    strcpy( LevelName, RTLMap.Name );
+}
+
+
+
+/*
+======================
+=
+= GetNextMap
+=
+======================
+*/
+int GetNextMap ( int tilex, int tiley )
+{
+    word next;
+    word icon;
+    boolean done;
+
+    next = MAPSPOT( tilex, tiley, 2 );
+    icon = MAPSPOT( tilex, tiley, 1 );
+    done=false;
+    if ( ( ( icon != EXITTILE ) && ( icon != SECRETEXITTILE ) ) ||
+            ( ( ( next&0xff00 ) != 0xe200 ) && ( ( next&0xff00 ) != 0xe400 ) ) )
+    {
+        int i,j;
+
+        for ( j = 0; j < mapheight; j++ )
+        {
+            for ( i = 0; i < mapwidth; i++ )
+            {
+                icon = MAPSPOT( i, j, 1 );
+                next = MAPSPOT( i, j, 2 );
+                if ( ( ( icon == EXITTILE ) || ( icon == SECRETEXITTILE ) ) &&
+                        ( ( ( next&0xff00 ) == 0xe200 ) ||
+                          ( ( next&0xff00 ) == 0xe400 ) ) )
+                {
+                    done=true;
+                    break;
+                }
+            }
+
+            if ( done == true )
+            {
+                break;
+            }
+        }
+
+        if ( !done )
+        {
+            Error( "GetNextMap : No exit tile on map %d.", gamestate.mapon );
+        }
+    }
+    if ( ( ( next & 0xff00 ) != 0xe200 ) &&
+            ( ( next & 0xff00 ) != 0xe400 ) )
+    {
+        // Should this be DEVELOPMENT only?
+        Error( "GetNextMap : Illegal destination map %xh at exit "
+               "tile on map %d.", next, gamestate.mapon );
+    }
+
+    if ( next == 0xe2ff )
+    {
+        return -1;
+    }
+
+    return ( next & 0xff );
+}
+
+/*
+======================
+=
+= GetMapFileInfo
+=
+======================
+*/
+void GetMapFileInfo
+(
+    mapfileinfo_t *mapinfo,
+    char *filename
+)
+
+{
+    RTLMAP RTLMap[ 100 ];
+    int    filehandle;
+    int    i;
+    int    nummaps;
+
+    CheckRTLVersion( filename );
+
+    filehandle = SafeOpenRead( filename );
+
+    //
+    // Load map header
+    //
+    lseek( filehandle, RTL_HEADER_OFFSET, SEEK_SET );
+    SafeRead( filehandle, &RTLMap, sizeof( RTLMap ) );
+    close( filehandle );
+
+    nummaps = 0;
+    for( i = 0; i < 100; i++ )
+    {
+        if ( !RTLMap[ i ].used )
+        {
+            continue;
+        }
+
+        mapinfo->maps[ nummaps ].number = i;
+
+        strcpy( mapinfo->maps[ nummaps ].mapname, RTLMap[ i ].Name );
+
+        nummaps++;
+    }
+
+    mapinfo->nummaps = nummaps;
+}
+
+/*
+======================
+=
+= GetMapFileName
+=
+======================
+*/
+void GetMapFileName ( char * filename )
+{
+    if ( ( BATTLEMODE ) && (BattleLevels.avail == true) )
+    {
+        strcpy(filename,BattleLevels.file);
+    }
+    else if (GameLevels.avail == true)
+    {
+        strcpy(filename,GameLevels.file);
+    }
+    else if ( BATTLEMODE )
+    {
+        strcpy(filename,BATTMAPS);
+    }
+    else
+    {
+        strcpy(filename,ROTTMAPS);
+    }
+}
+
+/*
+======================
+=
+= SetBattleMapFileName
+=
+======================
+*/
+void SetBattleMapFileName ( char * filename )
+{
+    BattleLevels.avail = true;
+    BattleLevels.file = strdup(filename);
+}
+
+/*
+======================
+=
+= GetMapCRC
+=
+======================
+*/
+word GetMapCRC
+(
+    int num
+)
+
+{
+    int  filehandle;
+    char filename[ 80 ];
+    RTLMAP RTLMap;
+
+    GetMapFileName( &filename[ 0 ] );
+    CheckRTLVersion( filename );
+    filehandle = SafeOpenRead( filename );
+
+    //
+    // Load map header
+    //
+    lseek( filehandle, RTL_HEADER_OFFSET + num * sizeof( RTLMap ), SEEK_SET );
+    SafeRead( filehandle, &RTLMap, sizeof( RTLMap ) );
+
+    close( filehandle );
+
+    return( RTLMap.CRC );
+}
+
+
+/*
+======================
+=
+= GetAlternateMapInfo
+=
+======================
+*/
+
+void GetAlternateMapInfo (mapfileinfo_t * mapinfo, AlternateInformation *info)
+{
+    if (UL_ChangeDirectory (info->path) == false)
+        Error ("ERROR : Can't change to alternate directory %s!\n", info->path);
+
+    GetMapFileInfo (mapinfo, info->file);
+
+    UL_ChangeDirectory (&CWD[0]);
+}
+
+/*
+======================
+=
+= GetMapInfo
+=
+======================
+*/
+void GetMapInfo
+(
+    mapfileinfo_t *mapinfo
+)
+
+{
+    if ( ( BATTLEMODE ) && ( BattleLevels.avail == true ) )
+    {
+        GetAlternateMapInfo( mapinfo, &BattleLevels );
+    }
+    else if ( GameLevels.avail == true )
+    {
+        GetAlternateMapInfo( mapinfo, &GameLevels );
+    }
+    else if ( BATTLEMODE )
+    {
+        GetMapFileInfo( mapinfo, BATTMAPS );
+    }
+    else
+    {
+        GetMapFileInfo( mapinfo, ROTTMAPS );
+    }
+}
+
+/*
+======================
+=
+= LoadTedMap
+=
+======================
+*/
+void LoadTedMap
+(
+    const char *extension,
+    int mapnum
+)
+
+{
+    long    pos;
+    long    compressed;
+    long    expanded;
+    int     plane;
+    int     i;
+    int     maphandle;
+    byte   *buffer;
+    maptype mapheader;
+    char    name[ 200 ];
+    mapfiletype *tinf;
+
+    //
+    // load maphead.ext (offsets and tileinfo for map file)
+    //
+    strcpy( name, "maphead." );
+    strcat( name, extension );
+    LoadFile( name, ( void * )&tinf );
+
+    // fix structure alignment
+    tinf = ( void * )( ( word * )tinf - 1 );
+
+    for( i = 0 ; i < 100 ; i++ )
+    {
+        tinf->headeroffsets[ i ] = IntelLong( tinf->headeroffsets[ i ] );
+    }
+
+    //
+    // open the data file
+    //
+    strcpy( name, "maptemp." );
+    strcat( name, extension );
+    maphandle = SafeOpenRead( name );
+
+    //
+    // load map header
+    //
+    pos = tinf->headeroffsets[ mapnum ];
+
+    // $FFFFFFFF start is a sparse map
+    if ( pos < 0 )
+    {
+        Error( "LoadTedMap : Tried to load a non existent map!" );
+    }
+
+    lseek( maphandle, pos, SEEK_SET );
+    SafeRead( maphandle, &mapheader, sizeof( maptype ) );
+
+    for( i = 0 ; i < 3; i++ )
+    {
+        mapheader.planestart[ i ]  = IntelLong( mapheader.planestart[ i ] );
+        mapheader.planelength[ i ] = IntelShort( mapheader.planelength[ i ] );
+    }
+
+    mapheader.width  = IntelShort( mapheader.width );
+    mapheader.height = IntelShort( mapheader.height );
+
+    mapwidth  = mapheader.width;
+    mapheight = mapheader.height;
+
+    // Set special map flags
+    MapSpecials = 0;
+
+    //
+    // load the planes in
+    //
+    expanded = mapheader.width * mapheader.height * 2;
+
+    for( plane = 0; plane <= 2; plane++ )
+    {
+        pos = mapheader.planestart[ plane ];
+        lseek( maphandle, pos, SEEK_SET );
+
+        compressed = mapheader.planelength[ plane ];
+        buffer = SafeMalloc( compressed );
+        SafeRead( maphandle, buffer, compressed );
+
+        mapplanes[ plane ] = Z_Malloc( expanded, PU_LEVEL, &mapplanes[ plane ] );
+
+        //
+        // unRLEW, skipping expanded length
+        //
+        CA_RLEWexpand( ( word * )( buffer + 2 ), ( word * )mapplanes[ plane ],
+                       expanded >> 1, 0xabcd );
+
+        SafeFree( buffer );
+    }
+
+    // fix structure alignment
+    tinf = ( void * )( ( word * )tinf + 1 );
+
+    SafeFree( tinf );
+
+    if ( close( maphandle ) )
+    {
+        Error( "Error closing Ted file Error #%d", errno );
+    }
+}
+
+
+/*
+======================
+=
+= LoadAlternateMap
+=
+======================
+*/
+
+void LoadAlternateMap (AlternateInformation *info, int mapnum)
+{
+    if (UL_ChangeDirectory (info->path) == false)
+        Error ("ERROR : Can't change to alternate directory %s!\n",info->path);
+
+    ReadROTTMap (info->file, mapnum);
+
+    UL_ChangeDirectory (&CWD[0]);
+}
+
+/*
+======================
+=
+= LoadROTTMap
+=
+======================
+*/
+void LoadROTTMap
+(
+    int mapnum
+)
+
+{
+    if ( tedlevel == true )
+    {
+        LoadTedMap( "rot", mapnum );
+    }
+    else if ( ( BATTLEMODE ) && ( BattleLevels.avail == true ) )
+    {
+        LoadAlternateMap( &BattleLevels, mapnum );
+    }
+    else if ( GameLevels.avail == true )
+    {
+        LoadAlternateMap( &GameLevels, mapnum );
+    }
+    else if ( BATTLEMODE )
+    {
+        ReadROTTMap( BATTMAPS, mapnum );
+    }
+    else
+    {
+        ReadROTTMap( ROTTMAPS, mapnum );
+    }
+}
+
+
+void CountAreaTiles(void)
+{   int i,j,areanumber;
+    word*map,tile;
+
+    memset(numareatiles,0,sizeof(numareatiles));
+    map  = mapplanes[0];
+
+    for(i=0; i<MAPSIZE; i++)
+        for(j=0; j<MAPSIZE; j++)
+        {   tile = *map++;
+
+            areanumber = tile - AREATILE;
+            if ((areanumber >= 0) && (areanumber <= NUMAREAS))
+                numareatiles[areanumber] ++;
+        }
+
+}
+
+
+
+#define InitWall(lump,index,newx,newy)      \
+   {                                        \
+   PreCacheLump(lump,PU_CACHEWALLS,cache_pic_t);  \
+   if (W_LumpLength(lump) == 0)                   \
+      Error("%s being used in shareware at %d %d",\
+      W_GetNameForNum(lump),newx,newy);           \
+   actorat[newx][newy]= &walls[index];      \
+   tempwall = (wall_t*)actorat[newx][newy]; \
+   tempwall->which = WALL;                  \
+   tempwall->tile = index;                  \
+   }                                        \
+
+
+/*
+==================
+=
+= SetupWalls
+=
+==================
+*/
+void SetupWalls( void )
+{
+    int   i,j,lump,index;
+    word   *map,tile;
+    wall_t * tempwall;
+
+
+    for (i=0; i<MAXWALLTILES; i++)
+        memset(&walls[i],0,sizeof(wall_t));
+
+    map = mapplanes[0];
+    for (j=0; j<mapheight; j++)
+    {
+        for(i=0; i<mapwidth; i++)
+        {
+            if ((i>=0) && (i<=3) && (j==0))
+            {
+                map++;
+                continue;
+            }
+            if ((loadedgame == false) && (MAPSPOT(i,j,2) == 0xeeee))
+            {   _2Dpoint *tdptr;
+
+                tdptr = &(MISCVARS->EPOP[MISCVARS->nextpop]);
+                tdptr->x = i;
+                tdptr->y = j;
+                MISCVARS->nextpop ++;
+                MISCVARS->popsleft ++;
+            }
+            tile= *map++;
+
+            if ((tile > 89) ||
+                    ((tile > 32) && (tile < 36)) ||
+                    (tile == 44) ||
+                    (tile == 45) ||
+                    (tile == 0)
+               )
+            {
+                tilemap[i][j] = 0;
+                continue;
+            }
+
+            if (tile <= 32)
+            {
+                index = tile;
+#if 0
+                if (tile==12)
+                {
+                    if (MAPSPOT(i,j,2)==0)
+                        MAPSPOT(i,j,2)=21;
+                }
+#endif
+            }
+            else
+                index = tile-3;
+
+            if ((tile > 75) && (tile <= 79))
+            {
+                lump = tilemap[i][j] = GetLumpForTile(tile);
+                PreCacheLump(lump,PU_CACHEWALLS,cache_pic_t);
+                PreCacheLump(elevatorstart+5,PU_CACHEWALLS,cache_pic_t);
+                PreCacheLump(elevatorstart+6,PU_CACHEWALLS,cache_pic_t);
+                PreCacheLump(elevatorstart+7,PU_CACHEWALLS,cache_pic_t);
+                tilemap[i][j]|=0x2000;
+                if (MAPSPOT(i,j,2)==0)
+                    MAPSPOT(i,j,2)=21;
+            }
+            else if ((tile >= 47) && (tile <= 48))
+            {
+                lump = tilemap[i][j] = GetLumpForTile(tile);
+                InitWall(lump,index,i,j);
+                tilemap[i][j]|=0x2000;
+                if (MAPSPOT(i,j,2)==0)
+                    MAPSPOT(i,j,2)=21;
+            }
+            else
+            {
+                lump = tilemap[i][j] = GetLumpForTile(tile);
+                InitWall(lump,index,i,j);
+                if (MAPSPOT(i,j,2))
+                    tilemap[i][j]|=0x2000;
+            }
+        }
+    }
+}
+
+
+/*
+===============
+=
+= GetNearestAreaNumber
+=
+===============
+*/
+word GetNearestAreaNumber ( int tilex, int tiley )
+{
+    int up,dn,lt,rt;
+    int tile;
+
+    tile=MAPSPOT(tilex,tiley,0)-AREATILE;
+
+    if ((tile<=NUMAREAS) && (tile>0))
+        return (tile+AREATILE);
+
+    up=MAPSPOT(tilex,tiley-1,0)-AREATILE;
+    dn=MAPSPOT(tilex,tiley+1,0)-AREATILE;
+    lt=MAPSPOT(tilex-1,tiley,0)-AREATILE;
+    rt=MAPSPOT(tilex+1,tiley,0)-AREATILE;
+
+    up = ((up>0) && (up<=NUMAREAS));
+    dn = ((dn>0) && (dn<=NUMAREAS));
+    lt = ((lt>0) && (lt<=NUMAREAS));
+    rt = ((rt>0) && (rt<=NUMAREAS));
+
+    if (rt)
+        return (MAPSPOT(tilex+1,tiley,0) + AREATILE);
+    else if (lt)
+        return (MAPSPOT(tilex-1,tiley,0) + AREATILE);
+    else if (up)
+        return (MAPSPOT(tilex,tiley-1,0) + AREATILE);
+    else if (dn)
+        return (MAPSPOT(tilex,tiley+1,0) + AREATILE);
+//	else
+//		Error("GetNearestAreaNumber: Couldn't fix up area at x=%ld y=%ld\n",tilex,tiley);
+    return (NUMAREAS+AREATILE-1);
+}
+
+/*
+===============
+=
+= SetupWindows
+=
+===============
+*/
+void SetupWindows ( void )
+{
+    int i,j;
+    boolean skythere;
+
+    skythere = SkyExists();
+
+    for (j=0; j<mapheight; j++)
+    {
+        for(i=0; i<mapwidth; i++)
+        {
+            if ((i>=0) && (i<=3) && (j==0))
+                continue;
+            if (IsWindow(i,j))
+            {
+                actorat[i][j]=0;
+                if (skythere==true)
+                {
+                    tilemap[i][j]|=0x2000;
+                }
+                else
+                {
+                    MAPSPOT(i,j,2)=0;
+                }
+                MAPSPOT(i,j,0)=(word)(GetNearestAreaNumber(i,j));
+            }
+        }
+    }
+
+}
+
+
+/*
+==================
+=
+= GetWallIndex
+=
+==================
+*/
+
+int GetWallIndex( int texture )
+{
+    int wallstart;
+    int exitstart;
+
+    wallstart=W_GetNumForName("WALLSTRT");
+    exitstart=W_GetNumForName("EXITSTRT");
+    elevatorstart = W_GetNumForName("ELEVSTRT");
+
+    if (texture&0x1000)
+    {
+        texture&=~0x1000;
+        if (texture==0)
+            return 41;
+        else if (texture==1)
+            return 90;
+        else if (texture==2)
+            return 91;
+        else if (texture==3)
+            return 42;
+        else if (texture==4)
+            return 92;
+        else if (texture==5)
+            return 93;
+        else if (texture==6)
+            return 94;
+        else if (texture==7)
+            return 95;
+        else if (texture==8)
+            return 96;
+        else if (texture==9)
+            return 97;
+        else if (texture==10)
+            return 98;
+        else if (texture==11)
+            return 99;
+        else if (texture==12)
+            return 100;
+        else if (texture==13)
+            return 101;
+        else if (texture==14)
+            return 102;
+        else if (texture==15)
+            return 103;
+        else if (texture==16)
+            return 104;
+    }
+    else if (texture > elevatorstart)
+        return (texture - elevatorstart + 68);
+//	else if (texture > specialstart)
+//      return (texture - specialstart + 41);
+    else if (texture > exitstart)
+        return (texture - exitstart + 43);
+    else
+    {
+        if (texture>wallstart+63)
+            return (texture - (wallstart + 63) + 76 );
+        else if (texture>wallstart+40)
+            return (texture - (wallstart + 40) + 45 );
+        else
+            return (texture - wallstart);
+    }
+    return 0x8000;
+}
+
+/*
+==================
+=
+= SetupAnimatedWalls
+=
+==================
+*/
+void SetupAnimatedWalls( void )
+{
+    int   i,j;
+    word   *map,tile;
+    wall_t * tempwall;
+
+    InitAnimatedWallList();
+    map = mapplanes[0];
+    for (j=0; j<mapheight; j++)
+    {
+        for(i=0; i<mapwidth; i++)
+        {
+            if ((i>=0) && (i<=3) && (j==0))
+            {
+                map++;
+                continue;
+            }
+            tile= *map++;
+            if (tile == 44)
+            {
+                actorat[i][j]= &walls[tile-3];
+                tempwall = (wall_t*)actorat[i][j];
+                tempwall->which = WALL;
+                tempwall->tile = tile-3;
+                tempwall->flags = FL_W_DAMAGE;
+                SetupAnimatedWall(0);
+                tilemap[i][j]=0;
+                tilemap[i][j]|=0x1000;
+            }
+            else if (tile == 45)
+            {
+                actorat[i][j]= &walls[tile-3];
+                tempwall = (wall_t*)actorat[i][j];
+                tempwall->which = WALL;
+                tempwall->tile = tile-3;
+                SetupAnimatedWall(3);
+                tilemap[i][j]=3;
+                tilemap[i][j]|=0x1000;
+            }
+            else if ((tile >= 106) && (tile <= 107))
+            {
+                actorat[i][j]= &walls[tile-16];
+                tempwall = (wall_t*)actorat[i][j];
+                tempwall->which = WALL;
+                tempwall->tile = tile-16;
+                SetupAnimatedWall(tile-105);
+                tilemap[i][j]=tile-105;
+                tilemap[i][j]|=0x1000;
+            }
+            else if ((tile >= 224) && (tile <= 233))
+            {
+                actorat[i][j]= &walls[tile-224+92];
+                tempwall = (wall_t*)actorat[i][j];
+                tempwall->which = WALL;
+                tempwall->tile = tile-224+94;
+                if (tile==233)
+                    tempwall->flags = FL_W_DAMAGE;
+                SetupAnimatedWall(tile-224+4);
+                tilemap[i][j]=tile-224+4;
+                tilemap[i][j]|=0x1000;
+            }
+            else if ((tile >= 242) && (tile <= 244))
+            {
+                actorat[i][j]= &walls[tile-242+102];
+                tempwall = (wall_t*)actorat[i][j];
+                tempwall->which = WALL;
+                tempwall->tile = tile-242+102;
+                SetupAnimatedWall(tile-242+14);
+                tilemap[i][j]=tile-242+14;
+                tilemap[i][j]|=0x1000;
+            }
+        }
+    }
+}
+
+
+/*
+==================
+=
+= SetupSwitches
+=
+==================
+*/
+
+void SetupSwitches( void )
+{
+    int   i,j;
+    word   *map,tile;
+
+    map = mapplanes[0];
+    for (j=0; j<mapheight; j++)
+    {
+        for(i=0; i<mapwidth; i++)
+        {
+            if ((i>=0) && (i<=3) && (j==0))
+            {
+                map++;
+                continue;
+            }
+            tile= *map++;
+            if ((tile >= 76) && (tile <= 79))
+            {
+                if (tile == 79)
+                    lastswitch->flags |= FL_ON;
+                SpawnSwitchThingy(i,j);
+            }
+            else if ((tile == 157) || (tile == 175)) // hi masked switches
+            {
+                lastswitch->flags |= FL_W_INVERTED;
+                lastswitch->flags |= FL_REVERSIBLE;
+                if (tile==175)
+                    lastswitch->flags |= FL_ON;
+                SpawnSwitchThingy(i,j);
+            }
+        }
+    }
+}
+
+
+
+void RespawnPlayerobj(objtype *ob)
+{   int rand,numchecked=0;
+    int oldsetupgame,nx,ny,ndir;
+    playertype *pstate;
+
+    M_LINKSTATE(ob,pstate);
+
+    if (gamestate.battlemode != battle_CaptureTheTriad)
+    {
+        rand = (GameRandomNumber("playerobj respawn",0) % NUMSPAWNLOCATIONS);
+
+        while(numchecked < NUMSPAWNLOCATIONS)
+        {
+            if (!actorat[SPAWNLOC[rand].x][SPAWNLOC[rand].y])
+            {   RevivePlayerobj(SPAWNLOC[rand].x,SPAWNLOC[rand].y,SPAWNLOC[rand].dir,ob);
+                return;
+            }
+            numchecked ++;
+            rand = (rand + 1) % NUMSPAWNLOCATIONS;
+        }
+#if (DEVELOPMENT == 1)
+        SoftError("\nno spawn locations available, using FindEmptyTile");
+#endif
+        nx = SPAWNLOC[rand].x;
+        ny = SPAWNLOC[rand].y;
+        ndir = SPAWNLOC[rand].dir;
+    }
+    else
+    {   nx = TEAM[pstate->team].tilex;
+        ny = TEAM[pstate->team].tiley;
+        ndir = TEAM[pstate->team].dir;
+    }
+
+    oldsetupgame = insetupgame;
+    insetupgame = true;
+    FindEmptyTile(&nx,&ny);
+    insetupgame = oldsetupgame;
+    RevivePlayerobj(nx,ny,ndir,ob);
+
+
+}
+
+#define SetupSpecificFlagTeamAt(whichteam, spawnlocindex) \
+{int newx,newy;                                           \
+                                                          \
+ newx = SPAWNLOC[spawnlocindex].x;                        \
+ newy = SPAWNLOC[spawnlocindex].y;                        \
+ TEAM[whichteam].tilex = newx;                            \
+ TEAM[whichteam].tiley = newy;                            \
+ TEAM[whichteam].dir = SPAWNLOC[spawnlocindex].x;         \
+ SpawnStatic(newx,newy,stat_collector,9);                  \
+ SpawnNewObj(newx,newy,&s_basemarker1,inertobj);          \
+ LASTACTOR->z = LASTSTAT->z;                              \
+ LASTSTAT->flags |= FL_COLORED;                           \
+ LASTSTAT->hitpoints = whichteam;                         \
+ locspawned[spawnlocindex]=1;                             \
+ for(j=0;j<numplayers;j++)                                \
+    {if (PLAYERSTATE[j].uniformcolor !=                   \
+         TEAM[whichteam].uniformcolor)                    \
+        continue;                                         \
+                                                          \
+     ntilex = newx;                                       \
+     ntiley = newy;                                       \
+     FindEmptyTile(&ntilex,&ntiley);                      \
+     SpawnPlayerobj(ntilex,ntiley,dir,j);                 \
+    }                                                     \
+}                                                         \
+
+
+/*
+=============
+=
+= AssignTeams called from SetGameDescription in rt_net.c
+=
+=============
+*/
+
+void AssignTeams(void)
+{   int i,color;
+    int teamforcolor[MAXPLAYERCOLORS];
+
+    numteams = 0;
+    if (!gamestate.teamplay)
+        return;
+
+    memset(teamforcolor,-1,sizeof(teamforcolor));
+    memset(TEAM,0,sizeof(TEAM));
+
+    for(i=0; i<numplayers; i++)
+    {   color = PLAYERSTATE[i].uniformcolor;
+        if (teamforcolor[color] == -1)
+        {   TEAM[numteams].uniformcolor = color;
+
+            TEAM[numteams].nummembers ++;
+            teamforcolor[color] = numteams;
+            numteams++;
+            if ((gamestate.battlemode == battle_CaptureTheTriad) &&
+                    (numteams > 2))
+                Error("players selected more colors(%d) than Capture the Triad allows",numteams);
+        }
+        else
+            TEAM[teamforcolor[color]].nummembers ++;
+
+        PLAYERSTATE[i].team = teamforcolor[color];
+
+    }
+
+}
+
+
+
+/*
+=============
+=
+= SetupTeams
+=
+=============
+*/
+
+
+void SetupTeams(void)
+{
+
+    int i,j,rand,sx,sy,ntilex,ntiley,dir,
+        maxdist,currdist,spawnindex,cnt;
+    int locspawned[MAXSPAWNLOCATIONS] = {0};
+
+    if (gamestate.battlemode == battle_CaptureTheTriad)
+    {   rand = (GameRandomNumber("net player spawn",0) % NUMSPAWNLOCATIONS);
+
+        for(i=0; i<NUMSPAWNLOCATIONS; i++)
+        {   sx = SPAWNLOC[rand].x;
+            sy = SPAWNLOC[rand].y;
+            dir = SPAWNLOC[rand].dir;
+
+            if (CheckTile(sx,sy) && (!IsPlatform(sx,sy)) &&
+                    (Number_of_Empty_Tiles_In_Area_Around(sx,sy) > TEAM[0].nummembers)
+               )
+            {   SetupSpecificFlagTeamAt(0,rand);
+                break;
+            }
+
+            rand = (rand + 1)%NUMSPAWNLOCATIONS;
+        }
+
+        if (i == NUMSPAWNLOCATIONS)
+            Error("No spawn location available for team 0, capture the flag");
+
+        maxdist = 0x80000000;
+        for(i=0; i<NUMSPAWNLOCATIONS; i++)
+        {   if (locspawned[i])
+                continue;
+
+            sx = SPAWNLOC[i].x;
+            sy = SPAWNLOC[i].y;
+            dir = SPAWNLOC[i].dir;
+
+            if ((Number_of_Empty_Tiles_In_Area_Around(sx,sy) < TEAM[1].nummembers)
+                    || (!CheckTile(sx,sy) || IsPlatform(sx,sy))
+               )
+                continue;
+
+            currdist = FindDistance(sx-TEAM[0].tilex,sy-TEAM[0].tiley);
+            if (currdist > maxdist)
+            {   maxdist = currdist;
+                spawnindex = i;
+            }
+        }
+
+        SetupSpecificFlagTeamAt(1,spawnindex);
+    }
+    else
+    {
+        int badcount = 0,teamindex;
+
+        if (numteams > NUMSPAWNLOCATIONS)
+            Error("More teams than spawn locations !");
+        //cnt =0;
+        //for(rand = 0;rand < NUMSPAWNLOCATIONS;rand++)
+        for(cnt=0; cnt<numteams;)
+        {
+            rand = (GameRandomNumber("team spawn",0) % NUMSPAWNLOCATIONS);
+
+            if (locspawned[rand])
+                continue;
+
+
+            sx = SPAWNLOC[rand].x;
+            sy = SPAWNLOC[rand].y;
+            dir = SPAWNLOC[rand].dir;
+
+            if (Number_of_Empty_Tiles_In_Area_Around(sx,sy) < TEAM[cnt].nummembers)
+            {
+                badcount ++;
+                if (badcount == (NUMSPAWNLOCATIONS - cnt))
+                    Error("\n%s team cannot spawn in this level",colorname[TEAM[cnt].uniformcolor]);
+                continue;
+            }
+
+            badcount = 0;
+            //Debug("\n\nSpawn Location %d",rand);
+            //Debug("\n-----------------");
+            TEAM[cnt].tilex = sx;
+            TEAM[cnt].tiley = sy;
+            TEAM[cnt].dir = dir;
+            locspawned[rand]=1;
+            cnt++;
+
+        }
+
+        for(j=0; j<numplayers; j++)
+        {
+            teamindex = PLAYERSTATE[j].team;
+
+            sx = TEAM[teamindex].tilex;
+            sy = TEAM[teamindex].tiley;
+            dir = TEAM[teamindex].dir;
+
+            FindEmptyTile(&sx,&sy);
+
+            //Debug("\n x: %3d, y: %3d",sx,sy);
+            SpawnPlayerobj(sx,sy,dir,j);
+        }
+
+
+    }
+
+
+
+
+//numplayers = 1;
+//Error("Okay");
+#if ((DEVELOPMENT == 1))
+#if (TEAMTEST == 1)
+
+    Debug("Team Spawn Location\n");
+    Debug("-------------------\n");
+    for(i=0; i<numteams; i++)
+        Debug("%d   %3d,%3d\n",i,TEAM[i].tilex,TEAM[i].tiley);
+
+
+    Debug("Player            Team          Location\n");
+    Debug("------            ----          --------\n");
+    for(i=0; i<numplayers; i++)
+        Debug("  %d             %d            %3d,%3d\n",i,PLAYERSTATE[i].team,PLAYER[i]->tilex,PLAYER[i]->tiley);
+
+//  Error("done");
+#endif
+#endif
+
+}
+
+
+/*
+==================
+=
+= SetupPlayers
+=
+==================
+*/
+
+void SetupPlayers( void )
+{
+    int   i,j;
+    word   *map,tile;
+
+    //START in icon plane = 10
+
+    map = mapplanes[1];
+    for(j=0; j<mapheight; j++)
+        for(i=0; i<mapwidth; i++)
+        {
+            tile = *map++;
+            switch (tile)
+            {
+            case 19:
+            case 20:
+            case 21:
+            case 22:
+                FIRST.x = i;
+                FIRST.y = j;
+                FIRST.dir = tile-19;
+                SPAWNLOC[NUMSPAWNLOCATIONS].x  = i;
+                SPAWNLOC[NUMSPAWNLOCATIONS].y  = j;
+                SPAWNLOC[NUMSPAWNLOCATIONS].dir  = tile-19;
+                if (NUMSPAWNLOCATIONS<MAXSPAWNLOCATIONS)
+                    NUMSPAWNLOCATIONS ++;
+                break;
+
+            case 274:
+            case 275:
+            case 276:
+            case 277:
+                SPAWNLOC[NUMSPAWNLOCATIONS].x  = i;
+                SPAWNLOC[NUMSPAWNLOCATIONS].y  = j;
+                SPAWNLOC[NUMSPAWNLOCATIONS].dir  = tile-274;
+                if (NUMSPAWNLOCATIONS<MAXSPAWNLOCATIONS)
+                    NUMSPAWNLOCATIONS ++;
+                break;
+            }
+
+        }
+
+    if ( NUMSPAWNLOCATIONS <= 0 )
+    {
+        Error( "No spawn locations found on map." );
+    }
+
+    /*modemgame=true;
+    gamestate.teamplay = true;
+    PLAYERSTATE[0].uniformcolor = 2;
+    PLAYERSTATE[1].uniformcolor = 2;
+    numplayers = 2;
+    AssignTeams();*/
+
+    if (!BATTLEMODE)
+    {
+        if (tedlevel)
+        {
+            if ((tedx==0) || (tedy == 0))
+                SpawnPlayerobj (FIRST.x, FIRST.y, FIRST.dir,0);
+            else
+                SpawnPlayerobj(tedx,tedy,FIRST.dir,0);
+        }
+        else
+            SpawnPlayerobj(FIRST.x,FIRST.y,FIRST.dir,0);
+    }
+
+    else if (gamestate.teamplay == true)
+        SetupTeams();
+
+    else
+    {
+        int rand,cnt,locspawned[MAXSPAWNLOCATIONS]= {0};
+        int locsleft;
+
+        locsleft=NUMSPAWNLOCATIONS;
+        for(cnt=0; cnt<numplayers;)
+        {   rand = (GameRandomNumber("net player spawn",0) % NUMSPAWNLOCATIONS);
+            if (locsleft==0)
+            {
+                int x,y;
+
+                x=SPAWNLOC[rand].x;
+                y=SPAWNLOC[rand].y;
+                FindEmptyTile(&x,&y);
+                SpawnPlayerobj(x,y,SPAWNLOC[rand].dir,cnt);
+                cnt++;
+            }
+            else if (!locspawned[rand])
+            {   SpawnPlayerobj(SPAWNLOC[rand].x,SPAWNLOC[rand].y,SPAWNLOC[rand].dir,cnt);
+                locspawned[rand]=1;
+                locsleft--;
+                cnt++;
+            }
+        }
+    }
+
+    if (gamestate.battlemode == battle_Tag)
+    {   int i;
+        playertype *pstate;
+
+        BATTLE_It = GameRandomNumber("tag choose",0) % numplayers;
+
+        PLAYER[BATTLE_It]->flags |= FL_DESIGNATED;
+        for(i=0; i<numplayers; i++)
+        {   M_LINKSTATE(PLAYER[i],pstate);
+
+            if (i == BATTLE_It)
+            {   pstate->missileweapon = pstate->oldweapon = pstate->new_weapon =
+                                            pstate->oldmissileweapon = pstate->weapon = wp_godhand;
+                pstate->bulletweapon = -1;
+            }
+            else
+            {   pstate->missileweapon = pstate->oldweapon = pstate->new_weapon =
+                                            pstate->oldmissileweapon = pstate->bulletweapon = pstate->weapon = -1;
+            }
+        }
+    }
+
+    PreCachePlayers();
+}
+
+
+
+/*
+==================
+=
+= SetupMaskedWalls
+=
+==================
+*/
+
+void SetupMaskedWalls( void )
+{
+    int   i,j;
+    word   *map,tile;
+
+    map = mapplanes[0];
+    for (j=0; j<mapheight; j++)
+    {
+        for(i=0; i<mapwidth; i++)
+        {
+            tile = *map++;
+            if ((tile >= 158) && (tile <= 160)) // Multi glassed walls
+            {
+                SpawnMaskedWall(i,j,mw_multi1+(tile-158),MW_MULTI|MW_BLOCKING|MW_BLOCKINGCHANGES|MW_SHOOTABLE);
+            }
+            else if ((tile >= 176) && (tile <= 178)) // Multi shot out glassed walls
+            {
+                SpawnMaskedWall(i,j,mw_multi1+(tile-176),MW_BOTTOMPASSABLE);
+            }
+            else if ((tile >= 162) && (tile <= 171))
+            {
+                switch (tile)
+                {
+                case 162:
+                    SpawnMaskedWall(i,j,mw_normal1,MW_SHOOTABLE|MW_BLOCKING);
+                    break;
+                case 163:
+                    SpawnMaskedWall(i,j,mw_normal1,MW_BLOCKING);
+                    break;
+                case 164:
+                    SpawnMaskedWall(i,j,mw_normal2,MW_SHOOTABLE|MW_BLOCKING);
+                    break;
+                case 165:
+                    SpawnMaskedWall(i,j,mw_normal2,MW_BLOCKING);
+                    break;
+                case 166:
+                    SpawnMaskedWall(i,j,mw_normal3,MW_SHOOTABLE|MW_BLOCKING);
+                    break;
+                case 167:
+                    SpawnMaskedWall(i,j,mw_normal3,MW_BLOCKING);
+                    break;
+                case 168:
+                    SpawnMaskedWall(i,j,mw_singlepane,MW_SHOOTABLE|MW_BLOCKINGCHANGES|MW_BLOCKING);
+                    break;
+                case 169:
+                    SpawnMaskedWall(i,j,mw_singlepane,MW_BOTTOMPASSABLE);
+                    break;
+                case 170:
+                    SpawnMaskedWall(i,j,mw_dogwall,MW_NONDOGBLOCKING|MW_WEAPONBLOCKING);
+                    break;
+                case 171:
+                    SpawnMaskedWall(i,j,mw_peephole,MW_WEAPONBLOCKING|MW_BLOCKING);
+                    break;
+                }
+            }
+            else if (tile == 172)
+                SpawnMaskedWall(i,j,mw_exitarch,MW_BOTTOMPASSABLE);
+            else if (tile == 173)
+                SpawnMaskedWall(i,j,mw_secretexitarch,MW_BOTTOMPASSABLE);
+            else if (tile == 174) // entry gate
+                SpawnMaskedWall(i,j,mw_entrygate,MW_BLOCKING);
+            else if (tile == 157) // hi switch off
+                SpawnMaskedWall(i,j,mw_hiswitchoff,MW_BLOCKING);
+            else if (tile == 175) // hi switch on
+                SpawnMaskedWall(i,j,mw_hiswitchon,MW_BLOCKING|MW_SWITCHON);
+            else if (tile == 179) // railing;
+                SpawnMaskedWall(i,j,mw_railing,MW_ABOVEPASSABLE|MW_MIDDLEPASSABLE);
+//         else if (tile == 161) // pillar
+//            SpawnMaskedWall(i,j,mw_pillar,MW_BLOCKING);
+        }
+    }
+    for (j=0; j<mapheight; j++)
+        for(i=0; i<mapwidth; i++)
+        {
+            if (IsPlatform(i,j)) // tall platform in icon plane
+            {
+                if ((MAPSPOT(i,j,0)-AREATILE>=0) || (MAPSPOT(i,j,0)==21))
+                    // check to see we are not on a wall
+                {
+                    int which;
+
+                    which=MAPSPOT(i,j,2)-4;
+                    switch (which)
+                    {
+                    case 0:
+                        SpawnMaskedWall(i,j,mw_platform1,MW_BOTTOMPASSABLE|MW_MIDDLEPASSABLE);
+                        break;
+                    case 1:
+                        SpawnMaskedWall(i,j,mw_platform2,MW_ABOVEPASSABLE|MW_MIDDLEPASSABLE);
+                        break;
+                    case 2:
+                        SpawnMaskedWall(i,j,mw_platform3,MW_MIDDLEPASSABLE);
+                        break;
+                    case 3:
+                        SpawnMaskedWall(i,j,mw_platform4,MW_BOTTOMPASSABLE);
+                        break;
+                    case 4:
+                        SpawnMaskedWall(i,j,mw_platform5,MW_BOTTOMPASSABLE|MW_ABOVEPASSABLE);
+                        break;
+                    case 5:
+                        SpawnMaskedWall(i,j,mw_platform6,MW_ABOVEPASSABLE);
+                        break;
+                    case -3:
+                        SpawnMaskedWall(i,j,mw_platform7,MW_ABOVEPASSABLE);
+                        break;
+                    default:
+                        Error ("Illegal Maskedwall platform value at x=%d y=%d\n",i,j);
+                        break;
+                    }
+#if 0
+                    if (IsPlatform(i+1,j))
+                    {
+                        if ( (IsPlatform(i,j+1)) || (IsPlatform(i,j-1)) )
+                            SpawnStatic(i,j,83,MAPSPOT(i,j,2));
+                    }
+                    else if (IsPlatform(i-1,j))
+                    {
+                        if ( (IsPlatform(i,j+1)) || (IsPlatform(i,j-1)) )
+                            SpawnStatic(i,j,83,MAPSPOT(i,j,2));
+                    }
+#endif
+                }
+                else
+                    Error("You have what appears to be a platform ontop\n a wall at x=%d y=%d\n",i,j);
+            }
+        }
+}
+
+/*
+int GetAreaNumber ( int tilex, int tiley, int dir );
+void RemoveDangerWalls
+   (
+   void
+   )
+
+   {
+   int   i;
+   int   j;
+   word *map;
+   word  tile;
+
+   map = mapplanes[ 1 ];
+
+   for( j = 0; j < mapheight; j++ )
+      {
+      for( i = 0; i < mapwidth; i++ )
+	      {
+         tile = *map++;
+         switch( tile )
+		      {
+            case 256:
+		      case 257:
+		      case 258:
+		      case 259:
+               if ( MAPSPOT( i, j, 2 ) == 0 )
+                  {
+                  MAPSPOT( i, j, 0 ) = ( word )( GetAreaNumber( i, j,
+                     ( tile - 256 ) << 1 ) + AREATILE );
+                  MAPSPOT( i, j, 1 ) = 0;
+                  }
+		         break;
+
+            case 300:
+		      case 318:
+		      case 336:
+		      case 354:
+               if ( MAPSPOT( i, j, 2 ) == 0 )
+                  {
+                  MAPSPOT( i, j, 0 ) = ( word )( GetAreaNumber( i, j,
+                     ( ( tile - 300 ) / 9 ) + AREATILE ) );
+                  MAPSPOT( i, j, 1 ) = 0;
+                  }
+		         break;
+            }
+         }
+      }
+   }
+*/
+
+
+/*
+==================
+=
+= SetupPushWalls
+=
+==================
+*/
+
+void SetupPushWalls( void )
+{
+    int   i,j;
+    word   *map,tile;
+    int   temp;
+
+    map = mapplanes[1];
+    for(j=0; j<mapheight; j++)
+    {
+        for(i=0; i<mapwidth; i++)
+        {
+            tile = *map++;
+            switch(tile)
+            {
+            case 72:
+            case 73:
+            case 74:
+            case 75:
+            case 76:
+            case 77:
+            case 78:
+            case 79:
+                if (tilemap[i][j] && ActorIsWall(i,j))
+                {
+                    temp=tilemap[i][j]&0x1fff;
+                    tilemap[i][j] = pwallnum;
+                    if (MAPSPOT(i,j,2))
+                        SpawnPushWall(i,j,1,temp,tile-72,0);
+                    else
+                        SpawnPushWall(i,j,0,temp,tile-72,0);
+                }
+                break;
+
+            case 80: //OldPushWall
+                if (tilemap[i][j])
+                {
+                    temp=tilemap[i][j]&0x1fff;
+                    tilemap[i][j] = pwallnum;
+                    if (MAPSPOT(i,j,2))
+                        Error("You cannot link a pushwall which has no direction associated\n with it at x=%d y=%d\n",i,j);
+                    else
+                        SpawnPushWall(i,j,0,temp,nodir,0);
+                }
+                break;
+
+
+            case 256:
+            case 257:
+            case 258:
+            case 259:
+                if (tilemap[i][j])
+                {
+                    temp=tilemap[i][j]&0x1fff;
+                    tilemap[i][j] = pwallnum;
+                    if (MAPSPOT(i,j,2))
+                        SpawnPushWall(i,j,0,temp,(tile-256)<<1,2);
+                    else
+                        SpawnPushWall(i,j,0,temp,(tile-256)<<1,4);
+                }
+                else
+                    Error("You have to place a turbomovewall icon on a wall at x=%d y=%d",i,j);
+                break;
+
+            case 300:
+            case 318:
+            case 336:
+            case 354:
+                if (tilemap[i][j])
+                {
+                    temp=tilemap[i][j]&0x1fff;
+                    tilemap[i][j] = pwallnum;
+                    if (MAPSPOT(i,j,2))
+                        SpawnPushWall(i,j,0,temp,(tile-300)/9,1);
+                    else
+                        SpawnPushWall(i,j,0,temp,(tile-300)/9,3);
+                }
+                else
+                    Error("You have to place a movewall icon on a wall at x=%d y=%d",i,j);
+                break;
+            }
+        }
+    }
+}
+
+
+/*
+==================
+=
+= GetPushWallNumber
+=
+==================
+*/
+
+int GetPushWallNumber( int tx, int ty )
+{
+    int i;
+
+    for (i=0; i<pwallnum; i++)
+        if ( (pwallobjlist[i]->tilex==tx) && (pwallobjlist[i]->tiley==ty))
+            return i;
+    Error ("Could not find a push wall at x=%d y=%d\n",tx,ty);
+    return -1;
+}
+
+
+/*
+==================
+=
+= SetupPushWallLinks
+=
+==================
+*/
+void SetupPushWallLinks( void )
+{
+    int   i,j;
+    word   *map,tile;
+    word  touchx,touchy;
+
+    map = mapplanes[1];
+    for(j=0; j<mapheight; j++)
+    {
+        for(i=0; i<mapwidth; i++)
+        {
+            tile = *map++;
+            switch(tile)
+            {
+            case 72:
+            case 73:
+            case 74:
+            case 75:
+            case 76:
+            case 77:
+            case 78:
+            case 79:
+                if (ActorIsPushWall(i,j))
+                {
+                    if (MAPSPOT(i,j,2))
+                    {
+                        touchx = (word) ((MAPSPOT(i,j,2) >> 8) & 0xff);
+                        touchy = (word) ((MAPSPOT(i,j,2) >> 0) & 0xff);
+                        if (touchindices[touchx][touchy])
+                        {
+                            if (MAPSPOT(i,j+1,2)!=0)
+                            {
+#if (DEVELOPMENT == 1)
+                                SoftError("MAPWARNING:You left a delay for a linked push wall under the pushwall\n at x=%ld y=%ld\n",i,j);
+#endif
+                            }
+                            Link_To_Touchplate(touchx,touchy,ActivatePushWall,NULL,GetPushWallNumber(i,j),0);
+                        }
+                        else
+                            Error("tried to link a pushwall at x=%d y=%d to a non-existent touchplate\n",i,j);
+                    }
+                }
+                break;
+
+            case 80:
+                if (ActorIsPushWall(i,j))
+                {
+                    if (MAPSPOT(i,j,2))
+                    {
+                        Error("You shouldn't be linking a nondirectional-push wall at x=%d y=%d\n",i,j);
+                    }
+                }
+                break;
+            case 256:
+            case 257:
+            case 258:
+            case 259:
+                if (ActorIsPushWall(i,j))
+                {
+                    if (MAPSPOT(i,j,2))
+                    {
+                        touchx = (word) ((MAPSPOT(i,j,2) >> 8) & 0xff);
+                        touchy = (word) ((MAPSPOT(i,j,2) >> 0) & 0xff);
+                        if (touchindices[touchx][touchy])
+                        {
+                            if (MAPSPOT(i,j+1,2)!=0)
+                            {
+#if (DEVELOPMENT == 1)
+                                SoftError("MAPWARNING:You left a delay for a linked push wall under the pushwall\n at x=%ld y=%ld\n",i,j);
+#endif
+                            }
+                            Link_To_Touchplate(touchx,touchy,ActivateMoveWall,NULL,GetPushWallNumber(i,j),0);
+                        }
+                        else
+                            Error("tried to link a turbomovewall at x=%d y=%d to a non-existent touchplate\n",i,j);
+                    }
+                }
+                break;
+
+            case 300:
+            case 318:
+            case 336:
+            case 354:
+                if (ActorIsPushWall(i,j))
+                {
+                    if (MAPSPOT(i,j,2))
+                    {
+                        touchx = (word) ((MAPSPOT(i,j,2) >> 8) & 0xff);
+                        touchy = (word) ((MAPSPOT(i,j,2) >> 0) & 0xff);
+                        if (touchindices[touchx][touchy])
+                        {
+                            if (MAPSPOT(i,j+1,2)!=0)
+                            {
+#if (DEVELOPMENT == 1)
+                                SoftError("MAPWARNING:You left a delay for a linked push wall under the pushwall\n at x=%ld y=%ld\n",i,j);
+#endif
+                            }
+                            Link_To_Touchplate(touchx,touchy,ActivateMoveWall,NULL,GetPushWallNumber(i,j),0);
+                        }
+                        else
+                            Error("tried to link a movewall at x=%d y=%d to a non-existent touchplate\n",i,j);
+                    }
+                }
+                break;
+            }
+        }
+    }
+}
+
+/*
+=================
+=
+= SetupElevators
+=
+=================
+*/
+
+void SetupElevators (void)
+{
+    int j, i,x,y,starti;
+    word *map;
+    word tile;
+    elevator_t *elev;
+    doorobj_t* dptr;
+
+    map = mapplanes[1];
+    map += 4 ;
+
+    for (j = 0; j < mapheight; j++)
+    {
+        if (j == 0)
+            starti = 4;
+        else
+            starti = 0;
+
+        for (i = starti; i < mapwidth; i++)
+        {   tile = *map++;
+
+            if ((tile > 89) && (tile < 98))
+            {   elev = &ELEVATOR[tile-90];
+                if (!elev->sx)
+                {   elev->sx = i;
+                    elev->sy = j;
+                    elev->doortoopen = -1;
+                    elev->doorclosing = -1;
+                    elev->nextaction = -1;
+                    _numelevators ++;
+                }
+                else
+                {   elev->dx = i;
+                    elev->dy = j;
+                }
+            }
+        }
+    }
+
+    if (_numelevators && (!ELEVATOR[0].sx))
+        Error("Elevators must start at 1, dumb ass.");
+
+    for(i=0; i<_numelevators; i++)
+    {   elev = &ELEVATOR[i];
+        x = elev->sx;
+        y = elev->sy;
+        for(j=0; j<doornum; j++)
+        {   dptr = doorobjlist[j];
+            if (((dptr->tilex == (x+1)) && (dptr->tiley == y)) ||
+                    ((dptr->tilex == (x-1)) && (dptr->tiley == y)) ||
+                    ((dptr->tilex == x) && (dptr->tiley == (y+1))) ||
+                    ((dptr->tilex == x) && (dptr->tiley == (y-1))))
+            {   elev->door1 = j;
+                dptr->eindex = i;
+                if ((dptr->tilex == (x+1)) && (dptr->tiley == y))
+                {   elev->esx = x-1;
+                    elev->esy = y;
+                }
+                else if ((dptr->tilex == (x-1)) && (dptr->tiley == y))
+                {   elev->esx = x+1;
+                    elev->esy = y;
+                }
+                else if ((dptr->tilex == x) && (dptr->tiley == (y+1)))
+                {   elev->esx = x;
+                    elev->esy = y-1;
+                }
+                else if ((dptr->tilex == x) && (dptr->tiley == (y-1)))
+                {   elev->esx = x;
+                    elev->esy = y+1;
+                }
+                break;
+            }
+        }
+
+        x = elev->dx;
+        y = elev->dy;
+        for(j=0; j<doornum; j++)
+        {   dptr = doorobjlist[j];
+            if (((dptr->tilex == (x+1)) && (dptr->tiley == y)) ||
+                    ((dptr->tilex == (x-1)) && (dptr->tiley == y)) ||
+                    ((dptr->tilex == x) && (dptr->tiley == (y+1))) ||
+                    ((dptr->tilex == x) && (dptr->tiley == (y-1))))
+            {   elev->door2 = j;
+                dptr->eindex = i;
+                dptr->flags |= DF_ELEVLOCKED;
+                if ((dptr->tilex == (x+1)) && (dptr->tiley == y))
+                {   elev->edx = x-1;
+                    elev->edy = y;
+                }
+                else if ((dptr->tilex == (x-1)) && (dptr->tiley == y))
+                {   elev->edx = x+1;
+                    elev->edy = y;
+                }
+                else if ((dptr->tilex == x) && (dptr->tiley == (y+1)))
+                {   elev->edx = x;
+                    elev->edy = y-1;
+                }
+                else if ((dptr->tilex == x) && (dptr->tiley == (y-1)))
+                {   elev->edx = x;
+                    elev->edy = y+1;
+                }
+                break;
+            }
+
+        }
+    }
+#if ((DEVELOPMENT == 1))
+#if ((ELEVATORTEST == 1))
+    for(i=0; i<_numelevators; i++)
+        Debug("\nelevator %d door1 %2d, door2 %2d",i,ELEVATOR[i].door1,ELEVATOR[i].door2);
+#endif
+#endif
+}
+
+
+/*
+=================
+=
+= SetupDoors
+=
+=================
+*/
+
+void SetupDoors (void)
+{
+    int j, i;
+    word *map;
+    word tile;
+    byte locked;
+
+    map = mapplanes[0];
+
+    for (j = 0; j < mapheight; j++)
+        for (i = 0; i < mapwidth; i++)
+        {
+            tile = *map++;
+
+            if ((tile >= 33) && (tile <= 35))
+            {
+                tilemap[i][j] = doornum;
+
+                locked=0;
+                if (MAPSPOT (i, j, 2))
+                    locked = 5;
+
+                SpawnDoor (i, j, locked, (tile-33)+15);
+            }
+
+            else if ((tile > 89) && (tile < 94))
+            {
+                tilemap[i][j] = doornum;
+
+                locked = 0;
+                if (MAPSPOT (i, j, 2))
+                    locked = 5;
+
+                SpawnDoor (i, j, locked, tile-90);
+            }
+
+            else if ((tile > 93) && (tile < 98))
+            {
+                Error("locked door %d being used at %d,%d",tile,i,j);
+            }
+
+
+            else if ((tile > 97) && (tile < 105))
+            {
+                tilemap[i][j] = doornum;
+
+                locked = 0;
+                if (MAPSPOT (i, j, 2))
+                    locked = 5;
+
+                SpawnDoor (i, j, locked, tile-90);
+            }
+            else if ((tile >= 154) && (tile <= 156))
+            {
+                tilemap[i][j] = doornum;
+
+                locked=0;
+                if (MAPSPOT (i, j, 2))
+                    locked = 5;
+
+                SpawnDoor (i, j, locked, (tile-154)+18);
+            }
+        }
+}
+
+/*
+==================
+=
+= GetDoorNumber
+=
+==================
+*/
+
+int GetDoorNumber( int tx, int ty )
+{
+    int i;
+
+    for (i=0; i<doornum; i++)
+        if ( (doorobjlist[i]->tilex==tx) && (doorobjlist[i]->tiley==ty))
+            return i;
+    Error ("Could not find a door at x=%d y=%d\n",tx,ty);
+    return -1;
+}
+
+/*
+=================
+=
+= SetupDoorLinks
+=
+=================
+*/
+
+void SetupDoorLinks (void)
+{
+    int  j,
+         i,
+         k;
+    word *map;
+    int  clocklinked;
+    int  clockx,clocky;
+    int  doornumber;
+    word touchx,
+         tile,
+         touchy;
+
+    map = mapplanes[0];
+
+    for (j = 0; j < mapheight; j++)
+        for (i = 0; i < mapwidth; i++)
+        {
+            tile = *map++;
+
+            if (MAPSPOT (i, j, 2))
+            {
+                if (IsDoor(i,j)==1)
+                {
+                    clocklinked = 0;
+
+                    doornumber=GetDoorNumber(i,j);
+
+                    for (k = 0; k < numclocks; k++)
+                    {
+                        clockx = Clocks[k].points_to_tilex;
+                        clocky = Clocks[k].points_to_tiley;
+
+                        if ((clockx == i) && (clocky == j))
+                        {
+                            clocklinked = 1;
+                            ClockLink (LinkedOpenDoor, LinkedCloseDoor, doornumber, k);
+                            doorobjlist[doornumber]->lock   = 5;
+                            doorobjlist[doornumber]->flags |= DF_TIMED;
+                        }
+                    }
+
+                    if (!clocklinked)
+                    {
+                        touchx = (word) ((MAPSPOT (i, j, 2) >> 8) & 0xff);
+                        touchy = (word) ((MAPSPOT (i, j, 2) >> 0) & 0xff);
+
+                        if (touchindices[touchx][touchy])
+                        {
+                            if (MAPSPOT (i, j, 1) == 192)
+                                Link_To_Touchplate (touchx, touchy, LinkedCloseDoor,
+                                                    LinkedCloseDoor, doornumber, 0);
+                            else
+                                Link_To_Touchplate (touchx, touchy, LinkedOpenDoor,
+                                                    LinkedOpenDoor, doornumber, 0);
+                        }
+                        else
+                            Error ("tried to link a door at x=%d y=%d to a non-existent touchplate",i,j);
+                    }
+                }
+            }
+        }
+}
+
+
+/*
+=================
+=
+= FindTimeTile
+=
+=================
+*/
+void FindTimeTile ( int * x, int * y )
+{
+    int xx,yy;
+
+    xx=*x;
+    yy=*y;
+
+    if (!(tilemap[xx+1][yy]) && MAPSPOT(xx+1,yy,2))
+    {
+        *x=xx+1;
+        return;
+    }
+    if (!(tilemap[xx-1][yy]) && MAPSPOT(xx-1,yy,2))
+    {
+        *x=xx-1;
+        return;
+    }
+    if (!(tilemap[xx][yy+1]) && MAPSPOT(xx,yy+1,2))
+    {
+        *y=yy+1;
+        return;
+    }
+    if (!(tilemap[xx][yy-1]) && MAPSPOT(xx,yy-1,2))
+    {
+        *y=yy-1;
+        return;
+    }
+    Error ("Could not find an end time for a clock linked item\nat x=%d y=%d\n",*x,*y);
+}
+
+
+
+/*
+=================
+=
+= SetupClocks
+=
+=================
+*/
+
+void SetupClocks (void)
+{
+    int  i,
+         j,
+         minutes,
+         seconds,
+         starti;
+    word *map,
+         tile,
+         mapx,
+         mapy;
+    int  endtimex,
+         endtimey;
+
+
+    map  = mapplanes[1];
+    map += 4 ;
+
+    for (j = 0; j < mapheight; j++)
+    {
+        if (j == 0)
+            starti = 4;
+        else
+            starti = 0;
+
+        for (i = starti; i < mapwidth; i++)
+        {
+            tile = *map++;
+
+            if (tile == 121)
+            {
+                mapx = (word) ((MAPSPOT (i, j, 2) >> 8) & 0xff);
+                mapy = (word) ((MAPSPOT (i, j, 2) >> 0) & 0xff);
+
+                minutes = (int) ((MAPSPOT (mapx, mapy, 2) >> 8) & 0xff);
+                seconds = (int) ((MAPSPOT (mapx, mapy, 2) >> 0) & 0xff);
+
+                if (seconds > 0x59)
+                    Error ("seconds of clock time must be below 0x5a (60 secs) ");
+
+                seconds = 10 * (seconds/16) + (seconds % 16);
+                minutes = 60 * (10*(minutes/16) + (minutes % 16));
+
+                // total seconds
+                Clocks[numclocks].time1 = VBLCOUNTER*(seconds + minutes);
+
+                endtimex=mapx;
+                endtimey=mapy;
+
+                FindTimeTile (&endtimex, &endtimey);
+
+                minutes = (int) ((MAPSPOT (endtimex, endtimey, 2) >> 8) & 0xff);
+                seconds = (int) ((MAPSPOT (endtimex, endtimey, 2) >> 0) & 0xff);
+
+                if (seconds > 0x59)
+                    Error("seconds of clock time must be below 0x5a (60 secs)");
+
+                seconds = 10 * (seconds/16) + (seconds % 16);
+                minutes = 60 * (10*(minutes/16) + (minutes % 16));
+
+                // total seconds
+                Clocks[numclocks].time2 = VBLCOUNTER * (seconds + minutes);
+                Clocks[numclocks].points_to_tilex = mapx;
+                Clocks[numclocks].points_to_tiley = mapy;
+                Clocks[numclocks].linkindex       = lasttouch;
+
+                numclocks ++;
+
+                // clocks treated as virtual touchplates
+                lasttouch ++;
+            }
+        }
+    }
+}
+
+
+
+/*
+=================
+=
+= LinkElevatorDiskGroups
+=
+=================
+*/
+
+void LinkElevatorDiskGroups(void)
+{
+    objtype *diskfinder1,*temp,*master;
+    int maxplatformheight[30]= {-1};
+    int num_distinct_max_heights=0;
+    int i;
+    boolean newdiskheight;
+
+
+#define M_ISELEVDISK(actor) \
+    ((actor->obclass == diskobj) && (actor->state == &s_elevdisk))
+
+
+
+    for(diskfinder1 = FIRSTACTOR; diskfinder1; diskfinder1 = diskfinder1->next)
+    {
+        if (!M_ISELEVDISK(diskfinder1))
+            continue;
+
+        newdiskheight = true;
+        for(i=0; i<num_distinct_max_heights; i++)
+        {
+            if (maxplatformheight[i] == diskfinder1->temp2)
+            {
+                newdiskheight = false;
+                break;
+            }
+        }
+
+        if (newdiskheight == true)
+            maxplatformheight[num_distinct_max_heights++] = diskfinder1->temp2;
+
+    }
+
+
+    for(i=0; i<num_distinct_max_heights; i++)
+    {
+
+        SpawnDisk(64,64,0,true);
+        master = new;
+        master->temp2 = maxplatformheight[i];
+
+        for(temp = FIRSTACTOR; temp; temp = temp->next)
+        {
+            if (temp == master)
+                continue;
+
+            if (!M_ISELEVDISK(temp))
+                continue;
+
+            if (temp->temp2 != maxplatformheight[i])
+                continue;
+
+            temp->target = master;
+            SetTilePosition(master,temp->tilex,temp->tiley);
+            master->areanumber=AREANUMBER(master->tilex,master->tiley);
+
+        }
+        master->flags |= FL_ABP;
+        MakeActive(master);
+    }
+
+
+}
+
+
+/*
+=================
+=
+= LinkActor
+=
+=================
+*/
+
+
+void LinkActor (objtype *ob,int tilex,int tiley,
+                void (*action)(long),void (*swapaction)(long)
+               )
+{
+    word  touchx,touchy;
+    int   clockx,clocky;
+    int   clocklinked,k;
+    wall_t * tswitch;
+
+
+    clocklinked = 0;
+    for(k=0; k<numclocks; k++)
+    {
+        clockx = Clocks[k].points_to_tilex;
+        clocky = Clocks[k].points_to_tiley;
+        if ((clockx == tilex) && (clocky == tiley))
+        {
+            clocklinked = 1;
+            ClockLink(EnableObject,DisableObject,(long)ob,k);
+        }
+    }
+
+    if (!clocklinked)
+    {
+        touchx = (word) ((MAPSPOT(tilex,tiley,2) >> 8) & 0xff);
+        touchy = (word) ((MAPSPOT(tilex,tiley,2) >> 0) & 0xff);
+        if ((MISCVARS->TOMLOC.x == touchx) && (MISCVARS->TOMLOC.y == touchy))
+        {
+            objtype *tom = (objtype*)actorat[touchx][touchy];
+            tom->whatever = ob;
+        }
+
+        else if (touchindices[touchx][touchy])
+        {
+            tswitch = (wall_t*) actorat[touchx][touchy];
+
+            if (tswitch && (ob->obclass == wallfireobj))
+            {
+                tswitch->flags |= FL_REVERSIBLE;
+                if (tswitch->flags & FL_ON)
+                    ob->flags |= FL_ACTIVE;
+            }
+
+
+            if (tswitch && (tswitch->flags & FL_ON))
+                Link_To_Touchplate(touchx,touchy,swapaction,action,(long)ob,0);
+            else
+                Link_To_Touchplate(touchx,touchy,action,swapaction,(long)ob,0);
+            if (ob->obclass == gasgrateobj)
+            {
+                ob->temp1 = touchx;
+                ob->temp2 = touchy;
+            }
+        }
+        else
+            Error("tried to link an object at x=%d y=%d to a non-existent touchplate supposedly at x=%d y=%d",tilex,tiley,touchx,touchy);
+    }
+
+    if (tilemap[tilex][tiley])
+        (MAPSPOT(tilex,tiley,2))=21;
+}
+
+
+
+
+/*
+======================
+=
+= SetupInanimateActors
+=
+======================
+*/
+
+
+void SetupInanimateActors (void)
+{
+    int   i,j,linked;
+    word   *map,tile;
+    void (*action)(long),(*swapaction)(long);
+
+
+    map = mapplanes[1];
+
+
+    // non-linked, harmless inanimate actors
+    for(j=0; j<mapheight; j++)
+    {
+        for(i=0; i<mapwidth; i++)
+        {
+            tile = *map++;
+
+            switch(tile)
+            {
+
+            case 193:
+                SpawnSpring(i,j);
+                break;
+
+#if 0
+            case 460:
+//               if ( gamestate.Product != ROTT_SHAREWARE )
+            {
+                SpawnNewObj(i,j,&s_wind,inertobj);
+            }
+            break;
+#endif
+
+            case 462:
+            case 463:
+            case 464:
+            case 465:
+            case 466:
+
+                SpawnDisk(i,j,tile-462,false);
+                break;
+
+            case 285:
+            case 286:
+            case 287:
+                SpawnPushColumn(i,j,tile-285,nodir,0);
+                break;
+            }
+        }
+    }
+
+
+    // linked, harmless actors
+    map = mapplanes[1];
+    for(j=0; j<mapheight; j++)
+    {
+        for(i=0; i<mapwidth; i++)
+        {
+            tile = *map++;
+            action = EnableObject;
+            swapaction = DisableObject;
+            linked = (MAPSPOT(i,j,2) && (!IsPlatform(i,j)));
+
+
+            switch(tile)
+            {
+
+            case 140:
+            case 141:
+            case 142:
+            case 143:
+
+                if ((!BATTLEMODE) || (gamestate.BattleOptions.SpawnDangers))
+                {
+                    PreCacheActor(wallfireobj,0);
+                    SpawnWallfire(i,j,tile-140);
+                    if (!linked)
+                    {
+                        new->flags |= FL_ACTIVE;
+                        if (tilemap[i][j])
+                            MAPSPOT(i,j,2) = 21;
+                    }
+                    else
+                        LinkActor(new,i,j,action,swapaction);
+                }
+                else if (tilemap[i][j])
+                    MAPSPOT(i,j,2) = 21;
+
+                break;
+
+
+
+
+
+            case 303:
+            case 304:
+            case 305:
+                SpawnPushColumn(i,j,tile-303,east,linked);
+                swapaction = NULL;
+                if (linked)
+                    LinkActor(new,i,j,action,swapaction);
+
+                break;
+
+            case 321:
+            case 322:
+            case 323:
+                SpawnPushColumn(i,j,tile-321,north,linked);
+                swapaction = NULL;
+                if (linked)
+                    LinkActor(new,i,j,action,swapaction);
+
+                break;
+
+            case 339:
+            case 340:
+            case 341:
+                SpawnPushColumn(i,j,tile-339,west,linked);
+                swapaction = NULL;
+                if (linked)
+                    LinkActor(new,i,j,action,swapaction);
+
+                break;
+
+            case 357:
+            case 358:
+            case 359:
+                SpawnPushColumn(i,j,tile-357,south,linked);
+                swapaction = NULL;
+                if (linked)
+                    LinkActor(new,i,j,action,swapaction);
+
+                break;
+
+
+            }
+
+        }
+    }
+
+    //harmful actors
+
+    if ((!BATTLEMODE) || (gamestate.BattleOptions.SpawnDangers))
+    {
+        map = mapplanes[1];
+        for(j=0; j<mapheight; j++)
+        {
+            for(i=0; i<mapwidth; i++)
+            {
+                tile = *map++;
+                action = EnableObject;
+                swapaction = DisableObject;
+                linked = (MAPSPOT(i,j,2) && (!IsPlatform(i,j)));
+
+                switch(tile)
+                {
+                case 89:
+                    SpawnFourWayGun(i,j);
+                    break;
+
+
+                case 156:
+                case 157:
+                    SpawnBlade(i,j,nodir,0,tile-156);
+                    if (linked)
+                        LinkActor(new,i,j,action,swapaction);
+
+                    break;
+
+                case 174:
+                case 175:
+                    SpawnBlade(i,j,nodir,1,tile-174);
+                    if (linked)
+                        LinkActor(new,i,j,action,swapaction);
+
+                    break;
+
+
+
+                case 412:
+                    SpawnSpear(i,j,0);
+                    break;
+
+                case 430:
+                    SpawnSpear(i,j,1);
+                    break;
+
+                case 413:
+                    SpawnCrushingColumn(i,j,1); //down
+                    break;
+
+                case 431:
+                    SpawnCrushingColumn(i,j,0); // up
+                    break;
+
+
+                case 192:
+                    if (!tilemap[i][j])
+                    {
+                        SpawnNewObj(i,j,&s_gas1,gasgrateobj);
+                        PreCacheActor(gasgrateobj,0);
+                        new->flags |= FL_ABP;
+                        MakeActive(new);
+                        swapaction = NULL;
+                        if (linked)
+                            LinkActor(new,i,j,action,swapaction);
+
+                    }
+                    break;
+
+
+                case 301:
+                case 302:
+                    SpawnBlade(i,j,east,tile-301,0);
+                    if (!linked)
+                        new->flags |= FL_ACTIVE;
+                    else
+                        LinkActor(new,i,j,action,swapaction);
+
+                    break;
+
+                case 319:
+                case 320:
+                    SpawnBlade(i,j,north,tile-319,0);
+                    if (!linked)
+                        new->flags |= FL_ACTIVE;
+                    else
+                        LinkActor(new,i,j,action,swapaction);
+
+                    break;
+
+                case 337:
+                case 338:
+                    SpawnBlade(i,j,west,tile-337,0);
+                    if (!linked)
+                        new->flags |= FL_ACTIVE;
+                    else
+                        LinkActor(new,i,j,action,swapaction);
+
+                    break;
+
+                case 355:
+                case 356:
+                    SpawnBlade(i,j,south,tile-355,0);
+                    if (!linked)
+                        new->flags |= FL_ACTIVE;
+                    else
+                        LinkActor(new,i,j,action,swapaction);
+
+                    break;
+
+                case 372:
+                    SpawnFirejet(i,j,nodir,0);
+                    break;
+
+                case 373:
+                case 374:
+                case 375:
+                case 376:
+                    SpawnFirejet(i,j,tile-373,0);
+                    break;
+
+                case 390:
+                    SpawnFirejet(i,j,nodir,1);
+                    break;
+
+                case 391:
+                case 392:
+                case 393:
+                case 394:
+                    SpawnFirejet(i,j,tile-391,1);
+                    break;
+
+                case 278:
+                case 279:
+                case 280:
+                case 281:
+                    SpawnBoulder(i,j,tile-278);
+                    if (!linked)
+                        new->flags |= FL_ACTIVE;
+                    else
+                        LinkActor(new,i,j,action,swapaction);
+
+                    break;
+
+                }
+
+
+            }
+        }
+    }
+
+    LinkElevatorDiskGroups();
+
+}
+
+
+/*
+===================
+=
+= FixTiles
+=
+===================
+*/
+
+void FixTiles(void)
+{
+    word *map,tile;
+    int i,j;
+
+    map = mapplanes[1];
+    for(j=0; j<mapheight; j++)
+    {
+        for(i=0; i<mapwidth; i++)
+        {
+            tile = *map++;
+            switch(tile)
+            {
+            case 140:
+            case 141:
+            case 142:
+            case 143:
+            case 192:
+            case 278:
+            case 279:
+            case 280:
+            case 281:
+                if (tilemap[i][j])
+                    (MAPSPOT(i,j,2))=21;
+                break;
+            }
+        }
+    }
+
+}
+
+
+void Illuminate(void)
+{   statobj_t*temp;
+
+    if (lightsource==0)
+        return;
+    for(temp=FIRSTSTAT; temp; temp=temp->statnext)
+        if (temp->flags & FL_LIGHTON)
+            TurnOnLight(temp->tilex,temp->tiley);
+}
+
+
+/*
+=================
+=
+= SetupLights
+=
+=================
+*/
+void SetupLights(void)
+{
+    int i,j,touchx,touchy;
+    wall_t *tswitch;
+    word *map,tile;
+    int starti;
+
+// Initialize Lights in Area
+
+    memset(LightsInArea,0,sizeof(LightsInArea));
+
+    map = mapplanes[1];
+    map+=5;
+
+    for (j=0; j<mapheight; j++)
+    {
+        if (j==0)
+            starti=5;
+        else
+            starti=0;
+        for(i=starti; i<mapwidth; i++)
+        {
+            tile= *map++;
+
+
+
+            switch (tile)
+            {
+
+            // Add light sourcing to these objects
+
+            case 23:
+            case 24:
+            case 25:
+            case 26:
+            case 27:
+            case 42:
+            case 63:
+            case 64:
+                sprites[i][j]->flags |= FL_LIGHTON;
+                break;
+
+            case 28:
+            case 43:
+                if (MAPSPOT(i,j,2))
+                {
+                    touchx = (word) ((MAPSPOT(i,j,2) >> 8) & 0xff);
+                    touchy = (word) ((MAPSPOT(i,j,2) >> 0) & 0xff);
+                    tswitch = (wall_t*) actorat[touchx][touchy];
+
+                    if (tswitch && (tswitch->which == WALL))
+                    {   tswitch->flags |= FL_REVERSIBLE;
+                        if (!(tswitch->flags & FL_ON))
+                        {   sprites[i][j]->shapenum --;
+                            if (touchindices[touchx][touchy])
+                            {   Link_To_Touchplate(touchx,touchy,ActivateLight,DeactivateLight,(long)(sprites[i][j]),0);
+                                sprites[i][j]->linked_to = touchindices[touchx][touchy]-1;
+                            }
+                            else
+                                Error("tried to link a light at x=%d y=%d to a non-existent touchplate",i,j);
+                        }
+                        else
+                        {   if (touchindices[touchx][touchy])
+                            {   Link_To_Touchplate(touchx,touchy,DeactivateLight,ActivateLight,(long)(sprites[i][j]),0);
+                                sprites[i][j]->linked_to = touchindices[touchx][touchy]-1;
+                            }
+                            else
+                                Error("tried to link a light at x=%d y=%d to a non-existent touchplate",i,j);
+                            sprites[i][j]->flags |= FL_LIGHTON;
+                        }
+                    }
+                    else
+                    {   if (touchindices[touchx][touchy])
+                        {   Link_To_Touchplate(touchx,touchy,DeactivateLight,ActivateLight,(long)(sprites[i][j]),0);
+                            sprites[i][j]->linked_to = touchindices[touchx][touchy]-1;
+                        }
+                        else
+                            Error("tried to link a light at x=%d y=%d to a non-existent touchplate",i,j);
+                        sprites[i][j]->flags |= FL_LIGHTON;
+                    }
+
+                }
+                else
+                    sprites[i][j]->flags |= FL_LIGHTON;
+
+                break;
+            }
+        }
+    }
+}
+
+/*
+==================
+=
+= PrintMapStats
+=
+==================
+*/
+void PrintMapStats (void)
+{
+    int size;
+    int total;
+
+    if (MAPSTATS==false)
+        return;
+
+    OpenMapDebug();
+
+    total=0;
+    MapDebug("MAP STATS Map Number %d\n",gamestate.mapon);
+    MapDebug("=======================\n");
+    size=pwallnum*sizeof(pwallobj_t);
+    total+=size;
+    MapDebug("Number of PushWalls   : %4d size = %6d\n",pwallnum,size);
+    size=maskednum*sizeof(maskedwallobj_t);
+    total+=size;
+    MapDebug("Number of MaskedWalls : %4d size = %6d\n",maskednum,size);
+    size=doornum*sizeof(doorobj_t);
+    total+=size;
+    MapDebug("Number of Doors       : %4d size = %6d\n",doornum,size);
+    size=lasttouch*sizeof(touchplatetype);
+    total+=size;
+    MapDebug("Number of TouchPlates : %4d size = %6d\n",lasttouch,size);
+    size=_numelevators*sizeof(elevator_t);
+    total+=size;
+    MapDebug("Number of Elevators   : %4d size = %6d\n",_numelevators,size);
+    size=statcount*sizeof(statobj_t);
+    total+=size;
+    MapDebug("Number of Sprites     : %4d size = %6d\n",statcount,size);
+    size=objcount*sizeof(objtype);
+    total+=size;
+    MapDebug("Number of Actors      : %4d size = %6d\n",objcount,size);
+    MapDebug("Number of Clocks      : %4d\n",numclocks);
+    MapDebug("\nTotal size of level : %6d\n",total);
+}
+
+
+boolean IsWeapon(int tile)
+{
+    if ((tile >= 46) && (tile <= 56))
+        return true;
+
+    return  false;
+
+}
+
+
+char *WeaponName(int tile)
+{
+    switch(tile)
+    {
+    case 46:
+        return "Bat           ";
+        break;
+
+    case 47:
+        return "Knife         ";
+        break;
+
+    case 48:
+        return "Double Pistol ";
+        break;
+
+    case 49:
+        return "MP40          ";
+        break;
+
+    case 50:
+        return "Bazooka       ";
+        break;
+
+    case 51:
+        return "Firebomb      ";
+        break;
+
+    case 52:
+        return "Heatseeker    ";
+        break;
+
+    case 53:
+        return "Drunk Missile ";
+        break;
+
+    case 54:
+        return "Flamewall     ";
+        break;
+
+    case 55:
+        return "Split Missile ";
+        break;
+
+    case 56:
+        return "KES           ";
+        break;
+    }
+    return " ";
+}
+
+
+
+int GetLumpForTile(int tile)
+{
+    int wallstart;
+    int exitstart;
+
+    wallstart=W_GetNumForName("WALLSTRT");
+    exitstart=W_GetNumForName("EXITSTRT");
+    elevatorstart = W_GetNumForName("ELEVSTRT");
+
+    if ((tile >= 1) && (tile <= 32))
+    {
+        return (tile + wallstart);
+    }
+    else if ((tile >= 36) && (tile <= 45))
+    {
+        return (tile + wallstart - 3);
+    }
+    else if (tile == 46)
+    {
+        return (wallstart + 74);
+    }
+    else if ((tile >= 47) && (tile <= 48))
+    {
+        return (tile + exitstart - 46);
+    }
+    else if ((tile >= 49) && (tile <= 71))
+    {
+        return (tile + wallstart - 8);
+    }
+    else if ((tile >= 72) && (tile <= 79))
+    {
+        return (tile - 72 + elevatorstart + 1);
+    }
+    else if ((tile >= 80) && (tile <= 89))
+    {
+        return (tile + wallstart - 16);
+    }
+    return -1;
+}
+
+
+
+
+#if (DEVELOPMENT == 1)
+
+
+/*
+==================
+=
+= Insane Dump
+=
+==================
+*/
+
+void InsaneDump(void)
+{
+    int i,j,level;
+    word *map,tile;
+    int tally[1000];
+    int inlevel[1000][10];
+
+    if (TILESTATS==false)
+        return;
+
+    OpenMapDebug();
+
+
+// WALLS
+    memset(tally,0,sizeof(tally));
+    memset(inlevel,0,sizeof(inlevel));
+    MapDebug("=======================\n");
+    MapDebug("= WALLS\n");
+    MapDebug("=======================\n");
+    mapheight = mapwidth = 128;
+    BATTLEMODE = 1;
+    for(level=0; level<8; level ++)
+    {
+        GetEpisode(level);
+        LoadROTTMap(level);
+        map = mapplanes[0];
+        for (j=0; j<mapheight; j++)
+        {
+            for(i=0; i<mapwidth; i++)
+            {   tile = *map++;
+                if (IsWall(i,j)==true)
+                {   tally[tile]++;
+                    inlevel[tile][level]=1;
+                }
+
+            }
+        }
+    }
+
+    MapDebug("Wall #   Frequency    Levels\n");
+    MapDebug("----------------------------\n");
+    for (i=0; i<1000; i++)
+        if (i < 90)
+        {   MapDebug("%4d      %4d       %s",i,tally[i],
+                     W_GetNameForNum(GetLumpForTile(i)));
+            MapDebug("     ");
+            for(level=0; level < 10; level ++)
+                if (inlevel[i][level])
+                    MapDebug("%d,",level);
+            MapDebug("\n");
+        }
+
+
+
+
+
+// Doors
+    memset(tally,0,sizeof(tally));
+    memset(inlevel,0,sizeof(inlevel));
+    MapDebug("=======================\n");
+    MapDebug("= DOORS\n");
+    MapDebug("=======================\n");
+    for(level=0; level<10; level ++)
+    {
+        GetEpisode(level);
+        LoadROTTMap(level);
+        map = mapplanes[0];
+        for (j=0; j<mapheight; j++)
+        {
+            for(i=0; i<mapwidth; i++)
+            {   tile = *map++;
+                if (IsDoor(i,j)==true)
+                {   tally[tile]++;
+                    inlevel[tile][level]=1;
+                }
+
+            }
+        }
+    }
+
+    MapDebug("Door #   Frequency    Levels\n");
+    MapDebug("----------------------------\n");
+    for (i=0; i<1000; i++)
+        if (tally[i]!=0)
+        {   MapDebug("%4d      %4d         ",i,tally[i]);
+            for(level=0; level < 10; level ++)
+                if (inlevel[i][level])
+                    MapDebug("%d,",level);
+            MapDebug("\n");
+
+        }
+
+// MaskedWalls
+    memset(tally,0,sizeof(tally));
+    memset(inlevel,0,sizeof(inlevel));
+    MapDebug("=======================\n");
+    MapDebug("= MASKED WALLS\n");
+    MapDebug("=======================\n");
+    for(level=0; level<10; level ++)
+    {
+        GetEpisode(level);
+        LoadROTTMap(level);
+        map = mapplanes[0];
+        for (j=0; j<mapheight; j++)
+        {
+            for(i=0; i<mapwidth; i++)
+            {   tile = *map++;
+                if ((IsMaskedWall(i,j)) && (!IsPlatform(i,j)))
+                {   tally[tile]++;
+                    inlevel[tile][level]=1;
+                }
+
+            }
+        }
+    }
+
+    MapDebug("MWall #   Frequency    Levels\n");
+    MapDebug("----------------------------\n");
+    for (i=0; i<1000; i++)
+        if (tally[i]!=0)
+        {   MapDebug("%4d      %4d         ",i,tally[i]);
+            for(level=0; level < 10; level ++)
+                if (inlevel[i][level])
+                    MapDebug("%d,",level);
+            MapDebug("\n");
+
+        }
+
+}
+
+#endif
+
+/*
+==================
+=
+= PrintTileStats
+=
+==================
+*/
+void PrintTileStats (void)
+{
+    int i,j;
+    word *map;
+    int easytotal;
+    int hardtotal;
+    int tally[1000];
+
+    if (TILESTATS==false)
+        return;
+
+    OpenMapDebug();
+
+    MapDebug("TILE STATS Map Number %d\n",gamestate.mapon);
+    MapDebug("=======================\n\n");
+
+
+// Weapons
+    memset(tally,0,sizeof(tally));
+    MapDebug("=======================\n");
+    MapDebug("= WEAPONS\n");
+    MapDebug("=======================\n");
+    map = mapplanes[1];
+    for (j=0; j<mapheight; j++)
+    {
+        for(i=0; i<mapwidth; i++)
+        {
+            if (IsWeapon(*map))
+                MapDebug("\n %s at %3d,%3d",WeaponName(*map),i,j);
+            map++;
+        }
+    }
+    MapDebug("\n\n");
+// WALLS
+    memset(tally,0,sizeof(tally));
+    MapDebug("=======================\n");
+    MapDebug("= WALLS\n");
+    MapDebug("=======================\n");
+    map = mapplanes[0];
+    for (j=0; j<mapheight; j++)
+    {
+        for(i=0; i<mapwidth; i++)
+        {
+            if (IsWall(i,j)==true)
+                tally[(*map)]++;
+            map++;
+        }
+    }
+    MapDebug("Wall #        Frequency\n");
+    MapDebug("-----------------------\n");
+    for (i=0; i<1000; i++)
+        if (tally[i]!=0)
+            MapDebug("  %4d    %4d\n",i,tally[i]);
+
+// Doors
+    memset(tally,0,sizeof(tally));
+    MapDebug("=======================\n");
+    MapDebug("= DOORS\n");
+    MapDebug("=======================\n");
+    map = mapplanes[0];
+    for (j=0; j<mapheight; j++)
+    {
+        for(i=0; i<mapwidth; i++)
+        {
+            if (IsDoor(i,j)==true)
+                tally[(*map)]++;
+            map++;
+        }
+    }
+    MapDebug("Door #        Frequency\n");
+    MapDebug("-----------------------\n");
+    for (i=0; i<1000; i++)
+        if (tally[i]!=0)
+            MapDebug("  %4d    %4d\n",i,tally[i]);
+
+// MaskedWalls
+    memset(tally,0,sizeof(tally));
+    MapDebug("=======================\n");
+    MapDebug("= MASKEDWALLS\n");
+    MapDebug("=======================\n");
+    map = mapplanes[0];
+    for (j=0; j<mapheight; j++)
+    {
+        for(i=0; i<mapwidth; i++)
+        {
+            if (IsMaskedWall(i,j)==true)
+                if (IsPlatform(i,j)==false)
+                    tally[(*map)]++;
+            map++;
+        }
+    }
+    MapDebug("Mwall #       Frequency\n");
+    MapDebug("-----------------------\n");
+    for (i=0; i<1000; i++)
+        if (tally[i]!=0)
+            MapDebug("  %4d    %4d\n",i,tally[i]);
+// Platforms
+    memset(tally,0,sizeof(tally));
+    MapDebug("=======================\n");
+    MapDebug("= PLATFORMS\n");
+    MapDebug("=======================\n");
+    map = mapplanes[2];
+    for (j=0; j<mapheight; j++)
+    {
+        for(i=0; i<mapwidth; i++)
+        {
+            if (IsPlatform(i,j)==true)
+                tally[(*map)]++;
+            map++;
+        }
+    }
+    MapDebug("Pform #        Frequency\n");
+    MapDebug("-----------------------\n");
+    for (i=0; i<1000; i++)
+        if (tally[i]!=0)
+            MapDebug("  %4d    %4d\n",i,tally[i]);
+
+// Actors
+    memset(tally,0,sizeof(tally));
+    MapDebug("=======================\n");
+    MapDebug("= ACTORS\n");
+    MapDebug("=======================\n");
+    map = mapplanes[1];
+    for (j=0; j<mapheight; j++)
+    {
+        for(i=0; i<mapwidth; i++)
+        {
+            if ((*map)>0)
+                tally[(*map)]++;
+            map++;
+        }
+    }
+
+// Low Guards
+    easytotal=0;
+    hardtotal=0;
+    for (i=108; i<=119; i++)
+        easytotal+=tally[i];
+    for (i=126; i<=137; i++)
+        hardtotal+=tally[i];
+    MapDebug("\nLowGuards\n");
+    MapDebug("-----------------------\n");
+    MapDebug("EasyTotal=%4d\n",easytotal);
+    MapDebug("HardTotal=%4d\n",hardtotal);
+    MapDebug("    Total=%4d\n",easytotal+hardtotal);
+
+// Sneaky Low Guards
+    easytotal=0;
+    hardtotal=0;
+    for (i=120; i<=120; i++)
+        easytotal+=tally[i];
+    for (i=138; i<=138; i++)
+        hardtotal+=tally[i];
+    MapDebug("\nSneakyLowGuards\n");
+    MapDebug("-----------------------\n");
+    MapDebug("EasyTotal=%4d\n",easytotal);
+    MapDebug("HardTotal=%4d\n",hardtotal);
+    MapDebug("    Total=%4d\n",easytotal+hardtotal);
+
+// High Guards
+    easytotal=0;
+    hardtotal=0;
+    for (i=144; i<=155; i++)
+        easytotal+=tally[i];
+    for (i=162; i<=173; i++)
+        hardtotal+=tally[i];
+    MapDebug("\nHighGuards\n");
+    MapDebug("-----------------------\n");
+    MapDebug("EasyTotal=%4d\n",easytotal);
+    MapDebug("HardTotal=%4d\n",hardtotal);
+    MapDebug("    Total=%4d\n",easytotal+hardtotal);
+
+// OverPatrol Guards
+    easytotal=0;
+    hardtotal=0;
+    for (i=216; i<=227; i++)
+        easytotal+=tally[i];
+    for (i=234; i<=245; i++)
+        hardtotal+=tally[i];
+    MapDebug("\nOverPatrolGuards\n");
+    MapDebug("-----------------------\n");
+    MapDebug("EasyTotal=%4d\n",easytotal);
+    MapDebug("HardTotal=%4d\n",hardtotal);
+    MapDebug("    Total=%4d\n",easytotal+hardtotal);
+
+// Strike Guards
+    easytotal=0;
+    hardtotal=0;
+    for (i=180; i<=191; i++)
+        easytotal+=tally[i];
+    for (i=198; i<=204; i++)
+        hardtotal+=tally[i];
+    MapDebug("\nStrikeGuards\n");
+    MapDebug("-----------------------\n");
+    MapDebug("EasyTotal=%4d\n",easytotal);
+    MapDebug("HardTotal=%4d\n",hardtotal);
+    MapDebug("    Total=%4d\n",easytotal+hardtotal);
+
+// TriadEnforcer Guards
+    easytotal=0;
+    hardtotal=0;
+    for (i=288; i<=299; i++)
+        easytotal+=tally[i];
+    for (i=306; i<=317; i++)
+        hardtotal+=tally[i];
+    MapDebug("\nTriadEnforcer Guards\n");
+    MapDebug("-----------------------\n");
+    MapDebug("EasyTotal=%4d\n",easytotal);
+    MapDebug("HardTotal=%4d\n",hardtotal);
+    MapDebug("    Total=%4d\n",easytotal+hardtotal);
+
+// Lightning Guards
+    easytotal=0;
+    hardtotal=0;
+    for (i=324; i<=335; i++)
+        easytotal+=tally[i];
+    for (i=342; i<=353; i++)
+        hardtotal+=tally[i];
+    MapDebug("\nLightningGuards\n");
+    MapDebug("-----------------------\n");
+    MapDebug("EasyTotal=%4d\n",easytotal);
+    MapDebug("HardTotal=%4d\n",hardtotal);
+    MapDebug("    Total=%4d\n",easytotal+hardtotal);
+
+// Random Actors
+    easytotal=0;
+    hardtotal=0;
+    for (i=122; i<=125; i++)
+        easytotal+=tally[i];
+    MapDebug("\nRandom Actors\n");
+    MapDebug("-----------------------\n");
+    MapDebug("    Total=%4d\n",easytotal);
+
+// Monks
+    easytotal=0;
+    hardtotal=0;
+    for (i=360; i<=371; i++)
+        easytotal+=tally[i];
+    for (i=378; i<=389; i++)
+        hardtotal+=tally[i];
+    MapDebug("\nMonks\n");
+    MapDebug("-----------------------\n");
+    MapDebug("EasyTotal=%4d\n",easytotal);
+    MapDebug("HardTotal=%4d\n",hardtotal);
+    MapDebug("    Total=%4d\n",easytotal+hardtotal);
+
+// Fire Monks
+    easytotal=0;
+    hardtotal=0;
+    for (i=396; i<=407; i++)
+        easytotal+=tally[i];
+    for (i=414; i<=425; i++)
+        hardtotal+=tally[i];
+    MapDebug("\nFire Monks\n");
+    MapDebug("-----------------------\n");
+    MapDebug("EasyTotal=%4d\n",easytotal);
+    MapDebug("HardTotal=%4d\n",hardtotal);
+    MapDebug("    Total=%4d\n",easytotal+hardtotal);
+
+// Robo Guards
+    easytotal=0;
+    hardtotal=0;
+    for (i=158; i<=161; i++)
+        easytotal+=tally[i];
+    for (i=176; i<=179; i++)
+        hardtotal+=tally[i];
+    MapDebug("\nRoboGuards\n");
+    MapDebug("-----------------------\n");
+    MapDebug("EasyTotal=%4d\n",easytotal);
+    MapDebug("HardTotal=%4d\n",hardtotal);
+    MapDebug("    Total=%4d\n",easytotal+hardtotal);
+
+// Ballistikrafts
+    easytotal=0;
+    hardtotal=0;
+    for (i=408; i<=411; i++)
+        easytotal+=tally[i];
+    for (i=426; i<=429; i++)
+        hardtotal+=tally[i];
+    MapDebug("\nBallistikrafts\n");
+    MapDebug("-----------------------\n");
+    MapDebug("EasyTotal=%4d\n",easytotal);
+    MapDebug("HardTotal=%4d\n",hardtotal);
+    MapDebug("    Total=%4d\n",easytotal+hardtotal);
+
+// Boulders
+    easytotal=0;
+    hardtotal=0;
+    for (i=278; i<=281; i++)
+        easytotal+=tally[i];
+    for (i=395; i<=395; i++)
+        hardtotal+=tally[i];
+    MapDebug("\nBoulders\n");
+    MapDebug("-----------------------\n");
+    MapDebug("Boulders=%4d\n",easytotal);
+    MapDebug("BoulderHoles=%4d\n",hardtotal);
+
+// PushColumns
+    easytotal=0;
+    hardtotal=0;
+    for (i=285; i<=287; i++)
+        easytotal+=tally[i];
+    for (i=303; i<=305; i++)
+        easytotal+=tally[i];
+    for (i=321; i<=323; i++)
+        easytotal+=tally[i];
+    for (i=339; i<=341; i++)
+        easytotal+=tally[i];
+    for (i=357; i<=359; i++)
+        easytotal+=tally[i];
+    MapDebug("\nPushColumns\n");
+    MapDebug("-----------------------\n");
+    MapDebug("    Total=%4d\n",easytotal);
+
+// Gun Emplacements
+    easytotal=0;
+    hardtotal=0;
+    for (i=194; i<=197; i++)
+        easytotal+=tally[i];
+    for (i=212; i<=215; i++)
+        hardtotal+=tally[i];
+    MapDebug("\nGun Emplacements\n");
+    MapDebug("-----------------------\n");
+    MapDebug("EasyTotal=%4d\n",easytotal);
+    MapDebug("HardTotal=%4d\n",hardtotal);
+    MapDebug("    Total=%4d\n",easytotal+hardtotal);
+
+// 4-way guns
+    easytotal=0;
+    hardtotal=0;
+    for (i=89; i<=89; i++)
+        easytotal+=tally[i];
+    for (i=211; i<=211; i++)
+        hardtotal+=tally[i];
+    MapDebug("\n4-way guns\n");
+    MapDebug("-----------------------\n");
+    MapDebug("EasyTotal=%4d\n",easytotal);
+    MapDebug("HardTotal=%4d\n",hardtotal);
+    MapDebug("    Total=%4d\n",easytotal+hardtotal);
+
+// Stabbers from above
+    MapDebug("\nStabbers from above\n");
+    MapDebug("-----------------------\n");
+    MapDebug("    Total=%4d\n",tally[412]);
+
+// Stabbers from below
+    MapDebug("\nStabbers from below\n");
+    MapDebug("-----------------------\n");
+    MapDebug("    Total=%4d\n",tally[430]);
+
+// Crushing pillar from above
+    MapDebug("\nCrushing pillar from above\n");
+    MapDebug("-----------------------\n");
+    MapDebug("    Total=%4d\n",tally[413]);
+
+// Crushing pillar from below
+    MapDebug("\nCrushing pillar from below\n");
+    MapDebug("-----------------------\n");
+    MapDebug("    Total=%4d\n",tally[431]);
+
+// Above Spinner
+    MapDebug("\nAbove Spinner\n");
+    MapDebug("-----------------------\n");
+    MapDebug("    Total=%4d\n",tally[156]);
+
+// Ground Spinner
+    MapDebug("\nGround Spinner\n");
+    MapDebug("-----------------------\n");
+    MapDebug("    Total=%4d\n",tally[174]);
+
+// Spinner from above
+    MapDebug("\nSpinner from above\n");
+    MapDebug("-----------------------\n");
+    MapDebug("    Total=%4d\n",tally[157]);
+
+// Spinner from below
+    MapDebug("\nSpinner from below\n");
+    MapDebug("-----------------------\n");
+    MapDebug("    Total=%4d\n",tally[175]);
+
+// Bosses
+    easytotal=0;
+    for (i=99; i<=103; i++)
+        easytotal+=tally[i];
+    MapDebug("\nBosses\n");
+    MapDebug("-----------------------\n");
+    MapDebug("    Total=%4d\n",easytotal);
+
+// Spring Boards
+    MapDebug("\nSpring Boards\n");
+    MapDebug("-----------------------\n");
+    MapDebug("    Total=%4d\n",tally[193]);
+
+// Above FlameJets
+    easytotal=0;
+    hardtotal=0;
+    for (i=372; i<=376; i++)
+        easytotal+=tally[i];
+    for (i=390; i<=394; i++)
+        hardtotal+=tally[i];
+    MapDebug("\nFlameJets\n");
+    MapDebug("-----------------------\n");
+    MapDebug("    Above=%4d\n",easytotal);
+    MapDebug("   Ground=%4d\n",hardtotal);
+
+// Fire Chutes
+    easytotal=0;
+    for (i=140; i<=143; i++)
+        easytotal+=tally[i];
+    MapDebug("\nFireChutes\n");
+    MapDebug("-----------------------\n");
+    MapDebug("    Total=%4d\n",easytotal);
+
+// Sprites
+    MapDebug("=======================\n");
+    MapDebug("= SPRITES\n");
+    MapDebug("=======================\n");
+    MapDebug("Sprite #       Frequency\n");
+    MapDebug("-----------------------\n");
+    for (i=1; i<=72; i++)
+        if (tally[i]!=0)
+            MapDebug("  %4d    %4d\n",i,tally[i]);
+    for (i=210; i<=210; i++)
+        if (tally[i]!=0)
+            MapDebug("  %4d    %4d\n",i,tally[i]);
+    for (i=228; i<=233; i++)
+        if (tally[i]!=0)
+            MapDebug("  %4d    %4d\n",i,tally[i]);
+    for (i=246; i<=255; i++)
+        if (tally[i]!=0)
+            MapDebug("  %4d    %4d\n",i,tally[i]);
+    for (i=260; i<=273; i++)
+        if (tally[i]!=0)
+            MapDebug("  %4d    %4d\n",i,tally[i]);
+    for (i=282; i<=284; i++)
+        if (tally[i]!=0)
+            MapDebug("  %4d    %4d\n",i,tally[i]);
+}
+
+//***************************************************************************
+//
+// GetSongForLevel - returns song to play for current level
+//
+//***************************************************************************
+int GetSongForLevel ( void )
+{
+    int i;
+    int num;
+
+    for (i=0; i<mapwidth; i++)
+    {
+        num = MAPSPOT(i,0,2);
+        if ( (num>>8) == 0xba )
+            return (num&0xff);
+    }
+//   Error("GetSongForLevel: could not find song in level %ld\n",gamestate.mapon);
+//   return -1;
+    return 0;
+}
+
+/*
+==================
+=
+= DoSharewareConversionBackgroundPlane
+=
+==================
+*/
+void DoSharewareConversionBackgroundPlane (void)
+{
+    int i,j;
+    word * map;
+
+
+    for (j=0; j<mapheight; j++)
+    {
+        for(i=0; i<mapwidth; i++)
+        {
+            map=&(mapplanes[0][MAPSIZE*(j)+(i)]);
+            switch (*map)
+            {
+
+            // Tom Face
+            case 45:
+                *map=44;
+                break;
+            // Doors
+            case 90:
+            case 92:
+            case 93:
+            case 98:
+            case 99:
+            case 100:
+                *map=91;
+                break;
+            case 103:
+            case 104:
+                *map=101;
+                break;
+            case 154:
+                *map=33;
+                break;
+            case 155:
+                *map=34;
+                break;
+            case 156:
+                *map=35;
+                break;
+
+            //locked doors
+            case 94:
+                *map = 101;
+                *(&(mapplanes[1][MAPSIZE*(j)+(i)]))=29;
+                break;
+            case 95:
+                *map = 101;
+                *(&(mapplanes[1][MAPSIZE*(j)+(i)]))=30;
+                break;
+            case 96:
+                *map = 101;
+                *(&(mapplanes[1][MAPSIZE*(j)+(i)]))=31;
+                break;
+            case 97:
+                *map = 101;
+                *(&(mapplanes[1][MAPSIZE*(j)+(i)]))=32;
+                break;
+            // Tall pillar
+            case 161:
+                *map=0;
+                break;
+            // Masked Walls
+            case 162:
+            case 166:
+                *map=164;
+                break;
+            case 163:
+            case 167:
+            case 170:
+            case 171:
+                *map=165;
+                break;
+
+            // Floors and Ceilings
+            case 180:
+            case 183:
+            case 184:
+                *map=181;
+                break;
+            case 198:
+            case 201:
+            case 202:
+                *map=199;
+                break;
+            case 188:
+                *map=187;
+                break;
+            case 206:
+                *map=205;
+                break;
+            case 190:
+                *map=191;
+                break;
+            case 208:
+                *map=209;
+                break;
+            case 192:
+            case 193:
+            case 194:
+            case 195:
+                *map=189;
+                break;
+            case 210:
+            case 211:
+            case 212:
+            case 213:
+                *map=207;
+                break;
+            // Skys
+            case 237:
+            case 238:
+            case 239:
+                *map=234;
+                break;
+            // Animating walls
+            case 107:
+                *map=106;
+                break;
+            case 228:
+            case 229:
+            case 230:
+            case 242:
+                *map=21;
+                break;
+            case 233:
+                *map=44;
+                break;
+            case 232:
+                *map=231;
+                break;
+            }
+        }
+    }
+}
+
+
+/*
+========================================
+=
+= DoLowMemoryConversionBackgroundPlane
+=
+========================================
+*/
+void DoLowMemoryConversionBackgroundPlane (void)
+{
+    int i,j;
+    word * map;
+
+
+    for (j=0; j<mapheight; j++)
+    {
+        for(i=0; i<mapwidth; i++)
+        {
+            map=&(mapplanes[0][MAPSIZE*(j)+(i)]);
+            switch (*map)
+            {
+            //Walls
+
+            case 2:
+            case 3:
+            case 4:
+                *map = 1;
+                break;
+
+            case 6:
+            case 7:
+            case 8:
+                *map = 5;
+                break;
+
+            case 14:
+            case 15:
+            case 16:
+                *map = 13;
+                break;
+
+            case 18:
+            case 19:
+            case 20:
+                *map = 17;
+                break;
+
+            case 26:
+            case 27:
+            case 28:
+                *map = 25;
+                break;
+
+            case 30:
+            case 31:
+            case 32:
+                *map = 29;
+                break;
+
+#if 0
+            case 37:
+            case 38:
+            case 39:
+                *map = 36;
+                break;
+
+            case 41:
+            case 42:
+            case 43:
+                *map = 40;
+                break;
+#endif
+
+            case 50:
+            case 51:
+            case 52:
+                *map = 49;
+                break;
+
+#if 0
+            case 55:
+            case 56:
+            case 57:
+                *map = 54;
+                break;
+
+            case 59:
+            case 60:
+            case 61:
+                *map = 58;
+                break;
+#endif
+
+            case 66:
+            case 67:
+            case 68:
+                *map = 65;
+                break;
+
+            case 70:
+            case 71:
+                *map = 69;
+                break;
+
+            case 81:
+            case 82:
+            case 84:
+                *map = 83;
+                break;
+
+            // Masked Walls
+            case 158:
+            case 159:
+            case 160:
+            case 168:
+            case 169:
+            case 176:
+            case 178:
+                *map=177;
+                break;
+            case 162:
+            case 163:
+            case 164:
+            case 166:
+            case 167:
+                *map=165;
+                break;
+
+            //Doors
+            case 90:
+            case 91:
+            case 92:
+            case 93:
+            case 98:
+            case 99:
+            case 100:
+            case 101:
+            case 103:
+            case 104:
+            case 33:
+            case 34:
+            case 35:
+            case 154:
+            case 155:
+            case 156:
+                *map = 101;
+                break;
+
+            //Animating Walls
+            case 22:
+            case 23:
+            case 24:
+            case 228:
+            case 229:
+            case 230:
+            case 231:
+            case 232:
+            case 242:
+            case 243:
+            case 244:
+                *map = 21;
+                break;
+            case 233:
+                *map = 44;
+                break;
+
+#if 0
+            //Skys
+            case 234:
+            case 235:
+            case 236:
+            case 237:
+            case 238:
+            case 239:
+                *map=(*(&(mapplanes[0][MAPSIZE*(0)+(0)]))) + 18;
+                break;
+#endif
+            }
+        }
+    }
+}
+
+
+/*
+========================================
+=
+= DoLowMemoryConversionIconPlane
+=
+========================================
+*/
+void DoLowMemoryConversionIconPlane (void)
+{
+#if 0
+    int i,j;
+    word * map;
+
+
+    for (j=0; j<mapheight; j++)
+    {
+        for(i=0; i<mapwidth; i++)
+        {
+            map=&(mapplanes[2][MAPSIZE*(j)+(i)]);
+            switch (*map)
+            {
+            case 13:
+                *(&(mapplanes[0][MAPSIZE*(j)+(i)]))=21;
+                *map=0;
+                break;
+            }
+        }
+    }
+#endif
+}
+
+
+
+/*
+========================================
+=
+= DoLowMemoryConversionForegroundPlane
+=
+========================================
+*/
+
+void DoLowMemoryConversionForegroundPlane (void)
+{
+    int i,j;
+    word * map;
+
+
+    for (j=0; j<mapheight; j++)
+    {
+        for(i=0; i<mapwidth; i++)
+        {
+            map=&MAPSPOT(i,j,1);
+            switch (*map)
+            {
+            // light sourcing
+            case 139:
+                *map=0;
+                break;
+
+            //sprites
+            case 42:
+            case 43:
+            case 63:
+            case 64:
+                *map = 43;
+                break;
+
+            case 246:
+            case 247:
+            case 248:
+            case 264:
+            case 265:
+            case 267:
+            case 283:
+                *map = 266;
+                break;
+
+            //lightning
+            case 377:
+                *map = 0;
+                break;
+
+            // actor guards
+
+            // normal low guards
+            case 108:
+            case 109:
+            case 110:
+            case 111:
+            case 112:
+            case 113:
+            case 114:
+            case 115:
+            case 116:
+            case 117:
+            case 118:
+            case 119:
+
+            case 126:
+            case 127:
+            case 128:
+            case 129:
+            case 130:
+            case 131:
+            case 132:
+            case 133:
+            case 134:
+            case 135:
+            case 136:
+            case 137:
+                (*map)+=216;
+                break;
+
+            // sneaky low guards
+            case 120:
+            case 138:
+                *map = 0;
+                break;
+
+            // normal over patrol
+            case 216:
+            case 217:
+            case 218:
+            case 219:
+            case 220:
+            case 221:
+            case 222:
+            case 223:
+            case 224:
+            case 225:
+            case 226:
+            case 227:
+
+
+            case 234:
+            case 235:
+            case 236:
+            case 237:
+            case 238:
+            case 239:
+            case 240:
+            case 241:
+            case 242:
+            case 243:
+            case 244:
+            case 245:
+                (*map)-=36;
+                break;
+
+                //environment dangers
+
+#if (SHAREWARE==0)
+            case 412:      //spears to firejets
+                *map = 372;
+                break;
+
+            case 430:
+                *map = 390;
+                break;
+
+            case 413:       //cylinders down to firejets
+                *map = 372;
+                break;
+#endif
+
+            case 156:
+            case 157:
+                *map = 372;    //spinblade stabbers to firejets
+                break;
+
+            case 174:
+            case 175:
+                *map = 390;
+                break;
+
+            case 301:          // directional spin blades
+                *map = 373;
+                break;
+
+            case 319:          // directional spin blades
+                *map = 374;
+                break;
+
+            case 337:          // directional spin blades
+                *map = 375;
+                break;
+
+            case 355:          // directional spin blades
+                *map = 376;
+                break;
+
+            case 302:          // directional spin blades
+                *map = 391;
+                break;
+
+            case 320:          // directional spin blades
+                *map = 392;
+                break;
+
+            case 338:          // directional spin blades
+                *map = 393;
+                break;
+
+            case 356:          // directional spin blades
+                *map = 394;
+                break;
+
+            case 194:      // directional emplacements to four-way
+            case 195:      // easy
+            case 196:
+            case 197:
+                *map = 89;
+                break;
+
+            case 212:      // hard
+            case 213:
+            case 214:
+            case 215:
+                *map = 211;
+                break;
+
+            }
+        }
+    }
+}
+
+
+/*
+==================
+=
+= DoSharewareConversionForegroundPlane
+=
+==================
+*/
+void DoSharewareConversionForegroundPlane (void)
+{
+    int i,j;
+    word * map;
+
+
+    for (j=0; j<mapheight; j++)
+    {
+        for(i=0; i<mapwidth; i++)
+        {
+            map=&(mapplanes[1][MAPSIZE*(j)+(i)]);
+            switch (*map)
+            {
+            case 32:  // Crystal Key
+            case 47:  // Knife
+            case 65:  // DIP BALL D
+            case 66:  // DIP BALL I
+            case 67:  // DIP BALL P
+            case 99:  // Boss
+            case 100:  // Boss
+            case 101:  // Boss
+            case 102:  // Boss
+            case 103:  // Boss
+            case 210:  // Scott's head
+            case 278:  // Boulder
+            case 279:  // Boulder
+            case 280:  // Boulder
+            case 281:  // Boulder
+            case 395:  // Boulder
+                *map=0;
+                break;
+            case 41:  // 3-UP to 1-UP
+                *map=40;
+                break;
+            case 46:  // Bat
+                *map=50;
+                break;
+            case 55:  // Split Missile
+                *map=52;
+                break;
+            case 56:  // KES
+                *map=53;
+                break;
+            case 253:  // Dog Mode
+                *map=254;
+                break;
+            case 262:  // Tom Larva
+                *map=263;
+                break;
+            }
+        }
+    }
+}
+
+/*
+========================================
+=
+= DoRegisterConversionBackgroundPlane
+=
+========================================
+*/
+void DoRegisterConversionBackgroundPlane (void)
+{
+    int i,j;
+    word * map;
+
+
+    for (j=0; j<mapheight; j++)
+    {
+        for(i=0; i<mapwidth; i++)
+        {
+            map=&(mapplanes[0][MAPSIZE*(j)+(i)]);
+            switch (*map)
+            {
+            //locked doors
+
+            case 94:
+                *map = 101;
+                *(&(mapplanes[1][MAPSIZE*(j)+(i)]))=29;
+                break;
+            case 95:
+                *map = 101;
+                *(&(mapplanes[1][MAPSIZE*(j)+(i)]))=30;
+                break;
+            case 96:
+                *map = 101;
+                *(&(mapplanes[1][MAPSIZE*(j)+(i)]))=31;
+                break;
+            case 97:
+                *map = 101;
+                *(&(mapplanes[1][MAPSIZE*(j)+(i)]))=32;
+                break;
+
+            case 232:
+                *map = 231; //map chains to machinery
+                break;
+
+            case 228:
+                *map = 230; //map gray water to blue water
+                break;
+
+            }
+        }
+    }
+}
+
+
+
+/*
+========================================
+=
+= DoRegisterConversionForegroundPlane
+=
+========================================
+*/
+void DoRegisterConversionForegroundPlane (void)
+{
+//   int i,j;
+//   word * map;
+
+
+#if 0
+    for (j=0; j<mapheight; j++)
+    {
+        for(i=0; i<mapwidth; i++)
+        {
+            map=&MAPSPOT(i,j,1);
+            switch (*map)
+            {
+            //sprites
+            case 42:
+            case 43:
+            case 63:
+            case 64:
+                *map = 43;
+                break;
+
+            }
+        }
+    }
+#endif
+}
+
+/*
+==================
+=
+= DoSharewareConversion
+=
+==================
+*/
+void DoSharewareConversion (void)
+{
+    DoSharewareConversionBackgroundPlane ();
+    DoSharewareConversionForegroundPlane ();
+}
+
+
+/*
+==================
+=
+= DoRegisterConversion
+=
+==================
+*/
+void DoRegisterConversion (void)
+{
+    DoRegisterConversionBackgroundPlane ();
+    DoRegisterConversionForegroundPlane ();
+}
+
+/*
+=======================
+=
+= DoPanicMapping
+=
+=======================
+*/
+boolean DoPanicMapping (void)
+{
+    if ((lowmemory==true) && (modemgame==false) && (demorecord==false) && (demoplayback==false))
+        return true;
+    else
+        return false;
+}
+
+/*
+=======================
+=
+= DoLowMemoryConversion
+=
+=======================
+*/
+void DoLowMemoryConversion (void)
+{
+    DoLowMemoryConversionBackgroundPlane ();
+    if ((modemgame==false) && (demorecord==false) && (demoplayback==false))
+        DoLowMemoryConversionForegroundPlane ();
+    DoLowMemoryConversionIconPlane ();
+}
+
+extern objtype * enemiesToRes = NULL;
+extern int freeSlot = 0;
+void SetupZomROTTStuff()
+{
+    if (enemiesToRes)
+    {
+        FreeUpResurrectList();
+    }
+    enemiesToRes = calloc(sizeof(objtype), gamestate.killtotal);
+    memset(enemiesToRes, 0, sizeof(enemiesToRes));
+    
+    freeSlot = 0;
+}
+
+/*
+==================
+=
+= SetupGameLevel
+=
+==================
+*/
+
+extern boolean enableZomROTT;
+
+void SetupGameLevel (void)
+{
+    int crud;
+    int i;
+
+#if 0
+    mapwidth = mapheight = 128;
+
+    InsaneDump();
+    /*
+    for(i=0;i<11;i++)
+      {GetEpisode(i);
+       LoadROTTMap(i);
+       MapDebug("\n//================================//");
+       MapDebug("\n//   SHAREWARE LEVEL %d            //",i);
+       MapDebug("\n//================================//\n\n");
+
+       PrintTileStats();
+      }
+    */
+    Error("okay");
+#endif
+
+    insetupgame=true;
+
+    InitializeRNG ();
+
+    if ((demoplayback==true) || (demorecord==true))
+        SetRNGindex ( 0 );
+
+    if (gamestate.randomseed!=-1)
+        SetRNGindex ( gamestate.randomseed );
+
+    if (tedlevel)
+    {
+        GetEpisode (tedlevelnum);
+        LoadROTTMap(tedlevelnum);
+        gamestate.mapon=tedlevelnum;
+    }
+    else
+    {
+        GetEpisode (gamestate.mapon);
+        LoadROTTMap(gamestate.mapon);
+    }
+    if (DoPanicMapping())
+    {
+        DoLowMemoryConversion();
+    }
+    if ( gamestate.Product == ROTT_SHAREWARE )
+    {
+        DoSharewareConversion ();
+    }
+    else
+    {
+        DoRegisterConversion ();
+    }
+    if ( (NewGame) || (lastlevelloaded!=gamestate.mapon) )
+    {
+        SetupPreCache();
+        lastlevelloaded=gamestate.mapon;
+        MU_StartSong(song_level);
+    }
+    shapestart = W_GetNumForName("SHAPSTRT");
+    shapestop = W_GetNumForName("SHAPSTOP");
+    gunsstart=W_GetNumForName("GUNSTART");
+
+    playstate = ex_stillplaying;
+    SNAKELEVEL = 0;
+    whichpath = 0;
+
+    // som of the code / calls below need bufferofs & friends to point
+    // to to the real screen, not the stretch buffer
+    DisableScreenStretch();//bna++ shut off streech mode
+
+    InitializePlayerstates();
+
+    ResetCheatCodes();
+
+    gamestate.killtotal     = gamestate.killcount     = 0;
+    gamestate.secrettotal   = gamestate.secretcount   = 0;
+    gamestate.treasuretotal = gamestate.treasurecount = 0;
+    gamestate.supertotal    = gamestate.supercount    = 0;
+    gamestate.healthtotal   = gamestate.healthcount   = 0;
+    gamestate.missiletotal  = gamestate.missilecount  = 0;
+    gamestate.democratictotal = gamestate.democraticcount = 0;
+    gamestate.planttotal    = gamestate.plantcount    = 0;
+    gamestate.DODEMOCRATICBONUS1 = true;
+    gamestate.DOGROUNDZEROBONUS  = false;
+
+    if (gamestate.mapon == 30)
+        SNAKELEVEL = 1;
+    else if (gamestate.mapon == 32)
+        SNAKELEVEL = 2;
+    else if (gamestate.mapon == 33)
+        SNAKELEVEL = 3;
+
+    InitAreas();
+    InitDoorList();
+    InitElevators();
+    if (loadedgame==false)
+    {
+        InitStaticList ();
+        InitActorList();
+    }
+    memset (tilemap,0,sizeof(tilemap));
+    memset (actorat,0,sizeof(actorat));
+    memset (sprites,0,sizeof(sprites));
+    memset (mapseen,0,sizeof(mapseen));
+    memset (LightsInArea,0,sizeof(LightsInArea));
+
+    PrintTileStats();
+
+    SetupLightLevels();
+
+    crud=(word)MAPSPOT(0,0,1);
+    if ((crud>=90) && (crud<=97))
+    {
+        levelheight=crud-89;
+        maxheight = (levelheight << 6)-32;
+        nominalheight = maxheight-32;
+    }
+    else if ((crud>=450) && (crud<=457))
+    {
+        levelheight=crud-450+9;
+        maxheight = (levelheight << 6)-32;
+        nominalheight = maxheight-32;
+    }
+    else
+        Error("You must specify a valid height sprite icon at (2,0) on map %d\n",gamestate.mapon);
+
+    /*
+       if ( ( BATTLEMODE ) && ( !gamestate.BattleOptions.SpawnDangers ) )
+          {
+          RemoveDangerWalls();
+          }
+    */
+// pheight=maxheight-32;
+    CountAreaTiles();
+    SetupWalls();
+
+    SetupClocks();
+    SetupAnimatedWalls();
+
+    if (loadedgame==false)
+    {
+        SetupSwitches();
+        SetupStatics ();
+        SetupMaskedWalls();
+        SetupDoors();
+        SetupPushWalls();
+        SetupPlayers();
+        if (!BATTLEMODE)
+        {
+            SetupActors();
+            SetupRandomActors();
+        }
+        SetupElevators();
+        SetupDoorLinks();
+        SetupPushWallLinks();
+        FixDoorAreaNumbers();
+        FixMaskedWallAreaNumbers();
+        SetupWindows();
+        SetupLights();
+        SetupInanimateActors();
+    }
+    else {
+        FixTiles();
+    }
+    if (enableZomROTT)
+    {
+        SetupZomROTTStuff();
+    }
+
+    if (gamestate.SpawnEluder || gamestate.SpawnDeluder)
+    {
+//MED
+        for (i=0; i<25; i++)
+            RespawnEluder();
+    }
+
+
+    if ( ( BATTLEMODE ) && ( MapSpecials & MAP_SPECIAL_TOGGLE_PUSHWALLS ) )
+    {
+        ActivateAllPushWalls();
+    }
+    Illuminate();
+
+    if (SNAKELEVEL == 1)
+        SetupSnakePath();
+
+    LoftSprites();
+
+    SetPlaneViewSize();
+    if (loadedgame==false)
+    {
+        ConnectAreas();
+#if (DEVELOPMENT == 1)
+#if (PRECACHETEST == 1)
+        SoftError("Start PreCaching\n");
+#endif
+#endif
+#if (DEVELOPMENT == 1)
+        PrintMapStats();
+#endif
+        PreCache();
+#if (DEVELOPMENT == 1)
+#if (PRECACHETEST == 1)
+        SoftError("Done PreCaching\n");
+#endif
+#endif
+        SetupPlayScreen();
+        SetupScreen(false);
+    }
+
+    if (BATTLEMODE) {
+        SetModemLightLevel ( gamestate.BattleOptions.LightLevel );
+    }
+
+    if (player != NULL) {
+        for (i=0; i<100; i++) {
+            UpdateLightLevel(player->areanumber);
+        }
+    }
+
+    insetupgame=false;
+
+    tedlevel = false;   // turn it off once we have done any ted stuff
+
+    EnableScreenStretch();
+}
+
+
+void InitializePlayerstates(void)
+{   int i;
+    playertype * pstate;
+
+    if (NewGame || (gamestate.mapon == 0) || tedlevel)
+    {   for(i=0; i<numplayers; i++)
+            InitializeWeapons(&PLAYERSTATE[i]);
+    }
+
+    for(i=0; i<numplayers; i++)
+    {
+        pstate=&PLAYERSTATE[i];
+        if (
+            (pstate->missileweapon == wp_godhand)
+#if (SHAREWARE == 0)
+            ||
+            (pstate->missileweapon == wp_dog)
+#endif
+        )
+        {
+            pstate->weapon=pstate->new_weapon=pstate->oldweapon;
+            pstate->missileweapon = pstate->oldmissileweapon;
+
+        }
+
+        ResetPlayerstate(pstate);
+    }
+
+    NewGame = false;
+
+}
+
+
+void SetupSnakePath(void)
+{
+#if (SHAREWARE == 0)
+    int i,j;
+    word *map,tile;
+
+    map = mapplanes[1];
+
+    for(j=0; j<mapheight; j++)
+        for(i=0; i<mapwidth; i++)
+        {   tile = *map++;
+            if ((tile >= 72) && (tile <= 79) && (!tilemap[i][j]))
+            {   SNAKEPATH[whichpath].x = i;
+                SNAKEPATH[whichpath].y = j;
+                whichpath ++;
+            }
+
+        }
+#endif
+}
+
+
+void SetupRandomActors(void)
+{   int i,j;
+    word *map,tile;
+    int starti,totalrandom=0,count=0,ambush,locindex,orig;
+    byte actorpresent[10]= {0},index=0,randomtype,used[100]= {0};
+    _2Dpoint randloc[100];
+
+
+    map = mapplanes[1];
+    map+=5;
+    for(i=0; i<10; i++)
+    {   if (RANDOMACTORTYPE[i])
+            actorpresent[index++]=i;
+    }
+
+
+    if (!index)
+        return;
+
+    for (j=0; j<mapheight; j++)
+    {   if (j==0)
+            starti=5;
+        else
+            starti=0;
+        for(i=starti; i<mapwidth; i++)
+        {   tile= *map++;
+
+            if ((tile >= 122) && (tile <= 125))
+            {   randloc[totalrandom].x = i;
+                randloc[totalrandom].y = j;
+                totalrandom++;
+                if (totalrandom >= 100)
+                    Error("Max random actors (100) exceeded");
+            }
+
+        }
+    }
+
+    orig = totalrandom;
+    switch(gamestate.difficulty)
+    {
+    case gd_baby:
+        totalrandom = 7*totalrandom/10;
+        break;
+
+    case gd_easy:
+        totalrandom = 8*totalrandom/10;
+        break;
+
+    case gd_medium:
+        totalrandom = 9*totalrandom/10;
+        break;
+
+    }
+
+
+    while(count<totalrandom)
+    {   locindex = (GameRandomNumber("rand loc index",0) % orig);
+
+        if (!used[locindex])
+        {   randomtype = actorpresent[GameRandomNumber("SetupRandomActors",0) % index];
+            ambush = (GameRandomNumber("rand actor",0) < 128);
+            i = randloc[locindex].x;
+            j = randloc[locindex].y;
+            tile = mapplanes[1][j*mapwidth + i];
+            SpawnStand(randomtype,i,j,tile-122,ambush);
+            used[locindex] = 1;
+            PreCacheActor(randomtype,0);
+            count++;
+        }
+    }
+
+}
+
+void SetupActors(void)
+{
+    int i,j;
+    word *map,tile;
+    int starti;
+
+
+    //GetRainActors();
+
+    map = mapplanes[1];
+    map+=5;
+
+    for (j=0; j<mapheight; j++)
+    {
+        if (j==0)
+            starti=5;
+        else
+            starti=0;
+        for(i=starti; i<mapwidth; i++)
+        {
+            tile= *map++;
+
+            switch(tile)
+            {
+
+            case 126:
+            case 127:
+            case 128:
+            case 129:
+                if (gamestate.difficulty < gd_hard)
+                    break;
+                tile -= 18;
+
+            case 108:
+            case 109:
+            case 110:
+            case 111:
+                SpawnStand(lowguardobj,i,j,tile-108,0);
+                break;
+
+
+
+
+            case 130:
+            case 131:
+            case 132:
+            case 133:
+                if (gamestate.difficulty < gd_hard)
+                    break;
+                tile -= 18;
+
+            case 112:
+            case 113:
+            case 114:
+            case 115:
+                SpawnPatrol(lowguardobj,i,j,tile-112);
+                break;
+
+            case 134:
+            case 135:
+            case 136:
+            case 137:
+                if (gamestate.difficulty < gd_hard)
+                    break;
+                tile -= 18;
+
+            case 116:
+            case 117:
+            case 118:
+            case 119:
+                SpawnStand(lowguardobj,i,j,tile-116,1);
+                break;
+
+            case 138:
+                if (gamestate.difficulty < gd_hard)
+                    break;
+                tile -= 18;
+
+            case 120:
+                SpawnSneaky(i,j);
+                break;
+
+            case 162:
+            case 163:
+            case 164:
+            case 165:
+                if (gamestate.difficulty < gd_hard)
+                    break;
+                tile -= 18;
+
+            case 144:
+            case 145:
+            case 146:
+            case 147:
+                SpawnStand(highguardobj,i,j,tile-144,0);
+                break;
+
+            case 170:
+            case 171:
+            case 172:
+            case 173:
+                if (gamestate.difficulty < gd_hard)
+                    break;
+                tile -= 18;
+
+            case 152:
+            case 153:
+            case 154:
+            case 155:
+                SpawnStand(highguardobj,i,j,tile-152,1);
+                break;
+
+
+
+            case 166:
+            case 167:
+            case 168:
+            case 169:
+                if (gamestate.difficulty < gd_hard)
+                    break;
+                tile -= 18;
+
+            case 148:
+            case 149:
+            case 150:
+            case 151:
+                SpawnPatrol(highguardobj,i,j,tile-148);
+                break;
+
+            case 176:
+            case 177:
+            case 178:
+            case 179:
+                if (gamestate.difficulty < gd_hard)
+                    break;
+                tile -= 18;
+
+            case 158:
+            case 159:
+            case 160:
+            case 161:
+                SpawnPatrol(roboguardobj,i,j,tile-158);
+                break;
+
+            case 212:
+            case 213:
+            case 214:
+            case 215:
+                if (gamestate.difficulty < gd_hard)
+                    break;
+                tile -= 18;
+
+            case 194:
+            case 195:
+            case 196:
+            case 197:
+                SpawnGunThingy(patrolgunobj,i,j,tile-194);
+                break;
+
+            case 198:
+            case 199:
+            case 200:
+            case 201:
+                if (gamestate.difficulty < gd_hard)
+                    break;
+                tile -= 18;
+
+            case 180:
+            case 181:
+            case 182:
+            case 183:
+                SpawnStand(strikeguardobj,i,j,tile-180,0);
+                break;
+
+            case 206:
+            case 207:
+            case 208:
+            case 209:
+                if (gamestate.difficulty < gd_hard)
+                    break;
+                tile -= 18;
+
+            case 188:
+            case 189:
+            case 190:
+            case 191:
+                SpawnStand(strikeguardobj,i,j,tile-188,1);
+                break;
+
+            case 202:
+            case 203:
+            case 204:
+            case 205:
+                if (gamestate.difficulty < gd_hard)
+                    break;
+                tile -= 18;
+
+            case 184:
+            case 185:
+            case 186:
+            case 187:
+                SpawnPatrol(strikeguardobj,i,j,tile-184);
+                break;
+
+            case 234:
+            case 235:
+            case 236:
+            case 237:
+                if (gamestate.difficulty < gd_hard)
+                    break;
+                tile -= 18;
+
+            case 216:
+            case 217:
+            case 218:
+            case 219:
+                SpawnStand(overpatrolobj,i,j,tile-216,0);
+                break;
+
+            case 242:
+            case 243:
+            case 244:
+            case 245:
+                if (gamestate.difficulty < gd_hard)
+                    break;
+                tile -= 18;
+
+            case 224:
+            case 225:
+            case 226:
+            case 227:
+                SpawnStand(overpatrolobj,i,j,tile-224,1);
+                break;
+
+            case 238:
+            case 239:
+            case 240:
+            case 241:
+                if (gamestate.difficulty < gd_hard)
+                    break;
+                tile -= 18;
+
+            case 220:
+            case 221:
+            case 222:
+            case 223:
+                SpawnPatrol(overpatrolobj,i,j,tile-220);
+                break;
+            case 306:
+            case 307:
+            case 308:
+            case 309:
+                if (gamestate.difficulty < gd_hard)
+                    break;
+                tile -= 18;
+
+            case 288:
+            case 289:
+            case 290:
+            case 291:
+                SpawnStand(triadenforcerobj,i,j,tile-288,0);
+                break;
+
+            case 314:
+            case 315:
+            case 316:
+            case 317:
+                if (gamestate.difficulty < gd_hard)
+                    break;
+                tile -= 18;
+
+            case 296:
+            case 297:
+            case 298:
+            case 299:
+                SpawnStand(triadenforcerobj,i,j,tile-296,1);
+                break;
+
+            case 310:
+            case 311:
+            case 312:
+            case 313:
+                if (gamestate.difficulty < gd_hard)
+                    break;
+                tile -= 18;
+
+            case 292:
+            case 293:
+            case 294:
+            case 295:
+                SpawnPatrol(triadenforcerobj,i,j,tile-292);
+                break;
+
+            case 342:
+            case 343:
+            case 344:
+            case 345:
+                if (gamestate.difficulty < gd_hard)
+                    break;
+                tile -= 18;
+
+            case 324:
+            case 325:
+            case 326:
+            case 327:
+                SpawnStand(blitzguardobj,i,j,tile-324,0);
+                break;
+
+            case 350:
+            case 351:
+            case 352:
+            case 353:
+                if (gamestate.difficulty < gd_hard)
+                    break;
+                tile -= 18;
+
+            case 332:
+            case 333:
+            case 334:
+            case 335:
+                SpawnStand(blitzguardobj,i,j,tile-332,1);
+                break;
+
+            case 346:
+            case 347:
+            case 348:
+            case 349:
+                if (gamestate.difficulty < gd_hard)
+                    break;
+                tile -= 18;
+            case 328:
+            case 329:
+            case 330:
+            case 331:
+                SpawnPatrol(blitzguardobj,i,j,tile-328);
+                break;
+
+            case 378:
+            case 379:
+            case 380:
+            case 381:
+                if (gamestate.difficulty < gd_hard)
+                    break;
+                tile -= 18;
+
+            case 360:
+            case 361:
+            case 362:
+            case 363:
+                SpawnStand(deathmonkobj,i,j,tile-360,0);
+                break;
+
+            case 386:
+            case 387:
+            case 388:
+            case 389:
+                if (gamestate.difficulty < gd_hard)
+                    break;
+                tile -= 18;
+
+            case 368:
+            case 369:
+            case 370:
+            case 371:
+                SpawnStand(deathmonkobj,i,j,tile-368,1);
+                break;
+
+            case 382:
+            case 383:
+            case 384:
+            case 385:
+                if (gamestate.difficulty < gd_hard)
+                    break;
+                tile -= 18;
+
+            case 364:
+            case 365:
+            case 366:
+            case 367:
+                SpawnPatrol(deathmonkobj,i,j,tile-364);
+                break;
+
+            case 414:
+            case 415:
+            case 416:
+            case 417:
+                if (gamestate.difficulty < gd_hard)
+                    break;
+                tile -= 18;
+
+            case 396:
+            case 397:
+            case 398:
+            case 399:
+                SpawnStand(dfiremonkobj,i,j,tile-396,0);
+                break;
+
+
+
+            case 422:
+            case 423:
+            case 424:
+            case 425:
+                if (gamestate.difficulty < gd_hard)
+                    break;
+                tile -= 18;
+
+
+            case 404:
+            case 405:
+            case 406:
+            case 407:
+                SpawnStand(dfiremonkobj,i,j,tile-404,1);
+                break;
+
+            case 418:
+            case 419:
+            case 420:
+            case 421:
+                if (gamestate.difficulty < gd_hard)
+                    break;
+                tile -= 18;
+
+            case 400:
+            case 401:
+            case 402:
+            case 403:
+                SpawnPatrol(dfiremonkobj,i,j,tile-400);
+                break;
+
+            case 99:
+                SpawnStand(b_darianobj,i,j,tile-99,0);
+                break;
+            case 100:
+                SpawnStand(b_heinrichobj,i,j,tile-100,0);
+                break;
+            case 101:
+                SpawnStand(b_darkmonkobj,i,j,tile-101,0);
+                MISCVARS->TOMLOC.x = i;
+                MISCVARS->TOMLOC.y = j;
+                break;
+            case 102:
+                SpawnMultiSpriteActor(b_robobossobj,i,j,tile-102);
+                break;
+
+            case 103:
+                SpawnSnake(i,j);
+                break;
+
+            case 426:
+            case 427:
+            case 428:
+            case 429:
+                if (gamestate.difficulty < gd_hard)
+                    break;
+                tile -= 18;
+
+            case 408:
+            case 409:
+            case 410:
+            case 411:
+                SpawnPatrol(wallopobj,i,j,tile-408);
+                break;
+
+
+            }
+        }
+    }
+}
+
+void SetupStatics(void)
+{
+    int i,j,spawnz;
+    word *map,tile;
+    int starti;
+
+    map = mapplanes[1];
+    map+=5;
+
+    BATTLE_NumCollectorItems = 0;
+    for (j=0; j<mapheight; j++)
+    {
+        if (j==0)
+            starti=5;
+        else
+            starti=0;
+        for(i=starti; i<mapwidth; i++)
+        {
+            tile= *map++;
+            spawnz = (MAPSPOT(i,j,2))?(MAPSPOT(i,j,2)):(-1);
+
+            if ( gamestate.BattleOptions.RandomWeapons )
+            {
+                int num;
+
+                switch( tile )
+                {
+                case 46:
+                case 48:
+                case 49:
+                case 50:
+                case 51:
+                case 52:
+                case 53:
+                case 54:
+                case 55:
+                case 56:
+                    if ( gamestate.Product == ROTT_SHAREWARE )
+                    {
+                        num = ( GameRandomNumber( "Random Weapon", 0 ) % 7 );
+                        tile = SharewareWeaponTiles[ num ];
+                    }
+                    else
+                    {
+                        num = ( GameRandomNumber( "Random Weapon", 1 ) % 10 );
+                        tile = NormalWeaponTiles[ num ];
+                    }
+                    break;
+                }
+            }
+
+            switch (tile)
+            {
+
+            // Add light sourcing to these objects
+
+            case 23:
+            case 24:
+            case 25:
+            case 26:
+            case 27:
+            case 28:
+            case 42:
+            case 43:
+            case 63:
+            case 64:
+                SpawnStatic(i,j,tile-23,spawnz);
+                break;
+
+            case 44:
+                SpawnStatic(i,j,tile-23,spawnz);
+                if (loadedgame == false)
+                {
+                    gamestate.healthtotal ++;
+                    gamestate.democratictotal ++;
+                }
+                break;
+
+
+            case 36:
+            case 37:
+            case 38:
+            case 39:
+                SpawnStatic(i,j,tile-23,spawnz);
+                if (loadedgame == false)
+                    gamestate.healthtotal ++;
+                break;
+
+            case 29:
+            case 30:
+            case 31:
+            case 32:
+                if (IsDoor (i, j) == 0)
+                {
+                    if ( BATTLEMODE )
+                    {
+                        // Spawn empty table
+                        SpawnStatic( i, j, 247 - 246 + 57, spawnz );
+                    }
+                    else
+                    {
+                        // Spawn key table
+                        SpawnStatic( i, j, tile - 23, spawnz );
+                    }
+                }
+                break;
+
+            case 33:
+            case 34:
+            case 35:
+            case 40:
+            case 41:
+            case 45:
+                SpawnStatic(i,j,tile-23,spawnz);
+                break;
+
+            case 46:
+#if (SHAREWARE == 1)
+                Error("\n tried to spawn excalibat at %d,%d in shareware !",i,j);
+#endif
+
+
+                SD_PreCacheSoundGroup(SD_EXCALIBOUNCESND,SD_EXCALIBLASTSND);
+
+
+                PreCacheGroup(W_GetNumForName("EXBAT1"),
+                              W_GetNumForName("EXBAT7"),
+                              cache_patch_t);
+
+
+
+                SpawnStatic(i,j,tile-23,spawnz);
+                if (loadedgame == false)
+                    gamestate.missiletotal ++;
+                break;
+            case 47:
+                PreCacheGroup(W_GetNumForName("KNIFE1"),
+                              W_GetNumForName("KNIFE10"),
+                              cache_patch_t);
+                PreCacheGroup(W_GetNumForName("ESTATUE1"),
+                              W_GetNumForName("ESTATUE8"),
+                              cache_patch_t);
+
+                SpawnStatic(i,j,tile-23,spawnz);
+                break;
+
+            case 48:
+                SD_PreCacheSound(SD_ATKTWOPISTOLSND);
+
+                if ((locplayerstate->player == 1) || (locplayerstate->player == 3))
+                    PreCacheGroup(W_GetNumForName("RFPIST1"),
+                                  W_GetNumForName("LFPIST3"),
+                                  cache_patch_t);
+
+                else if (locplayerstate->player == 2)
+                    PreCacheGroup(W_GetNumForName("RBMPIST1"),
+                                  W_GetNumForName("LBMPIST3"),
+                                  cache_patch_t);
+
+                else
+                    PreCacheGroup(W_GetNumForName("RMPIST1"),
+                                  W_GetNumForName("LMPIST3"),
+                                  cache_patch_t);
+
+                SpawnStatic(i,j,tile-23,spawnz);
+
+                break;
+            case 49:
+
+                SD_PreCacheSound(SD_ATKMP40SND);
+                PreCacheGroup(W_GetNumForName("MP401"),
+                              W_GetNumForName("MP403"),
+                              cache_patch_t);
+                SpawnStatic(i,j,tile-23,spawnz);
+                break;
+
+            case 50:
+                SD_PreCacheSound(SD_MISSILEHITSND);
+                SD_PreCacheSound(SD_MISSILEFLYSND);
+                SD_PreCacheSound(SD_BAZOOKAFIRESND);
+                PreCacheGroup(W_GetNumForName("BAZOOKA1"),
+                              W_GetNumForName("BAZOOKA4"),
+                              cache_patch_t);
+                SpawnStatic(i,j,tile-23,spawnz);
+                if (loadedgame == false)
+                    gamestate.missiletotal ++;
+                break;
+            case 51:
+
+
+                SD_PreCacheSound(SD_MISSILEHITSND);
+                SD_PreCacheSound(SD_MISSILEFLYSND);
+                SD_PreCacheSound(SD_FIREBOMBFIRESND);
+                PreCacheGroup(W_GetNumForName("FBOMB1"),
+                              W_GetNumForName("FBOMB4"),
+                              cache_patch_t);
+                SpawnStatic(i,j,tile-23,spawnz);
+                if (loadedgame == false)
+                    gamestate.missiletotal ++;
+                break;
+            case 52:
+                SD_PreCacheSound(SD_MISSILEHITSND);
+                SD_PreCacheSound(SD_MISSILEFLYSND);
+                SD_PreCacheSound(SD_HEATSEEKFIRESND);
+                PreCacheGroup(W_GetNumForName("HSEEK1"),
+                              W_GetNumForName("HSEEK4"),
+                              cache_patch_t);
+                SpawnStatic(i,j,tile-23,spawnz);
+                if (loadedgame == false)
+                    gamestate.missiletotal ++;
+                break;
+            case 53:
+                SD_PreCacheSound(SD_MISSILEHITSND);
+                SD_PreCacheSound(SD_MISSILEFLYSND);
+                SD_PreCacheSound(SD_DRUNKFIRESND);
+                PreCacheGroup(W_GetNumForName("DRUNK1"),
+                              W_GetNumForName("DRUNK4"),
+                              cache_patch_t);
+                SpawnStatic(i,j,tile-23,spawnz);
+                if (loadedgame == false)
+                    gamestate.missiletotal ++;
+                break;
+            case 54:
+                SD_PreCacheSound(SD_MISSILEHITSND);
+                SD_PreCacheSound(SD_MISSILEFLYSND);
+                SD_PreCacheSound(SD_FLAMEWALLFIRESND);
+                SD_PreCacheSound(SD_FLAMEWALLSND);
+                PreCacheGroup(W_GetNumForName("FIREW1"),
+                              W_GetNumForName("FIREW3"),
+                              cache_patch_t);
+                PreCacheGroup(W_GetNumForName("FWALL1"),
+                              W_GetNumForName("FWALL15"),
+                              cache_patch_t);
+                PreCacheGroup(W_GetNumForName("SKEL1"),
+                              W_GetNumForName("SKEL48"),
+                              cache_patch_t);
+                SpawnStatic(i,j,tile-23,spawnz);
+                if (loadedgame == false)
+                    gamestate.missiletotal ++;
+                break;
+            case 55:
+#if (SHAREWARE == 1)
+                Error("\n tried to spawn split missile at %d,%d in shareware !",i,j);
+#endif
+                SD_PreCacheSound(SD_MISSILEHITSND);
+                SD_PreCacheSound(SD_MISSILEFLYSND);
+                SD_PreCacheSound(SD_SPLITFIRESND);
+                SD_PreCacheSound(SD_SPLITSND);
+                PreCacheGroup(W_GetNumForName("SPLIT1"),
+                              W_GetNumForName("SPLIT4"),
+                              cache_patch_t);
+                SpawnStatic(i,j,tile-23,spawnz);
+                if (loadedgame == false)
+                    gamestate.missiletotal ++;
+                break;
+            case 56:
+#if (SHAREWARE == 1)
+                Error("\n tried to spawn kes at %d,%d in shareware !",i,j);
+#endif
+
+
+
+                SD_PreCacheSound(SD_GRAVSND);
+                SD_PreCacheSound(SD_GRAVHITSND);
+                SD_PreCacheSound(SD_GRAVFIRESND);
+                SD_PreCacheSound(SD_GRAVBUILDSND);
+
+                PreCacheGroup(W_GetNumForName("KES1"),
+                              W_GetNumForName("KES6"),
+                              cache_patch_t);
+                PreCacheGroup(W_GetNumForName("KSPHERE1"),
+                              W_GetNumForName("KSPHERE4"),
+                              cache_patch_t);
+                SpawnStatic(i,j,tile-23,spawnz);
+                if (loadedgame == false)
+                    gamestate.missiletotal ++;
+                break;
+
+            case 57:
+            case 58:
+            case 59:
+            case 60:
+            case 61:
+            case 62:
+            case 65:
+            case 66:
+            case 67:
+                SpawnStatic(i,j,tile-23,spawnz);
+                break;
+
+            case 68:
+            case 69:
+            case 70:
+            case 71:
+                SpawnStatic(i,j,tile-23,spawnz);
+                break;
+
+            case  98:
+                SpawnStatic(i,j,tile-98+49,spawnz);
+                break;
+
+            case 210:
+                SpawnStatic(i,j,stat_scotthead,spawnz);
+                break;
+
+            case 228:
+            case 229:
+            case 230:
+            case 231:
+            case 232:
+            case 233:
+                SpawnStatic(i,j,tile-228+51,spawnz);
+                break;
+            case 246:
+            case 247:
+            case 248:
+            case 249:
+            case 250:
+            case 251:
+                SpawnStatic(i,j,tile-246+57,spawnz);
+                break;
+            case 264:
+            case 265:
+                SpawnStatic(i,j,tile-264+63,spawnz);
+                gamestate.planttotal ++;
+                break;
+
+            case 266:
+                SpawnStatic(i,j,stat_urn,spawnz);
+                break;
+
+            case 268:
+                SpawnStatic(i,j,tile-265+63,spawnz);
+                break;
+
+            case 269:
+                SpawnStatic(i,j,tile-265+63,spawnz);
+                break;
+
+            case 267:
+                SpawnStatic(i,j,stat_emptystatue,spawnz);
+                break;
+
+            case 282:
+                SpawnStatic(i,j,stat_heatgrate,spawnz);
+                break;
+
+            case 283:
+                SpawnStatic(i,j,stat_standardpole,spawnz);
+                break;
+
+            case 284:
+                if ( !BATTLEMODE )
+                {
+                    SpawnStatic(i,j,stat_pit,spawnz);
+                }
+                break;
+
+
+
+
+            case 252:
+                SD_PreCacheSound(SD_GRAVSND);
+                SD_PreCacheSound(SD_GRAVHITSND);
+                SD_PreCacheSoundGroup(SD_GODMODEFIRESND,SD_LOSEMODESND);
+                if ((locplayerstate->player == 1) || (locplayerstate->player ==3))
+                    SD_PreCacheSound(SD_GODWOMANSND);
+                else
+                    SD_PreCacheSound(SD_GODMANSND);
+
+
+                PreCacheGroup(W_GetNumForName("GODHAND1"),
+                              W_GetNumForName("GODHAND8"),
+                              cache_patch_t);
+
+                PreCacheGroup(W_GetNumForName("VAPO1"),
+                              W_GetNumForName("LITSOUL"),
+                              cache_patch_t);
+
+                PreCacheGroup(W_GetNumForName("GODFIRE1"),
+                              W_GetNumForName("GODFIRE4"),
+                              cache_patch_t);
+
+                SpawnStatic(i,j,stat_godmode,spawnz);
+                if (loadedgame == false)
+                    gamestate.supertotal ++;
+                break;
+
+            case 253:
+
+#if (SHAREWARE == 1)
+                Error("DogMode Power up in shareware at x=%d y=%d\n",i,j);
+#endif
+
+                SD_PreCacheSoundGroup(SD_DOGMODEPANTSND,SD_DOGMODELICKSND);
+                if ((locplayerstate->player == 1) || (locplayerstate->player ==3))
+                    SD_PreCacheSound(SD_DOGWOMANSND);
+                else
+                    SD_PreCacheSound(SD_DOGMANSND);
+
+
+
+                PreCacheGroup(W_GetNumForName("DOGNOSE1"),
+                              W_GetNumForName("DOGPAW4"),
+                              cache_patch_t);
+                SpawnStatic(i,j,stat_dogmode,spawnz);
+                if (loadedgame == false)
+                    gamestate.supertotal ++;
+                break;
+
+            case 254:
+                SpawnStatic(i,j,stat_fleetfeet,spawnz);
+                if (loadedgame == false)
+                    gamestate.supertotal ++;
+                break;
+
+            case 255:
+                SpawnStatic(i,j,stat_random,spawnz);
+                if (loadedgame == false)
+                    gamestate.supertotal ++;
+                break;
+
+            case 260:
+                SpawnStatic(i,j,stat_elastic,spawnz);
+                if (loadedgame == false)
+                    gamestate.supertotal ++;
+                break;
+
+            case 261:
+                SpawnStatic(i,j,stat_mushroom,spawnz);
+                if (loadedgame == false)
+                {
+                    gamestate.supertotal ++;
+                    gamestate.democratictotal ++;
+                }
+                break;
+
+
+            case 262:
+                SpawnStatic(i,j,stat_tomlarva,spawnz);
+                break;
+
+            case 263:
+                if (gamestate.SpawnCollectItems)
+                {
+                    SpawnStatic(i,j,stat_collector,spawnz);
+                    LASTSTAT->flags |= FL_COLORED;
+                    LASTSTAT->hitpoints =
+                        ( GameRandomNumber("colors",0) % MAXPLAYERCOLORS );
+                    BATTLE_NumCollectorItems++;
+                }
+                break;
+
+            case 270:
+                SpawnStatic(i,j,stat_bulletproof,spawnz);
+                if (loadedgame == false)
+                    gamestate.supertotal ++;
+                break;
+            case 271:
+                SpawnStatic(i,j,stat_asbesto,spawnz);
+                if (loadedgame == false)
+                    gamestate.supertotal ++;
+                break;
+            case 272:
+                SpawnStatic(i,j,stat_gasmask,spawnz);
+                if (loadedgame == false)
+                    gamestate.supertotal ++;
+                break;
+            case 461:
+                SpawnStatic(i,j,stat_disk,spawnz);
+                break;
+            }
+        }
+    }
+}
+
+
+
+void RaiseSprites( int x, int y, int count, int dir )
+{
+    int a,c;
+    int dx,dy;
+    int h;
+    int i;
+    int xx;
+    int hc;
+    int d;
+
+    dx=0;
+    dy=0;
+    if (dir==1)
+        dx=1;
+    else
+        dy=1;
+
+
+    if (((statobj_t *)sprites[x][y])->z==-65)
+    {
+        c=(maxheight+20)<<8;
+        hc=(count+1)<<7;
+        a=(c<<8)/(hc*hc);
+        for (i=0; i<count; i++)
+        {
+            xx=-hc+((i+1)<<8);
+            h=(c-FixedMulShift(a,(xx*xx),8) )>>8;
+            ((statobj_t *)sprites[x+(dx*i)][y+(dy*i)])->z=maxheight-h;
+        }
+    }
+    else
+    {
+        if (ActorIsSpring(x-(dx),y-(dy)))
+            d=1;
+        else if (ActorIsSpring(x+(dx*count),y+(dy*count)))
+            d=0;
+        else
+            Error("Cannot find a spring board around a ramp ascension near x=%d y=%d\n",x,y);
+
+        hc=((maxheight+20)<<16)/(count+1);
+        h=hc<<1;
+        for (i=0; i<count; i++)
+        {
+            if (d==1)
+                ((statobj_t *)sprites[x+(dx*i)][y+(dy*i)])->z=maxheight-(h>>16);
+            else
+                ((statobj_t *)sprites[x+(dx*(count-i-1))][y+(dy*(count-i-1))])->z=maxheight-(h>>16);
+            h+=hc;
+        }
+    }
+}
+
+void LoftSprites( void )
+{
+    int x,y;
+    int count;
+
+    for(y=1; y<mapheight-1; y++)
+    {
+        for(x=1; x<mapwidth-1; x++)
+        {
+            if (StaticUndefined(x,y))
+            {
+                if (StaticUndefined(x+1,y))
+                {
+                    count=1;
+                    while (StaticUndefined(x+count,y))
+                        count++;
+                    if (count<3)
+                        Error ("Are You kidding me? You are trying to loft <3 sprites in an arc??? \n x=%d y=%d\n",x,y);
+                    RaiseSprites(x,y,count,1);
+                }
+                else if (StaticUndefined(x,y+1))
+                {
+                    count=1;
+                    while (StaticUndefined(x,y+count))
+                        count++;
+                    if (count<3)
+                        Error ("Are You kidding me? You are trying to loft <3 sprites??? \n x=%d y=%d\n",x,y);
+                    RaiseSprites(x,y,count,0);
+                }
+                else
+                    Error ("Sprite Lofter is confused around x=%d y=%d\n",x,y);
+            }
+        }
+    }
+}
+
--- /dev/null
+++ b/rott/rt_ted.h
@@ -1,0 +1,184 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+//***************************************************************************
+//
+//    RT_TED.C - Ted stuff for maps and such
+//
+//***************************************************************************
+
+#include "rottnet.h"
+
+
+#ifndef _rt_ted_public
+#define _rt_ted_public
+
+#define MAXCLOCKS 10
+#define MAXSPAWNLOCATIONS 50
+#define POWERUPTICS  ((VBLCOUNTER*60)+6)
+#define IsPlatform(x,y)  ( (MAPSPOT((x),(y),2)==1) || ((MAPSPOT((x),(y),2)>=4) && (MAPSPOT((x),(y),2)<=9)))
+
+#define EXITTILE             (107)
+#define SECRETEXITTILE       (106)
+
+#define FL_SWITCH      0x01
+#define FL_ON          0x02
+#define FL_REVERSIBLE  0x04
+#define FL_W_DAMAGE    0x08
+#define FL_W_INVERTED  0x10
+#define FL_S_FLIPPED   0x20
+
+
+
+#define MAXTEAMS 11
+
+typedef struct
+{
+    int nummembers;
+    int uniformcolor;
+    int tilex,tiley;
+    byte dir;
+
+} teamtype;
+
+extern teamtype TEAM[MAXPLAYERS];
+
+typedef struct
+{   thingtype   which;
+    byte        flags;
+    byte        hitpoints;
+    word        tile;
+    byte        tilex,tiley;
+
+
+} wall_t;
+
+typedef struct
+{
+    int  number;
+    char mapname[23];
+} mapinfo_t;
+
+typedef struct
+{
+    int  nummaps;
+    mapinfo_t maps[100];
+} mapfileinfo_t;
+
+#define MAXLEVELNAMELENGTH 23
+#define ALLOCATEDLEVELNAMELENGTH 24
+#define NUMPLANES        3
+#define NUMHEADEROFFSETS 100
+
+#define MAP_SPECIAL_TOGGLE_PUSHWALLS 0x0001
+
+typedef struct
+{
+    unsigned used;
+    unsigned CRC;
+    unsigned RLEWtag;
+    unsigned MapSpecials;
+    unsigned planestart[ NUMPLANES ];
+    unsigned planelength[ NUMPLANES ];
+    char     Name[ ALLOCATEDLEVELNAMELENGTH ];
+} RTLMAP;
+
+
+typedef struct
+{   int x,y,dir;
+} _2dvec;
+
+extern _2dvec SPAWNLOC[MAXSPAWNLOCATIONS],FIRST,SECOND;
+
+typedef struct
+{   int time1;
+    int time2;
+    byte points_to_tilex;
+    byte points_to_tiley;
+    int linkindex;
+} str_clock;
+
+
+extern int  numareatiles[NUMAREAS+1];
+extern int  shapestart,shapestop;
+extern int  NUMSPAWNLOCATIONS;
+extern int  mapwidth;
+extern int  mapheight;
+
+extern  wall_t walls[MAXWALLTILES];
+extern str_clock Clocks[MAXCLOCKS];
+extern int LightsInArea[NUMAREAS+1];
+extern int numclocks;
+extern word ELEVATORLOCATION;
+
+extern unsigned short int *mapplanes[3];
+extern int gunsstart;
+extern int elevatorstart;
+extern int spritestop;
+extern int fog;
+extern int lightsource;
+extern int SNAKELEVEL;
+extern boolean insetupgame;
+extern char LevelName[80];
+extern boolean ISRTL;
+
+void PreCacheGroup(int,int,int); // added type
+void AssignTeams(void);
+void LoadTedMap( const char *extension, int mapnum );
+void SetupGameLevel(void);
+void ScanInfoPlane(void);
+void PreCacheLump( int lump, int level, int type ); // added type
+void SetupGameLevelAgain (void);
+void ScanInfoPlaneAgain (void);
+void PreCacheActor( int actor, int which );
+void PreCache( void );
+
+void SetupWalls( void );
+void SetupAnimatedWalls( void );
+void SetupSwitches( void );
+void SetupPlayers( void );
+void SetupMaskedWalls( void );
+void SetupPushWalls( void );
+void SetupPushWallLinks( void );
+void SetupDoors (void);
+void SetupDoorLinks (void);
+void SetupClocks (void);
+void SetupLinkedActors (void);
+void SetupLights(void);
+void SetupWindows ( void );
+
+int GetWallIndex( int texture );
+void PrintMapStats (void);
+void PrintTileStats (void);
+
+void GetMapInfo (mapfileinfo_t * mapinfo);
+void GetMapFileName ( char * filename );
+void SetBattleMapFileName ( char * filename );
+word GetMapCRC ( int num );
+
+int GetNextMap ( int tilex, int tiley );
+void Illuminate();
+
+int GetSongForLevel ( void );
+void CheckHolidays(void);
+boolean IsChristmas(void);
+
+boolean DoPanicMapping (void);
+
+#endif
--- /dev/null
+++ b/rott/rt_util.c
@@ -1,0 +1,1924 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+
+#include "rt_def.h"
+
+#ifdef DOS
+#include <malloc.h>
+#include <dos.h>
+#include <conio.h>
+#include <io.h>
+#include <direct.h>
+#elif USE_SDL
+#include "SDL.h"
+#endif
+
+#include <stdarg.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <time.h>
+#include "watcom.h"
+#include "_rt_util.h"
+#include "rt_util.h"
+#include "isr.h"
+#include "z_zone.h"
+#include "rt_dr_a.h"
+#include "rt_in.h"
+#include "rt_main.h"
+#include "scriplib.h"
+#include "rt_menu.h"
+#include "rt_playr.h"
+#include "version.h"
+#include "develop.h"
+#include "rt_vid.h"
+#include "rt_view.h"
+#include "modexlib.h"
+#include "rt_cfg.h"
+//MED
+#include "memcheck.h"
+
+int    egacolor[16];
+byte   *  origpal;
+FILE   *  errout;
+FILE   *  debugout;
+FILE   *  mapdebugout;
+
+static boolean SoftErrorStarted=false;
+static boolean DebugStarted=false;
+static boolean MapDebugStarted=false;
+
+static unsigned char egargb[48]= { 0x00,0x00,0x00,
+                                   0x00,0x00,0xab,
+                                   0x00,0xab,0x00,
+                                   0x00,0xab,0xab,
+                                   0xab,0x00,0x00,
+                                   0xab,0x00,0xab,
+                                   0xab,0x57,0x00,
+                                   0xab,0xab,0xab,
+                                   0x57,0x57,0x57,
+                                   0x57,0x57,0xff,
+                                   0x57,0xff,0x57,
+                                   0x57,0xff,0xff,
+                                   0xff,0x57,0x57,
+                                   0xff,0x57,0xff,
+                                   0xff,0xff,0x57,
+                                   0xff,0xff,0xff
+                                 };
+
+extern const byte * ROTT_ERR;
+
+#if (DEVELOPMENT == 1)
+int TotalStaticMemory=0;
+#endif
+
+#define SWAP(a,b) \
+   {              \
+   a=(a)^(b);     \
+   b=(a)^(b);     \
+   a=(a)^(b);     \
+   }              \
+
+//******************************************************************************
+//
+// FindDistance
+//
+//******************************************************************************
+
+int FindDistance(int ix, int iy)
+{
+    int   t;
+
+    ix= abs(ix);        /* absolute values */
+    iy= abs(iy);
+
+    if (ix<iy)
+        SWAP(ix,iy);
+
+    t = iy + (iy>>1);
+
+    return (ix - (ix>>5) - (ix>>7)  + (t>>2) + (t>>6));
+}
+
+
+//******************************************************************************
+//
+// Find_3D_Distance
+//
+//******************************************************************************
+
+int Find_3D_Distance(int ix, int iy, int iz)
+{
+    int   t;
+
+    ix= abs(ix);           /* absolute values */
+    iy= abs(iy);
+    iz= abs(iz);
+
+    if (ix<iy)
+        SWAP(ix,iy);
+
+    if (ix<iz)
+        SWAP(ix,iz);
+
+    t = iy + iz;
+
+    return (ix - (ix>>4) + (t>>2) + (t>>3));
+}
+
+//******************************************************************************
+//
+// atan2_appx
+//
+//******************************************************************************
+
+int atan2_appx(int dx, int dy)
+{   int absdx, absdy;
+    fixed angle;
+    fixed ratio;
+
+
+    if (!(dx||dy))
+        return 0;
+    absdx = abs(dx);
+    absdy = abs(dy);
+    if (absdx >= absdy)
+        ratio = FixedDiv2(absdy,absdx);
+    else
+        ratio = FixedDiv2(absdx,absdy);
+
+    if (dx >= 0)
+    {   if (dy >= 0)
+        {   if (absdx >= absdy)
+                angle = ratio;	    // 1st octant
+            else
+                angle = (2<<16) - ratio; // 2nd octant
+        }
+        else
+        {   if (absdx >= absdy)
+                angle = (8<<16) - ratio; // 8th octant
+            else
+                angle = (6<<16) + ratio; // 7th octant
+        }
+    }
+    else
+    {   if (dy >= 0)
+        {   if (absdx >= absdy)
+                angle = (4<<16) - ratio; // 4th octant
+            else
+                angle = (2<<16) + ratio; // 3rd octant
+        }
+        else
+        {   if (absdx >= absdy)
+                angle = (4<<16) + ratio; // 5th octant
+            else
+                angle = (6<<16) - ratio; // 6th octant
+        }
+    }
+
+    return (((int)FixedMul(angle,ANGLESDIV8))&(FINEANGLES-1));
+}
+
+
+
+//******************************************************************************
+//
+// StringsNotEqual
+//
+//******************************************************************************
+boolean StringsNotEqual (char * s1, char * s2, int length)
+{
+    int i;
+
+    for (i=0; i<length; i++)
+        if (s1[i]!=s2[i])
+            return true;
+    return false;
+}
+
+
+
+void markgetch( void )
+{
+    int done;
+    int i;
+
+    done=0;
+    while (done==0)
+    {
+        IN_UpdateKeyboard ();
+        for (i=0; i<127; i++)
+            if (Keyboard[i]==1)
+                done=i;
+    }
+    while (Keyboard[done])
+        IN_UpdateKeyboard ();
+}
+
+/*
+====================
+=
+= FindEGAColors
+=
+====================
+*/
+
+void FindEGAColors ( void )
+{
+    int i;
+
+    for (i=0; i<16; i++)
+        egacolor[i]=BestColor((int)egargb[i*3],(int)egargb[i*3+1],(int)egargb[i*3+2],origpal);
+}
+
+//===========================================================================
+
+
+byte BestColor (int r, int g, int b, byte *palette)
+{
+    int	i;
+    long	dr, dg, db;
+    long	bestdistortion, distortion;
+    int	bestcolor;
+    byte	*pal;
+
+//
+// let any color go to 0 as a last resort
+//
+    bestdistortion = ( (long)WeightR*r*r + (long)WeightG*g*g + (long)WeightB*b*b )*2;
+    bestcolor = 0;
+
+    pal = &palette[0];
+    for (i=0 ; i<= 255 ; i++,pal+=3)
+    {
+        dr = r - (int)pal[0];
+        dg = g - (int)pal[1];
+        db = b - (int)pal[2];
+        distortion = WeightR*dr*dr + WeightG*dg*dg + WeightB*db*db;
+        if (distortion < bestdistortion)
+        {
+            if (!distortion)
+                return i;		// perfect match
+
+            bestdistortion = distortion;
+            bestcolor = i;
+        }
+    }
+
+    return bestcolor;
+}
+
+void ClearGraphicsScreen( void )
+{
+    VL_ClearVideo(0);
+}
+
+void ClearBuffer( char * buf, int size )
+{
+    memset(buf,0,size);
+}
+
+/*
+=============================================================================
+
+						MISC FUNCTIONS
+
+=============================================================================
+*/
+
+/*
+=================
+=
+= Error
+=
+= For abnormal program terminations
+=
+=================
+*/
+
+void Error (char *error, ...)
+{
+    char msgbuf[300];
+    va_list	argptr;
+    char i;
+    int size;
+    char * sptr;
+    char buf[30];
+    int handle;
+    int x,y;
+    int level;
+    static int inerror = 0;
+    char filename[ 128 ];
+
+
+    inerror++;
+    if (inerror > 1)
+        abort();
+
+
+    SetTextMode ();
+#ifdef DOS
+    memcpy ((byte *)0xB8000, &ROTT_ERR, 160*7);
+#elif defined (ANSIESC)
+    DisplayTextSplash (&ROTT_ERR, 7);
+#endif
+    memset (msgbuf, 0, 300);
+
+#ifdef DOS
+    px = ERRORVERSIONCOL-1;
+    py = ERRORVERSIONROW;
+#if (SHAREWARE == 1)
+    UL_printf ("S");
+#else
+    UL_printf ("R");
+#endif
+
+    px = ERRORVERSIONCOL;
+    py = ERRORVERSIONROW;
+#if (BETA == 1)
+    UL_printf ("�");
+#else
+    UL_printf (itoa(ROTTMAJORVERSION,&buf[0],10));
+#endif
+
+    // Skip the dot
+    px++;
+
+    UL_printf (itoa(ROTTMINORVERSION,&buf[0],10));
+#endif
+
+    va_start (argptr, error);
+    vsprintf (&msgbuf[0], error, argptr);
+    va_end (argptr);
+
+    scriptbuffer = &msgbuf[0];
+    size = strlen (msgbuf);
+
+    sptr = script_p = scriptbuffer;
+    scriptend_p = script_p + size;
+    scriptline = 1;
+    endofscript = false;
+    tokenready = false;
+
+    px = ERRORCOL;
+    py = ERRORROW;
+
+    GetToken (true);
+    while (!endofscript)
+    {
+        if ((script_p - sptr) >= 60)
+        {
+            px = ERRORCOL;
+            py++;
+            sptr = script_p;
+        }
+
+        UL_printf (token);
+        px++;                //SPACE
+        GetToken (true);
+    }
+
+#ifdef ANSIESC
+    for (i = 0; i < 8; i++)
+        printf ("\n");
+#endif
+
+    if (player!=NULL)
+    {
+        printf ("Player X     = %lx\n", (long int)player->x);
+        printf ("Player Y     = %lx\n", (long int)player->y);
+        printf ("Player Angle = %lx\n\n", (long int)player->angle);
+    }
+    printf ("Episode      = %ld\n", (long int)gamestate.episode);
+
+    if (gamestate.episode > 1)
+        level = (gamestate.mapon+1) - ((gamestate.episode-1) << 3);
+    else
+        level = gamestate.mapon+1;
+
+    printf ("Area         = %ld\n", (long int)level);
+
+    ShutDown();	// DDOI - moved this so that it doesn't try to access player
+    // which is freed by this function.
+
+#ifdef DOS
+    GetPathFromEnvironment( filename, ApogeePath, ERRORFILE );
+    handle=SafeOpenAppend ( filename );
+    for (y=0; y<16; y++)
+    {
+        for (x=0; x<160; x+=2)
+            SafeWrite(handle,(byte *)0xB8000+(y*160)+x,1);
+        i=10;
+        SafeWrite(handle,&i,1);
+        i=13;
+        SafeWrite(handle,&i,1);
+    }
+
+    close(handle);
+
+    if ( SOUNDSETUP )
+    {
+        getch();
+    }
+
+#endif
+
+#if USE_SDL
+    SDL_Quit();
+#endif
+
+    exit (1);
+}
+
+//#if (SOFTERROR==1)
+
+/*
+=================
+=
+= SoftwareError
+=
+=================
+*/
+void SoftwareError (char *error, ...)
+{
+    va_list	argptr;
+
+    if (SoftErrorStarted==false)
+        return;
+    va_start (argptr, error);
+    vfprintf (errout, error, argptr);
+    va_end (argptr);
+}
+
+//#endif
+
+
+//#if (DEBUG == 1)
+
+/*
+=================
+=
+= DebugError
+=
+=================
+*/
+void DebugError (char *error, ...)
+{
+    va_list	argptr;
+
+    if (DebugStarted==false)
+        return;
+    va_start (argptr, error);
+    vfprintf (debugout, error, argptr);
+    va_end (argptr);
+}
+
+//#endif
+
+/*
+=================
+=
+= OpenSoftError
+=
+=================
+*/
+void OpenSoftError ( void )
+{
+    errout = fopen(SOFTERRORFILE,"wt+");
+    SoftErrorStarted=true;
+}
+
+/*
+=================
+=
+= MapDebug
+=
+=================
+*/
+void MapDebug (char *error, ...)
+{
+    va_list	argptr;
+
+    if (MapDebugStarted==false)
+        return;
+    va_start (argptr, error);
+    vfprintf (mapdebugout, error, argptr);
+    va_end (argptr);
+}
+
+/*
+=================
+=
+= OpenMapDebug
+=
+=================
+*/
+void OpenMapDebug ( void )
+{
+    char filename[ 128 ];
+
+    if (MapDebugStarted==true)
+        return;
+    GetPathFromEnvironment( filename, ApogeePath, MAPDEBUGFILE );
+    mapdebugout = fopen(filename,"wt+");
+    MapDebugStarted=true;
+}
+
+
+/*
+=================
+=
+= StartupSoftError
+=
+=================
+*/
+void StartupSoftError ( void )
+{
+#if (DEBUG == 1)
+    if (DebugStarted==false)
+    {
+        debugout = fopen(DEBUGFILE,"wt+");
+        DebugStarted=true;
+    }
+#endif
+#if (SOFTERROR == 1)
+    if (SoftErrorStarted==false)
+        OpenSoftError();
+#endif
+}
+
+/*
+=================
+=
+= ShutdownSoftError
+=
+=================
+*/
+void ShutdownSoftError ( void )
+{
+    if (DebugStarted==true)
+    {
+        fclose(debugout);
+        DebugStarted=false;
+    }
+    if (SoftErrorStarted==true)
+    {
+        fclose(errout);
+        SoftErrorStarted=false;
+    }
+    if (MapDebugStarted==true)
+    {
+        fclose(mapdebugout);
+        MapDebugStarted=false;
+    }
+}
+
+
+/*
+=================
+=
+= CheckParm
+=
+= Checks for the given parameter in the program's command line arguments
+=
+= Returns the argument number (1 to argc-1) or 0 if not present
+=
+=================
+*/
+
+int CheckParm (char *check)
+{
+    int		i;
+    char	*parm;
+
+    for (i = 1; i<_argc; i++)
+    {
+        parm = _argv[i];
+        if ( !isalpha(*parm) )	// skip - / \ etc.. in front of parm
+        {
+            parm++;
+            if (!*parm)
+                continue;		// parm was only one char
+        }
+
+        if ( !_fstricmp(check,parm) )
+            return i;
+    }
+
+    return 0;
+}
+
+
+
+int SafeOpenAppend (char *_filename)
+{
+    int	handle;
+    char filename[MAX_PATH];
+    strncpy(filename, _filename, sizeof (filename));
+    filename[sizeof (filename) - 1] = '\0';
+    FixFilePath(filename);
+
+    handle = open(filename,O_RDWR | O_BINARY | O_CREAT | O_APPEND
+                  , S_IREAD | S_IWRITE);
+
+    if (handle == -1)
+        Error ("Error opening for append %s: %s",filename,strerror(errno));
+
+    return handle;
+}
+
+int SafeOpenWrite (char *_filename)
+{
+    int	handle;
+    char filename[MAX_PATH];
+    strncpy(filename, _filename, sizeof (filename));
+    filename[sizeof (filename) - 1] = '\0';
+    FixFilePath(filename);
+
+    handle = open(filename,O_RDWR | O_BINARY | O_CREAT | O_TRUNC
+                  , S_IREAD | S_IWRITE);
+
+    if (handle == -1)
+        Error ("Error opening %s: %s",filename,strerror(errno));
+
+    return handle;
+}
+
+int SafeOpenRead (char *_filename)
+{
+    int	handle;
+    char filename[MAX_PATH];
+    strncpy(filename, _filename, sizeof (filename));
+    filename[sizeof (filename) - 1] = '\0';
+    FixFilePath(filename);
+
+    handle = open(filename,O_RDONLY | O_BINARY);
+
+    if (handle == -1)
+        Error ("Error opening %s: %s",filename,strerror(errno));
+
+    return handle;
+}
+
+
+void SafeRead (int handle, void *buffer, long count)
+{
+    unsigned	iocount;
+
+    while (count)
+    {
+        iocount = count > 0x8000 ? 0x8000 : count;
+        if (read (handle,buffer,iocount) != (int)iocount)
+            Error ("File read failure reading %ld bytes",count);
+        buffer = (void *)( (byte *)buffer + iocount );
+        count -= iocount;
+    }
+}
+
+
+void SafeWrite (int handle, void *buffer, long count)
+{
+    unsigned	iocount;
+
+    while (count)
+    {
+        iocount = count > 0x8000 ? 0x8000 : count;
+        if (write (handle,buffer,iocount) != (int)iocount)
+            Error ("File write failure writing %ld bytes",count);
+        buffer = (void *)( (byte *)buffer + iocount );
+        count -= iocount;
+    }
+}
+
+void SafeWriteString (int handle, char * buffer)
+{
+    unsigned	iocount;
+
+    iocount=strlen(buffer);
+    if (write (handle,buffer,iocount) != (int)iocount)
+        Error ("File write string failure writing %s\n",buffer);
+}
+
+void *SafeMalloc (long size)
+{
+    void *ptr;
+
+    if (zonememorystarted==false)
+        Error("Called SafeMalloc without starting zone memory\n");
+    ptr = Z_Malloc (size,PU_STATIC,NULL);
+
+    if (!ptr)
+        Error ("SafeMalloc failure for %lu bytes",size);
+
+    return ptr;
+}
+
+void *SafeLevelMalloc (long size)
+{
+    void *ptr;
+
+    if (zonememorystarted==false)
+        Error("Called SafeLevelMalloc without starting zone memory\n");
+    ptr = Z_LevelMalloc (size,PU_STATIC,NULL);
+
+    if (!ptr)
+        Error ("SafeLevelMalloc failure for %lu bytes",size);
+
+    return ptr;
+}
+
+void SafeFree (void * ptr)
+{
+    if ( ptr == NULL )
+        Error ("SafeFree : Tried to free a freed pointer\n");
+
+    Z_Free (ptr);
+}
+
+/*
+==============
+=
+= LoadFile
+=
+==============
+*/
+
+long	LoadFile (char *filename, void **bufferptr)
+{
+    int		handle;
+    long	length;
+
+    handle = SafeOpenRead (filename);
+    length = filelength (handle);
+    *bufferptr = SafeMalloc (length);
+    SafeRead (handle,*bufferptr, length);
+    close (handle);
+    return length;
+}
+
+
+/*
+==============
+=
+= SaveFile
+=
+==============
+*/
+
+void	SaveFile (char *filename, void *buffer, long count)
+{
+    int		handle;
+
+    handle = SafeOpenWrite (filename);
+    SafeWrite (handle, buffer, count);
+    close (handle);
+}
+
+
+void FixFilePath(char *filename)
+{
+#if PLATFORM_UNIX
+    char *ptr;
+    char *lastsep = filename;
+
+    if ((!filename) || (*filename == '\0'))
+        return;
+
+    if (access(filename, F_OK) == 0)  /* File exists; we're good to go. */
+        return;
+
+    for (ptr = filename; 1; ptr++)
+    {
+        if (*ptr == '\\')
+            *ptr = PATH_SEP_CHAR;
+
+        if ((*ptr == PATH_SEP_CHAR) || (*ptr == '\0'))
+        {
+            char pch = *ptr;
+            struct dirent *dent = NULL;
+            DIR *dir;
+
+            if ((pch == PATH_SEP_CHAR) && (*(ptr + 1) == '\0'))
+                return; /* eos is pathsep; we're done. */
+
+            if (lastsep == ptr)
+                continue;  /* absolute path; skip to next one. */
+
+            *ptr = '\0';
+            if (lastsep == filename) {
+                dir = opendir((*lastsep == PATH_SEP_CHAR) ? ROOTDIR : CURDIR);
+
+                if (*lastsep == PATH_SEP_CHAR) {
+                    lastsep++;
+                }
+            }
+            else
+            {
+                *lastsep = '\0';
+                dir = opendir(filename);
+                *lastsep = PATH_SEP_CHAR;
+                lastsep++;
+            }
+
+            if (dir == NULL)
+            {
+                *ptr = PATH_SEP_CHAR;
+                return;  /* maybe dir doesn't exist? give up. */
+            }
+
+            while ((dent = readdir(dir)) != NULL)
+            {
+                if (strcasecmp(dent->d_name, lastsep) == 0)
+                {
+                    /* found match; replace it. */
+                    strcpy(lastsep, dent->d_name);
+                    break;
+                }
+            }
+
+            closedir(dir);
+            *ptr = pch;
+            lastsep = ptr;
+
+            if (dent == NULL)
+                return;  /* no match. oh well. */
+
+            if (pch == '\0')  /* eos? */
+                return;
+        }
+    }
+#endif
+}
+
+
+#if PLATFORM_DOS
+/* no-op. */
+
+#elif PLATFORM_WIN32
+int _dos_findfirst(char *filename, int x, struct find_t *f)
+{
+    long rc = _findfirst(filename, &f->data);
+    f->handle = rc;
+    if (rc != -1)
+    {
+        strncpy(f->name, f->data.name, sizeof (f->name) - 1);
+        f->name[sizeof (f->name) - 1] = '\0';
+        return(0);
+    }
+    return(1);
+}
+
+int _dos_findnext(struct find_t *f)
+{
+    int rc = 0;
+    if (f->handle == -1)
+        return(1);   /* invalid handle. */
+
+    rc = _findnext(f->handle, &f->data);
+    if (rc == -1)
+    {
+        _findclose(f->handle);
+        f->handle = -1;
+        return(1);
+    }
+
+    strncpy(f->name, f->data.name, sizeof (f->name) - 1);
+    f->name[sizeof (f->name) - 1] = '\0';
+    return(0);
+}
+
+#elif PLATFORM_UNIX
+int _dos_findfirst(char *filename, int x, struct find_t *f)
+{
+    char *ptr;
+
+    if (strlen(filename) >= sizeof (f->pattern))
+        return(1);
+
+    strcpy(f->pattern, filename);
+    FixFilePath(f->pattern);
+    ptr = strrchr(f->pattern, PATH_SEP_CHAR);
+
+    if (ptr == NULL)
+    {
+        ptr = filename;
+        f->dir = opendir(CURDIR);
+    }
+    else
+    {
+        *ptr = '\0';
+        f->dir = opendir(f->pattern);
+        memmove(f->pattern, ptr + 1, strlen(ptr + 1) + 1);
+    }
+
+    return(_dos_findnext(f));
+}
+
+
+static int check_pattern_nocase(const char *x, const char *y)
+{
+    if ((x == NULL) || (y == NULL))
+        return(0);  /* not a match. */
+
+    while ((*x) && (*y))
+    {
+        if (*x == '*')
+            Error("Unexpected wildcard!");  /* FIXME? */
+
+        else if (*x == '?')
+        {
+            if (*y == '\0')
+                return(0);  /* anything but EOS is okay. */
+        }
+
+        else
+        {
+            if (toupper((int) *x) != toupper((int) *y))
+                return(0);  /* not a match. */
+        }
+
+        x++;
+        y++;
+    }
+
+    return(*x == *y);  /* it's a match (both should be EOS). */
+}
+
+int _dos_findnext(struct find_t *f)
+{
+    struct dirent *dent;
+
+    if (f->dir == NULL)
+        return(1);  /* no such dir or we're just done searching. */
+
+    while ((dent = readdir(f->dir)) != NULL)
+    {
+        if (check_pattern_nocase(f->pattern, dent->d_name))
+        {
+            if (strlen(dent->d_name) < sizeof (f->name))
+            {
+                strcpy(f->name, dent->d_name);
+                return(0);  /* match. */
+            }
+        }
+    }
+
+    closedir(f->dir);
+    f->dir = NULL;
+    return(1);  /* no match in whole directory. */
+}
+#else
+#error please define for your platform.
+#endif
+
+
+#if !PLATFORM_DOS
+void _dos_getdate(struct dosdate_t *date)
+{
+    time_t curtime = time(NULL);
+    struct tm *tm;
+
+    if (date == NULL) {
+        return;
+    }
+
+    memset(date, 0, sizeof(struct dosdate_t));
+
+    if ((tm = localtime(&curtime)) != NULL) {
+        date->day = tm->tm_mday;
+        date->month = tm->tm_mon + 1;
+        date->year = tm->tm_year + 1900;
+        date->dayofweek = tm->tm_wday + 1;
+    }
+}
+#endif
+
+
+void GetPathFromEnvironment( char *fullname, const char *envname, const char *filename )
+{
+
+#ifdef DOS
+    char *path;
+    path = getenv( envname );
+#else
+    const char *path;
+    path = envname;
+#endif
+
+    if ( path != NULL )
+    {
+        strcpy( fullname, path );
+        if ( fullname[ strlen( fullname ) - 1 ] != PATH_SEP_CHAR )
+        {
+            strcat( fullname, PATH_SEP_STR );
+        }
+        strcat( fullname, filename );
+    }
+    else
+    {
+        strcpy( fullname, filename );
+    }
+
+    FixFilePath(fullname);
+}
+
+void DefaultExtension (char *path, char *extension)
+{
+    char	*src;
+//
+// if path doesn't have a .EXT, append extension
+// (extension should include the .)
+//
+    src = path + strlen(path) - 1;
+
+    while (*src != PATH_SEP_CHAR && src != path)
+    {
+        if (*src == '.')
+            return;			// it has an extension
+        src--;
+    }
+
+    strcat (path, extension);
+}
+
+void DefaultPath (char *path, char *basepath)
+{
+    char	temp[128];
+
+    if (path[0] == PATH_SEP_CHAR)
+        return;							// absolute path location
+    strcpy (temp,path);
+    strcpy (path,basepath);
+    strcat (path,temp);
+}
+
+
+void ExtractFileBase (char *path, char *dest)
+{
+    char	*src;
+    int		length;
+
+    src = path + strlen(path) - 1;
+
+//
+// back up until a \ or the start
+//
+    while (src != path && *(src-1) != PATH_SEP_CHAR)
+        src--;
+
+//
+// copy up to eight characters
+//
+    memset (dest,0,8);
+    length = 0;
+    while (*src && *src != '.')
+    {
+        if (++length == 9)
+            Error ("Filename base of %s >8 chars",path);
+        *dest++ = toupper(*src++);
+    }
+}
+
+
+/*
+==============
+=
+= ParseNum / ParseHex
+=
+==============
+*/
+
+long ParseHex (char *hex)
+{
+    char	*str;
+    long	num;
+
+    num = 0;
+    str = hex;
+
+    while (*str)
+    {
+        num <<= 4;
+        if (*str >= '0' && *str <= '9')
+            num += *str-'0';
+        else if (*str >= 'a' && *str <= 'f')
+            num += 10 + *str-'a';
+        else if (*str >= 'A' && *str <= 'F')
+            num += 10 + *str-'A';
+        else
+            Error ("Bad hex number: %s",hex);
+        str++;
+    }
+
+    return num;
+}
+
+
+long ParseNum (char *str)
+{
+    if (str[0] == '$')
+        return ParseHex (str+1);
+    if (str[0] == '0' && str[1] == 'x')
+        return ParseHex (str+2);
+    return atol (str);
+}
+
+
+#if (BYTE_ORDER == LITTLE_ENDIAN)
+#define KeepShort IntelShort
+#define SwapShort MotoShort
+#define KeepLong IntelLong
+#define SwapLong MotoLong
+#else
+#define KeepShort MotoShort
+#define SwapShort IntelShort
+#define KeepLong MotoLong
+#define SwapLong IntelLong
+#endif
+
+short	SwapShort (short l)
+{
+    byte	b1,b2;
+
+    b1 = l&255;
+    b2 = (l>>8)&255;
+
+    return (b1<<8) + b2;
+}
+
+short	KeepShort (short l)
+{
+    return l;
+}
+
+
+int	SwapLong (int l)
+{
+    byte	b1,b2,b3,b4;
+
+    b1 = l&255;
+    b2 = (l>>8)&255;
+    b3 = (l>>16)&255;
+    b4 = (l>>24)&255;
+
+    return ((int)b1<<24) + ((int)b2<<16) + ((int)b3<<8) + b4;
+}
+
+int	KeepLong (int l)
+{
+    return l;
+}
+
+
+#undef KeepShort
+#undef KeepLong
+#undef SwapShort
+#undef SwapLong
+
+void SwapIntelLong(int *l)
+{
+    *l = IntelLong(*l);
+}
+
+void SwapIntelShort(short *s)
+{
+    *s = IntelShort(*s);
+}
+
+void SwapIntelLongArray(int *l, int num)
+{
+    while (num--) {
+        SwapIntelLong(l);
+        l++;
+    }
+}
+
+void SwapIntelShortArray(short *s, int num)
+{
+    while (num--) {
+        SwapIntelShort(s);
+        s++;
+    }
+}
+
+/*
+============================================================================
+
+						BASIC GRAPHICS
+
+============================================================================
+*/
+
+/*
+==============
+=
+= GetaPalette
+=
+= Return an 8 bit / color palette
+=
+==============
+*/
+
+void GetaPalette (byte *palette)
+{
+#ifdef DOS
+    int	i;
+
+    OUTP (PEL_READ_ADR,0);
+    for (i=0 ; i<768 ; i++)
+        palette[i] = inp (PEL_DATA)<<2;
+#else
+    int i;
+    SDL_Palette *pal = SDL_GetVideoSurface()->format->palette;
+
+    for (i = 0; i < 256; i++) {
+        palette[0] = pal->colors[i].r;
+        palette[1] = pal->colors[i].g;
+        palette[2] = pal->colors[i].b;
+
+        palette += 3;
+    }
+#endif
+}
+
+/*
+==============
+=
+= SetaPalette
+=
+= Sets an 8 bit / color palette
+=
+==============
+*/
+
+void SetaPalette (byte *pal)
+{
+#ifdef DOS
+    int	i;
+
+    OUTP (PEL_WRITE_ADR,0);
+    for (i=0 ; i<768 ; i++)
+        OUTP (PEL_DATA, pal[i]>>2);
+#else
+    SDL_Color cmap[256];
+    int i;
+
+    for (i = 0; i < 256; i++)
+    {
+        cmap[i].r = pal[i*3+0];
+        cmap[i].g = pal[i*3+1];
+        cmap[i].b = pal[i*3+2];
+    }
+
+    SDL_SetColors (SDL_GetVideoSurface (), cmap, 0, 256);
+#endif
+}
+
+void GetPalette(char * palette)
+{
+#ifdef DOS
+    int i;
+
+    OUTP(0x03c7,0);
+    for (i=0; i<256*3; i++)
+        *(palette+(unsigned char)i)=inp(0x3c9)<<2;
+#else
+    int i;
+    SDL_Palette *pal = SDL_GetVideoSurface()->format->palette;
+
+    for (i = 0; i < 256; i++) {
+        palette[0] = pal->colors[i].r;
+        palette[1] = pal->colors[i].g;
+        palette[2] = pal->colors[i].b;
+
+        palette += 3;
+    }
+#endif
+}
+
+void SetPalette ( char * pal )
+{
+    VL_SetPalette (pal);
+}
+
+
+
+//******************************************************************************
+//
+// US_CheckParm() - checks to see if a string matches one of a set of
+//    strings. The check is case insensitive. The routine returns the
+//    index of the string that matched, or -1 if no matches were found
+//
+//******************************************************************************
+
+int US_CheckParm (char *parm, char **strings)
+{
+    char  cp,cs,
+          *p,*s;
+    int      i;
+    int      length;
+
+    length=strlen(parm);
+    while ( (!isalpha(*parm)) && (length>0)) // Skip non-alphas
+    {
+        length--;
+        parm++;
+    }
+
+    for (i = 0; *strings && **strings; i++)
+    {
+        for (s = *strings++,p = parm,cs = cp = 0; cs == cp;)
+        {
+            cs = *s++;
+            if (!cs)
+                return(i);
+            cp = *p++;
+
+            if (isupper(cs))
+                cs = tolower(cs);
+            if (isupper(cp))
+                cp = tolower(cp);
+        }
+    }
+    return(-1);
+}
+
+/*
+=============================================================================
+
+                  PALETTE OPS
+
+      To avoid snow, do a WaitVBL BEFORE calling these
+
+=============================================================================
+*/
+
+
+/*
+=================
+=
+= VL_FillPalette
+=
+=================
+*/
+
+void VL_FillPalette (int red, int green, int blue)
+{
+#ifdef DOS
+    int   i;
+
+    OUTP (PEL_WRITE_ADR,0);
+    for (i=0; i<256; i++)
+    {
+        OUTP (PEL_DATA,red);
+        OUTP (PEL_DATA,green);
+        OUTP (PEL_DATA,blue);
+    }
+#else
+    SDL_Color cmap[256];
+    int i;
+
+    for (i = 0; i < 256; i++)
+    {
+        cmap[i].r = red << 2;
+        cmap[i].g = green << 2;
+        cmap[i].b = blue << 2;
+    }
+
+    SDL_SetColors (SDL_GetVideoSurface (), cmap, 0, 256);
+#endif
+}
+
+//===========================================================================
+
+/*
+=================
+=
+= VL_SetColor
+=
+=================
+*/
+
+void VL_SetColor  (int color, int red, int green, int blue)
+{
+#ifdef DOS
+    OUTP (PEL_WRITE_ADR,color);
+    OUTP (PEL_DATA,red);
+    OUTP (PEL_DATA,green);
+    OUTP (PEL_DATA,blue);
+#else
+    STUB_FUNCTION;
+#endif
+}
+
+//===========================================================================
+
+/*
+=================
+=
+= VL_GetColor
+=
+=================
+*/
+
+void VL_GetColor  (int color, int *red, int *green, int *blue)
+{
+#ifdef DOS
+    OUTP (PEL_READ_ADR,color);
+    *red   = inp (PEL_DATA);
+    *green = inp (PEL_DATA);
+    *blue  = inp (PEL_DATA);
+#else
+    STUB_FUNCTION;
+#endif
+}
+
+//===========================================================================
+
+/*
+=================
+=
+= VL_NormalizePalette
+=
+=================
+*/
+
+void VL_NormalizePalette (byte *palette)
+{
+    int   i;
+
+    for (i = 0; i < 768; i++)
+        *(palette+i)=(*(palette+i))>>2;
+}
+
+
+/*
+=================
+=
+= VL_SetPalette
+=
+= If fast palette setting has been tested for, it is used
+= -some cards don't like outsb palette setting-
+=
+=================
+*/
+
+void VL_SetPalette (byte *palette)
+{
+#ifdef DOS
+    int   i;
+
+    OUTP (PEL_WRITE_ADR, 0);
+
+    for (i = 0; i < 768; i++)
+    {
+        OUTP (PEL_DATA, gammatable[(gammaindex<<6)+(*palette++)]);
+    }
+#else
+    SDL_Color cmap[256];
+    int i;
+
+    for (i = 0; i < 256; i++)
+    {
+        cmap[i].r = gammatable[(gammaindex<<6)+(*palette++)] << 2;
+        cmap[i].g = gammatable[(gammaindex<<6)+(*palette++)] << 2;
+        cmap[i].b = gammatable[(gammaindex<<6)+(*palette++)] << 2;
+    }
+
+    SDL_SetColors (SDL_GetVideoSurface (), cmap, 0, 256);
+#endif
+}
+
+
+//===========================================================================
+
+/*
+=================
+=
+= VL_GetPalette
+=
+= This does not use the port string instructions,
+= due to some incompatabilities
+=
+=================
+*/
+
+void VL_GetPalette (byte *palette)
+{
+#ifdef DOS
+    int   i;
+
+    OUTP (PEL_READ_ADR, 0);
+
+    for (i = 0; i < 768; i++)
+        *palette++ = inp (PEL_DATA);
+#else
+    int i;
+    SDL_Palette *pal = SDL_GetVideoSurface()->format->palette;
+
+    for (i = 0; i < 256; i++) {
+        palette[0] = pal->colors[i].r >> 2;
+        palette[1] = pal->colors[i].g >> 2;
+        palette[2] = pal->colors[i].b >> 2;
+
+        palette += 3;
+    }
+#endif
+}
+
+
+/*
+=================
+=
+= UL_DisplayMemoryError ()
+=
+=================
+*/
+
+void UL_DisplayMemoryError ( int memneeded )
+{
+#ifdef DOS
+    char buf[4000];
+    int i;
+
+    ShutDown ();
+    TextMode ();
+
+    for (i = 0; i < 19; i++)
+        printf ("\n");
+
+    memcpy (buf, &ROTT_ERR, 4000);
+    memcpy ((byte *)0xB8000, &buf[160*7], 4000-(160*7));
+
+    px = ERRORVERSIONCOL;
+    py = ERRORVERSIONROW;
+#if (BETA == 1)
+    UL_printf ("�");
+#else
+    UL_printf (itoa(ROTTMAJORVERSION,&buf[0],10));
+#endif
+    px++;
+
+    UL_printf (itoa(ROTTMINORVERSION,&buf[0],10));
+
+    px = LOWMEMORYCOL;
+    py = LOWMEMORYROW;
+    UL_printf ("You need ");
+    UL_printf (itoa(memneeded,&buf[0],10));
+    UL_printf (" bytes more memory");
+    if ( SOUNDSETUP )
+    {
+        getch();
+    }
+#else
+    STUB_FUNCTION;
+#endif
+    exit (0);
+}
+
+
+/*
+=================
+=
+= UL_printf
+=
+=================
+*/
+
+void UL_printf (byte *str)
+{
+#ifdef DOS
+    byte *s;
+    byte *screen;
+
+    s = str;
+    screen = (byte *)(0xB8000 + (py*160) + (px<<1));
+
+    while (*s)
+    {
+        *screen = *s;
+        s++;
+        screen += 2;
+        px++;
+
+        if ((*s < 32) && (*s > 0))
+            s++;
+    }
+#else
+#ifdef ANSIESC
+    printf ("\x1b[%d;%dH%s",py,px,str);
+#else
+    printf ("%s ",str);	// Hackish but works - DDOI
+#endif
+#endif
+}
+
+/*
+=================
+=
+= UL_ColorBox
+=
+=================
+*/
+
+void UL_ColorBox (int x, int y, int w, int h, int color)
+{
+#ifdef DOS
+    byte *screen;
+    int i,j;
+
+
+    for (j=0; j<h; j++)
+    {
+        screen = (byte *)(0xB8000 + ((y+j)*160) + (x<<1) + 1);
+        for (i=0; i<w; i++)
+        {
+            *screen = (byte)color;
+            screen+=2;
+        }
+    }
+#elif defined (ANSIESC)
+    int i,j;
+
+
+    for (j=0; j<h; j++)
+    {
+        for (i=0; i<w; i++)
+        {
+            printf ("\x1b[%d;%dH",y+j,x+i);
+            put_dos2ansi(color);
+        }
+    }
+#endif
+}
+
+//******************************************************************************
+//
+// SideOfLine
+//
+//******************************************************************************
+
+int SideOfLine(int x1, int y1, int x2, int y2, int x3, int y3)
+{
+    int a1,b1,c1;
+
+    /* Compute a1, b1, c1, where line joining points 1 and 2
+     * is "a1 x  +  b1 y  +  c1  =  0".
+     */
+
+    a1 = y2 - y1;
+    b1 = x1 - x2;
+    c1 = FixedMulShift(x2,y1,16) - FixedMulShift(x1,y2,16);
+
+    return SGN(FixedMulShift(a1,x3,16) + FixedMulShift(b1,y3,16) + c1);
+}
+
+
+
+//******************************************************************************
+//
+// HSORT - heap sort
+//
+//******************************************************************************
+
+typedef int (*PFI)();           /* pointer to a function returning int  */
+typedef void (*PFV)();           /* pointer to a function returning int  */
+static PFI Comp;                        /* pointer to comparison routine                */
+static PFV Switch;                        /* pointer to comparison routine                */
+static int Width;                       /* width of an object in bytes                  */
+static char *Base;                      /* pointer to element [-1] of array             */
+
+
+static void newsift_down(L,U) int L,U;
+{   int c;
+
+    while(1)
+    {   c=L+L;
+        if(c>U) break;
+        if( (c+Width <= U) && ((*Comp)(Base+c+Width,Base+c)>0) ) c+= Width;
+        if ((*Comp)(Base+L,Base+c)>=0) break;
+        (*Switch)(Base+L, Base+c);
+        L=c;
+    }
+}
+
+void hsort(char * base, int nel, int width, int (*compare)(), void (*switcher)())
+{
+    static int i,n,stop;
+    /*      Perform a heap sort on an array starting at base.  The array is
+            nel elements large and width is the size of a single element in
+            bytes.  Compare is a pointer to a comparison routine which will
+            be passed pointers to two elements of the array.  It should
+            return a negative number if the left-most argument is less than
+            the rightmost, 0 if the two arguments are equal, a positive
+            number if the left argument is greater than the right.  (That
+            is, it acts like a "subtract" operator.) If compare is 0 then
+            the default comparison routine, argvcmp (which sorts an
+            argv-like array of pointers to strings), is used.                                       */
+
+    Width=width;
+    Comp= compare;
+    Switch= switcher;
+    n=nel*Width;
+    Base=base-Width;
+    for (i=(n/Width/2)*Width; i>=Width; i-=Width) newsift_down(i,n);
+    stop=Width+Width;
+    for (i=n; i>=stop; )
+    {
+        (*Switch)(base, Base+i);
+        newsift_down(Width,i-=Width);
+    }
+
+}
+
+/*---------------------------------------------------------------------------*/
+
+//******************************************************************************
+//
+// UL_GetPath
+//
+// Purpose
+//    To parse the directory entered by the user to make the directory.
+//
+// Parms
+//    Path - the path to be parsed.
+//
+// Returns
+//    Pointer to next path
+//
+//******************************************************************************
+
+char * UL_GetPath (char * path, char *dir)
+{
+    boolean done      = 0;
+    char *dr          = dir;
+    int cnt           = 0;
+
+    if (*path == SLASHES)
+        path++;
+
+    while (!done)
+    {
+        *dr = *path;
+
+        cnt++;                  // make sure the number of characters in the dir
+        if (cnt > MAXCHARS)     // name doesn't exceed acceptable limits.
+            Error ("ERROR : Directory name can only be %d characters long.\n", MAXCHARS);
+
+        path++;
+        dr++;
+
+        if ((*path == SLASHES) || (*path == 0))
+            done = true;
+    }
+
+    *dr = 0;
+    return (path);
+}
+
+
+//******************************************************************************
+//
+// UL_ChangeDirectory ()
+//
+// Purpose
+//    To change to a directory.  Checks for drive changes.
+//
+// Parms
+//    path - The path to change to.
+//
+// Returns
+//    TRUE  - If successful.
+//    FALSE - If unsuccessful.
+//
+//******************************************************************************
+
+boolean UL_ChangeDirectory (char *path)
+{
+#ifdef DOS
+    char *p;
+    char dir[9];
+    char *d;
+
+    d = &dir[0];
+    p = path;
+    memset (dir, 0, 9);
+
+    // Check for a drive at the beginning of the path
+    if (*(p+1) == ':')
+    {
+        *d++ = *p++;      // drive letter
+        *d++ = *p++;      // colon
+
+        if (UL_ChangeDrive (dir) == false)
+            return (false);
+    }
+
+    if (*p == SLASHES)
+    {
+        chdir ("\\");
+        p++;
+    }
+
+    d = &dir[0];
+    while (*p)
+    {
+        p = UL_GetPath (p, d);
+
+        if (chdir (d) == -1)
+            return (false);
+    }
+
+    return (true);
+#else
+    if (!path || !*path) {
+        return true;
+    }
+
+    if (chdir (path) == -1) {
+        return (false);
+    }
+
+    return true;
+#endif
+}
+
+
+
+//******************************************************************************
+//
+// UL_ChangeDrive ()
+//
+// Purpose
+//    To change drives.
+//
+// Parms
+//    drive - The drive to change to.
+//
+// Returns
+//    TRUE  - If drive change successful.
+//    FALSE - If drive change unsuccessful.
+//
+//******************************************************************************
+
+boolean UL_ChangeDrive (char *drive)
+{
+#ifdef DOS
+    unsigned d, total, tempd;
+
+    d = toupper (*drive);
+
+    d = d - 'A' + 1;
+
+    _dos_setdrive (d, &total);
+    _dos_getdrive (&tempd);
+
+    if (d != tempd)
+        return (false);
+
+    return (true);
+#else
+    STUB_FUNCTION;
+
+    return false;
+#endif
+}
+
+
+/*
+=============
+=
+= AbortCheck
+=
+=============
+*/
+void AbortCheck (char * abortstring)
+{
+    // User abort check
+
+    IN_UpdateKeyboard ();
+
+    if (Keyboard[sc_Escape])
+        Error("%s\n",abortstring);
+}
--- /dev/null
+++ b/rott/rt_util.h
@@ -1,0 +1,210 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+//***************************************************************************
+//
+//    RT_UTIL.C - various utils palette funcs and modex stuff
+//
+//***************************************************************************
+
+#ifndef _rt_util_public
+#define _rt_util_public
+
+#define ERRORVERSIONROW 1
+#define ERRORVERSIONCOL 67
+
+#define LOWMEMORYROW 18
+#define LOWMEMORYCOL 1
+
+#include "develop.h"
+
+extern  int    egacolor[16];
+extern  byte   *  origpal;
+extern  int      _argc;
+extern  char **  _argv;
+
+void  markgetch( void );
+boolean StringsNotEqual (char * s1, char * s2, int length);
+void  GetPalette(char * pal);
+void  ClearGraphicsScreen( void );
+void  ClearBuffer( char * buf, int size );
+void  Error (char *error, ...) __attribute__((noreturn,format(printf,1,2)));
+void  StartupSoftError ( void );
+void  ShutdownSoftError ( void );
+int   CheckParm (char *check);
+int   SafeOpenWrite (char *filename);
+int   SafeOpenAppend (char *filename);
+int   SafeOpenRead (char *filename);
+void  SafeRead (int handle, void *buffer, long count);
+void  SafeWrite (int handle, void *buffer, long count);
+void  SafeWriteString (int handle, char * buffer);
+void  *SafeMalloc (long size);
+void  *SafeLevelMalloc (long size);
+void  SafeFree (void * ptr);
+long  LoadFile (char *filename, void **bufferptr);
+void  SaveFile (char *filename, void *buffer, long count);
+void  GetPathFromEnvironment( char *fullname, const char *envname, const char *filename );
+void  DefaultExtension (char *path, char *extension);
+void  DefaultPath (char *path, char *basepath);
+void  ExtractFileBase (char *path, char *dest);
+long  ParseHex (char *hex);
+long  ParseNum (char *str);
+short MotoShort (short l);
+short IntelShort (short l);
+int   MotoLong (int l);
+int   IntelLong (int l);
+void  SwapIntelLong (int *l);
+void  SwapIntelShort(short *s);
+void  SwapIntelLongArray (int *l, int num);
+void  SwapIntelShortArray (short *s, int num);
+int   US_CheckParm (char *parm, char **strings);
+byte  BestColor (int r, int g, int b, byte *palette);
+int   atan2_appx(int,int);
+int   FindDistance(int ix, int iy);
+int   Find_3D_Distance(int ix, int iy, int iz);
+void  SetPalette ( char * pal );
+void  SetaPalette ( byte * pal );
+void  FindEGAColors ( void );
+void  VL_FillPalette (int red, int green, int blue);
+void  VL_SetColor  (int color, int red, int green, int blue);
+void  VL_GetColor  (int color, int *red, int *green, int *blue);
+void  VL_SetPalette (byte *palette);
+void  VL_GetPalette (byte *palette);
+void  UL_printf (byte *str);
+void  VL_NormalizePalette (byte *palette);
+void  MapDebug (char *error, ...) __attribute__((format(printf,1,2)));
+void  OpenMapDebug ( void );
+void  UL_ColorBox (int x, int y, int w, int h, int color);
+
+void UL_DisplayMemoryError ( int memneeded );
+
+int   SideOfLine(int x1, int y1, int x2, int y2, int x3, int y3);
+
+void hsort(char * base, int nel, int width, int (*compare)(), void (*switcher)());
+
+char * UL_GetPath (char * path, char *dir);
+boolean UL_ChangeDirectory (char *path);
+boolean UL_ChangeDrive (char *drive);
+void AbortCheck (char * abortstring);
+
+void FixFilePath(char *filename);
+
+
+#if PLATFORM_WIN32
+#include <io.h>
+struct find_t
+{
+    long handle;
+    struct _finddata_t data;
+    char name[MAX_PATH];
+};
+int _dos_findfirst(char *filename, int x, struct find_t *f);
+int _dos_findnext(struct find_t *f);
+
+#elif PLATFORM_UNIX
+struct find_t
+{
+    DIR *dir;
+    char pattern[MAX_PATH];
+    char name[MAX_PATH];
+};
+int _dos_findfirst(char *filename, int x, struct find_t *f);
+int _dos_findnext(struct find_t *f);
+
+#elif PLATFORM_DOS
+/* no-op */
+#else
+#error please define for your platform.
+#endif
+
+
+#if !PLATFORM_DOS
+struct dosdate_t
+{
+    unsigned char day;
+    unsigned char month;
+    unsigned int year;
+    unsigned char dayofweek;
+};
+
+void _dos_getdate(struct dosdate_t *date);
+#endif
+
+
+#if (SOFTERROR==1)
+
+void  SoftwareError (char *error, ...) __attribute__((format(printf,1,2)));
+#define SoftError  SoftwareError
+
+#else
+void  SoftwareError (char *error, ...) __attribute__((format(printf,1,2)));
+//#define SoftError  SoftwareError
+
+#define SoftError  if (1) {} else SoftwareError
+
+//#define SoftError
+
+#endif
+
+#if (DEBUG==1)
+
+void  DebugError (char *error, ...) __attribute__((format(printf,1,2)));
+#define Debug  DebugError
+
+#else
+
+void  DebugError (char *error, ...) __attribute__((format(printf,1,2)));
+#define Debug  DebugError
+//#define Debug
+
+#endif
+
+void Square (void);
+
+#ifdef __WATCOMC__
+#pragma aux Square=\
+   "mov edx,03c4h",  \
+   "mov eax,0100h",  \
+	"out dx,ax",      \
+   "mov eax,0e3h",    \
+   "mov edx,03c2h",  \
+   "out dx,ax",      \
+   "mov eax,0300h",  \
+   "mov edx,03c4h",  \
+   "out dx,ax"      \
+   modify exact [eax edx]
+#endif
+
+
+#ifdef DOS
+void my_outp(int port, int data);
+#else
+#define my_outp(a,b)
+#endif
+
+#ifdef __WATCOMC__
+#pragma aux my_outp =  \
+        "out dx,al",                     \
+        parm    [edx] [eax] \
+        modify exact []
+#endif
+
+#define OUTP                              my_outp
+
+#endif
--- /dev/null
+++ b/rott/rt_vh_a.h
@@ -1,0 +1,36 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+#ifndef _rt_vh_a_public
+#define _rt_vh_a_public
+
+//***************************************************************************
+//
+// Public header for RT_VH_A.ASM.
+//
+//***************************************************************************
+
+void VH_UpdateScreen (void);
+void JoyStick_Vals (void);
+
+#ifdef __WATCOMC__
+#pragma aux JoyStick_Vals modify exact [eax ebx ecx edx esi edi]
+#endif
+
+#endif
--- /dev/null
+++ b/rott/rt_vid.c
@@ -1,0 +1,1341 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef DOS
+#include <dos.h>
+#include <conio.h>
+#endif
+
+#include "rt_def.h"
+#include "rt_vid.h"
+#include "_rt_vid.h"
+#include "rt_menu.h"
+#include "rt_util.h"
+#include "modexlib.h"
+#include "profile.h"
+#include "watcom.h"
+#include "rt_str.h"
+#include "rt_draw.h"
+#include "rt_in.h"
+#include "rt_main.h"
+#include "z_zone.h"
+#include "lumpy.h"
+#include "rt_vh_a.h"
+#include "isr.h"
+#include "rt_view.h"
+#include "cin_efct.h"
+#include "w_wad.h"
+//MED
+#include "memcheck.h"
+
+
+//******************************************************************************
+//
+// GLOBALS
+//
+//******************************************************************************
+
+byte     *updateptr;
+unsigned mapwidthtable[64];
+unsigned uwidthtable[UPDATEHIGH];
+unsigned blockstarts[UPDATEWIDE*UPDATEHIGH];
+byte     update[UPDATESIZE];
+byte     palette1[256][3], palette2[256][3];
+boolean  screenfaded;
+
+
+//******************************************************************************
+//
+// LOCALS
+//
+//******************************************************************************
+
+static byte  pixmasks[4] = {1,2,4,8};
+static byte  leftmasks[4] = {15,14,12,8};
+static byte  rightmasks[4] = {1,3,7,15};
+
+
+
+//******************************************************************************
+//
+// VL_MemToScreen ()
+//
+//******************************************************************************
+
+void VL_MemToScreen (byte *source, int width, int height, int x, int y)
+{
+#ifdef DOS
+    byte *screen, *dest, mask;
+    int  plane;
+
+    dest = (byte *)(bufferofs+ylookup[y]+(x>>2));
+//   dest = (byte *)(displayofs+ylookup[y]+(x>>2));
+    mask = 1 << (x&3);
+
+
+    for (plane = 0; plane<4; plane++)
+    {
+        VGAMAPMASK (mask);
+
+        screen = dest;
+        for (y = 0; y < height; y++, screen += linewidth, source+=width)
+            memcpy (screen, source, width);
+
+
+        mask <<= 1;
+
+        if (mask == 16)
+        {
+            mask = 1;
+            dest++;
+        }
+    }
+#else
+    /* TODO please optimize me */
+
+    byte *ptr, *destline;
+    int plane, i, j;
+
+    ptr = source;
+
+    for (plane = 0; plane < 4; plane++) {
+        for (j = 0; j < height; j++) {
+            destline = (byte *)(bufferofs+ylookup[y+j]+x);
+
+            for (i = 0; i < width; i++) {
+//				if (ptr < bufferofs + toplimit) { //bnafix zxcvb
+                *(destline + i*4 + plane) = *ptr++;
+//				}
+            }
+        }
+    }
+#endif
+}
+// bna function start
+void VL_MemToScreenClipped (byte *source, int width, int height, int x, int y);
+void VL_MemToScreenClipped (byte *source, int width, int height, int x, int y)
+{
+    byte *ptr, *destline;
+    int plane, i, j;//,toplimit;
+    ptr = source;
+    for (plane = 0; plane < 4; plane++) {
+        for (j = 0; j < height; j++) {
+            destline = (byte *)(bufferofs+ylookup[y+j]+x);
+            for (i = 0; i < width; i++) {
+                if (*ptr != 255) {
+                    *(destline + i*4 + plane) = *ptr++;
+                } else {
+                    ptr++;
+                }
+            }
+        }
+    }
+}
+
+//copy picture to mem (bufferofs) in doublesize
+void VL_MemStrechedToScreen (byte *source, int width, int height, int x, int y)
+{
+    byte *ptr, *destline,*tmp,*o;
+    int plane, i, j;
+
+    tmp = bufferofs;
+    ptr = source;
+
+    for (plane = 0; plane < 4; plane++) {
+        for (j = 0; j < height; j++) {
+            destline = (byte *)(bufferofs+(iGLOBAL_SCREENWIDTH*j)+ylookup[y+j]+x);
+            o = ptr;
+            for (i = 0; i < width; i+=1) {
+                *(destline + i*4 + plane) = *ptr;
+                destline++;
+                *(destline + i*4 + plane) = *ptr++;
+            }
+            ptr = o;
+
+            destline = (byte *)(bufferofs+iGLOBAL_SCREENWIDTH+(iGLOBAL_SCREENWIDTH*j)+ylookup[y+j]+x);
+            for (i = 0; i < width; i+=1) {
+                *(destline + i*4 + plane) = *ptr;
+                destline++;
+                *(destline + i*4 + plane) = *ptr++;
+
+            }
+
+        }
+    }
+    bufferofs = tmp;
+}
+// bna function end
+
+
+//*************************************************************************
+//
+// DrawTiledRegion () - Fills the specified region with a tiled image
+//
+//*************************************************************************
+void DrawTiledRegion
+(
+    int x,
+    int y,
+    int width,
+    int height,
+    int offx,
+    int offy,
+    pic_t *tile
+)
+
+{
+    byte  *source;
+    byte  *sourceoff;
+    int    sourcex;
+    int    sourcey;
+    int    sourcewidth;
+    int    sourceheight;
+    int    mask;
+    int    plane;
+    int    planesize;
+    byte  *start;
+    byte  *origdest;
+    byte  *dest;
+    int    startoffset;
+    int    HeightIndex;
+    int    WidthIndex;
+
+#ifdef DOS
+    start = ( byte * )( bufferofs + ( x>>2 ) + ylookup[ y ] );
+#else
+    start = ( byte * )( bufferofs +  x + ylookup[ y ] );
+#endif
+
+    source       = &tile->data;
+    sourcewidth  = tile->width;
+    sourceheight = tile->height;
+#ifdef DOS
+    offx >>= 2;
+#endif
+    if ( offx >= sourcewidth )
+    {
+        offx %= sourcewidth;
+    }
+    if ( offy >= sourceheight )
+    {
+        offy %= sourceheight;
+    }
+
+    startoffset = offy * sourcewidth;
+    planesize = sourcewidth * sourceheight;
+
+#ifdef DOS
+    width >>= 2;
+
+    mask  = 1 << ( x & 3 );
+#endif
+    plane = 4;
+    while( plane > 0 )
+    {
+        VGAMAPMASK( mask );
+
+#ifdef DOS
+        origdest = start;
+#else
+        origdest = start+(4-plane);
+#endif
+
+        sourcey     = offy;
+        sourceoff   = source + startoffset;
+        HeightIndex = height;
+
+        while( HeightIndex-- )
+        {
+            dest       = origdest;
+            sourcex    = offx;
+            WidthIndex = width;
+            while( WidthIndex-- )
+            {
+                *dest = sourceoff[ sourcex ];
+#ifdef DOS
+                dest++;
+#else
+                dest += 4;
+#endif
+
+                sourcex++;
+                if ( sourcex >= sourcewidth )
+                {
+                    sourcex = 0;
+                }
+            }
+
+#ifdef DOS
+            origdest  += iGLOBAL_SCREENBWIDE;
+#else
+            origdest += iGLOBAL_SCREENWIDTH;
+#endif
+
+            sourceoff += sourcewidth;
+            sourcey++;
+            if ( sourcey >= sourceheight )
+            {
+                sourcey   = 0;
+                sourceoff = source;
+            }
+        }
+
+        source += planesize;
+
+#ifdef DOS
+        mask <<= 1;
+        if ( mask > 8 )
+        {
+            mask = 1;
+        }
+#endif
+
+        plane--;
+    }
+}
+
+
+//******************************************************************************
+//
+// VWB_DrawPic () - Draws a linear pic and marks the update block
+//
+//******************************************************************************
+
+void VWB_DrawPic (int x, int y, pic_t *pic)
+{
+    if (((iGLOBAL_SCREENWIDTH > 320) && !StretchScreen) ||
+            VW_MarkUpdateBlock (x, y, x+(pic->width<<2)-1, y+(pic->height)-1))
+        VL_MemToScreen ((byte *)&pic->data, pic->width, pic->height, x, y);
+}
+
+
+
+//******************************************************************************
+//
+// VL_Bar () - Draws a bar
+//
+//******************************************************************************
+
+void VL_Bar (int x, int y, int width, int height, int color)
+{
+#ifdef DOS
+    byte  *dest;
+    byte  leftmask,rightmask;
+    int   midbytes,linedelta;
+
+    leftmask = leftmasks[x&3];
+    rightmask = rightmasks[(x+width-1)&3];
+    midbytes = ((x+width+3)>>2) - (x>>2) - 2;
+    linedelta = linewidth-(midbytes+1);
+
+    dest = (byte *)(bufferofs+ylookup[y]+(x>>2));
+
+    if (midbytes < 0)
+    {
+        // all in one byte
+        VGAMAPMASK (leftmask&rightmask);
+        while (height--)
+        {
+            *dest = color;
+            dest += linewidth;
+        }
+        VGAMAPMASK (15);
+        return;
+    }
+
+    while (height--)
+    {
+        VGAMAPMASK (leftmask);
+        *dest++ = color;
+
+        VGAMAPMASK (15);
+        memset (dest,color,midbytes);
+        dest += midbytes;
+
+        VGAMAPMASK (rightmask);
+        *dest = color;
+
+        dest += linedelta;
+    }
+
+    VGAMAPMASK(15);
+#else
+    byte *dest = (byte *)(bufferofs+ylookup[y]+x);
+
+    while (height--) {
+        memset(dest, color, width);
+
+        dest += linewidth;
+    }
+#endif
+}
+
+
+
+//******************************************************************************
+//
+// VWB_Bar () - Draws a block and marks the update block
+//
+//******************************************************************************
+
+void VWB_Bar (int x, int y, int width, int height, int color)
+{
+    if (((iGLOBAL_SCREENWIDTH > 320) && !StretchScreen) ||
+            VW_MarkUpdateBlock (x,y,x+width,y+height-1) )
+        VL_Bar (x, y, width, height, color);
+}
+
+
+//******************************************************************************
+//
+// VL_TBar () - Draws a bar
+//
+//******************************************************************************
+
+void VL_TBar (int x, int y, int width, int height)
+{
+#ifdef DOS
+    byte  *dest;
+    byte  pixel;
+    byte  readmask;
+    byte  writemask;
+    int   w = width;
+
+    while (height--)
+    {
+        width = w;
+
+        dest = (byte*)(bufferofs+ylookup[y]+(x>>2));
+        readmask    = (x&3);
+        writemask   = 1 << readmask;
+
+        VGAREADMAP (readmask);
+        VGAMAPMASK (writemask);
+
+        while (width--)
+        {
+            pixel = *dest;
+
+            pixel = *(colormap+(27<<8)+pixel);
+
+            *dest = pixel;
+
+            writemask <<= 1;
+            if (writemask == 16)
+            {
+                writemask = 1;
+                dest++;
+            }
+
+            readmask++;
+            if (readmask == 4)
+                readmask = 0;
+
+            VGAREADMAP (readmask);
+            VGAMAPMASK (writemask);
+        }
+
+        y++;
+    }
+#else
+    int w = width;
+
+    while (height--) {
+        byte *dest = (byte *)(bufferofs+ylookup[y]+x);
+
+        width = w;
+
+        while (width--) {
+            byte pixel = *dest;
+
+            pixel = *(colormap+(27<<8)+pixel);
+
+            *dest = pixel;
+
+            dest++;
+        }
+
+        y++;
+    }
+
+#endif
+}
+
+
+
+//******************************************************************************
+//
+// VWB_TBar () - Draws a block and marks the update block
+//
+//******************************************************************************
+
+void VWB_TBar (int x, int y, int width, int height)
+{
+    if (VW_MarkUpdateBlock (x,y,x+width,y+height-1))
+        VL_TBar (x, y, width, height);
+}
+
+
+//******************************************************************************
+//
+// VL_Hlin () - Draws a horizontal line
+//
+//******************************************************************************
+
+void VL_Hlin (unsigned x, unsigned y, unsigned width, unsigned color)
+{
+#ifdef DOS
+    unsigned xbyte;
+    byte     *dest;
+    byte     leftmask,
+             rightmask;
+    int      midbytes;
+
+    xbyte =      x >> 2;
+    leftmask    = leftmasks[x&3];
+    rightmask   = rightmasks[(x+width-1)&3];
+    midbytes    = ((x+width+3)>>2) - xbyte - 2;
+
+    dest = (byte*)(bufferofs+ylookup[y]+xbyte);
+
+    if (midbytes<0)
+    {
+        // all in one byte
+        VGAMAPMASK (leftmask & rightmask);
+        *dest = color;
+        VGAMAPMASK(15);
+        return;
+    }
+
+    VGAMAPMASK (leftmask);
+    *dest++ = color;
+
+    VGAMAPMASK (15);
+    memset (dest, color, midbytes);
+    dest += midbytes;
+
+    VGAMAPMASK (rightmask);
+    *dest = color;
+
+    VGAMAPMASK (15);
+#else
+    byte *dest = (byte*)(bufferofs+ylookup[y]+x);
+
+    memset(dest, color, width);
+#endif
+}
+
+
+//******************************************************************************
+//
+// VL_Vlin () - Draws a vertical line
+//
+//******************************************************************************
+
+void VL_Vlin (int x, int y, int height, int color)
+{
+#ifdef DOS
+    byte  *dest,
+          mask;
+
+    mask = pixmasks[x&3];
+    VGAMAPMASK (mask);
+
+    dest = (byte *)(bufferofs+ylookup[y]+(x>>2));
+
+    while (height--)
+    {
+        *dest = color;
+        dest += linewidth;
+    }
+
+    VGAMAPMASK (15);
+#else
+    byte *dest = (byte*)(bufferofs+ylookup[y]+x);
+
+    while (height--) {
+        *dest = color;
+
+        dest += linewidth;
+    }
+#endif
+}
+
+
+
+//******************************************************************************
+//
+// VWB_Hlin () - Draws a horizontal line and marks the update block
+//
+//******************************************************************************
+
+void VWB_Hlin (int x1, int x2, int y, int color)
+{
+    if (VW_MarkUpdateBlock (x1,y,x2,y))
+        VW_Hlin(x1,x2,y,color);
+}
+
+
+//******************************************************************************
+//
+// VWB_Vlin () - Draws a vertical line and marks the update block
+//
+//******************************************************************************
+
+void VWB_Vlin (int y1, int y2, int x, int color)
+{
+    if (VW_MarkUpdateBlock (x,y1,x,y2))
+        VW_Vlin(y1,y2,x,color);
+}
+
+
+
+
+//******************************************************************************
+//
+// VL_THlin ()
+//
+//******************************************************************************
+
+void VL_THlin (unsigned x, unsigned y, unsigned width, boolean up)
+{
+#ifdef DOS
+    byte     *dest;
+    byte     pixel;
+    byte     readmask;
+    byte     writemask;
+
+
+    readmask    = (x&3);
+    writemask   = 1 << readmask;
+
+    dest = (byte*)(bufferofs+ylookup[y]+(x>>2));
+
+    VGAREADMAP (readmask);
+    VGAMAPMASK (writemask);
+
+    while (width--)
+    {
+        pixel = *dest;
+
+        if (up)
+            pixel = *(colormap+(13<<8)+pixel);
+        else
+            pixel = *(colormap+(27<<8)+pixel);
+
+        *dest = pixel;
+
+        writemask <<= 1;
+        if (writemask == 16)
+        {
+            writemask = 1;
+            dest++;
+        }
+
+        readmask++;
+        if (readmask == 4)
+            readmask = 0;
+
+        VGAREADMAP (readmask);
+        VGAMAPMASK (writemask);
+    }
+#else
+    byte *dest = (byte*)(bufferofs+ylookup[y]+x);
+
+    while (width--) {
+        byte pixel = *dest;
+
+        if (up) {
+            pixel = *(colormap+(13<<8)+pixel);
+        } else {
+            pixel = *(colormap+(27<<8)+pixel);
+        }
+
+        *dest = pixel;
+
+        dest++;
+    }
+#endif
+}
+
+
+
+//******************************************************************************
+//
+// VL_TVlin ()
+//
+//******************************************************************************
+
+void VL_TVlin (unsigned x, unsigned y, unsigned height, boolean up)
+{
+#ifdef DOS
+    byte     *dest;
+    byte     pixel;
+    byte     readmask;
+    byte     writemask;
+
+
+
+    readmask    = (x&3);
+    writemask   = 1 << readmask;
+
+    dest = (byte*)(bufferofs+ylookup[y]+(x>>2));
+
+    VGAREADMAP (readmask);
+    VGAMAPMASK (writemask);
+
+    while (height--)
+    {
+        pixel = *dest;
+
+        if (up)
+            pixel = *(colormap+(13<<8)+pixel);
+        else
+            pixel = *(colormap+(27<<8)+pixel);
+
+        *dest = pixel;
+
+        dest += linewidth;
+    }
+#else
+    byte *dest = (byte*)(bufferofs+ylookup[y]+x);
+
+    while (height--) {
+        byte pixel = *dest;
+
+        if (up) {
+            pixel = *(colormap+(13<<8)+pixel);
+        } else {
+            pixel = *(colormap+(27<<8)+pixel);
+        }
+
+        *dest = pixel;
+
+        dest += linewidth;
+    }
+#endif
+}
+
+
+
+//******************************************************************************
+//
+// VWB_THlin () - Draws a horizontal line and marks the update block
+//
+//******************************************************************************
+
+void VWB_THlin (int x1, int x2, int y, boolean up)
+{
+    if (VW_MarkUpdateBlock (x1,y,x2,y))
+        VW_THlin (x1,x2,y,up);
+}
+
+
+//******************************************************************************
+//
+// VWB_TVlin () - Draws a vertical line and marks the update block
+//
+//******************************************************************************
+
+void VWB_TVlin (int y1, int y2, int x, boolean up)
+{
+    if (VW_MarkUpdateBlock (x,y1,x,y2))
+        VW_TVlin (y1,y2,x,up);
+}
+
+
+
+/*
+================================================================================
+
+            Double buffer management routines
+
+================================================================================
+*/
+
+
+//******************************************************************************
+//
+// VW_MarkUpdateBlock
+//
+// Takes a pixel bounded block and marks the tiles in bufferblocks
+// Returns 0 if the entire block is off the buffer screen
+//
+//******************************************************************************
+
+int VW_MarkUpdateBlock (int x1, int y1, int x2, int y2)
+{
+    int   x,
+          y,
+          xt1,
+          yt1,
+          xt2,
+          yt2,
+          nextline;
+    byte  *mark;
+
+    xt1 = x1 >> PIXTOBLOCK;
+    yt1 = y1 >> PIXTOBLOCK;
+
+    xt2 = x2 >> PIXTOBLOCK;
+    yt2 = y2 >> PIXTOBLOCK;
+
+    if (xt1 < 0)
+        xt1 = 0;
+    else if (xt1 >= UPDATEWIDE)
+        return 0;
+
+    if (yt1 < 0)
+        yt1 = 0;
+    else if (yt1 > UPDATEHIGH)
+        return 0;
+
+    if (xt2 < 0)
+        return 0;
+    else if (xt2 >= UPDATEWIDE)
+        xt2 = UPDATEWIDE-1;
+
+    if (yt2 < 0)
+        return 0;
+    else if (yt2 >= UPDATEHIGH)
+        yt2 = UPDATEHIGH-1;
+
+    mark = updateptr + uwidthtable[yt1] + xt1;
+    nextline = UPDATEWIDE - (xt2-xt1) - 1;
+
+    for (y = yt1; y <= yt2; y++)
+    {
+        for (x = xt1; x <= xt2; x++)
+            *mark++ = 1;                  // this tile will need to be updated
+
+        mark += nextline;
+    }
+
+    return 1;
+}
+
+
+//******************************************************************************
+//
+// VW_UpdateScreen ()
+//
+//******************************************************************************
+
+
+void VW_UpdateScreen (void)
+{
+    VH_UpdateScreen ();
+}
+
+//===========================================================================
+
+/*
+=================
+=
+= VL_FadeOut
+=
+= Fades the current palette to the given color in the given number of steps
+=
+=================
+*/
+
+void VL_FadeOut (int start, int end, int red, int green, int blue, int steps)
+{
+    int      i,j,orig,delta;
+    byte  *origptr, *newptr;
+
+    if (screenfaded)
+        return;
+
+    WaitVBL ();
+    VL_GetPalette (&palette1[0][0]);
+    memcpy (palette2, palette1, 768);
+
+//
+// fade through intermediate frames
+//
+    for (i = 0; i < steps; i++)
+    {
+        origptr = &palette1[start][0];
+        newptr = &palette2[start][0];
+
+        for (j = start; j <= end; j++)
+        {
+            orig = *origptr++;
+            delta = red-orig;
+            *newptr++ = orig + delta * i / steps;
+            orig = *origptr++;
+            delta = green-orig;
+            *newptr++ = orig + delta * i / steps;
+            orig = *origptr++;
+            delta = blue-orig;
+            *newptr++ = orig + delta * i / steps;
+        }
+
+        WaitVBL ();
+        VL_SetPalette (&palette2[0][0]);
+    }
+
+//
+// final color
+//
+    VL_FillPalette (red,green,blue);
+
+    screenfaded = true;
+}
+
+
+/*
+=================
+=
+= VL_FadeToColor
+=
+= Fades the current palette to the given color in the given number of steps
+=
+=================
+*/
+
+void VL_FadeToColor (int time, int red, int green, int blue)
+{
+    int      i,j,orig,delta;
+    byte  *origptr, *newptr;
+    int dmax,dmin;
+
+    if (screenfaded)
+        return;
+
+    WaitVBL ();
+    VL_GetPalette (&palette1[0][0]);
+    memcpy (palette2, palette1, 768);
+
+    dmax=(maxshade<<16)/time;
+    dmin=(minshade<<16)/time;
+//
+// fade through intermediate frames
+//
+    for (i = 0; i < time; i+=tics)
+    {
+        origptr = &palette1[0][0];
+        newptr = &palette2[0][0];
+
+        for (j = 0; j <= 255; j++)
+        {
+            orig = *origptr++;
+            delta = ((red>>2)-orig)<<16;
+            *newptr++ = orig + FixedMul(delta/time,i);
+            orig = *origptr++;
+            delta = ((green>>2)-orig)<<16;
+            *newptr++ = orig + FixedMul(delta/time,i);
+            orig = *origptr++;
+            delta = ((blue>>2)-orig)<<16;
+            *newptr++ = orig + FixedMul(delta/time,i);
+        }
+
+        maxshade=(dmax*(time-i))>>16;
+        minshade=(dmin*(time-i))>>16;
+        WaitVBL ();
+        VL_SetPalette (&palette2[0][0]);
+        ThreeDRefresh();
+        CalcTics();
+
+    }
+
+//
+// final color
+//
+    VL_FillPalette (red>>2,green>>2,blue>>2);
+
+    screenfaded = true;
+}
+
+
+
+
+/*
+=================
+=
+= VL_FadeIn
+=
+=================
+*/
+
+void VL_FadeIn (int start, int end, byte *palette, int steps)
+{
+    int      i,j,delta;
+
+    WaitVBL ();
+    VL_GetPalette (&palette1[0][0]);
+
+    memcpy (&palette2[0][0], &palette1[0][0], sizeof(palette1));
+
+    start *= 3;
+    end = end*3+2;
+
+//
+// fade through intermediate frames
+//
+    for (i=0; i<steps; i++)
+    {
+        for (j=start; j<=end; j++)
+        {
+            delta = palette[j]-palette1[0][j];
+            palette2[0][j] = palette1[0][j] + delta * i / steps;
+        }
+
+        WaitVBL ();
+        VL_SetPalette (&palette2[0][0]);
+    }
+
+//
+// final color
+//
+    VL_SetPalette (palette);
+    screenfaded = false;
+}
+
+
+
+//******************************************************************************
+//
+// SwitchPalette
+//
+//******************************************************************************
+
+void SwitchPalette (byte * newpal, int steps)
+{
+    byte *temp;
+
+    VL_FadeOut(0,255,0,0,0,steps>>1);
+
+    temp = bufferofs;
+    bufferofs = displayofs;
+    VL_Bar (0, 0, 320, 200, 0);
+    bufferofs = temp;
+
+    VL_FadeIn(0,255,newpal,steps>>1);
+}
+
+
+#if 0
+
+/*
+=================
+=
+= VL_TestPaletteSet
+=
+= Sets the palette with outsb, then reads it in and compares
+= If it compares ok, fastpalette is set to true.
+=
+=================
+*/
+
+void VL_TestPaletteSet (void)
+{
+    int   i;
+
+    for (i=0; i<768; i++)
+        palette1[0][i] = i;
+
+    fastpalette = true;
+    VL_SetPalette (&palette1[0][0]);
+    VL_GetPalette (&palette2[0][0]);
+    if (_fmemcmp (&palette1[0][0],&palette2[0][0],768))
+        fastpalette = false;
+}
+
+
+/*
+==================
+=
+= VL_ColorBorder
+=
+==================
+*/
+
+void VL_ColorBorder (int color)
+{
+    _AH=0x10;
+    _AL=1;
+    _BH=color;
+    geninterrupt (0x10);
+    bordercolor = color;
+}
+
+
+#endif
+
+
+//==========================================================================
+
+//****************************************************************************
+//
+// VL_DecompressLBM ()
+//
+// LIMITATIONS - Only works with 320x200!!!
+//
+//****************************************************************************
+
+void VL_DecompressLBM (lbm_t *lbminfo, boolean flip)
+{
+    int  count;
+    byte b, rept;
+    byte *source = (byte *)&lbminfo->data;
+    byte *buf;
+    int  ht = lbminfo->height;
+    byte pal[768];
+
+    EnableScreenStretch();
+
+    memcpy(&pal[0],lbminfo->palette,768);
+
+    VL_NormalizePalette (&pal[0]);
+
+    VW_MarkUpdateBlock (0, 0, 320, 200);
+
+    buf = (byte *)bufferofs;
+
+    while (ht--)
+    {
+        count = 0;
+
+        do
+        {
+            rept = *source++;
+
+            if (rept > 0x80)
+            {
+                rept = (rept^0xff)+2;
+                b = *source++;
+                memset (buf, b, rept);
+                buf += rept;
+            }
+            else if (rept < 0x80)
+            {
+                rept++;
+                memcpy (buf, source, rept);
+                buf += rept;
+                source += rept;
+            }
+            else
+                rept = 0;               // rept of 0x80 is NOP
+
+            count += rept;
+
+        } while (count < lbminfo->width);
+        if (iGLOBAL_SCREENWIDTH > 320) {
+            buf += (iGLOBAL_SCREENWIDTH-320); //eg 800 - 320)
+        }
+    }
+
+    if (flip==true)
+        VW_UpdateScreen ();
+
+    VL_FadeIn (0, 255, &pal[0], 15);
+
+}
+
+//****************************************************************************
+//
+// SetBorderColor
+//
+//****************************************************************************
+
+void SetBorderColor (int color)
+{
+    // bna section start
+
+    byte  *cnt,*Ycnt,*b;
+
+    b=(byte *)bufferofs;
+
+    // color 56 could be used
+
+    //paint top red line
+    for (cnt=b; cnt<b+viewwidth; cnt++) {
+        for (Ycnt=cnt; Ycnt<cnt+(5*iGLOBAL_SCREENWIDTH); Ycnt+=iGLOBAL_SCREENWIDTH) {
+            *Ycnt = color;
+        }
+    }
+    //paint left red line
+    for (cnt=b; cnt<b+5; cnt++) {
+        for (Ycnt=cnt; Ycnt<cnt+(viewheight*iGLOBAL_SCREENWIDTH); Ycnt+=iGLOBAL_SCREENWIDTH) {
+            *Ycnt = color;
+        }
+    }
+    //paint right red line
+    for (cnt=b+(viewwidth-5); cnt<b+viewwidth; cnt++) {
+        for (Ycnt=cnt; Ycnt<cnt+(viewheight*iGLOBAL_SCREENWIDTH); Ycnt+=iGLOBAL_SCREENWIDTH) {
+            *Ycnt = color;
+        }
+    }
+    //paint lower red line
+    for (cnt=b+((viewheight-5)*iGLOBAL_SCREENWIDTH); cnt<b+((viewheight-5)*iGLOBAL_SCREENWIDTH)+viewwidth; cnt++) {
+        for (Ycnt=cnt; Ycnt<b+(viewheight*iGLOBAL_SCREENWIDTH); Ycnt+=iGLOBAL_SCREENWIDTH) {
+            *Ycnt = color;
+        }
+    }
+    // bna section end
+
+#ifdef DOS
+    inp  (STATUS_REGISTER_1);
+    outp (ATR_INDEX,0x31);
+    outp (ATR_INDEX,color);
+#endif
+}
+
+//****************************************************************************
+//
+// SetBorderColorInterrupt
+//
+//****************************************************************************
+
+void SetBorderColorInterrupt (int color)
+{
+#ifdef DOS
+    union REGS regs;
+
+    regs.w.ax = 0x1001;
+    regs.w.bx = color<<8;
+    int386(0x10,&regs,&regs);
+#else
+    STUB_FUNCTION;
+#endif
+}
+
+
+//****************************************************************************
+//
+// VL_DrawPostPic
+//
+//****************************************************************************
+
+void VL_DrawPostPic (int lumpnum)
+{
+    DrawPostPic(lumpnum);
+    VW_MarkUpdateBlock (0, 0, 319, 199);
+}
+
+//****************************************************************************
+//
+// VL_DrawLine
+//
+//****************************************************************************
+
+void VL_DrawLine (int x1, int y1, int x2, int y2, byte color)
+{
+    int dx;
+    int dy;
+    int xinc;
+    int yinc;
+    int count;
+
+    dx=(x2-x1);
+    dy=(y2-y1);
+    if (abs(dy)>=abs(dx))
+    {
+        count=abs(dy);
+        yinc=(dy<<16)/count;
+        if (dy==0)
+        {
+            return;
+        }
+        else
+        {
+            xinc=(dx<<16)/count;
+        }
+    }
+    else
+    {
+        count=abs(dx);
+        xinc=(dx<<16)/count;
+        if (dx==0)
+        {
+            return;
+        }
+        else
+        {
+            yinc=(dy<<16)/count;
+        }
+    }
+    x1<<=16;
+    y1<<=16;
+    while (count>0)
+    {
+#ifdef DOS
+        VGAWRITEMAP((x1>>16)&3);
+        *((byte *)bufferofs+(x1>>18)+(ylookup[y1>>16]))=color;
+#else
+        *((byte *)bufferofs+(x1>>16)+(ylookup[y1>>16]))=color;
+#endif
+        x1+=xinc;
+        y1+=yinc;
+        count--;
+    }
+}
+
+
+//******************************************************************************
+//
+// DrawXYPic
+//
+//******************************************************************************
+
+void DrawXYPic (int x, int y, int shapenum)
+{
+    byte *buffer;
+    byte *buf;
+    int xx,yy;
+    int plane;
+    byte *src;
+    pic_t *p;
+
+    p = (pic_t *) W_CacheLumpNum (shapenum, PU_CACHE, Cvt_pic_t, 1);
+
+    if ((x<0) || ((x+(p->width<<2))>=320))
+        Error ("DrawXYPic: x is out of range\n");
+    if ((y<0) || ((y+p->height)>=200))
+        Error ("DrawXYPic: y is out of range\n");
+
+#ifdef DOS
+    buffer = (byte*)bufferofs+(x>>2)+ylookup[y];
+#else
+    buffer = (byte*)bufferofs+ylookup[y];
+#endif
+
+    src=(byte *)&p->data;
+
+    for (plane=x; plane<x+4; plane++)
+    {
+        VGAWRITEMAP((plane&3));
+        for (yy = 0; yy < p->height; yy++)
+        {
+            buf=buffer+ylookup[yy];
+            for (xx = 0; xx < p->width; xx++,buf++)
+#ifdef DOS
+                *(buf)=*(src++);
+#else
+                *(buf+plane+xx*4)=*(src++);
+#endif
+        }
+    }
+}
--- /dev/null
+++ b/rott/rt_vid.h
@@ -1,0 +1,94 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+#ifndef _rt_vid_public
+#define _rt_vid_public
+
+//***************************************************************************
+//
+// Public header for RT_VID.C
+//
+//***************************************************************************
+
+#include "lumpy.h"
+
+//***************************************************************************
+//
+// DEFINES
+//
+//***************************************************************************
+
+#define PORTTILESWIDE      20       // all drawing takes place inside a
+#define PORTTILESHIGH      13       // non displayed port of this size
+
+#define UPDATEWIDE         PORTTILESWIDE
+#define UPDATEHIGH         PORTTILESHIGH
+#define UPDATESIZE         (UPDATEWIDE*UPDATEHIGH)
+
+
+//***************************************************************************
+//
+// GLOBALS
+//
+//***************************************************************************
+
+extern byte     *updateptr;
+extern unsigned mapwidthtable[64];
+extern unsigned uwidthtable[UPDATEHIGH];
+extern unsigned blockstarts[UPDATEWIDE*UPDATEHIGH];
+extern byte     update[UPDATESIZE];
+extern boolean  screenfaded;
+
+
+//***************************************************************************
+//
+// PROTOTYPES
+//
+//***************************************************************************
+void VL_MemStrechedToScreen (byte *source, int width, int height, int x, int y);
+void VL_MemToScreen (byte *source, int width, int height, int x, int y);
+void DrawTiledRegion( int x, int y, int width, int height, int offx, int offy, pic_t *tile );
+void VWB_DrawPic (int x, int y, pic_t *pic);
+void VL_Bar (int x, int y, int width, int height, int color);
+void VWB_Bar (int x, int y, int width, int height, int color);
+void VWB_Hlin (int x1, int x2, int y, int color);
+void VWB_Vlin (int y1, int y2, int x, int color);
+void VWB_THlin (int x1, int x2, int y, boolean up);
+void VWB_TVlin (int y1, int y2, int x, boolean up);
+int VW_MarkUpdateBlock (int x1, int y1, int x2, int y2);
+void VW_UpdateScreen (void);
+
+void VL_FadeOut (int start, int end, int red, int green, int blue, int steps);
+void VL_FadeIn (int start, int end, byte *palette, int steps);
+void VL_DecompressLBM (lbm_t *lbminfo, boolean flip);
+void VL_FadeToColor (int time, int red, int green, int blue);
+void VWB_TBar (int x, int y, int width, int height);
+
+void SwitchPalette (byte * newpal, int steps);
+void SetBorderColor (int color);
+
+void VL_DrawPostPic (int lumpnum);
+void VL_DrawLine (int x1, int y1, int x2, int y2, byte color);
+
+#define MenuFadeOut()	VL_FadeOut (0, 255, 0, 0, 0, 10)
+#define MenuFadeIn()	   VL_FadeIn (0, 255, origpal, 10)
+
+void DrawXYPic (int x, int y, int shapenum);
+
+#endif
--- /dev/null
+++ b/rott/rt_view.c
@@ -1,0 +1,952 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+#include "rt_def.h"
+#include "rt_view.h"
+#include "z_zone.h"
+#include "w_wad.h"
+#include "lumpy.h"
+#include "rt_util.h"
+#include "rt_vid.h"
+#include "rt_game.h"
+#include "rt_draw.h"
+#include "rt_ted.h"
+#include "isr.h"
+#include "rt_rand.h"
+#include "rt_sound.h"
+#include "modexlib.h"
+#include "rt_menu.h"
+
+#ifdef DOS
+#include <mem.h>
+#endif
+
+#include <stdlib.h>
+
+#include "rt_main.h"
+#include "rt_battl.h"
+#include "rt_floor.h"
+#include "rt_str.h"
+#include "watcom.h"
+#include "develop.h"
+//MED
+#include "memcheck.h"
+
+#define LIGHTNINGLEVEL 4
+#define MINLIGHTNINGLEVEL   2
+#define MAXLIGHTNINGLEVEL   10
+
+/*
+=============================================================================
+
+                               GLOBALS
+
+=============================================================================
+*/
+extern int G_weaponscale;
+
+
+int    StatusBar = 0;
+int    lightninglevel=0;
+boolean  lightning=false;
+int    normalshade;
+int    darknesslevel;
+int    maxshade;
+int    minshade;
+int    baseminshade;
+int    basemaxshade;
+int    viewheight;
+int    viewwidth;
+longword   heightnumerator;
+fixed  scale;
+int    screenofs;
+int    centerx;
+int    centery;
+int    centeryfrac;
+int    fulllight;
+int    weaponscale;
+int    viewsize;
+byte * colormap;
+byte * redmap;
+byte * greenmap;
+byte * playermaps[MAXPLAYERCOLORS];
+//short  pixelangle[MAXVIEWWIDTH];
+short  pixelangle[800];
+byte   gammatable[GAMMAENTRIES];
+int    gammaindex;
+int    focalwidth=160;
+int    yzangleconverter;
+byte   uniformcolors[MAXPLAYERCOLORS]= {
+    25,
+    222,
+    29,
+    206,
+    52,
+    6,
+    155,
+    16,
+    90,
+    129,
+    109
+};
+
+#ifdef DOS
+byte    mapmasks1[4][9] = {
+    {1,3,7,15,15,15,15,15,15},
+    {2,6,14,14,14,14,14,14,14},
+    {4,12,12,12,12,12,12,12,12},
+    {8,8,8,8,8,8,8,8,8}
+};
+
+byte    mapmasks2[4][9] = {
+    {0,0,0,0,1,3,7,15,15},
+    {0,0,0,1,3,7,15,15,15},
+    {0,0,1,3,7,15,15,15,15},
+    {0,1,3,7,15,15,15,15,15}
+};
+
+byte    mapmasks3[4][9] = {
+    {0,0,0,0,0,0,0,0,1},
+    {0,0,0,0,0,0,0,1,3},
+    {0,0,0,0,0,0,1,3,7},
+    {0,0,0,0,0,1,3,7,15}
+};
+#endif
+
+
+/*
+=============================================================================
+
+                               LOCAL
+
+=============================================================================
+*/
+
+static char *YourComputerSucksString = "Buy a 486! :)";
+
+static int viewsizes[MAXVIEWSIZES*2]= { 80,48,
+                                        128,72,
+                                        160,88,
+                                        192,104,
+                                        224,120,
+                                        256,136,
+                                        288,152,
+                                        320,168,
+                                        320,184,
+                                        320,200,
+                                        320,200
+                                      };
+
+static int ColorMapLoaded=0;
+
+static int      lightningtime=0;
+static int      lightningdelta=0;
+static int      lightningdistance=0;
+static int      lightningsoundtime=0;
+static boolean  periodic=false;
+static int      periodictime=0;
+
+void SetViewDelta ( void );
+void UpdatePeriodicLighting (void);
+
+/*
+====================
+=
+= ResetFocalWidth
+=
+====================
+*/
+void ResetFocalWidth ( void )
+{
+    focalwidth=iGLOBAL_FOCALWIDTH;//FOCALWIDTH;
+    SetViewDelta();
+}
+
+/*
+====================
+=
+= ChangeFocalWidth
+=
+====================
+*/
+void ChangeFocalWidth ( int amount )
+{
+    focalwidth=iGLOBAL_FOCALWIDTH+amount;//FOCALWIDTH+amount;
+    SetViewDelta();
+}
+
+
+/*
+====================
+=
+= SetViewDelta
+=
+====================
+*/
+
+void SetViewDelta ( void )
+{
+//iGLOBAL_SCREENHEIGHT
+//iGLOBAL_SCREENWIDTH
+//
+// calculate scale value for vertical height calculations
+// and sprite x calculations
+//
+    if ( iGLOBAL_SCREENWIDTH == 320) {
+        scale = (centerx*focalwidth)/(160);
+    } else if ( iGLOBAL_SCREENWIDTH == 640) {
+        scale = (centerx*focalwidth)/(160);
+    } else if ( iGLOBAL_SCREENWIDTH == 800) {
+        scale = (centerx*focalwidth)/(160);
+    }
+//
+// divide heightnumerator by a posts distance to get the posts height for
+// the heightbuffer.  The pixel height is height>>HEIGHTFRACTION
+//
+    heightnumerator = (((focalwidth/10)*centerx*4096)<<HEIGHTFRACTION);
+}
+
+/*
+====================
+=
+= CalcProjection
+=
+====================
+*/
+
+void CalcProjection ( void )
+{
+    int   i;
+    int   frac;
+    int   intang;
+    byte * table;
+    byte * ptr;
+    int   length;
+    int  * pangle;
+
+
+
+// Already being called in ResetFocalWidth
+//    SetViewDelta();
+
+//
+// load in tables file
+//
+
+
+//Hey, isn't this stuff already loaded in?
+//Why don't we make this a lump?
+    table=W_CacheLumpName("tables",PU_STATIC, CvtNull, 1);
+    ptr=table;
+
+//
+// get size of table
+//
+
+    memcpy(&length,ptr,sizeof(int));
+    SwapIntelLong(&length);
+    ptr+=sizeof(int);
+    pangle=SafeMalloc(length*sizeof(int));
+    memcpy(pangle,ptr,length*sizeof(int));
+
+    frac=((length*65536/centerx))>>1;
+    for (i=0; i<centerx; i++)
+    {
+        // start 1/2 pixel over, so viewangle bisects two middle pixels
+        intang=pangle[frac>>16];
+        SwapIntelLong(&intang);
+        pixelangle[centerx-1-i] =(short) intang;
+        pixelangle[centerx+i] =(short) -intang;
+        frac+=(length*65536/centerx);
+    }
+    table=W_CacheLumpName("tables",PU_CACHE, CvtNull, 1);
+    SafeFree(pangle);
+}
+
+
+/*
+==========================
+=
+= SetViewSize
+=
+==========================
+*/
+
+void SetViewSize
+(
+    int size
+)
+
+{
+    int height;
+    int maxheight;
+    int screenx;
+    int screeny;
+    int topy;
+    /*
+    if (size>=10){
+
+       SetTextMode (  );
+       screenx=screenx;
+       return;
+    }
+    */
+
+    if ( iGLOBAL_SCREENWIDTH == 640) {
+        height = 0;//we use height as dummy cnt
+        viewsizes[height++]= 380;
+        viewsizes[height++]= 336;
+        viewsizes[height++]= 428;
+        viewsizes[height++]= 352;
+        viewsizes[height++]= 460;
+        viewsizes[height++]= 368;
+        viewsizes[height++]= 492;
+        viewsizes[height++]= 384;
+        viewsizes[height++]= 524;
+        viewsizes[height++]= 400;
+        viewsizes[height++]= 556;
+        viewsizes[height++]= 416;
+        viewsizes[height++]= 588;
+        viewsizes[height++]= 432;
+        viewsizes[height++]= 640;
+        viewsizes[height++]= 448;
+        viewsizes[height++]= 640;
+        viewsizes[height++]= 464;
+        viewsizes[height++]= 640;
+        viewsizes[height++]= 480;
+        viewsizes[height++]= 640;
+        viewsizes[height++]= 480;
+    } else if ( iGLOBAL_SCREENWIDTH == 800) {
+        height = 0;
+        viewsizes[height++]= 556;
+        viewsizes[height++]= 488;
+        viewsizes[height++]= 588;
+        viewsizes[height++]= 504;
+        viewsizes[height++]= 620;
+        viewsizes[height++]= 520;
+        viewsizes[height++]= 652;
+        viewsizes[height++]= 536;
+        viewsizes[height++]= 684;
+        viewsizes[height++]= 552;
+        viewsizes[height++]= 716;
+        viewsizes[height++]= 568;
+        viewsizes[height++]= 748;
+        viewsizes[height++]= 584;
+        viewsizes[height++]= 800;
+        viewsizes[height++]= 600;
+        viewsizes[height++]= 800;
+        viewsizes[height++]= 600;
+        viewsizes[height++]= 800;
+        viewsizes[height++]= 600;
+        viewsizes[height++]= 800;
+        viewsizes[height++]= 600;
+    }
+
+
+    if ((size<0) || (size>=MAXVIEWSIZES)) { //bna added
+        printf("Illegal screen size = %d\n",size);
+        size = 8;//set default value
+        viewsize = 8;
+    }
+
+    //if ((size<0) || (size>=MAXVIEWSIZES))
+    //   Error("Illegal screen size = %ld\n",size);
+
+    viewwidth  = viewsizes[ size << 1 ];         // must be divisable by 16
+    viewheight = viewsizes[ ( size << 1 ) + 1 ]; // must be even
+
+    maxheight = iGLOBAL_SCREENHEIGHT;
+    topy      = 0;
+
+    // Only keep the kills flag
+    StatusBar &= ~( BOTTOM_STATUS_BAR | TOP_STATUS_BAR |
+                    STATUS_PLAYER_STATS );
+
+    if ( SHOW_KILLS() )
+    {
+        // Account for height of kill boxes
+        maxheight -= 24;
+    }
+
+    if ( size < 9 )
+    {
+        StatusBar |= TOP_STATUS_BAR;
+
+        // Account for height of top status bar
+        maxheight -= 16;
+        topy      += 16;
+    }
+
+//   if ( size == 7 ){maxheight -= 16;}//bna++
+//   if ( size <= 6 ){topy -= 8;}//bna++
+
+    if ( size < 8 )
+    {
+        // Turn on health and ammo bar
+        StatusBar |= BOTTOM_STATUS_BAR;
+
+        maxheight -= 16;
+
+    }
+    else if ( size < 10 )
+    {
+        // Turn on transparent health and ammo bar
+        StatusBar |= STATUS_PLAYER_STATS;
+    }
+    //   SetTextMode (  );
+    //   viewheight=viewheight;
+    height = viewheight;
+    if ( height > 168*iGLOBAL_SCREENHEIGHT/200 )
+    {
+        // Prevent weapon from being scaled too big
+        height = 168*iGLOBAL_SCREENHEIGHT/200;
+    }
+
+    weaponscale = ( height << 16 ) / 168;//( height << 16 ) = 170 * 65536
+
+
+    centerx     = viewwidth >> 1;
+    centery     = viewheight >> 1;
+    centeryfrac = (centery << 16);
+    yzangleconverter = ( 0xaf85 * viewheight ) / iGLOBAL_SCREENHEIGHT;
+
+    // Center the view horizontally
+    screenx = ( iGLOBAL_SCREENWIDTH - viewwidth ) >> 1;
+
+    if ( viewheight >= maxheight )
+    {
+        screeny = topy;
+        viewheight = maxheight;
+    }
+    else
+    {
+        // Center the view vertically
+        screeny = ( ( maxheight - viewheight ) >> 1 ) + topy;
+    }
+
+    // Calculate offset of view window
+#ifdef DOS
+    screenofs = ( screenx >> 2 ) + ylookup[ screeny ];
+#else
+    screenofs = screenx + ylookup[ screeny ];
+#endif
+
+//
+// calculate trace angles and projection constants
+//
+
+    ResetFocalWidth();
+
+
+// Already being called in ResetFocalWidth
+//   SetViewDelta();
+
+
+    CalcProjection();
+
+}
+
+
+//******************************************************************************
+//
+// DrawCPUJape ()
+//
+//******************************************************************************
+
+void DrawCPUJape
+(
+    void
+)
+
+{
+    int width;
+    int height;
+
+    CurrentFont = tinyfont;
+    VW_MeasurePropString( YourComputerSucksString, &width, &height );
+
+    DrawGameString( 160 - width / 2, 100 + 48 / 2 + 2,
+                    YourComputerSucksString, true );
+}
+
+
+/*
+==========================
+=
+= SetupScreen
+=
+==========================
+*/
+
+void SetupScreen ( boolean flip )
+{
+    pic_t *shape;
+
+    SetViewSize(viewsize);
+
+    if ( viewsize < 7 )
+    {
+        shape =  ( pic_t * )W_CacheLumpName( "backtile", PU_CACHE, Cvt_pic_t, 1 );
+        //DrawTiledRegion( 0, 16, 320, 200 - 32, 0, 16, shape );
+        DrawTiledRegion( 0, 16, iGLOBAL_SCREENWIDTH, iGLOBAL_SCREENHEIGHT - 32, 0, 16, shape );//bna++
+    }
+
+    if ( viewsize == 0 )
+    {
+        DrawCPUJape();
+    }
+
+    DrawPlayScreen (true);
+    if (flip==true)
+    {
+        ThreeDRefresh();
+        VL_CopyDisplayToHidden();
+    }
+}
+
+
+
+void LoadColorMap( void )
+{
+    int i,j;
+    int lump, length;
+
+    if (ColorMapLoaded==1)
+        Error("Called LoadColorMap twice\n");
+    ColorMapLoaded=1;
+//
+//   load in the light tables
+//   256 byte align tables
+//
+
+    lump = W_GetNumForName("colormap");
+    length = W_LumpLength (lump) + 255;
+    colormap = SafeMalloc (length);
+    colormap = (byte *)( ((long)colormap + 255)&~0xff);
+    W_ReadLump (lump,colormap);
+
+// Fix fire colors in colormap
+
+    for (i=31; i>=16; i--)
+        for (j=0xea; j<0xf9; j++)
+            colormap[i*256+j]=colormap[(((i-16)/4+16))*256+j];
+
+// Get special maps
+
+    lump = W_GetNumForName("specmaps");
+    length = W_LumpLength (lump+1) + 255;
+    redmap = SafeMalloc (length);
+    redmap = (byte *)( ((long)redmap + 255)&~0xff);
+    W_ReadLump (lump+1,redmap);
+    greenmap = redmap+(16*256);
+
+// Get player colormaps
+
+//   if (modemgame==true)
+    {
+        lump = W_GetNumForName("playmaps")+1;
+        for (i=0; i<MAXPLAYERCOLORS; i++)
+        {
+            length = W_LumpLength (lump+i) + 255;
+            playermaps[i] = SafeMalloc (length);
+            playermaps[i] = (byte *)( ((long)playermaps[i] + 255)&~0xff);
+            W_ReadLump (lump+i,playermaps[i]);
+        }
+    }
+
+    if (!quiet)
+        printf("RT_VIEW: Colormaps Initialized\n");
+
+}
+
+/*
+==========================
+=
+= SetupLightLevels
+=
+==========================
+*/
+#define LIGHTRATEBASE 252
+#define LIGHTRATEEND  267
+#define LIGHTLEVELBASE 216
+#define LIGHTLEVELEND  223
+void SetupLightLevels ( void )
+{
+    int glevel;
+
+    periodic=false;
+    fog=0;
+    lightsource=0;
+
+// Set up light level for level
+
+    if (((word)MAPSPOT(2,0,1)>=104) && ((word)MAPSPOT(2,0,1)<=105))
+        fog=(word)MAPSPOT(2,0,1)-104;
+    else
+        Error ("There is no Fog icon on map %d\n",gamestate.mapon);
+    if ((word)MAPSPOT(3,0,1)==139)
+    {
+        if (fog==0)
+        {
+            lightsource=1;
+            lights=Z_Malloc(MAPSIZE*MAPSIZE*(sizeof(unsigned long)),PU_LEVEL,NULL);
+            memset (lights,0,MAPSIZE*MAPSIZE*(sizeof(unsigned long)));
+        }
+        else
+            Error("You cannot use light sourcing on a level with fog on map %d\n",gamestate.mapon);
+    }
+    else if ((word)MAPSPOT(3,0,1))
+        Error("You must use the lightsource icon or nothing at all at (3,0) in plane 1 on map %d\n",gamestate.mapon);
+    if (((word)MAPSPOT(2,0,0)>=LIGHTLEVELBASE) && ((word)MAPSPOT(2,0,0)<=LIGHTLEVELEND))
+        glevel=(MAPSPOT(2,0,0)-LIGHTLEVELBASE);
+    else
+        Error("You must specify a valid darkness level icon at (2,0) on map %d\n",gamestate.mapon);
+
+    SetLightLevels ( glevel );
+
+    if (((word)MAPSPOT(3,0,0)>=LIGHTRATEBASE) && ((word)MAPSPOT(3,0,0)<=LIGHTRATEEND))
+        glevel=(MAPSPOT(3,0,0)-LIGHTRATEBASE);
+    else
+    {
+//      Error("You must specify a valid darkness rate icon at (3,0) on map %ld\n",gamestate.mapon);
+        glevel = 4;
+    }
+
+    SetLightRate ( glevel );
+    lightningtime=0;
+    lightningdistance=0;
+    lightninglevel=0;
+    lightningdelta=0;
+    lightningsoundtime=0;
+}
+
+/*
+==========================
+=
+= SetLightLevels
+=
+==========================
+*/
+void SetLightLevels ( int darkness )
+{
+    if (fog==0)
+    {
+        baseminshade=0x10+((7-darkness)>>1);
+        basemaxshade=0x1f-(darkness>>1);
+    }
+    else
+    {
+        baseminshade=darkness;
+        basemaxshade=0x10;
+    }
+    minshade=baseminshade;
+    maxshade=basemaxshade;
+    darknesslevel=darkness;
+}
+
+/*
+==========================
+=
+= GetLightLevelTile
+=
+==========================
+*/
+int GetLightLevelTile ( void )
+{
+    if (fog==0)
+    {
+        return ((7-((baseminshade-0x10)<<1))+LIGHTLEVELBASE);
+    }
+    else
+    {
+        return (baseminshade+LIGHTLEVELBASE);
+    }
+}
+
+
+/*
+==========================
+=
+= SetLightRate
+=
+==========================
+*/
+void SetLightRate ( int rate )
+{
+    normalshade=(HEIGHTFRACTION+8)-rate;
+    if (normalshade>14) normalshade=14;
+    if (normalshade<3) normalshade=3;
+}
+
+/*
+==========================
+=
+= GetLightRate
+=
+==========================
+*/
+int GetLightRate ( void )
+{
+    return ((HEIGHTFRACTION+8)-normalshade);
+}
+
+/*
+==========================
+=
+= GetLightRateTile
+=
+==========================
+*/
+int GetLightRateTile ( void )
+{
+    return ((HEIGHTFRACTION+8)-normalshade+LIGHTRATEBASE);
+}
+
+
+
+/*
+==========================
+=
+= UpdateLightLevel
+=
+==========================
+*/
+void UpdateLightLevel (int area)
+{
+    int numlights;
+    int targetmin;
+    int targetmax;
+    int numtiles;
+
+    if (fog==true)
+        return;
+
+    numtiles=(numareatiles[area]>>5)-2;
+    numlights=(LightsInArea[area]-numtiles)>>1;
+
+    if (numlights<0)
+        numlights=0;
+    if (numlights>GENERALNUMLIGHTS)
+        numlights=GENERALNUMLIGHTS;
+    targetmin=baseminshade+(GENERALNUMLIGHTS-numlights);
+    targetmax=basemaxshade-numlights;
+    if (targetmax<baseminshade)
+        targetmax=baseminshade;
+    if (targetmin>targetmax)
+        targetmin=targetmax;
+
+    if (minshade>targetmin)
+        minshade-=1;
+    else if (minshade<targetmin)
+        minshade+=1;
+
+    if (maxshade>targetmax)
+        maxshade-=1;
+    else if (maxshade<targetmax)
+        maxshade+=1;
+
+#if 0
+    targetlevel=baseminshade+(GENERALNUMLIGHTS-numlights);
+    if (abs(minshade-targetlevel)==1)
+        minshade=targetlevel;
+    else if (minshade>targetlevel)
+        minshade-=2;
+    else if (minshade<targetlevel)
+        minshade+=2;
+#endif
+}
+
+/*
+==========================
+=
+= SetIllumination
+=
+= Postive value lightens
+= Negative value darkens
+=
+==========================
+*/
+void SetIllumination (int level)
+{
+    if (fog)
+        return;
+    maxshade-=level;
+    if (maxshade>31)
+        maxshade=31;
+    if (maxshade<0x10)
+        maxshade=0x10;
+    minshade-=level;
+    if (minshade<0x10)
+        minshade=0x10;
+    if (minshade>31)
+        minshade=31;
+}
+
+/*
+==========================
+=
+= GetIlluminationDelta
+=
+==========================
+*/
+int GetIlluminationDelta (void)
+{
+    if (fog)
+        return 0;
+    else
+        return maxshade-basemaxshade;
+}
+
+/*
+==========================
+=
+= UpdateLightning
+=
+==========================
+*/
+void UpdateLightning (void)
+{
+    if (periodic==true)
+    {
+        UpdatePeriodicLighting();
+        return;
+    }
+    if ((fog==1) || (lightning==false))
+        return;
+
+    if (lightningtime<=0)
+    {
+        if (lightningsoundtime>0)
+            SD_Play3D (SD_LIGHTNINGSND, 0, lightningdistance);
+        lightningtime=GameRandomNumber("UpdateLightning",0)<<1;
+        lightningdistance=GameRandomNumber("UpdateLightning",0);
+        lightninglevel=(255-lightningdistance)>>LIGHTNINGLEVEL;
+        if (lightninglevel<MINLIGHTNINGLEVEL)
+            lightninglevel=MINLIGHTNINGLEVEL;
+        if (lightninglevel>MAXLIGHTNINGLEVEL)
+            lightninglevel=MAXLIGHTNINGLEVEL;
+        lightningdelta=lightninglevel>>1;
+        lightningsoundtime=lightningdistance>>1;
+        if (lightningdistance<100)
+        {
+            SetIllumination(lightninglevel);
+        }
+    }
+    else if (lightninglevel>0)
+    {
+        lightninglevel-=lightningdelta;
+        if (lightninglevel<=0)
+        {
+            lightninglevel=0;
+        }
+    }
+    else
+        lightningtime--;
+    if (lightningsoundtime)
+    {
+        lightningsoundtime--;
+        if (lightningsoundtime<=0)
+        {
+            int volume;
+
+            volume=255-lightningdistance;
+            if (volume>170) volume=170;
+            SD_PlayPitchedSound ( SD_LIGHTNINGSND, volume,-(lightningdistance<<2));
+            lightningsoundtime=0;
+        }
+    }
+}
+
+/*
+==========================
+=
+= UpdatePeriodicLighting
+=
+==========================
+*/
+#define PERIODICMAG (6)
+#define PERIODICSTEP (20)
+#define PERIODICBASE (0x0f)
+void UpdatePeriodicLighting (void)
+{
+    int val;
+
+    val=FixedMul(PERIODICMAG,sintable[periodictime]);
+    periodictime=(periodictime+PERIODICSTEP)&(FINEANGLES-1);
+    basemaxshade=PERIODICBASE+(PERIODICMAG)+val;
+    baseminshade=basemaxshade-GENERALNUMLIGHTS-1;
+}
+
+/*
+==========================
+=
+= SetModemLightLevel
+=
+==========================
+*/
+void SetModemLightLevel ( int type )
+{
+    periodic=false;
+    fulllight=false;
+    switch (type)
+    {
+    case bo_light_dark:
+        MAPSPOT(2,0,0)=(word)216;
+        MAPSPOT(3,0,0)=(word)255;
+        MAPSPOT(3,0,1)=(word)139;
+        MAPSPOT(2,0,1)=(word)104;
+        SetupLightLevels ();
+        break;
+    case bo_light_normal:
+        break;
+    case bo_light_bright:
+        MAPSPOT(2,0,0)=(word)223;
+        MAPSPOT(3,0,0)=(word)267;
+        MAPSPOT(3,0,1)=(word)0;
+        MAPSPOT(2,0,1)=(word)104;
+        SetupLightLevels ();
+        break;
+    case bo_light_fog:
+        MAPSPOT(2,0,0)=(word)219;
+        MAPSPOT(3,0,0)=(word)259;
+        MAPSPOT(2,0,1)=(word)105;
+        MAPSPOT(3,0,1)=(word)0;
+        SetupLightLevels ();
+        break;
+    case bo_light_periodic:
+        fog=0;
+        MAPSPOT(2,0,1)=(word)104;
+        MAPSPOT(3,0,1)=(word)139;
+        SetupLightLevels ();
+        periodic=true;
+        break;
+    case bo_light_lightning:
+        if (sky!=0)
+        {
+            MAPSPOT(2,0,0)=(word)222;
+            MAPSPOT(3,0,0)=(word)255;
+            MAPSPOT(3,0,1)=(word)139;
+            MAPSPOT(2,0,1)=(word)104;
+            SetupLightLevels ();
+            lightning=true;
+        }
+        break;
+    }
+}
+
--- /dev/null
+++ b/rott/rt_view.h
@@ -1,0 +1,131 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+//***************************************************************************
+//
+//    RT_VIEW.H
+//
+//***************************************************************************
+#ifndef _rt_view_public
+#define _rt_view_public
+
+#include "modexlib.h"
+
+#define HEIGHTFRACTION 6
+#define MAXVIEWSIZES   11
+
+//#define FOCALWIDTH 160//160
+//#define FPFOCALWIDTH 160.0//160.0
+
+
+#define NUMGAMMALEVELS 8
+#define GAMMAENTRIES (64*8)
+
+#define GENERALNUMLIGHTS (5)
+
+extern int StatusBar;
+
+// Kill count
+#define STATUS_KILLS        0x1
+// Transparent health bar
+#define STATUS_PLAYER_STATS 0x2
+// Bottom status bar
+#define BOTTOM_STATUS_BAR   0x4
+// Top status bar
+#define TOP_STATUS_BAR      0x8
+
+#define SHOW_KILLS()             ( StatusBar & STATUS_KILLS )
+#define SHOW_PLAYER_STATS()      ( StatusBar & STATUS_PLAYER_STATS )
+#define SHOW_BOTTOM_STATUS_BAR() ( StatusBar & BOTTOM_STATUS_BAR )
+#define SHOW_TOP_STATUS_BAR()    ( StatusBar & TOP_STATUS_BAR )
+
+#define YOURCPUSUCKS_Y      ( 100 + 48 / 2 + 2 )
+#define YOURCPUSUCKS_HEIGHT 8
+
+#define MAXPLAYERCOLORS (11)
+typedef enum
+{
+    pc_gray,
+    pc_brown,
+    pc_black,
+    pc_tan,
+    pc_red,
+    pc_olive,
+    pc_blue,
+    pc_white,
+    pc_green,
+    pc_purple,
+    pc_orange
+} playercolors;
+
+extern byte * playermaps[MAXPLAYERCOLORS];
+//extern short  pixelangle[MAXVIEWWIDTH];
+extern short  pixelangle[800];
+extern byte   gammatable[GAMMAENTRIES];
+extern int    gammaindex;
+extern byte   uniformcolors[MAXPLAYERCOLORS];
+
+extern  byte mapmasks1[4][9];                   // Map Mask for post scaling
+extern  byte mapmasks2[4][9];                   // Map Mask for post scaling
+extern  byte mapmasks3[4][9];                   // Map Mask for post scaling
+
+extern  int normalshade;                        // Normal shading level for stuff
+extern  int maxshade;                           // max shading level
+extern  int minshade;                           // min shading level
+extern  int baseminshade;
+extern  int basemaxshade;
+extern  int    viewheight;
+extern  int    viewwidth;
+extern  longword heightnumerator;
+extern  fixed  scale;
+extern  int    screenofs;
+extern  int    centerx;
+extern  int centery;
+extern  int centeryfrac;
+extern  int fulllight;
+extern  byte * colormap;
+extern  byte * greenmap;
+extern  byte * redmap;
+extern  int weaponscale;
+extern  int viewsize;
+extern  int focalwidth;
+extern  int yzangleconverter;
+extern  int lightninglevel;
+extern  boolean  lightning;
+extern  int    darknesslevel;
+
+void DrawCPUJape( void );
+void SetupScreen ( boolean flip );
+void ResetFocalWidth ( void );
+void ChangeFocalWidth ( int amount );
+void SetViewSize ( int size );
+void LoadColorMap( void );
+void UpdateLightLevel (int area);
+void SetIllumination (int level);
+int  GetIlluminationDelta (void);
+void UpdateLightning (void);
+void SetLightLevels ( int darkness );
+void SetupLightLevels ( void );
+void SetLightRate ( int rate );
+int GetLightRate ( void );
+void SetModemLightLevel ( int type );
+int GetLightRateTile ( void );
+int GetLightLevelTile ( void );
+
+#endif
--- /dev/null
+++ b/rott/sbconfig.c
@@ -1,0 +1,499 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+/* Copyright 1995 Spacetec IMC Corporation */
+
+#if defined(__BORLANDC__)
+#  pragma inline
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <dos.h>
+
+typedef long fixed;
+
+#include "rt_def.h"
+
+#include "develop.h"
+#include "sbconfig.h"
+//MED
+#include "memcheck.h"
+
+/* ----------------------------------------------------------------------- */
+
+#define DEFAULT_CONFIG_FILENAME  "sbconfig.dat"
+
+#define NUM_ELEMENTS(x) (sizeof(x)/sizeof(x[0]))
+#define SIGN(x) ((x<0)?-1:1)
+
+/* ----------------------------------------------------------------------- */
+
+#if defined(__BORLANDC__)
+
+fixed FIXED_MUL(fixed a, fixed b)
+{
+
+    fixed ret_code;
+
+    asm {
+
+        mov  eax,a
+        mov  edx,b
+        imul edx
+        shrd eax,edx,16
+        mov  ret_code,eax
+    }
+
+    return ret_code;
+}
+
+#elif defined(_MSC_VER)
+
+/* Microsoft C7.0 can not be done with inline assembler because it
+   can not handle 32-bit instructions
+*/
+fixed FIXED_MUL(fixed a,fixed b)
+{
+    fixed sgn,ah,al,bh,bl;
+
+    sgn = (SIGN(a) ^ SIGN(b)) ? -1 : 1 ;
+    ah = (a >> 16) & 0xffff ;
+    al = (a        & 0xffff);
+    bh = (b >> 16) & 0xffff ;
+    bl = (b        & 0xffff);
+
+    return sgn * ( ((al*bl)>>16) + (ah*bl) + (al*bh) + ((ah*bh)<<16) );
+}
+
+#elif defined(__WATCOMC__)
+
+fixed FIXED_MUL(fixed a, fixed b);
+
+#pragma aux FIXED_MUL =     \
+   "imul    edx"            \
+   "shrd    eax,edx,16"     \
+   parm     [eax] [edx]     \
+   value    [eax]           \
+   modify   exact [eax]     ;
+
+#endif /* definition of inline FIXED_MUL */
+
+
+static
+fixed StrToFx1616(char *string, char **ret_string)
+{
+    long  whole;
+    long  fract;
+    fixed result;
+    int   sign;
+
+    /* Skip whitespace */
+    while((*string==' ')||(*string=='\t')||(*string=='\n')) string++;
+
+    /* Accept numbers in the form: [+-]?[0-9]+(.[0-9]*)
+    */
+
+    sign=1;
+    if(*string=='-')
+    {
+        string++;
+        sign=-1;
+    }
+    else if(*string=='+')
+    {
+        string++;
+        sign=1;
+    }
+
+    /* Read in the whole part */
+    whole=0;
+    while((*string>='0')&&(*string<='9'))
+        whole=whole*10+(*string++)-'0';
+
+    /* Read the optional fraction part */
+    fract=0;
+    if(*string=='.')
+    {
+        long place=1;
+        string++;
+        while((*string>='0')&&(*string<='9'))
+        {
+            fract=fract*10+(*string++)-'0';
+            place*=10;
+        }
+        /* Convert to fixed point */
+        fract=(fract<<16)/place;
+    }
+
+    if(ret_string) *ret_string=string;
+
+    if(sign==1)
+        result= (whole<<16) + fract;
+    else
+        result=-(whole<<16) + fract;
+
+    return result;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static char *SbButtonNames[]= {
+    "BUTTON_A",
+    "BUTTON_B",
+    "BUTTON_C",
+    "BUTTON_D",
+    "BUTTON_E",
+    "BUTTON_F"
+};
+
+static int         cfgFileVersion=0;
+static char        cfgButtons[NUM_ELEMENTS(SbButtonNames)][MAX_STRING_LENGTH];
+static WarpRecord *pCfgWarps;
+static int         nCfgWarps=0;
+
+/*-------------------------------------------------------------------------*/
+
+/* Read a string in the form: "{#, #, #}"
+ * and return a pointer to the character AFTER the '}'
+ * or NULL if error
+ */
+static char *GetWarpLevels(char *string, WarpRange *pw)
+{
+    short value;
+    fixed fxvalue;
+
+    if((*string++)!='{')
+        return NULL;
+
+    if(!*string)
+        return NULL;
+
+    /* Expecting the first number - low */
+    value=(short)strtol(string, &string, 0);
+    if(pw) pw->low=value;
+
+    /* Skip any whitespace */
+    while(isspace(*string)) string++;
+
+    if(*string++!=',')
+        return NULL;
+
+    /* Expecting the second number - high */
+    value=(short)strtol(string, &string, 0);
+    if(pw) pw->high=value;
+
+    /* Skip any whitespace */
+    while(isspace(*string)) string++;
+
+    if(*string++!=',')
+        return NULL;
+
+    /* Expecting the third number - multiplier */
+    fxvalue=StrToFx1616(string, &string);
+    if(pw) pw->mult=fxvalue;
+
+    /* Skip any whitespace */
+    while(isspace(*string)) string++;
+
+    if(*string!='}')
+        return NULL;
+
+    return string+1;
+}
+
+
+
+static int GetWarp(char *string, WarpRecord *pRecord)
+{
+    int        nWarp;
+    WarpRange *pWarp;
+
+    /* Only update the field if we successfully read the entire line */
+    nWarp=0;
+    pWarp=NULL;
+
+    /* Skip whitespace */
+    while(isspace(*string)) string++;
+
+    if(*string++!='{') return 0;
+
+    while(string && *string)
+    {
+        switch(*string)
+        {
+        case ' ':
+        case '\t':
+        case '\n':
+            string++;
+            break;
+
+        case ',':
+            string++;
+            break;
+
+        case '{':
+            if(nWarp++==0)
+                pWarp=malloc(sizeof(WarpRange));
+            else
+                pWarp=realloc(pWarp, nWarp*sizeof(WarpRange));
+
+            string=GetWarpLevels(string, pWarp+nWarp-1);
+            break;
+
+        case '}':
+            pRecord->nWarp=nWarp;
+            pRecord->pWarp=pWarp;
+            return 1;
+        }
+    }
+
+    /* Early EOL (didn't get closing '}') */
+    if(nWarp) free(pWarp);
+    return 0;
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+int SbConfigParse(char *_filename)
+{
+    int             i;
+    FILE           *file;
+    char           *pc;
+    char            buffer[128];
+    char filename[MAX_PATH];
+
+    if(!_filename) _filename=DEFAULT_CONFIG_FILENAME;
+
+    strncpy(filename, _filename, sizeof (filename));
+    filename[sizeof (filename) - 1] = '\0';
+    FixFilePath(filename);
+
+    if(!(file=fopen(filename, "r")))
+    {
+        printf("Config file: %s, not found\n", filename);
+        return 0;
+    }
+
+    while(fgets(buffer, sizeof(buffer), file))
+    {
+        int lineParsed=0;
+
+        /* each line in config file starts with either a ;, VERSION or an
+        ** element of GameButtonNames or WarpNames
+        */
+        pc=strtok(buffer, " \t\n,");
+
+        if(*pc==';')									/* commented out line? */
+            continue;
+
+        /* VERSION?  The version will be used in the future to allow fx1616
+        **           values in the config file
+        */
+        if(!stricmp(pc,"VERSION"))
+        {
+            pc=strtok(NULL, " \t\n,");
+            cfgFileVersion=atoi(pc);
+        }
+
+        /* Check if first token is an element of SbButtonNames */
+        for(i=0; i<NUM_ELEMENTS(SbButtonNames); i++)
+            if(!stricmp(pc, SbButtonNames[i]))
+            {
+                lineParsed=1;
+
+                /* Save the next token in the appropriate slot */
+                pc=strtok(NULL," \t\n,");
+
+                strncpy(cfgButtons[i], pc, MAX_STRING_LENGTH-1);
+                cfgButtons[i][MAX_STRING_LENGTH-1]=0;
+            }
+
+        /* If the first token is not from GameButtonNames,
+        ** it must be a WarpName
+        */
+        if(!lineParsed)
+        {
+            char *name;
+
+            name=pc;
+            pc=pc+strlen(pc)+1;			/* Skip this token */
+            while(isspace(*pc)) pc++;	/* Skip any whitespace */
+
+            if(*pc=='{')
+            {
+                WarpRecord warpRec;
+
+                strcpy(warpRec.name, name);
+                warpRec.pWarp=NULL;
+                warpRec.nWarp=0;
+
+                if(GetWarp(pc, &warpRec))
+                {
+                    if(nCfgWarps++==0)
+                        pCfgWarps=(WarpRecord *)malloc(sizeof(WarpRecord));
+                    else
+                        pCfgWarps=(WarpRecord *)realloc(pCfgWarps, nCfgWarps*sizeof(WarpRecord));
+                    pCfgWarps[nCfgWarps-1]=warpRec;
+                }
+            }
+        }
+    } /* end of while getting lines from config file */
+
+    fclose(file);
+    return 1;
+}
+
+/*-------------------------------------------------------------------------*/
+
+char *SbConfigGetButton(char *btnName)
+{
+    int i;
+    for(i=0; i<NUM_ELEMENTS(SbButtonNames); i++)
+    {
+        if(!stricmp(btnName, SbButtonNames[i]))
+            if(cfgButtons[i][0])
+                return cfgButtons[i];
+            else
+                return NULL;	/* Empty slot */
+
+        if(!stricmp(btnName, cfgButtons[i]))
+            return SbButtonNames[i];
+    }
+
+    /* Unknown button name */
+    return NULL;
+}
+
+
+
+int SbConfigGetButtonNumber(char *btnName)
+{
+    int i;
+    for(i=0; i<NUM_ELEMENTS(SbButtonNames); i++)
+    {
+        if(!stricmp(btnName, cfgButtons[i]))
+            return i;
+    }
+
+    /* Unknown button name */
+    return -1;
+}
+
+/*-------------------------------------------------------------------------*/
+
+WarpRecord *SbConfigGetWarpRange(char *rngName)
+{
+    int i;
+    for(i=0; i<nCfgWarps; i++)
+        if(!stricmp(rngName, pCfgWarps[i].name))
+            return &pCfgWarps[i];
+
+    return NULL;
+}
+
+/*-------------------------------------------------------------------------*/
+
+fixed SbFxConfigWarp(WarpRecord *warp, short value)
+{
+    int  i;
+    short absValue;
+    fixed accum;
+    int   sign;
+
+    if(!warp) return INT_TO_FIXED(value);
+
+    absValue=value;
+    sign=1;
+    if(absValue<0)
+    {
+        absValue= (short)-absValue;
+        sign=-1;
+    }
+
+    accum=INT_TO_FIXED(0);
+
+    for(i=0; i<warp->nWarp; i++)
+    {
+        if(absValue<=warp->pWarp[i].low)
+            ;	/* Ignore it if below this range (if required, will have
+					**	been caught by the previous warp)
+					*/
+        else if((absValue>warp->pWarp[i].low) && (absValue<=warp->pWarp[i].high))
+        {
+            fixed diff;
+            fixed partial;
+            diff=INT_TO_FIXED((long)absValue-(long)warp->pWarp[i].low);
+            partial=FIXED_MUL(diff, warp->pWarp[i].mult);
+            accum=FIXED_ADD(accum, partial);
+            break;	/* Exit the for loop */
+        }
+        else	/* Accumulate if greater than this range */
+        {
+            fixed partial;
+            partial=FIXED_MUL(INT_TO_FIXED((long)warp->pWarp[i].high-(long)warp->pWarp[i].low),
+                              warp->pWarp[i].mult);
+            accum=FIXED_ADD(accum, partial);
+        }
+    }
+
+    if(sign==1)
+        return  accum;
+    else
+        return -accum;
+
+#if 0	/* Old technique */
+    if((absValue>=warp->pWarp[i].low) && (absValue<=warp->pWarp[i].high))
+        if(warp->pWarp[i].shift>=0)
+            value=accum+((absValue-warp->pWarp[i].low)<<warp->pWarp[i].shift);
+        else
+            value=accum+((absValue-warp->pWarp[i].low)>>abs(warp->pWarp[i].shift));
+    else if(warp->pWarp[i].shift>=0)
+        accum+=(warp->pWarp[i].high-warp->pWarp[i].low)<<warp->pWarp[i].shift;
+    else
+        accum+=(warp->pWarp[i].high-warp->pWarp[i].low)>>abs(warp->pWarp[i].shift);
+
+    if(absValue>warp->pWarp[warp->nWarp-1].high)
+        value=accum;
+
+    return sign*value;
+#endif
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+long SbConfigWarp(WarpRecord *warp, short value)
+{
+    /* An apparent bug in the msc70 compiler, trashes r
+       if it is on the stack.  Leave in unitialized global segment.
+    */
+    static fixed r;
+
+    r = SbFxConfigWarp(warp,value);
+
+    return r >> 16 ;
+}
+
+
+/*-------------------------------------------------------------------------*/
+
--- /dev/null
+++ b/rott/sbconfig.h
@@ -1,0 +1,132 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+#ifndef SBCONFIG_H
+#define SBCONFIG_H
+/* ----------------------------------------------------------------------- */
+/* See the bottom of this file for a syntax diagram for the config file */
+
+#define MAX_STRING_LENGTH 40
+
+/* ----------------------------------------------------------------------- */
+
+//typedef long fixed;	/* 16.16 fixed pt number */
+
+#define INT_TO_FIXED(n)   ((fixed)((long)(n)<<16))
+#define FIXED_TO_INT(n)   ((long)((n)>>16))
+#define FLOAT_TO_FIXED(n) ((fixed)((n)*65536.0))
+
+#define FIXED_ADD(a, b)		((a)+(b))
+#define FIXED_SUB(a, b)		((a)-(b))
+
+/* ----------------------------------------------------------------------- */
+
+typedef struct {
+    short low; 			/* range of input values this warp covers */
+    short high;
+    fixed mult;		/* multiplier to be applied to this range */
+} WarpRange;
+
+
+
+typedef struct {
+    char       name[MAX_STRING_LENGTH];
+    WarpRange *pWarp;
+    int        nWarp;
+} WarpRecord;
+
+/* ----------------------------------------------------------------------- */
+
+/* Parse the config file */
+int   SbConfigParse(char *filename);
+
+/* Get the button config name for the button named <btnName> or return NULL
+ * if none exists.  <btnName> can be either the left or the right side name.
+ * So, for the config line:
+ *
+ * BUTTON_A MY_BUTTON
+ *
+ * ConfigGetButton("BUTTON_A") will return "MY_BUTTON"
+ * ConfigGetButton("MY_BUTTON") will return "BUTTON_A"
+ *
+ * Note that this makes it illegal to have game button names have the names
+ * "BUTTON_A", "BUTTON_B", "BUTTON_C", etc...
+ *
+ * Also, the comparison is CASE INSENSITIVE.
+ */
+char *SbConfigGetButton(char *btnName);
+int   SbConfigGetButtonNumber(char *btnName);
+
+/*
+ * Get the warp ranges for the config range named <rngName> or return NULL
+ * if none exists.
+ */
+WarpRecord *SbConfigGetWarpRange(char *rngName);
+
+/*
+ * Warp a value based on the given warp range
+ */
+fixed SbFxConfigWarp(WarpRecord *warp, short value);  /* returns fixed pt */
+long    SbConfigWarp(WarpRecord *warp, short value);  /* returns integer */
+
+/* ----------------------------------------------------------------------- */
+/* Lexical Definitions:
+**
+** comment:	;[^\n]*\n
+** integer: [0-9]+
+** identifier: [A-Za-z_][A-Za-z_0-9]*
+**
+*/
+/* Syntax Diagram:	(Line by Line parsing)
+**
+**
+** ConfigFile:
+**           |	ConfigLine ConfigFile
+**	          ;
+**
+** ConfigLine:
+**           | comment
+**           | VersionLine comment
+**           | ButtonLine comment
+**           | RangeLine comment
+**           ;
+**
+** VersionLine:	'VERSION' integer
+**            ;
+**
+** ButtonLine:	'BUTTON_A' identifier
+**           |	'BUTTON_B' identifier
+**           |	'BUTTON_C' identifier
+**           |	'BUTTON_D' identifier
+**           |	'BUTTON_E' identifier
+**           |	'BUTTON_F' identifier
+**           ;
+**
+** RangeLine: identifier '{' RangeList '}'
+**          ;
+**
+** RangeList:
+**          | '{' integer ',' integer ',' integer '}'
+**          | '{' integer ',' integer ',' integer '}' ',' RangeList
+**          ;
+**
+*/
+/* ----------------------------------------------------------------------- */
+#endif
+
--- /dev/null
+++ b/rott/scriplib.c
@@ -1,0 +1,319 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+// scriplib.c
+
+#ifdef DOS
+#include <io.h>
+#include <dos.h>
+#endif
+
+#include <fcntl.h>
+#include <string.h>
+
+#include "rt_def.h"
+#include "scriplib.h"
+#include "rt_util.h"
+//MED
+#include "memcheck.h"
+
+/*
+=============================================================================
+
+						PARSING STUFF
+
+=============================================================================
+*/
+
+char    token[MAXTOKEN];
+char    name[MAXTOKEN*2];
+char    scriptfilename[512];
+char    *scriptbuffer,*script_p,*scriptend_p;
+int     scriptline;
+boolean endofscript;
+boolean tokenready;                     // only true if UnGetToken was just called
+
+/*
+==============
+=
+= LoadScriptFile
+=
+==============
+*/
+
+void LoadScriptFile (char *filename)
+{
+    long            size;
+
+    size = LoadFile (filename, (void **)&scriptbuffer);
+
+    snprintf(scriptfilename, sizeof(scriptfilename), "%s", filename);
+    script_p = scriptbuffer;
+    scriptend_p = script_p + size;
+    scriptline = 1;
+    endofscript = false;
+    tokenready = false;
+}
+
+
+/*
+==============
+=
+= UnGetToken
+=
+= Signals that the current token was not used, and should be reported
+= for the next GetToken.  Note that
+
+GetToken (true);
+UnGetToken ();
+GetToken (false);
+
+= could cross a line boundary.
+=
+==============
+*/
+
+void UnGetToken (void)
+{
+    tokenready = true;
+}
+
+
+/*
+==============
+=
+= GetToken
+=
+==============
+*/
+
+void GetToken (boolean crossline)
+{
+    char    *token_p;
+
+    if (tokenready)                         // is a token allready waiting?
+    {
+        tokenready = false;
+        return;
+    }
+
+    if (script_p >= scriptend_p)
+    {
+        if (!crossline)
+            Error ("Line %i is incomplete\nin file %s\n",
+                   scriptline,scriptfilename);
+        endofscript = true;
+        return;
+    }
+
+//
+// skip space
+//
+skipspace:
+    while (*script_p <= 32)
+    {
+        if (script_p >= scriptend_p)
+        {
+            if (!crossline)
+                Error ("Line %i is incomplete\nin file %s\n",
+                       scriptline,scriptfilename);
+            endofscript = true;
+            return;
+        }
+        if (*script_p++ == '\n')
+        {
+            if (!crossline)
+                Error ("Line %i is incomplete\nin file %s\n",
+                       scriptline,scriptfilename);
+            scriptline++;
+        }
+    }
+
+    if (script_p >= scriptend_p)
+    {
+        if (!crossline)
+            Error ("Line %i is incomplete\nin file %s\n",
+                   scriptline,scriptfilename);
+        endofscript = true;
+        return;
+    }
+
+    if (*script_p == ';')   // semicolon is comment field
+    {
+        if (!crossline)
+            Error ("Line %i is incomplete\nin file %s\n",
+                   scriptline,scriptfilename);
+        while (*script_p++ != '\n')
+            if (script_p >= scriptend_p)
+            {
+                endofscript = true;
+                return;
+            }
+        goto skipspace;
+    }
+
+//
+// copy token
+//
+    token_p = token;
+
+    while ( *script_p > 32 && *script_p != ';')
+    {
+        *token_p++ = *script_p++;
+        if (script_p == scriptend_p)
+            break;
+        if (token_p == &token[MAXTOKEN])
+            Error ("Token too large on line %i\nin file %s\n",
+                   scriptline,scriptfilename);
+    }
+
+    *token_p = 0;
+}
+
+
+
+/*
+==============
+=
+= GetTokenEOL
+=
+==============
+*/
+
+void GetTokenEOL (boolean crossline)
+{
+    char    *name_p;
+
+    if (tokenready)                         // is a token allready waiting?
+    {
+        tokenready = false;
+        return;
+    }
+
+    if (script_p >= scriptend_p)
+    {
+        if (!crossline)
+            Error ("Line %i is incomplete\nin file %s\n",
+                   scriptline,scriptfilename);
+        endofscript = true;
+        return;
+    }
+
+//
+// skip space
+//
+skipspace:
+    while (*script_p <= 32)
+    {
+        if (script_p >= scriptend_p)
+        {
+            if (!crossline)
+                Error ("Line %i is incomplete\nin file %s\n",
+                       scriptline,scriptfilename);
+            endofscript = true;
+            return;
+        }
+        if (*script_p++ == '\n')
+        {
+            if (!crossline)
+                Error ("Line %i is incomplete\nin file %s\n",
+                       scriptline,scriptfilename);
+            scriptline++;
+        }
+    }
+
+    if (script_p >= scriptend_p)
+    {
+        if (!crossline)
+            Error ("Line %i is incomplete\nin file %s\n",
+                   scriptline,scriptfilename);
+        endofscript = true;
+        return;
+    }
+
+    if (*script_p == ';')   // semicolon is comment field
+    {
+        if (!crossline)
+            Error ("Line %i is incomplete\nin file %s\n",
+                   scriptline,scriptfilename);
+        while (*script_p++ != '\n')
+            if (script_p >= scriptend_p)
+            {
+                endofscript = true;
+                return;
+            }
+        goto skipspace;
+    }
+
+//
+// copy token
+//
+    name_p  = name;
+
+    while (*script_p >= 32)
+    {
+        *name_p++ = *script_p++;
+        if (script_p == scriptend_p)
+            break;
+        if (name_p == &name[MAXTOKEN*2])
+            Error ("Name too large on line %i\nin file %s\n",
+                   scriptline,scriptfilename);
+    }
+
+    *name_p = 0;
+}
+
+
+
+/*
+==============
+=
+= TokenAvailable
+=
+= Returns true if there is another token on the line
+=
+==============
+*/
+
+boolean TokenAvailable (void)
+{
+    char    *search_p;
+
+    search_p = script_p;
+
+    if (search_p >= scriptend_p)
+        return false;
+
+    while ( *search_p <= 32)
+    {
+        if (*search_p == '\n')
+            return false;
+        search_p++;
+        if (search_p == scriptend_p)
+            return false;
+
+    }
+
+    if (*search_p == ';')
+        return false;
+
+    return true;
+}
+
+
--- /dev/null
+++ b/rott/scriplib.h
@@ -1,0 +1,41 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+// scriplib.h
+
+#ifndef _scriplib_public
+#define _scriplib_public
+
+#define	MAXTOKEN	128
+
+extern	char	token[MAXTOKEN];
+extern	char	name[MAXTOKEN*2];
+extern	char	*scriptbuffer,*script_p,*scriptend_p;
+extern	int		scriptline;
+extern	boolean	endofscript;
+extern   boolean tokenready;      // only true if UnGetToken was just called
+
+
+void LoadScriptFile (char *filename);
+void GetToken (boolean crossline);
+void GetTokenEOL (boolean crossline);
+void UnGetToken (void);
+boolean TokenAvailable (void);
+
+#endif
--- /dev/null
+++ b/rott/snd_reg.h
@@ -1,0 +1,1435 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+typedef enum {
+
+//	MENU SOUNDS
+
+    D_MENUFLIP,
+    D_ESCPRESSEDSND,
+    D_MOVECURSORSND,
+    D_SELECTSND,
+    D_WARNINGBOXSND,
+    D_INFOBOXSND,
+    D_QUESTIONBOXSND,
+    D_NOPESND,
+    D_QUIT1SND,
+    D_QUIT2SND,
+    D_QUIT3SND,
+    D_QUIT4SND,
+    D_QUIT5SND,
+    D_QUIT6SND,
+    D_QUIT7SND,
+
+
+//	GAME SOUNDS
+
+    D_LEVELSTARTSND,
+    D_LEVELDONESND,
+    D_GAMEOVERSND,
+
+//	LEVEL END SCREEN
+
+    D_ENDBONUS1SND,
+    D_NOBONUSSND,
+    D_PERCENT100SND,
+
+//	PLAYER SOUNDS
+
+    D_HITWALLSND,
+    D_SELECTWPNSND,
+    D_NOWAYSND,
+    D_DONOTHINGSND,
+//         D_NOITEMSND,
+    D_PLAYERDYINGSND,
+
+    D_PLAYERTBDEATHSND,
+    D_PLAYERTCDEATHSND,
+    D_PLAYERLNDEATHSND,
+    D_PLAYERDWDEATHSND,
+    D_PLAYERIPFDEATHSND,
+    D_PLAYERTBHURTSND,
+    D_PLAYERTCHURTSND,
+    D_PLAYERLNHURTSND,
+    D_PLAYERDWHURTSND,
+    D_PLAYERIPFHURTSND,
+    D_PLAYERTBSND,
+    D_PLAYERTCSND,
+    D_PLAYERLNSND,
+    D_PLAYERDWSND,
+    D_PLAYERIPFSND,
+//         D_WALK1SND,
+//         D_WALK2SND,
+    D_PLAYERBURNEDSND,
+    D_PLAYERLANDSND,
+    D_PLAYERCOUGHMSND,
+    D_PLAYERCOUGHFSND,
+    D_NETWIGGLESND,
+    D_NETFALLSND,
+
+//	PLAYER WEAPONS
+
+    D_ATKPISTOLSND,
+    D_ATKTWOPISTOLSND,
+    D_ATKMP40SND,
+    D_RICOCHET1SND,
+    D_RICOCHET2SND,
+    D_RICOCHET3SND,
+    D_BAZOOKAFIRESND,
+    D_FIREBOMBFIRESND,
+    D_HEATSEEKFIRESND,
+    D_DRUNKFIRESND,
+    D_FLAMEWALLFIRESND,
+    D_FLAMEWALLSND,
+    D_SPLITFIRESND,
+    D_SPLITSND,
+    D_GRAVBUILDSND,
+    D_GRAVFIRESND,
+    D_GRAVSND,
+    D_GRAVHITSND,
+    D_FIREHITSND,
+    D_MISSILEFLYSND,
+    D_MISSILEHITSND,
+    D_EXCALIBOUNCESND,
+    D_EXCALISWINGSND,
+    D_EXCALIHITSND,
+    D_EXCALIBUILDSND,
+    D_EXCALIBLASTSND,
+    D_GODMODEFIRESND,
+    D_GODMODE1SND,
+    D_GODMODE2SND,
+    D_GODMODE3SND,
+    D_LOSEMODESND,
+    D_DOGMODEPANTSND,
+    D_DOGMODEBITE1SND,
+    D_DOGMODEBITE2SND,
+    D_DOGMODELICKSND,
+    D_DOGMODEBLASTSND,
+    D_DOGMODEPREPBLASTSND,
+    D_DOGMANSND,
+    D_DOGWOMANSND,
+    D_GODMANSND,
+    D_GODWOMANSND,
+    D_FLYINGSND,
+
+//	PLAYER-CAUSED SOUNDS
+
+    D_GLASSBREAKSND,
+    D_ITEMBLOWSND,
+    D_BONUSBARRELSND,
+    D_TOUCHPLATESND,
+    D_BADTOUCHSND,
+    D_EXPLODEFLOORSND,
+    D_EXPLODESND,
+//         D_GASSTARTSND,
+    D_GASHISSSND,
+    D_GASENDSND,
+    D_GASMASKSND,
+
+//	GET ITEM SOUNDS
+
+    D_GETKEYSND,
+    D_GETBONUSSND,
+    D_GETHEALTH1SND,
+    D_GETHEALTH2SND,
+    D_COOKHEALTHSND,
+
+    D_GETWEAPONSND,
+    D_GETKNIFESND,
+    D_GETGODSND,
+    D_GETDOGSND,
+    D_GETFLEETSND,
+    D_GETELASTSND,
+    D_GETSHROOMSSND,
+    D_GETBVESTSND,
+    D_GETAVESTSND,
+    D_GETMASKSND,
+    D_GETBATSND,
+    D_GETHEADSND,
+
+    D_GET1UPSND,
+    D_GET3UPSND,
+    D_RESPAWNSND,
+    D_PLAYERSPAWNSND,
+
+//	ACTOR SOUNDS
+
+    D_LOWGUARD1SEESND,
+    D_LOWGUARD1ASEESND,
+    D_LOWGUARD1SEE2SND,
+//         D_LOWGUARD2SEESND,
+//         D_LOWGUARD2ASEESND,
+//         D_LOWGUARD2SEE2SND,
+    D_LOWGUARDOUCHSND,
+    D_LOWGUARD1DIESND,
+//         D_LOWGUARD2DIESND,
+    D_SNEAKYSPRINGMSND,
+//         D_SNEAKYSPRINGFSND,
+
+    D_HIGHGUARD1SEESND,
+    D_HIGHGUARD2SEESND,
+    D_HIGHGUARDOUCHSND,
+    D_HIGHGUARDDIESND,
+
+    D_OVERP1SEESND,
+//         D_OVERP2SEESND,
+    D_OVERPNETSND,
+    D_OVERPOUCHSND,
+    D_OVERPDIESND,
+
+    D_STRIKE1SEESND,
+//         D_STRIKE2SEESND,
+    D_STRIKEROLLSND,
+    D_STRIKEOUCHSND,
+    D_STRIKEDIESND,
+
+    D_BLITZ1SEESND,
+    D_BLITZ2SEESND,
+    D_BLITZSTEALSND,
+    D_BLITZOUCHSND,
+    D_BLITZDIESND,
+    D_BLITZPLEADSND,
+    D_BLITZPLEAD1SND,
+    D_BLITZPLEAD2SND,
+
+    D_ENFORCERSEESND,
+    D_ENFORCERFIRESND,
+    D_ENFORCERTHROWSND,
+    D_ENFORCEROUCHSND,
+    D_ENFORCERDIESND,
+
+    D_MONKSEESND,
+    D_MONKGRABSND,
+    D_MONKOUCHSND,
+    D_MONKDIESND,
+
+    D_FIREMONKSEESND,
+    D_FIREMONKFIRESND,
+    D_FIREMONKOUCHSND,
+    D_FIREMONKDIESND,
+
+    D_ROBOTSEESND,
+    D_ROBOTFIRESND,
+    D_ROBOTDIESND,
+
+    D_DARIANSEESND,
+    D_DARIANGONNAUSESND,
+    D_DARIANHIDESND,
+    D_DARIANDIESND,
+    D_DARIANSAY1,
+    D_DARIANSAY2,
+    D_DARIANSAY3,
+
+    D_KRISTSEESND,
+    D_KRISTMOTORSND,
+    D_KRISTTURNSND,
+    D_KRISTDROPSND,
+    D_KRISTMINEBEEPSND,
+    D_KRISTMINEHITSND,
+    D_KRISTDIESND,
+    D_KRISTSAY1,
+    D_KRISTSAY2,
+    D_KRISTSAY3,
+
+    D_NMESEESND,
+    D_NMEREADYSND,
+    D_NMEAPARTSND,
+    D_NMEUFOSND,
+
+    D_DARKMONKSEESND,
+    D_DARKMONKFIRE1SND,
+    D_DARKMONKFIRE2SND,
+    D_DARKMONKFIRE3SND,
+    D_DARKMONKFIRE4SND,
+    D_DARKMONKRECHARGESND,
+    D_DARKMONKFLOATSND,
+    D_DARKMONKDIESND,
+    D_DARKMONKSAY1,
+    D_DARKMONKSAY2,
+    D_DARKMONKSAY3,
+
+    D_SNAKESEESND,
+    D_SNAKEREADYSND,
+    D_SNAKECHARGESND,
+    D_SNAKEOUCHSND,
+    D_SNAKEDIESND,
+    D_SNAKESPITSND,
+    D_SNAKESAY1,
+    D_SNAKESAY2,
+    D_SNAKESAY3,
+
+    D_EMPLACEMENTSEESND,
+    D_EMPLACEMENTFIRESND,
+    D_BIGEMPLACEFIRESND,
+
+
+//	ENVIRONMENT SOUNDS
+
+    D_OPENDOORSND,
+    D_CLOSEDOORSND,
+    D_DOORHITSND,
+    D_FIRECHUTESND,
+    D_FIREBALLSND,
+    D_FIREBALLHITSND,
+    D_BLADESPINSND,
+    D_PUSHWALLSND,
+    D_PUSHWALLHITSND,
+    D_GOWALLSND,
+    D_TURBOWALLSND,
+    D_BOULDERHITSND,
+    D_BOULDERROLLSND,
+    D_PITTRAPSND,
+    D_FIREJETSND,
+    D_ACTORSQUISHSND,
+    D_ACTORBURNEDSND,
+    D_ACTORSKELETONSND,
+
+    D_SPEARSTABSND,
+    D_CYLINDERMOVESND,
+    D_ELEVATORONSND,
+    D_ELEVATORENDSND,
+
+    D_SPRINGBOARDSND,
+    D_LIGHTNINGSND,
+    D_WINDSND,
+//         D_WATERSND,
+
+//	SECRET SOUNDS
+
+    D_DOPEFISHSND,
+    D_YOUSUCKSND,
+
+    D_SILLYMOVESND,
+    D_SOUNDSELECTSND,
+    D_SOUNDESCSND,
+    D_BODYLANDSND,
+    D_GIBSPLASHSND,
+    D_ACTORLANDSND,
+
+    D_LASTSOUND=-1
+
+} digisounds;
+
+static sound_t sounds[MAXSOUNDS] = {
+//SD_MENUFLIP,
+//|-------DIGITAL--------|---------MUSE---------|----FLAGS---|
+    {{D_MENUFLIP,            MUSE_MENUFLIPSND,      },  0,SD_PRIOMENU, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_ESCPRESSEDSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_ESCPRESSEDSND,       MUSE_ESCPRESSEDSND,    },  0,SD_PRIOMENU, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_MOVECURSORSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_MOVECURSORSND,       MUSE_MOVECURSORSND,    },  0,SD_PRIOMENU, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_SELECTSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_SELECTSND,           MUSE_SELECTSND,        },  0,SD_PRIOMENU, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_WARNINGBOXSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_WARNINGBOXSND,       MUSE_WARNINGBOXSND,    },  0,SD_PRIOMENU, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_INFOBOXSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_INFOBOXSND,          MUSE_INFOBOXSND,       },  0,SD_PRIOMENU, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_QUESTIONBOXSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_QUESTIONBOXSND,      MUSE_QUESTIONBOXSND,   },  0,SD_PRIOMENU, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_NOPESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_NOPESND,             MUSE_NOPESND,          },  0,SD_PRIOMENU, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_QUIT1SND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_QUIT1SND,            MUSE_SELECTSND,        },  0,SD_PRIOQUIT, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_QUIT2SND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_QUIT2SND,            MUSE_SELECTSND,        },  0,SD_PRIOQUIT, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_QUIT3SND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_QUIT3SND,            MUSE_SELECTSND,        },  0,SD_PRIOQUIT, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_QUIT4SND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_QUIT4SND,            MUSE_SELECTSND,        },  0,SD_PRIOQUIT, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_QUIT5SND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_QUIT5SND,            MUSE_SELECTSND,        },  0,SD_PRIOQUIT, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_QUIT6SND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_QUIT6SND,            MUSE_SELECTSND,        },  0,SD_PRIOQUIT, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_QUIT7SND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_QUIT7SND,            MUSE_SELECTSND,        },  0,SD_PRIOQUIT, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_LEVELSTARTSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LEVELSTARTSND,       MUSE_LEVELSTARTSND,    },  0,SD_PRIOGAME, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_LEVELDONESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LEVELDONESND,        MUSE_LEVELENDSND,      },  0,SD_PRIOGAME, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_GAMEOVERSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_GAMEOVERSND,         MUSE_GAMEOVERSND,      },  0,SD_PRIOGAME, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_ENDBONUS1SND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_ENDBONUS1SND,        MUSE_ENDBONUS1SND,     },  SD_PITCHSHIFTOFF,SD_PRIOGAME, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_NOBONUSSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_NOBONUSSND,          MUSE_NOBONUSSND,       },  0,SD_PRIOGAME, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_PERCENT100SND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_PERCENT100SND,       MUSE_PERCENT100SND,    },  0,SD_PRIOGAME, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_HITWALLSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_HITWALLSND,          MUSE_HITWALLSND,       },  0,SD_PRIOPCAUSD, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_SELECTWPNSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_SELECTWPNSND,        MUSE_SELECTWPNSND,     },  0,SD_PRIOGAME, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_NOWAYSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_NOWAYSND,            MUSE_NOWAYSND,         },  0,SD_PRIOSECRET, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_DONOTHINGSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_DONOTHINGSND,        MUSE_DONOTHINGSND,     },  0,SD_PRIOSECRET, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_NOITEMSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_NOWAYSND,            MUSE_NOITEMSND,        },  0,SD_PRIOSECRET, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_PLAYERDYINGSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_PLAYERDYINGSND,      MUSE_PLAYERDYINGSND,   },  SD_PITCHSHIFTOFF,SD_PRIOPSNDS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_PLAYERTCDEATHSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_PLAYERTCDEATHSND,    MUSE_PLAYERDEATHSND,   },  0,SD_PRIOGAME, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_PLAYERTBDEATHSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_PLAYERTBDEATHSND,    MUSE_PLAYERDEATHSND,   },  0,SD_PRIOGAME, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_PLAYERDWDEATHSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_PLAYERDWDEATHSND,    MUSE_PLAYERDEATHSND,   },  0,SD_PRIOGAME, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_PLAYERLNDEATHSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_PLAYERLNDEATHSND,    MUSE_PLAYERDEATHSND,   },  0,SD_PRIOGAME, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_PLAYERIPFDEATHSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_PLAYERIPFDEATHSND,   MUSE_PLAYERDEATHSND,   },  0,SD_PRIOGAME, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_PLAYERTCHURTSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_PLAYERTCHURTSND,     MUSE_PLAYERHURTSND,    },  SD_PLAYONCE, SD_PRIOPHURT, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_PLAYERTBHURTSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_PLAYERTBHURTSND,     MUSE_PLAYERHURTSND,    },  SD_PLAYONCE, SD_PRIOPHURT, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_PLAYERDWHURTSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_PLAYERDWHURTSND,     MUSE_PLAYERHURTSND,    },  SD_PLAYONCE, SD_PRIOPHURT, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_PLAYERLNHURTSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_PLAYERLNHURTSND,     MUSE_PLAYERHURTSND,    },  SD_PLAYONCE, SD_PRIOPHURT, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_PLAYERIPFHURTSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_PLAYERIPFHURTSND,    MUSE_PLAYERHURTSND,    },  SD_PLAYONCE, SD_PRIOPHURT, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_PLAYERTCSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_PLAYERTCSND,         MUSE_PLAYERYESSND,     },  0,SD_PRIOPSNDS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_PLAYERTBSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_PLAYERTBSND,         MUSE_PLAYERYESSND,     },  0,SD_PRIOPSNDS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_PLAYERDWSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_PLAYERDWSND,         MUSE_PLAYERYESSND,     },  0,SD_PRIOPSNDS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_PLAYERLNSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_PLAYERLNSND,         MUSE_PLAYERYESSND,     },  0,SD_PRIOPSNDS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_PLAYERIPFSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_PLAYERIPFSND,        MUSE_PLAYERYESSND,     },  0,SD_PRIOPSNDS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_WALK1SND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+// {{D_WALK1SND,            MUSE_WALK1SND,       },  0,SD_PRIOPSNDS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_WALK2SND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+// {{D_WALK2SND,            MUSE_WALK2SND,       },  0,SD_PRIOPSNDS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_PLAYERBURNEDSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_PLAYERBURNEDSND,     MUSE_PLAYERHURTSND,    },  SD_PLAYONCE,SD_PRIOPHURT, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_PLAYERLANDSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_PLAYERLANDSND,       MUSE_PLAYERLANDSND,    },  0,SD_PRIOPSNDS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_PLAYERCOUGHMSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_PLAYERCOUGHMSND,     MUSE_LASTSOUND,        },  0,SD_PRIOPSNDS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_PLAYERCOUGHFSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_PLAYERCOUGHFSND,     MUSE_LASTSOUND,        },  0,SD_PRIOPSNDS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_NETWIGGLESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_NETWIGGLESND,        MUSE_LASTSOUND,        },  0,SD_PRIOPSNDS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_NETFALLSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_NETFALLSND,          MUSE_NETFALLSND,       },  0,SD_PRIOPSNDS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_ATKPISTOLSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_ATKPISTOLSND,        MUSE_ATKPISTOLSND,     },  SD_WRITE,SD_PRIOPGUNS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_ATKTWOPISTOLSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_ATKTWOPISTOLSND,     MUSE_ATKPISTOLSND,     },  SD_WRITE,SD_PRIOPGUNS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_ATKMP40SND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_ATKMP40SND,          MUSE_ATKMP40SND,       },  SD_WRITE,SD_PRIOPMP40, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_RICOCHET1SND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_RICOCHET1SND,        MUSE_RICOCHETSND,      },  SD_WRITE,SD_PRIOPCAUSD, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_RICOCHET2SND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_RICOCHET2SND,        MUSE_RICOCHETSND,      },  SD_WRITE,SD_PRIOPCAUSD, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_RICOCHET3SND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_RICOCHET3SND,        MUSE_RICOCHETSND,      },  SD_WRITE,SD_PRIOPCAUSD, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_BAZOOKAFIRESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_BAZOOKAFIRESND,      MUSE_MISSILEFIRESND,   },  SD_WRITE,SD_PRIOPMISS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_FIREBOMBFIRESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_FIREBOMBFIRESND,     MUSE_MISSILEFIRESND,   },  SD_WRITE,SD_PRIOPMISS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_HEATSEEKFIRESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_HEATSEEKFIRESND,     MUSE_MISSILEFIRESND,   },  SD_WRITE,SD_PRIOPMISS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_DRUNKFIRESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_DRUNKFIRESND,        MUSE_MISSILEFIRESND,   },  SD_WRITE,SD_PRIOPMISS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_FLAMEWALLFIRESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_FLAMEWALLFIRESND,    MUSE_MISSILEFIRESND,   },  SD_WRITE,SD_PRIOPMISS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_FLAMEWALLSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_FLAMEWALLSND,        MUSE_FLAMEWALLSND,     },  0,SD_PRIOPMISS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_SPLITFIRESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_SPLITFIRESND,        MUSE_MISSILEFIRESND,   },  0,SD_PRIOPMISS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_SPLITSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_SPLITSND,            MUSE_MISSILEFIRESND,   },  0,SD_PRIOPMISS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_GRAVBUILDSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_GRAVBUILDSND,        MUSE_WEAPONBUILDSND,   },  0,SD_PRIOPSNDS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_GRAVFIRESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_GRAVFIRESND,         MUSE_ENERGYFIRESND,    },  0,SD_PRIOPMISS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_GRAVSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_GRAVSND,             MUSE_LASTSOUND,        },  0,SD_PRIOPMISS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_GRAVHITSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_GRAVHITSND,          MUSE_MISSILEHITSND,    },  0,SD_PRIOEXPL, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_FIREHITSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_FIREHITSND,          MUSE_MISSILEHITSND,    },  0,SD_PRIOEXPL, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_MISSILEFLYSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_MISSILEFLYSND,       MUSE_LASTSOUND,        },  0,SD_PRIOPCAUSD, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_MISSILEHITSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_MISSILEHITSND,       MUSE_MISSILEHITSND,    },  0,SD_PRIOEXPL, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_EXCALIBOUNCESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_EXCALIBOUNCESND,     MUSE_LASTSOUND,        },  0,SD_PRIOPMISS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_EXCALISWINGSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_EXCALISWINGSND,      MUSE_MISSILEFIRESND,   },  0,SD_PRIOPMISS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_EXCALIHITSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_EXCALIHITSND,        MUSE_MISSILEHITSND,    },  0,SD_PRIOEXPL, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_EXCALIBUILDSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_EXCALIBUILDSND,      MUSE_WEAPONBUILDSND,   },  0,SD_PRIOPSNDS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_EXCALIBLASTSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_EXCALIBLASTSND,      MUSE_ENERGYFIRESND,    },  0,SD_PRIOPMISS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_GODMODEFIRESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_GODMODEFIRESND,      MUSE_ENERGYFIRESND,    },  0,SD_PRIOGODDOG, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_GODMODE1SND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_GODMODE1SND,         MUSE_LASTSOUND,        },  0,SD_PRIOGODDOG, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_GODMODE2SND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_GODMODE2SND,         MUSE_LASTSOUND,        },  0,SD_PRIOGODDOG, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_GODMODE3SND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_GODMODE3SND,         MUSE_LASTSOUND,        },  0,SD_PRIOGODDOG, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_LOSEMODESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LOSEMODESND,         MUSE_LOSEMODESND,      },  0,SD_PRIOGAME, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_DOGMODEPANTSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_DOGMODEPANTSND,      MUSE_LASTSOUND,        },  0,SD_PRIOGODDOG, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_DOGMODEBITE1SND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_DOGMODEBITE1SND,      MUSE_DOGBITESND,      },  0,SD_PRIOGODDOG, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_DOGMODEBITE2SND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_DOGMODEBITE2SND,      MUSE_DOGBITESND,      },  0,SD_PRIOGODDOG, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_DOGMODELICKSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_DOGMODELICKSND,      MUSE_DOGLICKSND,       },  0,SD_PRIOGODDOG, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_DOGMODEBLASTSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_DOGMODEBLASTSND,      MUSE_DOGBITESND,      },  0,SD_PRIOGODDOG, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_DOGMODEPREPBLASTSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_DOGMODEPREPBLASTSND, MUSE_LASTSOUND,        },  0,SD_PRIOGODDOG, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_DOGMANSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_DOGMANSND,           MUSE_LASTSOUND,        },  0,SD_PRIOGODDOG, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_DOGWOMANSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_DOGWOMANSND,         MUSE_LASTSOUND,        },  0,SD_PRIOGODDOG, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_GODMANSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_GODMANSND,           MUSE_LASTSOUND,        },  0,SD_PRIOGODDOG, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_GODWOMANSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_GODWOMANSND,         MUSE_LASTSOUND,        },  0,SD_PRIOGODDOG, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_FLYINGSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_FLYINGSND,           MUSE_LASTSOUND,        },  0,SD_PRIOGODDOG, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_GLASSBREAKSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_GLASSBREAKSND,       MUSE_GLASSBREAKSND,    },  0,SD_PRIOGLASS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_ITEMBLOWSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_ITEMBLOWSND,         MUSE_EXPLOSIONSND,     },  0,SD_PRIOEXPL, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_BONUSBARRELSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_BONUSBARRELSND,      MUSE_EXPLOSIONSND,     },  0,SD_PRIOEXPL, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_TOUCHPLATESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_TOUCHPLATESND,       MUSE_TOUCHPLATESND,    },  0,SD_PRIOSECRET, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_BADTOUCHSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_BADTOUCHSND,         MUSE_BADTOUCHSND,      },  0,SD_PRIOSECRET, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_EXPLODEFLOORSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_EXPLODEFLOORSND,     MUSE_EXPLOSIONSND,     },  0,SD_PRIOEXPL, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_EXPLODESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_EXPLODESND,          MUSE_EXPLOSIONSND,     },  0,SD_PRIOEXPL, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_GASSTARTSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_TOUCHPLATESND,         MUSE_SWITCHSND,      },  0,SD_PRIOSECRET, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_GASHISSSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_GASHISSSND,          MUSE_LASTSOUND,        },  0,SD_PRIOENVRON, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_GASENDSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_GASENDSND,           MUSE_SWITCHSND,        },  0,SD_PRIOSECRET, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_GASMASKSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_GASMASKSND,          MUSE_LASTSOUND,        },  0,SD_PRIOGAME, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_GETKEYSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_GETKEYSND,           MUSE_GETKEYSND,        },  0,SD_PRIOGAME, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_GETBONUSSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_GETBONUSSND,         MUSE_GETBONUSSND,      },  0,SD_PRIOGAME, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_GETHEALTH1SND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_GETHEALTH1SND,       MUSE_GETHEALTHSND,     },  0,SD_PRIOGAME, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_GETHEALTH2SND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_GETHEALTH2SND,       MUSE_GETHEALTHSND,     },  0,SD_PRIOGAME, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_COOKHEALTHSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_COOKHEALTHSND,       MUSE_GETBONUSSND,      },  0,SD_PRIOSECRET, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_GETWEAPONSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_GETWEAPONSND,        MUSE_GETWEAPONSND,     },  0,SD_PRIOGAME, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_GETKNIFESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_GETKNIFESND,         MUSE_GETWEAPONSND,     },  0,SD_PRIOGAME, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_GETGODSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_GETGODSND,           MUSE_GETPOWERUPSND,    },  0,SD_PRIOGODDOG, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_GETDOGSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_GETDOGSND,           MUSE_GETPOWERUPSND,    },  0,SD_PRIOGODDOG, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_GETFLEETSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_GETFLEETSND,         MUSE_GETPOWERUPSND,    },  0,SD_PRIOGAME, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_GETELASTSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_GETELASTSND,         MUSE_GETPOWERDOWNSND,  },  0,SD_PRIOGAME, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_GETSHROOMSSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_GETSHROOMSSND,       MUSE_GETPOWERDOWNSND,  },  0,SD_PRIOGAME, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_GETBVESTSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_GETBVESTSND,         MUSE_GETARMORSND,      },  0,SD_PRIOGAME, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_GETAVESTSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_GETAVESTSND,         MUSE_GETARMORSND,      },  0,SD_PRIOGAME, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_GETMASKSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_GETMASKSND,          MUSE_GETARMORSND,      },  0,SD_PRIOGAME, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_GETBATSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_GETBATSND,           MUSE_GETWEIRDSND,      },  0,SD_PRIOGAME, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_GETHEADSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_GETHEADSND,          MUSE_GETWEIRDSND,      },  0,SD_PRIOSECRET, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_GET1UPSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_GET1UPSND,           MUSE_GETLIFESND,       },   SD_PITCHSHIFTOFF,SD_PRIOGAME, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_GET3UPSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_GET3UPSND,           MUSE_GETLIFESND,       },   SD_PITCHSHIFTOFF,SD_PRIOGAME, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_RESPAWNSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_RESPAWNSND,          MUSE_GETBONUSSND,      },   SD_PITCHSHIFTOFF,SD_PRIOGAME, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_PLAYERSPAWNSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_PLAYERSPAWNSND,      MUSE_GETLIFESND,       },   SD_PITCHSHIFTOFF,SD_PRIOGAME, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_LOWGUARD1SEESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LOWGUARD1SEESND,     MUSE_ACTORSEESND,      },  0,SD_PRIOAGREET, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_LOWGUARD1ASEESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LOWGUARD1ASEESND,    MUSE_ACTORSEESND,      },  0,SD_PRIOAGREET, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_LOWGUARD1SEE3SND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LOWGUARD1SEE2SND,    MUSE_ACTORSEESND,      },  0,SD_PRIOAGREET, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_LOWGUARD2SEESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LOWGUARD1SEESND,     MUSE_ACTORSEESND,      },  0,SD_PRIOAGREET, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_LOWGUARD2ASEESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LOWGUARD1ASEESND,    MUSE_ACTORSEESND,      },  0,SD_PRIOAGREET, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_LOWGUARD2SEE3SND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LOWGUARD1SEE2SND,    MUSE_ACTORSEESND,      },  0,SD_PRIOAGREET, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_LOWGUARDFIRESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_ATKPISTOLSND,     MUSE_ACTORFIRESND,        },  0,SD_PRIOAFIRE, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_LOWGUARDOUCHSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LOWGUARDOUCHSND,     MUSE_ACTOROUCHSND,     },  0,SD_PRIOAHURT, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_LOWGUARD1DIESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LOWGUARD1DIESND,    MUSE_ACTORDIESND,       },  0,SD_PRIOADEATH, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_LOWGUARD2DIESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LOWGUARD1DIESND,    MUSE_ACTORDIESND,       },  0,SD_PRIOADEATH, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_SNEAKYSPRINGMSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_SNEAKYSPRINGMSND,    MUSE_ACTORDOITSND,     },  0,SD_PRIOASNEAK, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_SNEAKYSPRINGFSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_SNEAKYSPRINGMSND,    MUSE_ACTORDOITSND,     },  0,SD_PRIOASNEAK, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_HIGHGUARD1SEESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_HIGHGUARD1SEESND,    MUSE_ACTORSEESND,      },  0,SD_PRIOAGREET, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_HIGHGUARD2SEESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_HIGHGUARD2SEESND,    MUSE_ACTORSEESND,      },  0,SD_PRIOAGREET, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_HIGHGUARDFIRESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_ATKMP40SND,          MUSE_ACTORFIRESND,     },  0,SD_PRIOAFIRE, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_HIGHGUARDOUCHSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_HIGHGUARDOUCHSND,    MUSE_ACTOROUCHSND,     },  0,SD_PRIOAHURT, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_HIGHGUARDDIESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_HIGHGUARDDIESND,     MUSE_ACTORDIESND,      },  0,SD_PRIOADEATH, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_OVERP1SEESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_OVERP1SEESND,        MUSE_ACTORSEESND,      },  0,SD_PRIOAGREET, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_OVERP2SEESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_OVERP1SEESND,        MUSE_ACTORSEESND,      },  0,SD_PRIOAGREET, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_OVERPFIRESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_ATKPISTOLSND,     MUSE_ACTORFIRESND,        },  0,SD_PRIOAFIRE, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_OVERPNETSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_OVERPNETSND,         MUSE_ACTORTHROWSND,    },  0,SD_PRIOASNEAK, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_OVERPOUCHSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_OVERPOUCHSND,        MUSE_ACTOROUCHSND,     },  0,SD_PRIOAHURT, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_OVERPDIESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_OVERPDIESND,         MUSE_ACTORDIESND,      },  0,SD_PRIOADEATH, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_STRIKE1SEESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_STRIKE1SEESND,       MUSE_ACTORSEESND,      },  0,SD_PRIOAGREET, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_STRIKE2SEESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_STRIKE1SEESND,       MUSE_ACTORSEESND,      },  0,SD_PRIOAGREET, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_STRIKEFIRESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_ATKPISTOLSND,     MUSE_ACTORFIRESND,        },  0,SD_PRIOAFIRE, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_STRIKEROLLSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_STRIKEROLLSND,       MUSE_ACTORROLLSND,     },  0,SD_PRIOASNEAK, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_STRIKEOUCHSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_STRIKEOUCHSND,       MUSE_ACTOROUCHSND,     },  0,SD_PRIOAHURT, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_STRIKEDIESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_STRIKEDIESND,        MUSE_ACTORDIESND,      },  0,SD_PRIOADEATH, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_BLITZ1SEESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_BLITZ1SEESND,        MUSE_ACTORSEESND,      },  0,SD_PRIOAGREET, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_BLITZ2SEESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_BLITZ2SEESND,        MUSE_ACTORSEESND,      },  0,SD_PRIOAGREET, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_BLITZFIRESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_ATKPISTOLSND,     MUSE_ACTORFIRESND,        },  0,SD_PRIOAFIRE, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_BLITZSTEALSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_BLITZSTEALSND,       MUSE_GETPOWERDOWNSND,  },  0,SD_PRIOASNEAK, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_BLITZOUCHSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_BLITZOUCHSND,        MUSE_ACTOROUCHSND,     },  0,SD_PRIOAHURT, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_BLITZDIESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_BLITZDIESND,         MUSE_ACTORDIESND,      },  0,SD_PRIOADEATH, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_BLITZPLEADSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_BLITZPLEADSND,       MUSE_LASTSOUND,        },  SD_PLAYONCE,SD_PRIOAGREET, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_BLITZPLEAD1SND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_BLITZPLEAD1SND,       MUSE_LASTSOUND,       },  SD_PLAYONCE,SD_PRIOAGREET, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_BLITZPLEAD2SND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_BLITZPLEAD2SND,       MUSE_LASTSOUND,       },  SD_PLAYONCE,SD_PRIOAGREET, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_ENFORCERSEESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_ENFORCERSEESND,      MUSE_ACTORSEESND,      },  0,SD_PRIOAGREET, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_ENFORCERFIRESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_ENFORCERFIRESND,     MUSE_ACTORFIRESND,     },  0,SD_PRIOAFIRE, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_ENFORCERTHROWSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_ENFORCERTHROWSND,    MUSE_ACTORTHROWSND,    },  0,SD_PRIOASNEAK, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_ENFORCEROUCHSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_ENFORCEROUCHSND,     MUSE_ACTOROUCHSND,     },  0,SD_PRIOAHURT, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_ENFORCERDIESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_ENFORCERDIESND,      MUSE_ACTORDIESND,      },  0,SD_PRIOADEATH, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_MONKSEESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_MONKSEESND,          MUSE_ACTORSEESND,      },  0,SD_PRIOAGREET, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_MONKGRABSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_MONKGRABSND,         MUSE_ACTORDOITSND,     },  0,SD_PRIOAFIRE, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_MONKOUCHSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_MONKOUCHSND,         MUSE_ACTOROUCHSND,     },  0,SD_PRIOAHURT, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_MONKDIESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_MONKDIESND,          MUSE_ACTORDIESND,      },  0,SD_PRIOADEATH, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_FIREMONKSEESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_FIREMONKSEESND,      MUSE_ACTORSEESND,      },  0,SD_PRIOAGREET, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_FIREMONKFIRESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_FIREMONKFIRESND,     MUSE_ACTORFIRESND,     },  0,SD_PRIOAFIRE, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_FIREMONKOUCHSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_FIREMONKOUCHSND,     MUSE_ACTOROUCHSND,     },  0,SD_PRIOAHURT, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_FIREMONKDIESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_FIREMONKDIESND,      MUSE_ACTORDIESND,      },  0,SD_PRIOADEATH, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_ROBOTSEESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_ROBOTSEESND,         MUSE_ACTORSEESND,      },  0,SD_PRIOAGREET, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_ROBOTFIRESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_ROBOTFIRESND,        MUSE_ACTORFIRESND,     },  0,SD_PRIOAFIRE, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_ROBOTDIESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_ROBOTDIESND,         MUSE_ACTORDIESND,      },  0,SD_PRIOADEATH, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_ROBOTMOVESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_KRISTMOTORSND,       MUSE_LASTSOUND,        },  SD_PLAYONCE,SD_PRIOENVRON, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_BALLISTIKRAFTSEESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_BAZOOKAFIRESND,         MUSE_ACTORSEESND,   },  0,SD_PRIOAGREET, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_BALLISTIKRAFTFIRESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_ROBOTFIRESND,        MUSE_ACTORFIRESND,     },  0,SD_PRIOAFIRE, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_DARIANSEESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_DARIANSEESND,        MUSE_BOSSSEESND,       },  0,SD_PRIOBOSS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_DARIANFIRESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_BAZOOKAFIRESND,       MUSE_BOSSFIRESND,     },  0,SD_PRIOBOSS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_DARIANGONNAUSESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_DARIANGONNAUSESND,   MUSE_BOSSDOSND,        },  0,SD_PRIOBOSS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_DARIANUSESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_TOUCHPLATESND,       MUSE_BOSSDOSND,        },  0,SD_PRIOBOSS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_DARIANHIDESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_DARIANHIDESND,       MUSE_BOSSDOSND,        },  0,SD_PRIOBOSS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_DARIANDIESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_DARIANDIESND,        MUSE_BOSSDIESND,       },  0,SD_PRIOBOSS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_DARIANSAY1,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_DARIANSAY1,          MUSE_BOSSWARNSND,      },  0,SD_PRIOBOSS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_DARIANSAY2,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_DARIANSAY2,          MUSE_BOSSHEYSND,       },  0,SD_PRIOBOSS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_DARIANSAY3,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_DARIANSAY3,          MUSE_BOSSWARNSND,      },  0,SD_PRIOBOSS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_KRISTSEESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_KRISTSEESND,         MUSE_BOSSSEESND,       },  0,SD_PRIOBOSS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_KRISTFIRESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_BAZOOKAFIRESND,      MUSE_BOSSFIRESND,      },  0,SD_PRIOBOSS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_KRISTMOTORSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_KRISTMOTORSND,       MUSE_LASTSOUND,        },  0,SD_PRIOBOSS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_KRISTTURNSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_KRISTTURNSND,        MUSE_BOSSBEEPSND,      },  0,SD_PRIOBOSS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_KRISTDROPSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_KRISTDROPSND,        MUSE_BOSSDOSND,        },  0,SD_PRIOBOSS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_KRISTMINEBEEPSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_KRISTMINEBEEPSND,    MUSE_BOSSBEEPSND,      },  0,SD_PRIOBOSS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_KRISTMINEHITSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_KRISTMINEHITSND,     MUSE_MISSILEHITSND,    },  0,SD_PRIOBOSS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_KRISTDIESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_KRISTDIESND,         MUSE_BOSSDIESND,       },  0,SD_PRIOBOSS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_KRISTSAY1,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_KRISTSAY1,           MUSE_BOSSWARNSND,      },  0,SD_PRIOBOSS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_KRISTSAY2,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_KRISTSAY2,           MUSE_BOSSHEYSND,       },  0,SD_PRIOBOSS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_KRISTSAY3,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_KRISTSAY3,           MUSE_BOSSWARNSND,      },  0,SD_PRIOBOSS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_NMESEESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_NMESEESND,           MUSE_BOSSSEESND,       },  0,SD_PRIOBOSS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_NMEREADYSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_NMEREADYSND,         MUSE_BOSSWARNSND,      },  0,SD_PRIOBOSS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_NMEFIRE1SND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_BAZOOKAFIRESND,      MUSE_BOSSFIRESND,      },  0,SD_PRIOBOSS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_NMEAPARTSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_NMEAPARTSND,         MUSE_BOSSBEEPSND,      },  0,SD_PRIOBOSS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_NMEUFOSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_NMEUFOSND,           MUSE_MISSILEFIRESND,   },  0,SD_PRIOBOSS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_NMEDIESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_EXPLODESND,           MUSE_BOSSDIESND,      },  0,SD_PRIOBOSS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_DARKMONKSEESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_DARKMONKSEESND,      MUSE_BOSSSEESND,       },  0,SD_PRIOBOSS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_DARKMONKFIRE1SND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_DARKMONKFIRE1SND,    MUSE_BOSSFIRESND,      },  0,SD_PRIOBOSS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_DARKMONKFIRE2SND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_DARKMONKFIRE2SND,    MUSE_BOSSFIRE2SND,     },  0,SD_PRIOBOSS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_DARKMONKFIRE3SND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_DARKMONKFIRE3SND,    MUSE_BOSSFIRESND,      },  0,SD_PRIOBOSS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_DARKMONKFIRE4SND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_DARKMONKFIRE4SND,    MUSE_BOSSFIRE2SND,     },  0,SD_PRIOBOSS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_DARKMONKRECHARGESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_DARKMONKRECHARGESND,   MUSE_WEAPONBUILDSND, },  0,SD_PRIOBOSS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_DARKMONKFLOATSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_DARKMONKFLOATSND,    MUSE_LASTSOUND,        },  0,SD_PRIOBOSS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_DARKMONKDIESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_DARKMONKDIESND,      MUSE_BOSSDIESND,       },  0,SD_PRIOBOSS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_DARKMONKSAY1,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_DARKMONKSAY1,        MUSE_BOSSWARNSND,      },  0,SD_PRIOBOSS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_DARKMONKSAY2,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_DARKMONKSAY2,        MUSE_BOSSHEYSND,       },  0,SD_PRIOBOSS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_DARKMONKSAY3,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_DARKMONKSAY3,        MUSE_BOSSWARNSND,      },  0,SD_PRIOBOSS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_SNAKESEESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_SNAKESEESND,         MUSE_BOSSSEESND,       },  0,SD_PRIOBOSS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_SNAKEREADYSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_SNAKEREADYSND,       MUSE_BOSSBEEPSND,      },  0,SD_PRIOBOSS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_SNAKECHARGESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_SNAKECHARGESND,      MUSE_WEAPONBUILDSND,   },  0,SD_PRIOBOSS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_SNAKEOUCHSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_SNAKEOUCHSND,        MUSE_BOSSOUCHSND,      },  0,SD_PRIOBOSS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_SNAKEDIESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_SNAKEDIESND,         MUSE_BOSSDIESND,       },  0,SD_PRIOBOSS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_SNAKESPITSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_SNAKESPITSND,        MUSE_BOSSFIRESND,      },  0,SD_PRIOBOSS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_SNAKESAY1,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_SNAKESAY1,           MUSE_BOSSWARNSND,      },  0,SD_PRIOBOSS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_SNAKESAY2,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_SNAKESAY2,           MUSE_BOSSHEYSND,       },  0,SD_PRIOBOSS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_SNAKESAY3,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_SNAKESAY3,           MUSE_BOSSWARNSND,      },  0,SD_PRIOBOSS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_EMPLACEMENTSEESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_EMPLACEMENTSEESND,   MUSE_SWITCHSND,        },  0,SD_PRIOAGREET, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_EMPLACEMENTFIRESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_EMPLACEMENTFIRESND,  MUSE_EMPFIRESND,       },  0,SD_PRIOAFIRE, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_BIGEMPLACEFIRESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_BIGEMPLACEFIRESND,   MUSE_EMPFIRESND,       },  0,SD_PRIOAFIRE, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_OPENDOORSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_OPENDOORSND,        MUSE_OPENDOORSND,       },  0,SD_PRIOPCAUSD, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_CLOSEDOORSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_CLOSEDOORSND,       MUSE_CLOSEDOORSND,      },  0,SD_PRIOPCAUSD, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_DOORHITSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_ELEVATORENDSND,       MUSE_LASTSOUND,           },  0,SD_PRIOPCAUSD, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_FIRECHUTESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_FIRECHUTESND,        MUSE_MISSILEFIRESND,   },  0,SD_PRIOENVRON, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_FIREBALLSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_FIREBALLSND,         MUSE_LASTSOUND,        },  0,SD_PRIOENVRON, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_FIREBALLHITSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_FIREBALLHITSND,      MUSE_MISSILEHITSND,    },  0,SD_PRIOENVRON, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_BLADESPINSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_BLADESPINSND,        MUSE_SPINBLADESND,     },  0,SD_PRIOENVRON, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_PUSHWALLSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_PUSHWALLSND,         MUSE_PUSHWALLSND,      },  0,SD_PRIOSECRET, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_PUSHWALLHITSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_PUSHWALLHITSND,      MUSE_MISSILEHITSND,    },  0,SD_PRIOENVRON, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_GOWALLSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_GOWALLSND,           MUSE_PUSHWALLSND,      },  0,SD_PRIOENVRON, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_TURBOWALLSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_TURBOWALLSND,        MUSE_PUSHWALLSND,      },  0,SD_PRIOENVRON, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_BOULDERHITSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_BOULDERHITSND,       MUSE_MISSILEHITSND,    },  0,SD_PRIOENVRON, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_BOULDERROLLSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_BOULDERROLLSND,      MUSE_BOULDERSND,       },  0,SD_PRIOENVRON, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_BOULDERFALLSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_BOULDERHITSND,       MUSE_PITTRAPSND,       },  0,SD_PRIOENVRON, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_PITTRAPSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_PITTRAPSND,          MUSE_PITTRAPSND,       },  0,SD_PRIOSECRET, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_FIREJETSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_FIREJETSND,          MUSE_FIREJETSND,       },  0,SD_PRIOENVRON, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_ACTORSQUISHSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_ACTORSQUISHSND,      MUSE_ACTORSQUISHSND,   },  0,SD_PRIOADEATH, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_ACTORBURNEDSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_ACTORBURNEDSND,      MUSE_ACTOROUCHSND,     },  0,SD_PRIOAHURT, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_ACTORSKELETONSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_ACTORSKELETONSND,    MUSE_LASTSOUND,        },  0,SD_PRIOAHURT, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_SPEARSTABSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_SPEARSTABSND,        MUSE_STABBERSND,       },  0,SD_PRIOENVRON, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_CYLINDERMOVESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_CYLINDERMOVESND,     MUSE_CYLINDERHITSND,   },  0,SD_PRIOENVRON, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_ELEVATORONSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_ELEVATORONSND,       MUSE_ELEVATORSND,      },  0,SD_PRIOPCAUSD, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_ELEVATORENDSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_ELEVATORENDSND,      MUSE_LASTSOUND,        },  0,SD_PRIOPCAUSD, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_SPRINGBOARDSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_SPRINGBOARDSND,      MUSE_SPRINGBOARDSND,   },  0,SD_PRIOPCAUSD, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_LIGHTNINGSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LIGHTNINGSND,        MUSE_LASTSOUND,        },  0,SD_PRIOPCAUSD, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_WINDSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_WINDSND,             MUSE_LASTSOUND,        },  0,SD_PRIOPCAUSD, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_WATERSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LASTSOUND,           MUSE_LASTSOUND,        },  0,SD_PRIOPCAUSD, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_BODYLANDSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_BODYLANDSND,         MUSE_LASTSOUND,        },  0,SD_PRIOENVRON, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_GIBSPLASHSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_GIBSPLASHSND,         MUSE_LASTSOUND,       },  0,SD_PRIOENVRON, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_ACTORLANDSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_ACTORLANDSND,         MUSE_LASTSOUND,       },  0,SD_PRIOENVRON, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_DOPEFISHSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_DOPEFISHSND,         MUSE_LASTSOUND,        },  0,SD_PRIOSECRET, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_YOUSUCKSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_YOUSUCKSND,          MUSE_LASTSOUND,        },  0,SD_PRIOSECRET, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_SILLYMOVESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_SILLYMOVESND,        MUSE_LASTSOUND,        },  0,SD_PRIOSECRET, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_SOUNDSELECTSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_SOUNDSELECTSND,      MUSE_LASTSOUND,        },  0,SD_PRIOSECRET, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_SOUNDESCSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_SOUNDESCSND,         MUSE_LASTSOUND,        },  0,SD_PRIOSECRET, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_REMOTEM1SND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_REMOTEM1SND,         MUSE_LASTSOUND,        },  0,SD_PRIOREMOTE, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_REMOTEM2SND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_REMOTEM2SND,         MUSE_LASTSOUND,        },  0,SD_PRIOREMOTE, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_REMOTEM3SND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_REMOTEM3SND,         MUSE_LASTSOUND,        },  0,SD_PRIOREMOTE, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_REMOTEM4SND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_REMOTEM4SND,         MUSE_LASTSOUND,        },  0,SD_PRIOREMOTE, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_REMOTEM5SND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_REMOTEM5SND,         MUSE_LASTSOUND,        },  0,SD_PRIOREMOTE, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_REMOTEM6SND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_REMOTEM6SND,         MUSE_LASTSOUND,        },  0,SD_PRIOREMOTE, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_REMOTEM7SND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_REMOTEM7SND,         MUSE_LASTSOUND,        },  0,SD_PRIOREMOTE, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_REMOTEM8SND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_REMOTEM8SND,         MUSE_LASTSOUND,        },  0,SD_PRIOREMOTE, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_REMOTEM9SND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_REMOTEM9SND,         MUSE_LASTSOUND,        },  0,SD_PRIOREMOTE, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_REMOTEM10SND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_REMOTEM10SND,        MUSE_LASTSOUND,        },  0,SD_PRIOREMOTE, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_LASTSOUND
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LASTSOUND,           MUSE_LASTSOUND,        },  0,SD_PRIOSECRET, 0, 0, 0}
+//����������������������������������������������������������������������
+};
+
--- /dev/null
+++ b/rott/snd_shar.h
@@ -1,0 +1,1302 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+typedef enum {
+
+    D_LASTSOUND=-1,
+// MENU SOUNDS
+
+    D_MENUFLIP,
+    D_ESCPRESSEDSND,
+    D_MOVECURSORSND,
+    D_SELECTSND,
+    D_WARNINGBOXSND,
+    D_INFOBOXSND,
+    D_QUESTIONBOXSND,
+    D_NOPESND,
+
+// GAME SOUNDS
+
+    D_LEVELSTARTSND,
+    D_LEVELDONESND,
+    D_GAMEOVERSND,
+
+// LEVEL END SCREEN
+
+    D_ENDBONUS1SND,
+
+// PLAYER SOUNDS
+
+    D_HITWALLSND,
+    D_SELECTWPNSND,
+    D_NOWAYSND,
+    D_DONOTHINGSND,
+//D_NOITEMSND,
+    D_PLAYERDYINGSND,
+
+    D_PLAYERTCDEATHSND,
+    D_PLAYERTCHURTSND,
+    D_PLAYERTCSND,
+//D_WALK1SND,
+//D_WALK2SND,
+    D_PLAYERBURNEDSND,
+    D_PLAYERLANDSND,
+    D_PLAYERCOUGHMSND,
+
+// PLAYER WEAPONS
+
+    D_ATKPISTOLSND,
+    D_ATKTWOPISTOLSND,
+    D_ATKMP40SND,
+    D_RICOCHET1SND,
+    D_RICOCHET2SND,
+    D_RICOCHET3SND,
+    D_BAZOOKAFIRESND,
+    D_HEATSEEKFIRESND,
+    D_FIREBOMBFIRESND,
+    D_DRUNKFIRESND,
+    D_FLAMEWALLFIRESND,
+    D_FLAMEWALLSND,
+    D_GRAVSND,
+    D_FIREHITSND,
+    D_MISSILEFLYSND,
+    D_MISSILEHITSND,
+    D_GODMODEFIRESND,
+    D_GODMODE1SND,
+    D_GODMODE2SND,
+    D_GODMODE3SND,
+    D_LOSEMODESND,
+    D_GODMANSND,
+    D_FLYINGSND,
+
+// PLAYER-CAUSED SOUNDS
+
+    D_GLASSBREAKSND,
+    D_ITEMBLOWSND,
+    D_BONUSBARRELSND,
+    D_TOUCHPLATESND,
+    D_BADTOUCHSND,
+    D_EXPLODEFLOORSND,
+    D_EXPLODESND,
+//D_GASSTARTSND,
+    D_GASHISSSND,
+    D_GASENDSND,
+    D_GASMASKSND,
+
+// GET ITEM SOUNDS
+
+    D_GETKEYSND,
+    D_GETBONUSSND,
+    D_GETHEALTH1SND,
+    D_COOKHEALTHSND,
+
+    D_GETWEAPONSND,
+    D_GETGODSND,
+    D_GETFLEETSND,
+    D_GETELASTSND,
+    D_GETSHROOMSSND,
+    D_GETBVESTSND,
+    D_GETAVESTSND,
+    D_GETMASKSND,
+
+    D_GET1UPSND,
+    D_RESPAWNSND,
+    D_PLAYERSPAWNSND,
+
+// ACTOR SOUNDS
+
+    D_LOWGUARD1SEESND,
+    D_LOWGUARD1SEE2SND,
+    D_LOWGUARDOUCHSND,
+    D_LOWGUARD1DIESND,
+    D_SNEAKYSPRINGMSND,
+
+    D_HIGHGUARD1SEESND,
+    D_HIGHGUARDOUCHSND,
+    D_HIGHGUARDDIESND,
+
+    D_STRIKE1SEESND,
+    D_STRIKEROLLSND,
+    D_STRIKEOUCHSND,
+    D_STRIKEDIESND,
+
+    D_BLITZ1SEESND,
+    D_BLITZSTEALSND,
+    D_BLITZOUCHSND,
+    D_BLITZDIESND,
+    D_BLITZPLEADSND,
+    D_BLITZPLEAD1SND,
+    D_BLITZPLEAD2SND,
+
+    D_ENFORCERSEESND,
+    D_ENFORCERFIRESND,
+    D_ENFORCERTHROWSND,
+    D_ENFORCEROUCHSND,
+    D_ENFORCERDIESND,
+
+    D_ROBOTSEESND,
+    D_ROBOTFIRESND,
+    D_ROBOTDIESND,
+
+    D_KRISTMOTORSND,
+
+// ENVIRONMENT SOUNDS
+
+    D_OPENDOORSND,
+    D_CLOSEDOORSND,
+    D_DOORHITSND,
+
+    D_FIRECHUTESND,
+    D_FIREBALLSND,
+    D_FIREBALLHITSND,
+    D_BLADESPINSND,
+    D_PUSHWALLSND,
+    D_PUSHWALLHITSND,
+    D_GOWALLSND,
+    D_TURBOWALLSND,
+    D_PITTRAPSND,
+    D_FIREJETSND,
+    D_ACTORSQUISHSND,
+    D_ACTORBURNEDSND,
+    D_ACTORSKELETONSND,
+
+    D_SPEARSTABSND,
+    D_CYLINDERMOVESND,
+    D_ELEVATORONSND,
+    D_ELEVATORENDSND,
+    D_SPRINGBOARDSND,
+    D_LIGHTNINGSND,
+//D_WINDSND,
+
+// SECRET SOUNDS
+
+    D_YOUSUCKSND,
+    D_BODYLANDSND,
+    D_GIBSPLASHSND,
+    D_ACTORLANDSND
+
+} digisounds;
+
+
+static sound_t sounds[MAXSOUNDS] = {
+//SD_MENUFLIP,
+//|-------DIGITAL--------|---------MUSE---------|-MIDI----------FLAGS---|
+    {{D_MENUFLIP,            MUSE_MENUFLIPSND,      },  0,SD_PRIOMENU, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_ESCPRESSEDSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_ESCPRESSEDSND,       MUSE_ESCPRESSEDSND,    },  0,SD_PRIOMENU, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_MOVECURSORSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_MOVECURSORSND,       MUSE_MOVECURSORSND,    },  0,SD_PRIOMENU, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_SELECTSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_SELECTSND,           MUSE_SELECTSND,        },  0,SD_PRIOMENU, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_WARNINGBOXSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_WARNINGBOXSND,       MUSE_WARNINGBOXSND,    },  0,SD_PRIOMENU, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_INFOBOXSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_INFOBOXSND,          MUSE_INFOBOXSND,       },  0,SD_PRIOMENU, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_QUESTIONBOXSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_QUESTIONBOXSND,      MUSE_QUESTIONBOXSND,   },  0,SD_PRIOMENU, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_NOPESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_NOPESND,             MUSE_NOPESND,          },  0,SD_PRIOMENU, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_QUIT1SND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LASTSOUND,           MUSE_SELECTSND,        },  0,SD_PRIOQUIT, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_QUIT2SND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LASTSOUND,            MUSE_SELECTSND,       },  0,SD_PRIOQUIT, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_QUIT3SND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LASTSOUND,            MUSE_SELECTSND,       },  0,SD_PRIOQUIT, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_QUIT4SND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LASTSOUND,            MUSE_SELECTSND,       },  0,SD_PRIOQUIT, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_QUIT5SND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LASTSOUND,            MUSE_SELECTSND,       },  0,SD_PRIOQUIT, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_QUIT6SND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LASTSOUND,            MUSE_SELECTSND,       },  0,SD_PRIOQUIT, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_QUIT7SND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LASTSOUND,            MUSE_SELECTSND,       },  0,SD_PRIOQUIT, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_LEVELSTARTSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LEVELSTARTSND,       MUSE_LEVELSTARTSND,    },  0,SD_PRIOGAME, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_LEVELDONESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LEVELDONESND,        MUSE_LEVELENDSND,      },  0,SD_PRIOGAME, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_GAMEOVERSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_GAMEOVERSND,         MUSE_GAMEOVERSND,      },  0,SD_PRIOGAME, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_ENDBONUS1SND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_ENDBONUS1SND,        MUSE_ENDBONUS1SND,     },  SD_PITCHSHIFTOFF,SD_PRIOGAME, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_NOBONUSSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LASTSOUND,          MUSE_NOBONUSSND,        },  0,SD_PRIOGAME, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_PERCENT100SND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LASTSOUND,       MUSE_PERCENT100SND,        },  0,SD_PRIOGAME, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_HITWALLSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_HITWALLSND,          MUSE_HITWALLSND,       },  0,SD_PRIOPCAUSD, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_SELECTWPNSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_SELECTWPNSND,        MUSE_SELECTWPNSND,     },  0,SD_PRIOGAME, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_NOWAYSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_NOWAYSND,            MUSE_NOWAYSND,         },  0,SD_PRIOSECRET, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_DONOTHINGSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_DONOTHINGSND,        MUSE_DONOTHINGSND,     },  0,SD_PRIOSECRET, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_NOITEMSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_NOWAYSND,            MUSE_NOITEMSND,        },  0,SD_PRIOSECRET, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_PLAYERDYINGSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_PLAYERDYINGSND,      MUSE_PLAYERDYINGSND,   },  SD_PITCHSHIFTOFF,SD_PRIOPSNDS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_PLAYERTCDEATHSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_PLAYERTCDEATHSND,    MUSE_PLAYERDEATHSND,   },  0,SD_PRIOGAME, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_PLAYERTBDEATHSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_PLAYERTCDEATHSND,    MUSE_PLAYERDEATHSND,   },  0,SD_PRIOGAME, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_PLAYERDWDEATHSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_PLAYERTCDEATHSND,    MUSE_PLAYERDEATHSND,   },  0,SD_PRIOGAME, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_PLAYERLNDEATHSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_PLAYERTCDEATHSND,    MUSE_PLAYERDEATHSND,   },  0,SD_PRIOGAME, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_PLAYERIPFDEATHSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_PLAYERTCDEATHSND,    MUSE_PLAYERDEATHSND,   },  0,SD_PRIOGAME, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_PLAYERTCHURTSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_PLAYERTCHURTSND,     MUSE_PLAYERHURTSND,    },  SD_PLAYONCE, SD_PRIOPHURT, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_PLAYERTBHURTSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_PLAYERTCHURTSND,     MUSE_PLAYERHURTSND,    },  SD_PLAYONCE, SD_PRIOPHURT, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_PLAYERDWHURTSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_PLAYERTCHURTSND,     MUSE_PLAYERHURTSND,    },  SD_PLAYONCE, SD_PRIOPHURT, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_PLAYERLNHURTSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_PLAYERTCHURTSND,     MUSE_PLAYERHURTSND,    },  SD_PLAYONCE, SD_PRIOPHURT, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_PLAYERIPFHURTSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_PLAYERTCHURTSND,     MUSE_PLAYERHURTSND,    },  SD_PLAYONCE, SD_PRIOPHURT, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_PLAYERTCSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_PLAYERTCSND,         MUSE_PLAYERYESSND,     },  0,SD_PRIOPSNDS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_PLAYERTBSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_PLAYERTCSND,         MUSE_PLAYERYESSND,     },  0,SD_PRIOPSNDS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_PLAYERDWSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_PLAYERTCSND,         MUSE_PLAYERYESSND,     },  0,SD_PRIOPSNDS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_PLAYERLNSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_PLAYERTCSND,         MUSE_PLAYERYESSND,     },  0,SD_PRIOPSNDS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_PLAYERIPFSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_PLAYERTCSND,         MUSE_PLAYERYESSND,     },  0,SD_PRIOPSNDS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_WALK1SND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+// {{D_WALK1SND,            MUSE_WALK1SND,       },  0,SD_PRIOPSNDS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_WALK2SND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+// {{D_WALK2SND,            MUSE_WALK2SND,       },  0,SD_PRIOPSNDS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_PLAYERBURNEDSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_PLAYERBURNEDSND,     MUSE_PLAYERHURTSND,    },  SD_PLAYONCE,SD_PRIOPHURT, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_PLAYERLANDSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_PLAYERLANDSND,       MUSE_PLAYERLANDSND,    },  0,SD_PRIOPSNDS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_PLAYERCOUGHMSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_PLAYERCOUGHMSND,     MUSE_LASTSOUND,        },  0,SD_PRIOPSNDS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_PLAYERCOUGHFSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LASTSOUND,     MUSE_LASTSOUND,              },  0,SD_PRIOPSNDS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_NETWIGGLESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LASTSOUND,        MUSE_LASTSOUND,           },  0,SD_PRIOPSNDS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_NETFALLSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LASTSOUND,          MUSE_NETFALLSND,        },  0,SD_PRIOPSNDS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_ATKPISTOLSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_ATKPISTOLSND,        MUSE_ATKPISTOLSND,     },  SD_WRITE,SD_PRIOPGUNS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_ATKTWOPISTOLSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_ATKTWOPISTOLSND,     MUSE_ATKPISTOLSND,     },  SD_WRITE,SD_PRIOPGUNS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_ATKMP40SND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_ATKMP40SND,          MUSE_ATKMP40SND,       },  SD_WRITE,SD_PRIOPMP40, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_RICOCHET1SND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_RICOCHET1SND,        MUSE_RICOCHETSND,      },  SD_WRITE,SD_PRIOPCAUSD, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_RICOCHET2SND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_RICOCHET2SND,        MUSE_RICOCHETSND,      },  SD_WRITE,SD_PRIOPCAUSD, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_RICOCHET3SND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_RICOCHET3SND,        MUSE_RICOCHETSND,      },  SD_WRITE,SD_PRIOPCAUSD, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_BAZOOKAFIRESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_BAZOOKAFIRESND,      MUSE_MISSILEFIRESND,   },  SD_WRITE,SD_PRIOPMISS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_FIREBOMBFIRESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_FIREBOMBFIRESND,     MUSE_MISSILEFIRESND,   },  SD_WRITE,SD_PRIOPMISS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_HEATSEEKFIRESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_HEATSEEKFIRESND,     MUSE_MISSILEFIRESND,   },  SD_WRITE,SD_PRIOPMISS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_DRUNKFIRESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_DRUNKFIRESND,        MUSE_MISSILEFIRESND,   },  SD_WRITE,SD_PRIOPMISS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_FLAMEWALLFIRESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_FLAMEWALLFIRESND,    MUSE_MISSILEFIRESND,   },  SD_WRITE,SD_PRIOPMISS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_FLAMEWALLSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_FLAMEWALLSND,        MUSE_FLAMEWALLSND,     },  0,SD_PRIOPMISS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_SPLITFIRESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LASTSOUND,        MUSE_MISSILEFIRESND,      },  0,SD_PRIOPMISS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_SPLITSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LASTSOUND,            MUSE_MISSILEFIRESND,  },  0,SD_PRIOPMISS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_GRAVBUILDSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LASTSOUND,        MUSE_WEAPONBUILDSND,      },  0,SD_PRIOPSNDS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_GRAVFIRESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LASTSOUND,         MUSE_ENERGYFIRESND,      },  0,SD_PRIOPMISS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_GRAVSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_GRAVSND,             MUSE_LASTSOUND,        },  0,SD_PRIOPMISS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_GRAVHITSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LASTSOUND,          MUSE_MISSILEHITSND,     },  0,SD_PRIOEXPL, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_FIREHITSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_FIREHITSND,          MUSE_MISSILEHITSND,    },  0,SD_PRIOEXPL, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_MISSILEFLYSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_MISSILEFLYSND,       MUSE_LASTSOUND,        },  0,SD_PRIOPCAUSD, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_MISSILEHITSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_MISSILEHITSND,       MUSE_MISSILEHITSND,    },  0,SD_PRIOEXPL, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_EXCALIBOUNCESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LASTSOUND,     MUSE_LASTSOUND,              },  0,SD_PRIOPMISS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_EXCALISWINGSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LASTSOUND,      MUSE_MISSILEFIRESND,        },  0,SD_PRIOPMISS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_EXCALIHITSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LASTSOUND,        MUSE_MISSILEHITSND,       },  0,SD_PRIOEXPL, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_EXCALIBUILDSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LASTSOUND,      MUSE_WEAPONBUILDSND,        },  0,SD_PRIOPSNDS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_EXCALIBLASTSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LASTSOUND,      MUSE_ENERGYFIRESND,         },  0,SD_PRIOPMISS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_GODMODEFIRESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_GODMODEFIRESND,      MUSE_ENERGYFIRESND,    },  0,SD_PRIOGODDOG, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_GODMODE1SND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_GODMODE1SND,         MUSE_LASTSOUND,        },  0,SD_PRIOGODDOG, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_GODMODE2SND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_GODMODE2SND,         MUSE_LASTSOUND,        },  0,SD_PRIOGODDOG, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_GODMODE3SND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_GODMODE3SND,         MUSE_LASTSOUND,        },  0,SD_PRIOGODDOG, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_LOSEMODESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LOSEMODESND,         MUSE_LOSEMODESND,      },  0,SD_PRIOGAME, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_DOGMODEPANTSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LASTSOUND,      MUSE_LASTSOUND,             },  0,SD_PRIOGODDOG, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_DOGMODEBITE1SND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LASTSOUND,      MUSE_DOGBITESND,            },  0,SD_PRIOGODDOG, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_DOGMODEBITE2SND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LASTSOUND,      MUSE_DOGBITESND,            },  0,SD_PRIOGODDOG, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_DOGMODELICKSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LASTSOUND,      MUSE_DOGLICKSND,            },  0,SD_PRIOGODDOG, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_DOGMODEBLASTSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LASTSOUND,      MUSE_DOGBITESND,            },  0,SD_PRIOGODDOG, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_DOGMODEPREPBLASTSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LASTSOUND, MUSE_LASTSOUND,                  },  0,SD_PRIOGODDOG, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_DOGMANSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LASTSOUND,           MUSE_LASTSOUND,        },  0,SD_PRIOGODDOG, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_DOGWOMANSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LASTSOUND,         MUSE_LASTSOUND,          },  0,SD_PRIOGODDOG, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_GODMANSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_GODMANSND,           MUSE_LASTSOUND,        },  0,SD_PRIOGODDOG, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_GODWOMANSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LASTSOUND,         MUSE_LASTSOUND,          },  0,SD_PRIOGODDOG, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_FLYINGSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_FLYINGSND,           MUSE_LASTSOUND,        },  0,SD_PRIOGODDOG, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_GLASSBREAKSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_GLASSBREAKSND,       MUSE_GLASSBREAKSND,    },  0,SD_PRIOGLASS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_ITEMBLOWSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_ITEMBLOWSND,         MUSE_EXPLOSIONSND,     },  0,SD_PRIOEXPL, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_BONUSBARRELSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_BONUSBARRELSND,      MUSE_EXPLOSIONSND,     },  0,SD_PRIOEXPL, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_TOUCHPLATESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_TOUCHPLATESND,       MUSE_TOUCHPLATESND,    },  0,SD_PRIOSECRET, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_BADTOUCHSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_BADTOUCHSND,         MUSE_BADTOUCHSND,      },  0,SD_PRIOSECRET, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_EXPLODEFLOORSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_EXPLODEFLOORSND,     MUSE_EXPLOSIONSND,     },  0,SD_PRIOEXPL, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_EXPLODESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_EXPLODESND,          MUSE_EXPLOSIONSND,     },  0,SD_PRIOEXPL, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_GASSTARTSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_TOUCHPLATESND,         MUSE_SWITCHSND,      },  0,SD_PRIOSECRET, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_GASHISSSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_GASHISSSND,          MUSE_LASTSOUND,        },  0,SD_PRIOENVRON, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_GASENDSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_GASENDSND,           MUSE_SWITCHSND,        },  0,SD_PRIOSECRET, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_GASMASKSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_GASMASKSND,          MUSE_LASTSOUND,        },  0,SD_PRIOGAME, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_GETKEYSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_GETKEYSND,           MUSE_GETKEYSND,        },  0,SD_PRIOGAME, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_GETBONUSSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_GETBONUSSND,         MUSE_GETBONUSSND,      },  0,SD_PRIOGAME, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_GETHEALTH1SND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_GETHEALTH1SND,       MUSE_GETHEALTHSND,     },  0,SD_PRIOGAME, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_GETHEALTH2SND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_GETHEALTH1SND,       MUSE_GETHEALTHSND,     },  0,SD_PRIOGAME, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_COOKHEALTHSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_COOKHEALTHSND,       MUSE_GETBONUSSND,      },  0,SD_PRIOSECRET, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_GETWEAPONSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_GETWEAPONSND,        MUSE_GETWEAPONSND,     },  0,SD_PRIOGAME, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_GETKNIFESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LASTSOUND,         MUSE_GETWEAPONSND,       },  0,SD_PRIOGAME, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_GETGODSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_GETGODSND,           MUSE_GETPOWERUPSND,    },  0,SD_PRIOGODDOG, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_GETDOGSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LASTSOUND,           MUSE_GETPOWERUPSND,    },  0,SD_PRIOGODDOG, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_GETFLEETSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_GETFLEETSND,         MUSE_GETPOWERUPSND,    },  0,SD_PRIOGAME, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_GETELASTSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_GETELASTSND,         MUSE_GETPOWERDOWNSND,  },  0,SD_PRIOGAME, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_GETSHROOMSSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_GETSHROOMSSND,       MUSE_GETPOWERDOWNSND,  },  0,SD_PRIOGAME, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_GETBVESTSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_GETBVESTSND,         MUSE_GETARMORSND,      },  0,SD_PRIOGAME, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_GETAVESTSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_GETAVESTSND,         MUSE_GETARMORSND,      },  0,SD_PRIOGAME, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_GETMASKSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_GETMASKSND,          MUSE_GETARMORSND,      },  0,SD_PRIOGAME, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_GETBATSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LASTSOUND,           MUSE_GETWEIRDSND,      },  0,SD_PRIOGAME, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_GETHEADSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LASTSOUND,          MUSE_GETWEIRDSND,       },  0,SD_PRIOSECRET, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_GET1UPSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_GET1UPSND,           MUSE_GETLIFESND,       },   SD_PITCHSHIFTOFF,SD_PRIOGAME, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_GET3UPSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LASTSOUND,           MUSE_GETLIFESND,       },   SD_PITCHSHIFTOFF,SD_PRIOGAME, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_RESPAWNSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_RESPAWNSND,          MUSE_GETBONUSSND,      },   SD_PITCHSHIFTOFF,SD_PRIOGAME, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_PLAYERSPAWNSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_PLAYERSPAWNSND,      MUSE_GETLIFESND,       },   SD_PITCHSHIFTOFF,SD_PRIOGAME, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_LOWGUARD1SEESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LOWGUARD1SEESND,     MUSE_ACTORSEESND,      },  0,SD_PRIOAGREET, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_LOWGUARD1ASEESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LOWGUARD1SEESND,    MUSE_ACTORSEESND,       },  0,SD_PRIOAGREET, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_LOWGUARD1SEE3SND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LOWGUARD1SEE2SND,    MUSE_ACTORSEESND,      },  0,SD_PRIOAGREET, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_LOWGUARD2SEESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LOWGUARD1SEESND,     MUSE_ACTORSEESND,      },  0,SD_PRIOAGREET, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_LOWGUARD2ASEESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LOWGUARD1SEESND,    MUSE_ACTORSEESND,       },  0,SD_PRIOAGREET, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_LOWGUARD2SEE3SND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LOWGUARD1SEE2SND,    MUSE_ACTORSEESND,      },  0,SD_PRIOAGREET, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_LOWGUARDFIRESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_ATKPISTOLSND,     MUSE_ACTORFIRESND,        },  0,SD_PRIOAFIRE, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_LOWGUARDOUCHSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LOWGUARDOUCHSND,     MUSE_ACTOROUCHSND,     },  0,SD_PRIOAHURT, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_LOWGUARD1DIESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LOWGUARD1DIESND,    MUSE_ACTORDIESND,       },  0,SD_PRIOADEATH, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_LOWGUARD2DIESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LOWGUARD1DIESND,    MUSE_ACTORDIESND,       },  0,SD_PRIOADEATH, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_SNEAKYSPRINGMSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_SNEAKYSPRINGMSND,    MUSE_ACTORDOITSND,     },  0,SD_PRIOASNEAK, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_SNEAKYSPRINGFSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_SNEAKYSPRINGMSND,    MUSE_ACTORDOITSND,     },  0,SD_PRIOASNEAK, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_HIGHGUARD1SEESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_HIGHGUARD1SEESND,    MUSE_ACTORSEESND,      },  0,SD_PRIOAGREET, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_HIGHGUARD2SEESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_HIGHGUARD1SEESND,    MUSE_ACTORSEESND,      },  0,SD_PRIOAGREET, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_HIGHGUARDFIRESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_ATKMP40SND,          MUSE_ACTORFIRESND,     },  0,SD_PRIOAFIRE, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_HIGHGUARDOUCHSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_HIGHGUARDOUCHSND,    MUSE_ACTOROUCHSND,     },  0,SD_PRIOAHURT, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_HIGHGUARDDIESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_HIGHGUARDDIESND,     MUSE_ACTORDIESND,      },  0,SD_PRIOADEATH, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_OVERP1SEESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LASTSOUND,        MUSE_ACTORSEESND,         },  0,SD_PRIOAGREET, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_OVERP2SEESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LASTSOUND,        MUSE_ACTORSEESND,         },  0,SD_PRIOAGREET, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_OVERPFIRESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_ATKPISTOLSND,     MUSE_ACTORFIRESND,        },  0,SD_PRIOAFIRE, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_OVERPNETSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LASTSOUND,         MUSE_ACTORTHROWSND,      },  0,SD_PRIOASNEAK, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_OVERPOUCHSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LASTSOUND,        MUSE_ACTOROUCHSND,        },  0,SD_PRIOAHURT, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_OVERPDIESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LASTSOUND,         MUSE_ACTORDIESND,        },  0,SD_PRIOADEATH, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_STRIKE1SEESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_STRIKE1SEESND,       MUSE_ACTORSEESND,      },  0,SD_PRIOAGREET, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_STRIKE2SEESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_STRIKE1SEESND,       MUSE_ACTORSEESND,      },  0,SD_PRIOAGREET, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_STRIKEFIRESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_ATKPISTOLSND,     MUSE_ACTORFIRESND,        },  0,SD_PRIOAFIRE, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_STRIKEROLLSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_STRIKEROLLSND,       MUSE_ACTORROLLSND,     },  0,SD_PRIOASNEAK, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_STRIKEOUCHSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_STRIKEOUCHSND,       MUSE_ACTOROUCHSND,     },  0,SD_PRIOAHURT, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_STRIKEDIESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_STRIKEDIESND,        MUSE_ACTORDIESND,      },  0,SD_PRIOADEATH, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_BLITZ1SEESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_BLITZ1SEESND,        MUSE_ACTORSEESND,      },  0,SD_PRIOAGREET, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_BLITZ2SEESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_BLITZ1SEESND,        MUSE_ACTORSEESND,      },  0,SD_PRIOAGREET, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_BLITZFIRESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_ATKPISTOLSND,     MUSE_ACTORFIRESND,        },  0,SD_PRIOAFIRE, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_BLITZSTEALSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_BLITZSTEALSND,       MUSE_GETPOWERDOWNSND,  },  0,SD_PRIOASNEAK, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_BLITZOUCHSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_BLITZOUCHSND,        MUSE_ACTOROUCHSND,     },  0,SD_PRIOAHURT, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_BLITZDIESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_BLITZDIESND,         MUSE_ACTORDIESND,      },  0,SD_PRIOADEATH, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_BLITZPLEADSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_BLITZPLEADSND,       MUSE_LASTSOUND,        },  SD_PLAYONCE,SD_PRIOAGREET, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_BLITZPLEAD1SND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_BLITZPLEAD1SND,       MUSE_LASTSOUND,       },  SD_PLAYONCE,SD_PRIOAGREET, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_BLITZPLEAD2SND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_BLITZPLEAD2SND,       MUSE_LASTSOUND,       },  SD_PLAYONCE,SD_PRIOAGREET, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_ENFORCERSEESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_ENFORCERSEESND,      MUSE_ACTORSEESND,      },  0,SD_PRIOAGREET, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_ENFORCERFIRESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_ENFORCERFIRESND,     MUSE_ACTORFIRESND,     },  0,SD_PRIOAFIRE, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_ENFORCERTHROWSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_ENFORCERTHROWSND,    MUSE_ACTORTHROWSND,    },  0,SD_PRIOASNEAK, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_ENFORCEROUCHSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_ENFORCEROUCHSND,     MUSE_ACTOROUCHSND,     },  0,SD_PRIOAHURT, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_ENFORCERDIESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_ENFORCERDIESND,      MUSE_ACTORDIESND,      },  0,SD_PRIOADEATH, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_MONKSEESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LASTSOUND,          MUSE_ACTORSEESND,       },  0,SD_PRIOAGREET, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_MONKGRABSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LASTSOUND,         MUSE_ACTORDOITSND,       },  0,SD_PRIOAFIRE, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_MONKOUCHSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LASTSOUND,         MUSE_ACTOROUCHSND,       },  0,SD_PRIOAHURT, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_MONKDIESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LASTSOUND,          MUSE_ACTORDIESND,       },  0,SD_PRIOADEATH, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_FIREMONKSEESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LASTSOUND,      MUSE_ACTORSEESND,           },  0,SD_PRIOAGREET, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_FIREMONKFIRESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LASTSOUND,     MUSE_ACTORFIRESND,           },  0,SD_PRIOAFIRE, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_FIREMONKOUCHSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LASTSOUND,     MUSE_ACTOROUCHSND,           },  0,SD_PRIOAHURT, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_FIREMONKDIESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LASTSOUND,      MUSE_ACTORDIESND,           },  0,SD_PRIOADEATH, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_ROBOTSEESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_ROBOTSEESND,         MUSE_ACTORSEESND,      },  0,SD_PRIOAGREET, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_ROBOTFIRESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_ROBOTFIRESND,        MUSE_ACTORFIRESND,     },  0,SD_PRIOAFIRE, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_ROBOTDIESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_ROBOTDIESND,         MUSE_ACTORDIESND,      },  0,SD_PRIOADEATH, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_ROBOTMOVESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_KRISTMOTORSND,       MUSE_LASTSOUND,        },  SD_PLAYONCE,SD_PRIOENVRON, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_BALLISTIKRAFTSEESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_BAZOOKAFIRESND,         MUSE_ACTORSEESND,   },  0,SD_PRIOAGREET, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_BALLISTIKRAFTFIRESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_ROBOTFIRESND,        MUSE_ACTORFIRESND,     },  0,SD_PRIOAFIRE, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_DARIANSEESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LASTSOUND,        MUSE_BOSSSEESND,          },  0,SD_PRIOBOSS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_DARIANFIRESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_BAZOOKAFIRESND,       MUSE_BOSSFIRESND,     },  0,SD_PRIOBOSS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_DARIANGONNAUSESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LASTSOUND,   MUSE_BOSSDOSND,                },  0,SD_PRIOBOSS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_DARIANUSESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_TOUCHPLATESND,       MUSE_BOSSDOSND,        },  0,SD_PRIOBOSS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_DARIANHIDESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LASTSOUND,       MUSE_BOSSDOSND,            },  0,SD_PRIOBOSS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_DARIANDIESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LASTSOUND,        MUSE_BOSSDIESND,          },  0,SD_PRIOBOSS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_DARIANSAY1,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LASTSOUND,          MUSE_BOSSWARNSND,       },  0,SD_PRIOBOSS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_DARIANSAY2,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LASTSOUND,          MUSE_BOSSHEYSND,        },  0,SD_PRIOBOSS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_DARIANSAY3,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LASTSOUND,          MUSE_BOSSWARNSND,       },  0,SD_PRIOBOSS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_KRISTSEESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LASTSOUND,         MUSE_BOSSSEESND,         },  0,SD_PRIOBOSS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_KRISTFIRESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_BAZOOKAFIRESND,      MUSE_BOSSFIRESND,      },  0,SD_PRIOBOSS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_KRISTMOTORSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LASTSOUND,       MUSE_LASTSOUND,            },  0,SD_PRIOBOSS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_KRISTTURNSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LASTSOUND,        MUSE_BOSSBEEPSND,         },  0,SD_PRIOBOSS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_KRISTDROPSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LASTSOUND,        MUSE_BOSSDOSND,           },  0,SD_PRIOBOSS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_KRISTMINEBEEPSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LASTSOUND,    MUSE_BOSSBEEPSND,             },  0,SD_PRIOBOSS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_KRISTMINEHITSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LASTSOUND,     MUSE_MISSILEHITSND,          },  0,SD_PRIOBOSS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_KRISTDIESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LASTSOUND,         MUSE_BOSSDIESND,         },  0,SD_PRIOBOSS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_KRISTSAY1,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LASTSOUND,           MUSE_BOSSWARNSND,      },  0,SD_PRIOBOSS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_KRISTSAY2,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LASTSOUND,           MUSE_BOSSHEYSND,       },  0,SD_PRIOBOSS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_KRISTSAY3,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LASTSOUND,           MUSE_BOSSWARNSND,      },  0,SD_PRIOBOSS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_NMESEESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LASTSOUND,           MUSE_BOSSSEESND,       },  0,SD_PRIOBOSS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_NMEREADYSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LASTSOUND,         MUSE_BOSSWARNSND,        },  0,SD_PRIOBOSS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_NMEFIRE1SND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_BAZOOKAFIRESND,      MUSE_BOSSFIRESND,      },  0,SD_PRIOBOSS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_NMEAPARTSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LASTSOUND,         MUSE_BOSSBEEPSND,        },  0,SD_PRIOBOSS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_NMEUFOSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LASTSOUND,           MUSE_MISSILEFIRESND,   },  0,SD_PRIOBOSS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_NMEDIESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_EXPLODESND,           MUSE_BOSSDIESND,      },  0,SD_PRIOBOSS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_DARKMONKSEESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LASTSOUND,      MUSE_BOSSSEESND,            },  0,SD_PRIOBOSS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_DARKMONKFIRE1SND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LASTSOUND,    MUSE_BOSSFIRESND,             },  0,SD_PRIOBOSS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_DARKMONKFIRE2SND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LASTSOUND,    MUSE_BOSSFIRE2SND,            },  0,SD_PRIOBOSS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_DARKMONKFIRE3SND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LASTSOUND,    MUSE_BOSSFIRESND,             },  0,SD_PRIOBOSS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_DARKMONKFIRE4SND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LASTSOUND,    MUSE_BOSSFIRE2SND,            },  0,SD_PRIOBOSS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_DARKMONKRECHARGESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LASTSOUND,   MUSE_WEAPONBUILDSND,           },  0,SD_PRIOBOSS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_DARKMONKFLOATSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LASTSOUND,    MUSE_LASTSOUND,               },  0,SD_PRIOBOSS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_DARKMONKDIESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LASTSOUND,      MUSE_BOSSDIESND,            },  0,SD_PRIOBOSS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_DARKMONKSAY1,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LASTSOUND,        MUSE_BOSSWARNSND,         },  0,SD_PRIOBOSS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_DARKMONKSAY2,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LASTSOUND,        MUSE_BOSSHEYSND,          },  0,SD_PRIOBOSS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_DARKMONKSAY3,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LASTSOUND,        MUSE_BOSSWARNSND,         },  0,SD_PRIOBOSS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_SNAKESEESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LASTSOUND,         MUSE_BOSSSEESND,         },  0,SD_PRIOBOSS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_SNAKEREADYSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LASTSOUND,       MUSE_BOSSBEEPSND,          },  0,SD_PRIOBOSS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_SNAKECHARGESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LASTSOUND,      MUSE_WEAPONBUILDSND,        },  0,SD_PRIOBOSS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_SNAKEOUCHSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LASTSOUND,        MUSE_BOSSOUCHSND,         },  0,SD_PRIOBOSS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_SNAKEDIESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LASTSOUND,         MUSE_BOSSDIESND,         },  0,SD_PRIOBOSS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_SNAKESPITSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LASTSOUND,        MUSE_BOSSFIRESND,         },  0,SD_PRIOBOSS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_SNAKESAY1,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LASTSOUND,           MUSE_BOSSWARNSND,      },  0,SD_PRIOBOSS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_SNAKESAY2,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LASTSOUND,           MUSE_BOSSHEYSND,       },  0,SD_PRIOBOSS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_SNAKESAY3,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LASTSOUND,           MUSE_BOSSWARNSND,      },  0,SD_PRIOBOSS, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_EMPLACEMENTSEESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LASTSOUND,   MUSE_SWITCHSND,                },  0,SD_PRIOAGREET, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_EMPLACEMENTFIRESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LASTSOUND,  MUSE_EMPFIRESND,                },  0,SD_PRIOAFIRE, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_BIGEMPLACEFIRESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LASTSOUND,   MUSE_EMPFIRESND,               },  0,SD_PRIOAFIRE, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_OPENDOORSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_OPENDOORSND,        MUSE_OPENDOORSND,       },  0,SD_PRIOPCAUSD, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_CLOSEDOORSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_CLOSEDOORSND,       MUSE_CLOSEDOORSND,      },  0,SD_PRIOPCAUSD, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_DOORHITSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_ELEVATORENDSND,       MUSE_LASTSOUND,           },  0,SD_PRIOPCAUSD, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_FIRECHUTESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_FIRECHUTESND,        MUSE_MISSILEFIRESND,   },  0,SD_PRIOENVRON, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_FIREBALLSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_FIREBALLSND,         MUSE_LASTSOUND,        },  0,SD_PRIOENVRON, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_FIREBALLHITSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_FIREBALLHITSND,      MUSE_MISSILEHITSND,    },  0,SD_PRIOENVRON, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_BLADESPINSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_BLADESPINSND,        MUSE_SPINBLADESND,     },  0,SD_PRIOENVRON, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_PUSHWALLSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_PUSHWALLSND,         MUSE_PUSHWALLSND,      },  0,SD_PRIOSECRET, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_PUSHWALLHITSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_PUSHWALLHITSND,      MUSE_MISSILEHITSND,    },  0,SD_PRIOENVRON, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_GOWALLSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_GOWALLSND,           MUSE_PUSHWALLSND,      },  0,SD_PRIOENVRON, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_TURBOWALLSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_TURBOWALLSND,        MUSE_PUSHWALLSND,      },  0,SD_PRIOENVRON, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_BOULDERHITSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LASTSOUND,       MUSE_MISSILEHITSND,        },  0,SD_PRIOENVRON, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_BOULDERROLLSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LASTSOUND,      MUSE_BOULDERSND,            },  0,SD_PRIOENVRON, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_BOULDERFALLSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LASTSOUND,       MUSE_PITTRAPSND,           },  0,SD_PRIOENVRON, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_PITTRAPSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_PITTRAPSND,          MUSE_PITTRAPSND,       },  0,SD_PRIOSECRET, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_FIREJETSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_FIREJETSND,          MUSE_FIREJETSND,       },  0,SD_PRIOENVRON, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_ACTORSQUISHSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_ACTORSQUISHSND,      MUSE_ACTORSQUISHSND,   },  0,SD_PRIOADEATH, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_ACTORBURNEDSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_ACTORBURNEDSND,      MUSE_ACTOROUCHSND,     },  0,SD_PRIOAHURT, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_ACTORSKELETONSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_ACTORSKELETONSND,    MUSE_LASTSOUND,        },  0,SD_PRIOAHURT, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_SPEARSTABSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_SPEARSTABSND,        MUSE_STABBERSND,       },  0,SD_PRIOENVRON, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_CYLINDERMOVESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_CYLINDERMOVESND,     MUSE_CYLINDERHITSND,   },  0,SD_PRIOENVRON, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_ELEVATORONSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_ELEVATORONSND,       MUSE_ELEVATORSND,      },  0,SD_PRIOPCAUSD, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_ELEVATORENDSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_ELEVATORENDSND,      MUSE_LASTSOUND,        },  0,SD_PRIOPCAUSD, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_SPRINGBOARDSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_SPRINGBOARDSND,      MUSE_SPRINGBOARDSND,   },  0,SD_PRIOPCAUSD, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_LIGHTNINGSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LIGHTNINGSND,        MUSE_LASTSOUND,        },  0,SD_PRIOPCAUSD, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_WINDSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LASTSOUND,             MUSE_LASTSOUND,        },  0,SD_PRIOPCAUSD, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_WATERSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LASTSOUND,            MUSE_LASTSOUND,       },  0,SD_PRIOPCAUSD, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_BODYLANDSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_BODYLANDSND,         MUSE_LASTSOUND,        },  0,SD_PRIOENVRON, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_GIBSPLASHSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_GIBSPLASHSND,         MUSE_LASTSOUND,       },  0,SD_PRIOENVRON, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_ACTORLANDSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_ACTORLANDSND,         MUSE_LASTSOUND,       },  0,SD_PRIOENVRON, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_DOPEFISHSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LASTSOUND,         MUSE_LASTSOUND,          },  0,SD_PRIOSECRET, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_YOUSUCKSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_YOUSUCKSND,          MUSE_LASTSOUND,        },  0,SD_PRIOSECRET, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_SILLYMOVESND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LASTSOUND,        MUSE_LASTSOUND,           },  0,SD_PRIOSECRET, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_SOUNDSELECTSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LASTSOUND,      MUSE_LASTSOUND,             },  0,SD_PRIOSECRET, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_SOUNDESCSND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_YOUSUCKSND,         MUSE_LASTSOUND,         },  0,SD_PRIOSECRET, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_REMOTEM1SND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_REMOTEM1SND,         MUSE_LASTSOUND,        },  0,SD_PRIOREMOTE, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_REMOTEM2SND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_REMOTEM2SND,         MUSE_LASTSOUND,        },  0,SD_PRIOREMOTE, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_REMOTEM3SND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_REMOTEM3SND,         MUSE_LASTSOUND,        },  0,SD_PRIOREMOTE, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_REMOTEM4SND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_REMOTEM4SND,         MUSE_LASTSOUND,        },  0,SD_PRIOREMOTE, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_REMOTEM5SND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_REMOTEM5SND,         MUSE_LASTSOUND,        },  0,SD_PRIOREMOTE, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_REMOTEM6SND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_REMOTEM6SND,         MUSE_LASTSOUND,        },  0,SD_PRIOREMOTE, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_REMOTEM7SND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_REMOTEM7SND,         MUSE_LASTSOUND,        },  0,SD_PRIOREMOTE, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_REMOTEM8SND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_REMOTEM8SND,         MUSE_LASTSOUND,        },  0,SD_PRIOREMOTE, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_REMOTEM9SND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_REMOTEM9SND,         MUSE_LASTSOUND,        },  0,SD_PRIOREMOTE, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_REMOTEM10SND,
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_REMOTEM10SND,        MUSE_LASTSOUND,        },  0,SD_PRIOREMOTE, 0, 0, 0},
+//�����������������������������������������������������������
+//SD_LASTSOUND
+//|-------DIGITAL--------|--------MUSE----------|----FLAGS---|
+    {{D_LASTSOUND,           MUSE_LASTSOUND,        },  0,SD_PRIOSECRET, 0, 0, 0}
+//�����������������������������������������������������������
+};
--- /dev/null
+++ b/rott/sndcards.h
@@ -1,0 +1,60 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+/**********************************************************************
+   module: SNDCARDS.H
+
+   author: James R. Dose
+   phone:  (214)-271-1365 Ext #221
+   date:   March 31, 1994
+
+   Contains enumerated type definitions for sound cards.
+
+   (c) Copyright 1994 James R. Dose.  All Rights Reserved.
+**********************************************************************/
+
+#ifndef __SNDCARDS_H
+#define __SNDCARDS_H
+
+#define ASS_VERSION_STRING "1.04"
+
+typedef enum
+{
+//   ASS_NoSound,
+    SoundBlaster,
+#ifdef DOS
+    ProAudioSpectrum,
+    SoundMan16,
+    Adlib,
+    GenMidi,
+    SoundCanvas,
+    Awe32,
+    WaveBlaster,
+#endif
+    SoundScape,
+    UltraSound,
+#ifdef DOS
+    SoundSource,
+    TandySoundSource,
+    PC,
+#endif
+    NumSoundCards
+} soundcardnames;
+
+#endif
--- /dev/null
+++ b/rott/splib.h
@@ -1,0 +1,213 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+#ifndef SPLIB_H
+#define SPLIB_H
+
+/* ======================================================================= *
+ * Please Read "SpReadme.doc" for usage                                    *
+ * ======================================================================= */
+
+/* ======================================================================= *
+ * Compiler & Memory Mode Wrappers.                                        *
+ * ----------------------------------------------------------------------- */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if defined(_MSC_VER) || defined(__BORLANDC__)
+#  if PLATFORM_DOS
+#    define REALMODE
+#  endif
+#endif
+
+#if defined(REALMODE)
+#define FAR __far
+#else
+#define FAR
+#endif
+
+//---------------------------------------------------------------------------
+// Constants
+
+#define TSR_SERIAL_LENGTH		14
+#define TSR_MAX_LENGTH			80
+
+//---------------------------------------------------------------------------
+
+typedef struct {
+    char           copyright[TSR_MAX_LENGTH];	// driver copyright
+    short          major;							// driver version number
+    short				minor;
+    short				count;							// # of available devices
+} SpwDrvOpenPacket;
+
+
+
+typedef struct {
+    char           copyright[TSR_MAX_LENGTH];	// device copyright
+    char           serial[TSR_SERIAL_LENGTH];	// device serial number
+} SpwDevOpenPacket;
+
+
+
+typedef struct {
+    long				timestamp;						// time of event
+    unsigned short	period;							// period since last MOVEMENT
+    unsigned short button;							// button pressed mask
+    short          tx;								// Translation X
+    short          ty;								//					Y
+    short          tz;								//					Z
+    short          rx;								// Rotation X
+    short          ry;								//				Y
+    short          rz;								//				Z
+} SpwForcePacket;
+
+
+
+typedef struct {
+    long           timestamp;						// time of event
+    unsigned short period;							// period since last BUTTON
+    unsigned short button;							// button pressed mask
+} SpwButtonPacket;
+
+
+
+typedef struct {
+    unsigned long data;								// MUST be TSRCMD_DATA
+} SpwCommandPacket;
+
+#define TSRCMD_DATA	0xFF0000FF
+
+//---------------------------------------------------------------------------
+
+typedef union {
+    char              padding[128];		/* Extra room for future expansion */
+
+    SpwCommandPacket	command;
+
+    SpwDrvOpenPacket	drvOpen;
+    SpwDevOpenPacket	devOpen;
+
+    SpwForcePacket		force;
+    SpwButtonPacket	button;
+} SpwPacket;
+
+
+
+// TSR Interrupt Functions
+#define TSR_DRIVER_CLOSE		 		0x0000
+#define TSR_DRIVER_OPEN					0x8001
+#define TSR_DEVICE_CLOSE				0x0002
+#define TSR_DEVICE_OPEN					0x8003
+
+#define TSR_DEVICE_DISABLE				0x0010
+#define TSR_DEVICE_ENABLE				0x0011
+
+#define TSR_DEVICE_GETFORCE			0x8020
+#define TSR_DEVICE_GETBUTTONS			0x8021
+
+/* ======================================================================= *
+ * Function Prototypes                                                     *
+ * ======================================================================= */
+
+short SpwOpenDriver(SpwPacket FAR *packet);
+short SpwCloseDriver(void);
+
+short SpwOpenDevice(short device, SpwPacket FAR *packet);
+short SpwCloseDevice(short device);
+
+short SpwEnableDevice(short device);
+short SpwDisableDevice(short device);
+
+short SpwGetForce(short device, SpwPacket FAR *packet);
+short SpwGetButton(short device, SpwPacket FAR *packet);
+
+/* ======================================================================= *
+ * Convience functions                                                     *
+ * ======================================================================= */
+
+/* ----------------------------------------------------------------------- *
+ * The SpwSimple... functions are just convienence wrappers for the above  *
+ * functions.                                                              *
+ * ----------------------------------------------------------------------- */
+
+#ifndef SPWSTRUCTS
+#define SPWSTRUCTS
+
+enum SpwDeviceType {
+    SPW_AVENGER=1,
+};
+
+
+
+enum SpwEventType {
+    SPW_NO_EVENT=0,
+    SPW_BUTTON_HELD=1,
+    SPW_BUTTON_DOWN=2,
+    SPW_BUTTON_UP=4,
+    SPW_MOTION=8
+};
+
+
+
+/* ----------------------------------------------------------------------- *
+ * Data struct for handling library calls                                  *
+ * ----------------------------------------------------------------------- */
+
+typedef struct {
+    short new;
+    short cur;
+    short old;
+} SpwButtonRec;
+
+
+
+typedef struct {
+    short 		 tx;			/* Current Translation vector */
+    short 		 ty;
+    short 		 tz;
+    short 		 rx;			/* Current Rotation vector    */
+    short 		 ry;
+    short        rz;
+    SpwButtonRec buttons;   /* Current Button Record      */
+    short			 newData;   /* An SpEventType mask of newData, 0 if none */
+} SpwRawData;
+
+#endif
+
+
+
+short SpwSimpleGet(short devNum, SpwRawData FAR *splayer);
+short SpwSimpleOpen(short devNum);
+short SpwSimpleClose(short devNum);
+
+/* ======================================================================= *
+ * Compiler & Memory Mode Wrappers.                                        *
+ * ======================================================================= *
+ */
+
+#ifdef __cplusplus
+};
+#endif
+
+/* ======================================================================= */
+#endif
+
--- /dev/null
+++ b/rott/sprites.h
@@ -1,0 +1,1611 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+#ifndef _sprites_public
+#define _sprites_public
+
+#include "develop.h"
+
+typedef enum {ACTOR_START_LABEL,
+
+
+              /***************    UNTERWACHE  *************************************/
+
+
+              SPR_LOWGRD_SHOOT1,SPR_LOWGRD_SHOOT2,SPR_LOWGRD_SHOOT3,SPR_LOWGRD_SHOOT4,
+
+              SPR_LOWGRD_S1,SPR_LOWGRD_S2,SPR_LOWGRD_S3,SPR_LOWGRD_S4,
+              SPR_LOWGRD_S5,SPR_LOWGRD_S6,SPR_LOWGRD_S7,SPR_LOWGRD_S8,
+
+              SPR_LOWGRD_W11,SPR_LOWGRD_W12,SPR_LOWGRD_W13,SPR_LOWGRD_W14,
+              SPR_LOWGRD_W15,SPR_LOWGRD_W16,SPR_LOWGRD_W17,SPR_LOWGRD_W18,
+
+              SPR_LOWGRD_W21,SPR_LOWGRD_W22,SPR_LOWGRD_W23,SPR_LOWGRD_W24,
+              SPR_LOWGRD_W25,SPR_LOWGRD_W26,SPR_LOWGRD_W27,SPR_LOWGRD_W28,
+
+              SPR_LOWGRD_W31,SPR_LOWGRD_W32,SPR_LOWGRD_W33,SPR_LOWGRD_W34,
+              SPR_LOWGRD_W35,SPR_LOWGRD_W36,SPR_LOWGRD_W37,SPR_LOWGRD_W38,
+
+              SPR_LOWGRD_W41,SPR_LOWGRD_W42,SPR_LOWGRD_W43,SPR_LOWGRD_W44,
+              SPR_LOWGRD_W45,SPR_LOWGRD_W46,SPR_LOWGRD_W47,SPR_LOWGRD_W48,
+
+
+              SPR_LOWGRD_PAIN1, SPR_LOWGRD_PAIN2, SPR_LOWGRD_DIE1, SPR_LOWGRD_DIE2,
+              SPR_LOWGRD_DIE3, SPR_LOWGRD_DIE4, SPR_LOWGRD_DEAD,
+
+              SPR_LOWGRD_WPAIN1, SPR_LOWGRD_WPAIN2, SPR_LOWGRD_WDIE1, SPR_LOWGRD_WDIE2,
+              SPR_LOWGRD_WDIE3, SPR_LOWGRD_WDIE4, SPR_LOWGRD_WDEAD,
+
+
+              SPR_SNEAKY_DEAD, SPR_RISE1, SPR_RISE2, SPR_RISE3, SPR_RISE4,
+
+              /*
+              SPR_LOWGRD_USE11,SPR_LOWGRD_USE12,SPR_LOWGRD_USE13,SPR_LOWGRD_USE14,
+              SPR_LOWGRD_USE15,SPR_LOWGRD_USE16,SPR_LOWGRD_USE17,SPR_LOWGRD_USE18,
+
+              SPR_LOWGRD_USE21,SPR_LOWGRD_USE22,SPR_LOWGRD_USE23,SPR_LOWGRD_USE24,
+              SPR_LOWGRD_USE25,SPR_LOWGRD_USE26,SPR_LOWGRD_USE27,SPR_LOWGRD_USE28,
+              */
+
+
+              /*****************  Highguard 1 (Steve B.)  ***************************************/
+
+
+
+
+              SPR_HIGHGRD_SHOOT1,SPR_HIGHGRD_SHOOT2,SPR_HIGHGRD_SHOOT3,SPR_HIGHGRD_SHOOT4,
+
+              SPR_HIGHGRD_S1,SPR_HIGHGRD_S2,SPR_HIGHGRD_S3,SPR_HIGHGRD_S4,
+              SPR_HIGHGRD_S5,SPR_HIGHGRD_S6,SPR_HIGHGRD_S7,SPR_HIGHGRD_S8,
+
+              SPR_HIGHGRD_W11,SPR_HIGHGRD_W12,SPR_HIGHGRD_W13,SPR_HIGHGRD_W14,
+              SPR_HIGHGRD_W15,SPR_HIGHGRD_W16,SPR_HIGHGRD_W17,SPR_HIGHGRD_W18,
+
+              SPR_HIGHGRD_W21,SPR_HIGHGRD_W22,SPR_HIGHGRD_W23,SPR_HIGHGRD_W24,
+              SPR_HIGHGRD_W25,SPR_HIGHGRD_W26,SPR_HIGHGRD_W27,SPR_HIGHGRD_W28,
+
+              SPR_HIGHGRD_W31,SPR_HIGHGRD_W32,SPR_HIGHGRD_W33,SPR_HIGHGRD_W34,
+              SPR_HIGHGRD_W35,SPR_HIGHGRD_W36,SPR_HIGHGRD_W37,SPR_HIGHGRD_W38,
+
+              SPR_HIGHGRD_W41,SPR_HIGHGRD_W42,SPR_HIGHGRD_W43,SPR_HIGHGRD_W44,
+              SPR_HIGHGRD_W45,SPR_HIGHGRD_W46,SPR_HIGHGRD_W47,SPR_HIGHGRD_W48,
+
+
+              SPR_HIGHGRD_PAIN1,SPR_HIGHGRD_PAIN2,
+              SPR_HIGHGRD_DIE1,SPR_HIGHGRD_DIE2,SPR_HIGHGRD_DIE3,SPR_HIGHGRD_DIE4,
+              SPR_HIGHGRD_DIE5,SPR_HIGHGRD_DEAD,
+
+              SPR_HIGHGRD_WPAIN1,SPR_HIGHGRD_WPAIN2,
+              SPR_HIGHGRD_WDIE1,SPR_HIGHGRD_WDIE2,SPR_HIGHGRD_WDIE3,SPR_HIGHGRD_WDIE4,
+              SPR_HIGHGRD_WDIE5,SPR_HIGHGRD_WDEAD,
+
+              /*
+              SPR_HIGHGRD_USE11,SPR_HIGHGRD_USE12,SPR_HIGHGRD_USE13,SPR_HIGHGRD_USE14,
+              SPR_HIGHGRD_USE15,SPR_HIGHGRD_USE16,SPR_HIGHGRD_USE17,SPR_HIGHGRD_USE18,
+
+              SPR_HIGHGRD_USE21,SPR_HIGHGRD_USE22,SPR_HIGHGRD_USE23,SPR_HIGHGRD_USE24,
+              SPR_HIGHGRD_USE25,SPR_HIGHGRD_USE26,SPR_HIGHGRD_USE27,SPR_HIGHGRD_USE28,
+              */
+
+
+
+
+              /******************** ANGRIFFSTUPPE **********************************/
+
+
+              SPR_STRIKE_SHOOT1,SPR_STRIKE_SHOOT2,SPR_STRIKE_SHOOT3,SPR_STRIKE_SHOOT4,
+              SPR_STRIKE_KSHOOT1,SPR_STRIKE_KSHOOT2,SPR_STRIKE_KSHOOT3,
+
+
+              SPR_STRIKE_S1,SPR_STRIKE_S2,SPR_STRIKE_S3,SPR_STRIKE_S4,
+              SPR_STRIKE_S5,SPR_STRIKE_S6,SPR_STRIKE_S7,SPR_STRIKE_S8,
+
+              SPR_STRIKE_W11,SPR_STRIKE_W12,SPR_STRIKE_W13,SPR_STRIKE_W14,
+              SPR_STRIKE_W15,SPR_STRIKE_W16,SPR_STRIKE_W17,SPR_STRIKE_W18,
+
+              SPR_STRIKE_W21,SPR_STRIKE_W22,SPR_STRIKE_W23,SPR_STRIKE_W24,
+              SPR_STRIKE_W25,SPR_STRIKE_W26,SPR_STRIKE_W27,SPR_STRIKE_W28,
+
+              SPR_STRIKE_W31,SPR_STRIKE_W32,SPR_STRIKE_W33,SPR_STRIKE_W34,
+              SPR_STRIKE_W35,SPR_STRIKE_W36,SPR_STRIKE_W37,SPR_STRIKE_W38,
+
+              SPR_STRIKE_W41,SPR_STRIKE_W42,SPR_STRIKE_W43,SPR_STRIKE_W44,
+              SPR_STRIKE_W45,SPR_STRIKE_W46,SPR_STRIKE_W47,SPR_STRIKE_W48,
+
+
+              SPR_STRIKE_PAIN1,SPR_STRIKE_PAIN2,
+              SPR_STRIKE_DIE1,SPR_STRIKE_DIE2,SPR_STRIKE_DIE3,
+              SPR_STRIKE_DIE4,SPR_STRIKE_DEAD1,SPR_STRIKE_DEAD2,SPR_STRIKE_DEAD3,
+
+              SPR_STRIKE_WPAIN1,SPR_STRIKE_WPAIN2,
+              SPR_STRIKE_WDIE1,SPR_STRIKE_WDIE2,SPR_STRIKE_WDIE3,
+              SPR_STRIKE_WDIE4,SPR_STRIKE_WDEAD1,SPR_STRIKE_WDEAD2,SPR_STRIKE_WDEAD3,
+
+              SPR_STRIKE_RROLL1,SPR_STRIKE_RROLL2,SPR_STRIKE_RROLL3,SPR_STRIKE_RROLL4,
+              SPR_STRIKE_RROLL5,SPR_STRIKE_RROLL6,
+
+              SPR_STRIKE_LROLL1,SPR_STRIKE_LROLL2,SPR_STRIKE_LROLL3,SPR_STRIKE_LROLL4,
+              SPR_STRIKE_LROLL5,SPR_STRIKE_LROLL6,
+
+
+
+
+              /********************** BLITZWACHE **********************************/
+
+
+              SPR_BLITZ_SHOOT1,SPR_BLITZ_SHOOT2,SPR_BLITZ_SHOOT3,SPR_BLITZ_SHOOT4,
+
+              SPR_BLITZ_S1,SPR_BLITZ_S2,SPR_BLITZ_S3,SPR_BLITZ_S4,
+              SPR_BLITZ_S5,SPR_BLITZ_S6,SPR_BLITZ_S7,SPR_BLITZ_S8,
+
+              SPR_BLITZ_W11,SPR_BLITZ_W12,SPR_BLITZ_W13,SPR_BLITZ_W14,
+              SPR_BLITZ_W15,SPR_BLITZ_W16,SPR_BLITZ_W17,SPR_BLITZ_W18,
+
+              SPR_BLITZ_W21,SPR_BLITZ_W22,SPR_BLITZ_W23,SPR_BLITZ_W24,
+              SPR_BLITZ_W25,SPR_BLITZ_W26,SPR_BLITZ_W27,SPR_BLITZ_W28,
+
+              SPR_BLITZ_W31,SPR_BLITZ_W32,SPR_BLITZ_W33,SPR_BLITZ_W34,
+              SPR_BLITZ_W35,SPR_BLITZ_W36,SPR_BLITZ_W37,SPR_BLITZ_W38,
+
+              SPR_BLITZ_W41,SPR_BLITZ_W42,SPR_BLITZ_W43,SPR_BLITZ_W44,
+              SPR_BLITZ_W45,SPR_BLITZ_W46,SPR_BLITZ_W47,SPR_BLITZ_W48,
+
+
+              SPR_BLITZ_PAIN1, SPR_BLITZ_PAIN2,SPR_BLITZ_DIE1,SPR_BLITZ_DIE2,
+              SPR_BLITZ_DIE3,SPR_BLITZ_DIE4,SPR_BLITZ_DEAD1, SPR_BLITZ_DEAD2,
+
+              SPR_BLITZ_WPAIN1, SPR_BLITZ_WPAIN2,SPR_BLITZ_WDIE1,SPR_BLITZ_WDIE2,
+              SPR_BLITZ_WDIE3,SPR_BLITZ_WDIE4,SPR_BLITZ_WDEAD1, SPR_BLITZ_WDEAD2,
+
+              SPR_BLITZ_RISE1, SPR_BLITZ_RISE2, SPR_BLITZ_RISE3, SPR_BLITZ_RISE4,
+
+              SPR_BLITZ_USE11,SPR_BLITZ_USE12,SPR_BLITZ_USE13,SPR_BLITZ_USE14,
+              SPR_BLITZ_USE15,SPR_BLITZ_USE16,SPR_BLITZ_USE17,SPR_BLITZ_USE18,
+
+              SPR_BLITZ_USE21,SPR_BLITZ_USE22,SPR_BLITZ_USE23,SPR_BLITZ_USE24,
+              SPR_BLITZ_USE25,SPR_BLITZ_USE26,SPR_BLITZ_USE27,SPR_BLITZ_USE28,
+
+              SPR_BLITZ_PLEAD1,SPR_BLITZ_PLEAD2,SPR_BLITZ_PLEAD3,SPR_BLITZ_PLEAD4,
+              SPR_BLITZ_PLEAD5,SPR_BLITZ_PLEAD6,SPR_BLITZ_PLEAD7,SPR_BLITZ_PLEAD8,
+              SPR_BLITZ_PLEAD9,SPR_BLITZ_PLEAD10,SPR_BLITZ_PLEAD11,
+
+
+
+
+              /******************** DREIHEITWACHE ***********************************/
+
+
+              SPR_ENFORCER_SHOOT1,SPR_ENFORCER_SHOOT2,SPR_ENFORCER_SHOOT3,
+              SPR_ENFORCER_SHOOT4,
+
+              SPR_ENFORCER_S1,SPR_ENFORCER_S2,SPR_ENFORCER_S3,SPR_ENFORCER_S4,
+              SPR_ENFORCER_S5,SPR_ENFORCER_S6,SPR_ENFORCER_S7,SPR_ENFORCER_S8,
+
+              SPR_ENFORCER_W11,SPR_ENFORCER_W12,SPR_ENFORCER_W13,SPR_ENFORCER_W14,
+              SPR_ENFORCER_W15,SPR_ENFORCER_W16,SPR_ENFORCER_W17,SPR_ENFORCER_W18,
+
+              SPR_ENFORCER_W21,SPR_ENFORCER_W22,SPR_ENFORCER_W23,SPR_ENFORCER_W24,
+              SPR_ENFORCER_W25,SPR_ENFORCER_W26,SPR_ENFORCER_W27,SPR_ENFORCER_W28,
+
+              SPR_ENFORCER_W31,SPR_ENFORCER_W32,SPR_ENFORCER_W33,SPR_ENFORCER_W34,
+              SPR_ENFORCER_W35,SPR_ENFORCER_W36,SPR_ENFORCER_W37,SPR_ENFORCER_W38,
+
+              SPR_ENFORCER_W41,SPR_ENFORCER_W42,SPR_ENFORCER_W43,SPR_ENFORCER_W44,
+              SPR_ENFORCER_W45,SPR_ENFORCER_W46,SPR_ENFORCER_W47,SPR_ENFORCER_W48,
+
+
+              SPR_ENFORCER_THROW1,SPR_ENFORCER_THROW2,SPR_ENFORCER_THROW3,SPR_ENFORCER_THROW4,
+              SPR_ENFORCER_THROW5,SPR_ENFORCER_THROW6,SPR_ENFORCER_THROW7,SPR_ENFORCER_THROW8,
+
+              SPR_ENFORCER_PAIN1,SPR_ENFORCER_PAIN2,
+              SPR_ENFORCER_DIE1,SPR_ENFORCER_DIE2,SPR_ENFORCER_DIE3,SPR_ENFORCER_DIE4,
+              SPR_ENFORCER_DEAD,
+
+              SPR_ENFORCER_WPAIN1,SPR_ENFORCER_WPAIN2,
+              SPR_ENFORCER_WDIE1,SPR_ENFORCER_WDIE2,SPR_ENFORCER_WDIE3,SPR_ENFORCER_WDIE4,
+              SPR_ENFORCER_WDEAD,
+
+              /*
+              SPR_ENFORCER_USE11,SPR_ENFORCER_USE12,SPR_ENFORCER_USE13,SPR_ENFORCER_USE14,
+              SPR_ENFORCER_USE15,SPR_ENFORCER_USE16,SPR_ENFORCER_USE17,SPR_ENFORCER_USE18,
+
+              SPR_ENFORCER_USE21,SPR_ENFORCER_USE22,SPR_ENFORCER_USE23,SPR_ENFORCER_USE24,
+              SPR_ENFORCER_USE25,SPR_ENFORCER_USE26,SPR_ENFORCER_USE27,SPR_ENFORCER_USE28,
+              */
+
+
+              /************************* ROBOT GUARD *********************************/
+
+
+              SPR_ROBOGRD_S11,SPR_ROBOGRD_S12,SPR_ROBOGRD_S13,SPR_ROBOGRD_S14,
+              SPR_ROBOGRD_S15,SPR_ROBOGRD_S16,SPR_ROBOGRD_S17,SPR_ROBOGRD_S18,
+
+              SPR_ROBOGRD_S21,SPR_ROBOGRD_S22,SPR_ROBOGRD_S23,SPR_ROBOGRD_S24,
+              SPR_ROBOGRD_S25,SPR_ROBOGRD_S26,SPR_ROBOGRD_S27,SPR_ROBOGRD_S28,
+
+              ROBOGRDDIE1,ROBOGRDDIE2,ROBOGRDDIE3,ROBOGRDDIE4,
+              ROBOGRDDIE5,ROBOGRDDIE6,ROBOGRDDIE7,ROBOGRDDIE8,
+              ROBOGRDDIE9,ROBOGRDDEAD,
+
+
+
+              /************************* EXPLOSIONS *******************************/
+
+              SPR_EXPLOSION1,SPR_EXPLOSION2,SPR_EXPLOSION3,SPR_EXPLOSION4,
+              SPR_EXPLOSION5,SPR_EXPLOSION6,SPR_EXPLOSION7,SPR_EXPLOSION8,
+              SPR_EXPLOSION9,SPR_EXPLOSION10,SPR_EXPLOSION11,SPR_EXPLOSION12,
+              SPR_EXPLOSION13,SPR_EXPLOSION14,SPR_EXPLOSION15,SPR_EXPLOSION16,
+              SPR_EXPLOSION17,SPR_EXPLOSION18,SPR_EXPLOSION19,SPR_EXPLOSION20,
+
+
+
+              SPR_STATICEXPL1,SPR_STATICEXPL2,SPR_STATICEXPL3,SPR_STATICEXPL4,
+              SPR_STATICEXPL5,SPR_STATICEXPL6,SPR_STATICEXPL7,SPR_STATICEXPL8,
+              SPR_STATICEXPL9,SPR_STATICEXPL10,SPR_STATICEXPL11,SPR_STATICEXPL12,
+              SPR_STATICEXPL13,SPR_STATICEXPL14,SPR_STATICEXPL15,SPR_STATICEXPL16,
+              SPR_STATICEXPL17,SPR_STATICEXPL18,SPR_STATICEXPL19,SPR_STATICEXPL20,
+              SPR_STATICEXPL21,SPR_STATICEXPL22,SPR_STATICEXPL23,SPR_STATICEXPL24,
+              SPR_STATICEXPL25,
+
+              SPR_GROUNDEXPL1,SPR_GROUNDEXPL2,SPR_GROUNDEXPL3,SPR_GROUNDEXPL4,
+              SPR_GROUNDEXPL5,SPR_GROUNDEXPL6,SPR_GROUNDEXPL7,SPR_GROUNDEXPL8,
+              SPR_GROUNDEXPL9,SPR_GROUNDEXPL10,SPR_GROUNDEXPL11,SPR_GROUNDEXPL12,
+              SPR_GROUNDEXPL13,SPR_GROUNDEXPL14,SPR_GROUNDEXPL15,SPR_GROUNDEXPL16,
+              SPR_GROUNDEXPL17,SPR_GROUNDEXPL18,SPR_GROUNDEXPL19,SPR_GROUNDEXPL20,
+
+
+              /************************* HAZARDS *******************************/
+
+
+
+              UBLADE1,UBLADE2,UBLADE3,UBLADE4,
+              UBLADE5,UBLADE6,UBLADE7,UBLADE8,
+              UBLADE9,//UBLADE10,UBLADE11,UBLADE12,
+//UBLADE13,UBLADE14,UBLADE15,UBLADE16,
+
+
+
+
+              FIREJETUP1,FIREJETUP2,FIREJETUP3,FIREJETUP4,
+              FIREJETUP5,FIREJETUP6,FIREJETUP7,FIREJETUP8,
+              FIREJETUP9,FIREJETUP10,FIREJETUP11,FIREJETUP12,
+              FIREJETUP13,FIREJETUP14,FIREJETUP15,FIREJETUP16,
+              FIREJETUP17,FIREJETUP18,FIREJETUP19,FIREJETUP20,
+              FIREJETUP21,FIREJETUP22,FIREJETUP23,
+
+
+
+              CRUSHDOWN1,CRUSHDOWN2,CRUSHDOWN3,CRUSHDOWN4,
+              CRUSHDOWN5,CRUSHDOWN6,CRUSHDOWN7,CRUSHDOWN8,
+//CRUSHDOWN9,CRUSHDOWN10,CRUSHDOWN11,CRUSHDOWN12,
+//CRUSHDOWN13,CRUSHDOWN14,CRUSHDOWN15,CRUSHDOWN16,
+
+
+
+              SPEARUP1,SPEARUP2,SPEARUP3,SPEARUP4,
+              SPEARUP5,SPEARUP6,SPEARUP7,SPEARUP8,
+              SPEARUP9,SPEARUP10,SPEARUP11,SPEARUP12,
+              SPEARUP13,SPEARUP14,SPEARUP15,SPEARUP16,
+
+
+
+
+
+              SPRING1,SPRING2,SPRING3,SPRING4,
+              SPRING5,SPRING6,SPRING7,SPRING8,
+              SPRING9,SPRING10,
+
+
+
+
+              FIREW1,FIREW2,FIREW3,FIREW4,FIREW5,FIREW6,FIREW7,FIREW8,
+              FIREW9,FIREW10,FIREW11,FIREW12,FIREW13,FIREW14,FIREW15,
+
+
+
+
+              GUTS1,GUTS2,GUTS3,GUTS4,
+              GUTS5,GUTS6,GUTS7,GUTS8,
+              GUTS9,GUTS10,GUTS11,GUTS12,
+
+
+              PARTICLE01,PARTICLE02,PARTICLE03,PARTICLE04,
+              PARTICLE05,PARTICLE06,PARTICLE07,PARTICLE08,
+              PARTICLE09,PARTICLE10,PARTICLE11,PARTICLE12,
+
+              ORGAN01,ORGAN02,ORGAN03,ORGAN04,
+              ORGAN05,ORGAN06,ORGAN07,ORGAN08,
+              ORGAN09,ORGAN10,ORGAN11,ORGAN12,
+
+              RIB01,RIB02,RIB03,RIB04,
+              RIB05,RIB06,RIB07,RIB08,
+              RIB09,RIB10,RIB11,RIB12,
+
+              PINK01, PINK02, PINK03, PINK04,
+              PINK05, PINK06, PINK07, PINK08,
+              PINK09, PINK10, PINK11, PINK12,
+
+              GIBHEAD01,GIBHEAD02,GIBHEAD03,GIBHEAD04,
+              GIBHEAD05,GIBHEAD06,GIBHEAD07,GIBHEAD08,
+              GIBHEAD09,GIBHEAD10,GIBHEAD11,GIBHEAD12,
+
+              GARM01,GARM02,GARM03,GARM04,
+              GARM05,GARM06,GARM07,GARM08,
+              GARM09,GARM10,GARM11,GARM12,
+
+              GLEG01,GLEG02,GLEG03,GLEG04,
+              GLEG05,GLEG06,GLEG07,GLEG08,
+              GLEG09,GLEG10,GLEG11,GLEG12,
+
+              HUMERUS01, HUMERUS02, HUMERUS03, HUMERUS04,
+              HUMERUS05, HUMERUS06, HUMERUS07, HUMERUS08,
+              HUMERUS09, HUMERUS10, HUMERUS11, HUMERUS12,
+
+              PELVIS01, PELVIS02, PELVIS03, PELVIS04,
+              PELVIS05, PELVIS06, PELVIS07, PELVIS08,
+              PELVIS09, PELVIS10, PELVIS11, PELVIS12,
+
+              LIMB01, LIMB02, LIMB03, LIMB04,
+              LIMB05, LIMB06, LIMB07, LIMB08,
+              LIMB09, LIMB10, LIMB11, LIMB12,
+
+
+              DEADHEAD,
+
+              WALLGIB1,WALLGIB2,WALLGIB3,WALLGIB4,
+
+              GIBEYE1,GIBEYE2,GIBEYE3,
+
+              VAPORIZED1,VAPORIZED2,VAPORIZED3,VAPORIZED4,
+              VAPORIZED5,VAPORIZED6,VAPORIZED7,VAPORIZED8,
+
+              BIGSOUL,LITTLESOUL,
+              COLLECTOR1,
+              COLLECTOR3,
+              COLLECTOR5,
+              COLLECTOR7,
+              COLLECTOR9,
+              COLLECTOR11,
+              COLLECTOR13,
+              COLLECTOR15,
+
+
+              ITEMSPAWN1,ITEMSPAWN2,ITEMSPAWN3,ITEMSPAWN4,
+              ITEMSPAWN5,ITEMSPAWN6,ITEMSPAWN7,ITEMSPAWN8,
+
+              DEADBLOOD1,DEADBLOOD2,DEADBLOOD3,DEADBLOOD4,
+              DEADBLOOD5,DEADBLOOD6,DEADBLOOD7,
+
+
+              FLASH1,FLASH2,FLASH3,FLASH4,
+              FLASH5,FLASH6,FLASH7,FLASH8,
+
+
+              SKELETON1,SKELETON2,SKELETON3,SKELETON4,
+              SKELETON5,SKELETON6,SKELETON7,SKELETON8,
+
+              SKELETON9,SKELETON10,SKELETON11,SKELETON12,
+              SKELETON13,SKELETON14,SKELETON15,SKELETON16,
+
+              SKELETON17,SKELETON18,SKELETON19,SKELETON20,
+              SKELETON21,SKELETON22,SKELETON23,SKELETON24,
+
+              SKELETON25,SKELETON26,SKELETON27,SKELETON28,
+              SKELETON29,SKELETON30,SKELETON31,SKELETON32,
+
+              SKELETON33,SKELETON34,SKELETON35,SKELETON36,
+              SKELETON37,SKELETON38,SKELETON39,SKELETON40,
+
+              SKELETON41,SKELETON42,SKELETON43,SKELETON44,
+              SKELETON45,SKELETON46,SKELETON47,SKELETON48,
+
+
+              SPR_PUSHCOLUMN1,SPR_PUSHCOLUMN1a,
+              /*
+              SPR_PUSHCOLUMN2,SPR_PUSHCOLUMN2a,
+              SPR_PUSHCOLUMN3,SPR_PUSHCOLUMN3a,
+              */
+
+              BLOODSPURT1,BLOODSPURT2,BLOODSPURT3,BLOODSPURT4,
+              BLOODSPURT5,BLOODSPURT6,BLOODSPURT7,BLOODSPURT8,
+
+              GUNSMOKE1,GUNSMOKE2,GUNSMOKE3,GUNSMOKE4,
+              GUNSMOKE5,GUNSMOKE6,GUNSMOKE7,GUNSMOKE8,
+
+
+
+              HITMETALWALL1,HITMETALWALL2,HITMETALWALL3,HITMETALWALL4,
+
+              HITMETALACTOR1,HITMETALACTOR2,HITMETALACTOR3,HITMETALACTOR4,
+
+
+              PLATFORM1,  PLATFORM2,  PLATFORM3,  PLATFORM4,  PLATFORM5,
+
+
+              SPR_CROSSFIRE11, SPR_CROSSFIRE12,SPR_CROSSFIRE13, SPR_CROSSFIRE14,
+              SPR_CROSSFIRE15, SPR_CROSSFIRE16,SPR_CROSSFIRE17, SPR_CROSSFIRE18,
+
+              SPR_CROSSFIRE31, SPR_CROSSFIRE32,SPR_CROSSFIRE33, SPR_CROSSFIRE34,
+              SPR_CROSSFIRE35, SPR_CROSSFIRE36,SPR_CROSSFIRE37, SPR_CROSSFIRE38,
+
+              SPR_CREXP1,SPR_CREXP2,SPR_CREXP3,SPR_CREXP4,SPR_CREXP5,
+
+
+              GODFIRE1,GODFIRE2,GODFIRE3,GODFIRE4,
+
+
+
+              SPR_ENFORCER_GR1,SPR_ENFORCER_GR2,SPR_ENFORCER_GR3,SPR_ENFORCER_GR4,
+              SPR_ENFORCER_GR5,SPR_ENFORCER_GR6,SPR_ENFORCER_GR7,SPR_ENFORCER_GR8,
+              SPR_ENFORCER_GR9,SPR_ENFORCER_GR10,
+
+              SPR_ENFORCER_FALL1,SPR_ENFORCER_FALL2,SPR_ENFORCER_FALL3,SPR_ENFORCER_FALL4,
+              SPR_ENFORCER_FALL5,SPR_ENFORCER_FALL6,
+
+
+              SPR_MINE1,SPR_MINE2,SPR_MINE3,SPR_MINE4,
+
+              SPR_BJMISS11,SPR_BJMISS12,SPR_BJMISS13,SPR_BJMISS14,
+              SPR_BJMISS15,SPR_BJMISS16,SPR_BJMISS17,SPR_BJMISS18,
+              SPR_BJMISS19,SPR_BJMISS110,SPR_BJMISS111,SPR_BJMISS112,
+              SPR_BJMISS113,SPR_BJMISS114,SPR_BJMISS115,SPR_BJMISS116,
+
+
+              SPR_BSTAR1,SPR_BSTAR2,SPR_BSTAR3,SPR_BSTAR4,
+
+
+
+              GODPOWERUP1,   GODPOWERUP2,   GODPOWERUP3, GODPOWERUP4,
+              GODPOWERUP5,   GODPOWERUP6,   GODPOWERUP7, GODPOWERUP8,
+
+
+
+              ELASTICPOWERUP1, ELASTICPOWERUP2, ELASTICPOWERUP3, ELASTICPOWERUP4,
+              ELASTICPOWERUP5, ELASTICPOWERUP6, ELASTICPOWERUP7, ELASTICPOWERUP8,
+
+              RANDOMPOWERUP1,  RANDOMPOWERUP2,  RANDOMPOWERUP3,  RANDOMPOWERUP4,
+              RANDOMPOWERUP5,  RANDOMPOWERUP6,  RANDOMPOWERUP7,	RANDOMPOWERUP8,
+
+              FLEETFEETPOWERUP1,  FLEETFEETPOWERUP2, FLEETFEETPOWERUP3, FLEETFEETPOWERUP4,
+              FLEETFEETPOWERUP5,  FLEETFEETPOWERUP6, FLEETFEETPOWERUP7, FLEETFEETPOWERUP8,
+
+              MUSHROOMPOWERUP1, MUSHROOMPOWERUP2, MUSHROOMPOWERUP3, MUSHROOMPOWERUP4,
+              MUSHROOMPOWERUP5, MUSHROOMPOWERUP6,	MUSHROOMPOWERUP7, MUSHROOMPOWERUP8,
+
+
+              ONEUP01,       ONEUP02,       ONEUP03,    ONEUP04,
+              ONEUP05,       ONEUP06,       ONEUP07,		ONEUP08,
+
+
+              LIFEITEMA01,   LIFEITEMA02,   LIFEITEMA03,   LIFEITEMA04,
+              LIFEITEMA05,   LIFEITEMA06,   LIFEITEMA07,   LIFEITEMA08,
+
+              LIFEITEMB01,   LIFEITEMB02,   LIFEITEMB03,   LIFEITEMB04,
+              LIFEITEMB05,   LIFEITEMB06,   LIFEITEMB07,   LIFEITEMB08,
+
+              LIFEITEMC01,   LIFEITEMC02,   LIFEITEMC03,   LIFEITEMC04,
+              LIFEITEMC05,   LIFEITEMC06,   LIFEITEMC07,   LIFEITEMC08,
+              LIFEITEMC09,   LIFEITEMC10,   LIFEITEMC11,   LIFEITEMC12,
+              LIFEITEMC13,   LIFEITEMC14,   LIFEITEMC15,
+
+              LIFEITEMD01,   LIFEITEMD02,   LIFEITEMD03,   LIFEITEMD04,
+              LIFEITEMD05,   LIFEITEMD06,   LIFEITEMD07,   LIFEITEMD08,
+
+
+              RUBBLE1,RUBBLE2,RUBBLE3,RUBBLE4,RUBBLE5,RUBBLE6,RUBBLE7,
+              RUBBLE8,RUBBLE9,RUBBLE10,
+
+              WOODFRAG1,WOODFRAG2,WOODFRAG3,WOODFRAG4,WOODFRAG5,WOODFRAG6,
+              WOODFRAG7,WOODFRAG8,WOODFRAG9,WOODFRAG10,WOODFRAG11,WOODFRAG12,
+              WOODFRAG13,WOODFRAG14,
+
+
+
+              MISSMOKE1,MISSMOKE2,MISSMOKE3,MISSMOKE4,
+
+              SPR62_ETOUCH1, SPR63_ETOUCH2,	SPR64_ETOUCH3,
+
+              SPR73_GKEY1,   SPR74_GKEY2,   SPR75_GKEY3,   SPR76_GKEY4,
+              SPR77_GKEY5,   SPR78_GKEY6,   SPR79_GKEY7,   SPR80_GKEY8,
+              SPR81_GKEY9,   SPR82_GKEY10,  SPR83_GKEY11,  SPR84_GKEY12,
+              SPR85_GKEY13,  SPR86_GKEY14,  SPR87_GKEY15,  SPR88_GKEY16,
+
+
+              SPR6_GIBS1,    SPR7_GIBS2,	   SPR8_GIBS3,    SPR33_CBARREL,
+              SPR34_TOUCH1,  SPR35_TOUCH2,  SPR36_TOUCH3,	SPR37_TOUCH4,
+              SPR40_GARBAGE3,SPR41_SHIT,    BLUEVASE,   SPR54_HAY,
+              BULLETHOLE,    ALTBULLETHO,
+              STNPOLE1,      STNPOLE2,      STNPOLE3,      STNPOLE4,
+              STNPOLE5,      STNPOLE6,      STNPOLE7,      STNPOLE8,
+
+
+              HGRATE1,       HGRATE2,       HGRATE3,
+              HGRATE4,
+
+              SPR0_YLIGHT,   SPR1_RLIGHT,   SPR2_GLIGHT,
+              SPR3_BLIGHT,	SPR4_CHAND,    SPR5_LAMPOFF, 	SPR5_LAMP,
+              SPR9_MONKMEAL, SPR_ABRAZIEROFF, SPR_ABRAZIER2,
+              SPR32_EXPLOS,  SPR38_GARBAGE1,SPR39_GARBAGE2,
+              SPR42_GRATE,   SPR43_MSHARDS, SPR44_PEDESTAL,SPR45_ETABLE,
+              SPR46_STOOL,   SPR50_TREE,    SPR51_PLANT,
+              SPR55_IBARREL, FBASIN1,       FBASIN2,       FBASIN3,
+              EBASIN,		   PORRIDGE1,     PORRIDGE2,     PORRIDGE3,
+              PORRIDGE4,	   PORRIDGE5,     PORRIDGE6,		MONKCRYSTAL11,
+              MONKCRYSTAL12, MONKCRYSTAL13, MONKCRYSTAL14,	MONKCRYSTAL15,
+              MONKCRYSTAL16, MONKCRYSTAL21,
+              MONKCRYSTAL22, MONKCRYSTAL23, MONKCRYSTAL24, MONKCRYSTAL25,
+              MONKCRYSTAL26, MONKCRYSTAL27, TORCH1,
+              TORCH2,        TORCH3,        TORCH4,		   TORCH5,
+              TORCH6,        TORCH7,        TORCH8,		   TORCH9,
+              TORCH10,       TORCH11,       TORCH12,		   TORCH13,
+              TORCH14,       TORCH15,
+
+              /*
+              ATORCH2,       ATORCH3,
+              ATORCH4,		   ATORCH5,       ATORCH6,       ATORCH7,
+              ATORCH8,		   ATORCH9,       ATORCH10,      ATORCH11,
+              ATORCH12,		ATORCH13,		ATORCH14,      ATORCH15,
+              ATORCH16,
+              */
+
+              FFLAME1,
+              FFLAME2,       FFLAME3,       FFLAME4,		   FFLAME5,
+              FFLAME6,       FFLAME7,       SPR_TWOPIST,   SPR_MP40,
+              SPR_BAZOOKA,   SPR_FIREBOMB,	SPR_HEATSEEK,  SPR_DRUNK,
+              SPR_FIREWALL,  SPR_KES,       SPR_SPLIT,
+
+
+
+              GASMASKPOWERUP,
+              BULLETPROOFPOWERUP, ASBESTOSPOWERUP,PREPIT,POSTPIT,
+
+
+              CASSATT_SHOOT11,CASSATT_SHOOT12,CASSATT_SHOOT13,CASSATT_SHOOT14,
+              CASSATT_SHOOT15,CASSATT_SHOOT16,CASSATT_SHOOT17,CASSATT_SHOOT18,
+
+              CASSATT_SHOOT21,CASSATT_SHOOT22,CASSATT_SHOOT23,CASSATT_SHOOT24,
+              CASSATT_SHOOT25,CASSATT_SHOOT26,CASSATT_SHOOT27,CASSATT_SHOOT28,
+
+
+
+              CASSATTM_SHOOT11,CASSATTM_SHOOT12,CASSATTM_SHOOT13,CASSATTM_SHOOT14,
+              CASSATTM_SHOOT15,CASSATTM_SHOOT16,CASSATTM_SHOOT17,CASSATTM_SHOOT18,
+
+              CASSATTM_SHOOT21,CASSATTM_SHOOT22,CASSATTM_SHOOT23,CASSATTM_SHOOT24,
+              CASSATTM_SHOOT25,CASSATTM_SHOOT26,CASSATTM_SHOOT27,CASSATTM_SHOOT28,
+
+
+
+              CASSATT_S1,CASSATT_S2,CASSATT_S3,CASSATT_S4,
+              CASSATT_S5,CASSATT_S6,CASSATT_S7,CASSATT_S8,
+
+              CASSATT_W11,CASSATT_W12,CASSATT_W13,CASSATT_W14,
+              CASSATT_W15,CASSATT_W16,CASSATT_W17,CASSATT_W18,
+
+              CASSATT_W21,CASSATT_W22,CASSATT_W23,CASSATT_W24,
+              CASSATT_W25,CASSATT_W26,CASSATT_W27,CASSATT_W28,
+
+              CASSATT_W31,CASSATT_W32,CASSATT_W33,CASSATT_W34,
+              CASSATT_W35,CASSATT_W36,CASSATT_W37,CASSATT_W38,
+
+              CASSATT_W41,CASSATT_W42,CASSATT_W43,CASSATT_W44,
+              CASSATT_W45,CASSATT_W46,CASSATT_W47,CASSATT_W48,
+
+
+              CASSATT_VDIE1,CASSATT_VDIE2,CASSATT_VDIE3,CASSATT_VDIE4,CASSATT_VDIE5,
+              CASSATT_VDIE6,
+              CASSATT_VDEAD,
+
+              CASSATT_DIE1,CASSATT_DIE2,CASSATT_DIE3,CASSATT_DIE4,CASSATT_DIE5,
+              CASSATT_DIE6,
+              CASSATT_DEAD,
+
+
+// DDOI - Wad ends here
+
+              BARRETT_SHOOT11,BARRETT_SHOOT12,BARRETT_SHOOT13,BARRETT_SHOOT14,
+              BARRETT_SHOOT15,BARRETT_SHOOT16,BARRETT_SHOOT17,BARRETT_SHOOT18,
+
+
+              BARRETT_SHOOT21,BARRETT_SHOOT22,BARRETT_SHOOT23,BARRETT_SHOOT24,
+              BARRETT_SHOOT25,BARRETT_SHOOT26,BARRETT_SHOOT27,BARRETT_SHOOT28,
+
+
+              BARRETTM_SHOOT11,BARRETTM_SHOOT12,BARRETTM_SHOOT13,BARRETTM_SHOOT14,
+              BARRETTM_SHOOT15,BARRETTM_SHOOT16,BARRETTM_SHOOT17,BARRETTM_SHOOT18,
+
+              BARRETTM_SHOOT21,BARRETTM_SHOOT22,BARRETTM_SHOOT23,BARRETTM_SHOOT24,
+              BARRETTM_SHOOT25,BARRETTM_SHOOT26,BARRETTM_SHOOT27,BARRETTM_SHOOT28,
+
+
+
+              BARRETT_S1,BARRETT_S2,BARRETT_S3,BARRETT_S4,
+              BARRETT_S5,BARRETT_S6,BARRETT_S7,BARRETT_S8,
+
+              BARRETT_W11,BARRETT_W12,BARRETT_W13,BARRETT_W14,
+              BARRETT_W15,BARRETT_W16,BARRETT_W17,BARRETT_W18,
+
+              BARRETT_W21,BARRETT_W22,BARRETT_W23,BARRETT_W24,
+              BARRETT_W25,BARRETT_W26,BARRETT_W27,BARRETT_W28,
+
+              BARRETT_W31,BARRETT_W32,BARRETT_W33,BARRETT_W34,
+              BARRETT_W35,BARRETT_W36,BARRETT_W37,BARRETT_W38,
+
+              BARRETT_W41,BARRETT_W42,BARRETT_W43,BARRETT_W44,
+              BARRETT_W45,BARRETT_W46,BARRETT_W47,BARRETT_W48,
+
+
+              BARRETT_VDIE1,BARRETT_VDIE2,BARRETT_VDIE3,BARRETT_VDIE4,BARRETT_VDIE5,
+              BARRETT_VDIE6,
+              BARRETT_VDEAD,
+
+              BARRETT_DIE1,BARRETT_DIE2,BARRETT_DIE3,BARRETT_DIE4,BARRETT_DIE5,
+              BARRETT_DIE6,
+              BARRETT_DEAD,
+
+
+
+              WENDT_SHOOT11,WENDT_SHOOT12,WENDT_SHOOT13,WENDT_SHOOT14,
+              WENDT_SHOOT15,WENDT_SHOOT16,WENDT_SHOOT17,WENDT_SHOOT18,
+
+              WENDT_SHOOT21,WENDT_SHOOT22,WENDT_SHOOT23,WENDT_SHOOT24,
+              WENDT_SHOOT25,WENDT_SHOOT26,WENDT_SHOOT27,WENDT_SHOOT28,
+
+
+
+              WENDTM_SHOOT11,WENDTM_SHOOT12,WENDTM_SHOOT13,WENDTM_SHOOT14,
+              WENDTM_SHOOT15,WENDTM_SHOOT16,WENDTM_SHOOT17,WENDTM_SHOOT18,
+
+              WENDTM_SHOOT21,WENDTM_SHOOT22,WENDTM_SHOOT23,WENDTM_SHOOT24,
+              WENDTM_SHOOT25,WENDTM_SHOOT26,WENDTM_SHOOT27,WENDTM_SHOOT28,
+
+
+
+              WENDT_S1,WENDT_S2,WENDT_S3,WENDT_S4,
+              WENDT_S5,WENDT_S6,WENDT_S7,WENDT_S8,
+
+              WENDT_W11,WENDT_W12,WENDT_W13,WENDT_W14,
+              WENDT_W15,WENDT_W16,WENDT_W17,WENDT_W18,
+
+              WENDT_W21,WENDT_W22,WENDT_W23,WENDT_W24,
+              WENDT_W25,WENDT_W26,WENDT_W27,WENDT_W28,
+
+              WENDT_W31,WENDT_W32,WENDT_W33,WENDT_W34,
+              WENDT_W35,WENDT_W36,WENDT_W37,WENDT_W38,
+
+              WENDT_W41,WENDT_W42,WENDT_W43,WENDT_W44,
+              WENDT_W45,WENDT_W46,WENDT_W47,WENDT_W48,
+
+
+              WENDT_VDIE1,WENDT_VDIE2,WENDT_VDIE3,WENDT_VDIE4,WENDT_VDIE5,WENDT_VDIE6,
+              WENDT_VDEAD,
+
+              WENDT_DIE1,WENDT_DIE2,WENDT_DIE3,WENDT_DIE4,WENDT_DIE5,WENDT_DIE6,
+              WENDT_DEAD,
+
+
+//======
+
+
+              NI_SHOOT11,NI_SHOOT12,NI_SHOOT13,NI_SHOOT14,
+              NI_SHOOT15,NI_SHOOT16,NI_SHOOT17,NI_SHOOT18,
+
+              NI_SHOOT21,NI_SHOOT22,NI_SHOOT23,NI_SHOOT24,
+              NI_SHOOT25,NI_SHOOT26,NI_SHOOT27,NI_SHOOT28,
+
+
+
+              NIM_SHOOT11,NIM_SHOOT12,NIM_SHOOT13,NIM_SHOOT14,
+              NIM_SHOOT15,NIM_SHOOT16,NIM_SHOOT17,NIM_SHOOT18,
+
+              NIM_SHOOT21,NIM_SHOOT22,NIM_SHOOT23,NIM_SHOOT24,
+              NIM_SHOOT25,NIM_SHOOT26,NIM_SHOOT27,NIM_SHOOT28,
+
+
+
+              NI_S1,NI_S2,NI_S3,NI_S4,
+              NI_S5,NI_S6,NI_S7,NI_S8,
+
+              NI_W11,NI_W12,NI_W13,NI_W14,
+              NI_W15,NI_W16,NI_W17,NI_W18,
+
+              NI_W21,NI_W22,NI_W23,NI_W24,
+              NI_W25,NI_W26,NI_W27,NI_W28,
+
+              NI_W31,NI_W32,NI_W33,NI_W34,
+              NI_W35,NI_W36,NI_W37,NI_W38,
+
+              NI_W41,NI_W42,NI_W43,NI_W44,
+              NI_W45,NI_W46,NI_W47,NI_W48,
+
+
+              NI_VDIE1,NI_VDIE2,NI_VDIE3,NI_VDIE4,NI_VDIE5,NI_VDIE6,
+              NI_VDEAD,
+
+              NI_DIE1,NI_DIE2,NI_DIE3,NI_DIE4,NI_DIE5,NI_DIE6,
+              NI_DEAD,
+
+
+
+
+              IPF_SHOOT11,IPF_SHOOT12,IPF_SHOOT13,IPF_SHOOT14,
+              IPF_SHOOT15,IPF_SHOOT16,IPF_SHOOT17,IPF_SHOOT18,
+
+              IPF_SHOOT21,IPF_SHOOT22,IPF_SHOOT23,IPF_SHOOT24,
+              IPF_SHOOT25,IPF_SHOOT26,IPF_SHOOT27,IPF_SHOOT28,
+
+
+              IPFM_SHOOT11,IPFM_SHOOT12,IPFM_SHOOT13,IPFM_SHOOT14,
+              IPFM_SHOOT15,IPFM_SHOOT16,IPFM_SHOOT17,IPFM_SHOOT18,
+
+              IPFM_SHOOT21,IPFM_SHOOT22,IPFM_SHOOT23,IPFM_SHOOT24,
+              IPFM_SHOOT25,IPFM_SHOOT26,IPFM_SHOOT27,IPFM_SHOOT28,
+
+
+
+              IPF_S1,IPF_S2,IPF_S3,IPF_S4,
+              IPF_S5,IPF_S6,IPF_S7,IPF_S8,
+
+              IPF_W11,IPF_W12,IPF_W13,IPF_W14,
+              IPF_W15,IPF_W16,IPF_W17,IPF_W18,
+
+              IPF_W21,IPF_W22,IPF_W23,IPF_W24,
+              IPF_W25,IPF_W26,IPF_W27,IPF_W28,
+
+              IPF_W31,IPF_W32,IPF_W33,IPF_W34,
+              IPF_W35,IPF_W36,IPF_W37,IPF_W38,
+
+              IPF_W41,IPF_W42,IPF_W43,IPF_W44,
+              IPF_W45,IPF_W46,IPF_W47,IPF_W48,
+
+
+              IPF_VDIE1,IPF_VDIE2,IPF_VDIE3,IPF_VDIE4,IPF_VDIE5,IPF_VDIE6,
+              IPF_VDEAD,
+
+              IPF_DIE1,IPF_DIE2,IPF_DIE3,IPF_DIE4,IPF_DIE5,IPF_DIE6,
+              IPF_DEAD,
+
+
+              SERIALDOG_W11,SERIALDOG_W12,SERIALDOG_W13,SERIALDOG_W14,
+              SERIALDOG_W15,SERIALDOG_W16,SERIALDOG_W17,SERIALDOG_W18,
+
+              SERIALDOG_W21,SERIALDOG_W22,SERIALDOG_W23,SERIALDOG_W24,
+              SERIALDOG_W25,SERIALDOG_W26,SERIALDOG_W27,SERIALDOG_W28,
+
+              SERIALDOG_W31,SERIALDOG_W32,SERIALDOG_W33,SERIALDOG_W34,
+              SERIALDOG_W35,SERIALDOG_W36,SERIALDOG_W37,SERIALDOG_W38,
+
+              SERIALDOG_W41,SERIALDOG_W42,SERIALDOG_W43,SERIALDOG_W44,
+              SERIALDOG_W45,SERIALDOG_W46,SERIALDOG_W47,SERIALDOG_W48,
+
+              SERIALDOG_ATTACK1,SERIALDOG_ATTACK2,SERIALDOG_ATTACK3,SERIALDOG_ATTACK4,
+              SERIALDOG_ATTACK5,SERIALDOG_ATTACK6,SERIALDOG_ATTACK7,SERIALDOG_ATTACK8,
+
+
+              /***************   Lowguard 2 (Marianna)  *************************************/
+
+
+              /*
+              SPR_MARIANNA_SHOOT1,SPR_MARIANNA_SHOOT2,SPR_MARIANNA_SHOOT3,SPR_MARIANNA_SHOOT4,
+
+              SPR_MARIANNA_S1,SPR_MARIANNA_S2,SPR_MARIANNA_S3,SPR_MARIANNA_S4,
+              SPR_MARIANNA_S5,SPR_MARIANNA_S6,SPR_MARIANNA_S7,SPR_MARIANNA_S8,
+
+              SPR_MARIANNA_W11,SPR_MARIANNA_W12,SPR_MARIANNA_W13,SPR_MARIANNA_W14,
+              SPR_MARIANNA_W15,SPR_MARIANNA_W16,SPR_MARIANNA_W17,SPR_MARIANNA_W18,
+
+              SPR_MARIANNA_W21,SPR_MARIANNA_W22,SPR_MARIANNA_W23,SPR_MARIANNA_W24,
+              SPR_MARIANNA_W25,SPR_MARIANNA_W26,SPR_MARIANNA_W27,SPR_MARIANNA_W28,
+
+              SPR_MARIANNA_W31,SPR_MARIANNA_W32,SPR_MARIANNA_W33,SPR_MARIANNA_W34,
+              SPR_MARIANNA_W35,SPR_MARIANNA_W36,SPR_MARIANNA_W37,SPR_MARIANNA_W38,
+
+              SPR_MARIANNA_W41,SPR_MARIANNA_W42,SPR_MARIANNA_W43,SPR_MARIANNA_W44,
+              SPR_MARIANNA_W45,SPR_MARIANNA_W46,SPR_MARIANNA_W47,SPR_MARIANNA_W48,
+
+
+              SPR_MARIANNA_PAIN1, SPR_MARIANNA_PAIN2, SPR_MARIANNA_DIE1, SPR_MARIANNA_DIE2,
+              SPR_MARIANNA_DIE3, SPR_MARIANNA_DIE4, SPR_MARIANNA_DEAD,
+
+              SPR_MARIANNA_WPAIN1, SPR_MARIANNA_WPAIN2, SPR_MARIANNA_WDIE1, SPR_MARIANNA_WDIE2,
+              SPR_MARIANNA_WDIE3, SPR_MARIANNA_WDIE4, SPR_MARIANNA_WDEAD,
+
+
+              SPR_SNMAR_DEAD, SPR_MARISE1, SPR_MARISE2, SPR_MARISE3, SPR_MARISE4,
+              */
+
+
+              /****************** OBERPATROLLE (Nolan) ***********************************/
+
+
+              SPR_OP_SHOOT1,SPR_OP_SHOOT2,SPR_OP_SHOOT3,SPR_OP_SHOOT4,
+
+              SPR_OP_BOLOSHOOT1,SPR_OP_BOLOSHOOT2,SPR_OP_BOLOSHOOT3,SPR_OP_BOLOSHOOT4,
+              SPR_OP_BOLOSHOOT5,
+
+              SPR_OP_S1,SPR_OP_S2,SPR_OP_S3,SPR_OP_S4,
+              SPR_OP_S5,SPR_OP_S6,SPR_OP_S7,SPR_OP_S8,
+
+              SPR_OP_W11,SPR_OP_W12,SPR_OP_W13,SPR_OP_W14,
+              SPR_OP_W15,SPR_OP_W16,SPR_OP_W17,SPR_OP_W18,
+
+              SPR_OP_W21,SPR_OP_W22,SPR_OP_W23,SPR_OP_W24,
+              SPR_OP_W25,SPR_OP_W26,SPR_OP_W27,SPR_OP_W28,
+
+              SPR_OP_W31,SPR_OP_W32,SPR_OP_W33,SPR_OP_W34,
+              SPR_OP_W35,SPR_OP_W36,SPR_OP_W37,SPR_OP_W38,
+
+              SPR_OP_W41,SPR_OP_W42,SPR_OP_W43,SPR_OP_W44,
+              SPR_OP_W45,SPR_OP_W46,SPR_OP_W47,SPR_OP_W48,
+
+
+              SPR_OP_PAIN1,SPR_OP_PAIN2,
+              SPR_OP_ALTDIE1,SPR_OP_ALTDIE2,SPR_OP_ALTDIE3,
+              SPR_OP_ALTDIE4,SPR_OP_ALTDIE5,SPR_OP_ALTDEAD,
+
+              SPR_OP_WPAIN1,SPR_OP_WPAIN2,
+              SPR_OP_WALTDIE1,SPR_OP_WALTDIE2,SPR_OP_WALTDIE3,
+              SPR_OP_WALTDIE4,SPR_OP_WALTDIE5,SPR_OP_WALTDEAD,
+
+              SPR_OP_DIE1,SPR_OP_DIE2,SPR_OP_DIE3,
+              SPR_OP_DIE4,SPR_OP_DIE5,SPR_OP_DIE6,
+              SPR_OP_DEAD,
+
+
+
+
+
+              /******************* Normal monk (Lee)**********************************/
+
+
+              SPR_MONK_DRAIN1,SPR_MONK_DRAIN2,SPR_MONK_DRAIN3,SPR_MONK_DRAIN4,
+              SPR_MONK_DRAIN5,SPR_MONK_DRAIN6,
+
+              /*SPR_MONK_CAST1,SPR_MONK_CAST2,SPR_MONK_CAST3,SPR_MONK_CAST4,
+              SPR_MONK_CAST5,SPR_MONK_CAST6,SPR_MONK_CAST7,SPR_MONK_CAST8,*/
+
+              SPR_MONK_S1,SPR_MONK_S2,SPR_MONK_S3,SPR_MONK_S4,
+              SPR_MONK_S5,SPR_MONK_S6,SPR_MONK_S7,SPR_MONK_S8,
+
+              SPR_MONK_W11,SPR_MONK_W12,SPR_MONK_W13,SPR_MONK_W14,
+              SPR_MONK_W15,SPR_MONK_W16,SPR_MONK_W17,SPR_MONK_W18,
+
+              SPR_MONK_W21,SPR_MONK_W22,SPR_MONK_W23,SPR_MONK_W24,
+              SPR_MONK_W25,SPR_MONK_W26,SPR_MONK_W27,SPR_MONK_W28,
+
+              SPR_MONK_W31,SPR_MONK_W32,SPR_MONK_W33,SPR_MONK_W34,
+              SPR_MONK_W35,SPR_MONK_W36,SPR_MONK_W37,SPR_MONK_W38,
+
+              SPR_MONK_W41,SPR_MONK_W42,SPR_MONK_W43,SPR_MONK_W44,
+              SPR_MONK_W45,SPR_MONK_W46,SPR_MONK_W47,SPR_MONK_W48,
+
+              SPR_MONK_PAIN1,SPR_MONK_PAIN2,
+
+              SPR_MONK_DIE1,SPR_MONK_DIE2,SPR_MONK_DIE3,SPR_MONK_DIE4,
+              SPR_MONK_DEAD,
+
+              /*SPR_MONK_USE11,SPR_MONK_USE12,SPR_MONK_USE13,SPR_MONK_USE14,
+              SPR_MONK_USE15,SPR_MONK_USE16,SPR_MONK_USE17,SPR_MONK_USE18,
+
+              SPR_MONK_USE21,SPR_MONK_USE22,SPR_MONK_USE23,SPR_MONK_USE24,
+              SPR_MONK_USE25,SPR_MONK_USE26,SPR_MONK_USE27,SPR_MONK_USE28,
+              */
+
+
+              /******************* Fire monk (Allen)**********************************/
+
+              SPR_FIREMONK_CAST1,SPR_FIREMONK_CAST2,SPR_FIREMONK_CAST3,SPR_FIREMONK_CAST4,
+              SPR_FIREMONK_CAST5,SPR_FIREMONK_CAST6,SPR_FIREMONK_CAST7,
+
+              SPR_FIREMONK_S1,SPR_FIREMONK_S2,SPR_FIREMONK_S3,SPR_FIREMONK_S4,
+              SPR_FIREMONK_S5,SPR_FIREMONK_S6,SPR_FIREMONK_S7,SPR_FIREMONK_S8,
+
+              SPR_FIREMONK_W11,SPR_FIREMONK_W12,SPR_FIREMONK_W13,SPR_FIREMONK_W14,
+              SPR_FIREMONK_W15,SPR_FIREMONK_W16,SPR_FIREMONK_W17,SPR_FIREMONK_W18,
+
+              SPR_FIREMONK_W21,SPR_FIREMONK_W22,SPR_FIREMONK_W23,SPR_FIREMONK_W24,
+              SPR_FIREMONK_W25,SPR_FIREMONK_W26,SPR_FIREMONK_W27,SPR_FIREMONK_W28,
+
+              SPR_FIREMONK_W31,SPR_FIREMONK_W32,SPR_FIREMONK_W33,SPR_FIREMONK_W34,
+              SPR_FIREMONK_W35,SPR_FIREMONK_W36,SPR_FIREMONK_W37,SPR_FIREMONK_W38,
+
+              SPR_FIREMONK_W41,SPR_FIREMONK_W42,SPR_FIREMONK_W43,SPR_FIREMONK_W44,
+              SPR_FIREMONK_W45,SPR_FIREMONK_W46,SPR_FIREMONK_W47,SPR_FIREMONK_W48,
+
+              SPR_FIREMONK_PAIN1,SPR_FIREMONK_PAIN2,
+
+              SPR_FIREMONK_DIE1,SPR_FIREMONK_DIE2,SPR_FIREMONK_DIE3,SPR_FIREMONK_DIE4,
+              SPR_FIREMONK_DEAD1,SPR_FIREMONK_DEAD2,SPR_FIREMONK_DEAD3,SPR_FIREMONK_DEAD4,
+              SPR_FIREMONK_DEAD5,SPR_FIREMONK_DEAD6,SPR_FIREMONK_DEAD7,
+
+
+
+              /*
+              SPR_ALLEN_USE11,SPR_ALLEN_USE12,SPR_ALLEN_USE13,SPR_ALLEN_USE14,
+              SPR_ALLEN_USE15,SPR_ALLEN_USE16,SPR_ALLEN_USE17,SPR_ALLEN_USE18,
+
+              SPR_ALLEN_USE21,SPR_ALLEN_USE22,SPR_ALLEN_USE23,SPR_ALLEN_USE24,
+              SPR_ALLEN_USE25,SPR_ALLEN_USE26,SPR_ALLEN_USE27,SPR_ALLEN_USE28,
+              */
+              BCRAFT01,BCRAFT02,BCRAFT03,BCRAFT04,
+              BCRAFT05,BCRAFT06,BCRAFT07,BCRAFT08,
+              BCRAFT09,BCRAFT10,BCRAFT11,BCRAFT12,
+              BCRAFT13,BCRAFT14,BCRAFT15,BCRAFT16,
+
+
+              /************************* GENERAL DARIAN *******************************/
+
+
+              SPR_DARIAN_SHOOT1,SPR_DARIAN_SHOOT2,SPR_DARIAN_SHOOT3,SPR_DARIAN_SHOOT4,
+
+              SPR_DARIAN_SINK1,SPR_DARIAN_SINK2,SPR_DARIAN_SINK3,SPR_DARIAN_SINK4,
+              SPR_DARIAN_SINK5,SPR_DARIAN_SINK6,SPR_DARIAN_SINK7,SPR_DARIAN_SINK8,
+
+
+              SPR_DARIAN_S1,SPR_DARIAN_S2,SPR_DARIAN_S3,SPR_DARIAN_S4,
+              SPR_DARIAN_S5,SPR_DARIAN_S6,SPR_DARIAN_S7,SPR_DARIAN_S8,
+
+              SPR_DARIAN_W11,SPR_DARIAN_W12,SPR_DARIAN_W13,SPR_DARIAN_W14,
+              SPR_DARIAN_W15,SPR_DARIAN_W16,SPR_DARIAN_W17,SPR_DARIAN_W18,
+
+              SPR_DARIAN_W21,SPR_DARIAN_W22,SPR_DARIAN_W23,SPR_DARIAN_W24,
+              SPR_DARIAN_W25,SPR_DARIAN_W26,SPR_DARIAN_W27,SPR_DARIAN_W28,
+
+              SPR_DARIAN_W31,SPR_DARIAN_W32,SPR_DARIAN_W33,SPR_DARIAN_W34,
+              SPR_DARIAN_W35,SPR_DARIAN_W36,SPR_DARIAN_W37,SPR_DARIAN_W38,
+
+              SPR_DARIAN_W41,SPR_DARIAN_W42,SPR_DARIAN_W43,SPR_DARIAN_W44,
+              SPR_DARIAN_W45,SPR_DARIAN_W46,SPR_DARIAN_W47,SPR_DARIAN_W48,
+
+
+              SPR_DARIAN_PAIN1, SPR_DARIAN_PAIN2, SPR_DARIAN_DIE1, SPR_DARIAN_DIE2,
+              SPR_DARIAN_DIE3, SPR_DARIAN_DIE4,SPR_DARIAN_DIE5, SPR_DARIAN_DIE6,
+              SPR_DARIAN_DIE7, SPR_DARIAN_DIE8,SPR_DARIAN_DIE9, SPR_DARIAN_DIE10,
+              SPR_DARIAN_DEAD,
+
+              SPR_DARIAN_WPAIN1, SPR_DARIAN_WPAIN2, SPR_WDARIAN_DIE1, SPR_WDARIAN_DIE2,
+              SPR_DARIAN_WDIE3, SPR_DARIAN_WDIE4,SPR_WDARIAN_DIE5, SPR_WDARIAN_DIE6,
+              SPR_DARIAN_WDIE7, SPR_DARIAN_WDIE8,SPR_WDARIAN_DIE9, SPR_WDARIAN_DIE10,
+              SPR_DARIAN_WDEAD,
+
+
+              SPR_DARIAN_USE11,SPR_DARIAN_USE12,SPR_DARIAN_USE13,SPR_DARIAN_USE14,
+              SPR_DARIAN_USE15,SPR_DARIAN_USE16,SPR_DARIAN_USE17,SPR_DARIAN_USE18,
+
+              SPR_DARIAN_USE21,SPR_DARIAN_USE22,SPR_DARIAN_USE23,SPR_DARIAN_USE24,
+              SPR_DARIAN_USE25,SPR_DARIAN_USE26,SPR_DARIAN_USE27,SPR_DARIAN_USE28,
+
+
+
+              /************************* HEINRICH KRIST ******************************/
+
+
+              SPR_KRIST_S1,SPR_KRIST_S2,SPR_KRIST_S3,SPR_KRIST_S4,
+              SPR_KRIST_S5,SPR_KRIST_S6,SPR_KRIST_S7,SPR_KRIST_S8,
+
+              SPR_KRIST_LEFT1,SPR_KRIST_LEFT2,SPR_KRIST_LEFT3,SPR_KRIST_LEFT4,
+              SPR_KRIST_LEFT5,SPR_KRIST_LEFT6,SPR_KRIST_LEFT7,SPR_KRIST_LEFT8,
+
+
+              SPR_KRIST_SHOOT1,SPR_KRIST_SHOOT2,SPR_KRIST_SHOOT3,SPR_KRIST_SHOOT4,
+              SPR_KRIST_SHOOT5,SPR_KRIST_SHOOT6,SPR_KRIST_SHOOT7,SPR_KRIST_SHOOT8,
+              SPR_KRIST_SHOOT9,SPR_KRIST_SHOOT10,SPR_KRIST_SHOOT11,
+
+//SPR_KRIST_PAIN1,SPR_KRIST_PAIN2,SPR_KRIST_PAIN3,SPR_KRIST_PAIN4,
+//SPR_KRIST_PAIN5,SPR_KRIST_PAIN6,SPR_KRIST_PAIN7,SPR_KRIST_PAIN8,
+
+              SPR_KRIST_DIE1,SPR_KRIST_DIE2,SPR_KRIST_DEAD1,SPR_KRIST_DEAD2,
+              SPR_KRIST_DEAD3,SPR_KRIST_DEAD4,SPR_KRIST_DEAD5,SPR_KRIST_DEAD6,
+              SPR_KRIST_DEAD7,SPR_KRIST_DEAD8,
+
+              SPR_KRIST_RIGHT1,SPR_KRIST_RIGHT2,SPR_KRIST_RIGHT3,SPR_KRIST_RIGHT4,
+              SPR_KRIST_RIGHT5,SPR_KRIST_RIGHT6,SPR_KRIST_RIGHT7,SPR_KRIST_RIGHT8,
+
+              SPR_KRIST_FOR1,SPR_KRIST_FOR2,SPR_KRIST_FOR3,SPR_KRIST_FOR4,
+              SPR_KRIST_FOR5,SPR_KRIST_FOR6,SPR_KRIST_FOR7,SPR_KRIST_FOR8,
+
+//SPR_KRIST_BACK1,SPR_KRIST_BACK2,SPR_KRIST_BACK3,SPR_KRIST_BACK4,
+//SPR_KRIST_BACK5,SPR_KRIST_BACK6,SPR_KRIST_BACK7,SPR_KRIST_BACK8,
+
+              SPR_KRIST_MINERIGHT1,SPR_KRIST_MINERIGHT2,SPR_KRIST_MINERIGHT3,SPR_KRIST_MINERIGHT4,
+              SPR_KRIST_MINERIGHT5,SPR_KRIST_MINERIGHT6,SPR_KRIST_MINERIGHT7,SPR_KRIST_MINERIGHT8,
+
+//SPR_KRIST_MINELEFT1,SPR_KRIST_MINELEFT2,SPR_KRIST_MINELEFT3,SPR_KRIST_MINELEFT4,
+//SPR_KRIST_MINELEFT5,SPR_KRIST_MINELEFT6,SPR_KRIST_MINELEFT7,SPR_KRIST_MINELEFT8,
+
+              SPR_KRIST_DOPE1,SPR_KRIST_DOPE2,SPR_KRIST_DOPE3,
+
+
+              /************************* NME  ******************************/
+
+              NMEHEAD1_01,NMEHEAD1_02,NMEHEAD1_03,NMEHEAD1_04,
+              NMEHEAD1_05,NMEHEAD1_06,NMEHEAD1_07,NMEHEAD1_08,
+              NMEHEAD1_09,NMEHEAD1_10,NMEHEAD1_11,NMEHEAD1_12,
+              NMEHEAD1_13,NMEHEAD1_14,NMEHEAD1_15,NMEHEAD1_16,
+
+              NMEHEAD2_01,NMEHEAD2_02,NMEHEAD2_03,NMEHEAD2_04,
+              NMEHEAD2_05,NMEHEAD2_06,NMEHEAD2_07,NMEHEAD2_08,
+              NMEHEAD2_09,NMEHEAD2_10,NMEHEAD2_11,NMEHEAD2_12,
+              NMEHEAD2_13,NMEHEAD2_14,NMEHEAD2_15,NMEHEAD2_16,
+
+              NMEBODY1_01,NMEBODY1_02,NMEBODY1_03,NMEBODY1_04,
+              NMEBODY1_05,NMEBODY1_06,NMEBODY1_07,NMEBODY1_08,
+              NMEBODY1_09,NMEBODY1_10,NMEBODY1_11,NMEBODY1_12,
+              NMEBODY1_13,NMEBODY1_14,NMEBODY1_15,NMEBODY1_16,
+
+              NMEBODY2_01,NMEBODY2_02,NMEBODY2_03,NMEBODY2_04,
+              NMEBODY2_05,NMEBODY2_06,NMEBODY2_07,NMEBODY2_08,
+              NMEBODY2_09,NMEBODY2_10,NMEBODY2_11,NMEBODY2_12,
+              NMEBODY2_13,NMEBODY2_14,NMEBODY2_15,NMEBODY2_16,
+
+              NMEBODY3_01,NMEBODY3_02,NMEBODY3_03,NMEBODY3_04,
+              NMEBODY3_05,NMEBODY3_06,NMEBODY3_07,NMEBODY3_08,
+              NMEBODY3_09,NMEBODY3_10,NMEBODY3_11,NMEBODY3_12,
+              NMEBODY3_13,NMEBODY3_14,NMEBODY3_15,NMEBODY3_16,
+
+              NMEBODY4_01,NMEBODY4_02,NMEBODY4_03,NMEBODY4_04,
+              NMEBODY4_05,NMEBODY4_06,NMEBODY4_07,NMEBODY4_08,
+              NMEBODY4_09,NMEBODY4_10,NMEBODY4_11,NMEBODY4_12,
+              NMEBODY4_13,NMEBODY4_14,NMEBODY4_15,NMEBODY4_16,
+
+              NMEWHEEL1_01,NMEWHEEL1_02,NMEWHEEL1_03,NMEWHEEL1_04,
+              NMEWHEEL1_05,NMEWHEEL1_06,NMEWHEEL1_07,NMEWHEEL1_08,
+              NMEWHEEL1_09,NMEWHEEL1_10,NMEWHEEL1_11,NMEWHEEL1_12,
+              NMEWHEEL1_13,NMEWHEEL1_14,NMEWHEEL1_15,NMEWHEEL1_16,
+
+              NMEWHEEL2_01,NMEWHEEL2_02,NMEWHEEL2_03,NMEWHEEL2_04,
+              NMEWHEEL2_05,NMEWHEEL2_06,NMEWHEEL2_07,NMEWHEEL2_08,
+              NMEWHEEL2_09,NMEWHEEL2_10,NMEWHEEL2_11,NMEWHEEL2_12,
+              NMEWHEEL2_13,NMEWHEEL2_14,NMEWHEEL2_15,NMEWHEEL2_16,
+
+              NMEWHEEL3_01,NMEWHEEL3_02,NMEWHEEL3_03,NMEWHEEL3_04,
+              NMEWHEEL3_05,NMEWHEEL3_06,NMEWHEEL3_07,NMEWHEEL3_08,
+              NMEWHEEL3_09,NMEWHEEL3_10,NMEWHEEL3_11,NMEWHEEL3_12,
+              NMEWHEEL3_13,NMEWHEEL3_14,NMEWHEEL3_15,NMEWHEEL3_16,
+
+              NMEWHEEL4_01,NMEWHEEL4_02,NMEWHEEL4_03,NMEWHEEL4_04,
+              NMEWHEEL4_05,NMEWHEEL4_06,NMEWHEEL4_07,NMEWHEEL4_08,
+              NMEWHEEL4_09,NMEWHEEL4_10,NMEWHEEL4_11,NMEWHEEL4_12,
+              NMEWHEEL4_13,NMEWHEEL4_14,NMEWHEEL4_15,NMEWHEEL4_16,
+
+              NMEWHEEL5_01,NMEWHEEL5_02,NMEWHEEL5_03,NMEWHEEL5_04,
+              NMEWHEEL5_05,NMEWHEEL5_06,NMEWHEEL5_07,NMEWHEEL5_08,
+              NMEWHEEL5_09,NMEWHEEL5_10,NMEWHEEL5_11,NMEWHEEL5_12,
+              NMEWHEEL5_13,NMEWHEEL5_14,NMEWHEEL5_15,NMEWHEEL5_16,
+
+              NMEROCKET_01,NMEROCKET_02,NMEROCKET_03,NMEROCKET_04,
+              NMEROCKET_05,NMEROCKET_06,NMEROCKET_07,NMEROCKET_08,
+              NMEROCKET_09,NMEROCKET_10,NMEROCKET_11,NMEROCKET_12,
+              NMEROCKET_13,NMEROCKET_14,NMEROCKET_15,NMEROCKET_16,
+
+              NMEROCKET2_01,NMEROCKET2_02,NMEROCKET2_03,NMEROCKET2_04,
+              NMEROCKET2_05,NMEROCKET2_06,NMEROCKET2_07,NMEROCKET2_08,
+              NMEROCKET2_09,NMEROCKET2_10,NMEROCKET2_11,NMEROCKET2_12,
+              NMEROCKET2_13,NMEROCKET2_14,NMEROCKET2_15,NMEROCKET2_16,
+
+              NMEMINIBALL_01,NMEMINIBALL_02,NMEMINIBALL_03,NMEMINIBALL_04,
+              NMESAUCER_01,NMESAUCER_02,NMESAUCER_03,NMESAUCER_04,
+
+
+              /************************** TOM ****************************************/
+
+              TOMS1,TOMS2,TOMS3,TOMS4,TOMS5,TOMS6,TOMS7,TOMS8,
+
+              TOMFLY11,TOMFLY12,TOMFLY13,TOMFLY14,
+              TOMFLY15,TOMFLY16,TOMFLY17,TOMFLY18,
+
+              TOMFLY21,TOMFLY22,TOMFLY23,TOMFLY24,
+              TOMFLY25,TOMFLY26,TOMFLY27,TOMFLY28,
+
+              TOMLG1,TOMLG2,TOMLG3,TOMLG4,
+              TOMLG5,TOMLG6,TOMLG7,TOMLG8,
+
+              TOMLG9,TOMLG10,TOMLG11,
+
+              TOMFS1,TOMFS2,TOMFS3,TOMFS4,
+              TOMFS5,TOMFS6,
+
+              TOMBR1,TOMBR2,TOMBR3,TOMBR4,
+              TOMBR5,TOMBR6,TOMBR7,TOMBR8,
+
+              TOMHEAD1,TOMHEAD2,TOMHEAD3,TOMHEAD4,
+              TOMHEAD5,TOMHEAD6,TOMHEAD7,TOMHEAD8,
+
+              TPREPARE,
+              THDIE1,
+              THDIE2,
+              TAWAKEN1,TAWAKEN2,TAWAKEN3,TAWAKEN4,
+              TAWAKEN5,
+
+              THBALL1,THBALL2,THBALL3,THBALL4,
+              THBALL5,THBALL6,THBALL7,THBALL8,
+              THBALL9,
+
+              TSPHERE1,TSPHERE2,TSPHERE3,TSPHERE4,
+              TSPHERE5,TSPHERE6,TSPHERE7,TSPHERE8,
+              TSPHERE9,TSPHERE10,
+
+              TBBALL1,TBBALL2,TBBALL3,TBBALL4,
+              TBBALL5,TBBALL6,TBBALL7,TBBALL8,
+              TBBALL9,
+
+              TSCAREB1,TSCAREB2,TSCAREB3,TSCAREB4,
+              TSCAREB5,
+
+              TOMDIE1,TOMDIE2,TOMDIE3,TOMDIE4,
+              TOMDIE5,TOMDIE6,TOMDIE7,TOMDIE8,
+
+              TOMRH1,TOMRH2,TOMRH3,TOMRH4,
+              TOMRH5,TOMRH6,TOMRH7,TOMRH8,
+
+              TOHRH1,TOHRH2,TOHRH3,TOHRH4,
+              TOHRH5,TOHRH6,TOHRH7,TOHRH8,
+
+
+
+
+              SPEARDOWN1,SPEARDOWN2,SPEARDOWN3,SPEARDOWN4,
+              SPEARDOWN5,SPEARDOWN6,SPEARDOWN7,SPEARDOWN8,
+              SPEARDOWN9,SPEARDOWN10,SPEARDOWN11,SPEARDOWN12,
+              SPEARDOWN13,SPEARDOWN14,SPEARDOWN15,SPEARDOWN16,
+
+
+              DBLADE1,DBLADE2,DBLADE3,DBLADE4,
+              DBLADE5,DBLADE6,DBLADE7,DBLADE8,
+              DBLADE9,//DBLADE10,DBLADE11,DBLADE12,
+//DBLADE13,DBLADE14,DBLADE15,DBLADE16,
+
+              FIREJETDOWN1,FIREJETDOWN2,FIREJETDOWN3,FIREJETDOWN4,
+              FIREJETDOWN5,FIREJETDOWN6,FIREJETDOWN7,FIREJETDOWN8,
+              FIREJETDOWN9,FIREJETDOWN10,FIREJETDOWN11,FIREJETDOWN12,
+              FIREJETDOWN13,FIREJETDOWN14,FIREJETDOWN15,FIREJETDOWN16,
+              FIREJETDOWN17,FIREJETDOWN18,FIREJETDOWN19,FIREJETDOWN20,
+              FIREJETDOWN21,FIREJETDOWN22,FIREJETDOWN23,
+
+
+              CRUSHUP1,CRUSHUP2,CRUSHUP3,CRUSHUP4,
+              CRUSHUP5,CRUSHUP6,CRUSHUP7,CRUSHUP8,
+
+
+
+              SPINUBLADE_01,SPINUBLADE_02,SPINUBLADE_03,SPINUBLADE_04,
+              SPINUBLADE_05,SPINUBLADE_06,SPINUBLADE_07,SPINUBLADE_08,
+
+              SPINUBLADE_09,SPINUBLADE_10,SPINUBLADE_11,SPINUBLADE_12,
+              SPINUBLADE_13,SPINUBLADE_14,SPINUBLADE_15,SPINUBLADE_16,
+
+
+
+
+              SPINDBLADE_01,SPINDBLADE_02,SPINDBLADE_03,SPINDBLADE_04,
+              SPINDBLADE_05,SPINDBLADE_06,SPINDBLADE_07,SPINDBLADE_08,
+
+              SPINDBLADE_09,SPINDBLADE_10,SPINDBLADE_11,SPINDBLADE_12,
+              SPINDBLADE_13,SPINDBLADE_14,SPINDBLADE_15,SPINDBLADE_16,
+
+
+
+              DIP11,DIP21,DIP31,
+              TOMLARVA1, TOMLARVA2, TOMLARVA3, TOMLARVA4,
+
+              SCOTHEAD1,SCOTHEAD2,SCOTHEAD3,SCOTHEAD4,
+              SCOTHEAD5,SCOTHEAD6,SCOTHEAD7,
+
+              KNIFE_STATUE1,KNIFE_STATUE2,KNIFE_STATUE3,KNIFE_STATUE4,
+              KNIFE_STATUE5,KNIFE_STATUE6,KNIFE_STATUE7,KNIFE_STATUE8,
+
+              EMPTY_STATUE1,EMPTY_STATUE2,EMPTY_STATUE3,EMPTY_STATUE4,
+              EMPTY_STATUE5,EMPTY_STATUE6,EMPTY_STATUE7,EMPTY_STATUE8,
+
+
+              BAT1,BAT2,BAT3,BAT4,
+              BAT5,BAT6,BAT7,BAT8,
+              BAT9,BAT10,BAT11,BAT12,
+              BAT13,BAT14,BAT15,BAT16,
+
+              DOGPOWERUP1,   DOGPOWERUP2,   DOGPOWERUP3, DOGPOWERUP4,
+              DOGPOWERUP5,   DOGPOWERUP6,   DOGPOWERUP7, DOGPOWERUP8,
+
+
+              THREEUP01,     THREEUP02,     THREEUP03,	THREEUP04,
+              THREEUP05,     THREEUP06,     THREEUP07,	THREEUP08,
+
+
+
+              BOULDER11,BOULDER21,BOULDER31,BOULDER41,
+
+              BDROP1,BDROP2,BDROP3,BDROP4,BDROP5,BDROP6,BDROP7,BDROP8,BDROP9,
+              BDROP10,BDROP11,
+
+              BSINK1,BSINK2,BSINK3,BSINK4,BSINK5,BSINK6,BSINK7,BSINK8,BSINK9,
+
+
+              GUNRISE11,GUNRISE12,GUNRISE13,GUNRISE14,
+              GUNRISE15,GUNRISE16,GUNRISE17,GUNRISE18,
+
+              GUNRISE21,GUNRISE22,GUNRISE23,GUNRISE24,
+              GUNRISE25,GUNRISE26,GUNRISE27,GUNRISE28,
+
+              GUNRISE31,GUNRISE32,GUNRISE33,GUNRISE34,
+              GUNRISE35,GUNRISE36,GUNRISE37,GUNRISE38,
+
+              GUNRISE41,GUNRISE42,GUNRISE43,GUNRISE44,
+              GUNRISE45,GUNRISE46,GUNRISE47,GUNRISE48,
+
+              GUNRISE51,GUNRISE52,GUNRISE53,GUNRISE54,
+              GUNRISE55,GUNRISE56,GUNRISE57,GUNRISE58,
+
+              GUNFIRE1,GUNFIRE2,GUNFIRE3,GUNFIRE4,
+              GUNFIRE5,GUNFIRE6,GUNFIRE7,GUNFIRE8,
+
+              GUNDEAD1,GUNDEAD2,
+
+
+              FOURWAY01,FOURWAY02,FOURWAY03,FOURWAY04,
+              FOURWAY05,FOURWAY06,FOURWAY07,FOURWAY08,
+              FOURWAYFIRE01,FOURWAYFIRE02,FOURWAYFIRE03,FOURWAYFIRE04,
+              FOURWAYFIRE05,FOURWAYFIRE06,FOURWAYFIRE07,FOURWAYFIRE08,
+
+
+
+
+              TOMLIGHTNING1,TOMLIGHTNING2,TOMLIGHTNING3,TOMLIGHTNING4,
+              TOMLIGHTNING5,TOMLIGHTNING6,TOMLIGHTNING7,TOMLIGHTNING8,
+
+              TOMSPHERE1,TOMSPHERE2,TOMSPHERE3,TOMSPHERE4,
+
+              TOMHANDBALL1,TOMHANDBALL2,
+
+              TOMFACEBALL1,TOMFACEBALL2,
+
+              TOMFLOORSPARK1,TOMFLOORSPARK2,TOMFLOORSPARK3,TOMFLOORSPARK4,
+
+
+              TOMSPIT1,TOMSPIT2,TOMSPIT3,TOMSPIT4,
+
+              SPITHIT1,SPITHIT2,SPITHIT3,SPITHIT4,
+
+
+
+              MONKFIRE1,MONKFIRE2,MONKFIRE3,MONKFIRE4,
+
+
+              BATBLAST1,BATBLAST2,BATBLAST3,BATBLAST4,
+
+              KESSPHERE1,KESSPHERE2,KESSPHERE3,KESSPHERE4,
+              KESSPHERE5,KESSPHERE6,KESSPHERE7,KESSPHERE8,
+
+              SPR_BOLO1,SPR_BOLO2,SPR_BOLO3,SPR_BOLO4,
+
+//MED
+              DOPE1,DOPE2,DOPE3,DOPE4,DOPE5,DOPE6,DOPE7,DOPE8,
+//CRUSHUP9,CRUSHUP10,CRUSHUP11,CRUSHUP12,
+//CRUSHUP13,CRUSHUP14,CRUSHUP15,CRUSHUP16,
+
+
+              /*****************  Highguard 2 (Steve H.)  ***************************************/
+
+
+              SPR_HIGHGRD2_SHOOT1,SPR_HIGHGRD2_SHOOT2,SPR_HIGHGRD2_SHOOT3,SPR_HIGHGRD2_SHOOT4,
+
+
+              SPR_HIGHGRD2_S1,SPR_HIGHGRD2_S2,SPR_HIGHGRD2_S3,SPR_HIGHGRD2_S4,
+              SPR_HIGHGRD2_S5,SPR_HIGHGRD2_S6,SPR_HIGHGRD2_S7,SPR_HIGHGRD2_S8,
+
+              SPR_HIGHGRD2_W11,SPR_HIGHGRD2_W12,SPR_HIGHGRD2_W13,SPR_HIGHGRD2_W14,
+              SPR_HIGHGRD2_W15,SPR_HIGHGRD2_W16,SPR_HIGHGRD2_W17,SPR_HIGHGRD2_W18,
+
+              SPR_HIGHGRD2_W21,SPR_HIGHGRD2_W22,SPR_HIGHGRD2_W23,SPR_HIGHGRD2_W24,
+              SPR_HIGHGRD2_W25,SPR_HIGHGRD2_W26,SPR_HIGHGRD2_W27,SPR_HIGHGRD2_W28,
+
+              SPR_HIGHGRD2_W31,SPR_HIGHGRD2_W32,SPR_HIGHGRD2_W33,SPR_HIGHGRD2_W34,
+              SPR_HIGHGRD2_W35,SPR_HIGHGRD2_W36,SPR_HIGHGRD2_W37,SPR_HIGHGRD2_W38,
+
+              SPR_HIGHGRD2_W41,SPR_HIGHGRD2_W42,SPR_HIGHGRD2_W43,SPR_HIGHGRD2_W44,
+              SPR_HIGHGRD2_W45,SPR_HIGHGRD2_W46,SPR_HIGHGRD2_W47,SPR_HIGHGRD2_W48,
+
+
+              SPR_HIGHGRD2_PAIN1,SPR_HIGHGRD2_PAIN2,
+              SPR_HIGHGRD2_DIE1,SPR_HIGHGRD2_DIE2,SPR_HIGHGRD2_DIE3,SPR_HIGHGRD2_DIE4,
+              SPR_HIGHGRD2_DIE5,SPR_HIGHGRD2_DEAD,
+
+              SPR_HIGHGRD2_WPAIN1,SPR_HIGHGRD2_WPAIN2,
+              SPR_HIGHGRD2_WDIE1,SPR_HIGHGRD2_WDIE2,SPR_HIGHGRD2_WDIE3,SPR_HIGHGRD2_WDIE4,
+              SPR_HIGHGRD2_WDIE5,SPR_HIGHGRD2_WDEAD,
+
+              /*
+              SPR_HIGHGRD2_USE11,SPR_HIGHGRD2_USE12,SPR_HIGHGRD2_USE13,SPR_HIGHGRD2_USE14,
+              SPR_HIGHGRD2_USE15,SPR_HIGHGRD2_USE16,SPR_HIGHGRD2_USE17,SPR_HIGHGRD2_USE18,
+
+              SPR_HIGHGRD2_USE21,SPR_HIGHGRD2_USE22,SPR_HIGHGRD2_USE23,SPR_HIGHGRD2_USE24,
+              SPR_HIGHGRD2_USE25,SPR_HIGHGRD2_USE26,SPR_HIGHGRD2_USE27,SPR_HIGHGRD2_USE28,
+              */
+
+
+              /****************** Alt. Overpatrol (Pat) ***********************************/
+
+              SPR_PAT_SHOOT1,SPR_PAT_SHOOT2,SPR_PAT_SHOOT3,SPR_PAT_SHOOT4,
+
+              SPR_PAT_BOLOSHOOT1,SPR_PAT_BOLOSHOOT2,SPR_PAT_BOLOSHOOT3,SPR_PAT_BOLOSHOOT4,
+              SPR_PAT_BOLOSHOOT5,
+
+              SPR_PAT_S1,SPR_PAT_S2,SPR_PAT_S3,SPR_PAT_S4,
+              SPR_PAT_S5,SPR_PAT_S6,SPR_PAT_S7,SPR_PAT_S8,
+
+              SPR_PAT_W11,SPR_PAT_W12,SPR_PAT_W13,SPR_PAT_W14,
+              SPR_PAT_W15,SPR_PAT_W16,SPR_PAT_W17,SPR_PAT_W18,
+
+              SPR_PAT_W21,SPR_PAT_W22,SPR_PAT_W23,SPR_PAT_W24,
+              SPR_PAT_W25,SPR_PAT_W26,SPR_PAT_W27,SPR_PAT_W28,
+
+              SPR_PAT_W31,SPR_PAT_W32,SPR_PAT_W33,SPR_PAT_W34,
+              SPR_PAT_W35,SPR_PAT_W36,SPR_PAT_W37,SPR_PAT_W38,
+
+              SPR_PAT_W41,SPR_PAT_W42,SPR_PAT_W43,SPR_PAT_W44,
+              SPR_PAT_W45,SPR_PAT_W46,SPR_PAT_W47,SPR_PAT_W48,
+
+
+              SPR_PAT_PAIN1,SPR_PAT_PAIN2,
+              SPR_PAT_ALTDIE1,SPR_PAT_ALTDIE2,SPR_PAT_ALTDIE3,
+              SPR_PAT_ALTDIE4,SPR_PAT_ALTDIE5,SPR_PAT_ALTDEAD,
+
+              SPR_PAT_WPAIN1,SPR_PAT_WPAIN2,
+              SPR_PAT_WALTDIE1,SPR_PAT_WALTDIE2,SPR_PAT_WALTDIE3,
+              SPR_PAT_WALTDIE4,SPR_PAT_WALTDIE5,SPR_PAT_WALTDEAD,
+
+              SPR_PAT_DIE1,SPR_PAT_DIE2,SPR_PAT_DIE3,
+              SPR_PAT_DIE4,SPR_PAT_DIE5,SPR_PAT_DIE6,
+              SPR_PAT_DEAD,
+
+
+              /******************** Alt. Lightning Guard (Ann) **********************************/
+
+
+              SPR_ANN_SHOOT1,SPR_ANN_SHOOT2,SPR_ANN_SHOOT3,SPR_ANN_SHOOT4,
+              SPR_ANN_KSHOOT1,SPR_ANN_KSHOOT2,SPR_ANN_KSHOOT3,
+
+
+              SPR_ANN_S1,SPR_ANN_S2,SPR_ANN_S3,SPR_ANN_S4,
+              SPR_ANN_S5,SPR_ANN_S6,SPR_ANN_S7,SPR_ANN_S8,
+
+              SPR_ANN_W11,SPR_ANN_W12,SPR_ANN_W13,SPR_ANN_W14,
+              SPR_ANN_W15,SPR_ANN_W16,SPR_ANN_W17,SPR_ANN_W18,
+
+              SPR_ANN_W21,SPR_ANN_W22,SPR_ANN_W23,SPR_ANN_W24,
+              SPR_ANN_W25,SPR_ANN_W26,SPR_ANN_W27,SPR_ANN_W28,
+
+              SPR_ANN_W31,SPR_ANN_W32,SPR_ANN_W33,SPR_ANN_W34,
+              SPR_ANN_W35,SPR_ANN_W36,SPR_ANN_W37,SPR_ANN_W38,
+
+              SPR_ANN_W41,SPR_ANN_W42,SPR_ANN_W43,SPR_ANN_W44,
+              SPR_ANN_W45,SPR_ANN_W46,SPR_ANN_W47,SPR_ANN_W48,
+
+
+              SPR_ANN_PAIN1,SPR_ANN_PAIN2,
+              SPR_ANN_DIE1,SPR_ANN_DIE2,SPR_ANN_DIE3,
+              SPR_ANN_DIE4,SPR_ANN_DEAD1,SPR_ANN_DEAD2,SPR_ANN_DEAD3,
+
+              SPR_ANN_WPAIN1,SPR_ANN_WPAIN2,
+              SPR_ANN_WDIE1,SPR_ANN_WDIE2,SPR_ANN_WDIE3,
+              SPR_ANN_WDIE4,SPR_ANN_WDEAD1,SPR_ANN_WDEAD2,SPR_ANN_WDEAD3,
+
+              SPR_ANN_RROLL1,SPR_ANN_RROLL2,SPR_ANN_RROLL3,SPR_ANN_RROLL4,
+              SPR_ANN_RROLL5,SPR_ANN_RROLL6,
+
+              SPR_ANN_LROLL1,SPR_ANN_LROLL2,SPR_ANN_LROLL3,SPR_ANN_LROLL4,
+              SPR_ANN_LROLL5,SPR_ANN_LROLL6,
+
+
+              /********************** Alt. Blitzguard (William) **********************************/
+
+
+              SPR_WILLIAM_SHOOT1,SPR_WILLIAM_SHOOT2,SPR_WILLIAM_SHOOT3,SPR_WILLIAM_SHOOT4,
+
+              SPR_WILLIAM_S1,SPR_WILLIAM_S2,SPR_WILLIAM_S3,SPR_WILLIAM_S4,
+              SPR_WILLIAM_S5,SPR_WILLIAM_S6,SPR_WILLIAM_S7,SPR_WILLIAM_S8,
+
+              SPR_WILLIAM_W11,SPR_WILLIAM_W12,SPR_WILLIAM_W13,SPR_WILLIAM_W14,
+              SPR_WILLIAM_W15,SPR_WILLIAM_W16,SPR_WILLIAM_W17,SPR_WILLIAM_W18,
+
+              SPR_WILLIAM_W21,SPR_WILLIAM_W22,SPR_WILLIAM_W23,SPR_WILLIAM_W24,
+              SPR_WILLIAM_W25,SPR_WILLIAM_W26,SPR_WILLIAM_W27,SPR_WILLIAM_W28,
+
+              SPR_WILLIAM_W31,SPR_WILLIAM_W32,SPR_WILLIAM_W33,SPR_WILLIAM_W34,
+              SPR_WILLIAM_W35,SPR_WILLIAM_W36,SPR_WILLIAM_W37,SPR_WILLIAM_W38,
+
+              SPR_WILLIAM_W41,SPR_WILLIAM_W42,SPR_WILLIAM_W43,SPR_WILLIAM_W44,
+              SPR_WILLIAM_W45,SPR_WILLIAM_W46,SPR_WILLIAM_W47,SPR_WILLIAM_W48,
+
+
+              SPR_WILLIAM_PAIN1, SPR_WILLIAM_PAIN2,SPR_WILLIAM_DIE1,SPR_WILLIAM_DIE2,
+              SPR_WILLIAM_DIE3,SPR_WILLIAM_DIE4,SPR_WILLIAM_DEAD1, SPR_WILLIAM_DEAD2,
+
+              SPR_WILLIAM_WPAIN1, SPR_WILLIAM_WPAIN2,SPR_WILLIAM_WDIE1,SPR_WILLIAM_WDIE2,
+              SPR_WILLIAM_WDIE3,SPR_WILLIAM_WDIE4,SPR_WILLIAM_WDEAD1, SPR_WILLIAM_WDEAD2,
+
+              SPR_WILLIAM_RISE1, SPR_WILLIAM_RISE2, SPR_WILLIAM_RISE3, SPR_WILLIAM_RISE4,
+
+              SPR_WILLIAM_USE11,SPR_WILLIAM_USE12,SPR_WILLIAM_USE13,SPR_WILLIAM_USE14,
+              SPR_WILLIAM_USE15,SPR_WILLIAM_USE16,SPR_WILLIAM_USE17,SPR_WILLIAM_USE18,
+
+              SPR_WILLIAM_USE21,SPR_WILLIAM_USE22,SPR_WILLIAM_USE23,SPR_WILLIAM_USE24,
+              SPR_WILLIAM_USE25,SPR_WILLIAM_USE26,SPR_WILLIAM_USE27,SPR_WILLIAM_USE28,
+
+              /******************* Fire monk (Mark)**********************************/
+
+
+              SPR_MARK_CAST1,SPR_MARK_CAST2,SPR_MARK_CAST3,SPR_MARK_CAST4,
+              SPR_MARK_CAST5,SPR_MARK_CAST6,SPR_MARK_CAST7,
+
+              SPR_MARK_S1,SPR_MARK_S2,SPR_MARK_S3,SPR_MARK_S4,
+              SPR_MARK_S5,SPR_MARK_S6,SPR_MARK_S7,SPR_MARK_S8,
+
+              SPR_MARK_W11,SPR_MARK_W12,SPR_MARK_W13,SPR_MARK_W14,
+              SPR_MARK_W15,SPR_MARK_W16,SPR_MARK_W17,SPR_MARK_W18,
+
+              SPR_MARK_W21,SPR_MARK_W22,SPR_MARK_W23,SPR_MARK_W24,
+              SPR_MARK_W25,SPR_MARK_W26,SPR_MARK_W27,SPR_MARK_W28,
+
+              SPR_MARK_W31,SPR_MARK_W32,SPR_MARK_W33,SPR_MARK_W34,
+              SPR_MARK_W35,SPR_MARK_W36,SPR_MARK_W37,SPR_MARK_W38,
+
+              SPR_MARK_W41,SPR_MARK_W42,SPR_MARK_W43,SPR_MARK_W44,
+              SPR_MARK_W45,SPR_MARK_W46,SPR_MARK_W47,SPR_MARK_W48,
+
+              SPR_MARK_PAIN1,SPR_MARK_PAIN2,
+
+              SPR_MARK_DIE1,SPR_MARK_DIE2,SPR_MARK_DIE3,SPR_MARK_DIE4,
+              SPR_MARK_DEAD1,SPR_MARK_DEAD2,SPR_MARK_DEAD3,SPR_MARK_DEAD4,
+              SPR_MARK_DEAD5,SPR_MARK_DEAD6,SPR_MARK_DEAD7,
+
+
+              /*
+              SPR_FIREMONK_USE11,SPR_FIREMONK_USE12,SPR_FIREMONK_USE13,SPR_FIREMONK_USE14,
+              SPR_FIREMONK_USE15,SPR_FIREMONK_USE16,SPR_FIREMONK_USE17,SPR_FIREMONK_USE18,
+
+              SPR_FIREMONK_USE21,SPR_FIREMONK_USE22,SPR_FIREMONK_USE23,SPR_FIREMONK_USE24,
+              SPR_FIREMONK_USE25,SPR_FIREMONK_USE26,SPR_FIREMONK_USE27,SPR_FIREMONK_USE28,
+              */
+
+//#endif
+
+             } actornames_t;
+
+typedef enum
+{   GUNSTART_LABEL,
+
+#if (SHAREWARE == 0)
+
+    W_KNIFE,WK2,WK3,WK4,WK5,WK6,WK7,WK8,WK9,WK10,
+
+    W_BMALEPISTOL1,xab,xcd,
+    W_BMRIGHTPISTOL1,xef,xgh,
+    W_BMLEFTPISTOL1,xij,xkl,
+#endif
+
+    W_MALEPISTOL1,x5,x6,
+    W_MRIGHTPISTOL1,x7,x8,
+    W_MLEFTPISTOL1,x9,x10,
+
+#if (SHAREWARE == 0)
+    W_FEMALEPISTOL1,x11,x12,
+    W_FRIGHTPISTOL1,x13,x14,
+    W_FLEFTPISTOL1,x15,x16,
+#endif
+
+    W_MP40,FN7,FN8,
+    W_BAZOOKA,FN22,fn104,fn105,
+    W_HEATSEEKER,FN80,fn108,fn109,
+    W_DRUNK,FN72,FN73,FN74,
+    W_FIREBOMB,FN33,fn106,fn107,
+    W_FIREWALL,FN66,FN67,
+    W_GODHAND,ded1,ded2,ded3,ded4,ded5,ded6,ded7,
+
+#if (SHAREWARE == 0)
+
+    W_SPLIT,FN69,FN70,FN71,
+    W_KES,fn101,fn102,fn103,x99,x100,
+    W_BAT,fn111,fn112,fn113,fn114,fn115,fn117,
+    W_DOG,bite1,bite2,bite3,nose1,nose2,nose3,nose4,paw1,paw2,paw3,paw4
+#endif
+} weaponsprites;
+
+
+#define SPR_DDOG_FIRE1 SPR_DDOG_JUMP1
+#define SPR_DDOG_FIRE2 SPR_DDOG_JUMP2
+#define SPR_DDOG_BOLTS2 SPR_DDOG_BOLTS1
+#define SPR_DDOG_BOLTS3 SPR_DDOG_BOLTS1
+#define SPR_DDOG_BOLTS4 SPR_DDOG_BOLTS1
+#define SPR_DDOG_HIT1 -1
+#define SPR_DDOG_HIT2 -1
+#define SPR_DDOG_HIT3 -1
+#define SPR_DDOG_PAIN1 SPR_DDOG_DIE1
+#define SPR_DDOG_PAIN2 SPR_DDOG_DIE1
+
+
+#define SPR_BLITZ_USE SPR_BLITZ_S1
+
+#define SPR_BLITZ_STEAL1 SPR_BLITZ_USE11
+#define SPR_BLITZ_STEAL2 SPR_BLITZ_USE12
+
+
+
+#define SPR_GRENADE_HIT1 -1
+#define SPR_GRENADE_HIT2 -1
+#define SPR_GRENADE_HIT3 -1
+
+#define SPR_FIREBALL_HIT1 -1
+#define SPR_FIREBALL_HIT2 -1
+#define SPR_FIREBALL_HIT3 -1
+
+#define SPR_ROBOGRD_SHURIKEN1 SPR_BSTAR1
+#define SPR_ROBOGRD_SHURIKEN2 SPR_BSTAR2
+#define SPR_ROBOGRD_SHURIKEN3 SPR_BSTAR3
+#define SPR_ROBOGRD_SHURIKEN4 SPR_BSTAR4
+#define SPR_SHURIKEN_HIT1 -1
+#define SPR_SHURIKEN_HIT2 -1
+#define SPR_SHURIKEN_HIT3 -1
+
+
+#define SPR_ESAU_USE SPR_ESAU_S1
+#define SPR_ESAU_WINS SPR_ESAU_S1
+#define SPR_ESAU_DIE4 SPR_ESAU_DIE3
+#define SPR_ESAU_DIE5 SPR_ESAU_DIE3
+#define SPR_ESAU_DIE6 SPR_ESAU_DIE3
+#define SPR_ESAU_DIE7 SPR_ESAU_DIE3
+
+
+#define SPR_MISSILEHIT1 -1
+#define SPR_MISSILEHIT2 -1
+#define SPR_MISSILEHIT3 -1
+#define SPR_HEINRICH_DIE4 SPR_HEINRICH_DIE3
+#define SPR_HEINRICH_DIE5 SPR_HEINRICH_DIE3
+#define SPR_HEINRICH_DIE6 SPR_HEINRICH_DIE3
+#define SPR_HEINRICH_DIE7 SPR_HEINRICH_DIE3
+#define SPR_HEINRICH_DEAD SPR_HEINRICH_DIE3
+#define SPR_HEINRICH_MINE SPR_HEINRICH_S1
+#define SPR_HEINRICH_USE SPR_HEINRICH_S1
+
+#define SPR_DMFBALL11 SPR_FIREBALL1
+#define SPR_DMFBALL21 SPR_FIREBALL2
+#define SPR_DMFBALL31 SPR_FIREBALL3
+#define SPR_DMFBALL41 SPR_FIREBALL4
+#define SPR_DMFBALLHIT1 -1
+#define SPR_DMFBALLHIT2 -1
+#define SPR_DMFBALLHIT3 -1
+#define SPR_DARKMONK_DIE4 SPR_DARKMONK_DIE3
+#define SPR_DARKMONK_DIE5 SPR_DARKMONK_DIE3
+#define SPR_DARKMONK_DIE6 SPR_DARKMONK_DIE3
+#define SPR_DARKMONK_DIE7 SPR_DARKMONK_DIE3
+#define SPR_DARKMONK_PAIN1 SPR_DARKMONK_DIE1
+#define SPR_DARKMONK_PAIN2 SPR_DARKMONK_DIE5
+
+#define SPR_OSHURHIT1 -1
+#define SPR_OSHURHIT2 -1
+#define SPR_OSHURHIT3 -1
+
+#define SPR_OSHUR1 SPR_BSTAR1
+#define SPR_OSHUR2 SPR_BSTAR2
+#define SPR_OSHUR3 SPR_BSTAR4
+#define SPR_OSHUR4 SPR_BSTAR4
+
+#define SPR_WALLSHOOT SPR_WALLSTAND1
+#define SPR_WALLPATH1 SPR_WALLSTAND1
+
+#endif
--- /dev/null
+++ b/rott/states.h
@@ -1,0 +1,668 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+#ifndef _states_public
+#define _states_public
+
+#include "develop.h"
+
+#if (SHAREWARE == 0)
+#define MAXSTATES 1300+17+8+32+32
+#else
+#define MAXSTATES 660+17+8+32+32
+#endif
+
+#define SF_CLOSE   0x01
+#define SF_CRUSH   0x02
+#define SF_UP      0x04
+#define SF_DOWN    0x08
+#define SF_SOUND   0x10
+#define SF_BLOCK   0x20
+#define SF_EYE1    0
+#define SF_EYE2    1
+#define SF_EYE3    2
+#define SF_DOGSTATE 0x40
+#define SF_BAT      0x80
+#define SF_FAKING   0x80
+#define SF_DEAD     0x80
+
+typedef struct  statestruct
+{
+    byte            rotate;
+    short           shapenum;  // a shapenum of -1 means get from ob->temp1
+    short           tictime;
+    void            (*think) ();
+    signed char     condition;
+    struct  statestruct     *next;
+} statetype;
+
+extern   statetype * statetable[MAXSTATES];
+
+extern   statetype s_lowgrdstand;
+extern   statetype s_lowgrdpath4;
+extern   statetype s_lowgrdpath3;
+extern   statetype s_lowgrdpath2;
+extern   statetype s_lowgrdpath1;
+extern   statetype s_lowgrdcollide;
+extern   statetype s_lowgrdcollide2;
+//extern   statetype s_lowgrduse1;
+extern   statetype s_lowgrdshoot1;
+extern   statetype s_lowgrdchase1;
+extern   statetype s_lowgrddie1;
+
+extern statetype s_lowgrddie4rev;
+
+extern   statetype s_lowgrdcrushed1;
+extern   statetype s_lowgrdcrushed1;
+extern   statetype s_sneakydown;
+extern   statetype s_sneakyrise1;
+
+
+extern   statetype s_highgrdstand;
+extern   statetype s_highgrdpath1;
+extern   statetype s_highgrdcollide;
+extern   statetype s_highgrdcollide2;
+//extern   statetype s_highgrduse1;
+extern   statetype s_highgrdshoot1;
+extern   statetype s_highgrdshoot3;
+extern   statetype s_highgrdchase1;
+extern   statetype s_highgrddie1;
+
+extern statetype s_highgrddie5rev;
+
+extern   statetype s_highgrdcrushed1;
+
+
+extern   statetype s_strikestand;
+extern   statetype s_strikepath1;
+extern   statetype s_strikecollide;
+extern   statetype s_strikecollide2;
+extern   statetype s_strikeshoot1;
+//extern   statetype s_strikeuse1;
+extern   statetype s_strikerollright1;
+extern   statetype s_strikerollright3;
+extern   statetype s_strikerollleft1;
+extern   statetype s_strikerollleft3;
+extern   statetype s_strikechase1;
+extern   statetype s_strikedie1;
+
+extern statetype s_strikedie4rev;
+
+extern   statetype s_strikewait;
+extern   statetype s_strikecrushed1;
+
+
+extern   statetype s_blitzstand;
+extern   statetype s_blitzpath1;
+extern   statetype s_blitzcollide;
+extern   statetype s_blitzcollide2;
+extern   statetype s_blitzshoot1;
+extern   statetype s_blitzuse;
+extern   statetype s_blitzsteal1;
+extern   statetype s_blitzchase1;
+extern   statetype s_blitzdie1;
+extern   statetype s_blitzdie3;
+
+extern statetype s_blitzdie4rev;
+
+extern   statetype s_blitzplead1;
+extern   statetype s_blitzplead3;
+extern   statetype s_blitzplead4;
+extern   statetype s_blitzplead7;
+extern   statetype s_blitzaplead5;
+extern   statetype s_blitzaplead4;
+extern   statetype s_blitzcrushed1;
+extern   statetype s_blitzfakedie1;
+extern   statetype s_blitzrise2;
+extern   statetype s_blitzstruggledie1;
+extern   statetype s_blitzstruggledead;
+
+extern   statetype s_enforcerstand;
+extern   statetype s_enforcerpath1;
+extern   statetype s_enforcercollide;
+extern   statetype s_enforcercollide2;
+//extern   statetype s_enforceruse1;
+extern   statetype s_enforcershoot1;
+extern   statetype s_enforcershoot3;
+extern   statetype s_enforcerthrow1;
+extern   statetype s_grenade1;
+extern   statetype s_grenadehit1;
+extern   statetype s_enforcerchase1;
+extern   statetype s_enforcerdie1;
+
+extern statetype s_enforcerdie4rev;
+
+extern   statetype s_grenade_fall1;
+extern   statetype s_grenade_fall6;
+extern   statetype s_enforcercrushed1;
+
+
+extern   statetype s_robogrdstand;
+extern   statetype s_robogrdpath1;
+extern   statetype s_robogrdshoot1;
+extern   statetype s_robogrdshuriken1;
+extern   statetype s_shurikenhit1;
+extern   statetype s_robogrdchase1;
+extern   statetype s_robogrddie1;
+extern   statetype s_robogrdcollide;
+extern   statetype s_robogrdcollide2;
+extern   statetype s_robogrdcrushed1;
+extern   statetype s_roboalign;
+extern   statetype s_robowait;
+extern   statetype s_roborealign;
+
+
+
+
+
+extern statetype s_altexplosion10;
+extern statetype s_altexplosion9 ;
+extern statetype s_altexplosion8 ;
+extern statetype s_altexplosion7 ;
+extern statetype s_altexplosion6 ;
+extern statetype s_altexplosion5 ;
+extern statetype s_altexplosion4 ;
+extern statetype s_altexplosion3  ;
+extern statetype s_altexplosion2  ;
+extern statetype s_altexplosion1  ;
+
+
+
+extern   statetype s_explosion1;
+extern   statetype s_explosion2;
+extern   statetype s_explosion3;
+extern   statetype s_explosion4;
+extern   statetype s_explosion5;
+extern   statetype s_explosion6;
+extern   statetype s_explosion7;
+extern   statetype s_explosion8;
+extern   statetype s_explosion9;
+extern   statetype s_explosion10;
+extern   statetype s_explosion11;
+extern   statetype s_explosion12;
+extern   statetype s_explosion13;
+extern   statetype s_explosion14;
+extern   statetype s_explosion15;
+extern   statetype s_explosion16;
+extern   statetype s_explosion17;
+extern   statetype s_explosion18;
+extern   statetype s_explosion19;
+extern   statetype s_explosion20;
+
+extern   statetype s_grexplosion1;
+extern   statetype s_grexplosion2;
+extern   statetype s_grexplosion3;
+extern   statetype s_grexplosion4;
+extern   statetype s_grexplosion5;
+extern   statetype s_grexplosion6;
+extern   statetype s_grexplosion7;
+extern   statetype s_grexplosion8;
+extern   statetype s_grexplosion9;
+extern   statetype s_grexplosion10;
+extern   statetype s_grexplosion11;
+extern   statetype s_grexplosion12;
+extern   statetype s_grexplosion13;
+extern   statetype s_grexplosion14;
+extern   statetype s_grexplosion15;
+extern   statetype s_grexplosion16;
+extern   statetype s_grexplosion17;
+extern   statetype s_grexplosion18;
+extern   statetype s_grexplosion19;
+extern   statetype s_grexplosion20;
+
+
+
+extern   statetype s_staticexplosion1;
+extern   statetype s_staticexplosion2;
+extern   statetype s_staticexplosion3;
+extern   statetype s_staticexplosion4;
+extern   statetype s_staticexplosion5;
+extern   statetype s_staticexplosion6;
+extern   statetype s_staticexplosion7;
+extern   statetype s_staticexplosion8;
+extern   statetype s_staticexplosion9;
+extern   statetype s_staticexplosion10;
+extern   statetype s_staticexplosion11;
+extern   statetype s_staticexplosion12;
+extern   statetype s_staticexplosion13;
+extern   statetype s_staticexplosion14;
+extern   statetype s_staticexplosion15;
+extern   statetype s_staticexplosion16;
+extern   statetype s_staticexplosion17;
+extern   statetype s_staticexplosion18;
+extern   statetype s_staticexplosion19;
+extern   statetype s_staticexplosion20;
+extern   statetype s_staticexplosion21;
+extern   statetype s_staticexplosion22;
+extern   statetype s_staticexplosion23;
+extern   statetype s_staticexplosion24;
+extern   statetype s_staticexplosion25;
+
+extern   statetype s_upblade1;
+
+extern   statetype s_firejetup1;
+
+
+extern   statetype s_columndowndown1;
+
+
+extern   statetype s_spearup1;
+extern   statetype s_pushcolumn1;
+extern   statetype s_pushcolumn2;
+extern   statetype s_pushcolumn3;
+
+extern   statetype s_wallfireball;
+extern   statetype s_crossfire1;
+extern   statetype s_crossdone1;
+
+
+
+
+extern   statetype s_fireunit1;
+extern   statetype s_firespan1;
+
+extern   statetype s_p_bazooka1;
+extern   statetype s_p_bazooka2;
+
+extern   statetype s_p_grenade;
+extern   statetype s_p_gfall1;
+extern   statetype s_p_gfall2;
+extern   statetype s_p_gfall3;
+extern   statetype s_p_gfall4;
+
+extern   statetype s_gunsmoke1;
+extern   statetype s_bloodspurt1;
+extern   statetype s_hitmetalwall1;
+extern   statetype s_hitmetalactor1;
+
+
+
+
+
+
+extern   statetype s_dust;
+
+
+
+extern   statetype s_skeleton1;
+
+
+extern   statetype s_gas2;
+extern   statetype s_gas1;
+
+
+extern   statetype s_spring1;
+extern   statetype s_spring2;
+
+
+
+
+extern   statetype s_player;
+extern   statetype s_free;
+
+extern   statetype s_pgunattack1;
+extern   statetype s_pmissattack1;
+extern   statetype s_pgunattack2;
+extern   statetype s_pmissattack2;
+extern   statetype s_remoteinelev;
+extern   statetype s_remotemove1;
+
+
+extern   statetype s_godfire1;
+
+
+
+extern   statetype s_remotedie1;
+
+
+extern   statetype s_guts1;
+extern   statetype s_guts12;
+
+
+extern   statetype s_bossdeath;
+extern   statetype s_megaexplosions;
+
+extern   statetype s_superparticles;
+extern   statetype s_gibs1;
+extern   statetype s_gibsdone1;
+extern   statetype s_bigsoul;
+extern   statetype s_littlesoul;
+extern   statetype s_vaporized1;
+extern   statetype s_autospring1;
+extern   statetype s_pbatblast;
+
+
+
+extern   statetype s_collectorwander1;
+extern   statetype s_collectorfdoor1;
+extern   statetype s_tag;
+extern   statetype s_timekeeper;
+extern   statetype s_skeleton48;
+extern   statetype s_skeleton24;
+
+extern   statetype s_wind;
+extern   statetype s_remoteguts1;
+extern   statetype s_voidwait;
+extern   statetype s_ashwait;
+extern   statetype s_deadwait;
+extern   statetype s_gutwait;
+extern   statetype s_vaporized8;
+extern   statetype s_remoteguts12;
+extern   statetype s_eye1;
+extern   statetype s_itemspawn1;
+extern   statetype s_deadblood1;
+
+
+extern   statetype s_flash1;
+
+extern   statetype s_elevdisk;
+extern   statetype s_pathdisk;
+extern   statetype s_megaremove;
+
+extern   statetype s_respawn1;
+extern   statetype s_basemarker1;
+
+extern   statetype s_blooddrip1;
+
+extern   statetype s_diskmaster;
+extern   statetype s_bstar1;
+
+
+#if (SHAREWARE == 0)
+
+extern   statetype s_scottwander1;
+extern   statetype s_scottwanderdoor1;
+
+extern   statetype s_opstand;
+extern   statetype s_oppath1;
+extern   statetype s_opcollide;
+extern   statetype s_opcollide2;
+extern   statetype s_opgiveup;
+//extern   statetype s_opuse1;
+extern   statetype s_opshoot1;
+extern   statetype s_opbolo1;
+extern   statetype s_bolocast1;
+extern   statetype s_opchase1;
+extern   statetype s_opdie1;
+
+extern statetype s_opdie5rev;
+
+extern   statetype s_opcrushed1;
+
+
+extern   statetype s_dmonkstand;
+extern   statetype s_dmonkpath1;
+extern   statetype s_dmonkshoot1;
+extern   statetype s_dmonkshoot2;
+extern   statetype s_dmonkchase1;
+extern   statetype s_dmonkdie1;
+
+extern statetype s_dmonkdie4rev;
+
+extern   statetype s_dmonkcollide;
+extern   statetype s_dmonkcollide2;
+extern   statetype s_dmonkcrushed1;
+extern   statetype s_dmonkshoot5;
+extern   statetype s_dmonkshoot3;
+extern   statetype s_dmonkshoot4;
+
+
+extern   statetype s_firemonkstand;
+extern   statetype s_firemonkpath1;
+extern   statetype s_firemonkcast1;
+extern   statetype s_monkfire1;
+extern   statetype s_fireballhit1;
+extern   statetype s_firemonkchase1;
+extern   statetype s_firemonkdie1;
+
+extern statetype s_firemonkdie4rev;
+
+extern   statetype s_firemonkcollide;
+extern   statetype s_firemonkcollide2;
+extern   statetype s_firemonkcrushed1;
+
+
+extern   statetype s_wallstand;
+extern   statetype s_wallpath;
+extern   statetype s_wallshoot;
+extern   statetype s_wallcollide;
+extern   statetype s_wallalign;
+extern   statetype s_wallwait;
+extern   statetype s_wallrestore;
+
+
+extern   statetype s_darianstand;
+extern   statetype s_darianchase1;
+extern   statetype s_darianuse;
+extern   statetype s_darianshoot1;
+extern   statetype s_dariancollide;
+extern   statetype s_dariancollide2;
+extern   statetype s_dariandie1;
+extern   statetype s_darianspears;
+extern   statetype s_darianuse1;
+extern   statetype s_dariansink1;
+extern   statetype s_dariansink9;
+extern   statetype s_darianrise1;
+extern   statetype s_darianwait;
+extern   statetype s_dariandefend1;
+
+
+extern   statetype s_heinrichstand;
+extern   statetype s_heinrichshoot1;
+extern   statetype s_heinrichshoot4;
+extern   statetype s_heinrichshoot9;
+extern   statetype s_heinrichooc;
+extern   statetype s_heinrichchase;
+extern   statetype s_heinexp1;
+extern   statetype s_kristleft;
+extern   statetype s_kristright;
+
+
+extern   statetype s_missile1;
+extern   statetype s_missilehit1;
+extern   statetype s_mine1;
+extern   statetype s_heinrichchase1;
+extern   statetype s_heinrichuse;
+extern   statetype s_heinrichmine;
+extern   statetype s_heinrichdie1;
+extern   statetype s_heinrichdead;
+extern   statetype s_heinrichdefend;
+
+extern   statetype s_dexplosion22;
+extern   statetype s_dexplosion21;
+extern   statetype s_dexplosion20;
+extern   statetype s_dexplosion19;
+extern   statetype s_dexplosion18;
+extern   statetype s_dexplosion17;
+extern   statetype s_dexplosion16;
+extern   statetype s_dexplosion15;
+extern   statetype s_dexplosion14;
+extern   statetype s_dexplosion13;
+extern   statetype s_dexplosion12;
+extern   statetype s_dexplosion11;
+extern   statetype s_dexplosion10;
+extern   statetype s_dexplosion9;
+extern   statetype s_dexplosion8;
+extern   statetype s_dexplosion7;
+extern   statetype s_dexplosion6;
+extern   statetype s_dexplosion5;
+extern   statetype s_dexplosion4;
+extern   statetype s_dexplosion3;
+extern   statetype s_dexplosion2;
+extern   statetype s_dexplosion1;
+extern   statetype s_dspear1;
+
+
+
+extern   statetype s_NMEchase;
+extern   statetype s_NMEdie;
+extern   statetype s_NMEhead1;
+extern   statetype s_NMEhead2;
+extern   statetype s_NMEwheels1;
+extern   statetype s_NMEwheels2;
+extern   statetype s_NMEwheels3;
+extern   statetype s_NMEwheels4;
+extern   statetype s_NMEwheels5;
+extern   statetype s_NMEwindup;
+extern   statetype s_NMEwheels120;
+
+extern   statetype s_NMEwrotleft3;
+extern   statetype s_NMEwrotleft2;
+extern   statetype s_NMEwrotleft1;
+
+extern   statetype s_NMEwrotright3;
+extern   statetype s_NMEwrotright2;
+extern   statetype s_NMEwrotright1;
+extern   statetype s_NMEminiball1;
+extern   statetype s_NMEattack;
+extern   statetype s_NMEsaucer1;
+extern   statetype s_NMEhead1rl;
+extern   statetype s_NMEhead2rl;
+extern   statetype s_NMEspinattack;
+extern   statetype s_NMEwheelspin;
+extern   statetype s_NMEcollide;
+extern   statetype s_NMEdeathbuildup;
+extern   statetype s_NMEheadexplosion;
+extern   statetype s_NMEstand;
+extern   statetype s_NMEspinfire;
+extern   statetype s_shootinghead;
+extern   statetype s_oshuriken1;
+extern   statetype s_oshurikenhit1;
+
+
+
+
+extern   statetype s_darkmonkstand;
+extern   statetype s_darkmonkcharge1;
+extern   statetype s_darkmonkreact;
+extern   statetype s_darkmonkland;
+extern   statetype s_darkmonkchase1;
+extern   statetype s_darkmonkcover1;
+extern   statetype s_darkmonkawaken1;
+extern   statetype s_darkmonklightning1;
+extern   statetype s_darkmonkfspark1;
+extern   statetype s_darkmonkbreathe1;
+extern   statetype s_darkmonksummon1;
+extern   statetype s_darkmonkhead;
+extern   statetype s_darkmonkhspawn;
+extern   statetype s_darkmonksneer1;
+extern   statetype s_darkmonkheadhappy;
+extern   statetype s_darkmonkheaddie1;
+extern   statetype s_darkmonkhball1;
+extern   statetype s_darkmonksphere1;
+extern   statetype s_darkmonksphere8;
+extern   statetype s_darkmonkbball1;
+extern   statetype s_darkmonkscare1;
+extern   statetype s_darkmonkdie1;
+extern   statetype s_darkmonkredhead;
+extern   statetype s_redheadhit;
+extern   statetype s_darkmonksnakelink;
+extern   statetype s_darkmonkredlink;
+extern   statetype s_redlinkhit;
+extern   statetype s_energysphere1;
+extern   statetype s_lightning;
+extern   statetype s_handball2;
+extern   statetype s_handball1;
+extern   statetype s_faceball2;
+extern   statetype s_faceball1;
+extern   statetype s_floorspark1;
+extern   statetype s_dmlandandfire;
+
+extern   statetype s_darkmonkhball7;
+extern   statetype s_darkmonkbball7;
+extern   statetype s_darkmonklightning9;
+extern   statetype s_darkmonkfspark5;
+extern   statetype s_darkmonkbreathe6;
+extern   statetype s_darkmonkabsorb1;
+extern   statetype s_dmgreenthing1;
+extern   statetype s_dmgreenthing8;
+extern   statetype s_darkmonkfastspawn;
+extern   statetype s_spit1;
+extern   statetype s_spithit1;
+extern   statetype s_snakefire1;
+extern   statetype s_snakepath;
+extern   statetype s_snakefindpath;
+extern   statetype s_snakefireworks1;
+extern   statetype s_snakefireworks2;
+
+
+extern   statetype s_speardown1;
+
+
+extern   statetype s_downblade1;
+
+
+extern   statetype s_firejetdown1;
+
+extern   statetype s_columnupup1;
+extern   statetype s_columnupup2;
+extern   statetype s_columnupup8;
+extern   statetype s_columnupup7;
+extern   statetype s_columnupdown1;
+extern   statetype s_columnupdown6;
+
+extern   statetype s_spinupblade1;
+extern   statetype s_spindownblade1;
+
+extern   statetype s_boulderdrop12;
+extern   statetype s_boulderdrop10;
+extern   statetype s_boulderdrop8;
+
+
+extern   statetype s_boulderdrop1;
+extern   statetype s_boulderspawn;
+extern   statetype s_bouldersink1;
+extern   statetype s_boulderroll1;
+
+extern   statetype s_gunfire1;
+extern   statetype s_gunfire2;
+extern   statetype s_gundie1;
+extern   statetype s_gunstand;
+extern   statetype s_gunraise1;
+extern   statetype s_gunlower1;
+extern   statetype s_4waygunfire1;
+extern   statetype s_4waygunfire2;
+extern   statetype s_4waygun;
+
+
+extern   statetype s_kessphere1;
+extern   statetype s_batblast1;
+extern   statetype s_slop1;
+
+
+
+extern   statetype s_serialdog4;
+extern   statetype s_serialdog3;
+extern   statetype s_serialdog2;
+extern   statetype s_serialdog;
+extern   statetype s_serialdogattack;
+extern   statetype s_doguse;
+extern   statetype s_doglick;
+extern   statetype s_dogwait;
+
+
+
+#endif
+
+
+
+
+
+
+#endif
--- /dev/null
+++ b/rott/stdout.txt
@@ -1,0 +1,14 @@
+Rise of the Triad Startup  Version 1.4
+ Commercial Version 
+Z_INIT: 8950000 bytes
+IN_Startup: Mouse Present
+    Adding DARKWAR.WAD.
+    Adding REMOTE1.RTS.
+W_Wad: Wad Manager Started NUMLUMPS=3904
+RT_DRAW: Tables Initialized
+MU_Startup: 
+SD_SetupFXCard: Fx ok.
+SD_Startup: Fx ok.
+RT_MAIN: Fonts Initialized
+RT_MSG: Message System Started
+RT_VIEW: Colormaps Initialized
--- /dev/null
+++ b/rott/task_man.h
@@ -1,0 +1,69 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+/**********************************************************************
+   module: TASK_MAN.C
+
+   author: James R. Dose
+   phone:  (214)-271-1365 Ext #221
+   date:   July 25, 1994
+
+   Public header for TASK_MAN.C, a low level timer task scheduler.
+
+   (c) Copyright 1994 James R. Dose.  All Rights Reserved.
+**********************************************************************/
+
+#ifndef __TASK_MAN_H
+#define __TASK_MAN_H
+
+enum TASK_ERRORS
+{
+    TASK_Warning = -2,
+    TASK_Error = -1,
+    TASK_Ok = 0
+};
+
+typedef struct task
+{
+    struct   task *next;
+    struct   task *prev;
+    void          ( *TaskService )( struct task * );
+    void          *data;
+    long          rate;
+    volatile long count;
+    int           priority;
+    int           active;
+} task;
+
+// TS_InInterrupt is TRUE during a taskman interrupt.
+// Use this if you have code that may be used both outside
+// and within interrupts.
+
+extern volatile int TS_InInterrupt;
+
+void    TS_Shutdown( void );
+task    *TS_ScheduleTask( void ( *Function )( task * ), int rate,
+                          int priority, void *data );
+int     TS_Terminate( task *ptr );
+void    TS_Dispatch( void );
+void    TS_SetTaskRate( task *Task, int rate );
+void    TS_UnlockMemory( void );
+int     TS_LockMemory( void );
+
+#endif
--- /dev/null
+++ b/rott/version.h
@@ -1,0 +1,28 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+
+#ifndef VERSION_H
+#define VERSION_H
+
+#define ROTTMAJORVERSION 1
+#define ROTTMINORVERSION 4
+#define ROTTVERSION ((ROTTMAJORVERSION*10)+(ROTTMINORVERSION))
+
+#endif
--- /dev/null
+++ b/rott/w_wad.c
@@ -1,0 +1,544 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+// W_wad.c
+
+#include <stdio.h>
+#include <string.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+
+#if PLATFORM_DOS
+#include <malloc.h>
+#include <conio.h>
+#include <io.h>
+#endif
+
+#include "rt_def.h"
+#include "rt_util.h"
+#include "_w_wad.h"
+#include "w_wad.h"
+#include "z_zone.h"
+#include "isr.h"
+#include "develop.h"
+
+#include "rt_crc.h"
+#include "rt_main.h"
+
+//=============
+// GLOBALS
+//=============
+
+int             numlumps;
+void            **lumpcache;
+
+//=============
+// STATICS
+//=============
+
+static lumpinfo_t      *lumpinfo;              // location of each lump on disk
+
+
+#if (DATACORRUPTIONTEST == 1)
+static byte *lumpcheck;
+#endif
+
+/*
+============================================================================
+
+                                                LUMP BASED ROUTINES
+
+============================================================================
+*/
+
+/*
+====================
+=
+= W_AddFile
+=
+= All files are optional, but at least one file must be found
+= Files with a .wad extension are wadlink files with multiple lumps
+= Other files are single lumps with the base filename for the lump name
+=
+====================
+*/
+
+void W_AddFile (char *_filename)
+{
+    wadinfo_t               header;
+    lumpinfo_t              *lump_p;
+    unsigned                i;
+    int                     handle, length;
+    int                     startlump;
+    filelump_t              *fileinfo, singleinfo;
+
+    char filename[MAX_PATH];
+    char buf[MAX_PATH+100];//bna++
+
+    strncpy(filename, _filename, sizeof (filename));
+    filename[sizeof (filename) - 1] = '\0';
+    FixFilePath(filename);
+
+    //bna section start
+    if (access (filename, 0) != 0) {
+        strcpy (buf,"Error, Could not find User file '");
+        strcat (buf,filename);
+        strcat (buf,"', ignoring file");
+        printf("%s", buf);
+    }
+    //bna section end
+
+//
+// read the entire file in
+//      FIXME: shared opens
+
+#ifdef PLATFORM_DOS
+    if ( (handle = open (filename,O_RDWR | O_BINARY)) == -1)
+#else
+    if ( (handle = open (filename,O_RDONLY | O_BINARY)) == -1)
+#endif
+        return;
+
+    startlump = numlumps;
+
+    if ( (strcmpi (filename+strlen(filename)-3, "wad" ) ) &&
+            (strcmpi (filename+strlen(filename)-3, "rts" ) ) )
+    {
+        // single lump file
+        if (!quiet)
+            printf("    Adding single file %s.\n",filename);
+        fileinfo = &singleinfo;
+        singleinfo.filepos = 0;
+        singleinfo.size = LONG(filelength(handle));
+        ExtractFileBase (filename, singleinfo.name);
+        numlumps++;
+    }
+    else
+    {
+        // WAD file
+        if (!quiet)
+            printf("    Adding %s.\n",filename);
+        read (handle, &header, sizeof(header));
+        if (strncmp(header.identification,"IWAD",4))
+            Error ("Wad file %s doesn't have IWAD id\n",filename);
+        header.numlumps = IntelLong(LONG(header.numlumps));
+        header.infotableofs = IntelLong(LONG(header.infotableofs));
+        length = header.numlumps*sizeof(filelump_t);
+        fileinfo = alloca (length);
+        if (!fileinfo)
+            Error ("Wad file could not allocate header info on stack");
+        lseek (handle, header.infotableofs, SEEK_SET);
+        read (handle, fileinfo, length);
+
+        numlumps += header.numlumps;
+    }
+
+//
+// Fill in lumpinfo
+//
+    Z_Realloc((void **)&lumpinfo,numlumps*sizeof(lumpinfo_t));
+//        lumpinfo = realloc (lumpinfo, numlumps*sizeof(lumpinfo_t));
+//        if (!lumpinfo)
+//           Error("W_AddFile: Could not realloc %ld bytes",numlumps*sizeof(lumpinfo_t));
+    lump_p = &lumpinfo[startlump];
+
+    for (i=startlump ; i<(unsigned int)numlumps ; i++,lump_p++, fileinfo++)
+    {
+        fileinfo->filepos = IntelLong(LONG(fileinfo->filepos));
+        fileinfo->size = IntelLong(LONG(fileinfo->size));
+        lump_p->handle = handle;
+        lump_p->position = LONG(fileinfo->filepos);
+        lump_p->size = LONG(fileinfo->size);
+        strncpy (lump_p->name, fileinfo->name, 8);
+    }
+}
+
+
+
+/*
+====================
+=
+= W_CheckWADIntegrity
+=
+====================
+*/
+
+void W_CheckWADIntegrity ( void )
+{
+    int crc;
+
+// CRC disabled because it's not very useful these days
+
+#ifdef DOS
+    crc = CalculateCRC ((byte *)lumpinfo, numlumps*sizeof(lumpinfo_t) );
+
+    if (crc != WADCHECKSUM)
+    {
+        printf("==============================================================================\n");
+        printf("ATTENTION: This version of ROTT has been modified.  If you would like to get\n");
+        printf("a copy of the original game, call 1-800-APOGEE1 or run ROTTHELP.EXE.\n");
+        printf("      You will not receive technical support for this modified version.\n");
+//      printf("                        Press any key to continue\n");
+        printf("==============================================================================\n");
+//      printf("crc=%ld\n",crc);
+//      getch();
+    }
+#endif
+}
+
+
+
+/*
+====================
+=
+= W_InitMultipleFiles
+=
+= Pass a null terminated list of files to use.
+=
+= All files are optional, but at least one file must be found
+=
+= Files with a .wad extension are idlink files with multiple lumps
+=
+= Other files are single lumps with the base filename for the lump name
+=
+= Lump names can appear multiple times. The name searcher looks backwards,
+= so a later file can override an earlier one.
+=
+====================
+*/
+
+void W_InitMultipleFiles (char **filenames)
+{
+//
+// open all the files, load headers, and count lumps
+//
+    numlumps = 0;
+    lumpinfo = SafeMalloc(5);   // will be realloced as lumps are added
+
+    for ( ; *filenames ; filenames++)
+        W_AddFile (*filenames);
+
+    if (!numlumps)
+        Error ("W_InitFiles: no files found");
+
+//
+// set up caching
+//
+    lumpcache = calloc (numlumps, sizeof(*lumpcache));
+    if (!lumpcache)
+        Error("W_InitFiles: lumpcache malloc failed size=%d\n",numlumps<<2);
+
+    if (!quiet)
+        printf("W_Wad: Wad Manager Started NUMLUMPS=%ld\n",(long int)numlumps);
+#if (DATACORRUPTIONTEST == 1)
+    lumpcheck=SafeMalloc(numlumps);
+    memset(lumpcheck,255,numlumps);
+#endif
+#ifdef DOS
+    if (!SOUNDSETUP)
+#endif
+        W_CheckWADIntegrity ();
+}
+
+
+
+
+/*
+====================
+=
+= W_InitFile
+=
+= Just initialize from a single file
+=
+====================
+*/
+
+void W_InitFile (char *filename)
+{
+    char    *names[2];
+
+    names[0] = filename;
+    names[1] = NULL;
+    W_InitMultipleFiles (names);
+}
+
+
+
+/*
+====================
+=
+= W_NumLumps
+=
+====================
+*/
+
+int     W_NumLumps (void)
+{
+    return numlumps;
+}
+
+
+
+/*
+====================
+=
+= W_CheckNumForName
+=
+= Returns -1 if name not found
+=
+====================
+*/
+
+int     W_CheckNumForName (char *name)
+{
+    char    name8[9];
+    int             v1,v2;
+    lumpinfo_t      *lump_p;
+    lumpinfo_t      *endlump;
+
+// make the name into two integers for easy compares
+
+    strncpy (name8,name,8);
+    name8[8] = 0;                   // in case the name was a fill 8 chars
+    strupr (name8);                 // case insensitive
+
+    v1 = *(int *)name8;
+    v2 = *(int *)&name8[4];
+
+
+// scan backwards so patch lump files take precedence
+
+    lump_p = lumpinfo;
+    endlump = lumpinfo + numlumps;
+
+    while (lump_p != endlump)
+    {
+        if ( *(int *)lump_p->name == v1 && *(int *)&lump_p->name[4] == v2)
+            return lump_p - lumpinfo;
+        lump_p++;
+    }
+
+
+    return -1;
+}
+
+
+/*
+====================
+=
+= W_GetNumForName
+=
+= Calls W_CheckNumForName, but bombs out if not found
+=
+====================
+*/
+
+int     W_GetNumForName (char *name)
+{
+    int     i;
+
+    i = W_CheckNumForName (name);
+    if (i != -1)
+        return i;
+
+    Error ("W_GetNumForName: %s not found!",name);
+    return -1;
+}
+
+
+/*
+====================
+=
+= W_LumpLength
+=
+= Returns the buffer size needed to load the given lump
+=
+====================
+*/
+
+int W_LumpLength (int lump)
+{
+    if (lump >= numlumps)
+        Error ("W_LumpLength: %i >= numlumps",lump);
+    return lumpinfo[lump].size;
+}
+
+/*
+====================
+=
+= W_GetNameForNum
+=
+====================
+*/
+
+char *  W_GetNameForNum (int i)
+{
+
+    if (i>=numlumps)
+        Error ("W_GetNameForNum: %i >= numlumps",i);
+    return &(lumpinfo[i].name[0]);
+}
+
+/*
+====================
+=
+= W_ReadLump
+=
+= Loads the lump into the given buffer, which must be >= W_LumpLength()
+=
+====================
+*/
+int readinglump;
+byte * lumpdest;
+void W_ReadLump (int lump, void *dest)
+{
+    int                     c;
+    lumpinfo_t      *l;
+
+    readinglump=lump;
+    lumpdest=dest;
+    if (lump >= numlumps)
+        Error ("W_ReadLump: %i >= numlumps",lump);
+    if (lump < 0)
+        Error ("W_ReadLump: %i < 0",lump);
+    l = lumpinfo+lump;
+
+    lseek (l->handle, l->position, SEEK_SET);
+    c = read (l->handle, dest, l->size);
+    if (c < l->size)
+        Error ("W_ReadLump: only read %i of %i on lump %i",c,l->size,lump);
+}
+
+
+/*
+====================
+=
+= W_WriteLump
+=
+= Writes the lump into the given buffer, which must be >= W_LumpLength()
+=
+====================
+*/
+
+void W_WriteLump (int lump, void *src)
+{
+    int        c;
+    lumpinfo_t *l;
+
+    if (lump >= numlumps)
+        Error ("W_WriteLump: %i >= numlumps",lump);
+    if (lump < 0)
+        Error ("W_WriteLump: %i < 0",lump);
+    l = lumpinfo+lump;
+
+    lseek (l->handle, l->position, SEEK_SET);
+    c = write (l->handle, src, l->size);
+    if (c < l->size)
+        Error ("W_WriteLump: only wrote %i of %i on lump %i",c,l->size,lump);
+}
+
+
+/*
+====================
+=
+= W_CacheLumpNum
+=
+====================
+*/
+void    *W_CacheLumpNum (int lump, int tag, converter_t converter, int numrec)
+{
+    if (lump >= (int)numlumps)
+        Error ("W_CacheLumpNum: %i >= numlumps",lump);
+
+    else if (lump < 0)
+        Error ("W_CacheLumpNum: %i < 0  Taglevel: %i",lump,tag);
+
+    if (!lumpcache[lump])
+    {
+        // read the lump in
+#if (PRECACHETEST == 1)
+        char str[9];
+        strncpy(&str[0],W_GetNameForNum(lump),8);
+        str[8]=0;
+        SoftError("Lump #%d, %s cached at %ld tics size=%ld tag=%ld\n",lump,str,ticcount,W_LumpLength (lump),tag);
+        if (W_LumpLength(lump)==0)
+            SoftError("Caching in zero length lump #%d, %s cached at %ld tics size=%ld tag=%ld\n",lump,str,ticcount,W_LumpLength (lump),tag);
+#endif
+
+#if (DATACORRUPTIONTEST == 1)
+        {
+            int length;
+
+            *(lumpcheck+lump)=CHECKPERIOD;
+            length=W_LumpLength(lump);
+            Z_Malloc (length+sizeof(word), tag, &lumpcache[lump]);
+            W_ReadLump (lump, lumpcache[lump]);
+            Debug("Invoking endian converter on %p, %i records.\n", lumpcache[lump], numrec);
+            converter(lumpcache[lump], numrec);
+
+            *( (word *) ((byte *)lumpcache[lump]+length) ) = CalculateCRC (lumpcache[lump], length);
+        }
+#else
+        Z_Malloc (W_LumpLength (lump), tag, &lumpcache[lump]);
+        W_ReadLump (lump, lumpcache[lump]);
+        Debug("Invoking endian converter on %p, %i records\n", lumpcache[lump], numrec);
+        converter(lumpcache[lump], numrec);
+#endif
+    }
+    else
+    {
+#if (DATACORRUPTIONTEST == 1)
+
+        if (*(lumpcheck+lump)==255)
+            Error("Tried using lump%ld before reading it in\n",lump);
+        (*(lumpcheck+lump))--;
+        if (*(lumpcheck+lump)==0)
+        {
+            word storedcrc;
+            word crc;
+            int length;
+
+            *(lumpcheck+lump)=CHECKPERIOD;
+
+            length=W_LumpLength(lump);
+            storedcrc = *( (word *) ((byte *)lumpcache[lump]+length) );
+            crc = CalculateCRC (lumpcache[lump], length);
+            if (crc!=storedcrc)
+                Error("Data corruption lump=%ld\n",lump);
+        }
+#endif
+        Z_ChangeTag (lumpcache[lump],tag);
+    }
+
+    return lumpcache[lump];
+}
+
+
+/*
+====================
+=
+= W_CacheLumpName
+=
+====================
+*/
+
+void    *W_CacheLumpName (char *name, int tag, converter_t converter, int numrec)
+{
+    return W_CacheLumpNum (W_GetNumForName(name), tag, converter, numrec);
+}
--- /dev/null
+++ b/rott/w_wad.h
@@ -1,0 +1,51 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+//***************************************************************************
+//
+//    W_WAD.C - Wad managment utilities
+//
+//***************************************************************************
+
+#ifndef _w_wad_public
+#define _w_wad_public
+
+#include "byteordr.h"
+
+void    W_InitMultipleFiles (char **filenames); // Initialize multiple wads
+void    W_InitFile (char *filename);            // Init a single wad file
+
+int     W_CheckNumForName (char *name);         // Check to see if the named lump exists
+int     W_GetNumForName (char *name);           // Get the number for the named lump
+char *  W_GetNameForNum (int i);                // Get the name for a number
+
+int     W_NumLumps (void);                      // Get the current number of lumps managed
+int     W_LumpLength (int lump);                // Get the length of the numbered lump
+void    W_ReadLump (int lump, void *dest);      // Read the numbered lump into a buffer
+void W_WriteLump (int lump, void *src);
+
+void    *W_CacheLumpNum (int lump, int tag, converter_t converter, int numrecs);
+// Cache in the numbered lump with the appropriate memory tag
+void    *W_CacheLumpName (char *name, int tag, converter_t converter, int numrecs);
+// Cache in the named lump with the appropriate memory tag
+
+extern int             numlumps;
+extern void            **lumpcache;
+
+#endif
--- /dev/null
+++ b/rott/watcom.c
@@ -1,0 +1,43 @@
+#include "rt_def.h"
+
+#include "watcom.h"
+
+/*
+  C versions of watcom.h assembly.
+  Uses the '__int64' type (see rt_def.h).
+ */
+
+fixed FixedMul(fixed a, fixed b)
+{
+    __int64 scratch1 = (__int64) a * (__int64) b + (__int64) 0x8000;
+    return (scratch1 >> 16) & 0xffffffff;
+}
+
+fixed FixedMulShift(fixed a, fixed b, fixed shift)
+{
+    __int64 x = a;
+    __int64 y = b;
+    __int64 z = x * y;
+
+    return (((unsigned __int64)z) >> shift) & 0xffffffff;
+}
+
+fixed FixedDiv2(fixed a, fixed b)
+{
+    __int64 x = (signed int)a;
+    __int64 y = (signed int)b;
+    __int64 z = x * 65536 / y;
+
+    return (z) & 0xffffffff;
+}
+
+fixed FixedScale(fixed orig, fixed factor, fixed divisor)
+{
+    __int64 x = orig;
+    __int64 y = factor;
+    __int64 z = divisor;
+
+    __int64 w = (x * y) / z;
+
+    return (w) & 0xffffffff;
+}
--- /dev/null
+++ b/rott/watcom.h
@@ -1,0 +1,59 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+#ifndef _watcom_h_public
+#define _watcom_h_public
+fixed FixedMul(fixed a, fixed b);
+fixed FixedDiv2(fixed a, fixed b);
+fixed FixedScale(fixed orig, fixed factor, fixed divisor);
+fixed FixedMulShift(fixed a, fixed b, fixed shift);
+#ifdef __WATCOMC__
+#pragma aux FixedMul =  \
+        "imul ebx",                     \
+        "add  eax, 8000h"        \
+        "adc  edx,0h"            \
+        "shrd eax,edx,16"       \
+        parm    [eax] [ebx] \
+        value   [eax]           \
+        modify exact [eax edx]
+
+#pragma aux FixedMulShift =  \
+        "imul ebx",                     \
+        "shrd eax,edx,cl"       \
+        parm    [eax] [ebx] [ecx]\
+        value   [eax]           \
+        modify exact [eax edx]
+
+#pragma aux FixedDiv2 = \
+        "cdq",                          \
+        "shld edx,eax,16",      \
+        "sal eax,16",           \
+        "idiv ebx"                      \
+        parm    [eax] [ebx] \
+        value   [eax]           \
+        modify exact [eax edx]
+#pragma aux FixedScale = \
+        "imul ebx",                     \
+        "idiv ecx"                      \
+        parm    [eax] [ebx] [ecx]\
+        value   [eax]           \
+        modify exact [eax edx]
+#endif
+
+#endif
--- /dev/null
+++ b/rott/winrott.c
@@ -1,0 +1,170 @@
+/* Routines from winrott needed for the highres support for the SDL port */
+#include <stdlib.h>
+#include <string.h>
+#include "WinRott.h"
+#include "modexlib.h"
+
+//typedef unsigned char byte;
+
+int iGLOBAL_SCREENWIDTH  = 640;//bna val 800
+int iGLOBAL_SCREENHEIGHT = 480;//bna val 600
+int iGLOBAL_SCREENBWIDE ;
+int iG_SCREENWIDTH;// default screen width in bytes
+
+int iGLOBAL_HEALTH_X;
+int iGLOBAL_HEALTH_Y;
+int iGLOBAL_AMMO_X;
+int iGLOBAL_AMMO_Y;
+
+int iGLOBAL_FOCALWIDTH;
+double dGLOBAL_FPFOCALWIDTH;
+
+double dTopYZANGLELIMIT;
+
+int iG_X_center;
+int iG_Y_center;
+
+//int topBarCenterOffset = 0;
+
+boolean iG_aimCross = 0;
+
+extern int  viewheight;
+extern int  viewwidth;
+
+//----------------------------------------------------------------------
+#define FINEANGLES                        2048
+void SetRottScreenRes (int Width, int Height)
+{
+
+    iGLOBAL_SCREENWIDTH = Width;
+    iGLOBAL_SCREENHEIGHT = Height;
+
+
+    iGLOBAL_SCREENBWIDE = iGLOBAL_SCREENWIDTH*(96/320);
+    iG_SCREENWIDTH = iGLOBAL_SCREENWIDTH*(96/320);;// default screen width in bytes
+
+    if (iGLOBAL_SCREENWIDTH == 320) {
+        iGLOBAL_FOCALWIDTH = 160;
+        dGLOBAL_FPFOCALWIDTH = 160.0;
+        iGLOBAL_HEALTH_X = 20;
+        iGLOBAL_HEALTH_Y = 185;
+        iGLOBAL_AMMO_X = 300;
+        iGLOBAL_AMMO_Y = 184;
+
+        dTopYZANGLELIMIT = (44*FINEANGLES/360);;
+    }
+    if (iGLOBAL_SCREENWIDTH == 640) {
+        iGLOBAL_FOCALWIDTH = 180;
+        dGLOBAL_FPFOCALWIDTH = 180.0 ;
+        iGLOBAL_HEALTH_X = 40;//20*2;
+        iGLOBAL_HEALTH_Y = 466;//(185*2)+16;
+        iGLOBAL_AMMO_X = 600;//300*2;
+        iGLOBAL_AMMO_Y = 464;//480-16;
+
+        dTopYZANGLELIMIT = (42*FINEANGLES/360);;
+    }
+    if (iGLOBAL_SCREENWIDTH == 800) {
+        iGLOBAL_FOCALWIDTH = 200;
+        dGLOBAL_FPFOCALWIDTH = 200.0 ;
+        iGLOBAL_HEALTH_X = 40;//20*2;
+        iGLOBAL_HEALTH_Y = 585;//(185/200)*600;
+        iGLOBAL_AMMO_X = 750;//(300/320)*800;
+        iGLOBAL_AMMO_Y = 584;//600-16;
+
+        dTopYZANGLELIMIT = (90*FINEANGLES/360);;
+    }
+
+    //dYZANGLELIMIT = (12*FINEANGLES/360);
+    //#define YZANGLELIMIT  (12*FINEANGLES/360)//bna--(30*FINEANGLES/360)
+
+    //#define TopYZANGLELIMIT  (44*FINEANGLES/360)//bna added
+
+//	GetCurrentDirectory(sizeof(ApogeePath),ApogeePath);// curent directory name
+
+}
+
+//----------------------------------------------------------------------
+//luckey for me that I am not programmin a 386 or the next
+//4 function would never have worked. bna++
+extern int     viewsize;
+void MoveScreenUpLeft()
+{
+    int startX,startY,startoffset;
+    byte  *Ycnt,*b;
+//   SetTextMode (  );
+    b=(byte *)bufferofs;
+    b += (((iGLOBAL_SCREENHEIGHT-viewheight)/2)*iGLOBAL_SCREENWIDTH)+((iGLOBAL_SCREENWIDTH-viewwidth)/2);
+    if (viewsize == 8) {
+        b += 8*iGLOBAL_SCREENWIDTH;
+    }
+    startX = 3; //take 3 pixels to the right
+    startY = 3; //take 3 lines down
+    startoffset = (startY*iGLOBAL_SCREENWIDTH)+startX;
+
+    for (Ycnt=b; Ycnt<b+((viewheight-startY)*iGLOBAL_SCREENWIDTH); Ycnt+=iGLOBAL_SCREENWIDTH) {
+        memcpy(Ycnt,Ycnt+startoffset, viewwidth-startX);
+    }
+}
+//----------------------------------------------------------------------
+void MoveScreenDownLeft()
+{
+    int startX,startY,startoffset;
+    byte  *Ycnt,*b;
+//   SetTextMode (  );
+    b=(byte *)bufferofs;
+    b += (((iGLOBAL_SCREENHEIGHT-viewheight)/2)*iGLOBAL_SCREENWIDTH)+((iGLOBAL_SCREENWIDTH-viewwidth)/2);
+    if (viewsize == 8) {
+        b += 8*iGLOBAL_SCREENWIDTH;
+    }
+    startX = 3; //take 3 pixels to the right
+    startY = 3; //take 3 lines down
+    startoffset = (startY*iGLOBAL_SCREENWIDTH);//+startX;
+
+    //Ycnt starts in botton of screen and copys lines upwards
+    for (Ycnt=b+((viewheight-startY-1)*iGLOBAL_SCREENWIDTH); Ycnt>b; Ycnt-=iGLOBAL_SCREENWIDTH) {
+        memcpy(Ycnt+startoffset,Ycnt+startX,viewwidth-startX);
+    }
+}
+//----------------------------------------------------------------------
+void MoveScreenUpRight()
+{
+    int startX,startY,startoffset;
+    byte  *Ycnt,*b;
+//   SetTextMode (  );
+    b=(byte *)bufferofs;
+
+    b += (((iGLOBAL_SCREENHEIGHT-viewheight)/2)*iGLOBAL_SCREENWIDTH)+((iGLOBAL_SCREENWIDTH-viewwidth)/2);
+    if (viewsize == 8) {
+        b += 8*iGLOBAL_SCREENWIDTH;
+    }
+    startX = 3; //take 3 pixels to the right
+    startY = 3; //take 3 lines down
+    startoffset = (startY*iGLOBAL_SCREENWIDTH);//+startX;
+
+    for (Ycnt=b; Ycnt<b+((viewheight-startY)*iGLOBAL_SCREENWIDTH); Ycnt+=iGLOBAL_SCREENWIDTH) {
+        memcpy(Ycnt+startX,Ycnt+startoffset, viewwidth-startX);
+    }
+}
+//----------------------------------------------------------------------
+void MoveScreenDownRight()
+{
+    int startX,startY,startoffset;
+    byte  *Ycnt,*b;
+//   SetTextMode (  );
+    b=(byte *)bufferofs;
+
+    b += (((iGLOBAL_SCREENHEIGHT-viewheight)/2)*iGLOBAL_SCREENWIDTH)+((iGLOBAL_SCREENWIDTH-viewwidth)/2);
+    if (viewsize == 8) {
+        b += 8*iGLOBAL_SCREENWIDTH;
+    }
+    startX = 3; //take 3 pixels to the right
+    startY = 3; //take 3 lines down
+    startoffset = (startY*iGLOBAL_SCREENWIDTH)+startX;
+
+    //Ycnt starts in botton of screen and copys lines upwards
+    for (Ycnt=b+((viewheight-startY-1)*iGLOBAL_SCREENWIDTH); Ycnt>b; Ycnt-=iGLOBAL_SCREENWIDTH) {
+        memcpy(Ycnt+startoffset,Ycnt,viewwidth-startX);
+    }
+}
+
+
--- /dev/null
+++ b/rott/z_zone.c
@@ -1,0 +1,798 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+// Z_zone.c
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef DOS
+#include <dos.h>
+#include <conio.h>
+#endif
+
+#include "rt_def.h"
+#include "_z_zone.h"
+#include "z_zone.h"
+#include "rt_util.h"
+#include "develop.h"
+#include "rt_net.h"
+
+#if (DEVELOPMENT == 1)
+#include "rt_main.h"
+#endif
+//MED
+#include "memcheck.h"
+
+int lowmemory=0;
+
+/*
+==============================================================================
+
+                                                ZONE MEMORY ALLOCATION
+
+There is never any space between memblocks, and there will never be two
+contiguous free memblocks.
+
+The rover can be left pointing at a non-empty block
+
+It is of no value to free a cachable block, because it will get overwritten
+automatically if needed
+
+==============================================================================
+*/
+
+//Globals
+
+int zonememorystarted=0;
+
+// Statics
+
+static memzone_t       *mainzone;
+static memzone_t       *levelzone;
+static int levelzonesize=LEVELZONESIZE;
+static struct meminfo
+{
+    unsigned LargestBlockAvail;
+    unsigned MaxUnlockedPage;
+    unsigned LargestLockablePage;
+    unsigned LinAddrSpace;
+    unsigned NumFreePagesAvail;
+    unsigned NumPhysicalPagesFree;
+    unsigned TotalPhysicalPages;
+    unsigned FreeLinAddrSpace;
+    unsigned SizeOfPageFile;
+    unsigned Reserved[3];
+} MemInfo;
+
+/*
+========================
+=
+= Z_ClearZone
+=
+========================
+*/
+
+void Z_ClearZone (memzone_t *zone)
+{
+    memblock_t      *block;
+
+// set the entire zone to one free block
+
+    zone->blocklist.next = zone->blocklist.prev = block =
+                               (memblock_t *)( (byte *)zone + sizeof(memzone_t) );
+    zone->blocklist.user = (void *)zone;
+    zone->blocklist.tag = PU_STATIC;
+    zone->rover = block;
+
+    block->prev = block->next = &zone->blocklist;
+    block->user = NULL;     // free block
+    block->size = zone->size - sizeof(memzone_t);
+}
+
+
+/*
+========================
+=
+= Z_AllocateZone
+=
+========================
+*/
+
+memzone_t *Z_AllocateZone (int size)
+{
+    memzone_t       *header;
+
+    header = malloc (size+sizeof(memzone_t));
+    if (!header)
+        Error ("Z_AllocateZone: Couldn't malloc %zd bytes avail=%d\n",
+               size+sizeof(memzone_t), Z_AvailHeap());
+    header->size = size;
+    Z_ClearZone (header);
+    return header;
+}
+
+/*
+========================
+=
+= Z_Init
+=
+========================
+*/
+void Z_Init (int size, int min)
+{
+    int maxsize;
+    int sz;
+
+    if (zonememorystarted==1)
+        return;
+    zonememorystarted=1;
+
+    sz = GamePacketSize();
+
+    sz*=MAXCMDS;
+
+    if (ConsoleIsServer() == true)
+        levelzonesize+=((numplayers*2)+1)*sz;
+    else
+        levelzonesize+=(numplayers+1)*sz;
+
+    maxsize=((int)(Z_AvailHeap())-size-levelzonesize);
+    if (maxsize<min)
+    {
+        UL_DisplayMemoryError (min-maxsize);
+    }
+    if (maxsize>MAXMEMORYSIZE)
+        maxsize=(MAXMEMORYSIZE-levelzonesize);
+
+    mainzone = Z_AllocateZone (maxsize);
+    levelzone = Z_AllocateZone (levelzonesize);
+
+    if (!quiet)
+        printf("Z_INIT: %ld bytes\n",(long int)(maxsize+levelzonesize));
+
+    if (maxsize<(min+(min>>1)))
+    {
+        lowmemory = 1;
+
+        printf("==============================================================================\n");
+        printf("WARNING: You are running ROTT with very little memory.  ROTT runs best with\n");
+        printf("8 Megabytes of memory and no TSR's loaded in memory.  If you can free up more\n");
+        printf("memory for ROTT then you should press CTRL-BREAK at this time. If you are\n");
+        printf("unable to do this you will experience momentary pauses in game-play whenever\n");
+        printf("you enter new areas of the game as well as an overall decreased performance.\n");
+        printf("                        Press any key to continue\n");
+        printf("==============================================================================\n");
+        getch();
+    }
+}
+
+/*
+========================
+=
+= Z_ShutDown
+=
+========================
+*/
+
+void Z_ShutDown( void )
+{
+    if (zonememorystarted==0)
+        return;
+    zonememorystarted=0;
+    free(mainzone);
+    free(levelzone);
+}
+
+/*
+========================
+=
+= Z_GetSize
+=
+========================
+*/
+
+int Z_GetSize (void *ptr)
+{
+    memblock_t      *block;
+
+    block = (memblock_t *) ( (byte *)ptr - sizeof(memblock_t));
+    return (block->size - sizeof(memblock_t));
+}
+
+
+/*
+========================
+=
+= Z_Free
+=
+========================
+*/
+
+void Z_Free (void *ptr)
+{
+    memblock_t      *block, *other;
+
+    block = (memblock_t *) ( (byte *)ptr - sizeof(memblock_t));
+    if (!block->user)
+        Error ("Z_Free: freed a freed pointer");
+
+    if (block->user > (void **)0x100)       // smaller values are not pointers
+        *block->user = 0;               // clear the user's mark
+    block->user = NULL;     // mark as free
+
+    other = block->prev;
+    if (!other->user)
+    {   // merge with previous free block
+        other->size += block->size;
+        other->next = block->next;
+        other->next->prev = other;
+        if (block == mainzone->rover)
+            mainzone->rover = other;
+        else if (block == levelzone->rover)
+            levelzone->rover = other;
+        block = other;
+    }
+
+    other = block->next;
+    if (!other->user)
+    {   // merge the next free block onto the end
+        block->size += other->size;
+        block->next = other->next;
+        block->next->prev = block;
+        if (other == mainzone->rover)
+            mainzone->rover = block;
+        else if (other == levelzone->rover)
+            levelzone->rover = block;
+    }
+}
+
+
+/*
+========================
+=
+= Z_Malloc
+=
+= You can pass a NULL user if the tag is < PU_PURGELEVEL
+========================
+*/
+
+#if (DEVELOPMENT == 1)
+int totallevelsize=0;
+#endif
+
+void *Z_Malloc (int size, int tag, void *user)
+{
+    int             extra;
+    memblock_t      *start, *rover, *new, *base;
+
+//
+// scan through the block list looking for the first free block
+// of sufficient size, throwing out any purgable blocks along the way
+//
+//        size += sizeof(memblock_t);     // account for size of block header
+    size = (size + sizeof(memblock_t) + 3)&~3;     // account for size of block header
+
+
+//
+// if there is a free block behind the rover, back up over them
+//
+    base = mainzone->rover;
+    if (!base->prev->user)
+        base = base->prev;
+
+    rover = base;
+    start = base->prev;
+
+    do
+    {
+        if (rover == start)     // scaned all the way around the list
+        {
+            SoftError("OHSHIT\n");
+            Z_DumpHeap(0,200);
+            Error ("Z_Malloc: failed on allocation of %i bytes",size);
+        }
+        if (rover->user)
+        {
+            if (rover->tag < PU_PURGELEVEL)
+                // hit a block that can't be purged, so move base past it
+                base = rover = rover->next;
+            else
+            {
+                // free the rover block (adding the size to base)
+                base = base->prev;      // the rover can be the base block
+                Z_Free ((byte *)rover+sizeof(memblock_t));
+                base = base->next;
+                rover = base->next;
+            }
+        }
+        else
+            rover = rover->next;
+    } while (base->user || base->size < size);
+
+//
+// found a block big enough
+//
+    extra = base->size - size;
+    if (extra >  MINFRAGMENT)
+    {   // there will be a free fragment after the allocated block
+        new = (memblock_t *) ((byte *)base + size );
+        new->size = extra;
+        new->user = NULL;               // free block
+        new->tag = 0;
+        new->prev = base;
+        new->next = base->next;
+        new->next->prev = new;
+        base->next = new;
+        base->size = size;
+    }
+
+    if (user)
+    {
+        base->user = user;                      // mark as an in use block
+        *(void **)user = (void *) ((byte *)base + sizeof(memblock_t));
+    }
+    else
+    {
+        if (tag >= PU_PURGELEVEL)
+            Error ("Z_Malloc: an owner is required for purgable blocks");
+        base->user = (void *)2;         // mark as in use, but unowned
+    }
+    base->tag = tag;
+
+    mainzone->rover = base->next;   // next allocation will start looking here
+
+
+#if (MEMORYCORRUPTIONTEST==1)
+    base->posttag=MEMORYPOSTTAG;
+    base->pretag=MEMORYPRETAG;
+#endif
+
+    return (void *) ((byte *)base + sizeof(memblock_t));
+}
+
+/*
+========================
+=
+= Z_LevelMalloc
+=
+= Only use this for level structures.
+= You can pass a NULL user if the tag is < PU_PURGELEVEL
+========================
+*/
+
+void *Z_LevelMalloc (int size, int tag, void *user)
+{
+    int             extra;
+    memblock_t      *start, *rover, *new, *base;
+
+//
+// scan through the block list looking for the first free block
+// of sufficient size, throwing out any purgable blocks along the way
+//
+//        size += sizeof(memblock_t);     // account for size of block header
+    size = (size + sizeof(memblock_t) + 3)&~3;     // account for size of block header
+
+
+//
+// if there is a free block behind the rover, back up over them
+//
+    base = levelzone->rover;
+    if (!base->prev->user)
+        base = base->prev;
+
+    rover = base;
+    start = base->prev;
+
+    do
+    {
+        if (rover == start)     // scaned all the way around the list
+        {
+            SoftError("OHSHIT\n");
+            Z_DumpHeap(0,200);
+            Error ("Z_LevelMalloc: failed on allocation of %i bytes",size);
+        }
+        if (rover->user)
+        {
+            if (rover->tag < PU_PURGELEVEL)
+                // hit a block that can't be purged, so move base past it
+                base = rover = rover->next;
+            else
+            {
+                // free the rover block (adding the size to base)
+                base = base->prev;      // the rover can be the base block
+                Z_Free ((byte *)rover+sizeof(memblock_t));
+                base = base->next;
+                rover = base->next;
+            }
+        }
+        else
+            rover = rover->next;
+    } while (base->user || base->size < size);
+
+//
+// found a block big enough
+//
+    extra = base->size - size;
+    if (extra >  MINFRAGMENT)
+    {   // there will be a free fragment after the allocated block
+        new = (memblock_t *) ((byte *)base + size );
+        new->size = extra;
+        new->user = NULL;               // free block
+        new->tag = 0;
+        new->prev = base;
+        new->next = base->next;
+        new->next->prev = new;
+        base->next = new;
+        base->size = size;
+    }
+
+    if (user)
+    {
+        base->user = user;                      // mark as an in use block
+        *(void **)user = (void *) ((byte *)base + sizeof(memblock_t));
+    }
+    else
+    {
+        if (tag >= PU_PURGELEVEL)
+            Error ("Z_Malloc: an owner is required for purgable blocks");
+        base->user = (void *)2;         // mark as in use, but unowned
+    }
+    base->tag = tag;
+
+    levelzone->rover = base->next;   // next allocation will start looking here
+
+#if (MEMORYCORRUPTIONTEST==1)
+    base->posttag=MEMORYPOSTTAG;
+    base->pretag=MEMORYPRETAG;
+#endif
+
+    return (void *) ((byte *)base + sizeof(memblock_t));
+}
+
+
+
+/*
+========================
+=
+= Z_FreeTags
+=
+========================
+*/
+
+void Z_FreeTags (int lowtag, int hightag)
+{
+    memblock_t      *block, *next;
+
+    for (block = mainzone->blocklist.next ; block != &mainzone->blocklist
+            ; block = next)
+    {
+        next = block->next;             // get link before freeing
+        if (!block->user)
+            continue;                       // free block
+        if (block->tag >= lowtag && block->tag <= hightag)
+            Z_Free ( (byte *)block+sizeof(memblock_t));
+    }
+    for (block = levelzone->blocklist.next ; block != &levelzone->blocklist
+            ; block = next)
+    {
+        next = block->next;             // get link before freeing
+        if (!block->user)
+            continue;                       // free block
+        if (block->tag >= lowtag && block->tag <= hightag)
+            Z_Free ( (byte *)block+sizeof(memblock_t));
+    }
+}
+
+/*
+========================
+=
+= Z_DumpHeap
+=
+========================
+*/
+
+void Z_DumpHeap (int lowtag, int hightag)
+{
+    memblock_t      *block;
+    int             totalsize;
+
+    SoftError("MAIN ZONE\n");
+    SoftError("zone size: %i  location: %p\n",mainzone->size,mainzone);
+    SoftError("tag range: %i to %i\n",lowtag, hightag);
+
+    totalsize=0;
+
+    for (block = mainzone->blocklist.next ; ; block = block->next)
+    {
+        if (block->tag >= lowtag && block->tag <= hightag)
+        {
+            SoftError("block:%p    size:%7i    user:%p    tag:%3i\n",
+                      block, block->size, block->user, block->tag);
+            totalsize+=block->size;
+        }
+
+        if (block->next == &mainzone->blocklist) {
+            break;                  // all blocks have been hit
+        }
+        if ( (byte *)block + block->size != (byte *)block->next) {
+            SoftError("ERROR: block size does not touch the next block\n");
+        }
+        if ( block->next->prev != block) {
+            SoftError("ERROR: next block doesn't have proper back link\n");
+        }
+        if (!block->user && !block->next->user) {
+            SoftError("ERROR: two consecutive free blocks\n");
+        }
+    }
+    SoftError("Total Size of blocks = %d\n",totalsize);
+
+    SoftError("LEVEL ZONE\n");
+    SoftError("zone size: %i  location: %p\n",levelzone->size,levelzone);
+    SoftError("tag range: %i to %i\n",lowtag, hightag);
+
+    totalsize=0;
+
+    for (block = levelzone->blocklist.next ; ; block = block->next)
+    {
+        if (block->tag >= lowtag && block->tag <= hightag)
+        {
+            SoftError("block:%p    size:%7i    user:%p    tag:%3i\n",
+                      block, block->size, block->user, block->tag);
+            totalsize+=block->size;
+        }
+
+        if (block->next == &levelzone->blocklist)
+            break;                  // all blocks have been hit
+        if ( (byte *)block + block->size != (byte *)block->next) {
+            SoftError("ERROR: block size does not touch the next block\n");
+        }
+        if ( block->next->prev != block) {
+            SoftError("ERROR: next block doesn't have proper back link\n");
+        }
+        if (!block->user && !block->next->user) {
+            SoftError("ERROR: two consecutive free blocks\n");
+        }
+    }
+    SoftError("Total Size of blocks = %d\n",totalsize);
+
+}
+
+/*
+========================
+=
+= Z_UsedHeap
+=
+========================
+*/
+
+int Z_UsedHeap ( void )
+{
+    memblock_t      *block;
+    int heapsize;
+
+
+    heapsize=0;
+    for (block = mainzone->blocklist.next ; ; block = block->next)
+    {
+        if ((block->tag>0) && (block->user>(void **)0))
+            heapsize+=(block->size);
+        if (block->next == &mainzone->blocklist)
+            break;                  // all blocks have been hit
+    }
+    return heapsize;
+}
+
+/*
+========================
+=
+= Z_UsedLevelHeap
+=
+========================
+*/
+
+int Z_UsedLevelHeap ( void )
+{
+    memblock_t      *block;
+    int heapsize;
+
+
+    heapsize=0;
+    for (block = levelzone->blocklist.next ; ; block = block->next)
+    {
+        if ((block->tag>0) && (block->user>(void **)0))
+            heapsize+=(block->size);
+        if (block->next == &levelzone->blocklist)
+            break;                  // all blocks have been hit
+    }
+    return heapsize;
+}
+
+
+/*
+========================
+=
+= Z_UsedStaticHeap
+=
+========================
+*/
+
+int Z_UsedStaticHeap ( void )
+{
+    memblock_t      *block;
+    int heapsize;
+
+
+    heapsize=0;
+    for (block = mainzone->blocklist.next ; ; block = block->next)
+    {
+        if ((block->tag>0) && (block->tag<PU_PURGELEVEL) && (block->user>(void **)0))
+            heapsize+=(block->size);
+        if (block->next == &mainzone->blocklist)
+            break;                  // all blocks have been hit
+    }
+    return heapsize;
+}
+
+
+/*
+========================
+=
+= Z_HeapSize
+=
+========================
+*/
+
+int Z_HeapSize ( void )
+{
+    return mainzone->size;
+}
+
+
+/*
+========================
+=
+= Z_CheckHeap
+=
+========================
+*/
+
+void Z_CheckHeap (void)
+{
+    memblock_t      *block;
+
+    // Check mainzone
+
+    for (block = mainzone->blocklist.next ; ; block = block->next)
+    {
+        if (block->next == &mainzone->blocklist)
+            break;                  // all blocks have been hit
+        if ( (byte *)block + block->size != (byte *)block->next)
+            Error ("Z_CheckHeap: block size does not touch the next block\n");
+        if ( block->next->prev != block)
+            Error ("Z_CheckHeap: next block doesn't have proper back link\n");
+        if (!block->user && !block->next->user)
+            Error ("Z_CheckHeap: two consecutive free blocks\n");
+#if (MEMORYCORRUPTIONTEST==1)
+        if ((block->tag>0) && (block->user>0))
+        {
+            if (block->posttag!=MEMORYPOSTTAG)
+                Error("Z_CheckHeap: Corrupted posttag\n");
+            if (block->pretag!=MEMORYPRETAG)
+                Error("Z_CheckHeap: Corrupted pretag\n");
+        }
+#endif
+    }
+
+    // Check levelzone
+
+    for (block = levelzone->blocklist.next ; ; block = block->next)
+    {
+        if (block->next == &levelzone->blocklist)
+            break;                  // all blocks have been hit
+        if ( (byte *)block + block->size != (byte *)block->next)
+            Error ("Z_CheckHeap: block size does not touch the next block\n");
+        if ( block->next->prev != block)
+            Error ("Z_CheckHeap: next block doesn't have proper back link\n");
+        if (!block->user && !block->next->user)
+            Error ("Z_CheckHeap: two consecutive free blocks\n");
+#if (MEMORYCORRUPTIONTEST==1)
+        if ((block->tag>0) && (block->user>0))
+        {
+            if (block->posttag!=MEMORYPOSTTAG)
+                Error("Z_CheckHeap: Corrupted posttag\n");
+            if (block->pretag!=MEMORYPRETAG)
+                Error("Z_CheckHeap: Corrupted pretag\n");
+        }
+#endif
+    }
+}
+
+
+/*
+========================
+=
+= Z_ChangeTag
+=
+========================
+*/
+
+void Z_ChangeTag (void *ptr, int tag)
+{
+    memblock_t      *block;
+
+    block = (memblock_t *) ( (byte *)ptr - sizeof(memblock_t));
+    block->tag = tag;
+}
+
+/*
+========================
+=
+= Z_AvailHeap
+=
+========================
+*/
+
+int Z_AvailHeap ( void )
+{
+#ifdef DOS
+    union REGS zregs;
+    struct SREGS zsregs;
+
+
+    zregs.x.eax = 0x00000500;
+    memset( &zsregs, 0, sizeof(zsregs) );
+    zsregs.es = FP_SEG( &MemInfo );
+    zregs.x.edi = FP_OFF( &MemInfo );
+
+    int386x( DPMI_INT, &zregs, &zregs, &zsregs );
+
+    return ((int)MemInfo.LargestBlockAvail);
+#else
+    return MAXMEMORYSIZE;
+#endif
+}
+
+/*
+========================
+=
+= Z_Realloc
+=
+========================
+*/
+
+void Z_Realloc (void ** ptr, int newsize)
+{
+    memblock_t      *block;
+    void * newptr;
+    int oldsize;
+
+    block = (memblock_t *) ( (byte *)(*ptr) - sizeof(memblock_t));
+    oldsize = block->size;
+    newptr = SafeMalloc(newsize);
+    if (oldsize > newsize)
+    {
+        oldsize = newsize;
+    }
+    memcpy( newptr, *ptr, oldsize );
+    SafeFree( *ptr );
+    *ptr = newptr;
+}
+
--- /dev/null
+++ b/rott/z_zone.h
@@ -1,0 +1,79 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+//***************************************************************************
+//
+//    Z_Zone Memory management Constants
+//
+//***************************************************************************
+
+
+#ifndef _z_zone_public
+#define _z_zone_public
+
+
+extern int lowmemory;
+
+// tags < 100 are not overwritten until freed
+#define PU_STATIC               1                       // static entire execution time
+#define PU_GAME                 20                      // static until game completed
+#define PU_LEVELSTRUCT          49                      // start of static until level exited
+#define PU_LEVEL                50                      // start of static until level exited
+#define PU_LEVELEND             51                      // end of static until level exited
+
+// tags >= 100 are purgable whenever needed
+#define PU_PURGELEVEL           100
+#define PU_CACHE                101
+#define PU_CACHEWALLS           155
+#define PU_CACHESPRITES         154
+#define PU_CACHEBJWEAP          153
+#define PU_CACHEACTORS          152
+#define PU_CACHESOUNDS          120
+#define PU_FLAT                 102
+#define PU_PATCH                103
+#define PU_TEXTURE              104
+
+#define URGENTLEVELSTART PU_LEVEL
+
+//***************************************************************************
+//
+//    Z_ZONE.C - Carmack's Memory manager for protected mode
+//
+//***************************************************************************
+
+extern int zonememorystarted;
+
+void Z_Init (int size, int min);                // Starts up Memory manager (size is in bytes), (min is minimum requirement)
+void Z_Free (void *ptr);                        // Free a pointer in Z_Zone's domain
+void *Z_Malloc (int size, int tag, void *user); // Malloc You can pass a NULL user if the tag is < PU_PURGELEVEL
+void *Z_LevelMalloc (int size, int tag, void *user); // Level Malloc for level structures
+void Z_FreeTags (int lowtag, int hightag);      // Free a series of memory tags
+void Z_DumpHeap (int lowtag, int hightag);      // Dump the heap (for debugging purposes)
+void Z_CheckHeap (void);                        // Check the heap for corruption
+void Z_ChangeTag (void *ptr, int tag);          // Change the tag of a memory item
+int Z_HeapSize ( void );                        // Return the total heap size
+int Z_UsedHeap ( void );                        // Return used portion of heap size
+int Z_AvailHeap ( void );                       // Returns largest available contiguous block
+int Z_UsedStaticHeap ( void );                  // Returns amount of heap which is static ( < PURGELEVEL )
+void Z_ShutDown( void );
+int Z_GetSize (void *ptr);
+int Z_UsedLevelHeap ( void );
+void Z_Realloc (void ** ptr, int newsize);
+
+#endif