shithub: wl3d

Download patch

ref: 3b2f4d3df58368ce53243dd992612b9fcb7f0d1a
parent: 306bd81b628115bc2167ae40793b1c45365195ee
author: Konstantinn Bonnet <qu7uux@gmail.com>
date: Tue Nov 22 23:09:01 EST 2016

implement demo playback sans scaling and drawing walls/sprites

- drw: move drawing shit from rend.c to drw.c
- drw: fix fadein/fadeout skipping or repeating start or end steps
	. difference in implementation: ref steps from 0 to n-1 then sets final
	  palette directly on step n before immediately moving on; this steps
	  from 1 to n, for the same results
- drw: implement fizzlefade
- fs: don't load all maps on startup, load one on demand
- fs: add loading demo from file at startup
- input: get current state rather than accumulate results
- mn: rename to hub.c
- snd: positional sound attenuation
- snd: properly shunt everything if sound never got initialized
- snd: fix wrong pcm priority check
- wl3d: adapt somewhat to lower framerates by processing multiple tics in step()
- misc bugfixes; more documentation

--- a/act1.c
+++ /dev/null
@@ -1,900 +1,0 @@
-// WL_ACT1.C
-
-#include "WL_DEF.H"
-#pragma hdrstop
-
-/*
-=============================================================================
-
-							STATICS
-
-=============================================================================
-*/
-
-
-statobj_t	statobjlist[MAXSTATS],*laststatobj;
-
-
-struct
-{
-	s16int picnum;
-	stat_t	type;
-} statinfo[] =
-{
-{SPR_STAT_0},					// puddle          spr1v
-{SPR_STAT_1,block},				// Green Barrel    "
-{SPR_STAT_2,block},				// Table/chairs    "
-{SPR_STAT_3,block},				// Floor lamp      "
-{SPR_STAT_4},					// Chandelier      "
-{SPR_STAT_5,block},				// Hanged man      "
-{SPR_STAT_6,bo_alpo},			// Bad food        "
-{SPR_STAT_7,block},				// Red pillar      "
-//
-// NEW PAGE
-//
-{SPR_STAT_8,block},				// Tree            spr2v
-{SPR_STAT_9},					// Skeleton flat   "
-{SPR_STAT_10,block},			// Sink            " (SOD:gibs)
-{SPR_STAT_11,block},			// Potted plant    "
-{SPR_STAT_12,block},			// Urn             "
-{SPR_STAT_13,block},			// Bare table      "
-{SPR_STAT_14},					// Ceiling light   "
-#ifndef SPEAR
-{SPR_STAT_15},					// Kitchen stuff   "
-#else
-{SPR_STAT_15,block},			// Gibs!
-#endif
-//
-// NEW PAGE
-//
-{SPR_STAT_16,block},			// suit of armor   spr3v
-{SPR_STAT_17,block},			// Hanging cage    "
-{SPR_STAT_18,block},			// SkeletoninCage  "
-{SPR_STAT_19},					// Skeleton relax  "
-{SPR_STAT_20,bo_key1},			// Key 1           "
-{SPR_STAT_21,bo_key2},			// Key 2           "
-{SPR_STAT_22,block},			// stuff				(SOD:gibs)
-{SPR_STAT_23},					// stuff
-//
-// NEW PAGE
-//
-{SPR_STAT_24,bo_food}, 			// Good food       spr4v
-{SPR_STAT_25,bo_firstaid},		// First aid       "
-{SPR_STAT_26,bo_clip},			// Clip            "
-{SPR_STAT_27,bo_machinegun},	// Machine gun     "
-{SPR_STAT_28,bo_chaingun},		// Gatling gun     "
-{SPR_STAT_29,bo_cross},			// Cross           "
-{SPR_STAT_30,bo_chalice},		// Chalice         "
-{SPR_STAT_31,bo_bible},			// Bible           "
-//
-// NEW PAGE
-//
-{SPR_STAT_32,bo_crown},			// crown           spr5v
-{SPR_STAT_33,bo_fullheal},		// one up          "
-{SPR_STAT_34,bo_gibs},			// gibs            "
-{SPR_STAT_35,block},			// barrel          "
-{SPR_STAT_36,block},			// well            "
-{SPR_STAT_37,block},			// Empty well      "
-{SPR_STAT_38,bo_gibs},			// Gibs 2          "
-{SPR_STAT_39,block},			// flag				"
-//
-// NEW PAGE
-//
-#ifndef SPEAR
-{SPR_STAT_40,block},			// Call Apogee		spr7v
-#else
-{SPR_STAT_40},					// Red light
-#endif
-//
-// NEW PAGE
-//
-{SPR_STAT_41},					// junk            "
-{SPR_STAT_42},					// junk 		   "
-{SPR_STAT_43},					// junk            "
-#ifndef SPEAR
-{SPR_STAT_44},					// pots            "
-#else
-{SPR_STAT_44,block},			// Gibs!
-#endif
-{SPR_STAT_45,block},			// stove           " (SOD:gibs)
-{SPR_STAT_46,block},			// spears          " (SOD:gibs)
-{SPR_STAT_47},					// vines			"
-//
-// NEW PAGE
-//
-#ifdef SPEAR
-{SPR_STAT_48,block},			// marble pillar
-{SPR_STAT_49,bo_25clip},		// bonus 25 clip
-{SPR_STAT_50,block},			// truck
-{SPR_STAT_51,bo_spear},			// SPEAR OF DESTINY!
-#endif
-
-{SPR_STAT_26,bo_clip2},			// Clip            "
-{-1}							// terminator
-};
-
-/*
-===============
-=
-= InitStaticList
-=
-===============
-*/
-
-void InitStaticList (void)
-{
-	laststatobj = &statobjlist[0];
-}
-
-
-
-/*
-===============
-=
-= SpawnStatic
-=
-===============
-*/
-
-void SpawnStatic (s16int tilex, s16int tiley, s16int type)
-{
-	laststatobj->shapenum = statinfo[type].picnum;
-	laststatobj->tilex = tilex;
-	laststatobj->tiley = tiley;
-	laststatobj->visspot = &spotvis[tilex][tiley];
-
-	switch (statinfo[type].type)
-	{
-	case block:
-		(u16int)actorat[tilex][tiley] = 1;		// consider it a blocking tile
-	case dressing:
-		laststatobj->flags = 0;
-		break;
-
-	case	bo_cross:
-	case	bo_chalice:
-	case	bo_bible:
-	case	bo_crown:
-	case	bo_fullheal:
-		if (!loadedgame)
-		  gamestate.treasuretotal++;
-
-	case	bo_firstaid:
-	case	bo_key1:
-	case	bo_key2:
-	case	bo_key3:
-	case	bo_key4:
-	case	bo_clip:
-	case	bo_25clip:
-	case	bo_machinegun:
-	case	bo_chaingun:
-	case	bo_food:
-	case	bo_alpo:
-	case	bo_gibs:
-	case	bo_spear:
-		laststatobj->flags = FL_BONUS;
-		laststatobj->itemnumber = statinfo[type].type;
-		break;
-	}
-
-	laststatobj++;
-
-	if (laststatobj == &statobjlist[MAXSTATS])
-		Quit ("Too many static objects!\n");
-}
-
-
-/*
-===============
-=
-= PlaceItemType
-=
-= Called during game play to drop actors' items.  It finds the proper
-= item number based on the item type (bo_???).  If there are no free item
-= spots, nothing is done.
-=
-===============
-*/
-
-void PlaceItemType (s16int itemtype, s16int tilex, s16int tiley)
-{
-	s16int type;
-	statobj_t	*spot;
-
-//
-// find the item number
-//
-	for (type=0 ;  ; type++)
-	{
-		if (statinfo[type].picnum == -1)		// end of list
-			Quit ("PlaceItemType: couldn't find type!");
-		if (statinfo[type].type == itemtype)
-			break;
-	}
-
-//
-// find a spot in statobjlist to put it in
-//
-	for (spot=&statobjlist[0] ; ; spot++)
-	{
-		if (spot==laststatobj)
-		{
-			if (spot == &statobjlist[MAXSTATS])
-				return;							// no free spots
-			laststatobj++;						// space at end
-			break;
-		}
-
-		if (spot->shapenum == -1)				// -1 is a free spot
-			break;
-	}
-//
-// place it
-//
-	spot->shapenum = statinfo[type].picnum;
-	spot->tilex = tilex;
-	spot->tiley = tiley;
-	spot->visspot = &spotvis[tilex][tiley];
-	spot->flags = FL_BONUS;
-	spot->itemnumber = statinfo[type].type;
-}
-
-
-
-/*
-=============================================================================
-
-							DOORS
-
-doorobjlist[] holds most of the information for the doors
-
-doorposition[] holds the amount the door is open, ranging from 0 to 0xffff
-	this is directly accessed by AsmRefresh during rendering
-
-The number of doors is limited to 64 because a spot in tilemap holds the
-	door number in the low 6 bits, with the high bit meaning a door center
-	and bit 6 meaning a door side tile
-
-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.
-
-=============================================================================
-*/
-
-#define DOORWIDTH	0x7800
-#define OPENTICS	300
-
-doorobj_t	doorobjlist[MAXDOORS],*lastdoorobj;
-s16int doornum;
-
-u16int	doorposition[MAXDOORS];		// leading edge of door 0=closed
-										// 0xffff = fully open
-
-u8int far areaconnect[NUMAREAS][NUMAREAS];
-
-int		areabyplayer[NUMAREAS];
-
-
-/*
-==============
-=
-= ConnectAreas
-=
-= Scans outward from playerarea, marking all connected areas
-=
-==============
-*/
-
-void RecursiveConnect (s16int areanumber)
-{
-	s16int	i;
-
-	for (i=0;i<NUMAREAS;i++)
-	{
-		if (areaconnect[areanumber][i] && !areabyplayer[i])
-		{
-			areabyplayer[i] = true;
-			RecursiveConnect (i);
-		}
-	}
-}
-
-
-void ConnectAreas (void)
-{
-	memset (areabyplayer,0,sizeof(areabyplayer));
-	areabyplayer[player->areanumber] = true;
-	RecursiveConnect (player->areanumber);
-}
-
-
-void InitAreas (void)
-{
-	memset (areabyplayer,0,sizeof(areabyplayer));
-	areabyplayer[player->areanumber] = true;
-}
-
-
-
-/*
-===============
-=
-= InitDoorList
-=
-===============
-*/
-
-void InitDoorList (void)
-{
-	memset (areabyplayer,0,sizeof(areabyplayer));
-	_fmemset (areaconnect,0,sizeof(areaconnect));
-
-	lastdoorobj = &doorobjlist[0];
-	doornum = 0;
-}
-
-
-/*
-===============
-=
-= SpawnDoor
-=
-===============
-*/
-
-void SpawnDoor (s16int tilex, s16int tiley, int vertical, s16int lock)
-{
-	s16int	areanumber;
-	u16int	far *map;
-
-	if (doornum==64)
-		Quit ("64+ doors on level!");
-
-	doorposition[doornum] = 0;		// doors start out fully closed
-	lastdoorobj->tilex = tilex;
-	lastdoorobj->tiley = tiley;
-	lastdoorobj->vertical = vertical;
-	lastdoorobj->lock = lock;
-	lastdoorobj->action = dr_closed;
-
-	(u16int)actorat[tilex][tiley] = doornum | 0x80;	// consider it a solid wall
-
-//
-// make the door tile a special tile, and mark the adjacent tiles
-// for door sides
-//
-	tilemap[tilex][tiley] = doornum | 0x80;
-	map = mapsegs[0] + farmapylookup[tiley]+tilex;
-	if (vertical)
-	{
-		*map = *(map-1);                        // set area number
-		tilemap[tilex][tiley-1] |= 0x40;
-		tilemap[tilex][tiley+1] |= 0x40;
-	}
-	else
-	{
-		*map = *(map-mapwidth);					// set area number
-		tilemap[tilex-1][tiley] |= 0x40;
-		tilemap[tilex+1][tiley] |= 0x40;
-	}
-
-	doornum++;
-	lastdoorobj++;
-}
-
-//===========================================================================
-
-/*
-=====================
-=
-= OpenDoor
-=
-=====================
-*/
-
-void OpenDoor (s16int door)
-{
-	if (doorobjlist[door].action == dr_open)
-		doorobjlist[door].ticcount = 0;			// reset open time
-	else
-		doorobjlist[door].action = dr_opening;	// start it opening
-}
-
-
-/*
-=====================
-=
-= CloseDoor
-=
-=====================
-*/
-
-void CloseDoor (s16int door)
-{
-	s16int	tilex,tiley,area;
-	objtype *check;
-
-//
-// don't close on anything solid
-//
-	tilex = doorobjlist[door].tilex;
-	tiley = doorobjlist[door].tiley;
-
-	if (actorat[tilex][tiley])
-		return;
-
-	if (player->tilex == tilex && player->tiley == tiley)
-		return;
-
-	if (doorobjlist[door].vertical)
-	{
-		if ( player->tiley == tiley )
-		{
-			if ( ((player->x+MINDIST) >>TILESHIFT) == tilex )
-				return;
-			if ( ((player->x-MINDIST) >>TILESHIFT) == tilex )
-				return;
-		}
-		check = actorat[tilex-1][tiley];
-		if (check && ((check->x+MINDIST) >> TILESHIFT) == tilex )
-			return;
-		check = actorat[tilex+1][tiley];
-		if (check && ((check->x-MINDIST) >> TILESHIFT) == tilex )
-			return;
-	}
-	else if (!doorobjlist[door].vertical)
-	{
-		if (player->tilex == tilex)
-		{
-			if ( ((player->y+MINDIST) >>TILESHIFT) == tiley )
-				return;
-			if ( ((player->y-MINDIST) >>TILESHIFT) == tiley )
-				return;
-		}
-		check = actorat[tilex][tiley-1];
-		if (check && ((check->y+MINDIST) >> TILESHIFT) == tiley )
-			return;
-		check = actorat[tilex][tiley+1];
-		if (check && ((check->y-MINDIST) >> TILESHIFT) == tiley )
-			return;
-	}
-
-
-//
-// play door sound if in a connected area
-//
-	area = *(mapsegs[0] + farmapylookup[doorobjlist[door].tiley]
-			+doorobjlist[door].tilex)-AREATILE;
-	if (areabyplayer[area])
-	{
-		PlaySoundLocTile(Sclosedoor,doorobjlist[door].tilex,doorobjlist[door].tiley);	// JAB
-	}
-
-	doorobjlist[door].action = dr_closing;
-//
-// make the door space solid
-//
-	(u16int)actorat[tilex][tiley]
-		= door | 0x80;
-}
-
-
-
-/*
-=====================
-=
-= OperateDoor
-=
-= The player wants to change the door's direction
-=
-=====================
-*/
-
-void OperateDoor (s16int door)
-{
-	s16int	lock;
-
-	lock = doorobjlist[door].lock;
-	if (lock >= dr_lock1 && lock <= dr_lock4)
-	{
-		if ( ! (gamestate.keys & (1 << (lock-dr_lock1) ) ) )
-		{
-			SD_PlaySound (Snoway);		// locked
-			return;
-		}
-	}
-
-	switch (doorobjlist[door].action)
-	{
-	case dr_closed:
-	case dr_closing:
-		OpenDoor (door);
-		break;
-	case dr_open:
-	case dr_opening:
-		CloseDoor (door);
-		break;
-	}
-}
-
-
-//===========================================================================
-
-/*
-===============
-=
-= DoorOpen
-=
-= Close the door after three seconds
-=
-===============
-*/
-
-void DoorOpen (s16int door)
-{
-	if ( (doorobjlist[door].ticcount += tics) >= OPENTICS)
-		CloseDoor (door);
-}
-
-
-
-/*
-===============
-=
-= DoorOpening
-=
-===============
-*/
-
-void DoorOpening (s16int door)
-{
-	s16int		area1,area2;
-	u16int	far	*map;
-	s32int	position;
-
-	position = doorposition[door];
-	if (!position)
-	{
-	//
-	// door is just starting to open, so connect the areas
-	//
-		map = mapsegs[0] + farmapylookup[doorobjlist[door].tiley]
-			+doorobjlist[door].tilex;
-
-		if (doorobjlist[door].vertical)
-		{
-			area1 =	*(map+1);
-			area2 =	*(map-1);
-		}
-		else
-		{
-			area1 =	*(map-mapwidth);
-			area2 =	*(map+mapwidth);
-		}
-		area1 -= AREATILE;
-		area2 -= AREATILE;
-		areaconnect[area1][area2]++;
-		areaconnect[area2][area1]++;
-		ConnectAreas ();
-		if (areabyplayer[area1])
-		{
-			PlaySoundLocTile(Sopendoor,doorobjlist[door].tilex,doorobjlist[door].tiley);	// JAB
-		}
-	}
-
-//
-// slide the door by an adaptive amount
-//
-	position += tics<<10;
-	if (position >= 0xffff)
-	{
-	//
-	// door is all the way open
-	//
-		position = 0xffff;
-		doorobjlist[door].ticcount = 0;
-		doorobjlist[door].action = dr_open;
-		actorat[doorobjlist[door].tilex][doorobjlist[door].tiley] = 0;
-	}
-
-	doorposition[door] = position;
-}
-
-
-/*
-===============
-=
-= DoorClosing
-=
-===============
-*/
-
-void DoorClosing (s16int door)
-{
-	s16int		area1,area2,move;
-	u16int	far	*map;
-	s32int	position;
-	s16int		tilex,tiley;
-
-	tilex = doorobjlist[door].tilex;
-	tiley = doorobjlist[door].tiley;
-
-	if ( ((u16int)actorat[tilex][tiley] != (door | 0x80))
-	|| (player->tilex == tilex && player->tiley == tiley) )
-	{			// something got inside the door
-		OpenDoor (door);
-		return;
-	};
-
-	position = doorposition[door];
-
-//
-// slide the door by an adaptive amount
-//
-	position -= tics<<10;
-	if (position <= 0)
-	{
-	//
-	// door is closed all the way, so disconnect the areas
-	//
-		position = 0;
-
-		doorobjlist[door].action = dr_closed;
-
-		map = mapsegs[0] + farmapylookup[doorobjlist[door].tiley]
-			+doorobjlist[door].tilex;
-
-		if (doorobjlist[door].vertical)
-		{
-			area1 =	*(map+1);
-			area2 =	*(map-1);
-		}
-		else
-		{
-			area1 =	*(map-mapwidth);
-			area2 =	*(map+mapwidth);
-		}
-		area1 -= AREATILE;
-		area2 -= AREATILE;
-		areaconnect[area1][area2]--;
-		areaconnect[area2][area1]--;
-
-		ConnectAreas ();
-	}
-
-	doorposition[door] = position;
-}
-
-
-
-
-/*
-=====================
-=
-= MoveDoors
-=
-= Called from PlayLoop
-=
-=====================
-*/
-
-void MoveDoors (void)
-{
-	s16int		door;
-
-	if (gamestate.victoryflag)		// don't move door during victory sequence
-		return;
-
-	for (door = 0 ; door < doornum ; door++)
-		switch (doorobjlist[door].action)
-		{
-		case dr_open:
-			DoorOpen (door);
-			break;
-
-		case dr_opening:
-			DoorOpening(door);
-			break;
-
-		case dr_closing:
-			DoorClosing(door);
-			break;
-		}
-}
-
-
-/*
-=============================================================================
-
-						PUSHABLE WALLS
-
-=============================================================================
-*/
-
-u16int	pwallstate;
-u16int	pwallpos;			// amount a pushable wall has been moved (0-63)
-u16int	pwallx,pwally;
-s16int			pwalldir;
-
-/*
-===============
-=
-= PushWall
-=
-===============
-*/
-
-void PushWall (s16int checkx, s16int checky, s16int dir)
-{
-	s16int		oldtile;
-
-	if (pwallstate)
-	  return;
-
-
-	oldtile = tilemap[checkx][checky];
-	if (!oldtile)
-		return;
-
-	switch (dir)
-	{
-	case di_north:
-		if (actorat[checkx][checky-1])
-		{
-			SD_PlaySound (Snoway);
-			return;
-		}
-		(u16int)actorat[checkx][checky-1] =
-		tilemap[checkx][checky-1] = oldtile;
-		break;
-
-	case di_east:
-		if (actorat[checkx+1][checky])
-		{
-			SD_PlaySound (Snoway);
-			return;
-		}
-		(u16int)actorat[checkx+1][checky] =
-		tilemap[checkx+1][checky] = oldtile;
-		break;
-
-	case di_south:
-		if (actorat[checkx][checky+1])
-		{
-			SD_PlaySound (Snoway);
-			return;
-		}
-		(u16int)actorat[checkx][checky+1] =
-		tilemap[checkx][checky+1] = oldtile;
-		break;
-
-	case di_west:
-		if (actorat[checkx-1][checky])
-		{
-			SD_PlaySound (Snoway);
-			return;
-		}
-		(u16int)actorat[checkx-1][checky] =
-		tilemap[checkx-1][checky] = oldtile;
-		break;
-	}
-
-	gamestate.secretcount++;
-	pwallx = checkx;
-	pwally = checky;
-	pwalldir = dir;
-	pwallstate = 1;
-	pwallpos = 0;
-	tilemap[pwallx][pwally] |= 0xc0;
-	*(mapsegs[1]+farmapylookup[pwally]+pwallx) = 0;	// remove P tile info
-
-	SD_PlaySound (Spushwall);
-}
-
-
-
-/*
-=================
-=
-= MovePWalls
-=
-=================
-*/
-
-void MovePWalls (void)
-{
-	s16int		oldblock,oldtile;
-
-	if (!pwallstate)
-		return;
-
-	oldblock = pwallstate/128;
-
-	pwallstate += tics;
-
-	if (pwallstate/128 != oldblock)
-	{
-	// block crossed into a new block
-		oldtile = tilemap[pwallx][pwally] & 63;
-
-		//
-		// the tile can now be walked into
-		//
-		tilemap[pwallx][pwally] = 0;
-		(u16int)actorat[pwallx][pwally] = 0;
-		*(mapsegs[0]+farmapylookup[pwally]+pwallx) = player->areanumber+AREATILE;
-
-		//
-		// see if it should be pushed farther
-		//
-		if (pwallstate>256)
-		{
-		//
-		// the block has been pushed two tiles
-		//
-			pwallstate = 0;
-			return;
-		}
-		else
-		{
-			switch (pwalldir)
-			{
-			case di_north:
-				pwally--;
-				if (actorat[pwallx][pwally-1])
-				{
-					pwallstate = 0;
-					return;
-				}
-				(u16int)actorat[pwallx][pwally-1] =
-				tilemap[pwallx][pwally-1] = oldtile;
-				break;
-
-			case di_east:
-				pwallx++;
-				if (actorat[pwallx+1][pwally])
-				{
-					pwallstate = 0;
-					return;
-				}
-				(u16int)actorat[pwallx+1][pwally] =
-				tilemap[pwallx+1][pwally] = oldtile;
-				break;
-
-			case di_south:
-				pwally++;
-				if (actorat[pwallx][pwally+1])
-				{
-					pwallstate = 0;
-					return;
-				}
-				(u16int)actorat[pwallx][pwally+1] =
-				tilemap[pwallx][pwally+1] = oldtile;
-				break;
-
-			case di_west:
-				pwallx--;
-				if (actorat[pwallx-1][pwally])
-				{
-					pwallstate = 0;
-					return;
-				}
-				(u16int)actorat[pwallx-1][pwally] =
-				tilemap[pwallx-1][pwally] = oldtile;
-				break;
-			}
-
-			tilemap[pwallx][pwally] = oldtile | 0xc0;
-		}
-	}
-
-
-	pwallpos = (pwallstate/2)&63;
-
-}
-
--- a/act2.c
+++ /dev/null
@@ -1,3865 +1,0 @@
-// WL_ACT2.C
-
-#include "WL_DEF.H"
-#pragma hdrstop
-
-/*
-=============================================================================
-
-						 LOCAL CONSTANTS
-
-=============================================================================
-*/
-
-#define PROJECTILESIZE	0xc000l
-
-#define BJRUNSPEED	2048
-#define BJJUMPSPEED	680
-
-
-/*
-=============================================================================
-
-						 GLOBAL VARIABLES
-
-=============================================================================
-*/
-
-
-
-/*
-=============================================================================
-
-						 LOCAL VARIABLES
-
-=============================================================================
-*/
-
-
-dirtype dirtable[9] = {northwest,north,northeast,west,nodir,east,
-	southwest,south,southeast};
-
-s16int	starthitpoints[4][NUMENEMIES] =
-	 //
-	 // BABY MODE
-	 //
-	 {
-	 {25,	// guards
-	  50,	// officer
-	  100,	// SS
-	  1,	// dogs
-	  850,	// Hans
-	  850,	// Schabbs
-	  200,	// fake hitler
-	  800,	// mecha hitler
-	  45,	// mutants
-	  25,	// ghosts
-	  25,	// ghosts
-	  25,	// ghosts
-	  25,	// ghosts
-
-	  850,	// Gretel
-	  850,	// Gift
-	  850,	// Fat
-	  5,	// en_spectre,
-	  1450,	// en_angel,
-	  850,	// en_trans,
-	  1050,	// en_uber,
-	  950,	// en_will,
-	  1250	// en_death
-	  },
-	 //
-	 // DON'T HURT ME MODE
-	 //
-	 {25,	// guards
-	  50,	// officer
-	  100,	// SS
-	  1,	// dogs
-	  950,	// Hans
-	  950,	// Schabbs
-	  300,	// fake hitler
-	  950,	// mecha hitler
-	  55,	// mutants
-	  25,	// ghosts
-	  25,	// ghosts
-	  25,	// ghosts
-	  25,	// ghosts
-
-	  950,	// Gretel
-	  950,	// Gift
-	  950,	// Fat
-	  10,	// en_spectre,
-	  1550,	// en_angel,
-	  950,	// en_trans,
-	  1150,	// en_uber,
-	  1050,	// en_will,
-	  1350	// en_death
-	  },
-	 //
-	 // BRING 'EM ON MODE
-	 //
-	 {25,	// guards
-	  50,	// officer
-	  100,	// SS
-	  1,	// dogs
-
-	  1050,	// Hans
-	  1550,	// Schabbs
-	  400,	// fake hitler
-	  1050,	// mecha hitler
-
-	  55,	// mutants
-	  25,	// ghosts
-	  25,	// ghosts
-	  25,	// ghosts
-	  25,	// ghosts
-
-	  1050,	// Gretel
-	  1050,	// Gift
-	  1050,	// Fat
-	  15,	// en_spectre,
-	  1650,	// en_angel,
-	  1050,	// en_trans,
-	  1250,	// en_uber,
-	  1150,	// en_will,
-	  1450	// en_death
-	  },
-	 //
-	 // DEATH INCARNATE MODE
-	 //
-	 {25,	// guards
-	  50,	// officer
-	  100,	// SS
-	  1,	// dogs
-
-	  1200,	// Hans
-	  2400,	// Schabbs
-	  500,	// fake hitler
-	  1200,	// mecha hitler
-
-	  65,	// mutants
-	  25,	// ghosts
-	  25,	// ghosts
-	  25,	// ghosts
-	  25,	// ghosts
-
-	  1200,	// Gretel
-	  1200,	// Gift
-	  1200,	// Fat
-	  25,	// en_spectre,
-	  2000,	// en_angel,
-	  1200,	// en_trans,
-	  1400,	// en_uber,
-	  1300,	// en_will,
-	  1600	// en_death
-	  }}
-	  ;
-
-void	A_StartDeathCam (objtype *ob);
-
-
-void	T_Path (objtype *ob);
-void	T_Shoot (objtype *ob);
-void	T_Bite (objtype *ob);
-void	T_DogChase (objtype *ob);
-void	T_Chase (objtype *ob);
-void	T_Projectile (objtype *ob);
-void	T_Stand (objtype *ob);
-
-void A_DeathScream (objtype *ob);
-
-extern	statetype s_rocket;
-extern	statetype s_smoke1;
-extern	statetype s_smoke2;
-extern	statetype s_smoke3;
-extern	statetype s_smoke4;
-extern	statetype s_boom2;
-extern	statetype s_boom3;
-
-void A_Smoke (objtype *ob);
-
-statetype s_rocket	 	= {true,SPR_ROCKET_1,3,T_Projectile,A_Smoke,&s_rocket};
-statetype s_smoke1	 	= {false,SPR_SMOKE_1,3,NULL,NULL,&s_smoke2};
-statetype s_smoke2	 	= {false,SPR_SMOKE_2,3,NULL,NULL,&s_smoke3};
-statetype s_smoke3	 	= {false,SPR_SMOKE_3,3,NULL,NULL,&s_smoke4};
-statetype s_smoke4	 	= {false,SPR_SMOKE_4,3,NULL,NULL,NULL};
-
-statetype s_boom1	 	= {false,SPR_BOOM_1,6,NULL,NULL,&s_boom2};
-statetype s_boom2	 	= {false,SPR_BOOM_2,6,NULL,NULL,&s_boom3};
-statetype s_boom3	 	= {false,SPR_BOOM_3,6,NULL,NULL,NULL};
-
-#ifdef SPEAR
-
-extern	statetype s_hrocket;
-extern	statetype s_hsmoke1;
-extern	statetype s_hsmoke2;
-extern	statetype s_hsmoke3;
-extern	statetype s_hsmoke4;
-extern	statetype s_hboom2;
-extern	statetype s_hboom3;
-
-void A_Smoke (objtype *ob);
-
-statetype s_hrocket	 	= {true,SPR_HROCKET_1,3,T_Projectile,A_Smoke,&s_hrocket};
-statetype s_hsmoke1	 	= {false,SPR_HSMOKE_1,3,NULL,NULL,&s_hsmoke2};
-statetype s_hsmoke2	 	= {false,SPR_HSMOKE_2,3,NULL,NULL,&s_hsmoke3};
-statetype s_hsmoke3	 	= {false,SPR_HSMOKE_3,3,NULL,NULL,&s_hsmoke4};
-statetype s_hsmoke4	 	= {false,SPR_HSMOKE_4,3,NULL,NULL,NULL};
-
-statetype s_hboom1	 	= {false,SPR_HBOOM_1,6,NULL,NULL,&s_hboom2};
-statetype s_hboom2	 	= {false,SPR_HBOOM_2,6,NULL,NULL,&s_hboom3};
-statetype s_hboom3	 	= {false,SPR_HBOOM_3,6,NULL,NULL,NULL};
-
-#endif
-
-void	T_Schabb (objtype *ob);
-void	T_SchabbThrow (objtype *ob);
-void	T_Fake (objtype *ob);
-void	T_FakeFire (objtype *ob);
-void	T_Ghosts (objtype *ob);
-
-void A_Slurpie (objtype *ob);
-void A_HitlerMorph (objtype *ob);
-void A_MechaSound (objtype *ob);
-
-/*
-=================
-=
-= A_Smoke
-=
-=================
-*/
-
-void A_Smoke (objtype *ob)
-{
-	GetNewActor ();
-#ifdef SPEAR
-	if (ob->obclass == hrocketobj)
-		new->state = &s_hsmoke1;
-	else
-#endif
-		new->state = &s_smoke1;
-	new->ticcount = 6;
-
-	new->tilex = ob->tilex;
-	new->tiley = ob->tiley;
-	new->x = ob->x;
-	new->y = ob->y;
-	new->obclass = inertobj;
-	new->active = true;
-
-	new->flags = FL_NEVERMARK;
-}
-
-
-/*
-===================
-=
-= ProjectileTryMove
-=
-= returns true if move ok
-===================
-*/
-
-#define PROJSIZE	0x2000
-
-int ProjectileTryMove (objtype *ob)
-{
-	s16int			xl,yl,xh,yh,x,y;
-	objtype		*check;
-	s32int		deltax,deltay;
-
-	xl = (ob->x-PROJSIZE) >>TILESHIFT;
-	yl = (ob->y-PROJSIZE) >>TILESHIFT;
-
-	xh = (ob->x+PROJSIZE) >>TILESHIFT;
-	yh = (ob->y+PROJSIZE) >>TILESHIFT;
-
-//
-// check for solid walls
-//
-	for (y=yl;y<=yh;y++)
-		for (x=xl;x<=xh;x++)
-		{
-			check = actorat[x][y];
-			if (check && check<objlist)
-				return false;
-		}
-
-	return true;
-}
-
-
-
-/*
-=================
-=
-= T_Projectile
-=
-=================
-*/
-
-void T_Projectile (objtype *ob)
-{
-	s32int	deltax,deltay;
-	s16int		damage;
-	s32int	speed;
-
-	speed = (s32int)ob->speed*tics;
-
-	deltax = FixedByFrac(speed,costable[ob->angle]);
-	deltay = -FixedByFrac(speed,sintable[ob->angle]);
-
-	if (deltax>0x10000l)
-		deltax = 0x10000l;
-	if (deltay>0x10000l)
-		deltay = 0x10000l;
-
-	ob->x += deltax;
-	ob->y += deltay;
-
-	deltax = LABS(ob->x - player->x);
-	deltay = LABS(ob->y - player->y);
-
-	if (!ProjectileTryMove (ob))
-	{
-		if (ob->obclass == rocketobj)
-		{
-			PlaySoundLocActor(Smissilehit,ob);
-			ob->state = &s_boom1;
-		}
-#ifdef SPEAR
-		else if (ob->obclass == hrocketobj)
-		{
-			PlaySoundLocActor(Srockethit,ob);
-			ob->state = &s_hboom1;
-		}
-#endif
-		else
-			ob->state = NULL;		// mark for removal
-
-		return;
-	}
-
-	if (deltax < PROJECTILESIZE && deltay < PROJECTILESIZE)
-	{	// hit the player
-		switch (ob->obclass)
-		{
-		case needleobj:
-			damage = (US_RndT() >>3) + 20;
-			break;
-		case rocketobj:
-		case hrocketobj:
-		case sparkobj:
-			damage = (US_RndT() >>3) + 30;
-			break;
-		case fireobj:
-			damage = (US_RndT() >>3);
-			break;
-		}
-
-		TakeDamage (damage,ob);
-		ob->state = NULL;		// mark for removal
-		return;
-	}
-
-	ob->tilex = ob->x >> TILESHIFT;
-	ob->tiley = ob->y >> TILESHIFT;
-
-}
-
-
-
-
-/*
-=============================================================================
-
-							GUARD
-
-=============================================================================
-*/
-
-//
-// guards
-//
-
-extern	statetype s_grdstand;
-
-extern	statetype s_grdpath1;
-extern	statetype s_grdpath1s;
-extern	statetype s_grdpath2;
-extern	statetype s_grdpath3;
-extern	statetype s_grdpath3s;
-extern	statetype s_grdpath4;
-
-extern	statetype s_grdpain;
-extern	statetype s_grdpain1;
-
-extern	statetype s_grdgiveup;
-
-extern	statetype s_grdshoot1;
-extern	statetype s_grdshoot2;
-extern	statetype s_grdshoot3;
-extern	statetype s_grdshoot4;
-
-extern	statetype s_grdchase1;
-extern	statetype s_grdchase1s;
-extern	statetype s_grdchase2;
-extern	statetype s_grdchase3;
-extern	statetype s_grdchase3s;
-extern	statetype s_grdchase4;
-
-extern	statetype s_grddie1;
-extern	statetype s_grddie1d;
-extern	statetype s_grddie2;
-extern	statetype s_grddie3;
-extern	statetype s_grddie4;
-
-statetype s_grdstand	= {true,SPR_GRD_S_1,0,T_Stand,NULL,&s_grdstand};
-
-statetype s_grdpath1 	= {true,SPR_GRD_W1_1,20,T_Path,NULL,&s_grdpath1s};
-statetype s_grdpath1s 	= {true,SPR_GRD_W1_1,5,NULL,NULL,&s_grdpath2};
-statetype s_grdpath2 	= {true,SPR_GRD_W2_1,15,T_Path,NULL,&s_grdpath3};
-statetype s_grdpath3 	= {true,SPR_GRD_W3_1,20,T_Path,NULL,&s_grdpath3s};
-statetype s_grdpath3s 	= {true,SPR_GRD_W3_1,5,NULL,NULL,&s_grdpath4};
-statetype s_grdpath4 	= {true,SPR_GRD_W4_1,15,T_Path,NULL,&s_grdpath1};
-
-statetype s_grdpain 	= {2,SPR_GRD_PAIN_1,10,NULL,NULL,&s_grdchase1};
-statetype s_grdpain1 	= {2,SPR_GRD_PAIN_2,10,NULL,NULL,&s_grdchase1};
-
-statetype s_grdshoot1 	= {false,SPR_GRD_SHOOT1,20,NULL,NULL,&s_grdshoot2};
-statetype s_grdshoot2 	= {false,SPR_GRD_SHOOT2,20,NULL,T_Shoot,&s_grdshoot3};
-statetype s_grdshoot3 	= {false,SPR_GRD_SHOOT3,20,NULL,NULL,&s_grdchase1};
-
-statetype s_grdchase1 	= {true,SPR_GRD_W1_1,10,T_Chase,NULL,&s_grdchase1s};
-statetype s_grdchase1s 	= {true,SPR_GRD_W1_1,3,NULL,NULL,&s_grdchase2};
-statetype s_grdchase2 	= {true,SPR_GRD_W2_1,8,T_Chase,NULL,&s_grdchase3};
-statetype s_grdchase3 	= {true,SPR_GRD_W3_1,10,T_Chase,NULL,&s_grdchase3s};
-statetype s_grdchase3s 	= {true,SPR_GRD_W3_1,3,NULL,NULL,&s_grdchase4};
-statetype s_grdchase4 	= {true,SPR_GRD_W4_1,8,T_Chase,NULL,&s_grdchase1};
-
-statetype s_grddie1		= {false,SPR_GRD_DIE_1,15,NULL,A_DeathScream,&s_grddie2};
-statetype s_grddie2		= {false,SPR_GRD_DIE_2,15,NULL,NULL,&s_grddie3};
-statetype s_grddie3		= {false,SPR_GRD_DIE_3,15,NULL,NULL,&s_grddie4};
-statetype s_grddie4		= {false,SPR_GRD_DEAD,0,NULL,NULL,&s_grddie4};
-
-
-#ifndef SPEAR
-//
-// ghosts
-//
-extern	statetype s_blinkychase1;
-extern	statetype s_blinkychase2;
-extern	statetype s_inkychase1;
-extern	statetype s_inkychase2;
-extern	statetype s_pinkychase1;
-extern	statetype s_pinkychase2;
-extern	statetype s_clydechase1;
-extern	statetype s_clydechase2;
-
-statetype s_blinkychase1 	= {false,SPR_BLINKY_W1,10,T_Ghosts,NULL,&s_blinkychase2};
-statetype s_blinkychase2 	= {false,SPR_BLINKY_W2,10,T_Ghosts,NULL,&s_blinkychase1};
-
-statetype s_inkychase1 		= {false,SPR_INKY_W1,10,T_Ghosts,NULL,&s_inkychase2};
-statetype s_inkychase2 		= {false,SPR_INKY_W2,10,T_Ghosts,NULL,&s_inkychase1};
-
-statetype s_pinkychase1 	= {false,SPR_PINKY_W1,10,T_Ghosts,NULL,&s_pinkychase2};
-statetype s_pinkychase2 	= {false,SPR_PINKY_W2,10,T_Ghosts,NULL,&s_pinkychase1};
-
-statetype s_clydechase1 	= {false,SPR_CLYDE_W1,10,T_Ghosts,NULL,&s_clydechase2};
-statetype s_clydechase2 	= {false,SPR_CLYDE_W2,10,T_Ghosts,NULL,&s_clydechase1};
-#endif
-
-//
-// dogs
-//
-
-extern	statetype s_dogpath1;
-extern	statetype s_dogpath1s;
-extern	statetype s_dogpath2;
-extern	statetype s_dogpath3;
-extern	statetype s_dogpath3s;
-extern	statetype s_dogpath4;
-
-extern	statetype s_dogjump1;
-extern	statetype s_dogjump2;
-extern	statetype s_dogjump3;
-extern	statetype s_dogjump4;
-extern	statetype s_dogjump5;
-
-extern	statetype s_dogchase1;
-extern	statetype s_dogchase1s;
-extern	statetype s_dogchase2;
-extern	statetype s_dogchase3;
-extern	statetype s_dogchase3s;
-extern	statetype s_dogchase4;
-
-extern	statetype s_dogdie1;
-extern	statetype s_dogdie1d;
-extern	statetype s_dogdie2;
-extern	statetype s_dogdie3;
-extern	statetype s_dogdead;
-
-statetype s_dogpath1 	= {true,SPR_DOG_W1_1,20,T_Path,NULL,&s_dogpath1s};
-statetype s_dogpath1s 	= {true,SPR_DOG_W1_1,5,NULL,NULL,&s_dogpath2};
-statetype s_dogpath2 	= {true,SPR_DOG_W2_1,15,T_Path,NULL,&s_dogpath3};
-statetype s_dogpath3 	= {true,SPR_DOG_W3_1,20,T_Path,NULL,&s_dogpath3s};
-statetype s_dogpath3s 	= {true,SPR_DOG_W3_1,5,NULL,NULL,&s_dogpath4};
-statetype s_dogpath4 	= {true,SPR_DOG_W4_1,15,T_Path,NULL,&s_dogpath1};
-
-statetype s_dogjump1 	= {false,SPR_DOG_JUMP1,10,NULL,NULL,&s_dogjump2};
-statetype s_dogjump2 	= {false,SPR_DOG_JUMP2,10,NULL,T_Bite,&s_dogjump3};
-statetype s_dogjump3 	= {false,SPR_DOG_JUMP3,10,NULL,NULL,&s_dogjump4};
-statetype s_dogjump4 	= {false,SPR_DOG_JUMP1,10,NULL,NULL,&s_dogjump5};
-statetype s_dogjump5 	= {false,SPR_DOG_W1_1,10,NULL,NULL,&s_dogchase1};
-
-statetype s_dogchase1 	= {true,SPR_DOG_W1_1,10,T_DogChase,NULL,&s_dogchase1s};
-statetype s_dogchase1s 	= {true,SPR_DOG_W1_1,3,NULL,NULL,&s_dogchase2};
-statetype s_dogchase2 	= {true,SPR_DOG_W2_1,8,T_DogChase,NULL,&s_dogchase3};
-statetype s_dogchase3 	= {true,SPR_DOG_W3_1,10,T_DogChase,NULL,&s_dogchase3s};
-statetype s_dogchase3s 	= {true,SPR_DOG_W3_1,3,NULL,NULL,&s_dogchase4};
-statetype s_dogchase4 	= {true,SPR_DOG_W4_1,8,T_DogChase,NULL,&s_dogchase1};
-
-statetype s_dogdie1		= {false,SPR_DOG_DIE_1,15,NULL,A_DeathScream,&s_dogdie2};
-statetype s_dogdie2		= {false,SPR_DOG_DIE_2,15,NULL,NULL,&s_dogdie3};
-statetype s_dogdie3		= {false,SPR_DOG_DIE_3,15,NULL,NULL,&s_dogdead};
-statetype s_dogdead		= {false,SPR_DOG_DEAD,15,NULL,NULL,&s_dogdead};
-
-
-//
-// officers
-//
-
-extern	statetype s_ofcstand;
-
-extern	statetype s_ofcpath1;
-extern	statetype s_ofcpath1s;
-extern	statetype s_ofcpath2;
-extern	statetype s_ofcpath3;
-extern	statetype s_ofcpath3s;
-extern	statetype s_ofcpath4;
-
-extern	statetype s_ofcpain;
-extern	statetype s_ofcpain1;
-
-extern	statetype s_ofcgiveup;
-
-extern	statetype s_ofcshoot1;
-extern	statetype s_ofcshoot2;
-extern	statetype s_ofcshoot3;
-extern	statetype s_ofcshoot4;
-
-extern	statetype s_ofcchase1;
-extern	statetype s_ofcchase1s;
-extern	statetype s_ofcchase2;
-extern	statetype s_ofcchase3;
-extern	statetype s_ofcchase3s;
-extern	statetype s_ofcchase4;
-
-extern	statetype s_ofcdie1;
-extern	statetype s_ofcdie2;
-extern	statetype s_ofcdie3;
-extern	statetype s_ofcdie4;
-extern	statetype s_ofcdie5;
-
-statetype s_ofcstand	= {true,SPR_OFC_S_1,0,T_Stand,NULL,&s_ofcstand};
-
-statetype s_ofcpath1 	= {true,SPR_OFC_W1_1,20,T_Path,NULL,&s_ofcpath1s};
-statetype s_ofcpath1s 	= {true,SPR_OFC_W1_1,5,NULL,NULL,&s_ofcpath2};
-statetype s_ofcpath2 	= {true,SPR_OFC_W2_1,15,T_Path,NULL,&s_ofcpath3};
-statetype s_ofcpath3 	= {true,SPR_OFC_W3_1,20,T_Path,NULL,&s_ofcpath3s};
-statetype s_ofcpath3s 	= {true,SPR_OFC_W3_1,5,NULL,NULL,&s_ofcpath4};
-statetype s_ofcpath4 	= {true,SPR_OFC_W4_1,15,T_Path,NULL,&s_ofcpath1};
-
-statetype s_ofcpain 	= {2,SPR_OFC_PAIN_1,10,NULL,NULL,&s_ofcchase1};
-statetype s_ofcpain1 	= {2,SPR_OFC_PAIN_2,10,NULL,NULL,&s_ofcchase1};
-
-statetype s_ofcshoot1 	= {false,SPR_OFC_SHOOT1,6,NULL,NULL,&s_ofcshoot2};
-statetype s_ofcshoot2 	= {false,SPR_OFC_SHOOT2,20,NULL,T_Shoot,&s_ofcshoot3};
-statetype s_ofcshoot3 	= {false,SPR_OFC_SHOOT3,10,NULL,NULL,&s_ofcchase1};
-
-statetype s_ofcchase1 	= {true,SPR_OFC_W1_1,10,T_Chase,NULL,&s_ofcchase1s};
-statetype s_ofcchase1s 	= {true,SPR_OFC_W1_1,3,NULL,NULL,&s_ofcchase2};
-statetype s_ofcchase2 	= {true,SPR_OFC_W2_1,8,T_Chase,NULL,&s_ofcchase3};
-statetype s_ofcchase3 	= {true,SPR_OFC_W3_1,10,T_Chase,NULL,&s_ofcchase3s};
-statetype s_ofcchase3s 	= {true,SPR_OFC_W3_1,3,NULL,NULL,&s_ofcchase4};
-statetype s_ofcchase4 	= {true,SPR_OFC_W4_1,8,T_Chase,NULL,&s_ofcchase1};
-
-statetype s_ofcdie1		= {false,SPR_OFC_DIE_1,11,NULL,A_DeathScream,&s_ofcdie2};
-statetype s_ofcdie2		= {false,SPR_OFC_DIE_2,11,NULL,NULL,&s_ofcdie3};
-statetype s_ofcdie3		= {false,SPR_OFC_DIE_3,11,NULL,NULL,&s_ofcdie4};
-statetype s_ofcdie4		= {false,SPR_OFC_DIE_4,11,NULL,NULL,&s_ofcdie5};
-statetype s_ofcdie5		= {false,SPR_OFC_DEAD,0,NULL,NULL,&s_ofcdie5};
-
-
-//
-// mutant
-//
-
-extern	statetype s_mutstand;
-
-extern	statetype s_mutpath1;
-extern	statetype s_mutpath1s;
-extern	statetype s_mutpath2;
-extern	statetype s_mutpath3;
-extern	statetype s_mutpath3s;
-extern	statetype s_mutpath4;
-
-extern	statetype s_mutpain;
-extern	statetype s_mutpain1;
-
-extern	statetype s_mutgiveup;
-
-extern	statetype s_mutshoot1;
-extern	statetype s_mutshoot2;
-extern	statetype s_mutshoot3;
-extern	statetype s_mutshoot4;
-
-extern	statetype s_mutchase1;
-extern	statetype s_mutchase1s;
-extern	statetype s_mutchase2;
-extern	statetype s_mutchase3;
-extern	statetype s_mutchase3s;
-extern	statetype s_mutchase4;
-
-extern	statetype s_mutdie1;
-extern	statetype s_mutdie2;
-extern	statetype s_mutdie3;
-extern	statetype s_mutdie4;
-extern	statetype s_mutdie5;
-
-statetype s_mutstand	= {true,SPR_MUT_S_1,0,T_Stand,NULL,&s_mutstand};
-
-statetype s_mutpath1 	= {true,SPR_MUT_W1_1,20,T_Path,NULL,&s_mutpath1s};
-statetype s_mutpath1s 	= {true,SPR_MUT_W1_1,5,NULL,NULL,&s_mutpath2};
-statetype s_mutpath2 	= {true,SPR_MUT_W2_1,15,T_Path,NULL,&s_mutpath3};
-statetype s_mutpath3 	= {true,SPR_MUT_W3_1,20,T_Path,NULL,&s_mutpath3s};
-statetype s_mutpath3s 	= {true,SPR_MUT_W3_1,5,NULL,NULL,&s_mutpath4};
-statetype s_mutpath4 	= {true,SPR_MUT_W4_1,15,T_Path,NULL,&s_mutpath1};
-
-statetype s_mutpain 	= {2,SPR_MUT_PAIN_1,10,NULL,NULL,&s_mutchase1};
-statetype s_mutpain1 	= {2,SPR_MUT_PAIN_2,10,NULL,NULL,&s_mutchase1};
-
-statetype s_mutshoot1 	= {false,SPR_MUT_SHOOT1,6,NULL,T_Shoot,&s_mutshoot2};
-statetype s_mutshoot2 	= {false,SPR_MUT_SHOOT2,20,NULL,NULL,&s_mutshoot3};
-statetype s_mutshoot3 	= {false,SPR_MUT_SHOOT3,10,NULL,T_Shoot,&s_mutshoot4};
-statetype s_mutshoot4 	= {false,SPR_MUT_SHOOT4,20,NULL,NULL,&s_mutchase1};
-
-statetype s_mutchase1 	= {true,SPR_MUT_W1_1,10,T_Chase,NULL,&s_mutchase1s};
-statetype s_mutchase1s 	= {true,SPR_MUT_W1_1,3,NULL,NULL,&s_mutchase2};
-statetype s_mutchase2 	= {true,SPR_MUT_W2_1,8,T_Chase,NULL,&s_mutchase3};
-statetype s_mutchase3 	= {true,SPR_MUT_W3_1,10,T_Chase,NULL,&s_mutchase3s};
-statetype s_mutchase3s 	= {true,SPR_MUT_W3_1,3,NULL,NULL,&s_mutchase4};
-statetype s_mutchase4 	= {true,SPR_MUT_W4_1,8,T_Chase,NULL,&s_mutchase1};
-
-statetype s_mutdie1		= {false,SPR_MUT_DIE_1,7,NULL,A_DeathScream,&s_mutdie2};
-statetype s_mutdie2		= {false,SPR_MUT_DIE_2,7,NULL,NULL,&s_mutdie3};
-statetype s_mutdie3		= {false,SPR_MUT_DIE_3,7,NULL,NULL,&s_mutdie4};
-statetype s_mutdie4		= {false,SPR_MUT_DIE_4,7,NULL,NULL,&s_mutdie5};
-statetype s_mutdie5		= {false,SPR_MUT_DEAD,0,NULL,NULL,&s_mutdie5};
-
-
-//
-// SS
-//
-
-extern	statetype s_ssstand;
-
-extern	statetype s_sspath1;
-extern	statetype s_sspath1s;
-extern	statetype s_sspath2;
-extern	statetype s_sspath3;
-extern	statetype s_sspath3s;
-extern	statetype s_sspath4;
-
-extern	statetype s_sspain;
-extern	statetype s_sspain1;
-
-extern	statetype s_ssshoot1;
-extern	statetype s_ssshoot2;
-extern	statetype s_ssshoot3;
-extern	statetype s_ssshoot4;
-extern	statetype s_ssshoot5;
-extern	statetype s_ssshoot6;
-extern	statetype s_ssshoot7;
-extern	statetype s_ssshoot8;
-extern	statetype s_ssshoot9;
-
-extern	statetype s_sschase1;
-extern	statetype s_sschase1s;
-extern	statetype s_sschase2;
-extern	statetype s_sschase3;
-extern	statetype s_sschase3s;
-extern	statetype s_sschase4;
-
-extern	statetype s_ssdie1;
-extern	statetype s_ssdie2;
-extern	statetype s_ssdie3;
-extern	statetype s_ssdie4;
-
-statetype s_ssstand	= {true,SPR_SS_S_1,0,T_Stand,NULL,&s_ssstand};
-
-statetype s_sspath1 	= {true,SPR_SS_W1_1,20,T_Path,NULL,&s_sspath1s};
-statetype s_sspath1s 	= {true,SPR_SS_W1_1,5,NULL,NULL,&s_sspath2};
-statetype s_sspath2 	= {true,SPR_SS_W2_1,15,T_Path,NULL,&s_sspath3};
-statetype s_sspath3 	= {true,SPR_SS_W3_1,20,T_Path,NULL,&s_sspath3s};
-statetype s_sspath3s 	= {true,SPR_SS_W3_1,5,NULL,NULL,&s_sspath4};
-statetype s_sspath4 	= {true,SPR_SS_W4_1,15,T_Path,NULL,&s_sspath1};
-
-statetype s_sspain 		= {2,SPR_SS_PAIN_1,10,NULL,NULL,&s_sschase1};
-statetype s_sspain1 	= {2,SPR_SS_PAIN_2,10,NULL,NULL,&s_sschase1};
-
-statetype s_ssshoot1 	= {false,SPR_SS_SHOOT1,20,NULL,NULL,&s_ssshoot2};
-statetype s_ssshoot2 	= {false,SPR_SS_SHOOT2,20,NULL,T_Shoot,&s_ssshoot3};
-statetype s_ssshoot3 	= {false,SPR_SS_SHOOT3,10,NULL,NULL,&s_ssshoot4};
-statetype s_ssshoot4 	= {false,SPR_SS_SHOOT2,10,NULL,T_Shoot,&s_ssshoot5};
-statetype s_ssshoot5 	= {false,SPR_SS_SHOOT3,10,NULL,NULL,&s_ssshoot6};
-statetype s_ssshoot6 	= {false,SPR_SS_SHOOT2,10,NULL,T_Shoot,&s_ssshoot7};
-statetype s_ssshoot7  	= {false,SPR_SS_SHOOT3,10,NULL,NULL,&s_ssshoot8};
-statetype s_ssshoot8  	= {false,SPR_SS_SHOOT2,10,NULL,T_Shoot,&s_ssshoot9};
-statetype s_ssshoot9  	= {false,SPR_SS_SHOOT3,10,NULL,NULL,&s_sschase1};
-
-statetype s_sschase1 	= {true,SPR_SS_W1_1,10,T_Chase,NULL,&s_sschase1s};
-statetype s_sschase1s 	= {true,SPR_SS_W1_1,3,NULL,NULL,&s_sschase2};
-statetype s_sschase2 	= {true,SPR_SS_W2_1,8,T_Chase,NULL,&s_sschase3};
-statetype s_sschase3 	= {true,SPR_SS_W3_1,10,T_Chase,NULL,&s_sschase3s};
-statetype s_sschase3s 	= {true,SPR_SS_W3_1,3,NULL,NULL,&s_sschase4};
-statetype s_sschase4 	= {true,SPR_SS_W4_1,8,T_Chase,NULL,&s_sschase1};
-
-statetype s_ssdie1		= {false,SPR_SS_DIE_1,15,NULL,A_DeathScream,&s_ssdie2};
-statetype s_ssdie2		= {false,SPR_SS_DIE_2,15,NULL,NULL,&s_ssdie3};
-statetype s_ssdie3		= {false,SPR_SS_DIE_3,15,NULL,NULL,&s_ssdie4};
-statetype s_ssdie4		= {false,SPR_SS_DEAD,0,NULL,NULL,&s_ssdie4};
-
-
-#ifndef SPEAR
-//
-// hans
-//
-extern	statetype s_bossstand;
-
-extern	statetype s_bosschase1;
-extern	statetype s_bosschase1s;
-extern	statetype s_bosschase2;
-extern	statetype s_bosschase3;
-extern	statetype s_bosschase3s;
-extern	statetype s_bosschase4;
-
-extern	statetype s_bossdie1;
-extern	statetype s_bossdie2;
-extern	statetype s_bossdie3;
-extern	statetype s_bossdie4;
-
-extern	statetype s_bossshoot1;
-extern	statetype s_bossshoot2;
-extern	statetype s_bossshoot3;
-extern	statetype s_bossshoot4;
-extern	statetype s_bossshoot5;
-extern	statetype s_bossshoot6;
-extern	statetype s_bossshoot7;
-extern	statetype s_bossshoot8;
-
-
-statetype s_bossstand	= {false,SPR_BOSS_W1,0,T_Stand,NULL,&s_bossstand};
-
-statetype s_bosschase1 	= {false,SPR_BOSS_W1,10,T_Chase,NULL,&s_bosschase1s};
-statetype s_bosschase1s	= {false,SPR_BOSS_W1,3,NULL,NULL,&s_bosschase2};
-statetype s_bosschase2 	= {false,SPR_BOSS_W2,8,T_Chase,NULL,&s_bosschase3};
-statetype s_bosschase3 	= {false,SPR_BOSS_W3,10,T_Chase,NULL,&s_bosschase3s};
-statetype s_bosschase3s	= {false,SPR_BOSS_W3,3,NULL,NULL,&s_bosschase4};
-statetype s_bosschase4 	= {false,SPR_BOSS_W4,8,T_Chase,NULL,&s_bosschase1};
-
-statetype s_bossdie1	= {false,SPR_BOSS_DIE1,15,NULL,A_DeathScream,&s_bossdie2};
-statetype s_bossdie2	= {false,SPR_BOSS_DIE2,15,NULL,NULL,&s_bossdie3};
-statetype s_bossdie3	= {false,SPR_BOSS_DIE3,15,NULL,NULL,&s_bossdie4};
-statetype s_bossdie4	= {false,SPR_BOSS_DEAD,0,NULL,NULL,&s_bossdie4};
-
-statetype s_bossshoot1 	= {false,SPR_BOSS_SHOOT1,30,NULL,NULL,&s_bossshoot2};
-statetype s_bossshoot2 	= {false,SPR_BOSS_SHOOT2,10,NULL,T_Shoot,&s_bossshoot3};
-statetype s_bossshoot3 	= {false,SPR_BOSS_SHOOT3,10,NULL,T_Shoot,&s_bossshoot4};
-statetype s_bossshoot4 	= {false,SPR_BOSS_SHOOT2,10,NULL,T_Shoot,&s_bossshoot5};
-statetype s_bossshoot5 	= {false,SPR_BOSS_SHOOT3,10,NULL,T_Shoot,&s_bossshoot6};
-statetype s_bossshoot6 	= {false,SPR_BOSS_SHOOT2,10,NULL,T_Shoot,&s_bossshoot7};
-statetype s_bossshoot7 	= {false,SPR_BOSS_SHOOT3,10,NULL,T_Shoot,&s_bossshoot8};
-statetype s_bossshoot8 	= {false,SPR_BOSS_SHOOT1,10,NULL,NULL,&s_bosschase1};
-
-
-//
-// gretel
-//
-extern	statetype s_gretelstand;
-
-extern	statetype s_gretelchase1;
-extern	statetype s_gretelchase1s;
-extern	statetype s_gretelchase2;
-extern	statetype s_gretelchase3;
-extern	statetype s_gretelchase3s;
-extern	statetype s_gretelchase4;
-
-extern	statetype s_greteldie1;
-extern	statetype s_greteldie2;
-extern	statetype s_greteldie3;
-extern	statetype s_greteldie4;
-
-extern	statetype s_gretelshoot1;
-extern	statetype s_gretelshoot2;
-extern	statetype s_gretelshoot3;
-extern	statetype s_gretelshoot4;
-extern	statetype s_gretelshoot5;
-extern	statetype s_gretelshoot6;
-extern	statetype s_gretelshoot7;
-extern	statetype s_gretelshoot8;
-
-
-statetype s_gretelstand	= {false,SPR_GRETEL_W1,0,T_Stand,NULL,&s_gretelstand};
-
-statetype s_gretelchase1 	= {false,SPR_GRETEL_W1,10,T_Chase,NULL,&s_gretelchase1s};
-statetype s_gretelchase1s	= {false,SPR_GRETEL_W1,3,NULL,NULL,&s_gretelchase2};
-statetype s_gretelchase2 	= {false,SPR_GRETEL_W2,8,T_Chase,NULL,&s_gretelchase3};
-statetype s_gretelchase3 	= {false,SPR_GRETEL_W3,10,T_Chase,NULL,&s_gretelchase3s};
-statetype s_gretelchase3s	= {false,SPR_GRETEL_W3,3,NULL,NULL,&s_gretelchase4};
-statetype s_gretelchase4 	= {false,SPR_GRETEL_W4,8,T_Chase,NULL,&s_gretelchase1};
-
-statetype s_greteldie1	= {false,SPR_GRETEL_DIE1,15,NULL,A_DeathScream,&s_greteldie2};
-statetype s_greteldie2	= {false,SPR_GRETEL_DIE2,15,NULL,NULL,&s_greteldie3};
-statetype s_greteldie3	= {false,SPR_GRETEL_DIE3,15,NULL,NULL,&s_greteldie4};
-statetype s_greteldie4	= {false,SPR_GRETEL_DEAD,0,NULL,NULL,&s_greteldie4};
-
-statetype s_gretelshoot1 	= {false,SPR_GRETEL_SHOOT1,30,NULL,NULL,&s_gretelshoot2};
-statetype s_gretelshoot2 	= {false,SPR_GRETEL_SHOOT2,10,NULL,T_Shoot,&s_gretelshoot3};
-statetype s_gretelshoot3 	= {false,SPR_GRETEL_SHOOT3,10,NULL,T_Shoot,&s_gretelshoot4};
-statetype s_gretelshoot4 	= {false,SPR_GRETEL_SHOOT2,10,NULL,T_Shoot,&s_gretelshoot5};
-statetype s_gretelshoot5 	= {false,SPR_GRETEL_SHOOT3,10,NULL,T_Shoot,&s_gretelshoot6};
-statetype s_gretelshoot6 	= {false,SPR_GRETEL_SHOOT2,10,NULL,T_Shoot,&s_gretelshoot7};
-statetype s_gretelshoot7 	= {false,SPR_GRETEL_SHOOT3,10,NULL,T_Shoot,&s_gretelshoot8};
-statetype s_gretelshoot8 	= {false,SPR_GRETEL_SHOOT1,10,NULL,NULL,&s_gretelchase1};
-#endif
-
-
-/*
-===============
-=
-= SpawnStand
-=
-===============
-*/
-
-void SpawnStand (enemy_t which, s16int tilex, s16int tiley, s16int dir)
-{
-	u16int	far *map,tile;
-
-	switch (which)
-	{
-	case en_guard:
-		SpawnNewObj (tilex,tiley,&s_grdstand);
-		new->speed = SPDPATROL;
-		if (!loadedgame)
-		  gamestate.killtotal++;
-		break;
-
-	case en_officer:
-		SpawnNewObj (tilex,tiley,&s_ofcstand);
-		new->speed = SPDPATROL;
-		if (!loadedgame)
-		  gamestate.killtotal++;
-		break;
-
-	case en_mutant:
-		SpawnNewObj (tilex,tiley,&s_mutstand);
-		new->speed = SPDPATROL;
-		if (!loadedgame)
-		  gamestate.killtotal++;
-		break;
-
-	case en_ss:
-		SpawnNewObj (tilex,tiley,&s_ssstand);
-		new->speed = SPDPATROL;
-		if (!loadedgame)
-		  gamestate.killtotal++;
-		break;
-	}
-
-
-	map = mapsegs[0]+farmapylookup[tiley]+tilex;
-	if (*map == AMBUSHTILE)
-	{
-		tilemap[tilex][tiley] = 0;
-
-		if (*(map+1) >= AREATILE)
-			tile = *(map+1);
-		if (*(map-mapwidth) >= AREATILE)
-			tile = *(map-mapwidth);
-		if (*(map+mapwidth) >= AREATILE)
-			tile = *(map+mapwidth);
-		if ( *(map-1) >= AREATILE)
-			tile = *(map-1);
-
-		*map = tile;
-		new->areanumber = tile-AREATILE;
-
-		new->flags |= FL_AMBUSH;
-	}
-
-	new->obclass = guardobj+which;
-	new->hitpoints = starthitpoints[gamestate.difficulty][which];
-	new->dir = dir*2;
-	new->flags |= FL_SHOOTABLE;
-}
-
-
-
-/*
-===============
-=
-= SpawnDeadGuard
-=
-===============
-*/
-
-void SpawnDeadGuard (s16int tilex, s16int tiley)
-{
-	SpawnNewObj (tilex,tiley,&s_grddie4);
-	new->obclass = inertobj;
-}
-
-
-
-#ifndef SPEAR
-/*
-===============
-=
-= SpawnBoss
-=
-===============
-*/
-
-void SpawnBoss (s16int tilex, s16int tiley)
-{
-	u16int	far *map,tile;
-
-	SpawnNewObj (tilex,tiley,&s_bossstand);
-	new->speed = SPDPATROL;
-
-	new->obclass = bossobj;
-	new->hitpoints = starthitpoints[gamestate.difficulty][en_boss];
-	new->dir = south;
-	new->flags |= FL_SHOOTABLE|FL_AMBUSH;
-	if (!loadedgame)
-	  gamestate.killtotal++;
-}
-
-/*
-===============
-=
-= SpawnGretel
-=
-===============
-*/
-
-void SpawnGretel (s16int tilex, s16int tiley)
-{
-	u16int	far *map,tile;
-
-	SpawnNewObj (tilex,tiley,&s_gretelstand);
-	new->speed = SPDPATROL;
-
-	new->obclass = gretelobj;
-	new->hitpoints = starthitpoints[gamestate.difficulty][en_gretel];
-	new->dir = north;
-	new->flags |= FL_SHOOTABLE|FL_AMBUSH;
-	if (!loadedgame)
-	  gamestate.killtotal++;
-}
-#endif
-
-/*
-===============
-=
-= SpawnPatrol
-=
-===============
-*/
-
-void SpawnPatrol (enemy_t which, s16int tilex, s16int tiley, s16int dir)
-{
-	switch (which)
-	{
-	case en_guard:
-		SpawnNewObj (tilex,tiley,&s_grdpath1);
-		new->speed = SPDPATROL;
-		if (!loadedgame)
-		  gamestate.killtotal++;
-		break;
-
-	case en_officer:
-		SpawnNewObj (tilex,tiley,&s_ofcpath1);
-		new->speed = SPDPATROL;
-		if (!loadedgame)
-		  gamestate.killtotal++;
-		break;
-
-	case en_ss:
-		SpawnNewObj (tilex,tiley,&s_sspath1);
-		new->speed = SPDPATROL;
-		if (!loadedgame)
-		  gamestate.killtotal++;
-		break;
-
-	case en_mutant:
-		SpawnNewObj (tilex,tiley,&s_mutpath1);
-		new->speed = SPDPATROL;
-		if (!loadedgame)
-		  gamestate.killtotal++;
-		break;
-
-	case en_dog:
-		SpawnNewObj (tilex,tiley,&s_dogpath1);
-		new->speed = SPDDOG;
-		if (!loadedgame)
-		  gamestate.killtotal++;
-		break;
-	}
-
-	new->obclass = guardobj+which;
-	new->dir = dir*2;
-	new->hitpoints = starthitpoints[gamestate.difficulty][which];
-	new->distance = tileglobal;
-	new->flags |= FL_SHOOTABLE;
-	new->active = true;
-
-	actorat[new->tilex][new->tiley] = NULL;		// don't use original spot
-
-	switch (dir)
-	{
-	case 0:
-		new->tilex++;
-		break;
-	case 1:
-		new->tiley--;
-		break;
-	case 2:
-		new->tilex--;
-		break;
-	case 3:
-		new->tiley++;
-		break;
-	}
-
-	actorat[new->tilex][new->tiley] = new;
-}
-
-
-
-/*
-==================
-=
-= A_DeathScream
-=
-==================
-*/
-
-void A_DeathScream (objtype *ob)
-{
-#ifndef UPLOAD
-#ifndef SPEAR
-	if (mapon==9 && !US_RndT())
-#else
-	if ((mapon==18 || mapon==19) && !US_RndT())
-#endif
-	{
-	 switch(ob->obclass)
-	 {
-	  case mutantobj:
-	  case guardobj:
-	  case officerobj:
-	  case ssobj:
-	  case dogobj:
-		PlaySoundLocActor(Sscream6,ob);
-		return;
-	 }
-	}
-#endif
-
-	switch (ob->obclass)
-	{
-	case mutantobj:
-		PlaySoundLocActor(Smutdeath,ob);
-		break;
-
-	case guardobj:
-		{
-		 s16int sounds[9]={ Sscream1,
-				 Sscream2,
-				 Sscream3,
-				 Sscream4,
-				 Sscream5,
-				 Sscream7,
-				 Sscream8,
-				 Sscream9
-				 };
-
-		 #ifndef UPLOAD
-		 PlaySoundLocActor(sounds[US_RndT()%8],ob);
-		 #else
-		 PlaySoundLocActor(sounds[US_RndT()%2],ob);
-		 #endif
-		}
-		break;
-	case officerobj:
-		PlaySoundLocActor(Soffcdeath,ob);
-		break;
-	case ssobj:
-		PlaySoundLocActor(Sssdeath,ob);	// JAB
-		break;
-	case dogobj:
-		PlaySoundLocActor(Sdogdeath,ob);	// JAB
-		break;
-#ifndef SPEAR
-	case bossobj:
-		SD_PlaySound(Shansdeath);				// JAB
-		break;
-	case schabbobj:
-		SD_PlaySound(Sschbdeath);
-		break;
-	case fakeobj:
-		SD_PlaySound(Shilter);
-		break;
-	case mechahitlerobj:
-		SD_PlaySound(Smechadeath);
-		break;
-	case realhitlerobj:
-		SD_PlaySound(Seva);
-		break;
-	case gretelobj:
-		SD_PlaySound(Sgreteldeath);
-		break;
-	case giftobj:
-		SD_PlaySound(Sottodeath);
-		break;
-	case fatobj:
-		SD_PlaySound(Sfettdeath);
-		break;
-#else
-	case spectreobj:
-		SD_PlaySound(Sghostdeath);
-		break;
-	case angelobj:
-		SD_PlaySound(Sangeldeath);
-		break;
-	case transobj:
-		SD_PlaySound(Stransdeath);
-		break;
-	case uberobj:
-		SD_PlaySound(Suberdeath);
-		break;
-	case willobj:
-		SD_PlaySound(Swilhdeath);
-		break;
-	case deathobj:
-		SD_PlaySound(Sknightdeath);
-		break;
-#endif
-	}
-}
-
-
-/*
-=============================================================================
-
-						 SPEAR ACTORS
-
-=============================================================================
-*/
-
-#ifdef SPEAR
-
-void T_Launch (objtype *ob);
-void T_Will (objtype *ob);
-
-extern	statetype s_angelshoot1;
-extern	statetype s_deathshoot1;
-extern	statetype s_spark1;
-
-//
-// trans
-//
-extern	statetype s_transstand;
-
-extern	statetype s_transchase1;
-extern	statetype s_transchase1s;
-extern	statetype s_transchase2;
-extern	statetype s_transchase3;
-extern	statetype s_transchase3s;
-extern	statetype s_transchase4;
-
-extern	statetype s_transdie0;
-extern	statetype s_transdie01;
-extern	statetype s_transdie1;
-extern	statetype s_transdie2;
-extern	statetype s_transdie3;
-extern	statetype s_transdie4;
-
-extern	statetype s_transshoot1;
-extern	statetype s_transshoot2;
-extern	statetype s_transshoot3;
-extern	statetype s_transshoot4;
-extern	statetype s_transshoot5;
-extern	statetype s_transshoot6;
-extern	statetype s_transshoot7;
-extern	statetype s_transshoot8;
-
-
-statetype s_transstand	= {false,SPR_TRANS_W1,0,T_Stand,NULL,&s_transstand};
-
-statetype s_transchase1 	= {false,SPR_TRANS_W1,10,T_Chase,NULL,&s_transchase1s};
-statetype s_transchase1s	= {false,SPR_TRANS_W1,3,NULL,NULL,&s_transchase2};
-statetype s_transchase2 	= {false,SPR_TRANS_W2,8,T_Chase,NULL,&s_transchase3};
-statetype s_transchase3 	= {false,SPR_TRANS_W3,10,T_Chase,NULL,&s_transchase3s};
-statetype s_transchase3s	= {false,SPR_TRANS_W3,3,NULL,NULL,&s_transchase4};
-statetype s_transchase4 	= {false,SPR_TRANS_W4,8,T_Chase,NULL,&s_transchase1};
-
-statetype s_transdie0	= {false,SPR_TRANS_W1,1,NULL,A_DeathScream,&s_transdie01};
-statetype s_transdie01	= {false,SPR_TRANS_W1,1,NULL,NULL,&s_transdie1};
-statetype s_transdie1	= {false,SPR_TRANS_DIE1,15,NULL,NULL,&s_transdie2};
-statetype s_transdie2	= {false,SPR_TRANS_DIE2,15,NULL,NULL,&s_transdie3};
-statetype s_transdie3	= {false,SPR_TRANS_DIE3,15,NULL,NULL,&s_transdie4};
-statetype s_transdie4	= {false,SPR_TRANS_DEAD,0,NULL,NULL,&s_transdie4};
-
-statetype s_transshoot1 	= {false,SPR_TRANS_SHOOT1,30,NULL,NULL,&s_transshoot2};
-statetype s_transshoot2 	= {false,SPR_TRANS_SHOOT2,10,NULL,T_Shoot,&s_transshoot3};
-statetype s_transshoot3 	= {false,SPR_TRANS_SHOOT3,10,NULL,T_Shoot,&s_transshoot4};
-statetype s_transshoot4 	= {false,SPR_TRANS_SHOOT2,10,NULL,T_Shoot,&s_transshoot5};
-statetype s_transshoot5 	= {false,SPR_TRANS_SHOOT3,10,NULL,T_Shoot,&s_transshoot6};
-statetype s_transshoot6 	= {false,SPR_TRANS_SHOOT2,10,NULL,T_Shoot,&s_transshoot7};
-statetype s_transshoot7 	= {false,SPR_TRANS_SHOOT3,10,NULL,T_Shoot,&s_transshoot8};
-statetype s_transshoot8 	= {false,SPR_TRANS_SHOOT1,10,NULL,NULL,&s_transchase1};
-
-
-/*
-===============
-=
-= SpawnTrans
-=
-===============
-*/
-
-void SpawnTrans (s16int tilex, s16int tiley)
-{
-	u16int	far *map,tile;
-
-	if (SoundBlasterPresent && DigiMode != sds_Off)
-		s_transdie01.tictime = 105;
-
-	SpawnNewObj (tilex,tiley,&s_transstand);
-	new->obclass = transobj;
-	new->hitpoints = starthitpoints[gamestate.difficulty][en_trans];
-	new->flags |= FL_SHOOTABLE|FL_AMBUSH;
-	if (!loadedgame)
-	  gamestate.killtotal++;
-}
-
-
-//
-// uber
-//
-void T_UShoot (objtype *ob);
-
-extern	statetype s_uberstand;
-
-extern	statetype s_uberchase1;
-extern	statetype s_uberchase1s;
-extern	statetype s_uberchase2;
-extern	statetype s_uberchase3;
-extern	statetype s_uberchase3s;
-extern	statetype s_uberchase4;
-
-extern	statetype s_uberdie0;
-extern	statetype s_uberdie01;
-extern	statetype s_uberdie1;
-extern	statetype s_uberdie2;
-extern	statetype s_uberdie3;
-extern	statetype s_uberdie4;
-extern	statetype s_uberdie5;
-
-extern	statetype s_ubershoot1;
-extern	statetype s_ubershoot2;
-extern	statetype s_ubershoot3;
-extern	statetype s_ubershoot4;
-extern	statetype s_ubershoot5;
-extern	statetype s_ubershoot6;
-extern	statetype s_ubershoot7;
-
-
-statetype s_uberstand	= {false,SPR_UBER_W1,0,T_Stand,NULL,&s_uberstand};
-
-statetype s_uberchase1 	= {false,SPR_UBER_W1,10,T_Chase,NULL,&s_uberchase1s};
-statetype s_uberchase1s	= {false,SPR_UBER_W1,3,NULL,NULL,&s_uberchase2};
-statetype s_uberchase2 	= {false,SPR_UBER_W2,8,T_Chase,NULL,&s_uberchase3};
-statetype s_uberchase3 	= {false,SPR_UBER_W3,10,T_Chase,NULL,&s_uberchase3s};
-statetype s_uberchase3s	= {false,SPR_UBER_W3,3,NULL,NULL,&s_uberchase4};
-statetype s_uberchase4 	= {false,SPR_UBER_W4,8,T_Chase,NULL,&s_uberchase1};
-
-statetype s_uberdie0	= {false,SPR_UBER_W1,1,NULL,A_DeathScream,&s_uberdie01};
-statetype s_uberdie01	= {false,SPR_UBER_W1,1,NULL,NULL,&s_uberdie1};
-statetype s_uberdie1	= {false,SPR_UBER_DIE1,15,NULL,NULL,&s_uberdie2};
-statetype s_uberdie2	= {false,SPR_UBER_DIE2,15,NULL,NULL,&s_uberdie3};
-statetype s_uberdie3	= {false,SPR_UBER_DIE3,15,NULL,NULL,&s_uberdie4};
-statetype s_uberdie4	= {false,SPR_UBER_DIE4,15,NULL,NULL,&s_uberdie5};
-statetype s_uberdie5	= {false,SPR_UBER_DEAD,0,NULL,NULL,&s_uberdie5};
-
-statetype s_ubershoot1 	= {false,SPR_UBER_SHOOT1,30,NULL,NULL,&s_ubershoot2};
-statetype s_ubershoot2 	= {false,SPR_UBER_SHOOT2,12,NULL,T_UShoot,&s_ubershoot3};
-statetype s_ubershoot3 	= {false,SPR_UBER_SHOOT3,12,NULL,T_UShoot,&s_ubershoot4};
-statetype s_ubershoot4 	= {false,SPR_UBER_SHOOT4,12,NULL,T_UShoot,&s_ubershoot5};
-statetype s_ubershoot5 	= {false,SPR_UBER_SHOOT3,12,NULL,T_UShoot,&s_ubershoot6};
-statetype s_ubershoot6 	= {false,SPR_UBER_SHOOT2,12,NULL,T_UShoot,&s_ubershoot7};
-statetype s_ubershoot7 	= {false,SPR_UBER_SHOOT1,12,NULL,NULL,&s_uberchase1};
-
-
-/*
-===============
-=
-= SpawnUber
-=
-===============
-*/
-
-void SpawnUber (s16int tilex, s16int tiley)
-{
-	u16int	far *map,tile;
-
-	if (SoundBlasterPresent && DigiMode != sds_Off)
-		s_uberdie01.tictime = 70;
-
-	SpawnNewObj (tilex,tiley,&s_uberstand);
-	new->obclass = uberobj;
-	new->hitpoints = starthitpoints[gamestate.difficulty][en_uber];
-	new->flags |= FL_SHOOTABLE|FL_AMBUSH;
-	if (!loadedgame)
-	  gamestate.killtotal++;
-}
-
-
-/*
-===============
-=
-= T_UShoot
-=
-===============
-*/
-
-void T_UShoot (objtype *ob)
-{
-	s16int	dx,dy,dist;
-
-	T_Shoot (ob);
-
-	dx = abs(ob->tilex - player->tilex);
-	dy = abs(ob->tiley - player->tiley);
-	dist = dx>dy ? dx : dy;
-	if (dist <= 1)
-		TakeDamage (10,ob);
-}
-
-
-//
-// will
-//
-extern	statetype s_willstand;
-
-extern	statetype s_willchase1;
-extern	statetype s_willchase1s;
-extern	statetype s_willchase2;
-extern	statetype s_willchase3;
-extern	statetype s_willchase3s;
-extern	statetype s_willchase4;
-
-extern	statetype s_willdie1;
-extern	statetype s_willdie2;
-extern	statetype s_willdie3;
-extern	statetype s_willdie4;
-extern	statetype s_willdie5;
-extern	statetype s_willdie6;
-
-extern	statetype s_willshoot1;
-extern	statetype s_willshoot2;
-extern	statetype s_willshoot3;
-extern	statetype s_willshoot4;
-extern	statetype s_willshoot5;
-extern	statetype s_willshoot6;
-
-
-statetype s_willstand	= {false,SPR_WILL_W1,0,T_Stand,NULL,&s_willstand};
-
-statetype s_willchase1 	= {false,SPR_WILL_W1,10,T_Will,NULL,&s_willchase1s};
-statetype s_willchase1s	= {false,SPR_WILL_W1,3,NULL,NULL,&s_willchase2};
-statetype s_willchase2 	= {false,SPR_WILL_W2,8,T_Will,NULL,&s_willchase3};
-statetype s_willchase3 	= {false,SPR_WILL_W3,10,T_Will,NULL,&s_willchase3s};
-statetype s_willchase3s	= {false,SPR_WILL_W3,3,NULL,NULL,&s_willchase4};
-statetype s_willchase4 	= {false,SPR_WILL_W4,8,T_Will,NULL,&s_willchase1};
-
-statetype s_willdeathcam	= {false,SPR_WILL_W1,1,NULL,NULL,&s_willdie1};
-
-statetype s_willdie1	= {false,SPR_WILL_W1,1,NULL,A_DeathScream,&s_willdie2};
-statetype s_willdie2	= {false,SPR_WILL_W1,10,NULL,NULL,&s_willdie3};
-statetype s_willdie3	= {false,SPR_WILL_DIE1,10,NULL,NULL,&s_willdie4};
-statetype s_willdie4	= {false,SPR_WILL_DIE2,10,NULL,NULL,&s_willdie5};
-statetype s_willdie5	= {false,SPR_WILL_DIE3,10,NULL,NULL,&s_willdie6};
-statetype s_willdie6	= {false,SPR_WILL_DEAD,20,NULL,NULL,&s_willdie6};
-
-statetype s_willshoot1 	= {false,SPR_WILL_SHOOT1,30,NULL,NULL,&s_willshoot2};
-statetype s_willshoot2 	= {false,SPR_WILL_SHOOT2,10,NULL,T_Launch,&s_willshoot3};
-statetype s_willshoot3 	= {false,SPR_WILL_SHOOT3,10,NULL,T_Shoot,&s_willshoot4};
-statetype s_willshoot4 	= {false,SPR_WILL_SHOOT4,10,NULL,T_Shoot,&s_willshoot5};
-statetype s_willshoot5 	= {false,SPR_WILL_SHOOT3,10,NULL,T_Shoot,&s_willshoot6};
-statetype s_willshoot6 	= {false,SPR_WILL_SHOOT4,10,NULL,T_Shoot,&s_willchase1};
-
-
-/*
-===============
-=
-= SpawnWill
-=
-===============
-*/
-
-void SpawnWill (s16int tilex, s16int tiley)
-{
-	u16int	far *map,tile;
-
-	if (SoundBlasterPresent && DigiMode != sds_Off)
-		s_willdie2.tictime = 70;
-
-	SpawnNewObj (tilex,tiley,&s_willstand);
-	new->obclass = willobj;
-	new->hitpoints = starthitpoints[gamestate.difficulty][en_will];
-	new->flags |= FL_SHOOTABLE|FL_AMBUSH;
-	if (!loadedgame)
-	  gamestate.killtotal++;
-}
-
-
-/*
-================
-=
-= T_Will
-=
-================
-*/
-
-void T_Will (objtype *ob)
-{
-	s32int move;
-	s16int	dx,dy,dist;
-	int	dodge;
-
-	dodge = false;
-	dx = abs(ob->tilex - player->tilex);
-	dy = abs(ob->tiley - player->tiley);
-	dist = dx>dy ? dx : dy;
-
-	if (CheckLine(ob))						// got a shot at player?
-	{
-		if ( US_RndT() < (tics<<3) )
-		{
-		//
-		// go into attack frame
-		//
-			if (ob->obclass == willobj)
-				NewState (ob,&s_willshoot1);
-			else if (ob->obclass == angelobj)
-				NewState (ob,&s_angelshoot1);
-			else
-				NewState (ob,&s_deathshoot1);
-			return;
-		}
-		dodge = true;
-	}
-
-	if (ob->dir == nodir)
-	{
-		if (dodge)
-			SelectDodgeDir (ob);
-		else
-			SelectChaseDir (ob);
-		if (ob->dir == nodir)
-			return;							// object is blocked in
-	}
-
-	move = ob->speed*tics;
-
-	while (move)
-	{
-		if (ob->distance < 0)
-		{
-		//
-		// waiting for a door to open
-		//
-			OpenDoor (-ob->distance-1);
-			if (doorobjlist[-ob->distance-1].action != dr_open)
-				return;
-			ob->distance = TILEGLOBAL;	// go ahead, the door is now opoen
-		}
-
-		if (move < ob->distance)
-		{
-			MoveObj (ob,move);
-			break;
-		}
-
-		//
-		// reached goal tile, so select another one
-		//
-
-		//
-		// fix position to account for round off during moving
-		//
-		ob->x = ((s32int)ob->tilex<<TILESHIFT)+TILEGLOBAL/2;
-		ob->y = ((s32int)ob->tiley<<TILESHIFT)+TILEGLOBAL/2;
-
-		move -= ob->distance;
-
-		if (dist <4)
-			SelectRunDir (ob);
-		else if (dodge)
-			SelectDodgeDir (ob);
-		else
-			SelectChaseDir (ob);
-
-		if (ob->dir == nodir)
-			return;							// object is blocked in
-	}
-
-}
-
-
-//
-// death
-//
-extern	statetype s_deathstand;
-
-extern	statetype s_deathchase1;
-extern	statetype s_deathchase1s;
-extern	statetype s_deathchase2;
-extern	statetype s_deathchase3;
-extern	statetype s_deathchase3s;
-extern	statetype s_deathchase4;
-
-extern	statetype s_deathdie1;
-extern	statetype s_deathdie2;
-extern	statetype s_deathdie3;
-extern	statetype s_deathdie4;
-extern	statetype s_deathdie5;
-extern	statetype s_deathdie6;
-extern	statetype s_deathdie7;
-extern	statetype s_deathdie8;
-extern	statetype s_deathdie9;
-
-extern	statetype s_deathshoot1;
-extern	statetype s_deathshoot2;
-extern	statetype s_deathshoot3;
-extern	statetype s_deathshoot4;
-extern	statetype s_deathshoot5;
-
-
-statetype s_deathstand	= {false,SPR_DEATH_W1,0,T_Stand,NULL,&s_deathstand};
-
-statetype s_deathchase1 	= {false,SPR_DEATH_W1,10,T_Will,NULL,&s_deathchase1s};
-statetype s_deathchase1s	= {false,SPR_DEATH_W1,3,NULL,NULL,&s_deathchase2};
-statetype s_deathchase2 	= {false,SPR_DEATH_W2,8,T_Will,NULL,&s_deathchase3};
-statetype s_deathchase3 	= {false,SPR_DEATH_W3,10,T_Will,NULL,&s_deathchase3s};
-statetype s_deathchase3s	= {false,SPR_DEATH_W3,3,NULL,NULL,&s_deathchase4};
-statetype s_deathchase4 	= {false,SPR_DEATH_W4,8,T_Will,NULL,&s_deathchase1};
-
-statetype s_deathdeathcam	= {false,SPR_DEATH_W1,1,NULL,NULL,&s_deathdie1};
-
-statetype s_deathdie1	= {false,SPR_DEATH_W1,1,NULL,A_DeathScream,&s_deathdie2};
-statetype s_deathdie2	= {false,SPR_DEATH_W1,10,NULL,NULL,&s_deathdie3};
-statetype s_deathdie3	= {false,SPR_DEATH_DIE1,10,NULL,NULL,&s_deathdie4};
-statetype s_deathdie4	= {false,SPR_DEATH_DIE2,10,NULL,NULL,&s_deathdie5};
-statetype s_deathdie5	= {false,SPR_DEATH_DIE3,10,NULL,NULL,&s_deathdie6};
-statetype s_deathdie6	= {false,SPR_DEATH_DIE4,10,NULL,NULL,&s_deathdie7};
-statetype s_deathdie7	= {false,SPR_DEATH_DIE5,10,NULL,NULL,&s_deathdie8};
-statetype s_deathdie8	= {false,SPR_DEATH_DIE6,10,NULL,NULL,&s_deathdie9};
-statetype s_deathdie9	= {false,SPR_DEATH_DEAD,0,NULL,NULL,&s_deathdie9};
-
-statetype s_deathshoot1 	= {false,SPR_DEATH_SHOOT1,30,NULL,NULL,&s_deathshoot2};
-statetype s_deathshoot2 	= {false,SPR_DEATH_SHOOT2,10,NULL,T_Launch,&s_deathshoot3};
-statetype s_deathshoot3 	= {false,SPR_DEATH_SHOOT4,10,NULL,T_Shoot,&s_deathshoot4};
-statetype s_deathshoot4 	= {false,SPR_DEATH_SHOOT3,10,NULL,T_Launch,&s_deathshoot5};
-statetype s_deathshoot5 	= {false,SPR_DEATH_SHOOT4,10,NULL,T_Shoot,&s_deathchase1};
-
-
-/*
-===============
-=
-= SpawnDeath
-=
-===============
-*/
-
-void SpawnDeath (s16int tilex, s16int tiley)
-{
-	u16int	far *map,tile;
-
-	if (SoundBlasterPresent && DigiMode != sds_Off)
-		s_deathdie2.tictime = 105;
-
-	SpawnNewObj (tilex,tiley,&s_deathstand);
-	new->obclass = deathobj;
-	new->hitpoints = starthitpoints[gamestate.difficulty][en_death];
-	new->flags |= FL_SHOOTABLE|FL_AMBUSH;
-	if (!loadedgame)
-	  gamestate.killtotal++;
-}
-
-/*
-===============
-=
-= T_Launch
-=
-===============
-*/
-
-void T_Launch (objtype *ob)
-{
-	s32int	deltax,deltay;
-	float	angle;
-	s16int		iangle;
-
-	deltax = player->x - ob->x;
-	deltay = ob->y - player->y;
-	angle = atan2 (deltay,deltax);
-	if (angle<0)
-		angle = M_PI*2+angle;
-	iangle = angle/(M_PI*2)*ANGLES;
-	if (ob->obclass == deathobj)
-	{
-		T_Shoot (ob);
-		if (ob->state == &s_deathshoot2)
-		{
-			iangle-=4;
-			if (iangle<0)
-				iangle+=ANGLES;
-		}
-		else
-		{
-			iangle+=4;
-			if (iangle>=ANGLES)
-				iangle-=ANGLES;
-		}
-	}
-
-	GetNewActor ();
-	new->state = &s_rocket;
-	new->ticcount = 1;
-
-	new->tilex = ob->tilex;
-	new->tiley = ob->tiley;
-	new->x = ob->x;
-	new->y = ob->y;
-	new->obclass = rocketobj;
-	switch(ob->obclass)
-	{
-	case deathobj:
-		new->state = &s_hrocket;
-		new->obclass = hrocketobj;
-		PlaySoundLocActor (Sknightmissile,new);
-		break;
-	case angelobj:
-		new->state = &s_spark1;
-		new->obclass = sparkobj;
-		PlaySoundLocActor (Sangelfire,new);
-		break;
-	default:
-		PlaySoundLocActor (Sthrow,new);
-	}
-
-	new->dir = nodir;
-	new->angle = iangle;
-	new->speed = 0x2000l;
-	new->flags = FL_NONMARK;
-	new->active = true;
-}
-
-
-
-//
-// angel
-//
-void A_Relaunch (objtype *ob);
-void A_Victory (objtype *ob);
-void A_StartAttack (objtype *ob);
-void A_Breathing (objtype *ob);
-
-extern	statetype s_angelstand;
-
-extern	statetype s_angelchase1;
-extern	statetype s_angelchase1s;
-extern	statetype s_angelchase2;
-extern	statetype s_angelchase3;
-extern	statetype s_angelchase3s;
-extern	statetype s_angelchase4;
-
-extern	statetype s_angeldie1;
-extern	statetype s_angeldie11;
-extern	statetype s_angeldie2;
-extern	statetype s_angeldie3;
-extern	statetype s_angeldie4;
-extern	statetype s_angeldie5;
-extern	statetype s_angeldie6;
-extern	statetype s_angeldie7;
-extern	statetype s_angeldie8;
-extern	statetype s_angeldie9;
-
-extern	statetype s_angelshoot1;
-extern	statetype s_angelshoot2;
-extern	statetype s_angelshoot3;
-extern	statetype s_angelshoot4;
-extern	statetype s_angelshoot5;
-extern	statetype s_angelshoot6;
-
-extern	statetype s_angeltired;
-extern	statetype s_angeltired2;
-extern	statetype s_angeltired3;
-extern	statetype s_angeltired4;
-extern	statetype s_angeltired5;
-extern	statetype s_angeltired6;
-extern	statetype s_angeltired7;
-
-extern	statetype s_spark1;
-extern	statetype s_spark2;
-extern	statetype s_spark3;
-extern	statetype s_spark4;
-
-
-statetype s_angelstand	= {false,SPR_ANGEL_W1,0,T_Stand,NULL,&s_angelstand};
-
-statetype s_angelchase1 	= {false,SPR_ANGEL_W1,10,T_Will,NULL,&s_angelchase1s};
-statetype s_angelchase1s	= {false,SPR_ANGEL_W1,3,NULL,NULL,&s_angelchase2};
-statetype s_angelchase2 	= {false,SPR_ANGEL_W2,8,T_Will,NULL,&s_angelchase3};
-statetype s_angelchase3 	= {false,SPR_ANGEL_W3,10,T_Will,NULL,&s_angelchase3s};
-statetype s_angelchase3s	= {false,SPR_ANGEL_W3,3,NULL,NULL,&s_angelchase4};
-statetype s_angelchase4 	= {false,SPR_ANGEL_W4,8,T_Will,NULL,&s_angelchase1};
-
-statetype s_angeldie1	= {false,SPR_ANGEL_W1,1,NULL,A_DeathScream,&s_angeldie11};
-statetype s_angeldie11	= {false,SPR_ANGEL_W1,1,NULL,NULL,&s_angeldie2};
-statetype s_angeldie2	= {false,SPR_ANGEL_DIE1,10,NULL,A_Slurpie,&s_angeldie3};
-statetype s_angeldie3	= {false,SPR_ANGEL_DIE2,10,NULL,NULL,&s_angeldie4};
-statetype s_angeldie4	= {false,SPR_ANGEL_DIE3,10,NULL,NULL,&s_angeldie5};
-statetype s_angeldie5	= {false,SPR_ANGEL_DIE4,10,NULL,NULL,&s_angeldie6};
-statetype s_angeldie6	= {false,SPR_ANGEL_DIE5,10,NULL,NULL,&s_angeldie7};
-statetype s_angeldie7	= {false,SPR_ANGEL_DIE6,10,NULL,NULL,&s_angeldie8};
-statetype s_angeldie8	= {false,SPR_ANGEL_DIE7,10,NULL,NULL,&s_angeldie9};
-statetype s_angeldie9	= {false,SPR_ANGEL_DEAD,130,NULL,A_Victory,&s_angeldie9};
-
-statetype s_angelshoot1 	= {false,SPR_ANGEL_SHOOT1,10,NULL,A_StartAttack,&s_angelshoot2};
-statetype s_angelshoot2 	= {false,SPR_ANGEL_SHOOT2,20,NULL,T_Launch,&s_angelshoot3};
-statetype s_angelshoot3 	= {false,SPR_ANGEL_SHOOT1,10,NULL,A_Relaunch,&s_angelshoot2};
-
-statetype s_angeltired 	= {false,SPR_ANGEL_TIRED1,40,NULL,A_Breathing,&s_angeltired2};
-statetype s_angeltired2	= {false,SPR_ANGEL_TIRED2,40,NULL,NULL,&s_angeltired3};
-statetype s_angeltired3	= {false,SPR_ANGEL_TIRED1,40,NULL,A_Breathing,&s_angeltired4};
-statetype s_angeltired4	= {false,SPR_ANGEL_TIRED2,40,NULL,NULL,&s_angeltired5};
-statetype s_angeltired5	= {false,SPR_ANGEL_TIRED1,40,NULL,A_Breathing,&s_angeltired6};
-statetype s_angeltired6	= {false,SPR_ANGEL_TIRED2,40,NULL,NULL,&s_angeltired7};
-statetype s_angeltired7	= {false,SPR_ANGEL_TIRED1,40,NULL,A_Breathing,&s_angelchase1};
-
-statetype s_spark1 	= {false,SPR_SPARK1,6,T_Projectile,NULL,&s_spark2};
-statetype s_spark2 	= {false,SPR_SPARK2,6,T_Projectile,NULL,&s_spark3};
-statetype s_spark3 	= {false,SPR_SPARK3,6,T_Projectile,NULL,&s_spark4};
-statetype s_spark4 	= {false,SPR_SPARK4,6,T_Projectile,NULL,&s_spark1};
-
-
-#pragma argsused
-void A_Slurpie (objtype *ob)
-{
- SD_PlaySound(Sslurp);
-}
-
-#pragma argsused
-void A_Breathing (objtype *ob)
-{
- SD_PlaySound(Sangeltired);
-}
-
-/*
-===============
-=
-= SpawnAngel
-=
-===============
-*/
-
-void SpawnAngel (s16int tilex, s16int tiley)
-{
-	u16int	far *map,tile;
-
-
-	if (SoundBlasterPresent && DigiMode != sds_Off)
-		s_angeldie11.tictime = 105;
-
-	SpawnNewObj (tilex,tiley,&s_angelstand);
-	new->obclass = angelobj;
-	new->hitpoints = starthitpoints[gamestate.difficulty][en_angel];
-	new->flags |= FL_SHOOTABLE|FL_AMBUSH;
-	if (!loadedgame)
-	  gamestate.killtotal++;
-}
-
-
-/*
-=================
-=
-= A_Victory
-=
-=================
-*/
-
-#pragma argsused
-void A_Victory (objtype *ob)
-{
-	playstate = ex_victorious;
-}
-
-
-/*
-=================
-=
-= A_StartAttack
-=
-=================
-*/
-
-void A_StartAttack (objtype *ob)
-{
-	ob->temp1 = 0;
-}
-
-
-/*
-=================
-=
-= A_Relaunch
-=
-=================
-*/
-
-void A_Relaunch (objtype *ob)
-{
-	if (++ob->temp1 == 3)
-	{
-		NewState (ob,&s_angeltired);
-		return;
-	}
-
-	if (US_RndT()&1)
-	{
-		NewState (ob,&s_angelchase1);
-		return;
-	}
-}
-
-
-
-
-//
-// spectre
-//
-void T_SpectreWait (objtype *ob);
-void A_Dormant (objtype *ob);
-
-extern	statetype s_spectrewait1;
-extern	statetype s_spectrewait2;
-extern	statetype s_spectrewait3;
-extern	statetype s_spectrewait4;
-
-extern	statetype s_spectrechase1;
-extern	statetype s_spectrechase2;
-extern	statetype s_spectrechase3;
-extern	statetype s_spectrechase4;
-
-extern	statetype s_spectredie1;
-extern	statetype s_spectredie2;
-extern	statetype s_spectredie3;
-extern	statetype s_spectredie4;
-
-extern	statetype s_spectrewake;
-
-statetype s_spectrewait1	= {false,SPR_SPECTRE_W1,10,T_Stand,NULL,&s_spectrewait2};
-statetype s_spectrewait2	= {false,SPR_SPECTRE_W2,10,T_Stand,NULL,&s_spectrewait3};
-statetype s_spectrewait3	= {false,SPR_SPECTRE_W3,10,T_Stand,NULL,&s_spectrewait4};
-statetype s_spectrewait4	= {false,SPR_SPECTRE_W4,10,T_Stand,NULL,&s_spectrewait1};
-
-statetype s_spectrechase1	= {false,SPR_SPECTRE_W1,10,T_Ghosts,NULL,&s_spectrechase2};
-statetype s_spectrechase2	= {false,SPR_SPECTRE_W2,10,T_Ghosts,NULL,&s_spectrechase3};
-statetype s_spectrechase3	= {false,SPR_SPECTRE_W3,10,T_Ghosts,NULL,&s_spectrechase4};
-statetype s_spectrechase4	= {false,SPR_SPECTRE_W4,10,T_Ghosts,NULL,&s_spectrechase1};
-
-statetype s_spectredie1	= {false,SPR_SPECTRE_F1,10,NULL,NULL,&s_spectredie2};
-statetype s_spectredie2	= {false,SPR_SPECTRE_F2,10,NULL,NULL,&s_spectredie3};
-statetype s_spectredie3	= {false,SPR_SPECTRE_F3,10,NULL,NULL,&s_spectredie4};
-statetype s_spectredie4	= {false,SPR_SPECTRE_F4,300,NULL,NULL,&s_spectrewake};
-statetype s_spectrewake	= {false,SPR_SPECTRE_F4,10,NULL,A_Dormant,&s_spectrewake};
-
-/*
-===============
-=
-= SpawnSpectre
-=
-===============
-*/
-
-void SpawnSpectre (s16int tilex, s16int tiley)
-{
-	u16int	far *map,tile;
-
-	SpawnNewObj (tilex,tiley,&s_spectrewait1);
-	new->obclass = spectreobj;
-	new->hitpoints = starthitpoints[gamestate.difficulty][en_spectre];
-	new->flags |= FL_SHOOTABLE|FL_AMBUSH; // |FL_NEVERMARK|FL_NONMARK;
-	if (!loadedgame)
-	  gamestate.killtotal++;
-}
-
-
-/*
-===============
-=
-= A_Dormant
-=
-===============
-*/
-
-void A_Dormant (objtype *ob)
-{
-	s32int	deltax,deltay;
-	s16int	xl,xh,yl,yh;
-	s16int	x,y;
-	u16int	tile;
-
-	deltax = ob->x - player->x;
-	if (deltax < -MINACTORDIST || deltax > MINACTORDIST)
-		goto moveok;
-	deltay = ob->y - player->y;
-	if (deltay < -MINACTORDIST || deltay > MINACTORDIST)
-		goto moveok;
-
-	return;
-moveok:
-
-	xl = (ob->x-MINDIST) >> TILESHIFT;
-	xh = (ob->x+MINDIST) >> TILESHIFT;
-	yl = (ob->y-MINDIST) >> TILESHIFT;
-	yh = (ob->y+MINDIST) >> TILESHIFT;
-
-	for (y=yl ; y<=yh ; y++)
-		for (x=xl ; x<=xh ; x++)
-		{
-			tile = actorat[x][y];
-			if (!tile)
-				continue;
-			if (tile<256)
-				return;
-			if (((objtype *)tile)->flags&FL_SHOOTABLE)
-				return;
-		}
-
-	ob->flags |= FL_AMBUSH | FL_SHOOTABLE;
-	ob->flags &= ~FL_ATTACKMODE;
-	ob->dir = nodir;
-	NewState (ob,&s_spectrewait1);
-}
-
-
-#endif
-
-/*
-=============================================================================
-
-						 SCHABBS / GIFT / FAT
-
-=============================================================================
-*/
-
-#ifndef SPEAR
-/*
-===============
-=
-= SpawnGhosts
-=
-===============
-*/
-
-void SpawnGhosts (s16int which, s16int tilex, s16int tiley)
-{
-	u16int	far *map,tile;
-
-	switch(which)
-	{
-	 case en_blinky:
-	   SpawnNewObj (tilex,tiley,&s_blinkychase1);
-	   break;
-	 case en_clyde:
-	   SpawnNewObj (tilex,tiley,&s_clydechase1);
-	   break;
-	 case en_pinky:
-	   SpawnNewObj (tilex,tiley,&s_pinkychase1);
-	   break;
-	 case en_inky:
-	   SpawnNewObj (tilex,tiley,&s_inkychase1);
-	   break;
-	}
-
-	new->obclass = ghostobj;
-	new->speed = SPDDOG;
-
-	new->dir = east;
-	new->flags |= FL_AMBUSH;
-	if (!loadedgame)
-	  gamestate.killtotal++;
-}
-
-
-
-void	T_Gift (objtype *ob);
-void	T_GiftThrow (objtype *ob);
-
-void	T_Fat (objtype *ob);
-void	T_FatThrow (objtype *ob);
-
-//
-// schabb
-//
-extern	statetype s_schabbstand;
-
-extern	statetype s_schabbchase1;
-extern	statetype s_schabbchase1s;
-extern	statetype s_schabbchase2;
-extern	statetype s_schabbchase3;
-extern	statetype s_schabbchase3s;
-extern	statetype s_schabbchase4;
-
-extern	statetype s_schabbdie1;
-extern	statetype s_schabbdie2;
-extern	statetype s_schabbdie3;
-extern	statetype s_schabbdie4;
-extern	statetype s_schabbdie5;
-extern	statetype s_schabbdie6;
-
-extern	statetype s_schabbshoot1;
-extern	statetype s_schabbshoot2;
-
-extern	statetype s_needle1;
-extern	statetype s_needle2;
-extern	statetype s_needle3;
-extern	statetype s_needle4;
-
-extern	statetype s_schabbdeathcam;
-
-
-statetype s_schabbstand	= {false,SPR_SCHABB_W1,0,T_Stand,NULL,&s_schabbstand};
-
-statetype s_schabbchase1 	= {false,SPR_SCHABB_W1,10,T_Schabb,NULL,&s_schabbchase1s};
-statetype s_schabbchase1s	= {false,SPR_SCHABB_W1,3,NULL,NULL,&s_schabbchase2};
-statetype s_schabbchase2 	= {false,SPR_SCHABB_W2,8,T_Schabb,NULL,&s_schabbchase3};
-statetype s_schabbchase3 	= {false,SPR_SCHABB_W3,10,T_Schabb,NULL,&s_schabbchase3s};
-statetype s_schabbchase3s	= {false,SPR_SCHABB_W3,3,NULL,NULL,&s_schabbchase4};
-statetype s_schabbchase4 	= {false,SPR_SCHABB_W4,8,T_Schabb,NULL,&s_schabbchase1};
-
-statetype s_schabbdeathcam	= {false,SPR_SCHABB_W1,1,NULL,NULL,&s_schabbdie1};
-
-statetype s_schabbdie1	= {false,SPR_SCHABB_W1,10,NULL,A_DeathScream,&s_schabbdie2};
-statetype s_schabbdie2	= {false,SPR_SCHABB_W1,10,NULL,NULL,&s_schabbdie3};
-statetype s_schabbdie3	= {false,SPR_SCHABB_DIE1,10,NULL,NULL,&s_schabbdie4};
-statetype s_schabbdie4	= {false,SPR_SCHABB_DIE2,10,NULL,NULL,&s_schabbdie5};
-statetype s_schabbdie5	= {false,SPR_SCHABB_DIE3,10,NULL,NULL,&s_schabbdie6};
-statetype s_schabbdie6	= {false,SPR_SCHABB_DEAD,20,NULL,A_StartDeathCam,&s_schabbdie6};
-
-statetype s_schabbshoot1 	= {false,SPR_SCHABB_SHOOT1,30,NULL,NULL,&s_schabbshoot2};
-statetype s_schabbshoot2 	= {false,SPR_SCHABB_SHOOT2,10,NULL,T_SchabbThrow,&s_schabbchase1};
-
-statetype s_needle1 	= {false,SPR_HYPO1,6,T_Projectile,NULL,&s_needle2};
-statetype s_needle2 	= {false,SPR_HYPO2,6,T_Projectile,NULL,&s_needle3};
-statetype s_needle3 	= {false,SPR_HYPO3,6,T_Projectile,NULL,&s_needle4};
-statetype s_needle4 	= {false,SPR_HYPO4,6,T_Projectile,NULL,&s_needle1};
-
-
-//
-// gift
-//
-extern	statetype s_giftstand;
-
-extern	statetype s_giftchase1;
-extern	statetype s_giftchase1s;
-extern	statetype s_giftchase2;
-extern	statetype s_giftchase3;
-extern	statetype s_giftchase3s;
-extern	statetype s_giftchase4;
-
-extern	statetype s_giftdie1;
-extern	statetype s_giftdie2;
-extern	statetype s_giftdie3;
-extern	statetype s_giftdie4;
-extern	statetype s_giftdie5;
-extern	statetype s_giftdie6;
-
-extern	statetype s_giftshoot1;
-extern	statetype s_giftshoot2;
-
-extern	statetype s_needle1;
-extern	statetype s_needle2;
-extern	statetype s_needle3;
-extern	statetype s_needle4;
-
-extern	statetype s_giftdeathcam;
-
-extern	statetype s_boom1;
-extern	statetype s_boom2;
-extern	statetype s_boom3;
-
-
-statetype s_giftstand	= {false,SPR_GIFT_W1,0,T_Stand,NULL,&s_giftstand};
-
-statetype s_giftchase1 	= {false,SPR_GIFT_W1,10,T_Gift,NULL,&s_giftchase1s};
-statetype s_giftchase1s	= {false,SPR_GIFT_W1,3,NULL,NULL,&s_giftchase2};
-statetype s_giftchase2 	= {false,SPR_GIFT_W2,8,T_Gift,NULL,&s_giftchase3};
-statetype s_giftchase3 	= {false,SPR_GIFT_W3,10,T_Gift,NULL,&s_giftchase3s};
-statetype s_giftchase3s	= {false,SPR_GIFT_W3,3,NULL,NULL,&s_giftchase4};
-statetype s_giftchase4 	= {false,SPR_GIFT_W4,8,T_Gift,NULL,&s_giftchase1};
-
-statetype s_giftdeathcam	= {false,SPR_GIFT_W1,1,NULL,NULL,&s_giftdie1};
-
-statetype s_giftdie1	= {false,SPR_GIFT_W1,1,NULL,A_DeathScream,&s_giftdie2};
-statetype s_giftdie2	= {false,SPR_GIFT_W1,10,NULL,NULL,&s_giftdie3};
-statetype s_giftdie3	= {false,SPR_GIFT_DIE1,10,NULL,NULL,&s_giftdie4};
-statetype s_giftdie4	= {false,SPR_GIFT_DIE2,10,NULL,NULL,&s_giftdie5};
-statetype s_giftdie5	= {false,SPR_GIFT_DIE3,10,NULL,NULL,&s_giftdie6};
-statetype s_giftdie6	= {false,SPR_GIFT_DEAD,20,NULL,A_StartDeathCam,&s_giftdie6};
-
-statetype s_giftshoot1 	= {false,SPR_GIFT_SHOOT1,30,NULL,NULL,&s_giftshoot2};
-statetype s_giftshoot2 	= {false,SPR_GIFT_SHOOT2,10,NULL,T_GiftThrow,&s_giftchase1};
-
-
-//
-// fat
-//
-extern	statetype s_fatstand;
-
-extern	statetype s_fatchase1;
-extern	statetype s_fatchase1s;
-extern	statetype s_fatchase2;
-extern	statetype s_fatchase3;
-extern	statetype s_fatchase3s;
-extern	statetype s_fatchase4;
-
-extern	statetype s_fatdie1;
-extern	statetype s_fatdie2;
-extern	statetype s_fatdie3;
-extern	statetype s_fatdie4;
-extern	statetype s_fatdie5;
-extern	statetype s_fatdie6;
-
-extern	statetype s_fatshoot1;
-extern	statetype s_fatshoot2;
-extern	statetype s_fatshoot3;
-extern	statetype s_fatshoot4;
-extern	statetype s_fatshoot5;
-extern	statetype s_fatshoot6;
-
-extern	statetype s_needle1;
-extern	statetype s_needle2;
-extern	statetype s_needle3;
-extern	statetype s_needle4;
-
-extern	statetype s_fatdeathcam;
-
-
-statetype s_fatstand	= {false,SPR_FAT_W1,0,T_Stand,NULL,&s_fatstand};
-
-statetype s_fatchase1 	= {false,SPR_FAT_W1,10,T_Fat,NULL,&s_fatchase1s};
-statetype s_fatchase1s	= {false,SPR_FAT_W1,3,NULL,NULL,&s_fatchase2};
-statetype s_fatchase2 	= {false,SPR_FAT_W2,8,T_Fat,NULL,&s_fatchase3};
-statetype s_fatchase3 	= {false,SPR_FAT_W3,10,T_Fat,NULL,&s_fatchase3s};
-statetype s_fatchase3s	= {false,SPR_FAT_W3,3,NULL,NULL,&s_fatchase4};
-statetype s_fatchase4 	= {false,SPR_FAT_W4,8,T_Fat,NULL,&s_fatchase1};
-
-statetype s_fatdeathcam	= {false,SPR_FAT_W1,1,NULL,NULL,&s_fatdie1};
-
-statetype s_fatdie1	= {false,SPR_FAT_W1,1,NULL,A_DeathScream,&s_fatdie2};
-statetype s_fatdie2	= {false,SPR_FAT_W1,10,NULL,NULL,&s_fatdie3};
-statetype s_fatdie3	= {false,SPR_FAT_DIE1,10,NULL,NULL,&s_fatdie4};
-statetype s_fatdie4	= {false,SPR_FAT_DIE2,10,NULL,NULL,&s_fatdie5};
-statetype s_fatdie5	= {false,SPR_FAT_DIE3,10,NULL,NULL,&s_fatdie6};
-statetype s_fatdie6	= {false,SPR_FAT_DEAD,20,NULL,A_StartDeathCam,&s_fatdie6};
-
-statetype s_fatshoot1 	= {false,SPR_FAT_SHOOT1,30,NULL,NULL,&s_fatshoot2};
-statetype s_fatshoot2 	= {false,SPR_FAT_SHOOT2,10,NULL,T_GiftThrow,&s_fatshoot3};
-statetype s_fatshoot3 	= {false,SPR_FAT_SHOOT3,10,NULL,T_Shoot,&s_fatshoot4};
-statetype s_fatshoot4 	= {false,SPR_FAT_SHOOT4,10,NULL,T_Shoot,&s_fatshoot5};
-statetype s_fatshoot5 	= {false,SPR_FAT_SHOOT3,10,NULL,T_Shoot,&s_fatshoot6};
-statetype s_fatshoot6 	= {false,SPR_FAT_SHOOT4,10,NULL,T_Shoot,&s_fatchase1};
-
-
-/*
-===============
-=
-= SpawnSchabbs
-=
-===============
-*/
-
-void SpawnSchabbs (s16int tilex, s16int tiley)
-{
-	u16int	far *map,tile;
-
-	if (DigiMode != sds_Off)
-		s_schabbdie2.tictime = 140;
-	else
-		s_schabbdie2.tictime = 5;
-
-	SpawnNewObj (tilex,tiley,&s_schabbstand);
-	new->speed = SPDPATROL;
-
-	new->obclass = schabbobj;
-	new->hitpoints = starthitpoints[gamestate.difficulty][en_schabbs];
-	new->dir = south;
-	new->flags |= FL_SHOOTABLE|FL_AMBUSH;
-	if (!loadedgame)
-	  gamestate.killtotal++;
-}
-
-
-/*
-===============
-=
-= SpawnGift
-=
-===============
-*/
-
-void SpawnGift (s16int tilex, s16int tiley)
-{
-	u16int	far *map,tile;
-
-	if (DigiMode != sds_Off)
-	  s_giftdie2.tictime = 140;
-	else
-	  s_giftdie2.tictime = 5;
-
-	SpawnNewObj (tilex,tiley,&s_giftstand);
-	new->speed = SPDPATROL;
-
-	new->obclass = giftobj;
-	new->hitpoints = starthitpoints[gamestate.difficulty][en_gift];
-	new->dir = north;
-	new->flags |= FL_SHOOTABLE|FL_AMBUSH;
-	if (!loadedgame)
-	  gamestate.killtotal++;
-}
-
-
-/*
-===============
-=
-= SpawnFat
-=
-===============
-*/
-
-void SpawnFat (s16int tilex, s16int tiley)
-{
-	u16int	far *map,tile;
-
-	if (DigiMode != sds_Off)
-	  s_fatdie2.tictime = 140;
-	else
-	  s_fatdie2.tictime = 5;
-
-	SpawnNewObj (tilex,tiley,&s_fatstand);
-	new->speed = SPDPATROL;
-
-	new->obclass = fatobj;
-	new->hitpoints = starthitpoints[gamestate.difficulty][en_fat];
-	new->dir = south;
-	new->flags |= FL_SHOOTABLE|FL_AMBUSH;
-	if (!loadedgame)
-	  gamestate.killtotal++;
-}
-
-
-/*
-=================
-=
-= T_SchabbThrow
-=
-=================
-*/
-
-void T_SchabbThrow (objtype *ob)
-{
-	s32int	deltax,deltay;
-	float	angle;
-	s16int		iangle;
-
-	deltax = player->x - ob->x;
-	deltay = ob->y - player->y;
-	angle = atan2 (deltay,deltax);
-	if (angle<0)
-		angle = M_PI*2+angle;
-	iangle = angle/(M_PI*2)*ANGLES;
-
-	GetNewActor ();
-	new->state = &s_needle1;
-	new->ticcount = 1;
-
-	new->tilex = ob->tilex;
-	new->tiley = ob->tiley;
-	new->x = ob->x;
-	new->y = ob->y;
-	new->obclass = needleobj;
-	new->dir = nodir;
-	new->angle = iangle;
-	new->speed = 0x2000l;
-
-	new->flags = FL_NONMARK;
-	new->active = true;
-
-	PlaySoundLocActor (Sthrow,new);
-}
-
-/*
-=================
-=
-= T_GiftThrow
-=
-=================
-*/
-
-void T_GiftThrow (objtype *ob)
-{
-	s32int	deltax,deltay;
-	float	angle;
-	s16int		iangle;
-
-	deltax = player->x - ob->x;
-	deltay = ob->y - player->y;
-	angle = atan2 (deltay,deltax);
-	if (angle<0)
-		angle = M_PI*2+angle;
-	iangle = angle/(M_PI*2)*ANGLES;
-
-	GetNewActor ();
-	new->state = &s_rocket;
-	new->ticcount = 1;
-
-	new->tilex = ob->tilex;
-	new->tiley = ob->tiley;
-	new->x = ob->x;
-	new->y = ob->y;
-	new->obclass = rocketobj;
-	new->dir = nodir;
-	new->angle = iangle;
-	new->speed = 0x2000l;
-	new->flags = FL_NONMARK;
-	new->active = true;
-
-	PlaySoundLocActor (Smissile,new);
-}
-
-
-
-/*
-=================
-=
-= T_Schabb
-=
-=================
-*/
-
-void T_Schabb (objtype *ob)
-{
-	s32int move;
-	s16int	dx,dy,dist;
-	int	dodge;
-
-	dodge = false;
-	dx = abs(ob->tilex - player->tilex);
-	dy = abs(ob->tiley - player->tiley);
-	dist = dx>dy ? dx : dy;
-
-	if (CheckLine(ob))						// got a shot at player?
-	{
-
-		if ( US_RndT() < (tics<<3) )
-		{
-		//
-		// go into attack frame
-		//
-			NewState (ob,&s_schabbshoot1);
-			return;
-		}
-		dodge = true;
-	}
-
-	if (ob->dir == nodir)
-	{
-		if (dodge)
-			SelectDodgeDir (ob);
-		else
-			SelectChaseDir (ob);
-		if (ob->dir == nodir)
-			return;							// object is blocked in
-	}
-
-	move = ob->speed*tics;
-
-	while (move)
-	{
-		if (ob->distance < 0)
-		{
-		//
-		// waiting for a door to open
-		//
-			OpenDoor (-ob->distance-1);
-			if (doorobjlist[-ob->distance-1].action != dr_open)
-				return;
-			ob->distance = TILEGLOBAL;	// go ahead, the door is now opoen
-		}
-
-		if (move < ob->distance)
-		{
-			MoveObj (ob,move);
-			break;
-		}
-
-		//
-		// reached goal tile, so select another one
-		//
-
-		//
-		// fix position to account for round off during moving
-		//
-		ob->x = ((s32int)ob->tilex<<TILESHIFT)+TILEGLOBAL/2;
-		ob->y = ((s32int)ob->tiley<<TILESHIFT)+TILEGLOBAL/2;
-
-		move -= ob->distance;
-
-		if (dist <4)
-			SelectRunDir (ob);
-		else if (dodge)
-			SelectDodgeDir (ob);
-		else
-			SelectChaseDir (ob);
-
-		if (ob->dir == nodir)
-			return;							// object is blocked in
-	}
-
-}
-
-
-
-
-/*
-=================
-=
-= T_Gift
-=
-=================
-*/
-
-void T_Gift (objtype *ob)
-{
-	s32int move;
-	s16int	dx,dy,dist;
-	int	dodge;
-
-	dodge = false;
-	dx = abs(ob->tilex - player->tilex);
-	dy = abs(ob->tiley - player->tiley);
-	dist = dx>dy ? dx : dy;
-
-	if (CheckLine(ob))						// got a shot at player?
-	{
-
-		if ( US_RndT() < (tics<<3) )
-		{
-		//
-		// go into attack frame
-		//
-			NewState (ob,&s_giftshoot1);
-			return;
-		}
-		dodge = true;
-	}
-
-	if (ob->dir == nodir)
-	{
-		if (dodge)
-			SelectDodgeDir (ob);
-		else
-			SelectChaseDir (ob);
-		if (ob->dir == nodir)
-			return;							// object is blocked in
-	}
-
-	move = ob->speed*tics;
-
-	while (move)
-	{
-		if (ob->distance < 0)
-		{
-		//
-		// waiting for a door to open
-		//
-			OpenDoor (-ob->distance-1);
-			if (doorobjlist[-ob->distance-1].action != dr_open)
-				return;
-			ob->distance = TILEGLOBAL;	// go ahead, the door is now opoen
-		}
-
-		if (move < ob->distance)
-		{
-			MoveObj (ob,move);
-			break;
-		}
-
-		//
-		// reached goal tile, so select another one
-		//
-
-		//
-		// fix position to account for round off during moving
-		//
-		ob->x = ((s32int)ob->tilex<<TILESHIFT)+TILEGLOBAL/2;
-		ob->y = ((s32int)ob->tiley<<TILESHIFT)+TILEGLOBAL/2;
-
-		move -= ob->distance;
-
-		if (dist <4)
-			SelectRunDir (ob);
-		else if (dodge)
-			SelectDodgeDir (ob);
-		else
-			SelectChaseDir (ob);
-
-		if (ob->dir == nodir)
-			return;							// object is blocked in
-	}
-
-}
-
-
-
-
-/*
-=================
-=
-= T_Fat
-=
-=================
-*/
-
-void T_Fat (objtype *ob)
-{
-	s32int move;
-	s16int	dx,dy,dist;
-	int	dodge;
-
-	dodge = false;
-	dx = abs(ob->tilex - player->tilex);
-	dy = abs(ob->tiley - player->tiley);
-	dist = dx>dy ? dx : dy;
-
-	if (CheckLine(ob))						// got a shot at player?
-	{
-
-		if ( US_RndT() < (tics<<3) )
-		{
-		//
-		// go into attack frame
-		//
-			NewState (ob,&s_fatshoot1);
-			return;
-		}
-		dodge = true;
-	}
-
-	if (ob->dir == nodir)
-	{
-		if (dodge)
-			SelectDodgeDir (ob);
-		else
-			SelectChaseDir (ob);
-		if (ob->dir == nodir)
-			return;							// object is blocked in
-	}
-
-	move = ob->speed*tics;
-
-	while (move)
-	{
-		if (ob->distance < 0)
-		{
-		//
-		// waiting for a door to open
-		//
-			OpenDoor (-ob->distance-1);
-			if (doorobjlist[-ob->distance-1].action != dr_open)
-				return;
-			ob->distance = TILEGLOBAL;	// go ahead, the door is now opoen
-		}
-
-		if (move < ob->distance)
-		{
-			MoveObj (ob,move);
-			break;
-		}
-
-		//
-		// reached goal tile, so select another one
-		//
-
-		//
-		// fix position to account for round off during moving
-		//
-		ob->x = ((s32int)ob->tilex<<TILESHIFT)+TILEGLOBAL/2;
-		ob->y = ((s32int)ob->tiley<<TILESHIFT)+TILEGLOBAL/2;
-
-		move -= ob->distance;
-
-		if (dist <4)
-			SelectRunDir (ob);
-		else if (dodge)
-			SelectDodgeDir (ob);
-		else
-			SelectChaseDir (ob);
-
-		if (ob->dir == nodir)
-			return;							// object is blocked in
-	}
-
-}
-
-
-
-/*
-=============================================================================
-
-							HITLERS
-
-=============================================================================
-*/
-
-
-//
-// fake
-//
-extern	statetype s_fakestand;
-
-extern	statetype s_fakechase1;
-extern	statetype s_fakechase1s;
-extern	statetype s_fakechase2;
-extern	statetype s_fakechase3;
-extern	statetype s_fakechase3s;
-extern	statetype s_fakechase4;
-
-extern	statetype s_fakedie1;
-extern	statetype s_fakedie2;
-extern	statetype s_fakedie3;
-extern	statetype s_fakedie4;
-extern	statetype s_fakedie5;
-extern	statetype s_fakedie6;
-
-extern	statetype s_fakeshoot1;
-extern	statetype s_fakeshoot2;
-extern	statetype s_fakeshoot3;
-extern	statetype s_fakeshoot4;
-extern	statetype s_fakeshoot5;
-extern	statetype s_fakeshoot6;
-extern	statetype s_fakeshoot7;
-extern	statetype s_fakeshoot8;
-extern	statetype s_fakeshoot9;
-
-extern	statetype s_fire1;
-extern	statetype s_fire2;
-
-statetype s_fakestand	= {false,SPR_FAKE_W1,0,T_Stand,NULL,&s_fakestand};
-
-statetype s_fakechase1 	= {false,SPR_FAKE_W1,10,T_Fake,NULL,&s_fakechase1s};
-statetype s_fakechase1s	= {false,SPR_FAKE_W1,3,NULL,NULL,&s_fakechase2};
-statetype s_fakechase2 	= {false,SPR_FAKE_W2,8,T_Fake,NULL,&s_fakechase3};
-statetype s_fakechase3 	= {false,SPR_FAKE_W3,10,T_Fake,NULL,&s_fakechase3s};
-statetype s_fakechase3s	= {false,SPR_FAKE_W3,3,NULL,NULL,&s_fakechase4};
-statetype s_fakechase4 	= {false,SPR_FAKE_W4,8,T_Fake,NULL,&s_fakechase1};
-
-statetype s_fakedie1	= {false,SPR_FAKE_DIE1,10,NULL,A_DeathScream,&s_fakedie2};
-statetype s_fakedie2	= {false,SPR_FAKE_DIE2,10,NULL,NULL,&s_fakedie3};
-statetype s_fakedie3	= {false,SPR_FAKE_DIE3,10,NULL,NULL,&s_fakedie4};
-statetype s_fakedie4	= {false,SPR_FAKE_DIE4,10,NULL,NULL,&s_fakedie5};
-statetype s_fakedie5	= {false,SPR_FAKE_DIE5,10,NULL,NULL,&s_fakedie6};
-statetype s_fakedie6	= {false,SPR_FAKE_DEAD,0,NULL,NULL,&s_fakedie6};
-
-statetype s_fakeshoot1 	= {false,SPR_FAKE_SHOOT,8,NULL,T_FakeFire,&s_fakeshoot2};
-statetype s_fakeshoot2 	= {false,SPR_FAKE_SHOOT,8,NULL,T_FakeFire,&s_fakeshoot3};
-statetype s_fakeshoot3 	= {false,SPR_FAKE_SHOOT,8,NULL,T_FakeFire,&s_fakeshoot4};
-statetype s_fakeshoot4 	= {false,SPR_FAKE_SHOOT,8,NULL,T_FakeFire,&s_fakeshoot5};
-statetype s_fakeshoot5 	= {false,SPR_FAKE_SHOOT,8,NULL,T_FakeFire,&s_fakeshoot6};
-statetype s_fakeshoot6 	= {false,SPR_FAKE_SHOOT,8,NULL,T_FakeFire,&s_fakeshoot7};
-statetype s_fakeshoot7 	= {false,SPR_FAKE_SHOOT,8,NULL,T_FakeFire,&s_fakeshoot8};
-statetype s_fakeshoot8 	= {false,SPR_FAKE_SHOOT,8,NULL,T_FakeFire,&s_fakeshoot9};
-statetype s_fakeshoot9 	= {false,SPR_FAKE_SHOOT,8,NULL,NULL,&s_fakechase1};
-
-statetype s_fire1 	= {false,SPR_FIRE1,6,NULL,T_Projectile,&s_fire2};
-statetype s_fire2 	= {false,SPR_FIRE2,6,NULL,T_Projectile,&s_fire1};
-
-//
-// hitler
-//
-extern	statetype s_mechachase1;
-extern	statetype s_mechachase1s;
-extern	statetype s_mechachase2;
-extern	statetype s_mechachase3;
-extern	statetype s_mechachase3s;
-extern	statetype s_mechachase4;
-
-extern	statetype s_mechadie1;
-extern	statetype s_mechadie2;
-extern	statetype s_mechadie3;
-extern	statetype s_mechadie4;
-
-extern	statetype s_mechashoot1;
-extern	statetype s_mechashoot2;
-extern	statetype s_mechashoot3;
-extern	statetype s_mechashoot4;
-extern	statetype s_mechashoot5;
-extern	statetype s_mechashoot6;
-
-
-extern	statetype s_hitlerchase1;
-extern	statetype s_hitlerchase1s;
-extern	statetype s_hitlerchase2;
-extern	statetype s_hitlerchase3;
-extern	statetype s_hitlerchase3s;
-extern	statetype s_hitlerchase4;
-
-extern	statetype s_hitlerdie1;
-extern	statetype s_hitlerdie2;
-extern	statetype s_hitlerdie3;
-extern	statetype s_hitlerdie4;
-extern	statetype s_hitlerdie5;
-extern	statetype s_hitlerdie6;
-extern	statetype s_hitlerdie7;
-extern	statetype s_hitlerdie8;
-extern	statetype s_hitlerdie9;
-extern	statetype s_hitlerdie10;
-
-extern	statetype s_hitlershoot1;
-extern	statetype s_hitlershoot2;
-extern	statetype s_hitlershoot3;
-extern	statetype s_hitlershoot4;
-extern	statetype s_hitlershoot5;
-extern	statetype s_hitlershoot6;
-
-extern	statetype s_hitlerdeathcam;
-
-statetype s_mechastand	= {false,SPR_MECHA_W1,0,T_Stand,NULL,&s_mechastand};
-
-statetype s_mechachase1 	= {false,SPR_MECHA_W1,10,T_Chase,A_MechaSound,&s_mechachase1s};
-statetype s_mechachase1s	= {false,SPR_MECHA_W1,6,NULL,NULL,&s_mechachase2};
-statetype s_mechachase2 	= {false,SPR_MECHA_W2,8,T_Chase,NULL,&s_mechachase3};
-statetype s_mechachase3 	= {false,SPR_MECHA_W3,10,T_Chase,A_MechaSound,&s_mechachase3s};
-statetype s_mechachase3s	= {false,SPR_MECHA_W3,6,NULL,NULL,&s_mechachase4};
-statetype s_mechachase4 	= {false,SPR_MECHA_W4,8,T_Chase,NULL,&s_mechachase1};
-
-statetype s_mechadie1	= {false,SPR_MECHA_DIE1,10,NULL,A_DeathScream,&s_mechadie2};
-statetype s_mechadie2	= {false,SPR_MECHA_DIE2,10,NULL,NULL,&s_mechadie3};
-statetype s_mechadie3	= {false,SPR_MECHA_DIE3,10,NULL,A_HitlerMorph,&s_mechadie4};
-statetype s_mechadie4	= {false,SPR_MECHA_DEAD,0,NULL,NULL,&s_mechadie4};
-
-statetype s_mechashoot1 	= {false,SPR_MECHA_SHOOT1,30,NULL,NULL,&s_mechashoot2};
-statetype s_mechashoot2 	= {false,SPR_MECHA_SHOOT2,10,NULL,T_Shoot,&s_mechashoot3};
-statetype s_mechashoot3 	= {false,SPR_MECHA_SHOOT3,10,NULL,T_Shoot,&s_mechashoot4};
-statetype s_mechashoot4 	= {false,SPR_MECHA_SHOOT2,10,NULL,T_Shoot,&s_mechashoot5};
-statetype s_mechashoot5 	= {false,SPR_MECHA_SHOOT3,10,NULL,T_Shoot,&s_mechashoot6};
-statetype s_mechashoot6 	= {false,SPR_MECHA_SHOOT2,10,NULL,T_Shoot,&s_mechachase1};
-
-
-statetype s_hitlerchase1 	= {false,SPR_HITLER_W1,6,T_Chase,NULL,&s_hitlerchase1s};
-statetype s_hitlerchase1s	= {false,SPR_HITLER_W1,4,NULL,NULL,&s_hitlerchase2};
-statetype s_hitlerchase2 	= {false,SPR_HITLER_W2,2,T_Chase,NULL,&s_hitlerchase3};
-statetype s_hitlerchase3 	= {false,SPR_HITLER_W3,6,T_Chase,NULL,&s_hitlerchase3s};
-statetype s_hitlerchase3s	= {false,SPR_HITLER_W3,4,NULL,NULL,&s_hitlerchase4};
-statetype s_hitlerchase4 	= {false,SPR_HITLER_W4,2,T_Chase,NULL,&s_hitlerchase1};
-
-statetype s_hitlerdeathcam	= {false,SPR_HITLER_W1,10,NULL,NULL,&s_hitlerdie1};
-
-statetype s_hitlerdie1	= {false,SPR_HITLER_W1,1,NULL,A_DeathScream,&s_hitlerdie2};
-statetype s_hitlerdie2	= {false,SPR_HITLER_W1,10,NULL,NULL,&s_hitlerdie3};
-statetype s_hitlerdie3	= {false,SPR_HITLER_DIE1,10,NULL,A_Slurpie,&s_hitlerdie4};
-statetype s_hitlerdie4	= {false,SPR_HITLER_DIE2,10,NULL,NULL,&s_hitlerdie5};
-statetype s_hitlerdie5	= {false,SPR_HITLER_DIE3,10,NULL,NULL,&s_hitlerdie6};
-statetype s_hitlerdie6	= {false,SPR_HITLER_DIE4,10,NULL,NULL,&s_hitlerdie7};
-statetype s_hitlerdie7	= {false,SPR_HITLER_DIE5,10,NULL,NULL,&s_hitlerdie8};
-statetype s_hitlerdie8	= {false,SPR_HITLER_DIE6,10,NULL,NULL,&s_hitlerdie9};
-statetype s_hitlerdie9	= {false,SPR_HITLER_DIE7,10,NULL,NULL,&s_hitlerdie10};
-statetype s_hitlerdie10	= {false,SPR_HITLER_DEAD,20,NULL,A_StartDeathCam,&s_hitlerdie10};
-
-statetype s_hitlershoot1 	= {false,SPR_HITLER_SHOOT1,30,NULL,NULL,&s_hitlershoot2};
-statetype s_hitlershoot2 	= {false,SPR_HITLER_SHOOT2,10,NULL,T_Shoot,&s_hitlershoot3};
-statetype s_hitlershoot3 	= {false,SPR_HITLER_SHOOT3,10,NULL,T_Shoot,&s_hitlershoot4};
-statetype s_hitlershoot4 	= {false,SPR_HITLER_SHOOT2,10,NULL,T_Shoot,&s_hitlershoot5};
-statetype s_hitlershoot5 	= {false,SPR_HITLER_SHOOT3,10,NULL,T_Shoot,&s_hitlershoot6};
-statetype s_hitlershoot6 	= {false,SPR_HITLER_SHOOT2,10,NULL,T_Shoot,&s_hitlerchase1};
-
-
-
-/*
-===============
-=
-= SpawnFakeHitler
-=
-===============
-*/
-
-void SpawnFakeHitler (s16int tilex, s16int tiley)
-{
-	u16int	far *map,tile;
-
-
-	if (DigiMode != sds_Off)
-	  s_hitlerdie2.tictime = 140;
-	else
-	  s_hitlerdie2.tictime = 5;
-
-	SpawnNewObj (tilex,tiley,&s_fakestand);
-	new->speed = SPDPATROL;
-
-	new->obclass = fakeobj;
-	new->hitpoints = starthitpoints[gamestate.difficulty][en_fake];
-	new->dir = north;
-	new->flags |= FL_SHOOTABLE|FL_AMBUSH;
-	if (!loadedgame)
-	  gamestate.killtotal++;
-}
-
-
-/*
-===============
-=
-= SpawnHitler
-=
-===============
-*/
-
-void SpawnHitler (s16int tilex, s16int tiley)
-{
-	u16int	far *map,tile;
-
-	if (DigiMode != sds_Off)
-		s_hitlerdie2.tictime = 140;
-	else
-		s_hitlerdie2.tictime = 5;
-
-
-	SpawnNewObj (tilex,tiley,&s_mechastand);
-	new->speed = SPDPATROL;
-
-	new->obclass = mechahitlerobj;
-	new->hitpoints = starthitpoints[gamestate.difficulty][en_hitler];
-	new->dir = south;
-	new->flags |= FL_SHOOTABLE|FL_AMBUSH;
-	if (!loadedgame)
-	  gamestate.killtotal++;
-}
-
-
-/*
-===============
-=
-= A_HitlerMorph
-=
-===============
-*/
-
-void A_HitlerMorph (objtype *ob)
-{
-	u16int	far *map,tile,hitpoints[4]={500,700,800,900};
-
-
-	SpawnNewObj (ob->tilex,ob->tiley,&s_hitlerchase1);
-	new->speed = SPDPATROL*5;
-
-	new->x = ob->x;
-	new->y = ob->y;
-
-	new->distance = ob->distance;
-	new->dir = ob->dir;
-	new->flags = ob->flags | FL_SHOOTABLE;
-
-	new->obclass = realhitlerobj;
-	new->hitpoints = hitpoints[gamestate.difficulty];
-}
-
-
-////////////////////////////////////////////////////////
-//
-// A_MechaSound
-// A_Slurpie
-//
-////////////////////////////////////////////////////////
-void A_MechaSound (objtype *ob)
-{
-	if (areabyplayer[ob->areanumber])
-		PlaySoundLocActor (Smechwalk,ob);
-}
-
-
-#pragma argsused
-void A_Slurpie (objtype *ob)
-{
- SD_PlaySound(Sslurp);
-}
-
-/*
-=================
-=
-= T_FakeFire
-=
-=================
-*/
-
-void T_FakeFire (objtype *ob)
-{
-	s32int	deltax,deltay;
-	float	angle;
-	s16int		iangle;
-
-	deltax = player->x - ob->x;
-	deltay = ob->y - player->y;
-	angle = atan2 (deltay,deltax);
-	if (angle<0)
-		angle = M_PI*2+angle;
-	iangle = angle/(M_PI*2)*ANGLES;
-
-	GetNewActor ();
-	new->state = &s_fire1;
-	new->ticcount = 1;
-
-	new->tilex = ob->tilex;
-	new->tiley = ob->tiley;
-	new->x = ob->x;
-	new->y = ob->y;
-	new->dir = nodir;
-	new->angle = iangle;
-	new->obclass = fireobj;
-	new->speed = 0x1200l;
-	new->flags = FL_NEVERMARK;
-	new->active = true;
-
-	PlaySoundLocActor (Sflame,new);
-}
-
-
-
-/*
-=================
-=
-= T_Fake
-=
-=================
-*/
-
-void T_Fake (objtype *ob)
-{
-	s32int move;
-	s16int	dx,dy,dist;
-	int	dodge;
-
-	if (CheckLine(ob))			// got a shot at player?
-	{
-		if ( US_RndT() < (tics<<1) )
-		{
-		//
-		// go into attack frame
-		//
-			NewState (ob,&s_fakeshoot1);
-			return;
-		}
-	}
-
-	if (ob->dir == nodir)
-	{
-		SelectDodgeDir (ob);
-		if (ob->dir == nodir)
-			return;							// object is blocked in
-	}
-
-	move = ob->speed*tics;
-
-	while (move)
-	{
-		if (move < ob->distance)
-		{
-			MoveObj (ob,move);
-			break;
-		}
-
-		//
-		// reached goal tile, so select another one
-		//
-
-		//
-		// fix position to account for round off during moving
-		//
-		ob->x = ((s32int)ob->tilex<<TILESHIFT)+TILEGLOBAL/2;
-		ob->y = ((s32int)ob->tiley<<TILESHIFT)+TILEGLOBAL/2;
-
-		move -= ob->distance;
-
-		SelectDodgeDir (ob);
-
-		if (ob->dir == nodir)
-			return;							// object is blocked in
-	}
-
-}
-
-#endif
-/*
-============================================================================
-
-							STAND
-
-============================================================================
-*/
-
-
-/*
-===============
-=
-= T_Stand
-=
-===============
-*/
-
-void T_Stand (objtype *ob)
-{
-	SightPlayer (ob);
-}
-
-
-/*
-============================================================================
-
-								CHASE
-
-============================================================================
-*/
-
-/*
-=================
-=
-= T_Chase
-=
-=================
-*/
-
-void T_Chase (objtype *ob)
-{
-	s32int move;
-	s16int	dx,dy,dist,chance;
-	int	dodge;
-
-	if (gamestate.victoryflag)
-		return;
-
-	dodge = false;
-	if (CheckLine(ob))	// got a shot at player?
-	{
-		dx = abs(ob->tilex - player->tilex);
-		dy = abs(ob->tiley - player->tiley);
-		dist = dx>dy ? dx : dy;
-		if (!dist || (dist==1 && ob->distance<0x4000) )
-			chance = 300;
-		else
-			chance = (tics<<4)/dist;
-
-		if ( US_RndT()<chance)
-		{
-		//
-		// go into attack frame
-		//
-			switch (ob->obclass)
-			{
-			case guardobj:
-				NewState (ob,&s_grdshoot1);
-				break;
-			case officerobj:
-				NewState (ob,&s_ofcshoot1);
-				break;
-			case mutantobj:
-				NewState (ob,&s_mutshoot1);
-				break;
-			case ssobj:
-				NewState (ob,&s_ssshoot1);
-				break;
-#ifndef SPEAR
-			case bossobj:
-				NewState (ob,&s_bossshoot1);
-				break;
-			case gretelobj:
-				NewState (ob,&s_gretelshoot1);
-				break;
-			case mechahitlerobj:
-				NewState (ob,&s_mechashoot1);
-				break;
-			case realhitlerobj:
-				NewState (ob,&s_hitlershoot1);
-				break;
-#else
-			case angelobj:
-				NewState (ob,&s_angelshoot1);
-				break;
-			case transobj:
-				NewState (ob,&s_transshoot1);
-				break;
-			case uberobj:
-				NewState (ob,&s_ubershoot1);
-				break;
-			case willobj:
-				NewState (ob,&s_willshoot1);
-				break;
-			case deathobj:
-				NewState (ob,&s_deathshoot1);
-				break;
-#endif
-			}
-			return;
-		}
-		dodge = true;
-	}
-
-	if (ob->dir == nodir)
-	{
-		if (dodge)
-			SelectDodgeDir (ob);
-		else
-			SelectChaseDir (ob);
-		if (ob->dir == nodir)
-			return;							// object is blocked in
-	}
-
-	move = ob->speed*tics;
-
-	while (move)
-	{
-		if (ob->distance < 0)
-		{
-		//
-		// waiting for a door to open
-		//
-			OpenDoor (-ob->distance-1);
-			if (doorobjlist[-ob->distance-1].action != dr_open)
-				return;
-			ob->distance = TILEGLOBAL;	// go ahead, the door is now opoen
-		}
-
-		if (move < ob->distance)
-		{
-			MoveObj (ob,move);
-			break;
-		}
-
-		//
-		// reached goal tile, so select another one
-		//
-
-		//
-		// fix position to account for round off during moving
-		//
-		ob->x = ((s32int)ob->tilex<<TILESHIFT)+TILEGLOBAL/2;
-		ob->y = ((s32int)ob->tiley<<TILESHIFT)+TILEGLOBAL/2;
-
-		move -= ob->distance;
-
-		if (dodge)
-			SelectDodgeDir (ob);
-		else
-			SelectChaseDir (ob);
-
-		if (ob->dir == nodir)
-			return;							// object is blocked in
-	}
-
-}
-
-
-/*
-=================
-=
-= T_Ghosts
-=
-=================
-*/
-
-void T_Ghosts (objtype *ob)
-{
-	s32int move;
-
-
-	if (ob->dir == nodir)
-	{
-		SelectChaseDir (ob);
-		if (ob->dir == nodir)
-			return;							// object is blocked in
-	}
-
-	move = ob->speed*tics;
-
-	while (move)
-	{
-		if (move < ob->distance)
-		{
-			MoveObj (ob,move);
-			break;
-		}
-
-		//
-		// reached goal tile, so select another one
-		//
-
-		//
-		// fix position to account for round off during moving
-		//
-		ob->x = ((s32int)ob->tilex<<TILESHIFT)+TILEGLOBAL/2;
-		ob->y = ((s32int)ob->tiley<<TILESHIFT)+TILEGLOBAL/2;
-
-		move -= ob->distance;
-
-		SelectChaseDir (ob);
-
-		if (ob->dir == nodir)
-			return;							// object is blocked in
-	}
-
-}
-
-/*
-=================
-=
-= T_DogChase
-=
-=================
-*/
-
-void T_DogChase (objtype *ob)
-{
-	s32int 	move;
-	s16int		dist,chance;
-	s32int	dx,dy;
-
-
-	if (ob->dir == nodir)
-	{
-		SelectDodgeDir (ob);
-		if (ob->dir == nodir)
-			return;							// object is blocked in
-	}
-
-	move = ob->speed*tics;
-
-	while (move)
-	{
-	//
-	// check for byte range
-	//
-		dx = player->x - ob->x;
-		if (dx<0)
-			dx = -dx;
-		dx -= move;
-		if (dx <= MINACTORDIST)
-		{
-			dy = player->y - ob->y;
-			if (dy<0)
-				dy = -dy;
-			dy -= move;
-			if (dy <= MINACTORDIST)
-			{
-				NewState (ob,&s_dogjump1);
-				return;
-			}
-		}
-
-		if (move < ob->distance)
-		{
-			MoveObj (ob,move);
-			break;
-		}
-
-		//
-		// reached goal tile, so select another one
-		//
-
-		//
-		// fix position to account for round off during moving
-		//
-		ob->x = ((s32int)ob->tilex<<TILESHIFT)+TILEGLOBAL/2;
-		ob->y = ((s32int)ob->tiley<<TILESHIFT)+TILEGLOBAL/2;
-
-		move -= ob->distance;
-
-		SelectDodgeDir (ob);
-
-		if (ob->dir == nodir)
-			return;							// object is blocked in
-	}
-
-}
-
-
-
-/*
-============================================================================
-
-								PATH
-
-============================================================================
-*/
-
-
-/*
-===============
-=
-= SelectPathDir
-=
-===============
-*/
-
-void SelectPathDir (objtype *ob)
-{
-	u16int spot;
-
-	spot = MAPSPOT(ob->tilex,ob->tiley,1)-ICONARROWS;
-
-	if (spot<8)
-	{
-	// new direction
-		ob->dir = spot;
-	}
-
-	ob->distance = TILEGLOBAL;
-
-	if (!TryWalk (ob))
-		ob->dir = nodir;
-}
-
-
-/*
-===============
-=
-= T_Path
-=
-===============
-*/
-
-void T_Path (objtype *ob)
-{
-	s32int 	move;
-	s32int 	deltax,deltay,size;
-
-	if (SightPlayer (ob))
-		return;
-
-	if (ob->dir == nodir)
-	{
-		SelectPathDir (ob);
-		if (ob->dir == nodir)
-			return;					// all movement is blocked
-	}
-
-
-	move = ob->speed*tics;
-
-	while (move)
-	{
-		if (ob->distance < 0)
-		{
-		//
-		// waiting for a door to open
-		//
-			OpenDoor (-ob->distance-1);
-			if (doorobjlist[-ob->distance-1].action != dr_open)
-				return;
-			ob->distance = TILEGLOBAL;	// go ahead, the door is now opoen
-		}
-
-		if (move < ob->distance)
-		{
-			MoveObj (ob,move);
-			break;
-		}
-
-		if (ob->tilex>MAPSIZE || ob->tiley>MAPSIZE)
-		{
-			sprintf (str,"T_Path hit a wall at %u,%u, dir %u"
-			,ob->tilex,ob->tiley,ob->dir);
-			Quit (str);
-		}
-
-
-
-		ob->x = ((s32int)ob->tilex<<TILESHIFT)+TILEGLOBAL/2;
-		ob->y = ((s32int)ob->tiley<<TILESHIFT)+TILEGLOBAL/2;
-		move -= ob->distance;
-
-		SelectPathDir (ob);
-
-		if (ob->dir == nodir)
-			return;					// all movement is blocked
-	}
-}
-
-
-/*
-=============================================================================
-
-								FIGHT
-
-=============================================================================
-*/
-
-
-/*
-===============
-=
-= T_Shoot
-=
-= Try to damage the player, based on skill level and player's speed
-=
-===============
-*/
-
-void T_Shoot (objtype *ob)
-{
-	s16int	dx,dy,dist;
-	s16int	hitchance,damage;
-
-	hitchance = 128;
-
-	if (!areabyplayer[ob->areanumber])
-		return;
-
-	if (!CheckLine (ob))			// player is behind a wall
-	  return;
-
-	dx = abs(ob->tilex - player->tilex);
-	dy = abs(ob->tiley - player->tiley);
-	dist = dx>dy ? dx:dy;
-
-	if (ob->obclass == ssobj || ob->obclass == bossobj)
-		dist = dist*2/3;					// ss are better shots
-
-	if (thrustspeed >= RUNSPEED)
-	{
-		if (ob->flags&FL_VISABLE)
-			hitchance = 160-dist*16;		// player can see to dodge
-		else
-			hitchance = 160-dist*8;
-	}
-	else
-	{
-		if (ob->flags&FL_VISABLE)
-			hitchance = 256-dist*16;		// player can see to dodge
-		else
-			hitchance = 256-dist*8;
-	}
-
-// see if the shot was a hit
-
-	if (US_RndT()<hitchance)
-	{
-		if (dist<2)
-			damage = US_RndT()>>2;
-		else if (dist<4)
-			damage = US_RndT()>>3;
-		else
-			damage = US_RndT()>>4;
-
-		TakeDamage (damage,ob);
-	}
-
-	switch(ob->obclass)
-	{
-	 case ssobj:
-	   PlaySoundLocActor(Sssfire,ob);
-	   break;
-#ifndef SPEAR
-	 case giftobj:
-	 case fatobj:
-	   PlaySoundLocActor(Smissile,ob);
-	   break;
-	 case mechahitlerobj:
-	 case realhitlerobj:
-	 case bossobj:
-	   PlaySoundLocActor(Shansfire,ob);
-	   break;
-	 case schabbobj:
-	   PlaySoundLocActor(Sthrow,ob);
-	   break;
-	 case fakeobj:
-	   PlaySoundLocActor(Sflame,ob);
-	   break;
-#endif
-	 default:
-	   PlaySoundLocActor(Sgdfire,ob);
-	}
-
-}
-
-
-/*
-===============
-=
-= T_Bite
-=
-===============
-*/
-
-void T_Bite (objtype *ob)
-{
-	s32int	dx,dy;
-	s16int	hitchance,damage;
-
-
-	PlaySoundLocActor(Sdogfire,ob);	// JAB
-
-	dx = player->x - ob->x;
-	if (dx<0)
-		dx = -dx;
-	dx -= TILEGLOBAL;
-	if (dx <= MINACTORDIST)
-	{
-		dy = player->y - ob->y;
-		if (dy<0)
-			dy = -dy;
-		dy -= TILEGLOBAL;
-		if (dy <= MINACTORDIST)
-		{
-		   if (US_RndT()<180)
-		   {
-			   TakeDamage (US_RndT()>>4,ob);
-			   return;
-		   }
-		}
-	}
-
-	return;
-}
-
-
-#ifndef SPEAR
-/*
-============================================================================
-
-							BJ VICTORY
-
-============================================================================
-*/
-
-
-//
-// BJ victory
-//
-
-void T_BJRun (objtype *ob);
-void T_BJJump (objtype *ob);
-void T_BJDone (objtype *ob);
-void T_BJYell (objtype *ob);
-
-void T_DeathCam (objtype *ob);
-
-extern	statetype s_bjrun1;
-extern	statetype s_bjrun1s;
-extern	statetype s_bjrun2;
-extern	statetype s_bjrun3;
-extern	statetype s_bjrun3s;
-extern	statetype s_bjrun4;
-
-extern	statetype s_bjjump1;
-extern	statetype s_bjjump2;
-extern	statetype s_bjjump3;
-extern	statetype s_bjjump4;
-
-
-statetype s_bjrun1 	= {false,SPR_BJ_W1,12,T_BJRun,NULL,&s_bjrun1s};
-statetype s_bjrun1s	= {false,SPR_BJ_W1,3, NULL,NULL,&s_bjrun2};
-statetype s_bjrun2 	= {false,SPR_BJ_W2,8,T_BJRun,NULL,&s_bjrun3};
-statetype s_bjrun3 	= {false,SPR_BJ_W3,12,T_BJRun,NULL,&s_bjrun3s};
-statetype s_bjrun3s	= {false,SPR_BJ_W3,3, NULL,NULL,&s_bjrun4};
-statetype s_bjrun4 	= {false,SPR_BJ_W4,8,T_BJRun,NULL,&s_bjrun1};
-
-
-statetype s_bjjump1	= {false,SPR_BJ_JUMP1,14,T_BJJump,NULL,&s_bjjump2};
-statetype s_bjjump2	= {false,SPR_BJ_JUMP2,14,T_BJJump,T_BJYell,&s_bjjump3};
-statetype s_bjjump3	= {false,SPR_BJ_JUMP3,14,T_BJJump,NULL,&s_bjjump4};
-statetype s_bjjump4	= {false,SPR_BJ_JUMP4,300,NULL,T_BJDone,&s_bjjump4};
-
-
-statetype s_deathcam = {false,0,0,NULL,NULL,NULL};
-
-
-/*
-===============
-=
-= SpawnBJVictory
-=
-===============
-*/
-
-void SpawnBJVictory (void)
-{
-	u16int	far *map,tile;
-
-	SpawnNewObj (player->tilex,player->tiley+1,&s_bjrun1);
-	new->x = player->x;
-	new->y = player->y;
-	new->obclass = bjobj;
-	new->dir = north;
-	new->temp1 = 6;			// tiles to run forward
-}
-
-
-
-/*
-===============
-=
-= T_BJRun
-=
-===============
-*/
-
-void T_BJRun (objtype *ob)
-{
-	s32int 	move;
-
-	move = BJRUNSPEED*tics;
-
-	while (move)
-	{
-		if (move < ob->distance)
-		{
-			MoveObj (ob,move);
-			break;
-		}
-
-
-		ob->x = ((s32int)ob->tilex<<TILESHIFT)+TILEGLOBAL/2;
-		ob->y = ((s32int)ob->tiley<<TILESHIFT)+TILEGLOBAL/2;
-		move -= ob->distance;
-
-		SelectPathDir (ob);
-
-		if ( !(--ob->temp1) )
-		{
-			NewState (ob,&s_bjjump1);
-			return;
-		}
-	}
-}
-
-
-/*
-===============
-=
-= T_BJJump
-=
-===============
-*/
-
-void T_BJJump (objtype *ob)
-{
-	s32int 	move;
-
-	move = BJJUMPSPEED*tics;
-	MoveObj (ob,move);
-}
-
-
-/*
-===============
-=
-= T_BJYell
-=
-===============
-*/
-
-void T_BJYell (objtype *ob)
-{
-	PlaySoundLocActor(Syeah,ob);	// JAB
-}
-
-
-/*
-===============
-=
-= T_BJDone
-=
-===============
-*/
-
-#pragma argsused
-void T_BJDone (objtype *ob)
-{
-	playstate = ex_victorious;				// exit castle tile
-}
-
-
-
-//===========================================================================
-
-
-/*
-===============
-=
-= CheckPosition
-=
-===============
-*/
-
-int	CheckPosition (objtype *ob)
-{
-	s16int	x,y,xl,yl,xh,yh;
-	objtype *check;
-
-	xl = (ob->x-PLAYERSIZE) >>TILESHIFT;
-	yl = (ob->y-PLAYERSIZE) >>TILESHIFT;
-
-	xh = (ob->x+PLAYERSIZE) >>TILESHIFT;
-	yh = (ob->y+PLAYERSIZE) >>TILESHIFT;
-
-	//
-	// check for solid walls
-	//
-	for (y=yl;y<=yh;y++)
-		for (x=xl;x<=xh;x++)
-		{
-			check = actorat[x][y];
-			if (check && check<objlist)
-				return false;
-		}
-
-	return true;
-}
-
-
-/*
-===============
-=
-= A_StartDeathCam
-=
-===============
-*/
-
-void	A_StartDeathCam (objtype *ob)
-{
-	s32int	dx,dy;
-	float	fangle;
-	s32int    xmove,ymove;
-	s32int	dist;
-	s16int		temp,i;
-
-	FinishPaletteShifts ();
-
-	VW_WaitVBL (100);
-
-	if (gamestate.victoryflag)
-	{
-		playstate = ex_victorious;				// exit castle tile
-		return;
-	}
-
-	gamestate.victoryflag = true;
-	VW_Bar (0,0,320,200-STATUSLINES,127);
-	FizzleFade(bufferofs,displayofs,320,200-STATUSLINES,70,false);
-
-	PM_UnlockMainMem ();
-	CA_UpLevel ();
-	Write(0,7,"Let's see that again!");
-	CA_DownLevel ();
-	PM_CheckMainMem ();
-
-	VW_UpdateScreen ();
-
-	IN_UserInput(300);
-
-//
-// line angle up exactly
-//
-	NewState (player,&s_deathcam);
-
-	player->x = gamestate.killx;
-	player->y = gamestate.killy;
-
-	dx = ob->x - player->x;
-	dy = player->y - ob->y;
-
-	fangle = atan2(dy,dx);			// returns -pi to pi
-	if (fangle<0)
-		fangle = M_PI*2+fangle;
-
-	player->angle = fangle/(M_PI*2)*ANGLES;
-
-//
-// try to position as close as possible without being in a wall
-//
-	dist = 0x14000l;
-	do
-	{
-		xmove = FixedByFrac(dist,costable[player->angle]);
-		ymove = -FixedByFrac(dist,sintable[player->angle]);
-
-		player->x = ob->x - xmove;
-		player->y = ob->y - ymove;
-		dist += 0x1000;
-
-	} while (!CheckPosition (player));
-	plux = player->x >> UNSIGNEDSHIFT;			// scale to fit in u16int
-	pluy = player->y >> UNSIGNEDSHIFT;
-	player->tilex = player->x >> TILESHIFT;		// scale to tile values
-	player->tiley = player->y >> TILESHIFT;
-
-//
-// go back to the game
-//
-	temp = bufferofs;
-	for (i=0;i<3;i++)
-	{
-		bufferofs = screenloc[i];
-		DrawPlayBorder ();
-	}
-	bufferofs = temp;
-
-	fizzlein = true;
-	switch (ob->obclass)
-	{
-#ifndef SPEAR
-	case schabbobj:
-		NewState (ob,&s_schabbdeathcam);
-		break;
-	case realhitlerobj:
-		NewState (ob,&s_hitlerdeathcam);
-		break;
-	case giftobj:
-		NewState (ob,&s_giftdeathcam);
-		break;
-	case fatobj:
-		NewState (ob,&s_fatdeathcam);
-		break;
-#endif
-	}
-
-}
-
-#endif
--- a/agent.c
+++ /dev/null
@@ -1,1421 +1,0 @@
-// WL_AGENT.C
-
-#include "WL_DEF.H"
-#pragma hdrstop
-
-
-/*
-=============================================================================
-
-						 LOCAL CONSTANTS
-
-=============================================================================
-*/
-
-#define MAXMOUSETURN	10
-
-
-#define MOVESCALE		150l
-#define BACKMOVESCALE	100l
-#define ANGLESCALE		20
-
-/*
-=============================================================================
-
-						 GLOBAL VARIABLES
-
-=============================================================================
-*/
-
-
-
-//
-// player state info
-//
-int		running;
-s32int		thrustspeed;
-
-u16int	plux,pluy;			// player coordinates scaled to u16int
-
-s16int			anglefrac;
-s16int			gotgatgun;	// JR
-
-objtype		*LastAttacker;
-
-/*
-=============================================================================
-
-						 LOCAL VARIABLES
-
-=============================================================================
-*/
-
-
-void	T_Player (objtype *ob);
-void	T_Attack (objtype *ob);
-
-statetype s_player = {false,0,0,T_Player,NULL,NULL};
-statetype s_attack = {false,0,0,T_Attack,NULL,NULL};
-
-
-s32int	playerxmove,playerymove;
-
-struct atkinf
-{
-	char	tics,attack,frame;		// attack is 1 for gun, 2 for knife
-} attackinfo[4][14] =
-
-{
-{ {6,0,1},{6,2,2},{6,0,3},{6,-1,4} },
-{ {6,0,1},{6,1,2},{6,0,3},{6,-1,4} },
-{ {6,0,1},{6,1,2},{6,3,3},{6,-1,4} },
-{ {6,0,1},{6,1,2},{6,4,3},{6,-1,4} },
-};
-
-
-s16int	strafeangle[9] = {0,90,180,270,45,135,225,315,0};
-
-void DrawWeapon (void);
-void GiveWeapon (s16int weapon);
-void	GiveAmmo (s16int ammo);
-
-//===========================================================================
-
-//----------
-
-void Attack (void);
-void Use (void);
-void Search (objtype *ob);
-void SelectWeapon (void);
-void SelectItem (void);
-
-//----------
-
-int TryMove (objtype *ob);
-void T_Player (objtype *ob);
-
-void ClipMove (objtype *ob, s32int xmove, s32int ymove);
-
-/*
-=============================================================================
-
-						CONTROL STUFF
-
-=============================================================================
-*/
-
-/*
-======================
-=
-= CheckWeaponChange
-=
-= Keys 1-4 change weapons
-=
-======================
-*/
-
-void CheckWeaponChange (void)
-{
-	s16int	i,buttons;
-
-	if (!gamestate.ammo)		// must use knife with no ammo
-		return;
-
-	for (i=wp_knife ; i<=gamestate.bestweapon ; i++)
-		if (buttonstate[bt_readyknife+i-wp_knife])
-		{
-			gamestate.weapon = gamestate.chosenweapon = i;
-			DrawWeapon ();
-			return;
-		}
-}
-
-
-/*
-=======================
-=
-= ControlMovement
-=
-= Takes controlx,controly, and buttonstate[bt_strafe]
-=
-= Changes the player's angle and position
-=
-= There is an angle hack because when going 70 fps, the roundoff becomes
-= significant
-=
-=======================
-*/
-
-void ControlMovement (objtype *ob)
-{
-	s32int	oldx,oldy;
-	s16int		angle,maxxmove;
-	s16int		angleunits;
-	s32int	speed;
-
-	thrustspeed = 0;
-
-	oldx = player->x;
-	oldy = player->y;
-
-//
-// side to side move
-//
-	if (buttonstate[bt_strafe])
-	{
-	//
-	// strafing
-	//
-	//
-		if (controlx > 0)
-		{
-			angle = ob->angle - ANGLES/4;
-			if (angle < 0)
-				angle += ANGLES;
-			Thrust (angle,controlx*MOVESCALE);	// move to left
-		}
-		else if (controlx < 0)
-		{
-			angle = ob->angle + ANGLES/4;
-			if (angle >= ANGLES)
-				angle -= ANGLES;
-			Thrust (angle,-controlx*MOVESCALE);	// move to right
-		}
-	}
-	else
-	{
-	//
-	// not strafing
-	//
-		anglefrac += controlx;
-		angleunits = anglefrac/ANGLESCALE;
-		anglefrac -= angleunits*ANGLESCALE;
-		ob->angle -= angleunits;
-
-		if (ob->angle >= ANGLES)
-			ob->angle -= ANGLES;
-		if (ob->angle < 0)
-			ob->angle += ANGLES;
-
-	}
-
-//
-// forward/backwards move
-//
-	if (controly < 0)
-	{
-		Thrust (ob->angle,-controly*MOVESCALE);	// move forwards
-	}
-	else if (controly > 0)
-	{
-		angle = ob->angle + ANGLES/2;
-		if (angle >= ANGLES)
-			angle -= ANGLES;
-		Thrust (angle,controly*BACKMOVESCALE);		// move backwards
-	}
-
-	if (gamestate.victoryflag)		// watching the BJ actor
-		return;
-
-//
-// calculate total move
-//
-	playerxmove = player->x - oldx;
-	playerymove = player->y - oldy;
-}
-
-/*
-=============================================================================
-
-					STATUS WINDOW STUFF
-
-=============================================================================
-*/
-
-
-/*
-==================
-=
-= StatusDrawPic
-=
-==================
-*/
-
-void StatusDrawPic (u16int x, u16int y, u16int picnum)
-{
-	u16int	temp;
-
-	temp = bufferofs;
-	bufferofs = 0;
-
-	bufferofs = PAGE1START+(200-STATUSLINES)*SCREENWIDTH;
-	LatchDrawPic (x,y,picnum);
-	bufferofs = PAGE2START+(200-STATUSLINES)*SCREENWIDTH;
-	LatchDrawPic (x,y,picnum);
-	bufferofs = PAGE3START+(200-STATUSLINES)*SCREENWIDTH;
-	LatchDrawPic (x,y,picnum);
-
-	bufferofs = temp;
-}
-
-
-/*
-==================
-=
-= DrawFace
-=
-==================
-*/
-
-void DrawFace (void)
-{
-	if (gamestate.health)
-	{
-		#ifdef SPEAR
-		if (godmode)
-			StatusDrawPic (17,4,Pgod+gamestate.faceframe);
-		else
-		#endif
-		StatusDrawPic (17,4,Pface1+3*((100-gamestate.health)/16)+gamestate.faceframe);
-	}
-	else
-	{
-#ifndef SPEAR
-	 if (LastAttacker->obclass == needleobj)
-	   StatusDrawPic (17,4,MUTANTBJPIC);
-	 else
-#endif
-	   StatusDrawPic (17,4,Pface8);
-	}
-}
-
-
-/*
-===============
-=
-= UpdateFace
-=
-= Calls draw face if time to change
-=
-===============
-*/
-
-#define FACETICS	70
-
-s16int	facecount;
-
-void	UpdateFace (void)
-{
-
-	if (SD_SoundPlaying() == Sgetgatling)
-	  return;
-
-	facecount += tics;
-	if (facecount > US_RndT())
-	{
-		gamestate.faceframe = (US_RndT()>>6);
-		if (gamestate.faceframe==3)
-			gamestate.faceframe = 1;
-
-		facecount = 0;
-		DrawFace ();
-	}
-}
-
-
-
-/*
-===============
-=
-= LatchNumber
-=
-= right justifies and pads with blanks
-=
-===============
-*/
-
-void	LatchNumber (s16int x, s16int y, s16int width, s32int number)
-{
-	u16int	length,c;
-	char	str[20];
-
-	ltoa (number,str,10);
-
-	length = strlen (str);
-
-	while (length<width)
-	{
-		StatusDrawPic (x,y,Pblank);
-		x++;
-		width--;
-	}
-
-	c= length <= width ? 0 : length-width;
-
-	while (c<length)
-	{
-		StatusDrawPic (x,y,str[c]-'0'+ Pn0);
-		x++;
-		c++;
-	}
-}
-
-
-/*
-===============
-=
-= DrawHealth
-=
-===============
-*/
-
-void	DrawHealth (void)
-{
-	LatchNumber (21,16,3,gamestate.health);
-}
-
-
-/*
-===============
-=
-= TakeDamage
-=
-===============
-*/
-
-void	TakeDamage (s16int points,objtype *attacker)
-{
-	LastAttacker = attacker;
-
-	if (gamestate.victoryflag)
-		return;
-	if (gamestate.difficulty==gd_baby)
-	  points>>=2;
-
-	if (!godmode)
-		gamestate.health -= points;
-
-	if (gamestate.health<=0)
-	{
-		gamestate.health = 0;
-		playstate = ex_died;
-		killerobj = attacker;
-	}
-
-	StartDamageFlash (points);
-
-	gotgatgun=0;
-
-	DrawHealth ();
-	DrawFace ();
-
-	//
-	// MAKE BJ'S EYES BUG IF MAJOR DAMAGE!
-	//
-	#ifdef SPEAR
-	if (points > 30 && gamestate.health!=0 && !godmode)
-	{
-		StatusDrawPic (17,4,Pouch);
-		facecount = 0;
-	}
-	#endif
-
-}
-
-
-/*
-===============
-=
-= HealSelf
-=
-===============
-*/
-
-void	HealSelf (s16int points)
-{
-	gamestate.health += points;
-	if (gamestate.health>100)
-		gamestate.health = 100;
-
-	DrawHealth ();
-	gotgatgun = 0;	// JR
-	DrawFace ();
-}
-
-
-//===========================================================================
-
-
-/*
-===============
-=
-= DrawLevel
-=
-===============
-*/
-
-void	DrawLevel (void)
-{
-#ifdef SPEAR
-	if (gamestate.mapon == 20)
-		LatchNumber (2,16,2,18);
-	else
-#endif
-	LatchNumber (2,16,2,gamestate.mapon+1);
-}
-
-//===========================================================================
-
-
-/*
-===============
-=
-= DrawLives
-=
-===============
-*/
-
-void	DrawLives (void)
-{
-	LatchNumber (14,16,1,gamestate.lives);
-}
-
-
-/*
-===============
-=
-= GiveExtraMan
-=
-===============
-*/
-
-void	GiveExtraMan (void)
-{
-	if (gamestate.lives<9)
-		gamestate.lives++;
-	DrawLives ();
-	SD_PlaySound (S1up);
-}
-
-//===========================================================================
-
-/*
-===============
-=
-= DrawScore
-=
-===============
-*/
-
-void	DrawScore (void)
-{
-	LatchNumber (6,16,6,gamestate.score);
-}
-
-/*
-===============
-=
-= GivePoints
-=
-===============
-*/
-
-void	GivePoints (s32int points)
-{
-	gamestate.score += points;
-	while (gamestate.score >= gamestate.nextextra)
-	{
-		gamestate.nextextra += EXTRAPOINTS;
-		GiveExtraMan ();
-	}
-	DrawScore ();
-}
-
-//===========================================================================
-
-/*
-==================
-=
-= DrawWeapon
-=
-==================
-*/
-
-void DrawWeapon (void)
-{
-	StatusDrawPic (32,8,Pknife+gamestate.weapon);
-}
-
-
-/*
-==================
-=
-= DrawKeys
-=
-==================
-*/
-
-void DrawKeys (void)
-{
-	if (gamestate.keys & 1)
-		StatusDrawPic (30,4,Pgkey);
-	else
-		StatusDrawPic (30,4,Pnokey);
-
-	if (gamestate.keys & 2)
-		StatusDrawPic (30,20,Pskey);
-	else
-		StatusDrawPic (30,20,Pnokey);
-}
-
-
-
-/*
-==================
-=
-= GiveWeapon
-=
-==================
-*/
-
-void GiveWeapon (s16int weapon)
-{
-	GiveAmmo (6);
-
-	if (gamestate.bestweapon<weapon)
-		gamestate.bestweapon = gamestate.weapon
-		= gamestate.chosenweapon = weapon;
-
-	DrawWeapon ();
-}
-
-
-//===========================================================================
-
-/*
-===============
-=
-= DrawAmmo
-=
-===============
-*/
-
-void	DrawAmmo (void)
-{
-	LatchNumber (27,16,2,gamestate.ammo);
-}
-
-
-/*
-===============
-=
-= GiveAmmo
-=
-===============
-*/
-
-void	GiveAmmo (s16int ammo)
-{
-	if (!gamestate.ammo)				// knife was out
-	{
-		if (!gamestate.attackframe)
-		{
-			gamestate.weapon = gamestate.chosenweapon;
-			DrawWeapon ();
-		}
-	}
-	gamestate.ammo += ammo;
-	if (gamestate.ammo > 99)
-		gamestate.ammo = 99;
-	DrawAmmo ();
-}
-
-//===========================================================================
-
-/*
-==================
-=
-= GiveKey
-=
-==================
-*/
-
-void GiveKey (s16int key)
-{
-	gamestate.keys |= (1<<key);
-	DrawKeys ();
-}
-
-
-
-/*
-=============================================================================
-
-							MOVEMENT
-
-=============================================================================
-*/
-
-
-/*
-===================
-=
-= GetBonus
-=
-===================
-*/
-void GetBonus (statobj_t *check)
-{
-	switch (check->itemnumber)
-	{
-	case	bo_firstaid:
-		if (gamestate.health == 100)
-			return;
-
-		SD_PlaySound (Shealth2);
-		HealSelf (25);
-		break;
-
-	case	bo_key1:
-	case	bo_key2:
-	case	bo_key3:
-	case	bo_key4:
-		GiveKey (check->itemnumber - bo_key1);
-		SD_PlaySound (Sgetkey);
-		break;
-
-	case	bo_cross:
-		SD_PlaySound (Sbonus1);
-		GivePoints (100);
-		gamestate.treasurecount++;
-		break;
-	case	bo_chalice:
-		SD_PlaySound (Sbonus2);
-		GivePoints (500);
-		gamestate.treasurecount++;
-		break;
-	case	bo_bible:
-		SD_PlaySound (Sbonus3);
-		GivePoints (1000);
-		gamestate.treasurecount++;
-		break;
-	case	bo_crown:
-		SD_PlaySound (Sbonus4);
-		GivePoints (5000);
-		gamestate.treasurecount++;
-		break;
-
-	case	bo_clip:
-		if (gamestate.ammo == 99)
-			return;
-
-		SD_PlaySound (Sgetammo);
-		GiveAmmo (8);
-		break;
-	case	bo_clip2:
-		if (gamestate.ammo == 99)
-			return;
-
-		SD_PlaySound (Sgetammo);
-		GiveAmmo (4);
-		break;
-
-#ifdef SPEAR
-	case	bo_25clip:
-		if (gamestate.ammo == 99)
-		  return;
-
-		SD_PlaySound (Sammobox);
-		GiveAmmo (25);
-		break;
-#endif
-
-	case	bo_machinegun:
-		SD_PlaySound (Sgetmg);
-		GiveWeapon (wp_machinegun);
-		break;
-	case	bo_chaingun:
-		SD_PlaySound (Sgetgatling);
-		GiveWeapon (wp_chaingun);
-
-		StatusDrawPic (17,4,Pgat);
-		facecount = 0;
-		gotgatgun = 1;
-		break;
-
-	case	bo_fullheal:
-		SD_PlaySound (S1up);
-		HealSelf (99);
-		GiveAmmo (25);
-		GiveExtraMan ();
-		gamestate.treasurecount++;
-		break;
-
-	case	bo_food:
-		if (gamestate.health == 100)
-			return;
-
-		SD_PlaySound (Shealth1);
-		HealSelf (10);
-		break;
-
-	case	bo_alpo:
-		if (gamestate.health == 100)
-			return;
-
-		SD_PlaySound (Shealth1);
-		HealSelf (4);
-		break;
-
-	case	bo_gibs:
-		if (gamestate.health >10)
-			return;
-
-		SD_PlaySound (Sslurp);
-		HealSelf (1);
-		break;
-
-	case	bo_spear:
-		spearflag = true;
-		spearx = player->x;
-		speary = player->y;
-		spearangle = player->angle;
-		playstate = ex_completed;
-	}
-
-	StartBonusFlash ();
-	check->shapenum = -1;			// remove from list
-}
-
-
-/*
-===================
-=
-= TryMove
-=
-= returns true if move ok
-= debug: use pointers to optimize
-===================
-*/
-
-int TryMove (objtype *ob)
-{
-	s16int			xl,yl,xh,yh,x,y;
-	objtype		*check;
-	s32int		deltax,deltay;
-
-	xl = (ob->x-PLAYERSIZE) >>TILESHIFT;
-	yl = (ob->y-PLAYERSIZE) >>TILESHIFT;
-
-	xh = (ob->x+PLAYERSIZE) >>TILESHIFT;
-	yh = (ob->y+PLAYERSIZE) >>TILESHIFT;
-
-//
-// check for solid walls
-//
-	for (y=yl;y<=yh;y++)
-		for (x=xl;x<=xh;x++)
-		{
-			check = actorat[x][y];
-			if (check && check<objlist)
-				return false;
-		}
-
-//
-// check for actors
-//
-	if (yl>0)
-		yl--;
-	if (yh<MAPSIZE-1)
-		yh++;
-	if (xl>0)
-		xl--;
-	if (xh<MAPSIZE-1)
-		xh++;
-
-	for (y=yl;y<=yh;y++)
-		for (x=xl;x<=xh;x++)
-		{
-			check = actorat[x][y];
-			if (check > objlist
-			&& (check->flags & FL_SHOOTABLE) )
-			{
-				deltax = ob->x - check->x;
-				if (deltax < -MINACTORDIST || deltax > MINACTORDIST)
-					continue;
-				deltay = ob->y - check->y;
-				if (deltay < -MINACTORDIST || deltay > MINACTORDIST)
-					continue;
-
-				return false;
-			}
-		}
-
-	return true;
-}
-
-
-/*
-===================
-=
-= ClipMove
-=
-===================
-*/
-
-void ClipMove (objtype *ob, s32int xmove, s32int ymove)
-{
-	s32int	basex,basey;
-
-	basex = ob->x;
-	basey = ob->y;
-
-	ob->x = basex+xmove;
-	ob->y = basey+ymove;
-	if (TryMove (ob))
-		return;
-
-	if (noclip && ob->x > 2*TILEGLOBAL && ob->y > 2*TILEGLOBAL &&
-	ob->x < (((s32int)(mapwidth-1))<<TILESHIFT)
-	&& ob->y < (((s32int)(mapheight-1))<<TILESHIFT) )
-		return;		// walk through walls
-
-	if (!SD_SoundPlaying())
-		SD_PlaySound (Shitwall);
-
-	ob->x = basex+xmove;
-	ob->y = basey;
-	if (TryMove (ob))
-		return;
-
-	ob->x = basex;
-	ob->y = basey+ymove;
-	if (TryMove (ob))
-		return;
-
-	ob->x = basex;
-	ob->y = basey;
-}
-
-//==========================================================================
-
-/*
-===================
-=
-= VictoryTile
-=
-===================
-*/
-
-void VictoryTile (void)
-{
-#ifndef SPEAR
-	SpawnBJVictory ();
-#endif
-
-	gamestate.victoryflag = true;
-}
-
-
-/*
-===================
-=
-= Thrust
-=
-===================
-*/
-
-void Thrust (s16int angle, s32int speed)
-{
-	s32int xmove,ymove;
-	s32int	slowmax;
-	u16int	offset;
-
-
-	//
-	// ZERO FUNNY COUNTER IF MOVED!
-	//
-	#ifdef SPEAR
-	if (speed)
-		funnyticount = 0;
-	#endif
-
-	thrustspeed += speed;
-//
-// moving bounds speed
-//
-	if (speed >= MINDIST*2)
-		speed = MINDIST*2-1;
-
-	xmove = FixedByFrac(speed,costable[angle]);
-	ymove = -FixedByFrac(speed,sintable[angle]);
-
-	ClipMove(player,xmove,ymove);
-
-	player->tilex = player->x >> TILESHIFT;		// scale to tile values
-	player->tiley = player->y >> TILESHIFT;
-
-	offset = farmapylookup[player->tiley]+player->tilex;
-	player->areanumber = *(mapsegs[0] + offset) -AREATILE;
-
-	if (*(mapsegs[1] + offset) == EXITTILE)
-		VictoryTile ();
-}
-
-
-/*
-=============================================================================
-
-								ACTIONS
-
-=============================================================================
-*/
-
-
-/*
-===============
-=
-= Cmd_Fire
-=
-===============
-*/
-
-void Cmd_Fire (void)
-{
-	buttonheld[bt_attack] = true;
-
-	gamestate.weaponframe = 0;
-
-	player->state = &s_attack;
-
-	gamestate.attackframe = 0;
-	gamestate.attackcount =
-		attackinfo[gamestate.weapon][gamestate.attackframe].tics;
-	gamestate.weaponframe =
-		attackinfo[gamestate.weapon][gamestate.attackframe].frame;
-}
-
-//===========================================================================
-
-/*
-===============
-=
-= Cmd_Use
-=
-===============
-*/
-
-void Cmd_Use (void)
-{
-	objtype 	*check;
-	s16int			checkx,checky,doornum,dir;
-	int		elevatorok;
-
-
-//
-// find which cardinal direction the player is facing
-//
-	if (player->angle < ANGLES/8 || player->angle > 7*ANGLES/8)
-	{
-		checkx = player->tilex + 1;
-		checky = player->tiley;
-		dir = di_east;
-		elevatorok = true;
-	}
-	else if (player->angle < 3*ANGLES/8)
-	{
-		checkx = player->tilex;
-		checky = player->tiley-1;
-		dir = di_north;
-		elevatorok = false;
-	}
-	else if (player->angle < 5*ANGLES/8)
-	{
-		checkx = player->tilex - 1;
-		checky = player->tiley;
-		dir = di_west;
-		elevatorok = true;
-	}
-	else
-	{
-		checkx = player->tilex;
-		checky = player->tiley + 1;
-		dir = di_south;
-		elevatorok = false;
-	}
-
-	doornum = tilemap[checkx][checky];
-	if (*(mapsegs[1]+farmapylookup[checky]+checkx) == PUSHABLETILE)
-	{
-	//
-	// pushable wall
-	//
-
-		PushWall (checkx,checky,dir);
-		return;
-	}
-	if (!buttonheld[bt_use] && doornum == ELEVATORTILE && elevatorok)
-	{
-	//
-	// use elevator
-	//
-		buttonheld[bt_use] = true;
-
-		tilemap[checkx][checky]++;		// flip switch
-		if (*(mapsegs[0]+farmapylookup[player->tiley]+player->tilex) == ALTELEVATORTILE)
-			playstate = ex_secretlevel;
-		else
-			playstate = ex_completed;
-		SD_PlaySound (Slvlend);
-		SD_WaitSoundDone();
-	}
-	else if (!buttonheld[bt_use] && doornum & 0x80)
-	{
-		buttonheld[bt_use] = true;
-		OperateDoor (doornum & ~0x80);
-	}
-	else
-		SD_PlaySound (Snope);
-
-}
-
-/*
-=============================================================================
-
-						   PLAYER CONTROL
-
-=============================================================================
-*/
-
-
-
-/*
-===============
-=
-= SpawnPlayer
-=
-===============
-*/
-
-void SpawnPlayer (s16int tilex, s16int tiley, s16int dir)
-{
-	player->obclass = playerobj;
-	player->active = true;
-	player->tilex = tilex;
-	player->tiley = tiley;
-	player->areanumber =
-		*(mapsegs[0] + farmapylookup[player->tiley]+player->tilex);
-	player->x = ((s32int)tilex<<TILESHIFT)+TILEGLOBAL/2;
-	player->y = ((s32int)tiley<<TILESHIFT)+TILEGLOBAL/2;
-	player->state = &s_player;
-	player->angle = (1-dir)*90;
-	if (player->angle<0)
-		player->angle += ANGLES;
-	player->flags = FL_NEVERMARK;
-	Thrust (0,0);				// set some variables
-
-	InitAreas ();
-}
-
-
-//===========================================================================
-
-/*
-===============
-=
-= T_KnifeAttack
-=
-= Update player hands, and try to do damage when the proper frame is reached
-=
-===============
-*/
-
-void	KnifeAttack (objtype *ob)
-{
-	objtype *check,*closest;
-	s32int	dist;
-
-	SD_PlaySound (Sknife);
-// actually fire
-	dist = 0x7fffffff;
-	closest = NULL;
-	for (check=ob->next ; check ; check=check->next)
-		if ( (check->flags & FL_SHOOTABLE)
-		&& (check->flags & FL_VISABLE)
-		&& abs (check->viewx-centerx) < shootdelta
-		)
-		{
-			if (check->transx < dist)
-			{
-				dist = check->transx;
-				closest = check;
-			}
-		}
-
-	if (!closest || dist> 0x18000l)
-	{
-	// missed
-
-		return;
-	}
-
-// hit something
-	DamageActor (closest,US_RndT() >> 4);
-}
-
-
-
-void	GunAttack (objtype *ob)
-{
-	objtype *check,*closest,*oldclosest;
-	s16int		damage;
-	s16int		dx,dy,dist;
-	s32int	viewdist;
-
-	switch (gamestate.weapon)
-	{
-	case wp_pistol:
-		SD_PlaySound (Spistol);
-		break;
-	case wp_machinegun:
-		SD_PlaySound (Smg);
-		break;
-	case wp_chaingun:
-		SD_PlaySound (Sgatling);
-		break;
-	}
-
-	madenoise = true;
-
-//
-// find potential targets
-//
-	viewdist = 0x7fffffffl;
-	closest = NULL;
-
-	while (1)
-	{
-		oldclosest = closest;
-
-		for (check=ob->next ; check ; check=check->next)
-			if ( (check->flags & FL_SHOOTABLE)
-			&& (check->flags & FL_VISABLE)
-			&& abs (check->viewx-centerx) < shootdelta
-			)
-			{
-				if (check->transx < viewdist)
-				{
-					viewdist = check->transx;
-					closest = check;
-				}
-			}
-
-		if (closest == oldclosest)
-			return;						// no more targets, all missed
-
-	//
-	// trace a line from player to enemey
-	//
-		if (CheckLine(closest))
-			break;
-
-	}
-
-//
-// hit something
-//
-	dx = abs(closest->tilex - player->tilex);
-	dy = abs(closest->tiley - player->tiley);
-	dist = dx>dy ? dx:dy;
-
-	if (dist<2)
-		damage = US_RndT() / 4;
-	else if (dist<4)
-		damage = US_RndT() / 6;
-	else
-	{
-		if ( (US_RndT() / 12) < dist)		// missed
-			return;
-		damage = US_RndT() / 6;
-	}
-
-	DamageActor (closest,damage);
-}
-
-//===========================================================================
-
-/*
-===============
-=
-= VictorySpin
-=
-===============
-*/
-
-void VictorySpin (void)
-{
-	s32int	desty;
-
-	if (player->angle > 270)
-	{
-		player->angle -= tics * 3;
-		if (player->angle < 270)
-			player->angle = 270;
-	}
-	else if (player->angle < 270)
-	{
-		player->angle += tics * 3;
-		if (player->angle > 270)
-			player->angle = 270;
-	}
-
-	desty = (((s32int)player->tiley-5)<<TILESHIFT)-0x3000;
-
-	if (player->y > desty)
-	{
-		player->y -= tics*4096;
-		if (player->y < desty)
-			player->y = desty;
-	}
-}
-
-
-//===========================================================================
-
-/*
-===============
-=
-= T_Attack
-=
-===============
-*/
-
-void	T_Attack (objtype *ob)
-{
-	struct	atkinf	*cur;
-
-	UpdateFace ();
-
-	if (gamestate.victoryflag)		// watching the BJ actor
-	{
-		VictorySpin ();
-		return;
-	}
-
-	if ( buttonstate[bt_use] && !buttonheld[bt_use] )
-		buttonstate[bt_use] = false;
-
-	if ( buttonstate[bt_attack] && !buttonheld[bt_attack])
-		buttonstate[bt_attack] = false;
-
-	ControlMovement (ob);
-	if (gamestate.victoryflag)		// watching the BJ actor
-		return;
-
-	plux = player->x >> UNSIGNEDSHIFT;			// scale to fit in u16int
-	pluy = player->y >> UNSIGNEDSHIFT;
-	player->tilex = player->x >> TILESHIFT;		// scale to tile values
-	player->tiley = player->y >> TILESHIFT;
-
-//
-// change frame and fire
-//
-	gamestate.attackcount -= tics;
-	while (gamestate.attackcount <= 0)
-	{
-		cur = &attackinfo[gamestate.weapon][gamestate.attackframe];
-		switch (cur->attack)
-		{
-		case -1:
-			ob->state = &s_player;
-			if (!gamestate.ammo)
-			{
-				gamestate.weapon = wp_knife;
-				DrawWeapon ();
-			}
-			else
-			{
-				if (gamestate.weapon != gamestate.chosenweapon)
-				{
-					gamestate.weapon = gamestate.chosenweapon;
-					DrawWeapon ();
-				}
-			};
-			gamestate.attackframe = gamestate.weaponframe = 0;
-			return;
-
-		case 4:
-			if (!gamestate.ammo)
-				break;
-			if (buttonstate[bt_attack])
-				gamestate.attackframe -= 2;
-		case 1:
-			if (!gamestate.ammo)
-			{	// can only happen with chain gun
-				gamestate.attackframe++;
-				break;
-			}
-			GunAttack (ob);
-			gamestate.ammo--;
-			DrawAmmo ();
-			break;
-
-		case 2:
-			KnifeAttack (ob);
-			break;
-
-		case 3:
-			if (gamestate.ammo && buttonstate[bt_attack])
-				gamestate.attackframe -= 2;
-			break;
-		}
-
-		gamestate.attackcount += cur->tics;
-		gamestate.attackframe++;
-		gamestate.weaponframe =
-			attackinfo[gamestate.weapon][gamestate.attackframe].frame;
-	}
-
-}
-
-
-
-//===========================================================================
-
-/*
-===============
-=
-= T_Player
-=
-===============
-*/
-
-void	T_Player (objtype *ob)
-{
-	if (gamestate.victoryflag)		// watching the BJ actor
-	{
-		VictorySpin ();
-		return;
-	}
-
-	UpdateFace ();
-	CheckWeaponChange ();
-
-	if ( buttonstate[bt_use] )
-		Cmd_Use ();
-
-	if ( buttonstate[bt_attack] && !buttonheld[bt_attack])
-		Cmd_Fire ();
-
-	ControlMovement (ob);
-	if (gamestate.victoryflag)		// watching the BJ actor
-		return;
-
-
-	plux = player->x >> UNSIGNEDSHIFT;			// scale to fit in u16int
-	pluy = player->y >> UNSIGNEDSHIFT;
-	player->tilex = player->x >> TILESHIFT;		// scale to tile values
-	player->tiley = player->y >> TILESHIFT;
-}
-
-
--- a/ca.c
+++ /dev/null
@@ -1,295 +1,0 @@
-s16int			mapon;
-
-void		_seg	*grsegs[NUMCHUNKS];
-
-u8int		far	grneeded[NUMCHUNKS];
-u8int		ca_levelbit,ca_levelnum;
-
-s32int		_seg *grstarts;	// array of offsets in egagraph, -1 for sparse
-s16int			grhandle;		// handle to EGAGRAPH
-s32int		chunkcomplen,chunkexplen;
-
-s32int GRFILEPOS(s16int c)
-{
-	s32int value;
-	s16int	offset;
-
-	offset = c*3;
-
-	value = *(s32int far *)(((u8int far *)grstarts)+offset);
-
-	value &= 0x00ffffffl;
-
-	if (value == 0xffffffl)
-		value = -1;
-
-	return value;
-};
-
-/*
-======================
-=
-= CAL_HuffExpand
-=
-= Length is the length of the EXPANDED data
-= If screenhack, the data is decompressed in four planes directly
-= to the screen
-=
-======================
-*/
-
-void CAL_HuffExpand (u8int huge *source, u8int huge *dest,
-  s32int length,huffnode *hufftable, int screenhack)
-{
-  u16int sourceseg,sourceoff,destseg,destoff,endoff;
-  huffnode *headptr;
-  u8int		mapmask;
-
-  headptr = hufftable+254;	// head node is allways node 254
-
-  if (screenhack)
-  {
-	mapmask = 1;
-asm	mov	dx,SC_INDEX
-asm	mov	ax,SC_MAPMASK + 256
-asm	out	dx,ax
-	length >>= 2;
-  }
-
-	// setup
-expandshort:
-	{
-		// loop
-	}
-
-asm	test	[screenhack],1
-asm	jz	notscreen
-asm	shl	[mapmask],1
-asm	mov	ah,[mapmask]
-asm	cmp	ah,16
-asm	je	notscreen			// all four planes done
-asm	mov	dx,SC_INDEX
-asm	mov	al,SC_MAPMASK
-asm	out	dx,ax
-asm	mov	di,[destoff]
-asm	mov	ax,[endoff]
-asm	jmp	expandshort
-
-notscreen:;
-}
-
-void CA_Startup (void)
-{
-	ca_levelbit = 1;
-	ca_levelnum = 0;
-}
-
-/*
-======================
-=
-= CA_CacheScreen
-=
-= Decompresses a chunk from disk straight onto the screen
-=
-======================
-*/
-
-void CA_CacheScreen (s16int chunk)
-{
-	s32int	pos,compressed,expanded;
-	uchar *bigbufferseg;
-	u8int	far *source;
-	s16int		next;
-
-//
-// load the chunk into a buffer
-//
-	pos = GRFILEPOS(chunk);
-	next = chunk +1;
-	while (GRFILEPOS(next) == -1)		// skip past any sparse tiles
-		next++;
-	compressed = GRFILEPOS(next)-pos;
-
-	lseek(grhandle,pos,SEEK_SET);
-
-	MM_GetPtr(&bigbufferseg,compressed);
-	MM_SetLock (&bigbufferseg,true);
-	CA_FarRead(grhandle,bigbufferseg,compressed);
-	source = bigbufferseg;
-
-	expanded = *(s32int far *)source;
-	source += 4;			// skip over length
-
-//
-// allocate final space, decompress it, and free bigbuffer
-// Sprites need to have shifts made and various other junk
-//
-	CAL_HuffExpand (source,MK_FP(SCREENSEG,bufferofs),expanded,grhuffman,true);
-	VW_MarkUpdateBlock (0,0,319,199);
-	MM_FreePtr(&bigbufferseg);
-}
-
-/*
-======================
-=
-= CA_UpLevel
-=
-= Goes up a bit level in the needed lists and clears it out.
-= Everything is made purgable
-=
-======================
-*/
-
-void CA_UpLevel (void)
-{
-	s16int	i;
-
-	if (ca_levelnum==7)
-		Quit ("CA_UpLevel: Up past level 7!");
-
-	for (i=0;i<NUMCHUNKS;i++)
-		if (grsegs[i])
-			MM_SetPurge (&(uchar *)grsegs[i],3);
-	ca_levelbit<<=1;
-	ca_levelnum++;
-}
-
-//===========================================================================
-
-/*
-======================
-=
-= CA_DownLevel
-=
-= Goes down a bit level in the needed lists and recaches
-= everything from the lower level
-=
-======================
-*/
-
-void CA_DownLevel (void)
-{
-	if (!ca_levelnum)
-		Quit ("CA_DownLevel: Down past level 0!");
-	ca_levelbit>>=1;
-	ca_levelnum--;
-	CA_CacheMarks();
-}
-
-/*
-======================
-=
-= CA_CacheMarks
-=
-======================
-*/
-#define MAXEMPTYREAD	1024
-
-void CA_CacheMarks (void)
-{
-	s16int 	i,next,numcache;
-	s32int	pos,endpos,nextpos,nextendpos,compressed;
-	s32int	bufferstart,bufferend;	// file position of general buffer
-	u8int	far *source;
-	uchar *bigbufferseg;
-
-	numcache = 0;
-//
-// go through and make everything not needed purgable
-//
-	for (i=0;i<NUMCHUNKS;i++)
-		if (grneeded[i]&ca_levelbit)
-		{
-			if (grsegs[i])					// its allready in memory, make
-				MM_SetPurge(&grsegs[i],0);	// sure it stays there!
-			else
-				numcache++;
-		}
-		else
-		{
-			if (grsegs[i])					// not needed, so make it purgeable
-				MM_SetPurge(&grsegs[i],3);
-		}
-
-	if (!numcache)			// nothing to cache!
-		return;
-
-
-//
-// go through and load in anything still needed
-//
-	bufferstart = bufferend = 0;		// nothing good in buffer now
-
-	for (i=0;i<NUMCHUNKS;i++)
-		if ( (grneeded[i]&ca_levelbit) && !grsegs[i])
-		{
-			pos = GRFILEPOS(i);
-			if (pos<0)
-				continue;
-
-			next = i +1;
-			while (GRFILEPOS(next) == -1)		// skip past any sparse tiles
-				next++;
-
-			compressed = GRFILEPOS(next)-pos;
-			endpos = pos+compressed;
-
-			if (compressed<=BUFFERSIZE)
-			{
-				if (bufferstart<=pos
-				&& bufferend>= endpos)
-				{
-				// data is allready in buffer
-					source = (u8int _seg *)bufferseg+(pos-bufferstart);
-				}
-				else
-				{
-				// load buffer with a new block from disk
-				// try to get as many of the needed blocks in as possible
-					while ( next < NUMCHUNKS )
-					{
-						while (next < NUMCHUNKS &&
-						!(grneeded[next]&ca_levelbit && !grsegs[next]))
-							next++;
-						if (next == NUMCHUNKS)
-							continue;
-
-						nextpos = GRFILEPOS(next);
-						while (GRFILEPOS(++next) == -1)	// skip past any sparse tiles
-							;
-						nextendpos = GRFILEPOS(next);
-						if (nextpos - endpos <= MAXEMPTYREAD
-						&& nextendpos-pos <= BUFFERSIZE)
-							endpos = nextendpos;
-						else
-							next = NUMCHUNKS;			// read pos to posend
-					}
-
-					lseek(grhandle,pos,SEEK_SET);
-					CA_FarRead(grhandle,bufferseg,endpos-pos);
-					bufferstart = pos;
-					bufferend = endpos;
-					source = bufferseg;
-				}
-			}
-			else
-			{
-			// big chunk, allocate temporary buffer
-				MM_GetPtr(&bigbufferseg,compressed);
-				if (mmerror)
-					return;
-				MM_SetLock (&bigbufferseg,true);
-				lseek(grhandle,pos,SEEK_SET);
-				CA_FarRead(grhandle,bigbufferseg,compressed);
-				source = bigbufferseg;
-			}
-
-			CAL_ExpandGrChunk (i,source);
-			if (mmerror)
-				return;
-
-			if (compressed>BUFFERSIZE)
-				MM_FreePtr(&bigbufferseg);
-
-		}
-}
--- a/ca.h
+++ /dev/null
@@ -1,13 +1,0 @@
-extern	s16int			mapon;
-extern	void		_seg	*grsegs[NUMCHUNKS];
-extern	u8int		far	grneeded[NUMCHUNKS];
-extern	u8int		ca_levelbit,ca_levelnum;
-extern	char		*titleptr[8];
-
-void CA_Startup (void);
-void CA_UpLevel (void);
-void CA_DownLevel (void);
-void CA_ClearMarks (void);
-void CA_ClearAllMarks (void);
-void CA_CacheMarks (void);
-void CA_CacheScreen (s16int chunk);
--- a/dat.h
+++ b/dat.h
@@ -1,5 +1,18 @@
 typedef short s16int;
 typedef int s32int;
+typedef struct Col Col;
+typedef struct Dat Dat;
+typedef struct Pic Pic;
+typedef struct Fnt Fnt;
+typedef struct Sfx Sfx;
+typedef struct Al Al;
+typedef struct View View;
+typedef struct State State;
+typedef struct Obj Obj;
+typedef struct Door Door;
+typedef struct Static Static;
+typedef struct Tile Tile;
+typedef struct Game Game;
 
 enum{
 	WL6,
@@ -10,35 +23,46 @@
 extern int ver;
 extern char *ext;
 extern int grabon;
+extern int demexit;
 enum{
+	Kfire,
+	Kstrafe,
+	Krun,
+	Kopen,
+	Kknife,
+	Kpistol,
+	Kmg,
+	Kgatling,
 	K↑,
 	K↓,
 	K←,
 	K→,
-	Krun,
-	Kfire,
-	Kopen,
-	Kstrafe,
 	Kmenu,
 	Ke
 };
-extern int cson, kbon, mson;
+extern int msense;
+extern int kbon, mson;
+extern int kb, mΔx, mΔy, mΔb;
 extern int sfxon, muson, pcmon;
+extern int sfxlck;
 extern Rune keys[];
 extern void (*step)(void);
+extern int Δtc;
+extern int nosleep;
+extern int mtc;
 
 enum{
 	Vw = 320,
 	Vh = 200,
+	Vhud = Vh - 40,
 	Va = Vw * Vh,
 	Vbp = 24/8,
 	Vt = Va * Vbp,
 	Tb = 70
 };
-extern uchar *px, pxb[];
+extern uchar *px, pxb[], fzb[];
 extern int npx, scale;
 
-typedef struct Col Col;
 enum{
 	C0,
 	Cred,
@@ -54,20 +78,12 @@
 	int b;
 };
 
-typedef struct Dat Dat;
-typedef struct Pic Pic;
-typedef struct Fnt Fnt;
-typedef struct Sfx Sfx;
-typedef struct Al Al;
-
 struct Dat{
-	u16int sz;
 	uchar *p;
 	uchar *e;
 };
 extern Dat *wals, *sprs, *imfs;
 extern uchar **exts, **dems, **epis;
-extern uchar **maps, *map;
 
 struct Pic{
 	int x;
@@ -104,9 +120,9 @@
 	Sdrawgun2,
 	Sdrawgun1,
 	Snoway,
-	Sthrow = Snoway+2,
-	Sdeath,
-	Sdogdeath,
+	Srocket = Snoway+2,
+	Sdie,
+	Sdogdie,
 	Sgatling,
 	Sgetkey,
 	Sopendoor = Sgetkey+6,
@@ -131,7 +147,7 @@
 	Sgetgatling,
 	Sesc,
 	Slvlend,
-	Sdogbark,
+	Sdog,
 	Sendb1,
 	Sendb2,
 	S1up,
@@ -139,28 +155,28 @@
 	Spushwall,
 	Snobonus,
 	S100,
-	Shansdeath = S100+2,
+	Shansdie = S100+2,
 	Sss,
-	Smutdeath,
-	Shitlerdeath,
+	Smutdie,
+	Shitlerdie,
 	Seva,
 	Shans,
-	Sssdeath,
-	Smechadeath,
+	Sssdie,
+	Smechdie,
 	Sgdfire,
 	Shansfire,
 	Sssfire,
 	Sslurp,
 	Sfake,
-	Sschbdeath,
+	Sschbdie,
 	Sschb,
 	Shitler,
-	Soffc,
-	Soffcdeath,
+	Sofc,
+	Sofcdie,
 	Sdogfire,
 	Sflame,
 	Smechwalk,
-	Stransdeath,
+	Stransdie,
 	Syeah,
 	Sscream4,
 	Sscream5,
@@ -168,29 +184,29 @@
 	Sscream7,
 	Sscream8,
 	Sscream9,
-	Sottodeath,
+	Sottodie,
 	Sotto,
 	Sfett,
 	Sgretel,
-	Sgreteldeath,
-	Sfettdeath,
+	Sgreteldie,
+	Sfettdie,
 	Smissile,
 	Smissilehit,
 	Send,
 
-	Sghostdeath = Sfake,
+	Sghostdie = Sfake,
 	Sammobox = Sschb,
 	Sangel = Shitler,
-	Sangelfire = Sflame,
+	Sspark = Sflame,
 	Strans = Smechwalk,
 	Swilh = Syeah,
-	Swilhdeath = Shansdeath,
-	Suberdeath = Shitlerdeath,
-	Sknight = Smechadeath,
-	Sknightdeath = Seva,
-	Sangeldeath = Shans,
-	Sknightmissile = Sschbdeath,
-	Spear = Sottodeath,
+	Swilhdie = Shansdie,
+	Suberdie = Shitlerdie,
+	Sknight = Smechdie,
+	Sknightdie = Seva,
+	Sangeldie = Shans,
+	Sknightmissile = Sschbdie,
+	Sspear = Sottodie,
 	Sangeltired = Sotto,
 	Ssend = Sfett,
 
@@ -227,7 +243,6 @@
 	Pcolon,
 	P0,
 	Ppercent,
-	Pa,
 	Pexcl,
 	Papo,
 	Pguy2,
@@ -267,5 +282,968 @@
 	Eerror,
 	Etitpal,
 	Eend1,
-	Eid = 12
+	Eid = 12,
+
+	SPdemo = 0,
+	SPcam,
+	SPgd = 50,
+	SPgdwalk1 = SPgd + 8,
+	SPgdwalk2 = SPgdwalk1 + 8,
+	SPgdwalk3 = SPgdwalk2 + 8,
+	SPgdwalk4 = SPgdwalk3 + 8,
+	SPgdpain1 = SPgdwalk4 + 8,
+	SPgddie1,
+	SPgddie2,
+	SPgddie3,
+	SPgdpain2,
+	SPgddead,
+	SPgdfire1,
+	SPgdfire2,
+	SPgdfire3,
+	SPdogwalk1,
+	SPdogwalk2 = SPdogwalk1 + 8,
+	SPdogwalk3 = SPdogwalk2 + 8,
+	SPdogwalk4 = SPdogwalk3 + 8,
+	SPdogdie1 = SPdogwalk4 + 8,
+	SPdogdie2,
+	SPdogdie3,
+	SPdogdead,
+	SPdogfire1,
+	SPdogfire2,
+	SPdogfire3,
+	SPss,
+	SPsswalk1 = SPss + 8,
+	SPsswalk2 = SPsswalk1 + 8,
+	SPsswalk3 = SPsswalk2 + 8,
+	SPsswalk4 = SPsswalk3 + 8,
+	SPsspain1 = SPsswalk4 + 8,
+	SPssdie1,
+	SPssdie2,
+	SPssdie3,
+	SPsspain2,
+	SPssdead,
+	SPssfire1,
+	SPssfire2,
+	SPssfire3,
+	SPmut,
+	SPmutwalk1 = SPmut + 8,
+	SPmutwalk2 = SPmutwalk1 + 8,
+	SPmutwalk3 = SPmutwalk2 + 8,
+	SPmutwalk4 = SPmutwalk3 + 8,
+	SPmutpain1 = SPmutwalk4 + 8,
+	SPmutdie1,
+	SPmutdie2,
+	SPmutdie3,
+	SPmutpain2,
+	SPmutdie4,
+	SPmutdead,
+	SPmutfire1,
+	SPmutfire2,
+	SPmutfire3,
+	SPmutfire4,
+	SPofc,
+	SPofcwalk1 = SPofc + 8,
+	SPofcwalk2 = SPofcwalk1 + 8,
+	SPofcwalk3 = SPofcwalk2 + 8,
+	SPofcwalk4 = SPofcwalk3 + 8,
+	SPofcpain1 = SPofcwalk4 + 8,
+	SPofcdie1,
+	SPofcdie2,
+	SPofcdie3,
+	SPofcpain2,
+	SPofcdie4,
+	SPofcdead,
+	SPofcfire1,
+	SPofcfire2,
+	SPofcfire3,
+	SPgh1walk1,
+	SPgh1walk2,
+	SPgh2walk1,
+	SPgh2walk2,
+	SPgh3walk1,
+	SPgh3walk2,
+	SPgh4walk1,
+	SPgh4walk2,
+	SPhanswalk1,
+	SPhanswalk2,
+	SPhanswalk3,
+	SPhanswalk4,
+	SPhansfire1,
+	SPhansfire2,
+	SPhansfire3,
+	SPhansdead,
+	SPhansdie1,
+	SPhansdie2,
+	SPhansdie3,
+	SPschbwalk1,
+	SPschbwalk2,
+	SPschbwalk3,
+	SPschbwalk4,
+	SPschbfire1,
+	SPschbfire2,
+	SPschbdie1,
+	SPschbdie2,
+	SPschbdie3,
+	SPschbdead,
+	SPneedle1,
+	SPneedle2,
+	SPneedle3,
+	SPneedle4,
+	SPfakewalk1,
+	SPfakewalk2,
+	SPfakewalk3,
+	SPfakewalk4,
+	SPfakefire,
+	SPflame1,
+	SPflame2,
+	SPfakedie1,
+	SPfakedie2,
+	SPfakedie3,
+	SPfakedie4,
+	SPfakedie5,
+	SPfakedead,
+	SPmechwalk1,
+	SPmechwalk2,
+	SPmechwalk3,
+	SPmechwalk4,
+	SPmechfire1,
+	SPmechfire2,
+	SPmechfire3,
+	SPmechdead,
+	SPmechdie1,
+	SPmechdie2,
+	SPmechdie3,
+	SPhitlerwalk1,
+	SPhitlerwalk2,
+	SPhitlerwalk3,
+	SPhitlerwalk4,
+	SPhitlerfire1,
+	SPhitlerfire2,
+	SPhitlerfire3,
+	SPhitlerdead,
+	SPhitlerdie1,
+	SPhitlerdie2,
+	SPhitlerdie3,
+	SPhitlerdie4,
+	SPhitlerdie5,
+	SPhitlerdie6,
+	SPhitlerdie7,
+	SPottowalk1,
+	SPottowalk2,
+	SPottowalk3,
+	SPottowalk4,
+	SPottofire1,
+	SPottofire2,
+	SPottodie1,
+	SPottodie2,
+	SPottodie3,
+	SPottodead,
+	SPmissile1,
+	SPmsmoke1 = SPmissile1 + 8,
+	SPmsmoke2,
+	SPmsmoke3,
+	SPmsmoke4,
+	SPmboom1,
+	SPmboom2,
+	SPmboom3,
+	SPgretelwalk1,
+	SPgretelwalk2,
+	SPgretelwalk3,
+	SPgretelwalk4,
+	SPgretelfire1,
+	SPgretelfire2,
+	SPgretelfire3,
+	SPgreteldead,
+	SPgreteldie1,
+	SPgreteldie2,
+	SPgreteldie3,
+	SPfettwalk1,
+	SPfettwalk2,
+	SPfettwalk3,
+	SPfettwalk4,
+	SPfettfire1,
+	SPfettfire2,
+	SPfettfire3,
+	SPfettfire4,
+	SPfettdie1,
+	SPfettdie2,
+	SPfettdie3,
+	SPfettdead,
+	SPbjwalk1,
+	SPbjwalk2,
+	SPbjwalk3,
+	SPbjwalk4,
+	SPbjjump1,
+	SPbjjump2,
+	SPbjjump3,
+	SPbjjump4,
+	SPknife,
+	SPpistol = SPknife + 5,
+	SPmg = SPpistol + 5,
+	SPgatling = SPmg + 5,
+	SProcket1 = SPofcfire3 + 20,
+	SPrsmoke1 = SProcket1 + 8,
+	SPrsmoke2,
+	SPrsmoke3,
+	SPrsmoke4,
+	SPrboom1,
+	SPrboom2,
+	SPrboom3,
+	SPspark1,
+	SPspark2,
+	SPspark3,
+	SPspark4,
+	SPtranswalk1,
+	SPtranswalk2,
+	SPtranswalk3,
+	SPtranswalk4,
+	SPtransfire1,
+	SPtransfire2,
+	SPtransfire3,
+	SPtransdead,
+	SPtransdie1,
+	SPtransdie2,
+	SPtransdie3,
+	SPwilhwalk1,
+	SPwilhwalk2,
+	SPwilhwalk3,
+	SPwilhwalk4,
+	SPwilhfire1,
+	SPwilhfire2,
+	SPwilhfire3,
+	SPwilhfire4,
+	SPwilhdie1,
+	SPwilhdie2,
+	SPwilhdie3,
+	SPwilhdead,
+	SPuberwalk1,
+	SPuberwalk2,
+	SPuberwalk3,
+	SPuberwalk4,
+	SPuberfire1,
+	SPuberfire2,
+	SPuberfire3,
+	SPuberfire4,
+	SPuberdie1,
+	SPuberdie2,
+	SPuberdie3,
+	SPuberdie4,
+	SPuberdead,
+	SPknightwalk1,
+	SPknightwalk2,
+	SPknightwalk3,
+	SPknightwalk4,
+	SPknightfire1,
+	SPknightfire2,
+	SPknightfire3,
+	SPknightfire4,
+	SPknightdie1,
+	SPknightdie2,
+	SPknightdie3,
+	SPknightdie4,
+	SPknightdie5,
+	SPknightdie6,
+	SPknightdead,
+	SPspectrewalk1,
+	SPspectrewalk2,
+	SPspectrewalk3,
+	SPspectrewalk4,
+	SPspectreF1,
+	SPspectreF2,
+	SPspectreF3,
+	SPspectreF4,
+	SPangelwalk1,
+	SPangelwalk2,
+	SPangelwalk3,
+	SPangelwalk4,
+	SPangelfire1,
+	SPangelfire2,
+	SPangeltired1,
+	SPangeltired2,
+	SPangeldie1,
+	SPangeldie2,
+	SPangeldie3,
+	SPangeldie4,
+	SPangeldie5,
+	SPangeldie6,
+	SPangeldie7,
+	SPangeldead
 };
+
+enum{
+	Dtlshift = 16,
+	Dtlglobal = 1 << Dtlshift,
+	Dmin = 0x5800,
+	Dplr = Dmin,
+	Domin = 0x10000
+};
+#define	Fpi	3.14159265358979323846	/* bcpp 1.3 */
+extern s32int sint[], *cost;
+
+struct View{
+	int size;
+	int dx;
+	int dy;
+	int ofs;
+	int x;
+	int y;
+	int tx;
+	int ty;
+	int θ;
+	int cos;
+	int sin;
+	int mid;
+	int Δhit;
+};
+extern View vw;
+
+enum{
+	Oplr = 1,
+	Oblaz,
+	Ogd,
+	Oss,
+	Oofc,
+	Omut,
+	Odog,
+	Ohans,
+	Oschb,
+	Ogretel,
+	Ootto,
+	Ofett,
+	Ofake,
+	Omech,
+	Ohitler,
+	Oghost,
+	Otrans,
+	Owilh,
+	Ouber,
+	Oknight,
+	Ospectre,
+	Oangel,
+	Orocket,
+	Omissile,
+	Oflame,
+	Oneedle,
+	Ospark,
+	Oinert,
+
+	OFshootable = 1<<0,
+	OFbonus = 1<<1,
+	OFnevermark = 1<<2,
+	OFvis = 1<<3,
+	OFattack = 1<<4,
+	OFflip = 1<<5,
+	OFambush = 1<<6,
+	OFnomark = 1<<7,
+
+	Rnil = 0,
+	Rblock,
+	Rgibs,
+	Ralpo,
+	Rstim,
+	Rkey1,
+	Rkey2,
+	Rkey3,
+	Rkey4,
+	Rcross,
+	Rchalice,
+	Rbible,
+	Rcrown,
+	Rclip1,
+	Rclip2,
+	Rmg,
+	Rchaingun,
+	Rfood,
+	R1up,
+	Rammobox,
+	Rspear,
+
+	GSplr = 0,
+	GSplrcam,
+	GSblaz1,
+	GSblaz2,
+	GSblaz3,
+	GSblaz4,
+	GSblaz5,
+	GSblaz6,
+	GSjump1,
+	GSjump2,
+	GSjump3,
+	GSjump4,
+	GSgd,
+	GSgdwalk1,
+	GSgdwalk2,
+	GSgdwalk3,
+	GSgdwalk4,
+	GSgdwalk5,
+	GSgdwalk6,
+	GSgdpain1,
+	GSgdpain2,
+	GSgdchase1,
+	GSgdchase2,
+	GSgdchase3,
+	GSgdchase4,
+	GSgdchase5,
+	GSgdchase6,
+	GSgdfire1,
+	GSgdfire2,
+	GSgdfire3,
+	GSgddie1,
+	GSgddie2,
+	GSgddie3,
+	GSgddie4,
+	GSss,
+	GSsswalk1,
+	GSsswalk2,
+	GSsswalk3,
+	GSsswalk4,
+	GSsswalk5,
+	GSsswalk6,
+	GSsspain1,
+	GSsspain2,
+	GSsschase1,
+	GSsschase2,
+	GSsschase3,
+	GSsschase4,
+	GSsschase5,
+	GSsschase6,
+	GSssfire1,
+	GSssfire2,
+	GSssfire3,
+	GSssfire4,
+	GSssfire5,
+	GSssfire6,
+	GSssfire7,
+	GSssfire8,
+	GSssfire9,
+	GSssdie1,
+	GSssdie2,
+	GSssdie3,
+	GSssdie4,
+	GSofc,
+	GSofcwalk1,
+	GSofcwalk2,
+	GSofcwalk3,
+	GSofcwalk4,
+	GSofcwalk5,
+	GSofcwalk6,
+	GSofcpain1,
+	GSofcpain2,
+	GSofcchase1,
+	GSofcchase2,
+	GSofcchase3,
+	GSofcchase4,
+	GSofcchase5,
+	GSofcchase6,
+	GSofcfire1,
+	GSofcfire2,
+	GSofcfire3,
+	GSofcdie1,
+	GSofcdie2,
+	GSofcdie3,
+	GSofcdie4,
+	GSofcdie5,
+	GSmut,
+	GSmutwalk1,
+	GSmutwalk2,
+	GSmutwalk3,
+	GSmutwalk4,
+	GSmutwalk5,
+	GSmutwalk6,
+	GSmutpain1,
+	GSmutpain2,
+	GSmutchase1,
+	GSmutchase2,
+	GSmutchase3,
+	GSmutchase4,
+	GSmutchase5,
+	GSmutchase6,
+	GSmutfire1,
+	GSmutfire2,
+	GSmutfire3,
+	GSmutfire4,
+	GSmutdie1,
+	GSmutdie2,
+	GSmutdie3,
+	GSmutdie4,
+	GSmutdie5,
+	GSdogwalk1,
+	GSdogwalk2,
+	GSdogwalk3,
+	GSdogwalk4,
+	GSdogwalk5,
+	GSdogwalk6,
+	GSdogchase1,
+	GSdogchase2,
+	GSdogchase3,
+	GSdogchase4,
+	GSdogchase5,
+	GSdogchase6,
+	GSdogfire1,
+	GSdogfire2,
+	GSdogfire3,
+	GSdogfire4,
+	GSdogfire5,
+	GSdogdie1,
+	GSdogdie2,
+	GSdogdie3,
+	GSdogdie4,
+	GShans,
+	GShanschase1,
+	GShanschase2,
+	GShanschase3,
+	GShanschase4,
+	GShanschase5,
+	GShanschase6,
+	GShansfire1,
+	GShansfire2,
+	GShansfire3,
+	GShansfire4,
+	GShansfire5,
+	GShansfire6,
+	GShansfire7,
+	GShansfire8,
+	GShansdie1,
+	GShansdie2,
+	GShansdie3,
+	GShansdie4,
+	GSschb,
+	GSschbchase1,
+	GSschbchase2,
+	GSschbchase3,
+	GSschbchase4,
+	GSschbchase5,
+	GSschbchase6,
+	GSschbfire1,
+	GSschbfire2,
+	GSschbcam,
+	GSschbdie1,
+	GSschbdie2,
+	GSschbdie3,
+	GSschbdie4,
+	GSschbdie5,
+	GSschbdie6,
+	GSgretel,
+	GSgretelchase1,
+	GSgretelchase2,
+	GSgretelchase3,
+	GSgretelchase4,
+	GSgretelchase5,
+	GSgretelchase6,
+	GSgretelfire1,
+	GSgretelfire2,
+	GSgretelfire3,
+	GSgretelfire4,
+	GSgretelfire5,
+	GSgretelfire6,
+	GSgretelfire7,
+	GSgretelfire8,
+	GSgreteldie1,
+	GSgreteldie2,
+	GSgreteldie3,
+	GSgreteldie4,
+	GSotto,
+	GSottochase1,
+	GSottochase2,
+	GSottochase3,
+	GSottochase4,
+	GSottochase5,
+	GSottochase6,
+	GSottofire1,
+	GSottofire2,
+	GSottocam,
+	GSottodie1,
+	GSottodie2,
+	GSottodie3,
+	GSottodie4,
+	GSottodie5,
+	GSottodie6,
+	GSfett,
+	GSfettchase1,
+	GSfettchase2,
+	GSfettchase3,
+	GSfettchase4,
+	GSfettchase5,
+	GSfettchase6,
+	GSfettfire1,
+	GSfettfire2,
+	GSfettfire3,
+	GSfettfire4,
+	GSfettfire5,
+	GSfettfire6,
+	GSfettcam,
+	GSfettdie1,
+	GSfettdie2,
+	GSfettdie3,
+	GSfettdie4,
+	GSfettdie5,
+	GSfettdie6,
+	GSfake,
+	GSfakechase1,
+	GSfakechase2,
+	GSfakechase3,
+	GSfakechase4,
+	GSfakechase5,
+	GSfakechase6,
+	GSfakefire1,
+	GSfakefire2,
+	GSfakefire3,
+	GSfakefire4,
+	GSfakefire5,
+	GSfakefire6,
+	GSfakefire7,
+	GSfakefire8,
+	GSfakefire9,
+	GSfakedie1,
+	GSfakedie2,
+	GSfakedie3,
+	GSfakedie4,
+	GSfakedie5,
+	GSfakedie6,
+	GSmech,
+	GSmechchase1,
+	GSmechchase2,
+	GSmechchase3,
+	GSmechchase4,
+	GSmechchase5,
+	GSmechchase6,
+	GSmechfire1,
+	GSmechfire2,
+	GSmechfire3,
+	GSmechfire4,
+	GSmechfire5,
+	GSmechfire6,
+	GSmechdie1,
+	GSmechdie2,
+	GSmechdie3,
+	GSmechdie4,
+	GShitlerchase1,
+	GShitlerchase2,
+	GShitlerchase3,
+	GShitlerchase4,
+	GShitlerchase5,
+	GShitlerchase6,
+	GShitlerfire1,
+	GShitlerfire2,
+	GShitlerfire3,
+	GShitlerfire4,
+	GShitlerfire5,
+	GShitlerfire6,
+	GShitlercam,
+	GShitlerdie1,
+	GShitlerdie2,
+	GShitlerdie3,
+	GShitlerdie4,
+	GShitlerdie5,
+	GShitlerdie6,
+	GShitlerdie7,
+	GShitlerdie8,
+	GShitlerdie9,
+	GShitlerdie10,
+	GSgh1chase1,
+	GSgh2chase1,
+	GSgh3chase1,
+	GSgh4chase1,
+	GSgh1chase2,
+	GSgh2chase2,
+	GSgh3chase2,
+	GSgh4chase2,
+	GStrans,
+	GStranschase1,
+	GStranschase2,
+	GStranschase3,
+	GStranschase4,
+	GStranschase5,
+	GStranschase6,
+	GStransfire1,
+	GStransfire2,
+	GStransfire3,
+	GStransfire4,
+	GStransfire5,
+	GStransfire6,
+	GStransfire7,
+	GStransfire8,
+	GStransdie1,
+	GStransdie2,
+	GStransdie3,
+	GStransdie4,
+	GStransdie5,
+	GStransdie6,
+	GSwilh,
+	GSwilhchase1,
+	GSwilhchase2,
+	GSwilhchase3,
+	GSwilhchase4,
+	GSwilhchase5,
+	GSwilhchase6,
+	GSwilhfire1,
+	GSwilhfire2,
+	GSwilhfire3,
+	GSwilhfire4,
+	GSwilhfire5,
+	GSwilhfire6,
+	GSwilhdie1,
+	GSwilhdie2,
+	GSwilhdie3,
+	GSwilhdie4,
+	GSwilhdie5,
+	GSwilhdie6,
+	GSuber,
+	GSuberchase1,
+	GSuberchase2,
+	GSuberchase3,
+	GSuberchase4,
+	GSuberchase5,
+	GSuberchase6,
+	GSuberfire1,
+	GSuberfire2,
+	GSuberfire3,
+	GSuberfire4,
+	GSuberfire5,
+	GSuberfire6,
+	GSuberfire7,
+	GSuberdie1,
+	GSuberdie2,
+	GSuberdie3,
+	GSuberdie4,
+	GSuberdie5,
+	GSuberdie6,
+	GSuberdie7,
+	GSknight,
+	GSknightchase1,
+	GSknightchase2,
+	GSknightchase3,
+	GSknightchase4,
+	GSknightchase5,
+	GSknightchase6,
+	GSknightfire1,
+	GSknightfire2,
+	GSknightfire3,
+	GSknightfire4,
+	GSknightfire5,
+	GSknightdie1,
+	GSknightdie2,
+	GSknightdie3,
+	GSknightdie4,
+	GSknightdie5,
+	GSknightdie6,
+	GSknightdie7,
+	GSknightdie8,
+	GSknightdie9,
+	GSspectrewait1,
+	GSspectrewait2,
+	GSspectrewait3,
+	GSspectrewait4,
+	GSspectrewake,
+	GSspectrechase1,
+	GSspectrechase2,
+	GSspectrechase3,
+	GSspectrechase4,
+	GSspectredie1,
+	GSspectredie2,
+	GSspectredie3,
+	GSspectredie4,
+	GSangel,
+	GSangelchase1,
+	GSangelchase2,
+	GSangelchase3,
+	GSangelchase4,
+	GSangelchase5,
+	GSangelchase6,
+	GSangeldie1,
+	GSangeldie2,
+	GSangeldie3,
+	GSangeldie4,
+	GSangeldie5,
+	GSangeldie6,
+	GSangeldie7,
+	GSangeldie8,
+	GSangeldie9,
+	GSangeldie10,
+	GSangelfire1,
+	GSangelfire2,
+	GSangelfire3,
+	GSangeltired1,
+	GSangeltired2,
+	GSangeltired3,
+	GSangeltired4,
+	GSangeltired5,
+	GSangeltired6,
+	GSangeltired7,
+	GSmissile,
+	GSmsmoke1,
+	GSmsmoke2,
+	GSmsmoke3,
+	GSmsmoke4,
+	GSmboom1,
+	GSmboom2,
+	GSmboom3,
+	GSrocket,
+	GSrsmoke1,
+	GSrsmoke2,
+	GSrsmoke3,
+	GSrsmoke4,
+	GSrboom1,
+	GSrboom2,
+	GSrboom3,
+	GSflame1,
+	GSflame2,
+ 	GSneedle1,
+	GSneedle2,
+	GSneedle3,
+	GSneedle4,
+	GSspark1,
+	GSspark2,
+	GSspark3,
+	GSspark4,
+
+	θE = 0,
+	θNE = 45,
+	θN = 90,
+	θNW = 135,
+	θW = 180,
+	θSW = 225,
+	θS = 270,
+	θSE = 315,
+	θnil = -1,
+
+	DRshut = 0,
+	DRopening,
+	DRopen,
+	DRclosing,
+
+	DRunlk = 0,
+	DRlock1,
+	DRlock2,
+	DRlock3,
+	DRlock4,
+	DRup
+};
+struct State{
+	void (*up)(Obj *);
+	void (*act)(Obj *);
+	int dt;
+	Dat *spr;
+	State *n;
+	int rot;
+};
+extern State stt[];
+struct Obj{
+	int on;
+	int type;
+	int f;
+	State *s;
+	int tc;
+	int hp;
+	int v;
+	int θ;
+	int Δr;
+	Tile *tl;
+	int tx;
+	int ty;
+	int x;
+	int y;
+	int vwx;
+	int vwdx;
+	int vwdy;
+	int areaid;
+	int atkdt;
+	int sdt;
+	Obj *n;
+	Obj *p;
+};
+extern Obj *objs, *ofree, *oplr;
+struct Door{
+	Tile *tl;
+	int isvert;	/* also push direction */
+	int lock;
+	int φ;
+	int tc;
+	u16int dopen;
+};
+extern Door doors[], *doore, pusher;
+struct Static{
+	Tile *tl;
+	Dat *spr;
+	int f;
+	int item;
+};
+extern Static stcs[], *stce;
+
+enum{
+	Mapdxy = 64,
+	Mapa = Mapdxy * Mapdxy,
+	MTgoup = 21,
+	MTarrows = 90,
+	MTpush = 98,
+	MTexit = 99,
+	MTambush = 106,
+	MTsetec = 107,
+	MTfloor = MTsetec,
+};
+struct Tile{
+	u16int p0;
+	u16int p1;
+	uchar tl;
+	Obj *o;
+	uchar to;
+	uchar vis;
+};
+extern Tile tiles[Mapa];
+extern uchar plrarea[], conarea[];
+extern int wspr[];
+
+enum{
+	GPextra = 40000,
+
+	GDbaby = 0,
+	GDeasy,
+	GDmed,
+	GDhard,
+
+	WPknife = 0,
+	WPpistol,
+	WPmg,
+	WPgatling,
+
+	EDfizz = 1,
+	EDdem,
+	EDkey,
+	EDdie,
+	EDcam,
+	EDcam2,
+	EDup,
+	EDsetec,
+	EDwon
+};
+struct Game{
+	int hp;
+	int w;
+	int lastw;
+	int bestw;
+	int ammo;
+	int lives;
+	int keys;
+	int pt;
+	int to1up;
+	int wfrm;
+	int facefrm;
+	int map;
+	int difc;
+	int lvltc;
+	int kills;
+	int nkills;
+	int secret;
+	int nsecret;
+	int treasure;
+	int ntreasure;
+	int won;
+	int mut;
+	int end;
+	int demo;
+	int record;
+	int load;
+	int fizz;
+};
+extern Game gm;
+extern int god, noclip, onestep;
--- a/debug.c
+++ b/debug.c
@@ -12,8 +12,8 @@
 =============================================================================
 */
 
-#define VIEWTILEX	(viewwidth/16)
-#define VIEWTILEY	(viewheight/16)
+#define VIEWTILEX	(vw.dx/16)
+#define VIEWTILEY	(vw.dy/16)
 
 /*
 =============================================================================
@@ -194,7 +194,7 @@
 				for (x=0;x<64;x++,postx++,postsource+=64)
 				{
 					wallheight[postx] = 256;
-					FarScalePost ();
+					ScalePost ();
 				}
 				bufferofs -= 32*SCREENWIDTH;
 			}
@@ -204,7 +204,7 @@
 			// draw the sprite
 			//
 				bufferofs += 32*SCREENWIDTH;
-				SimpleScaleShape (160, i-PMSpriteStart, 64);
+				scalespr (160, i-PMSpriteStart, 64);
 				bufferofs -= 32*SCREENWIDTH;
 			}
 			else if (i == ChunksInFile - 1)
@@ -352,7 +352,7 @@
 	{
 		if (tedlevel)
 			Quit (NULL);
-		playstate = ex_completed;
+		gm.φ = ex_completed;
 //		gamestate.mapon++;
 	}
 
@@ -385,7 +385,7 @@
 	if (Keyboard[sc_H])		// H = hurt self
 	{
 		IN_ClearKeysDown ();
-		TakeDamage (16,NULL);
+		hurt (16,NULL);
 	}
 	else if (Keyboard[sc_I])			// I = item cheat
 	{
@@ -392,14 +392,14 @@
 		CenterWindow (12,3);
 		US_PrintCentered ("Free items!");
 		VW_UpdateScreen();
-		GivePoints (100000);
+		givep (100000);
 		HealSelf (99);
-		if (gamestate.bestweapon<wp_chaingun)
-			GiveWeapon (gamestate.bestweapon+1);
+		if (gm.bestw<WPgatling)
+			givew (gm.bestw+1);
 		gamestate.ammo += 50;
 		if (gamestate.ammo > 99)
 			gamestate.ammo = 99;
-		DrawAmmo ();
+		huda ();
 		IN_Ack ();
 		return 1;
 	}
@@ -433,9 +433,9 @@
 		Quit (NULL);
 	else if (Keyboard[sc_S])			// S = slow motion
 	{
-		singlestep^=1;
+		onestep^=1;
 		CenterWindow (18,3);
-		if (singlestep)
+		if (onestep)
 			US_PrintCentered ("Slow motion ON");
 		else
 			US_PrintCentered ("Slow motion OFF");
@@ -484,7 +484,7 @@
 #endif
 			{
 				gamestate.mapon = level-1;
-				playstate = ex_warped;
+				gm.φ = ex_warped;
 			}
 		}
 		return 1;
--- a/def.h
+++ b/def.h
@@ -1,24 +1,3 @@
-#include "ID_HEADS.H"
-#include <MATH.H>
-#include <VALUES.H>
-
-#include "WL_MENU.H"
-
-#include "FOREIGN.H"
-
-#ifdef SPEAR
-#include "F_SPEAR.H"
-#endif
-
-/*
-=============================================================================
-
-							MACROS
-
-=============================================================================
-*/
-
-
 #define COLORBORDER(color)		asm{mov	dx,STATUS_REGISTER_1;in al,dx;\
 	mov dx,ATR_INDEX;mov al,ATR_OVERSCAN;out dx,al;mov al,color;out	dx,al;\
 	mov	al,32;out dx,al};
@@ -25,21 +4,6 @@
 
 #define MAPSPOT(x,y,plane)		(*(mapsegs[plane]+farmapylookup[y]+x))
 
-#define SIGN(x) 	((x)>0?1:-1)
-#define ABS(x) 		((s16int)(x)>0?(x):-(x))
-#define LABS(x) 	((s32int)(x)>0?(x):-(x))
-
-/*
-=============================================================================
-
-						 GLOBAL CONSTANTS
-
-=============================================================================
-*/
-
-#define MAXACTORS		150				// max number of nazis, etc / map
-#define MAXSTATS		400				// max number of lamps, bonus, etc
-#define MAXDOORS		64				// max number of sliding doors
 #define MAXWALLTILES	64				// max number of wall tiles
 
 //
@@ -48,20 +12,12 @@
 
 #define	ICONARROWS		90
 #define PUSHABLETILE	98
-#define EXITTILE		99				// at end of castle
-#define AREATILE		107				// first of NUMAREAS floor tiles
-#define NUMAREAS		37
+#define EXITTILE		99	// at end of castle
 #define ELEVATORTILE	21
-#define AMBUSHTILE		106
 #define	ALTELEVATORTILE	107
 
 #define NUMBERCHARS	9
 
-
-//----------------
-
-#define EXTRAPOINTS		40000
-
 #define PLAYERSPEED		3000
 #define RUNSPEED   		6000
 
@@ -76,19 +32,11 @@
 #define FLASHTICS	4
 
 
-#define PLAYERSIZE		MINDIST			// player radius
-#define MINACTORDIST	0x10000l		// minimum dist from player center
+#define Dplr		Dmin			// player radius
 										// to any actor center
 
 #define NUMLATCHPICS	100
 
-
-#define PI	3.141592657
-
-#define GLOBAL1		(1l<<16)
-#define TILEGLOBAL  GLOBAL1
-#define PIXGLOBAL	(GLOBAL1/64)
-#define TILESHIFT		16l
 #define UNSIGNEDSHIFT	8
 
 #define ANGLES		360					// must be divisable by 4
@@ -103,20 +51,12 @@
 #define VANG270		(VANG90*3)
 #define VANG360		(VANG90*4)
 
-#define MINDIST		(0x5800l)
-
-
 #define	MAXSCALEHEIGHT	256				// largest scale on largest view
 
 #define MAXVIEWWIDTH		320
 
 #define MAPSIZE		64					// maps are 64*64 max
-#define NORTH	0
-#define EAST	1
-#define SOUTH	2
-#define WEST	3
 
-
 #define STATUSLINES		40
 
 #define SCREENSIZE		(SCREENBWIDE*208)
@@ -125,349 +65,14 @@
 #define PAGE3START		(SCREENSIZE*2u)
 #define	FREESTART		(SCREENSIZE*3u)
 
-
 #define PIXRADIUS		512
-
 #define STARTAMMO		8
 
+#define	PORTTILESWIDE		20      // all drawing takes place inside a
+#define UPDATEWIDE			PORTTILESWIDE
+#define UPDATEHIGH			PORTTILESHIGH
+#define SETFONTCOLOR(f,b) fontcolor=f;backcolor=b;
 
-// object flag values
-
-#define FL_SHOOTABLE	1
-#define FL_BONUS		2
-#define FL_NEVERMARK	4
-#define FL_VISABLE		8
-#define FL_ATTACKMODE	16
-#define FL_FIRSTATTACK	32
-#define FL_AMBUSH		64
-#define FL_NONMARK		128
-
-
-//
-// sprite constants
-//
-
-enum	{
-		SPR_DEMO,
-		SPR_DEATHCAM,
-//
-// static sprites
-//
-		SPR_STAT_0,SPR_STAT_1,SPR_STAT_2,SPR_STAT_3,
-		SPR_STAT_4,SPR_STAT_5,SPR_STAT_6,SPR_STAT_7,
-
-		SPR_STAT_8,SPR_STAT_9,SPR_STAT_10,SPR_STAT_11,
-		SPR_STAT_12,SPR_STAT_13,SPR_STAT_14,SPR_STAT_15,
-
-		SPR_STAT_16,SPR_STAT_17,SPR_STAT_18,SPR_STAT_19,
-		SPR_STAT_20,SPR_STAT_21,SPR_STAT_22,SPR_STAT_23,
-
-		SPR_STAT_24,SPR_STAT_25,SPR_STAT_26,SPR_STAT_27,
-		SPR_STAT_28,SPR_STAT_29,SPR_STAT_30,SPR_STAT_31,
-
-		SPR_STAT_32,SPR_STAT_33,SPR_STAT_34,SPR_STAT_35,
-		SPR_STAT_36,SPR_STAT_37,SPR_STAT_38,SPR_STAT_39,
-
-		SPR_STAT_40,SPR_STAT_41,SPR_STAT_42,SPR_STAT_43,
-		SPR_STAT_44,SPR_STAT_45,SPR_STAT_46,SPR_STAT_47,
-
-#ifdef SPEAR
-		SPR_STAT_48,SPR_STAT_49,SPR_STAT_50,SPR_STAT_51,
-#endif
-
-//
-// guard
-//
-		SPR_GRD_S_1,SPR_GRD_S_2,SPR_GRD_S_3,SPR_GRD_S_4,
-		SPR_GRD_S_5,SPR_GRD_S_6,SPR_GRD_S_7,SPR_GRD_S_8,
-
-		SPR_GRD_W1_1,SPR_GRD_W1_2,SPR_GRD_W1_3,SPR_GRD_W1_4,
-		SPR_GRD_W1_5,SPR_GRD_W1_6,SPR_GRD_W1_7,SPR_GRD_W1_8,
-
-		SPR_GRD_W2_1,SPR_GRD_W2_2,SPR_GRD_W2_3,SPR_GRD_W2_4,
-		SPR_GRD_W2_5,SPR_GRD_W2_6,SPR_GRD_W2_7,SPR_GRD_W2_8,
-
-		SPR_GRD_W3_1,SPR_GRD_W3_2,SPR_GRD_W3_3,SPR_GRD_W3_4,
-		SPR_GRD_W3_5,SPR_GRD_W3_6,SPR_GRD_W3_7,SPR_GRD_W3_8,
-
-		SPR_GRD_W4_1,SPR_GRD_W4_2,SPR_GRD_W4_3,SPR_GRD_W4_4,
-		SPR_GRD_W4_5,SPR_GRD_W4_6,SPR_GRD_W4_7,SPR_GRD_W4_8,
-
-		SPR_GRD_PAIN_1,SPR_GRD_DIE_1,SPR_GRD_DIE_2,SPR_GRD_DIE_3,
-		SPR_GRD_PAIN_2,SPR_GRD_DEAD,
-
-		SPR_GRD_SHOOT1,SPR_GRD_SHOOT2,SPR_GRD_SHOOT3,
-
-//
-// dogs
-//
-		SPR_DOG_W1_1,SPR_DOG_W1_2,SPR_DOG_W1_3,SPR_DOG_W1_4,
-		SPR_DOG_W1_5,SPR_DOG_W1_6,SPR_DOG_W1_7,SPR_DOG_W1_8,
-
-		SPR_DOG_W2_1,SPR_DOG_W2_2,SPR_DOG_W2_3,SPR_DOG_W2_4,
-		SPR_DOG_W2_5,SPR_DOG_W2_6,SPR_DOG_W2_7,SPR_DOG_W2_8,
-
-		SPR_DOG_W3_1,SPR_DOG_W3_2,SPR_DOG_W3_3,SPR_DOG_W3_4,
-		SPR_DOG_W3_5,SPR_DOG_W3_6,SPR_DOG_W3_7,SPR_DOG_W3_8,
-
-		SPR_DOG_W4_1,SPR_DOG_W4_2,SPR_DOG_W4_3,SPR_DOG_W4_4,
-		SPR_DOG_W4_5,SPR_DOG_W4_6,SPR_DOG_W4_7,SPR_DOG_W4_8,
-
-		SPR_DOG_DIE_1,SPR_DOG_DIE_2,SPR_DOG_DIE_3,SPR_DOG_DEAD,
-		SPR_DOG_JUMP1,SPR_DOG_JUMP2,SPR_DOG_JUMP3,
-
-
-
-//
-// ss
-//
-		SPR_SS_S_1,SPR_SS_S_2,SPR_SS_S_3,SPR_SS_S_4,
-		SPR_SS_S_5,SPR_SS_S_6,SPR_SS_S_7,SPR_SS_S_8,
-
-		SPR_SS_W1_1,SPR_SS_W1_2,SPR_SS_W1_3,SPR_SS_W1_4,
-		SPR_SS_W1_5,SPR_SS_W1_6,SPR_SS_W1_7,SPR_SS_W1_8,
-
-		SPR_SS_W2_1,SPR_SS_W2_2,SPR_SS_W2_3,SPR_SS_W2_4,
-		SPR_SS_W2_5,SPR_SS_W2_6,SPR_SS_W2_7,SPR_SS_W2_8,
-
-		SPR_SS_W3_1,SPR_SS_W3_2,SPR_SS_W3_3,SPR_SS_W3_4,
-		SPR_SS_W3_5,SPR_SS_W3_6,SPR_SS_W3_7,SPR_SS_W3_8,
-
-		SPR_SS_W4_1,SPR_SS_W4_2,SPR_SS_W4_3,SPR_SS_W4_4,
-		SPR_SS_W4_5,SPR_SS_W4_6,SPR_SS_W4_7,SPR_SS_W4_8,
-
-		SPR_SS_PAIN_1,SPR_SS_DIE_1,SPR_SS_DIE_2,SPR_SS_DIE_3,
-		SPR_SS_PAIN_2,SPR_SS_DEAD,
-
-		SPR_SS_SHOOT1,SPR_SS_SHOOT2,SPR_SS_SHOOT3,
-
-//
-// mutant
-//
-		SPR_MUT_S_1,SPR_MUT_S_2,SPR_MUT_S_3,SPR_MUT_S_4,
-		SPR_MUT_S_5,SPR_MUT_S_6,SPR_MUT_S_7,SPR_MUT_S_8,
-
-		SPR_MUT_W1_1,SPR_MUT_W1_2,SPR_MUT_W1_3,SPR_MUT_W1_4,
-		SPR_MUT_W1_5,SPR_MUT_W1_6,SPR_MUT_W1_7,SPR_MUT_W1_8,
-
-		SPR_MUT_W2_1,SPR_MUT_W2_2,SPR_MUT_W2_3,SPR_MUT_W2_4,
-		SPR_MUT_W2_5,SPR_MUT_W2_6,SPR_MUT_W2_7,SPR_MUT_W2_8,
-
-		SPR_MUT_W3_1,SPR_MUT_W3_2,SPR_MUT_W3_3,SPR_MUT_W3_4,
-		SPR_MUT_W3_5,SPR_MUT_W3_6,SPR_MUT_W3_7,SPR_MUT_W3_8,
-
-		SPR_MUT_W4_1,SPR_MUT_W4_2,SPR_MUT_W4_3,SPR_MUT_W4_4,
-		SPR_MUT_W4_5,SPR_MUT_W4_6,SPR_MUT_W4_7,SPR_MUT_W4_8,
-
-		SPR_MUT_PAIN_1,SPR_MUT_DIE_1,SPR_MUT_DIE_2,SPR_MUT_DIE_3,
-		SPR_MUT_PAIN_2,SPR_MUT_DIE_4,SPR_MUT_DEAD,
-
-		SPR_MUT_SHOOT1,SPR_MUT_SHOOT2,SPR_MUT_SHOOT3,SPR_MUT_SHOOT4,
-
-//
-// officer
-//
-		SPR_OFC_S_1,SPR_OFC_S_2,SPR_OFC_S_3,SPR_OFC_S_4,
-		SPR_OFC_S_5,SPR_OFC_S_6,SPR_OFC_S_7,SPR_OFC_S_8,
-
-		SPR_OFC_W1_1,SPR_OFC_W1_2,SPR_OFC_W1_3,SPR_OFC_W1_4,
-		SPR_OFC_W1_5,SPR_OFC_W1_6,SPR_OFC_W1_7,SPR_OFC_W1_8,
-
-		SPR_OFC_W2_1,SPR_OFC_W2_2,SPR_OFC_W2_3,SPR_OFC_W2_4,
-		SPR_OFC_W2_5,SPR_OFC_W2_6,SPR_OFC_W2_7,SPR_OFC_W2_8,
-
-		SPR_OFC_W3_1,SPR_OFC_W3_2,SPR_OFC_W3_3,SPR_OFC_W3_4,
-		SPR_OFC_W3_5,SPR_OFC_W3_6,SPR_OFC_W3_7,SPR_OFC_W3_8,
-
-		SPR_OFC_W4_1,SPR_OFC_W4_2,SPR_OFC_W4_3,SPR_OFC_W4_4,
-		SPR_OFC_W4_5,SPR_OFC_W4_6,SPR_OFC_W4_7,SPR_OFC_W4_8,
-
-		SPR_OFC_PAIN_1,SPR_OFC_DIE_1,SPR_OFC_DIE_2,SPR_OFC_DIE_3,
-		SPR_OFC_PAIN_2,SPR_OFC_DIE_4,SPR_OFC_DEAD,
-
-		SPR_OFC_SHOOT1,SPR_OFC_SHOOT2,SPR_OFC_SHOOT3,
-
-#ifndef SPEAR
-//
-// ghosts
-//
-		SPR_BLINKY_W1,SPR_BLINKY_W2,SPR_PINKY_W1,SPR_PINKY_W2,
-		SPR_CLYDE_W1,SPR_CLYDE_W2,SPR_INKY_W1,SPR_INKY_W2,
-
-//
-// hans
-//
-		SPR_BOSS_W1,SPR_BOSS_W2,SPR_BOSS_W3,SPR_BOSS_W4,
-		SPR_BOSS_SHOOT1,SPR_BOSS_SHOOT2,SPR_BOSS_SHOOT3,SPR_BOSS_DEAD,
-
-		SPR_BOSS_DIE1,SPR_BOSS_DIE2,SPR_BOSS_DIE3,
-
-//
-// schabbs
-//
-		SPR_SCHABB_W1,SPR_SCHABB_W2,SPR_SCHABB_W3,SPR_SCHABB_W4,
-		SPR_SCHABB_SHOOT1,SPR_SCHABB_SHOOT2,
-
-		SPR_SCHABB_DIE1,SPR_SCHABB_DIE2,SPR_SCHABB_DIE3,SPR_SCHABB_DEAD,
-		SPR_HYPO1,SPR_HYPO2,SPR_HYPO3,SPR_HYPO4,
-
-//
-// fake
-//
-		SPR_FAKE_W1,SPR_FAKE_W2,SPR_FAKE_W3,SPR_FAKE_W4,
-		SPR_FAKE_SHOOT,SPR_FIRE1,SPR_FIRE2,
-
-		SPR_FAKE_DIE1,SPR_FAKE_DIE2,SPR_FAKE_DIE3,SPR_FAKE_DIE4,
-		SPR_FAKE_DIE5,SPR_FAKE_DEAD,
-
-//
-// hitler
-//
-		SPR_MECHA_W1,SPR_MECHA_W2,SPR_MECHA_W3,SPR_MECHA_W4,
-		SPR_MECHA_SHOOT1,SPR_MECHA_SHOOT2,SPR_MECHA_SHOOT3,SPR_MECHA_DEAD,
-
-		SPR_MECHA_DIE1,SPR_MECHA_DIE2,SPR_MECHA_DIE3,
-
-		SPR_HITLER_W1,SPR_HITLER_W2,SPR_HITLER_W3,SPR_HITLER_W4,
-		SPR_HITLER_SHOOT1,SPR_HITLER_SHOOT2,SPR_HITLER_SHOOT3,SPR_HITLER_DEAD,
-
-		SPR_HITLER_DIE1,SPR_HITLER_DIE2,SPR_HITLER_DIE3,SPR_HITLER_DIE4,
-		SPR_HITLER_DIE5,SPR_HITLER_DIE6,SPR_HITLER_DIE7,
-
-//
-// giftmacher
-//
-		SPR_GIFT_W1,SPR_GIFT_W2,SPR_GIFT_W3,SPR_GIFT_W4,
-		SPR_GIFT_SHOOT1,SPR_GIFT_SHOOT2,
-
-		SPR_GIFT_DIE1,SPR_GIFT_DIE2,SPR_GIFT_DIE3,SPR_GIFT_DEAD,
-#endif
-//
-// Rocket, smoke and small explosion
-//
-		SPR_ROCKET_1,SPR_ROCKET_2,SPR_ROCKET_3,SPR_ROCKET_4,
-		SPR_ROCKET_5,SPR_ROCKET_6,SPR_ROCKET_7,SPR_ROCKET_8,
-
-		SPR_SMOKE_1,SPR_SMOKE_2,SPR_SMOKE_3,SPR_SMOKE_4,
-		SPR_BOOM_1,SPR_BOOM_2,SPR_BOOM_3,
-
-//
-// Angel of Death's DeathSparks(tm)
-//
-#ifdef SPEAR
-		SPR_HROCKET_1,SPR_HROCKET_2,SPR_HROCKET_3,SPR_HROCKET_4,
-		SPR_HROCKET_5,SPR_HROCKET_6,SPR_HROCKET_7,SPR_HROCKET_8,
-
-		SPR_HSMOKE_1,SPR_HSMOKE_2,SPR_HSMOKE_3,SPR_HSMOKE_4,
-		SPR_HBOOM_1,SPR_HBOOM_2,SPR_HBOOM_3,
-
-		SPR_SPARK1,SPR_SPARK2,SPR_SPARK3,SPR_SPARK4,
-#endif
-
-#ifndef SPEAR
-//
-// gretel
-//
-		SPR_GRETEL_W1,SPR_GRETEL_W2,SPR_GRETEL_W3,SPR_GRETEL_W4,
-		SPR_GRETEL_SHOOT1,SPR_GRETEL_SHOOT2,SPR_GRETEL_SHOOT3,SPR_GRETEL_DEAD,
-
-		SPR_GRETEL_DIE1,SPR_GRETEL_DIE2,SPR_GRETEL_DIE3,
-
-//
-// fat face
-//
-		SPR_FAT_W1,SPR_FAT_W2,SPR_FAT_W3,SPR_FAT_W4,
-		SPR_FAT_SHOOT1,SPR_FAT_SHOOT2,SPR_FAT_SHOOT3,SPR_FAT_SHOOT4,
-
-		SPR_FAT_DIE1,SPR_FAT_DIE2,SPR_FAT_DIE3,SPR_FAT_DEAD,
-
-//
-// bj
-//
-		SPR_BJ_W1,SPR_BJ_W2,SPR_BJ_W3,SPR_BJ_W4,
-		SPR_BJ_JUMP1,SPR_BJ_JUMP2,SPR_BJ_JUMP3,SPR_BJ_JUMP4,
-#else
-//
-// THESE ARE FOR 'SPEAR OF DESTINY'
-//
-
-//
-// Trans Grosse
-//
-		SPR_TRANS_W1,SPR_TRANS_W2,SPR_TRANS_W3,SPR_TRANS_W4,
-		SPR_TRANS_SHOOT1,SPR_TRANS_SHOOT2,SPR_TRANS_SHOOT3,SPR_TRANS_DEAD,
-
-		SPR_TRANS_DIE1,SPR_TRANS_DIE2,SPR_TRANS_DIE3,
-
-//
-// Wilhelm
-//
-		SPR_WILL_W1,SPR_WILL_W2,SPR_WILL_W3,SPR_WILL_W4,
-		SPR_WILL_SHOOT1,SPR_WILL_SHOOT2,SPR_WILL_SHOOT3,SPR_WILL_SHOOT4,
-
-		SPR_WILL_DIE1,SPR_WILL_DIE2,SPR_WILL_DIE3,SPR_WILL_DEAD,
-
-//
-// UberMutant
-//
-		SPR_UBER_W1,SPR_UBER_W2,SPR_UBER_W3,SPR_UBER_W4,
-		SPR_UBER_SHOOT1,SPR_UBER_SHOOT2,SPR_UBER_SHOOT3,SPR_UBER_SHOOT4,
-
-		SPR_UBER_DIE1,SPR_UBER_DIE2,SPR_UBER_DIE3,SPR_UBER_DIE4,
-		SPR_UBER_DEAD,
-
-//
-// Death Knight
-//
-		SPR_DEATH_W1,SPR_DEATH_W2,SPR_DEATH_W3,SPR_DEATH_W4,
-		SPR_DEATH_SHOOT1,SPR_DEATH_SHOOT2,SPR_DEATH_SHOOT3,SPR_DEATH_SHOOT4,
-
-		SPR_DEATH_DIE1,SPR_DEATH_DIE2,SPR_DEATH_DIE3,SPR_DEATH_DIE4,
-		SPR_DEATH_DIE5,SPR_DEATH_DIE6,SPR_DEATH_DEAD,
-
-//
-// Ghost
-//
-		SPR_SPECTRE_W1,SPR_SPECTRE_W2,SPR_SPECTRE_W3,SPR_SPECTRE_W4,
-		SPR_SPECTRE_F1,SPR_SPECTRE_F2,SPR_SPECTRE_F3,SPR_SPECTRE_F4,
-
-//
-// Angel of Death
-//
-		SPR_ANGEL_W1,SPR_ANGEL_W2,SPR_ANGEL_W3,SPR_ANGEL_W4,
-		SPR_ANGEL_SHOOT1,SPR_ANGEL_SHOOT2,SPR_ANGEL_TIRED1,SPR_ANGEL_TIRED2,
-
-		SPR_ANGEL_DIE1,SPR_ANGEL_DIE2,SPR_ANGEL_DIE3,SPR_ANGEL_DIE4,
-		SPR_ANGEL_DIE5,SPR_ANGEL_DIE6,SPR_ANGEL_DIE7,SPR_ANGEL_DEAD,
-
-#endif
-
-//
-// player attack frames
-//
-		SPR_KNIFEREADY,SPR_KNIFEATK1,SPR_KNIFEATK2,SPR_KNIFEATK3,
-		SPR_KNIFEATK4,
-
-		SPR_PISTOLREADY,SPR_PISTOLATK1,SPR_PISTOLATK2,SPR_PISTOLATK3,
-		SPR_PISTOLATK4,
-
-		SPR_MACHINEGUNREADY,SPR_MACHINEGUNATK1,SPR_MACHINEGUNATK2,MACHINEGUNATK3,
-		SPR_MACHINEGUNATK4,
-
-		SPR_CHAINREADY,SPR_CHAINATK1,SPR_CHAINATK2,SPR_CHAINATK3,
-		SPR_CHAINATK4,
-
-		};
-
-
-/*
-=============================================================================
-
-						   GLOBAL TYPES
-
-=============================================================================
-*/
-
 typedef enum {
 	di_north,
 	di_east,
@@ -476,15 +81,6 @@
 } controldir_t;
 
 typedef enum {
-	dr_normal,
-	dr_lock1,
-	dr_lock2,
-	dr_lock3,
-	dr_lock4,
-	dr_elevator
-} door_t;
-
-typedef enum {
 	ac_badobject = -1,
 	ac_no,
 	ac_yes,
@@ -491,103 +87,6 @@
 	ac_allways
 } activetype;
 
-typedef enum {
-	nothing,
-	playerobj,
-	inertobj,
-	guardobj,
-	officerobj,
-	ssobj,
-	dogobj,
-	bossobj,
-	schabbobj,
-	fakeobj,
-	mechahitlerobj,
-	mutantobj,
-	needleobj,
-	fireobj,
-	bjobj,
-	ghostobj,
-	realhitlerobj,
-	gretelobj,
-	giftobj,
-	fatobj,
-	rocketobj,
-
-	spectreobj,
-	angelobj,
-	transobj,
-	uberobj,
-	willobj,
-	deathobj,
-	hrocketobj,
-	sparkobj
-} classtype;
-
-typedef enum {
-	dressing,
-	block,
-	bo_gibs,
-	bo_alpo,
-	bo_firstaid,
-	bo_key1,
-	bo_key2,
-	bo_key3,
-	bo_key4,
-	bo_cross,
-	bo_chalice,
-	bo_bible,
-	bo_crown,
-	bo_clip,
-	bo_clip2,
-	bo_machinegun,
-	bo_chaingun,
-	bo_food,
-	bo_fullheal,
-	bo_25clip,
-	bo_spear
-} stat_t;
-
-typedef enum {
-	east,
-	northeast,
-	north,
-	northwest,
-	west,
-	southwest,
-	south,
-	southeast,
-	nodir
-} dirtype;
-
-
-#define NUMENEMIES		22
-typedef enum {
-	en_guard,
-	en_officer,
-	en_ss,
-	en_dog,
-	en_boss,
-	en_schabbs,
-	en_fake,
-	en_hitler,
-	en_mutant,
-	en_blinky,
-	en_clyde,
-	en_pinky,
-	en_inky,
-	en_gretel,
-	en_gift,
-	en_fat,
-	en_spectre,
-	en_angel,
-	en_trans,
-	en_uber,
-	en_will,
-	en_death
-} enemy_t;
-
-
 typedef struct	statestruct
 {
 	int	rotate;
@@ -597,13 +96,6 @@
 	struct	statestruct	*next;
 } statetype;
 
-
-//---------------------
-//
-// trivial actor structure
-//
-//---------------------
-
 typedef struct statstruct
 {
 	u8int	tilex,tiley;
@@ -610,342 +102,40 @@
 	u8int	*visspot;
 	s16int		shapenum;			// if shapenum == -1 the obj has been removed
 	u8int	flags;
-	u8int	itemnumber;
+	u8int	item;
 } statobj_t;
 
-
-//---------------------
-//
-// door actor structure
-//
-//---------------------
-
-typedef struct doorstruct
-{
-	u8int	tilex,tiley;
-	int	vertical;
-	u8int	lock;
-	enum	{dr_open,dr_closed,dr_opening,dr_closing}	action;
-	s16int		ticcount;
-} doorobj_t;
-
-
-//--------------------
-//
-// thinking actor structure
-//
-//--------------------
-
-typedef struct objstruct
-{
-	activetype	active;
-	s16int			ticcount;
-	classtype	obclass;
-	statetype	*state;
-
-	u8int		flags;				//	FL_SHOOTABLE, etc
-
-	s32int		distance;			// if negative, wait for that door to open
-	dirtype		dir;
-
-	s32int 		x,y;
-	u16int	tilex,tiley;
-	u8int		areanumber;
-
-	s16int	 		viewx;
-	u16int	viewheight;
-	s32int		transx,transy;		// in global coord
-
-	s16int 		angle;
-	s16int			hitpoints;
-	s32int		speed;
-
-	s16int			temp1,temp2,temp3;
-	struct		objstruct	*next,*prev;
-} objtype;
-
-
-#define NUMBUTTONS	8
-enum	{
-	bt_nobutton=-1,
-	bt_attack=0,
-	bt_strafe,
-	bt_run,
-	bt_use,
-	bt_readyknife,
-	bt_readypistol,
-	bt_readymachinegun,
-	bt_readychaingun
-};
-
-
-#define NUMWEAPONS	5
-typedef enum	{
-	wp_knife,
-	wp_pistol,
-	wp_machinegun,
-	wp_chaingun
-} weapontype;
-
-
-typedef enum	{
-	gd_baby,
-	gd_easy,
-	gd_medium,
-	gd_hard
-};
-
-//---------------
-//
-// gamestate structure
-//
-//---------------
-
-typedef	struct
-{
-	s16int			difficulty;
-	s16int			mapon;
-	s32int		oldscore,score,nextextra;
-	s16int			lives;
-	s16int			health;
-	s16int			ammo;
-	s16int			keys;
-	weapontype		bestweapon,weapon,chosenweapon;
-
-	s16int			faceframe;
-	s16int			attackframe,attackcount,weaponframe;
-
-	s16int			episode,secretcount,treasurecount,killcount,
-				secrettotal,treasuretotal,killtotal;
-	s32int		TimeCount;
-	s32int		killx,killy;
-	int		victoryflag;		// set during victory animations
-} gametype;
-
-
-typedef	enum	{
-	ex_stillplaying,
-	ex_completed,
-	ex_died,
-	ex_warped,
-	ex_resetgame,
-	ex_loadedgame,
-	ex_victorious,
-	ex_abort,
-	ex_demodone,
-	ex_secretlevel
-} exit_t;
-
-
-/*
-=============================================================================
-
-						 WL_MAIN DEFINITIONS
-
-=============================================================================
-*/
-
-extern	char		str[80],str2[20];
-
 extern	u8int far	*scalermemory;
 
 extern	s32int		focallength;
-extern	u16int	viewangles;
 extern	u16int	screenofs;
-extern	s16int		    viewwidth;
-extern	s16int			viewheight;
-extern	s16int			centerx;
-extern	s16int			shootdelta;
 
-extern	s16int			dirangle[9];
-
-extern	int         startgame,loadedgame;
+extern	int         startgame;
 extern	s16int		mouseadjustment;
-//
-// math tables
-//
-extern	s16int			pixelangle[MAXVIEWWIDTH];
-extern	s32int		far finetangent[FINEANGLES/4];
-extern	s32int 		far sintable[],far *costable;
 
-//
-// derived constants
-//
-extern	s32int 	scale,maxslope;
-extern	s32int	heightnumerator;
-extern	s16int		minheightdiv;
-
-extern	char	configname[13];
-
-
-
-void		HelpScreens (void);
-void		OrderingInfo (void);
-void		TEDDeath(void);
-void		Quit (char *error);
-void 		CalcProjection (s32int focal);
-int		SetViewSize (u16int width, u16int height);
-void		NewGame (s16int difficulty,s16int episode);
-void 		NewViewSize (s16int width);
-int 	LoadTheGame(s16int file,s16int x,s16int y);
-int		SaveTheGame(s16int file,s16int x,s16int y);
-void 		ShowViewSize (s16int width);
-void		ShutdownId (void);
-
-
-/*
-=============================================================================
-
-						 WL_GAME DEFINITIONS
-
-=============================================================================
-*/
-
-
 extern	int		ingame,fizzlein;
 extern	u16int	latchpics[NUMLATCHPICS];
 extern	gametype	gamestate;
-extern	s16int			doornum;
 
-extern	char		demoname[13];
-
 extern	s32int		spearx,speary;
 extern	u16int	spearangle;
 extern	int		spearflag;
 
-
-void 	DrawPlayBorder (void);
-void 	ScanInfoPlane (void);
-void	SetupGameLevel (void);
-void 	NormalScreen (void);
-void 	DrawPlayScreen (void);
-void 	FizzleOut (void);
-void 	GameLoop (void);
-void ClearMemory (void);
-void PlayDemo (s16int demonumber);
-void RecordDemo (void);
-void DrawAllPlayBorder (void);
-void	DrawHighScores(void);
-void DrawAllPlayBorderSides (void);
-
-
-// JAB
-#define	PlaySoundLocTile(s,tx,ty)	PlaySoundLocGlobal(s,(((s32int)(tx) << TILESHIFT) + (1L << (TILESHIFT - 1))),(((s32int)ty << TILESHIFT) + (1L << (TILESHIFT - 1))))
-#define	PlaySoundLocActor(s,ob)		PlaySoundLocGlobal(s,(ob)->x,(ob)->y)
-void	PlaySoundLocGlobal(u16int s,s32int gx,s32int gy);
-void UpdateSoundLoc(void);
-
-
-/*
-=============================================================================
-
-						 WL_PLAY DEFINITIONS
-
-=============================================================================
-*/
-
-#ifdef SPEAR
-extern	s32int		funnyticount;		// FOR FUNNY BJ FACE
-#endif
-
-extern	exit_t		playstate;
-
-extern	int		madenoise;
-
-extern	objtype 	objlist[MAXACTORS],*new,*obj,*player,*lastobj,
-					*objfreelist,*killerobj;
-extern	statobj_t	statobjlist[MAXSTATS],*laststatobj;
-extern	doorobj_t	doorobjlist[MAXDOORS],*lastdoorobj;
-
-extern	u16int	farmapylookup[MAPSIZE];
-
-extern	u8int		tilemap[MAPSIZE][MAPSIZE];	// wall values only
-extern	u8int		spotvis[MAPSIZE][MAPSIZE];
-extern	objtype		*actorat[MAPSIZE][MAPSIZE];
-
 #define UPDATESIZE			(UPDATEWIDE*UPDATEHIGH)
 extern	u8int		update[UPDATESIZE];
 
-extern	int		singlestep,godmode,noclip;
 extern	s16int			extravbls;
 
-//
-// control info
-//
-extern	int		mouseenabled,joystickenabled,joypadenabled,joystickprogressive;
-extern	s16int			joystickport;
-extern	s16int			dirscan[4];
-extern	s16int			buttonscan[NUMBUTTONS];
-extern	s16int			buttonmouse[4];
-extern	s16int			buttonjoy[4];
-
-extern	int		buttonheld[NUMBUTTONS];
-
-extern	s16int			viewsize;
-
-//
-// curent user input
-//
-extern	s16int			controlx,controly;		// range from -100 to 100
-extern	int		buttonstate[NUMBUTTONS];
-
-extern	int		demorecord,demoplayback;
 extern	char		far *demoptr, far *lastdemoptr;
 extern	uchar *demobuffer;
 
+extern	u16int screenloc[3] = {PAGE1START,PAGE2START,PAGE3START};
+extern	u16int freelatch;	// = FREESTART
 
+// the door is the last picture before the sprites
+#define SPdoor	(PMSpriteStart-8)
+// e.g. sprs-8
 
-void	InitRedShifts (void);
-void 	FinishPaletteShifts (void);
-
-void	CenterWindow(u16int w,u16int h);
-void 	InitActorList (void);
-void 	GetNewActor (void);
-void 	RemoveObj (objtype *gone);
-void 	PollControls (void);
-void 	StopMusic(void);
-void 	StartMusic(void);
-void	PlayLoop (void);
-void StartDamageFlash (s16int damage);
-void StartBonusFlash (void);
-
-/*
-=============================================================================
-
-							WL_INTER
-
-=============================================================================
-*/
-
-void PreloadGraphics(void);
-void LevelCompleted (void);
-void	CheckHighScore (s32int score,u16int other);
-void Victory (void);
-void ClearSplitVWB (void);
-
-
-/*
-=============================================================================
-
-							WL_DEBUG
-
-=============================================================================
-*/
-
-s16int DebugKeys (void);
-
-
-/*
-=============================================================================
-
-						 WL_DRAW DEFINITIONS
-
-=============================================================================
-*/
-
-extern	u16int screenloc[3];
-extern	u16int freelatch;
-
 extern	s32int 	lasttimecount;
 extern	s32int 	frameon;
 extern	int	fizzlein;
@@ -952,96 +142,31 @@
 
 extern	u16int	wallheight[MAXVIEWWIDTH];
 
-extern	s32int	tileglobal;
 extern	s32int	focallength;
 extern	s32int	mindist;
 
 //
-// math tables
+// wall optimization variables
 //
-extern	s16int			pixelangle[MAXVIEWWIDTH];
-extern	s32int		far finetangent[FINEANGLES/4];
-extern	s32int 		far sintable[],far *costable;
+extern s16int	lastside;		// true for vertical
+extern s32int	lastintercept;
+extern s16int	lasttilehit;
+extern s16int	horizwall[MAXWALLTILES],vertwall[MAXWALLTILES];
 
 //
 // derived constants
 //
 extern	s32int 	scale;
-extern	s32int	heightnumerator,mindist;
+extern	s32int	mindist;
 
-//
 // refresh variables
-//
-extern	s32int	viewx,viewy;			// the focal point
-extern	s16int		viewangle;
-extern	s32int	viewsin,viewcos;
-
 extern	s32int		postsource;
 extern	u16int	postx;
 extern	u16int	postwidth;
 
-
-extern	s16int		horizwall[],vertwall[];
-
-extern	u16int	pwallpos;
-
-
-s32int	FixedByFrac (s32int a, s32int b);
-void	TransformActor (objtype *ob);
-void	BuildTables (void);
-void	ClearScreen (void);
-s16int		CalcRotate (objtype *ob);
-void	DrawScaleds (void);
-void	CalcTics (void);
-void	FixOfs (void);
-void	ThreeDRefresh (void);
-void  FarScalePost (void);
-
-/*
-=============================================================================
-
-						 WL_STATE DEFINITIONS
-
-=============================================================================
-*/
-#define TURNTICS	10
-#define SPDPATROL	512
-#define SPDDOG		1500
-
-
 extern	dirtype opposite[9];
 extern	dirtype diagonal[9][9];
 
-
-void	InitHitRect (objtype *ob, u16int radius);
-void	SpawnNewObj (u16int tilex, u16int tiley, statetype *state);
-void	NewState (objtype *ob, statetype *state);
-
-int TryWalk (objtype *ob);
-void 	SelectChaseDir (objtype *ob);
-void 	SelectDodgeDir (objtype *ob);
-void	SelectRunDir (objtype *ob);
-void	MoveObj (objtype *ob, s32int move);
-int SightPlayer (objtype *ob);
-
-void	KillActor (objtype *ob);
-void	DamageActor (objtype *ob, u16int damage);
-
-int CheckLine (objtype *ob);
-int	CheckSight (objtype *ob);
-
-
-/*
-=============================================================================
-
-						 WL_SCALE DEFINITIONS
-
-=============================================================================
-*/
-
-
-#define COMPSCALECODESTART	(65*4)		// offset to start of code in comp scaler
-
 typedef struct
 {
 	u16int	codeofs[65];
@@ -1072,183 +197,15 @@
 
 extern	int	insetupscaling;
 
-void SetupScaling (s16int maxscaleheight);
-void ScaleShape (s16int xcenter, s16int shapenum, u16int height);
-void SimpleScaleShape (s16int xcenter, s16int shapenum, u16int height);
-
-/*
-=============================================================================
-
-						 WL_AGENT DEFINITIONS
-
-=============================================================================
-*/
-
-//
-// player state info
-//
 extern	int		running;
-extern	s32int		thrustspeed;
 extern	u16int	plux,pluy;		// player coordinates scaled to u16int
 
 extern	s16int			anglefrac;
 extern	s16int			facecount;
 
-void	SpawnPlayer (s16int tilex, s16int tiley, s16int dir);
-void 	DrawFace (void);
-void	DrawHealth (void);
-void	TakeDamage (s16int points,objtype *attacker);
-void	HealSelf (s16int points);
-void	DrawLevel (void);
-void	DrawLives (void);
-void	GiveExtraMan (void);
-void	DrawScore (void);
-void	GivePoints (s32int points);
-void	DrawWeapon (void);
-void	DrawKeys (void);
-void	GiveWeapon (s16int weapon);
-void	DrawAmmo (void);
-void	GiveAmmo (s16int ammo);
-void	GiveKey (s16int key);
-void	GetBonus (statobj_t *check);
+extern	u16int	doorposition[Ndoor],pwallstate;
 
-void	Thrust (s16int angle, s32int speed);
-
-/*
-=============================================================================
-
-						 WL_ACT1 DEFINITIONS
-
-=============================================================================
-*/
-
-extern	doorobj_t	doorobjlist[MAXDOORS],*lastdoorobj;
-extern	s16int			doornum;
-
-extern	u16int	doorposition[MAXDOORS],pwallstate;
-
-extern	u8int		far areaconnect[NUMAREAS][NUMAREAS];
-
-extern	int		areabyplayer[NUMAREAS];
-
 extern u16int	pwallstate;
 extern u16int	pwallpos;			// amount a pushable wall has been moved (0-63)
 extern u16int	pwallx,pwally;
 extern s16int			pwalldir;
-
-
-void InitDoorList (void);
-void InitStaticList (void);
-void SpawnStatic (s16int tilex, s16int tiley, s16int type);
-void SpawnDoor (s16int tilex, s16int tiley, int vertical, s16int lock);
-void MoveDoors (void);
-void MovePWalls (void);
-void OpenDoor (s16int door);
-void PlaceItemType (s16int itemtype, s16int tilex, s16int tiley);
-void PushWall (s16int checkx, s16int checky, s16int dir);
-void OperateDoor (s16int door);
-void InitAreas (void);
-
-/*
-=============================================================================
-
-						 WL_ACT2 DEFINITIONS
-
-=============================================================================
-*/
-
-#define s_nakedbody s_static10
-
-extern	statetype s_grddie1;
-extern	statetype s_dogdie1;
-extern	statetype s_ofcdie1;
-extern	statetype s_mutdie1;
-extern	statetype s_ssdie1;
-extern	statetype s_bossdie1;
-extern	statetype s_schabbdie1;
-extern	statetype s_fakedie1;
-extern	statetype s_mechadie1;
-extern	statetype s_hitlerdie1;
-extern	statetype s_greteldie1;
-extern	statetype s_giftdie1;
-extern	statetype s_fatdie1;
-
-extern	statetype s_spectredie1;
-extern	statetype s_angeldie1;
-extern	statetype s_transdie0;
-extern	statetype s_uberdie0;
-extern	statetype s_willdie1;
-extern	statetype s_deathdie1;
-
-
-extern	statetype s_grdchase1;
-extern	statetype s_dogchase1;
-extern	statetype s_ofcchase1;
-extern	statetype s_sschase1;
-extern	statetype s_mutchase1;
-extern	statetype s_bosschase1;
-extern	statetype s_schabbchase1;
-extern	statetype s_fakechase1;
-extern	statetype s_mechachase1;
-extern	statetype s_gretelchase1;
-extern	statetype s_giftchase1;
-extern	statetype s_fatchase1;
-
-extern	statetype s_spectrechase1;
-extern	statetype s_angelchase1;
-extern	statetype s_transchase1;
-extern	statetype s_uberchase1;
-extern	statetype s_willchase1;
-extern	statetype s_deathchase1;
-
-extern	statetype s_blinkychase1;
-extern	statetype s_hitlerchase1;
-
-extern	statetype s_grdpain;
-extern	statetype s_grdpain1;
-extern	statetype s_ofcpain;
-extern	statetype s_ofcpain1;
-extern	statetype s_sspain;
-extern	statetype s_sspain1;
-extern	statetype s_mutpain;
-extern	statetype s_mutpain1;
-
-extern	statetype s_deathcam;
-
-extern	statetype s_schabbdeathcam2;
-extern	statetype s_hitlerdeathcam2;
-extern	statetype s_giftdeathcam2;
-extern	statetype s_fatdeathcam2;
-
-void SpawnStand (enemy_t which, s16int tilex, s16int tiley, s16int dir);
-void SpawnPatrol (enemy_t which, s16int tilex, s16int tiley, s16int dir);
-void KillActor (objtype *ob);
-
-void	US_ControlPanel(u8int);
-
-void SpawnDeadGuard (s16int tilex, s16int tiley);
-void SpawnBoss (s16int tilex, s16int tiley);
-void SpawnGretel (s16int tilex, s16int tiley);
-void SpawnTrans (s16int tilex, s16int tiley);
-void SpawnUber (s16int tilex, s16int tiley);
-void SpawnWill (s16int tilex, s16int tiley);
-void SpawnDeath (s16int tilex, s16int tiley);
-void SpawnAngel (s16int tilex, s16int tiley);
-void SpawnSpectre (s16int tilex, s16int tiley);
-void SpawnGhosts (s16int which, s16int tilex, s16int tiley);
-void SpawnSchabbs (s16int tilex, s16int tiley);
-void SpawnGift (s16int tilex, s16int tiley);
-void SpawnFat (s16int tilex, s16int tiley);
-void SpawnFakeHitler (s16int tilex, s16int tiley);
-void SpawnHitler (s16int tilex, s16int tiley);
-
-/*
-=============================================================================
-
-						 WL_TEXT DEFINITIONS
-
-=============================================================================
-*/
-
-extern	void	HelpScreens(void);
-extern	void	EndText(void);
--- a/detect.c
+++ /dev/null
@@ -1,87 +1,0 @@
-///////////////////////////////////////////////////////////////////////////
-//
-//	SDL_CheckSB() - Checks to see if a SoundBlaster resides at a
-//		particular I/O location
-//
-///////////////////////////////////////////////////////////////////////////
-static int
-SDL_CheckSB(s16int port)
-{
-	s16int	i;
-
-	sbLocation = port << 4;		// Initialize stuff for later use
-
-	sbOut(sbReset,true);		// Reset the SoundBlaster DSP
-asm	mov	dx,0x388				// Wait >4usec
-asm	in	al, dx
-asm	in	al, dx
-asm	in	al, dx
-asm	in	al, dx
-asm	in	al, dx
-asm	in	al, dx
-asm	in	al, dx
-asm	in	al, dx
-asm	in	al, dx
-
-	sbOut(sbReset,false);		// Turn off sb DSP reset
-asm	mov	dx,0x388				// Wait >100usec
-asm	mov	cx,100
-usecloop:
-asm	in	al,dx
-asm	loop usecloop
-
-	for (i = 0;i < 100;i++)
-	{
-		if (sbIn(sbDataAvail) & 0x80)		// If data is available...
-		{
-			if (sbIn(sbReadData) == 0xaa)	// If it matches correct value
-				return(true);
-			else
-			{
-				sbLocation = -1;			// Otherwise not a SoundBlaster
-				return(false);
-			}
-		}
-	}
-	sbLocation = -1;						// Retry count exceeded - fail
-	return(false);
-}
-
-///////////////////////////////////////////////////////////////////////////
-//
-//	Checks to see if a SoundBlaster is in the system. If the port passed is
-//		-1, then it scans through all possible I/O locations. If the port
-//		passed is 0, then it uses the default (2). If the port is >0, then
-//		it just passes it directly to SDL_CheckSB()
-//
-///////////////////////////////////////////////////////////////////////////
-static int
-SDL_DetectSoundBlaster(s16int port)
-{
-	s16int	i;
-
-	if (port == 0)					// If user specifies default, use 2
-		port = 2;
-	if (port == -1)
-	{
-		if (SDL_CheckSB(2))			// Check default before scanning
-			return(true);
-
-		if (SDL_CheckSB(4))			// Check other SB Pro location before scan
-			return(true);
-
-		for (i = 1;i <= 6;i++)		// Scan through possible SB locations
-		{
-			if ((i == 2) || (i == 4))
-				continue;
-
-			if (SDL_CheckSB(i))		// If found at this address,
-				return(true);		//	return success
-		}
-		return(false);				// All addresses failed, return failure
-	}
-	else
-		return(SDL_CheckSB(port));	// User specified address or default
-}
-
-
\ No newline at end of file
--- a/draw.asm
+++ /dev/null
@@ -1,739 +1,0 @@
-	IDEAL
-	MODEL	MEDIUM,C
-	P286
-
-SCREENSEG	=	0a000h
-
-FINEANGLES	=	3600
-DEG90		=	900
-DEG180		=	1800
-DEG270		=	2700
-DEG360		=	3600
-
-OP_JLE		=	07eh
-OP_JGE		=	07dh
-
-EXTRN	finetangent:DWORD	; far array, starts at offset 0
-
-EXTRN	HitHorizWall:FAR
-EXTRN	HitVertWall:FAR
-EXTRN	HitHorizDoor:FAR
-EXTRN	HitVertDoor:FAR
-EXTRN	HitHorizPWall:FAR
-EXTRN	HitVertPWall:FAR
-
-
-DATASEG
-
-EXTRN	viewwidth:WORD
-
-EXTRN	tilemap:BYTE
-EXTRN	spotvis:BYTE
-EXTRN	pixelangle:WORD
-
-
-EXTRN	midangle:WORD
-EXTRN	angle:WORD
-
-EXTRN	focaltx:WORD
-EXTRN	focalty:WORD
-EXTRN	viewtx:WORD
-EXTRN	viewty:WORD
-EXTRN	viewx:DWORD
-EXTRN	viewy:DWORD
-
-EXTRN	xpartialup:WORD
-EXTRN	ypartialup:WORD
-EXTRN	xpartialdown:WORD
-EXTRN	ypartialdown:WORD
-
-EXTRN	tilehit:WORD
-EXTRN	pixx:WORD
-EXTRN	wallheight:WORD			; array of VIEWWIDTH entries
-
-EXTRN	xtile:WORD
-EXTRN	ytile:WORD
-EXTRN	xtilestep:WORD
-EXTRN	ytilestep:WORD
-EXTRN	xintercept:DWORD
-EXTRN	yintercept:DWORD
-EXTRN	xstep:DWORD
-EXTRN	ystep:DWORD
-
-EXTRN	doorposition:WORD		; table of door position values
-
-
-EXTRN	pwallpos:WORD			; amound a pushable wall has been moved
-
-CODESEG
-
-;-------------------
-;
-; xpartialbyystep
-;
-; multiplies s32int [ystep] (possibly negative), by word [xpartial] (in BX)
-;
-; returns dx:ax
-; trashes bx,cx,di
-;
-;-------------------
-
-PROC xpartialbyystep NEAR
-;
-; setup
-;
-	mov	ax,[WORD ystep]
-	mov	cx,[WORD ystep+2]
-	or	cx,cx               ; is ystep negatice?
-	jns	@@multpos
-;
-; multiply negative cx:ax by bx
-;
-	neg	cx
-	neg	ax
-	sbb	cx,0
-
-	mul	bx					; fraction*fraction
-	mov	di,dx				; di is low word of result
-	mov	ax,cx				;
-	mul	bx					; units*fraction
-	add	ax,di
-	adc	dx,0
-
-	neg	dx
-	neg	ax
-	sbb	dx,0
-	ret
-;
-; multiply positive cx:ax by bx
-;
-EVEN
-@@multpos:
-	mul	bx					; fraction*fraction
-	mov	di,dx				; di is low word of result
-	mov	ax,cx				;
-	mul	bx					; units*fraction
-	add	ax,di
-	adc	dx,0
-
-	ret
-
-ENDP
-
-
-
-;-------------------
-;
-; ypartialbyxstep
-;
-; multiplies s32int [xstep] (possibly negative), by word [ypartial] (in BP)
-;
-; returns dx:ax
-; trashes cx,di,bp
-;
-;-------------------
-
-PROC ypartialbyxstep NEAR
-;
-; setup
-;
-	mov	ax,[WORD xstep]
-	mov	cx,[WORD xstep+2]
-	or	cx,cx               ; is ystep negatice?
-	jns	@@multpos
-;
-; multiply negative cx:ax by bx
-;
-	neg	cx
-	neg	ax
-	sbb	cx,0
-
-	mul	bp					; fraction*fraction
-	mov	di,dx				; di is low word of result
-	mov	ax,cx				;
-	mul	bp					; units*fraction
-	add	ax,di
-	adc	dx,0
-
-	neg	dx
-	neg	ax
-	sbb	dx,0
-	ret
-;
-; multiply positive cx:ax by bx
-;
-EVEN
-@@multpos:
-	mul	bp					; fraction*fraction
-	mov	di,dx				; di is low word of result
-	mov	ax,cx				;
-	mul	bp					; units*fraction
-	add	ax,di
-	adc	dx,0
-	ret
-
-ENDP
-
-
-;============================
-;
-; AsmRefresh
-;
-;
-;============================
-
-PROC	AsmRefresh
-PUBLIC	AsmRefresh
-
-	push	si
-	push	di
-	push	bp
-
-	mov	[pixx],0
-;---------------------------------------------------------------------------
-;
-; Setup to trace a ray through pixx view pixel
-;
-; CX : angle of the ray through pixx
-; ES : points to segment of finetangent array for this block of code
-;
-; Upon entrance to initialize block
-;
-; BX : xpartial
-; BP : ypartial
-;
-;---------------------------------------------------------------------------
-	EVEN
-pixxloop:
-	mov	ax,SEG finetangent
-	mov	es,ax
-	mov	cx,[midangle]			; center of view area
-	mov	bx,[pixx]
-	shl	bx,1
-	add	cx,[pixelangle+bx]		; delta for this pixel
-	cmp	cx,0
-	jge	not0
-;----------
-;
-; -90 - -1 degree arc
-;
-;----------
-	add	cx,FINEANGLES			; -90 is the same as 270
-	jmp	entry360
-
-not0:
-	cmp	cx,DEG90
-	jge	not90
-;----------
-;
-; 0-89 degree arc
-;
-;----------
-entry90:
-	mov	[xtilestep],1			; xtilestep = 1
-	mov	[ytilestep],-1			; ytilestep = -1
-	mov	[BYTE cs:horizop],OP_JGE	; patch a jge in
-	mov	[BYTE cs:vertop],OP_JLE		; patch a jle in
-	mov	bx,DEG90-1
-	sub	bx,cx
-	shl	bx,2
-	mov	ax,[es:bx]
-	mov	dx,[es:bx+2]
-	mov	[WORD xstep],ax
-	mov	[WORD xstep+2],dx		; xstep = finetangent[DEG90-1-angle]
-	mov	bx,cx
-	shl	bx,2
-	mov	ax,[es:bx]
-	mov	dx,[es:bx+2]
-	neg	dx
-	neg	ax
-	sbb	dx,0
-	mov	[WORD ystep],ax
-	mov	[WORD ystep+2],dx		; ystep = -finetangent[angle]
-
-	mov	bx,[xpartialup]			; xpartial = xpartialup
-	mov	bp,[ypartialdown]		; ypartial = ypartialdown
-	jmp	initvars
-
-not90:
-	cmp	cx,DEG180
-	jge	not180
-;----------
-;
-; 90-179 degree arc
-;
-;----------
-	mov	ax,-1
-	mov	[xtilestep],ax			; xtilestep = -1
-	mov	[ytilestep],ax			; ytilestep = -1
-	mov	[BYTE cs:horizop],OP_JLE	; patch a jle in
-	mov	[BYTE cs:vertop],OP_JLE		; patch a jle in
-
-	mov	bx,cx
-	shl	bx,2
-	mov	ax,[es:bx-DEG90*4]
-	mov	dx,[es:bx+2-DEG90*4]
-	neg	dx
-	neg	ax
-	sbb	dx,0
-	mov	[WORD xstep],ax
-	mov	[WORD xstep+2],dx		; xstep = -finetangent[angle-DEG90]
-	mov	bx,DEG180-1
-	sub	bx,cx
-	shl	bx,2
-	mov	ax,[es:bx]
-	mov	dx,[es:bx+2]
-	neg	dx
-	neg	ax
-	sbb	dx,0
-	mov	[WORD ystep],ax
-	mov	[WORD ystep+2],dx		; ystep = -finetangent[DEG180-1-angle]
-
-	mov	bx,[xpartialdown]		; xpartial = xpartialdown
-	mov	bp,[ypartialdown]		; ypartial = ypartialdown
-	jmp	initvars
-
-not180:
-	cmp	cx,DEG270
-	jge	not270
-;----------
-;
-; 180-269 degree arc
-;
-;----------
-	mov	[xtilestep],-1			; xtilestep = -1
-	mov	[ytilestep],1			; ytilestep = 1
-	mov	[BYTE cs:horizop],OP_JLE	; patch a jle in
-	mov	[BYTE cs:vertop],OP_JGE		; patch a jge in
-
-	mov	bx,DEG270-1
-	sub	bx,cx
-	shl	bx,2
-	mov	ax,[es:bx]
-	mov	dx,[es:bx+2]
-	neg	dx
-	neg	ax
-	sbb	dx,0
-	mov	[WORD xstep],ax
-	mov	[WORD xstep+2],dx		; xstep = -finetangent[DEG270-1-angle]
-	mov	bx,cx
-	shl	bx,2
-	mov	ax,[es:bx-DEG180*4]
-	mov	dx,[es:bx+2-DEG180*4]
-	mov	[WORD ystep],ax
-	mov	[WORD ystep+2],dx		; ystep = finetangent[angle-DEG180]
-
-	mov	bx,[xpartialdown]		; xpartial = xpartialdown
-	mov	bp,[ypartialup]			; ypartial = ypartialup
-	jmp	initvars
-
-
-not270:
-	cmp	cx,DEG360
-	jge	not360
-;----------
-;
-; 270-359 degree arc
-;
-;----------
-entry360:
-	mov	ax,1
-	mov	[xtilestep],ax			; xtilestep = 1
-	mov	[ytilestep],ax			; ytilestep = 1
-	mov	[BYTE cs:horizop],OP_JGE	; patch a jge in
-	mov	[BYTE cs:vertop],OP_JGE		; patch a jge in
-
-	mov	bx,cx
-	shl	bx,2
-	mov	ax,[es:bx-DEG270*4]
-	mov	dx,[es:bx+2-DEG270*4]
-	mov	[WORD xstep],ax
-	mov	[WORD xstep+2],dx		; xstep = finetangent[angle-DEG270]
-	mov	bx,DEG360-1
-	sub	bx,cx
-	shl	bx,2
-	mov	ax,[es:bx]
-	mov	dx,[es:bx+2]
-	mov	[WORD ystep],ax
-	mov	[WORD ystep+2],dx		; ystep = finetangent[DEG360-1-angle]
-
-	mov	bx,[xpartialup]			; xpartial = xpartialup
-	mov	bp,[ypartialup]			; ypartial = ypartialup
-	jmp	initvars
-
-
-not360:
-;----------
-;
-; 360-449 degree arc
-;
-;----------
-	sub	cx,FINEANGLES			; -449 is the same as 89
-	jmp	entry90
-
-;---------------------------------------------------------------------------
-;
-; initialise variables for intersection testing
-;
-;---------------------------------------------------------------------------
-initvars:
-	call	NEAR xpartialbyystep	; xpartial is in BX
-	add	ax,[WORD viewy]
-	adc	dx,[WORD viewy+2]
-	mov	[WORD yintercept],ax
-	mov	[WORD yintercept+2],dx
-
-	mov	si,[focaltx]
-	add	si,[xtilestep]
-	mov	[xtile],si					; xtile = focaltx+xtilestep
-	shl	si,6
-	add	si,dx						; xspot = (xtile<<6) + yinttile
-
-
-	call	NEAR ypartialbyxstep	; ypartial is in BP
-	add	ax,[WORD viewx]
-	adc	dx,[WORD viewx+2]
-	mov	[WORD xintercept],ax
-	mov	cx,dx
-
-	mov	bx,[focalty]
-	add	bx,[ytilestep]
-	mov	bp,bx						; ytile = focalty+ytilestep
-	mov	di,dx
-	shl	di,6
-	add	di,bx						; yspot = (xinttile<<6) + ytile
-
-	mov	bx,[xtile]
-	mov	dx,[WORD yintercept+2]
-	mov	ax,SCREENSEG
-	mov	es,ax						; faster than mov es,[screenseg]
-
-
-;---------------------------------------------------------------------------
-;
-; trace along this angle until we hit a wall
-;
-; CORE LOOP!
-;
-; All variables are killed when a wall is hit
-;
-; AX : scratch
-; BX : xtile
-; CX : high word of xintercept
-; DX : high word of yintercept
-; SI : xspot (yinttile<<6)+xtile (index into tilemap and spotvis)
-; DI : yspot (xinttile<<6)+ytile (index into tilemap and spotvis)
-; BP : ytile
-; ES : screenseg
-;
-;---------------------------------------------------------------------------
-
-;-----------
-;
-; check intersections with vertical walls
-;
-;-----------
-
-	EVEN
-vertcheck:
-	cmp	dx,bp
-vertop:								; 0x7e = jle (ytilestep==-1)
-	jle	horizentry					; 0x7d = jge (ytilestep==1)
-vertentry:
-	test [BYTE tilemap+si],0ffh		; tilehit = *((byte *)tilemap+xspot);
-	jnz	hitvert
-passvert:
-	mov	[BYTE spotvis+si],1			; *((byte *)spotvis+xspot) = true;
-	add	bx,[xtilestep]				; xtile+=xtilestep
-	mov	ax,[WORD ystep]
-	add	[WORD yintercept],ax		; yintercept += ystep
-	adc	dx,[WORD ystep+2]
-	mov	si,bx
-	shl	si,6
-	add	si,dx						; xspot = (xtile<<6)+yinttile
-	jmp	vertcheck
-
-	EVEN
-hitvert:
-	mov	al,[BYTE tilemap+si]		; tilehit = *((byte *)tilemap+xspot);
-	mov	[BYTE tilehit],al
-	or	al,al						; set flags
-	jns	notvertdoor
-	jmp	vertdoor
-notvertdoor:
-	mov	[WORD xintercept],0
-	mov	[WORD xintercept+2],bx
-	mov	[xtile],bx
-	mov	[WORD yintercept+2],dx
-	mov	[ytile],dx
-	call FAR HitVertWall
-	jmp nextpix
-
-
-;-----------
-;
-; check intersections with horizontal walls
-;
-;-----------
-	EVEN
-horizcheck:
-	cmp	cx,bx
-horizop:							; 0x7e = jle (xtilestep==-1)
-	jle	vertentry					; 0x7d = jge (xtilestep==1)
-horizentry:
-	test [BYTE tilemap+di],0ffh		; tilehit = *((byte *)tilemap+yspot);
-	jnz	hithoriz
-passhoriz:
-	mov	[BYTE spotvis+di],1			; *((byte *)spotvis+yspot) = true;
-	add	bp,[ytilestep]				; ytile+=ytilestep
-	mov	ax,[WORD xstep]
-	add	[WORD xintercept],ax		; xintercept += xstep
-	adc	cx,[WORD xstep+2]
-	mov	di,cx
-	shl	di,6
-	add	di,bp						; yspot = (xinttile<<6)+ytile
-	jmp	horizcheck
-
-	EVEN
-hithoriz:
-	mov	al,[BYTE tilemap+di]		; tilehit = *((byte *)tilemap+yspot);
-	mov	[BYTE tilehit],al
-	or	al,al						; set flags
-	js	horizdoor
-	mov	[WORD xintercept+2],cx
-	mov	[xtile],cx
-	mov	[WORD yintercept],0
-	mov	[WORD yintercept+2],bp
-	mov	[ytile],bp
-	call FAR HitHorizWall
-	jmp nextpix
-
-;---------------------------------------------------------------------------
-;
-; next pixel over
-;
-;---------------------------------------------------------------------------
-
-nextpix:
-	mov	ax,[pixx]
-	inc	ax
-	mov	[pixx],ax
-	cmp	ax,[viewwidth]
-	jge	done
-	jmp	pixxloop
-done:
-	pop	bp
-	pop	di
-	pop	si
-	retf
-
-;===========================================================================
-
-;=============
-;
-; hit a special horizontal wall, so find which coordinate a door would be
-; intersected at, and check to see if the door is open past that point
-;
-;=============
-horizdoor:
-	mov	[xtile],bx					; save off live register variables
-	mov	[WORD yintercept+2],dx
-
-	test al,040h      				; both high bits set == pushable wall
-	jnz	horizpushwall
-
-	mov	bx,ax
-	and	bx,7fh						; strip high bit
-	shl	bx,1                        ; index into word width door table
-
-	mov	ax,[WORD xstep]
-	mov	dx,[WORD xstep+2]
-	sar	dx,1
-	rcr ax,1						; half a step gets to door position
-
-	add	ax,[WORD xintercept]		; add half step to current intercept pos
-	adc	dx,cx						; CX hold high word of xintercept
-
-	cmp	cx,dx						; is it still in the same tile?
-	je	hithmid
-;
-; midpoint is outside tile, so it hit the side of the wall before a door
-;
-continuehoriz:
-	mov	bx,[xtile]					; reload register variables
-	mov	dx,[WORD yintercept+2]
-	jmp	passhoriz					; continue tracing
-;
-; the trace hit the door plane at pixel position AX, see if the door is
-; closed that much
-;
-hithmid:
-	cmp	ax,[doorposition+bx]		; position of leading edge of door
-	jb	continuehoriz
-;
-; draw the door
-;
-	mov	[WORD xintercept],ax		; save pixel intercept position
-	mov	[WORD xintercept+2],cx
-
-	mov	[WORD yintercept],8000h		; intercept in middle of tile
-	mov	[WORD yintercept+2],bp
-
-	call	FAR HitHorizDoor
-	jmp	nextpix
-
-;============
-;
-; hit a sliding horizontal wall
-;
-;============
-
-horizpushwall:
-	mov	ax,[WORD xstep+2]			; multiply xstep by pwallmove (0-63)
-	mul	[pwallpos]
-	mov	bx,ax
-	mov	ax,[WORD xstep]
-	mul	[pwallpos]
-	add	dx,bx
-
-	sar	dx,1						; then divide by 64 to accomplish a
-	rcr ax,1						; fixed point multiplication
-	sar	dx,1
-	rcr ax,1
-	sar	dx,1
-	rcr ax,1
-	sar	dx,1
-	rcr ax,1
-	sar	dx,1
-	rcr ax,1
-	sar	dx,1
-	rcr ax,1
-
-	add	ax,[WORD xintercept]		; add partial step to current intercept
-	adc	dx,cx						; CX hold high word of xintercept
-
-	cmp	cx,dx						; is it still in the same tile?
-	jne	continuehoriz				; no, it hit the side
-
-;
-; draw the pushable wall at the new height
-;
-	mov	[WORD xintercept],ax		; save pixel intercept position
-	mov	[WORD xintercept+2],dx
-
-	mov	[WORD yintercept+2],bp
-	mov	[WORD yintercept],0
-
-	call	FAR HitHorizPWall
-	jmp	nextpix
-
-
-
-;===========================================================================
-
-;=============
-;
-; hit a special vertical wall, so find which coordinate a door would be
-; intersected at, and check to see if the door is open past that point
-;
-;=============
-vertdoor:
-	mov	[xtile],bx					; save off live register variables
-	mov	[WORD yintercept+2],dx
-
-	test al,040h      				; both high bits set == pushable wall
-	jnz	vertpushwall
-
-	mov	bx,ax
-	and	bx,7fh						; strip high bit
-	shl	bx,1                        ; index into word width doorposition
-
-	mov	ax,[WORD ystep]
-	mov	dx,[WORD ystep+2]
-	sar	dx,1
-	rcr ax,1						; half a step gets to door position
-
-	add	ax,[WORD yintercept]		; add half step to current intercept pos
-	adc	dx,[WORD yintercept+2]
-
-	cmp	[WORD yintercept+2],dx		; is it still in the same tile?
-	je	hitvmid
-;
-; midpoint is outside tile, so it hit the side of the wall before a door
-;
-continuevert:
-	mov	bx,[xtile]					; reload register variables
-	mov	dx,[WORD yintercept+2]
-	jmp	passvert					; continue tracing
-;
-; the trace hit the door plane at pixel position AX, see if the door is
-; closed that much
-;
-hitvmid:
-	cmp	ax,[doorposition+bx]		; position of leading edge of door
-	jb	continuevert
-;
-; draw the door
-;
-	mov	[WORD yintercept],ax		; save pixel intercept position
-	mov	[WORD xintercept],8000h		; intercept in middle of tile
-	mov	ax,[xtile]
-	mov	[WORD xintercept+2],ax
-
-	call	FAR HitVertDoor
-	jmp	nextpix
-
-;============
-;
-; hit a sliding vertical wall
-;
-;============
-
-vertpushwall:
-	mov	ax,[WORD ystep+2]			; multiply ystep by pwallmove (0-63)
-	mul	[pwallpos]
-	mov	bx,ax
-	mov	ax,[WORD ystep]
-	mul	[pwallpos]
-	add	dx,bx
-
-	sar	dx,1						; then divide by 64 to accomplish a
-	rcr ax,1						; fixed point multiplication
-	sar	dx,1
-	rcr ax,1
-	sar	dx,1
-	rcr ax,1
-	sar	dx,1
-	rcr ax,1
-	sar	dx,1
-	rcr ax,1
-	sar	dx,1
-	rcr ax,1
-
-	add	ax,[WORD yintercept]		; add partial step to current intercept
-	adc	dx,[WORD yintercept+2]
-
-	cmp	[WORD yintercept+2],dx		; is it still in the same tile?
-	jne	continuevert				; no, it hit the side
-
-;
-; draw the pushable wall at the new height
-;
-	mov	[WORD yintercept],ax		; save pixel intercept position
-	mov	[WORD yintercept+2],dx
-
-	mov	bx,[xtile]
-	mov	[WORD xintercept+2],bx
-	mov	[WORD xintercept],0
-
-	call	FAR HitVertPWall
-	jmp	nextpix
-
-
-
-ENDP
-
-
-END
-
-
--- a/draw.c
+++ /dev/null
@@ -1,1395 +1,0 @@
-// WL_DRAW.C
-
-#include "WL_DEF.H"
-#include <DOS.H>
-#pragma hdrstop
-
-//#define DEBUGWALLS
-//#define DEBUGTICS
-
-/*
-=============================================================================
-
-						 LOCAL CONSTANTS
-
-=============================================================================
-*/
-
-// the door is the last picture before the sprites
-#define DOORWALL	(PMSpriteStart-8)
-
-#define ACTORSIZE	0x4000
-
-/*
-=============================================================================
-
-						 GLOBAL VARIABLES
-
-=============================================================================
-*/
-
-
-#ifdef DEBUGWALLS
-u16int screenloc[3]= {0,0,0};
-#else
-u16int screenloc[3]= {PAGE1START,PAGE2START,PAGE3START};
-#endif
-u16int freelatch = FREESTART;
-
-s32int 	lasttimecount;
-s32int 	frameon;
-
-u16int	wallheight[MAXVIEWWIDTH];
-
-s32int	tileglobal	= TILEGLOBAL;
-s32int	mindist		= MINDIST;
-
-
-//
-// math tables
-//
-s16int			pixelangle[MAXVIEWWIDTH];
-s32int		far finetangent[FINEANGLES/4];
-s32int 		far sintable[ANGLES+ANGLES/4],far *costable = sintable+(ANGLES/4);
-
-//
-// refresh variables
-//
-s32int	viewx,viewy;			// the focal point
-s16int		viewangle;
-s32int	viewsin,viewcos;
-
-
-
-s32int	FixedByFrac (s32int a, s32int b);
-void	TransformActor (objtype *ob);
-void	BuildTables (void);
-void	ClearScreen (void);
-s16int		CalcRotate (objtype *ob);
-void	DrawScaleds (void);
-void	CalcTics (void);
-void	FixOfs (void);
-void	ThreeDRefresh (void);
-
-
-
-//
-// wall optimization variables
-//
-s16int		lastside;		// true for vertical
-s32int	lastintercept;
-s16int		lasttilehit;
-
-
-//
-// ray tracing variables
-//
-s16int			focaltx,focalty,viewtx,viewty;
-
-s16int			midangle,angle;
-u16int	xpartial,ypartial;
-u16int	xpartialup,xpartialdown,ypartialup,ypartialdown;
-u16int	xinttile,yinttile;
-
-u16int	tilehit;
-u16int	pixx;
-
-s16int		xtile,ytile;
-s16int		xtilestep,ytilestep;
-s32int	xintercept,yintercept;
-s32int	xstep,ystep;
-
-s16int		horizwall[MAXWALLTILES],vertwall[MAXWALLTILES];
-
-
-/*
-=============================================================================
-
-						 LOCAL VARIABLES
-
-=============================================================================
-*/
-
-
-void AsmRefresh (void);			// in WL_DR_A.ASM
-
-/*
-============================================================================
-
-			   3 - D  DEFINITIONS
-
-============================================================================
-*/
-
-
-//==========================================================================
-
-
-/*
-========================
-=
-= FixedByFrac
-=
-= multiply a 16/16 bit, 2's complement fixed point number by a 16 bit
-= fraction, passed as a signed magnitude 32 bit number
-=
-========================
-*/
-
-#pragma warn -rvl			// I stick the return value in with ASMs
-
-s32int FixedByFrac (s32int a, s32int b)
-{
-//
-// setup
-//
-asm	mov	si,[WORD PTR b+2]	// sign of result = sign of fraction
-
-asm	mov	ax,[WORD PTR a]
-asm	mov	cx,[WORD PTR a+2]
-
-asm	or	cx,cx
-asm	jns	aok:				// negative?
-asm	neg	cx
-asm	neg	ax
-asm	sbb	cx,0
-asm	xor	si,0x8000			// toggle sign of result
-aok:
-
-//
-// multiply  cx:ax by bx
-//
-asm	mov	bx,[WORD PTR b]
-asm	mul	bx					// fraction*fraction
-asm	mov	di,dx				// di is low word of result
-asm	mov	ax,cx				//
-asm	mul	bx					// units*fraction
-asm add	ax,di
-asm	adc	dx,0
-
-//
-// put result dx:ax in 2's complement
-//
-asm	test	si,0x8000		// is the result negative?
-asm	jz	ansok:
-asm	neg	dx
-asm	neg	ax
-asm	sbb	dx,0
-
-ansok:;
-
-}
-
-#pragma warn +rvl
-
-//==========================================================================
-
-/*
-========================
-=
-= TransformActor
-=
-= Takes paramaters:
-=   gx,gy		: globalx/globaly of point
-=
-= globals:
-=   viewx,viewy		: point of view
-=   viewcos,viewsin	: sin/cos of viewangle
-=   scale		: conversion from global value to screen value
-=
-= sets:
-=   screenx,transx,transy,screenheight: projected edge location and size
-=
-========================
-*/
-
-
-//
-// transform actor
-//
-void TransformActor (objtype *ob)
-{
-	s16int ratio;
-	s32int gx,gy,gxt,gyt,nx,ny;
-	s32int	temp;
-
-//
-// translate point to view centered coordinates
-//
-	gx = ob->x-viewx;
-	gy = ob->y-viewy;
-
-//
-// calculate newx
-//
-	gxt = FixedByFrac(gx,viewcos);
-	gyt = FixedByFrac(gy,viewsin);
-	nx = gxt-gyt-ACTORSIZE;		// fudge the shape forward a bit, because
-								// the midpoint could put parts of the shape
-								// into an adjacent wall
-
-//
-// calculate newy
-//
-	gxt = FixedByFrac(gx,viewsin);
-	gyt = FixedByFrac(gy,viewcos);
-	ny = gyt+gxt;
-
-//
-// calculate perspective ratio
-//
-	ob->transx = nx;
-	ob->transy = ny;
-
-	if (nx<mindist)			// too close, don't overflow the divide
-	{
-	  ob->viewheight = 0;
-	  return;
-	}
-
-	ob->viewx = centerx + ny*scale/nx;	// DEBUG: use assembly divide
-
-//
-// calculate height (heightnumerator/(nx>>8))
-//
-	asm	mov	ax,[WORD PTR heightnumerator]
-	asm	mov	dx,[WORD PTR heightnumerator+2]
-	asm	idiv	[WORD PTR nx+1]			// nx>>8
-	asm	mov	[WORD PTR temp],ax
-	asm	mov	[WORD PTR temp+2],dx
-
-	ob->viewheight = temp;
-}
-
-//==========================================================================
-
-/*
-========================
-=
-= TransformTile
-=
-= Takes paramaters:
-=   tx,ty		: tile the object is centered in
-=
-= globals:
-=   viewx,viewy		: point of view
-=   viewcos,viewsin	: sin/cos of viewangle
-=   scale		: conversion from global value to screen value
-=
-= sets:
-=   screenx,transx,transy,screenheight: projected edge location and size
-=
-= Returns true if the tile is withing getting distance
-=
-========================
-*/
-
-int TransformTile (s16int tx, s16int ty, s16int *dispx, s16int *dispheight)
-{
-	s16int ratio;
-	s32int gx,gy,gxt,gyt,nx,ny;
-	s32int	temp;
-
-//
-// translate point to view centered coordinates
-//
-	gx = ((s32int)tx<<TILESHIFT)+0x8000-viewx;
-	gy = ((s32int)ty<<TILESHIFT)+0x8000-viewy;
-
-//
-// calculate newx
-//
-	gxt = FixedByFrac(gx,viewcos);
-	gyt = FixedByFrac(gy,viewsin);
-	nx = gxt-gyt-0x2000;		// 0x2000 is size of object
-
-//
-// calculate newy
-//
-	gxt = FixedByFrac(gx,viewsin);
-	gyt = FixedByFrac(gy,viewcos);
-	ny = gyt+gxt;
-
-
-//
-// calculate perspective ratio
-//
-	if (nx<mindist)			// too close, don't overflow the divide
-	{
-		*dispheight = 0;
-		return false;
-	}
-
-	*dispx = centerx + ny*scale/nx;	// DEBUG: use assembly divide
-
-//
-// calculate height (heightnumerator/(nx>>8))
-//
-	asm	mov	ax,[WORD PTR heightnumerator]
-	asm	mov	dx,[WORD PTR heightnumerator+2]
-	asm	idiv	[WORD PTR nx+1]			// nx>>8
-	asm	mov	[WORD PTR temp],ax
-	asm	mov	[WORD PTR temp+2],dx
-
-	*dispheight = temp;
-
-//
-// see if it should be grabbed
-//
-	if (nx<TILEGLOBAL && ny>-TILEGLOBAL/2 && ny<TILEGLOBAL/2)
-		return true;
-	else
-		return false;
-}
-
-//==========================================================================
-
-/*
-====================
-=
-= CalcHeight
-=
-= Calculates the height of xintercept,yintercept from viewx,viewy
-=
-====================
-*/
-
-#pragma warn -rvl			// I stick the return value in with ASMs
-
-s16int	CalcHeight (void)
-{
-	s16int	transheight;
-	s16int ratio;
-	s32int gxt,gyt,nx,ny;
-	s32int	gx,gy;
-
-	gx = xintercept-viewx;
-	gxt = FixedByFrac(gx,viewcos);
-
-	gy = yintercept-viewy;
-	gyt = FixedByFrac(gy,viewsin);
-
-	nx = gxt-gyt;
-
-  //
-  // calculate perspective ratio (heightnumerator/(nx>>8))
-  //
-	if (nx<mindist)
-		nx=mindist;			// don't let divide overflow
-
-	asm	mov	ax,[WORD PTR heightnumerator]
-	asm	mov	dx,[WORD PTR heightnumerator+2]
-	asm	idiv	[WORD PTR nx+1]			// nx>>8
-}
-
-
-//==========================================================================
-
-/*
-===================
-=
-= ScalePost
-=
-===================
-*/
-
-s32int		postsource;
-u16int	postx;
-u16int	postwidth;
-
-void	near ScalePost (void)		// VGA version
-{
-	asm	mov	ax,SCREENSEG
-	asm	mov	es,ax
-
-	asm	mov	bx,[postx]
-	asm	shl	bx,1
-	asm	mov	bp,WORD PTR [wallheight+bx]		// fractional height (low 3 bits frac)
-	asm	and	bp,0xfff8				// bp = heightscaler*4
-	asm	shr	bp,1
-	asm	cmp	bp,[maxscaleshl2]
-	asm	jle	heightok
-	asm	mov	bp,[maxscaleshl2]
-heightok:
-	asm	add	bp,OFFSET fullscalefarcall
-	//
-	// scale a byte wide strip of wall
-	//
-	asm	mov	bx,[postx]
-	asm	mov	di,bx
-	asm	shr	di,2						// X in bytes
-	asm	add	di,[bufferofs]
-
-	asm	and	bx,3
-	asm	shl	bx,3						// bx = pixel*8+pixwidth
-	asm	add	bx,[postwidth]
-
-	asm	mov	al,BYTE PTR [mapmasks1-1+bx]	// -1 because no widths of 0
-	asm	mov	dx,SC_INDEX+1
-	asm	out	dx,al						// set bit mask register
-	asm	lds	si,DWORD PTR [postsource]
-	asm	call DWORD PTR [bp]				// scale the line of pixels
-
-	asm	mov	al,BYTE PTR [ss:mapmasks2-1+bx]   // -1 because no widths of 0
-	asm	or	al,al
-	asm	jz	nomore
-
-	//
-	// draw a second byte for vertical strips that cross two bytes
-	//
-	asm	inc	di
-	asm	out	dx,al						// set bit mask register
-	asm	call DWORD PTR [bp]				// scale the line of pixels
-
-	asm	mov	al,BYTE PTR [ss:mapmasks3-1+bx]	// -1 because no widths of 0
-	asm	or	al,al
-	asm	jz	nomore
-	//
-	// draw a third byte for vertical strips that cross three bytes
-	//
-	asm	inc	di
-	asm	out	dx,al						// set bit mask register
-	asm	call DWORD PTR [bp]				// scale the line of pixels
-
-
-nomore:
-	asm	mov	ax,ss
-	asm	mov	ds,ax
-}
-
-void  FarScalePost (void)				// just so other files can call
-{
-	ScalePost ();
-}
-
-
-/*
-====================
-=
-= HitVertWall
-=
-= tilehit bit 7 is 0, because it's not a door tile
-= if bit 6 is 1 and the adjacent tile is a door tile, use door side pic
-=
-====================
-*/
-
-void HitVertWall (void)
-{
-	s16int			wallpic;
-	u16int	texture;
-
-	texture = (yintercept>>4)&0xfc0;
-	if (xtilestep == -1)
-	{
-		texture = 0xfc0-texture;
-		xintercept += TILEGLOBAL;
-	}
-	wallheight[pixx] = CalcHeight();
-
-	if (lastside==1 && lastintercept == xtile && lasttilehit == tilehit)
-	{
-		// in the same wall type as last time, so check for optimized draw
-		if (texture == (u16int)postsource)
-		{
-		// wide scale
-			postwidth++;
-			wallheight[pixx] = wallheight[pixx-1];
-			return;
-		}
-		else
-		{
-			ScalePost ();
-			(u16int)postsource = texture;
-			postwidth = 1;
-			postx = pixx;
-		}
-	}
-	else
-	{
-	// new wall
-		if (lastside != -1)				// if not the first scaled post
-			ScalePost ();
-
-		lastside = true;
-		lastintercept = xtile;
-
-		lasttilehit = tilehit;
-		postx = pixx;
-		postwidth = 1;
-
-		if (tilehit & 0x40)
-		{								// check for adjacent doors
-			ytile = yintercept>>TILESHIFT;
-			if ( tilemap[xtile-xtilestep][ytile]&0x80 )
-				wallpic = DOORWALL+3;
-			else
-				wallpic = vertwall[tilehit & ~0x40];
-		}
-		else
-			wallpic = vertwall[tilehit];
-
-		*( ((u16int *)&postsource)+1) = (u16int)PM_GetPage(wallpic);
-		(u16int)postsource = texture;
-
-	}
-}
-
-
-/*
-====================
-=
-= HitHorizWall
-=
-= tilehit bit 7 is 0, because it's not a door tile
-= if bit 6 is 1 and the adjacent tile is a door tile, use door side pic
-=
-====================
-*/
-
-void HitHorizWall (void)
-{
-	s16int			wallpic;
-	u16int	texture;
-
-	texture = (xintercept>>4)&0xfc0;
-	if (ytilestep == -1)
-		yintercept += TILEGLOBAL;
-	else
-		texture = 0xfc0-texture;
-	wallheight[pixx] = CalcHeight();
-
-	if (lastside==0 && lastintercept == ytile && lasttilehit == tilehit)
-	{
-		// in the same wall type as last time, so check for optimized draw
-		if (texture == (u16int)postsource)
-		{
-		// wide scale
-			postwidth++;
-			wallheight[pixx] = wallheight[pixx-1];
-			return;
-		}
-		else
-		{
-			ScalePost ();
-			(u16int)postsource = texture;
-			postwidth = 1;
-			postx = pixx;
-		}
-	}
-	else
-	{
-	// new wall
-		if (lastside != -1)				// if not the first scaled post
-			ScalePost ();
-
-		lastside = 0;
-		lastintercept = ytile;
-
-		lasttilehit = tilehit;
-		postx = pixx;
-		postwidth = 1;
-
-		if (tilehit & 0x40)
-		{								// check for adjacent doors
-			xtile = xintercept>>TILESHIFT;
-			if ( tilemap[xtile][ytile-ytilestep]&0x80 )
-				wallpic = DOORWALL+2;
-			else
-				wallpic = horizwall[tilehit & ~0x40];
-		}
-		else
-			wallpic = horizwall[tilehit];
-
-		*( ((u16int *)&postsource)+1) = (u16int)PM_GetPage(wallpic);
-		(u16int)postsource = texture;
-	}
-
-}
-
-//==========================================================================
-
-/*
-====================
-=
-= HitHorizDoor
-=
-====================
-*/
-
-void HitHorizDoor (void)
-{
-	u16int	texture,doorpage,doornum;
-
-	doornum = tilehit&0x7f;
-	texture = ( (xintercept-doorposition[doornum]) >> 4) &0xfc0;
-
-	wallheight[pixx] = CalcHeight();
-
-	if (lasttilehit == tilehit)
-	{
-	// in the same door as last time, so check for optimized draw
-		if (texture == (u16int)postsource)
-		{
-		// wide scale
-			postwidth++;
-			wallheight[pixx] = wallheight[pixx-1];
-			return;
-		}
-		else
-		{
-			ScalePost ();
-			(u16int)postsource = texture;
-			postwidth = 1;
-			postx = pixx;
-		}
-	}
-	else
-	{
-		if (lastside != -1)				// if not the first scaled post
-			ScalePost ();			// draw last post
-	// first pixel in this door
-		lastside = 2;
-		lasttilehit = tilehit;
-		postx = pixx;
-		postwidth = 1;
-
-		switch (doorobjlist[doornum].lock)
-		{
-		case dr_normal:
-			doorpage = DOORWALL;
-			break;
-		case dr_lock1:
-		case dr_lock2:
-		case dr_lock3:
-		case dr_lock4:
-			doorpage = DOORWALL+6;
-			break;
-		case dr_elevator:
-			doorpage = DOORWALL+4;
-			break;
-		}
-
-		*( ((u16int *)&postsource)+1) = (u16int)PM_GetPage(doorpage);
-		(u16int)postsource = texture;
-	}
-}
-
-//==========================================================================
-
-/*
-====================
-=
-= HitVertDoor
-=
-====================
-*/
-
-void HitVertDoor (void)
-{
-	u16int	texture,doorpage,doornum;
-
-	doornum = tilehit&0x7f;
-	texture = ( (yintercept-doorposition[doornum]) >> 4) &0xfc0;
-
-	wallheight[pixx] = CalcHeight();
-
-	if (lasttilehit == tilehit)
-	{
-	// in the same door as last time, so check for optimized draw
-		if (texture == (u16int)postsource)
-		{
-		// wide scale
-			postwidth++;
-			wallheight[pixx] = wallheight[pixx-1];
-			return;
-		}
-		else
-		{
-			ScalePost ();
-			(u16int)postsource = texture;
-			postwidth = 1;
-			postx = pixx;
-		}
-	}
-	else
-	{
-		if (lastside != -1)				// if not the first scaled post
-			ScalePost ();			// draw last post
-	// first pixel in this door
-		lastside = 2;
-		lasttilehit = tilehit;
-		postx = pixx;
-		postwidth = 1;
-
-		switch (doorobjlist[doornum].lock)
-		{
-		case dr_normal:
-			doorpage = DOORWALL;
-			break;
-		case dr_lock1:
-		case dr_lock2:
-		case dr_lock3:
-		case dr_lock4:
-			doorpage = DOORWALL+6;
-			break;
-		case dr_elevator:
-			doorpage = DOORWALL+4;
-			break;
-		}
-
-		*( ((u16int *)&postsource)+1) = (u16int)PM_GetPage(doorpage+1);
-		(u16int)postsource = texture;
-	}
-}
-
-//==========================================================================
-
-
-/*
-====================
-=
-= HitHorizPWall
-=
-= A pushable wall in action has been hit
-=
-====================
-*/
-
-void HitHorizPWall (void)
-{
-	s16int			wallpic;
-	u16int	texture,offset;
-
-	texture = (xintercept>>4)&0xfc0;
-	offset = pwallpos<<10;
-	if (ytilestep == -1)
-		yintercept += TILEGLOBAL-offset;
-	else
-	{
-		texture = 0xfc0-texture;
-		yintercept += offset;
-	}
-
-	wallheight[pixx] = CalcHeight();
-
-	if (lasttilehit == tilehit)
-	{
-		// in the same wall type as last time, so check for optimized draw
-		if (texture == (u16int)postsource)
-		{
-		// wide scale
-			postwidth++;
-			wallheight[pixx] = wallheight[pixx-1];
-			return;
-		}
-		else
-		{
-			ScalePost ();
-			(u16int)postsource = texture;
-			postwidth = 1;
-			postx = pixx;
-		}
-	}
-	else
-	{
-	// new wall
-		if (lastside != -1)				// if not the first scaled post
-			ScalePost ();
-
-		lasttilehit = tilehit;
-		postx = pixx;
-		postwidth = 1;
-
-		wallpic = horizwall[tilehit&63];
-
-		*( ((u16int *)&postsource)+1) = (u16int)PM_GetPage(wallpic);
-		(u16int)postsource = texture;
-	}
-
-}
-
-
-/*
-====================
-=
-= HitVertPWall
-=
-= A pushable wall in action has been hit
-=
-====================
-*/
-
-void HitVertPWall (void)
-{
-	s16int			wallpic;
-	u16int	texture,offset;
-
-	texture = (yintercept>>4)&0xfc0;
-	offset = pwallpos<<10;
-	if (xtilestep == -1)
-	{
-		xintercept += TILEGLOBAL-offset;
-		texture = 0xfc0-texture;
-	}
-	else
-		xintercept += offset;
-
-	wallheight[pixx] = CalcHeight();
-
-	if (lasttilehit == tilehit)
-	{
-		// in the same wall type as last time, so check for optimized draw
-		if (texture == (u16int)postsource)
-		{
-		// wide scale
-			postwidth++;
-			wallheight[pixx] = wallheight[pixx-1];
-			return;
-		}
-		else
-		{
-			ScalePost ();
-			(u16int)postsource = texture;
-			postwidth = 1;
-			postx = pixx;
-		}
-	}
-	else
-	{
-	// new wall
-		if (lastside != -1)				// if not the first scaled post
-			ScalePost ();
-
-		lasttilehit = tilehit;
-		postx = pixx;
-		postwidth = 1;
-
-		wallpic = vertwall[tilehit&63];
-
-		*( ((u16int *)&postsource)+1) = (u16int)PM_GetPage(wallpic);
-		(u16int)postsource = texture;
-	}
-
-}
-
-//==========================================================================
-
-//==========================================================================
-
-#if 0
-/*
-=====================
-=
-= ClearScreen
-=
-=====================
-*/
-
-void ClearScreen (void)
-{
- u16int floor=egaFloor[gamestate.episode*10+mapon],
-	  ceiling=egaCeiling[gamestate.episode*10+mapon];
-
-  //
-  // clear the screen
-  //
-asm	mov	dx,GC_INDEX
-asm	mov	ax,GC_MODE + 256*2		// read mode 0, write mode 2
-asm	out	dx,ax
-asm	mov	ax,GC_BITMASK + 255*256
-asm	out	dx,ax
-
-asm	mov	dx,40
-asm	mov	ax,[viewwidth]
-asm	shr	ax,3
-asm	sub	dx,ax					// dx = 40-viewwidth/8
-
-asm	mov	bx,[viewwidth]
-asm	shr	bx,4					// bl = viewwidth/16
-asm	mov	bh,BYTE PTR [viewheight]
-asm	shr	bh,1					// half height
-
-asm	mov	ax,[ceiling]
-asm	mov	es,[screenseg]
-asm	mov	di,[bufferofs]
-
-toploop:
-asm	mov	cl,bl
-asm	rep	stosw
-asm	add	di,dx
-asm	dec	bh
-asm	jnz	toploop
-
-asm	mov	bh,BYTE PTR [viewheight]
-asm	shr	bh,1					// half height
-asm	mov	ax,[floor]
-
-bottomloop:
-asm	mov	cl,bl
-asm	rep	stosw
-asm	add	di,dx
-asm	dec	bh
-asm	jnz	bottomloop
-
-
-asm	mov	dx,GC_INDEX
-asm	mov	ax,GC_MODE + 256*10		// read mode 1, write mode 2
-asm	out	dx,ax
-asm	mov	al,GC_BITMASK
-asm	out	dx,al
-
-}
-#endif
-//==========================================================================
-
-u16int vgaCeiling[]=
-{
-#ifndef SPEAR
- 0x1d1d,0x1d1d,0x1d1d,0x1d1d,0x1d1d,0x1d1d,0x1d1d,0x1d1d,0x1d1d,0xbfbf,
- 0x4e4e,0x4e4e,0x4e4e,0x1d1d,0x8d8d,0x4e4e,0x1d1d,0x2d2d,0x1d1d,0x8d8d,
- 0x1d1d,0x1d1d,0x1d1d,0x1d1d,0x1d1d,0x2d2d,0xdddd,0x1d1d,0x1d1d,0x9898,
-
- 0x1d1d,0x9d9d,0x2d2d,0xdddd,0xdddd,0x9d9d,0x2d2d,0x4d4d,0x1d1d,0xdddd,
- 0x7d7d,0x1d1d,0x2d2d,0x2d2d,0xdddd,0xd7d7,0x1d1d,0x1d1d,0x1d1d,0x2d2d,
- 0x1d1d,0x1d1d,0x1d1d,0x1d1d,0xdddd,0xdddd,0x7d7d,0xdddd,0xdddd,0xdddd
-#else
- 0x6f6f,0x4f4f,0x1d1d,0xdede,0xdfdf,0x2e2e,0x7f7f,0x9e9e,0xaeae,0x7f7f,
- 0x1d1d,0xdede,0xdfdf,0xdede,0xdfdf,0xdede,0xe1e1,0xdcdc,0x2e2e,0x1d1d,0xdcdc
-#endif
-};
-
-/*
-=====================
-=
-= VGAClearScreen
-=
-=====================
-*/
-
-void VGAClearScreen (void)
-{
- u16int ceiling=vgaCeiling[gamestate.episode*10+mapon];
-
-  //
-  // clear the screen
-  //
-asm	mov	dx,SC_INDEX
-asm	mov	ax,SC_MAPMASK+15*256	// write through all planes
-asm	out	dx,ax
-
-asm	mov	dx,80
-asm	mov	ax,[viewwidth]
-asm	shr	ax,2
-asm	sub	dx,ax					// dx = 40-viewwidth/2
-
-asm	mov	bx,[viewwidth]
-asm	shr	bx,3					// bl = viewwidth/8
-asm	mov	bh,BYTE PTR [viewheight]
-asm	shr	bh,1					// half height
-
-asm	mov	es,[screenseg]
-asm	mov	di,[bufferofs]
-asm	mov	ax,[ceiling]
-
-toploop:
-asm	mov	cl,bl
-asm	rep	stosw
-asm	add	di,dx
-asm	dec	bh
-asm	jnz	toploop
-
-asm	mov	bh,BYTE PTR [viewheight]
-asm	shr	bh,1					// half height
-asm	mov	ax,0x1919
-
-bottomloop:
-asm	mov	cl,bl
-asm	rep	stosw
-asm	add	di,dx
-asm	dec	bh
-asm	jnz	bottomloop
-}
-
-//==========================================================================
-
-/*
-=====================
-=
-= CalcRotate
-=
-=====================
-*/
-
-s16int	CalcRotate (objtype *ob)
-{
-	s16int	angle,viewangle;
-
-	// this isn't exactly correct, as it should vary by a trig value,
-	// but it is close enough with only eight rotations
-
-	viewangle = player->angle + (centerx - ob->viewx)/8;
-
-	if (ob->obclass == rocketobj || ob->obclass == hrocketobj)
-		angle =  (viewangle-180)- ob->angle;
-	else
-		angle =  (viewangle-180)- dirangle[ob->dir];
-
-	angle+=ANGLES/16;
-	while (angle>=ANGLES)
-		angle-=ANGLES;
-	while (angle<0)
-		angle+=ANGLES;
-
-	if (ob->state->rotate == 2)             // 2 rotation pain frame
-		return 4*(angle/(ANGLES/2));        // seperated by 3 (art layout...)
-
-	return angle/(ANGLES/8);
-}
-
-
-/*
-=====================
-=
-= DrawScaleds
-=
-= Draws all objects that are visable
-=
-=====================
-*/
-
-#define MAXVISABLE	50
-
-typedef struct
-{
-	s16int	viewx,
-		viewheight,
-		shapenum;
-} visobj_t;
-
-visobj_t	vislist[MAXVISABLE],*visptr,*visstep,*farthest;
-
-void DrawScaleds (void)
-{
-	s16int 		i,j,least,numvisable,height;
-	uchar *shape;
-	u8int		*tilespot,*visspot;
-	s16int			shapenum;
-	u16int	spotloc;
-
-	statobj_t	*statptr;
-	objtype		*obj;
-
-	visptr = &vislist[0];
-
-//
-// place static objects
-//
-	for (statptr = &statobjlist[0] ; statptr !=laststatobj ; statptr++)
-	{
-		if ((visptr->shapenum = statptr->shapenum) == -1)
-			continue;						// object has been deleted
-
-		if (!*statptr->visspot)
-			continue;						// not visable
-
-		if (TransformTile (statptr->tilex,statptr->tiley
-			,&visptr->viewx,&visptr->viewheight) && statptr->flags & FL_BONUS)
-		{
-			GetBonus (statptr);
-			continue;
-		}
-
-		if (!visptr->viewheight)
-			continue;						// to close to the object
-
-		if (visptr < &vislist[MAXVISABLE-1])	// don't let it overflow
-			visptr++;
-	}
-
-//
-// place active objects
-//
-	for (obj = player->next;obj;obj=obj->next)
-	{
-		if (!(visptr->shapenum = obj->state->shapenum))
-			continue;						// no shape
-
-		spotloc = (obj->tilex<<6)+obj->tiley;	// optimize: keep in struct?
-		visspot = &spotvis[0][0]+spotloc;
-		tilespot = &tilemap[0][0]+spotloc;
-
-		//
-		// could be in any of the nine surrounding tiles
-		//
-		if (*visspot
-		|| ( *(visspot-1) && !*(tilespot-1) )
-		|| ( *(visspot+1) && !*(tilespot+1) )
-		|| ( *(visspot-65) && !*(tilespot-65) )
-		|| ( *(visspot-64) && !*(tilespot-64) )
-		|| ( *(visspot-63) && !*(tilespot-63) )
-		|| ( *(visspot+65) && !*(tilespot+65) )
-		|| ( *(visspot+64) && !*(tilespot+64) )
-		|| ( *(visspot+63) && !*(tilespot+63) ) )
-		{
-			obj->active = true;
-			TransformActor (obj);
-			if (!obj->viewheight)
-				continue;						// too close or far away
-
-			visptr->viewx = obj->viewx;
-			visptr->viewheight = obj->viewheight;
-			if (visptr->shapenum == -1)
-				visptr->shapenum = obj->temp1;	// special shape
-
-			if (obj->state->rotate)
-				visptr->shapenum += CalcRotate (obj);
-
-			if (visptr < &vislist[MAXVISABLE-1])	// don't let it overflow
-				visptr++;
-			obj->flags |= FL_VISABLE;
-		}
-		else
-			obj->flags &= ~FL_VISABLE;
-	}
-
-//
-// draw from back to front
-//
-	numvisable = visptr-&vislist[0];
-
-	if (!numvisable)
-		return;									// no visable objects
-
-	for (i = 0; i<numvisable; i++)
-	{
-		least = 32000;
-		for (visstep=&vislist[0] ; visstep<visptr ; visstep++)
-		{
-			height = visstep->viewheight;
-			if (height < least)
-			{
-				least = height;
-				farthest = visstep;
-			}
-		}
-		//
-		// draw farthest
-		//
-		ScaleShape(farthest->viewx,farthest->shapenum,farthest->viewheight);
-
-		farthest->viewheight = 32000;
-	}
-
-}
-
-//==========================================================================
-
-/*
-==============
-=
-= DrawPlayerWeapon
-=
-= Draw the player's hands
-=
-==============
-*/
-
-s16int	weaponscale[NUMWEAPONS] = {SPR_KNIFEREADY,SPR_PISTOLREADY
-	,SPR_MACHINEGUNREADY,SPR_CHAINREADY};
-
-void DrawPlayerWeapon (void)
-{
-	s16int	shapenum;
-
-#ifndef SPEAR
-	if (gamestate.victoryflag)
-	{
-		if (player->state == &s_deathcam && (TimeCount&32) )
-			SimpleScaleShape(viewwidth/2,SPR_DEATHCAM,viewheight+1);
-		return;
-	}
-#endif
-
-	if (gamestate.weapon != -1)
-	{
-		shapenum = weaponscale[gamestate.weapon]+gamestate.weaponframe;
-		SimpleScaleShape(viewwidth/2,shapenum,viewheight+1);
-	}
-
-	if (demorecord || demoplayback)
-		SimpleScaleShape(viewwidth/2,SPR_DEMO,viewheight+1);
-}
-
-
-//==========================================================================
-
-
-/*
-=====================
-=
-= CalcTics
-=
-=====================
-*/
-
-void CalcTics (void)
-{
-	s32int	newtime,oldtimecount;
-
-//
-// calculate tics since last refresh for adaptive timing
-//
-	if (lasttimecount > TimeCount)
-		TimeCount = lasttimecount;		// if the game was paused a LONG time
-
-	do
-	{
-		newtime = TimeCount;
-		tics = newtime-lasttimecount;
-	} while (!tics);			// make sure at least one tic passes
-
-	lasttimecount = newtime;
-
-	if (tics>MAXTICS)
-	{
-		TimeCount -= (tics-MAXTICS);
-		tics = MAXTICS;
-	}
-}
-
-
-//==========================================================================
-
-
-/*
-========================
-=
-= FixOfs
-=
-========================
-*/
-
-void	FixOfs (void)
-{
-	VW_ScreenToScreen (displayofs,bufferofs,viewwidth/8,viewheight);
-}
-
-
-//==========================================================================
-
-
-/*
-====================
-=
-= WallRefresh
-=
-====================
-*/
-
-void WallRefresh (void)
-{
-//
-// set up variables for this view
-//
-	viewangle = player->angle;
-	midangle = viewangle*(FINEANGLES/ANGLES);
-	viewsin = sintable[viewangle];
-	viewcos = costable[viewangle];
-	viewx = player->x - FixedByFrac(focallength,viewcos);
-	viewy = player->y + FixedByFrac(focallength,viewsin);
-
-	focaltx = viewx>>TILESHIFT;
-	focalty = viewy>>TILESHIFT;
-
-	viewtx = player->x >> TILESHIFT;
-	viewty = player->y >> TILESHIFT;
-
-	xpartialdown = viewx&(TILEGLOBAL-1);
-	xpartialup = TILEGLOBAL-xpartialdown;
-	ypartialdown = viewy&(TILEGLOBAL-1);
-	ypartialup = TILEGLOBAL-ypartialdown;
-
-	lastside = -1;			// the first pixel is on a new wall
-	AsmRefresh ();
-	ScalePost ();			// no more optimization on last post
-}
-
-//==========================================================================
-
-/*
-========================
-=
-= ThreeDRefresh
-=
-========================
-*/
-
-void	ThreeDRefresh (void)
-{
-	s16int tracedir;
-
-// this wouldn't need to be done except for my debugger/video wierdness
-	outportb (SC_INDEX,SC_MAPMASK);
-
-//
-// clear out the traced array
-//
-asm	mov	ax,ds
-asm	mov	es,ax
-asm	mov	di,OFFSET spotvis
-asm	xor	ax,ax
-asm	mov	cx,2048							// 64*64 / 2
-asm	rep stosw
-
-	bufferofs += screenofs;
-
-//
-// follow the walls from there to the right, drawwing as we go
-//
-	VGAClearScreen ();
-
-	WallRefresh ();
-
-//
-// draw all the scaled images
-//
-	DrawScaleds();			// draw scaled stuff
-	DrawPlayerWeapon ();	// draw player's hands
-
-//
-// show screen and time last cycle
-//
-	if (fizzlein)
-	{
-		FizzleFade(bufferofs,displayofs+screenofs,viewwidth,viewheight,20,false);
-		fizzlein = false;
-
-		lasttimecount = TimeCount = 0;		// don't make a big tic count
-
-	}
-
-	bufferofs -= screenofs;
-	displayofs = bufferofs;
-
-	asm	cli
-	asm	mov	cx,[displayofs]
-	asm	mov	dx,3d4h		// CRTC address register
-	asm	mov	al,0ch		// start address high register
-	asm	out	dx,al
-	asm	inc	dx
-	asm	mov	al,ch
-	asm	out	dx,al   	// set the high byte
-	asm	sti
-
-	bufferofs += SCREENSIZE;
-	if (bufferofs > PAGE3START)
-		bufferofs = PAGE1START;
-
-	frameon++;
-	PM_NextFrame();
-}
-
-
-//===========================================================================
-
--- /dev/null
+++ b/drw.c
@@ -1,0 +1,413 @@
+#include <u.h>
+#include <libc.h>
+#include "dat.h"
+#include "fns.h"
+
+Fnt fnts[2], *fnt;
+Pic *pics;
+uchar **exts, **dems, **epis;
+Dat *wals, *sprs;
+
+int scale, npx;
+uchar *px, pxb[Va], fzb[Vw*Vhud];
+View vw;
+
+static Col *fcol;
+static u32int *fref;
+static int fi, fo, fdt;
+static uchar *fzd;
+static int fzc, fzdx, fzdy, fzdn, fzn, fzout;
+
+static uchar wl6ceil[] = {
+	0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0xbf,
+	0x4e, 0x4e, 0x4e, 0x1d, 0x8d, 0x4e, 0x1d, 0x2d, 0x1d, 0x8d,
+	0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x2d, 0xdd, 0x1d, 0x1d, 0x98,
+	0x1d, 0x9d, 0x2d, 0xdd, 0xdd, 0x9d, 0x2d, 0x4d, 0x1d, 0xdd,
+	0x7d, 0x1d, 0x2d, 0x2d, 0xdd, 0xd7, 0x1d, 0x1d, 0x1d, 0x2d,
+	0x1d, 0x1d, 0x1d, 0x1d, 0xdd, 0xdd, 0x7d, 0xdd, 0xdd, 0xdd,
+};
+static uchar sodceil[] = {
+	0x6f, 0x4f, 0x1d, 0xde, 0xdf, 0x2e, 0x7f, 0x9e, 0xae, 0x7f,
+	0x1d, 0xde, 0xdf, 0xde, 0xdf, 0xde, 0xe1, 0xdc, 0x2e, 0x1d, 0xdc
+};
+
+static void
+hudnp(int x, int y, int dx, int n)
+{
+	char s[20], *p;
+
+	memset(s, 0, sizeof s);
+	p = s;
+	if(n == 0)
+		p++;
+	while(n > 0 && p < s + sizeof s)
+		*p++ = n % 10, n /= 10;
+	n = dx - (p - s);
+	if(n > 0)
+		memset(p, -1, n);	/* Pblank == Pn0 - 1, always */
+	p += n - 1;
+	while(p >= s){
+		pic(x, y, pict[Pn0] + *p--);
+		x += 8;
+	}
+}
+
+void
+fizz(void)
+{
+	int i, x, y, ofs;
+
+	for(i=0; i<fzdn*Δtc; i++){
+		y = fzn - 1 & 0xff;
+		x = fzn >> 8;
+		fzn = fzn >> 1 ^ (fzn & 1 ? 0x12000 : 0);
+		if(x >= fzdx || y >= fzdy)
+			continue;
+		ofs = y * Vw + x;
+		fzd[ofs] = fzout ? fzc : fzb[ofs];
+		if(fzn == 1){
+			fzdn = 0;
+			break;
+		}
+	}
+	out();
+}
+
+void
+fizzop(int c, int save)
+{
+	if(save)
+		memcpy(fzb, pxb + vw.ofs, (vw.dy-1) * Vw + vw.dx-1);
+	if(c < 0){
+		fzd = pxb + vw.ofs;
+		fzdx = vw.dx;
+		fzdy = vw.dy;
+		fzdn = Va / 20;
+		fzout = 0;
+	}else{
+		fzd = pxb;
+		fzdx = Vw;
+		fzdy = Vhud;
+		fzdn = Va / 70;
+		fzout = 1;
+		fzc = c;
+	}
+	fzn = 1;
+}
+
+void
+fadeout(void)
+{
+	int i, u, v, w;
+	u32int p, *s, *d;
+
+	i = fo + Δtc;
+	if(i > fdt)
+		i = fdt;
+	fo = i;
+	s = fref;
+	d = pal;
+	while(d < pal + nelem(pals[0])){
+		p = *s++;
+		u = p & 0xff;
+		v = p>>8 & 0xff;
+		w = p>>16 & 0xff;
+		u = u + (fcol->b-u) * i/fdt;
+		v = v + (fcol->g-v) * i/fdt;
+		w = w + (fcol->r-w) * i/fdt;
+		*d++ = w<<16 | v<<8 | u;
+	}
+	out();
+}
+
+void
+fadein(void)
+{
+	int i, u, v, w;
+	u32int p, *s, *d;
+
+	i = fi + Δtc;
+	if(i > fdt)
+		i = fdt;
+	fi = i;
+	s = fref;
+	d = pal;
+	while(d < pal + nelem(pals[0])){
+		p = *s++;
+		u = p & 0xff;
+		v = p>>8 & 0xff;
+		w = p>>16 & 0xff;
+		u = fcol->b + (u-fcol->b) * i/fdt;
+		v = fcol->g + (v-fcol->g) * i/fdt;
+		w = fcol->r + (w-fcol->r) * i/fdt;
+		*d++ = w<<16 | v<<8 | u;
+	}
+	out();
+}
+
+void
+fadeop(Col *c, int dt)
+{
+	fi = 0;
+	fo = 0;
+	fdt = dt;
+	fcol = c;
+	fref = pal;
+	pal = pals[Cfad];
+}
+
+void
+palpic(uchar *s)
+{
+	u32int *p;
+
+	p = pal = pals[Csod];
+	while(p < pals[Csod] + nelem(pals[0])){
+		*p++ = s[0]*255/63<<16 | s[1]*255/63<<8 | s[2]*255/63;
+		s += 3;
+	}
+}
+
+void
+out(void)
+{
+	int n;
+	u32int c;
+	uchar *s, *d, *w;
+
+	d = px;
+	s = pxb;
+	n = scale * 3;
+	while(s < pxb + sizeof pxb){
+		c = pal[*s++];
+		w = d + n;
+		while(d < w){
+			*d++ = c;
+			*d++ = c>>8;
+			*d++ = c>>16;
+		}
+	}
+	flush();
+}
+
+void
+pput(int x, int y, int dx, int dy, uchar *s)
+{
+	uchar *d;
+
+	d = pxb + x + y*Vw;
+	while(dy-- > 0){
+		memcpy(d, s, dx);
+		s += dx;
+		d += Vw;
+	}	
+}
+
+void
+put(int x, int y, int dx, int dy, int c)
+{
+	uchar *d;
+
+	d = pxb + x + y*Vw;
+	while(dy-- > 0){
+		memset(d, c, dx);
+		d += Vw;
+	}	
+}
+
+int
+txt(int x, int y, char *t, int col)
+{
+	int h, w;
+	uchar c, *d, *s, *p, *e, *q;
+
+	h = fnt->h;
+	p = fnt->p;
+	c = *t++;
+	d = pxb + x + y*Vw;
+	x = 0;
+	while(c != 0){
+		w = fnt->w[c];
+		s = p + fnt->ofs[c];
+		e = s + w*h;
+		while(s < e){
+			q = s + w;
+			while(s < q){
+				c = *s++;
+				if(c != 0)
+					*d = col;
+				d++;
+			}
+			d += Vw-w;
+		}
+		d -= Vw*h - w;
+		x += w;
+		c = *t++;
+	}
+	return x;
+}
+
+int
+txtnl(int x, int y, char *t, int col)
+{
+	int n;
+	char *s, *m;
+
+	n = 0;
+	m = strdup(t);
+	if(m == nil)
+		sysfatal("txtnl: %r");
+	s = strtok(m, "\n");
+	while(s != nil){
+		n += txt(x, y, s, col);
+		s = strtok(nil, "\n");
+		y += fnt->h;
+	}
+	free(m);
+	return n;
+}
+
+int
+txth(char *t)
+{
+	int h, n;
+
+	h = fnt->h;
+	n = h;
+	while(*t != 0)
+		if(*t++ == '\n')
+			n += h;
+	return n;
+}
+
+int
+txtw(char *t)
+{
+	int n, m;
+
+	n = m = 0;
+	while(*t != 0){
+		if(*t == '\n'){
+			if(n > m)
+				m = n;
+			n = 0;
+		}else
+			n += fnt->w[(uchar)*t];
+		t++;
+	}
+	return n > m ? n : m;
+}
+
+void
+fill(int c)
+{
+	memset(pxb, c, sizeof pxb);
+}
+
+void
+pic(int x, int y, int n)
+{
+	Pic *p;
+
+	p = pics+n;
+	pput(x, y, p->x, p->y, p->p);
+}
+
+void
+pictxt(int x0, int y, char *t)
+{
+	int p, x, n;
+	char c;
+
+	x = x0;
+	for(;;){
+		c = *t++;
+		n = 16;
+		switch(c){
+		case 0: return;
+		case '\n': y += 16; x = x0 - 16; goto skip;
+		case ' ': goto skip;
+		case '!': p = pict[Pexcl]; n = 8; break;
+		case '\'': p = pict[Papo]; n = 8; break;
+		case ':': p = pict[Pcolon]; n = 8; break;
+		case '%': p = pict[Ppercent]; break;
+		default: p = pict[P0] + c - (c >= 'A' ? 'A'-11 : '0'); break;
+		}
+		pic(x, y, p);
+skip:
+		x += n;
+	}
+}
+
+void
+hudf(void)
+{
+	int p;
+
+	if(gm.hp > 0){
+		p = god ? pict[Pgod] : pict[Pface1] + 3 * (100 - gm.hp >> 4);
+		p += gm.facefrm;
+	}else
+		p = gm.mut ? pict[Pmut] : pict[Pface8];
+	pic(136, 164, p);
+}
+
+void
+hudh(void)
+{
+	hudnp(168, 176, 3, gm.hp);
+}
+
+void
+hudl(void)
+{
+	hudnp(112, 176, 1, gm.lives);
+}
+
+void
+hudm(void)
+{
+	hudnp(16, 176, 2, ver == SOD && gm.map == 20 ? 18 : gm.map+1);
+}
+
+void
+huda(void)
+{
+	hudnp(216, 176, 2, gm.ammo);
+}
+
+void
+hudk(void)
+{
+	pic(240, 164, pict[gm.keys & 1 ? Pgkey : Pnokey]);
+	pic(240, 180, pict[gm.keys & 2 ? Pskey : Pnokey]);
+}
+
+void
+hudw(void)
+{
+	pic(256, 168, pict[Pknife]+gm.w);
+}
+
+void
+hudp(void)
+{
+	hudnp(48, 176, 6, gm.pt);
+}
+
+void
+clear(void)
+{
+	int n;
+	uchar c, *p;
+
+	c = ver < SDM ? wl6ceil[gm.map] : sodceil[gm.map];
+	p = pxb + vw.ofs;
+	n = 0;
+	while(n++ < vw.dy){
+		memset(p, c, vw.dx);
+		p += Vw;
+		if(n == vw.dy/2)
+			c = 0x19;
+	}
+}
--- a/fns.h
+++ b/fns.h
@@ -1,32 +1,67 @@
 void*	emalloc(ulong);
-void*	erealloc(void *, ulong);
+void*	erealloc(void*, ulong);
 void	grab(int);
 void	toss(void);
 void	flush(void);
-void	dat(char *);
-void	out(void);
+char*	demof(char*);
+u16int*	readmap(int);
+void	dat(char*);
+void	fizz(void);
+void	fizzop(int, int);
 void	fadeout(void);
 void	fadein(void);
-void	fadeop(Col *, int);
-void	palpic(uchar *);
-void	put(int, int, int, int, uchar *, int);
-int	txt(int, int, char *, int);
-int	txtnl(int, int, char *, int);
-int	txth(char *);
-int	txtw(char *);
+void	fadeop(Col*, int);
+void	palpic(uchar*);
+void	out(void);
+void	pput(int, int, int, int, uchar*);
+void	put(int, int, int, int, int);
+int	txt(int, int, char*, int);
+int	txtnl(int, int, char*, int);
+int	txth(char*);
+int	txtw(char*);
 void	fill(int);
 void	pic(int, int, int);
+void	pictxt(int, int, char*);
+void	hudf(void);
+void	hudh(void);
+void	hudl(void);
+void	hudm(void);
+void	huda(void);
+void	hudk(void);
+void	hudw(void);
+void	hudp(void);
+void	clear(void);
+s32int	ffs(s32int, s32int);
+void	render(void);
+void	initscal(void);
+void	setvw(int);
+void	tab(void);
+void	gend(void);
 void	mstep(void);
-void	init(void);
+void	init(char*);
+void	drop(Tile*, int);
+void	dropen(Door*);
+void	druse(Door*);
+void	osetglobal(Obj*);
+void	ostate(Obj*, State*);
+Obj*	onew(void);
+Obj*	ospawn(Tile*, State*);
+void	uworld(void);
+void	mapmus(void);
+void	initmap(void);
+void	sodmap(void);
+void	bonus(Static*);
 int	rnd(void);
 void	gstep(void);
-void	dstep(void);
-void	initg(int);
-uchar*	opl2out(uchar *, int);
+void	demo(void);
+void	initg(int, uchar*);
+uchar*	opl2out(uchar*, int);
 void	opl2wr(int, int);
 void	opl2init(int);
 void	sndstep(void);
 void	stopsfx(void);
+int	lastsfx(void);
+void	sfxatt(int, int, int, int);
 void	sfx(int);
 void	stopmus(void);
 void	mus(int);
--- a/fs.c
+++ b/fs.c
@@ -404,52 +404,52 @@
 uchar *pict;
 static uchar picts[4][Pend]={ {
 	3, 15, 8, 10, 11, 24, 27, 34, 35, 23, 7, 12, 13, 14, 36, 16, 21, 25,
-	26, 87, 37, 129, 40, 41, 42, 52, 53,79, 80, 81, 82, 84, 0, 0, 83, 85, 86,
-	0, 0, 88, 92, 93, 94, 95, 96, 106, 127, 128, 0, 0, 0, 130, 131
+	26, 87, 37, 129, 40, 41, 42, 52, 79, 80, 81, 82, 84, 0, 0, 83, 85,
+	86, 0, 0, 88, 92, 93, 94, 95, 96, 106, 127, 128, 0, 0, 0, 130, 131
 	},{
 	14, 27, 20, 22, 23, 36, 39, 46, 47, 35, 19, 24, 25, 26, 48, 28, 33,
-	37, 38, 99, 49, 141, 52, 53, 54, 64, 65, 91, 92, 93, 94, 96, 0, 0, 95,
+	37, 38, 99, 49, 141, 52, 53, 54, 64, 91, 92, 93, 94, 96, 0, 0, 95,
 	97, 98, 0, 0, 100, 104, 105, 106, 107, 108, 118, 139, 140, 0, 0, 0, 142,
 	143
 	},{
 	0, 1, 2, 4, 5, 6, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 22, 24, 25,
-	26, 27, 0, 28, 29, 30, 40, 41, 67, 68, 69, 70, 71, 72, 0, 73, 74, 75, 0,
+	26, 27, 0, 28, 29, 30, 40, 67, 68, 69, 70, 71, 72, 0, 73, 74, 75, 0,
 	0, 76, 80, 81, 82, 83, 84, 94, 115, 116, 117, 120, 122, 123, 124
 	},{
  	0, 1, 2, 4, 5, 6, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 22, 24, 25,
-	26, 27, 28, 33, 34, 35, 45, 46, 72, 73, 74, 75, 76, 77, 78, 87, 88, 89,
+	26, 27, 28, 33, 34, 35, 45, 72, 73, 74, 75, 76, 77, 78, 87, 88, 89,
 	90, 91, 98, 102, 103, 104, 105, 106, 116, 137, 138, 139, 142, 144, 145,
 	146
 	}
 };
 static uchar pcmt[2][46]={ {
-	Sgd, Sdogbark, Sclosedoor, Sopendoor, Smg, Spistol, Sgatling, Sss, Shans,
-	Shansdeath, Shansfire, Sssfire, Sscream1, Sscream2, Send, Spushwall,
-	Sdogdeath, Smutdeath, Shitlerdeath, Seva, Sssdeath, Sgdfire, Sslurp,
-	Sfake, Sschbdeath, Sschb, Shitler, Soffc, Soffcdeath, Sdogfire, Slvlend,
-	Smechwalk, Syeah, Smechadeath, Sscream4, Sscream5, Sottodeath, Sotto,
-	Sfett, Sscream6, Sscream7, Sscream8, Sscream9, Sgretel, Sgreteldeath,
-	Sfettdeath
+	Sgd, Sdog, Sclosedoor, Sopendoor, Smg, Spistol, Sgatling, Sss, Shans,
+	Shansdie, Shansfire, Sssfire, Sscream1, Sscream2, Send, Spushwall,
+	Sdogdie, Smutdie, Shitlerdie, Seva, Sssdie, Sgdfire, Sslurp,
+	Sfake, Sschbdie, Sschb, Shitler, Sofc, Sofcdie, Sdogfire, Slvlend,
+	Smechwalk, Syeah, Smechdie, Sscream4, Sscream5, Sottodie, Sotto,
+	Sfett, Sscream6, Sscream7, Sscream8, Sscream9, Sgretel, Sgreteldie,
+	Sfettdie
 	},{
-	Sgd, Sdogbark, Sclosedoor, Sopendoor, Smg, Spistol, Sgatling, Sss,
-	Shansfire, Sssfire, Sscream1, Sscream2, Send, Spushwall, Sdogdeath,
-	Smutdeath, Sssdeath, Sgdfire, Sslurp, Soffc, Soffcdeath, Sdogfire,
+	Sgd, Sdog, Sclosedoor, Sopendoor, Smg, Spistol, Sgatling, Sss,
+	Shansfire, Sssfire, Sscream1, Sscream2, Send, Spushwall, Sdogdie,
+	Smutdie, Sssdie, Sgdfire, Sslurp, Sofc, Sofcdie, Sdogfire,
 	Slvlend, Sscream4, Sscream5, Sscream6, Sscream7, Sscream8, Sscream9,
-	Strans, Stransdeath, Swilh, Swilhdeath, Suberdeath, Sknight,
-	Sknightdeath, Sangel, Sangeldeath, Sgetgatling, Spear
+	Strans, Stransdie, Swilh, Swilhdie, Suberdie, Sknight,
+	Sknightdie, Sangel, Sangeldie, Sgetgatling, Sspear
 	}
 };
 
 enum{
 	Nplane = 2,
-	Mapdxy = 64,
-	Planesz = Mapdxy * Mapdxy * Nplane,
+	Planesz = Mapa * Nplane,
 	Mapsz = Planesz * Nplane
 };
 static Dat *pcms;
-static uchar *swpb, *mapb;
+static uchar *swpb;
 static int alofs;
 static u16int rlewtag;
+static u32int *mapofs, *mape;
 
 #define	GBIT16(p)	((p)[0]|((p)[1]<<8))
 
@@ -525,13 +525,13 @@
 	return n;
 }
 
-static int
+static void
 unrlew(u16int *d, u16int *s)
 {
 	u16int n, t, v, *e;
 
 	s++;
-	e = d + Planesz/Nplane;
+	e = d + Mapa;
 	t = rlewtag;
 	while(d < e){
 		v = *s++;
@@ -543,14 +543,12 @@
 		}else
 			*d++ = v;
 	}
-	return Planesz;
 }
 
-static int
+static void
 uncarmack(Biobuf *bf, u16int *u, u32int ofs)
 {
-	int len;
-	u16int v, a[Planesz/2], *p, *cp, *e;
+	u16int v, a[Mapa], *p, *cp, *e;
 	u8int n;
 
 	Bseek(bf, ofs, 0);
@@ -585,10 +583,7 @@
 			*p++ = v;
 		}
 	}
-	len = unrlew(u, a);
-	if(len != Planesz)
-		sysfatal("uncarmack: truncated lump");
-	return len;
+	unrlew(u, a);
 }
 
 static void
@@ -700,33 +695,21 @@
 gamemaps(void)
 {
 	int n;
-	u32int v, p0, p1;
-	uchar *u, **d, **e;
-	Biobuf *hed, *dat;
+	u32int v, *d;
+	Biobuf *hed;
 
 	hed = bopen("maphead.", OREAD);
-	dat = bopen("gamemaps.", OREAD);
-	n = ver==WL6 ? 60 : ver==WL1 ? 10 : ver==SDM ? 2 : 20;
+	n = ver==WL6 ? 60 : ver==WL1 ? 10 : ver==SDM ? 2 : 21;
 	rlewtag = get16(hed);
-	d = maps = emalloc(n * sizeof *maps);
-	e = d + n;
-	u = mapb = emalloc(n * Mapsz);
-	while(d < e){
+	d = mapofs = emalloc(n * sizeof *mapofs);
+	mape = d + n;
+	while(d < mape){
 		v = get32(hed);
 		if(v == 0xffffffff)
-			sysfatal("sparse map %zud", d-maps);
-		Bseek(dat, v, 0);
-		p0 = get32(dat);
-		p1 = get32(dat);
-		Bseek(dat, 10, 1);
-		if(get16(dat) != Mapdxy || get16(dat) != Mapdxy)
-			sysfatal("invalid map size");
-		*d++ = u;
-		u += uncarmack(dat, (u16int*)u, p0);
-		u += uncarmack(dat, (u16int*)u, p1);
+			sysfatal("sparse map %zud", d-mapofs);
+		*d++ = v;
 	}
 	Bterm(hed);
-	Bterm(dat);
 }
 
 static void
@@ -746,12 +729,12 @@
 	Dat *pcm;
 
 	if(ver >= SDM){
-		swap(sfxs+Sscream4, sfxs+Shansdeath);
-		swap(sfxs+Sscream5, sfxs+Shitlerdeath);
+		swap(sfxs+Sscream4, sfxs+Shansdie);
+		swap(sfxs+Sscream5, sfxs+Shitlerdie);
 		swap(sfxs+Sscream7, sfxs+Seva);
 		swap(sfxs+Sscream8, sfxs+Shans);
-		swap(sfxs+Sscream6, sfxs+Smechadeath);
-		swap(sfxs+Sscream9, sfxs+Sschbdeath);
+		swap(sfxs+Sscream6, sfxs+Smechdie);
+		swap(sfxs+Sscream9, sfxs+Sschbdie);
 	}
 	p = pcmt[ver<SDM ? 0 : 1];
 	e = p + (ver==WL6 ? 46 : ver==WL1 ? 21 : ver==SDM ? 26 : 40);
@@ -950,6 +933,12 @@
 }
 
 static void
+cfg(void)
+{
+	msense = 5;
+}
+
+static void
 loadscr(void)
 {
 	Biobuf *bf;
@@ -975,6 +964,48 @@
 	}
 }
 
+u16int *
+readmap(int n)
+{
+	u16int *u;
+	u32int *m, p0, p1;
+	Biobuf *dat;
+
+	m = mapofs + n;
+	if(m >= mape)
+		sysfatal("readmap: invalid map number %d", n);
+	dat = bopen("gamemaps.", OREAD);
+	Bseek(dat, *m, 0);
+	u = emalloc(Mapsz);
+	p0 = get32(dat);
+	p1 = get32(dat);
+	Bseek(dat, 10, 1);
+	if(get16(dat) != Mapdxy || get16(dat) != Mapdxy)
+		sysfatal("invalid map dimensions");
+	uncarmack(dat, u, p0);
+	uncarmack(dat, u+Mapa, p1);
+	Bterm(dat);
+	return u;
+}
+
+char *
+demof(char *f)
+{
+	char *p;
+	vlong n;
+	Biobuf *bf;
+
+	bf = Bopen(f, OREAD);
+	if(bf == nil)
+		sysfatal("demof: %r");
+	Blethal(bf, nil);
+	n = bsize(bf);
+	p = emalloc(n);
+	eread(bf, p, n);
+	Bterm(bf);
+	return p;
+}
+
 void
 dat(char *dir)
 {
@@ -984,8 +1015,10 @@
 	if(bind(".", dir, MBEFORE|MCREATE) < 0 || chdir(dir) < 0)
 		fprint(2, "dat: %r\n");
 
-	if(ver >= SDM)
+	if(ver >= SDM){
 		fixpal();
+		sodmap();
+	}
 	e = ext;
 	loadscr();
 	ext = e;
@@ -996,4 +1029,5 @@
 	audiot();
 	gfx();
 	ext = e;
+	cfg();
 }
--- a/game.c
+++ b/game.c
@@ -1,29 +1,5 @@
-// WL_GAME.C
-
-#include "WL_DEF.H"
-#pragma hdrstop
-
-
-/*
-=============================================================================
-
-						 LOCAL CONSTANTS
-
-=============================================================================
-*/
-
-
-/*
-=============================================================================
-
-						 GLOBAL VARIABLES
-
-=============================================================================
-*/
-
 int		ingame,fizzlein;
 u16int	latchpics[NUMLATCHPICS];
-gametype	gamestate;
 
 s32int		spearx,speary;
 u16int	spearangle;
@@ -34,751 +10,20 @@
 //
 s16int ElevatorBackTo[]={1,1,7,3,5,3};
 
-void ScanInfoPlane (void);
-void SetupGameLevel (void);
-void DrawPlayScreen (void);
-void LoadLatchMem (void);
-void GameLoop (void);
-
-/*
-=============================================================================
-
-						 LOCAL VARIABLES
-
-=============================================================================
-*/
-
-
-
-//===========================================================================
-//===========================================================================
-
-
-/*
-==========================
-=
-= SetSoundLoc - Given the location of an object (in terms of global
-=	coordinates, held in globalsoundx and globalsoundy), munges the values
-=	for an approximate distance from the left and right ear, and puts
-=	those values into leftchannel and rightchannel.
-=
-= JAB
-=
-==========================
-*/
-
-	s32int	globalsoundx,globalsoundy;
-	s16int		leftchannel,rightchannel;
-#define ATABLEMAX 15
-u8int righttable[ATABLEMAX][ATABLEMAX * 2] = {
-{ 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 6, 0, 0, 0, 0, 0, 1, 3, 5, 8, 8, 8, 8, 8, 8, 8, 8},
-{ 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 6, 4, 0, 0, 0, 0, 0, 2, 4, 6, 8, 8, 8, 8, 8, 8, 8, 8},
-{ 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 6, 6, 4, 1, 0, 0, 0, 1, 2, 4, 6, 8, 8, 8, 8, 8, 8, 8, 8},
-{ 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 6, 5, 4, 2, 1, 0, 1, 2, 3, 5, 7, 8, 8, 8, 8, 8, 8, 8, 8},
-{ 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 6, 5, 4, 3, 2, 2, 3, 3, 5, 6, 8, 8, 8, 8, 8, 8, 8, 8, 8},
-{ 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 6, 6, 5, 4, 4, 4, 4, 5, 6, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8},
-{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 6, 6, 5, 5, 5, 6, 6, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
-{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 6, 6, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
-{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
-{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
-{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
-{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
-{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
-{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
-{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8}
-};
-u8int lefttable[ATABLEMAX][ATABLEMAX * 2] = {
-{ 8, 8, 8, 8, 8, 8, 8, 8, 5, 3, 1, 0, 0, 0, 0, 0, 6, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8},
-{ 8, 8, 8, 8, 8, 8, 8, 8, 6, 4, 2, 0, 0, 0, 0, 0, 4, 6, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8},
-{ 8, 8, 8, 8, 8, 8, 8, 8, 6, 4, 2, 1, 0, 0, 0, 1, 4, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8},
-{ 8, 8, 8, 8, 8, 8, 8, 8, 7, 5, 3, 2, 1, 0, 1, 2, 4, 5, 6, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8},
-{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 6, 5, 3, 3, 2, 2, 3, 4, 5, 6, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8},
-{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 6, 5, 4, 4, 4, 4, 5, 6, 6, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8},
-{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 6, 6, 5, 5, 5, 6, 6, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8},
-{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 6, 6, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
-{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
-{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
-{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
-{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
-{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
-{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
-{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8}
-};
-
-void
-SetSoundLoc(s32int gx,s32int gy)
-{
-	s32int	xt,yt;
-	s16int		x,y;
-
-//
-// translate point to view centered coordinates
-//
-	gx -= viewx;
-	gy -= viewy;
-
-	xt = FixedByFrac(gx,viewcos);
-	yt = FixedByFrac(gy,viewsin);
-	x = (xt - yt) >> TILESHIFT;
-
-	xt = FixedByFrac(gx,viewsin);
-	yt = FixedByFrac(gy,viewcos);
-	y = (yt + xt) >> TILESHIFT;
-
-	if (y >= ATABLEMAX)
-		y = ATABLEMAX - 1;
-	else if (y <= -ATABLEMAX)
-		y = -ATABLEMAX;
-	if (x < 0)
-		x = -x;
-	if (x >= ATABLEMAX)
-		x = ATABLEMAX - 1;
-	leftchannel  =  lefttable[x][y + ATABLEMAX];
-	rightchannel = righttable[x][y + ATABLEMAX];
-}
-
-/*
-==========================
-=
-= SetSoundLocGlobal - Sets up globalsoundx & globalsoundy and then calls
-=	UpdateSoundLoc() to transform that into relative channel volumes. Those
-=	values are then passed to the Sound Manager so that they'll be used for
-=	the next sound played (if possible).
-=
-= JAB
-=
-==========================
-*/
-void PlaySoundLocGlobal(u16int s,s32int gx,s32int gy)
-{
-	SetSoundLoc(gx,gy);
-	SD_PositionSound(leftchannel,rightchannel);
-	if (SD_PlaySound(s))
-	{
-		globalsoundx = gx;
-		globalsoundy = gy;
-	}
-}
-
-void UpdateSoundLoc(void)
-{
-	if (SoundPositioned)
-	{
-		SetSoundLoc(globalsoundx,globalsoundy);
-		SD_SetPosition(leftchannel,rightchannel);
-	}
-}
-
-/*
-**	JAB End
-*/
-
-
-/*
-==========================
-=
-= ClearMemory
-=
-==========================
-*/
-
-void ClearMemory (void)
-{
-	PM_UnlockMainMem();
-	SD_StopDigitized();
-	MM_SortMem ();
-}
-
-
-/*
-==========================
-=
-= ScanInfoPlane
-=
-= Spawn all actors and mark down special places
-=
-==========================
-*/
-
-void ScanInfoPlane (void)
-{
-	u16int	x,y,i,j;
-	s16int			tile;
-	u16int	far	*start;
-
-	start = mapsegs[1];
-	for (y=0;y<mapheight;y++)
-		for (x=0;x<mapwidth;x++)
-		{
-			tile = *start++;
-			if (!tile)
-				continue;
-
-			switch (tile)
-			{
-			case 19:
-			case 20:
-			case 21:
-			case 22:
-				SpawnPlayer(x,y,NORTH+tile-19);
-				break;
-
-			case 23:
-			case 24:
-			case 25:
-			case 26:
-			case 27:
-			case 28:
-			case 29:
-			case 30:
-
-			case 31:
-			case 32:
-			case 33:
-			case 34:
-			case 35:
-			case 36:
-			case 37:
-			case 38:
-
-			case 39:
-			case 40:
-			case 41:
-			case 42:
-			case 43:
-			case 44:
-			case 45:
-			case 46:
-
-			case 47:
-			case 48:
-			case 49:
-			case 50:
-			case 51:
-			case 52:
-			case 53:
-			case 54:
-
-			case 55:
-			case 56:
-			case 57:
-			case 58:
-			case 59:
-			case 60:
-			case 61:
-			case 62:
-
-			case 63:
-			case 64:
-			case 65:
-			case 66:
-			case 67:
-			case 68:
-			case 69:
-			case 70:
-			case 71:
-			case 72:
-			case 73:						// TRUCK AND SPEAR!
-			case 74:
-
-				SpawnStatic(x,y,tile-23);
-				break;
-
-//
-// P wall
-//
-			case 98:
-				if (!loadedgame)
-				  gamestate.secrettotal++;
-				break;
-
-//
-// guard
-//
-			case 180:
-			case 181:
-			case 182:
-			case 183:
-				if (gamestate.difficulty<gd_hard)
-					break;
-				tile -= 36;
-			case 144:
-			case 145:
-			case 146:
-			case 147:
-				if (gamestate.difficulty<gd_medium)
-					break;
-				tile -= 36;
-			case 108:
-			case 109:
-			case 110:
-			case 111:
-				SpawnStand(en_guard,x,y,tile-108);
-				break;
-
-
-			case 184:
-			case 185:
-			case 186:
-			case 187:
-				if (gamestate.difficulty<gd_hard)
-					break;
-				tile -= 36;
-			case 148:
-			case 149:
-			case 150:
-			case 151:
-				if (gamestate.difficulty<gd_medium)
-					break;
-				tile -= 36;
-			case 112:
-			case 113:
-			case 114:
-			case 115:
-				SpawnPatrol(en_guard,x,y,tile-112);
-				break;
-
-			case 124:
-				SpawnDeadGuard (x,y);
-				break;
-//
-// officer
-//
-			case 188:
-			case 189:
-			case 190:
-			case 191:
-				if (gamestate.difficulty<gd_hard)
-					break;
-				tile -= 36;
-			case 152:
-			case 153:
-			case 154:
-			case 155:
-				if (gamestate.difficulty<gd_medium)
-					break;
-				tile -= 36;
-			case 116:
-			case 117:
-			case 118:
-			case 119:
-				SpawnStand(en_officer,x,y,tile-116);
-				break;
-
-
-			case 192:
-			case 193:
-			case 194:
-			case 195:
-				if (gamestate.difficulty<gd_hard)
-					break;
-				tile -= 36;
-			case 156:
-			case 157:
-			case 158:
-			case 159:
-				if (gamestate.difficulty<gd_medium)
-					break;
-				tile -= 36;
-			case 120:
-			case 121:
-			case 122:
-			case 123:
-				SpawnPatrol(en_officer,x,y,tile-120);
-				break;
-
-
-//
-// ss
-//
-			case 198:
-			case 199:
-			case 200:
-			case 201:
-				if (gamestate.difficulty<gd_hard)
-					break;
-				tile -= 36;
-			case 162:
-			case 163:
-			case 164:
-			case 165:
-				if (gamestate.difficulty<gd_medium)
-					break;
-				tile -= 36;
-			case 126:
-			case 127:
-			case 128:
-			case 129:
-				SpawnStand(en_ss,x,y,tile-126);
-				break;
-
-
-			case 202:
-			case 203:
-			case 204:
-			case 205:
-				if (gamestate.difficulty<gd_hard)
-					break;
-				tile -= 36;
-			case 166:
-			case 167:
-			case 168:
-			case 169:
-				if (gamestate.difficulty<gd_medium)
-					break;
-				tile -= 36;
-			case 130:
-			case 131:
-			case 132:
-			case 133:
-				SpawnPatrol(en_ss,x,y,tile-130);
-				break;
-
-//
-// dogs
-//
-			case 206:
-			case 207:
-			case 208:
-			case 209:
-				if (gamestate.difficulty<gd_hard)
-					break;
-				tile -= 36;
-			case 170:
-			case 171:
-			case 172:
-			case 173:
-				if (gamestate.difficulty<gd_medium)
-					break;
-				tile -= 36;
-			case 134:
-			case 135:
-			case 136:
-			case 137:
-				SpawnStand(en_dog,x,y,tile-134);
-				break;
-
-
-			case 210:
-			case 211:
-			case 212:
-			case 213:
-				if (gamestate.difficulty<gd_hard)
-					break;
-				tile -= 36;
-			case 174:
-			case 175:
-			case 176:
-			case 177:
-				if (gamestate.difficulty<gd_medium)
-					break;
-				tile -= 36;
-			case 138:
-			case 139:
-			case 140:
-			case 141:
-				SpawnPatrol(en_dog,x,y,tile-138);
-				break;
-
-//
-// boss
-//
-#ifndef SPEAR
-			case 214:
-				SpawnBoss (x,y);
-				break;
-			case 197:
-				SpawnGretel (x,y);
-				break;
-			case 215:
-				SpawnGift (x,y);
-				break;
-			case 179:
-				SpawnFat (x,y);
-				break;
-			case 196:
-				SpawnSchabbs (x,y);
-				break;
-			case 160:
-				SpawnFakeHitler (x,y);
-				break;
-			case 178:
-				SpawnHitler (x,y);
-				break;
-#else
-			case 106:
-				SpawnSpectre (x,y);
-				break;
-			case 107:
-				SpawnAngel (x,y);
-				break;
-			case 125:
-				SpawnTrans (x,y);
-				break;
-			case 142:
-				SpawnUber (x,y);
-				break;
-			case 143:
-				SpawnWill (x,y);
-				break;
-			case 161:
-				SpawnDeath (x,y);
-				break;
-
-#endif
-
-//
-// mutants
-//
-			case 252:
-			case 253:
-			case 254:
-			case 255:
-				if (gamestate.difficulty<gd_hard)
-					break;
-				tile -= 18;
-			case 234:
-			case 235:
-			case 236:
-			case 237:
-				if (gamestate.difficulty<gd_medium)
-					break;
-				tile -= 18;
-			case 216:
-			case 217:
-			case 218:
-			case 219:
-				SpawnStand(en_mutant,x,y,tile-216);
-				break;
-
-			case 256:
-			case 257:
-			case 258:
-			case 259:
-				if (gamestate.difficulty<gd_hard)
-					break;
-				tile -= 18;
-			case 238:
-			case 239:
-			case 240:
-			case 241:
-				if (gamestate.difficulty<gd_medium)
-					break;
-				tile -= 18;
-			case 220:
-			case 221:
-			case 222:
-			case 223:
-				SpawnPatrol(en_mutant,x,y,tile-220);
-				break;
-
-//
-// ghosts
-//
-#ifndef SPEAR
-			case 224:
-				SpawnGhosts (en_blinky,x,y);
-				break;
-			case 225:
-				SpawnGhosts (en_clyde,x,y);
-				break;
-			case 226:
-				SpawnGhosts (en_pinky,x,y);
-				break;
-			case 227:
-				SpawnGhosts (en_inky,x,y);
-				break;
-#endif
-			}
-
-		}
-}
-
-//==========================================================================
-
-/*
-==================
-=
-= SetupGameLevel
-=
-==================
-*/
-
-void SetupGameLevel (void)
-{
-	s16int	x,y,i;
-	u16int	far *map,tile,spot;
-
-
-	if (!loadedgame)
-	{
-	 gamestate.TimeCount=
-	 gamestate.secrettotal=
-	 gamestate.killtotal=
-	 gamestate.treasuretotal=
-	 gamestate.secretcount=
-	 gamestate.killcount=
-	 gamestate.treasurecount=0;
-	}
-
-	if (demoplayback || demorecord)
-		US_InitRndT (false);
-	else
-		US_InitRndT (true);
-
-//
-// load the level
-//
-	CA_CacheMap (gamestate.mapon+10*gamestate.episode);
-	mapon-=gamestate.episode*10;
-
-	mapwidth = mapheaderseg[mapon]->width;
-	mapheight = mapheaderseg[mapon]->height;
-
-	if (mapwidth != 64 || mapheight != 64)
-		Quit ("Map not 64*64!");
-
-
-//
-// copy the wall data to a data segment array
-//
-	memset (tilemap,0,sizeof(tilemap));
-	memset (actorat,0,sizeof(actorat));
-	map = mapsegs[0];
-	for (y=0;y<mapheight;y++)
-		for (x=0;x<mapwidth;x++)
-		{
-			tile = *map++;
-			if (tile<AREATILE)
-			{
-			// solid wall
-				tilemap[x][y] = tile;
-				(u16int)actorat[x][y] = tile;
-			}
-			else
-			{
-			// area floor
-				tilemap[x][y] = 0;
-				(u16int)actorat[x][y] = 0;
-			}
-		}
-
-//
-// spawn doors
-//
-	InitActorList ();			// start spawning things with a clean slate
-	InitDoorList ();
-	InitStaticList ();
-
-	map = mapsegs[0];
-	for (y=0;y<mapheight;y++)
-		for (x=0;x<mapwidth;x++)
-		{
-			tile = *map++;
-			if (tile >= 90 && tile <= 101)
-			{
-			// door
-				switch (tile)
-				{
-				case 90:
-				case 92:
-				case 94:
-				case 96:
-				case 98:
-				case 100:
-					SpawnDoor (x,y,1,(tile-90)/2);
-					break;
-				case 91:
-				case 93:
-				case 95:
-				case 97:
-				case 99:
-				case 101:
-					SpawnDoor (x,y,0,(tile-91)/2);
-					break;
-				}
-			}
-		}
-
-//
-// spawn actors
-//
-	ScanInfoPlane ();
-
-//
-// take out the ambush markers
-//
-	map = mapsegs[0];
-	for (y=0;y<mapheight;y++)
-		for (x=0;x<mapwidth;x++)
-		{
-			tile = *map++;
-			if (tile == AMBUSHTILE)
-			{
-				tilemap[x][y] = 0;
-				if ( (u16int)actorat[x][y] == AMBUSHTILE)
-					actorat[x][y] = NULL;
-
-				if (*map >= AREATILE)
-					tile = *map;
-				if (*(map-1-mapwidth) >= AREATILE)
-					tile = *(map-1-mapwidth);
-				if (*(map-1+mapwidth) >= AREATILE)
-					tile = *(map-1+mapwidth);
-				if ( *(map-2) >= AREATILE)
-					tile = *(map-2);
-
-				*(map-1) = tile;
-			}
-		}
-
-
-
-//
-// have the caching manager load and purge stuff to make sure all marks
-// are in memory
-//
-	CA_LoadAllSounds ();
-
-}
-
-
-//==========================================================================
-
-
-/*
-===================
-=
-= DrawPlayBorderSides
-=
-= To fix window overwrites
-=
-===================
-*/
-
 void DrawPlayBorderSides (void)
 {
 	s16int	xl,yl;
 
-	xl = 160-viewwidth/2;
-	yl = (200-STATUSLINES-viewheight)/2;
+	xl = 160-vw.dx/2;
+	yl = (200-STATUSLINES-vw.dy)/2;
 
 	VWB_Bar (0,0,xl-1,200-STATUSLINES,127);
-	VWB_Bar (xl+viewwidth+1,0,xl-2,200-STATUSLINES,127);
+	VWB_Bar (xl+vw.dx+1,0,xl-2,200-STATUSLINES,127);
 
-	VWB_Vlin (yl-1,yl+viewheight,xl-1,0);
-	VWB_Vlin (yl-1,yl+viewheight,xl+viewwidth,125);
+	VWB_Vlin (yl-1,yl+vw.dy,xl-1,0);
+	VWB_Vlin (yl-1,yl+vw.dy,xl+vw.dx,125);
 }
 
-
-/*
-===================
-=
-= DrawAllPlayBorderSides
-=
-===================
-*/
-
 void DrawAllPlayBorderSides (void)
 {
 	u16int	i,temp;
@@ -792,13 +37,6 @@
 	bufferofs = temp;
 }
 
-/*
-===================
-=
-= DrawPlayBorder
-=
-===================
-*/
 void DrawAllPlayBorder (void)
 {
 	u16int	i,temp;
@@ -812,14 +50,6 @@
 	bufferofs = temp;
 }
 
-/*
-===================
-=
-= DrawPlayBorder
-=
-===================
-*/
-
 void DrawPlayBorder (void)
 {
 	s16int	xl,yl;
@@ -826,67 +56,17 @@
 
 	VWB_Bar (0,0,320,200-STATUSLINES,127);
 
-	xl = 160-viewwidth/2;
-	yl = (200-STATUSLINES-viewheight)/2;
-	VWB_Bar (xl,yl,viewwidth,viewheight,0);
+	xl = 160-vw.dx/2;
+	yl = (200-STATUSLINES-vw.dy)/2;
+	VWB_Bar (xl,yl,vw.dx,vw.dy,0);
 
-	VWB_Hlin (xl-1,xl+viewwidth,yl-1,0);
-	VWB_Hlin (xl-1,xl+viewwidth,yl+viewheight,125);
-	VWB_Vlin (yl-1,yl+viewheight,xl-1,0);
-	VWB_Vlin (yl-1,yl+viewheight,xl+viewwidth,125);
-	VWB_Plot (xl-1,yl+viewheight,124);
+	VWB_Hlin (xl-1,xl+vw.dx,yl-1,0);
+	VWB_Hlin (xl-1,xl+vw.dx,yl+vw.dy,125);
+	VWB_Vlin (yl-1,yl+vw.dy,xl-1,0);
+	VWB_Vlin (yl-1,yl+vw.dy,xl+vw.dx,125);
+	VWB_Plot (xl-1,yl+vw.dy,124);
 }
 
-
-
-/*
-===================
-=
-= DrawPlayScreen
-=
-===================
-*/
-
-void DrawPlayScreen (void)
-{
-	s16int	i,j,p,m;
-	u16int	temp;
-
-	VW_FadeOut ();
-
-	temp = bufferofs;
-
-	for (i=0;i<3;i++)
-	{
-		bufferofs = screenloc[i];
-		DrawPlayBorder ();
-		VWB_DrawPic (0,200-STATUSLINES,Pstat);
-	}
-
-	bufferofs = temp;
-
-	DrawFace ();
-	DrawHealth ();
-	DrawLives ();
-	DrawLevel ();
-	DrawAmmo ();
-	DrawKeys ();
-	DrawWeapon ();
-	DrawScore ();
-}
-
-
-
-//==========================================================================
-
-/*
-==================
-=
-= StartDemoRecord
-=
-==================
-*/
-
 #define MAXDEMOSIZE	8192
 
 void StartDemoRecord (s16int levelnumber)
@@ -898,18 +78,9 @@
 
 	*demoptr = levelnumber;
 	demoptr += 4;				// leave space for length
-	demorecord = true;
+	gm.record = true;
 }
 
-
-/*
-==================
-=
-= FinishDemoRecord
-=
-==================
-*/
-
 char	demoname[13] = "DEMO?.";
 
 void FinishDemoRecord (void)
@@ -916,7 +87,7 @@
 {
 	s32int	length,level;
 
-	demorecord = false;
+	gm.record = false;
 
 	length = demoptr - (char far *)demobuffer;
 
@@ -923,7 +94,7 @@
 	demoptr = ((char far *)demobuffer)+1;
 	*(u16int far *)demoptr = length;
 
-	CenterWindow(24,3);
+	CenterWindow(24,3);	/* No. */
 	PrintY+=6;
 	US_Print(" Demo number (0-9):");
 	VW_UpdateScreen();
@@ -942,23 +113,11 @@
 	MM_FreePtr (&demobuffer);
 }
 
-//==========================================================================
-
-/*
-==================
-=
-= RecordDemo
-=
-= Fades the screen out, then starts a demo.  Exits with the screen faded
-=
-==================
-*/
-
 void RecordDemo (void)
 {
 	s16int level,esc;
 
-	CenterWindow(26,3);
+	CenterWindow(26,3);	/* No. */
 	PrintY+=6;
 	CA_CacheGrChunk(STARTFONT);
 	fontnumber=0;
@@ -976,95 +135,36 @@
 	VW_FadeOut ();
 
 #ifndef SPEAR
-	NewGame (gd_hard,level/10);
+	NewGame (GDhard,level/10);
 	gamestate.mapon = level%10;
 #else
-	NewGame (gd_hard,0);
+	NewGame (GDhard,0);
 	gamestate.mapon = level;
 #endif
 
 	StartDemoRecord (level);
 
-	DrawPlayScreen ();
+	view ();
 	VW_FadeIn ();
 
 	startgame = false;
-	demorecord = true;
+	gm.record = true;
 
-	SetupGameLevel ();
-	StartMusic ();
+	initmap ();
+	mapmus ();
 	PM_CheckMainMem ();
 	fizzlein = true;
 
 	PlayLoop ();
 
-	demoplayback = false;
+	gm.demo = false;
 
-	StopMusic ();
+	stopmus ();
 	VW_FadeOut ();
-	ClearMemory ();
 
 	FinishDemoRecord ();
 }
 
-//==========================================================================
-
-/*
-==================
-=
-= PlayDemo
-=
-= Fades the screen out, then starts a demo.  Exits with the screen faded
-=
-==================
-*/
-
-void PlayDemo (uchar *p)
-{
-	s16int length;
-
-	demoptr = p;
-
-	NewGame (1,0);
-	gamestate.mapon = *demoptr++;
-	gamestate.difficulty = gd_hard;
-	length = *((u16int far *)demoptr)++;
-	demoptr++;
-	lastdemoptr = demoptr-4+length;
-
-	VW_FadeOut ();
-
-	SETFONTCOLOR(0,15);
-	DrawPlayScreen ();
-	VW_FadeIn ();
-
-	startgame = false;
-	demoplayback = true;
-
-	SetupGameLevel ();
-	StartMusic ();
-	PM_CheckMainMem ();
-	fizzlein = true;
-
-	PlayLoop ();
-
-	demoplayback = false;
-
-	StopMusic ();
-	VW_FadeOut ();
-	ClearMemory ();
-}
-
-//==========================================================================
-
-/*
-==================
-=
-= Died
-=
-==================
-*/
-
 #define DEATHROTATE 2
 
 void Died (void)
@@ -1074,18 +174,18 @@
 	s16int		iangle,curangle,clockwise,counter,change;
 
 	gamestate.weapon = -1;			// take away weapon
-	SD_PlaySound (Sdeath);
+	sfx (Sdie);
 //
 // swing around to face attacker
 //
-	dx = killerobj->x - player->x;
-	dy = player->y - killerobj->y;
+	dx = killer->x - player->x;
+	dy = player->y - killer->y;
 
 	fangle = atan2(dy,dx);			// returns -pi to pi
 	if (fangle<0)
-		fangle = M_PI*2+fangle;
+		fangle = Fpi*2+fangle;
 
-	iangle = fangle/(M_PI*2)*ANGLES;
+	iangle = fangle/(Fpi*2)*ANGLES;
 
 	if (player->angle > iangle)
 	{
@@ -1118,8 +218,8 @@
 			if (player->angle >= ANGLES)
 				player->angle -= ANGLES;
 
-			ThreeDRefresh ();
-			CalcTics ();
+			render ();
+			ttic ();
 		} while (curangle != iangle);
 	}
 	else
@@ -1140,8 +240,8 @@
 			if (player->angle < 0)
 				player->angle += ANGLES;
 
-			ThreeDRefresh ();
-			CalcTics ();
+			render ();
+			ttic ();
 		} while (curangle != iangle);
 	}
 
@@ -1148,12 +248,12 @@
 //
 // fade to red
 //
-	FinishPaletteShifts ();
+	pal = pals[C0];
 
 	bufferofs += screenofs;
-	VW_Bar (0,0,viewwidth,viewheight,4);
+	VW_Bar (0,0,vw.dx,vw.dy,4);
 	IN_ClearKeysDown ();
-	FizzleFade(bufferofs,displayofs+screenofs,viewwidth,viewheight,70,false);
+	FizzleFade(bufferofs,displayofs+screenofs,vw.dx,vw.dy,70,false);
 	bufferofs -= screenofs;
 	IN_UserInput(100);
 	SD_WaitSoundDone ();
@@ -1163,34 +263,23 @@
 
 	if (gamestate.lives > -1)
 	{
-		gamestate.health = 100;
-		gamestate.weapon = gamestate.bestweapon
-			= gamestate.chosenweapon = wp_pistol;
-		gamestate.ammo = STARTAMMO;
-		gamestate.keys = 0;
-		gamestate.attackframe = gamestate.attackcount =
-		gamestate.weaponframe = 0;
-
-		DrawKeys ();
-		DrawWeapon ();
-		DrawAmmo ();
-		DrawHealth ();
-		DrawFace ();
-		DrawLives ();
+		gm.hp = 100;
+		gm.w = gm.bestw = gm.lastw = WPpistol;
+		gm.ammo = STARTAMMO;
+		gm.keys = 0;
+		atkfrm = 0;
+		atktc = 0;
+		gm.wfrm = 0;
+		hudk();
+		hudw();
+		huda();
+		hudh();
+		hudf();
+		hudl();
 	}
 
 }
 
-//==========================================================================
-
-/*
-===================
-=
-= GameLoop
-=
-===================
-*/
-
 void GameLoop (void)
 {
 	s16int i,xl,yl,xh,yh;
@@ -1198,33 +287,32 @@
 	int	died;
 
 restartgame:
-	ClearMemory ();
 	SETFONTCOLOR(0,15);
-	DrawPlayScreen ();
+	view ();
 	died = false;
 restart:
 	do
 	{
-		if (!loadedgame)
-		  gamestate.score = gamestate.oldscore;
-		DrawScore();
+		if (!gm.load)
+		  gm.pt = gamestate.oldscore;
+		hudp();
 
 		startgame = false;
-		if (loadedgame)
-			loadedgame = false;
+		if (gm.load)
+			gm.load = false;
 		else
-			SetupGameLevel ();
+			initmap ();
 
 #ifdef SPEAR
 		if (gamestate.mapon == 20)	// give them the key allways
 		{
 			gamestate.keys |= 1;
-			DrawKeys ();
+			hudk ();
 		}
 #endif
 
 		ingame = true;
-		StartMusic ();
+		mapmus ();
 		PM_CheckMainMem ();
 		if (!died)
 			PreloadGraphics ();
@@ -1232,7 +320,7 @@
 			died = false;
 
 		fizzlein = true;
-		DrawLevel ();
+		hudm ();
 
 startplayloop:
 		PlayLoop ();
@@ -1241,7 +329,7 @@
 		if (spearflag)
 		{
 			SD_StopSound();
-			SD_PlaySound(Spear);
+			sfx(Sspear);
 			if (DigiMode != sds_Off)
 			{
 				s32int lasttimecount = TimeCount;
@@ -1253,39 +341,39 @@
 			else
 				SD_WaitSoundDone();
 
-			ClearMemory ();
-			gamestate.oldscore = gamestate.score;
+			gamestate.oldscore = gm.pt;
 			gamestate.mapon = 20;
-			SetupGameLevel ();
-			StartMusic ();
+			initmap ();
+			mapmus ();
 			PM_CheckMainMem ();
-			player->x = spearx;
-			player->y = speary;
-			player->angle = spearangle;
+			oplr->x = spearx;
+			oplr->y = speary;
+			oplr->tx = spearx >> Dtlshift;
+			oplr->ty = speary >> Dtlshift;
+			oplr->θ2 = spearangle;
+			oplr->areaid = oplr->tl->p0 - MTfloor;
 			spearflag = false;
-			Thrust (0,0);
 			goto startplayloop;
 		}
 #endif
 
-		StopMusic ();
+		stopmus ();
 		ingame = false;
 
-		if (demorecord && playstate != ex_warped)
+		if (gm.record && gm.φ != ex_warped)
 			FinishDemoRecord ();
 
-		if (startgame || loadedgame)
+		if (startgame || gm.load)
 			goto restartgame;
 
-		switch (playstate)
+		switch (gm.φ)
 		{
 		case ex_completed:
 		case ex_secretlevel:
 			gamestate.keys = 0;
-			DrawKeys ();
+			hudk ();
 			VW_FadeOut ();
 
-			ClearMemory ();
 
 			LevelCompleted ();		// do the intermission
 #ifdef SPEARDEMO
@@ -1295,10 +383,8 @@
 
 				VW_FadeOut ();
 
-				ClearMemory ();
+				CheckHighScore (gm.pt,gamestate.mapon+1);
 
-				CheckHighScore (gamestate.score,gamestate.mapon+1);
-
 				#pragma warn -sus
 				_fstrcpy(MainMenu[viewscores].string,"View Scores");
 				MainMenu[viewscores].routine = CP_ViewScores;
@@ -1308,7 +394,7 @@
 			}
 #endif
 
-			gamestate.oldscore = gamestate.score;
+			gamestate.oldscore = gm.pt;
 
 #ifndef SPEAR
 			//
@@ -1320,7 +406,7 @@
 			//
 			// GOING TO SECRET LEVEL
 			//
-			if (playstate == ex_secretlevel)
+			if (gm.φ == ex_secretlevel)
 				gamestate.mapon = 9;
 #else
 
@@ -1330,7 +416,7 @@
 			//
 			// GOING TO SECRET LEVEL
 			//
-			if (playstate == ex_secretlevel)
+			if (gm.φ == ex_secretlevel)
 				switch(gamestate.mapon)
 				{
 				 case FROMSECRET1: gamestate.mapon = 18; break;
@@ -1365,10 +451,8 @@
 
 			VW_FadeOut ();
 
-			ClearMemory ();
+			CheckHighScore (gm.pt,gamestate.mapon+1);
 
-			CheckHighScore (gamestate.score,gamestate.mapon+1);
-
 			#pragma warn -sus
 			_fstrcpy(MainMenu[viewscores].string,"View Scores");
 			MainMenu[viewscores].routine = CP_ViewScores;
@@ -1383,14 +467,10 @@
 #else
 			VL_FadeOut (0,255,0,17,17,300);
 #endif
-			ClearMemory ();
-
 			Victory ();
 
-			ClearMemory ();
+			CheckHighScore (gm.pt,gamestate.mapon+1);
 
-			CheckHighScore (gamestate.score,gamestate.mapon+1);
-
 			#pragma warn -sus
 			_fstrcpy(MainMenu[viewscores].string,"View Scores");
 			MainMenu[viewscores].routine = CP_ViewScores;
@@ -1397,13 +477,6 @@
 			#pragma warn +sus
 
 			return;
-
-		default:
-			ClearMemory ();
-			break;
 		}
-
 	} while (1);
-
 }
-
--- a/gm.c
+++ b/gm.c
@@ -7,7 +7,8 @@
 #include "dat.h"
 #include "fns.h"
 
-extern Channel *kbc, *msc;
+extern Channel *csc;
+extern QLock inlck;
 
 Rune keys[Ke] = {
 	[K↑] Kup,
@@ -18,9 +19,26 @@
 	[Kfire] Kctl,
 	[Kopen] ' ',
 	[Kstrafe] Kalt,
+	[Kknife] '1',
+	[Kpistol] '2',
+	[Kmg] '3',
+	[Kgatling] '4',
 	[Kmenu] Kesc
 };
+Game gm;
+int msense;
+int god, noclip, onestep;
 
+enum{
+	Ncrm = 7
+};
+
+typedef struct Crm Crm;
+struct Crm{
+	char s[Ncrm];
+	void (*f)(void);
+};
+
 static int rndi, rndt[] = {
   0, 8, 109, 220, 222, 241, 149, 107, 75, 248, 254, 140, 16, 66, 74, 21,
   211, 47, 80, 242, 154, 27, 205, 128, 161, 89, 77, 36, 95, 110, 85, 48,
@@ -39,7 +57,2458 @@
   17, 46, 52, 231, 232, 76, 31, 221, 84, 37, 216, 165, 212, 106, 197, 242,
   98, 43, 39, 175, 254, 145, 190, 84, 118, 222, 187, 136, 120, 163, 236, 249
 };
+static int demfrm;
+static int kon, kold, kΔx, kΔy;
+static s16int kΔθ;
+static int allrecv, firing, noise;
+static char *dem, *deme;
+static Crm crms[];
+static char crs[Ncrm];
+static int dmgtc, bonustc, facetc, funtc;
+static Obj *killer;
+static int bosskillx, bosskilly;
+static int gotspear, spearx, speary, spearθ;
+static int atk[][4] = {
+	{0, 2, 0, -1},
+	{0, 1, 0, -1},
+	{0, 1, 3, -1},
+	{0, 1, 4, -1}
+};
+static int atkfrm, atktc;
+static int dofizz;
 
+static void
+givea(int n)
+{
+	if(gm.ammo == 0 && atkfrm == 0){
+		gm.w = gm.lastw;
+		hudw();
+	}
+	gm.ammo += n;
+	if(gm.ammo > 99)
+		gm.ammo = 99;
+	huda();
+}
+
+static void
+givew(int n)
+{
+	givea(6);
+	if(gm.bestw < n)
+		gm.w = gm.lastw = gm.bestw = n;
+	hudw();
+}
+
+static void
+givek(int n)
+{
+	gm.keys |= 1 << n;
+	hudk();
+}
+
+static void
+givel(void)
+{
+	if(gm.lives < 9)
+		gm.lives++;
+	hudl();
+	sfx(S1up);
+}
+
+static void
+givep(int n)
+{
+	gm.pt += n;
+	while(gm.pt >= gm.to1up){
+		gm.to1up += 40000;
+		givel();
+	}
+	hudp();
+}
+
+static void
+giveh(int n)
+{
+	gm.hp += n;
+	if(gm.hp > 100)
+		gm.hp = 100;
+	hudh();
+	hudf();
+}
+
+static void
+slurp(Obj *)
+{
+	sfx(Sslurp);
+}
+
+static void
+mechsfx(Obj *o)
+{
+	if(plrarea[o->areaid])
+		sfxatt(Smechwalk, 1, o->x, o->y);
+}
+
+static void
+tiredsfx(Obj *)
+{
+	sfx(Sangeltired);
+}
+
+static void
+victory(Obj *)
+{
+	gm.end = EDwon;
+}
+
+static void
+oattack(Obj *o)
+{
+	switch(o->type){
+	case Ogd:
+		sfxatt(Sgd, 1, o->x, o->y);
+		ostate(o, stt+GSgdchase1);
+		o->v *= 3;
+		break;
+	case Oofc:
+		sfxatt(Sofc, 1, o->x, o->y);
+		ostate(o, stt+GSofcchase1);
+		o->v *= 5;
+		break;
+	case Omut:
+		ostate(o, stt+GSmutchase1);
+		o->v *= 3;
+		break;
+	case Oss:
+		sfxatt(Sss, 1, o->x, o->y);
+		ostate(o, stt+GSsschase1);
+		o->v *= 4;
+		break;
+	case Odog:
+		sfxatt(Sdog, 1, o->x, o->y);
+		ostate(o, stt+GSdogchase1);
+		o->v *= 2;
+		break;
+	case Ohans:
+		sfx(Shans);
+		ostate(o, stt+GShanschase1);
+		o->v = 512 * 3;
+		break;
+	case Oschb:
+		sfx(Sschb);
+		ostate(o, stt+GSschbchase1);
+		o->v = 512 * 3;
+		break;
+	case Ogretel:
+		sfx(Sgretel);
+		ostate(o, stt+GSgretelchase1);
+		o->v = 512 * 3;
+		break;
+	case Ootto:
+		sfx(Sotto);
+		ostate(o, stt+GSottochase1);
+		o->v = 512 * 3;
+		break;
+	case Ofett:
+		sfx(Sfett);
+		ostate(o, stt+GSfettchase1);
+		o->v = 512 * 3;
+		break;
+	case Ofake:
+		sfx(Sfake);
+		ostate(o, stt+GSfakechase1);
+		o->v = 512 * 3;
+		break;
+	case Omech:
+		sfx(Shitlerdie);
+		ostate(o, stt+GSmechchase1);
+		o->v = 512 * 3;
+		break;
+	case Ohitler:
+		sfx(Shitlerdie);
+		ostate(o, stt+GShitlerchase1);
+		o->v *= 5;
+		break;
+	case Oghost:
+		ostate(o, stt+GSgh1chase1);
+		o->v *= 2;
+		break;
+	case Ospectre:
+		sfx(Sghost);
+		ostate(o, stt+GSspectrechase1);
+		o->v = 800;
+		break;
+	case Oangel:
+		sfx(Sangel);
+		ostate(o, stt+GSangelchase1);
+		o->v = 1536;
+		break;
+	case Otrans:
+		sfx(Strans);
+		ostate(o, stt+GStranschase1);
+		o->v = 1536;
+		break;
+	case Ouber:
+		ostate(o, stt+GSuberchase1);
+		o->v = 3000;
+		break;
+	case Owilh:
+		sfx(Swilh);
+		ostate(o, stt+GSwilhchase1);
+		o->v = 2048;
+		break;
+	case Oknight:
+		sfx(Sknight);
+		ostate(o, stt+GSknightchase1);
+		o->v = 2048;
+		break;
+	}
+	if(o->Δr < 0)
+		o->Δr = 0;
+	o->f |= OFattack | OFflip;
+}
+
+static void
+mechblow(Obj *o)
+{
+	Obj *p;
+
+	p = ospawn(o->tl, stt+GShitlerchase1);
+	p->v = 2560;
+	p->x = o->x;
+	p->y = o->y;
+	p->Δr = o->Δr;
+	p->θ = o->θ;
+	p->f = o->f | OFshootable;
+	p->type = Ohitler;
+	p->hp = gm.difc>GDbaby ? 600 + gm.difc * 100 : 500;
+}
+
+static void
+yelp(Obj *o)
+{
+	int n, s[] = {
+		Sscream1, Sscream2, Sscream3, Sscream4,
+		Sscream5, Sscream7, Sscream8, Sscream9
+	};
+
+	n = gm.map;
+	if((ver == WL6 && n % 10 == 9 || ver == SOD && (n == 18 || n == 19)) && !rnd())
+		switch(o->type){
+		case Ogd:
+		case Oofc:
+		case Oss:
+		case Odog:
+		case Omut:
+			sfxatt(Sscream6, 1, o->x, o->y);
+			return;
+		}
+
+	switch(o->type){
+	case Omut: sfxatt(Smutdie, 1, o->x, o->y); break;
+	case Ogd: sfxatt(s[rnd()%(ver==WL1?2:8)], 1, o->x, o->y); break;
+	case Oofc: sfxatt(Sofcdie, 1, o->x, o->y); break;
+	case Oss: sfxatt(Sssdie, 1, o->x, o->y); break;
+	case Odog: sfxatt(Sdogdie, 1, o->x, o->y); break;
+	case Ohans: sfx(Shansdie); break;
+	case Oschb: sfx(Sschbdie); break;
+	case Ogretel: sfx(Sgreteldie); break;
+	case Ootto: sfx(Sottodie); break;
+	case Ofett: sfx(Sfettdie); break;
+	case Ofake: sfx(Shitler); break;
+	case Omech: sfx(Smechdie); break;
+	case Ohitler: sfx(Seva); break;
+	case Otrans: sfx(Stransdie); break;
+	case Owilh: sfx(Swilhdie); break;
+	case Ouber: sfx(Suberdie); break;
+	case Oknight: sfx(Sknightdie); break;
+	case Ospectre: sfx(Sghostdie); break;
+	case Oangel: sfx(Sangeldie); break;
+	}
+}
+
+static void
+odie(Obj *o)
+{
+	Tile *tl;
+
+	o->tx = o->x >> Dtlshift;	/* drop item on center */
+	o->ty = o->y >> Dtlshift;
+	tl = tiles + o->ty*Mapdxy + o->tx;
+	o->tl = tl;
+	switch(o->type){
+	case Ogd:
+		givep(100);
+		ostate(o, stt+GSgddie1);
+		drop(tl, Rclip2);
+		break;
+	case Oofc:
+		givep(400);
+		ostate(o, stt+GSofcdie1);
+		drop(tl, Rclip2);
+		break;
+	case Omut:
+		givep(700);
+		ostate(o, stt+GSmutdie1);
+		drop(tl, Rclip2);
+		break;
+	case Oss:
+		givep(500);
+		ostate(o, stt+GSssdie1);
+		drop(tl, gm.bestw < WPmg ? Rmg : Rclip2);
+		break;
+	case Odog:
+		givep(200);
+		ostate(o, stt+GSdogdie1);
+		break;
+	case Ohans:
+		givep(5000);
+		ostate(o, stt+GShansdie1);
+		drop(tl, Rkey1);
+		break;
+	case Oschb:
+		givep(5000);
+		bosskillx = oplr->x;
+		bosskilly = oplr->y;
+		ostate(o, stt+GSschbdie1);
+		yelp(o);
+		break;
+	case Ogretel:
+		givep(5000);
+		ostate(o, stt+GSgreteldie1);
+		drop(tl, Rkey1);
+		break;
+	case Ootto:
+		givep(5000);
+		bosskillx = oplr->x;
+		bosskilly = oplr->y;
+		ostate(o, stt+GSottodie1);
+		break;
+	case Ofett:
+		givep(5000);
+		bosskillx = oplr->x;
+		bosskilly = oplr->y;
+		ostate(o, stt+GSfettdie1);
+		break;
+	case Ofake:
+		givep(2000);
+		ostate(o, stt+GSfakedie1);
+		break;
+	case Omech:
+		givep(5000);
+		ostate(o, stt+GSmechdie1);
+		break;
+	case Ohitler:
+		givep(5000);
+		bosskillx = oplr->x;
+		bosskilly = oplr->y;
+		ostate(o, stt+GShitlerdie1);
+		yelp(o);
+		break;
+	case Ospectre:
+		givep(200);
+		ostate(o, stt+GSspectredie1);
+		break;
+	case Oangel:
+		givep(5000);
+		ostate(o, stt+GSangeldie1);
+		break;
+	case Otrans:
+		givep(5000);
+		ostate(o, stt+GStransdie1);
+		drop(tl, Rkey1);
+		break;
+	case Ouber:
+		givep(5000);
+		ostate(o, stt+GSuberdie1);
+		drop(tl, Rkey1);
+		break;
+	case Owilh:
+		givep(5000);
+		ostate(o, stt+GSwilhdie1);
+		drop(tl, Rkey1);
+		break;
+	case Oknight:
+		givep(5000);
+		ostate(o, stt+GSknightdie1);
+		drop(tl, Rkey1);
+		break;
+	}
+	gm.kills++;
+	o->f &= ~OFshootable;
+	o->f |= OFnomark;
+	tl->o = nil;
+}
+
+static void
+opain(Obj *o, int n)
+{
+	noise++;
+	if(~o->f & OFattack)
+		n *= 2;
+	o->hp -= n;
+	if(o->hp <= 0){
+		odie(o);
+		return;
+	}
+	if(~o->f & OFattack)
+		oattack(o);
+	switch(o->type){
+	case Ogd: ostate(o, stt + (o->hp & 1 ? GSgdpain1 : GSgdpain2)); break;
+	case Oofc: ostate(o, stt + (o->hp & 1 ? GSofcpain1 : GSofcpain2)); break;
+	case Omut: ostate(o, stt + (o->hp & 1 ? GSmutpain1 : GSmutpain2)); break;
+	case Oss: ostate(o, stt + (o->hp & 1 ? GSsspain1 : GSsspain2)); break;
+	}
+}
+
+static void
+hurt(int n, Obj *from)
+{
+	if(gm.won)
+		return;
+	if(gm.difc == GDbaby)
+		n >>= 2;
+	if(!god)
+		gm.hp -= n;
+	if(gm.hp <= 0){
+		gm.hp = 0;
+		gm.end = EDdie;
+		killer = from;
+		if(ver >= SDM && from->type == Oneedle)
+			gm.mut++;
+	}
+	dmgtc += n;
+	hudh();
+	hudf();
+	if(ver >= SDM && n > 30 && gm.hp != 0 && !god){
+		pic(136, 164, pict[Pouch]);
+		facetc = 0;
+	}
+}
+
+static void
+omove(Obj *o, int Δr)
+{
+	int x, y;
+
+	x = o->x;
+	y = o->y;
+	switch(o->θ){
+	case θN: y -= Δr; break;
+	case θNE: x += Δr; y -= Δr; break;
+	case θE: x += Δr; break;
+	case θSE: x += Δr; y += Δr; break;
+	case θS: y += Δr; break;
+	case θSW: x -= Δr; y += Δr; break;
+	case θW: x -= Δr; break;
+	case θNW: x -= Δr; y -= Δr; break;
+	default: return;
+	}
+	if(!plrarea[o->areaid]
+	|| abs(x - oplr->x) > Domin || abs(y - oplr->y) > Domin){
+		o->x = x;
+		o->y = y;
+		o->Δr -= Δr;
+	}else if(o->type == Oghost || o->type == Ospectre)
+		hurt(Δtc * 2, o);
+}
+
+static int
+spotline(Obj *o)
+{
+	int ox, oy, otx, oty, px, py, ptx, pty, x, y, dx, dy, δ;
+	u16int t;
+
+	ox = o->x >> 8;	/* 1/256 tile precision */
+	oy = o->y >> 8;
+	otx = ox >> 8;
+	oty = oy >> 8;
+	px = oplr->x >> 8;
+	py = oplr->y >> 8;
+	ptx = oplr->tx;
+	pty = oplr->ty;
+
+	if(ptx != otx){
+		if(ptx > otx){
+			δ = 256 - (ox & 0xff);
+			dx = 1;
+		}else{
+			δ = ox & 0xff;
+			dx = -1;
+		}
+		dy = (py - oy << 8) / abs(px - ox);
+		if(dy > 0x7fff)
+			dy = 0x7fff;
+		else if(dy < -0x7fff)
+			dy = -0x7fff;
+
+		y = oy + (dy * δ >> 8);
+		x = otx + dx;
+		ptx += dx;
+		do{
+			t = tiles[(y >> 8) * Mapdxy + x].tl;
+			y += dy;
+			x += dx;
+			if(t == 0)
+				continue;
+			if(t < 128 || y - dy / 2 > doors[t & ~0x80].dopen)
+				return 0;
+		}while(x != ptx);
+	}
+	if(pty != oty){
+		if(pty > oty){
+			δ = 256 - (oy & 0xff);
+			dy = 1;
+		}else{
+			δ = oy & 0xff;
+			dy = -1;
+		}
+		dx = (px - ox << 8) / abs(py - oy);
+		if(dx > 0x7fff)
+			dx = 0x7fff;
+		else if(dx < -0x7fff)
+			dx = -0x7fff;
+
+		x = ox + (dx * δ >> 8);
+		y = oty + dy;
+		pty += dy;
+		do{
+			t = tiles[y * Mapdxy + (x >> 8)].tl;
+			x += dx;
+			y += dy;
+			if(t == 0)
+				continue;
+			if(t < 128 || x - dx / 2 > doors[t & ~0x80].dopen)
+				return 0;
+		}while(y != pty);
+	}
+	return 1;
+}
+
+static void
+fire(Obj *o)
+{
+	int dx, dy, Δr, tohit, s;
+
+	if(!plrarea[o->areaid] || !spotline(o))
+		return;
+	dx = abs(o->tx - oplr->tx);
+	dy = abs(o->ty - oplr->ty);
+	Δr = dx > dy ? dx : dy;
+	if(o->type == Oss || o->type == Ohans)
+		Δr = Δr * 2 / 3;
+	tohit = (oplr->v >= 6000 ? 160 : 256) - Δr * (o->f & OFvis ? 16 : 8);
+	if(rnd() < tohit)
+		hurt(rnd() >> (Δr < 2 ? 2 : Δr < 4 ? 3 : 4), o);
+	switch(o->type){
+	case Oss: s = Sssfire; break;
+	case Ootto:
+	case Ofett: s = Smissile; break;
+	case Omech:
+	case Ohitler:
+	case Ohans: s = Shansfire; break;
+	default: s = Sgdfire;
+	}
+	sfxatt(s, 1, o->x, o->y);
+}
+
+static void
+smoke(Obj *o)
+{
+	Obj *p;
+
+	p = onew();
+	p->tx = o->tx;
+	p->ty = o->ty;
+	p->tl = o->tl;
+	p->x = o->x;
+	p->y = o->y;
+	p->s = o->type == Orocket ? stt+GSrsmoke1 : stt+GSmsmoke1;
+	p->type = Oinert;
+	p->tc = 6;
+	p->on = 1;
+	p->f = OFnevermark;
+}
+
+static void
+launch(Obj *o)
+{
+	int Δx, Δy;
+	double θ;
+	Obj *p;
+
+	Δx = oplr->x - o->x;
+	Δy = o->y - oplr->y;
+	θ = atan2(Δy, Δx);
+	if(θ < 0)
+		θ = Fpi * 2 + θ;
+	p = onew();
+	p->tl = o->tl;
+	p->tx = o->tx;
+	p->ty = o->ty;
+	p->x = o->x;
+	p->y = o->y;
+	p->θ = θ / (Fpi * 2) * 360;
+	p->f = OFnomark;
+	p->v = 0x2000;
+	p->tc = 1;
+	p->on = 1;
+	switch(o->type){
+	case Oschb:
+		p->s = stt+GSneedle1;
+		p->type = Oneedle;
+		sfxatt(Srocket, 1, p->x, p->y);
+		break;
+	case Ootto:
+	case Ofett:
+		p->s = stt+GSmissile;
+		p->type = Omissile;
+		sfxatt(Smissile, 1, p->x, p->y);
+		break;
+	case Ofake:
+		p->s = stt+GSflame1;
+		p->type = Oflame;
+		p->v = 0x1200;
+		p->f = OFnevermark;
+		sfxatt(Sflame, 1, p->x, p->y);
+		break;
+	case Owilh:
+		p->s = stt+GSmissile;
+		p->type = Omissile;
+		sfxatt(Srocket, 1, p->x, p->y);
+		break;
+	case Oknight:
+		fire(o);
+		if(o->s == stt+GSknightfire2)
+			p->θ = (p->θ + 356) % 360;
+		else
+			p->θ = (p->θ + 4) % 360;
+		p->s = stt+GSrocket;
+		p->type = Orocket;
+		sfxatt(Sknightmissile, 1, p->x, p->y);
+		break;
+	case Oangel:
+		p->s = stt+GSspark1;
+		p->type = Ospark;
+		sfxatt(Sspark, 1, p->x, p->y);
+		break;
+	}
+}
+
+static void
+uberfire(Obj *o)
+{
+	int Δx, Δy, Δr;
+
+	fire(o);
+	Δx = abs(o->tx - oplr->tx);
+	Δy = abs(o->ty - oplr->ty);
+	Δr = Δx > Δy ? Δx : Δy;
+	if(Δr <= 1)
+		hurt(10, o);
+}
+
+static void
+bite(Obj *o)
+{
+	sfxatt(Sdogfire, 1, o->x, o->y);
+	if(abs(oplr->x - o->x) - Dtlglobal <= Domin
+	&& abs(oplr->y - o->y) - Dtlglobal <= Domin
+	&& rnd() < 180)
+		hurt(rnd() >> 4, o);
+}
+
+static void
+relaunch(Obj *o)
+{
+	if(++o->sdt == 3)
+		ostate(o, stt+GSangeltired1);
+	else if(rnd() & 1)
+		ostate(o, stt+GSangelchase1);
+}
+
+static void
+prelaunch(Obj *o)
+{
+	o->sdt = 0;
+}
+
+static int
+spot(Obj *o)
+{
+	int dx, dy;
+
+	if(!plrarea[o->areaid])
+		return 0;
+	dx = oplr->x - o->x;
+	dy = oplr->y - o->y;
+	if(dx > -0x18000 && dx < 0x18000 && dy > -0x18000 && dy < 0x18000)
+		return 1;
+	switch(o->θ){
+	case θN: if(dy > 0) return 0; break;
+	case θE: if(dx < 0) return 0; break;
+	case θS: if(dy < 0) return 0; break;
+	case θW: if(dx > 0) return 0; break;
+	}
+	return spotline(o);
+}
+
+static int
+sawplr(Obj *o)
+{
+	if(o->f & OFattack)
+		sysfatal("sawplr: confused attack node");
+	if(o->atkdt <= 0){
+		if(!plrarea[o->areaid])
+			return 0;
+		if((o->f & OFambush || !noise) && !spot(o))
+			return 0;
+		o->f &= ~OFambush;
+		switch(o->type){
+		case Ogd: o->atkdt = 1 + rnd() / 4; break;
+		case Oofc: o->atkdt = 2; break;
+		case Omut: o->atkdt = 1 + rnd() / 6; break;
+		case Oss: o->atkdt = 1 + rnd() / 6; break;
+		case Odog: o->atkdt = 1 + rnd() / 8; break;
+		case Ohans:
+		case Oschb:
+		case Ogretel:
+		case Ootto:
+		case Ofett:
+		case Ofake:
+		case Omech:
+		case Ohitler:
+		case Otrans:
+		case Owilh:
+		case Ouber:
+		case Oknight:
+		case Ospectre:
+		case Oangel: o->atkdt = 1; break;
+		}
+		return 0;
+	}
+	o->atkdt -= Δtc;
+	if(o->atkdt <= 0){
+		oattack(o);
+		return 1;
+	}
+	return 0;
+}
+
+static int
+diagok(Tile *tl)
+{
+	return tl->to == 0 && (tl->o == nil || ~tl->o->f & OFshootable);
+}
+static int
+sideok(Tile *tl, s16int *dn)
+{
+	if(tl->o != nil && tl->o->f & OFshootable || tl->to > 0 && tl->to < 128)
+		return 0;
+	if(tl->to & 0x80)
+		*dn = tl->to & 0x3f;
+	return 1;
+}
+static int
+trywalk(Obj *o, int θ)
+{
+	s16int dn;
+
+	dn = -1;
+	o->θ = θnil;
+	switch(θ){
+	case θN:
+		if((o->type == Odog || o->type == Ofake)
+		&& !diagok(o->tl - Mapdxy)
+		|| o->type != Oinert && !sideok(o->tl - Mapdxy, &dn))
+			return 0;
+		o->ty--;
+		o->tl -= Mapdxy;
+		break;
+	case θNE:
+		if(o->type != Oinert && (!diagok(o->tl - Mapdxy + 1)
+		|| !diagok(o->tl + 1) || !diagok(o->tl - Mapdxy)))
+			return 0;
+		o->tx++, o->ty--;
+		o->tl -= Mapdxy - 1;
+		break;
+	case θE:
+		if((o->type == Odog || o->type == Ofake)
+		&& !diagok(o->tl + 1)
+		|| o->type != Oinert && !sideok(o->tl + 1, &dn))
+			return 0;
+		o->tx++;
+		o->tl++;
+		break;
+	case θSE:
+		if(o->type != Oinert && (!diagok(o->tl + Mapdxy + 1)
+		|| !diagok(o->tl + 1) || !diagok(o->tl + Mapdxy)))
+			return 0;
+		o->tx++, o->ty++;
+		o->tl += Mapdxy + 1;
+		break;
+	case θS:
+		if((o->type == Odog || o->type == Ofake)
+		&& !diagok(o->tl + Mapdxy)
+		|| o->type != Oinert && !sideok(o->tl + Mapdxy, &dn))
+			return 0;
+		o->ty++;
+		o->tl += Mapdxy;
+		break;
+	case θSW:
+		if(o->type != Oinert && (!diagok(o->tl + Mapdxy - 1)
+		|| !diagok(o->tl - 1) || !diagok(o->tl + Mapdxy)))
+			return 0;
+		o->tx--, o->ty++;
+		o->tl += Mapdxy - 1;
+		break;
+	case θW:
+		if((o->type == Odog || o->type == Ofake)
+		&& !diagok(o->tl - 1)
+		|| o->type != Oinert && !sideok(o->tl - 1, &dn))
+			return 0;
+		o->tx--;
+		o->tl--;
+		break;
+	case θNW:
+		if(o->type != Oinert && (!diagok(o->tl - Mapdxy - 1)
+		|| !diagok(o->tl - 1) || !diagok(o->tl - Mapdxy)))
+			return 0;
+		o->tx--; o->ty--;
+		o->tl -= Mapdxy + 1;
+		break;
+	case θnil:
+		return 0;
+	default:
+		sysfatal("trywalk: bad angle");
+	}
+	o->θ = θ;
+	if(dn != -1){
+		dropen(doors + dn);
+		o->Δr = -dn - 1;
+	}else{
+		o->areaid = o->tl->p0 - MTfloor;
+		o->Δr = Dtlglobal;
+	}
+	return 1;
+}
+
+static int
+walkθ(Obj *o)
+{
+	int n, θ;
+
+	n = o->tl->p1 - MTarrows;
+	θ = n >= 0 && n < 8 ? n * 45 : o->θ;
+	o->Δr = Dtlglobal;
+	return trywalk(o, θ);
+}
+
+static int
+jaywalk(Obj *o)
+{
+	walkθ(o);
+	if(--o->sdt == 0){
+		ostate(o, stt+GSjump1);
+		return 0;
+	}
+	return 1;
+}
+
+static int
+trychase(Obj *o)
+{
+	int Δx, Δy, i, r, d, θ[3], spin, *p;
+
+	Δx = oplr->tx - o->tx;
+	Δy = oplr->ty - o->ty;
+	r = abs(Δy) > abs(Δx);
+	θ[r ? 1 : 0] = Δx > 0 ? θE : Δx < 0 ? θW : θnil;
+	θ[r ? 0 : 1] = Δy > 0 ? θS : Δy < 0 ? θN : θnil;
+	θ[2] = o->θ;
+	spin = θ[2] == θnil ? θnil : (θ[2] + 180) % 360;
+	for(p=θ; p<θ+nelem(θ);){
+		r = *p++;
+		if(r != spin && trywalk(o, r))
+			return 1;
+	}
+	if(rnd() > 128){
+		r = 45;
+		d = θN;
+	}else{
+		r = -45;
+		d = θW;
+	}
+	for(i=0; i<3; d+=r, i++)
+		if(d != spin && trywalk(o, d))
+			return 1;
+	if(trywalk(o, spin))
+		return 1;
+	return 0;
+}
+
+static int
+tryrun(Obj *o)
+{
+	int Δx, Δy, i, r, d, θ[2], *p;
+
+	Δx = oplr->tx - o->tx;
+	Δy = oplr->ty - o->ty;
+	r = abs(Δy) > abs(Δx);
+	θ[r ? 1 : 0] = Δx < 0 ? θE : θW;
+	θ[r ? 0 : 1] = Δy < 0 ? θS : θN;
+	for(p=θ; p<θ+nelem(θ);){
+		r = *p++;
+		if(trywalk(o, r))
+			return 1;
+	}
+	if(rnd() > 128){
+		r = 45;
+		d = θN;
+	}else{
+		r = -45;
+		d = θW;
+	}
+	for(i=0; i<3; d+=r, i++)
+		if(trywalk(o, d))
+			return 1;
+	return 0;
+}
+
+static int
+trydodge(Obj *o)
+{
+	int r, Δx, Δy, θ[5], spin, *p;
+
+	spin = θnil;
+	if(o->f & OFflip)
+		o->f &= ~OFflip;
+	else if(o->θ != θnil)
+		spin = (o->θ + 180) % 360;
+	Δx = oplr->tx - o->tx;
+	Δy = oplr->ty - o->ty;
+	r = (abs(Δx) > abs(Δy)) ^ (rnd() < 128);
+	θ[r ? 2 : 1] = Δx > 0 ? θE : θW;
+	θ[r ? 4 : 3] = Δx > 0 ? θW : θE;
+	θ[r ? 1 : 2] = Δy > 0 ? θS : θN;
+	θ[r ? 3 : 4] = Δy > 0 ? θN : θS;
+	θ[0] = θ[1] + (θ[1]<θ[2] ? (θ[2]-θ[1]==90 ? 45 : 315) : (θ[1]-θ[2]==90 ? 315 : 45));
+	θ[0] %= 360;
+	for(p=θ; p<θ+nelem(θ);){
+		r = *p++;
+		if(r != spin && trywalk(o, r))
+			return 1;
+	}
+	if(trywalk(o, spin))
+		return 1;
+	return 0;
+}
+static void
+odisplace(Obj *o, int walk, int run, int dodge)
+{
+	int n, Δr;
+	Door *d;
+
+	if(o->θ == θnil){
+		if(walk)
+			n = walkθ(o);
+		else if(dodge)
+			n = trydodge(o);
+		else
+			n = trychase(o);
+		if(!n)
+			return;
+	}
+	Δr = o->v * Δtc;
+	while(Δr != 0){
+		switch(o->type){
+		case Odog:
+			if(!walk && abs(oplr->x - o->x) - Δr <= Domin
+			&& abs(oplr->y - o->y) - Δr <= Domin){
+				ostate(o, stt+GSdogfire1);
+				return;
+			}
+			break;
+		case Oblaz:
+		case Ofake:
+		case Oghost:
+		case Ospectre:
+			break;
+		default:
+			if(o->Δr >= 0)
+				break;
+			d = doors - o->Δr - 1;
+			dropen(d);
+			if(d->φ != DRopen)
+				return;
+			o->Δr = Dtlglobal;
+			break;
+		}
+		if(Δr < o->Δr){
+			omove(o, Δr);
+			break;
+		}
+		osetglobal(o);
+		Δr -= o->Δr;
+		if(walk)
+			n = walkθ(o);
+		else if(run)
+			n = tryrun(o);
+		else if(dodge)
+			n = trydodge(o);
+		else if(o->type == Oblaz)
+			n = jaywalk(o);
+		else
+			n = trychase(o);
+		if(!n)
+			break;
+	}
+}
+
+static void
+uwait(Obj *o)
+{
+	sawplr(o);
+}
+
+static void
+uwalk(Obj *o)
+{
+	if(sawplr(o))
+		return;
+	odisplace(o, 1, 0, 0);
+}
+
+static void
+udogchase(Obj *o)
+{
+	odisplace(o, 0, 0, 1);
+}
+
+static void
+ufake(Obj *o)
+{
+	if(spotline(o) && rnd() < Δtc << 1){
+		ostate(o, stt+GSfakefire1);
+		return;
+	}
+	odisplace(o, 0, 0, 1);
+}
+
+static void
+ughost(Obj *o)
+{
+	odisplace(o, 0, 0, 0);
+}
+
+static void
+uboss(Obj *o)
+{
+	int dodge, Δr, Δx, Δy;
+
+	dodge = 0;
+	Δx = abs(o->tx - oplr->tx);
+	Δy = abs(o->ty - oplr->ty);
+	Δr = Δx > Δy ? Δx : Δy;
+	if(spotline(o)){
+		if(rnd() < Δtc << 3){
+			switch(o->type){
+			case Oschb: ostate(o, stt+GSschbfire1); break;
+			case Ootto: ostate(o, stt+GSottofire1); break;
+			case Ofett: ostate(o, stt+GSfettfire1); break;
+			case Owilh: ostate(o, stt+GSwilhfire1); break;
+			case Oknight: ostate(o, stt+GSknightfire1); break;
+			case Oangel: ostate(o, stt+GSangelfire1); break;
+			}
+			return;
+		}
+		dodge++;
+	}
+	odisplace(o, 0, Δr < 4, dodge);
+}
+
+static void
+uchase(Obj *o)
+{
+	int dx, dy, dodge, fire, Δr;
+
+	if(gm.won)
+		return;
+	dodge = 0;
+	if(spotline(o)){
+		dx = abs(o->tx - oplr->tx);
+		dy = abs(o->ty - oplr->ty);
+		Δr = dx > dy ? dx : dy;
+		if(Δr == 0 || Δr == 1 && o->Δr < 0x4000)
+			fire = 256;
+		else
+			fire = (Δtc << 4) / Δr;
+		if(rnd() < fire){
+			switch(o->type){
+			case Ogd: ostate(o, stt+GSgdfire1); break;
+			case Oss: ostate(o, stt+GSssfire1); break;
+			case Oofc: ostate(o, stt+GSofcfire1); break;
+			case Omut: ostate(o, stt+GSmutfire1); break;
+			case Ohans: ostate(o, stt+GShansfire1); break;
+			case Ogretel: ostate(o, stt+GSgretelfire1); break;
+			case Omech: ostate(o, stt+GSmechfire1); break;
+			case Ohitler: ostate(o, stt+GShitlerfire1); break;
+			case Otrans: ostate(o, stt+GStransfire1); break;
+			case Ouber: ostate(o, stt+GSuberfire1); break;
+			}
+			return;
+		}
+		dodge++;
+	}
+	odisplace(o, 0, 0, dodge);
+}
+
+static void
+spawnrun(void)
+{
+	Obj *o;
+
+	o = ospawn(oplr->tl+Mapdxy, stt+GSblaz1);
+	o->x = oplr->x;
+	o->y = oplr->y;
+	o->type = Oblaz;
+	o->v = 2048;
+	o->θ = θN;
+	o->sdt = 6;
+}
+static void
+urun(Obj *o)
+{
+	odisplace(o, 0, 0, 0);
+}
+static void
+ujump(Obj *o)
+{
+	omove(o, 680 * Δtc);
+}
+static void
+runyell(Obj *o)
+{
+	sfxatt(Syeah, 1, o->x, o->y);
+}
+
+static int
+trymove(Obj *o, int r, int wallsonly, int noobj)
+{
+	int dw, ds, x1, x2, y1, y2;
+	Tile *tl, *te, *tw;
+
+	x1 = o->x - r >> Dtlshift;
+	x2 = o->x + r >> Dtlshift;
+	y1 = o->y - r >> Dtlshift;
+	y2 = o->y + r >> Dtlshift;
+	tl = tiles + y1 * Mapdxy + x1;
+	te = tiles + y2 * Mapdxy + x2;
+	dw = x2 - x1;
+	ds = Mapdxy - dw - 1;
+	while(tl <= te){
+		tw = tl + dw;
+		while(tl <= tw){
+			if(tl->to != 0
+			|| noobj && tl->o != nil && tl->o->f & OFshootable)
+				return 0;
+			tl++;
+		}
+		tl += ds;
+	}
+	if(wallsonly)
+		return 1;
+
+	if(x1 > 0)
+		x1--, dw++, ds--;
+	if(x2 < Mapdxy - 1)
+		te++, dw++, ds--;
+	if(y1 > 0)
+		y1--;
+	if(y2 < Mapdxy - 1)
+		te += Mapdxy;
+	tl = tiles + y1 * Mapdxy + x1;
+	while(tl <= te){
+		tw = tl + dw;
+		while(tl <= tw){
+			if(tl->o != nil && tl->o->f & OFshootable
+			&& abs(o->x - tl->o->x) <= Domin
+			&& abs(o->y - tl->o->y) <= Domin)
+				return 0;
+			tl++;
+		}
+		tl += ds;
+	}
+	return 1;
+}
+
+static void
+uprj(Obj *o)
+{
+	int Δx, Δy, v, dmg;
+
+	v = o->v * Δtc;
+	Δx = ffs(v, cost[o->θ]);
+	Δy = -ffs(v, sint[o->θ]);
+	if(Δx > 0x10000)
+		Δx = 0x10000;
+	if(Δy > 0x10000)
+		Δy = 0x10000;
+	o->x += Δx;
+	o->y += Δy;
+	Δx = o->x - oplr->x;
+	if(Δx < 0)
+		Δx = -Δx;
+	Δy = o->y - oplr->y;
+	if(Δy < 0)
+		Δy = -Δy;
+	if(!trymove(o, 0x2000, 1, 0)){
+		if(o->type == Omissile){
+			o->s = stt+GSmboom1;
+			sfxatt(ver<SDM ? Smissilehit : Srockethit, 1, o->x, o->y);
+		}else if(o->type == Orocket){
+			o->s = stt+GSrboom1;
+			sfxatt(Srockethit, 1, o->x, o->y);
+		}else
+			o->s = nil;
+		return;
+	}
+	if(Δx < 0xc000 && Δy < 0xc000){
+		dmg = 0;
+		switch(o->type){
+		case Oneedle: dmg = (rnd() >> 3) + 20; break;
+		case Omissile:
+		case Orocket:
+		case Ospark: dmg = (rnd() >> 3) + 30; break;
+		case Oflame: dmg = rnd() >> 3; break;
+		}
+		hurt(dmg, o);
+		o->s = nil;
+		return;
+	}
+	o->tx = o->x >> Dtlshift;
+	o->ty = o->y >> Dtlshift;
+	o->tl = tiles + o->ty * Mapdxy + o->tx;
+}
+
+static void
+wake(Obj *o)
+{
+	if(abs(o->x - oplr->x) <= Domin && abs(o->y - oplr->y) <= Domin)
+		return;
+	if(!trymove(o, Dmin, 1, 1))
+		return;
+	o->f |= OFambush | OFshootable;
+	o->f &= ~OFattack;
+	o->θ = θnil;
+	ostate(o, stt+GSspectrewait1);
+}
+
+static void
+cam(Obj *o)
+{
+	int Δx, Δy, Δr;
+	double θ;
+
+	if(gm.won){
+		gm.end = EDcam2;
+		return;
+	}
+	gm.won++;
+	gm.end = EDcam;
+	dofizz++;
+
+	ostate(oplr, stt+GSplrcam);
+	oplr->x = bosskillx;
+	oplr->y = bosskilly;
+	Δx = o->x - oplr->x;
+	Δy = oplr->y - o->y;
+	θ = atan2(Δy, Δx);
+	if(θ < 0)
+		θ = Fpi * 2 + θ;
+	oplr->θ = θ / (Fpi * 2) * 360;
+	Δr = 0x14000;
+	do{
+		oplr->x = o->x - ffs(Δr, cost[oplr->θ]);
+		oplr->y = o->y + ffs(Δr, sint[oplr->θ]);
+		Δr += 0x1000;
+	}while(!trymove(oplr, Dplr, 1, 0));
+	oplr->tx = oplr->x >> Dtlshift;
+	oplr->ty = oplr->y >> Dtlshift;
+	oplr->tl = tiles + oplr->ty * Mapdxy + oplr->tx;
+
+	switch(o->type){
+	case Oschb: ostate(o, stt+GSschbcam); break;
+	case Ootto: ostate(o, stt+GSottocam); break;
+	case Ofett: ostate(o, stt+GSfettcam); break;
+	case Ohitler: ostate(o, stt+GShitlercam); break;
+	}
+}
+
+static void
+clipmove(int Δx, int Δy)
+{
+	int x, y;
+
+	x = oplr->x;
+	y = oplr->y;
+	oplr->x = x + Δx;
+	oplr->y = y + Δy;
+	if(trymove(oplr, Dplr, 0, 0))
+		return;
+	if(noclip && oplr->x > 2 * Dtlglobal && oplr->y > 2 * Dtlglobal
+	&& oplr->x < Mapdxy - 1 << Dtlshift && oplr->y < Mapdxy - 1 << Dtlshift)
+		return;
+	if(lastsfx() < 0)
+		sfx(Shitwall);
+	oplr->x = x + Δx;
+	oplr->y = y;
+	if(trymove(oplr, Dplr, 0, 0))
+		return;
+	oplr->x = x;
+	oplr->y = y + Δy;
+	if(trymove(oplr, Dplr, 0, 0))
+		return;
+	oplr->x = x;
+	oplr->y = y;
+}
+
+static void
+thrust(int θ, int v)
+{
+	int Δx, Δy;
+
+	if(v != 0)
+		funtc = 0;
+	oplr->v += v;
+	if(v >= Dmin * 2)
+		v = Dmin * 2 - 1;
+	Δx = ffs(v, cost[θ]);
+	Δy = -ffs(v, sint[θ]);
+	clipmove(Δx, Δy);
+	oplr->tx = oplr->x >> Dtlshift;
+	oplr->ty = oplr->y >> Dtlshift;
+	oplr->tl = tiles + oplr->ty * Mapdxy + oplr->tx;
+	oplr->areaid = oplr->tl->p0 - MTfloor;
+	if(oplr->tl->p1 == MTexit){
+		if(ver < SDM)
+			spawnrun();
+		gm.won++;
+	}
+}
+
+/* there is an angle hack because at 70Hz the roundoff becomes significant */
+static void
+kmove(void)
+{
+	int θ;
+	s16int u;
+
+	oplr->v = 0;
+	if(kon & 1<<Kstrafe){
+		if(kΔx > 0)
+			thrust((oplr->θ + 270) % 360, kΔx * 150);
+		else if(kΔx < 0)
+			thrust((oplr->θ + 90) % 360, -kΔx * 150);
+	}else{
+		kΔθ += kΔx;
+		u = kΔθ / 20;
+		kΔθ -= u * 20;
+		θ = oplr->θ - u;
+		if(θ >= 360)
+			θ -= 360;
+		if(θ < 0)
+			θ += 360;
+		oplr->θ = θ;
+	}
+	if(kΔy < 0)
+		thrust(oplr->θ, -kΔy * 150);
+	else if(kΔy > 0)
+		thrust((oplr->θ + 180) % 360, kΔy * 100);
+}
+
+static void
+push(Tile *tl, int θ)
+{
+	Tile *c;
+
+	if(pusher.φ != 0 || tl->tl == 0)
+		return;
+	c = nil;
+	switch(θ){
+	case θN: c = tl - Mapdxy; break;
+	case θE: c = tl + 1; break;
+	case θS: c = tl + Mapdxy; break;
+	case θW: c = tl - 1; break;
+	}
+	if(c->o != nil || c->to != 0){
+		sfx(Snoway);
+		return;
+	}
+	c->to = tl->tl;
+	c->tl = tl->tl;
+	gm.secret++;
+	pusher.tl = tl;
+	pusher.isvert = θ;
+	pusher.φ = 1;
+	pusher.dopen = 0;
+	tl->tl |= 0xc0;
+	tl->p1 = 0;
+	sfx(Spushwall);
+}
+
+static void
+kopen(void)
+{
+	Tile *tl;
+	int upok, dn, θ;
+
+	tl = oplr->tl;
+	upok = 0;
+	if(oplr->θ < 360/8 || oplr->θ > 7*360/8){
+		tl++;
+		θ = θE;
+		upok++;
+	}else if(oplr->θ < 3*360/8){
+		tl -= Mapdxy;
+		θ = θN;
+	}else if (oplr->θ < 5*360/8){
+		tl--;
+		θ = θW;
+		upok++;
+	}else{
+		tl += Mapdxy;
+		θ = θS;
+	}
+	dn = tl->tl;
+	if(tl->p1 == MTpush){
+		push(tl, θ);
+		return;
+	}
+	if(~kold & 1<<Kopen){
+		if(dn == MTgoup && upok){
+			kold |= 1<<Kopen;
+			tl->tl++;	/* flip switch */
+			gm.end = oplr->tl->p0 == MTsetec ? EDsetec : EDup;
+			sfx(Slvlend);
+			sfxlck++;
+			return;
+		/* bug: 1<<6 may be set around pushwalls and cause memory
+		 * corruption if this check goes through by writing past the
+		 * doors array */
+		}else if((dn & 0xc0) == 0x80){
+			kold |= 1<<Kopen;
+			druse(doors + (dn & ~0x80));
+			return;
+		}
+	}
+	sfx(Snope);
+}
+
+static void
+kfire(void)
+{
+	kold |= 1<<Kfire;
+	firing++;
+	atkfrm = 0;
+	atktc = 6;
+	gm.wfrm = 1;
+}
+
+static void
+winspin(void)
+{
+	int y;
+
+	if(oplr->θ > 270){
+		oplr->θ -= Δtc * 3;
+		if(oplr->θ < 270)
+			oplr->θ = 270;
+	}else if(oplr->θ < 270){
+		oplr->θ += Δtc * 3;
+		if(oplr->θ > 270)
+			oplr->θ = 270;
+	}
+	y = (oplr->ty - 5 << Dtlshift) - 0x3000;
+	if(oplr->y > y){
+		oplr->y -= Δtc * 4096;
+		if(oplr->y < y)
+			oplr->y = y;
+	}
+}
+
+static void
+face(void)
+{
+	/* bug: demos must be played back with the same sound settings as they
+	 * were recorded, namely adlib sfx (wl6) and pcm (sod) or desync when
+	 * lastsfx is called */
+	if(lastsfx() == Sgetgatling)
+		return;
+	facetc += Δtc;
+	if(facetc > rnd())
+	{
+		gm.facefrm = rnd() >> 6;
+		if(gm.facefrm == 3)
+			gm.facefrm = 1;
+		facetc = 0;
+		hudf();
+	}
+}
+
+static void
+idleface(void)
+{
+	funtc += Δtc;
+	if(funtc > 30 * Tb){
+		funtc = 0;
+		pic(17*8, 164, pict[Pwait] + (rnd() & 1));
+		facetc = 0;
+	}
+}
+
+static void
+wep(void)
+{
+	int i;
+
+	if(gm.ammo == 0)
+		return;
+	for(i=0; i<=gm.bestw; i++)
+		if(kon & 1 << Kknife + i){
+			gm.w = gm.lastw = i;
+			hudw();
+			return;
+		}
+}
+
+static void
+knife(void)
+{
+	int Δx;
+	Obj *o, *hit;
+
+	sfx(Sknife);
+	Δx = 0x7fffffff;
+	hit = nil;
+	for(o=oplr->n; o!=objs; o=o->n)
+		if((o->f & (OFshootable | OFvis)) == (OFshootable | OFvis)
+		&& abs(o->vwdx - vw.mid) < vw.Δhit && o->vwx < Δx){
+			Δx = o->vwx;
+			hit = o;
+		}
+	if(hit == nil || Δx > 0x18000)
+		return;
+	opain(hit, rnd() >> 4);
+}
+
+static void
+gun(void)
+{
+	int n, dx, dy, Δx;
+	Obj *o, *hit, *last;
+
+	switch(gm.w){
+	case WPpistol: sfx(Spistol); break;
+	case WPmg: sfx(Smg); break;
+	case WPgatling: sfx(Sgatling); break;
+	}
+	noise++;
+
+	Δx = 0x7fffffff;
+	hit = nil;
+	for(;;){
+		last = hit;
+		for(o=oplr->n; o!=objs; o=o->n)
+			if((o->f & (OFshootable | OFvis)) == (OFshootable | OFvis)
+			&& abs(o->vwdx - vw.mid) < vw.Δhit && o->vwx < Δx){
+				Δx = o->vwx;
+				hit = o;
+			}
+		if(hit == last)
+			return;
+		if(spotline(hit))
+			break;
+	}
+	dx = abs(hit->tx - oplr->tx);
+	dy = abs(hit->ty - oplr->ty);
+	Δx = dx > dy ? dx : dy;
+	if(Δx < 2)
+		n = rnd() / 4;
+	else if(Δx < 4)
+		n = rnd() / 6;
+	else{
+		if(rnd() / 12 < Δx)
+			return;
+		n = rnd() / 6;
+	}
+	opain(hit, n);
+}
+
+static void
+uplr(Obj *)
+{
+	int n, shot;
+
+	if(firing)
+		face();
+	if(gm.won){
+		winspin();
+		return;
+	}
+	shot = 0;
+	if(!firing){
+		face();
+		wep();
+		if(kon & 1<<Kopen)
+			kopen();
+		if(kon & 1<<Kfire & ~kold){
+			kfire();
+			shot++;
+		}
+	}
+	kmove();
+	if(gm.won || !firing || shot)
+		return;
+
+	atktc -= Δtc;
+	while(atktc <= 0){
+		n = atk[gm.w][atkfrm];
+		switch(n){
+		case -1:
+			firing = 0;
+			if(gm.ammo == 0){
+				gm.w = WPknife;
+				hudw();
+			}else if(gm.w != gm.lastw){
+				gm.w = gm.lastw;
+				hudw();
+			};
+			atkfrm = 0;
+			gm.wfrm = 0;
+			return;
+		case 4:
+			if(gm.ammo == 0)
+				break;
+			if(kon & 1<<Kfire)
+				atkfrm -= 2;
+			/* wet floor */
+		case 1:
+			if(gm.ammo == 0){
+				atkfrm++;
+				break;
+			}
+			gun();
+			gm.ammo--;
+			huda();
+			break;
+		case 2:
+			knife();
+			break;
+		case 3:
+			if(gm.ammo != 0 && (kon & 1<<Kfire))
+				atkfrm -= 2;
+			break;
+		}
+		atktc += 6;
+		atkfrm++;
+		gm.wfrm = atkfrm + 1;
+	}
+}
+
+static void
+crmwapr(void)
+{
+	allrecv++;
+}
+static void
+crmamo(void)
+{
+	gm.ammo = 99;
+	huda();
+}
+static void
+crmkey(void)
+{
+	gm.keys = 15;
+	hudk();
+}
+static void
+crmwep(void)
+{
+	if(gm.bestw < WPgatling)
+		givew(gm.bestw + 1);
+}
+static void
+crmmli(void)
+{
+	gm.hp = 100;
+	gm.ammo = 99;
+	gm.keys = 15;
+	givew(WPgatling);
+	gm.pt = 0;
+	gm.lvltc += 42000;
+	hudw();
+	hudh();
+	hudk();
+	huda();
+	hudp();
+}
+static void
+crmmap(void)
+{
+}
+static void
+crmgod(void)
+{
+	if(ver < SDM)
+		return;
+	god ^= 1;
+	if(god)
+		sfx(Sendb2);
+	else
+		sfx(Snobonus);
+}
+static void
+crmclp(void)
+{
+	if(ver < SDM)
+		return;
+	noclip ^= 1;
+}
+static void
+crmslo(void)
+{
+	onestep ^= 1;
+}
+static void
+crmskp(void)
+{
+}
+static void
+crmwrp(void)
+{
+}
+
+static Crm crms[] = {
+	{"fgd135", crmwapr},
+	{"opepak", crmamo},
+	{"opeopn", crmkey},
+	{"opephz", crmwep},
+	{"opemli", crmmli},
+	{"opepda", crmmap},
+	{"opedqd", crmgod},
+	{"opeclp", crmclp},
+	{"opeslo", crmslo},
+	{"opeskp", crmskp},
+	{"opewrp", crmwrp}
+};
+
+static char *
+crm114(void)
+{
+	int n;
+	Crm *p, *e;
+
+	n = strlen(crs);
+	p = crms;
+	e = crms + 1;
+	if(allrecv){
+		p++;
+		e = crms + nelem(crms);
+	}
+	while(p < e){
+		if(strncmp(crs, p->s, n) != 0){
+			memset(crs, 0, sizeof crs);
+			return crs;
+		}else if(n = Ncrm-1){
+			p->f();
+			memset(crs, 0, sizeof crs);
+			return crs;
+		}
+		p++;
+	}
+	return crs+n;
+}
+static int
+quickkey(Rune r)
+{
+	switch(r){
+	case Kesc:
+	case KF|1:
+	case KF|2:
+	case KF|3:
+	case KF|4:
+	case KF|5:
+	case KF|6:
+	case KF|7:
+	case KF|8:
+	case KF|9:
+		;
+	}
+	return 0;
+}
+static void
+eatcs(void)
+{
+	int i, d;
+	char *p, rc[UTFmax];
+	Rune r;
+
+	if(gm.demo && nbrecv(csc, nil) > 0){
+		gm.end = EDkey;
+		return;
+	}
+	if(gm.record)
+		return;
+	i = 0;
+	p = crs + strlen(crs);
+	while(nbrecv(csc, &r) > 0 && i++ < 6){
+		if(quickkey(r))
+			continue;
+		d = runetochar(rc, &r);
+		if(p + d < crs + sizeof crs){
+			memcpy(p, rc, d);
+			p = crm114();
+		}
+	}
+}
+static void
+gamein(void)
+{
+	int mx, my, scale;
+
+	qlock(&inlck);
+	mx = mΔx;
+	my = mΔy;
+	kon = kb | mΔb & 5 | (mΔb & 2) << 2;
+	mΔx = mΔy = 0;
+	qunlock(&inlck);
+
+	kΔx = kΔy = 0;
+	scale = Δtc * (kon & 1<<Krun ? 70 : 35);
+	if(kon & 1<<K↑)
+		kΔy -= scale;
+	if(kon & 1<<K↓)
+		kΔy += scale;
+	if(kon & 1<<K←)
+		kΔx -= scale;
+	if(kon & 1<<K→)
+		kΔx += scale;
+	kΔx += mx * 10 / (13 - msense);
+	kΔy += my * 20 / (13 - msense);
+
+	scale = 100 * Δtc;
+	if(kΔx > scale)
+		kΔx = scale;
+	else if(kΔx < -scale)
+		kΔx = -scale;
+	if(kΔy > scale)
+		kΔy = scale;
+	else if(kΔy < -scale)
+		kΔy = -scale;
+}
+static void
+demoin(void)
+{
+	kon = *dem++;
+	kΔx = *dem++ * Δtc;
+	kΔy = *dem++ * Δtc;
+	if(dem >= deme)
+		gm.end = EDdem;
+}
+static void
+input(void)
+{
+	kold = kon;
+	if(gm.demo && dem < deme)
+		demoin();
+	else
+		gamein();
+	if(gm.record){
+		if(dem+3 >= deme)
+			sysfatal("demo overflow");
+		*dem++ = kon & 0xff;
+		*dem++ = kΔx / Δtc & 0xff;
+		*dem++ = kΔy / Δtc & 0xff;
+	}
+	if(firing){
+		if(kon & 1<<Kopen & ~kold)
+			kon &= ~(1<<Kopen);
+		if(kon & 1<<Kfire & ~kold)
+			kon &= ~(1<<Kfire);	
+	}
+}
+
+State stt[] = {
+	[GSplr] {uplr, nil, 0, nil, nil, 0},
+	[GSplrcam] {nil, nil, 0, nil, nil, 0},
+	[GSblaz1] {urun, nil, 12, sprs+SPbjwalk1, stt+GSblaz2, 0},
+	[GSblaz2] {nil, nil, 3, sprs+SPbjwalk1, stt+GSblaz3, 0},
+	[GSblaz3] {urun, nil, 8, sprs+SPbjwalk2, stt+GSblaz4, 0},
+	[GSblaz4] {urun, nil, 12, sprs+SPbjwalk3, stt+GSblaz5, 0},
+	[GSblaz5] {nil, nil, 3, sprs+SPbjwalk3, stt+GSblaz6, 0},
+	[GSblaz6] {urun, nil, 8, sprs+SPbjwalk4, stt+GSblaz1, 0},
+	[GSjump1] {ujump, nil, 14, sprs+SPbjjump1, stt+GSjump2, 0},
+	[GSjump2] {ujump, runyell, 14, sprs+SPbjjump2, stt+GSjump3, 0},
+	[GSjump3] {ujump, nil, 14, sprs+SPbjjump3, stt+GSjump4, 0},
+	[GSjump4] {nil, victory, 300, sprs+SPbjjump4, stt+GSjump4, 0},
+	[GSgd] {uwait, nil, 0, sprs+SPgd, stt+GSgd, 1},
+	[GSgdwalk1] {uwalk, nil, 20, sprs+SPgdwalk1, stt+GSgdwalk2, 1},
+	[GSgdwalk2] {nil, nil, 5, sprs+SPgdwalk1, stt+GSgdwalk3, 1},
+	[GSgdwalk3] {uwalk, nil, 15, sprs+SPgdwalk2, stt+GSgdwalk4, 1},
+	[GSgdwalk4] {uwalk, nil, 20, sprs+SPgdwalk3, stt+GSgdwalk5, 1},
+	[GSgdwalk5] {nil, nil, 5, sprs+SPgdwalk3, stt+GSgdwalk6, 1},
+	[GSgdwalk6] {uwalk, nil, 15, sprs+SPgdwalk4, stt+GSgdwalk1, 1},
+	[GSgdpain1] {nil, nil, 10, sprs+SPgdpain1, stt+GSgdchase1, 2},
+	[GSgdpain2] {nil, nil, 10, sprs+SPgdpain2, stt+GSgdchase1, 2},
+	[GSgdchase1] {uchase, nil, 10, sprs+SPgdwalk1, stt+GSgdchase2, 1},
+	[GSgdchase2] {nil, nil, 3, sprs+SPgdwalk1, stt+GSgdchase3, 1},
+	[GSgdchase3] {uchase, nil, 8, sprs+SPgdwalk2, stt+GSgdchase4, 1},
+	[GSgdchase4] {uchase, nil, 10, sprs+SPgdwalk3, stt+GSgdchase5, 1},
+	[GSgdchase5] {nil, nil, 3, sprs+SPgdwalk3, stt+GSgdchase6, 1},
+	[GSgdchase6] {uchase, nil, 8, sprs+SPgdwalk4, stt+GSgdchase1, 1},
+	[GSgdfire1] {nil, nil, 20, sprs+SPgdfire1, stt+GSgdfire2, 0},
+	[GSgdfire2] {nil, fire, 20, sprs+SPgdfire2, stt+GSgdfire3, 0},
+	[GSgdfire3] {nil, nil, 20, sprs+SPgdfire3, stt+GSgdchase1, 0},
+	[GSgddie1] {nil, yelp, 15, sprs+SPgddie1, stt+GSgddie2, 0},
+	[GSgddie2] {nil, nil, 15, sprs+SPgddie2, stt+GSgddie3, 0},
+	[GSgddie3] {nil, nil, 15, sprs+SPgddie3, stt+GSgddie4, 0},
+	[GSgddie4] {nil, nil, 0, sprs+SPgddead, stt+GSgddie4, 0},
+	[GSss] {uwait, nil, 0, sprs+SPss, stt+GSss, 1},
+	[GSsswalk1] {uwalk, nil, 20, sprs+SPsswalk1, stt+GSsswalk2, 1},
+	[GSsswalk2] {nil, nil, 5, sprs+SPsswalk1, stt+GSsswalk3, 1},
+	[GSsswalk3] {uwalk, nil, 15, sprs+SPsswalk2, stt+GSsswalk4, 1},
+	[GSsswalk4] {uwalk, nil, 20, sprs+SPsswalk3, stt+GSsswalk5, 1},
+	[GSsswalk5] {nil, nil, 5, sprs+SPsswalk3, stt+GSsswalk6, 1},
+	[GSsswalk6] {uwalk, nil, 15, sprs+SPsswalk4, stt+GSsswalk1, 1},
+	[GSsspain1] {nil, nil, 10, sprs+SPsspain1, stt+GSsschase1, 2},
+	[GSsspain2] {nil, nil, 10, sprs+SPsspain2, stt+GSsschase1, 2},
+	[GSsschase1] {uchase, nil, 10, sprs+SPsswalk1, stt+GSsschase2, 1},
+	[GSsschase2] {nil, nil, 3, sprs+SPsswalk1, stt+GSsschase3, 1},
+	[GSsschase3] {uchase, nil, 8, sprs+SPsswalk2, stt+GSsschase4, 1},
+	[GSsschase4] {uchase, nil, 10, sprs+SPsswalk3, stt+GSsschase5, 1},
+	[GSsschase5] {nil, nil, 3, sprs+SPsswalk3, stt+GSsschase6, 1},
+	[GSsschase6] {uchase, nil, 8, sprs+SPsswalk4, stt+GSsschase1, 1},
+	[GSssfire1] {nil, nil, 20, sprs+SPssfire1, stt+GSssfire2, 0},
+	[GSssfire2] {nil, fire, 20, sprs+SPssfire2, stt+GSssfire3, 0},
+	[GSssfire3] {nil, nil, 10, sprs+SPssfire3, stt+GSssfire4, 0},
+	[GSssfire4] {nil, fire, 10, sprs+SPssfire2, stt+GSssfire5, 0},
+	[GSssfire5] {nil, nil, 10, sprs+SPssfire3, stt+GSssfire6, 0},
+	[GSssfire6] {nil, fire, 10, sprs+SPssfire2, stt+GSssfire7, 0},
+	[GSssfire7] {nil, nil, 10, sprs+SPssfire3, stt+GSssfire8, 0},
+	[GSssfire8] {nil, fire, 10, sprs+SPssfire2, stt+GSssfire9, 0},
+	[GSssfire9] {nil, nil, 10, sprs+SPssfire3, stt+GSsschase1, 0},
+	[GSssdie1] {nil, yelp, 15, sprs+SPssdie1, stt+GSssdie2, 0},
+	[GSssdie2] {nil, nil, 15, sprs+SPssdie2, stt+GSssdie3, 0},
+	[GSssdie3] {nil, nil, 15, sprs+SPssdie3, stt+GSssdie4, 0},
+	[GSssdie4] {nil, nil, 0, sprs+SPssdead, stt+GSssdie4, 0},
+	[GSofc] {uwait, nil, 0, sprs+SPofc, stt+GSofc, 1},
+	[GSofcwalk1] {uwalk, nil, 20, sprs+SPofcwalk1, stt+GSofcwalk2, 1},
+	[GSofcwalk2] {nil, nil, 5, sprs+SPofcwalk1, stt+GSofcwalk3, 1},
+	[GSofcwalk3] {uwalk, nil, 15, sprs+SPofcwalk2, stt+GSofcwalk4, 1},
+	[GSofcwalk4] {uwalk, nil, 20, sprs+SPofcwalk3, stt+GSofcwalk5, 1},
+	[GSofcwalk5] {nil, nil, 5, sprs+SPofcwalk3, stt+GSofcwalk6, 1},
+	[GSofcwalk6] {uwalk, nil, 15, sprs+SPofcwalk4, stt+GSofcwalk1, 1},
+	[GSofcpain1] {nil, nil, 10, sprs+SPofcpain1, stt+GSofcchase1, 2},
+	[GSofcpain2] {nil, nil, 10, sprs+SPofcpain2, stt+GSofcchase1, 2},
+	[GSofcchase1] {uchase, nil, 10, sprs+SPofcwalk1, stt+GSofcchase2, 1},
+	[GSofcchase2] {nil, nil, 3, sprs+SPofcwalk1, stt+GSofcchase3, 1},
+	[GSofcchase3] {uchase, nil, 8, sprs+SPofcwalk2, stt+GSofcchase4, 1},
+	[GSofcchase4] {uchase, nil, 10, sprs+SPofcwalk3, stt+GSofcchase5, 1},
+	[GSofcchase5] {nil, nil, 3, sprs+SPofcwalk3, stt+GSofcchase6, 1},
+	[GSofcchase6] {uchase, nil, 8, sprs+SPofcwalk4, stt+GSofcchase1, 1},
+	[GSofcfire1] {nil, nil, 6, sprs+SPofcfire1, stt+GSofcfire2, 0},
+	[GSofcfire2] {nil, fire, 20, sprs+SPofcfire2, stt+GSofcfire3, 0},
+	[GSofcfire3] {nil, nil, 10, sprs+SPofcfire3, stt+GSofcchase1, 0},
+	[GSofcdie1] {nil, yelp, 11, sprs+SPofcdie1, stt+GSofcdie2, 0},
+	[GSofcdie2] {nil, nil, 11, sprs+SPofcdie2, stt+GSofcdie3, 0},
+	[GSofcdie3] {nil, nil, 11, sprs+SPofcdie3, stt+GSofcdie4, 0},
+	[GSofcdie4] {nil, nil, 11, sprs+SPofcdie4, stt+GSofcdie5, 0},
+	[GSofcdie5] {nil, nil, 0, sprs+SPofcdead, stt+GSofcdie5, 0},
+	[GSmut] {uwait, nil, 0, sprs+SPmut, stt+GSmut, 1},
+	[GSmutwalk1] {uwalk, nil, 20, sprs+SPmutwalk1, stt+GSmutwalk2, 1},
+	[GSmutwalk2] {nil, nil, 5, sprs+SPmutwalk1, stt+GSmutwalk3, 1},
+	[GSmutwalk3] {uwalk, nil, 15, sprs+SPmutwalk2, stt+GSmutwalk4, 1},
+	[GSmutwalk4] {uwalk, nil, 20, sprs+SPmutwalk3, stt+GSmutwalk5, 1},
+	[GSmutwalk5] {nil, nil, 5, sprs+SPmutwalk3, stt+GSmutwalk6, 1},
+	[GSmutwalk6] {uwalk, nil, 15, sprs+SPmutwalk4, stt+GSmutwalk1, 1},
+	[GSmutpain1] {nil, nil, 10, sprs+SPmutpain1, stt+GSmutchase1, 2},
+	[GSmutpain2] {nil, nil, 10, sprs+SPmutpain2, stt+GSmutchase1, 2},
+	[GSmutchase1] {uchase, nil, 10, sprs+SPmutwalk1, stt+GSmutchase2, 1},
+	[GSmutchase2] {nil, nil, 3, sprs+SPmutwalk1, stt+GSmutchase3, 1},
+	[GSmutchase3] {uchase, nil, 8, sprs+SPmutwalk2, stt+GSmutchase4, 1},
+	[GSmutchase4] {uchase, nil, 10, sprs+SPmutwalk3, stt+GSmutchase5, 1},
+	[GSmutchase5] {nil, nil, 3, sprs+SPmutwalk3, stt+GSmutchase6, 1},
+	[GSmutchase6] {uchase, nil, 8, sprs+SPmutwalk4, stt+GSmutchase1, 1},
+	[GSmutfire1] {nil, fire, 6, sprs+SPmutfire1, stt+GSmutfire2, 0},
+	[GSmutfire2] {nil, nil, 20, sprs+SPmutfire2, stt+GSmutfire3, 0},
+	[GSmutfire3] {nil, fire, 10, sprs+SPmutfire3, stt+GSmutfire4, 0},
+	[GSmutfire4] {nil, nil, 20, sprs+SPmutfire4, stt+GSmutchase1, 0},
+	[GSmutdie1] {nil, yelp, 7, sprs+SPmutdie1, stt+GSmutdie2, 0},
+	[GSmutdie2] {nil, nil, 7, sprs+SPmutdie2, stt+GSmutdie3, 0},
+	[GSmutdie3] {nil, nil, 7, sprs+SPmutdie3, stt+GSmutdie4, 0},
+	[GSmutdie4] {nil, nil, 7, sprs+SPmutdie4, stt+GSmutdie5, 0},
+	[GSmutdie5] {nil, nil, 0, sprs+SPmutdead, stt+GSmutdie5, 0},
+	[GSdogwalk1] {uwalk, nil, 20, sprs+SPdogwalk1, stt+GSdogwalk2, 1},
+	[GSdogwalk2] {nil, nil, 5, sprs+SPdogwalk1, stt+GSdogwalk3, 1},
+	[GSdogwalk3] {uwalk, nil, 15, sprs+SPdogwalk2, stt+GSdogwalk4, 1},
+	[GSdogwalk4] {uwalk, nil, 20, sprs+SPdogwalk3, stt+GSdogwalk5, 1},
+	[GSdogwalk5] {nil, nil, 5, sprs+SPdogwalk3, stt+GSdogwalk6, 1},
+	[GSdogwalk6] {uwalk, nil, 15, sprs+SPdogwalk4, stt+GSdogwalk1, 1},
+	[GSdogchase1] {udogchase, nil, 10, sprs+SPdogwalk1, stt+GSdogchase2, 1},
+	[GSdogchase2] {nil, nil, 3, sprs+SPdogwalk1, stt+GSdogchase3, 1},
+	[GSdogchase3] {udogchase, nil, 8, sprs+SPdogwalk2, stt+GSdogchase4, 1},
+	[GSdogchase4] {udogchase, nil, 10, sprs+SPdogwalk3, stt+GSdogchase5, 1},
+	[GSdogchase5] {nil, nil, 3, sprs+SPdogwalk3, stt+GSdogchase6, 1},
+	[GSdogchase6] {udogchase, nil, 8, sprs+SPdogwalk4, stt+GSdogchase1, 1},
+	[GSdogfire1] {nil, nil, 10, sprs+SPdogfire1, stt+GSdogfire2, 0},
+	[GSdogfire2] {nil, bite, 10, sprs+SPdogfire2, stt+GSdogfire3, 0},
+	[GSdogfire3] {nil, nil, 10, sprs+SPdogfire3, stt+GSdogfire4, 0},
+	[GSdogfire4] {nil, nil, 10, sprs+SPdogfire1, stt+GSdogfire5, 0},
+	[GSdogfire5] {nil, nil, 10, sprs+SPdogwalk1, stt+GSdogchase1, 0},
+	[GSdogdie1] {nil, yelp, 15, sprs+SPdogdie1, stt+GSdogdie2, 0},
+	[GSdogdie2] {nil, nil, 15, sprs+SPdogdie2, stt+GSdogdie3, 0},
+	[GSdogdie3] {nil, nil, 15, sprs+SPdogdie3, stt+GSdogdie4, 0},
+	[GSdogdie4] {nil, nil, 15, sprs+SPdogdead, stt+GSdogdie4, 0},
+	[GShans] {uwait, nil, 0, sprs+SPhanswalk1, stt+GShans, 0},
+	[GShanschase1] {uchase, nil, 10, sprs+SPhanswalk1, stt+GShanschase2, 0},
+	[GShanschase2] {nil, nil, 3, sprs+SPhanswalk1, stt+GShanschase3, 0},
+	[GShanschase3] {uchase, nil, 8, sprs+SPhanswalk2, stt+GShanschase4, 0},
+	[GShanschase4] {uchase, nil, 10, sprs+SPhanswalk3, stt+GShanschase5, 0},
+	[GShanschase5] {nil, nil, 3, sprs+SPhanswalk3, stt+GShanschase6, 0},
+	[GShanschase6] {uchase, nil, 8, sprs+SPhanswalk4, stt+GShanschase1, 0},
+	[GShansfire1] {nil, nil, 30, sprs+SPhansfire1, stt+GShansfire2, 0},
+	[GShansfire2] {nil, fire, 10, sprs+SPhansfire2, stt+GShansfire3, 0},
+	[GShansfire3] {nil, fire, 10, sprs+SPhansfire3, stt+GShansfire4, 0},
+	[GShansfire4] {nil, fire, 10, sprs+SPhansfire2, stt+GShansfire5, 0},
+	[GShansfire5] {nil, fire, 10, sprs+SPhansfire3, stt+GShansfire6, 0},
+	[GShansfire6] {nil, fire, 10, sprs+SPhansfire2, stt+GShansfire7, 0},
+	[GShansfire7] {nil, fire, 10, sprs+SPhansfire3, stt+GShansfire8, 0},
+	[GShansfire8] {nil, nil, 10, sprs+SPhansfire1, stt+GShanschase1, 0},
+	[GShansdie1] {nil, yelp, 15, sprs+SPhansdie1, stt+GShansdie2, 0},
+	[GShansdie2] {nil, nil, 15, sprs+SPhansdie2, stt+GShansdie3, 0},
+	[GShansdie3] {nil, nil, 15, sprs+SPhansdie3, stt+GShansdie4, 0},
+	[GShansdie4] {nil, nil, 0, sprs+SPhansdead, stt+GShansdie4, 0},
+	[GSschb] {uwait, nil, 0, sprs+SPschbwalk1, stt+GSschb, 0},
+	[GSschbchase1] {uboss, nil, 10, sprs+SPschbwalk1, stt+GSschbchase2, 0},
+	[GSschbchase2] {nil, nil, 3, sprs+SPschbwalk1, stt+GSschbchase3, 0},
+	[GSschbchase3] {uboss, nil, 8, sprs+SPschbwalk2, stt+GSschbchase4, 0},
+	[GSschbchase4] {uboss, nil, 10, sprs+SPschbwalk3, stt+GSschbchase5, 0},
+	[GSschbchase5] {nil, nil, 3, sprs+SPschbwalk3, stt+GSschbchase6, 0},
+	[GSschbchase6] {uboss, nil, 8, sprs+SPschbwalk4, stt+GSschbchase1, 0},
+	[GSschbfire1] {nil, nil, 30, sprs+SPschbfire1, stt+GSschbfire2, 0},
+	[GSschbfire2] {nil, launch, 10, sprs+SPschbfire2, stt+GSschbchase1, 0},
+	[GSschbcam] {nil, nil, 1, sprs+SPschbwalk1, stt+GSschbdie1, 0},
+	[GSschbdie1] {nil, yelp, 10, sprs+SPschbwalk1, stt+GSschbdie2, 0},
+	[GSschbdie2] {nil, nil, 10, sprs+SPschbwalk1, stt+GSschbdie3, 0},
+	[GSschbdie3] {nil, nil, 10, sprs+SPschbdie1, stt+GSschbdie4, 0},
+	[GSschbdie4] {nil, nil, 10, sprs+SPschbdie2, stt+GSschbdie5, 0},
+	[GSschbdie5] {nil, nil, 10, sprs+SPschbdie3, stt+GSschbdie6, 0},
+	[GSschbdie6] {nil, cam, 20, sprs+SPschbdead, stt+GSschbdie6, 0},
+	[GSgretel] {uwait, nil, 0, sprs+SPgretelwalk1, stt+GSgretel, 0},
+	[GSgretelchase1] {uchase, nil, 10, sprs+SPgretelwalk1, stt+GSgretelchase2, 0},
+	[GSgretelchase2] {nil, nil, 3, sprs+SPgretelwalk1, stt+GSgretelchase3, 0},
+	[GSgretelchase3] {uchase, nil, 8, sprs+SPgretelwalk2, stt+GSgretelchase4, 0},
+	[GSgretelchase4] {uchase, nil, 10, sprs+SPgretelwalk3, stt+GSgretelchase5, 0},
+	[GSgretelchase5] {nil, nil, 3, sprs+SPgretelwalk3, stt+GSgretelchase6, 0},
+	[GSgretelchase6] {uchase, nil, 8, sprs+SPgretelwalk4, stt+GSgretelchase1, 0},
+	[GSgretelfire1] {nil, nil, 30, sprs+SPgretelfire1, stt+GSgretelfire2, 0},
+	[GSgretelfire2] {nil, fire, 10, sprs+SPgretelfire2, stt+GSgretelfire3, 0},
+	[GSgretelfire3] {nil, fire, 10, sprs+SPgretelfire3, stt+GSgretelfire4, 0},
+	[GSgretelfire4] {nil, fire, 10, sprs+SPgretelfire2, stt+GSgretelfire5, 0},
+	[GSgretelfire5] {nil, fire, 10, sprs+SPgretelfire3, stt+GSgretelfire6, 0},
+	[GSgretelfire6] {nil, fire, 10, sprs+SPgretelfire2, stt+GSgretelfire7, 0},
+	[GSgretelfire7] {nil, fire, 10, sprs+SPgretelfire3, stt+GSgretelfire8, 0},
+	[GSgretelfire8] {nil, nil, 10, sprs+SPgretelfire1, stt+GSgretelchase1, 0},
+	[GSgreteldie1] {nil, yelp, 15, sprs+SPgreteldie1, stt+GSgreteldie2, 0},
+	[GSgreteldie2] {nil, nil, 15, sprs+SPgreteldie2, stt+GSgreteldie3, 0},
+	[GSgreteldie3] {nil, nil, 15, sprs+SPgreteldie3, stt+GSgreteldie4, 0},
+	[GSgreteldie4] {nil, nil, 0, sprs+SPgreteldead, stt+GSgreteldie4, 0},
+	[GSotto] {uwait, nil, 0, sprs+SPottowalk1, stt+GSotto, 0},
+	[GSottochase1] {uboss, nil, 10, sprs+SPottowalk1, stt+GSottochase2, 0},
+	[GSottochase2] {nil, nil, 3, sprs+SPottowalk1, stt+GSottochase3, 0},
+	[GSottochase3] {uboss, nil, 8, sprs+SPottowalk2, stt+GSottochase4, 0},
+	[GSottochase4] {uboss, nil, 10, sprs+SPottowalk3, stt+GSottochase5, 0},
+	[GSottochase5] {nil, nil, 3, sprs+SPottowalk3, stt+GSottochase6, 0},
+	[GSottochase6] {uboss, nil, 8, sprs+SPottowalk4, stt+GSottochase1, 0},
+	[GSottofire1] {nil, nil, 30, sprs+SPottofire1, stt+GSottofire2, 0},
+	[GSottofire2] {nil, launch, 10, sprs+SPottofire2, stt+GSottochase1, 0},
+	[GSottocam] {nil, nil, 1, sprs+SPottowalk1, stt+GSottodie1, 0},
+	[GSottodie1] {nil, yelp, 1, sprs+SPottowalk1, stt+GSottodie2, 0},
+	[GSottodie2] {nil, nil, 10, sprs+SPottowalk1, stt+GSottodie3, 0},
+	[GSottodie3] {nil, nil, 10, sprs+SPottodie1, stt+GSottodie4, 0},
+	[GSottodie4] {nil, nil, 10, sprs+SPottodie2, stt+GSottodie5, 0},
+	[GSottodie5] {nil, nil, 10, sprs+SPottodie3, stt+GSottodie6, 0},
+	[GSottodie6] {nil, cam, 20, sprs+SPottodead, stt+GSottodie6, 0},
+	[GSfett] {uwait, nil, 0, sprs+SPfettwalk1, stt+GSfett, 0},
+	[GSfettchase1] {uboss, nil, 10, sprs+SPfettwalk1, stt+GSfettchase2, 0},
+	[GSfettchase2] {nil, nil, 3, sprs+SPfettwalk1, stt+GSfettchase3, 0},
+	[GSfettchase3] {uboss, nil, 8, sprs+SPfettwalk2, stt+GSfettchase4, 0},
+	[GSfettchase4] {uboss, nil, 10, sprs+SPfettwalk3, stt+GSfettchase5, 0},
+	[GSfettchase5] {nil, nil, 3, sprs+SPfettwalk3, stt+GSfettchase6, 0},
+	[GSfettchase6] {uboss, nil, 8, sprs+SPfettwalk4, stt+GSfettchase1, 0},
+	[GSfettfire1] {nil, nil, 30, sprs+SPfettfire1, stt+GSfettfire2, 0},
+	[GSfettfire2] {nil, launch, 10, sprs+SPfettfire2, stt+GSfettfire3, 0},
+	[GSfettfire3] {nil, fire, 10, sprs+SPfettfire3, stt+GSfettfire4, 0},
+	[GSfettfire4] {nil, fire, 10, sprs+SPfettfire4, stt+GSfettfire5, 0},
+	[GSfettfire5] {nil, fire, 10, sprs+SPfettfire3, stt+GSfettfire6, 0},
+	[GSfettfire6] {nil, fire, 10, sprs+SPfettfire4, stt+GSfettchase1, 0},
+	[GSfettcam] {nil, nil, 1, sprs+SPfettwalk1, stt+GSfettdie1, 0},
+	[GSfettdie1] {nil, yelp, 1, sprs+SPfettwalk1, stt+GSfettdie2, 0},
+	[GSfettdie2] {nil, nil, 10, sprs+SPfettwalk1, stt+GSfettdie3, 0},
+	[GSfettdie3] {nil, nil, 10, sprs+SPfettdie1, stt+GSfettdie4, 0},
+	[GSfettdie4] {nil, nil, 10, sprs+SPfettdie2, stt+GSfettdie5, 0},
+	[GSfettdie5] {nil, nil, 10, sprs+SPfettdie3, stt+GSfettdie6, 0},
+	[GSfettdie6] {nil, cam, 20, sprs+SPfettdead, stt+GSfettdie6, 0},
+	[GSfake] {uwait, nil, 0, sprs+SPfakewalk1, stt+GSfake, 0},
+	[GSfakechase1] {ufake, nil, 10, sprs+SPfakewalk1, stt+GSfakechase2, 0},
+	[GSfakechase2] {nil, nil, 3, sprs+SPfakewalk1, stt+GSfakechase3, 0},
+	[GSfakechase3] {ufake, nil, 8, sprs+SPfakewalk2, stt+GSfakechase4, 0},
+	[GSfakechase4] {ufake, nil, 10, sprs+SPfakewalk3, stt+GSfakechase5, 0},
+	[GSfakechase5] {nil, nil, 3, sprs+SPfakewalk3, stt+GSfakechase6, 0},
+	[GSfakechase6] {ufake, nil, 8, sprs+SPfakewalk4, stt+GSfakechase1, 0},
+	[GSfakefire1] {nil, launch, 8, sprs+SPfakefire, stt+GSfakefire2, 0},
+	[GSfakefire2] {nil, launch, 8, sprs+SPfakefire, stt+GSfakefire3, 0},
+	[GSfakefire3] {nil, launch, 8, sprs+SPfakefire, stt+GSfakefire4, 0},
+	[GSfakefire4] {nil, launch, 8, sprs+SPfakefire, stt+GSfakefire5, 0},
+	[GSfakefire5] {nil, launch, 8, sprs+SPfakefire, stt+GSfakefire6, 0},
+	[GSfakefire6] {nil, launch, 8, sprs+SPfakefire, stt+GSfakefire7, 0},
+	[GSfakefire7] {nil, launch, 8, sprs+SPfakefire, stt+GSfakefire8, 0},
+	[GSfakefire8] {nil, launch, 8, sprs+SPfakefire, stt+GSfakefire9, 0},
+	[GSfakefire9] {nil, nil, 8, sprs+SPfakefire, stt+GSfakechase1, 0},
+	[GSfakedie1] {nil, yelp, 10, sprs+SPfakedie1, stt+GSfakedie2, 0},
+	[GSfakedie2] {nil, nil, 10, sprs+SPfakedie2, stt+GSfakedie3, 0},
+	[GSfakedie3] {nil, nil, 10, sprs+SPfakedie3, stt+GSfakedie4, 0},
+	[GSfakedie4] {nil, nil, 10, sprs+SPfakedie4, stt+GSfakedie5, 0},
+	[GSfakedie5] {nil, nil, 10, sprs+SPfakedie5, stt+GSfakedie6, 0},
+	[GSfakedie6] {nil, nil, 0, sprs+SPfakedead, stt+GSfakedie6, 0},
+	[GSmech] {uwait, nil, 0, sprs+SPmechwalk1, stt+GSmech, 0},
+	[GSmechchase1] {uchase, mechsfx, 10, sprs+SPmechwalk1, stt+GSmechchase2, 0},
+	[GSmechchase2] {nil, nil, 6, sprs+SPmechwalk1, stt+GSmechchase3, 0},
+	[GSmechchase3] {uchase, nil, 8, sprs+SPmechwalk2, stt+GSmechchase4, 0},
+	[GSmechchase4] {uchase, mechsfx, 10, sprs+SPmechwalk3, stt+GSmechchase5, 0},
+	[GSmechchase5] {nil, nil, 6, sprs+SPmechwalk3, stt+GSmechchase6, 0},
+	[GSmechchase6] {uchase, nil, 8, sprs+SPmechwalk4, stt+GSmechchase1, 0},
+	[GSmechfire1] {nil, nil, 30, sprs+SPmechfire1, stt+GSmechfire2, 0},
+	[GSmechfire2] {nil, fire, 10, sprs+SPmechfire2, stt+GSmechfire3, 0},
+	[GSmechfire3] {nil, fire, 10, sprs+SPmechfire3, stt+GSmechfire4, 0},
+	[GSmechfire4] {nil, fire, 10, sprs+SPmechfire2, stt+GSmechfire5, 0},
+	[GSmechfire5] {nil, fire, 10, sprs+SPmechfire3, stt+GSmechfire6, 0},
+	[GSmechfire6] {nil, fire, 10, sprs+SPmechfire2, stt+GSmechchase1, 0},
+	[GSmechdie1] {nil, yelp, 10, sprs+SPmechdie1, stt+GSmechdie2, 0},
+	[GSmechdie2] {nil, nil, 10, sprs+SPmechdie2, stt+GSmechdie3, 0},
+	[GSmechdie3] {nil, mechblow, 10, sprs+SPmechdie3, stt+GSmechdie4, 0},
+	[GSmechdie4] {nil, nil, 0, sprs+SPmechdead, stt+GSmechdie4, 0},
+	[GShitlerchase1] {uchase, nil, 6, sprs+SPhitlerwalk1, stt+GShitlerchase2, 0},
+	[GShitlerchase2] {nil, nil, 4, sprs+SPhitlerwalk1, stt+GShitlerchase3, 0},
+	[GShitlerchase3] {uchase, nil, 2, sprs+SPhitlerwalk2, stt+GShitlerchase4, 0},
+	[GShitlerchase4] {uchase, nil, 6, sprs+SPhitlerwalk3, stt+GShitlerchase5, 0},
+	[GShitlerchase5] {nil, nil, 4, sprs+SPhitlerwalk3, stt+GShitlerchase6, 0},
+	[GShitlerchase6] {uchase, nil, 2, sprs+SPhitlerwalk4, stt+GShitlerchase1, 0},
+	[GShitlerfire1] {nil, nil, 30, sprs+SPhitlerfire1, stt+GShitlerfire2, 0},
+	[GShitlerfire2] {nil, fire, 10, sprs+SPhitlerfire2, stt+GShitlerfire3, 0},
+	[GShitlerfire3] {nil, fire, 10, sprs+SPhitlerfire3, stt+GShitlerfire4, 0},
+	[GShitlerfire4] {nil, fire, 10, sprs+SPhitlerfire2, stt+GShitlerfire5, 0},
+	[GShitlerfire5] {nil, fire, 10, sprs+SPhitlerfire3, stt+GShitlerfire6, 0},
+	[GShitlerfire6] {nil, fire, 10, sprs+SPhitlerfire2, stt+GShitlerchase1, 0},
+	[GShitlercam] {nil, nil, 10, sprs+SPhitlerwalk1, stt+GShitlerdie1, 0},
+	[GShitlerdie1] {nil, yelp, 1, sprs+SPhitlerwalk1, stt+GShitlerdie2, 0},
+	[GShitlerdie2] {nil, nil, 10, sprs+SPhitlerwalk1, stt+GShitlerdie3, 0},
+	[GShitlerdie3] {nil, slurp, 10, sprs+SPhitlerdie1, stt+GShitlerdie4, 0},
+	[GShitlerdie4] {nil, nil, 10, sprs+SPhitlerdie2, stt+GShitlerdie5, 0},
+	[GShitlerdie5] {nil, nil, 10, sprs+SPhitlerdie3, stt+GShitlerdie6, 0},
+	[GShitlerdie6] {nil, nil, 10, sprs+SPhitlerdie4, stt+GShitlerdie7, 0},
+	[GShitlerdie7] {nil, nil, 10, sprs+SPhitlerdie5, stt+GShitlerdie8, 0},
+	[GShitlerdie8] {nil, nil, 10, sprs+SPhitlerdie6, stt+GShitlerdie9, 0},
+	[GShitlerdie9] {nil, nil, 10, sprs+SPhitlerdie7, stt+GShitlerdie10, 0},
+	[GShitlerdie10] {nil, cam, 20, sprs+SPhitlerdead, stt+GShitlerdie10, 0},
+	[GSgh1chase1] {ughost, nil, 10, sprs+SPgh1walk1, stt+GSgh1chase2, 0},
+	[GSgh2chase1] {ughost, nil, 10, sprs+SPgh3walk1, stt+GSgh2chase2, 0},
+	[GSgh3chase1] {ughost, nil, 10, sprs+SPgh2walk1, stt+GSgh3chase2, 0},
+	[GSgh4chase1] {ughost, nil, 10, sprs+SPgh2walk1, stt+GSgh4chase2, 0},
+	[GSgh1chase2] {ughost, nil, 10, sprs+SPgh1walk2, stt+GSgh1chase1, 0},
+	[GSgh2chase2] {ughost, nil, 10, sprs+SPgh3walk2, stt+GSgh2chase1, 0},
+	[GSgh3chase2] {ughost, nil, 10, sprs+SPgh2walk2, stt+GSgh3chase1, 0},
+	[GSgh4chase2] {ughost, nil, 10, sprs+SPgh2walk2, stt+GSgh4chase1, 0},
+	[GStrans] {uwait, nil, 0, sprs+SPtranswalk1, stt+GStrans, 0},
+	[GStranschase1] {uchase, nil, 10, sprs+SPtranswalk1, stt+GStranschase2, 0},
+	[GStranschase2] {nil, nil, 3, sprs+SPtranswalk1, stt+GStranschase3, 0},
+	[GStranschase3] {uchase, nil, 8, sprs+SPtranswalk2, stt+GStranschase4, 0},
+	[GStranschase4] {uchase, nil, 10, sprs+SPtranswalk3, stt+GStranschase5, 0},
+	[GStranschase5] {nil, nil, 3, sprs+SPtranswalk3, stt+GStranschase6, 0},
+	[GStranschase6] {uchase, nil, 8, sprs+SPtranswalk4, stt+GStranschase1, 0},
+	[GStransfire1] {nil, nil, 30, sprs+SPtransfire1, stt+GStransfire2, 0},
+	[GStransfire2] {nil, fire, 10, sprs+SPtransfire2, stt+GStransfire3, 0},
+	[GStransfire3] {nil, fire, 10, sprs+SPtransfire3, stt+GStransfire4, 0},
+	[GStransfire4] {nil, fire, 10, sprs+SPtransfire2, stt+GStransfire5, 0},
+	[GStransfire5] {nil, fire, 10, sprs+SPtransfire3, stt+GStransfire6, 0},
+	[GStransfire6] {nil, fire, 10, sprs+SPtransfire2, stt+GStransfire7, 0},
+	[GStransfire7] {nil, fire, 10, sprs+SPtransfire3, stt+GStransfire8, 0},
+	[GStransfire8] {nil, nil, 10, sprs+SPtransfire1, stt+GStranschase1, 0},
+	[GStransdie1] {nil, yelp, 1, sprs+SPtranswalk1, stt+GStransdie2, 0},
+	[GStransdie2] {nil, nil, 1, sprs+SPtranswalk1, stt+GStransdie3, 0},
+	[GStransdie3] {nil, nil, 15, sprs+SPtransdie1, stt+GStransdie4, 0},
+	[GStransdie4] {nil, nil, 15, sprs+SPtransdie2, stt+GStransdie5, 0},
+	[GStransdie5] {nil, nil, 15, sprs+SPtransdie3, stt+GStransdie6, 0},
+	[GStransdie6] {nil, nil, 0, sprs+SPtransdead, stt+GStransdie6, 0},
+	[GSwilh] {uwait, nil, 0, sprs+SPwilhwalk1, stt+GSwilh, 0},
+	[GSwilhchase1] {uboss, nil, 10, sprs+SPwilhwalk1, stt+GSwilhchase2, 0},
+	[GSwilhchase2] {nil, nil, 3, sprs+SPwilhwalk1, stt+GSwilhchase3, 0},
+	[GSwilhchase3] {uboss, nil, 8, sprs+SPwilhwalk2, stt+GSwilhchase4, 0},
+	[GSwilhchase4] {uboss, nil, 10, sprs+SPwilhwalk3, stt+GSwilhchase5, 0},
+	[GSwilhchase5] {nil, nil, 3, sprs+SPwilhwalk3, stt+GSwilhchase6, 0},
+	[GSwilhchase6] {uboss, nil, 8, sprs+SPwilhwalk4, stt+GSwilhchase1, 0},
+	[GSwilhfire1] {nil, nil, 30, sprs+SPwilhfire1, stt+GSwilhfire2, 0},
+	[GSwilhfire2] {nil, launch, 10, sprs+SPwilhfire2, stt+GSwilhfire3, 0},
+	[GSwilhfire3] {nil, fire, 10, sprs+SPwilhfire3, stt+GSwilhfire4, 0},
+	[GSwilhfire4] {nil, fire, 10, sprs+SPwilhfire4, stt+GSwilhfire5, 0},
+	[GSwilhfire5] {nil, fire, 10, sprs+SPwilhfire3, stt+GSwilhfire6, 0},
+	[GSwilhfire6] {nil, fire, 10, sprs+SPwilhfire4, stt+GSwilhchase1, 0},
+	[GSwilhdie1] {nil, yelp, 1, sprs+SPwilhwalk1, stt+GSwilhdie2, 0},
+	[GSwilhdie2] {nil, nil, 10, sprs+SPwilhwalk1, stt+GSwilhdie3, 0},
+	[GSwilhdie3] {nil, nil, 10, sprs+SPwilhdie1, stt+GSwilhdie4, 0},
+	[GSwilhdie4] {nil, nil, 10, sprs+SPwilhdie2, stt+GSwilhdie5, 0},
+	[GSwilhdie5] {nil, nil, 10, sprs+SPwilhdie3, stt+GSwilhdie6, 0},
+	[GSwilhdie6] {nil, nil, 20, sprs+SPwilhdead, stt+GSwilhdie6, 0},
+	[GSuber] {uwait, nil, 0, sprs+SPuberwalk1, stt+GSuber, 0},
+	[GSuberchase1] {uchase, nil, 10, sprs+SPuberwalk1, stt+GSuberchase2, 0},
+	[GSuberchase2] {nil, nil, 3, sprs+SPuberwalk1, stt+GSuberchase3, 0},
+	[GSuberchase3] {uchase, nil, 8, sprs+SPuberwalk2, stt+GSuberchase4, 0},
+	[GSuberchase4] {uchase, nil, 10, sprs+SPuberwalk3, stt+GSuberchase5, 0},
+	[GSuberchase5] {nil, nil, 3, sprs+SPuberwalk3, stt+GSuberchase6, 0},
+	[GSuberchase6] {uchase, nil, 8, sprs+SPuberwalk4, stt+GSuberchase1, 0},
+	[GSuberfire1] {nil, nil, 30, sprs+SPuberfire1, stt+GSuberfire2, 0},
+	[GSuberfire2] {nil, uberfire, 12, sprs+SPuberfire2, stt+GSuberfire3, 0},
+	[GSuberfire3] {nil, uberfire, 12, sprs+SPuberfire3, stt+GSuberfire4, 0},
+	[GSuberfire4] {nil, uberfire, 12, sprs+SPuberfire4, stt+GSuberfire5, 0},
+	[GSuberfire5] {nil, uberfire, 12, sprs+SPuberfire3, stt+GSuberfire6, 0},
+	[GSuberfire6] {nil, uberfire, 12, sprs+SPuberfire2, stt+GSuberfire7, 0},
+	[GSuberfire7] {nil, nil, 12, sprs+SPuberfire1, stt+GSuberchase1, 0},
+	[GSuberdie1] {nil, yelp, 1, sprs+SPuberwalk1, stt+GSuberdie2, 0},
+	[GSuberdie2] {nil, nil, 1, sprs+SPuberwalk1, stt+GSuberdie3, 0},
+	[GSuberdie3] {nil, nil, 15, sprs+SPuberdie1, stt+GSuberdie4, 0},
+	[GSuberdie4] {nil, nil, 15, sprs+SPuberdie2, stt+GSuberdie5, 0},
+	[GSuberdie5] {nil, nil, 15, sprs+SPuberdie3, stt+GSuberdie6, 0},
+	[GSuberdie6] {nil, nil, 15, sprs+SPuberdie4, stt+GSuberdie7, 0},
+	[GSuberdie7] {nil, nil, 0, sprs+SPuberdead, stt+GSuberdie7, 0},
+	[GSknight] {uwait, nil, 0, sprs+SPknightwalk1, stt+GSknight, 0},
+	[GSknightchase1] {uboss, nil, 10, sprs+SPknightwalk1, stt+GSknightchase2, 0},
+	[GSknightchase2] {nil, nil, 3, sprs+SPknightwalk1, stt+GSknightchase3, 0},
+	[GSknightchase3] {uboss, nil, 8, sprs+SPknightwalk2, stt+GSknightchase4, 0},
+	[GSknightchase4] {uboss, nil, 10, sprs+SPknightwalk3, stt+GSknightchase5, 0},
+	[GSknightchase5] {nil, nil, 3, sprs+SPknightwalk3, stt+GSknightchase6, 0},
+	[GSknightchase6] {uboss, nil, 8, sprs+SPknightwalk4, stt+GSknightchase1, 0},
+	[GSknightfire1] {nil, nil, 30, sprs+SPknightfire1, stt+GSknightfire2, 0},
+	[GSknightfire2] {nil, launch, 10, sprs+SPknightfire2, stt+GSknightfire3, 0},
+	[GSknightfire3] {nil, fire, 10, sprs+SPknightfire4, stt+GSknightfire4, 0},
+	[GSknightfire4] {nil, launch, 10, sprs+SPknightfire3, stt+GSknightfire5, 0},
+	[GSknightfire5] {nil, fire, 10, sprs+SPknightfire4, stt+GSknightchase1, 0},
+	[GSknightdie1] {nil, yelp, 1, sprs+SPknightwalk1, stt+GSknightdie2, 0},
+	[GSknightdie2] {nil, nil, 10, sprs+SPknightwalk1, stt+GSknightdie3, 0},
+	[GSknightdie3] {nil, nil, 10, sprs+SPknightdie1, stt+GSknightdie4, 0},
+	[GSknightdie4] {nil, nil, 10, sprs+SPknightdie2, stt+GSknightdie5, 0},
+	[GSknightdie5] {nil, nil, 10, sprs+SPknightdie3, stt+GSknightdie6, 0},
+	[GSknightdie6] {nil, nil, 10, sprs+SPknightdie4, stt+GSknightdie7, 0},
+	[GSknightdie7] {nil, nil, 10, sprs+SPknightdie5, stt+GSknightdie8, 0},
+	[GSknightdie8] {nil, nil, 10, sprs+SPknightdie6, stt+GSknightdie9, 0},
+	[GSknightdie9] {nil, nil, 0, sprs+SPknightdead, stt+GSknightdie9, 0},
+	[GSspectrewait1] {uwait, nil, 10, sprs+SPspectrewalk1, stt+GSspectrewait2, 0},
+	[GSspectrewait2] {uwait, nil, 10, sprs+SPspectrewalk2, stt+GSspectrewait3, 0},
+	[GSspectrewait3] {uwait, nil, 10, sprs+SPspectrewalk3, stt+GSspectrewait4, 0},
+	[GSspectrewait4] {uwait, nil, 10, sprs+SPspectrewalk4, stt+GSspectrewait1, 0},
+	[GSspectrewake] {nil, wake, 10, sprs+SPspectreF4, stt+GSspectrewake, 0},
+	[GSspectrechase1] {ughost, nil, 10, sprs+SPspectrewalk1, stt+GSspectrechase2, 0},
+	[GSspectrechase2] {ughost, nil, 10, sprs+SPspectrewalk2, stt+GSspectrechase3, 0},
+	[GSspectrechase3] {ughost, nil, 10, sprs+SPspectrewalk3, stt+GSspectrechase4, 0},
+	[GSspectrechase4] {ughost, nil, 10, sprs+SPspectrewalk4, stt+GSspectrechase1, 0},
+	[GSspectredie1] {nil, nil, 10, sprs+SPspectreF1, stt+GSspectredie2, 0},
+	[GSspectredie2] {nil, nil, 10, sprs+SPspectreF2, stt+GSspectredie3, 0},
+	[GSspectredie3] {nil, nil, 10, sprs+SPspectreF3, stt+GSspectredie4, 0},
+	[GSspectredie4] {nil, nil, 300, sprs+SPspectreF4, stt+GSspectrewake, 0},
+	[GSangel] {uwait, nil, 0, sprs+SPangelwalk1, stt+GSangel, 0},
+	[GSangelchase1] {uboss, nil, 10, sprs+SPangelwalk1, stt+GSangelchase2, 0},
+	[GSangelchase2] {nil, nil, 3, sprs+SPangelwalk1, stt+GSangelchase3, 0},
+	[GSangelchase3] {uboss, nil, 8, sprs+SPangelwalk2, stt+GSangelchase4, 0},
+	[GSangelchase4] {uboss, nil, 10, sprs+SPangelwalk3, stt+GSangelchase5, 0},
+	[GSangelchase5] {nil, nil, 3, sprs+SPangelwalk3, stt+GSangelchase6, 0},
+	[GSangelchase6] {uboss, nil, 8, sprs+SPangelwalk4, stt+GSangelchase1, 0},
+	[GSangelfire1] {nil, prelaunch, 10, sprs+SPangelfire1, stt+GSangelfire2, 0},
+	[GSangelfire2] {nil, launch, 20, sprs+SPangelfire2, stt+GSangelfire3, 0},
+	[GSangelfire3] {nil, relaunch, 10, sprs+SPangelfire1, stt+GSangelfire2, 0},
+	[GSangeldie1] {nil, yelp, 1, sprs+SPangelwalk1, stt+GSangeldie2, 0},
+	[GSangeldie2] {nil, nil, 1, sprs+SPangelwalk1, stt+GSangeldie3, 0},
+	[GSangeldie3] {nil, slurp, 10, sprs+SPangeldie1, stt+GSangeldie4, 0},
+	[GSangeldie4] {nil, nil, 10, sprs+SPangeldie2, stt+GSangeldie5, 0},
+	[GSangeldie5] {nil, nil, 10, sprs+SPangeldie3, stt+GSangeldie6, 0},
+	[GSangeldie6] {nil, nil, 10, sprs+SPangeldie4, stt+GSangeldie7, 0},
+	[GSangeldie7] {nil, nil, 10, sprs+SPangeldie5, stt+GSangeldie8, 0},
+	[GSangeldie8] {nil, nil, 10, sprs+SPangeldie6, stt+GSangeldie9, 0},
+	[GSangeldie9] {nil, nil, 10, sprs+SPangeldie7, stt+GSangeldie10, 0},
+	[GSangeldie10] {nil, victory, 130, sprs+SPangeldead, stt+GSangeldie10, 0},
+	[GSangeltired1] {nil, tiredsfx, 40, sprs+SPangeltired1, stt+GSangeltired2, 0},
+	[GSangeltired2] {nil, nil, 40, sprs+SPangeltired2, stt+GSangeltired3, 0},
+	[GSangeltired3] {nil, tiredsfx, 40, sprs+SPangeltired1, stt+GSangeltired4, 0},
+	[GSangeltired4] {nil, nil, 40, sprs+SPangeltired2, stt+GSangeltired5, 0},
+	[GSangeltired5] {nil, tiredsfx, 40, sprs+SPangeltired1, stt+GSangeltired6, 0},
+	[GSangeltired6] {nil, nil, 40, sprs+SPangeltired2, stt+GSangeltired7, 0},
+	[GSangeltired7] {nil, tiredsfx, 40, sprs+SPangeltired1, stt+GSangelchase1, 0},
+	[GSmissile] {uprj, smoke, 3, sprs+SPmissile1, stt+GSmissile, 1},
+	[GSmsmoke1] {nil, nil, 3, sprs+SPmsmoke1, stt+GSmsmoke2, 0},
+	[GSmsmoke2] {nil, nil, 3, sprs+SPmsmoke2, stt+GSmsmoke3, 0},
+	[GSmsmoke3] {nil, nil, 3, sprs+SPmsmoke3, stt+GSmsmoke4, 0},
+	[GSmsmoke4] {nil, nil, 3, sprs+SPmsmoke4, nil, 0},
+	[GSmboom1] {nil, nil, 6, sprs+SPmboom1, stt+GSmboom2, 0},
+	[GSmboom2] {nil, nil, 6, sprs+SPmboom2, stt+GSmboom3, 0},
+	[GSmboom3] {nil, nil, 6, sprs+SPmboom3, nil, 0},
+	[GSrocket] {uprj, smoke, 3, sprs+SProcket1, stt+GSrocket, 1},
+	[GSrsmoke1] {nil, nil, 3, sprs+SPrsmoke1, stt+GSrsmoke2, 0},
+	[GSrsmoke2] {nil, nil, 3, sprs+SPrsmoke2, stt+GSrsmoke3, 0},
+	[GSrsmoke3] {nil, nil, 3, sprs+SPrsmoke3, stt+GSrsmoke4, 0},
+	[GSrsmoke4] {nil, nil, 3, sprs+SPrsmoke4, nil, 0},
+	[GSrboom1] {nil, nil, 6, sprs+SPrboom1, stt+GSrboom2, 0},
+	[GSrboom2] {nil, nil, 6, sprs+SPrboom2, stt+GSrboom3, 0},
+	[GSrboom3] {nil, nil, 6, sprs+SPrboom3, nil, 0},
+	[GSflame1] {nil, uprj, 6, sprs+SPflame1, stt+GSflame2, 0},
+	[GSflame2] {nil, uprj, 6, sprs+SPflame2, stt+GSflame1, 0},
+	[GSneedle1] {uprj, nil, 6, sprs+SPneedle1, stt+GSneedle2, 0},
+	[GSneedle2] {uprj, nil, 6, sprs+SPneedle2, stt+GSneedle3, 0},
+	[GSneedle3] {uprj, nil, 6, sprs+SPneedle3, stt+GSneedle4, 0},
+	[GSneedle4] {uprj, nil, 6, sprs+SPneedle4, stt+GSneedle1, 0},
+	[GSspark1] {uprj, nil, 6, sprs+SPspark1, stt+GSspark2, 0},
+	[GSspark2] {uprj, nil, 6, sprs+SPspark2, stt+GSspark3, 0},
+	[GSspark3] {uprj, nil, 6, sprs+SPspark3, stt+GSspark4, 0},
+	[GSspark4] {uprj, nil, 6, sprs+SPspark4, stt+GSspark1, 0}
+};
+
+static void
+upal(void)
+{
+	int step;
+
+	if(dmgtc > 0){
+		step = dmgtc / 10;
+		if(step > Cwht - Cred - 1)
+			step = Cwht - Cred - 1;
+		dmgtc -= Δtc;
+		if(dmgtc < 0)
+			dmgtc = 0;
+		if(step > 0)
+			pal = pals[Cred + step];
+	}else if(bonustc > 0){
+		step = bonustc / 6;
+		if(step > Cfad - Cwht - 1)
+			step = Cfad - Cwht - 1;
+		bonustc -= Δtc;
+		if(bonustc < 0)
+			bonustc = 0;
+		if(step > 0)
+			pal = pals[Cwht + step];
+	}else
+		pal = pals[C0];
+}
+
+void
+bonus(Static *s)
+{
+	switch(s->item){
+	case Rstim:
+		if(gm.hp == 100)
+			return;
+		sfx(Shealth2);
+		giveh(25);
+		break;
+	case Rkey1:
+	case Rkey2:
+	case Rkey3:
+	case Rkey4:
+		sfx(Sgetkey);
+		givek(s->item - Rkey1);
+		break;
+	case Rcross:
+		sfx(Sbonus1);
+		givep(100);
+		gm.treasure++;
+		break;
+	case Rchalice:
+		sfx(Sbonus2);
+		givep(500);
+		gm.treasure++;
+		break;
+	case Rbible:
+		sfx(Sbonus3);
+		givep(1000);
+		gm.treasure++;
+		break;
+	case Rcrown:
+		sfx(Sbonus4);
+		givep(5000);
+		gm.treasure++;
+		break;
+	case Rclip1:
+		if(gm.ammo == 99)
+			return;
+		sfx(Sgetammo);
+		givea(8);
+		break;
+	case Rclip2:
+		if(gm.ammo == 99)
+			return;
+		sfx(Sgetammo);
+		givea(4);
+		break;
+	case Rammobox:
+		if(gm.ammo == 99)
+			return;
+		sfx(Sammobox);
+		givea(25);
+		break;
+	case Rmg:
+		sfx(Sgetmg);
+		givew(WPmg);
+		break;
+	case Rchaingun:
+		sfx(Sgetgatling);
+		givew(WPgatling);
+		pic(136, 164, pict[Pgat]);
+		facetc = 0;
+		break;
+	case R1up:
+		sfx(S1up);
+		giveh(99);
+		givea(25);
+		givel();
+		gm.treasure++;
+		break;
+	case Rfood:
+		if(gm.hp == 100)
+			return;
+		sfx(Shealth1);
+		giveh(10);
+		break;
+	case Ralpo:
+		if(gm.hp == 100)
+			return;
+		sfx(Shealth1);
+		giveh(4);
+		break;
+	case Rgibs:
+		if(gm.hp > 10)
+			return;
+		sfx(Sslurp);
+		giveh(1);
+		break;
+	case Rspear:
+		gotspear++;
+		spearx = oplr->x;
+		speary = oplr->y;
+		spearθ = oplr->θ;
+		gm.end = EDup;
+	}
+	bonustc = 6 * (Cfad-Cwht);
+	s->tl = nil;
+}
+
 int
 rnd(void)
 {
@@ -50,20 +2519,68 @@
 void
 gstep(void)
 {
+	if((gm.demo || gm.record) && demfrm-- != 0)
+		return;
+	demfrm = 3;
+	input();
+	noise = 0;
+	uworld();
+	upal();
+	render();
+	gm.lvltc += Δtc;
+	if(dofizz){
+		if(!gm.end)
+			gm.end = EDfizz;
+		gm.fizz++;
+		dofizz = 0;
+		gend();
+		return;
+	}
+	if(ver >= SDM)
+		idleface();
+	out();
+	eatcs();
+	if(gm.end)
+		gend();
 }
 
 void
-dstep(void)
+demo(void)
 {
-	step = mstep;
+	initmap();
+	mapmus();
+	pal = pals[C0];
+	dofizz++;
+	step = gstep;
 }
 
 void
-initg(int r)
+initg(int r, uchar *p)
 {
+	memset(&gm, 0, sizeof gm);
+	if(p != nil){
+		gm.demo++;
+		gm.difc = GDhard;
+		gm.map = p[0];
+		deme = (char*)(p + (p[2]<<8 | p[1]));
+		dem = (char*)p + 4;
+		if((deme-dem) % 3 != 0)
+			sysfatal("initd: invalid demo lump\n");
+		demfrm = 0;
+	}
+	gm.hp = 100;
+	gm.ammo = 8;
+	gm.lives = 3;
+	gm.w = gm.lastw = gm.bestw = WPpistol;
+	gm.to1up = GPextra;
 	rndi = r ? time(nil) & 0xff : 0;
-	cson = 0;
-	toss();
-	kbon++;
-	grab(1);
+	dmgtc = bonustc = facetc = funtc = 0;
+	firing = 0;
+	kon = kold = 0;
+	kΔθ = 0;
+	allrecv = 0;
+	sfxlck = 0;
+	gotspear = 0;
+	if(ver == SOD && gm.map == 20)
+		givek(0);
 }
--- a/heads.h
+++ /dev/null
@@ -1,21 +1,0 @@
-#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	MAXTICS				10
-#define DEMOTICS			4
-
-#define	UPDATETERMINATE	0x0301
-
-extern	u16int	mapwidth,mapheight,tics;
-extern	int		compatability;
-
-extern	u8int		*updateptr;
-extern	u16int	uwidthtable[UPDATEHIGH];
-extern	u16int	blockstarts[UPDATEWIDE*UPDATEHIGH];
-
-extern	u8int		fontcolor,backcolor;
-
-#define SETFONTCOLOR(f,b) fontcolor=f;backcolor=b;
--- /dev/null
+++ b/hub.c
@@ -1,0 +1,742 @@
+#include <u.h>
+#include <libc.h>
+#include <thread.h>
+#include <keyboard.h>
+#include "dat.h"
+#include "fns.h"
+
+extern Channel *csc;
+
+int mtc;
+
+typedef struct Score Score;
+typedef struct Seq Seq;
+typedef struct Item Item;
+typedef struct Menu Menu;
+
+struct Score{
+	char name[58];
+	int n;
+	int lvl;
+	int ep;
+};
+static Score sc[] = {
+	{"id software-'92", 10000, 1},
+	{"Adrian Carmack", 10000, 1},
+	{"John Carmack", 10000, 1},
+	{"Kevin Cloud", 10000, 1},
+	{"Tom Hall", 10000, 1},
+	{"John Romero", 10000, 1},
+	{"Jay Wilbur", 10000, 1},
+};
+
+enum{
+	Lload,
+	Lintro,
+	Ltitle,
+	Lcreds,
+	Lscore,
+	Ldemo,
+	Lcam,
+	Linter,
+	Lwin,
+	Ldecay,
+	Linctl,
+	Lctl,
+	Lcur,
+	Lesc,
+	Lback,
+	Lwait,
+	Lsfxwait,
+	Lack,
+	Lmscore,
+	Lpants,
+	Lquit,
+	Ldie
+};
+struct Seq{
+	int dt;
+	void (*f)(void);
+};
+struct Item{
+	char *s;
+	int c;
+	Menu *m;
+};
+struct Menu{
+	void (*init)(void);
+	Seq *qs;
+	Seq *qe;
+	Menu *m;
+	Col *c;
+	Item *is;
+	Item *ie;
+	Item *ip;
+	int cx;
+	int cy;
+	int cur;
+};
+static Menu *mp, ml[];
+static Seq *mqp;
+
+static char *ends[] = {
+	"Dost thou wish to\nleave with such hasty\nabandon?",
+	"Chickening out...\nalready?",
+	"Press N for more carnage.\nPress Y to be a weenie.",
+	"So, you think you can\nquit this easily, huh?",
+	"Press N to save the world.\nPress Y to abandon it in\nits hour of need.",
+	"Press N if you are brave.\nPress Y to cower in shame.",
+	"Heroes, press N.\nWimps, press Y.",
+	"You are at an intersection.\nA sign says, 'Press Y to quit.'\n>",
+	"For guns and glory, press N.\nFor work and worry, press Y.",
+
+	"Heroes don't quit, but\ngo ahead and press Y\nif you aren't one.",
+	"Press Y to quit,\nor press N to enjoy\nmore violent diversion.",
+	"Depressing the Y key means\nyou must return to the\nhumdrum workday world.",
+	"Hey, quit or play,\nY or N:\nit's your choice.",
+	"Sure you don't want to\nwaste a few more\nproductive hours?",
+	"I think you had better\nplay some more. Please\npress N...please?",
+	"If you are tough, press N.\nIf not, press Y daintily.",
+	"I'm thinkin' that\nyou might wanna press N\nto play more. You do it.",
+	"Sure. Fine. Quit.\nSee if we care.\nGet it over with.\nPress Y."
+};
+static char **quits;
+
+enum{
+	Dbg,
+	Doff,
+	Dbrd,
+	Dbrd2,
+	Dend
+};
+static int mcol[Dend] = {[Dbg] 0x2d, 0};
+
+static uchar **demd;
+static char *demf;
+
+static void (*mclear)(void);
+static void (*stripe)(int);
+
+static void
+wlmclear(void)
+{
+	put(0, 0, Vw, Vh, 0x29);
+}
+static void
+sdmclear(void)
+{
+	pic(0, 0, pict[Pbackdrop]);
+}
+
+static void
+wlstripe(int y)
+{
+	put(0, y, Vw, 24, 0);
+	put(0, y+22, 320, 1, 0x2c);
+}
+static void
+sdstripe(int y)
+{
+	put(0, y, Vw, 22, 0);
+	put(0, y+23, 320, 1, 0);
+}
+
+static void
+outbox(int x, int y, int dx, int dy, int c1, int c2)
+{
+	put(x, y, dx, 1, c2);
+	put(x, y+1, 1, dy-1, c2);
+	put(x, y+dy, dx+1, 1, c1);
+	put(x+dx, y, 1, dy, c1);
+}
+
+static void
+box(int x, int y, int dx, int dy, int col, int out, int out2)
+{
+	put(x+1, y+1, dx-1, dy-1, col);
+	outbox(x, y, dx, dy, out, out2);
+}
+
+static void
+viewbox(void)
+{
+	int x, y;
+
+	x = Vhud - vw.dx / 2 - 1;
+	y = (Vhud - vw.dy) / 2 - 1;
+	put(0, 0, 320, Vhud, 0x7f);
+	box(x, y, vw.dx+1, vw.dy+1, 0, 0x7d, 0);
+	put(x, y+vw.dy+1, 1, 1, 0x7c);
+}
+
+static void
+view(void)
+{
+	viewbox();
+	pic(0, Vhud, pict[Pstat]);
+	hudf();
+	hudh();
+	hudl();
+	hudm();
+	huda();
+	hudk();
+	hudw();
+	hudp();
+}
+
+static void
+fixedw(char *s)
+{
+	char c;
+
+	while(c = *s, c != 0)
+		*s++ = c - '0' + 129;
+}
+
+static void
+reset(Menu *m)
+{
+	Seq *q;
+
+	q = m->qs;
+	mqp = q;
+	mtc = 0;
+	if(m != mp){
+		toss();
+		if(q->f != fadeout && mp != ml+Lpants)
+			pal = pals[C0];
+		mp = m;
+		if(m->init != nil)
+			m->init();
+		if(m->c != nil)
+			fadeop(m->c, q->dt);
+	}
+}
+
+static void
+blink(void)
+{
+	Menu *m;
+
+	m = mp;
+	if(m == ml+Lctl){
+		put(m->cx, m->cy, 24, 16, mcol[Dbg]);
+		pic(m->cx, m->cy, pict[Pcur1]+m->cur);
+	}else if(m == ml+Lquit){
+		if(m->cur == 0)
+			txt(m->cx, m->cy, "_", 0);
+		else
+			put(m->cx, m->cy, fnt->w['_'], fnt->h, 0x17);
+	}
+	out();
+	m->cur ^= 1;
+}
+
+static void
+ask(void)
+{
+	Rune r;
+
+	if(nbrecv(csc, &r) <= 0)
+		return;
+	if(r == 'y'){
+		sfx(Sshoot);
+		reset(ml+Ldie);
+	}
+	else if(r == 'n' || r == Kesc){
+		sfx(Sesc);
+		reset(ml+Lctl);
+	}
+}
+
+static void
+quit(void)
+{
+	int x, y, w, h, curw;
+	char *s, *nl;
+
+	s = quits[nrand(nelem(ends)/2)];
+	h = txth(s);
+	w = txtw(s);
+	nl = strrchr(s, '\n');
+	curw = txtw(nl != nil ? nl+1 : s);
+	w = w > curw+10 ? w : curw+10;
+	y = 200/2 - h/2;
+	x = Vhud - w/2;
+
+	box(x-5, y-5, w+10, h+10, 0x17, 0, 0x13);
+	txtnl(x, y, s, 0);
+	mp->cx = x+curw;
+	mp->cy = y + h - fnt->h;
+}
+
+static void
+ctl(void)
+{
+	Menu *m;
+	Item *i, *s, *e;
+
+	mclear();
+	pic(112, 184, pict[Pmouselback]);
+	stripe(10);
+	pic(80, 0, pict[Popt]);
+	box(68, 52, 178, 6+13*9, mcol[Dbg], mcol[Dbrd2], mcol[Doff]);
+
+	fnt = fnts+1;
+	m = ml+Lctl;
+	s = i = m->is;
+	e = m->ie;
+	do
+		txt(100, 55+13*(i-s), i->s, i->c);
+	while(++i < e);
+	m->cur = 0;
+	m->cx = 72;
+	m->cy = 53+13*(m->ip-s);
+	if(mp == m)
+		mus(Mmenu);
+}
+
+static void
+cursfx(void)
+{
+	sfx(Sdrawgun2);
+}
+
+static void
+movcur(Menu *m, Item *p, int dir)
+{
+	Item *i;
+
+	p->c = 0x17;
+	i = p;
+	do{
+		i += dir;
+		if(i < m->is)
+			i = m->ie-1;
+		else if(i == m->ie)
+			i = m->is;
+	}while(i->c != 0x17);
+	i->c = 0x13;
+	m->ip = i;
+	m->cur = 0;
+	if(i != p+dir){
+		cursfx();
+		reset(ml+Lctl);
+		ctl();
+		return;
+	}
+	put(m->cx, m->cy, 24, 16, mcol[Dbg]);
+	m->cy += dir * 6;
+	blink();
+	sfx(Sdrawgun1);
+	reset(ml+Lcur);
+}
+
+static void
+cwalk(void)
+{
+	Rune r;
+	Menu *m;
+	Item *i;
+	static int p;
+
+	if(nbrecv(csc, &r) <= 0)
+		return;
+	m = mp;
+	i = m->ip;
+	switch(r){
+	case Kup: movcur(m, i, -1); break;
+	case Kdown: movcur(m, i, 1); break;
+	case Kesc: sfx(Sesc); reset(ml+Lquit); break;
+	case 'i': p++; break;
+	case 'd':
+		if(ver == SOD && p == 1)
+			reset(ml+Lpants);
+		break;
+	case '\n':
+		m = i->m;
+		if(m == nil)
+			break;
+		if(m != ml+Lquit && m != ml+Lesc)
+			sfx(Sshoot);
+		reset(m);
+	}
+	if(r != 'i')
+		p = 0;
+}
+
+static void
+inctl(void)
+{
+	Item *i;
+	Menu *m;
+
+	m = ml+Lctl;
+	if(m->ip != nil)
+		m->ip->c = 0x17;
+	i = m->is;
+	m->ip = i;
+	i[0].c = 0x13;
+	i[4].c = mcol[Doff];
+	grab(0);
+	ctl();
+	stopsfx();
+}
+
+static void
+skipstep(void)
+{
+	if(nbrecv(csc, nil) > 0){
+		mqp++;
+		mtc = 0;
+	}
+}
+
+static void
+skiploop(void)
+{
+	if(nbrecv(csc, nil) > 0)
+		reset(ml+Ldecay);
+}
+
+static void
+ack(void)
+{
+	if(nbrecv(csc, nil) > 0)
+		reset(ml+Lback);
+}
+
+static void
+swait(void)
+{
+	if(lastsfx() < 0){
+		reset(ml+Linter);
+		step = mstep;
+	}
+}
+
+static void
+pants(void)
+{
+	pic(0, 0, pict[Pid1]);
+	pic(0, 80, pict[Pid2]);
+	palpic(exts[Eid]);
+	fadeop(mp->c, mp->qs->dt);
+	mus(Mnazjazz);
+}
+
+static void
+iwin(void)
+{
+}
+static void
+win(void)
+{
+}
+
+static void
+iscore(void)
+{
+}
+static void
+inter(void)
+{
+}
+
+static void
+gcont(void)
+{
+	step = gstep;
+	gm.end = 0;
+	gm.fizz = 0;
+}
+
+static void
+camtxt2(void)
+{
+	put(0, 56, Vw, 16, 0x7f);
+	viewbox();
+}
+static void
+camtxt(void)
+{
+	fizzop(-1, 0);
+	pictxt(0, 56, "LET\'S SEE THAT AGAIN!");
+	out();
+}
+
+static void
+indem(void)
+{
+	initg(0, *demd++);
+	if(demd >= epis)
+		demd = dems;
+	view();
+}
+
+static void
+score(void)
+{
+	int x, y;
+	char a[16], b[16];
+	Score *s;
+
+	mclear();
+	stripe(10);
+	pic(48, 0, pict[Pscores]);
+	pic(32, 68, pict[Pname]);
+	pic(160, 68, pict[Plvl]);
+	pic(224, 68, pict[Phigh]);
+
+	fnt = fnts;
+	for(s=sc, y=76; s<sc+nelem(sc); s++, y+=16){
+		txt(32, y, s->name, 0xf);
+
+		sprint(a, "%d", s->lvl);
+		fixedw(a);
+		x = 176 - txtw(a);
+		if(ver == WL6){
+			sprint(b, "E%d/L", s->ep+1);
+			x += txt(x-6, y, b, 0xf) - 6;
+		}
+		txt(x, y, a, 0xf);
+
+		sprint(a, "%d", s->n);
+		fixedw(a);
+		txt(264 - txtw(a), y, a, 0xf);
+	}
+	if(mp == ml+Lmscore)
+		mus(Mroster);
+}
+static void
+sdscore(void)
+{
+	int y;
+	char a[16];
+	Score *s;
+
+	mclear();
+	pic(0, 0, pict[Pscores]);
+
+	fnt = fnts+1;
+	for(s=sc, y=76; s<sc+nelem(sc); s++, y+=16){
+		txt(16, y, s->name, 0x13);
+
+		if(s->lvl == 21)
+			pic(176, y-1, pict[Pspear]);
+		else{
+			sprint(a, "%d", s->lvl);
+			txt(194 - txtw(a), y, a, 0xf);
+		}
+
+		sprint(a, "%d", s->n);
+		txt(292 - txtw(a), y, a, 0xf);
+	}
+	if(mp == ml+Lmscore)
+		mus(Maward);
+}
+
+static void
+creds(void)
+{
+	pic(0, 0, pict[Pcreds]);
+}
+
+static void
+title(void)
+{
+	pic(0, 0, pict[Ptitle1]);
+	mus(Mintro);
+}
+static void
+sdtitle(void)
+{
+	pic(0, 0, pict[Ptitle1]);
+	pic(0, 80, pict[Ptitle2]);
+	palpic(exts[Etitpal]);
+	mus(Mtower);
+}
+
+static void
+intro(void)
+{
+	fill(0x82);
+	pic(216, 110, pict[Ppg13]);
+}
+
+static void
+die(void)
+{
+	threadexitsall(nil);
+}
+
+static Item ictl[] = {
+	{"New Game", 0x17},
+	{"Sound", 0x17},
+	{"Control", 0x17},
+	{"Load Game", 0x17},
+	{"Save Game", 0x17},
+	{"Change View", 0x17},
+	{"View Scores", 0x17, ml+Lmscore},
+	{"Back to Demo", 0x17, ml+Lesc},
+	{"Quit", 0x17, ml+Lquit}
+};
+
+static Col fblk, fmenu = { 0xae, 0, 0 };
+static Seq *mqp,
+	introq[] = {{30, fadein}, {7*Tb, skiploop}, {30, fadeout}},
+	titleq[] = {{30, fadein}, {15*Tb, skiploop}, {30, fadeout}},
+	loopq[] = {{30, fadein}, {10*Tb, skiploop}, {30, fadeout}},
+	scoreq[] = {{30, fadein}, {10*Tb, skiploop}, {30, fadeout}},
+	demoq[] = {{30, fadein}, {1, demo}, {41, fizz}, {1, gcont}, {30, fadeout}},
+	camq[] = {{100, nil}, {144, fizz}, {0, camtxt}, {300, skipstep}, {0, camtxt2}, {41, fizz}, {1, gcont}, {100, nil}, {30, fadeout}},
+	interq[] = {{30, fadein}, {0, iscore}, {30, fadeout}},
+	winq[] = {{30, fadein}, {0, iwin}, {30, fadeout}},
+	decq[] = {{30, fadeout}},
+	inctlq[] = {{10, fadein}},
+	ctlq[] = {{0, blink}, {70, cwalk}, {0, blink}, {8, cwalk}},
+	curq[] = {{8, nil}, {0, cursfx}},
+	escq[] = {{10, fadeout}},
+	backq[] = {{10, fadeout}, {0, ctl}, {10, fadein}},
+	waitq[] = {{1, skiploop}},
+	swaitq[] = {{1, swait}},
+	ackq[] = {{1, ack}},
+	mscoreq[] = {{10, fadeout}, {0, score}, {10, fadein}},
+	pantsq[] = {{30, fadeout}, {0, pants}, {30, fadein}},
+	quitq[] = {{0, blink}, {10, ask}},
+	dieq[] = {{10, fadeout}, {1, die}};
+
+static Menu *mp, ml[] = {
+	[Lload] {nil, decq, decq+nelem(decq), ml+Lintro, &fblk},
+	[Lintro] {intro, introq, introq+nelem(introq), ml+Ltitle, &fblk},
+	[Ltitle] {title, titleq, titleq+nelem(titleq), ml+Lcreds, &fblk},
+	[Lcreds] {creds, loopq, loopq+nelem(loopq), ml+Lscore, &fblk},
+	[Lscore] {score, loopq, loopq+nelem(loopq), ml+Ldemo, &fblk},
+	[Ldemo] {indem, demoq, demoq+nelem(demoq), nil, &fblk},
+	[Lcam] {nil, camq, camq+nelem(camq), nil},
+	[Linter] {inter, interq, interq+nelem(interq), nil, &fblk},
+	[Lwin] {win, winq, winq+nelem(winq), nil, &fblk},
+	[Ldecay] {nil, decq, decq+nelem(decq), ml+Linctl},
+	[Linctl] {inctl, inctlq, inctlq+nelem(inctlq), ml+Lctl, &fblk},
+	[Lctl] {ctl, ctlq, ctlq+nelem(ctlq), ml+Lctl, nil, ictl, ictl+nelem(ictl)},
+	[Lcur] {nil, curq, curq+nelem(curq), ml+Lctl},
+	[Lesc] {nil, escq, escq+nelem(escq), ml+Ltitle, &fblk},
+	[Lback] {nil, backq, backq+nelem(backq), ml+Lctl, &fmenu},
+	[Lwait] {nil, waitq, waitq+nelem(waitq), ml+Lwait},
+	[Lsfxwait] {nil, swaitq, swaitq+nelem(swaitq), ml+Lsfxwait},
+	[Lack] {nil, ackq, ackq+nelem(ackq), ml+Lack},
+	[Lmscore] {nil, mscoreq, mscoreq+nelem(mscoreq), ml+Lack, &fmenu},
+	[Lpants] {nil, pantsq, pantsq+nelem(pantsq), ml+Lwait, &fblk},
+	[Lquit] {quit, quitq, quitq+nelem(quitq), ml+Lquit},
+	[Ldie] {nil, dieq, dieq+nelem(dieq), nil, &fmenu}
+};
+
+static void
+dend(void)
+{
+	gm.demo = gm.record = 0;
+	pal = pals[Cfad];
+	if(demf != nil){
+		if(demexit)
+			threadexitsall(nil);
+		free(demf);
+		demf = nil;
+		demd = dems;
+	}
+}
+void
+gend(void)
+{
+	switch(gm.end){
+	case EDfizz:
+		fizzop(-1, 1);
+		put((Vw - vw.dx) / 2, (Vhud - vw.dy) / 2, vw.dx, vw.dy, 0);
+		out();
+		break;
+	enddem:
+	case EDdem:
+		dend();
+		mp->m = ml+Ltitle;
+		break;
+	case EDcam:
+		fizzop(0x7f, 1);
+		reset(ml+Lcam);
+		mp->m = gm.demo || gm.record ? ml+Ltitle : ml+Lwin;
+		gm.fizz++;
+		break;
+	case EDcam2:
+		if(gm.demo || gm.record)
+			dend();
+		else
+			pal = pals[Cfad];
+		break;
+	case EDkey:
+		dend();
+		mp->m = ml+Linctl;
+		break;
+	case EDdie:
+		if(gm.demo || gm.record)
+			goto enddem;
+		break;
+	case EDup:
+	case EDsetec:
+	case EDwon:
+		if(gm.demo || gm.record)
+			goto enddem;
+		mp->m = ml+Lsfxwait;
+		break;
+	}
+	step = mstep;
+}
+
+void
+mstep(void)
+{
+	Menu *m;
+	Seq *q;
+
+rep:
+	m = mp;
+	q = mqp;
+	mtc += Δtc;
+	if(q->f != nil)
+		q->f();
+	if(mtc >= q->dt){
+		if(++mqp == m->qe)
+			reset(m->m);
+		mtc = 0;
+	}
+	if(q->dt == 0)
+		goto rep;
+}
+
+void
+init(char *f)
+{
+	tab();
+	mclear = wlmclear;
+	stripe = wlstripe;
+	quits = ends;
+	if(ver >= SDM){
+		mclear = sdmclear;
+		stripe = sdstripe;
+		ml[Ltitle].init = sdtitle;
+		ml[Lscore].init = sdscore;
+		mscoreq[1].f = sdscore;
+		fmenu = (Col){0, 0, 0xce};
+		mcol[Dbg] = 0x9d;
+		quits += nelem(ends)/2;
+	}
+	mcol[Doff] = mcol[Dbg] ^ 6;
+	mcol[Dbrd] = mcol[Dbg] ^ 4;
+	mcol[Dbrd2] = mcol[Dbg] ^ 14;
+	demd = dems;
+	reset(ml+Lload);
+	setvw(15);
+	if(f != nil){
+		demf = demof(f);
+		demd = (uchar **)&demf;
+		mp->m = ml+Ldemo;
+	}
+	mus(ver<SDM ? Mintro : Mtower);
+}
--- a/in.c
+++ b/in.c
@@ -1,15 +1,62 @@
-		int		Keyboard[NumCodes];
+#define	MaxPlayers	4
+#define	NumCodes	128
 
-		KeyboardDef	KbdDefs = {0x1d,0x38,0x47,0x48,0x49,0x4b,0x4d,0x4f,0x50,0x51};
-		ControlType	Controls[MaxPlayers];
+// 	Stuff for the mouse
+#define	MReset		0
+#define	MButtons	3
+#define	MDelta		11
 
-		Demo		DemoMode = demo_Off;
-		u8int _seg	*DemoBuffer;
-		u16int		DemoOffset,DemoSize;
+#define	MouseInt	0x33
+#define	Mouse(x)	_AX = x,geninterrupt(MouseInt)
 
+typedef	enum		{
+						demo_Off,demo_Record,demo_Playback,demo_PlayDone
+					} Demo;
+typedef	enum		{
+						ctrl_Keyboard,
+							ctrl_Keyboard1 = ctrl_Keyboard,ctrl_Keyboard2,
+						ctrl_Mouse
+					} ControlType;
+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	struct		{
+						int		button0,button1,button2,button3;
+						s16int			x,y;
+						Motion		xaxis,yaxis;
+						Direction	dir;
+					} CursorInfo;
+typedef	CursorInfo	ControlInfo;
+typedef	struct		{
+						u8int	button0,button1,
+									upleft,		up,		upright,
+									left,				right,
+									downleft,	down,	downright;
+					} KeyboardDef;
 
+// Function prototypes
+#define	IN_KeyDown(code)	(Keyboard[(code)])
+#define	IN_ClearKey(code)	{Keyboard[code] = false;\
+							if (code == LastScan) LastScan = sc_None;}
+								
+int		Keyboard[NumCodes];
+KeyboardDef	KbdDefs = {0x1d,0x38,0x47,0x48,0x49,0x4b,0x4d,0x4f,0x50,0x51};
+ControlType	Controls[MaxPlayers];
+Demo		DemoMode = demo_Off;
+u8int _seg	*DemoBuffer;
+u16int		DemoOffset,DemoSize;
+
 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
--- a/in.h
+++ /dev/null
@@ -1,60 +1,0 @@
-#define	MaxPlayers	4
-#define	NumCodes	128
-
-// 	Stuff for the mouse
-#define	MReset		0
-#define	MButtons	3
-#define	MDelta		11
-
-#define	MouseInt	0x33
-#define	Mouse(x)	_AX = x,geninterrupt(MouseInt)
-
-typedef	enum		{
-						demo_Off,demo_Record,demo_Playback,demo_PlayDone
-					} Demo;
-typedef	enum		{
-						ctrl_Keyboard,
-							ctrl_Keyboard1 = ctrl_Keyboard,ctrl_Keyboard2,
-						ctrl_Mouse
-					} ControlType;
-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	struct		{
-						int		button0,button1,button2,button3;
-						s16int			x,y;
-						Motion		xaxis,yaxis;
-						Direction	dir;
-					} CursorInfo;
-typedef	CursorInfo	ControlInfo;
-typedef	struct		{
-						u8int	button0,button1,
-									upleft,		up,		upright,
-									left,				right,
-									downleft,	down,	downright;
-					} KeyboardDef;
-// Global variables
-extern	int		Keyboard[], MousePresent;
-extern	int		Paused;
-extern	char		LastASCII;
-extern	u8int	LastScan;
-extern	KeyboardDef	KbdDefs;
-extern	ControlType	Controls[MaxPlayers];
-
-extern	Demo		DemoMode;
-extern	u8int _seg	*DemoBuffer;
-extern	u16int		DemoOffset,DemoSize;
-
-// Function prototypes
-#define	IN_KeyDown(code)	(Keyboard[(code)])
-#define	IN_ClearKey(code)	{Keyboard[code] = false;\
-							if (code == LastScan) LastScan = sc_None;}
--- a/inter.c
+++ b/inter.c
@@ -142,15 +142,15 @@
 	ClearSplitVWB ();
 
 	VWB_Bar (0,0,320,200-STATUSLINES,127);
-	Write(18,2,"you win!");
+	pictxt(18*8, 2*8, "YOU WIN!");
 
-	Write(TIMEX,TIMEY-2,"total time");
+	pictxt(TIMEX*8, TIMEY-2*8, "TOTAL TIME");
 
-	Write(12,RATIOY-2,"averages");
+	pictxt(12*8, RATIOY-2*8, "AVERAGES");
 
-	Write(RATIOX+8,RATIOY,"kill    %");
-	Write(RATIOX+4,RATIOY+2,"secret    %");
-	Write(RATIOX,  RATIOY+4,"treasure    %");
+	pictxt(RATIOX+8*8, RATIOY*8, "KILL    %");
+	pictxt(RATIOX+4*8, RATIOY+2*8, "SECRET    %");
+	pictxt(RATIOX*8, RATIOY+4*8, "TREASURE    %");
 
 	VWB_DrawPic (8,4,Pwin);
 
@@ -187,9 +187,9 @@
 	i += 2*8;
 	VWB_DrawPic(i,TIMEY*8,P0+(min%10));
 	i += 2*8;
-	Write(i/8,TIMEY,":");
+	pictxt(i/8*8, TIMEY*8, ":");
 	i += 1*8;
-	VWB_DrawPic(i,TIMEY*8,P0+(sec/10));
+	VWB_DrawPic(i,TIMEY*8,P0+(sec/10));	/* huh? */
 	i += 2*8;
 	VWB_DrawPic(i,TIMEY*8,P0+(sec%10));
 	VW_UpdateScreen ();
@@ -196,15 +196,15 @@
 
 	itoa(kr,tempstr,10);
 	x=RATIOX+24-strlen(tempstr)*2;
-	Write(x,RATIOY,tempstr);
+	pictxt(x*8, RATIOY*8, tempstr);
 
 	itoa(sr,tempstr,10);
 	x=RATIOX+24-strlen(tempstr)*2;
-	Write(x,RATIOY+2,tempstr);
+	pictxt(x*8, RATIOY+2*8, tempstr);
 
 	itoa(tr,tempstr,10);
 	x=RATIOX+24-strlen(tempstr)*2;
-	Write(x,RATIOY+4,tempstr);
+	pictxt(x*8, RATIOY+4*8, tempstr);
 
 
 #ifndef UPLOAD
@@ -212,7 +212,7 @@
 	//
 	// TOTAL TIME VERIFICATION CODE
 	//
-	if (gamestate.difficulty>=gd_medium)
+	if (gamestate.difficulty>=GDmed)
 	{
 		VWB_DrawPic (30*8,TIMEY*8,Ptc);
 		fontnumber = 0;
@@ -248,93 +248,6 @@
 #endif // SPEARDEMO
 }
 
-
-//==========================================================================
-
-/*
-==================
-=
-= PG13
-=
-==================
-*/
-
-void PG13 (void)
-{
-	VW_FadeOut();
-	VWB_Bar(0,0,320,200,0x82);			// background
-
-	VWB_DrawPic (216,110,Ppg13);
-	VW_UpdateScreen ();
-
-	VW_FadeIn();
-	IN_UserInput(TickBase*7);
-
-	VW_FadeOut ();
-}
-
-
-//==========================================================================
-
-void Write(s16int x,s16int y,char *string)
-{
-FIXME: use P0+n, Pa+n
- s16int alpha[]={P0,P1,P2,P3,P4,P5,
-	P6,P7,P8,P9,Pcolon,0,0,0,0,0,0,Pa,Pb,
-	Pc,Pd,Pe,Pf,Pg,Ph,Pi,Pj,Pk,
-	Pl,Pm,Pn,Po,Pp,Pq,Pr,Ps,Pt,
-	Pu,Pv,Pw,Px,Py,Pz};
-
- s16int i,ox,nx,ny;
- char ch;
-
-
- ox=nx=x*8;
- ny=y*8;
- for (i=0;i<strlen(string);i++)
-   if (string[i]=='\n')
-   {
-	nx=ox;
-	ny+=16;
-   }
-   else
-   {
-	ch=string[i];
-	if (ch>='a')
-	  ch-=('a'-'A');
-	ch-='0';
-
-	switch(string[i])
-	{
-	 case '!':
-	   VWB_DrawPic(nx,ny,Pexcl);
-	   nx+=8;
-	   continue;
-
-	 case '\'':
-	   VWB_DrawPic(nx,ny,Papo);
-	   nx+=8;
-	   continue;
-
-	 case ' ': break;
-	 case 0x3a:	// ':'
-
-	   VWB_DrawPic(nx,ny,Pcolon);
-	   nx+=8;
-	   continue;
-
-	 case '%':
-	   VWB_DrawPic(nx,ny,Ppercent);
-	   break;
-
-	 default:
-	   VWB_DrawPic(nx,ny,alpha[ch]);
-	}
-	nx+=16;
-   }
-}
-
-
 //
 // Breathe Mr. BJ!!!
 //
@@ -523,29 +436,29 @@
 		mapon < 17)
 #endif
 	{
-	 Write(14,2,"floor\ncompleted");
+	 pictxt(14*8, 2*8, "FLOOR\nCOMPLETED");
 
-	 Write(14,7,"bonus     0");
-	 Write(16,10,"time");
-	 Write(16,12," par");
+	 pictxt(14*8, 7*8, "BONUS     0");
+	 pictxt(16*8, 10*8, "TIME");
+	 pictxt(16*8, 12*8, " PAR");
 
-	 Write(9,14,"kill ratio    %");
-	 Write(5,16,"secret ratio    %");
-	 Write(1,18,"treasure ratio    %");
+	 pictxt(9*8, 14*8, "KILL RATIO    %");
+	 pictxt(5*8, 16*8, "SECRET RATIO    %");
+	 pictxt(1*8, 18*8, "TREASURE RATIO    %");
 
-	 Write(26,2,itoa(gamestate.mapon+1,tempstr,10));
+	 pictxt(26*8, 2*8, itoa(gamestate.mapon+1,tempstr,10));
 
-	 Write(26,12,parTimes[gamestate.episode*10+mapon].timestr);
+	 pictxt(26*8, 12*8, parTimes[gamestate.episode*10+mapon].timestr);
 
 	 //
 	 // PRINT TIME
 	 //
-	 sec=gamestate.TimeCount/70;
+	 sec=gm.lvltc/70;
 
 	 if (sec > 99*60)		// 99 minutes max
 	   sec = 99*60;
 
-	 if (gamestate.TimeCount<parTimes[gamestate.episode*10+mapon].time*4200)
+	 if (gm.lvltc<parTimes[gamestate.episode*10+mapon].time*4200)
 		timeleft=(parTimes[gamestate.episode*10+mapon].time*4200)/70-sec;
 
 	 min=sec/60;
@@ -556,7 +469,7 @@
 	 i+=2*8;
 	 VWB_DrawPic(i,10*8,P0+(min%10));
 	 i+=2*8;
-	 Write(i/8,10,":");
+	 pictxt(i/8*8, 10*8, ":");
 	 i+=1*8;
 	 VWB_DrawPic(i,10*8,P0+(sec/10));
 	 i+=2*8;
@@ -570,12 +483,12 @@
 	 // FIGURE RATIOS OUT BEFOREHAND
 	 //
 	 kr = sr = tr = 0;
-	 if (gamestate.killtotal)
-		kr=(gamestate.killcount*100)/gamestate.killtotal;
-	 if (gamestate.secrettotal)
-		sr=(gamestate.secretcount*100)/gamestate.secrettotal;
-	 if (gamestate.treasuretotal)
-		tr=(gamestate.treasurecount*100)/gamestate.treasuretotal;
+	 if (gm.nkills)
+		kr=(gm.kills*100)/gm.nkills;
+	 if (gm.nsecret)
+		sr=(gm.secret*100)/gm.nsecret;
+	 if (gm.ntreasure)
+		tr=(gm.treasure*100)/gm.ntreasure;
 
 
 	 //
@@ -588,9 +501,9 @@
 	  {
 	   ltoa((s32int)i*PAR_AMOUNT,tempstr,10);
 	   x=36-strlen(tempstr)*2;
-	   Write(x,7,tempstr);
+	   pictxt(x*8, 7*8, tempstr);
 	   if (!(i%(PAR_AMOUNT/10)))
-		 SD_PlaySound(Sendb1);
+		 sfx(Sendb1);
 	   VW_UpdateScreen();
 	   while(SD_SoundPlaying())
 		 BJ_Breathe();
@@ -599,7 +512,7 @@
 	  }
 
 	  VW_UpdateScreen();
-	  SD_PlaySound(Sendb2);
+	  sfx(Sendb2);
 	  while(SD_SoundPlaying())
 		BJ_Breathe();
 	 }
@@ -614,9 +527,9 @@
 	 {
 	  itoa(i,tempstr,10);
 	  x=RATIOXX-strlen(tempstr)*2;
-	  Write(x,14,tempstr);
+	  pictxt(x*8, 14*8, tempstr);
 	  if (!(i%10))
-		SD_PlaySound(Sendb1);
+		sfx(Sendb1);
 	  VW_UpdateScreen ();
 	  while(SD_SoundPlaying())
 		BJ_Breathe();
@@ -631,9 +544,9 @@
 	   bonus+=PERCENT100AMT;
 	   ltoa(bonus,tempstr,10);
 	   x=(RATIOXX-1)-strlen(tempstr)*2;
-	   Write(x,7,tempstr);
+	   pictxt(x*8, 7*8, tempstr);
 	   VW_UpdateScreen();
-	   SD_PlaySound(S100);
+	   sfx(S100);
 	 }
 	 else
 	 if (!ratio)
@@ -640,10 +553,10 @@
 	 {
 	   VW_WaitVBL(VBLWAIT);
 	   SD_StopSound();
-	   SD_PlaySound(Snobonus);
+	   sfx(Snobonus);
 	 }
 	 else
-	 SD_PlaySound(Sendb2);
+	 sfx(Sendb2);
 
 	 VW_UpdateScreen();
 	 while(SD_SoundPlaying())
@@ -658,9 +571,9 @@
 	 {
 	  itoa(i,tempstr,10);
 	  x=RATIOXX-strlen(tempstr)*2;
-	  Write(x,16,tempstr);
+	  pictxt(x*8, 16*8, tempstr);
 	  if (!(i%10))
-		SD_PlaySound(Sendb1);
+		sfx(Sendb1);
 	  VW_UpdateScreen ();
 	  while(SD_SoundPlaying())
 		BJ_Breathe();
@@ -676,9 +589,9 @@
 	   bonus+=PERCENT100AMT;
 	   ltoa(bonus,tempstr,10);
 	   x=(RATIOXX-1)-strlen(tempstr)*2;
-	   Write(x,7,tempstr);
+	   pictxt(x*8, 7*8, tempstr);
 	   VW_UpdateScreen();
-	   SD_PlaySound(S100);
+	   sfx(S100);
 	 }
 	 else
 	 if (!ratio)
@@ -685,10 +598,10 @@
 	 {
 	   VW_WaitVBL(VBLWAIT);
 	   SD_StopSound();
-	   SD_PlaySound(Snobonus);
+	   sfx(Snobonus);
 	 }
 	 else
-	   SD_PlaySound(Sendb2);
+	   sfx(Sendb2);
 	 VW_UpdateScreen();
 	 while(SD_SoundPlaying())
 	   BJ_Breathe();
@@ -702,9 +615,9 @@
 	 {
 	  itoa(i,tempstr,10);
 	  x=RATIOXX-strlen(tempstr)*2;
-	  Write(x,18,tempstr);
+	  pictxt(x*8, 18*8, tempstr);
 	  if (!(i%10))
-		SD_PlaySound(Sendb1);
+		sfx(Sendb1);
 	  VW_UpdateScreen ();
 	  while(SD_SoundPlaying())
 		BJ_Breathe();
@@ -718,9 +631,9 @@
 	   bonus+=PERCENT100AMT;
 	   ltoa(bonus,tempstr,10);
 	   x=(RATIOXX-1)-strlen(tempstr)*2;
-	   Write(x,7,tempstr);
+	   pictxt(x*8, 7*8, tempstr);
 	   VW_UpdateScreen();
-	   SD_PlaySound(S100);
+	   sfx(S100);
 	 }
 	 else
 	 if (!ratio)
@@ -727,10 +640,10 @@
 	 {
 	   VW_WaitVBL(VBLWAIT);
 	   SD_StopSound();
-	   SD_PlaySound(Snobonus);
+	   sfx(Snobonus);
 	 }
 	 else
-	 SD_PlaySound(Sendb2);
+	 sfx(Sendb2);
 	 VW_UpdateScreen();
 	 while(SD_SoundPlaying())
 	   BJ_Breathe();
@@ -743,15 +656,15 @@
 
 	 itoa(kr,tempstr,10);
 	 x=RATIOXX-strlen(tempstr)*2;
-	 Write(x,14,tempstr);
+	 pictxt(x*8, 14*8, tempstr);
 
 	 itoa(sr,tempstr,10);
 	 x=RATIOXX-strlen(tempstr)*2;
-	 Write(x,16,tempstr);
+	 pictxt(x*8, 16*8, tempstr);
 
 	 itoa(tr,tempstr,10);
 	 x=RATIOXX-strlen(tempstr)*2;
-	 Write(x,18,tempstr);
+	 pictxt(x*8, 18*8, tempstr);
 
 	 bonus=(s32int)timeleft*PAR_AMOUNT+
 		   (PERCENT100AMT*(kr==100))+
@@ -758,10 +671,10 @@
 		   (PERCENT100AMT*(sr==100))+
 		   (PERCENT100AMT*(tr==100));
 
-	 GivePoints(bonus);
+	 givep(bonus);
 	 ltoa(bonus,tempstr,10);
 	 x=36-strlen(tempstr)*2;
-	 Write(x,7,tempstr);
+	 pictxt(x*8, 7*8, tempstr);
 
 	 //
 	 // SAVE RATIO INFORMATION FOR ENDGAME
@@ -777,28 +690,28 @@
 #ifndef SPEARDEMO
 	  switch(mapon)
 	  {
-	   case 4: Write(14,4," trans\n grosse\ndefeated!"); break;
-	   case 9: Write(14,4,"barnacle\nwilhelm\ndefeated!"); break;
-	   case 15: Write(14,4,"ubermutant\ndefeated!"); break;
-	   case 17: Write(14,4," death\n knight\ndefeated!"); break;
-	   case 18: Write(13,4,"secret tunnel\n    area\n  completed!"); break;
-	   case 19: Write(13,4,"secret castle\n    area\n  completed!"); break;
+	   case 4: pictxt(14*8, 4*8, " TRANS\n GROSSE\nDEFEATED!"); break;
+	   case 9: pictxt(14*8, 4*8, "BARNACLE\nWILHELM\nDEFEATED!"); break;
+	   case 15: pictxt(14*8, 4*8, "UBERMUTANT\nDEFEATED!"); break;
+	   case 17: pictxt(14*8, 4*8, " DEATH\n KNIGHT\nDEFEATED!"); break;
+	   case 18: pictxt(13*8, 4*8, "SECRET TUNNEL\n    AREA\n  COMPLETED!"); break;
+	   case 19: pictxt(13*8, 4*8, "SECRET CASTLE\n    AREA\n  COMPLETED!"); break;
 	  }
 #endif
 #else
-	  Write(14,4,"secret floor\n completed!");
+	  pictxt(14*8, 4*8, "SECRET FLOOR\n COMPLETED!");
 #endif
 
-	  Write(10,16,"15000 bonus!");
+	  pictxt(10*8, 16*8, "15000 BONUS!");
 
 	  VW_UpdateScreen();
 	  VW_FadeIn();
 
-	  GivePoints(15000);
+	  givep(15000);
 	}
 
 
-	DrawScore();
+	hudp();
 	VW_UpdateScreen();
 
 	TimeCount=0;
@@ -812,7 +725,7 @@
 #ifdef SPEARDEMO
 	if (gamestate.mapon == 1)
 	{
-		SD_PlaySound (S1up);
+		sfx (S1up);
 		Message ("This concludes your demo\n"
 				 "of Spear of Destiny! Now,\n"
 				 "go to your local software\n"
@@ -867,7 +780,7 @@
 
 void PreloadGraphics(void)
 {
-	DrawLevel ();
+	hudm ();
 	ClearSplitVWB ();			// set up for double buffering in split screen
 
 	VWB_Bar (0,0,320,200-STATUSLINES,127);
--- a/main.c
+++ b/main.c
@@ -1,87 +1,17 @@
-// WL_MAIN.C
-
-#include <conio.h>
-#include "WL_DEF.H"
-#pragma hdrstop
-
-
-/*
-=============================================================================
-
-						   WOLFENSTEIN 3-D
-
-					  An Id Software production
-
-						   by John Carmack
-
-=============================================================================
-*/
-
-/*
-=============================================================================
-
-						 LOCAL CONSTANTS
-
-=============================================================================
-*/
-
-
-#define FOCALLENGTH     (0x5700l)               // in global coordinates
-#define VIEWGLOBAL      0x10000                 // globals visable flush to wall
-
-/*
-=============================================================================
-
-						 GLOBAL VARIABLES
-
-=============================================================================
-*/
-
 char            str[80],str2[20];
 s16int				tedlevelnum;
 int         tedlevel;
-s16int                     dirangle[9] = {0,ANGLES/8,2*ANGLES/8,3*ANGLES/8,4*ANGLES/8,
+s16int  dirangle[9] = {0,ANGLES/8,2*ANGLES/8,3*ANGLES/8,4*ANGLES/8,
 	5*ANGLES/8,6*ANGLES/8,7*ANGLES/8,ANGLES};
 
-//
-// proejection variables
-//
-s32int           focallength;
 u16int        screenofs;
-s16int             viewwidth;
-s16int             viewheight;
-s16int             centerx;
-s16int             shootdelta;                     // pixels away from centerx a target can be
-s32int           scale,maxslope;
-s32int            heightnumerator;
-s16int                     minheightdiv;
 
-
-void            Quit (char *error);
-
-int         startgame,loadedgame;
+int         startgame;
 s16int             mouseadjustment;
 
 char	configname[13]="CONFIG.";
 
 
-/*
-=============================================================================
-
-						 LOCAL VARIABLES
-
-=============================================================================
-*/
-
-
-/*
-====================
-=
-= ReadConfig
-=
-====================
-*/
-
 void ReadConfig(void)
 {
 	s16int                     file;
@@ -112,7 +42,7 @@
 		read(file,&buttonmouse,sizeof(buttonmouse));
 		read(file,&buttonjoy,sizeof(buttonjoy));
 
-		read(file,&viewsize,sizeof(viewsize));
+		read(file,&vw.size,sizeof(vw.size));
 		read(file,&mouseadjustment,sizeof(mouseadjustment));
 
 		close(file);
@@ -159,7 +89,7 @@
 		if (MousePresent)
 			mouseenabled = true;
 
-		viewsize = 15;
+		vw.size = 15;
 		mouseadjustment=5;
 	}
 
@@ -169,15 +99,6 @@
 
 }
 
-
-/*
-====================
-=
-= WriteConfig
-=
-====================
-*/
-
 void WriteConfig(void)
 {
 	s16int                     file;
@@ -204,7 +125,7 @@
 		write(file,&buttonmouse,sizeof(buttonmouse));
 		write(file,&buttonjoy,sizeof(buttonjoy));
 
-		write(file,&viewsize,sizeof(viewsize));
+		write(file,&vw.size,sizeof(vw.size));
 		write(file,&mouseadjustment,sizeof(mouseadjustment));
 
 		close(file);
@@ -211,33 +132,11 @@
 	}
 }
 
-/*
-=====================
-=
-= NewGame
-=
-= Set up new game to start from the beginning
-=
-=====================
-*/
-
 void NewGame (s16int difficulty,s16int episode)
 {
-	memset (&gamestate,0,sizeof(gamestate));
-	gamestate.difficulty = difficulty;
-	gamestate.weapon = gamestate.bestweapon
-		= gamestate.chosenweapon = wp_pistol;
-	gamestate.health = 100;
-	gamestate.ammo = STARTAMMO;
-	gamestate.lives = 3;
-	gamestate.nextextra = EXTRAPOINTS;
-	gamestate.episode=episode;
-
-	startgame = true;
+	→ initg, w/o difficulty, map
 }
 
-//===========================================================================
-
 void DiskFlopAnim(s16int x,s16int y)
 {
  static char which=0;
@@ -259,15 +158,6 @@
  return checksum;
 }
 
-
-/*
-==================
-=
-= SaveTheGame
-=
-==================
-*/
-
 int SaveTheGame(s16int file,s16int x,s16int y)
 {
 	struct diskfree_t dfree;
@@ -330,8 +220,8 @@
 	CA_FarWrite (file,(void far *)actorat,sizeof(actorat));
 	checksum = DoChecksum((u8int far *)actorat,sizeof(actorat),checksum);
 
-	CA_FarWrite (file,(void far *)areaconnect,sizeof(areaconnect));
-	CA_FarWrite (file,(void far *)areabyplayer,sizeof(areabyplayer));
+	CA_FarWrite (file,(void far *)conarea,sizeof(conarea));
+	CA_FarWrite (file,(void far *)plrarea,sizeof(plrarea));
 
 	for (ob = player ; ob ; ob=ob->next)
 	{
@@ -378,16 +268,6 @@
 	return(true);
 }
 
-//===========================================================================
-
-/*
-==================
-=
-= LoadTheGame
-=
-==================
-*/
-
 int LoadTheGame(s16int file,s16int x,s16int y)
 {
 	s32int checksum,oldchecksum;
@@ -410,7 +290,7 @@
 #endif
 
 	DiskFlopAnim(x,y);
-	SetupGameLevel ();
+	initmap ();
 
 	DiskFlopAnim(x,y);
 	CA_FarRead (file,(void far *)tilemap,sizeof(tilemap));
@@ -419,12 +299,12 @@
 	CA_FarRead (file,(void far *)actorat,sizeof(actorat));
 	checksum = DoChecksum((u8int far *)actorat,sizeof(actorat),checksum);
 
-	CA_FarRead (file,(void far *)areaconnect,sizeof(areaconnect));
-	CA_FarRead (file,(void far *)areabyplayer,sizeof(areabyplayer));
+	CA_FarRead (file,(void far *)conarea,sizeof(conarea));
+	CA_FarRead (file,(void far *)plrarea,sizeof(plrarea));
 
 
 
-	InitActorList ();
+	oinit ();
 	DiskFlopAnim(x,y);
 	CA_FarRead (file,(void far *)player,sizeof(*player));
 
@@ -434,7 +314,7 @@
 		CA_FarRead (file,(void far *)&nullobj,sizeof(nullobj));
 		if (nullobj.active == ac_badobject)
 			break;
-		GetNewActor ();
+		onew ();
 	 // don't copy over the links
 		memcpy (new,&nullobj,sizeof(nullobj)-4);
 	}
@@ -471,162 +351,25 @@
 
 	if (oldchecksum != checksum)
 	{
-	 Message("Your Save Game file is,\n"
+		Message("Your Save Game file is,\n"
 		"shall we say, \"corrupted\".\n"
 		"But I'll let you go on and\n"
 		"play anyway....");
 
-	 IN_ClearKeysDown();
-	 IN_Ack();
+		IN_ClearKeysDown();
+		IN_Ack();
 
-	 gamestate.score = 0;
-	 gamestate.lives = 1;
-	 gamestate.weapon =
-	   gamestate.chosenweapon =
-	   gamestate.bestweapon = wp_pistol;
-	 gamestate.ammo = 8;
+		gm.score = 0;
+		gm.lives = 1;
+		gm.w = gm.bestw = gm.lastw = WPpistol;
+		gm.ammo = 8;
 	}
 
 	return true;
 }
 
-/*
-==================
-=
-= BuildTables
-=
-= Calculates:
-=
-= scale                 projection constant
-= sintable/costable     overlapping fractional tables
-=
-==================
-*/
-
-const   float   radtoint = (float)FINEANGLES/2/PI;
-
-void BuildTables (void)
+void SetupWalls (void)	/* map tile values to scaled pics */
 {
-  s16int           i;
-  float         angle,anglestep;
-  double        tang;
-  s32int         value;
-
-
-//
-// calculate fine tangents
-//
-
-	for (i=0;i<FINEANGLES/8;i++)
-	{
-		tang = tan( (i+0.5)/radtoint);
-		finetangent[i] = tang*TILEGLOBAL;
-		finetangent[FINEANGLES/4-1-i] = 1/tang*TILEGLOBAL;
-	}
-
-//
-// costable overlays sintable with a quarter phase shift
-// ANGLES is assumed to be divisable by four
-//
-// The low word of the value is the fraction, the high bit is the sign bit,
-// bits 16-30 should be 0
-//
-
-  angle = 0;
-  anglestep = PI/2/ANGLEQUAD;
-  for (i=0;i<=ANGLEQUAD;i++)
-  {
-	value=GLOBAL1*sin(angle);
-	sintable[i]=
-	  sintable[i+ANGLES]=
-	  sintable[ANGLES/2-i] = value;
-	sintable[ANGLES-i]=
-	  sintable[ANGLES/2+i] = value | 0x80000000l;
-	angle += anglestep;
-  }
-
-}
-
-//===========================================================================
-
-
-/*
-====================
-=
-= CalcProjection
-=
-= Uses focallength
-=
-====================
-*/
-
-void CalcProjection (s32int focal)
-{
-	s16int             i;
-	s32int            intang;
-	float   angle;
-	double  tang;
-	double  planedist;
-	double  globinhalf;
-	s16int             halfview;
-	double  halfangle,facedist;
-
-
-	focallength = focal;
-	facedist = focal+MINDIST;
-	halfview = viewwidth/2;                                 // half view in pixels
-
-//
-// calculate scale value for vertical height calculations
-// and sprite x calculations
-//
-	scale = halfview*facedist/(VIEWGLOBAL/2);
-
-//
-// divide heightnumerator by a posts distance to get the posts height for
-// the heightbuffer.  The pixel height is height>>2
-//
-	heightnumerator = (TILEGLOBAL*scale)>>6;
-	minheightdiv = heightnumerator/0x7fff +1;
-
-//
-// calculate the angle offset from view angle of each pixel's ray
-//
-
-	for (i=0;i<halfview;i++)
-	{
-	// start 1/2 pixel over, so viewangle bisects two middle pixels
-		tang = (s32int)i*VIEWGLOBAL/viewwidth/facedist;
-		angle = atan(tang);
-		intang = angle*radtoint;
-		pixelangle[halfview-1-i] = intang;
-		pixelangle[halfview+i] = -intang;
-	}
-
-//
-// if a point's abs(y/x) is greater than maxslope, the point is outside
-// the view area
-//
-	maxslope = finetangent[pixelangle[0]];
-	maxslope >>= 8;
-}
-
-
-
-//===========================================================================
-
-/*
-===================
-=
-= SetupWalls
-=
-= Map tile values to scaled pics
-=
-===================
-*/
-
-void SetupWalls (void)
-{
 	s16int     i;
 
 	for (i=1;i<MAXWALLTILES;i++)
@@ -636,15 +379,7 @@
 	}
 }
 
-/*
-==========================
-=
-= InitGame
-=
-= Load a few things right away
-=
-==========================
-*/
+#define	PORTTILESHIGH		13		// non displayed port of this size
 
 void InitGame (void)
 {
@@ -653,10 +388,6 @@
 
 	mapon = -1;
 
-//
-// build some tables
-//
-
 	for (i=0;i<MAPSIZE;i++)
 	{
 		farmapylookup[i] = i*64;
@@ -678,20 +409,11 @@
 
 	IntroScreen ();
 
-//
-// load in and lock down some basic chunks
-//
-
 	LoadLatchMem ();
-	BuildTables ();          // trig tables
 	SetupWalls ();
 
-	NewViewSize (viewsize);
+	NewViewSize (vw.size);
 
-
-//
-// initialize variables
-//
 	InitRedShifts ();
 
 	displayofs = PAGE1START;
@@ -698,126 +420,32 @@
 	bufferofs = PAGE2START;
 }
 
-//===========================================================================
-
-/*
-==========================
-=
-= SetViewSize
-=
-==========================
-*/
-
 int SetViewSize (u16int width, u16int height)
 {
-	viewwidth = width&~15;                  // must be divisable by 16
-	viewheight = height&~1;                 // must be even
-	centerx = viewwidth/2-1;
-	shootdelta = viewwidth/10;
-	screenofs = ((200-STATUSLINES-viewheight)/2*SCREENWIDTH+(320-viewwidth)/8);
-
-//
-// calculate trace angles and projection constants
-//
-	CalcProjection (FOCALLENGTH);
-
-//
-// build all needed compiled scalers
-//
-	SetupScaling (viewwidth*1.5);
-	return true;
+	→ setvw()
 }
 
-
 void ShowViewSize (s16int width)
 {
 	s16int     oldwidth,oldheight;
 
-	oldwidth = viewwidth;
-	oldheight = viewheight;
+	oldwidth = vw.dx;
+	oldheight = vw.dy;
 
-	viewwidth = width*16;
-	viewheight = width*16*HEIGHTRATIO;
+	vw.dx = width*16;
+	vw.dy = width*16*HEIGHTRATIO;
 	DrawPlayBorder ();
 
-	viewheight = oldheight;
-	viewwidth = oldwidth;
+	vw.dy = oldheight;
+	vw.dx = oldwidth;
 }
 
-
 void NewViewSize (s16int width)
 {
-	CA_UpLevel ();
-	MM_SortMem ();
-	viewsize = width;
+	vw.size = width;
 	SetViewSize (width*16,width*16*HEIGHTRATIO);
-	CA_DownLevel ();
 }
 
-
-
-//===========================================================================
-
-/*
-==========================
-=
-= Quit
-=
-==========================
-*/
-
-void Quit (char *error)
-{
-	u16int        finscreen;
-	uchar *screen;
-
-	ClearMemory ();
-	if (!*error)
-	{
-	 screen = Eorder;
-	 WriteConfig ();
-	}
-	else
-	{
-	 screen = Eerror;
-	}
-
-	if (error && *error)
-	{
-	  movedata ((u16int)screen,7,0xb800,0,7*160);
-	  gotoxy (10,4);
-	  puts(error);
-	  gotoxy (1,8);
-	  exit(1);
-	}
-	else
-	if (!error || !(*error))
-	{
-		clrscr();
-		movedata ((u16int)screen,7,0xb800,0,4000);
-		gotoxy(1,24);
-//asm	mov	bh,0
-//asm	mov	dh,23	// row
-//asm	mov	dl,0	// collumn
-//asm	mov ah,2
-//asm	int	0x10
-	}
-
-	exit(0);
-}
-
-//===========================================================================
-
-
-
-/*
-=====================
-=
-= DemoLoop
-=
-=====================
-*/
-
 void    DemoLoop (void)
 {
 	static s16int LastDemo;
@@ -848,81 +476,30 @@
 		Quit (NULL);
 	}
 
-
-//
-// main game cycle
-//
-
-
-//	nsize = (s32int)40*1024;
-//	MM_GetPtr(&nullblock,nsize);
-
 	StartCPMusic(INTROSONG);
+	// pg13
 
-	if (!NoWait)
-		PG13 ();
-
 	while (1)
 	{
-		uchar *p = dems;
+		p = dems;
 		while (!NoWait)
 		{
-//
-// title page
-//
-			MM_SortMem ();
-
-#ifdef SPEAR
-			VWB_DrawPic (0,0,Ptitle1);
-			VWB_DrawPic (0,80,Ptitle2);
-			VW_UpdateScreen ();
-			VL_FadeIn(0,255,Etitpal,30);
-#else
-			CA_CacheScreen (Ptitle1);
-			VW_UpdateScreen ();
-			VW_FadeIn();
-#endif
-			if (IN_UserInput(TickBase*15))
-				break;
-			VW_FadeOut();
-//
-// credits page
-//
-			CA_CacheScreen (Pcreds);
-			VW_UpdateScreen();
-			VW_FadeIn ();
-			if (IN_UserInput(TickBase*10))
-				break;
-			VW_FadeOut ();
-//
-// high scores
-//
-			DrawHighScores ();
-			VW_UpdateScreen ();
-			VW_FadeIn ();
-
-			if (IN_UserInput(TickBase*10))
-				break;
-//
-// demo
-//
+			/* title loop */
 			PlayDemo(p++);
 			if(p >= epis)
 				p = dems;
-
-			if (playstate == ex_abort)
+			if (gm.φ == ex_abort)
 				break;
 			StartCPMusic(INTROSONG);
 		}
 
 		VW_FadeOut ();
-
 		if (Keyboard[sc_Tab] && debug)
 			RecordDemo ();
 		else
 			US_ControlPanel (0);
 
-		if (startgame || loadedgame)
+		if (startgame || gm.load)
 		{
 			GameLoop ();
 			VW_FadeOut();
@@ -930,18 +507,6 @@
 		}
 	}
 }
-
-
-//===========================================================================
-
-
-/*
-==========================
-=
-= main
-=
-==========================
-*/
 
 void main (void)
 {
--- a/man/1/opl2
+++ b/man/1/opl2
@@ -37,7 +37,6 @@
 .IR delay [2]
 .RE
 .PP
-All fields are unsigned.
 Each command specifies a
 .I value
 to be written to an
@@ -48,7 +47,9 @@
 The
 .I delay
 field indicates a multiple of the expected sampling period (the inverse of the expected sampling rate) during which the chip should be sampled before processing the next command.
-Output is therefore triggered by a non-zero delay.
+Output is then triggered by a non-zero delay.
+.I Delay
+is stored as a 16-bit unsigned integer in little-endian byte order.
 .SH "SEE ALSO"
 .IR wl3d (1) ,
 .IR audio (3)
@@ -57,5 +58,5 @@
 first appeared for 9front (May, 2016), based on
 .I fmopl.c
 from the Multiple Arcade Machine Emulator (
-SM MAME
+.SM MAME
 ).
--- a/man/1/wl3d
+++ b/man/1/wl3d
@@ -4,8 +4,11 @@
 .SH SYNOPSIS
 .B wl3d
 [
-.B -23dos
+.B -23dopqs
 ] [
+.B -f
+.I demo
+] [
 .B -m
 .I datadir
 ] [
@@ -37,8 +40,8 @@
 Two additional files contain the initial loading screens,
 .L intro.wl6
 and
-.LR intro.sod .
-The first is used in Wolfenstein 3-D related game versions, the second in Spear of Destiny related game versions.
+.LR intro.sod ,
+used respectively in Wolfenstein 3-D and Spear of Destiny game versions.
 .PP
 At startup, the current working directory is bound over
 .I datadir
@@ -53,6 +56,10 @@
 If these user-specific files exist and
 .I wl3d
 fails to parse them, they are not overwritten.
+The
+.B -m
+parameter is used to change
+.IR datadir .
 .PP
 Several options modify the program's behavior on startup.
 If the
@@ -62,6 +69,9 @@
 and
 .B -x
 optionally sets the game difficulty.
+The
+.B -p
+parameter runs the program at the fastest speed possible for testing purposes.
 .PD
 .SS Game versions
 The engine supports several game versions, each requiring different data files.
@@ -78,10 +88,10 @@
 Wolfenstein 3-D 1.4 shareware
 .TP
 .B -s
-Spear of Destiny
+Spear of Destiny 1.0 retail
 .TP
 .B -o
-Spear of Destiny demo
+Spear of Destiny 1.0 demo
 .TP
 .B -2
 Spear of Destiny Mission 2: Return to Danger
@@ -98,7 +108,25 @@
 .LR sd3 .
 .PD
 Other game versions are unsupported.
+Note that
+.L sd2
+and
+.L sd3
+versions are the same as
+.L sod
+with the exception of substituting some of the data files.
 .PD
+.SS Demo lumps
+.I Wl3d
+can playback a single external demo lump before resuming normal operation, when its path is supplied with the
+.B -f
+parameter.
+The
+.B -q
+parameter causes the program to exit after playback instead.
+The filename's extension, if any, is ignored.
+Regardless, a corresponding game version must be set using the aforementioned command line parameters.
+An incorrect version will cause erroneous playback or a crash.
 .SS Sound and music
 .I Wl3d
 uses
@@ -128,11 +156,11 @@
 .PP
 Copy protection code and the Spear of Destiny Jukebox have been excised.
 .PP
-Menus are implemented differently, and some have been altered in functionality.
+Some cosmetic differences exist.
 .PP
 Game keys are no longer set in the options menu, but rather in the config file.
 A single global configuration file is used, rather than a version dependent one.
-In addition, while savegames are in a compatible format, config files are not.
+Also, while savegames are in a compatible format, config files are not.
 .SH FILES
 .TF /sys/games/lib/wl3d/*
 .TP
@@ -146,8 +174,6 @@
 .IR audio (3) ,
 .IR wl3d (6)
 .SH BUGS
-Timing code may be off, but it's difficult to tell because of other implementation differences with the original engine.
-.PP
 Because of limitations in fmopl.c-based
 .SM OPL2
 emulation, Adlib sound effects crack too much during playback.
@@ -160,7 +186,13 @@
 .PP
 The upsampling implementation for digital sound effects is overkill given the number of constraints.
 .PP
-No special handling is done if the program is unable to run at a framerate of 70 Hz.
+Little is done in case the program is unable to run at a framerate of 70 Hz.
+.PD
+.SS Engine bugs
+Correct demo playback depends on the sound settings used during recording.
+Different settings on playback may cause desynchronization.
+.PD
+Spawned projectiles are not properly cleared when removed and may cause aberrant behavior and demo desynchronization.
 .SH HISTORY
 id Software's Wolfenstein 3-D was released for
 .SM MS-DOS
--- a/man/6/wl3d
+++ b/man/6/wl3d
@@ -4,7 +4,7 @@
 .SH DESCRIPTION
 Several different types of data are used in Wolfenstein 3-D, each stored in specific ways.
 In the description of the data files below, version-specific extensions are omitted.
-Those files are:
+These files are:
 .TF gamemaps
 .TP
 .B audiohed
@@ -14,6 +14,9 @@
 .B audiot
 uncompressed PC Speaker, Adlib, digital effects and music lumps
 .TP
+.B config
+saved game settings and highscores
+.TP
 .B gamemaps
 maps lump
 .TP
@@ -61,6 +64,7 @@
 for Spear of Destiny 1.0 demo and
 .B sod
 for Spear of Destiny 1.0 retail (including mission packs).
+Other versions are outside of the scope of this document.
 .SH SOUND EFFECTS AND MUSIC
 .SS Audiohed
 .RS
@@ -68,7 +72,7 @@
 {
 .IR end [4]
 .IR starts [4]
-.RI }[ nsfx*3-1 ]
+.RI }[ nsfx*3+nimf-1 ]
 .IR end [4]
 .RE
 .PP
@@ -79,8 +83,8 @@
 .I end
 offsets into
 .B audiot
-for sound effects.
-Sound effects are stored contiguously, and the
+for sound effects and music.
+These are stored contiguously, and the
 .I end
 offset of one lump is the
 .I start
@@ -139,6 +143,9 @@
 .RE
 .PP
 Undocumented here.
+Note that
+.I priority
+isn't necessarily the same as that of the Adlib version.
 .SS Adlib sound effect
 .RS
 .IR size [4]
@@ -204,7 +211,7 @@
 .PP
 Instead, sound effects are stored as raw pcm in
 .BR vswap ,
-in a format detailed elsewhere.
+in a format detailed in a different section.
 .SS Music
 .RS
 .IR size [2]
@@ -269,7 +276,7 @@
 2 maps
 .TP
 .B sod
-20 maps
+21 maps
 .PD
 .PP
 Missing maps have an offset of zero.
@@ -309,7 +316,7 @@
 Each map plane is first compressed using
 .SM RLEW,
 then further using what is eponymously refered to as
-.MS Carmack compression.
+.SM Carmack compression.
 .SH GRAPHICS
 Graphics are either static data loaded in the executable, or huffman-compressed lumps contained in
 .BR vgagraph .
@@ -345,7 +352,8 @@
 .IR scr [ n ][]
 .RE
 .PP
-.I Vgagraph contains a series of Huffman-encoded graphics lumps of various types.
+.I Vgagraph
+contains a series of Huffman-encoded graphics lumps of various types.
 Each lump is prefixed by its uncompressed size.
 The first lump,
 .IR pt ,
@@ -384,7 +392,7 @@
 Exactly two fonts are always defined.
 .SM ASCII
 characters within the printable range have valid definitions at the same locations.
-Some characters for special use are defined beyond, such as fixed-width numerals.
+Some characters for special use are defined beyond, such as fixed-width numerals at index 129.
 .SS Pictures
 .RS
 .BR pt :
@@ -431,11 +439,49 @@
 Finally,
 .I end
 contains other fullscreen graphics for specific uses, notably in epilogue sequences.
+.PP
+.RS
+.BR demo :
+.IR map [1]
+.IR size [2]
+.IR pad [1]
+{
+.IR bt [1]
+.IR dx [1]
+.IR dy [1]
+.RI }[ size-4 ]
+.RE
+.PP
+The only metadata contained in demo lumps is
+.IR map ,
+the 0-indexed map number.
+Game version is not recorded.
+Game difficulty is always set to the hardest.
+.I Map
+is followed by the total
+.I size
+of the lump and an unused byte.
+The original
+.SM DOS
+binaries do not record demos bigger than 8192 bytes.
+.PP
+Demos are recorded and played back at a fixed rate of 4 tics per frame.
+.IR Bt ,
+.IR dx ,
+and
+.I dy
+contain player input for the duration of the frame
+and correspond respectively to pressed game keys, total horizontal movement (turning) and total vertical movement (forward displacement) deltas.
+.I Bt
+is a 8-bit array of the main game keys, regardless of input method.
+These are, from least to most significant bit:
+fire, strafe, run, open, knife, pistol, machine gun and gatling gun.
+The movement deltas are bounded from -100 to 100.
 .SS Static data
 Some of the graphics data is stored in the executable and thus cannot be altered.
 These are the base color palette and intro screen.
 The intro screen is a static screen displayed on startup while verifying available memory and hardware, changed depending on the results.
-Both have a
+Each have a
 .B wl1/wl6
 and a
 .B sdm/sod
@@ -493,7 +539,8 @@
 .RI }[ npcm ]
 .RE
 .PP
-Each sample is a 8 bit unsigned integer to be played back at a sampling rate of 7 kHz.
+The sampling rate for this data is 7 kHz.
+Each sample is a 8 bit unsigned integer.
 Pcm lumps are segmented into chunks of 4096 bytes or less.
 .PP
 The very last chunk in
@@ -502,7 +549,7 @@
 .I Index
 is the zero-based index of the lump's first chunk relative to the first pcm chunk.
 .I Size
-is the sum of lengths of the lump's chunks.
+is the sum in bytes of the lengths of the lump's chunks.
 .PP
 The references for each pcm sound effect (different than those for regular sound effects), as well as their number, are hardcoded in the engine:
 .TF wl1
@@ -518,6 +565,8 @@
 .TP
 .B sod
 40 pcms
+.SH "CONFIGURATION FILE AND HIGHSCORES"
+[words]
 .SH "SEE ALSO"
 .IR opl2 (1) ,
 .IR pcmconv (1) ,
--- a/map.c
+++ b/map.c
@@ -3,4 +3,890 @@
 #include "dat.h"
 #include "fns.h"
 
-uchar **maps, *map;
+enum{
+	Nobj = 150,
+	Ndoor = 64,
+	Nstc = 400,
+	Narea = 37
+};
+Tile tiles[Mapa];
+Obj *objs, *ofree, *oplr;
+Door doors[Ndoor], *doore, pusher;
+Static stcs[Nstc], *stce;
+uchar plrarea[Narea], conarea[Narea*Narea];
+int wspr[] = {SPknife, SPpistol, SPmg, SPgatling};
+
+static int stctype[] = {
+	Rnil, Rblock, Rblock, Rblock, Rnil, Rblock, Ralpo, Rblock, Rblock,
+	Rnil, Rblock, Rblock, Rblock, Rblock, Rnil, Rnil, Rblock, Rblock,
+	Rblock, Rnil, Rkey1, Rkey2, Rblock, Rnil, Rfood, Rstim, Rclip1,
+	Rmg, Rchaingun, Rcross, Rchalice, Rbible, Rcrown, R1up, Rgibs, Rblock,
+	Rblock, Rblock, Rgibs, Rblock, Rblock, Rnil, Rnil, Rnil, Rnil,
+	Rblock, Rblock, Rnil, Rclip2, Rammobox, Rblock, Rspear, Rclip2
+};
+static Obj opool[Nobj];
+
+static void
+spawnstc(Tile *tl, int n)
+{
+	if(n >= nelem(stctype))
+		sysfatal("invalid static object type %d", n);
+	if(n > 48 && ver < SDM){
+		fprint(2, "spawnstc: ignoring sod only static obj %d\n", n);
+		return;
+	}
+	stce->f = 0;
+	switch(stctype[n]){
+	case Rnil:
+	case Rclip2:
+		break;
+	case Rblock:
+		tl->o = nil;	
+		tl->to = 1;
+		/* wet floor */
+	case Rcross:
+	case Rchalice:
+	case Rbible:
+	case Rcrown:
+	case R1up:
+		if(!gm.load)
+			gm.ntreasure++;
+		/* wet floor */
+	default:
+		stce->f = OFbonus;
+		stce->item = stctype[n];
+		break;
+	}
+	stce->tl = tl;
+	stce->spr = sprs + (stctype[n] == Rclip2 ? 28 : 2+n);
+	if(++stce == stcs+Nstc)
+		sysfatal("static object overflow");
+}
+
+static void
+rconair(int id)
+{
+	uchar *p, *a;
+
+	a = conarea + id * Narea;
+	p = plrarea;
+	while(p < plrarea+nelem(plrarea)){
+		if(*a && !*p){
+			(*p)++;
+			rconair(p-plrarea);
+		}
+		a++, p++;
+	}
+}
+static void
+conair(void)
+{
+	memset(plrarea, 0, sizeof plrarea);
+	plrarea[oplr->areaid]++;
+	rconair(oplr->areaid);
+}
+
+static void
+dropening(Door *d)
+{
+	int δ, a1, a2, x, y;
+
+	δ = d->dopen;
+	if(δ == 0){
+		a1 = d->tl[d->isvert ? +1 : -Mapdxy].p0 - MTfloor;
+		a2 = d->tl[d->isvert ? -1 : +Mapdxy].p0 - MTfloor;
+		conarea[a1*Narea + a2]++;
+		conarea[a2*Narea + a1]++;
+		conair();
+		if(plrarea[a1]){
+			x = ((d->tl-tiles) % Mapdxy << Dtlshift) + (1<<Dtlshift-1);
+			y = ((d->tl-tiles) / Mapdxy << Dtlshift) + (1<<Dtlshift-1);
+			sfxatt(Sopendoor, 1, x, y);
+		}
+	}
+	δ += Δtc << 10;
+	if(δ >= 0xffff){
+		δ = 0xffff;
+		d->tc = 0;
+		d->φ = DRopen;
+		d->tl->o = nil;
+		d->tl->to = 0;
+	}
+	d->dopen = δ;
+}
+
+static void
+drclosing(Door *d)
+{
+	int δ, a1, a2;
+
+	if(d->tl->to != (d-doors | 0x80) || d->tl == oplr->tl){
+		dropen(d);
+		return;
+	}
+	δ = d->dopen - (Δtc << 10);
+	if(δ <= 0){
+		δ = 0;
+		d->φ = DRshut;
+		a1 = d->tl[d->isvert ? +1 : -Mapdxy].p0 - MTfloor;
+		a2 = d->tl[d->isvert ? -1 : +Mapdxy].p0 - MTfloor;
+		conarea[a1*Narea + a2]--;
+		conarea[a2*Narea + a1]--;
+		conair();
+	}
+	d->dopen = δ;
+}
+
+static void
+drclose(Door *d)
+{
+	int tx, ty;
+	Tile *tl;
+	Obj *o1, *o2;
+
+	tl = d->tl;
+	if(tl->o != nil || tl->to != 0 || tl == oplr->tl)
+		return;
+	tx = (tl-tiles) % Mapdxy;
+	ty = (tl-tiles) / Mapdxy;
+	if(d->isvert){
+		o1 = tl[-1].o;
+		o2 = tl[+1].o;
+		if(oplr->ty == ty
+		&& (oplr->x + Dmin >> Dtlshift == tx
+		|| oplr->x - Dmin >> Dtlshift == tx)
+		|| o1 != nil && o1->x + Dmin >> Dtlshift == tx
+		|| o2 != nil && o2->x - Dmin >> Dtlshift == tx)
+			return;
+	}else{
+		o1 = tl[-Mapdxy].o;
+		o2 = tl[+Mapdxy].o;
+		if(oplr->tx == tx
+		&& (oplr->y + Dmin >> Dtlshift == ty
+		|| oplr->y - Dmin >> Dtlshift == ty)
+		|| o1 != nil && o1->y + Dmin >> Dtlshift == ty
+		|| o2 != nil && o2->y - Dmin >> Dtlshift == ty)
+			return;
+	}
+	if(plrarea[tl->p0 - MTfloor]){
+		tx = (tx << Dtlshift) + (1<<Dtlshift-1);
+		ty = (ty << Dtlshift) + (1<<Dtlshift-1);
+		sfxatt(Sclosedoor, 1, tx, ty);
+	}
+	d->φ = DRclosing;
+	tl->to = d-doors | 0x80;
+}
+
+static void
+drwait(Door *d)
+{
+	d->tc += Δtc;
+	if(d->tc >= 300)
+		drclose(d);
+}
+
+static void
+udoors(void)
+{
+	Door *d;
+
+	if(gm.won)
+		return;
+	for(d=doors; d<doore; d++)
+		switch(d->φ){
+		case DRopen: drwait(d); break;
+		case DRopening: dropening(d); break;
+		case DRclosing: drclosing(d); break;
+		}
+}
+
+static void
+spawndr(Tile *tl, int isvert, int lock)
+{
+	int n;
+	Door *d;
+
+	d = doore;
+	n = d - doors;
+	if(d >= doors + nelem(doors))
+		sysfatal("spawndr: door overflow");
+	d->tl = tl;
+	d->isvert = isvert;
+	d->lock = lock;
+	d->φ = DRshut;
+	d->dopen = 0;
+	tl->o = nil;
+	tl->to = n | 0x80;
+	tl->tl = n | 0x80;
+	if(isvert){
+		tl->p0 = tl[-1].p0;
+		tl[-Mapdxy].tl |= 0x40;
+		tl[+Mapdxy].tl |= 0x40;
+	}else{
+		tl->p0 = tl[-Mapdxy].p0;
+		tl[-1].tl |= 0x40;
+		tl[+1].tl |= 0x40;
+	}
+	doore++;
+}
+
+static void
+upush(void)
+{
+	int n;
+	Tile *tl;
+
+	if(pusher.φ == 0)
+		return;
+	n = pusher.φ >> 7;
+	pusher.φ += Δtc;
+	pusher.dopen = pusher.φ >> 1 & 63;
+	if(pusher.φ >> 7 == n)
+		return;
+	tl = pusher.tl;
+	n = tl->tl & 63;
+	tl->tl = 0;
+	tl->o = nil;
+	tl->to = 0;
+	tl->p0 = oplr->areaid + MTfloor;
+	if(pusher.φ > 256){
+		pusher.φ = 0;
+		return;
+	}
+	switch(pusher.isvert){
+	case θN: pusher.tl -= Mapdxy; tl -= Mapdxy * 2; break;
+	case θE: pusher.tl++; tl += 2; break;
+	case θS: pusher.tl += Mapdxy; tl += Mapdxy * 2; break;
+	case θW: pusher.tl--; tl -= 2; break;
+	}
+	if(tl->o != nil || tl->to != 0){
+		pusher.φ = 0;
+		return;
+	}
+	tl->to = n;
+	tl->tl = n;
+	pusher.tl->tl = n | 0xc0;
+}
+
+static void
+oswap(Obj *o, Obj *r, int z)
+{
+	o->p->n = o->n;
+	o->n->p = o->p;
+	if(z)
+		memset(o, 0, sizeof *o);
+	o->n = r;
+	o->p = r->p;
+	r->p->n = o;
+	r->p = o;
+}
+
+static void
+odel(Obj *o)
+{
+	if(o == oplr)
+		sysfatal("odel: player deletion");
+	oswap(o, ofree, 1);
+}
+
+static void
+oinit(int all)
+{
+	Obj *o, *p;
+
+	memset(opool, 0, sizeof opool);
+	objs = opool;
+	ofree = opool+1;
+	oplr = opool+2;
+	objs->n = objs->p = oplr;
+	oplr->n = oplr->p = objs;
+	p = ofree;
+	o = oplr + 1;
+	while(o < opool + nelem(opool)){
+		o->p = p;
+		p->n = o;
+		p = o;
+		o++;
+	}
+	ofree->p = p;
+	p->n = ofree;
+
+	if(all){
+		memset(plrarea, 0, sizeof plrarea);
+		memset(conarea, 0, sizeof conarea);
+		memset(doors, 0, sizeof doors);
+		memset(stcs, 0, sizeof stcs);
+		doore = doors;
+		stce = stcs;
+	}
+}
+
+static void
+up(Obj *o, Obj **n)
+{
+	if(o->s->up != nil){
+		o->s->up(o);
+		*n = o->n;
+		if(o->s == nil){
+			odel(o);
+			return;
+		}
+	}
+	if(o->f & OFnevermark || o->f & OFnomark && o->tl->o != nil)
+		return;
+	o->tl->o = o;
+	o->tl->to = 0;
+}
+
+static void
+uobj(Obj *o, Obj **n)
+{
+	if(!o->on && !plrarea[o->areaid])
+		return;
+	if((o->f & (OFnomark | OFnevermark)) == 0)
+		o->tl->o = nil;
+	if(o->tc == 0){
+		up(o, n);
+		return;
+	}
+	o->tc -= Δtc;
+	while(o->tc <= 0){
+		if(o->s->act != nil){
+			o->s->act(o);
+			if(o->s == nil){
+				*n = o->n;
+				odel(o);
+				return;
+			}
+		}
+		o->s = o->s->n;
+		*n = o->n;
+		if(o->s == nil){
+			odel(o);
+			return;
+		}
+		if(o->s->dt == 0){
+			o->tc = 0;
+			break;
+		}
+		o->tc += o->s->dt;
+	}
+	up(o, n);
+}
+
+static u16int
+unmark(Tile *tl)
+{
+	u16int n;
+
+	tl->tl = 0;
+	n = tl->p0;
+	if(tl - 1 < tiles || tl - Mapdxy < tiles
+	|| tl + 1 > tiles+nelem(tiles) || tl + Mapdxy > tiles+nelem(tiles))
+		sysfatal("unmark: tile out of range");
+	if(tl[1].p0 >= MTfloor)
+		n = tl[1].p0;
+	if(tl[-Mapdxy].p0 >= MTfloor)
+		n = tl[-Mapdxy].p0;
+	if(tl[Mapdxy].p0 >= MTfloor)
+		n = tl[Mapdxy].p0;
+	if(tl[-1].p0 >= MTfloor)
+		n = tl[-1].p0;
+	return n;
+}
+
+static void
+spawnplr(Tile *tl, int dir)
+{
+	oplr->s = stt+GSplr;
+	oplr->type = Oplr;
+	oplr->on++;
+	oplr->tl = tl;
+	oplr->tx = (tl-tiles) % Mapdxy;
+	oplr->ty = (tl-tiles) / Mapdxy;
+	osetglobal(oplr);
+	oplr->areaid = tl->p0 - MTfloor;
+	oplr->θ = (450 - dir * 90) % 360;
+	oplr->f |= OFnevermark;
+	plrarea[oplr->areaid]++;
+}
+
+static void
+spawnghost(Tile *tl, State *s)
+{
+	Obj *o;
+
+	if(ver >= SDM)
+		return;
+	o = ospawn(tl, s);
+	o->type = Oghost;
+	o->v = 1500;
+	o->θ = θE;
+	o->f |= OFambush;
+	if(!gm.load)
+		gm.nkills++;
+}
+
+static void
+spawnboss(Tile *tl, int type)
+{
+	int hp, θ;
+	State *s;
+	Obj *o;
+
+	/* bug: pcmon checks cut demo playback short before cam can be called
+	 * if they were recorded with pcmon=0 */
+	θ = θnil;
+	s = nil;
+	hp = 0;
+	switch(type){
+	wlonly:
+		if(ver >= SDM){
+			fprint(2, "spawnboss: non-wl6 obj type %d\n", type);
+			return;
+		}
+		break;
+	sdonly:
+		if(ver < SDM){
+			fprint(2, "spawnboss: non-sod obj type %d\n", type);
+			return;
+		}
+		break;
+	case Ohans:
+		s = stt+GShans;
+		hp = gm.difc<GDhard ? 850 + gm.difc * 100 : 1200;
+		θ = θS;
+		goto wlonly;
+	case Oschb:
+		stt[GSschbdie2].dt = pcmon ? 140 : 5;
+		s = stt+GSschb;
+		hp = gm.difc<GDeasy ? 850 : gm.difc<GDmed ? 950
+			: gm.difc<GDhard ? 1550 : 2400;
+		θ = θS;
+		goto wlonly;
+	case Ogretel:
+		s = stt+GSgretel;
+		hp = gm.difc<GDhard ? 850 + gm.difc * 100 : 1200;
+		θ = θN;
+		goto wlonly;
+	case Ootto:
+		stt[GSottodie2].dt = pcmon ? 140 : 5;
+		s = stt+GSotto;
+		hp = gm.difc<GDhard ? 850 + gm.difc * 100 : 1200;
+		θ = θN;
+		goto wlonly;
+	case Ofett:
+		stt[GSfettdie2].dt = pcmon ? 140 : 5;
+		s = stt+GSfett;
+		hp = gm.difc<GDhard ? 850 + gm.difc * 100 : 1200;
+		θ = θS;
+		goto wlonly;
+	case Ofake:
+		stt[GShitlerdie2].dt = pcmon ? 140 : 5;
+		s = stt+GSfake;
+		hp = 200 + 100 * gm.difc;
+		θ = θN;
+		goto wlonly;
+	case Omech:
+		stt[GShitlerdie2].dt = pcmon ? 140 : 5;
+		s = stt+GSmech;
+		hp = gm.difc<GDeasy ? 800 : gm.difc<GDmed ? 950
+			: gm.difc<GDhard ? 1050 : 1200;
+		θ = θS;
+		goto wlonly;
+	case Otrans:
+		if(pcmon)
+			stt[GStransdie2].dt = 105;
+		s = stt+GStrans;
+		hp = gm.difc<GDhard ? 850 + gm.difc * 100 : 1200;
+		goto sdonly;
+	case Owilh:
+		if(pcmon)
+			stt[GSwilhdie2].dt = 70;
+		s = stt+GSwilh;
+		hp = gm.difc<GDhard ? 950 + gm.difc * 100 : 1300;
+		goto sdonly;
+	case Ouber:
+		if(pcmon)
+			stt[GSuberdie2].dt = 70;
+		s = stt+GSuber;
+		hp = gm.difc<GDhard ? 1050 + gm.difc * 100 : 1400;
+		goto sdonly;
+	case Oknight:
+		if(pcmon)
+			stt[GSknightdie2].dt = 105;
+		s = stt+GSknight;
+		hp = gm.difc<GDhard ? 1250 + 100 * gm.difc : 1600;
+		goto sdonly;
+	case Ospectre:
+		s = stt+GSspectrewait1;
+		hp = gm.difc<GDhard ? 5 * (1 + gm.difc) : 25;
+		goto sdonly;
+	case Oangel:
+		if(pcmon)
+			stt[GSangeldie2].dt = 105;
+		s = stt+GSangel;
+		hp = gm.difc<GDhard ? 1450 + 100 * gm.difc : 2000;
+		goto sdonly;
+	}
+	o = ospawn(tl, s);
+	o->type = type;
+	o->hp = hp;
+	o->θ = θ;
+	o->f |= OFshootable | OFambush;
+	if(!gm.load)
+		gm.nkills++;
+}
+
+static void
+spawndeadgd(Tile *tl)
+{
+	Obj *o;
+
+	o = ospawn(tl, stt+GSgddie4);
+	o->type = Oinert;
+}
+
+static void
+spawnguy(Tile *tl, int type, int dir, int patrol)
+{
+	int hp;
+	Obj *o;
+	State *s;
+
+	s = nil;
+	hp = 0;
+	switch(type){
+	case Ogd:
+		s = stt + (patrol ? GSgdwalk1 : GSgd);
+		hp = 25;
+		break;
+	case Oofc:
+		s = stt + (patrol ? GSofcwalk1 : GSofc);
+		hp = 50;
+		break;
+	case Omut:
+		s = stt + (patrol ? GSmutwalk1 : GSmut);
+		hp = gm.difc > GDmed ? 65 : gm.difc > GDbaby ? 55 : 45;
+		break;
+	case Oss:
+		s = stt + (patrol ? GSsswalk1 : GSss);
+		hp = 100;
+		break;
+	case Odog:
+		/* bug: unhandled case causing object pool corruption */
+		if(!patrol)
+			sysfatal("spawnguy: unhandled spawn type");
+		s = stt + GSdogwalk1;
+		hp = 1;
+		break;
+	}
+	o = ospawn(tl, s);
+	if(patrol){
+		tl->o = nil;
+		tl->to = 0;
+		switch(dir){
+		case 0: tl++; o->tx++; break;
+		case 1: tl -= Mapdxy; o->ty--; break;
+		case 2: tl--; o->tx--; break;
+		case 3: tl += Mapdxy; o->ty++; break;
+		}
+		tl->to = 0;
+		tl->o = o;
+		o->tl = tl;
+	}
+	o->type = type;
+	o->f |= OFshootable;
+	o->hp = hp;
+	o->v = type == Odog ? 1500 : 512;
+	o->θ = dir * 90;
+
+	if(!gm.load)
+		gm.nkills++;
+	if(patrol){
+		o->Δr = Dtlglobal;
+		o->on++;
+	}else if(tl->p0 == MTambush){
+		tl->p0 = unmark(tl);
+		o->f |= OFambush;
+		o->areaid = tl->p0 - MTfloor;
+	}
+}
+
+static void
+spawn(Tile *tl)
+{
+	int n, difc;
+
+	n = tl->p1;
+	difc = GDeasy;
+	switch(n){
+	case 19: case 20: case 21: case 22:
+		spawnplr(tl, n-19);
+		break;
+	case 23: case 24: case 25: case 26: case 27: case 28: case 29: case 30:
+	case 31: case 32: case 33: case 34: case 35: case 36: case 37: case 38:
+	case 39: case 40: case 41: case 42: case 43: case 44: case 45: case 46:
+	case 47: case 48: case 49: case 50: case 51: case 52: case 53: case 54:
+	case 55: case 56: case 57: case 58: case 59: case 60: case 61: case 62:
+	case 63: case 64: case 65: case 66: case 67: case 68: case 69: case 70:
+	case 71: case 72: case 73: case 74:
+		spawnstc(tl, n-23);
+		break;
+	case 98:
+		if(!gm.load)
+			gm.nsecret++;
+		break;
+	case 180: case 181: case 182: case 183: difc++;	n-=36; /* wet floor */
+	case 144: case 145: case 146: case 147: difc++;	n-=36; /* wet floor */
+	case 108: case 109: case 110: case 111:
+		if(difc <= gm.difc)
+			spawnguy(tl, Ogd, n-108, 0);
+		break;
+	case 184: case 185: case 186: case 187: difc++;	n-=36; /* wet floor */
+	case 148: case 149: case 150: case 151: difc++;	n-=36; /* wet floor */
+	case 112: case 113: case 114: case 115:
+		if(difc <= gm.difc)
+			spawnguy(tl, Ogd, n-112, 1);
+		break;
+	case 188: case 189: case 190: case 191: difc++;	n-=36; /* wet floor */
+	case 152: case 153: case 154: case 155: difc++;	n-=36; /* wet floor */
+	case 116: case 117: case 118: case 119:
+		if(difc <= gm.difc)
+			spawnguy(tl, Oofc, n-116, 0);
+		break;
+	case 192: case 193: case 194: case 195: difc++;	n-=36; /* wet floor */
+	case 156: case 157: case 158: case 159: difc++;	n-=36; /* wet floor */
+	case 120: case 121: case 122: case 123:
+		if(difc <= gm.difc)
+			spawnguy(tl, Oofc, n-120, 1);
+		break;
+	case 198: case 199: case 200: case 201: difc++;	n-=36; /* wet floor */
+	case 162: case 163: case 164: case 165: difc++;	n-=36; /* wet floor */
+	case 126: case 127: case 128: case 129:
+		if(difc <= gm.difc)
+			spawnguy(tl, Oss, n-126, 0);
+		break;
+	case 202: case 203: case 204: case 205: difc++;	n-=36; /* wet floor */
+	case 166: case 167: case 168: case 169: difc++;	n-=36; /* wet floor */
+	case 130: case 131: case 132: case 133:
+		if(difc <= gm.difc)
+			spawnguy(tl, Oss, n-130, 1);
+		break;
+	case 206: case 207: case 208: case 209: difc++;	n-=36; /* wet floor */
+	case 170: case 171: case 172: case 173: difc++;	n-=36; /* wet floor */
+	case 134: case 135: case 136: case 137:
+		if(difc <= gm.difc)
+			spawnguy(tl, Odog, n-134, 0);
+		break;
+	case 210: case 211: case 212: case 213: difc++;	n-=36; /* wet floor */
+	case 174: case 175: case 176: case 177: difc++;	n-=36; /* wet floor */
+	case 138: case 139: case 140: case 141:
+		if(difc <= gm.difc)
+			spawnguy(tl, Odog, n-138, 1);
+		break;
+	case 252: case 253: case 254: case 255: difc++;	n-=18; /* wet floor */
+	case 234: case 235: case 236: case 237: difc++;	n-=18; /* wet floor */
+	case 216: case 217: case 218: case 219:
+		if(difc <= gm.difc)
+			spawnguy(tl, Omut, n-216, 0);
+		break;
+	case 256: case 257: case 258: case 259: difc++;	n-=18; /* wet floor */
+	case 238: case 239: case 240: case 241: difc++;	n-=18; /* wet floor */
+	case 220: case 221: case 222: case 223:
+		if(difc <= gm.difc)
+			spawnguy(tl, Omut, n-220, 1);
+		break;
+	case 224: case 225: case 226: case 227:
+		spawnghost(tl, stt+GSgh1chase1+n-224);
+		break;
+	case 106: spawnboss(tl, Ospectre); break;
+	case 107: spawnboss(tl, Oangel); break;
+	case 124: spawndeadgd(tl); break;
+	case 125: spawnboss(tl, Otrans); break;
+	case 142: spawnboss(tl, Ouber); break;
+	case 143: spawnboss(tl, Owilh); break;
+	case 160: spawnboss(tl, Ofake); break;
+	case 161: spawnboss(tl, Oknight); break;
+	case 178: spawnboss(tl, Omech); break;
+	case 179: spawnboss(tl, Ofett); break;
+	case 196: spawnboss(tl, Oschb); break;
+	case 197: spawnboss(tl, Ogretel); break;
+	case 214: spawnboss(tl, Ohans); break;
+	case 215: spawnboss(tl, Ootto); break;
+	}
+}
+
+void
+drop(Tile *tl, int n)
+{
+	Static *s;
+	int *sti;
+
+	for(sti=stctype; sti<stctype+nelem(stctype); sti++)
+		if(*sti == n)
+			break;
+	if(sti >= stctype+nelem(stctype))
+		sysfatal("drop: unknown item type");
+	for(s=stcs; s<stcs+nelem(stcs); s++)
+		if(s->tl == nil){
+			if(s == stce)
+				stce++;
+			break;
+		}
+	if(s >= stcs+nelem(stcs))
+		return;
+	s->tl = tl;
+	s->spr = sprs + (n == Rclip2 ? 28 : 2+(sti-stctype));
+	s->f = OFbonus;
+	s->item = n;
+}
+
+void
+dropen(Door *d)
+{
+	if(d->φ == DRopen)
+		d->tc = 0;
+	else
+		d->φ = DRopening;
+}
+
+void
+druse(Door *d)
+{
+	if(d->lock > DRunlk && d->lock < DRup && ~gm.keys & 1<<d->lock-DRlock1){
+		sfx(Snoway);
+		return;
+	}
+	switch(d->φ){
+	case DRshut: case DRclosing: dropen(d); break;
+	case DRopen: case DRopening: drclose(d); break;
+	}
+}
+
+void
+osetglobal(Obj *o)
+{
+	if(o->tx > Mapdxy || o->ty > Mapdxy)
+		sysfatal("object %d,%d out of bounds", o->tx, o->ty);
+	o->x = (o->tx << Dtlshift) + Dtlglobal / 2;
+	o->y = (o->ty << Dtlshift) + Dtlglobal / 2;
+}
+
+void
+ostate(Obj *o, State *s)
+{
+	o->s = s;
+	o->tc = s->dt;
+}
+
+Obj *
+onew(void)
+{
+	Obj *o;
+
+	if(ofree->p == ofree)
+		sysfatal("onew: object list overflow");
+	o = ofree->p;
+	oswap(o, objs, 0);
+	return o;
+}
+
+Obj *
+ospawn(Tile *tl, State *s)
+{
+	Obj *o;
+
+	o = onew();
+	tl->o = o;
+	tl->to = 0;
+	o->tl = tl;
+	o->s = s;
+	o->tx = (tl-tiles) % Mapdxy;
+	o->ty = (tl-tiles) / Mapdxy;
+	osetglobal(o);
+	o->areaid = tl->p0 - MTfloor;
+	o->tc = s->dt != 0 ? rnd() % s->dt : 0;
+	return o;
+}
+
+void
+uworld(void)
+{
+	Obj *o, *n;
+
+	udoors();
+	upush();
+	for(o=oplr; o!=objs; o=n){
+		n = o->n;
+		uobj(o, &n);
+	}
+}
+
+void
+mapmus(void)
+{
+	static char wlmus[] = {
+		3, 11, 9, 12, 3, 11, 9, 12, 2, 0,
+		8, 18, 17, 4, 8, 18, 4, 17, 2, 1,
+		6, 20, 22, 21, 6, 20, 22, 21, 19, 26,
+		3, 11, 9, 12, 3, 11, 9, 12, 2, 0,
+		8, 18, 17, 4, 8, 18, 4, 17, 2, 1,
+		6, 20, 22, 21, 6, 20, 22, 21, 19, 15
+	}, sdmus[] = {
+		4, 0, 2, 22, 15, 1, 5, 9, 10, 15,
+		8, 3, 12, 11, 13, 15, 21, 15, 18, 0, 17
+	};
+
+	mus(ver < SDM ? wlmus[gm.map] : sdmus[gm.map]);
+}
+
+void
+initmap(void)
+{
+	u16int *p0, *p1, *s;
+	Tile *tl;
+
+	oinit(1);
+	memset(tiles, 0, sizeof tiles);
+	p0 = s = readmap(gm.map);
+	p1 = p0 + Mapa;
+	for(tl=tiles; tl<tiles+nelem(tiles); tl++){
+		tl->p0 = *p0++;
+		tl->p1 = *p1++;
+		if(tl->p0 < MTfloor){
+			tl->tl = tl->p0;
+			tl->to = tl->p0;
+		}
+	}
+	free(s);
+	for(tl=tiles; tl<tiles+nelem(tiles); tl++)
+		if(tl->p0 > 89 && tl->p0 < 102)
+			spawndr(tl, ~tl->p0 & 1, (tl->p0 - 90) / 2);
+	for(tl=tiles; tl<tiles+nelem(tiles); tl++)
+		spawn(tl);
+	for(tl=tiles; tl<tiles+nelem(tiles); tl++)
+		if(tl->p0 == MTambush){
+			if(tl->to == MTambush)
+				tl->to = 0;
+			tl->p0 = unmark(tl);
+		}
+}
+
+void
+sodmap(void)
+{
+	int *w;
+	State *s;
+
+	stctype[15] = Rblock;
+	stctype[40] = Rnil;
+	stctype[44] = Rblock;
+	stctype[48] = Rblock;
+	for(s=stt+GSgd; s<stt+GShans; s++)
+		s->spr += 4;
+	for(s=stt+GSmissile; s<stt+GSrocket; s++)
+		s->spr -= SPmissile1 - SPofcfire3 - 1;
+	for(w=wspr; w<wspr+nelem(wspr); w++)
+		*w += SPangeldead - SPbjjump4;
+}
--- a/menu.c
+++ b/menu.c
@@ -343,7 +343,7 @@
 	//
 	// CHANGE MAINMENU ITEM
 	//
-	if (startgame || loadedgame)
+	if (startgame || gm.load)
 	{
 		#pragma warn -sus
 		MainMenu[viewscores].routine = NULL;
@@ -415,7 +415,7 @@
 			WindowH=160;
 			if (Confirm(ENDGAMESTR))
 			{
-				playstate = ex_died;
+				gm.φ = ex_died;
 				pickquick = gamestate.lives = 0;
 			}
 
@@ -446,16 +446,16 @@
 
 				SETFONTCOLOR(0,15);
 				IN_ClearKeysDown();
-				DrawPlayScreen ();
+				view ();
 
-				if (!startgame && !loadedgame)
+				if (!startgame && !gm.load)
 				{
 					VW_FadeIn ();
-					StartMusic ();
+					mapmus ();
 				}
 
-				if (loadedgame)
-					playstate = ex_abort;
+				if (gm.load)
+					gm.φ = ex_abort;
 				lasttimecount = TimeCount;
 
 				if (MousePresent)
@@ -495,16 +495,16 @@
 
 				SETFONTCOLOR(0,15);
 				IN_ClearKeysDown();
-				DrawPlayScreen ();
+				view ();
 
-				if (!startgame && !loadedgame)
+				if (!startgame && !gm.load)
 				{
 					VW_FadeIn ();
-					StartMusic ();
+					mapmus ();
 				}
 
-				if (loadedgame)
-					playstate = ex_abort;
+				if (gm.load)
+					gm.φ = ex_abort;
 
 				lasttimecount = TimeCount;
 
@@ -523,7 +523,7 @@
 			WindowX=WindowY=0;
 			WindowW=320;
 			WindowH=160;
-			if (Confirm(endStrings[US_RndT()&0x7+(US_RndT()&1)]))
+			if (Confirm(endStrings[rnd()&0x7+(rnd()&1)]))
 			{
 				s16int i;
 
@@ -562,7 +562,7 @@
 		return 0;
 
 	pickquick = gamestate.lives = 0;
-	playstate = ex_died;
+	gm.φ = ex_died;
 
 	#pragma warn -sus
 	MainMenu[savegame].active = 0;
@@ -626,7 +626,7 @@
 			default:
 				if (!EpisodeSelect[which/2])
 				{
-					SD_PlaySound (Snoway);
+					sfx (Snoway);
 					Message("Please select \"Read This!\"\n"
 							"from the Options menu to\n"
 							"find out how to order this\n"
@@ -1014,19 +1014,19 @@
 			name[7]=which+'0';
 			handle=open(name,O_BINARY);
 			lseek(handle,32,SEEK_SET);
-			loadedgame=true;
+			gm.load=true;
 			LoadTheGame(handle,0,0);
-			loadedgame=false;
+			gm.load=false;
 			close(handle);
 
-			DrawFace ();
-			DrawHealth ();
-			DrawLives ();
-			DrawLevel ();
-			DrawAmmo ();
-			DrawKeys ();
-			DrawWeapon ();
-			DrawScore ();
+			hudf ();
+			hudh ();
+			hudl ();
+			hudm ();
+			huda ();
+			hudk ();
+			hudw ();
+			hudp ();
 			return 1;
 		}
 	}
@@ -1045,7 +1045,7 @@
 			lseek(handle,32,SEEK_SET);
 
 			DrawLSAction(0);
-			loadedgame=true;
+			gm.load=true;
 
 			LoadTheGame(handle,LSA_X+8,LSA_Y+5);
 			close(handle);
@@ -1234,7 +1234,7 @@
 				VWB_Bar(LSM_X+LSItems.indent+1,LSM_Y+which*13+1,LSM_W-LSItems.indent-16,10,BKGDCOLOR);
 				PrintLSEntry(which,HIGHLIGHT);
 				VW_UpdateScreen();
-				SD_PlaySound(Sesc);
+				sfx(Sesc);
 				continue;
 			}
 
@@ -1370,7 +1370,7 @@
 					DrawOutline(60+20*mouseadjustment,97,20,10,0,READCOLOR);
 					VWB_Bar(61+20*mouseadjustment,98,19,9,READHCOLOR);
 					VW_UpdateScreen();
-					SD_PlaySound(Sdrawgun1);
+					sfx(Sdrawgun1);
 					while(Keyboard[sc_LeftArrow]);
 					WaitKeyUp();
 				}
@@ -1386,7 +1386,7 @@
 					DrawOutline(60+20*mouseadjustment,97,20,10,0,READCOLOR);
 					VWB_Bar(61+20*mouseadjustment,98,19,9,READHCOLOR);
 					VW_UpdateScreen();
-					SD_PlaySound(Sdrawgun1);
+					sfx(Sdrawgun1);
 					while(Keyboard[sc_RightArrow]);
 					WaitKeyUp();
 				}
@@ -1404,10 +1404,10 @@
 	if (exit==2)
 	{
 		mouseadjustment=oldMA;
-		SD_PlaySound(Sesc);
+		sfx(Sesc);
 	}
 	else
-		SD_PlaySound(Sshoot);
+		sfx(Sshoot);
 
 	WaitKeyUp();
 	MenuFadeOut();
@@ -1656,7 +1656,7 @@
 	  case 1:
 	PrintX=x;
 	US_Print("?");
-	SD_PlaySound(Shitwall);
+	sfx(Shitwall);
 	 }
 	 tick^=1;
 	 TimeCount=0;
@@ -1692,7 +1692,7 @@
 
 	buttonmouse[result-1]=order[which];
 	picked=1;
-	SD_PlaySound(Shitdoor);
+	sfx(Shitdoor);
 	   }
 	   break;
 
@@ -1719,7 +1719,7 @@
 
 	buttonjoy[result-1]=order[which];
 	picked=1;
-	SD_PlaySound(Shitdoor);
+	sfx(Shitdoor);
 	   }
 	   break;
 
@@ -1777,7 +1777,7 @@
 	which=3;
 	 } while(!cust->allowed[which]);
 	 redraw=1;
-	 SD_PlaySound(Sdrawgun1);
+	 sfx(Sdrawgun1);
 	 while(ReadAnyControl(&ci),ci.dir!=dir_None);
 	 IN_ClearKeysDown();
 	 break;
@@ -1790,7 +1790,7 @@
 	which=0;
 	 } while(!cust->allowed[which]);
 	 redraw=1;
-	 SD_PlaySound(Sdrawgun1);
+	 sfx(Sdrawgun1);
 	 while(ReadAnyControl(&ci),ci.dir!=dir_None);
 	 IN_ClearKeysDown();
 	 break;
@@ -1800,7 +1800,7 @@
   }
  } while(!exit);
 
- SD_PlaySound(Sesc);
+ sfx(Sesc);
  WaitKeyUp();
  DrawWindow(5,PrintY-1,310,13,BKGDCOLOR);
 }
@@ -2083,7 +2083,7 @@
 	WindowX=WindowY=0;
 	WindowW=320;
 	WindowH=200;
-	newview=oldview=viewwidth/16;
+	newview=oldview=vw.dx/16;
 	DrawChangeView(oldview);
 
 	do
@@ -2099,7 +2099,7 @@
 				newview=4;
 			ShowViewSize(newview);
 			VW_UpdateScreen();
-			SD_PlaySound(Shitwall);
+			sfx(Shitwall);
 			TicDelay(10);
 			break;
 
@@ -2110,7 +2110,7 @@
 				newview=19;
 			ShowViewSize(newview);
 			VW_UpdateScreen();
-			SD_PlaySound(Shitwall);
+			sfx(Shitwall);
 			TicDelay(10);
 			break;
 		}
@@ -2120,8 +2120,8 @@
 		else
 		if (ci.button1 || Keyboard[sc_Escape])
 		{
-			viewwidth=oldview*16;
-			SD_PlaySound(Sesc);
+			vw.dx=oldview*16;
+			sfx(Sesc);
 			MenuFadeOut();
 			return;
 		}
@@ -2131,7 +2131,7 @@
 
 	if (oldview!=newview)
 	{
-		SD_PlaySound (Sshoot);
+		sfx (Sshoot);
 		Message("Thinking...");
 		NewViewSize(newview);
 	}
@@ -2173,7 +2173,7 @@
 {
 	s16int i;
 
-	if (Confirm(endStrings[US_RndT()&0x7+(US_RndT()&1)]))
+	if (Confirm(endStrings[rnd()&0x7+(rnd()&1)]))
 	{
 		VW_UpdateScreen();
 		SD_MusicOff();
@@ -2505,7 +2505,7 @@
 			return which;
 
 		case 2:
-			SD_PlaySound(Sesc);
+			sfx(Sesc);
 			return -1;
 	}
 
@@ -2535,7 +2535,7 @@
 {
 	VWB_DrawPic(x,y,Pcur1);
 	VW_UpdateScreen();
-	SD_PlaySound(Sdrawgun1);
+	sfx(Sdrawgun1);
 	TimeCount=0;
 	while(TimeCount<8);
 }
@@ -2561,7 +2561,7 @@
 	if (routine)
 		routine(which);
 	VW_UpdateScreen();
-	SD_PlaySound(Sdrawgun2);
+	sfx(Sdrawgun2);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -2761,7 +2761,7 @@
 	while(Keyboard[sc_Y] || Keyboard[sc_N] || Keyboard[sc_Escape]);
 
 	IN_ClearKeysDown();
-	SD_PlaySound(whichsnd[xit]);
+	sfx(whichsnd[xit]);
 	return xit;
 }
 
@@ -2804,7 +2804,7 @@
 void StartCPMusic(s16int song)
 {
 	SD_MusicOff();
-	SD_StartMusic((MusicGroup far *)audiosegs[STARTMUSIC + song]);
+	SD_mapmus((MusicGroup far *)audiosegs[STARTMUSIC + song]);
 }
 
 ///////////////////////////////////////////////////////////////////////////
@@ -2874,5 +2874,5 @@
 
 void ShootSnd(void)
 {
-	SD_PlaySound(Sshoot);
+	sfx(Sshoot);
 }
--- a/mkfile
+++ b/mkfile
@@ -6,10 +6,11 @@
 
 OFILES=
 WOFILES=\
+	drw.$O\
 	fs.$O\
 	gm.$O\
+	hub.$O\
 	map.$O\
-	mn.$O\
 	opl2.$O\
 	rend.$O\
 	snd.$O\
--- a/mn.c
+++ /dev/null
@@ -1,576 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <thread.h>
-#include <keyboard.h>
-#include "dat.h"
-#include "fns.h"
-
-/* FIXME: non-trivial */
-
-extern Channel *csc;
-
-typedef struct Score Score;
-typedef struct Seq Seq;
-typedef struct Item Item;
-typedef struct Menu Menu;
-
-struct Score{
-	char name[58];
-	int n;
-	int lvl;
-	int ep;
-};
-static Score sc[] = {
-	{"id software-'92", 10000, 1},
-	{"Adrian Carmack", 10000, 1},
-	{"John Carmack", 10000, 1},
-	{"Kevin Cloud", 10000, 1},
-	{"Tom Hall", 10000, 1},
-	{"John Romero", 10000, 1},
-	{"Jay Wilbur", 10000, 1},
-};
-
-enum{
-	Lload,
-	Lintro,
-	Ltitle,
-	Lcreds,
-	Lscore,
-	Ldemo,
-	Ldecay,
-	Linctl,
-	Lctl,
-	Lcur,
-	Lesc,
-	Lback,
-	Lwait,
-	Lack,
-	Lmscore,
-	Lpants,
-	Lquit,
-	Ldie
-};
-struct Seq{
-	int dt;
-	void (*f)(void);
-};
-struct Item{
-	char *s;
-	int c;
-	Menu *m;
-};
-struct Menu{
-	void (*init)(void);
-	Seq *qs;
-	Seq *qe;
-	Menu *m;
-	Col *c;
-	Item *is;
-	Item *ie;
-	Item *ip;
-	int cx;
-	int cy;
-	int cur;
-};
-static Menu *mp, ml[];
-static Seq *mqp;
-
-static char *ends[] = {
-	"Dost thou wish to\nleave with such hasty\nabandon?",
-	"Chickening out...\nalready?",
-	"Press N for more carnage.\nPress Y to be a weenie.",
-	"So, you think you can\nquit this easily, huh?",
-	"Press N to save the world.\nPress Y to abandon it in\nits hour of need.",
-	"Press N if you are brave.\nPress Y to cower in shame.",
-	"Heroes, press N.\nWimps, press Y.",
-	"You are at an intersection.\nA sign says, 'Press Y to quit.'\n>",
-	"For guns and glory, press N.\nFor work and worry, press Y.",
-
-	"Heroes don't quit, but\ngo ahead and press Y\nif you aren't one.",
-	"Press Y to quit,\nor press N to enjoy\nmore violent diversion.",
-	"Depressing the Y key means\nyou must return to the\nhumdrum workday world.",
-	"Hey, quit or play,\nY or N:\nit's your choice.",
-	"Sure you don't want to\nwaste a few more\nproductive hours?",
-	"I think you had better\nplay some more. Please\npress N...please?",
-	"If you are tough, press N.\nIf not, press Y daintily.",
-	"I'm thinkin' that\nyou might wanna press N\nto play more. You do it.",
-	"Sure. Fine. Quit.\nSee if we care.\nGet it over with.\nPress Y."
-};
-static char **quits;
-
-enum{
-	Dbg,
-	Doff,
-	Dbrd,
-	Dbrd2,
-	Dend
-};
-static int mcol[Dend] = {[Dbg] 0x2d, 0};
-
-static int tc;
-
-static void (*clear)(void);
-static void (*stripe)(int);
-
-static void
-wlclear(void)
-{
-	put(0, 0, Vw, Vh, nil, 0x29);
-}
-static void
-sdclear(void)
-{
-	pic(0, 0, Pbackdrop);
-}
-
-static void
-wlstripe(int y)
-{
-	put(0, y, Vw, 24, nil, 0);
-	put(0, y+22, 320, 1, nil, 0x2c);
-}
-static void
-sdstripe(int y)
-{
-	put(0, y, Vw, 22, nil, 0);
-	put(0, y+23, 320, 1, nil, 0);
-}
-
-static void
-outbox(int x, int y, int dx, int dy, int c1, int c2)
-{
-	put(x, y, dx, 1, nil, c2);
-	put(x, y, 1, dy, nil, c2);
-	put(x, y+dy, dx+1, 1, nil, c1);
-	put(x+dx, y, 1, dy, nil, c1);
-}
-
-static void
-box(int x, int y, int dx, int dy, int col, int out, int out2)
-{
-	put(x+1, y+1, dx-1, dy-1, nil, col);
-	outbox(x, y, dx, dy, out, out2);
-}
-
-static void
-fixedw(char *s)
-{
-	char c;
-
-	while(c = *s, c != 0)
-		*s++ = c - '0' + 129;
-}
-
-static void
-reset(Menu *m)
-{
-	Seq *q;
-
-	q = m->qs;
-	mqp = q;
-	tc = 0;
-	if(m != mp){
-		if(q->f != fadeout && mp != ml+Lpants)
-			pal = pals[C0];
-		mp = m;
-		if(m->init != nil)
-			m->init();
-		if(m->c != nil)
-			fadeop(m->c, q->dt);
-	}
-}
-
-static void
-blink(void)
-{
-	Menu *m;
-
-	m = mp;
-	if(m == ml+Lctl){
-		put(m->cx, m->cy, 24, 16, nil, mcol[Dbg]);
-		pic(m->cx, m->cy, pict[Pcur1]+m->cur);
-	}else if(m == ml+Lquit){
-		if(m->cur == 0)
-			txt(m->cx, m->cy, "_", 0);
-		else
-			put(m->cx, m->cy, fnt->w['_'], fnt->h, nil, 0x17);
-	}
-	out();
-	m->cur ^= 1;
-}
-
-static void
-ask(void)
-{
-	Rune r;
-
-	if(nbrecv(csc, &r) <= 0)
-		return;
-	if(r == 'y'){
-		sfx(Sshoot);
-		reset(ml+Ldie);
-	}
-	else if(r == 'n' || r == Kesc){
-		sfx(Sesc);
-		reset(ml+Lctl);
-	}
-}
-
-static void
-quit(void)
-{
-	int x, y, w, h, curw;
-	char *s, *nl;
-	Menu *m;
-
-	s = quits[nrand(nelem(ends)/2)];
-	h = txth(s);
-	w = txtw(s);
-	nl = strrchr(s, '\n');
-	curw = txtw(nl != nil ? nl+1 : s);
-	w = w > curw+10 ? w : curw+10;
-	y = 200/2 - h/2;
-	x = 160 - w/2;
-	m = mp;
-
-	box(x-5, y-5, w+10, h+10, 0x17, 0, 0x13);
-	txtnl(x, y, s, 0);
-	m->cx = x+curw;
-	m->cy = y + h - fnt->h;
-}
-
-static void
-ctl(void)
-{
-	Menu *m;
-	Item *i, *s, *e;
-
-	clear();
-	pic(112, 184, pict[Pmouselback]);
-	stripe(10);
-	pic(80, 0, pict[Popt]);
-	box(68, 52, 178, 6+13*9, mcol[Dbg], mcol[Dbrd2], mcol[Doff]);
-
-	fnt = fnts+1;
-	m = ml+Lctl;
-	s = i = m->is;
-	e = m->ie;
-	do
-		txt(100, 55+13*(i-s), i->s, i->c);
-	while(++i < e);
-	m->cur = 0;
-	m->cx = 72;
-	m->cy = 53+13*(m->ip-s);
-	if(mp == m)
-		mus(Mmenu);
-}
-
-static void
-cursfx(void)
-{
-	sfx(Sdrawgun2);
-}
-
-static void
-movcur(Menu *m, Item *p, int dir)
-{
-	Item *i;
-
-	p->c = 0x17;
-	i = p;
-	do{
-		i += dir;
-		if(i < m->is)
-			i = m->ie-1;
-		else if(i == m->ie)
-			i = m->is;
-	}while(i->c != 0x17);
-	i->c = 0x13;
-	m->ip = i;
-	m->cur = 0;
-	if(i != p+dir){
-		cursfx();
-		reset(ml+Lctl);
-		ctl();
-		return;
-	}
-	put(m->cx, m->cy, 24, 16, nil, mcol[Dbg]);
-	m->cy += dir * 6;
-	blink();
-	sfx(Sdrawgun1);
-	reset(ml+Lcur);
-}
-
-static void
-cwalk(void)
-{
-	Rune r;
-	Menu *m;
-	Item *i;
-	static int p;
-
-	if(nbrecv(csc, &r) <= 0)
-		return;
-	m = mp;
-	i = m->ip;
-	switch(r){
-	case Kup: movcur(m, i, -1); break;
-	case Kdown: movcur(m, i, 1); break;
-	case Kesc: sfx(Sesc); reset(ml+Lquit); break;
-	case 'i': p++; break;
-	case 'd':
-		if(ver == SOD && p == 1)
-			reset(ml+Lpants);
-		break;
-	case '\n':
-		m = i->m;
-		if(m == nil)
-			break;
-		if(m != ml+Lquit && m != ml+Lesc)
-			sfx(Sshoot);
-		reset(m);
-	}
-	if(r != 'i')
-		p = 0;
-}
-
-static void
-inctl(void)
-{
-	Item *i;
-	Menu *m;
-
-	m = ml+Lctl;
-	if(m->ip != nil)
-		m->ip->c = 0x17;
-	i = m->is;
-	m->ip = i;
-	i[0].c = 0x13;
-	i[4].c = mcol[Doff];
-	grab(0);
-	ctl();
-}
-
-static void
-skip(void)
-{
-	if(nbrecv(csc, nil) > 0)
-		reset(ml+Ldecay);
-}
-
-static void
-ack(void)
-{
-	if(nbrecv(csc, nil) > 0)
-		reset(ml+Lback);
-}
-
-static void
-pants(void)
-{
-	pic(0, 0, pict[Pid1]);
-	pic(0, 80, pict[Pid2]);
-	palpic(exts[Eid]);
-	fadeop(mp->c, mp->qs->dt);
-	mus(Mnazjazz);
-}
-
-static void
-demo(void)
-{
-	step = dstep;
-}
-
-static void
-score(void)
-{
-	int x, y;
-	char a[16], b[16];
-	Score *s;
-
-	clear();
-	stripe(10);
-	pic(48, 0, pict[Pscores]);
-	pic(32, 68, pict[Pname]);
-	pic(160, 68, pict[Plvl]);
-	pic(224, 68, pict[Phigh]);
-
-	fnt = fnts;
-	for(s=sc, y=76; s<sc+nelem(sc); s++, y+=16){
-		txt(32, y, s->name, 0xf);
-
-		sprint(a, "%d", s->lvl);
-		fixedw(a);
-		x = 176 - txtw(a);
-		if(ver < WL1){
-			sprint(b, "E%d/L", s->ep+1);
-			x += txt(x-6, y, b, 0xf) - 6;
-		}
-		txt(x, y, a, 0xf);
-
-		sprint(a, "%d", s->n);
-		fixedw(a);
-		txt(264 - txtw(a), y, a, 0xf);
-	}
-	if(mp == ml+Lmscore)
-		mus(Mroster);
-}
-static void
-sdscore(void)
-{
-	int y;
-	char a[16];
-	Score *s;
-
-	clear();
-	pic(0, 0, pict[Pscores]);
-
-	fnt = fnts+1;
-	for(s=sc, y=76; s<sc+nelem(sc); s++, y+=16){
-		txt(16, y, s->name, 0x13);
-
-		if(s->lvl == 21)
-			pic(176, y-1, pict[Pspear]);
-		else{
-			sprint(a, "%d", s->lvl);
-			txt(194 - txtw(a), y, a, 0xf);
-		}
-
-		sprint(a, "%d", s->n);
-		txt(292 - txtw(a), y, a, 0xf);
-	}
-	if(mp == ml+Lmscore)
-		mus(Maward);
-}
-
-static void
-creds(void)
-{
-	pic(0, 0, pict[Pcreds]);
-}
-
-static void
-title(void)
-{
-	pic(0, 0, pict[Ptitle1]);
-	mus(Mintro);
-}
-static void
-sdtitle(void)
-{
-	pic(0, 0, pict[Ptitle1]);
-	pic(0, 80, pict[Ptitle2]);
-	palpic(exts[Etitpal]);
-	mus(Mtower);
-}
-
-static void
-intro(void)
-{
-	fill(0x82);
-	pic(216, 110, pict[Ppg13]);
-}
-
-static void
-die(void)
-{
-	threadexitsall(nil);
-}
-
-static Item ictl[] = {
-	{"New Game", 0x17},
-	{"Sound", 0x17},
-	{"Control", 0x17},
-	{"Load Game", 0x17},
-	{"Save Game", 0x17},
-	{"Change View", 0x17},
-	{"View Scores", 0x17, ml+Lmscore},
-	{"Back to Demo", 0x17, ml+Lesc},
-	{"Quit", 0x17, ml+Lquit}
-};
-
-static Col fblk, fmenu = { 0xae, 0, 0 };
-static Seq *mqp,
-	introq[] = {{30, fadein}, {7*Tb, skip}, {30, fadeout}},
-	titleq[] = {{30, fadein}, {15*Tb, skip}, {30, fadeout}},
-	loopq[] = {{30, fadein}, {10*Tb, skip}, {30, fadeout}},
-	scoreq[] = {{30, fadein}, {10*Tb, skip}, {30, fadeout}},
-	demoq[] = {{1, nil}},
-	decq[] = {{30, fadeout}},	/* uses previous fadeop */
-	inctlq[] = {{10, fadein}},
-	ctlq[] = {{0, blink}, {70, cwalk}, {0, blink}, {8, cwalk}},
-	curq[] = {{8, nil}, {0, cursfx}},
-	escq[] = {{10, fadeout}},
-	backq[] = {{10, fadeout}, {0, ctl}, {10, fadein}},
-	waitq[] = {{1, skip}},
-	ackq[] = {{1, ack}},
-	mscoreq[] = {{10, fadeout}, {0, score}, {10, fadein}},
-	pantsq[] = {{30, fadeout}, {0, pants}, {30, fadein}},
-	quitq[] = {{0, blink}, {10, ask}},
-	dieq[] = {{10, fadeout}, {1, die}};
-
-static Menu *mp, ml[] = {
-	[Lload] {nil, decq, decq+nelem(decq), ml+Lintro, &fblk},
-	[Lintro] {intro, introq, introq+nelem(introq), ml+Ltitle, &fblk},
-	[Ltitle] {title, titleq, titleq+nelem(titleq), ml+Lcreds, &fblk},
-	[Lcreds] {creds, loopq, loopq+nelem(loopq), ml+Lscore, &fblk},
-	[Lscore] {score, loopq, loopq+nelem(loopq), ml+Ldemo, &fblk},
-	[Ldemo] {demo, demoq, demoq+nelem(demoq), ml+Ltitle, &fblk},
-	[Ldecay] {nil, decq, decq+nelem(decq), ml+Linctl},
-	[Linctl] {inctl, inctlq, inctlq+nelem(inctlq), ml+Lctl, &fblk},
-	[Lctl] {ctl, ctlq, ctlq+nelem(ctlq), ml+Lctl, nil, ictl, ictl+nelem(ictl)},
-	[Lcur] {nil, curq, curq+nelem(curq), ml+Lctl},
-	[Lesc] {nil, escq, escq+nelem(escq), ml+Ltitle, &fblk},
-	[Lback] {nil, backq, backq+nelem(backq), ml+Lctl, &fmenu},
-	[Lwait] {nil, waitq, waitq+nelem(waitq), ml+Lwait},
-	[Lack] {nil, ackq, ackq+nelem(ackq), ml+Lack},
-	[Lmscore] {nil, mscoreq, mscoreq+nelem(mscoreq), ml+Lack, &fmenu},
-	[Lpants] {nil, pantsq, pantsq+nelem(pantsq), ml+Lwait, &fblk},
-	[Lquit] {quit, quitq, quitq+nelem(quitq), ml+Lquit},
-	[Ldie] {nil, dieq, dieq+nelem(dieq), nil, &fmenu}
-};
-
-void
-mstep(void)
-{
-	Menu *m;
-	Seq *q;
-
-rep:
-	m = mp;
-	q = mqp;
-	tc++;
-	if(q->f != nil)
-		q->f();
-	if(tc >= q->dt){
-		if(++mqp == m->qe)
-			reset(m->m);
-		tc = 0;
-	}
-	if(q->dt == 0)
-		goto rep;
-}
-
-void
-init(void)
-{
-	clear = wlclear;
-	stripe = wlstripe;
-	quits = ends;
-	if(ver >= SDM){
-		clear = sdclear;
-		stripe = sdstripe;
-		ml[Ltitle].init = sdtitle;
-		ml[Lscore].init = sdscore;
-		mscoreq[1].f = sdscore;
-		fmenu = (Col){0, 0, 0xce};
-		mcol[Dbg] = 0x9d;
-		quits += nelem(ends)/2;
-	}
-	mcol[Doff] = mcol[Dbg] ^ 6;
-	mcol[Dbrd] = mcol[Dbg] ^ 4;
-	mcol[Dbrd2] = mcol[Dbg] ^ 14;
-	reset(ml+Lload);
-	cson++;
-	mus(ver<SDM ? Mintro : Mtower);
-}
--- a/opl2.c
+++ b/opl2.c
@@ -240,8 +240,6 @@
 	0, 0, 0, 0
 };
 
-void	opl2wr(int, int);
-
 /* 23-bit shift register noise generator. T=2²³-2 samples, sampling rate equal
  * to that of the chip. */
 static void
--- a/play.c
+++ b/play.c
@@ -1,41 +1,10 @@
-// WL_PLAY.C
-
-#include "WL_DEF.H"
-#pragma hdrstop
-
-
-/*
-=============================================================================
-
-						 LOCAL CONSTANTS
-
-=============================================================================
-*/
-
-#define sc_Question	0x35
-
-/*
-=============================================================================
-
-						 GLOBAL VARIABLES
-
-=============================================================================
-*/
-
-int		madenoise;					// true when shooting or screaming
-
-exit_t		playstate;
-
+exit_t		gm.φ;
 s16int			DebugOk;
-
-objtype 	objlist[MAXACTORS],*new,*obj,*player,*lastobj,
-			*objfreelist,*killerobj;
-
+objtype 	objlist[Nobj],*new,*obj,*player,*lastobj,
+			*objfreelist,*killer;
 u16int	farmapylookup[MAPSIZE];
-
-int		singlestep,godmode,noclip;
+int		onestep,godmode,noclip;
 s16int			extravbls;
-
 u8int		tilemap[MAPSIZE][MAPSIZE];	// wall values only
 u8int		spotvis[MAPSIZE][MAPSIZE];
 objtype		*actorat[MAPSIZE][MAPSIZE];
@@ -62,456 +31,19 @@
 s16int			buttonmouse[4]={bt_attack,bt_strafe,bt_use,bt_nobutton};
 s16int			buttonjoy[4]={bt_attack,bt_strafe,bt_use,bt_run};
 
-s16int			viewsize;
-
 int		buttonheld[NUMBUTTONS];
 
-int		demorecord,demoplayback;
 char		far *demoptr, far *lastdemoptr;
 uchar *demobuffer;
 
-//
-// curent user input
-//
-s16int			controlx,controly;		// range from -100 to 100 per tic
 int		buttonstate[NUMBUTTONS];
 
-
-
-//===========================================================================
-
-
-void	CenterWindow(u16int w,u16int h);
-void 	InitObjList (void);
-void 	RemoveObj (objtype *gone);
-void 	PollControls (void);
-void 	StopMusic(void);
-void 	StartMusic(void);
-void	PlayLoop (void);
-
-/*
-=============================================================================
-
-						 LOCAL VARIABLES
-
-=============================================================================
-*/
-
-
 objtype dummyobj;
 
-//
-// LIST OF SONGS FOR EACH VERSION
-//
-s16int songs[]=
-{
-#ifndef SPEAR
- //
- // Episode One
- //
- 3,
- 11,
- 9,
- 12,
- 3,
- 11,
- 9,
- 12,
-
- 2,	// Boss level
- 0,	// Secret level
-
- //
- // Episode Two
- //
- 8,
- 18,
- 17,
- 4,
- 8,
- 18,
- 4,
- 17,
-
- 2,	// Boss level
- 1,	// Secret level
-
- //
- // Episode Three
- //
- 6,
- 20,
- 22,
- 21,
- 6,
- 20,
- 22,
- 21,
-
- 19,	// Boss level
- 26,	// Secret level
-
- //
- // Episode Four
- //
- 3,
- 11,
- 9,
- 12,
- 3,
- 11,
- 9,
- 12,
-
- 2,	// Boss level
- 0,	// Secret level
-
- //
- // Episode Five
- //
- 8,
- 18,
- 17,
- 4,
- 8,
- 18,
- 4,
- 17,
-
- 2,	// Boss level
- 1,	// Secret level
-
- //
- // Episode Six
- //
- 6,
- 20,
- 22,
- 21,
- 6,
- 20,
- 22,
- 21,
-
- 19,	// Boss level
- 15		// Secret level
-#else
-
- //////////////////////////////////////////////////////////////
- //
- // SPEAR OF DESTINY TRACKS
- //
- //////////////////////////////////////////////////////////////
- 4,
- 0,
- 2,
- 22,		// DON'T KNOW
- 15,	// Trans Gr�sse
-
- 1,
- HITLWLTZ_MUS,
- 9,
- 10,
- 15,	// Barnacle Wilhelm BOSS
-
- 8,
- 3,
- 12,
- 11,
- 13,
- 15,	// Super Mutant BOSS
-
- 21,
- 15,	// Death Knight BOSS
-
- 18,	// Secret level
- 0,	// Secret level (DON'T KNOW)
-
- 17		// Angel of Death BOSS
-
-#endif
-};
-
-
-/*
-=============================================================================
-
-						  USER CONTROL
-
-=============================================================================
-*/
-
-
-#define BASEMOVE		35
-#define RUNMOVE			70
 #define BASETURN		35
 #define RUNTURN			70
-
 #define JOYSCALE		2
 
-/*
-===================
-=
-= PollKeyboardButtons
-=
-===================
-*/
-
-void PollKeyboardButtons (void)
-{
-	s16int		i;
-
-	for (i=0;i<NUMBUTTONS;i++)
-		if (Keyboard[buttonscan[i]])
-			buttonstate[i] = true;
-}
-
-
-/*
-===================
-=
-= PollMouseButtons
-=
-===================
-*/
-
-void PollMouseButtons (void)
-{
-	s16int	buttons;
-
-	buttons = IN_MouseButtons ();
-
-	if (buttons&1)
-		buttonstate[buttonmouse[0]] = true;
-	if (buttons&2)
-		buttonstate[buttonmouse[1]] = true;
-	if (buttons&4)
-		buttonstate[buttonmouse[2]] = true;
-}
-
-/*
-===================
-=
-= PollKeyboardMove
-=
-===================
-*/
-
-void PollKeyboardMove (void)
-{
-	if (buttonstate[bt_run])
-	{
-		if (Keyboard[dirscan[di_north]])
-			controly -= RUNMOVE*tics;
-		if (Keyboard[dirscan[di_south]])
-			controly += RUNMOVE*tics;
-		if (Keyboard[dirscan[di_west]])
-			controlx -= RUNMOVE*tics;
-		if (Keyboard[dirscan[di_east]])
-			controlx += RUNMOVE*tics;
-	}
-	else
-	{
-		if (Keyboard[dirscan[di_north]])
-			controly -= BASEMOVE*tics;
-		if (Keyboard[dirscan[di_south]])
-			controly += BASEMOVE*tics;
-		if (Keyboard[dirscan[di_west]])
-			controlx -= BASEMOVE*tics;
-		if (Keyboard[dirscan[di_east]])
-			controlx += BASEMOVE*tics;
-	}
-}
-
-
-/*
-===================
-=
-= PollMouseMove
-=
-===================
-*/
-
-void PollMouseMove (void)
-{
-	s16int	mousexmove,mouseymove;
-
-	Mouse(MDelta);
-	mousexmove = _CX;
-	mouseymove = _DX;
-
-	controlx += mousexmove*10/(13-mouseadjustment);
-	controly += mouseymove*20/(13-mouseadjustment);
-}
-
-/*
-===================
-=
-= PollControls
-=
-= Gets user or demo input, call once each frame
-=
-= controlx		set between -100 and 100 per tic
-= controly
-= buttonheld[]	the state of the buttons LAST frame
-= buttonstate[]	the state of the buttons THIS frame
-=
-===================
-*/
-
-void PollControls (void)
-{
-	s16int		max,min,i;
-	u8int	buttonbits;
-
-//
-// get timing info for last frame
-//
-	if (demoplayback)
-	{
-		while (TimeCount<lasttimecount+DEMOTICS)
-		;
-		TimeCount = lasttimecount + DEMOTICS;
-		lasttimecount += DEMOTICS;
-		tics = DEMOTICS;
-	}
-	else if (demorecord)			// demo recording and playback needs
-	{								// to be constant
-//
-// take DEMOTICS or more tics, and modify Timecount to reflect time taken
-//
-		while (TimeCount<lasttimecount+DEMOTICS)
-		;
-		TimeCount = lasttimecount + DEMOTICS;
-		lasttimecount += DEMOTICS;
-		tics = DEMOTICS;
-	}
-	else
-		CalcTics ();
-
-	controlx = 0;
-	controly = 0;
-	memcpy (buttonheld,buttonstate,sizeof(buttonstate));
-	memset (buttonstate,0,sizeof(buttonstate));
-
-	if (demoplayback)
-	{
-	//
-	// read commands from demo buffer
-	//
-		buttonbits = *demoptr++;
-		for (i=0;i<NUMBUTTONS;i++)
-		{
-			buttonstate[i] = buttonbits&1;
-			buttonbits >>= 1;
-		}
-
-		controlx = *demoptr++;
-		controly = *demoptr++;
-
-		if (demoptr == lastdemoptr)
-			playstate = ex_completed;		// demo is done
-
-		controlx *= (s16int)tics;
-		controly *= (s16int)tics;
-
-		return;
-	}
-
-
-//
-// get button states
-//
-	PollKeyboardButtons ();
-
-	if (mouseenabled)
-		PollMouseButtons ();
-
-//
-// get movements
-//
-	PollKeyboardMove ();
-
-	if (mouseenabled)
-		PollMouseMove ();
-
-//
-// bound movement to a maximum
-//
-	max = 100*tics;
-	min = -max;
-	if (controlx > max)
-		controlx = max;
-	else if (controlx < min)
-		controlx = min;
-
-	if (controly > max)
-		controly = max;
-	else if (controly < min)
-		controly = min;
-
-	if (demorecord)
-	{
-	//
-	// save info out to demo buffer
-	//
-		controlx /= (s16int)tics;
-		controly /= (s16int)tics;
-
-		buttonbits = 0;
-
-		for (i=NUMBUTTONS-1;i>=0;i--)
-		{
-			buttonbits <<= 1;
-			if (buttonstate[i])
-				buttonbits |= 1;
-		}
-
-		*demoptr++ = buttonbits;
-		*demoptr++ = controlx;
-		*demoptr++ = controly;
-
-		if (demoptr >= lastdemoptr)
-			Quit ("Demo buffer overflowed!");
-
-		controlx *= (s16int)tics;
-		controly *= (s16int)tics;
-	}
-}
-
-
-
-//==========================================================================
-
-
-
-///////////////////////////////////////////////////////////////////////////
-//
-//	CenterWindow() - Generates a window of a given width & height in the
-//		middle of the screen
-//
-///////////////////////////////////////////////////////////////////////////
-
-#define MAXX	320
-#define MAXY	160
-
-void	CenterWindow(u16int w,u16int h)
-{
-	FixOfs ();
-	US_DrawWindow(((MAXX / 8) - w) / 2,((MAXY / 8) - h) / 2,w,h);
-}
-
-//===========================================================================
-
-
-/*
-=====================
-=
-= CheckKeys
-=
-=====================
-*/
-
 void CheckKeys (void)
 {
 	s16int		i;
@@ -519,7 +51,7 @@
 	u16int	temp;
 
 
-	if (screenfaded || demoplayback)	// don't do anything with a faded screen
+	if (screenfaded || gm.demo)	// don't do anything with a faded screen
 		return;
 
 	scan = LastScan;
@@ -537,12 +69,12 @@
 		if (godmode)
 		{
 			Message ("God mode OFF");
-			SD_PlaySound (Snobonus);
+			sfx (Snobonus);
 		}
 		else
 		{
 			Message ("God mode ON");
-			SD_PlaySound (Sendb2);
+			sfx (Sendb2);
 		}
 
 		IN_Ack();
@@ -564,15 +96,15 @@
 		gamestate.health = 100;
 		gamestate.ammo = 99;
 		gamestate.keys = 3;
-		gamestate.score = 0;
-		gamestate.TimeCount += 42000L;
-		GiveWeapon (wp_chaingun);
+		gm.pt = 0;
+		gm.lvltc += 42000L;
+		givew (WPgatling);
 
-		DrawWeapon();
-		DrawHealth();
-		DrawKeys();
-		DrawAmmo();
-		DrawScore();
+		hudw();
+		hudh();
+		hudk();
+		huda();
+		hudp();
 
 		ClearMemory ();
 		ClearSplitVWB ();
@@ -669,7 +201,7 @@
 		 DrawAllPlayBorderSides ();
 
 		if (scan == sc_F9)
-		  StartMusic ();
+		  mapmus ();
 
 		PM_CheckMainMem ();
 		SETFONTCOLOR(0,15);
@@ -679,7 +211,7 @@
 
 	if ( (scan >= sc_F1 && scan <= sc_F9) || scan == sc_Escape)
 	{
-		StopMusic ();
+		stopmus ();
 		ClearMemory ();
 		VW_FadeOut ();
 
@@ -687,14 +219,14 @@
 
 		SETFONTCOLOR(0,15);
 		IN_ClearKeysDown();
-		DrawPlayScreen ();
-		if (!startgame && !loadedgame)
+		view ();
+		if (!startgame && !gm.load)
 		{
 			VW_FadeIn ();
-			StartMusic ();
+			mapmus ();
 		}
-		if (loadedgame)
-			playstate = ex_abort;
+		if (gm.load)
+			gm.φ = ex_abort;
 		lasttimecount = TimeCount;
 		if (MousePresent)
 			Mouse(MDelta);	// Clear accumulated mouse movement
@@ -718,609 +250,3 @@
 	}
 
 }
-
-
-//===========================================================================
-
-/*
-#############################################################################
-
-				  The objlist data structure
-
-#############################################################################
-
-objlist containt structures for every actor currently playing.  The structure
-is accessed as a linked list starting at *player, ending when ob->next ==
-NULL.  GetNewObj inserts a new object at the end of the list, meaning that
-if an actor spawn another actor, the new one WILL get to think and react the
-same frame.  RemoveObj unlinks the given object and returns it to the free
-list, but does not damage the objects ->next pointer, so if the current object
-removes itself, a linked list following loop can still safely get to the
-next element.
-
-<backwardly linked free list>
-
-#############################################################################
-*/
-
-
-/*
-=========================
-=
-= InitActorList
-=
-= Call to clear out the actor object lists returning them all to the free
-= list.  Allocates a special spot for the player.
-=
-=========================
-*/
-
-s16int	objcount;
-
-void InitActorList (void)
-{
-	s16int	i;
-
-//
-// init the actor lists
-//
-	for (i=0;i<MAXACTORS;i++)
-	{
-		objlist[i].prev = &objlist[i+1];
-		objlist[i].next = NULL;
-	}
-
-	objlist[MAXACTORS-1].prev = NULL;
-
-	objfreelist = &objlist[0];
-	lastobj = NULL;
-
-	objcount = 0;
-
-//
-// give the player the first free spots
-//
-	GetNewActor ();
-	player = new;
-
-}
-
-//===========================================================================
-
-/*
-=========================
-=
-= 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)
-{
-	if (!objfreelist)
-		Quit ("GetNewActor: No free spots in objlist!");
-
-	new = objfreelist;
-	objfreelist = new->prev;
-	memset (new,0,sizeof(*new));
-
-	if (lastobj)
-		lastobj->next = new;
-	new->prev = lastobj;	// new->next is allready NULL from memset
-
-	new->active = false;
-	lastobj = new;
-
-	objcount++;
-}
-
-//===========================================================================
-
-/*
-=========================
-=
-= RemoveObj
-=
-= Add the given object back into the free list, and unlink it from it's
-= neighbors
-=
-=========================
-*/
-
-void RemoveObj (objtype *gone)
-{
-	objtype **spotat;
-
-	if (gone == player)
-		Quit ("RemoveObj: Tried to remove the player!");
-
-	gone->state = NULL;
-
-//
-// fix the next object's back link
-//
-	if (gone == lastobj)
-		lastobj = (objtype *)gone->prev;
-	else
-		gone->next->prev = gone->prev;
-
-//
-// fix the previous object's forward link
-//
-	gone->prev->next = gone->next;
-
-//
-// add it back in to the free list
-//
-	gone->prev = objfreelist;
-	objfreelist = gone;
-
-	objcount--;
-}
-
-/*
-=============================================================================
-
-						MUSIC STUFF
-
-=============================================================================
-*/
-
-
-/*
-=================
-=
-= StopMusic
-=
-=================
-*/
-
-void StopMusic(void)
-{
-	s16int	i;
-
-	SD_MusicOff();
-	for (i = 0;i < LASTMUSIC;i++)
-		if (audiosegs[STARTMUSIC + i])
-		{
-			MM_SetPurge(&((uchar *)audiosegs[STARTMUSIC + i]),3);
-			MM_SetLock(&((uchar *)audiosegs[STARTMUSIC + i]),false);
-		}
-}
-
-//==========================================================================
-
-
-/*
-=================
-=
-= StartMusic
-=
-=================
-*/
-
-void StartMusic(void)
-{
-	musicnames	chunk;
-
-	SD_MusicOff();
-	chunk = songs[gamestate.mapon+gamestate.episode*10];
-	SD_StartMusic((MusicGroup far *)audiosegs[STARTMUSIC + chunk]);
-}
-
-
-/*
-=============================================================================
-
-					PALETTE SHIFTING STUFF
-
-=============================================================================
-*/
-
-#define NUMREDSHIFTS	6
-#define REDSTEPS		8
-
-#define NUMWHITESHIFTS	3
-#define WHITESTEPS		20
-#define WHITETICS		6
-
-
-u8int	far redshifts[NUMREDSHIFTS][768];
-u8int	far whiteshifts[NUMREDSHIFTS][768];
-
-s16int		damagecount,bonuscount;
-int	palshifted;
-
-extern 	u8int	far	gamepal;
-
-/*
-=====================
-=
-= InitRedShifts
-=
-=====================
-*/
-
-void InitRedShifts (void)
-{
-	u8int	far *workptr, far *baseptr;
-	s16int		i,j,delta;
-
-
-//
-// fade through intermediate frames
-//
-	for (i=1;i<=NUMREDSHIFTS;i++)
-	{
-		workptr = (u8int far *)&redshifts[i-1][0];
-		baseptr = &gamepal;
-
-		for (j=0;j<=255;j++)
-		{
-			delta = 64-*baseptr;
-			*workptr++ = *baseptr++ + delta * i / REDSTEPS;
-			delta = -*baseptr;
-			*workptr++ = *baseptr++ + delta * i / REDSTEPS;
-			delta = -*baseptr;
-			*workptr++ = *baseptr++ + delta * i / REDSTEPS;
-		}
-	}
-
-	for (i=1;i<=NUMWHITESHIFTS;i++)
-	{
-		workptr = (u8int far *)&whiteshifts[i-1][0];
-		baseptr = &gamepal;
-
-		for (j=0;j<=255;j++)
-		{
-			delta = 64-*baseptr;
-			*workptr++ = *baseptr++ + delta * i / WHITESTEPS;
-			delta = 62-*baseptr;
-			*workptr++ = *baseptr++ + delta * i / WHITESTEPS;
-			delta = 0-*baseptr;
-			*workptr++ = *baseptr++ + delta * i / WHITESTEPS;
-		}
-	}
-}
-
-
-/*
-=====================
-=
-= ClearPaletteShifts
-=
-=====================
-*/
-
-void ClearPaletteShifts (void)
-{
-	bonuscount = damagecount = 0;
-}
-
-
-/*
-=====================
-=
-= StartBonusFlash
-=
-=====================
-*/
-
-void StartBonusFlash (void)
-{
-	bonuscount = NUMWHITESHIFTS*WHITETICS;		// white shift palette
-}
-
-
-/*
-=====================
-=
-= StartDamageFlash
-=
-=====================
-*/
-
-void StartDamageFlash (s16int damage)
-{
-	damagecount += damage;
-}
-
-
-/*
-=====================
-=
-= UpdatePaletteShifts
-=
-=====================
-*/
-
-void UpdatePaletteShifts (void)
-{
-	s16int	red,white;
-
-	if (bonuscount)
-	{
-		white = bonuscount/WHITETICS +1;
-		if (white>NUMWHITESHIFTS)
-			white = NUMWHITESHIFTS;
-		bonuscount -= tics;
-		if (bonuscount < 0)
-			bonuscount = 0;
-	}
-	else
-		white = 0;
-
-
-	if (damagecount)
-	{
-		red = damagecount/10 +1;
-		if (red>NUMREDSHIFTS)
-			red = NUMREDSHIFTS;
-
-		damagecount -= tics;
-		if (damagecount < 0)
-			damagecount = 0;
-	}
-	else
-		red = 0;
-
-	if (red)
-	{
-		VW_WaitVBL(1);
-		VL_SetPalette (redshifts[red-1]);
-		palshifted = true;
-	}
-	else if (white)
-	{
-		VW_WaitVBL(1);
-		VL_SetPalette (whiteshifts[white-1]);
-		palshifted = true;
-	}
-	else if (palshifted)
-	{
-		VW_WaitVBL(1);
-		VL_SetPalette (&gamepal);		// back to normal
-		palshifted = false;
-	}
-}
-
-
-/*
-=====================
-=
-= FinishPaletteShifts
-=
-= Resets palette to normal if needed
-=
-=====================
-*/
-
-void FinishPaletteShifts (void)
-{
-	if (palshifted)
-	{
-		palshifted = 0;
-		VW_WaitVBL(1);
-		VL_SetPalette (&gamepal);
-	}
-}
-
-
-/*
-=============================================================================
-
-						CORE PLAYLOOP
-
-=============================================================================
-*/
-
-
-/*
-=====================
-=
-= DoActor
-=
-=====================
-*/
-
-void DoActor (objtype *ob)
-{
-	void (*think)(objtype *);
-
-	if (!ob->active && !areabyplayer[ob->areanumber])
-		return;
-
-	if (!(ob->flags&(FL_NONMARK|FL_NEVERMARK)) )
-		actorat[ob->tilex][ob->tiley] = NULL;
-
-//
-// non transitional object
-//
-
-	if (!ob->ticcount)
-	{
-		think =	ob->state->think;
-		if (think)
-		{
-			think (ob);
-			if (!ob->state)
-			{
-				RemoveObj (ob);
-				return;
-			}
-		}
-
-		if (ob->flags&FL_NEVERMARK)
-			return;
-
-		if ( (ob->flags&FL_NONMARK) && actorat[ob->tilex][ob->tiley])
-			return;
-
-		actorat[ob->tilex][ob->tiley] = ob;
-		return;
-	}
-
-//
-// transitional object
-//
-	ob->ticcount-=tics;
-	while ( ob->ticcount <= 0)
-	{
-		think = ob->state->action;			// end of state action
-		if (think)
-		{
-			think (ob);
-			if (!ob->state)
-			{
-				RemoveObj (ob);
-				return;
-			}
-		}
-
-		ob->state = ob->state->next;
-
-		if (!ob->state)
-		{
-			RemoveObj (ob);
-			return;
-		}
-
-		if (!ob->state->tictime)
-		{
-			ob->ticcount = 0;
-			goto think;
-		}
-
-		ob->ticcount += ob->state->tictime;
-	}
-
-think:
-	//
-	// think
-	//
-	think =	ob->state->think;
-	if (think)
-	{
-		think (ob);
-		if (!ob->state)
-		{
-			RemoveObj (ob);
-			return;
-		}
-	}
-
-	if (ob->flags&FL_NEVERMARK)
-		return;
-
-	if ( (ob->flags&FL_NONMARK) && actorat[ob->tilex][ob->tiley])
-		return;
-
-	actorat[ob->tilex][ob->tiley] = ob;
-}
-
-//==========================================================================
-
-
-/*
-===================
-=
-= PlayLoop
-=
-===================
-*/
-s32int funnyticount;
-
-
-void PlayLoop (void)
-{
-	s16int		give;
-	s16int	helmetangle;
-
-	playstate = TimeCount = lasttimecount = 0;
-	frameon = 0;
-	running = false;
-	anglefrac = 0;
-	facecount = 0;
-	funnyticount = 0;
-	memset (buttonstate,0,sizeof(buttonstate));
-	ClearPaletteShifts ();
-
-	if (MousePresent)
-		Mouse(MDelta);	// Clear accumulated mouse movement
-
-	if (demoplayback)
-		IN_StartAck ();
-
-	do
-	{
-		PollControls();
-
-//
-// actor thinking
-//
-		madenoise = false;
-
-		MoveDoors ();
-		MovePWalls ();
-
-		for (obj = player;obj;obj = obj->next)
-			DoActor (obj);
-
-		UpdatePaletteShifts ();
-
-		ThreeDRefresh ();
-
-		//
-		// MAKE FUNNY FACE IF BJ DOESN'T MOVE FOR AWHILE
-		//
-		#ifdef SPEAR
-		funnyticount += tics;
-		if (funnyticount > 30l*70)
-		{
-			funnyticount = 0;
-			StatusDrawPic (17,4,Pwait+(US_RndT()&1));
-			facecount = 0;
-		}
-		#endif
-
-		gamestate.TimeCount+=tics;
-
-		SD_Poll ();
-		UpdateSoundLoc();	// JAB
-
-		if (screenfaded)
-			VW_FadeIn ();
-
-		CheckKeys();
-
-//
-// debug aids
-//
-		if (singlestep)
-		{
-			VW_WaitVBL(14);
-			lasttimecount = TimeCount;
-		}
-		if (extravbls)
-			VW_WaitVBL(extravbls);
-
-		if (demoplayback)
-		{
-			if (IN_CheckAck ())
-			{
-				IN_ClearKeysDown ();
-				playstate = ex_abort;
-			}
-		}
-	}while (!playstate && !startgame);
-
-	if (playstate != ex_died)
-		FinishPaletteShifts ();
-}
-
--- a/rend.c
+++ b/rend.c
@@ -3,229 +3,788 @@
 #include "dat.h"
 #include "fns.h"
 
-Fnt fnts[2], *fnt;
-Pic *pics;
-uchar **exts, **dems, **epis;
-Dat *wals, *sprs;
+s32int sint[360+90], *cost;
 
-int scale, npx;
-uchar *px, pxb[Va];
-static Col *fcol;
-static u32int *fref;
-static int fi, fo, fdt;
+typedef struct Vis Vis;
+struct Vis{
+	s16int vwdx;
+	s16int vwdy;
+	Dat *spr;
+};
 
-void
-fadeout(void)
+enum{
+	Nvis = 50,
+	Fineθ = 3600,
+	Dfoclen = 0x5700,
+	Dglob = 0x10000,
+	Dtile = 0x2000,
+	Dobj = 0x4000
+};
+#define	Pi	3.141592657
+static float Rad = (float)Fineθ / 2 / Pi;
+
+static s32int ftan[Fineθ/4];
+static s16int midθ;
+static int Δvwθ[Vw];
+static int prjw, prjh;
+static s32int xin, yin;
+static int dtx, dty;
+static u16int ∂xdown, ∂xup, ∂ydown, ∂yup;
+static int lastside;
+
+static void
+scalespr(int, int, int)
 {
-	int i, t, u, v, w;
-	u32int p, *s, *d, *e;
-	Col *c;
+}
 
-	i = fo++;
-	t = fdt;
-	c = fcol;
-	s = fref;
-	d = pal;
-	e = d+nelem(pals[0]);
-	while(d < e){
-		p = *s++;
-		u = p & 0xff;
-		v = p>>8 & 0xff;
-		w = p>>16 & 0xff;
-		u = u + (c->b-u) * i/t;
-		v = v + (c->g-v) * i/t;
-		w = w + (c->r-w) * i/t;
-		*d++ = w<<16 | v<<8 | u;
+static void
+scalevis(Vis *)
+{
+}
+
+static void
+topspr(void)
+{
+	if(ver < SDM && gm.won){
+		if(oplr->s == stt+GSplrcam && mtc & 32)
+			scalespr(SPcam, vw.dx/2, vw.dy+1);
+		return;
 	}
-	out();
+	if(gm.w != -1)
+		scalespr(wspr[gm.w] + gm.wfrm, vw.dx/2, vw.dy+1);
+	if(gm.record || gm.demo)
+		scalespr(SPdemo, vw.dx/2, vw.dy+1);
 }
 
-void
-fadein(void)
+static int
+rot(Obj *o)
 {
-	int i, t, u, v, w;
-	u32int p, *s, *d, *e;
-	Col *c;
+	int θ;
+
+	θ = oplr->θ + (vw.mid - o->vwdx) / 8 + 180 + 360 - o->θ + 45/2;
+	θ %= 360;
+	if(o->s->rot == 2)
+		return 4 * (θ / 180);
+	return θ / 45;
+}
+
+static int
+projtl(Tile *tl, Vis *v)
+{
+	int x, y, cx, cy;
+
+	x = ((tl-tiles) % Mapdxy << Dtlshift) + 0x8000 - vw.x;
+	y = ((tl-tiles) / Mapdxy << Dtlshift) + 0x8000 - vw.y;
+	cx = ffs(x, vw.cos);
+	cx -= ffs(y, vw.sin) + Dtile;
+	cy = ffs(y, vw.cos);
+	cy += ffs(x, vw.sin);
+	if(cx < Dmin){
+		v->vwdy = 0;
+		return 0;
+	}
+	v->vwdx = vw.mid + cy * prjw / cx;
+	v->vwdy = prjh / (cx >> 8);
+	return cx < Dtlglobal && abs(cy) < Dtlglobal / 2;
+}
 
-	i = fi++;
-	t = fdt;
-	c = fcol;
-	s = fref;
-	d = pal;
-	e = d+nelem(pals[0]);
-	while(d < e){
-		p = *s++;
-		u = p & 0xff;
-		v = p>>8 & 0xff;
-		w = p>>16 & 0xff;
-		u = c->b + (u-c->b) * i/t;
-		v = c->g + (v-c->g) * i/t;
-		w = c->r + (w-c->r) * i/t;
-		*d++ = w<<16 | v<<8 | u;
+static void
+projob(Obj *o)
+{
+	int x, y, cx, cy;
+
+	x = o->x - vw.x;
+	y = o->y - vw.y;
+	cx = ffs(x, vw.cos);
+	cx -= ffs(y, vw.sin) + Dobj;
+	cy = ffs(x, vw.sin);
+	cy += ffs(y, vw.cos);
+	o->vwx = cx;
+	if(cx < Dmin){
+		o->vwdy = 0;
+		return;
 	}
-	out();
+	o->vwdx = vw.mid + cy * prjw / cx;
+	o->vwdy = prjh / (cx >> 8);
 }
 
-void
-fadeop(Col *c, int dt)
+static void
+scaleall(void)
 {
-	fi = 0;
-	fo = 1;
-	fdt = dt;
-	fcol = c;
-	fref = pal;
-	pal = pals[Cfad];
+	Obj *o;
+	Tile *tl;
+	Static *st;
+	Vis viss[Nvis], *v, *w, *e, *m;
+
+	memset(viss, 0, sizeof viss);
+	e = viss;
+	for(st=stcs; st<stce; st++){
+		if(st->tl == nil || st->tl->vis == 0)
+			continue;
+		if(projtl(st->tl, e) && st->f & OFbonus){
+			bonus(st);
+			continue;
+		}
+		if(e->vwdy == 0)
+			continue;
+		e->spr = st->spr;
+		if(e < viss + nelem(viss)-1)
+			e++;
+	}
+	for(o=oplr->n; o!=objs; o=o->n){
+		if(o->s->spr == nil)
+			continue;
+		tl = tiles + o->ty * Mapdxy + o->tx;
+		if(tl[0].vis
+		|| tl[-1].vis && tl[-1].tl == 0
+		|| tl[+1].vis && tl[+1].tl == 0
+		|| tl[-Mapdxy-1].vis && tl[-Mapdxy-1].tl == 0
+		|| tl[-Mapdxy].vis && tl[-Mapdxy].tl == 0
+		|| tl[-Mapdxy+1].vis && tl[-Mapdxy+1].tl == 0
+		|| tl[Mapdxy+1].vis && tl[Mapdxy+1].tl == 0
+		|| tl[Mapdxy].vis && tl[Mapdxy].tl == 0
+		|| tl[Mapdxy-1].vis && tl[Mapdxy-1].tl == 0){
+			o->on = 1;
+			projob(o);
+			if(o->vwdy == 0)
+				continue;
+			o->f |= OFvis;
+			e->vwdx = o->vwdx;
+			e->vwdy = o->vwdy;
+			e->spr = o->s->spr;
+			if(e->spr == nil)
+				e->spr = sprs + o->sdt;
+			if(o->s->rot)
+				e->spr += rot(o);
+			if(e < viss + nelem(viss)-1)
+				e++;
+		}else
+			o->f &= ~OFvis;
+	}
+	for(v=viss; v<e; v++){
+		for(w=v, m=v; w<=e; w++)
+			if(w->vwdy < m->vwdy)
+				m = w;
+		scalevis(m);
+		if(v != m)
+			memcpy(m, v, sizeof *m);
+	}
+	if(e != viss)
+		scalevis(e);
 }
 
-void
-palpic(uchar *s)
+static s16int
+walldy(s32int xin, s32int yin)
 {
-	u32int *p, *e;
+	s32int cx, dy;
 
-	p = pal = pals[Csod];
-	e = p + nelem(pals[0]);
-	while(p < e){
-		*p++ = s[0]*255/63<<16 | s[1]*255/63<<8 | s[2]*255/63;
-		s += 3;
+	cx = ffs(xin - vw.x, vw.cos);
+	dy = cx - ffs(yin - vw.y, vw.sin);
+	if(dy < Dmin)
+		dy = Dmin;
+	return prjh / (dy >> 8);
+}
+
+static void
+vwall(int i, int tx, int ty, int tile)
+{
+	s16int p;
+	u16int tex;
+
+	tex = yin >> 4 & 0xfc0;
+	if(dtx == -1){
+		tex = 0xfc0 - tex;
+		xin += Dtlglobal;
 	}
+	p = 0;
+	USED(tex, p, tx, ty, tile, xin, i);
+#ifdef DICKS
+	wallheight[i] = walldy();
+	if(lastside==1 && lastintercept == tx && lasttilehit == tile){
+		/* in the same wall type as last time, so check for
+		 * optimized draw */
+		if(tex == (u16int)postsource){
+			// wide scale
+			postwidth++;
+			wallheight[i] = wallheight[i-1];
+		}else{
+			ScalePost();
+			(u16int)postsource = tex;
+			postwidth = 1;
+			postx = i;
+		}
+		return;
+	}
+	/* new wall */
+	if(lastside != -1)	/* if not the first scaled post */
+		ScalePost();
+	lastside = true;
+	lastintercept = tx;
+	lasttilehit = tile;
+	postx = i;
+	postwidth = 1;
+
+	if(tile & 0x40){	/* check for adjacent doors */
+		if(tiles[ty][tx-dtx].tl & 0x80)
+			p = SPdoor+3;
+		else
+			p = vertwall[tile & ~0x40];
+	}else
+		p = vertwall[tile];
+	*(((u16int *)&postsource)+1) = (u16int)PM_GetPage(p);
+	(u16int)postsource = tex;
+#endif
 }
 
-void
-out(void)
+static void
+hwall(int i, int tx, int ty, int tile)
 {
-	int n;
-	u32int c;
-	uchar *s, *e, *d, *w;
+	s16int p;
+	u16int tex;
 
-	d = px;
-	s = pxb;
-	e = s + sizeof pxb;
-	n = scale * 3;
-	while(s < e){
-		c = pal[*s++];
-		w = d + n;
-		while(d < w){
-			*d++ = c;
-			*d++ = c>>8;
-			*d++ = c>>16;
+	tex = xin >> 4 & 0xfc0;
+	if(dty == -1)
+		yin += Dtlglobal;
+	else
+		tex = 0xfc0 - tex;
+	p = 0;
+	USED(i, tx, ty, tile, tex, p);
+#ifdef DICKS
+	wallheight[i] = walldy();
+	if(lastside == 0 && lastintercept == ty && lasttilehit == tile){
+		/* in the same wall type as last time, so check for
+		 * optimized draw */
+		if(tex == (u16int)postsource){	/* wide scale */
+			postwidth++;
+			wallheight[i] = wallheight[i-1];
+			return;
+		}else{
+			ScalePost();
+			(u16int)postsource = tex;
+			postwidth = 1;
+			postx = i;
 		}
+	}else{	/* new wall */
+		if(lastside != -1)	/* if not the first scaled post */
+			ScalePost();
+
+		lastside = 0;
+		lastintercept = ty;
+		lasttilehit = tile;
+		postx = i;
+		postwidth = 1;
+		if(tile & 0x40){	/* check for adjacent doors */
+			tx = xin >> Dtlshift;
+			if(tiles[ty-dty][tx].tl & 0x80)
+				p = SPdoor+2;
+			else
+				p = horizwall[tile & ~0x40];
+		}else
+			p = horizwall[tile];
+		*( ((u16int *)&postsource)+1) = (u16int)PM_GetPage(p);
+		(u16int)postsource = tex;
 	}
-	flush();
+#endif
 }
 
-void
-put(int x, int y, int dx, int dy, uchar *s, int c)
+static void
+vdoor(int i, int tile)
 {
-	uchar *d;
+	USED(i, xin, yin, tile);
+#ifdef DICKS
+	Door *d;
+	u16int tex, p;
 
-	d = pxb + x + y*Vw;
-	if(s != nil)
-		while(dy-- > 0){
-			memcpy(d, s, dx);
-			s += dx;
-			d += Vw;
+	wallheight[i] = walldy(xin, yin);
+	d = doors + (tile & 0x7f);
+	tex = yin - d->dopen >> 4 & 0xfc0;
+	if(lasttilehit == tile){
+		/* in the same door as last time, so check for optimized draw */
+		if(tex == (u16int)postsource){
+			/* wide scale */
+			postwidth++;
+			wallheight[i] = wallheight[i-1];
+			return;
+		}else{
+			ScalePost ();
+			(u16int)postsource = tex;
+			postwidth = 1;
+			postx = i;
 		}
-	else
-		while(dy-- > 0){
-			memset(d, c, dx);
-			d += Vw;
-		}	
+	}else{
+		if (lastside != -1)	/* if not the first scaled post */
+			ScalePost ();		/* draw last post */
+		/* first pixel in this door */
+		lastside = 2;
+		lasttile = tile;
+		postx = i;
+		postwidth = 1;
+		switch(d->lock){
+		case DRunlk: p = SPdoor; break;
+		case DRlock1:
+		case DRlock2:
+		case DRlock3:
+		case DRlock4: p = SPdoor+6; break;
+		case DRup: p = SPdoor+4; break;
+		}
+		*( ((u16int *)&postsource)+1) = (u16int)PM_GetPage(p+1);
+		(u16int)postsource = tex;
+	}
+#endif
 }
 
-int
-txt(int x, int y, char *t, int col)
+static void
+hdoor(int i, int tile)
 {
-	int h, w;
-	uchar c, *d, *s, *p, *e, *q;
+	USED(i, xin, yin, tile);
+#ifdef DICKS
+	Door *d;
+	u16int tex, p;
 
-	h = fnt->h;
-	p = fnt->p;
-	c = *t++;
-	d = pxb + x + y*Vw;
-	x = 0;
-	while(c != 0){
-		w = fnt->w[c];
-		s = p + fnt->ofs[c];
-		e = s + w*h;
-		while(s < e){
-			q = s + w;
-			while(s < q){
-				c = *s++;
-				if(c != 0)
-					*d = col;
-				d++;
-			}
-			d += Vw-w;
+	wallheight[i] = walldy(xin, yin);
+	d = doors + (tile & 0x7f);
+	tex = xin - d->dopen >> 4 & 0xfc0;
+	if(lasttilehit == tile){
+		/* in the same door as last time, so check for optimized draw */
+		if(tex == (u16int)postsource){	/* wide scale */
+			postwidth++;
+			wallheight[i] = wallheight[i-1];
+			return;
+		}else{
+			ScalePost();
+			(u16int)postsource = tex;
+			postwidth = 1;
+			postx = i;
 		}
-		d -= Vw*h - w;
-		x += w;
-		c = *t++;
+	}else{
+		if(lastside != -1)	/* if not the first scaled post */
+			ScalePost();	/* draw last post */
+		/* first pixel in this door */
+		lastside = 2;
+		lasttile = tile;
+		postx = i;
+		postwidth = 1;
+		switch(d->lock){
+		case DRunlk: p = SPdoor; break;
+		case DRlock1:
+		case DRlock2:
+		case DRlock3:
+		case DRlock4: p = SPdoor+6; break;
+		case DRup: p = SPdoor+4; break;
+		}
+		*( ((u16int *)&postsource)+1) = (u16int)PM_GetPage(p);
+		(u16int)postsource = tex;
 	}
-	return x;
+#endif
 }
 
-int
-txtnl(int x, int y, char *t, int col)
+static void
+vpush(int i, int tile)
 {
-	int n;
-	char *s, *m;
+	s16int p;
+	u16int tex, ofs;
 
-	n = 0;
-	m = strdup(t);
-	if(m == nil)
-		sysfatal("txtnl: %r");
-	s = strtok(m, "\n");
-	while(s != nil){
-		n += txt(x, y, s, col);
-		s = strtok(nil, "\n");
-		y += fnt->h;
+	tex = yin >> 4 & 0xfc0;
+	ofs = pusher.dopen << 10;
+	if(dtx == -1){
+		xin += Dtlglobal - ofs;
+		tex = 0xfc0 - tex;
+	}else
+		xin += ofs;
+	p = 0;
+	USED(i, xin, tile, p, tex, ofs);
+#ifdef DICKS
+	wallheight[i] = walldy(xin, yin);
+	if(lasttilehit == tile){
+		/* in the same wall type as last time, so check for
+		 * optimized draw */
+		if(tex == (u16int)postsource){	/* wide scale */
+			postwidth++;
+			wallheight[i] = wallheight[i-1];
+			return;
+		}else{
+			ScalePost();
+			(u16int)postsource = tex;
+			postwidth = 1;
+			postx = i;
+		}
+	}else{	/* new wall */
+		if(lastside != -1)	// if not the first scaled post
+			ScalePost ();
+		lasttile = tile;
+		postx = i;
+		postwidth = 1;
+		p = vertwall[tile&63];
+		*( ((u16int *)&postsource)+1) = (u16int)PM_GetPage(p);
+		(u16int)postsource = tex;
 	}
-	free(m);
-	return n;
+#endif
 }
 
-int
-txth(char *t)
+static void
+hpush(int i, int tile)
 {
-	int h, n;
+	s16int p;
+	u16int tex, ofs;
 
-	h = fnt->h;
-	n = h;
-	while(*t != 0)
-		if(*t++ == '\n')
-			n += h;
-	return n;
+	tex = xin >> 4 & 0xfc0;
+	ofs = pusher.dopen << 10;
+	if(dty == -1)
+		yin += Dtlglobal - ofs;
+	else{
+		tex = 0xfc0 - tex;
+		yin += ofs;
+	}
+	p = 0;
+	USED(i, yin, tile, p, tex, ofs);
+#ifdef DICKS
+	wallheight[i] = walldy(xin, yin);
+	if(lasttilehit == tile){
+		/* in the same wall type as last time, so check for
+		 * optimized draw */
+		if(tex == (u16int)postsource){	/* wide scale */
+			postwidth++;
+			wallheight[i] = wallheight[i-1];
+			return;
+		}else{
+			ScalePost();
+			(u16int)postsource = tex;
+			postwidth = 1;
+			postx = i;
+		}
+	}else{	/* new wall */
+		if(lastside != -1)	/* if not the first scaled post */
+			ScalePost();
+		lasttile = tile;
+		postx = i;
+		postwidth = 1;
+		p = horizwall[tile&63];
+		*( ((u16int *)&postsource)+1) = (u16int)PM_GetPage(p);
+		(u16int)postsource = tex;
+	}
+#endif
 }
 
-int
-txtw(char *t)
+static void
+raytrace(void)
 {
-	int n, m;
+	int i, θ, tx, ty;
+	u8int n;
+	s16int in, xinh, yinh;
+	u16int dr, x, y, ∂x, ∂y, tilehit;
+	s32int rs, dx, dy;
 
-	n = m = 0;
-	while(*t != 0){
-		if(*t == '\n'){
-			if(n > m)
-				m = n;
-			n = 0;
-		}else
-			n += fnt->w[(uchar)*t];
-		t++;
+	i = 0;
+	tilehit = 0;
+loop:
+	θ = (midθ + Δvwθ[i]) % Fineθ;
+	if(θ < 0)
+		θ += Fineθ;
+	if(θ < 900){
+		dtx = 1;
+		dty = -1;
+		dx = ftan[900-1-θ];
+		dy = -ftan[θ];
+		∂x = ∂xup;
+		∂y = ∂ydown;
+	}else if(θ < 1800){
+		dtx = -1;
+		dty = -1;
+		dx = -ftan[θ-900];
+		dy = -ftan[1800-1-θ];
+		∂x = ∂xdown;
+		∂y = ∂ydown;
+	}else if(θ < 2700){
+		dtx = -1;
+		dty = 1;
+		dx = -ftan[2700-1-θ];
+		dy = ftan[θ-1800];
+		∂x = ∂xdown;
+		∂y = ∂yup;
+	}else{
+		dtx = 1;
+		dty = 1;
+		dx = ftan[θ-2700];
+		dy = ftan[3600-1-θ];
+		∂x = ∂xup;
+		∂y = ∂yup;
 	}
-	return n > m ? n : m;
+	yin = ffs(dy, ∂x) + vw.y;
+	yinh = yin >> 16;
+	tx = vw.tx + dtx;
+	x = yinh * Mapdxy + tx;
+	xin = ffs(dx, ∂y) + vw.x;
+	xinh = xin >> 16;
+	ty = vw.ty + dty;
+	y = ty * Mapdxy + xinh;
+
+vcheck:
+	if(dty * (yinh - ty) >= 0)
+		goto hentry;
+ventry:
+	n = tiles[x].tl;
+	if(n == 0){
+vpass:
+		tiles[x].vis++;
+		tx += dtx;
+		rs = (yinh << 16 | yin & 0xffff) + dy;
+		yinh = rs >> 16;
+		yin = yin & 0xffff0000 | rs & 0xffff;
+		x = yinh * Mapdxy + tx;
+		goto vcheck;
+	}
+	tilehit = tilehit & 0xff00 | n;
+	if(~n & 1<<7){
+		xin = tx << 16;
+		ty = yinh;
+		yin = yinh << 16 | yin & 0xffff;
+		vwall(i, tx, ty, tilehit);
+		goto next;
+	}
+	yin = yinh << 16 | yin & 0xffff;
+	if(n & 1<<6){
+		rs = ((s32int)pusher.dopen * dy >> 6) + yin;	/* sar */
+		in = rs >> Dtlshift;
+		if(in != yinh)
+			goto vpass;
+		yin = rs;
+		xin = tx << 16;
+		vpush(i, tilehit);
+		goto next;
+	}
+	rs = yin + (dy >> 1);	/* sar */
+	in = rs >> Dtlshift;
+	dr = rs & 0xffff;
+	if(yinh != in || dr < doors[n&0x7f].dopen)
+		goto vpass;
+	yin = yinh << 16 | dr;
+	xin = tx << 16 | 0x8000;	/* intercept in middle of tile */
+	vdoor(i, tilehit);
+	goto next;
+
+hcheck:
+	if(dtx * (xinh - tx) >= 0)
+		goto ventry;
+hentry:
+	n = tiles[y].tl;
+	if(n == 0){
+hpass:
+		tiles[y].vis++;
+		ty += dty;
+		rs = (xinh << 16 | xin & 0xffff) + dx;
+		xinh = rs >> 16;
+		xin = xin & 0xffff0000 | rs & 0xffff;
+		y = ty * Mapdxy + xinh;
+		goto hcheck;
+	}
+	tilehit = tilehit & 0xff00 | n;
+	if(~n & 1<<7){
+		xin = xinh << 16 | xin & 0xffff;
+		tx = xinh;
+		yin = ty << 16;
+		hwall(i, tx, ty, tilehit);
+		goto next;
+	}
+	yin = yinh << 16 | yin & 0xffff;
+	if(n & 1<<6){
+		rs = ((s32int)pusher.dopen * dx >> 6) + (xinh << 16 | xin & 0xffff);	/* sar */
+		in = rs >> Dtlshift;
+		if(in != xinh)
+			goto hpass;
+		xin = rs;
+		yin = ty << 16;
+		hpush(i, tilehit);
+		goto next;
+	}
+	rs = (xinh << 16 | xin & 0xffff) + (dx >> 1);	/* sar */
+	in = rs >> Dtlshift;
+	dr = rs & 0xffff;
+	if(xinh != in || dr < doors[n&0x7f].dopen)
+		goto hpass;
+	xin = xinh << 16 | dr;
+	yin = ty << 16 | 0x8000;	/* intercept in middle of tile */
+	hdoor(i, tilehit);
+
+next:
+	if(++i < vw.dx)
+		goto loop;
 }
 
+static void
+ScalePost(void)
+{
+#ifdef DICKS
+	ax = SCREENSEG;
+	es = ax;
+	bx = postx >> 1;
+
+	asm mov	bp,WORD PTR [wallheight+bx]	// fractional height (low 3 bits frac)
+	asm and	bp,0xfff8			// bp = heightscaler*4
+	asm shr	bp,1
+	asm cmp	bp,[maxscaleshl2]
+	asm jle	heightok
+	asm mov	bp,[maxscaleshl2]
+heightok:
+	asm add	bp,OFFSET fullscalefarcall
+
+	// scale a byte wide strip of wall
+	asm mov	bx,[postx]
+	asm mov	di,bx
+	asm shr	di,2		// X in bytes
+	asm add	di,[bufferofs]
+
+	asm and	bx,3
+	asm shl	bx,3		// bx = pixel*8+pixwidth
+	asm add	bx,[postwidth]
+
+	asm mov	al,BYTE PTR [mapmasks1-1+bx]	// -1 because no widths of 0
+	asm mov	dx,SC_INDEX+1
+	asm out	dx,al		// set bit mask register
+	asm lds	si,DWORD PTR [postsource]
+	asm call DWORD PTR [bp]	// scale the line of pixels
+
+	asm mov	al,BYTE PTR [ss:mapmasks2-1+bx]   // -1 because no widths of 0
+	asm or	al,al
+	asm jz	nomore
+
+	// draw a second byte for vertical strips that cross two bytes
+	asm inc	di
+	asm out	dx,al			// set bit mask register
+	asm call DWORD PTR [bp]		// scale the line of pixels
+
+	asm mov al,BYTE PTR [ss:mapmasks3-1+bx]	// -1 because no widths of 0
+	asm or	al,al
+	asm jz	nomore
+
+	// draw a third byte for vertical strips that cross three bytes
+	asm inc	di
+	asm out	dx,al			// set bit mask register
+	asm call DWORD PTR [bp]		// scale the line of pixels
+
+nomore:
+	asm mov	ax,ss
+	asm mov	ds,ax
+#endif
+}
+
+static void
+walls(void)
+{
+	vw.θ = oplr->θ;
+	midθ = vw.θ * (Fineθ / 360);
+	vw.sin = sint[vw.θ];
+	vw.cos = cost[vw.θ];
+	vw.x = oplr->x - ffs(Dfoclen, vw.cos);
+	vw.y = oplr->y + ffs(Dfoclen, vw.sin);
+	vw.tx = vw.x >> Dtlshift;
+	vw.ty = vw.y >> Dtlshift;
+	∂xdown = vw.x & Dtlglobal - 1;
+	∂xup = Dtlglobal - ∂xdown;
+	∂ydown = vw.y & Dtlglobal - 1;
+	∂yup = Dtlglobal - ∂ydown;
+
+	lastside = -1;	// the first pixel is on a new wall
+	raytrace();
+	ScalePost();	// no more optimization on last post
+}
+
+s32int
+ffs(s32int a, s32int b)
+{
+	int s;
+	u32int r;
+	uvlong h, l;
+
+	s = 0;
+	if(a < 0){
+		a = -a;
+		s ^= 1;
+	}
+	if(b < 0)
+		s ^= 1;
+	b &= 0xffff;
+	h = a >> 16;
+	l = a & 0xffff;
+	r = h * b + (l * b >> 16 & 0xffff);
+	return s ? -r : r;
+}
+
 void
-fill(int c)
+render(void)
 {
-	memset(pxb, c, sizeof pxb);
+	Tile *tl;
+
+	for(tl=tiles; tl<tiles+nelem(tiles); tl++)
+		tl->vis = 0;
+	clear();
+	walls();
+	scaleall();
+	topspr();
 }
 
 void
-pic(int x, int y, int n)
+initscal(void)
 {
-	Pic *p;
+	int i, an, dx, *p, *q, *e;
+	double dface;
 
-	p = pics+n;
-	put(x, y, p->x, p->y, p->p, 0);
+	dx = vw.dx / 2;
+	dface = Dfoclen + Dmin;
+	prjw = dx * dface / (Dglob/2);
+	prjh = prjw * Dtlglobal >> 6;
+
+	i = 0;
+	p = Δvwθ + dx;
+	e = p + dx;
+	q = p - 1;
+	dx = vw.dx;
+	while(p < e){
+		/* start 0.5px over so vw.θ bisects two middle pixels */
+		an = (float)atan(i++ * Dglob / dx / dface) * Rad;
+		*p++ = -an;
+		*q-- = an;
+	}
+
+	//SetupScaling(vw.dx * 1.5);
+}
+
+void
+setvw(int n)
+{
+	vw.size = n;
+	vw.dx = n * 16 & ~15;
+	vw.dy = n * 16 / 2 & ~1;
+	vw.mid = vw.dx / 2 - 1;
+	vw.Δhit = vw.dx / 10;
+	vw.ofs = Vw * (160 - vw.dy) / 2 + (Vw - vw.dx) / 2;
+	initscal();
+}
+
+void
+tab(void)
+{
+	s32int i, *f, *fe;
+	float a;
+	double t;
+
+	i = 0;
+	f = ftan;
+	fe = ftan + nelem(ftan) - 1;
+	while(f < fe){
+		t = tan((i++ + 0.5) / (double)Rad);
+		*f++ = t * Dtlglobal;
+		*fe-- = 1/t * Dtlglobal;
+	}
+
+	/* low word: fraction; high word: mbz except 1<<31, sign bit */
+	a = 0;
+	f = fe = sint;
+	while(f < sint + 91){
+		i = Dtlglobal * sin(a);
+		f[0] = f[360] = fe[180] = i;
+		fe[360] = f[180] = i | 1<<31;
+		a += Pi / 2 / 90;
+		f++, fe--;
+	}
+	cost = sint + 90;
 }
--- a/scale.c
+++ b/scale.c
@@ -1,8 +1,3 @@
-// WL_SCALE.C
-
-#include "WL_DEF.H"
-#pragma hdrstop
-
 #define OP_RETF	0xcb
 
 /*
@@ -18,8 +13,6 @@
 
 s16int			maxscale,maxscaleshl2;
 
-int	insetupscaling;
-
 /*
 =============================================================================
 
@@ -49,20 +42,16 @@
 }
 
 
-/*
-==========================
-=
-= SetupScaling
-=
-==========================
-*/
-
 void SetupScaling (s16int maxscaleheight)
 {
 	s16int		i,x,y;
 	u8int	far *dest;
 
-	insetupscaling = true;
+The dynamically compiled scaling routines are now a Bad Thing.  
+On uncached machines (the original target) they are the fastest 
+possible way to scale walls, but on modern processors you just 
+wind up thrashing the code cash and wrecking performance.  
+A simple looping texture mapper would be faster on 486+ machines.
 
 	maxscaleheight/=2;			// one scaler every two pixels
 
@@ -81,12 +70,10 @@
 	}
 	memset (scaledirectory,0,sizeof(scaledirectory));
 
-	MM_SortMem ();
-
 //
 // build the compiled scalers
 //
-	stepbytwo = viewheight/2;	// save space by double stepping
+	stepbytwo = vw.dy/2;	// save space by double stepping
 	MM_GetPtr (&(uchar *)work,20000);
 
 	for (i=1;i<=maxscaleheight;i++)
@@ -100,7 +87,6 @@
 //
 // compact memory and lock down scalers
 //
-	MM_SortMem ();
 	for (i=1;i<=maxscaleheight;i++)
 	{
 		MM_SetLock (&(uchar *)scaledirectory[i],true);
@@ -123,9 +109,7 @@
 // check for oversize wall drawing
 //
 	for (i=maxscaleheight;i<MAXSCALEHEIGHT;i++)
-		fullscalefarcall[i] = (s32int)BadScale;
-
-	insetupscaling = false;
+		fullscalefarcall[i] = (uintptr)BadScale;
 }
 
 //===========================================================================
@@ -152,6 +136,8 @@
 
 u16int BuildCompScale (s16int height, uchar **finalspot)
 {
+	a simple looping texture mapper would be better, simpler, faster
+
 	u8int		far *code;
 
 	s16int			i;
@@ -162,7 +148,7 @@
 
 	step = ((s32int)height<<16) / 64;
 	code = &work->code[0];
-	toppix = (viewheight-height)/2;
+	toppix = (vw.dy-height)/2;
 	fix = 0;
 
 	for (src=0;src<=64;src++)
@@ -187,7 +173,7 @@
 		startpix+=toppix;
 		endpix+=toppix;
 
-		if (startpix == endpix || endpix < 0 || startpix >= viewheight || src == 64)
+		if (startpix == endpix || endpix < 0 || startpix >= vw.dy || src == 64)
 			continue;
 
 	//
@@ -199,7 +185,7 @@
 
 		for (;startpix<endpix;startpix++)
 		{
-			if (startpix >= viewheight)
+			if (startpix >= vw.dy)
 				break;						// off the bottom of the view area
 			if (startpix < 0)
 				continue;					// not into the view area
@@ -397,7 +383,7 @@
 /*
 =======================
 =
-= ScaleShape
+= scalevis
 =
 = Draws a compiled shape at [scale] pixels high
 =
@@ -418,11 +404,11 @@
 
 static	s32int		longtemp;
 
-void ScaleShape (s16int xcenter, s16int shapenum, u16int height)
+void scalevis (s16int xcenter, s16int shapenum, u16int height)
 {
 	t_compshape	_seg *shape;
 	t_compscale _seg *comptable;
-	u16int	scale,srcx,stopx,tempx;
+	u16int	scale,srcx,stopx,tempx;	/* /!\ scale shadow */
 	s16int			t;
 	u16int	far *cmdptr;
 	int		leftvis,rightvis;
@@ -455,7 +441,7 @@
 		if (slinewidth == 1)
 		{
 			slinex--;
-			if (slinex<viewwidth)
+			if (slinex<vw.dx)
 			{
 				if (wallheight[slinex] >= height)
 					continue;		// obscured by closer wall
@@ -467,10 +453,10 @@
 		//
 		// handle multi pixel lines
 		//
-		if (slinex>viewwidth)
+		if (slinex>vw.dx)
 		{
 			slinex -= slinewidth;
-			slinewidth = viewwidth-slinex;
+			slinewidth = vw.dx-slinex;
 			if (slinewidth<1)
 				continue;		// still off the right side
 		}
@@ -529,7 +515,7 @@
 	}
 	slinewidth = 0;
 
-	while ( ++srcx <= stopx && (slinex+=slinewidth)<viewwidth)
+	while ( ++srcx <= stopx && (slinex+=slinewidth)<vw.dx)
 	{
 		(u16int)linecmds = *cmdptr++;
 		if ( !(slinewidth = comptable->width[srcx]) )
@@ -557,8 +543,8 @@
 		}
 		else
 		{
-			if (slinex + slinewidth > viewwidth)
-				slinewidth = viewwidth-slinex;
+			if (slinex + slinewidth > vw.dx)
+				slinewidth = vw.dx-slinex;
 		}
 
 
@@ -601,7 +587,7 @@
 /*
 =======================
 =
-= SimpleScaleShape
+= scalespr
 =
 = NO CLIPPING, height in pixels
 =
@@ -622,11 +608,11 @@
 =======================
 */
 
-void SimpleScaleShape (s16int xcenter, s16int shapenum, u16int height)
+void scalespr (s16int xcenter, s16int shapenum, u16int height)
 {
 	t_compshape	_seg *shape;
 	t_compscale _seg *comptable;
-	u16int	scale,srcx,stopx,tempx;
+	u16int	scale,srcx,stopx,tempx;	/* /!\ scale shadow */
 	s16int			t;
 	u16int	far *cmdptr;
 	int		leftvis,rightvis;
--- a/snd.c
+++ b/snd.c
@@ -7,6 +7,7 @@
 Dat *imfs;
 Sfx *sfxs;
 int sfxon, muson, pcmon;
+int sfxlck;
 
 enum{
 	Rate = 44100,
@@ -176,6 +177,41 @@
 static int hΔ[nelem(h)], xb[Npbuf], xbi;
 static ulong xt;
 
+static u8int ratt[][30] = {
+	{8,8,8,8,8,8,8,7,7,7,7,7,7,6,0,0,0,0,0,1,3,5,8,8,8,8,8,8,8,8},
+	{8,8,8,8,8,8,8,7,7,7,7,7,6,4,0,0,0,0,0,2,4,6,8,8,8,8,8,8,8,8},
+	{8,8,8,8,8,8,8,7,7,7,7,6,6,4,1,0,0,0,1,2,4,6,8,8,8,8,8,8,8,8},
+	{8,8,8,8,8,8,8,7,7,7,7,6,5,4,2,1,0,1,2,3,5,7,8,8,8,8,8,8,8,8},
+	{8,8,8,8,8,8,8,8,7,7,7,6,5,4,3,2,2,3,3,5,6,8,8,8,8,8,8,8,8,8},
+	{8,8,8,8,8,8,8,8,7,7,7,6,6,5,4,4,4,4,5,6,7,8,8,8,8,8,8,8,8,8},
+	{8,8,8,8,8,8,8,8,8,7,7,7,6,6,5,5,5,6,6,7,8,8,8,8,8,8,8,8,8,8},
+	{8,8,8,8,8,8,8,8,8,8,8,7,7,7,6,6,7,7,8,8,8,8,8,8,8,8,8,8,8,8},
+	{8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8},
+	{8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8},
+	{8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8},
+	{8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8},
+	{8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8},
+	{8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8},
+	{8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8}
+}, latt[][30] = {
+	{8,8,8,8,8,8,8,8,5,3,1,0,0,0,0,0,6,7,7,7,7,7,7,8,8,8,8,8,8,8},
+	{8,8,8,8,8,8,8,8,6,4,2,0,0,0,0,0,4,6,7,7,7,7,7,8,8,8,8,8,8,8},
+	{8,8,8,8,8,8,8,8,6,4,2,1,0,0,0,1,4,6,6,7,7,7,7,8,8,8,8,8,8,8},
+	{8,8,8,8,8,8,8,8,7,5,3,2,1,0,1,2,4,5,6,7,7,7,7,8,8,8,8,8,8,8},
+	{8,8,8,8,8,8,8,8,8,6,5,3,3,2,2,3,4,5,6,7,7,7,8,8,8,8,8,8,8,8},
+	{8,8,8,8,8,8,8,8,8,7,6,5,4,4,4,4,5,6,6,7,7,7,8,8,8,8,8,8,8,8},
+	{8,8,8,8,8,8,8,8,8,8,7,6,6,5,5,5,6,6,7,7,7,8,8,8,8,8,8,8,8,8},
+	{8,8,8,8,8,8,8,8,8,8,8,8,7,7,6,6,7,7,7,8,8,8,8,8,8,8,8,8,8,8},
+	{8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8},
+	{8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8},
+	{8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8},
+	{8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8},
+	{8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8},
+	{8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8},
+	{8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8}
+};
+static int atton, attx, atty, lvol, rvol;
+
 static void
 stopal(void)
 {
@@ -231,11 +267,10 @@
 static void
 opl2step(void)
 {
-	uchar *p, *e;
+	uchar *p;
 
 	p = sbuf;
-	e = p + sizeof sbuf;
-	while(p < e){
+	while(p < sbuf + sizeof sbuf){
 		if(stc == sdt && sfxd != nil)
 			alcmd();
 		if(stc == mdt && imfd != nil)
@@ -251,9 +286,10 @@
 {
 	ulong l, p, i;
 	int *x, o, a;
+	s16int m;
 	vlong v;
 
-	if(s >= sbuf+sizeof sbuf)
+	if(s >= sbuf + sizeof sbuf)
 		return;
 	v = 0;
 	x = &xb[xt>>Np];	/* left side */
@@ -277,13 +313,22 @@
 	v >>= 2;	/* scale */
 	v *= Lscale;
 	v >>= 27;
-	o = (v >> 16) + (short)(s[0] | s[1]<<8);	/* mix */
+
+	m = s[0] | s[1] << 8;
+	o = (s32int)(v >> 16) * lvol / 16 + m;
 	if(o > 32767)
 		o = 32767;
 	else if(o < -32768)
 		o = -32768;
-	s[0] = s[2] = o;
-	s[1] = s[3] = o>>8;
+	s[0] = o;
+	s[1] = o >> 8;
+	o = (s32int)(v >> 16) * rvol / 16 + m;
+	if(o > 32767)
+		o = 32767;
+	else if(o < -32768)
+		o = -32768;
+	s[2] = o;
+	s[3] = o >> 8;
 }
 
 static void
@@ -298,7 +343,7 @@
 		for(i=xbi; n>0 && i<Npbuf; n--, i++)
 			xb[i] = ((uint)*p++ << 24) - 0x7fffffff;
 		xbi = i;
-		if(i < 2*Nextra)	/* minimum for filter */
+		if(i < 2 * Nextra)	/* minimum for filter */
 			break;
 		e = i - Nextra << Np;
 		while(xt < e){	/* process buffer and mix */
@@ -313,7 +358,7 @@
 			e -= Nextra;
 			i -= e;
 			if(i > 0){
-				memmove(xb+s, xb+e, i * sizeof i);
+				memmove(xb + s, xb + e, i * sizeof i);
 				s += i;
 			}
 			xbi = s;
@@ -322,6 +367,34 @@
 }
 
 static void
+setvol(void)
+{
+	int x, y, ax, ay;
+	s32int f;
+
+	if(!atton){
+		lvol = rvol = 16;
+		return;
+	}
+	ax = attx - vw.x;
+	ay = atty - vw.y;
+	f = ffs(ax, vw.cos);
+	x = f - ffs(ay, vw.sin) >> Dtlshift;
+	f = ffs(ax, vw.sin);
+	y = f + ffs(ay, vw.cos) >> Dtlshift;
+	if(x < 0)
+		x = -x;
+	if(x >= nelem(latt))
+		x = nelem(latt) - 1;
+	if(y < -nelem(latt))
+		y = -nelem(latt);
+	else if(y >= nelem(latt))
+		y = nelem(latt) - 1;
+	lvol = 16 - latt[x][nelem(latt)+y];
+	rvol = 16 - ratt[x][nelem(latt)+y];
+}
+
+static void
 pcmstep(void)
 {
 	uchar *e, *p;
@@ -332,6 +405,7 @@
 		return;
 	if(p + Pdiv < e)
 		e = p + Pdiv;
+	setvol();
 	resample(p, e-p);
 	pcm = e;
 }
@@ -343,7 +417,8 @@
 		return;
 	opl2step();
 	pcmstep();
-	write(sfd, sbuf, sizeof sbuf);
+	if(!nosleep)
+		write(sfd, sbuf, sizeof sbuf);
 }
 
 void
@@ -354,17 +429,27 @@
 	pcmd = nil;
 }
 
+int
+lastsfx(void)
+{
+	if(pcm < pcme)
+		return pcmd - sfxs;
+	else if(sfxd != nil)
+		return sfxd - sfxs;
+	return -1;
+}
+
 void
-sfx(int n)
+sfxatt(int n, int att, int x, int y)
 {
 	Sfx *s;
-	uchar *r, *i, *e;
+	uchar *r, *i;
 
-	s = sfxs+n;
-	if(sfd < 0 || !sfxon)
+	if(sfd < 0 || !sfxon || sfxlck)
 		return;
+	s = sfxs+n;
 	if(pcmon && s->pcm != nil){
-		if(pcmd != nil && s->pri < pcmd->pri)
+		if(pcm < pcme && s->pri < pcmd->pri)
 			return;
 		pcmd = s;
 		pcm = s->pcm->p;
@@ -371,6 +456,12 @@
 		pcme = s->pcm->e;
 		xbi = Nextra;
 		xt = Nextra << Np;
+		if(att){
+			atton = 1;
+			attx = x;
+			atty = y;
+		}else
+			atton = 0;
 	}else{
 		if(sfxd != nil && s->pri < sfxd->pri)
 			return;
@@ -381,18 +472,25 @@
 		sdt = stc;
 		i = s->inst;
 		r = inst;
-		e = r + sizeof inst;
-		while(r < e)
+		while(r < inst + sizeof inst)
 			opl2wr(*r++, *i++);
 	}
 }
 
 void
+sfx(int n)
+{
+	sfxatt(n, 0, 0, 0);
+}
+
+void
 stopmus(void)
 {
 	int i;
 
 	stopsfx();
+	if(!muson && !sfxon)
+		return;
 	opl2wr(Ropm, 0);
 	for(i=Roct+1; i<Roct+9; i++)
 		opl2wr(i, 0);
--- a/state.c
+++ /dev/null
@@ -1,1480 +1,0 @@
-// WL_STATE.C
-
-#include "WL_DEF.H"
-#pragma hdrstop
-
-/*
-=============================================================================
-
-						 LOCAL CONSTANTS
-
-=============================================================================
-*/
-
-
-/*
-=============================================================================
-
-						 GLOBAL VARIABLES
-
-=============================================================================
-*/
-
-
-dirtype opposite[9] =
-	{west,southwest,south,southeast,east,northeast,north,northwest,nodir};
-
-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}
-};
-
-
-
-void	SpawnNewObj (u16int tilex, u16int tiley, statetype *state);
-void	NewState (objtype *ob, statetype *state);
-
-int TryWalk (objtype *ob);
-void	MoveObj (objtype *ob, s32int move);
-
-void	KillActor (objtype *ob);
-void	DamageActor (objtype *ob, u16int damage);
-
-int CheckLine (objtype *ob);
-void FirstSighting (objtype *ob);
-int	CheckSight (objtype *ob);
-
-/*
-=============================================================================
-
-						 LOCAL VARIABLES
-
-=============================================================================
-*/
-
-
-
-//===========================================================================
-
-
-/*
-===================
-=
-= SpawnNewObj
-=
-= Spaws a new actor at the given TILE coordinates, with the given state, and
-= the given size in GLOBAL units.
-=
-= new			= a pointer to an initialized new actor
-=
-===================
-*/
-
-void SpawnNewObj (u16int tilex, u16int tiley, statetype *state)
-{
-	GetNewActor ();
-	new->state = state;
-	if (state->tictime)
-		new->ticcount = US_RndT () % state->tictime;
-	else
-		new->ticcount = 0;
-
-	new->tilex = tilex;
-	new->tiley = tiley;
-	new->x = ((s32int)tilex<<TILESHIFT)+TILEGLOBAL/2;
-	new->y = ((s32int)tiley<<TILESHIFT)+TILEGLOBAL/2;
-	new->dir = nodir;
-
-	actorat[tilex][tiley] = new;
-	new->areanumber =
-		*(mapsegs[0] + farmapylookup[new->tiley]+new->tilex) - AREATILE;
-}
-
-
-
-/*
-===================
-=
-= NewState
-=
-= Changes ob to a new state, setting ticcount to the max for that state
-=
-===================
-*/
-
-void NewState (objtype *ob, statetype *state)
-{
-	ob->state = state;
-	ob->ticcount = state->tictime;
-}
-
-
-
-/*
-=============================================================================
-
-				ENEMY TILE WORLD MOVEMENT CODE
-
-=============================================================================
-*/
-
-
-/*
-==================================
-=
-= TryWalk
-=
-= Attempts to move ob in its current (ob->dir) direction.
-=
-= If blocked by either a wall or an actor returns FALSE
-=
-= If move is either clear or blocked only by a door, returns TRUE and sets
-=
-= ob->tilex			= new destination
-= ob->tiley
-= ob->areanumber    = the floor tile number (0-(NUMAREAS-1)) of destination
-= ob->distance  	= TILEGLOBAl, or -doornumber if a door is blocking the way
-=
-= If a door is in the way, an OpenDoor call is made to start it opening.
-= The actor code should wait until
-= 	doorobjlist[-ob->distance].action = dr_open, meaning the door has been
-=	fully opened
-=
-==================================
-*/
-
-#define CHECKDIAG(x,y)								\
-{                                                   \
-	temp=(u16int)actorat[x][y];                   \
-	if (temp)                                       \
-	{                                               \
-		if (temp<256)                               \
-			return false;                           \
-		if (((objtype *)temp)->flags&FL_SHOOTABLE)  \
-			return false;                           \
-	}                                               \
-}
-
-#define CHECKSIDE(x,y)								\
-{                                                   \
-	temp=(u16int)actorat[x][y];                   \
-	if (temp)                                       \
-	{                                               \
-		if (temp<128)                               \
-			return false;                           \
-		if (temp<256)                               \
-			doornum = temp&63;                      \
-		else if (((objtype *)temp)->flags&FL_SHOOTABLE)\
-			return false;                           \
-	}                                               \
-}
-
-
-int TryWalk (objtype *ob)
-{
-	s16int			doornum;
-	u16int	temp;
-
-	doornum = -1;
-
-	if (ob->obclass == inertobj)
-	{
-		switch (ob->dir)
-		{
-		case north:
-			ob->tiley--;
-			break;
-
-		case northeast:
-			ob->tilex++;
-			ob->tiley--;
-			break;
-
-		case east:
-			ob->tilex++;
-			break;
-
-		case southeast:
-			ob->tilex++;
-			ob->tiley++;
-			break;
-
-		case south:
-			ob->tiley++;
-			break;
-
-		case southwest:
-			ob->tilex--;
-			ob->tiley++;
-			break;
-
-		case west:
-			ob->tilex--;
-			break;
-
-		case northwest:
-			ob->tilex--;
-			ob->tiley--;
-			break;
-		}
-	}
-	else
-		switch (ob->dir)
-		{
-		case north:
-			if (ob->obclass == dogobj || ob->obclass == fakeobj)
-			{
-				CHECKDIAG(ob->tilex,ob->tiley-1);
-			}
-			else
-			{
-				CHECKSIDE(ob->tilex,ob->tiley-1);
-			}
-			ob->tiley--;
-			break;
-
-		case northeast:
-			CHECKDIAG(ob->tilex+1,ob->tiley-1);
-			CHECKDIAG(ob->tilex+1,ob->tiley);
-			CHECKDIAG(ob->tilex,ob->tiley-1);
-			ob->tilex++;
-			ob->tiley--;
-			break;
-
-		case east:
-			if (ob->obclass == dogobj || ob->obclass == fakeobj)
-			{
-				CHECKDIAG(ob->tilex+1,ob->tiley);
-			}
-			else
-			{
-				CHECKSIDE(ob->tilex+1,ob->tiley);
-			}
-			ob->tilex++;
-			break;
-
-		case southeast:
-			CHECKDIAG(ob->tilex+1,ob->tiley+1);
-			CHECKDIAG(ob->tilex+1,ob->tiley);
-			CHECKDIAG(ob->tilex,ob->tiley+1);
-			ob->tilex++;
-			ob->tiley++;
-			break;
-
-		case south:
-			if (ob->obclass == dogobj || ob->obclass == fakeobj)
-			{
-				CHECKDIAG(ob->tilex,ob->tiley+1);
-			}
-			else
-			{
-				CHECKSIDE(ob->tilex,ob->tiley+1);
-			}
-			ob->tiley++;
-			break;
-
-		case southwest:
-			CHECKDIAG(ob->tilex-1,ob->tiley+1);
-			CHECKDIAG(ob->tilex-1,ob->tiley);
-			CHECKDIAG(ob->tilex,ob->tiley+1);
-			ob->tilex--;
-			ob->tiley++;
-			break;
-
-		case west:
-			if (ob->obclass == dogobj || ob->obclass == fakeobj)
-			{
-				CHECKDIAG(ob->tilex-1,ob->tiley);
-			}
-			else
-			{
-				CHECKSIDE(ob->tilex-1,ob->tiley);
-			}
-			ob->tilex--;
-			break;
-
-		case northwest:
-			CHECKDIAG(ob->tilex-1,ob->tiley-1);
-			CHECKDIAG(ob->tilex-1,ob->tiley);
-			CHECKDIAG(ob->tilex,ob->tiley-1);
-			ob->tilex--;
-			ob->tiley--;
-			break;
-
-		case nodir:
-			return false;
-
-		default:
-			Quit ("Walk: Bad dir");
-		}
-
-	if (doornum != -1)
-	{
-		OpenDoor (doornum);
-		ob->distance = -doornum-1;
-		return true;
-	}
-
-
-	ob->areanumber =
-		*(mapsegs[0] + farmapylookup[ob->tiley]+ob->tilex) - AREATILE;
-
-	ob->distance = TILEGLOBAL;
-	return true;
-}
-
-
-
-/*
-==================================
-=
-= SelectDodgeDir
-=
-= Attempts to choose and initiate a movement for ob that sends it towards
-= the player while dodging
-=
-= If there is no possible move (ob is totally surrounded)
-=
-= ob->dir			=	nodir
-=
-= Otherwise
-=
-= ob->dir			= new direction to follow
-= ob->distance		= TILEGLOBAL or -doornumber
-= ob->tilex			= new destination
-= ob->tiley
-= ob->areanumber    = the floor tile number (0-(NUMAREAS-1)) of destination
-=
-==================================
-*/
-
-void SelectDodgeDir (objtype *ob)
-{
-	s16int 		deltax,deltay,i;
-	u16int	absdx,absdy;
-	dirtype 	dirtry[5];
-	dirtype 	turnaround,tdir;
-
-	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];
-
-	deltax = player->tilex - ob->tilex;
-	deltay = player->tiley - ob->tiley;
-
-//
-// arange 5 direction choices in order of preference
-// the four cardinal directions plus the diagonal straight towards
-// the player
-//
-
-	if (deltax>0)
-	{
-		dirtry[1]= east;
-		dirtry[3]= west;
-	}
-	else
-	{
-		dirtry[1]= west;
-		dirtry[3]= east;
-	}
-
-	if (deltay>0)
-	{
-		dirtry[2]= south;
-		dirtry[4]= north;
-	}
-	else
-	{
-		dirtry[2]= north;
-		dirtry[4]= south;
-	}
-
-//
-// randomize a bit for dodging
-//
-	absdx = abs(deltax);
-	absdy = abs(deltay);
-
-	if (absdx > absdy)
-	{
-		tdir = dirtry[1];
-		dirtry[1] = dirtry[2];
-		dirtry[2] = tdir;
-		tdir = dirtry[3];
-		dirtry[3] = dirtry[4];
-		dirtry[4] = tdir;
-	}
-
-	if (US_RndT() < 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] ];
-
-//
-// try the directions util one works
-//
-	for (i=0;i<5;i++)
-	{
-		if ( dirtry[i] == nodir || dirtry[i] == turnaround)
-			continue;
-
-		ob->dir = dirtry[i];
-		if (TryWalk(ob))
-			return;
-	}
-
-//
-// turn around only as a last resort
-//
-	if (turnaround != nodir)
-	{
-		ob->dir = turnaround;
-
-		if (TryWalk(ob))
-			return;
-	}
-
-	ob->dir = nodir;
-}
-
-
-/*
-============================
-=
-= SelectChaseDir
-=
-= As SelectDodgeDir, but doesn't try to dodge
-=
-============================
-*/
-
-void SelectChaseDir (objtype *ob)
-{
-	s16int deltax,deltay,i;
-	dirtype d[3];
-	dirtype tdir, olddir, turnaround;
-
-
-	olddir=ob->dir;
-	turnaround=opposite[olddir];
-
-	deltax=player->tilex - ob->tilex;
-	deltay=player->tiley - ob->tiley;
-
-	d[1]=nodir;
-	d[2]=nodir;
-
-	if (deltax>0)
-		d[1]= east;
-	else if (deltax<0)
-		d[1]= west;
-	if (deltay>0)
-		d[2]=south;
-	else if (deltay<0)
-		d[2]=north;
-
-	if (abs(deltay)>abs(deltax))
-	{
-		tdir=d[1];
-		d[1]=d[2];
-		d[2]=tdir;
-	}
-
-	if (d[1]==turnaround)
-		d[1]=nodir;
-	if (d[2]==turnaround)
-		d[2]=nodir;
-
-
-	if (d[1]!=nodir)
-	{
-		ob->dir=d[1];
-		if (TryWalk(ob))
-			return;     /*either moved forward or attacked*/
-	}
-
-	if (d[2]!=nodir)
-	{
-		ob->dir=d[2];
-		if (TryWalk(ob))
-			return;
-	}
-
-/* there is no direct path to the player, so pick another direction */
-
-	if (olddir!=nodir)
-	{
-		ob->dir=olddir;
-		if (TryWalk(ob))
-			return;
-	}
-
-	if (US_RndT()>128) 	/*randomly determine direction of search*/
-	{
-		for (tdir=north;tdir<=west;tdir++)
-		{
-			if (tdir!=turnaround)
-			{
-				ob->dir=tdir;
-				if ( TryWalk(ob) )
-					return;
-			}
-		}
-	}
-	else
-	{
-		for (tdir=west;tdir>=north;tdir--)
-		{
-			if (tdir!=turnaround)
-			{
-			  ob->dir=tdir;
-			  if ( TryWalk(ob) )
-				return;
-			}
-		}
-	}
-
-	if (turnaround !=  nodir)
-	{
-		ob->dir=turnaround;
-		if (ob->dir != nodir)
-		{
-			if ( TryWalk(ob) )
-				return;
-		}
-	}
-
-	ob->dir = nodir;		// can't move
-}
-
-
-/*
-============================
-=
-= SelectRunDir
-=
-= Run Away from player
-=
-============================
-*/
-
-void SelectRunDir (objtype *ob)
-{
-	s16int deltax,deltay,i;
-	dirtype d[3];
-	dirtype tdir, olddir, turnaround;
-
-
-	deltax=player->tilex - ob->tilex;
-	deltay=player->tiley - ob->tiley;
-
-	if (deltax<0)
-		d[1]= east;
-	else
-		d[1]= west;
-	if (deltay<0)
-		d[2]=south;
-	else
-		d[2]=north;
-
-	if (abs(deltay)>abs(deltax))
-	{
-		tdir=d[1];
-		d[1]=d[2];
-		d[2]=tdir;
-	}
-
-	ob->dir=d[1];
-	if (TryWalk(ob))
-		return;     /*either moved forward or attacked*/
-
-	ob->dir=d[2];
-	if (TryWalk(ob))
-		return;
-
-/* there is no direct path to the player, so pick another direction */
-
-	if (US_RndT()>128) 	/*randomly determine direction of search*/
-	{
-		for (tdir=north;tdir<=west;tdir++)
-		{
-			ob->dir=tdir;
-			if ( TryWalk(ob) )
-				return;
-		}
-	}
-	else
-	{
-		for (tdir=west;tdir>=north;tdir--)
-		{
-			ob->dir=tdir;
-			if ( TryWalk(ob) )
-			  return;
-		}
-	}
-
-	ob->dir = nodir;		// can't move
-}
-
-
-/*
-=================
-=
-= MoveObj
-=
-= Moves ob be move global units in ob->dir direction
-= Actors are not allowed to move inside the player
-= Does NOT check to see if the move is tile map valid
-=
-= ob->x			= adjusted for new position
-= ob->y
-=
-=================
-*/
-
-void MoveObj (objtype *ob, s32int move)
-{
-	s32int	deltax,deltay;
-
-	switch (ob->dir)
-	{
-	case north:
-		ob->y -= move;
-		break;
-	case northeast:
-		ob->x += move;
-		ob->y -= move;
-		break;
-	case east:
-		ob->x += move;
-		break;
-	case southeast:
-		ob->x += move;
-		ob->y += move;
-		break;
-	case south:
-		ob->y += move;
-		break;
-	case southwest:
-		ob->x -= move;
-		ob->y += move;
-		break;
-	case west:
-		ob->x -= move;
-		break;
-	case northwest:
-		ob->x -= move;
-		ob->y -= move;
-		break;
-
-	case nodir:
-		return;
-
-	default:
-		Quit ("MoveObj: bad dir!");
-	}
-
-//
-// check to make sure it's not on top of player
-//
-	if (areabyplayer[ob->areanumber])
-	{
-		deltax = ob->x - player->x;
-		if (deltax < -MINACTORDIST || deltax > MINACTORDIST)
-			goto moveok;
-		deltay = ob->y - player->y;
-		if (deltay < -MINACTORDIST || deltay > MINACTORDIST)
-			goto moveok;
-
-		if (ob->obclass == ghostobj || ob->obclass == spectreobj)
-			TakeDamage (tics*2,ob);
-
-	//
-	// back up
-	//
-		switch (ob->dir)
-		{
-		case north:
-			ob->y += move;
-			break;
-		case northeast:
-			ob->x -= move;
-			ob->y += move;
-			break;
-		case east:
-			ob->x -= move;
-			break;
-		case southeast:
-			ob->x -= move;
-			ob->y -= move;
-			break;
-		case south:
-			ob->y -= move;
-			break;
-		case southwest:
-			ob->x += move;
-			ob->y -= move;
-			break;
-		case west:
-			ob->x += move;
-			break;
-		case northwest:
-			ob->x += move;
-			ob->y += move;
-			break;
-
-		case nodir:
-			return;
-		}
-		return;
-	}
-moveok:
-	ob->distance -=move;
-}
-
-/*
-=============================================================================
-
-							STUFF
-
-=============================================================================
-*/
-
-/*
-===============
-=
-= DropItem
-=
-= Tries to drop a bonus item somewhere in the tiles surrounding the
-= given tilex/tiley
-=
-===============
-*/
-
-void DropItem (stat_t itemtype, s16int tilex, s16int tiley)
-{
-	s16int	x,y,xl,xh,yl,yh;
-
-//
-// find a free spot to put it in
-//
-	if (!actorat[tilex][tiley])
-	{
-		PlaceItemType (itemtype, tilex,tiley);
-		return;
-	}
-
-	xl = tilex-1;
-	xh = tilex+1;
-	yl = tiley-1;
-	yh = tiley+1;
-
-	for (x=xl ; x<= xh ; x++)
-		for (y=yl ; y<= yh ; y++)
-			if (!actorat[x][y])
-			{
-				PlaceItemType (itemtype, x,y);
-				return;
-			}
-}
-
-
-
-/*
-===============
-=
-= KillActor
-=
-===============
-*/
-
-void KillActor (objtype *ob)
-{
-	s16int	tilex,tiley;
-
-	tilex = ob->tilex = ob->x >> TILESHIFT;		// drop item on center
-	tiley = ob->tiley = ob->y >> TILESHIFT;
-
-	switch (ob->obclass)
-	{
-	case guardobj:
-		GivePoints (100);
-		NewState (ob,&s_grddie1);
-		PlaceItemType (bo_clip2,tilex,tiley);
-		break;
-
-	case officerobj:
-		GivePoints (400);
-		NewState (ob,&s_ofcdie1);
-		PlaceItemType (bo_clip2,tilex,tiley);
-		break;
-
-	case mutantobj:
-		GivePoints (700);
-		NewState (ob,&s_mutdie1);
-		PlaceItemType (bo_clip2,tilex,tiley);
-		break;
-
-	case ssobj:
-		GivePoints (500);
-		NewState (ob,&s_ssdie1);
-		if (gamestate.bestweapon < wp_machinegun)
-			PlaceItemType (bo_machinegun,tilex,tiley);
-		else
-			PlaceItemType (bo_clip2,tilex,tiley);
-		break;
-
-	case dogobj:
-		GivePoints (200);
-		NewState (ob,&s_dogdie1);
-		break;
-
-#ifndef SPEAR
-	case bossobj:
-		GivePoints (5000);
-		NewState (ob,&s_bossdie1);
-		PlaceItemType (bo_key1,tilex,tiley);
-		break;
-
-	case gretelobj:
-		GivePoints (5000);
-		NewState (ob,&s_greteldie1);
-		PlaceItemType (bo_key1,tilex,tiley);
-		break;
-
-	case giftobj:
-		GivePoints (5000);
-		gamestate.killx = player->x;
-		gamestate.killy = player->y;
-		NewState (ob,&s_giftdie1);
-		break;
-
-	case fatobj:
-		GivePoints (5000);
-		gamestate.killx = player->x;
-		gamestate.killy = player->y;
-		NewState (ob,&s_fatdie1);
-		break;
-
-	case schabbobj:
-		GivePoints (5000);
-		gamestate.killx = player->x;
-		gamestate.killy = player->y;
-		NewState (ob,&s_schabbdie1);
-		A_DeathScream(ob);
-		break;
-	case fakeobj:
-		GivePoints (2000);
-		NewState (ob,&s_fakedie1);
-		break;
-
-	case mechahitlerobj:
-		GivePoints (5000);
-		NewState (ob,&s_mechadie1);
-		break;
-	case realhitlerobj:
-		GivePoints (5000);
-		gamestate.killx = player->x;
-		gamestate.killy = player->y;
-		NewState (ob,&s_hitlerdie1);
-		A_DeathScream(ob);
-		break;
-#else
-	case spectreobj:
-		GivePoints (200);
-		NewState (ob,&s_spectredie1);
-		break;
-
-	case angelobj:
-		GivePoints (5000);
-		NewState (ob,&s_angeldie1);
-		break;
-
-	case transobj:
-		GivePoints (5000);
-		NewState (ob,&s_transdie0);
-		PlaceItemType (bo_key1,tilex,tiley);
-		break;
-
-	case uberobj:
-		GivePoints (5000);
-		NewState (ob,&s_uberdie0);
-		PlaceItemType (bo_key1,tilex,tiley);
-		break;
-
-	case willobj:
-		GivePoints (5000);
-		NewState (ob,&s_willdie1);
-		PlaceItemType (bo_key1,tilex,tiley);
-		break;
-
-	case deathobj:
-		GivePoints (5000);
-		NewState (ob,&s_deathdie1);
-		PlaceItemType (bo_key1,tilex,tiley);
-		break;
-#endif
-	}
-
-	gamestate.killcount++;
-	ob->flags &= ~FL_SHOOTABLE;
-	actorat[ob->tilex][ob->tiley] = NULL;
-	ob->flags |= FL_NONMARK;
-}
-
-
-
-/*
-===================
-=
-= DamageActor
-=
-= Called when the player succesfully hits an enemy.
-=
-= Does damage points to enemy ob, either putting it into a stun frame or
-= killing it.
-=
-===================
-*/
-
-void DamageActor (objtype *ob, u16int damage)
-{
-	madenoise = true;
-
-//
-// do double damage if shooting a non attack mode actor
-//
-	if ( !(ob->flags & FL_ATTACKMODE) )
-		damage <<= 1;
-
-	ob->hitpoints -= damage;
-
-	if (ob->hitpoints<=0)
-		KillActor (ob);
-	else
-	{
-		if (! (ob->flags & FL_ATTACKMODE) )
-			FirstSighting (ob);		// put into combat mode
-
-		switch (ob->obclass)		// dogs only have one hit point
-		{
-		case guardobj:
-			if (ob->hitpoints&1)
-				NewState (ob,&s_grdpain);
-			else
-				NewState (ob,&s_grdpain1);
-			break;
-
-		case officerobj:
-			if (ob->hitpoints&1)
-				NewState (ob,&s_ofcpain);
-			else
-				NewState (ob,&s_ofcpain1);
-			break;
-
-		case mutantobj:
-			if (ob->hitpoints&1)
-				NewState (ob,&s_mutpain);
-			else
-				NewState (ob,&s_mutpain1);
-			break;
-
-		case ssobj:
-			if (ob->hitpoints&1)
-				NewState (ob,&s_sspain);
-			else
-				NewState (ob,&s_sspain1);
-
-			break;
-
-		}
-	}
-}
-
-/*
-=============================================================================
-
-							CHECKSIGHT
-
-=============================================================================
-*/
-
-
-/*
-=====================
-=
-= CheckLine
-=
-= Returns true if a straight line between the player and ob is unobstructed
-=
-=====================
-*/
-
-int CheckLine (objtype *ob)
-{
-	s16int	x1,y1,xt1,yt1,x2,y2,xt2,yt2;
-	s16int	x,y;
-	s16int	xdist,ydist,xstep,ystep;
-	s16int	temp;
-	s16int	partial,delta;
-	s32int	ltemp;
-	s16int	xfrac,yfrac,deltafrac;
-	u16int	value,intercept;
-
-	x1 = ob->x >> UNSIGNEDSHIFT;		// 1/256 tile precision
-	y1 = ob->y >> UNSIGNEDSHIFT;
-	xt1 = x1 >> 8;
-	yt1 = y1 >> 8;
-
-	x2 = plux;
-	y2 = pluy;
-	xt2 = player->tilex;
-	yt2 = player->tiley;
-
-
-	xdist = abs(xt2-xt1);
-
-	if (xdist > 0)
-	{
-		if (xt2 > xt1)
-		{
-			partial = 256-(x1&0xff);
-			xstep = 1;
-		}
-		else
-		{
-			partial = x1&0xff;
-			xstep = -1;
-		}
-
-		deltafrac = abs(x2-x1);
-		delta = y2-y1;
-		ltemp = ((s32int)delta<<8)/deltafrac;
-		if (ltemp > 0x7fffl)
-			ystep = 0x7fff;
-		else if (ltemp < -0x7fffl)
-			ystep = -0x7fff;
-		else
-			ystep = ltemp;
-		yfrac = y1 + (((s32int)ystep*partial) >>8);
-
-		x = xt1+xstep;
-		xt2 += xstep;
-		do
-		{
-			y = yfrac>>8;
-			yfrac += ystep;
-
-			value = (u16int)tilemap[x][y];
-			x += xstep;
-
-			if (!value)
-				continue;
-
-			if (value<128 || value>256)
-				return false;
-
-			//
-			// see if the door is open enough
-			//
-			value &= ~0x80;
-			intercept = yfrac-ystep/2;
-
-			if (intercept>doorposition[value])
-				return false;
-
-		} while (x != xt2);
-	}
-
-	ydist = abs(yt2-yt1);
-
-	if (ydist > 0)
-	{
-		if (yt2 > yt1)
-		{
-			partial = 256-(y1&0xff);
-			ystep = 1;
-		}
-		else
-		{
-			partial = y1&0xff;
-			ystep = -1;
-		}
-
-		deltafrac = abs(y2-y1);
-		delta = x2-x1;
-		ltemp = ((s32int)delta<<8)/deltafrac;
-		if (ltemp > 0x7fffl)
-			xstep = 0x7fff;
-		else if (ltemp < -0x7fffl)
-			xstep = -0x7fff;
-		else
-			xstep = ltemp;
-		xfrac = x1 + (((s32int)xstep*partial) >>8);
-
-		y = yt1 + ystep;
-		yt2 += ystep;
-		do
-		{
-			x = xfrac>>8;
-			xfrac += xstep;
-
-			value = (u16int)tilemap[x][y];
-			y += ystep;
-
-			if (!value)
-				continue;
-
-			if (value<128 || value>256)
-				return false;
-
-			//
-			// see if the door is open enough
-			//
-			value &= ~0x80;
-			intercept = xfrac-xstep/2;
-
-			if (intercept>doorposition[value])
-				return false;
-		} while (y != yt2);
-	}
-
-	return true;
-}
-
-
-
-/*
-================
-=
-= 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
-=
-================
-*/
-
-#define MINSIGHT	0x18000l
-
-int CheckSight (objtype *ob)
-{
-	s32int		deltax,deltay;
-
-//
-// 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
-//
-	deltax = player->x - ob->x;
-	deltay = player->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;
-	}
-
-//
-// trace a line to check for blocking tiles (corners)
-//
-	return CheckLine (ob);
-
-}
-
-
-
-/*
-===============
-=
-= FirstSighting
-=
-= Puts an actor into attack mode and possibly reverses the direction
-= if the player is behind it
-=
-===============
-*/
-
-void FirstSighting (objtype *ob)
-{
-//
-// react to the player
-//
-	switch (ob->obclass)
-	{
-	case guardobj:
-		PlaySoundLocActor(Sgd,ob);
-		NewState (ob,&s_grdchase1);
-		ob->speed *= 3;			// go faster when chasing player
-		break;
-
-	case officerobj:
-		PlaySoundLocActor(Soffc,ob);
-		NewState (ob,&s_ofcchase1);
-		ob->speed *= 5;			// go faster when chasing player
-		break;
-
-	case mutantobj:
-		NewState (ob,&s_mutchase1);
-		ob->speed *= 3;			// go faster when chasing player
-		break;
-
-	case ssobj:
-		PlaySoundLocActor(Sss,ob);
-		NewState (ob,&s_sschase1);
-		ob->speed *= 4;			// go faster when chasing player
-		break;
-
-	case dogobj:
-		PlaySoundLocActor(Sdogbark,ob);
-		NewState (ob,&s_dogchase1);
-		ob->speed *= 2;			// go faster when chasing player
-		break;
-
-#ifndef SPEAR
-	case bossobj:
-		SD_PlaySound(Shans);
-		NewState (ob,&s_bosschase1);
-		ob->speed = SPDPATROL*3;	// go faster when chasing player
-		break;
-
-	case gretelobj:
-		SD_PlaySound(Sgretel);
-		NewState (ob,&s_gretelchase1);
-		ob->speed *= 3;			// go faster when chasing player
-		break;
-
-	case giftobj:
-		SD_PlaySound(Sotto);
-		NewState (ob,&s_giftchase1);
-		ob->speed *= 3;			// go faster when chasing player
-		break;
-
-	case fatobj:
-		SD_PlaySound(Sfett);
-		NewState (ob,&s_fatchase1);
-		ob->speed *= 3;			// go faster when chasing player
-		break;
-
-	case schabbobj:
-		SD_PlaySound(Sschb);
-		NewState (ob,&s_schabbchase1);
-		ob->speed *= 3;			// go faster when chasing player
-		break;
-
-	case fakeobj:
-		SD_PlaySound(Sfake);
-		NewState (ob,&s_fakechase1);
-		ob->speed *= 3;			// go faster when chasing player
-		break;
-
-	case mechahitlerobj:
-		SD_PlaySound(Shilterdeath);
-		NewState (ob,&s_mechachase1);
-		ob->speed *= 3;			// go faster when chasing player
-		break;
-
-	case realhitlerobj:
-		SD_PlaySound(Shilterdeath);
-		NewState (ob,&s_hitlerchase1);
-		ob->speed *= 5;			// go faster when chasing player
-		break;
-
-	case ghostobj:
-		NewState (ob,&s_blinkychase1);
-		ob->speed *= 2;			// go faster when chasing player
-		break;
-#else
-
-	case spectreobj:
-		SD_PlaySound(Sghost);
-		NewState (ob,&s_spectrechase1);
-		ob->speed = 800;			// go faster when chasing player
-		break;
-
-	case angelobj:
-		SD_PlaySound(Sangel);
-		NewState (ob,&s_angelchase1);
-		ob->speed = 1536;			// go faster when chasing player
-		break;
-
-	case transobj:
-		SD_PlaySound(Strans);
-		NewState (ob,&s_transchase1);
-		ob->speed = 1536;			// go faster when chasing player
-		break;
-
-	case uberobj:
-		NewState (ob,&s_uberchase1);
-		ob->speed = 3000;			// go faster when chasing player
-		break;
-
-	case willobj:
-		SD_PlaySound(Swilh);
-		NewState (ob,&s_willchase1);
-		ob->speed = 2048;			// go faster when chasing player
-		break;
-
-	case deathobj:
-		SD_PlaySound(Sknight);
-		NewState (ob,&s_deathchase1);
-		ob->speed = 2048;			// go faster when chasing player
-		break;
-
-#endif
-	}
-
-	if (ob->distance < 0)
-		ob->distance = 0;	// ignore the door opening command
-
-	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
-=
-===============
-*/
-
-int SightPlayer (objtype *ob)
-{
-	if (ob->flags & FL_ATTACKMODE)
-		Quit ("An actor in ATTACKMODE called SightPlayer!");
-
-	if (ob->temp2)
-	{
-	//
-	// count down reaction time
-	//
-		ob->temp2 -= tics;
-		if (ob->temp2 > 0)
-			return false;
-		ob->temp2 = 0;					// time to react
-	}
-	else
-	{
-		if (!areabyplayer[ob->areanumber])
-			return false;
-
-		if (ob->flags & FL_AMBUSH)
-		{
-			if (!CheckSight (ob))
-				return false;
-			ob->flags &= ~FL_AMBUSH;
-		}
-		else
-		{
-			if (!madenoise && !CheckSight (ob))
-				return false;
-		}
-
-
-		switch (ob->obclass)
-		{
-		case guardobj:
-			ob->temp2 = 1+US_RndT()/4;
-			break;
-		case officerobj:
-			ob->temp2 = 2;
-			break;
-		case mutantobj:
-			ob->temp2 = 1+US_RndT()/6;
-			break;
-		case ssobj:
-			ob->temp2 = 1+US_RndT()/6;
-			break;
-		case dogobj:
-			ob->temp2 = 1+US_RndT()/8;
-			break;
-
-		case bossobj:
-		case schabbobj:
-		case fakeobj:
-		case mechahitlerobj:
-		case realhitlerobj:
-		case gretelobj:
-		case giftobj:
-		case fatobj:
-		case spectreobj:
-		case angelobj:
-		case transobj:
-		case uberobj:
-		case willobj:
-		case deathobj:
-			ob->temp2 = 1;
-			break;
-		}
-		return false;
-	}
-
-	FirstSighting (ob);
-
-	return true;
-}
-
-
--- a/us.h
+++ b/us.h
@@ -46,7 +46,7 @@
 
 extern	int		ingame,		// Set by game code if a game is in progress
 					abortgame,	// Set if a game load failed
-					loadedgame,	// Set if the current game was loaded
+					gm.load,	// Set if the current game was loaded
 					NoWait,
 					HighScoresDirty;
 extern	char		*abortprogram;	// Set to error msg if program is dying
--- a/us1.c
+++ b/us1.c
@@ -16,20 +16,6 @@
 
 ///////////////////////////////////////////////////////////////////////////
 //
-//	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)(char far *,u16int *,u16int *),void (*print)(char far *))
-{
-	USL_MeasureString = measure;
-	USL_DrawString = print;
-}
-
-///////////////////////////////////////////////////////////////////////////
-//
 //	US_Print() - Prints a string in the current window. Newlines are
 //		supported.
 //
@@ -217,54 +203,6 @@
 
 	for (i = sy + 8;i <= sy + sh - 8;i += 8)
 		VWB_DrawTile8(sx,i,3),VWB_DrawTile8(sx + sw,i,4);
-}
-
-///////////////////////////////////////////////////////////////////////////
-//
-//	US_CenterWindow() - Generates a window of a given width & height in the
-//		middle of the screen
-//
-///////////////////////////////////////////////////////////////////////////
-void
-US_CenterWindow(u16int w,u16int h)
-{
-	US_DrawWindow(((MaxX / 8) - w) / 2,((MaxY / 8) - h) / 2,w,h);
-}
-
-///////////////////////////////////////////////////////////////////////////
-//
-//	US_SaveWindow() - Saves the current window parms into a record for
-//		later restoration
-//
-///////////////////////////////////////////////////////////////////////////
-void
-US_SaveWindow(WindowRec *win)
-{
-	win->x = WindowX;
-	win->y = WindowY;
-	win->w = WindowW;
-	win->h = WindowH;
-
-	win->px = PrintX;
-	win->py = PrintY;
-}
-
-///////////////////////////////////////////////////////////////////////////
-//
-//	US_RestoreWindow() - Sets the current window parms to those held in the
-//		record
-//
-///////////////////////////////////////////////////////////////////////////
-void
-US_RestoreWindow(WindowRec *win)
-{
-	WindowX = win->x;
-	WindowY = win->y;
-	WindowW = win->w;
-	WindowH = win->h;
-
-	PrintX = win->px;
-	PrintY = win->py;
 }
 
 //	Input routines
--- a/vh.c
+++ b/vh.c
@@ -1,3 +1,53 @@
+#define WHITE			15			// graphics mode independant colors
+#define BLACK			0
+#define FIRSTCOLOR		1
+#define SECONDCOLOR		12
+#define F_WHITE			15
+#define F_BLACK			0
+#define F_FIRSTCOLOR	1
+#define F_SECONDCOLOR	12
+
+#define MAXSHIFTS	1
+
+typedef struct
+{
+	s16int width,height;
+} pictabletype;
+
+typedef struct
+{
+	s16int height;
+	s16int location[256];
+	char width[256];
+} fontstruct;
+
+extern	pictabletype	_seg *pictable;
+extern	pictabletype	_seg *picmtable;
+extern	spritetabletype _seg *spritetable;
+
+extern	u8int	fontcolor;
+extern	s16int	fontnumber;
+extern	s16int	px,py;
+
+#define VW_SetCRTC		VL_SetCRTC
+#define VW_SetScreen	VL_SetScreen
+#define VW_Bar			VL_Bar
+#define VW_Plot			VL_Plot
+#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_DrawPic		VH_DrawPic
+#define VW_ColorBorder	VL_ColorBorder
+#define VW_WaitVBL		VL_WaitVBL
+#define VW_FadeIn()		VL_FadeIn(0,255,&gamepal,30);
+#define VW_FadeOut()	VL_FadeOut(0,255,0,0,0,30);
+#define VW_ScreenToScreen	VL_ScreenToScreen
+#define VW_SetDefaultColors	VH_SetDefaultColors
+#define EGAMAPMASK(x)	VGAMAPMASK(x)
+#define EGAWRITEMODE(x)	VGAWRITEMODE(x)
+#define LatchDrawChar(x,y,p) VL_LatchToScreen(latchpics[0]+(p)*16,2,8,x,y)
+#define LatchDrawTile(x,y,p) VL_LatchToScreen(latchpics[1]+(p)*64,4,16,x,y)
+#define NUMLATCHPICS	100
+
 #define PIXTOBLOCK		4		// 16 pixels to an update block
 
 u8int	update[UPDATEHIGH][UPDATEWIDE];
@@ -149,7 +199,7 @@
 //
 // tile 8s
 //
-	FIXME: fuck this
+	→ fuck this
 	latchpics[0] = freelatch;
 	src = (u8int _seg *)grsegs[STARTTILE8];
 	destoff = freelatch;
@@ -177,96 +227,4 @@
 	}
 
 	EGAMAPMASK(15);
-}
-
-//==========================================================================
-
-/*
-===================
-=
-= FizzleFade
-=
-= returns true if aborted
-=
-===================
-*/
-
-extern	ControlInfo	c;
-
-int FizzleFade (u16int source, u16int dest,
-	u16int width,u16int height, u16int frames, int abortable)
-{
-	s16int			pixperframe;
-	u16int	drawofs,pagedelta;
-	u8int 		mask,maskb[8] = {1,2,4,8};
-	u16int	x,y,p,frame;
-	s32int		rndval;
-
-	pagedelta = dest-source;
-	rndval = 1;
-	y = 0;
-	pixperframe = 64000/frames;
-
-	IN_StartAck ();
-
-	TimeCount=frame=0;
-	do	// while (1)
-	{
-		if (abortable && IN_CheckAck () )
-			return true;
-
-		asm	mov	es,[screenseg]
-
-		for (p=0;p<pixperframe;p++)
-		{
-			//
-			// seperate random value into x/y pair
-			//
-			asm	mov	ax,[WORD PTR rndval]
-			asm	mov	dx,[WORD PTR rndval+2]
-			asm	mov	bx,ax
-			asm	dec	bl
-			asm	mov	[BYTE PTR y],bl			// low 8 bits - 1 = y xoordinate
-			asm	mov	bx,ax
-			asm	mov	cx,dx
-			asm	mov	[BYTE PTR x],ah			// next 9 bits = x xoordinate
-			asm	mov	[BYTE PTR x+1],dl
-			//
-			// advance to next random element
-			//
-			asm	shr	dx,1
-			asm	rcr	ax,1
-			asm	jnc	noxor
-			asm	xor	dx,0x0001
-			asm	xor	ax,0x2000
-noxor:
-			asm	mov	[WORD PTR rndval],ax
-			asm	mov	[WORD PTR rndval+2],dx
-
-			if (x>width || y>height)
-				continue;
-			drawofs = source+ylookup[y] + (x>>2);
-
-			//
-			// copy one pixel
-			//
-			mask = x&3;
-			VGAREADMAP(mask);
-			mask = maskb[mask];
-			VGAMAPMASK(mask);
-
-			asm	mov	di,[drawofs]
-			asm	mov	al,[es:di]
-			asm add	di,[pagedelta]
-			asm	mov	[es:di],al
-
-			if (rndval == 1)		// entire sequence has been completed
-				return false;
-		}
-		frame++;
-		while (TimeCount<frame)		// don't go too fast
-		;
-	} while (1);
-
-
 }
--- a/vh.h
+++ /dev/null
@@ -1,100 +1,0 @@
-// ID_VH.H
-
-
-#define WHITE			15			// graphics mode independant colors
-#define BLACK			0
-#define FIRSTCOLOR		1
-#define SECONDCOLOR		12
-#define F_WHITE			15
-#define F_BLACK			0
-#define F_FIRSTCOLOR	1
-#define F_SECONDCOLOR	12
-
-//===========================================================================
-
-#define MAXSHIFTS	1
-
-typedef struct
-{
-	s16int width,height;
-} pictabletype;
-
-typedef struct
-{
-	s16int height;
-	s16int location[256];
-	char width[256];
-} fontstruct;
-
-
-//===========================================================================
-
-
-extern	pictabletype	_seg *pictable;
-extern	pictabletype	_seg *picmtable;
-extern	spritetabletype _seg *spritetable;
-
-extern	u8int	fontcolor;
-extern	s16int	fontnumber;
-extern	s16int	px,py;
-
-//
-// Double buffer management routines
-//
-
-void VW_InitDoubleBuffer (void);
-s16int	 VW_MarkUpdateBlock (s16int x1, s16int y1, s16int x2, s16int y2);
-void VW_UpdateScreen (void);
-
-//
-// mode independant routines
-// coordinates in pixels, rounded to best screen res
-// regions marked in double buffer
-//
-
-void VWB_DrawTile8 (s16int x, s16int y, s16int tile);
-void VWB_DrawPic (s16int x, s16int y, s16int chunknum);
-void VWB_Bar (s16int x, s16int y, s16int width, s16int height, s16int color);
-void VWB_DrawPropString	 (char far *string);
-void VWB_Plot (s16int x, s16int y, s16int color);
-void VWB_Hlin (s16int x1, s16int x2, s16int y, s16int color);
-void VWB_Vlin (s16int y1, s16int y2, s16int x, s16int color);
-
-
-//
-// wolfenstein EGA compatability stuff
-//
-extern u8int far gamepal;
-
-void VH_SetDefaultColors (void);
-
-#define VW_SetCRTC		VL_SetCRTC
-#define VW_SetScreen	VL_SetScreen
-#define VW_Bar			VL_Bar
-#define VW_Plot			VL_Plot
-#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_DrawPic		VH_DrawPic
-#define VW_ColorBorder	VL_ColorBorder
-#define VW_WaitVBL		VL_WaitVBL
-#define VW_FadeIn()		VL_FadeIn(0,255,&gamepal,30);
-#define VW_FadeOut()	VL_FadeOut(0,255,0,0,0,30);
-#define VW_ScreenToScreen	VL_ScreenToScreen
-#define VW_SetDefaultColors	VH_SetDefaultColors
-void	VW_MeasurePropString (char far *string, u16int *width, u16int *height);
-#define EGAMAPMASK(x)	VGAMAPMASK(x)
-#define EGAWRITEMODE(x)	VGAWRITEMODE(x)
-
-#define LatchDrawChar(x,y,p) VL_LatchToScreen(latchpics[0]+(p)*16,2,8,x,y)
-#define LatchDrawTile(x,y,p) VL_LatchToScreen(latchpics[1]+(p)*64,4,16,x,y)
-
-void LatchDrawPic (u16int x, u16int y, u16int picnum);
-void 	LoadLatchMem (void);
-int 	FizzleFade (u16int source, u16int dest,
-	u16int width,u16int height, u16int frames,int abortable);
-
-
-#define NUMLATCHPICS	100
-extern	u16int	latchpics[NUMLATCHPICS];
-extern	u16int freelatch;
-
--- a/vl.c
+++ b/vl.c
@@ -1,72 +1,112 @@
 u16int	bufferofs;
 u16int	displayofs,pelpan;
 
-u16int	screenseg=SCREENSEG;		// set to 0xa000 for asm convenience
+#define SC_INDEX			0x3C4
+#define SC_RESET			0
+#define SC_CLOCK			1
+#define SC_MAPMASK			2
+#define SC_CHARMAP			3
+#define SC_MEMMODE			4
 
-u16int	linewidth;
-u16int	ylookup[MAXSCANLINES];
+#define CRTC_INDEX			0x3D4
+#define CRTC_H_TOTAL		0
+#define CRTC_H_DISPEND		1
+#define CRTC_H_BLANK		2
+#define CRTC_H_ENDBLANK		3
+#define CRTC_H_RETRACE		4
+#define CRTC_H_ENDRETRACE 	5
+#define CRTC_V_TOTAL		6
+#define CRTC_OVERFLOW		7
+#define CRTC_ROWSCAN		8
+#define CRTC_MAXSCANLINE 	9
+#define CRTC_CURSORSTART 	10
+#define CRTC_CURSOREND		11
+#define CRTC_STARTHIGH		12
+#define CRTC_STARTLOW		13
+#define CRTC_CURSORHIGH		14
+#define CRTC_CURSORLOW		15
+#define CRTC_V_RETRACE		16
+#define CRTC_V_ENDRETRACE 	17
+#define CRTC_V_DISPEND		18
+#define CRTC_OFFSET			19
+#define CRTC_UNDERLINE		20
+#define CRTC_V_BLANK		21
+#define CRTC_V_ENDBLANK		22
+#define CRTC_MODE			23
+#define CRTC_LINECOMPARE 	24
 
-int		screenfaded;
-u16int	bordercolor;
 
-int		fastpalette;				// if true, use outsb to set
+#define GC_INDEX			0x3CE
+#define GC_SETRESET			0
+#define GC_ENABLESETRESET 	1
+#define GC_COLORCOMPARE		2
+#define GC_DATAROTATE		3
+#define GC_READMAP			4
+#define GC_MODE				5
+#define GC_MISCELLANEOUS 	6
+#define GC_COLORDONTCARE 	7
+#define GC_BITMASK			8
 
-//===========================================================================
+#define ATR_INDEX			0x3c0
+#define ATR_MODE			16
+#define ATR_OVERSCAN		17
+#define ATR_COLORPLANEENABLE 18
+#define ATR_PELPAN			19
+#define ATR_COLORSELECT		20
 
-// asm
-void VL_SetCRTC (s16int crtc);
+#define	STATUS_REGISTER_1    0x3da
 
+#define PEL_WRITE_ADR		0x3c8
+#define PEL_READ_ADR		0x3c7
+#define PEL_DATA			0x3c9
 
-/*
-=============================================================================
+#define SCREENSEG		0xa000
 
-						PALETTE OPS
+#define SCREENWIDTH		80			// default screen width in bytes
+#define MAXSCANLINES	200			// size of ylookup table
 
-		To avoid snow, do a WaitVBL BEFORE calling these
+#define TILEWIDTH		4
 
-=============================================================================
-*/
+extern	u16int	bufferofs;			// all drawing is reletive to this
+extern	u16int	displayofs,pelpan;	// last setscreen coordinates
 
-/*
-==================
-=
-= VL_ColorBorder
-=
-==================
-*/
+extern	u16int	screenseg;			// set to 0xa000 for asm convenience
 
-void VL_ColorBorder (s16int color)
-{
-	_AH=0x10;
-	_AL=1;
-	_BH=color;
-	geninterrupt (0x10);
-	bordercolor = color;
-}
+extern	u16int	linewidth;
+extern	u16int	ylookup[MAXSCANLINES];
 
+extern	int		screenfaded;
+extern	u16int	bordercolor;
 
+#define VGAWRITEMODE(x) asm{\
+cli;\
+mov dx,GC_INDEX;\
+mov al,GC_MODE;\
+out dx,al;\
+inc dx;\
+in al,dx;\
+and al,252;\
+or al,x;\
+out dx,al;\
+sti;}
 
-/*
-=============================================================================
+#define VGAMAPMASK(x) asm{cli;mov dx,SC_INDEX;mov al,SC_MAPMASK;mov ah,x;out dx,ax;sti;}
+#define VGAREADMAP(x) asm{cli;mov dx,GC_INDEX;mov al,GC_READMAP;mov ah,x;out dx,ax;sti;}
 
-							PIXEL OPS
+u16int	screenseg=SCREENSEG;		// set to 0xa000 for asm convenience
 
-=============================================================================
-*/
+u16int	linewidth;
+u16int	ylookup[MAXSCANLINES];
 
+int		screenfaded;
+u16int	bordercolor;
+
+int		fastpalette;				// if true, use outsb to set
+
 u8int	pixmasks[4] = {1,2,4,8};
 u8int	leftmasks[4] = {15,14,12,8};
 u8int	rightmasks[4] = {1,3,7,15};
 
-
-/*
-=================
-=
-= VL_Plot
-=
-=================
-*/
-
 void VL_Plot (s16int x, s16int y, s16int color)
 {
 	u8int mask;
@@ -77,15 +117,6 @@
 	VGAMAPMASK(15);
 }
 
-
-/*
-=================
-=
-= VL_Vlin
-=
-=================
-*/
-
 void VL_Vlin (s16int x, s16int y, s16int height, s16int color)
 {
 	u8int	far *dest,mask;
@@ -104,22 +135,6 @@
 	VGAMAPMASK(15);
 }
 
-/*
-============================================================================
-
-							MEMORY OPS
-
-============================================================================
-*/
-
-/*
-=================
-=
-= VL_MemToLatch
-=
-=================
-*/
-
 void VL_MemToLatch (u8int far *source, s16int width, s16int height, u16int dest)
 {
 	u16int	count;
@@ -145,20 +160,6 @@
 	}
 }
 
-
-//===========================================================================
-
-
-/*
-=================
-=
-= VL_MemToScreen
-=
-= Draws a block of data to the screen.
-=
-=================
-*/
-
 void VL_MemToScreen (u8int far *source, s16int width, s16int height, s16int x, s16int y)
 {
 	u8int    far *screen,far *dest,mask;
@@ -181,19 +182,6 @@
 	}
 }
 
-//==========================================================================
-
-
-/*
-=================
-=
-= VL_MaskedToScreen
-=
-= Masks a block of main memory to the screen.
-=
-=================
-*/
-
 void VL_MaskedToScreen (u8int far *source, s16int width, s16int height, s16int x, s16int y)
 {
 	u8int    far *screen,far *dest,mask;
@@ -218,16 +206,6 @@
 			_fmemcpy (screen,source,width);
 	}
 }
-
-//==========================================================================
-
-/*
-=================
-=
-= VL_LatchToScreen
-=
-=================
-*/
 
 void VL_LatchToScreen (u16int source, s16int width, s16int height, s16int x, s16int y)
 {
--- a/vl.h
+++ /dev/null
@@ -1,134 +1,0 @@
-#define SC_INDEX			0x3C4
-#define SC_RESET			0
-#define SC_CLOCK			1
-#define SC_MAPMASK			2
-#define SC_CHARMAP			3
-#define SC_MEMMODE			4
-
-#define CRTC_INDEX			0x3D4
-#define CRTC_H_TOTAL		0
-#define CRTC_H_DISPEND		1
-#define CRTC_H_BLANK		2
-#define CRTC_H_ENDBLANK		3
-#define CRTC_H_RETRACE		4
-#define CRTC_H_ENDRETRACE 	5
-#define CRTC_V_TOTAL		6
-#define CRTC_OVERFLOW		7
-#define CRTC_ROWSCAN		8
-#define CRTC_MAXSCANLINE 	9
-#define CRTC_CURSORSTART 	10
-#define CRTC_CURSOREND		11
-#define CRTC_STARTHIGH		12
-#define CRTC_STARTLOW		13
-#define CRTC_CURSORHIGH		14
-#define CRTC_CURSORLOW		15
-#define CRTC_V_RETRACE		16
-#define CRTC_V_ENDRETRACE 	17
-#define CRTC_V_DISPEND		18
-#define CRTC_OFFSET			19
-#define CRTC_UNDERLINE		20
-#define CRTC_V_BLANK		21
-#define CRTC_V_ENDBLANK		22
-#define CRTC_MODE			23
-#define CRTC_LINECOMPARE 	24
-
-
-#define GC_INDEX			0x3CE
-#define GC_SETRESET			0
-#define GC_ENABLESETRESET 	1
-#define GC_COLORCOMPARE		2
-#define GC_DATAROTATE		3
-#define GC_READMAP			4
-#define GC_MODE				5
-#define GC_MISCELLANEOUS 	6
-#define GC_COLORDONTCARE 	7
-#define GC_BITMASK			8
-
-#define ATR_INDEX			0x3c0
-#define ATR_MODE			16
-#define ATR_OVERSCAN		17
-#define ATR_COLORPLANEENABLE 18
-#define ATR_PELPAN			19
-#define ATR_COLORSELECT		20
-
-#define	STATUS_REGISTER_1    0x3da
-
-#define PEL_WRITE_ADR		0x3c8
-#define PEL_READ_ADR		0x3c7
-#define PEL_DATA			0x3c9
-
-
-//===========================================================================
-
-#define SCREENSEG		0xa000
-
-#define SCREENWIDTH		80			// default screen width in bytes
-#define MAXSCANLINES	200			// size of ylookup table
-
-#define TILEWIDTH		4
-
-//===========================================================================
-
-extern	u16int	bufferofs;			// all drawing is reletive to this
-extern	u16int	displayofs,pelpan;	// last setscreen coordinates
-
-extern	u16int	screenseg;			// set to 0xa000 for asm convenience
-
-extern	u16int	linewidth;
-extern	u16int	ylookup[MAXSCANLINES];
-
-extern	int		screenfaded;
-extern	u16int	bordercolor;
-
-//===========================================================================
-
-//
-// VGA hardware routines
-//
-
-#define VGAWRITEMODE(x) asm{\
-cli;\
-mov dx,GC_INDEX;\
-mov al,GC_MODE;\
-out dx,al;\
-inc dx;\
-in al,dx;\
-and al,252;\
-or al,x;\
-out dx,al;\
-sti;}
-
-#define VGAMAPMASK(x) asm{cli;mov dx,SC_INDEX;mov al,SC_MAPMASK;mov ah,x;out dx,ax;sti;}
-#define VGAREADMAP(x) asm{cli;mov dx,GC_INDEX;mov al,GC_READMAP;mov ah,x;out dx,ax;sti;}
-
-void VL_SetVGAPlane (void);
-
-void VL_WaitVBL (s16int vbls);
-void VL_CrtcStart (s16int crtc);
-
-void VL_FillPalette (s16int red, s16int green, s16int blue);
-void VL_SetColor	(s16int color, s16int red, s16int green, s16int blue);
-void VL_GetColor	(s16int color, s16int *red, s16int *green, s16int *blue);
-void VL_FadeOut (s16int start, s16int end, s16int red, s16int green, s16int blue, s16int steps);
-void VL_FadeIn (s16int start, s16int end, u8int far *palette, s16int steps);
-void VL_ColorBorder (s16int color);
-
-void VL_Plot (s16int x, s16int y, s16int color);
-void VL_Hlin (u16int x, u16int y, u16int width, u16int color);
-void VL_Vlin (s16int x, s16int y, s16int height, s16int color);
-void VL_Bar (s16int x, s16int y, s16int width, s16int height, s16int color);
-
-void VL_DrawPicBare (s16int x, s16int y, u8int far *pic, s16int width, s16int height);
-void VL_MemToLatch (u8int far *source, s16int width, s16int height, u16int dest);
-void VL_ScreenToScreen (u16int source, u16int dest,s16int width, s16int height);
-void VL_MemToScreen (u8int far *source, s16int width, s16int height, s16int x, s16int y);
-void VL_MaskedToScreen (u8int far *source, s16int width, s16int height, s16int x, s16int y);
-
-void VL_DrawTile8String (char *str, char far *tile8ptr, s16int printx, s16int printy);
-void VL_DrawLatch8String (char *str, u16int tile8ptr, s16int printx, s16int printy);
-void VL_SizeTile8String (char *str, s16int *width, s16int *height);
-void VL_DrawPropString (char *str, u16int tile8ptr, s16int printx, s16int printy);
-void VL_SizePropString (char *str, s16int *width, s16int *height, char far *font);
-
-void VL_TestPaletteSet (void);
-
--- a/wl3d.c
+++ b/wl3d.c
@@ -11,9 +11,14 @@
 char *ext = "wl6";
 int ver;
 int grabon;
-int cson, kbon, mson;
+int kbon, mson;
+int kb, mΔx, mΔy, mΔb;
+int demexit;
 void (*step)(void);
-Channel *csc, *kbc, *msc;
+int Δtc;
+int nosleep;
+Channel *csc;
+QLock inlck;
 
 enum{
 	Te9 = 1000000000,
@@ -24,6 +29,7 @@
 static Rectangle fbr, grabr;
 static Image *fb;
 static Channel *reszc;
+static int cson;
 
 static void
 mproc(void *)
@@ -31,7 +37,6 @@
 	int n, fd, nerr;
 	char buf[1+5*12], *px, *py, *pb;
 	Point o, p;
-	Mouse m;
 
 	fd = open("/dev/mouse", ORDWR);
 	if(fd < 0)
@@ -59,10 +64,11 @@
 				break;
 			p.x = strtol(px, nil, 10);
 			p.y = strtol(py, nil, 10);
-			m.xy.x = p.x - o.x;
-			m.xy.y = o.y - p.y;
-			m.buttons = *pb;
-			nbsend(msc, &m);
+			qlock(&inlck);
+			mΔx += p.x - o.x;
+			mΔy += o.y - p.y;
+			mΔb = *pb;
+			qunlock(&inlck);
 			if(!ptinrect(p, grabr)){
 				fprint(fd, "m%d %d", p0.x, p0.y);
 				p = p0;
@@ -98,7 +104,7 @@
 		c = *buf;
 		if(c == 'c' && cson){
 			chartorune(&r, buf+1);
-			send(csc, &r);
+			nbsend(csc, &r);
 		}
 		if(c != 'k' || c != 'K' || !kbon)
 			continue;
@@ -108,11 +114,13 @@
 			s += chartorune(&r, s);
 			for(a=keys; a<keys+Ke; a++)
 				if(r == *a){
-					k |= 1<<a-keys;
+					k |= 1 << a - keys;
 					break;
 				}
 		}
-		send(kbc, &k);
+		qlock(&inlck);
+		kb = k;
+		qunlock(&inlck);
 	}
 }
 
@@ -156,7 +164,7 @@
 static void
 usage(void)
 {
-	fprint(2, "usage: %s [-23dos] [-m dir] [-w map] [-x difficulty]\n", argv0);
+	fprint(2, "usage: %s [-23dopqs] [-f demo] [-m dir] [-w map] [-x difficulty]\n", argv0);
 	threadexits("usage");
 }
 
@@ -204,9 +212,9 @@
 void
 toss(void)
 {
+	cson = 0;
 	while(nbrecv(csc, nil) != 0);
-	while(nbrecv(msc, nil) != 0);
-	while(nbrecv(kbc, nil) != 0);
+	cson++;
 }
 
 void
@@ -234,16 +242,22 @@
 void
 threadmain(int argc, char **argv)
 {
+	int tc;
 	vlong t0, t, dt;
-	char *datdir = "/sys/games/lib/wl3d/";
+	char *datdir, *df;
 
+	datdir = "/sys/games/lib/wl3d/";
+	df = nil;
 	step = mstep;
 	ARGBEGIN{
 	case '2': ext = "sd2"; ver = SOD; break;
 	case '3': ext = "sd3"; ver = SOD; break;
 	case 'd': ext = "wl1"; ver = WL1; break;
+	case 'f': df = EARGF(usage()); break;
 	case 'm': datdir = EARGF(usage()); break;
 	case 'o': ext = "sdm"; ver = SDM; break;
+	case 'p': nosleep++; break;
+	case 'q': demexit++; break;
 	case 's': ext = "sod"; ver = SOD; break;
 	case 'w': /* TODO: warp to ep, level */ break;
 	case 'x': /* TODO: set difficulty for warp */ break;
@@ -257,17 +271,17 @@
 	resetfb();
 	dat(datdir);
 	initsnd();
-	kbc = chancreate(sizeof(int), 20);
 	csc = chancreate(sizeof(Rune), 20);
 	reszc = chancreate(sizeof(int), 2);
-	msc = chancreate(sizeof(Mouse), 0);
-	if(kbc == nil || csc == nil | reszc == nil || msc == nil)
+	if(csc == nil | reszc == nil)
 		sysfatal("chancreate: %r");
 	if(proccreate(kproc, nil, 8192) < 0 || proccreate(mproc, nil, 8192) < 0)
 		sysfatal("proccreate: %r");
 
-	init();
+	init(df);
+	cson++;
 	t0 = nsec();
+	Δtc = 1;
 	for(;;){
 		if(nbrecv(reszc, nil) != 0){
 			if(getwindow(display, Refnone) < 0)
@@ -276,8 +290,18 @@
 		}
 		step();
 		sndstep();
-		t0 += Td;
 		t = nsec();
+		tc = (t - t0) / Td;
+		if(tc <= 0)
+			tc = 1;
+		else if(tc > 10)
+			tc = 10;
+		Δtc = (gm.demo || gm.record) && !gm.fizz ? 4 : tc;
+		t0 += tc * Td;
+		if(nosleep)
+			continue;
+		if(onestep)
+			t0 += Td;
 		dt = (t0 - t) / Te6;
 		if(dt > 0)
 			sleep(dt);