shithub: hexen

Download patch

ref: 0de63fa5e707d4811a67e3f3e81cd7e9349581f2
author: Jacob Moody <moody@posixcafe.org>
date: Sat Jan 21 20:12:46 EST 2023

initial commit

--- /dev/null
+++ b/a_action.c
@@ -1,0 +1,1321 @@
+
+//**************************************************************************
+//**
+//** a_action.c : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 584 $
+//** $Date: 2012-02-17 12:01:51 +0200 (Fri, 17 Feb 2012) $
+//**
+//**************************************************************************
+
+// HEADER FILES ------------------------------------------------------------
+
+#include "h2stdinc.h"
+#include "h2def.h"
+#include "p_local.h"
+#include "soundst.h"
+
+// MACROS ------------------------------------------------------------------
+
+// TYPES -------------------------------------------------------------------
+
+// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
+
+// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
+
+// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
+
+// EXTERNAL DATA DECLARATIONS ----------------------------------------------
+
+extern fixed_t FloatBobOffsets[64];
+
+// PUBLIC DATA DEFINITIONS -------------------------------------------------
+
+// PRIVATE DATA DEFINITIONS ------------------------------------------------
+
+static int orbitTableX[256] =
+{
+	983025, 982725, 981825, 980340, 978255, 975600, 972330, 968490,
+	964065, 959070, 953475, 947325, 940590, 933300, 925440, 917025,
+	908055, 898545, 888495, 877905, 866775, 855135, 842985, 830310,
+	817155, 803490, 789360, 774735, 759660, 744120, 728130, 711690,
+	694845, 677565, 659880, 641805, 623340, 604500, 585285, 565725,
+	545820, 525600, 505050, 484200, 463065, 441645, 419955, 398010,
+	375840, 353430, 330810, 307995, 285000, 261825, 238485, 215010,
+	191400, 167685, 143865, 119955, 95970, 71940, 47850, 23745,
+	-375, -24495, -48600, -72690, -96720, -120705, -144600, -168420,
+	-192150, -215745, -239220, -262545, -285720, -308715, -331530, -354135,
+	-376530, -398700, -420630, -442320, -463725, -484860, -505695, -526230,
+	-546450, -566340, -585885, -605085, -623925, -642375, -660435, -678105,
+	-695370, -712215, -728625, -744600, -760125, -775200, -789795, -803925,
+	-817575, -830715, -843375, -855510, -867135, -878235, -888810, -898845,
+	-908340, -917295, -925695, -933540, -940815, -947520, -953670, -959235,
+	-964215, -968625, -972450, -975690, -978330, -980400, -981870, -982740,
+	-983025, -982725, -981825, -980340, -978255, -975600, -972330, -968490,
+	-964065, -959070, -953475, -947325, -940590, -933300, -925440, -917025,
+	-908055, -898545, -888495, -877905, -866775, -855135, -842985, -830310,
+	-817155, -803490, -789360, -774735, -759660, -744120, -728130, -711690,
+	-694845, -677565, -659880, -641805, -623340, -604485, -585285, -565725,
+	-545820, -525600, -505050, -484200, -463065, -441645, -419955, -398010,
+	-375840, -353430, -330810, -307995, -285000, -261825, -238485, -215010,
+	-191400, -167685, -143865, -119955, -95970, -71940, -47850, -23745,
+	375, 24495, 48600, 72690, 96720, 120705, 144600, 168420,
+	192150, 215745, 239220, 262545, 285720, 308715, 331530, 354135,
+	376530, 398700, 420630, 442320, 463725, 484860, 505695, 526230,
+	546450, 566340, 585885, 605085, 623925, 642375, 660435, 678105,
+	695370, 712215, 728625, 744600, 760125, 775200, 789795, 803925,
+	817575, 830715, 843375, 855510, 867135, 878235, 888810, 898845,
+	908340, 917295, 925695, 933540, 940815, 947520, 953670, 959235,
+	964215, 968625, 972450, 975690, 978330, 980400, 981870, 982740
+};
+
+static int orbitTableY[256] =
+{
+	375, 24495, 48600, 72690, 96720, 120705, 144600, 168420,
+	192150, 215745, 239220, 262545, 285720, 308715, 331530, 354135,
+	376530, 398700, 420630, 442320, 463725, 484860, 505695, 526230,
+	546450, 566340, 585885, 605085, 623925, 642375, 660435, 678105,
+	695370, 712215, 728625, 744600, 760125, 775200, 789795, 803925,
+	817575, 830715, 843375, 855510, 867135, 878235, 888810, 898845,
+	908340, 917295, 925695, 933540, 940815, 947520, 953670, 959235,
+	964215, 968625, 972450, 975690, 978330, 980400, 981870, 982740,
+	983025, 982725, 981825, 980340, 978255, 975600, 972330, 968490,
+	964065, 959070, 953475, 947325, 940590, 933300, 925440, 917025,
+	908055, 898545, 888495, 877905, 866775, 855135, 842985, 830310,
+	817155, 803490, 789360, 774735, 759660, 744120, 728130, 711690,
+	694845, 677565, 659880, 641805, 623340, 604500, 585285, 565725,
+	545820, 525600, 505050, 484200, 463065, 441645, 419955, 398010,
+	375840, 353430, 330810, 307995, 285000, 261825, 238485, 215010,
+	191400, 167685, 143865, 119955, 95970, 71940, 47850, 23745,
+	-375, -24495, -48600, -72690, -96720, -120705, -144600, -168420,
+	-192150, -215745, -239220, -262545, -285720, -308715, -331530, -354135,
+	-376530, -398700, -420630, -442320, -463725, -484860, -505695, -526230,
+	-546450, -566340, -585885, -605085, -623925, -642375, -660435, -678105,
+	-695370, -712215, -728625, -744600, -760125, -775200, -789795, -803925,
+	-817575, -830715, -843375, -855510, -867135, -878235, -888810, -898845,
+	-908340, -917295, -925695, -933540, -940815, -947520, -953670, -959235,
+	-964215, -968625, -972450, -975690, -978330, -980400, -981870, -982740,
+	-983025, -982725, -981825, -980340, -978255, -975600, -972330, -968490,
+	-964065, -959070, -953475, -947325, -940590, -933300, -925440, -917025,
+	-908055, -898545, -888495, -877905, -866775, -855135, -842985, -830310,
+	-817155, -803490, -789360, -774735, -759660, -744120, -728130, -711690,
+	-694845, -677565, -659880, -641805, -623340, -604485, -585285, -565725,
+	-545820, -525600, -505050, -484200, -463065, -441645, -419955, -398010,
+	-375840, -353430, -330810, -307995, -285000, -261825, -238485, -215010,
+	-191400, -167685, -143865, -119955, -95970, -71940, -47850, -23745
+};
+
+// CODE --------------------------------------------------------------------
+
+//--------------------------------------------------------------------------
+//
+// Environmental Action routines
+//
+//--------------------------------------------------------------------------
+
+//==========================================================================
+//
+// A_DripBlood
+//
+//==========================================================================
+
+/*
+void A_DripBlood(mobj_t *actor)
+{
+	mobj_t *mo;
+
+	mo = P_SpawnMobj(actor->x+((P_Random()-P_Random())<<11),
+		actor->y+((P_Random()-P_Random())<<11), actor->z, MT_BLOOD);
+	mo->momx = (P_Random()-P_Random())<<10;
+	mo->momy = (P_Random()-P_Random())<<10;
+	mo->flags2 |= MF2_LOGRAV;
+}
+*/
+
+//============================================================================
+//
+// A_PotteryExplode
+//
+//============================================================================
+
+void A_PotteryExplode(mobj_t *actor)
+{
+	mobj_t *mo = NULL;
+	int i;
+
+	for (i = (P_Random()&3)+3; i; i--)
+	{
+		mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_POTTERYBIT1);
+		P_SetMobjState(mo, mo->info->spawnstate + (P_Random() % 5));
+		if (mo)
+		{
+			mo->momz = ((P_Random()&7)+5)*(3*FRACUNIT/4);
+			mo->momx = (P_Random()-P_Random())<<(FRACBITS-6);
+			mo->momy = (P_Random()-P_Random())<<(FRACBITS-6);
+		}
+	}
+	S_StartSound(mo, SFX_POTTERY_EXPLODE);
+	if (actor->args[0])
+	{ // Spawn an item
+		if (!nomonsters ||
+		    !(mobjinfo[TranslateThingType[actor->args[0]]].flags & MF_COUNTKILL))
+		{ // Only spawn monsters if not -nomonsters
+			P_SpawnMobj(actor->x, actor->y, actor->z,
+				    TranslateThingType[actor->args[0]]);
+		}
+	}
+	P_RemoveMobj(actor);
+}
+
+//============================================================================
+//
+// A_PotteryChooseBit
+//
+//============================================================================
+
+void A_PotteryChooseBit(mobj_t *actor)
+{
+	P_SetMobjState(actor, actor->info->deathstate + (P_Random()%5) + 1);
+	actor->tics = 256 + (P_Random()<<1);
+}
+
+//============================================================================
+//
+// A_PotteryCheck
+//
+//============================================================================
+
+void A_PotteryCheck(mobj_t *actor)
+{
+	int i;
+	mobj_t *pmo;
+
+	if (!netgame)
+	{
+		pmo = players[consoleplayer].mo;
+		if (P_CheckSight(actor, pmo) &&
+		    abs(R_PointToAngle2(pmo->x, pmo->y, actor->x, actor->y)-pmo->angle) <= ANGLE_45)
+		{ // Previous state (pottery bit waiting state)
+			P_SetMobjState(actor, actor->state-&states[0]-1);
+		}
+		else
+		{
+			return;
+		}
+	}
+	else
+	{
+		for (i = 0; i < MAXPLAYERS; i++)
+		{
+			if (!playeringame[i])
+			{
+				continue;
+			}
+			pmo = players[i].mo;
+			if (P_CheckSight(actor, pmo) &&
+			    abs(R_PointToAngle2(pmo->x, pmo->y, actor->x, actor->y)-pmo->angle) <= ANGLE_45)
+			{ // Previous state (pottery bit waiting state)
+				P_SetMobjState(actor, actor->state-&states[0]-1);
+				return;
+			}
+		}
+	}
+}
+
+//============================================================================
+//
+// A_CorpseBloodDrip
+//
+//============================================================================
+
+void A_CorpseBloodDrip(mobj_t *actor)
+{
+	if (P_Random() > 128)
+	{
+		return;
+	}
+	P_SpawnMobj(actor->x, actor->y, actor->z+actor->height/2, MT_CORPSEBLOODDRIP);
+}
+
+//============================================================================
+//
+// A_CorpseExplode
+//
+//============================================================================
+
+void A_CorpseExplode(mobj_t *actor)
+{
+	mobj_t *mo;
+	int i;
+
+	for (i = (P_Random()&3)+3; i; i--)
+	{
+		mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_CORPSEBIT);
+		P_SetMobjState(mo, mo->info->spawnstate + (P_Random()%3));
+		if (mo)
+		{
+			mo->momz = ((P_Random()&7)+5)*(3*FRACUNIT/4);
+			mo->momx = (P_Random()-P_Random())<<(FRACBITS-6);
+			mo->momy = (P_Random()-P_Random())<<(FRACBITS-6);
+		}
+	}
+	// Spawn a skull
+	mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_CORPSEBIT);
+	P_SetMobjState(mo, S_CORPSEBIT_4);
+	if (mo)
+	{
+		mo->momz = ((P_Random()&7) + 5) * (3*FRACUNIT/4);
+		mo->momx = (P_Random()-P_Random())<<(FRACBITS-6);
+		mo->momy = (P_Random()-P_Random())<<(FRACBITS-6);
+		S_StartSound(mo, SFX_FIRED_DEATH);
+	}
+	P_RemoveMobj(actor);
+}
+
+//============================================================================
+//
+// A_LeafSpawn
+//
+//============================================================================
+
+void A_LeafSpawn(mobj_t *actor)
+{
+	mobj_t *mo;
+	int i;
+
+	for (i = (P_Random()&3)+1; i; i--)
+	{
+		mo = P_SpawnMobj(actor->x + ((P_Random()-P_Random())<<14),
+				 actor->y + ((P_Random()-P_Random())<<14),
+				 actor->z + (P_Random()<<14),
+				 MT_LEAF1 + (P_Random()&1));
+		if (mo)
+		{
+			P_ThrustMobj(mo, actor->angle, (P_Random()<<9)+3*FRACUNIT);
+			mo->target = actor;
+			mo->special1 = 0;
+		}
+	}
+}
+
+//============================================================================
+//
+// A_LeafThrust
+//
+//============================================================================
+
+void A_LeafThrust(mobj_t *actor)
+{
+	if (P_Random() > 96)
+	{
+		return;
+	}
+	actor->momz += (P_Random()<<9)+FRACUNIT;
+}
+
+//============================================================================
+//
+// A_LeafCheck
+//
+//============================================================================
+
+void A_LeafCheck(mobj_t *actor)
+{
+	actor->special1++;
+	if (actor->special1 >= 20)
+	{
+		P_SetMobjState(actor, S_NULL);
+		return;
+	}
+	if (P_Random() > 64)
+	{
+		if (!actor->momx && !actor->momy)
+		{
+			P_ThrustMobj(actor, actor->target->angle,
+				(P_Random()<<9)+FRACUNIT);
+		}
+		return;
+	}
+	P_SetMobjState(actor, S_LEAF1_8);
+	actor->momz = (P_Random()<<9)+FRACUNIT;
+	P_ThrustMobj(actor, actor->target->angle, (P_Random()<<9)+2*FRACUNIT);
+	actor->flags |= MF_MISSILE;
+}
+
+/*
+#define ORBIT_RADIUS	(15*FRACUNIT)
+void GenerateOrbitTable(void)
+{
+	int angle;
+
+	for (angle = 0; angle < 256; angle++)
+	{
+		orbitTableX[angle] = FixedMul(ORBIT_RADIUS, finecosine[angle<<5]);
+		orbitTableY[angle] = FixedMul(ORBIT_RADIUS, finesine[angle<<5]);
+	}
+
+	printf("int orbitTableX[256]=\n{\n");
+	for (angle = 0; angle < 256; angle += 8)
+	{
+		printf("%d, %d, %d, %d, %d, %d, %d, %d,\n",
+			orbitTableX[angle],
+			orbitTableX[angle+1],
+			orbitTableX[angle+2],
+			orbitTableX[angle+3],
+			orbitTableX[angle+4],
+			orbitTableX[angle+5],
+			orbitTableX[angle+6],
+			orbitTableX[angle+7]);
+	}
+	printf("};\n\n");
+
+	printf("int orbitTableY[256]=\n{\n");
+	for (angle = 0; angle < 256; angle += 8)
+	{
+		printf("%d, %d, %d, %d, %d, %d, %d, %d,\n",
+			orbitTableY[angle],
+			orbitTableY[angle+1],
+			orbitTableY[angle+2],
+			orbitTableY[angle+3],
+			orbitTableY[angle+4],
+			orbitTableY[angle+5],
+			orbitTableY[angle+6],
+			orbitTableY[angle+7]);
+	}
+	printf("};\n");
+}
+*/
+
+// New bridge stuff
+//	Parent
+//		special1	true == removing from world
+//
+//	Child
+//		target		pointer to center mobj
+//		args[0]		angle of ball
+
+void A_BridgeOrbit(mobj_t *actor)
+{
+	if (actor->target->special1)
+	{
+		P_SetMobjState(actor, S_NULL);
+	}
+	actor->args[0] += 3;
+	actor->x = actor->target->x + orbitTableX[actor->args[0]];
+	actor->y = actor->target->y + orbitTableY[actor->args[0]];
+	actor->z = actor->target->z;
+}
+
+
+void A_BridgeInit(mobj_t *actor)
+{
+	byte startangle;
+	mobj_t *ball1, *ball2, *ball3;
+	fixed_t cx,cy,cz;
+
+//	GenerateOrbitTable();
+
+	cx = actor->x;
+	cy = actor->y;
+	cz = actor->z;
+	startangle = P_Random();
+	actor->special1 = 0;
+
+	// Spawn triad into world
+	ball1 = P_SpawnMobj(cx, cy, cz, MT_BRIDGEBALL);
+	ball1->args[0] = startangle;
+	ball1->target = actor;
+
+	ball2 = P_SpawnMobj(cx, cy, cz, MT_BRIDGEBALL);
+	ball2->args[0] = (startangle + 85) & 255;
+	ball2->target = actor;
+
+	ball3 = P_SpawnMobj(cx, cy, cz, MT_BRIDGEBALL);
+	ball3->args[0] = (startangle + 170) & 255;
+	ball3->target = actor;
+
+	A_BridgeOrbit(ball1);
+	A_BridgeOrbit(ball2);
+	A_BridgeOrbit(ball3);
+}
+
+void A_BridgeRemove(mobj_t *actor)
+{
+	actor->special1 = true;		// Removing the bridge
+	actor->flags &= ~MF_SOLID;
+	P_SetMobjState(actor, S_FREE_BRIDGE1);
+}
+
+
+//==========================================================================
+//
+// A_GhostOn
+//
+//==========================================================================
+
+/*
+void A_GhostOn(mobj_t *actor)
+{
+	actor->flags |= MF_SHADOW;
+}
+*/
+
+//==========================================================================
+//
+// A_GhostOff
+//
+//==========================================================================
+
+/*
+void A_GhostOff(mobj_t *actor)
+{
+	actor->flags &= ~MF_SHADOW;
+}
+*/
+
+//==========================================================================
+//
+// A_HideThing
+//
+//==========================================================================
+
+void A_HideThing(mobj_t *actor)
+{
+	actor->flags2 |= MF2_DONTDRAW;
+}
+
+//==========================================================================
+//
+// A_UnHideThing
+//
+//==========================================================================
+
+void A_UnHideThing(mobj_t *actor)
+{
+	actor->flags2 &= ~MF2_DONTDRAW;
+}
+
+//==========================================================================
+//
+// A_SetShootable
+//
+//==========================================================================
+
+void A_SetShootable(mobj_t *actor)
+{
+	actor->flags2 &= ~MF2_NONSHOOTABLE;
+	actor->flags |= MF_SHOOTABLE;
+}
+
+//==========================================================================
+//
+// A_UnSetShootable
+//
+//==========================================================================
+
+void A_UnSetShootable(mobj_t *actor)
+{
+	actor->flags2 |= MF2_NONSHOOTABLE;
+	actor->flags &= ~MF_SHOOTABLE;
+}
+
+//==========================================================================
+//
+// A_SetAltShadow
+//
+//==========================================================================
+
+void A_SetAltShadow(mobj_t *actor)
+{
+	actor->flags &= ~MF_SHADOW;
+	actor->flags |= MF_ALTSHADOW;
+}
+
+//==========================================================================
+//
+// A_UnSetAltShadow
+//
+//==========================================================================
+
+/*
+void A_UnSetAltShadow(mobj_t *actor)
+{
+	actor->flags &= ~MF_ALTSHADOW;
+}
+*/
+
+//--------------------------------------------------------------------------
+//
+// Sound Action Routines
+//
+//--------------------------------------------------------------------------
+
+//==========================================================================
+//
+// A_ContMobjSound
+//
+//==========================================================================
+
+void A_ContMobjSound(mobj_t *actor)
+{
+	switch (actor->type)
+	{
+	case MT_SERPENTFX:
+		S_StartSound(actor, SFX_SERPENTFX_CONTINUOUS);
+		break;
+	case MT_HAMMER_MISSILE:
+		S_StartSound(actor, SFX_FIGHTER_HAMMER_CONTINUOUS);
+		break;
+	case MT_QUAKE_FOCUS:
+		S_StartSound(actor, SFX_EARTHQUAKE);
+		break;
+	default:
+		break;
+	}
+}
+
+//==========================================================================
+//
+// PROC A_ESound
+//
+//==========================================================================
+
+void A_ESound(mobj_t *mo)
+{
+	int sound;
+
+	switch (mo->type)
+	{
+	case MT_SOUNDWIND:
+		sound = SFX_WIND;
+		break;
+	default:
+		sound = SFX_NONE;
+		break;
+	}
+	S_StartSound(mo, sound);
+}
+
+
+//==========================================================================
+// Summon Minotaur -- see p_enemy for variable descriptions
+//==========================================================================
+
+void A_Summon(mobj_t *actor)
+{
+	mobj_t *mo;
+	mobj_t *master;
+	int summontime;
+
+	mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_MINOTAUR);
+	if (mo)
+	{
+		if (P_TestMobjLocation(mo) == false || !actor->special1)
+		{ // Didn't fit - change back to artifact
+			P_SetMobjState(mo, S_NULL);
+			mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_SUMMONMAULATOR);
+			if (mo)
+				mo->flags2 |= MF2_DROPPED;
+			return;
+		}
+
+		/* record the time in little endian format */
+		summontime = LONG(leveltime);
+		memcpy((void *)mo->args, &summontime, sizeof(int));
+		master = (mobj_t *)actor->special1;
+		if (master->flags & MF_CORPSE)
+		{	// Master dead
+			mo->special1 = 0;		// No master
+		}
+		else
+		{
+			mo->special1 = actor->special1;		// Pointer to master (mobj_t *)
+			P_GivePower(master->player, pw_minotaur);
+		}
+
+		// Make smoke puff
+		P_SpawnMobj(actor->x, actor->y, actor->z, MT_MNTRSMOKE);
+		S_StartSound(actor, SFX_MAULATOR_ACTIVE);
+	}
+}
+
+
+//==========================================================================
+// Fog Variables:
+//
+//		args[0]		Speed (0..10) of fog
+//		args[1]		Angle of spread (0..128)
+//		args[2]		Frequency of spawn (1..10)
+//		args[3]		Lifetime countdown
+//		args[4]		Boolean: fog moving?
+//		special1	Internal:  Counter for spawn frequency
+//		special2	Internal:  Index into floatbob table
+//
+//==========================================================================
+
+void A_FogSpawn(mobj_t *actor)
+{
+	mobj_t *mo = NULL;
+	angle_t delta;
+
+	if (actor->special1-- > 0)
+		return;
+
+	actor->special1 = actor->args[2];		// Reset frequency count
+
+	switch (P_Random() % 3)
+	{
+	case 0:
+		mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_FOGPATCHS);
+		break;
+	case 1:
+		mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_FOGPATCHM);
+		break;
+	case 2:
+		mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_FOGPATCHL);
+		break;
+	}
+
+	if (mo)
+	{
+		delta = actor->args[1];
+		if (delta == 0)
+			delta = 1;
+		mo->angle = actor->angle + (((P_Random()%delta)-(delta>>1))<<24);
+		mo->target = actor;
+		if (actor->args[0] < 1)
+			actor->args[0] = 1;
+		mo->args[0] = (P_Random() % (actor->args[0])) + 1;	// Random speed
+		mo->args[3] = actor->args[3];				// Set lifetime
+		mo->args[4] = 1;					// Set to moving
+		mo->special2 = P_Random() & 63;
+	}
+}
+
+
+void A_FogMove(mobj_t *actor)
+{
+	int speed = actor->args[0]<<FRACBITS;
+	angle_t angle;
+	int weaveindex;
+
+	if (!(actor->args[4]))
+		return;
+
+	if (actor->args[3]-- <= 0)
+	{
+		P_SetMobjStateNF(actor, actor->info->deathstate);
+		return;
+	}
+
+	if ((actor->args[3] % 4) == 0)
+	{
+		weaveindex = actor->special2;
+		actor->z += FloatBobOffsets[weaveindex]>>1;
+		actor->special2 = (weaveindex + 1) & 63;
+	}
+
+	angle = actor->angle>>ANGLETOFINESHIFT;
+	actor->momx = FixedMul(speed, finecosine[angle]);
+	actor->momy = FixedMul(speed, finesine[angle]);
+}
+
+//===========================================================================
+//
+// A_PoisonBagInit
+//
+//===========================================================================
+
+void A_PoisonBagInit(mobj_t *actor)
+{
+	mobj_t *mo;
+
+	mo = P_SpawnMobj(actor->x, actor->y, actor->z+28*FRACUNIT, MT_POISONCLOUD);
+	if (!mo)
+	{
+		return;
+	}
+	mo->momx = 1; // missile objects must move to impact other objects
+	mo->special1 = 24 + (P_Random() & 7);
+	mo->special2 = 0;
+	mo->target = actor->target;
+	mo->radius = 20 * FRACUNIT;
+	mo->height = 30 * FRACUNIT;
+	mo->flags &= ~MF_NOCLIP;
+}
+
+//===========================================================================
+//
+// A_PoisonBagCheck
+//
+//===========================================================================
+
+void A_PoisonBagCheck(mobj_t *actor)
+{
+	if (!--actor->special1)
+	{
+		P_SetMobjState(actor, S_POISONCLOUD_X1);
+	}
+	else
+	{
+		return;
+	}
+}
+
+//===========================================================================
+//
+// A_PoisonBagDamage
+//
+//===========================================================================
+
+void A_PoisonBagDamage(mobj_t *actor)
+{
+	int bobIndex;
+
+	extern void A_Explode(mobj_t *actor);
+
+	A_Explode(actor);
+
+	bobIndex = actor->special2;
+	actor->z += FloatBobOffsets[bobIndex]>>4;
+	actor->special2 = (bobIndex + 1) & 63;
+}
+
+//===========================================================================
+//
+// A_PoisonShroom
+//
+//===========================================================================
+
+void A_PoisonShroom(mobj_t *actor)
+{
+	actor->tics = 128+(P_Random()<<1);
+}
+
+//===========================================================================
+//
+// A_CheckThrowBomb
+//
+//===========================================================================
+
+void A_CheckThrowBomb(mobj_t *actor)
+{
+	if (abs(actor->momx) < 1.5*FRACUNIT && abs(actor->momy) < 1.5*FRACUNIT
+		&& actor->momz < 2*FRACUNIT
+		&& actor->state == &states[S_THROWINGBOMB6])
+	{
+		P_SetMobjState(actor, S_THROWINGBOMB7);
+		actor->z = actor->floorz;
+		actor->momz = 0;
+		actor->flags2 &= ~MF2_FLOORBOUNCE;
+		actor->flags &= ~MF_MISSILE;
+	}
+	if (!--actor->health)
+	{
+		P_SetMobjState(actor, actor->info->deathstate);
+	}
+}
+
+//===========================================================================
+// Quake variables
+//
+//		args[0]		Intensity on richter scale (2..9)
+//		args[1]		Duration in tics
+//		args[2]		Radius for damage
+//		args[3]		Radius for tremor
+//		args[4]		TID of map thing for focus of quake
+//
+//===========================================================================
+
+//===========================================================================
+//
+// A_LocalQuake
+//
+//===========================================================================
+
+boolean A_LocalQuake(byte *args, mobj_t *actor)
+{
+	mobj_t *focus, *target;
+	int lastfound = 0;
+	int success = false;
+
+	(void)actor;	// suppress warning
+
+	// Find all quake foci
+	do
+	{
+		target = P_FindMobjFromTID(args[4], &lastfound);
+		if (target)
+		{
+			focus = P_SpawnMobj(target->x,
+							target->y,
+							target->z, MT_QUAKE_FOCUS);
+			if (focus)
+			{
+				focus->args[0] = args[0];
+				focus->args[1] = args[1]>>1;	// decremented every 2 tics
+				focus->args[2] = args[2];
+				focus->args[3] = args[3];
+				focus->args[4] = args[4];
+				success = true;
+			}
+		}
+	} while (target != NULL);
+
+	return success;
+}
+
+
+//===========================================================================
+//
+// A_Quake
+//
+//===========================================================================
+int	localQuakeHappening[MAXPLAYERS];
+
+void A_Quake(mobj_t *actor)
+{
+	angle_t an;
+	player_t *player;
+	mobj_t *victim;
+	int richters = actor->args[0];
+	int playnum;
+	fixed_t dist;
+
+	if (actor->args[1]-- > 0)
+	{
+		for (playnum = 0; playnum < MAXPLAYERS; playnum++)
+		{
+			player = &players[playnum];
+			if (!playeringame[playnum])
+				continue;
+
+			victim = player->mo;
+			dist = P_AproxDistance(actor->x - victim->x,
+						actor->y - victim->y) >> (FRACBITS+6);
+			// Tested in tile units (64 pixels)
+			if (dist < actor->args[3])		// In tremor radius
+			{
+				localQuakeHappening[playnum] = richters;
+			}
+			// Check if in damage radius
+			if ((dist < actor->args[2]) &&
+				(victim->z <= victim->floorz))
+			{
+				if (P_Random() < 50)
+				{
+					P_DamageMobj(victim, NULL, NULL, HITDICE(1));
+				}
+				// Thrust player around
+				an = victim->angle + ANGLE_1*P_Random();
+				P_ThrustMobj(victim,an,richters<<(FRACBITS-1));
+			}
+		}
+	}
+	else
+	{
+		for (playnum = 0; playnum < MAXPLAYERS; playnum++)
+		{
+			localQuakeHappening[playnum] = false;
+		}
+		P_SetMobjState(actor, S_NULL);
+	}
+}
+
+
+//===========================================================================
+//
+// Teleport other stuff
+//
+//===========================================================================
+
+#define TELEPORT_LIFE		1
+
+void A_TeloSpawnA(mobj_t *actor)
+{
+	mobj_t *mo;
+
+	mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_TELOTHER_FX2);
+	if (mo)
+	{
+		mo->special1 = TELEPORT_LIFE;			// Lifetime countdown
+		mo->angle = actor->angle;
+		mo->target = actor->target;
+		mo->momx = actor->momx>>1;
+		mo->momy = actor->momy>>1;
+		mo->momz = actor->momz>>1;
+	}
+}
+
+void A_TeloSpawnB(mobj_t *actor)
+{
+	mobj_t *mo;
+
+	mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_TELOTHER_FX3);
+	if (mo)
+	{
+		mo->special1 = TELEPORT_LIFE;			// Lifetime countdown
+		mo->angle = actor->angle;
+		mo->target = actor->target;
+		mo->momx = actor->momx>>1;
+		mo->momy = actor->momy>>1;
+		mo->momz = actor->momz>>1;
+	}
+}
+
+void A_TeloSpawnC(mobj_t *actor)
+{
+	mobj_t *mo;
+
+	mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_TELOTHER_FX4);
+	if (mo)
+	{
+		mo->special1 = TELEPORT_LIFE;			// Lifetime countdown
+		mo->angle = actor->angle;
+		mo->target = actor->target;
+		mo->momx = actor->momx>>1;
+		mo->momy = actor->momy>>1;
+		mo->momz = actor->momz>>1;
+	}
+}
+
+void A_TeloSpawnD(mobj_t *actor)
+{
+	mobj_t *mo;
+
+	mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_TELOTHER_FX5);
+	if (mo)
+	{
+		mo->special1 = TELEPORT_LIFE;			// Lifetime countdown
+		mo->angle = actor->angle;
+		mo->target = actor->target;
+		mo->momx = actor->momx>>1;
+		mo->momy = actor->momy>>1;
+		mo->momz = actor->momz>>1;
+	}
+}
+
+void A_CheckTeleRing(mobj_t *actor)
+{
+	if (actor->special1-- <= 0)
+	{
+		P_SetMobjState(actor, actor->info->deathstate);
+	}
+}
+
+
+// Dirt stuff
+
+void P_SpawnDirt(mobj_t *actor, fixed_t radius)
+{
+	fixed_t x,y,z;
+	int dtype = 0;
+	mobj_t *mo;
+	angle_t angle;
+
+	angle = P_Random()<<5;		// <<24 >>19
+	x = actor->x + FixedMul(radius,finecosine[angle]);
+	y = actor->y + FixedMul(radius,finesine[angle]);
+//	x = actor->x + ((P_Random()-P_Random())%radius)<<FRACBITS;
+//	y = actor->y + ((P_Random()-P_Random()<<FRACBITS)%radius);
+	z = actor->z + (P_Random()<<9) + FRACUNIT;
+	switch (P_Random() % 6)
+	{
+	case 0:
+		dtype = MT_DIRT1;
+		break;
+	case 1:
+		dtype = MT_DIRT2;
+		break;
+	case 2:
+		dtype = MT_DIRT3;
+		break;
+	case 3:
+		dtype = MT_DIRT4;
+		break;
+	case 4:
+		dtype = MT_DIRT5;
+		break;
+	case 5:
+		dtype = MT_DIRT6;
+		break;
+	}
+	mo = P_SpawnMobj(x, y, z, dtype);
+	if (mo)
+	{
+		mo->momz = P_Random()<<10;
+	}
+}
+
+
+//===========================================================================
+//
+// Thrust floor stuff
+//
+// Thrust Spike Variables
+//		special1		pointer to dirt clump mobj
+//		special2		speed of raise
+//		args[0]		0 = lowered,  1 = raised
+//		args[1]		0 = normal,   1 = bloody
+//===========================================================================
+
+void A_ThrustInitUp(mobj_t *actor)
+{
+	actor->special2 = 5;		// Raise speed
+	actor->args[0] = 1;		// Mark as up
+	actor->floorclip = 0;
+	actor->flags = MF_SOLID;
+	actor->flags2 = MF2_NOTELEPORT|MF2_FLOORCLIP;
+	actor->special1 = 0L;
+}
+
+void A_ThrustInitDn(mobj_t *actor)
+{
+	mobj_t *mo;
+	actor->special2 = 5;		// Raise speed
+	actor->args[0] = 0;		// Mark as down
+	actor->floorclip = actor->info->height;
+	actor->flags = 0;
+	actor->flags2 = MF2_NOTELEPORT|MF2_FLOORCLIP|MF2_DONTDRAW;
+	mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_DIRTCLUMP);
+	actor->special1 = (intptr_t)mo;
+}
+
+void A_ThrustRaise(mobj_t *actor)
+{
+	if (A_RaiseMobj(actor))
+	{	// Reached it's target height
+		actor->args[0] = 1;
+		if (actor->args[1])
+			P_SetMobjStateNF(actor, S_BTHRUSTINIT2_1);
+		else
+			P_SetMobjStateNF(actor, S_THRUSTINIT2_1);
+	}
+
+	// Lose the dirt clump
+	if ((actor->floorclip < actor->height) && actor->special1)
+	{
+		P_RemoveMobj((mobj_t *)actor->special1);
+		actor->special1 = 0;
+	}
+
+	// Spawn some dirt
+	if (P_Random() < 40)
+		P_SpawnDirt(actor, actor->radius);
+	actor->special2++;		// Increase raise speed
+}
+
+void A_ThrustLower(mobj_t *actor)
+{
+	if (A_SinkMobj(actor))
+	{
+		actor->args[0] = 0;
+		if (actor->args[1])
+			P_SetMobjStateNF(actor, S_BTHRUSTINIT1_1);
+		else
+			P_SetMobjStateNF(actor, S_THRUSTINIT1_1);
+	}
+}
+
+void A_ThrustBlock(mobj_t *actor)
+{
+	actor->flags |= MF_SOLID;
+}
+
+void A_ThrustImpale(mobj_t *actor)
+{
+	// Impale all shootables in radius
+	PIT_ThrustSpike(actor);
+}
+
+//===========================================================================
+//
+// A_SoAExplode - Suit of Armor Explode
+//
+//===========================================================================
+
+void A_SoAExplode(mobj_t *actor)
+{
+	mobj_t *mo;
+	int i;
+
+	for (i = 0; i < 10; i++)
+	{
+		mo = P_SpawnMobj(actor->x+((P_Random()-128)<<12), 
+			actor->y + ((P_Random()-128)<<12), 
+			actor->z + (P_Random()*actor->height/256), MT_ZARMORCHUNK);
+		P_SetMobjState(mo, mo->info->spawnstate + i);
+		if (mo)
+		{
+			mo->momz = ((P_Random()&7)+5)*FRACUNIT;
+			mo->momx = (P_Random()-P_Random())<<(FRACBITS-6);
+			mo->momy = (P_Random()-P_Random())<<(FRACBITS-6);
+		}
+	}
+	if (actor->args[0])
+	{ // Spawn an item
+		if (!nomonsters ||
+		    !(mobjinfo[TranslateThingType[actor->args[0]]].flags & MF_COUNTKILL))
+		{ // Only spawn monsters if not -nomonsters
+			P_SpawnMobj(actor->x, actor->y, actor->z,
+				TranslateThingType[actor->args[0]]);
+		}
+	}
+	S_StartSound(mo, SFX_SUITOFARMOR_BREAK);
+	P_RemoveMobj(actor);
+}
+
+//===========================================================================
+//
+// A_BellReset1
+//
+//===========================================================================
+
+void A_BellReset1(mobj_t *actor)
+{
+	actor->flags |= MF_NOGRAVITY;
+	actor->height <<= 2;
+}
+
+//===========================================================================
+//
+// A_BellReset2
+//
+//===========================================================================
+
+void A_BellReset2(mobj_t *actor)
+{
+	actor->flags |= MF_SHOOTABLE;
+	actor->flags &= ~MF_CORPSE;
+	actor->health = 5;
+}
+
+
+//===========================================================================
+//
+// A_FlameCheck
+//
+//===========================================================================
+
+void A_FlameCheck(mobj_t *actor)
+{
+	if (!actor->args[0]--)		// Called every 8 tics
+	{
+		P_SetMobjState(actor, S_NULL);
+	}
+}
+
+
+//===========================================================================
+// Bat Spawner Variables
+//	special1	frequency counter
+//	special2	
+//	args[0]		frequency of spawn (1=fastest, 10=slowest)
+//	args[1]		spread angle (0..255)
+//	args[2]		
+//	args[3]		duration of bats (in octics)
+//	args[4]		turn amount per move (in degrees)
+//
+// Bat Variables
+//	special2	lifetime counter
+//	args[4]		turn amount per move (in degrees)
+//===========================================================================
+
+void A_BatSpawnInit(mobj_t *actor)
+{
+	actor->special1 = 0;	// Frequency count
+}
+
+void A_BatSpawn(mobj_t *actor)
+{
+	mobj_t *mo;
+	int delta;
+	angle_t angle;
+
+	// Countdown until next spawn
+	if (actor->special1-- > 0)
+		return;
+	actor->special1 = actor->args[0];		// Reset frequency count
+
+	delta = actor->args[1];
+	if (delta == 0)
+		delta = 1;
+	angle = actor->angle + (((P_Random()%delta)-(delta>>1))<<24);
+	mo = P_SpawnMissileAngle(actor, MT_BAT, angle, 0);
+	if (mo)
+	{
+		mo->args[0] = P_Random() & 63;			// floatbob index
+		mo->args[4] = actor->args[4];			// turn degrees
+		mo->special2 = actor->args[3]<<3;		// Set lifetime
+		mo->target = actor;
+	}
+}
+
+
+void A_BatMove(mobj_t *actor)
+{
+	angle_t newangle;
+	fixed_t speed;
+
+	if (actor->special2 < 0)
+	{
+		P_SetMobjState(actor, actor->info->deathstate);
+	}
+	actor->special2 -= 2;		// Called every 2 tics
+
+	if (P_Random() < 128)
+	{
+		newangle = actor->angle + ANGLE_1*actor->args[4];
+	}
+	else
+	{
+		newangle = actor->angle - ANGLE_1*actor->args[4];
+	}
+
+	// Adjust momentum vector to new direction
+	newangle >>= ANGLETOFINESHIFT;
+	speed = FixedMul(actor->info->speed, P_Random()<<10);
+	actor->momx = FixedMul(speed, finecosine[newangle]);
+	actor->momy = FixedMul(speed, finesine[newangle]);
+
+	if (P_Random() < 15)
+		S_StartSound(actor, SFX_BAT_SCREAM);
+
+	// Handle Z movement
+	actor->z = actor->target->z + 2*FloatBobOffsets[actor->args[0]];
+	actor->args[0] = (actor->args[0] + 3) & 63;
+}
+
+//===========================================================================
+//
+// A_TreeDeath
+//
+//===========================================================================
+
+void A_TreeDeath(mobj_t *actor)
+{
+	if (!(actor->flags2 & MF2_FIREDAMAGE))
+	{
+		actor->height <<= 2;
+		actor->flags |= MF_SHOOTABLE;
+		actor->flags &= ~(MF_CORPSE + MF_DROPOFF);
+		actor->health = 35;
+		return;
+	}
+	else
+	{
+		P_SetMobjState(actor, actor->info->meleestate);
+	}
+}
+
+//===========================================================================
+//
+// A_NoGravity
+//
+//===========================================================================
+
+void A_NoGravity(mobj_t *actor)
+{
+	actor->flags |= MF_NOGRAVITY;
+}
+
--- /dev/null
+++ b/am_data.h
@@ -1,0 +1,111 @@
+
+//**************************************************************************
+//**
+//** am_data.h : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 373 $
+//** $Date: 2009-05-19 21:14:28 +0300 (Tue, 19 May 2009) $
+//**
+//**************************************************************************
+
+#ifndef __AMDATA_H__
+#define __AMDATA_H__
+
+/* a line drawing of the player pointing right, starting from the middle. */
+
+#define R	((8 * PLAYERRADIUS) / 7)
+
+mline_t player_arrow[] =
+{
+	{ { -R+R/4, 0 }, { 0, 0} },		// center line.
+	{ { -R+R/4, R/8 }, { R, 0} },		// blade
+	{ { -R+R/4, -R/8 }, { R, 0 } },
+	{ { -R+R/4, -R/4 }, { -R+R/4, R/4 } },	// crosspiece
+	{ { -R+R/8, -R/4 }, { -R+R/8, R/4 } },
+	{ { -R+R/8, -R/4 }, { -R+R/4, -R/4} },	// crosspiece connectors
+	{ { -R+R/8, R/4 }, { -R+R/4, R/4} },
+	{ { -R-R/4, R/8 }, { -R-R/4, -R/8 } },	// pommel
+	{ { -R-R/4, R/8 }, { -R+R/8, R/8 } },
+	{ { -R-R/4, -R/8}, { -R+R/8, -R/8 } }
+};
+
+/*
+mline_t keysquare[] =
+{
+	{ { 0, 0 }, { R/4, -R/2 } },
+	{ { R/4, -R/2 }, { R/2, -R/2 } },
+	{ { R/2, -R/2 }, { R/2, R/2 } },
+	{ { R/2, R/2 }, { R/4, R/2 } },
+	{ { R/4, R/2 }, { 0, 0 } },		// handle part type thing
+	{ { 0, 0 }, { -R, 0 } },		// stem
+	{ { -R, 0 }, { -R, -R/2 } },		// end lockpick part
+	{ { -3*R/4, 0 }, { -3*R/4, -R/4 } }
+};
+*/
+
+/*
+mline_t player_arrow[] =
+{
+	{ { -R+R/8, 0 }, { R, 0 } },		// -----
+	{ { R, 0 }, { R-R/2, R/4 } },		// ----->
+	{ { R, 0 }, { R-R/2, -R/4 } },
+	{ { -R+R/8, 0 }, { -R-R/8, R/4 } },	// >---->
+	{ { -R+R/8, 0 }, { -R-R/8, -R/4 } },
+	{ { -R+3*R/8, 0 }, { -R+R/8, R/4 } },	// >>--->
+	{ { -R+3*R/8, 0 }, { -R+R/8, -R/4 } }
+};
+*/
+#undef R
+
+#define NUMPLYRLINES		(sizeof(player_arrow) / sizeof(mline_t))
+#define NUMKEYSQUARELINES	(sizeof(keysquare) / sizeof(mline_t))
+
+/*
+#define R	((8 * PLAYERRADIUS) / 7)
+mline_t cheat_player_arrow[] =
+{
+	{ { -R+R/8, 0 }, { R, 0 } },		// -----
+	{ { R, 0 }, { R-R/2, R/6 } },		// ----->
+	{ { R, 0 }, { R-R/2, -R/6 } },
+	{ { -R+R/8, 0 }, { -R-R/8, R/6 } },	// >----->
+	{ { -R+R/8, 0 }, { -R-R/8, -R/6 } },
+	{ { -R+3*R/8, 0 }, { -R+R/8, R/6 } },	// >>----->
+	{ { -R+3*R/8, 0 }, { -R+R/8, -R/6 } },
+	{ { -R/2, 0 }, { -R/2, -R/6 } },	// >>-d--->
+	{ { -R/2, -R/6 }, { -R/2+R/6, -R/6 } },
+	{ { -R/2+R/6, -R/6 }, { -R/2+R/6, R/4 } },
+	{ { -R/6, 0 }, { -R/6, -R/6 } },	// >>-dd-->
+	{ { -R/6, -R/6 }, { 0, -R/6 } },
+	{ { 0, -R/6 }, { 0, R/4 } },
+	{ { R/6, R/4 }, { R/6, -R/7 } },	// >>-ddt->
+	{ { R/6, -R/7 }, { R/6+R/32, -R/7-R/32 } },
+	{ { R/6+R/32, -R/7-R/32 }, { R/6+R/10, -R/7 } }
+};
+#undef R
+#define NUMCHEATPLYRLINES	(sizeof(cheat_player_arrow) / sizeof(mline_t))
+*/
+
+/*
+#define R	(FRACUNIT)
+mline_t triangle_guy[] =
+{
+	{ { -.867*R, -.5*R }, { .867*R, -.5*R } },
+	{ { .867*R, -.5*R } , { 0, R } },
+	{ { 0, R }, { -.867*R, -.5*R } }
+};
+#undef R
+#define NUMTRIANGLEGUYLINES	(sizeof(triangle_guy) / sizeof(mline_t))
+*/
+
+#define R	(FRACUNIT)
+mline_t thintriangle_guy[] =
+{
+	{ { -.5*R, -.7*R }, { R, 0 } },
+	{ { R, 0 }, { -.5*R, .7*R } },
+	{ { -.5*R, .7*R }, { -.5*R, -.7*R } }
+};
+#undef R
+#define NUMTHINTRIANGLEGUYLINES	(sizeof(thintriangle_guy) / sizeof(mline_t))
+
+#endif	/* __AMDATA_H__ */
+
--- /dev/null
+++ b/am_map.c
@@ -1,0 +1,1562 @@
+
+//**************************************************************************
+//**
+//** am_map.c : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 575 $
+//** $Date: 2011-04-13 22:06:28 +0300 (Wed, 13 Apr 2011) $
+//**
+//**************************************************************************
+
+#include "h2stdinc.h"
+#include "h2def.h"
+#include "p_local.h"
+#include "am_map.h"
+#include "am_data.h"
+
+#ifdef RENDER3D
+#include "ogl_def.h"
+
+#define MTOFX(x)	FixedMul((x),scale_mtof)
+
+#define CXMTOFX(x)	((f_x<<16) + MTOFX((x)-m_x))
+#define CYMTOFX(y)	((f_y<<16) + ((f_h<<16) - MTOFX((y)-m_y)))
+
+static int maplumpnum;
+#endif	/* RENDER3D */
+
+#define NUMALIAS	3 /* Number of antialiased lines. */
+
+int cheating = 0;
+static int grid = 0;
+
+static int leveljuststarted = 1; // kluge until AM_LevelInit() is called
+
+boolean    automapactive = false;
+static int finit_width = SCREENWIDTH;
+static int finit_height = SCREENHEIGHT-SBARHEIGHT-3;
+static int f_x, f_y; // location of window on screen
+static int f_w, f_h; // size of window on screen
+static int lightlev; // used for funky strobing effect
+static int amclock;
+
+static mpoint_t m_paninc; // how far the window pans each tic (map coords)
+static fixed_t mtof_zoommul; // how far the window zooms in each tic (map coords)
+static fixed_t ftom_zoommul; // how far the window zooms in each tic (fb coords)
+
+static fixed_t m_x, m_y;   // LL x,y where the window is on the map (map coords)
+static fixed_t m_x2, m_y2; // UR x,y where the window is on the map (map coords)
+
+// width/height of window on map (map coords)
+static fixed_t m_w, m_h;
+static fixed_t min_x, min_y; // based on level size
+static fixed_t max_x, max_y; // based on level size
+static fixed_t max_w, max_h; // max_x-min_x, max_y-min_y
+static fixed_t min_w, min_h; // based on player size
+static fixed_t min_scale_mtof; // used to tell when to stop zooming out
+static fixed_t max_scale_mtof; // used to tell when to stop zooming in
+
+// old stuff for recovery later
+static fixed_t old_m_w, old_m_h;
+static fixed_t old_m_x, old_m_y;
+
+// old location used by the Follower routine
+static mpoint_t f_oldloc;
+
+// used by MTOF to scale from map-to-frame-buffer coords
+static fixed_t scale_mtof = INITSCALEMTOF;
+// used by FTOM to scale from frame-buffer-to-map coords (=1/scale_mtof)
+static fixed_t scale_ftom;
+
+static player_t *plr; // the player represented by an arrow
+static vertex_t oldplr;
+
+static int followplayer = 1; // specifies whether to follow the player around
+
+static char cheat_kills[] = { 'k', 'i', 'l', 'l', 's' };
+static boolean ShowKills = 0;
+static unsigned ShowKillsCount = 0;
+
+extern boolean viewactive;
+
+#ifndef RENDER3D
+static byte antialias[NUMALIAS][8] =
+{
+	{ 83, 84, 85, 86, 87, 88, 89, 90 },
+	{ 96, 96, 95, 94, 93, 92, 91, 90 },
+	{ 107, 108, 109, 110, 111, 112, 89, 90 }
+};
+
+/*
+static byte *aliasmax[NUMALIAS] =
+{
+	&antialias[0][7],
+	&antialias[1][7],
+	&antialias[2][7]
+};
+*/
+
+static byte *maplump;	// pointer to the raw data for the automap background.
+
+static byte *fb;	// pseudo-frame buffer
+#endif	/* RENDER3D */
+
+static short mapystart = 0; // y-value for the start of the map bitmap...used in
+							//the parallax stuff.
+static short mapxstart = 0; //x-value for the bitmap.
+
+// Functions
+
+#ifndef RENDER3D
+static void DrawWuLine (int X0, int Y0, int X1, int Y1, byte *BaseColor,
+			int NumLevels, unsigned short IntensityBits);
+#endif	/* RENDER3D */
+
+static void AM_DrawDeathmatchStats(void);
+static void DrawWorldTimer(void);
+
+// Calculates the slope and slope according to the x-axis of a line
+// segment in map coordinates (with the upright y-axis n' all) so
+// that it can be used with the brain-dead drawing stuff.
+
+// Ripped out for Heretic
+/*
+static void AM_getIslope(mline_t *ml, islope_t *is)
+{
+	int dx, dy;
+
+	dy = ml->a.y - ml->b.y;
+	dx = ml->b.x - ml->a.x;
+	if (!dy)
+		is->islp = (dx < 0 ? -H2MAXINT : H2MAXINT);
+	else
+		is->islp = FixedDiv(dx, dy);
+	if (!dx)
+		is->slp = (dy < 0 ? -H2MAXINT : H2MAXINT);
+	else
+		is->slp = FixedDiv(dy, dx);
+}
+*/
+
+static void AM_activateNewScale(void)
+{
+	m_x += m_w/2;
+	m_y += m_h/2;
+	m_w = FTOM(f_w);
+	m_h = FTOM(f_h);
+	m_x -= m_w/2;
+	m_y -= m_h/2;
+	m_x2 = m_x + m_w;
+	m_y2 = m_y + m_h;
+}
+
+static void AM_saveScaleAndLoc(void)
+{
+	old_m_x = m_x;
+	old_m_y = m_y;
+	old_m_w = m_w;
+	old_m_h = m_h;
+}
+
+static void AM_restoreScaleAndLoc(void)
+{
+	m_w = old_m_w;
+	m_h = old_m_h;
+	if (!followplayer)
+	{
+		m_x = old_m_x;
+		m_y = old_m_y;
+	}
+	else
+	{
+		m_x = plr->mo->x - m_w/2;
+		m_y = plr->mo->y - m_h/2;
+	}
+	m_x2 = m_x + m_w;
+	m_y2 = m_y + m_h;
+
+	// Change the scaling multipliers
+	scale_mtof = FixedDiv(f_w<<FRACBITS, m_w);
+	scale_ftom = FixedDiv(FRACUNIT, scale_mtof);
+}
+
+static void AM_findMinMaxBoundaries(void)
+{
+	int i;
+	fixed_t a, b;
+
+	min_x = min_y = H2MAXINT;
+	max_x = max_y = -H2MAXINT;
+	for (i = 0; i < numvertexes; i++)
+	{
+		if (vertexes[i].x < min_x)
+			min_x = vertexes[i].x;
+		else if (vertexes[i].x > max_x)
+			max_x = vertexes[i].x;
+		if (vertexes[i].y < min_y)
+			min_y = vertexes[i].y;
+		else if (vertexes[i].y > max_y)
+			max_y = vertexes[i].y;
+	}
+	max_w = max_x - min_x;
+	max_h = max_y - min_y;
+	min_w = 2*PLAYERRADIUS;
+	min_h = 2*PLAYERRADIUS;
+
+	a = FixedDiv(f_w<<FRACBITS, max_w);
+	b = FixedDiv(f_h<<FRACBITS, max_h);
+	min_scale_mtof = a < b ? a : b;
+
+	max_scale_mtof = FixedDiv(f_h<<FRACBITS, 2*PLAYERRADIUS);
+}
+
+static void AM_changeWindowLoc(void)
+{
+	if (m_paninc.x || m_paninc.y)
+	{
+		followplayer = 0;
+		f_oldloc.x = H2MAXINT;
+	}
+
+	m_x += m_paninc.x;
+	m_y += m_paninc.y;
+
+	if (m_x + m_w/2 > max_x)
+	{
+		m_x = max_x - m_w/2;
+		m_paninc.x = 0;
+	}
+	else if (m_x + m_w/2 < min_x)
+	{
+		m_x = min_x - m_w/2;
+		m_paninc.x = 0;
+	}
+	if (m_y + m_h/2 > max_y)
+	{
+		m_y = max_y - m_h/2;
+		m_paninc.y = 0;
+	}
+	else if (m_y + m_h/2 < min_y)
+	{
+		m_y = min_y - m_h/2;
+		m_paninc.y = 0;
+	}
+	/*
+	mapxstart += MTOF(m_paninc.x+FRACUNIT/2);
+	mapystart -= MTOF(m_paninc.y+FRACUNIT/2);
+	if (mapxstart >= finit_width)
+		mapxstart -= finit_width;
+	if (mapxstart < 0)
+		mapxstart += finit_width;
+	if (mapystart >= finit_height)
+		mapystart -= finit_height;
+	if (mapystart < 0)
+		mapystart += finit_height;
+	*/
+	m_x2 = m_x + m_w;
+	m_y2 = m_y + m_h;
+}
+
+static void AM_initVariables(void)
+{
+	int pnum;
+
+	automapactive = true;
+#ifndef RENDER3D
+	fb = screen;
+#endif
+
+	f_oldloc.x = H2MAXINT;
+	amclock = 0;
+	lightlev = 0;
+
+	m_paninc.x = m_paninc.y = 0;
+	ftom_zoommul = FRACUNIT;
+	mtof_zoommul = FRACUNIT;
+
+	m_w = FTOM(f_w);
+	m_h = FTOM(f_h);
+
+	// find player to center on initially
+	if (!playeringame[pnum = consoleplayer])
+	{
+		for (pnum = 0; pnum < MAXPLAYERS; pnum++)
+		{
+			if (playeringame[pnum])
+				break;
+		}
+	}
+	plr = &players[pnum];
+	oldplr.x = plr->mo->x;
+	oldplr.y = plr->mo->y;
+	m_x = plr->mo->x - m_w/2;
+	m_y = plr->mo->y - m_h/2;
+	AM_changeWindowLoc();
+
+	// for saving & restoring
+	old_m_x = m_x;
+	old_m_y = m_y;
+	old_m_w = m_w;
+	old_m_h = m_h;
+}
+
+static void AM_loadPics(void)
+{
+#ifdef RENDER3D
+	maplumpnum = W_GetNumForName("AUTOPAGE");
+#else
+	maplump = (byte *) W_CacheLumpName("AUTOPAGE", PU_STATIC);
+#endif
+}
+
+// should be called at the start of every level
+// right now, i figure it out myself
+
+static void AM_LevelInit(void)
+{
+	leveljuststarted = 0;
+
+	f_x = f_y = 0;
+	f_w = finit_width;
+	f_h = finit_height;
+	mapxstart = mapystart = 0;
+
+	AM_findMinMaxBoundaries();
+	scale_mtof = FixedDiv(min_scale_mtof, (int) (0.7*FRACUNIT));
+	if (scale_mtof > max_scale_mtof)
+		scale_mtof = min_scale_mtof;
+	scale_ftom = FixedDiv(FRACUNIT, scale_mtof);
+}
+
+static boolean stopped = true;
+
+void AM_Stop (void)
+{
+	automapactive = false;
+	stopped = true;
+	BorderNeedRefresh = true;
+}
+
+static void AM_Start (void)
+{
+	static int lastlevel = -1, lastepisode = -1;
+
+	if (!stopped)
+		AM_Stop();
+	stopped = false;
+	if (gamestate != GS_LEVEL)
+	{
+		return; // don't show automap if we aren't in a game!
+	}
+	if (lastlevel != gamemap || lastepisode != gameepisode)
+	{
+		AM_LevelInit();
+		lastlevel = gamemap;
+		lastepisode = gameepisode;
+	}
+	AM_initVariables();
+	AM_loadPics();
+}
+
+// set the window scale to the maximum size
+
+static void AM_minOutWindowScale(void)
+{
+	scale_mtof = min_scale_mtof;
+	scale_ftom = FixedDiv(FRACUNIT, scale_mtof);
+	AM_activateNewScale();
+}
+
+// set the window scale to the minimum size
+
+static void AM_maxOutWindowScale(void)
+{
+	scale_mtof = max_scale_mtof;
+	scale_ftom = FixedDiv(FRACUNIT, scale_mtof);
+	AM_activateNewScale();
+}
+
+boolean AM_Responder (event_t *ev)
+{
+	int rc;
+	static int bigstate = 0;
+
+	rc = false;
+	if (!automapactive)
+	{
+		if (ev->type == ev_keydown && ev->data1 == AM_STARTKEY
+			&& gamestate == GS_LEVEL)
+		{
+			AM_Start ();
+			SB_state = -1;
+			viewactive = false;
+			rc = true;
+		}
+	}
+	else if (ev->type == ev_keydown)
+	{
+		rc = true;
+		switch (ev->data1)
+		{
+		case AM_PANRIGHTKEY: // pan right
+			if (!followplayer)
+				m_paninc.x = FTOM(F_PANINC);
+			else
+				rc = false;
+			break;
+		case AM_PANLEFTKEY: // pan left
+			if (!followplayer)
+				m_paninc.x = -FTOM(F_PANINC);
+			else
+				rc = false;
+			break;
+		case AM_PANUPKEY: // pan up
+			if (!followplayer)
+				m_paninc.y = FTOM(F_PANINC);
+			else
+				rc = false;
+			break;
+		case AM_PANDOWNKEY: // pan down
+			if (!followplayer)
+				m_paninc.y = -FTOM(F_PANINC);
+			else
+				rc = false;
+			break;
+		case AM_ZOOMOUTKEY: // zoom out
+			mtof_zoommul = M_ZOOMOUT;
+			ftom_zoommul = M_ZOOMIN;
+			break;
+		case AM_ZOOMINKEY: // zoom in
+			mtof_zoommul = M_ZOOMIN;
+			ftom_zoommul = M_ZOOMOUT;
+			break;
+		case AM_ENDKEY:
+			bigstate = 0;
+			viewactive = true;
+			AM_Stop ();
+			SB_state = -1;
+			break;
+		case AM_GOBIGKEY:
+			bigstate = !bigstate;
+			if (bigstate)
+			{
+				AM_saveScaleAndLoc();
+				AM_minOutWindowScale();
+			}
+			else AM_restoreScaleAndLoc();
+			break;
+		case AM_FOLLOWKEY:
+			followplayer = !followplayer;
+			f_oldloc.x = H2MAXINT;
+			P_SetMessage(plr, 
+				followplayer ? AMSTR_FOLLOWON : AMSTR_FOLLOWOFF, true);
+			break;
+		default:
+			rc = false;
+		}
+
+		if (cheat_kills[ShowKillsCount] == ev->data1 && netgame && deathmatch)
+		{
+			ShowKillsCount++;
+			if (ShowKillsCount == 5)
+			{
+				ShowKillsCount = 0;
+				rc = false;
+				ShowKills ^= 1;
+			}
+		}
+		else
+		{
+			ShowKillsCount = 0;
+		}
+	}
+	else if (ev->type == ev_keyup)
+	{
+		rc = false;
+		switch (ev->data1)
+		{
+		case AM_PANRIGHTKEY:
+			if (!followplayer)
+				m_paninc.x = 0;
+			break;
+		case AM_PANLEFTKEY:
+			if (!followplayer)
+				m_paninc.x = 0;
+			break;
+		case AM_PANUPKEY:
+			if (!followplayer)
+				m_paninc.y = 0;
+			break;
+		case AM_PANDOWNKEY:
+			if (!followplayer)
+				m_paninc.y = 0;
+			break;
+		case AM_ZOOMOUTKEY:
+		case AM_ZOOMINKEY:
+			mtof_zoommul = FRACUNIT;
+			ftom_zoommul = FRACUNIT;
+			break;
+		}
+	}
+
+	return rc;
+}
+
+static void AM_changeWindowScale(void)
+{
+	// Change the scaling multipliers
+	scale_mtof = FixedMul(scale_mtof, mtof_zoommul);
+	scale_ftom = FixedDiv(FRACUNIT, scale_mtof);
+
+	if (scale_mtof < min_scale_mtof)
+		AM_minOutWindowScale();
+	else if (scale_mtof > max_scale_mtof)
+		AM_maxOutWindowScale();
+	else
+		AM_activateNewScale();
+}
+
+static void AM_doFollowPlayer(void)
+{
+	if (f_oldloc.x != plr->mo->x || f_oldloc.y != plr->mo->y)
+	{
+	//	m_x = FTOM(MTOF(plr->mo->x - m_w/2));
+	//	m_y = FTOM(MTOF(plr->mo->y - m_h/2));
+	//	m_x = plr->mo->x - m_w/2;
+	//	m_y = plr->mo->y - m_h/2;
+		m_x = FTOM(MTOF(plr->mo->x)) - m_w/2;
+		m_y = FTOM(MTOF(plr->mo->y)) - m_h/2;
+		m_x2 = m_x + m_w;
+		m_y2 = m_y + m_h;
+
+		// do the parallax parchment scrolling.
+		/*
+		dmapx = (MTOF(plr->mo->x)-MTOF(f_oldloc.x)); //fixed point
+		dmapy = (MTOF(f_oldloc.y)-MTOF(plr->mo->y));
+
+		if (f_oldloc.x == H2MAXINT)	//to eliminate an error when the user first
+			dmapx = 0;				//goes into the automap.
+		mapxstart += dmapx;
+		mapystart += dmapy;
+
+		while (mapxstart >= finit_width)
+			mapxstart -= finit_width;
+		while (mapxstart < 0)
+			mapxstart += finit_width;
+		while (mapystart >= finit_height)
+			mapystart -= finit_height;
+		while (mapystart < 0)
+			mapystart += finit_height;
+		*/
+		f_oldloc.x = plr->mo->x;
+		f_oldloc.y = plr->mo->y;
+	}
+}
+
+// Ripped out for Heretic
+/*
+static void AM_updateLightLev(void)
+{
+	static nexttic = 0;
+//	static int litelevels[] = { 0, 3, 5, 6, 6, 7, 7, 7 };
+	static int litelevels[] = { 0, 4, 7, 10, 12, 14, 15, 15 };
+	static int litelevelscnt = 0;
+
+	// Change light level
+	if (amclock > nexttic)
+	{
+		lightlev = litelevels[litelevelscnt++];
+		if (litelevelscnt == sizeof(litelevels)/sizeof(int))
+			litelevelscnt = 0;
+		nexttic = amclock + 6 - (amclock % 6);
+	}
+}
+*/
+
+void AM_Ticker (void)
+{
+	if (!automapactive)
+		return;
+
+	amclock++;
+
+	if (followplayer)
+		AM_doFollowPlayer();
+
+	// Change the zoom if necessary
+	if (ftom_zoommul != FRACUNIT)
+		AM_changeWindowScale();
+
+	// Change x,y location
+	if (m_paninc.x || m_paninc.y)
+		AM_changeWindowLoc();
+	// Update light level
+	/*
+	AM_updateLightLev();
+	*/
+}
+
+static void AM_clearFB(int color)
+{
+#ifdef RENDER3D
+	float scaler;
+	int lump;
+#else
+# if !AM_TRANSPARENT
+	int i, j;
+# endif
+#endif
+
+	if (followplayer)
+	{
+		int dmapx = (MTOF(plr->mo->x) - MTOF(oldplr.x));	//fixed point
+		int dmapy = (MTOF(oldplr.y) - MTOF(plr->mo->y));
+
+		oldplr.x = plr->mo->x;
+		oldplr.y = plr->mo->y;
+	//	if (f_oldloc.x == H2MAXINT)	//to eliminate an error when the user first
+	//		dmapx = 0;				//goes into the automap.
+		mapxstart += dmapx>>1;
+		mapystart += dmapy>>1;
+
+	  	while (mapxstart >= finit_width)
+			mapxstart -= finit_width;
+		while (mapxstart < 0)
+			mapxstart += finit_width;
+		while (mapystart >= finit_height)
+			mapystart -= finit_height;
+		while (mapystart < 0)
+			mapystart += finit_height;
+	}
+	else
+	{
+		mapxstart += (MTOF(m_paninc.x)>>1);
+		mapystart -= (MTOF(m_paninc.y)>>1);
+		if (mapxstart >= finit_width)
+			mapxstart -= finit_width;
+		if (mapxstart < 0)
+			mapxstart += finit_width;
+		if (mapystart >= finit_height)
+			mapystart -= finit_height;
+		if (mapystart < 0)
+			mapystart += finit_height;
+	}
+
+#ifdef RENDER3D
+	OGL_SetColorAndAlpha(1, 1, 1, 1);
+	OGL_SetFlat(W_GetNumForName("F_022")-firstflat);
+	scaler = sbarscale/20.0;
+	OGL_DrawCutRectTiled(0, finit_height+4, 320, 200-finit_height-4, 64, 64,
+				160-160*scaler+1, finit_height, 320*scaler-2, 200-finit_height);
+
+	lump = W_GetNumForName("bordb");
+	OGL_SetPatch(lump);
+	OGL_DrawCutRectTiled(0, finit_height, 320, 4,
+				lumptexsizes[lump].w, lumptexsizes[lump].h,
+				160-160*scaler+1, finit_height, 320*scaler-2, 4);
+# if !AM_TRANSPARENT
+	OGL_SetRawImage(maplumpnum, 0);	// We only want the left portion.
+	OGL_DrawRectTiled(0, 0, finit_width,
+				/*(sbarscale<20)?200:*/ finit_height, 128, 128);
+# endif
+
+#else	/* RENDER3D */
+
+# if !AM_TRANSPARENT
+	// blit the automap background to the screen.
+	j = mapystart*finit_width;
+	for (i = 0; i < SCREENHEIGHT-SBARHEIGHT; i++)
+	{
+		memcpy(screen + i*finit_width, maplump + j + mapxstart, finit_width - mapxstart);
+		memcpy(screen + i*finit_width + finit_width - mapxstart, maplump + j, mapxstart);
+		j += finit_width;
+		if (j >= finit_height*finit_width)
+			j = 0;
+	}
+# endif
+#endif	/* !RENDER3D */
+}
+
+
+#ifndef RENDER3D
+/* Wu antialiased line drawer.
+ * (X0,Y0),(X1,Y1) = line to draw
+ * BaseColor = color # of first color in block used for antialiasing, the
+ *          100% intensity version of the drawing color
+ * NumLevels = size of color block, with BaseColor+NumLevels-1 being the
+ *          0% intensity version of the drawing color
+ * IntensityBits = log base 2 of NumLevels; the # of bits used to describe
+ *          the intensity of the drawing color. 2**IntensityBits==NumLevels
+ */
+static void PUTDOT(short xx,short yy,byte *cc, byte *cm)
+{
+	static int oldyy;
+	static int oldyyshifted;
+	byte *oldcc = cc;
+
+	if (xx < 32)
+		cc += 7-(xx>>2);
+	else if (xx > (finit_width - 32))
+		cc += 7-((finit_width-xx) >> 2);
+//	if (cc == oldcc) //make sure that we don't double fade the corners.
+//	{
+		if (yy < 32)
+			cc += 7-(yy>>2);
+		else if (yy > (finit_height - 32))
+			cc += 7-((finit_height-yy) >> 2);
+//	}
+	if (cc > cm && cm != NULL)
+	{
+		cc = cm;
+	}
+	else if (cc > oldcc+6) // don't let the color escape from the fade table...
+	{
+		cc = oldcc+6;
+	}
+	if (yy == oldyy+1)
+	{
+		oldyy++;
+		oldyyshifted += 320;
+	}
+	else if (yy == oldyy-1)
+	{
+		oldyy--;
+		oldyyshifted -= 320;
+	}
+	else if (yy != oldyy)
+	{
+		oldyy = yy;
+		oldyyshifted = yy*320;
+	}
+	fb[oldyyshifted+xx] = *(cc);
+// 	fb[(yy)*f_w+(xx)]=*(cc);
+}
+
+static void DrawWuLine (int X0, int Y0, int X1, int Y1, byte *BaseColor,
+			int NumLevels, unsigned short IntensityBits)
+{
+	unsigned short IntensityShift, ErrorAdj, ErrorAcc;
+	unsigned short ErrorAccTemp, Weighting, WeightingComplementMask;
+	short DeltaX, DeltaY, Temp, XDir;
+
+	/* Make sure the line runs top to bottom */
+	if (Y0 > Y1)
+	{
+		Temp = Y0; Y0 = Y1; Y1 = Temp;
+		Temp = X0; X0 = X1; X1 = Temp;
+	}
+	/* Draw the initial pixel, which is always exactly intersected by
+	   the line and so needs no weighting */
+	PUTDOT(X0, Y0, &BaseColor[0], NULL);
+
+	if ((DeltaX = X1 - X0) >= 0)
+	{
+		XDir = 1;
+	}
+	else
+	{
+		XDir = -1;
+		DeltaX = -DeltaX; /* make DeltaX positive */
+	}
+	/* Special-case horizontal, vertical, and diagonal lines, which
+	   require no weighting because they go right through the center of
+	   every pixel */
+	if ((DeltaY = Y1 - Y0) == 0)
+	{
+		/* Horizontal line */
+		while (DeltaX-- != 0)
+		{
+			X0 += XDir;
+			PUTDOT(X0, Y0, &BaseColor[0], NULL);
+		}
+		return;
+	}
+	if (DeltaX == 0)
+	{
+		/* Vertical line */
+		do
+		{
+			Y0++;
+			PUTDOT(X0, Y0, &BaseColor[0], NULL);
+		} while (--DeltaY != 0);
+		return;
+	}
+	//diagonal line.
+	if (DeltaX == DeltaY)
+	{
+		do
+		{
+			X0 += XDir;
+			Y0++;
+			PUTDOT(X0, Y0, &BaseColor[0], NULL);
+		} while (--DeltaY != 0);
+		return;
+	}
+	/* Line is not horizontal, diagonal, or vertical */
+	ErrorAcc = 0;  /* initialize the line error accumulator to 0 */
+	/* # of bits by which to shift ErrorAcc to get intensity level */
+	IntensityShift = 16 - IntensityBits;
+	/* Mask used to flip all bits in an intensity weighting, producing the
+	   result (1 - intensity weighting) */
+	WeightingComplementMask = NumLevels - 1;
+	/* Is this an X-major or Y-major line? */
+	if (DeltaY > DeltaX)
+	{
+		/* Y-major line; calculate 16-bit fixed-point fractional part of a
+		   pixel that X advances each time Y advances 1 pixel, truncating the
+		   result so that we won't overrun the endpoint along the X axis */
+		ErrorAdj = ((unsigned long) DeltaX << 16) / (unsigned long) DeltaY;
+		/* Draw all pixels other than the first and last */
+		while (--DeltaY)
+		{
+			ErrorAccTemp = ErrorAcc;   /* remember currrent accumulated error */
+			ErrorAcc += ErrorAdj;      /* calculate error for next pixel */
+			if (ErrorAcc <= ErrorAccTemp)
+			{
+				/* The error accumulator turned over, so advance the X coord */
+				X0 += XDir;
+			}
+			Y0++; /* Y-major, so always advance Y */
+			/* The IntensityBits most significant bits of ErrorAcc give us the
+			   intensity weighting for this pixel, and the complement of the
+			   weighting for the paired pixel */
+			Weighting = ErrorAcc >> IntensityShift;
+			PUTDOT(X0, Y0, &BaseColor[Weighting], &BaseColor[7]);
+			PUTDOT(X0 + XDir, Y0,
+				&BaseColor[(Weighting ^ WeightingComplementMask)], &BaseColor[7]);
+		}
+		/* Draw the final pixel, which is always exactly intersected by the line
+		   and so needs no weighting */
+		PUTDOT(X1, Y1, &BaseColor[0], NULL);
+		return;
+	}
+	/* It's an X-major line; calculate 16-bit fixed-point fractional part of a
+	   pixel that Y advances each time X advances 1 pixel, truncating the
+	   result to avoid overrunning the endpoint along the X axis */
+	ErrorAdj = ((unsigned long) DeltaY << 16) / (unsigned long) DeltaX;
+	/* Draw all pixels other than the first and last */
+	while (--DeltaX)
+	{
+		ErrorAccTemp = ErrorAcc;   /* remember currrent accumulated error */
+		ErrorAcc += ErrorAdj;      /* calculate error for next pixel */
+		if (ErrorAcc <= ErrorAccTemp)
+		{
+			/* The error accumulator turned over, so advance the Y coord */
+			Y0++;
+		}
+		X0 += XDir; /* X-major, so always advance X */
+		/* The IntensityBits most significant bits of ErrorAcc give us the
+		   intensity weighting for this pixel, and the complement of the
+		   weighting for the paired pixel */
+		Weighting = ErrorAcc >> IntensityShift;
+		PUTDOT(X0, Y0, &BaseColor[Weighting], &BaseColor[7]);
+		PUTDOT(X0, Y0 + 1,
+			&BaseColor[(Weighting ^ WeightingComplementMask)], &BaseColor[7]);
+	}
+	/* Draw the final pixel, which is always exactly intersected by the line
+	   and so needs no weighting */
+	PUTDOT(X1, Y1, &BaseColor[0], NULL);
+}
+
+// Based on Cohen-Sutherland clipping algorithm but with a slightly
+// faster reject and precalculated slopes.  If I need the speed, will
+// hash algorithm to the common cases.
+
+static boolean AM_clipMline(mline_t *ml, fline_t *fl)
+{
+	enum { LEFT = 1, RIGHT = 2, BOTTOM = 4, TOP = 8 };
+	register int outcode1 = 0, outcode2 = 0, outside;
+	fpoint_t tmp;
+	int dx, dy;
+
+#define DOOUTCODE(oc, mx, my)			\
+	(oc) = 0;				\
+	if ((my) < 0) (oc) |= TOP;		\
+	else if ((my) >= f_h) (oc) |= BOTTOM;	\
+	if ((mx) < 0) (oc) |= LEFT;		\
+	else if ((mx) >= f_w) (oc) |= RIGHT
+
+	// do trivial rejects and outcodes
+	if (ml->a.y > m_y2)
+		outcode1 = TOP;
+	else if (ml->a.y < m_y)
+		outcode1 = BOTTOM;
+	if (ml->b.y > m_y2)
+		outcode2 = TOP;
+	else if (ml->b.y < m_y)
+		outcode2 = BOTTOM;
+	if (outcode1 & outcode2)
+		return false; // trivially outside
+
+	if (ml->a.x < m_x)
+		outcode1 |= LEFT;
+	else if (ml->a.x > m_x2)
+		outcode1 |= RIGHT;
+	if (ml->b.x < m_x)
+		outcode2 |= LEFT;
+	else if (ml->b.x > m_x2)
+		outcode2 |= RIGHT;
+	if (outcode1 & outcode2)
+		return false; // trivially outside
+
+	// transform to frame-buffer coordinates.
+	fl->a.x = CXMTOF(ml->a.x);
+	fl->a.y = CYMTOF(ml->a.y);
+	fl->b.x = CXMTOF(ml->b.x);
+	fl->b.y = CYMTOF(ml->b.y);
+	DOOUTCODE(outcode1, fl->a.x, fl->a.y);
+	DOOUTCODE(outcode2, fl->b.x, fl->b.y);
+	if (outcode1 & outcode2)
+		return false;
+
+	while (outcode1 | outcode2)
+	{
+		// may be partially inside box
+		// find an outside point
+		if (outcode1)
+			outside = outcode1;
+		else
+			outside = outcode2;
+		// clip to each side
+		if (outside & TOP)
+		{
+			dy = fl->a.y - fl->b.y;
+			dx = fl->b.x - fl->a.x;
+			tmp.x = fl->a.x + (dx*(fl->a.y))/dy;
+			tmp.y = 0;
+		}
+		else if (outside & BOTTOM)
+		{
+			dy = fl->a.y - fl->b.y;
+			dx = fl->b.x - fl->a.x;
+			tmp.x = fl->a.x + (dx*(fl->a.y-f_h))/dy;
+			tmp.y = f_h-1;
+		}
+		else if (outside & RIGHT)
+		{
+			dy = fl->b.y - fl->a.y;
+			dx = fl->b.x - fl->a.x;
+			tmp.y = fl->a.y + (dy*(f_w-1 - fl->a.x))/dx;
+			tmp.x = f_w-1;
+		}
+		else if (outside & LEFT)
+		{
+			dy = fl->b.y - fl->a.y;
+			dx = fl->b.x - fl->a.x;
+			tmp.y = fl->a.y + (dy*(-fl->a.x))/dx;
+			tmp.x = 0;
+		}
+		else /* avoid compiler warning */
+		{
+			tmp.x = 0;
+			tmp.y = 0;
+		}
+		if (outside == outcode1)
+		{
+			fl->a = tmp;
+			DOOUTCODE(outcode1, fl->a.x, fl->a.y);
+		}
+		else
+		{
+			fl->b = tmp;
+			DOOUTCODE(outcode2, fl->b.x, fl->b.y);
+		}
+		if (outcode1 & outcode2)
+			return false; // trivially outside
+	}
+
+	return true;
+}
+#undef DOOUTCODE
+
+// Classic Bresenham w/ whatever optimizations I need for speed
+
+static void AM_drawFline(fline_t *fl, int color)
+{
+	register int x, y, dx, dy, sx, sy, ax, ay, d;
+//	static int fuck = 0;
+
+	switch (color)
+	{
+	case WALLCOLORS:
+		DrawWuLine(fl->a.x, fl->a.y, fl->b.x, fl->b.y,
+				&antialias[0][0], 8, 3);
+		break;
+	case FDWALLCOLORS:
+		DrawWuLine(fl->a.x, fl->a.y, fl->b.x, fl->b.y,
+				&antialias[1][0], 8, 3);
+		break;
+	case CDWALLCOLORS:
+		DrawWuLine(fl->a.x, fl->a.y, fl->b.x, fl->b.y,
+				&antialias[2][0], 8, 3);
+		break;
+	default:
+		// For debugging only
+		if (fl->a.x < 0 || fl->a.x >= f_w
+			|| fl->a.y < 0 || fl->a.y >= f_h
+			|| fl->b.x < 0 || fl->b.x >= f_w
+			|| fl->b.y < 0 || fl->b.y >= f_h)
+		{
+		//	fprintf(stderr, "fuck %d \r", fuck++);
+			return;
+		}
+
+		#define DOT(xx,yy,cc) fb[(yy)*f_w+(xx)]=(cc) //the MACRO!
+
+		dx = fl->b.x - fl->a.x;
+		ax = 2 * (dx<0 ? -dx : dx);
+		sx = dx<0 ? -1 : 1;
+
+		dy = fl->b.y - fl->a.y;
+		ay = 2 * (dy < 0 ? -dy : dy);
+		sy = dy < 0 ? -1 : 1;
+
+		x = fl->a.x;
+		y = fl->a.y;
+
+		if (ax > ay)
+		{
+			d = ay - ax/2;
+			while (1)
+			{
+				DOT(x, y, color);
+				if (x == fl->b.x)
+					return;
+				if (d >= 0)
+				{
+					y += sy;
+					d -= ax;
+				}
+				x += sx;
+				d += ay;
+			}
+		}
+		else
+		{
+			d = ax - ay/2;
+			while (1)
+			{
+				DOT(x, y, color);
+				if (y == fl->b.y)
+					return;
+				if (d >= 0)
+				{
+					x += sx;
+					d -= ay;
+				}
+				y += sy;
+				d += ax;
+			}
+		}
+	}
+}
+
+static void AM_drawMline(mline_t *ml, int color)
+{
+	static fline_t fl;
+
+	if (AM_clipMline(ml, &fl))
+		AM_drawFline(&fl, color); // draws it on frame buffer using fb coords
+}
+#endif	/* ! RENDER3D */
+
+#ifdef RENDER3D
+static void AM_drawMline(mline_t *ml, int color)
+{
+	/* bbm: disabled this. doing it more directly below.
+	byte	*palette = (byte *) W_CacheLumpName("PLAYPAL", PU_CACHE);
+	byte	r = palette[color*3],
+		g = palette[color*3 + 1],
+		b = palette[color*3 + 2];
+
+	OGL_DrawLine(FIX2FLT(CXMTOFX(ml->a.x)), FIX2FLT(CYMTOFX(ml->a.y))/1.2,
+		     FIX2FLT(CXMTOFX(ml->b.x)), FIX2FLT(CYMTOFX(ml->b.y))/1.2,
+		     r/255.0, g/255.0, b/255.0, 1);
+	*/
+	OGL_SetColor(color);
+	// Draw the line. 1.2 is the to-square aspect corrector.
+	glVertex2f(FIX2FLT(CXMTOFX(ml->a.x)), FIX2FLT(CYMTOFX(ml->a.y))/1.2);
+	glVertex2f(FIX2FLT(CXMTOFX(ml->b.x)), FIX2FLT(CYMTOFX(ml->b.y))/1.2);
+}
+#endif	/* RENDER3D */
+
+static void AM_drawGrid(int color)
+{
+	fixed_t x, y;
+	fixed_t start, end;
+	mline_t ml;
+
+	// Figure out start of vertical gridlines
+	start = m_x;
+	if ((start-bmaporgx) % (MAPBLOCKUNITS<<FRACBITS))
+		start += (MAPBLOCKUNITS<<FRACBITS) - ((start-bmaporgx)%(MAPBLOCKUNITS<<FRACBITS));
+	end = m_x + m_w;
+
+	// draw vertical gridlines
+	ml.a.y = m_y;
+	ml.b.y = m_y+m_h;
+	for (x = start; x < end; x += (MAPBLOCKUNITS<<FRACBITS))
+	{
+		ml.a.x = x;
+		ml.b.x = x;
+		AM_drawMline(&ml, color);
+	}
+
+	// Figure out start of horizontal gridlines
+	start = m_y;
+	if ((start-bmaporgy) % (MAPBLOCKUNITS<<FRACBITS))
+		start += (MAPBLOCKUNITS<<FRACBITS) - ((start-bmaporgy)%(MAPBLOCKUNITS<<FRACBITS));
+	end = m_y + m_h;
+
+	// draw horizontal gridlines
+	ml.a.x = m_x;
+	ml.b.x = m_x + m_w;
+	for (y = start; y < end; y += (MAPBLOCKUNITS<<FRACBITS))
+	{
+		ml.a.y = y;
+		ml.b.y = y;
+		AM_drawMline(&ml, color);
+	}
+}
+
+static void AM_drawWalls(void)
+{
+	int i;
+
+#ifdef RENDER3D
+	/* bbm: disabled this to draw all lines at once, see AM_Drawer()
+	glDisable(GL_TEXTURE_2D);
+	glLineWidth(2.5);
+	glBegin(GL_LINES);	// We'll draw pretty much all of them.
+	*/
+	for (i = 0; i < numlines; i++)
+	{
+		if (cheating || (lines[i].flags & ML_MAPPED))
+		{
+			if ((lines[i].flags & LINE_NEVERSEE) && !cheating)
+				continue;
+			if (!lines[i].backsector)
+			{
+				OGL_SetColor(WALLCOLORS);
+			}
+			else
+			{
+				if (lines[i].flags & ML_SECRET) // secret door
+				{
+					if (cheating) //AM_drawMline(&l, 0);
+						OGL_SetColor(0);
+					else
+						OGL_SetColor(WALLCOLORS);
+				}
+				else if (lines[i].special == 13 || lines[i].special == 83)
+				{ // Locked door line -- all locked doors are greed
+					OGL_SetColor(GREENKEY);
+				}
+				else if (lines[i].special == 70 || lines[i].special == 71)
+				{ // intra-level teleports are blue
+					OGL_SetColor(BLUEKEY);
+				}
+				else if (lines[i].special == 74 || lines[i].special == 75)
+				{ // inter-level teleport/game-winning exit -- both are red
+					OGL_SetColor(BLOODRED);
+				}
+				else if (lines[i].backsector->floorheight != lines[i].frontsector->floorheight)
+				{ // floor level change
+					OGL_SetColor(FDWALLCOLORS);
+				}
+				else if (lines[i].backsector->ceilingheight != lines[i].frontsector->ceilingheight)
+				{ // ceiling level change
+					OGL_SetColor(CDWALLCOLORS);
+				}
+				else if (cheating)
+				{
+					OGL_SetColor(TSWALLCOLORS);
+				}
+				else
+					continue;
+			}
+		}
+		else if (plr->powers[pw_allmap])
+		{
+			if (!(lines[i].flags & LINE_NEVERSEE))
+				OGL_SetColor(GRAYS+3);
+			else
+				continue;
+		}
+		else
+			continue;
+
+		// Draw the line. 1.2 is the to-square aspect corrector.
+		glVertex2f (FIX2FLT(CXMTOFX(lines[i].v1->x)),
+			    FIX2FLT(CYMTOFX(lines[i].v1->y))/1.2);
+		glVertex2f (FIX2FLT(CXMTOFX(lines[i].v2->x)),
+			    FIX2FLT(CYMTOFX(lines[i].v2->y))/1.2);
+	}
+	/* bbm .
+	glEnd();
+	glLineWidth(1.0);
+	glEnable(GL_TEXTURE_2D);
+	*/
+#else
+	static mline_t l;
+
+	for (i = 0; i < numlines; i++)
+	{
+		l.a.x = lines[i].v1->x;
+		l.a.y = lines[i].v1->y;
+		l.b.x = lines[i].v2->x;
+		l.b.y = lines[i].v2->y;
+		if (cheating || (lines[i].flags & ML_MAPPED))
+		{
+			if ((lines[i].flags & LINE_NEVERSEE) && !cheating)
+				continue;
+			if (!lines[i].backsector)
+			{
+				AM_drawMline(&l, WALLCOLORS+lightlev);
+			}
+			else
+			{
+				if (lines[i].flags & ML_SECRET) // secret door
+				{
+					if (cheating)
+						AM_drawMline(&l, 0);
+					else
+						AM_drawMline(&l, WALLCOLORS+lightlev);
+				}
+				else if (lines[i].special == 13 || lines[i].special == 83)
+				{ // Locked door line -- all locked doors are greed
+					AM_drawMline(&l, GREENKEY);
+				}
+				else if (lines[i].special == 70 || lines[i].special == 71)
+				{ // intra-level teleports are blue
+					AM_drawMline(&l, BLUEKEY);
+				}
+				else if (lines[i].special == 74 || lines[i].special == 75)
+				{ // inter-level teleport/game-winning exit -- both are red
+					AM_drawMline(&l, BLOODRED);
+				}
+				else if (lines[i].backsector->floorheight != lines[i].frontsector->floorheight)
+				{ // floor level change
+					AM_drawMline(&l, FDWALLCOLORS + lightlev);
+				}
+				else if (lines[i].backsector->ceilingheight != lines[i].frontsector->ceilingheight)
+				{ // ceiling level change
+					AM_drawMline(&l, CDWALLCOLORS+lightlev);
+				}
+				else if (cheating)
+				{
+					AM_drawMline(&l, TSWALLCOLORS+lightlev);
+				}
+			}
+		}
+		else if (plr->powers[pw_allmap])
+		{
+			if (!(lines[i].flags & LINE_NEVERSEE))
+				AM_drawMline(&l, GRAYS+3);
+		}
+	}
+#endif
+}
+
+static void AM_rotate(fixed_t *x, fixed_t *y, angle_t a)
+{
+	fixed_t tmpx;
+
+	tmpx = FixedMul(*x,finecosine[a>>ANGLETOFINESHIFT]) - FixedMul(*y,finesine[a>>ANGLETOFINESHIFT]);
+	*y   = FixedMul(*x,finesine[a>>ANGLETOFINESHIFT]) + FixedMul(*y,finecosine[a>>ANGLETOFINESHIFT]);
+	*x = tmpx;
+}
+
+static void AM_drawLineCharacter(mline_t *lineguy, int lineguylines, fixed_t scale,
+				 angle_t angle, int color, fixed_t x, fixed_t y)
+{
+	int i;
+	mline_t l;
+
+	for (i = 0; i < lineguylines; i++)
+	{
+		l.a.x = lineguy[i].a.x;
+		l.a.y = lineguy[i].a.y;
+		if (scale)
+		{
+			l.a.x = FixedMul(scale, l.a.x);
+			l.a.y = FixedMul(scale, l.a.y);
+		}
+		if (angle)
+			AM_rotate(&l.a.x, &l.a.y, angle);
+		l.a.x += x;
+		l.a.y += y;
+
+		l.b.x = lineguy[i].b.x;
+		l.b.y = lineguy[i].b.y;
+		if (scale)
+		{
+			l.b.x = FixedMul(scale, l.b.x);
+			l.b.y = FixedMul(scale, l.b.y);
+		}
+		if (angle)
+			AM_rotate(&l.b.x, &l.b.y, angle);
+		l.b.x += x;
+		l.b.y += y;
+
+		AM_drawMline(&l, color);
+	}
+}
+
+static void AM_drawPlayers(void)
+{
+	int i;
+	player_t *p;
+	static int their_colors[] =
+	{
+		AM_PLR1_COLOR,
+		AM_PLR2_COLOR,
+		AM_PLR3_COLOR,
+		AM_PLR4_COLOR,
+		AM_PLR5_COLOR,
+		AM_PLR6_COLOR,
+		AM_PLR7_COLOR,
+		AM_PLR8_COLOR
+	};
+	int their_color = -1;
+	int color;
+
+	if (!netgame)
+	{
+		AM_drawLineCharacter(player_arrow, NUMPLYRLINES, 0, plr->mo->angle,
+						AM_PLR5_COLOR, plr->mo->x, plr->mo->y);
+		// AM_PLR5_COLOR: Jade. Used to be WHITE, couldn't see it! - S.A.
+		return;
+	}
+
+	for (i = 0; i < MAXPLAYERS; i++)
+	{
+		their_color++;
+		p = &players[i];
+		if (deathmatch && !singledemo && p != plr)
+		{
+			continue;
+		}
+		if (!playeringame[i])
+			continue;
+		color = their_colors[their_color];
+		AM_drawLineCharacter(player_arrow, NUMPLYRLINES, 0, p->mo->angle,
+							color, p->mo->x, p->mo->y);
+	}
+}
+
+static void AM_drawThings(int colors, int colorrange)
+{
+	int i;
+	mobj_t *t;
+
+	for (i = 0; i < numsectors; i++)
+	{
+		t = sectors[i].thinglist;
+		while (t)
+		{
+			AM_drawLineCharacter(thintriangle_guy, NUMTHINTRIANGLEGUYLINES,
+				16<<FRACBITS, t->angle, colors+lightlev, t->x, t->y);
+			t = t->snext;
+		}
+	}
+}
+
+
+#ifdef RENDER3D
+static void AM_OGL_SetupState(void)
+{
+	float ys = screenHeight/200.0;
+
+	// Let's set up a scissor box to clip the map lines and stuff.
+	glPushAttrib(GL_SCISSOR_BIT);
+	glScissor(0, screenHeight-finit_height*ys, screenWidth, finit_height*ys);
+	glEnable(GL_SCISSOR_TEST);
+}
+
+static void AM_OGL_RestoreState(void)
+{
+	glPopAttrib();
+}
+#endif	/* RENDER3D */
+
+
+void AM_Drawer (void)
+{
+	if (!automapactive)
+		return;
+
+	UpdateState |= I_FULLSCRN;
+
+#ifdef RENDER3D
+	// Update the height (in case sbarscale has been changed).
+	finit_height = SCREENHEIGHT - SBARHEIGHT * sbarscale / 20;
+	AM_OGL_SetupState();
+#endif
+
+	AM_clearFB(BACKGROUND);
+
+#ifdef RENDER3D
+	/* bbm 3/9/2003: start drawing all lines at once */
+	glDisable(GL_TEXTURE_2D);
+	glLineWidth(1.0);
+	glBegin(GL_LINES);
+#endif
+
+	if (grid)
+		AM_drawGrid(GRIDCOLORS);
+	AM_drawWalls();
+	AM_drawPlayers();
+
+	if (cheating == 2)
+		AM_drawThings(THINGCOLORS, THINGRANGE);
+
+#ifdef RENDER3D
+	/* bbm: finish drawing all lines at once */
+	glEnd();
+	glLineWidth(1.0);
+	glEnable(GL_TEXTURE_2D);
+
+	AM_OGL_RestoreState();
+#endif
+
+	DrawWorldTimer();
+	MN_DrTextA(P_GetMapName(gamemap), 38, 144);
+	if (ShowKills && netgame && deathmatch)
+	{
+		AM_DrawDeathmatchStats();
+	}
+}
+
+//===========================================================================
+//
+// AM_DrawDeathmatchStats
+//
+//===========================================================================
+
+// 8-player note:  Proper player color names here, too
+
+static const char *PlayerColorText[MAXPLAYERS_11] =
+{
+	"BLUE:",
+	"RED:",
+	"YELLOW:",
+	"GREEN:",
+	"JADE:",
+	"WHITE:",
+	"HAZEL:",
+	"PURPLE:"
+};
+
+static void AM_DrawDeathmatchStats(void)
+{
+	int i, j, k, m;
+	int fragCount[MAXPLAYERS];
+	int order[MAXPLAYERS];
+	char textBuffer[80];
+	int yPosition;
+
+	for (i = 0; i < MAXPLAYERS; i++)
+	{
+		fragCount[i] = 0;
+		order[i] = -1;
+	}
+	for (i = 0; i < MAXPLAYERS; i++)
+	{
+		if (!playeringame[i])
+		{
+			continue;
+		}
+		else
+		{
+			for (j = 0; j < MAXPLAYERS; j++)
+			{
+				if (playeringame[j])
+				{
+					fragCount[i] += players[i].frags[j];
+				}
+			}
+			for (k = 0; k < MAXPLAYERS; k++)
+			{
+				if (order[k] == -1)
+				{
+					order[k] = i;
+					break;
+				}
+				else if (fragCount[i] > fragCount[order[k]])
+				{
+					for (m = MAXPLAYERS-1; m > k; m--)
+					{
+						order[m] = order[m-1];
+					}
+					order[k] = i;
+					break;
+				}
+			}
+		}
+	}
+	yPosition = 15;
+	for (i = 0; i < MAXPLAYERS; i++)
+	{
+		if (!playeringame[order[i]])
+		{
+			continue;
+		}
+		else
+		{
+			MN_DrTextA(PlayerColorText[order[i]], 8, yPosition);
+			snprintf(textBuffer, sizeof(textBuffer), "%d", fragCount[order[i]]);
+			MN_DrTextA(textBuffer, 80, yPosition);
+			yPosition += 10;
+		}
+	}
+}
+
+//===========================================================================
+//
+// DrawWorldTimer
+//
+//===========================================================================
+
+static void DrawWorldTimer(void)
+{
+	int days;
+	int hours;
+	int minutes;
+	int seconds;
+	int worldTimer;
+	char timeBuffer[15];
+	char dayBuffer[20];
+
+	worldTimer = players[consoleplayer].worldTimer;
+
+	worldTimer /= 35;
+	days = worldTimer/86400;
+	worldTimer -= days*86400;
+	hours = worldTimer/3600;
+	worldTimer -= hours*3600;
+	minutes = worldTimer/60;
+	worldTimer -= minutes*60;
+	seconds = worldTimer;
+
+	snprintf(timeBuffer, sizeof(timeBuffer), "%.2d : %.2d : %.2d", hours, minutes,seconds);
+	MN_DrTextA(timeBuffer, 240, 8);
+
+	if (days)
+	{
+		if (days == 1)
+		{
+			snprintf(dayBuffer, sizeof(dayBuffer), "%.2d DAY", days);
+		}
+		else
+		{
+			snprintf(dayBuffer, sizeof(dayBuffer), "%.2d DAYS", days);
+		}
+		MN_DrTextA(dayBuffer, 240, 20);
+		if (days >= 5)
+		{
+			MN_DrTextA("YOU FREAK!!!", 230, 35);
+		}
+	}
+}
+
--- /dev/null
+++ b/am_map.h
@@ -1,0 +1,131 @@
+
+//**************************************************************************
+//**
+//** am_map.h : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 440 $
+//** $Date: 2009-05-24 00:08:25 +0300 (Sun, 24 May 2009) $
+//**
+//**************************************************************************
+
+#ifndef __AMMAP_H__
+#define __AMMAP_H__
+
+/* For use if I do walls with outsides/insides */
+#define REDS		(12 * 8)
+#define REDRANGE	1 /* 16 */
+#define BLUES		(256 - 4*16 + 8)
+#define BLUERANGE	1 /* 8 */
+#define GREENS		(33 * 8)
+#define GREENRANGE	1 /* 16 */
+#define GRAYS		(5 * 8)
+#define GRAYSRANGE	1 /* 16 */
+#define BROWNS		(14 * 8)
+#define BROWNRANGE	1 /* 16 */
+#define YELLOWS		(10 * 8)
+#define YELLOWRANGE	1
+#define BLACK		0
+#define WHITE		(4 * 8)
+#define PARCH		(13*8 - 1)
+#define BLOODRED	177
+#define BLUEKEY		157
+#define YELLOWKEY	137
+#define GREENKEY	198
+
+/* Automap colors */
+#define AM_PLR1_COLOR	157	/* Blue */
+#define AM_PLR2_COLOR	177	/* Red */
+#define AM_PLR3_COLOR	137	/* Yellow */
+#define AM_PLR4_COLOR	198	/* Green */
+#define AM_PLR5_COLOR	215	/* Jade */
+#define AM_PLR6_COLOR	32	/* White */
+#define AM_PLR7_COLOR	106	/* Hazel */
+#define AM_PLR8_COLOR	234	/* Purple */
+
+#define BACKGROUND	PARCH
+#define YOURCOLORS	WHITE
+#define YOURRANGE	0
+#define WALLCOLORS	REDS
+#define WALLRANGE	REDRANGE
+#define TSWALLCOLORS	GRAYS
+#define TSWALLRANGE	GRAYSRANGE
+#define FDWALLCOLORS	BROWNS
+#define FDWALLRANGE	BROWNRANGE
+#define CDWALLCOLORS	YELLOWS
+#define CDWALLRANGE	YELLOWRANGE
+#define THINGCOLORS	GREENS
+#define THINGRANGE	GREENRANGE
+#define SECRETWALLCOLORS WALLCOLORS
+#define SECRETWALLRANGE	WALLRANGE
+#define GRIDCOLORS	(GRAYS + GRAYSRANGE/2)
+#define GRIDRANGE	0
+#define XHAIRCOLORS	GRAYS
+
+/* drawing stuff */
+#define	FB		0
+
+#define AM_PANDOWNKEY	KEY_DOWNARROW
+#define AM_PANUPKEY	KEY_UPARROW
+#define AM_PANRIGHTKEY	KEY_RIGHTARROW
+#define AM_PANLEFTKEY	KEY_LEFTARROW
+
+#define AM_ZOOMINKEY	'='
+#define AM_ZOOMOUTKEY	'-'
+#define AM_STARTKEY	KEY_TAB
+#define AM_ENDKEY	KEY_TAB
+#define AM_GOBIGKEY	'0'
+#define AM_FOLLOWKEY	'f'
+#define AM_GRIDKEY	'g'
+
+#define AM_NUMMARKPOINTS	10
+
+#define AM_MSGHEADER	(('a'<<24) + ('m'<<16))
+#define AM_MSGENTERED	(AM_MSGHEADER | ('e'<<8))
+#define AM_MSGEXITED	(AM_MSGHEADER | ('x'<<8))
+
+#define INITSCALEMTOF	(.2*FRACUNIT)	/* scale on entry */
+
+/* how much the automap moves window per tic in frame-buffer coordinates */
+#define F_PANINC	4	/* moves 140 pixels in 1 second */
+
+/* how much zoom-in per tic */
+#define M_ZOOMIN	((int) (1.02*FRACUNIT))	/* goes to 2x in 1 second */
+
+/* how much zoom-out per tic */
+#define M_ZOOMOUT	((int) (FRACUNIT/1.02))	/* pulls out to 0.5x in 1 second */
+
+/* translates between frame-buffer and map distances */
+#define FTOM(x)		FixedMul(((x)<<16),scale_ftom)
+#define MTOF(x)		(FixedMul((x),scale_mtof)>>16)
+
+/* translates between frame-buffer and map coordinates */
+#define CXMTOF(x)	(f_x + MTOF((x)-m_x))
+#define CYMTOF(y)	(f_y + (f_h - MTOF((y)-m_y)))
+
+/* the following is crap */
+#define LINE_NEVERSEE	ML_DONTDRAW
+
+typedef struct
+{
+	int		x, y;
+} fpoint_t;
+
+typedef struct
+{
+	fpoint_t	a, b;
+} fline_t;
+
+typedef vertex_t	mpoint_t;
+
+typedef struct
+{
+	mpoint_t	a, b;
+} mline_t;
+
+typedef struct
+{
+	fixed_t		slp, islp;
+} islope_t;
+
+#endif	/* __AMMAP_H__ */
+
--- /dev/null
+++ b/audio_plugin.h
@@ -1,0 +1,63 @@
+/*  XMMS - Cross-platform multimedia player
+ *  Copyright (C) 1998-1999  Peter Alm, Mikael Alm, Olle Hallnas, Thomas Nilsson and 4Front Technologies
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef AUDIO_PLUGIN_H
+#define AUDIO_PLUGIN_H
+
+
+typedef enum
+{
+	FMT_U8, FMT_S8, FMT_U16_LE, FMT_U16_BE, FMT_U16_NE, FMT_S16_LE, FMT_S16_BE, FMT_S16_NE
+}
+AFormat;
+
+typedef struct
+{
+	void *handle;			/* Filled in by xmms */
+	char *filename;			/* Filled in by xmms */
+	const char *description;	/* The description that is shown in the preferences box */
+	void (*init) (void);
+	void (*about) (void);		/* Show the about box */
+	void (*configure) (void);	/* Show the configuration dialog */
+	void (*get_volume) (int *l, int *r);
+	void (*set_volume) (int l, int r);	/* Set the volume */
+
+	int (*open_audio) (AFormat fmt, int rate, int nch);
+					/* Open the device, if the device can't handle the given 
+					   parameters the plugin is responsible for downmixing
+					   the data to the right format before outputting it */
+
+	void (*write_audio) (void *ptr, int length);
+					/* The input plugin calls this to write data to the output buffer */
+
+	void (*close_audio) (void);	/* No comment... */
+	void (*flush) (int flushtime);	/* Flush the buffer and set the plugins internal timers to time */
+	void (*pause) (short paused);	/* Pause or unpause the output */
+	int (*buffer_free) (void);	/* Return the amount of data that can be written to the buffer,
+					   two calls to this without a call to write_audio should make
+					   the plugin output audio directly */
+	int (*buffer_playing) (void);	/* Returns TRUE if the plugin currently is playing some audio,
+					   otherwise return FALSE */
+	int (*output_time) (void);	/* Return the current playing time */
+	int (*written_time) (void);	/* Return the length of all the data that has been written to
+					   the buffer */
+}
+OutputPlugin;
+
+#endif	/* AUDIO_PLUGIN_H */
+
--- /dev/null
+++ b/ct_chat.c
@@ -1,0 +1,515 @@
+
+//**************************************************************************
+//**
+//** ct_chat.c : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 529 $
+//** $Date: 2009-06-10 16:27:26 +0300 (Wed, 10 Jun 2009) $
+//**
+//**************************************************************************
+
+#include "h2stdinc.h"
+#include <ctype.h>
+#include "h2def.h"
+#include "p_local.h"
+#include "soundst.h"
+#ifdef RENDER3D
+#include "ogl_def.h"
+#endif
+
+#define QUEUESIZE		128
+#define MESSAGESIZE		128
+#define MESSAGELEN		265
+
+// 8-player note:  Change this stuff (CT_PLR_*, and the key mappings)
+enum
+{
+	CT_PLR_BLUE	= 1,
+	CT_PLR_RED,
+	CT_PLR_YELLOW,
+	CT_PLR_GREEN,
+#if (MAXPLAYERS >= MAXPLAYERS_11)
+	CT_PLR_PLAYER5,
+	CT_PLR_PLAYER6,
+	CT_PLR_PLAYER7,
+	CT_PLR_PLAYER8,
+#endif
+	CT_PLR_ALL
+};
+
+#define CT_KEY_BLUE		'b'
+#define CT_KEY_RED		'r'
+#define CT_KEY_YELLOW		'y'
+#define CT_KEY_GREEN		'g'
+#define CT_KEY_PLAYER5		'j'	/* Jade */
+#define CT_KEY_PLAYER6		'w'	/* White */
+#define CT_KEY_PLAYER7		'h'	/* Hazel */
+#define CT_KEY_PLAYER8		'p'	/* Purple */
+#define CT_KEY_ALL		't'
+#define CT_ESCAPE		6
+
+// Public data
+
+void CT_Init(void);
+void CT_Drawer(void);
+boolean CT_Responder(event_t *ev);
+void CT_Ticker(void);
+char CT_dequeueChatChar(void);
+
+boolean chatmodeon;
+
+char chat_macros[10][80] =
+{
+	HUSTR_CHATMACRO0,
+	HUSTR_CHATMACRO1,
+	HUSTR_CHATMACRO2,
+	HUSTR_CHATMACRO3,
+	HUSTR_CHATMACRO4,
+	HUSTR_CHATMACRO5,
+	HUSTR_CHATMACRO6,
+	HUSTR_CHATMACRO7,
+	HUSTR_CHATMACRO8,
+	HUSTR_CHATMACRO9
+};
+
+// Private data
+
+static void CT_queueChatChar(char ch);
+static void CT_ClearChatMessage(int player);
+static void CT_AddChar(int player, char c);
+static void CT_BackSpace(int player);
+
+static int head, tail;
+static byte ChatQueue[QUEUESIZE];
+static int chat_dest[MAXPLAYERS];
+static char chat_msg[MAXPLAYERS][MESSAGESIZE];
+static char plr_lastmsg[MAXPLAYERS][MESSAGESIZE+9];
+static int msgptr[MAXPLAYERS];
+static int msglen[MAXPLAYERS];
+
+static int FontABaseLump;
+
+static const char *CT_FromPlrText[MAXPLAYERS_11] =
+{
+	"BLUE:  ",
+	"RED:  ",
+	"YELLOW:  ",
+	"GREEN:  ",
+	"JADE:  ",
+	"WHITE:  ",
+	"HAZEL:  ",
+	"PURPLE:  "
+};
+
+static boolean altdown, shiftdown;
+
+extern boolean usearti;
+
+
+//===========================================================================
+//
+// CT_Init
+//
+// 	Initialize chat mode data
+//===========================================================================
+
+void CT_Init(void)
+{
+	int i;
+
+	head = 0; //initialize the queue index
+	tail = 0;
+	chatmodeon = false;
+	memset(ChatQueue, 0, QUEUESIZE);
+	for (i = 0; i < MAXPLAYERS; i++)
+	{
+		chat_dest[i] = 0;
+		msgptr[i] = 0;
+		memset(plr_lastmsg[i], 0, MESSAGESIZE);
+		memset(chat_msg[i], 0, MESSAGESIZE);
+	}
+	FontABaseLump = W_GetNumForName("FONTA_S") + 1;
+	return;
+}
+
+//===========================================================================
+//
+// CT_Stop
+//
+//===========================================================================
+
+void CT_Stop(void)
+{
+	chatmodeon = false;
+	return;
+}
+
+//===========================================================================
+//
+// CT_Responder
+//
+//===========================================================================
+
+boolean CT_Responder(event_t *ev)
+{
+	const char *macro;
+	int sendtarget;
+
+	if (!netgame)
+	{
+		return false;
+	}
+	if (ev->data1 == KEY_RALT)
+	{
+		altdown = (ev->type == ev_keydown);
+		return false;
+	}
+	if (ev->data1 == KEY_RSHIFT)
+	{
+		shiftdown = (ev->type == ev_keydown);
+		return false;
+	}
+	if (gamestate != GS_LEVEL || ev->type != ev_keydown)
+	{
+		return false;
+	}
+	if (!chatmodeon)
+	{
+		sendtarget = 0;
+		if (ev->data1 == CT_KEY_ALL)
+		{
+			sendtarget = CT_PLR_ALL;
+		}
+		else if (ev->data1 == CT_KEY_GREEN)
+		{
+			sendtarget = CT_PLR_GREEN;
+		}
+		else if (ev->data1 == CT_KEY_YELLOW)
+		{
+			sendtarget = CT_PLR_YELLOW;
+		}
+		else if (ev->data1 == CT_KEY_RED)
+		{
+			sendtarget = CT_PLR_RED;
+		}
+		else if (ev->data1 == CT_KEY_BLUE)
+		{
+			sendtarget = CT_PLR_BLUE;
+		}
+#if (MAXPLAYERS == MAXPLAYERS_11)
+		else if (ev->data1 == CT_KEY_PLAYER5)
+		{
+			sendtarget = CT_PLR_PLAYER5;
+		}
+		else if (ev->data1 == CT_KEY_PLAYER6)
+		{
+			sendtarget = CT_PLR_PLAYER6;
+		}
+		else if (ev->data1 == CT_KEY_PLAYER7)
+		{
+			sendtarget = CT_PLR_PLAYER7;
+		}
+		else if (ev->data1 == CT_KEY_PLAYER8)
+		{
+			sendtarget = CT_PLR_PLAYER8;
+		}
+#endif	/* 8-players */
+		if (sendtarget == 0 || (sendtarget != CT_PLR_ALL && !playeringame[sendtarget - 1])
+			|| sendtarget == consoleplayer + 1)
+		{
+			return false;
+		}
+		CT_queueChatChar(sendtarget);
+		chatmodeon = true;
+		return true;
+	}
+	else
+	{
+		if (altdown)
+		{
+			if (ev->data1 >= '0' && ev->data1 <= '9')
+			{
+				if (ev->data1 == '0')
+				{ // macro 0 comes after macro 9
+					ev->data1 = '9' + 1;
+				}
+				macro = chat_macros[ev->data1-'1'];
+				CT_queueChatChar(KEY_ENTER); //send old message
+				CT_queueChatChar(chat_dest[consoleplayer]); // chose the dest.
+				while (*macro)
+				{
+					CT_queueChatChar(toupper(*macro++));
+				}
+				CT_queueChatChar(KEY_ENTER); //send it off...
+				CT_Stop();
+				return true;
+			}
+		}
+		if (ev->data1 == KEY_ENTER)
+		{
+			CT_queueChatChar(KEY_ENTER);
+			usearti = false;
+			CT_Stop();
+			return true;
+		}
+		else if (ev->data1 == KEY_ESCAPE)
+		{
+			CT_queueChatChar(CT_ESCAPE);
+			CT_Stop();
+			return true;
+		}
+		else if (ev->data1 >= 'a' && ev->data1 <= 'z')
+		{
+			CT_queueChatChar(ev->data1-32);
+			return true;
+		}
+		else if (shiftdown)
+		{
+			if (ev->data1 == '1')
+			{
+				CT_queueChatChar('!');
+				return true;
+			}
+			else if (ev->data1 == '/')
+			{
+				CT_queueChatChar('?');
+				return true;
+			}
+		}
+		if (ev->data1 == ' ' || ev->data1 == ',' || ev->data1 == '.' ||
+		    (ev->data1 >= '0' && ev->data1 <= '9') || ev->data1 == '\'' ||
+		    ev->data1 == KEY_BACKSPACE || ev->data1 == '-' || ev->data1 == '=')
+		{
+			CT_queueChatChar(ev->data1);
+			return true;
+		}
+	}
+	return false;
+}
+
+//===========================================================================
+//
+// CT_Ticker
+//
+//===========================================================================
+
+void CT_Ticker(void)
+{
+	int i, j;
+	char c;
+	int numplayers;
+
+	for (i = 0; i < MAXPLAYERS; i++)
+	{
+		if (!playeringame[i])
+		{
+			continue;
+		}
+		if ((c = players[i].cmd.chatchar) != 0)
+		{
+			if (c <= CT_PLR_ALL)
+			{
+				chat_dest[i] = c;
+				continue;
+			}
+			else if (c == CT_ESCAPE)
+			{
+				CT_ClearChatMessage(i);
+			}
+			else if (c == KEY_ENTER)
+			{
+				numplayers = 0;
+				for (j = 0; j < MAXPLAYERS; j++)
+				{
+					numplayers += playeringame[j];
+				}
+				CT_AddChar(i, 0); // set the end of message character
+				if (numplayers > 2)
+				{
+					strcpy(plr_lastmsg[i], CT_FromPlrText[i]);
+					strcat(plr_lastmsg[i], chat_msg[i]);
+				}
+				else
+				{
+					strcpy(plr_lastmsg[i], chat_msg[i]);
+				}
+				if (i != consoleplayer && (chat_dest[i] == consoleplayer + 1
+					|| chat_dest[i] == CT_PLR_ALL) && *chat_msg[i])
+				{
+					P_SetMessage(&players[consoleplayer], plr_lastmsg[i], true);
+					S_StartSound(NULL, SFX_CHAT);
+				}
+				else if (i == consoleplayer && (*chat_msg[i]))
+				{
+					if (numplayers <= 1)
+					{
+						P_SetMessage(&players[consoleplayer],
+							"THERE ARE NO OTHER PLAYERS IN THE GAME!", true);
+						S_StartSound(NULL, SFX_CHAT);
+					}
+				}
+				CT_ClearChatMessage(i);
+			}
+			else if (c == KEY_BACKSPACE)
+			{
+				CT_BackSpace(i);
+			}
+			else
+			{
+				CT_AddChar(i, c);
+			}
+		}
+	}
+	return;
+}
+
+//===========================================================================
+//
+// CT_Drawer
+//
+//===========================================================================
+
+void CT_Drawer(void)
+{
+	int i;
+	int x;
+	patch_t *patch;
+
+	if (chatmodeon)
+	{
+		x = 25;
+		for (i = 0; i < msgptr[consoleplayer]; i++)
+		{
+			if (chat_msg[consoleplayer][i] < 33)
+			{
+				x += 6;
+			}
+			else
+			{
+				patch = (patch_t *) W_CacheLumpNum(FontABaseLump + chat_msg[consoleplayer][i] - 33, PU_CACHE);
+#ifdef RENDER3D
+				OGL_DrawPatch_CS(x, 10, FontABaseLump + chat_msg[consoleplayer][i] - 33);
+#else
+				V_DrawPatch(x, 10, patch);
+#endif
+				x += SHORT(patch->width);
+			}
+		}
+#ifdef RENDER3D
+		OGL_DrawPatch_CS(x, 10, W_GetNumForName("FONTA59"));
+#else
+		patch = (patch_t *) W_CacheLumpName("FONTA59", PU_CACHE);
+		V_DrawPatch(x, 10, patch);
+#endif
+		BorderTopRefresh = true;
+		UpdateState |= I_MESSAGES;
+	}
+}
+
+//===========================================================================
+//
+// CT_queueChatChar
+//
+//===========================================================================
+
+static void CT_queueChatChar(char ch)
+{
+	if (((tail + 1) & (QUEUESIZE - 1)) == head)
+	{ // the queue is full
+		return;
+	}
+	ChatQueue[tail] = ch;
+	tail = (tail + 1) & (QUEUESIZE - 1);
+}
+
+//===========================================================================
+//
+// CT_dequeueChatChar
+//
+//===========================================================================
+
+char CT_dequeueChatChar(void)
+{
+	byte temp;
+
+	if (head == tail)
+	{ // queue is empty
+		return 0;
+	}
+	temp = ChatQueue[head];
+	head = (head + 1) & (QUEUESIZE - 1);
+	return temp;
+}
+
+//===========================================================================
+//
+// CT_AddChar
+//
+//===========================================================================
+
+static void CT_AddChar(int player, char c)
+{
+	patch_t *patch;
+
+	if (msgptr[player] + 1 >= MESSAGESIZE || msglen[player] >= MESSAGELEN)
+	{ // full.
+		return;
+	}
+	chat_msg[player][msgptr[player]] = c;
+	msgptr[player]++;
+	if (c < 33)
+	{
+		msglen[player] += 6;
+	}
+	else
+	{
+		patch = (patch_t *) W_CacheLumpNum(FontABaseLump + c - 33, PU_CACHE);
+		msglen[player] += SHORT(patch->width);
+	}
+}
+
+//===========================================================================
+//
+// CT_BackSpace
+//
+// 	Backs up a space, when the user hits (obviously) backspace
+//===========================================================================
+
+static void CT_BackSpace(int player)
+{
+	patch_t *patch;
+	char c;
+
+	if (msgptr[player] == 0)
+	{ // message is already blank
+		return;
+	}
+	msgptr[player]--;
+	c = chat_msg[player][msgptr[player]];
+	if (c < 33)
+	{
+		msglen[player] -= 6;
+	}
+	else
+	{
+		patch = (patch_t *) W_CacheLumpNum(FontABaseLump + c - 33, PU_CACHE);
+		msglen[player] -= SHORT(patch->width);
+	}
+	chat_msg[player][msgptr[player]] = 0;
+}
+
+//===========================================================================
+//
+// CT_ClearChatMessage
+//
+// 	Clears out the data for the chat message, but the player's message
+//		is still saved in plrmsg.
+//===========================================================================
+
+static void CT_ClearChatMessage(int player)
+{
+	memset(chat_msg[player], 0, MESSAGESIZE);
+	msgptr[player] = 0;
+	msglen[player] = 0;
+}
+
--- /dev/null
+++ b/d_net.c
@@ -1,0 +1,929 @@
+
+//**************************************************************************
+//**
+//** d_net.c : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 469 $
+//** $Date: 2009-05-26 13:45:39 +0300 (Tue, 26 May 2009) $
+//**
+//** This version has the fixed ticdup code.
+//**
+//**************************************************************************
+
+#include "h2stdinc.h"
+#include "h2def.h"
+#include "st_start.h"
+#include "p_local.h"
+
+#define NCMD_EXIT	0x80000000
+#define NCMD_RETRANSMIT	0x40000000
+#define NCMD_SETUP	0x20000000
+#define NCMD_KILL	0x10000000		/* kill game */
+#define NCMD_CHECKSUM	0x0fffffff
+
+
+doomcom_t		*doomcom;
+doomdata_t		*netbuffer;		/* points inside doomcom */
+
+
+/*
+==============================================================================
+
+							NETWORKING
+
+gametic is the tic about to (or currently being) run
+maketic is the tick that hasn't had control made for it yet
+nettics[] has the maketics for all players
+
+a gametic cannot be run until nettics[] > gametic for all players
+
+==============================================================================
+*/
+
+#define RESENDCOUNT	10
+#define PL_DRONE	0x80			/* bit flag in doomdata->player */
+
+ticcmd_t	localcmds[BACKUPTICS];
+
+ticcmd_t	netcmds[MAXPLAYERS][BACKUPTICS];
+int		nettics[MAXNETNODES];
+
+int		maketic;
+int		lastnettic, skiptics;
+int		ticdup;
+int		maxsend;			/* BACKUPTICS/(2*ticdup)-1 */
+
+static boolean	nodeingame[MAXNETNODES];	/* set false as nodes leave game */
+static boolean	remoteresend[MAXNETNODES];	/* set when local needs tics */
+static int	resendto[MAXNETNODES];		/* set when remote needs tics */
+static int	resendcount[MAXNETNODES];
+
+static int	nodeforplayer[MAXPLAYERS];
+
+static boolean	reboundpacket;
+static doomdata_t	reboundstore;
+
+/* extern functions */
+void H2_ProcessEvents (void);
+void G_BuildTiccmd (ticcmd_t *cmd);
+void H2_DoAdvanceDemo (void);
+
+
+//============================================================================
+
+
+static int NetbufferSize (void)
+{
+	return (int) ((ptrdiff_t)&(((doomdata_t *)0)->cmds[netbuffer->numtics]));
+}
+
+static unsigned int NetbufferChecksum (void)
+{
+	unsigned int	c;
+	int		i, l;
+
+	c = 0x1234567;
+
+#if defined(NeXT) || defined(NORMALUNIX)
+	return 0;	/* byte order problems */
+#endif
+
+	l = NetbufferSize() - (int)((ptrdiff_t)&(((doomdata_t *)0)->retransmitfrom))/4;
+	for (i = 0; i < l; i++)
+		c += ((unsigned int *)&netbuffer->retransmitfrom)[i] * (i + 1);
+
+	return c & NCMD_CHECKSUM;
+}
+
+static int ExpandTics (int low)
+{
+	int	delta;
+
+	delta = low - (maketic & 0xff);
+
+	if (delta >= -64 && delta <= 64)
+		return (maketic & ~0xff) + low;
+	if (delta > 64)
+		return (maketic & ~0xff) - 256 + low;
+	if (delta < -64)
+		return (maketic & ~0xff) + 256 + low;
+
+	I_Error ("ExpandTics: strange value %i at maketic %i", low, maketic);
+	return 0;
+}
+
+
+//============================================================================
+
+
+/*
+==============
+=
+= HSendPacket
+=
+==============
+*/
+
+static void HSendPacket (int node, int flags)
+{
+	netbuffer->checksum = NetbufferChecksum () | flags;
+
+	if (!node)
+	{
+		reboundstore = *netbuffer;
+		reboundpacket = true;
+		return;
+	}
+
+	if (demoplayback)
+		return;
+
+	if (!netgame)
+		I_Error ("Tried to transmit to another node");
+
+	doomcom->command = CMD_SEND;
+	doomcom->remotenode = node;
+	doomcom->datalength = NetbufferSize();
+
+	if (debugfile)
+	{
+		int		i;
+		int		realretrans;
+
+		if (netbuffer->checksum & NCMD_RETRANSMIT)
+			realretrans = ExpandTics (netbuffer->retransmitfrom);
+		else
+			realretrans = -1;
+
+		fprintf (debugfile, "send (%i + %i, R %i) [%i] ",
+			 ExpandTics(netbuffer->starttic), netbuffer->numtics,
+			 realretrans, doomcom->datalength);
+
+		for (i = 0; i < doomcom->datalength; i++)
+			fprintf (debugfile, "%i ", ((byte *)netbuffer)[i]);
+
+		fprintf (debugfile, "\n");
+	}
+
+	I_NetCmd ();
+}
+
+//==========================================================================
+//
+// NET_SendFrags
+//
+//==========================================================================
+
+void NET_SendFrags(player_t *player)
+{
+	int i;
+	int frags;
+
+	netbuffer->checksum = NetbufferChecksum();
+
+	if (demoplayback)
+	{
+		return;
+	}
+	if (!netgame)
+	{
+		I_Error ("Tried to transmit to another node");
+	}
+
+	frags = 0;
+	for (i = 0; i < MAXPLAYERS; i++)
+	{
+		frags += player->frags[i];
+	}
+	doomcom->command = CMD_FRAG;
+	doomcom->remotenode = frags;
+	doomcom->datalength = NetbufferSize();
+
+	I_NetCmd ();
+}
+
+/*
+==============
+=
+= HGetPacket
+=
+= Returns false if no packet is waiting
+=
+==============
+*/
+
+static boolean HGetPacket (void)
+{
+	if (reboundpacket)
+	{
+		*netbuffer = reboundstore;
+		doomcom->remotenode = 0;
+		reboundpacket = false;
+		return true;
+	}
+
+	if (!netgame)
+		return false;
+	if (demoplayback)
+		return false;
+
+	doomcom->command = CMD_GET;
+	I_NetCmd ();
+	if (doomcom->remotenode == -1)
+		return false;
+
+	if (doomcom->datalength != NetbufferSize())
+	{
+		if (debugfile)
+			fprintf (debugfile, "bad packet length %i\n", doomcom->datalength);
+		return false;
+	}
+
+	if (NetbufferChecksum () != (netbuffer->checksum & NCMD_CHECKSUM))
+	{
+		if (debugfile)
+			fprintf (debugfile, "bad packet checksum\n");
+		return false;
+	}
+
+	if (debugfile)
+	{
+		int		realretrans;
+		int		i;
+
+		if (netbuffer->checksum & NCMD_SETUP)
+			fprintf (debugfile, "setup packet\n");
+		else
+		{
+			if (netbuffer->checksum & NCMD_RETRANSMIT)
+				realretrans = ExpandTics (netbuffer->retransmitfrom);
+			else
+				realretrans = -1;
+
+			fprintf (debugfile, "get %i = (%i + %i, R %i)[%i] ",
+				 doomcom->remotenode,  ExpandTics(netbuffer->starttic),
+				 netbuffer->numtics, realretrans, doomcom->datalength);
+
+			for (i = 0; i < doomcom->datalength; i++)
+				fprintf (debugfile, "%i ", ((byte *)netbuffer)[i]);
+
+			fprintf (debugfile, "\n");
+		}
+	}
+	return true;
+}
+
+
+/*
+===================
+=
+= GetPackets
+=
+===================
+*/
+
+static char	exitmsg[80];
+
+static void GetPackets (void)
+{
+	int		netconsole;
+	int		netnode;
+	ticcmd_t	*src, *dest;
+	int		realend;
+	int		realstart;
+
+	while (HGetPacket ())
+	{
+		if (netbuffer->checksum & NCMD_SETUP)
+			continue;	// extra setup packet
+
+		netconsole = netbuffer->player & ~PL_DRONE;
+		netnode = doomcom->remotenode;
+		//
+		// to save bytes, only the low byte of tic numbers are sent
+		// Figure out what the rest of the bytes are
+		//
+		realstart = ExpandTics (netbuffer->starttic);
+		realend = (realstart + netbuffer->numtics);
+
+		//
+		// check for exiting the game
+		//
+		if (netbuffer->checksum & NCMD_EXIT)
+		{
+			if (!nodeingame[netnode])
+				continue;
+			nodeingame[netnode] = false;
+			playeringame[netconsole] = false;
+			strcpy (exitmsg, "PLAYER 1 LEFT THE GAME");
+			exitmsg[7] += netconsole;
+			P_SetMessage(&players[consoleplayer], exitmsg, true);
+			S_StartSound(NULL, SFX_CHAT);
+		//	players[consoleplayer].message = exitmsg;
+		//	if (demorecording)
+		//		G_CheckDemoStatus ();
+			continue;
+		}
+
+		//
+		// check for a remote game kill
+		//
+		if (netbuffer->checksum & NCMD_KILL)
+			I_Error ("Killed by network driver");
+
+		nodeforplayer[netconsole] = netnode;
+
+		//
+		// check for retransmit request
+		//
+		if (resendcount[netnode] <= 0 && (netbuffer->checksum & NCMD_RETRANSMIT))
+		{
+			resendto[netnode] = ExpandTics(netbuffer->retransmitfrom);
+			if (debugfile)
+				fprintf (debugfile, "retransmit from %i\n", resendto[netnode]);
+			resendcount[netnode] = RESENDCOUNT;
+		}
+		else
+			resendcount[netnode]--;
+
+		//
+		// check for out of order / duplicated packet
+		//
+		if (realend == nettics[netnode])
+			continue;
+
+		if (realend < nettics[netnode])
+		{
+			if (debugfile)
+				fprintf (debugfile, "out of order packet (%i + %i)\n", realstart, netbuffer->numtics);
+			continue;
+		}
+
+		//
+		// check for a missed packet
+		//
+		if (realstart > nettics[netnode])
+		{
+		// stop processing until the other system resends the missed tics
+			if (debugfile)
+				fprintf (debugfile, "missed tics from %i (%i - %i)\n", netnode, realstart, nettics[netnode]);
+			remoteresend[netnode] = true;
+			continue;
+		}
+
+		//
+		// update command store from the packet
+		//
+		{
+			int		start;
+
+			remoteresend[netnode] = false;
+
+			start = nettics[netnode] - realstart;
+			src = &netbuffer->cmds[start];
+
+			while (nettics[netnode] < realend)
+			{
+				dest = &netcmds[netconsole][nettics[netnode] % BACKUPTICS];
+				nettics[netnode]++;
+				*dest = *src;
+				src++;
+			}
+		}
+	}
+}
+
+/*
+=============
+=
+= NetUpdate
+=
+= Builds ticcmds for console player
+= sends out a packet
+=============
+*/
+
+static int	gametime;
+
+void NetUpdate (void)
+{
+	int		nowtime;
+	int		newtics;
+	int		i, j;
+	int		realstart;
+	int		gameticdiv;
+
+//
+// check time
+//
+	nowtime = I_GetTime()/ticdup;
+	newtics = nowtime - gametime;
+	gametime = nowtime;
+
+	if (newtics <= 0)		// nothing new to update
+		goto listen;
+
+	if (skiptics <= newtics)
+	{
+		newtics -= skiptics;
+		skiptics = 0;
+	}
+	else
+	{
+		skiptics -= newtics;
+		newtics = 0;
+	}
+
+	netbuffer->player = consoleplayer;
+
+//
+// build new ticcmds for console player
+//
+	gameticdiv = gametic/ticdup;
+	for (i = 0; i < newtics; i++)
+	{
+		I_StartTic ();
+		H2_ProcessEvents ();
+		if (maketic - gameticdiv >= BACKUPTICS/2 - 1)
+			break;		// can't hold any more
+	//	printf ("mk:%i ", maketic);
+		G_BuildTiccmd (&localcmds[maketic % BACKUPTICS]);
+		maketic++;
+	}
+
+	if (singletics)
+		return;		// singletic update is syncronous
+
+//
+// send the packet to the other nodes
+//
+	for (i = 0; i < doomcom->numnodes; i++)
+	{
+		if (nodeingame[i])
+		{
+			netbuffer->starttic = realstart = resendto[i];
+			netbuffer->numtics = maketic - realstart;
+			if (netbuffer->numtics > BACKUPTICS)
+				I_Error ("NetUpdate: netbuffer->numtics > BACKUPTICS");
+
+			resendto[i] = maketic - doomcom->extratics;
+
+			for (j = 0; j < netbuffer->numtics; j++)
+				netbuffer->cmds[j] = localcmds[(realstart + j) % BACKUPTICS];
+
+			if (remoteresend[i])
+			{
+				netbuffer->retransmitfrom = nettics[i];
+				HSendPacket (i, NCMD_RETRANSMIT);
+			}
+			else
+			{
+				netbuffer->retransmitfrom = 0;
+				HSendPacket (i, 0);
+			}
+		}
+	}
+
+//
+// listen for other packets
+//
+listen:
+
+	GetPackets ();
+}
+
+
+/*
+=====================
+=
+= CheckAbort
+=
+=====================
+*/
+
+static void CheckAbort (void)
+{
+	event_t	*ev;
+	int		stoptic;
+
+	stoptic = I_GetTime () + 2;
+	while (I_GetTime() < stoptic)
+		I_StartTic ();
+
+	I_StartTic ();
+	while (eventtail != eventhead)
+	{
+		ev = &events[eventtail];
+		if (ev->type == ev_keydown && ev->data1 == KEY_ESCAPE)
+			I_Error ("Network game synchronization aborted.");
+		eventtail = (eventtail + 1) & (MAXEVENTS - 1);
+	}
+}
+
+/*
+=====================
+=
+= D_ArbitrateNetStart
+=
+=====================
+*/
+
+static void D_ArbitrateNetStart (void)
+{
+	int		i;
+	boolean	gotinfo[MAXNETNODES];
+	boolean	gotClass[MAXNETNODES];
+
+	autostart = true;
+
+	memset (gotClass, 0, sizeof(gotClass));
+	memset (gotinfo, 0, sizeof(gotinfo));
+	gotClass[doomcom->consoleplayer] = true;
+
+	do
+	{
+		i = 0;
+
+		CheckAbort();
+		while (HGetPacket())
+		{ // Check for any incoming packets
+			if (netbuffer->checksum & NCMD_SETUP && netbuffer->starttic >= 64)
+			{
+				PlayerClasses[netbuffer->player] = netbuffer->starttic & 0x3f;
+				if (!gotClass[netbuffer->player])
+				{
+					gotClass[netbuffer->player] = true;
+					ST_NetProgress();
+					ST_Message("\n");
+				}
+				if (netbuffer->retransmitfrom)
+				{ // that node has received info from all other nodes
+					gotinfo[netbuffer->player] = true;
+				}
+			}
+		}
+		// Keep sending out packets containing the console class
+		for (i = 0; i < doomcom->numnodes; i++)
+		{
+			netbuffer->player = doomcom->consoleplayer;
+			netbuffer->starttic = PlayerClasses[doomcom->consoleplayer] + 64;
+			netbuffer->retransmitfrom = gotinfo[doomcom->consoleplayer];
+			netbuffer->numtics = 0;
+			HSendPacket(i, NCMD_SETUP);
+		}
+		for (i = 0; i < doomcom->numnodes; i++)
+		{ // Make sure that all nodes have sent class info
+			if (!gotClass[i])
+			{
+				ST_Message(".");
+				break;
+			}
+		}
+		if (i < doomcom->numnodes)
+		{
+			continue;
+		}
+		else
+		{ // consoleplayer has received all player classes
+			if (gotinfo[doomcom->consoleplayer])
+			{
+				CheckAbort();
+			}
+			else
+			{
+				gotinfo[doomcom->consoleplayer] = true;
+				ST_Message("All player classes received, ready to proceed\n");
+				ST_NetDone();
+			}
+		}
+		for (i = 0; i < doomcom->numnodes; i++)
+		{ // Make sure that all nodes are ready to proceed
+			if (!gotinfo[i])
+			{
+				break;
+			}
+		}
+	} while (i < doomcom->numnodes);
+
+	memset (gotinfo, 0, sizeof(gotinfo));
+
+	if (doomcom->consoleplayer)
+	{ // listen for setup info from key player
+	//	ST_Message ("listening for network start info...\n");
+		while (1)
+		{
+			CheckAbort ();
+			if (!HGetPacket ())
+				continue;
+			if (netbuffer->checksum & NCMD_SETUP && netbuffer->starttic < 64)
+			{
+				if (netbuffer->player != VERSION)
+					I_Error ("Different HEXEN versions cannot play a net game!");
+				startskill = netbuffer->retransmitfrom & 15;
+				deathmatch = (netbuffer->retransmitfrom & 0xc0) >> 6;
+				nomonsters = (netbuffer->retransmitfrom & 0x20) > 0;
+				respawnparm = (netbuffer->retransmitfrom & 0x10) > 0;
+				startmap = netbuffer->starttic & 0x3f;
+				startepisode = 1;
+				return;
+			}
+		}
+	}
+	else
+	{ // key player, send the setup info
+	//	ST_Message ("sending network start info...\n");
+		do
+		{
+			CheckAbort ();
+			for (i = 0; i < doomcom->numnodes; i++)
+			{
+				netbuffer->retransmitfrom = startskill;
+				if (deathmatch)
+					netbuffer->retransmitfrom |= (deathmatch << 6);
+				if (nomonsters)
+					netbuffer->retransmitfrom |= 0x20;
+				if (respawnparm)
+					netbuffer->retransmitfrom |= 0x10;
+				netbuffer->starttic = startmap & 0x3f;
+				netbuffer->player = VERSION;
+				netbuffer->numtics = 0;
+				HSendPacket (i, NCMD_SETUP);
+			}
+
+#if 1
+			for (i = 10; i && HGetPacket(); --i)
+			{
+				if ((netbuffer->player & 0x7f) < MAXNETNODES)
+					gotinfo[netbuffer->player & 0x7f] = true;
+			}
+#else
+			while (HGetPacket ())
+			{
+				gotinfo[netbuffer->player & 0x7f] = true;
+			}
+#endif
+
+			for (i = 1; i < doomcom->numnodes; i++)
+			{
+				if (!gotinfo[i])
+					break;
+			}
+		} while (i < doomcom->numnodes);
+	}
+}
+
+/*
+===================
+=
+= D_CheckNetGame
+=
+= Works out player numbers among the net participants
+===================
+*/
+
+extern	int			viewangleoffset;
+
+void D_CheckNetGame (void)
+{
+	int		i;
+	int		pClass;
+
+	for (i = 0; i < MAXNETNODES; i++)
+	{
+		nodeingame[i] = false;
+		nettics[i] = 0;
+		remoteresend[i] = false;	// set when local needs tics
+		resendto[i] = 0;		// which tic to start sending
+	}
+
+// I_InitNetwork sets doomcom and netgame
+	I_InitNetwork ();
+	if (doomcom->id != DOOMCOM_ID)
+		I_Error ("Doomcom buffer invalid!");
+	netbuffer = &doomcom->data;
+	consoleplayer = displayplayer = doomcom->consoleplayer;
+	pClass = PCLASS_FIGHTER;
+	if ((i = M_CheckParm("-class")))
+	{
+		pClass = atoi(myargv[i + 1]);
+		if (pClass > PCLASS_MAGE || pClass < PCLASS_FIGHTER)
+		{
+			I_Error("Invalid player class: %d\n", pClass);
+		}
+		ST_Message("\nPlayer Class: %d\n", pClass);
+	}
+	PlayerClasses[consoleplayer] = pClass;
+	if (netgame)
+		D_ArbitrateNetStart ();
+
+//	ST_Message ("startskill %i  deathmatch: %i  startmap: %i  startepisode: %i\n",
+//		    startskill, deathmatch, startmap, startepisode);
+
+// read values out of doomcom
+	ticdup = doomcom->ticdup;
+	maxsend = BACKUPTICS / (2*ticdup) - 1;
+	if (maxsend < 1)
+		maxsend = 1;
+
+	for (i = 0; i < doomcom->numplayers; i++)
+		playeringame[i] = true;
+	for (i = 0; i < doomcom->numnodes; i++)
+		nodeingame[i] = true;
+
+//	ST_Message ("player %i of %i (%i nodes)\n",
+//		    consoleplayer + 1, doomcom->numplayers, doomcom->numnodes);
+}
+
+/*
+==================
+=
+= D_QuitNetGame
+=
+= Called before quitting to leave a net game without hanging the
+= other players
+=
+==================
+*/
+
+void D_QuitNetGame (void)
+{
+	int		i, j;
+
+	if (debugfile)
+		fclose (debugfile);
+
+	if (!netgame || !usergame || consoleplayer == -1 || demoplayback)
+		return;
+
+// send a bunch of packets for security
+	netbuffer->player = consoleplayer;
+	netbuffer->numtics = 0;
+	for (i = 0; i < 4; i++)
+	{
+		for (j = 1; j < doomcom->numnodes; j++)
+		{
+			if (nodeingame[j])
+				HSendPacket (j, NCMD_EXIT);
+		}
+		I_WaitVBL (1);
+	}
+}
+
+
+/*
+===============
+=
+= TryRunTics
+=
+===============
+*/
+
+int	frametics[4], frameon;
+int	frameskip[4];
+int	oldnettics;
+extern	boolean	advancedemo;
+
+void TryRunTics (void)
+{
+	int		i;
+	int		lowtic;
+	int		entertic;
+	static int	oldentertics;
+	int		realtics, availabletics;
+	int		counts;
+	int		numplaying;
+
+//
+// get real tics
+//
+	entertic = I_GetTime () / ticdup;
+	realtics = entertic - oldentertics;
+	oldentertics = entertic;
+
+//
+// get available tics
+//
+	NetUpdate ();
+
+	lowtic = H2MAXINT;
+	numplaying = 0;
+	for (i = 0; i < doomcom->numnodes; i++)
+	{
+		if (nodeingame[i])
+		{
+			numplaying++;
+			if (nettics[i] < lowtic)
+				lowtic = nettics[i];
+		}
+	}
+	availabletics = lowtic - gametic/ticdup;
+
+//
+// decide how many tics to run
+//
+	if (realtics < availabletics - 1)
+		counts = realtics + 1;
+	else if (realtics < availabletics)
+		counts = realtics;
+	else
+		counts = availabletics;
+	if (counts < 1)
+		counts = 1;
+
+	frameon++;
+
+	if (debugfile)
+		fprintf (debugfile, "=======real: %i  avail: %i  game: %i\n", realtics, availabletics, counts);
+
+	if (!demoplayback)
+	{
+	//	ideally nettics[0] should be 1 - 3 tics above lowtic
+	//	if we are consistantly slower, speed up time
+		for (i = 0; i < MAXPLAYERS; i++)
+		{
+			if (playeringame[i])
+				break;
+		}
+		if (consoleplayer == i)
+		{
+			// the key player does not adapt
+		}
+		else
+		{
+			if (nettics[0] <= nettics[nodeforplayer[i]])
+			{
+				gametime--;
+			//	printf ("-");
+			}
+			frameskip[frameon & 3] = (oldnettics > nettics[nodeforplayer[i]]);
+			oldnettics = nettics[0];
+			if (frameskip[0] && frameskip[1] && frameskip[2] && frameskip[3])
+			{
+				skiptics = 1;
+			//	printf ("+");
+			}
+		}
+	}
+
+	//
+	// wait for new tics if needed
+	//
+	while (lowtic < gametic/ticdup + counts)
+	{
+		NetUpdate ();
+		lowtic = H2MAXINT;
+
+		for (i = 0; i < doomcom->numnodes; i++)
+		{
+			if (nodeingame[i] && nettics[i] < lowtic)
+				lowtic = nettics[i];
+		}
+
+		if (lowtic < gametic / ticdup)
+			I_Error ("TryRunTics: lowtic < gametic");
+
+		// don't stay in here forever -- give the menu a chance to work
+		if (I_GetTime() / ticdup - entertic >= 20)
+		{
+			MN_Ticker ();
+			return;
+		}
+	}
+
+//
+// run the count * ticdup dics
+//
+	while (counts--)
+	{
+		for (i = 0; i < ticdup; i++)
+		{
+			if (gametic / ticdup > lowtic)
+				I_Error ("gametic>lowtic");
+			if (advancedemo)
+				H2_DoAdvanceDemo ();
+			MN_Ticker ();
+			G_Ticker ();
+			gametic++;
+			//
+			// modify command for duplicated tics
+			//
+			if (i != ticdup - 1)
+			{
+				ticcmd_t	*cmd;
+				int			buf;
+				int			j;
+
+				buf = (gametic / ticdup) % BACKUPTICS;
+				for (j = 0; j < MAXPLAYERS; j++)
+				{
+					cmd = &netcmds[j][buf];
+					cmd->chatchar = 0;
+					if (cmd->buttons & BT_SPECIAL)
+						cmd->buttons = 0;
+				}
+			}
+		}
+		NetUpdate ();	// check for new console commands
+	}
+}
+
--- /dev/null
+++ b/f_finale.c
@@ -1,0 +1,413 @@
+
+//**************************************************************************
+//**
+//** f_finale.c : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 458 $
+//** $Date: 2009-05-25 15:35:27 +0300 (Mon, 25 May 2009) $
+//**
+//**************************************************************************
+
+// HEADER FILES ------------------------------------------------------------
+
+#include "h2stdinc.h"
+#include <ctype.h>
+#include "h2def.h"
+#include "soundst.h"
+#include "p_local.h"
+#include "v_compat.h"
+
+// MACROS ------------------------------------------------------------------
+
+#define	TEXTSPEED	3
+#define	TEXTWAIT	250
+
+#ifdef RENDER3D
+#define V_DrawPatch(x,y,p)		OGL_DrawPatch((x),(y),(p))
+#define V_DrawRawScreen(a)		OGL_DrawRawScreen((a))
+#endif
+
+// TYPES -------------------------------------------------------------------
+
+// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
+
+// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
+
+// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
+
+static void TextWrite(void);
+static void DrawPic(void);
+
+#ifdef RENDER3D
+static void FadeIn (void);
+static void FadeOut(void);
+#define InitializeFade(x)	do {} while (0)
+#define DeInitializeFade()	do {} while (0)
+#define FadePic()		do {} while (0)
+#else
+#define FadeIn()		do {} while (0)
+#define FadeOut()		do {} while (0)
+static void InitializeFade(boolean fadeIn);
+static void DeInitializeFade(void);
+static void FadePic(void);
+#endif
+
+// EXTERNAL DATA DECLARATIONS ----------------------------------------------
+
+extern boolean viewactive;
+
+// PUBLIC DATA DECLARATIONS ------------------------------------------------
+
+// PRIVATE DATA DEFINITIONS ------------------------------------------------
+
+static int FinaleStage;
+static int FinaleCount;
+static int FinaleEndCount;
+static int FinaleLumpNum;
+static int FontABaseLump;
+static const char *FinaleText;
+
+#ifndef RENDER3D
+static fixed_t *Palette;
+static fixed_t *PaletteDelta;
+static byte *RealPalette;
+#endif
+
+// CODE --------------------------------------------------------------------
+
+//===========================================================================
+//
+// F_StartFinale
+//
+//===========================================================================
+
+void F_StartFinale (void)
+{
+	gameaction = ga_nothing;
+	gamestate = GS_FINALE;
+	viewactive = false;
+	automapactive = false;
+	P_ClearMessage(&players[consoleplayer]);
+
+	FinaleStage = 0;
+	FinaleCount = 0;
+	FinaleText = GetFinaleText(0);
+	FinaleEndCount = 70;
+	FinaleLumpNum = W_GetNumForName("FINALE1");
+	FontABaseLump = W_GetNumForName("FONTA_S") + 1;
+	InitializeFade(1);
+#ifdef RENDER3D
+	OGL_SetFilter(0);
+#endif
+//	S_ChangeMusic(mus_victor, true);
+	S_StartSongName("hall", false); // don't loop the song
+}
+
+//===========================================================================
+//
+// F_Responder
+//
+//===========================================================================
+
+boolean F_Responder(event_t *event)
+{
+	return false;
+}
+
+//===========================================================================
+//
+// F_Ticker
+//
+//===========================================================================
+
+void F_Ticker (void)
+{
+	FinaleCount++;
+	if (FinaleStage < 5 && FinaleCount >= FinaleEndCount)
+	{
+		FinaleCount = 0;
+		FinaleStage++;
+		switch (FinaleStage)
+		{
+		case 1: // Text 1
+			FinaleEndCount = strlen(FinaleText)*TEXTSPEED + TEXTWAIT;
+			break;
+		case 2: // Pic 2, Text 2
+			FinaleText = GetFinaleText(1);
+			FinaleEndCount = strlen(FinaleText)*TEXTSPEED + TEXTWAIT;
+			FinaleLumpNum = W_GetNumForName("FINALE2");
+			S_StartSongName("orb", false);
+			break;
+		case 3: // Pic 2 -- Fade out
+			FinaleEndCount = 70;
+			DeInitializeFade();
+			InitializeFade(0);
+			break;
+		case 4: // Pic 3 -- Fade in
+			FinaleLumpNum = W_GetNumForName("FINALE3");
+			FinaleEndCount = 71;
+			DeInitializeFade();
+			InitializeFade(1);
+			S_StartSongName("chess", true);
+			break;
+		case 5: // Pic 3 , Text 3
+			FinaleText = GetFinaleText(2);
+			DeInitializeFade();
+			break;
+		default:
+			break;
+		}
+		return;
+	}
+	if (FinaleStage == 0 || FinaleStage == 3 || FinaleStage == 4)
+	{
+		FadePic();
+	}
+}
+
+//===========================================================================
+//
+// TextWrite
+//
+//===========================================================================
+
+static void TextWrite (void)
+{
+	int		count;
+	const char	*ch;
+	int		c;
+	int		cx, cy;
+	patch_t		*w;
+	int		width;
+
+	V_DrawRawScreen((BYTE_REF) WR_CacheLumpNum(FinaleLumpNum, PU_CACHE));
+
+	if (FinaleStage == 5)
+	{ // Chess pic, draw the correct character graphic
+		if (netgame)
+		{
+			V_DrawPatch(20, 0, (PATCH_REF)WR_CacheLumpName("chessall", PU_CACHE));
+		}
+#ifdef ASSASSIN
+		else if (PlayerClasses[consoleplayer] == PCLASS_ASS)
+		{
+			V_DrawPatch(60, 0, (PATCH_REF)WR_CacheLumpNum(W_GetNumForName("chessa"), PU_CACHE));
+		}
+#endif
+		else if (PlayerClasses[consoleplayer])
+		{
+			V_DrawPatch(60, 0, (PATCH_REF)WR_CacheLumpNum(W_GetNumForName("chessc")
+									+ PlayerClasses[consoleplayer] - 1, PU_CACHE));
+		}
+	}
+	// Draw the actual text
+	if (FinaleStage == 5)
+	{
+		cy = 135;
+	}
+	else
+	{
+		cy = 5;
+	}
+	cx = 20;
+	ch = FinaleText;
+	count = (FinaleCount - 10) / TEXTSPEED;
+	if (count < 0)
+	{
+		count = 0;
+	}
+	for ( ; count; count--)
+	{
+		c = *ch++;
+		if (!c)
+		{
+			break;
+		}
+		if (c == '\n')
+		{
+			cx = 20;
+			cy += 9;
+			continue;
+		}
+		if (c < 32)
+		{
+			continue;
+		}
+		c = toupper(c);
+		if (c == 32)
+		{
+			cx += 5;
+			continue;
+		}
+		w = (patch_t *) W_CacheLumpNum(FontABaseLump + c - 33, PU_CACHE);
+		width = SHORT(w->width);
+		if (cx + width > SCREENWIDTH)
+		{
+			break;
+		}
+#ifdef RENDER3D
+		OGL_DrawPatch_CS(cx, cy, FontABaseLump + c - 33);
+#else
+		V_DrawPatch(cx, cy, w);
+#endif
+		cx += width;
+	}
+}
+
+//===========================================================================
+//
+// InitializeFade
+//
+//===========================================================================
+
+#if !defined(RENDER3D)
+static void InitializeFade(boolean fadeIn)
+{
+	unsigned i;
+
+	Palette = (fixed_t *) Z_Malloc(768*sizeof(fixed_t), PU_STATIC, NULL);
+	PaletteDelta = (fixed_t *) Z_Malloc(768*sizeof(fixed_t), PU_STATIC, NULL);
+	RealPalette = (byte *) Z_Malloc(768*sizeof(byte), PU_STATIC, NULL);
+
+	if (fadeIn)
+	{
+		memset(RealPalette, 0, 768*sizeof(byte));
+		for (i = 0; i < 768; i++)
+		{
+			Palette[i] = 0;
+			PaletteDelta[i] = FixedDiv((*((byte *)W_CacheLumpName("PLAYPAL", PU_CACHE) + i))<<FRACBITS, 70*FRACUNIT);
+		}
+	}
+	else
+	{
+		for (i = 0; i < 768; i++)
+		{
+			RealPalette[i] = *((byte *)W_CacheLumpName("PLAYPAL", PU_CACHE) + i);
+			Palette[i] = RealPalette[i]<<FRACBITS;
+			PaletteDelta[i] = FixedDiv(Palette[i], -70*FRACUNIT);
+		}
+	}
+	I_SetPalette(RealPalette);
+}
+
+//===========================================================================
+//
+// DeInitializeFade
+//
+//===========================================================================
+
+static void DeInitializeFade(void)
+{
+	Z_Free(Palette);
+	Z_Free(PaletteDelta);
+	Z_Free(RealPalette);
+}
+
+//===========================================================================
+//
+// FadePic
+//
+//===========================================================================
+
+static void FadePic(void)
+{
+	unsigned i;
+
+	for (i = 0; i < 768; i++)
+	{
+		Palette[i] += PaletteDelta[i];
+		RealPalette[i] = Palette[i]>>FRACBITS;
+	}
+	I_SetPalette(RealPalette);
+}
+
+#else	/* ! RENDER3D */
+
+/* For OpenGL: adapted from the Vavoom project.
+ *
+ * The FinaleCount / FinaleEndCount tick rates seem to work fine
+ * for us here:  for FinaleStage 0, 3 and 4, where this code is
+ * used, FinaleEndCount is set to 70 or 71, FinaleCount is reset
+ * to 0 and incremented at every tick, and this gives us about 2
+ * seconds of fade-in/fade-out.
+ */
+static void FadeOut (void)
+{
+	float fade = (float)FinaleCount / (float)FinaleEndCount;
+
+	if (fade < 0.0)
+		fade = 0.0;
+	if (fade > 0.99)
+		fade = 0.99;
+	OGL_ShadeRect(0, 0, 320, 200, fade);
+}
+
+static void FadeIn (void)
+{
+	float fade = 1.0 - (float)FinaleCount / (float)FinaleEndCount;
+
+	if (fade < 0.0)
+		fade = 0.0;
+	if (fade > 0.99)
+		fade = 0.99;
+	OGL_ShadeRect(0, 0, 320, 200, fade);
+}
+#endif	/* ! RENDER3D */
+
+//===========================================================================
+//
+// DrawPic
+//
+//===========================================================================
+
+static void DrawPic(void)
+{
+	V_DrawRawScreen((BYTE_REF) WR_CacheLumpNum(FinaleLumpNum, PU_CACHE));
+
+	if (FinaleStage == 4 || FinaleStage == 5)
+	{ // Chess pic, draw the correct character graphic
+		if (netgame)
+		{
+			V_DrawPatch(20, 0, (PATCH_REF)WR_CacheLumpName("chessall", PU_CACHE));
+		}
+		else if (PlayerClasses[consoleplayer])
+		{
+			V_DrawPatch(60, 0, (PATCH_REF)WR_CacheLumpNum(W_GetNumForName("chessc")
+									+ PlayerClasses[consoleplayer] - 1, PU_CACHE));
+		}
+	}
+}
+
+//===========================================================================
+//
+// F_Drawer
+//
+//===========================================================================
+
+void F_Drawer(void)
+{
+	switch (FinaleStage)
+	{
+	case 0: // Fade in initial finale screen
+		DrawPic();
+		FadeIn();
+		break;
+	case 1:
+	case 2:
+		TextWrite();
+		break;
+	case 3: // Fade screen out
+		DrawPic();
+		FadeOut();
+		break;
+	case 4: // Fade in chess screen
+		DrawPic();
+		FadeIn();
+		break;
+	case 5:
+		TextWrite();
+		break;
+	}
+	UpdateState |= I_FULLSCRN;
+}
+
--- /dev/null
+++ b/g_game.c
@@ -1,0 +1,1883 @@
+
+//**************************************************************************
+//**
+//** g_game.c : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 584 $
+//** $Date: 2012-02-17 12:01:51 +0200 (Fri, 17 Feb 2012) $
+//**
+//**************************************************************************
+
+#include "h2stdinc.h"
+#include "h2def.h"
+#include "p_local.h"
+#include "soundst.h"
+
+#define AM_STARTKEY	9
+
+// External functions
+
+extern void R_InitSky(int map);
+extern void P_PlayerNextArtifact(player_t *player);
+
+// Functions
+
+boolean G_CheckDemoStatus (void);
+static void G_ReadDemoTiccmd (ticcmd_t *cmd);
+static void G_WriteDemoTiccmd (ticcmd_t *cmd);
+
+void G_InitNew (skill_t skill, int episode, int map);
+
+static void G_DoReborn (int playernum);
+
+static void G_DoLoadLevel(void);
+static void G_DoInitNew(void);
+static void G_DoNewGame(void);
+
+void G_DoLoadGame(void);
+static void G_DoPlayDemo(void);
+static void G_DoTeleportNewMap(void);
+static void G_DoCompleted(void);
+static void G_DoWorldDone(void);
+static void G_DoSaveGame(void);
+static void G_DoSingleReborn(void);
+
+void H2_PageTicker(void);
+void H2_AdvanceDemo(void);
+
+extern boolean mn_SuicideConsole;
+
+gameaction_t	gameaction;
+gamestate_t	gamestate;
+skill_t		gameskill;
+int		gameepisode;
+int		gamemap;
+int		prevmap;
+
+boolean		paused;
+
+boolean		usergame;		// ok to save / end game
+
+static boolean	sendpause;		// send a pause event next tic
+static boolean	sendsave;		// send a save event next tic
+
+static boolean	timingdemo;		// if true, exit with report on completion
+static int	starttime;		// for comparative timing purposes      
+
+boolean		viewactive;
+
+boolean		deathmatch;		// only if started as net death
+boolean		netgame;		// only true if packets are broadcast
+boolean		playeringame[MAXPLAYERS];
+player_t	players[MAXPLAYERS];
+pclass_t	PlayerClasses[MAXPLAYERS];
+
+// Position indicator for cooperative net-play reborn
+int		RebornPosition;
+
+int		consoleplayer;		// player taking events and displaying
+int		displayplayer;		// view being displayed
+int		gametic;
+int		levelstarttic;		// gametic at level start
+
+boolean		demorecording;
+boolean		demoplayback;
+boolean		singledemo;		// quit after playing a demo from cmdline
+static byte	*demobuffer, *demo_p;
+static char	demoname[MAX_OSPATH];
+
+static short	consistancy[MAXPLAYERS][BACKUPTICS];
+
+boolean		precache = true;	// if true, load all graphics at start
+
+//
+// controls (have defaults)
+//
+int	key_right, key_left, key_up, key_down;
+int	key_strafeleft, key_straferight, key_jump;
+int	key_fire, key_use, key_strafe, key_speed;
+int	key_flyup, key_flydown, key_flycenter;
+int	key_lookup, key_lookdown, key_lookcenter;
+int	key_invleft, key_invright, key_useartifact;
+
+int	mouselook;
+int	alwaysrun;	/* boolean */
+
+int	mousebfire;
+int	mousebstrafe;
+int	mousebforward;
+int	mousebjump;
+
+int	joybfire;
+int	joybstrafe;
+int	joybuse;
+int	joybspeed;
+int	joybjump;
+
+int	LeaveMap;
+static int LeavePosition;
+
+//#define MAXPLMOVE       0x32 // Old Heretic Max move
+
+static fixed_t MaxPlayerMove[NUMCLASSES] =
+{
+		0x3C,
+		0x32,
+		0x2D,
+#ifdef ASSASSIN
+		0x3D,
+#endif
+		0x31
+};
+
+static fixed_t forwardmove[NUMCLASSES][2] =
+{
+	{ 0x1D, 0x3C },
+	{ 0x19, 0x32 },
+	{ 0x16, 0x2E },
+#ifdef ASSASSIN
+	{ 0x17, 0x3D },
+#endif
+	{ 0x18, 0x31 }
+};
+
+static fixed_t sidemove[NUMCLASSES][2] =
+{
+	{ 0x1B, 0x3B },
+	{ 0x18, 0x28 },
+	{ 0x15, 0x25 },
+#ifdef ASSASSIN
+	{ 0x16, 0x3C },
+#endif
+	{ 0x17, 0x27 }
+};
+
+static fixed_t	angleturn[3] = {640, 1280, 320};	// + slow turn
+#define SLOWTURNTICS		6
+
+boolean	gamekeydown[MAXKEYS];
+static int	turnheld;			// for accelerative turning
+static int	lookheld;
+
+static boolean	mousearray[4];
+static boolean	*mousebuttons = &mousearray[1];	// allow [-1]
+
+static int	mousex, mousey;			// mouse values are used once
+static int	dclicktime, dclickstate, dclicks;
+static int	dclicktime2, dclickstate2, dclicks2;
+
+static int	joyxmove, joyymove;		// joystick values are repeated
+static boolean	joyarray[5];
+static boolean	*joybuttons = &joyarray[1];	// allow [-1]
+
+static int	loadgameslot;
+static int	savegameslot;
+static char	savedescription[32];
+
+static int	inventoryTics;
+
+boolean		usearti = true;
+
+static skill_t	TempSkill;
+static int	TempEpisode;
+static int	TempMap;
+
+//=============================================================================
+
+/*
+====================
+=
+= G_BuildTiccmd
+=
+= Builds a ticcmd from all of the available inputs or reads it from the
+= demo buffer.
+= If recording a demo, write it out
+====================
+*/
+
+extern boolean inventory;
+extern boolean artiskip;
+extern int curpos;
+extern int inv_ptr;
+
+void G_BuildTiccmd (ticcmd_t *cmd)
+{
+	int	i;
+	boolean	strafe, bstrafe;
+	int	speed, tspeed, lspeed;
+	int	forward, side;
+	int	look, arti;
+	int	flyheight;
+	int	pClass;
+
+	pClass = players[consoleplayer].playerclass;
+	memset (cmd, 0, sizeof(*cmd));
+
+//	cmd->consistancy =
+//		consistancy[consoleplayer][(maketic*ticdup)%BACKUPTICS];
+
+	cmd->consistancy =
+		consistancy[consoleplayer][maketic%BACKUPTICS];
+
+//printf ("cons: %i\n",cmd->consistancy);
+	strafe = gamekeydown[key_strafe] || mousebuttons[mousebstrafe] || joybuttons[joybstrafe];
+	speed = gamekeydown[key_speed] || joybuttons[joybspeed] || joybuttons[joybspeed];
+	if (alwaysrun && !demoplayback && !demorecording)
+		speed = !speed;
+	forward = side = look = arti = flyheight = 0;
+
+//
+// use two stage accelerative turning on the keyboard and joystick
+//
+	if (joyxmove < 0 || joyxmove > 0 || gamekeydown[key_right] || gamekeydown[key_left])
+		turnheld += ticdup;
+	else
+		turnheld = 0;
+	if (turnheld < SLOWTURNTICS)
+		tspeed = 2;		// slow turn
+	else
+		tspeed = speed;
+
+	if (gamekeydown[key_lookdown] || gamekeydown[key_lookup])
+	{
+		lookheld += ticdup;
+	}
+	else
+	{
+		lookheld = 0;
+	}
+	if (lookheld < SLOWTURNTICS)
+	{
+		lspeed = 1; // 3;
+	}
+	else
+	{
+		lspeed = 2; // 5;
+	}
+
+//
+// let movement keys cancel each other out
+//
+	if (strafe)
+	{
+		if (gamekeydown[key_right])
+		{
+			side += sidemove[pClass][speed];
+		}
+		if (gamekeydown[key_left])
+		{
+			side -= sidemove[pClass][speed];
+		}
+		if (joyxmove > 0)
+		{
+			side += sidemove[pClass][speed];
+		}
+		if (joyxmove < 0)
+		{
+			side -= sidemove[pClass][speed];
+		}
+	}
+	else
+	{
+		if (gamekeydown[key_right])
+			cmd->angleturn -= angleturn[tspeed];
+		if (gamekeydown[key_left])
+			cmd->angleturn += angleturn[tspeed];
+		if (joyxmove > 0)
+			cmd->angleturn -= angleturn[tspeed];
+		if (joyxmove < 0)
+			cmd->angleturn += angleturn[tspeed];
+	}
+
+	if (gamekeydown[key_up])
+	{
+		forward += forwardmove[pClass][speed];
+	}
+	if (gamekeydown[key_down])
+	{
+		forward -= forwardmove[pClass][speed];
+	}
+	if (joyymove < 0)
+	{
+		forward += forwardmove[pClass][speed];
+	}
+	if (joyymove > 0)
+	{
+		forward -= forwardmove[pClass][speed];
+	}
+	if (gamekeydown[key_straferight])
+	{
+		side += sidemove[pClass][speed];
+	}
+	if (gamekeydown[key_strafeleft])
+	{
+		side -= sidemove[pClass][speed];
+	}
+
+	// Look up/down/center keys
+	if (gamekeydown[key_lookup])
+	{
+		look = lspeed;
+	}
+	if (gamekeydown[key_lookdown])
+	{
+		look = -lspeed;
+	}
+	if (gamekeydown[key_lookcenter])
+	{
+		look = TOCENTER;
+	}
+
+	// Fly up/down/drop keys
+	if (gamekeydown[key_flyup])
+	{
+		flyheight = 5; // note that the actual flyheight will be twice this
+	}
+	if (gamekeydown[key_flydown])
+	{
+		flyheight = -5;
+	}
+	if (gamekeydown[key_flycenter])
+	{
+		flyheight = TOCENTER;
+		look = TOCENTER;
+	}
+	// Use artifact key
+	if (gamekeydown[key_useartifact])
+	{
+		if (gamekeydown[key_speed] && artiskip)
+		{
+			if (players[consoleplayer].inventory[inv_ptr].type != arti_none)
+			{ // Skip an artifact
+				gamekeydown[key_useartifact] = false;
+				P_PlayerNextArtifact(&players[consoleplayer]);
+			}
+		}
+		else
+		{
+			if (inventory)
+			{
+				players[consoleplayer].readyArtifact =
+					players[consoleplayer].inventory[inv_ptr].type;
+				inventory = false;
+				cmd->arti = 0;
+				usearti = false;
+			}
+			else if (usearti)
+			{
+				cmd->arti |= 
+					players[consoleplayer].inventory[inv_ptr].type&AFLAG_MASK;
+				usearti = false;
+			}
+		}
+	}
+	if (gamekeydown[key_jump] || mousebuttons[mousebjump] || joybuttons[joybjump])
+	{
+		cmd->arti |= AFLAG_JUMP;
+	}
+	if (mn_SuicideConsole)
+	{
+		cmd->arti |= AFLAG_SUICIDE;
+		mn_SuicideConsole = false;
+	}
+
+	// Artifact hot keys
+	if (gamekeydown[KEY_BACKSPACE] && !cmd->arti)
+	{
+		gamekeydown[KEY_BACKSPACE] = false;	// Use one of each artifact
+		cmd->arti = NUMARTIFACTS;
+	}
+	else if (gamekeydown[KEY_BACKSLASH] && !cmd->arti && (players[consoleplayer].mo->health < MAXHEALTH))
+	{
+		gamekeydown[KEY_BACKSLASH] = false;
+		cmd->arti = arti_health;
+	}
+	else if (gamekeydown[KEY_ZERO] && !cmd->arti)
+	{
+		gamekeydown[KEY_ZERO] = false;
+		cmd->arti = arti_poisonbag;
+	}
+	else if (gamekeydown[KEY_NINE] && !cmd->arti)
+	{
+		gamekeydown[KEY_NINE] = false;
+		cmd->arti = arti_blastradius;
+	}
+	else if (gamekeydown[KEY_EIGHT] && !cmd->arti)
+	{
+		gamekeydown[KEY_EIGHT] = false;
+		cmd->arti = arti_teleport;
+	}
+	else if (gamekeydown[KEY_SEVEN] && !cmd->arti)
+	{
+		gamekeydown[KEY_SEVEN] = false;
+		cmd->arti = arti_teleportother;
+	}
+	else if (gamekeydown[KEY_SIX] && !cmd->arti)
+	{
+		gamekeydown[KEY_SIX] = false;
+		cmd->arti = arti_egg;
+	}
+	else if (gamekeydown[KEY_FIVE] && !cmd->arti && !players[consoleplayer].powers[pw_invulnerability])
+	{
+		gamekeydown[KEY_FIVE] = false;
+		cmd->arti = arti_invulnerability;
+	}
+
+//
+// buttons
+//
+	cmd->chatchar = CT_dequeueChatChar();
+	if (gamekeydown[key_fire] || mousebuttons[mousebfire]
+				  || joybuttons[joybfire])
+		cmd->buttons |= BT_ATTACK;
+
+	if (gamekeydown[key_use] || joybuttons[joybuse] )
+	{
+		cmd->buttons |= BT_USE;
+		dclicks = 0;		// clear double clicks if hit use button
+	}
+
+	for (i = 0; i < NUMWEAPONS; i++)
+	{
+		if (gamekeydown['1'+i])
+		{
+			cmd->buttons |= BT_CHANGE;
+			cmd->buttons |= i<<BT_WEAPONSHIFT;
+			break;
+		}
+	}
+
+//
+// mouse
+//
+#if 0
+	printf ("%d %d %d %d <%d %d>\n",
+		mousebuttons[mousebfire], mousebuttons[mousebforward],
+		mousebuttons[mousebjump], mousebuttons[mousebstrafe],
+		mousex, mousey);
+#endif
+	if (mousebuttons[mousebforward])
+	{
+		forward += forwardmove[pClass][speed];
+	}
+
+//
+// forward double click
+//
+	if (mousebuttons[mousebforward] != dclickstate && dclicktime > 1)
+	{
+		dclickstate = mousebuttons[mousebforward];
+		if (dclickstate)
+			dclicks++;
+		if (dclicks == 2)
+		{
+			cmd->buttons |= BT_USE;
+			dclicks = 0;
+		}
+		else
+			dclicktime = 0;
+	}
+	else
+	{
+		dclicktime += ticdup;
+		if (dclicktime > 20)
+		{
+			dclicks = 0;
+			dclickstate = 0;
+		}
+	}
+
+//
+// strafe double click
+//
+	bstrafe = mousebuttons[mousebstrafe] || joybuttons[joybstrafe];
+	if (bstrafe != dclickstate2 && dclicktime2 > 1)
+	{
+		dclickstate2 = bstrafe;
+		if (dclickstate2)
+			dclicks2++;
+		if (dclicks2 == 2)
+		{
+			cmd->buttons |= BT_USE;
+			dclicks2 = 0;
+		}
+		else
+			dclicktime2 = 0;
+	}
+	else
+	{
+		dclicktime2 += ticdup;
+		if (dclicktime2 > 20)
+		{
+			dclicks2 = 0;
+			dclickstate2 = 0;
+		}
+	}
+	if (strafe)
+	{
+		side += mousex*2;
+	}
+	else
+	{
+		cmd->angleturn -= mousex*0x8;
+	}
+
+	if (demorecording || demoplayback || (mouselook == 0))
+	{
+		forward += mousey;
+	}
+	else if (mousey && !paused)	/* mouselook, but not when paused */
+	{
+		/* We'll directly change the viewing pitch of the console player. */
+		float adj = ((mousey*0x4) << 16) / (float) ANGLE_180*180*110.0/85.0;
+		float newlookdir = 0; /* jim initialiser added to prevent warning */
+
+		adj *= 2;	/* Speed up the X11 mlook a little. */
+
+		if (mouselook == 1)
+			newlookdir = players[consoleplayer].lookdir + adj;
+		else if (mouselook == 2)
+			newlookdir = players[consoleplayer].lookdir - adj;
+
+		// vertical view angle taken from p_user.c line 249.
+		if (newlookdir > 90)
+			newlookdir = 90;
+		else if (newlookdir < -110)
+			newlookdir = -110;
+
+		players[consoleplayer].lookdir = newlookdir;
+	}
+
+	mousex = mousey = 0;
+
+	if (forward > MaxPlayerMove[pClass])
+	{
+		forward = MaxPlayerMove[pClass];
+	}
+	else if (forward < -MaxPlayerMove[pClass])
+	{
+		forward = -MaxPlayerMove[pClass];
+	}
+	if (side > MaxPlayerMove[pClass])
+	{
+		side = MaxPlayerMove[pClass];
+	}
+	else if (side < -MaxPlayerMove[pClass])
+	{
+		side = -MaxPlayerMove[pClass];
+	}
+	if (players[consoleplayer].powers[pw_speed] && !players[consoleplayer].morphTics)
+	{ // Adjust for a player with a speed artifact
+		forward = (3*forward)>>1;
+		side = (3*side)>>1;
+	}
+	cmd->forwardmove += forward;
+	cmd->sidemove += side;
+	if (players[consoleplayer].playerstate == PST_LIVE)
+	{
+		if (look < 0)
+		{
+			look += 16;
+		}
+		cmd->lookfly = look;
+	}
+	if (flyheight < 0)
+	{
+		flyheight += 16;
+	}
+	cmd->lookfly |= flyheight<<4;
+
+//
+// special buttons
+//
+	if (sendpause)
+	{
+		sendpause = false;
+		cmd->buttons = BT_SPECIAL | BTS_PAUSE;
+	}
+	if (sendsave)
+	{
+		sendsave = false;
+		cmd->buttons = BT_SPECIAL | BTS_SAVEGAME | (savegameslot<<BTS_SAVESHIFT);
+	}
+}
+
+
+/*
+==============
+=
+= G_DoLoadLevel
+=
+==============
+*/
+
+static void G_DoLoadLevel (void)
+{
+	int		i;
+
+	levelstarttic = gametic;	// for time calculation
+	gamestate = GS_LEVEL;
+	for (i = 0; i < MAXPLAYERS; i++)
+	{
+		if (playeringame[i] && players[i].playerstate == PST_DEAD)
+			players[i].playerstate = PST_REBORN;
+		memset (players[i].frags, 0, sizeof(players[i].frags));
+	}
+
+	SN_StopAllSequences();
+	P_SetupLevel (gameepisode, gamemap, 0, gameskill);
+	displayplayer = consoleplayer;	// view the guy you are playing
+	starttime = I_GetTime ();
+	gameaction = ga_nothing;
+	Z_CheckHeap ();
+
+//
+// clear cmd building stuff
+//
+	memset (gamekeydown, 0, sizeof(gamekeydown));
+	joyxmove = joyymove = 0;
+	mousex = mousey = 0;
+	sendpause = sendsave = paused = false;
+//	memset (mousebuttons, 0, sizeof(mousebuttons));
+//	memset (joybuttons, 0, sizeof(joybuttons));
+	memset (joyarray, 0, sizeof(joyarray));
+	memset (mousearray, 0, sizeof(mousearray));
+}
+
+
+/*
+===============================================================================
+=
+= G_Responder 
+=
+= get info needed to make ticcmd_ts for the players
+=
+===============================================================================
+*/
+
+boolean G_Responder(event_t *ev)
+{
+	player_t *plr;
+	extern boolean MenuActive;
+
+	plr = &players[consoleplayer];
+	if (ev->type == ev_keyup && ev->data1 == key_useartifact)
+	{ // flag to denote that it's okay to use an artifact
+		if (!inventory)
+		{
+			plr->readyArtifact = plr->inventory[inv_ptr].type;
+		}
+		usearti = true;
+	}
+
+	// Check for spy mode player cycle
+	if  (gamestate == GS_LEVEL && ev->type == ev_keydown
+			&& ev->data1 == KEY_F12 && !deathmatch)
+	{ // Cycle the display player
+		do
+		{
+			displayplayer++;
+			if (displayplayer == MAXPLAYERS)
+			{
+				displayplayer = 0;
+			}
+		}
+		while (!playeringame[displayplayer] && displayplayer != consoleplayer);
+
+		return true;
+	}
+
+	if (CT_Responder(ev))
+	{ // Chat ate the event
+		return true;
+	}
+	if (gamestate == GS_LEVEL)
+	{
+		if (SB_Responder(ev))
+		{ // Status bar ate the event
+			return true;
+		}
+		if (AM_Responder(ev))
+		{ // Automap ate the event
+			return true;
+		}
+	}
+
+	switch (ev->type)
+	{
+	case ev_keydown:
+		if (ev->data1 == key_invleft)
+		{
+			inventoryTics = 5*35;
+			if (!inventory)
+			{
+				inventory = true;
+				break;
+			}
+			inv_ptr--;
+			if (inv_ptr < 0)
+			{
+				inv_ptr = 0;
+			}
+			else
+			{
+				curpos--;
+				if (curpos < 0)
+				{
+					curpos = 0;
+				}
+			}
+			return true;
+		}
+		if (ev->data1 == key_invright)
+		{
+			inventoryTics = 5*35;
+			if (!inventory)
+			{
+				inventory = true;
+				break;
+			}
+			inv_ptr++;
+			if (inv_ptr >= plr->inventorySlotNum)
+			{
+				inv_ptr--;
+				if (inv_ptr < 0)
+					inv_ptr = 0;
+			}
+			else
+			{
+				curpos++;
+				if (curpos > 6)
+				{
+					curpos = 6;
+				}
+			}
+			return true;
+		}
+		if (ev->data1 == KEY_PAUSE)
+		{
+			if (!MenuActive && gamestate != GS_FINALE)
+				sendpause = true;
+			return true;
+		}
+		if (ev->data1 < MAXKEYS)
+		{
+			gamekeydown[ev->data1] = true;
+		}
+		return true;	// eat key down events
+
+	case ev_keyup:
+		if (ev->data1 < MAXKEYS)
+		{
+			gamekeydown[ev->data1] = false;
+		}
+		return false;	// always let key up events filter down
+
+	case ev_mouse:
+		mousebuttons[0] = ev->data1 & 1;
+		mousebuttons[1] = ev->data1 & 2;
+		mousebuttons[2] = ev->data1 & 4;
+		mousex = ev->data2 * (mouseSensitivity + 5) / 10;
+		mousey = ev->data3 * (mouseSensitivity + 5) / 10;
+		return true;	// eat events
+
+	case ev_joystick:
+		joybuttons[0] = ev->data1 & 1;
+		joybuttons[1] = ev->data1 & 2;
+		joybuttons[2] = ev->data1 & 4;
+		joybuttons[3] = ev->data1 & 8;
+		joyxmove = ev->data2;
+		joyymove = ev->data3;
+		return true;	// eat events
+
+	default:
+		break;
+	}
+	return false;
+}
+
+
+//==========================================================================
+//
+// G_Ticker
+//
+//==========================================================================
+
+void G_Ticker(void)
+{
+	int		i, buf;
+	ticcmd_t	*cmd = NULL;
+
+//
+// do player reborns if needed
+//
+	for (i = 0; i < MAXPLAYERS; i++)
+	{
+		if (playeringame[i] && players[i].playerstate == PST_REBORN)
+			G_DoReborn (i);
+	}
+
+//
+// do things to change the game state
+//
+	while (gameaction != ga_nothing)
+	{
+		switch (gameaction)
+		{
+		case ga_loadlevel:
+			G_DoLoadLevel();
+			break;
+		case ga_initnew:
+			G_DoInitNew();
+			break;
+		case ga_newgame:
+			G_DoNewGame();
+			break;
+		case ga_loadgame:
+			Draw_LoadIcon();
+			G_DoLoadGame();
+			break;
+		case ga_savegame:
+			Draw_SaveIcon();
+			G_DoSaveGame();
+			break;
+		case ga_singlereborn:
+			G_DoSingleReborn();
+			break;
+		case ga_playdemo:
+			G_DoPlayDemo();
+			break;
+		case ga_screenshot:
+			M_ScreenShot();
+			gameaction = ga_nothing;
+			break;
+		case ga_leavemap:
+			Draw_TeleportIcon();
+			G_DoTeleportNewMap();
+			break;
+		case ga_completed:
+			G_DoCompleted();
+			break;
+		case ga_worlddone:
+			G_DoWorldDone();
+			break;
+		case ga_victory:
+			F_StartFinale();
+			break;
+		default:
+			break;
+		}
+	}
+
+//
+// get commands, check consistancy, and build new consistancy check
+//
+	//buf = gametic % BACKUPTICS;
+	buf = (gametic / ticdup) % BACKUPTICS;
+
+	for (i = 0; i < MAXPLAYERS; i++)
+	{
+		if (playeringame[i])
+		{
+			cmd = &players[i].cmd;
+
+			memcpy (cmd, &netcmds[i][buf], sizeof(ticcmd_t));
+
+			if (demoplayback)
+				G_ReadDemoTiccmd (cmd);
+			if (demorecording)
+				G_WriteDemoTiccmd (cmd);
+
+			if (netgame && !(gametic%ticdup))
+			{
+				if (gametic > BACKUPTICS && consistancy[i][buf] != cmd->consistancy)
+				{
+					I_Error ("consistency failure (%i should be %i)",cmd->consistancy, consistancy[i][buf]);
+				}
+				if (players[i].mo)
+					consistancy[i][buf] = players[i].mo->x;
+				else
+					consistancy[i][buf] = rndindex;
+			}
+		}
+	}
+
+//
+// check for special buttons
+//
+	for (i = 0; i < MAXPLAYERS; i++)
+	{
+		if (playeringame[i])
+		{
+			if (players[i].cmd.buttons & BT_SPECIAL)
+			{
+				switch (players[i].cmd.buttons & BT_SPECIALMASK)
+				{
+				case BTS_PAUSE:
+					paused ^= 1;
+					if (paused)
+					{
+						S_PauseSound();
+					}
+					else
+					{
+						S_ResumeSound();
+					}
+					break;
+
+				case BTS_SAVEGAME:
+					if (!savedescription[0])
+					{
+						if (netgame)
+						{
+							strcpy (savedescription, "NET GAME");
+						}
+						else
+						{
+							strcpy(savedescription, "SAVE GAME");
+						}
+					}
+					savegameslot = 
+						(players[i].cmd.buttons & BTS_SAVEMASK)>>BTS_SAVESHIFT;
+					gameaction = ga_savegame;
+					break;
+				}
+			}
+		}
+	}
+
+// turn inventory off after a certain amount of time
+	if (inventory && !(--inventoryTics))
+	{
+		players[consoleplayer].readyArtifact =
+			players[consoleplayer].inventory[inv_ptr].type;
+		inventory = false;
+		cmd->arti = 0;
+	}
+
+//
+// do main actions
+//
+	switch (gamestate)
+	{
+	case GS_LEVEL:
+		P_Ticker ();
+		SB_Ticker ();
+		AM_Ticker ();
+		CT_Ticker();
+		break;
+	case GS_INTERMISSION:
+		IN_Ticker ();
+		break;
+	case GS_FINALE:
+		F_Ticker();
+		break;
+	case GS_DEMOSCREEN:
+		H2_PageTicker ();
+		break;
+	}
+}
+
+
+/*
+==============================================================================
+
+						PLAYER STRUCTURE FUNCTIONS
+
+also see P_SpawnPlayer in P_Things
+==============================================================================
+*/
+
+//==========================================================================
+//
+// G_PlayerExitMap
+//
+// Called when the player leaves a map.
+//
+//==========================================================================
+
+void G_PlayerExitMap(int playerNumber)
+{
+	int i;
+	player_t *player;
+	int flightPower;
+
+	player = &players[playerNumber];
+
+//	if (deathmatch)
+//	{
+//		// Strip all but one of each type of artifact
+//		for (i = 0; i < player->inventorySlotNum; i++)
+//		{
+//			player->inventory[i].count = 1;
+//		}
+//		player->artifactCount = player->inventorySlotNum;
+//	}
+//	else
+
+	// Strip all current powers (retain flight)
+	flightPower = player->powers[pw_flight];
+	memset(player->powers, 0, sizeof(player->powers));
+	player->powers[pw_flight] = flightPower;
+
+	if (deathmatch)
+	{
+		player->powers[pw_flight] = 0;
+	}
+	else
+	{
+		if (P_GetMapCluster(gamemap) != P_GetMapCluster(LeaveMap))
+		{ // Entering new cluster
+			// Strip all keys
+			player->keys = 0;
+
+			// Strip flight artifact
+			for (i = 0; i < 25; i++)
+			{
+				player->powers[pw_flight] = 0;
+				P_PlayerUseArtifact(player, arti_fly);
+			}
+			player->powers[pw_flight] = 0;
+		}
+	}
+
+	if (player->morphTics)
+	{
+		player->readyweapon = player->mo->special1;	// Restore weapon
+		player->morphTics = 0;
+	}
+	player->messageTics = 0;
+	player->lookdir = 0;
+	player->mo->flags &= ~MF_SHADOW;	// Remove invisibility
+	player->extralight = 0;			// Remove weapon flashes
+	player->fixedcolormap = 0;		// Remove torch
+	player->damagecount = 0;		// No palette changes
+	player->bonuscount = 0;
+	player->poisoncount = 0;
+	if (player == &players[consoleplayer])
+	{
+		SB_state = -1;			// refresh the status bar
+		viewangleoffset = 0;
+	}
+}
+
+//==========================================================================
+//
+// G_PlayerReborn
+//
+// Called after a player dies.  Almost everything is cleared and
+// initialized.
+//
+//==========================================================================
+
+void G_PlayerReborn(int player)
+{
+	player_t *p;
+	int frags[MAXPLAYERS];
+	int killcount, itemcount, secretcount;
+	unsigned int worldTimer;
+
+	memcpy(frags, players[player].frags, sizeof(frags));
+	killcount = players[player].killcount;
+	itemcount = players[player].itemcount;
+	secretcount = players[player].secretcount;
+	worldTimer = players[player].worldTimer;
+
+	p = &players[player];
+	memset(p, 0, sizeof(*p));
+
+	memcpy(players[player].frags, frags, sizeof(players[player].frags));
+	players[player].killcount = killcount;
+	players[player].itemcount = itemcount;
+	players[player].secretcount = secretcount;
+	players[player].worldTimer = worldTimer;
+	players[player].playerclass = PlayerClasses[player];
+
+	p->usedown = p->attackdown = true;	// don't do anything immediately
+	p->playerstate = PST_LIVE;
+	p->health = MAXHEALTH;
+	p->readyweapon = p->pendingweapon = WP_FIRST;
+	p->weaponowned[WP_FIRST] = true;
+	p->messageTics = 0;
+	p->lookdir = 0;
+	localQuakeHappening[player] = false;
+	if (p == &players[consoleplayer])
+	{
+		SB_state = -1;	// refresh the status bar
+		inv_ptr = 0;	// reset the inventory pointer
+		curpos = 0;
+		viewangleoffset = 0;
+	}
+}
+
+/*
+====================
+=
+= G_CheckSpot
+=
+= Returns false if the player cannot be respawned at the given mapthing_t spot
+= because something is occupying it
+====================
+*/
+
+void P_SpawnPlayer (mapthing_t *mthing);
+
+boolean G_CheckSpot (int playernum, mapthing_t *mthing)
+{
+	fixed_t		x, y;
+	subsector_t	*ss;
+	unsigned int	an;
+	mobj_t		*mo;
+
+	x = mthing->x << FRACBITS;
+	y = mthing->y << FRACBITS;
+
+	players[playernum].mo->flags2 &= ~MF2_PASSMOBJ;
+	if (! P_CheckPosition(players[playernum].mo, x, y))
+	{
+		players[playernum].mo->flags2 |= MF2_PASSMOBJ;
+		return false;
+	}
+	players[playernum].mo->flags2 |= MF2_PASSMOBJ;
+
+// spawn a teleport fog
+	ss = R_PointInSubsector (x, y);
+	an = (ANG45 * (mthing->angle / 45)) >> ANGLETOFINESHIFT;
+
+	mo = P_SpawnMobj (x + 20*finecosine[an], y + 20*finesine[an],
+		ss->sector->floorheight + TELEFOGHEIGHT, MT_TFOG);
+
+	if (players[consoleplayer].viewz != 1)
+		S_StartSound (mo, SFX_TELEPORT);	// don't start sound on first frame
+
+	return true;
+}
+
+/*
+====================
+=
+= G_DeathMatchSpawnPlayer
+=
+= Spawns a player at one of the random death match spots
+= called at level load and each death
+====================
+*/
+
+void G_DeathMatchSpawnPlayer (int playernum)
+{
+	int		i, j;
+	int		selections;
+
+	selections = deathmatch_p - deathmatchstarts;
+
+	// This check has been moved to p_setup.c:P_LoadThings()
+	//if (selections < 8)
+	//	I_Error ("Only %i deathmatch spots, 8 required", selections);
+
+	for (j = 0; j < 20; j++)
+	{
+		i = P_Random() % selections;
+		if (G_CheckSpot (playernum, &deathmatchstarts[i]))
+		{
+			deathmatchstarts[i].type = playernum + 1;
+			P_SpawnPlayer (&deathmatchstarts[i]);
+			return;
+		}
+	}
+
+// no good spot, so the player will probably get stuck
+	P_SpawnPlayer (&playerstarts[0][playernum]);
+}
+
+//==========================================================================
+//
+// G_DoReborn
+//
+//==========================================================================
+
+static void G_DoReborn(int playernum)
+{
+	int i;
+	boolean oldWeaponowned[NUMWEAPONS];
+	int oldKeys;
+	int oldPieces;
+	boolean foundSpot;
+	int bestWeapon;
+
+	if (G_CheckDemoStatus())
+	{
+		return;
+	}
+	if (!netgame)
+	{
+		if (SV_RebornSlotAvailable())
+		{ // Use the reborn code if the slot is available
+			gameaction = ga_singlereborn;
+		}
+		else
+		{ // Start a new game if there's no reborn info
+			gameaction = ga_newgame;
+		}
+	}
+	else
+	{ // Net-game
+		players[playernum].mo->player = NULL;	// Dissassociate the corpse
+
+		if (deathmatch)
+		{ // Spawn at random spot if in death match
+			G_DeathMatchSpawnPlayer(playernum);
+			return;
+		}
+
+		// Cooperative net-play, retain keys and weapons
+		oldKeys = players[playernum].keys;
+		oldPieces = players[playernum].pieces;
+		for (i = 0; i < NUMWEAPONS; i++)
+		{
+			oldWeaponowned[i] = players[playernum].weaponowned[i];
+		}
+
+		foundSpot = false;
+		if (G_CheckSpot(playernum, &playerstarts[RebornPosition][playernum]))
+		{ // Appropriate player start spot is open
+			P_SpawnPlayer(&playerstarts[RebornPosition][playernum]);
+			foundSpot = true;
+		}
+		else
+		{
+			// Try to spawn at one of the other player start spots
+			for (i = 0; i < MAXPLAYERS; i++)
+			{
+				if (G_CheckSpot(playernum, &playerstarts[RebornPosition][i]))
+				{ // Found an open start spot
+					// Fake as other player
+					playerstarts[RebornPosition][i].type = playernum + 1;
+					P_SpawnPlayer(&playerstarts[RebornPosition][i]);
+
+					// Restore proper player type
+					playerstarts[RebornPosition][i].type = i + 1;
+
+					foundSpot = true;
+					break;
+				}
+			}
+		}
+
+		if (foundSpot == false)
+		{ // Player's going to be inside something
+			P_SpawnPlayer(&playerstarts[RebornPosition][playernum]);
+		}
+
+		// Restore keys and weapons
+		players[playernum].keys = oldKeys;
+		players[playernum].pieces = oldPieces;
+		for (bestWeapon = 0, i = 0; i < NUMWEAPONS; i++)
+		{
+			if (oldWeaponowned[i])
+			{
+				bestWeapon = i;
+				players[playernum].weaponowned[i] = true;
+			}
+		}
+		players[playernum].mana[MANA_1] = 25;
+		players[playernum].mana[MANA_2] = 25;
+		if (bestWeapon)
+		{ // Bring up the best weapon
+			players[playernum].pendingweapon = bestWeapon;
+		}
+	}
+}
+
+
+void G_ScreenShot (void)
+{
+	gameaction = ga_screenshot;
+}
+
+
+//==========================================================================
+//
+// G_StartNewInit
+//
+//==========================================================================
+
+void G_StartNewInit(void)
+{
+	SV_InitBaseSlot();
+	SV_ClearRebornSlot();
+	P_ACSInitNewGame();
+	// Default the player start spot group to 0
+	RebornPosition = 0;
+}
+
+//==========================================================================
+//
+// G_StartNewGame
+//
+//==========================================================================
+
+void G_StartNewGame(skill_t skill)
+{
+	int realMap;
+
+	G_StartNewInit();
+	realMap = P_TranslateMap(1);
+	if (realMap == -1)
+	{
+		realMap = 1;
+	}
+	G_InitNew(TempSkill, 1, realMap);
+}
+
+//==========================================================================
+//
+// G_TeleportNewMap
+//
+// Only called by the warp cheat code.  Works just like normal map to map
+// teleporting, but doesn't do any interlude stuff.
+//
+//==========================================================================
+
+void G_TeleportNewMap(int map, int position)
+{
+	gameaction = ga_leavemap;
+	LeaveMap = map;
+	LeavePosition = position;
+}
+
+//==========================================================================
+//
+// G_DoTeleportNewMap
+//
+//==========================================================================
+
+static void G_DoTeleportNewMap(void)
+{
+	SV_MapTeleport(LeaveMap, LeavePosition);
+	gamestate = GS_LEVEL;
+	gameaction = ga_nothing;
+	RebornPosition = LeavePosition;
+}
+
+/*
+boolean secretexit;
+void G_ExitLevel (void)
+{
+	secretexit = false;
+	gameaction = ga_completed;
+}
+void G_SecretExitLevel (void)
+{
+	secretexit = true;
+	gameaction = ga_completed;
+}
+*/
+
+//==========================================================================
+//
+// G_Completed
+//
+// Starts intermission routine, which is used only during hub exits,
+// and DeathMatch games.
+//==========================================================================
+
+void G_Completed(int map, int position)
+{
+	if (shareware && map > 4)
+	{
+		// Not possible in the 4-level demo.
+		P_SetMessage(&players[consoleplayer], "ACCESS DENIED -- DEMO", true);
+		return;
+	}
+
+	gameaction = ga_completed;
+	LeaveMap = map;
+	LeavePosition = position;
+}
+
+static void G_DoCompleted(void)
+{
+	int i;
+
+	gameaction = ga_nothing;
+	if (G_CheckDemoStatus())
+	{
+		return;
+	}
+	for (i = 0; i < MAXPLAYERS; i++)
+	{
+		if (playeringame[i])
+		{
+			G_PlayerExitMap(i);
+		}
+	}
+	if (LeaveMap == -1 && LeavePosition == -1)
+	{
+		gameaction = ga_victory;
+		return;
+	}
+	else
+	{
+		gamestate = GS_INTERMISSION;
+		IN_Start();
+	}
+
+	/*
+	int i;
+	static int afterSecret[3] = { 7, 5, 5 };
+
+	gameaction = ga_nothing;
+	if (G_CheckDemoStatus())
+	{
+		return;
+	}
+	for (i = 0; i < MAXPLAYERS; i++)
+	{
+		if (playeringame[i])
+		{
+			G_PlayerFinishLevel(i);
+		}
+	}
+	prevmap = gamemap;
+	if (secretexit == true)
+	{
+		gamemap = 9;
+	}
+	else if (gamemap == 9)
+	{ // Finished secret level
+		gamemap = afterSecret[gameepisode - 1];
+	}
+	else if (gamemap == 8)
+	{
+		gameaction = ga_victory;
+		return;
+	}
+	else
+	{
+		gamemap++;
+	}
+	gamestate = GS_INTERMISSION;
+	IN_Start();
+	*/
+}
+
+//============================================================================
+//
+// G_WorldDone
+//
+//============================================================================
+
+void G_WorldDone(void)
+{
+	gameaction = ga_worlddone;
+}
+
+//============================================================================
+//
+// G_DoWorldDone
+//
+//============================================================================
+
+static void G_DoWorldDone(void)
+{
+	gamestate = GS_LEVEL;
+	G_DoLoadLevel();
+	gameaction = ga_nothing;
+	viewactive = true;
+}
+
+//==========================================================================
+//
+// G_DoSingleReborn
+//
+// Called by G_Ticker based on gameaction.  Loads a game from the reborn
+// save slot.
+//
+//==========================================================================
+
+static void G_DoSingleReborn(void)
+{
+	gameaction = ga_nothing;
+	SV_LoadGame(SV_GetRebornSlot());
+	SB_SetClassData();
+}
+
+//==========================================================================
+//
+// G_LoadGame
+//
+// Can be called by the startup code or the menu task.
+//
+//==========================================================================
+
+void G_LoadGame(int slot)
+{
+	loadgameslot = slot;
+	gameaction = ga_loadgame;
+}
+
+//==========================================================================
+//
+// G_DoLoadGame
+//
+// Called by G_Ticker based on gameaction.
+//
+//==========================================================================
+
+void G_DoLoadGame(void)
+{
+	gameaction = ga_nothing;
+	SV_LoadGame(loadgameslot);
+	if (!netgame)
+	{ // Copy the base slot to the reborn slot
+		SV_UpdateRebornSlot();
+	}
+	SB_SetClassData();
+}
+
+//==========================================================================
+//
+// G_SaveGame
+//
+// Called by the menu task.  <description> is a 24 byte text string.
+//
+//==========================================================================
+
+void G_SaveGame(int slot, const char *description)
+{
+	savegameslot = slot;
+	strcpy(savedescription, description);
+	sendsave = true;
+}
+
+//==========================================================================
+//
+// G_DoSaveGame
+//
+// Called by G_Ticker based on gameaction.
+//
+//==========================================================================
+
+static void G_DoSaveGame(void)
+{
+	SV_SaveGame(savegameslot, savedescription);
+	gameaction = ga_nothing;
+	savedescription[0] = 0;
+	P_SetMessage(&players[consoleplayer], TXT_GAMESAVED, true);
+}
+
+//==========================================================================
+//
+// G_DeferredNewGame
+//
+//==========================================================================
+
+void G_DeferredNewGame(skill_t skill)
+{
+	TempSkill = skill;
+	gameaction = ga_newgame;
+}
+
+//==========================================================================
+//
+// G_DoNewGame
+//
+//==========================================================================
+
+static void G_DoNewGame(void)
+{
+	G_StartNewGame(TempSkill);
+	gameaction = ga_nothing;
+}
+
+/*
+====================
+=
+= G_InitNew
+=
+= Can be called by the startup code or the menu task
+= consoleplayer, displayplayer, playeringame[] should be set
+====================
+*/
+
+void G_DeferedInitNew(skill_t skill, int episode, int map)
+{
+	TempSkill = skill;
+	TempEpisode = episode;
+	TempMap = map;
+	gameaction = ga_initnew;
+}
+
+static void G_DoInitNew(void)
+{
+	SV_InitBaseSlot();
+	G_InitNew(TempSkill, TempEpisode, TempMap);
+	gameaction = ga_nothing;
+}
+
+void G_InitNew(skill_t skill, int episode, int map)
+{
+	int i;
+
+	if (paused)
+	{
+		paused = false;
+		S_ResumeSound();
+	}
+	if (skill < sk_baby)
+	{
+		skill = sk_baby;
+	}
+	if (skill > sk_nightmare)
+	{
+		skill = sk_nightmare;
+	}
+	if (map < 1)
+	{
+		map = 1;
+	}
+	if (map > 99)
+	{
+		map = 99;
+	}
+	M_ClearRandom();
+	// Force players to be initialized upon first level load
+	for (i = 0; i < MAXPLAYERS; i++)
+	{
+		players[i].playerstate = PST_REBORN;
+		players[i].worldTimer = 0;
+	}
+
+	// Set up a bunch of globals
+	usergame = true;	// will be set false if a demo
+	paused = false;
+	demorecording = false;
+	demoplayback = false;
+	viewactive = true;
+	gameepisode = episode;
+	gamemap = map;
+	gameskill = skill;
+	BorderNeedRefresh = true;
+
+	// Initialize the sky
+	R_InitSky(map);
+
+	// Give one null ticcmd_t
+	//gametic = 0;
+	//maketic = 1;
+	//for (i = 0; i < MAXPLAYERS; i++)
+	//	nettics[i] = 1;	// one null event for this gametic
+	//memset (localcmds, 0, sizeof(localcmds));
+	//memset (netcmds, 0, sizeof(netcmds));
+
+	G_DoLoadLevel();
+}
+
+/*
+===============================================================================
+
+							DEMO RECORDING
+
+===============================================================================
+*/
+
+#define DEMOMARKER	0x80
+
+static void G_ReadDemoTiccmd (ticcmd_t *cmd)
+{
+	if (*demo_p == DEMOMARKER)
+	{	// end of demo data stream
+		G_CheckDemoStatus ();
+		return;
+	}
+	cmd->forwardmove = ((signed char)*demo_p++);
+	cmd->sidemove = ((signed char)*demo_p++);
+	cmd->angleturn = ((unsigned char)*demo_p++)<<8;
+	cmd->buttons = (unsigned char)*demo_p++;
+	cmd->lookfly = (unsigned char)*demo_p++;
+	cmd->arti = (unsigned char)*demo_p++;
+}
+
+static void G_WriteDemoTiccmd (ticcmd_t *cmd)
+{
+	if (gamekeydown['q'])		// press q to end demo recording
+		G_CheckDemoStatus ();
+	*demo_p++ = (byte) cmd->forwardmove;
+	*demo_p++ = (byte) cmd->sidemove;
+	*demo_p++ = cmd->angleturn>>8;
+	*demo_p++ = cmd->buttons;
+	*demo_p++ = cmd->lookfly;
+	*demo_p++ = cmd->arti;
+	demo_p -= 6;
+	G_ReadDemoTiccmd (cmd);		// make SURE it is exactly the same
+}
+
+
+/*
+===================
+=
+= G_RecordDemo
+=
+===================
+*/
+
+void G_RecordDemo (skill_t skill, int numplayers, int episode, int map, const char *name)
+{
+	int		i;
+
+	G_InitNew (skill, episode, map);
+	usergame = false;
+	snprintf (demoname, sizeof(demoname), "%s%s.lmp", basePath, name);
+	demobuffer = demo_p = (byte *) Z_Malloc (0x20000, PU_STATIC, NULL);
+	*demo_p++ = skill;
+	*demo_p++ = episode;
+	*demo_p++ = map;
+
+	for (i = 0; i < MAXPLAYERS; i++)
+	{
+#if (MAXPLAYERS > MAXPLAYERS_10)
+	/* 8-player support is added to Hexen starting
+	 * with version 1.1.  If using 1.0 wad files,
+	 * don't write player data > 4 to the demo...
+	 * See also G_DoPlayDemo() below.
+	 * FIXME: What if the player count is > 4 ???
+	 */
+		if (oldwad_10 && i >= MAXPLAYERS_10)
+			break;
+#endif
+		*demo_p++ = playeringame[i];
+		*demo_p++ = PlayerClasses[i];
+	}
+	demorecording = true;
+}
+
+
+/*
+===================
+=
+= G_PlayDemo
+=
+===================
+*/
+
+static const char	*defdemoname;
+
+void G_DeferedPlayDemo (const char *name)
+{
+	defdemoname = name;
+	gameaction = ga_playdemo;
+}
+
+static void G_DoPlayDemo (void)
+{
+	skill_t	skill;
+	int	i, episode, map;
+
+	gameaction = ga_nothing;
+	demobuffer = demo_p = (byte *) W_CacheLumpName (defdemoname, PU_STATIC);
+	skill = *demo_p++;
+	episode = *demo_p++;
+	map = *demo_p++;
+
+	for (i = 0; i < MAXPLAYERS; i++)
+	{
+#if (MAXPLAYERS > MAXPLAYERS_10)
+	/* here is the tricky part: the demos in the
+	 * version 1.0 wad files are for MAXPLAYERS 4,
+	 * not 8. the check that I added below is not
+	 * accurate, though, because the demo may be
+	 * recorded using MAXPLAYERS == 8, ie. it may
+	 * not be from the wad file..
+	 * See also G_RecordDemo() above.
+	 */
+		if (oldwad_10 && i >= MAXPLAYERS_10)
+		{
+			playeringame[i] = 0;
+			PlayerClasses[i] = 0;
+			continue;
+		}
+#endif
+		playeringame[i] = *demo_p++;
+		PlayerClasses[i] = *demo_p++;
+	}
+
+	// Initialize world info, etc.
+	G_StartNewInit();
+
+	precache = false;		// don't spend a lot of time in loadlevel
+	G_InitNew (skill, episode, map);
+	precache = true;
+	usergame = false;
+	demoplayback = true;
+}
+
+
+/*
+===================
+=
+= G_TimeDemo
+=
+===================
+*/
+
+void G_TimeDemo (const char *name)
+{
+	skill_t	skill;
+	int	episode, map;
+
+	demobuffer = demo_p = (byte *) W_CacheLumpName (name, PU_STATIC);
+	skill = *demo_p++;
+	episode = *demo_p++;
+	map = *demo_p++;
+	G_InitNew (skill, episode, map);
+	usergame = false;
+	demoplayback = true;
+	timingdemo = true;
+	singletics = true;
+}
+
+
+/*
+===================
+=
+= G_CheckDemoStatus
+=
+= Called after a death or level completion to allow demos to be cleaned up
+= Returns true if a new demo loop action will take place
+===================
+*/
+
+boolean G_CheckDemoStatus (void)
+{
+	int		endtime;
+
+	if (timingdemo)
+	{
+		endtime = I_GetTime ();
+		I_Error ("timed %i gametics in %i realtics", gametic,
+						endtime - starttime);
+	}
+
+	if (demoplayback)
+	{
+		if (singledemo)
+			I_Quit ();
+
+		Z_ChangeTag (demobuffer, PU_CACHE);
+		demoplayback = false;
+		H2_AdvanceDemo();
+		return true;
+	}
+
+	if (demorecording)
+	{
+		*demo_p++ = DEMOMARKER;
+		M_WriteFile (demoname, demobuffer, demo_p - demobuffer);
+		Z_Free (demobuffer);
+		demorecording = false;
+		I_Error ("Recorded demo: %s", demoname);
+	}
+
+	return false;
+}
+
--- /dev/null
+++ b/h2_main.c
@@ -1,0 +1,964 @@
+
+//**************************************************************************
+//**
+//** h2_main.c : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 586 $
+//** $Date: 2012-08-31 21:51:13 +0300 (Fri, 31 Aug 2012) $
+//**
+//**************************************************************************
+
+// HEADER FILES ------------------------------------------------------------
+
+#include "h2stdinc.h"
+#include <ctype.h>
+#include "h2def.h"
+#include "p_local.h"
+#include "soundst.h"
+#include "v_compat.h"
+
+// MACROS ------------------------------------------------------------------
+
+#define MAXWADFILES		20
+
+#ifdef RENDER3D
+#define V_DrawPatch(x,y,p)		OGL_DrawPatch((x),(y),(p))
+#define V_DrawRawScreen(a)		OGL_DrawRawScreen((a))
+#endif
+
+// TYPES -------------------------------------------------------------------
+
+typedef struct
+{
+	const char *name;
+	void (*func)(const char **args, int tag);
+	int	requiredArgs;
+	int		tag;
+} execOpt_t;
+
+// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
+
+void R_ExecuteSetViewSize(void);
+void D_CheckNetGame(void);
+void G_BuildTiccmd(ticcmd_t *cmd);
+void F_Drawer(void);
+boolean F_Responder(event_t *ev);
+void I_StartupKeyboard(void);
+void I_StartupJoystick(void);
+void I_ShutdownKeyboard(void);
+void S_InitScript(void);
+
+// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
+
+void H2_ProcessEvents(void);
+void H2_DoAdvanceDemo(void);
+void H2_AdvanceDemo(void);
+void H2_StartTitle(void);
+void H2_PageTicker(void);
+
+// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
+
+static void DrawMessage(void);
+static void PageDrawer(void);
+static void HandleArgs(void);
+static void CheckRecordFrom(void);
+static void AddWADFile(const char *file);
+static void DrawAndBlit(void);
+static void ExecOptionFILE(const char **args, int tag);
+static void ExecOptionSCRIPTS(const char **args, int tag);
+static void ExecOptionDEVMAPS(const char **args, int tag);
+static void ExecOptionSKILL(const char **args, int tag);
+static void ExecOptionPLAYDEMO(const char **args, int tag);
+static void ExecOptionMAXZONE(const char **args, int tag);
+static void WarpCheck(void);
+
+
+// EXTERNAL DATA DECLARATIONS ----------------------------------------------
+
+extern boolean MenuActive;
+extern boolean askforquit;
+
+// PUBLIC DATA DEFINITIONS -------------------------------------------------
+
+const char *basePath = DUMMY_BASEPATH;
+boolean DevMaps;			// true = Map development mode
+const char *DevMapsDir = "";		// development maps directory
+boolean shareware;			// true if only episode 1 present
+boolean oldwad_10;			// true if version 1.0 wad files
+boolean mac_hexen;			// true if Macintosh version wad
+boolean nomonsters;			// checkparm of -nomonsters
+boolean respawnparm;		// checkparm of -respawn
+boolean randomclass;		// checkparm of -randclass
+boolean debugmode;			// checkparm of -debug
+boolean ravpic;				// checkparm of -ravpic
+boolean cmdfrag;			// true if a CMD_FRAG packet should be sent out
+boolean singletics;			// debug flag to cancel adaptiveness
+boolean artiskip;			// whether shift-enter skips an artifact
+int maxzone = 0x800000;		// Maximum allocated for zone heap (8meg default)
+skill_t startskill;
+int startepisode;
+int startmap;
+boolean autostart;
+boolean advancedemo;
+FILE *debugfile;
+event_t events[MAXEVENTS];
+int eventhead;
+int eventtail;
+
+// PRIVATE DATA DEFINITIONS ------------------------------------------------
+
+static int WarpMap;
+static int demosequence;
+static int pagetic;
+static const char *pagename;
+
+static const char *wadfiles[MAXWADFILES + 1] =
+{
+	"hexen.wad",
+#ifdef ASSASSIN
+	"assassin.wad",
+#endif
+	NULL	/* the last entry MUST be NULL */
+};
+static execOpt_t ExecOptions[] =
+{
+	{ "-file", ExecOptionFILE, 1, 0 },
+	{ "-scripts", ExecOptionSCRIPTS, 1, 0 },
+	{ "-devmaps", ExecOptionDEVMAPS, 1, 0 },
+	{ "-skill", ExecOptionSKILL, 1, 0 },
+	{ "-playdemo", ExecOptionPLAYDEMO, 1, 0 },
+	{ "-timedemo", ExecOptionPLAYDEMO, 1, 0 },
+	{ "-maxzone", ExecOptionMAXZONE, 1, 0 },
+	{ NULL, NULL, 0, 0 } // Terminator
+};
+
+// CODE --------------------------------------------------------------------
+
+#if !(defined(__DOS__) || defined(__WATCOMC__) || defined(__DJGPP__) || defined(_WIN32) || defined(_WIN64))
+char *strlwr (char *str)
+{
+	char	*c;
+	c = str;
+	while (*c)
+	{
+		*c = tolower(*c);
+		c++;
+	}
+	return str;
+}
+
+char *strupr (char *str)
+{
+	char	*c;
+	c = str;
+	while (*c)
+	{
+		*c = toupper(*c);
+		c++;
+	}
+	return str;
+}
+
+int filelength(int handle)
+{
+	Dir *d;
+	int length;
+
+	d = dirfstat(handle);
+	if (d == nil)
+	{
+		I_Error("Error fstating");
+	}
+	length = d->length;
+	free(d);
+	return length;
+}
+#endif
+
+//==========================================================================
+//
+// H2_Main
+//
+//==========================================================================
+void InitMapMusicInfo(void);
+
+void H2_Main(void)
+{
+	int p;
+
+	M_FindResponseFile();
+	setbuf(stdout, NULL);
+	startepisode = 1;
+	autostart = false;
+	startskill = sk_medium;
+	startmap = 1;
+
+	HandleArgs();
+
+	// Initialize subsystems
+
+	ST_Message("V_Init: allocate screens.\n");
+	V_Init();
+
+	// Load defaults before initing other systems
+	ST_Message("M_LoadDefaults: Load system defaults.\n");
+	M_LoadDefaults(CONFIG_FILE_NAME);
+
+	// HEXEN MODIFICATION:
+	// There is a realloc() in W_AddFile() that might fail if the zone
+	// heap has been previously allocated, so we need to initialize the
+	// WAD files BEFORE the zone memory initialization.
+	ST_Message("W_Init: Init WADfiles.\n");
+	W_InitMultipleFiles(wadfiles);
+	W_CheckWADFiles();
+
+	ST_Message("Z_Init: Init zone memory allocation daemon.\n");
+	Z_Init();
+
+	ST_Message("MN_Init: Init menu system.\n");
+	MN_Init();
+
+	ST_Message("CT_Init: Init chat mode data.\n");
+	CT_Init();
+
+	InitMapMusicInfo();		// Init music fields in mapinfo
+
+	ST_Message("S_InitScript\n");
+	S_InitScript();
+
+	ST_Message("SN_InitSequenceScript: Registering sound sequences.\n");
+	SN_InitSequenceScript();
+	ST_Message("I_Init: Setting up machine state.\n");
+	I_Init();
+
+	ST_Message("ST_Init: Init startup screen.\n");
+	ST_Init();
+
+	S_StartSongName("orb", true);
+
+	// Show version message now, so it's visible during R_Init()
+	ST_Message("Executable: "VERSIONTEXT".\n");
+
+	ST_Message("R_Init: Init Hexen refresh daemon");
+	R_Init();
+	ST_Message("\n");
+
+	if (M_CheckParm("-net"))
+		ST_NetProgress();	// Console player found
+
+	ST_Message("P_Init: Init Playloop state.\n");
+	P_Init();
+
+	// Check for command line warping. Follows P_Init() because the
+	// MAPINFO.TXT script must be already processed.
+	WarpCheck();
+
+	if (autostart)
+	{
+		ST_Message("Warp to Map %d (\"%s\":%d), Skill %d\n",
+			WarpMap, P_GetMapName(startmap), startmap, startskill + 1);
+	}
+
+	ST_Message("D_CheckNetGame: Checking network game status.\n");
+	D_CheckNetGame();
+
+	ST_Message("SB_Init: Loading patches.\n");
+	SB_Init();
+
+	CheckRecordFrom();
+
+	p = M_CheckParm("-record");
+	if (p && p < myargc - 1)
+	{
+		G_RecordDemo(startskill, 1, startepisode, startmap, myargv[p + 1]);
+		H2_GameLoop(); // Never returns
+	}
+
+	p = M_CheckParm("-playdemo");
+	if (p && p < myargc - 1)
+	{
+		singledemo = true; // Quit after one demo
+		G_DeferedPlayDemo(myargv[p + 1]);
+		H2_GameLoop(); // Never returns
+	}
+
+	p = M_CheckParm("-timedemo");
+	if (p && p < myargc - 1)
+	{
+		G_TimeDemo(myargv[p + 1]);
+		H2_GameLoop(); // Never returns
+	}
+
+	p = M_CheckParm("-loadgame");
+	if (p && p < myargc - 1)
+	{
+		G_LoadGame(atoi(myargv[p + 1]));
+	}
+
+	if (gameaction != ga_loadgame)
+	{
+		UpdateState |= I_FULLSCRN;
+		BorderNeedRefresh = true;
+		if (autostart || netgame)
+		{
+			G_StartNewInit();
+			G_InitNew(startskill, startepisode, startmap);
+		}
+		else
+		{
+			H2_StartTitle();
+		}
+	}
+	H2_GameLoop(); // Never returns
+}
+
+//==========================================================================
+//
+// HandleArgs
+//
+//==========================================================================
+
+static void HandleArgs(void)
+{
+	int p;
+	execOpt_t *opt;
+
+	nomonsters = M_ParmExists("-nomonsters");
+	respawnparm = M_ParmExists("-respawn");
+	randomclass = M_ParmExists("-randclass");
+	ravpic = M_ParmExists("-ravpic");
+	artiskip = M_ParmExists("-artiskip");
+	debugmode = M_ParmExists("-debug");
+	deathmatch = M_ParmExists("-deathmatch");
+	cmdfrag = M_ParmExists("-cmdfrag");
+
+	// Process command line options
+	for (opt = ExecOptions; opt->name != NULL; opt++)
+	{
+		p = M_CheckParm(opt->name);
+		if (p && p < myargc-opt->requiredArgs)
+		{
+			opt->func(&myargv[p], opt->tag);
+		}
+	}
+
+	// Look for an external device driver
+	I_CheckExternDriver();
+}
+
+//==========================================================================
+//
+// WarpCheck
+//
+//==========================================================================
+
+static void WarpCheck(void)
+{
+	int p;
+	int map;
+
+	p = M_CheckParm("-warp");
+	if (p && p < myargc - 1)
+	{
+		WarpMap = atoi(myargv[p + 1]);
+		map = P_TranslateMap(WarpMap);
+		if (map == -1)
+		{ // Couldn't find real map number
+			startmap = 1;
+			ST_Message("-WARP: Invalid map number.\n");
+		}
+		else
+		{ // Found a valid startmap
+			startmap = map;
+			autostart = true;
+		}
+	}
+	else
+	{
+		WarpMap = 1;
+		startmap = P_TranslateMap(1);
+		if (startmap == -1)
+		{
+			startmap = 1;
+		}
+	}
+}
+
+//==========================================================================
+//
+// ExecOptionSKILL
+//
+//==========================================================================
+
+static void ExecOptionSKILL(const char **args, int tag)
+{
+	startskill = args[1][0] - '1';
+	autostart = true;
+}
+
+//==========================================================================
+//
+// ExecOptionFILE
+//
+//==========================================================================
+
+static void ExecOptionFILE(const char **args, int tag)
+{
+	int p;
+
+	p = M_CheckParm("-file");
+	while (++p != myargc && myargv[p][0] != '-')
+	{
+		AddWADFile(myargv[p]);
+	}
+}
+
+
+//==========================================================================
+//
+// ExecOptionPLAYDEMO
+//
+//==========================================================================
+
+static void ExecOptionPLAYDEMO(const char **args, int tag)
+{
+	char file[256];
+
+	snprintf(file, sizeof(file), "%s.lmp", args[1]);
+	AddWADFile(file);
+	ST_Message("Playing demo %s.lmp.\n", args[1]);
+}
+
+//==========================================================================
+//
+// ExecOptionSCRIPTS
+//
+//==========================================================================
+
+static void ExecOptionSCRIPTS(const char **args, int tag)
+{
+	sc_FileScripts = true;
+	sc_ScriptsDir = args[1];
+}
+
+//==========================================================================
+//
+// ExecOptionDEVMAPS
+//
+//==========================================================================
+
+static void ExecOptionDEVMAPS(const char **args, int tag)
+{
+	char *ptr;
+	DevMaps = true;
+	ST_Message("Map development mode enabled:\n");
+	ST_Message("[config    ] = %s\n", args[1]);
+	SC_OpenFileCLib(args[1]);
+	SC_MustGetStringName("mapsdir");
+	SC_MustGetString();
+	ST_Message("[mapsdir   ] = %s\n", sc_String);
+	ptr = (char *) malloc(strlen(sc_String) + 1);
+	strcpy(ptr, sc_String);
+	DevMapsDir = ptr;
+	SC_MustGetStringName("scriptsdir");
+	SC_MustGetString();
+	ST_Message("[scriptsdir] = %s\n", sc_String);
+	sc_FileScripts = true;
+	ptr = (char *) malloc(strlen(sc_String) + 1);
+	strcpy(ptr, sc_String);
+	sc_ScriptsDir = ptr;
+	while (SC_GetString())
+	{
+		if (SC_Compare("file"))
+		{
+			SC_MustGetString();
+			AddWADFile(sc_String);
+		}
+		else
+		{
+			SC_ScriptError(NULL);
+		}
+	}
+	SC_Close();
+}
+
+
+static long superatol(const char *s)
+{
+	long int n = 0, r = 10, x, mul = 1;
+	const char *c = s;
+
+	for ( ; *c; c++)
+	{
+		x = (*c & 223) - 16;
+
+		if (x == -3)
+		{
+			mul = -mul;
+		}
+		else if (x == 72 && r == 10)
+		{
+			n -= (r = n);
+			if (!r)
+				r = 16;
+			if (r < 2 || r > 36)
+				return -1;
+		}
+		else
+		{
+			if (x > 10)
+				x -= 39;
+			if (x >= r)
+				return -1;
+			n = (n*r) + x;
+		}
+	}
+	return (mul*n);
+}
+
+static void ExecOptionMAXZONE(const char **args, int tag)
+{
+	int size;
+
+	size = (int) superatol(args[1]);
+	if (size < MINIMUM_HEAP_SIZE)
+		size = MINIMUM_HEAP_SIZE;
+	if (size > MAXIMUM_HEAP_SIZE)
+		size = MAXIMUM_HEAP_SIZE;
+	maxzone = size;
+}
+
+//==========================================================================
+//
+// H2_GameLoop
+//
+//==========================================================================
+
+void H2_GameLoop(void)
+{
+	if (M_CheckParm("-debugfile"))
+	{
+		char filename[20];
+		snprintf(filename, sizeof(filename), "debug%i.txt", consoleplayer);
+		debugfile = fopen(filename,"w");
+	}
+	I_InitGraphics();
+	while (1)
+	{
+		// Frame syncronous IO operations
+		I_StartFrame();
+
+		// Process one or more tics
+		if (singletics)
+		{
+			I_StartTic();
+			H2_ProcessEvents();
+			G_BuildTiccmd(&netcmds[consoleplayer][maketic % BACKUPTICS]);
+			if (advancedemo)
+			{
+				H2_DoAdvanceDemo();
+			}
+			G_Ticker();
+			gametic++;
+			maketic++;
+		}
+		else
+		{
+			// Will run at least one tic
+			TryRunTics();
+		}
+
+		// Move positional sounds
+		S_UpdateSounds(players[displayplayer].mo);
+
+		DrawAndBlit();
+	}
+}
+
+//==========================================================================
+//
+// H2_ProcessEvents
+//
+// Send all the events of the given timestamp down the responder chain.
+//
+//==========================================================================
+
+void H2_ProcessEvents(void)
+{
+	event_t *ev;
+
+	while (eventtail != eventhead)
+	{
+		ev = &events[eventtail];
+		if (F_Responder(ev))
+		{
+			goto _next_ev;
+		}
+		if (MN_Responder(ev))
+		{
+			goto _next_ev;
+		}
+		G_Responder(ev);
+	_next_ev:
+		eventtail = (eventtail + 1) & (MAXEVENTS - 1);
+	}
+}
+
+//==========================================================================
+//
+// H2_PostEvent
+//
+// Called by the I/O functions when input is detected.
+//
+//==========================================================================
+
+void H2_PostEvent(event_t *ev)
+{
+	events[eventhead] = *ev;
+	eventhead++;
+	eventhead &= (MAXEVENTS - 1);
+}
+
+//==========================================================================
+//
+// DrawAndBlit
+//
+//==========================================================================
+
+static void DrawAndBlit(void)
+{
+	// Change the view size if needed
+	if (setsizeneeded)
+	{
+		R_ExecuteSetViewSize();
+	}
+
+	// Do buffered drawing
+	switch (gamestate)
+	{
+	case GS_LEVEL:
+		if (!gametic)
+			break;
+#if  AM_TRANSPARENT
+		R_RenderPlayerView(&players[displayplayer]);
+#endif
+		if (automapactive)
+			AM_Drawer();
+#if !AM_TRANSPARENT
+		else
+		{
+			R_RenderPlayerView(&players[displayplayer]);
+		}
+#endif
+		CT_Drawer();
+		UpdateState |= I_FULLVIEW;
+		SB_Drawer();
+		break;
+	case GS_INTERMISSION:
+		IN_Drawer();
+		break;
+	case GS_FINALE:
+		F_Drawer();
+		break;
+	case GS_DEMOSCREEN:
+		PageDrawer();
+		break;
+	}
+
+	if (paused && !MenuActive && !askforquit)
+	{
+		if (!netgame)
+		{
+			V_DrawPatch(160, viewwindowy + 5, (PATCH_REF)WR_CacheLumpName("PAUSED", PU_CACHE));
+		}
+		else
+		{
+			V_DrawPatch(160, 70, (PATCH_REF)WR_CacheLumpName("PAUSED", PU_CACHE));
+		}
+	}
+
+#ifdef RENDER3D
+	if (OGL_DrawFilter())
+		BorderNeedRefresh = true;
+#endif
+
+	// Draw current message
+	DrawMessage();
+
+	// Draw Menu
+	MN_Drawer();
+
+	// Send out any new accumulation
+	NetUpdate();
+
+	// Flush buffered stuff to screen
+	I_Update();
+}
+
+//==========================================================================
+//
+// DrawMessage
+//
+//==========================================================================
+
+static void DrawMessage(void)
+{
+	player_t *player;
+
+	player = &players[consoleplayer];
+	if (player->messageTics <= 0 || !player->message)
+	{ // No message
+		return;
+	}
+	if (player->yellowMessage)
+	{
+		MN_DrTextAYellow(player->message, 160 - MN_TextAWidth(player->message)/2, 1);
+	}
+	else
+	{
+		MN_DrTextA(player->message, 160 - MN_TextAWidth(player->message)/2, 1);
+	}
+}
+
+//==========================================================================
+//
+// H2_PageTicker
+//
+//==========================================================================
+
+void H2_PageTicker(void)
+{
+	if (--pagetic < 0)
+	{
+		H2_AdvanceDemo();
+	}
+}
+
+//==========================================================================
+//
+// PageDrawer
+//
+//==========================================================================
+
+static void PageDrawer(void)
+{
+	V_DrawRawScreen((BYTE_REF)WR_CacheLumpName(pagename, PU_CACHE));
+	if (demosequence == 1)
+	{
+		V_DrawPatch(4, 160, (PATCH_REF)WR_CacheLumpName("ADVISOR", PU_CACHE));
+	}
+	UpdateState |= I_FULLSCRN;
+}
+
+//==========================================================================
+//
+// H2_AdvanceDemo
+//
+// Called after each demo or intro demosequence finishes.
+//
+//==========================================================================
+
+void H2_AdvanceDemo(void)
+{
+	advancedemo = true;
+}
+
+//==========================================================================
+//
+// H2_DoAdvanceDemo
+//
+//==========================================================================
+
+void H2_DoAdvanceDemo(void)
+{
+	players[consoleplayer].playerstate = PST_LIVE; // don't reborn
+	advancedemo = false;
+	usergame = false; // can't save/end game here
+	paused = false;
+	gameaction = ga_nothing;
+	demosequence = (demosequence + 1) % 7;
+	switch (demosequence)
+	{
+	case 0:
+		pagetic = 280;
+		gamestate = GS_DEMOSCREEN;
+		pagename = "TITLE";
+		S_StartSongName("hexen", true);
+		break;
+	case 1:
+		pagetic = 210;
+		gamestate = GS_DEMOSCREEN;
+		pagename = "TITLE";
+		break;
+	case 2:
+		BorderNeedRefresh = true;
+		UpdateState |= I_FULLSCRN;
+		G_DeferedPlayDemo("demo1");
+		break;
+	case 3:
+		pagetic = 200;
+		gamestate = GS_DEMOSCREEN;
+		pagename = "CREDIT";
+		break;
+	case 4:
+		BorderNeedRefresh = true;
+		UpdateState |= I_FULLSCRN;
+		G_DeferedPlayDemo("demo2");
+		break;
+	case 5:
+		pagetic = 200;
+		gamestate = GS_DEMOSCREEN;
+		pagename = (mac_hexen == true)	? "PRSGCRED"	/* credits for Mac port by Presage */
+						: "CREDIT";	/* original Raven/iD credits page . */
+		break;
+	case 6:
+		BorderNeedRefresh = true;
+		UpdateState |= I_FULLSCRN;
+		G_DeferedPlayDemo("demo3");
+		break;
+	}
+}
+
+//==========================================================================
+//
+// H2_StartTitle
+//
+//==========================================================================
+
+void H2_StartTitle(void)
+{
+	gameaction = ga_nothing;
+	demosequence = -1;
+	H2_AdvanceDemo();
+}
+
+//==========================================================================
+//
+// CheckRecordFrom
+//
+// -recordfrom <savegame num> <demoname>
+//
+//==========================================================================
+
+static void CheckRecordFrom(void)
+{
+	int p;
+
+	p = M_CheckParm("-recordfrom");
+	if (!p || p >= myargc - 2)
+	{ // Bad args
+		return;
+	}
+	G_LoadGame(atoi(myargv[p + 1]));
+	G_DoLoadGame(); // Load the gameskill etc info from savegame
+	G_RecordDemo(gameskill, 1, gameepisode, gamemap, myargv[p + 2]);
+	H2_GameLoop(); // Never returns
+}
+
+//==========================================================================
+//
+// AddWADFile
+//
+//==========================================================================
+
+static void AddWADFile(const char *file)
+{
+	int i = 0;
+	char *newwad;
+
+	ST_Message("Adding external file: %s\n", file);
+	while (wadfiles[i])
+	{
+		if (++i == MAXWADFILES)
+			I_Error ("MAXWADFILES reached for %s", file);
+	}
+	newwad = (char *) malloc(strlen(file) + 1);
+	strcpy(newwad, file);
+	wadfiles[i] = newwad;
+	if (++i <= MAXWADFILES)
+		wadfiles[i] = NULL;
+}
+
+
+//==========================================================================
+//
+// Fixed Point math
+//
+//==========================================================================
+
+#if defined(_HAVE_FIXED_ASM)
+
+#if defined(__i386__) || defined(__386__) || defined(_M_IX86)
+#if defined(__GNUC__) && !defined(_INLINE_FIXED_ASM)
+fixed_t	FixedMul (fixed_t a, fixed_t b)
+{
+	fixed_t retval;
+	__asm__ __volatile__(
+		"imull  %%edx			\n\t"
+		"shrdl  $16, %%edx, %%eax	\n\t"
+		: "=a" (retval)
+		: "a" (a), "d" (b)
+		: "cc"
+	);
+	return retval;
+}
+
+fixed_t	FixedDiv2 (fixed_t a, fixed_t b)
+{
+	fixed_t retval;
+	__asm__ __volatile__(
+		"cdq				\n\t"
+		"shldl  $16, %%eax, %%edx	\n\t"
+		"sall   $16, %%eax		\n\t"
+		"idivl  %%ebx			\n\t"
+		: "=a" (retval)
+		: "a" (a), "b" (b)
+		: "%edx", "cc"
+	);
+	return retval;
+}
+#endif	/* GCC and !_INLINE_FIXED_ASM */
+#endif	/* x86 */
+
+#else	/* C-only versions */
+
+fixed_t FixedMul (fixed_t a, fixed_t b)
+{
+	return ((int64_t) a * (int64_t) b) >> 16;
+}
+
+fixed_t FixedDiv2 (fixed_t a, fixed_t b)
+{
+	if (!b)
+		return 0;
+	return (fixed_t) (((double) a / (double) b) * FRACUNIT);
+}
+#endif
+
+fixed_t FixedDiv (fixed_t a, fixed_t b)
+{
+	if ((abs(a) >> 14) >= abs(b))
+	{
+		return ((a^b) < 0 ? H2MININT : H2MAXINT);
+	}
+	return (FixedDiv2(a, b));
+}
+
+//==========================================================================
+//
+// Byte swap functions
+//
+//==========================================================================
+
+int16_t ShortSwap (int16_t x)
+{
+	return (int16_t) (((uint16_t)x << 8) | ((uint16_t)x >> 8));
+}
+
+int32_t LongSwap (int32_t x)
+{
+	return (int32_t) (((uint32_t)x << 24) | ((uint32_t)x >> 24) |
+			  (((uint32_t)x & (uint32_t)0x0000ff00UL) << 8) |
+			  (((uint32_t)x & (uint32_t)0x00ff0000UL) >> 8));
+}
+
--- /dev/null
+++ b/h2def.h
@@ -1,0 +1,1695 @@
+
+//**************************************************************************
+//**
+//** h2def.h : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 590 $
+//** $Date: 2012-10-23 23:55:31 +0300 (Tue, 23 Oct 2012) $
+//**
+//**************************************************************************
+
+#ifndef __H2DEF__
+#define __H2DEF__
+
+/* if rangecheck is undefined, most parameter
+ * validation debugging code will not be compiled
+ */
+#ifndef NORANGECHECKING
+#define RANGECHECK	1
+#endif
+
+#define __STRINGIFY(x) #x
+#define STRINGIFY(x) __STRINGIFY(x)
+
+/* 8-player support is added by hexen version 1.1:
+ * Hexen v1.0 supported 4 players, just like Doom.
+ * Changing the following MAXPLAYERS macros would
+ * break many things.
+ */
+#define MAXPLAYERS_10	4
+#define MAXPLAYERS_11	8
+#if defined(VERSION10_WAD)
+#define MAXPLAYERS	(MAXPLAYERS_10)
+#else
+#define MAXPLAYERS	(MAXPLAYERS_11)
+#endif
+
+#if (MAXPLAYERS == MAXPLAYERS_10)
+#define VERSION		100
+#define VERSION_TEXT	"v1.0"
+#else
+#define VERSION		110
+#define VERSION_TEXT	"v1.1"
+#endif
+
+#define VERSION_MAJ	1
+#define VERSION_MIN	6
+#define VERSION_PATCH	3
+#define HHEXEN_VERSION	"v" STRINGIFY(VERSION_MAJ) "." STRINGIFY(VERSION_MIN) "." STRINGIFY(VERSION_PATCH)
+
+#if 0
+/* Version texts of old releases */
+#define VERSIONTEXT	"ID V1.2"
+#define VERSIONTEXT	"RETAIL STORE BETA"	/* 9/26/95 */
+#define VERSIONTEXT	"DVL BETA 10 05 95"	/* Used for GT for testing */
+#define VERSIONTEXT	"DVL BETA 10 07 95"	/* Just an update for Romero */
+#define VERSIONTEXT	"FINAL 1.0 (10 13 95)"	/* Just an update for Romero */
+#endif
+
+/*
+#define VER_ID		"RETAIL"
+*/
+#define VER_ID		"DVL"
+
+#if (MAXPLAYERS == MAXPLAYERS_10)
+#define VER_ID2		VER_ID "/4PLYR"
+#else
+#define VER_ID2		VER_ID "/8PLYR"
+#endif
+
+#ifdef RANGECHECK
+#define VER_ID_FINAL	VER_ID2 "+R"
+#else
+#define VER_ID_FINAL	VER_ID2
+#endif
+
+#define VERSIONTEXT	HHEXEN_VERSION " " __DATE__ " (" VER_ID_FINAL ")"
+
+#if defined(__linux)
+#define VERSION_PLATFORM "Linux"
+#elif defined (__FreeBSD__)
+#define VERSION_PLATFORM "FreeBSD"
+#elif defined (_WIN32)
+#define VERSION_PLATFORM "Windows"
+#else
+#define VERSION_PLATFORM "Unknown"
+#endif
+
+/* compatibility definitions: */
+#if defined(_WIN32) && !defined(F_OK)
+/* values for the mode argument of access(). MS does not define them.
+   these aren't in h2stdinc.h, because not all files include io.h or
+   unistd.h */
+#define	R_OK	4		/* Test for read permission.  */
+#define	W_OK	2		/* Test for write permission.  */
+#define	X_OK	1		/* Test for execute permission.  */
+#define	F_OK	0		/* Test for existence.  */
+#endif
+
+/* max length of a filesystem pathname	*/
+#define	MAX_OSPATH		256
+
+#define	DATA_ENVVAR		"HHEXEN_DATA"
+#define	H_USERDIR		".hhexen"
+
+/* path to the user directory with a trailing
+ * directory separator character. initialized
+ * to DUMMY_BASEPATH string, which is "./" or
+ * empty string "", so that it will have no
+ * effect when user directories are disabled.
+ */
+extern	const char		*basePath;
+#define	DUMMY_BASEPATH		""
+
+#define	CONFIG_FILE_NAME	"hhexen.cfg"
+
+
+#include "st_start.h"
+
+/* all exterior data is defined here */
+#include "xddefs.h"
+
+/* all important printed strings */
+#include "textdefs.h"
+
+/* header generated by multigen utility */
+#include "info.h"
+
+extern	byte	*destview, *destscreen;	/* PC direct to screen pointers */
+
+/* most key data are simple ascii (uppercased) */
+#define	KEY_TAB			9
+#define	KEY_ENTER		13
+#define	KEY_ESCAPE		27
+#define	KEY_SPACE		32	/* 0x20 */
+#define	KEY_MINUS		45	/* 0x2D */
+
+#define	KEY_FIVE		53	/* 0x35 */
+#define	KEY_SIX			54	/* 0x36 */
+#define	KEY_SEVEN		55	/* 0x37 */
+#define	KEY_EIGHT		56	/* 0x38 */
+#define	KEY_NINE		57	/* 0x39 */
+#define	KEY_ZERO		48	/* 0x30 */
+
+#define	KEY_EQUALS		61	/* 0x3D */
+
+/* These added by S.A. */
+#define KEY_LEFTBRACKET		91
+#define KEY_RIGHTBRACKET	93
+#define KEY_BACKQUOTE		96
+#define KEY_QUOTEDBL		34
+#define KEY_QUOTE		39
+#define KEY_SEMICOLON		59
+#define KEY_PERIOD		46
+#define KEY_COMMA		44
+#define KEY_SLASH		47
+
+#define	KEY_BACKSLASH		92	/* 0x5C */
+
+#define	KEY_BACKSPACE		127	/* 0x7F */
+
+#define	KEY_UPARROW		128	/* 0x80 */
+#define	KEY_DOWNARROW		129
+#define	KEY_LEFTARROW		130
+#define	KEY_RIGHTARROW		131
+
+#define	KEY_ALT			132
+#define	KEY_LALT		KEY_ALT
+#define	KEY_RALT		KEY_ALT
+
+#define	KEY_CTRL		133
+#define	KEY_LCTRL		KEY_CTRL
+#define	KEY_RCTRL		KEY_CTRL
+
+#define	KEY_SHIFT		134
+#define	KEY_LSHIFT		KEY_SHIFT
+#define	KEY_RSHIFT		KEY_SHIFT
+
+#define	KEY_F1			135
+#define	KEY_F2			136
+#define	KEY_F3			137
+#define	KEY_F4			138
+#define	KEY_F5			139
+#define	KEY_F6			140
+#define	KEY_F7			141
+#define	KEY_F8			142
+#define	KEY_F9			143
+#define	KEY_F10			144
+#define	KEY_F11			145
+#define	KEY_F12			146
+#define	KEY_INS			147
+#define	KEY_DEL			148
+#define	KEY_PGDN		149
+#define	KEY_PGUP		150
+#define	KEY_HOME		151
+#define	KEY_END			152
+
+#define KEY_PAUSE		255	/* 0xFF */
+
+/* mouse buttons */
+#define	KEY_MOUSE1		200	/* 0xC8 */
+#define	KEY_MOUSE2		201	/* right mouse button			*/
+#define	KEY_MOUSE3		202	/* middle mouse button			*/
+#define	KEY_MWHEELUP		203	/* wheel-up as a virtual button		*/
+#define	KEY_MWHEELDOWN		204	/* wheel-down as a virtual button	*/
+#define	KEY_MOUSE4		205	/* thumb buttons			*/
+#define	KEY_MOUSE5		206	/* thumb buttons			*/
+
+/* joystick buttons */
+#define	KEY_JOY1		207
+#define	KEY_JOY2		208
+#define	KEY_JOY3		209
+#define	KEY_JOY4		210
+
+/* aux keys, for multi-buttoned joysticks */
+#define	KEY_AUX1		211
+#define	KEY_AUX2		212
+#define	KEY_AUX3		213
+#define	KEY_AUX4		214
+#define	KEY_AUX5		215
+#define	KEY_AUX6		216
+#define	KEY_AUX7		217
+#define	KEY_AUX8		218
+#define	KEY_AUX9		219
+#define	KEY_AUX10		220
+#define	KEY_AUX11		221
+#define	KEY_AUX12		222
+#define	KEY_AUX13		223
+#define	KEY_AUX14		224
+#define	KEY_AUX15		225
+#define	KEY_AUX16		226
+#define	KEY_AUX17		227
+#define	KEY_AUX18		228
+#define	KEY_AUX19		229
+#define	KEY_AUX20		230
+#define	KEY_AUX21		231
+#define	KEY_AUX22		232
+#define	KEY_AUX23		233
+#define	KEY_AUX24		234
+#define	KEY_AUX25		235
+#define	KEY_AUX26		236
+#define	KEY_AUX27		237
+#define	KEY_AUX28		238
+#define	KEY_AUX29		239
+#define	KEY_AUX30		240
+#define	KEY_AUX31		241
+#define	KEY_AUX32		242
+
+#define	MAXKEYS				256
+
+
+#define	FINEANGLES		8192
+#define	FINEMASK		(FINEANGLES - 1)
+#define	ANGLETOFINESHIFT	19	/* 0x100000000 to 0x2000 */
+
+/*
+===============================================================================
+
+						GLOBAL TYPES
+
+===============================================================================
+*/
+
+/*
+#define NUMARTIFCTS	28
+*/
+
+#define TICRATE		35		/* number of tics / second */
+#define TICSPERSEC	35
+
+#define MINIMUM_HEAP_SIZE	0x800000	/*  8 meg */
+#define MAXIMUM_HEAP_SIZE	0x2000000	/* 32 meg */
+
+/*
+#define ANGLE_1		0x01000000
+*/
+#define ANGLE_45	0x20000000
+#define ANGLE_90	0x40000000
+#define ANGLE_180	0x80000000
+#define ANGLE_MAX	0xffffffff
+#define ANGLE_1		(ANGLE_45 / 45)
+#define ANGLE_60	(ANGLE_180 / 3)
+
+#define	ANG45		0x20000000
+#define	ANG90		0x40000000
+#define	ANG180		0x80000000
+#define	ANG270		0xc0000000
+
+typedef unsigned angle_t;
+
+typedef enum
+{
+	sk_baby,
+	sk_easy,
+	sk_medium,
+	sk_hard,
+	sk_nightmare
+} skill_t;
+
+typedef enum
+{
+	ev_keydown,
+	ev_keyup,
+	ev_mouse,
+	ev_joystick
+} evtype_t;
+
+typedef struct
+{
+	evtype_t	type;
+	int		data1;		/* keys / mouse/joystick buttons */
+	int		data2;		/* mouse/joystick x move */
+	int		data3;		/* mouse/joystick y move */
+} event_t;
+
+typedef struct
+{
+	signed char	forwardmove;	/* *2048 for move */
+	signed char	sidemove;	/* *2048 for move */
+	short		angleturn;	/* <<16 for angle delta */
+	short		consistancy;	/* checks for net game */
+	byte		chatchar;
+	byte		buttons;
+	byte		lookfly;	/* look/fly up/down/centering */
+	byte		arti;		/* artitype_t to use */
+} ticcmd_t;
+
+#define	BT_ATTACK		1
+#define	BT_USE			2
+#define	BT_CHANGE		4	/* if true, the next 3 bits hold weapon num */
+#define	BT_WEAPONMASK	(8 + 16 + 32)
+#define	BT_WEAPONSHIFT		3
+
+#define BT_SPECIAL		128	/* game events, not really buttons */
+#define	BTS_SAVEMASK	(4 + 8 + 16)
+#define	BTS_SAVESHIFT		2
+#define	BT_SPECIALMASK		3
+#define	BTS_PAUSE		1	/* pause the game */
+#define	BTS_SAVEGAME		2	/* save the game at each console */
+/* savegame slot numbers occupy the second byte of buttons */
+
+/* The top 3 bits of the artifact field in the
+ * ticcmd_t struct are used as  additional flags
+ */
+#define AFLAG_MASK		0x3F
+#define AFLAG_SUICIDE		0x40
+#define AFLAG_JUMP		0x80
+
+typedef enum
+{
+	GS_LEVEL,
+	GS_INTERMISSION,
+	GS_FINALE,
+	GS_DEMOSCREEN
+} gamestate_t;
+
+typedef enum
+{
+	ga_nothing,
+	ga_loadlevel,
+	ga_initnew,
+	ga_newgame,
+	ga_loadgame,
+	ga_savegame,
+	ga_playdemo,
+	ga_completed,
+	ga_leavemap,
+	ga_singlereborn,
+	ga_victory,
+	ga_worlddone,
+	ga_screenshot
+} gameaction_t;
+
+typedef enum
+{
+	wipe_0,
+	wipe_1,
+	wipe_2,
+	wipe_3,
+	wipe_4,
+	NUMWIPES,
+	wipe_random
+} wipe_t;
+
+typedef struct
+{
+	const char	*name;
+	int	*location;
+	int	defaultvalue;
+	int	minvalue;
+	int	maxvalue;
+} default_t;
+
+typedef struct
+{
+	const char	*name;
+	char	*location;	/* pointer to an 80 char array, null terminated */
+	char	*defaultvalue;	/* backup of the default value. malloc'ed at init */
+} default_str_t;
+
+/*
+===============================================================================
+
+							MAPOBJ DATA
+
+===============================================================================
+*/
+
+/* think_t is a function pointer to a routine to handle an actor */
+typedef void (*think_t) (void*);
+
+typedef struct thinker_s
+{
+	struct thinker_s	*prev, *next;
+	think_t		function;
+} thinker_t;
+
+struct player_s;
+
+typedef struct mobj_s
+{
+	thinker_t		thinker;	/* thinker node */
+
+	/* info for drawing */
+	fixed_t			x, y, z;
+	struct mobj_s	*snext, *sprev;		/* links in sector (if needed) */
+	angle_t			angle;
+	spritenum_t		sprite;		/* used to find patch_t and flip value */
+	int			frame;		/* might be ord with FF_FULLBRIGHT */
+
+	/* interaction info */
+	struct mobj_s	*bnext, *bprev;		/* links in blocks (if needed) */
+	struct subsector_s	*subsector;
+	fixed_t			floorz, ceilingz;	/* closest together of contacted secs */
+	fixed_t			floorpic;		/* contacted sec floorpic */
+	fixed_t			radius, height;		/* for movement checking */
+	fixed_t			momx, momy, momz;	/* momentums */
+	int			validcount;	/* if == validcount, already checked */
+	mobjtype_t		type;
+	mobjinfo_t		*info;		/* &mobjinfo[mobj->type] */
+	int			tics;		/* state tic counter */
+	state_t			*state;
+	int			damage;		/* For missiles */
+	int			flags;
+	int			flags2;		/* Heretic flags */
+
+	/* be doubly careful with these two: they may be used to store
+	 * a state or the address of an mobj_t or player_t structure!!!
+	 */
+	intptr_t		special1;	/* Special info */
+	intptr_t		special2;	/* Special info */
+
+	int			health;
+	int			movedir;	/* 0-7 */
+	int			movecount;	/* when 0, select a new dir */
+	struct mobj_s		*target;	/* thing being chased/attacked (or NULL)
+						   also the originator for missiles */
+	int			reactiontime;	/* if non 0, don't attack yet
+						   used by player to freeze a bit after
+						   teleporting */
+	int			threshold;	/* if > 0, the target will be chased
+						   no matter what (even if shot) */
+	struct player_s		*player;	/* only valid if type == MT_PLAYER */
+	int			lastlook;	/* player number last looked for */
+	fixed_t			floorclip;	/* value to use for floor clipping */
+	int			archiveNum;	/* Identity during archive */
+	short			tid;		/* thing identifier */
+	byte			special;	/* special */
+	byte			args[5];	/* special arguments */
+} mobj_t;
+
+/* each sector has a degenmobj_t in it's center for sound origin purposes */
+typedef struct
+{
+	thinker_t		thinker;	/* not used for anything. */
+	fixed_t			x, y, z;
+} degenmobj_t;
+
+/* Most damage defined using HITDICE */
+#define HITDICE(a)	((1 + (P_Random() & 7)) * (a))
+
+/* frame flags */
+#define	FF_FULLBRIGHT	0x8000		/* flag in thing->frame */
+#define FF_FRAMEMASK	0x7fff
+
+/* --- mobj.flags --- */
+#define	MF_SPECIAL		1	/* call P_SpecialThing when touched */
+#define	MF_SOLID		2
+#define	MF_SHOOTABLE		4
+#define	MF_NOSECTOR		8	/* don't use the sector links (invisible but touchable) */
+#define	MF_NOBLOCKMAP		16	/* don't use the blocklinks (inert but displayable) */
+#define	MF_AMBUSH		32
+#define	MF_JUSTHIT		64	/* try to attack right back */
+#define	MF_JUSTATTACKED		128	/* take at least one step before attacking */
+#define	MF_SPAWNCEILING		256	/* hang from ceiling instead of floor */
+#define	MF_NOGRAVITY		512	/* don't apply gravity every tic */
+
+/* movement flags */
+#define	MF_DROPOFF		0x400		/* allow jumps from high places */
+#define	MF_PICKUP		0x800		/* for players to pick up items */
+#define	MF_NOCLIP		0x1000		/* player cheat */
+#define	MF_SLIDE		0x2000		/* keep info about sliding along walls */
+#define	MF_FLOAT		0x4000		/* allow moves to any height, no gravity */
+#define	MF_TELEPORT		0x8000		/* don't cross lines or look at heights */
+#define MF_MISSILE		0x10000		/* don't hit same species, explode on block */
+
+#define	MF_ALTSHADOW		0x20000		/* alternate fuzzy draw */
+#define	MF_SHADOW		0x40000		/* use fuzzy draw (shadow demons / invis) */
+#define	MF_NOBLOOD		0x80000		/* don't bleed when shot (use puff) */
+#define	MF_CORPSE		0x100000	/* don't stop moving halfway off a step */
+#define	MF_INFLOAT		0x200000	/* floating to a height for a move, don't */
+							/* auto float to target's height. */
+
+#define	MF_COUNTKILL		0x400000	/* count towards intermission kill total */
+#define	MF_ICECORPSE		0x800000	/* a frozen corpse (for blasting) */
+
+#define	MF_SKULLFLY		0x1000000	/* skull in flight */
+#define	MF_NOTDMATCH		0x2000000	/* don't spawn in death match (key cards) */
+
+//#define	MF_TRANSLATION	0xc000000	/* if 0x4 0x8 or 0xc, use a translation */
+#define	MF_TRANSLATION		0x1c000000	/* use a translation table (>>MF_TRANSHIFT) */
+
+#define	MF_TRANSSHIFT		26		/* table for player colormaps */
+
+/* --- mobj.flags2 --- */
+
+#define MF2_LOGRAV		0x00000001	/* alternate gravity setting */
+#define MF2_WINDTHRUST		0x00000002	/* gets pushed around by the wind specials */
+#define MF2_FLOORBOUNCE		0x00000004	/* bounces off the floor */
+#define MF2_BLASTED		0x00000008	/* missile will pass through ghosts */
+#define MF2_FLY			0x00000010	/* fly mode is active */
+#define MF2_FLOORCLIP		0x00000020	/* if feet are allowed to be clipped */
+#define MF2_SPAWNFLOAT		0x00000040	/* spawn random float z */
+#define MF2_NOTELEPORT		0x00000080	/* does not teleport */
+#define MF2_RIP			0x00000100	/* missile rips through solid targets */
+#define MF2_PUSHABLE		0x00000200	/* can be pushed by other moving mobjs */
+#define MF2_SLIDE		0x00000400	/* slides against walls */
+#define MF2_ONMOBJ		0x00000800	/* mobj is resting on top of another mobj */
+#define MF2_PASSMOBJ		0x00001000	/* Enable z block checking.  If on, */
+							/* this flag will allow the mobj to */
+							/* pass over/under other mobjs. */
+#define MF2_CANNOTPUSH		0x00002000	/* cannot push other pushable mobjs */
+#define MF2_DROPPED		0x00004000	/* dropped by a demon */
+#define MF2_BOSS		0x00008000	/* mobj is a major boss */
+#define MF2_FIREDAMAGE		0x00010000	/* does fire damage */
+#define MF2_NODMGTHRUST		0x00020000	/* does not thrust target when damaging */
+#define MF2_TELESTOMP		0x00040000	/* mobj can stomp another */
+#define MF2_FLOATBOB		0x00080000	/* use float bobbing z movement */
+#define MF2_DONTDRAW		0x00100000	/* don't generate a vissprite */
+#define MF2_IMPACT		0x00200000 	/* an MF_MISSILE mobj can activate SPAC_IMPACT */
+#define MF2_PUSHWALL		0x00400000 	/* mobj can push walls */
+#define MF2_MCROSS		0x00800000	/* can activate monster cross lines */
+#define MF2_PCROSS		0x01000000	/* can activate projectile cross lines */
+#define MF2_CANTLEAVEFLOORPIC	0x02000000	/* stay within a certain floor type */
+#define MF2_NONSHOOTABLE	0x04000000	/* mobj is totally non-shootable, but still considered solid */
+#define MF2_INVULNERABLE	0x08000000	/* mobj is invulnerable */
+#define MF2_DORMANT		0x10000000	/* thing is dormant */
+#define MF2_ICEDAMAGE		0x20000000	/* does ice damage */
+#define MF2_SEEKERMISSILE	0x40000000	/* is a seeker (for reflection) */
+#define MF2_REFLECTIVE		0x80000000	/* reflects missiles */
+
+/*============================================================================*/
+
+/* ===== Player Class Types ===== */
+typedef enum
+{
+	PCLASS_FIGHTER,
+	PCLASS_CLERIC,
+	PCLASS_MAGE,
+#ifdef ASSASSIN
+	PCLASS_ASS,
+#endif
+	/* end of the actual classes */
+	NUMCLASSES_HUMAN,
+
+	/* morphed classes (Pig ...) */
+	PCLASS_PIG = NUMCLASSES_HUMAN,
+
+	NUMCLASSES	/* all classes */
+} pclass_t;
+
+typedef enum
+{
+	PST_LIVE,		/* playing */
+	PST_DEAD,		/* dead on the ground */
+	PST_REBORN		/* ready to restart */
+} playerstate_t;
+
+/* psprites are scaled shapes directly on the view screen
+ * coordinates are given for a 320*200 view screen
+ */
+typedef enum
+{
+	ps_weapon,
+	ps_flash,
+	NUMPSPRITES
+} psprnum_t;
+
+typedef struct
+{
+	state_t	*state;		/* a NULL state means not active */
+	int		tics;
+	fixed_t	sx, sy;
+} pspdef_t;
+
+/* Old Heretic key type
+typedef enum
+{
+	key_yellow,
+	key_green,
+	key_blue,
+	NUMKEYS
+} keytype_t;
+*/
+
+typedef enum
+{
+	KEY_1,
+	KEY_2,
+	KEY_3,
+	KEY_4,
+	KEY_5,
+	KEY_6,
+	KEY_7,
+	KEY_8,
+	KEY_9,
+	KEY_A,
+	KEY_B,
+	NUMKEYS
+} keytype_t;
+
+typedef enum
+{
+	ARMOR_ARMOR,
+	ARMOR_SHIELD,
+	ARMOR_HELMET,
+	ARMOR_AMULET,
+	NUMARMOR
+} armortype_t;
+
+typedef enum
+{
+	WP_FIRST,
+	WP_SECOND,
+	WP_THIRD,
+	WP_FOURTH,
+	NUMWEAPONS,
+	WP_NOCHANGE
+} weapontype_t;
+
+typedef enum
+{
+	MANA_1,
+	MANA_2,
+	NUMMANA,
+	MANA_BOTH,
+	MANA_NONE
+} manatype_t;
+
+#define MAX_MANA	200
+
+#define WPIECE1		1
+#define WPIECE2		2
+#define WPIECE3		4
+
+typedef struct
+{
+	manatype_t	mana;
+	int	upstate;
+	int	downstate;
+	int	readystate;
+	int	atkstate;
+	int	holdatkstate;
+	int	flashstate;
+} weaponinfo_t;
+
+extern	weaponinfo_t	WeaponInfo[NUMWEAPONS][NUMCLASSES];
+
+typedef enum
+{
+	arti_none,
+	arti_invulnerability,
+	arti_health,
+	arti_superhealth,
+	arti_healingradius,
+	arti_summon,
+	arti_torch,
+	arti_egg,
+	arti_fly,
+	arti_blastradius,
+	arti_poisonbag,
+	arti_teleportother,
+	arti_speed,
+	arti_boostmana,
+	arti_boostarmor,
+	arti_teleport,
+	/* Puzzle artifacts */
+	arti_firstpuzzitem,
+	arti_puzzskull = arti_firstpuzzitem,
+	arti_puzzgembig,
+	arti_puzzgemred,
+	arti_puzzgemgreen1,
+	arti_puzzgemgreen2,
+	arti_puzzgemblue1,
+	arti_puzzgemblue2,
+	arti_puzzbook1,
+	arti_puzzbook2,
+	arti_puzzskull2,
+	arti_puzzfweapon,
+	arti_puzzcweapon,
+	arti_puzzmweapon,
+	arti_puzzgear1,
+	arti_puzzgear2,
+	arti_puzzgear3,
+	arti_puzzgear4,
+	NUMARTIFACTS
+} artitype_t;
+
+typedef enum
+{
+	pw_None,
+	pw_invulnerability,
+	pw_allmap,
+	pw_infrared,
+	pw_flight,
+	pw_shield,
+	pw_health2,
+	pw_speed,
+	pw_minotaur,
+	NUMPOWERS
+} powertype_t;
+
+#define	INVULNTICS	(30 * 35)
+#define	INVISTICS	(60 * 35)
+#define	INFRATICS	(120* 35)
+#define	IRONTICS	(60 * 35)
+#define WPNLEV2TICS	(40 * 35)
+#define FLIGHTTICS	(60 * 35)
+#define SPEEDTICS	(45 * 35)
+#define MORPHTICS	(40 * 35)
+#define MAULATORTICS	(25 * 35)
+
+#define MESSAGETICS	( 4 * 35)
+#define BLINKTHRESHOLD	( 4 * 35)
+
+#define NUMINVENTORYSLOTS	NUMARTIFACTS
+
+typedef struct
+{
+	int	type;
+	int	count;
+} inventory_t;
+
+/*
+================
+player_t
+================
+*/
+typedef struct player_s
+{
+	mobj_t		*mo;
+	playerstate_t	playerstate;
+	ticcmd_t	cmd;
+
+	pclass_t	playerclass;		/* player class type */
+
+	fixed_t		viewz;			/* focal origin above r.z */
+	fixed_t		viewheight;		/* base height above floor for viewz */
+	fixed_t		deltaviewheight;	/* squat speed */
+	fixed_t		bob;			/* bounded/scaled total momentum */
+
+	int		flyheight;
+	int		lookdir;
+	boolean		centering;
+	int		health;			/* only used between levels, mo->health */
+								/* is used during levels */
+	int		armorpoints[NUMARMOR];
+
+	inventory_t	inventory[NUMINVENTORYSLOTS];
+	artitype_t	readyArtifact;
+	int		artifactCount;
+	int		inventorySlotNum;
+	int		powers[NUMPOWERS];
+	int		keys;
+	int		pieces;			/* Fourth Weapon pieces */
+	signed int	frags[MAXPLAYERS];	/* kills of other players */
+	weapontype_t	readyweapon;
+	weapontype_t	pendingweapon;		/* wp_nochange if not changing */
+	boolean		weaponowned[NUMWEAPONS];
+	int		mana[NUMMANA];
+	int		attackdown, usedown;	/* true if button down last tic */
+	int		cheats;			/* bit flags */
+
+	int		refire;			/* refired shots are less accurate */
+
+	int		killcount, itemcount, secretcount;	/* for intermission */
+	char		message[80];		/* hint messages */
+	int		messageTics;		/* counter for showing messages */
+	short		ultimateMessage;
+	short		yellowMessage;
+	int		damagecount, bonuscount;/* for screen flashing */
+	int		poisoncount;		/* screen flash for poison damage */
+	mobj_t		*poisoner;		/* NULL for non-player mobjs */
+	mobj_t		*attacker;		/* who did damage (NULL for floors) */
+	int		extralight;		/* so gun flashes light up areas */
+	int		fixedcolormap;		/* can be set to REDCOLORMAP, etc */
+	int		colormap;		/* 0-3 for which color to draw player */
+	pspdef_t	psprites[NUMPSPRITES];	/* view sprites (gun, etc) */
+	int		morphTics;		/* player is a pig if > 0 */
+	unsigned int	jumpTics;		/* delay the next jump for a moment */
+	unsigned int	worldTimer;		/* total time the player's been playing */
+} player_t;
+
+#define CF_NOCLIP		1
+#define	CF_GODMODE		2
+#define	CF_NOMOMENTUM		4	/* not really a cheat, just a debug aid */
+
+
+#define	BACKUPTICS		12
+
+typedef struct
+{
+	unsigned int	checksum;		/* high bit is retransmit request */
+	byte		retransmitfrom;		/* only valid if NCMD_RETRANSMIT */
+	byte		starttic;
+	byte		player, numtics;
+	ticcmd_t	cmds[BACKUPTICS];
+} doomdata_t;
+
+typedef struct
+{
+	int32_t		id;
+	short		intnum;		/* DOOM executes an int to execute commands */
+
+/* communication between DOOM and the driver */
+	short		command;	/* CMD_SEND or CMD_GET */
+	short		remotenode;	/* dest for send, set by get (-1 = no packet) */
+	short		datalength;	/* bytes in doomdata to be sent */
+
+/* info common to all nodes */
+	short		numnodes;	/* console is allways node 0 */
+	short		ticdup;		/* 1 = no duplication, 2-5 = dup for slow nets */
+	short		extratics;	/* 1 = send a backup tic in every packet */
+	short		deathmatch;	/* 1 = deathmatch */
+	short		savegame;	/* -1 = new game, 0-5 = load savegame */
+	short		episode;	/* 1-3 */
+	short		map;		/* 1-9 */
+	short		skill;		/* 1-5 */
+
+/* info specific to this node */
+	short		consoleplayer;
+	short		numplayers;
+	short		angleoffset;	/* 1 = left, 0 = center, -1 = right */
+	short		drone;		/* 1 = drone */
+
+/* packet data to be sent */
+	doomdata_t	data;
+} doomcom_t;
+
+#define	DOOMCOM_ID		0x12345678l
+
+extern	doomcom_t		*doomcom;
+extern	doomdata_t		*netbuffer;	/* points inside doomcom */
+
+/*
+#define	MAXNETNODES		8
+*/
+#define	MAXNETNODES		16		/* max computers in a game */
+
+#define	CMD_SEND		1
+#define	CMD_GET			2
+#define	CMD_FRAG		3
+
+#define	SBARHEIGHT		39		/* status bar height at bottom of screen */
+
+void NET_SendFrags(player_t *player);
+
+/*
+===============================================================================
+
+					GLOBAL VARIABLES
+
+===============================================================================
+*/
+
+#define TELEFOGHEIGHT		(32 * FRACUNIT)
+
+#define MAXEVENTS		64
+
+extern	event_t		events[MAXEVENTS];
+extern	int		eventhead;
+extern	int		eventtail;
+
+extern	fixed_t		finesine[5*FINEANGLES/4];
+extern	fixed_t		*finecosine;
+
+extern	gameaction_t	gameaction;
+extern	boolean		paused;
+extern	boolean		shareware;	/* true if other episodes not present */
+extern	boolean		oldwad_10;	/* true if version 1.0 wad files (shareware or full) */
+extern	boolean		mac_hexen;	/* true if Macintosh version wad (shareware or full) */
+extern	boolean		DevMaps;	/* true = map development mode */
+extern	const char	*DevMapsDir;	/* development maps directory */
+extern	boolean		nomonsters;	/* checkparm of -nomonsters */
+extern	boolean		respawnparm;	/* checkparm of -respawn */
+extern	boolean		randomclass;	/* checkparm of -randclass */
+extern	boolean		debugmode;	/* checkparm of -debug */
+extern	boolean		usergame;	/* ok to save / end game */
+extern	boolean		ravpic;		/* checkparm of -ravpic */
+extern	boolean		deathmatch;	/* only if started as net death */
+extern	boolean		netgame;	/* only true if >1 player */
+extern	boolean		cmdfrag;	/* true if a CMD_FRAG packet should be sent out every kill */
+
+extern	boolean		playeringame[MAXPLAYERS];
+extern	pclass_t	PlayerClasses[MAXPLAYERS];
+extern	int		consoleplayer;	/* player taking events and displaying */
+extern	int		displayplayer;
+extern	int		viewangleoffset;/* ANG90 = left side, ANG270 = right */
+extern	player_t	players[MAXPLAYERS];
+
+extern	boolean		singletics;	/* debug flag to cancel adaptiveness */
+extern	boolean		DebugSound;	/* debug flag for displaying sound info */
+
+extern	boolean		demoplayback;
+extern	int		Sky1Texture;
+extern	int		Sky2Texture;
+
+extern	int		maxzone;	/* Maximum chunk allocated for zone heap */
+
+extern	gamestate_t	gamestate;
+extern	skill_t		gameskill;
+extern	int		gameepisode;
+extern	int		gamemap;
+extern 	int 		prevmap;
+extern	int		levelstarttic;	/* gametic at level start */
+extern	int		leveltime;	/* tics in game play for par */
+
+extern	int		ticcount;
+
+extern	ticcmd_t	netcmds[MAXPLAYERS][BACKUPTICS];
+extern	int		ticdup;
+extern	ticcmd_t	localcmds[BACKUPTICS];
+extern	int		rndindex;
+extern	int		gametic, maketic;
+extern	int		nettics[MAXNETNODES];
+
+#define MAXDEATHMATCHSTARTS	16
+extern	mapthing_t	*deathmatch_p;
+extern	mapthing_t	deathmatchstarts[MAXDEATHMATCHSTARTS];
+
+/* Position indicator for cooperative net-play reborn */
+extern	int		RebornPosition;
+
+#define MAX_PLAYER_STARTS	8
+extern	mapthing_t	playerstarts[MAX_PLAYER_STARTS][MAXPLAYERS];
+
+extern	int		viewwindowx;
+extern	int		viewwindowy;
+extern	int		viewwidth;
+extern	int		scaledviewwidth;
+extern	int		viewheight;
+
+extern	int		mouseSensitivity;
+
+extern	boolean		precache;	/* if true, load all graphics at level load */
+
+extern	byte		*screen;	/* off screen work buffer, from V_video.c */
+
+extern	boolean		singledemo;	/* quit after playing a demo from cmdline */
+
+extern	FILE		*debugfile;
+extern	int		bodyqueslot;
+extern	skill_t		startskill;
+extern	int		startepisode;
+extern	int		startmap;
+extern	boolean		autostart;
+
+
+/*
+===============================================================================
+
+					GLOBAL FUNCTIONS
+
+===============================================================================
+*/
+
+
+fixed_t	FixedMul (fixed_t a, fixed_t b);
+fixed_t	FixedDiv (fixed_t a, fixed_t b);
+fixed_t	FixedDiv2 (fixed_t a, fixed_t b);
+
+#undef	_HAVE_FIXED_ASM
+
+#if !defined(_DISABLE_ASM)
+#if defined(__i386__) || defined(__386__) || defined(_M_IX86)
+#if defined(__WATCOMC__)
+
+#define	_HAVE_FIXED_ASM			1
+
+#pragma aux FixedMul =			\
+	"imul ebx",			\
+	"shrd eax,edx,16"		\
+	parm	[eax] [ebx]		\
+	value	[eax]			\
+	modify exact [eax edx]
+
+#pragma aux FixedDiv2 =			\
+	"cdq",				\
+	"shld edx,eax,16",		\
+	"sal eax,16",			\
+	"idiv ebx"			\
+	parm	[eax] [ebx]		\
+	value	[eax]			\
+	modify exact [eax edx]
+
+#elif defined(__GNUC__)
+
+#define	_HAVE_FIXED_ASM			1
+
+# if defined(_INLINE_FIXED_ASM)
+# if (__GNUC__ == 2) && (__GNUC_MINOR__ <= 91)
+# define FixedMul(fa,fb) ({ int __value, __fb = (fb);	\
+	__asm__("imul %%ebx; shrd $16,%%edx,%%eax"	\
+		: "=a" (__value)			\
+		: "0" (fa), "b" (__fb)			\
+		: "eax", "edx" ); __value; })
+
+# define FixedDiv2(fa,fb) ({ int __value;		\
+	__asm__("cdq; shld $16,%%eax,%%edx; sall $16,%%eax; idiv %%ebx"	\
+		: "=a" (__value)			\
+		: "0" (fa), "b" (fb)			\
+		: "eax", "edx" ); __value; })
+
+# else	/* GCC > 2.91.x */
+# define FixedMul(fa,fb) ({ int __value, __fb = (fb);	\
+	__asm__("imul %%ebx; shrd $16,%%edx,%%eax"	\
+		: "=a" (__value)			\
+		: "0" (fa), "b" (__fb)			\
+		: "edx" ); __value; })
+
+# define FixedDiv2(fa,fb) ({ int __value;		\
+	__asm__("cdq; shld $16,%%eax,%%edx; sall $16,%%eax; idiv %%ebx"	\
+		: "=a" (__value)			\
+		: "0" (fa), "b" (fb)			\
+		: "edx" ); __value; })
+
+# endif	/* GCC/EGCS versions */
+
+# endif	/* _INLINE_FIXED_ASM */
+#endif
+#endif	/* X86 */
+#endif	/* !_DISABLE_ASM */
+
+#define FIX2FLT(x)	((float)((x)>>FRACBITS) + (float)((x)&(FRACUNIT-1)) / (float)(FRACUNIT))
+#define Q_FIX2FLT(x)	((float)((x)>>FRACBITS))
+
+
+int16_t ShortSwap(int16_t) __attribute__((__const__));
+int32_t LongSwap (int32_t) __attribute__((__const__));
+
+#if defined(__GNUC__)
+static inline __attribute__((__const__)) int16_t _H2_SWAP16(int16_t x)
+{
+	return (int16_t) (((uint16_t)x << 8) | ((uint16_t)x >> 8));
+}
+static inline __attribute__((__const__)) int32_t _H2_SWAP32(int32_t x)
+{
+	return (int32_t) (((uint32_t)x << 24) | ((uint32_t)x >> 24) |
+			  (((uint32_t)x & (uint32_t)0x0000ff00UL) << 8) |
+			  (((uint32_t)x & (uint32_t)0x00ff0000UL) >> 8));
+}
+#endif	/* GCC */
+
+/*
+#ifdef __BIG_ENDIAN__
+*/
+#ifdef WORDS_BIGENDIAN
+# ifdef __GNUC__
+#  define SHORT(a)	_H2_SWAP16((a))
+#  define LONG(a)	_H2_SWAP32((a))
+# else
+#  define SHORT(x)	ShortSwap((x))
+#  define LONG(x)	LongSwap((x))
+# endif
+#else
+#define SHORT(x)	(x)
+#define LONG(x)		(x)
+#endif
+
+/* ---- READ_INT16/32 --- */
+
+#define READ_INT16(b)	((b)[0] | ((b)[1] << 8))
+#define READ_INT32(b)	((b)[0] | ((b)[1] << 8) | ((b)[2] << 16) | ((b)[3] << 24))
+#define INCR_INT16(b)	(b)+=2
+#define INCR_INT32(b)	(b)+=4
+
+
+/* ----- MEMORY ZONE ---- */
+
+/* tags < 100 are not overwritten until freed */
+#define	PU_STATIC		1		/* static entire execution time */
+#define	PU_SOUND		2		/* static while playing */
+#define	PU_MUSIC		3		/* static while playing */
+#define	PU_DAVE			4		/* anything else Dave wants static */
+#define	PU_LEVEL		50		/* static until level exited */
+#define	PU_LEVSPEC		51		/* a special thinker in a level */
+/* tags >= 100 are purgable whenever needed */
+#define	PU_PURGELEVEL		100
+#define	PU_CACHE		101
+
+#define	ZONEID		0x1d4a11
+
+void Z_Init (void);
+void *Z_Malloc (int size, int tag, void *ptr);
+void Z_Free (void *ptr);
+void Z_FreeTags (int lowtag, int hightag);
+void Z_CheckHeap (void);
+void Z_ChangeTag2 (void *ptr, int tag);
+/*
+void Z_DumpHeap (int lowtag, int hightag);
+void Z_FileDumpHeap (FILE *f);
+int Z_FreeMemory (void);
+*/
+
+typedef struct memblock_s
+{
+	int			size;		/* including the header and possibly tiny fragments */
+	void			**user;		/* NULL if a free block */
+	int			tag;		/* purgelevel */
+	int			id;		/* should be ZONEID */
+	struct memblock_s	*next, *prev;
+} memblock_t;
+
+#define Z_ChangeTag(p,t)							\
+{										\
+	if (((memblock_t *)((byte *)((p)) - sizeof(memblock_t)))->id != ZONEID)	\
+		I_Error("Z_CT at %s:%i", __FILE__, __LINE__);			\
+	Z_ChangeTag2((p),(t));							\
+};
+
+/* ------- WADFILE ------- */
+typedef struct
+{
+	char		name[8];
+	int		handle, position, size;
+} lumpinfo_t;
+
+extern	lumpinfo_t	*lumpinfo;
+extern	int		numlumps;
+extern	const char	*waddir;
+
+boolean W_IsWadPresent(const char *filename);
+void W_InitMultipleFiles(const char **filenames);
+void W_OpenAuxiliary(const char *filename);
+void W_CloseAuxiliaryFile(void);
+void W_CloseAuxiliary(void);
+void W_UsePrimary(void);
+void W_UseAuxiliary(void);
+int W_CheckNumForName(const char *name);
+int W_GetNumForName(const char *name);
+int W_LumpLength(int lump);
+void W_ReadLump(int lump, void *dest);
+void *W_CacheLumpNum(int lump, int tag);
+void *W_CacheLumpName(const char *name, int tag);
+void W_CheckWADFiles(void);
+
+
+/* ---------- BASE LEVEL ---------- */
+
+void H2_Main(void);
+/* not a globally visible function, just included for source reference
+ * calls all startup code
+ * parses command line options
+ * if not overrided, calls N_AdvanceDemo
+ */
+
+void H2_GameLoop(void);
+/* not a globally visible function, just included for source reference
+ * called by H2_Main, never exits
+ * manages timing and IO
+ * calls all ?_Responder, ?_Ticker, and ?_Drawer functions
+ * calls I_GetTime, I_StartFrame, and I_StartTic
+ */
+
+void H2_PostEvent(event_t *ev);
+/* called by IO functions when input is detected */
+
+void NetUpdate (void);
+/* create any new ticcmds and broadcast to other players */
+
+void D_QuitNetGame (void);
+/* broadcasts special packets to other players to notify of game exit */
+
+void TryRunTics (void);
+
+#if !(defined(__WATCOMC__) || defined(__DJGPP__) || defined(__DOS__) || \
+      defined(_WIN32) || defined(_WIN64))
+char *strupr (char *str);
+char *strlwr (char *str);
+int filelength(int handle);
+#endif
+
+
+/* --------- SYSTEM IO --------- */
+
+#if 1
+#define	SCREENWIDTH	320
+#define	SCREENHEIGHT	200
+#else
+#define	SCREENWIDTH	560
+#define	SCREENHEIGHT	375
+#endif
+
+byte *I_ZoneBase (int *size);
+/* called by startup code to get the ammount of memory to malloc
+ * for the zone management
+ */
+
+int I_GetTime (void);
+/* called by H2_GameLoop
+ * returns current time in tics
+ */
+
+void I_StartFrame (void);
+/* called by H2_GameLoop
+ * called before processing any tics in a frame (just after displaying a frame)
+ * time consuming syncronous operations are performed here (joystick reading)
+ * can call H2_PostEvent
+ */
+
+void I_StartTic (void);
+/* called by H2_GameLoop
+ * called before processing each tic in a frame
+ * quick syncronous operations are performed here
+ * can call H2_PostEvent
+ *
+ * asyncronous interrupt functions should maintain private ques that are
+ * read by the syncronous functions to be converted into events
+ */
+
+void I_Init (void);
+/* called by H2_Main
+ * determines the hardware configuration and sets up the video mode
+ */
+
+void I_InitGraphics (void);
+
+void I_InitNetwork (void);
+void I_NetCmd (void);
+
+void I_CheckExternDriver(void);
+
+void I_Error (const char *error, ...) __attribute__((__format__(__printf__,1,2), __noreturn__));
+/* called by anything that can generate a terminal error
+ * bad exit with diagnostic message
+ */
+
+void I_Quit (void) __attribute__((__noreturn__));
+/* called by M_Responder when quit is selected
+ * clean exit, displays sell blurb
+ */
+
+void I_SetPalette (byte *palette);
+/* takes full 8 bit values */
+
+void I_Update(void);
+/* Copy buffer to video */
+
+void I_WipeUpdate(wipe_t wipe);
+/* Copy buffer to video with wipe effect */
+
+void I_WaitVBL(int count);
+/* wait for vertical retrace or pause a bit */
+
+void I_BeginRead (void);
+void I_EndRead (void);
+
+byte *I_AllocLow (int length);
+/* allocates from low memory under dos, just mallocs under unix */
+
+extern	boolean		useexterndriver;
+
+#if defined(__WATCOMC__) || defined(__DJGPP__) || defined(__DOS__)
+#define EBT_FIRE		1
+#define EBT_OPENDOOR		2
+#define EBT_SPEED		4
+#define EBT_STRAFE		8
+#define EBT_MAP			0x10
+#define EBT_INVENTORYLEFT	0x20
+#define EBT_INVENTORYRIGHT	0x40
+#define EBT_USEARTIFACT		0x80
+#define EBT_FLYDROP		0x100
+#define EBT_CENTERVIEW		0x200
+#define EBT_PAUSE		0x400
+#define EBT_WEAPONCYCLE		0x800
+#define EBT_JUMP		0x1000
+
+typedef struct
+{
+	short		vector;		/* Interrupt vector */
+
+	signed char	moveForward;	/* forward/backward (maxes at 50) */
+	signed char	moveSideways;	/* strafe (maxes at 24) */
+	short		angleTurn;	/* turning speed (640 [slow] 1280 [fast]) */
+	short		angleHead;	/* head angle (+2080 [left] : 0 [center] : -2048 [right]) */
+	signed char	pitch;		/* look up/down (-110 : +90) */
+	signed char	flyDirection;	/* flyheight (+1/-1) */
+	unsigned short	buttons;	/* EBT_* flags */
+} externdata_t;
+
+void I_Tactile (int on, int off, int total);
+#endif	/* externdriver, DOS */
+
+
+/* ---- GAME ---- */
+
+void G_DeathMatchSpawnPlayer (int playernum);
+
+void G_InitNew (skill_t skill, int episode, int map);
+
+void G_DeferedInitNew (skill_t skill, int episode, int map);
+/* can be called by the startup code or M_Responder
+ * a normal game starts at map 1, but a warp test can start elsewhere
+ */
+
+void G_DeferredNewGame(skill_t skill);
+
+void G_DeferedPlayDemo (const char *demo);
+
+void G_LoadGame(int slot);
+/* can be called by the startup code or M_Responder
+ * calls P_SetupLevel or W_EnterWorld
+ */
+
+void G_DoLoadGame (void);
+
+void G_SaveGame (int slot, const char *description);
+/* called by M_Responder */
+
+void G_RecordDemo (skill_t skill, int numplayers, int episode,
+		   int map, const char *name);
+/* only called by startup code */
+
+void G_PlayDemo (const char *name);
+void G_TimeDemo (const char *name);
+
+void G_TeleportNewMap(int map, int position);
+
+void G_Completed(int map, int position);
+/*
+void G_ExitLevel (void);
+void G_SecretExitLevel (void);
+*/
+
+void G_StartNewGame(skill_t skill);
+void G_StartNewInit(void);
+
+void G_WorldDone (void);
+
+void G_Ticker (void);
+boolean G_Responder (event_t *ev);
+
+void G_ScreenShot (void);
+
+
+/* ------- SV_SAVE ------- */
+
+#if (MAXPLAYERS == MAXPLAYERS_10)
+#define HXS_VERSION_TEXT	"HXS Ver 2.36"
+#else
+#define HXS_VERSION_TEXT	"HXS Ver 2.37"
+#endif
+#define HXS_VERSION_TEXT_LENGTH		16
+#define HXS_DESCRIPTION_LENGTH		24
+
+void SV_SaveGame(int slot, const char *description);
+void SV_SaveMap(boolean savePlayers);
+void SV_LoadGame(int slot);
+void SV_MapTeleport(int map, int position);
+void SV_LoadMap(void);
+void SV_InitBaseSlot(void);
+void SV_UpdateRebornSlot(void);
+void SV_ClearRebornSlot(void);
+boolean SV_RebornSlotAvailable(void);
+int SV_GetRebornSlot(void);
+
+
+/* ----- PLAY ----- */
+
+void P_Ticker (void);
+/* called by C_Ticker
+ * can call G_PlayerExited
+ * carries out all thinking of monsters and players
+ */
+
+void P_SetupLevel (int episode, int map, int playermask, skill_t skill);
+/* called by W_Ticker */
+
+void P_Init (void);
+/* called by startup code */
+
+int P_GetMapCluster(int map);
+int P_TranslateMap(int map);
+int P_GetMapCDTrack(int map);
+int P_GetMapWarpTrans(int map);
+int P_GetMapNextMap(int map);
+int P_GetMapSky1Texture(int map);
+int P_GetMapSky2Texture(int map);
+const char *P_GetMapName(int map);
+fixed_t P_GetMapSky1ScrollDelta(int map);
+fixed_t P_GetMapSky2ScrollDelta(int map);
+boolean P_GetMapDoubleSky(int map);
+boolean P_GetMapLightning(int map);
+boolean P_GetMapFadeTable(int map);
+const char *P_GetMapSongLump(int map);
+void P_PutMapSongLump(int map, const char *lumpName);
+int P_GetCDStartTrack(void);
+int P_GetCDEnd1Track(void);
+int P_GetCDEnd2Track(void);
+int P_GetCDEnd3Track(void);
+int P_GetCDIntermissionTrack(void);
+int P_GetCDTitleTrack(void);
+
+
+/* ------- REFRESH ------- */
+
+extern	boolean		setsizeneeded;
+
+extern	boolean		BorderNeedRefresh;
+extern	boolean		BorderTopRefresh;
+
+extern	int		UpdateState;
+
+/* define the different areas for the dirty map */
+#define I_NOUPDATE	0
+#define I_FULLVIEW	1
+#define I_STATBAR	2
+#define I_MESSAGES	4
+#define I_FULLSCRN	8
+
+void R_RenderPlayerView (player_t *player);
+/* called by G_Drawer */
+
+void R_Init (void);
+/* called by startup code */
+
+void R_DrawViewBorder (void);
+void R_DrawTopBorder (void);
+/* if the view size is not full screen, draws a border around it */
+
+void R_SetViewSize (int blocks, int detail);
+/* called by M_Responder */
+
+int R_FlatNumForName (const char *name);
+
+int R_TextureNumForName (const char *name);
+int R_CheckTextureNumForName (const char *name);
+/* called by P_Ticker for switches and animations
+ * returns the texture number for the texture name
+ */
+
+
+/* ---- MISC ---- */
+extern	const char	**myargv;
+extern	int		myargc;
+extern	int		localQuakeHappening[MAXPLAYERS];
+
+int M_CheckParm(const char *check);
+/* returns the position of the given parameter in the arg list (0 if not found) */
+
+boolean M_ParmExists(const char *check);
+
+void M_ExtractFileBase(const char *path, char *dest);
+
+void M_ForceUppercase(char *text);
+/* Changes a string to uppercase */
+
+int M_Random (void);
+/* returns a number from 0 to 255 */
+
+unsigned char P_Random(void);
+/* as M_Random, but used only by the play simulation */
+
+void M_ClearRandom (void);
+/* fix randoms for demos */
+
+void M_FindResponseFile(void);
+
+void M_ClearBox (fixed_t *box);
+void M_AddToBox (fixed_t *box, fixed_t x, fixed_t y);
+/* bounding box functions */
+
+boolean M_WriteFile(char const *name, const void *source, int length);
+int M_ReadFile(char const *name, void **buffer);
+int M_ReadFileCLib(char const *name, void **buffer);
+
+void M_ScreenShot (void);
+
+void M_LoadDefaults(const char *fileName);
+
+void M_SaveDefaults (void);
+
+
+/* ----- SC_man.c ---- */
+
+void SC_Open(const char *name);
+void SC_OpenLump(const char *name);
+void SC_OpenFile(const char *name);
+void SC_OpenFileCLib(const char *name);
+void SC_Close(void);
+boolean SC_GetString(void);
+void SC_MustGetString(void);
+void SC_MustGetStringName(const char *name);
+boolean SC_GetNumber(void);
+void SC_MustGetNumber(void);
+void SC_UnGet(void);
+/*
+boolean SC_Check(void);
+*/
+boolean SC_Compare(const char *text);
+int SC_MatchString(const char **strings);
+int SC_MustMatchString(const char **strings);
+void SC_ScriptError(const char *message) __attribute__((__noreturn__));
+
+extern	char	*sc_String;
+extern	int		sc_Number;
+extern	int		sc_Line;
+extern	boolean		sc_End;
+extern	boolean		sc_Crossed;
+extern	boolean		sc_FileScripts;
+extern	const char	*sc_ScriptsDir;
+
+
+/* ---- SN_sonix.c ---- */
+
+enum
+{
+	SEQ_PLATFORM,
+	SEQ_PLATFORM_HEAVY,		/* same script as a normal platform */
+	SEQ_PLATFORM_METAL,
+	SEQ_PLATFORM_CREAK,		/* same script as a normal platform */
+	SEQ_PLATFORM_SILENCE,
+	SEQ_PLATFORM_LAVA,
+	SEQ_PLATFORM_WATER,
+	SEQ_PLATFORM_ICE,
+	SEQ_PLATFORM_EARTH,
+	SEQ_PLATFORM_METAL2,
+	SEQ_DOOR_STONE,
+	SEQ_DOOR_HEAVY,
+	SEQ_DOOR_METAL,
+	SEQ_DOOR_CREAK,
+	SEQ_DOOR_SILENCE,
+	SEQ_DOOR_LAVA,
+	SEQ_DOOR_WATER,
+	SEQ_DOOR_ICE,
+	SEQ_DOOR_EARTH,
+	SEQ_DOOR_METAL2,
+	SEQ_ESOUND_WIND,
+	SEQ_NUMSEQ
+};
+
+typedef enum
+{
+	SEQTYPE_STONE,
+	SEQTYPE_HEAVY,
+	SEQTYPE_METAL,
+	SEQTYPE_CREAK,
+	SEQTYPE_SILENCE,
+	SEQTYPE_LAVA,
+	SEQTYPE_WATER,
+	SEQTYPE_ICE,
+	SEQTYPE_EARTH,
+	SEQTYPE_METAL2,
+	SEQTYPE_NUMSEQ
+} seqtype_t;
+
+void SN_InitSequenceScript(void);
+void SN_StartSequence(mobj_t *mobj, int sequence);
+void SN_StartSequenceName(mobj_t *mobj, const char *name);
+void SN_StopSequence(mobj_t *mobj);
+void SN_UpdateActiveSequences(void);
+void SN_StopAllSequences(void);
+int SN_GetSequenceOffset(int sequence, int *sequencePtr);
+void SN_ChangeNodeData(int nodeNum, int seqOffset, int delayTics, int volume, int currentSoundID);
+
+typedef struct seqnode_s seqnode_t;
+struct seqnode_s
+{
+	int	*sequencePtr;
+	int		sequence;
+	mobj_t		*mobj;
+	int		currentSoundID;
+	int		delayTics;
+	int		volume;
+	int		stopSound;
+	seqnode_t	*prev;
+	seqnode_t	*next;
+};
+
+extern	int		ActiveSequences;
+extern	seqnode_t	*SequenceListHead;
+
+extern	boolean		nosound;
+extern	int		mouselook;
+
+
+/* ---- Interlude (IN_lude.c) ---- */
+
+extern	boolean		intermission;
+
+void IN_Start(void);
+void IN_Ticker(void);
+void IN_Drawer(void);
+
+/* ---- Interlude (hubmsg.c) ----- */
+
+const char *GetClusterText(int sequence);
+const char *GetFinaleText (int sequence);
+
+/* ---- Finale (F_finale.c) ------ */
+
+void F_Drawer(void);
+void F_Ticker(void);
+void F_StartFinale(void);
+
+
+/* ---- Chat mode (CT_chat.c) ---- */
+
+void CT_Init(void);
+void CT_Drawer(void);
+boolean CT_Responder(event_t *ev);
+void CT_Ticker(void);
+char CT_dequeueChatChar(void);
+
+extern	char		chat_macros[10][80];
+extern	boolean		chatmodeon;
+
+
+/* ---- STATUS BAR (SB_bar.c) ---- */
+
+extern	int		inv_ptr;
+extern	int		curpos;
+extern	int		SB_state;
+
+void SB_Init(void);
+void SB_SetClassData(void);
+boolean SB_Responder(event_t *event);
+void SB_Ticker(void);
+void SB_Drawer(void);
+void Draw_TeleportIcon(void);
+void Draw_SaveIcon(void);
+void Draw_LoadIcon(void);
+
+
+/* ---- MENU (MN_menu.c) ---- */
+
+void MN_Init(void);
+void MN_ActivateMenu(void);
+void MN_DeactivateMenu(void);
+boolean MN_Responder(event_t *event);
+void MN_Ticker(void);
+void MN_Drawer(void);
+void MN_DrTextA(const char *text, int x, int y);
+void MN_DrTextAYellow(const char *text, int x, int y);
+int MN_TextAWidth(const char *text);
+void MN_DrTextB(const char *text, int x, int y);
+int MN_TextBWidth(const char *text);
+
+
+/* --- AUTOMAP---- */
+
+#define	AM_TRANSPARENT	1	/* compile time option. 0: old style map drawn	*/
+				/* onto solid background.  1:  transparent map.	*/
+
+extern	boolean		automapactive;
+
+
+/* ---- VIDEO ---- */
+
+extern	int		dirtybox[4];
+extern	byte		gammatable[5][256];
+extern	int		usegamma;
+
+void V_Init(void); /* Allocates buffer screens, call before R_Init */
+void V_DrawPatch(int x, int y, patch_t *patch);
+void V_DrawPatchBuffer(int x, int y, patch_t *patch, byte *buffer);
+void V_DrawFuzzPatch(int x, int y, patch_t *patch);
+void V_DrawAltFuzzPatch(int x, int y, patch_t *patch);
+void V_DrawShadowedPatch(int x, int y, patch_t *patch);
+void V_BlitToScreen (int x, int y, byte *buffer, int width, int height);
+void V_DrawRawScreen(byte *raw);
+
+#include "sounds.h"
+
+#endif	/* __H2DEF__ */
+
--- /dev/null
+++ b/h2stdinc.h
@@ -1,0 +1,166 @@
+/*
+	h2stdinc.h
+	includes the minimum necessary stdc headers,
+	defines common and / or missing types.
+
+	$Id: h2stdinc.h 577 2011-06-11 13:30:45Z sezero $
+*/
+
+#ifndef __H2STDINC_H
+#define __H2STDINC_H
+
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+
+#define uint32_t u32int
+#define int32_t s32int
+#define int16_t s16int
+#define uint16_t u16int
+#define uint64_t u64int
+#define int64_t s64int
+
+#define intptr_t vlong
+#define uintptr_t uvlong
+#define ptrdiff_t vlong
+
+#define size_t uvlong
+
+#undef PI
+
+
+/*==========================================================================*/
+
+#ifndef NULL
+#if defined(__cplusplus)
+#define	NULL		0
+#else
+#define	NULL		((void *)0)
+#endif
+#endif
+
+#define	H2MAXCHAR	((char)0x7f)
+#define	H2MAXSHORT	((short)0x7fff)
+#define	H2MAXINT	((int)0x7fffffff)	/* max positive 32-bit integer */
+#define	H2MINCHAR	((char)0x80)
+#define	H2MINSHORT	((short)0x8000)
+#define	H2MININT	((int)0x80000000)	/* max negative 32-bit integer */
+
+/* Make sure the types really have the right
+ * sizes: These macros are from SDL headers.
+ */
+#define	COMPILE_TIME_ASSERT(name, x)	\
+	typedef int dummy_ ## name[(x) * 2 - 1]
+
+COMPILE_TIME_ASSERT(char, sizeof(char) == 1);
+COMPILE_TIME_ASSERT(float, sizeof(float) == 4);
+COMPILE_TIME_ASSERT(long, sizeof(long) >= 4);
+COMPILE_TIME_ASSERT(int, sizeof(int) == 4);
+COMPILE_TIME_ASSERT(short, sizeof(short) == 2);
+
+/* make sure enums are the size of ints for structure packing */
+typedef enum {
+	THE_DUMMY_VALUE
+} THE_DUMMY_ENUM;
+COMPILE_TIME_ASSERT(enum, sizeof(THE_DUMMY_ENUM) == sizeof(int));
+
+
+/*==========================================================================*/
+
+typedef unsigned char		byte;
+
+#undef true
+#undef false
+#if defined(__cplusplus)
+/* some structures have boolean members and the x86 asm code expect
+ * those members to be 4 bytes long. therefore, boolean must be 32
+ * bits and it can NOT be binary compatible with the 8 bit C++ bool.  */
+typedef int	boolean;
+COMPILE_TIME_ASSERT(falsehood, (0 == false));
+COMPILE_TIME_ASSERT(truth, (1  == true));
+#else
+typedef enum {
+	false = 0,
+	true  = 1
+} boolean;
+COMPILE_TIME_ASSERT(falsehood, ((1 != 1) == false));
+COMPILE_TIME_ASSERT(truth, ((1 == 1) == true));
+#endif
+COMPILE_TIME_ASSERT(boolean, sizeof(boolean) == 4);
+
+/*==========================================================================*/
+
+/* math */
+#define	FRACBITS		16
+#define	FRACUNIT		(1 << FRACBITS)
+
+typedef int	fixed_t;
+
+
+/*==========================================================================*/
+
+/* compatibility with DOS/Windows */
+#ifndef O_BINARY
+# if defined(_O_BINARY)
+#  define O_BINARY	_O_BINARY
+# else
+#  define O_BINARY		0
+# endif
+#endif
+
+/* compatibility with M$ types */
+#if !defined(_WIN32)
+#define	PASCAL
+#define	FAR
+#define	APIENTRY
+#endif	/* ! WINDOWS */
+
+/*==========================================================================*/
+
+/* compiler specific definitions */
+
+#if !defined(__GNUC__)
+#define	__attribute__(x)
+#endif	/* __GNUC__ */
+
+/* argument format attributes for function
+ * pointers are supported for gcc >= 3.1
+ */
+#if defined(__GNUC__) && (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 0))
+#define	__fp_attribute__	__attribute__
+#else
+#define	__fp_attribute__(x)
+#endif
+
+/* function optimize attribute is added
+ * starting with gcc 4.4.0
+ */
+#if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 3))
+#define	__no_optimize		__attribute__((__optimize__("0")))
+#else
+#define	__no_optimize
+#endif
+
+/*==========================================================================*/
+
+/* Some compilers, such as OpenWatcom, and possibly other compilers
+ * from the DOS universe, define __386__ instead of __i386__
+ */
+#if defined(__386__) && !defined(__i386__)
+#define __i386__	1
+#endif
+
+/*==========================================================================*/
+
+/* Provide a substitute for offsetof() if we don't have one.
+ * This variant works on most (but not *all*) systems...
+ */
+#ifndef offsetof
+#define offsetof(t,m) ((size_t)&(((t *)0)->m))
+#endif
+
+/*==========================================================================*/
+
+
+#endif	/* __H2STDINC_H */
+
--- /dev/null
+++ b/h_hubmsg.c
@@ -1,0 +1,122 @@
+
+//**************************************************************************
+//**
+//** h_hubmsg.c : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 373 $
+//** $Date: 2009-05-19 21:14:28 +0300 (Tue, 19 May 2009) $
+//**
+//**************************************************************************
+
+// HEADER FILES ------------------------------------------------------------
+
+#include "h2stdinc.h"
+#include "h2def.h"
+#include "h_hubmsg.h"
+
+// MACROS ------------------------------------------------------------------
+
+// TYPES -------------------------------------------------------------------
+
+// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
+
+// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
+
+// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
+
+// EXTERNAL DATA DECLARATIONS ----------------------------------------------
+
+// PUBLIC DATA DEFINITIONS -------------------------------------------------
+
+// PRIVATE DATA DEFINITIONS ------------------------------------------------
+
+static char ClusterMessage[MAX_INTRMSN_MESSAGE_SIZE];
+
+static const char *ClusMsgLumpNames[] =
+{
+	"CLUS1MSG",
+	"CLUS2MSG", 
+	"CLUS3MSG",
+	"CLUS4MSG", 
+	"CLUS5MSG"
+};
+
+static const char *winMsgLumpNames[] =
+{
+	"WIN1MSG",
+	"WIN2MSG",
+	"WIN3MSG"
+};
+
+static const char *winMsg_OldWad[] =
+{
+	TXT_WIN1MSG,
+	TXT_WIN2MSG,
+	TXT_WIN3MSG
+};
+
+static const char *ClusMsg_OldWad[] =
+{
+	TXT_CLUS1MSG,
+	TXT_CLUS2MSG, 
+	TXT_CLUS3MSG,
+	TXT_CLUS4MSG, 
+	TXT_CLUS5MSG
+};
+
+// CODE --------------------------------------------------------------------
+
+//==========================================================================
+//
+// GetClusterText
+//
+//==========================================================================
+
+const char *GetClusterText (int sequence)
+{
+	const char *msgLumpName;
+	int msgSize;
+	int msgLump;
+
+	if (oldwad_10)
+		return ClusMsg_OldWad[sequence];
+
+	msgLumpName = ClusMsgLumpNames[sequence];
+	msgLump = W_GetNumForName(msgLumpName);
+	msgSize = W_LumpLength(msgLump);
+	if (msgSize >= MAX_INTRMSN_MESSAGE_SIZE)
+	{
+		I_Error("Cluster message too long (%s)", msgLumpName);
+	}
+	W_ReadLump(msgLump, ClusterMessage);
+	ClusterMessage[msgSize] = 0; // Append terminator
+	return ClusterMessage;
+}
+
+//==========================================================================
+//
+// GetFinaleText
+//
+//==========================================================================
+
+const char *GetFinaleText (int sequence)
+{
+	const char *msgLumpName;
+	int msgSize;
+	int msgLump;
+
+	if (oldwad_10)
+		return winMsg_OldWad[sequence];
+
+	msgLumpName = winMsgLumpNames[sequence];
+	msgLump = W_GetNumForName(msgLumpName);
+	msgSize = W_LumpLength(msgLump);
+	if (msgSize >= MAX_INTRMSN_MESSAGE_SIZE)
+	{
+		I_Error("Finale message too long (%s)", msgLumpName);
+	}
+	W_ReadLump(msgLump, ClusterMessage);
+	ClusterMessage[msgSize] = 0;	// Append terminator
+	return ClusterMessage;
+}
+
--- /dev/null
+++ b/h_hubmsg.h
@@ -1,0 +1,125 @@
+
+//**************************************************************************
+//**
+//** h_hubmsg.h : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 373 $
+//** $Date: 2009-05-19 21:14:28 +0300 (Tue, 19 May 2009) $
+//**
+//**************************************************************************
+
+#ifndef _H_HUBMSG
+#define _H_HUBMSG
+
+#define MAX_INTRMSN_MESSAGE_SIZE	1024
+
+const char *GetClusterText(int sequence);
+const char *GetFinaleText (int sequence);
+
+/* Hardcoded Cluster Ending Messages for Version 1.0 WAD files: ----------*/
+/* h_hubmsg.c  -----------------------------------------------------------*/
+
+#define TXT_CLUS1MSG	"HAVING PASSED THE SEVEN PORTALS\n"		\
+			"WHICH SEALED THIS REALM, A VAST\n"		\
+			"DOMAIN OF HARSH WILDERNESS STRETCHES\n"	\
+			"BEFORE YOU. FIRE, ICE, AND STEEL HAVE\n"	\
+			"TESTED YOU, BUT GREATER CHALLANGES\n"		\
+			"REMAIN AHEAD. THE DENSE TANGLE OF\n"		\
+			"FOREST SURELY HIDES HOSTILE EYES,\n"		\
+			"BUT WHAT LIES BEYOND WILL BE WORSE.\n\n"	\
+			"BARREN DESERT, DANK SWAMPS AND\n"		\
+			"MUSTY CAVERNS BAR YOUR WAY, BUT YOU\n"		\
+			"CANNOT LET ANYTHING KEEP YOU FROM\n"		\
+			"YOUR FATE, EVEN IF YOU MIGHT COME\n"		\
+			"TO WISH THAT IT WOULD.\n\n"			\
+			"AND BEYOND, FLICKERING IN THE\n"		\
+			"DISTANCE, THE EVER-SHIFTING WALLS\n"		\
+			"OF THE HYPOSTYLE SEEM TO MOCK\n"		\
+			"YOUR EVERY EFFORT."
+
+#define TXT_CLUS2MSG	"YOUR MIND STILL REELING FROM YOUR\n"		\
+			"ENCOUNTERS WITHIN THE HYPOSTYLE, YOU\n"	\
+			"STAGGER TOWARD WHAT YOU HOPE IS\n"		\
+			"A WAY OUT, THINGS SEEM TO MOVE FASTER\n"	\
+			"AND FASTER, YOUR VISION BLURS AND\n"		\
+			"BEGINS TO FADE...\n"				\
+			"AS THE WORLD COLLAPSES AROUND YOU,\n"		\
+			"THE BRIGHTNESS OF A TELEPORTAL\n"		\
+			"ENGULFS YOU. A FLASH OF LIGHT AND THEN\n"	\
+			"YOU CLIMB WEARILY TO YOUR FEET.\n\n"		\
+			"YOU STAND ATOP A HIGH TOWER, AND\n"		\
+			"FROM BELOW COME THE SCREAMS OF THE\n"		\
+			"DAMNED. YOU STEP FORWARD, AND\n"		\
+			"INSTANTLY THE SOUND OF DEMONIC\n"		\
+			"CHANTING CHILLS YOUR BLOOD.\n"			\
+			"BY ALL THE GODS OF DEATH! WHAT PLACE\n"	\
+			"HAVE YOU COME TO? BY ALL THE GODS OF\n"	\
+			"PAIN, HOW WILL YOU EVER FIND YOUR\n"		\
+			"WAY OUT?"
+
+#define TXT_CLUS3MSG	"THE MIGHTIEST WEAPONS AND ARTIFACTS\n"		\
+			"OF THE ANCIENTS BARELY SUFFICED TO\n"		\
+			"DEFEAT THE HERESIARCH AND HIS\n"		\
+			"MINIONS, BUT NOW THEIR FOUL REMAINS\n"		\
+			"LIE STREWN AT YOUR FEET. GATHERING\n"		\
+			"THE LAST OF YOUR STRENGTH, YOU\n"		\
+			"PREPARE TO ENTER THE PORTAL WHICH\n"		\
+			"LEADS FROM THE HERESIARCH'S INNER\n"		\
+			"SANCTUM.\n\n"					\
+			"ABOVE YOU, THE RAMPARTS OF AN\n"		\
+			"IMMENSE CASTLE LOOM. SILENT TOWERS\n"		\
+			"AND BARE WALLS SURROUND A SINGLE\n"		\
+			"SPIRE OF BLACK STONE, WHICH SQUATS\n"		\
+			"IN THE CENTER OF THE CASTLE LIKE A\n"		\
+			"BROODING GIANT. FIRE AND SHADOW\n"		\
+			"TWIST BEHIND GAPING WINDOWS, DOZENS\n"		\
+			"OF BALEFUL EYES GLARING DOWN UPON\n"		\
+			"YOU.\n"					\
+			"SOMEWHERE WITHIN, YOUR ENEMIES ARE\n"		\
+			"WAITING..."
+
+#define TXT_CLUS4MSG	"\"... AND HE SHALL JOURNEY INTO THE\n"		\
+			"REALMS OF THE DEAD, AND CONTEST WITH\n"	\
+			"THE FORCES THEREIN, UNTO THE VERY\n"		\
+			"GATES OF DESPAIR, BUT WHETHER HE\n"		\
+			"SHALL RETURN AGAIN TO THE WORLD OF\n"		\
+			"LIGHT, NO MAN KNOWS.\"\n"			\
+			"\n\n\n\n\n"					\
+			"DAMN."
+
+#define TXT_CLUS5MSG	"PLEASE EMAIL THE DEVELOPERS\n"			\
+			"AND TELL THEM HOW YOU FOUND\n"			\
+			"THIS MESSAGE IN AS MUCH DETAIL\n"		\
+			"AS POSSIBLE SO THEY CAN PUT\n"			\
+			"THE RIGHT MESSAGE HERE.\n\n"			\
+			"THANKS."
+
+#define TXT_WIN1MSG	"WITH A SCREAM OF AGONY YOU ARE\n"		\
+			"WRENCHED FROM THIS WORLD INTO\n"		\
+			"ANTOHER, EVERY PART OF YOUR BODY\n"		\
+			"WREATHED IN MYSTIC FIRE. WHEN YOUR\n"		\
+			"VISION CLEARS, YOU FIND YOURSELF\n"		\
+			"STANDING IN A GREAT HALL, FILLED\n"		\
+			"WITH GHOSTLY ECHOES AND MENACING\n"		\
+			"SHADOWS. IN THE DISTANCE YOU CAN\n"		\
+			"SEE A RAISED DAIS, AND UPON IT THE\n"		\
+			"ONLY SOURCE OF LIGHT IN THIS WORLD."
+
+#define TXT_WIN2MSG	"THIS CAN ONLY BE THE CHAOS SPHERE,\n"		\
+			"THE SOURCE OF KORAX'S POWER. WITH\n"		\
+			"THIS, YOU CAN CREATE WORLDS... OR\n"		\
+			"DESTROY THEM. BY RIGHTS OF BATTLE\n"		\
+			"AND CONQUEST IT IS YOURS, AND WITH\n"		\
+			"TREMBLING HANDS YOU REACH TO GRASP\n"		\
+			"IT. PERHAPS, NOW, A NEW PLAYER WILL\n"		\
+			"JOIN THE COSMIC GAME OF POWER. LIKE\n"		\
+			"THE PAWN WHO IS PROMOTED TO QUEEN,\n"		\
+			"SUDDENLY THE VERY REACHES OF THE\n"		\
+			"BOARD SEEM TO BE WITHIN YOUR GRASP."
+
+#define TXT_WIN3MSG	"BUT THERE ARE OTHER PLAYERS MIGHTIER\n"	\
+			"THAN YOU, AND WHO CAN KNOW THEIR\n"		\
+			"NEXT MOVES?"
+
+#endif	/* _H_HUBMSG */
+
--- /dev/null
+++ b/i_cdmus.h
@@ -1,0 +1,44 @@
+
+//**************************************************************************
+//**
+//** i_cdmus.h : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 421 $
+//** $Date: 2009-05-22 16:08:37 +0300 (Fri, 22 May 2009) $
+//**
+//**************************************************************************
+
+#ifndef __ICDMUS__
+#define __ICDMUS__
+
+#define CDERR_NOTINSTALLED	10	/* MSCDEX not installed */
+#define CDERR_NOAUDIOSUPPORT	11	/* CD-ROM Doesn't support audio */
+#define CDERR_NOAUDIOTRACKS	12	/* Current CD has no audio tracks */
+#define CDERR_BADDRIVE		20	/* Bad drive number */
+#define CDERR_BADTRACK		21	/* Bad track number */
+#define CDERR_IOCTLBUFFMEM	22	/* Not enough low memory for IOCTL */
+#define CDERR_DEVREQBASE	100	/* DevReq errors */
+
+extern boolean i_CDMusic;	/* is cdaudio initialized */
+extern int cdaudio;		/* boolean: is cd audio enabled or disabled */
+
+extern int i_CDTrack;
+extern int i_CDCurrentTrack;
+extern int i_CDMusicLength;
+extern int oldTic;
+
+extern int cd_Error;
+
+int I_CDMusInit(void);
+int I_CDMusPlay(int track);
+int I_CDMusStop(void);
+int I_CDMusResume(void);
+int I_CDMusSetVolume(int volume);
+int I_CDMusFirstTrack(void);
+int I_CDMusLastTrack(void);
+int I_CDMusTrackLength(int track);
+void I_CDMusUpdate(void);
+void I_CDMusShutdown(void);
+
+#endif	/* __ICDMUS__ */
+
--- /dev/null
+++ b/i_sound.h
@@ -1,0 +1,54 @@
+//**************************************************************************
+//**
+//** i_sound.h : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 421 $
+//** $Date: 2009-05-22 16:08:37 +0300 (Fri, 22 May 2009) $
+//**
+//**************************************************************************
+
+#ifndef __SOUND__
+#define __SOUND__
+
+#define SND_TICRATE		140	/* tic rate for updating sound */
+#define SND_MAXSONGS		40	/* max number of songs in game */
+#define SND_SAMPLERATE		11025	/* sample rate of sound effects */
+
+typedef enum
+{
+	snd_none,
+	snd_PC,
+	snd_Adlib,
+	snd_SB,
+	snd_PAS,
+	snd_GUS,
+	snd_MPU,
+	snd_MPU2,
+	snd_MPU3,
+	snd_AWE,
+	snd_CDMUSIC,
+	NUM_SCARDS
+} cardenum_t;
+
+void I_PauseSong(int handle);
+void I_ResumeSong(int handle);
+void I_SetMusicVolume(int volume);
+void I_SetSfxVolume(int volume);
+int I_RegisterSong(void *data);
+int I_RegisterExternalSong(const char *name);	/* External music file support */
+void I_UnRegisterSong(int handle);
+int I_QrySongPlaying(int handle);
+void I_StopSong(int handle);
+void I_PlaySong(int handle, boolean looping);
+int I_GetSfxLumpNum(sfxinfo_t *sound);
+int I_StartSound (int id, void *data, int vol, int sep, int pitch, int priority);
+void I_StopSound(int handle);
+int I_SoundIsPlaying(int handle);
+void I_UpdateSoundParams(int handle, int vol, int sep, int pitch);
+void I_sndArbitrateCards(void);
+void I_StartupSound (void);
+void I_ShutdownSound (void);
+void I_SetChannels(int channels);
+
+#endif	/* __SOUND__ */
+
--- /dev/null
+++ b/in_lude.c
@@ -1,0 +1,586 @@
+
+//**************************************************************************
+//**
+//** in_lude.c : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 458 $
+//** $Date: 2009-05-25 15:35:27 +0300 (Mon, 25 May 2009) $
+//**
+//**************************************************************************
+
+#include "h2stdinc.h"
+#include <ctype.h>
+#include "h2def.h"
+#include "v_compat.h"
+
+// MACROS ------------------------------------------------------------------
+
+#define	TEXTSPEED	3
+#define	TEXTWAIT	140
+
+#ifdef RENDER3D
+#define V_DrawPatch(x,y,p)		OGL_DrawPatch((x),(y),(p))
+#define V_DrawRawScreen(a)		OGL_DrawRawScreen((a))
+#endif
+
+// TYPES -------------------------------------------------------------------
+
+typedef enum
+{
+	SINGLE,
+	COOPERATIVE,
+	DEATHMATCH
+} gametype_t;
+
+// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
+
+extern void AM_Stop(void);
+
+// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
+
+void IN_Start(void);
+void IN_Ticker(void);
+void IN_Drawer(void);
+
+// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
+
+static void WaitStop(void);
+static void Stop(void);
+static void LoadPics(void);
+static void UnloadPics(void);
+static void CheckForSkip(void);
+static void InitStats(void);
+static void DrDeathTally(void);
+static void DrNumber(int val, int x, int y, int wrapThresh);
+static void DrNumberBold(int val, int x, int y, int wrapThresh);
+static void DrawHubText(void);
+
+// EXTERNAL DATA DECLARATIONS ----------------------------------------------
+
+// PUBLIC DATA DECLARATIONS ------------------------------------------------
+
+boolean intermission;
+
+// PRIVATE DATA DEFINITIONS ------------------------------------------------
+
+static boolean skipintermission;
+static int interstate = 0;
+static int intertime = -1;
+static gametype_t gametype;
+static int cnt;
+static int slaughterboy; // in DM, the player with the most kills
+static PATCH_REF patchINTERPIC;
+static PATCH_REF FontBNumbers[10];
+static PATCH_REF FontBNegative;
+static PATCH_REF FontBSlash;
+static PATCH_REF FontBPercent;
+static int FontABaseLump;
+static int FontBLump;
+static int FontBLumpBase;
+
+static signed int totalFrags[MAXPLAYERS];
+
+static int HubCount;
+static const char *HubText;
+
+// CODE --------------------------------------------------------------------
+
+//========================================================================
+//
+// IN_Start
+//
+//========================================================================
+
+void IN_Start(void)
+{
+	int i;
+
+	V_SetPaletteBase();
+	InitStats();
+	LoadPics();
+	intermission = true;
+	interstate = 0;
+	skipintermission = false;
+	intertime = 0;
+	AM_Stop();
+	for (i = 0; i < MAXPLAYERS; i++)
+	{
+		players[i].messageTics = 0;
+		players[i].message[0] = 0;
+	}
+	SN_StopAllSequences();
+}
+
+//========================================================================
+//
+// Stop
+//
+//========================================================================
+
+static void Stop(void)
+{
+	intermission = false;
+	UnloadPics();
+	SB_state = -1;
+	BorderNeedRefresh = true;
+}
+
+//========================================================================
+//
+// WaitStop
+//
+//========================================================================
+
+void WaitStop(void)
+{
+	if (!--cnt)
+	{
+		Stop();
+//		gamestate = GS_LEVEL;
+//		G_DoLoadLevel();
+		gameaction = ga_leavemap;
+//		G_WorldDone();
+	}
+}
+
+//========================================================================
+//
+// InitStats
+//
+// 	Initializes the stats for single player mode
+//========================================================================
+
+static void InitStats(void)
+{
+	int i;
+	int j;
+	int oldCluster;
+	signed int slaughterfrags;
+	int posnum;
+	int slaughtercount;
+	int playercount;
+
+	extern int LeaveMap;
+
+	if (!deathmatch)
+	{
+		gametype = SINGLE;
+		HubCount = 0;
+		oldCluster = P_GetMapCluster(gamemap);
+		if (oldCluster != P_GetMapCluster(LeaveMap))
+		{
+			if (oldCluster >= 1 && oldCluster <= 5)
+			{
+				HubText = GetClusterText(oldCluster - 1);
+				HubCount = strlen(HubText)*TEXTSPEED + TEXTWAIT;
+				S_StartSongName("hub", true);
+			}
+		}
+	}
+	else
+	{
+		gametype = DEATHMATCH;
+		slaughterboy = 0;
+		slaughterfrags = -9999;
+		posnum = 0;
+		playercount = 0;
+		slaughtercount = 0;
+		for (i = 0; i < MAXPLAYERS; i++)
+		{
+			totalFrags[i] = 0;
+			if (playeringame[i])
+			{
+				playercount++;
+				for (j = 0; j < MAXPLAYERS; j++)
+				{
+					if (playeringame[j])
+					{
+						totalFrags[i] += players[i].frags[j];
+					}
+				}
+				posnum++;
+			}
+			if (totalFrags[i] > slaughterfrags)
+			{
+				slaughterboy = 1<<i;
+				slaughterfrags = totalFrags[i];
+				slaughtercount = 1;
+			}
+			else if (totalFrags[i] == slaughterfrags)
+			{
+				slaughterboy |= 1<<i;
+				slaughtercount++;
+			}
+		}
+		if (playercount == slaughtercount)
+		{ // don't do the slaughter stuff if everyone is equal
+			slaughterboy = 0;
+		}
+		S_StartSongName("hub", true);
+	}
+}
+
+//========================================================================
+//
+// LoadPics
+//
+//========================================================================
+
+static void LoadPics(void)
+{
+	int i;
+
+	if (HubCount || gametype == DEATHMATCH)
+	{
+		patchINTERPIC = (PATCH_REF) WR_CacheLumpName("INTERPIC", PU_STATIC);
+		FontBLumpBase = W_GetNumForName("FONTB16");
+		for (i = 0; i < 10; i++)
+		{
+			FontBNumbers[i] = (PATCH_REF) WR_CacheLumpNum(FontBLumpBase + i, PU_STATIC);
+		}
+		FontBLump = W_GetNumForName("FONTB_S") + 1;
+		FontBNegative = (PATCH_REF) WR_CacheLumpName("FONTB13", PU_STATIC);
+		FontABaseLump = W_GetNumForName("FONTA_S") + 1;
+
+		FontBSlash = (PATCH_REF) WR_CacheLumpName("FONTB15", PU_STATIC);
+		FontBPercent = (PATCH_REF) WR_CacheLumpName("FONTB05", PU_STATIC);
+	}
+}
+
+//========================================================================
+//
+// UnloadPics
+//
+//========================================================================
+
+static void UnloadPics(void)
+{
+#ifndef RENDER3D
+	int i;
+
+	if (HubCount || gametype == DEATHMATCH)
+	{
+		Z_ChangeTag(patchINTERPIC, PU_CACHE);
+		for (i = 0; i < 10; i++)
+		{
+			Z_ChangeTag(FontBNumbers[i], PU_CACHE);
+		}
+		Z_ChangeTag(FontBNegative, PU_CACHE);
+		Z_ChangeTag(FontBSlash, PU_CACHE);
+		Z_ChangeTag(FontBPercent, PU_CACHE);
+	}
+#endif
+}
+
+//========================================================================
+//
+// IN_Ticker
+//
+//========================================================================
+
+void IN_Ticker(void)
+{
+	if (!intermission)
+	{
+		return;
+	}
+	if (interstate)
+	{
+		WaitStop();
+		return;
+	}
+	skipintermission = false;
+	CheckForSkip();
+	intertime++;
+	if (skipintermission || (gametype == SINGLE && !HubCount))
+	{
+		interstate = 1;
+		cnt = 10;
+		skipintermission = false;
+		//S_StartSound(NULL, sfx_dorcls);
+	}
+}
+
+//========================================================================
+//
+// CheckForSkip
+//
+// 	Check to see if any player hit a key
+//========================================================================
+
+static void CheckForSkip(void)
+{
+	int i;
+	player_t *player;
+	static boolean triedToSkip;
+
+	for (i = 0, player = players; i < MAXPLAYERS; i++, player++)
+	{
+		if (playeringame[i])
+		{
+			if (player->cmd.buttons & BT_ATTACK)
+			{
+				if (!player->attackdown)
+				{
+					skipintermission = 1;
+				}
+				player->attackdown = true;
+			}
+			else
+			{
+				player->attackdown = false;
+			}
+			if (player->cmd.buttons & BT_USE)
+			{
+				if (!player->usedown)
+				{
+					skipintermission = 1;
+				}
+				player->usedown = true;
+			}
+			else
+			{
+				player->usedown = false;
+			}
+		}
+	}
+	if (deathmatch && intertime < 140)
+	{ // wait for 4 seconds before allowing a skip
+		if (skipintermission == 1)
+		{
+			triedToSkip = true;
+			skipintermission = 0;
+		}
+	}
+	else
+	{
+		if (triedToSkip)
+		{
+			skipintermission = 1;
+			triedToSkip = false;
+		}
+	}
+}
+
+//========================================================================
+//
+// IN_Drawer
+//
+//========================================================================
+
+void IN_Drawer(void)
+{
+	if (!intermission)
+	{
+		return;
+	}
+	if (interstate)
+	{
+		return;
+	}
+	UpdateState |= I_FULLSCRN;
+
+	V_DrawRawScreen((BYTE_REF) patchINTERPIC);
+
+	if (gametype == SINGLE)
+	{
+		if (HubCount)
+		{
+			DrawHubText();
+		}
+	}
+	else
+	{
+		DrDeathTally();
+	}
+}
+
+//========================================================================
+//
+// DrDeathTally
+//
+//========================================================================
+
+#define TALLY_EFFECT_TICKS	20
+#define TALLY_FINAL_X_DELTA	(23 * FRACUNIT)
+#define TALLY_FINAL_Y_DELTA	(13 * FRACUNIT)
+#define TALLY_START_XPOS	(178* FRACUNIT)
+#define TALLY_STOP_XPOS		(90 * FRACUNIT)
+#define TALLY_START_YPOS	(132* FRACUNIT)
+#define TALLY_STOP_YPOS		(83 * FRACUNIT)
+#define TALLY_TOP_X		85
+#define TALLY_TOP_Y		9
+#define TALLY_LEFT_X		7
+#define TALLY_LEFT_Y		71
+#define TALLY_TOTALS_X		291
+
+static void DrDeathTally(void)
+{
+	int i, j, temp;
+	fixed_t xPos, yPos;
+	fixed_t xDelta, yDelta;
+	fixed_t xStart, scale;
+	int x, y;
+	boolean bold;
+	static boolean showTotals;
+
+	V_DrawPatch(TALLY_TOP_X, TALLY_TOP_Y, (PATCH_REF)WR_CacheLumpName("tallytop", PU_CACHE));
+	V_DrawPatch(TALLY_LEFT_X, TALLY_LEFT_Y, (PATCH_REF)WR_CacheLumpName("tallylft", PU_CACHE));
+	if (intertime < TALLY_EFFECT_TICKS)
+	{
+		showTotals = false;
+		scale = (intertime * FRACUNIT) / TALLY_EFFECT_TICKS;
+		xDelta = FixedMul(scale, TALLY_FINAL_X_DELTA);
+		yDelta = FixedMul(scale, TALLY_FINAL_Y_DELTA);
+		xStart = TALLY_START_XPOS - FixedMul(scale, TALLY_START_XPOS-TALLY_STOP_XPOS);
+		yPos = TALLY_START_YPOS - FixedMul(scale, TALLY_START_YPOS-TALLY_STOP_YPOS);
+	}
+	else
+	{
+		xDelta = TALLY_FINAL_X_DELTA;
+		yDelta = TALLY_FINAL_Y_DELTA;
+		xStart = TALLY_STOP_XPOS;
+		yPos = TALLY_STOP_YPOS;
+	}
+	if (intertime >= TALLY_EFFECT_TICKS && showTotals == false)
+	{
+		showTotals = true;
+		S_StartSound(NULL, SFX_PLATFORM_STOP);
+	}
+	y = yPos>>FRACBITS;
+	for (i = 0; i < MAXPLAYERS; i++)
+	{
+		xPos = xStart;
+		for (j = 0; j < MAXPLAYERS; j++, xPos += xDelta)
+		{
+			x = xPos>>FRACBITS;
+			bold = (i == consoleplayer || j == consoleplayer);
+			if (playeringame[i] && playeringame[j])
+			{
+				if (bold)
+				{
+					DrNumberBold(players[i].frags[j], x, y, 100);
+				}
+				else
+				{
+					DrNumber(players[i].frags[j], x, y, 100);
+				}
+			}
+			else
+			{
+				temp = MN_TextAWidth("--")/2;
+				if (bold)
+				{
+					MN_DrTextAYellow("--", x - temp, y);
+				}
+				else
+				{
+					MN_DrTextA("--", x - temp, y);
+				}
+			}
+		}
+		if (showTotals && playeringame[i]
+			&& !((slaughterboy & (1<<i)) && !(intertime & 16)))
+		{
+			DrNumber(totalFrags[i], TALLY_TOTALS_X, y, 1000);
+		}
+		yPos += yDelta;
+		y = yPos>>FRACBITS;
+	}
+}
+
+//==========================================================================
+//
+// DrNumber
+//
+//==========================================================================
+
+static void DrNumber(int val, int x, int y, int wrapThresh)
+{
+	char buff[8] = "XX";
+
+	if (!(val < -9 && wrapThresh < 1000))
+	{
+		snprintf(buff, sizeof(buff), "%d", val >= wrapThresh ? val % wrapThresh : val);
+	}
+	MN_DrTextA(buff, x - MN_TextAWidth(buff)/2, y);
+}
+
+//==========================================================================
+//
+// DrNumberBold
+//
+//==========================================================================
+
+static void DrNumberBold(int val, int x, int y, int wrapThresh)
+{
+	char buff[8] = "XX";
+
+	if (!(val < -9 && wrapThresh < 1000))
+	{
+		snprintf(buff, sizeof(buff), "%d", val >= wrapThresh ? val % wrapThresh : val);
+	}
+	MN_DrTextAYellow(buff, x - MN_TextAWidth(buff)/2, y);
+}
+
+//===========================================================================
+//
+// DrawHubText
+//
+//===========================================================================
+
+static void DrawHubText(void)
+{
+	int		count;
+	const char	*ch;
+	int		c;
+	int		cx, cy;
+	patch_t		*w;
+	int		width;
+
+	cy = 5;
+	cx = 10;
+	ch = HubText;
+	count = (intertime - 10) / TEXTSPEED;
+	if (count < 0)
+	{
+		count = 0;
+	}
+	for ( ; count; count--)
+	{
+		c = *ch++;
+		if (!c)
+		{
+			break;
+		}
+		if (c == '\n')
+		{
+			cx = 10;
+			cy += 9;
+			continue;
+		}
+		if (c < 32)
+		{
+			continue;
+		}
+		c = toupper(c);
+		if (c == 32)
+		{
+			cx += 5;
+			continue;
+		}
+		w = (patch_t *) W_CacheLumpNum(FontABaseLump + c - 33, PU_CACHE);
+		width = SHORT(w->width);
+		if (cx + width > SCREENWIDTH)
+		{
+			break;
+		}
+#ifdef RENDER3D
+		OGL_DrawPatch_CS(cx, cy, FontABaseLump + c - 33);
+#else
+		V_DrawPatch(cx, cy, w);
+#endif
+		cx += width;
+	}
+}
+
--- /dev/null
+++ b/info.c
@@ -1,0 +1,14174 @@
+
+//**************************************************************************
+//**
+//** info.c : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 373 $
+//** $Date: 2009-05-19 21:14:28 +0300 (Tue, 19 May 2009) $
+//**
+//**************************************************************************
+
+#include "h2stdinc.h"
+#include "h2def.h"
+// generated by stateco
+
+const char *sprnames[NUMSPRITES] = {
+"MAN1","ACLO","TLGL","FBL1","XPL1","ARRW","DART","RIPP","CFCF","BLAD",
+"SHRD","FFSM","FFLG","PTN1","PTN2","SOAR","INVU","SUMN","TSPK","TELO",
+"TRNG","ROCK","FOGS","FOGM","FOGL","SGSA","SGSB","PORK","EGGM","FHFX",
+"SPHL","STWN","GMPD","ASKU","ABGM","AGMR","AGMG","AGG2","AGMB","AGB2",
+"ABK1","ABK2","ASK2","AFWP","ACWP","AMWP","AGER","AGR2","AGR3","AGR4",
+"TRCH","PSBG","ATLP","THRW","SPED","BMAN","BRAC","BLST","HRAD","SPSH",
+"LVAS","SLDG","STTW","RCK1","RCK2","RCK3","RCK4","CDLR","TRE1","TRDT",
+"TRE2","TRE3","STM1","STM2","STM3","STM4","MSH1","MSH2","MSH3","MSH4",
+"MSH5","MSH6","MSH7","MSH8","SGMP","SGM1","SGM2","SGM3","SLC1","SLC2",
+"SLC3","MSS1","MSS2","SWMV","CPS1","CPS2","TMS1","TMS2","TMS3","TMS4",
+"TMS5","TMS6","TMS7","CPS3","STT2","STT3","STT4","STT5","GAR1","GAR2",
+"GAR3","GAR4","GAR5","GAR6","GAR7","GAR8","GAR9","BNR1","TRE4","TRE5",
+"TRE6","TRE7","LOGG","ICT1","ICT2","ICT3","ICT4","ICM1","ICM2","ICM3",
+"ICM4","RKBL","RKBS","RKBK","RBL1","RBL2","RBL3","VASE","POT1","POT2",
+"POT3","PBIT","CPS4","CPS5","CPS6","CPB1","CPB2","CPB3","CPB4","BDRP",
+"BDSH","BDPL","CNDL","LEF1","LEF3","LEF2","TWTR","WLTR","BARL","SHB1",
+"SHB2","BCKT","SHRM","FBUL","FSKL","BRTR","SUIT","BBLL","CAND","IRON",
+"XMAS","CDRN","CHNS","TST1","TST2","TST3","TST4","TST5","TST6","TST7",
+"TST8","TST9","TST0","TELE","TSMK","FPCH","WFAX","FAXE","WFHM","FHMR",
+"FSRD","FSFX","CMCE","WCSS","CSSF","WCFM","CFLM","CFFX","CHLY","SPIR",
+"MWND","WMLG","MLNG","MLFX","MLF2","MSTF","MSP1","MSP2","WFR1","WFR2",
+"WFR3","WCH1","WCH2","WCH3","WMS1","WMS2","WMS3","WPIG","WMCS","CONE",
+"SHEX","BLOD","GIBS","PLAY","FDTH","BSKL","ICEC","CLER","MAGE","PIGY",
+"CENT","CTXD","CTFX","CTDP","DEMN","DEMA","DEMB","DEMC","DEMD","DEME",
+"DMFX","DEM2","DMBA","DMBB","DMBC","DMBD","DMBE","D2FX","WRTH","WRT2",
+"WRBL","MNTR","FX12","FX13","MNSM","SSPT","SSDV","SSXD","SSFX","BISH",
+"BPFX","DRAG","DRFX","ARM1","ARM2","ARM3","ARM4","MAN2","MAN3","KEY1",
+"KEY2","KEY3","KEY4","KEY5","KEY6","KEY7","KEY8","KEY9","KEYA","KEYB",
+"ETTN","ETTB","FDMN","FDMB","ICEY","ICPR","ICWS","SORC","SBMP","SBS4",
+"SBMB","SBS3","SBMG","SBS1","SBS2","SBFX","RADE","WATR","KORX","ABAT",
+#ifdef ASSASSIN
+"AKTR","ACSB","AGRN","ASTF","ASP1","ASP2","ASSN",
+#endif
+NULL
+};
+
+void A_FreeTargMobj ();
+void A_FlameCheck ();
+void A_HideThing ();
+void A_UnHideThing ();
+void A_RestoreSpecialThing1 ();
+void A_RestoreSpecialThing2 ();
+void A_RestoreArtifact ();
+void A_Summon ();
+void A_ThrustInitUp ();
+void A_ThrustInitDn ();
+void A_ThrustRaise ();
+void A_ThrustBlock ();
+void A_ThrustImpale ();
+void A_ThrustLower ();
+void A_TeloSpawnC ();
+void A_TeloSpawnB ();
+void A_TeloSpawnA ();
+void A_TeloSpawnD ();
+void A_CheckTeleRing ();
+void A_FogSpawn ();
+void A_FogMove ();
+void A_Quake ();
+void A_ContMobjSound ();
+void A_Scream ();
+void A_Explode ();
+void A_PoisonBagInit ();
+void A_PoisonBagDamage ();
+void A_PoisonBagCheck ();
+void A_CheckThrowBomb ();
+void A_NoGravity ();
+void A_PotteryExplode ();
+void A_PotteryChooseBit ();
+void A_PotteryCheck ();
+void A_CorpseBloodDrip ();
+void A_CorpseExplode ();
+void A_LeafSpawn ();
+void A_LeafThrust ();
+void A_LeafCheck ();
+void A_BridgeInit ();
+void A_BridgeOrbit ();
+void A_TreeDeath ();
+void A_PoisonShroom ();
+void A_Pain ();
+void A_SoAExplode ();
+void A_BellReset1 ();
+void A_BellReset2 ();
+void A_NoBlocking ();
+void A_Light0 ();
+void A_WeaponReady ();
+void A_Lower ();
+void A_Raise ();
+void A_FPunchAttack ();
+void A_ReFire ();
+void A_FAxeAttack ();
+void A_FHammerAttack ();
+void A_FHammerThrow ();
+void A_FSwordAttack ();
+void A_FSwordFlames ();
+void A_CMaceAttack ();
+void A_CStaffInitBlink ();
+void A_CStaffCheckBlink ();
+void A_CStaffCheck ();
+void A_CStaffAttack ();
+void A_CStaffMissileSlither ();
+void A_CFlameAttack ();
+void A_CFlameRotate ();
+void A_CFlamePuff ();
+void A_CFlameMissile ();
+void A_CHolyAttack ();
+void A_CHolyPalette ();
+void A_CHolySeek ();
+void A_CHolyCheckScream ();
+void A_CHolyTail ();
+void A_CHolySpawnPuff ();
+void A_CHolyAttack2 ();
+void A_MWandAttack ();
+void A_LightningReady ();
+void A_MLightningAttack ();
+void A_LightningZap ();
+void A_LightningClip ();
+void A_LightningRemove ();
+void A_LastZap ();
+void A_ZapMimic ();
+void A_MStaffAttack ();
+void A_MStaffPalette ();
+void A_MStaffWeave ();
+void A_MStaffTrack ();
+void A_SnoutAttack ();
+void A_FireConePL1 ();
+void A_ShedShard ();
+void A_AddPlayerCorpse ();
+void A_SkullPop ();
+void A_FreezeDeath ();
+void A_FreezeDeathChunks ();
+void A_CheckBurnGone ();
+void A_CheckSkullFloor ();
+void A_CheckSkullDone ();
+void A_SpeedFade ();
+void A_IceSetTics ();
+void A_IceCheckHeadDone ();
+void A_PigPain ();
+void A_PigLook ();
+void A_PigChase ();
+void A_FaceTarget ();
+void A_PigAttack ();
+void A_QueueCorpse ();
+void A_Look ();
+void A_Chase ();
+void A_CentaurAttack ();
+void A_CentaurAttack2 ();
+void A_SetReflective ();
+void A_CentaurDefend ();
+void A_UnSetReflective ();
+void A_CentaurDropStuff ();
+void A_CheckFloor ();
+void A_DemonAttack1 ();
+void A_DemonAttack2 ();
+void A_DemonDeath ();
+void A_Demon2Death ();
+void A_WraithRaiseInit ();
+void A_WraithRaise ();
+void A_WraithInit ();
+void A_WraithLook ();
+void A_WraithChase ();
+void A_WraithFX3 ();
+void A_WraithMelee ();
+void A_WraithMissile ();
+void A_WraithFX2 ();
+void A_MinotaurFade1 ();
+void A_MinotaurFade2 ();
+void A_MinotaurLook ();
+void A_MinotaurChase ();
+void A_MinotaurRoam ();
+void A_MinotaurAtk1 ();
+void A_MinotaurDecide ();
+void A_MinotaurAtk2 ();
+void A_MinotaurAtk3 ();
+void A_MinotaurCharge ();
+void A_SmokePuffExit ();
+void A_MinotaurFade0 ();
+void A_MntrFloorFire ();
+void A_SerpentChase ();
+void A_SerpentHumpDecide ();
+void A_SerpentUnHide ();
+void A_SerpentRaiseHump ();
+void A_SerpentLowerHump ();
+void A_SerpentHide ();
+void A_SerpentBirthScream ();
+void A_SetShootable ();
+void A_SerpentCheckForAttack ();
+void A_UnSetShootable ();
+void A_SerpentDiveSound ();
+void A_SerpentWalk ();
+void A_SerpentChooseAttack ();
+void A_SerpentMeleeAttack ();
+void A_SerpentMissileAttack ();
+void A_SerpentHeadPop ();
+void A_SerpentSpawnGibs ();
+void A_SerpentHeadCheck ();
+void A_FloatGib ();
+void A_DelayGib ();
+void A_SinkGib ();
+void A_BishopDecide ();
+void A_BishopDoBlur ();
+void A_BishopSpawnBlur ();
+void A_BishopChase ();
+void A_BishopAttack ();
+void A_BishopAttack2 ();
+void A_BishopPainBlur ();
+void A_BishopPuff ();
+void A_SetAltShadow ();
+void A_BishopMissileWeave ();
+void A_BishopMissileSeek ();
+void A_DragonInitFlight ();
+void A_DragonFlap ();
+void A_DragonFlight ();
+void A_DragonAttack ();
+void A_DragonPain ();
+void A_DragonCheckCrash ();
+void A_DragonFX2 ();
+void A_ESound ();
+void A_EttinAttack ();
+void A_DropMace ();
+void A_FiredRocks ();
+void A_UnSetInvulnerable ();
+void A_FiredChase ();
+void A_FiredAttack ();
+void A_FiredSplotch ();
+void A_SmBounce ();
+void A_IceGuyLook ();
+void A_IceGuyChase ();
+void A_IceGuyAttack ();
+void A_IceGuyDie ();
+void A_IceGuyMissilePuff ();
+void A_IceGuyMissileExplode ();
+void A_ClassBossHealth ();
+void A_FastChase ();
+void A_FighterAttack ();
+void A_ClericAttack ();
+void A_MageAttack ();
+void A_SorcSpinBalls ();
+void A_SpeedBalls ();
+void A_SpawnFizzle ();
+void A_SorcBossAttack ();
+void A_SorcBallOrbit ();
+void A_SorcBallPop ();
+void A_BounceCheck ();
+void A_SorcFX1Seek ();
+void A_SorcFX2Split ();
+void A_SorcFX2Orbit ();
+void A_SorcererBishopEntry ();
+void A_SpawnBishop ();
+void A_SorcFX4Check ();
+void A_KoraxStep2 ();
+void A_KoraxChase ();
+void A_KoraxStep ();
+void A_KoraxDecide ();
+void A_KoraxMissile ();
+void A_KoraxCommand ();
+void A_KoraxBonePop ();
+void A_KSpiritRoam ();
+void A_KBoltRaise ();
+void A_KBolt ();
+void A_BatSpawnInit ();
+void A_BatSpawn ();
+void A_BatMove ();
+#ifdef ASSASSIN
+void A_AKnifeAttack ();
+void A_ACrossAttack ();
+void A_AGrenAttack ();
+void A_AStaffAttack ();
+#endif
+
+state_t	states[NUMSTATES] = {
+{SPR_MAN1,0,-1,NULL,S_NULL,0,0},	// S_NULL
+{SPR_ACLO,4,1050,A_FreeTargMobj,S_NULL,0,0},	// S_FREETARGMOBJ
+{SPR_TLGL,0,-1,NULL,S_NULL,0,0},	// S_MAPSPOT
+{SPR_FBL1,32768,4,NULL,S_FIREBALL1_2,0,0},	// S_FIREBALL1_1
+{SPR_FBL1,32769,4,NULL,S_FIREBALL1_1,0,0},	// S_FIREBALL1_2
+{SPR_XPL1,32768,4,NULL,S_FIREBALL1_X2,0,0},	// S_FIREBALL1_X1
+{SPR_XPL1,32769,4,NULL,S_FIREBALL1_X3,0,0},	// S_FIREBALL1_X2
+{SPR_XPL1,32770,4,NULL,S_FIREBALL1_X4,0,0},	// S_FIREBALL1_X3
+{SPR_XPL1,32771,4,NULL,S_FIREBALL1_X5,0,0},	// S_FIREBALL1_X4
+{SPR_XPL1,32772,4,NULL,S_FIREBALL1_X6,0,0},	// S_FIREBALL1_X5
+{SPR_XPL1,32773,4,NULL,S_NULL,0,0},	// S_FIREBALL1_X6
+{SPR_ARRW,0,-1,NULL,S_NULL,0,0},	// S_ARROW_1
+{SPR_ARRW,0,1,NULL,S_NULL,0,0},	// S_ARROW_X1
+{SPR_DART,0,-1,NULL,S_NULL,0,0},	// S_DART_1
+{SPR_DART,0,1,NULL,S_NULL,0,0},	// S_DART_X1
+{SPR_DART,0,-1,NULL,S_NULL,0,0},	// S_POISONDART_1
+{SPR_DART,0,1,NULL,S_NULL,0,0},	// S_POISONDART_X1
+{SPR_RIPP,0,3,NULL,S_RIPPERBALL_2,0,0},	// S_RIPPERBALL_1
+{SPR_RIPP,1,3,NULL,S_RIPPERBALL_3,0,0},	// S_RIPPERBALL_2
+{SPR_RIPP,2,3,NULL,S_RIPPERBALL_1,0,0},	// S_RIPPERBALL_3
+{SPR_CFCF,32784,4,NULL,S_RIPPERBALL_X2,0,0},	// S_RIPPERBALL_X1
+{SPR_CFCF,32785,3,NULL,S_RIPPERBALL_X3,0,0},	// S_RIPPERBALL_X2
+{SPR_CFCF,32786,4,NULL,S_RIPPERBALL_X4,0,0},	// S_RIPPERBALL_X3
+{SPR_CFCF,32787,3,NULL,S_RIPPERBALL_X5,0,0},	// S_RIPPERBALL_X4
+{SPR_CFCF,32788,4,NULL,S_RIPPERBALL_X6,0,0},	// S_RIPPERBALL_X5
+{SPR_CFCF,32789,3,NULL,S_RIPPERBALL_X7,0,0},	// S_RIPPERBALL_X6
+{SPR_CFCF,32790,4,NULL,S_RIPPERBALL_X8,0,0},	// S_RIPPERBALL_X7
+{SPR_CFCF,32791,3,NULL,S_RIPPERBALL_X9,0,0},	// S_RIPPERBALL_X8
+{SPR_CFCF,32792,4,NULL,S_RIPPERBALL_X10,0,0},	// S_RIPPERBALL_X9
+{SPR_CFCF,32793,3,NULL,S_NULL,0,0},	// S_RIPPERBALL_X10
+{SPR_BLAD,0,-1,NULL,S_NULL,0,0},	// S_PRJ_BLADE1
+{SPR_BLAD,0,1,NULL,S_NULL,0,0},	// S_PRJ_BLADE_X1
+{SPR_SHRD,32768,3,NULL,S_ICESHARD2,0,0},	// S_ICESHARD1
+{SPR_SHRD,32769,3,NULL,S_ICESHARD3,0,0},	// S_ICESHARD2
+{SPR_SHRD,32770,3,NULL,S_ICESHARD1,0,0},	// S_ICESHARD3
+{SPR_FFSM,32768,3,NULL,S_FLAME_TSMALL2,0,0},	// S_FLAME_TSMALL1
+{SPR_FFSM,32769,3,NULL,S_FLAME_TSMALL3,0,0},	// S_FLAME_TSMALL2
+{SPR_FFSM,32770,2,A_FlameCheck,S_FLAME_TSMALL4,0,0},	// S_FLAME_TSMALL3
+{SPR_FFSM,32770,2,NULL,S_FLAME_TSMALL5,0,0},	// S_FLAME_TSMALL4
+{SPR_FFSM,32771,3,NULL,S_FLAME_TSMALL6,0,0},	// S_FLAME_TSMALL5
+{SPR_FFSM,32772,3,A_FlameCheck,S_FLAME_TSMALL1,0,0},	// S_FLAME_TSMALL6
+{SPR_FFLG,32768,4,NULL,S_FLAME_TLARGE2,0,0},	// S_FLAME_TLARGE1
+{SPR_FFLG,32769,4,A_FlameCheck,S_FLAME_TLARGE3,0,0},	// S_FLAME_TLARGE2
+{SPR_FFLG,32770,4,NULL,S_FLAME_TLARGE4,0,0},	// S_FLAME_TLARGE3
+{SPR_FFLG,32771,4,A_FlameCheck,S_FLAME_TLARGE5,0,0},	// S_FLAME_TLARGE4
+{SPR_FFLG,32772,4,NULL,S_FLAME_TLARGE6,0,0},	// S_FLAME_TLARGE5
+{SPR_FFLG,32773,4,A_FlameCheck,S_FLAME_TLARGE7,0,0},	// S_FLAME_TLARGE6
+{SPR_FFLG,32774,4,NULL,S_FLAME_TLARGE8,0,0},	// S_FLAME_TLARGE7
+{SPR_FFLG,32775,4,A_FlameCheck,S_FLAME_TLARGE9,0,0},	// S_FLAME_TLARGE8
+{SPR_FFLG,32776,4,NULL,S_FLAME_TLARGE10,0,0},	// S_FLAME_TLARGE9
+{SPR_FFLG,32777,4,A_FlameCheck,S_FLAME_TLARGE11,0,0},	// S_FLAME_TLARGE10
+{SPR_FFLG,32778,4,NULL,S_FLAME_TLARGE12,0,0},	// S_FLAME_TLARGE11
+{SPR_FFLG,32779,4,A_FlameCheck,S_FLAME_TLARGE13,0,0},	// S_FLAME_TLARGE12
+{SPR_FFLG,32780,4,NULL,S_FLAME_TLARGE14,0,0},	// S_FLAME_TLARGE13
+{SPR_FFLG,32781,4,A_FlameCheck,S_FLAME_TLARGE15,0,0},	// S_FLAME_TLARGE14
+{SPR_FFLG,32782,4,NULL,S_FLAME_TLARGE16,0,0},	// S_FLAME_TLARGE15
+{SPR_FFLG,32783,4,A_FlameCheck,S_FLAME_TLARGE5,0,0},	// S_FLAME_TLARGE16
+{SPR_FFSM,0,2,NULL,S_FLAME_SDORM2,0,0},	// S_FLAME_SDORM1
+{SPR_FFSM,1,2,A_HideThing,S_FLAME_SDORM3,0,0},	// S_FLAME_SDORM2
+{SPR_FFSM,2,200,NULL,S_FLAME_SDORM3,0,0},	// S_FLAME_SDORM3
+{SPR_FFSM,32768,3,NULL,S_FLAME_SMALL2,0,0},	// S_FLAME_SMALL1
+{SPR_FFSM,32768,3,A_UnHideThing,S_FLAME_SMALL3,0,0},	// S_FLAME_SMALL2
+{SPR_FFSM,32768,3,NULL,S_FLAME_SMALL4,0,0},	// S_FLAME_SMALL3
+{SPR_FFSM,32769,3,NULL,S_FLAME_SMALL5,0,0},	// S_FLAME_SMALL4
+{SPR_FFSM,32770,3,NULL,S_FLAME_SMALL6,0,0},	// S_FLAME_SMALL5
+{SPR_FFSM,32771,3,NULL,S_FLAME_SMALL7,0,0},	// S_FLAME_SMALL6
+{SPR_FFSM,32772,3,NULL,S_FLAME_SMALL3,0,0},	// S_FLAME_SMALL7
+{SPR_FFLG,3,2,NULL,S_FLAME_LDORM2,0,0},	// S_FLAME_LDORM1
+{SPR_FFLG,2,2,NULL,S_FLAME_LDORM3,0,0},	// S_FLAME_LDORM2
+{SPR_FFLG,1,2,NULL,S_FLAME_LDORM4,0,0},	// S_FLAME_LDORM3
+{SPR_FFLG,0,2,A_HideThing,S_FLAME_LDORM5,0,0},	// S_FLAME_LDORM4
+{SPR_FFLG,0,200,NULL,S_FLAME_LDORM5,0,0},	// S_FLAME_LDORM5
+{SPR_FFLG,32768,2,NULL,S_FLAME_LARGE2,0,0},	// S_FLAME_LARGE1
+{SPR_FFLG,32768,2,A_UnHideThing,S_FLAME_LARGE3,0,0},	// S_FLAME_LARGE2
+{SPR_FFLG,32768,4,NULL,S_FLAME_LARGE4,0,0},	// S_FLAME_LARGE3
+{SPR_FFLG,32769,4,NULL,S_FLAME_LARGE5,0,0},	// S_FLAME_LARGE4
+{SPR_FFLG,32770,4,NULL,S_FLAME_LARGE6,0,0},	// S_FLAME_LARGE5
+{SPR_FFLG,32771,4,NULL,S_FLAME_LARGE7,0,0},	// S_FLAME_LARGE6
+{SPR_FFLG,32772,4,NULL,S_FLAME_LARGE8,0,0},	// S_FLAME_LARGE7
+{SPR_FFLG,32773,4,NULL,S_FLAME_LARGE9,0,0},	// S_FLAME_LARGE8
+{SPR_FFLG,32774,4,NULL,S_FLAME_LARGE10,0,0},	// S_FLAME_LARGE9
+{SPR_FFLG,32775,4,NULL,S_FLAME_LARGE11,0,0},	// S_FLAME_LARGE10
+{SPR_FFLG,32776,4,NULL,S_FLAME_LARGE12,0,0},	// S_FLAME_LARGE11
+{SPR_FFLG,32777,4,NULL,S_FLAME_LARGE13,0,0},	// S_FLAME_LARGE12
+{SPR_FFLG,32778,4,NULL,S_FLAME_LARGE14,0,0},	// S_FLAME_LARGE13
+{SPR_FFLG,32779,4,NULL,S_FLAME_LARGE15,0,0},	// S_FLAME_LARGE14
+{SPR_FFLG,32780,4,NULL,S_FLAME_LARGE16,0,0},	// S_FLAME_LARGE15
+{SPR_FFLG,32781,4,NULL,S_FLAME_LARGE17,0,0},	// S_FLAME_LARGE16
+{SPR_FFLG,32782,4,NULL,S_FLAME_LARGE18,0,0},	// S_FLAME_LARGE17
+{SPR_FFLG,32783,4,NULL,S_FLAME_LARGE7,0,0},	// S_FLAME_LARGE18
+{SPR_PTN1,0,3,NULL,S_ITEM_PTN1_2,0,0},	// S_ITEM_PTN1_1
+{SPR_PTN1,1,3,NULL,S_ITEM_PTN1_3,0,0},	// S_ITEM_PTN1_2
+{SPR_PTN1,2,3,NULL,S_ITEM_PTN1_1,0,0},	// S_ITEM_PTN1_3
+{SPR_ACLO,4,1400,NULL,S_HIDESPECIAL2,0,0},	// S_HIDESPECIAL1
+{SPR_ACLO,0,4,A_RestoreSpecialThing1,S_HIDESPECIAL3,0,0},	// S_HIDESPECIAL2
+{SPR_ACLO,1,4,NULL,S_HIDESPECIAL4,0,0},	// S_HIDESPECIAL3
+{SPR_ACLO,0,4,NULL,S_HIDESPECIAL5,0,0},	// S_HIDESPECIAL4
+{SPR_ACLO,1,4,NULL,S_HIDESPECIAL6,0,0},	// S_HIDESPECIAL5
+{SPR_ACLO,2,4,NULL,S_HIDESPECIAL7,0,0},	// S_HIDESPECIAL6
+{SPR_ACLO,1,4,NULL,S_HIDESPECIAL8,0,0},	// S_HIDESPECIAL7
+{SPR_ACLO,2,4,NULL,S_HIDESPECIAL9,0,0},	// S_HIDESPECIAL8
+{SPR_ACLO,3,4,NULL,S_HIDESPECIAL10,0,0},	// S_HIDESPECIAL9
+{SPR_ACLO,2,4,NULL,S_HIDESPECIAL11,0,0},	// S_HIDESPECIAL10
+{SPR_ACLO,3,4,A_RestoreSpecialThing2,S_NULL,0,0},	// S_HIDESPECIAL11
+{SPR_ACLO,3,3,NULL,S_DORMANTARTI1_2,0,0},	// S_DORMANTARTI1_1
+{SPR_ACLO,2,3,NULL,S_DORMANTARTI1_3,0,0},	// S_DORMANTARTI1_2
+{SPR_ACLO,3,3,NULL,S_DORMANTARTI1_4,0,0},	// S_DORMANTARTI1_3
+{SPR_ACLO,2,3,NULL,S_DORMANTARTI1_5,0,0},	// S_DORMANTARTI1_4
+{SPR_ACLO,1,3,NULL,S_DORMANTARTI1_6,0,0},	// S_DORMANTARTI1_5
+{SPR_ACLO,2,3,NULL,S_DORMANTARTI1_7,0,0},	// S_DORMANTARTI1_6
+{SPR_ACLO,1,3,NULL,S_DORMANTARTI1_8,0,0},	// S_DORMANTARTI1_7
+{SPR_ACLO,0,3,NULL,S_DORMANTARTI1_9,0,0},	// S_DORMANTARTI1_8
+{SPR_ACLO,1,3,NULL,S_DORMANTARTI1_10,0,0},	// S_DORMANTARTI1_9
+{SPR_ACLO,0,3,NULL,S_DORMANTARTI1_11,0,0},	// S_DORMANTARTI1_10
+{SPR_ACLO,0,1400,A_HideThing,S_DORMANTARTI1_12,0,0},	// S_DORMANTARTI1_11
+{SPR_ACLO,0,3,A_UnHideThing,S_DORMANTARTI1_13,0,0},	// S_DORMANTARTI1_12
+{SPR_ACLO,1,3,NULL,S_DORMANTARTI1_14,0,0},	// S_DORMANTARTI1_13
+{SPR_ACLO,0,3,NULL,S_DORMANTARTI1_15,0,0},	// S_DORMANTARTI1_14
+{SPR_ACLO,1,3,NULL,S_DORMANTARTI1_16,0,0},	// S_DORMANTARTI1_15
+{SPR_ACLO,2,3,NULL,S_DORMANTARTI1_17,0,0},	// S_DORMANTARTI1_16
+{SPR_ACLO,1,3,NULL,S_DORMANTARTI1_18,0,0},	// S_DORMANTARTI1_17
+{SPR_ACLO,2,3,NULL,S_DORMANTARTI1_19,0,0},	// S_DORMANTARTI1_18
+{SPR_ACLO,3,3,NULL,S_DORMANTARTI1_20,0,0},	// S_DORMANTARTI1_19
+{SPR_ACLO,2,3,NULL,S_DORMANTARTI1_21,0,0},	// S_DORMANTARTI1_20
+{SPR_ACLO,3,3,A_RestoreArtifact,S_NULL,0,0},	// S_DORMANTARTI1_21
+{SPR_ACLO,3,3,NULL,S_DORMANTARTI2_2,0,0},	// S_DORMANTARTI2_1
+{SPR_ACLO,2,3,NULL,S_DORMANTARTI2_3,0,0},	// S_DORMANTARTI2_2
+{SPR_ACLO,3,3,NULL,S_DORMANTARTI2_4,0,0},	// S_DORMANTARTI2_3
+{SPR_ACLO,2,3,NULL,S_DORMANTARTI2_5,0,0},	// S_DORMANTARTI2_4
+{SPR_ACLO,1,3,NULL,S_DORMANTARTI2_6,0,0},	// S_DORMANTARTI2_5
+{SPR_ACLO,2,3,NULL,S_DORMANTARTI2_7,0,0},	// S_DORMANTARTI2_6
+{SPR_ACLO,1,3,NULL,S_DORMANTARTI2_8,0,0},	// S_DORMANTARTI2_7
+{SPR_ACLO,0,3,NULL,S_DORMANTARTI2_9,0,0},	// S_DORMANTARTI2_8
+{SPR_ACLO,1,3,NULL,S_DORMANTARTI2_10,0,0},	// S_DORMANTARTI2_9
+{SPR_ACLO,0,3,NULL,S_DORMANTARTI2_11,0,0},	// S_DORMANTARTI2_10
+{SPR_ACLO,0,4200,A_HideThing,S_DORMANTARTI2_12,0,0},	// S_DORMANTARTI2_11
+{SPR_ACLO,0,3,A_UnHideThing,S_DORMANTARTI2_13,0,0},	// S_DORMANTARTI2_12
+{SPR_ACLO,1,3,NULL,S_DORMANTARTI2_14,0,0},	// S_DORMANTARTI2_13
+{SPR_ACLO,0,3,NULL,S_DORMANTARTI2_15,0,0},	// S_DORMANTARTI2_14
+{SPR_ACLO,1,3,NULL,S_DORMANTARTI2_16,0,0},	// S_DORMANTARTI2_15
+{SPR_ACLO,2,3,NULL,S_DORMANTARTI2_17,0,0},	// S_DORMANTARTI2_16
+{SPR_ACLO,1,3,NULL,S_DORMANTARTI2_18,0,0},	// S_DORMANTARTI2_17
+{SPR_ACLO,2,3,NULL,S_DORMANTARTI2_19,0,0},	// S_DORMANTARTI2_18
+{SPR_ACLO,3,3,NULL,S_DORMANTARTI2_20,0,0},	// S_DORMANTARTI2_19
+{SPR_ACLO,2,3,NULL,S_DORMANTARTI2_21,0,0},	// S_DORMANTARTI2_20
+{SPR_ACLO,3,3,A_RestoreArtifact,S_NULL,0,0},	// S_DORMANTARTI2_21
+{SPR_ACLO,3,3,NULL,S_DORMANTARTI3_2,0,0},	// S_DORMANTARTI3_1
+{SPR_ACLO,2,3,NULL,S_DORMANTARTI3_3,0,0},	// S_DORMANTARTI3_2
+{SPR_ACLO,3,3,NULL,S_DORMANTARTI3_4,0,0},	// S_DORMANTARTI3_3
+{SPR_ACLO,2,3,NULL,S_DORMANTARTI3_5,0,0},	// S_DORMANTARTI3_4
+{SPR_ACLO,1,3,NULL,S_DORMANTARTI3_6,0,0},	// S_DORMANTARTI3_5
+{SPR_ACLO,2,3,NULL,S_DORMANTARTI3_7,0,0},	// S_DORMANTARTI3_6
+{SPR_ACLO,1,3,NULL,S_DORMANTARTI3_8,0,0},	// S_DORMANTARTI3_7
+{SPR_ACLO,0,3,NULL,S_DORMANTARTI3_9,0,0},	// S_DORMANTARTI3_8
+{SPR_ACLO,1,3,NULL,S_DORMANTARTI3_10,0,0},	// S_DORMANTARTI3_9
+{SPR_ACLO,0,3,NULL,S_DORMANTARTI3_11,0,0},	// S_DORMANTARTI3_10
+{SPR_ACLO,0,21000,A_HideThing,S_DORMANTARTI3_12,0,0},	// S_DORMANTARTI3_11
+{SPR_ACLO,0,3,A_UnHideThing,S_DORMANTARTI3_13,0,0},	// S_DORMANTARTI3_12
+{SPR_ACLO,1,3,NULL,S_DORMANTARTI3_14,0,0},	// S_DORMANTARTI3_13
+{SPR_ACLO,0,3,NULL,S_DORMANTARTI3_15,0,0},	// S_DORMANTARTI3_14
+{SPR_ACLO,1,3,NULL,S_DORMANTARTI3_16,0,0},	// S_DORMANTARTI3_15
+{SPR_ACLO,2,3,NULL,S_DORMANTARTI3_17,0,0},	// S_DORMANTARTI3_16
+{SPR_ACLO,1,3,NULL,S_DORMANTARTI3_18,0,0},	// S_DORMANTARTI3_17
+{SPR_ACLO,2,3,NULL,S_DORMANTARTI3_19,0,0},	// S_DORMANTARTI3_18
+{SPR_ACLO,3,3,NULL,S_DORMANTARTI3_20,0,0},	// S_DORMANTARTI3_19
+{SPR_ACLO,2,3,NULL,S_DORMANTARTI3_21,0,0},	// S_DORMANTARTI3_20
+{SPR_ACLO,3,3,A_RestoreArtifact,S_NULL,0,0},	// S_DORMANTARTI3_21
+{SPR_ACLO,3,3,NULL,S_DEADARTI2,0,0},	// S_DEADARTI1
+{SPR_ACLO,2,3,NULL,S_DEADARTI3,0,0},	// S_DEADARTI2
+{SPR_ACLO,3,3,NULL,S_DEADARTI4,0,0},	// S_DEADARTI3
+{SPR_ACLO,2,3,NULL,S_DEADARTI5,0,0},	// S_DEADARTI4
+{SPR_ACLO,1,3,NULL,S_DEADARTI6,0,0},	// S_DEADARTI5
+{SPR_ACLO,2,3,NULL,S_DEADARTI7,0,0},	// S_DEADARTI6
+{SPR_ACLO,1,3,NULL,S_DEADARTI8,0,0},	// S_DEADARTI7
+{SPR_ACLO,0,3,NULL,S_DEADARTI9,0,0},	// S_DEADARTI8
+{SPR_ACLO,1,3,NULL,S_DEADARTI10,0,0},	// S_DEADARTI9
+{SPR_ACLO,0,3,NULL,S_NULL,0,0},	// S_DEADARTI10
+{SPR_PTN2,0,4,NULL,S_ARTI_PTN2_2,0,0},	// S_ARTI_PTN2_1
+{SPR_PTN2,1,4,NULL,S_ARTI_PTN2_3,0,0},	// S_ARTI_PTN2_2
+{SPR_PTN2,2,4,NULL,S_ARTI_PTN2_1,0,0},	// S_ARTI_PTN2_3
+{SPR_SOAR,0,5,NULL,S_ARTI_SOAR2,0,0},	// S_ARTI_SOAR1
+{SPR_SOAR,1,5,NULL,S_ARTI_SOAR3,0,0},	// S_ARTI_SOAR2
+{SPR_SOAR,2,5,NULL,S_ARTI_SOAR4,0,0},	// S_ARTI_SOAR3
+{SPR_SOAR,1,5,NULL,S_ARTI_SOAR1,0,0},	// S_ARTI_SOAR4
+{SPR_INVU,0,3,NULL,S_ARTI_INVU2,0,0},	// S_ARTI_INVU1
+{SPR_INVU,1,3,NULL,S_ARTI_INVU3,0,0},	// S_ARTI_INVU2
+{SPR_INVU,2,3,NULL,S_ARTI_INVU4,0,0},	// S_ARTI_INVU3
+{SPR_INVU,3,3,NULL,S_ARTI_INVU1,0,0},	// S_ARTI_INVU4
+{SPR_SUMN,0,350,NULL,S_ARTI_SUMMON,0,0},	// S_ARTI_SUMMON
+{SPR_SUMN,0,4,NULL,S_SUMMON_FX1_1,0,0},	// S_SUMMON_FX1_1
+{SPR_SUMN,0,4,NULL,S_SUMMON_FX2_2,0,0},	// S_SUMMON_FX2_1
+{SPR_SUMN,0,4,NULL,S_SUMMON_FX2_3,0,0},	// S_SUMMON_FX2_2
+{SPR_SUMN,0,4,A_Summon,S_NULL,0,0},	// S_SUMMON_FX2_3
+{SPR_TSPK,0,3,NULL,S_THRUSTINIT2_2,0,0},	// S_THRUSTINIT2_1
+{SPR_TSPK,0,4,A_ThrustInitUp,S_THRUSTBLOCK,0,0},	// S_THRUSTINIT2_2
+{SPR_TSPK,1,3,NULL,S_BTHRUSTINIT2_2,0,0},	// S_BTHRUSTINIT2_1
+{SPR_TSPK,1,4,A_ThrustInitUp,S_BTHRUSTBLOCK,0,0},	// S_BTHRUSTINIT2_2
+{SPR_TSPK,0,3,NULL,S_THRUSTINIT1_2,0,0},	// S_THRUSTINIT1_1
+{SPR_TSPK,0,4,A_ThrustInitDn,S_THRUSTSTAY,0,0},	// S_THRUSTINIT1_2
+{SPR_TSPK,1,3,NULL,S_BTHRUSTINIT1_2,0,0},	// S_BTHRUSTINIT1_1
+{SPR_TSPK,1,4,A_ThrustInitDn,S_BTHRUSTSTAY,0,0},	// S_BTHRUSTINIT1_2
+{SPR_TSPK,0,8,A_ThrustRaise,S_THRUSTRAISE2,0,0},	// S_THRUSTRAISE1
+{SPR_TSPK,0,6,A_ThrustRaise,S_THRUSTRAISE3,0,0},	// S_THRUSTRAISE2
+{SPR_TSPK,0,4,A_ThrustRaise,S_THRUSTRAISE4,0,0},	// S_THRUSTRAISE3
+{SPR_TSPK,0,3,A_ThrustBlock,S_THRUSTIMPALE,0,0},	// S_THRUSTRAISE4
+{SPR_TSPK,1,8,A_ThrustRaise,S_BTHRUSTRAISE2,0,0},	// S_BTHRUSTRAISE1
+{SPR_TSPK,1,6,A_ThrustRaise,S_BTHRUSTRAISE3,0,0},	// S_BTHRUSTRAISE2
+{SPR_TSPK,1,4,A_ThrustRaise,S_BTHRUSTRAISE4,0,0},	// S_BTHRUSTRAISE3
+{SPR_TSPK,1,3,A_ThrustBlock,S_BTHRUSTIMPALE,0,0},	// S_BTHRUSTRAISE4
+{SPR_TSPK,0,2,A_ThrustImpale,S_THRUSTRAISE,0,0},	// S_THRUSTIMPALE
+{SPR_TSPK,1,2,A_ThrustImpale,S_BTHRUSTRAISE,0,0},	// S_BTHRUSTIMPALE
+{SPR_TSPK,0,2,A_ThrustRaise,S_THRUSTRAISE,0,0},	// S_THRUSTRAISE
+{SPR_TSPK,1,2,A_ThrustRaise,S_BTHRUSTRAISE,0,0},	// S_BTHRUSTRAISE
+{SPR_TSPK,0,10,NULL,S_THRUSTBLOCK,0,0},	// S_THRUSTBLOCK
+{SPR_TSPK,1,10,NULL,S_BTHRUSTBLOCK,0,0},	// S_BTHRUSTBLOCK
+{SPR_TSPK,0,2,A_ThrustLower,S_THRUSTLOWER,0,0},	// S_THRUSTLOWER
+{SPR_TSPK,1,2,A_ThrustLower,S_BTHRUSTLOWER,0,0},	// S_BTHRUSTLOWER
+{SPR_TSPK,0,-1,NULL,S_THRUSTSTAY,0,0},	// S_THRUSTSTAY
+{SPR_TSPK,1,-1,NULL,S_BTHRUSTSTAY,0,0},	// S_BTHRUSTSTAY
+{SPR_TELO,0,5,NULL,S_ARTI_TELOTHER2,0,0},	// S_ARTI_TELOTHER1
+{SPR_TELO,1,5,NULL,S_ARTI_TELOTHER3,0,0},	// S_ARTI_TELOTHER2
+{SPR_TELO,2,5,NULL,S_ARTI_TELOTHER4,0,0},	// S_ARTI_TELOTHER3
+{SPR_TELO,3,5,NULL,S_ARTI_TELOTHER1,0,0},	// S_ARTI_TELOTHER4
+{SPR_TRNG,32772,5,NULL,S_TELO_FX2,0,0},	// S_TELO_FX1
+{SPR_TRNG,32771,4,NULL,S_TELO_FX3,0,0},	// S_TELO_FX2
+{SPR_TRNG,32770,3,A_TeloSpawnC,S_TELO_FX4,0,0},	// S_TELO_FX3
+{SPR_TRNG,32769,3,A_TeloSpawnB,S_TELO_FX5,0,0},	// S_TELO_FX4
+{SPR_TRNG,32768,3,A_TeloSpawnA,S_TELO_FX6,0,0},	// S_TELO_FX5
+{SPR_TRNG,32769,3,A_TeloSpawnB,S_TELO_FX7,0,0},	// S_TELO_FX6
+{SPR_TRNG,32770,3,A_TeloSpawnC,S_TELO_FX8,0,0},	// S_TELO_FX7
+{SPR_TRNG,32771,3,A_TeloSpawnD,S_TELO_FX3,0,0},	// S_TELO_FX8
+{SPR_TRNG,32772,3,NULL,S_NULL,0,0},	// S_TELO_FX9
+{SPR_TRNG,32769,4,NULL,S_TELO_FX2_2,0,0},	// S_TELO_FX2_1
+{SPR_TRNG,32770,4,NULL,S_TELO_FX2_3,0,0},	// S_TELO_FX2_2
+{SPR_TRNG,32771,4,NULL,S_TELO_FX2_4,0,0},	// S_TELO_FX2_3
+{SPR_TRNG,32770,4,NULL,S_TELO_FX2_5,0,0},	// S_TELO_FX2_4
+{SPR_TRNG,32769,4,NULL,S_TELO_FX2_6,0,0},	// S_TELO_FX2_5
+{SPR_TRNG,32768,4,A_CheckTeleRing,S_TELO_FX2_1,0,0},	// S_TELO_FX2_6
+{SPR_TRNG,32770,4,NULL,S_TELO_FX3_2,0,0},	// S_TELO_FX3_1
+{SPR_TRNG,32771,4,NULL,S_TELO_FX3_3,0,0},	// S_TELO_FX3_2
+{SPR_TRNG,32770,4,NULL,S_TELO_FX3_4,0,0},	// S_TELO_FX3_3
+{SPR_TRNG,32769,4,NULL,S_TELO_FX3_5,0,0},	// S_TELO_FX3_4
+{SPR_TRNG,32768,4,NULL,S_TELO_FX3_6,0,0},	// S_TELO_FX3_5
+{SPR_TRNG,32769,4,A_CheckTeleRing,S_TELO_FX3_1,0,0},	// S_TELO_FX3_6
+{SPR_TRNG,32771,4,NULL,S_TELO_FX4_2,0,0},	// S_TELO_FX4_1
+{SPR_TRNG,32770,4,NULL,S_TELO_FX4_3,0,0},	// S_TELO_FX4_2
+{SPR_TRNG,32769,4,NULL,S_TELO_FX4_4,0,0},	// S_TELO_FX4_3
+{SPR_TRNG,32768,4,NULL,S_TELO_FX4_5,0,0},	// S_TELO_FX4_4
+{SPR_TRNG,32769,4,NULL,S_TELO_FX4_6,0,0},	// S_TELO_FX4_5
+{SPR_TRNG,32770,4,A_CheckTeleRing,S_TELO_FX4_1,0,0},	// S_TELO_FX4_6
+{SPR_TRNG,32770,4,NULL,S_TELO_FX5_2,0,0},	// S_TELO_FX5_1
+{SPR_TRNG,32769,4,NULL,S_TELO_FX5_3,0,0},	// S_TELO_FX5_2
+{SPR_TRNG,32768,4,NULL,S_TELO_FX5_4,0,0},	// S_TELO_FX5_3
+{SPR_TRNG,32769,4,NULL,S_TELO_FX5_5,0,0},	// S_TELO_FX5_4
+{SPR_TRNG,32770,4,NULL,S_TELO_FX5_6,0,0},	// S_TELO_FX5_5
+{SPR_TRNG,32771,4,A_CheckTeleRing,S_TELO_FX5_1,0,0},	// S_TELO_FX5_6
+{SPR_ROCK,3,20,NULL,S_DIRT1_1,0,0},	// S_DIRT1_1
+{SPR_ROCK,3,10,NULL,S_NULL,0,0},	// S_DIRT1_D
+{SPR_ROCK,4,20,NULL,S_DIRT2_1,0,0},	// S_DIRT2_1
+{SPR_ROCK,4,10,NULL,S_NULL,0,0},	// S_DIRT2_D
+{SPR_ROCK,5,20,NULL,S_DIRT3_1,0,0},	// S_DIRT3_1
+{SPR_ROCK,5,10,NULL,S_NULL,0,0},	// S_DIRT3_D
+{SPR_ROCK,6,20,NULL,S_DIRT4_1,0,0},	// S_DIRT4_1
+{SPR_ROCK,6,10,NULL,S_NULL,0,0},	// S_DIRT4_D
+{SPR_ROCK,7,20,NULL,S_DIRT5_1,0,0},	// S_DIRT5_1
+{SPR_ROCK,7,10,NULL,S_NULL,0,0},	// S_DIRT5_D
+{SPR_ROCK,8,20,NULL,S_DIRT6_1,0,0},	// S_DIRT6_1
+{SPR_ROCK,8,10,NULL,S_NULL,0,0},	// S_DIRT6_D
+{SPR_TSPK,2,20,NULL,S_DIRTCLUMP1,0,0},	// S_DIRTCLUMP1
+{SPR_ROCK,0,20,NULL,S_ROCK1_1,0,0},	// S_ROCK1_1
+{SPR_ROCK,0,10,NULL,S_NULL,0,0},	// S_ROCK1_D
+{SPR_ROCK,1,20,NULL,S_ROCK2_1,0,0},	// S_ROCK2_1
+{SPR_ROCK,1,10,NULL,S_NULL,0,0},	// S_ROCK2_D
+{SPR_ROCK,2,20,NULL,S_ROCK3_1,0,0},	// S_ROCK3_1
+{SPR_ROCK,2,10,NULL,S_NULL,0,0},	// S_ROCK3_D
+{SPR_MAN1,0,20,A_FogSpawn,S_SPAWNFOG1,0,0},	// S_SPAWNFOG1
+{SPR_FOGS,0,7,A_FogMove,S_FOGPATCHS2,0,0},	// S_FOGPATCHS1
+{SPR_FOGS,1,7,A_FogMove,S_FOGPATCHS3,0,0},	// S_FOGPATCHS2
+{SPR_FOGS,2,7,A_FogMove,S_FOGPATCHS4,0,0},	// S_FOGPATCHS3
+{SPR_FOGS,3,7,A_FogMove,S_FOGPATCHS5,0,0},	// S_FOGPATCHS4
+{SPR_FOGS,4,7,A_FogMove,S_FOGPATCHS1,0,0},	// S_FOGPATCHS5
+{SPR_FOGS,4,5,NULL,S_NULL,0,0},	// S_FOGPATCHS0
+{SPR_FOGM,0,7,A_FogMove,S_FOGPATCHM2,0,0},	// S_FOGPATCHM1
+{SPR_FOGM,1,7,A_FogMove,S_FOGPATCHM3,0,0},	// S_FOGPATCHM2
+{SPR_FOGM,2,7,A_FogMove,S_FOGPATCHM4,0,0},	// S_FOGPATCHM3
+{SPR_FOGM,3,7,A_FogMove,S_FOGPATCHM5,0,0},	// S_FOGPATCHM4
+{SPR_FOGM,4,7,A_FogMove,S_FOGPATCHM1,0,0},	// S_FOGPATCHM5
+{SPR_FOGS,0,5,NULL,S_FOGPATCHMA,0,0},	// S_FOGPATCHM0
+{SPR_FOGS,1,5,NULL,S_FOGPATCHMB,0,0},	// S_FOGPATCHMA
+{SPR_FOGS,2,5,NULL,S_FOGPATCHMC,0,0},	// S_FOGPATCHMB
+{SPR_FOGS,3,5,NULL,S_FOGPATCHMD,0,0},	// S_FOGPATCHMC
+{SPR_FOGS,4,5,NULL,S_FOGPATCHS0,0,0},	// S_FOGPATCHMD
+{SPR_FOGL,0,7,A_FogMove,S_FOGPATCHL2,0,0},	// S_FOGPATCHL1
+{SPR_FOGL,1,7,A_FogMove,S_FOGPATCHL3,0,0},	// S_FOGPATCHL2
+{SPR_FOGL,2,7,A_FogMove,S_FOGPATCHL4,0,0},	// S_FOGPATCHL3
+{SPR_FOGL,3,7,A_FogMove,S_FOGPATCHL5,0,0},	// S_FOGPATCHL4
+{SPR_FOGL,4,7,A_FogMove,S_FOGPATCHL1,0,0},	// S_FOGPATCHL5
+{SPR_FOGM,0,4,NULL,S_FOGPATCHLA,0,0},	// S_FOGPATCHL0
+{SPR_FOGM,1,4,NULL,S_FOGPATCHLB,0,0},	// S_FOGPATCHLA
+{SPR_FOGM,2,4,NULL,S_FOGPATCHLC,0,0},	// S_FOGPATCHLB
+{SPR_FOGM,3,4,NULL,S_FOGPATCHLD,0,0},	// S_FOGPATCHLC
+{SPR_FOGM,4,4,NULL,S_FOGPATCHM0,0,0},	// S_FOGPATCHLD
+{SPR_MAN1,0,2,A_Quake,S_QUAKE_ACTIVE2,0,0},	// S_QUAKE_ACTIVE1
+{SPR_MAN1,0,1,A_ContMobjSound,S_QUAKE_ACTIVE3,0,0},	// S_QUAKE_ACTIVE2
+{SPR_MAN1,0,2,A_Quake,S_QUAKE_ACTIVE4,0,0},	// S_QUAKE_ACTIVE3
+{SPR_MAN1,0,2,A_Quake,S_QUAKE_ACTIVE5,0,0},	// S_QUAKE_ACTIVE4
+{SPR_MAN1,0,2,A_Quake,S_QUAKE_ACTIVE6,0,0},	// S_QUAKE_ACTIVE5
+{SPR_MAN1,0,2,A_Quake,S_QUAKE_ACTIVE7,0,0},	// S_QUAKE_ACTIVE6
+{SPR_MAN1,0,2,A_Quake,S_QUAKE_ACTIVE8,0,0},	// S_QUAKE_ACTIVE7
+{SPR_MAN1,0,2,A_Quake,S_QUAKE_ACTIVE9,0,0},	// S_QUAKE_ACTIVE8
+{SPR_MAN1,0,2,A_Quake,S_QUAKE_ACTIVE0,0,0},	// S_QUAKE_ACTIVE9
+{SPR_MAN1,0,2,A_Quake,S_QUAKE_ACTIVEA,0,0},	// S_QUAKE_ACTIVE0
+{SPR_MAN1,0,2,A_Quake,S_QUAKE_ACTIVEB,0,0},	// S_QUAKE_ACTIVEA
+{SPR_MAN1,0,2,A_Quake,S_QUAKE_ACTIVEC,0,0},	// S_QUAKE_ACTIVEB
+{SPR_MAN1,0,2,A_Quake,S_QUAKE_ACTIVED,0,0},	// S_QUAKE_ACTIVEC
+{SPR_MAN1,0,2,A_Quake,S_QUAKE_ACTIVEE,0,0},	// S_QUAKE_ACTIVED
+{SPR_MAN1,0,2,A_Quake,S_QUAKE_ACTIVEF,0,0},	// S_QUAKE_ACTIVEE
+{SPR_MAN1,0,2,A_Quake,S_QUAKE_ACTIVEG,0,0},	// S_QUAKE_ACTIVEF
+{SPR_MAN1,0,2,A_Quake,S_QUAKE_ACTIVEH,0,0},	// S_QUAKE_ACTIVEG
+{SPR_MAN1,0,2,A_Quake,S_QUAKE_ACTIVEI,0,0},	// S_QUAKE_ACTIVEH
+{SPR_MAN1,0,2,A_Quake,S_QUAKE_ACTIVEJ,0,0},	// S_QUAKE_ACTIVEI
+{SPR_MAN1,0,2,A_Quake,S_QUAKE_ACTIVEK,0,0},	// S_QUAKE_ACTIVEJ
+{SPR_MAN1,0,2,A_Quake,S_QUAKE_ACTIVEL,0,0},	// S_QUAKE_ACTIVEK
+{SPR_MAN1,0,2,A_Quake,S_QUAKE_ACTIVEM,0,0},	// S_QUAKE_ACTIVEL
+{SPR_MAN1,0,2,A_Quake,S_QUAKE_ACTIVEN,0,0},	// S_QUAKE_ACTIVEM
+{SPR_MAN1,0,2,A_Quake,S_QUAKE_ACTIVEO,0,0},	// S_QUAKE_ACTIVEN
+{SPR_MAN1,0,2,A_Quake,S_QUAKE_ACTIVEP,0,0},	// S_QUAKE_ACTIVEO
+{SPR_MAN1,0,2,A_Quake,S_QUAKE_ACTIVEQ,0,0},	// S_QUAKE_ACTIVEP
+{SPR_MAN1,0,2,A_Quake,S_QUAKE_ACTIVER,0,0},	// S_QUAKE_ACTIVEQ
+{SPR_MAN1,0,2,A_Quake,S_QUAKE_ACTIVES,0,0},	// S_QUAKE_ACTIVER
+{SPR_MAN1,0,2,A_Quake,S_QUAKE_ACTIVET,0,0},	// S_QUAKE_ACTIVES
+{SPR_MAN1,0,2,A_Quake,S_QUAKE_ACTIVEU,0,0},	// S_QUAKE_ACTIVET
+{SPR_MAN1,0,2,A_Quake,S_QUAKE_ACTIVEV,0,0},	// S_QUAKE_ACTIVEU
+{SPR_MAN1,0,2,A_Quake,S_QUAKE_ACTIVEW,0,0},	// S_QUAKE_ACTIVEV
+{SPR_MAN1,0,2,A_Quake,S_QUAKE_ACTIVEX,0,0},	// S_QUAKE_ACTIVEW
+{SPR_MAN1,0,2,A_Quake,S_QUAKE_ACTIVEY,0,0},	// S_QUAKE_ACTIVEX
+{SPR_MAN1,0,2,A_Quake,S_QUAKE_ACTIVEZ,0,0},	// S_QUAKE_ACTIVEY
+{SPR_MAN1,0,2,A_Quake,S_QUAKE_ACT1,0,0},	// S_QUAKE_ACTIVEZ
+{SPR_MAN1,0,2,A_Quake,S_QUAKE_ACT2,0,0},	// S_QUAKE_ACT1
+{SPR_MAN1,0,2,A_Quake,S_QUAKE_ACT3,0,0},	// S_QUAKE_ACT2
+{SPR_MAN1,0,2,A_Quake,S_QUAKE_ACT4,0,0},	// S_QUAKE_ACT3
+{SPR_MAN1,0,2,A_Quake,S_QUAKE_ACT5,0,0},	// S_QUAKE_ACT4
+{SPR_MAN1,0,2,A_Quake,S_QUAKE_ACT6,0,0},	// S_QUAKE_ACT5
+{SPR_MAN1,0,2,A_Quake,S_QUAKE_ACT7,0,0},	// S_QUAKE_ACT6
+{SPR_MAN1,0,2,A_Quake,S_QUAKE_ACT8,0,0},	// S_QUAKE_ACT7
+{SPR_MAN1,0,2,A_Quake,S_QUAKE_ACT9,0,0},	// S_QUAKE_ACT8
+{SPR_MAN1,0,2,A_Quake,S_QUAKE_ACT0,0,0},	// S_QUAKE_ACT9
+{SPR_MAN1,0,2,A_Quake,S_QUAKE_ACTIVE1,0,0},	// S_QUAKE_ACT0
+{SPR_SGSA,0,4,NULL,S_SGSHARD1_2,0,0},	// S_SGSHARD1_1
+{SPR_SGSA,1,4,NULL,S_SGSHARD1_3,0,0},	// S_SGSHARD1_2
+{SPR_SGSA,2,4,NULL,S_SGSHARD1_4,0,0},	// S_SGSHARD1_3
+{SPR_SGSA,3,4,NULL,S_SGSHARD1_5,0,0},	// S_SGSHARD1_4
+{SPR_SGSA,4,4,NULL,S_SGSHARD1_1,0,0},	// S_SGSHARD1_5
+{SPR_SGSA,4,30,NULL,S_NULL,0,0},	// S_SGSHARD1_D
+{SPR_SGSA,5,4,NULL,S_SGSHARD2_2,0,0},	// S_SGSHARD2_1
+{SPR_SGSA,6,4,NULL,S_SGSHARD2_3,0,0},	// S_SGSHARD2_2
+{SPR_SGSA,7,4,NULL,S_SGSHARD2_4,0,0},	// S_SGSHARD2_3
+{SPR_SGSA,8,4,NULL,S_SGSHARD2_5,0,0},	// S_SGSHARD2_4
+{SPR_SGSA,9,4,NULL,S_SGSHARD2_1,0,0},	// S_SGSHARD2_5
+{SPR_SGSA,9,30,NULL,S_NULL,0,0},	// S_SGSHARD2_D
+{SPR_SGSA,10,4,NULL,S_SGSHARD3_2,0,0},	// S_SGSHARD3_1
+{SPR_SGSA,11,4,NULL,S_SGSHARD3_3,0,0},	// S_SGSHARD3_2
+{SPR_SGSA,12,4,NULL,S_SGSHARD3_4,0,0},	// S_SGSHARD3_3
+{SPR_SGSA,13,4,NULL,S_SGSHARD3_5,0,0},	// S_SGSHARD3_4
+{SPR_SGSA,14,4,NULL,S_SGSHARD3_1,0,0},	// S_SGSHARD3_5
+{SPR_SGSA,14,30,NULL,S_NULL,0,0},	// S_SGSHARD3_D
+{SPR_SGSA,15,4,NULL,S_SGSHARD4_2,0,0},	// S_SGSHARD4_1
+{SPR_SGSA,16,4,NULL,S_SGSHARD4_3,0,0},	// S_SGSHARD4_2
+{SPR_SGSA,17,4,NULL,S_SGSHARD4_4,0,0},	// S_SGSHARD4_3
+{SPR_SGSA,18,4,NULL,S_SGSHARD4_5,0,0},	// S_SGSHARD4_4
+{SPR_SGSA,19,4,NULL,S_SGSHARD4_1,0,0},	// S_SGSHARD4_5
+{SPR_SGSA,19,30,NULL,S_NULL,0,0},	// S_SGSHARD4_D
+{SPR_SGSA,20,4,NULL,S_SGSHARD5_2,0,0},	// S_SGSHARD5_1
+{SPR_SGSA,21,4,NULL,S_SGSHARD5_3,0,0},	// S_SGSHARD5_2
+{SPR_SGSA,22,4,NULL,S_SGSHARD5_4,0,0},	// S_SGSHARD5_3
+{SPR_SGSA,23,4,NULL,S_SGSHARD5_5,0,0},	// S_SGSHARD5_4
+{SPR_SGSA,24,4,NULL,S_SGSHARD5_1,0,0},	// S_SGSHARD5_5
+{SPR_SGSA,24,30,NULL,S_NULL,0,0},	// S_SGSHARD5_D
+{SPR_SGSB,0,4,NULL,S_SGSHARD6_1,0,0},	// S_SGSHARD6_1
+{SPR_SGSB,0,30,NULL,S_NULL,0,0},	// S_SGSHARD6_D
+{SPR_SGSB,1,4,NULL,S_SGSHARD7_1,0,0},	// S_SGSHARD7_1
+{SPR_SGSB,1,30,NULL,S_NULL,0,0},	// S_SGSHARD7_D
+{SPR_SGSB,2,4,NULL,S_SGSHARD8_1,0,0},	// S_SGSHARD8_1
+{SPR_SGSB,2,30,NULL,S_NULL,0,0},	// S_SGSHARD8_D
+{SPR_SGSB,3,4,NULL,S_SGSHARD9_1,0,0},	// S_SGSHARD9_1
+{SPR_SGSB,3,30,NULL,S_NULL,0,0},	// S_SGSHARD9_D
+{SPR_SGSB,4,4,NULL,S_SGSHARD0_1,0,0},	// S_SGSHARD0_1
+{SPR_SGSB,4,30,NULL,S_NULL,0,0},	// S_SGSHARD0_D
+{SPR_PORK,0,5,NULL,S_ARTI_EGGC2,0,0},	// S_ARTI_EGGC1
+{SPR_PORK,1,5,NULL,S_ARTI_EGGC3,0,0},	// S_ARTI_EGGC2
+{SPR_PORK,2,5,NULL,S_ARTI_EGGC4,0,0},	// S_ARTI_EGGC3
+{SPR_PORK,3,5,NULL,S_ARTI_EGGC5,0,0},	// S_ARTI_EGGC4
+{SPR_PORK,4,5,NULL,S_ARTI_EGGC6,0,0},	// S_ARTI_EGGC5
+{SPR_PORK,5,5,NULL,S_ARTI_EGGC7,0,0},	// S_ARTI_EGGC6
+{SPR_PORK,6,5,NULL,S_ARTI_EGGC8,0,0},	// S_ARTI_EGGC7
+{SPR_PORK,7,5,NULL,S_ARTI_EGGC1,0,0},	// S_ARTI_EGGC8
+{SPR_EGGM,0,4,NULL,S_EGGFX2,0,0},	// S_EGGFX1
+{SPR_EGGM,1,4,NULL,S_EGGFX3,0,0},	// S_EGGFX2
+{SPR_EGGM,2,4,NULL,S_EGGFX4,0,0},	// S_EGGFX3
+{SPR_EGGM,3,4,NULL,S_EGGFX5,0,0},	// S_EGGFX4
+{SPR_EGGM,4,4,NULL,S_EGGFX1,0,0},	// S_EGGFX5
+{SPR_FHFX,32776,3,NULL,S_EGGFXI1_2,0,0},	// S_EGGFXI1_1
+{SPR_FHFX,32777,3,NULL,S_EGGFXI1_3,0,0},	// S_EGGFXI1_2
+{SPR_FHFX,32778,3,NULL,S_EGGFXI1_4,0,0},	// S_EGGFXI1_3
+{SPR_FHFX,32779,3,NULL,S_NULL,0,0},	// S_EGGFXI1_4
+{SPR_SPHL,0,350,NULL,S_ARTI_SPHL1,0,0},	// S_ARTI_SPHL1
+{SPR_STWN,0,-1,NULL,S_NULL,0,0},	// S_ZWINGEDSTATUENOSKULL
+{SPR_STWN,1,-1,NULL,S_NULL,0,0},	// S_ZWINGEDSTATUENOSKULL2
+{SPR_GMPD,0,-1,NULL,S_NULL,0,0},	// S_ZGEMPEDESTAL1
+{SPR_GMPD,1,-1,NULL,S_NULL,0,0},	// S_ZGEMPEDESTAL2
+{SPR_ASKU,0,-1,NULL,S_NULL,0,0},	// S_ARTIPUZZSKULL
+{SPR_ABGM,0,-1,NULL,S_NULL,0,0},	// S_ARTIPUZZGEMBIG
+{SPR_AGMR,0,-1,NULL,S_NULL,0,0},	// S_ARTIPUZZGEMRED
+{SPR_AGMG,0,-1,NULL,S_NULL,0,0},	// S_ARTIPUZZGEMGREEN1
+{SPR_AGG2,0,-1,NULL,S_NULL,0,0},	// S_ARTIPUZZGEMGREEN2
+{SPR_AGMB,0,-1,NULL,S_NULL,0,0},	// S_ARTIPUZZGEMBLUE1
+{SPR_AGB2,0,-1,NULL,S_NULL,0,0},	// S_ARTIPUZZGEMBLUE2
+{SPR_ABK1,0,-1,NULL,S_NULL,0,0},	// S_ARTIPUZZBOOK1
+{SPR_ABK2,0,-1,NULL,S_NULL,0,0},	// S_ARTIPUZZBOOK2
+{SPR_ASK2,0,-1,NULL,S_NULL,0,0},	// S_ARTIPUZZSKULL2
+{SPR_AFWP,0,-1,NULL,S_NULL,0,0},	// S_ARTIPUZZFWEAPON
+{SPR_ACWP,0,-1,NULL,S_NULL,0,0},	// S_ARTIPUZZCWEAPON
+{SPR_AMWP,0,-1,NULL,S_NULL,0,0},	// S_ARTIPUZZMWEAPON
+{SPR_AGER,32768,4,NULL,S_ARTIPUZZGEAR_2,0,0},	// S_ARTIPUZZGEAR_1
+{SPR_AGER,32769,4,NULL,S_ARTIPUZZGEAR_3,0,0},	// S_ARTIPUZZGEAR_2
+{SPR_AGER,32770,4,NULL,S_ARTIPUZZGEAR_4,0,0},	// S_ARTIPUZZGEAR_3
+{SPR_AGER,32771,4,NULL,S_ARTIPUZZGEAR_5,0,0},	// S_ARTIPUZZGEAR_4
+{SPR_AGER,32772,4,NULL,S_ARTIPUZZGEAR_6,0,0},	// S_ARTIPUZZGEAR_5
+{SPR_AGER,32773,4,NULL,S_ARTIPUZZGEAR_7,0,0},	// S_ARTIPUZZGEAR_6
+{SPR_AGER,32774,4,NULL,S_ARTIPUZZGEAR_8,0,0},	// S_ARTIPUZZGEAR_7
+{SPR_AGER,32775,4,NULL,S_ARTIPUZZGEAR_1,0,0},	// S_ARTIPUZZGEAR_8
+{SPR_AGR2,32768,4,NULL,S_ARTIPUZZGEAR2_2,0,0},	// S_ARTIPUZZGEAR2_1
+{SPR_AGR2,32769,4,NULL,S_ARTIPUZZGEAR2_3,0,0},	// S_ARTIPUZZGEAR2_2
+{SPR_AGR2,32770,4,NULL,S_ARTIPUZZGEAR2_4,0,0},	// S_ARTIPUZZGEAR2_3
+{SPR_AGR2,32771,4,NULL,S_ARTIPUZZGEAR2_5,0,0},	// S_ARTIPUZZGEAR2_4
+{SPR_AGR2,32772,4,NULL,S_ARTIPUZZGEAR2_6,0,0},	// S_ARTIPUZZGEAR2_5
+{SPR_AGR2,32773,4,NULL,S_ARTIPUZZGEAR2_7,0,0},	// S_ARTIPUZZGEAR2_6
+{SPR_AGR2,32774,4,NULL,S_ARTIPUZZGEAR2_8,0,0},	// S_ARTIPUZZGEAR2_7
+{SPR_AGR2,32775,4,NULL,S_ARTIPUZZGEAR2_1,0,0},	// S_ARTIPUZZGEAR2_8
+{SPR_AGR3,32768,4,NULL,S_ARTIPUZZGEAR3_2,0,0},	// S_ARTIPUZZGEAR3_1
+{SPR_AGR3,32769,4,NULL,S_ARTIPUZZGEAR3_3,0,0},	// S_ARTIPUZZGEAR3_2
+{SPR_AGR3,32770,4,NULL,S_ARTIPUZZGEAR3_4,0,0},	// S_ARTIPUZZGEAR3_3
+{SPR_AGR3,32771,4,NULL,S_ARTIPUZZGEAR3_5,0,0},	// S_ARTIPUZZGEAR3_4
+{SPR_AGR3,32772,4,NULL,S_ARTIPUZZGEAR3_6,0,0},	// S_ARTIPUZZGEAR3_5
+{SPR_AGR3,32773,4,NULL,S_ARTIPUZZGEAR3_7,0,0},	// S_ARTIPUZZGEAR3_6
+{SPR_AGR3,32774,4,NULL,S_ARTIPUZZGEAR3_8,0,0},	// S_ARTIPUZZGEAR3_7
+{SPR_AGR3,32775,4,NULL,S_ARTIPUZZGEAR3_1,0,0},	// S_ARTIPUZZGEAR3_8
+{SPR_AGR4,32768,4,NULL,S_ARTIPUZZGEAR4_2,0,0},	// S_ARTIPUZZGEAR4_1
+{SPR_AGR4,32769,4,NULL,S_ARTIPUZZGEAR4_3,0,0},	// S_ARTIPUZZGEAR4_2
+{SPR_AGR4,32770,4,NULL,S_ARTIPUZZGEAR4_4,0,0},	// S_ARTIPUZZGEAR4_3
+{SPR_AGR4,32771,4,NULL,S_ARTIPUZZGEAR4_5,0,0},	// S_ARTIPUZZGEAR4_4
+{SPR_AGR4,32772,4,NULL,S_ARTIPUZZGEAR4_6,0,0},	// S_ARTIPUZZGEAR4_5
+{SPR_AGR4,32773,4,NULL,S_ARTIPUZZGEAR4_7,0,0},	// S_ARTIPUZZGEAR4_6
+{SPR_AGR4,32774,4,NULL,S_ARTIPUZZGEAR4_8,0,0},	// S_ARTIPUZZGEAR4_7
+{SPR_AGR4,32775,4,NULL,S_ARTIPUZZGEAR4_1,0,0},	// S_ARTIPUZZGEAR4_8
+{SPR_TRCH,32768,3,NULL,S_ARTI_TRCH2,0,0},	// S_ARTI_TRCH1
+{SPR_TRCH,32769,3,NULL,S_ARTI_TRCH3,0,0},	// S_ARTI_TRCH2
+{SPR_TRCH,32770,3,NULL,S_ARTI_TRCH1,0,0},	// S_ARTI_TRCH3
+{SPR_PSBG,0,20,NULL,S_FIREBOMB2,0,0},	// S_FIREBOMB1
+{SPR_PSBG,0,10,NULL,S_FIREBOMB3,0,0},	// S_FIREBOMB2
+{SPR_PSBG,0,10,NULL,S_FIREBOMB4,0,0},	// S_FIREBOMB3
+{SPR_PSBG,1,4,NULL,S_FIREBOMB5,0,0},	// S_FIREBOMB4
+{SPR_PSBG,2,4,A_Scream,S_FIREBOMB6,0,0},	// S_FIREBOMB5
+{SPR_XPL1,32768,4,A_Explode,S_FIREBOMB7,0,0},	// S_FIREBOMB6
+{SPR_XPL1,32769,4,NULL,S_FIREBOMB8,0,0},	// S_FIREBOMB7
+{SPR_XPL1,32770,4,NULL,S_FIREBOMB9,0,0},	// S_FIREBOMB8
+{SPR_XPL1,32771,4,NULL,S_FIREBOMB10,0,0},	// S_FIREBOMB9
+{SPR_XPL1,32772,4,NULL,S_FIREBOMB11,0,0},	// S_FIREBOMB10
+{SPR_XPL1,32773,4,NULL,S_NULL,0,0},	// S_FIREBOMB11
+{SPR_ATLP,0,4,NULL,S_ARTI_ATLP2,0,0},	// S_ARTI_ATLP1
+{SPR_ATLP,1,4,NULL,S_ARTI_ATLP3,0,0},	// S_ARTI_ATLP2
+{SPR_ATLP,2,4,NULL,S_ARTI_ATLP4,0,0},	// S_ARTI_ATLP3
+{SPR_ATLP,1,4,NULL,S_ARTI_ATLP1,0,0},	// S_ARTI_ATLP4
+{SPR_PSBG,0,-1,NULL,S_NULL,0,0},	// S_ARTI_PSBG1
+{SPR_PSBG,32768,18,NULL,S_POISONBAG2,0,0},	// S_POISONBAG1
+{SPR_PSBG,32769,4,NULL,S_POISONBAG3,0,0},	// S_POISONBAG2
+{SPR_PSBG,2,3,NULL,S_POISONBAG4,0,0},	// S_POISONBAG3
+{SPR_PSBG,2,1,A_PoisonBagInit,S_NULL,0,0},	// S_POISONBAG4
+{SPR_PSBG,3,1,NULL,S_POISONCLOUD2,0,0},	// S_POISONCLOUD1
+{SPR_PSBG,3,1,A_Scream,S_POISONCLOUD3,0,0},	// S_POISONCLOUD2
+{SPR_PSBG,3,2,A_PoisonBagDamage,S_POISONCLOUD4,0,0},	// S_POISONCLOUD3
+{SPR_PSBG,4,2,A_PoisonBagDamage,S_POISONCLOUD5,0,0},	// S_POISONCLOUD4
+{SPR_PSBG,4,2,A_PoisonBagDamage,S_POISONCLOUD6,0,0},	// S_POISONCLOUD5
+{SPR_PSBG,4,2,A_PoisonBagDamage,S_POISONCLOUD7,0,0},	// S_POISONCLOUD6
+{SPR_PSBG,5,2,A_PoisonBagDamage,S_POISONCLOUD8,0,0},	// S_POISONCLOUD7
+{SPR_PSBG,5,2,A_PoisonBagDamage,S_POISONCLOUD9,0,0},	// S_POISONCLOUD8
+{SPR_PSBG,5,2,A_PoisonBagDamage,S_POISONCLOUD10,0,0},	// S_POISONCLOUD9
+{SPR_PSBG,6,2,A_PoisonBagDamage,S_POISONCLOUD11,0,0},	// S_POISONCLOUD10
+{SPR_PSBG,6,2,A_PoisonBagDamage,S_POISONCLOUD12,0,0},	// S_POISONCLOUD11
+{SPR_PSBG,6,2,A_PoisonBagDamage,S_POISONCLOUD13,0,0},	// S_POISONCLOUD12
+{SPR_PSBG,7,2,A_PoisonBagDamage,S_POISONCLOUD14,0,0},	// S_POISONCLOUD13
+{SPR_PSBG,7,2,A_PoisonBagDamage,S_POISONCLOUD15,0,0},	// S_POISONCLOUD14
+{SPR_PSBG,7,2,A_PoisonBagDamage,S_POISONCLOUD16,0,0},	// S_POISONCLOUD15
+{SPR_PSBG,8,2,A_PoisonBagDamage,S_POISONCLOUD17,0,0},	// S_POISONCLOUD16
+{SPR_PSBG,8,1,A_PoisonBagDamage,S_POISONCLOUD18,0,0},	// S_POISONCLOUD17
+{SPR_PSBG,8,1,A_PoisonBagCheck,S_POISONCLOUD4,0,0},	// S_POISONCLOUD18
+{SPR_PSBG,7,7,NULL,S_POISONCLOUD_X2,0,0},	// S_POISONCLOUD_X1
+{SPR_PSBG,6,7,NULL,S_POISONCLOUD_X3,0,0},	// S_POISONCLOUD_X2
+{SPR_PSBG,5,6,NULL,S_POISONCLOUD_X4,0,0},	// S_POISONCLOUD_X3
+{SPR_PSBG,3,6,NULL,S_NULL,0,0},	// S_POISONCLOUD_X4
+{SPR_THRW,0,4,A_CheckThrowBomb,S_THROWINGBOMB2,0,0},	// S_THROWINGBOMB1
+{SPR_THRW,1,3,A_CheckThrowBomb,S_THROWINGBOMB3,0,0},	// S_THROWINGBOMB2
+{SPR_THRW,2,3,A_CheckThrowBomb,S_THROWINGBOMB4,0,0},	// S_THROWINGBOMB3
+{SPR_THRW,3,3,A_CheckThrowBomb,S_THROWINGBOMB5,0,0},	// S_THROWINGBOMB4
+{SPR_THRW,4,3,A_CheckThrowBomb,S_THROWINGBOMB6,0,0},	// S_THROWINGBOMB5
+{SPR_THRW,5,3,A_CheckThrowBomb,S_THROWINGBOMB1,0,0},	// S_THROWINGBOMB6
+{SPR_THRW,6,6,A_CheckThrowBomb,S_THROWINGBOMB8,0,0},	// S_THROWINGBOMB7
+{SPR_THRW,5,4,A_CheckThrowBomb,S_THROWINGBOMB9,0,0},	// S_THROWINGBOMB8
+{SPR_THRW,7,6,A_CheckThrowBomb,S_THROWINGBOMB10,0,0},	// S_THROWINGBOMB9
+{SPR_THRW,5,4,A_CheckThrowBomb,S_THROWINGBOMB11,0,0},	// S_THROWINGBOMB10
+{SPR_THRW,6,6,A_CheckThrowBomb,S_THROWINGBOMB12,0,0},	// S_THROWINGBOMB11
+{SPR_THRW,5,3,A_CheckThrowBomb,S_THROWINGBOMB12,0,0},	// S_THROWINGBOMB12
+{SPR_CFCF,32784,4,A_NoGravity,S_THROWINGBOMB_X2,0,0},	// S_THROWINGBOMB_X1
+{SPR_CFCF,32785,3,A_Scream,S_THROWINGBOMB_X3,0,0},	// S_THROWINGBOMB_X2
+{SPR_CFCF,32786,4,A_Explode,S_THROWINGBOMB_X4,0,0},	// S_THROWINGBOMB_X3
+{SPR_CFCF,32787,3,NULL,S_THROWINGBOMB_X5,0,0},	// S_THROWINGBOMB_X4
+{SPR_CFCF,32788,4,NULL,S_THROWINGBOMB_X6,0,0},	// S_THROWINGBOMB_X5
+{SPR_CFCF,32790,3,NULL,S_THROWINGBOMB_X7,0,0},	// S_THROWINGBOMB_X6
+{SPR_CFCF,32791,4,NULL,S_THROWINGBOMB_X8,0,0},	// S_THROWINGBOMB_X7
+{SPR_CFCF,32793,3,NULL,S_NULL,0,0},	// S_THROWINGBOMB_X8
+{SPR_SPED,32768,3,NULL,S_ARTI_BOOTS2,0,0},	// S_ARTI_BOOTS1
+{SPR_SPED,32769,3,NULL,S_ARTI_BOOTS3,0,0},	// S_ARTI_BOOTS2
+{SPR_SPED,32770,3,NULL,S_ARTI_BOOTS4,0,0},	// S_ARTI_BOOTS3
+{SPR_SPED,32771,3,NULL,S_ARTI_BOOTS5,0,0},	// S_ARTI_BOOTS4
+{SPR_SPED,32772,3,NULL,S_ARTI_BOOTS6,0,0},	// S_ARTI_BOOTS5
+{SPR_SPED,32773,3,NULL,S_ARTI_BOOTS7,0,0},	// S_ARTI_BOOTS6
+{SPR_SPED,32774,3,NULL,S_ARTI_BOOTS8,0,0},	// S_ARTI_BOOTS7
+{SPR_SPED,32775,3,NULL,S_ARTI_BOOTS1,0,0},	// S_ARTI_BOOTS8
+{SPR_BMAN,32768,-1,NULL,S_NULL,0,0},	// S_ARTI_MANA
+{SPR_BRAC,32768,4,NULL,S_ARTI_ARMOR2,0,0},	// S_ARTI_ARMOR1
+{SPR_BRAC,32769,4,NULL,S_ARTI_ARMOR3,0,0},	// S_ARTI_ARMOR2
+{SPR_BRAC,32770,4,NULL,S_ARTI_ARMOR4,0,0},	// S_ARTI_ARMOR3
+{SPR_BRAC,32771,4,NULL,S_ARTI_ARMOR5,0,0},	// S_ARTI_ARMOR4
+{SPR_BRAC,32772,4,NULL,S_ARTI_ARMOR6,0,0},	// S_ARTI_ARMOR5
+{SPR_BRAC,32773,4,NULL,S_ARTI_ARMOR7,0,0},	// S_ARTI_ARMOR6
+{SPR_BRAC,32774,4,NULL,S_ARTI_ARMOR8,0,0},	// S_ARTI_ARMOR7
+{SPR_BRAC,32775,4,NULL,S_ARTI_ARMOR1,0,0},	// S_ARTI_ARMOR8
+{SPR_BLST,32768,4,NULL,S_ARTI_BLAST2,0,0},	// S_ARTI_BLAST1
+{SPR_BLST,32769,4,NULL,S_ARTI_BLAST3,0,0},	// S_ARTI_BLAST2
+{SPR_BLST,32770,4,NULL,S_ARTI_BLAST4,0,0},	// S_ARTI_BLAST3
+{SPR_BLST,32771,4,NULL,S_ARTI_BLAST5,0,0},	// S_ARTI_BLAST4
+{SPR_BLST,32772,4,NULL,S_ARTI_BLAST6,0,0},	// S_ARTI_BLAST5
+{SPR_BLST,32773,4,NULL,S_ARTI_BLAST7,0,0},	// S_ARTI_BLAST6
+{SPR_BLST,32774,4,NULL,S_ARTI_BLAST8,0,0},	// S_ARTI_BLAST7
+{SPR_BLST,32775,4,NULL,S_ARTI_BLAST1,0,0},	// S_ARTI_BLAST8
+{SPR_HRAD,32768,4,NULL,S_ARTI_HEALRAD2,0,0},	// S_ARTI_HEALRAD1
+{SPR_HRAD,32769,4,NULL,S_ARTI_HEALRAD3,0,0},	// S_ARTI_HEALRAD2
+{SPR_HRAD,32770,4,NULL,S_ARTI_HEALRAD4,0,0},	// S_ARTI_HEALRAD3
+{SPR_HRAD,32771,4,NULL,S_ARTI_HEALRAD5,0,0},	// S_ARTI_HEALRAD4
+{SPR_HRAD,32772,4,NULL,S_ARTI_HEALRAD6,0,0},	// S_ARTI_HEALRAD5
+{SPR_HRAD,32773,4,NULL,S_ARTI_HEALRAD7,0,0},	// S_ARTI_HEALRAD6
+{SPR_HRAD,32774,4,NULL,S_ARTI_HEALRAD8,0,0},	// S_ARTI_HEALRAD7
+{SPR_HRAD,32775,4,NULL,S_ARTI_HEALRAD9,0,0},	// S_ARTI_HEALRAD8
+{SPR_HRAD,32776,4,NULL,S_ARTI_HEALRAD0,0,0},	// S_ARTI_HEALRAD9
+{SPR_HRAD,32777,4,NULL,S_ARTI_HEALRADA,0,0},	// S_ARTI_HEALRAD0
+{SPR_HRAD,32778,4,NULL,S_ARTI_HEALRADB,0,0},	// S_ARTI_HEALRADA
+{SPR_HRAD,32779,4,NULL,S_ARTI_HEALRADC,0,0},	// S_ARTI_HEALRADB
+{SPR_HRAD,32780,4,NULL,S_ARTI_HEALRADD,0,0},	// S_ARTI_HEALRADC
+{SPR_HRAD,32781,4,NULL,S_ARTI_HEALRADE,0,0},	// S_ARTI_HEALRADD
+{SPR_HRAD,32782,4,NULL,S_ARTI_HEALRADF,0,0},	// S_ARTI_HEALRADE
+{SPR_HRAD,32783,4,NULL,S_ARTI_HEALRAD1,0,0},	// S_ARTI_HEALRADF
+{SPR_SPSH,0,8,NULL,S_SPLASH2,0,0},	// S_SPLASH1
+{SPR_SPSH,1,8,NULL,S_SPLASH3,0,0},	// S_SPLASH2
+{SPR_SPSH,2,8,NULL,S_SPLASH4,0,0},	// S_SPLASH3
+{SPR_SPSH,3,16,NULL,S_NULL,0,0},	// S_SPLASH4
+{SPR_SPSH,3,10,NULL,S_NULL,0,0},	// S_SPLASHX
+{SPR_SPSH,4,5,NULL,S_SPLASHBASE2,0,0},	// S_SPLASHBASE1
+{SPR_SPSH,5,5,NULL,S_SPLASHBASE3,0,0},	// S_SPLASHBASE2
+{SPR_SPSH,6,5,NULL,S_SPLASHBASE4,0,0},	// S_SPLASHBASE3
+{SPR_SPSH,7,5,NULL,S_SPLASHBASE5,0,0},	// S_SPLASHBASE4
+{SPR_SPSH,8,5,NULL,S_SPLASHBASE6,0,0},	// S_SPLASHBASE5
+{SPR_SPSH,9,5,NULL,S_SPLASHBASE7,0,0},	// S_SPLASHBASE6
+{SPR_SPSH,10,5,NULL,S_NULL,0,0},	// S_SPLASHBASE7
+{SPR_LVAS,32768,5,NULL,S_LAVASPLASH2,0,0},	// S_LAVASPLASH1
+{SPR_LVAS,32769,5,NULL,S_LAVASPLASH3,0,0},	// S_LAVASPLASH2
+{SPR_LVAS,32770,5,NULL,S_LAVASPLASH4,0,0},	// S_LAVASPLASH3
+{SPR_LVAS,32771,5,NULL,S_LAVASPLASH5,0,0},	// S_LAVASPLASH4
+{SPR_LVAS,32772,5,NULL,S_LAVASPLASH6,0,0},	// S_LAVASPLASH5
+{SPR_LVAS,32773,5,NULL,S_NULL,0,0},	// S_LAVASPLASH6
+{SPR_LVAS,32774,5,NULL,S_LAVASMOKE2,0,0},	// S_LAVASMOKE1
+{SPR_LVAS,32775,5,NULL,S_LAVASMOKE3,0,0},	// S_LAVASMOKE2
+{SPR_LVAS,32776,5,NULL,S_LAVASMOKE4,0,0},	// S_LAVASMOKE3
+{SPR_LVAS,32777,5,NULL,S_LAVASMOKE5,0,0},	// S_LAVASMOKE4
+{SPR_LVAS,32778,5,NULL,S_NULL,0,0},	// S_LAVASMOKE5
+{SPR_SLDG,0,8,NULL,S_SLUDGECHUNK2,0,0},	// S_SLUDGECHUNK1
+{SPR_SLDG,1,8,NULL,S_SLUDGECHUNK3,0,0},	// S_SLUDGECHUNK2
+{SPR_SLDG,2,8,NULL,S_SLUDGECHUNK4,0,0},	// S_SLUDGECHUNK3
+{SPR_SLDG,3,8,NULL,S_NULL,0,0},	// S_SLUDGECHUNK4
+{SPR_SLDG,3,6,NULL,S_NULL,0,0},	// S_SLUDGECHUNKX
+{SPR_SLDG,4,6,NULL,S_SLUDGESPLASH2,0,0},	// S_SLUDGESPLASH1
+{SPR_SLDG,5,6,NULL,S_SLUDGESPLASH3,0,0},	// S_SLUDGESPLASH2
+{SPR_SLDG,6,6,NULL,S_SLUDGESPLASH4,0,0},	// S_SLUDGESPLASH3
+{SPR_SLDG,7,6,NULL,S_NULL,0,0},	// S_SLUDGESPLASH4
+{SPR_STTW,0,-1,NULL,S_NULL,0,0},	// S_ZWINGEDSTATUE1
+{SPR_RCK1,0,-1,NULL,S_NULL,0,0},	// S_ZROCK1_1
+{SPR_RCK2,0,-1,NULL,S_NULL,0,0},	// S_ZROCK2_1
+{SPR_RCK3,0,-1,NULL,S_NULL,0,0},	// S_ZROCK3_1
+{SPR_RCK4,0,-1,NULL,S_NULL,0,0},	// S_ZROCK4_1
+{SPR_CDLR,0,4,NULL,S_ZCHANDELIER2,0,0},	// S_ZCHANDELIER1
+{SPR_CDLR,1,4,NULL,S_ZCHANDELIER3,0,0},	// S_ZCHANDELIER2
+{SPR_CDLR,2,4,NULL,S_ZCHANDELIER1,0,0},	// S_ZCHANDELIER3
+{SPR_CDLR,3,-1,NULL,S_NULL,0,0},	// S_ZCHANDELIER_U
+{SPR_TRE1,0,-1,NULL,S_NULL,0,0},	// S_ZTREEDEAD1
+{SPR_TRE1,0,-1,NULL,S_NULL,0,0},	// S_ZTREE
+{SPR_TRDT,0,-1,NULL,S_NULL,0,0},	// S_ZTREEDESTRUCTIBLE1
+{SPR_TRDT,1,5,NULL,S_ZTREEDES_D2,0,0},	// S_ZTREEDES_D1
+{SPR_TRDT,2,5,A_Scream,S_ZTREEDES_D3,0,0},	// S_ZTREEDES_D2
+{SPR_TRDT,3,5,NULL,S_ZTREEDES_D4,0,0},	// S_ZTREEDES_D3
+{SPR_TRDT,4,5,NULL,S_ZTREEDES_D5,0,0},	// S_ZTREEDES_D4
+{SPR_TRDT,5,5,NULL,S_ZTREEDES_D6,0,0},	// S_ZTREEDES_D5
+{SPR_TRDT,6,-1,NULL,S_NULL,0,0},	// S_ZTREEDES_D6
+{SPR_TRDT,32775,5,NULL,S_ZTREEDES_X2,0,0},	// S_ZTREEDES_X1
+{SPR_TRDT,32776,5,NULL,S_ZTREEDES_X3,0,0},	// S_ZTREEDES_X2
+{SPR_TRDT,32777,5,NULL,S_ZTREEDES_X4,0,0},	// S_ZTREEDES_X3
+{SPR_TRDT,32778,5,NULL,S_ZTREEDES_X5,0,0},	// S_ZTREEDES_X4
+{SPR_TRDT,32779,5,NULL,S_ZTREEDES_X6,0,0},	// S_ZTREEDES_X5
+{SPR_TRDT,32780,5,A_Explode,S_ZTREEDES_X7,0,0},	// S_ZTREEDES_X6
+{SPR_TRDT,32781,5,NULL,S_ZTREEDES_X8,0,0},	// S_ZTREEDES_X7
+{SPR_TRDT,14,5,NULL,S_ZTREEDES_X9,0,0},	// S_ZTREEDES_X8
+{SPR_TRDT,15,5,NULL,S_ZTREEDES_X10,0,0},	// S_ZTREEDES_X9
+{SPR_TRDT,16,-1,NULL,S_NULL,0,0},	// S_ZTREEDES_X10
+{SPR_TRE2,0,-1,NULL,S_NULL,0,0},	// S_ZTREESWAMP182_1
+{SPR_TRE3,0,-1,NULL,S_NULL,0,0},	// S_ZTREESWAMP172_1
+{SPR_STM1,0,-1,NULL,S_NULL,0,0},	// S_ZSTUMPBURNED1
+{SPR_STM2,0,-1,NULL,S_NULL,0,0},	// S_ZSTUMPBARE1
+{SPR_STM3,0,-1,NULL,S_NULL,0,0},	// S_ZSTUMPSWAMP1_1
+{SPR_STM4,0,-1,NULL,S_NULL,0,0},	// S_ZSTUMPSWAMP2_1
+{SPR_MSH1,0,-1,NULL,S_NULL,0,0},	// S_ZSHROOMLARGE1_1
+{SPR_MSH2,0,-1,NULL,S_NULL,0,0},	// S_ZSHROOMLARGE2_1
+{SPR_MSH3,0,-1,NULL,S_NULL,0,0},	// S_ZSHROOMLARGE3_1
+{SPR_MSH4,0,-1,NULL,S_NULL,0,0},	// S_ZSHROOMSMALL1_1
+{SPR_MSH5,0,-1,NULL,S_NULL,0,0},	// S_ZSHROOMSMALL2_1
+{SPR_MSH6,0,-1,NULL,S_NULL,0,0},	// S_ZSHROOMSMALL3_1
+{SPR_MSH7,0,-1,NULL,S_NULL,0,0},	// S_ZSHROOMSMALL4_1
+{SPR_MSH8,0,-1,NULL,S_NULL,0,0},	// S_ZSHROOMSMALL5_1
+{SPR_SGMP,0,-1,NULL,S_NULL,0,0},	// S_ZSTALAGMITEPILLAR1
+{SPR_SGM1,0,-1,NULL,S_NULL,0,0},	// S_ZSTALAGMITELARGE1
+{SPR_SGM2,0,-1,NULL,S_NULL,0,0},	// S_ZSTALAGMITEMEDIUM1
+{SPR_SGM3,0,-1,NULL,S_NULL,0,0},	// S_ZSTALAGMITESMALL1
+{SPR_SLC1,0,-1,NULL,S_NULL,0,0},	// S_ZSTALACTITELARGE1
+{SPR_SLC2,0,-1,NULL,S_NULL,0,0},	// S_ZSTALACTITEMEDIUM1
+{SPR_SLC3,0,-1,NULL,S_NULL,0,0},	// S_ZSTALACTITESMALL1
+{SPR_MSS1,0,-1,NULL,S_NULL,0,0},	// S_ZMOSSCEILING1_1
+{SPR_MSS2,0,-1,NULL,S_NULL,0,0},	// S_ZMOSSCEILING2_1
+{SPR_SWMV,0,-1,NULL,S_NULL,0,0},	// S_ZSWAMPVINE1
+{SPR_CPS1,0,-1,NULL,S_NULL,0,0},	// S_ZCORPSEKABOB1
+{SPR_CPS2,0,-1,NULL,S_NULL,0,0},	// S_ZCORPSESLEEPING1
+{SPR_TMS1,0,-1,NULL,S_NULL,0,0},	// S_ZTOMBSTONERIP1
+{SPR_TMS2,0,-1,NULL,S_NULL,0,0},	// S_ZTOMBSTONESHANE1
+{SPR_TMS3,0,-1,NULL,S_NULL,0,0},	// S_ZTOMBSTONEBIGCROSS1
+{SPR_TMS4,0,-1,NULL,S_NULL,0,0},	// S_ZTOMBSTONEBRIANR1
+{SPR_TMS5,0,-1,NULL,S_NULL,0,0},	// S_ZTOMBSTONECROSSCIRCLE1
+{SPR_TMS6,0,-1,NULL,S_NULL,0,0},	// S_ZTOMBSTONESMALLCROSS1
+{SPR_TMS7,0,-1,NULL,S_NULL,0,0},	// S_ZTOMBSTONEBRIANP1
+{SPR_CPS3,0,-1,NULL,S_NULL,0,0},	// S_CORPSEHANGING_1
+{SPR_STT2,0,-1,NULL,S_NULL,0,0},	// S_ZSTATUEGARGOYLEGREENTALL_1
+{SPR_STT3,0,-1,NULL,S_NULL,0,0},	// S_ZSTATUEGARGOYLEBLUETALL_1
+{SPR_STT4,0,-1,NULL,S_NULL,0,0},	// S_ZSTATUEGARGOYLEGREENSHORT_1
+{SPR_STT5,0,-1,NULL,S_NULL,0,0},	// S_ZSTATUEGARGOYLEBLUESHORT_1
+{SPR_GAR1,0,-1,NULL,S_NULL,0,0},	// S_ZSTATUEGARGOYLESTRIPETALL_1
+{SPR_GAR2,0,-1,NULL,S_NULL,0,0},	// S_ZSTATUEGARGOYLEDARKREDTALL_1
+{SPR_GAR3,0,-1,NULL,S_NULL,0,0},	// S_ZSTATUEGARGOYLEREDTALL_1
+{SPR_GAR4,0,-1,NULL,S_NULL,0,0},	// S_ZSTATUEGARGOYLETANTALL_1
+{SPR_GAR5,0,-1,NULL,S_NULL,0,0},	// S_ZSTATUEGARGOYLERUSTTALL_1
+{SPR_GAR6,0,-1,NULL,S_NULL,0,0},	// S_ZSTATUEGARGOYLEDARKREDSHORT_1
+{SPR_GAR7,0,-1,NULL,S_NULL,0,0},	// S_ZSTATUEGARGOYLEREDSHORT_1
+{SPR_GAR8,0,-1,NULL,S_NULL,0,0},	// S_ZSTATUEGARGOYLETANSHORT_1
+{SPR_GAR9,0,-1,NULL,S_NULL,0,0},	// S_ZSTATUEGARGOYLERUSTSHORT_1
+{SPR_BNR1,0,-1,NULL,S_NULL,0,0},	// S_ZBANNERTATTERED_1
+{SPR_TRE4,0,-1,NULL,S_NULL,0,0},	// S_ZTREELARGE1
+{SPR_TRE5,0,-1,NULL,S_NULL,0,0},	// S_ZTREELARGE2
+{SPR_TRE6,0,-1,NULL,S_NULL,0,0},	// S_ZTREEGNARLED1
+{SPR_TRE7,0,-1,NULL,S_NULL,0,0},	// S_ZTREEGNARLED2
+{SPR_LOGG,0,-1,NULL,S_NULL,0,0},	// S_ZLOG
+{SPR_ICT1,0,-1,NULL,S_NULL,0,0},	// S_ZSTALACTITEICELARGE
+{SPR_ICT2,0,-1,NULL,S_NULL,0,0},	// S_ZSTALACTITEICEMEDIUM
+{SPR_ICT3,0,-1,NULL,S_NULL,0,0},	// S_ZSTALACTITEICESMALL
+{SPR_ICT4,0,-1,NULL,S_NULL,0,0},	// S_ZSTALACTITEICETINY
+{SPR_ICM1,0,-1,NULL,S_NULL,0,0},	// S_ZSTALAGMITEICELARGE
+{SPR_ICM2,0,-1,NULL,S_NULL,0,0},	// S_ZSTALAGMITEICEMEDIUM
+{SPR_ICM3,0,-1,NULL,S_NULL,0,0},	// S_ZSTALAGMITEICESMALL
+{SPR_ICM4,0,-1,NULL,S_NULL,0,0},	// S_ZSTALAGMITEICETINY
+{SPR_RKBL,0,-1,NULL,S_NULL,0,0},	// S_ZROCKBROWN1
+{SPR_RKBS,0,-1,NULL,S_NULL,0,0},	// S_ZROCKBROWN2
+{SPR_RKBK,0,-1,NULL,S_NULL,0,0},	// S_ZROCKBLACK
+{SPR_RBL1,0,-1,NULL,S_NULL,0,0},	// S_ZRUBBLE1
+{SPR_RBL2,0,-1,NULL,S_NULL,0,0},	// S_ZRUBBLE2
+{SPR_RBL3,0,-1,NULL,S_NULL,0,0},	// S_ZRUBBLE3
+{SPR_VASE,0,-1,NULL,S_NULL,0,0},	// S_ZVASEPILLAR
+{SPR_POT1,0,-1,NULL,S_NULL,0,0},	// S_ZPOTTERY1
+{SPR_POT2,0,-1,NULL,S_NULL,0,0},	// S_ZPOTTERY2
+{SPR_POT3,0,-1,NULL,S_NULL,0,0},	// S_ZPOTTERY3
+{SPR_POT1,0,0,A_PotteryExplode,S_NULL,0,0},	// S_ZPOTTERY_EXPLODE
+{SPR_PBIT,0,-1,NULL,S_NULL,0,0},	// S_POTTERYBIT_1
+{SPR_PBIT,1,-1,NULL,S_NULL,0,0},	// S_POTTERYBIT_2
+{SPR_PBIT,2,-1,NULL,S_NULL,0,0},	// S_POTTERYBIT_3
+{SPR_PBIT,3,-1,NULL,S_NULL,0,0},	// S_POTTERYBIT_4
+{SPR_PBIT,4,-1,NULL,S_NULL,0,0},	// S_POTTERYBIT_5
+{SPR_PBIT,5,0,A_PotteryChooseBit,S_NULL,0,0},	// S_POTTERYBIT_EX0
+{SPR_PBIT,5,140,NULL,S_POTTERYBIT_EX1_2,0,0},	// S_POTTERYBIT_EX1
+{SPR_PBIT,5,1,A_PotteryCheck,S_NULL,0,0},	// S_POTTERYBIT_EX1_2
+{SPR_PBIT,6,140,NULL,S_POTTERYBIT_EX2_2,0,0},	// S_POTTERYBIT_EX2
+{SPR_PBIT,6,1,A_PotteryCheck,S_NULL,0,0},	// S_POTTERYBIT_EX2_2
+{SPR_PBIT,7,140,NULL,S_POTTERYBIT_EX3_2,0,0},	// S_POTTERYBIT_EX3
+{SPR_PBIT,7,1,A_PotteryCheck,S_NULL,0,0},	// S_POTTERYBIT_EX3_2
+{SPR_PBIT,8,140,NULL,S_POTTERYBIT_EX4_2,0,0},	// S_POTTERYBIT_EX4
+{SPR_PBIT,8,1,A_PotteryCheck,S_NULL,0,0},	// S_POTTERYBIT_EX4_2
+{SPR_PBIT,9,140,NULL,S_POTTERYBIT_EX5_2,0,0},	// S_POTTERYBIT_EX5
+{SPR_PBIT,9,1,A_PotteryCheck,S_NULL,0,0},	// S_POTTERYBIT_EX5_2
+{SPR_CPS4,0,-1,NULL,S_NULL,0,0},	// S_ZCORPSELYNCHED1
+{SPR_CPS5,0,140,A_CorpseBloodDrip,S_ZCORPSELYNCHED2,0,0},	// S_ZCORPSELYNCHED2
+{SPR_CPS6,0,-1,NULL,S_NULL,0,0},	// S_ZCORPSESITTING
+{SPR_CPS6,0,1,A_CorpseExplode,S_NULL,0,0},	// S_ZCORPSESITTING_X
+{SPR_CPB1,0,-1,NULL,S_NULL,0,0},	// S_CORPSEBIT_1
+{SPR_CPB2,0,-1,NULL,S_NULL,0,0},	// S_CORPSEBIT_2
+{SPR_CPB3,0,-1,NULL,S_NULL,0,0},	// S_CORPSEBIT_3
+{SPR_CPB4,0,-1,NULL,S_NULL,0,0},	// S_CORPSEBIT_4
+{SPR_BDRP,0,-1,NULL,S_NULL,0,0},	// S_CORPSEBLOODDRIP
+{SPR_BDSH,0,3,NULL,S_CORPSEBLOODDRIP_X2,0,0},	// S_CORPSEBLOODDRIP_X1
+{SPR_BDSH,1,3,NULL,S_CORPSEBLOODDRIP_X3,0,0},	// S_CORPSEBLOODDRIP_X2
+{SPR_BDSH,2,2,NULL,S_CORPSEBLOODDRIP_X4,0,0},	// S_CORPSEBLOODDRIP_X3
+{SPR_BDSH,3,2,NULL,S_NULL,0,0},	// S_CORPSEBLOODDRIP_X4
+{SPR_BDPL,0,-1,NULL,S_NULL,0,0},	// S_BLOODPOOL
+{SPR_CNDL,32768,4,NULL,S_ZCANDLE2,0,0},	// S_ZCANDLE1
+{SPR_CNDL,32769,4,NULL,S_ZCANDLE3,0,0},	// S_ZCANDLE2
+{SPR_CNDL,32770,4,NULL,S_ZCANDLE1,0,0},	// S_ZCANDLE3
+{SPR_MAN1,0,20,A_LeafSpawn,S_ZLEAFSPAWNER,0,0},	// S_ZLEAFSPAWNER
+{SPR_LEF1,0,4,NULL,S_LEAF1_2,0,0},	// S_LEAF1_1
+{SPR_LEF1,1,4,NULL,S_LEAF1_3,0,0},	// S_LEAF1_2
+{SPR_LEF1,2,4,NULL,S_LEAF1_4,0,0},	// S_LEAF1_3
+{SPR_LEF1,3,4,A_LeafThrust,S_LEAF1_5,0,0},	// S_LEAF1_4
+{SPR_LEF1,4,4,NULL,S_LEAF1_6,0,0},	// S_LEAF1_5
+{SPR_LEF1,5,4,NULL,S_LEAF1_7,0,0},	// S_LEAF1_6
+{SPR_LEF1,6,4,NULL,S_LEAF1_8,0,0},	// S_LEAF1_7
+{SPR_LEF1,7,4,A_LeafThrust,S_LEAF1_9,0,0},	// S_LEAF1_8
+{SPR_LEF1,8,4,NULL,S_LEAF1_10,0,0},	// S_LEAF1_9
+{SPR_LEF1,0,4,NULL,S_LEAF1_11,0,0},	// S_LEAF1_10
+{SPR_LEF1,1,4,NULL,S_LEAF1_12,0,0},	// S_LEAF1_11
+{SPR_LEF1,2,4,A_LeafThrust,S_LEAF1_13,0,0},	// S_LEAF1_12
+{SPR_LEF1,3,4,NULL,S_LEAF1_14,0,0},	// S_LEAF1_13
+{SPR_LEF1,4,4,NULL,S_LEAF1_15,0,0},	// S_LEAF1_14
+{SPR_LEF1,5,4,NULL,S_LEAF1_16,0,0},	// S_LEAF1_15
+{SPR_LEF1,6,4,A_LeafThrust,S_LEAF1_17,0,0},	// S_LEAF1_16
+{SPR_LEF1,7,4,NULL,S_LEAF1_18,0,0},	// S_LEAF1_17
+{SPR_LEF1,8,4,NULL,S_NULL,0,0},	// S_LEAF1_18
+{SPR_LEF3,3,10,A_LeafCheck,S_LEAF_X1,0,0},	// S_LEAF_X1
+{SPR_LEF2,0,4,NULL,S_LEAF2_2,0,0},	// S_LEAF2_1
+{SPR_LEF2,1,4,NULL,S_LEAF2_3,0,0},	// S_LEAF2_2
+{SPR_LEF2,2,4,NULL,S_LEAF2_4,0,0},	// S_LEAF2_3
+{SPR_LEF2,3,4,A_LeafThrust,S_LEAF2_5,0,0},	// S_LEAF2_4
+{SPR_LEF2,4,4,NULL,S_LEAF2_6,0,0},	// S_LEAF2_5
+{SPR_LEF2,5,4,NULL,S_LEAF2_7,0,0},	// S_LEAF2_6
+{SPR_LEF2,6,4,NULL,S_LEAF2_8,0,0},	// S_LEAF2_7
+{SPR_LEF2,7,4,A_LeafThrust,S_LEAF2_9,0,0},	// S_LEAF2_8
+{SPR_LEF2,8,4,NULL,S_LEAF2_10,0,0},	// S_LEAF2_9
+{SPR_LEF2,0,4,NULL,S_LEAF2_11,0,0},	// S_LEAF2_10
+{SPR_LEF2,1,4,NULL,S_LEAF2_12,0,0},	// S_LEAF2_11
+{SPR_LEF2,2,4,A_LeafThrust,S_LEAF2_13,0,0},	// S_LEAF2_12
+{SPR_LEF2,3,4,NULL,S_LEAF2_14,0,0},	// S_LEAF2_13
+{SPR_LEF2,4,4,NULL,S_LEAF2_15,0,0},	// S_LEAF2_14
+{SPR_LEF2,5,4,NULL,S_LEAF2_16,0,0},	// S_LEAF2_15
+{SPR_LEF2,6,4,A_LeafThrust,S_LEAF2_17,0,0},	// S_LEAF2_16
+{SPR_LEF2,7,4,NULL,S_LEAF2_18,0,0},	// S_LEAF2_17
+{SPR_LEF2,8,4,NULL,S_NULL,0,0},	// S_LEAF2_18
+{SPR_TWTR,32768,4,NULL,S_ZTWINEDTORCH_2,0,0},	// S_ZTWINEDTORCH_1
+{SPR_TWTR,32769,4,NULL,S_ZTWINEDTORCH_3,0,0},	// S_ZTWINEDTORCH_2
+{SPR_TWTR,32770,4,NULL,S_ZTWINEDTORCH_4,0,0},	// S_ZTWINEDTORCH_3
+{SPR_TWTR,32771,4,NULL,S_ZTWINEDTORCH_5,0,0},	// S_ZTWINEDTORCH_4
+{SPR_TWTR,32772,4,NULL,S_ZTWINEDTORCH_6,0,0},	// S_ZTWINEDTORCH_5
+{SPR_TWTR,32773,4,NULL,S_ZTWINEDTORCH_7,0,0},	// S_ZTWINEDTORCH_6
+{SPR_TWTR,32774,4,NULL,S_ZTWINEDTORCH_8,0,0},	// S_ZTWINEDTORCH_7
+{SPR_TWTR,32775,4,NULL,S_ZTWINEDTORCH_1,0,0},	// S_ZTWINEDTORCH_8
+{SPR_TWTR,8,-1,NULL,S_NULL,0,0},	// S_ZTWINEDTORCH_UNLIT
+{SPR_TLGL,0,2,NULL,S_BRIDGE2,0,0},	// S_BRIDGE1
+{SPR_TLGL,0,2,A_BridgeInit,S_BRIDGE3,0,0},	// S_BRIDGE2
+{SPR_TLGL,0,-1,NULL,S_NULL,0,0},	// S_BRIDGE3
+{SPR_TLGL,0,2,NULL,S_FREE_BRIDGE2,0,0},	// S_FREE_BRIDGE1
+{SPR_TLGL,0,300,NULL,S_NULL,0,0},	// S_FREE_BRIDGE2
+{SPR_TLGL,0,2,NULL,S_BBALL2,0,0},	// S_BBALL1
+{SPR_TLGL,0,5,A_BridgeOrbit,S_BBALL2,0,0},	// S_BBALL2
+{SPR_WLTR,32768,5,NULL,S_ZWALLTORCH2,0,0},	// S_ZWALLTORCH1
+{SPR_WLTR,32769,5,NULL,S_ZWALLTORCH3,0,0},	// S_ZWALLTORCH2
+{SPR_WLTR,32770,5,NULL,S_ZWALLTORCH4,0,0},	// S_ZWALLTORCH3
+{SPR_WLTR,32771,5,NULL,S_ZWALLTORCH5,0,0},	// S_ZWALLTORCH4
+{SPR_WLTR,32772,5,NULL,S_ZWALLTORCH6,0,0},	// S_ZWALLTORCH5
+{SPR_WLTR,32773,5,NULL,S_ZWALLTORCH7,0,0},	// S_ZWALLTORCH6
+{SPR_WLTR,32774,5,NULL,S_ZWALLTORCH8,0,0},	// S_ZWALLTORCH7
+{SPR_WLTR,32775,5,NULL,S_ZWALLTORCH1,0,0},	// S_ZWALLTORCH8
+{SPR_WLTR,8,-1,NULL,S_NULL,0,0},	// S_ZWALLTORCH_U
+{SPR_BARL,0,-1,NULL,S_NULL,0,0},	// S_ZBARREL1
+{SPR_SHB1,0,-1,NULL,S_NULL,0,0},	// S_ZSHRUB1
+{SPR_SHB1,0,1,A_TreeDeath,S_ZSHRUB1,0,0},	// S_ZSHRUB1_DIE
+{SPR_SHB1,32769,7,NULL,S_ZSHRUB1_X2,0,0},	// S_ZSHRUB1_X1
+{SPR_SHB1,32770,6,A_Scream,S_ZSHRUB1_X3,0,0},	// S_ZSHRUB1_X2
+{SPR_SHB1,32771,5,NULL,S_NULL,0,0},	// S_ZSHRUB1_X3
+{SPR_SHB2,0,-1,NULL,S_NULL,0,0},	// S_ZSHRUB2
+{SPR_SHB2,0,1,A_TreeDeath,S_ZSHRUB2,0,0},	// S_ZSHRUB2_DIE
+{SPR_SHB2,32769,7,NULL,S_ZSHRUB2_X2,0,0},	// S_ZSHRUB2_X1
+{SPR_SHB2,32770,6,A_Scream,S_ZSHRUB2_X3,0,0},	// S_ZSHRUB2_X2
+{SPR_SHB2,32771,5,A_Explode,S_ZSHRUB2_X4,0,0},	// S_ZSHRUB2_X3
+{SPR_SHB2,32772,5,NULL,S_NULL,0,0},	// S_ZSHRUB2_X4
+{SPR_BCKT,0,-1,NULL,S_NULL,0,0},	// S_ZBUCKET1
+{SPR_SHRM,0,5,A_PoisonShroom,S_ZPOISONSHROOM_P2,0,0},	// S_ZPOISONSHROOM1
+{SPR_SHRM,0,6,NULL,S_ZPOISONSHROOM_P2,0,0},	// S_ZPOISONSHROOM_P1
+{SPR_SHRM,1,8,A_Pain,S_ZPOISONSHROOM1,0,0},	// S_ZPOISONSHROOM_P2
+{SPR_SHRM,2,5,NULL,S_ZPOISONSHROOM_X2,0,0},	// S_ZPOISONSHROOM_X1
+{SPR_SHRM,3,5,NULL,S_ZPOISONSHROOM_X3,0,0},	// S_ZPOISONSHROOM_X2
+{SPR_SHRM,4,5,A_PoisonBagInit,S_ZPOISONSHROOM_X4,0,0},	// S_ZPOISONSHROOM_X3
+{SPR_SHRM,5,-1,NULL,S_NULL,0,0},	// S_ZPOISONSHROOM_X4
+{SPR_FBUL,32768,4,NULL,S_ZFIREBULL2,0,0},	// S_ZFIREBULL1
+{SPR_FBUL,32769,4,NULL,S_ZFIREBULL3,0,0},	// S_ZFIREBULL2
+{SPR_FBUL,32770,4,NULL,S_ZFIREBULL4,0,0},	// S_ZFIREBULL3
+{SPR_FBUL,32771,4,NULL,S_ZFIREBULL5,0,0},	// S_ZFIREBULL4
+{SPR_FBUL,32772,4,NULL,S_ZFIREBULL6,0,0},	// S_ZFIREBULL5
+{SPR_FBUL,32773,4,NULL,S_ZFIREBULL7,0,0},	// S_ZFIREBULL6
+{SPR_FBUL,32774,4,NULL,S_ZFIREBULL1,0,0},	// S_ZFIREBULL7
+{SPR_FBUL,32777,4,NULL,S_ZFIREBULL_DEATH2,0,0},	// S_ZFIREBULL_DEATH
+{SPR_FBUL,32776,4,NULL,S_ZFIREBULL_U,0,0},	// S_ZFIREBULL_DEATH2
+{SPR_FBUL,7,-1,NULL,S_NULL,0,0},	// S_ZFIREBULL_U
+{SPR_FBUL,32776,4,NULL,S_ZFIREBULL_BIRTH2,0,0},	// S_ZFIREBULL_BIRTH
+{SPR_FBUL,32777,4,NULL,S_ZFIREBULL1,0,0},	// S_ZFIREBULL_BIRTH2
+{SPR_FSKL,32768,4,NULL,S_ZFIRETHING2,0,0},	// S_ZFIRETHING1
+{SPR_FSKL,32769,3,NULL,S_ZFIRETHING3,0,0},	// S_ZFIRETHING2
+{SPR_FSKL,32770,4,NULL,S_ZFIRETHING4,0,0},	// S_ZFIRETHING3
+{SPR_FSKL,32771,3,NULL,S_ZFIRETHING5,0,0},	// S_ZFIRETHING4
+{SPR_FSKL,32772,4,NULL,S_ZFIRETHING6,0,0},	// S_ZFIRETHING5
+{SPR_FSKL,32773,3,NULL,S_ZFIRETHING7,0,0},	// S_ZFIRETHING6
+{SPR_FSKL,32774,4,NULL,S_ZFIRETHING8,0,0},	// S_ZFIRETHING7
+{SPR_FSKL,32775,3,NULL,S_ZFIRETHING9,0,0},	// S_ZFIRETHING8
+{SPR_FSKL,32776,4,NULL,S_ZFIRETHING1,0,0},	// S_ZFIRETHING9
+{SPR_BRTR,32768,4,NULL,S_ZBRASSTORCH2,0,0},	// S_ZBRASSTORCH1
+{SPR_BRTR,32769,4,NULL,S_ZBRASSTORCH3,0,0},	// S_ZBRASSTORCH2
+{SPR_BRTR,32770,4,NULL,S_ZBRASSTORCH4,0,0},	// S_ZBRASSTORCH3
+{SPR_BRTR,32771,4,NULL,S_ZBRASSTORCH5,0,0},	// S_ZBRASSTORCH4
+{SPR_BRTR,32772,4,NULL,S_ZBRASSTORCH6,0,0},	// S_ZBRASSTORCH5
+{SPR_BRTR,32773,4,NULL,S_ZBRASSTORCH7,0,0},	// S_ZBRASSTORCH6
+{SPR_BRTR,32774,4,NULL,S_ZBRASSTORCH8,0,0},	// S_ZBRASSTORCH7
+{SPR_BRTR,32775,4,NULL,S_ZBRASSTORCH9,0,0},	// S_ZBRASSTORCH8
+{SPR_BRTR,32776,4,NULL,S_ZBRASSTORCH10,0,0},	// S_ZBRASSTORCH9
+{SPR_BRTR,32777,4,NULL,S_ZBRASSTORCH11,0,0},	// S_ZBRASSTORCH10
+{SPR_BRTR,32778,4,NULL,S_ZBRASSTORCH12,0,0},	// S_ZBRASSTORCH11
+{SPR_BRTR,32779,4,NULL,S_ZBRASSTORCH13,0,0},	// S_ZBRASSTORCH12
+{SPR_BRTR,32780,4,NULL,S_ZBRASSTORCH1,0,0},	// S_ZBRASSTORCH13
+{SPR_SUIT,0,-1,NULL,S_NULL,0,0},	// S_ZSUITOFARMOR
+{SPR_SUIT,0,1,A_SoAExplode,S_NULL,0,0},	// S_ZSUITOFARMOR_X1
+{SPR_SUIT,1,-1,NULL,S_NULL,0,0},	// S_ZARMORCHUNK1
+{SPR_SUIT,2,-1,NULL,S_NULL,0,0},	// S_ZARMORCHUNK2
+{SPR_SUIT,3,-1,NULL,S_NULL,0,0},	// S_ZARMORCHUNK3
+{SPR_SUIT,4,-1,NULL,S_NULL,0,0},	// S_ZARMORCHUNK4
+{SPR_SUIT,5,-1,NULL,S_NULL,0,0},	// S_ZARMORCHUNK5
+{SPR_SUIT,6,-1,NULL,S_NULL,0,0},	// S_ZARMORCHUNK6
+{SPR_SUIT,7,-1,NULL,S_NULL,0,0},	// S_ZARMORCHUNK7
+{SPR_SUIT,8,-1,NULL,S_NULL,0,0},	// S_ZARMORCHUNK8
+{SPR_SUIT,9,-1,NULL,S_NULL,0,0},	// S_ZARMORCHUNK9
+{SPR_SUIT,10,-1,NULL,S_NULL,0,0},	// S_ZARMORCHUNK10
+{SPR_BBLL,5,-1,NULL,S_NULL,0,0},	// S_ZBELL
+{SPR_BBLL,0,4,A_BellReset1,S_ZBELL_X2,0,0},	// S_ZBELL_X1
+{SPR_BBLL,1,4,NULL,S_ZBELL_X3,0,0},	// S_ZBELL_X2
+{SPR_BBLL,2,4,NULL,S_ZBELL_X4,0,0},	// S_ZBELL_X3
+{SPR_BBLL,3,5,A_Scream,S_ZBELL_X5,0,0},	// S_ZBELL_X4
+{SPR_BBLL,2,4,NULL,S_ZBELL_X6,0,0},	// S_ZBELL_X5
+{SPR_BBLL,1,4,NULL,S_ZBELL_X7,0,0},	// S_ZBELL_X6
+{SPR_BBLL,0,3,NULL,S_ZBELL_X8,0,0},	// S_ZBELL_X7
+{SPR_BBLL,4,4,NULL,S_ZBELL_X9,0,0},	// S_ZBELL_X8
+{SPR_BBLL,5,5,NULL,S_ZBELL_X10,0,0},	// S_ZBELL_X9
+{SPR_BBLL,6,6,A_Scream,S_ZBELL_X11,0,0},	// S_ZBELL_X10
+{SPR_BBLL,5,5,NULL,S_ZBELL_X12,0,0},	// S_ZBELL_X11
+{SPR_BBLL,4,4,NULL,S_ZBELL_X13,0,0},	// S_ZBELL_X12
+{SPR_BBLL,0,4,NULL,S_ZBELL_X14,0,0},	// S_ZBELL_X13
+{SPR_BBLL,1,5,NULL,S_ZBELL_X15,0,0},	// S_ZBELL_X14
+{SPR_BBLL,2,5,NULL,S_ZBELL_X16,0,0},	// S_ZBELL_X15
+{SPR_BBLL,3,6,A_Scream,S_ZBELL_X17,0,0},	// S_ZBELL_X16
+{SPR_BBLL,2,5,NULL,S_ZBELL_X18,0,0},	// S_ZBELL_X17
+{SPR_BBLL,1,5,NULL,S_ZBELL_X19,0,0},	// S_ZBELL_X18
+{SPR_BBLL,0,4,NULL,S_ZBELL_X20,0,0},	// S_ZBELL_X19
+{SPR_BBLL,4,5,NULL,S_ZBELL_X21,0,0},	// S_ZBELL_X20
+{SPR_BBLL,5,5,NULL,S_ZBELL_X22,0,0},	// S_ZBELL_X21
+{SPR_BBLL,6,7,A_Scream,S_ZBELL_X23,0,0},	// S_ZBELL_X22
+{SPR_BBLL,5,5,NULL,S_ZBELL_X24,0,0},	// S_ZBELL_X23
+{SPR_BBLL,4,5,NULL,S_ZBELL_X25,0,0},	// S_ZBELL_X24
+{SPR_BBLL,0,5,NULL,S_ZBELL_X26,0,0},	// S_ZBELL_X25
+{SPR_BBLL,1,6,NULL,S_ZBELL_X27,0,0},	// S_ZBELL_X26
+{SPR_BBLL,2,6,NULL,S_ZBELL_X28,0,0},	// S_ZBELL_X27
+{SPR_BBLL,3,7,A_Scream,S_ZBELL_X29,0,0},	// S_ZBELL_X28
+{SPR_BBLL,2,6,NULL,S_ZBELL_X30,0,0},	// S_ZBELL_X29
+{SPR_BBLL,1,6,NULL,S_ZBELL_X31,0,0},	// S_ZBELL_X30
+{SPR_BBLL,0,5,NULL,S_ZBELL_X32,0,0},	// S_ZBELL_X31
+{SPR_BBLL,4,6,NULL,S_ZBELL_X33,0,0},	// S_ZBELL_X32
+{SPR_BBLL,5,6,NULL,S_ZBELL_X34,0,0},	// S_ZBELL_X33
+{SPR_BBLL,6,7,A_Scream,S_ZBELL_X35,0,0},	// S_ZBELL_X34
+{SPR_BBLL,5,6,NULL,S_ZBELL_X36,0,0},	// S_ZBELL_X35
+{SPR_BBLL,4,6,NULL,S_ZBELL_X37,0,0},	// S_ZBELL_X36
+{SPR_BBLL,0,6,NULL,S_ZBELL_X38,0,0},	// S_ZBELL_X37
+{SPR_BBLL,1,6,NULL,S_ZBELL_X39,0,0},	// S_ZBELL_X38
+{SPR_BBLL,2,6,NULL,S_ZBELL_X40,0,0},	// S_ZBELL_X39
+{SPR_BBLL,1,7,NULL,S_ZBELL_X41,0,0},	// S_ZBELL_X40
+{SPR_BBLL,0,8,NULL,S_ZBELL_X42,0,0},	// S_ZBELL_X41
+{SPR_BBLL,4,12,NULL,S_ZBELL_X43,0,0},	// S_ZBELL_X42
+{SPR_BBLL,0,10,NULL,S_ZBELL_X44,0,0},	// S_ZBELL_X43
+{SPR_BBLL,1,12,NULL,S_ZBELL_X45,0,0},	// S_ZBELL_X44
+{SPR_BBLL,0,12,NULL,S_ZBELL_X46,0,0},	// S_ZBELL_X45
+{SPR_BBLL,4,14,NULL,S_ZBELL_X47,0,0},	// S_ZBELL_X46
+{SPR_BBLL,0,1,A_BellReset2,S_ZBELL,0,0},	// S_ZBELL_X47
+{SPR_CAND,32768,5,NULL,S_ZBLUE_CANDLE2,0,0},	// S_ZBLUE_CANDLE1
+{SPR_CAND,32769,5,NULL,S_ZBLUE_CANDLE3,0,0},	// S_ZBLUE_CANDLE2
+{SPR_CAND,32770,5,NULL,S_ZBLUE_CANDLE4,0,0},	// S_ZBLUE_CANDLE3
+{SPR_CAND,32771,5,NULL,S_ZBLUE_CANDLE5,0,0},	// S_ZBLUE_CANDLE4
+{SPR_CAND,32772,5,NULL,S_ZBLUE_CANDLE1,0,0},	// S_ZBLUE_CANDLE5
+{SPR_IRON,0,-1,NULL,S_NULL,0,0},	// S_ZIRON_MAIDEN
+{SPR_XMAS,0,-1,NULL,S_NULL,0,0},	// S_ZXMAS_TREE
+{SPR_XMAS,0,4,A_TreeDeath,S_ZXMAS_TREE,0,0},	// S_ZXMAS_TREE_DIE
+{SPR_XMAS,32769,6,NULL,S_ZXMAS_TREE_X2,0,0},	// S_ZXMAS_TREE_X1
+{SPR_XMAS,32770,6,A_Scream,S_ZXMAS_TREE_X3,0,0},	// S_ZXMAS_TREE_X2
+{SPR_XMAS,32771,5,NULL,S_ZXMAS_TREE_X4,0,0},	// S_ZXMAS_TREE_X3
+{SPR_XMAS,32772,5,A_Explode,S_ZXMAS_TREE_X5,0,0},	// S_ZXMAS_TREE_X4
+{SPR_XMAS,32773,5,NULL,S_ZXMAS_TREE_X6,0,0},	// S_ZXMAS_TREE_X5
+{SPR_XMAS,32774,4,NULL,S_ZXMAS_TREE_X7,0,0},	// S_ZXMAS_TREE_X6
+{SPR_XMAS,7,5,NULL,S_ZXMAS_TREE_X8,0,0},	// S_ZXMAS_TREE_X7
+{SPR_XMAS,8,4,A_NoBlocking,S_ZXMAS_TREE_X9,0,0},	// S_ZXMAS_TREE_X8
+{SPR_XMAS,9,4,NULL,S_ZXMAS_TREE_X10,0,0},	// S_ZXMAS_TREE_X9
+{SPR_XMAS,10,-1,NULL,S_NULL,0,0},	// S_ZXMAS_TREE_X10
+{SPR_CDRN,32769,4,NULL,S_ZCAULDRON2,0,0},	// S_ZCAULDRON1
+{SPR_CDRN,32770,4,NULL,S_ZCAULDRON3,0,0},	// S_ZCAULDRON2
+{SPR_CDRN,32771,4,NULL,S_ZCAULDRON4,0,0},	// S_ZCAULDRON3
+{SPR_CDRN,32772,4,NULL,S_ZCAULDRON5,0,0},	// S_ZCAULDRON4
+{SPR_CDRN,32773,4,NULL,S_ZCAULDRON6,0,0},	// S_ZCAULDRON5
+{SPR_CDRN,32774,4,NULL,S_ZCAULDRON7,0,0},	// S_ZCAULDRON6
+{SPR_CDRN,32775,4,NULL,S_ZCAULDRON1,0,0},	// S_ZCAULDRON7
+{SPR_CDRN,0,-1,NULL,S_NULL,0,0},	// S_ZCAULDRON_U
+{SPR_CHNS,0,-1,NULL,S_NULL,0,0},	// S_ZCHAINBIT32
+{SPR_CHNS,1,-1,NULL,S_NULL,0,0},	// S_ZCHAINBIT64
+{SPR_CHNS,2,-1,NULL,S_NULL,0,0},	// S_ZCHAINEND_HEART
+{SPR_CHNS,3,-1,NULL,S_NULL,0,0},	// S_ZCHAINEND_HOOK1
+{SPR_CHNS,4,-1,NULL,S_NULL,0,0},	// S_ZCHAINEND_HOOK2
+{SPR_CHNS,5,-1,NULL,S_NULL,0,0},	// S_ZCHAINEND_SPIKE
+{SPR_CHNS,6,-1,NULL,S_NULL,0,0},	// S_ZCHAINEND_SKULL
+{SPR_TST1,0,-1,NULL,S_NULL,0,0},	// S_TABLE_SHIT1
+{SPR_TST2,0,-1,NULL,S_NULL,0,0},	// S_TABLE_SHIT2
+{SPR_TST3,0,-1,NULL,S_NULL,0,0},	// S_TABLE_SHIT3
+{SPR_TST4,0,-1,NULL,S_NULL,0,0},	// S_TABLE_SHIT4
+{SPR_TST5,0,-1,NULL,S_NULL,0,0},	// S_TABLE_SHIT5
+{SPR_TST6,0,-1,NULL,S_NULL,0,0},	// S_TABLE_SHIT6
+{SPR_TST7,0,-1,NULL,S_NULL,0,0},	// S_TABLE_SHIT7
+{SPR_TST8,0,-1,NULL,S_NULL,0,0},	// S_TABLE_SHIT8
+{SPR_TST9,0,-1,NULL,S_NULL,0,0},	// S_TABLE_SHIT9
+{SPR_TST0,0,-1,NULL,S_NULL,0,0},	// S_TABLE_SHIT10
+{SPR_TELE,32768,6,NULL,S_TFOG2,0,0},	// S_TFOG1
+{SPR_TELE,32769,6,NULL,S_TFOG3,0,0},	// S_TFOG2
+{SPR_TELE,32770,6,NULL,S_TFOG4,0,0},	// S_TFOG3
+{SPR_TELE,32771,6,NULL,S_TFOG5,0,0},	// S_TFOG4
+{SPR_TELE,32772,6,NULL,S_TFOG6,0,0},	// S_TFOG5
+{SPR_TELE,32773,6,NULL,S_TFOG7,0,0},	// S_TFOG6
+{SPR_TELE,32774,6,NULL,S_TFOG8,0,0},	// S_TFOG7
+{SPR_TELE,32775,6,NULL,S_TFOG9,0,0},	// S_TFOG8
+{SPR_TELE,32774,6,NULL,S_TFOG10,0,0},	// S_TFOG9
+{SPR_TELE,32773,6,NULL,S_TFOG11,0,0},	// S_TFOG10
+{SPR_TELE,32772,6,NULL,S_TFOG12,0,0},	// S_TFOG11
+{SPR_TELE,32771,6,NULL,S_TFOG13,0,0},	// S_TFOG12
+{SPR_TELE,32770,6,NULL,S_NULL,0,0},	// S_TFOG13
+{SPR_TSMK,0,4,NULL,S_TELESMOKE2,0,0},	// S_TELESMOKE1
+{SPR_TSMK,1,3,NULL,S_TELESMOKE3,0,0},	// S_TELESMOKE2
+{SPR_TSMK,2,4,NULL,S_TELESMOKE4,0,0},	// S_TELESMOKE3
+{SPR_TSMK,3,3,NULL,S_TELESMOKE5,0,0},	// S_TELESMOKE4
+{SPR_TSMK,4,4,NULL,S_TELESMOKE6,0,0},	// S_TELESMOKE5
+{SPR_TSMK,5,3,NULL,S_TELESMOKE7,0,0},	// S_TELESMOKE6
+{SPR_TSMK,6,4,NULL,S_TELESMOKE8,0,0},	// S_TELESMOKE7
+{SPR_TSMK,7,3,NULL,S_TELESMOKE9,0,0},	// S_TELESMOKE8
+{SPR_TSMK,8,4,NULL,S_TELESMOKE10,0,0},	// S_TELESMOKE9
+{SPR_TSMK,9,3,NULL,S_TELESMOKE11,0,0},	// S_TELESMOKE10
+{SPR_TSMK,10,4,NULL,S_TELESMOKE12,0,0},	// S_TELESMOKE11
+{SPR_TSMK,11,3,NULL,S_TELESMOKE13,0,0},	// S_TELESMOKE12
+{SPR_TSMK,12,4,NULL,S_TELESMOKE14,0,0},	// S_TELESMOKE13
+{SPR_TSMK,13,3,NULL,S_TELESMOKE15,0,0},	// S_TELESMOKE14
+{SPR_TSMK,14,4,NULL,S_TELESMOKE16,0,0},	// S_TELESMOKE15
+{SPR_TSMK,15,3,NULL,S_TELESMOKE17,0,0},	// S_TELESMOKE16
+{SPR_TSMK,16,4,NULL,S_TELESMOKE18,0,0},	// S_TELESMOKE17
+{SPR_TSMK,17,3,NULL,S_TELESMOKE19,0,0},	// S_TELESMOKE18
+{SPR_TSMK,18,4,NULL,S_TELESMOKE20,0,0},	// S_TELESMOKE19
+{SPR_TSMK,19,3,NULL,S_TELESMOKE21,0,0},	// S_TELESMOKE20
+{SPR_TSMK,20,4,NULL,S_TELESMOKE22,0,0},	// S_TELESMOKE21
+{SPR_TSMK,21,3,NULL,S_TELESMOKE23,0,0},	// S_TELESMOKE22
+{SPR_TSMK,22,4,NULL,S_TELESMOKE24,0,0},	// S_TELESMOKE23
+{SPR_TSMK,23,3,NULL,S_TELESMOKE25,0,0},	// S_TELESMOKE24
+{SPR_TSMK,24,4,NULL,S_TELESMOKE26,0,0},	// S_TELESMOKE25
+{SPR_TSMK,25,3,NULL,S_TELESMOKE1,0,0},	// S_TELESMOKE26
+{SPR_FPCH,0,0,A_Light0,S_NULL,0,0},	// S_LIGHTDONE
+{SPR_FPCH,0,1,A_WeaponReady,S_PUNCHREADY,0,0},	// S_PUNCHREADY
+{SPR_FPCH,0,1,A_Lower,S_PUNCHDOWN,0,0},	// S_PUNCHDOWN
+{SPR_FPCH,0,1,A_Raise,S_PUNCHUP,0,0},	// S_PUNCHUP
+{SPR_FPCH,1,5,NULL,S_PUNCHATK1_2,5,40},	// S_PUNCHATK1_1
+{SPR_FPCH,2,4,NULL,S_PUNCHATK1_3,5,40},	// S_PUNCHATK1_2
+{SPR_FPCH,3,4,A_FPunchAttack,S_PUNCHATK1_4,5,40},	// S_PUNCHATK1_3
+{SPR_FPCH,2,4,NULL,S_PUNCHATK1_5,5,40},	// S_PUNCHATK1_4
+{SPR_FPCH,1,5,A_ReFire,S_PUNCHREADY,5,40},	// S_PUNCHATK1_5
+{SPR_FPCH,3,4,NULL,S_PUNCHATK2_2,5,40},	// S_PUNCHATK2_1
+{SPR_FPCH,4,4,NULL,S_PUNCHATK2_3,5,40},	// S_PUNCHATK2_2
+{SPR_FPCH,4,1,NULL,S_PUNCHATK2_4,15,50},	// S_PUNCHATK2_3
+{SPR_FPCH,4,1,NULL,S_PUNCHATK2_5,25,60},	// S_PUNCHATK2_4
+{SPR_FPCH,4,1,NULL,S_PUNCHATK2_6,35,70},	// S_PUNCHATK2_5
+{SPR_FPCH,4,1,NULL,S_PUNCHATK2_7,45,80},	// S_PUNCHATK2_6
+{SPR_FPCH,4,1,NULL,S_PUNCHATK2_8,55,90},	// S_PUNCHATK2_7
+{SPR_FPCH,4,1,NULL,S_PUNCHATK2_9,65,100},	// S_PUNCHATK2_8
+{SPR_FPCH,4,10,NULL,S_PUNCHREADY,0,150},	// S_PUNCHATK2_9
+{SPR_FHFX,18,4,NULL,S_PUNCHPUFF2,0,0},	// S_PUNCHPUFF1
+{SPR_FHFX,19,4,NULL,S_PUNCHPUFF3,0,0},	// S_PUNCHPUFF2
+{SPR_FHFX,20,4,NULL,S_PUNCHPUFF4,0,0},	// S_PUNCHPUFF3
+{SPR_FHFX,21,4,NULL,S_PUNCHPUFF5,0,0},	// S_PUNCHPUFF4
+{SPR_FHFX,22,4,NULL,S_NULL,0,0},	// S_PUNCHPUFF5
+{SPR_WFAX,0,-1,NULL,S_NULL,0,0},	// S_AXE
+{SPR_FAXE,0,1,A_WeaponReady,S_FAXEREADY,0,0},	// S_FAXEREADY
+{SPR_FAXE,0,1,A_Lower,S_FAXEDOWN,0,0},	// S_FAXEDOWN
+{SPR_FAXE,0,1,A_Raise,S_FAXEUP,0,0},	// S_FAXEUP
+{SPR_FAXE,1,4,NULL,S_FAXEATK_2,15,32},	// S_FAXEATK_1
+{SPR_FAXE,2,3,NULL,S_FAXEATK_3,15,32},	// S_FAXEATK_2
+{SPR_FAXE,3,2,NULL,S_FAXEATK_4,15,32},	// S_FAXEATK_3
+{SPR_FAXE,3,1,A_FAxeAttack,S_FAXEATK_5,-5,70},	// S_FAXEATK_4
+{SPR_FAXE,3,2,NULL,S_FAXEATK_6,-25,90},	// S_FAXEATK_5
+{SPR_FAXE,4,1,NULL,S_FAXEATK_7,15,32},	// S_FAXEATK_6
+{SPR_FAXE,4,2,NULL,S_FAXEATK_8,10,54},	// S_FAXEATK_7
+{SPR_FAXE,4,7,NULL,S_FAXEATK_9,10,150},	// S_FAXEATK_8
+{SPR_FAXE,0,1,A_ReFire,S_FAXEATK_10,0,60},	// S_FAXEATK_9
+{SPR_FAXE,0,1,NULL,S_FAXEATK_11,0,52},	// S_FAXEATK_10
+{SPR_FAXE,0,1,NULL,S_FAXEATK_12,0,44},	// S_FAXEATK_11
+{SPR_FAXE,0,1,NULL,S_FAXEATK_13,0,36},	// S_FAXEATK_12
+{SPR_FAXE,0,1,NULL,S_FAXEREADY,0,0},	// S_FAXEATK_13
+{SPR_FAXE,11,1,A_WeaponReady,S_FAXEREADY_G1,0,0},	// S_FAXEREADY_G
+{SPR_FAXE,11,1,A_WeaponReady,S_FAXEREADY_G2,0,0},	// S_FAXEREADY_G1
+{SPR_FAXE,11,1,A_WeaponReady,S_FAXEREADY_G3,0,0},	// S_FAXEREADY_G2
+{SPR_FAXE,12,1,A_WeaponReady,S_FAXEREADY_G4,0,0},	// S_FAXEREADY_G3
+{SPR_FAXE,12,1,A_WeaponReady,S_FAXEREADY_G5,0,0},	// S_FAXEREADY_G4
+{SPR_FAXE,12,1,A_WeaponReady,S_FAXEREADY_G,0,0},	// S_FAXEREADY_G5
+{SPR_FAXE,11,1,A_Lower,S_FAXEDOWN_G,0,0},	// S_FAXEDOWN_G
+{SPR_FAXE,11,1,A_Raise,S_FAXEUP_G,0,0},	// S_FAXEUP_G
+{SPR_FAXE,13,4,NULL,S_FAXEATK_G2,15,32},	// S_FAXEATK_G1
+{SPR_FAXE,14,3,NULL,S_FAXEATK_G3,15,32},	// S_FAXEATK_G2
+{SPR_FAXE,15,2,NULL,S_FAXEATK_G4,15,32},	// S_FAXEATK_G3
+{SPR_FAXE,15,1,A_FAxeAttack,S_FAXEATK_G5,-5,70},	// S_FAXEATK_G4
+{SPR_FAXE,15,2,NULL,S_FAXEATK_G6,-25,90},	// S_FAXEATK_G5
+{SPR_FAXE,16,1,NULL,S_FAXEATK_G7,15,32},	// S_FAXEATK_G6
+{SPR_FAXE,16,2,NULL,S_FAXEATK_G8,10,54},	// S_FAXEATK_G7
+{SPR_FAXE,16,7,NULL,S_FAXEATK_G9,10,150},	// S_FAXEATK_G8
+{SPR_FAXE,0,1,A_ReFire,S_FAXEATK_G10,0,60},	// S_FAXEATK_G9
+{SPR_FAXE,0,1,NULL,S_FAXEATK_G11,0,52},	// S_FAXEATK_G10
+{SPR_FAXE,0,1,NULL,S_FAXEATK_G12,0,44},	// S_FAXEATK_G11
+{SPR_FAXE,0,1,NULL,S_FAXEATK_G13,0,36},	// S_FAXEATK_G12
+{SPR_FAXE,0,1,NULL,S_FAXEREADY_G,0,0},	// S_FAXEATK_G13
+{SPR_FAXE,32785,4,NULL,S_AXEPUFF_GLOW2,0,0},	// S_AXEPUFF_GLOW1
+{SPR_FAXE,32786,4,NULL,S_AXEPUFF_GLOW3,0,0},	// S_AXEPUFF_GLOW2
+{SPR_FAXE,32787,4,NULL,S_AXEPUFF_GLOW4,0,0},	// S_AXEPUFF_GLOW3
+{SPR_FAXE,32788,4,NULL,S_AXEPUFF_GLOW5,0,0},	// S_AXEPUFF_GLOW4
+{SPR_FAXE,32789,4,NULL,S_AXEPUFF_GLOW6,0,0},	// S_AXEPUFF_GLOW5
+{SPR_FAXE,32790,4,NULL,S_AXEPUFF_GLOW7,0,0},	// S_AXEPUFF_GLOW6
+{SPR_FAXE,32791,4,NULL,S_NULL,0,0},	// S_AXEPUFF_GLOW7
+{SPR_FAXE,5,3,NULL,S_AXEBLOOD2,0,0},	// S_AXEBLOOD1
+{SPR_FAXE,6,3,NULL,S_AXEBLOOD3,0,0},	// S_AXEBLOOD2
+{SPR_FAXE,7,3,NULL,S_AXEBLOOD4,0,0},	// S_AXEBLOOD3
+{SPR_FAXE,8,3,NULL,S_AXEBLOOD5,0,0},	// S_AXEBLOOD4
+{SPR_FAXE,9,3,NULL,S_AXEBLOOD6,0,0},	// S_AXEBLOOD5
+{SPR_FAXE,10,3,NULL,S_NULL,0,0},	// S_AXEBLOOD6
+{SPR_WFHM,0,-1,NULL,S_NULL,0,0},	// S_HAMM
+{SPR_FHMR,0,1,A_WeaponReady,S_FHAMMERREADY,0,0},	// S_FHAMMERREADY
+{SPR_FHMR,0,1,A_Lower,S_FHAMMERDOWN,0,0},	// S_FHAMMERDOWN
+{SPR_FHMR,0,1,A_Raise,S_FHAMMERUP,0,0},	// S_FHAMMERUP
+{SPR_FHMR,1,6,NULL,S_FHAMMERATK_2,5,0},	// S_FHAMMERATK_1
+{SPR_FHMR,2,3,A_FHammerAttack,S_FHAMMERATK_3,5,0},	// S_FHAMMERATK_2
+{SPR_FHMR,3,3,NULL,S_FHAMMERATK_4,5,0},	// S_FHAMMERATK_3
+{SPR_FHMR,4,2,NULL,S_FHAMMERATK_5,5,0},	// S_FHAMMERATK_4
+{SPR_FHMR,4,10,A_FHammerThrow,S_FHAMMERATK_6,5,150},	// S_FHAMMERATK_5
+{SPR_FHMR,0,1,NULL,S_FHAMMERATK_7,0,60},	// S_FHAMMERATK_6
+{SPR_FHMR,0,1,NULL,S_FHAMMERATK_8,0,55},	// S_FHAMMERATK_7
+{SPR_FHMR,0,1,NULL,S_FHAMMERATK_9,0,50},	// S_FHAMMERATK_8
+{SPR_FHMR,0,1,NULL,S_FHAMMERATK_10,0,45},	// S_FHAMMERATK_9
+{SPR_FHMR,0,1,NULL,S_FHAMMERATK_11,0,40},	// S_FHAMMERATK_10
+{SPR_FHMR,0,1,NULL,S_FHAMMERATK_12,0,35},	// S_FHAMMERATK_11
+{SPR_FHMR,0,1,NULL,S_FHAMMERREADY,0,0},	// S_FHAMMERATK_12
+{SPR_FHFX,32768,2,NULL,S_HAMMER_MISSILE_2,0,0},	// S_HAMMER_MISSILE_1
+{SPR_FHFX,32769,2,A_ContMobjSound,S_HAMMER_MISSILE_3,0,0},	// S_HAMMER_MISSILE_2
+{SPR_FHFX,32770,2,NULL,S_HAMMER_MISSILE_4,0,0},	// S_HAMMER_MISSILE_3
+{SPR_FHFX,32771,2,NULL,S_HAMMER_MISSILE_5,0,0},	// S_HAMMER_MISSILE_4
+{SPR_FHFX,32772,2,NULL,S_HAMMER_MISSILE_6,0,0},	// S_HAMMER_MISSILE_5
+{SPR_FHFX,32773,2,NULL,S_HAMMER_MISSILE_7,0,0},	// S_HAMMER_MISSILE_6
+{SPR_FHFX,32774,2,NULL,S_HAMMER_MISSILE_8,0,0},	// S_HAMMER_MISSILE_7
+{SPR_FHFX,32775,2,NULL,S_HAMMER_MISSILE_1,0,0},	// S_HAMMER_MISSILE_8
+{SPR_FHFX,32776,3,NULL,S_HAMMER_MISSILE_X2,0,0},	// S_HAMMER_MISSILE_X1
+{SPR_FHFX,32777,3,NULL,S_HAMMER_MISSILE_X3,0,0},	// S_HAMMER_MISSILE_X2
+{SPR_FHFX,32778,3,A_Explode,S_HAMMER_MISSILE_X4,0,0},	// S_HAMMER_MISSILE_X3
+{SPR_FHFX,32779,3,NULL,S_HAMMER_MISSILE_X5,0,0},	// S_HAMMER_MISSILE_X4
+{SPR_FHFX,32780,3,NULL,S_HAMMER_MISSILE_X6,0,0},	// S_HAMMER_MISSILE_X5
+{SPR_FHFX,13,3,NULL,S_HAMMER_MISSILE_X7,0,0},	// S_HAMMER_MISSILE_X6
+{SPR_FHFX,32782,3,NULL,S_HAMMER_MISSILE_X8,0,0},	// S_HAMMER_MISSILE_X7
+{SPR_FHFX,32783,3,NULL,S_HAMMER_MISSILE_X9,0,0},	// S_HAMMER_MISSILE_X8
+{SPR_FHFX,32784,3,NULL,S_HAMMER_MISSILE_X10,0,0},	// S_HAMMER_MISSILE_X9
+{SPR_FHFX,32785,3,NULL,S_NULL,0,0},	// S_HAMMER_MISSILE_X10
+{SPR_FHFX,18,4,NULL,S_HAMMERPUFF2,0,0},	// S_HAMMERPUFF1
+{SPR_FHFX,19,4,NULL,S_HAMMERPUFF3,0,0},	// S_HAMMERPUFF2
+{SPR_FHFX,20,4,NULL,S_HAMMERPUFF4,0,0},	// S_HAMMERPUFF3
+{SPR_FHFX,21,4,NULL,S_HAMMERPUFF5,0,0},	// S_HAMMERPUFF4
+{SPR_FHFX,22,4,NULL,S_NULL,0,0},	// S_HAMMERPUFF5
+{SPR_FSRD,32768,1,A_WeaponReady,S_FSWORDREADY1,0,0},	// S_FSWORDREADY
+{SPR_FSRD,32768,1,A_WeaponReady,S_FSWORDREADY2,0,0},	// S_FSWORDREADY1
+{SPR_FSRD,32768,1,A_WeaponReady,S_FSWORDREADY3,0,0},	// S_FSWORDREADY2
+{SPR_FSRD,32768,1,A_WeaponReady,S_FSWORDREADY4,0,0},	// S_FSWORDREADY3
+{SPR_FSRD,32769,1,A_WeaponReady,S_FSWORDREADY5,0,0},	// S_FSWORDREADY4
+{SPR_FSRD,32769,1,A_WeaponReady,S_FSWORDREADY6,0,0},	// S_FSWORDREADY5
+{SPR_FSRD,32769,1,A_WeaponReady,S_FSWORDREADY7,0,0},	// S_FSWORDREADY6
+{SPR_FSRD,32769,1,A_WeaponReady,S_FSWORDREADY8,0,0},	// S_FSWORDREADY7
+{SPR_FSRD,32770,1,A_WeaponReady,S_FSWORDREADY9,0,0},	// S_FSWORDREADY8
+{SPR_FSRD,32770,1,A_WeaponReady,S_FSWORDREADY10,0,0},	// S_FSWORDREADY9
+{SPR_FSRD,32770,1,A_WeaponReady,S_FSWORDREADY11,0,0},	// S_FSWORDREADY10
+{SPR_FSRD,32770,1,A_WeaponReady,S_FSWORDREADY,0,0},	// S_FSWORDREADY11
+{SPR_FSRD,32768,1,A_Lower,S_FSWORDDOWN,0,0},	// S_FSWORDDOWN
+{SPR_FSRD,32768,1,A_Raise,S_FSWORDUP,0,0},	// S_FSWORDUP
+{SPR_FSRD,32771,3,NULL,S_FSWORDATK_2,5,36},	// S_FSWORDATK_1
+{SPR_FSRD,32772,3,NULL,S_FSWORDATK_3,5,36},	// S_FSWORDATK_2
+{SPR_FSRD,32773,2,NULL,S_FSWORDATK_4,5,36},	// S_FSWORDATK_3
+{SPR_FSRD,32774,3,A_FSwordAttack,S_FSWORDATK_5,5,36},	// S_FSWORDATK_4
+{SPR_FSRD,32775,2,NULL,S_FSWORDATK_6,5,36},	// S_FSWORDATK_5
+{SPR_FSRD,32776,2,NULL,S_FSWORDATK_7,5,36},	// S_FSWORDATK_6
+{SPR_FSRD,32776,10,NULL,S_FSWORDATK_8,5,150},	// S_FSWORDATK_7
+{SPR_FSRD,32768,1,NULL,S_FSWORDATK_9,5,60},	// S_FSWORDATK_8
+{SPR_FSRD,32769,1,NULL,S_FSWORDATK_10,5,55},	// S_FSWORDATK_9
+{SPR_FSRD,32770,1,NULL,S_FSWORDATK_11,5,50},	// S_FSWORDATK_10
+{SPR_FSRD,32768,1,NULL,S_FSWORDATK_12,5,45},	// S_FSWORDATK_11
+{SPR_FSRD,32769,1,NULL,S_FSWORDREADY,5,40},	// S_FSWORDATK_12
+{SPR_FSFX,32768,3,NULL,S_FSWORD_MISSILE2,0,0},	// S_FSWORD_MISSILE1
+{SPR_FSFX,32769,3,NULL,S_FSWORD_MISSILE3,0,0},	// S_FSWORD_MISSILE2
+{SPR_FSFX,32770,3,NULL,S_FSWORD_MISSILE1,0,0},	// S_FSWORD_MISSILE3
+{SPR_FSFX,32771,4,NULL,S_FSWORD_MISSILE_X2,0,0},	// S_FSWORD_MISSILE_X1
+{SPR_FSFX,32772,3,A_FSwordFlames,S_FSWORD_MISSILE_X3,0,0},	// S_FSWORD_MISSILE_X2
+{SPR_FSFX,32773,4,A_Explode,S_FSWORD_MISSILE_X4,0,0},	// S_FSWORD_MISSILE_X3
+{SPR_FSFX,32774,3,NULL,S_FSWORD_MISSILE_X5,0,0},	// S_FSWORD_MISSILE_X4
+{SPR_FSFX,32775,4,NULL,S_FSWORD_MISSILE_X6,0,0},	// S_FSWORD_MISSILE_X5
+{SPR_FSFX,32776,3,NULL,S_FSWORD_MISSILE_X7,0,0},	// S_FSWORD_MISSILE_X6
+{SPR_FSFX,32777,4,NULL,S_FSWORD_MISSILE_X8,0,0},	// S_FSWORD_MISSILE_X7
+{SPR_FSFX,32778,3,NULL,S_FSWORD_MISSILE_X9,0,0},	// S_FSWORD_MISSILE_X8
+{SPR_FSFX,32779,3,NULL,S_FSWORD_MISSILE_X10,0,0},	// S_FSWORD_MISSILE_X9
+{SPR_FSFX,32780,3,NULL,S_NULL,0,0},	// S_FSWORD_MISSILE_X10
+{SPR_FSFX,32781,3,NULL,S_FSWORD_FLAME2,0,0},	// S_FSWORD_FLAME1
+{SPR_FSFX,32782,3,NULL,S_FSWORD_FLAME3,0,0},	// S_FSWORD_FLAME2
+{SPR_FSFX,32783,3,NULL,S_FSWORD_FLAME4,0,0},	// S_FSWORD_FLAME3
+{SPR_FSFX,32784,3,NULL,S_FSWORD_FLAME5,0,0},	// S_FSWORD_FLAME4
+{SPR_FSFX,32785,3,NULL,S_FSWORD_FLAME6,0,0},	// S_FSWORD_FLAME5
+{SPR_FSFX,32786,3,NULL,S_FSWORD_FLAME7,0,0},	// S_FSWORD_FLAME6
+{SPR_FSFX,32787,3,NULL,S_FSWORD_FLAME8,0,0},	// S_FSWORD_FLAME7
+{SPR_FSFX,32788,3,NULL,S_FSWORD_FLAME9,0,0},	// S_FSWORD_FLAME8
+{SPR_FSFX,32789,3,NULL,S_FSWORD_FLAME10,0,0},	// S_FSWORD_FLAME9
+{SPR_FSFX,32790,3,NULL,S_NULL,0,0},	// S_FSWORD_FLAME10
+{SPR_CMCE,0,1,A_WeaponReady,S_CMACEREADY,0,0},	// S_CMACEREADY
+{SPR_CMCE,0,1,A_Lower,S_CMACEDOWN,0,0},	// S_CMACEDOWN
+{SPR_CMCE,0,1,A_Raise,S_CMACEUP,0,0},	// S_CMACEUP
+{SPR_CMCE,1,2,NULL,S_CMACEATK_2,60,20},	// S_CMACEATK_1
+{SPR_CMCE,1,1,NULL,S_CMACEATK_3,30,33},	// S_CMACEATK_2
+{SPR_CMCE,1,2,NULL,S_CMACEATK_4,8,45},	// S_CMACEATK_3
+{SPR_CMCE,2,1,NULL,S_CMACEATK_5,8,45},	// S_CMACEATK_4
+{SPR_CMCE,3,1,NULL,S_CMACEATK_6,8,45},	// S_CMACEATK_5
+{SPR_CMCE,4,1,NULL,S_CMACEATK_7,8,45},	// S_CMACEATK_6
+{SPR_CMCE,4,1,A_CMaceAttack,S_CMACEATK_8,-11,58},	// S_CMACEATK_7
+{SPR_CMCE,5,1,NULL,S_CMACEATK_9,8,45},	// S_CMACEATK_8
+{SPR_CMCE,5,2,NULL,S_CMACEATK_10,-8,74},	// S_CMACEATK_9
+{SPR_CMCE,5,1,NULL,S_CMACEATK_11,-20,96},	// S_CMACEATK_10
+{SPR_CMCE,5,8,NULL,S_CMACEATK_12,-33,160},	// S_CMACEATK_11
+{SPR_CMCE,0,2,A_ReFire,S_CMACEATK_13,8,75},	// S_CMACEATK_12
+{SPR_CMCE,0,1,NULL,S_CMACEATK_14,8,65},	// S_CMACEATK_13
+{SPR_CMCE,0,2,NULL,S_CMACEATK_15,8,60},	// S_CMACEATK_14
+{SPR_CMCE,0,1,NULL,S_CMACEATK_16,8,55},	// S_CMACEATK_15
+{SPR_CMCE,0,2,NULL,S_CMACEATK_17,8,50},	// S_CMACEATK_16
+{SPR_CMCE,0,1,NULL,S_CMACEREADY,8,45},	// S_CMACEATK_17
+{SPR_WCSS,0,-1,NULL,S_NULL,0,0},	// S_CSTAFF
+{SPR_CSSF,2,4,NULL,S_CSTAFFREADY1,0,0},	// S_CSTAFFREADY
+{SPR_CSSF,1,3,A_CStaffInitBlink,S_CSTAFFREADY2,0,0},	// S_CSTAFFREADY1
+{SPR_CSSF,0,1,A_WeaponReady,S_CSTAFFREADY3,0,0},	// S_CSTAFFREADY2
+{SPR_CSSF,0,1,A_WeaponReady,S_CSTAFFREADY4,0,0},	// S_CSTAFFREADY3
+{SPR_CSSF,0,1,A_WeaponReady,S_CSTAFFREADY5,0,0},	// S_CSTAFFREADY4
+{SPR_CSSF,0,1,A_WeaponReady,S_CSTAFFREADY6,0,0},	// S_CSTAFFREADY5
+{SPR_CSSF,0,1,A_WeaponReady,S_CSTAFFREADY7,0,0},	// S_CSTAFFREADY6
+{SPR_CSSF,0,1,A_WeaponReady,S_CSTAFFREADY8,0,0},	// S_CSTAFFREADY7
+{SPR_CSSF,0,1,A_WeaponReady,S_CSTAFFREADY9,0,0},	// S_CSTAFFREADY8
+{SPR_CSSF,0,1,A_CStaffCheckBlink,S_CSTAFFREADY2,0,0},	// S_CSTAFFREADY9
+{SPR_CSSF,1,1,A_WeaponReady,S_CSTAFFBLINK2,0,0},	// S_CSTAFFBLINK1
+{SPR_CSSF,1,1,A_WeaponReady,S_CSTAFFBLINK3,0,0},	// S_CSTAFFBLINK2
+{SPR_CSSF,1,1,A_WeaponReady,S_CSTAFFBLINK4,0,0},	// S_CSTAFFBLINK3
+{SPR_CSSF,2,1,A_WeaponReady,S_CSTAFFBLINK5,0,0},	// S_CSTAFFBLINK4
+{SPR_CSSF,2,1,A_WeaponReady,S_CSTAFFBLINK6,0,0},	// S_CSTAFFBLINK5
+{SPR_CSSF,2,1,A_WeaponReady,S_CSTAFFBLINK7,0,0},	// S_CSTAFFBLINK6
+{SPR_CSSF,2,1,A_WeaponReady,S_CSTAFFBLINK8,0,0},	// S_CSTAFFBLINK7
+{SPR_CSSF,2,1,A_WeaponReady,S_CSTAFFBLINK9,0,0},	// S_CSTAFFBLINK8
+{SPR_CSSF,1,1,A_WeaponReady,S_CSTAFFBLINK10,0,0},	// S_CSTAFFBLINK9
+{SPR_CSSF,1,1,A_WeaponReady,S_CSTAFFBLINK11,0,0},	// S_CSTAFFBLINK10
+{SPR_CSSF,1,1,A_WeaponReady,S_CSTAFFREADY2,0,0},	// S_CSTAFFBLINK11
+{SPR_CSSF,1,3,NULL,S_CSTAFFDOWN2,0,0},	// S_CSTAFFDOWN
+{SPR_CSSF,2,4,NULL,S_CSTAFFDOWN3,0,0},	// S_CSTAFFDOWN2
+{SPR_CSSF,2,1,A_Lower,S_CSTAFFDOWN3,0,0},	// S_CSTAFFDOWN3
+{SPR_CSSF,2,1,A_Raise,S_CSTAFFUP,0,0},	// S_CSTAFFUP
+{SPR_CSSF,0,1,A_CStaffCheck,S_CSTAFFATK_2,0,45},	// S_CSTAFFATK_1
+{SPR_CSSF,9,1,A_CStaffAttack,S_CSTAFFATK_3,0,50},	// S_CSTAFFATK_2
+{SPR_CSSF,9,2,NULL,S_CSTAFFATK_4,0,50},	// S_CSTAFFATK_3
+{SPR_CSSF,9,2,NULL,S_CSTAFFATK_5,0,45},	// S_CSTAFFATK_4
+{SPR_CSSF,0,2,NULL,S_CSTAFFATK_6,0,40},	// S_CSTAFFATK_5
+{SPR_CSSF,0,2,NULL,S_CSTAFFREADY2,0,36},	// S_CSTAFFATK_6
+{SPR_CSSF,10,10,NULL,S_CSTAFFREADY2,0,36},	// S_CSTAFFATK2_1
+{SPR_CSSF,32771,1,A_CStaffMissileSlither,S_CSTAFF_MISSILE2,0,0},	// S_CSTAFF_MISSILE1
+{SPR_CSSF,32771,1,A_CStaffMissileSlither,S_CSTAFF_MISSILE3,0,0},	// S_CSTAFF_MISSILE2
+{SPR_CSSF,32772,1,A_CStaffMissileSlither,S_CSTAFF_MISSILE4,0,0},	// S_CSTAFF_MISSILE3
+{SPR_CSSF,32772,1,A_CStaffMissileSlither,S_CSTAFF_MISSILE1,0,0},	// S_CSTAFF_MISSILE4
+{SPR_CSSF,32773,4,NULL,S_CSTAFF_MISSILE_X2,0,0},	// S_CSTAFF_MISSILE_X1
+{SPR_CSSF,32774,4,NULL,S_CSTAFF_MISSILE_X3,0,0},	// S_CSTAFF_MISSILE_X2
+{SPR_CSSF,32775,3,NULL,S_CSTAFF_MISSILE_X4,0,0},	// S_CSTAFF_MISSILE_X3
+{SPR_CSSF,32776,3,NULL,S_NULL,0,0},	// S_CSTAFF_MISSILE_X4
+{SPR_FHFX,18,4,NULL,S_CSTAFFPUFF2,0,0},	// S_CSTAFFPUFF1
+{SPR_FHFX,19,4,NULL,S_CSTAFFPUFF3,0,0},	// S_CSTAFFPUFF2
+{SPR_FHFX,20,4,NULL,S_CSTAFFPUFF4,0,0},	// S_CSTAFFPUFF3
+{SPR_FHFX,21,4,NULL,S_CSTAFFPUFF5,0,0},	// S_CSTAFFPUFF4
+{SPR_FHFX,22,4,NULL,S_NULL,0,0},	// S_CSTAFFPUFF5
+{SPR_WCFM,32768,4,NULL,S_CFLAME2,0,0},	// S_CFLAME1
+{SPR_WCFM,32769,4,NULL,S_CFLAME3,0,0},	// S_CFLAME2
+{SPR_WCFM,32770,4,NULL,S_CFLAME4,0,0},	// S_CFLAME3
+{SPR_WCFM,32771,4,NULL,S_CFLAME5,0,0},	// S_CFLAME4
+{SPR_WCFM,32772,4,NULL,S_CFLAME6,0,0},	// S_CFLAME5
+{SPR_WCFM,32773,4,NULL,S_CFLAME7,0,0},	// S_CFLAME6
+{SPR_WCFM,32774,4,NULL,S_CFLAME8,0,0},	// S_CFLAME7
+{SPR_WCFM,32775,4,NULL,S_CFLAME1,0,0},	// S_CFLAME8
+{SPR_CFLM,0,1,A_WeaponReady,S_CFLAMEREADY2,0,0},	// S_CFLAMEREADY1
+{SPR_CFLM,0,1,A_WeaponReady,S_CFLAMEREADY3,0,0},	// S_CFLAMEREADY2
+{SPR_CFLM,0,1,A_WeaponReady,S_CFLAMEREADY4,0,0},	// S_CFLAMEREADY3
+{SPR_CFLM,0,1,A_WeaponReady,S_CFLAMEREADY5,0,0},	// S_CFLAMEREADY4
+{SPR_CFLM,1,1,A_WeaponReady,S_CFLAMEREADY6,0,0},	// S_CFLAMEREADY5
+{SPR_CFLM,1,1,A_WeaponReady,S_CFLAMEREADY7,0,0},	// S_CFLAMEREADY6
+{SPR_CFLM,1,1,A_WeaponReady,S_CFLAMEREADY8,0,0},	// S_CFLAMEREADY7
+{SPR_CFLM,1,1,A_WeaponReady,S_CFLAMEREADY9,0,0},	// S_CFLAMEREADY8
+{SPR_CFLM,2,1,A_WeaponReady,S_CFLAMEREADY10,0,0},	// S_CFLAMEREADY9
+{SPR_CFLM,2,1,A_WeaponReady,S_CFLAMEREADY11,0,0},	// S_CFLAMEREADY10
+{SPR_CFLM,2,1,A_WeaponReady,S_CFLAMEREADY12,0,0},	// S_CFLAMEREADY11
+{SPR_CFLM,2,1,A_WeaponReady,S_CFLAMEREADY1,0,0},	// S_CFLAMEREADY12
+{SPR_CFLM,0,1,A_Lower,S_CFLAMEDOWN,0,0},	// S_CFLAMEDOWN
+{SPR_CFLM,0,1,A_Raise,S_CFLAMEUP,0,0},	// S_CFLAMEUP
+{SPR_CFLM,0,2,NULL,S_CFLAMEATK_2,0,40},	// S_CFLAMEATK_1
+{SPR_CFLM,3,2,NULL,S_CFLAMEATK_3,0,50},	// S_CFLAMEATK_2
+{SPR_CFLM,3,2,NULL,S_CFLAMEATK_4,0,36},	// S_CFLAMEATK_3
+{SPR_CFLM,32772,4,NULL,S_CFLAMEATK_5,0,0},	// S_CFLAMEATK_4
+{SPR_CFLM,32773,4,A_CFlameAttack,S_CFLAMEATK_6,0,0},	// S_CFLAMEATK_5
+{SPR_CFLM,32772,4,NULL,S_CFLAMEATK_7,0,0},	// S_CFLAMEATK_6
+{SPR_CFLM,6,2,NULL,S_CFLAMEATK_8,0,40},	// S_CFLAMEATK_7
+{SPR_CFLM,6,2,NULL,S_CFLAMEREADY1,0,0},	// S_CFLAMEATK_8
+{SPR_CFFX,32781,5,NULL,S_CFLAMEFLOOR2,0,0},	// S_CFLAMEFLOOR1
+{SPR_CFFX,32782,4,NULL,S_CFLAMEFLOOR3,0,0},	// S_CFLAMEFLOOR2
+{SPR_CFFX,32783,3,NULL,S_NULL,0,0},	// S_CFLAMEFLOOR3
+{SPR_CFFX,32768,3,NULL,S_FLAMEPUFF2,0,0},	// S_FLAMEPUFF1
+{SPR_CFFX,32769,3,NULL,S_FLAMEPUFF3,0,0},	// S_FLAMEPUFF2
+{SPR_CFFX,32770,3,NULL,S_FLAMEPUFF4,0,0},	// S_FLAMEPUFF3
+{SPR_CFFX,32771,4,NULL,S_FLAMEPUFF5,0,0},	// S_FLAMEPUFF4
+{SPR_CFFX,32772,3,NULL,S_FLAMEPUFF6,0,0},	// S_FLAMEPUFF5
+{SPR_CFFX,32773,4,NULL,S_FLAMEPUFF7,0,0},	// S_FLAMEPUFF6
+{SPR_CFFX,32774,3,NULL,S_FLAMEPUFF8,0,0},	// S_FLAMEPUFF7
+{SPR_CFFX,32775,4,NULL,S_FLAMEPUFF9,0,0},	// S_FLAMEPUFF8
+{SPR_CFFX,32776,3,NULL,S_FLAMEPUFF10,0,0},	// S_FLAMEPUFF9
+{SPR_CFFX,32777,4,NULL,S_FLAMEPUFF11,0,0},	// S_FLAMEPUFF10
+{SPR_CFFX,32778,3,NULL,S_FLAMEPUFF12,0,0},	// S_FLAMEPUFF11
+{SPR_CFFX,32779,4,NULL,S_FLAMEPUFF13,0,0},	// S_FLAMEPUFF12
+{SPR_CFFX,32780,3,NULL,S_NULL,0,0},	// S_FLAMEPUFF13
+{SPR_CFFX,32768,3,NULL,S_FLAMEPUFF2_2,0,0},	// S_FLAMEPUFF2_1
+{SPR_CFFX,32769,3,NULL,S_FLAMEPUFF2_3,0,0},	// S_FLAMEPUFF2_2
+{SPR_CFFX,32770,3,NULL,S_FLAMEPUFF2_4,0,0},	// S_FLAMEPUFF2_3
+{SPR_CFFX,32771,4,NULL,S_FLAMEPUFF2_5,0,0},	// S_FLAMEPUFF2_4
+{SPR_CFFX,32772,3,NULL,S_FLAMEPUFF2_6,0,0},	// S_FLAMEPUFF2_5
+{SPR_CFFX,32773,4,NULL,S_FLAMEPUFF2_7,0,0},	// S_FLAMEPUFF2_6
+{SPR_CFFX,32774,3,NULL,S_FLAMEPUFF2_8,0,0},	// S_FLAMEPUFF2_7
+{SPR_CFFX,32775,4,NULL,S_FLAMEPUFF2_9,0,0},	// S_FLAMEPUFF2_8
+{SPR_CFFX,32776,3,NULL,S_FLAMEPUFF2_10,0,0},	// S_FLAMEPUFF2_9
+{SPR_CFFX,32770,3,NULL,S_FLAMEPUFF2_11,0,0},	// S_FLAMEPUFF2_10
+{SPR_CFFX,32771,4,NULL,S_FLAMEPUFF2_12,0,0},	// S_FLAMEPUFF2_11
+{SPR_CFFX,32772,3,NULL,S_FLAMEPUFF2_13,0,0},	// S_FLAMEPUFF2_12
+{SPR_CFFX,32773,4,NULL,S_FLAMEPUFF2_14,0,0},	// S_FLAMEPUFF2_13
+{SPR_CFFX,32774,3,NULL,S_FLAMEPUFF2_15,0,0},	// S_FLAMEPUFF2_14
+{SPR_CFFX,32775,4,NULL,S_FLAMEPUFF2_16,0,0},	// S_FLAMEPUFF2_15
+{SPR_CFFX,32776,3,NULL,S_FLAMEPUFF2_17,0,0},	// S_FLAMEPUFF2_16
+{SPR_CFFX,32777,4,NULL,S_FLAMEPUFF2_18,0,0},	// S_FLAMEPUFF2_17
+{SPR_CFFX,32778,3,NULL,S_FLAMEPUFF2_19,0,0},	// S_FLAMEPUFF2_18
+{SPR_CFFX,32779,4,NULL,S_FLAMEPUFF2_20,0,0},	// S_FLAMEPUFF2_19
+{SPR_CFFX,32780,3,NULL,S_NULL,0,0},	// S_FLAMEPUFF2_20
+{SPR_CFCF,32768,4,NULL,S_CIRCLE_FLAME2,0,0},	// S_CIRCLE_FLAME1
+{SPR_CFCF,32769,2,A_CFlameRotate,S_CIRCLE_FLAME3,0,0},	// S_CIRCLE_FLAME2
+{SPR_CFCF,32770,2,NULL,S_CIRCLE_FLAME4,0,0},	// S_CIRCLE_FLAME3
+{SPR_CFCF,32771,1,NULL,S_CIRCLE_FLAME5,0,0},	// S_CIRCLE_FLAME4
+{SPR_CFCF,32772,2,NULL,S_CIRCLE_FLAME6,0,0},	// S_CIRCLE_FLAME5
+{SPR_CFCF,32773,2,A_CFlameRotate,S_CIRCLE_FLAME7,0,0},	// S_CIRCLE_FLAME6
+{SPR_CFCF,32774,1,NULL,S_CIRCLE_FLAME8,0,0},	// S_CIRCLE_FLAME7
+{SPR_CFCF,32775,2,NULL,S_CIRCLE_FLAME9,0,0},	// S_CIRCLE_FLAME8
+{SPR_CFCF,32776,2,NULL,S_CIRCLE_FLAME10,0,0},	// S_CIRCLE_FLAME9
+{SPR_CFCF,32777,1,A_CFlameRotate,S_CIRCLE_FLAME11,0,0},	// S_CIRCLE_FLAME10
+{SPR_CFCF,32778,2,NULL,S_CIRCLE_FLAME12,0,0},	// S_CIRCLE_FLAME11
+{SPR_CFCF,32779,3,NULL,S_CIRCLE_FLAME13,0,0},	// S_CIRCLE_FLAME12
+{SPR_CFCF,32780,3,NULL,S_CIRCLE_FLAME14,0,0},	// S_CIRCLE_FLAME13
+{SPR_CFCF,32781,2,A_CFlameRotate,S_CIRCLE_FLAME15,0,0},	// S_CIRCLE_FLAME14
+{SPR_CFCF,32782,3,NULL,S_CIRCLE_FLAME16,0,0},	// S_CIRCLE_FLAME15
+{SPR_CFCF,32783,2,NULL,S_NULL,0,0},	// S_CIRCLE_FLAME16
+{SPR_CFCF,32784,3,NULL,S_CIRCLE_FLAME_X2,0,0},	// S_CIRCLE_FLAME_X1
+{SPR_CFCF,32785,3,NULL,S_CIRCLE_FLAME_X3,0,0},	// S_CIRCLE_FLAME_X2
+{SPR_CFCF,32786,3,A_Explode,S_CIRCLE_FLAME_X4,0,0},	// S_CIRCLE_FLAME_X3
+{SPR_CFCF,32787,3,NULL,S_CIRCLE_FLAME_X5,0,0},	// S_CIRCLE_FLAME_X4
+{SPR_CFCF,32788,3,NULL,S_CIRCLE_FLAME_X6,0,0},	// S_CIRCLE_FLAME_X5
+{SPR_CFCF,32789,3,NULL,S_CIRCLE_FLAME_X7,0,0},	// S_CIRCLE_FLAME_X6
+{SPR_CFCF,32790,3,NULL,S_CIRCLE_FLAME_X8,0,0},	// S_CIRCLE_FLAME_X7
+{SPR_CFCF,32791,3,NULL,S_CIRCLE_FLAME_X9,0,0},	// S_CIRCLE_FLAME_X8
+{SPR_CFCF,32792,3,NULL,S_CIRCLE_FLAME_X10,0,0},	// S_CIRCLE_FLAME_X9
+{SPR_CFCF,32793,3,NULL,S_NULL,0,0},	// S_CIRCLE_FLAME_X10
+{SPR_CFFX,32768,4,NULL,S_CFLAME_MISSILE2,0,0},	// S_CFLAME_MISSILE1
+{SPR_CFFX,0,1,A_CFlamePuff,S_FLAMEPUFF1,0,0},	// S_CFLAME_MISSILE2
+{SPR_CFFX,32768,1,A_CFlameMissile,S_FLAMEPUFF1,0,0},	// S_CFLAME_MISSILE_X
+{SPR_CHLY,0,1,A_WeaponReady,S_CHOLYREADY,0,0},	// S_CHOLYREADY
+{SPR_CHLY,0,1,A_Lower,S_CHOLYDOWN,0,0},	// S_CHOLYDOWN
+{SPR_CHLY,0,1,A_Raise,S_CHOLYUP,0,0},	// S_CHOLYUP
+{SPR_CHLY,32768,1,NULL,S_CHOLYATK_2,0,40},	// S_CHOLYATK_1
+{SPR_CHLY,32769,1,NULL,S_CHOLYATK_3,0,40},	// S_CHOLYATK_2
+{SPR_CHLY,32770,2,NULL,S_CHOLYATK_4,0,43},	// S_CHOLYATK_3
+{SPR_CHLY,32771,2,NULL,S_CHOLYATK_5,0,43},	// S_CHOLYATK_4
+{SPR_CHLY,32772,2,NULL,S_CHOLYATK_6,0,45},	// S_CHOLYATK_5
+{SPR_CHLY,32773,6,A_CHolyAttack,S_CHOLYATK_7,0,48},	// S_CHOLYATK_6
+{SPR_CHLY,32774,2,A_CHolyPalette,S_CHOLYATK_8,0,40},	// S_CHOLYATK_7
+{SPR_CHLY,32774,2,A_CHolyPalette,S_CHOLYATK_9,0,40},	// S_CHOLYATK_8
+{SPR_CHLY,32774,2,A_CHolyPalette,S_CHOLYREADY,0,36},	// S_CHOLYATK_9
+{SPR_SPIR,0,2,A_CHolySeek,S_HOLY_FX2,0,0},	// S_HOLY_FX1
+{SPR_SPIR,0,2,A_CHolySeek,S_HOLY_FX3,0,0},	// S_HOLY_FX2
+{SPR_SPIR,1,2,A_CHolySeek,S_HOLY_FX4,0,0},	// S_HOLY_FX3
+{SPR_SPIR,1,2,A_CHolyCheckScream,S_HOLY_FX1,0,0},	// S_HOLY_FX4
+{SPR_SPIR,3,4,NULL,S_HOLY_FX_X2,0,0},	// S_HOLY_FX_X1
+{SPR_SPIR,4,4,A_Scream,S_HOLY_FX_X3,0,0},	// S_HOLY_FX_X2
+{SPR_SPIR,5,4,NULL,S_HOLY_FX_X4,0,0},	// S_HOLY_FX_X3
+{SPR_SPIR,6,4,NULL,S_HOLY_FX_X5,0,0},	// S_HOLY_FX_X4
+{SPR_SPIR,7,4,NULL,S_HOLY_FX_X6,0,0},	// S_HOLY_FX_X5
+{SPR_SPIR,8,4,NULL,S_NULL,0,0},	// S_HOLY_FX_X6
+{SPR_SPIR,2,1,A_CHolyTail,S_HOLY_TAIL1,0,0},	// S_HOLY_TAIL1
+{SPR_SPIR,3,-1,NULL,S_NULL,0,0},	// S_HOLY_TAIL2
+{SPR_SPIR,10,3,NULL,S_HOLY_PUFF2,0,0},	// S_HOLY_PUFF1
+{SPR_SPIR,11,3,NULL,S_HOLY_PUFF3,0,0},	// S_HOLY_PUFF2
+{SPR_SPIR,12,3,NULL,S_HOLY_PUFF4,0,0},	// S_HOLY_PUFF3
+{SPR_SPIR,13,3,NULL,S_HOLY_PUFF5,0,0},	// S_HOLY_PUFF4
+{SPR_SPIR,14,3,NULL,S_NULL,0,0},	// S_HOLY_PUFF5
+{SPR_SPIR,32783,3,A_CHolySpawnPuff,S_HOLY_MISSILE2,0,0},	// S_HOLY_MISSILE1
+{SPR_SPIR,32783,3,A_CHolySpawnPuff,S_HOLY_MISSILE3,0,0},	// S_HOLY_MISSILE2
+{SPR_SPIR,32783,3,A_CHolySpawnPuff,S_HOLY_MISSILE4,0,0},	// S_HOLY_MISSILE3
+{SPR_SPIR,32783,3,A_CHolySpawnPuff,S_HOLY_MISSILE_X,0,0},	// S_HOLY_MISSILE4
+{SPR_SPIR,32783,1,A_CHolyAttack2,S_NULL,0,0},	// S_HOLY_MISSILE_X
+{SPR_SPIR,16,3,NULL,S_HOLY_MISSILE_P2,0,0},	// S_HOLY_MISSILE_P1
+{SPR_SPIR,17,3,NULL,S_HOLY_MISSILE_P3,0,0},	// S_HOLY_MISSILE_P2
+{SPR_SPIR,18,3,NULL,S_HOLY_MISSILE_P4,0,0},	// S_HOLY_MISSILE_P3
+{SPR_SPIR,19,3,NULL,S_HOLY_MISSILE_P5,0,0},	// S_HOLY_MISSILE_P4
+{SPR_SPIR,20,3,NULL,S_NULL,0,0},	// S_HOLY_MISSILE_P5
+{SPR_MWND,0,1,A_WeaponReady,S_MWANDREADY,0,0},	// S_MWANDREADY
+{SPR_MWND,0,1,A_Lower,S_MWANDDOWN,0,0},	// S_MWANDDOWN
+{SPR_MWND,0,1,A_Raise,S_MWANDUP,0,0},	// S_MWANDUP
+{SPR_MWND,0,6,NULL,S_MWANDATK_2,0,0},	// S_MWANDATK_1
+{SPR_MWND,32769,6,A_MWandAttack,S_MWANDATK_3,0,48},	// S_MWANDATK_2
+{SPR_MWND,0,3,NULL,S_MWANDATK_4,0,40},	// S_MWANDATK_3
+{SPR_MWND,0,3,A_ReFire,S_MWANDREADY,0,36},	// S_MWANDATK_4
+{SPR_MWND,32772,4,NULL,S_MWANDPUFF2,0,0},	// S_MWANDPUFF1
+{SPR_MWND,32773,3,NULL,S_MWANDPUFF3,0,0},	// S_MWANDPUFF2
+{SPR_MWND,32774,4,NULL,S_MWANDPUFF4,0,0},	// S_MWANDPUFF3
+{SPR_MWND,32775,3,NULL,S_MWANDPUFF5,0,0},	// S_MWANDPUFF4
+{SPR_MWND,32776,4,NULL,S_NULL,0,0},	// S_MWANDPUFF5
+{SPR_MWND,2,4,NULL,S_MWANDSMOKE2,0,0},	// S_MWANDSMOKE1
+{SPR_MWND,3,4,NULL,S_MWANDSMOKE3,0,0},	// S_MWANDSMOKE2
+{SPR_MWND,2,4,NULL,S_MWANDSMOKE4,0,0},	// S_MWANDSMOKE3
+{SPR_MWND,3,4,NULL,S_NULL,0,0},	// S_MWANDSMOKE4
+{SPR_MWND,32770,4,NULL,S_MWAND_MISSILE2,0,0},	// S_MWAND_MISSILE1
+{SPR_MWND,32771,4,NULL,S_MWAND_MISSILE1,0,0},	// S_MWAND_MISSILE2
+{SPR_WMLG,32768,4,NULL,S_MW_LIGHTNING2,0,0},	// S_MW_LIGHTNING1
+{SPR_WMLG,32769,4,NULL,S_MW_LIGHTNING3,0,0},	// S_MW_LIGHTNING2
+{SPR_WMLG,32770,4,NULL,S_MW_LIGHTNING4,0,0},	// S_MW_LIGHTNING3
+{SPR_WMLG,32771,4,NULL,S_MW_LIGHTNING5,0,0},	// S_MW_LIGHTNING4
+{SPR_WMLG,32772,4,NULL,S_MW_LIGHTNING6,0,0},	// S_MW_LIGHTNING5
+{SPR_WMLG,32773,4,NULL,S_MW_LIGHTNING7,0,0},	// S_MW_LIGHTNING6
+{SPR_WMLG,32774,4,NULL,S_MW_LIGHTNING8,0,0},	// S_MW_LIGHTNING7
+{SPR_WMLG,32775,4,NULL,S_MW_LIGHTNING1,0,0},	// S_MW_LIGHTNING8
+{SPR_MLNG,32768,1,A_WeaponReady,S_MLIGHTNINGREADY2,0,0},	// S_MLIGHTNINGREADY
+{SPR_MLNG,32768,1,A_WeaponReady,S_MLIGHTNINGREADY3,0,0},	// S_MLIGHTNINGREADY2
+{SPR_MLNG,32768,1,A_WeaponReady,S_MLIGHTNINGREADY4,0,0},	// S_MLIGHTNINGREADY3
+{SPR_MLNG,32768,1,A_WeaponReady,S_MLIGHTNINGREADY5,0,0},	// S_MLIGHTNINGREADY4
+{SPR_MLNG,32768,1,A_WeaponReady,S_MLIGHTNINGREADY6,0,0},	// S_MLIGHTNINGREADY5
+{SPR_MLNG,32768,1,A_LightningReady,S_MLIGHTNINGREADY7,0,0},	// S_MLIGHTNINGREADY6
+{SPR_MLNG,32769,1,A_WeaponReady,S_MLIGHTNINGREADY8,0,0},	// S_MLIGHTNINGREADY7
+{SPR_MLNG,32769,1,A_WeaponReady,S_MLIGHTNINGREADY9,0,0},	// S_MLIGHTNINGREADY8
+{SPR_MLNG,32769,1,A_WeaponReady,S_MLIGHTNINGREADY10,0,0},	// S_MLIGHTNINGREADY9
+{SPR_MLNG,32769,1,A_WeaponReady,S_MLIGHTNINGREADY11,0,0},	// S_MLIGHTNINGREADY10
+{SPR_MLNG,32769,1,A_WeaponReady,S_MLIGHTNINGREADY12,0,0},	// S_MLIGHTNINGREADY11
+{SPR_MLNG,32769,1,A_WeaponReady,S_MLIGHTNINGREADY13,0,0},	// S_MLIGHTNINGREADY12
+{SPR_MLNG,32770,1,A_WeaponReady,S_MLIGHTNINGREADY14,0,0},	// S_MLIGHTNINGREADY13
+{SPR_MLNG,32770,1,A_WeaponReady,S_MLIGHTNINGREADY15,0,0},	// S_MLIGHTNINGREADY14
+{SPR_MLNG,32770,1,A_WeaponReady,S_MLIGHTNINGREADY16,0,0},	// S_MLIGHTNINGREADY15
+{SPR_MLNG,32770,1,A_WeaponReady,S_MLIGHTNINGREADY17,0,0},	// S_MLIGHTNINGREADY16
+{SPR_MLNG,32770,1,A_WeaponReady,S_MLIGHTNINGREADY18,0,0},	// S_MLIGHTNINGREADY17
+{SPR_MLNG,32770,1,A_LightningReady,S_MLIGHTNINGREADY19,0,0},	// S_MLIGHTNINGREADY18
+{SPR_MLNG,32769,1,A_WeaponReady,S_MLIGHTNINGREADY20,0,0},	// S_MLIGHTNINGREADY19
+{SPR_MLNG,32769,1,A_WeaponReady,S_MLIGHTNINGREADY21,0,0},	// S_MLIGHTNINGREADY20
+{SPR_MLNG,32769,1,A_WeaponReady,S_MLIGHTNINGREADY22,0,0},	// S_MLIGHTNINGREADY21
+{SPR_MLNG,32769,1,A_WeaponReady,S_MLIGHTNINGREADY23,0,0},	// S_MLIGHTNINGREADY22
+{SPR_MLNG,32769,1,A_WeaponReady,S_MLIGHTNINGREADY24,0,0},	// S_MLIGHTNINGREADY23
+{SPR_MLNG,32769,1,A_WeaponReady,S_MLIGHTNINGREADY,0,0},	// S_MLIGHTNINGREADY24
+{SPR_MLNG,32768,1,A_Lower,S_MLIGHTNINGDOWN,0,0},	// S_MLIGHTNINGDOWN
+{SPR_MLNG,32768,1,A_Raise,S_MLIGHTNINGUP,0,0},	// S_MLIGHTNINGUP
+{SPR_MLNG,32771,3,NULL,S_MLIGHTNINGATK_2,0,0},	// S_MLIGHTNINGATK_1
+{SPR_MLNG,32772,3,NULL,S_MLIGHTNINGATK_3,0,0},	// S_MLIGHTNINGATK_2
+{SPR_MLNG,32773,4,A_MLightningAttack,S_MLIGHTNINGATK_4,0,0},	// S_MLIGHTNINGATK_3
+{SPR_MLNG,32774,4,NULL,S_MLIGHTNINGATK_5,0,0},	// S_MLIGHTNINGATK_4
+{SPR_MLNG,32775,3,NULL,S_MLIGHTNINGATK_6,0,0},	// S_MLIGHTNINGATK_5
+{SPR_MLNG,32776,3,NULL,S_MLIGHTNINGATK_7,0,0},	// S_MLIGHTNINGATK_6
+{SPR_MLNG,32776,6,NULL,S_MLIGHTNINGATK_8,0,199},	// S_MLIGHTNINGATK_7
+{SPR_MLNG,32770,2,NULL,S_MLIGHTNINGATK_9,0,55},	// S_MLIGHTNINGATK_8
+{SPR_MLNG,32769,2,NULL,S_MLIGHTNINGATK_10,0,50},	// S_MLIGHTNINGATK_9
+{SPR_MLNG,32769,2,NULL,S_MLIGHTNINGATK_11,0,45},	// S_MLIGHTNINGATK_10
+{SPR_MLNG,32769,2,NULL,S_MLIGHTNINGREADY,0,40},	// S_MLIGHTNINGATK_11
+{SPR_MLFX,32768,2,A_LightningZap,S_LIGHTNING_CEILING2,0,0},	// S_LIGHTNING_CEILING1
+{SPR_MLFX,32769,2,A_LightningClip,S_LIGHTNING_CEILING3,0,0},	// S_LIGHTNING_CEILING2
+{SPR_MLFX,32770,2,A_LightningClip,S_LIGHTNING_CEILING4,0,0},	// S_LIGHTNING_CEILING3
+{SPR_MLFX,32771,2,A_LightningClip,S_LIGHTNING_CEILING1,0,0},	// S_LIGHTNING_CEILING4
+{SPR_MLF2,32768,2,A_LightningRemove,S_LIGHTNING_C_X2,0,0},	// S_LIGHTNING_C_X1
+{SPR_MLF2,32769,3,NULL,S_LIGHTNING_C_X3,0,0},	// S_LIGHTNING_C_X2
+{SPR_MLF2,32770,3,NULL,S_LIGHTNING_C_X4,0,0},	// S_LIGHTNING_C_X3
+{SPR_MLF2,32771,3,NULL,S_LIGHTNING_C_X5,0,0},	// S_LIGHTNING_C_X4
+{SPR_MLF2,32772,3,NULL,S_LIGHTNING_C_X6,0,0},	// S_LIGHTNING_C_X5
+{SPR_MLF2,32778,3,NULL,S_LIGHTNING_C_X7,0,0},	// S_LIGHTNING_C_X6
+{SPR_MLF2,32779,3,NULL,S_LIGHTNING_C_X8,0,0},	// S_LIGHTNING_C_X7
+{SPR_MLF2,32780,3,NULL,S_LIGHTNING_C_X9,0,0},	// S_LIGHTNING_C_X8
+{SPR_ACLO,4,35,NULL,S_LIGHTNING_C_X10,0,0},	// S_LIGHTNING_C_X9
+{SPR_MLF2,32781,3,NULL,S_LIGHTNING_C_X11,0,0},	// S_LIGHTNING_C_X10
+{SPR_MLF2,32782,3,NULL,S_LIGHTNING_C_X12,0,0},	// S_LIGHTNING_C_X11
+{SPR_MLF2,32783,4,NULL,S_LIGHTNING_C_X13,0,0},	// S_LIGHTNING_C_X12
+{SPR_MLF2,32784,3,NULL,S_LIGHTNING_C_X14,0,0},	// S_LIGHTNING_C_X13
+{SPR_MLF2,32783,3,NULL,S_LIGHTNING_C_X15,0,0},	// S_LIGHTNING_C_X14
+{SPR_MLF2,32784,4,NULL,S_LIGHTNING_C_X16,0,0},	// S_LIGHTNING_C_X15
+{SPR_MLF2,32783,3,NULL,S_LIGHTNING_C_X17,0,0},	// S_LIGHTNING_C_X16
+{SPR_MLF2,32782,3,NULL,S_LIGHTNING_C_X18,0,0},	// S_LIGHTNING_C_X17
+{SPR_MLF2,32783,3,NULL,S_LIGHTNING_C_X19,0,0},	// S_LIGHTNING_C_X18
+{SPR_MLF2,32783,1,A_HideThing,S_FREETARGMOBJ,0,0},	// S_LIGHTNING_C_X19
+{SPR_MLFX,32772,2,A_LightningZap,S_LIGHTNING_FLOOR2,0,0},	// S_LIGHTNING_FLOOR1
+{SPR_MLFX,32773,2,A_LightningClip,S_LIGHTNING_FLOOR3,0,0},	// S_LIGHTNING_FLOOR2
+{SPR_MLFX,32774,2,A_LightningClip,S_LIGHTNING_FLOOR4,0,0},	// S_LIGHTNING_FLOOR3
+{SPR_MLFX,32775,2,A_LightningClip,S_LIGHTNING_FLOOR1,0,0},	// S_LIGHTNING_FLOOR4
+{SPR_MLF2,32773,2,A_LightningRemove,S_LIGHTNING_F_X2,0,0},	// S_LIGHTNING_F_X1
+{SPR_MLF2,32774,3,NULL,S_LIGHTNING_F_X3,0,0},	// S_LIGHTNING_F_X2
+{SPR_MLF2,32775,3,NULL,S_LIGHTNING_F_X4,0,0},	// S_LIGHTNING_F_X3
+{SPR_MLF2,32776,3,NULL,S_LIGHTNING_F_X5,0,0},	// S_LIGHTNING_F_X4
+{SPR_MLF2,32777,3,NULL,S_LIGHTNING_F_X6,0,0},	// S_LIGHTNING_F_X5
+{SPR_MLF2,32778,3,NULL,S_LIGHTNING_F_X7,0,0},	// S_LIGHTNING_F_X6
+{SPR_MLF2,32779,3,NULL,S_LIGHTNING_F_X8,0,0},	// S_LIGHTNING_F_X7
+{SPR_MLF2,32780,3,NULL,S_LIGHTNING_F_X9,0,0},	// S_LIGHTNING_F_X8
+{SPR_ACLO,4,20,NULL,S_LIGHTNING_F_X10,0,0},	// S_LIGHTNING_F_X9
+{SPR_MLF2,32781,3,NULL,S_LIGHTNING_F_X11,0,0},	// S_LIGHTNING_F_X10
+{SPR_MLF2,32782,3,NULL,S_LIGHTNING_F_X12,0,0},	// S_LIGHTNING_F_X11
+{SPR_MLF2,32783,4,NULL,S_LIGHTNING_F_X13,0,0},	// S_LIGHTNING_F_X12
+{SPR_MLF2,32784,3,NULL,S_LIGHTNING_F_X14,0,0},	// S_LIGHTNING_F_X13
+{SPR_MLF2,32783,3,NULL,S_LIGHTNING_F_X15,0,0},	// S_LIGHTNING_F_X14
+{SPR_MLF2,32784,4,A_LastZap,S_LIGHTNING_F_X16,0,0},	// S_LIGHTNING_F_X15
+{SPR_MLF2,32783,3,NULL,S_LIGHTNING_F_X17,0,0},	// S_LIGHTNING_F_X16
+{SPR_MLF2,32782,3,NULL,S_LIGHTNING_F_X18,0,0},	// S_LIGHTNING_F_X17
+{SPR_MLF2,32783,3,NULL,S_LIGHTNING_F_X19,0,0},	// S_LIGHTNING_F_X18
+{SPR_MLF2,32783,1,A_HideThing,S_FREETARGMOBJ,0,0},	// S_LIGHTNING_F_X19
+{SPR_MLFX,32776,2,A_ZapMimic,S_LIGHTNING_ZAP2,0,0},	// S_LIGHTNING_ZAP1
+{SPR_MLFX,32777,2,A_ZapMimic,S_LIGHTNING_ZAP3,0,0},	// S_LIGHTNING_ZAP2
+{SPR_MLFX,32778,2,A_ZapMimic,S_LIGHTNING_ZAP4,0,0},	// S_LIGHTNING_ZAP3
+{SPR_MLFX,32779,2,A_ZapMimic,S_LIGHTNING_ZAP5,0,0},	// S_LIGHTNING_ZAP4
+{SPR_MLFX,32780,2,A_ZapMimic,S_LIGHTNING_ZAP1,0,0},	// S_LIGHTNING_ZAP5
+{SPR_MLFX,32781,2,NULL,S_LIGHTNING_ZAP_X2,0,0},	// S_LIGHTNING_ZAP_X1
+{SPR_MLFX,32782,2,NULL,S_LIGHTNING_ZAP_X3,0,0},	// S_LIGHTNING_ZAP_X2
+{SPR_MLFX,32783,2,NULL,S_LIGHTNING_ZAP_X4,0,0},	// S_LIGHTNING_ZAP_X3
+{SPR_MLFX,32784,2,NULL,S_LIGHTNING_ZAP_X5,0,0},	// S_LIGHTNING_ZAP_X4
+{SPR_MLFX,32785,2,NULL,S_LIGHTNING_ZAP_X6,0,0},	// S_LIGHTNING_ZAP_X5
+{SPR_MLFX,32786,2,NULL,S_LIGHTNING_ZAP_X7,0,0},	// S_LIGHTNING_ZAP_X6
+{SPR_MLFX,32787,2,NULL,S_LIGHTNING_ZAP_X8,0,0},	// S_LIGHTNING_ZAP_X7
+{SPR_MLFX,32788,2,NULL,S_NULL,0,0},	// S_LIGHTNING_ZAP_X8
+{SPR_MSTF,0,1,A_WeaponReady,S_MSTAFFREADY2,0,0},	// S_MSTAFFREADY
+{SPR_MSTF,0,1,A_WeaponReady,S_MSTAFFREADY3,0,0},	// S_MSTAFFREADY2
+{SPR_MSTF,0,1,A_WeaponReady,S_MSTAFFREADY4,0,0},	// S_MSTAFFREADY3
+{SPR_MSTF,0,1,A_WeaponReady,S_MSTAFFREADY5,0,0},	// S_MSTAFFREADY4
+{SPR_MSTF,0,1,A_WeaponReady,S_MSTAFFREADY6,0,0},	// S_MSTAFFREADY5
+{SPR_MSTF,0,1,A_WeaponReady,S_MSTAFFREADY7,0,0},	// S_MSTAFFREADY6
+{SPR_MSTF,1,1,A_WeaponReady,S_MSTAFFREADY8,0,0},	// S_MSTAFFREADY7
+{SPR_MSTF,1,1,A_WeaponReady,S_MSTAFFREADY9,0,0},	// S_MSTAFFREADY8
+{SPR_MSTF,1,1,A_WeaponReady,S_MSTAFFREADY10,0,0},	// S_MSTAFFREADY9
+{SPR_MSTF,1,1,A_WeaponReady,S_MSTAFFREADY11,0,0},	// S_MSTAFFREADY10
+{SPR_MSTF,1,1,A_WeaponReady,S_MSTAFFREADY12,0,0},	// S_MSTAFFREADY11
+{SPR_MSTF,1,1,A_WeaponReady,S_MSTAFFREADY13,0,0},	// S_MSTAFFREADY12
+{SPR_MSTF,2,1,A_WeaponReady,S_MSTAFFREADY14,0,0},	// S_MSTAFFREADY13
+{SPR_MSTF,2,1,A_WeaponReady,S_MSTAFFREADY15,0,0},	// S_MSTAFFREADY14
+{SPR_MSTF,2,1,A_WeaponReady,S_MSTAFFREADY16,0,0},	// S_MSTAFFREADY15
+{SPR_MSTF,2,1,A_WeaponReady,S_MSTAFFREADY17,0,0},	// S_MSTAFFREADY16
+{SPR_MSTF,2,1,A_WeaponReady,S_MSTAFFREADY18,0,0},	// S_MSTAFFREADY17
+{SPR_MSTF,2,1,A_WeaponReady,S_MSTAFFREADY19,0,0},	// S_MSTAFFREADY18
+{SPR_MSTF,3,1,A_WeaponReady,S_MSTAFFREADY20,0,0},	// S_MSTAFFREADY19
+{SPR_MSTF,3,1,A_WeaponReady,S_MSTAFFREADY21,0,0},	// S_MSTAFFREADY20
+{SPR_MSTF,3,1,A_WeaponReady,S_MSTAFFREADY22,0,0},	// S_MSTAFFREADY21
+{SPR_MSTF,3,1,A_WeaponReady,S_MSTAFFREADY23,0,0},	// S_MSTAFFREADY22
+{SPR_MSTF,3,1,A_WeaponReady,S_MSTAFFREADY24,0,0},	// S_MSTAFFREADY23
+{SPR_MSTF,3,1,A_WeaponReady,S_MSTAFFREADY25,0,0},	// S_MSTAFFREADY24
+{SPR_MSTF,4,1,A_WeaponReady,S_MSTAFFREADY26,0,0},	// S_MSTAFFREADY25
+{SPR_MSTF,4,1,A_WeaponReady,S_MSTAFFREADY27,0,0},	// S_MSTAFFREADY26
+{SPR_MSTF,4,1,A_WeaponReady,S_MSTAFFREADY28,0,0},	// S_MSTAFFREADY27
+{SPR_MSTF,4,1,A_WeaponReady,S_MSTAFFREADY29,0,0},	// S_MSTAFFREADY28
+{SPR_MSTF,4,1,A_WeaponReady,S_MSTAFFREADY30,0,0},	// S_MSTAFFREADY29
+{SPR_MSTF,4,1,A_WeaponReady,S_MSTAFFREADY31,0,0},	// S_MSTAFFREADY30
+{SPR_MSTF,5,1,A_WeaponReady,S_MSTAFFREADY32,0,0},	// S_MSTAFFREADY31
+{SPR_MSTF,5,1,A_WeaponReady,S_MSTAFFREADY33,0,0},	// S_MSTAFFREADY32
+{SPR_MSTF,5,1,A_WeaponReady,S_MSTAFFREADY34,0,0},	// S_MSTAFFREADY33
+{SPR_MSTF,5,1,A_WeaponReady,S_MSTAFFREADY35,0,0},	// S_MSTAFFREADY34
+{SPR_MSTF,5,1,A_WeaponReady,S_MSTAFFREADY,0,0},	// S_MSTAFFREADY35
+{SPR_MSTF,0,1,A_Lower,S_MSTAFFDOWN,0,0},	// S_MSTAFFDOWN
+{SPR_MSTF,0,1,A_Raise,S_MSTAFFUP,0,0},	// S_MSTAFFUP
+{SPR_MSTF,6,4,NULL,S_MSTAFFATK_2,0,40},	// S_MSTAFFATK_1
+{SPR_MSTF,32775,4,A_MStaffAttack,S_MSTAFFATK_3,0,48},	// S_MSTAFFATK_2
+{SPR_MSTF,32775,2,A_MStaffPalette,S_MSTAFFATK_4,0,48},	// S_MSTAFFATK_3
+{SPR_MSTF,8,2,A_MStaffPalette,S_MSTAFFATK_5,0,48},	// S_MSTAFFATK_4
+{SPR_MSTF,8,2,A_MStaffPalette,S_MSTAFFATK_6,0,48},	// S_MSTAFFATK_5
+{SPR_MSTF,8,1,NULL,S_MSTAFFATK_7,0,40},	// S_MSTAFFATK_6
+{SPR_MSTF,9,5,NULL,S_MSTAFFREADY,0,36},	// S_MSTAFFATK_7
+{SPR_MSP1,32768,3,A_MStaffWeave,S_MSTAFF_FX1_2,0,0},	// S_MSTAFF_FX1_1
+{SPR_MSP1,32769,3,A_MStaffWeave,S_MSTAFF_FX1_3,0,0},	// S_MSTAFF_FX1_2
+{SPR_MSP1,32770,3,A_MStaffWeave,S_MSTAFF_FX1_4,0,0},	// S_MSTAFF_FX1_3
+{SPR_MSP1,32771,3,A_MStaffWeave,S_MSTAFF_FX1_5,0,0},	// S_MSTAFF_FX1_4
+{SPR_MSP1,32772,3,A_MStaffWeave,S_MSTAFF_FX1_6,0,0},	// S_MSTAFF_FX1_5
+{SPR_MSP1,32773,3,A_MStaffWeave,S_MSTAFF_FX1_1,0,0},	// S_MSTAFF_FX1_6
+{SPR_MSP1,32774,4,NULL,S_MSTAFF_FX_X2,0,0},	// S_MSTAFF_FX_X1
+{SPR_MSP1,32775,5,A_Explode,S_MSTAFF_FX_X3,0,0},	// S_MSTAFF_FX_X2
+{SPR_MSP1,32776,4,NULL,S_MSTAFF_FX_X4,0,0},	// S_MSTAFF_FX_X3
+{SPR_MSP1,32777,5,NULL,S_MSTAFF_FX_X5,0,0},	// S_MSTAFF_FX_X4
+{SPR_MSP1,32778,4,NULL,S_MSTAFF_FX_X6,0,0},	// S_MSTAFF_FX_X5
+{SPR_MSP1,32779,5,NULL,S_MSTAFF_FX_X7,0,0},	// S_MSTAFF_FX_X6
+{SPR_MSP1,32780,4,NULL,S_MSTAFF_FX_X8,0,0},	// S_MSTAFF_FX_X7
+{SPR_MSP1,32781,5,NULL,S_MSTAFF_FX_X9,0,0},	// S_MSTAFF_FX_X8
+{SPR_MSP1,32782,4,NULL,S_MSTAFF_FX_X10,0,0},	// S_MSTAFF_FX_X9
+{SPR_MSP1,32783,4,NULL,S_NULL,0,0},	// S_MSTAFF_FX_X10
+{SPR_MSP2,32768,2,A_MStaffTrack,S_MSTAFF_FX2_2,0,0},	// S_MSTAFF_FX2_1
+{SPR_MSP2,32769,2,A_MStaffTrack,S_MSTAFF_FX2_3,0,0},	// S_MSTAFF_FX2_2
+{SPR_MSP2,32770,2,A_MStaffTrack,S_MSTAFF_FX2_4,0,0},	// S_MSTAFF_FX2_3
+{SPR_MSP2,32771,2,A_MStaffTrack,S_MSTAFF_FX2_1,0,0},	// S_MSTAFF_FX2_4
+{SPR_MSP2,32772,4,NULL,S_MSTAFF_FX2_X2,0,0},	// S_MSTAFF_FX2_X1
+{SPR_MSP2,32773,5,A_Explode,S_MSTAFF_FX2_X3,0,0},	// S_MSTAFF_FX2_X2
+{SPR_MSP2,32774,5,NULL,S_MSTAFF_FX2_X4,0,0},	// S_MSTAFF_FX2_X3
+{SPR_MSP2,32775,5,NULL,S_MSTAFF_FX2_X5,0,0},	// S_MSTAFF_FX2_X4
+{SPR_MSP2,32776,4,NULL,S_NULL,0,0},	// S_MSTAFF_FX2_X5
+{SPR_WFR1,32768,-1,NULL,S_NULL,0,0},	// S_FSWORD1
+{SPR_WFR2,32768,-1,NULL,S_NULL,0,0},	// S_FSWORD2
+{SPR_WFR3,32768,-1,NULL,S_NULL,0,0},	// S_FSWORD3
+{SPR_WCH1,32768,-1,NULL,S_NULL,0,0},	// S_CHOLY1
+{SPR_WCH2,32768,-1,NULL,S_NULL,0,0},	// S_CHOLY2
+{SPR_WCH3,32768,-1,NULL,S_NULL,0,0},	// S_CHOLY3
+{SPR_WMS1,32768,-1,NULL,S_NULL,0,0},	// S_MSTAFF1
+{SPR_WMS2,32768,-1,NULL,S_NULL,0,0},	// S_MSTAFF2
+{SPR_WMS3,32768,-1,NULL,S_NULL,0,0},	// S_MSTAFF3
+{SPR_WPIG,0,1,A_WeaponReady,S_SNOUTREADY,0,0},	// S_SNOUTREADY
+{SPR_WPIG,0,1,A_Lower,S_SNOUTDOWN,0,0},	// S_SNOUTDOWN
+{SPR_WPIG,0,1,A_Raise,S_SNOUTUP,0,0},	// S_SNOUTUP
+{SPR_WPIG,0,4,A_SnoutAttack,S_SNOUTATK2,0,0},	// S_SNOUTATK1
+{SPR_WPIG,1,8,A_SnoutAttack,S_SNOUTREADY,0,0},	// S_SNOUTATK2
+{SPR_WMCS,32768,8,NULL,S_COS2,0,0},	// S_COS1
+{SPR_WMCS,32769,8,NULL,S_COS3,0,0},	// S_COS2
+{SPR_WMCS,32770,8,NULL,S_COS1,0,0},	// S_COS3
+{SPR_CONE,0,1,A_WeaponReady,S_CONEREADY,0,0},	// S_CONEREADY
+{SPR_CONE,0,1,A_Lower,S_CONEDOWN,0,0},	// S_CONEDOWN
+{SPR_CONE,0,1,A_Raise,S_CONEUP,0,0},	// S_CONEUP
+{SPR_CONE,1,3,NULL,S_CONEATK1_2,0,0},	// S_CONEATK1_1
+{SPR_CONE,2,4,NULL,S_CONEATK1_3,0,0},	// S_CONEATK1_2
+{SPR_CONE,3,3,NULL,S_CONEATK1_4,0,0},	// S_CONEATK1_3
+{SPR_CONE,4,5,NULL,S_CONEATK1_5,0,0},	// S_CONEATK1_4
+{SPR_CONE,5,3,A_FireConePL1,S_CONEATK1_6,0,0},	// S_CONEATK1_5
+{SPR_CONE,6,3,NULL,S_CONEATK1_7,0,0},	// S_CONEATK1_6
+{SPR_CONE,0,9,NULL,S_CONEATK1_8,0,0},	// S_CONEATK1_7
+{SPR_CONE,0,10,A_ReFire,S_CONEREADY,0,0},	// S_CONEATK1_8
+{SPR_SHRD,32768,2,NULL,S_SHARDFX1_2,0,0},	// S_SHARDFX1_1
+{SPR_SHRD,32768,3,A_ShedShard,S_SHARDFX1_3,0,0},	// S_SHARDFX1_2
+{SPR_SHRD,32769,3,NULL,S_SHARDFX1_4,0,0},	// S_SHARDFX1_3
+{SPR_SHRD,32770,3,NULL,S_SHARDFX1_1,0,0},	// S_SHARDFX1_4
+{SPR_SHEX,32768,5,NULL,S_SHARDFXE1_2,0,0},	// S_SHARDFXE1_1
+{SPR_SHEX,32769,5,NULL,S_SHARDFXE1_3,0,0},	// S_SHARDFXE1_2
+{SPR_SHEX,32770,5,NULL,S_SHARDFXE1_4,0,0},	// S_SHARDFXE1_3
+{SPR_SHEX,32771,5,NULL,S_SHARDFXE1_5,0,0},	// S_SHARDFXE1_4
+{SPR_SHEX,32772,5,NULL,S_NULL,0,0},	// S_SHARDFXE1_5
+{SPR_BLOD,2,8,NULL,S_BLOOD2,0,0},	// S_BLOOD1
+{SPR_BLOD,1,8,NULL,S_BLOOD3,0,0},	// S_BLOOD2
+{SPR_BLOD,0,8,NULL,S_NULL,0,0},	// S_BLOOD3
+{SPR_BLOD,2,8,NULL,S_BLOODSPLATTER2,0,0},	// S_BLOODSPLATTER1
+{SPR_BLOD,1,8,NULL,S_BLOODSPLATTER3,0,0},	// S_BLOODSPLATTER2
+{SPR_BLOD,0,8,NULL,S_NULL,0,0},	// S_BLOODSPLATTER3
+{SPR_BLOD,0,6,NULL,S_NULL,0,0},	// S_BLOODSPLATTERX
+{SPR_GIBS,0,-1,NULL,S_NULL,0,0},	// S_GIBS1
+{SPR_PLAY,0,-1,NULL,S_NULL,0,0},	// S_FPLAY
+{SPR_PLAY,0,4,NULL,S_FPLAY_RUN2,0,0},	// S_FPLAY_RUN1
+{SPR_PLAY,1,4,NULL,S_FPLAY_RUN3,0,0},	// S_FPLAY_RUN2
+{SPR_PLAY,2,4,NULL,S_FPLAY_RUN4,0,0},	// S_FPLAY_RUN3
+{SPR_PLAY,3,4,NULL,S_FPLAY_RUN1,0,0},	// S_FPLAY_RUN4
+{SPR_PLAY,4,8,NULL,S_FPLAY_ATK2,0,0},	// S_FPLAY_ATK1
+{SPR_PLAY,5,8,NULL,S_FPLAY,0,0},	// S_FPLAY_ATK2
+{SPR_PLAY,6,4,NULL,S_FPLAY_PAIN2,0,0},	// S_FPLAY_PAIN
+{SPR_PLAY,6,4,A_Pain,S_FPLAY,0,0},	// S_FPLAY_PAIN2
+{SPR_PLAY,7,6,NULL,S_FPLAY_DIE2,0,0},	// S_FPLAY_DIE1
+{SPR_PLAY,8,6,A_Scream,S_FPLAY_DIE3,0,0},	// S_FPLAY_DIE2
+{SPR_PLAY,9,6,NULL,S_FPLAY_DIE4,0,0},	// S_FPLAY_DIE3
+{SPR_PLAY,10,6,NULL,S_FPLAY_DIE5,0,0},	// S_FPLAY_DIE4
+{SPR_PLAY,11,6,A_NoBlocking,S_FPLAY_DIE6,0,0},	// S_FPLAY_DIE5
+{SPR_PLAY,12,6,NULL,S_FPLAY_DIE7,0,0},	// S_FPLAY_DIE6
+{SPR_PLAY,13,-1,A_AddPlayerCorpse,S_NULL,0,0},	// S_FPLAY_DIE7
+{SPR_PLAY,14,5,A_Scream,S_FPLAY_XDIE2,0,0},	// S_FPLAY_XDIE1
+{SPR_PLAY,15,5,A_SkullPop,S_FPLAY_XDIE3,0,0},	// S_FPLAY_XDIE2
+{SPR_PLAY,17,5,A_NoBlocking,S_FPLAY_XDIE4,0,0},	// S_FPLAY_XDIE3
+{SPR_PLAY,18,5,NULL,S_FPLAY_XDIE5,0,0},	// S_FPLAY_XDIE4
+{SPR_PLAY,19,5,NULL,S_FPLAY_XDIE6,0,0},	// S_FPLAY_XDIE5
+{SPR_PLAY,20,5,NULL,S_FPLAY_XDIE7,0,0},	// S_FPLAY_XDIE6
+{SPR_PLAY,21,5,NULL,S_FPLAY_XDIE8,0,0},	// S_FPLAY_XDIE7
+{SPR_PLAY,22,-1,A_AddPlayerCorpse,S_NULL,0,0},	// S_FPLAY_XDIE8
+{SPR_PLAY,23,5,A_FreezeDeath,S_FPLAY_ICE2,0,0},	// S_FPLAY_ICE
+{SPR_PLAY,23,1,A_FreezeDeathChunks,S_FPLAY_ICE2,0,0},	// S_FPLAY_ICE2
+{SPR_FDTH,32768,5,NULL,S_PLAY_F_FDTH2,0,0},	// S_PLAY_F_FDTH1
+{SPR_FDTH,32769,4,NULL,S_PLAY_FDTH3,0,0},	// S_PLAY_F_FDTH2
+{SPR_FDTH,32770,5,NULL,S_PLAY_C_FDTH2,0,0},	// S_PLAY_C_FDTH1
+{SPR_FDTH,32771,4,NULL,S_PLAY_FDTH3,0,0},	// S_PLAY_C_FDTH2
+{SPR_FDTH,32772,5,NULL,S_PLAY_M_FDTH2,0,0},	// S_PLAY_M_FDTH1
+{SPR_FDTH,32773,4,NULL,S_PLAY_FDTH3,0,0},	// S_PLAY_M_FDTH2
+{SPR_FDTH,32774,5,NULL,S_PLAY_FDTH4,0,0},	// S_PLAY_FDTH3
+{SPR_FDTH,32775,4,A_Scream,S_PLAY_FDTH5,0,0},	// S_PLAY_FDTH4
+{SPR_FDTH,32776,5,NULL,S_PLAY_FDTH6,0,0},	// S_PLAY_FDTH5
+{SPR_FDTH,32777,4,NULL,S_PLAY_FDTH7,0,0},	// S_PLAY_FDTH6
+{SPR_FDTH,32778,5,NULL,S_PLAY_FDTH8,0,0},	// S_PLAY_FDTH7
+{SPR_FDTH,32779,4,NULL,S_PLAY_FDTH9,0,0},	// S_PLAY_FDTH8
+{SPR_FDTH,32780,5,NULL,S_PLAY_FDTH10,0,0},	// S_PLAY_FDTH9
+{SPR_FDTH,32781,4,NULL,S_PLAY_FDTH11,0,0},	// S_PLAY_FDTH10
+{SPR_FDTH,32782,5,NULL,S_PLAY_FDTH12,0,0},	// S_PLAY_FDTH11
+{SPR_FDTH,32783,4,NULL,S_PLAY_FDTH13,0,0},	// S_PLAY_FDTH12
+{SPR_FDTH,32784,5,NULL,S_PLAY_FDTH14,0,0},	// S_PLAY_FDTH13
+{SPR_FDTH,32785,4,NULL,S_PLAY_FDTH15,0,0},	// S_PLAY_FDTH14
+{SPR_FDTH,32786,5,A_NoBlocking,S_PLAY_FDTH16,0,0},	// S_PLAY_FDTH15
+{SPR_FDTH,32787,4,NULL,S_PLAY_FDTH17,0,0},	// S_PLAY_FDTH16
+{SPR_FDTH,32788,5,NULL,S_PLAY_FDTH18,0,0},	// S_PLAY_FDTH17
+{SPR_FDTH,32789,4,NULL,S_PLAY_FDTH19,0,0},	// S_PLAY_FDTH18
+{SPR_ACLO,4,35,A_CheckBurnGone,S_PLAY_FDTH19,0,0},	// S_PLAY_FDTH19
+{SPR_ACLO,4,8,NULL,S_NULL,0,0},	// S_PLAY_FDTH20
+{SPR_BSKL,0,5,A_CheckSkullFloor,S_BLOODYSKULL2,0,0},	// S_BLOODYSKULL1
+{SPR_BSKL,1,5,A_CheckSkullFloor,S_BLOODYSKULL3,0,0},	// S_BLOODYSKULL2
+{SPR_BSKL,2,5,A_CheckSkullFloor,S_BLOODYSKULL4,0,0},	// S_BLOODYSKULL3
+{SPR_BSKL,3,5,A_CheckSkullFloor,S_BLOODYSKULL5,0,0},	// S_BLOODYSKULL4
+{SPR_BSKL,5,5,A_CheckSkullFloor,S_BLOODYSKULL6,0,0},	// S_BLOODYSKULL5
+{SPR_BSKL,6,5,A_CheckSkullFloor,S_BLOODYSKULL7,0,0},	// S_BLOODYSKULL6
+{SPR_BSKL,7,5,A_CheckSkullFloor,S_BLOODYSKULL1,0,0},	// S_BLOODYSKULL7
+{SPR_BSKL,8,16,A_CheckSkullDone,S_BLOODYSKULLX1,0,0},	// S_BLOODYSKULLX1
+{SPR_BSKL,8,1050,NULL,S_NULL,0,0},	// S_BLOODYSKULLX2
+{SPR_PLAY,0,5,NULL,S_PLAYER_SPEED2,0,0},	// S_PLAYER_SPEED1
+{SPR_PLAY,0,3,A_SpeedFade,S_NULL,0,0},	// S_PLAYER_SPEED2
+{SPR_ICEC,0,10,NULL,S_ICECHUNK2,0,0},	// S_ICECHUNK1
+{SPR_ICEC,1,10,A_IceSetTics,S_ICECHUNK3,0,0},	// S_ICECHUNK2
+{SPR_ICEC,2,10,A_IceSetTics,S_ICECHUNK4,0,0},	// S_ICECHUNK3
+{SPR_ICEC,3,10,A_IceSetTics,S_NULL,0,0},	// S_ICECHUNK4
+{SPR_ICEC,0,10,A_IceCheckHeadDone,S_ICECHUNK_HEAD,0,0},	// S_ICECHUNK_HEAD
+{SPR_ICEC,0,1050,NULL,S_NULL,0,0},	// S_ICECHUNK_HEAD2
+{SPR_CLER,0,-1,NULL,S_NULL,0,0},	// S_CPLAY
+{SPR_CLER,0,4,NULL,S_CPLAY_RUN2,0,0},	// S_CPLAY_RUN1
+{SPR_CLER,1,4,NULL,S_CPLAY_RUN3,0,0},	// S_CPLAY_RUN2
+{SPR_CLER,2,4,NULL,S_CPLAY_RUN4,0,0},	// S_CPLAY_RUN3
+{SPR_CLER,3,4,NULL,S_CPLAY_RUN1,0,0},	// S_CPLAY_RUN4
+{SPR_CLER,4,6,NULL,S_CPLAY_ATK2,0,0},	// S_CPLAY_ATK1
+{SPR_CLER,5,6,NULL,S_CPLAY_ATK3,0,0},	// S_CPLAY_ATK2
+{SPR_CLER,6,6,NULL,S_CPLAY,0,0},	// S_CPLAY_ATK3
+{SPR_CLER,7,4,NULL,S_CPLAY_PAIN2,0,0},	// S_CPLAY_PAIN
+{SPR_CLER,7,4,A_Pain,S_CPLAY,0,0},	// S_CPLAY_PAIN2
+{SPR_CLER,8,6,NULL,S_CPLAY_DIE2,0,0},	// S_CPLAY_DIE1
+{SPR_CLER,10,6,A_Scream,S_CPLAY_DIE3,0,0},	// S_CPLAY_DIE2
+{SPR_CLER,11,6,NULL,S_CPLAY_DIE4,0,0},	// S_CPLAY_DIE3
+{SPR_CLER,11,6,NULL,S_CPLAY_DIE5,0,0},	// S_CPLAY_DIE4
+{SPR_CLER,12,6,A_NoBlocking,S_CPLAY_DIE6,0,0},	// S_CPLAY_DIE5
+{SPR_CLER,13,6,NULL,S_CPLAY_DIE7,0,0},	// S_CPLAY_DIE6
+{SPR_CLER,14,6,NULL,S_CPLAY_DIE8,0,0},	// S_CPLAY_DIE7
+{SPR_CLER,15,6,NULL,S_CPLAY_DIE9,0,0},	// S_CPLAY_DIE8
+{SPR_CLER,16,-1,A_AddPlayerCorpse,S_NULL,0,0},	// S_CPLAY_DIE9
+{SPR_CLER,17,5,A_Scream,S_CPLAY_XDIE2,0,0},	// S_CPLAY_XDIE1
+{SPR_CLER,18,5,NULL,S_CPLAY_XDIE3,0,0},	// S_CPLAY_XDIE2
+{SPR_CLER,19,5,A_NoBlocking,S_CPLAY_XDIE4,0,0},	// S_CPLAY_XDIE3
+{SPR_CLER,20,5,NULL,S_CPLAY_XDIE5,0,0},	// S_CPLAY_XDIE4
+{SPR_CLER,21,5,NULL,S_CPLAY_XDIE6,0,0},	// S_CPLAY_XDIE5
+{SPR_CLER,22,5,NULL,S_CPLAY_XDIE7,0,0},	// S_CPLAY_XDIE6
+{SPR_CLER,23,5,NULL,S_CPLAY_XDIE8,0,0},	// S_CPLAY_XDIE7
+{SPR_CLER,24,5,NULL,S_CPLAY_XDIE9,0,0},	// S_CPLAY_XDIE8
+{SPR_CLER,25,5,NULL,S_CPLAY_XDIE10,0,0},	// S_CPLAY_XDIE9
+{SPR_CLER,26,-1,A_AddPlayerCorpse,S_NULL,0,0},	// S_CPLAY_XDIE10
+{SPR_CLER,27,5,A_FreezeDeath,S_CPLAY_ICE2,0,0},	// S_CPLAY_ICE
+{SPR_CLER,27,1,A_FreezeDeathChunks,S_CPLAY_ICE2,0,0},	// S_CPLAY_ICE2
+{SPR_MAGE,0,-1,NULL,S_NULL,0,0},	// S_MPLAY
+{SPR_MAGE,0,4,NULL,S_MPLAY_RUN2,0,0},	// S_MPLAY_RUN1
+{SPR_MAGE,1,4,NULL,S_MPLAY_RUN3,0,0},	// S_MPLAY_RUN2
+{SPR_MAGE,2,4,NULL,S_MPLAY_RUN4,0,0},	// S_MPLAY_RUN3
+{SPR_MAGE,3,4,NULL,S_MPLAY_RUN1,0,0},	// S_MPLAY_RUN4
+{SPR_MAGE,4,8,NULL,S_MPLAY_ATK2,0,0},	// S_MPLAY_ATK1
+{SPR_MAGE,32773,8,NULL,S_MPLAY,0,0},	// S_MPLAY_ATK2
+{SPR_MAGE,6,4,NULL,S_MPLAY_PAIN2,0,0},	// S_MPLAY_PAIN
+{SPR_MAGE,6,4,A_Pain,S_MPLAY,0,0},	// S_MPLAY_PAIN2
+{SPR_MAGE,7,6,NULL,S_MPLAY_DIE2,0,0},	// S_MPLAY_DIE1
+{SPR_MAGE,8,6,A_Scream,S_MPLAY_DIE3,0,0},	// S_MPLAY_DIE2
+{SPR_MAGE,9,6,NULL,S_MPLAY_DIE4,0,0},	// S_MPLAY_DIE3
+{SPR_MAGE,10,6,NULL,S_MPLAY_DIE5,0,0},	// S_MPLAY_DIE4
+{SPR_MAGE,11,6,A_NoBlocking,S_MPLAY_DIE6,0,0},	// S_MPLAY_DIE5
+{SPR_MAGE,12,6,NULL,S_MPLAY_DIE7,0,0},	// S_MPLAY_DIE6
+{SPR_MAGE,13,-1,A_AddPlayerCorpse,S_NULL,0,0},	// S_MPLAY_DIE7
+{SPR_MAGE,14,5,A_Scream,S_MPLAY_XDIE2,0,0},	// S_MPLAY_XDIE1
+{SPR_MAGE,15,5,NULL,S_MPLAY_XDIE3,0,0},	// S_MPLAY_XDIE2
+{SPR_MAGE,17,5,A_NoBlocking,S_MPLAY_XDIE4,0,0},	// S_MPLAY_XDIE3
+{SPR_MAGE,18,5,NULL,S_MPLAY_XDIE5,0,0},	// S_MPLAY_XDIE4
+{SPR_MAGE,19,5,NULL,S_MPLAY_XDIE6,0,0},	// S_MPLAY_XDIE5
+{SPR_MAGE,20,5,NULL,S_MPLAY_XDIE7,0,0},	// S_MPLAY_XDIE6
+{SPR_MAGE,21,5,NULL,S_MPLAY_XDIE8,0,0},	// S_MPLAY_XDIE7
+{SPR_MAGE,22,5,NULL,S_MPLAY_XDIE9,0,0},	// S_MPLAY_XDIE8
+{SPR_MAGE,23,-1,A_AddPlayerCorpse,S_NULL,0,0},	// S_MPLAY_XDIE9
+{SPR_MAGE,24,5,A_FreezeDeath,S_MPLAY_ICE2,0,0},	// S_MPLAY_ICE
+{SPR_MAGE,24,1,A_FreezeDeathChunks,S_MPLAY_ICE2,0,0},	// S_MPLAY_ICE2
+{SPR_PIGY,0,-1,NULL,S_NULL,0,0},	// S_PIGPLAY
+{SPR_PIGY,0,3,NULL,S_PIGPLAY_RUN2,0,0},	// S_PIGPLAY_RUN1
+{SPR_PIGY,1,3,NULL,S_PIGPLAY_RUN3,0,0},	// S_PIGPLAY_RUN2
+{SPR_PIGY,2,3,NULL,S_PIGPLAY_RUN4,0,0},	// S_PIGPLAY_RUN3
+{SPR_PIGY,3,3,NULL,S_PIGPLAY_RUN1,0,0},	// S_PIGPLAY_RUN4
+{SPR_PIGY,0,12,NULL,S_PIGPLAY,0,0},	// S_PIGPLAY_ATK1
+{SPR_PIGY,3,4,A_PigPain,S_PIGPLAY,0,0},	// S_PIGPLAY_PAIN
+{SPR_PIGY,1,10,A_PigLook,S_PIG_LOOK1,0,0},	// S_PIG_LOOK1
+{SPR_PIGY,0,3,A_PigChase,S_PIG_WALK2,0,0},	// S_PIG_WALK1
+{SPR_PIGY,1,3,A_PigChase,S_PIG_WALK3,0,0},	// S_PIG_WALK2
+{SPR_PIGY,2,3,A_PigChase,S_PIG_WALK4,0,0},	// S_PIG_WALK3
+{SPR_PIGY,3,3,A_PigChase,S_PIG_WALK1,0,0},	// S_PIG_WALK4
+{SPR_PIGY,3,4,A_PigPain,S_PIG_WALK1,0,0},	// S_PIG_PAIN
+{SPR_PIGY,0,5,A_FaceTarget,S_PIG_ATK2,0,0},	// S_PIG_ATK1
+{SPR_PIGY,0,10,A_PigAttack,S_PIG_WALK1,0,0},	// S_PIG_ATK2
+{SPR_PIGY,4,4,A_Scream,S_PIG_DIE2,0,0},	// S_PIG_DIE1
+{SPR_PIGY,5,3,A_NoBlocking,S_PIG_DIE3,0,0},	// S_PIG_DIE2
+{SPR_PIGY,6,4,A_QueueCorpse,S_PIG_DIE4,0,0},	// S_PIG_DIE3
+{SPR_PIGY,7,3,NULL,S_PIG_DIE5,0,0},	// S_PIG_DIE4
+{SPR_PIGY,8,4,NULL,S_PIG_DIE6,0,0},	// S_PIG_DIE5
+{SPR_PIGY,9,4,NULL,S_PIG_DIE7,0,0},	// S_PIG_DIE6
+{SPR_PIGY,10,4,NULL,S_PIG_DIE8,0,0},	// S_PIG_DIE7
+{SPR_PIGY,11,-1,NULL,S_NULL,0,0},	// S_PIG_DIE8
+{SPR_PIGY,12,5,A_FreezeDeath,S_PIG_ICE2,0,0},	// S_PIG_ICE
+{SPR_PIGY,12,1,A_FreezeDeathChunks,S_PIG_ICE2,0,0},	// S_PIG_ICE2
+{SPR_CENT,0,10,A_Look,S_CENTAUR_LOOK2,0,0},	// S_CENTAUR_LOOK1
+{SPR_CENT,1,10,A_Look,S_CENTAUR_LOOK1,0,0},	// S_CENTAUR_LOOK2
+{SPR_CENT,0,4,A_Chase,S_CENTAUR_WALK2,0,0},	// S_CENTAUR_WALK1
+{SPR_CENT,1,4,A_Chase,S_CENTAUR_WALK3,0,0},	// S_CENTAUR_WALK2
+{SPR_CENT,2,4,A_Chase,S_CENTAUR_WALK4,0,0},	// S_CENTAUR_WALK3
+{SPR_CENT,3,4,A_Chase,S_CENTAUR_WALK1,0,0},	// S_CENTAUR_WALK4
+{SPR_CENT,7,5,A_FaceTarget,S_CENTAUR_ATK2,0,0},	// S_CENTAUR_ATK1
+{SPR_CENT,8,4,A_FaceTarget,S_CENTAUR_ATK3,0,0},	// S_CENTAUR_ATK2
+{SPR_CENT,9,7,A_CentaurAttack,S_CENTAUR_WALK1,0,0},	// S_CENTAUR_ATK3
+{SPR_CENT,4,10,A_FaceTarget,S_CENTAUR_MISSILE2,0,0},	// S_CENTAUR_MISSILE1
+{SPR_CENT,32773,8,A_CentaurAttack2,S_CENTAUR_MISSILE3,0,0},	// S_CENTAUR_MISSILE2
+{SPR_CENT,4,10,A_FaceTarget,S_CENTAUR_MISSILE4,0,0},	// S_CENTAUR_MISSILE3
+{SPR_CENT,32773,8,A_CentaurAttack2,S_CENTAUR_WALK1,0,0},	// S_CENTAUR_MISSILE4
+{SPR_CENT,6,6,A_Pain,S_CENTAUR_PAIN2,0,0},	// S_CENTAUR_PAIN1
+{SPR_CENT,6,6,A_SetReflective,S_CENTAUR_PAIN3,0,0},	// S_CENTAUR_PAIN2
+{SPR_CENT,4,15,A_CentaurDefend,S_CENTAUR_PAIN4,0,0},	// S_CENTAUR_PAIN3
+{SPR_CENT,4,15,A_CentaurDefend,S_CENTAUR_PAIN5,0,0},	// S_CENTAUR_PAIN4
+{SPR_CENT,4,15,A_CentaurDefend,S_CENTAUR_PAIN6,0,0},	// S_CENTAUR_PAIN5
+{SPR_CENT,4,1,A_UnSetReflective,S_CENTAUR_WALK1,0,0},	// S_CENTAUR_PAIN6
+{SPR_CENT,10,4,NULL,S_CENTAUR_DEATH2,0,0},	// S_CENTAUR_DEATH1
+{SPR_CENT,11,4,A_Scream,S_CENTAUR_DEATH3,0,0},	// S_CENTAUR_DEATH2
+{SPR_CENT,12,4,NULL,S_CENTAUR_DEATH4,0,0},	// S_CENTAUR_DEATH3
+{SPR_CENT,13,4,NULL,S_CENTAUR_DEATH5,0,0},	// S_CENTAUR_DEATH4
+{SPR_CENT,14,4,A_NoBlocking,S_CENTAUR_DEATH6,0,0},	// S_CENTAUR_DEATH5
+{SPR_CENT,15,4,NULL,S_CENTAUR_DEATH7,0,0},	// S_CENTAUR_DEATH6
+{SPR_CENT,16,4,NULL,S_CENTAUR_DEATH8,0,0},	// S_CENTAUR_DEATH7
+{SPR_CENT,17,4,A_QueueCorpse,S_CENTAUR_DEATH9,0,0},	// S_CENTAUR_DEATH8
+{SPR_CENT,18,4,NULL,S_CENTAUR_DEATH0,0,0},	// S_CENTAUR_DEATH9
+{SPR_CENT,19,-1,NULL,S_NULL,0,0},	// S_CENTAUR_DEATH0
+{SPR_CTXD,0,4,NULL,S_CENTAUR_DEATH_X2,0,0},	// S_CENTAUR_DEATH_X1
+{SPR_CTXD,1,4,A_NoBlocking,S_CENTAUR_DEATH_X3,0,0},	// S_CENTAUR_DEATH_X2
+{SPR_CTXD,2,4,A_CentaurDropStuff,S_CENTAUR_DEATH_X4,0,0},	// S_CENTAUR_DEATH_X3
+{SPR_CTXD,3,3,A_Scream,S_CENTAUR_DEATH_X5,0,0},	// S_CENTAUR_DEATH_X4
+{SPR_CTXD,4,4,A_QueueCorpse,S_CENTAUR_DEATH_X6,0,0},	// S_CENTAUR_DEATH_X5
+{SPR_CTXD,5,3,NULL,S_CENTAUR_DEATH_X7,0,0},	// S_CENTAUR_DEATH_X6
+{SPR_CTXD,6,4,NULL,S_CENTAUR_DEATH_X8,0,0},	// S_CENTAUR_DEATH_X7
+{SPR_CTXD,7,3,NULL,S_CENTAUR_DEATH_X9,0,0},	// S_CENTAUR_DEATH_X8
+{SPR_CTXD,8,4,NULL,S_CENTAUR_DEATH_X10,0,0},	// S_CENTAUR_DEATH_X9
+{SPR_CTXD,9,3,NULL,S_CENTAUR_DEATH_X11,0,0},	// S_CENTAUR_DEATH_X10
+{SPR_CTXD,10,-1,NULL,S_NULL,0,0},	// S_CENTAUR_DEATH_X11
+{SPR_CENT,20,5,A_FreezeDeath,S_CENTAUR_ICE2,0,0},	// S_CENTAUR_ICE
+{SPR_CENT,20,1,A_FreezeDeathChunks,S_CENTAUR_ICE2,0,0},	// S_CENTAUR_ICE2
+{SPR_CTFX,32768,-1,NULL,S_NULL,0,0},	// S_CENTAUR_FX1
+{SPR_CTFX,32769,4,NULL,S_CENTAUR_FX_X2,0,0},	// S_CENTAUR_FX_X1
+{SPR_CTFX,32770,3,NULL,S_CENTAUR_FX_X3,0,0},	// S_CENTAUR_FX_X2
+{SPR_CTFX,32771,4,NULL,S_CENTAUR_FX_X4,0,0},	// S_CENTAUR_FX_X3
+{SPR_CTFX,32772,3,NULL,S_CENTAUR_FX_X5,0,0},	// S_CENTAUR_FX_X4
+{SPR_CTFX,32773,2,NULL,S_NULL,0,0},	// S_CENTAUR_FX_X5
+{SPR_CTDP,0,3,A_CheckFloor,S_CENTAUR_SHIELD2,0,0},	// S_CENTAUR_SHIELD1
+{SPR_CTDP,1,3,A_CheckFloor,S_CENTAUR_SHIELD3,0,0},	// S_CENTAUR_SHIELD2
+{SPR_CTDP,2,3,A_CheckFloor,S_CENTAUR_SHIELD4,0,0},	// S_CENTAUR_SHIELD3
+{SPR_CTDP,3,3,A_CheckFloor,S_CENTAUR_SHIELD5,0,0},	// S_CENTAUR_SHIELD4
+{SPR_CTDP,4,3,A_CheckFloor,S_CENTAUR_SHIELD6,0,0},	// S_CENTAUR_SHIELD5
+{SPR_CTDP,5,3,A_CheckFloor,S_CENTAUR_SHIELD3,0,0},	// S_CENTAUR_SHIELD6
+{SPR_CTDP,6,4,NULL,S_CENTAUR_SHIELD_X2,0,0},	// S_CENTAUR_SHIELD_X1
+{SPR_CTDP,7,4,A_QueueCorpse,S_CENTAUR_SHIELD_X3,0,0},	// S_CENTAUR_SHIELD_X2
+{SPR_CTDP,8,4,NULL,S_CENTAUR_SHIELD_X4,0,0},	// S_CENTAUR_SHIELD_X3
+{SPR_CTDP,9,-1,NULL,S_NULL,0,0},	// S_CENTAUR_SHIELD_X4
+{SPR_CTDP,10,3,A_CheckFloor,S_CENTAUR_SWORD2,0,0},	// S_CENTAUR_SWORD1
+{SPR_CTDP,11,3,A_CheckFloor,S_CENTAUR_SWORD3,0,0},	// S_CENTAUR_SWORD2
+{SPR_CTDP,12,3,A_CheckFloor,S_CENTAUR_SWORD4,0,0},	// S_CENTAUR_SWORD3
+{SPR_CTDP,13,3,A_CheckFloor,S_CENTAUR_SWORD5,0,0},	// S_CENTAUR_SWORD4
+{SPR_CTDP,14,3,A_CheckFloor,S_CENTAUR_SWORD6,0,0},	// S_CENTAUR_SWORD5
+{SPR_CTDP,15,3,A_CheckFloor,S_CENTAUR_SWORD7,0,0},	// S_CENTAUR_SWORD6
+{SPR_CTDP,16,3,A_CheckFloor,S_CENTAUR_SWORD3,0,0},	// S_CENTAUR_SWORD7
+{SPR_CTDP,17,4,NULL,S_CENTAUR_SWORD_X2,0,0},	// S_CENTAUR_SWORD_X1
+{SPR_CTDP,18,4,A_QueueCorpse,S_CENTAUR_SWORD_X3,0,0},	// S_CENTAUR_SWORD_X2
+{SPR_CTDP,19,-1,NULL,S_NULL,0,0},	// S_CENTAUR_SWORD_X3
+{SPR_DEMN,0,10,A_Look,S_DEMN_LOOK2,0,0},	// S_DEMN_LOOK1
+{SPR_DEMN,0,10,A_Look,S_DEMN_LOOK1,0,0},	// S_DEMN_LOOK2
+{SPR_DEMN,0,4,A_Chase,S_DEMN_CHASE2,0,0},	// S_DEMN_CHASE1
+{SPR_DEMN,1,4,A_Chase,S_DEMN_CHASE3,0,0},	// S_DEMN_CHASE2
+{SPR_DEMN,2,4,A_Chase,S_DEMN_CHASE4,0,0},	// S_DEMN_CHASE3
+{SPR_DEMN,3,4,A_Chase,S_DEMN_CHASE1,0,0},	// S_DEMN_CHASE4
+{SPR_DEMN,4,6,A_FaceTarget,S_DEMN_ATK1_2,0,0},	// S_DEMN_ATK1_1
+{SPR_DEMN,5,8,A_FaceTarget,S_DEMN_ATK1_3,0,0},	// S_DEMN_ATK1_2
+{SPR_DEMN,6,6,A_DemonAttack1,S_DEMN_CHASE1,0,0},	// S_DEMN_ATK1_3
+{SPR_DEMN,4,5,A_FaceTarget,S_DEMN_ATK2_2,0,0},	// S_DEMN_ATK2_1
+{SPR_DEMN,5,6,A_FaceTarget,S_DEMN_ATK2_3,0,0},	// S_DEMN_ATK2_2
+{SPR_DEMN,6,5,A_DemonAttack2,S_DEMN_CHASE1,0,0},	// S_DEMN_ATK2_3
+{SPR_DEMN,4,4,NULL,S_DEMN_PAIN2,0,0},	// S_DEMN_PAIN1
+{SPR_DEMN,4,4,A_Pain,S_DEMN_CHASE1,0,0},	// S_DEMN_PAIN2
+{SPR_DEMN,7,6,NULL,S_DEMN_DEATH2,0,0},	// S_DEMN_DEATH1
+{SPR_DEMN,8,6,NULL,S_DEMN_DEATH3,0,0},	// S_DEMN_DEATH2
+{SPR_DEMN,9,6,A_Scream,S_DEMN_DEATH4,0,0},	// S_DEMN_DEATH3
+{SPR_DEMN,10,6,A_NoBlocking,S_DEMN_DEATH5,0,0},	// S_DEMN_DEATH4
+{SPR_DEMN,11,6,A_QueueCorpse,S_DEMN_DEATH6,0,0},	// S_DEMN_DEATH5
+{SPR_DEMN,12,6,NULL,S_DEMN_DEATH7,0,0},	// S_DEMN_DEATH6
+{SPR_DEMN,13,6,NULL,S_DEMN_DEATH8,0,0},	// S_DEMN_DEATH7
+{SPR_DEMN,14,6,NULL,S_DEMN_DEATH9,0,0},	// S_DEMN_DEATH8
+{SPR_DEMN,15,-1,NULL,S_NULL,0,0},	// S_DEMN_DEATH9
+{SPR_DEMN,7,6,NULL,S_DEMN_XDEATH2,0,0},	// S_DEMN_XDEATH1
+{SPR_DEMN,8,6,A_DemonDeath,S_DEMN_XDEATH3,0,0},	// S_DEMN_XDEATH2
+{SPR_DEMN,9,6,A_Scream,S_DEMN_XDEATH4,0,0},	// S_DEMN_XDEATH3
+{SPR_DEMN,10,6,A_NoBlocking,S_DEMN_XDEATH5,0,0},	// S_DEMN_XDEATH4
+{SPR_DEMN,11,6,A_QueueCorpse,S_DEMN_XDEATH6,0,0},	// S_DEMN_XDEATH5
+{SPR_DEMN,12,6,NULL,S_DEMN_XDEATH7,0,0},	// S_DEMN_XDEATH6
+{SPR_DEMN,13,6,NULL,S_DEMN_XDEATH8,0,0},	// S_DEMN_XDEATH7
+{SPR_DEMN,14,6,NULL,S_DEMN_XDEATH9,0,0},	// S_DEMN_XDEATH8
+{SPR_DEMN,15,-1,NULL,S_NULL,0,0},	// S_DEMN_XDEATH9
+{SPR_DEMN,16,5,A_FreezeDeath,S_DEMON_ICE2,0,0},	// S_DEMON_ICE
+{SPR_DEMN,16,1,A_FreezeDeathChunks,S_DEMON_ICE2,0,0},	// S_DEMON_ICE2
+{SPR_DEMA,0,4,NULL,S_DEMONCHUNK1_2,0,0},	// S_DEMONCHUNK1_1
+{SPR_DEMA,0,10,A_QueueCorpse,S_DEMONCHUNK1_3,0,0},	// S_DEMONCHUNK1_2
+{SPR_DEMA,0,20,NULL,S_DEMONCHUNK1_3,0,0},	// S_DEMONCHUNK1_3
+{SPR_DEMA,0,-1,NULL,S_NULL,0,0},	// S_DEMONCHUNK1_4
+{SPR_DEMB,0,4,NULL,S_DEMONCHUNK2_2,0,0},	// S_DEMONCHUNK2_1
+{SPR_DEMB,0,10,A_QueueCorpse,S_DEMONCHUNK2_3,0,0},	// S_DEMONCHUNK2_2
+{SPR_DEMB,0,20,NULL,S_DEMONCHUNK2_3,0,0},	// S_DEMONCHUNK2_3
+{SPR_DEMB,0,-1,NULL,S_NULL,0,0},	// S_DEMONCHUNK2_4
+{SPR_DEMC,0,4,NULL,S_DEMONCHUNK3_2,0,0},	// S_DEMONCHUNK3_1
+{SPR_DEMC,0,10,A_QueueCorpse,S_DEMONCHUNK3_3,0,0},	// S_DEMONCHUNK3_2
+{SPR_DEMC,0,20,NULL,S_DEMONCHUNK3_3,0,0},	// S_DEMONCHUNK3_3
+{SPR_DEMC,0,-1,NULL,S_NULL,0,0},	// S_DEMONCHUNK3_4
+{SPR_DEMD,0,4,NULL,S_DEMONCHUNK4_2,0,0},	// S_DEMONCHUNK4_1
+{SPR_DEMD,0,10,A_QueueCorpse,S_DEMONCHUNK4_3,0,0},	// S_DEMONCHUNK4_2
+{SPR_DEMD,0,20,NULL,S_DEMONCHUNK4_3,0,0},	// S_DEMONCHUNK4_3
+{SPR_DEMD,0,-1,NULL,S_NULL,0,0},	// S_DEMONCHUNK4_4
+{SPR_DEME,0,4,NULL,S_DEMONCHUNK5_2,0,0},	// S_DEMONCHUNK5_1
+{SPR_DEME,0,10,A_QueueCorpse,S_DEMONCHUNK5_3,0,0},	// S_DEMONCHUNK5_2
+{SPR_DEME,0,20,NULL,S_DEMONCHUNK5_3,0,0},	// S_DEMONCHUNK5_3
+{SPR_DEME,0,-1,NULL,S_NULL,0,0},	// S_DEMONCHUNK5_4
+{SPR_DMFX,32768,4,NULL,S_DEMONFX_MOVE2,0,0},	// S_DEMONFX_MOVE1
+{SPR_DMFX,32769,4,NULL,S_DEMONFX_MOVE3,0,0},	// S_DEMONFX_MOVE2
+{SPR_DMFX,32770,4,NULL,S_DEMONFX_MOVE1,0,0},	// S_DEMONFX_MOVE3
+{SPR_DMFX,32771,4,NULL,S_DEMONFX_BOOM2,0,0},	// S_DEMONFX_BOOM1
+{SPR_DMFX,32772,4,NULL,S_DEMONFX_BOOM3,0,0},	// S_DEMONFX_BOOM2
+{SPR_DMFX,32773,3,NULL,S_DEMONFX_BOOM4,0,0},	// S_DEMONFX_BOOM3
+{SPR_DMFX,32774,3,NULL,S_DEMONFX_BOOM5,0,0},	// S_DEMONFX_BOOM4
+{SPR_DMFX,32775,3,NULL,S_NULL,0,0},	// S_DEMONFX_BOOM5
+{SPR_DEM2,0,10,A_Look,S_DEMN2_LOOK2,0,0},	// S_DEMN2_LOOK1
+{SPR_DEM2,0,10,A_Look,S_DEMN2_LOOK1,0,0},	// S_DEMN2_LOOK2
+{SPR_DEM2,0,4,A_Chase,S_DEMN2_CHASE2,0,0},	// S_DEMN2_CHASE1
+{SPR_DEM2,1,4,A_Chase,S_DEMN2_CHASE3,0,0},	// S_DEMN2_CHASE2
+{SPR_DEM2,2,4,A_Chase,S_DEMN2_CHASE4,0,0},	// S_DEMN2_CHASE3
+{SPR_DEM2,3,4,A_Chase,S_DEMN2_CHASE1,0,0},	// S_DEMN2_CHASE4
+{SPR_DEM2,4,6,A_FaceTarget,S_DEMN2_ATK1_2,0,0},	// S_DEMN2_ATK1_1
+{SPR_DEM2,5,8,A_FaceTarget,S_DEMN2_ATK1_3,0,0},	// S_DEMN2_ATK1_2
+{SPR_DEM2,6,6,A_DemonAttack1,S_DEMN2_CHASE1,0,0},	// S_DEMN2_ATK1_3
+{SPR_DEM2,4,5,A_FaceTarget,S_DEMN2_ATK2_2,0,0},	// S_DEMN2_ATK2_1
+{SPR_DEM2,5,6,A_FaceTarget,S_DEMN2_ATK2_3,0,0},	// S_DEMN2_ATK2_2
+{SPR_DEM2,6,5,A_DemonAttack2,S_DEMN2_CHASE1,0,0},	// S_DEMN2_ATK2_3
+{SPR_DEM2,4,4,NULL,S_DEMN2_PAIN2,0,0},	// S_DEMN2_PAIN1
+{SPR_DEM2,4,4,A_Pain,S_DEMN2_CHASE1,0,0},	// S_DEMN2_PAIN2
+{SPR_DEM2,7,6,NULL,S_DEMN2_DEATH2,0,0},	// S_DEMN2_DEATH1
+{SPR_DEM2,8,6,NULL,S_DEMN2_DEATH3,0,0},	// S_DEMN2_DEATH2
+{SPR_DEM2,9,6,A_Scream,S_DEMN2_DEATH4,0,0},	// S_DEMN2_DEATH3
+{SPR_DEM2,10,6,A_NoBlocking,S_DEMN2_DEATH5,0,0},	// S_DEMN2_DEATH4
+{SPR_DEM2,11,6,A_QueueCorpse,S_DEMN2_DEATH6,0,0},	// S_DEMN2_DEATH5
+{SPR_DEM2,12,6,NULL,S_DEMN2_DEATH7,0,0},	// S_DEMN2_DEATH6
+{SPR_DEM2,13,6,NULL,S_DEMN2_DEATH8,0,0},	// S_DEMN2_DEATH7
+{SPR_DEM2,14,6,NULL,S_DEMN2_DEATH9,0,0},	// S_DEMN2_DEATH8
+{SPR_DEM2,15,-1,NULL,S_NULL,0,0},	// S_DEMN2_DEATH9
+{SPR_DEM2,7,6,NULL,S_DEMN2_XDEATH2,0,0},	// S_DEMN2_XDEATH1
+{SPR_DEM2,8,6,A_Demon2Death,S_DEMN2_XDEATH3,0,0},	// S_DEMN2_XDEATH2
+{SPR_DEM2,9,6,A_Scream,S_DEMN2_XDEATH4,0,0},	// S_DEMN2_XDEATH3
+{SPR_DEM2,10,6,A_NoBlocking,S_DEMN2_XDEATH5,0,0},	// S_DEMN2_XDEATH4
+{SPR_DEM2,11,6,A_QueueCorpse,S_DEMN2_XDEATH6,0,0},	// S_DEMN2_XDEATH5
+{SPR_DEM2,12,6,NULL,S_DEMN2_XDEATH7,0,0},	// S_DEMN2_XDEATH6
+{SPR_DEM2,13,6,NULL,S_DEMN2_XDEATH8,0,0},	// S_DEMN2_XDEATH7
+{SPR_DEM2,14,6,NULL,S_DEMN2_XDEATH9,0,0},	// S_DEMN2_XDEATH8
+{SPR_DEM2,15,-1,NULL,S_NULL,0,0},	// S_DEMN2_XDEATH9
+{SPR_DMBA,0,4,NULL,S_DEMON2CHUNK1_2,0,0},	// S_DEMON2CHUNK1_1
+{SPR_DMBA,0,10,A_QueueCorpse,S_DEMON2CHUNK1_3,0,0},	// S_DEMON2CHUNK1_2
+{SPR_DMBA,0,20,NULL,S_DEMON2CHUNK1_3,0,0},	// S_DEMON2CHUNK1_3
+{SPR_DMBA,0,-1,NULL,S_NULL,0,0},	// S_DEMON2CHUNK1_4
+{SPR_DMBB,0,4,NULL,S_DEMON2CHUNK2_2,0,0},	// S_DEMON2CHUNK2_1
+{SPR_DMBB,0,10,A_QueueCorpse,S_DEMON2CHUNK2_3,0,0},	// S_DEMON2CHUNK2_2
+{SPR_DMBB,0,20,NULL,S_DEMON2CHUNK2_3,0,0},	// S_DEMON2CHUNK2_3
+{SPR_DMBB,0,-1,NULL,S_NULL,0,0},	// S_DEMON2CHUNK2_4
+{SPR_DMBC,0,4,NULL,S_DEMON2CHUNK3_2,0,0},	// S_DEMON2CHUNK3_1
+{SPR_DMBC,0,10,A_QueueCorpse,S_DEMON2CHUNK3_3,0,0},	// S_DEMON2CHUNK3_2
+{SPR_DMBC,0,20,NULL,S_DEMON2CHUNK3_3,0,0},	// S_DEMON2CHUNK3_3
+{SPR_DMBC,0,-1,NULL,S_NULL,0,0},	// S_DEMON2CHUNK3_4
+{SPR_DMBD,0,4,NULL,S_DEMON2CHUNK4_2,0,0},	// S_DEMON2CHUNK4_1
+{SPR_DMBD,0,10,A_QueueCorpse,S_DEMON2CHUNK4_3,0,0},	// S_DEMON2CHUNK4_2
+{SPR_DMBD,0,20,NULL,S_DEMON2CHUNK4_3,0,0},	// S_DEMON2CHUNK4_3
+{SPR_DMBD,0,-1,NULL,S_NULL,0,0},	// S_DEMON2CHUNK4_4
+{SPR_DMBE,0,4,NULL,S_DEMON2CHUNK5_2,0,0},	// S_DEMON2CHUNK5_1
+{SPR_DMBE,0,10,NULL,S_DEMON2CHUNK5_3,0,0},	// S_DEMON2CHUNK5_2
+{SPR_DMBE,0,20,NULL,S_DEMON2CHUNK5_3,0,0},	// S_DEMON2CHUNK5_3
+{SPR_DMBE,0,-1,NULL,S_NULL,0,0},	// S_DEMON2CHUNK5_4
+{SPR_D2FX,32768,4,NULL,S_DEMON2FX_MOVE2,0,0},	// S_DEMON2FX_MOVE1
+{SPR_D2FX,32769,4,NULL,S_DEMON2FX_MOVE3,0,0},	// S_DEMON2FX_MOVE2
+{SPR_D2FX,32770,4,NULL,S_DEMON2FX_MOVE4,0,0},	// S_DEMON2FX_MOVE3
+{SPR_D2FX,32771,4,NULL,S_DEMON2FX_MOVE5,0,0},	// S_DEMON2FX_MOVE4
+{SPR_D2FX,32772,4,NULL,S_DEMON2FX_MOVE6,0,0},	// S_DEMON2FX_MOVE5
+{SPR_D2FX,32773,4,NULL,S_DEMON2FX_MOVE1,0,0},	// S_DEMON2FX_MOVE6
+{SPR_D2FX,32774,4,NULL,S_DEMON2FX_BOOM2,0,0},	// S_DEMON2FX_BOOM1
+{SPR_D2FX,32775,4,NULL,S_DEMON2FX_BOOM3,0,0},	// S_DEMON2FX_BOOM2
+{SPR_D2FX,32776,4,NULL,S_DEMON2FX_BOOM4,0,0},	// S_DEMON2FX_BOOM3
+{SPR_D2FX,32777,4,NULL,S_DEMON2FX_BOOM5,0,0},	// S_DEMON2FX_BOOM4
+{SPR_D2FX,32778,3,NULL,S_DEMON2FX_BOOM6,0,0},	// S_DEMON2FX_BOOM5
+{SPR_D2FX,32779,3,NULL,S_NULL,0,0},	// S_DEMON2FX_BOOM6
+{SPR_WRTH,0,2,A_WraithRaiseInit,S_WRAITH_RAISE2,0,0},	// S_WRAITH_RAISE1
+{SPR_WRTH,0,2,A_WraithRaise,S_WRAITH_RAISE3,0,0},	// S_WRAITH_RAISE2
+{SPR_WRTH,0,2,A_FaceTarget,S_WRAITH_RAISE4,0,0},	// S_WRAITH_RAISE3
+{SPR_WRTH,1,2,A_WraithRaise,S_WRAITH_RAISE5,0,0},	// S_WRAITH_RAISE4
+{SPR_WRTH,1,2,A_WraithRaise,S_WRAITH_RAISE2,0,0},	// S_WRAITH_RAISE5
+{SPR_WRTH,0,10,NULL,S_WRAITH_INIT2,0,0},	// S_WRAITH_INIT1
+{SPR_WRTH,1,5,A_WraithInit,S_WRAITH_LOOK1,0,0},	// S_WRAITH_INIT2
+{SPR_WRTH,0,15,A_WraithLook,S_WRAITH_LOOK2,0,0},	// S_WRAITH_LOOK1
+{SPR_WRTH,1,15,A_WraithLook,S_WRAITH_LOOK1,0,0},	// S_WRAITH_LOOK2
+{SPR_WRTH,0,4,A_WraithChase,S_WRAITH_CHASE2,0,0},	// S_WRAITH_CHASE1
+{SPR_WRTH,1,4,A_WraithChase,S_WRAITH_CHASE3,0,0},	// S_WRAITH_CHASE2
+{SPR_WRTH,2,4,A_WraithChase,S_WRAITH_CHASE4,0,0},	// S_WRAITH_CHASE3
+{SPR_WRTH,3,4,A_WraithChase,S_WRAITH_CHASE1,0,0},	// S_WRAITH_CHASE4
+{SPR_WRTH,4,6,A_FaceTarget,S_WRAITH_ATK1_2,0,0},	// S_WRAITH_ATK1_1
+{SPR_WRTH,5,6,A_WraithFX3,S_WRAITH_ATK1_3,0,0},	// S_WRAITH_ATK1_2
+{SPR_WRTH,6,6,A_WraithMelee,S_WRAITH_CHASE1,0,0},	// S_WRAITH_ATK1_3
+{SPR_WRTH,4,6,A_FaceTarget,S_WRAITH_ATK2_2,0,0},	// S_WRAITH_ATK2_1
+{SPR_WRTH,5,6,NULL,S_WRAITH_ATK2_3,0,0},	// S_WRAITH_ATK2_2
+{SPR_WRTH,6,6,A_WraithMissile,S_WRAITH_CHASE1,0,0},	// S_WRAITH_ATK2_3
+{SPR_WRTH,0,2,NULL,S_WRAITH_PAIN2,0,0},	// S_WRAITH_PAIN1
+{SPR_WRTH,7,6,A_Pain,S_WRAITH_CHASE1,0,0},	// S_WRAITH_PAIN2
+{SPR_WRTH,8,4,NULL,S_WRAITH_DEATH1_2,0,0},	// S_WRAITH_DEATH1_1
+{SPR_WRTH,9,4,A_Scream,S_WRAITH_DEATH1_3,0,0},	// S_WRAITH_DEATH1_2
+{SPR_WRTH,10,4,NULL,S_WRAITH_DEATH1_4,0,0},	// S_WRAITH_DEATH1_3
+{SPR_WRTH,11,4,NULL,S_WRAITH_DEATH1_5,0,0},	// S_WRAITH_DEATH1_4
+{SPR_WRTH,12,4,A_NoBlocking,S_WRAITH_DEATH1_6,0,0},	// S_WRAITH_DEATH1_5
+{SPR_WRTH,13,4,A_QueueCorpse,S_WRAITH_DEATH1_7,0,0},	// S_WRAITH_DEATH1_6
+{SPR_WRTH,14,4,NULL,S_WRAITH_DEATH1_8,0,0},	// S_WRAITH_DEATH1_7
+{SPR_WRTH,15,5,NULL,S_WRAITH_DEATH1_9,0,0},	// S_WRAITH_DEATH1_8
+{SPR_WRTH,16,5,NULL,S_WRAITH_DEATH1_0,0,0},	// S_WRAITH_DEATH1_9
+{SPR_WRTH,17,-1,NULL,S_NULL,0,0},	// S_WRAITH_DEATH1_0
+{SPR_WRT2,0,5,NULL,S_WRAITH_DEATH2_2,0,0},	// S_WRAITH_DEATH2_1
+{SPR_WRT2,1,5,A_Scream,S_WRAITH_DEATH2_3,0,0},	// S_WRAITH_DEATH2_2
+{SPR_WRT2,2,5,NULL,S_WRAITH_DEATH2_4,0,0},	// S_WRAITH_DEATH2_3
+{SPR_WRT2,3,5,NULL,S_WRAITH_DEATH2_5,0,0},	// S_WRAITH_DEATH2_4
+{SPR_WRT2,4,5,A_NoBlocking,S_WRAITH_DEATH2_6,0,0},	// S_WRAITH_DEATH2_5
+{SPR_WRT2,5,5,A_QueueCorpse,S_WRAITH_DEATH2_7,0,0},	// S_WRAITH_DEATH2_6
+{SPR_WRT2,6,5,NULL,S_WRAITH_DEATH2_8,0,0},	// S_WRAITH_DEATH2_7
+{SPR_WRT2,7,-1,NULL,S_NULL,0,0},	// S_WRAITH_DEATH2_8
+{SPR_WRT2,8,5,A_FreezeDeath,S_WRAITH_ICE2,0,0},	// S_WRAITH_ICE
+{SPR_WRT2,8,1,A_FreezeDeathChunks,S_WRAITH_ICE2,0,0},	// S_WRAITH_ICE2
+{SPR_WRBL,32768,3,NULL,S_WRTHFX_MOVE2,0,0},	// S_WRTHFX_MOVE1
+{SPR_WRBL,32769,3,A_WraithFX2,S_WRTHFX_MOVE3,0,0},	// S_WRTHFX_MOVE2
+{SPR_WRBL,32770,3,NULL,S_WRTHFX_MOVE1,0,0},	// S_WRTHFX_MOVE3
+{SPR_WRBL,32771,4,NULL,S_WRTHFX_BOOM2,0,0},	// S_WRTHFX_BOOM1
+{SPR_WRBL,32772,4,A_WraithFX2,S_WRTHFX_BOOM3,0,0},	// S_WRTHFX_BOOM2
+{SPR_WRBL,32773,4,NULL,S_WRTHFX_BOOM4,0,0},	// S_WRTHFX_BOOM3
+{SPR_WRBL,32774,3,A_WraithFX2,S_WRTHFX_BOOM5,0,0},	// S_WRTHFX_BOOM4
+{SPR_WRBL,32775,3,A_WraithFX2,S_WRTHFX_BOOM6,0,0},	// S_WRTHFX_BOOM5
+{SPR_WRBL,32776,3,NULL,S_NULL,0,0},	// S_WRTHFX_BOOM6
+{SPR_WRBL,32777,4,NULL,S_WRTHFX_SIZZLE2,0,0},	// S_WRTHFX_SIZZLE1
+{SPR_WRBL,32778,4,NULL,S_WRTHFX_SIZZLE3,0,0},	// S_WRTHFX_SIZZLE2
+{SPR_WRBL,32779,4,NULL,S_WRTHFX_SIZZLE4,0,0},	// S_WRTHFX_SIZZLE3
+{SPR_WRBL,32780,4,NULL,S_WRTHFX_SIZZLE5,0,0},	// S_WRTHFX_SIZZLE4
+{SPR_WRBL,32781,4,NULL,S_WRTHFX_SIZZLE6,0,0},	// S_WRTHFX_SIZZLE5
+{SPR_WRBL,32782,4,NULL,S_WRTHFX_SIZZLE7,0,0},	// S_WRTHFX_SIZZLE6
+{SPR_WRBL,32783,4,NULL,S_NULL,0,0},	// S_WRTHFX_SIZZLE7
+{SPR_WRBL,32784,4,NULL,S_WRTHFX_DROP2,0,0},	// S_WRTHFX_DROP1
+{SPR_WRBL,32785,4,NULL,S_WRTHFX_DROP3,0,0},	// S_WRTHFX_DROP2
+{SPR_WRBL,32786,4,NULL,S_WRTHFX_DROP1,0,0},	// S_WRTHFX_DROP3
+{SPR_WRBL,32786,4,NULL,S_NULL,0,0},	// S_WRTHFX_DEAD1
+{SPR_WRBL,19,4,NULL,S_WRTHFX_ADROP2,0,0},	// S_WRTHFX_ADROP1
+{SPR_WRBL,20,4,NULL,S_WRTHFX_ADROP3,0,0},	// S_WRTHFX_ADROP2
+{SPR_WRBL,21,4,NULL,S_WRTHFX_ADROP4,0,0},	// S_WRTHFX_ADROP3
+{SPR_WRBL,22,4,NULL,S_WRTHFX_ADROP1,0,0},	// S_WRTHFX_ADROP4
+{SPR_WRBL,22,10,NULL,S_NULL,0,0},	// S_WRTHFX_ADEAD1
+{SPR_WRBL,23,7,NULL,S_WRTHFX_BDROP2,0,0},	// S_WRTHFX_BDROP1
+{SPR_WRBL,24,7,NULL,S_WRTHFX_BDROP3,0,0},	// S_WRTHFX_BDROP2
+{SPR_WRBL,25,7,NULL,S_WRTHFX_BDROP1,0,0},	// S_WRTHFX_BDROP3
+{SPR_WRBL,25,35,NULL,S_NULL,0,0},	// S_WRTHFX_BDEAD1
+{SPR_MNTR,0,15,NULL,S_MNTR_SPAWN2,0,0},	// S_MNTR_SPAWN1
+{SPR_MNTR,0,15,A_MinotaurFade1,S_MNTR_SPAWN3,0,0},	// S_MNTR_SPAWN2
+{SPR_MNTR,0,3,A_MinotaurFade2,S_MNTR_LOOK1,0,0},	// S_MNTR_SPAWN3
+{SPR_MNTR,0,10,A_MinotaurLook,S_MNTR_LOOK2,0,0},	// S_MNTR_LOOK1
+{SPR_MNTR,1,10,A_MinotaurLook,S_MNTR_LOOK1,0,0},	// S_MNTR_LOOK2
+{SPR_MNTR,0,5,A_MinotaurChase,S_MNTR_WALK2,0,0},	// S_MNTR_WALK1
+{SPR_MNTR,1,5,A_MinotaurChase,S_MNTR_WALK3,0,0},	// S_MNTR_WALK2
+{SPR_MNTR,2,5,A_MinotaurChase,S_MNTR_WALK4,0,0},	// S_MNTR_WALK3
+{SPR_MNTR,3,5,A_MinotaurChase,S_MNTR_WALK1,0,0},	// S_MNTR_WALK4
+{SPR_MNTR,0,5,A_MinotaurRoam,S_MNTR_ROAM2,0,0},	// S_MNTR_ROAM1
+{SPR_MNTR,1,5,A_MinotaurRoam,S_MNTR_ROAM3,0,0},	// S_MNTR_ROAM2
+{SPR_MNTR,2,5,A_MinotaurRoam,S_MNTR_ROAM4,0,0},	// S_MNTR_ROAM3
+{SPR_MNTR,3,5,A_MinotaurRoam,S_MNTR_ROAM1,0,0},	// S_MNTR_ROAM4
+{SPR_MNTR,6,10,A_FaceTarget,S_MNTR_ATK1_2,0,0},	// S_MNTR_ATK1_1
+{SPR_MNTR,7,7,A_FaceTarget,S_MNTR_ATK1_3,0,0},	// S_MNTR_ATK1_2
+{SPR_MNTR,8,12,A_MinotaurAtk1,S_MNTR_WALK1,0,0},	// S_MNTR_ATK1_3
+{SPR_MNTR,6,10,A_MinotaurDecide,S_MNTR_ATK2_2,0,0},	// S_MNTR_ATK2_1
+{SPR_MNTR,9,4,A_FaceTarget,S_MNTR_ATK2_3,0,0},	// S_MNTR_ATK2_2
+{SPR_MNTR,10,9,A_MinotaurAtk2,S_MNTR_WALK1,0,0},	// S_MNTR_ATK2_3
+{SPR_MNTR,6,10,A_FaceTarget,S_MNTR_ATK3_2,0,0},	// S_MNTR_ATK3_1
+{SPR_MNTR,7,7,A_FaceTarget,S_MNTR_ATK3_3,0,0},	// S_MNTR_ATK3_2
+{SPR_MNTR,8,12,A_MinotaurAtk3,S_MNTR_WALK1,0,0},	// S_MNTR_ATK3_3
+{SPR_MNTR,8,12,NULL,S_MNTR_ATK3_1,0,0},	// S_MNTR_ATK3_4
+{SPR_MNTR,5,2,A_MinotaurCharge,S_MNTR_ATK4_1,0,0},	// S_MNTR_ATK4_1
+{SPR_MNTR,4,3,NULL,S_MNTR_PAIN2,0,0},	// S_MNTR_PAIN1
+{SPR_MNTR,4,6,A_Pain,S_MNTR_WALK1,0,0},	// S_MNTR_PAIN2
+{SPR_MNTR,4,6,NULL,S_MNTR_DIE2,0,0},	// S_MNTR_DIE1
+{SPR_MNTR,4,2,A_Scream,S_MNTR_DIE3,0,0},	// S_MNTR_DIE2
+{SPR_MNTR,4,5,A_SmokePuffExit,S_MNTR_DIE4,0,0},	// S_MNTR_DIE3
+{SPR_MNTR,4,5,NULL,S_MNTR_DIE5,0,0},	// S_MNTR_DIE4
+{SPR_MNTR,4,5,A_NoBlocking,S_MNTR_DIE6,0,0},	// S_MNTR_DIE5
+{SPR_MNTR,4,5,NULL,S_MNTR_DIE7,0,0},	// S_MNTR_DIE6
+{SPR_MNTR,4,5,A_MinotaurFade1,S_MNTR_DIE8,0,0},	// S_MNTR_DIE7
+{SPR_MNTR,4,5,A_MinotaurFade0,S_MNTR_DIE9,0,0},	// S_MNTR_DIE8
+{SPR_MNTR,4,10,NULL,S_NULL,0,0},	// S_MNTR_DIE9
+{SPR_FX12,32768,6,NULL,S_MNTRFX1_2,0,0},	// S_MNTRFX1_1
+{SPR_FX12,32769,6,NULL,S_MNTRFX1_1,0,0},	// S_MNTRFX1_2
+{SPR_FX12,32770,5,NULL,S_MNTRFXI1_2,0,0},	// S_MNTRFXI1_1
+{SPR_FX12,32771,5,NULL,S_MNTRFXI1_3,0,0},	// S_MNTRFXI1_2
+{SPR_FX12,32772,5,NULL,S_MNTRFXI1_4,0,0},	// S_MNTRFXI1_3
+{SPR_FX12,32773,5,NULL,S_MNTRFXI1_5,0,0},	// S_MNTRFXI1_4
+{SPR_FX12,32774,5,NULL,S_MNTRFXI1_6,0,0},	// S_MNTRFXI1_5
+{SPR_FX12,32775,5,NULL,S_NULL,0,0},	// S_MNTRFXI1_6
+{SPR_FX13,0,2,A_MntrFloorFire,S_MNTRFX2_1,0,0},	// S_MNTRFX2_1
+{SPR_FX13,32776,4,A_Explode,S_MNTRFXI2_2,0,0},	// S_MNTRFXI2_1
+{SPR_FX13,32777,4,NULL,S_MNTRFXI2_3,0,0},	// S_MNTRFXI2_2
+{SPR_FX13,32778,4,NULL,S_MNTRFXI2_4,0,0},	// S_MNTRFXI2_3
+{SPR_FX13,32779,4,NULL,S_MNTRFXI2_5,0,0},	// S_MNTRFXI2_4
+{SPR_FX13,32780,4,NULL,S_NULL,0,0},	// S_MNTRFXI2_5
+{SPR_FX13,32771,4,NULL,S_MNTRFX3_2,0,0},	// S_MNTRFX3_1
+{SPR_FX13,32770,4,NULL,S_MNTRFX3_3,0,0},	// S_MNTRFX3_2
+{SPR_FX13,32769,5,NULL,S_MNTRFX3_4,0,0},	// S_MNTRFX3_3
+{SPR_FX13,32770,5,NULL,S_MNTRFX3_5,0,0},	// S_MNTRFX3_4
+{SPR_FX13,32771,5,NULL,S_MNTRFX3_6,0,0},	// S_MNTRFX3_5
+{SPR_FX13,32772,5,NULL,S_MNTRFX3_7,0,0},	// S_MNTRFX3_6
+{SPR_FX13,32773,4,NULL,S_MNTRFX3_8,0,0},	// S_MNTRFX3_7
+{SPR_FX13,32774,4,NULL,S_MNTRFX3_9,0,0},	// S_MNTRFX3_8
+{SPR_FX13,32775,4,NULL,S_NULL,0,0},	// S_MNTRFX3_9
+{SPR_MNSM,0,3,NULL,S_MINOSMOKE2,0,0},	// S_MINOSMOKE1
+{SPR_MNSM,1,3,NULL,S_MINOSMOKE3,0,0},	// S_MINOSMOKE2
+{SPR_MNSM,2,3,NULL,S_MINOSMOKE4,0,0},	// S_MINOSMOKE3
+{SPR_MNSM,3,3,NULL,S_MINOSMOKE5,0,0},	// S_MINOSMOKE4
+{SPR_MNSM,4,3,NULL,S_MINOSMOKE6,0,0},	// S_MINOSMOKE5
+{SPR_MNSM,5,3,NULL,S_MINOSMOKE7,0,0},	// S_MINOSMOKE6
+{SPR_MNSM,6,3,NULL,S_MINOSMOKE8,0,0},	// S_MINOSMOKE7
+{SPR_MNSM,7,3,NULL,S_MINOSMOKE9,0,0},	// S_MINOSMOKE8
+{SPR_MNSM,8,3,NULL,S_MINOSMOKE0,0,0},	// S_MINOSMOKE9
+{SPR_MNSM,9,3,NULL,S_MINOSMOKEA,0,0},	// S_MINOSMOKE0
+{SPR_MNSM,10,3,NULL,S_MINOSMOKEB,0,0},	// S_MINOSMOKEA
+{SPR_MNSM,11,3,NULL,S_MINOSMOKEC,0,0},	// S_MINOSMOKEB
+{SPR_MNSM,12,3,NULL,S_MINOSMOKED,0,0},	// S_MINOSMOKEC
+{SPR_MNSM,13,3,NULL,S_MINOSMOKEE,0,0},	// S_MINOSMOKED
+{SPR_MNSM,14,3,NULL,S_MINOSMOKEF,0,0},	// S_MINOSMOKEE
+{SPR_MNSM,15,3,NULL,S_MINOSMOKEG,0,0},	// S_MINOSMOKEF
+{SPR_MNSM,16,3,NULL,S_NULL,0,0},	// S_MINOSMOKEG
+{SPR_MNSM,0,3,NULL,S_MINOSMOKEX2,0,0},	// S_MINOSMOKEX1
+{SPR_MNSM,1,3,NULL,S_MINOSMOKEX3,0,0},	// S_MINOSMOKEX2
+{SPR_MNSM,2,3,NULL,S_MINOSMOKEX4,0,0},	// S_MINOSMOKEX3
+{SPR_MNSM,3,3,NULL,S_MINOSMOKEX5,0,0},	// S_MINOSMOKEX4
+{SPR_MNSM,4,3,NULL,S_MINOSMOKEX6,0,0},	// S_MINOSMOKEX5
+{SPR_MNSM,5,3,NULL,S_MINOSMOKEX7,0,0},	// S_MINOSMOKEX6
+{SPR_MNSM,6,3,NULL,S_MINOSMOKEX8,0,0},	// S_MINOSMOKEX7
+{SPR_MNSM,7,3,NULL,S_MINOSMOKEX9,0,0},	// S_MINOSMOKEX8
+{SPR_MNSM,8,3,NULL,S_MINOSMOKEX0,0,0},	// S_MINOSMOKEX9
+{SPR_MNSM,9,3,NULL,S_MINOSMOKEXA,0,0},	// S_MINOSMOKEX0
+{SPR_MNSM,8,3,NULL,S_MINOSMOKEXB,0,0},	// S_MINOSMOKEXA
+{SPR_MNSM,7,3,NULL,S_MINOSMOKEXC,0,0},	// S_MINOSMOKEXB
+{SPR_MNSM,6,3,NULL,S_MINOSMOKEXD,0,0},	// S_MINOSMOKEXC
+{SPR_MNSM,5,3,NULL,S_MINOSMOKEXE,0,0},	// S_MINOSMOKEXD
+{SPR_MNSM,4,3,NULL,S_MINOSMOKEXF,0,0},	// S_MINOSMOKEXE
+{SPR_MNSM,3,3,NULL,S_MINOSMOKEXG,0,0},	// S_MINOSMOKEXF
+{SPR_MNSM,2,3,NULL,S_MINOSMOKEXH,0,0},	// S_MINOSMOKEXG
+{SPR_MNSM,1,3,NULL,S_MINOSMOKEXI,0,0},	// S_MINOSMOKEXH
+{SPR_MNSM,0,3,NULL,S_NULL,0,0},	// S_MINOSMOKEXI
+{SPR_SSPT,7,10,A_Look,S_SERPENT_LOOK1,0,0},	// S_SERPENT_LOOK1
+{SPR_SSPT,7,1,A_SerpentChase,S_SERPENT_SWIM2,0,0},	// S_SERPENT_SWIM1
+{SPR_SSPT,7,1,A_SerpentChase,S_SERPENT_SWIM3,0,0},	// S_SERPENT_SWIM2
+{SPR_SSPT,7,2,A_SerpentHumpDecide,S_SERPENT_SWIM1,0,0},	// S_SERPENT_SWIM3
+{SPR_SSPT,7,3,A_SerpentUnHide,S_SERPENT_HUMP2,0,0},	// S_SERPENT_HUMP1
+{SPR_SSPT,4,3,A_SerpentRaiseHump,S_SERPENT_HUMP3,0,0},	// S_SERPENT_HUMP2
+{SPR_SSPT,5,3,A_SerpentRaiseHump,S_SERPENT_HUMP4,0,0},	// S_SERPENT_HUMP3
+{SPR_SSPT,6,3,A_SerpentRaiseHump,S_SERPENT_HUMP5,0,0},	// S_SERPENT_HUMP4
+{SPR_SSPT,4,3,A_SerpentRaiseHump,S_SERPENT_HUMP6,0,0},	// S_SERPENT_HUMP5
+{SPR_SSPT,5,3,A_SerpentRaiseHump,S_SERPENT_HUMP7,0,0},	// S_SERPENT_HUMP6
+{SPR_SSPT,6,3,NULL,S_SERPENT_HUMP8,0,0},	// S_SERPENT_HUMP7
+{SPR_SSPT,4,3,NULL,S_SERPENT_HUMP9,0,0},	// S_SERPENT_HUMP8
+{SPR_SSPT,5,3,NULL,S_SERPENT_HUMP10,0,0},	// S_SERPENT_HUMP9
+{SPR_SSPT,6,3,A_SerpentLowerHump,S_SERPENT_HUMP11,0,0},	// S_SERPENT_HUMP10
+{SPR_SSPT,4,3,A_SerpentLowerHump,S_SERPENT_HUMP12,0,0},	// S_SERPENT_HUMP11
+{SPR_SSPT,5,3,A_SerpentLowerHump,S_SERPENT_HUMP13,0,0},	// S_SERPENT_HUMP12
+{SPR_SSPT,6,3,A_SerpentLowerHump,S_SERPENT_HUMP14,0,0},	// S_SERPENT_HUMP13
+{SPR_SSPT,4,3,A_SerpentLowerHump,S_SERPENT_HUMP15,0,0},	// S_SERPENT_HUMP14
+{SPR_SSPT,5,3,A_SerpentHide,S_SERPENT_SWIM1,0,0},	// S_SERPENT_HUMP15
+{SPR_SSPT,0,1,A_UnHideThing,S_SERPENT_SURFACE2,0,0},	// S_SERPENT_SURFACE1
+{SPR_SSPT,0,1,A_SerpentBirthScream,S_SERPENT_SURFACE3,0,0},	// S_SERPENT_SURFACE2
+{SPR_SSPT,1,3,A_SetShootable,S_SERPENT_SURFACE4,0,0},	// S_SERPENT_SURFACE3
+{SPR_SSPT,2,3,NULL,S_SERPENT_SURFACE5,0,0},	// S_SERPENT_SURFACE4
+{SPR_SSPT,3,4,A_SerpentCheckForAttack,S_SERPENT_DIVE1,0,0},	// S_SERPENT_SURFACE5
+{SPR_SSDV,0,4,NULL,S_SERPENT_DIVE2,0,0},	// S_SERPENT_DIVE1
+{SPR_SSDV,1,4,NULL,S_SERPENT_DIVE3,0,0},	// S_SERPENT_DIVE2
+{SPR_SSDV,2,4,NULL,S_SERPENT_DIVE4,0,0},	// S_SERPENT_DIVE3
+{SPR_SSDV,3,4,A_UnSetShootable,S_SERPENT_DIVE5,0,0},	// S_SERPENT_DIVE4
+{SPR_SSDV,4,3,A_SerpentDiveSound,S_SERPENT_DIVE6,0,0},	// S_SERPENT_DIVE5
+{SPR_SSDV,5,3,NULL,S_SERPENT_DIVE7,0,0},	// S_SERPENT_DIVE6
+{SPR_SSDV,6,4,NULL,S_SERPENT_DIVE8,0,0},	// S_SERPENT_DIVE7
+{SPR_SSDV,7,4,NULL,S_SERPENT_DIVE9,0,0},	// S_SERPENT_DIVE8
+{SPR_SSDV,8,3,NULL,S_SERPENT_DIVE10,0,0},	// S_SERPENT_DIVE9
+{SPR_SSDV,9,3,A_SerpentHide,S_SERPENT_SWIM1,0,0},	// S_SERPENT_DIVE10
+{SPR_SSPT,8,5,A_SerpentWalk,S_SERPENT_WALK2,0,0},	// S_SERPENT_WALK1
+{SPR_SSPT,9,5,A_SerpentWalk,S_SERPENT_WALK3,0,0},	// S_SERPENT_WALK2
+{SPR_SSPT,8,5,A_SerpentWalk,S_SERPENT_WALK4,0,0},	// S_SERPENT_WALK3
+{SPR_SSPT,9,5,A_SerpentCheckForAttack,S_SERPENT_DIVE1,0,0},	// S_SERPENT_WALK4
+{SPR_SSPT,11,5,NULL,S_SERPENT_PAIN2,0,0},	// S_SERPENT_PAIN1
+{SPR_SSPT,11,5,A_Pain,S_SERPENT_DIVE1,0,0},	// S_SERPENT_PAIN2
+{SPR_SSPT,10,6,A_FaceTarget,S_SERPENT_ATK2,0,0},	// S_SERPENT_ATK1
+{SPR_SSPT,11,5,A_SerpentChooseAttack,S_SERPENT_MELEE1,0,0},	// S_SERPENT_ATK2
+{SPR_SSPT,13,5,A_SerpentMeleeAttack,S_SERPENT_DIVE1,0,0},	// S_SERPENT_MELEE1
+{SPR_SSPT,13,5,A_SerpentMissileAttack,S_SERPENT_DIVE1,0,0},	// S_SERPENT_MISSILE1
+{SPR_SSPT,14,4,NULL,S_SERPENT_DIE2,0,0},	// S_SERPENT_DIE1
+{SPR_SSPT,15,4,A_Scream,S_SERPENT_DIE3,0,0},	// S_SERPENT_DIE2
+{SPR_SSPT,16,4,A_NoBlocking,S_SERPENT_DIE4,0,0},	// S_SERPENT_DIE3
+{SPR_SSPT,17,4,NULL,S_SERPENT_DIE5,0,0},	// S_SERPENT_DIE4
+{SPR_SSPT,18,4,NULL,S_SERPENT_DIE6,0,0},	// S_SERPENT_DIE5
+{SPR_SSPT,19,4,NULL,S_SERPENT_DIE7,0,0},	// S_SERPENT_DIE6
+{SPR_SSPT,20,4,NULL,S_SERPENT_DIE8,0,0},	// S_SERPENT_DIE7
+{SPR_SSPT,21,4,NULL,S_SERPENT_DIE9,0,0},	// S_SERPENT_DIE8
+{SPR_SSPT,22,4,NULL,S_SERPENT_DIE10,0,0},	// S_SERPENT_DIE9
+{SPR_SSPT,23,4,NULL,S_SERPENT_DIE11,0,0},	// S_SERPENT_DIE10
+{SPR_SSPT,24,4,NULL,S_SERPENT_DIE12,0,0},	// S_SERPENT_DIE11
+{SPR_SSPT,25,4,NULL,S_NULL,0,0},	// S_SERPENT_DIE12
+{SPR_SSXD,0,4,NULL,S_SERPENT_XDIE2,0,0},	// S_SERPENT_XDIE1
+{SPR_SSXD,1,4,A_SerpentHeadPop,S_SERPENT_XDIE3,0,0},	// S_SERPENT_XDIE2
+{SPR_SSXD,2,4,A_NoBlocking,S_SERPENT_XDIE4,0,0},	// S_SERPENT_XDIE3
+{SPR_SSXD,3,4,NULL,S_SERPENT_XDIE5,0,0},	// S_SERPENT_XDIE4
+{SPR_SSXD,4,4,NULL,S_SERPENT_XDIE6,0,0},	// S_SERPENT_XDIE5
+{SPR_SSXD,5,3,NULL,S_SERPENT_XDIE7,0,0},	// S_SERPENT_XDIE6
+{SPR_SSXD,6,3,NULL,S_SERPENT_XDIE8,0,0},	// S_SERPENT_XDIE7
+{SPR_SSXD,7,3,A_SerpentSpawnGibs,S_NULL,0,0},	// S_SERPENT_XDIE8
+{SPR_SSPT,26,5,A_FreezeDeath,S_SERPENT_ICE2,0,0},	// S_SERPENT_ICE
+{SPR_SSPT,26,1,A_FreezeDeathChunks,S_SERPENT_ICE2,0,0},	// S_SERPENT_ICE2
+{SPR_SSFX,32768,3,A_ContMobjSound,S_SERPENT_FX2,0,0},	// S_SERPENT_FX1
+{SPR_SSFX,32769,3,NULL,S_SERPENT_FX3,0,0},	// S_SERPENT_FX2
+{SPR_SSFX,32768,3,NULL,S_SERPENT_FX4,0,0},	// S_SERPENT_FX3
+{SPR_SSFX,32769,3,NULL,S_SERPENT_FX1,0,0},	// S_SERPENT_FX4
+{SPR_SSFX,32770,4,NULL,S_SERPENT_FX_X2,0,0},	// S_SERPENT_FX_X1
+{SPR_SSFX,32771,4,NULL,S_SERPENT_FX_X3,0,0},	// S_SERPENT_FX_X2
+{SPR_SSFX,32772,4,NULL,S_SERPENT_FX_X4,0,0},	// S_SERPENT_FX_X3
+{SPR_SSFX,32773,4,NULL,S_SERPENT_FX_X5,0,0},	// S_SERPENT_FX_X4
+{SPR_SSFX,32774,4,NULL,S_SERPENT_FX_X6,0,0},	// S_SERPENT_FX_X5
+{SPR_SSFX,32775,4,NULL,S_NULL,0,0},	// S_SERPENT_FX_X6
+{SPR_SSXD,8,4,A_SerpentHeadCheck,S_SERPENT_HEAD2,0,0},	// S_SERPENT_HEAD1
+{SPR_SSXD,9,4,A_SerpentHeadCheck,S_SERPENT_HEAD3,0,0},	// S_SERPENT_HEAD2
+{SPR_SSXD,10,4,A_SerpentHeadCheck,S_SERPENT_HEAD4,0,0},	// S_SERPENT_HEAD3
+{SPR_SSXD,11,4,A_SerpentHeadCheck,S_SERPENT_HEAD5,0,0},	// S_SERPENT_HEAD4
+{SPR_SSXD,12,4,A_SerpentHeadCheck,S_SERPENT_HEAD6,0,0},	// S_SERPENT_HEAD5
+{SPR_SSXD,13,4,A_SerpentHeadCheck,S_SERPENT_HEAD7,0,0},	// S_SERPENT_HEAD6
+{SPR_SSXD,14,4,A_SerpentHeadCheck,S_SERPENT_HEAD8,0,0},	// S_SERPENT_HEAD7
+{SPR_SSXD,15,4,A_SerpentHeadCheck,S_SERPENT_HEAD1,0,0},	// S_SERPENT_HEAD8
+{SPR_SSXD,18,-1,NULL,S_SERPENT_HEAD_X1,0,0},	// S_SERPENT_HEAD_X1
+{SPR_SSXD,16,6,NULL,S_SERPENT_GIB1_2,0,0},	// S_SERPENT_GIB1_1
+{SPR_SSXD,16,6,A_FloatGib,S_SERPENT_GIB1_3,0,0},	// S_SERPENT_GIB1_2
+{SPR_SSXD,16,8,A_FloatGib,S_SERPENT_GIB1_4,0,0},	// S_SERPENT_GIB1_3
+{SPR_SSXD,16,8,A_FloatGib,S_SERPENT_GIB1_5,0,0},	// S_SERPENT_GIB1_4
+{SPR_SSXD,16,12,A_FloatGib,S_SERPENT_GIB1_6,0,0},	// S_SERPENT_GIB1_5
+{SPR_SSXD,16,12,A_FloatGib,S_SERPENT_GIB1_7,0,0},	// S_SERPENT_GIB1_6
+{SPR_SSXD,16,232,A_DelayGib,S_SERPENT_GIB1_8,0,0},	// S_SERPENT_GIB1_7
+{SPR_SSXD,16,12,A_SinkGib,S_SERPENT_GIB1_9,0,0},	// S_SERPENT_GIB1_8
+{SPR_SSXD,16,12,A_SinkGib,S_SERPENT_GIB1_10,0,0},	// S_SERPENT_GIB1_9
+{SPR_SSXD,16,8,A_SinkGib,S_SERPENT_GIB1_11,0,0},	// S_SERPENT_GIB1_10
+{SPR_SSXD,16,8,A_SinkGib,S_SERPENT_GIB1_12,0,0},	// S_SERPENT_GIB1_11
+{SPR_SSXD,16,8,A_SinkGib,S_NULL,0,0},	// S_SERPENT_GIB1_12
+{SPR_SSXD,17,6,NULL,S_SERPENT_GIB2_2,0,0},	// S_SERPENT_GIB2_1
+{SPR_SSXD,17,6,A_FloatGib,S_SERPENT_GIB2_3,0,0},	// S_SERPENT_GIB2_2
+{SPR_SSXD,17,8,A_FloatGib,S_SERPENT_GIB2_4,0,0},	// S_SERPENT_GIB2_3
+{SPR_SSXD,17,8,A_FloatGib,S_SERPENT_GIB2_5,0,0},	// S_SERPENT_GIB2_4
+{SPR_SSXD,17,12,A_FloatGib,S_SERPENT_GIB2_6,0,0},	// S_SERPENT_GIB2_5
+{SPR_SSXD,17,12,A_FloatGib,S_SERPENT_GIB2_7,0,0},	// S_SERPENT_GIB2_6
+{SPR_SSXD,17,232,A_DelayGib,S_SERPENT_GIB2_8,0,0},	// S_SERPENT_GIB2_7
+{SPR_SSXD,17,12,A_SinkGib,S_SERPENT_GIB2_9,0,0},	// S_SERPENT_GIB2_8
+{SPR_SSXD,17,12,A_SinkGib,S_SERPENT_GIB2_10,0,0},	// S_SERPENT_GIB2_9
+{SPR_SSXD,17,8,A_SinkGib,S_SERPENT_GIB2_11,0,0},	// S_SERPENT_GIB2_10
+{SPR_SSXD,17,8,A_SinkGib,S_SERPENT_GIB2_12,0,0},	// S_SERPENT_GIB2_11
+{SPR_SSXD,17,8,A_SinkGib,S_NULL,0,0},	// S_SERPENT_GIB2_12
+{SPR_SSXD,19,6,NULL,S_SERPENT_GIB3_2,0,0},	// S_SERPENT_GIB3_1
+{SPR_SSXD,19,6,A_FloatGib,S_SERPENT_GIB3_3,0,0},	// S_SERPENT_GIB3_2
+{SPR_SSXD,19,8,A_FloatGib,S_SERPENT_GIB3_4,0,0},	// S_SERPENT_GIB3_3
+{SPR_SSXD,19,8,A_FloatGib,S_SERPENT_GIB3_5,0,0},	// S_SERPENT_GIB3_4
+{SPR_SSXD,19,12,A_FloatGib,S_SERPENT_GIB3_6,0,0},	// S_SERPENT_GIB3_5
+{SPR_SSXD,19,12,A_FloatGib,S_SERPENT_GIB3_7,0,0},	// S_SERPENT_GIB3_6
+{SPR_SSXD,19,232,A_DelayGib,S_SERPENT_GIB3_8,0,0},	// S_SERPENT_GIB3_7
+{SPR_SSXD,19,12,A_SinkGib,S_SERPENT_GIB3_9,0,0},	// S_SERPENT_GIB3_8
+{SPR_SSXD,19,12,A_SinkGib,S_SERPENT_GIB3_10,0,0},	// S_SERPENT_GIB3_9
+{SPR_SSXD,19,8,A_SinkGib,S_SERPENT_GIB3_11,0,0},	// S_SERPENT_GIB3_10
+{SPR_SSXD,19,8,A_SinkGib,S_SERPENT_GIB3_12,0,0},	// S_SERPENT_GIB3_11
+{SPR_SSXD,19,8,A_SinkGib,S_NULL,0,0},	// S_SERPENT_GIB3_12
+{SPR_BISH,0,10,A_Look,S_BISHOP_LOOK1,0,0},	// S_BISHOP_LOOK1
+{SPR_BISH,0,1,A_BishopDecide,S_BISHOP_WALK1,0,0},	// S_BISHOP_DECIDE
+{SPR_BISH,0,2,A_BishopDoBlur,S_BISHOP_BLUR2,0,0},	// S_BISHOP_BLUR1
+{SPR_BISH,0,4,A_BishopSpawnBlur,S_BISHOP_BLUR2,0,0},	// S_BISHOP_BLUR2
+{SPR_BISH,0,2,A_Chase,S_BISHOP_WALK2,0,0},	// S_BISHOP_WALK1
+{SPR_BISH,0,2,A_BishopChase,S_BISHOP_WALK3,0,0},	// S_BISHOP_WALK2
+{SPR_BISH,0,2,NULL,S_BISHOP_WALK4,0,0},	// S_BISHOP_WALK3
+{SPR_BISH,1,2,A_BishopChase,S_BISHOP_WALK5,0,0},	// S_BISHOP_WALK4
+{SPR_BISH,1,2,A_Chase,S_BISHOP_WALK6,0,0},	// S_BISHOP_WALK5
+{SPR_BISH,1,2,A_BishopChase,S_BISHOP_DECIDE,0,0},	// S_BISHOP_WALK6
+{SPR_BISH,0,3,A_FaceTarget,S_BISHOP_ATK2,0,0},	// S_BISHOP_ATK1
+{SPR_BISH,32771,3,A_FaceTarget,S_BISHOP_ATK3,0,0},	// S_BISHOP_ATK2
+{SPR_BISH,32772,3,A_FaceTarget,S_BISHOP_ATK4,0,0},	// S_BISHOP_ATK3
+{SPR_BISH,32773,3,A_BishopAttack,S_BISHOP_ATK5,0,0},	// S_BISHOP_ATK4
+{SPR_BISH,32773,5,A_BishopAttack2,S_BISHOP_ATK5,0,0},	// S_BISHOP_ATK5
+{SPR_BISH,2,6,A_Pain,S_BISHOP_PAIN2,0,0},	// S_BISHOP_PAIN1
+{SPR_BISH,2,6,A_BishopPainBlur,S_BISHOP_PAIN3,0,0},	// S_BISHOP_PAIN2
+{SPR_BISH,2,6,A_BishopPainBlur,S_BISHOP_PAIN4,0,0},	// S_BISHOP_PAIN3
+{SPR_BISH,2,6,A_BishopPainBlur,S_BISHOP_PAIN5,0,0},	// S_BISHOP_PAIN4
+{SPR_BISH,2,0,NULL,S_BISHOP_WALK1,0,0},	// S_BISHOP_PAIN5
+{SPR_BISH,6,6,NULL,S_BISHOP_DEATH2,0,0},	// S_BISHOP_DEATH1
+{SPR_BISH,32775,6,A_Scream,S_BISHOP_DEATH3,0,0},	// S_BISHOP_DEATH2
+{SPR_BISH,32776,5,A_NoBlocking,S_BISHOP_DEATH4,0,0},	// S_BISHOP_DEATH3
+{SPR_BISH,32777,5,A_Explode,S_BISHOP_DEATH5,0,0},	// S_BISHOP_DEATH4
+{SPR_BISH,32778,5,NULL,S_BISHOP_DEATH6,0,0},	// S_BISHOP_DEATH5
+{SPR_BISH,32779,4,NULL,S_BISHOP_DEATH7,0,0},	// S_BISHOP_DEATH6
+{SPR_BISH,32780,4,NULL,S_BISHOP_DEATH8,0,0},	// S_BISHOP_DEATH7
+{SPR_BISH,13,4,A_BishopPuff,S_BISHOP_DEATH9,0,0},	// S_BISHOP_DEATH8
+{SPR_BISH,14,4,A_QueueCorpse,S_BISHOP_DEATH10,0,0},	// S_BISHOP_DEATH9
+{SPR_BISH,15,-1,NULL,S_NULL,0,0},	// S_BISHOP_DEATH10
+{SPR_BISH,23,5,A_FreezeDeath,S_BISHOP_ICE2,0,0},	// S_BISHOP_ICE
+{SPR_BISH,23,1,A_FreezeDeathChunks,S_BISHOP_ICE2,0,0},	// S_BISHOP_ICE2
+{SPR_BISH,16,5,NULL,S_BISHOP_PUFF2,0,0},	// S_BISHOP_PUFF1
+{SPR_BISH,17,5,NULL,S_BISHOP_PUFF3,0,0},	// S_BISHOP_PUFF2
+{SPR_BISH,18,5,NULL,S_BISHOP_PUFF4,0,0},	// S_BISHOP_PUFF3
+{SPR_BISH,19,5,NULL,S_BISHOP_PUFF5,0,0},	// S_BISHOP_PUFF4
+{SPR_BISH,20,6,NULL,S_BISHOP_PUFF6,0,0},	// S_BISHOP_PUFF5
+{SPR_BISH,21,6,NULL,S_BISHOP_PUFF7,0,0},	// S_BISHOP_PUFF6
+{SPR_BISH,22,5,NULL,S_NULL,0,0},	// S_BISHOP_PUFF7
+{SPR_BISH,0,16,NULL,S_BISHOPBLUR2,0,0},	// S_BISHOPBLUR1
+{SPR_BISH,0,8,A_SetAltShadow,S_NULL,0,0},	// S_BISHOPBLUR2
+{SPR_BISH,2,8,NULL,S_NULL,0,0},	// S_BISHOPPAINBLUR1
+{SPR_BPFX,32768,1,A_BishopMissileWeave,S_BISHFX1_2,0,0},	// S_BISHFX1_1
+{SPR_BPFX,32769,1,A_BishopMissileWeave,S_BISHFX1_3,0,0},	// S_BISHFX1_2
+{SPR_BPFX,32768,1,A_BishopMissileWeave,S_BISHFX1_4,0,0},	// S_BISHFX1_3
+{SPR_BPFX,32769,1,A_BishopMissileWeave,S_BISHFX1_5,0,0},	// S_BISHFX1_4
+{SPR_BPFX,32769,0,A_BishopMissileSeek,S_BISHFX1_1,0,0},	// S_BISHFX1_5
+{SPR_BPFX,32770,4,NULL,S_BISHFXI1_2,0,0},	// S_BISHFXI1_1
+{SPR_BPFX,32771,4,NULL,S_BISHFXI1_3,0,0},	// S_BISHFXI1_2
+{SPR_BPFX,32772,4,NULL,S_BISHFXI1_4,0,0},	// S_BISHFXI1_3
+{SPR_BPFX,32773,4,NULL,S_BISHFXI1_5,0,0},	// S_BISHFXI1_4
+{SPR_BPFX,32774,3,NULL,S_BISHFXI1_6,0,0},	// S_BISHFXI1_5
+{SPR_BPFX,32775,3,NULL,S_NULL,0,0},	// S_BISHFXI1_6
+{SPR_DRAG,3,10,A_Look,S_DRAGON_LOOK1,0,0},	// S_DRAGON_LOOK1
+{SPR_DRAG,2,5,NULL,S_DRAGON_INIT2,0,0},	// S_DRAGON_INIT
+{SPR_DRAG,1,5,NULL,S_DRAGON_INIT3,0,0},	// S_DRAGON_INIT2
+{SPR_DRAG,0,5,A_DragonInitFlight,S_DRAGON_WALK1,0,0},	// S_DRAGON_INIT3
+{SPR_DRAG,1,3,A_DragonFlap,S_DRAGON_WALK2,0,0},	// S_DRAGON_WALK1
+{SPR_DRAG,1,3,A_DragonFlight,S_DRAGON_WALK3,0,0},	// S_DRAGON_WALK2
+{SPR_DRAG,2,3,A_DragonFlight,S_DRAGON_WALK4,0,0},	// S_DRAGON_WALK3
+{SPR_DRAG,2,3,A_DragonFlight,S_DRAGON_WALK5,0,0},	// S_DRAGON_WALK4
+{SPR_DRAG,3,3,A_DragonFlight,S_DRAGON_WALK6,0,0},	// S_DRAGON_WALK5
+{SPR_DRAG,3,3,A_DragonFlight,S_DRAGON_WALK7,0,0},	// S_DRAGON_WALK6
+{SPR_DRAG,2,3,A_DragonFlight,S_DRAGON_WALK8,0,0},	// S_DRAGON_WALK7
+{SPR_DRAG,2,3,A_DragonFlight,S_DRAGON_WALK9,0,0},	// S_DRAGON_WALK8
+{SPR_DRAG,1,3,A_DragonFlight,S_DRAGON_WALK10,0,0},	// S_DRAGON_WALK9
+{SPR_DRAG,1,3,A_DragonFlight,S_DRAGON_WALK11,0,0},	// S_DRAGON_WALK10
+{SPR_DRAG,0,3,A_DragonFlight,S_DRAGON_WALK12,0,0},	// S_DRAGON_WALK11
+{SPR_DRAG,0,3,A_DragonFlight,S_DRAGON_WALK1,0,0},	// S_DRAGON_WALK12
+{SPR_DRAG,4,8,A_DragonAttack,S_DRAGON_WALK1,0,0},	// S_DRAGON_ATK1
+{SPR_DRAG,5,10,A_DragonPain,S_DRAGON_WALK1,0,0},	// S_DRAGON_PAIN1
+{SPR_DRAG,6,5,A_Scream,S_DRAGON_DEATH2,0,0},	// S_DRAGON_DEATH1
+{SPR_DRAG,7,4,A_NoBlocking,S_DRAGON_DEATH3,0,0},	// S_DRAGON_DEATH2
+{SPR_DRAG,8,4,NULL,S_DRAGON_DEATH4,0,0},	// S_DRAGON_DEATH3
+{SPR_DRAG,9,4,A_DragonCheckCrash,S_DRAGON_DEATH4,0,0},	// S_DRAGON_DEATH4
+{SPR_DRAG,10,5,NULL,S_DRAGON_CRASH2,0,0},	// S_DRAGON_CRASH1
+{SPR_DRAG,11,5,NULL,S_DRAGON_CRASH3,0,0},	// S_DRAGON_CRASH2
+{SPR_DRAG,12,-1,NULL,S_NULL,0,0},	// S_DRAGON_CRASH3
+{SPR_DRFX,32768,4,NULL,S_DRAGON_FX1_2,0,0},	// S_DRAGON_FX1_1
+{SPR_DRFX,32769,4,NULL,S_DRAGON_FX1_3,0,0},	// S_DRAGON_FX1_2
+{SPR_DRFX,32770,4,NULL,S_DRAGON_FX1_4,0,0},	// S_DRAGON_FX1_3
+{SPR_DRFX,32771,4,NULL,S_DRAGON_FX1_5,0,0},	// S_DRAGON_FX1_4
+{SPR_DRFX,32772,4,NULL,S_DRAGON_FX1_6,0,0},	// S_DRAGON_FX1_5
+{SPR_DRFX,32773,4,NULL,S_DRAGON_FX1_1,0,0},	// S_DRAGON_FX1_6
+{SPR_DRFX,32774,4,NULL,S_DRAGON_FX1_X2,0,0},	// S_DRAGON_FX1_X1
+{SPR_DRFX,32775,4,NULL,S_DRAGON_FX1_X3,0,0},	// S_DRAGON_FX1_X2
+{SPR_DRFX,32776,4,NULL,S_DRAGON_FX1_X4,0,0},	// S_DRAGON_FX1_X3
+{SPR_DRFX,32777,4,A_DragonFX2,S_DRAGON_FX1_X5,0,0},	// S_DRAGON_FX1_X4
+{SPR_DRFX,32778,3,NULL,S_DRAGON_FX1_X6,0,0},	// S_DRAGON_FX1_X5
+{SPR_DRFX,32779,3,NULL,S_NULL,0,0},	// S_DRAGON_FX1_X6
+{SPR_CFCF,32784,1,NULL,S_DRAGON_FX2_2,0,0},	// S_DRAGON_FX2_1
+{SPR_CFCF,32784,4,A_UnHideThing,S_DRAGON_FX2_3,0,0},	// S_DRAGON_FX2_2
+{SPR_CFCF,32785,3,A_Scream,S_DRAGON_FX2_4,0,0},	// S_DRAGON_FX2_3
+{SPR_CFCF,32786,4,NULL,S_DRAGON_FX2_5,0,0},	// S_DRAGON_FX2_4
+{SPR_CFCF,32787,3,A_Explode,S_DRAGON_FX2_6,0,0},	// S_DRAGON_FX2_5
+{SPR_CFCF,32788,4,NULL,S_DRAGON_FX2_7,0,0},	// S_DRAGON_FX2_6
+{SPR_CFCF,32789,3,NULL,S_DRAGON_FX2_8,0,0},	// S_DRAGON_FX2_7
+{SPR_CFCF,32790,4,NULL,S_DRAGON_FX2_9,0,0},	// S_DRAGON_FX2_8
+{SPR_CFCF,32791,3,NULL,S_DRAGON_FX2_10,0,0},	// S_DRAGON_FX2_9
+{SPR_CFCF,32792,4,NULL,S_DRAGON_FX2_11,0,0},	// S_DRAGON_FX2_10
+{SPR_CFCF,32793,3,NULL,S_NULL,0,0},	// S_DRAGON_FX2_11
+{SPR_ARM1,0,-1,NULL,S_NULL,0,0},	// S_ARMOR_1
+{SPR_ARM2,0,-1,NULL,S_NULL,0,0},	// S_ARMOR_2
+{SPR_ARM3,0,-1,NULL,S_NULL,0,0},	// S_ARMOR_3
+{SPR_ARM4,0,-1,NULL,S_NULL,0,0},	// S_ARMOR_4
+{SPR_MAN1,32768,4,NULL,S_MANA1_2,0,0},	// S_MANA1_1
+{SPR_MAN1,32769,4,NULL,S_MANA1_3,0,0},	// S_MANA1_2
+{SPR_MAN1,32770,4,NULL,S_MANA1_4,0,0},	// S_MANA1_3
+{SPR_MAN1,32771,4,NULL,S_MANA1_5,0,0},	// S_MANA1_4
+{SPR_MAN1,32772,4,NULL,S_MANA1_6,0,0},	// S_MANA1_5
+{SPR_MAN1,32773,4,NULL,S_MANA1_7,0,0},	// S_MANA1_6
+{SPR_MAN1,32774,4,NULL,S_MANA1_8,0,0},	// S_MANA1_7
+{SPR_MAN1,32775,4,NULL,S_MANA1_9,0,0},	// S_MANA1_8
+{SPR_MAN1,32776,4,NULL,S_MANA1_1,0,0},	// S_MANA1_9
+{SPR_MAN2,32768,4,NULL,S_MANA2_2,0,0},	// S_MANA2_1
+{SPR_MAN2,32769,4,NULL,S_MANA2_3,0,0},	// S_MANA2_2
+{SPR_MAN2,32770,4,NULL,S_MANA2_4,0,0},	// S_MANA2_3
+{SPR_MAN2,32771,4,NULL,S_MANA2_5,0,0},	// S_MANA2_4
+{SPR_MAN2,32772,4,NULL,S_MANA2_6,0,0},	// S_MANA2_5
+{SPR_MAN2,32773,4,NULL,S_MANA2_7,0,0},	// S_MANA2_6
+{SPR_MAN2,32774,4,NULL,S_MANA2_8,0,0},	// S_MANA2_7
+{SPR_MAN2,32775,4,NULL,S_MANA2_9,0,0},	// S_MANA2_8
+{SPR_MAN2,32776,4,NULL,S_MANA2_10,0,0},	// S_MANA2_9
+{SPR_MAN2,32777,4,NULL,S_MANA2_11,0,0},	// S_MANA2_10
+{SPR_MAN2,32778,4,NULL,S_MANA2_12,0,0},	// S_MANA2_11
+{SPR_MAN2,32779,4,NULL,S_MANA2_13,0,0},	// S_MANA2_12
+{SPR_MAN2,32780,4,NULL,S_MANA2_14,0,0},	// S_MANA2_13
+{SPR_MAN2,32781,4,NULL,S_MANA2_15,0,0},	// S_MANA2_14
+{SPR_MAN2,32782,4,NULL,S_MANA2_16,0,0},	// S_MANA2_15
+{SPR_MAN2,32783,4,NULL,S_MANA2_1,0,0},	// S_MANA2_16
+{SPR_MAN3,32768,4,NULL,S_MANA3_2,0,0},	// S_MANA3_1
+{SPR_MAN3,32769,4,NULL,S_MANA3_3,0,0},	// S_MANA3_2
+{SPR_MAN3,32770,4,NULL,S_MANA3_4,0,0},	// S_MANA3_3
+{SPR_MAN3,32771,4,NULL,S_MANA3_5,0,0},	// S_MANA3_4
+{SPR_MAN3,32772,4,NULL,S_MANA3_6,0,0},	// S_MANA3_5
+{SPR_MAN3,32773,4,NULL,S_MANA3_7,0,0},	// S_MANA3_6
+{SPR_MAN3,32774,4,NULL,S_MANA3_8,0,0},	// S_MANA3_7
+{SPR_MAN3,32775,4,NULL,S_MANA3_9,0,0},	// S_MANA3_8
+{SPR_MAN3,32776,4,NULL,S_MANA3_10,0,0},	// S_MANA3_9
+{SPR_MAN3,32777,4,NULL,S_MANA3_11,0,0},	// S_MANA3_10
+{SPR_MAN3,32778,4,NULL,S_MANA3_12,0,0},	// S_MANA3_11
+{SPR_MAN3,32779,4,NULL,S_MANA3_13,0,0},	// S_MANA3_12
+{SPR_MAN3,32780,4,NULL,S_MANA3_14,0,0},	// S_MANA3_13
+{SPR_MAN3,32781,4,NULL,S_MANA3_15,0,0},	// S_MANA3_14
+{SPR_MAN3,32782,4,NULL,S_MANA3_16,0,0},	// S_MANA3_15
+{SPR_MAN3,32783,4,NULL,S_MANA3_1,0,0},	// S_MANA3_16
+{SPR_KEY1,0,-1,NULL,S_NULL,0,0},	// S_KEY1
+{SPR_KEY2,0,-1,NULL,S_NULL,0,0},	// S_KEY2
+{SPR_KEY3,0,-1,NULL,S_NULL,0,0},	// S_KEY3
+{SPR_KEY4,0,-1,NULL,S_NULL,0,0},	// S_KEY4
+{SPR_KEY5,0,-1,NULL,S_NULL,0,0},	// S_KEY5
+{SPR_KEY6,0,-1,NULL,S_NULL,0,0},	// S_KEY6
+{SPR_KEY7,0,-1,NULL,S_NULL,0,0},	// S_KEY7
+{SPR_KEY8,0,-1,NULL,S_NULL,0,0},	// S_KEY8
+{SPR_KEY9,0,-1,NULL,S_NULL,0,0},	// S_KEY9
+{SPR_KEYA,0,-1,NULL,S_NULL,0,0},	// S_KEYA
+{SPR_KEYB,0,-1,NULL,S_NULL,0,0},	// S_KEYB
+{SPR_TLGL,0,1,NULL,S_SND_WIND2,0,0},	// S_SND_WIND1
+{SPR_TLGL,0,200,A_ESound,S_SND_WIND2,0,0},	// S_SND_WIND2
+{SPR_TLGL,0,85,A_ESound,S_SND_WATERFALL,0,0},	// S_SND_WATERFALL
+{SPR_ETTN,0,10,A_Look,S_ETTIN_LOOK2,0,0},	// S_ETTIN_LOOK1
+{SPR_ETTN,0,10,A_Look,S_ETTIN_LOOK1,0,0},	// S_ETTIN_LOOK2
+{SPR_ETTN,0,5,A_Chase,S_ETTIN_CHASE2,0,0},	// S_ETTIN_CHASE1
+{SPR_ETTN,1,5,A_Chase,S_ETTIN_CHASE3,0,0},	// S_ETTIN_CHASE2
+{SPR_ETTN,2,5,A_Chase,S_ETTIN_CHASE4,0,0},	// S_ETTIN_CHASE3
+{SPR_ETTN,3,5,A_Chase,S_ETTIN_CHASE1,0,0},	// S_ETTIN_CHASE4
+{SPR_ETTN,7,7,A_Pain,S_ETTIN_CHASE1,0,0},	// S_ETTIN_PAIN1
+{SPR_ETTN,4,6,A_FaceTarget,S_ETTIN_ATK1_2,0,0},	// S_ETTIN_ATK1_1
+{SPR_ETTN,5,6,A_FaceTarget,S_ETTIN_ATK1_3,0,0},	// S_ETTIN_ATK1_2
+{SPR_ETTN,6,8,A_EttinAttack,S_ETTIN_CHASE1,0,0},	// S_ETTIN_ATK1_3
+{SPR_ETTN,8,4,NULL,S_ETTIN_DEATH1_2,0,0},	// S_ETTIN_DEATH1_1
+{SPR_ETTN,9,4,NULL,S_ETTIN_DEATH1_3,0,0},	// S_ETTIN_DEATH1_2
+{SPR_ETTN,10,4,A_Scream,S_ETTIN_DEATH1_4,0,0},	// S_ETTIN_DEATH1_3
+{SPR_ETTN,11,4,A_NoBlocking,S_ETTIN_DEATH1_5,0,0},	// S_ETTIN_DEATH1_4
+{SPR_ETTN,12,4,A_QueueCorpse,S_ETTIN_DEATH1_6,0,0},	// S_ETTIN_DEATH1_5
+{SPR_ETTN,13,4,NULL,S_ETTIN_DEATH1_7,0,0},	// S_ETTIN_DEATH1_6
+{SPR_ETTN,14,4,NULL,S_ETTIN_DEATH1_8,0,0},	// S_ETTIN_DEATH1_7
+{SPR_ETTN,15,4,NULL,S_ETTIN_DEATH1_9,0,0},	// S_ETTIN_DEATH1_8
+{SPR_ETTN,16,-1,NULL,S_NULL,0,0},	// S_ETTIN_DEATH1_9
+{SPR_ETTB,0,4,NULL,S_ETTIN_DEATH2_2,0,0},	// S_ETTIN_DEATH2_1
+{SPR_ETTB,1,4,A_NoBlocking,S_ETTIN_DEATH2_3,0,0},	// S_ETTIN_DEATH2_2
+{SPR_ETTB,2,4,A_DropMace,S_ETTIN_DEATH2_4,0,0},	// S_ETTIN_DEATH2_3
+{SPR_ETTB,3,4,A_Scream,S_ETTIN_DEATH2_5,0,0},	// S_ETTIN_DEATH2_4
+{SPR_ETTB,4,4,A_QueueCorpse,S_ETTIN_DEATH2_6,0,0},	// S_ETTIN_DEATH2_5
+{SPR_ETTB,5,4,NULL,S_ETTIN_DEATH2_7,0,0},	// S_ETTIN_DEATH2_6
+{SPR_ETTB,6,4,NULL,S_ETTIN_DEATH2_8,0,0},	// S_ETTIN_DEATH2_7
+{SPR_ETTB,7,4,NULL,S_ETTIN_DEATH2_9,0,0},	// S_ETTIN_DEATH2_8
+{SPR_ETTB,8,4,NULL,S_ETTIN_DEATH2_0,0,0},	// S_ETTIN_DEATH2_9
+{SPR_ETTB,9,4,NULL,S_ETTIN_DEATH2_A,0,0},	// S_ETTIN_DEATH2_0
+{SPR_ETTB,10,4,NULL,S_ETTIN_DEATH2_B,0,0},	// S_ETTIN_DEATH2_A
+{SPR_ETTB,11,-1,NULL,S_NULL,0,0},	// S_ETTIN_DEATH2_B
+{SPR_ETTN,17,5,A_FreezeDeath,S_ETTIN_ICE2,0,0},	// S_ETTIN_ICE1
+{SPR_ETTN,17,1,A_FreezeDeathChunks,S_ETTIN_ICE2,0,0},	// S_ETTIN_ICE2
+{SPR_ETTB,12,5,A_CheckFloor,S_ETTIN_MACE2,0,0},	// S_ETTIN_MACE1
+{SPR_ETTB,13,5,A_CheckFloor,S_ETTIN_MACE3,0,0},	// S_ETTIN_MACE2
+{SPR_ETTB,14,5,A_CheckFloor,S_ETTIN_MACE4,0,0},	// S_ETTIN_MACE3
+{SPR_ETTB,15,5,A_CheckFloor,S_ETTIN_MACE1,0,0},	// S_ETTIN_MACE4
+{SPR_ETTB,16,5,NULL,S_ETTIN_MACE6,0,0},	// S_ETTIN_MACE5
+{SPR_ETTB,17,5,A_QueueCorpse,S_ETTIN_MACE7,0,0},	// S_ETTIN_MACE6
+{SPR_ETTB,18,-1,NULL,S_NULL,0,0},	// S_ETTIN_MACE7
+{SPR_FDMN,32791,5,NULL,S_FIRED_LOOK1,0,0},	// S_FIRED_SPAWN1
+{SPR_FDMN,32772,10,A_Look,S_FIRED_LOOK2,0,0},	// S_FIRED_LOOK1
+{SPR_FDMN,32773,10,A_Look,S_FIRED_LOOK3,0,0},	// S_FIRED_LOOK2
+{SPR_FDMN,32774,10,A_Look,S_FIRED_LOOK1,0,0},	// S_FIRED_LOOK3
+{SPR_FDMN,32772,8,NULL,S_FIRED_LOOK5,0,0},	// S_FIRED_LOOK4
+{SPR_FDMN,32773,6,NULL,S_FIRED_LOOK6,0,0},	// S_FIRED_LOOK5
+{SPR_FDMN,32774,5,NULL,S_FIRED_LOOK7,0,0},	// S_FIRED_LOOK6
+{SPR_FDMN,32773,8,NULL,S_FIRED_LOOK8,0,0},	// S_FIRED_LOOK7
+{SPR_FDMN,32772,6,NULL,S_FIRED_LOOK9,0,0},	// S_FIRED_LOOK8
+{SPR_FDMN,32773,7,A_FiredRocks,S_FIRED_LOOK0,0,0},	// S_FIRED_LOOK9
+{SPR_FDMN,32775,5,NULL,S_FIRED_LOOKA,0,0},	// S_FIRED_LOOK0
+{SPR_FDMN,32776,5,NULL,S_FIRED_LOOKB,0,0},	// S_FIRED_LOOKA
+{SPR_FDMN,32777,5,A_UnSetInvulnerable,S_FIRED_WALK1,0,0},	// S_FIRED_LOOKB
+{SPR_FDMN,32768,5,A_FiredChase,S_FIRED_WALK2,0,0},	// S_FIRED_WALK1
+{SPR_FDMN,32769,5,A_FiredChase,S_FIRED_WALK3,0,0},	// S_FIRED_WALK2
+{SPR_FDMN,32770,5,A_FiredChase,S_FIRED_WALK1,0,0},	// S_FIRED_WALK3
+{SPR_FDMN,32771,6,A_Pain,S_FIRED_WALK1,0,0},	// S_FIRED_PAIN1
+{SPR_FDMN,32778,3,A_FaceTarget,S_FIRED_ATTACK2,0,0},	// S_FIRED_ATTACK1
+{SPR_FDMN,32778,5,A_FiredAttack,S_FIRED_ATTACK3,0,0},	// S_FIRED_ATTACK2
+{SPR_FDMN,32778,5,A_FiredAttack,S_FIRED_ATTACK4,0,0},	// S_FIRED_ATTACK3
+{SPR_FDMN,32778,5,A_FiredAttack,S_FIRED_WALK1,0,0},	// S_FIRED_ATTACK4
+{SPR_FDMN,32771,4,A_FaceTarget,S_FIRED_DEATH2,0,0},	// S_FIRED_DEATH1
+{SPR_FDMN,32779,4,A_Scream,S_FIRED_DEATH3,0,0},	// S_FIRED_DEATH2
+{SPR_FDMN,32779,4,A_NoBlocking,S_FIRED_DEATH4,0,0},	// S_FIRED_DEATH3
+{SPR_FDMN,32779,200,NULL,S_NULL,0,0},	// S_FIRED_DEATH4
+{SPR_FDMN,12,5,A_FaceTarget,S_FIRED_XDEATH2,0,0},	// S_FIRED_XDEATH1
+{SPR_FDMN,13,5,A_NoBlocking,S_FIRED_XDEATH3,0,0},	// S_FIRED_XDEATH2
+{SPR_FDMN,14,5,A_FiredSplotch,S_NULL,0,0},	// S_FIRED_XDEATH3
+{SPR_FDMN,17,5,A_FreezeDeath,S_FIRED_ICE2,0,0},	// S_FIRED_ICE1
+{SPR_FDMN,17,1,A_FreezeDeathChunks,S_FIRED_ICE2,0,0},	// S_FIRED_ICE2
+{SPR_FDMN,15,3,NULL,S_FIRED_CORPSE2,0,0},	// S_FIRED_CORPSE1
+{SPR_FDMN,15,6,A_QueueCorpse,S_FIRED_CORPSE3,0,0},	// S_FIRED_CORPSE2
+{SPR_FDMN,24,-1,NULL,S_NULL,0,0},	// S_FIRED_CORPSE3
+{SPR_FDMN,16,3,NULL,S_FIRED_CORPSE5,0,0},	// S_FIRED_CORPSE4
+{SPR_FDMN,16,6,A_QueueCorpse,S_FIRED_CORPSE6,0,0},	// S_FIRED_CORPSE5
+{SPR_FDMN,25,-1,NULL,S_NULL,0,0},	// S_FIRED_CORPSE6
+{SPR_FDMN,18,4,NULL,S_FIRED_RDROP1,0,0},	// S_FIRED_RDROP1
+{SPR_FDMN,18,5,A_SmBounce,S_FIRED_RDEAD1_2,0,0},	// S_FIRED_RDEAD1_1
+{SPR_FDMN,18,200,NULL,S_NULL,0,0},	// S_FIRED_RDEAD1_2
+{SPR_FDMN,19,4,NULL,S_FIRED_RDROP2,0,0},	// S_FIRED_RDROP2
+{SPR_FDMN,19,5,A_SmBounce,S_FIRED_RDEAD2_2,0,0},	// S_FIRED_RDEAD2_1
+{SPR_FDMN,19,200,NULL,S_NULL,0,0},	// S_FIRED_RDEAD2_2
+{SPR_FDMN,20,4,NULL,S_FIRED_RDROP3,0,0},	// S_FIRED_RDROP3
+{SPR_FDMN,20,5,A_SmBounce,S_FIRED_RDEAD3_2,0,0},	// S_FIRED_RDEAD3_1
+{SPR_FDMN,20,200,NULL,S_NULL,0,0},	// S_FIRED_RDEAD3_2
+{SPR_FDMN,21,4,NULL,S_FIRED_RDROP4,0,0},	// S_FIRED_RDROP4
+{SPR_FDMN,21,5,A_SmBounce,S_FIRED_RDEAD4_2,0,0},	// S_FIRED_RDEAD4_1
+{SPR_FDMN,21,200,NULL,S_NULL,0,0},	// S_FIRED_RDEAD4_2
+{SPR_FDMN,22,4,NULL,S_FIRED_RDROP5,0,0},	// S_FIRED_RDROP5
+{SPR_FDMN,22,5,A_SmBounce,S_FIRED_RDEAD5_2,0,0},	// S_FIRED_RDEAD5_1
+{SPR_FDMN,22,200,NULL,S_NULL,0,0},	// S_FIRED_RDEAD5_2
+{SPR_FDMB,32768,5,NULL,S_FIRED_FX6_1,0,0},	// S_FIRED_FX6_1
+{SPR_FDMB,32769,5,NULL,S_FIRED_FX6_3,0,0},	// S_FIRED_FX6_2
+{SPR_FDMB,32770,5,NULL,S_FIRED_FX6_4,0,0},	// S_FIRED_FX6_3
+{SPR_FDMB,32771,5,NULL,S_FIRED_FX6_5,0,0},	// S_FIRED_FX6_4
+{SPR_FDMB,32772,5,NULL,S_NULL,0,0},	// S_FIRED_FX6_5
+{SPR_ICEY,0,10,A_IceGuyLook,S_ICEGUY_LOOK,0,0},	// S_ICEGUY_LOOK
+{SPR_ICEY,0,-1,NULL,S_ICEGUY_LOOK,0,0},	// S_ICEGUY_DORMANT
+{SPR_ICEY,0,4,A_Chase,S_ICEGUY_WALK2,0,0},	// S_ICEGUY_WALK1
+{SPR_ICEY,1,4,A_IceGuyChase,S_ICEGUY_WALK3,0,0},	// S_ICEGUY_WALK2
+{SPR_ICEY,2,4,A_Chase,S_ICEGUY_WALK4,0,0},	// S_ICEGUY_WALK3
+{SPR_ICEY,3,4,A_Chase,S_ICEGUY_WALK1,0,0},	// S_ICEGUY_WALK4
+{SPR_ICEY,4,3,A_FaceTarget,S_ICEGUY_ATK2,0,0},	// S_ICEGUY_ATK1
+{SPR_ICEY,5,3,A_FaceTarget,S_ICEGUY_ATK3,0,0},	// S_ICEGUY_ATK2
+{SPR_ICEY,32774,8,A_IceGuyAttack,S_ICEGUY_ATK4,0,0},	// S_ICEGUY_ATK3
+{SPR_ICEY,5,4,A_FaceTarget,S_ICEGUY_WALK1,0,0},	// S_ICEGUY_ATK4
+{SPR_ICEY,0,1,A_Pain,S_ICEGUY_WALK1,0,0},	// S_ICEGUY_PAIN1
+{SPR_ICEY,0,1,A_IceGuyDie,S_NULL,0,0},	// S_ICEGUY_DEATH
+{SPR_ICPR,32768,3,A_IceGuyMissilePuff,S_ICEGUY_FX2,0,0},	// S_ICEGUY_FX1
+{SPR_ICPR,32769,3,A_IceGuyMissilePuff,S_ICEGUY_FX3,0,0},	// S_ICEGUY_FX2
+{SPR_ICPR,32770,3,A_IceGuyMissilePuff,S_ICEGUY_FX1,0,0},	// S_ICEGUY_FX3
+{SPR_ICPR,32771,4,NULL,S_ICEGUY_FX_X2,0,0},	// S_ICEGUY_FX_X1
+{SPR_ICPR,32772,4,A_IceGuyMissileExplode,S_ICEGUY_FX_X3,0,0},	// S_ICEGUY_FX_X2
+{SPR_ICPR,32773,4,NULL,S_ICEGUY_FX_X4,0,0},	// S_ICEGUY_FX_X3
+{SPR_ICPR,32774,4,NULL,S_ICEGUY_FX_X5,0,0},	// S_ICEGUY_FX_X4
+{SPR_ICPR,32775,3,NULL,S_NULL,0,0},	// S_ICEGUY_FX_X5
+{SPR_ICPR,8,3,NULL,S_ICEFX_PUFF2,0,0},	// S_ICEFX_PUFF1
+{SPR_ICPR,9,3,NULL,S_ICEFX_PUFF3,0,0},	// S_ICEFX_PUFF2
+{SPR_ICPR,10,3,NULL,S_ICEFX_PUFF4,0,0},	// S_ICEFX_PUFF3
+{SPR_ICPR,11,2,NULL,S_ICEFX_PUFF5,0,0},	// S_ICEFX_PUFF4
+{SPR_ICPR,12,2,NULL,S_NULL,0,0},	// S_ICEFX_PUFF5
+{SPR_ICPR,32781,3,NULL,S_ICEGUY_FX2_2,0,0},	// S_ICEGUY_FX2_1
+{SPR_ICPR,32782,3,NULL,S_ICEGUY_FX2_3,0,0},	// S_ICEGUY_FX2_2
+{SPR_ICPR,32783,3,NULL,S_ICEGUY_FX2_1,0,0},	// S_ICEGUY_FX2_3
+{SPR_ICPR,32784,50,NULL,S_NULL,0,0},	// S_ICEGUY_BIT1
+{SPR_ICPR,32785,50,NULL,S_NULL,0,0},	// S_ICEGUY_BIT2
+{SPR_ICWS,0,2,NULL,S_ICEGUY_WISP1_2,0,0},	// S_ICEGUY_WISP1_1
+{SPR_ICWS,1,2,NULL,S_ICEGUY_WISP1_3,0,0},	// S_ICEGUY_WISP1_2
+{SPR_ICWS,2,2,NULL,S_ICEGUY_WISP1_4,0,0},	// S_ICEGUY_WISP1_3
+{SPR_ICWS,3,2,NULL,S_ICEGUY_WISP1_5,0,0},	// S_ICEGUY_WISP1_4
+{SPR_ICWS,4,2,NULL,S_ICEGUY_WISP1_6,0,0},	// S_ICEGUY_WISP1_5
+{SPR_ICWS,5,2,NULL,S_ICEGUY_WISP1_7,0,0},	// S_ICEGUY_WISP1_6
+{SPR_ICWS,6,2,NULL,S_ICEGUY_WISP1_8,0,0},	// S_ICEGUY_WISP1_7
+{SPR_ICWS,7,2,NULL,S_ICEGUY_WISP1_9,0,0},	// S_ICEGUY_WISP1_8
+{SPR_ICWS,8,2,NULL,S_NULL,0,0},	// S_ICEGUY_WISP1_9
+{SPR_ICWS,9,2,NULL,S_ICEGUY_WISP2_2,0,0},	// S_ICEGUY_WISP2_1
+{SPR_ICWS,10,2,NULL,S_ICEGUY_WISP2_3,0,0},	// S_ICEGUY_WISP2_2
+{SPR_ICWS,11,2,NULL,S_ICEGUY_WISP2_4,0,0},	// S_ICEGUY_WISP2_3
+{SPR_ICWS,12,2,NULL,S_ICEGUY_WISP2_5,0,0},	// S_ICEGUY_WISP2_4
+{SPR_ICWS,13,2,NULL,S_ICEGUY_WISP2_6,0,0},	// S_ICEGUY_WISP2_5
+{SPR_ICWS,14,2,NULL,S_ICEGUY_WISP2_7,0,0},	// S_ICEGUY_WISP2_6
+{SPR_ICWS,15,2,NULL,S_ICEGUY_WISP2_8,0,0},	// S_ICEGUY_WISP2_7
+{SPR_ICWS,16,2,NULL,S_ICEGUY_WISP2_9,0,0},	// S_ICEGUY_WISP2_8
+{SPR_ICWS,17,2,NULL,S_NULL,0,0},	// S_ICEGUY_WISP2_9
+{SPR_PLAY,0,2,NULL,S_FIGHTER2,0,0},	// S_FIGHTER
+{SPR_PLAY,0,3,A_ClassBossHealth,S_FIGHTERLOOK,0,0},	// S_FIGHTER2
+{SPR_PLAY,0,5,A_Look,S_FIGHTERLOOK,0,0},	// S_FIGHTERLOOK
+{SPR_PLAY,0,4,A_FastChase,S_FIGHTER_RUN2,0,0},	// S_FIGHTER_RUN1
+{SPR_PLAY,1,4,A_FastChase,S_FIGHTER_RUN3,0,0},	// S_FIGHTER_RUN2
+{SPR_PLAY,2,4,A_FastChase,S_FIGHTER_RUN4,0,0},	// S_FIGHTER_RUN3
+{SPR_PLAY,3,4,A_FastChase,S_FIGHTER_RUN1,0,0},	// S_FIGHTER_RUN4
+{SPR_PLAY,4,8,A_FaceTarget,S_FIGHTER_ATK2,0,0},	// S_FIGHTER_ATK1
+{SPR_PLAY,5,8,A_FighterAttack,S_FIGHTER_RUN1,0,0},	// S_FIGHTER_ATK2
+{SPR_PLAY,6,4,NULL,S_FIGHTER_PAIN2,0,0},	// S_FIGHTER_PAIN
+{SPR_PLAY,6,4,A_Pain,S_FIGHTER_RUN1,0,0},	// S_FIGHTER_PAIN2
+{SPR_PLAY,7,6,NULL,S_FIGHTER_DIE2,0,0},	// S_FIGHTER_DIE1
+{SPR_PLAY,8,6,A_Scream,S_FIGHTER_DIE3,0,0},	// S_FIGHTER_DIE2
+{SPR_PLAY,9,6,NULL,S_FIGHTER_DIE4,0,0},	// S_FIGHTER_DIE3
+{SPR_PLAY,10,6,NULL,S_FIGHTER_DIE5,0,0},	// S_FIGHTER_DIE4
+{SPR_PLAY,11,6,A_NoBlocking,S_FIGHTER_DIE6,0,0},	// S_FIGHTER_DIE5
+{SPR_PLAY,12,6,NULL,S_FIGHTER_DIE7,0,0},	// S_FIGHTER_DIE6
+{SPR_PLAY,13,-1,NULL,S_NULL,0,0},	// S_FIGHTER_DIE7
+{SPR_PLAY,14,5,A_Scream,S_FIGHTER_XDIE2,0,0},	// S_FIGHTER_XDIE1
+{SPR_PLAY,15,5,A_SkullPop,S_FIGHTER_XDIE3,0,0},	// S_FIGHTER_XDIE2
+{SPR_PLAY,17,5,A_NoBlocking,S_FIGHTER_XDIE4,0,0},	// S_FIGHTER_XDIE3
+{SPR_PLAY,18,5,NULL,S_FIGHTER_XDIE5,0,0},	// S_FIGHTER_XDIE4
+{SPR_PLAY,19,5,NULL,S_FIGHTER_XDIE6,0,0},	// S_FIGHTER_XDIE5
+{SPR_PLAY,20,5,NULL,S_FIGHTER_XDIE7,0,0},	// S_FIGHTER_XDIE6
+{SPR_PLAY,21,5,NULL,S_FIGHTER_XDIE8,0,0},	// S_FIGHTER_XDIE7
+{SPR_PLAY,22,-1,NULL,S_NULL,0,0},	// S_FIGHTER_XDIE8
+{SPR_PLAY,23,5,A_FreezeDeath,S_FIGHTER_ICE2,0,0},	// S_FIGHTER_ICE
+{SPR_PLAY,23,1,A_FreezeDeathChunks,S_FIGHTER_ICE2,0,0},	// S_FIGHTER_ICE2
+{SPR_CLER,0,2,NULL,S_CLERIC2,0,0},	// S_CLERIC
+{SPR_CLER,0,3,A_ClassBossHealth,S_CLERICLOOK,0,0},	// S_CLERIC2
+{SPR_CLER,0,5,A_Look,S_CLERICLOOK,0,0},	// S_CLERICLOOK
+{SPR_CLER,0,4,A_FastChase,S_CLERIC_RUN2,0,0},	// S_CLERIC_RUN1
+{SPR_CLER,1,4,A_FastChase,S_CLERIC_RUN3,0,0},	// S_CLERIC_RUN2
+{SPR_CLER,2,4,A_FastChase,S_CLERIC_RUN4,0,0},	// S_CLERIC_RUN3
+{SPR_CLER,3,4,A_FastChase,S_CLERIC_RUN1,0,0},	// S_CLERIC_RUN4
+{SPR_CLER,4,8,A_FaceTarget,S_CLERIC_ATK2,0,0},	// S_CLERIC_ATK1
+{SPR_CLER,5,8,A_FaceTarget,S_CLERIC_ATK3,0,0},	// S_CLERIC_ATK2
+{SPR_CLER,6,10,A_ClericAttack,S_CLERIC_RUN1,0,0},	// S_CLERIC_ATK3
+{SPR_CLER,7,4,NULL,S_CLERIC_PAIN2,0,0},	// S_CLERIC_PAIN
+{SPR_CLER,7,4,A_Pain,S_CLERIC_RUN1,0,0},	// S_CLERIC_PAIN2
+{SPR_CLER,8,6,NULL,S_CLERIC_DIE2,0,0},	// S_CLERIC_DIE1
+{SPR_CLER,10,6,A_Scream,S_CLERIC_DIE3,0,0},	// S_CLERIC_DIE2
+{SPR_CLER,11,6,NULL,S_CLERIC_DIE4,0,0},	// S_CLERIC_DIE3
+{SPR_CLER,11,6,NULL,S_CLERIC_DIE5,0,0},	// S_CLERIC_DIE4
+{SPR_CLER,12,6,A_NoBlocking,S_CLERIC_DIE6,0,0},	// S_CLERIC_DIE5
+{SPR_CLER,13,6,NULL,S_CLERIC_DIE7,0,0},	// S_CLERIC_DIE6
+{SPR_CLER,14,6,NULL,S_CLERIC_DIE8,0,0},	// S_CLERIC_DIE7
+{SPR_CLER,15,6,NULL,S_CLERIC_DIE9,0,0},	// S_CLERIC_DIE8
+{SPR_CLER,16,-1,NULL,S_NULL,0,0},	// S_CLERIC_DIE9
+{SPR_CLER,17,5,A_Scream,S_CLERIC_XDIE2,0,0},	// S_CLERIC_XDIE1
+{SPR_CLER,18,5,NULL,S_CLERIC_XDIE3,0,0},	// S_CLERIC_XDIE2
+{SPR_CLER,19,5,A_NoBlocking,S_CLERIC_XDIE4,0,0},	// S_CLERIC_XDIE3
+{SPR_CLER,20,5,NULL,S_CLERIC_XDIE5,0,0},	// S_CLERIC_XDIE4
+{SPR_CLER,21,5,NULL,S_CLERIC_XDIE6,0,0},	// S_CLERIC_XDIE5
+{SPR_CLER,22,5,NULL,S_CLERIC_XDIE7,0,0},	// S_CLERIC_XDIE6
+{SPR_CLER,23,5,NULL,S_CLERIC_XDIE8,0,0},	// S_CLERIC_XDIE7
+{SPR_CLER,24,5,NULL,S_CLERIC_XDIE9,0,0},	// S_CLERIC_XDIE8
+{SPR_CLER,25,5,NULL,S_CLERIC_XDIE10,0,0},	// S_CLERIC_XDIE9
+{SPR_CLER,26,-1,NULL,S_NULL,0,0},	// S_CLERIC_XDIE10
+{SPR_CLER,27,5,A_FreezeDeath,S_CLERIC_ICE2,0,0},	// S_CLERIC_ICE
+{SPR_CLER,27,1,A_FreezeDeathChunks,S_CLERIC_ICE2,0,0},	// S_CLERIC_ICE2
+{SPR_MAGE,0,2,NULL,S_MAGE2,0,0},	// S_MAGE
+{SPR_MAGE,0,3,A_ClassBossHealth,S_MAGELOOK,0,0},	// S_MAGE2
+{SPR_MAGE,0,5,A_Look,S_MAGELOOK,0,0},	// S_MAGELOOK
+{SPR_MAGE,0,4,A_FastChase,S_MAGE_RUN2,0,0},	// S_MAGE_RUN1
+{SPR_MAGE,1,4,A_FastChase,S_MAGE_RUN3,0,0},	// S_MAGE_RUN2
+{SPR_MAGE,2,4,A_FastChase,S_MAGE_RUN4,0,0},	// S_MAGE_RUN3
+{SPR_MAGE,3,4,A_FastChase,S_MAGE_RUN1,0,0},	// S_MAGE_RUN4
+{SPR_MAGE,4,8,A_FaceTarget,S_MAGE_ATK2,0,0},	// S_MAGE_ATK1
+{SPR_MAGE,32773,8,A_MageAttack,S_MAGE_RUN1,0,0},	// S_MAGE_ATK2
+{SPR_MAGE,6,4,NULL,S_MAGE_PAIN2,0,0},	// S_MAGE_PAIN
+{SPR_MAGE,6,4,A_Pain,S_MAGE_RUN1,0,0},	// S_MAGE_PAIN2
+{SPR_MAGE,7,6,NULL,S_MAGE_DIE2,0,0},	// S_MAGE_DIE1
+{SPR_MAGE,8,6,A_Scream,S_MAGE_DIE3,0,0},	// S_MAGE_DIE2
+{SPR_MAGE,9,6,NULL,S_MAGE_DIE4,0,0},	// S_MAGE_DIE3
+{SPR_MAGE,10,6,NULL,S_MAGE_DIE5,0,0},	// S_MAGE_DIE4
+{SPR_MAGE,11,6,A_NoBlocking,S_MAGE_DIE6,0,0},	// S_MAGE_DIE5
+{SPR_MAGE,12,6,NULL,S_MAGE_DIE7,0,0},	// S_MAGE_DIE6
+{SPR_MAGE,13,-1,NULL,S_NULL,0,0},	// S_MAGE_DIE7
+{SPR_MAGE,14,5,A_Scream,S_MAGE_XDIE2,0,0},	// S_MAGE_XDIE1
+{SPR_MAGE,15,5,NULL,S_MAGE_XDIE3,0,0},	// S_MAGE_XDIE2
+{SPR_MAGE,17,5,A_NoBlocking,S_MAGE_XDIE4,0,0},	// S_MAGE_XDIE3
+{SPR_MAGE,18,5,NULL,S_MAGE_XDIE5,0,0},	// S_MAGE_XDIE4
+{SPR_MAGE,19,5,NULL,S_MAGE_XDIE6,0,0},	// S_MAGE_XDIE5
+{SPR_MAGE,20,5,NULL,S_MAGE_XDIE7,0,0},	// S_MAGE_XDIE6
+{SPR_MAGE,21,5,NULL,S_MAGE_XDIE8,0,0},	// S_MAGE_XDIE7
+{SPR_MAGE,22,5,NULL,S_MAGE_XDIE9,0,0},	// S_MAGE_XDIE8
+{SPR_MAGE,23,-1,NULL,S_NULL,0,0},	// S_MAGE_XDIE9
+{SPR_MAGE,24,5,A_FreezeDeath,S_MAGE_ICE2,0,0},	// S_MAGE_ICE
+{SPR_MAGE,24,1,A_FreezeDeathChunks,S_MAGE_ICE2,0,0},	// S_MAGE_ICE2
+{SPR_SORC,0,3,NULL,S_SORC_SPAWN2,0,0},	// S_SORC_SPAWN1
+{SPR_SORC,0,2,A_SorcSpinBalls,S_SORC_LOOK1,0,0},	// S_SORC_SPAWN2
+{SPR_SORC,0,10,A_Look,S_SORC_LOOK1,0,0},	// S_SORC_LOOK1
+{SPR_SORC,0,5,A_Chase,S_SORC_WALK2,0,0},	// S_SORC_WALK1
+{SPR_SORC,1,5,A_Chase,S_SORC_WALK3,0,0},	// S_SORC_WALK2
+{SPR_SORC,2,5,A_Chase,S_SORC_WALK4,0,0},	// S_SORC_WALK3
+{SPR_SORC,3,5,A_Chase,S_SORC_WALK1,0,0},	// S_SORC_WALK4
+{SPR_SORC,6,8,NULL,S_SORC_PAIN2,0,0},	// S_SORC_PAIN1
+{SPR_SORC,6,8,A_Pain,S_SORC_WALK1,0,0},	// S_SORC_PAIN2
+{SPR_SORC,32773,6,A_FaceTarget,S_SORC_ATK2_2,0,0},	// S_SORC_ATK2_1
+{SPR_SORC,32773,6,A_SpeedBalls,S_SORC_ATK2_3,0,0},	// S_SORC_ATK2_2
+{SPR_SORC,32773,6,A_FaceTarget,S_SORC_ATK2_3,0,0},	// S_SORC_ATK2_3
+{SPR_SORC,32772,6,NULL,S_SORC_ATTACK2,0,0},	// S_SORC_ATTACK1
+{SPR_SORC,32772,6,A_SpawnFizzle,S_SORC_ATTACK3,0,0},	// S_SORC_ATTACK2
+{SPR_SORC,32772,5,A_FaceTarget,S_SORC_ATTACK2,0,0},	// S_SORC_ATTACK3
+{SPR_SORC,32772,2,NULL,S_SORC_ATTACK5,0,0},	// S_SORC_ATTACK4
+{SPR_SORC,32772,2,A_SorcBossAttack,S_SORC_WALK1,0,0},	// S_SORC_ATTACK5
+{SPR_SORC,32775,5,NULL,S_SORC_DIE2,0,0},	// S_SORC_DIE1
+{SPR_SORC,32776,5,A_FaceTarget,S_SORC_DIE3,0,0},	// S_SORC_DIE2
+{SPR_SORC,32777,5,A_Scream,S_SORC_DIE4,0,0},	// S_SORC_DIE3
+{SPR_SORC,32778,5,NULL,S_SORC_DIE5,0,0},	// S_SORC_DIE4
+{SPR_SORC,32779,5,NULL,S_SORC_DIE6,0,0},	// S_SORC_DIE5
+{SPR_SORC,32780,5,NULL,S_SORC_DIE7,0,0},	// S_SORC_DIE6
+{SPR_SORC,32781,5,NULL,S_SORC_DIE8,0,0},	// S_SORC_DIE7
+{SPR_SORC,32782,5,NULL,S_SORC_DIE9,0,0},	// S_SORC_DIE8
+{SPR_SORC,32783,5,NULL,S_SORC_DIE0,0,0},	// S_SORC_DIE9
+{SPR_SORC,32784,5,NULL,S_SORC_DIEA,0,0},	// S_SORC_DIE0
+{SPR_SORC,32785,5,NULL,S_SORC_DIEB,0,0},	// S_SORC_DIEA
+{SPR_SORC,32786,5,NULL,S_SORC_DIEC,0,0},	// S_SORC_DIEB
+{SPR_SORC,32787,5,NULL,S_SORC_DIED,0,0},	// S_SORC_DIEC
+{SPR_SORC,32788,5,A_NoBlocking,S_SORC_DIEE,0,0},	// S_SORC_DIED
+{SPR_SORC,32789,5,NULL,S_SORC_DIEF,0,0},	// S_SORC_DIEE
+{SPR_SORC,32790,5,NULL,S_SORC_DIEG,0,0},	// S_SORC_DIEF
+{SPR_SORC,32791,5,NULL,S_SORC_DIEH,0,0},	// S_SORC_DIEG
+{SPR_SORC,32792,5,NULL,S_SORC_DIEI,0,0},	// S_SORC_DIEH
+{SPR_SORC,32793,-1,NULL,S_NULL,0,0},	// S_SORC_DIEI
+{SPR_SBMP,0,2,A_SorcBallOrbit,S_SORCBALL1_2,0,0},	// S_SORCBALL1_1
+{SPR_SBMP,1,2,A_SorcBallOrbit,S_SORCBALL1_3,0,0},	// S_SORCBALL1_2
+{SPR_SBMP,2,2,A_SorcBallOrbit,S_SORCBALL1_4,0,0},	// S_SORCBALL1_3
+{SPR_SBMP,3,2,A_SorcBallOrbit,S_SORCBALL1_5,0,0},	// S_SORCBALL1_4
+{SPR_SBMP,4,2,A_SorcBallOrbit,S_SORCBALL1_6,0,0},	// S_SORCBALL1_5
+{SPR_SBMP,5,2,A_SorcBallOrbit,S_SORCBALL1_7,0,0},	// S_SORCBALL1_6
+{SPR_SBMP,6,2,A_SorcBallOrbit,S_SORCBALL1_8,0,0},	// S_SORCBALL1_7
+{SPR_SBMP,7,2,A_SorcBallOrbit,S_SORCBALL1_9,0,0},	// S_SORCBALL1_8
+{SPR_SBMP,8,2,A_SorcBallOrbit,S_SORCBALL1_0,0,0},	// S_SORCBALL1_9
+{SPR_SBMP,9,2,A_SorcBallOrbit,S_SORCBALL1_A,0,0},	// S_SORCBALL1_0
+{SPR_SBMP,10,2,A_SorcBallOrbit,S_SORCBALL1_B,0,0},	// S_SORCBALL1_A
+{SPR_SBMP,11,2,A_SorcBallOrbit,S_SORCBALL1_C,0,0},	// S_SORCBALL1_B
+{SPR_SBMP,12,2,A_SorcBallOrbit,S_SORCBALL1_D,0,0},	// S_SORCBALL1_C
+{SPR_SBMP,13,2,A_SorcBallOrbit,S_SORCBALL1_E,0,0},	// S_SORCBALL1_D
+{SPR_SBMP,14,2,A_SorcBallOrbit,S_SORCBALL1_F,0,0},	// S_SORCBALL1_E
+{SPR_SBMP,15,2,A_SorcBallOrbit,S_SORCBALL1_1,0,0},	// S_SORCBALL1_F
+{SPR_SBMP,0,5,A_SorcBallPop,S_SORCBALL1_D2,0,0},	// S_SORCBALL1_D1
+{SPR_SBMP,1,2,A_BounceCheck,S_SORCBALL1_D2,0,0},	// S_SORCBALL1_D2
+{SPR_SBS4,3,5,A_Explode,S_SORCBALL1_D6,0,0},	// S_SORCBALL1_D5
+{SPR_SBS4,4,5,NULL,S_SORCBALL1_D7,0,0},	// S_SORCBALL1_D6
+{SPR_SBS4,5,6,NULL,S_SORCBALL1_D8,0,0},	// S_SORCBALL1_D7
+{SPR_SBS4,6,6,NULL,S_SORCBALL1_D9,0,0},	// S_SORCBALL1_D8
+{SPR_SBS4,7,6,NULL,S_NULL,0,0},	// S_SORCBALL1_D9
+{SPR_SBMB,0,2,A_SorcBallOrbit,S_SORCBALL2_2,0,0},	// S_SORCBALL2_1
+{SPR_SBMB,1,2,A_SorcBallOrbit,S_SORCBALL2_3,0,0},	// S_SORCBALL2_2
+{SPR_SBMB,2,2,A_SorcBallOrbit,S_SORCBALL2_4,0,0},	// S_SORCBALL2_3
+{SPR_SBMB,3,2,A_SorcBallOrbit,S_SORCBALL2_5,0,0},	// S_SORCBALL2_4
+{SPR_SBMB,4,2,A_SorcBallOrbit,S_SORCBALL2_6,0,0},	// S_SORCBALL2_5
+{SPR_SBMB,5,2,A_SorcBallOrbit,S_SORCBALL2_7,0,0},	// S_SORCBALL2_6
+{SPR_SBMB,6,2,A_SorcBallOrbit,S_SORCBALL2_8,0,0},	// S_SORCBALL2_7
+{SPR_SBMB,7,2,A_SorcBallOrbit,S_SORCBALL2_9,0,0},	// S_SORCBALL2_8
+{SPR_SBMB,8,2,A_SorcBallOrbit,S_SORCBALL2_0,0,0},	// S_SORCBALL2_9
+{SPR_SBMB,9,2,A_SorcBallOrbit,S_SORCBALL2_A,0,0},	// S_SORCBALL2_0
+{SPR_SBMB,10,2,A_SorcBallOrbit,S_SORCBALL2_B,0,0},	// S_SORCBALL2_A
+{SPR_SBMB,11,2,A_SorcBallOrbit,S_SORCBALL2_C,0,0},	// S_SORCBALL2_B
+{SPR_SBMB,12,2,A_SorcBallOrbit,S_SORCBALL2_D,0,0},	// S_SORCBALL2_C
+{SPR_SBMB,13,2,A_SorcBallOrbit,S_SORCBALL2_E,0,0},	// S_SORCBALL2_D
+{SPR_SBMB,14,2,A_SorcBallOrbit,S_SORCBALL2_F,0,0},	// S_SORCBALL2_E
+{SPR_SBMB,15,2,A_SorcBallOrbit,S_SORCBALL2_1,0,0},	// S_SORCBALL2_F
+{SPR_SBMB,0,5,A_SorcBallPop,S_SORCBALL2_D2,0,0},	// S_SORCBALL2_D1
+{SPR_SBMB,1,2,A_BounceCheck,S_SORCBALL2_D2,0,0},	// S_SORCBALL2_D2
+{SPR_SBS3,3,5,A_Explode,S_SORCBALL2_D6,0,0},	// S_SORCBALL2_D5
+{SPR_SBS3,4,5,NULL,S_SORCBALL2_D7,0,0},	// S_SORCBALL2_D6
+{SPR_SBS3,5,6,NULL,S_SORCBALL2_D8,0,0},	// S_SORCBALL2_D7
+{SPR_SBS3,6,6,NULL,S_SORCBALL2_D9,0,0},	// S_SORCBALL2_D8
+{SPR_SBS3,7,6,NULL,S_NULL,0,0},	// S_SORCBALL2_D9
+{SPR_SBMG,0,2,A_SorcBallOrbit,S_SORCBALL3_2,0,0},	// S_SORCBALL3_1
+{SPR_SBMG,1,2,A_SorcBallOrbit,S_SORCBALL3_3,0,0},	// S_SORCBALL3_2
+{SPR_SBMG,2,2,A_SorcBallOrbit,S_SORCBALL3_4,0,0},	// S_SORCBALL3_3
+{SPR_SBMG,3,2,A_SorcBallOrbit,S_SORCBALL3_5,0,0},	// S_SORCBALL3_4
+{SPR_SBMG,4,2,A_SorcBallOrbit,S_SORCBALL3_6,0,0},	// S_SORCBALL3_5
+{SPR_SBMG,5,2,A_SorcBallOrbit,S_SORCBALL3_7,0,0},	// S_SORCBALL3_6
+{SPR_SBMG,6,2,A_SorcBallOrbit,S_SORCBALL3_8,0,0},	// S_SORCBALL3_7
+{SPR_SBMG,7,2,A_SorcBallOrbit,S_SORCBALL3_9,0,0},	// S_SORCBALL3_8
+{SPR_SBMG,8,2,A_SorcBallOrbit,S_SORCBALL3_0,0,0},	// S_SORCBALL3_9
+{SPR_SBMG,9,2,A_SorcBallOrbit,S_SORCBALL3_A,0,0},	// S_SORCBALL3_0
+{SPR_SBMG,10,2,A_SorcBallOrbit,S_SORCBALL3_B,0,0},	// S_SORCBALL3_A
+{SPR_SBMG,11,2,A_SorcBallOrbit,S_SORCBALL3_C,0,0},	// S_SORCBALL3_B
+{SPR_SBMG,12,2,A_SorcBallOrbit,S_SORCBALL3_D,0,0},	// S_SORCBALL3_C
+{SPR_SBMG,13,2,A_SorcBallOrbit,S_SORCBALL3_E,0,0},	// S_SORCBALL3_D
+{SPR_SBMG,14,2,A_SorcBallOrbit,S_SORCBALL3_F,0,0},	// S_SORCBALL3_E
+{SPR_SBMG,15,2,A_SorcBallOrbit,S_SORCBALL3_1,0,0},	// S_SORCBALL3_F
+{SPR_SBMG,0,5,A_SorcBallPop,S_SORCBALL3_D2,0,0},	// S_SORCBALL3_D1
+{SPR_SBMG,1,2,A_BounceCheck,S_SORCBALL3_D2,0,0},	// S_SORCBALL3_D2
+{SPR_SBS3,3,5,A_Explode,S_SORCBALL3_D6,0,0},	// S_SORCBALL3_D5
+{SPR_SBS3,4,5,NULL,S_SORCBALL3_D7,0,0},	// S_SORCBALL3_D6
+{SPR_SBS3,5,6,NULL,S_SORCBALL3_D8,0,0},	// S_SORCBALL3_D7
+{SPR_SBS3,6,6,NULL,S_SORCBALL3_D9,0,0},	// S_SORCBALL3_D8
+{SPR_SBS3,7,6,NULL,S_NULL,0,0},	// S_SORCBALL3_D9
+{SPR_SBS1,32768,2,NULL,S_SORCFX1_2,0,0},	// S_SORCFX1_1
+{SPR_SBS1,32769,3,A_SorcFX1Seek,S_SORCFX1_3,0,0},	// S_SORCFX1_2
+{SPR_SBS1,32770,3,A_SorcFX1Seek,S_SORCFX1_4,0,0},	// S_SORCFX1_3
+{SPR_SBS1,32771,3,A_SorcFX1Seek,S_SORCFX1_1,0,0},	// S_SORCFX1_4
+{SPR_FHFX,32786,2,A_Explode,S_SORCFX1_D2,0,0},	// S_SORCFX1_D1
+{SPR_FHFX,32786,6,NULL,S_SORCFX1_D3,0,0},	// S_SORCFX1_D2
+{SPR_FHFX,32786,6,NULL,S_NULL,0,0},	// S_SORCFX1_D3
+{SPR_SBS2,32768,3,A_SorcFX2Split,S_SORCFX2_SPLIT1,0,0},	// S_SORCFX2_SPLIT1
+{SPR_SBS2,32768,2,A_SorcFX2Orbit,S_SORCFX2_ORBIT2,0,0},	// S_SORCFX2_ORBIT1
+{SPR_SBS2,32769,2,A_SorcFX2Orbit,S_SORCFX2_ORBIT3,0,0},	// S_SORCFX2_ORBIT2
+{SPR_SBS2,32770,2,A_SorcFX2Orbit,S_SORCFX2_ORBIT4,0,0},	// S_SORCFX2_ORBIT3
+{SPR_SBS2,32771,2,A_SorcFX2Orbit,S_SORCFX2_ORBIT5,0,0},	// S_SORCFX2_ORBIT4
+{SPR_SBS2,32772,2,A_SorcFX2Orbit,S_SORCFX2_ORBIT6,0,0},	// S_SORCFX2_ORBIT5
+{SPR_SBS2,32773,2,A_SorcFX2Orbit,S_SORCFX2_ORBIT7,0,0},	// S_SORCFX2_ORBIT6
+{SPR_SBS2,32774,2,A_SorcFX2Orbit,S_SORCFX2_ORBIT8,0,0},	// S_SORCFX2_ORBIT7
+{SPR_SBS2,32775,2,A_SorcFX2Orbit,S_SORCFX2_ORBIT9,0,0},	// S_SORCFX2_ORBIT8
+{SPR_SBS2,32776,2,A_SorcFX2Orbit,S_SORCFX2_ORBIT0,0,0},	// S_SORCFX2_ORBIT9
+{SPR_SBS2,32777,2,A_SorcFX2Orbit,S_SORCFX2_ORBITA,0,0},	// S_SORCFX2_ORBIT0
+{SPR_SBS2,32778,2,A_SorcFX2Orbit,S_SORCFX2_ORBITB,0,0},	// S_SORCFX2_ORBITA
+{SPR_SBS2,32779,2,A_SorcFX2Orbit,S_SORCFX2_ORBITC,0,0},	// S_SORCFX2_ORBITB
+{SPR_SBS2,32780,2,A_SorcFX2Orbit,S_SORCFX2_ORBITD,0,0},	// S_SORCFX2_ORBITC
+{SPR_SBS2,32781,2,A_SorcFX2Orbit,S_SORCFX2_ORBITE,0,0},	// S_SORCFX2_ORBITD
+{SPR_SBS2,32782,2,A_SorcFX2Orbit,S_SORCFX2_ORBITF,0,0},	// S_SORCFX2_ORBITE
+{SPR_SBS2,32783,2,A_SorcFX2Orbit,S_SORCFX2_ORBIT1,0,0},	// S_SORCFX2_ORBITF
+{SPR_SBS2,0,10,NULL,S_NULL,0,0},	// S_SORCFX2T1
+{SPR_SBS3,32768,2,NULL,S_SORCFX3_2,0,0},	// S_SORCFX3_1
+{SPR_SBS3,32769,2,NULL,S_SORCFX3_3,0,0},	// S_SORCFX3_2
+{SPR_SBS3,32770,2,NULL,S_SORCFX3_1,0,0},	// S_SORCFX3_3
+{SPR_SBS3,32768,4,NULL,S_BISHMORPHA,0,0},	// S_BISHMORPH1
+{SPR_BISH,15,4,A_SorcererBishopEntry,S_BISHMORPHB,0,0},	// S_BISHMORPHA
+{SPR_BISH,14,4,NULL,S_BISHMORPHC,0,0},	// S_BISHMORPHB
+{SPR_BISH,13,4,NULL,S_BISHMORPHD,0,0},	// S_BISHMORPHC
+{SPR_BISH,12,3,NULL,S_BISHMORPHE,0,0},	// S_BISHMORPHD
+{SPR_BISH,11,3,NULL,S_BISHMORPHF,0,0},	// S_BISHMORPHE
+{SPR_BISH,10,3,NULL,S_BISHMORPHG,0,0},	// S_BISHMORPHF
+{SPR_BISH,9,3,NULL,S_BISHMORPHH,0,0},	// S_BISHMORPHG
+{SPR_BISH,8,3,NULL,S_BISHMORPHI,0,0},	// S_BISHMORPHH
+{SPR_BISH,7,3,NULL,S_BISHMORPHJ,0,0},	// S_BISHMORPHI
+{SPR_BISH,6,3,A_SpawnBishop,S_NULL,0,0},	// S_BISHMORPHJ
+{SPR_SBS3,3,3,NULL,S_SORCFX3_EXP2,0,0},	// S_SORCFX3_EXP1
+{SPR_SBS3,4,3,NULL,S_SORCFX3_EXP3,0,0},	// S_SORCFX3_EXP2
+{SPR_SBS3,5,3,NULL,S_SORCFX3_EXP4,0,0},	// S_SORCFX3_EXP3
+{SPR_SBS3,6,3,NULL,S_SORCFX3_EXP5,0,0},	// S_SORCFX3_EXP4
+{SPR_SBS3,7,3,NULL,S_NULL,0,0},	// S_SORCFX3_EXP5
+{SPR_SBS4,32768,2,A_SorcFX4Check,S_SORCFX4_2,0,0},	// S_SORCFX4_1
+{SPR_SBS4,32769,2,A_SorcFX4Check,S_SORCFX4_3,0,0},	// S_SORCFX4_2
+{SPR_SBS4,32770,2,A_SorcFX4Check,S_SORCFX4_1,0,0},	// S_SORCFX4_3
+{SPR_SBS4,32771,2,NULL,S_SORCFX4_D2,0,0},	// S_SORCFX4_D1
+{SPR_SBS4,32772,2,A_Explode,S_SORCFX4_D3,0,0},	// S_SORCFX4_D2
+{SPR_SBS4,32773,2,NULL,S_SORCFX4_D4,0,0},	// S_SORCFX4_D3
+{SPR_SBS4,32774,2,NULL,S_SORCFX4_D5,0,0},	// S_SORCFX4_D4
+{SPR_SBS4,32775,2,NULL,S_NULL,0,0},	// S_SORCFX4_D5
+{SPR_SBFX,32768,4,NULL,S_SORCSPARK2,0,0},	// S_SORCSPARK1
+{SPR_SBFX,32769,4,NULL,S_SORCSPARK3,0,0},	// S_SORCSPARK2
+{SPR_SBFX,32770,4,NULL,S_SORCSPARK4,0,0},	// S_SORCSPARK3
+{SPR_SBFX,32771,4,NULL,S_SORCSPARK5,0,0},	// S_SORCSPARK4
+{SPR_SBFX,32772,4,NULL,S_SORCSPARK6,0,0},	// S_SORCSPARK5
+{SPR_SBFX,32773,4,NULL,S_SORCSPARK7,0,0},	// S_SORCSPARK6
+{SPR_SBFX,32774,4,NULL,S_NULL,0,0},	// S_SORCSPARK7
+{SPR_RADE,0,4,NULL,S_BLASTEFFECT2,0,0},	// S_BLASTEFFECT1
+{SPR_RADE,1,4,NULL,S_BLASTEFFECT3,0,0},	// S_BLASTEFFECT2
+{SPR_RADE,2,4,NULL,S_BLASTEFFECT4,0,0},	// S_BLASTEFFECT3
+{SPR_RADE,3,4,NULL,S_BLASTEFFECT5,0,0},	// S_BLASTEFFECT4
+{SPR_RADE,4,4,NULL,S_BLASTEFFECT6,0,0},	// S_BLASTEFFECT5
+{SPR_RADE,5,4,NULL,S_BLASTEFFECT7,0,0},	// S_BLASTEFFECT6
+{SPR_RADE,6,4,NULL,S_BLASTEFFECT8,0,0},	// S_BLASTEFFECT7
+{SPR_RADE,7,4,NULL,S_BLASTEFFECT9,0,0},	// S_BLASTEFFECT8
+{SPR_RADE,8,4,NULL,S_NULL,0,0},	// S_BLASTEFFECT9
+{SPR_WATR,0,5,NULL,S_WATERDRIP1,0,0},	// S_WATERDRIP1
+{SPR_KORX,0,5,A_Look,S_KORAX_LOOK1,0,0},	// S_KORAX_LOOK1
+{SPR_KORX,0,3,A_KoraxStep2,S_KORAX_CHASE2,0,0},	// S_KORAX_CHASE1
+{SPR_KORX,0,3,A_KoraxChase,S_KORAX_CHASE3,0,0},	// S_KORAX_CHASE2
+{SPR_KORX,0,3,A_KoraxChase,S_KORAX_CHASE4,0,0},	// S_KORAX_CHASE3
+{SPR_KORX,0,3,A_KoraxChase,S_KORAX_CHASE5,0,0},	// S_KORAX_CHASE4
+{SPR_KORX,1,3,A_KoraxStep,S_KORAX_CHASE6,0,0},	// S_KORAX_CHASE5
+{SPR_KORX,1,3,A_KoraxChase,S_KORAX_CHASE7,0,0},	// S_KORAX_CHASE6
+{SPR_KORX,1,3,A_KoraxChase,S_KORAX_CHASE8,0,0},	// S_KORAX_CHASE7
+{SPR_KORX,1,3,A_KoraxChase,S_KORAX_CHASE9,0,0},	// S_KORAX_CHASE8
+{SPR_KORX,2,3,A_KoraxStep2,S_KORAX_CHASE0,0,0},	// S_KORAX_CHASE9
+{SPR_KORX,2,3,A_KoraxChase,S_KORAX_CHASEA,0,0},	// S_KORAX_CHASE0
+{SPR_KORX,2,3,A_KoraxChase,S_KORAX_CHASEB,0,0},	// S_KORAX_CHASEA
+{SPR_KORX,2,3,A_KoraxChase,S_KORAX_CHASEC,0,0},	// S_KORAX_CHASEB
+{SPR_KORX,3,3,A_KoraxStep,S_KORAX_CHASED,0,0},	// S_KORAX_CHASEC
+{SPR_KORX,3,3,A_KoraxChase,S_KORAX_CHASEE,0,0},	// S_KORAX_CHASED
+{SPR_KORX,3,3,A_KoraxChase,S_KORAX_CHASEF,0,0},	// S_KORAX_CHASEE
+{SPR_KORX,3,3,A_KoraxChase,S_KORAX_CHASE1,0,0},	// S_KORAX_CHASEF
+{SPR_KORX,7,5,A_Pain,S_KORAX_PAIN2,0,0},	// S_KORAX_PAIN1
+{SPR_KORX,7,5,NULL,S_KORAX_CHASE2,0,0},	// S_KORAX_PAIN2
+{SPR_KORX,32772,2,A_FaceTarget,S_KORAX_ATTACK2,0,0},	// S_KORAX_ATTACK1
+{SPR_KORX,32772,5,A_KoraxDecide,S_KORAX_ATTACK2,0,0},	// S_KORAX_ATTACK2
+{SPR_KORX,32772,4,A_FaceTarget,S_KORAX_MISSILE2,0,0},	// S_KORAX_MISSILE1
+{SPR_KORX,32773,8,A_KoraxMissile,S_KORAX_MISSILE3,0,0},	// S_KORAX_MISSILE2
+{SPR_KORX,32772,8,NULL,S_KORAX_CHASE2,0,0},	// S_KORAX_MISSILE3
+{SPR_KORX,32772,5,A_FaceTarget,S_KORAX_COMMAND2,0,0},	// S_KORAX_COMMAND1
+{SPR_KORX,32790,10,A_FaceTarget,S_KORAX_COMMAND3,0,0},	// S_KORAX_COMMAND2
+{SPR_KORX,32774,15,A_KoraxCommand,S_KORAX_COMMAND4,0,0},	// S_KORAX_COMMAND3
+{SPR_KORX,32790,10,NULL,S_KORAX_COMMAND5,0,0},	// S_KORAX_COMMAND4
+{SPR_KORX,32772,5,NULL,S_KORAX_CHASE2,0,0},	// S_KORAX_COMMAND5
+{SPR_KORX,8,5,NULL,S_KORAX_DEATH2,0,0},	// S_KORAX_DEATH1
+{SPR_KORX,9,5,A_FaceTarget,S_KORAX_DEATH3,0,0},	// S_KORAX_DEATH2
+{SPR_KORX,10,5,A_Scream,S_KORAX_DEATH4,0,0},	// S_KORAX_DEATH3
+{SPR_KORX,11,5,NULL,S_KORAX_DEATH5,0,0},	// S_KORAX_DEATH4
+{SPR_KORX,12,5,NULL,S_KORAX_DEATH6,0,0},	// S_KORAX_DEATH5
+{SPR_KORX,13,5,NULL,S_KORAX_DEATH7,0,0},	// S_KORAX_DEATH6
+{SPR_KORX,14,5,NULL,S_KORAX_DEATH8,0,0},	// S_KORAX_DEATH7
+{SPR_KORX,15,5,NULL,S_KORAX_DEATH9,0,0},	// S_KORAX_DEATH8
+{SPR_KORX,16,10,NULL,S_KORAX_DEATH0,0,0},	// S_KORAX_DEATH9
+{SPR_KORX,17,5,A_KoraxBonePop,S_KORAX_DEATHA,0,0},	// S_KORAX_DEATH0
+{SPR_KORX,18,5,A_NoBlocking,S_KORAX_DEATHB,0,0},	// S_KORAX_DEATHA
+{SPR_KORX,19,5,NULL,S_KORAX_DEATHC,0,0},	// S_KORAX_DEATHB
+{SPR_KORX,20,5,NULL,S_KORAX_DEATHD,0,0},	// S_KORAX_DEATHC
+{SPR_KORX,21,-1,NULL,S_NULL,0,0},	// S_KORAX_DEATHD
+{SPR_SPIR,0,5,A_KSpiritRoam,S_KSPIRIT_ROAM2,0,0},	// S_KSPIRIT_ROAM1
+{SPR_SPIR,1,5,A_KSpiritRoam,S_KSPIRIT_ROAM1,0,0},	// S_KSPIRIT_ROAM2
+{SPR_SPIR,3,5,NULL,S_KSPIRIT_DEATH2,0,0},	// S_KSPIRIT_DEATH1
+{SPR_SPIR,4,5,NULL,S_KSPIRIT_DEATH3,0,0},	// S_KSPIRIT_DEATH2
+{SPR_SPIR,5,5,NULL,S_KSPIRIT_DEATH4,0,0},	// S_KSPIRIT_DEATH3
+{SPR_SPIR,6,5,NULL,S_KSPIRIT_DEATH5,0,0},	// S_KSPIRIT_DEATH4
+{SPR_SPIR,7,5,NULL,S_KSPIRIT_DEATH6,0,0},	// S_KSPIRIT_DEATH5
+{SPR_SPIR,8,5,NULL,S_NULL,0,0},	// S_KSPIRIT_DEATH6
+{SPR_MLFX,32776,2,NULL,S_KBOLT2,0,0},	// S_KBOLT1
+{SPR_MLFX,32777,2,A_KBoltRaise,S_KBOLT3,0,0},	// S_KBOLT2
+{SPR_MLFX,32776,2,A_KBolt,S_KBOLT4,0,0},	// S_KBOLT3
+{SPR_MLFX,32777,2,A_KBolt,S_KBOLT5,0,0},	// S_KBOLT4
+{SPR_MLFX,32778,2,A_KBolt,S_KBOLT6,0,0},	// S_KBOLT5
+{SPR_MLFX,32779,2,A_KBolt,S_KBOLT7,0,0},	// S_KBOLT6
+{SPR_MLFX,32780,2,A_KBolt,S_KBOLT3,0,0},	// S_KBOLT7
+{SPR_MAN1,0,2,NULL,S_SPAWNBATS2,0,0},	// S_SPAWNBATS1
+{SPR_MAN1,0,2,A_BatSpawnInit,S_SPAWNBATS3,0,0},	// S_SPAWNBATS2
+{SPR_MAN1,0,2,A_BatSpawn,S_SPAWNBATS3,0,0},	// S_SPAWNBATS3
+{SPR_MAN1,0,-1,NULL,S_NULL,0,0},	// S_SPAWNBATS_OFF
+{SPR_ABAT,0,2,A_BatMove,S_BAT2,0,0},	// S_BAT1
+{SPR_ABAT,1,2,A_BatMove,S_BAT3,0,0},	// S_BAT2
+{SPR_ABAT,2,2,A_BatMove,S_BAT1,0,0},	// S_BAT3
+{SPR_ABAT,0,2,NULL,S_NULL,0,0},	// S_BAT_DEATH
+#ifdef ASSASSIN
+{SPR_AKTR,0,1,A_WeaponReady,S_KATARREADY,0,0},	// S_KATARREADY
+{SPR_AKTR,0,1,A_Lower,S_KATARDOWN,0,0},	// S_KATARDOWN
+{SPR_AKTR,0,1,A_Raise,S_KATARUP,0,0},	// S_KATARUP
+{SPR_AKTR,1,4,NULL,S_KATARATK1_2,5,40},	// S_KATARATK1_1
+{SPR_AKTR,2,3,NULL,S_KATARATK1_3,5,40},	// S_KATARATK1_2
+{SPR_AKTR,3,3,A_AKnifeAttack,S_KATARATK1_4,5,40},	// S_KATARATK1_3
+{SPR_AKTR,2,3,NULL,S_KATARATK1_5,5,40},	// S_KATARATK1_4
+{SPR_AKTR,1,5,A_ReFire,S_KATARREADY,5,40},	// S_KATARATK1_5
+{SPR_AKTR,3,4,NULL,S_KATARATK2_2,5,40},	// S_KATARATK2_1
+{SPR_AKTR,4,4,NULL,S_KATARATK2_3,5,40},	// S_KATARATK2_2
+{SPR_AKTR,4,1,NULL,S_KATARATK2_4,15,50},	// S_KATARATK2_3
+{SPR_AKTR,4,1,NULL,S_KATARATK2_5,25,60},	// S_KATARATK2_4
+{SPR_AKTR,4,1,NULL,S_KATARATK2_6,35,70},	// S_KATARATK2_5
+{SPR_AKTR,4,1,NULL,S_KATARATK2_7,45,80},	// S_KATARATK2_6
+{SPR_AKTR,4,1,NULL,S_KATARATK2_8,55,90},	// S_KATARATK2_7
+{SPR_AKTR,4,1,NULL,S_KATARATK2_9,65,100},	// S_KATARATK2_8
+{SPR_AKTR,4,10,NULL,S_KATARREADY,0,150},	// S_KATARATK2_9
+{SPR_ACSB,2,4,NULL,S_ACROSSREADY1,0,0},	// S_ACROSSREADY
+{SPR_ACSB,1,3,NULL,S_ACROSSREADY2,0,0},	// S_ACROSSREADY1
+{SPR_ACSB,0,1,A_WeaponReady,S_ACROSSREADY3,0,0},	// S_ACROSSREADY2
+{SPR_ACSB,0,1,A_WeaponReady,S_ACROSSREADY4,0,0},	// S_ACROSSREADY3
+{SPR_ACSB,0,1,A_WeaponReady,S_ACROSSREADY5,0,0},	// S_ACROSSREADY4
+{SPR_ACSB,0,1,A_WeaponReady,S_ACROSSREADY6,0,0},	// S_ACROSSREADY5
+{SPR_ACSB,0,1,A_WeaponReady,S_ACROSSREADY7,0,0},	// S_ACROSSREADY6
+{SPR_ACSB,0,1,A_WeaponReady,S_ACROSSREADY8,0,0},	// S_ACROSSREADY7
+{SPR_ACSB,0,1,A_WeaponReady,S_ACROSSREADY9,0,0},	// S_ACROSSREADY8
+{SPR_ACSB,0,1,NULL,S_ACROSSREADY2,0,0},	// S_ACROSSREADY9
+{SPR_ACSB,1,1,A_WeaponReady,S_ACROSSBLINK2,0,0},	// S_ACROSSBLINK1
+{SPR_ACSB,1,1,A_WeaponReady,S_ACROSSBLINK3,0,0},	// S_ACROSSBLINK2
+{SPR_ACSB,1,1,A_WeaponReady,S_ACROSSBLINK4,0,0},	// S_ACROSSBLINK3
+{SPR_ACSB,2,1,A_WeaponReady,S_ACROSSBLINK5,0,0},	// S_ACROSSBLINK4
+{SPR_ACSB,2,1,A_WeaponReady,S_ACROSSBLINK6,0,0},	// S_ACROSSBLINK5
+{SPR_ACSB,2,1,A_WeaponReady,S_ACROSSBLINK7,0,0},	// S_ACROSSBLINK6
+{SPR_ACSB,2,1,A_WeaponReady,S_ACROSSBLINK8,0,0},	// S_ACROSSBLINK7
+{SPR_ACSB,2,1,A_WeaponReady,S_ACROSSBLINK9,0,0},	// S_ACROSSBLINK8
+{SPR_ACSB,1,1,A_WeaponReady,S_ACROSSBLINK10,0,0},	// S_ACROSSBLINK9
+{SPR_ACSB,1,1,A_WeaponReady,S_ACROSSBLINK11,0,0},	// S_ACROSSBLINK10
+{SPR_ACSB,1,1,A_WeaponReady,S_ACROSSREADY2,0,0},	// S_ACROSSBLINK11
+{SPR_ACSB,1,3,NULL,S_ACROSSDOWN2,0,0},	// S_ACROSSDOWN
+{SPR_ACSB,2,4,NULL,S_ACROSSDOWN3,0,0},	// S_ACROSSDOWN2
+{SPR_ACSB,2,1,A_Lower,S_ACROSSDOWN3,0,0},	// S_ACROSSDOWN3
+{SPR_ACSB,2,1,A_Raise,S_ACROSSUP,0,0},	// S_ACROSSUP
+/* jim {SPR_ACSB,0,1,A_ACrossCheck,S_ACROSSATK_2,0,45},	// S_ACROSSATK_1 */
+{SPR_ACSB,0,1,NULL,S_ACROSSATK_2,0,45},        // S_ACROSSATK_1
+{SPR_ACSB,1,1,A_ACrossAttack,S_ACROSSATK_3,0,50},      // S_ACROSSATK_2
+{SPR_ACSB,1,2,NULL,S_ACROSSATK_4,0,50},        // S_ACROSSATK_3
+{SPR_ACSB,1,2,NULL,S_ACROSSATK_5,0,45},        // S_ACROSSATK_4
+{SPR_ACSB,0,2,NULL,S_ACROSSATK_6,0,40},        // S_ACROSSATK_5
+{SPR_ACSB,0,2,NULL,S_ACROSSREADY,0,36},        // S_ACROSSATK_6
+/* jim {SPR_ACSB,10,10,NULL,S_ACROSSREADY2,0,36},      // S_ACROSSATK2_1 */
+{SPR_ACSB,32771,1,NULL,S_ACROSS_MISSILE2,0,0},       // S_ACROSS_MISSILE1
+{SPR_ACSB,32771,1,NULL,S_ACROSS_MISSILE3,0,0},       // S_ACROSS_MISSILE2
+{SPR_ACSB,32772,1,NULL,S_ACROSS_MISSILE4,0,0},       // S_ACROSS_MISSILE3
+{SPR_ACSB,32772,1,NULL,S_ACROSS_MISSILE1,0,0},	// S_ACROSS_MISSILE4
+{SPR_ACSB,32773,4,NULL,S_ACROSS_MISSILE_X2,0,0},	// S_ACROSS_MISSILE_X1
+{SPR_ACSB,32774,4,NULL,S_ACROSS_MISSILE_X3,0,0},	// S_ACROSS_MISSILE_X2
+{SPR_ACSB,32775,3,NULL,S_ACROSS_MISSILE_X4,0,0},	// S_ACROSS_MISSILE_X3
+{SPR_ACSB,32776,3,NULL,S_NULL,0,0},	// S_ACROSS_MISSILE_X4
+{SPR_AGRN,0,1,A_WeaponReady,S_AGRENREADY,0,0},	// S_AGRENREADY
+{SPR_AGRN,0,1,A_Lower,S_AGRENDOWN,0,0},	// S_AGRENDOWN
+{SPR_AGRN,0,1,A_Raise,S_AGRENUP,0,0},	// S_AGRENUP
+{SPR_AGRN,0,6,NULL,S_AGRENATK_2,0,0},	// S_AGRENATK_1
+{SPR_AGRN,32769,6,A_AGrenAttack,S_AGRENATK_3,0,48},	// S_AGRENATK_2
+{SPR_AGRN,0,3,NULL,S_AGRENATK_4,0,40},	// S_AGRENATK_3
+{SPR_AGRN,0,3,A_ReFire,S_AGRENREADY,0,36},	// S_AGRENATK_4
+{SPR_AGRN,32772,4,NULL,S_AGRENPUFF2,0,0},	// S_AGRENPUFF1
+{SPR_AGRN,32773,3,NULL,S_AGRENPUFF3,0,0},	// S_AGRENPUFF2
+{SPR_AGRN,32774,4,NULL,S_AGRENPUFF4,0,0},	// S_AGRENPUFF3
+{SPR_AGRN,32775,3,NULL,S_AGRENPUFF5,0,0},	// S_AGRENPUFF4
+{SPR_AGRN,32776,4,NULL,S_NULL,0,0},	// S_AGRENPUFF5
+{SPR_AGRN,2,4,NULL,S_AGRENSMOKE2,0,0},	// S_AGRENSMOKE1
+{SPR_AGRN,3,4,NULL,S_AGRENSMOKE3,0,0},	// S_AGRENSMOKE2
+{SPR_AGRN,2,4,NULL,S_AGRENSMOKE4,0,0},	// S_AGRENSMOKE3
+{SPR_AGRN,3,4,NULL,S_NULL,0,0},	// S_AGRENSMOKE4
+{SPR_AGRN,32770,4,NULL,S_AGREN_MISSILE2,0,0},	// S_AGREN_MISSILE1
+{SPR_AGRN,32771,4,NULL,S_AGREN_MISSILE1,0,0},	// S_AGREN_MISSILE2
+{SPR_ASTF,0,1,A_WeaponReady,S_ASTAFFREADY2,0,0},	// S_ASTAFFREADY
+{SPR_ASTF,0,1,A_WeaponReady,S_ASTAFFREADY3,0,0},	// S_ASTAFFREADY2
+{SPR_ASTF,0,1,A_WeaponReady,S_ASTAFFREADY4,0,0},	// S_ASTAFFREADY3
+{SPR_ASTF,0,1,A_WeaponReady,S_ASTAFFREADY5,0,0},	// S_ASTAFFREADY4
+{SPR_ASTF,0,1,A_WeaponReady,S_ASTAFFREADY6,0,0},	// S_ASTAFFREADY5
+{SPR_ASTF,0,1,A_WeaponReady,S_ASTAFFREADY7,0,0},	// S_ASTAFFREADY6
+{SPR_ASTF,1,1,A_WeaponReady,S_ASTAFFREADY8,0,0},	// S_ASTAFFREADY7
+{SPR_ASTF,1,1,A_WeaponReady,S_ASTAFFREADY9,0,0},	// S_ASTAFFREADY8
+{SPR_ASTF,1,1,A_WeaponReady,S_ASTAFFREADY10,0,0},	// S_ASTAFFREADY9
+{SPR_ASTF,1,1,A_WeaponReady,S_ASTAFFREADY11,0,0},	// S_ASTAFFREADY10
+{SPR_ASTF,1,1,A_WeaponReady,S_ASTAFFREADY12,0,0},	// S_ASTAFFREADY11
+{SPR_ASTF,1,1,A_WeaponReady,S_ASTAFFREADY13,0,0},	// S_ASTAFFREADY12
+{SPR_ASTF,2,1,A_WeaponReady,S_ASTAFFREADY14,0,0},	// S_ASTAFFREADY13
+{SPR_ASTF,2,1,A_WeaponReady,S_ASTAFFREADY15,0,0},	// S_ASTAFFREADY14
+{SPR_ASTF,2,1,A_WeaponReady,S_ASTAFFREADY16,0,0},	// S_ASTAFFREADY15
+{SPR_ASTF,2,1,A_WeaponReady,S_ASTAFFREADY17,0,0},	// S_ASTAFFREADY16
+{SPR_ASTF,2,1,A_WeaponReady,S_ASTAFFREADY18,0,0},	// S_ASTAFFREADY17
+{SPR_ASTF,2,1,A_WeaponReady,S_ASTAFFREADY19,0,0},	// S_ASTAFFREADY18
+{SPR_ASTF,3,1,A_WeaponReady,S_ASTAFFREADY20,0,0},	// S_ASTAFFREADY19
+{SPR_ASTF,3,1,A_WeaponReady,S_ASTAFFREADY21,0,0},	// S_ASTAFFREADY20
+{SPR_ASTF,3,1,A_WeaponReady,S_ASTAFFREADY22,0,0},	// S_ASTAFFREADY21
+{SPR_ASTF,3,1,A_WeaponReady,S_ASTAFFREADY23,0,0},	// S_ASTAFFREADY22
+{SPR_ASTF,3,1,A_WeaponReady,S_ASTAFFREADY24,0,0},	// S_ASTAFFREADY23
+{SPR_ASTF,3,1,A_WeaponReady,S_ASTAFFREADY25,0,0},	// S_ASTAFFREADY24
+{SPR_ASTF,4,1,A_WeaponReady,S_ASTAFFREADY26,0,0},	// S_ASTAFFREADY25
+{SPR_ASTF,4,1,A_WeaponReady,S_ASTAFFREADY27,0,0},	// S_ASTAFFREADY26
+{SPR_ASTF,4,1,A_WeaponReady,S_ASTAFFREADY28,0,0},	// S_ASTAFFREADY27
+{SPR_ASTF,4,1,A_WeaponReady,S_ASTAFFREADY29,0,0},	// S_ASTAFFREADY28
+{SPR_ASTF,4,1,A_WeaponReady,S_ASTAFFREADY30,0,0},	// S_ASTAFFREADY29
+{SPR_ASTF,4,1,A_WeaponReady,S_ASTAFFREADY31,0,0},	// S_ASTAFFREADY30
+{SPR_ASTF,5,1,A_WeaponReady,S_ASTAFFREADY32,0,0},	// S_ASTAFFREADY31
+{SPR_ASTF,5,1,A_WeaponReady,S_ASTAFFREADY33,0,0},	// S_ASTAFFREADY32
+{SPR_ASTF,5,1,A_WeaponReady,S_ASTAFFREADY34,0,0},	// S_ASTAFFREADY33
+{SPR_ASTF,5,1,A_WeaponReady,S_ASTAFFREADY35,0,0},	// S_ASTAFFREADY34
+{SPR_ASTF,5,1,A_WeaponReady,S_ASTAFFREADY,0,0},	// S_ASTAFFREADY35
+{SPR_ASTF,0,1,A_Lower,S_ASTAFFDOWN,0,0},	// S_ASTAFFDOWN
+{SPR_ASTF,0,1,A_Raise,S_ASTAFFUP,0,0},	// S_ASTAFFUP
+{SPR_ASTF,6,4,NULL,S_ASTAFFATK_2,0,40},	// S_ASTAFFATK_1
+{SPR_ASTF,32775,4,A_AStaffAttack,S_ASTAFFATK_3,0,48},	// S_ASTAFFATK_2
+{SPR_ASTF,32775,2,NULL,S_ASTAFFATK_4,0,48},	// S_ASTAFFATK_3
+{SPR_ASTF,8,2,NULL,S_ASTAFFATK_5,0,48},	// S_ASTAFFATK_4
+{SPR_ASTF,8,2,NULL,S_ASTAFFATK_6,0,48},	// S_ASTAFFATK_5
+{SPR_ASTF,8,1,NULL,S_ASTAFFATK_7,0,40},	// S_ASTAFFATK_6
+{SPR_ASTF,9,5,NULL,S_ASTAFFREADY,0,36},	// S_ASTAFFATK_7
+{SPR_ASP1,32768,3,A_MStaffWeave,S_ASTAFF_FX1_2,0,0},	// S_ASTAFF_FX1_1
+{SPR_ASP1,32769,3,A_MStaffWeave,S_ASTAFF_FX1_3,0,0},	// S_ASTAFF_FX1_2
+{SPR_ASP1,32770,3,A_MStaffWeave,S_ASTAFF_FX1_4,0,0},	// S_ASTAFF_FX1_3
+{SPR_ASP1,32771,3,A_MStaffWeave,S_ASTAFF_FX1_5,0,0},	// S_ASTAFF_FX1_4
+{SPR_ASP1,32772,3,A_MStaffWeave,S_ASTAFF_FX1_6,0,0},	// S_ASTAFF_FX1_5
+{SPR_ASP1,32773,3,A_MStaffWeave,S_ASTAFF_FX1_1,0,0},	// S_ASTAFF_FX1_6
+{SPR_ASP1,32774,4,NULL,S_ASTAFF_FX_X2,0,0},	// S_ASTAFF_FX_X1
+{SPR_ASP1,32775,5,A_Explode,S_ASTAFF_FX_X3,0,0},	// S_ASTAFF_FX_X2
+{SPR_ASP1,32776,4,NULL,S_ASTAFF_FX_X4,0,0},	// S_ASTAFF_FX_X3
+{SPR_ASP1,32777,5,NULL,S_ASTAFF_FX_X5,0,0},	// S_ASTAFF_FX_X4
+{SPR_ASP1,32778,4,NULL,S_ASTAFF_FX_X6,0,0},	// S_ASTAFF_FX_X5
+{SPR_ASP1,32779,5,NULL,S_ASTAFF_FX_X7,0,0},	// S_ASTAFF_FX_X6
+{SPR_ASP1,32780,4,NULL,S_ASTAFF_FX_X8,0,0},	// S_ASTAFF_FX_X7
+{SPR_ASP1,32781,5,NULL,S_ASTAFF_FX_X9,0,0},	// S_ASTAFF_FX_X8
+{SPR_ASP1,32782,4,NULL,S_ASTAFF_FX_X10,0,0},	// S_ASTAFF_FX_X9
+{SPR_ASP1,32783,4,NULL,S_NULL,0,0},	// S_ASTAFF_FX_X10
+{SPR_ASP2,32768,2,A_MStaffTrack,S_ASTAFF_FX2_2,0,0},	// S_ASTAFF_FX2_1
+{SPR_ASP2,32769,2,A_MStaffTrack,S_ASTAFF_FX2_3,0,0},	// S_ASTAFF_FX2_2
+{SPR_ASP2,32770,2,A_MStaffTrack,S_ASTAFF_FX2_4,0,0},	// S_ASTAFF_FX2_3
+{SPR_ASP2,32771,2,A_MStaffTrack,S_ASTAFF_FX2_1,0,0},	// S_ASTAFF_FX2_4
+{SPR_ASP2,32772,4,NULL,S_ASTAFF_FX2_X2,0,0},	// S_ASTAFF_FX2_X1
+{SPR_ASP2,32773,5,A_Explode,S_ASTAFF_FX2_X3,0,0},	// S_ASTAFF_FX2_X2
+{SPR_ASP2,32774,5,NULL,S_ASTAFF_FX2_X4,0,0},	// S_ASTAFF_FX2_X3
+{SPR_ASP2,32775,5,NULL,S_ASTAFF_FX2_X5,0,0},	// S_ASTAFF_FX2_X4
+{SPR_ASP2,32776,4,NULL,S_NULL,0,0},	// S_ASTAFF_FX2_X5
+{SPR_ASSN,0,-1,NULL,S_NULL,0,0},	// S_APLAY
+{SPR_ASSN,0,4,NULL,S_APLAY_RUN2,0,0},	// S_APLAY_RUN1
+{SPR_ASSN,1,4,NULL,S_APLAY_RUN3,0,0},	// S_APLAY_RUN2
+{SPR_ASSN,2,4,NULL,S_APLAY_RUN4,0,0},	// S_APLAY_RUN3
+{SPR_ASSN,3,4,NULL,S_APLAY_RUN1,0,0},	// S_APLAY_RUN4
+{SPR_ASSN,4,6,NULL,S_APLAY_ATK2,0,0},	// S_APLAY_ATK1
+{SPR_ASSN,5,6,NULL,S_APLAY_ATK3,0,0},	// S_APLAY_ATK2
+{SPR_ASSN,6,6,NULL,S_APLAY,0,0},	// S_APLAY_ATK3
+{SPR_ASSN,7,4,NULL,S_APLAY_PAIN2,0,0},	// S_APLAY_PAIN
+{SPR_ASSN,7,4,A_Pain,S_APLAY,0,0},	// S_APLAY_PAIN2
+{SPR_ASSN,8,6,NULL,S_APLAY_DIE2,0,0},	// S_APLAY_DIE1
+{SPR_ASSN,10,6,A_Scream,S_APLAY_DIE3,0,0},	// S_APLAY_DIE2
+{SPR_ASSN,11,6,NULL,S_APLAY_DIE4,0,0},	// S_APLAY_DIE3
+{SPR_ASSN,11,6,NULL,S_APLAY_DIE5,0,0},	// S_APLAY_DIE4
+{SPR_ASSN,12,6,A_NoBlocking,S_APLAY_DIE6,0,0},	// S_APLAY_DIE5
+{SPR_ASSN,13,6,NULL,S_APLAY_DIE7,0,0},	// S_APLAY_DIE6
+{SPR_ASSN,14,6,NULL,S_APLAY_DIE8,0,0},	// S_APLAY_DIE7
+{SPR_ASSN,15,6,NULL,S_APLAY_DIE9,0,0},	// S_APLAY_DIE8
+{SPR_ASSN,16,-1,A_AddPlayerCorpse,S_NULL,0,0},	// S_APLAY_DIE9
+{SPR_ASSN,17,5,A_Scream,S_APLAY_XDIE2,0,0},	// S_APLAY_XDIE1
+{SPR_ASSN,18,5,NULL,S_APLAY_XDIE3,0,0},	// S_APLAY_XDIE2
+{SPR_ASSN,19,5,A_NoBlocking,S_APLAY_XDIE4,0,0},	// S_APLAY_XDIE3
+{SPR_ASSN,20,5,NULL,S_APLAY_XDIE5,0,0},	// S_APLAY_XDIE4
+{SPR_ASSN,21,5,NULL,S_APLAY_XDIE6,0,0},	// S_APLAY_XDIE5
+{SPR_ASSN,22,5,NULL,S_APLAY_XDIE7,0,0},	// S_APLAY_XDIE6
+{SPR_ASSN,23,5,NULL,S_APLAY_XDIE8,0,0},	// S_APLAY_XDIE7
+{SPR_ASSN,24,5,NULL,S_APLAY_XDIE9,0,0},	// S_APLAY_XDIE8
+{SPR_ASSN,25,5,NULL,S_APLAY_XDIE10,0,0},	// S_APLAY_XDIE9
+{SPR_ASSN,26,-1,A_AddPlayerCorpse,S_NULL,0,0},	// S_APLAY_XDIE10
+{SPR_ASSN,27,5,A_FreezeDeath,S_APLAY_ICE2,0,0},	// S_APLAY_ICE
+{SPR_ASSN,27,1,A_FreezeDeathChunks,S_APLAY_ICE2,0,0}	// S_APLAY_ICE2
+#endif	/* ASSASSIN */
+};
+
+
+mobjinfo_t mobjinfo[NUMMOBJTYPES] = {
+
+{		// MT_MAPSPOT
+9001,		// doomednum
+S_MAPSPOT,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_NOSECTOR|MF_NOGRAVITY,		// flags
+0		// flags2
+ },
+
+{		// MT_MAPSPOTGRAVITY
+9013,		// doomednum
+S_MAPSPOT,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+0,		// flags
+MF2_DONTDRAW		// flags2
+ },
+
+{		// MT_FIREBALL1
+-1,		// doomednum
+S_FIREBALL1_1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_FIREBALL1_X1,		// deathstate
+S_NULL,		// xdeathstate
+SFX_FIREBALL,		// deathsound
+2*FRACUNIT,		// speed
+8*FRACUNIT,		// radius
+8*FRACUNIT,		// height
+100,		// mass
+4,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_NOGRAVITY,		// flags
+MF2_NOTELEPORT|MF2_FIREDAMAGE		// flags2
+ },
+
+{		// MT_ARROW
+-1,		// doomednum
+S_ARROW_1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_ARROW_X1,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+6*FRACUNIT,		// speed
+8*FRACUNIT,		// radius
+4*FRACUNIT,		// height
+100,		// mass
+4,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_NOGRAVITY,		// flags
+MF2_NOTELEPORT		// flags2
+ },
+
+{		// MT_DART
+-1,		// doomednum
+S_DART_1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_DART_X1,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+6*FRACUNIT,		// speed
+8*FRACUNIT,		// radius
+4*FRACUNIT,		// height
+100,		// mass
+2,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_NOGRAVITY,		// flags
+MF2_NOTELEPORT		// flags2
+ },
+
+{		// MT_POISONDART
+-1,		// doomednum
+S_POISONDART_1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_POISONDART_X1,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+6*FRACUNIT,		// speed
+8*FRACUNIT,		// radius
+4*FRACUNIT,		// height
+100,		// mass
+2,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_NOGRAVITY,		// flags
+MF2_NOTELEPORT		// flags2
+ },
+
+{		// MT_RIPPERBALL
+-1,		// doomednum
+S_RIPPERBALL_1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_RIPPERBALL_X1,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+6*FRACUNIT,		// speed
+8*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+2,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_NOGRAVITY,		// flags
+MF2_NOTELEPORT|MF2_RIP		// flags2
+ },
+
+{		// MT_PROJECTILE_BLADE
+-1,		// doomednum
+S_PRJ_BLADE1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_PRJ_BLADE_X1,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+6*FRACUNIT,		// speed
+6*FRACUNIT,		// radius
+6*FRACUNIT,		// height
+100,		// mass
+3,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_NOGRAVITY,		// flags
+MF2_NOTELEPORT		// flags2
+ },
+
+{		// MT_ICESHARD
+-1,		// doomednum
+S_ICESHARD1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_SHARDFXE1_1,		// deathstate
+S_NULL,		// xdeathstate
+SFX_MAGE_SHARDS_EXPLODE,		// deathsound
+25*FRACUNIT,		// speed
+13*FRACUNIT,		// radius
+8*FRACUNIT,		// height
+100,		// mass
+1,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_NOGRAVITY,		// flags
+MF2_NOTELEPORT|MF2_ICEDAMAGE		// flags2
+ },
+
+{		// MT_FLAME_SMALL_TEMP
+10500,		// doomednum
+S_FLAME_TSMALL1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+0,		// flags
+MF2_NOTELEPORT		// flags2
+ },
+
+{		// MT_FLAME_LARGE_TEMP
+10502,		// doomednum
+S_FLAME_TLARGE1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+0,		// flags
+MF2_NOTELEPORT		// flags2
+ },
+
+{		// MT_FLAME_SMALL
+10501,		// doomednum
+S_FLAME_SMALL1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+0,		// flags
+MF2_NOTELEPORT|MF2_DONTDRAW		// flags2
+ },
+
+{		// MT_FLAME_LARGE
+10503,		// doomednum
+S_FLAME_LARGE1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+0,		// flags
+MF2_NOTELEPORT|MF2_DONTDRAW		// flags2
+ },
+
+{		// MT_HEALINGBOTTLE
+81,		// doomednum
+S_ITEM_PTN1_1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SPECIAL,		// flags
+MF2_FLOATBOB		// flags2
+ },
+
+{		// MT_HEALTHFLASK
+82,		// doomednum
+S_ARTI_PTN2_1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SPECIAL,		// flags
+MF2_FLOATBOB		// flags2
+ },
+
+{		// MT_ARTIFLY
+83,		// doomednum
+S_ARTI_SOAR1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SPECIAL,		// flags
+MF2_FLOATBOB		// flags2
+ },
+
+{		// MT_ARTIINVULNERABILITY
+84,		// doomednum
+S_ARTI_INVU1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SPECIAL,		// flags
+MF2_FLOATBOB		// flags2
+ },
+
+{		// MT_SUMMONMAULATOR
+86,		// doomednum
+S_ARTI_SUMMON,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SPECIAL,		// flags
+MF2_FLOATBOB		// flags2
+ },
+
+{		// MT_SUMMON_FX
+-1,		// doomednum
+S_SUMMON_FX1_1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_SUMMON_FX2_1,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+20*FRACUNIT,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_MISSILE|MF_DROPOFF|MF_NOBLOCKMAP,		// flags
+MF2_NOTELEPORT		// flags2
+ },
+
+{		// MT_THRUSTFLOOR_UP
+10091,		// doomednum
+S_THRUSTINIT2_1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+128*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SOLID,		// flags
+MF2_NOTELEPORT|MF2_FLOORCLIP		// flags2
+ },
+
+{		// MT_THRUSTFLOOR_DOWN
+10090,		// doomednum
+S_THRUSTINIT1_1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+128*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+0,		// flags
+MF2_NOTELEPORT|MF2_FLOORCLIP|MF2_DONTDRAW		// flags2
+ },
+
+{		// MT_TELEPORTOTHER
+10040,		// doomednum
+S_ARTI_TELOTHER1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SPECIAL,		// flags
+MF2_FLOATBOB		// flags2
+ },
+
+{		// MT_TELOTHER_FX1
+-1,		// doomednum
+S_TELO_FX1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_TELO_FX9,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+20*FRACUNIT,		// speed
+16*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+10001,		// damage
+SFX_NONE,		// activesound
+MF_MISSILE|MF_DROPOFF|MF_NOGRAVITY|MF_NOBLOCKMAP,		// flags
+MF2_NOTELEPORT		// flags2
+ },
+
+{		// MT_TELOTHER_FX2
+-1,		// doomednum
+S_TELO_FX2_1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_TELO_FX9,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+16*FRACUNIT,		// speed
+16*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+10001,		// damage
+SFX_NONE,		// activesound
+MF_MISSILE|MF_DROPOFF|MF_NOGRAVITY|MF_NOBLOCKMAP,		// flags
+MF2_NOTELEPORT		// flags2
+ },
+
+{		// MT_TELOTHER_FX3
+-1,		// doomednum
+S_TELO_FX3_1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_TELO_FX9,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+16*FRACUNIT,		// speed
+16*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+10001,		// damage
+SFX_NONE,		// activesound
+MF_MISSILE|MF_DROPOFF|MF_NOGRAVITY|MF_NOBLOCKMAP,		// flags
+MF2_NOTELEPORT		// flags2
+ },
+
+{		// MT_TELOTHER_FX4
+-1,		// doomednum
+S_TELO_FX4_1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_TELO_FX9,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+16*FRACUNIT,		// speed
+16*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+10001,		// damage
+SFX_NONE,		// activesound
+MF_MISSILE|MF_DROPOFF|MF_NOGRAVITY|MF_NOBLOCKMAP,		// flags
+MF2_NOTELEPORT		// flags2
+ },
+
+{		// MT_TELOTHER_FX5
+-1,		// doomednum
+S_TELO_FX5_1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_TELO_FX9,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+16*FRACUNIT,		// speed
+16*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+10001,		// damage
+SFX_NONE,		// activesound
+MF_MISSILE|MF_DROPOFF|MF_NOGRAVITY|MF_NOBLOCKMAP,		// flags
+MF2_NOTELEPORT		// flags2
+ },
+
+{		// MT_DIRT1
+-1,		// doomednum
+S_DIRT1_1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_DIRT1_D,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_DROPOFF|MF_MISSILE,		// flags
+MF2_NOTELEPORT		// flags2
+ },
+
+{		// MT_DIRT2
+-1,		// doomednum
+S_DIRT2_1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_DIRT2_D,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_DROPOFF|MF_MISSILE,		// flags
+MF2_NOTELEPORT		// flags2
+ },
+
+{		// MT_DIRT3
+-1,		// doomednum
+S_DIRT3_1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_DIRT3_D,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_DROPOFF|MF_MISSILE,		// flags
+MF2_NOTELEPORT		// flags2
+ },
+
+{		// MT_DIRT4
+-1,		// doomednum
+S_DIRT4_1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_DIRT4_D,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_DROPOFF|MF_MISSILE,		// flags
+MF2_NOTELEPORT|MF2_LOGRAV		// flags2
+ },
+
+{		// MT_DIRT5
+-1,		// doomednum
+S_DIRT5_1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_DIRT5_D,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_DROPOFF|MF_MISSILE,		// flags
+MF2_NOTELEPORT|MF2_LOGRAV		// flags2
+ },
+
+{		// MT_DIRT6
+-1,		// doomednum
+S_DIRT6_1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_DIRT6_D,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_DROPOFF|MF_MISSILE,		// flags
+MF2_NOTELEPORT|MF2_LOGRAV		// flags2
+ },
+
+{		// MT_DIRTCLUMP
+-1,		// doomednum
+S_DIRTCLUMP1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP,		// flags
+MF2_NOTELEPORT		// flags2
+ },
+
+{		// MT_ROCK1
+-1,		// doomednum
+S_ROCK1_1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_ROCK1_D,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_DROPOFF|MF_MISSILE,		// flags
+MF2_NOTELEPORT		// flags2
+ },
+
+{		// MT_ROCK2
+-1,		// doomednum
+S_ROCK2_1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_ROCK2_D,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_DROPOFF|MF_MISSILE,		// flags
+MF2_NOTELEPORT		// flags2
+ },
+
+{		// MT_ROCK3
+-1,		// doomednum
+S_ROCK3_1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_ROCK3_D,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_DROPOFF|MF_MISSILE,		// flags
+MF2_NOTELEPORT		// flags2
+ },
+
+{		// MT_FOGSPAWNER
+10000,		// doomednum
+S_SPAWNFOG1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_NOSECTOR,		// flags
+MF2_DONTDRAW|MF2_FLOATBOB		// flags2
+ },
+
+{		// MT_FOGPATCHS
+10001,		// doomednum
+S_FOGPATCHS1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_FOGPATCHS0,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+FRACUNIT,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_FLOAT|MF_NOGRAVITY|MF_SHADOW|MF_NOCLIP,		// flags
+MF2_NOTELEPORT		// flags2
+ },
+
+{		// MT_FOGPATCHM
+10002,		// doomednum
+S_FOGPATCHM1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_FOGPATCHM0,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+FRACUNIT,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_FLOAT|MF_NOGRAVITY|MF_SHADOW|MF_NOCLIP,		// flags
+MF2_NOTELEPORT		// flags2
+ },
+
+{		// MT_FOGPATCHL
+10003,		// doomednum
+S_FOGPATCHL1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_FOGPATCHL0,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+FRACUNIT,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_FLOAT|MF_NOGRAVITY|MF_SHADOW|MF_NOCLIP,		// flags
+MF2_NOTELEPORT		// flags2
+ },
+
+{		// MT_QUAKE_FOCUS
+-1,		// doomednum
+S_QUAKE_ACTIVE1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_NOSECTOR,		// flags
+MF2_DONTDRAW		// flags2
+ },
+
+{		// MT_SGSHARD1
+-1,		// doomednum
+S_SGSHARD1_1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_SGSHARD1_D,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+5*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+5,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_DROPOFF|MF_MISSILE|MF_NOGRAVITY,		// flags
+MF2_NOTELEPORT|MF2_FLOORBOUNCE		// flags2
+ },
+
+{		// MT_SGSHARD2
+-1,		// doomednum
+S_SGSHARD2_1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_SGSHARD2_D,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+5*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+5,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_DROPOFF|MF_MISSILE|MF_NOGRAVITY,		// flags
+MF2_NOTELEPORT|MF2_FLOORBOUNCE		// flags2
+ },
+
+{		// MT_SGSHARD3
+-1,		// doomednum
+S_SGSHARD3_1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_SGSHARD3_D,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+5*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+5,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_DROPOFF|MF_MISSILE|MF_NOGRAVITY,		// flags
+MF2_NOTELEPORT|MF2_FLOORBOUNCE		// flags2
+ },
+
+{		// MT_SGSHARD4
+-1,		// doomednum
+S_SGSHARD4_1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_SGSHARD4_D,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+5*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+5,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_DROPOFF|MF_MISSILE|MF_NOGRAVITY,		// flags
+MF2_NOTELEPORT|MF2_FLOORBOUNCE		// flags2
+ },
+
+{		// MT_SGSHARD5
+-1,		// doomednum
+S_SGSHARD5_1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_SGSHARD5_D,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+5*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+5,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_DROPOFF|MF_MISSILE|MF_NOGRAVITY,		// flags
+MF2_NOTELEPORT|MF2_FLOORBOUNCE		// flags2
+ },
+
+{		// MT_SGSHARD6
+-1,		// doomednum
+S_SGSHARD6_1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_SGSHARD6_D,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+5*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+5,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_DROPOFF|MF_MISSILE|MF_NOGRAVITY,		// flags
+MF2_NOTELEPORT|MF2_FLOORBOUNCE		// flags2
+ },
+
+{		// MT_SGSHARD7
+-1,		// doomednum
+S_SGSHARD7_1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_SGSHARD7_D,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+5*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+5,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_DROPOFF|MF_MISSILE|MF_NOGRAVITY,		// flags
+MF2_NOTELEPORT|MF2_FLOORBOUNCE		// flags2
+ },
+
+{		// MT_SGSHARD8
+-1,		// doomednum
+S_SGSHARD8_1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_SGSHARD8_D,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+5*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+5,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_DROPOFF|MF_MISSILE|MF_NOGRAVITY,		// flags
+MF2_NOTELEPORT|MF2_FLOORBOUNCE		// flags2
+ },
+
+{		// MT_SGSHARD9
+-1,		// doomednum
+S_SGSHARD9_1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_SGSHARD9_D,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+5*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+5,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_DROPOFF|MF_MISSILE|MF_NOGRAVITY,		// flags
+MF2_NOTELEPORT|MF2_FLOORBOUNCE		// flags2
+ },
+
+{		// MT_SGSHARD0
+-1,		// doomednum
+S_SGSHARD0_1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_SGSHARD0_D,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+5*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+5,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_DROPOFF|MF_MISSILE|MF_NOGRAVITY,		// flags
+MF2_NOTELEPORT|MF2_FLOORBOUNCE		// flags2
+ },
+
+{		// MT_ARTIEGG
+30,		// doomednum
+S_ARTI_EGGC1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SPECIAL,		// flags
+MF2_FLOATBOB		// flags2
+ },
+
+{		// MT_EGGFX
+-1,		// doomednum
+S_EGGFX1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+0,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_EGGFXI1_1,		// deathstate
+S_NULL,		// xdeathstate
+0,		// deathsound
+18*FRACUNIT,		// speed
+8*FRACUNIT,		// radius
+8*FRACUNIT,		// height
+100,		// mass
+1,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_NOGRAVITY,		// flags
+MF2_NOTELEPORT		// flags2
+ },
+
+{		// MT_ARTISUPERHEAL
+32,		// doomednum
+S_ARTI_SPHL1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SPECIAL,		// flags
+MF2_FLOATBOB		// flags2
+ },
+
+{		// MT_ZWINGEDSTATUENOSKULL
+9011,		// doomednum
+S_ZWINGEDSTATUENOSKULL,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+10*FRACUNIT,		// radius
+62*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SOLID,		// flags
+0		// flags2
+ },
+
+{		// MT_ZGEMPEDESTAL
+9012,		// doomednum
+S_ZGEMPEDESTAL1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+10*FRACUNIT,		// radius
+40*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SOLID,		// flags
+0		// flags2
+ },
+
+{		// MT_ARTIPUZZSKULL
+9002,		// doomednum
+S_ARTIPUZZSKULL,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SPECIAL|MF_NOGRAVITY,		// flags
+0		// flags2
+ },
+
+{		// MT_ARTIPUZZGEMBIG
+9003,		// doomednum
+S_ARTIPUZZGEMBIG,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SPECIAL|MF_NOGRAVITY,		// flags
+0		// flags2
+ },
+
+{		// MT_ARTIPUZZGEMRED
+9004,		// doomednum
+S_ARTIPUZZGEMRED,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SPECIAL|MF_NOGRAVITY,		// flags
+0		// flags2
+ },
+
+{		// MT_ARTIPUZZGEMGREEN1
+9005,		// doomednum
+S_ARTIPUZZGEMGREEN1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SPECIAL|MF_NOGRAVITY,		// flags
+0		// flags2
+ },
+
+{		// MT_ARTIPUZZGEMGREEN2
+9009,		// doomednum
+S_ARTIPUZZGEMGREEN2,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SPECIAL|MF_NOGRAVITY,		// flags
+0		// flags2
+ },
+
+{		// MT_ARTIPUZZGEMBLUE1
+9006,		// doomednum
+S_ARTIPUZZGEMBLUE1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SPECIAL|MF_NOGRAVITY,		// flags
+0		// flags2
+ },
+
+{		// MT_ARTIPUZZGEMBLUE2
+9010,		// doomednum
+S_ARTIPUZZGEMBLUE2,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SPECIAL|MF_NOGRAVITY,		// flags
+0		// flags2
+ },
+
+{		// MT_ARTIPUZZBOOK1
+9007,		// doomednum
+S_ARTIPUZZBOOK1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SPECIAL|MF_NOGRAVITY,		// flags
+0		// flags2
+ },
+
+{		// MT_ARTIPUZZBOOK2
+9008,		// doomednum
+S_ARTIPUZZBOOK2,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SPECIAL|MF_NOGRAVITY,		// flags
+0		// flags2
+ },
+
+{		// MT_ARTIPUZZSKULL2
+9014,		// doomednum
+S_ARTIPUZZSKULL2,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SPECIAL|MF_NOGRAVITY,		// flags
+0		// flags2
+ },
+
+{		// MT_ARTIPUZZFWEAPON
+9015,		// doomednum
+S_ARTIPUZZFWEAPON,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SPECIAL|MF_NOGRAVITY,		// flags
+0		// flags2
+ },
+
+{		// MT_ARTIPUZZCWEAPON
+9016,		// doomednum
+S_ARTIPUZZCWEAPON,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SPECIAL|MF_NOGRAVITY,		// flags
+0		// flags2
+ },
+
+{		// MT_ARTIPUZZMWEAPON
+9017,		// doomednum
+S_ARTIPUZZMWEAPON,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SPECIAL|MF_NOGRAVITY,		// flags
+0		// flags2
+ },
+
+{		// MT_ARTIPUZZGEAR
+9018,		// doomednum
+S_ARTIPUZZGEAR_1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SPECIAL|MF_NOGRAVITY,		// flags
+0		// flags2
+ },
+
+{		// MT_ARTIPUZZGEAR2
+9019,		// doomednum
+S_ARTIPUZZGEAR2_1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SPECIAL|MF_NOGRAVITY,		// flags
+0		// flags2
+ },
+
+{		// MT_ARTIPUZZGEAR3
+9020,		// doomednum
+S_ARTIPUZZGEAR3_1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SPECIAL|MF_NOGRAVITY,		// flags
+0		// flags2
+ },
+
+{		// MT_ARTIPUZZGEAR4
+9021,		// doomednum
+S_ARTIPUZZGEAR4_1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SPECIAL|MF_NOGRAVITY,		// flags
+0		// flags2
+ },
+
+{		// MT_ARTITORCH
+33,		// doomednum
+S_ARTI_TRCH1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SPECIAL,		// flags
+MF2_FLOATBOB		// flags2
+ },
+
+{		// MT_FIREBOMB
+-1,		// doomednum
+S_FIREBOMB1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_FLECHETTE_EXPLODE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOGRAVITY|MF_ALTSHADOW,		// flags
+MF2_FIREDAMAGE		// flags2
+ },
+
+{		// MT_ARTITELEPORT
+36,		// doomednum
+S_ARTI_ATLP1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SPECIAL,		// flags
+MF2_FLOATBOB		// flags2
+ },
+
+{		// MT_ARTIPOISONBAG
+8000,		// doomednum
+S_ARTI_PSBG1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SPECIAL,		// flags
+MF2_FLOATBOB		// flags2
+ },
+
+{		// MT_POISONBAG
+-1,		// doomednum
+S_POISONBAG1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+5*FRACUNIT,		// radius
+5*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOGRAVITY|MF_NOBLOCKMAP,		// flags
+0		// flags2
+ },
+
+{		// MT_POISONCLOUD
+-1,		// doomednum
+S_POISONCLOUD1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_POISONSHROOM_DEATH,		// deathsound
+0,		// speed
+1,		// radius
+1,		// height
+H2MAXINT,	// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOGRAVITY|MF_NOBLOCKMAP|MF_SHADOW|MF_NOCLIP|MF_DROPOFF,		// flags
+MF2_NODMGTHRUST		// flags2
+ },
+
+{		// MT_THROWINGBOMB
+-1,		// doomednum
+S_THROWINGBOMB1,		// spawnstate
+48,		// spawnhealth
+S_NULL,		// seestate
+SFX_FLECHETTE_BOUNCE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_THROWINGBOMB_X1,		// deathstate
+S_NULL,		// xdeathstate
+SFX_FLECHETTE_EXPLODE,		// deathsound
+12*FRACUNIT,		// speed
+8*FRACUNIT,		// radius
+10*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_DROPOFF|MF_MISSILE,		// flags
+MF2_FLOORBOUNCE|MF2_FIREDAMAGE		// flags2
+ },
+
+{		// MT_SPEEDBOOTS
+8002,		// doomednum
+S_ARTI_BOOTS1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SPECIAL,		// flags
+MF2_FLOATBOB		// flags2
+ },
+
+{		// MT_BOOSTMANA
+8003,		// doomednum
+S_ARTI_MANA,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SPECIAL,		// flags
+MF2_FLOATBOB		// flags2
+ },
+
+{		// MT_BOOSTARMOR
+8041,		// doomednum
+S_ARTI_ARMOR1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SPECIAL,		// flags
+MF2_FLOATBOB		// flags2
+ },
+
+{		// MT_BLASTRADIUS
+10110,		// doomednum
+S_ARTI_BLAST1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SPECIAL,		// flags
+MF2_FLOATBOB		// flags2
+ },
+
+{		// MT_HEALRADIUS
+10120,		// doomednum
+S_ARTI_HEALRAD1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SPECIAL,		// flags
+MF2_FLOATBOB		// flags2
+ },
+
+{		// MT_SPLASH
+-1,		// doomednum
+S_SPLASH1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_SPLASHX,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+2*FRACUNIT,		// radius
+4*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF,		// flags
+MF2_NOTELEPORT|MF2_LOGRAV|MF2_CANNOTPUSH		// flags2
+ },
+
+{		// MT_SPLASHBASE
+-1,		// doomednum
+S_SPLASHBASE1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP,		// flags
+0		// flags2
+ },
+
+{		// MT_LAVASPLASH
+-1,		// doomednum
+S_LAVASPLASH1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP,		// flags
+0		// flags2
+ },
+
+{		// MT_LAVASMOKE
+-1,		// doomednum
+S_LAVASMOKE1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_NOGRAVITY|MF_SHADOW,		// flags
+0		// flags2
+ },
+
+{		// MT_SLUDGECHUNK
+-1,		// doomednum
+S_SLUDGECHUNK1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_SLUDGECHUNKX,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+2*FRACUNIT,		// radius
+4*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF,		// flags
+MF2_NOTELEPORT|MF2_LOGRAV|MF2_CANNOTPUSH		// flags2
+ },
+
+{		// MT_SLUDGESPLASH
+-1,		// doomednum
+S_SLUDGESPLASH1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP,		// flags
+0		// flags2
+ },
+
+{		// MT_MISC0
+5,		// doomednum
+S_ZWINGEDSTATUE1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+10*FRACUNIT,		// radius
+62*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SOLID,		// flags
+0		// flags2
+ },
+
+{		// MT_MISC1
+6,		// doomednum
+S_ZROCK1_1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+0,		// flags
+0		// flags2
+ },
+
+{		// MT_MISC2
+7,		// doomednum
+S_ZROCK2_1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+0,		// flags
+0		// flags2
+ },
+
+{		// MT_MISC3
+9,		// doomednum
+S_ZROCK3_1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+0,		// flags
+0		// flags2
+ },
+
+{		// MT_MISC4
+15,		// doomednum
+S_ZROCK4_1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SOLID,		// flags
+0		// flags2
+ },
+
+{		// MT_MISC5
+17,		// doomednum
+S_ZCHANDELIER1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+60*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SPAWNCEILING|MF_NOGRAVITY,		// flags
+0		// flags2
+ },
+
+{		// MT_MISC6
+8063,		// doomednum
+S_ZCHANDELIER_U,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+60*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SPAWNCEILING|MF_NOGRAVITY,		// flags
+0		// flags2
+ },
+
+{		// MT_MISC7
+24,		// doomednum
+S_ZTREEDEAD1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+10*FRACUNIT,		// radius
+96*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SOLID,		// flags
+0		// flags2
+ },
+
+{		// MT_MISC8
+25,		// doomednum
+S_ZTREE,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+15*FRACUNIT,		// radius
+128*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SOLID,		// flags
+0		// flags2
+ },
+
+{		// MT_TREEDESTRUCTIBLE
+8062,		// doomednum
+S_ZTREEDESTRUCTIBLE1,		// spawnstate
+70,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_ZTREEDES_D1,		// deathstate
+S_NULL,		// xdeathstate
+SFX_TREE_BREAK,		// deathsound
+0,		// speed
+15*FRACUNIT,		// radius
+180*FRACUNIT,		// height
+H2MAXINT,	// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SOLID|MF_SHOOTABLE|MF_NOBLOOD,		// flags
+0		// flags2
+ },
+
+{		// MT_MISC9
+26,		// doomednum
+S_ZTREESWAMP182_1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+10*FRACUNIT,		// radius
+150*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SOLID,		// flags
+0		// flags2
+ },
+
+{		// MT_MISC10
+27,		// doomednum
+S_ZTREESWAMP172_1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+10*FRACUNIT,		// radius
+120*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SOLID,		// flags
+0		// flags2
+ },
+
+{		// MT_MISC11
+28,		// doomednum
+S_ZSTUMPBURNED1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+12*FRACUNIT,		// radius
+20*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SOLID,		// flags
+0		// flags2
+ },
+
+{		// MT_MISC12
+29,		// doomednum
+S_ZSTUMPBARE1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+12*FRACUNIT,		// radius
+20*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SOLID,		// flags
+0		// flags2
+ },
+
+{		// MT_MISC13
+37,		// doomednum
+S_ZSTUMPSWAMP1_1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+0,		// flags
+0		// flags2
+ },
+
+{		// MT_MISC14
+38,		// doomednum
+S_ZSTUMPSWAMP2_1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+0,		// flags
+0		// flags2
+ },
+
+{		// MT_MISC15
+39,		// doomednum
+S_ZSHROOMLARGE1_1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+0,		// flags
+0		// flags2
+ },
+
+{		// MT_MISC16
+40,		// doomednum
+S_ZSHROOMLARGE2_1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+0,		// flags
+0		// flags2
+ },
+
+{		// MT_MISC17
+41,		// doomednum
+S_ZSHROOMLARGE3_1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+0,		// flags
+0		// flags2
+ },
+
+{		// MT_MISC18
+42,		// doomednum
+S_ZSHROOMSMALL1_1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+0,		// flags
+0		// flags2
+ },
+
+{		// MT_MISC19
+44,		// doomednum
+S_ZSHROOMSMALL2_1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+0,		// flags
+0		// flags2
+ },
+
+{		// MT_MISC20
+45,		// doomednum
+S_ZSHROOMSMALL3_1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+0,		// flags
+0		// flags2
+ },
+
+{		// MT_MISC21
+46,		// doomednum
+S_ZSHROOMSMALL4_1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+0,		// flags
+0		// flags2
+ },
+
+{		// MT_MISC22
+47,		// doomednum
+S_ZSHROOMSMALL5_1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+0,		// flags
+0		// flags2
+ },
+
+{		// MT_MISC23
+48,		// doomednum
+S_ZSTALAGMITEPILLAR1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+8*FRACUNIT,		// radius
+138*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SOLID,		// flags
+0		// flags2
+ },
+
+{		// MT_MISC24
+49,		// doomednum
+S_ZSTALAGMITELARGE1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+8*FRACUNIT,		// radius
+48*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SOLID,		// flags
+0		// flags2
+ },
+
+{		// MT_MISC25
+50,		// doomednum
+S_ZSTALAGMITEMEDIUM1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+6*FRACUNIT,		// radius
+40*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SOLID,		// flags
+0		// flags2
+ },
+
+{		// MT_MISC26
+51,		// doomednum
+S_ZSTALAGMITESMALL1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+8*FRACUNIT,		// radius
+36*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SOLID,		// flags
+0		// flags2
+ },
+
+{		// MT_MISC27
+52,		// doomednum
+S_ZSTALACTITELARGE1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+8*FRACUNIT,		// radius
+66*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SOLID|MF_SPAWNCEILING|MF_NOGRAVITY,		// flags
+0		// flags2
+ },
+
+{		// MT_MISC28
+56,		// doomednum
+S_ZSTALACTITEMEDIUM1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+6*FRACUNIT,		// radius
+50*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SOLID|MF_SPAWNCEILING|MF_NOGRAVITY,		// flags
+0		// flags2
+ },
+
+{		// MT_MISC29
+57,		// doomednum
+S_ZSTALACTITESMALL1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+8*FRACUNIT,		// radius
+40*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SOLID|MF_SPAWNCEILING|MF_NOGRAVITY,		// flags
+0		// flags2
+ },
+
+{		// MT_MISC30
+58,		// doomednum
+S_ZMOSSCEILING1_1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+20*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SPAWNCEILING|MF_NOGRAVITY,		// flags
+0		// flags2
+ },
+
+{		// MT_MISC31
+59,		// doomednum
+S_ZMOSSCEILING2_1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+24*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SPAWNCEILING|MF_NOGRAVITY,		// flags
+0		// flags2
+ },
+
+{		// MT_MISC32
+60,		// doomednum
+S_ZSWAMPVINE1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+8*FRACUNIT,		// radius
+52*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SOLID,		// flags
+0		// flags2
+ },
+
+{		// MT_MISC33
+61,		// doomednum
+S_ZCORPSEKABOB1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+10*FRACUNIT,		// radius
+92*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SOLID,		// flags
+0		// flags2
+ },
+
+{		// MT_MISC34
+62,		// doomednum
+S_ZCORPSESLEEPING1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+0,		// flags
+0		// flags2
+ },
+
+{		// MT_MISC35
+63,		// doomednum
+S_ZTOMBSTONERIP1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+10*FRACUNIT,		// radius
+46*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SOLID,		// flags
+0		// flags2
+ },
+
+{		// MT_MISC36
+64,		// doomednum
+S_ZTOMBSTONESHANE1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+10*FRACUNIT,		// radius
+46*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SOLID,		// flags
+0		// flags2
+ },
+
+{		// MT_MISC37
+65,		// doomednum
+S_ZTOMBSTONEBIGCROSS1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+10*FRACUNIT,		// radius
+46*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SOLID,		// flags
+0		// flags2
+ },
+
+{		// MT_MISC38
+66,		// doomednum
+S_ZTOMBSTONEBRIANR1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+10*FRACUNIT,		// radius
+52*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SOLID,		// flags
+0		// flags2
+ },
+
+{		// MT_MISC39
+67,		// doomednum
+S_ZTOMBSTONECROSSCIRCLE1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+10*FRACUNIT,		// radius
+52*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SOLID,		// flags
+0		// flags2
+ },
+
+{		// MT_MISC40
+68,		// doomednum
+S_ZTOMBSTONESMALLCROSS1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+8*FRACUNIT,		// radius
+46*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SOLID,		// flags
+0		// flags2
+ },
+
+{		// MT_MISC41
+69,		// doomednum
+S_ZTOMBSTONEBRIANP1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+8*FRACUNIT,		// radius
+46*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SOLID,		// flags
+0		// flags2
+ },
+
+{		// MT_MISC42
+71,		// doomednum
+S_CORPSEHANGING_1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+6*FRACUNIT,		// radius
+75*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SOLID|MF_SPAWNCEILING|MF_NOGRAVITY,		// flags
+0		// flags2
+ },
+
+{		// MT_MISC43
+72,		// doomednum
+S_ZSTATUEGARGOYLEGREENTALL_1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+14*FRACUNIT,		// radius
+108*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SOLID,		// flags
+0		// flags2
+ },
+
+{		// MT_MISC44
+73,		// doomednum
+S_ZSTATUEGARGOYLEBLUETALL_1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+14*FRACUNIT,		// radius
+108*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SOLID,		// flags
+0		// flags2
+ },
+
+{		// MT_MISC45
+74,		// doomednum
+S_ZSTATUEGARGOYLEGREENSHORT_1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+14*FRACUNIT,		// radius
+62*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SOLID,		// flags
+0		// flags2
+ },
+
+{		// MT_MISC46
+76,		// doomednum
+S_ZSTATUEGARGOYLEBLUESHORT_1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+14*FRACUNIT,		// radius
+62*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SOLID,		// flags
+0		// flags2
+ },
+
+{		// MT_MISC47
+8044,		// doomednum
+S_ZSTATUEGARGOYLESTRIPETALL_1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+14*FRACUNIT,		// radius
+108*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SOLID,		// flags
+0		// flags2
+ },
+
+{		// MT_MISC48
+8045,		// doomednum
+S_ZSTATUEGARGOYLEDARKREDTALL_1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+14*FRACUNIT,		// radius
+108*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SOLID,		// flags
+0		// flags2
+ },
+
+{		// MT_MISC49
+8046,		// doomednum
+S_ZSTATUEGARGOYLEREDTALL_1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+14*FRACUNIT,		// radius
+108*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SOLID,		// flags
+0		// flags2
+ },
+
+{		// MT_MISC50
+8047,		// doomednum
+S_ZSTATUEGARGOYLETANTALL_1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+14*FRACUNIT,		// radius
+108*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SOLID,		// flags
+0		// flags2
+ },
+
+{		// MT_MISC51
+8048,		// doomednum
+S_ZSTATUEGARGOYLERUSTTALL_1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+14*FRACUNIT,		// radius
+108*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SOLID,		// flags
+0		// flags2
+ },
+
+{		// MT_MISC52
+8049,		// doomednum
+S_ZSTATUEGARGOYLEDARKREDSHORT_1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+14*FRACUNIT,		// radius
+62*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SOLID,		// flags
+0		// flags2
+ },
+
+{		// MT_MISC53
+8050,		// doomednum
+S_ZSTATUEGARGOYLEREDSHORT_1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+14*FRACUNIT,		// radius
+62*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SOLID,		// flags
+0		// flags2
+ },
+
+{		// MT_MISC54
+8051,		// doomednum
+S_ZSTATUEGARGOYLETANSHORT_1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+14*FRACUNIT,		// radius
+62*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SOLID,		// flags
+0		// flags2
+ },
+
+{		// MT_MISC55
+8052,		// doomednum
+S_ZSTATUEGARGOYLERUSTSHORT_1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+14*FRACUNIT,		// radius
+62*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SOLID,		// flags
+0		// flags2
+ },
+
+{		// MT_MISC56
+77,		// doomednum
+S_ZBANNERTATTERED_1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+8*FRACUNIT,		// radius
+120*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SOLID,		// flags
+0		// flags2
+ },
+
+{		// MT_MISC57
+78,		// doomednum
+S_ZTREELARGE1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_ZTREELARGE1,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+15*FRACUNIT,		// radius
+180*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SOLID,		// flags
+0		// flags2
+ },
+
+{		// MT_MISC58
+79,		// doomednum
+S_ZTREELARGE2,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_ZTREELARGE2,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+15*FRACUNIT,		// radius
+180*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SOLID,		// flags
+0		// flags2
+ },
+
+{		// MT_MISC59
+80,		// doomednum
+S_ZTREEGNARLED1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+22*FRACUNIT,		// radius
+100*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SOLID,		// flags
+0		// flags2
+ },
+
+{		// MT_MISC60
+87,		// doomednum
+S_ZTREEGNARLED2,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+22*FRACUNIT,		// radius
+100*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SOLID,		// flags
+0		// flags2
+ },
+
+{		// MT_MISC61
+88,		// doomednum
+S_ZLOG,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+25*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SOLID,		// flags
+0		// flags2
+ },
+
+{		// MT_MISC62
+89,		// doomednum
+S_ZSTALACTITEICELARGE,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+8*FRACUNIT,		// radius
+66*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SOLID|MF_SPAWNCEILING|MF_NOGRAVITY,		// flags
+0		// flags2
+ },
+
+{		// MT_MISC63
+90,		// doomednum
+S_ZSTALACTITEICEMEDIUM,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+5*FRACUNIT,		// radius
+50*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SOLID|MF_SPAWNCEILING|MF_NOGRAVITY,		// flags
+0		// flags2
+ },
+
+{		// MT_MISC64
+91,		// doomednum
+S_ZSTALACTITEICESMALL,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+4*FRACUNIT,		// radius
+32*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SOLID|MF_SPAWNCEILING|MF_NOGRAVITY,		// flags
+0		// flags2
+ },
+
+{		// MT_MISC65
+92,		// doomednum
+S_ZSTALACTITEICETINY,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+4*FRACUNIT,		// radius
+8*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SOLID|MF_SPAWNCEILING|MF_NOGRAVITY,		// flags
+0		// flags2
+ },
+
+{		// MT_MISC66
+93,		// doomednum
+S_ZSTALAGMITEICELARGE,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+8*FRACUNIT,		// radius
+66*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SOLID,		// flags
+0		// flags2
+ },
+
+{		// MT_MISC67
+94,		// doomednum
+S_ZSTALAGMITEICEMEDIUM,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+5*FRACUNIT,		// radius
+50*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SOLID,		// flags
+0		// flags2
+ },
+
+{		// MT_MISC68
+95,		// doomednum
+S_ZSTALAGMITEICESMALL,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+4*FRACUNIT,		// radius
+32*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SOLID,		// flags
+0		// flags2
+ },
+
+{		// MT_MISC69
+96,		// doomednum
+S_ZSTALAGMITEICETINY,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+4*FRACUNIT,		// radius
+8*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SOLID,		// flags
+0		// flags2
+ },
+
+{		// MT_MISC70
+97,		// doomednum
+S_ZROCKBROWN1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+17*FRACUNIT,		// radius
+72*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SOLID,		// flags
+0		// flags2
+ },
+
+{		// MT_MISC71
+98,		// doomednum
+S_ZROCKBROWN2,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+15*FRACUNIT,		// radius
+50*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SOLID,		// flags
+0		// flags2
+ },
+
+{		// MT_MISC72
+99,		// doomednum
+S_ZROCKBLACK,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+40*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SOLID,		// flags
+0		// flags2
+ },
+
+{		// MT_MISC73
+100,		// doomednum
+S_ZRUBBLE1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+0,		// flags
+0		// flags2
+ },
+
+{		// MT_MISC74
+101,		// doomednum
+S_ZRUBBLE2,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+0,		// flags
+0		// flags2
+ },
+
+{		// MT_MISC75
+102,		// doomednum
+S_ZRUBBLE3,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+0,		// flags
+0		// flags2
+ },
+
+{		// MT_MISC76
+103,		// doomednum
+S_ZVASEPILLAR,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+12*FRACUNIT,		// radius
+54*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SOLID,		// flags
+0		// flags2
+ },
+
+{		// MT_POTTERY1
+104,		// doomednum
+S_ZPOTTERY1,		// spawnstate
+15,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_ZPOTTERY_EXPLODE,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+10*FRACUNIT,		// radius
+32*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SOLID|MF_SHOOTABLE|MF_NOBLOOD|MF_DROPOFF,		// flags
+MF2_SLIDE|MF2_PUSHABLE|MF2_TELESTOMP|MF2_PASSMOBJ		// flags2
+ },
+
+{		// MT_POTTERY2
+105,		// doomednum
+S_ZPOTTERY2,		// spawnstate
+15,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_ZPOTTERY_EXPLODE,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+10*FRACUNIT,		// radius
+25*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SOLID|MF_SHOOTABLE|MF_NOBLOOD|MF_DROPOFF,		// flags
+MF2_SLIDE|MF2_PUSHABLE|MF2_TELESTOMP|MF2_PASSMOBJ		// flags2
+ },
+
+{		// MT_POTTERY3
+106,		// doomednum
+S_ZPOTTERY3,		// spawnstate
+15,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_ZPOTTERY_EXPLODE,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+15*FRACUNIT,		// radius
+25*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SOLID|MF_SHOOTABLE|MF_NOBLOOD|MF_DROPOFF,		// flags
+MF2_SLIDE|MF2_PUSHABLE|MF2_TELESTOMP|MF2_PASSMOBJ		// flags2
+ },
+
+{		// MT_POTTERYBIT1
+-1,		// doomednum
+S_POTTERYBIT_1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_POTTERYBIT_EX0,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+5*FRACUNIT,		// radius
+5*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_MISSILE,		// flags
+MF2_NOTELEPORT		// flags2
+ },
+
+{		// MT_MISC77
+108,		// doomednum
+S_ZCORPSELYNCHED1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+11*FRACUNIT,		// radius
+95*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SOLID|MF_SPAWNCEILING|MF_NOGRAVITY,		// flags
+0		// flags2
+ },
+
+{		// MT_ZLYNCHED_NOHEART
+109,		// doomednum
+S_ZCORPSELYNCHED2,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+10*FRACUNIT,		// radius
+100*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SOLID|MF_SPAWNCEILING|MF_NOGRAVITY,		// flags
+0		// flags2
+ },
+
+{		// MT_MISC78
+110,		// doomednum
+S_ZCORPSESITTING,		// spawnstate
+30,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_ZCORPSESITTING_X,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+15*FRACUNIT,		// radius
+35*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SOLID|MF_SHOOTABLE|MF_NOBLOOD,		// flags
+0		// flags2
+ },
+
+{		// MT_CORPSEBIT
+-1,		// doomednum
+S_CORPSEBIT_1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+5*FRACUNIT,		// radius
+5*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP,		// flags
+MF2_TELESTOMP		// flags2
+ },
+
+{		// MT_CORPSEBLOODDRIP
+-1,		// doomednum
+S_CORPSEBLOODDRIP,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_CORPSEBLOODDRIP_X1,		// deathstate
+S_NULL,		// xdeathstate
+SFX_DRIP,		// deathsound
+0,		// speed
+FRACUNIT,		// radius
+4*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_MISSILE,		// flags
+MF2_LOGRAV		// flags2
+ },
+
+{		// MT_BLOODPOOL
+111,		// doomednum
+S_BLOODPOOL,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP,		// flags
+0		// flags2
+ },
+
+{		// MT_MISC79
+119,		// doomednum
+S_ZCANDLE1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_NOGRAVITY,		// flags
+0		// flags2
+ },
+
+{		// MT_MISC80
+113,		// doomednum
+S_ZLEAFSPAWNER,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_NOSECTOR,		// flags
+MF2_DONTDRAW		// flags2
+ },
+
+{		// MT_LEAF1
+-1,		// doomednum
+S_LEAF1_1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_LEAF_X1,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+2*FRACUNIT,		// radius
+4*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_MISSILE,		// flags
+MF2_NOTELEPORT|MF2_LOGRAV		// flags2
+ },
+
+{		// MT_LEAF2
+-1,		// doomednum
+S_LEAF2_1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_LEAF_X1,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+2*FRACUNIT,		// radius
+4*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_MISSILE,		// flags
+MF2_NOTELEPORT|MF2_LOGRAV		// flags2
+ },
+
+{		// MT_ZTWINEDTORCH
+116,		// doomednum
+S_ZTWINEDTORCH_1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+10*FRACUNIT,		// radius
+64*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SOLID,		// flags
+0		// flags2
+ },
+
+{		// MT_ZTWINEDTORCH_UNLIT
+117,		// doomednum
+S_ZTWINEDTORCH_UNLIT,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+10*FRACUNIT,		// radius
+64*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SOLID,		// flags
+0		// flags2
+ },
+
+{		// MT_BRIDGE
+118,		// doomednum
+S_BRIDGE1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+32*FRACUNIT,		// radius
+2*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SOLID|MF_NOGRAVITY,		// flags
+MF2_DONTDRAW		// flags2
+ },
+
+{		// MT_BRIDGEBALL
+-1,		// doomednum
+S_BBALL1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_NOGRAVITY,		// flags
+MF2_NOTELEPORT		// flags2
+ },
+
+{		// MT_ZWALLTORCH
+54,		// doomednum
+S_ZWALLTORCH1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_NOGRAVITY,		// flags
+0		// flags2
+ },
+
+{		// MT_ZWALLTORCH_UNLIT
+55,		// doomednum
+S_ZWALLTORCH_U,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_NOGRAVITY,		// flags
+0		// flags2
+ },
+
+{		// MT_ZBARREL
+8100,		// doomednum
+S_ZBARREL1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+15*FRACUNIT,		// radius
+32*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SOLID,		// flags
+0		// flags2
+ },
+
+{		// MT_ZSHRUB1
+8101,		// doomednum
+S_ZSHRUB1,		// spawnstate
+20,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_ZSHRUB1_X1,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_ZSHRUB1_DIE,		// deathstate
+S_NULL,		// xdeathstate
+SFX_TREE_EXPLODE,		// deathsound
+0,		// speed
+8*FRACUNIT,		// radius
+24*FRACUNIT,		// height
+H2MAXINT,	// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SOLID|MF_SHOOTABLE|MF_NOBLOOD,		// flags
+0		// flags2
+ },
+
+{		// MT_ZSHRUB2
+8102,		// doomednum
+S_ZSHRUB2,		// spawnstate
+10,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_ZSHRUB2_X1,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_ZSHRUB2_DIE,		// deathstate
+S_NULL,		// xdeathstate
+SFX_TREE_EXPLODE,		// deathsound
+0,		// speed
+16*FRACUNIT,		// radius
+40*FRACUNIT,		// height
+H2MAXINT,	// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SOLID|MF_SHOOTABLE|MF_NOBLOOD,		// flags
+0		// flags2
+ },
+
+{		// MT_ZBUCKET
+8103,		// doomednum
+S_ZBUCKET1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+8*FRACUNIT,		// radius
+72*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SOLID|MF_SPAWNCEILING|MF_NOGRAVITY,		// flags
+0		// flags2
+ },
+
+{		// MT_ZPOISONSHROOM
+8104,		// doomednum
+S_ZPOISONSHROOM1,		// spawnstate
+30,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_ZPOISONSHROOM_P1,		// painstate
+255,		// painchance
+SFX_POISONSHROOM_PAIN,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_ZPOISONSHROOM_X1,		// deathstate
+S_NULL,		// xdeathstate
+SFX_POISONSHROOM_DEATH,		// deathsound
+0,		// speed
+6*FRACUNIT,		// radius
+20*FRACUNIT,		// height
+H2MAXINT,	// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SHOOTABLE|MF_SOLID|MF_NOBLOOD,		// flags
+0		// flags2
+ },
+
+{		// MT_ZFIREBULL
+8042,		// doomednum
+S_ZFIREBULL1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+80*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SOLID,		// flags
+0		// flags2
+ },
+
+{		// MT_ZFIREBULL_UNLIT
+8043,		// doomednum
+S_ZFIREBULL_U,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+80*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SOLID,		// flags
+0		// flags2
+ },
+
+{		// MT_FIRETHING
+8060,		// doomednum
+S_ZFIRETHING1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+5*FRACUNIT,		// radius
+10*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SOLID,		// flags
+0		// flags2
+ },
+
+{		// MT_BRASSTORCH
+8061,		// doomednum
+S_ZBRASSTORCH1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+6*FRACUNIT,		// radius
+35*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SOLID,		// flags
+0		// flags2
+ },
+
+{		// MT_ZSUITOFARMOR
+8064,		// doomednum
+S_ZSUITOFARMOR,		// spawnstate
+60,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_ZSUITOFARMOR_X1,		// deathstate
+S_NULL,		// xdeathstate
+SFX_SUITOFARMOR_BREAK,		// deathsound
+0,		// speed
+16*FRACUNIT,		// radius
+72*FRACUNIT,		// height
+H2MAXINT,	// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SOLID|MF_SHOOTABLE|MF_NOBLOOD,		// flags
+0		// flags2
+ },
+
+{		// MT_ZARMORCHUNK
+-1,		// doomednum
+S_ZARMORCHUNK1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+4*FRACUNIT,		// radius
+8*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+0,		// flags
+0		// flags2
+ },
+
+{		// MT_ZBELL
+8065,		// doomednum
+S_ZBELL,		// spawnstate
+5,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_ZBELL_X1,		// deathstate
+S_NULL,		// xdeathstate
+SFX_BELLRING,		// deathsound
+0,		// speed
+56*FRACUNIT,		// radius
+120*FRACUNIT,		// height
+H2MAXINT,	// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SOLID|MF_SHOOTABLE|MF_NOBLOOD|MF_NOGRAVITY|MF_SPAWNCEILING,		// flags
+0		// flags2
+ },
+
+{		// MT_ZBLUE_CANDLE
+8066,		// doomednum
+S_ZBLUE_CANDLE1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP,		// flags
+0		// flags2
+ },
+
+{		// MT_ZIRON_MAIDEN
+8067,		// doomednum
+S_ZIRON_MAIDEN,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+12*FRACUNIT,		// radius
+60*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SOLID,		// flags
+0		// flags2
+ },
+
+{		// MT_ZXMAS_TREE
+8068,		// doomednum
+S_ZXMAS_TREE,		// spawnstate
+20,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_ZXMAS_TREE_X1,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_ZXMAS_TREE_DIE,		// deathstate
+S_NULL,		// xdeathstate
+SFX_TREE_EXPLODE,		// deathsound
+0,		// speed
+11*FRACUNIT,		// radius
+130*FRACUNIT,		// height
+H2MAXINT,	// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SOLID|MF_SHOOTABLE|MF_NOBLOOD,		// flags
+0		// flags2
+ },
+
+{		// MT_ZCAULDRON
+8069,		// doomednum
+S_ZCAULDRON1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+12*FRACUNIT,		// radius
+26*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SOLID,		// flags
+0		// flags2
+ },
+
+{		// MT_ZCAULDRON_UNLIT
+8070,		// doomednum
+S_ZCAULDRON_U,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+12*FRACUNIT,		// radius
+26*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SOLID,		// flags
+0		// flags2
+ },
+
+{		// MT_ZCHAINBIT32
+8071,		// doomednum
+S_ZCHAINBIT32,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+4*FRACUNIT,		// radius
+32*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_NOGRAVITY|MF_SPAWNCEILING,		// flags
+0		// flags2
+ },
+
+{		// MT_ZCHAINBIT64
+8072,		// doomednum
+S_ZCHAINBIT64,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+4*FRACUNIT,		// radius
+64*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_NOGRAVITY|MF_SPAWNCEILING,		// flags
+0		// flags2
+ },
+
+{		// MT_ZCHAINEND_HEART
+8073,		// doomednum
+S_ZCHAINEND_HEART,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+4*FRACUNIT,		// radius
+32*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_NOGRAVITY|MF_SPAWNCEILING,		// flags
+0		// flags2
+ },
+
+{		// MT_ZCHAINEND_HOOK1
+8074,		// doomednum
+S_ZCHAINEND_HOOK1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+4*FRACUNIT,		// radius
+32*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_NOGRAVITY|MF_SPAWNCEILING,		// flags
+0		// flags2
+ },
+
+{		// MT_ZCHAINEND_HOOK2
+8075,		// doomednum
+S_ZCHAINEND_HOOK2,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+4*FRACUNIT,		// radius
+32*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_NOGRAVITY|MF_SPAWNCEILING,		// flags
+0		// flags2
+ },
+
+{		// MT_ZCHAINEND_SPIKE
+8076,		// doomednum
+S_ZCHAINEND_SPIKE,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+4*FRACUNIT,		// radius
+32*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_NOGRAVITY|MF_SPAWNCEILING,		// flags
+0		// flags2
+ },
+
+{		// MT_ZCHAINEND_SKULL
+8077,		// doomednum
+S_ZCHAINEND_SKULL,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+4*FRACUNIT,		// radius
+32*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_NOGRAVITY|MF_SPAWNCEILING,		// flags
+0		// flags2
+ },
+
+{		// MT_TABLE_SHIT1
+8500,		// doomednum
+S_TABLE_SHIT1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP,		// flags
+0		// flags2
+ },
+
+{		// MT_TABLE_SHIT2
+8501,		// doomednum
+S_TABLE_SHIT2,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP,		// flags
+0		// flags2
+ },
+
+{		// MT_TABLE_SHIT3
+8502,		// doomednum
+S_TABLE_SHIT3,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP,		// flags
+0		// flags2
+ },
+
+{		// MT_TABLE_SHIT4
+8503,		// doomednum
+S_TABLE_SHIT4,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP,		// flags
+0		// flags2
+ },
+
+{		// MT_TABLE_SHIT5
+8504,		// doomednum
+S_TABLE_SHIT5,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP,		// flags
+0		// flags2
+ },
+
+{		// MT_TABLE_SHIT6
+8505,		// doomednum
+S_TABLE_SHIT6,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP,		// flags
+0		// flags2
+ },
+
+{		// MT_TABLE_SHIT7
+8506,		// doomednum
+S_TABLE_SHIT7,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP,		// flags
+0		// flags2
+ },
+
+{		// MT_TABLE_SHIT8
+8507,		// doomednum
+S_TABLE_SHIT8,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP,		// flags
+0		// flags2
+ },
+
+{		// MT_TABLE_SHIT9
+8508,		// doomednum
+S_TABLE_SHIT9,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP,		// flags
+0		// flags2
+ },
+
+{		// MT_TABLE_SHIT10
+8509,		// doomednum
+S_TABLE_SHIT10,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP,		// flags
+0		// flags2
+ },
+
+{		// MT_TFOG
+-1,		// doomednum
+S_TFOG1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_NOGRAVITY,		// flags
+0		// flags2
+ },
+
+{		// MT_MISC81
+140,		// doomednum
+S_TELESMOKE1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_NOGRAVITY,		// flags
+0		// flags2
+ },
+
+{		// MT_TELEPORTMAN
+14,		// doomednum
+S_NULL,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_NOSECTOR,		// flags
+0		// flags2
+ },
+
+{		// MT_PUNCHPUFF
+-1,		// doomednum
+S_PUNCHPUFF1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_FIGHTER_PUNCH_HITTHING,		// seesound
+8,		// reactiontime
+SFX_FIGHTER_PUNCH_HITWALL,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_NOGRAVITY|MF_SHADOW,		// flags
+0		// flags2
+ },
+
+{		// MT_FW_AXE
+8010,		// doomednum
+S_AXE,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SPECIAL,		// flags
+0		// flags2
+ },
+
+{		// MT_AXEPUFF
+-1,		// doomednum
+S_HAMMERPUFF1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_FIGHTER_AXE_HITTHING,		// seesound
+8,		// reactiontime
+SFX_FIGHTER_HAMMER_HITWALL,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_NOGRAVITY|MF_SHADOW,		// flags
+0		// flags2
+ },
+
+{		// MT_AXEPUFF_GLOW
+-1,		// doomednum
+S_AXEPUFF_GLOW1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_FIGHTER_AXE_HITTHING,		// seesound
+8,		// reactiontime
+SFX_FIGHTER_HAMMER_HITWALL,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_NOGRAVITY,		// flags
+0		// flags2
+ },
+
+{		// MT_AXEBLOOD
+-1,		// doomednum
+S_AXEBLOOD1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_AXEBLOOD6,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+2*FRACUNIT,		// radius
+4*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_NOGRAVITY|MF_DROPOFF,		// flags
+MF2_NOTELEPORT|MF2_CANNOTPUSH		// flags2
+ },
+
+{		// MT_FW_HAMMER
+123,		// doomednum
+S_HAMM,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SPECIAL,		// flags
+0		// flags2
+ },
+
+{		// MT_HAMMER_MISSILE
+-1,		// doomednum
+S_HAMMER_MISSILE_1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_HAMMER_MISSILE_X1,		// deathstate
+S_NULL,		// xdeathstate
+SFX_FIGHTER_HAMMER_EXPLODE,		// deathsound
+25*FRACUNIT,		// speed
+14*FRACUNIT,		// radius
+20*FRACUNIT,		// height
+100,		// mass
+10,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_NOGRAVITY,		// flags
+MF2_NOTELEPORT|MF2_IMPACT|MF2_PCROSS|MF2_FIREDAMAGE		// flags2
+ },
+
+{		// MT_HAMMERPUFF
+-1,		// doomednum
+S_HAMMERPUFF1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_FIGHTER_HAMMER_HITTHING,		// seesound
+8,		// reactiontime
+SFX_FIGHTER_HAMMER_HITWALL,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_NOGRAVITY|MF_SHADOW,		// flags
+0		// flags2
+ },
+
+{		// MT_FSWORD_MISSILE
+-1,		// doomednum
+S_FSWORD_MISSILE1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_FSWORD_MISSILE_X1,		// deathstate
+S_NULL,		// xdeathstate
+SFX_FIGHTER_SWORD_EXPLODE,		// deathsound
+30*FRACUNIT,		// speed
+16*FRACUNIT,		// radius
+8*FRACUNIT,		// height
+100,		// mass
+8,		// damage
+SFX_NONE,		// activesound
+MF_MISSILE|MF_NOBLOCKMAP|MF_NOGRAVITY|MF_DROPOFF,		// flags
+MF2_NOTELEPORT|MF2_IMPACT|MF2_PCROSS		// flags2
+ },
+
+{		// MT_FSWORD_FLAME
+-1,		// doomednum
+S_FSWORD_FLAME1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_NOGRAVITY|MF_SHADOW,		// flags
+0		// flags2
+ },
+
+{		// MT_CW_SERPSTAFF
+10,		// doomednum
+S_CSTAFF,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SPECIAL,		// flags
+0		// flags2
+ },
+
+{		// MT_CSTAFF_MISSILE
+-1,		// doomednum
+S_CSTAFF_MISSILE1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_CSTAFF_MISSILE_X1,		// deathstate
+S_NULL,		// xdeathstate
+SFX_CLERIC_CSTAFF_EXPLODE,		// deathsound
+22*FRACUNIT,		// speed
+12*FRACUNIT,		// radius
+10*FRACUNIT,		// height
+100,		// mass
+5,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_NOGRAVITY,		// flags
+MF2_NOTELEPORT|MF2_IMPACT|MF2_PCROSS		// flags2
+ },
+
+{		// MT_CSTAFFPUFF
+-1,		// doomednum
+S_CSTAFFPUFF1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_CLERIC_CSTAFF_HITTHING,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_NOGRAVITY|MF_SHADOW,		// flags
+0		// flags2
+ },
+
+{		// MT_CW_FLAME
+8009,		// doomednum
+S_CFLAME1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SPECIAL|MF_NOGRAVITY,		// flags
+0		// flags2
+ },
+
+{		// MT_CFLAMEFLOOR
+-1,		// doomednum
+S_CFLAMEFLOOR1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_NOGRAVITY,		// flags
+0		// flags2
+ },
+
+{		// MT_FLAMEPUFF
+-1,		// doomednum
+S_FLAMEPUFF1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_CLERIC_FLAME_EXPLODE,		// seesound
+8,		// reactiontime
+SFX_CLERIC_FLAME_EXPLODE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+FRACUNIT,		// radius
+FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_NOGRAVITY,		// flags
+0		// flags2
+ },
+
+{		// MT_FLAMEPUFF2
+-1,		// doomednum
+S_FLAMEPUFF2_1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_CLERIC_FLAME_EXPLODE,		// seesound
+8,		// reactiontime
+SFX_CLERIC_FLAME_EXPLODE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+FRACUNIT,		// radius
+FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_NOGRAVITY,		// flags
+0		// flags2
+ },
+
+{		// MT_CIRCLEFLAME
+-1,		// doomednum
+S_CIRCLE_FLAME1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_CIRCLE_FLAME_X1,		// deathstate
+S_NULL,		// xdeathstate
+SFX_CLERIC_FLAME_CIRCLE,		// deathsound
+0,		// speed
+6*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+2,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_NOGRAVITY,		// flags
+MF2_NOTELEPORT|MF2_FIREDAMAGE		// flags2
+ },
+
+{		// MT_CFLAME_MISSILE
+-1,		// doomednum
+S_CFLAME_MISSILE1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_CFLAME_MISSILE_X,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+200*FRACUNIT,		// speed
+14*FRACUNIT,		// radius
+8*FRACUNIT,		// height
+100,		// mass
+8,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_NOGRAVITY,		// flags
+MF2_NOTELEPORT|MF2_IMPACT|MF2_PCROSS|MF2_DONTDRAW|MF2_FIREDAMAGE		// flags2
+ },
+
+{		// MT_HOLY_FX
+-1,		// doomednum
+S_HOLY_FX1,		// spawnstate
+105,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_HOLY_FX_X1,		// deathstate
+S_NULL,		// xdeathstate
+SFX_SPIRIT_DIE,		// deathsound
+12*FRACUNIT,		// speed
+10*FRACUNIT,		// radius
+6*FRACUNIT,		// height
+100,		// mass
+3,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_DROPOFF|MF_NOGRAVITY|MF_ALTSHADOW|MF_MISSILE,		// flags
+MF2_NOTELEPORT|MF2_SEEKERMISSILE|MF2_RIP|MF2_IMPACT|MF2_PCROSS		// flags2
+ },
+
+{		// MT_HOLY_TAIL
+-1,		// doomednum
+S_HOLY_TAIL1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+FRACUNIT,		// radius
+FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_DROPOFF|MF_NOGRAVITY|MF_NOCLIP|MF_ALTSHADOW,		// flags
+MF2_NOTELEPORT		// flags2
+ },
+
+{		// MT_HOLY_PUFF
+-1,		// doomednum
+S_HOLY_PUFF1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_NOGRAVITY|MF_SHADOW,		// flags
+0		// flags2
+ },
+
+{		// MT_HOLY_MISSILE
+-1,		// doomednum
+S_HOLY_MISSILE1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_HOLY_MISSILE_X,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+30*FRACUNIT,		// speed
+15*FRACUNIT,		// radius
+8*FRACUNIT,		// height
+100,		// mass
+4,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_DROPOFF|MF_NOGRAVITY|MF_MISSILE,		// flags
+MF2_NOTELEPORT		// flags2
+ },
+
+{		// MT_HOLY_MISSILE_PUFF
+-1,		// doomednum
+S_HOLY_MISSILE_P1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+4*FRACUNIT,		// radius
+8*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_DROPOFF|MF_NOGRAVITY|MF_ALTSHADOW,		// flags
+MF2_NOTELEPORT		// flags2
+ },
+
+{		// MT_MWANDPUFF
+-1,		// doomednum
+S_MWANDPUFF1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_NOGRAVITY,		// flags
+MF2_NOTELEPORT|MF2_CANNOTPUSH|MF2_NODMGTHRUST		// flags2
+ },
+
+{		// MT_MWANDSMOKE
+-1,		// doomednum
+S_MWANDSMOKE1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_NOGRAVITY|MF_SHADOW,		// flags
+MF2_NOTELEPORT|MF2_CANNOTPUSH|MF2_NODMGTHRUST		// flags2
+ },
+
+{		// MT_MWAND_MISSILE
+-1,		// doomednum
+S_MWAND_MISSILE1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_MWANDPUFF1,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+184*FRACUNIT,		// speed
+12*FRACUNIT,		// radius
+8*FRACUNIT,		// height
+100,		// mass
+2,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_NOGRAVITY,		// flags
+MF2_NOTELEPORT|MF2_RIP|MF2_IMPACT|MF2_PCROSS|MF2_NODMGTHRUST|MF2_CANNOTPUSH		// flags2
+ },
+
+{		// MT_MW_LIGHTNING
+8040,		// doomednum
+S_MW_LIGHTNING1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SPECIAL|MF_NOGRAVITY,		// flags
+0		// flags2
+ },
+
+{		// MT_LIGHTNING_CEILING
+-1,		// doomednum
+S_LIGHTNING_CEILING1,		// spawnstate
+144,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_LIGHTNING_C_X1,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+25*FRACUNIT,		// speed
+16*FRACUNIT,		// radius
+40*FRACUNIT,		// height
+100,		// mass
+8,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_NOGRAVITY|MF_MISSILE|MF_DROPOFF,		// flags
+MF2_NOTELEPORT|MF2_IMPACT|MF2_PCROSS		// flags2
+ },
+
+{		// MT_LIGHTNING_FLOOR
+-1,		// doomednum
+S_LIGHTNING_FLOOR1,		// spawnstate
+144,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_LIGHTNING_F_X1,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+25*FRACUNIT,		// speed
+16*FRACUNIT,		// radius
+40*FRACUNIT,		// height
+100,		// mass
+8,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_NOGRAVITY|MF_MISSILE|MF_DROPOFF,		// flags
+MF2_NOTELEPORT|MF2_IMPACT|MF2_PCROSS		// flags2
+ },
+
+{		// MT_LIGHTNING_ZAP
+-1,		// doomednum
+S_LIGHTNING_ZAP1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_LIGHTNING_ZAP_X8,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+15*FRACUNIT,		// radius
+35*FRACUNIT,		// height
+100,		// mass
+2,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_NOGRAVITY|MF_MISSILE|MF_DROPOFF,		// flags
+0		// flags2
+ },
+
+{		// MT_MSTAFF_FX
+-1,		// doomednum
+S_MSTAFF_FX1_1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_MSTAFF_FX_X1,		// deathstate
+S_NULL,		// xdeathstate
+SFX_MAGE_STAFF_EXPLODE,		// deathsound
+20*FRACUNIT,		// speed
+16*FRACUNIT,		// radius
+8*FRACUNIT,		// height
+100,		// mass
+6,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_NOGRAVITY,		// flags
+MF2_NOTELEPORT|MF2_FIREDAMAGE|MF2_RIP|MF2_IMPACT|MF2_PCROSS		// flags2
+ },
+
+{		// MT_MSTAFF_FX2
+-1,		// doomednum
+S_MSTAFF_FX2_1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_MSTAFF_FX2_X1,		// deathstate
+S_NULL,		// xdeathstate
+SFX_MAGE_STAFF_EXPLODE,		// deathsound
+17*FRACUNIT,		// speed
+20*FRACUNIT,		// radius
+8*FRACUNIT,		// height
+100,		// mass
+4,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_NOGRAVITY,		// flags
+MF2_NOTELEPORT|MF2_FIREDAMAGE|MF2_IMPACT|MF2_PCROSS|MF2_SEEKERMISSILE		// flags2
+ },
+
+{		// MT_FW_SWORD1
+12,		// doomednum
+S_FSWORD1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SPECIAL,		// flags
+MF2_FLOATBOB		// flags2
+ },
+
+{		// MT_FW_SWORD2
+13,		// doomednum
+S_FSWORD2,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SPECIAL,		// flags
+MF2_FLOATBOB		// flags2
+ },
+
+{		// MT_FW_SWORD3
+16,		// doomednum
+S_FSWORD3,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SPECIAL,		// flags
+MF2_FLOATBOB		// flags2
+ },
+
+{		// MT_CW_HOLY1
+18,		// doomednum
+S_CHOLY1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SPECIAL,		// flags
+MF2_FLOATBOB		// flags2
+ },
+
+{		// MT_CW_HOLY2
+19,		// doomednum
+S_CHOLY2,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SPECIAL,		// flags
+MF2_FLOATBOB		// flags2
+ },
+
+{		// MT_CW_HOLY3
+20,		// doomednum
+S_CHOLY3,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SPECIAL,		// flags
+MF2_FLOATBOB		// flags2
+ },
+
+{		// MT_MW_STAFF1
+21,		// doomednum
+S_MSTAFF1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SPECIAL,		// flags
+MF2_FLOATBOB		// flags2
+ },
+
+{		// MT_MW_STAFF2
+22,		// doomednum
+S_MSTAFF2,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SPECIAL,		// flags
+MF2_FLOATBOB		// flags2
+ },
+
+{		// MT_MW_STAFF3
+23,		// doomednum
+S_MSTAFF3,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SPECIAL,		// flags
+MF2_FLOATBOB		// flags2
+ },
+
+{		// MT_SNOUTPUFF
+-1,		// doomednum
+S_PUNCHPUFF1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_NOGRAVITY|MF_SHADOW,		// flags
+0		// flags2
+ },
+
+{		// MT_MW_CONE
+53,		// doomednum
+S_COS1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SPECIAL,		// flags
+0		// flags2
+ },
+
+{		// MT_SHARDFX1
+-1,		// doomednum
+S_SHARDFX1_1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_SHARDFXE1_1,		// deathstate
+S_NULL,		// xdeathstate
+SFX_MAGE_SHARDS_EXPLODE,		// deathsound
+25*FRACUNIT,		// speed
+13*FRACUNIT,		// radius
+8*FRACUNIT,		// height
+100,		// mass
+1,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_NOGRAVITY,		// flags
+MF2_NOTELEPORT|MF2_IMPACT|MF2_PCROSS|MF2_ICEDAMAGE		// flags2
+ },
+
+{		// MT_BLOOD
+-1,		// doomednum
+S_BLOOD1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+5,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP,		// flags
+0		// flags2
+ },
+
+{		// MT_BLOODSPLATTER
+-1,		// doomednum
+S_BLOODSPLATTER1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_BLOODSPLATTERX,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+2*FRACUNIT,		// radius
+4*FRACUNIT,		// height
+5,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF,		// flags
+MF2_NOTELEPORT|MF2_CANNOTPUSH		// flags2
+ },
+
+{		// MT_GIBS
+-1,		// doomednum
+S_GIBS1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_DROPOFF|MF_CORPSE,		// flags
+MF2_NOTELEPORT		// flags2
+ },
+
+{		// MT_PLAYER_FIGHTER
+-1,		// doomednum
+S_FPLAY,		// spawnstate
+100,		// spawnhealth
+S_FPLAY_RUN1,		// seestate
+SFX_NONE,		// seesound
+0,		// reactiontime
+SFX_NONE,		// attacksound
+S_FPLAY_PAIN,		// painstate
+255,		// painchance
+SFX_PLAYER_FIGHTER_PAIN,		// painsound
+S_NULL,		// meleestate
+S_FPLAY_ATK1,		// missilestate
+S_NULL,		// crashstate
+S_FPLAY_DIE1,		// deathstate
+S_FPLAY_XDIE1,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+16*FRACUNIT,		// radius
+64*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SOLID|MF_SHOOTABLE|MF_DROPOFF|MF_PICKUP|MF_NOTDMATCH,		// flags
+MF2_WINDTHRUST|MF2_FLOORCLIP|MF2_SLIDE|MF2_PASSMOBJ|MF2_TELESTOMP|MF2_PUSHWALL		// flags2
+ },
+
+{		// MT_BLOODYSKULL
+-1,		// doomednum
+S_BLOODYSKULL1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+4*FRACUNIT,		// radius
+4*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_DROPOFF,		// flags
+MF2_LOGRAV|MF2_CANNOTPUSH		// flags2
+ },
+
+{		// MT_PLAYER_SPEED
+-1,		// doomednum
+S_PLAYER_SPEED1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_NOGRAVITY|MF_ALTSHADOW,		// flags
+0		// flags2
+ },
+
+{		// MT_ICECHUNK
+-1,		// doomednum
+S_ICECHUNK1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+3*FRACUNIT,		// radius
+4*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_DROPOFF,		// flags
+MF2_LOGRAV|MF2_CANNOTPUSH|MF2_FLOORCLIP		// flags2
+ },
+
+{		// MT_PLAYER_CLERIC
+-1,		// doomednum
+S_CPLAY,		// spawnstate
+100,		// spawnhealth
+S_CPLAY_RUN1,		// seestate
+SFX_NONE,		// seesound
+0,		// reactiontime
+SFX_NONE,		// attacksound
+S_CPLAY_PAIN,		// painstate
+255,		// painchance
+SFX_PLAYER_CLERIC_PAIN,		// painsound
+S_NULL,		// meleestate
+S_CPLAY_ATK1,		// missilestate
+S_NULL,		// crashstate
+S_CPLAY_DIE1,		// deathstate
+S_CPLAY_XDIE1,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+16*FRACUNIT,		// radius
+64*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SOLID|MF_SHOOTABLE|MF_DROPOFF|MF_PICKUP|MF_NOTDMATCH,		// flags
+MF2_WINDTHRUST|MF2_FLOORCLIP|MF2_SLIDE|MF2_PASSMOBJ|MF2_TELESTOMP|MF2_PUSHWALL		// flags2
+ },
+
+{		// MT_PLAYER_MAGE
+-1,		// doomednum
+S_MPLAY,		// spawnstate
+100,		// spawnhealth
+S_MPLAY_RUN1,		// seestate
+SFX_NONE,		// seesound
+0,		// reactiontime
+SFX_NONE,		// attacksound
+S_MPLAY_PAIN,		// painstate
+255,		// painchance
+SFX_PLAYER_MAGE_PAIN,		// painsound
+S_NULL,		// meleestate
+S_MPLAY_ATK1,		// missilestate
+S_NULL,		// crashstate
+S_MPLAY_DIE1,		// deathstate
+S_MPLAY_XDIE1,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+16*FRACUNIT,		// radius
+64*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SOLID|MF_SHOOTABLE|MF_DROPOFF|MF_PICKUP|MF_NOTDMATCH,		// flags
+MF2_WINDTHRUST|MF2_FLOORCLIP|MF2_SLIDE|MF2_PASSMOBJ|MF2_TELESTOMP|MF2_PUSHWALL		// flags2
+ },
+
+#ifdef ASSASSIN
+{		// MT_PLAYER_ASS
+-1,		// doomednum
+S_APLAY,		// spawnstate
+100,		// spawnhealth
+S_APLAY_RUN1,		// seestate
+SFX_NONE,		// seesound
+0,		// reactiontime
+SFX_NONE, 		// attacksound
+S_APLAY_PAIN,		// painstate
+255,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_APLAY_ATK1,		// misslestate
+S_NULL,		// crashstate
+S_APLAY_DIE1,		// deathstate
+S_APLAY_XDIE1,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+16*FRACUNIT,		// radius
+64*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SOLID|MF_SHOOTABLE|MF_DROPOFF|MF_PICKUP|MF_NOTDMATCH,		// flags
+MF2_WINDTHRUST|MF2_FLOORCLIP|MF2_SLIDE|MF2_PASSMOBJ|MF2_TELESTOMP|MF2_PUSHWALL		// flags2
+ },
+#endif	/* ASSASSIN */
+
+{		// MT_PIGPLAYER
+-1,		// doomednum
+S_PIGPLAY,		// spawnstate
+100,		// spawnhealth
+S_PIGPLAY_RUN1,		// seestate
+SFX_NONE,		// seesound
+0,		// reactiontime
+SFX_NONE,		// attacksound
+S_PIGPLAY_PAIN,		// painstate
+255,		// painchance
+SFX_PIG_PAIN,		// painsound
+S_NULL,		// meleestate
+S_PIGPLAY_ATK1,		// missilestate
+S_NULL,		// crashstate
+S_PIG_DIE1,		// deathstate
+S_NULL,		// xdeathstate
+SFX_PIG_DEATH,		// deathsound
+0,		// speed
+16*FRACUNIT,		// radius
+24*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SOLID|MF_SHOOTABLE|MF_DROPOFF|MF_NOTDMATCH,		// flags
+MF2_WINDTHRUST|MF2_SLIDE|MF2_PASSMOBJ|MF2_FLOORCLIP|MF2_TELESTOMP|MF2_PUSHWALL		// flags2
+ },
+
+{		// MT_PIG
+-1,		// doomednum
+S_PIG_LOOK1,		// spawnstate
+25,		// spawnhealth
+S_PIG_WALK1,		// seestate
+SFX_PIG_ACTIVE1,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_PIG_PAIN,		// painstate
+128,		// painchance
+SFX_PIG_PAIN,		// painsound
+S_PIG_ATK1,		// meleestate
+0,		// missilestate
+S_NULL,		// crashstate
+S_PIG_DIE1,		// deathstate
+S_NULL,		// xdeathstate
+SFX_PIG_DEATH,		// deathsound
+10,		// speed
+12*FRACUNIT,		// radius
+22*FRACUNIT,		// height
+60,		// mass
+0,		// damage
+SFX_PIG_ACTIVE1,		// activesound
+MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL,		// flags
+MF2_WINDTHRUST|MF2_FLOORCLIP|MF2_PASSMOBJ|MF2_PUSHWALL|MF2_TELESTOMP		// flags2
+ },
+
+{		// MT_CENTAUR
+107,		// doomednum
+S_CENTAUR_LOOK1,		// spawnstate
+200,		// spawnhealth
+S_CENTAUR_WALK1,		// seestate
+SFX_CENTAUR_SIGHT,		// seesound
+8,		// reactiontime
+SFX_CENTAUR_ATTACK,		// attacksound
+S_CENTAUR_PAIN1,		// painstate
+135,		// painchance
+SFX_CENTAUR_PAIN,		// painsound
+S_CENTAUR_ATK1,		// meleestate
+0,		// missilestate
+S_NULL,		// crashstate
+S_CENTAUR_DEATH1,		// deathstate
+S_CENTAUR_DEATH_X1,		// xdeathstate
+SFX_CENTAUR_DEATH,		// deathsound
+13,		// speed
+20*FRACUNIT,		// radius
+64*FRACUNIT,		// height
+120,		// mass
+0,		// damage
+SFX_CENTAUR_ACTIVE,		// activesound
+MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL,		// flags
+MF2_FLOORCLIP|MF2_PASSMOBJ|MF2_PUSHWALL|MF2_MCROSS|MF2_TELESTOMP		// flags2
+ },
+
+{		// MT_CENTAURLEADER
+115,		// doomednum
+S_CENTAUR_LOOK1,		// spawnstate
+250,		// spawnhealth
+S_CENTAUR_WALK1,		// seestate
+SFX_CENTAUR_SIGHT,		// seesound
+8,		// reactiontime
+SFX_CENTAUR_ATTACK,		// attacksound
+S_CENTAUR_PAIN1,		// painstate
+96,		// painchance
+SFX_CENTAUR_PAIN,		// painsound
+S_CENTAUR_ATK1,		// meleestate
+S_CENTAUR_MISSILE1,		// missilestate
+S_NULL,		// crashstate
+S_CENTAUR_DEATH1,		// deathstate
+S_CENTAUR_DEATH_X1,		// xdeathstate
+SFX_CENTAUR_DEATH,		// deathsound
+10,		// speed
+20*FRACUNIT,		// radius
+64*FRACUNIT,		// height
+120,		// mass
+0,		// damage
+SFX_CENTAUR_ACTIVE,		// activesound
+MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL,		// flags
+MF2_FLOORCLIP|MF2_PASSMOBJ|MF2_PUSHWALL|MF2_MCROSS|MF2_TELESTOMP		// flags2
+ },
+
+{		// MT_CENTAUR_FX
+-1,		// doomednum
+S_CENTAUR_FX1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_CENTAUR_FX_X1,		// deathstate
+S_NULL,		// xdeathstate
+SFX_CENTAUR_MISSILE_EXPLODE,		// deathsound
+20*FRACUNIT,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+4,		// damage
+SFX_NONE,		// activesound
+MF_MISSILE|MF_NOBLOCKMAP|MF_NOGRAVITY|MF_DROPOFF,		// flags
+MF2_NOTELEPORT|MF2_IMPACT|MF2_PCROSS		// flags2
+ },
+
+{		// MT_CENTAUR_SHIELD
+-1,		// doomednum
+S_CENTAUR_SHIELD1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_CENTAUR_SHIELD_X1,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_DROPOFF|MF_CORPSE,		// flags
+MF2_NOTELEPORT		// flags2
+ },
+
+{		// MT_CENTAUR_SWORD
+-1,		// doomednum
+S_CENTAUR_SWORD1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_CENTAUR_SWORD_X1,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_DROPOFF|MF_CORPSE,		// flags
+MF2_NOTELEPORT		// flags2
+ },
+
+{		// MT_DEMON
+31,		// doomednum
+S_DEMN_LOOK1,		// spawnstate
+250,		// spawnhealth
+S_DEMN_CHASE1,		// seestate
+SFX_DEMON_SIGHT,		// seesound
+8,		// reactiontime
+SFX_DEMON_ATTACK,		// attacksound
+S_DEMN_PAIN1,		// painstate
+50,		// painchance
+SFX_DEMON_PAIN,		// painsound
+S_DEMN_ATK1_1,		// meleestate
+S_DEMN_ATK2_1,		// missilestate
+S_NULL,		// crashstate
+S_DEMN_DEATH1,		// deathstate
+S_DEMN_XDEATH1,		// xdeathstate
+SFX_DEMON_DEATH,		// deathsound
+13,		// speed
+32*FRACUNIT,		// radius
+64*FRACUNIT,		// height
+220,		// mass
+0,		// damage
+SFX_DEMON_ACTIVE,		// activesound
+MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL,		// flags
+MF2_FLOORCLIP|MF2_PASSMOBJ|MF2_MCROSS|MF2_TELESTOMP		// flags2
+ },
+
+{		// MT_DEMONCHUNK1
+-1,		// doomednum
+S_DEMONCHUNK1_1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_DEMONCHUNK1_4,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+5*FRACUNIT,		// radius
+5*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_CORPSE,		// flags
+MF2_NOTELEPORT|MF2_FLOORCLIP		// flags2
+ },
+
+{		// MT_DEMONCHUNK2
+-1,		// doomednum
+S_DEMONCHUNK2_1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_DEMONCHUNK2_4,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+5*FRACUNIT,		// radius
+5*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_CORPSE,		// flags
+MF2_NOTELEPORT|MF2_FLOORCLIP		// flags2
+ },
+
+{		// MT_DEMONCHUNK3
+-1,		// doomednum
+S_DEMONCHUNK3_1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_DEMONCHUNK3_4,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+5*FRACUNIT,		// radius
+5*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_CORPSE,		// flags
+MF2_NOTELEPORT|MF2_FLOORCLIP		// flags2
+ },
+
+{		// MT_DEMONCHUNK4
+-1,		// doomednum
+S_DEMONCHUNK4_1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_DEMONCHUNK4_4,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+5*FRACUNIT,		// radius
+5*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_CORPSE,		// flags
+MF2_NOTELEPORT|MF2_FLOORCLIP		// flags2
+ },
+
+{		// MT_DEMONCHUNK5
+-1,		// doomednum
+S_DEMONCHUNK5_1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_DEMONCHUNK5_4,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+5*FRACUNIT,		// radius
+5*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_CORPSE,		// flags
+MF2_NOTELEPORT|MF2_FLOORCLIP		// flags2
+ },
+
+{		// MT_DEMONFX1
+-1,		// doomednum
+S_DEMONFX_MOVE1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_DEMONFX_BOOM1,		// deathstate
+S_NULL,		// xdeathstate
+SFX_DEMON_MISSILE_EXPLODE,		// deathsound
+15*FRACUNIT,		// speed
+10*FRACUNIT,		// radius
+6*FRACUNIT,		// height
+100,		// mass
+5,		// damage
+SFX_NONE,		// activesound
+MF_MISSILE|MF_NOBLOCKMAP|MF_NOGRAVITY|MF_DROPOFF,		// flags
+MF2_NOTELEPORT|MF2_IMPACT|MF2_PCROSS|MF2_FIREDAMAGE		// flags2
+ },
+
+{		// MT_DEMON2
+8080,		// doomednum
+S_DEMN2_LOOK1,		// spawnstate
+250,		// spawnhealth
+S_DEMN2_CHASE1,		// seestate
+SFX_DEMON_SIGHT,		// seesound
+8,		// reactiontime
+SFX_DEMON_ATTACK,		// attacksound
+S_DEMN2_PAIN1,		// painstate
+50,		// painchance
+SFX_DEMON_PAIN,		// painsound
+S_DEMN2_ATK1_1,		// meleestate
+S_DEMN2_ATK2_1,		// missilestate
+S_NULL,		// crashstate
+S_DEMN2_DEATH1,		// deathstate
+S_DEMN2_XDEATH1,		// xdeathstate
+SFX_DEMON_DEATH,		// deathsound
+13,		// speed
+32*FRACUNIT,		// radius
+64*FRACUNIT,		// height
+220,		// mass
+0,		// damage
+SFX_DEMON_ACTIVE,		// activesound
+MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL,		// flags
+MF2_FLOORCLIP|MF2_PASSMOBJ|MF2_MCROSS|MF2_TELESTOMP		// flags2
+ },
+
+{		// MT_DEMON2CHUNK1
+-1,		// doomednum
+S_DEMON2CHUNK1_1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_DEMON2CHUNK1_4,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+5*FRACUNIT,		// radius
+5*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_CORPSE,		// flags
+MF2_NOTELEPORT|MF2_FLOORCLIP		// flags2
+ },
+
+{		// MT_DEMON2CHUNK2
+-1,		// doomednum
+S_DEMON2CHUNK2_1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_DEMON2CHUNK2_4,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+5*FRACUNIT,		// radius
+5*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_CORPSE,		// flags
+MF2_NOTELEPORT|MF2_FLOORCLIP		// flags2
+ },
+
+{		// MT_DEMON2CHUNK3
+-1,		// doomednum
+S_DEMON2CHUNK3_1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_DEMON2CHUNK3_4,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+5*FRACUNIT,		// radius
+5*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_CORPSE,		// flags
+MF2_NOTELEPORT|MF2_FLOORCLIP		// flags2
+ },
+
+{		// MT_DEMON2CHUNK4
+-1,		// doomednum
+S_DEMON2CHUNK4_1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_DEMON2CHUNK4_4,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+5*FRACUNIT,		// radius
+5*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_CORPSE,		// flags
+MF2_NOTELEPORT|MF2_FLOORCLIP		// flags2
+ },
+
+{		// MT_DEMON2CHUNK5
+-1,		// doomednum
+S_DEMON2CHUNK5_1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_DEMON2CHUNK5_4,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+5*FRACUNIT,		// radius
+5*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_CORPSE,		// flags
+MF2_NOTELEPORT|MF2_FLOORCLIP		// flags2
+ },
+
+{		// MT_DEMON2FX1
+-1,		// doomednum
+S_DEMON2FX_MOVE1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_DEMON2FX_BOOM1,		// deathstate
+S_NULL,		// xdeathstate
+SFX_DEMON_MISSILE_EXPLODE,		// deathsound
+15*FRACUNIT,		// speed
+10*FRACUNIT,		// radius
+6*FRACUNIT,		// height
+100,		// mass
+5,		// damage
+SFX_NONE,		// activesound
+MF_MISSILE|MF_NOBLOCKMAP|MF_NOGRAVITY|MF_DROPOFF,		// flags
+MF2_NOTELEPORT|MF2_IMPACT|MF2_PCROSS|MF2_FIREDAMAGE		// flags2
+ },
+
+{		// MT_WRAITHB
+10011,		// doomednum
+S_WRAITH_LOOK1,		// spawnstate
+150,		// spawnhealth
+S_WRAITH_RAISE1,		// seestate
+SFX_WRAITH_SIGHT,		// seesound
+8,		// reactiontime
+SFX_WRAITH_ATTACK,		// attacksound
+S_WRAITH_PAIN1,		// painstate
+25,		// painchance
+SFX_WRAITH_PAIN,		// painsound
+S_WRAITH_ATK1_1,		// meleestate
+S_WRAITH_ATK2_1,		// missilestate
+S_NULL,		// crashstate
+S_WRAITH_DEATH1_1,		// deathstate
+S_WRAITH_DEATH2_1,		// xdeathstate
+SFX_WRAITH_DEATH,		// deathsound
+11,		// speed
+20*FRACUNIT,		// radius
+68*FRACUNIT,		// height
+75,		// mass
+10,		// damage
+SFX_WRAITH_ACTIVE,		// activesound
+MF_DROPOFF|MF_NOGRAVITY|MF_FLOAT|MF_COUNTKILL,		// flags
+MF2_FLOORCLIP|MF2_PASSMOBJ|MF2_PUSHWALL|MF2_TELESTOMP|MF2_DONTDRAW		// flags2
+ },
+
+{		// MT_WRAITH
+34,		// doomednum
+S_WRAITH_INIT1,		// spawnstate
+150,		// spawnhealth
+S_WRAITH_CHASE1,		// seestate
+SFX_WRAITH_SIGHT,		// seesound
+8,		// reactiontime
+SFX_WRAITH_ATTACK,		// attacksound
+S_WRAITH_PAIN1,		// painstate
+25,		// painchance
+SFX_WRAITH_PAIN,		// painsound
+S_WRAITH_ATK1_1,		// meleestate
+S_WRAITH_ATK2_1,		// missilestate
+S_NULL,		// crashstate
+S_WRAITH_DEATH1_1,		// deathstate
+S_WRAITH_DEATH2_1,		// xdeathstate
+SFX_WRAITH_DEATH,		// deathsound
+11,		// speed
+20*FRACUNIT,		// radius
+55*FRACUNIT,		// height
+75,		// mass
+10,		// damage
+SFX_WRAITH_ACTIVE,		// activesound
+MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL|MF_DROPOFF|MF_NOGRAVITY|MF_FLOAT,		// flags
+MF2_FLOORCLIP|MF2_PASSMOBJ|MF2_PUSHWALL|MF2_TELESTOMP		// flags2
+ },
+
+{		// MT_WRAITHFX1
+-1,		// doomednum
+S_WRTHFX_MOVE1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_WRTHFX_BOOM1,		// deathstate
+S_NULL,		// xdeathstate
+SFX_WRAITH_MISSILE_EXPLODE,		// deathsound
+14*FRACUNIT,		// speed
+10*FRACUNIT,		// radius
+6*FRACUNIT,		// height
+5,		// mass
+5,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_NOGRAVITY|MF_DROPOFF|MF_MISSILE,		// flags
+MF2_NOTELEPORT|MF2_IMPACT|MF2_PCROSS|MF2_FLOORCLIP|MF2_FIREDAMAGE		// flags2
+ },
+
+{		// MT_WRAITHFX2
+-1,		// doomednum
+S_WRTHFX_SIZZLE1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+2*FRACUNIT,		// radius
+5*FRACUNIT,		// height
+5,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_DROPOFF,		// flags
+MF2_NOTELEPORT|MF2_FLOORCLIP		// flags2
+ },
+
+{		// MT_WRAITHFX3
+-1,		// doomednum
+S_WRTHFX_DROP1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_WRTHFX_DEAD1,		// deathstate
+S_NULL,		// xdeathstate
+SFX_DRIP,		// deathsound
+0,		// speed
+2*FRACUNIT,		// radius
+5*FRACUNIT,		// height
+5,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_DROPOFF|MF_MISSILE,		// flags
+MF2_NOTELEPORT|MF2_FLOORCLIP		// flags2
+ },
+
+{		// MT_WRAITHFX4
+-1,		// doomednum
+S_WRTHFX_ADROP1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_WRTHFX_ADEAD1,		// deathstate
+S_NULL,		// xdeathstate
+SFX_DRIP,		// deathsound
+0,		// speed
+2*FRACUNIT,		// radius
+5*FRACUNIT,		// height
+5,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_DROPOFF|MF_MISSILE,		// flags
+MF2_NOTELEPORT		// flags2
+ },
+
+{		// MT_WRAITHFX5
+-1,		// doomednum
+S_WRTHFX_BDROP1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_WRTHFX_BDEAD1,		// deathstate
+S_NULL,		// xdeathstate
+SFX_DRIP,		// deathsound
+0,		// speed
+2*FRACUNIT,		// radius
+5*FRACUNIT,		// height
+5,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_DROPOFF|MF_MISSILE,		// flags
+MF2_NOTELEPORT		// flags2
+ },
+
+{		// MT_MINOTAUR
+9,		// doomednum
+S_MNTR_SPAWN1,		// spawnstate
+2500,		// spawnhealth
+S_MNTR_WALK1,		// seestate
+SFX_MAULATOR_SIGHT,		// seesound
+8,		// reactiontime
+SFX_MAULATOR_HAMMER_SWING,		// attacksound
+S_MNTR_PAIN1,		// painstate
+25,		// painchance
+SFX_MAULATOR_PAIN,		// painsound
+S_MNTR_ATK1_1,		// meleestate
+S_MNTR_ATK2_1,		// missilestate
+S_NULL,		// crashstate
+S_MNTR_DIE1,		// deathstate
+S_NULL,		// xdeathstate
+SFX_MAULATOR_DEATH,		// deathsound
+16,		// speed
+28*FRACUNIT,		// radius
+100*FRACUNIT,		// height
+800,		// mass
+7,		// damage
+SFX_MAULATOR_ACTIVE,		// activesound
+MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL|MF_SHADOW,		// flags
+MF2_FLOORCLIP|MF2_PASSMOBJ|MF2_PUSHWALL|MF2_TELESTOMP		// flags2
+ },
+
+{		// MT_MNTRFX1
+-1,		// doomednum
+S_MNTRFX1_1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_MNTRFXI1_1,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+20*FRACUNIT,		// speed
+10*FRACUNIT,		// radius
+6*FRACUNIT,		// height
+100,		// mass
+3,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_NOGRAVITY,		// flags
+MF2_NOTELEPORT|MF2_FIREDAMAGE		// flags2
+ },
+
+{		// MT_MNTRFX2
+-1,		// doomednum
+S_MNTRFX2_1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_MNTRFXI2_1,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+14*FRACUNIT,		// speed
+5*FRACUNIT,		// radius
+12*FRACUNIT,		// height
+100,		// mass
+4,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_NOGRAVITY,		// flags
+MF2_NOTELEPORT|MF2_FIREDAMAGE		// flags2
+ },
+
+{		// MT_MNTRFX3
+-1,		// doomednum
+S_MNTRFX3_1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+0,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_MNTRFXI2_1,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+8*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+4,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_NOGRAVITY,		// flags
+MF2_NOTELEPORT|MF2_FIREDAMAGE		// flags2
+ },
+
+{		// MT_MNTRSMOKE
+-1,		// doomednum
+S_MINOSMOKE1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_NOGRAVITY|MF_SHADOW,		// flags
+MF2_NOTELEPORT		// flags2
+ },
+
+{		// MT_MNTRSMOKEEXIT
+-1,		// doomednum
+S_MINOSMOKEX1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_NOGRAVITY|MF_SHADOW,		// flags
+MF2_NOTELEPORT		// flags2
+ },
+
+{		// MT_SERPENT
+121,		// doomednum
+S_SERPENT_LOOK1,		// spawnstate
+90,		// spawnhealth
+S_SERPENT_SWIM1,		// seestate
+SFX_SERPENT_SIGHT,		// seesound
+8,		// reactiontime
+SFX_SERPENT_ATTACK,		// attacksound
+S_SERPENT_PAIN1,		// painstate
+96,		// painchance
+SFX_SERPENT_PAIN,		// painsound
+S_SERPENT_SURFACE1,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_SERPENT_DIE1,		// deathstate
+S_SERPENT_XDIE1,		// xdeathstate
+SFX_SERPENT_DEATH,		// deathsound
+12,		// speed
+32*FRACUNIT,		// radius
+70*FRACUNIT,		// height
+H2MAXINT,	// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SOLID|MF_COUNTKILL|MF_NOBLOOD,		// flags
+MF2_PASSMOBJ|MF2_DONTDRAW|MF2_CANTLEAVEFLOORPIC|MF2_NONSHOOTABLE|MF2_MCROSS		// flags2
+ },
+
+{		// MT_SERPENTLEADER
+120,		// doomednum
+S_SERPENT_LOOK1,		// spawnstate
+90,		// spawnhealth
+S_SERPENT_SWIM1,		// seestate
+SFX_SERPENT_SIGHT,		// seesound
+8,		// reactiontime
+SFX_SERPENT_ATTACK,		// attacksound
+S_SERPENT_PAIN1,		// painstate
+96,		// painchance
+SFX_SERPENT_PAIN,		// painsound
+S_SERPENT_SURFACE1,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_SERPENT_DIE1,		// deathstate
+S_SERPENT_XDIE1,		// xdeathstate
+SFX_SERPENT_DEATH,		// deathsound
+12,		// speed
+32*FRACUNIT,		// radius
+70*FRACUNIT,		// height
+200,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SOLID|MF_COUNTKILL|MF_NOBLOOD,		// flags
+MF2_PASSMOBJ|MF2_DONTDRAW|MF2_CANTLEAVEFLOORPIC|MF2_NONSHOOTABLE|MF2_MCROSS		// flags2
+ },
+
+{		// MT_SERPENTFX
+-1,		// doomednum
+S_SERPENT_FX1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+0,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_SERPENT_FX_X1,		// deathstate
+S_NULL,		// xdeathstate
+SFX_SERPENTFX_HIT,		// deathsound
+15*FRACUNIT,		// speed
+8*FRACUNIT,		// radius
+10*FRACUNIT,		// height
+100,		// mass
+4,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_NOGRAVITY,		// flags
+MF2_NOTELEPORT		// flags2
+ },
+
+{		// MT_SERPENT_HEAD
+-1,		// doomednum
+S_SERPENT_HEAD1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+5*FRACUNIT,		// radius
+10*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP,		// flags
+MF2_LOGRAV		// flags2
+ },
+
+{		// MT_SERPENT_GIB1
+-1,		// doomednum
+S_SERPENT_GIB1_1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+3*FRACUNIT,		// radius
+3*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_NOGRAVITY,		// flags
+0		// flags2
+ },
+
+{		// MT_SERPENT_GIB2
+-1,		// doomednum
+S_SERPENT_GIB2_1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+3*FRACUNIT,		// radius
+3*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_NOGRAVITY,		// flags
+0		// flags2
+ },
+
+{		// MT_SERPENT_GIB3
+-1,		// doomednum
+S_SERPENT_GIB3_1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+3*FRACUNIT,		// radius
+3*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_NOGRAVITY,		// flags
+0		// flags2
+ },
+
+{		// MT_BISHOP
+114,		// doomednum
+S_BISHOP_LOOK1,		// spawnstate
+130,		// spawnhealth
+S_BISHOP_WALK1,		// seestate
+SFX_BISHOP_SIGHT,		// seesound
+8,		// reactiontime
+SFX_BISHOP_ATTACK,		// attacksound
+S_BISHOP_PAIN1,		// painstate
+110,		// painchance
+SFX_BISHOP_PAIN,		// painsound
+0,		// meleestate
+S_BISHOP_ATK1,		// missilestate
+S_NULL,		// crashstate
+S_BISHOP_DEATH1,		// deathstate
+S_NULL,		// xdeathstate
+SFX_BISHOP_DEATH,		// deathsound
+10,		// speed
+22*FRACUNIT,		// radius
+65*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_BISHOP_ACTIVE,		// activesound
+MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL|MF_FLOAT|MF_NOGRAVITY|MF_NOBLOOD,		// flags
+MF2_PASSMOBJ|MF2_PUSHWALL|MF2_TELESTOMP		// flags2
+ },
+
+{		// MT_BISHOP_PUFF
+-1,		// doomednum
+S_BISHOP_PUFF1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SHADOW|MF_NOBLOCKMAP|MF_NOGRAVITY,		// flags
+0		// flags2
+ },
+
+{		// MT_BISHOPBLUR
+-1,		// doomednum
+S_BISHOPBLUR1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_NOGRAVITY|MF_SHADOW,		// flags
+0		// flags2
+ },
+
+{		// MT_BISHOPPAINBLUR
+-1,		// doomednum
+S_BISHOPPAINBLUR1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_NOGRAVITY|MF_SHADOW,		// flags
+0		// flags2
+ },
+
+{		// MT_BISH_FX
+-1,		// doomednum
+S_BISHFX1_1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_BISHFXI1_1,		// deathstate
+S_NULL,		// xdeathstate
+SFX_BISHOP_MISSILE_EXPLODE,		// deathsound
+10*FRACUNIT,		// speed
+10*FRACUNIT,		// radius
+6*FRACUNIT,		// height
+100,		// mass
+1,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_NOGRAVITY,		// flags
+MF2_NOTELEPORT|MF2_SEEKERMISSILE		// flags2
+ },
+
+{		// MT_DRAGON
+254,		// doomednum
+S_DRAGON_LOOK1,		// spawnstate
+640,		// spawnhealth
+S_DRAGON_INIT,		// seestate
+SFX_DRAGON_SIGHT,		// seesound
+8,		// reactiontime
+SFX_DRAGON_ATTACK,		// attacksound
+S_DRAGON_PAIN1,		// painstate
+128,		// painchance
+SFX_DRAGON_PAIN,		// painsound
+S_NULL,		// meleestate
+S_DRAGON_ATK1,		// missilestate
+S_NULL,		// crashstate
+S_DRAGON_DEATH1,		// deathstate
+S_NULL,		// xdeathstate
+SFX_DRAGON_DEATH,		// deathsound
+10*FRACUNIT,		// speed
+20*FRACUNIT,		// radius
+65*FRACUNIT,		// height
+H2MAXINT,	// mass
+0,		// damage
+SFX_DRAGON_ACTIVE,		// activesound
+MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL|MF_FLOAT|MF_NOGRAVITY|MF_NOBLOOD,		// flags
+MF2_PASSMOBJ|MF2_BOSS		// flags2
+ },
+
+{		// MT_DRAGON_FX
+-1,		// doomednum
+S_DRAGON_FX1_1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_DRAGON_FX1_X1,		// deathstate
+S_NULL,		// xdeathstate
+SFX_DRAGON_FIREBALL_EXPLODE,		// deathsound
+24*FRACUNIT,		// speed
+12*FRACUNIT,		// radius
+10*FRACUNIT,		// height
+100,		// mass
+6,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_NOGRAVITY,		// flags
+MF2_NOTELEPORT|MF2_FIREDAMAGE		// flags2
+ },
+
+{		// MT_DRAGON_FX2
+-1,		// doomednum
+S_DRAGON_FX2_1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_DRAGON_FIREBALL_EXPLODE,		// deathsound
+0,		// speed
+8*FRACUNIT,		// radius
+8*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP,		// flags
+MF2_NOTELEPORT|MF2_FIREDAMAGE|MF2_DONTDRAW		// flags2
+ },
+
+{		// MT_ARMOR_1
+8005,		// doomednum
+S_ARMOR_1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SPECIAL|MF_NOGRAVITY,		// flags
+0		// flags2
+ },
+
+{		// MT_ARMOR_2
+8006,		// doomednum
+S_ARMOR_2,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SPECIAL|MF_NOGRAVITY,		// flags
+0		// flags2
+ },
+
+{		// MT_ARMOR_3
+8007,		// doomednum
+S_ARMOR_3,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SPECIAL|MF_NOGRAVITY,		// flags
+0		// flags2
+ },
+
+{		// MT_ARMOR_4
+8008,		// doomednum
+S_ARMOR_4,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SPECIAL|MF_NOGRAVITY,		// flags
+0		// flags2
+ },
+
+{		// MT_MANA1
+122,		// doomednum
+S_MANA1_1,		// spawnstate
+10,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+8*FRACUNIT,		// radius
+8*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SPECIAL,		// flags
+MF2_FLOATBOB		// flags2
+ },
+
+{		// MT_MANA2
+124,		// doomednum
+S_MANA2_1,		// spawnstate
+10,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+8*FRACUNIT,		// radius
+8*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SPECIAL,		// flags
+MF2_FLOATBOB		// flags2
+ },
+
+{		// MT_MANA3
+8004,		// doomednum
+S_MANA3_1,		// spawnstate
+20,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+8*FRACUNIT,		// radius
+8*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SPECIAL,		// flags
+MF2_FLOATBOB		// flags2
+ },
+
+{		// MT_KEY1
+8030,		// doomednum
+S_KEY1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+8*FRACUNIT,		// radius
+20*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SPECIAL,		// flags
+0		// flags2
+ },
+
+{		// MT_KEY2
+8031,		// doomednum
+S_KEY2,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+8*FRACUNIT,		// radius
+20*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SPECIAL,		// flags
+0		// flags2
+ },
+
+{		// MT_KEY3
+8032,		// doomednum
+S_KEY3,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+8*FRACUNIT,		// radius
+20*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SPECIAL,		// flags
+0		// flags2
+ },
+
+{		// MT_KEY4
+8033,		// doomednum
+S_KEY4,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+8*FRACUNIT,		// radius
+20*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SPECIAL,		// flags
+0		// flags2
+ },
+
+{		// MT_KEY5
+8034,		// doomednum
+S_KEY5,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+8*FRACUNIT,		// radius
+20*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SPECIAL,		// flags
+0		// flags2
+ },
+
+{		// MT_KEY6
+8035,		// doomednum
+S_KEY6,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+8*FRACUNIT,		// radius
+20*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SPECIAL,		// flags
+0		// flags2
+ },
+
+{		// MT_KEY7
+8036,		// doomednum
+S_KEY7,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+8*FRACUNIT,		// radius
+20*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SPECIAL,		// flags
+0		// flags2
+ },
+
+{		// MT_KEY8
+8037,		// doomednum
+S_KEY8,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+8*FRACUNIT,		// radius
+20*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SPECIAL,		// flags
+0		// flags2
+ },
+
+{		// MT_KEY9
+8038,		// doomednum
+S_KEY9,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+8*FRACUNIT,		// radius
+20*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SPECIAL,		// flags
+0		// flags2
+ },
+
+{		// MT_KEYA
+8039,		// doomednum
+S_KEYA,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+8*FRACUNIT,		// radius
+20*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SPECIAL,		// flags
+0		// flags2
+ },
+
+{		// MT_KEYB
+8200,		// doomednum
+S_KEYB,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+8*FRACUNIT,		// radius
+20*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SPECIAL,		// flags
+0		// flags2
+ },
+
+{		// MT_SOUNDWIND
+1410,		// doomednum
+S_SND_WIND1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_NOSECTOR,		// flags
+0		// flags2
+ },
+
+{		// MT_SOUNDWATERFALL
+41,		// doomednum
+S_SND_WATERFALL,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_NOSECTOR,		// flags
+0		// flags2
+ },
+
+{		// MT_ETTIN
+10030,		// doomednum
+S_ETTIN_LOOK1,		// spawnstate
+175,		// spawnhealth
+S_ETTIN_CHASE1,		// seestate
+SFX_ETTIN_SIGHT,		// seesound
+8,		// reactiontime
+SFX_ETTIN_ATTACK,		// attacksound
+S_ETTIN_PAIN1,		// painstate
+60,		// painchance
+SFX_ETTIN_PAIN,		// painsound
+S_ETTIN_ATK1_1,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_ETTIN_DEATH1_1,		// deathstate
+S_ETTIN_DEATH2_1,		// xdeathstate
+SFX_ETTIN_DEATH,		// deathsound
+13,		// speed
+25*FRACUNIT,		// radius
+68*FRACUNIT,		// height
+175,		// mass
+3,		// damage
+SFX_ETTIN_ACTIVE,		// activesound
+MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL,		// flags
+MF2_FLOORCLIP|MF2_PUSHWALL|MF2_MCROSS|MF2_TELESTOMP		// flags2
+ },
+
+{		// MT_ETTIN_MACE
+-1,		// doomednum
+S_ETTIN_MACE1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_ETTIN_MACE5,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+5*FRACUNIT,		// radius
+5*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_DROPOFF|MF_CORPSE,		// flags
+MF2_NOTELEPORT|MF2_FLOORCLIP		// flags2
+ },
+
+{		// MT_FIREDEMON
+10060,		// doomednum
+S_FIRED_SPAWN1,		// spawnstate
+80,		// spawnhealth
+S_FIRED_LOOK4,		// seestate
+SFX_FIRED_SPAWN,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_FIRED_PAIN1,		// painstate
+1,		// painchance
+SFX_FIRED_PAIN,		// painsound
+S_NULL,		// meleestate
+S_FIRED_ATTACK1,		// missilestate
+S_FIRED_XDEATH1,		// crashstate
+S_FIRED_DEATH1,		// deathstate
+S_FIRED_XDEATH1,		// xdeathstate
+SFX_FIRED_DEATH,		// deathsound
+13,		// speed
+20*FRACUNIT,		// radius
+68*FRACUNIT,		// height
+75,		// mass
+1,		// damage
+SFX_FIRED_ACTIVE,		// activesound
+MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL|MF_DROPOFF|MF_NOGRAVITY|MF_FLOAT,		// flags
+MF2_FLOORCLIP|MF2_PASSMOBJ|MF2_PUSHWALL|MF2_INVULNERABLE|MF2_MCROSS|MF2_TELESTOMP		// flags2
+ },
+
+{		// MT_FIREDEMON_SPLOTCH1
+-1,		// doomednum
+S_FIRED_CORPSE1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+3*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_DROPOFF|MF_CORPSE,		// flags
+MF2_NOTELEPORT|MF2_FLOORCLIP		// flags2
+ },
+
+{		// MT_FIREDEMON_SPLOTCH2
+-1,		// doomednum
+S_FIRED_CORPSE4,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+3*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_DROPOFF|MF_CORPSE,		// flags
+MF2_NOTELEPORT|MF2_FLOORCLIP		// flags2
+ },
+
+{		// MT_FIREDEMON_FX1
+-1,		// doomednum
+S_FIRED_RDROP1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_FIRED_RDEAD1_1,		// deathstate
+S_FIRED_RDEAD1_2,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+3*FRACUNIT,		// radius
+5*FRACUNIT,		// height
+16,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_DROPOFF|MF_MISSILE,		// flags
+MF2_NOTELEPORT		// flags2
+ },
+
+{		// MT_FIREDEMON_FX2
+-1,		// doomednum
+S_FIRED_RDROP2,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_FIRED_RDEAD2_1,		// deathstate
+S_FIRED_RDEAD2_2,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+3*FRACUNIT,		// radius
+5*FRACUNIT,		// height
+16,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_DROPOFF|MF_MISSILE,		// flags
+MF2_NOTELEPORT		// flags2
+ },
+
+{		// MT_FIREDEMON_FX3
+-1,		// doomednum
+S_FIRED_RDROP3,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_FIRED_RDEAD3_1,		// deathstate
+S_FIRED_RDEAD3_2,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+3*FRACUNIT,		// radius
+5*FRACUNIT,		// height
+16,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_DROPOFF|MF_MISSILE,		// flags
+MF2_NOTELEPORT		// flags2
+ },
+
+{		// MT_FIREDEMON_FX4
+-1,		// doomednum
+S_FIRED_RDROP4,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_FIRED_RDEAD4_1,		// deathstate
+S_FIRED_RDEAD4_2,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+3*FRACUNIT,		// radius
+5*FRACUNIT,		// height
+16,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_DROPOFF|MF_MISSILE,		// flags
+MF2_NOTELEPORT		// flags2
+ },
+
+{		// MT_FIREDEMON_FX5
+-1,		// doomednum
+S_FIRED_RDROP5,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_FIRED_RDEAD5_1,		// deathstate
+S_FIRED_RDEAD5_2,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+3*FRACUNIT,		// radius
+5*FRACUNIT,		// height
+16,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_DROPOFF|MF_MISSILE,		// flags
+MF2_NOTELEPORT		// flags2
+ },
+
+{		// MT_FIREDEMON_FX6
+-1,		// doomednum
+S_FIRED_FX6_1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_FIRED_FX6_2,		// deathstate
+S_NULL,		// xdeathstate
+SFX_FIRED_MISSILE_HIT,		// deathsound
+10*FRACUNIT,		// speed
+10*FRACUNIT,		// radius
+6*FRACUNIT,		// height
+15,		// mass
+1,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_NOGRAVITY|MF_DROPOFF|MF_MISSILE,		// flags
+MF2_NOTELEPORT|MF2_IMPACT|MF2_PCROSS|MF2_FLOORCLIP|MF2_FIREDAMAGE		// flags2
+ },
+
+{		// MT_ICEGUY
+8020,		// doomednum
+S_ICEGUY_LOOK,		// spawnstate
+120,		// spawnhealth
+S_ICEGUY_WALK1,		// seestate
+SFX_ICEGUY_SIGHT,		// seesound
+8,		// reactiontime
+SFX_ICEGUY_ATTACK,		// attacksound
+S_ICEGUY_PAIN1,		// painstate
+144,		// painchance
+SFX_NONE,		// painsound
+0,		// meleestate
+S_ICEGUY_ATK1,		// missilestate
+S_NULL,		// crashstate
+S_ICEGUY_DEATH,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+14,		// speed
+22*FRACUNIT,		// radius
+75*FRACUNIT,		// height
+150,		// mass
+0,		// damage
+SFX_ICEGUY_ACTIVE,		// activesound
+MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL|MF_NOBLOOD,		// flags
+MF2_PASSMOBJ|MF2_PUSHWALL|MF2_ICEDAMAGE|MF2_MCROSS|MF2_TELESTOMP		// flags2
+ },
+
+{		// MT_ICEGUY_FX
+-1,		// doomednum
+S_ICEGUY_FX1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_ICEGUY_FX_X1,		// deathstate
+S_NULL,		// xdeathstate
+SFX_ICEGUY_FX_EXPLODE,		// deathsound
+14*FRACUNIT,		// speed
+8*FRACUNIT,		// radius
+10*FRACUNIT,		// height
+100,		// mass
+1,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_NOGRAVITY,		// flags
+MF2_NOTELEPORT|MF2_ICEDAMAGE		// flags2
+ },
+
+{		// MT_ICEFX_PUFF
+-1,		// doomednum
+S_ICEFX_PUFF1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+FRACUNIT,		// radius
+FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_NOGRAVITY|MF_SHADOW|MF_DROPOFF,		// flags
+MF2_NOTELEPORT		// flags2
+ },
+
+{		// MT_ICEGUY_FX2
+-1,		// doomednum
+S_ICEGUY_FX2_1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+10*FRACUNIT,		// speed
+4*FRACUNIT,		// radius
+4*FRACUNIT,		// height
+100,		// mass
+1,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_DROPOFF|MF_MISSILE,		// flags
+MF2_NOTELEPORT|MF2_LOGRAV|MF2_ICEDAMAGE		// flags2
+ },
+
+{		// MT_ICEGUY_BIT
+-1,		// doomednum
+S_ICEGUY_BIT1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+FRACUNIT,		// radius
+FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_DROPOFF,		// flags
+MF2_NOTELEPORT|MF2_LOGRAV		// flags2
+ },
+
+{		// MT_ICEGUY_WISP1
+-1,		// doomednum
+S_ICEGUY_WISP1_1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_DROPOFF|MF_NOGRAVITY|MF_ALTSHADOW|MF_MISSILE,		// flags
+MF2_NOTELEPORT		// flags2
+ },
+
+{		// MT_ICEGUY_WISP2
+-1,		// doomednum
+S_ICEGUY_WISP2_1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_DROPOFF|MF_NOGRAVITY|MF_ALTSHADOW|MF_MISSILE,		// flags
+MF2_NOTELEPORT		// flags2
+ },
+
+{		// MT_FIGHTER_BOSS
+10100,		// doomednum
+S_FIGHTER,		// spawnstate
+800,		// spawnhealth
+S_FIGHTER_RUN1,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_FIGHTER_PAIN,		// painstate
+50,		// painchance
+SFX_PLAYER_FIGHTER_PAIN,		// painsound
+S_FIGHTER_ATK1,		// meleestate
+S_FIGHTER_ATK1,		// missilestate
+S_NULL,		// crashstate
+S_FIGHTER_DIE1,		// deathstate
+S_FIGHTER_XDIE1,		// xdeathstate
+SFX_PLAYER_FIGHTER_CRAZY_DEATH,		// deathsound
+25,		// speed
+16*FRACUNIT,		// radius
+64*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL,		// flags
+MF2_FLOORCLIP|MF2_PASSMOBJ|MF2_TELESTOMP|MF2_PUSHWALL|MF2_MCROSS		// flags2
+ },
+
+{		// MT_CLERIC_BOSS
+10101,		// doomednum
+S_CLERIC,		// spawnstate
+800,		// spawnhealth
+S_CLERIC_RUN1,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_CLERIC_PAIN,		// painstate
+50,		// painchance
+SFX_PLAYER_CLERIC_PAIN,		// painsound
+S_CLERIC_ATK1,		// meleestate
+S_CLERIC_ATK1,		// missilestate
+S_NULL,		// crashstate
+S_CLERIC_DIE1,		// deathstate
+S_CLERIC_XDIE1,		// xdeathstate
+SFX_PLAYER_CLERIC_CRAZY_DEATH,		// deathsound
+25,		// speed
+16*FRACUNIT,		// radius
+64*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL,		// flags
+MF2_FLOORCLIP|MF2_PASSMOBJ|MF2_TELESTOMP|MF2_PUSHWALL|MF2_MCROSS		// flags2
+ },
+
+{		// MT_MAGE_BOSS
+10102,		// doomednum
+S_MAGE,		// spawnstate
+800,		// spawnhealth
+S_MAGE_RUN1,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_MAGE_PAIN,		// painstate
+50,		// painchance
+SFX_PLAYER_MAGE_PAIN,		// painsound
+S_MAGE_ATK1,		// meleestate
+S_MAGE_ATK1,		// missilestate
+S_NULL,		// crashstate
+S_MAGE_DIE1,		// deathstate
+S_MAGE_XDIE1,		// xdeathstate
+SFX_PLAYER_MAGE_CRAZY_DEATH,		// deathsound
+25,		// speed
+16*FRACUNIT,		// radius
+64*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL,		// flags
+MF2_FLOORCLIP|MF2_PASSMOBJ|MF2_TELESTOMP|MF2_PUSHWALL|MF2_MCROSS		// flags2
+ },
+
+{		// MT_SORCBOSS
+10080,		// doomednum
+S_SORC_SPAWN1,		// spawnstate
+5000,		// spawnhealth
+S_SORC_WALK1,		// seestate
+SFX_SORCERER_SIGHT,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_SORC_PAIN1,		// painstate
+10,		// painchance
+SFX_SORCERER_PAIN,		// painsound
+S_NULL,		// meleestate
+S_SORC_ATK2_1,		// missilestate
+S_NULL,		// crashstate
+S_SORC_DIE1,		// deathstate
+S_NULL,		// xdeathstate
+SFX_SORCERER_DEATHSCREAM,		// deathsound
+16,		// speed
+40*FRACUNIT,		// radius
+110*FRACUNIT,		// height
+500,		// mass
+9,		// damage
+SFX_SORCERER_ACTIVE,		// activesound
+MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL|MF_NOBLOOD,		// flags
+MF2_FLOORCLIP|MF2_PASSMOBJ|MF2_PUSHWALL|MF2_BOSS|MF2_MCROSS		// flags2
+ },
+
+{		// MT_SORCBALL1
+-1,		// doomednum
+S_SORCBALL1_1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_SORCERER_BALLBOUNCE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_SORCBALL1_D1,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_SORCBALL1_D5,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+10*FRACUNIT,		// speed
+5*FRACUNIT,		// radius
+5*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_NOGRAVITY|MF_MISSILE,		// flags
+MF2_NOTELEPORT|MF2_FLOORBOUNCE		// flags2
+ },
+
+{		// MT_SORCBALL2
+-1,		// doomednum
+S_SORCBALL2_1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_SORCERER_BALLBOUNCE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_SORCBALL2_D1,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_SORCBALL2_D5,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+10*FRACUNIT,		// speed
+5*FRACUNIT,		// radius
+5*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_NOGRAVITY|MF_MISSILE,		// flags
+MF2_NOTELEPORT|MF2_FLOORBOUNCE		// flags2
+ },
+
+{		// MT_SORCBALL3
+-1,		// doomednum
+S_SORCBALL3_1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_SORCERER_BALLBOUNCE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_SORCBALL3_D1,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_SORCBALL3_D5,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+10*FRACUNIT,		// speed
+5*FRACUNIT,		// radius
+5*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_NOGRAVITY|MF_MISSILE,		// flags
+MF2_NOTELEPORT|MF2_FLOORBOUNCE		// flags2
+ },
+
+{		// MT_SORCFX1
+-1,		// doomednum
+S_SORCFX1_1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_SORCERER_BALLBOUNCE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_SORCFX1_D1,		// deathstate
+S_SORCFX1_D1,		// xdeathstate
+SFX_NONE,		// deathsound
+7*FRACUNIT,		// speed
+5*FRACUNIT,		// radius
+5*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_MISSILE,		// flags
+MF2_NOTELEPORT|MF2_FLOORBOUNCE		// flags2
+ },
+
+{		// MT_SORCFX2
+-1,		// doomednum
+S_SORCFX2_SPLIT1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_SORCFX2T1,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+15*FRACUNIT,		// speed
+5*FRACUNIT,		// radius
+5*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_NOGRAVITY,		// flags
+MF2_NOTELEPORT		// flags2
+ },
+
+{		// MT_SORCFX2_T1
+-1,		// doomednum
+S_SORCFX2T1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_NOGRAVITY|MF_ALTSHADOW,		// flags
+MF2_NOTELEPORT		// flags2
+ },
+
+{		// MT_SORCFX3
+-1,		// doomednum
+S_SORCFX3_1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_SORCERER_BISHOPSPAWN,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_BISHMORPH1,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+15*FRACUNIT,		// speed
+22*FRACUNIT,		// radius
+65*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_MISSILE,		// flags
+MF2_NOTELEPORT		// flags2
+ },
+
+{		// MT_SORCFX3_EXPLOSION
+-1,		// doomednum
+S_SORCFX3_EXP1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_NOGRAVITY|MF_ALTSHADOW,		// flags
+MF2_NOTELEPORT		// flags2
+ },
+
+{		// MT_SORCFX4
+-1,		// doomednum
+S_SORCFX4_1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_SORCFX4_D1,		// deathstate
+S_NULL,		// xdeathstate
+SFX_SORCERER_BALLEXPLODE,		// deathsound
+12*FRACUNIT,		// speed
+10*FRACUNIT,		// radius
+10*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_MISSILE|MF_NOGRAVITY,		// flags
+MF2_NOTELEPORT		// flags2
+ },
+
+{		// MT_SORCSPARK1
+-1,		// doomednum
+S_SORCSPARK1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+5*FRACUNIT,		// radius
+5*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_DROPOFF,		// flags
+MF2_NOTELEPORT|MF2_LOGRAV		// flags2
+ },
+
+{		// MT_BLASTEFFECT
+-1,		// doomednum
+S_BLASTEFFECT1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_NOGRAVITY|MF_NOCLIP|MF_ALTSHADOW,		// flags
+MF2_NOTELEPORT		// flags2
+ },
+
+{		// MT_WATER_DRIP
+-1,		// doomednum
+S_WATERDRIP1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_DRIP,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+1,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_MISSILE,		// flags
+MF2_LOGRAV|MF2_NOTELEPORT		// flags2
+ },
+
+{		// MT_KORAX
+10200,		// doomednum
+S_KORAX_LOOK1,		// spawnstate
+5000,		// spawnhealth
+S_KORAX_CHASE2,		// seestate
+SFX_KORAX_SIGHT,		// seesound
+8,		// reactiontime
+SFX_KORAX_ATTACK,		// attacksound
+S_KORAX_PAIN1,		// painstate
+20,		// painchance
+SFX_KORAX_PAIN,		// painsound
+S_NULL,		// meleestate
+S_KORAX_ATTACK1,		// missilestate
+S_NULL,		// crashstate
+S_KORAX_DEATH1,		// deathstate
+S_NULL,		// xdeathstate
+SFX_KORAX_DEATH,		// deathsound
+10,		// speed
+65*FRACUNIT,		// radius
+115*FRACUNIT,		// height
+2000,		// mass
+15,		// damage
+SFX_KORAX_ACTIVE,		// activesound
+MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL,		// flags
+MF2_FLOORCLIP|MF2_PUSHWALL|MF2_MCROSS|MF2_TELESTOMP|MF2_BOSS		// flags2
+ },
+
+{		// MT_KORAX_SPIRIT1
+-1,		// doomednum
+S_KSPIRIT_ROAM1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+8*FRACUNIT,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_DROPOFF|MF_NOGRAVITY|MF_ALTSHADOW|MF_MISSILE|MF_NOCLIP,		// flags
+MF2_NOTELEPORT		// flags2
+ },
+
+{		// MT_KORAX_SPIRIT2
+-1,		// doomednum
+S_KSPIRIT_ROAM1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+8*FRACUNIT,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_DROPOFF|MF_NOGRAVITY|MF_ALTSHADOW|MF_MISSILE|MF_NOCLIP,		// flags
+MF2_NOTELEPORT		// flags2
+ },
+
+{		// MT_KORAX_SPIRIT3
+-1,		// doomednum
+S_KSPIRIT_ROAM1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+8*FRACUNIT,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_DROPOFF|MF_NOGRAVITY|MF_ALTSHADOW|MF_MISSILE|MF_NOCLIP,		// flags
+MF2_NOTELEPORT		// flags2
+ },
+
+{		// MT_KORAX_SPIRIT4
+-1,		// doomednum
+S_KSPIRIT_ROAM1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+8*FRACUNIT,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_DROPOFF|MF_NOGRAVITY|MF_ALTSHADOW|MF_MISSILE|MF_NOCLIP,		// flags
+MF2_NOTELEPORT		// flags2
+ },
+
+{		// MT_KORAX_SPIRIT5
+-1,		// doomednum
+S_KSPIRIT_ROAM1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+8*FRACUNIT,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_DROPOFF|MF_NOGRAVITY|MF_ALTSHADOW|MF_MISSILE|MF_NOCLIP,		// flags
+MF2_NOTELEPORT		// flags2
+ },
+
+{		// MT_KORAX_SPIRIT6
+-1,		// doomednum
+S_KSPIRIT_ROAM1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+8*FRACUNIT,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_DROPOFF|MF_NOGRAVITY|MF_ALTSHADOW|MF_MISSILE|MF_NOCLIP,		// flags
+MF2_NOTELEPORT		// flags2
+ },
+
+{		// MT_DEMON_MASH
+-1,		// doomednum
+S_DEMN_LOOK1,		// spawnstate
+250,		// spawnhealth
+S_DEMN_CHASE1,		// seestate
+SFX_DEMON_SIGHT,		// seesound
+8,		// reactiontime
+SFX_DEMON_ATTACK,		// attacksound
+S_DEMN_PAIN1,		// painstate
+50,		// painchance
+SFX_DEMON_PAIN,		// painsound
+S_DEMN_ATK1_1,		// meleestate
+S_DEMN_ATK2_1,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_DEMON_DEATH,		// deathsound
+13,		// speed
+32*FRACUNIT,		// radius
+64*FRACUNIT,		// height
+220,		// mass
+0,		// damage
+SFX_DEMON_ACTIVE,		// activesound
+MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL|MF_ALTSHADOW|MF_NOBLOOD,		// flags
+MF2_FLOORCLIP|MF2_PASSMOBJ|MF2_MCROSS|MF2_PUSHWALL|MF2_BLASTED		// flags2
+ },
+
+{		// MT_DEMON2_MASH
+-1,		// doomednum
+S_DEMN2_LOOK1,		// spawnstate
+250,		// spawnhealth
+S_DEMN2_CHASE1,		// seestate
+SFX_DEMON_SIGHT,		// seesound
+8,		// reactiontime
+SFX_DEMON_ATTACK,		// attacksound
+S_DEMN2_PAIN1,		// painstate
+50,		// painchance
+SFX_DEMON_PAIN,		// painsound
+S_DEMN2_ATK1_1,		// meleestate
+S_DEMN2_ATK2_1,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_DEMON_DEATH,		// deathsound
+13,		// speed
+32*FRACUNIT,		// radius
+64*FRACUNIT,		// height
+220,		// mass
+0,		// damage
+SFX_DEMON_ACTIVE,		// activesound
+MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL|MF_ALTSHADOW|MF_NOBLOOD,		// flags
+MF2_FLOORCLIP|MF2_PASSMOBJ|MF2_MCROSS|MF2_PUSHWALL|MF2_BLASTED		// flags2
+ },
+
+{		// MT_ETTIN_MASH
+-1,		// doomednum
+S_ETTIN_LOOK1,		// spawnstate
+175,		// spawnhealth
+S_ETTIN_CHASE1,		// seestate
+SFX_ETTIN_SIGHT,		// seesound
+8,		// reactiontime
+SFX_ETTIN_ATTACK,		// attacksound
+S_ETTIN_PAIN1,		// painstate
+60,		// painchance
+SFX_ETTIN_PAIN,		// painsound
+S_ETTIN_ATK1_1,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_ETTIN_DEATH,		// deathsound
+13,		// speed
+25*FRACUNIT,		// radius
+68*FRACUNIT,		// height
+175,		// mass
+3,		// damage
+SFX_ETTIN_ACTIVE,		// activesound
+MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL|MF_ALTSHADOW|MF_NOBLOOD,		// flags
+MF2_FLOORCLIP|MF2_PASSMOBJ|MF2_MCROSS|MF2_PUSHWALL|MF2_BLASTED		// flags2
+ },
+
+{		// MT_CENTAUR_MASH
+-1,		// doomednum
+S_CENTAUR_LOOK1,		// spawnstate
+200,		// spawnhealth
+S_CENTAUR_WALK1,		// seestate
+SFX_CENTAUR_SIGHT,		// seesound
+8,		// reactiontime
+SFX_CENTAUR_ATTACK,		// attacksound
+S_CENTAUR_PAIN1,		// painstate
+135,		// painchance
+SFX_CENTAUR_PAIN,		// painsound
+S_CENTAUR_ATK1,		// meleestate
+0,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_CENTAUR_DEATH,		// deathsound
+13,		// speed
+20*FRACUNIT,		// radius
+64*FRACUNIT,		// height
+120,		// mass
+0,		// damage
+SFX_CENTAUR_ACTIVE,		// activesound
+MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL|MF_ALTSHADOW|MF_NOBLOOD,		// flags
+MF2_FLOORCLIP|MF2_PASSMOBJ|MF2_MCROSS|MF2_PUSHWALL|MF2_BLASTED		// flags2
+ },
+
+{		// MT_KORAX_BOLT
+-1,		// doomednum
+S_KBOLT1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+15*FRACUNIT,		// radius
+35*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_NOGRAVITY|MF_MISSILE|MF_DROPOFF,		// flags
+MF2_NOTELEPORT		// flags2
+ },
+
+{		// MT_BAT_SPAWNER
+10225,		// doomednum
+S_SPAWNBATS1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_NOSECTOR|MF_NOGRAVITY,		// flags
+MF2_DONTDRAW		// flags2
+ },
+
+{		// MT_BAT
+-1,		// doomednum
+S_BAT1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_BAT_DEATH,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+5*FRACUNIT,		// speed
+3*FRACUNIT,		// radius
+3*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_NOGRAVITY|MF_MISSILE,		// flags
+MF2_PASSMOBJ|MF2_NOTELEPORT		// flags2
+ },
+
+#ifdef ASSASSIN
+{		// MT_AW_CROSSBOW
+10,		// doomednum
+S_CSTAFF,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+0,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// misslestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SPECIAL,		// flags
+0		// flags2
+ },
+
+  /* jim We need a missile type for it as well! */
+{		// MT_ACROSS_MISSILE
+-1,		// doomednum
+S_ACROSS_MISSILE1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+8,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_ACROSS_MISSILE_X1,		// deathstate
+S_NULL,		// xdeathstate
+SFX_CLERIC_CSTAFF_EXPLODE,		// deathsound
+110*FRACUNIT,		// speed  /* jim speed up the crossbow missles */
+12*FRACUNIT,		// radius
+10*FRACUNIT,		// height
+100,		// mass
+5,		// damage
+SFX_NONE,		// activesound
+MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_NOGRAVITY,		// flags
+MF2_NOTELEPORT|MF2_IMPACT|MF2_PCROSS		// flags2
+ },
+
+{		// MT_AW_GRENADES
+8040,		// doomednum
+S_MW_LIGHTNING1,		// spawnstate
+1000,		// spawnhealth
+S_NULL,		// seestate
+SFX_NONE,		// seesound
+0,		// reactiontime
+SFX_NONE,		// attacksound
+S_NULL,		// painstate
+0,		// painchance
+SFX_NONE,		// painsound
+S_NULL,		// meleestate
+S_NULL,		// missilestate
+S_NULL,		// crashstate
+S_NULL,		// deathstate
+S_NULL,		// xdeathstate
+SFX_NONE,		// deathsound
+0,		// speed
+20*FRACUNIT,		// radius
+16*FRACUNIT,		// height
+100,		// mass
+0,		// damage
+SFX_NONE,		// activesound
+MF_SPECIAL|MF_NOGRAVITY,		// flags
+0		// flags2
+}
+#endif	/* ASSASSIN */
+};
+
--- /dev/null
+++ b/info.h
@@ -1,0 +1,3813 @@
+
+//**************************************************************************
+//**
+//** info.h : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 373 $
+//** $Date: 2009-05-19 21:14:28 +0300 (Tue, 19 May 2009) $
+//**
+//**************************************************************************
+
+#ifndef __INFO_H
+#define __INFO_H
+
+// generated by stateco
+
+typedef enum {
+SPR_MAN1,
+SPR_ACLO,
+SPR_TLGL,
+SPR_FBL1,
+SPR_XPL1,
+SPR_ARRW,
+SPR_DART,
+SPR_RIPP,
+SPR_CFCF,
+SPR_BLAD,
+SPR_SHRD,
+SPR_FFSM,
+SPR_FFLG,
+SPR_PTN1,
+SPR_PTN2,
+SPR_SOAR,
+SPR_INVU,
+SPR_SUMN,
+SPR_TSPK,
+SPR_TELO,
+SPR_TRNG,
+SPR_ROCK,
+SPR_FOGS,
+SPR_FOGM,
+SPR_FOGL,
+SPR_SGSA,
+SPR_SGSB,
+SPR_PORK,
+SPR_EGGM,
+SPR_FHFX,
+SPR_SPHL,
+SPR_STWN,
+SPR_GMPD,
+SPR_ASKU,
+SPR_ABGM,
+SPR_AGMR,
+SPR_AGMG,
+SPR_AGG2,
+SPR_AGMB,
+SPR_AGB2,
+SPR_ABK1,
+SPR_ABK2,
+SPR_ASK2,
+SPR_AFWP,
+SPR_ACWP,
+SPR_AMWP,
+SPR_AGER,
+SPR_AGR2,
+SPR_AGR3,
+SPR_AGR4,
+SPR_TRCH,
+SPR_PSBG,
+SPR_ATLP,
+SPR_THRW,
+SPR_SPED,
+SPR_BMAN,
+SPR_BRAC,
+SPR_BLST,
+SPR_HRAD,
+SPR_SPSH,
+SPR_LVAS,
+SPR_SLDG,
+SPR_STTW,
+SPR_RCK1,
+SPR_RCK2,
+SPR_RCK3,
+SPR_RCK4,
+SPR_CDLR,
+SPR_TRE1,
+SPR_TRDT,
+SPR_TRE2,
+SPR_TRE3,
+SPR_STM1,
+SPR_STM2,
+SPR_STM3,
+SPR_STM4,
+SPR_MSH1,
+SPR_MSH2,
+SPR_MSH3,
+SPR_MSH4,
+SPR_MSH5,
+SPR_MSH6,
+SPR_MSH7,
+SPR_MSH8,
+SPR_SGMP,
+SPR_SGM1,
+SPR_SGM2,
+SPR_SGM3,
+SPR_SLC1,
+SPR_SLC2,
+SPR_SLC3,
+SPR_MSS1,
+SPR_MSS2,
+SPR_SWMV,
+SPR_CPS1,
+SPR_CPS2,
+SPR_TMS1,
+SPR_TMS2,
+SPR_TMS3,
+SPR_TMS4,
+SPR_TMS5,
+SPR_TMS6,
+SPR_TMS7,
+SPR_CPS3,
+SPR_STT2,
+SPR_STT3,
+SPR_STT4,
+SPR_STT5,
+SPR_GAR1,
+SPR_GAR2,
+SPR_GAR3,
+SPR_GAR4,
+SPR_GAR5,
+SPR_GAR6,
+SPR_GAR7,
+SPR_GAR8,
+SPR_GAR9,
+SPR_BNR1,
+SPR_TRE4,
+SPR_TRE5,
+SPR_TRE6,
+SPR_TRE7,
+SPR_LOGG,
+SPR_ICT1,
+SPR_ICT2,
+SPR_ICT3,
+SPR_ICT4,
+SPR_ICM1,
+SPR_ICM2,
+SPR_ICM3,
+SPR_ICM4,
+SPR_RKBL,
+SPR_RKBS,
+SPR_RKBK,
+SPR_RBL1,
+SPR_RBL2,
+SPR_RBL3,
+SPR_VASE,
+SPR_POT1,
+SPR_POT2,
+SPR_POT3,
+SPR_PBIT,
+SPR_CPS4,
+SPR_CPS5,
+SPR_CPS6,
+SPR_CPB1,
+SPR_CPB2,
+SPR_CPB3,
+SPR_CPB4,
+SPR_BDRP,
+SPR_BDSH,
+SPR_BDPL,
+SPR_CNDL,
+SPR_LEF1,
+SPR_LEF3,
+SPR_LEF2,
+SPR_TWTR,
+SPR_WLTR,
+SPR_BARL,
+SPR_SHB1,
+SPR_SHB2,
+SPR_BCKT,
+SPR_SHRM,
+SPR_FBUL,
+SPR_FSKL,
+SPR_BRTR,
+SPR_SUIT,
+SPR_BBLL,
+SPR_CAND,
+SPR_IRON,
+SPR_XMAS,
+SPR_CDRN,
+SPR_CHNS,
+SPR_TST1,
+SPR_TST2,
+SPR_TST3,
+SPR_TST4,
+SPR_TST5,
+SPR_TST6,
+SPR_TST7,
+SPR_TST8,
+SPR_TST9,
+SPR_TST0,
+SPR_TELE,
+SPR_TSMK,
+SPR_FPCH,
+SPR_WFAX,
+SPR_FAXE,
+SPR_WFHM,
+SPR_FHMR,
+SPR_FSRD,
+SPR_FSFX,
+SPR_CMCE,
+SPR_WCSS,
+SPR_CSSF,
+SPR_WCFM,
+SPR_CFLM,
+SPR_CFFX,
+SPR_CHLY,
+SPR_SPIR,
+SPR_MWND,
+SPR_WMLG,
+SPR_MLNG,
+SPR_MLFX,
+SPR_MLF2,
+SPR_MSTF,
+SPR_MSP1,
+SPR_MSP2,
+SPR_WFR1,
+SPR_WFR2,
+SPR_WFR3,
+SPR_WCH1,
+SPR_WCH2,
+SPR_WCH3,
+SPR_WMS1,
+SPR_WMS2,
+SPR_WMS3,
+SPR_WPIG,
+SPR_WMCS,
+SPR_CONE,
+SPR_SHEX,
+SPR_BLOD,
+SPR_GIBS,
+SPR_PLAY,
+SPR_FDTH,
+SPR_BSKL,
+SPR_ICEC,
+SPR_CLER,
+SPR_MAGE,
+SPR_PIGY,
+SPR_CENT,
+SPR_CTXD,
+SPR_CTFX,
+SPR_CTDP,
+SPR_DEMN,
+SPR_DEMA,
+SPR_DEMB,
+SPR_DEMC,
+SPR_DEMD,
+SPR_DEME,
+SPR_DMFX,
+SPR_DEM2,
+SPR_DMBA,
+SPR_DMBB,
+SPR_DMBC,
+SPR_DMBD,
+SPR_DMBE,
+SPR_D2FX,
+SPR_WRTH,
+SPR_WRT2,
+SPR_WRBL,
+SPR_MNTR,
+SPR_FX12,
+SPR_FX13,
+SPR_MNSM,
+SPR_SSPT,
+SPR_SSDV,
+SPR_SSXD,
+SPR_SSFX,
+SPR_BISH,
+SPR_BPFX,
+SPR_DRAG,
+SPR_DRFX,
+SPR_ARM1,
+SPR_ARM2,
+SPR_ARM3,
+SPR_ARM4,
+SPR_MAN2,
+SPR_MAN3,
+SPR_KEY1,
+SPR_KEY2,
+SPR_KEY3,
+SPR_KEY4,
+SPR_KEY5,
+SPR_KEY6,
+SPR_KEY7,
+SPR_KEY8,
+SPR_KEY9,
+SPR_KEYA,
+SPR_KEYB,
+SPR_ETTN,
+SPR_ETTB,
+SPR_FDMN,
+SPR_FDMB,
+SPR_ICEY,
+SPR_ICPR,
+SPR_ICWS,
+SPR_SORC,
+SPR_SBMP,
+SPR_SBS4,
+SPR_SBMB,
+SPR_SBS3,
+SPR_SBMG,
+SPR_SBS1,
+SPR_SBS2,
+SPR_SBFX,
+SPR_RADE,
+SPR_WATR,
+SPR_KORX,
+SPR_ABAT,
+#ifdef ASSASSIN
+SPR_AKTR,
+SPR_ACSB,
+SPR_AGRN,
+SPR_ASTF,
+SPR_ASP1,
+SPR_ASP2,
+SPR_ASSN,
+#endif
+SPR_NULL, /* for the terminator in sprnames[] */
+NUMSPRITES
+} spritenum_t;
+
+typedef enum {
+S_NULL,
+S_FREETARGMOBJ,
+S_MAPSPOT,
+S_FIREBALL1_1,
+S_FIREBALL1_2,
+S_FIREBALL1_X1,
+S_FIREBALL1_X2,
+S_FIREBALL1_X3,
+S_FIREBALL1_X4,
+S_FIREBALL1_X5,
+S_FIREBALL1_X6,
+S_ARROW_1,
+S_ARROW_X1,
+S_DART_1,
+S_DART_X1,
+S_POISONDART_1,
+S_POISONDART_X1,
+S_RIPPERBALL_1,
+S_RIPPERBALL_2,
+S_RIPPERBALL_3,
+S_RIPPERBALL_X1,
+S_RIPPERBALL_X2,
+S_RIPPERBALL_X3,
+S_RIPPERBALL_X4,
+S_RIPPERBALL_X5,
+S_RIPPERBALL_X6,
+S_RIPPERBALL_X7,
+S_RIPPERBALL_X8,
+S_RIPPERBALL_X9,
+S_RIPPERBALL_X10,
+S_PRJ_BLADE1,
+S_PRJ_BLADE_X1,
+S_ICESHARD1,
+S_ICESHARD2,
+S_ICESHARD3,
+S_FLAME_TSMALL1,
+S_FLAME_TSMALL2,
+S_FLAME_TSMALL3,
+S_FLAME_TSMALL4,
+S_FLAME_TSMALL5,
+S_FLAME_TSMALL6,
+S_FLAME_TLARGE1,
+S_FLAME_TLARGE2,
+S_FLAME_TLARGE3,
+S_FLAME_TLARGE4,
+S_FLAME_TLARGE5,
+S_FLAME_TLARGE6,
+S_FLAME_TLARGE7,
+S_FLAME_TLARGE8,
+S_FLAME_TLARGE9,
+S_FLAME_TLARGE10,
+S_FLAME_TLARGE11,
+S_FLAME_TLARGE12,
+S_FLAME_TLARGE13,
+S_FLAME_TLARGE14,
+S_FLAME_TLARGE15,
+S_FLAME_TLARGE16,
+S_FLAME_SDORM1,
+S_FLAME_SDORM2,
+S_FLAME_SDORM3,
+S_FLAME_SMALL1,
+S_FLAME_SMALL2,
+S_FLAME_SMALL3,
+S_FLAME_SMALL4,
+S_FLAME_SMALL5,
+S_FLAME_SMALL6,
+S_FLAME_SMALL7,
+S_FLAME_LDORM1,
+S_FLAME_LDORM2,
+S_FLAME_LDORM3,
+S_FLAME_LDORM4,
+S_FLAME_LDORM5,
+S_FLAME_LARGE1,
+S_FLAME_LARGE2,
+S_FLAME_LARGE3,
+S_FLAME_LARGE4,
+S_FLAME_LARGE5,
+S_FLAME_LARGE6,
+S_FLAME_LARGE7,
+S_FLAME_LARGE8,
+S_FLAME_LARGE9,
+S_FLAME_LARGE10,
+S_FLAME_LARGE11,
+S_FLAME_LARGE12,
+S_FLAME_LARGE13,
+S_FLAME_LARGE14,
+S_FLAME_LARGE15,
+S_FLAME_LARGE16,
+S_FLAME_LARGE17,
+S_FLAME_LARGE18,
+S_ITEM_PTN1_1,
+S_ITEM_PTN1_2,
+S_ITEM_PTN1_3,
+S_HIDESPECIAL1,
+S_HIDESPECIAL2,
+S_HIDESPECIAL3,
+S_HIDESPECIAL4,
+S_HIDESPECIAL5,
+S_HIDESPECIAL6,
+S_HIDESPECIAL7,
+S_HIDESPECIAL8,
+S_HIDESPECIAL9,
+S_HIDESPECIAL10,
+S_HIDESPECIAL11,
+S_DORMANTARTI1_1,
+S_DORMANTARTI1_2,
+S_DORMANTARTI1_3,
+S_DORMANTARTI1_4,
+S_DORMANTARTI1_5,
+S_DORMANTARTI1_6,
+S_DORMANTARTI1_7,
+S_DORMANTARTI1_8,
+S_DORMANTARTI1_9,
+S_DORMANTARTI1_10,
+S_DORMANTARTI1_11,
+S_DORMANTARTI1_12,
+S_DORMANTARTI1_13,
+S_DORMANTARTI1_14,
+S_DORMANTARTI1_15,
+S_DORMANTARTI1_16,
+S_DORMANTARTI1_17,
+S_DORMANTARTI1_18,
+S_DORMANTARTI1_19,
+S_DORMANTARTI1_20,
+S_DORMANTARTI1_21,
+S_DORMANTARTI2_1,
+S_DORMANTARTI2_2,
+S_DORMANTARTI2_3,
+S_DORMANTARTI2_4,
+S_DORMANTARTI2_5,
+S_DORMANTARTI2_6,
+S_DORMANTARTI2_7,
+S_DORMANTARTI2_8,
+S_DORMANTARTI2_9,
+S_DORMANTARTI2_10,
+S_DORMANTARTI2_11,
+S_DORMANTARTI2_12,
+S_DORMANTARTI2_13,
+S_DORMANTARTI2_14,
+S_DORMANTARTI2_15,
+S_DORMANTARTI2_16,
+S_DORMANTARTI2_17,
+S_DORMANTARTI2_18,
+S_DORMANTARTI2_19,
+S_DORMANTARTI2_20,
+S_DORMANTARTI2_21,
+S_DORMANTARTI3_1,
+S_DORMANTARTI3_2,
+S_DORMANTARTI3_3,
+S_DORMANTARTI3_4,
+S_DORMANTARTI3_5,
+S_DORMANTARTI3_6,
+S_DORMANTARTI3_7,
+S_DORMANTARTI3_8,
+S_DORMANTARTI3_9,
+S_DORMANTARTI3_10,
+S_DORMANTARTI3_11,
+S_DORMANTARTI3_12,
+S_DORMANTARTI3_13,
+S_DORMANTARTI3_14,
+S_DORMANTARTI3_15,
+S_DORMANTARTI3_16,
+S_DORMANTARTI3_17,
+S_DORMANTARTI3_18,
+S_DORMANTARTI3_19,
+S_DORMANTARTI3_20,
+S_DORMANTARTI3_21,
+S_DEADARTI1,
+S_DEADARTI2,
+S_DEADARTI3,
+S_DEADARTI4,
+S_DEADARTI5,
+S_DEADARTI6,
+S_DEADARTI7,
+S_DEADARTI8,
+S_DEADARTI9,
+S_DEADARTI10,
+S_ARTI_PTN2_1,
+S_ARTI_PTN2_2,
+S_ARTI_PTN2_3,
+S_ARTI_SOAR1,
+S_ARTI_SOAR2,
+S_ARTI_SOAR3,
+S_ARTI_SOAR4,
+S_ARTI_INVU1,
+S_ARTI_INVU2,
+S_ARTI_INVU3,
+S_ARTI_INVU4,
+S_ARTI_SUMMON,
+S_SUMMON_FX1_1,
+S_SUMMON_FX2_1,
+S_SUMMON_FX2_2,
+S_SUMMON_FX2_3,
+S_THRUSTINIT2_1,
+S_THRUSTINIT2_2,
+S_BTHRUSTINIT2_1,
+S_BTHRUSTINIT2_2,
+S_THRUSTINIT1_1,
+S_THRUSTINIT1_2,
+S_BTHRUSTINIT1_1,
+S_BTHRUSTINIT1_2,
+S_THRUSTRAISE1,
+S_THRUSTRAISE2,
+S_THRUSTRAISE3,
+S_THRUSTRAISE4,
+S_BTHRUSTRAISE1,
+S_BTHRUSTRAISE2,
+S_BTHRUSTRAISE3,
+S_BTHRUSTRAISE4,
+S_THRUSTIMPALE,
+S_BTHRUSTIMPALE,
+S_THRUSTRAISE,
+S_BTHRUSTRAISE,
+S_THRUSTBLOCK,
+S_BTHRUSTBLOCK,
+S_THRUSTLOWER,
+S_BTHRUSTLOWER,
+S_THRUSTSTAY,
+S_BTHRUSTSTAY,
+S_ARTI_TELOTHER1,
+S_ARTI_TELOTHER2,
+S_ARTI_TELOTHER3,
+S_ARTI_TELOTHER4,
+S_TELO_FX1,
+S_TELO_FX2,
+S_TELO_FX3,
+S_TELO_FX4,
+S_TELO_FX5,
+S_TELO_FX6,
+S_TELO_FX7,
+S_TELO_FX8,
+S_TELO_FX9,
+S_TELO_FX2_1,
+S_TELO_FX2_2,
+S_TELO_FX2_3,
+S_TELO_FX2_4,
+S_TELO_FX2_5,
+S_TELO_FX2_6,
+S_TELO_FX3_1,
+S_TELO_FX3_2,
+S_TELO_FX3_3,
+S_TELO_FX3_4,
+S_TELO_FX3_5,
+S_TELO_FX3_6,
+S_TELO_FX4_1,
+S_TELO_FX4_2,
+S_TELO_FX4_3,
+S_TELO_FX4_4,
+S_TELO_FX4_5,
+S_TELO_FX4_6,
+S_TELO_FX5_1,
+S_TELO_FX5_2,
+S_TELO_FX5_3,
+S_TELO_FX5_4,
+S_TELO_FX5_5,
+S_TELO_FX5_6,
+S_DIRT1_1,
+S_DIRT1_D,
+S_DIRT2_1,
+S_DIRT2_D,
+S_DIRT3_1,
+S_DIRT3_D,
+S_DIRT4_1,
+S_DIRT4_D,
+S_DIRT5_1,
+S_DIRT5_D,
+S_DIRT6_1,
+S_DIRT6_D,
+S_DIRTCLUMP1,
+S_ROCK1_1,
+S_ROCK1_D,
+S_ROCK2_1,
+S_ROCK2_D,
+S_ROCK3_1,
+S_ROCK3_D,
+S_SPAWNFOG1,
+S_FOGPATCHS1,
+S_FOGPATCHS2,
+S_FOGPATCHS3,
+S_FOGPATCHS4,
+S_FOGPATCHS5,
+S_FOGPATCHS0,
+S_FOGPATCHM1,
+S_FOGPATCHM2,
+S_FOGPATCHM3,
+S_FOGPATCHM4,
+S_FOGPATCHM5,
+S_FOGPATCHM0,
+S_FOGPATCHMA,
+S_FOGPATCHMB,
+S_FOGPATCHMC,
+S_FOGPATCHMD,
+S_FOGPATCHL1,
+S_FOGPATCHL2,
+S_FOGPATCHL3,
+S_FOGPATCHL4,
+S_FOGPATCHL5,
+S_FOGPATCHL0,
+S_FOGPATCHLA,
+S_FOGPATCHLB,
+S_FOGPATCHLC,
+S_FOGPATCHLD,
+S_QUAKE_ACTIVE1,
+S_QUAKE_ACTIVE2,
+S_QUAKE_ACTIVE3,
+S_QUAKE_ACTIVE4,
+S_QUAKE_ACTIVE5,
+S_QUAKE_ACTIVE6,
+S_QUAKE_ACTIVE7,
+S_QUAKE_ACTIVE8,
+S_QUAKE_ACTIVE9,
+S_QUAKE_ACTIVE0,
+S_QUAKE_ACTIVEA,
+S_QUAKE_ACTIVEB,
+S_QUAKE_ACTIVEC,
+S_QUAKE_ACTIVED,
+S_QUAKE_ACTIVEE,
+S_QUAKE_ACTIVEF,
+S_QUAKE_ACTIVEG,
+S_QUAKE_ACTIVEH,
+S_QUAKE_ACTIVEI,
+S_QUAKE_ACTIVEJ,
+S_QUAKE_ACTIVEK,
+S_QUAKE_ACTIVEL,
+S_QUAKE_ACTIVEM,
+S_QUAKE_ACTIVEN,
+S_QUAKE_ACTIVEO,
+S_QUAKE_ACTIVEP,
+S_QUAKE_ACTIVEQ,
+S_QUAKE_ACTIVER,
+S_QUAKE_ACTIVES,
+S_QUAKE_ACTIVET,
+S_QUAKE_ACTIVEU,
+S_QUAKE_ACTIVEV,
+S_QUAKE_ACTIVEW,
+S_QUAKE_ACTIVEX,
+S_QUAKE_ACTIVEY,
+S_QUAKE_ACTIVEZ,
+S_QUAKE_ACT1,
+S_QUAKE_ACT2,
+S_QUAKE_ACT3,
+S_QUAKE_ACT4,
+S_QUAKE_ACT5,
+S_QUAKE_ACT6,
+S_QUAKE_ACT7,
+S_QUAKE_ACT8,
+S_QUAKE_ACT9,
+S_QUAKE_ACT0,
+S_SGSHARD1_1,
+S_SGSHARD1_2,
+S_SGSHARD1_3,
+S_SGSHARD1_4,
+S_SGSHARD1_5,
+S_SGSHARD1_D,
+S_SGSHARD2_1,
+S_SGSHARD2_2,
+S_SGSHARD2_3,
+S_SGSHARD2_4,
+S_SGSHARD2_5,
+S_SGSHARD2_D,
+S_SGSHARD3_1,
+S_SGSHARD3_2,
+S_SGSHARD3_3,
+S_SGSHARD3_4,
+S_SGSHARD3_5,
+S_SGSHARD3_D,
+S_SGSHARD4_1,
+S_SGSHARD4_2,
+S_SGSHARD4_3,
+S_SGSHARD4_4,
+S_SGSHARD4_5,
+S_SGSHARD4_D,
+S_SGSHARD5_1,
+S_SGSHARD5_2,
+S_SGSHARD5_3,
+S_SGSHARD5_4,
+S_SGSHARD5_5,
+S_SGSHARD5_D,
+S_SGSHARD6_1,
+S_SGSHARD6_D,
+S_SGSHARD7_1,
+S_SGSHARD7_D,
+S_SGSHARD8_1,
+S_SGSHARD8_D,
+S_SGSHARD9_1,
+S_SGSHARD9_D,
+S_SGSHARD0_1,
+S_SGSHARD0_D,
+S_ARTI_EGGC1,
+S_ARTI_EGGC2,
+S_ARTI_EGGC3,
+S_ARTI_EGGC4,
+S_ARTI_EGGC5,
+S_ARTI_EGGC6,
+S_ARTI_EGGC7,
+S_ARTI_EGGC8,
+S_EGGFX1,
+S_EGGFX2,
+S_EGGFX3,
+S_EGGFX4,
+S_EGGFX5,
+S_EGGFXI1_1,
+S_EGGFXI1_2,
+S_EGGFXI1_3,
+S_EGGFXI1_4,
+S_ARTI_SPHL1,
+S_ZWINGEDSTATUENOSKULL,
+S_ZWINGEDSTATUENOSKULL2,
+S_ZGEMPEDESTAL1,
+S_ZGEMPEDESTAL2,
+S_ARTIPUZZSKULL,
+S_ARTIPUZZGEMBIG,
+S_ARTIPUZZGEMRED,
+S_ARTIPUZZGEMGREEN1,
+S_ARTIPUZZGEMGREEN2,
+S_ARTIPUZZGEMBLUE1,
+S_ARTIPUZZGEMBLUE2,
+S_ARTIPUZZBOOK1,
+S_ARTIPUZZBOOK2,
+S_ARTIPUZZSKULL2,
+S_ARTIPUZZFWEAPON,
+S_ARTIPUZZCWEAPON,
+S_ARTIPUZZMWEAPON,
+S_ARTIPUZZGEAR_1,
+S_ARTIPUZZGEAR_2,
+S_ARTIPUZZGEAR_3,
+S_ARTIPUZZGEAR_4,
+S_ARTIPUZZGEAR_5,
+S_ARTIPUZZGEAR_6,
+S_ARTIPUZZGEAR_7,
+S_ARTIPUZZGEAR_8,
+S_ARTIPUZZGEAR2_1,
+S_ARTIPUZZGEAR2_2,
+S_ARTIPUZZGEAR2_3,
+S_ARTIPUZZGEAR2_4,
+S_ARTIPUZZGEAR2_5,
+S_ARTIPUZZGEAR2_6,
+S_ARTIPUZZGEAR2_7,
+S_ARTIPUZZGEAR2_8,
+S_ARTIPUZZGEAR3_1,
+S_ARTIPUZZGEAR3_2,
+S_ARTIPUZZGEAR3_3,
+S_ARTIPUZZGEAR3_4,
+S_ARTIPUZZGEAR3_5,
+S_ARTIPUZZGEAR3_6,
+S_ARTIPUZZGEAR3_7,
+S_ARTIPUZZGEAR3_8,
+S_ARTIPUZZGEAR4_1,
+S_ARTIPUZZGEAR4_2,
+S_ARTIPUZZGEAR4_3,
+S_ARTIPUZZGEAR4_4,
+S_ARTIPUZZGEAR4_5,
+S_ARTIPUZZGEAR4_6,
+S_ARTIPUZZGEAR4_7,
+S_ARTIPUZZGEAR4_8,
+S_ARTI_TRCH1,
+S_ARTI_TRCH2,
+S_ARTI_TRCH3,
+S_FIREBOMB1,
+S_FIREBOMB2,
+S_FIREBOMB3,
+S_FIREBOMB4,
+S_FIREBOMB5,
+S_FIREBOMB6,
+S_FIREBOMB7,
+S_FIREBOMB8,
+S_FIREBOMB9,
+S_FIREBOMB10,
+S_FIREBOMB11,
+S_ARTI_ATLP1,
+S_ARTI_ATLP2,
+S_ARTI_ATLP3,
+S_ARTI_ATLP4,
+S_ARTI_PSBG1,
+S_POISONBAG1,
+S_POISONBAG2,
+S_POISONBAG3,
+S_POISONBAG4,
+S_POISONCLOUD1,
+S_POISONCLOUD2,
+S_POISONCLOUD3,
+S_POISONCLOUD4,
+S_POISONCLOUD5,
+S_POISONCLOUD6,
+S_POISONCLOUD7,
+S_POISONCLOUD8,
+S_POISONCLOUD9,
+S_POISONCLOUD10,
+S_POISONCLOUD11,
+S_POISONCLOUD12,
+S_POISONCLOUD13,
+S_POISONCLOUD14,
+S_POISONCLOUD15,
+S_POISONCLOUD16,
+S_POISONCLOUD17,
+S_POISONCLOUD18,
+S_POISONCLOUD_X1,
+S_POISONCLOUD_X2,
+S_POISONCLOUD_X3,
+S_POISONCLOUD_X4,
+S_THROWINGBOMB1,
+S_THROWINGBOMB2,
+S_THROWINGBOMB3,
+S_THROWINGBOMB4,
+S_THROWINGBOMB5,
+S_THROWINGBOMB6,
+S_THROWINGBOMB7,
+S_THROWINGBOMB8,
+S_THROWINGBOMB9,
+S_THROWINGBOMB10,
+S_THROWINGBOMB11,
+S_THROWINGBOMB12,
+S_THROWINGBOMB_X1,
+S_THROWINGBOMB_X2,
+S_THROWINGBOMB_X3,
+S_THROWINGBOMB_X4,
+S_THROWINGBOMB_X5,
+S_THROWINGBOMB_X6,
+S_THROWINGBOMB_X7,
+S_THROWINGBOMB_X8,
+S_ARTI_BOOTS1,
+S_ARTI_BOOTS2,
+S_ARTI_BOOTS3,
+S_ARTI_BOOTS4,
+S_ARTI_BOOTS5,
+S_ARTI_BOOTS6,
+S_ARTI_BOOTS7,
+S_ARTI_BOOTS8,
+S_ARTI_MANA,
+S_ARTI_ARMOR1,
+S_ARTI_ARMOR2,
+S_ARTI_ARMOR3,
+S_ARTI_ARMOR4,
+S_ARTI_ARMOR5,
+S_ARTI_ARMOR6,
+S_ARTI_ARMOR7,
+S_ARTI_ARMOR8,
+S_ARTI_BLAST1,
+S_ARTI_BLAST2,
+S_ARTI_BLAST3,
+S_ARTI_BLAST4,
+S_ARTI_BLAST5,
+S_ARTI_BLAST6,
+S_ARTI_BLAST7,
+S_ARTI_BLAST8,
+S_ARTI_HEALRAD1,
+S_ARTI_HEALRAD2,
+S_ARTI_HEALRAD3,
+S_ARTI_HEALRAD4,
+S_ARTI_HEALRAD5,
+S_ARTI_HEALRAD6,
+S_ARTI_HEALRAD7,
+S_ARTI_HEALRAD8,
+S_ARTI_HEALRAD9,
+S_ARTI_HEALRAD0,
+S_ARTI_HEALRADA,
+S_ARTI_HEALRADB,
+S_ARTI_HEALRADC,
+S_ARTI_HEALRADD,
+S_ARTI_HEALRADE,
+S_ARTI_HEALRADF,
+S_SPLASH1,
+S_SPLASH2,
+S_SPLASH3,
+S_SPLASH4,
+S_SPLASHX,
+S_SPLASHBASE1,
+S_SPLASHBASE2,
+S_SPLASHBASE3,
+S_SPLASHBASE4,
+S_SPLASHBASE5,
+S_SPLASHBASE6,
+S_SPLASHBASE7,
+S_LAVASPLASH1,
+S_LAVASPLASH2,
+S_LAVASPLASH3,
+S_LAVASPLASH4,
+S_LAVASPLASH5,
+S_LAVASPLASH6,
+S_LAVASMOKE1,
+S_LAVASMOKE2,
+S_LAVASMOKE3,
+S_LAVASMOKE4,
+S_LAVASMOKE5,
+S_SLUDGECHUNK1,
+S_SLUDGECHUNK2,
+S_SLUDGECHUNK3,
+S_SLUDGECHUNK4,
+S_SLUDGECHUNKX,
+S_SLUDGESPLASH1,
+S_SLUDGESPLASH2,
+S_SLUDGESPLASH3,
+S_SLUDGESPLASH4,
+S_ZWINGEDSTATUE1,
+S_ZROCK1_1,
+S_ZROCK2_1,
+S_ZROCK3_1,
+S_ZROCK4_1,
+S_ZCHANDELIER1,
+S_ZCHANDELIER2,
+S_ZCHANDELIER3,
+S_ZCHANDELIER_U,
+S_ZTREEDEAD1,
+S_ZTREE,
+S_ZTREEDESTRUCTIBLE1,
+S_ZTREEDES_D1,
+S_ZTREEDES_D2,
+S_ZTREEDES_D3,
+S_ZTREEDES_D4,
+S_ZTREEDES_D5,
+S_ZTREEDES_D6,
+S_ZTREEDES_X1,
+S_ZTREEDES_X2,
+S_ZTREEDES_X3,
+S_ZTREEDES_X4,
+S_ZTREEDES_X5,
+S_ZTREEDES_X6,
+S_ZTREEDES_X7,
+S_ZTREEDES_X8,
+S_ZTREEDES_X9,
+S_ZTREEDES_X10,
+S_ZTREESWAMP182_1,
+S_ZTREESWAMP172_1,
+S_ZSTUMPBURNED1,
+S_ZSTUMPBARE1,
+S_ZSTUMPSWAMP1_1,
+S_ZSTUMPSWAMP2_1,
+S_ZSHROOMLARGE1_1,
+S_ZSHROOMLARGE2_1,
+S_ZSHROOMLARGE3_1,
+S_ZSHROOMSMALL1_1,
+S_ZSHROOMSMALL2_1,
+S_ZSHROOMSMALL3_1,
+S_ZSHROOMSMALL4_1,
+S_ZSHROOMSMALL5_1,
+S_ZSTALAGMITEPILLAR1,
+S_ZSTALAGMITELARGE1,
+S_ZSTALAGMITEMEDIUM1,
+S_ZSTALAGMITESMALL1,
+S_ZSTALACTITELARGE1,
+S_ZSTALACTITEMEDIUM1,
+S_ZSTALACTITESMALL1,
+S_ZMOSSCEILING1_1,
+S_ZMOSSCEILING2_1,
+S_ZSWAMPVINE1,
+S_ZCORPSEKABOB1,
+S_ZCORPSESLEEPING1,
+S_ZTOMBSTONERIP1,
+S_ZTOMBSTONESHANE1,
+S_ZTOMBSTONEBIGCROSS1,
+S_ZTOMBSTONEBRIANR1,
+S_ZTOMBSTONECROSSCIRCLE1,
+S_ZTOMBSTONESMALLCROSS1,
+S_ZTOMBSTONEBRIANP1,
+S_CORPSEHANGING_1,
+S_ZSTATUEGARGOYLEGREENTALL_1,
+S_ZSTATUEGARGOYLEBLUETALL_1,
+S_ZSTATUEGARGOYLEGREENSHORT_1,
+S_ZSTATUEGARGOYLEBLUESHORT_1,
+S_ZSTATUEGARGOYLESTRIPETALL_1,
+S_ZSTATUEGARGOYLEDARKREDTALL_1,
+S_ZSTATUEGARGOYLEREDTALL_1,
+S_ZSTATUEGARGOYLETANTALL_1,
+S_ZSTATUEGARGOYLERUSTTALL_1,
+S_ZSTATUEGARGOYLEDARKREDSHORT_1,
+S_ZSTATUEGARGOYLEREDSHORT_1,
+S_ZSTATUEGARGOYLETANSHORT_1,
+S_ZSTATUEGARGOYLERUSTSHORT_1,
+S_ZBANNERTATTERED_1,
+S_ZTREELARGE1,
+S_ZTREELARGE2,
+S_ZTREEGNARLED1,
+S_ZTREEGNARLED2,
+S_ZLOG,
+S_ZSTALACTITEICELARGE,
+S_ZSTALACTITEICEMEDIUM,
+S_ZSTALACTITEICESMALL,
+S_ZSTALACTITEICETINY,
+S_ZSTALAGMITEICELARGE,
+S_ZSTALAGMITEICEMEDIUM,
+S_ZSTALAGMITEICESMALL,
+S_ZSTALAGMITEICETINY,
+S_ZROCKBROWN1,
+S_ZROCKBROWN2,
+S_ZROCKBLACK,
+S_ZRUBBLE1,
+S_ZRUBBLE2,
+S_ZRUBBLE3,
+S_ZVASEPILLAR,
+S_ZPOTTERY1,
+S_ZPOTTERY2,
+S_ZPOTTERY3,
+S_ZPOTTERY_EXPLODE,
+S_POTTERYBIT_1,
+S_POTTERYBIT_2,
+S_POTTERYBIT_3,
+S_POTTERYBIT_4,
+S_POTTERYBIT_5,
+S_POTTERYBIT_EX0,
+S_POTTERYBIT_EX1,
+S_POTTERYBIT_EX1_2,
+S_POTTERYBIT_EX2,
+S_POTTERYBIT_EX2_2,
+S_POTTERYBIT_EX3,
+S_POTTERYBIT_EX3_2,
+S_POTTERYBIT_EX4,
+S_POTTERYBIT_EX4_2,
+S_POTTERYBIT_EX5,
+S_POTTERYBIT_EX5_2,
+S_ZCORPSELYNCHED1,
+S_ZCORPSELYNCHED2,
+S_ZCORPSESITTING,
+S_ZCORPSESITTING_X,
+S_CORPSEBIT_1,
+S_CORPSEBIT_2,
+S_CORPSEBIT_3,
+S_CORPSEBIT_4,
+S_CORPSEBLOODDRIP,
+S_CORPSEBLOODDRIP_X1,
+S_CORPSEBLOODDRIP_X2,
+S_CORPSEBLOODDRIP_X3,
+S_CORPSEBLOODDRIP_X4,
+S_BLOODPOOL,
+S_ZCANDLE1,
+S_ZCANDLE2,
+S_ZCANDLE3,
+S_ZLEAFSPAWNER,
+S_LEAF1_1,
+S_LEAF1_2,
+S_LEAF1_3,
+S_LEAF1_4,
+S_LEAF1_5,
+S_LEAF1_6,
+S_LEAF1_7,
+S_LEAF1_8,
+S_LEAF1_9,
+S_LEAF1_10,
+S_LEAF1_11,
+S_LEAF1_12,
+S_LEAF1_13,
+S_LEAF1_14,
+S_LEAF1_15,
+S_LEAF1_16,
+S_LEAF1_17,
+S_LEAF1_18,
+S_LEAF_X1,
+S_LEAF2_1,
+S_LEAF2_2,
+S_LEAF2_3,
+S_LEAF2_4,
+S_LEAF2_5,
+S_LEAF2_6,
+S_LEAF2_7,
+S_LEAF2_8,
+S_LEAF2_9,
+S_LEAF2_10,
+S_LEAF2_11,
+S_LEAF2_12,
+S_LEAF2_13,
+S_LEAF2_14,
+S_LEAF2_15,
+S_LEAF2_16,
+S_LEAF2_17,
+S_LEAF2_18,
+S_ZTWINEDTORCH_1,
+S_ZTWINEDTORCH_2,
+S_ZTWINEDTORCH_3,
+S_ZTWINEDTORCH_4,
+S_ZTWINEDTORCH_5,
+S_ZTWINEDTORCH_6,
+S_ZTWINEDTORCH_7,
+S_ZTWINEDTORCH_8,
+S_ZTWINEDTORCH_UNLIT,
+S_BRIDGE1,
+S_BRIDGE2,
+S_BRIDGE3,
+S_FREE_BRIDGE1,
+S_FREE_BRIDGE2,
+S_BBALL1,
+S_BBALL2,
+S_ZWALLTORCH1,
+S_ZWALLTORCH2,
+S_ZWALLTORCH3,
+S_ZWALLTORCH4,
+S_ZWALLTORCH5,
+S_ZWALLTORCH6,
+S_ZWALLTORCH7,
+S_ZWALLTORCH8,
+S_ZWALLTORCH_U,
+S_ZBARREL1,
+S_ZSHRUB1,
+S_ZSHRUB1_DIE,
+S_ZSHRUB1_X1,
+S_ZSHRUB1_X2,
+S_ZSHRUB1_X3,
+S_ZSHRUB2,
+S_ZSHRUB2_DIE,
+S_ZSHRUB2_X1,
+S_ZSHRUB2_X2,
+S_ZSHRUB2_X3,
+S_ZSHRUB2_X4,
+S_ZBUCKET1,
+S_ZPOISONSHROOM1,
+S_ZPOISONSHROOM_P1,
+S_ZPOISONSHROOM_P2,
+S_ZPOISONSHROOM_X1,
+S_ZPOISONSHROOM_X2,
+S_ZPOISONSHROOM_X3,
+S_ZPOISONSHROOM_X4,
+S_ZFIREBULL1,
+S_ZFIREBULL2,
+S_ZFIREBULL3,
+S_ZFIREBULL4,
+S_ZFIREBULL5,
+S_ZFIREBULL6,
+S_ZFIREBULL7,
+S_ZFIREBULL_DEATH,
+S_ZFIREBULL_DEATH2,
+S_ZFIREBULL_U,
+S_ZFIREBULL_BIRTH,
+S_ZFIREBULL_BIRTH2,
+S_ZFIRETHING1,
+S_ZFIRETHING2,
+S_ZFIRETHING3,
+S_ZFIRETHING4,
+S_ZFIRETHING5,
+S_ZFIRETHING6,
+S_ZFIRETHING7,
+S_ZFIRETHING8,
+S_ZFIRETHING9,
+S_ZBRASSTORCH1,
+S_ZBRASSTORCH2,
+S_ZBRASSTORCH3,
+S_ZBRASSTORCH4,
+S_ZBRASSTORCH5,
+S_ZBRASSTORCH6,
+S_ZBRASSTORCH7,
+S_ZBRASSTORCH8,
+S_ZBRASSTORCH9,
+S_ZBRASSTORCH10,
+S_ZBRASSTORCH11,
+S_ZBRASSTORCH12,
+S_ZBRASSTORCH13,
+S_ZSUITOFARMOR,
+S_ZSUITOFARMOR_X1,
+S_ZARMORCHUNK1,
+S_ZARMORCHUNK2,
+S_ZARMORCHUNK3,
+S_ZARMORCHUNK4,
+S_ZARMORCHUNK5,
+S_ZARMORCHUNK6,
+S_ZARMORCHUNK7,
+S_ZARMORCHUNK8,
+S_ZARMORCHUNK9,
+S_ZARMORCHUNK10,
+S_ZBELL,
+S_ZBELL_X1,
+S_ZBELL_X2,
+S_ZBELL_X3,
+S_ZBELL_X4,
+S_ZBELL_X5,
+S_ZBELL_X6,
+S_ZBELL_X7,
+S_ZBELL_X8,
+S_ZBELL_X9,
+S_ZBELL_X10,
+S_ZBELL_X11,
+S_ZBELL_X12,
+S_ZBELL_X13,
+S_ZBELL_X14,
+S_ZBELL_X15,
+S_ZBELL_X16,
+S_ZBELL_X17,
+S_ZBELL_X18,
+S_ZBELL_X19,
+S_ZBELL_X20,
+S_ZBELL_X21,
+S_ZBELL_X22,
+S_ZBELL_X23,
+S_ZBELL_X24,
+S_ZBELL_X25,
+S_ZBELL_X26,
+S_ZBELL_X27,
+S_ZBELL_X28,
+S_ZBELL_X29,
+S_ZBELL_X30,
+S_ZBELL_X31,
+S_ZBELL_X32,
+S_ZBELL_X33,
+S_ZBELL_X34,
+S_ZBELL_X35,
+S_ZBELL_X36,
+S_ZBELL_X37,
+S_ZBELL_X38,
+S_ZBELL_X39,
+S_ZBELL_X40,
+S_ZBELL_X41,
+S_ZBELL_X42,
+S_ZBELL_X43,
+S_ZBELL_X44,
+S_ZBELL_X45,
+S_ZBELL_X46,
+S_ZBELL_X47,
+S_ZBLUE_CANDLE1,
+S_ZBLUE_CANDLE2,
+S_ZBLUE_CANDLE3,
+S_ZBLUE_CANDLE4,
+S_ZBLUE_CANDLE5,
+S_ZIRON_MAIDEN,
+S_ZXMAS_TREE,
+S_ZXMAS_TREE_DIE,
+S_ZXMAS_TREE_X1,
+S_ZXMAS_TREE_X2,
+S_ZXMAS_TREE_X3,
+S_ZXMAS_TREE_X4,
+S_ZXMAS_TREE_X5,
+S_ZXMAS_TREE_X6,
+S_ZXMAS_TREE_X7,
+S_ZXMAS_TREE_X8,
+S_ZXMAS_TREE_X9,
+S_ZXMAS_TREE_X10,
+S_ZCAULDRON1,
+S_ZCAULDRON2,
+S_ZCAULDRON3,
+S_ZCAULDRON4,
+S_ZCAULDRON5,
+S_ZCAULDRON6,
+S_ZCAULDRON7,
+S_ZCAULDRON_U,
+S_ZCHAINBIT32,
+S_ZCHAINBIT64,
+S_ZCHAINEND_HEART,
+S_ZCHAINEND_HOOK1,
+S_ZCHAINEND_HOOK2,
+S_ZCHAINEND_SPIKE,
+S_ZCHAINEND_SKULL,
+S_TABLE_SHIT1,
+S_TABLE_SHIT2,
+S_TABLE_SHIT3,
+S_TABLE_SHIT4,
+S_TABLE_SHIT5,
+S_TABLE_SHIT6,
+S_TABLE_SHIT7,
+S_TABLE_SHIT8,
+S_TABLE_SHIT9,
+S_TABLE_SHIT10,
+S_TFOG1,
+S_TFOG2,
+S_TFOG3,
+S_TFOG4,
+S_TFOG5,
+S_TFOG6,
+S_TFOG7,
+S_TFOG8,
+S_TFOG9,
+S_TFOG10,
+S_TFOG11,
+S_TFOG12,
+S_TFOG13,
+S_TELESMOKE1,
+S_TELESMOKE2,
+S_TELESMOKE3,
+S_TELESMOKE4,
+S_TELESMOKE5,
+S_TELESMOKE6,
+S_TELESMOKE7,
+S_TELESMOKE8,
+S_TELESMOKE9,
+S_TELESMOKE10,
+S_TELESMOKE11,
+S_TELESMOKE12,
+S_TELESMOKE13,
+S_TELESMOKE14,
+S_TELESMOKE15,
+S_TELESMOKE16,
+S_TELESMOKE17,
+S_TELESMOKE18,
+S_TELESMOKE19,
+S_TELESMOKE20,
+S_TELESMOKE21,
+S_TELESMOKE22,
+S_TELESMOKE23,
+S_TELESMOKE24,
+S_TELESMOKE25,
+S_TELESMOKE26,
+S_LIGHTDONE,
+S_PUNCHREADY,
+S_PUNCHDOWN,
+S_PUNCHUP,
+S_PUNCHATK1_1,
+S_PUNCHATK1_2,
+S_PUNCHATK1_3,
+S_PUNCHATK1_4,
+S_PUNCHATK1_5,
+S_PUNCHATK2_1,
+S_PUNCHATK2_2,
+S_PUNCHATK2_3,
+S_PUNCHATK2_4,
+S_PUNCHATK2_5,
+S_PUNCHATK2_6,
+S_PUNCHATK2_7,
+S_PUNCHATK2_8,
+S_PUNCHATK2_9,
+S_PUNCHPUFF1,
+S_PUNCHPUFF2,
+S_PUNCHPUFF3,
+S_PUNCHPUFF4,
+S_PUNCHPUFF5,
+S_AXE,
+S_FAXEREADY,
+S_FAXEDOWN,
+S_FAXEUP,
+S_FAXEATK_1,
+S_FAXEATK_2,
+S_FAXEATK_3,
+S_FAXEATK_4,
+S_FAXEATK_5,
+S_FAXEATK_6,
+S_FAXEATK_7,
+S_FAXEATK_8,
+S_FAXEATK_9,
+S_FAXEATK_10,
+S_FAXEATK_11,
+S_FAXEATK_12,
+S_FAXEATK_13,
+S_FAXEREADY_G,
+S_FAXEREADY_G1,
+S_FAXEREADY_G2,
+S_FAXEREADY_G3,
+S_FAXEREADY_G4,
+S_FAXEREADY_G5,
+S_FAXEDOWN_G,
+S_FAXEUP_G,
+S_FAXEATK_G1,
+S_FAXEATK_G2,
+S_FAXEATK_G3,
+S_FAXEATK_G4,
+S_FAXEATK_G5,
+S_FAXEATK_G6,
+S_FAXEATK_G7,
+S_FAXEATK_G8,
+S_FAXEATK_G9,
+S_FAXEATK_G10,
+S_FAXEATK_G11,
+S_FAXEATK_G12,
+S_FAXEATK_G13,
+S_AXEPUFF_GLOW1,
+S_AXEPUFF_GLOW2,
+S_AXEPUFF_GLOW3,
+S_AXEPUFF_GLOW4,
+S_AXEPUFF_GLOW5,
+S_AXEPUFF_GLOW6,
+S_AXEPUFF_GLOW7,
+S_AXEBLOOD1,
+S_AXEBLOOD2,
+S_AXEBLOOD3,
+S_AXEBLOOD4,
+S_AXEBLOOD5,
+S_AXEBLOOD6,
+S_HAMM,
+S_FHAMMERREADY,
+S_FHAMMERDOWN,
+S_FHAMMERUP,
+S_FHAMMERATK_1,
+S_FHAMMERATK_2,
+S_FHAMMERATK_3,
+S_FHAMMERATK_4,
+S_FHAMMERATK_5,
+S_FHAMMERATK_6,
+S_FHAMMERATK_7,
+S_FHAMMERATK_8,
+S_FHAMMERATK_9,
+S_FHAMMERATK_10,
+S_FHAMMERATK_11,
+S_FHAMMERATK_12,
+S_HAMMER_MISSILE_1,
+S_HAMMER_MISSILE_2,
+S_HAMMER_MISSILE_3,
+S_HAMMER_MISSILE_4,
+S_HAMMER_MISSILE_5,
+S_HAMMER_MISSILE_6,
+S_HAMMER_MISSILE_7,
+S_HAMMER_MISSILE_8,
+S_HAMMER_MISSILE_X1,
+S_HAMMER_MISSILE_X2,
+S_HAMMER_MISSILE_X3,
+S_HAMMER_MISSILE_X4,
+S_HAMMER_MISSILE_X5,
+S_HAMMER_MISSILE_X6,
+S_HAMMER_MISSILE_X7,
+S_HAMMER_MISSILE_X8,
+S_HAMMER_MISSILE_X9,
+S_HAMMER_MISSILE_X10,
+S_HAMMERPUFF1,
+S_HAMMERPUFF2,
+S_HAMMERPUFF3,
+S_HAMMERPUFF4,
+S_HAMMERPUFF5,
+S_FSWORDREADY,
+S_FSWORDREADY1,
+S_FSWORDREADY2,
+S_FSWORDREADY3,
+S_FSWORDREADY4,
+S_FSWORDREADY5,
+S_FSWORDREADY6,
+S_FSWORDREADY7,
+S_FSWORDREADY8,
+S_FSWORDREADY9,
+S_FSWORDREADY10,
+S_FSWORDREADY11,
+S_FSWORDDOWN,
+S_FSWORDUP,
+S_FSWORDATK_1,
+S_FSWORDATK_2,
+S_FSWORDATK_3,
+S_FSWORDATK_4,
+S_FSWORDATK_5,
+S_FSWORDATK_6,
+S_FSWORDATK_7,
+S_FSWORDATK_8,
+S_FSWORDATK_9,
+S_FSWORDATK_10,
+S_FSWORDATK_11,
+S_FSWORDATK_12,
+S_FSWORD_MISSILE1,
+S_FSWORD_MISSILE2,
+S_FSWORD_MISSILE3,
+S_FSWORD_MISSILE_X1,
+S_FSWORD_MISSILE_X2,
+S_FSWORD_MISSILE_X3,
+S_FSWORD_MISSILE_X4,
+S_FSWORD_MISSILE_X5,
+S_FSWORD_MISSILE_X6,
+S_FSWORD_MISSILE_X7,
+S_FSWORD_MISSILE_X8,
+S_FSWORD_MISSILE_X9,
+S_FSWORD_MISSILE_X10,
+S_FSWORD_FLAME1,
+S_FSWORD_FLAME2,
+S_FSWORD_FLAME3,
+S_FSWORD_FLAME4,
+S_FSWORD_FLAME5,
+S_FSWORD_FLAME6,
+S_FSWORD_FLAME7,
+S_FSWORD_FLAME8,
+S_FSWORD_FLAME9,
+S_FSWORD_FLAME10,
+S_CMACEREADY,
+S_CMACEDOWN,
+S_CMACEUP,
+S_CMACEATK_1,
+S_CMACEATK_2,
+S_CMACEATK_3,
+S_CMACEATK_4,
+S_CMACEATK_5,
+S_CMACEATK_6,
+S_CMACEATK_7,
+S_CMACEATK_8,
+S_CMACEATK_9,
+S_CMACEATK_10,
+S_CMACEATK_11,
+S_CMACEATK_12,
+S_CMACEATK_13,
+S_CMACEATK_14,
+S_CMACEATK_15,
+S_CMACEATK_16,
+S_CMACEATK_17,
+S_CSTAFF,
+S_CSTAFFREADY,
+S_CSTAFFREADY1,
+S_CSTAFFREADY2,
+S_CSTAFFREADY3,
+S_CSTAFFREADY4,
+S_CSTAFFREADY5,
+S_CSTAFFREADY6,
+S_CSTAFFREADY7,
+S_CSTAFFREADY8,
+S_CSTAFFREADY9,
+S_CSTAFFBLINK1,
+S_CSTAFFBLINK2,
+S_CSTAFFBLINK3,
+S_CSTAFFBLINK4,
+S_CSTAFFBLINK5,
+S_CSTAFFBLINK6,
+S_CSTAFFBLINK7,
+S_CSTAFFBLINK8,
+S_CSTAFFBLINK9,
+S_CSTAFFBLINK10,
+S_CSTAFFBLINK11,
+S_CSTAFFDOWN,
+S_CSTAFFDOWN2,
+S_CSTAFFDOWN3,
+S_CSTAFFUP,
+S_CSTAFFATK_1,
+S_CSTAFFATK_2,
+S_CSTAFFATK_3,
+S_CSTAFFATK_4,
+S_CSTAFFATK_5,
+S_CSTAFFATK_6,
+S_CSTAFFATK2_1,
+S_CSTAFF_MISSILE1,
+S_CSTAFF_MISSILE2,
+S_CSTAFF_MISSILE3,
+S_CSTAFF_MISSILE4,
+S_CSTAFF_MISSILE_X1,
+S_CSTAFF_MISSILE_X2,
+S_CSTAFF_MISSILE_X3,
+S_CSTAFF_MISSILE_X4,
+S_CSTAFFPUFF1,
+S_CSTAFFPUFF2,
+S_CSTAFFPUFF3,
+S_CSTAFFPUFF4,
+S_CSTAFFPUFF5,
+S_CFLAME1,
+S_CFLAME2,
+S_CFLAME3,
+S_CFLAME4,
+S_CFLAME5,
+S_CFLAME6,
+S_CFLAME7,
+S_CFLAME8,
+S_CFLAMEREADY1,
+S_CFLAMEREADY2,
+S_CFLAMEREADY3,
+S_CFLAMEREADY4,
+S_CFLAMEREADY5,
+S_CFLAMEREADY6,
+S_CFLAMEREADY7,
+S_CFLAMEREADY8,
+S_CFLAMEREADY9,
+S_CFLAMEREADY10,
+S_CFLAMEREADY11,
+S_CFLAMEREADY12,
+S_CFLAMEDOWN,
+S_CFLAMEUP,
+S_CFLAMEATK_1,
+S_CFLAMEATK_2,
+S_CFLAMEATK_3,
+S_CFLAMEATK_4,
+S_CFLAMEATK_5,
+S_CFLAMEATK_6,
+S_CFLAMEATK_7,
+S_CFLAMEATK_8,
+S_CFLAMEFLOOR1,
+S_CFLAMEFLOOR2,
+S_CFLAMEFLOOR3,
+S_FLAMEPUFF1,
+S_FLAMEPUFF2,
+S_FLAMEPUFF3,
+S_FLAMEPUFF4,
+S_FLAMEPUFF5,
+S_FLAMEPUFF6,
+S_FLAMEPUFF7,
+S_FLAMEPUFF8,
+S_FLAMEPUFF9,
+S_FLAMEPUFF10,
+S_FLAMEPUFF11,
+S_FLAMEPUFF12,
+S_FLAMEPUFF13,
+S_FLAMEPUFF2_1,
+S_FLAMEPUFF2_2,
+S_FLAMEPUFF2_3,
+S_FLAMEPUFF2_4,
+S_FLAMEPUFF2_5,
+S_FLAMEPUFF2_6,
+S_FLAMEPUFF2_7,
+S_FLAMEPUFF2_8,
+S_FLAMEPUFF2_9,
+S_FLAMEPUFF2_10,
+S_FLAMEPUFF2_11,
+S_FLAMEPUFF2_12,
+S_FLAMEPUFF2_13,
+S_FLAMEPUFF2_14,
+S_FLAMEPUFF2_15,
+S_FLAMEPUFF2_16,
+S_FLAMEPUFF2_17,
+S_FLAMEPUFF2_18,
+S_FLAMEPUFF2_19,
+S_FLAMEPUFF2_20,
+S_CIRCLE_FLAME1,
+S_CIRCLE_FLAME2,
+S_CIRCLE_FLAME3,
+S_CIRCLE_FLAME4,
+S_CIRCLE_FLAME5,
+S_CIRCLE_FLAME6,
+S_CIRCLE_FLAME7,
+S_CIRCLE_FLAME8,
+S_CIRCLE_FLAME9,
+S_CIRCLE_FLAME10,
+S_CIRCLE_FLAME11,
+S_CIRCLE_FLAME12,
+S_CIRCLE_FLAME13,
+S_CIRCLE_FLAME14,
+S_CIRCLE_FLAME15,
+S_CIRCLE_FLAME16,
+S_CIRCLE_FLAME_X1,
+S_CIRCLE_FLAME_X2,
+S_CIRCLE_FLAME_X3,
+S_CIRCLE_FLAME_X4,
+S_CIRCLE_FLAME_X5,
+S_CIRCLE_FLAME_X6,
+S_CIRCLE_FLAME_X7,
+S_CIRCLE_FLAME_X8,
+S_CIRCLE_FLAME_X9,
+S_CIRCLE_FLAME_X10,
+S_CFLAME_MISSILE1,
+S_CFLAME_MISSILE2,
+S_CFLAME_MISSILE_X,
+S_CHOLYREADY,
+S_CHOLYDOWN,
+S_CHOLYUP,
+S_CHOLYATK_1,
+S_CHOLYATK_2,
+S_CHOLYATK_3,
+S_CHOLYATK_4,
+S_CHOLYATK_5,
+S_CHOLYATK_6,
+S_CHOLYATK_7,
+S_CHOLYATK_8,
+S_CHOLYATK_9,
+S_HOLY_FX1,
+S_HOLY_FX2,
+S_HOLY_FX3,
+S_HOLY_FX4,
+S_HOLY_FX_X1,
+S_HOLY_FX_X2,
+S_HOLY_FX_X3,
+S_HOLY_FX_X4,
+S_HOLY_FX_X5,
+S_HOLY_FX_X6,
+S_HOLY_TAIL1,
+S_HOLY_TAIL2,
+S_HOLY_PUFF1,
+S_HOLY_PUFF2,
+S_HOLY_PUFF3,
+S_HOLY_PUFF4,
+S_HOLY_PUFF5,
+S_HOLY_MISSILE1,
+S_HOLY_MISSILE2,
+S_HOLY_MISSILE3,
+S_HOLY_MISSILE4,
+S_HOLY_MISSILE_X,
+S_HOLY_MISSILE_P1,
+S_HOLY_MISSILE_P2,
+S_HOLY_MISSILE_P3,
+S_HOLY_MISSILE_P4,
+S_HOLY_MISSILE_P5,
+S_MWANDREADY,
+S_MWANDDOWN,
+S_MWANDUP,
+S_MWANDATK_1,
+S_MWANDATK_2,
+S_MWANDATK_3,
+S_MWANDATK_4,
+S_MWANDPUFF1,
+S_MWANDPUFF2,
+S_MWANDPUFF3,
+S_MWANDPUFF4,
+S_MWANDPUFF5,
+S_MWANDSMOKE1,
+S_MWANDSMOKE2,
+S_MWANDSMOKE3,
+S_MWANDSMOKE4,
+S_MWAND_MISSILE1,
+S_MWAND_MISSILE2,
+S_MW_LIGHTNING1,
+S_MW_LIGHTNING2,
+S_MW_LIGHTNING3,
+S_MW_LIGHTNING4,
+S_MW_LIGHTNING5,
+S_MW_LIGHTNING6,
+S_MW_LIGHTNING7,
+S_MW_LIGHTNING8,
+S_MLIGHTNINGREADY,
+S_MLIGHTNINGREADY2,
+S_MLIGHTNINGREADY3,
+S_MLIGHTNINGREADY4,
+S_MLIGHTNINGREADY5,
+S_MLIGHTNINGREADY6,
+S_MLIGHTNINGREADY7,
+S_MLIGHTNINGREADY8,
+S_MLIGHTNINGREADY9,
+S_MLIGHTNINGREADY10,
+S_MLIGHTNINGREADY11,
+S_MLIGHTNINGREADY12,
+S_MLIGHTNINGREADY13,
+S_MLIGHTNINGREADY14,
+S_MLIGHTNINGREADY15,
+S_MLIGHTNINGREADY16,
+S_MLIGHTNINGREADY17,
+S_MLIGHTNINGREADY18,
+S_MLIGHTNINGREADY19,
+S_MLIGHTNINGREADY20,
+S_MLIGHTNINGREADY21,
+S_MLIGHTNINGREADY22,
+S_MLIGHTNINGREADY23,
+S_MLIGHTNINGREADY24,
+S_MLIGHTNINGDOWN,
+S_MLIGHTNINGUP,
+S_MLIGHTNINGATK_1,
+S_MLIGHTNINGATK_2,
+S_MLIGHTNINGATK_3,
+S_MLIGHTNINGATK_4,
+S_MLIGHTNINGATK_5,
+S_MLIGHTNINGATK_6,
+S_MLIGHTNINGATK_7,
+S_MLIGHTNINGATK_8,
+S_MLIGHTNINGATK_9,
+S_MLIGHTNINGATK_10,
+S_MLIGHTNINGATK_11,
+S_LIGHTNING_CEILING1,
+S_LIGHTNING_CEILING2,
+S_LIGHTNING_CEILING3,
+S_LIGHTNING_CEILING4,
+S_LIGHTNING_C_X1,
+S_LIGHTNING_C_X2,
+S_LIGHTNING_C_X3,
+S_LIGHTNING_C_X4,
+S_LIGHTNING_C_X5,
+S_LIGHTNING_C_X6,
+S_LIGHTNING_C_X7,
+S_LIGHTNING_C_X8,
+S_LIGHTNING_C_X9,
+S_LIGHTNING_C_X10,
+S_LIGHTNING_C_X11,
+S_LIGHTNING_C_X12,
+S_LIGHTNING_C_X13,
+S_LIGHTNING_C_X14,
+S_LIGHTNING_C_X15,
+S_LIGHTNING_C_X16,
+S_LIGHTNING_C_X17,
+S_LIGHTNING_C_X18,
+S_LIGHTNING_C_X19,
+S_LIGHTNING_FLOOR1,
+S_LIGHTNING_FLOOR2,
+S_LIGHTNING_FLOOR3,
+S_LIGHTNING_FLOOR4,
+S_LIGHTNING_F_X1,
+S_LIGHTNING_F_X2,
+S_LIGHTNING_F_X3,
+S_LIGHTNING_F_X4,
+S_LIGHTNING_F_X5,
+S_LIGHTNING_F_X6,
+S_LIGHTNING_F_X7,
+S_LIGHTNING_F_X8,
+S_LIGHTNING_F_X9,
+S_LIGHTNING_F_X10,
+S_LIGHTNING_F_X11,
+S_LIGHTNING_F_X12,
+S_LIGHTNING_F_X13,
+S_LIGHTNING_F_X14,
+S_LIGHTNING_F_X15,
+S_LIGHTNING_F_X16,
+S_LIGHTNING_F_X17,
+S_LIGHTNING_F_X18,
+S_LIGHTNING_F_X19,
+S_LIGHTNING_ZAP1,
+S_LIGHTNING_ZAP2,
+S_LIGHTNING_ZAP3,
+S_LIGHTNING_ZAP4,
+S_LIGHTNING_ZAP5,
+S_LIGHTNING_ZAP_X1,
+S_LIGHTNING_ZAP_X2,
+S_LIGHTNING_ZAP_X3,
+S_LIGHTNING_ZAP_X4,
+S_LIGHTNING_ZAP_X5,
+S_LIGHTNING_ZAP_X6,
+S_LIGHTNING_ZAP_X7,
+S_LIGHTNING_ZAP_X8,
+S_MSTAFFREADY,
+S_MSTAFFREADY2,
+S_MSTAFFREADY3,
+S_MSTAFFREADY4,
+S_MSTAFFREADY5,
+S_MSTAFFREADY6,
+S_MSTAFFREADY7,
+S_MSTAFFREADY8,
+S_MSTAFFREADY9,
+S_MSTAFFREADY10,
+S_MSTAFFREADY11,
+S_MSTAFFREADY12,
+S_MSTAFFREADY13,
+S_MSTAFFREADY14,
+S_MSTAFFREADY15,
+S_MSTAFFREADY16,
+S_MSTAFFREADY17,
+S_MSTAFFREADY18,
+S_MSTAFFREADY19,
+S_MSTAFFREADY20,
+S_MSTAFFREADY21,
+S_MSTAFFREADY22,
+S_MSTAFFREADY23,
+S_MSTAFFREADY24,
+S_MSTAFFREADY25,
+S_MSTAFFREADY26,
+S_MSTAFFREADY27,
+S_MSTAFFREADY28,
+S_MSTAFFREADY29,
+S_MSTAFFREADY30,
+S_MSTAFFREADY31,
+S_MSTAFFREADY32,
+S_MSTAFFREADY33,
+S_MSTAFFREADY34,
+S_MSTAFFREADY35,
+S_MSTAFFDOWN,
+S_MSTAFFUP,
+S_MSTAFFATK_1,
+S_MSTAFFATK_2,
+S_MSTAFFATK_3,
+S_MSTAFFATK_4,
+S_MSTAFFATK_5,
+S_MSTAFFATK_6,
+S_MSTAFFATK_7,
+S_MSTAFF_FX1_1,
+S_MSTAFF_FX1_2,
+S_MSTAFF_FX1_3,
+S_MSTAFF_FX1_4,
+S_MSTAFF_FX1_5,
+S_MSTAFF_FX1_6,
+S_MSTAFF_FX_X1,
+S_MSTAFF_FX_X2,
+S_MSTAFF_FX_X3,
+S_MSTAFF_FX_X4,
+S_MSTAFF_FX_X5,
+S_MSTAFF_FX_X6,
+S_MSTAFF_FX_X7,
+S_MSTAFF_FX_X8,
+S_MSTAFF_FX_X9,
+S_MSTAFF_FX_X10,
+S_MSTAFF_FX2_1,
+S_MSTAFF_FX2_2,
+S_MSTAFF_FX2_3,
+S_MSTAFF_FX2_4,
+S_MSTAFF_FX2_X1,
+S_MSTAFF_FX2_X2,
+S_MSTAFF_FX2_X3,
+S_MSTAFF_FX2_X4,
+S_MSTAFF_FX2_X5,
+S_FSWORD1,
+S_FSWORD2,
+S_FSWORD3,
+S_CHOLY1,
+S_CHOLY2,
+S_CHOLY3,
+S_MSTAFF1,
+S_MSTAFF2,
+S_MSTAFF3,
+S_SNOUTREADY,
+S_SNOUTDOWN,
+S_SNOUTUP,
+S_SNOUTATK1,
+S_SNOUTATK2,
+S_COS1,
+S_COS2,
+S_COS3,
+S_CONEREADY,
+S_CONEDOWN,
+S_CONEUP,
+S_CONEATK1_1,
+S_CONEATK1_2,
+S_CONEATK1_3,
+S_CONEATK1_4,
+S_CONEATK1_5,
+S_CONEATK1_6,
+S_CONEATK1_7,
+S_CONEATK1_8,
+S_SHARDFX1_1,
+S_SHARDFX1_2,
+S_SHARDFX1_3,
+S_SHARDFX1_4,
+S_SHARDFXE1_1,
+S_SHARDFXE1_2,
+S_SHARDFXE1_3,
+S_SHARDFXE1_4,
+S_SHARDFXE1_5,
+S_BLOOD1,
+S_BLOOD2,
+S_BLOOD3,
+S_BLOODSPLATTER1,
+S_BLOODSPLATTER2,
+S_BLOODSPLATTER3,
+S_BLOODSPLATTERX,
+S_GIBS1,
+S_FPLAY,
+S_FPLAY_RUN1,
+S_FPLAY_RUN2,
+S_FPLAY_RUN3,
+S_FPLAY_RUN4,
+S_FPLAY_ATK1,
+S_FPLAY_ATK2,
+S_FPLAY_PAIN,
+S_FPLAY_PAIN2,
+S_FPLAY_DIE1,
+S_FPLAY_DIE2,
+S_FPLAY_DIE3,
+S_FPLAY_DIE4,
+S_FPLAY_DIE5,
+S_FPLAY_DIE6,
+S_FPLAY_DIE7,
+S_FPLAY_XDIE1,
+S_FPLAY_XDIE2,
+S_FPLAY_XDIE3,
+S_FPLAY_XDIE4,
+S_FPLAY_XDIE5,
+S_FPLAY_XDIE6,
+S_FPLAY_XDIE7,
+S_FPLAY_XDIE8,
+S_FPLAY_ICE,
+S_FPLAY_ICE2,
+S_PLAY_F_FDTH1,
+S_PLAY_F_FDTH2,
+S_PLAY_C_FDTH1,
+S_PLAY_C_FDTH2,
+S_PLAY_M_FDTH1,
+S_PLAY_M_FDTH2,
+S_PLAY_FDTH3,
+S_PLAY_FDTH4,
+S_PLAY_FDTH5,
+S_PLAY_FDTH6,
+S_PLAY_FDTH7,
+S_PLAY_FDTH8,
+S_PLAY_FDTH9,
+S_PLAY_FDTH10,
+S_PLAY_FDTH11,
+S_PLAY_FDTH12,
+S_PLAY_FDTH13,
+S_PLAY_FDTH14,
+S_PLAY_FDTH15,
+S_PLAY_FDTH16,
+S_PLAY_FDTH17,
+S_PLAY_FDTH18,
+S_PLAY_FDTH19,
+S_PLAY_FDTH20,
+S_BLOODYSKULL1,
+S_BLOODYSKULL2,
+S_BLOODYSKULL3,
+S_BLOODYSKULL4,
+S_BLOODYSKULL5,
+S_BLOODYSKULL6,
+S_BLOODYSKULL7,
+S_BLOODYSKULLX1,
+S_BLOODYSKULLX2,
+S_PLAYER_SPEED1,
+S_PLAYER_SPEED2,
+S_ICECHUNK1,
+S_ICECHUNK2,
+S_ICECHUNK3,
+S_ICECHUNK4,
+S_ICECHUNK_HEAD,
+S_ICECHUNK_HEAD2,
+S_CPLAY,
+S_CPLAY_RUN1,
+S_CPLAY_RUN2,
+S_CPLAY_RUN3,
+S_CPLAY_RUN4,
+S_CPLAY_ATK1,
+S_CPLAY_ATK2,
+S_CPLAY_ATK3,
+S_CPLAY_PAIN,
+S_CPLAY_PAIN2,
+S_CPLAY_DIE1,
+S_CPLAY_DIE2,
+S_CPLAY_DIE3,
+S_CPLAY_DIE4,
+S_CPLAY_DIE5,
+S_CPLAY_DIE6,
+S_CPLAY_DIE7,
+S_CPLAY_DIE8,
+S_CPLAY_DIE9,
+S_CPLAY_XDIE1,
+S_CPLAY_XDIE2,
+S_CPLAY_XDIE3,
+S_CPLAY_XDIE4,
+S_CPLAY_XDIE5,
+S_CPLAY_XDIE6,
+S_CPLAY_XDIE7,
+S_CPLAY_XDIE8,
+S_CPLAY_XDIE9,
+S_CPLAY_XDIE10,
+S_CPLAY_ICE,
+S_CPLAY_ICE2,
+S_MPLAY,
+S_MPLAY_RUN1,
+S_MPLAY_RUN2,
+S_MPLAY_RUN3,
+S_MPLAY_RUN4,
+S_MPLAY_ATK1,
+S_MPLAY_ATK2,
+S_MPLAY_PAIN,
+S_MPLAY_PAIN2,
+S_MPLAY_DIE1,
+S_MPLAY_DIE2,
+S_MPLAY_DIE3,
+S_MPLAY_DIE4,
+S_MPLAY_DIE5,
+S_MPLAY_DIE6,
+S_MPLAY_DIE7,
+S_MPLAY_XDIE1,
+S_MPLAY_XDIE2,
+S_MPLAY_XDIE3,
+S_MPLAY_XDIE4,
+S_MPLAY_XDIE5,
+S_MPLAY_XDIE6,
+S_MPLAY_XDIE7,
+S_MPLAY_XDIE8,
+S_MPLAY_XDIE9,
+S_MPLAY_ICE,
+S_MPLAY_ICE2,
+S_PIGPLAY,
+S_PIGPLAY_RUN1,
+S_PIGPLAY_RUN2,
+S_PIGPLAY_RUN3,
+S_PIGPLAY_RUN4,
+S_PIGPLAY_ATK1,
+S_PIGPLAY_PAIN,
+S_PIG_LOOK1,
+S_PIG_WALK1,
+S_PIG_WALK2,
+S_PIG_WALK3,
+S_PIG_WALK4,
+S_PIG_PAIN,
+S_PIG_ATK1,
+S_PIG_ATK2,
+S_PIG_DIE1,
+S_PIG_DIE2,
+S_PIG_DIE3,
+S_PIG_DIE4,
+S_PIG_DIE5,
+S_PIG_DIE6,
+S_PIG_DIE7,
+S_PIG_DIE8,
+S_PIG_ICE,
+S_PIG_ICE2,
+S_CENTAUR_LOOK1,
+S_CENTAUR_LOOK2,
+S_CENTAUR_WALK1,
+S_CENTAUR_WALK2,
+S_CENTAUR_WALK3,
+S_CENTAUR_WALK4,
+S_CENTAUR_ATK1,
+S_CENTAUR_ATK2,
+S_CENTAUR_ATK3,
+S_CENTAUR_MISSILE1,
+S_CENTAUR_MISSILE2,
+S_CENTAUR_MISSILE3,
+S_CENTAUR_MISSILE4,
+S_CENTAUR_PAIN1,
+S_CENTAUR_PAIN2,
+S_CENTAUR_PAIN3,
+S_CENTAUR_PAIN4,
+S_CENTAUR_PAIN5,
+S_CENTAUR_PAIN6,
+S_CENTAUR_DEATH1,
+S_CENTAUR_DEATH2,
+S_CENTAUR_DEATH3,
+S_CENTAUR_DEATH4,
+S_CENTAUR_DEATH5,
+S_CENTAUR_DEATH6,
+S_CENTAUR_DEATH7,
+S_CENTAUR_DEATH8,
+S_CENTAUR_DEATH9,
+S_CENTAUR_DEATH0,
+S_CENTAUR_DEATH_X1,
+S_CENTAUR_DEATH_X2,
+S_CENTAUR_DEATH_X3,
+S_CENTAUR_DEATH_X4,
+S_CENTAUR_DEATH_X5,
+S_CENTAUR_DEATH_X6,
+S_CENTAUR_DEATH_X7,
+S_CENTAUR_DEATH_X8,
+S_CENTAUR_DEATH_X9,
+S_CENTAUR_DEATH_X10,
+S_CENTAUR_DEATH_X11,
+S_CENTAUR_ICE,
+S_CENTAUR_ICE2,
+S_CENTAUR_FX1,
+S_CENTAUR_FX_X1,
+S_CENTAUR_FX_X2,
+S_CENTAUR_FX_X3,
+S_CENTAUR_FX_X4,
+S_CENTAUR_FX_X5,
+S_CENTAUR_SHIELD1,
+S_CENTAUR_SHIELD2,
+S_CENTAUR_SHIELD3,
+S_CENTAUR_SHIELD4,
+S_CENTAUR_SHIELD5,
+S_CENTAUR_SHIELD6,
+S_CENTAUR_SHIELD_X1,
+S_CENTAUR_SHIELD_X2,
+S_CENTAUR_SHIELD_X3,
+S_CENTAUR_SHIELD_X4,
+S_CENTAUR_SWORD1,
+S_CENTAUR_SWORD2,
+S_CENTAUR_SWORD3,
+S_CENTAUR_SWORD4,
+S_CENTAUR_SWORD5,
+S_CENTAUR_SWORD6,
+S_CENTAUR_SWORD7,
+S_CENTAUR_SWORD_X1,
+S_CENTAUR_SWORD_X2,
+S_CENTAUR_SWORD_X3,
+S_DEMN_LOOK1,
+S_DEMN_LOOK2,
+S_DEMN_CHASE1,
+S_DEMN_CHASE2,
+S_DEMN_CHASE3,
+S_DEMN_CHASE4,
+S_DEMN_ATK1_1,
+S_DEMN_ATK1_2,
+S_DEMN_ATK1_3,
+S_DEMN_ATK2_1,
+S_DEMN_ATK2_2,
+S_DEMN_ATK2_3,
+S_DEMN_PAIN1,
+S_DEMN_PAIN2,
+S_DEMN_DEATH1,
+S_DEMN_DEATH2,
+S_DEMN_DEATH3,
+S_DEMN_DEATH4,
+S_DEMN_DEATH5,
+S_DEMN_DEATH6,
+S_DEMN_DEATH7,
+S_DEMN_DEATH8,
+S_DEMN_DEATH9,
+S_DEMN_XDEATH1,
+S_DEMN_XDEATH2,
+S_DEMN_XDEATH3,
+S_DEMN_XDEATH4,
+S_DEMN_XDEATH5,
+S_DEMN_XDEATH6,
+S_DEMN_XDEATH7,
+S_DEMN_XDEATH8,
+S_DEMN_XDEATH9,
+S_DEMON_ICE,
+S_DEMON_ICE2,
+S_DEMONCHUNK1_1,
+S_DEMONCHUNK1_2,
+S_DEMONCHUNK1_3,
+S_DEMONCHUNK1_4,
+S_DEMONCHUNK2_1,
+S_DEMONCHUNK2_2,
+S_DEMONCHUNK2_3,
+S_DEMONCHUNK2_4,
+S_DEMONCHUNK3_1,
+S_DEMONCHUNK3_2,
+S_DEMONCHUNK3_3,
+S_DEMONCHUNK3_4,
+S_DEMONCHUNK4_1,
+S_DEMONCHUNK4_2,
+S_DEMONCHUNK4_3,
+S_DEMONCHUNK4_4,
+S_DEMONCHUNK5_1,
+S_DEMONCHUNK5_2,
+S_DEMONCHUNK5_3,
+S_DEMONCHUNK5_4,
+S_DEMONFX_MOVE1,
+S_DEMONFX_MOVE2,
+S_DEMONFX_MOVE3,
+S_DEMONFX_BOOM1,
+S_DEMONFX_BOOM2,
+S_DEMONFX_BOOM3,
+S_DEMONFX_BOOM4,
+S_DEMONFX_BOOM5,
+S_DEMN2_LOOK1,
+S_DEMN2_LOOK2,
+S_DEMN2_CHASE1,
+S_DEMN2_CHASE2,
+S_DEMN2_CHASE3,
+S_DEMN2_CHASE4,
+S_DEMN2_ATK1_1,
+S_DEMN2_ATK1_2,
+S_DEMN2_ATK1_3,
+S_DEMN2_ATK2_1,
+S_DEMN2_ATK2_2,
+S_DEMN2_ATK2_3,
+S_DEMN2_PAIN1,
+S_DEMN2_PAIN2,
+S_DEMN2_DEATH1,
+S_DEMN2_DEATH2,
+S_DEMN2_DEATH3,
+S_DEMN2_DEATH4,
+S_DEMN2_DEATH5,
+S_DEMN2_DEATH6,
+S_DEMN2_DEATH7,
+S_DEMN2_DEATH8,
+S_DEMN2_DEATH9,
+S_DEMN2_XDEATH1,
+S_DEMN2_XDEATH2,
+S_DEMN2_XDEATH3,
+S_DEMN2_XDEATH4,
+S_DEMN2_XDEATH5,
+S_DEMN2_XDEATH6,
+S_DEMN2_XDEATH7,
+S_DEMN2_XDEATH8,
+S_DEMN2_XDEATH9,
+S_DEMON2CHUNK1_1,
+S_DEMON2CHUNK1_2,
+S_DEMON2CHUNK1_3,
+S_DEMON2CHUNK1_4,
+S_DEMON2CHUNK2_1,
+S_DEMON2CHUNK2_2,
+S_DEMON2CHUNK2_3,
+S_DEMON2CHUNK2_4,
+S_DEMON2CHUNK3_1,
+S_DEMON2CHUNK3_2,
+S_DEMON2CHUNK3_3,
+S_DEMON2CHUNK3_4,
+S_DEMON2CHUNK4_1,
+S_DEMON2CHUNK4_2,
+S_DEMON2CHUNK4_3,
+S_DEMON2CHUNK4_4,
+S_DEMON2CHUNK5_1,
+S_DEMON2CHUNK5_2,
+S_DEMON2CHUNK5_3,
+S_DEMON2CHUNK5_4,
+S_DEMON2FX_MOVE1,
+S_DEMON2FX_MOVE2,
+S_DEMON2FX_MOVE3,
+S_DEMON2FX_MOVE4,
+S_DEMON2FX_MOVE5,
+S_DEMON2FX_MOVE6,
+S_DEMON2FX_BOOM1,
+S_DEMON2FX_BOOM2,
+S_DEMON2FX_BOOM3,
+S_DEMON2FX_BOOM4,
+S_DEMON2FX_BOOM5,
+S_DEMON2FX_BOOM6,
+S_WRAITH_RAISE1,
+S_WRAITH_RAISE2,
+S_WRAITH_RAISE3,
+S_WRAITH_RAISE4,
+S_WRAITH_RAISE5,
+S_WRAITH_INIT1,
+S_WRAITH_INIT2,
+S_WRAITH_LOOK1,
+S_WRAITH_LOOK2,
+S_WRAITH_CHASE1,
+S_WRAITH_CHASE2,
+S_WRAITH_CHASE3,
+S_WRAITH_CHASE4,
+S_WRAITH_ATK1_1,
+S_WRAITH_ATK1_2,
+S_WRAITH_ATK1_3,
+S_WRAITH_ATK2_1,
+S_WRAITH_ATK2_2,
+S_WRAITH_ATK2_3,
+S_WRAITH_PAIN1,
+S_WRAITH_PAIN2,
+S_WRAITH_DEATH1_1,
+S_WRAITH_DEATH1_2,
+S_WRAITH_DEATH1_3,
+S_WRAITH_DEATH1_4,
+S_WRAITH_DEATH1_5,
+S_WRAITH_DEATH1_6,
+S_WRAITH_DEATH1_7,
+S_WRAITH_DEATH1_8,
+S_WRAITH_DEATH1_9,
+S_WRAITH_DEATH1_0,
+S_WRAITH_DEATH2_1,
+S_WRAITH_DEATH2_2,
+S_WRAITH_DEATH2_3,
+S_WRAITH_DEATH2_4,
+S_WRAITH_DEATH2_5,
+S_WRAITH_DEATH2_6,
+S_WRAITH_DEATH2_7,
+S_WRAITH_DEATH2_8,
+S_WRAITH_ICE,
+S_WRAITH_ICE2,
+S_WRTHFX_MOVE1,
+S_WRTHFX_MOVE2,
+S_WRTHFX_MOVE3,
+S_WRTHFX_BOOM1,
+S_WRTHFX_BOOM2,
+S_WRTHFX_BOOM3,
+S_WRTHFX_BOOM4,
+S_WRTHFX_BOOM5,
+S_WRTHFX_BOOM6,
+S_WRTHFX_SIZZLE1,
+S_WRTHFX_SIZZLE2,
+S_WRTHFX_SIZZLE3,
+S_WRTHFX_SIZZLE4,
+S_WRTHFX_SIZZLE5,
+S_WRTHFX_SIZZLE6,
+S_WRTHFX_SIZZLE7,
+S_WRTHFX_DROP1,
+S_WRTHFX_DROP2,
+S_WRTHFX_DROP3,
+S_WRTHFX_DEAD1,
+S_WRTHFX_ADROP1,
+S_WRTHFX_ADROP2,
+S_WRTHFX_ADROP3,
+S_WRTHFX_ADROP4,
+S_WRTHFX_ADEAD1,
+S_WRTHFX_BDROP1,
+S_WRTHFX_BDROP2,
+S_WRTHFX_BDROP3,
+S_WRTHFX_BDEAD1,
+S_MNTR_SPAWN1,
+S_MNTR_SPAWN2,
+S_MNTR_SPAWN3,
+S_MNTR_LOOK1,
+S_MNTR_LOOK2,
+S_MNTR_WALK1,
+S_MNTR_WALK2,
+S_MNTR_WALK3,
+S_MNTR_WALK4,
+S_MNTR_ROAM1,
+S_MNTR_ROAM2,
+S_MNTR_ROAM3,
+S_MNTR_ROAM4,
+S_MNTR_ATK1_1,
+S_MNTR_ATK1_2,
+S_MNTR_ATK1_3,
+S_MNTR_ATK2_1,
+S_MNTR_ATK2_2,
+S_MNTR_ATK2_3,
+S_MNTR_ATK3_1,
+S_MNTR_ATK3_2,
+S_MNTR_ATK3_3,
+S_MNTR_ATK3_4,
+S_MNTR_ATK4_1,
+S_MNTR_PAIN1,
+S_MNTR_PAIN2,
+S_MNTR_DIE1,
+S_MNTR_DIE2,
+S_MNTR_DIE3,
+S_MNTR_DIE4,
+S_MNTR_DIE5,
+S_MNTR_DIE6,
+S_MNTR_DIE7,
+S_MNTR_DIE8,
+S_MNTR_DIE9,
+S_MNTRFX1_1,
+S_MNTRFX1_2,
+S_MNTRFXI1_1,
+S_MNTRFXI1_2,
+S_MNTRFXI1_3,
+S_MNTRFXI1_4,
+S_MNTRFXI1_5,
+S_MNTRFXI1_6,
+S_MNTRFX2_1,
+S_MNTRFXI2_1,
+S_MNTRFXI2_2,
+S_MNTRFXI2_3,
+S_MNTRFXI2_4,
+S_MNTRFXI2_5,
+S_MNTRFX3_1,
+S_MNTRFX3_2,
+S_MNTRFX3_3,
+S_MNTRFX3_4,
+S_MNTRFX3_5,
+S_MNTRFX3_6,
+S_MNTRFX3_7,
+S_MNTRFX3_8,
+S_MNTRFX3_9,
+S_MINOSMOKE1,
+S_MINOSMOKE2,
+S_MINOSMOKE3,
+S_MINOSMOKE4,
+S_MINOSMOKE5,
+S_MINOSMOKE6,
+S_MINOSMOKE7,
+S_MINOSMOKE8,
+S_MINOSMOKE9,
+S_MINOSMOKE0,
+S_MINOSMOKEA,
+S_MINOSMOKEB,
+S_MINOSMOKEC,
+S_MINOSMOKED,
+S_MINOSMOKEE,
+S_MINOSMOKEF,
+S_MINOSMOKEG,
+S_MINOSMOKEX1,
+S_MINOSMOKEX2,
+S_MINOSMOKEX3,
+S_MINOSMOKEX4,
+S_MINOSMOKEX5,
+S_MINOSMOKEX6,
+S_MINOSMOKEX7,
+S_MINOSMOKEX8,
+S_MINOSMOKEX9,
+S_MINOSMOKEX0,
+S_MINOSMOKEXA,
+S_MINOSMOKEXB,
+S_MINOSMOKEXC,
+S_MINOSMOKEXD,
+S_MINOSMOKEXE,
+S_MINOSMOKEXF,
+S_MINOSMOKEXG,
+S_MINOSMOKEXH,
+S_MINOSMOKEXI,
+S_SERPENT_LOOK1,
+S_SERPENT_SWIM1,
+S_SERPENT_SWIM2,
+S_SERPENT_SWIM3,
+S_SERPENT_HUMP1,
+S_SERPENT_HUMP2,
+S_SERPENT_HUMP3,
+S_SERPENT_HUMP4,
+S_SERPENT_HUMP5,
+S_SERPENT_HUMP6,
+S_SERPENT_HUMP7,
+S_SERPENT_HUMP8,
+S_SERPENT_HUMP9,
+S_SERPENT_HUMP10,
+S_SERPENT_HUMP11,
+S_SERPENT_HUMP12,
+S_SERPENT_HUMP13,
+S_SERPENT_HUMP14,
+S_SERPENT_HUMP15,
+S_SERPENT_SURFACE1,
+S_SERPENT_SURFACE2,
+S_SERPENT_SURFACE3,
+S_SERPENT_SURFACE4,
+S_SERPENT_SURFACE5,
+S_SERPENT_DIVE1,
+S_SERPENT_DIVE2,
+S_SERPENT_DIVE3,
+S_SERPENT_DIVE4,
+S_SERPENT_DIVE5,
+S_SERPENT_DIVE6,
+S_SERPENT_DIVE7,
+S_SERPENT_DIVE8,
+S_SERPENT_DIVE9,
+S_SERPENT_DIVE10,
+S_SERPENT_WALK1,
+S_SERPENT_WALK2,
+S_SERPENT_WALK3,
+S_SERPENT_WALK4,
+S_SERPENT_PAIN1,
+S_SERPENT_PAIN2,
+S_SERPENT_ATK1,
+S_SERPENT_ATK2,
+S_SERPENT_MELEE1,
+S_SERPENT_MISSILE1,
+S_SERPENT_DIE1,
+S_SERPENT_DIE2,
+S_SERPENT_DIE3,
+S_SERPENT_DIE4,
+S_SERPENT_DIE5,
+S_SERPENT_DIE6,
+S_SERPENT_DIE7,
+S_SERPENT_DIE8,
+S_SERPENT_DIE9,
+S_SERPENT_DIE10,
+S_SERPENT_DIE11,
+S_SERPENT_DIE12,
+S_SERPENT_XDIE1,
+S_SERPENT_XDIE2,
+S_SERPENT_XDIE3,
+S_SERPENT_XDIE4,
+S_SERPENT_XDIE5,
+S_SERPENT_XDIE6,
+S_SERPENT_XDIE7,
+S_SERPENT_XDIE8,
+S_SERPENT_ICE,
+S_SERPENT_ICE2,
+S_SERPENT_FX1,
+S_SERPENT_FX2,
+S_SERPENT_FX3,
+S_SERPENT_FX4,
+S_SERPENT_FX_X1,
+S_SERPENT_FX_X2,
+S_SERPENT_FX_X3,
+S_SERPENT_FX_X4,
+S_SERPENT_FX_X5,
+S_SERPENT_FX_X6,
+S_SERPENT_HEAD1,
+S_SERPENT_HEAD2,
+S_SERPENT_HEAD3,
+S_SERPENT_HEAD4,
+S_SERPENT_HEAD5,
+S_SERPENT_HEAD6,
+S_SERPENT_HEAD7,
+S_SERPENT_HEAD8,
+S_SERPENT_HEAD_X1,
+S_SERPENT_GIB1_1,
+S_SERPENT_GIB1_2,
+S_SERPENT_GIB1_3,
+S_SERPENT_GIB1_4,
+S_SERPENT_GIB1_5,
+S_SERPENT_GIB1_6,
+S_SERPENT_GIB1_7,
+S_SERPENT_GIB1_8,
+S_SERPENT_GIB1_9,
+S_SERPENT_GIB1_10,
+S_SERPENT_GIB1_11,
+S_SERPENT_GIB1_12,
+S_SERPENT_GIB2_1,
+S_SERPENT_GIB2_2,
+S_SERPENT_GIB2_3,
+S_SERPENT_GIB2_4,
+S_SERPENT_GIB2_5,
+S_SERPENT_GIB2_6,
+S_SERPENT_GIB2_7,
+S_SERPENT_GIB2_8,
+S_SERPENT_GIB2_9,
+S_SERPENT_GIB2_10,
+S_SERPENT_GIB2_11,
+S_SERPENT_GIB2_12,
+S_SERPENT_GIB3_1,
+S_SERPENT_GIB3_2,
+S_SERPENT_GIB3_3,
+S_SERPENT_GIB3_4,
+S_SERPENT_GIB3_5,
+S_SERPENT_GIB3_6,
+S_SERPENT_GIB3_7,
+S_SERPENT_GIB3_8,
+S_SERPENT_GIB3_9,
+S_SERPENT_GIB3_10,
+S_SERPENT_GIB3_11,
+S_SERPENT_GIB3_12,
+S_BISHOP_LOOK1,
+S_BISHOP_DECIDE,
+S_BISHOP_BLUR1,
+S_BISHOP_BLUR2,
+S_BISHOP_WALK1,
+S_BISHOP_WALK2,
+S_BISHOP_WALK3,
+S_BISHOP_WALK4,
+S_BISHOP_WALK5,
+S_BISHOP_WALK6,
+S_BISHOP_ATK1,
+S_BISHOP_ATK2,
+S_BISHOP_ATK3,
+S_BISHOP_ATK4,
+S_BISHOP_ATK5,
+S_BISHOP_PAIN1,
+S_BISHOP_PAIN2,
+S_BISHOP_PAIN3,
+S_BISHOP_PAIN4,
+S_BISHOP_PAIN5,
+S_BISHOP_DEATH1,
+S_BISHOP_DEATH2,
+S_BISHOP_DEATH3,
+S_BISHOP_DEATH4,
+S_BISHOP_DEATH5,
+S_BISHOP_DEATH6,
+S_BISHOP_DEATH7,
+S_BISHOP_DEATH8,
+S_BISHOP_DEATH9,
+S_BISHOP_DEATH10,
+S_BISHOP_ICE,
+S_BISHOP_ICE2,
+S_BISHOP_PUFF1,
+S_BISHOP_PUFF2,
+S_BISHOP_PUFF3,
+S_BISHOP_PUFF4,
+S_BISHOP_PUFF5,
+S_BISHOP_PUFF6,
+S_BISHOP_PUFF7,
+S_BISHOPBLUR1,
+S_BISHOPBLUR2,
+S_BISHOPPAINBLUR1,
+S_BISHFX1_1,
+S_BISHFX1_2,
+S_BISHFX1_3,
+S_BISHFX1_4,
+S_BISHFX1_5,
+S_BISHFXI1_1,
+S_BISHFXI1_2,
+S_BISHFXI1_3,
+S_BISHFXI1_4,
+S_BISHFXI1_5,
+S_BISHFXI1_6,
+S_DRAGON_LOOK1,
+S_DRAGON_INIT,
+S_DRAGON_INIT2,
+S_DRAGON_INIT3,
+S_DRAGON_WALK1,
+S_DRAGON_WALK2,
+S_DRAGON_WALK3,
+S_DRAGON_WALK4,
+S_DRAGON_WALK5,
+S_DRAGON_WALK6,
+S_DRAGON_WALK7,
+S_DRAGON_WALK8,
+S_DRAGON_WALK9,
+S_DRAGON_WALK10,
+S_DRAGON_WALK11,
+S_DRAGON_WALK12,
+S_DRAGON_ATK1,
+S_DRAGON_PAIN1,
+S_DRAGON_DEATH1,
+S_DRAGON_DEATH2,
+S_DRAGON_DEATH3,
+S_DRAGON_DEATH4,
+S_DRAGON_CRASH1,
+S_DRAGON_CRASH2,
+S_DRAGON_CRASH3,
+S_DRAGON_FX1_1,
+S_DRAGON_FX1_2,
+S_DRAGON_FX1_3,
+S_DRAGON_FX1_4,
+S_DRAGON_FX1_5,
+S_DRAGON_FX1_6,
+S_DRAGON_FX1_X1,
+S_DRAGON_FX1_X2,
+S_DRAGON_FX1_X3,
+S_DRAGON_FX1_X4,
+S_DRAGON_FX1_X5,
+S_DRAGON_FX1_X6,
+S_DRAGON_FX2_1,
+S_DRAGON_FX2_2,
+S_DRAGON_FX2_3,
+S_DRAGON_FX2_4,
+S_DRAGON_FX2_5,
+S_DRAGON_FX2_6,
+S_DRAGON_FX2_7,
+S_DRAGON_FX2_8,
+S_DRAGON_FX2_9,
+S_DRAGON_FX2_10,
+S_DRAGON_FX2_11,
+S_ARMOR_1,
+S_ARMOR_2,
+S_ARMOR_3,
+S_ARMOR_4,
+S_MANA1_1,
+S_MANA1_2,
+S_MANA1_3,
+S_MANA1_4,
+S_MANA1_5,
+S_MANA1_6,
+S_MANA1_7,
+S_MANA1_8,
+S_MANA1_9,
+S_MANA2_1,
+S_MANA2_2,
+S_MANA2_3,
+S_MANA2_4,
+S_MANA2_5,
+S_MANA2_6,
+S_MANA2_7,
+S_MANA2_8,
+S_MANA2_9,
+S_MANA2_10,
+S_MANA2_11,
+S_MANA2_12,
+S_MANA2_13,
+S_MANA2_14,
+S_MANA2_15,
+S_MANA2_16,
+S_MANA3_1,
+S_MANA3_2,
+S_MANA3_3,
+S_MANA3_4,
+S_MANA3_5,
+S_MANA3_6,
+S_MANA3_7,
+S_MANA3_8,
+S_MANA3_9,
+S_MANA3_10,
+S_MANA3_11,
+S_MANA3_12,
+S_MANA3_13,
+S_MANA3_14,
+S_MANA3_15,
+S_MANA3_16,
+S_KEY1,
+S_KEY2,
+S_KEY3,
+S_KEY4,
+S_KEY5,
+S_KEY6,
+S_KEY7,
+S_KEY8,
+S_KEY9,
+S_KEYA,
+S_KEYB,
+S_SND_WIND1,
+S_SND_WIND2,
+S_SND_WATERFALL,
+S_ETTIN_LOOK1,
+S_ETTIN_LOOK2,
+S_ETTIN_CHASE1,
+S_ETTIN_CHASE2,
+S_ETTIN_CHASE3,
+S_ETTIN_CHASE4,
+S_ETTIN_PAIN1,
+S_ETTIN_ATK1_1,
+S_ETTIN_ATK1_2,
+S_ETTIN_ATK1_3,
+S_ETTIN_DEATH1_1,
+S_ETTIN_DEATH1_2,
+S_ETTIN_DEATH1_3,
+S_ETTIN_DEATH1_4,
+S_ETTIN_DEATH1_5,
+S_ETTIN_DEATH1_6,
+S_ETTIN_DEATH1_7,
+S_ETTIN_DEATH1_8,
+S_ETTIN_DEATH1_9,
+S_ETTIN_DEATH2_1,
+S_ETTIN_DEATH2_2,
+S_ETTIN_DEATH2_3,
+S_ETTIN_DEATH2_4,
+S_ETTIN_DEATH2_5,
+S_ETTIN_DEATH2_6,
+S_ETTIN_DEATH2_7,
+S_ETTIN_DEATH2_8,
+S_ETTIN_DEATH2_9,
+S_ETTIN_DEATH2_0,
+S_ETTIN_DEATH2_A,
+S_ETTIN_DEATH2_B,
+S_ETTIN_ICE1,
+S_ETTIN_ICE2,
+S_ETTIN_MACE1,
+S_ETTIN_MACE2,
+S_ETTIN_MACE3,
+S_ETTIN_MACE4,
+S_ETTIN_MACE5,
+S_ETTIN_MACE6,
+S_ETTIN_MACE7,
+S_FIRED_SPAWN1,
+S_FIRED_LOOK1,
+S_FIRED_LOOK2,
+S_FIRED_LOOK3,
+S_FIRED_LOOK4,
+S_FIRED_LOOK5,
+S_FIRED_LOOK6,
+S_FIRED_LOOK7,
+S_FIRED_LOOK8,
+S_FIRED_LOOK9,
+S_FIRED_LOOK0,
+S_FIRED_LOOKA,
+S_FIRED_LOOKB,
+S_FIRED_WALK1,
+S_FIRED_WALK2,
+S_FIRED_WALK3,
+S_FIRED_PAIN1,
+S_FIRED_ATTACK1,
+S_FIRED_ATTACK2,
+S_FIRED_ATTACK3,
+S_FIRED_ATTACK4,
+S_FIRED_DEATH1,
+S_FIRED_DEATH2,
+S_FIRED_DEATH3,
+S_FIRED_DEATH4,
+S_FIRED_XDEATH1,
+S_FIRED_XDEATH2,
+S_FIRED_XDEATH3,
+S_FIRED_ICE1,
+S_FIRED_ICE2,
+S_FIRED_CORPSE1,
+S_FIRED_CORPSE2,
+S_FIRED_CORPSE3,
+S_FIRED_CORPSE4,
+S_FIRED_CORPSE5,
+S_FIRED_CORPSE6,
+S_FIRED_RDROP1,
+S_FIRED_RDEAD1_1,
+S_FIRED_RDEAD1_2,
+S_FIRED_RDROP2,
+S_FIRED_RDEAD2_1,
+S_FIRED_RDEAD2_2,
+S_FIRED_RDROP3,
+S_FIRED_RDEAD3_1,
+S_FIRED_RDEAD3_2,
+S_FIRED_RDROP4,
+S_FIRED_RDEAD4_1,
+S_FIRED_RDEAD4_2,
+S_FIRED_RDROP5,
+S_FIRED_RDEAD5_1,
+S_FIRED_RDEAD5_2,
+S_FIRED_FX6_1,
+S_FIRED_FX6_2,
+S_FIRED_FX6_3,
+S_FIRED_FX6_4,
+S_FIRED_FX6_5,
+S_ICEGUY_LOOK,
+S_ICEGUY_DORMANT,
+S_ICEGUY_WALK1,
+S_ICEGUY_WALK2,
+S_ICEGUY_WALK3,
+S_ICEGUY_WALK4,
+S_ICEGUY_ATK1,
+S_ICEGUY_ATK2,
+S_ICEGUY_ATK3,
+S_ICEGUY_ATK4,
+S_ICEGUY_PAIN1,
+S_ICEGUY_DEATH,
+S_ICEGUY_FX1,
+S_ICEGUY_FX2,
+S_ICEGUY_FX3,
+S_ICEGUY_FX_X1,
+S_ICEGUY_FX_X2,
+S_ICEGUY_FX_X3,
+S_ICEGUY_FX_X4,
+S_ICEGUY_FX_X5,
+S_ICEFX_PUFF1,
+S_ICEFX_PUFF2,
+S_ICEFX_PUFF3,
+S_ICEFX_PUFF4,
+S_ICEFX_PUFF5,
+S_ICEGUY_FX2_1,
+S_ICEGUY_FX2_2,
+S_ICEGUY_FX2_3,
+S_ICEGUY_BIT1,
+S_ICEGUY_BIT2,
+S_ICEGUY_WISP1_1,
+S_ICEGUY_WISP1_2,
+S_ICEGUY_WISP1_3,
+S_ICEGUY_WISP1_4,
+S_ICEGUY_WISP1_5,
+S_ICEGUY_WISP1_6,
+S_ICEGUY_WISP1_7,
+S_ICEGUY_WISP1_8,
+S_ICEGUY_WISP1_9,
+S_ICEGUY_WISP2_1,
+S_ICEGUY_WISP2_2,
+S_ICEGUY_WISP2_3,
+S_ICEGUY_WISP2_4,
+S_ICEGUY_WISP2_5,
+S_ICEGUY_WISP2_6,
+S_ICEGUY_WISP2_7,
+S_ICEGUY_WISP2_8,
+S_ICEGUY_WISP2_9,
+S_FIGHTER,
+S_FIGHTER2,
+S_FIGHTERLOOK,
+S_FIGHTER_RUN1,
+S_FIGHTER_RUN2,
+S_FIGHTER_RUN3,
+S_FIGHTER_RUN4,
+S_FIGHTER_ATK1,
+S_FIGHTER_ATK2,
+S_FIGHTER_PAIN,
+S_FIGHTER_PAIN2,
+S_FIGHTER_DIE1,
+S_FIGHTER_DIE2,
+S_FIGHTER_DIE3,
+S_FIGHTER_DIE4,
+S_FIGHTER_DIE5,
+S_FIGHTER_DIE6,
+S_FIGHTER_DIE7,
+S_FIGHTER_XDIE1,
+S_FIGHTER_XDIE2,
+S_FIGHTER_XDIE3,
+S_FIGHTER_XDIE4,
+S_FIGHTER_XDIE5,
+S_FIGHTER_XDIE6,
+S_FIGHTER_XDIE7,
+S_FIGHTER_XDIE8,
+S_FIGHTER_ICE,
+S_FIGHTER_ICE2,
+S_CLERIC,
+S_CLERIC2,
+S_CLERICLOOK,
+S_CLERIC_RUN1,
+S_CLERIC_RUN2,
+S_CLERIC_RUN3,
+S_CLERIC_RUN4,
+S_CLERIC_ATK1,
+S_CLERIC_ATK2,
+S_CLERIC_ATK3,
+S_CLERIC_PAIN,
+S_CLERIC_PAIN2,
+S_CLERIC_DIE1,
+S_CLERIC_DIE2,
+S_CLERIC_DIE3,
+S_CLERIC_DIE4,
+S_CLERIC_DIE5,
+S_CLERIC_DIE6,
+S_CLERIC_DIE7,
+S_CLERIC_DIE8,
+S_CLERIC_DIE9,
+S_CLERIC_XDIE1,
+S_CLERIC_XDIE2,
+S_CLERIC_XDIE3,
+S_CLERIC_XDIE4,
+S_CLERIC_XDIE5,
+S_CLERIC_XDIE6,
+S_CLERIC_XDIE7,
+S_CLERIC_XDIE8,
+S_CLERIC_XDIE9,
+S_CLERIC_XDIE10,
+S_CLERIC_ICE,
+S_CLERIC_ICE2,
+S_MAGE,
+S_MAGE2,
+S_MAGELOOK,
+S_MAGE_RUN1,
+S_MAGE_RUN2,
+S_MAGE_RUN3,
+S_MAGE_RUN4,
+S_MAGE_ATK1,
+S_MAGE_ATK2,
+S_MAGE_PAIN,
+S_MAGE_PAIN2,
+S_MAGE_DIE1,
+S_MAGE_DIE2,
+S_MAGE_DIE3,
+S_MAGE_DIE4,
+S_MAGE_DIE5,
+S_MAGE_DIE6,
+S_MAGE_DIE7,
+S_MAGE_XDIE1,
+S_MAGE_XDIE2,
+S_MAGE_XDIE3,
+S_MAGE_XDIE4,
+S_MAGE_XDIE5,
+S_MAGE_XDIE6,
+S_MAGE_XDIE7,
+S_MAGE_XDIE8,
+S_MAGE_XDIE9,
+S_MAGE_ICE,
+S_MAGE_ICE2,
+S_SORC_SPAWN1,
+S_SORC_SPAWN2,
+S_SORC_LOOK1,
+S_SORC_WALK1,
+S_SORC_WALK2,
+S_SORC_WALK3,
+S_SORC_WALK4,
+S_SORC_PAIN1,
+S_SORC_PAIN2,
+S_SORC_ATK2_1,
+S_SORC_ATK2_2,
+S_SORC_ATK2_3,
+S_SORC_ATTACK1,
+S_SORC_ATTACK2,
+S_SORC_ATTACK3,
+S_SORC_ATTACK4,
+S_SORC_ATTACK5,
+S_SORC_DIE1,
+S_SORC_DIE2,
+S_SORC_DIE3,
+S_SORC_DIE4,
+S_SORC_DIE5,
+S_SORC_DIE6,
+S_SORC_DIE7,
+S_SORC_DIE8,
+S_SORC_DIE9,
+S_SORC_DIE0,
+S_SORC_DIEA,
+S_SORC_DIEB,
+S_SORC_DIEC,
+S_SORC_DIED,
+S_SORC_DIEE,
+S_SORC_DIEF,
+S_SORC_DIEG,
+S_SORC_DIEH,
+S_SORC_DIEI,
+S_SORCBALL1_1,
+S_SORCBALL1_2,
+S_SORCBALL1_3,
+S_SORCBALL1_4,
+S_SORCBALL1_5,
+S_SORCBALL1_6,
+S_SORCBALL1_7,
+S_SORCBALL1_8,
+S_SORCBALL1_9,
+S_SORCBALL1_0,
+S_SORCBALL1_A,
+S_SORCBALL1_B,
+S_SORCBALL1_C,
+S_SORCBALL1_D,
+S_SORCBALL1_E,
+S_SORCBALL1_F,
+S_SORCBALL1_D1,
+S_SORCBALL1_D2,
+S_SORCBALL1_D5,
+S_SORCBALL1_D6,
+S_SORCBALL1_D7,
+S_SORCBALL1_D8,
+S_SORCBALL1_D9,
+S_SORCBALL2_1,
+S_SORCBALL2_2,
+S_SORCBALL2_3,
+S_SORCBALL2_4,
+S_SORCBALL2_5,
+S_SORCBALL2_6,
+S_SORCBALL2_7,
+S_SORCBALL2_8,
+S_SORCBALL2_9,
+S_SORCBALL2_0,
+S_SORCBALL2_A,
+S_SORCBALL2_B,
+S_SORCBALL2_C,
+S_SORCBALL2_D,
+S_SORCBALL2_E,
+S_SORCBALL2_F,
+S_SORCBALL2_D1,
+S_SORCBALL2_D2,
+S_SORCBALL2_D5,
+S_SORCBALL2_D6,
+S_SORCBALL2_D7,
+S_SORCBALL2_D8,
+S_SORCBALL2_D9,
+S_SORCBALL3_1,
+S_SORCBALL3_2,
+S_SORCBALL3_3,
+S_SORCBALL3_4,
+S_SORCBALL3_5,
+S_SORCBALL3_6,
+S_SORCBALL3_7,
+S_SORCBALL3_8,
+S_SORCBALL3_9,
+S_SORCBALL3_0,
+S_SORCBALL3_A,
+S_SORCBALL3_B,
+S_SORCBALL3_C,
+S_SORCBALL3_D,
+S_SORCBALL3_E,
+S_SORCBALL3_F,
+S_SORCBALL3_D1,
+S_SORCBALL3_D2,
+S_SORCBALL3_D5,
+S_SORCBALL3_D6,
+S_SORCBALL3_D7,
+S_SORCBALL3_D8,
+S_SORCBALL3_D9,
+S_SORCFX1_1,
+S_SORCFX1_2,
+S_SORCFX1_3,
+S_SORCFX1_4,
+S_SORCFX1_D1,
+S_SORCFX1_D2,
+S_SORCFX1_D3,
+S_SORCFX2_SPLIT1,
+S_SORCFX2_ORBIT1,
+S_SORCFX2_ORBIT2,
+S_SORCFX2_ORBIT3,
+S_SORCFX2_ORBIT4,
+S_SORCFX2_ORBIT5,
+S_SORCFX2_ORBIT6,
+S_SORCFX2_ORBIT7,
+S_SORCFX2_ORBIT8,
+S_SORCFX2_ORBIT9,
+S_SORCFX2_ORBIT0,
+S_SORCFX2_ORBITA,
+S_SORCFX2_ORBITB,
+S_SORCFX2_ORBITC,
+S_SORCFX2_ORBITD,
+S_SORCFX2_ORBITE,
+S_SORCFX2_ORBITF,
+S_SORCFX2T1,
+S_SORCFX3_1,
+S_SORCFX3_2,
+S_SORCFX3_3,
+S_BISHMORPH1,
+S_BISHMORPHA,
+S_BISHMORPHB,
+S_BISHMORPHC,
+S_BISHMORPHD,
+S_BISHMORPHE,
+S_BISHMORPHF,
+S_BISHMORPHG,
+S_BISHMORPHH,
+S_BISHMORPHI,
+S_BISHMORPHJ,
+S_SORCFX3_EXP1,
+S_SORCFX3_EXP2,
+S_SORCFX3_EXP3,
+S_SORCFX3_EXP4,
+S_SORCFX3_EXP5,
+S_SORCFX4_1,
+S_SORCFX4_2,
+S_SORCFX4_3,
+S_SORCFX4_D1,
+S_SORCFX4_D2,
+S_SORCFX4_D3,
+S_SORCFX4_D4,
+S_SORCFX4_D5,
+S_SORCSPARK1,
+S_SORCSPARK2,
+S_SORCSPARK3,
+S_SORCSPARK4,
+S_SORCSPARK5,
+S_SORCSPARK6,
+S_SORCSPARK7,
+S_BLASTEFFECT1,
+S_BLASTEFFECT2,
+S_BLASTEFFECT3,
+S_BLASTEFFECT4,
+S_BLASTEFFECT5,
+S_BLASTEFFECT6,
+S_BLASTEFFECT7,
+S_BLASTEFFECT8,
+S_BLASTEFFECT9,
+S_WATERDRIP1,
+S_KORAX_LOOK1,
+S_KORAX_CHASE1,
+S_KORAX_CHASE2,
+S_KORAX_CHASE3,
+S_KORAX_CHASE4,
+S_KORAX_CHASE5,
+S_KORAX_CHASE6,
+S_KORAX_CHASE7,
+S_KORAX_CHASE8,
+S_KORAX_CHASE9,
+S_KORAX_CHASE0,
+S_KORAX_CHASEA,
+S_KORAX_CHASEB,
+S_KORAX_CHASEC,
+S_KORAX_CHASED,
+S_KORAX_CHASEE,
+S_KORAX_CHASEF,
+S_KORAX_PAIN1,
+S_KORAX_PAIN2,
+S_KORAX_ATTACK1,
+S_KORAX_ATTACK2,
+S_KORAX_MISSILE1,
+S_KORAX_MISSILE2,
+S_KORAX_MISSILE3,
+S_KORAX_COMMAND1,
+S_KORAX_COMMAND2,
+S_KORAX_COMMAND3,
+S_KORAX_COMMAND4,
+S_KORAX_COMMAND5,
+S_KORAX_DEATH1,
+S_KORAX_DEATH2,
+S_KORAX_DEATH3,
+S_KORAX_DEATH4,
+S_KORAX_DEATH5,
+S_KORAX_DEATH6,
+S_KORAX_DEATH7,
+S_KORAX_DEATH8,
+S_KORAX_DEATH9,
+S_KORAX_DEATH0,
+S_KORAX_DEATHA,
+S_KORAX_DEATHB,
+S_KORAX_DEATHC,
+S_KORAX_DEATHD,
+S_KSPIRIT_ROAM1,
+S_KSPIRIT_ROAM2,
+S_KSPIRIT_DEATH1,
+S_KSPIRIT_DEATH2,
+S_KSPIRIT_DEATH3,
+S_KSPIRIT_DEATH4,
+S_KSPIRIT_DEATH5,
+S_KSPIRIT_DEATH6,
+S_KBOLT1,
+S_KBOLT2,
+S_KBOLT3,
+S_KBOLT4,
+S_KBOLT5,
+S_KBOLT6,
+S_KBOLT7,
+S_SPAWNBATS1,
+S_SPAWNBATS2,
+S_SPAWNBATS3,
+S_SPAWNBATS_OFF,
+S_BAT1,
+S_BAT2,
+S_BAT3,
+S_BAT_DEATH,
+#ifdef ASSASSIN
+S_KATARREADY,
+S_KATARDOWN,
+S_KATARUP,
+S_KATARATK1_1,
+S_KATARATK1_2,
+S_KATARATK1_3,
+S_KATARATK1_4,
+S_KATARATK1_5,
+S_KATARATK2_1,
+S_KATARATK2_2,
+S_KATARATK2_3,
+S_KATARATK2_4,
+S_KATARATK2_5,
+S_KATARATK2_6,
+S_KATARATK2_7,
+S_KATARATK2_8,
+S_KATARATK2_9,
+S_ACROSSREADY,
+S_ACROSSREADY1,
+S_ACROSSREADY2,
+S_ACROSSREADY3,
+S_ACROSSREADY4,
+S_ACROSSREADY5,
+S_ACROSSREADY6,
+S_ACROSSREADY7,
+S_ACROSSREADY8,
+S_ACROSSREADY9,
+S_ACROSSBLINK1,
+S_ACROSSBLINK2,
+S_ACROSSBLINK3,
+S_ACROSSBLINK4,
+S_ACROSSBLINK5,
+S_ACROSSBLINK6,
+S_ACROSSBLINK7,
+S_ACROSSBLINK8,
+S_ACROSSBLINK9,
+S_ACROSSBLINK10,
+S_ACROSSBLINK11,
+S_ACROSSDOWN,
+S_ACROSSDOWN2,
+S_ACROSSDOWN3,
+S_ACROSSUP,
+S_ACROSSATK_1,
+S_ACROSSATK_2,
+S_ACROSSATK_3,
+S_ACROSSATK_4,
+S_ACROSSATK_5,
+S_ACROSSATK_6,
+/* S_ACROSSATK2_1, jim not used (melee attack) */
+S_ACROSS_MISSILE1,
+S_ACROSS_MISSILE2,
+S_ACROSS_MISSILE3,
+S_ACROSS_MISSILE4,
+S_ACROSS_MISSILE_X1,
+S_ACROSS_MISSILE_X2,
+S_ACROSS_MISSILE_X3,
+S_ACROSS_MISSILE_X4,
+S_AGRENREADY,
+S_AGRENDOWN,
+S_AGRENUP,
+S_AGRENATK_1,
+S_AGRENATK_2,
+S_AGRENATK_3,
+S_AGRENATK_4,
+S_AGRENPUFF1,
+S_AGRENPUFF2,
+S_AGRENPUFF3,
+S_AGRENPUFF4,
+S_AGRENPUFF5,
+S_AGRENSMOKE1,
+S_AGRENSMOKE2,
+S_AGRENSMOKE3,
+S_AGRENSMOKE4,
+S_AGREN_MISSILE1,
+S_AGREN_MISSILE2,
+S_ASTAFFREADY,
+/*S_ASTAFFREADY1, jim No such state! */
+S_ASTAFFREADY2,
+S_ASTAFFREADY3,
+S_ASTAFFREADY4,
+S_ASTAFFREADY5,
+S_ASTAFFREADY6,
+S_ASTAFFREADY7,
+S_ASTAFFREADY8,
+S_ASTAFFREADY9,
+S_ASTAFFREADY10,
+S_ASTAFFREADY11,
+S_ASTAFFREADY12,
+S_ASTAFFREADY13,
+S_ASTAFFREADY14,
+S_ASTAFFREADY15,
+S_ASTAFFREADY16,
+S_ASTAFFREADY17,
+S_ASTAFFREADY18,
+S_ASTAFFREADY19,
+S_ASTAFFREADY20,
+S_ASTAFFREADY21,
+S_ASTAFFREADY22,
+S_ASTAFFREADY23,
+S_ASTAFFREADY24,
+S_ASTAFFREADY25,
+S_ASTAFFREADY26,
+S_ASTAFFREADY27,
+S_ASTAFFREADY28,
+S_ASTAFFREADY29,
+S_ASTAFFREADY30,
+S_ASTAFFREADY31,
+S_ASTAFFREADY32,
+S_ASTAFFREADY33,
+S_ASTAFFREADY34,
+S_ASTAFFREADY35,
+S_ASTAFFDOWN,
+S_ASTAFFUP,
+S_ASTAFFATK_1,
+S_ASTAFFATK_2,
+S_ASTAFFATK_3,
+S_ASTAFFATK_4,
+S_ASTAFFATK_5,
+S_ASTAFFATK_6,
+S_ASTAFFATK_7,
+S_ASTAFF_FX1_1,
+S_ASTAFF_FX1_2,
+S_ASTAFF_FX1_3,
+S_ASTAFF_FX1_4,
+S_ASTAFF_FX1_5,
+S_ASTAFF_FX1_6,
+S_ASTAFF_FX_X1,
+S_ASTAFF_FX_X2,
+S_ASTAFF_FX_X3,
+S_ASTAFF_FX_X4,
+S_ASTAFF_FX_X5,
+S_ASTAFF_FX_X6,
+S_ASTAFF_FX_X7,
+S_ASTAFF_FX_X8,
+S_ASTAFF_FX_X9,
+S_ASTAFF_FX_X10,
+S_ASTAFF_FX2_1,
+S_ASTAFF_FX2_2,
+S_ASTAFF_FX2_3,
+S_ASTAFF_FX2_4,
+S_ASTAFF_FX2_X1,
+S_ASTAFF_FX2_X2,
+S_ASTAFF_FX2_X3,
+S_ASTAFF_FX2_X4,
+S_ASTAFF_FX2_X5,
+S_APLAY,
+S_APLAY_RUN1,
+S_APLAY_RUN2,
+S_APLAY_RUN3,
+S_APLAY_RUN4,
+S_APLAY_ATK1,
+S_APLAY_ATK2,
+S_APLAY_ATK3,
+S_APLAY_PAIN,
+S_APLAY_PAIN2,
+S_APLAY_DIE1,
+S_APLAY_DIE2,
+S_APLAY_DIE3,
+S_APLAY_DIE4,
+S_APLAY_DIE5,
+S_APLAY_DIE6,
+S_APLAY_DIE7,
+S_APLAY_DIE8,
+S_APLAY_DIE9,
+S_APLAY_XDIE1,
+S_APLAY_XDIE2,
+S_APLAY_XDIE3,
+S_APLAY_XDIE4,
+S_APLAY_XDIE5,
+S_APLAY_XDIE6,
+S_APLAY_XDIE7,
+S_APLAY_XDIE8,
+S_APLAY_XDIE9,
+S_APLAY_XDIE10,
+S_APLAY_ICE,
+S_APLAY_ICE2,
+#endif /* ASSASSIN */
+NUMSTATES
+} statenum_t;
+
+typedef struct
+{
+	spritenum_t	sprite;
+	int32_t			frame;
+	int32_t			tics;
+	void			(*action) (void*,void*);
+	statenum_t		nextstate;
+	int32_t			misc1, misc2;
+} state_t;
+
+extern state_t	states[NUMSTATES];
+extern const char *sprnames[NUMSPRITES];
+
+
+
+typedef enum {
+MT_MAPSPOT,
+MT_MAPSPOTGRAVITY,
+MT_FIREBALL1,
+MT_ARROW,
+MT_DART,
+MT_POISONDART,
+MT_RIPPERBALL,
+MT_PROJECTILE_BLADE,
+MT_ICESHARD,
+MT_FLAME_SMALL_TEMP,
+MT_FLAME_LARGE_TEMP,
+MT_FLAME_SMALL,
+MT_FLAME_LARGE,
+MT_HEALINGBOTTLE,
+MT_HEALTHFLASK,
+MT_ARTIFLY,
+MT_ARTIINVULNERABILITY,
+MT_SUMMONMAULATOR,
+MT_SUMMON_FX,
+MT_THRUSTFLOOR_UP,
+MT_THRUSTFLOOR_DOWN,
+MT_TELEPORTOTHER,
+MT_TELOTHER_FX1,
+MT_TELOTHER_FX2,
+MT_TELOTHER_FX3,
+MT_TELOTHER_FX4,
+MT_TELOTHER_FX5,
+MT_DIRT1,
+MT_DIRT2,
+MT_DIRT3,
+MT_DIRT4,
+MT_DIRT5,
+MT_DIRT6,
+MT_DIRTCLUMP,
+MT_ROCK1,
+MT_ROCK2,
+MT_ROCK3,
+MT_FOGSPAWNER,
+MT_FOGPATCHS,
+MT_FOGPATCHM,
+MT_FOGPATCHL,
+MT_QUAKE_FOCUS,
+MT_SGSHARD1,
+MT_SGSHARD2,
+MT_SGSHARD3,
+MT_SGSHARD4,
+MT_SGSHARD5,
+MT_SGSHARD6,
+MT_SGSHARD7,
+MT_SGSHARD8,
+MT_SGSHARD9,
+MT_SGSHARD0,
+MT_ARTIEGG,
+MT_EGGFX,
+MT_ARTISUPERHEAL,
+MT_ZWINGEDSTATUENOSKULL,
+MT_ZGEMPEDESTAL,
+MT_ARTIPUZZSKULL,
+MT_ARTIPUZZGEMBIG,
+MT_ARTIPUZZGEMRED,
+MT_ARTIPUZZGEMGREEN1,
+MT_ARTIPUZZGEMGREEN2,
+MT_ARTIPUZZGEMBLUE1,
+MT_ARTIPUZZGEMBLUE2,
+MT_ARTIPUZZBOOK1,
+MT_ARTIPUZZBOOK2,
+MT_ARTIPUZZSKULL2,
+MT_ARTIPUZZFWEAPON,
+MT_ARTIPUZZCWEAPON,
+MT_ARTIPUZZMWEAPON,
+MT_ARTIPUZZGEAR,
+MT_ARTIPUZZGEAR2,
+MT_ARTIPUZZGEAR3,
+MT_ARTIPUZZGEAR4,
+MT_ARTITORCH,
+MT_FIREBOMB,
+MT_ARTITELEPORT,
+MT_ARTIPOISONBAG,
+MT_POISONBAG,
+MT_POISONCLOUD,
+MT_THROWINGBOMB,
+MT_SPEEDBOOTS,
+MT_BOOSTMANA,
+MT_BOOSTARMOR,
+MT_BLASTRADIUS,
+MT_HEALRADIUS,
+MT_SPLASH,
+MT_SPLASHBASE,
+MT_LAVASPLASH,
+MT_LAVASMOKE,
+MT_SLUDGECHUNK,
+MT_SLUDGESPLASH,
+MT_MISC0,
+MT_MISC1,
+MT_MISC2,
+MT_MISC3,
+MT_MISC4,
+MT_MISC5,
+MT_MISC6,
+MT_MISC7,
+MT_MISC8,
+MT_TREEDESTRUCTIBLE,
+MT_MISC9,
+MT_MISC10,
+MT_MISC11,
+MT_MISC12,
+MT_MISC13,
+MT_MISC14,
+MT_MISC15,
+MT_MISC16,
+MT_MISC17,
+MT_MISC18,
+MT_MISC19,
+MT_MISC20,
+MT_MISC21,
+MT_MISC22,
+MT_MISC23,
+MT_MISC24,
+MT_MISC25,
+MT_MISC26,
+MT_MISC27,
+MT_MISC28,
+MT_MISC29,
+MT_MISC30,
+MT_MISC31,
+MT_MISC32,
+MT_MISC33,
+MT_MISC34,
+MT_MISC35,
+MT_MISC36,
+MT_MISC37,
+MT_MISC38,
+MT_MISC39,
+MT_MISC40,
+MT_MISC41,
+MT_MISC42,
+MT_MISC43,
+MT_MISC44,
+MT_MISC45,
+MT_MISC46,
+MT_MISC47,
+MT_MISC48,
+MT_MISC49,
+MT_MISC50,
+MT_MISC51,
+MT_MISC52,
+MT_MISC53,
+MT_MISC54,
+MT_MISC55,
+MT_MISC56,
+MT_MISC57,
+MT_MISC58,
+MT_MISC59,
+MT_MISC60,
+MT_MISC61,
+MT_MISC62,
+MT_MISC63,
+MT_MISC64,
+MT_MISC65,
+MT_MISC66,
+MT_MISC67,
+MT_MISC68,
+MT_MISC69,
+MT_MISC70,
+MT_MISC71,
+MT_MISC72,
+MT_MISC73,
+MT_MISC74,
+MT_MISC75,
+MT_MISC76,
+MT_POTTERY1,
+MT_POTTERY2,
+MT_POTTERY3,
+MT_POTTERYBIT1,
+MT_MISC77,
+MT_ZLYNCHED_NOHEART,
+MT_MISC78,
+MT_CORPSEBIT,
+MT_CORPSEBLOODDRIP,
+MT_BLOODPOOL,
+MT_MISC79,
+MT_MISC80,
+MT_LEAF1,
+MT_LEAF2,
+MT_ZTWINEDTORCH,
+MT_ZTWINEDTORCH_UNLIT,
+MT_BRIDGE,
+MT_BRIDGEBALL,
+MT_ZWALLTORCH,
+MT_ZWALLTORCH_UNLIT,
+MT_ZBARREL,
+MT_ZSHRUB1,
+MT_ZSHRUB2,
+MT_ZBUCKET,
+MT_ZPOISONSHROOM,
+MT_ZFIREBULL,
+MT_ZFIREBULL_UNLIT,
+MT_FIRETHING,
+MT_BRASSTORCH,
+MT_ZSUITOFARMOR,
+MT_ZARMORCHUNK,
+MT_ZBELL,
+MT_ZBLUE_CANDLE,
+MT_ZIRON_MAIDEN,
+MT_ZXMAS_TREE,
+MT_ZCAULDRON,
+MT_ZCAULDRON_UNLIT,
+MT_ZCHAINBIT32,
+MT_ZCHAINBIT64,
+MT_ZCHAINEND_HEART,
+MT_ZCHAINEND_HOOK1,
+MT_ZCHAINEND_HOOK2,
+MT_ZCHAINEND_SPIKE,
+MT_ZCHAINEND_SKULL,
+MT_TABLE_SHIT1,
+MT_TABLE_SHIT2,
+MT_TABLE_SHIT3,
+MT_TABLE_SHIT4,
+MT_TABLE_SHIT5,
+MT_TABLE_SHIT6,
+MT_TABLE_SHIT7,
+MT_TABLE_SHIT8,
+MT_TABLE_SHIT9,
+MT_TABLE_SHIT10,
+MT_TFOG,
+MT_MISC81,
+MT_TELEPORTMAN,
+MT_PUNCHPUFF,
+MT_FW_AXE,
+MT_AXEPUFF,
+MT_AXEPUFF_GLOW,
+MT_AXEBLOOD,
+MT_FW_HAMMER,
+MT_HAMMER_MISSILE,
+MT_HAMMERPUFF,
+MT_FSWORD_MISSILE,
+MT_FSWORD_FLAME,
+MT_CW_SERPSTAFF,
+MT_CSTAFF_MISSILE,
+MT_CSTAFFPUFF,
+MT_CW_FLAME,
+MT_CFLAMEFLOOR,
+MT_FLAMEPUFF,
+MT_FLAMEPUFF2,
+MT_CIRCLEFLAME,
+MT_CFLAME_MISSILE,
+MT_HOLY_FX,
+MT_HOLY_TAIL,
+MT_HOLY_PUFF,
+MT_HOLY_MISSILE,
+MT_HOLY_MISSILE_PUFF,
+MT_MWANDPUFF,
+MT_MWANDSMOKE,
+MT_MWAND_MISSILE,
+MT_MW_LIGHTNING,
+MT_LIGHTNING_CEILING,
+MT_LIGHTNING_FLOOR,
+MT_LIGHTNING_ZAP,
+MT_MSTAFF_FX,
+MT_MSTAFF_FX2,
+MT_FW_SWORD1,
+MT_FW_SWORD2,
+MT_FW_SWORD3,
+MT_CW_HOLY1,
+MT_CW_HOLY2,
+MT_CW_HOLY3,
+MT_MW_STAFF1,
+MT_MW_STAFF2,
+MT_MW_STAFF3,
+MT_SNOUTPUFF,
+MT_MW_CONE,
+MT_SHARDFX1,
+MT_BLOOD,
+MT_BLOODSPLATTER,
+MT_GIBS,
+MT_PLAYER_FIGHTER,
+MT_BLOODYSKULL,
+MT_PLAYER_SPEED,
+MT_ICECHUNK,
+MT_PLAYER_CLERIC,
+MT_PLAYER_MAGE,
+#ifdef ASSASSIN
+MT_PLAYER_ASS,
+#endif
+MT_PIGPLAYER,
+MT_PIG,
+MT_CENTAUR,
+MT_CENTAURLEADER,
+MT_CENTAUR_FX,
+MT_CENTAUR_SHIELD,
+MT_CENTAUR_SWORD,
+MT_DEMON,
+MT_DEMONCHUNK1,
+MT_DEMONCHUNK2,
+MT_DEMONCHUNK3,
+MT_DEMONCHUNK4,
+MT_DEMONCHUNK5,
+MT_DEMONFX1,
+MT_DEMON2,
+MT_DEMON2CHUNK1,
+MT_DEMON2CHUNK2,
+MT_DEMON2CHUNK3,
+MT_DEMON2CHUNK4,
+MT_DEMON2CHUNK5,
+MT_DEMON2FX1,
+MT_WRAITHB,
+MT_WRAITH,
+MT_WRAITHFX1,
+MT_WRAITHFX2,
+MT_WRAITHFX3,
+MT_WRAITHFX4,
+MT_WRAITHFX5,
+MT_MINOTAUR,
+MT_MNTRFX1,
+MT_MNTRFX2,
+MT_MNTRFX3,
+MT_MNTRSMOKE,
+MT_MNTRSMOKEEXIT,
+MT_SERPENT,
+MT_SERPENTLEADER,
+MT_SERPENTFX,
+MT_SERPENT_HEAD,
+MT_SERPENT_GIB1,
+MT_SERPENT_GIB2,
+MT_SERPENT_GIB3,
+MT_BISHOP,
+MT_BISHOP_PUFF,
+MT_BISHOPBLUR,
+MT_BISHOPPAINBLUR,
+MT_BISH_FX,
+MT_DRAGON,
+MT_DRAGON_FX,
+MT_DRAGON_FX2,
+MT_ARMOR_1,
+MT_ARMOR_2,
+MT_ARMOR_3,
+MT_ARMOR_4,
+MT_MANA1,
+MT_MANA2,
+MT_MANA3,
+MT_KEY1,
+MT_KEY2,
+MT_KEY3,
+MT_KEY4,
+MT_KEY5,
+MT_KEY6,
+MT_KEY7,
+MT_KEY8,
+MT_KEY9,
+MT_KEYA,
+MT_KEYB,
+MT_SOUNDWIND,
+MT_SOUNDWATERFALL,
+MT_ETTIN,
+MT_ETTIN_MACE,
+MT_FIREDEMON,
+MT_FIREDEMON_SPLOTCH1,
+MT_FIREDEMON_SPLOTCH2,
+MT_FIREDEMON_FX1,
+MT_FIREDEMON_FX2,
+MT_FIREDEMON_FX3,
+MT_FIREDEMON_FX4,
+MT_FIREDEMON_FX5,
+MT_FIREDEMON_FX6,
+MT_ICEGUY,
+MT_ICEGUY_FX,
+MT_ICEFX_PUFF,
+MT_ICEGUY_FX2,
+MT_ICEGUY_BIT,
+MT_ICEGUY_WISP1,
+MT_ICEGUY_WISP2,
+MT_FIGHTER_BOSS,
+MT_CLERIC_BOSS,
+MT_MAGE_BOSS,
+MT_SORCBOSS,
+MT_SORCBALL1,
+MT_SORCBALL2,
+MT_SORCBALL3,
+MT_SORCFX1,
+MT_SORCFX2,
+MT_SORCFX2_T1,
+MT_SORCFX3,
+MT_SORCFX3_EXPLOSION,
+MT_SORCFX4,
+MT_SORCSPARK1,
+MT_BLASTEFFECT,
+MT_WATER_DRIP,
+MT_KORAX,
+MT_KORAX_SPIRIT1,
+MT_KORAX_SPIRIT2,
+MT_KORAX_SPIRIT3,
+MT_KORAX_SPIRIT4,
+MT_KORAX_SPIRIT5,
+MT_KORAX_SPIRIT6,
+MT_DEMON_MASH,
+MT_DEMON2_MASH,
+MT_ETTIN_MASH,
+MT_CENTAUR_MASH,
+MT_KORAX_BOLT,
+MT_BAT_SPAWNER,
+MT_BAT,
+#ifdef ASSASSIN
+MT_AW_CROSSBOW,
+/* jim And its missiles! */
+MT_ACROSS_MISSILE,
+MT_AW_GRENADES,
+#endif
+NUMMOBJTYPES} mobjtype_t;
+
+typedef struct {
+	int	doomednum;
+	int	spawnstate;
+	int	spawnhealth;
+	int	seestate;
+	int	seesound;
+	int	reactiontime;
+	int	attacksound;
+	int	painstate;
+	int	painchance;
+	int	painsound;
+	int	meleestate;
+	int	missilestate;
+	int	crashstate;
+	int	deathstate;
+	int	xdeathstate;
+	int	deathsound;
+	int	speed;
+	int	radius;
+	int	height;
+	int	mass;
+	int	damage;
+	int	activesound;
+	int	flags;
+	int	flags2;
+} mobjinfo_t;
+
+extern mobjinfo_t mobjinfo[NUMMOBJTYPES];
+
+#endif	/* __INFO_H */
+
--- /dev/null
+++ b/m_bams.h
@@ -1,0 +1,45 @@
+//**************************************************************************
+//**
+//** m_bams.h
+//**
+//** $Revision: 396 $
+//** $Date: 2009-05-21 12:32:55 +0300 (Thu, 21 May 2009) $
+//**
+//**************************************************************************
+
+#ifndef __MY_BAMS_MATH_H__
+#define __MY_BAMS_MATH_H__
+
+typedef unsigned short	binangle;
+
+/* Some predefined angles */
+#define	BANG_0		0		/* To the east.		*/
+#define BANG_45		0x2000		/* To the northeast.	*/
+#define BANG_90		0x4000		/* To the north.	*/
+#define BANG_135	0x6000		/* To the northwest.	*/
+#define BANG_180	0x8000		/* To the west.		*/
+#define BANG_225	0xa000		/* To the southwest.	*/
+#define BANG_270	0xc000		/* To the south.	*/
+#define BANG_315	0xe000		/* To the southeast.	*/
+#define BANG_360	0x10000		/* The same as angle 0.	*/
+#define BANG_MAX	0xffff		/* The largest possible angle.	*/
+
+/* Compass directions, for convenience. */
+#define BANG_EAST	BANG_0
+#define BANG_NORTHEAST	BANG_45
+#define BANG_NORTH	BANG_90
+#define BANG_NORTHWEST	BANG_135
+#define BANG_WEST	BANG_180
+#define BANG_SOUTHWEST	BANG_225
+#define BANG_SOUTH	BANG_270
+#define BANG_SOUTHEAST	BANG_315
+
+#define BAMS_PI		3.14159265359
+#define RAD2BANG(x)	((binangle)((x)/BAMS_PI*BANG_180))
+#define BANG2RAD(x)	((float)((x)/(float)BANG_180*BAMS_PI))
+
+void bamsInit(void);	/* Fill in the tables */
+binangle bamsAtan2(int y,int x);
+
+#endif	/* __MY_BAMS_MATH_H__ */
+
--- /dev/null
+++ b/m_misc.c
@@ -1,0 +1,799 @@
+
+//**************************************************************************
+//**
+//** m_misc.c : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 560 $
+//** $Date: 2010-10-20 15:15:39 +0300 (Wed, 20 Oct 2010) $
+//**
+//**************************************************************************
+
+// HEADER FILES ------------------------------------------------------------
+
+#include "h2stdinc.h"
+#include <ctype.h>
+#include "h2def.h"
+#include "p_local.h"
+#include "i_cdmus.h"
+#include "soundst.h"
+#ifdef __WATCOMC__
+#include "i_sound.h"
+#endif
+#ifdef RENDER3D
+#include "ogl_def.h"
+#endif
+
+// MACROS ------------------------------------------------------------------
+
+#define MALLOC_CLIB	1
+#define MALLOC_ZONE	2
+
+// TYPES -------------------------------------------------------------------
+
+// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
+
+// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
+
+// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
+
+static int __ReadFile(char const *name, void **buffer, int mallocType);
+
+// EXTERNAL DATA DECLARATIONS ----------------------------------------------
+
+// PUBLIC DATA DEFINITIONS -------------------------------------------------
+
+int		myargc;
+const char	**myargv;
+
+// PRIVATE DATA DEFINITIONS ------------------------------------------------
+
+// CODE --------------------------------------------------------------------
+
+//==========================================================================
+//
+// M_CheckParm
+//
+// Checks for the given parameter in the program's command line arguments.
+// Returns the argument number (1 to argc-1) or 0 if not present.
+//
+//==========================================================================
+
+int M_CheckParm(const char *check)
+{
+	int i;
+
+	for (i = 1; i < myargc; i++)
+	{
+		if (!strcmp(check, myargv[i]))
+		{
+			return i;
+		}
+	}
+	return 0;
+}
+
+//==========================================================================
+//
+// M_ParmExists
+//
+// Returns true if the given parameter exists in the program's command
+// line arguments, false if not.
+//
+//==========================================================================
+
+boolean M_ParmExists(const char *check)
+{
+	return M_CheckParm(check) != 0 ? true : false;
+}
+
+//==========================================================================
+//
+// M_ExtractFileBase
+//
+//==========================================================================
+
+void M_ExtractFileBase(const char *path, char *dest)
+{
+	const char *src;
+	int length;
+
+	src = path + strlen(path) - 1;
+	if (src <= path)
+	{
+		*dest = '\0';
+		return;
+	}
+
+	// Back up until a \ or the start
+	while (src != path && src[-1] != '/' && src[-1] != '\\')
+		src--;
+
+	// Copy up to eight characters
+	memset(dest, 0, 8);
+	length = 0;
+	while (*src && *src != '.')
+	{
+		if (++length == 9)
+		{
+			I_Error("Filename base of %s > 8 chars", path);
+		}
+		*dest++ = toupper((int)*src++);
+	}
+}
+
+/*
+===============
+=
+= M_Random
+=
+= Returns a 0-255 number
+=
+===============
+*/
+
+// This is the new flat distribution table
+unsigned char rndtable[256] =
+{
+	201,  1,243, 19, 18, 42,183,203,101,123,154,137, 34,118, 10,216,
+	135,246,  0,107,133,229, 35,113,177,211,110, 17,139, 84,251,235,
+	182,166,161,230,143, 91, 24, 81, 22, 94,  7, 51,232,104,122,248,
+	175,138,127,171,222,213, 44, 16,  9, 33, 88,102,170,150,136,114,
+	 62,  3,142,237,  6,252,249, 56, 74, 30, 13, 21,180,199, 32,132,
+	187,234, 78,210, 46,131,197,  8,206,244, 73,  4,236,178,195, 70,
+	121, 97,167,217,103, 40,247,186,105, 39, 95,163, 99,149,253, 29,
+	119, 83,254, 26,202, 65,130,155, 60, 64,184,106,221, 93,164,196,
+	112,108,179,141, 54,109, 11,126, 75,165,191,227, 87,225,156, 15,
+	 98,162,116, 79,169,140,190,205,168,194, 41,250, 27, 20, 14,241,
+	 50,214, 72,192,220,233, 67,148, 96,185,176,181,215,207,172, 85,
+	 89, 90,209,128,124,  2, 55,173, 66,152, 47,129, 59, 43,159,240,
+	239, 12,189,212,144, 28,200, 77,219,198,134,228, 45, 92,125,151,
+	  5, 53,255, 52, 68,245,160,158, 61, 86, 58, 82,117, 37,242,145,
+	 69,188,115, 76, 63,100, 49,111,153, 80, 38, 57,174,224, 71,231,
+	 23, 25, 48,218,120,147,208, 36,226,223,193,238,157,204,146, 31
+};
+
+int rndindex = 0;
+int prndindex = 0;
+
+unsigned char P_Random (void)
+{
+	prndindex = (prndindex + 1) & 0xff;
+	return rndtable[prndindex];
+}
+
+int M_Random (void)
+{
+	rndindex = (rndindex + 1) & 0xff;
+	return rndtable[rndindex];
+}
+
+void M_ClearRandom (void)
+{
+	rndindex = prndindex = 0;
+}
+
+
+void M_ClearBox (fixed_t *box)
+{
+	box[BOXTOP] = box[BOXRIGHT] = H2MININT;
+	box[BOXBOTTOM] = box[BOXLEFT] = H2MAXINT;
+}
+
+void M_AddToBox (fixed_t *box, fixed_t x, fixed_t y)
+{
+	if (x < box[BOXLEFT])
+		box[BOXLEFT] = x;
+	else if (x > box[BOXRIGHT])
+		box[BOXRIGHT] = x;
+	if (y < box[BOXBOTTOM])
+		box[BOXBOTTOM] = y;
+	else if (y > box[BOXTOP])
+		box[BOXTOP] = y;
+}
+
+/*
+==================
+=
+= M_WriteFile
+=
+==================
+*/
+
+boolean M_WriteFile (char const *name, const void *source, int length)
+{
+	int handle, count;
+
+	handle = create (name, OWRITE, 0666);
+	if (handle < 0)
+		return false;
+	count = write (handle, source, length);
+	close (handle);
+
+	if (count < length)
+		return false;
+
+	return true;
+}
+
+//==========================================================================
+//
+// M_ReadFile
+//
+// Read a file into a buffer allocated using Z_Malloc().
+//
+//==========================================================================
+
+int M_ReadFile(char const *name, void **buffer)
+{
+	return __ReadFile(name, buffer, MALLOC_ZONE);
+}
+
+//==========================================================================
+//
+// M_ReadFileCLib
+//
+// Read a file into a buffer allocated using malloc().
+//
+//==========================================================================
+
+int M_ReadFileCLib(char const *name, void **buffer)
+{
+	return __ReadFile(name, buffer, MALLOC_CLIB);
+}
+
+//==========================================================================
+//
+// ReadFile
+//
+//==========================================================================
+
+static int __ReadFile(char const *name, void **buffer, int mallocType)
+{
+	int handle, count, length;
+	struct stat fileinfo;
+	void *buf;
+	Dir *d;
+
+	handle = open(name, OREAD);
+	if (handle == -1)
+	{
+		I_Error("Couldn't read file %s", name);
+	}
+	d = dirfstat(handle);
+	if (d == nil)
+	{
+		I_Error("Couldn't read file %s", name);
+	}
+	length = d->length;
+	free(d);
+	if (mallocType == MALLOC_ZONE)
+	{ // Use zone memory allocation
+		buf = Z_Malloc(length, PU_STATIC, NULL);
+	}
+	else
+	{ // Use c library memory allocation
+		buf = malloc(length);
+		if (buf == NULL)
+		{
+			I_Error("Couldn't malloc buffer %d for file %s.",
+				length, name);
+		}
+	}
+	count = read(handle, buf, length);
+	close(handle);
+	if (count < length)
+	{
+		I_Error("Couldn't read file %s", name);
+	}
+	*buffer = buf;
+	return length;
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC M_FindResponseFile
+//
+//---------------------------------------------------------------------------
+
+#define MAXARGVS	100
+
+void M_FindResponseFile(void)
+{
+	int i;
+
+	for (i = 1; i < myargc; i++)
+	{
+		if (myargv[i][0] == '@')
+		{
+			FILE *handle;
+			int size, k, idx;
+			int indexinfile;
+			char *infile;
+			char *file;
+			const char *moreargs[20];
+			const char *firstargv;
+
+			// READ THE RESPONSE FILE INTO MEMORY
+			handle = fopen(&myargv[i][1], "rb");
+			if (!handle)
+			{
+				printf("\nNo such response file!");
+				exits("No such response file!");
+			}
+			ST_Message("Found response file %s!\n",&myargv[i][1]);
+			fseek (handle, 0, SEEK_END);
+			size = ftell(handle);
+			fseek (handle, 0, SEEK_SET);
+			file = (char *) malloc (size);
+			fread (file, size, 1, handle);
+			fclose (handle);
+
+			// KEEP ALL CMDLINE ARGS FOLLOWING @RESPONSEFILE ARG
+			for (idx = 0, k = i + 1; k < myargc; k++)
+				moreargs[idx++] = myargv[k];
+
+			firstargv = myargv[0];
+			myargv = (const char **) calloc(1, sizeof(char *) * MAXARGVS);
+			myargv[0] = firstargv;
+
+			infile = file;
+			indexinfile = k = 0;
+			indexinfile++;	// SKIP PAST ARGV[0] (KEEP IT)
+			do
+			{
+				myargv[indexinfile++] = infile + k;
+				while (k < size && ((*(infile + k) >= ' ' + 1) && (*(infile + k) <= 'z')))
+					k++;
+				*(infile + k) = 0;
+				while (k < size && ((*(infile + k) <= ' ') || (*(infile + k) > 'z')))
+					k++;
+			} while (k < size);
+
+			for (k = 0; k < idx; k++)
+				myargv[indexinfile++] = moreargs[k];
+			myargc = indexinfile;
+			// DISPLAY ARGS
+			if (M_CheckParm("-debug"))
+			{
+				ST_Message("%d command-line args:\n", myargc);
+				for (k = 1; k < myargc; k++)
+				{
+					ST_Message("%s\n", myargv[k]);
+				}
+			}
+			break;
+		}
+	}
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC M_ForceUppercase
+//
+// Change string to uppercase.
+//
+//---------------------------------------------------------------------------
+
+void M_ForceUppercase(char *text)
+{
+	char c;
+
+	while ((c = *text) != 0)
+	{
+		if (c >= 'a' && c <= 'z')
+		{
+			*text++ = c-('a'-'A');
+		}
+		else
+		{
+			text++;
+		}
+	}
+}
+
+/*
+==============================================================================
+
+							DEFAULTS
+
+==============================================================================
+*/
+
+int	usemouse;
+int	usejoystick;
+
+int	mouseSensitivity;
+
+extern int mouselook;
+extern int alwaysrun;
+
+extern int key_right, key_left, key_up, key_down;
+extern int key_strafeleft, key_straferight, key_jump;
+extern int key_fire, key_use, key_strafe, key_speed;
+extern int key_flyup, key_flydown, key_flycenter;
+extern int key_lookup, key_lookdown, key_lookcenter;
+extern int key_invleft, key_invright, key_useartifact;
+
+extern int mousebfire;
+extern int mousebstrafe;
+extern int mousebforward;
+extern int mousebjump;
+
+extern int joybfire;
+extern int joybstrafe;
+extern int joybuse;
+extern int joybspeed;
+extern int joybjump;
+
+extern int messageson;
+
+extern int viewwidth, viewheight;
+
+extern int screenblocks;
+
+extern int snd_Channels;
+#ifdef __WATCOMC__
+extern int snd_DesiredMusicDevice, snd_DesiredSfxDevice;
+extern int snd_MusicDevice,	// current music card # (index to dmxCodes)
+	   snd_SfxDevice;	// current sfx card # (index to dmxCodes)
+
+extern int snd_SBport, snd_SBirq, snd_SBdma;	// sound blaster variables
+extern int snd_Mport;				// midi variables
+#endif	/* DOS vars */
+
+default_t defaults[] =
+{
+/* change of order here affects mn_menu.c :
+ * see, for example, Options3Items there...
+ */
+	{ "mouse_sensitivity",	&mouseSensitivity,	5,	0, 50 },
+	{ "sfx_volume",		&snd_MaxVolume,		10,	0, 15 },
+	{ "music_volume",	&snd_MusicVolume,	10,	0, 15 },
+
+	{ "key_right",		&key_right,		KEY_RIGHTARROW,	0, 254 },
+	{ "key_left",		&key_left,		KEY_LEFTARROW,	0, 254 },
+	{ "key_up",		&key_up,		KEY_UPARROW,	0, 254 },
+	{ "key_down",		&key_down,		KEY_DOWNARROW,	0, 254 },
+	{ "key_strafeleft",	&key_strafeleft,	',',		0, 254 },
+	{ "key_straferight",	&key_straferight,	'.',		0, 254 },
+	{ "key_flyup",		&key_flyup,		KEY_PGUP,	0, 254 },
+	{ "key_flydown",	&key_flydown,		KEY_INS,	0, 254 },
+	{ "key_flycenter",	&key_flycenter,		KEY_HOME,	0, 254 },
+	{ "key_lookup",		&key_lookup,		KEY_PGDN,	0, 254 },
+	{ "key_lookdown",	&key_lookdown,		KEY_DEL,	0, 254 },
+	{ "key_lookcenter",	&key_lookcenter,	KEY_END,	0, 254 },
+	{ "key_invleft",	&key_invleft,		'[',		0, 254 },
+	{ "key_invright",	&key_invright,		']',		0, 254 },
+	{ "key_useartifact",	&key_useartifact,	KEY_ENTER,	0, 254 },
+	{ "key_fire",		&key_fire,		KEY_RCTRL,	0, 254 },
+	{ "key_use",		&key_use,		' ',		0, 254 },
+	{ "key_strafe",		&key_strafe,		KEY_RALT,	0, 254 },
+	{ "key_speed",		&key_speed,		KEY_RSHIFT,	0, 254 },
+	{ "key_jump",		&key_jump,		'/',		0, 254 },
+
+	{ "use_mouse",		&usemouse,		1,	0, 1 },
+	{ "mouseb_fire",	&mousebfire,		0,	-1, 2 },
+	{ "mouseb_strafe",	&mousebstrafe,		1,	-1, 2 },
+	{ "mouseb_forward",	&mousebforward,		2,	-1, 2 },
+	{ "mouseb_jump",	&mousebjump,		-1,	-1, 2 },
+
+	{ "use_joystick",	&usejoystick,		0,	0, 1 },
+	{ "joyb_fire",		&joybfire,		0,	-1, 3 },
+	{ "joyb_strafe",	&joybstrafe,		1,	-1, 3 },
+	{ "joyb_use",		&joybuse,		3,	-1, 3 },
+	{ "joyb_speed",		&joybspeed,		2,	-1, 3 },
+	{ "joyb_jump",		&joybjump,		-1,	-1, 3 },
+
+	{ "screenblocks",	&screenblocks,		10,	3, 11 },
+	{ "usegamma",		&usegamma,		0,	0, 4 },
+	{ "messageson",		&messageson,		1,	0, 1 },
+	{ "mouselook",		&mouselook,		1,	0, 2 },
+	{ "cdaudio",		&cdaudio,		0,	0, 1 },
+	{ "alwaysrun",		&alwaysrun,		0,	0, 1 },
+
+	{ "snd_channels",	&snd_Channels,		3,	3, MAX_CHANNELS },
+#ifdef __WATCOMC__
+	/* the min/max values I added here are pretty much meaningless.
+	the values used to be set by the DOS version's setup program. */
+	{ "snd_musicdevice",	&snd_DesiredMusicDevice,0,	0, NUM_SCARDS-1 },
+	{ "snd_sfxdevice",	&snd_DesiredSfxDevice,	0,	0, NUM_SCARDS-1 },
+	{ "snd_sbport",		&snd_SBport,		544,	0, 544 },
+	{ "snd_sbirq",		&snd_SBirq,		-1,	-1, 7 },
+	{ "snd_sbdma",		&snd_SBdma,		-1,	-1, 7 },
+	{ "snd_mport",		&snd_Mport,		-1,	-1, 360 }
+#endif	/* DOS vars */
+};
+
+default_str_t default_strings[] =
+{
+	{ "chatmacro0", chat_macros[0] },
+	{ "chatmacro1", chat_macros[1] },
+	{ "chatmacro2", chat_macros[2] },
+	{ "chatmacro3", chat_macros[3] },
+	{ "chatmacro4", chat_macros[4] },
+	{ "chatmacro5", chat_macros[5] },
+	{ "chatmacro6", chat_macros[6] },
+	{ "chatmacro7", chat_macros[7] },
+	{ "chatmacro8", chat_macros[8] },
+	{ "chatmacro9", chat_macros[9] }
+};
+
+static int numdefaults, numstrings;
+static char defaultfile[MAX_OSPATH];
+
+/*
+==============
+=
+= M_SaveDefaults
+=
+==============
+*/
+
+void M_SaveDefaults (void)
+{
+	int	i,v;
+	FILE	*f;
+
+	f = fopen (defaultfile, "w");
+	if (!f)
+		return;	// can't write the file, but don't complain
+
+	for (i = 0; i < numdefaults; i++)
+	{
+		v = *defaults[i].location;
+		fprintf (f, "%s\t\t%i\n", defaults[i].name, v);
+	}
+
+	for (i = 0; i < numstrings; i++)
+	{
+		fprintf (f, "%s\t\t\"%s\"\n", default_strings[i].name,
+					default_strings[i].location);
+	}
+
+	fclose (f);
+}
+
+//==========================================================================
+//
+// M_LoadDefaults
+//
+//==========================================================================
+
+void M_LoadDefaults(const char *fileName)
+{
+	int i;
+	int len;
+	FILE *f;
+	char def[80];
+	char strparm[100];
+	int parm;
+
+	numdefaults = sizeof(defaults) / sizeof(defaults[0]);
+	numstrings = sizeof(default_strings) / sizeof(default_strings[0]);
+	ST_Message("Loading default settings\n");
+	// Set everything to base values
+	for (i = 0; i < numdefaults; i++)
+	{
+		*defaults[i].location = defaults[i].defaultvalue;
+	}
+	// Make a backup of all default strings
+	for (i = 0; i < numstrings; i++)
+	{
+		default_strings[i].defaultvalue = (char *) calloc(1, 80);
+		strcpy (default_strings[i].defaultvalue, default_strings[i].location);
+	}
+
+	// Check for a custom config file
+	i = M_CheckParm("-config");
+	if (i && i < myargc-1)
+	{
+		snprintf(defaultfile, sizeof(defaultfile), "%s%s", basePath, myargv[i + 1]);
+		ST_Message("config file: %s\n", defaultfile);
+	}
+	else
+	{
+		snprintf(defaultfile, sizeof(defaultfile), "%s%s", basePath, fileName);
+	}
+
+	// Scan the config file
+	f = fopen(defaultfile, "r");
+	if (f)
+	{
+		while (!feof(f))
+		{
+			if (fscanf(f, "%79s %[^\n]\n", def, strparm) == 2)
+			{
+				if (strparm[0] == '"') /* string values */
+				{
+					for (i = 0; i < numstrings; i++)
+					{
+						if (!strcmp(def, default_strings[i].name))
+						{
+							len = (int)strlen(strparm) - 2;
+							if (len <= 0)
+							{
+								default_strings[i].location[0] = '\0';
+								break;
+							}
+							if (len > 79)
+							{
+								len = 79;
+							}
+							strncpy(default_strings[i].location, strparm + 1, len);
+							default_strings[i].location[len] = '\0';
+							break;
+						}
+					}
+					continue;
+				}
+
+				/* numeric values */
+				if (strparm[0] == '0' && strparm[1] == 'x')
+				{
+					sscanf(strparm + 2, "%x", &parm);
+				}
+				else
+				{
+					sscanf(strparm, "%i", &parm);
+				}
+				for (i = 0; i < numdefaults; i++)
+				{
+					if (!strcmp(def, defaults[i].name))
+					{
+						if (parm >= defaults[i].minvalue && parm <= defaults[i].maxvalue)
+							*defaults[i].location = parm;
+						break;
+					}
+				}
+			}
+		}
+		fclose (f);
+	}
+}
+
+
+/*
+==============================================================================
+
+						SCREEN SHOTS
+
+==============================================================================
+*/
+
+typedef struct
+{
+	char	manufacturer;
+	char	version;
+	char	encoding;
+	char	bits_per_pixel;
+	unsigned short	xmin,ymin,xmax,ymax;
+	unsigned short	hres,vres;
+	unsigned char	palette[48];
+	char	reserved;
+	char	color_planes;
+	unsigned short	bytes_per_line;
+	unsigned short	palette_type;
+	char	filler[58];
+	unsigned char	data;	// unbounded
+} pcx_t;
+
+/*
+==============
+=
+= WritePCXfile
+=
+==============
+*/
+
+void WritePCXfile (const char *filename, byte *data, int width, int height, byte *palette)
+{
+	int	i, length;
+	pcx_t	*pcx;
+	byte	*pack;
+
+	pcx = (pcx_t *) Z_Malloc (width*height*2 + 1000, PU_STATIC, NULL);
+
+	pcx->manufacturer = 0x0a;	// PCX id
+	pcx->version = 5;		// 256 color
+	pcx->encoding = 1;		// uncompressed
+	pcx->bits_per_pixel = 8;	// 256 color
+	pcx->xmin = 0;
+	pcx->ymin = 0;
+	pcx->xmax = SHORT(width - 1);
+	pcx->ymax = SHORT(height - 1);
+	pcx->hres = SHORT(width);
+	pcx->vres = SHORT(height);
+	memset (pcx->palette, 0, sizeof(pcx->palette));
+	pcx->color_planes = 1;		// chunky image
+	pcx->bytes_per_line = SHORT(width);
+	pcx->palette_type = SHORT(2);	// not a grey scale
+	memset (pcx->filler, 0, sizeof(pcx->filler));
+
+//
+// pack the image
+//
+	pack = &pcx->data;
+
+	for (i = 0; i < width*height; i++)
+	{
+		if ((*data & 0xc0) != 0xc0)
+			*pack++ = *data++;
+		else
+		{
+			*pack++ = 0xc1;
+			*pack++ = *data++;
+		}
+	}
+
+//
+// write the palette
+//
+	*pack++ = 0x0c;		// palette ID byte
+	for (i = 0; i < 768; i++)
+		*pack++ = *palette++;
+
+//
+// write output file
+//
+	length = pack - (byte *)pcx;
+	M_WriteFile (filename, pcx, length);
+
+	Z_Free (pcx);
+}
+
+
+//==============================================================================
+
+/*
+==================
+=
+= M_ScreenShot
+=
+==================
+*/
+#ifdef RENDER3D
+void M_ScreenShot (void)
+{
+	OGL_GrabScreen();
+}
+#else
+void M_ScreenShot (void)
+{
+	int	i;
+	byte	*linear;
+	char	lbmname[MAX_OSPATH], *p;
+	byte	*pal;
+
+//
+// munge planar buffer to linear
+// 
+	linear = screen;
+//
+// find a file name to save it to
+//
+	snprintf (lbmname, sizeof(lbmname), "%shexen00.pcx", basePath);
+	p = lbmname + strlen(basePath);
+	for (i = 0; i <= 99; i++)
+	{
+		p[5] = i/10 + '0';
+		p[6] = i%10 + '0';
+		if (access(lbmname, AEXIST) == -1)
+			break;	// file doesn't exist
+	}
+	if (i == 100)
+	{
+		P_SetMessage(&players[consoleplayer], "SCREEN SHOT FAILED", false);
+		return;
+	}
+
+//
+// save the pcx file
+//
+	pal = (byte *)W_CacheLumpName("PLAYPAL", PU_CACHE);
+
+	WritePCXfile (lbmname, linear, SCREENWIDTH, SCREENHEIGHT, pal);
+
+	P_SetMessage(&players[consoleplayer], "SCREEN SHOT", false);
+}
+#endif
+
--- /dev/null
+++ b/mkfile
@@ -1,0 +1,60 @@
+</$objtype/mkfile
+
+BIN=/$objtype/bin
+TARG=hexen
+CFLAGS=-Fpw
+
+OFILES=\
+	am_map.$O \
+	a_action.$O \
+	ct_chat.$O \
+	d_net.$O \
+	f_finale.$O \
+	g_game.$O \
+	h2_main.$O \
+	h_hubmsg.$O \
+	info.$O \
+	in_lude.$O \
+	mn_menu.$O \
+	m_misc.$O \
+	p_acs.$O \
+	p_anim.$O \
+	p_ceilng.$O \
+	p_doors.$O \
+	p_enemy.$O \
+	p_floor.$O \
+	p_inter.$O \
+	p_lights.$O \
+	p_map.$O \
+	p_maputl.$O \
+	p_mobj.$O \
+	p_plats.$O \
+	p_pspr.$O \
+	p_setup.$O \
+	p_sight.$O \
+	p_spec.$O \
+	p_switch.$O \
+	p_telept.$O \
+	p_tick.$O \
+	p_things.$O \
+	p_user.$O \
+	po_man.$O \
+	r_bsp.$O \
+	r_data.$O \
+	r_draw.$O \
+	r_main.$O \
+	r_plane.$O \
+	r_segs.$O \
+	r_things.$O \
+	sb_bar.$O \
+	sc_man.$O \
+	s_sound.$O \
+	sn_sonix.$O \
+	st_start.$O \
+	sv_save.$O \
+	tables.$O \
+	v_video.$O \
+	w_wad.$O \
+	z_zone.$O
+
+</sys/src/cmd/mkone
--- /dev/null
+++ b/mmus2mid.c
@@ -1,0 +1,852 @@
+/* $Id: mmus2mid.c 543 2010-01-11 18:44:55Z sezero $
+ *
+ *  Ripped && Adapted from the PrBoom project:
+ *  PrBoom: a Doom port merged with LxDoom and LSDLDoom
+ *  based on BOOM, a modified and improved DOOM engine
+ *  Copyright (C) 1999 by
+ *  id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
+ *  Copyright (C) 1999-2000 by
+ *  Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
+ *  Copyright 2005, 2006 by
+ *  Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version 2
+ *  of the License, or (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ *  02110-1301  USA.
+ *
+ * DESCRIPTION:
+ *  This file supports conversion of MUS format music in memory
+ *  to MIDI format 1 music in memory.
+ *
+ *  The primary routine, mmus2mid, converts a block of memory in MUS format
+ *  to an Allegro MIDI structure. This supports playing MUS lumps in a wad
+ *  file with BOOM.
+ *
+ *  Another routine, Midi2MIDI, converts a block of memory in MIDI format 1 to
+ *  an Allegro MIDI structure. This supports playing MIDI lumps in a wad
+ *  file with BOOM.
+ *
+ *  For testing purposes, and to make a utility if desired, if the symbol
+ *  STANDALONE is defined by uncommenting the definition below, a main
+ *  routine is compiled that will convert a possibly wildcarded set of MUS
+ *  files to a similarly named set of MIDI files.
+ *
+ *  Much of the code here is thanks to S. Bacquet's source for QMUS2MID.C
+ *
+ */
+
+
+#include "h2stdinc.h"
+#include <sys/stat.h>
+#ifdef MSDOS
+#include <allegro.h>
+#endif /* !MSDOS */
+#include "h2def.h"
+#include "mmus2mid.h"
+
+//#define STANDALONE  /* uncomment this to make MMUS2MID.EXE */
+
+// some macros to decode mus event bit fields
+
+#define last(e)         ((uint8_t)((e) & 0x80))
+#define event_type(e)   ((uint8_t)(((e) & 0x7F) >> 4))
+#define channel(e)      ((uint8_t)((e) & 0x0F))
+
+// event types
+
+typedef enum
+{
+  RELEASE_NOTE,
+  PLAY_NOTE,
+  BEND_NOTE,
+  SYS_EVENT,
+  CNTL_CHANGE,
+  UNKNOWN_EVENT1,
+  SCORE_END,
+  UNKNOWN_EVENT2,
+} mus_event_t;
+
+// MUS format header structure
+
+typedef struct
+{
+  char        ID[4];            // identifier "MUS"0x1A
+  uint16_t       ScoreLength;      // length of music portion
+  uint16_t       ScoreStart;       // offset of music portion
+  uint16_t       channels;         // count of primary channels
+  uint16_t       SecChannels;      // count of secondary channels
+  uint16_t       InstrCnt;         // number of instruments
+} __attribute__((__packed__)) MUSheader;
+
+// to keep track of information in a MIDI track
+
+typedef struct Track
+{
+  char  velocity;
+  int32_t deltaT;
+  uint8_t   lastEvt;
+  uint32_t alloced;
+} TrackInfo;
+
+// array of info about tracks
+
+static TrackInfo track[MIDI_TRACKS];
+
+// initial track size allocation
+#define TRACKBUFFERSIZE 1024
+
+// lookup table MUS -> MID controls
+static uint8_t MUS2MIDcontrol[15] =
+{
+  0,         // Program change - not a MIDI control change
+  0x00,      // Bank select
+  0x01,      // Modulation pot
+  0x07,      // Volume
+  0x0A,      // Pan pot
+  0x0B,      // Expression pot
+  0x5B,      // Reverb depth
+  0x5D,      // Chorus depth
+  0x40,      // Sustain pedal
+  0x43,      // Soft pedal
+  0x78,      // All sounds off
+  0x7B,      // All notes off
+  0x7E,      // Mono
+  0x7F,      // Poly
+  0x79       // Reset all controllers
+};
+
+// some strings of uint8_ts used in the midi format
+
+static uint8_t midikey[]   =
+{0x00,0xff,0x59,0x02,0x00,0x00};        // C major
+static uint8_t miditempo[] =
+{0x00,0xff,0x51,0x03,0x09,0xa3,0x1a};   // uS/qnote
+static uint8_t midihdr[]   =
+{'M','T','h','d',0,0,0,6,0,1,0,0,0,0};  // header (length 6, format 1)
+static uint8_t trackhdr[]  =
+{'M','T','r','k'};                      // track header
+
+// static routine prototypes
+
+static int TWriteByte(MIDI *mididata, int MIDItrack, uint8_t value);
+static int TWriteVarLen(MIDI *mididata, int MIDItrack, uint32_t value);
+static uint32_t ReadTime(const uint8_t **musptrp);
+static int FirstChannelAvailable(int MUS2MIDchannel[]);
+static uint8_t MidiEvent(MIDI *mididata,uint8_t midicode,uint8_t MIDIchannel,
+               uint8_t MIDItrack,int nocomp);
+
+//
+// TWriteByte()
+//
+// write one byte to the selected MIDItrack, update current position
+// if track allocation exceeded, double it
+// if track not allocated, initially allocate TRACKBUFFERSIZE bytes
+//
+// Passed pointer to Allegro MIDI structure, number of the MIDI track being
+// written, and the byte to write.
+//
+// Returns 0 on success, MEMALLOC if a memory allocation error occurs
+//
+static int TWriteByte(MIDI *mididata, int MIDItrack, uint8_t value)
+{
+  uint32_t pos;
+
+  pos = mididata->track[MIDItrack].len;
+  if (pos >= track[MIDItrack].alloced)
+  {
+    track[MIDItrack].alloced =        // double allocation
+      track[MIDItrack].alloced?       // or set initial TRACKBUFFERSIZE
+        2*track[MIDItrack].alloced :
+        TRACKBUFFERSIZE;
+
+    if (!(mididata->track[MIDItrack].data =     // attempt to reallocate
+      realloc(mididata->track[MIDItrack].data,
+              track[MIDItrack].alloced)))
+      return MEMALLOC;
+  }
+  mididata->track[MIDItrack].data[pos] = value;
+  mididata->track[MIDItrack].len++;
+  return 0;
+}
+
+//
+// TWriteVarLen()
+//
+// write the ULONG value to tracknum-th track, in midi format, which is
+// big endian, 7 bits per byte, with all bytes but the last flagged by
+// bit 8 being set, allowing the length to vary.
+//
+// Passed the Allegro MIDI structure, the track number to write,
+// and the ULONG value to encode in midi format there
+//
+// Returns 0 if sucessful, MEMALLOC if a memory allocation error occurs
+//
+static int TWriteVarLen(MIDI *mididata, int tracknum, uint32_t value)
+{
+  uint32_t buffer;
+
+  buffer = value & 0x7f;
+  while ((value >>= 7))         // terminates because value unsigned
+  {
+    buffer <<= 8;               // note first value shifted in has bit 8 clear
+    buffer |= 0x80;             // all succeeding values do not
+    buffer += (value & 0x7f);
+  }
+  while (1)                     // write bytes out in opposite order
+  {
+    if (TWriteByte(mididata, tracknum, (uint8_t)(buffer&0xff))) // insure buffer masked
+      return MEMALLOC;
+
+    if (buffer & 0x80)
+      buffer >>= 8;
+    else                        // terminate on the byte with bit 8 clear
+      break;
+  }
+  return 0;
+}
+
+//
+// ReadTime()
+//
+// Read a time value from the MUS buffer, advancing the position in it
+//
+// A time value is a variable length sequence of 8 bit bytes, with all
+// but the last having bit 8 set.
+//
+// Passed a pointer to the pointer to the MUS buffer
+// Returns the integer unsigned long time value there and advances the pointer
+//
+static uint32_t ReadTime(const uint8_t **musptrp)
+{
+  uint32_t timeval = 0;
+  int _byte;
+
+  do    // shift each byte read up in the result until a byte with bit 8 clear
+  {
+    _byte = *(*musptrp)++;
+    timeval = (timeval << 7) + (_byte & 0x7F);
+  }
+  while(_byte & 0x80);
+
+  return timeval;
+}
+
+//
+// FirstChannelAvailable()
+//
+// Return the next unassigned MIDI channel number
+//
+// The assignment for MUS channel 15 is not counted in the caculation, that
+// being percussion and always assigned to MIDI channel 9 (base 0).
+//
+// Passed the array of MIDI channels assigned to MUS channels
+// Returns the maximum channel number unassigned unless that is 9 in which
+// case 10 is returned.
+//
+// killough 10/7/98: changed char parameter, return values to int
+
+static int FirstChannelAvailable(int MUS2MIDchannel[])
+{
+  int i ;
+  int max = -1 ;
+
+  // find the largest MIDI channel assigned so far
+  for (i = 0; i < 15; i++)
+    if (MUS2MIDchannel[i] > max)
+      max = MUS2MIDchannel[i];
+
+  return (max == 8 ? 10 : max+1); // skip MIDI channel 9 (percussion)
+}
+
+//
+// MidiEvent()
+//
+// Constructs a MIDI event code, and writes it to the current MIDI track
+// unless its the same as the last event code and compressio is enabled
+// in which case nothing is written.
+//
+// Passed the Allegro MIDI structure, the midi event code, the current
+// MIDI channel number, the current MIDI track number, and whether compression
+// (running status) is enabled.
+//
+// Returns the new event code if successful, 0 if a memory allocation error
+//
+static uint8_t MidiEvent(MIDI *mididata,uint8_t midicode,uint8_t MIDIchannel,
+        uint8_t MIDItrack,int nocomp)
+{
+  uint8_t newevent;
+
+  newevent = midicode | MIDIchannel;
+  if ((newevent != track[MIDItrack].lastEvt) || nocomp)
+  {
+    if (TWriteByte(mididata,MIDItrack, newevent))
+      return 0;                                    // indicates MEMALLOC error
+    track[MIDItrack].lastEvt = newevent;
+  }
+  return newevent;
+}
+
+//
+// mmus2mid()
+//
+// Convert a memory buffer contain MUS data to an Allegro MIDI structure
+// with specified time division and compression.
+//
+// Passed a pointer to the buffer containing MUS data, a pointer to the
+// Allegro MIDI structure, the divisions, and a flag whether to compress.
+//
+// Returns 0 if successful, otherwise an error code (see mmus2mid.h).
+//
+int mmus2mid(const uint8_t *mus, MIDI *mididata, uint16_t division, int nocomp)
+{
+  uint16_t TrackCnt = 0;
+  uint8_t evt, MUSchannel, MIDIchannel, MIDItrack=0, NewEvent;
+  int i, event, data;
+  const uint8_t *musptr;
+  size_t muslen;
+  static MUSheader MUSh;
+  uint8_t MIDIchan2track[MIDI_TRACKS];  // killough 10/7/98: fix too small array
+  int MUS2MIDchannel[MIDI_TRACKS];    // killough 10/7/98: fix too small array
+
+  // copy the MUS header from the MUS buffer to the MUSh header structure
+
+  memcpy(&MUSh,mus,sizeof(MUSheader));
+  MUSh.ScoreLength = SHORT(MUSh.ScoreLength);
+  MUSh.ScoreStart  = SHORT(MUSh.ScoreStart);
+  MUSh.channels    = SHORT(MUSh.channels);
+  MUSh.SecChannels = SHORT(MUSh.SecChannels);
+  MUSh.InstrCnt    = SHORT(MUSh.InstrCnt);
+
+  // check some things and set length of MUS buffer from internal data
+
+  if (!(muslen = MUSh.ScoreLength + MUSh.ScoreStart))
+    return MUSDATAMT;     // MUS file empty
+
+  if (MUSh.channels > 15)       // MUSchannels + drum channel > 16
+    return TOOMCHAN ;
+
+  musptr = mus+MUSh.ScoreStart; // init musptr to start of score
+
+  for (i = 0; i < MIDI_TRACKS; i++)   // init the track structure's tracks
+  {
+    MUS2MIDchannel[i] = -1;       // flag for channel not used yet
+    track[i].velocity = 64;
+    track[i].deltaT = 0;
+    track[i].lastEvt = 0;
+    //free(mididata->track[i].data);//jff 3/5/98 remove old allocations
+    mididata->track[i].data=NULL;
+    track[i].alloced = 0;
+    mididata->track[i].len = 0;
+  }
+
+  if (!division)
+    division = 70;
+
+  // allocate the first track which is a special tempo/key track
+  // note multiple tracks means midi format 1
+
+  // set the divisions (ticks per quarter note)
+  mididata->divisions = division;
+
+  // allocate for midi tempo/key track, allow for end of track
+  if (!(mididata->track[0].data =
+      realloc(mididata->track[0].data,sizeof(midikey)+sizeof(miditempo)+4)))
+    return MEMALLOC;
+
+  // key C major
+  memcpy(mididata->track[0].data,midikey,sizeof(midikey));
+  // tempo uS/qnote
+  memcpy(mididata->track[0].data+sizeof(midikey),miditempo,sizeof(miditempo));
+  mididata->track[0].len = sizeof(midikey)+sizeof(miditempo);
+
+  TrackCnt++;   // music tracks start at 1
+
+  // process the MUS events in the MUS buffer
+
+  do
+  {
+    // get a mus event, decode its type and channel fields
+
+    event = *musptr++;
+    if ((evt = event_type(event)) == SCORE_END) //jff 1/23/98 use symbol
+      break;  // if end of score event, leave
+    MUSchannel = channel(event);
+
+    // if this channel not initialized, do so
+
+    if (MUS2MIDchannel[MUSchannel] == -1)
+    {
+      // set MIDIchannel and MIDItrack
+
+      MIDIchannel = MUS2MIDchannel[MUSchannel] =
+        (MUSchannel == 15 ? 9 : FirstChannelAvailable(MUS2MIDchannel));
+      MIDItrack = MIDIchan2track[MIDIchannel] = (uint8_t)TrackCnt++;
+    }
+    else // channel already allocated as a track, use those values
+    {
+      MIDIchannel = MUS2MIDchannel[MUSchannel];
+      MIDItrack   = MIDIchan2track[MIDIchannel];
+    }
+
+    if (TWriteVarLen(mididata, MIDItrack, track[MIDItrack].deltaT))
+      return MEMALLOC;
+    track[MIDItrack].deltaT = 0;
+
+    switch(evt)
+    {
+      case RELEASE_NOTE:
+      // killough 10/7/98: Fix noise problems by not allowing compression
+      if (!(NewEvent=MidiEvent(mididata,0x90,MIDIchannel,MIDItrack,1)))
+        return MEMALLOC;
+
+          data = *musptr++;
+          if (TWriteByte(mididata, MIDItrack, (uint8_t)(data & 0x7F)))
+            return MEMALLOC;
+          if (TWriteByte(mididata, MIDItrack, 0))
+            return MEMALLOC;
+          break;
+
+      case PLAY_NOTE:
+      if (!(NewEvent=MidiEvent(mididata,0x90,MIDIchannel,MIDItrack,nocomp)))
+        return MEMALLOC;
+
+          data = *musptr++;
+          if (TWriteByte(mididata, MIDItrack, (uint8_t)(data & 0x7F)))
+            return MEMALLOC;
+          if( data & 0x80 )
+            track[MIDItrack].velocity = (*musptr++) & 0x7f;
+          if (TWriteByte(mididata, MIDItrack, track[MIDItrack].velocity))
+            return MEMALLOC;
+          break;
+
+      case BEND_NOTE:
+      if (!(NewEvent=MidiEvent(mididata,0xE0,MIDIchannel,MIDItrack,nocomp)))
+        return MEMALLOC;
+
+          data = *musptr++;
+          if (TWriteByte(mididata, MIDItrack, (uint8_t)((data & 1) << 6)))
+            return MEMALLOC;
+          if (TWriteByte(mididata, MIDItrack, (uint8_t)(data >> 1)))
+            return MEMALLOC;
+          break;
+
+      case SYS_EVENT:
+      if (!(NewEvent=MidiEvent(mididata,0xB0,MIDIchannel,MIDItrack,nocomp)))
+        return MEMALLOC;
+
+          data = *musptr++;
+      if (data<10 || data>14)
+        return BADSYSEVT;
+
+          if (TWriteByte(mididata, MIDItrack, MUS2MIDcontrol[data]))
+            return MEMALLOC;
+          if (data == 12)
+      {
+              if (TWriteByte(mididata, MIDItrack, (uint8_t)(MUSh.channels+1)))
+                return MEMALLOC;
+      }
+          else
+      if (TWriteByte(mididata, MIDItrack, 0))
+        return MEMALLOC;
+          break;
+
+      case CNTL_CHANGE:
+          data = *musptr++;
+      if (data>9)
+        return BADCTLCHG;
+
+          if (data)
+          {
+        if (!(NewEvent=MidiEvent(mididata,0xB0,MIDIchannel,MIDItrack,nocomp)))
+                return MEMALLOC;
+
+              if (TWriteByte(mididata, MIDItrack, MUS2MIDcontrol[data]))
+                return MEMALLOC;
+          }
+          else
+          {
+        if (!(NewEvent=MidiEvent(mididata,0xC0,MIDIchannel,MIDItrack,nocomp)))
+                return MEMALLOC;
+          }
+          data = *musptr++;
+          if (TWriteByte(mididata, MIDItrack, (uint8_t)(data & 0x7F)))
+            return MEMALLOC;
+          break;
+
+    case UNKNOWN_EVENT1:   // mus events 5 and 7
+    case UNKNOWN_EVENT2:   // meaning not known
+      return BADMUSCTL;
+
+    case SCORE_END:
+      break;
+
+      default:
+          return BADMUSCTL;   // exit with error
+    }
+    if (last(event))
+    {
+          uint32_t DeltaTime = ReadTime(&musptr); // killough 10/7/98: make local
+    for (i = 0;i < MIDI_TRACKS; i++) //jff 3/13/98 update all tracks
+      track[i].deltaT += DeltaTime;  //whether allocated yet or not
+    }
+
+    }
+  while ((evt != SCORE_END) && ((size_t)(musptr-mus) < muslen));
+
+  if (evt!=SCORE_END)
+    return MUSDATACOR;
+
+  // Now add an end of track to each mididata track, correct allocation
+
+  for (i = 0; i < MIDI_TRACKS; i++)
+    if (mididata->track[i].len)
+    {       // killough 10/7/98: simplify code
+      if (TWriteByte(mididata, i, 0x00) || // midi end of track code
+        TWriteByte(mididata, i, 0xFF) ||
+        TWriteByte(mididata, i, 0x2F) ||
+        TWriteByte(mididata, i, 0x00))
+       return MEMALLOC;
+
+      // jff 1/23/98 fix failure to set data NULL, len 0 for unused tracks
+      // shorten allocation to proper length (important for Allegro)
+      if (!(mididata->track[i].data =
+        realloc(mididata->track[i].data,mididata->track[i].len)))
+        return MEMALLOC;
+    }
+    else
+    {
+      free(mididata->track[i].data);
+      mididata->track[i].data = NULL;
+    }
+
+  return 0;
+}
+
+void free_mididata(MIDI *mid)
+{
+  int i;
+
+  for (i = 0; i < MIDI_TRACKS; i++)
+    if (mid->track[i].data)
+      free(mid->track[i].data);
+}
+
+//
+// ReadLength()
+//
+// Reads the length of a chunk in a midi buffer, advancing the pointer
+// 4 bytes, bigendian
+//
+// Passed a pointer to the pointer to a MIDI buffer
+// Returns the chunk length at the pointer position
+//
+static size_t ReadLength(uint8_t **mid)
+{
+  uint8_t *midptr = *mid;
+
+  size_t length = (*midptr++)<<24;
+  length += (*midptr++)<<16;
+  length += (*midptr++)<<8;
+  length += *midptr++;
+  *mid = midptr;
+  return length;
+}
+
+//
+// MidiToMIDI()
+//
+// Convert an in-memory copy of a MIDI format 0 or 1 file to
+// an Allegro MIDI structure, that is valid or has been zeroed
+//
+// Passed a pointer to a memory buffer with MIDI format music in it and a
+// pointer to an Allegro MIDI structure.
+//
+// Returns 0 if successful, BADMIDHDR if the buffer is not MIDI format
+//
+int MidiToMIDI(uint8_t *mid,MIDI *mididata)
+{
+  int i;
+  int ntracks;
+
+  // read the midi header
+
+  if (memcmp(mid,midihdr,4))
+    return BADMIDHDR;
+
+  mididata->divisions = (mid[12]<<8)+mid[13];
+  ntracks = (mid[10]<<8)+mid[11];
+
+  if (ntracks>=MIDI_TRACKS)
+    return BADMIDHDR;
+
+  mid += 4;
+  {  // killough 10/7/98: fix mid from being modified twice before sequence pt.
+    size_t t = ReadLength(&mid);            // seek past header
+    mid += t;
+  }
+
+  // now read each track
+
+  for (i=0;i<ntracks;i++)
+  {
+    while (memcmp(mid,trackhdr,4))    // simply skip non-track data
+    {
+      mid += 4;
+      {
+        size_t t = ReadLength(&mid);            // seek past header
+        mid += t;  // killough 10/7/98: prevent mid undefined behavior
+      }
+    }
+    mid += 4;
+    mididata->track[i].len = ReadLength(&mid);  // get length, move mid past it
+
+    // read a track
+    mididata->track[i].data = realloc(mididata->track[i].data,mididata->track[i].len);
+    memcpy(mididata->track[i].data,mid,mididata->track[i].len);
+    mid += mididata->track[i].len;
+  }
+  for (;i<MIDI_TRACKS;i++)
+    if (mididata->track[i].len)
+    {
+      free(mididata->track[i].data);
+      mididata->track[i].data = NULL;
+      mididata->track[i].len = 0;
+    }
+  return 0;
+}
+
+//#ifdef STANDALONE /* this code unused by BOOM provided for future portability */
+//                  /* it also provides a MUS to MID file converter*/
+// proff: I moved this down, because I need MIDItoMidi
+
+//
+// TWriteLength()
+//
+// Write the length of a MIDI chunk to a midi buffer. The length is four
+// uint8_ts and is written uint8_t-reversed for bigendian. The pointer to the
+// midi buffer is advanced.
+//
+// Passed a pointer to the pointer to a midi buffer, and the length to write
+// Returns nothing
+//
+static void TWriteLength(uint8_t **midiptr,uint32_t length)
+{
+// proff: Added typecast to avoid warning
+  *(*midiptr)++ = (unsigned char)((length>>24)&0xff);
+  *(*midiptr)++ = (unsigned char)((length>>16)&0xff);
+  *(*midiptr)++ = (unsigned char)((length>>8)&0xff);
+  *(*midiptr)++ = (unsigned char)((length)&0xff);
+}
+
+//
+// MIDIToMidi()
+//
+// This routine converts an Allegro MIDI structure to a midi 1 format file
+// in memory. It is used to support memory MUS -> MIDI conversion
+//
+// Passed a pointer to an Allegro MIDI structure, a pointer to a pointer to
+// a buffer containing midi data, and a pointer to a length return.
+// Returns 0 if successful, MEMALLOC if a memory allocation error occurs
+//
+int MIDIToMidi(MIDI *mididata,uint8_t **mid,int *midlen)
+{
+  size_t total;
+  int i,ntrks;
+  uint8_t *midiptr;
+
+  // calculate how long the mid buffer must be, and allocate
+
+  total = sizeof(midihdr);
+  for (i=0,ntrks=0;i<MIDI_TRACKS;i++)
+    if (mididata->track[i].len)
+    {
+      total += 8 + mididata->track[i].len; // Track hdr + track length
+      ntrks++;
+    }
+  if ((*mid = malloc(total))==NULL)
+    return MEMALLOC;
+
+
+  // fill in number of tracks and bigendian divisions (ticks/qnote)
+
+  midihdr[10] = 0;
+  midihdr[11] = (uint8_t)ntrks;   // set number of tracks in header
+  midihdr[12] = (mididata->divisions>>8) & 0x7f;
+  midihdr[13] = (mididata->divisions) & 0xff;
+
+  // write the midi header
+
+  midiptr = *mid;
+  memcpy(midiptr,midihdr,sizeof(midihdr));
+  midiptr += sizeof(midihdr);
+
+  // write the tracks
+
+  for (i=0;i<MIDI_TRACKS;i++)
+  {
+    if (mididata->track[i].len)
+    {
+      memcpy(midiptr,trackhdr,sizeof(trackhdr));    // header
+      midiptr += sizeof(trackhdr);
+      TWriteLength(&midiptr,mididata->track[i].len);  // track length
+      // data
+      memcpy(midiptr,mididata->track[i].data,mididata->track[i].len);
+      midiptr += mididata->track[i].len;
+    }
+  }
+
+  // return length information
+
+  *midlen = midiptr - *mid;
+
+  return 0;
+}
+
+#ifdef STANDALONE /* this code unused by BOOM provided for future portability */
+                  /* it also provides a MUS to MID file converter*/
+// proff: I moved this down, because I need MIDItoMidi
+
+//
+// FreeTracks()
+//
+// Free all track allocations in the MIDI structure
+//
+// Passed a pointer to an Allegro MIDI structure
+// Returns nothing
+//
+static void FreeTracks(MIDI *mididata)
+{
+  int i;
+
+  for (i=0; i<MIDI_TRACKS; i++)
+  {
+    free(mididata->track[i].data);
+    mididata->track[i].data = NULL;
+    mididata->track[i].len = 0;
+  }
+}
+
+//
+// main()
+//
+// Main routine that will convert a globbed set of MUS files to the
+// correspondingly named MID files using mmus2mid(). Only compiled
+// if the STANDALONE symbol is defined.
+//
+// Passed the command line arguments, returns 0 if successful
+//
+int main(int argc,char **argv)
+{
+  FILE *musst,*midst;
+  char musfile[FILENAME_MAX],midfile[FILENAME_MAX];
+  MUSheader MUSh;
+  uint8_t *mus,*mid;
+  static MIDI mididata;
+  int err,midlen;
+  char *p,*q;
+  int i;
+
+  if (argc<2)
+  {
+    //jff 8/3/98 use logical output routine
+    lprintf(LO_INFO,"Usage: MMUS2MID musfile[.MUS]\n");
+    lprintf(LO_INFO,"writes musfile.MID as output\n");
+    lprintf(LO_INFO,"musfile may contain wildcards\n");
+    exit(1);
+  }
+
+  for (i=1;i<argc;i++)
+  {
+    strcpy(musfile,argv[i]);
+    p = strrchr(musfile,'.');
+    q = strrchr(musfile,'\\');
+    if (p && (!q || q<p)) *p='\0';
+    strcpy(midfile,musfile);
+    strcat(musfile,".MUS");
+    strcat(midfile,".MID");
+
+    musst = fopen(musfile,"rb");
+    if (musst)
+    {
+      fread(&MUSh,sizeof(MUSheader),1,musst);
+      mus = malloc(MUSh.ScoreLength+MUSh.ScoreStart);
+      if (mus)
+      {
+        fseek(musst,0,SEEK_SET);
+        if (!fread(mus,MUSh.ScoreLength+MUSh.ScoreStart,1,musst))
+        {
+          //jff 8/3/98 use logical output routine
+          lprintf(LO_FATAL,"Error reading MUS file\n");
+          free(mus);
+          exit(1);
+        }
+        fclose(musst);
+      }
+      else
+      {
+        //jff 8/3/98 use logical output routine
+        lprintf(LO_FATAL,"Out of memory\n");
+        free(mus);
+        exit(1);
+      }
+
+      err = mmus2mid(mus,&mididata,89,1);
+      if (err)
+      {
+        //jff 8/3/98 use logical output routine
+        lprintf(LO_FATAL,"Error converting MUS file to MIDI: %d\n",err);
+        exit(1);
+      }
+      free(mus);
+
+      MIDIToMidi(&mididata,&mid,&midlen);
+
+      midst = fopen(midfile,"wb");
+      if (midst)
+      {
+        if (!fwrite(mid,midlen,1,midst))
+        {
+          //jff 8/3/98 use logical output routine
+          lprintf(LO_FATAL,"Error writing MIDI file\n");
+          FreeTracks(&mididata);
+          free(mid);
+          exit(1);
+        }
+        fclose(midst);
+      }
+      else
+      {
+        //jff 8/3/98 use logical output routine
+        lprintf(LO_FATAL,"Can't open MIDI file for output: %s\n", midfile);
+        FreeTracks(&mididata);
+        free(mid);
+        exit(1);
+      }
+    }
+    else
+    {
+      //jff 8/3/98 use logical output routine
+      lprintf(LO_FATAL,"Can't open MUS file for input: %s\n", midfile);
+      exit(1);
+    }
+
+    //jff 8/3/98 use logical output routine
+    lprintf(LO_CONFIRM,"MUS file %s converted to MIDI file %s\n",musfile,midfile);
+    FreeTracks(&mididata);
+    free(mid);
+  }
+  exit(0);
+}
+
+#endif
--- /dev/null
+++ b/mmus2mid.h
@@ -1,0 +1,69 @@
+/* $Id: mmus2mid.h 373 2009-05-19 18:14:28Z sezero $
+ *
+ *  Ripped && Adapted from the PrBoom project:
+ *  PrBoom: a Doom port merged with LxDoom and LSDLDoom
+ *  based on BOOM, a modified and improved DOOM engine
+ *  Copyright (C) 1999 by
+ *  id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
+ *  Copyright (C) 1999-2000 by
+ *  Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
+ *  Copyright 2005, 2006 by
+ *  Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version 2
+ *  of the License, or (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ *  02110-1301  USA.
+ *
+ * DESCRIPTION:
+ *  mmus2mid.c supports conversion of MUS format music in memory
+ *  to MIDI format 1 music in memory.
+ */
+
+#if !defined( MMUS2MID_H )
+#define MMUS2MID_H
+
+// error codes
+
+typedef enum
+{
+  MUSDATACOR,    // MUS data corrupt
+  TOOMCHAN,      // Too many channels
+  MEMALLOC,      // Memory allocation error
+  MUSDATAMT,     // MUS file empty
+  BADMUSCTL,     // MUS event 5 or 7 found
+  BADSYSEVT,     // MUS system event not in 10-14 range
+  BADCTLCHG,     // MUS control change larger than 9
+  TRACKOVF,      // MIDI track exceeds allocation
+  BADMIDHDR,     // bad midi header detected
+} error_code_t;
+
+#ifndef MSDOS /* proff: This is from allegro.h */
+#define MIDI_TRACKS           32
+
+typedef struct MIDI                    /* a midi file */
+{
+   int divisions;                      /* number of ticks per quarter note */
+   struct {
+      unsigned char *data;             /* MIDI message stream */
+      int len;                         /* length of the track data */
+   } track[MIDI_TRACKS];
+} MIDI;
+#endif /* !MSDOS */
+
+extern int mmus2mid(const uint8_t *mus,MIDI *mid, uint16_t division, int nocomp);
+extern void free_mididata(MIDI *mid);
+extern int MIDIToMidi(MIDI *mididata,uint8_t **mid,int *midlen);
+extern int MidiToMIDI(uint8_t *mid,MIDI *mididata);
+
+#endif
--- /dev/null
+++ b/mn_menu.c
@@ -1,0 +1,2253 @@
+//**************************************************************************
+//**
+//** mn_menu.c : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 560 $
+//** $Date: 2010-10-20 15:15:39 +0300 (Wed, 20 Oct 2010) $
+//**
+//**************************************************************************
+
+// HEADER FILES ------------------------------------------------------------
+
+#include "h2stdinc.h"
+#include <ctype.h>
+#include "h2def.h"
+#include "p_local.h"
+#include "r_local.h"
+#include "i_cdmus.h"
+#include "soundst.h"
+#include "v_compat.h"
+
+// MACROS ------------------------------------------------------------------
+
+#define LEFT_DIR		0
+#define RIGHT_DIR		1
+#define ITEM_HEIGHT		20
+#define SMALL_ITEM_HEIGHT	9
+#define MENU_MAX_MOUSE_SENS	50
+
+#define SELECTOR_XOFFSET	(-28)
+#define SELECTOR_YOFFSET	(-1)
+#define SLOTTEXTLEN		16
+#define ASCII_CURSOR		'['
+
+#ifdef RENDER3D
+#define V_DrawPatch(x,y,p)		OGL_DrawPatch((x),(y),(p))
+#define V_DrawRawScreen(a)		OGL_DrawRawScreen((a))
+#endif
+
+// TYPES -------------------------------------------------------------------
+
+typedef enum
+{
+	ITT_EMPTY,
+	ITT_EFUNC,
+	ITT_LRFUNC,
+	ITT_SETMENU,
+	ITT_INERT,
+	ITT_SETKEY
+} ItemType_t;
+
+typedef enum
+{
+	MENU_MAIN,
+	MENU_CLASS,
+	MENU_SKILL,
+	MENU_OPTIONS,
+	MENU_OPTIONS2,
+	MENU_OPTIONS3,
+	MENU_FILES,
+	MENU_LOAD,
+	MENU_SAVE,
+	MENU_NONE
+} MenuType_t;
+
+typedef struct
+{
+	ItemType_t type;
+	const char *text;
+	void (*func)(int option);
+	int option;
+	MenuType_t menu;
+} MenuItem_t;
+
+typedef struct
+{
+	int x;
+	int y;
+	void (*drawFunc)(void);
+	int itemCount;
+	MenuItem_t *items;
+	int oldItPos;
+	int step;
+	MenuType_t prevMenu;
+} Menu_t;
+
+// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
+
+// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
+
+// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
+
+static const char *Key2String(int key);
+static void ClearControls(int key);
+static void InitFonts(void);
+static void SetTheMenu(MenuType_t menu);
+static void SCQuitGame(int option);
+static void SCClass(int option);
+static void SCSkill(int option);
+static void SCMouseSensi(int option);
+static void SCSfxVolume(int option);
+static void SCMusicVolume(int option);
+static void SCScreenSize(int option);
+static boolean SCNetCheck(int option);
+static void SCNetCheck2(int option);
+static void SCLoadGame(int option);
+static void SCSaveGame(int option);
+static void SCMessages(int option);
+static void SCEndGame(int option);
+static void SCInfo(int option);
+static void SCSetKey(int option);
+static void SCMouselook(int option);
+static void SCAlwaysRun(int option);
+static void SCCDAudio(int option);
+static void DrawMainMenu(void);
+static void DrawClassMenu(void);
+static void DrawSkillMenu(void);
+static void DrawOptionsMenu(void);
+static void DrawOptions2Menu(void);
+static void DrawOptions3Menu(void);
+static void DrawFileSlots(Menu_t *menu);
+static void DrawFilesMenu(void);
+static void MN_DrawInfo(void);
+static void DrawLoadMenu(void);
+static void DrawSaveMenu(void);
+static void DrawSlider(Menu_t *menu, int item, int width, int slot);
+static void MN_LoadSlotText(void);
+
+// EXTERNAL DATA DECLARATIONS ----------------------------------------------
+
+extern default_t defaults[];
+
+extern int detailLevel;
+extern int screenblocks;
+extern boolean gamekeydown[MAXKEYS];
+
+extern int alwaysrun;
+extern int mouselook;
+
+extern int key_right,key_left,key_up,key_down;
+extern int key_straferight,key_strafeleft,key_jump;
+extern int key_fire, key_use, key_strafe, key_speed;
+extern int key_flyup, key_flydown, key_flycenter;
+extern int key_lookup, key_lookdown, key_lookcenter;
+extern int key_invleft, key_invright, key_useartifact;
+
+// PUBLIC DATA DEFINITIONS -------------------------------------------------
+
+boolean MenuActive;
+int InfoType;
+int messageson;	/* boolean */
+boolean mn_SuicideConsole;
+
+// PRIVATE DATA DEFINITIONS ------------------------------------------------
+
+static int FontABaseLump;
+static int FontAYellowBaseLump;
+static int FontBBaseLump;
+static int MauloBaseLump;
+static Menu_t *CurrentMenu;
+static int CurrentItPos;
+static int MenuPClass;
+static int MenuTime;
+static boolean soundchanged;
+
+#ifdef RENDER3D
+static float bgAlpha = 0;
+static float outFade = 0;
+static boolean fadingOut = false;
+static int menuDarkTicks = 15;
+static int slamInTicks = 9;
+#endif
+
+boolean askforquit;
+static boolean FileMenuKeySteal;
+static boolean slottextloaded;
+static char SlotText[6][SLOTTEXTLEN+2];
+static char oldSlotText[SLOTTEXTLEN+2];
+static int SlotStatus[6];
+static int slotptr;
+static int currentSlot;
+static int quicksave;
+static int quickload;
+static int typeofask;
+
+static int FirstKey = 0;
+static boolean askforkey = false;
+static int keyaskedfor;
+
+static MenuItem_t MainItems[] =
+{
+	{ ITT_SETMENU, "NEW GAME", SCNetCheck2, 1, MENU_CLASS },
+	{ ITT_SETMENU, "OPTIONS", NULL, 0, MENU_OPTIONS },
+	{ ITT_SETMENU, "GAME FILES", NULL, 0, MENU_FILES },
+	{ ITT_EFUNC, "INFO", SCInfo, 0, MENU_NONE },
+	{ ITT_EFUNC, "QUIT GAME", SCQuitGame, 0, MENU_NONE }
+};
+
+static Menu_t MainMenu =
+{
+	110, 56,
+	DrawMainMenu,
+	5, MainItems,
+	0,
+	ITEM_HEIGHT,
+	MENU_NONE
+};
+
+static MenuItem_t ClassItems[] =
+{
+	{ ITT_EFUNC, "FIGHTER", SCClass, 0, MENU_NONE },
+	{ ITT_EFUNC, "CLERIC", SCClass, 1, MENU_NONE },
+	{ ITT_EFUNC, "MAGE", SCClass, 2, MENU_NONE },
+#ifdef ASSASSIN
+	{ ITT_EFUNC, "ASSASSIN", SCClass, 3, MENU_NONE }
+#endif
+};
+
+static Menu_t ClassMenu =
+{
+	66, 66,
+	DrawClassMenu,
+	NUMCLASSES_HUMAN,
+	ClassItems,
+	0,
+	ITEM_HEIGHT,
+	MENU_MAIN
+};
+
+static MenuItem_t FilesItems[] =
+{
+	{ ITT_SETMENU, "LOAD GAME", SCNetCheck2, 2, MENU_LOAD },
+	{ ITT_SETMENU, "SAVE GAME", NULL, 0, MENU_SAVE }
+};
+
+static Menu_t FilesMenu =
+{
+	110, 60,
+	DrawFilesMenu,
+	2, FilesItems,
+	0,
+	ITEM_HEIGHT,
+	MENU_MAIN
+};
+
+static MenuItem_t LoadItems[] =
+{
+	{ ITT_EFUNC, NULL, SCLoadGame, 0, MENU_NONE },
+	{ ITT_EFUNC, NULL, SCLoadGame, 1, MENU_NONE },
+	{ ITT_EFUNC, NULL, SCLoadGame, 2, MENU_NONE },
+	{ ITT_EFUNC, NULL, SCLoadGame, 3, MENU_NONE },
+	{ ITT_EFUNC, NULL, SCLoadGame, 4, MENU_NONE },
+	{ ITT_EFUNC, NULL, SCLoadGame, 5, MENU_NONE }
+};
+
+static Menu_t LoadgameMenu =
+{
+	70, 30,
+	DrawLoadMenu,
+	6, LoadItems,
+	0,
+	ITEM_HEIGHT,
+	MENU_FILES
+};
+
+static MenuItem_t SaveItems[] =
+{
+	{ ITT_EFUNC, NULL, SCSaveGame, 0, MENU_NONE },
+	{ ITT_EFUNC, NULL, SCSaveGame, 1, MENU_NONE },
+	{ ITT_EFUNC, NULL, SCSaveGame, 2, MENU_NONE },
+	{ ITT_EFUNC, NULL, SCSaveGame, 3, MENU_NONE },
+	{ ITT_EFUNC, NULL, SCSaveGame, 4, MENU_NONE },
+	{ ITT_EFUNC, NULL, SCSaveGame, 5, MENU_NONE }
+};
+
+static Menu_t SavegameMenu =
+{
+	70, 30,
+	DrawSaveMenu,
+	6, SaveItems,
+	0,
+	ITEM_HEIGHT,
+	MENU_FILES
+};
+
+static MenuItem_t SkillItems[] =
+{
+	{ ITT_EFUNC, NULL, SCSkill, sk_baby, MENU_NONE },
+	{ ITT_EFUNC, NULL, SCSkill, sk_easy, MENU_NONE },
+	{ ITT_EFUNC, NULL, SCSkill, sk_medium, MENU_NONE },
+	{ ITT_EFUNC, NULL, SCSkill, sk_hard, MENU_NONE },
+	{ ITT_EFUNC, NULL, SCSkill, sk_nightmare, MENU_NONE }
+};
+
+static Menu_t SkillMenu =
+{
+	120, 44,
+	DrawSkillMenu,
+	5, SkillItems,
+	2,
+	ITEM_HEIGHT,
+	MENU_CLASS
+};
+
+static MenuItem_t OptionsItems[] =
+{
+	{ ITT_EFUNC, "END GAME", SCEndGame, 0, MENU_NONE },
+	{ ITT_EFUNC, "MESSAGES : ", SCMessages, 0, MENU_NONE },
+	{ ITT_LRFUNC, "MOUSE SENSITIVITY :", SCMouseSensi, 0, MENU_NONE },
+	{ ITT_SETMENU, "CONTROL SETUP", NULL, 0, MENU_OPTIONS3 },
+	{ ITT_LRFUNC, "MOUSELOOK : ", SCMouselook, 0, MENU_NONE },
+	{ ITT_EFUNC, "ALWAYS RUN : ", SCAlwaysRun, 0, MENU_NONE },
+	{ ITT_SETMENU, "MORE...", NULL, 0, MENU_OPTIONS2 }
+};
+
+static Menu_t OptionsMenu =
+{
+	88, 30,
+	DrawOptionsMenu,
+	7,
+	OptionsItems,
+	0,
+	ITEM_HEIGHT,
+	MENU_MAIN
+};
+
+static MenuItem_t Options2Items[] =
+{
+	{ ITT_LRFUNC, "SCREEN SIZE", SCScreenSize, 0, MENU_NONE },
+	{ ITT_EMPTY, NULL, NULL, 0, MENU_NONE },
+	{ ITT_LRFUNC, "SFX VOLUME", SCSfxVolume, 0, MENU_NONE },
+	{ ITT_EMPTY, NULL, NULL, 0, MENU_NONE },
+	{ ITT_LRFUNC, "MUSIC VOLUME", SCMusicVolume, 0, MENU_NONE },
+	{ ITT_EMPTY, NULL, NULL, 0, MENU_NONE },
+	{ ITT_EFUNC, "CD AUDIO :", SCCDAudio, 0, MENU_NONE }
+};
+
+static Menu_t Options2Menu =
+{
+	90, 20,
+	DrawOptions2Menu,
+	7,
+	Options2Items,
+	0,
+	ITEM_HEIGHT,
+	MENU_OPTIONS
+};
+
+static MenuItem_t Options3Items[] =
+{
+/* see defaults[] in m_misc.c for the correct option number:
+ * key_right corresponds to defaults[3], which means that we
+ * are using the (index_number - 3) here.
+ */
+	{ ITT_SETKEY, "TURN RIGHT :", SCSetKey, 0, MENU_NONE },
+	{ ITT_SETKEY, "TURN LEFT :", SCSetKey, 1, MENU_NONE },
+	{ ITT_SETKEY, "MOVE FORWARD :", SCSetKey, 2, MENU_NONE },
+	{ ITT_SETKEY, "MOVE BACK :" , SCSetKey, 3, MENU_NONE },
+	{ ITT_SETKEY, "STRAFE LEFT :", SCSetKey, 4, MENU_NONE },
+	{ ITT_SETKEY, "STRAFE RIGHT :", SCSetKey, 5, MENU_NONE },
+	{ ITT_SETKEY, "FLY UP :", SCSetKey, 6, MENU_NONE },
+	{ ITT_SETKEY, "FLY DOWN :", SCSetKey, 7, MENU_NONE },
+	{ ITT_SETKEY, "FLY CENTER :", SCSetKey, 8, MENU_NONE },
+	{ ITT_SETKEY, "LOOK UP :", SCSetKey, 9, MENU_NONE },
+	{ ITT_SETKEY, "LOOK DOWN :", SCSetKey, 10, MENU_NONE },
+	{ ITT_SETKEY, "LOOK CENTER :", SCSetKey, 11, MENU_NONE },
+	{ ITT_SETKEY, "INVENTORY LEFT :", SCSetKey, 12, MENU_NONE },
+	{ ITT_SETKEY, "INVENTORY RIGHT :", SCSetKey, 13, MENU_NONE },
+	{ ITT_SETKEY, "USE ARTIFACT :", SCSetKey, 14, MENU_NONE },
+	{ ITT_SETKEY, "FIRE :", SCSetKey, 15, MENU_NONE },
+	{ ITT_SETKEY, "USE :", SCSetKey, 16, MENU_NONE },
+	{ ITT_SETKEY, "STRAFE :", SCSetKey, 17, MENU_NONE },
+	{ ITT_SETKEY, "SPEED :", SCSetKey, 18, MENU_NONE },
+	{ ITT_SETKEY, "JUMP :", SCSetKey, 19, MENU_NONE }
+};
+
+/* Many items in Options3Items[], only 15 can be drawn on a page:
+ * So, FirstKey changes between 0 and FIRSTKEY_MAX. This menu is
+ * way too fragile. Should we adapt from Quake's M_Menu_Keys and
+ * bindnames?? */
+#define FIRSTKEY_MAX	5
+static Menu_t Options3Menu =
+{
+	70, 20,
+	DrawOptions3Menu,
+	15, /* actually 20 */
+	Options3Items,
+	0,
+	SMALL_ITEM_HEIGHT,
+	MENU_OPTIONS
+};
+
+static Menu_t *Menus[] =
+{
+	&MainMenu,
+	&ClassMenu,
+	&SkillMenu,
+	&OptionsMenu,
+	&Options2Menu,
+	&Options3Menu,
+	&FilesMenu,
+	&LoadgameMenu,
+	&SavegameMenu
+};
+
+static const char *mlooktext[] =
+{
+	"OFF",
+	"NORMAL",
+	"INVERSE"
+};
+
+static const char *stupidtable[] =
+{
+	"A","B","C","D","E",
+	"F","G","H","I","J",
+	"K","L","M","N","O",
+	"P","Q","R","S","T",
+	"U","V","W","X","Y",
+	"Z"
+};
+
+static const char *GammaText[] =
+{
+	TXT_GAMMA_LEVEL_OFF,
+	TXT_GAMMA_LEVEL_1,
+	TXT_GAMMA_LEVEL_2,
+	TXT_GAMMA_LEVEL_3,
+	TXT_GAMMA_LEVEL_4
+};
+
+// CODE --------------------------------------------------------------------
+
+static const char *Key2String (int key)
+{
+/* S.A.: return "[" or "]" or "\"" doesn't work
+ * because there are no lumps for these chars,
+ * therefore we have to go with "RIGHT BRACKET"
+ * and similar for much punctuation.  Probably
+ * won't work with international keyboards and
+ * dead keys, either.
+ */
+	switch (key)
+	{
+	case KEY_LEFTBRACKET:	return "LEFT BRACK";
+	case KEY_RIGHTBRACKET:	return "RIGHT BRACK";
+	case KEY_BACKQUOTE:	return "BACK QUOTE";
+	case KEY_QUOTE:		return "'";
+	case KEY_QUOTEDBL:	return "DOUBLE QUOTE";
+	case KEY_SEMICOLON:	return ";";
+	case KEY_MINUS:		return "-";
+	case KEY_PERIOD:	return ".";
+	case KEY_COMMA:		return ",";
+	case KEY_SLASH:		return "/";
+	case KEY_BACKSLASH:	return "BACKSLASH";
+	case KEY_TAB:		return "TAB";
+	case KEY_EQUALS:	return "=";
+
+	case KEY_RIGHTARROW:	return "RIGHT ARROW";
+	case KEY_LEFTARROW:	return "LEFT ARROW";
+	case KEY_DOWNARROW:	return "DOWN ARROW";
+	case KEY_UPARROW:	return "UP ARROW";
+	case KEY_ENTER:		return "ENTER";
+	case KEY_PGUP:		return "PAGE UP";
+	case KEY_PGDN:		return "PAGE DOWN";
+	case KEY_INS:		return "INSERT";
+	case KEY_HOME:		return "HOME";
+	case KEY_END:		return "END";
+	case KEY_DEL:		return "DELETE";
+	case ' ':		return "SPACE";
+	case KEY_RSHIFT:	return "SHIFT";
+	case KEY_RALT:		return "ALT";
+	case KEY_RCTRL:		return "CTRL";
+	}
+	/* Handle letter keys */
+	/* S.A.: could also be done with toupper */
+	if (key >= 'a' && key <= 'z')
+		return stupidtable[(key - 'a')];
+
+	return "?";		/* Everything else */
+}
+
+static void ClearControls (int key)
+{
+	int i;
+
+	for (i = 3; i < 24; i++)
+	{
+		if (*defaults[i].location == key)
+			*defaults[i].location = 0;
+	}
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC MN_Init
+//
+//---------------------------------------------------------------------------
+
+void MN_Init(void)
+{
+	InitFonts();
+	MenuActive = false;
+//	messageson = 1;	// Set by defaults in .CFG
+	MauloBaseLump = W_GetNumForName("FBULA0"); // ("M_SKL00");
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC InitFonts
+//
+//---------------------------------------------------------------------------
+
+static void InitFonts(void)
+{
+	FontABaseLump = W_GetNumForName("FONTA_S") + 1;
+	FontAYellowBaseLump = W_GetNumForName("FONTAY_S") + 1;
+	FontBBaseLump = W_GetNumForName("FONTB_S") + 1;
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC MN_DrTextA
+//
+// Draw text using font A.
+//
+//---------------------------------------------------------------------------
+
+void MN_DrTextA(const char *text, int x, int y)
+{
+	char c;
+	patch_t *p;
+
+#ifdef RENDER3D
+	OGL_SetColorAndAlpha(1, 1, 1, 1);
+#endif
+
+	while ((c = *text++) != 0)
+	{
+		if (c < 33)
+		{
+			x += 5;
+		}
+		else
+		{
+			p = (patch_t *) W_CacheLumpNum(FontABaseLump + c - 33, PU_CACHE);
+#ifdef RENDER3D
+			OGL_DrawPatch_CS(x, y, FontABaseLump + c - 33);
+#else
+			V_DrawPatch(x, y, p);
+#endif
+			x += SHORT(p->width) - 1;
+		}
+	}
+}
+
+//==========================================================================
+//
+// MN_DrTextAYellow
+//
+//==========================================================================
+
+void MN_DrTextAYellow(const char *text, int x, int y)
+{
+	char c;
+	patch_t *p;
+
+#ifdef RENDER3D
+	OGL_SetColorAndAlpha(1, 1, 1, 1);
+#endif
+
+	while ((c = *text++) != 0)
+	{
+		if (c < 33)
+		{
+			x += 5;
+		}
+		else
+		{
+			p = (patch_t *) W_CacheLumpNum(FontAYellowBaseLump + c - 33, PU_CACHE);
+#ifdef RENDER3D
+			OGL_DrawPatch_CS(x, y, FontAYellowBaseLump + c - 33);
+#else
+			V_DrawPatch(x, y, p);
+#endif
+			x += SHORT(p->width) - 1;
+		}
+	}
+}
+
+//---------------------------------------------------------------------------
+//
+// FUNC MN_TextAWidth
+//
+// Returns the pixel width of a string using font A.
+//
+//---------------------------------------------------------------------------
+
+int MN_TextAWidth(const char *text)
+{
+	char c;
+	int width;
+	patch_t *p;
+
+	width = 0;
+	while ((c = *text++) != 0)
+	{
+		if (c < 33)
+		{
+			width += 5;
+		}
+		else
+		{
+			p = (patch_t *) W_CacheLumpNum(FontABaseLump + c - 33, PU_CACHE);
+			width += SHORT(p->width) - 1;
+		}
+	}
+	return (width);
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC MN_DrTextB
+//
+// Draw text using font B.
+//
+//---------------------------------------------------------------------------
+
+void MN_DrTextB(const char *text, int x, int y)
+{
+	char c;
+	patch_t *p;
+
+#ifdef RENDER3D
+	OGL_SetColorAndAlpha(1, 1, 1, 1);
+#endif
+
+	while ((c = *text++) != 0)
+	{
+		if (c < 33)
+		{
+			x += 8;
+		}
+		else
+		{
+			p = (patch_t *) W_CacheLumpNum(FontBBaseLump + c - 33, PU_CACHE);
+#ifdef RENDER3D
+			OGL_DrawPatch_CS(x, y, FontBBaseLump + c - 33);
+#else
+			V_DrawPatch(x, y, p);
+#endif
+			x += SHORT(p->width) - 1;
+		}
+	}
+}
+
+//---------------------------------------------------------------------------
+//
+// FUNC MN_TextBWidth
+//
+// Returns the pixel width of a string using font B.
+//
+//---------------------------------------------------------------------------
+
+int MN_TextBWidth(const char *text)
+{
+	char c;
+	int width;
+	patch_t *p;
+
+	width = 0;
+	while ((c = *text++) != 0)
+	{
+		if (c < 33)
+		{
+			width += 5;
+		}
+		else
+		{
+			p = (patch_t *) W_CacheLumpNum(FontBBaseLump + c - 33, PU_CACHE);
+			width += SHORT(p->width) - 1;
+		}
+	}
+	return (width);
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC MN_Ticker
+//
+//---------------------------------------------------------------------------
+
+void MN_Ticker(void)
+{
+	if (MenuActive == false)
+	{
+#ifdef RENDER3D
+		if (bgAlpha > 0)
+		{
+			bgAlpha -= .5 / (float)menuDarkTicks;
+			if (bgAlpha < 0)
+				bgAlpha = 0;
+		}
+		if (fadingOut)
+		{
+			outFade += 1 / (float)slamInTicks;
+			if (outFade > 1)
+				fadingOut = false;
+		}
+#endif
+		return;
+	}
+	MenuTime++;
+}
+
+
+#ifdef RENDER3D
+static void MN_OGL_SetupState(float time)
+{
+	glMatrixMode(GL_MODELVIEW);
+	glPushMatrix();
+
+	if (time > 1 && time <= 2)
+	{
+		time = 2 - time;
+		glTranslatef(160, 100, 0);
+		glScalef(.9 + time*.1, .9 + time*.1, 1);
+		glTranslatef(-160, -100, 0);
+		glColor4f(1, 1, 1, time);
+		return;
+	}
+
+	glTranslatef(160, 100, 0);
+	glScalef(2-time, 2-time, 1);
+	glTranslatef(-160, -100, 0);
+	glColor4f(1, 1, 1, time*time);
+}
+
+static void MN_OGL_RestoreState(void)
+{
+	glMatrixMode(GL_MODELVIEW);
+	glPopMatrix();
+}
+#endif
+
+
+//---------------------------------------------------------------------------
+//
+// PROC MN_Drawer
+//
+//---------------------------------------------------------------------------
+
+static const char *QuitEndMsg[] =
+{
+	"ARE YOU SURE YOU WANT TO QUIT?",
+	"ARE YOU SURE YOU WANT TO END THE GAME?",
+	"DO YOU WANT TO QUICKSAVE THE GAME NAMED",
+	"DO YOU WANT TO QUICKLOAD THE GAME NAMED",
+	"ARE YOU SURE YOU WANT TO SUICIDE?"
+};
+
+
+void MN_Drawer(void)
+{
+	int i;
+	int x;
+	int y;
+	MenuItem_t *item;
+	const char *selName;
+
+	if (MenuActive == false)
+	{
+#ifdef RENDER3D
+		if (bgAlpha > 0)
+		{
+			UpdateState |= I_FULLSCRN;
+			BorderNeedRefresh = true;
+		//	OGL_SetNoTexture();
+			glDisable(GL_TEXTURE_2D);
+			OGL_DrawRect(0, 0, 320, 200, 0, 0, 0, bgAlpha);
+			glEnable(GL_TEXTURE_2D);
+		}
+#endif
+		if (askforquit)
+		{
+			MN_DrTextA(QuitEndMsg[typeofask-1], 160 - MN_TextAWidth(QuitEndMsg[typeofask-1])/2, 80);
+			if (typeofask == 3)
+			{
+				MN_DrTextA(SlotText[quicksave-1], 160 - MN_TextAWidth(SlotText[quicksave-1])/2, 90);
+				MN_DrTextA("?", 160 + MN_TextAWidth(SlotText[quicksave-1])/2, 90);
+			}
+			if (typeofask == 4)
+			{
+				MN_DrTextA(SlotText[quickload-1], 160 - MN_TextAWidth(SlotText[quickload-1])/2, 90);
+				MN_DrTextA("?", 160 + MN_TextAWidth(SlotText[quicksave-1])/2, 90);
+			}
+			UpdateState |= I_FULLSCRN;
+		}
+	}
+#ifdef RENDER3D
+	if (MenuActive || fadingOut)
+	{
+		int effTime = (MenuTime > menuDarkTicks) ? menuDarkTicks : MenuTime;
+		float temp = .5 * effTime / (float)menuDarkTicks;
+
+		UpdateState |= I_FULLSCRN;
+
+		if (!fadingOut)
+		{
+			if (temp > bgAlpha)
+				bgAlpha = temp;
+			effTime = (MenuTime>slamInTicks) ? slamInTicks : MenuTime;
+			temp = effTime / (float)slamInTicks;
+
+			// Draw a dark background. It makes it easier to read the menus.
+			//OGL_SetNoTexture();
+			glDisable(GL_TEXTURE_2D);
+			OGL_DrawRect(0, 0, 320, 200, 0, 0, 0, bgAlpha);
+			glEnable(GL_TEXTURE_2D);
+		}
+		else
+			temp = outFade + 1;
+		MN_OGL_SetupState(temp);
+
+		if (InfoType)
+		{
+			MN_DrawInfo();
+			MN_OGL_RestoreState();
+			return;
+		}
+	//	if (screenblocks < 10)
+	//	{
+			BorderNeedRefresh = true;
+	//	}
+		if (CurrentMenu->drawFunc != NULL)
+		{
+			CurrentMenu->drawFunc();
+		}
+		x = CurrentMenu->x;
+		y = CurrentMenu->y;
+		item = CurrentMenu->items;
+		if (item->type == ITT_SETKEY)
+			item += FirstKey;
+		for (i = 0; i < CurrentMenu->itemCount; i++)
+		{
+			switch (item->type)
+			{
+			case (ITT_EMPTY):
+				break;
+			case (ITT_SETKEY):
+				if (item->text)
+					MN_DrTextA(item->text, x, y+6);
+				break;
+			default:
+				if (item->text)
+					MN_DrTextB(item->text, x, y);
+			}
+			y += CurrentMenu->step;
+			item++;
+		}
+		y = CurrentMenu->y + (CurrentItPos * CurrentMenu->step) + SELECTOR_YOFFSET;
+		selName = (MenuTime & 16) ? "M_SLCTR1" : "M_SLCTR2";
+		OGL_DrawPatch_CS(x + SELECTOR_XOFFSET, y, W_GetNumForName(selName));
+
+		MN_OGL_RestoreState();
+	}
+#else
+	else
+	{
+		UpdateState |= I_FULLSCRN;
+		if (InfoType)
+		{
+			MN_DrawInfo();
+			return;
+		}
+		if (screenblocks < 10)
+		{
+			BorderNeedRefresh = true;
+		}
+		if (CurrentMenu->drawFunc != NULL)
+		{
+			CurrentMenu->drawFunc();
+		}
+		x = CurrentMenu->x;
+		y = CurrentMenu->y;
+		item = CurrentMenu->items;
+		if (item->type == ITT_SETKEY)
+			item += FirstKey;
+		for (i = 0; i < CurrentMenu->itemCount; i++)
+		{
+			switch (item->type)
+			{
+			case (ITT_EMPTY):
+				break;
+			case (ITT_SETKEY):
+				if (item->text)
+					MN_DrTextA(item->text, x, y+6);
+				break;
+			default:
+				if (item->text)
+					MN_DrTextB(item->text, x, y);
+			}
+			y += CurrentMenu->step;
+			item++;
+		}
+		y = CurrentMenu->y + (CurrentItPos * CurrentMenu->step) + SELECTOR_YOFFSET;
+		selName = (MenuTime & 16) ? "M_SLCTR1" : "M_SLCTR2";
+		V_DrawPatch(x + SELECTOR_XOFFSET, y, (patch_t *)W_CacheLumpName(selName, PU_CACHE));
+	}
+#endif
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC DrawMainMenu
+//
+//---------------------------------------------------------------------------
+
+static void DrawMainMenu(void)
+{
+	int frame;
+
+	frame = (MenuTime / 5) % 7;
+
+#ifdef RENDER3D
+	OGL_DrawPatch_CS(88, 0, W_GetNumForName("M_HTIC") );
+	OGL_DrawPatch_CS(37, 80, MauloBaseLump + (frame + 2) % 7);
+	OGL_DrawPatch_CS(278, 80, MauloBaseLump + frame);
+#else
+	V_DrawPatch(88, 0, (patch_t *)W_CacheLumpName("M_HTIC", PU_CACHE));
+// Old Gold skull positions: (40, 10) and (232, 10)
+	V_DrawPatch(37, 80, (patch_t *)W_CacheLumpNum(MauloBaseLump + (frame + 2) % 7, PU_CACHE));
+	V_DrawPatch(278, 80, (patch_t *)W_CacheLumpNum(MauloBaseLump + frame, PU_CACHE));
+#endif
+}
+
+//==========================================================================
+//
+// DrawClassMenu
+//
+//==========================================================================
+
+static void DrawClassMenu(void)
+{
+	pclass_t pClass;
+	static const char *boxLumpName[4] =
+	{
+		"m_fbox",
+		"m_cbox",
+		"m_mbox",
+		"m_abox"
+	};
+	static const char *walkLumpName[4] =
+	{
+		"m_fwalk1",
+		"m_cwalk1",
+		"m_mwalk1",
+		"m_awalk1"
+	};
+
+	MN_DrTextB("CHOOSE CLASS:", 34, 24);
+	pClass = (pclass_t)CurrentMenu->items[CurrentItPos].option;
+#ifdef RENDER3D
+	OGL_DrawPatch_CS(174, 8, W_GetNumForName(boxLumpName[pClass]));
+	OGL_DrawPatch_CS(174+24, 8+12,
+			 W_GetNumForName(walkLumpName[pClass]) + ((MenuTime>>3) & 3));
+#else
+	V_DrawPatch(174, 8, (patch_t *)W_CacheLumpName(boxLumpName[pClass], PU_CACHE));
+	V_DrawPatch(174+24, 8+12,
+		(patch_t *)W_CacheLumpNum(W_GetNumForName(walkLumpName[pClass]) + ((MenuTime>>3) & 3), PU_CACHE));
+#endif
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC DrawSkillMenu
+//
+//---------------------------------------------------------------------------
+
+static void DrawSkillMenu(void)
+{
+	MN_DrTextB("CHOOSE SKILL LEVEL:", 74, 16);
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC DrawFilesMenu
+//
+//---------------------------------------------------------------------------
+
+static void DrawFilesMenu(void)
+{
+// clear out the quicksave/quickload stuff
+	quicksave = 0;
+	quickload = 0;
+	P_ClearMessage(&players[consoleplayer]);
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC DrawLoadMenu
+//
+//---------------------------------------------------------------------------
+
+static void DrawLoadMenu(void)
+{
+	MN_DrTextB("LOAD GAME", 160 - MN_TextBWidth("LOAD GAME")/2, 10);
+	if (!slottextloaded)
+	{
+		MN_LoadSlotText();
+	}
+	DrawFileSlots(&LoadgameMenu);
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC DrawSaveMenu
+//
+//---------------------------------------------------------------------------
+
+static void DrawSaveMenu(void)
+{
+	MN_DrTextB("SAVE GAME", 160 - MN_TextBWidth("SAVE GAME")/2, 10);
+	if (!slottextloaded)
+	{
+		MN_LoadSlotText();
+	}
+	DrawFileSlots(&SavegameMenu);
+}
+
+//===========================================================================
+//
+// MN_LoadSlotText
+//
+// For each slot, looks for save games and reads the description field.
+//
+//===========================================================================
+
+static void MN_LoadSlotText(void)
+{
+	int slot;
+	FILE *fp;
+	char name[MAX_OSPATH];
+	char versionText[HXS_VERSION_TEXT_LENGTH];
+	char description[HXS_DESCRIPTION_LENGTH];
+	boolean found;
+
+	for (slot = 0; slot < 6; slot++)
+	{
+		found = false;
+		snprintf(name, sizeof(name), "%shex%d.hxs", basePath, slot);
+		fp = fopen(name, "rb");
+		if (fp)
+		{
+			fread(description, HXS_DESCRIPTION_LENGTH, 1, fp);
+			fread(versionText, HXS_VERSION_TEXT_LENGTH, 1, fp);
+			fclose(fp);
+			if (!strcmp(versionText, HXS_VERSION_TEXT))
+			{
+				found = true;
+			}
+		}
+		if (found)
+		{
+			memcpy(SlotText[slot], description, SLOTTEXTLEN);
+			SlotStatus[slot] = 1;
+		}
+		else
+		{
+			memset(SlotText[slot], 0, SLOTTEXTLEN);
+			SlotStatus[slot] = 0;
+		}
+	}
+	slottextloaded = true;
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC DrawFileSlots
+//
+//---------------------------------------------------------------------------
+
+static void DrawFileSlots(Menu_t *menu)
+{
+	int i;
+	int x;
+	int y;
+
+	x = menu->x;
+	y = menu->y;
+	for (i = 0; i < 6; i++)
+	{
+#ifdef RENDER3D
+		OGL_DrawPatch_CS(x, y, W_GetNumForName("M_FSLOT"));
+#else
+		V_DrawPatch(x, y, (patch_t *)W_CacheLumpName("M_FSLOT", PU_CACHE));
+#endif
+		if (SlotStatus[i])
+		{
+			MN_DrTextA(SlotText[i], x+5, y+5);
+		}
+		y += ITEM_HEIGHT;
+	}
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC DrawOptionsMenu
+//
+//---------------------------------------------------------------------------
+
+static void DrawOptionsMenu(void)
+{
+	char num[5];
+
+	if (messageson)
+	{
+		MN_DrTextB("ON", 196, 50);
+	}
+	else
+	{
+		MN_DrTextB("OFF", 196, 50);
+	}
+
+	MN_DrTextB(mlooktext[mouselook], 208, 110);
+
+	snprintf(num, sizeof(num), "%d", mouseSensitivity);
+	MN_DrTextB(num, 265, 71);
+
+	if (alwaysrun)
+	{
+		MN_DrTextB("ON", 208, 130);
+	}
+	else
+	{
+		MN_DrTextB("OFF", 208,130);
+	}
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC DrawOptions2Menu
+//
+//---------------------------------------------------------------------------
+
+static void DrawOptions2Menu(void)
+{
+	DrawSlider(&Options2Menu, 1, 9, screenblocks-3);
+	DrawSlider(&Options2Menu, 3, 16, snd_MaxVolume);
+	DrawSlider(&Options2Menu, 5, 16, snd_MusicVolume);
+	if (cdaudio)
+	{
+		MN_DrTextB("ON", 196, 140);
+	}
+	else
+	{
+		MN_DrTextB("OFF", 196, 140);
+	}
+}
+
+static void DrawOptions3Menu(void)
+{
+	int i;
+
+	for (i = 0; i < 15; i++)
+	{
+		if (askforkey && keyaskedfor == i)
+		{
+			MN_DrTextAYellow("???", 195, (i*SMALL_ITEM_HEIGHT+26));
+		}
+		else
+		{
+			MN_DrTextA(Key2String(*(defaults[i+FirstKey+3].location)),
+				195, (i*SMALL_ITEM_HEIGHT+26));
+		}
+	}
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC SCQuitGame
+//
+//---------------------------------------------------------------------------
+
+static void SCQuitGame(int option)
+{
+	MenuActive = false;
+	askforquit = true;
+	typeofask = 1; //quit game
+	if (!netgame && !demoplayback)
+	{
+		paused = true;
+	}
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC SCEndGame
+//
+//---------------------------------------------------------------------------
+
+static void SCEndGame(int option)
+{
+	if (demoplayback)
+	{
+		return;
+	}
+	if (SCNetCheck(3))
+	{
+		MenuActive = false;
+		askforquit = true;
+		typeofask = 2; //endgame
+		if (!netgame && !demoplayback)
+		{
+			paused = true;
+		}
+	}
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC SCMessages
+//
+//---------------------------------------------------------------------------
+
+static void SCMessages(int option)
+{
+	if (messageson)
+	{
+		messageson = 0;
+		P_SetMessage(&players[consoleplayer], "MESSAGES OFF", true);
+	}
+	else
+	{
+		messageson = 1;
+		P_SetMessage(&players[consoleplayer], "MESSAGES ON", true);
+	}
+	S_StartSound(NULL, SFX_CHAT);
+}
+
+//===========================================================================
+//
+// SCNetCheck
+//
+//===========================================================================
+
+static boolean SCNetCheck(int option)
+{
+	if (!netgame)
+	{
+		return true;
+	}
+	switch (option)
+	{
+	case 1: // new game
+		P_SetMessage(&players[consoleplayer],
+			"YOU CAN'T START A NEW GAME IN NETPLAY!", true);
+		break;
+	case 2: // load game
+		P_SetMessage(&players[consoleplayer],
+			"YOU CAN'T LOAD A GAME IN NETPLAY!", true);
+		break;
+	case 3: // end game
+		P_SetMessage(&players[consoleplayer],
+			"YOU CAN'T END A GAME IN NETPLAY!", true);
+		break;
+	}
+	MenuActive = false;
+	S_StartSound(NULL, SFX_CHAT);
+	return false;
+}
+
+//===========================================================================
+//
+// SCNetCheck2
+//
+//===========================================================================
+
+static void SCNetCheck2(int option)
+{
+	SCNetCheck(option);
+	return;
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC SCLoadGame
+//
+//---------------------------------------------------------------------------
+
+static void SCLoadGame(int option)
+{
+	if (!SlotStatus[option])
+	{ // Don't try to load from an empty slot
+		return;
+	}
+	G_LoadGame(option);
+	MN_DeactivateMenu();
+	BorderNeedRefresh = true;
+	if (quickload == -1)
+	{
+		quickload = option+1;
+		P_ClearMessage(&players[consoleplayer]);
+	}
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC SCSaveGame
+//
+//---------------------------------------------------------------------------
+
+static void SCSaveGame(int option)
+{
+	char *ptr;
+	player_t *player = &players[consoleplayer];
+
+	if (gamestate != GS_LEVEL || demoplayback
+		|| player->playerstate == PST_DEAD)
+	{
+		FileMenuKeySteal = false;
+		return;
+	}
+
+	if (!FileMenuKeySteal)
+	{
+		FileMenuKeySteal = true;
+		strcpy(oldSlotText, SlotText[option]);
+		ptr = SlotText[option];
+		while (*ptr)
+		{
+			ptr++;
+		}
+		*ptr = '[';
+		*(ptr+1) = 0;
+		SlotStatus[option]++;
+		currentSlot = option;
+		slotptr = ptr-SlotText[option];
+		return;
+	}
+	else
+	{
+		G_SaveGame(option, SlotText[option]);
+		FileMenuKeySteal = false;
+		MN_DeactivateMenu();
+	}
+	BorderNeedRefresh = true;
+	if (quicksave == -1)
+	{
+		quicksave = option+1;
+		P_ClearMessage(&players[consoleplayer]);
+	}
+}
+
+//==========================================================================
+//
+// SCClass
+//
+//==========================================================================
+
+static void SCClass(int option)
+{
+	if (netgame)
+	{
+		P_SetMessage(&players[consoleplayer],
+			"YOU CAN'T START A NEW GAME FROM WITHIN A NETGAME!", true);
+		return;
+	}
+	MenuPClass = option;
+	switch (MenuPClass)
+	{
+	case PCLASS_FIGHTER:
+		SkillMenu.x = 120;
+		SkillItems[0].text = "SQUIRE";
+		SkillItems[1].text = "KNIGHT";
+		SkillItems[2].text = "WARRIOR";
+		SkillItems[3].text = "BERSERKER";
+		SkillItems[4].text = "TITAN";
+		break;
+	case PCLASS_CLERIC:
+		SkillMenu.x = 116;
+		SkillItems[0].text = "ALTAR BOY";
+		SkillItems[1].text = "ACOLYTE";
+		SkillItems[2].text = "PRIEST";
+		SkillItems[3].text = "CARDINAL";
+		SkillItems[4].text = "POPE";
+		break;
+	case PCLASS_MAGE:
+		SkillMenu.x = 112;
+		SkillItems[0].text = "APPRENTICE";
+		SkillItems[1].text = "ENCHANTER";
+		SkillItems[2].text = "SORCERER";
+		SkillItems[3].text = "WARLOCK";
+		SkillItems[4].text = "ARCHIMAGE";
+		break;
+#ifdef ASSASSIN
+	case PCLASS_ASS:
+		SkillMenu.x = 116;
+		SkillItems[0].text = "KNAVE";
+		SkillItems[1].text = "ROUGE";
+		SkillItems[2].text = "CUTTHROAT";
+		SkillItems[3].text = "EXECUTIONER";
+		SkillItems[4].text = "WIDOW MAKER";
+		break;
+#endif
+	}
+	SetTheMenu(MENU_SKILL);
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC SCSkill
+//
+//---------------------------------------------------------------------------
+
+static void SCSkill(int option)
+{
+	extern int SB_state;
+
+	PlayerClasses[consoleplayer] = MenuPClass;
+	G_DeferredNewGame(option);
+	SB_SetClassData();
+	SB_state = -1;
+	MN_DeactivateMenu();
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC SCMouseSensi
+//
+//---------------------------------------------------------------------------
+
+static void SCMouseSensi(int option)
+{
+	if (option == RIGHT_DIR)
+	{
+		if (mouseSensitivity < MENU_MAX_MOUSE_SENS)
+		{
+			mouseSensitivity++;
+		}
+	}
+	else if (mouseSensitivity)
+	{
+		mouseSensitivity--;
+	}
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC SCSfxVolume
+//
+//---------------------------------------------------------------------------
+
+static void SCSfxVolume(int option)
+{
+	if (option == RIGHT_DIR)
+	{
+		if (snd_MaxVolume < 15)
+		{
+			snd_MaxVolume++;
+		}
+	}
+	else if (snd_MaxVolume)
+	{
+		snd_MaxVolume--;
+	}
+	soundchanged = true; // we'll set it when we leave the menu
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC SCMusicVolume
+//
+//---------------------------------------------------------------------------
+
+static void SCMusicVolume(int option)
+{
+	if (option == RIGHT_DIR)
+	{
+		if (snd_MusicVolume < 15)
+		{
+			snd_MusicVolume++;
+		}
+	}
+	else if (snd_MusicVolume)
+	{
+		snd_MusicVolume--;
+	}
+	S_SetMusicVolume();
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC SCScreenSize
+//
+//---------------------------------------------------------------------------
+
+static void SCScreenSize(int option)
+{
+	if (option == RIGHT_DIR)
+	{
+		if (screenblocks < 11)
+		{
+			screenblocks++;
+		}
+	}
+	else if (screenblocks > 3)
+	{
+		screenblocks--;
+	}
+	R_SetViewSize(screenblocks, detailLevel);
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC SCInfo
+//
+//---------------------------------------------------------------------------
+
+static void SCInfo(int option)
+{
+	InfoType = 1;
+	S_StartSound(NULL, SFX_DOOR_LIGHT_CLOSE);
+	if (!netgame && !demoplayback)
+	{
+		paused = true;
+	}
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC SCSetKey
+//
+//---------------------------------------------------------------------------
+
+static void SCSetKey(int option)
+{
+	askforkey = true;
+	keyaskedfor = option;
+	if (!netgame && !demoplayback)
+	{
+		paused = true;
+	}
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC SCMouslook(int option)
+//
+//---------------------------------------------------------------------------
+
+static void SCMouselook(int option)
+{
+	if (option == RIGHT_DIR)
+	{
+		if (mouselook < 2)
+			mouselook++;
+	}
+	else if (mouselook)
+		mouselook--;
+}
+
+static void SCAlwaysRun(int option)
+{
+	if (alwaysrun)
+		alwaysrun = 0;
+	else	alwaysrun = 1;
+}
+
+static void SCCDAudio(int option)
+{
+	if (cdaudio)
+	{
+		cdaudio = 0;
+		I_CDMusStop();
+	// FIXME: start ordinary music here
+	}
+	else
+	{
+		cdaudio = 1;
+		if (i_CDMusic)
+		{
+		// FIXME: start cdaudio here
+		}
+	}
+}
+
+//---------------------------------------------------------------------------
+//
+// FUNC MN_Responder
+//
+//---------------------------------------------------------------------------
+
+boolean MN_Responder(event_t *event)
+{
+	int key;
+	int i;
+	MenuItem_t *item;
+	static boolean shiftdown;
+	extern void H2_StartTitle(void);
+	extern void G_CheckDemoStatus(void);
+	char *textBuffer;
+
+	if (askforkey && event->type == ev_keydown)
+	{
+		ClearControls(event->data1);
+		*defaults[keyaskedfor + 3 + FirstKey].location = event->data1;
+		askforkey = false;
+		return true;
+	}
+	if (askforkey && event->type == ev_mouse)
+	{
+		if (event->data1 & 1)
+			return true;
+		if (event->data1 & 2)
+			return true;
+		if (event->data1 & 4)
+			return true;
+		return false;
+	}
+	if (event->data1 == KEY_RSHIFT)
+	{
+		shiftdown = (event->type == ev_keydown);
+	}
+	if (event->type != ev_keydown)
+	{
+		return false;
+	}
+	key = event->data1;
+	if (InfoType)
+	{
+		InfoType = (InfoType + 1) % 4;
+		if (key == KEY_ESCAPE)
+		{
+			InfoType = 0;
+		}
+		if (!InfoType)
+		{
+			if (!netgame && !demoplayback)
+			{
+				paused = false;
+			}
+			MN_DeactivateMenu();
+			SB_state = -1; //refresh the statbar
+			BorderNeedRefresh = true;
+		}
+		S_StartSound(NULL, SFX_DOOR_LIGHT_CLOSE);
+		return true; //make the info screen eat the keypress
+	}
+
+	if (ravpic && key == KEY_F1)
+	{
+	// F12 is screenshot now. This
+	// is here for reference, only.
+		G_ScreenShot();
+		return true;
+	}
+
+	if (askforquit)
+	{
+		switch (key)
+		{
+		case KEY_ENTER:
+		case 'y':
+			if (askforquit)
+			{
+				switch (typeofask)
+				{
+				case 1:
+					G_CheckDemoStatus(); 
+					I_Quit();
+					break;
+				case 2:
+					P_ClearMessage(&players[consoleplayer]);
+					typeofask = 0;
+					askforquit = false;
+					paused = false;
+					V_SetPaletteBase();
+					H2_StartTitle(); // go to intro/demo mode.
+					break;
+				case 3:
+					P_SetMessage(&players[consoleplayer], 
+						"QUICKSAVING....", false);
+					FileMenuKeySteal = true;
+					SCSaveGame(quicksave-1);
+					askforquit = false;
+					typeofask = 0;
+					BorderNeedRefresh = true;
+					return true;
+				case 4:
+					P_SetMessage(&players[consoleplayer], 
+						"QUICKLOADING....", false);
+					SCLoadGame(quickload-1);
+					askforquit = false;
+					typeofask = 0;
+					BorderNeedRefresh = true;
+					return true;
+				case 5:
+					askforquit = false;
+					typeofask = 0;
+					BorderNeedRefresh = true;
+					mn_SuicideConsole = true;
+					return true;
+				default:
+					return true; // eat the 'y' keypress
+				}
+			}
+			return false;
+
+		case 'n':
+		case KEY_ESCAPE:
+			if (askforquit)
+			{
+				players[consoleplayer].messageTics = 0;
+				askforquit = false;
+				typeofask = 0;
+				paused = false;
+				UpdateState |= I_FULLSCRN;
+				BorderNeedRefresh = true;
+				return true;
+			}
+			return false;
+		}
+		return false; // don't let the keys filter thru
+	}
+	if (MenuActive == false && !chatmodeon)
+	{
+		switch (key)
+		{
+		case KEY_MINUS:
+			if (automapactive)
+			{ // Don't screen size in automap
+				return false;
+			}
+			SCScreenSize(LEFT_DIR);
+			S_StartSound(NULL, SFX_PICKUP_KEY);
+			BorderNeedRefresh = true;
+			UpdateState |= I_FULLSCRN;
+			return true;
+		case KEY_EQUALS:
+			if (automapactive)
+			{ // Don't screen size in automap
+				return false;
+			}
+			SCScreenSize(RIGHT_DIR);
+			S_StartSound(NULL, SFX_PICKUP_KEY);
+			BorderNeedRefresh = true;
+			UpdateState |= I_FULLSCRN;
+			return true;
+#ifdef __NeXT__
+		case 'q':
+			MenuActive = false;
+			askforquit = true;
+			typeofask = 5; // suicide
+			return true;
+#endif
+		case KEY_F1: // help screen
+			SCInfo(0); // start up info screens
+			MenuActive = true;
+			return true;
+		case KEY_F2: // save game
+			if (gamestate == GS_LEVEL && !demoplayback)
+			{
+				MenuActive = true;
+				FileMenuKeySteal = false;
+				MenuTime = 0;
+				CurrentMenu = &SavegameMenu;
+				CurrentItPos = CurrentMenu->oldItPos;
+				if (!netgame && !demoplayback)
+				{
+					paused = true;
+				}
+				S_StartSound(NULL, SFX_DOOR_LIGHT_CLOSE);
+				slottextloaded = false; //reload the slot text, when needed
+			}
+			return true;
+		case KEY_F3: // load game
+			if (SCNetCheck(2))
+			{
+				MenuActive = true;
+				FileMenuKeySteal = false;
+				MenuTime = 0;
+				CurrentMenu = &LoadgameMenu;
+				CurrentItPos = CurrentMenu->oldItPos;
+				if (!netgame && !demoplayback)
+				{
+					paused = true;
+				}
+				S_StartSound(NULL, SFX_DOOR_LIGHT_CLOSE);
+				slottextloaded = false; //reload the slot text, when needed
+			}
+			return true;
+		case KEY_F4: // S.A.: made F4 Controls. was Volume, before.
+			MenuActive = true;
+			FileMenuKeySteal = false;
+			MenuTime = 0;
+			CurrentMenu = &OptionsMenu;
+			CurrentItPos = CurrentMenu->oldItPos;
+			if (!netgame && !demoplayback)
+			{
+				paused = true;
+			}
+			S_StartSound(NULL, SFX_DOOR_LIGHT_CLOSE);
+			slottextloaded = false; //reload the slot text, when needed
+			return true;
+		case KEY_F5: // volume
+			MenuActive = true;
+			FileMenuKeySteal = false;
+			MenuTime = 0;
+			CurrentMenu = &Options2Menu;
+			CurrentItPos = CurrentMenu->oldItPos;
+			if (!netgame && !demoplayback)
+			{
+				paused = true;
+			}
+			S_StartSound(NULL, SFX_DOOR_LIGHT_CLOSE);
+			slottextloaded = false; //reload the slot text, when needed
+			return true;
+		case KEY_F6: // quicksave
+			if (gamestate == GS_LEVEL && !demoplayback)
+			{
+				if (!quicksave || quicksave == -1)
+				{
+					MenuActive = true;
+					FileMenuKeySteal = false;
+					MenuTime = 0;
+					CurrentMenu = &SavegameMenu;
+					CurrentItPos = CurrentMenu->oldItPos;
+					if (!netgame && !demoplayback)
+					{
+						paused = true;
+					}
+					S_StartSound(NULL, SFX_DOOR_LIGHT_CLOSE);
+					slottextloaded = false; //reload the slot text
+					quicksave = -1;
+					P_SetMessage(&players[consoleplayer],
+						"CHOOSE A QUICKSAVE SLOT", true);
+				}
+				else
+				{
+					askforquit = true;
+					typeofask = 3;
+					if (!netgame && !demoplayback)
+					{
+						paused = true;
+					}
+					S_StartSound(NULL, SFX_CHAT);
+				}
+			}
+			return true;
+		case KEY_F7: // endgame
+			if (SCNetCheck(3))
+			{
+				if (gamestate == GS_LEVEL && !demoplayback)
+				{
+					S_StartSound(NULL, SFX_CHAT);
+					SCEndGame(0);
+				}
+			}
+			return true;
+		case KEY_F8: // toggle messages
+			SCMessages(0);
+			return true;
+		case KEY_F9: // quickload
+			if (SCNetCheck(2))
+			{
+				if (!quickload || quickload == -1)
+				{
+					MenuActive = true;
+					FileMenuKeySteal = false;
+					MenuTime = 0;
+					CurrentMenu = &LoadgameMenu;
+					CurrentItPos = CurrentMenu->oldItPos;
+					if (!netgame && !demoplayback)
+					{
+						paused = true;
+					}
+					S_StartSound(NULL, SFX_DOOR_LIGHT_CLOSE);
+					slottextloaded = false; // reload the slot text
+					quickload = -1;
+					P_SetMessage(&players[consoleplayer],
+						"CHOOSE A QUICKLOAD SLOT", true);
+				}
+				else
+				{
+					askforquit = true;
+					if (!netgame && !demoplayback)
+					{
+						paused = true;
+					}
+					typeofask = 4;
+					S_StartSound(NULL, SFX_CHAT);
+				}
+			}
+			return true;
+		case KEY_F10: // quit
+		// S.A.: allowed quit to work when not in a level
+		//	if (!(gamestate == GS_LEVEL || gamestate == GS_FINALE))
+		//		return true;
+			SCQuitGame(0);
+			S_StartSound(NULL, SFX_CHAT);
+			return true;
+		case KEY_F11: // F11 - gamma mode correction
+			usegamma++;
+			if (usegamma > 4)
+			{
+				usegamma = 0;
+			}
+			SB_PaletteFlash(true); // force change
+			P_SetMessage(&players[consoleplayer], GammaText[usegamma], false);
+			return true;
+		/*
+		case KEY_F12: // F12 - reload current map (devmaps mode)
+			if (netgame || DevMaps == false)
+			{
+				return false;
+			}
+			if (gamekeydown[key_speed])
+			{ // Monsters ON
+				nomonsters = false;
+			}
+			if (gamekeydown[key_strafe])
+			{ // Monsters OFF
+				nomonsters = true;
+			}
+			G_DeferedInitNew(gameskill, gameepisode, gamemap);
+			P_SetMessage(&players[consoleplayer], TXT_CHEATWARP,
+				false);
+			return true;
+		*/
+		case KEY_F12: // S.A.: made F12 Screenshot
+			G_ScreenShot();
+			return true;
+		}
+	}
+
+	if (MenuActive == false)
+	{
+		if (key == KEY_ESCAPE || gamestate == GS_DEMOSCREEN || demoplayback)
+		{
+			MN_ActivateMenu();
+			return true;
+		}
+		return false;
+	}
+	if (!FileMenuKeySteal)
+	{
+		item = &CurrentMenu->items[CurrentItPos];
+		switch (key)
+		{
+		case KEY_DOWNARROW:
+			do
+			{
+				if (CurrentMenu->items[CurrentItPos].type == ITT_SETKEY
+					&& CurrentItPos+1 > CurrentMenu->itemCount-1)
+				{
+					if (FirstKey == FIRSTKEY_MAX)
+					{
+						CurrentItPos = 0; // End of Key menu
+						FirstKey = 0;
+					}
+					else
+					{
+						FirstKey++;
+					}
+				}
+				else if (CurrentItPos+1 > CurrentMenu->itemCount-1)
+				{
+					CurrentItPos = 0;
+				}
+				else
+				{
+					CurrentItPos++;
+				}
+			}
+			while (CurrentMenu->items[CurrentItPos].type == ITT_EMPTY);
+			S_StartSound(NULL, SFX_FIGHTER_HAMMER_HITWALL);
+			return true;
+		case KEY_UPARROW:
+			do
+			{
+				if (CurrentMenu->items[CurrentItPos].type == ITT_SETKEY && CurrentItPos == 0)
+				{
+					if (FirstKey == 0)
+					{
+						CurrentItPos = 14; // End of Key menu
+								   // 14 == 15 (max lines on a page) - 1
+						FirstKey = FIRSTKEY_MAX;
+					}
+					else
+					{
+						FirstKey--;
+					}
+				}
+				else if (CurrentItPos == 0)
+				{
+					CurrentItPos = CurrentMenu->itemCount-1;
+				}
+				else
+				{
+					CurrentItPos--;
+				}
+			}
+			while (CurrentMenu->items[CurrentItPos].type == ITT_EMPTY);
+			S_StartSound(NULL, SFX_FIGHTER_HAMMER_HITWALL);
+			return true;
+		case KEY_LEFTARROW:
+			if (item->type == ITT_LRFUNC && item->func != NULL)
+			{
+				item->func(LEFT_DIR);
+				S_StartSound(NULL, SFX_PICKUP_KEY);
+			}
+			return true;
+		case KEY_RIGHTARROW:
+			if (item->type == ITT_LRFUNC && item->func != NULL)
+			{
+				item->func(RIGHT_DIR);
+				S_StartSound(NULL, SFX_PICKUP_KEY);
+			}
+			return true;
+		case KEY_ENTER:
+			if (item->type == ITT_SETMENU)
+			{
+				if (item->func != NULL)	
+				{
+					item->func(item->option);
+				}
+				SetTheMenu(item->menu);
+			}
+			else if (item->func != NULL)
+			{
+				CurrentMenu->oldItPos = CurrentItPos;
+				if (item->type == ITT_LRFUNC)
+				{
+					item->func(RIGHT_DIR);
+				}
+				else if (item->type == ITT_EFUNC)
+				{
+					item->func(item->option);
+				}
+				else if (item->type == ITT_SETKEY)
+				{
+					item->func(item->option);
+				}
+			}
+			S_StartSound(NULL, SFX_DOOR_LIGHT_CLOSE);
+			return true;
+		case KEY_ESCAPE:
+			MN_DeactivateMenu();
+			return true;
+		case KEY_BACKSPACE:
+			S_StartSound(NULL, SFX_PICKUP_KEY);
+			if (CurrentMenu->prevMenu == MENU_NONE)
+			{
+				MN_DeactivateMenu();
+			}
+			else
+			{
+				SetTheMenu(CurrentMenu->prevMenu);
+			}
+			return true;
+		default:
+			for (i = 0; i < CurrentMenu->itemCount; i++)
+			{
+				if (CurrentMenu->items[i].text)
+				{
+					if (toupper(key)
+						== toupper(CurrentMenu->items[i].text[0]))
+					{
+						CurrentItPos = i;
+						return true;
+					}
+				}
+			}
+			break;
+		}
+		return false;
+	}
+	else
+	{ // Editing file names
+		textBuffer = &SlotText[currentSlot][slotptr];
+		if (key == KEY_BACKSPACE)
+		{
+			if (slotptr)
+			{
+				*textBuffer-- = 0;
+				*textBuffer = ASCII_CURSOR;
+				slotptr--;
+			}
+			return true;
+		}
+		if (key == KEY_ESCAPE)
+		{
+			memset(SlotText[currentSlot], 0, SLOTTEXTLEN+2);
+			strcpy(SlotText[currentSlot], oldSlotText);
+			SlotStatus[currentSlot]--;
+			MN_DeactivateMenu();
+			return true;
+		}
+		if (key == KEY_ENTER)
+		{
+			SlotText[currentSlot][slotptr] = 0; // clear the cursor
+			item = &CurrentMenu->items[CurrentItPos];
+			CurrentMenu->oldItPos = CurrentItPos;
+			if (item->type == ITT_EFUNC)
+			{
+				item->func(item->option);
+				if (item->menu != MENU_NONE)
+				{
+					SetTheMenu(item->menu);
+				}
+			}
+			return true;
+		}
+		if (slotptr < SLOTTEXTLEN && key != KEY_BACKSPACE)
+		{
+			if ((key >= 'a' && key <= 'z'))
+			{
+				*textBuffer++ = key-32;
+				*textBuffer = ASCII_CURSOR;
+				slotptr++;
+				return true;
+			}
+			if (((key >= '0' && key <= '9') || key == ' '
+				|| key == ',' || key == '.' || key == '-')
+				&& !shiftdown)
+			{
+				*textBuffer++ = key;
+				*textBuffer = ASCII_CURSOR;
+				slotptr++;
+				return true;
+			}
+			if (shiftdown && key == '1')
+			{
+				*textBuffer++ = '!';
+				*textBuffer = ASCII_CURSOR;
+				slotptr++;
+				return true;
+			}
+		}
+		return true;
+	}
+	return false;
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC MN_ActivateMenu
+//
+//---------------------------------------------------------------------------
+
+void MN_ActivateMenu(void)
+{
+	if (MenuActive)
+	{
+		return;
+	}
+	if (paused)
+	{
+		S_ResumeSound();
+	}
+	MenuActive = true;
+	FileMenuKeySteal = false;
+	MenuTime = 0;
+	CurrentMenu = &MainMenu;
+	CurrentItPos = CurrentMenu->oldItPos;
+	if (!netgame && !demoplayback)
+	{
+		paused = true;
+	}
+	S_StartSound(NULL, SFX_PLATFORM_STOP);
+	slottextloaded = false; //reload the slot text, when needed
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC MN_DeactivateMenu
+//
+//---------------------------------------------------------------------------
+
+void MN_DeactivateMenu(void)
+{
+	if (CurrentMenu)
+		CurrentMenu->oldItPos = CurrentItPos;
+	MenuActive = false;
+	if (!netgame)
+	{
+		paused = false;
+	}
+	S_StartSound(NULL, SFX_PLATFORM_STOP);
+	P_ClearMessage(&players[consoleplayer]);
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC MN_DrawInfo
+//
+//---------------------------------------------------------------------------
+
+void MN_DrawInfo(void)
+{
+	V_SetPaletteBase();
+	V_DrawRawScreen((BYTE_REF) WR_CacheLumpNum(W_GetNumForName("TITLE")+InfoType, PU_CACHE));
+}
+
+
+//---------------------------------------------------------------------------
+//
+// PROC SetMenu
+//
+//---------------------------------------------------------------------------
+
+static void SetTheMenu(MenuType_t menu)
+{
+	CurrentMenu->oldItPos = CurrentItPos;
+	CurrentMenu = Menus[menu];
+	CurrentItPos = CurrentMenu->oldItPos;
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC DrawSlider
+//
+//---------------------------------------------------------------------------
+
+static void DrawSlider(Menu_t *menu, int item, int width, int slot)
+{
+	int x;
+	int y;
+	int x2;
+	int count;
+
+	x = menu->x + 24;
+	y = menu->y + 2 + (item*ITEM_HEIGHT);
+
+#ifdef RENDER3D
+	OGL_DrawPatch_CS(x-32, y, W_GetNumForName("M_SLDLT"));
+	for (x2 = x, count = width; count--; x2 += 8)
+	{
+		OGL_DrawPatch_CS(x2, y, W_GetNumForName((count & 1) ? "M_SLDMD1" : "M_SLDMD2"));
+	}
+	OGL_DrawPatch_CS(x2, y, W_GetNumForName("M_SLDRT"));
+	OGL_DrawPatch_CS(x + 4 + slot*8, y + 7, W_GetNumForName("M_SLDKB"));
+#else
+	V_DrawPatch(x-32, y, (patch_t *)W_CacheLumpName("M_SLDLT", PU_CACHE));
+	for (x2 = x, count = width; count--; x2 += 8)
+	{
+		V_DrawPatch(x2, y, (patch_t *)W_CacheLumpName((count & 1) ? "M_SLDMD1" : "M_SLDMD2", PU_CACHE));
+	}
+	V_DrawPatch(x2, y, (patch_t *)W_CacheLumpName("M_SLDRT", PU_CACHE));
+	V_DrawPatch(x + 4 + slot*8, y + 7, (patch_t *)W_CacheLumpName("M_SLDKB", PU_CACHE));
+#endif
+}
+
--- /dev/null
+++ b/ogl_def.h
@@ -1,0 +1,199 @@
+//**************************************************************************
+//**
+//** ogl_def.h
+//**
+//** $Revision: 499 $
+//** $Date: 2009-06-02 20:50:47 +0300 (Tue, 02 Jun 2009) $
+//**
+//**************************************************************************
+
+#ifndef __H2OPENGL__
+#define __H2OPENGL__
+
+#include "r_local.h"
+#include <GL/gl.h>
+
+/* whether to printf devel debug messages */
+#define OPENGL_DEBUGGING		0
+
+#if (OPENGL_DEBUGGING)
+#define OGL_DEBUG			printf
+#else	/* no debug msg : */
+#if defined (__GNUC__) && !(defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L)
+#define OGL_DEBUG(fmt, args...)		do {} while (0)
+#else
+#define OGL_DEBUG(fmt, ...)		do {} while (0)
+#endif
+#endif
+
+
+enum { VX, VY };	/* Vertex indices. */
+
+typedef struct	/* For dynamic lighting. */
+{
+	int		use;
+	mobj_t		*thing;
+	float		top, height;
+} lumobj_t;
+
+/* ScreenBits is currently unused. */
+extern int screenWidth, screenHeight, screenBits;
+
+void I_InitGraphics(void);
+void I_ShutdownGraphics(void);
+
+void OGL_InitRenderer(void);
+void OGL_InitData(void);
+void OGL_ResetData(void);
+
+void OGL_SwitchTo3DState(void);
+void OGL_Restore2DState(int step);	/* Step 1: matrices, 2: attributes. */
+void OGL_UseWhiteFog(int yes);
+
+float PointDist2D(float c[2]);
+
+void R_RenderSprite(vissprite_t *spr);
+
+/* 2D drawing routines. */
+void OGL_DrawPatch_CS(int x, int y, int lumpnum);
+void OGL_DrawPatch(int x, int y, int lumpnum);
+void OGL_DrawFuzzPatch(int x, int y, int lumpnum);
+void OGL_DrawAltFuzzPatch(int x, int y, int lumpnum);
+void OGL_DrawShadowedPatch(int x, int y, int lumpnum);
+void OGL_DrawRawScreen(int lump);	/* Raw screens are 320 x 200. */
+void OGL_DrawRawScreenOfs(int lump, float offx, float offy);
+void OGL_DrawLine(float x1, float y1, float x2, float y2, float r, float g, float b, float a);
+void OGL_DrawRect(float x, float y, float w, float h, float r, float g, float b, float a);
+void OGL_DrawRectTiled(int x, int y, int w, int h, int tw, int th);
+void OGL_DrawCutRectTiled(int x, int y, int w, int h, int tw, int th, int cx, int cy, int cw, int ch);
+void OGL_SetColor(int palidx);
+void OGL_SetColorAndAlpha(float r, float g, float b, float a);
+void OGL_DrawPSprite(int x, int y, float scale, int flip, int lump);
+
+/* Filters. */
+void OGL_SetFilter(int filter);
+int OGL_DrawFilter(void);
+
+void OGL_ShadeRect(int x, int y, int w, int h, float darkening);
+
+/* ogl_tex.c */
+typedef struct
+{
+	unsigned short	w, h;
+	short		offx, offy;
+	unsigned short	w2;		/* For split textures, width of the other part. */
+} texsize_t;
+
+extern texsize_t *lumptexsizes;		/* Sizes for all the lumps. */
+extern unsigned short *spriteheights;
+
+extern float		texw, texh;
+extern int		texmask;
+extern unsigned int	curtex;
+extern int		pallump;
+
+int FindNextPower2(int num);
+float NextPower2Ratio(int num);
+void OGL_TexInit(void);
+void OGL_TexReset(void);
+void OGL_ResetLumpTexData(void);
+void OGL_SetPaletteLump(const char *palname);
+void PalToRGB(byte *palidx, byte *rgb);
+void PalIdxToRGB(byte *pal, int idx, byte *rgb);
+unsigned int OGL_BindTexFlat(int lump);
+void OGL_SetFlat(int idx);
+void OGL_BindTexture(GLuint texname);
+
+/* Returns the OpenGL texture name. */
+GLuint OGL_PrepareTexture(int idx);
+GLuint OGL_PrepareFlat(int idx);	/* Returns the OpenGL name of the texture. */
+GLuint OGL_PrepareLightTexture(void);	/* The dynamic light map. */
+
+void OGL_SetTexture(int idx);
+unsigned int OGL_PrepareSky(int idx, boolean zeroMask);
+
+void OGL_SetSprite(int pnum);
+unsigned int OGL_PrepareSprite(int pnum);
+void OGL_NewSplitTex(int lump, GLuint part2name);
+GLuint OGL_GetOtherPart(int lump);
+
+/* Part is either 1 or 2. Part 0 means only the left side is loaded.
+ * No splittex is created in that case. Once a raw image is loaded
+ * as part 0 it must be deleted before the other part is loaded at the
+ * next loading.
+ */
+void OGL_SetRawImage(int lump, int part);
+void OGL_SetPatch(int lump);	/* No mipmaps are generated. */
+void OGL_SetNoTexture(void);
+
+int OGL_GetLumpTexWidth(int lump);
+int OGL_GetLumpTexHeight(int lump);
+int OGL_ValidTexHeight2(int width, int height);
+
+void OGL_UpdateTexParams(int mipmode);
+void OGL_UpdateRawScreenParams(int smoothing);
+
+
+/* ogl_scr.c */
+typedef struct _TargaHeader
+{
+	unsigned char	id_length, colormap_type, image_type;
+	unsigned short	colormap_index, colormap_length;
+	unsigned char	colormap_size;
+	unsigned short	x_origin, y_origin, width, height;
+	unsigned char	pixel_size, attributes;
+} TargaHeader;
+
+void OGL_GrabScreen(void);
+
+
+#include "m_bams.h"
+
+/* ogl_clip.c */
+typedef struct clipnode_s
+{
+	int			used;		/* 1 if the node is in use. */
+	struct clipnode_s	*prev, *next;	/* Previous and and nodes.  */
+	binangle		start, end;	/* The start and end angles (start < end). */
+} clipnode_t;
+
+extern clipnode_t *clipnodes;	/* The list of clipnodes. */
+extern clipnode_t *cliphead;	/* The head node. */
+
+void C_Init(void);
+void C_Ranger(void);
+void C_ClearRanges(void);
+void C_SafeAddRange(binangle startAngle, binangle endAngle);
+
+/* Add a segment relative to the current viewpoint. */
+void C_AddViewRelSeg(float x1, float y1, float x2, float y2);
+
+/* Check a segment relative to the current viewpoint. */
+int C_CheckViewRelSeg(float x1, float y1, float x2, float y2);
+
+/* Returns 1 if the specified angle is visible. */
+int C_IsAngleVisible(binangle bang);
+
+clipnode_t *C_AngleClippedBy(binangle bang);
+
+/* Returns 1 if the subsector might be visible. */
+int C_CheckSubsector(subsector_t *ssec);
+
+
+/* ogl_sky.c */
+
+/* Sky hemispheres. */
+#define SKYHEMI_UPPER		0x1
+#define SKYHEMI_LOWER		0x2
+#define SKYHEMI_JUST_CAP	0x4	/* Just draw the top or bottom cap. */
+
+typedef struct
+{
+	float	rgb[3];		/* The RGB values. */
+	short	set, use;	/* Is this set? Should be used? */
+} fadeout_t;
+
+void R_RenderSkyHemispheres(int hemis);
+
+#endif	/* __H2OPENGL__ */
+
--- /dev/null
+++ b/ogl_rl.h
@@ -1,0 +1,63 @@
+//**************************************************************************
+//**
+//** ogl_rl.h
+//**
+//** $Revision: 584 $
+//** $Date: 2012-02-17 12:01:51 +0200 (Fri, 17 Feb 2012) $
+//**
+//**************************************************************************
+
+#ifndef __OGL_REND_LIST_H__
+#define __OGL_REND_LIST_H__
+
+/* Rendquad flags. */
+#define RQF_FLAT		0x1	/* This is a flat triangle. */
+#define RQF_MASKED		0x2	/* Use the special list for masked textures. */
+#define RQF_MISSING_WALL	0x4	/* Originally this surface had no texture. */
+#define RQF_SKY_MASK		0x8	/* A sky mask triangle. */
+#define RQF_SKY_MASK_WALL	0x10	/* A sky mask wall (with skyfix). */
+#define RQF_LIGHT		0x20	/* A dynamic light. */
+#define RQF_FLOOR_FACING	0x40	/* Used for flats, the quad faces upwards. */
+
+typedef struct
+{
+	float	v1[2], v2[2];		/* Two vertices. */
+	float	top;			/* Top height. */
+	union _quadTri {
+		struct _quad {
+			float bottom;		/* Bottom height. */
+			float len;		/* Length of the quad. */
+		} q;
+		float v3[2];		/* Third vertex for flats. */
+	} u;
+	float	light;			/* Light level, as in 0 = black, 1 = fullbright. */
+	float	texoffx;		/* Texture coordinates for left/top (in real texcoords). */
+	float	texoffy;
+	short	flags;			/* RQF_*. */
+	GLuint	masktex;		/* Texture name for masked textures. */
+	unsigned short texw, texh;	/* Size of the texture. */
+	float	dist[3];		/* Distances to the vertices. */
+} rendquad_t;	/* Or flat triangle. */
+
+typedef struct
+{
+	GLuint	tex;			/* The name of the texture for this list. */
+	int		numquads;	/* Number of quads in the list. */
+	int		listsize;	/* Absolute size of the list. */
+	rendquad_t *quads;		/* The list of quads. */
+} rendlist_t;
+
+
+/* ogl_rl.c */
+
+void RL_Init(void);
+void RL_ClearLists(void);
+void RL_DeleteLists(void);
+void RL_AddQuad(rendquad_t *quad, GLuint quadtex);
+void RL_AddFlatQuads(rendquad_t *base, /* GLuint */ uintptr_t quadtex,
+				int numvrts, fvertex_t *vrts, int dir);
+void RL_RenderAllLists(void);
+void SetVertexColor(float light, float dist, float alpha);
+
+#endif	/* __OGL_REND_LIST_H__ */
+
--- /dev/null
+++ b/oss.h
@@ -1,0 +1,38 @@
+/*  XMMS - Cross-platform multimedia player
+ *  Copyright (C) 1998-1999  Peter Alm, Mikael Alm, Olle Hallnas, Thomas Nilsson and 4Front Technologies
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _SNDOSS_H
+#define _SNDOSS_H
+
+
+#include "config.h"
+#include "audio_plugin.h"
+
+
+typedef struct
+{
+	int audio_device;
+	int mixer_device;
+	int buffer_size;
+	int prebuffer;
+	int fragment_count;
+}
+OSSConfig;
+
+#endif	/* _SNDOSS_H */
+
--- /dev/null
+++ b/p_acs.c
@@ -1,0 +1,1805 @@
+
+//**************************************************************************
+//**
+//** p_acs.c : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 491 $
+//** $Date: 2009-05-30 01:10:42 +0300 (Sat, 30 May 2009) $
+//**
+//**************************************************************************
+
+// HEADER FILES ------------------------------------------------------------
+
+#include "h2stdinc.h"
+#include "h2def.h"
+#include "p_local.h"
+
+// MACROS ------------------------------------------------------------------
+
+#define SCRIPT_CONTINUE		0
+#define SCRIPT_STOP		1
+#define SCRIPT_TERMINATE	2
+
+#define OPEN_SCRIPTS_BASE	1000
+#define PRINT_BUFFER_SIZE	256
+
+#define GAME_SINGLE_PLAYER	0
+#define GAME_NET_COOPERATIVE	1
+#define GAME_NET_DEATHMATCH	2
+
+#define TEXTURE_TOP		0
+#define TEXTURE_MIDDLE		1
+#define TEXTURE_BOTTOM		2
+
+#define S_DROP		ACScript->stackPtr--
+#define S_POP		ACScript->stack[--ACScript->stackPtr]
+#define S_PUSH(x)	ACScript->stack[ACScript->stackPtr++] = (x)
+
+// TYPES -------------------------------------------------------------------
+
+typedef struct
+{
+	int marker;
+	int infoOffset;
+	int code;
+} acsHeader_t;
+
+// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
+
+// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
+
+// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
+
+static void StartOpenACS(int number, int infoIndex, byte *address);
+static void ScriptFinished(int number);
+static boolean TagBusy(int tag);
+static boolean AddToACSStore(int map, int number, byte *args);
+static int GetACSIndex(int number);
+static void Push(int value);
+static int Pop(void);
+static int Top(void);
+static void Drop(void);
+
+static int CmdNOP(void);
+static int CmdTerminate(void);
+static int CmdSuspend(void);
+static int CmdPushNumber(void);
+static int CmdLSpec1(void);
+static int CmdLSpec2(void);
+static int CmdLSpec3(void);
+static int CmdLSpec4(void);
+static int CmdLSpec5(void);
+static int CmdLSpec1Direct(void);
+static int CmdLSpec2Direct(void);
+static int CmdLSpec3Direct(void);
+static int CmdLSpec4Direct(void);
+static int CmdLSpec5Direct(void);
+static int CmdAdd(void);
+static int CmdSubtract(void);
+static int CmdMultiply(void);
+static int CmdDivide(void);
+static int CmdModulus(void);
+static int CmdEQ(void);
+static int CmdNE(void);
+static int CmdLT(void);
+static int CmdGT(void);
+static int CmdLE(void);
+static int CmdGE(void);
+static int CmdAssignScriptVar(void);
+static int CmdAssignMapVar(void);
+static int CmdAssignWorldVar(void);
+static int CmdPushScriptVar(void);
+static int CmdPushMapVar(void);
+static int CmdPushWorldVar(void);
+static int CmdAddScriptVar(void);
+static int CmdAddMapVar(void);
+static int CmdAddWorldVar(void);
+static int CmdSubScriptVar(void);
+static int CmdSubMapVar(void);
+static int CmdSubWorldVar(void);
+static int CmdMulScriptVar(void);
+static int CmdMulMapVar(void);
+static int CmdMulWorldVar(void);
+static int CmdDivScriptVar(void);
+static int CmdDivMapVar(void);
+static int CmdDivWorldVar(void);
+static int CmdModScriptVar(void);
+static int CmdModMapVar(void);
+static int CmdModWorldVar(void);
+static int CmdIncScriptVar(void);
+static int CmdIncMapVar(void);
+static int CmdIncWorldVar(void);
+static int CmdDecScriptVar(void);
+static int CmdDecMapVar(void);
+static int CmdDecWorldVar(void);
+static int CmdGoto(void);
+static int CmdIfGoto(void);
+static int CmdDrop(void);
+static int CmdDelay(void);
+static int CmdDelayDirect(void);
+static int CmdRandom(void);
+static int CmdRandomDirect(void);
+static int CmdThingCount(void);
+static int CmdThingCountDirect(void);
+static int CmdTagWait(void);
+static int CmdTagWaitDirect(void);
+static int CmdPolyWait(void);
+static int CmdPolyWaitDirect(void);
+static int CmdChangeFloor(void);
+static int CmdChangeFloorDirect(void);
+static int CmdChangeCeiling(void);
+static int CmdChangeCeilingDirect(void);
+static int CmdRestart(void);
+static int CmdAndLogical(void);
+static int CmdOrLogical(void);
+static int CmdAndBitwise(void);
+static int CmdOrBitwise(void);
+static int CmdEorBitwise(void);
+static int CmdNegateLogical(void);
+static int CmdLShift(void);
+static int CmdRShift(void);
+static int CmdUnaryMinus(void);
+static int CmdIfNotGoto(void);
+static int CmdLineSide(void);
+static int CmdScriptWait(void);
+static int CmdScriptWaitDirect(void);
+static int CmdClearLineSpecial(void);
+static int CmdCaseGoto(void);
+static int CmdBeginPrint(void);
+static int CmdEndPrint(void);
+static int CmdPrintString(void);
+static int CmdPrintNumber(void);
+static int CmdPrintCharacter(void);
+static int CmdPlayerCount(void);
+static int CmdGameType(void);
+static int CmdGameSkill(void);
+static int CmdTimer(void);
+static int CmdSectorSound(void);
+static int CmdAmbientSound(void);
+static int CmdSoundSequence(void);
+static int CmdSetLineTexture(void);
+static int CmdSetLineBlocking(void);
+static int CmdSetLineSpecial(void);
+static int CmdThingSound(void);
+static int CmdEndPrintBold(void);
+
+static void ThingCount(int type, int tid);
+
+// EXTERNAL DATA DECLARATIONS ----------------------------------------------
+
+extern const char *TextKeyMessages[11];
+
+// PUBLIC DATA DEFINITIONS -------------------------------------------------
+
+int		ACScriptCount;
+byte		*ActionCodeBase;
+acsInfo_t	*ACSInfo;
+int		MapVars[MAX_ACS_MAP_VARS];
+int		WorldVars[MAX_ACS_WORLD_VARS];
+acsstore_t	ACSStore[MAX_ACS_STORE + 1];	// +1 for termination marker
+
+// PRIVATE DATA DEFINITIONS ------------------------------------------------
+
+static acs_t	*ACScript;
+static byte	*PCodePtr;
+static byte	SpecArgs[8];
+static int	ACStringCount;
+static char	**ACStrings;
+static char	PrintBuffer[PRINT_BUFFER_SIZE];
+static acs_t	*NewScript;
+
+static int (*PCodeCmds[])(void) =
+{
+	CmdNOP,
+	CmdTerminate,
+	CmdSuspend,
+	CmdPushNumber,
+	CmdLSpec1,
+	CmdLSpec2,
+	CmdLSpec3,
+	CmdLSpec4,
+	CmdLSpec5,
+	CmdLSpec1Direct,
+	CmdLSpec2Direct,
+	CmdLSpec3Direct,
+	CmdLSpec4Direct,
+	CmdLSpec5Direct,
+	CmdAdd,
+	CmdSubtract,
+	CmdMultiply,
+	CmdDivide,
+	CmdModulus,
+	CmdEQ,
+	CmdNE,
+	CmdLT,
+	CmdGT,
+	CmdLE,
+	CmdGE,
+	CmdAssignScriptVar,
+	CmdAssignMapVar,
+	CmdAssignWorldVar,
+	CmdPushScriptVar,
+	CmdPushMapVar,
+	CmdPushWorldVar,
+	CmdAddScriptVar,
+	CmdAddMapVar,
+	CmdAddWorldVar,
+	CmdSubScriptVar,
+	CmdSubMapVar,
+	CmdSubWorldVar,
+	CmdMulScriptVar,
+	CmdMulMapVar,
+	CmdMulWorldVar,
+	CmdDivScriptVar,
+	CmdDivMapVar,
+	CmdDivWorldVar,
+	CmdModScriptVar,
+	CmdModMapVar,
+	CmdModWorldVar,
+	CmdIncScriptVar,
+	CmdIncMapVar,
+	CmdIncWorldVar,
+	CmdDecScriptVar,
+	CmdDecMapVar,
+	CmdDecWorldVar,
+	CmdGoto,
+	CmdIfGoto,
+	CmdDrop,
+	CmdDelay,
+	CmdDelayDirect,
+	CmdRandom,
+	CmdRandomDirect,
+	CmdThingCount,
+	CmdThingCountDirect,
+	CmdTagWait,
+	CmdTagWaitDirect,
+	CmdPolyWait,
+	CmdPolyWaitDirect,
+	CmdChangeFloor,
+	CmdChangeFloorDirect,
+	CmdChangeCeiling,
+	CmdChangeCeilingDirect,
+	CmdRestart,
+	CmdAndLogical,
+	CmdOrLogical,
+	CmdAndBitwise,
+	CmdOrBitwise,
+	CmdEorBitwise,
+	CmdNegateLogical,
+	CmdLShift,
+	CmdRShift,
+	CmdUnaryMinus,
+	CmdIfNotGoto,
+	CmdLineSide,
+	CmdScriptWait,
+	CmdScriptWaitDirect,
+	CmdClearLineSpecial,
+	CmdCaseGoto,
+	CmdBeginPrint,
+	CmdEndPrint,
+	CmdPrintString,
+	CmdPrintNumber,
+	CmdPrintCharacter,
+	CmdPlayerCount,
+	CmdGameType,
+	CmdGameSkill,
+	CmdTimer,
+	CmdSectorSound,
+	CmdAmbientSound,
+	CmdSoundSequence,
+	CmdSetLineTexture,
+	CmdSetLineBlocking,
+	CmdSetLineSpecial,
+	CmdThingSound,
+	CmdEndPrintBold
+};
+
+// CODE --------------------------------------------------------------------
+
+static inline int32_t ReadCodePtr (void)
+{
+	uint32_t val = READ_INT32(PCodePtr);
+	return (int32_t) val;
+}
+
+static inline void IncrCodePtr (void)
+{
+	INCR_INT32(PCodePtr);
+}
+
+static inline int32_t ReadAndIncrCodePtr (void)
+{
+	uint32_t val = READ_INT32(PCodePtr);
+	INCR_INT32(PCodePtr);
+	return (int32_t) val;
+}
+
+//==========================================================================
+//
+// P_LoadACScripts
+//
+//==========================================================================
+
+void P_LoadACScripts(int lump)
+{
+	int i;
+	int *buffer;
+	acsHeader_t *header;
+	acsInfo_t *info;
+
+	header = (acsHeader_t *) W_CacheLumpNum(lump, PU_LEVEL);
+	ActionCodeBase = (byte *)header;
+	buffer = (int *)((byte *)header + LONG(header->infoOffset));
+	ACScriptCount = LONG(*buffer++);
+	if (ACScriptCount == 0)
+	{ // Empty behavior lump
+		return;
+	}
+	ACSInfo = (acsInfo_t *) Z_Malloc(ACScriptCount*sizeof(acsInfo_t), PU_LEVEL, NULL);
+	memset(ACSInfo, 0, ACScriptCount*sizeof(acsInfo_t));
+	for (i = 0, info = ACSInfo; i < ACScriptCount; i++, info++)
+	{
+		info->number = LONG(*buffer++);
+		info->address = ActionCodeBase + LONG(*buffer++);
+		info->argCount = LONG(*buffer++);
+		if (info->number >= OPEN_SCRIPTS_BASE)
+		{ // Auto-activate
+			info->number -= OPEN_SCRIPTS_BASE;
+			StartOpenACS(info->number, i, info->address);
+			info->state = ASTE_RUNNING;
+		}
+		else
+		{
+			info->state = ASTE_INACTIVE;
+		}
+	}
+	ACStringCount = LONG(*buffer++);
+	ACStrings = (char **) Z_Malloc(ACStringCount*sizeof(char *), PU_LEVEL, NULL);
+	for (i = 0; i < ACStringCount; i++)
+	{
+		ACStrings[i] = (char *)ActionCodeBase + LONG(buffer[i]);
+	}
+	memset(MapVars, 0, sizeof(MapVars));
+}
+
+//==========================================================================
+//
+// StartOpenACS
+//
+//==========================================================================
+
+static void StartOpenACS(int number, int infoIndex, byte *address)
+{
+	acs_t *script;
+
+	script = (acs_t *) Z_Malloc(sizeof(acs_t), PU_LEVSPEC, NULL);
+	memset(script, 0, sizeof(acs_t));
+	script->number = number;
+
+	// World objects are allotted 1 second for initialization
+	script->delayCount = 35;
+
+	script->infoIndex = infoIndex;
+	script->ip = address;
+	script->thinker.function = T_InterpretACS;
+	P_AddThinker(&script->thinker);
+}
+
+//==========================================================================
+//
+// P_CheckACSStore
+//
+// Scans the ACS store and executes all scripts belonging to the current
+// map.
+//
+//==========================================================================
+
+void P_CheckACSStore(void)
+{
+	acsstore_t *store;
+
+	for (store = ACSStore; store->map != 0; store++)
+	{
+		if (store->map == gamemap)
+		{
+			P_StartACS(store->script, 0, store->args, NULL, NULL, 0);
+			if (NewScript)
+			{
+				NewScript->delayCount = 35;
+			}
+			store->map = -1;
+		}
+	}
+}
+
+//==========================================================================
+//
+// P_StartACS
+//
+//==========================================================================
+
+static char ErrorMsg[128];
+
+boolean P_StartACS(int number, int map, byte *args, mobj_t *activator,
+	line_t *line, int side)
+{
+	int i;
+	acs_t *script;
+	int infoIndex;
+	aste_t *statePtr;
+
+	NewScript = NULL;
+	if (map && map != gamemap)
+	{ // Add to the script store
+		return AddToACSStore(map, number, args);
+	}
+	infoIndex = GetACSIndex(number);
+	if (infoIndex == -1)
+	{ // Script not found
+		//I_Error("P_StartACS: Unknown script number %d", number);
+		snprintf(ErrorMsg, sizeof(ErrorMsg), "P_STARTACS ERROR: UNKNOWN SCRIPT %d", number);
+		P_SetMessage(&players[consoleplayer], ErrorMsg, true);
+	}
+	statePtr = &ACSInfo[infoIndex].state;
+	if (*statePtr == ASTE_SUSPENDED)
+	{ // Resume a suspended script
+		*statePtr = ASTE_RUNNING;
+		return true;
+	}
+	if (*statePtr != ASTE_INACTIVE)
+	{ // Script is already executing
+		return false;
+	}
+	script = (acs_t *) Z_Malloc(sizeof(acs_t), PU_LEVSPEC, NULL);
+	memset(script, 0, sizeof(acs_t));
+	script->number = number;
+	script->infoIndex = infoIndex;
+	script->activator = activator;
+	script->line = line;
+	script->side = side;
+	script->ip = ACSInfo[infoIndex].address;
+	script->thinker.function = T_InterpretACS;
+	for (i = 0; i < ACSInfo[infoIndex].argCount; i++)
+	{
+		script->vars[i] = args[i];
+	}
+	*statePtr = ASTE_RUNNING;
+	P_AddThinker(&script->thinker);
+	NewScript = script;
+	return true;
+}
+
+//==========================================================================
+//
+// AddToACSStore
+//
+//==========================================================================
+
+static boolean AddToACSStore(int map, int number, byte *args)
+{
+	int i;
+	int idx;
+
+	idx = -1;
+	for (i = 0; ACSStore[i].map != 0; i++)
+	{
+		if (ACSStore[i].script == number && ACSStore[i].map == map)
+		{ // Don't allow duplicates
+			return false;
+		}
+		if (idx == -1 && ACSStore[i].map == -1)
+		{ // Remember first empty slot
+			idx = i;
+		}
+	}
+	if (idx == -1)
+	{ // Append required
+		if (i == MAX_ACS_STORE)
+		{
+			I_Error("AddToACSStore: MAX_ACS_STORE (%d) exceeded.",
+				MAX_ACS_STORE);
+		}
+		idx = i;
+		ACSStore[idx + 1].map = 0;
+	}
+	ACSStore[idx].map = map;
+	ACSStore[idx].script = number;
+//	*((int *)ACSStore[idx].args) = *((int *)args);
+	ACSStore[idx].args[0] = args[0];
+	ACSStore[idx].args[1] = args[1];
+	ACSStore[idx].args[2] = args[2];
+	ACSStore[idx].args[3] = 0;	/* unused */
+	return true;
+}
+
+//==========================================================================
+//
+// P_StartLockedACS
+//
+//==========================================================================
+
+boolean P_StartLockedACS(line_t *line, byte *args, mobj_t *mo, int side)
+{
+	int i;
+	int lock;
+	byte newArgs[5];
+	char LockedBuffer[80];
+
+	lock = args[4];
+	if (!mo->player)
+	{
+		return false;
+	}
+	if (lock)
+	{
+		if (!(mo->player->keys & (1<<(lock-1))))
+		{
+			snprintf(LockedBuffer, sizeof(LockedBuffer),
+				 "YOU NEED THE %s\n", TextKeyMessages[lock-1]);
+			P_SetMessage(mo->player, LockedBuffer, true);
+			S_StartSound(mo, SFX_DOOR_LOCKED);
+			return false;
+		}
+	}
+	for (i = 0; i < 4; i++)
+	{
+		newArgs[i] = args[i];
+	}
+	newArgs[4] = 0;
+	return P_StartACS(newArgs[0], newArgs[1], &newArgs[2], mo, line, side);
+}
+
+//==========================================================================
+//
+// P_TerminateACS
+//
+//==========================================================================
+
+boolean P_TerminateACS(int number, int map)
+{
+	int infoIndex;
+
+	infoIndex = GetACSIndex(number);
+	if (infoIndex == -1)
+	{ // Script not found
+		return false;
+	}
+	if (ACSInfo[infoIndex].state == ASTE_INACTIVE
+		|| ACSInfo[infoIndex].state == ASTE_TERMINATING)
+	{ // States that disallow termination
+		return false;
+	}
+	ACSInfo[infoIndex].state = ASTE_TERMINATING;
+	return true;
+}
+
+//==========================================================================
+//
+// P_SuspendACS
+//
+//==========================================================================
+
+boolean P_SuspendACS(int number, int map)
+{
+	int infoIndex;
+
+	infoIndex = GetACSIndex(number);
+	if (infoIndex == -1)
+	{ // Script not found
+		return false;
+	}
+	if (ACSInfo[infoIndex].state == ASTE_INACTIVE
+		|| ACSInfo[infoIndex].state == ASTE_SUSPENDED
+		|| ACSInfo[infoIndex].state == ASTE_TERMINATING)
+	{ // States that disallow suspension
+		return false;
+	}
+	ACSInfo[infoIndex].state = ASTE_SUSPENDED;
+	return true;
+}
+
+//==========================================================================
+//
+// P_Init
+//
+//==========================================================================
+
+void P_ACSInitNewGame(void)
+{
+	memset(WorldVars, 0, sizeof(WorldVars));
+	memset(ACSStore, 0, sizeof(ACSStore));
+}
+
+//==========================================================================
+//
+// T_InterpretACS
+//
+//==========================================================================
+
+void T_InterpretACS(acs_t *script)
+{
+	int cmd;
+	int action;
+
+	if (ACSInfo[script->infoIndex].state == ASTE_TERMINATING)
+	{
+		ACSInfo[script->infoIndex].state = ASTE_INACTIVE;
+		ScriptFinished(ACScript->number);
+		P_RemoveThinker(&ACScript->thinker);
+		return;
+	}
+	if (ACSInfo[script->infoIndex].state != ASTE_RUNNING)
+	{
+		return;
+	}
+	if (script->delayCount)
+	{
+		script->delayCount--;
+		return;
+	}
+	ACScript = script;
+	PCodePtr = ACScript->ip;
+	do
+	{
+		cmd = ReadAndIncrCodePtr();
+		action = PCodeCmds[cmd]();
+	} while (action == SCRIPT_CONTINUE);
+	ACScript->ip = PCodePtr;
+	if (action == SCRIPT_TERMINATE)
+	{
+		ACSInfo[script->infoIndex].state = ASTE_INACTIVE;
+		ScriptFinished(ACScript->number);
+		P_RemoveThinker(&ACScript->thinker);
+	}
+}
+
+//==========================================================================
+//
+// P_TagFinished
+//
+//==========================================================================
+
+void P_TagFinished(int tag)
+{
+	int i;
+
+	if (TagBusy(tag) == true)
+	{
+		return;
+	}
+	for (i = 0; i < ACScriptCount; i++)
+	{
+		if (ACSInfo[i].state == ASTE_WAITINGFORTAG
+			&& ACSInfo[i].waitValue == tag)
+		{
+			ACSInfo[i].state = ASTE_RUNNING;
+		}
+	}
+}
+
+//==========================================================================
+//
+// P_PolyobjFinished
+//
+//==========================================================================
+
+void P_PolyobjFinished(int po)
+{
+	int i;
+
+	if (PO_Busy(po) == true)
+	{
+		return;
+	}
+	for (i = 0; i < ACScriptCount; i++)
+	{
+		if (ACSInfo[i].state == ASTE_WAITINGFORPOLY
+			&& ACSInfo[i].waitValue == po)
+		{
+			ACSInfo[i].state = ASTE_RUNNING;
+		}
+	}
+}
+
+//==========================================================================
+//
+// ScriptFinished
+//
+//==========================================================================
+
+static void ScriptFinished(int number)
+{
+	int i;
+
+	for (i = 0; i < ACScriptCount; i++)
+	{
+		if (ACSInfo[i].state == ASTE_WAITINGFORSCRIPT
+			&& ACSInfo[i].waitValue == number)
+		{
+			ACSInfo[i].state = ASTE_RUNNING;
+		}
+	}
+}
+
+//==========================================================================
+//
+// TagBusy
+//
+//==========================================================================
+
+static boolean TagBusy(int tag)
+{
+	int sectorIndex;
+
+	sectorIndex = -1;
+	while ((sectorIndex = P_FindSectorFromTag(tag, sectorIndex)) >= 0)
+	{
+		if (sectors[sectorIndex].specialdata)
+		{
+			return true;
+		}
+	}
+	return false;
+}
+
+//==========================================================================
+//
+// GetACSIndex
+//
+// Returns the index of a script number.  Returns -1 if the script number
+// is not found.
+//
+//==========================================================================
+
+static int GetACSIndex(int number)
+{
+	int i;
+
+	for (i = 0; i < ACScriptCount; i++)
+	{
+		if (ACSInfo[i].number == number)
+		{
+			return i;
+		}
+	}
+	return -1;
+}
+
+//==========================================================================
+//
+// Push
+//
+//==========================================================================
+
+static void Push(int value)
+{
+	ACScript->stack[ACScript->stackPtr++] = value;
+}
+
+//==========================================================================
+//
+// Pop
+//
+//==========================================================================
+
+static int Pop(void)
+{
+	return ACScript->stack[--ACScript->stackPtr];
+}
+
+//==========================================================================
+//
+// Top
+//
+//==========================================================================
+
+static int Top(void)
+{
+	return ACScript->stack[ACScript->stackPtr - 1];
+}
+
+//==========================================================================
+//
+// Drop
+//
+//==========================================================================
+
+static void Drop(void)
+{
+	ACScript->stackPtr--;
+}
+
+//==========================================================================
+//
+// P-Code Commands
+//
+//==========================================================================
+
+static int CmdNOP(void)
+{
+	return SCRIPT_CONTINUE;
+}
+
+static int CmdTerminate(void)
+{
+	return SCRIPT_TERMINATE;
+}
+
+static int CmdSuspend(void)
+{
+	ACSInfo[ACScript->infoIndex].state = ASTE_SUSPENDED;
+	return SCRIPT_STOP;
+}
+
+static int CmdPushNumber(void)
+{
+	Push(ReadAndIncrCodePtr());
+	return SCRIPT_CONTINUE;
+}
+
+static int CmdLSpec1(void)
+{
+	int special;
+
+	special = ReadAndIncrCodePtr();
+	SpecArgs[0] = Pop();
+	P_ExecuteLineSpecial(special, SpecArgs, ACScript->line,
+			ACScript->side, ACScript->activator);
+	return SCRIPT_CONTINUE;
+}
+
+static int CmdLSpec2(void)
+{
+	int special;
+
+	special = ReadAndIncrCodePtr();
+	SpecArgs[1] = Pop();
+	SpecArgs[0] = Pop();
+	P_ExecuteLineSpecial(special, SpecArgs, ACScript->line,
+			ACScript->side, ACScript->activator);
+	return SCRIPT_CONTINUE;
+}
+
+static int CmdLSpec3(void)
+{
+	int special;
+
+	special = ReadAndIncrCodePtr();
+	SpecArgs[2] = Pop();
+	SpecArgs[1] = Pop();
+	SpecArgs[0] = Pop();
+	P_ExecuteLineSpecial(special, SpecArgs, ACScript->line,
+			ACScript->side, ACScript->activator);
+	return SCRIPT_CONTINUE;
+}
+
+static int CmdLSpec4(void)
+{
+	int special;
+
+	special = ReadAndIncrCodePtr();
+	SpecArgs[3] = Pop();
+	SpecArgs[2] = Pop();
+	SpecArgs[1] = Pop();
+	SpecArgs[0] = Pop();
+	P_ExecuteLineSpecial(special, SpecArgs, ACScript->line,
+			ACScript->side, ACScript->activator);
+	return SCRIPT_CONTINUE;
+}
+
+static int CmdLSpec5(void)
+{
+	int special;
+
+	special = ReadAndIncrCodePtr();
+	SpecArgs[4] = Pop();
+	SpecArgs[3] = Pop();
+	SpecArgs[2] = Pop();
+	SpecArgs[1] = Pop();
+	SpecArgs[0] = Pop();
+	P_ExecuteLineSpecial(special, SpecArgs, ACScript->line,
+			ACScript->side, ACScript->activator);
+	return SCRIPT_CONTINUE;
+}
+
+static int CmdLSpec1Direct(void)
+{
+	int special;
+
+	special = ReadAndIncrCodePtr();
+	SpecArgs[0] = ReadAndIncrCodePtr();
+	P_ExecuteLineSpecial(special, SpecArgs, ACScript->line,
+			ACScript->side, ACScript->activator);
+	return SCRIPT_CONTINUE;
+}
+
+static int CmdLSpec2Direct(void)
+{
+	int special;
+
+	special = ReadAndIncrCodePtr();
+	SpecArgs[0] = ReadAndIncrCodePtr();
+	SpecArgs[1] = ReadAndIncrCodePtr();
+	P_ExecuteLineSpecial(special, SpecArgs, ACScript->line,
+			ACScript->side, ACScript->activator);
+	return SCRIPT_CONTINUE;
+}
+
+static int CmdLSpec3Direct(void)
+{
+	int special;
+
+	special = ReadAndIncrCodePtr();
+	SpecArgs[0] = ReadAndIncrCodePtr();
+	SpecArgs[1] = ReadAndIncrCodePtr();
+	SpecArgs[2] = ReadAndIncrCodePtr();
+	P_ExecuteLineSpecial(special, SpecArgs, ACScript->line,
+			ACScript->side, ACScript->activator);
+	return SCRIPT_CONTINUE;
+}
+
+static int CmdLSpec4Direct(void)
+{
+	int special;
+
+	special = ReadAndIncrCodePtr();
+	SpecArgs[0] = ReadAndIncrCodePtr();
+	SpecArgs[1] = ReadAndIncrCodePtr();
+	SpecArgs[2] = ReadAndIncrCodePtr();
+	SpecArgs[3] = ReadAndIncrCodePtr();
+	P_ExecuteLineSpecial(special, SpecArgs, ACScript->line,
+			ACScript->side, ACScript->activator);
+	return SCRIPT_CONTINUE;
+}
+
+static int CmdLSpec5Direct(void)
+{
+	int special;
+
+	special = ReadAndIncrCodePtr();
+	SpecArgs[0] = ReadAndIncrCodePtr();
+	SpecArgs[1] = ReadAndIncrCodePtr();
+	SpecArgs[2] = ReadAndIncrCodePtr();
+	SpecArgs[3] = ReadAndIncrCodePtr();
+	SpecArgs[4] = ReadAndIncrCodePtr();
+	P_ExecuteLineSpecial(special, SpecArgs, ACScript->line,
+			ACScript->side, ACScript->activator);
+	return SCRIPT_CONTINUE;
+}
+
+static int CmdAdd(void)
+{
+	Push (Pop() + Pop());
+	return SCRIPT_CONTINUE;
+}
+
+static int CmdSubtract(void)
+{
+	int operand2;
+
+	operand2 = Pop();
+	Push (Pop() - operand2);
+	return SCRIPT_CONTINUE;
+}
+
+static int CmdMultiply(void)
+{
+	Push (Pop() * Pop());
+	return SCRIPT_CONTINUE;
+}
+
+static int CmdDivide(void)
+{
+	int operand2;
+
+	operand2 = Pop();
+	Push (Pop() / operand2);
+	return SCRIPT_CONTINUE;
+}
+
+static int CmdModulus(void)
+{
+	int operand2;
+
+	operand2 = Pop();
+	Push (Pop() % operand2);
+	return SCRIPT_CONTINUE;
+}
+
+static int CmdEQ(void)
+{
+	Push (Pop() == Pop());
+	return SCRIPT_CONTINUE;
+}
+
+static int CmdNE(void)
+{
+	Push (Pop() != Pop());
+	return SCRIPT_CONTINUE;
+}
+
+static int CmdLT(void)
+{
+	int operand2;
+
+	operand2 = Pop();
+	Push (Pop() < operand2);
+	return SCRIPT_CONTINUE;
+}
+
+static int CmdGT(void)
+{
+	int operand2;
+
+	operand2 = Pop();
+	Push (Pop() > operand2);
+	return SCRIPT_CONTINUE;
+}
+
+static int CmdLE(void)
+{
+	int operand2;
+
+	operand2 = Pop();
+	Push (Pop() <= operand2);
+	return SCRIPT_CONTINUE;
+}
+
+static int CmdGE(void)
+{
+	int operand2;
+
+	operand2 = Pop();
+	Push (Pop() >= operand2);
+	return SCRIPT_CONTINUE;
+}
+
+static int CmdAssignScriptVar(void)
+{
+	ACScript->vars[ReadAndIncrCodePtr()] = Pop();
+	return SCRIPT_CONTINUE;
+}
+
+static int CmdAssignMapVar(void)
+{
+	MapVars[ReadAndIncrCodePtr()] = Pop();
+	return SCRIPT_CONTINUE;
+}
+
+static int CmdAssignWorldVar(void)
+{
+	WorldVars[ReadAndIncrCodePtr()] = Pop();
+	return SCRIPT_CONTINUE;
+}
+
+static int CmdPushScriptVar(void)
+{
+	Push(ACScript->vars[ReadAndIncrCodePtr()]);
+	return SCRIPT_CONTINUE;
+}
+
+static int CmdPushMapVar(void)
+{
+	Push(MapVars[ReadAndIncrCodePtr()]);
+	return SCRIPT_CONTINUE;
+}
+
+static int CmdPushWorldVar(void)
+{
+	Push(WorldVars[ReadAndIncrCodePtr()]);
+	return SCRIPT_CONTINUE;
+}
+
+static int CmdAddScriptVar(void)
+{
+	ACScript->vars[ReadAndIncrCodePtr()] += Pop();
+	return SCRIPT_CONTINUE;
+}
+
+static int CmdAddMapVar(void)
+{
+	MapVars[ReadAndIncrCodePtr()] += Pop();
+	return SCRIPT_CONTINUE;
+}
+
+static int CmdAddWorldVar(void)
+{
+	WorldVars[ReadAndIncrCodePtr()] += Pop();
+	return SCRIPT_CONTINUE;
+}
+
+static int CmdSubScriptVar(void)
+{
+	ACScript->vars[ReadAndIncrCodePtr()] -= Pop();
+	return SCRIPT_CONTINUE;
+}
+
+static int CmdSubMapVar(void)
+{
+	MapVars[ReadAndIncrCodePtr()] -= Pop();
+	return SCRIPT_CONTINUE;
+}
+
+static int CmdSubWorldVar(void)
+{
+	WorldVars[ReadAndIncrCodePtr()] -= Pop();
+	return SCRIPT_CONTINUE;
+}
+
+static int CmdMulScriptVar(void)
+{
+	ACScript->vars[ReadAndIncrCodePtr()] *= Pop();
+	return SCRIPT_CONTINUE;
+}
+
+static int CmdMulMapVar(void)
+{
+	MapVars[ReadAndIncrCodePtr()] *= Pop();
+	return SCRIPT_CONTINUE;
+}
+
+static int CmdMulWorldVar(void)
+{
+	WorldVars[ReadAndIncrCodePtr()] *= Pop();
+	return SCRIPT_CONTINUE;
+}
+
+static int CmdDivScriptVar(void)
+{
+	ACScript->vars[ReadAndIncrCodePtr()] /= Pop();
+	return SCRIPT_CONTINUE;
+}
+
+static int CmdDivMapVar(void)
+{
+	MapVars[ReadAndIncrCodePtr()] /= Pop();
+	return SCRIPT_CONTINUE;
+}
+
+static int CmdDivWorldVar(void)
+{
+	WorldVars[ReadAndIncrCodePtr()] /= Pop();
+	return SCRIPT_CONTINUE;
+}
+
+static int CmdModScriptVar(void)
+{
+	ACScript->vars[ReadAndIncrCodePtr()] %= Pop();
+	return SCRIPT_CONTINUE;
+}
+
+static int CmdModMapVar(void)
+{
+	MapVars[ReadAndIncrCodePtr()] %= Pop();
+	return SCRIPT_CONTINUE;
+}
+
+static int CmdModWorldVar(void)
+{
+	WorldVars[ReadAndIncrCodePtr()] %= Pop();
+	return SCRIPT_CONTINUE;
+}
+
+static int CmdIncScriptVar(void)
+{
+	ACScript->vars[ReadAndIncrCodePtr()]++;
+	return SCRIPT_CONTINUE;
+}
+
+static int CmdIncMapVar(void)
+{
+	MapVars[ReadAndIncrCodePtr()]++;
+	return SCRIPT_CONTINUE;
+}
+
+static int CmdIncWorldVar(void)
+{
+	WorldVars[ReadAndIncrCodePtr()]++;
+	return SCRIPT_CONTINUE;
+}
+
+static int CmdDecScriptVar(void)
+{
+	ACScript->vars[ReadAndIncrCodePtr()]--;
+	return SCRIPT_CONTINUE;
+}
+
+static int CmdDecMapVar(void)
+{
+	MapVars[ReadAndIncrCodePtr()]--;
+	return SCRIPT_CONTINUE;
+}
+
+static int CmdDecWorldVar(void)
+{
+	WorldVars[ReadAndIncrCodePtr()]--;
+	return SCRIPT_CONTINUE;
+}
+
+static int CmdGoto(void)
+{
+	PCodePtr = ActionCodeBase + ReadCodePtr();
+	return SCRIPT_CONTINUE;
+}
+
+static int CmdIfGoto(void)
+{
+	if (Pop())
+	{
+		PCodePtr = ActionCodeBase + ReadCodePtr();
+	}
+	else
+	{
+		IncrCodePtr();
+	}
+	return SCRIPT_CONTINUE;
+}
+
+static int CmdDrop(void)
+{
+	Drop();
+	return SCRIPT_CONTINUE;
+}
+
+static int CmdDelay(void)
+{
+	ACScript->delayCount = Pop();
+	return SCRIPT_STOP;
+}
+
+static int CmdDelayDirect(void)
+{
+	ACScript->delayCount = ReadAndIncrCodePtr();
+	return SCRIPT_STOP;
+}
+
+static int CmdRandom(void)
+{
+	int low;
+	int high;
+
+	high = Pop();
+	low = Pop();
+	Push (low + (P_Random() % (high - low + 1)));
+	return SCRIPT_CONTINUE;
+}
+
+static int CmdRandomDirect(void)
+{
+	int low;
+	int high;
+
+	low = ReadAndIncrCodePtr();
+	high = ReadAndIncrCodePtr();
+	Push (low + (P_Random() % (high - low + 1)));
+	return SCRIPT_CONTINUE;
+}
+
+static int CmdThingCount(void)
+{
+	int tid;
+
+	tid = Pop();
+	ThingCount(Pop(), tid);
+	return SCRIPT_CONTINUE;
+}
+
+static int CmdThingCountDirect(void)
+{
+	int type;
+
+	type = ReadAndIncrCodePtr();
+	ThingCount(type, ReadAndIncrCodePtr());
+	return SCRIPT_CONTINUE;
+}
+
+static void ThingCount(int type, int tid)
+{
+	int count;
+	int searcher;
+	mobj_t *mobj;
+	mobjtype_t moType;
+	thinker_t *think;
+
+	if (!(type + tid))
+	{ // Nothing to count
+		return;
+	}
+	moType = TranslateThingType[type];
+	count = 0;
+	searcher = -1;
+	if (tid)
+	{ // Count TID things
+		while ((mobj = P_FindMobjFromTID(tid, &searcher)) != NULL)
+		{
+			if (type == 0)
+			{ // Just count TIDs
+				count++;
+			}
+			else if (moType == mobj->type)
+			{
+				if (mobj->flags & MF_COUNTKILL && mobj->health <= 0)
+				{ // Don't count dead monsters
+					continue;
+				}
+				count++;
+			}
+		}
+	}
+	else
+	{ // Count only types
+		for (think = thinkercap.next; think != &thinkercap;
+						think = think->next)
+		{
+			if (think->function != P_MobjThinker)
+			{ // Not a mobj thinker
+				continue;
+			}
+			mobj = (mobj_t *)think;
+			if (mobj->type != moType)
+			{ // Doesn't match
+				continue;
+			}
+			if (mobj->flags & MF_COUNTKILL && mobj->health <= 0)
+			{ // Don't count dead monsters
+				continue;
+			}
+			count++;
+		}
+	}
+	Push(count);
+}
+
+static int CmdTagWait(void)
+{
+	ACSInfo[ACScript->infoIndex].waitValue = Pop();
+	ACSInfo[ACScript->infoIndex].state = ASTE_WAITINGFORTAG;
+	return SCRIPT_STOP;
+}
+
+static int CmdTagWaitDirect(void)
+{
+	ACSInfo[ACScript->infoIndex].waitValue = ReadAndIncrCodePtr();
+	ACSInfo[ACScript->infoIndex].state = ASTE_WAITINGFORTAG;
+	return SCRIPT_STOP;
+}
+
+static int CmdPolyWait(void)
+{
+	ACSInfo[ACScript->infoIndex].waitValue = Pop();
+	ACSInfo[ACScript->infoIndex].state = ASTE_WAITINGFORPOLY;
+	return SCRIPT_STOP;
+}
+
+static int CmdPolyWaitDirect(void)
+{
+	ACSInfo[ACScript->infoIndex].waitValue = ReadAndIncrCodePtr();
+	ACSInfo[ACScript->infoIndex].state = ASTE_WAITINGFORPOLY;
+	return SCRIPT_STOP;
+}
+
+static int CmdChangeFloor(void)
+{
+	int tag;
+	int flat;
+	int sectorIndex;
+
+	flat = R_FlatNumForName(ACStrings[Pop()]);
+	tag = Pop();
+	sectorIndex = -1;
+	while ((sectorIndex = P_FindSectorFromTag(tag, sectorIndex)) >= 0)
+	{
+		sectors[sectorIndex].floorpic = flat;
+	}
+	return SCRIPT_CONTINUE;
+}
+
+static int CmdChangeFloorDirect(void)
+{
+	int tag;
+	int flat;
+	int sectorIndex;
+
+	tag = ReadAndIncrCodePtr();
+	flat = R_FlatNumForName(ACStrings[ReadAndIncrCodePtr()]);
+	sectorIndex = -1;
+	while ((sectorIndex = P_FindSectorFromTag(tag, sectorIndex)) >= 0)
+	{
+		sectors[sectorIndex].floorpic = flat;
+	}
+	return SCRIPT_CONTINUE;
+}
+
+static int CmdChangeCeiling(void)
+{
+	int tag;
+	int flat;
+	int sectorIndex;
+
+	flat = R_FlatNumForName(ACStrings[Pop()]);
+	tag = Pop();
+	sectorIndex = -1;
+	while ((sectorIndex = P_FindSectorFromTag(tag, sectorIndex)) >= 0)
+	{
+		sectors[sectorIndex].ceilingpic = flat;
+	}
+	return SCRIPT_CONTINUE;
+}
+
+static int CmdChangeCeilingDirect(void)
+{
+	int tag;
+	int flat;
+	int sectorIndex;
+
+	tag = ReadAndIncrCodePtr();
+	flat = R_FlatNumForName(ACStrings[ReadAndIncrCodePtr()]);
+	sectorIndex = -1;
+	while ((sectorIndex = P_FindSectorFromTag(tag, sectorIndex)) >= 0)
+	{
+		sectors[sectorIndex].ceilingpic = flat;
+	}
+	return SCRIPT_CONTINUE;
+}
+
+static int CmdRestart(void)
+{
+	PCodePtr = ACSInfo[ACScript->infoIndex].address;
+	return SCRIPT_CONTINUE;
+}
+
+static int CmdAndLogical(void)
+{
+	Push (Pop() && Pop());
+	return SCRIPT_CONTINUE;
+}
+
+static int CmdOrLogical(void)
+{
+	Push (Pop() || Pop());
+	return SCRIPT_CONTINUE;
+}
+
+static int CmdAndBitwise(void)
+{
+	Push (Pop() & Pop());
+	return SCRIPT_CONTINUE;
+}
+
+static int CmdOrBitwise(void)
+{
+	Push (Pop() | Pop());
+	return SCRIPT_CONTINUE;
+}
+
+static int CmdEorBitwise(void)
+{
+	Push (Pop() ^ Pop());
+	return SCRIPT_CONTINUE;
+}
+
+static int CmdNegateLogical(void)
+{
+	Push (!Pop());
+	return SCRIPT_CONTINUE;
+}
+
+static int CmdLShift(void)
+{
+	int operand2;
+
+	operand2 = Pop();
+	Push (Pop() << operand2);
+	return SCRIPT_CONTINUE;
+}
+
+static int CmdRShift(void)
+{
+	int operand2;
+
+	operand2 = Pop();
+	Push (Pop() >> operand2);
+	return SCRIPT_CONTINUE;
+}
+
+static int CmdUnaryMinus(void)
+{
+	Push (-Pop());
+	return SCRIPT_CONTINUE;
+}
+
+static int CmdIfNotGoto(void)
+{
+	if (Pop())
+	{
+		IncrCodePtr();
+	}
+	else
+	{
+		PCodePtr = ActionCodeBase + ReadCodePtr();
+	}
+	return SCRIPT_CONTINUE;
+}
+
+static int CmdLineSide(void)
+{
+	Push(ACScript->side);
+	return SCRIPT_CONTINUE;
+}
+
+static int CmdScriptWait(void)
+{
+	ACSInfo[ACScript->infoIndex].waitValue = Pop();
+	ACSInfo[ACScript->infoIndex].state = ASTE_WAITINGFORSCRIPT;
+	return SCRIPT_STOP;
+}
+
+static int CmdScriptWaitDirect(void)
+{
+	ACSInfo[ACScript->infoIndex].waitValue = ReadAndIncrCodePtr();
+	ACSInfo[ACScript->infoIndex].state = ASTE_WAITINGFORSCRIPT;
+	return SCRIPT_STOP;
+}
+
+static int CmdClearLineSpecial(void)
+{
+	if (ACScript->line)
+	{
+		ACScript->line->special = 0;
+	}
+	return SCRIPT_CONTINUE;
+}
+
+static int CmdCaseGoto(void)
+{
+	if (Top() == ReadAndIncrCodePtr())
+	{
+		PCodePtr = ActionCodeBase + ReadCodePtr();
+		Drop();
+	}
+	else
+	{
+		IncrCodePtr();
+	}
+	return SCRIPT_CONTINUE;
+}
+
+static int CmdBeginPrint(void)
+{
+	*PrintBuffer = 0;
+	return SCRIPT_CONTINUE;
+}
+
+static int CmdEndPrint(void)
+{
+	player_t *player;
+
+	if (ACScript->activator && ACScript->activator->player)
+	{
+		player = ACScript->activator->player;
+	}
+	else
+	{
+		player = &players[consoleplayer];
+	}
+	P_SetMessage(player, PrintBuffer, true);
+	return SCRIPT_CONTINUE;
+}
+
+static int CmdEndPrintBold(void)
+{
+	int i;
+
+	for (i = 0; i < MAXPLAYERS; i++)
+	{
+		if (playeringame[i])
+		{
+			P_SetYellowMessage(&players[i], PrintBuffer, true);
+		}
+	}
+	return SCRIPT_CONTINUE;
+}
+
+static int CmdPrintString(void)
+{
+	strcat(PrintBuffer, ACStrings[Pop()]);
+	return SCRIPT_CONTINUE;
+}
+
+static int CmdPrintNumber(void)
+{
+	char tempStr[16];
+
+	snprintf(tempStr, sizeof(tempStr), "%d", Pop());
+	strcat(PrintBuffer, tempStr);
+	return SCRIPT_CONTINUE;
+}
+
+static int CmdPrintCharacter(void)
+{
+	char *bufferEnd;
+
+	bufferEnd = PrintBuffer + strlen(PrintBuffer);
+	*bufferEnd++ = Pop();
+	*bufferEnd = 0;
+	return SCRIPT_CONTINUE;
+}
+
+static int CmdPlayerCount(void)
+{
+	int i;
+	int count;
+
+	count = 0;
+	for (i = 0; i < MAXPLAYERS; i++)
+	{
+		count += playeringame[i];
+	}
+	Push(count);
+	return SCRIPT_CONTINUE;
+}
+
+static int CmdGameType(void)
+{
+	int gametype;
+
+	if (netgame == false)
+	{
+		gametype = GAME_SINGLE_PLAYER;
+	}
+	else if (deathmatch)
+	{
+		gametype = GAME_NET_DEATHMATCH;
+	}
+	else
+	{
+		gametype = GAME_NET_COOPERATIVE;
+	}
+	Push(gametype);
+	return SCRIPT_CONTINUE;
+}
+
+static int CmdGameSkill(void)
+{
+	Push(gameskill);
+	return SCRIPT_CONTINUE;
+}
+
+static int CmdTimer(void)
+{
+	Push(leveltime);
+	return SCRIPT_CONTINUE;
+}
+
+static int CmdSectorSound(void)
+{
+	int volume;
+	mobj_t *mobj;
+
+	mobj = NULL;
+	if (ACScript->line)
+	{
+		mobj = (mobj_t *)(void *)&ACScript->line->frontsector->soundorg;
+	}
+	volume = Pop();
+	S_StartSoundAtVolume(mobj, S_GetSoundID(ACStrings[Pop()]), volume);
+	return SCRIPT_CONTINUE;
+}
+
+static int CmdThingSound(void)
+{
+	int tid;
+	int sound;
+	int volume;
+	mobj_t *mobj;
+	int searcher;
+
+	volume = Pop();
+	sound = S_GetSoundID(ACStrings[Pop()]);
+	tid = Pop();
+	searcher = -1;
+	while ((mobj = P_FindMobjFromTID(tid, &searcher)) != NULL)
+	{
+		S_StartSoundAtVolume(mobj, sound, volume);
+	}
+	return SCRIPT_CONTINUE;
+}
+
+static int CmdAmbientSound(void)
+{
+	int volume;
+
+	volume = Pop();
+	S_StartSoundAtVolume(NULL, S_GetSoundID(ACStrings[Pop()]), volume);
+	return SCRIPT_CONTINUE;
+}
+
+static int CmdSoundSequence(void)
+{
+	mobj_t *mobj;
+
+	mobj = NULL;
+	if (ACScript->line)
+	{
+		mobj = (mobj_t *)(void *)&ACScript->line->frontsector->soundorg;
+	}
+	SN_StartSequenceName(mobj, ACStrings[Pop()]);
+	return SCRIPT_CONTINUE;
+}
+
+static int CmdSetLineTexture(void)
+{
+	line_t *line;
+	int lineTag;
+	int side;
+	int position;
+	int texture;
+	int searcher;
+
+	texture = R_TextureNumForName(ACStrings[Pop()]);
+	position = Pop();
+	side = Pop();
+	lineTag = Pop();
+	searcher = -1;
+	while ((line = P_FindLine(lineTag, &searcher)) != NULL)
+	{
+		if (position == TEXTURE_MIDDLE)
+		{
+			sides[line->sidenum[side]].midtexture = texture;
+		}
+		else if (position == TEXTURE_BOTTOM)
+		{
+			sides[line->sidenum[side]].bottomtexture = texture;
+		}
+		else
+		{ // TEXTURE_TOP
+			sides[line->sidenum[side]].toptexture = texture;
+		}
+	}
+	return SCRIPT_CONTINUE;
+}
+
+static int CmdSetLineBlocking(void)
+{
+	line_t *line;
+	int lineTag;
+	boolean blocking;
+	int searcher;
+
+	blocking = Pop() ? ML_BLOCKING : 0;
+	lineTag = Pop();
+	searcher = -1;
+	while ((line = P_FindLine(lineTag, &searcher)) != NULL)
+	{
+		line->flags = (line->flags & ~ML_BLOCKING) | blocking;
+	}
+	return SCRIPT_CONTINUE;
+}
+
+static int CmdSetLineSpecial(void)
+{
+	line_t *line;
+	int lineTag;
+	int special, arg1, arg2, arg3, arg4, arg5;
+	int searcher;
+
+	arg5 = Pop();
+	arg4 = Pop();
+	arg3 = Pop();
+	arg2 = Pop();
+	arg1 = Pop();
+	special = Pop();
+	lineTag = Pop();
+	searcher = -1;
+	while ((line = P_FindLine(lineTag, &searcher)) != NULL)
+	{
+		line->special = special;
+		line->arg1 = arg1;
+		line->arg2 = arg2;
+		line->arg3 = arg3;
+		line->arg4 = arg4;
+		line->arg5 = arg5;
+	}
+	return SCRIPT_CONTINUE;
+}
+
--- /dev/null
+++ b/p_anim.c
@@ -1,0 +1,476 @@
+
+//**************************************************************************
+//**
+//** p_anim.c : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 373 $
+//** $Date: 2009-05-19 21:14:28 +0300 (Tue, 19 May 2009) $
+//**
+//**************************************************************************
+
+// HEADER FILES ------------------------------------------------------------
+
+#include "h2stdinc.h"
+#include "h2def.h"
+#include "p_local.h"
+
+// MACROS ------------------------------------------------------------------
+
+#define ANIM_SCRIPT_NAME	"ANIMDEFS"
+
+#define MAX_ANIM_DEFS		20
+#define MAX_FRAME_DEFS		96
+
+#define ANIM_FLAT		0
+#define ANIM_TEXTURE		1
+
+#define SCI_FLAT		"flat"
+#define SCI_TEXTURE		"texture"
+#define SCI_PIC			"pic"
+#define SCI_TICS		"tics"
+#define SCI_RAND		"rand"
+
+#define LIGHTNING_SPECIAL	198
+#define LIGHTNING_SPECIAL2	199
+#define SKYCHANGE_SPECIAL	200
+
+// TYPES -------------------------------------------------------------------
+
+typedef struct
+{
+	int index;
+	int tics;
+} frameDef_t;
+
+typedef struct
+{
+	int type;
+	int index;
+	int tics;
+	int currentFrameDef;
+	int startFrameDef;
+	int endFrameDef;
+} animDef_t;
+
+// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
+
+// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
+
+// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
+
+static void P_LightningFlash(void);
+
+// EXTERNAL DATA DECLARATIONS ----------------------------------------------
+
+extern fixed_t		Sky1ColumnOffset;
+extern fixed_t		Sky2ColumnOffset;
+extern int		Sky1Texture;
+extern boolean		DoubleSky;
+
+// PUBLIC DATA DEFINITIONS -------------------------------------------------
+
+fixed_t			Sky1ScrollDelta;
+fixed_t			Sky2ScrollDelta;
+
+// PRIVATE DATA DEFINITIONS ------------------------------------------------
+
+static animDef_t	AnimDefs[MAX_ANIM_DEFS];
+static frameDef_t	FrameDefs[MAX_FRAME_DEFS];
+static int		AnimDefCount;
+static boolean		LevelHasLightning;
+static int		NextLightningFlash;
+static int		LightningFlash;
+static int		*LightningLightLevels;
+
+// CODE --------------------------------------------------------------------
+
+//==========================================================================
+//
+// P_AnimateSurfaces
+//
+//==========================================================================
+
+void P_AnimateSurfaces(void)
+{
+	int i;
+	animDef_t *ad;
+	line_t *line;
+
+	// Animate flats and textures
+	for (i = 0; i < AnimDefCount; i++)
+	{
+		ad = &AnimDefs[i];
+		ad->tics--;
+		if (ad->tics == 0)
+		{
+			if (ad->currentFrameDef == ad->endFrameDef)
+			{
+				ad->currentFrameDef = ad->startFrameDef;
+			}
+			else
+			{
+				ad->currentFrameDef++;
+			}
+			ad->tics = FrameDefs[ad->currentFrameDef].tics;
+			if (ad->tics > 255)
+			{ // Random tics
+				ad->tics = (ad->tics>>16)
+					+ P_Random() % ((ad->tics & 0xff00)>>8);
+			}
+			if (ad->type == ANIM_FLAT)
+			{
+				flattranslation[ad->index] =
+					FrameDefs[ad->currentFrameDef].index;
+			}
+			else
+			{ // Texture
+				texturetranslation[ad->index] =
+					FrameDefs[ad->currentFrameDef].index;
+			}
+		}
+	}
+
+	// Update scrolling textures
+	for (i = 0; i < numlinespecials; i++)
+	{
+		line = linespeciallist[i];
+		switch (line->special)
+		{
+		case 100: // Scroll_Texture_Left
+			sides[line->sidenum[0]].textureoffset += line->arg1<<10;
+			break;
+		case 101: // Scroll_Texture_Right
+			sides[line->sidenum[0]].textureoffset -= line->arg1<<10;
+			break;
+		case 102: // Scroll_Texture_Up
+			sides[line->sidenum[0]].rowoffset += line->arg1<<10;
+			break;
+		case 103: // Scroll_Texture_Down
+			sides[line->sidenum[0]].rowoffset -= line->arg1<<10;
+			break;
+		}
+	}
+
+	// Update sky column offsets
+	Sky1ColumnOffset += Sky1ScrollDelta;
+	Sky2ColumnOffset += Sky2ScrollDelta;
+
+	if (LevelHasLightning)
+	{
+		if (!NextLightningFlash || LightningFlash)
+		{
+			P_LightningFlash();
+		}
+		else
+		{
+			NextLightningFlash--;
+		}
+	}
+}
+
+//==========================================================================
+//
+// P_LightningFlash
+//
+//==========================================================================
+
+static void P_LightningFlash(void)
+{
+	int i;
+	sector_t *tempSec;
+	int *tempLight;
+	boolean foundSec;
+	int flashLight;
+
+	if (LightningFlash)
+	{
+		LightningFlash--;
+		if (LightningFlash)
+		{
+			tempLight = LightningLightLevels;
+			tempSec = sectors;
+			for (i = 0; i < numsectors; i++, tempSec++)
+			{
+				if (tempSec->ceilingpic == skyflatnum
+					|| tempSec->special == LIGHTNING_SPECIAL
+					|| tempSec->special == LIGHTNING_SPECIAL2)
+				{
+					if (*tempLight < tempSec->lightlevel - 4)
+					{
+						tempSec->lightlevel -= 4;
+					}
+					tempLight++;
+				}
+			}
+		}
+		else
+		{ // remove the alternate lightning flash special
+			tempLight = LightningLightLevels;
+			tempSec = sectors;
+			for (i = 0; i < numsectors; i++, tempSec++)
+			{
+				if (tempSec->ceilingpic == skyflatnum
+					|| tempSec->special == LIGHTNING_SPECIAL
+					|| tempSec->special == LIGHTNING_SPECIAL2)
+				{
+					tempSec->lightlevel = *tempLight;
+					tempLight++;
+				}
+			}
+			Sky1Texture = P_GetMapSky1Texture(gamemap);
+		}
+		return;
+	}
+	LightningFlash = (P_Random() & 7) + 8;
+	flashLight = 200 + (P_Random() & 31);
+	tempSec = sectors;
+	tempLight = LightningLightLevels;
+	foundSec = false;
+	for (i = 0; i < numsectors; i++, tempSec++)
+	{
+		if (tempSec->ceilingpic == skyflatnum
+			|| tempSec->special == LIGHTNING_SPECIAL
+			|| tempSec->special == LIGHTNING_SPECIAL2)
+		{
+			*tempLight = tempSec->lightlevel;
+			if (tempSec->special == LIGHTNING_SPECIAL)
+			{
+				tempSec->lightlevel += 64;
+				if (tempSec->lightlevel > flashLight)
+				{
+					tempSec->lightlevel = flashLight;
+				}
+			}
+			else if (tempSec->special == LIGHTNING_SPECIAL2)
+			{
+				tempSec->lightlevel += 32;
+				if (tempSec->lightlevel > flashLight)
+				{
+					tempSec->lightlevel = flashLight;
+				}
+			}
+			else
+			{
+				tempSec->lightlevel = flashLight;
+			}
+			if (tempSec->lightlevel < *tempLight)
+			{
+				tempSec->lightlevel = *tempLight;
+			}
+			tempLight++;
+			foundSec = true;
+		}
+	}
+	if (foundSec)
+	{
+		Sky1Texture = P_GetMapSky2Texture(gamemap); // set alternate sky
+		S_StartSound(NULL, SFX_THUNDER_CRASH);
+	}
+	// Calculate the next lighting flash
+	if (!NextLightningFlash)
+	{
+		if (P_Random() < 50)
+		{ // Immediate Quick flash
+			NextLightningFlash = (P_Random() & 15) + 16;
+		}
+		else
+		{
+			if (P_Random() < 128 && !(leveltime & 32))
+			{
+				NextLightningFlash = ((P_Random() & 7) + 2)*35;
+			}
+			else
+			{
+				NextLightningFlash = ((P_Random() & 15) + 5)*35;
+			}
+		}
+	}
+}
+
+//==========================================================================
+//
+// P_ForceLightning
+//
+//==========================================================================
+
+void P_ForceLightning(void)
+{
+	NextLightningFlash = 0;
+}
+
+//==========================================================================
+//
+// P_InitLightning
+//
+//==========================================================================
+
+void P_InitLightning(void)
+{
+	int i;
+	int secCount;
+
+	if (!P_GetMapLightning(gamemap))
+	{
+		LevelHasLightning = false;
+		LightningFlash = 0;
+		return;
+	}
+	LightningFlash = 0;
+	secCount = 0;
+	for (i = 0; i < numsectors; i++)
+	{
+		if (sectors[i].ceilingpic == skyflatnum
+			|| sectors[i].special == LIGHTNING_SPECIAL
+			|| sectors[i].special == LIGHTNING_SPECIAL2)
+		{
+			secCount++;
+		}
+	}
+	if (secCount)
+	{
+		LevelHasLightning = true;
+	}
+	else
+	{
+		LevelHasLightning = false;
+		return;
+	}
+	LightningLightLevels = (int *)Z_Malloc(secCount*sizeof(int), PU_LEVEL, NULL);
+	NextLightningFlash = ((P_Random() & 15) + 5)*35; // don't flash at level start
+}
+
+//==========================================================================
+//
+// P_InitFTAnims
+//
+// Initialize flat and texture animation lists.
+//
+//==========================================================================
+
+void P_InitFTAnims(void)
+{
+	int base;
+	int mod;
+	int fd;
+	animDef_t *ad;
+	boolean ignore;
+	boolean done;
+
+	fd = 0;
+	ad = AnimDefs;
+	AnimDefCount = 0;
+	SC_Open(ANIM_SCRIPT_NAME);
+	while (SC_GetString())
+	{
+		if (AnimDefCount == MAX_ANIM_DEFS)
+		{
+			I_Error("P_InitFTAnims: too many AnimDefs.");
+		}
+		if (SC_Compare(SCI_FLAT))
+		{
+			ad->type = ANIM_FLAT;
+		}
+		else if (SC_Compare(SCI_TEXTURE))
+		{
+			ad->type = ANIM_TEXTURE;
+		}
+		else
+		{
+			SC_ScriptError(NULL);
+		}
+		SC_MustGetString(); // Name
+		ignore = false;
+		if (ad->type == ANIM_FLAT)
+		{
+			if (W_CheckNumForName(sc_String) == -1)
+			{
+				ignore = true;
+			}
+			else
+			{
+				ad->index = R_FlatNumForName(sc_String);
+			}
+		}
+		else
+		{ // Texture
+			if (R_CheckTextureNumForName(sc_String) == -1)
+			{
+				ignore = true;
+			}
+			else
+			{
+				ad->index = R_TextureNumForName(sc_String);
+			}
+		}
+		ad->startFrameDef = fd;
+		done = false;
+		while (done == false)
+		{
+			if (SC_GetString())
+			{
+				if (SC_Compare(SCI_PIC))
+				{
+					if (fd == MAX_FRAME_DEFS)
+					{
+						I_Error("P_InitFTAnims: too many FrameDefs.");
+					}
+					SC_MustGetNumber();
+					if (ignore == false)
+					{
+						FrameDefs[fd].index = ad->index + sc_Number - 1;
+					}
+					SC_MustGetString();
+					if (SC_Compare(SCI_TICS))
+					{
+						SC_MustGetNumber();
+						if (ignore == false)
+						{
+							FrameDefs[fd].tics = sc_Number;
+							fd++;
+						}
+					}
+					else if (SC_Compare(SCI_RAND))
+					{
+						SC_MustGetNumber();
+						base = sc_Number;
+						SC_MustGetNumber();
+						if (ignore == false)
+						{
+							mod = sc_Number-base + 1;
+							FrameDefs[fd].tics = (base<<16) + (mod<<8);
+							fd++;
+						}
+					}
+					else
+					{
+						SC_ScriptError(NULL);
+					}
+				}
+				else
+				{
+					SC_UnGet();
+					done = true;
+				}
+			}
+			else
+			{
+				done = true;
+			}
+		}
+		if ((ignore == false) && (fd - ad->startFrameDef < 2))
+		{
+			I_Error("P_InitFTAnims: AnimDef has framecount < 2.");
+		}
+		if (ignore == false)
+		{
+			ad->endFrameDef = fd - 1;
+			ad->currentFrameDef = ad->endFrameDef;
+			ad->tics = 1; // Force 1st game tic to animate
+			AnimDefCount++;
+			ad++;
+		}
+	}
+
+	SC_Close();
+}
+
--- /dev/null
+++ b/p_ceilng.c
@@ -1,0 +1,303 @@
+
+//**************************************************************************
+//**
+//** p_ceilng.c : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 472 $
+//** $Date: 2009-05-26 15:45:18 +0300 (Tue, 26 May 2009) $
+//**
+//**************************************************************************
+
+#include "h2stdinc.h"
+#include "h2def.h"
+#include "p_local.h"
+#include "soundst.h"
+
+//==================================================================
+//
+// CEILINGS
+//
+//==================================================================
+
+ceiling_t	*activeceilings[MAXCEILINGS];
+
+//==================================================================
+//
+// T_MoveCeiling
+//
+//==================================================================
+
+void T_MoveCeiling (ceiling_t *ceiling)
+{
+	result_e	res;
+
+	switch (ceiling->direction)
+	{
+//	case 0: // IN STASIS
+//		break;
+
+	case 1: // UP
+		res = T_MovePlane(ceiling->sector, ceiling->speed,
+				  ceiling->topheight, false, 1, ceiling->direction);
+		if (res == RES_PASTDEST)
+		{
+			SN_StopSequence((mobj_t *)(void *)&ceiling->sector->soundorg);
+			switch (ceiling->type)
+			{
+			case CLEV_CRUSHANDRAISE:
+				ceiling->direction = -1;
+				ceiling->speed = ceiling->speed*2;
+				break;
+			default:
+				P_RemoveActiveCeiling(ceiling);
+				break;
+			}
+		}
+		break;
+
+	case -1: // DOWN
+		res = T_MovePlane(ceiling->sector, ceiling->speed,
+				  ceiling->bottomheight, ceiling->crush, 1, ceiling->direction);
+		if (res == RES_PASTDEST)
+		{
+			SN_StopSequence((mobj_t *)(void *)&ceiling->sector->soundorg);
+			switch (ceiling->type)
+			{
+			case CLEV_CRUSHANDRAISE:
+			case CLEV_CRUSHRAISEANDSTAY:
+				ceiling->direction = 1;
+				ceiling->speed = ceiling->speed/2;
+				break;
+			default:
+				P_RemoveActiveCeiling(ceiling);
+				break;
+			}
+		} 
+		else if (res == RES_CRUSHED)
+		{
+			switch (ceiling->type)
+			{
+			case CLEV_CRUSHANDRAISE:
+			case CLEV_LOWERANDCRUSH:
+			case CLEV_CRUSHRAISEANDSTAY:
+				//ceiling->speed = ceiling->speed/4;
+				break;
+			default:
+				break;
+			}
+		}
+		break;
+	}
+}
+
+//==================================================================
+//
+// EV_DoCeiling
+// Move a ceiling up/down and all around!
+//
+//==================================================================
+
+int EV_DoCeiling (line_t *line, byte *arg, ceiling_e type)
+{
+	int		secnum, rtn;
+	sector_t	*sec;
+	ceiling_t	*ceiling;
+
+	secnum = -1;
+	rtn = 0;
+
+/* Old Ceiling stasis code
+	//
+	// Reactivate in-stasis ceilings...for certain types.
+	//
+	switch (type)
+	{
+	case CLEV_CRUSHANDRAISE:
+		P_ActivateInStasisCeiling(line);
+	default:
+		break;
+	}
+*/
+	while ((secnum = P_FindSectorFromTag(arg[0], secnum)) >= 0)
+	{
+		sec = &sectors[secnum];
+		if (sec->specialdata)
+			continue;
+
+		//
+		// new door thinker
+		//
+		rtn = 1;
+		ceiling = (ceiling_t *) Z_Malloc (sizeof(*ceiling), PU_LEVSPEC, NULL);
+		P_AddThinker (&ceiling->thinker);
+		sec->specialdata = ceiling;
+		ceiling->thinker.function = T_MoveCeiling;
+		ceiling->sector = sec;
+		ceiling->crush = 0;
+		ceiling->speed = arg[1]*(FRACUNIT/8);
+		switch (type)
+		{
+		case CLEV_CRUSHRAISEANDSTAY:
+			ceiling->crush = arg[2]; // arg[2] = crushing value
+			ceiling->topheight = sec->ceilingheight;
+			ceiling->bottomheight = sec->floorheight + (8*FRACUNIT);
+			ceiling->direction = -1;
+			break;
+		case CLEV_CRUSHANDRAISE:
+			ceiling->topheight = sec->ceilingheight;
+		case CLEV_LOWERANDCRUSH:
+			ceiling->crush = arg[2]; // arg[2] = crushing value
+		case CLEV_LOWERTOFLOOR:
+			ceiling->bottomheight = sec->floorheight;
+			if (type != CLEV_LOWERTOFLOOR)
+			{
+				ceiling->bottomheight += 8*FRACUNIT;
+			}
+			ceiling->direction = -1;
+			break;
+		case CLEV_RAISETOHIGHEST:
+			ceiling->topheight = P_FindHighestCeilingSurrounding(sec);
+			ceiling->direction = 1;
+			break;
+		case CLEV_LOWERBYVALUE:
+			ceiling->bottomheight = sec->ceilingheight-arg[2]*FRACUNIT;
+			ceiling->direction = -1;
+			break;
+		case CLEV_RAISEBYVALUE:
+			ceiling->topheight = sec->ceilingheight+arg[2]*FRACUNIT;
+			ceiling->direction = 1;
+			break;
+		case CLEV_MOVETOVALUETIMES8:
+		    {	int destHeight = arg[2]*FRACUNIT*8;
+			if (arg[3])
+			{
+				destHeight = -destHeight;
+			}
+			if (sec->ceilingheight <= destHeight)
+			{
+				ceiling->direction = 1;
+				ceiling->topheight = destHeight;
+				if (sec->ceilingheight == destHeight)
+				{
+					rtn = 0;
+				}
+			}
+			else if (sec->ceilingheight > destHeight)
+			{
+				ceiling->direction = -1;
+				ceiling->bottomheight = destHeight;
+			}
+			break;
+		    }
+		default:
+			rtn = 0;
+			break;
+		}
+		ceiling->tag = sec->tag;
+		ceiling->type = type;
+		P_AddActiveCeiling(ceiling);
+		if (rtn)
+		{
+			SN_StartSequence((mobj_t *)(void *)&ceiling->sector->soundorg,
+					 SEQ_PLATFORM + ceiling->sector->seqType);
+		}
+	}
+	return rtn;
+}
+
+//==================================================================
+//
+// Add an active ceiling
+//
+//==================================================================
+
+void P_AddActiveCeiling(ceiling_t *c)
+{
+	int		i;
+	for (i = 0; i < MAXCEILINGS; i++)
+	{
+		if (activeceilings[i] == NULL)
+		{
+			activeceilings[i] = c;
+			return;
+		}
+	}
+}
+
+//==================================================================
+//
+// Remove a ceiling's thinker
+//
+//==================================================================
+
+void P_RemoveActiveCeiling(ceiling_t *c)
+{
+	int		i;
+
+	for (i = 0; i < MAXCEILINGS; i++)
+	{
+		if (activeceilings[i] == c)
+		{
+			activeceilings[i]->sector->specialdata = NULL;
+			P_RemoveThinker (&activeceilings[i]->thinker);
+			P_TagFinished(activeceilings[i]->sector->tag);
+			activeceilings[i] = NULL;
+			break;
+		}
+	}
+}
+
+#if 0
+//==================================================================
+//
+// Restart a ceiling that's in-stasis
+//
+//==================================================================
+
+void P_ActivateInStasisCeiling(line_t *line)
+{
+	int	i;
+
+	for (i = 0; i < MAXCEILINGS; i++)
+	{
+		if (activeceilings[i] && (activeceilings[i]->tag == line->arg1) &&
+			(activeceilings[i]->direction == 0))
+		{
+			activeceilings[i]->direction = activeceilings[i]->olddirection;
+			activeceilings[i]->thinker.function = T_MoveCeiling;
+			SN_StartSequence((mobj_t *)(void *)&activeceilings[i]->sector->soundorg,
+					SEQ_PLATFORM + activeceilings[i]->sector->seqType);
+		}
+	}
+}
+#endif
+
+//==================================================================
+//
+// EV_CeilingCrushStop
+// Stop a ceiling from crushing!
+//
+//==================================================================
+
+int EV_CeilingCrushStop(line_t *line, byte *args)
+{
+	int		i;
+	int		rtn;
+
+	rtn = 0;
+	for (i = 0; i < MAXCEILINGS; i++)
+	{
+		if (activeceilings[i] && activeceilings[i]->tag == args[0])
+		{
+			rtn = 1;
+			SN_StopSequence((mobj_t*)(void *)&activeceilings[i]->sector->soundorg);
+			activeceilings[i]->sector->specialdata = NULL;
+			P_RemoveThinker (&activeceilings[i]->thinker);
+			P_TagFinished(activeceilings[i]->sector->tag);
+			activeceilings[i] = NULL;
+			break;
+		}
+	}
+	return rtn;
+}
+
--- /dev/null
+++ b/p_doors.c
@@ -1,0 +1,314 @@
+
+//**************************************************************************
+//**
+//** p_doors.c : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 575 $
+//** $Date: 2011-04-13 22:06:28 +0300 (Wed, 13 Apr 2011) $
+//**
+//**************************************************************************
+
+#include "h2stdinc.h"
+#include "h2def.h"
+#include "p_local.h"
+#include "soundst.h"
+
+//==================================================================
+//
+// VERTICAL DOORS
+//
+//==================================================================
+
+//==================================================================
+//
+// T_VerticalDoor
+//
+//==================================================================
+
+void T_VerticalDoor(vldoor_t *door)
+{
+	result_e res;
+
+	switch (door->direction)
+	{
+	case 0: // WAITING
+		if (!--door->topcountdown)
+		{
+			switch (door->type)
+			{
+			case DREV_NORMAL:
+				door->direction = -1; // time to go back down
+				SN_StartSequence((mobj_t *)(void *)&door->sector->soundorg,
+						SEQ_DOOR_STONE + door->sector->seqType);
+				break;
+			case DREV_CLOSE30THENOPEN:
+				door->direction = 1;
+				break;
+			default:
+				break;
+			}
+		}
+		break;
+	case 2: // INITIAL WAIT
+		if (!--door->topcountdown)
+		{
+			switch (door->type)
+			{
+			case DREV_RAISEIN5MINS:
+				door->direction = 1;
+				door->type = DREV_NORMAL;
+				break;
+			default:
+				break;
+			}
+		}
+		break;
+	case -1: // DOWN
+		res = T_MovePlane(door->sector, door->speed,
+				  door->sector->floorheight, false, 1, door->direction);
+		if (res == RES_PASTDEST)
+		{
+			SN_StopSequence((mobj_t *)(void *)&door->sector->soundorg);
+			switch (door->type)
+			{
+			case DREV_NORMAL:
+			case DREV_CLOSE:
+				door->sector->specialdata = NULL;
+				P_TagFinished(door->sector->tag);
+				P_RemoveThinker(&door->thinker);  // unlink and free
+				break;
+			case DREV_CLOSE30THENOPEN:
+				door->direction = 0;
+				door->topcountdown = 35*30;
+				break;
+			default:
+				break;
+			}
+		}
+		else if (res == RES_CRUSHED)
+		{
+			switch (door->type)
+			{
+			case DREV_CLOSE: // DON'T GO BACK UP!
+				break;
+			default:
+				door->direction = 1;
+				break;
+			}
+		}
+		break;
+	case 1: // UP
+		res = T_MovePlane(door->sector, door->speed,
+				  door->topheight, false, 1, door->direction);
+		if (res == RES_PASTDEST)
+		{
+			SN_StopSequence((mobj_t *)(void *)&door->sector->soundorg);
+			switch (door->type)
+			{
+			case DREV_NORMAL:
+				door->direction = 0; // wait at top
+				door->topcountdown = door->topwait;
+				break;
+			case DREV_CLOSE30THENOPEN:
+			case DREV_OPEN:
+				door->sector->specialdata = NULL;
+				P_TagFinished(door->sector->tag);
+				P_RemoveThinker (&door->thinker); // unlink and free
+				break;
+			default:
+				break;
+			}
+		}
+		break;
+	}
+}
+
+//----------------------------------------------------------------------------
+//
+// EV_DoDoor
+//
+// Move a door up/down
+//
+//----------------------------------------------------------------------------
+
+int EV_DoDoor(line_t *line, byte *args, vldoor_e type)
+{
+	int secnum;
+	int retcode;
+	sector_t *sec;
+	vldoor_t *door;
+	fixed_t speed;
+
+	speed = args[1]*FRACUNIT/8;
+	secnum = -1;
+	retcode = 0;
+	while ((secnum = P_FindSectorFromTag(args[0], secnum)) >= 0)
+	{
+		sec = &sectors[secnum];
+		if (sec->specialdata)
+		{
+			continue;
+		}
+		// Add new door thinker
+		retcode = 1;
+		door = (vldoor_t *) Z_Malloc(sizeof(*door), PU_LEVSPEC, NULL);
+		P_AddThinker(&door->thinker);
+		sec->specialdata = door;
+		door->thinker.function = T_VerticalDoor;
+		door->sector = sec;
+		switch (type)
+		{
+		case DREV_CLOSE:
+			door->topheight = P_FindLowestCeilingSurrounding(sec);
+			door->topheight -= 4*FRACUNIT;
+			door->direction = -1;
+			break;
+		case DREV_CLOSE30THENOPEN:
+			door->topheight = sec->ceilingheight;
+			door->direction = -1;
+			break;
+		case DREV_NORMAL:
+		case DREV_OPEN:
+			door->direction = 1;
+			door->topheight = P_FindLowestCeilingSurrounding(sec);
+			door->topheight -= 4*FRACUNIT;
+			break;
+		default:
+			break;
+		}
+		door->type = type;
+		door->speed = speed;
+		door->topwait = args[2]; // line->arg3
+		SN_StartSequence((mobj_t *)(void *)&door->sector->soundorg,
+				 SEQ_DOOR_STONE + door->sector->seqType);
+	}
+	return retcode;
+}
+
+//==================================================================
+//
+// EV_VerticalDoor : open a door manually, no tag value
+//
+//==================================================================
+
+boolean EV_VerticalDoor(line_t *line, mobj_t *thing)
+{
+	sector_t	*sec;
+	vldoor_t	*door;
+	int		side;
+
+	side = 0; // only front sides can be used
+
+	// if the sector has an active thinker, use it
+	sec = sides[line->sidenum[side^1]].sector;
+	if (sec->specialdata)
+	{
+		return false;
+		/*
+		door = sec->specialdata;
+		switch (line->special)
+		{	// only for raise doors
+		case 12:
+			if (door->direction == -1)
+			{
+				door->direction = 1; // go back up
+			}
+			else
+			{
+				if (!thing->player)
+				{ // Monsters don't close doors
+					return;
+				}
+				door->direction = -1; // start going down immediately
+			}
+			return;
+		}
+		*/
+	}
+	//
+	// new door thinker
+	//
+	door = (vldoor_t *) Z_Malloc (sizeof(*door), PU_LEVSPEC, NULL);
+	P_AddThinker(&door->thinker);
+	sec->specialdata = door;
+	door->thinker.function = T_VerticalDoor;
+	door->sector = sec;
+	door->direction = 1;
+	switch (line->special)
+	{
+	case 11:
+		door->type = DREV_OPEN;
+		line->special = 0;
+		break;
+	case 12:
+	case 13:
+		door->type = DREV_NORMAL;
+		break;
+	default:
+		door->type = DREV_NORMAL;
+		break;
+	}
+	door->speed = line->arg2*(FRACUNIT/8);
+	door->topwait = line->arg3;
+
+	//
+	// find the top and bottom of the movement range
+	//
+	door->topheight = P_FindLowestCeilingSurrounding(sec);
+	door->topheight -= 4*FRACUNIT;
+	SN_StartSequence((mobj_t *)(void *)&door->sector->soundorg,
+			 SEQ_DOOR_STONE + door->sector->seqType);
+	return true;
+}
+
+//==================================================================
+//
+// Spawn a door that closes after 30 seconds
+//
+//==================================================================
+
+/*
+void P_SpawnDoorCloseIn30(sector_t *sec)
+{
+	vldoor_t *door;
+
+	door = (vldoor_t *) Z_Malloc(sizeof(*door), PU_LEVSPEC, NULL);
+	P_AddThinker(&door->thinker);
+	sec->specialdata = door;
+	sec->special = 0;
+	door->thinker.function = T_VerticalDoor;
+	door->sector = sec;
+	door->direction = 0;
+	door->type = DREV_NORMAL;
+	door->speed = VDOORSPEED;
+	door->topcountdown = 30*35;
+}
+*/
+
+//==================================================================
+//
+// Spawn a door that opens after 5 minutes
+//
+//==================================================================
+
+/*
+void P_SpawnDoorRaiseIn5Mins(sector_t *sec, int secnum)
+{
+	vldoor_t *door;
+
+	door = (vldoor_t *) Z_Malloc(sizeof(*door), PU_LEVSPEC, NULL);
+	P_AddThinker(&door->thinker);
+	sec->specialdata = door;
+	sec->special = 0;
+	door->thinker.function = T_VerticalDoor;
+	door->sector = sec;
+	door->direction = 2;
+	door->type = DREV_RAISEIN5MINS;
+	door->speed = VDOORSPEED;
+	door->topheight = P_FindLowestCeilingSurrounding(sec);
+	door->topheight -= 4*FRACUNIT;
+	door->topwait = VDOORWAIT;
+	door->topcountdown = 5*60*35;
+}
+*/
+
--- /dev/null
+++ b/p_enemy.c
@@ -1,0 +1,5264 @@
+
+//**************************************************************************
+//**
+//** p_enemy.c : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 596 $
+//** $Date: 2013-03-16 02:24:28 +0200 (Sat, 16 Mar 2013) $
+//**
+//**************************************************************************
+
+#include "h2stdinc.h"
+#include "h2def.h"
+#include "p_local.h"
+#include "soundst.h"
+
+// Macros
+// Types
+// Private Data
+static mobj_t	*soundtarget;
+// External Data
+extern fixed_t	FloatBobOffsets[64];
+
+
+//----------------------------------------------------------------------------
+//
+// PROC P_RecursiveSound
+//
+//----------------------------------------------------------------------------
+
+static void P_RecursiveSound(sector_t *sec, int soundblocks)
+{
+	int i;
+	line_t *check;
+	sector_t *other;
+
+	// Wake up all monsters in this sector
+	if (sec->validcount == validcount && sec->soundtraversed <= soundblocks + 1)
+	{ // Already flooded
+		return;
+	}
+	sec->validcount = validcount;
+	sec->soundtraversed = soundblocks + 1;
+	sec->soundtarget = soundtarget;
+	for (i = 0; i < sec->linecount; i++)
+	{
+		check = sec->lines[i];
+		if (!(check->flags & ML_TWOSIDED))
+		{
+			continue;
+		}
+		P_LineOpening(check);
+		if (openrange <= 0)
+		{ // Closed door
+			continue;
+		}
+		if (sides[check->sidenum[0]].sector == sec)
+		{
+			other = sides[check->sidenum[1]].sector;
+		}
+		else
+		{
+			other = sides[check->sidenum[0]].sector;
+		}
+		if (check->flags & ML_SOUNDBLOCK)
+		{
+			if (!soundblocks)
+			{
+				P_RecursiveSound(other, 1);
+			}
+		}
+		else
+		{
+			P_RecursiveSound(other, soundblocks);
+		}
+	}
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC P_NoiseAlert
+//
+// If a monster yells at a player, it will alert other monsters to the
+// player.
+//
+//----------------------------------------------------------------------------
+
+void P_NoiseAlert(mobj_t *target, mobj_t *emmiter)
+{
+	soundtarget = target;
+	validcount++;
+	P_RecursiveSound(emmiter->subsector->sector, 0);
+}
+
+//----------------------------------------------------------------------------
+//
+// FUNC P_CheckMeleeRange
+//
+//----------------------------------------------------------------------------
+
+static boolean P_CheckMeleeRange(mobj_t *actor)
+{
+	mobj_t *mo;
+	fixed_t dist;
+
+	if (!actor->target)
+	{
+		return false;
+	}
+	mo = actor->target;
+	dist = P_AproxDistance(mo->x - actor->x, mo->y - actor->y);
+	if (dist >= MELEERANGE)
+	{
+		return false;
+	}
+	if (!P_CheckSight(actor, mo))
+	{
+		return false;
+	}
+	if (mo->z > actor->z + actor->height)
+	{ // Target is higher than the attacker
+		return false;
+	}
+	else if (actor->z > mo->z + mo->height)
+	{ // Attacker is higher
+		return false;
+	}
+	return true;
+}
+
+//----------------------------------------------------------------------------
+//
+// FUNC P_CheckMeleeRange2
+//
+//----------------------------------------------------------------------------
+
+static boolean P_CheckMeleeRange2(mobj_t *actor)
+{
+	mobj_t *mo;
+	fixed_t dist;
+
+	if (!actor->target)
+	{
+		return false;
+	}
+	mo = actor->target;
+	dist = P_AproxDistance(mo->x - actor->x, mo->y - actor->y);
+	if (dist >= MELEERANGE*2 || dist < MELEERANGE)
+	{
+		return false;
+	}
+	if (!P_CheckSight(actor, mo))
+	{
+		return false;
+	}
+	if (mo->z > actor->z + actor->height)
+	{ // Target is higher than the attacker
+		return false;
+	}
+	else if (actor->z > mo->z + mo->height)
+	{ // Attacker is higher
+		return false;
+	}
+	return true;
+}
+
+//----------------------------------------------------------------------------
+//
+// FUNC P_CheckMissileRange
+//
+//----------------------------------------------------------------------------
+
+static boolean P_CheckMissileRange(mobj_t *actor)
+{
+	fixed_t dist;
+
+	if (!P_CheckSight(actor, actor->target))
+	{
+		return false;
+	}
+	if (actor->flags & MF_JUSTHIT)
+	{ // The target just hit the enemy, so fight back!
+		actor->flags &= ~MF_JUSTHIT;
+		return true;
+	}
+	if (actor->reactiontime)
+	{ // Don't attack yet
+		return false;
+	}
+	dist = (P_AproxDistance(actor->x - actor->target->x,
+		actor->y - actor->target->y)>>FRACBITS) - 64;
+	if (!actor->info->meleestate)
+	{ // No melee attack, so fire more frequently
+		dist -= 128;
+	}
+	if (dist > 200)
+	{
+		dist = 200;
+	}
+	if (P_Random() < dist)
+	{
+		return false;
+	}
+	return true;
+}
+
+/*
+================
+=
+= P_Move
+=
+= Move in the current direction
+= returns false if the move is blocked
+================
+*/
+
+static fixed_t xspeed[8] = {FRACUNIT,47000,0,-47000,-FRACUNIT,-47000,0,47000};
+static fixed_t yspeed[8] = {0,47000,FRACUNIT,47000,0,-47000,-FRACUNIT,-47000};
+
+#define MAXSPECIALCROSS		8
+extern line_t	*spechit[MAXSPECIALCROSS];
+extern int			numspechit;
+
+static boolean P_Move(mobj_t *actor)
+{
+	fixed_t tryx, tryy;
+	line_t *ld;
+	boolean good;
+
+	if (actor->flags2 & MF2_BLASTED)
+		return true;
+	if (actor->movedir == DI_NODIR)
+	{
+		return false;
+	}
+	tryx = actor->x + actor->info->speed * xspeed[actor->movedir];
+	tryy = actor->y + actor->info->speed * yspeed[actor->movedir];
+	if (!P_TryMove(actor, tryx, tryy))
+	{ // open any specials
+		if (actor->flags & MF_FLOAT && floatok)
+		{ // must adjust height
+			if (actor->z < tmfloorz)
+			{
+				actor->z += FLOATSPEED;
+			}
+			else
+			{
+				actor->z -= FLOATSPEED;
+			}
+			actor->flags |= MF_INFLOAT;
+			return true;
+		}
+		if (!numspechit)
+		{
+			return false;
+		}
+		actor->movedir = DI_NODIR;
+		good = false;
+		while (numspechit--)
+		{
+			ld = spechit[numspechit];
+			// if the special isn't a door that can be opened, return false
+			if (P_ActivateLine(ld, actor, 0, SPAC_USE))
+			{
+				good = true;
+			}
+/* Old version before use/cross/impact specials were combined
+			if (P_UseSpecialLine(actor, ld))
+			{
+				good = true;
+			}
+*/
+		}
+		return good;
+	}
+	else
+	{
+		actor->flags &= ~MF_INFLOAT;
+	}
+	if (!(actor->flags & MF_FLOAT))
+	{
+		if (actor->z > actor->floorz)
+		{
+			P_HitFloor(actor);
+		}
+		actor->z = actor->floorz;
+	}
+	return true;
+}
+
+//----------------------------------------------------------------------------
+//
+// FUNC P_TryWalk
+//
+// Attempts to move actor in its current (ob->moveangle) direction.
+// If blocked by either a wall or an actor returns FALSE.
+// If move is either clear of block only by a door, returns TRUE and sets.
+// If a door is in the way, an OpenDoor call is made to start it opening.
+//
+//----------------------------------------------------------------------------
+
+static boolean P_TryWalk(mobj_t *actor)
+{
+	if (!P_Move(actor))
+	{
+		return false;
+	}
+	actor->movecount = P_Random() & 15;
+	return true;
+}
+
+/*
+================
+=
+= P_NewChaseDir
+=
+================
+*/
+
+static dirtype_t opposite[] =
+{
+	DI_WEST, DI_SOUTHWEST, DI_SOUTH, DI_SOUTHEAST,
+	DI_EAST, DI_NORTHEAST, DI_NORTH, DI_NORTHWEST,
+	DI_NODIR
+};
+
+static dirtype_t diags[] =
+{
+	DI_NORTHWEST,
+	DI_NORTHEAST,
+	DI_SOUTHWEST,
+	DI_SOUTHEAST
+};
+
+static void P_NewChaseDir (mobj_t *actor)
+{
+	fixed_t		deltax, deltay;
+	dirtype_t	d[3];
+	dirtype_t	tdir, olddir, turnaround;
+
+	if (!actor->target)
+		I_Error ("P_NewChaseDir: called with no target");
+
+	olddir = actor->movedir;
+	turnaround = opposite[olddir];
+
+	deltax = actor->target->x - actor->x;
+	deltay = actor->target->y - actor->y;
+	if (deltax > 10*FRACUNIT)
+		d[1] = DI_EAST;
+	else if (deltax < -10*FRACUNIT)
+		d[1] = DI_WEST;
+	else
+		d[1] = DI_NODIR;
+	if (deltay < -10*FRACUNIT)
+		d[2] = DI_SOUTH;
+	else if (deltay > 10*FRACUNIT)
+		d[2] = DI_NORTH;
+	else
+		d[2] = DI_NODIR;
+
+// try direct route
+	if (d[1] != DI_NODIR && d[2] != DI_NODIR)
+	{
+		actor->movedir = diags[((deltay < 0)<<1) + (deltax > 0)];
+		if (actor->movedir != turnaround && P_TryWalk(actor))
+			return;
+	}
+
+// try other directions
+	if (P_Random() > 200 || abs(deltay) > abs(deltax))
+	{
+		tdir = d[1];
+		d[1] = d[2];
+		d[2] = tdir;
+	}
+
+	if (d[1] == turnaround)
+		d[1] = DI_NODIR;
+	if (d[2] == turnaround)
+		d[2] = DI_NODIR;
+
+	if (d[1] != DI_NODIR)
+	{
+		actor->movedir = d[1];
+		if (P_TryWalk(actor))
+			return;	/* either moved forward or attacked */
+	}
+
+	if (d[2] != DI_NODIR)
+	{
+		actor->movedir = d[2];
+		if (P_TryWalk(actor))
+			return;
+	}
+
+/* there is no direct path to the player, so pick another direction */
+
+	if (olddir != DI_NODIR)
+	{
+		actor->movedir = olddir;
+		if (P_TryWalk(actor))
+			return;
+	}
+
+	if (P_Random() & 1)	/* randomly determine direction of search */
+	{
+		for (tdir = DI_EAST; tdir <= DI_SOUTHEAST; tdir++)
+		{
+			if (tdir != turnaround)
+			{
+				actor->movedir = tdir;
+				if (P_TryWalk(actor))
+					return;
+			}
+		}
+	}
+	else
+	{
+		for (tdir = DI_SOUTHEAST; (int)tdir >= DI_EAST; tdir--)
+		{
+			if (tdir != turnaround)
+			{
+				actor->movedir = tdir;
+				if (P_TryWalk(actor))
+					return;
+			}
+		}
+	}
+
+	if (turnaround != DI_NODIR)
+	{
+		actor->movedir = turnaround;
+		if (P_TryWalk(actor))
+			return;
+	}
+
+	actor->movedir = DI_NODIR;		// can't move
+}
+
+//---------------------------------------------------------------------------
+//
+// FUNC P_LookForMonsters
+//
+//---------------------------------------------------------------------------
+
+#define MONS_LOOK_RANGE		(16 * 64 * FRACUNIT)
+#define MONS_LOOK_LIMIT		64
+
+static boolean P_LookForMonsters(mobj_t *actor)
+{
+	int count;
+	mobj_t *mo;
+	thinker_t *think;
+
+	if (!P_CheckSight(players[0].mo, actor))
+	{ // Player can't see monster
+		return false;
+	}
+	count = 0;
+	for (think = thinkercap.next; think != &thinkercap; think = think->next)
+	{
+		if (think->function != P_MobjThinker)
+		{ // Not a mobj thinker
+			continue;
+		}
+		mo = (mobj_t *)think;
+		if (!(mo->flags & MF_COUNTKILL) || (mo == actor) || (mo->health <= 0))
+		{ // Not a valid monster
+			continue;
+		}
+		if (P_AproxDistance(actor->x - mo->x, actor->y - mo->y) > MONS_LOOK_RANGE)
+		{ // Out of range
+			continue;
+		}
+		if (P_Random() < 16)
+		{ // Skip
+			continue;
+		}
+		if (count++ > MONS_LOOK_LIMIT)
+		{ // Stop searching
+			return false;
+		}
+		if (!P_CheckSight(actor, mo))
+		{ // Out of sight
+			continue;
+		}
+		if (actor->type == MT_MINOTAUR)
+		{
+			if ((mo->type == MT_MINOTAUR) && 
+				(mo->target != ((player_t *)actor->special1)->mo))
+			{
+				continue;
+			}
+		}
+		// Found a target monster
+		actor->target = mo;
+		return true;
+	}
+	return false;
+}
+
+/*
+================
+=
+= P_LookForPlayers
+=
+= If allaround is false, only look 180 degrees in front
+= returns true if a player is targeted
+================
+*/
+
+static boolean P_LookForPlayers(mobj_t *actor, boolean allaround)
+{
+	int c;
+	int stop;
+	player_t *player;
+	angle_t an;
+	fixed_t dist;
+
+	if (!netgame && players[0].health <= 0)
+	{ // Single player game and player is dead, look for monsters
+		return(P_LookForMonsters(actor));
+	}
+	c = 0;
+	// O.S. - lastlook mask was 3 here, but it should have been
+	// a leftover from hexen-1.0 where MAXPLAYERS was 4..
+	// also see p_mobj.c :: P_SpawnMobj() where it is set.
+	stop = (actor->lastlook - 1) & (MAXPLAYERS - 1);
+	for ( ; ; actor->lastlook = (actor->lastlook + 1) & (MAXPLAYERS - 1))
+	{
+		if (!playeringame[actor->lastlook])
+			continue;
+
+		if (c++ == 2 || actor->lastlook == stop)
+			return false;		// done looking
+
+		player = &players[actor->lastlook];
+		if (player->health <= 0)
+			continue;		// dead
+		if (!P_CheckSight (actor, player->mo))
+			continue;		// out of sight
+
+		if (!allaround)
+		{
+			an = R_PointToAngle2 (actor->x, actor->y, player->mo->x, player->mo->y)
+				- actor->angle;
+			if (an > ANG90 && an < ANG270)
+			{
+				dist = P_AproxDistance (player->mo->x - actor->x, player->mo->y - actor->y);
+				// if real close, react anyway
+				if (dist > MELEERANGE)
+					continue;		// behind back
+			}
+		}
+		if (player->mo->flags & MF_SHADOW)
+		{ // Player is invisible
+			if ((P_AproxDistance(player->mo->x - actor->x, player->mo->y - actor->y) > 2*MELEERANGE)
+				&& P_AproxDistance(player->mo->momx, player->mo->momy) < 5*FRACUNIT)
+			{ // Player is sneaking - can't detect
+				return false;
+			}
+			if (P_Random() < 225)
+			{ // Player isn't sneaking, but still didn't detect
+				return false;
+			}
+		}
+		if (actor->type == MT_MINOTAUR)
+		{
+			if (((player_t *)(actor->special1)) == player)
+			{
+				continue;			// Don't target master
+			}
+		}
+
+		actor->target = player->mo;
+		return true;
+	}
+	return false;
+}
+
+/*
+===============================================================================
+
+						ACTION ROUTINES
+
+===============================================================================
+*/
+
+/*
+==============
+=
+= A_Look
+=
+= Stay in state until a player is sighted
+=
+==============
+*/
+
+void A_Look (mobj_t *actor)
+{
+	mobj_t		*targ;
+
+	actor->threshold = 0;		// any shot will wake up
+	targ = actor->subsector->sector->soundtarget;
+	if (targ && (targ->flags & MF_SHOOTABLE))
+	{
+		actor->target = targ;
+		if (actor->flags & MF_AMBUSH)
+		{
+			if (P_CheckSight (actor, actor->target))
+				goto seeyou;
+		}
+		else
+			goto seeyou;
+	}
+
+	if (!P_LookForPlayers (actor, false))
+		return;
+
+// go into chase state
+seeyou:
+	if (actor->info->seesound)
+	{
+		int		sound;
+
+		sound = actor->info->seesound;
+		if (actor->flags2 & MF2_BOSS)
+		{ // Full volume
+			S_StartSound(NULL, sound);
+		}
+		else
+		{
+			S_StartSound(actor, sound);
+		}
+	}
+	P_SetMobjState(actor, actor->info->seestate);
+}
+
+
+/*
+==============
+=
+= A_Chase
+=
+= Actor has a melee attack, so it tries to close as fast as possible
+=
+==============
+*/
+
+void A_Chase(mobj_t *actor)
+{
+	int delta;
+
+	if (actor->reactiontime)
+	{
+		actor->reactiontime--;
+	}
+
+	// Modify target threshold
+	if (actor->threshold)
+	{
+		actor->threshold--;
+	}
+
+	if (gameskill == sk_nightmare)
+	{ // Monsters move faster in nightmare mode
+		actor->tics -= actor->tics/2;
+		if (actor->tics < 3)
+		{
+			actor->tics = 3;
+		}
+	}
+
+//
+// turn towards movement direction if not there yet
+//
+	if (actor->movedir < 8)
+	{
+		actor->angle &= (7 << 29);
+		delta = actor->angle - (actor->movedir << 29);
+		if (delta > 0)
+		{
+			actor->angle -= ANG90/2;
+		}
+		else if (delta < 0)
+		{
+			actor->angle += ANG90/2;
+		}
+	}
+
+	if (!actor->target || !(actor->target->flags & MF_SHOOTABLE))
+	{ // look for a new target
+		if (P_LookForPlayers(actor, true))
+		{ // got a new target
+			return;
+		}
+		P_SetMobjState(actor, actor->info->spawnstate);
+		return;
+	}
+
+//
+// don't attack twice in a row
+//
+	if (actor->flags & MF_JUSTATTACKED)
+	{
+		actor->flags &= ~MF_JUSTATTACKED;
+		if (gameskill != sk_nightmare)
+			P_NewChaseDir (actor);
+		return;
+	}
+
+//
+// check for melee attack
+//
+	if (actor->info->meleestate && P_CheckMeleeRange (actor))
+	{
+		if (actor->info->attacksound)
+		{
+			S_StartSound (actor, actor->info->attacksound);
+		}
+		P_SetMobjState (actor, actor->info->meleestate);
+		return;
+	}
+
+//
+// check for missile attack
+//
+	if (actor->info->missilestate)
+	{
+		if (gameskill < sk_nightmare && actor->movecount)
+			goto nomissile;
+		if (!P_CheckMissileRange (actor))
+			goto nomissile;
+		P_SetMobjState (actor, actor->info->missilestate);
+		actor->flags |= MF_JUSTATTACKED;
+		return;
+	}
+
+nomissile:
+//
+// possibly choose another target
+//
+	if (netgame && !actor->threshold && !P_CheckSight(actor, actor->target))
+	{
+		if (P_LookForPlayers(actor, true))
+			return;		// got a new target
+	}
+
+//
+// chase towards player
+//
+	if (--actor->movecount < 0 || !P_Move(actor))
+	{
+		P_NewChaseDir (actor);
+	}
+
+//
+// make active sound
+//
+	if (actor->info->activesound && P_Random() < 3)
+	{
+		if (actor->type == MT_BISHOP && P_Random() < 128)
+		{
+			S_StartSound(actor, actor->info->seesound);
+		}
+		else if (actor->type == MT_PIG)
+		{
+			S_StartSound(actor, SFX_PIG_ACTIVE1 + (P_Random() & 1));
+		}
+		else if (actor->flags2 & MF2_BOSS)
+		{
+			S_StartSound(NULL, actor->info->activesound);
+		}
+		else
+		{
+			S_StartSound(actor, actor->info->activesound);
+		}
+	}
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_FaceTarget
+//
+//----------------------------------------------------------------------------
+
+void A_FaceTarget(mobj_t *actor)
+{
+	if (!actor->target)
+	{
+		return;
+	}
+	actor->flags &= ~MF_AMBUSH;
+	actor->angle = R_PointToAngle2(actor->x, actor->y, actor->target->x, actor->target->y);
+	if (actor->target->flags & MF_SHADOW)
+	{ // Target is a ghost
+		actor->angle += (P_Random() - P_Random()) << 21;
+	}
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_Pain
+//
+//----------------------------------------------------------------------------
+
+void A_Pain(mobj_t *actor)
+{
+	if (actor->info->painsound)
+	{
+		S_StartSound(actor, actor->info->painsound);
+	}
+}
+
+//============================================================================
+//
+// A_SetInvulnerable
+//
+//============================================================================
+
+void A_SetInvulnerable(mobj_t *actor)
+{
+	actor->flags2 |= MF2_INVULNERABLE;
+}
+
+//============================================================================
+//
+// A_UnSetInvulnerable
+//
+//============================================================================
+
+void A_UnSetInvulnerable(mobj_t *actor)
+{
+	actor->flags2 &= ~MF2_INVULNERABLE;
+}
+
+//============================================================================
+//
+// A_SetReflective
+//
+//============================================================================
+
+void A_SetReflective(mobj_t *actor)
+{
+	actor->flags2 |= MF2_REFLECTIVE;
+
+	if ((actor->type == MT_CENTAUR) ||
+		(actor->type == MT_CENTAURLEADER))
+	{
+		A_SetInvulnerable(actor);
+	}
+}
+
+//============================================================================
+//
+// A_UnSetReflective
+//
+//============================================================================
+
+void A_UnSetReflective(mobj_t *actor)
+{
+	actor->flags2 &= ~MF2_REFLECTIVE;
+
+	if ((actor->type == MT_CENTAUR) ||
+		(actor->type == MT_CENTAURLEADER))
+	{
+		A_UnSetInvulnerable(actor);
+	}
+}
+
+
+//----------------------------------------------------------------------------
+//
+// FUNC P_UpdateMorphedMonster
+//
+// Returns true if the pig morphs.
+//
+//----------------------------------------------------------------------------
+
+static boolean P_UpdateMorphedMonster(mobj_t *actor, int tics)
+{
+	mobj_t *fog;
+	fixed_t x;
+	fixed_t y;
+	fixed_t z;
+	mobjtype_t moType;
+	mobj_t *mo;
+	mobj_t oldMonster;
+
+	actor->special1 -= tics;
+	if (actor->special1 > 0)
+	{
+		return false;
+	}
+	moType = actor->special2;
+	switch (moType)
+	{
+	case MT_WRAITHB:			// These must remain morphed
+	case MT_SERPENT:
+	case MT_SERPENTLEADER:
+	case MT_MINOTAUR:
+		return false;
+	default:
+		break;
+	}
+	x = actor->x;
+	y = actor->y;
+	z = actor->z;
+	oldMonster = *actor;			// Save pig vars
+
+	P_RemoveMobjFromTIDList(actor);
+	P_SetMobjState(actor, S_FREETARGMOBJ);
+	mo = P_SpawnMobj(x, y, z, moType);
+
+	if (P_TestMobjLocation(mo) == false)
+	{ // Didn't fit
+		P_RemoveMobj(mo);
+		mo = P_SpawnMobj(x, y, z, oldMonster.type);
+		mo->angle = oldMonster.angle;
+		mo->flags = oldMonster.flags;
+		mo->health = oldMonster.health;
+		mo->target = oldMonster.target;
+		mo->special = oldMonster.special;
+		mo->special1 = 5*35; // Next try in 5 seconds
+		mo->special2 = moType;
+		mo->tid = oldMonster.tid;
+		memcpy(mo->args, oldMonster.args, 5);
+		P_InsertMobjIntoTIDList(mo, oldMonster.tid);
+		return false;
+	}
+	mo->angle = oldMonster.angle;
+	mo->target = oldMonster.target;
+	mo->tid = oldMonster.tid;
+	mo->special = oldMonster.special;
+	memcpy(mo->args, oldMonster.args, 5);
+	P_InsertMobjIntoTIDList(mo, oldMonster.tid);
+	fog = P_SpawnMobj(x, y, z + TELEFOGHEIGHT, MT_TFOG);
+	S_StartSound(fog, SFX_TELEPORT);
+	return true;
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_PigLook
+//
+//----------------------------------------------------------------------------
+
+void A_PigLook(mobj_t *actor)
+{
+	if (P_UpdateMorphedMonster(actor, 10))
+	{
+		return;
+	}
+	A_Look(actor);
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_PigChase
+//
+//----------------------------------------------------------------------------
+
+void A_PigChase(mobj_t *actor)
+{
+	if (P_UpdateMorphedMonster(actor, 3))
+	{
+		return;
+	}
+	A_Chase(actor);
+}
+
+//============================================================================
+//
+// A_PigAttack
+//
+//============================================================================
+
+void A_PigAttack(mobj_t *actor)
+{
+	if (P_UpdateMorphedMonster(actor, 18))
+	{
+		return;
+	}
+	if (!actor->target)
+	{
+		return;
+	}
+	if (P_CheckMeleeRange(actor))
+	{
+		P_DamageMobj(actor->target, actor, actor, 2+(P_Random() & 1));
+		S_StartSound(actor, SFX_PIG_ATTACK);
+	}
+}
+
+//============================================================================
+//
+// A_PigPain
+//
+//============================================================================
+
+void A_PigPain(mobj_t *actor)
+{
+	A_Pain(actor);
+	if (actor->z <= actor->floorz)
+	{
+		actor->momz = 3.5*FRACUNIT;
+	}
+}
+
+
+static void FaceMovementDirection(mobj_t *actor)
+{
+	switch (actor->movedir)
+	{
+	case DI_EAST:
+		actor->angle = 0<<24;
+		break;
+	case DI_NORTHEAST:
+		actor->angle = 32<<24;
+		break;
+	case DI_NORTH:
+		actor->angle = 64<<24;
+		break;
+	case DI_NORTHWEST:
+		actor->angle = 96<<24;
+		break;
+	case DI_WEST:
+		actor->angle = 128<<24;
+		break;
+	case DI_SOUTHWEST:
+		actor->angle = 160<<24;
+		break;
+	case DI_SOUTH:
+		actor->angle = 192<<24;
+		break;
+	case DI_SOUTHEAST:
+		actor->angle = 224<<24;
+		break;
+	}
+}
+
+
+//----------------------------------------------------------------------------
+//
+// Minotaur variables
+//
+//	special1		pointer to player that spawned it (mobj_t)
+//	special2		internal to minotaur AI
+//	args[0]			args[0]-args[3] together make up minotaur start time
+//	args[1]			|
+//	args[2]			|
+//	args[3]			V
+//	args[4]			charge duration countdown
+//----------------------------------------------------------------------------
+
+void A_MinotaurFade0(mobj_t *actor)
+{
+	actor->flags &= ~MF_ALTSHADOW;
+	actor->flags |= MF_SHADOW;
+}
+
+void A_MinotaurFade1(mobj_t *actor)
+{
+	// Second level of transparency
+	actor->flags &= ~MF_SHADOW;
+	actor->flags |= MF_ALTSHADOW;
+}
+
+void A_MinotaurFade2(mobj_t *actor)
+{
+	// Make fully visible
+	actor->flags &= ~MF_SHADOW;
+	actor->flags &= ~MF_ALTSHADOW;
+}
+
+
+//----------------------------------------------------------------------------
+//
+// A_MinotaurRoam - 
+//
+//
+//----------------------------------------------------------------------------
+
+void A_MinotaurLook(mobj_t *actor);
+
+void A_MinotaurRoam(mobj_t *actor)
+{
+	int	summontime;
+
+	actor->flags &= ~MF_SHADOW;	// In case pain caused him to 
+	actor->flags &= ~MF_ALTSHADOW;		// skip his fade in.
+
+	summontime = READ_INT32(actor->args);
+	if ((leveltime - summontime) >= MAULATORTICS)
+	{
+		P_DamageMobj(actor, NULL, NULL, 10000);
+		return;
+	}
+
+	if (P_Random() < 30)
+		A_MinotaurLook(actor);		// adjust to closest target
+
+	if (P_Random() < 6)
+	{
+		//Choose new direction
+		actor->movedir = P_Random() % 8;
+		FaceMovementDirection(actor);
+	}
+	if (!P_Move(actor))
+	{
+		// Turn
+		if (P_Random() & 1)
+		{
+		//	actor->movedir = (++actor->movedir) % 8;
+			++actor->movedir;
+			actor->movedir = actor->movedir % 8;
+		}
+		else
+		{
+			actor->movedir = (actor->movedir + 7) % 8;
+		}
+		FaceMovementDirection(actor);
+	}
+}
+
+//----------------------------------------------------------------------------
+//
+//	PROC A_MinotaurLook
+//
+// Look for enemy of player
+//----------------------------------------------------------------------------
+#define MINOTAUR_LOOK_DIST		(16 * 54 * FRACUNIT)
+
+void A_MinotaurLook(mobj_t *actor)
+{
+	mobj_t *mo = NULL;
+	player_t *player;
+	thinker_t *think;
+	fixed_t dist;
+	int i;
+	mobj_t *master = (mobj_t *)(actor->special1);
+
+	actor->target = NULL;
+	if (deathmatch)		// Quick search for players
+	{
+		for (i = 0; i < MAXPLAYERS; i++)
+		{
+			if (!playeringame[i])
+				continue;
+			player = &players[i];
+			mo = player->mo;
+			if (mo == master)
+				continue;
+			if (mo->health <= 0)
+				continue;
+			dist = P_AproxDistance(actor->x - mo->x, actor->y - mo->y);
+			if (dist > MINOTAUR_LOOK_DIST)
+				continue;
+			actor->target = mo;
+			break;
+		}
+	}
+
+	if (!actor->target)	// Near player monster search
+	{
+		if (master && (master->health > 0) && (master->player))
+			mo = P_RoughMonsterSearch(master, 20);
+		else
+			mo = P_RoughMonsterSearch(actor, 20);
+		actor->target = mo;
+	}
+
+	if (!actor->target)	// Normal monster search
+	{
+		for (think = thinkercap.next; think != &thinkercap; think = think->next)
+		{
+			if (think->function != P_MobjThinker)
+				continue;
+			mo = (mobj_t *)think;
+			if (!(mo->flags & MF_COUNTKILL))
+				continue;
+			if (mo->health <= 0)
+				continue;
+			if (!(mo->flags & MF_SHOOTABLE))
+				continue;
+			dist = P_AproxDistance(actor->x - mo->x, actor->y - mo->y);
+			if (dist > MINOTAUR_LOOK_DIST)
+				continue;
+			if ((mo == master) || (mo == actor))
+				continue;
+			if ((mo->type == MT_MINOTAUR) && (mo->special1 == actor->special1))
+				continue;
+			actor->target = mo;
+			break;	// Found mobj to attack
+		}
+	}
+
+	if (actor->target)
+	{
+		P_SetMobjStateNF(actor, S_MNTR_WALK1);
+	}
+	else
+	{
+		P_SetMobjStateNF(actor, S_MNTR_ROAM1);
+	}
+}
+
+
+void A_MinotaurChase(mobj_t *actor)
+{
+	int	summontime;
+
+	actor->flags &= ~MF_SHADOW;	// In case pain caused him to 
+	actor->flags &= ~MF_ALTSHADOW;		// skip his fade in.
+
+	summontime = READ_INT32(actor->args);
+	if ((leveltime - summontime) >= MAULATORTICS)
+	{
+		P_DamageMobj(actor, NULL, NULL, 10000);
+		return;
+	}
+
+	if (P_Random() < 30)
+		A_MinotaurLook(actor);		// adjust to closest target
+
+	if (!actor->target || (actor->target->health <= 0) ||
+			!(actor->target->flags&MF_SHOOTABLE))
+	{ // look for a new target
+		P_SetMobjState(actor, S_MNTR_LOOK1);
+		return;
+	}
+
+	FaceMovementDirection(actor);
+	actor->reactiontime = 0;
+
+	// Melee attack
+	if (actor->info->meleestate && P_CheckMeleeRange(actor))
+	{
+		if (actor->info->attacksound)
+		{
+			S_StartSound (actor, actor->info->attacksound);
+		}
+		P_SetMobjState (actor, actor->info->meleestate);
+		return;
+	}
+
+	// Missile attack
+	if (actor->info->missilestate && P_CheckMissileRange(actor))
+	{
+		P_SetMobjState (actor, actor->info->missilestate);
+		return;
+	}
+
+	// chase towards target
+	if (!P_Move(actor))
+	{
+		P_NewChaseDir(actor);
+	}
+
+	// Active sound
+	if (actor->info->activesound && P_Random() < 6)
+	{
+		S_StartSound(actor, actor->info->activesound);
+	}
+}
+
+
+//----------------------------------------------------------------------------
+//
+// PROC A_MinotaurAtk1
+//
+// Melee attack.
+//
+//----------------------------------------------------------------------------
+
+void A_MinotaurAtk1(mobj_t *actor)
+{
+	if (!actor->target)
+		return;
+
+	S_StartSound(actor, SFX_MAULATOR_HAMMER_SWING);
+	if (P_CheckMeleeRange(actor))
+	{
+		P_DamageMobj(actor->target, actor, actor, HITDICE(4));
+	}
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_MinotaurDecide
+//
+// Choose a missile attack.
+//
+//----------------------------------------------------------------------------
+
+#define MNTR_CHARGE_SPEED	(23 * FRACUNIT)
+
+void A_MinotaurDecide(mobj_t *actor)
+{
+	angle_t angle;
+	mobj_t *target = actor->target;
+	int dist;
+
+	if (!target)
+		return;
+	dist = P_AproxDistance(actor->x - target->x, actor->y - target->y);
+
+	if (target->z + target->height > actor->z
+		&& target->z + target->height < actor->z + actor->height
+		&& dist < 16*64*FRACUNIT
+		&& dist > 1*64*FRACUNIT
+		&& P_Random() < 230)
+	{ // Charge attack
+		// Don't call the state function right away
+		P_SetMobjStateNF(actor, S_MNTR_ATK4_1);
+		actor->flags |= MF_SKULLFLY;
+		A_FaceTarget(actor);
+		angle = actor->angle>>ANGLETOFINESHIFT;
+		actor->momx = FixedMul(MNTR_CHARGE_SPEED, finecosine[angle]);
+		actor->momy = FixedMul(MNTR_CHARGE_SPEED, finesine[angle]);
+		actor->args[4] = 35/2; // Charge duration
+	}
+	else if (target->z == target->floorz
+		&& dist < 9*64*FRACUNIT
+		&& P_Random() < 100)
+	{ // Floor fire attack
+		P_SetMobjState(actor, S_MNTR_ATK3_1);
+		actor->special2 = 0;
+	}
+	else
+	{ // Swing attack
+		A_FaceTarget(actor);
+		// Don't need to call P_SetMobjState because the current state
+		// falls through to the swing attack
+	}
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_MinotaurCharge
+//
+//----------------------------------------------------------------------------
+
+void A_MinotaurCharge(mobj_t *actor)
+{
+	mobj_t *puff;
+
+	if (!actor->target)
+		return;
+
+	if (actor->args[4] > 0)
+	{
+		puff = P_SpawnMobj(actor->x, actor->y, actor->z, MT_PUNCHPUFF);
+		puff->momz = 2*FRACUNIT;
+		actor->args[4]--;
+	}
+	else
+	{
+		actor->flags &= ~MF_SKULLFLY;
+		P_SetMobjState(actor, actor->info->seestate);
+	}
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_MinotaurAtk2
+//
+// Swing attack.
+//
+//----------------------------------------------------------------------------
+
+void A_MinotaurAtk2(mobj_t *actor)
+{
+	mobj_t *mo;
+	angle_t angle;
+	fixed_t momz;
+
+	if (!actor->target)
+		return;
+
+	S_StartSound(actor, SFX_MAULATOR_HAMMER_SWING);
+	if (P_CheckMeleeRange(actor))
+	{
+		P_DamageMobj(actor->target, actor, actor, HITDICE(3));
+		return;
+	}
+	mo = P_SpawnMissile(actor, actor->target, MT_MNTRFX1);
+	if (mo)
+	{
+		//S_StartSound(mo, sfx_minat2);
+		momz = mo->momz;
+		angle = mo->angle;
+		P_SpawnMissileAngle(actor, MT_MNTRFX1, angle - (ANG45 / 8), momz);
+		P_SpawnMissileAngle(actor, MT_MNTRFX1, angle + (ANG45 / 8), momz);
+		P_SpawnMissileAngle(actor, MT_MNTRFX1, angle - (ANG45 /16), momz);
+		P_SpawnMissileAngle(actor, MT_MNTRFX1, angle + (ANG45 /16), momz);
+	}
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_MinotaurAtk3
+//
+// Floor fire attack.
+//
+//----------------------------------------------------------------------------
+
+void A_MinotaurAtk3(mobj_t *actor)
+{
+	mobj_t *mo;
+	player_t *player;
+
+	if (!actor->target)
+	{
+		return;
+	}
+	if (P_CheckMeleeRange(actor))
+	{
+		P_DamageMobj(actor->target, actor, actor, HITDICE(3));
+		if ((player = actor->target->player) != NULL)
+		{ // Squish the player
+			player->deltaviewheight = -16*FRACUNIT;
+		}
+	}
+	else
+	{
+		mo = P_SpawnMissile(actor, actor->target, MT_MNTRFX2);
+		if (mo != NULL)
+		{
+			S_StartSound(mo, SFX_MAULATOR_HAMMER_HIT);
+		}
+	}
+	if (P_Random() < 192 && actor->special2 == 0)
+	{
+		P_SetMobjState(actor, S_MNTR_ATK3_4);
+		actor->special2 = 1;
+	}
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_MntrFloorFire
+//
+//----------------------------------------------------------------------------
+
+void A_MntrFloorFire(mobj_t *actor)
+{
+	mobj_t *mo;
+
+	actor->z = actor->floorz;
+	mo = P_SpawnMobj(actor->x + ((P_Random() - P_Random()) << 10),
+			 actor->y + ((P_Random() - P_Random()) << 10), ONFLOORZ, MT_MNTRFX3);
+	mo->target = actor->target;
+	mo->momx = 1; // Force block checking
+	P_CheckMissileSpawn(mo);
+}
+
+
+//----------------------------------------------------------------------------
+//
+// PROC A_Scream
+//
+//----------------------------------------------------------------------------
+
+void A_Scream(mobj_t *actor)
+{
+	int sound;
+
+	S_StopSound(actor);
+	if (actor->player)
+	{
+		if (actor->player->morphTics)
+		{
+			S_StartSound(actor, actor->info->deathsound);
+		}
+		else
+		{
+			// Handle the different player death screams
+			if (actor->momz <= -39*FRACUNIT)
+			{ // Falling splat
+				sound = SFX_PLAYER_FALLING_SPLAT;
+			}
+			else if (actor->health > -50)
+			{ // Normal death sound
+				switch (actor->player->playerclass)
+				{
+				case PCLASS_FIGHTER:
+					sound = SFX_PLAYER_FIGHTER_NORMAL_DEATH;
+					break;
+				case PCLASS_CLERIC:
+					sound = SFX_PLAYER_CLERIC_NORMAL_DEATH;
+					break;
+				case PCLASS_MAGE:
+					sound = SFX_PLAYER_MAGE_NORMAL_DEATH;
+					break;
+				default:
+					sound = SFX_NONE;
+					break;
+				}
+			}
+			else if (actor->health > -100)
+			{ // Crazy death sound
+				switch (actor->player->playerclass)
+				{
+				case PCLASS_FIGHTER:
+					sound = SFX_PLAYER_FIGHTER_CRAZY_DEATH;
+					break;
+				case PCLASS_CLERIC:
+					sound = SFX_PLAYER_CLERIC_CRAZY_DEATH;
+					break;
+				case PCLASS_MAGE:
+					sound = SFX_PLAYER_MAGE_CRAZY_DEATH;
+					break;
+				default:
+					sound = SFX_NONE;
+					break;
+				}
+			}
+			else
+			{ // Extreme death sound
+				switch (actor->player->playerclass)
+				{
+				case PCLASS_FIGHTER:
+					sound = SFX_PLAYER_FIGHTER_EXTREME1_DEATH;
+					break;
+				case PCLASS_CLERIC:
+					sound = SFX_PLAYER_CLERIC_EXTREME1_DEATH;
+					break;
+				case PCLASS_MAGE:
+					sound = SFX_PLAYER_MAGE_EXTREME1_DEATH;
+					break;
+				default:
+					sound = SFX_NONE;
+					break;
+				}
+				sound += P_Random() % 3; // Three different extreme deaths
+			}
+			S_StartSound(actor, sound);
+		}
+	}
+	else
+	{
+		S_StartSound(actor, actor->info->deathsound);
+	}
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC P_DropItem
+//
+//---------------------------------------------------------------------------
+
+/*
+void P_DropItem(mobj_t *source, mobjtype_t type, int special, int chance)
+{
+	mobj_t *mo;
+
+	if (P_Random() > chance)
+	{
+		return;
+	}
+	mo = P_SpawnMobj(source->x, source->y, source->z + (source->height>>1), type);
+	mo->momx = (P_Random() - P_Random()) << 8;
+	mo->momy = (P_Random() - P_Random()) << 8;
+	mo->momz = FRACUNIT*5 + (P_Random() << 10);
+	mo->flags2 |= MF2_DROPPED;
+	mo->health = special;
+}
+*/
+
+//----------------------------------------------------------------------------
+//
+// PROC A_NoBlocking
+//
+//----------------------------------------------------------------------------
+
+void A_NoBlocking(mobj_t *actor)
+{
+	actor->flags &= ~MF_SOLID;
+
+// Check for monsters dropping things
+/*	switch (actor->type)
+	{
+	// Add the monster dropped items here
+	case MT_MUMMYLEADERGHOST:
+		P_DropItem(actor, MT_AMGWNDWIMPY, 3, 84);
+		break;
+	default:
+		break;
+	}
+*/
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_Explode
+//
+// Handles a bunch of exploding things.
+//
+//----------------------------------------------------------------------------
+
+void A_Explode(mobj_t *actor)
+{
+	int damage;
+	int distance;
+	boolean damageSelf;
+
+	damage = 128;
+	distance = 128;
+	damageSelf = true;
+	switch (actor->type)
+	{
+	case MT_FIREBOMB:	// Time Bombs
+		actor->z += 32*FRACUNIT;
+		actor->flags &= ~MF_SHADOW;
+		break;
+	case MT_MNTRFX2:	// Minotaur floor fire
+		damage = 24;
+		break;
+	case MT_BISHOP:		// Bishop radius death
+		damage = 25 + (P_Random() & 15);
+		break;
+	case MT_HAMMER_MISSILE:	// Fighter Hammer
+		damage = 128;
+		damageSelf = false;
+		break;
+	case MT_FSWORD_MISSILE:	// Fighter Runesword
+		damage = 64;
+		damageSelf = false;
+		break;
+	case MT_CIRCLEFLAME:	// Cleric Flame secondary flames
+		damage = 20;
+		damageSelf = false;
+		break;
+	case MT_SORCBALL1:	// Sorcerer balls
+	case MT_SORCBALL2:
+	case MT_SORCBALL3:
+		distance = 255;
+		damage = 255;
+		actor->args[0] = 1;	// don't play bounce
+		break;
+	case MT_SORCFX1:	// Sorcerer spell 1
+		damage = 30;
+		break;
+	case MT_SORCFX4:	// Sorcerer spell 4
+		damage = 20;
+		break;
+	case MT_TREEDESTRUCTIBLE:
+		damage = 10;
+		break;
+	case MT_DRAGON_FX2:
+		damage = 80;
+		damageSelf = false;
+		break;
+	case MT_MSTAFF_FX:
+		damage = 64;
+		distance = 192;
+		damageSelf = false;
+		break;
+	case MT_MSTAFF_FX2:
+		damage = 80;
+		distance = 192;
+		damageSelf = false;
+		break;
+	case MT_POISONCLOUD:
+		damage = 4;
+		distance = 40;
+		break;
+	case MT_ZXMAS_TREE:
+	case MT_ZSHRUB2:
+		damage = 30;
+		distance = 64;
+		break;
+	default:
+		break;
+	}
+
+	P_RadiusAttack(actor, actor->target, damage, distance, damageSelf);
+	if (actor->z <= actor->floorz + (distance<<FRACBITS)
+				&& actor->type != MT_POISONCLOUD)
+	{
+ 		P_HitFloor(actor);
+	}
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC P_Massacre
+//
+// Kills all monsters.
+//
+//----------------------------------------------------------------------------
+
+int P_Massacre(void)
+{
+	int count;
+	mobj_t *mo;
+	thinker_t *think;
+
+	count = 0;
+	for (think = thinkercap.next; think != &thinkercap; think = think->next)
+	{
+		if (think->function != P_MobjThinker)
+		{ // Not a mobj thinker
+			continue;
+		}
+		mo = (mobj_t *)think;
+		if ((mo->flags & MF_COUNTKILL) && (mo->health > 0))
+		{
+			mo->flags2 &= ~(MF2_NONSHOOTABLE+MF2_INVULNERABLE);
+			mo->flags |= MF_SHOOTABLE;
+			P_DamageMobj(mo, NULL, NULL, 10000);
+			count++;
+		}
+	}
+	return count;
+}
+
+
+//----------------------------------------------------------------------------
+//
+// PROC A_SkullPop
+//
+//----------------------------------------------------------------------------
+
+void A_SkullPop(mobj_t *actor)
+{
+	mobj_t *mo;
+	player_t *player;
+
+	if (!actor->player)
+	{
+		return;
+	}
+	actor->flags &= ~MF_SOLID;
+	mo = P_SpawnMobj(actor->x, actor->y, actor->z + 48*FRACUNIT, MT_BLOODYSKULL);
+	//mo->target = actor;
+	mo->momx = (P_Random() - P_Random()) << 9;
+	mo->momy = (P_Random() - P_Random()) << 9;
+	mo->momz = FRACUNIT*2 + (P_Random() << 6);
+	// Attach player mobj to bloody skull
+	player = actor->player;
+	actor->player = NULL;
+	actor->special1 = player->playerclass;
+	mo->player = player;
+	mo->health = actor->health;
+	mo->angle = actor->angle;
+	player->mo = mo;
+	player->lookdir = 0;
+	player->damagecount = 32;
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_CheckSkullFloor
+//
+//----------------------------------------------------------------------------
+
+void A_CheckSkullFloor(mobj_t *actor)
+{
+	if (actor->z <= actor->floorz)
+	{
+		P_SetMobjState(actor, S_BLOODYSKULLX1);
+		S_StartSound(actor, SFX_DRIP);
+	}
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_CheckSkullDone
+//
+//----------------------------------------------------------------------------
+
+void A_CheckSkullDone(mobj_t *actor)
+{
+	if (actor->special2 == 666)
+	{
+		P_SetMobjState(actor, S_BLOODYSKULLX2);
+	}
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_CheckBurnGone
+//
+//----------------------------------------------------------------------------
+
+void A_CheckBurnGone(mobj_t *actor)
+{
+	if (actor->special2 == 666)
+	{
+		P_SetMobjState(actor, S_PLAY_FDTH20);
+	}
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_FreeTargMobj
+//
+//----------------------------------------------------------------------------
+
+void A_FreeTargMobj(mobj_t *mo)
+{
+	mo->momx = mo->momy = mo->momz = 0;
+	mo->z = mo->ceilingz + 4*FRACUNIT;
+	mo->flags &= ~(MF_SHOOTABLE|MF_FLOAT|MF_SKULLFLY|MF_SOLID|MF_COUNTKILL);
+	mo->flags |= MF_CORPSE|MF_DROPOFF|MF_NOGRAVITY;
+	mo->flags2 &= ~(MF2_PASSMOBJ|MF2_LOGRAV);
+	mo->flags2 |= MF2_DONTDRAW;
+	mo->player = NULL;
+	mo->health = -1000;		// Don't resurrect
+}
+
+
+//----------------------------------------------------------------------------
+//
+// CorpseQueue Routines
+//
+//----------------------------------------------------------------------------
+
+// Corpse queue for monsters - this should be saved out
+#define CORPSEQUEUESIZE			64
+static mobj_t	*corpseQueue[CORPSEQUEUESIZE];
+static int	corpseQueueSlot;
+
+// throw another corpse on the queue
+void A_QueueCorpse(mobj_t *actor)
+{
+	mobj_t *corpse;
+
+	if (corpseQueueSlot >= CORPSEQUEUESIZE)
+	{ // Too many corpses - remove an old one
+		corpse = corpseQueue[corpseQueueSlot % CORPSEQUEUESIZE];
+		if (corpse)
+			P_RemoveMobj(corpse);
+	}
+	corpseQueue[corpseQueueSlot % CORPSEQUEUESIZE] = actor;
+	corpseQueueSlot++;
+}
+
+// Remove a mobj from the queue (for resurrection)
+void A_DeQueueCorpse(mobj_t *actor)
+{
+	int slot;
+
+	for (slot = 0; slot < CORPSEQUEUESIZE; slot++)
+	{
+		if (corpseQueue[slot] == actor)
+		{
+			corpseQueue[slot] = NULL;
+			break;
+		}
+	}
+}
+
+void P_InitCreatureCorpseQueue(boolean corpseScan)
+{
+	thinker_t *think;
+	mobj_t *mo;
+
+	// Initialize queue
+	corpseQueueSlot = 0;
+	memset(corpseQueue, 0, sizeof(mobj_t *)*CORPSEQUEUESIZE);
+
+	if (!corpseScan)
+		return;
+
+	// Search mobj list for corpses and place them in this queue
+	for (think = thinkercap.next; think != &thinkercap; think = think->next)
+	{
+		if (think->function != P_MobjThinker)
+			continue;
+		mo = (mobj_t *)think;
+		if (!(mo->flags & MF_CORPSE))
+			continue;	// Must be a corpse
+		if (mo->flags & MF_ICECORPSE)
+			continue;	// Not ice corpses
+		// Only corpses that call A_QueueCorpse from death routine
+		switch (mo->type)
+		{
+		case MT_CENTAUR:
+		case MT_CENTAURLEADER:
+		case MT_DEMON:
+		case MT_DEMON2:
+		case MT_WRAITH:
+		case MT_WRAITHB:
+		case MT_BISHOP:
+		case MT_ETTIN:
+		case MT_PIG:
+		case MT_CENTAUR_SHIELD:
+		case MT_CENTAUR_SWORD:
+		case MT_DEMONCHUNK1:
+		case MT_DEMONCHUNK2:
+		case MT_DEMONCHUNK3:
+		case MT_DEMONCHUNK4:
+		case MT_DEMONCHUNK5:
+		case MT_DEMON2CHUNK1:
+		case MT_DEMON2CHUNK2:
+		case MT_DEMON2CHUNK3:
+		case MT_DEMON2CHUNK4:
+		case MT_DEMON2CHUNK5:
+		case MT_FIREDEMON_SPLOTCH1:
+		case MT_FIREDEMON_SPLOTCH2:
+			A_QueueCorpse(mo);	// Add corpse to queue
+			break;
+		default:
+			break;
+		}
+	}
+}
+
+
+//----------------------------------------------------------------------------
+//
+// PROC A_AddPlayerCorpse
+//
+//----------------------------------------------------------------------------
+
+#define BODYQUESIZE			32
+static mobj_t		*bodyque[BODYQUESIZE];
+int			bodyqueslot;
+
+void A_AddPlayerCorpse(mobj_t *actor)
+{
+	if (bodyqueslot >= BODYQUESIZE)
+	{ // Too many player corpses - remove an old one
+		P_RemoveMobj(bodyque[bodyqueslot % BODYQUESIZE]);
+	}
+	bodyque[bodyqueslot % BODYQUESIZE] = actor;
+	bodyqueslot++;
+}
+
+//============================================================================
+//
+// A_SerpentUnHide
+//
+//============================================================================
+
+void A_SerpentUnHide(mobj_t *actor)
+{
+	actor->flags2 &= ~MF2_DONTDRAW;
+	actor->floorclip = 24*FRACUNIT;
+}
+
+//============================================================================
+//
+// A_SerpentHide
+//
+//============================================================================
+
+void A_SerpentHide(mobj_t *actor)
+{
+	actor->flags2 |= MF2_DONTDRAW;
+	actor->floorclip = 0;
+}
+
+//============================================================================
+//
+// A_SerpentChase
+//
+//============================================================================
+
+void A_SerpentChase(mobj_t *actor)
+{
+	int delta;
+	int oldX, oldY, oldFloor;
+
+	if (actor->reactiontime)
+	{
+		actor->reactiontime--;
+	}
+
+	// Modify target threshold
+	if (actor->threshold)
+	{
+		actor->threshold--;
+	}
+
+	if (gameskill == sk_nightmare)
+	{ // Monsters move faster in nightmare mode
+		actor->tics -= actor->tics/2;
+		if (actor->tics < 3)
+		{
+			actor->tics = 3;
+		}
+	}
+
+//
+// turn towards movement direction if not there yet
+//
+	if (actor->movedir < 8)
+	{
+		actor->angle &= (7 << 29);
+		delta = actor->angle - (actor->movedir << 29);
+		if (delta > 0)
+		{
+			actor->angle -= ANG90/2;
+		}
+		else if (delta < 0)
+		{
+			actor->angle += ANG90/2;
+		}
+	}
+
+	if (!actor->target || !(actor->target->flags & MF_SHOOTABLE))
+	{ // look for a new target
+		if (P_LookForPlayers(actor, true))
+		{ // got a new target
+			return;
+		}
+		P_SetMobjState(actor, actor->info->spawnstate);
+		return;
+	}
+
+//
+// don't attack twice in a row
+//
+	if (actor->flags & MF_JUSTATTACKED)
+	{
+		actor->flags &= ~MF_JUSTATTACKED;
+		if (gameskill != sk_nightmare)
+			P_NewChaseDir (actor);
+		return;
+	}
+
+//
+// check for melee attack
+//
+	if (actor->info->meleestate && P_CheckMeleeRange (actor))
+	{
+		if (actor->info->attacksound)
+		{
+			S_StartSound (actor, actor->info->attacksound);
+		}
+		P_SetMobjState (actor, actor->info->meleestate);
+		return;
+	}
+
+//
+// possibly choose another target
+//
+	if (netgame && !actor->threshold && !P_CheckSight(actor, actor->target))
+	{
+		if (P_LookForPlayers(actor, true))
+			return;		// got a new target
+	}
+
+//
+// chase towards player
+//
+	oldX = actor->x;
+	oldY = actor->y;
+	oldFloor = actor->subsector->sector->floorpic;
+	if (--actor->movecount < 0 || !P_Move(actor))
+	{
+		P_NewChaseDir (actor);
+	}
+	if (actor->subsector->sector->floorpic != oldFloor)
+	{
+		P_TryMove(actor, oldX, oldY);
+		P_NewChaseDir (actor);
+	}
+
+//
+// make active sound
+//
+	if (actor->info->activesound && P_Random() < 3)
+	{
+		S_StartSound(actor, actor->info->activesound);
+	}
+}
+
+//============================================================================
+//
+// A_SerpentRaiseHump
+//
+// Raises the hump above the surface by raising the floorclip level
+//============================================================================
+
+void A_SerpentRaiseHump(mobj_t *actor)
+{
+	actor->floorclip -= 4*FRACUNIT;
+}
+
+//============================================================================
+//
+// A_SerpentLowerHump
+//
+//============================================================================
+
+void A_SerpentLowerHump(mobj_t *actor)
+{
+	actor->floorclip += 4*FRACUNIT;
+}
+
+//============================================================================
+//
+// A_SerpentHumpDecide
+//
+//	Decided whether to hump up, or if the mobj is a serpent leader,
+//	to missile attack
+//============================================================================
+
+void A_SerpentHumpDecide(mobj_t *actor)
+{
+	if (actor->type == MT_SERPENTLEADER)
+	{
+		if (P_Random() > 30)
+		{
+			return;
+		}
+		else if (P_Random() < 40)
+		{ // Missile attack
+			P_SetMobjState(actor, S_SERPENT_SURFACE1);
+			return;
+		}
+	}
+	else if (P_Random() > 3)
+	{
+		return;
+	}
+	if (!P_CheckMeleeRange(actor))
+	{ // The hump shouldn't occur when within melee range
+		if (actor->type == MT_SERPENTLEADER && P_Random() < 128)
+		{
+			P_SetMobjState(actor, S_SERPENT_SURFACE1);
+		}
+		else
+		{
+			P_SetMobjState(actor, S_SERPENT_HUMP1);
+			S_StartSound(actor, SFX_SERPENT_ACTIVE);
+		}
+	}
+}
+
+//============================================================================
+//
+// A_SerpentBirthScream
+//
+//============================================================================
+
+void A_SerpentBirthScream(mobj_t *actor)
+{
+	S_StartSound(actor, SFX_SERPENT_BIRTH);
+}
+
+//============================================================================
+//
+// A_SerpentDiveSound
+//
+//============================================================================
+
+void A_SerpentDiveSound(mobj_t *actor)
+{
+	S_StartSound(actor, SFX_SERPENT_ACTIVE);
+}
+
+//============================================================================
+//
+// A_SerpentWalk
+//
+// Similar to A_Chase, only has a hardcoded entering of meleestate
+//============================================================================
+
+void A_SerpentWalk(mobj_t *actor)
+{
+	int delta;
+
+	if (actor->reactiontime)
+	{
+		actor->reactiontime--;
+	}
+
+	// Modify target threshold
+	if (actor->threshold)
+	{
+		actor->threshold--;
+	}
+
+	if (gameskill == sk_nightmare)
+	{ // Monsters move faster in nightmare mode
+		actor->tics -= actor->tics/2;
+		if (actor->tics < 3)
+		{
+			actor->tics = 3;
+		}
+	}
+
+//
+// turn towards movement direction if not there yet
+//
+	if (actor->movedir < 8)
+	{
+		actor->angle &= (7 << 29);
+		delta = actor->angle-(actor->movedir << 29);
+		if (delta > 0)
+		{
+			actor->angle -= ANG90/2;
+		}
+		else if (delta < 0)
+		{
+			actor->angle += ANG90/2;
+		}
+	}
+
+	if (!actor->target || !(actor->target->flags & MF_SHOOTABLE))
+	{ // look for a new target
+		if (P_LookForPlayers(actor, true))
+		{ // got a new target
+			return;
+		}
+		P_SetMobjState(actor, actor->info->spawnstate);
+		return;
+	}
+
+//
+// don't attack twice in a row
+//
+	if (actor->flags & MF_JUSTATTACKED)
+	{
+		actor->flags &= ~MF_JUSTATTACKED;
+		if (gameskill != sk_nightmare)
+			P_NewChaseDir (actor);
+		return;
+	}
+
+//
+// check for melee attack
+//
+	if (actor->info->meleestate && P_CheckMeleeRange (actor))
+	{
+		if (actor->info->attacksound)
+		{
+			S_StartSound (actor, actor->info->attacksound);
+		}
+		P_SetMobjState(actor, S_SERPENT_ATK1);
+		return;
+	}
+//
+// possibly choose another target
+//
+	if (netgame && !actor->threshold && !P_CheckSight(actor, actor->target))
+	{
+		if (P_LookForPlayers(actor, true))
+			return;		// got a new target
+	}
+
+//
+// chase towards player
+//
+	if (--actor->movecount < 0 || !P_Move(actor))
+	{
+		P_NewChaseDir (actor);
+	}
+}
+
+//============================================================================
+//
+// A_SerpentCheckForAttack
+//
+//============================================================================
+
+void A_SerpentCheckForAttack(mobj_t *actor)
+{
+	if (!actor->target)
+	{
+		return;
+	}
+	if (actor->type == MT_SERPENTLEADER)
+	{
+		if (!P_CheckMeleeRange(actor))
+		{
+			P_SetMobjState(actor, S_SERPENT_ATK1);
+			return;
+		}
+	}
+	if (P_CheckMeleeRange2(actor))
+	{
+		P_SetMobjState(actor, S_SERPENT_WALK1);
+	}
+	else if (P_CheckMeleeRange(actor))
+	{
+		if (P_Random() < 32)
+		{
+			P_SetMobjState(actor, S_SERPENT_WALK1);
+		}
+		else
+		{
+			P_SetMobjState(actor, S_SERPENT_ATK1);
+		}
+	}
+}
+
+//============================================================================
+//
+// A_SerpentChooseAttack
+//
+//============================================================================
+
+void A_SerpentChooseAttack(mobj_t *actor)
+{
+	if (!actor->target || P_CheckMeleeRange(actor))
+	{
+		return;
+	}
+	if (actor->type == MT_SERPENTLEADER)
+	{
+		P_SetMobjState(actor, S_SERPENT_MISSILE1);
+	}
+}
+
+//============================================================================
+//
+// A_SerpentMeleeAttack
+//
+//============================================================================
+
+void A_SerpentMeleeAttack(mobj_t *actor)
+{
+	if (!actor->target)
+	{
+		return;
+	}
+	if (P_CheckMeleeRange(actor))
+	{
+		P_DamageMobj(actor->target, actor, actor, HITDICE(5));
+		S_StartSound(actor, SFX_SERPENT_MELEEHIT);
+	}
+	if (P_Random() < 96)
+	{
+		A_SerpentCheckForAttack(actor);
+	}
+}
+
+//============================================================================
+//
+// A_SerpentMissileAttack
+//
+//============================================================================
+
+void A_SerpentMissileAttack(mobj_t *actor)
+{
+	if (!actor->target)
+	{
+		return;
+	}
+	P_SpawnMissile(actor, actor->target, MT_SERPENTFX);
+}
+
+//============================================================================
+//
+// A_SerpentHeadPop
+//
+//============================================================================
+
+void A_SerpentHeadPop(mobj_t *actor)
+{
+	P_SpawnMobj(actor->x, actor->y, actor->z + 45*FRACUNIT, MT_SERPENT_HEAD);
+}
+
+//============================================================================
+//
+// A_SerpentSpawnGibs
+//
+//============================================================================
+
+void A_SerpentSpawnGibs(mobj_t *actor)
+{
+	mobj_t *mo;
+
+	mo = P_SpawnMobj(actor->x + ((P_Random() - 128) << 12),
+			 actor->y + ((P_Random() - 128) << 12),
+			 actor->floorz + FRACUNIT, MT_SERPENT_GIB1);
+	if (mo)
+	{
+		mo->momx = (P_Random() - 128) << 6;
+		mo->momy = (P_Random() - 128) << 6;
+		mo->floorclip = 6*FRACUNIT;
+	}
+	mo = P_SpawnMobj(actor->x + ((P_Random() - 128) << 12),
+			 actor->y + ((P_Random() - 128) << 12),
+			 actor->floorz + FRACUNIT, MT_SERPENT_GIB2);
+	if (mo)
+	{
+		mo->momx = (P_Random() - 128) << 6;
+		mo->momy = (P_Random() - 128) << 6;
+		mo->floorclip = 6*FRACUNIT;
+	}
+	mo = P_SpawnMobj(actor->x + ((P_Random() - 128) << 12),
+			 actor->y + ((P_Random() - 128) << 12),
+			 actor->floorz + FRACUNIT, MT_SERPENT_GIB3);
+	if (mo)
+	{
+		mo->momx = (P_Random() - 128) << 6;
+		mo->momy = (P_Random() - 128) << 6;
+		mo->floorclip = 6*FRACUNIT;
+	}
+}
+
+//============================================================================
+//
+// A_FloatGib
+//
+//============================================================================
+
+void A_FloatGib(mobj_t *actor)
+{
+	actor->floorclip -= FRACUNIT;
+}
+
+//============================================================================
+//
+// A_SinkGib
+//
+//============================================================================
+
+void A_SinkGib(mobj_t *actor)
+{
+	actor->floorclip += FRACUNIT;
+}
+
+//============================================================================
+//
+// A_DelayGib
+//
+//============================================================================
+
+void A_DelayGib(mobj_t *actor)
+{
+	actor->tics -= P_Random()>>2;
+}
+
+//============================================================================
+//
+// A_SerpentHeadCheck
+//
+//============================================================================
+
+void A_SerpentHeadCheck(mobj_t *actor)
+{
+	if (actor->z <= actor->floorz)
+	{
+		if (P_GetThingFloorType(actor) >= FLOOR_LIQUID)
+		{
+			P_HitFloor(actor);
+			P_SetMobjState(actor, S_NULL);
+		}
+		else
+		{
+			P_SetMobjState(actor, S_SERPENT_HEAD_X1);
+		}
+	}
+}
+
+//============================================================================
+//
+// A_CentaurAttack
+//
+//============================================================================
+
+void A_CentaurAttack(mobj_t *actor)
+{
+	if (!actor->target)
+	{
+		return;
+	}
+	if (P_CheckMeleeRange(actor))
+	{
+		P_DamageMobj(actor->target, actor, actor, (P_Random() % 7) + 3);
+	}
+}
+
+//============================================================================
+//
+// A_CentaurAttack2
+//
+//============================================================================
+
+void A_CentaurAttack2(mobj_t *actor)
+{
+	if (!actor->target)
+	{
+		return;
+	}
+	P_SpawnMissile(actor, actor->target, MT_CENTAUR_FX);
+	S_StartSound(actor, SFX_CENTAURLEADER_ATTACK);
+}
+
+//============================================================================
+//
+// A_CentaurDropStuff
+//
+// Spawn shield/sword sprites when the centaur pulps
+//============================================================================
+
+void A_CentaurDropStuff(mobj_t *actor)
+{
+	mobj_t *mo;
+	angle_t angle;
+
+	mo = P_SpawnMobj(actor->x, actor->y, actor->z + 45*FRACUNIT, MT_CENTAUR_SHIELD);
+	if (mo)
+	{
+		angle = actor->angle + ANG90;
+		mo->momz = FRACUNIT*8 + (P_Random() << 10);
+		mo->momx = FixedMul(((P_Random() - 128) << 11) + FRACUNIT,
+				    finecosine[angle >> ANGLETOFINESHIFT]);
+		mo->momy = FixedMul(((P_Random() - 128) << 11) + FRACUNIT,
+				    finesine[angle >> ANGLETOFINESHIFT]);
+		mo->target = actor;
+	}
+	mo = P_SpawnMobj(actor->x, actor->y, actor->z + 45*FRACUNIT, MT_CENTAUR_SWORD);
+	if (mo)
+	{
+		angle = actor->angle - ANG90;
+		mo->momz = FRACUNIT*8 + (P_Random() << 10);
+		mo->momx = FixedMul(((P_Random() - 128) << 11) + FRACUNIT,
+				    finecosine[angle >> ANGLETOFINESHIFT]);
+		mo->momy = FixedMul(((P_Random() - 128) << 11) + FRACUNIT,
+				    finesine[angle>>ANGLETOFINESHIFT]);
+		mo->target = actor;
+	}
+}
+
+//============================================================================
+//
+// A_CentaurDefend
+//
+//============================================================================
+
+void A_CentaurDefend(mobj_t *actor)
+{
+	A_FaceTarget(actor);
+	if (P_CheckMeleeRange(actor) && P_Random() < 32)
+	{
+		A_UnSetInvulnerable(actor);
+		P_SetMobjState(actor, actor->info->meleestate);
+	}
+}
+
+//============================================================================
+//
+// A_BishopAttack
+//
+//============================================================================
+
+void A_BishopAttack(mobj_t *actor)
+{
+	if (!actor->target)
+	{
+		return;
+	}
+	S_StartSound(actor, actor->info->attacksound);
+	if (P_CheckMeleeRange(actor))
+	{
+		P_DamageMobj(actor->target, actor, actor, HITDICE(4));
+		return;
+	}
+	actor->special1 = (P_Random() & 3) + 5;
+}
+
+//============================================================================
+//
+// A_BishopAttack2
+//
+//	Spawns one of a string of bishop missiles
+//============================================================================
+
+void A_BishopAttack2(mobj_t *actor)
+{
+	mobj_t *mo;
+
+	if (!actor->target || !actor->special1)
+	{
+		actor->special1 = 0;
+		P_SetMobjState(actor, S_BISHOP_WALK1);
+		return;
+	}
+	mo = P_SpawnMissile(actor, actor->target, MT_BISH_FX);
+	if (mo)
+	{
+		mo->special1 = (intptr_t)actor->target;
+		mo->special2 = 16; // High word == x/y, Low word == z
+	}
+	actor->special1--;
+}
+
+//============================================================================
+//
+// A_BishopMissileWeave
+//
+//============================================================================
+
+void A_BishopMissileWeave(mobj_t *actor)
+{
+	fixed_t newX, newY;
+	int weaveXY, weaveZ;
+	int angle;
+
+	weaveXY = actor->special2 >> 16;
+	weaveZ = actor->special2 & 0xFFFF;
+	angle = (actor->angle + ANG90) >> ANGLETOFINESHIFT;
+	newX = actor->x - FixedMul(finecosine[angle], FloatBobOffsets[weaveXY]<<1);
+	newY = actor->y - FixedMul(finesine[angle], FloatBobOffsets[weaveXY]<<1);
+	weaveXY = (weaveXY + 2) & 63;
+	newX += FixedMul(finecosine[angle], FloatBobOffsets[weaveXY]<<1);
+	newY += FixedMul(finesine[angle], FloatBobOffsets[weaveXY]<<1);
+	P_TryMove(actor, newX, newY);
+	actor->z -= FloatBobOffsets[weaveZ];
+	weaveZ = (weaveZ + 2) & 63;
+	actor->z += FloatBobOffsets[weaveZ];
+	actor->special2 = weaveZ + (weaveXY<<16);
+}
+
+//============================================================================
+//
+// A_BishopMissileSeek
+//
+//============================================================================
+
+void A_BishopMissileSeek(mobj_t *actor)
+{
+	P_SeekerMissile(actor, ANGLE_1*2, ANGLE_1*3);
+}
+
+//============================================================================
+//
+// A_BishopDecide
+//
+//============================================================================
+
+void A_BishopDecide(mobj_t *actor)
+{
+	if (P_Random() < 220)
+	{
+		return;
+	}
+	else
+	{
+		P_SetMobjState(actor, S_BISHOP_BLUR1);
+	}
+}
+
+//============================================================================
+//
+// A_BishopDoBlur
+//
+//============================================================================
+
+void A_BishopDoBlur(mobj_t *actor)
+{
+	actor->special1 = (P_Random() & 3) + 3; // Random number of blurs
+	if (P_Random() < 120)
+	{
+		P_ThrustMobj(actor, actor->angle + ANG90, 11*FRACUNIT);
+	}
+	else if (P_Random() > 125)
+	{
+		P_ThrustMobj(actor, actor->angle - ANG90, 11*FRACUNIT);
+	}
+	else
+	{ // Thrust forward
+		P_ThrustMobj(actor, actor->angle, 11*FRACUNIT);
+	}
+	S_StartSound(actor, SFX_BISHOP_BLUR);
+}
+
+//============================================================================
+//
+// A_BishopSpawnBlur
+//
+//============================================================================
+
+void A_BishopSpawnBlur(mobj_t *actor)
+{
+	mobj_t *mo;
+
+	if (!--actor->special1)
+	{
+		actor->momx = 0;
+		actor->momy = 0;
+		if (P_Random() > 96)
+		{
+			P_SetMobjState(actor, S_BISHOP_WALK1);
+		}
+		else
+		{
+			P_SetMobjState(actor, S_BISHOP_ATK1);
+		}
+	}
+	mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_BISHOPBLUR);
+	if (mo)
+	{
+		mo->angle = actor->angle;
+	}
+}
+
+//============================================================================
+//
+// A_BishopChase
+//
+//============================================================================
+
+void A_BishopChase(mobj_t *actor)
+{
+	actor->z -= FloatBobOffsets[actor->special2]>>1;
+	actor->special2 = (actor->special2 + 4) & 63;
+	actor->z += FloatBobOffsets[actor->special2]>>1;
+}
+
+//============================================================================
+//
+// A_BishopPuff
+//
+//============================================================================
+
+void A_BishopPuff(mobj_t *actor)
+{
+	mobj_t *mo;
+
+	mo = P_SpawnMobj(actor->x, actor->y, actor->z + 40*FRACUNIT, MT_BISHOP_PUFF);
+	if (mo)
+	{
+		mo->momz = FRACUNIT/2;
+	}
+}
+
+//============================================================================
+//
+// A_BishopPainBlur
+//
+//============================================================================
+
+void A_BishopPainBlur(mobj_t *actor)
+{
+	mobj_t *mo;
+
+	if (P_Random() < 64)
+	{
+		P_SetMobjState(actor, S_BISHOP_BLUR1);
+		return;
+	}
+	mo = P_SpawnMobj(actor->x + ((P_Random() - P_Random()) << 12),
+			 actor->y + ((P_Random() - P_Random()) << 12),
+			 actor->z + ((P_Random() - P_Random()) << 11),
+			 MT_BISHOPPAINBLUR);
+	if (mo)
+	{
+		mo->angle = actor->angle;
+	}
+}
+
+//============================================================================
+//
+// DragonSeek
+//
+//============================================================================
+
+static void DragonSeek(mobj_t *actor, angle_t thresh, angle_t turnMax)
+{
+	int dir;
+	int dist;
+	angle_t delta;
+	angle_t angle;
+	mobj_t *target;
+	int search;
+	int i;
+	int bestArg;
+	angle_t bestAngle;
+	angle_t angleToSpot, angleToTarget;
+	mobj_t *mo;
+
+	target = (mobj_t *)actor->special1;
+	if (target == NULL)
+	{
+		return;
+	}
+	dir = P_FaceMobj(actor, target, &delta);
+	if (delta > thresh)
+	{
+		delta >>= 1;
+		if (delta > turnMax)
+		{
+			delta = turnMax;
+		}
+	}
+	if (dir)
+	{ // Turn clockwise
+		actor->angle += delta;
+	}
+	else
+	{ // Turn counter clockwise
+		actor->angle -= delta;
+	}
+	angle = actor->angle >> ANGLETOFINESHIFT;
+	actor->momx = FixedMul(actor->info->speed, finecosine[angle]);
+	actor->momy = FixedMul(actor->info->speed, finesine[angle]);
+	if (actor->z + actor->height < target->z ||
+	    target->z + target->height < actor->z)
+	{
+		dist = P_AproxDistance(target->x - actor->x, target->y - actor->y);
+		dist = dist / actor->info->speed;
+		if (dist < 1)
+		{
+			dist = 1;
+		}
+		actor->momz = (target->z - actor->z) / dist;
+	}
+	else
+	{
+		dist = P_AproxDistance(target->x - actor->x, target->y - actor->y);
+		dist = dist / actor->info->speed;
+	}
+	if (target->flags & MF_SHOOTABLE && P_Random() < 64)
+	{ // attack the destination mobj if it's attackable
+		mobj_t *oldTarget;
+
+		if (abs(actor->angle - R_PointToAngle2(actor->x, actor->y, target->x, target->y)) < ANGLE_45/2)
+		{
+			oldTarget = actor->target;
+			actor->target = target;
+			if (P_CheckMeleeRange(actor))
+			{
+				P_DamageMobj(actor->target, actor, actor, HITDICE(10));
+				S_StartSound(actor, SFX_DRAGON_ATTACK);
+			}
+			else if (P_Random() < 128 && P_CheckMissileRange(actor))
+			{
+				P_SpawnMissile(actor, target, MT_DRAGON_FX);
+				S_StartSound(actor, SFX_DRAGON_ATTACK);
+			}
+			actor->target = oldTarget;
+		}
+	}
+	if (dist < 4)
+	{ // Hit the target thing
+		if (actor->target && P_Random() < 200)
+		{
+			bestArg = -1;
+			bestAngle = ANGLE_MAX;
+			angleToTarget = R_PointToAngle2(actor->x, actor->y,
+							actor->target->x, actor->target->y);
+			for (i = 0; i < 5; i++)
+			{
+				if (!target->args[i])
+				{
+					continue;
+				}
+				search = -1;
+				mo = P_FindMobjFromTID(target->args[i], &search);
+				angleToSpot = R_PointToAngle2(actor->x, actor->y, mo->x, mo->y);
+				if (abs(angleToSpot - angleToTarget) < bestAngle)
+				{
+					bestAngle = abs(angleToSpot - angleToTarget);
+					bestArg = i;
+				}
+			}
+			if (bestArg != -1)
+			{
+				search = -1;
+				actor->special1 = (intptr_t)P_FindMobjFromTID(target->args[bestArg], &search);
+			}
+		}
+		else
+		{
+			do
+			{
+				i = (P_Random() >> 2) % 5;
+			} while (!target->args[i]);
+			search = -1;
+			actor->special1 = (intptr_t)P_FindMobjFromTID(target->args[i], &search);
+		}
+	}
+}
+
+//============================================================================
+//
+// A_DragonInitFlight
+//
+//============================================================================
+
+void A_DragonInitFlight(mobj_t *actor)
+{
+	int search;
+
+	search = -1;
+	do
+	{ // find the first tid identical to the dragon's tid
+		actor->special1 = (intptr_t)P_FindMobjFromTID(actor->tid, &search);
+		if (search == -1)
+		{
+			P_SetMobjState(actor, actor->info->spawnstate);
+			return;
+		}
+	} while (actor->special1 == (intptr_t)actor);
+	P_RemoveMobjFromTIDList(actor);
+}
+
+//============================================================================
+//
+// A_DragonFlight
+//
+//============================================================================
+
+void A_DragonFlight(mobj_t *actor)
+{
+	angle_t angle;
+
+	DragonSeek(actor, 4*ANGLE_1, 8*ANGLE_1);
+	if (actor->target)
+	{
+		if (!(actor->target->flags & MF_SHOOTABLE))
+		{ // target died
+			actor->target = NULL;
+			return;
+		}
+		angle = R_PointToAngle2(actor->x, actor->y, actor->target->x, actor->target->y);
+		if (abs(actor->angle - angle) < ANGLE_45/2 && P_CheckMeleeRange(actor))
+		{
+			P_DamageMobj(actor->target, actor, actor, HITDICE(8));
+			S_StartSound(actor, SFX_DRAGON_ATTACK);
+		}
+		else if (abs(actor->angle - angle) <= ANGLE_1*20)
+		{
+			P_SetMobjState(actor, actor->info->missilestate);
+			S_StartSound(actor, SFX_DRAGON_ATTACK);
+		}
+	}
+	else
+	{
+		P_LookForPlayers(actor, true);
+	}
+}
+
+//============================================================================
+//
+// A_DragonFlap
+//
+//============================================================================
+
+void A_DragonFlap(mobj_t *actor)
+{
+	A_DragonFlight(actor);
+	if (P_Random() < 240)
+	{
+		S_StartSound(actor, SFX_DRAGON_WINGFLAP);
+	}
+	else
+	{
+		S_StartSound(actor, actor->info->activesound);
+	}
+}
+
+//============================================================================
+//
+// A_DragonAttack
+//
+//============================================================================
+
+void A_DragonAttack(mobj_t *actor)
+{
+	P_SpawnMissile(actor, actor->target, MT_DRAGON_FX);
+}
+
+//============================================================================
+//
+// A_DragonFX2
+//
+//============================================================================
+
+void A_DragonFX2(mobj_t *actor)
+{
+	mobj_t *mo;
+	int i;
+	int delay;
+
+	delay = 16 + (P_Random() >> 3);
+	for (i = 1 + (P_Random() & 3); i; i--)
+	{
+		mo = P_SpawnMobj(actor->x + ((P_Random() - 128) << 14),
+				 actor->y + ((P_Random() - 128) << 14),
+				 actor->z + ((P_Random() - 128) << 12),
+				 MT_DRAGON_FX2);
+		if (mo)
+		{
+			mo->tics = delay + (P_Random() & 3) * i * 2;
+			mo->target = actor->target;
+		}
+	}
+}
+
+//============================================================================
+//
+// A_DragonPain
+//
+//============================================================================
+
+void A_DragonPain(mobj_t *actor)
+{
+	A_Pain(actor);
+	if (!actor->special1)
+	{ // no destination spot yet
+		P_SetMobjState(actor, S_DRAGON_INIT);
+	}
+}
+
+//============================================================================
+//
+// A_DragonCheckCrash
+//
+//============================================================================
+
+void A_DragonCheckCrash(mobj_t *actor)
+{
+	if (actor->z <= actor->floorz)
+	{
+		P_SetMobjState(actor, S_DRAGON_CRASH1);
+	}
+}
+
+//============================================================================
+// Demon AI
+//============================================================================
+
+//
+// A_DemonAttack1 (melee)
+//
+void A_DemonAttack1(mobj_t *actor)
+{
+	if (P_CheckMeleeRange(actor))
+	{
+		P_DamageMobj(actor->target, actor, actor, HITDICE(2));
+	}
+}
+
+//
+// A_DemonAttack2 (missile)
+//
+void A_DemonAttack2(mobj_t *actor)
+{
+	mobj_t *mo;
+	int fireBall;
+
+	if (actor->type == MT_DEMON)
+	{
+		fireBall = MT_DEMONFX1;
+	}
+	else
+	{
+		fireBall = MT_DEMON2FX1;
+	}
+	mo = P_SpawnMissile(actor, actor->target, fireBall);
+	if (mo)
+	{
+		mo->z += 30*FRACUNIT;
+		S_StartSound(actor, SFX_DEMON_MISSILE_FIRE);
+	}
+}
+
+//
+// A_DemonDeath
+//
+void A_DemonDeath(mobj_t *actor)
+{
+	mobj_t *mo;
+	angle_t angle;
+
+	mo = P_SpawnMobj(actor->x, actor->y, actor->z + 45*FRACUNIT, MT_DEMONCHUNK1);
+	if (mo)
+	{
+		angle = actor->angle + ANG90;
+		mo->momz = 8*FRACUNIT;
+		mo->momx = FixedMul((P_Random() << 10) + FRACUNIT,
+				    finecosine[angle>>ANGLETOFINESHIFT]);
+		mo->momy = FixedMul((P_Random() << 10) + FRACUNIT,
+				    finesine[angle>>ANGLETOFINESHIFT]);
+		mo->target = actor;
+	}
+	mo = P_SpawnMobj(actor->x, actor->y, actor->z + 45*FRACUNIT, MT_DEMONCHUNK2);
+	if (mo)
+	{
+		angle = actor->angle - ANG90;
+		mo->momz = 8*FRACUNIT;
+		mo->momx = FixedMul((P_Random() << 10) + FRACUNIT,
+				    finecosine[angle>>ANGLETOFINESHIFT]);
+		mo->momy = FixedMul((P_Random() << 10) + FRACUNIT,
+				    finesine[angle>>ANGLETOFINESHIFT]);
+		mo->target = actor;
+	}
+	mo = P_SpawnMobj(actor->x, actor->y, actor->z + 45*FRACUNIT, MT_DEMONCHUNK3);
+	if (mo)
+	{
+		angle = actor->angle - ANG90;
+		mo->momz = 8*FRACUNIT;
+		mo->momx = FixedMul((P_Random() << 10) + FRACUNIT,
+				    finecosine[angle>>ANGLETOFINESHIFT]);
+		mo->momy = FixedMul((P_Random() << 10) + FRACUNIT,
+				    finesine[angle>>ANGLETOFINESHIFT]);
+		mo->target = actor;
+	}
+	mo = P_SpawnMobj(actor->x, actor->y, actor->z + 45*FRACUNIT, MT_DEMONCHUNK4);
+	if (mo)
+	{
+		angle = actor->angle - ANG90;
+		mo->momz = 8*FRACUNIT;
+		mo->momx = FixedMul((P_Random() << 10) + FRACUNIT,
+				    finecosine[angle>>ANGLETOFINESHIFT]);
+		mo->momy = FixedMul((P_Random() << 10) + FRACUNIT,
+				    finesine[angle>>ANGLETOFINESHIFT]);
+		mo->target = actor;
+	}
+	mo = P_SpawnMobj(actor->x, actor->y, actor->z + 45*FRACUNIT, MT_DEMONCHUNK5);
+	if (mo)
+	{
+		angle = actor->angle - ANG90;
+		mo->momz = 8*FRACUNIT;
+		mo->momx = FixedMul((P_Random() << 10) + FRACUNIT,
+				    finecosine[angle>>ANGLETOFINESHIFT]);
+		mo->momy = FixedMul((P_Random() << 10) + FRACUNIT,
+				    finesine[angle>>ANGLETOFINESHIFT]);
+		mo->target = actor;
+	}
+}
+
+//===========================================================================
+//
+// A_Demon2Death
+//
+//===========================================================================
+
+void A_Demon2Death(mobj_t *actor)
+{
+	mobj_t *mo;
+	angle_t angle;
+
+	mo = P_SpawnMobj(actor->x, actor->y, actor->z + 45*FRACUNIT, MT_DEMON2CHUNK1);
+	if (mo)
+	{
+		angle = actor->angle + ANG90;
+		mo->momz = 8*FRACUNIT;
+		mo->momx = FixedMul((P_Random() << 10) + FRACUNIT,
+				    finecosine[angle>>ANGLETOFINESHIFT]);
+		mo->momy = FixedMul((P_Random() << 10) + FRACUNIT,
+				    finesine[angle>>ANGLETOFINESHIFT]);
+		mo->target = actor;
+	}
+	mo = P_SpawnMobj(actor->x, actor->y, actor->z + 45*FRACUNIT, MT_DEMON2CHUNK2);
+	if (mo)
+	{
+		angle = actor->angle - ANG90;
+		mo->momz = 8*FRACUNIT;
+		mo->momx = FixedMul((P_Random() << 10) + FRACUNIT,
+				    finecosine[angle>>ANGLETOFINESHIFT]);
+		mo->momy = FixedMul((P_Random() << 10) + FRACUNIT,
+				    finesine[angle>>ANGLETOFINESHIFT]);
+		mo->target = actor;
+	}
+	mo = P_SpawnMobj(actor->x, actor->y, actor->z + 45*FRACUNIT, MT_DEMON2CHUNK3);
+	if (mo)
+	{
+		angle = actor->angle - ANG90;
+		mo->momz = 8*FRACUNIT;
+		mo->momx = FixedMul((P_Random() << 10) + FRACUNIT,
+				    finecosine[angle>>ANGLETOFINESHIFT]);
+		mo->momy = FixedMul((P_Random() << 10) + FRACUNIT,
+				    finesine[angle>>ANGLETOFINESHIFT]);
+		mo->target = actor;
+	}
+	mo = P_SpawnMobj(actor->x, actor->y, actor->z + 45*FRACUNIT, MT_DEMON2CHUNK4);
+	if (mo)
+	{
+		angle = actor->angle - ANG90;
+		mo->momz = 8*FRACUNIT;
+		mo->momx = FixedMul((P_Random() << 10) + FRACUNIT,
+				    finecosine[angle>>ANGLETOFINESHIFT]);
+		mo->momy = FixedMul((P_Random() << 10) + FRACUNIT,
+				    finesine[angle>>ANGLETOFINESHIFT]);
+		mo->target = actor;
+	}
+	mo = P_SpawnMobj(actor->x, actor->y, actor->z + 45*FRACUNIT, MT_DEMON2CHUNK5);
+	if (mo)
+	{
+		angle = actor->angle - ANG90;
+		mo->momz = 8*FRACUNIT;
+		mo->momx = FixedMul((P_Random() << 10) + FRACUNIT,
+				    finecosine[angle>>ANGLETOFINESHIFT]);
+		mo->momy = FixedMul((P_Random() << 10) + FRACUNIT,
+				    finesine[angle>>ANGLETOFINESHIFT]);
+		mo->target = actor;
+	}
+}
+
+
+//
+// A_SinkMobj
+// Sink a mobj incrementally into the floor
+//
+
+boolean A_SinkMobj(mobj_t *actor)
+{
+	if (actor->floorclip <  actor->info->height)
+	{
+		switch (actor->type)
+		{
+		case MT_THRUSTFLOOR_DOWN:
+		case MT_THRUSTFLOOR_UP:
+			actor->floorclip += 6*FRACUNIT;
+			break;
+		default:
+			actor->floorclip += FRACUNIT;
+			break;
+		}
+		return false;
+	}
+	return true;
+}
+
+//
+// A_RaiseMobj
+// Raise a mobj incrementally from the floor to 
+//
+
+boolean A_RaiseMobj(mobj_t *actor)
+{
+	int done = true;
+
+	// Raise a mobj from the ground
+	if (actor->floorclip > 0)
+	{
+		switch (actor->type)
+		{
+		case MT_WRAITHB:
+			actor->floorclip -= 2*FRACUNIT;
+			break;
+		case MT_THRUSTFLOOR_DOWN:
+		case MT_THRUSTFLOOR_UP:
+			actor->floorclip -= actor->special2*FRACUNIT;
+			break;
+		default:
+			actor->floorclip -= 2*FRACUNIT;
+			break;
+		}
+		if (actor->floorclip <= 0)
+		{
+			actor->floorclip = 0;
+			done = true;
+		}
+		else
+		{
+			done = false;
+		}
+	}
+	return done;		// Reached target height
+}
+
+
+//============================================================================
+// Wraith Variables
+//
+//	special1				Internal index into floatbob
+//	special2
+//============================================================================
+
+//
+// A_WraithInit
+//
+
+void A_WraithInit(mobj_t *actor)
+{
+	actor->z += 48<<FRACBITS;
+	actor->special1 = 0;			// index into floatbob
+}
+
+void A_WraithRaiseInit(mobj_t *actor)
+{
+	actor->flags2 &= ~MF2_DONTDRAW;
+	actor->flags2 &= ~MF2_NONSHOOTABLE;
+	actor->flags |= MF_SHOOTABLE|MF_SOLID;
+	actor->floorclip = actor->info->height;
+}
+
+void A_WraithRaise(mobj_t *actor)
+{
+	if (A_RaiseMobj(actor))
+	{
+		// Reached it's target height
+		P_SetMobjState(actor,S_WRAITH_CHASE1);
+	}
+
+	P_SpawnDirt(actor, actor->radius);
+}
+
+void A_WraithMelee(mobj_t *actor)
+{
+	int amount;
+
+	// Steal health from target and give to player
+	if (P_CheckMeleeRange(actor) && (P_Random() < 220))
+	{
+		amount = HITDICE(2);
+		P_DamageMobj(actor->target, actor, actor, amount);
+		actor->health += amount;
+	}
+}
+
+void A_WraithMissile(mobj_t *actor)
+{
+	mobj_t *mo;
+
+	mo = P_SpawnMissile(actor, actor->target, MT_WRAITHFX1);
+	if (mo)
+	{
+		S_StartSound(actor, SFX_WRAITH_MISSILE_FIRE);
+	}
+}
+
+//
+// A_WraithFX2 - spawns sparkle tail of missile
+//
+void A_WraithFX2(mobj_t *actor)
+{
+	mobj_t *mo;
+	angle_t angle;
+	int i;
+
+	for (i = 0; i < 2; i++)
+	{
+		mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_WRAITHFX2);
+		if (mo)
+		{
+			if (P_Random() < 128)
+			{
+				angle = actor->angle + (P_Random() << 22);
+			}
+			else
+			{
+				angle = actor->angle - (P_Random() << 22);
+			}
+			mo->momz = 0;
+			mo->momx = FixedMul((P_Random() << 7) + FRACUNIT,
+					    finecosine[angle>>ANGLETOFINESHIFT]);
+			mo->momy = FixedMul((P_Random() << 7) + FRACUNIT,
+					    finesine[angle>>ANGLETOFINESHIFT]);
+			mo->target = actor;
+			mo->floorclip = 10*FRACUNIT;
+		}
+	}
+}
+
+// Spawn an FX3 around the actor during attacks
+void A_WraithFX3(mobj_t *actor)
+{
+	mobj_t *mo;
+	int numdropped = P_Random() % 15;
+	int i;
+
+	for (i = 0; i < numdropped; i++)
+	{
+		mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_WRAITHFX3);
+		if (mo)
+		{
+			mo->x += (P_Random() - 128) << 11;
+			mo->y += (P_Random() - 128) << 11;
+			mo->z += (P_Random() << 10);
+			mo->target = actor;
+		}
+	}
+}
+
+// Spawn an FX4 during movement
+void A_WraithFX4(mobj_t *actor)
+{
+	mobj_t *mo;
+	int chance = P_Random();
+	int spawn4, spawn5;
+
+	if (chance < 10)
+	{
+		spawn4 = true;
+		spawn5 = false;
+	}
+	else if (chance < 20)
+	{
+		spawn4 = false;
+		spawn5 = true;
+	}
+	else if (chance < 25)
+	{
+		spawn4 = true;
+		spawn5 = true;
+	}
+	else
+	{
+		spawn4 = false;
+		spawn5 = false;
+	}
+
+	if (spawn4)
+	{
+		mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_WRAITHFX4);
+		if (mo)
+		{
+			mo->x += (P_Random() - 128) << 12;
+			mo->y += (P_Random() - 128) << 12;
+			mo->z += (P_Random() << 10);
+			mo->target = actor;
+		}
+	}
+	if (spawn5)
+	{
+		mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_WRAITHFX5);
+		if (mo)
+		{
+			mo->x += (P_Random() - 128) << 11;
+			mo->y += (P_Random() - 128) << 11;
+			mo->z += (P_Random() << 10);
+			mo->target = actor;
+		}
+	}
+}
+
+void A_WraithLook(mobj_t *actor)
+{
+//	A_WraithFX4(actor);		// too expensive
+	A_Look(actor);
+}
+
+void A_WraithChase(mobj_t *actor)
+{
+	int weaveindex = actor->special1;
+	actor->z += FloatBobOffsets[weaveindex];
+	actor->special1 = (weaveindex + 2) & 63;
+//	if (actor->floorclip > 0)
+//	{
+//		P_SetMobjState(actor, S_WRAITH_RAISE2);
+//		return;
+//	}
+	A_Chase(actor);
+	A_WraithFX4(actor);
+}
+
+
+//============================================================================
+// Ettin AI
+//============================================================================
+
+void A_EttinAttack(mobj_t *actor)
+{
+	if (P_CheckMeleeRange(actor))
+	{
+		P_DamageMobj(actor->target, actor, actor, HITDICE(2));
+	}
+}
+
+void A_DropMace(mobj_t *actor)
+{
+	mobj_t *mo;
+
+	mo = P_SpawnMobj(actor->x, actor->y, actor->z + (actor->height>>1), MT_ETTIN_MACE);
+	if (mo)
+	{
+		mo->momx = (P_Random() - 128) << 11;
+		mo->momy = (P_Random() - 128) << 11;
+		mo->momz = FRACUNIT*10 + (P_Random() << 10);
+		mo->target = actor;
+	}
+}
+
+
+//============================================================================
+// Fire Demon AI
+//
+// special1			index into floatbob
+// special2			whether strafing or not
+//============================================================================
+
+void A_FiredSpawnRock(mobj_t *actor)
+{
+	mobj_t *mo;
+	int x, y, z;
+	int rtype = 0;
+
+	switch (P_Random() % 5)
+	{
+	case 0:
+		rtype = MT_FIREDEMON_FX1;
+		break;
+	case 1:
+		rtype = MT_FIREDEMON_FX2;
+		break;
+	case 2:
+		rtype = MT_FIREDEMON_FX3;
+		break;
+	case 3:
+		rtype = MT_FIREDEMON_FX4;
+		break;
+	case 4:
+		rtype = MT_FIREDEMON_FX5;
+		break;
+	}
+
+	x = actor->x + ((P_Random() - 128) << 12);
+	y = actor->y + ((P_Random() - 128) << 12);
+	z = actor->z + ((P_Random()) << 11);
+	mo = P_SpawnMobj(x, y, z, rtype);
+	if (mo)
+	{
+		mo->target = actor;
+		mo->momx = (P_Random() - 128) << 10;
+		mo->momy = (P_Random() - 128) << 10;
+		mo->momz = (P_Random() << 10);
+		mo->special1 = 2;	// Number bounces
+	}
+
+	// Initialize fire demon
+	actor->special2 = 0;
+	actor->flags &= ~MF_JUSTATTACKED;
+}
+
+void A_FiredRocks(mobj_t *actor)
+{
+	A_FiredSpawnRock(actor);
+	A_FiredSpawnRock(actor);
+	A_FiredSpawnRock(actor);
+	A_FiredSpawnRock(actor);
+	A_FiredSpawnRock(actor);
+}
+
+void A_FiredAttack(mobj_t *actor)
+{
+	mobj_t *mo;
+	mo = P_SpawnMissile(actor, actor->target, MT_FIREDEMON_FX6);
+	if (mo)
+		S_StartSound(actor, SFX_FIRED_ATTACK);
+}
+
+void A_SmBounce(mobj_t *actor)
+{
+	// give some more momentum (x,y,&z)
+	actor->z = actor->floorz + FRACUNIT;
+	actor->momz = (2*FRACUNIT) + (P_Random()<<10);
+	actor->momx = (P_Random() % 3) << FRACBITS;
+	actor->momy = (P_Random() % 3) << FRACBITS;
+}
+
+
+#define FIREDEMON_ATTACK_RANGE	(64 * 8 * FRACUNIT)
+
+void A_FiredChase(mobj_t *actor)
+{
+	int weaveindex = actor->special1;
+	mobj_t *target = actor->target;
+	angle_t ang;
+	fixed_t dist;
+
+	if (actor->reactiontime)
+		actor->reactiontime--;
+	if (actor->threshold)
+		actor->threshold--;
+
+	// Float up and down
+	actor->z += FloatBobOffsets[weaveindex];
+	actor->special1 = (weaveindex + 2) & 63;
+
+	// Insure it stays above certain height
+	if (actor->z < actor->floorz + (64*FRACUNIT))
+	{
+		actor->z += 2*FRACUNIT;
+	}
+
+	if (!actor->target || !(actor->target->flags & MF_SHOOTABLE))
+	{	// Invalid target
+		P_LookForPlayers(actor, true);
+		return;
+	}
+
+	// Strafe
+	if (actor->special2 > 0)
+	{
+		actor->special2--;
+	}
+	else
+	{
+		actor->special2 = 0;
+		actor->momx = actor->momy = 0;
+		dist = P_AproxDistance(actor->x - target->x, actor->y - target->y);
+		if (dist < FIREDEMON_ATTACK_RANGE)
+		{
+			if (P_Random() < 30)
+			{
+				ang = R_PointToAngle2(actor->x, actor->y, target->x, target->y);
+				if (P_Random() < 128)
+					ang += ANGLE_90;
+				else
+					ang -= ANGLE_90;
+				ang >>= ANGLETOFINESHIFT;
+				actor->momx = FixedMul(8*FRACUNIT, finecosine[ang]);
+				actor->momy = FixedMul(8*FRACUNIT, finesine[ang]);
+				actor->special2 = 3;		// strafe time
+			}
+		}
+	}
+
+	FaceMovementDirection(actor);
+
+	// Normal movement
+	if (!actor->special2)
+	{
+		if (--actor->movecount < 0 || !P_Move (actor))
+		{
+			P_NewChaseDir (actor);
+		}
+	}
+
+	// Do missile attack
+	if (!(actor->flags & MF_JUSTATTACKED))
+	{
+		if (P_CheckMissileRange(actor) && (P_Random() < 20))
+		{
+			P_SetMobjState (actor, actor->info->missilestate);
+			actor->flags |= MF_JUSTATTACKED;
+			return;
+		}
+	}
+	else
+	{
+		actor->flags &= ~MF_JUSTATTACKED;
+	}
+
+	// make active sound
+	if (actor->info->activesound && P_Random() < 3)
+	{
+		S_StartSound(actor, actor->info->activesound);
+	}
+}
+
+void A_FiredSplotch(mobj_t *actor)
+{
+	mobj_t *mo;
+
+	mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_FIREDEMON_SPLOTCH1);
+	if (mo)
+	{
+		mo->momx = (P_Random() - 128) << 11;
+		mo->momy = (P_Random() - 128) << 11;
+		mo->momz = FRACUNIT*3 + (P_Random() << 10);
+	}
+	mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_FIREDEMON_SPLOTCH2);
+	if (mo)
+	{
+		mo->momx = (P_Random() - 128) << 11;
+		mo->momy = (P_Random() - 128) << 11;
+		mo->momz = FRACUNIT*3 + (P_Random() << 10);
+	}
+}
+
+
+//============================================================================
+//
+// A_IceGuyLook
+//
+//============================================================================
+
+void A_IceGuyLook(mobj_t *actor)
+{
+	fixed_t dist;
+	fixed_t an;
+
+	A_Look(actor);
+	if (P_Random() < 64)
+	{
+		dist = ((P_Random() - 128) * actor->radius) >> 7;
+		an = (actor->angle + ANG90) >> ANGLETOFINESHIFT;
+
+		P_SpawnMobj(actor->x + FixedMul(dist, finecosine[an]),
+			    actor->y + FixedMul(dist, finesine[an]),
+			    actor->z + 60*FRACUNIT,
+			    MT_ICEGUY_WISP1 + (P_Random() & 1));
+	}
+}
+
+//============================================================================
+//
+// A_IceGuyChase
+//
+//============================================================================
+
+void A_IceGuyChase(mobj_t *actor)
+{
+	fixed_t dist;
+	fixed_t an;
+	mobj_t *mo;
+
+	A_Chase(actor);
+	if (P_Random() < 128)
+	{
+		dist = ((P_Random() - 128) * actor->radius) >> 7;
+		an = (actor->angle + ANG90) >> ANGLETOFINESHIFT;
+
+		mo = P_SpawnMobj(actor->x + FixedMul(dist, finecosine[an]),
+				 actor->y + FixedMul(dist, finesine[an]),
+				 actor->z + 60*FRACUNIT,
+				 MT_ICEGUY_WISP1 + (P_Random() & 1));
+		if (mo)
+		{
+			mo->momx = actor->momx;
+			mo->momy = actor->momy;
+			mo->momz = actor->momz;
+			mo->target = actor;
+		}
+	}
+}
+
+//============================================================================
+//
+// A_IceGuyAttack
+//
+//============================================================================
+
+void A_IceGuyAttack(mobj_t *actor)
+{
+	fixed_t an;
+
+	if (!actor->target)
+	{
+		return;
+	}
+	an = (actor->angle + ANG90) >> ANGLETOFINESHIFT;
+	P_SpawnMissileXYZ(actor->x + FixedMul(actor->radius >> 1, finecosine[an]),
+			  actor->y + FixedMul(actor->radius >> 1, finesine[an]),
+			  actor->z + 40*FRACUNIT, actor, actor->target, MT_ICEGUY_FX);
+	an = (actor->angle - ANG90) >> ANGLETOFINESHIFT;
+	P_SpawnMissileXYZ(actor->x + FixedMul(actor->radius >> 1, finecosine[an]),
+			  actor->y + FixedMul(actor->radius >> 1, finesine[an]),
+			  actor->z + 40*FRACUNIT, actor, actor->target, MT_ICEGUY_FX);
+	S_StartSound(actor, actor->info->attacksound);
+}
+
+//============================================================================
+//
+// A_IceGuyMissilePuff
+//
+//============================================================================
+
+void A_IceGuyMissilePuff(mobj_t *actor)
+{
+	P_SpawnMobj(actor->x, actor->y, actor->z + 2*FRACUNIT, MT_ICEFX_PUFF);
+}
+
+//============================================================================
+//
+// A_IceGuyDie
+//
+//============================================================================
+
+void A_FreezeDeathChunks(mobj_t *actor);
+
+void A_IceGuyDie(mobj_t *actor)
+{
+	actor->momx = 0;
+	actor->momy = 0;
+	actor->momz = 0;
+	actor->height <<= 2;
+	A_FreezeDeathChunks(actor);
+}
+
+//============================================================================
+//
+// A_IceGuyMissileExplode
+//
+//============================================================================
+
+void A_IceGuyMissileExplode(mobj_t *actor)
+{
+	mobj_t *mo;
+	unsigned int i;
+
+	for (i = 0; i < 8; i++)
+	{
+		mo = P_SpawnMissileAngle(actor, MT_ICEGUY_FX2, i*ANG45,	-0.3*FRACUNIT);
+		if (mo)
+		{
+			mo->target = actor->target;
+		}
+	}
+}
+
+
+//============================================================================
+//
+//	Sorcerer stuff
+//
+//	Sorcerer Variables
+//		special1		Angle of ball 1 (all others relative to that)
+//		special2		which ball to stop at in stop mode (MT_???)
+//		args[0]			Denfense time
+//		args[1]			Number of full rotations since stopping mode
+//		args[2]			Target orbit speed for acceleration/deceleration
+//		args[3]			Movement mode (see SORC_ macros)
+//		args[4]			Current ball orbit speed
+//	Sorcerer Ball Variables
+//		special1		Previous angle of ball (for woosh)
+//		special2		Countdown of rapid fire (FX4)
+//		args[0]			If set, don't play the bounce sound when bouncing
+//============================================================================
+
+#define SORCBALL_INITIAL_SPEED		7
+#define SORCBALL_TERMINAL_SPEED		25
+#define SORCBALL_SPEED_ROTATIONS	5
+
+#define SORC_DEFENSE_TIME		255
+#define SORC_DEFENSE_HEIGHT		45
+
+#define BOUNCE_TIME_UNIT		(35/2)
+
+#define SORCFX4_RAPIDFIRE_TIME		(6*3)		/* 3 seconds */
+#define SORCFX4_SPREAD_ANGLE		20
+
+#define SORC_DECELERATE		0
+#define SORC_ACCELERATE		1
+#define SORC_STOPPING		2
+#define SORC_FIRESPELL		3
+#define SORC_STOPPED		4
+#define SORC_NORMAL		5
+#define SORC_FIRING_SPELL	6
+
+#define BALL1_ANGLEOFFSET	0
+#define BALL2_ANGLEOFFSET	(ANGLE_MAX / 3)
+#define BALL3_ANGLEOFFSET	((ANGLE_MAX / 3) * 2)
+
+void A_SorcBallOrbit(mobj_t *actor);
+void A_SorcSpinBalls(mobj_t *actor);
+void A_SpeedBalls(mobj_t *actor);
+void A_SlowBalls(mobj_t *actor);
+void A_StopBalls(mobj_t *actor);
+void A_AccelBalls(mobj_t *actor);
+void A_DecelBalls(mobj_t *actor);
+void A_SorcBossAttack(mobj_t *actor);
+void A_SpawnFizzle(mobj_t *actor);
+void A_CastSorcererSpell(mobj_t *actor);
+void A_SorcUpdateBallAngle(mobj_t *actor);
+void A_BounceCheck(mobj_t *actor);
+void A_SorcFX1Seek(mobj_t *actor);
+void A_SorcOffense1(mobj_t *actor);
+void A_SorcOffense2(mobj_t *actor);
+
+// Spawn spinning balls above head - actor is sorcerer
+void A_SorcSpinBalls(mobj_t *actor)
+{
+	mobj_t *mo;
+	fixed_t z;
+
+	A_SlowBalls(actor);
+	actor->args[0] = 0;					// Currently no defense
+	actor->args[3] = SORC_NORMAL;
+	actor->args[4] = SORCBALL_INITIAL_SPEED;		// Initial orbit speed
+	actor->special1 = ANGLE_1;
+	z = actor->z - actor->floorclip + actor->info->height;
+
+	mo = P_SpawnMobj(actor->x, actor->y, z, MT_SORCBALL1);
+	if (mo)
+	{
+		mo->target = actor;
+		mo->special2 = SORCFX4_RAPIDFIRE_TIME;
+	}
+	mo = P_SpawnMobj(actor->x, actor->y, z, MT_SORCBALL2);
+	if (mo)
+		mo->target = actor;
+	mo = P_SpawnMobj(actor->x, actor->y, z, MT_SORCBALL3);
+	if (mo)
+		mo->target = actor;
+}
+
+//
+// A_SorcBallOrbit() ==========================================
+//
+void A_SorcBallOrbit(mobj_t *actor)
+{
+	int x,y;
+	angle_t angle = 0, baseangle;
+	int mode = actor->target->args[3];
+	mobj_t *parent = (mobj_t *)actor->target;
+	int dist = parent->radius - (actor->radius<<1);
+	angle_t prevangle = actor->special1;
+
+	if (actor->target->health <= 0)
+		P_SetMobjState(actor, actor->info->painstate);
+
+	baseangle = (angle_t)parent->special1;
+	switch (actor->type)
+	{
+	case MT_SORCBALL1:
+		angle = baseangle + BALL1_ANGLEOFFSET;
+		break;
+	case MT_SORCBALL2:
+		angle = baseangle + BALL2_ANGLEOFFSET;
+		break;
+	case MT_SORCBALL3:
+		angle = baseangle + BALL3_ANGLEOFFSET;
+		break;
+	default:
+		I_Error("corrupted sorcerer");
+		break;
+	}
+	actor->angle = angle;
+	angle >>= ANGLETOFINESHIFT;
+
+	switch (mode)
+	{
+	case SORC_NORMAL:		// Balls rotating normally
+		A_SorcUpdateBallAngle(actor);
+		break;
+	case SORC_DECELERATE:		// Balls decelerating
+		A_DecelBalls(actor);
+		A_SorcUpdateBallAngle(actor);
+		break;
+	case SORC_ACCELERATE:		// Balls accelerating
+		A_AccelBalls(actor);
+		A_SorcUpdateBallAngle(actor);
+		break;
+	case SORC_STOPPING:		// Balls stopping
+		if ((parent->special2 == actor->type) &&
+			(parent->args[1] > SORCBALL_SPEED_ROTATIONS) &&
+			(abs(angle - (parent->angle>>ANGLETOFINESHIFT)) < (30<<5)))
+		{
+			// Can stop now
+			actor->target->args[3] = SORC_FIRESPELL;
+			actor->target->args[4] = 0;
+			// Set angle so ball angle == sorcerer angle
+			switch (actor->type)
+			{
+			case MT_SORCBALL1:
+				parent->special1 = (int)(parent->angle - BALL1_ANGLEOFFSET);
+				break;
+			case MT_SORCBALL2:
+				parent->special1 = (int)(parent->angle - BALL2_ANGLEOFFSET);
+				break;
+			case MT_SORCBALL3:
+				parent->special1 = (int)(parent->angle - BALL3_ANGLEOFFSET);
+				break;
+			default:
+				break;
+			}
+		}
+		else
+		{
+			A_SorcUpdateBallAngle(actor);
+		}
+		break;
+	case SORC_FIRESPELL:		// Casting spell
+		if (parent->special2 == actor->type)
+		{
+			// Put sorcerer into special throw spell anim
+			if (parent->health > 0)
+				P_SetMobjStateNF(parent, S_SORC_ATTACK1);
+
+			if (actor->type == MT_SORCBALL1 && P_Random()<200)
+			{
+				S_StartSound(NULL, SFX_SORCERER_SPELLCAST);
+				actor->special2 = SORCFX4_RAPIDFIRE_TIME;
+				actor->args[4] = 128;
+				parent->args[3] = SORC_FIRING_SPELL;
+			}
+			else
+			{
+				A_CastSorcererSpell(actor);
+				parent->args[3] = SORC_STOPPED;
+			}
+		}
+		break;
+	case SORC_FIRING_SPELL:
+		if (parent->special2 == actor->type)
+		{
+			if (actor->special2-- <= 0)
+			{
+				// Done rapid firing 
+				parent->args[3] = SORC_STOPPED;
+				// Back to orbit balls
+				if (parent->health > 0)
+					P_SetMobjStateNF(parent, S_SORC_ATTACK4);
+			}
+			else
+			{
+				// Do rapid fire spell
+				A_SorcOffense2(actor);
+			}
+		}
+		break;
+	case SORC_STOPPED:		// Balls stopped
+	default:
+		break;
+	}
+
+	if ((angle < prevangle) && (parent->args[4] == SORCBALL_TERMINAL_SPEED))
+	{
+		parent->args[1]++;	// Bump rotation counter
+		// Completed full rotation - make woosh sound
+		S_StartSound(actor, SFX_SORCERER_BALLWOOSH);
+	}
+	actor->special1 = angle;	// Set previous angle
+	x = parent->x + FixedMul(dist, finecosine[angle]);
+	y = parent->y + FixedMul(dist, finesine[angle]);
+	actor->x = x;
+	actor->y = y;
+	actor->z = parent->z - parent->floorclip + parent->info->height;
+}
+
+//
+// Set balls to speed mode - actor is sorcerer
+//
+void A_SpeedBalls(mobj_t *actor)
+{
+	actor->args[3] = SORC_ACCELERATE;		// speed mode
+	actor->args[2] = SORCBALL_TERMINAL_SPEED;	// target speed
+}
+
+//
+// Set balls to slow mode - actor is sorcerer
+//
+void A_SlowBalls(mobj_t *actor)
+{
+	actor->args[3] = SORC_DECELERATE;		// slow mode
+	actor->args[2] = SORCBALL_INITIAL_SPEED;	// target speed
+}
+
+//
+// Instant stop when rotation gets to ball in special2
+//		actor is sorcerer
+//
+void A_StopBalls(mobj_t *actor)
+{
+	int chance = P_Random();
+	actor->args[3] = SORC_STOPPING;			// stopping mode
+	actor->args[1] = 0;				// Reset rotation counter
+
+	if ((actor->args[0] <= 0) && (chance < 200))
+	{
+		actor->special2 = MT_SORCBALL2;		// Blue
+	}
+	else if ((actor->health < (actor->info->spawnhealth >> 1)) &&
+			(chance < 200))
+	{
+		actor->special2 = MT_SORCBALL3;		// Green
+	}
+	else
+	{
+		actor->special2 = MT_SORCBALL1;		// Yellow
+	}
+}
+
+//
+// Increase ball orbit speed - actor is ball
+//
+void A_AccelBalls(mobj_t *actor)
+{
+	mobj_t *sorc = actor->target;
+
+	if (sorc->args[4] < sorc->args[2])
+	{
+		sorc->args[4]++;
+	}
+	else
+	{
+		sorc->args[3] = SORC_NORMAL;
+		if (sorc->args[4] >= SORCBALL_TERMINAL_SPEED)
+		{
+			// Reached terminal velocity - stop balls
+			A_StopBalls(sorc);
+		}
+	}
+}
+
+// Decrease ball orbit speed - actor is ball
+void A_DecelBalls(mobj_t *actor)
+{
+	mobj_t *sorc = actor->target;
+
+	if (sorc->args[4] > sorc->args[2])
+	{
+		sorc->args[4]--;
+	}
+	else
+	{
+		sorc->args[3] = SORC_NORMAL;
+	}
+}
+
+// Update angle if first ball - actor is ball
+void A_SorcUpdateBallAngle(mobj_t *actor)
+{
+	if (actor->type == MT_SORCBALL1)
+	{
+		actor->target->special1 += ANGLE_1*actor->target->args[4];
+	}
+}
+
+// actor is ball
+void A_CastSorcererSpell(mobj_t *actor)
+{
+	mobj_t *mo;
+	int spell = actor->type;
+	angle_t ang1, ang2;
+	fixed_t z;
+	mobj_t *parent = actor->target;
+
+	S_StartSound(NULL, SFX_SORCERER_SPELLCAST);
+
+	// Put sorcerer into throw spell animation
+	if (parent->health > 0)
+		P_SetMobjStateNF(parent, S_SORC_ATTACK4);
+
+	switch (spell)
+	{
+	case MT_SORCBALL1:		// Offensive
+		A_SorcOffense1(actor);
+		break;
+	case MT_SORCBALL2:		// Defensive
+		z = parent->z - parent->floorclip + SORC_DEFENSE_HEIGHT*FRACUNIT;
+		mo = P_SpawnMobj(actor->x, actor->y, z, MT_SORCFX2);
+		parent->flags2 |= MF2_REFLECTIVE|MF2_INVULNERABLE;
+		parent->args[0] = SORC_DEFENSE_TIME;
+		if (mo)
+			mo->target = parent;
+		break;
+	case MT_SORCBALL3:		// Reinforcements
+		ang1 = actor->angle - ANGLE_45;
+		ang2 = actor->angle + ANGLE_45;
+		if (actor->health < (actor->info->spawnhealth/3))
+		{	// Spawn 2 at a time
+			mo = P_SpawnMissileAngle(parent, MT_SORCFX3, ang1, 4*FRACUNIT);
+			if (mo)
+				mo->target = parent;
+			mo = P_SpawnMissileAngle(parent, MT_SORCFX3, ang2, 4*FRACUNIT);
+			if (mo)
+				mo->target = parent;
+		}
+		else
+		{
+			if (P_Random() < 128)
+				ang1 = ang2;
+			mo = P_SpawnMissileAngle(parent, MT_SORCFX3, ang1, 4*FRACUNIT);
+			if (mo)
+				mo->target = parent;
+		}
+		break;
+	default:
+		break;
+	}
+}
+
+/*
+void A_SpawnReinforcements(mobj_t *actor)
+{
+	mobj_t *parent = actor->target;
+	mobj_t *mo;
+	angle_t ang;
+
+	ang = ANGLE_1 * P_Random();
+	mo = P_SpawnMissileAngle(actor, MT_SORCFX3, ang, 5*FRACUNIT);
+	if (mo)
+		mo->target = parent;
+}
+*/
+
+// actor is ball
+void A_SorcOffense1(mobj_t *actor)
+{
+	mobj_t *mo;
+	angle_t ang1,ang2;
+	mobj_t *parent = (mobj_t *)actor->target;
+
+	ang1 = actor->angle + ANGLE_1*70;
+	ang2 = actor->angle - ANGLE_1*70;
+	mo = P_SpawnMissileAngle(parent, MT_SORCFX1, ang1, 0);
+	if (mo)
+	{
+		mo->target = parent;
+		mo->special1 = (intptr_t)parent->target;
+		mo->args[4] = BOUNCE_TIME_UNIT;
+		mo->args[3] = 15;	// Bounce time in seconds
+	}
+	mo = P_SpawnMissileAngle(parent, MT_SORCFX1, ang2, 0);
+	if (mo)
+	{
+		mo->target = parent;
+		mo->special1 = (intptr_t)parent->target;
+		mo->args[4] = BOUNCE_TIME_UNIT;
+		mo->args[3] = 15;	// Bounce time in seconds
+	}
+}
+
+// Actor is ball
+void A_SorcOffense2(mobj_t *actor)
+{
+	angle_t ang1;
+	mobj_t *mo;
+	int delta, idx;
+	mobj_t *parent = actor->target;
+	mobj_t *dest = parent->target;
+	int dist;
+
+	idx = actor->args[4] << 5;
+	actor->args[4] += 15;
+	delta = (finesine[idx])*SORCFX4_SPREAD_ANGLE;
+	delta = (delta>>FRACBITS)*ANGLE_1;
+	ang1 = actor->angle + delta;
+	mo = P_SpawnMissileAngle(parent, MT_SORCFX4, ang1, 0);
+	if (mo)
+	{
+		mo->special2 = 35*5/2;		// 5 seconds
+		dist = P_AproxDistance(dest->x - mo->x, dest->y - mo->y);
+		dist = dist / mo->info->speed;
+		if (dist < 1)
+			dist = 1;
+		mo->momz = (dest->z-mo->z) / dist;
+	}
+}
+
+// Resume ball spinning
+void A_SorcBossAttack(mobj_t *actor)
+{
+	actor->args[3] = SORC_ACCELERATE;
+	actor->args[2] = SORCBALL_INITIAL_SPEED;
+}
+
+// spell cast magic fizzle
+void A_SpawnFizzle(mobj_t *actor)
+{
+	fixed_t x, y, z;
+	fixed_t dist = 5*FRACUNIT;
+	angle_t angle = actor->angle >> ANGLETOFINESHIFT;
+	fixed_t speed = actor->info->speed;
+	angle_t rangle;
+	mobj_t *mo;
+	int ix;
+
+	x = actor->x + FixedMul(dist, finecosine[angle]);
+	y = actor->y + FixedMul(dist, finesine[angle]);
+	z = actor->z - actor->floorclip + (actor->height>>1);
+	for (ix = 0; ix < 5; ix++)
+	{
+		mo = P_SpawnMobj(x, y, z, MT_SORCSPARK1);
+		if (mo)
+		{
+			rangle = angle + ((P_Random() % 5) << 1);
+			mo->momx = FixedMul(P_Random() % speed, finecosine[rangle]);
+			mo->momy = FixedMul(P_Random() % speed, finesine[rangle]);
+			mo->momz = FRACUNIT*2;
+		}
+	}
+}
+
+//============================================================================
+// Yellow spell - offense
+//============================================================================
+
+void A_SorcFX1Seek(mobj_t *actor)
+{
+	A_BounceCheck(actor);
+	P_SeekerMissile(actor, ANGLE_1*2, ANGLE_1*6);
+}
+
+//============================================================================
+// Blue spell - defense
+//============================================================================
+//
+// FX2 Variables
+//		special1		current angle
+//		special2
+//		args[0]		0 = CW,  1 = CCW
+//		args[1]		
+//============================================================================
+
+// Split ball in two
+void A_SorcFX2Split(mobj_t *actor)
+{
+	mobj_t *mo;
+
+	mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_SORCFX2);
+	if (mo)
+	{
+		mo->target = actor->target;
+		mo->args[0] = 0;			// CW
+		mo->special1 = actor->angle;		// Set angle
+		P_SetMobjStateNF(mo, S_SORCFX2_ORBIT1);
+	}
+	mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_SORCFX2);
+	if (mo)
+	{
+		mo->target = actor->target;
+		mo->args[0] = 1;			// CCW
+		mo->special1 = actor->angle;		// Set angle
+		P_SetMobjStateNF(mo, S_SORCFX2_ORBIT1);
+	}
+	P_SetMobjStateNF(actor, S_NULL);
+}
+
+// Orbit FX2 about sorcerer
+void A_SorcFX2Orbit(mobj_t *actor)
+{
+	angle_t angle;
+	fixed_t x, y, z;
+	mobj_t *parent = actor->target;
+	fixed_t dist = parent->info->radius;
+
+	if ((parent->health <= 0) ||		// Sorcerer is dead
+		(!parent->args[0]))			// Time expired
+	{
+		P_SetMobjStateNF(actor, actor->info->deathstate);
+		parent->args[0] = 0;
+		parent->flags2 &= ~MF2_REFLECTIVE;
+		parent->flags2 &= ~MF2_INVULNERABLE;
+	}
+
+	if (actor->args[0] && (parent->args[0]-- <= 0))	// Time expired
+	{
+		P_SetMobjStateNF(actor, actor->info->deathstate);
+		parent->args[0] = 0;
+		parent->flags2 &= ~MF2_REFLECTIVE;
+	}
+
+	// Move to new position based on angle
+	if (actor->args[0])		// Counter clock-wise
+	{
+		actor->special1 += ANGLE_1*10;
+		angle = ((angle_t)actor->special1) >> ANGLETOFINESHIFT;
+		x = parent->x + FixedMul(dist, finecosine[angle]);
+		y = parent->y + FixedMul(dist, finesine[angle]);
+		z = parent->z - parent->floorclip + SORC_DEFENSE_HEIGHT*FRACUNIT;
+		z += FixedMul(15*FRACUNIT, finecosine[angle]);
+		// Spawn trailer
+		P_SpawnMobj(x, y, z, MT_SORCFX2_T1);
+	}
+	else	// Clock wise
+	{
+		actor->special1 -= ANGLE_1*10;
+		angle = ((angle_t)actor->special1) >> ANGLETOFINESHIFT;
+		x = parent->x + FixedMul(dist, finecosine[angle]);
+		y = parent->y + FixedMul(dist, finesine[angle]);
+		z = parent->z - parent->floorclip + SORC_DEFENSE_HEIGHT*FRACUNIT;
+		z += FixedMul(20*FRACUNIT, finesine[angle]);
+		// Spawn trailer
+		P_SpawnMobj(x, y, z, MT_SORCFX2_T1);
+	}
+
+	actor->x = x;
+	actor->y = y;
+	actor->z = z;
+}
+
+//============================================================================
+// Green spell - spawn bishops
+//============================================================================
+
+void A_SpawnBishop(mobj_t *actor)
+{
+	mobj_t *mo;
+	mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_BISHOP);
+	if (mo)
+	{
+		if (!P_TestMobjLocation(mo))
+		{
+			P_SetMobjState(mo, S_NULL);
+		}
+	}
+	P_SetMobjState(actor, S_NULL);
+}
+
+/*
+void A_SmokePuffEntry(mobj_t *actor)
+{
+	P_SpawnMobj(actor->x, actor->y, actor->z, MT_MNTRSMOKE);
+}
+*/
+
+void A_SmokePuffExit(mobj_t *actor)
+{
+	P_SpawnMobj(actor->x, actor->y, actor->z, MT_MNTRSMOKEEXIT);
+}
+
+void A_SorcererBishopEntry(mobj_t *actor)
+{
+	P_SpawnMobj(actor->x, actor->y, actor->z, MT_SORCFX3_EXPLOSION);
+	S_StartSound(actor, actor->info->seesound);
+}
+
+//============================================================================
+// FX4 - rapid fire balls
+//============================================================================
+
+void A_SorcFX4Check(mobj_t *actor)
+{
+	if (actor->special2-- <= 0)
+	{
+		P_SetMobjStateNF(actor, actor->info->deathstate);
+	}
+}
+
+//============================================================================
+// Ball death - spawn stuff
+//============================================================================
+
+void A_SorcBallPop(mobj_t *actor)
+{
+	S_StartSound(NULL, SFX_SORCERER_BALLPOP);
+	actor->flags &= ~MF_NOGRAVITY;
+	actor->flags2 |= MF2_LOGRAV;
+	actor->momx = ((P_Random() % 10) - 5) << FRACBITS;
+	actor->momy = ((P_Random() % 10) - 5) << FRACBITS;
+	actor->momz = (2 + (P_Random() % 3)) << FRACBITS;
+	actor->special2 = 4*FRACUNIT;		// Initial bounce factor
+	actor->args[4] = BOUNCE_TIME_UNIT;	// Bounce time unit
+	actor->args[3] = 5;			// Bounce time in seconds
+}
+
+void A_BounceCheck(mobj_t *actor)
+{
+	if (actor->args[4]-- <= 0)
+	{
+		if (actor->args[3]-- <= 0)
+		{
+			P_SetMobjState(actor, actor->info->deathstate);
+			switch (actor->type)
+			{
+			case MT_SORCBALL1:
+			case MT_SORCBALL2:
+			case MT_SORCBALL3:
+				S_StartSound(NULL, SFX_SORCERER_BIGBALLEXPLODE);
+				break;
+			case MT_SORCFX1:
+				S_StartSound(NULL, SFX_SORCERER_HEADSCREAM);
+				break;
+			default:
+				break;
+			}
+		}
+		else
+		{
+			actor->args[4] = BOUNCE_TIME_UNIT;
+		}
+	}
+}
+
+
+//============================================================================
+// Class Bosses
+//============================================================================
+#define CLASS_BOSS_STRAFE_RANGE	(64 * 10 * FRACUNIT)
+
+void A_FastChase(mobj_t *actor)
+{
+	int delta;
+	fixed_t dist;
+	angle_t ang;
+	mobj_t *target;
+
+	if (actor->reactiontime)
+	{
+		actor->reactiontime--;
+	}
+
+	// Modify target threshold
+	if (actor->threshold)
+	{
+		actor->threshold--;
+	}
+
+	if (gameskill == sk_nightmare)
+	{ // Monsters move faster in nightmare mode
+		actor->tics -= actor->tics/2;
+		if (actor->tics < 3)
+		{
+			actor->tics = 3;
+		}
+	}
+
+//
+// turn towards movement direction if not there yet
+//
+	if (actor->movedir < 8)
+	{
+		actor->angle &= (7 << 29);
+		delta = actor->angle - (actor->movedir << 29);
+		if (delta > 0)
+		{
+			actor->angle -= ANG90/2;
+		}
+		else if (delta < 0)
+		{
+			actor->angle += ANG90/2;
+		}
+	}
+
+	if (!actor->target || !(actor->target->flags & MF_SHOOTABLE))
+	{ // look for a new target
+		if (P_LookForPlayers(actor, true))
+		{ // got a new target
+			return;
+		}
+		P_SetMobjState(actor, actor->info->spawnstate);
+		return;
+	}
+
+//
+// don't attack twice in a row
+//
+	if (actor->flags & MF_JUSTATTACKED)
+	{
+		actor->flags &= ~MF_JUSTATTACKED;
+		if (gameskill != sk_nightmare)
+			P_NewChaseDir (actor);
+		return;
+	}
+
+	// Strafe
+	if (actor->special2 > 0)
+	{
+		actor->special2--;
+	}
+	else
+	{
+		target = actor->target;
+		actor->special2 = 0;
+		actor->momx = actor->momy = 0;
+		dist = P_AproxDistance (actor->x - target->x,
+					actor->y - target->y);
+		if (dist < CLASS_BOSS_STRAFE_RANGE)
+		{
+			if (P_Random() < 100)
+			{
+				ang = R_PointToAngle2(actor->x, actor->y,
+							target->x, target->y);
+				if (P_Random() < 128)
+					ang += ANGLE_90;
+				else
+					ang -= ANGLE_90;
+				ang >>= ANGLETOFINESHIFT;
+				actor->momx = FixedMul(13*FRACUNIT, finecosine[ang]);
+				actor->momy = FixedMul(13*FRACUNIT, finesine[ang]);
+				actor->special2 = 3;		// strafe time
+			}
+		}
+	}
+
+//
+// check for missile attack
+//
+	if (actor->info->missilestate)
+	{
+		if (gameskill < sk_nightmare && actor->movecount)
+			goto nomissile;
+		if (!P_CheckMissileRange (actor))
+			goto nomissile;
+		P_SetMobjState (actor, actor->info->missilestate);
+		actor->flags |= MF_JUSTATTACKED;
+		return;
+	}
+
+nomissile:
+//
+// possibly choose another target
+//
+	if (netgame && !actor->threshold && !P_CheckSight (actor, actor->target) )
+	{
+		if (P_LookForPlayers(actor, true))
+			return;		// got a new target
+	}
+
+//
+// chase towards player
+//
+	if (!actor->special2)
+	{
+		if (--actor->movecount < 0 || !P_Move(actor))
+		{
+			P_NewChaseDir (actor);
+		}
+	}
+}
+
+void A_FighterAttack(mobj_t *actor)
+{
+	extern void A_FSwordAttack2(mobj_t *actor);
+
+	if (!actor->target)
+		return;
+	A_FSwordAttack2(actor);
+}
+
+void A_ClericAttack(mobj_t *actor)
+{
+	extern void A_CHolyAttack3(mobj_t *actor);
+
+	if (!actor->target)
+		return;
+	A_CHolyAttack3(actor);
+}
+
+void A_MageAttack(mobj_t *actor)
+{
+	extern void A_MStaffAttack2(mobj_t *actor);
+
+	if (!actor->target)
+		return;
+	A_MStaffAttack2(actor);
+}
+
+void A_ClassBossHealth(mobj_t *actor)
+{
+	if (netgame && !deathmatch)		// co-op only
+	{
+		if (!actor->special1)
+		{
+			actor->health *= 5;
+			actor->special1 = true;	// has been initialized
+		}
+	}
+}
+
+
+//===========================================================================
+//
+// A_CheckFloor - Checks if an object hit the floor
+//
+//===========================================================================
+
+void A_CheckFloor(mobj_t *actor)
+{
+	if (actor->z <= actor->floorz)
+	{
+		actor->z = actor->floorz;
+		actor->flags2 &= ~MF2_LOGRAV;
+		P_SetMobjState(actor, actor->info->deathstate);
+	}
+}
+
+//============================================================================
+//
+// A_FreezeDeath
+//
+//============================================================================
+
+void A_FreezeDeath(mobj_t *actor)
+{
+	actor->tics = 75 + P_Random() + P_Random();
+	actor->flags |= MF_SOLID|MF_SHOOTABLE|MF_NOBLOOD;
+	actor->flags2 |= MF2_PUSHABLE|MF2_TELESTOMP|MF2_PASSMOBJ|MF2_SLIDE;
+	actor->height <<= 2;
+	S_StartSound(actor, SFX_FREEZE_DEATH);
+
+	if (actor->player)
+	{
+		actor->player->damagecount = 0;
+		actor->player->poisoncount = 0;
+		actor->player->bonuscount = 0;
+		if (actor->player == &players[consoleplayer])
+		{
+			SB_PaletteFlash(false);
+		}
+	}
+	else if (actor->flags&MF_COUNTKILL && actor->special)
+	{ // Initiate monster death actions
+		P_ExecuteLineSpecial(actor->special, actor->args, NULL, 0, actor);
+	}
+}
+
+//============================================================================
+//
+// A_IceSetTics
+//
+//============================================================================
+
+void A_IceSetTics(mobj_t *actor)
+{
+	int floor;
+
+	actor->tics = 70 + (P_Random() & 63);
+	floor = P_GetThingFloorType(actor);
+	if (floor == FLOOR_LAVA)
+	{
+		actor->tics >>= 2;
+	}
+	else if (floor == FLOOR_ICE)
+	{
+		actor->tics <<= 1;
+	}
+}
+
+//============================================================================
+//
+// A_IceCheckHeadDone
+//
+//============================================================================
+
+void A_IceCheckHeadDone(mobj_t *actor)
+{
+	if (actor->special2 == 666)
+	{
+		P_SetMobjState(actor, S_ICECHUNK_HEAD2);
+	}
+}
+
+//============================================================================
+//
+// A_FreezeDeathChunks
+//
+//============================================================================
+
+void A_FreezeDeathChunks(mobj_t *actor)
+{
+	int i;
+	mobj_t *mo;
+
+	if (actor->momx || actor->momy || actor->momz)
+	{
+		actor->tics = 105;
+		return;
+	}
+	S_StartSound(actor, SFX_FREEZE_SHATTER);
+
+	for (i = 12 + (P_Random() & 15); i >= 0; i--)
+	{
+		mo = P_SpawnMobj(actor->x + (((P_Random() - 128) * actor->radius) >> 7),
+				 actor->y + (((P_Random() - 128) * actor->radius) >> 7),
+				 actor->z + (P_Random() * actor->height / 255), MT_ICECHUNK);
+		P_SetMobjState(mo, mo->info->spawnstate + (P_Random() % 3));
+		if (mo)
+		{
+			mo->momz = FixedDiv(mo->z - actor->z, actor->height)<<2;
+			mo->momx = (P_Random() - P_Random()) << (FRACBITS - 7);
+			mo->momy = (P_Random() - P_Random()) << (FRACBITS - 7);
+			A_IceSetTics(mo);	// set a random tic wait
+		}
+	}
+	for (i = 12 + (P_Random() & 15); i >= 0; i--)
+	{
+		mo = P_SpawnMobj(actor->x + (((P_Random() - 128) * actor->radius) >> 7),
+				 actor->y + (((P_Random() - 128) * actor->radius) >> 7),
+				 actor->z + (P_Random() * actor->height / 255), MT_ICECHUNK);
+		P_SetMobjState(mo, mo->info->spawnstate + (P_Random() % 3));
+		if (mo)
+		{
+			mo->momz = FixedDiv(mo->z - actor->z, actor->height)<<2;
+			mo->momx = (P_Random() - P_Random()) << (FRACBITS - 7);
+			mo->momy = (P_Random() - P_Random()) << (FRACBITS - 7);
+			A_IceSetTics(mo);	// set a random tic wait
+		}
+	}
+	if (actor->player)
+	{ // attach the player's view to a chunk of ice
+		mo = P_SpawnMobj(actor->x, actor->y, actor->z + VIEWHEIGHT, MT_ICECHUNK);
+		P_SetMobjState(mo, S_ICECHUNK_HEAD);
+		mo->momz = FixedDiv(mo->z - actor->z, actor->height)<<2;
+		mo->momx = (P_Random() - P_Random()) << (FRACBITS - 7);
+		mo->momy = (P_Random() - P_Random()) << (FRACBITS - 7);
+		mo->flags2 |= MF2_ICEDAMAGE; // used to force blue palette
+		mo->flags2 &= ~MF2_FLOORCLIP;
+		mo->player = actor->player;
+		actor->player = NULL;
+		mo->health = actor->health;
+		mo->angle = actor->angle;
+		mo->player->mo = mo;
+		mo->player->lookdir = 0;
+	}
+	P_RemoveMobjFromTIDList(actor);
+	P_SetMobjState(actor, S_FREETARGMOBJ);
+	actor->flags2 |= MF2_DONTDRAW;
+}
+
+//===========================================================================
+// Korax Variables
+//	special1	last teleport destination
+//	special2	set if "below half" script not yet run
+//
+// Korax Scripts (reserved)
+//	249		Tell scripts that we are below half health
+//	250-254	Control scripts
+//	255		Death script
+//
+// Korax TIDs (reserved)
+//	245		Reserved for Korax himself
+//	248		Initial teleport destination
+//	249		Teleport destination
+//	250-254	For use in respective control scripts
+//	255		For use in death script (spawn spots)
+//===========================================================================
+#define KORAX_SPIRIT_LIFETIME	(5 * (35 / 5))	/* 5 seconds */
+#define KORAX_COMMAND_HEIGHT	(120 * FRACUNIT)
+#define KORAX_COMMAND_OFFSET	(27 * FRACUNIT)
+
+void KoraxFire1(mobj_t *actor, int type);
+void KoraxFire2(mobj_t *actor, int type);
+void KoraxFire3(mobj_t *actor, int type);
+void KoraxFire4(mobj_t *actor, int type);
+void KoraxFire5(mobj_t *actor, int type);
+void KoraxFire6(mobj_t *actor, int type);
+void KSpiritInit(mobj_t *spirit, mobj_t *korax);
+
+#define KORAX_TID			(245)
+#define KORAX_FIRST_TELEPORT_TID	(248)
+#define KORAX_TELEPORT_TID		(249)
+
+void A_KoraxChase(mobj_t *actor)
+{
+	mobj_t *spot;
+	int lastfound;
+	byte args[3] = {0, 0, 0};
+
+	if ((!actor->special2) &&
+		(actor->health <= (actor->info->spawnhealth/2)))
+	{
+		lastfound = 0;
+		spot = P_FindMobjFromTID(KORAX_FIRST_TELEPORT_TID, &lastfound);
+		if (spot)
+		{
+			P_Teleport(actor, spot->x, spot->y, spot->angle, true);
+		}
+
+		P_StartACS(249, 0, args, actor, NULL, 0);
+		actor->special2 = 1;	// Don't run again
+
+		return;
+	}
+
+	if (!actor->target)
+		return;
+	if (P_Random() < 30)
+	{
+		P_SetMobjState(actor, actor->info->missilestate);
+	}
+	else if (P_Random() < 30)
+	{
+		S_StartSound(NULL, SFX_KORAX_ACTIVE);
+	}
+
+	// Teleport away
+	if (actor->health < (actor->info->spawnhealth>>1))
+	{
+		if (P_Random() < 10)
+		{
+			lastfound = actor->special1;
+			spot = P_FindMobjFromTID(KORAX_TELEPORT_TID, &lastfound);
+			actor->special1 = lastfound;
+			if (spot)
+			{
+				P_Teleport(actor, spot->x, spot->y, spot->angle, true);
+			}
+		}
+	}
+}
+
+void A_KoraxStep(mobj_t *actor)
+{
+	A_Chase(actor);
+}
+
+void A_KoraxStep2(mobj_t *actor)
+{
+	S_StartSound(NULL, SFX_KORAX_STEP);
+	A_Chase(actor);
+}
+
+void A_KoraxBonePop(mobj_t *actor)
+{
+	mobj_t *mo;
+	byte args[5];
+
+	args[0] = args[1] = args[2] = args[3] = args[4] = 0;
+
+	// Spawn 6 spirits equalangularly
+	mo = P_SpawnMissileAngle(actor, MT_KORAX_SPIRIT1, ANGLE_60*0, 5*FRACUNIT);
+	if (mo)
+		KSpiritInit(mo, actor);
+	mo = P_SpawnMissileAngle(actor, MT_KORAX_SPIRIT2, ANGLE_60*1, 5*FRACUNIT);
+	if (mo)
+		KSpiritInit(mo, actor);
+	mo = P_SpawnMissileAngle(actor, MT_KORAX_SPIRIT3, ANGLE_60*2, 5*FRACUNIT);
+	if (mo)
+		KSpiritInit(mo, actor);
+	mo = P_SpawnMissileAngle(actor, MT_KORAX_SPIRIT4, ANGLE_60*3, 5*FRACUNIT);
+	if (mo)
+		KSpiritInit(mo, actor);
+	mo = P_SpawnMissileAngle(actor, MT_KORAX_SPIRIT5, ANGLE_60*4, 5*FRACUNIT);
+	if (mo)
+		KSpiritInit(mo, actor);
+	mo = P_SpawnMissileAngle(actor, MT_KORAX_SPIRIT6, ANGLE_60*5, 5*FRACUNIT);
+	if (mo)
+		KSpiritInit(mo, actor);
+
+	P_StartACS(255, 0, args, actor, NULL, 0);		// Death script
+}
+
+void KSpiritInit(mobj_t *spirit, mobj_t *korax)
+{
+	int i;
+	mobj_t *tail, *next;
+
+	spirit->health = KORAX_SPIRIT_LIFETIME;
+
+	spirit->special1 = (intptr_t)korax;	// Swarm around korax
+	spirit->special2 = 32+(P_Random()&7);	// Float bob index
+	spirit->args[0] = 10;			// initial turn value
+	spirit->args[1] = 0;			// initial look angle
+
+	// Spawn a tail for spirit
+	tail = P_SpawnMobj(spirit->x, spirit->y, spirit->z, MT_HOLY_TAIL);
+	tail->special2 = (intptr_t)spirit;	// parent
+	for (i = 1; i < 3; i++)
+	{
+		next = P_SpawnMobj(spirit->x, spirit->y, spirit->z, MT_HOLY_TAIL);
+		P_SetMobjState(next, next->info->spawnstate + 1);
+		tail->special1 = (intptr_t)next;
+		tail = next;
+	}
+	tail->special1 = 0; // last tail bit
+}
+
+void A_KoraxDecide(mobj_t *actor)
+{
+	if (P_Random() < 220)
+	{
+		P_SetMobjState(actor, S_KORAX_MISSILE1);
+	}
+	else
+	{
+		P_SetMobjState(actor, S_KORAX_COMMAND1);
+	}
+}
+
+void A_KoraxMissile(mobj_t *actor)
+{
+	int type = P_Random() % 6;
+	int sound = SFX_NONE;
+
+	S_StartSound(actor, SFX_KORAX_ATTACK);
+
+	switch (type)
+	{
+	case 0:
+		type = MT_WRAITHFX1;
+		sound = SFX_WRAITH_MISSILE_FIRE;
+		break;
+	case 1:
+		type = MT_DEMONFX1;
+		sound = SFX_DEMON_MISSILE_FIRE;
+		break;
+	case 2:
+		type = MT_DEMON2FX1;
+		sound = SFX_DEMON_MISSILE_FIRE;
+		break;
+	case 3:
+		type = MT_FIREDEMON_FX6;
+		sound = SFX_FIRED_ATTACK;
+		break;
+	case 4:
+		type = MT_CENTAUR_FX;
+		sound = SFX_CENTAURLEADER_ATTACK;
+		break;
+	case 5:
+		type = MT_SERPENTFX;
+		sound = SFX_CENTAURLEADER_ATTACK;
+		break;
+	}
+
+	// Fire all 6 missiles at once
+	S_StartSound(NULL, sound);
+	KoraxFire1(actor, type);
+	KoraxFire2(actor, type);
+	KoraxFire3(actor, type);
+	KoraxFire4(actor, type);
+	KoraxFire5(actor, type);
+	KoraxFire6(actor, type);
+}
+
+// Call action code scripts (250-254)
+void A_KoraxCommand(mobj_t *actor)
+{
+	byte args[5];
+	fixed_t x, y, z;
+	angle_t ang;
+	int numcommands;
+
+	S_StartSound(actor, SFX_KORAX_COMMAND);
+
+	// Shoot stream of lightning to ceiling
+	ang = (actor->angle - ANGLE_90) >> ANGLETOFINESHIFT;
+	x = actor->x + FixedMul(KORAX_COMMAND_OFFSET, finecosine[ang]);
+	y = actor->y + FixedMul(KORAX_COMMAND_OFFSET, finesine[ang]);
+	z = actor->z + KORAX_COMMAND_HEIGHT;
+	P_SpawnMobj(x, y, z, MT_KORAX_BOLT);
+
+	args[0] = args[1] = args[2] = args[3] = args[4] = 0;
+
+	if (actor->health <= (actor->info->spawnhealth >> 1))
+	{
+		numcommands = 5;
+	}
+	else
+	{
+		numcommands = 4;
+	}
+
+	switch (P_Random() % numcommands)
+	{
+	case 0:
+		P_StartACS(250, 0, args, actor, NULL, 0);
+		break;
+	case 1:
+		P_StartACS(251, 0, args, actor, NULL, 0);
+		break;
+	case 2:
+		P_StartACS(252, 0, args, actor, NULL, 0);
+		break;
+	case 3:
+		P_StartACS(253, 0, args, actor, NULL, 0);
+		break;
+	case 4:
+		P_StartACS(254, 0, args, actor, NULL, 0);
+		break;
+	}
+}
+
+
+#define KORAX_DELTAANGLE		(85 * ANGLE_1)
+#define KORAX_ARM_EXTENSION_SHORT	(40 * FRACUNIT)
+#define KORAX_ARM_EXTENSION_LONG	(55 * FRACUNIT)
+
+#define KORAX_ARM1_HEIGHT		(108* FRACUNIT)
+#define KORAX_ARM2_HEIGHT		(82 * FRACUNIT)
+#define KORAX_ARM3_HEIGHT		(54 * FRACUNIT)
+#define KORAX_ARM4_HEIGHT		(104* FRACUNIT)
+#define KORAX_ARM5_HEIGHT		(86 * FRACUNIT)
+#define KORAX_ARM6_HEIGHT		(53 * FRACUNIT)
+
+// Arm projectiles
+//		arm positions numbered:
+//			1	top left
+//			2	middle left
+//			3	lower left
+//			4	top right
+//			5	middle right
+//			6	lower right
+
+// Arm 1 projectile
+void KoraxFire1(mobj_t *actor, int type)
+{
+	angle_t ang;
+	fixed_t x, y, z;
+
+	ang = (actor->angle - KORAX_DELTAANGLE) >> ANGLETOFINESHIFT;
+	x = actor->x + FixedMul(KORAX_ARM_EXTENSION_SHORT, finecosine[ang]);
+	y = actor->y + FixedMul(KORAX_ARM_EXTENSION_SHORT, finesine[ang]);
+	z = actor->z - actor->floorclip + KORAX_ARM1_HEIGHT;
+	P_SpawnKoraxMissile(x, y, z, actor, actor->target, type);
+}
+
+// Arm 2 projectile
+void KoraxFire2(mobj_t *actor, int type)
+{
+	angle_t ang;
+	fixed_t x, y, z;
+
+	ang = (actor->angle - KORAX_DELTAANGLE) >> ANGLETOFINESHIFT;
+	x = actor->x + FixedMul(KORAX_ARM_EXTENSION_LONG, finecosine[ang]);
+	y = actor->y + FixedMul(KORAX_ARM_EXTENSION_LONG, finesine[ang]);
+	z = actor->z - actor->floorclip + KORAX_ARM2_HEIGHT;
+	P_SpawnKoraxMissile(x, y, z, actor, actor->target, type);
+}
+
+// Arm 3 projectile
+void KoraxFire3(mobj_t *actor, int type)
+{
+	angle_t ang;
+	fixed_t x, y, z;
+
+	ang = (actor->angle - KORAX_DELTAANGLE) >> ANGLETOFINESHIFT;
+	x = actor->x + FixedMul(KORAX_ARM_EXTENSION_LONG, finecosine[ang]);
+	y = actor->y + FixedMul(KORAX_ARM_EXTENSION_LONG, finesine[ang]);
+	z = actor->z - actor->floorclip + KORAX_ARM3_HEIGHT;
+	P_SpawnKoraxMissile(x, y, z, actor, actor->target, type);
+}
+
+// Arm 4 projectile
+void KoraxFire4(mobj_t *actor, int type)
+{
+	angle_t ang;
+	fixed_t x, y, z;
+
+	ang = (actor->angle + KORAX_DELTAANGLE) >> ANGLETOFINESHIFT;
+	x = actor->x + FixedMul(KORAX_ARM_EXTENSION_SHORT, finecosine[ang]);
+	y = actor->y + FixedMul(KORAX_ARM_EXTENSION_SHORT, finesine[ang]);
+	z = actor->z - actor->floorclip + KORAX_ARM4_HEIGHT;
+	P_SpawnKoraxMissile(x, y, z, actor, actor->target, type);
+}
+
+// Arm 5 projectile
+void KoraxFire5(mobj_t *actor, int type)
+{
+	angle_t ang;
+	fixed_t x, y, z;
+
+	ang = (actor->angle + KORAX_DELTAANGLE) >> ANGLETOFINESHIFT;
+	x = actor->x + FixedMul(KORAX_ARM_EXTENSION_LONG, finecosine[ang]);
+	y = actor->y + FixedMul(KORAX_ARM_EXTENSION_LONG, finesine[ang]);
+	z = actor->z - actor->floorclip + KORAX_ARM5_HEIGHT;
+	P_SpawnKoraxMissile(x, y, z, actor, actor->target, type);
+}
+
+// Arm 6 projectile
+void KoraxFire6(mobj_t *actor, int type)
+{
+	angle_t ang;
+	fixed_t x, y, z;
+
+	ang = (actor->angle + KORAX_DELTAANGLE) >> ANGLETOFINESHIFT;
+	x = actor->x + FixedMul(KORAX_ARM_EXTENSION_LONG, finecosine[ang]);
+	y = actor->y + FixedMul(KORAX_ARM_EXTENSION_LONG, finesine[ang]);
+	z = actor->z - actor->floorclip + KORAX_ARM6_HEIGHT;
+	P_SpawnKoraxMissile(x, y, z, actor, actor->target, type);
+}
+
+
+void A_KSpiritWeave(mobj_t *actor)
+{
+	fixed_t newX, newY;
+	int weaveXY, weaveZ;
+	int angle;
+
+	weaveXY = actor->special2 >> 16;
+	weaveZ = actor->special2 & 0xFFFF;
+	angle = (actor->angle + ANG90) >> ANGLETOFINESHIFT;
+	newX = actor->x - FixedMul(finecosine[angle], FloatBobOffsets[weaveXY] << 2);
+	newY = actor->y - FixedMul(finesine[angle], FloatBobOffsets[weaveXY] << 2);
+	weaveXY = (weaveXY + (P_Random() % 5)) & 63;
+	newX += FixedMul(finecosine[angle], FloatBobOffsets[weaveXY] << 2);
+	newY += FixedMul(finesine[angle], FloatBobOffsets[weaveXY] << 2);
+	P_TryMove(actor, newX, newY);
+	actor->z -= FloatBobOffsets[weaveZ] << 1;
+	weaveZ = (weaveZ + (P_Random() % 5)) & 63;
+	actor->z += FloatBobOffsets[weaveZ] << 1;
+	actor->special2 = weaveZ + (weaveXY << 16);
+}
+
+void A_KSpiritSeeker(mobj_t *actor, angle_t thresh, angle_t turnMax)
+{
+	int dir;
+	int dist;
+	angle_t delta;
+	angle_t angle;
+	mobj_t *target;
+	fixed_t newZ;
+	fixed_t deltaZ;
+
+	target = (mobj_t *)actor->special1;
+	if (target == NULL)
+	{
+		return;
+	}
+	dir = P_FaceMobj(actor, target, &delta);
+	if (delta > thresh)
+	{
+		delta >>= 1;
+		if (delta > turnMax)
+		{
+			delta = turnMax;
+		}
+	}
+	if (dir)
+	{ // Turn clockwise
+		actor->angle += delta;
+	}
+	else
+	{ // Turn counter clockwise
+		actor->angle -= delta;
+	}
+	angle = actor->angle >> ANGLETOFINESHIFT;
+	actor->momx = FixedMul(actor->info->speed, finecosine[angle]);
+	actor->momy = FixedMul(actor->info->speed, finesine[angle]);
+
+	if (!(leveltime & 15)
+		|| actor->z > target->z + (target->info->height)
+		|| actor->z + actor->height < target->z)
+	{
+		newZ = target->z + ((P_Random() * target->info->height) >> 8);
+		deltaZ = newZ - actor->z;
+		if (abs(deltaZ) > 15*FRACUNIT)
+		{
+			if (deltaZ > 0)
+			{
+				deltaZ = 15*FRACUNIT;
+			}
+			else
+			{
+				deltaZ = -15*FRACUNIT;
+			}
+		}
+		dist = P_AproxDistance(target->x - actor->x, target->y - actor->y);
+		dist = dist / actor->info->speed;
+		if (dist < 1)
+		{
+			dist = 1;
+		}
+		actor->momz = deltaZ / dist;
+	}
+	return;
+}
+
+void A_KSpiritRoam(mobj_t *actor)
+{
+	if (actor->health-- <= 0)
+	{
+		S_StartSound(actor, SFX_SPIRIT_DIE);
+		P_SetMobjState(actor, S_KSPIRIT_DEATH1);
+	}
+	else
+	{
+		if (actor->special1)
+		{
+			A_KSpiritSeeker(actor, actor->args[0]*ANGLE_1,
+						actor->args[0]*ANGLE_1*2);
+		}
+		A_KSpiritWeave(actor);
+		if (P_Random() < 50)
+		{
+			S_StartSound(NULL, SFX_SPIRIT_ACTIVE);
+		}
+	}
+}
+
+void A_KBolt(mobj_t *actor)
+{
+	// Countdown lifetime
+	if (actor->special1-- <= 0)
+	{
+		P_SetMobjState(actor, S_NULL);
+	}
+}
+
+
+#define KORAX_BOLT_HEIGHT		48*FRACUNIT
+#define KORAX_BOLT_LIFETIME		3
+
+void A_KBoltRaise(mobj_t *actor)
+{
+	mobj_t *mo;
+	fixed_t z;
+
+	// Spawn a child upward
+	z = actor->z + KORAX_BOLT_HEIGHT;
+
+	if ((z + KORAX_BOLT_HEIGHT) < actor->ceilingz)
+	{
+		mo = P_SpawnMobj(actor->x, actor->y, z, MT_KORAX_BOLT);
+		if (mo)
+		{
+			mo->special1 = KORAX_BOLT_LIFETIME;
+		}
+	}
+	else
+	{
+		// Maybe cap it off here
+	}
+}
+
--- /dev/null
+++ b/p_floor.c
@@ -1,0 +1,924 @@
+
+//**************************************************************************
+//**
+//** p_floor.c : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 472 $
+//** $Date: 2009-05-26 15:45:18 +0300 (Tue, 26 May 2009) $
+//**
+//**************************************************************************
+
+#include "h2stdinc.h"
+#include "h2def.h"
+#include "p_local.h"
+#include "soundst.h"
+
+//==================================================================
+//
+// FLOORS
+//
+//==================================================================
+
+extern fixed_t FloatBobOffsets[64];
+
+
+//==================================================================
+//
+// Move a plane (floor or ceiling) and check for crushing
+//
+//==================================================================
+
+result_e T_MovePlane(sector_t *sector,fixed_t speed, fixed_t dest,
+			int crush, int floorOrCeiling, int direction)
+{
+	boolean flag;
+	fixed_t lastpos;
+
+	switch (floorOrCeiling)
+	{
+	case 0:	// FLOOR
+		switch (direction)
+		{
+		case -1: // DOWN
+			if (sector->floorheight - speed < dest)
+			{
+				lastpos = sector->floorheight;
+				sector->floorheight = dest;
+				flag = P_ChangeSector(sector,crush);
+				if (flag == true)
+				{
+					sector->floorheight = lastpos;
+					P_ChangeSector(sector, crush);
+					//return RES_CRUSHED;
+				}
+				return RES_PASTDEST;
+			}
+			else
+			{
+				lastpos = sector->floorheight;
+				sector->floorheight -= speed;
+				flag = P_ChangeSector(sector, crush);
+				if (flag == true)
+				{
+					sector->floorheight = lastpos;
+					P_ChangeSector(sector, crush);
+					return RES_CRUSHED;
+				}
+			}
+			break;
+
+		case 1:	// UP
+			if (sector->floorheight + speed > dest)
+			{
+				lastpos = sector->floorheight;
+				sector->floorheight = dest;
+				flag = P_ChangeSector(sector, crush);
+				if (flag == true)
+				{
+					sector->floorheight = lastpos;
+					P_ChangeSector(sector, crush);
+					//return RES_CRUSHED;
+				}
+				return RES_PASTDEST;
+			}
+			else	// COULD GET CRUSHED
+			{
+				lastpos = sector->floorheight;
+				sector->floorheight += speed;
+				flag = P_ChangeSector(sector, crush);
+				if (flag == true)
+				{
+					//if (crush == true)
+					//{
+					//	return RES_CRUSHED;
+					//}
+					sector->floorheight = lastpos;
+					P_ChangeSector(sector, crush);
+					return RES_CRUSHED;
+				}
+			}
+			break;
+		}
+		break;	/* END OF THE FLOOR CASE */
+
+	case 1:	// CEILING
+		switch (direction)
+		{
+		case -1: // DOWN
+			if (sector->ceilingheight - speed < dest)
+			{
+				lastpos = sector->ceilingheight;
+				sector->ceilingheight = dest;
+				flag = P_ChangeSector(sector, crush);
+				if (flag == true)
+				{
+					sector->ceilingheight = lastpos;
+					P_ChangeSector(sector, crush);
+					//return RES_CRUSHED;
+				}
+				return RES_PASTDEST;
+			}
+			else	// COULD GET CRUSHED
+			{
+				lastpos = sector->ceilingheight;
+				sector->ceilingheight -= speed;
+				flag = P_ChangeSector(sector, crush);
+				if (flag == true)
+				{
+					//if (crush == true)
+					//{
+					//	return RES_CRUSHED;
+					//}
+					sector->ceilingheight = lastpos;
+					P_ChangeSector(sector, crush);
+					return RES_CRUSHED;
+				}
+			}
+			break;
+
+		case 1:	// UP
+			if (sector->ceilingheight + speed > dest)
+			{
+				lastpos = sector->ceilingheight;
+				sector->ceilingheight = dest;
+				flag = P_ChangeSector(sector, crush);
+				if (flag == true)
+				{
+					sector->ceilingheight = lastpos;
+					P_ChangeSector(sector, crush);
+					//return RES_CRUSHED;
+				}
+				return RES_PASTDEST;
+			}
+			else
+			{
+				lastpos = sector->ceilingheight;
+				sector->ceilingheight += speed;
+				flag = P_ChangeSector(sector, crush);
+				#if 0
+				if (flag == true)
+				{
+					sector->ceilingheight = lastpos;
+					P_ChangeSector(sector, crush);
+					return RES_CRUSHED;
+				}
+				#endif
+			}
+			break;
+		}
+		break;	/* END OF THE CEILING CASE */
+	}
+
+	return RES_OK;
+}
+
+//==================================================================
+//
+// MOVE A FLOOR TO IT'S DESTINATION (UP OR DOWN)
+//
+//==================================================================
+
+void T_MoveFloor(floormove_t *floor)
+{
+	result_e	res;
+
+	if (floor->resetDelayCount)
+	{
+		floor->resetDelayCount--;
+		if (!floor->resetDelayCount)
+		{
+			floor->floordestheight = floor->resetHeight;
+			floor->direction = -floor->direction;
+			floor->resetDelay = 0;
+			floor->delayCount = 0;
+			floor->delayTotal = 0;
+		}
+	}
+	if (floor->delayCount)
+	{
+		floor->delayCount--;
+		if (!floor->delayCount && floor->textureChange)
+		{
+			floor->sector->floorpic += floor->textureChange;
+		}
+		return;
+	}
+
+	res = T_MovePlane(floor->sector,floor->speed,
+			floor->floordestheight, floor->crush, 0, floor->direction);
+
+	if (floor->type == FLEV_RAISEBUILDSTEP)
+	{
+		if ((floor->direction == 1 && floor->sector->floorheight >= floor->stairsDelayHeight) ||
+		    (floor->direction == -1 && floor->sector->floorheight <= floor->stairsDelayHeight))
+		{
+			floor->delayCount = floor->delayTotal;
+			floor->stairsDelayHeight += floor->stairsDelayHeightDelta;
+		}
+	}
+	if (res == RES_PASTDEST)
+	{
+		SN_StopSequence((mobj_t *)(void *)&floor->sector->soundorg);
+		if (floor->delayTotal)
+		{
+			floor->delayTotal = 0;
+		}
+		if (floor->resetDelay)
+		{
+		//	floor->resetDelayCount = floor->resetDelay;
+		//	floor->resetDelay = 0;
+			return;
+		}
+		floor->sector->specialdata = NULL;
+		/*
+		if (floor->direction == 1)
+		{
+			switch (floor->type)
+			{
+			case donutRaise:
+				floor->sector->special = floor->newspecial;
+				floor->sector->floorpic = floor->texture;
+			default:
+				break;
+			}
+		}
+		else if (floor->direction == -1)
+		{
+			switch (floor->type)
+			{
+			case lowerAndChange:
+				floor->sector->special = floor->newspecial;
+				floor->sector->floorpic = floor->texture;
+			default:
+				break;
+			}
+		}
+		*/
+		if (floor->textureChange)
+		{
+			floor->sector->floorpic -= floor->textureChange;
+		}
+		P_TagFinished(floor->sector->tag);
+		P_RemoveThinker(&floor->thinker);
+	}
+}
+
+//==================================================================
+//
+// HANDLE FLOOR TYPES
+//
+//==================================================================
+
+int EV_DoFloor(line_t *line, byte *args, floor_e floortype)
+{
+	int		secnum;
+	int		rtn;
+	sector_t	*sec;
+	floormove_t	*floor = NULL;
+
+	secnum = -1;
+	rtn = 0;
+	while ((secnum = P_FindSectorFromTag(args[0], secnum)) >= 0)
+	{
+		sec = &sectors[secnum];
+
+		// ALREADY MOVING?  IF SO, KEEP GOING...
+		if (sec->specialdata)
+			continue;
+
+		//
+		// new floor thinker
+		//
+		rtn = 1;
+		floor = (floormove_t *) Z_Malloc (sizeof(*floor), PU_LEVSPEC, NULL);
+		memset(floor, 0, sizeof(*floor));
+		P_AddThinker (&floor->thinker);
+		sec->specialdata = floor;
+		floor->thinker.function = T_MoveFloor;
+		floor->type = floortype;
+		floor->crush = 0;
+		floor->speed = args[1]*(FRACUNIT/8);
+		if (floortype == FLEV_LOWERTIMES8INSTANT ||
+			floortype == FLEV_RAISETIMES8INSTANT)
+		{
+			floor->speed = 2000<<FRACBITS;
+		}
+		switch (floortype)
+		{
+		case FLEV_LOWERFLOOR:
+			floor->direction = -1;
+			floor->sector = sec;
+			floor->floordestheight = P_FindHighestFloorSurrounding(sec);
+			break;
+		case FLEV_LOWERFLOORTOLOWEST:
+			floor->direction = -1;
+			floor->sector = sec;
+			floor->floordestheight = P_FindLowestFloorSurrounding(sec);
+			break;
+		case FLEV_LOWERFLOORBYVALUE:
+			floor->direction = -1;
+			floor->sector = sec;
+			floor->floordestheight = floor->sector->floorheight - args[2]*FRACUNIT;
+			break;
+		case FLEV_LOWERTIMES8INSTANT:
+		case FLEV_LOWERBYVALUETIMES8:
+			floor->direction = -1;
+			floor->sector = sec;
+			floor->floordestheight = floor->sector->floorheight - args[2]*FRACUNIT*8;
+			break;
+		case FLEV_RAISEFLOORCRUSH:
+			floor->crush = args[2]; // arg[2] = crushing value
+			floor->direction = 1;
+			floor->sector = sec;
+			floor->floordestheight = sec->ceilingheight - 8*FRACUNIT;
+			break;
+		case FLEV_RAISEFLOOR:
+			floor->direction = 1;
+			floor->sector = sec;
+			floor->floordestheight = P_FindLowestCeilingSurrounding(sec);
+			if (floor->floordestheight > sec->ceilingheight)
+				floor->floordestheight = sec->ceilingheight;
+			break;
+		case FLEV_RAISEFLOORTONEAREST:
+			floor->direction = 1;
+			floor->sector = sec;
+			floor->floordestheight = P_FindNextHighestFloor(sec, sec->floorheight);
+			break;
+		case FLEV_RAISEFLOORBYVALUE:
+			floor->direction = 1;
+			floor->sector = sec;
+			floor->floordestheight = floor->sector->floorheight + args[2]*FRACUNIT;
+			break;
+		case FLEV_RAISETIMES8INSTANT:
+		case FLEV_RAISEBYVALUETIMES8:
+			floor->direction = 1;
+			floor->sector = sec;
+			floor->floordestheight = floor->sector->floorheight + args[2]*FRACUNIT*8;
+			break;
+		case FLEV_MOVETOVALUETIMES8:
+			floor->sector = sec;
+			floor->floordestheight = args[2]*FRACUNIT*8;
+			if (args[3])
+			{
+				floor->floordestheight = -floor->floordestheight;
+			}
+			if (floor->floordestheight > floor->sector->floorheight)
+			{
+				floor->direction = 1;
+			}
+			else if (floor->floordestheight < floor->sector->floorheight)
+			{
+				floor->direction = -1;
+			}
+			else
+			{ // already at lowest position
+				rtn = 0;
+			}
+			break;
+		default:
+			rtn = 0;
+			break;
+		}
+	}
+	if (rtn)
+	{
+		SN_StartSequence((mobj_t *)(void *)&floor->sector->soundorg,
+				 SEQ_PLATFORM + floor->sector->seqType);
+	}
+	return rtn;
+}
+
+//============================================================================
+//
+// EV_DoFloorAndCeiling
+//
+//============================================================================
+
+int EV_DoFloorAndCeiling(line_t *line, byte *args, boolean raise)
+{
+	boolean	floor, ceiling;
+	int		secnum;
+	sector_t	*sec;
+
+	if (raise)
+	{
+		floor = EV_DoFloor(line, args, FLEV_RAISEFLOORBYVALUE);
+		secnum = -1;
+		while ((secnum = P_FindSectorFromTag(args[0], secnum)) >= 0)
+		{
+			sec = &sectors[secnum];
+			sec->specialdata = NULL;
+		}
+		ceiling = EV_DoCeiling(line, args, CLEV_RAISEBYVALUE);
+	}
+	else
+	{
+		floor = EV_DoFloor(line, args, FLEV_LOWERFLOORBYVALUE);
+		secnum = -1;
+		while ((secnum = P_FindSectorFromTag(args[0], secnum)) >= 0)
+		{
+			sec = &sectors[secnum];
+			sec->specialdata = NULL;
+		}
+		ceiling = EV_DoCeiling(line, args, CLEV_LOWERBYVALUE);
+	}
+	return (floor|ceiling);
+}
+
+// ===== Build Stairs Private Data =====
+
+#define STAIR_SECTOR_TYPE	26
+#define STAIR_QUEUE_SIZE	32
+
+static struct
+{
+	sector_t *sector;
+	int	type;
+	int	height;
+} StairQueue[STAIR_QUEUE_SIZE];
+
+static int	QueueHead;
+static int	QueueTail;
+
+static int	StepDelta;
+static int	Direction;
+static int	Speed;
+static int	Texture;
+static int	StartDelay;
+static int	StartDelayDelta;
+static int	TextureChange;
+static int	StartHeight;
+
+//==========================================================================
+//
+// QueueStairSector
+//
+//==========================================================================
+
+static void QueueStairSector(sector_t *sec, int type, int height)
+{
+	if ((QueueTail + 1) % STAIR_QUEUE_SIZE == QueueHead)
+	{
+		I_Error("BuildStairs:  Too many branches located.\n");
+	}
+	StairQueue[QueueTail].sector = sec;
+	StairQueue[QueueTail].type = type;
+	StairQueue[QueueTail].height = height;
+
+	QueueTail = (QueueTail + 1) % STAIR_QUEUE_SIZE;
+}
+
+//==========================================================================
+//
+// DequeueStairSector
+//
+//==========================================================================
+
+static sector_t *DequeueStairSector(int *type, int *height)
+{
+	sector_t	*sec;
+
+	if (QueueHead == QueueTail)
+	{ // queue is empty
+		return NULL;
+	}
+	*type = StairQueue[QueueHead].type;
+	*height = StairQueue[QueueHead].height;
+	sec = StairQueue[QueueHead].sector;
+	QueueHead = (QueueHead + 1) % STAIR_QUEUE_SIZE;
+
+	return sec;
+}
+
+//==========================================================================
+//
+// ProcessStairSector
+//
+//==========================================================================
+
+static void ProcessStairSector(sector_t *sec, int type, int height,
+			stairs_e stairsType, int delay, int resetDelay)
+{
+	int		i;
+	sector_t	*tsec;
+	floormove_t	*floor;
+
+	//
+	// new floor thinker
+	//
+	height += StepDelta;
+	floor = (floormove_t *) Z_Malloc(sizeof(*floor), PU_LEVSPEC, NULL);
+	memset(floor, 0, sizeof(*floor));
+	P_AddThinker(&floor->thinker);
+	sec->specialdata = floor;
+	floor->thinker.function = T_MoveFloor;
+	floor->type = FLEV_RAISEBUILDSTEP;
+	floor->direction = Direction;
+	floor->sector = sec;
+	floor->floordestheight = height;
+	switch (stairsType)
+	{
+	case STAIRS_NORMAL:
+		floor->speed = Speed;
+		if (delay)
+		{
+			floor->delayTotal = delay;
+			floor->stairsDelayHeight = sec->floorheight + StepDelta;
+			floor->stairsDelayHeightDelta = StepDelta;
+		}
+		floor->resetDelay = resetDelay;
+		floor->resetDelayCount = resetDelay;
+		floor->resetHeight = sec->floorheight;
+		break;
+	case STAIRS_SYNC:
+		floor->speed = FixedMul(Speed, FixedDiv(height - StartHeight, StepDelta));
+		floor->resetDelay = delay; //arg4
+		floor->resetDelayCount = delay;
+		floor->resetHeight = sec->floorheight;
+		break;
+	/*
+	case STAIRS_PHASED:
+		floor->floordestheight = sec->floorheight + StepDelta;
+		floor->speed = Speed;
+		floor->delayCount = StartDelay;
+		StartDelay += StartDelayDelta;
+		floor->textureChange = TextureChange;
+		floor->resetDelayCount = StartDelay;
+		break;
+	*/
+	default:
+		break;
+	}
+	SN_StartSequence((mobj_t *)(void *)&sec->soundorg, SEQ_PLATFORM + sec->seqType);
+	//
+	// Find next sector to raise
+	// Find nearby sector with sector special equal to type
+	//
+	for (i = 0; i < sec->linecount; i++)
+	{
+		if (!((sec->lines[i])->flags & ML_TWOSIDED))
+		{
+			continue;
+		}
+		tsec = (sec->lines[i])->frontsector;
+		if (tsec->special == type + STAIR_SECTOR_TYPE && !tsec->specialdata
+			&& tsec->floorpic == Texture && tsec->validcount != validcount)
+		{
+			QueueStairSector(tsec, type^1, height);
+			tsec->validcount = validcount;
+			//tsec->special = 0;
+		}
+		tsec = (sec->lines[i])->backsector;
+		if (tsec->special == type + STAIR_SECTOR_TYPE && !tsec->specialdata
+			&& tsec->floorpic == Texture && tsec->validcount != validcount)
+		{
+			QueueStairSector(tsec, type^1, height);
+			tsec->validcount = validcount;
+			//tsec->special = 0;
+		}
+	}
+}
+
+//==================================================================
+//
+// BUILD A STAIRCASE!
+//
+// Direction is either positive or negative, denoting build stairs
+// up or down.
+//==================================================================
+
+int EV_BuildStairs(line_t *line, byte *args, int direction,
+					stairs_e stairsType)
+{
+	int		secnum;
+	int		height;
+	int		delay;
+	int		resetDelay;
+	sector_t	*sec;
+	sector_t	*qSec;
+	int		type;
+
+	// Set global stairs variables
+	TextureChange = 0;
+	Direction = direction;
+	StepDelta = Direction*(args[2]*FRACUNIT);
+	Speed = args[1]*(FRACUNIT/8);
+	resetDelay = args[4];
+	delay = args[3];
+	if (stairsType == STAIRS_PHASED)
+	{
+		StartDelayDelta = args[3];
+		StartDelay = StartDelayDelta;
+		resetDelay = StartDelayDelta;
+		delay = 0;
+		TextureChange = args[4];
+	}
+
+	secnum = -1;
+
+	validcount++;
+	while ((secnum = P_FindSectorFromTag(args[0], secnum)) >= 0)
+	{
+		sec = &sectors[secnum];
+
+		Texture = sec->floorpic;
+		StartHeight = sec->floorheight;
+
+		// ALREADY MOVING?  IF SO, KEEP GOING...
+		if (sec->specialdata)
+			continue;
+
+		QueueStairSector(sec, 0, sec->floorheight);
+		sec->special = 0;
+	}
+	while ((qSec = DequeueStairSector(&type, &height)) != NULL)
+	{
+		ProcessStairSector(qSec, type, height, stairsType, delay, resetDelay);
+	}
+	return 1;
+}
+
+//=========================================================================
+//
+// T_BuildPillar
+//
+//=========================================================================
+
+void T_BuildPillar(pillar_t *pillar)
+{
+	result_e	res1;
+	result_e	res2;
+
+	// First, raise the floor
+	res1 = T_MovePlane(pillar->sector, pillar->floorSpeed,
+			   pillar->floordest, pillar->crush, 0,
+			   pillar->direction); // floorOrCeiling, direction
+	// Then, lower the ceiling
+	res2 = T_MovePlane(pillar->sector, pillar->ceilingSpeed,
+			   pillar->ceilingdest, pillar->crush, 1,
+			   -pillar->direction);
+	if (res1 == RES_PASTDEST && res2 == RES_PASTDEST)
+	{
+		pillar->sector->specialdata = NULL;
+		SN_StopSequence((mobj_t *)(void *)&pillar->sector->soundorg);
+		P_TagFinished(pillar->sector->tag);
+		P_RemoveThinker(&pillar->thinker);
+	}
+}
+
+//=========================================================================
+//
+// EV_BuildPillar
+//
+//=========================================================================
+
+int EV_BuildPillar(line_t *line, byte *args, boolean crush)
+{
+	int secnum;
+	sector_t *sec;
+	pillar_t *pillar;
+	int newHeight;
+	int rtn;
+
+	rtn = 0;
+	secnum = -1;
+	while ((secnum = P_FindSectorFromTag(args[0], secnum)) >= 0)
+	{
+		sec = &sectors[secnum];
+		if (sec->specialdata)
+			continue; // already moving
+		if (sec->floorheight == sec->ceilingheight)
+		{ // pillar is already closed
+			continue;
+		}
+		rtn = 1;
+		if (!args[2])
+		{
+			newHeight = sec->floorheight +
+				((sec->ceilingheight - sec->floorheight)/2);
+		}
+		else
+		{
+			newHeight = sec->floorheight + (args[2]<<FRACBITS);
+		}
+
+		pillar = (pillar_t *) Z_Malloc(sizeof(*pillar), PU_LEVSPEC, NULL);
+		sec->specialdata = pillar;
+		P_AddThinker(&pillar->thinker);
+		pillar->thinker.function = T_BuildPillar;
+		pillar->sector = sec;
+		if (!args[2])
+		{
+			pillar->ceilingSpeed = pillar->floorSpeed = args[1]*(FRACUNIT/8);
+		}
+		else if (newHeight-sec->floorheight > sec->ceilingheight - newHeight)
+		{
+			pillar->floorSpeed = args[1]*(FRACUNIT/8);
+			pillar->ceilingSpeed = FixedMul(sec->ceilingheight - newHeight,
+				FixedDiv(pillar->floorSpeed, newHeight - sec->floorheight));
+		}
+		else
+		{
+			pillar->ceilingSpeed = args[1]*(FRACUNIT/8);
+			pillar->floorSpeed = FixedMul(newHeight - sec->floorheight,
+				FixedDiv(pillar->ceilingSpeed, sec->ceilingheight - newHeight));
+		}
+		pillar->floordest = newHeight;
+		pillar->ceilingdest = newHeight;
+		pillar->direction = 1;
+		pillar->crush = crush*args[3];
+		SN_StartSequence((mobj_t *)(void *)&pillar->sector->soundorg,
+				 SEQ_PLATFORM + pillar->sector->seqType);
+	}
+	return rtn;
+}
+
+//=========================================================================
+//
+// EV_OpenPillar
+//
+//=========================================================================
+
+int EV_OpenPillar(line_t *line, byte *args)
+{
+	int secnum;
+	sector_t *sec;
+	pillar_t *pillar;
+	int rtn;
+
+	rtn = 0;
+	secnum = -1;
+	while ((secnum = P_FindSectorFromTag(args[0], secnum)) >= 0)
+	{
+		sec = &sectors[secnum];
+		if (sec->specialdata)
+			continue; // already moving
+		if (sec->floorheight != sec->ceilingheight)
+		{ // pillar isn't closed
+			continue;
+		}
+		rtn = 1;
+		pillar = (pillar_t *) Z_Malloc(sizeof(*pillar), PU_LEVSPEC, NULL);
+		sec->specialdata = pillar;
+		P_AddThinker(&pillar->thinker);
+		pillar->thinker.function = T_BuildPillar;
+		pillar->sector = sec;
+		if (!args[2])
+		{
+			pillar->floordest = P_FindLowestFloorSurrounding(sec);
+		}
+		else
+		{
+			pillar->floordest = sec->floorheight - (args[2]<<FRACBITS);
+		}
+		if (!args[3])
+		{
+			pillar->ceilingdest = P_FindHighestCeilingSurrounding(sec);
+		}
+		else
+		{
+			pillar->ceilingdest = sec->ceilingheight + (args[3]<<FRACBITS);
+		}
+		if (sec->floorheight - pillar->floordest >= 
+					pillar->ceilingdest - sec->ceilingheight)
+		{
+			pillar->floorSpeed = args[1]*(FRACUNIT/8);
+			pillar->ceilingSpeed = FixedMul(sec->ceilingheight - pillar->ceilingdest,
+				FixedDiv(pillar->floorSpeed, pillar->floordest - sec->floorheight));
+		}
+		else
+		{
+			pillar->ceilingSpeed = args[1]*(FRACUNIT/8);
+			pillar->floorSpeed = FixedMul(pillar->floordest - sec->floorheight,
+				FixedDiv(pillar->ceilingSpeed, sec->ceilingheight - pillar->ceilingdest));
+		}
+		pillar->direction = -1; // open the pillar
+		SN_StartSequence((mobj_t *)(void *)&pillar->sector->soundorg,
+				 SEQ_PLATFORM + pillar->sector->seqType);
+	}
+	return rtn;
+}
+
+//=========================================================================
+//
+// EV_FloorCrushStop
+//
+//=========================================================================
+
+int EV_FloorCrushStop(line_t *line, byte *args)
+{
+	thinker_t *think;
+	floormove_t *floor;
+	boolean rtn;
+
+	rtn = 0;
+	for (think = thinkercap.next; think != &thinkercap; think = think->next)
+	{
+		if (think->function != T_MoveFloor)
+		{
+			continue;
+		}
+		floor = (floormove_t *)think;
+		if (floor->type != FLEV_RAISEFLOORCRUSH)
+		{
+			continue;
+		}
+		// Completely remove the crushing floor
+		SN_StopSequence((mobj_t *)(void *)&floor->sector->soundorg);
+		floor->sector->specialdata = NULL;
+		P_TagFinished(floor->sector->tag);
+		P_RemoveThinker(&floor->thinker);
+		rtn = 1;
+	}
+	return rtn;
+}
+
+//==========================================================================
+//
+// T_FloorWaggle
+//
+//==========================================================================
+
+#define WGLSTATE_EXPAND		1
+#define WGLSTATE_STABLE		2
+#define WGLSTATE_REDUCE		3
+
+void T_FloorWaggle(floorWaggle_t *waggle)
+{
+	switch (waggle->state)
+	{
+	case WGLSTATE_EXPAND:
+		if ((waggle->scale += waggle->scaleDelta) >= waggle->targetScale)
+		{
+			waggle->scale = waggle->targetScale;
+			waggle->state = WGLSTATE_STABLE;
+		}
+		break;
+	case WGLSTATE_REDUCE:
+		if ((waggle->scale -= waggle->scaleDelta) <= 0)
+		{ // Remove
+			waggle->sector->floorheight = waggle->originalHeight;
+			P_ChangeSector(waggle->sector, true);
+			waggle->sector->specialdata = NULL;
+			P_TagFinished(waggle->sector->tag);
+			P_RemoveThinker(&waggle->thinker);
+			return;
+		}
+		break;
+	case WGLSTATE_STABLE:
+		if (waggle->ticker != -1)
+		{
+			if (!--waggle->ticker)
+			{
+				waggle->state = WGLSTATE_REDUCE;
+			}
+		}
+		break;
+	}
+	waggle->accumulator += waggle->accDelta;
+	waggle->sector->floorheight = waggle->originalHeight +
+		FixedMul(FloatBobOffsets[(waggle->accumulator>>FRACBITS) & 63], waggle->scale);
+	P_ChangeSector(waggle->sector, true);
+}
+
+//==========================================================================
+//
+// EV_StartFloorWaggle
+//
+//==========================================================================
+
+boolean EV_StartFloorWaggle(int tag, int height, int speed, int offset,
+								int timer)
+{
+	int sectorIndex;
+	sector_t *sector;
+	floorWaggle_t *waggle;
+	boolean retCode;
+
+	retCode = false;
+	sectorIndex = -1;
+	while ((sectorIndex = P_FindSectorFromTag(tag, sectorIndex)) >= 0)
+	{
+		sector = &sectors[sectorIndex];
+		if (sector->specialdata)
+		{ // Already busy with another thinker
+			continue;
+		}
+		retCode = true;
+		waggle = (floorWaggle_t *) Z_Malloc(sizeof(*waggle), PU_LEVSPEC, NULL);
+		sector->specialdata = waggle;
+		waggle->thinker.function = T_FloorWaggle;
+		waggle->sector = sector;
+		waggle->originalHeight = sector->floorheight;
+		waggle->accumulator = offset*FRACUNIT;
+		waggle->accDelta = speed<<10;
+		waggle->scale = 0;
+		waggle->targetScale = height<<10;
+		waggle->scaleDelta = waggle->targetScale / (35 + ((3*35)*height)/255);
+		waggle->ticker = timer ? timer*35 : -1;
+		waggle->state = WGLSTATE_EXPAND;
+		P_AddThinker(&waggle->thinker);
+	}
+	return retCode;
+}
+
--- /dev/null
+++ b/p_inter.c
@@ -1,0 +1,2276 @@
+
+//**************************************************************************
+//**
+//** p_inter.c : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 575 $
+//** $Date: 2011-04-13 22:06:28 +0300 (Wed, 13 Apr 2011) $
+//**
+//**************************************************************************
+
+#include "h2stdinc.h"
+#include "h2def.h"
+#include "p_local.h"
+#include "soundst.h"
+
+extern int messageson;
+
+#define BONUSADD	6
+
+int ArmorIncrement[NUMCLASSES][NUMARMOR] =
+{
+	{ 25*FRACUNIT, 20*FRACUNIT, 15*FRACUNIT, 5*FRACUNIT },
+	{ 10*FRACUNIT, 25*FRACUNIT, 5*FRACUNIT, 20*FRACUNIT },
+	{ 5*FRACUNIT, 15*FRACUNIT, 10*FRACUNIT, 25*FRACUNIT },
+#ifdef ASSASSIN
+	{ 20*FRACUNIT, 10*FRACUNIT, 25*FRACUNIT, 5*FRACUNIT },
+#endif
+	{ 0, 0, 0, 0 }
+};
+
+int AutoArmorSave[NUMCLASSES] =
+{
+	15*FRACUNIT,
+	10*FRACUNIT,
+	5*FRACUNIT,
+#ifdef ASSASSIN
+	10*FRACUNIT,
+#endif
+	0
+};
+
+const char *TextKeyMessages[] =
+{
+	TXT_KEY_STEEL,
+	TXT_KEY_CAVE,
+	TXT_KEY_AXE,
+	TXT_KEY_FIRE,
+	TXT_KEY_EMERALD,
+	TXT_KEY_DUNGEON,
+	TXT_KEY_SILVER,
+	TXT_KEY_RUSTED,
+	TXT_KEY_HORN,
+	TXT_KEY_SWAMP,
+	TXT_KEY_CASTLE
+};
+
+static void SetDormantArtifact(mobj_t *arti);
+static void TryPickupArtifact(player_t *player, artitype_t artifactType, mobj_t *artifact);
+static void TryPickupWeapon(player_t *player, pclass_t weaponClass, weapontype_t weaponType, mobj_t *weapon, const char *message);
+static void TryPickupWeaponPiece(player_t *player, pclass_t matchClass, int pieceValue, mobj_t *pieceMobj);
+
+//--------------------------------------------------------------------------
+//
+// PROC P_SetMessage
+//
+//--------------------------------------------------------------------------
+
+void P_SetMessage(player_t *player, const char *message, boolean ultmsg)
+{
+	if ((player->ultimateMessage || !messageson) && !ultmsg)
+	{
+		return;
+	}
+	if (strlen(message) > 79)
+	{
+		memcpy(player->message, message, 79);
+		player->message[79] = 0;
+	}
+	else
+	{
+		strcpy(player->message, message);
+	}
+	strupr(player->message);
+	player->messageTics = MESSAGETICS;
+	player->yellowMessage = false;
+	if (ultmsg)
+	{
+		player->ultimateMessage = true;
+	}
+	if (player == &players[consoleplayer])
+	{
+		BorderTopRefresh = true;
+	}
+}
+
+//==========================================================================
+//
+// P_SetYellowMessage
+//
+//==========================================================================
+
+void P_SetYellowMessage(player_t *player, const char *message, boolean ultmsg)
+{
+	if ((player->ultimateMessage || !messageson) && !ultmsg)
+	{
+		return;
+	}
+	if (strlen(message) > 79)
+	{
+		memcpy(player->message, message, 79);
+		player->message[79] = 0;
+	}
+	else
+	{
+		strcpy(player->message, message);
+	}
+	player->messageTics = 5*MESSAGETICS; // Bold messages last longer
+	player->yellowMessage = true;
+	if (ultmsg)
+	{
+		player->ultimateMessage = true;
+	}
+	if (player == &players[consoleplayer])
+	{
+		BorderTopRefresh = true;
+	}
+}
+
+//==========================================================================
+//
+// P_ClearMessage
+//
+//==========================================================================
+
+void P_ClearMessage(player_t *player)
+{
+	player->messageTics = 0;
+	if (player == &players[consoleplayer])
+	{
+		BorderTopRefresh = true;
+	}
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC P_HideSpecialThing
+//
+//----------------------------------------------------------------------------
+
+static void P_HideSpecialThing(mobj_t *thing)
+{
+	thing->flags &= ~MF_SPECIAL;
+	thing->flags2 |= MF2_DONTDRAW;
+	P_SetMobjState(thing, S_HIDESPECIAL1);
+}
+
+//--------------------------------------------------------------------------
+//
+// FUNC P_GiveMana
+//
+// Returns true if the player accepted the mana, false if it was
+// refused (player has MAX_MANA).
+//
+//--------------------------------------------------------------------------
+
+boolean P_GiveMana(player_t *player, manatype_t mana, int count)
+{
+	int prevMana;
+	//weapontype_t changeWeapon;
+
+	if (mana == MANA_NONE || mana == MANA_BOTH)
+	{
+		return false;
+	}
+	if (mana < 0 || mana > NUMMANA)
+	{
+		I_Error("P_GiveMana: bad type %i", mana);
+	}
+	if (player->mana[mana] == MAX_MANA)
+	{
+		return false;
+	}
+	if (gameskill == sk_baby || gameskill == sk_nightmare)
+	{ // extra mana in baby mode and nightmare mode
+		count += count>>1;
+	}
+	prevMana = player->mana[mana];
+
+	player->mana[mana] += count;
+	if (player->mana[mana] > MAX_MANA)
+	{
+		player->mana[mana] = MAX_MANA;
+	}
+	if (player->playerclass == PCLASS_FIGHTER && player->readyweapon == WP_SECOND
+						  && mana == MANA_1 && prevMana <= 0)
+	{
+		P_SetPsprite(player, ps_weapon, S_FAXEREADY_G);
+	}
+	return true;
+}
+
+//==========================================================================
+//
+// TryPickupWeapon
+//
+//==========================================================================
+
+static void TryPickupWeapon(player_t *player, pclass_t weaponClass,
+	weapontype_t weaponType, mobj_t *weapon, const char *message)
+{
+	boolean removeit;
+	boolean gaveMana;
+	boolean gaveWeapon;
+
+	removeit = true;
+	if (player->playerclass != weaponClass
+#ifdef ASSASSIN
+		&& player->playerclass != PCLASS_ASS
+#endif
+		)
+	{ // Wrong class, but try to pick up for mana
+		if (netgame && !deathmatch)
+		{ // Can't pick up weapons for other classes in coop netplay
+			return;
+		}
+		if (weaponType == WP_SECOND)
+		{
+			if (!P_GiveMana(player, MANA_1, 25))
+			{
+				return;
+			}
+		}
+		else
+		{
+			if (!P_GiveMana(player, MANA_2, 25))
+			{
+				return;
+			}
+		}
+	}
+	else if (netgame && !deathmatch)
+	{ // Cooperative net-game
+		if (player->weaponowned[weaponType])
+		{
+			return;
+		}
+		player->weaponowned[weaponType] = true;
+		if (weaponType == WP_SECOND)
+		{
+			P_GiveMana(player, MANA_1, 25);
+		}
+		else
+		{
+			P_GiveMana(player, MANA_2, 25);
+		}
+		player->pendingweapon = weaponType;
+		removeit = false;
+	}
+	else
+	{ // Deathmatch or single player game
+		if (weaponType == WP_SECOND)
+		{
+			gaveMana = P_GiveMana(player, MANA_1, 25);
+		}
+		else
+		{
+			gaveMana = P_GiveMana(player, MANA_2, 25);
+		}
+		if (player->weaponowned[weaponType])
+		{
+			gaveWeapon = false;
+		}
+		else
+		{
+			gaveWeapon = true;
+			player->weaponowned[weaponType] = true;
+			if (weaponType > player->readyweapon)
+			{ // Only switch to more powerful weapons
+				player->pendingweapon = weaponType;
+			}
+		}
+		if (!(gaveWeapon || gaveMana))
+		{ // Player didn't need the weapon or any mana
+			return;
+		}
+	}
+
+	P_SetMessage(player, message, false);
+	if (weapon->special)
+	{
+		P_ExecuteLineSpecial(weapon->special, weapon->args,
+						NULL, 0, player->mo);
+		weapon->special = 0;
+	}
+
+	if (removeit)
+	{
+		if (deathmatch && !(weapon->flags2 & MF2_DROPPED))
+		{
+			P_HideSpecialThing(weapon);
+		}
+		else
+		{
+			P_RemoveMobj(weapon);
+		}
+	}
+
+	player->bonuscount += BONUSADD;
+	if (player == &players[consoleplayer])
+	{
+		S_StartSound(NULL, SFX_PICKUP_WEAPON);
+		SB_PaletteFlash(false);
+	}
+}
+
+//--------------------------------------------------------------------------
+//
+// FUNC P_GiveWeapon
+//
+// Returns true if the weapon or its mana was accepted.
+//
+//--------------------------------------------------------------------------
+
+/*
+static boolean P_GiveWeapon(player_t *player, pclass_t pClass, weapontype_t weapon)
+{
+	boolean gaveMana;
+	boolean gaveWeapon;
+
+	if (player->playerclass != pClass)
+	{ // player cannot use this weapon, take it anyway, and get mana
+		if (netgame && !deathmatch)
+		{ // Can't pick up weapons for other classes in coop netplay
+			return false;
+		}
+		if (weapon == WP_SECOND)
+		{
+			return P_GiveMana(player, MANA_1, 25);
+		}
+		else
+		{
+			return P_GiveMana(player, MANA_2, 25);
+		}
+	}
+	if (netgame && !deathmatch)
+	{ // Cooperative net-game
+		if (player->weaponowned[weapon])
+		{
+			return false;
+		}
+		player->bonuscount += BONUSADD;
+		player->weaponowned[weapon] = true;
+		if (weapon == WP_SECOND)
+		{
+			P_GiveMana(player, MANA_1, 25);
+		}
+		else
+		{
+			P_GiveMana(player, MANA_2, 25);
+		}
+		player->pendingweapon = weapon;
+		if (player == &players[consoleplayer])
+		{
+			S_StartSound(NULL, SFX_PICKUP_WEAPON);
+		}
+		return false;
+	}
+	if (weapon == WP_SECOND)
+	{
+		gaveMana = P_GiveMana(player, MANA_1, 25);
+	}
+	else
+	{
+		gaveMana = P_GiveMana(player, MANA_2, 25);
+	}
+	if (player->weaponowned[weapon])
+	{
+		gaveWeapon = false;
+	}
+	else
+	{
+		gaveWeapon = true;
+		player->weaponowned[weapon] = true;
+		if (weapon > player->readyweapon)
+		{ // Only switch to more powerful weapons
+			player->pendingweapon = weapon;
+		}
+	}
+	return(gaveWeapon || gaveMana);
+}
+*/
+
+//===========================================================================
+//
+// P_GiveWeaponPiece
+//
+//===========================================================================
+
+/*
+static boolean P_GiveWeaponPiece(player_t *player, pclass_t pClass, int piece)
+{
+	P_GiveMana(player, MANA_1, 20);
+	P_GiveMana(player, MANA_2, 20);
+	if (player->playerclass != pClass)
+	{
+		return true;
+	}
+	else if (player->pieces & piece)
+	{ // player already has that weapon piece
+		return true;
+	}
+	player->pieces |= piece;
+	if (player->pieces == 7)
+	{ // player has built the fourth weapon!
+		P_GiveWeapon(player, pClass, WP_FOURTH);
+		S_StartSound(player->mo, SFX_WEAPON_BUILD);
+	}
+	return true;
+}
+*/
+
+//==========================================================================
+//
+// TryPickupWeaponPiece
+//
+//==========================================================================
+
+static void TryPickupWeaponPiece(player_t *player, pclass_t matchClass,
+				 int pieceValue, mobj_t *pieceMobj)
+{
+	boolean removeit;
+	boolean checkAssembled;
+	boolean gaveWeapon;
+	int gaveMana;
+	static const char *fourthWeaponText[] =
+	{
+		TXT_WEAPON_F4,
+		TXT_WEAPON_C4,
+		TXT_WEAPON_M4,
+#ifdef ASSASSIN
+		TXT_WEAPON_A4
+#endif
+	};
+	static const char *weaponPieceText[] =
+	{
+		TXT_QUIETUS_PIECE,
+		TXT_WRAITHVERGE_PIECE,
+		TXT_BLOODSCOURGE_PIECE,
+#ifdef ASSASSIN
+		TXT_STAFFOFSET_PIECE
+#endif
+	};
+	static int pieceValueTrans[] =
+	{
+		0,				// 0: never
+		WPIECE1|WPIECE2|WPIECE3,	// WPIECE1 (1)
+		WPIECE2|WPIECE3,		// WPIECE2 (2)
+		0,				// 3: never
+		WPIECE3				// WPIECE3 (4)
+	};
+
+	removeit = true;
+	checkAssembled = true;
+	gaveWeapon = false;
+	// Allow assassin to pick up any weapons
+	if (player->playerclass != matchClass
+#ifdef ASSASSIN
+		&& player->playerclass != PCLASS_ASS
+#endif
+		)
+	{ // Wrong class, but try to pick up for mana
+		if (netgame && !deathmatch)
+		{ // Can't pick up wrong-class weapons in coop netplay
+			return;
+		}
+		checkAssembled = false;
+		gaveMana = P_GiveMana(player, MANA_1, 20) +
+			   P_GiveMana(player, MANA_2, 20);
+		if (!gaveMana)
+		{ // Didn't need the mana, so don't pick it up
+			return;
+		}
+	}
+	else if (netgame && !deathmatch)
+	{ // Cooperative net-game
+		if (player->pieces & pieceValue)
+		{ // Already has the piece
+			return;
+		}
+		pieceValue = pieceValueTrans[pieceValue];
+		P_GiveMana(player, MANA_1, 20);
+		P_GiveMana(player, MANA_2, 20);
+		removeit = false;
+	}
+	else
+	{ // Deathmatch or single player game
+		gaveMana = P_GiveMana(player, MANA_1, 20) +
+			   P_GiveMana(player, MANA_2, 20);
+		if (player->pieces & pieceValue)
+		{ // Already has the piece, check if mana needed
+			if (!gaveMana)
+			{ // Didn't need the mana, so don't pick it up
+				return;
+			}
+			checkAssembled = false;
+		}
+	}
+
+	// Pick up the weapon piece
+	if (pieceMobj->special)
+	{
+		P_ExecuteLineSpecial(pieceMobj->special, pieceMobj->args,
+							NULL, 0, player->mo);
+		pieceMobj->special = 0;
+	}
+	if (removeit)
+	{
+		if (deathmatch && !(pieceMobj->flags2 & MF2_DROPPED))
+		{
+			P_HideSpecialThing(pieceMobj);
+		}
+		else
+		{
+			P_RemoveMobj(pieceMobj);
+		}
+	}
+	player->bonuscount += BONUSADD;
+	if (player == &players[consoleplayer])
+	{
+		SB_PaletteFlash(false);
+	}
+
+	// Check if fourth weapon assembled
+	if (checkAssembled)
+	{
+		player->pieces |= pieceValue;
+		if (player->pieces == (WPIECE1|WPIECE2|WPIECE3))
+		{
+			gaveWeapon = true;
+			player->weaponowned[WP_FOURTH] = true;
+			player->pendingweapon = WP_FOURTH;
+		}
+	}
+
+	if (gaveWeapon)
+	{
+		P_SetMessage(player, fourthWeaponText[matchClass], false);
+		// Play the build-sound full volume for all players
+		S_StartSound(NULL, SFX_WEAPON_BUILD);
+	}
+	else
+	{
+		P_SetMessage(player, weaponPieceText[matchClass], false);
+		if (player == &players[consoleplayer])
+		{
+			S_StartSound(NULL, SFX_PICKUP_WEAPON);
+		}
+	}
+}
+
+//---------------------------------------------------------------------------
+//
+// FUNC P_GiveBody
+//
+// Returns false if the body isn't needed at all.
+//
+//---------------------------------------------------------------------------
+
+boolean P_GiveBody(player_t *player, int num)
+{
+	int max;
+
+	max = MAXHEALTH;
+	if (player->morphTics)
+	{
+		max = MAXMORPHHEALTH;
+	}
+	if (player->health >= max)
+	{
+		return false;
+	}
+	player->health += num;
+	if (player->health > max)
+	{
+		player->health = max;
+	}
+	player->mo->health = player->health;
+	return true;
+}
+
+//---------------------------------------------------------------------------
+//
+// FUNC P_GiveArmor
+//
+// Returns false if the armor is worse than the current armor.
+//
+//---------------------------------------------------------------------------
+
+boolean P_GiveArmor(player_t *player, armortype_t armortype, int amount)
+{
+	int hits;
+	int totalArmor;
+
+	extern int ArmorMax[NUMCLASSES];
+
+	if (amount == -1)
+	{
+		hits = ArmorIncrement[player->playerclass][armortype];
+		if (player->armorpoints[armortype] >= hits)
+		{
+			return false;
+		}
+		else
+		{
+			player->armorpoints[armortype] = hits;
+		}
+	}
+	else
+	{
+		hits = amount * 5 * FRACUNIT;
+		totalArmor = player->armorpoints[ARMOR_ARMOR]
+				+ player->armorpoints[ARMOR_SHIELD]
+				+ player->armorpoints[ARMOR_HELMET]
+				+ player->armorpoints[ARMOR_AMULET]
+				+ AutoArmorSave[player->playerclass];
+		if (totalArmor < ArmorMax[player->playerclass]*5*FRACUNIT)
+		{
+			player->armorpoints[armortype] += hits;
+		}
+		else
+		{
+			return false;
+		}
+	}
+	return true;
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC P_GiveKey
+//
+//---------------------------------------------------------------------------
+
+static boolean P_GiveKey(player_t *player, keytype_t key)
+{
+	if (player->keys & (1<<key))
+	{
+		return false;
+	}
+	player->bonuscount += BONUSADD;
+	player->keys |= 1<<key;
+	return true;
+}
+
+//---------------------------------------------------------------------------
+//
+// FUNC P_GivePower
+//
+// Returns true if power accepted.
+//
+//---------------------------------------------------------------------------
+
+boolean P_GivePower(player_t *player, powertype_t power)
+{
+	if (power == pw_invulnerability)
+	{
+		if (player->powers[power] > BLINKTHRESHOLD)
+		{ // Already have it
+			return false;
+		}
+		player->powers[power] = INVULNTICS;
+		player->mo->flags2 |= MF2_INVULNERABLE;
+		if (player->playerclass == PCLASS_MAGE)
+		{
+			player->mo->flags2 |= MF2_REFLECTIVE;
+		}
+		return true;
+	}
+	if (power == pw_flight)
+	{
+		if (player->powers[power] > BLINKTHRESHOLD)
+		{ // Already have it
+			return false;
+		}
+		player->powers[power] = FLIGHTTICS;
+		player->mo->flags2 |= MF2_FLY;
+		player->mo->flags |= MF_NOGRAVITY;
+		if (player->mo->z <= player->mo->floorz)
+		{
+			player->flyheight = 10; // thrust the player in the air a bit
+		}
+		return true;
+	}
+	if (power == pw_infrared)
+	{
+		if (player->powers[power] > BLINKTHRESHOLD)
+		{ // Already have it
+			return false;
+		}
+		player->powers[power] = INFRATICS;
+		return true;
+	}
+	if (power == pw_speed)
+	{
+		if (player->powers[power] > BLINKTHRESHOLD)
+		{ // Already have it
+			return false;
+		}
+		player->powers[power] = SPEEDTICS;
+		return true;
+	}
+	if (power == pw_minotaur)
+	{
+		// Doesn't matter if already have power, renew ticker
+		player->powers[power] = MAULATORTICS;
+		return true;
+	}
+	/*
+	if (power == pw_ironfeet)
+	{
+		player->powers[power] = IRONTICS;
+		return true;
+	}
+	if (power == pw_strength)
+	{
+		P_GiveBody(player, 100);
+		player->powers[power] = 1;
+		return true;
+	}
+	*/
+	if (player->powers[power])
+	{
+		return false; // already got it
+	}
+	player->powers[power] = 1;
+	return true;
+}
+
+//==========================================================================
+//
+// TryPickupArtifact
+//
+//==========================================================================
+
+static void TryPickupArtifact(player_t *player, artitype_t artifactType,
+							mobj_t *artifact)
+{
+	static const char *artifactMessages[NUMARTIFACTS] =
+	{
+		NULL,
+		TXT_ARTIINVULNERABILITY,
+		TXT_ARTIHEALTH,
+		TXT_ARTISUPERHEALTH,
+		TXT_ARTIHEALINGRADIUS,
+		TXT_ARTISUMMON,
+		TXT_ARTITORCH,
+		TXT_ARTIEGG,
+		TXT_ARTIFLY,
+		TXT_ARTIBLASTRADIUS,
+		TXT_ARTIPOISONBAG,
+		TXT_ARTITELEPORTOTHER,
+		TXT_ARTISPEED,
+		TXT_ARTIBOOSTMANA,
+		TXT_ARTIBOOSTARMOR,
+		TXT_ARTITELEPORT,
+		TXT_ARTIPUZZSKULL,
+		TXT_ARTIPUZZGEMBIG,
+		TXT_ARTIPUZZGEMRED,
+		TXT_ARTIPUZZGEMGREEN1,
+		TXT_ARTIPUZZGEMGREEN2,
+		TXT_ARTIPUZZGEMBLUE1,
+		TXT_ARTIPUZZGEMBLUE2,
+		TXT_ARTIPUZZBOOK1,
+		TXT_ARTIPUZZBOOK2,
+		TXT_ARTIPUZZSKULL2,
+		TXT_ARTIPUZZFWEAPON,
+		TXT_ARTIPUZZCWEAPON,
+		TXT_ARTIPUZZMWEAPON,
+		TXT_ARTIPUZZGEAR,	// All gear pickups use the same text
+		TXT_ARTIPUZZGEAR,
+		TXT_ARTIPUZZGEAR,
+		TXT_ARTIPUZZGEAR
+	};
+
+	if (P_GiveArtifact(player, artifactType, artifact))
+	{
+		if (artifact->special)
+		{
+			P_ExecuteLineSpecial(artifact->special, artifact->args,
+								NULL, 0, NULL);
+			artifact->special = 0;
+		}
+		player->bonuscount += BONUSADD;
+		if (artifactType < arti_firstpuzzitem)
+		{
+			SetDormantArtifact(artifact);
+			S_StartSound(artifact, SFX_PICKUP_ARTIFACT);
+			P_SetMessage(player, artifactMessages[artifactType], false);
+		}
+		else
+		{ // Puzzle item
+			S_StartSound(NULL, SFX_PICKUP_ITEM);
+			P_SetMessage(player, artifactMessages[artifactType], true);
+			if (!netgame || deathmatch)
+			{ // Remove puzzle items if not cooperative netplay
+				P_RemoveMobj(artifact);
+			}
+		}
+	}
+}
+
+//---------------------------------------------------------------------------
+//
+// FUNC P_GiveArtifact
+//
+// Returns true if artifact accepted.
+//
+//---------------------------------------------------------------------------
+
+boolean P_GiveArtifact(player_t *player, artitype_t arti, mobj_t *mo)
+{
+	int i;
+	int j;
+	boolean slidePointer;
+
+	slidePointer = false;
+	i = 0;
+	while (player->inventory[i].type != arti && i < player->inventorySlotNum)
+	{
+		i++;
+	}
+	if (i == player->inventorySlotNum)
+	{
+		if (arti < arti_firstpuzzitem)
+		{
+			i = 0;
+			while (player->inventory[i].type < arti_firstpuzzitem &&
+						  i < player->inventorySlotNum)
+			{
+				i++;
+			}
+			if (i != player->inventorySlotNum)
+			{
+				for (j = player->inventorySlotNum; j > i; j--)
+				{
+					player->inventory[j].count = player->inventory[j-1].count;
+					player->inventory[j].type = player->inventory[j-1].type;
+					slidePointer = true;
+				}
+			}
+		}
+		player->inventory[i].count = 1;
+		player->inventory[i].type = arti;
+		player->inventorySlotNum++;
+	}
+	else
+	{
+		if (arti >= arti_firstpuzzitem && netgame && !deathmatch)
+		{ // Can't carry more than 1 puzzle item in coop netplay
+			return false;
+		}
+		if (player->inventory[i].count >= 25)
+		{ // Player already has 25 of this item
+			return false;
+		}
+		player->inventory[i].count++;
+	}
+	if (!player->artifactCount)
+	{
+		player->readyArtifact = arti;
+	}
+	else if (player == &players[consoleplayer] && slidePointer
+						   && i <= inv_ptr)
+	{
+		inv_ptr++;
+		curpos++;
+		if (curpos > 6)
+		{
+			curpos = 6;
+		}
+	}
+	player->artifactCount++;
+	return true;
+}
+
+//==========================================================================
+//
+// SetDormantArtifact
+//
+// Removes the MF_SPECIAL flag and initiates the artifact pickup
+// animation.
+//
+//==========================================================================
+
+static void SetDormantArtifact(mobj_t *arti)
+{
+	arti->flags &= ~MF_SPECIAL;
+	if (deathmatch && !(arti->flags2 & MF2_DROPPED))
+	{
+		if (arti->type == MT_ARTIINVULNERABILITY)
+		{
+			P_SetMobjState(arti, S_DORMANTARTI3_1);
+		}
+		else if (arti->type == MT_SUMMONMAULATOR ||
+				arti->type == MT_ARTIFLY)
+		{
+			P_SetMobjState(arti, S_DORMANTARTI2_1);
+		}
+		else
+		{
+			P_SetMobjState(arti, S_DORMANTARTI1_1);
+		}
+	}
+	else
+	{ // Don't respawn
+		P_SetMobjState(arti, S_DEADARTI1);
+	}
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC A_RestoreArtifact
+//
+//---------------------------------------------------------------------------
+
+void A_RestoreArtifact(mobj_t *arti)
+{
+	arti->flags |= MF_SPECIAL;
+	P_SetMobjState(arti, arti->info->spawnstate);
+	S_StartSound(arti, SFX_RESPAWN);
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC A_RestoreSpecialThing1
+//
+// Make a special thing visible again.
+//
+//---------------------------------------------------------------------------
+
+void A_RestoreSpecialThing1(mobj_t *thing)
+{
+	thing->flags2 &= ~MF2_DONTDRAW;
+	S_StartSound(thing, SFX_RESPAWN);
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC A_RestoreSpecialThing2
+//
+//---------------------------------------------------------------------------
+
+void A_RestoreSpecialThing2(mobj_t *thing)
+{
+	thing->flags |= MF_SPECIAL;
+	P_SetMobjState(thing, thing->info->spawnstate);
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC P_TouchSpecialThing
+//
+//---------------------------------------------------------------------------
+
+void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher)
+{
+	player_t *player;
+	fixed_t delta;
+	int sound;
+	boolean respawn;
+
+	delta = special->z-toucher->z;
+	if (delta > toucher->height || delta < -32*FRACUNIT)
+	{ // Out of reach
+		return;
+	}
+	if (toucher->health <= 0)
+	{ // Toucher is dead
+		return;
+	}
+	sound = SFX_PICKUP_ITEM;
+	player = toucher->player;
+	respawn = true;
+	switch (special->sprite)
+	{
+	// Items
+	case SPR_PTN1: // Item_HealingPotion
+		if (!P_GiveBody(player, 10))
+		{
+			return;
+		}
+		P_SetMessage(player, TXT_ITEMHEALTH, false);
+		break;
+	case SPR_ARM1:
+		if (!P_GiveArmor(player, ARMOR_ARMOR, -1))
+		{
+			return;
+		}
+		P_SetMessage(player, TXT_ARMOR1, false);
+		break;
+	case SPR_ARM2:
+		if (!P_GiveArmor(player, ARMOR_SHIELD, -1))
+		{
+			return;
+		}
+		P_SetMessage(player, TXT_ARMOR2, false);
+		break;
+	case SPR_ARM3:
+		if (!P_GiveArmor(player, ARMOR_HELMET, -1))
+		{
+			return;
+		}
+		P_SetMessage(player, TXT_ARMOR3, false);
+		break;
+	case SPR_ARM4:
+		if (!P_GiveArmor(player, ARMOR_AMULET, -1))
+		{
+			return;
+		}
+		P_SetMessage(player, TXT_ARMOR4, false);
+		break;
+
+	// Keys
+	case SPR_KEY1:
+	case SPR_KEY2:
+	case SPR_KEY3:
+	case SPR_KEY4:
+	case SPR_KEY5:
+	case SPR_KEY6:
+	case SPR_KEY7:
+	case SPR_KEY8:
+	case SPR_KEY9:
+	case SPR_KEYA:
+	case SPR_KEYB:
+		if (!P_GiveKey(player, special->sprite-SPR_KEY1))
+		{
+			return;
+		}
+		P_SetMessage(player, TextKeyMessages[special->sprite-SPR_KEY1], true);
+		sound = SFX_PICKUP_KEY;
+
+		// Check and process the special now in case the key doesn't
+		// get removed for coop netplay
+		if (special->special)
+		{
+			P_ExecuteLineSpecial(special->special, special->args,
+							NULL, 0, toucher);
+			special->special = 0;
+		}
+
+		if (!netgame)
+		{ // Only remove keys in single player game
+			break;
+		}
+		player->bonuscount += BONUSADD;
+		if (player == &players[consoleplayer])
+		{
+			S_StartSound(NULL, sound);
+			SB_PaletteFlash(false);
+		}
+		return;
+
+	// Artifacts
+	case SPR_PTN2:
+		TryPickupArtifact(player, arti_health, special);
+		return;
+	case SPR_SOAR:
+		TryPickupArtifact(player, arti_fly, special);
+		return;
+	case SPR_INVU:
+		TryPickupArtifact(player, arti_invulnerability, special);
+		return;
+	case SPR_SUMN:
+		TryPickupArtifact(player, arti_summon, special);
+		return;
+	case SPR_PORK:
+		TryPickupArtifact(player, arti_egg, special);
+		return;
+	case SPR_SPHL:
+		TryPickupArtifact(player, arti_superhealth, special);
+		return;
+	case SPR_HRAD:
+		TryPickupArtifact(player, arti_healingradius, special);
+		return;
+	case SPR_TRCH:
+		TryPickupArtifact(player, arti_torch, special);
+		return;
+	case SPR_ATLP:
+		TryPickupArtifact(player, arti_teleport, special);
+		return;
+	case SPR_TELO:
+		TryPickupArtifact(player, arti_teleportother, special);
+		return;
+	case SPR_PSBG:
+		TryPickupArtifact(player, arti_poisonbag, special);
+		return;
+	case SPR_SPED:
+		TryPickupArtifact(player, arti_speed, special);
+		return;
+	case SPR_BMAN:
+		TryPickupArtifact(player, arti_boostmana, special);
+		return;
+	case SPR_BRAC:
+		TryPickupArtifact(player, arti_boostarmor, special);
+		return;
+	case SPR_BLST:
+		TryPickupArtifact(player, arti_blastradius, special);
+		return;
+
+	// Puzzle artifacts
+	case SPR_ASKU:
+		TryPickupArtifact(player, arti_puzzskull, special);
+		return;
+	case SPR_ABGM:
+		TryPickupArtifact(player, arti_puzzgembig, special);
+		return;
+	case SPR_AGMR:
+		TryPickupArtifact(player, arti_puzzgemred, special);
+		return;
+	case SPR_AGMG:
+		TryPickupArtifact(player, arti_puzzgemgreen1, special);
+		return;
+	case SPR_AGG2:
+		TryPickupArtifact(player, arti_puzzgemgreen2, special);
+		return;
+	case SPR_AGMB:
+		TryPickupArtifact(player, arti_puzzgemblue1, special);
+		return;
+	case SPR_AGB2:
+		TryPickupArtifact(player, arti_puzzgemblue2, special);
+		return;
+	case SPR_ABK1:
+		TryPickupArtifact(player, arti_puzzbook1, special);
+		return;
+	case SPR_ABK2:
+		TryPickupArtifact(player, arti_puzzbook2, special);
+		return;
+	case SPR_ASK2:
+		TryPickupArtifact(player, arti_puzzskull2, special);
+		return;
+	case SPR_AFWP:
+		TryPickupArtifact(player, arti_puzzfweapon, special);
+		return;
+	case SPR_ACWP:
+		TryPickupArtifact(player, arti_puzzcweapon, special);
+		return;
+	case SPR_AMWP:
+		TryPickupArtifact(player, arti_puzzmweapon, special);
+		return;
+	case SPR_AGER:
+		TryPickupArtifact(player, arti_puzzgear1, special);
+		return;
+	case SPR_AGR2:
+		TryPickupArtifact(player, arti_puzzgear2, special);
+		return;
+	case SPR_AGR3:
+		TryPickupArtifact(player, arti_puzzgear3, special);
+		return;
+	case SPR_AGR4:
+		TryPickupArtifact(player, arti_puzzgear4, special);
+		return;
+
+	// Mana
+	case SPR_MAN1:
+		if (!P_GiveMana(player, MANA_1, 15))
+		{
+			return;
+		}
+		P_SetMessage(player, TXT_MANA_1, false);
+		break;
+	case SPR_MAN2:
+		if (!P_GiveMana(player, MANA_2, 15))
+		{
+			return;
+		}
+		P_SetMessage(player, TXT_MANA_2, false);
+		break;
+	case SPR_MAN3: // Double Mana Dodecahedron
+		if (!P_GiveMana(player, MANA_1, 20))
+		{
+			if (!P_GiveMana(player, MANA_2, 20))
+			{
+				return;
+			}
+		}
+		else
+		{
+			P_GiveMana(player, MANA_2, 20);
+		}
+		P_SetMessage(player, TXT_MANA_BOTH, false);
+		break;
+
+	// 2nd and 3rd Mage Weapons
+	case SPR_WMCS: // Frost Shards
+		TryPickupWeapon(player, PCLASS_MAGE, WP_SECOND,
+				special, TXT_WEAPON_M2);
+		return;
+	case SPR_WMLG: // Arc of Death
+		TryPickupWeapon(player, PCLASS_MAGE, WP_THIRD,
+				special, TXT_WEAPON_M3);
+		return;
+
+	// 2nd and 3rd Fighter Weapons
+	case SPR_WFAX: // Timon's Axe
+		TryPickupWeapon(player, PCLASS_FIGHTER, WP_SECOND,
+				special, TXT_WEAPON_F2);
+		return;
+	case SPR_WFHM: // Hammer of Retribution
+		TryPickupWeapon(player, PCLASS_FIGHTER, WP_THIRD,
+				special, TXT_WEAPON_F3);
+		return;
+
+	// 2nd and 3rd Cleric Weapons
+	case SPR_WCSS: // Serpent Staff
+		TryPickupWeapon(player, PCLASS_CLERIC, WP_SECOND,
+				special, TXT_WEAPON_C2);
+		return;
+	case SPR_WCFM: // Firestorm
+		TryPickupWeapon(player, PCLASS_CLERIC, WP_THIRD,
+				special, TXT_WEAPON_C3);
+		return;
+
+	// Fourth Weapon Pieces
+	case SPR_WFR1:
+		TryPickupWeaponPiece(player, PCLASS_FIGHTER, WPIECE1, special);
+		return;
+	case SPR_WFR2:
+		TryPickupWeaponPiece(player, PCLASS_FIGHTER, WPIECE2, special);
+		return;
+	case SPR_WFR3:
+		TryPickupWeaponPiece(player, PCLASS_FIGHTER, WPIECE3, special);
+		return;
+	case SPR_WCH1:
+		TryPickupWeaponPiece(player, PCLASS_CLERIC, WPIECE1, special);
+		return;
+	case SPR_WCH2:
+		TryPickupWeaponPiece(player, PCLASS_CLERIC, WPIECE2, special);
+		return;
+	case SPR_WCH3:
+		TryPickupWeaponPiece(player, PCLASS_CLERIC, WPIECE3, special);
+		return;
+	case SPR_WMS1:
+		TryPickupWeaponPiece(player, PCLASS_MAGE, WPIECE1, special);
+		return;
+	case SPR_WMS2:
+		TryPickupWeaponPiece(player, PCLASS_MAGE, WPIECE2, special);
+		return;
+	case SPR_WMS3:
+		TryPickupWeaponPiece(player, PCLASS_MAGE, WPIECE3, special);
+		return;
+#ifdef ASSASSIN
+	/*
+	// Don't forget to fix this
+	case SPR_WAS1:
+		TryPickupWeaponPiece(player, PCLASS_ASS, WPIECE1, special);
+		return;
+	case SPR_WAS2:
+		TryPickupWeaponPiece(player, PCLASS_ASS, WPIECE2, special);
+		return;
+	case SPR_WAS3:
+		TryPickupWeaponPiece(player,PCLASS_ASS, WPIECE3, special);
+		return;
+	*/
+#endif
+	default:
+		I_Error("P_SpecialThing: Unknown gettable thing");
+	}
+	if (special->special)
+	{
+		P_ExecuteLineSpecial(special->special, special->args, NULL,
+								0, toucher);
+		special->special = 0;
+	}
+	if (deathmatch && respawn && !(special->flags2 & MF2_DROPPED))
+	{
+		P_HideSpecialThing(special);
+	}
+	else
+	{
+		P_RemoveMobj(special);
+	}
+	player->bonuscount += BONUSADD;
+	if (player == &players[consoleplayer])
+	{
+		S_StartSound(NULL, sound);
+		SB_PaletteFlash(false);
+	}
+}
+
+// Search thinker list for minotaur
+static mobj_t *ActiveMinotaur(player_t *master)
+{
+	mobj_t *mo;
+	player_t *plr;
+	thinker_t *think;
+	int summontime;
+
+	for (think = thinkercap.next; think != &thinkercap; think = think->next)
+	{
+		if (think->function != P_MobjThinker)
+			continue;
+		mo = (mobj_t *)think;
+		if (mo->type != MT_MINOTAUR)
+			continue;
+		if (mo->health <= 0)
+			continue;
+		if (!(mo->flags & MF_COUNTKILL))
+			continue;		// for morphed minotaurs
+		if (mo->flags & MF_CORPSE)
+			continue;
+		summontime = READ_INT32(mo->args);
+		if ((leveltime - summontime) >= MAULATORTICS)
+			continue;
+		plr = ((mobj_t *)mo->special1)->player;
+		if (plr == master)
+			return mo;
+	}
+	return NULL;
+}
+
+
+//---------------------------------------------------------------------------
+//
+// PROC P_KillMobj
+//
+//---------------------------------------------------------------------------
+
+static void P_KillMobj(mobj_t *source, mobj_t *target)
+{
+	int dummy;
+	mobj_t *master;
+
+	target->flags &= ~(MF_SHOOTABLE|MF_FLOAT|MF_SKULLFLY|MF_NOGRAVITY);
+	target->flags |= MF_CORPSE|MF_DROPOFF;
+	target->flags2 &= ~MF2_PASSMOBJ;
+	target->height >>= 2;
+	if ((target->flags & MF_COUNTKILL || target->type == MT_ZBELL) && target->special)
+	{ // Initiate monster death actions
+		if (target->type == MT_SORCBOSS)
+		{
+			dummy = 0;
+			P_StartACS(target->special, 0, (byte *)&dummy, target, NULL, 0);
+		}
+		else
+		{
+			P_ExecuteLineSpecial(target->special, target->args, NULL, 0, target);
+		}
+	}
+	if (source && source->player)
+	{ // Check for frag changes
+		if (target->player)
+		{
+			if (target == source)
+			{ // Self-frag
+				target->player->frags[target->player-players]--;
+				if (cmdfrag && netgame &&
+					source->player == &players[consoleplayer])
+				{ // Send out a frag count packet
+					NET_SendFrags(source->player);
+				}
+			}
+			else
+			{
+				source->player->frags[target->player-players]++;
+				if (cmdfrag && netgame &&
+					source->player == &players[consoleplayer])
+				{ // Send out a frag count packet
+					NET_SendFrags(source->player);
+				}
+			}
+		}
+	}
+	if (target->player)
+	{ // Player death
+		if (!source)
+		{ // Self-frag
+			target->player->frags[target->player-players]--;
+			if (cmdfrag && netgame &&
+				target->player == &players[consoleplayer])
+			{ // Send out a frag count packet
+				NET_SendFrags(target->player);
+			}
+		}
+		target->flags &= ~MF_SOLID;
+		target->flags2 &= ~MF2_FLY;
+		target->player->powers[pw_flight] = 0;
+		target->player->playerstate = PST_DEAD;
+		P_DropWeapon(target->player);
+		if (target->flags2 & MF2_FIREDAMAGE)
+		{ // Player flame death
+			switch (target->player->playerclass)
+			{
+			case PCLASS_FIGHTER:
+				S_StartSound(target, SFX_PLAYER_FIGHTER_BURN_DEATH);
+				P_SetMobjState(target, S_PLAY_F_FDTH1);
+				return;
+			case PCLASS_CLERIC:
+				S_StartSound(target, SFX_PLAYER_CLERIC_BURN_DEATH);
+				P_SetMobjState(target, S_PLAY_C_FDTH1);
+				return;
+			case PCLASS_MAGE:
+				S_StartSound(target, SFX_PLAYER_MAGE_BURN_DEATH);
+				P_SetMobjState(target, S_PLAY_M_FDTH1);
+				return;
+			default:
+				break;
+			}
+		}
+		if (target->flags2 & MF2_ICEDAMAGE)
+		{ // Player ice death
+			target->flags &= ~(7<<MF_TRANSSHIFT); //no translation
+			target->flags |= MF_ICECORPSE;
+			switch (target->player->playerclass)
+			{
+			case PCLASS_FIGHTER:
+				P_SetMobjState(target, S_FPLAY_ICE);
+				return;
+			case PCLASS_CLERIC:
+				P_SetMobjState(target, S_CPLAY_ICE);
+				return;
+			case PCLASS_MAGE:
+				P_SetMobjState(target, S_MPLAY_ICE);
+				return;
+			case PCLASS_PIG:
+				P_SetMobjState(target, S_PIG_ICE);
+				return;
+			default:
+				break;
+			}
+		}
+	}
+	if (target->flags2 & MF2_FIREDAMAGE)
+	{
+		if (target->type == MT_FIGHTER_BOSS
+			|| target->type == MT_CLERIC_BOSS
+			|| target->type == MT_MAGE_BOSS)
+		{
+			switch (target->type)
+			{
+			case MT_FIGHTER_BOSS:
+				S_StartSound(target, SFX_PLAYER_FIGHTER_BURN_DEATH);
+				P_SetMobjState(target, S_PLAY_F_FDTH1);
+				return;
+			case MT_CLERIC_BOSS:
+				S_StartSound(target, SFX_PLAYER_CLERIC_BURN_DEATH);
+				P_SetMobjState(target, S_PLAY_C_FDTH1);
+				return;
+			case MT_MAGE_BOSS:
+				S_StartSound(target, SFX_PLAYER_MAGE_BURN_DEATH);
+				P_SetMobjState(target, S_PLAY_M_FDTH1);
+				return;
+			default:
+				break;
+			}
+		}
+		else if (target->type == MT_TREEDESTRUCTIBLE)
+		{
+			P_SetMobjState(target, S_ZTREEDES_X1);
+			target->height = 24*FRACUNIT;
+			S_StartSound(target, SFX_TREE_EXPLODE);
+			return;
+		}
+	}
+	if (target->flags2 & MF2_ICEDAMAGE)
+	{
+		target->flags |= MF_ICECORPSE;
+		switch (target->type)
+		{
+		case MT_BISHOP:
+			P_SetMobjState(target, S_BISHOP_ICE);
+			return;
+		case MT_CENTAUR:
+		case MT_CENTAURLEADER:
+			P_SetMobjState(target, S_CENTAUR_ICE);
+			return;
+		case MT_DEMON:
+		case MT_DEMON2:
+			P_SetMobjState(target, S_DEMON_ICE);
+			return;
+		case MT_SERPENT:
+		case MT_SERPENTLEADER:
+			P_SetMobjState(target, S_SERPENT_ICE);
+			return;
+		case MT_WRAITH:
+		case MT_WRAITHB:
+			P_SetMobjState(target, S_WRAITH_ICE);
+			return;
+		case MT_ETTIN:
+			P_SetMobjState(target, S_ETTIN_ICE1);
+			return;
+		case MT_FIREDEMON:
+			P_SetMobjState(target, S_FIRED_ICE1);
+			return;
+		case MT_FIGHTER_BOSS:
+			P_SetMobjState(target, S_FIGHTER_ICE);
+			return;
+		case MT_CLERIC_BOSS:
+			P_SetMobjState(target, S_CLERIC_ICE);
+			return;
+		case MT_MAGE_BOSS:
+			P_SetMobjState(target, S_MAGE_ICE);
+			return;
+		case MT_PIG:
+			P_SetMobjState(target, S_PIG_ICE);
+			return;
+		default:
+			target->flags &= ~MF_ICECORPSE;
+			break;
+		}
+	}
+
+	if (target->type == MT_MINOTAUR)
+	{
+		master = (mobj_t *)target->special1;
+		if (master->health > 0)
+		{
+			if (!ActiveMinotaur(master->player))
+			{
+				master->player->powers[pw_minotaur] = 0;
+			}
+		}
+	}
+	else if (target->type == MT_TREEDESTRUCTIBLE)
+	{
+		target->height = 24*FRACUNIT;
+	}
+	if (target->health < -(target->info->spawnhealth>>1)
+				&& target->info->xdeathstate)
+	{ // Extreme death
+		P_SetMobjState(target, target->info->xdeathstate);
+	}
+	else
+	{ // Normal death
+		if ((target->type==MT_FIREDEMON) &&
+			(target->z <= target->floorz + 2*FRACUNIT) &&
+			(target->info->xdeathstate))
+		{
+			// This is to fix the imps' staying in fall state
+			P_SetMobjState(target, target->info->xdeathstate);
+		}
+		else
+		{
+			P_SetMobjState(target, target->info->deathstate);
+		}
+	}
+	target->tics -= P_Random() & 3;
+//	I_StartSound(&actor->r, actor->info->deathsound);
+}
+
+//---------------------------------------------------------------------------
+//
+// FUNC P_MinotaurSlam
+//
+//---------------------------------------------------------------------------
+
+static void P_MinotaurSlam(mobj_t *source, mobj_t *target)
+{
+	angle_t angle;
+	fixed_t thrust;
+
+	angle = R_PointToAngle2(source->x, source->y, target->x, target->y);
+	angle >>= ANGLETOFINESHIFT;
+	thrust = 16*FRACUNIT + (P_Random()<<10);
+	target->momx += FixedMul(thrust, finecosine[angle]);
+	target->momy += FixedMul(thrust, finesine[angle]);
+	P_DamageMobj(target, NULL, source, HITDICE(4));
+	if (target->player)
+	{
+		target->reactiontime = 14 + (P_Random() & 7);
+	}
+	source->args[0] = 0;			// Stop charging
+}
+
+
+//---------------------------------------------------------------------------
+//
+// FUNC P_MorphPlayer
+//
+// Returns true if the player gets turned into a pig
+//
+//---------------------------------------------------------------------------
+
+boolean P_MorphPlayer(player_t *player)
+{
+	mobj_t *pmo;
+	mobj_t *fog;
+	mobj_t *beastMo;
+	fixed_t x;
+	fixed_t y;
+	fixed_t z;
+	angle_t angle;
+	int oldFlags2;
+
+	if (player->powers[pw_invulnerability])
+	{ // Immune when invulnerable
+		return false;
+	}
+	if (player->morphTics)
+	{ // Player is already a beast
+		return false;
+	}
+	pmo = player->mo;
+	x = pmo->x;
+	y = pmo->y;
+	z = pmo->z;
+	angle = pmo->angle;
+	oldFlags2 = pmo->flags2;
+	P_SetMobjState(pmo, S_FREETARGMOBJ);
+	fog = P_SpawnMobj(x, y, z + TELEFOGHEIGHT, MT_TFOG);
+	S_StartSound(fog, SFX_TELEPORT);
+	beastMo = P_SpawnMobj(x, y, z, MT_PIGPLAYER);
+	beastMo->special1 = player->readyweapon;
+	beastMo->angle = angle;
+	beastMo->player = player;
+	player->health = beastMo->health = MAXMORPHHEALTH;
+	player->mo = beastMo;
+	memset(&player->armorpoints[0], 0, NUMARMOR*sizeof(int));
+	player->playerclass = PCLASS_PIG;
+	if (oldFlags2 & MF2_FLY)
+	{
+		beastMo->flags2 |= MF2_FLY;
+	}
+	player->morphTics = MORPHTICS;
+	P_ActivateMorphWeapon(player);
+	return true;
+}
+
+//---------------------------------------------------------------------------
+//
+// FUNC P_MorphMonster
+//
+//---------------------------------------------------------------------------
+
+static boolean P_MorphMonster(mobj_t *actor)
+{
+	mobj_t *master, *monster, *fog;
+	mobjtype_t moType;
+	fixed_t x;
+	fixed_t y;
+	fixed_t z;
+	mobj_t oldMonster;
+
+	if (actor->player)
+		return false;
+	if (!(actor->flags & MF_COUNTKILL))
+		return false;
+	if (actor->flags2 & MF2_BOSS)
+		return false;
+	moType = actor->type;
+	switch (moType)
+	{
+	case MT_PIG:
+		return false;
+	case MT_FIGHTER_BOSS:
+	case MT_CLERIC_BOSS:
+	case MT_MAGE_BOSS:
+		return false;
+	default:
+		break;
+	}
+
+	oldMonster = *actor;
+	x = oldMonster.x;
+	y = oldMonster.y;
+	z = oldMonster.z;
+	P_RemoveMobjFromTIDList(actor);
+	P_SetMobjState(actor, S_FREETARGMOBJ);
+	fog = P_SpawnMobj(x, y, z+TELEFOGHEIGHT, MT_TFOG);
+	S_StartSound(fog, SFX_TELEPORT);
+	monster = P_SpawnMobj(x, y, z, MT_PIG);
+	monster->special2 = moType;
+	monster->special1 = MORPHTICS + P_Random();
+	monster->flags |= (oldMonster.flags & MF_SHADOW);
+	monster->target = oldMonster.target;
+	monster->angle = oldMonster.angle;
+	monster->tid = oldMonster.tid;
+	monster->special = oldMonster.special;
+	P_InsertMobjIntoTIDList(monster, oldMonster.tid);
+	memcpy(monster->args, oldMonster.args, 5);
+
+	// check for turning off minotaur power for active icon
+	if (moType == MT_MINOTAUR)
+	{
+		master = (mobj_t *)oldMonster.special1;
+		if (master->health > 0)
+		{
+			if (!ActiveMinotaur(master->player))
+			{
+				master->player->powers[pw_minotaur] = 0;
+			}
+		}
+	}
+	return true;
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC P_AutoUseHealth
+//
+//---------------------------------------------------------------------------
+
+static void P_AutoUseHealth(player_t *player, int saveHealth)
+{
+	int i;
+	int count;
+	int normalCount;
+	int normalSlot = 0;
+	int superCount;
+	int superSlot = 0;
+
+	normalCount = superCount = 0;
+	for (i = 0; i < player->inventorySlotNum; i++)
+	{
+		if (player->inventory[i].type == arti_health)
+		{
+			normalSlot = i;
+			normalCount = player->inventory[i].count;
+		}
+		else if (player->inventory[i].type == arti_superhealth)
+		{
+			superSlot = i;
+			superCount = player->inventory[i].count;
+		}
+	}
+	if ((gameskill == sk_baby) && (normalCount*25 >= saveHealth))
+	{ // Use quartz flasks
+		count = (saveHealth + 24) / 25;
+		for (i = 0; i < count; i++)
+		{
+			player->health += 25;
+			P_PlayerRemoveArtifact(player, normalSlot);
+		}
+	}
+	else if (superCount*100 >= saveHealth)
+	{ // Use mystic urns
+		count = (saveHealth + 99) / 100;
+		for (i = 0; i < count; i++)
+		{
+			player->health += 100;
+			P_PlayerRemoveArtifact(player, superSlot);
+		}
+	}
+	else if ((gameskill == sk_baby) &&
+		 (superCount*100 + normalCount*25 >= saveHealth))
+	{ // Use mystic urns and quartz flasks
+		count = (saveHealth + 24) / 25;
+		saveHealth -= count * 25;
+		for (i = 0; i < count; i++)
+		{
+			player->health += 25;
+			P_PlayerRemoveArtifact(player, normalSlot);
+		}
+		count = (saveHealth + 99) / 100;
+		for (i = 0; i < count; i++)
+		{
+			player->health += 100;
+			P_PlayerRemoveArtifact(player, normalSlot);
+		}
+	}
+	player->mo->health = player->health;
+}
+
+/*
+=================
+=
+= P_DamageMobj
+=
+= Damages both enemies and players
+= inflictor is the thing that caused the damage
+= 		creature or missile, can be NULL (slime, etc)
+= source is the thing to target after taking damage
+=		creature or NULL
+= Source and inflictor are the same for melee attacks
+= source can be null for barrel explosions and other environmental stuff
+==================
+*/
+
+void P_DamageMobj (mobj_t *target, mobj_t *inflictor, mobj_t *source, int damage)
+{
+	unsigned int ang;
+	int saved;
+	fixed_t savedPercent;
+	player_t *player;
+	mobj_t *master;
+	fixed_t thrust;
+	int i;
+
+	if (!(target->flags & MF_SHOOTABLE))
+	{
+		// Shouldn't happen
+		return;
+	}
+	if (target->health <= 0)
+	{
+		if (inflictor && inflictor->flags2 & MF2_ICEDAMAGE)
+		{
+			return;
+		}
+		else if (target->flags & MF_ICECORPSE) // frozen
+		{
+			target->tics = 1;
+			target->momx = target->momy = 0;
+		}
+		return;
+	}
+	if ((target->flags2 & MF2_INVULNERABLE) && damage < 10000)
+	{ // mobj is invulnerable
+		if (target->player)
+			return;	// for player, no exceptions
+		if (inflictor)
+		{
+			switch (inflictor->type)
+			{
+			// These inflictors aren't foiled by invulnerability
+			case MT_HOLY_FX:
+			case MT_POISONCLOUD:
+			case MT_FIREBOMB:
+				break;
+			default:
+				return;
+			}
+		}
+		else
+		{
+			return;
+		}
+	}
+	if (target->player)
+	{
+		if (damage < 1000 &&
+			((target->player->cheats & CF_GODMODE) ||
+			 target->player->powers[pw_invulnerability]))
+		{
+			return;
+		}
+	}
+	if (target->flags & MF_SKULLFLY)
+	{
+		target->momx = target->momy = target->momz = 0;
+	}
+	if (target->flags2 & MF2_DORMANT)
+	{
+		// Invulnerable, and won't wake up
+		return;
+	}
+	player = target->player;
+	if (player && gameskill == sk_baby)
+	{
+		// Take half damage in trainer mode
+		damage >>= 1;
+	}
+	// Special damage types
+	if (inflictor)
+	{
+		switch (inflictor->type)
+		{
+		case MT_EGGFX:
+			if (player)
+			{
+				P_MorphPlayer(player);
+			}
+			else
+			{
+				P_MorphMonster(target);
+			}
+			return; // Always return
+		case MT_TELOTHER_FX1:
+		case MT_TELOTHER_FX2:
+		case MT_TELOTHER_FX3:
+		case MT_TELOTHER_FX4:
+		case MT_TELOTHER_FX5:
+			if ((target->flags & MF_COUNTKILL) &&
+				(target->type != MT_SERPENT) &&
+				(target->type != MT_SERPENTLEADER) &&
+				(!(target->flags2 & MF2_BOSS)))
+			{
+				P_TeleportOther(target);
+			}
+			return;
+		case MT_MINOTAUR:
+			if (inflictor->flags & MF_SKULLFLY)
+			{ // Slam only when in charge mode
+				P_MinotaurSlam(inflictor, target);
+				return;
+			}
+			break;
+		case MT_BISH_FX:
+			// Bishops are just too nasty
+			damage >>= 1;
+			break;
+		case MT_SHARDFX1:
+			switch (inflictor->special2)
+			{
+			case 3:
+				damage <<= 3;
+				break;
+			case 2:
+				damage <<= 2;
+				break;
+			case 1:
+				damage <<= 1;
+				break;
+			default:
+				break;
+			}
+			break;
+		case MT_CSTAFF_MISSILE:
+			// Cleric Serpent Staff does poison damage
+			if (target->player)
+			{
+				P_PoisonPlayer(target->player, source, 20);
+				damage >>= 1;
+			}
+			break;
+		case MT_ICEGUY_FX2:
+			damage >>= 1;
+			break;
+		case MT_POISONDART:
+			if (target->player)
+			{
+				P_PoisonPlayer(target->player, source, 20);
+				damage >>= 1;
+			}
+			break;
+		case MT_POISONCLOUD:
+			if (target->player)
+			{
+				if (target->player->poisoncount < 4)
+				{
+					P_PoisonDamage(target->player, source,
+							15 + (P_Random() & 15), false);	// Don't play painsound
+					P_PoisonPlayer(target->player, source, 50);
+					S_StartSound(target, SFX_PLAYER_POISONCOUGH);
+				}
+				return;
+			}
+			else if (!(target->flags & MF_COUNTKILL))
+			{ // only damage monsters/players with the poison cloud
+				return;
+			}
+			break;
+		case MT_FSWORD_MISSILE:
+			if (target->player)
+			{
+				damage -= damage>>2;
+			}
+			break;
+		default:
+			break;
+		}
+	}
+	// Push the target unless source is using the gauntlets
+	if (inflictor && (!source || !source->player) &&
+		!(inflictor->flags2 & MF2_NODMGTHRUST))
+	{
+		ang = R_PointToAngle2(inflictor->x, inflictor->y, target->x, target->y);
+		//thrust = damage*(FRACUNIT>>3)*100/target->info->mass;
+		thrust = damage*(FRACUNIT>>3)*150/target->info->mass;
+		// make fall forwards sometimes
+		if ((damage < 40) && (damage > target->health) &&
+			(target->z-inflictor->z > 64*FRACUNIT) && (P_Random() & 1))
+		{
+			ang += ANG180;
+			thrust *= 4;
+		}
+		ang >>= ANGLETOFINESHIFT;
+		target->momx += FixedMul(thrust, finecosine[ang]);
+		target->momy += FixedMul(thrust, finesine[ang]);
+	}
+
+	//
+	// player specific
+	//
+	if (player)
+	{
+		savedPercent = AutoArmorSave[player->playerclass]
+				+ player->armorpoints[ARMOR_ARMOR]
+				+ player->armorpoints[ARMOR_SHIELD]
+				+ player->armorpoints[ARMOR_HELMET]
+				+ player->armorpoints[ARMOR_AMULET];
+		if (savedPercent)
+		{ // armor absorbed some damage
+			if (savedPercent > 100*FRACUNIT)
+			{
+				savedPercent = 100*FRACUNIT;
+			}
+			for (i = 0; i < NUMARMOR; i++)
+			{
+				if (player->armorpoints[i])
+				{
+					player->armorpoints[i] -= 
+						FixedDiv(FixedMul(damage<<FRACBITS,
+								  ArmorIncrement[player->playerclass][i]),
+							 300 * FRACUNIT);
+					if (player->armorpoints[i] < 2*FRACUNIT)
+					{
+						player->armorpoints[i] = 0;
+					}
+				}
+			}
+			saved = FixedDiv(FixedMul(damage<<FRACBITS, savedPercent), 100 * FRACUNIT);
+			if (saved > savedPercent * 2)
+			{
+				saved = savedPercent * 2;
+			}
+			damage -= saved>>FRACBITS;
+		}
+		if (damage >= player->health &&
+			((gameskill == sk_baby) || deathmatch) &&
+			!player->morphTics)
+		{ // Try to use some inventory health
+			P_AutoUseHealth(player, damage-player->health + 1);
+		}
+		player->health -= damage; // mirror mobj health here for Dave
+		if (player->health < 0)
+		{
+			player->health = 0;
+		}
+		player->attacker = source;
+		player->damagecount += damage; // add damage after armor / invuln
+		if (player->damagecount > 100)
+		{
+			player->damagecount = 100; // teleport stomp does 10k points...
+		}
+		if (player == &players[consoleplayer])
+		{
+#if defined(__WATCOMC__) || defined(__DJGPP__) || defined(__DOS__)
+			int temp = damage < 100 ? damage : 100;
+			I_Tactile(40, 10, 40 + temp*2);
+#endif	/* externdriver, DOS */
+			SB_PaletteFlash(false);
+		}
+	}
+
+	//
+	// do the damage
+	//
+	target->health -= damage;
+	if (target->health <= 0)
+	{ // Death
+		if (inflictor)
+		{ // check for special fire damage or ice damage deaths
+			if (inflictor->flags2 & MF2_FIREDAMAGE)
+			{
+				if (player && !player->morphTics)
+				{ // Check for flame death
+					if (target->health > -50 && damage > 25)
+					{
+						target->flags2 |= MF2_FIREDAMAGE;
+					}
+				}
+				else
+				{
+					target->flags2 |= MF2_FIREDAMAGE;
+				}
+			}
+			else if (inflictor->flags2 & MF2_ICEDAMAGE)
+			{
+				target->flags2 |= MF2_ICEDAMAGE;
+			}
+		}
+		if (source && (source->type == MT_MINOTAUR))
+		{ // Minotaur's kills go to his master
+			master = (mobj_t *)(source->special1);
+			// Make sure still alive and not a pointer to fighter head
+			if (master->player && (master->player->mo == master))
+			{
+				source = master;
+			}
+		}
+		if (source && (source->player) &&
+			(source->player->readyweapon == WP_FOURTH))
+		{
+			// Always extreme death from fourth weapon
+			target->health = -5000;
+		}
+		P_KillMobj(source, target);
+		return;
+	}
+	if ((P_Random() < target->info->painchance)
+		&& !(target->flags & MF_SKULLFLY))
+	{
+		if (inflictor && (inflictor->type >= MT_LIGHTNING_FLOOR
+			&& inflictor->type <= MT_LIGHTNING_ZAP))
+		{
+			if (P_Random() < 96)
+			{
+				target->flags |= MF_JUSTHIT; // fight back!
+				P_SetMobjState(target, target->info->painstate);
+			}
+			else
+			{ // "electrocute" the target
+				target->frame |= FF_FULLBRIGHT;
+				if (target->flags & MF_COUNTKILL && P_Random() < 128 &&
+				    !S_GetSoundPlayingInfo(target, SFX_PUPPYBEAT))
+				{
+					if ((target->type == MT_CENTAUR) ||
+						(target->type == MT_CENTAURLEADER) ||
+						(target->type == MT_ETTIN))
+					{
+						S_StartSound(target, SFX_PUPPYBEAT);
+					}
+				}
+			}
+		}
+		else
+		{
+			target->flags |= MF_JUSTHIT; // fight back!
+			P_SetMobjState(target, target->info->painstate);
+			if (inflictor && inflictor->type == MT_POISONCLOUD)
+			{
+				if (target->flags & MF_COUNTKILL && P_Random() < 128 &&
+				    !S_GetSoundPlayingInfo(target, SFX_PUPPYBEAT))
+				{
+					if ((target->type == MT_CENTAUR) ||
+						(target->type == MT_CENTAURLEADER) ||
+						(target->type == MT_ETTIN))
+					{
+						S_StartSound(target, SFX_PUPPYBEAT);
+					}
+				}
+			}
+		}
+	}
+	target->reactiontime = 0; // we're awake now...
+	if (!target->threshold && source && !(source->flags2 & MF2_BOSS) &&
+	    !(target->type == MT_BISHOP) && !(target->type == MT_MINOTAUR))
+	{
+		// Target actor is not intent on another actor,
+		// so make him chase after source
+		if ((target->type == MT_CENTAUR && source->type == MT_CENTAURLEADER) ||
+		    (target->type == MT_CENTAURLEADER && source->type == MT_CENTAUR))
+		{
+			return;
+		}
+		target->target = source;
+		target->threshold = BASETHRESHOLD;
+		if (target->state == &states[target->info->spawnstate]
+			&& target->info->seestate != S_NULL)
+		{
+			P_SetMobjState(target, target->info->seestate);
+		}
+	}
+}
+
+//==========================================================================
+//
+// P_FallingDamage
+//
+//==========================================================================
+
+void P_FallingDamage(player_t *player)
+{
+	int damage;
+	int mom;
+	int dist;
+
+	mom = abs(player->mo->momz);
+	dist = FixedMul(mom, 16*FRACUNIT/23);
+
+	if (mom >= 63*FRACUNIT)
+	{ // automatic death
+		P_DamageMobj(player->mo, NULL, NULL, 10000);
+		return;
+	}
+	damage = ((FixedMul(dist, dist)/10)>>FRACBITS) - 24;
+	if (player->mo->momz > -39*FRACUNIT && damage > player->mo->health
+		&& player->mo->health != 1)
+	{ // No-death threshold
+		damage = player->mo->health - 1;
+	}
+	S_StartSound(player->mo, SFX_PLAYER_LAND);
+	P_DamageMobj(player->mo, NULL, NULL, damage);
+}
+
+//==========================================================================
+//
+// P_PoisonPlayer - Sets up all data concerning poisoning
+//
+//==========================================================================
+
+void P_PoisonPlayer(player_t *player, mobj_t *poisoner, int poison)
+{
+	if ((player->cheats&CF_GODMODE) || player->powers[pw_invulnerability])
+	{
+		return;
+	}
+	player->poisoncount += poison;
+	player->poisoner = poisoner;
+	if (player->poisoncount > 100)
+	{
+		player->poisoncount = 100;
+	}
+}
+
+//==========================================================================
+//
+// P_PoisonDamage - Similar to P_DamageMobj
+//
+//==========================================================================
+
+void P_PoisonDamage(player_t *player, mobj_t *source, int damage,
+					boolean playPainSound)
+{
+	mobj_t *target;
+	mobj_t *inflictor;
+
+	target = player->mo;
+	inflictor = source;
+	if (target->health <= 0)
+	{
+		return;
+	}
+	if (target->flags2 & MF2_INVULNERABLE && damage < 10000)
+	{ // mobj is invulnerable
+		return;
+	}
+	if (player && gameskill == sk_baby)
+	{
+		// Take half damage in trainer mode
+		damage >>= 1;
+	}
+	if (damage < 1000 && ((player->cheats & CF_GODMODE)
+		|| player->powers[pw_invulnerability]))
+	{
+		return;
+	}
+	if (damage >= player->health
+		&& ((gameskill == sk_baby) || deathmatch)
+		&& !player->morphTics)
+	{ // Try to use some inventory health
+		P_AutoUseHealth(player, damage-player->health + 1);
+	}
+	player->health -= damage; // mirror mobj health here for Dave
+	if (player->health < 0)
+	{
+		player->health = 0;
+	}
+	player->attacker = source;
+
+	//
+	// do the damage
+	//
+	target->health -= damage;
+	if (target->health <= 0)
+	{ // Death
+		target->special1 = damage;
+		if (player && inflictor && !player->morphTics)
+		{ // Check for flame death
+			if ((inflictor->flags2 & MF2_FIREDAMAGE)
+				&& (target->health > -50) && (damage > 25))
+			{
+				target->flags2 |= MF2_FIREDAMAGE;
+			}
+			if (inflictor->flags2 & MF2_ICEDAMAGE)
+			{
+				target->flags2 |= MF2_ICEDAMAGE;
+			}
+		}
+		P_KillMobj(source, target);
+		return;
+	}
+	if (!(leveltime & 63) && playPainSound)
+	{
+		P_SetMobjState(target, target->info->painstate);
+	}
+	/*
+	if ((P_Random() < target->info->painchance)
+		&& !(target->flags & MF_SKULLFLY))
+	{
+		target->flags |= MF_JUSTHIT; // fight back!
+		P_SetMobjState(target, target->info->painstate);
+	}
+	*/
+}
+
--- /dev/null
+++ b/p_lights.c
@@ -1,0 +1,345 @@
+
+//**************************************************************************
+//**
+//** p_lights.c : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 491 $
+//** $Date: 2009-05-30 01:10:42 +0300 (Sat, 30 May 2009) $
+//**
+//**************************************************************************
+
+#include "h2stdinc.h"
+#include "h2def.h"
+#include "p_local.h"
+
+//============================================================================
+//
+//	T_Light
+//
+//============================================================================
+
+void T_Light(light_t *light)
+{
+	if (light->count)
+	{
+		light->count--;
+		return;
+	}
+	switch (light->type)
+	{
+	case LITE_FADE:
+		light->sector->lightlevel = ((light->sector->lightlevel<<FRACBITS)
+							+ light->value2)>>FRACBITS;
+		if (light->tics2 == 1)
+		{
+			if (light->sector->lightlevel >= light->value1)
+			{
+				light->sector->lightlevel = light->value1;
+				P_RemoveThinker(&light->thinker);
+			}
+		}
+		else if (light->sector->lightlevel <= light->value1)
+		{
+			light->sector->lightlevel = light->value1;
+			P_RemoveThinker(&light->thinker);
+		}
+		break;
+	case LITE_GLOW:
+		light->sector->lightlevel = ((light->sector->lightlevel<<FRACBITS)
+							+ light->tics1)>>FRACBITS;
+		if (light->tics2 == 1)
+		{
+			if (light->sector->lightlevel >= light->value1)
+			{
+				light->sector->lightlevel = light->value1;
+				light->tics1 = -light->tics1;
+				light->tics2 = -1; // reverse direction
+			}
+		}
+		else if (light->sector->lightlevel <= light->value2)
+		{
+			light->sector->lightlevel = light->value2;
+			light->tics1 = -light->tics1;
+			light->tics2 = 1; // reverse direction
+		}
+		break;
+	case LITE_FLICKER:
+		if (light->sector->lightlevel == light->value1)
+		{
+			light->sector->lightlevel = light->value2;
+			light->count = (P_Random() & 7) + 1;
+		}
+		else
+		{
+			light->sector->lightlevel = light->value1;
+			light->count = (P_Random() & 31) + 1;
+		}
+		break;
+	case LITE_STROBE:
+		if (light->sector->lightlevel == light->value1)
+		{
+			light->sector->lightlevel = light->value2;
+			light->count = light->tics2;
+		}
+		else
+		{
+			light->sector->lightlevel = light->value1;
+			light->count = light->tics1;
+		}
+		break;
+	default:
+		break;
+	}
+}
+
+//============================================================================
+//
+//	EV_SpawnLight
+//
+//============================================================================
+
+boolean EV_SpawnLight(line_t *line, byte *arg, lighttype_t type)
+{
+	light_t *light;
+	sector_t *sec;
+	int secNum;
+	int arg1, arg2, arg3, arg4;
+	boolean think;
+	boolean rtn;
+
+	arg1 = arg[1];
+	arg2 = arg[2];
+	arg3 = arg[3];
+	arg4 = arg[4];
+
+	secNum = -1;
+	rtn = false;
+	think = false;
+	while ((secNum = P_FindSectorFromTag(arg[0], secNum)) >= 0)
+	{
+		think = false;
+		sec = &sectors[secNum];
+
+		light = (light_t *)Z_Malloc(sizeof(light_t), PU_LEVSPEC, NULL);
+		light->type = type;
+		light->sector = sec;
+		light->count = 0;
+		rtn = true;
+		switch (type)
+		{
+		case LITE_RAISEBYVALUE:
+			sec->lightlevel += arg1;
+			if (sec->lightlevel > 255)
+			{
+				sec->lightlevel = 255;
+			}
+			break;
+		case LITE_LOWERBYVALUE:
+			sec->lightlevel -= arg1;
+			if (sec->lightlevel < 0)
+			{
+				sec->lightlevel = 0;
+			}
+			break;
+		case LITE_CHANGETOVALUE:
+			sec->lightlevel = arg1;
+			if (sec->lightlevel < 0)
+			{
+				sec->lightlevel = 0;
+			}
+			else if (sec->lightlevel > 255)
+			{
+				sec->lightlevel = 255;
+			}
+			break;
+		case LITE_FADE:
+			think = true;
+			light->value1 = arg1; // destination lightlevel
+			light->value2 = FixedDiv((arg1 - sec->lightlevel)<<FRACBITS, arg2<<FRACBITS);  // delta lightlevel
+			if (sec->lightlevel <= arg1)
+			{
+				light->tics2 = 1; // get brighter
+			}
+			else
+			{
+				light->tics2 = -1;
+			}
+			break;
+		case LITE_GLOW:
+			think = true;
+			light->value1 = arg1; // upper lightlevel
+			light->value2 = arg2; // lower lightlevel
+			light->tics1 = FixedDiv((arg1 - sec->lightlevel)<<FRACBITS, arg3<<FRACBITS);  // lightlevel delta
+			if (sec->lightlevel <= arg1)
+			{
+				light->tics2 = 1; // get brighter
+			}
+			else
+			{
+				light->tics2 = -1;
+			}
+			break;
+		case LITE_FLICKER:
+			think = true;
+			light->value1 = arg1; // upper lightlevel
+			light->value2 = arg2; // lower lightlevel
+			sec->lightlevel = light->value1;
+			light->count = (P_Random() & 64) + 1;
+			break;
+		case LITE_STROBE:
+			think = true;
+			light->value1 = arg1; // upper lightlevel
+			light->value2 = arg2; // lower lightlevel
+			light->tics1 = arg3;  // upper tics
+			light->tics2 = arg4;  // lower tics
+			light->count = arg3;
+			sec->lightlevel = light->value1;
+			break;
+		default:
+			rtn = false;
+			break;
+		}
+		if (think)
+		{
+			P_AddThinker(&light->thinker);
+			light->thinker.function = T_Light;
+		}
+		else
+		{
+			Z_Free(light);
+		}
+	}
+	return rtn;
+}
+
+//============================================================================
+//
+//	T_Phase
+//
+//============================================================================
+
+static int PhaseTable[64] =
+{
+	128, 112, 96, 80, 64, 48, 32, 32,
+	16, 16, 16, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 16, 16, 16,
+	32, 32, 48, 64, 80, 96, 112, 128
+};
+
+void T_Phase(phase_t *phase)
+{
+	phase->index = (phase->index + 1) & 63;
+	phase->sector->lightlevel = phase->base + PhaseTable[phase->index];
+}
+
+//==========================================================================
+//
+// P_SpawnPhasedLight
+//
+//==========================================================================
+
+void P_SpawnPhasedLight(sector_t *sector, int base, int idx)
+{
+	phase_t	*phase;
+
+	phase = (phase_t *) Z_Malloc(sizeof(*phase), PU_LEVSPEC, NULL);
+	P_AddThinker(&phase->thinker);
+	phase->sector = sector;
+	if (idx == -1)
+	{ // sector->lightlevel as the index
+		phase->index = sector->lightlevel & 63;
+	}
+	else
+	{
+		phase->index = idx & 63;
+	}
+	phase->base = base & 255;
+	sector->lightlevel = phase->base + PhaseTable[phase->index];
+	phase->thinker.function = T_Phase;
+
+	sector->special = 0;
+}
+
+//==========================================================================
+//
+// P_SpawnLightSequence
+//
+//==========================================================================
+
+void P_SpawnLightSequence(sector_t *sector, int indexStep)
+{
+	sector_t *sec;
+	sector_t *nextSec;
+	sector_t *tempSec;
+	int seqSpecial;
+	int i;
+	int count;
+	fixed_t idx;
+	fixed_t indexDelta;
+	int base;
+
+	seqSpecial = LIGHT_SEQUENCE; // look for Light_Sequence, first
+	sec = sector;
+	count = 1;
+	do
+	{
+		nextSec = NULL;
+		sec->special = LIGHT_SEQUENCE_START; // make sure that the search doesn't back up.
+		for (i = 0; i < sec->linecount; i++)
+		{
+			tempSec = getNextSector(sec->lines[i], sec);
+			if (!tempSec)
+			{
+				continue;
+			}
+			if (tempSec->special == seqSpecial)
+			{
+				if (seqSpecial == LIGHT_SEQUENCE)
+				{
+					seqSpecial = LIGHT_SEQUENCE_ALT;
+				}
+				else
+				{
+					seqSpecial = LIGHT_SEQUENCE;
+				}
+				nextSec = tempSec;
+				count++;
+			}
+		}
+		sec = nextSec;
+	} while (sec);
+
+	sec = sector;
+	count *= indexStep;
+	idx = 0;
+	indexDelta = FixedDiv(64*FRACUNIT, count*FRACUNIT);
+	base = sector->lightlevel;
+	do
+	{
+		nextSec = NULL;
+		if (sec->lightlevel)
+		{
+			base = sec->lightlevel;
+		}
+		P_SpawnPhasedLight(sec, base, idx>>FRACBITS);
+		idx += indexDelta;
+		for (i = 0; i < sec->linecount; i++)
+		{
+			tempSec = getNextSector(sec->lines[i], sec);
+			if (!tempSec)
+			{
+				continue;
+			}
+			if (tempSec->special == LIGHT_SEQUENCE_START)
+			{
+				nextSec = tempSec;
+			}
+		}
+		sec = nextSec;
+	} while (sec);
+}
+
--- /dev/null
+++ b/p_local.h
@@ -1,0 +1,378 @@
+
+//**************************************************************************
+//**
+//** p_local.h : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 373 $
+//** $Date: 2009-05-19 21:14:28 +0300 (Tue, 19 May 2009) $
+//**
+//**************************************************************************
+
+#ifndef __P_LOCAL__
+#define __P_LOCAL__
+
+#ifndef __R_LOCAL__
+#include "r_local.h"
+#endif
+
+#define STARTREDPALS	1
+#define STARTBONUSPALS	9
+#define STARTPOISONPALS	13
+#define STARTICEPAL	21
+#define STARTHOLYPAL	22
+#define STARTSCOURGEPAL	25
+#define NUMREDPALS	8
+#define NUMBONUSPALS	4
+#define NUMPOISONPALS	8
+
+#define TOCENTER	-8
+#define FLOATSPEED	(FRACUNIT * 4)
+
+#define MAXHEALTH	100
+#define MAXMORPHHEALTH	30
+#define VIEWHEIGHT	(48 * FRACUNIT)
+
+/* mapblocks are used to check movement against lines and things */
+#define MAPBLOCKUNITS	128
+#define MAPBLOCKSIZE	(MAPBLOCKUNITS * FRACUNIT)
+#define MAPBLOCKSHIFT	(FRACBITS + 7)
+#define MAPBMASK	(MAPBLOCKSIZE - 1)
+#define MAPBTOFRAC	(MAPBLOCKSHIFT - FRACBITS)
+
+/* player radius for movement checking */
+#define PLAYERRADIUS	(16 * FRACUNIT)
+
+/* MAXRADIUS is for precalculated sector block boxes
+ * the spider demon is larger, but we don't have any
+ * moving sectors nearby
+ */
+#define MAXRADIUS	(32 * FRACUNIT)
+
+#define GRAVITY		FRACUNIT
+#define MAXMOVE		(30 * FRACUNIT)
+
+#define USERANGE	(64 * FRACUNIT)
+#define MELEERANGE	(64 * FRACUNIT)
+#define MISSILERANGE	(32 * 64 * FRACUNIT)
+
+typedef enum
+{
+	DI_EAST,
+	DI_NORTHEAST,
+	DI_NORTH,
+	DI_NORTHWEST,
+	DI_WEST,
+	DI_SOUTHWEST,
+	DI_SOUTH,
+	DI_SOUTHEAST,
+	DI_NODIR,
+	NUMDIRS
+} dirtype_t;
+
+#define BASETHRESHOLD	100	/* follow a player exlusively for 3 seconds */
+
+
+/* ---- P_TICK ---- */
+
+extern	thinker_t	thinkercap;	/* both the head and tail of the thinker list */
+extern	int		TimerGame;	/* tic countdown for deathmatch */
+
+void P_InitThinkers(void);
+void P_AddThinker(thinker_t *thinker);
+void P_RemoveThinker(thinker_t *thinker);
+
+
+/* ---- P_PSPR ---- */
+
+#define USE_MANA1	1
+#define USE_MANA2	1
+
+void P_SetPsprite(player_t *player, int position, statenum_t stnum);
+void P_SetPspriteNF(player_t *player, int position, statenum_t stnum);
+void P_SetupPsprites(player_t *curplayer);
+void P_MovePsprites(player_t *curplayer);
+void P_DropWeapon(player_t *player);
+void P_ActivateMorphWeapon(player_t *player);
+void P_PostMorphWeapon(player_t *player, weapontype_t weapon);
+
+
+/* ---- P_USER ---- */
+
+extern	int		PStateNormal[NUMCLASSES];
+extern	int		PStateRun[NUMCLASSES];
+extern	int		PStateAttack[NUMCLASSES];
+extern	int		PStateAttackEnd[NUMCLASSES];
+
+void P_PlayerThink(player_t *player);
+void P_Thrust(player_t *player, angle_t angle, fixed_t move);
+void P_PlayerRemoveArtifact(player_t *player, int slot);
+void P_PlayerUseArtifact(player_t *player, artitype_t arti);
+boolean P_UseArtifact(player_t *player, artitype_t arti);
+int P_GetPlayerNum(player_t *player);
+void P_TeleportOther(mobj_t *victim);
+void ResetBlasted(mobj_t *mo);
+
+
+/* ---- P_MOBJ ---- */
+
+/* Any floor type >= FLOOR_LIQUID will floorclip sprites */
+enum
+{
+	FLOOR_SOLID,
+	FLOOR_ICE,
+	FLOOR_LIQUID,
+	FLOOR_WATER,
+	FLOOR_LAVA,
+	FLOOR_SLUDGE
+};
+
+#define ONFLOORZ	H2MININT
+#define ONCEILINGZ	H2MAXINT
+#define FLOATRANDZ	(H2MAXINT - 1)
+#define FROMCEILINGZ128	(H2MAXINT - 2)
+
+extern	mobjtype_t	PuffType;
+extern	mobj_t		*MissileMobj;
+
+mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type);
+void P_RemoveMobj(mobj_t *th);
+boolean P_SetMobjState(mobj_t *mobj, statenum_t state);
+boolean P_SetMobjStateNF(mobj_t *mobj, statenum_t state);
+void P_ThrustMobj(mobj_t *mo, angle_t angle, fixed_t move);
+int P_FaceMobj(mobj_t *source, mobj_t *target, angle_t *delta);
+boolean P_SeekerMissile(mobj_t *actor, angle_t thresh, angle_t turnMax);
+void P_MobjThinker(mobj_t *mobj);
+void P_BlasterMobjThinker(mobj_t *mobj);
+void P_SpawnPuff(fixed_t x, fixed_t y, fixed_t z);
+void P_SpawnBlood(fixed_t x, fixed_t y, fixed_t z, int damage);
+void P_BloodSplatter(fixed_t x, fixed_t y, fixed_t z, mobj_t *originator);
+void P_BloodSplatter2(fixed_t x, fixed_t y, fixed_t z, mobj_t *originator);
+void P_RipperBlood(mobj_t *mo);
+int P_GetThingFloorType(mobj_t *thing);
+int P_HitFloor(mobj_t *thing);
+boolean P_CheckMissileSpawn(mobj_t *missile);
+mobj_t *P_SpawnMissile(mobj_t *source, mobj_t *dest, mobjtype_t type);
+mobj_t *P_SpawnMissileXYZ(fixed_t x, fixed_t y, fixed_t z, mobj_t *source, mobj_t *dest, mobjtype_t type);
+mobj_t *P_SpawnMissileAngle(mobj_t *source, mobjtype_t type, angle_t angle, fixed_t momz);
+mobj_t *P_SpawnMissileAngleSpeed(mobj_t *source, mobjtype_t type, angle_t angle, fixed_t momz, fixed_t speed);
+mobj_t *P_SpawnPlayerMissile(mobj_t *source, mobjtype_t type);
+mobj_t *P_SPMAngle(mobj_t *source, mobjtype_t type, angle_t angle);
+mobj_t *P_SPMAngleXYZ(mobj_t *source, fixed_t x, fixed_t y, fixed_t z, mobjtype_t type, angle_t angle);
+void P_CreateTIDList(void);
+void P_RemoveMobjFromTIDList(mobj_t *mobj);
+void P_InsertMobjIntoTIDList(mobj_t *mobj, int tid);
+mobj_t *P_FindMobjFromTID(int tid, int *searchPosition);
+mobj_t *P_SpawnKoraxMissile(fixed_t x, fixed_t y, fixed_t z, mobj_t *source, mobj_t *dest, mobjtype_t type);
+
+
+/* ---- P_ENEMY ---- */
+
+void P_NoiseAlert (mobj_t *target, mobj_t *emmiter);
+int P_Massacre(void);
+boolean A_RaiseMobj(mobj_t *actor);
+boolean A_SinkMobj(mobj_t *actor);
+void A_NoBlocking(mobj_t *actor);
+void P_InitCreatureCorpseQueue(boolean corpseScan);
+void A_DeQueueCorpse(mobj_t *actor);
+
+
+/* ---- P_MAPUTL ---- */
+
+typedef struct
+{
+	fixed_t	x, y, dx, dy;
+} divline_t;
+
+#ifdef RENDER3D
+typedef struct
+{
+	float	x, y, dx, dy;
+} fdivline_t;
+#endif
+
+typedef struct
+{
+	fixed_t		frac;	/* along trace line */
+	boolean		isaline;
+	union {
+		mobj_t	*thing;
+		line_t	*line;
+	} d;
+} intercept_t;
+
+#define MAXINTERCEPTS	128
+extern	intercept_t	intercepts[MAXINTERCEPTS], *intercept_p;
+
+typedef boolean (*traverser_t) (intercept_t *in);
+
+fixed_t P_AproxDistance (fixed_t dx, fixed_t dy);
+int P_PointOnLineSide (fixed_t x, fixed_t y, line_t *line);
+int P_PointOnDivlineSide (fixed_t x, fixed_t y, divline_t *line);
+void P_MakeDivline (line_t *li, divline_t *dl);
+fixed_t P_InterceptVector (divline_t *v2, divline_t *v1);
+int P_BoxOnLineSide (fixed_t *tmbox, line_t *ld);
+
+extern	fixed_t		opentop, openbottom, openrange;
+extern	fixed_t		lowfloor;
+
+void P_LineOpening (line_t *ld);
+
+boolean P_BlockLinesIterator (int x, int y, boolean(*func)(line_t*));
+boolean P_BlockThingsIterator (int x, int y, boolean(*func)(mobj_t*));
+
+#define PT_ADDLINES	1
+#define PT_ADDTHINGS	2
+#define PT_EARLYOUT	4
+
+extern	divline_t	trace;
+
+boolean P_PathTraverse (fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2, int flags, boolean (*trav) (intercept_t *));
+void P_UnsetThingPosition (mobj_t *thing);
+void P_SetThingPosition (mobj_t *thing);
+mobj_t *P_RoughMonsterSearch(mobj_t *mo, int distance);
+
+
+/* ---- P_MAP ---- */
+
+extern	boolean		floatok;		/* if true, move would be ok if */
+extern	fixed_t		tmfloorz, tmceilingz;	/* within tmfloorz - tmceilingz */
+extern	int		tmfloorpic;
+extern	mobj_t		*BlockingMobj;
+extern	line_t		*ceilingline;
+extern	mobj_t		*PuffSpawned;		/* true if a puff was spawned */
+extern	mobj_t		*linetarget;		/* who got hit (or NULL) */
+
+boolean P_TestMobjLocation(mobj_t *mobj);
+boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y);
+mobj_t *P_CheckOnmobj(mobj_t *thing);
+void P_FakeZMovement(mobj_t *mo);
+boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y);
+boolean P_TeleportMove(mobj_t *thing, fixed_t x, fixed_t y);
+void P_SlideMove(mobj_t *mo);
+void P_BounceWall(mobj_t *mo);
+boolean P_CheckSight(mobj_t *t1, mobj_t *t2);
+void P_UseLines(player_t *player);
+boolean P_UsePuzzleItem(player_t *player, int itemType);
+void PIT_ThrustSpike(mobj_t *actor);
+boolean P_ChangeSector (sector_t *sector, int crunch);
+fixed_t P_AimLineAttack (mobj_t *t1, angle_t angle, fixed_t distance);
+void P_LineAttack (mobj_t *t1, angle_t angle, fixed_t distance, fixed_t slope, int damage);
+void P_RadiusAttack (mobj_t *spot, mobj_t *source, int damage, int distance, boolean damageSource);
+
+
+/* ---- P_SETUP ---- */
+
+extern	byte		*rejectmatrix;		/* for fast sight rejection */
+extern	short		*blockmaplump;		/* offsets in blockmap are from here */
+extern	short		*blockmap;
+extern	int		bmapwidth, bmapheight;	/* in mapblocks */
+extern	fixed_t		bmaporgx, bmaporgy;	/* origin of block map */
+extern	mobj_t		**blocklinks;		/* for thing chains */
+
+
+/* ---- P_INTER ---- */
+
+extern	int		clipmana[NUMMANA];
+
+void P_SetMessage(player_t *player, const char *message, boolean ultmsg);
+void P_SetYellowMessage(player_t *player, const char *message, boolean ultmsg);
+void P_ClearMessage(player_t *player);
+void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher);
+void P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, int damage);
+void P_FallingDamage(player_t *player);
+void P_PoisonPlayer(player_t *player, mobj_t *poisoner, int poison);
+void P_PoisonDamage(player_t *player, mobj_t *source, int damage, boolean playPainSound);
+boolean P_GiveMana(player_t *player, manatype_t mana, int count);
+boolean P_GiveArtifact(player_t *player, artitype_t arti, mobj_t *mo);
+boolean P_GiveArmor(player_t *player, armortype_t armortype, int amount);
+boolean P_GiveBody(player_t *player, int num);
+boolean P_GivePower(player_t *player, powertype_t power);
+boolean P_MorphPlayer(player_t *player);
+
+
+/* ---- AM_MAP ---- */
+
+boolean AM_Responder(event_t *ev);
+void AM_Ticker(void);
+void AM_Drawer(void);
+
+
+/* ---- A_ACTION ---- */
+
+boolean A_LocalQuake(byte *args, mobj_t *victim);
+void P_SpawnDirt(mobj_t *actor, fixed_t radius);
+void A_BridgeRemove(mobj_t *actor);
+
+
+/* ---- SB_BAR ---- */
+
+extern	int		SB_state;
+extern	int		ArtifactFlash;
+
+void SB_PaletteFlash(boolean forceChange);
+
+
+/* ---- PO_MAN ---- */
+
+typedef enum
+{
+	PODOOR_NONE,
+	PODOOR_SLIDE,
+	PODOOR_SWING
+} podoortype_t;
+
+typedef struct
+{
+	thinker_t thinker;
+	int polyobj;
+	int speed;
+	unsigned int dist;
+	int angle;
+	fixed_t xSpeed;	/* for sliding walls */
+	fixed_t ySpeed;
+} polyevent_t;
+
+typedef struct
+{
+	thinker_t thinker;
+	int polyobj;
+	int speed;
+	int dist;
+	int totalDist;
+	int direction;
+	fixed_t xSpeed, ySpeed;
+	int tics;
+	int waitTics;
+	podoortype_t type;
+	boolean close;
+} polydoor_t;
+
+enum
+{
+	PO_ANCHOR_TYPE = 3000,
+	PO_SPAWN_TYPE,
+	PO_SPAWNCRUSH_TYPE
+};
+
+#define PO_LINE_START		1	/* polyobj line start special */
+#define PO_LINE_EXPLICIT	5
+
+extern	polyobj_t	*polyobjs;	/* list of all poly-objects on the level */
+extern	int		po_NumPolyobjs;
+
+void T_PolyDoor(polydoor_t *pd);
+void T_RotatePoly(polyevent_t *pe);
+boolean EV_RotatePoly(line_t *line, byte *args, int direction, boolean overRide);
+void T_MovePoly(polyevent_t *pe);
+boolean EV_MovePoly(line_t *line, byte *args, boolean timesEight, boolean overRide);
+boolean EV_OpenPolyDoor(line_t *line, byte *args, podoortype_t type);
+
+boolean PO_MovePolyobj(int num, int x, int y);
+boolean PO_RotatePolyobj(int num, angle_t angle);
+void PO_Init(int lump);
+boolean PO_Busy(int polyobj);
+
+#include "p_spec.h"
+
+#endif	/* __P_LOCAL__ */
+
--- /dev/null
+++ b/p_map.c
@@ -1,0 +1,2325 @@
+
+//**************************************************************************
+//**
+//** p_map.c : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 373 $
+//** $Date: 2009-05-19 21:14:28 +0300 (Tue, 19 May 2009) $
+//**
+//**************************************************************************
+
+#include "h2stdinc.h"
+#include "h2def.h"
+#include "p_local.h"
+#include "soundst.h"
+
+/*
+===============================================================================
+
+NOTES:
+
+===============================================================================
+*/
+
+/*
+===============================================================================
+
+mobj_t NOTES
+
+mobj_ts are used to tell the refresh where to draw an image, tell the world
+simulation when objects are contacted, and tell the sound driver how to
+position a sound.
+
+The refresh uses the next and prev links to follow lists of things in sectors
+as they are being drawn.  The sprite, frame, and angle elements determine
+which patch_t is used to draw the sprite if it is visible.  The sprite and
+frame values are allmost allways set from state_t structures.
+The statescr.exe utility generates the states.h and states.c files that contain
+the sprite/frame numbers from the statescr.txt source file.  The xyz origin
+point represents a point at the bottom middle of the sprite (between the feet
+of a biped).  This is the default origin position for patch_ts grabbed with
+lumpy.exe. A walking creature will have its z equal to the floor it is standing
+on.
+
+The sound code uses the x,y, and subsector fields to do stereo positioning of
+any sound effited by the mobj_t.
+
+The play simulation uses the blocklinks, x,y,z, radius, height to determine
+when mobj_ts are touching each other, touching lines in the map, or hit by
+trace lines (gunshots, lines of sight, etc). The mobj_t->flags element has
+various bit flags used by the simulation.
+
+Every mobj_t is linked into a single sector based on it's origin coordinates.
+The subsector_t is found with R_PointInSubsector(x,y), and the sector_t can be
+found with subsector->sector.  The sector links are only used by the rendering
+code,  the play simulation does not care about them at all.
+
+Any mobj_t that needs to be acted upon be something else in the play world
+(block movement, be shot, etc) will also need to be linked into the blockmap.
+If the thing has the MF_NOBLOCK flag set, it will not use the block links.
+It can still interact with other things, but only as the instigator (missiles
+will run into other things, but nothing can run into a missile).   Each block
+in the grid is 128*128 units, and knows about every line_t that it contains a
+piece of, and every interactable mobj_t that has it's origin contained.
+
+A valid mobj_t is a mobj_t that has the proper subsector_t filled in for it's
+xy coordinates and is linked into the subsector's sector or has the MF_NOSECTOR
+flag set (the subsector_t needs to be valid even if MF_NOSECTOR is set), and is
+linked into a blockmap block or has the MF_NOBLOCKMAP flag set.  Links should
+only be modified by the P_[Un]SetThingPosition () functions.  Do not change the
+MF_NO? flags while a thing is valid.
+
+===============================================================================
+*/
+
+extern mobj_t		LavaInflictor;
+
+extern fixed_t		topslope, bottomslope;	/* slopes to top and bottom of target */
+
+static fixed_t		tmbbox[4];
+static mobj_t		*tmthing;
+static mobj_t		*tsthing;
+static int		tmflags;
+static fixed_t		tmx, tmy;
+
+static mobj_t		*onmobj;	/* used for landing on pods/players */
+
+mobj_t			*BlockingMobj;
+
+boolean			floatok;	/* if true, move would be ok if */
+					/* within tmfloorz - tmceilingz */
+
+fixed_t			tmfloorz, tmceilingz, tmdropoffz;
+int			tmfloorpic;
+
+line_t			*ceilingline;	/* keep track of the line that lowers the ceiling, */
+					/* so missiles don't explode against sky hack walls */
+
+#define MAXSPECIALCROSS		8
+line_t		*spechit[MAXSPECIALCROSS];	/* keep track of special lines as they are hit, */
+int			numspechit;	/* but don't process them until the move is proven valid */
+
+
+static void CheckForPushSpecial(line_t *line, int side, mobj_t *mobj);
+
+
+/*
+===============================================================================
+
+					TELEPORT MOVE
+
+===============================================================================
+*/
+
+/*
+==================
+=
+= PIT_StompThing
+=
+==================
+*/
+
+static boolean PIT_StompThing (mobj_t *thing)
+{
+	fixed_t		blockdist;
+
+	if (!(thing->flags & MF_SHOOTABLE) )
+		return true;
+
+	blockdist = thing->radius + tmthing->radius;
+	if ( abs(thing->x - tmx) >= blockdist || abs(thing->y - tmy) >= blockdist )
+		return true;		// didn't hit it
+
+	if (thing == tmthing)
+		return true;		// don't clip against self
+
+	if (!(tmthing->flags2 & MF2_TELESTOMP))
+	{ // Not allowed to stomp things
+		return false;
+	}
+
+	P_DamageMobj (thing, tmthing, tmthing, 10000);
+
+	return true;
+}
+
+
+/*
+===================
+=
+= P_TeleportMove
+=
+===================
+*/
+
+boolean P_TeleportMove (mobj_t *thing, fixed_t x, fixed_t y)
+{
+	int		xl, xh, yl, yh, bx, by;
+	subsector_t		*newsubsec;
+
+//
+// kill anything occupying the position
+//
+
+	tmthing = thing;
+	tmflags = thing->flags;
+
+	tmx = x;
+	tmy = y;
+
+	tmbbox[BOXTOP] = y + tmthing->radius;
+	tmbbox[BOXBOTTOM] = y - tmthing->radius;
+	tmbbox[BOXRIGHT] = x + tmthing->radius;
+	tmbbox[BOXLEFT] = x - tmthing->radius;
+
+	newsubsec = R_PointInSubsector (x, y);
+	ceilingline = NULL;
+
+//
+// the base floor / ceiling is from the subsector that contains the
+// point.  Any contacted lines the step closer together will adjust them
+//
+	tmfloorz = tmdropoffz = newsubsec->sector->floorheight;
+	tmceilingz = newsubsec->sector->ceilingheight;
+	tmfloorpic = newsubsec->sector->floorpic;
+
+	validcount++;
+	numspechit = 0;
+
+//
+// stomp on any things contacted
+//
+	xl = (tmbbox[BOXLEFT] - bmaporgx - MAXRADIUS)>>MAPBLOCKSHIFT;
+	xh = (tmbbox[BOXRIGHT] - bmaporgx + MAXRADIUS)>>MAPBLOCKSHIFT;
+	yl = (tmbbox[BOXBOTTOM] - bmaporgy - MAXRADIUS)>>MAPBLOCKSHIFT;
+	yh = (tmbbox[BOXTOP] - bmaporgy + MAXRADIUS)>>MAPBLOCKSHIFT;
+
+	for (bx = xl; bx <= xh; bx++)
+	{
+		for (by = yl; by <= yh; by++)
+		{
+			if (!P_BlockThingsIterator(bx, by, PIT_StompThing))
+				return false;
+		}
+	}
+
+//
+// the move is ok, so link the thing into its new position
+//
+	P_UnsetThingPosition (thing);
+
+	thing->floorz = tmfloorz;
+	thing->ceilingz = tmceilingz;
+	thing->x = x;
+	thing->y = y;
+
+	P_SetThingPosition (thing);
+
+	return true;
+}
+
+
+static boolean PIT_ThrustStompThing (mobj_t *thing)
+{
+	fixed_t		blockdist;
+
+	if (!(thing->flags & MF_SHOOTABLE) )
+		return true;
+
+	blockdist = thing->radius + tsthing->radius;
+	if ( abs(thing->x - tsthing->x) >= blockdist || 
+			abs(thing->y - tsthing->y) >= blockdist ||
+			(thing->z > tsthing->z + tsthing->height) )
+		return true;		// didn't hit it
+
+	if (thing == tsthing)
+		return true;		// don't clip against self
+
+	P_DamageMobj (thing, tsthing, tsthing, 10001);
+	tsthing->args[1] = 1;	// Mark thrust thing as bloody
+
+	return true;
+}
+
+
+void PIT_ThrustSpike(mobj_t *actor)
+{
+	int	xl, xh, yl, yh, bx, by;
+	int	x0, x2, y0, y2;
+
+	tsthing = actor;
+
+	x0 = actor->x - actor->info->radius;
+	x2 = actor->x + actor->info->radius;
+	y0 = actor->y - actor->info->radius;
+	y2 = actor->y + actor->info->radius;
+
+	xl = (x0 - bmaporgx - MAXRADIUS)>>MAPBLOCKSHIFT;
+	xh = (x2 - bmaporgx + MAXRADIUS)>>MAPBLOCKSHIFT;
+	yl = (y0 - bmaporgy - MAXRADIUS)>>MAPBLOCKSHIFT;
+	yh = (y2 - bmaporgy + MAXRADIUS)>>MAPBLOCKSHIFT;
+
+	// stomp on any things contacted
+	for (bx = xl; bx <= xh; bx++)
+	{
+		for (by = yl; by <= yh; by++)
+			P_BlockThingsIterator(bx, by, PIT_ThrustStompThing);
+	}
+}
+
+
+/*
+===============================================================================
+
+					MOVEMENT ITERATOR FUNCTIONS
+
+===============================================================================
+*/
+
+/*
+==================
+=
+= PIT_CheckLine
+=
+= Adjusts tmfloorz and tmceilingz as lines are contacted
+==================
+*/
+
+static boolean PIT_CheckLine(line_t *ld)
+{
+	if (tmbbox[BOXRIGHT] <= ld->bbox[BOXLEFT]
+		|| tmbbox[BOXLEFT] >= ld->bbox[BOXRIGHT]
+		|| tmbbox[BOXTOP] <= ld->bbox[BOXBOTTOM]
+		|| tmbbox[BOXBOTTOM] >= ld->bbox[BOXTOP])
+	{
+		return true;
+	}
+	if (P_BoxOnLineSide(tmbbox, ld) != -1)
+	{
+		return true;
+	}
+
+// a line has been hit
+/*
+= The moving thing's destination position will cross the given line.
+= If this should not be allowed, return false.
+= If the line is special, keep track of it to process later if the move
+= is proven ok.  NOTE: specials are NOT sorted by order, so two special
+= lines that are only 8 pixels apart could be crossed in either order.
+*/
+	if (!ld->backsector)
+	{ // One sided line
+		if (tmthing->flags2 & MF2_BLASTED)
+		{
+			P_DamageMobj(tmthing, NULL, NULL, tmthing->info->mass>>5);
+		}
+		CheckForPushSpecial(ld, 0, tmthing);
+		return false;
+	}
+	if (!(tmthing->flags & MF_MISSILE))
+	{
+		if (ld->flags & ML_BLOCKING)
+		{ // Explicitly blocking everything
+			if (tmthing->flags2 & MF2_BLASTED)
+			{
+				P_DamageMobj(tmthing, NULL, NULL, tmthing->info->mass>>5);
+			}
+			CheckForPushSpecial(ld, 0, tmthing);
+			return false;
+		}
+		if (!tmthing->player && ld->flags & ML_BLOCKMONSTERS)
+		{ // Block monsters only
+			if (tmthing->flags2 & MF2_BLASTED)
+			{
+				P_DamageMobj(tmthing, NULL, NULL, tmthing->info->mass>>5);
+			}
+			return false;
+		}
+	}
+	P_LineOpening(ld);		// set openrange, opentop, openbottom
+	// adjust floor / ceiling heights
+	if (opentop < tmceilingz)
+	{
+		tmceilingz = opentop;
+		ceilingline = ld;
+	}
+	if (openbottom > tmfloorz)
+	{
+		tmfloorz = openbottom;
+	}
+	if (lowfloor < tmdropoffz)
+	{
+		tmdropoffz = lowfloor;
+	}
+	if (ld->special)
+	{ // Contacted a special line, add it to the list
+		spechit[numspechit] = ld;
+		numspechit++;
+	}
+	return true;
+}
+
+//---------------------------------------------------------------------------
+//
+// FUNC PIT_CheckThing
+//
+//---------------------------------------------------------------------------
+
+static boolean PIT_CheckThing(mobj_t *thing)
+{
+	fixed_t blockdist;
+	boolean solid;
+	int damage;
+
+	if (!(thing->flags & (MF_SOLID|MF_SPECIAL|MF_SHOOTABLE)))
+	{ // Can't hit thing
+		return true;
+	}
+	blockdist = thing->radius + tmthing->radius;
+	if (abs(thing->x - tmx) >= blockdist || abs(thing->y - tmy) >= blockdist)
+	{ // Didn't hit thing
+		return true;
+	}
+	if (thing == tmthing)
+	{ // Don't clip against self
+		return true;
+	}
+	BlockingMobj = thing;
+	if (tmthing->flags2 & MF2_PASSMOBJ)
+	{ // check if a mobj passed over/under another object
+		if (tmthing->type == MT_BISHOP && thing->type == MT_BISHOP)
+		{ // don't let bishops fly over other bishops
+			return false;
+		}
+		if (tmthing->z >= thing->z + thing->height
+			&& !(thing->flags & MF_SPECIAL))
+		{
+			return true;
+		}
+		else if (tmthing->z + tmthing->height < thing->z
+			&& !(thing->flags & MF_SPECIAL))
+		{ // under thing
+			return true;
+		}
+	}
+	// Check for skulls slamming into things
+	if (tmthing->flags & MF_SKULLFLY)
+	{
+		if (tmthing->type == MT_MINOTAUR)
+		{
+			// Slamming minotaurs shouldn't move non-creatures
+			if (!(thing->flags & MF_COUNTKILL))
+			{
+				return false;
+			}
+		}
+		else if (tmthing->type == MT_HOLY_FX)
+		{
+			if (thing->flags & MF_SHOOTABLE && thing != tmthing->target)
+			{
+				if (netgame && !deathmatch && thing->player)
+				{ // don't attack other co-op players
+					return true;
+				}
+				if (thing->flags2 & MF2_REFLECTIVE
+					&& (thing->player || thing->flags2 & MF2_BOSS))
+				{
+					tmthing->special1 = (intptr_t)tmthing->target;
+					tmthing->target = thing;
+					return true;
+				}
+				if (thing->flags & MF_COUNTKILL || thing->player)
+				{
+					tmthing->special1 = (intptr_t)thing;
+				}
+				if (P_Random() < 96)
+				{
+					damage = 12;
+					if (thing->player || thing->flags2 & MF2_BOSS)
+					{
+						damage = 3;
+						// ghost burns out faster when attacking players/bosses
+						tmthing->health -= 6;
+					}
+					P_DamageMobj(thing, tmthing, tmthing->target, damage);
+					if (P_Random() < 128)
+					{
+						P_SpawnMobj(tmthing->x, tmthing->y, tmthing->z,
+										MT_HOLY_PUFF);
+						S_StartSound(tmthing, SFX_SPIRIT_ATTACK);
+						if (thing->flags & MF_COUNTKILL && P_Random() < 128
+						    && !S_GetSoundPlayingInfo(thing, SFX_PUPPYBEAT))
+						{
+							if ((thing->type == MT_CENTAUR) ||
+								(thing->type == MT_CENTAURLEADER) ||
+								(thing->type == MT_ETTIN))
+							{
+								S_StartSound(thing, SFX_PUPPYBEAT);
+							}
+						}
+					}
+				}
+				if (thing->health <= 0)
+				{
+					tmthing->special1 = 0;
+				}
+			}
+			return true;
+		}
+		damage = ((P_Random() % 8) + 1) * tmthing->damage;
+		P_DamageMobj(thing, tmthing, tmthing, damage);
+		tmthing->flags &= ~MF_SKULLFLY;
+		tmthing->momx = tmthing->momy = tmthing->momz = 0;
+		P_SetMobjState(tmthing, tmthing->info->seestate);
+		return false;
+	}
+	// Check for blasted thing running into another
+	if (tmthing->flags2 & MF2_BLASTED && thing->flags & MF_SHOOTABLE)
+	{
+		if (!(thing->flags2 & MF2_BOSS) &&
+			(thing->flags & MF_COUNTKILL))
+		{
+			thing->momx += tmthing->momx;
+			thing->momy += tmthing->momy;
+			if ((thing->momx + thing->momy) > 3*FRACUNIT)
+			{
+				damage = (tmthing->info->mass/100) + 1;
+				P_DamageMobj(thing, tmthing, tmthing, damage);
+				damage = (thing->info->mass/100) + 1;
+				P_DamageMobj(tmthing, thing, thing, damage>>2);
+			}
+			return false;
+		}
+	}
+	// Check for missile
+	if (tmthing->flags & MF_MISSILE)
+	{
+		// Check for a non-shootable mobj
+		if (thing->flags2 & MF2_NONSHOOTABLE)
+		{
+			return true;
+		}
+		// Check if it went over / under
+		if (tmthing->z > thing->z + thing->height)
+		{ // Over thing
+			return true;
+		}
+		if (tmthing->z + tmthing->height < thing->z)
+		{ // Under thing
+			return true;
+		}
+		if (tmthing->flags2 & MF2_FLOORBOUNCE)
+		{
+			if (tmthing->target == thing || !(thing->flags & MF_SOLID))
+			{
+				return true;
+			}
+			else
+			{
+				return false;
+			}
+		}
+		if (tmthing->type == MT_LIGHTNING_FLOOR
+			|| tmthing->type == MT_LIGHTNING_CEILING)
+		{
+			if (thing->flags & MF_SHOOTABLE && thing != tmthing->target)
+			{
+				if (thing->info->mass != H2MAXINT)
+				{
+					thing->momx += tmthing->momx>>4;
+					thing->momy += tmthing->momy>>4;
+				}
+				if ((!thing->player && !(thing->flags2 & MF2_BOSS))
+					|| !(leveltime & 1))
+				{
+					if (thing->type == MT_CENTAUR || thing->type == MT_CENTAURLEADER)
+					{ // Lightning does more damage to centaurs
+						P_DamageMobj(thing, tmthing, tmthing->target, 9);
+					}
+					else
+					{
+						P_DamageMobj(thing, tmthing, tmthing->target, 3);
+					}
+					if (!(S_GetSoundPlayingInfo(tmthing, SFX_MAGE_LIGHTNING_ZAP)))
+					{
+						S_StartSound(tmthing, SFX_MAGE_LIGHTNING_ZAP);
+					}
+					if (thing->flags & MF_COUNTKILL && P_Random() < 64 
+						&& !S_GetSoundPlayingInfo(thing, SFX_PUPPYBEAT))
+					{
+						if ((thing->type == MT_CENTAUR) ||
+							(thing->type == MT_CENTAURLEADER) ||
+							(thing->type == MT_ETTIN))
+						{
+							S_StartSound(thing, SFX_PUPPYBEAT);
+						}
+					}
+				}
+				tmthing->health--;
+				if (tmthing->health <= 0 || thing->health <= 0)
+				{
+					return false;
+				}
+				if (tmthing->type == MT_LIGHTNING_FLOOR)
+				{
+					if (tmthing->special2 
+						&& !((mobj_t *)tmthing->special2)->special1)
+					{
+						((mobj_t *)tmthing->special2)->special1 = (intptr_t)thing;
+					}
+				}
+				else if (!tmthing->special1)
+				{
+					tmthing->special1 = (intptr_t)thing;
+				}
+			}
+			return true;	// lightning zaps through all sprites
+		}
+		else if (tmthing->type == MT_LIGHTNING_ZAP)
+		{
+			mobj_t *lmo;
+
+			if (thing->flags & MF_SHOOTABLE && thing != tmthing->target)
+			{
+				lmo = (mobj_t *)tmthing->special2;
+				if (lmo)
+				{
+					if (lmo->type == MT_LIGHTNING_FLOOR)
+					{
+						if (lmo->special2 
+							&& !((mobj_t *)lmo->special2)->special1)
+						{
+							((mobj_t *)lmo->special2)->special1 = (intptr_t)thing;
+						}
+					}
+					else if (!lmo->special1)
+					{
+						lmo->special1 = (intptr_t)thing;
+					}
+					if (!(leveltime & 3))
+					{
+						lmo->health--;
+					}
+				}
+			}
+		}
+		else if (tmthing->type == MT_MSTAFF_FX2 && thing != tmthing->target)
+		{
+			if (!thing->player && !(thing->flags2 & MF2_BOSS))
+			{
+				switch (thing->type)
+				{
+				case MT_FIGHTER_BOSS:	// these not flagged boss
+				case MT_CLERIC_BOSS:	// so they can be blasted
+				case MT_MAGE_BOSS:
+					break;
+				default:
+					P_DamageMobj(thing, tmthing, tmthing->target, 10);
+					return true;
+				}
+			}
+		}
+		if (tmthing->target && tmthing->target->type == thing->type)
+		{ // Don't hit same species as originator
+			if (thing == tmthing->target)
+			{ // Don't missile self
+				return true;
+			}
+			if (!thing->player)
+			{ // Hit same species as originator, explode, no damage
+				return false;
+			}
+		}
+		if (!(thing->flags & MF_SHOOTABLE))
+		{ // Didn't do any damage
+			return !(thing->flags & MF_SOLID);
+		}
+		if (tmthing->flags2 & MF2_RIP)
+		{
+			if (!(thing->flags & MF_NOBLOOD) &&
+				!(thing->flags2 & MF2_REFLECTIVE) &&
+				!(thing->flags2 & MF2_INVULNERABLE))
+			{ // Ok to spawn some blood
+				P_RipperBlood(tmthing);
+			}
+			//S_StartSound(tmthing, sfx_ripslop);
+			damage = ((P_Random() & 3) + 2) * tmthing->damage;
+			P_DamageMobj(thing, tmthing, tmthing->target, damage);
+			if (thing->flags2 & MF2_PUSHABLE
+				&& !(tmthing->flags2 & MF2_CANNOTPUSH))
+			{ // Push thing
+				thing->momx += tmthing->momx>>2;
+				thing->momy += tmthing->momy>>2;
+			}
+			numspechit = 0;
+			return true;
+		}
+		// Do damage
+		damage = ((P_Random() % 8) + 1) * tmthing->damage;
+		if (damage)
+		{
+			if (!(thing->flags & MF_NOBLOOD) && 
+				!(thing->flags2 & MF2_REFLECTIVE) &&
+				!(thing->flags2 & MF2_INVULNERABLE) &&
+				!(tmthing->type == MT_TELOTHER_FX1) &&
+				!(tmthing->type == MT_TELOTHER_FX2) &&
+				!(tmthing->type == MT_TELOTHER_FX3) &&
+				!(tmthing->type == MT_TELOTHER_FX4) &&
+				!(tmthing->type == MT_TELOTHER_FX5) &&
+				(P_Random() < 192))
+			{
+				P_BloodSplatter(tmthing->x, tmthing->y, tmthing->z, thing);
+			}
+			P_DamageMobj(thing, tmthing, tmthing->target, damage);
+		}
+		return false;
+	}
+	if (thing->flags2 & MF2_PUSHABLE && !(tmthing->flags2 & MF2_CANNOTPUSH))
+	{ // Push thing
+		thing->momx += tmthing->momx>>2;
+		thing->momy += tmthing->momy>>2;
+	}
+	// Check for special thing
+	if (thing->flags & MF_SPECIAL)
+	{
+		solid = thing->flags & MF_SOLID;
+		if (tmflags & MF_PICKUP)
+		{ // Can be picked up by tmthing
+			P_TouchSpecialThing(thing, tmthing);	// Can remove thing
+		}
+		return !solid;
+	}
+	return !(thing->flags & MF_SOLID);
+}
+
+//---------------------------------------------------------------------------
+//
+// PIT_CheckOnmobjZ
+//
+//---------------------------------------------------------------------------
+
+static boolean PIT_CheckOnmobjZ(mobj_t *thing)
+{
+	fixed_t blockdist;
+
+	if (!(thing->flags & (MF_SOLID|MF_SPECIAL|MF_SHOOTABLE)))
+	{ // Can't hit thing
+		return true;
+	}
+	blockdist = thing->radius + tmthing->radius;
+	if (abs(thing->x - tmx) >= blockdist || abs(thing->y - tmy) >= blockdist)
+	{ // Didn't hit thing
+		return true;
+	}
+	if (thing == tmthing)
+	{ // Don't clip against self
+		return true;
+	}
+	if (tmthing->z > thing->z + thing->height)
+	{
+		return true;
+	}
+	else if (tmthing->z + tmthing->height < thing->z)
+	{ // under thing
+		return true;
+	}
+	if (thing->flags & MF_SOLID)
+	{
+		onmobj = thing;
+	}
+	return !(thing->flags & MF_SOLID);
+}
+
+/*
+===============================================================================
+
+						MOVEMENT CLIPPING
+
+===============================================================================
+*/
+
+//----------------------------------------------------------------------------
+//
+// FUNC P_TestMobjLocation
+//
+// Returns true if the mobj is not blocked by anything at its current
+// location, otherwise returns false.
+//
+//----------------------------------------------------------------------------
+
+boolean P_TestMobjLocation(mobj_t *mobj)
+{
+	int flags;
+
+	flags = mobj->flags;
+	mobj->flags &= ~MF_PICKUP;
+	if (P_CheckPosition(mobj, mobj->x, mobj->y))
+	{ // XY is ok, now check Z
+		mobj->flags = flags;
+		if ((mobj->z < mobj->floorz)
+			|| (mobj->z + mobj->height > mobj->ceilingz))
+		{ // Bad Z
+			return false;
+		}
+		return true;
+	}
+	mobj->flags = flags;
+	return false;
+}
+
+/*
+==================
+=
+= P_CheckPosition
+=
+= This is purely informative, nothing is modified (except things picked up)
+
+in:
+a mobj_t (can be valid or invalid)
+a position to be checked (doesn't need to be related to the mobj_t->x,y)
+
+during:
+special things are touched if MF_PICKUP
+early out on solid lines?
+
+out:
+newsubsec
+floorz
+ceilingz
+tmdropoffz = the lowest point contacted (monsters won't move to a dropoff)
+speciallines[]
+numspeciallines
+mobj_t *BlockingMobj = pointer to thing that blocked position (NULL if not
+blocked, or blocked by a line).
+
+==================
+*/
+
+boolean P_CheckPosition (mobj_t *thing, fixed_t x, fixed_t y)
+{
+	int		xl, xh, yl, yh, bx, by;
+	subsector_t		*newsubsec;
+
+	tmthing = thing;
+	tmflags = thing->flags;
+
+	tmx = x;
+	tmy = y;
+
+	tmbbox[BOXTOP] = y + tmthing->radius;
+	tmbbox[BOXBOTTOM] = y - tmthing->radius;
+	tmbbox[BOXRIGHT] = x + tmthing->radius;
+	tmbbox[BOXLEFT] = x - tmthing->radius;
+
+	newsubsec = R_PointInSubsector (x, y);
+	ceilingline = NULL;
+
+//
+// the base floor / ceiling is from the subsector that contains the
+// point.  Any contacted lines the step closer together will adjust them
+//
+	tmfloorz = tmdropoffz = newsubsec->sector->floorheight;
+	tmceilingz = newsubsec->sector->ceilingheight;
+	tmfloorpic = newsubsec->sector->floorpic;
+
+	validcount++;
+	numspechit = 0;
+
+	if (tmflags & MF_NOCLIP && !(tmflags & MF_SKULLFLY))
+	{
+		return true;
+	}
+
+//
+// check things first, possibly picking things up
+// the bounding box is extended by MAXRADIUS because mobj_ts are grouped
+// into mapblocks based on their origin point, and can overlap into adjacent
+// blocks by up to MAXRADIUS units
+//
+	xl = (tmbbox[BOXLEFT] - bmaporgx - MAXRADIUS)>>MAPBLOCKSHIFT;
+	xh = (tmbbox[BOXRIGHT] - bmaporgx + MAXRADIUS)>>MAPBLOCKSHIFT;
+	yl = (tmbbox[BOXBOTTOM] - bmaporgy - MAXRADIUS)>>MAPBLOCKSHIFT;
+	yh = (tmbbox[BOXTOP] - bmaporgy + MAXRADIUS)>>MAPBLOCKSHIFT;
+
+	BlockingMobj = NULL;
+	for (bx = xl; bx <= xh; bx++)
+	{
+		for (by = yl; by <= yh; by++)
+		{
+			if (!P_BlockThingsIterator(bx, by, PIT_CheckThing))
+				return false;
+		}
+	}
+//
+// check lines
+//
+	if (tmflags & MF_NOCLIP)
+	{
+		return true;
+	}
+
+	BlockingMobj = NULL;
+	xl = (tmbbox[BOXLEFT] - bmaporgx)>>MAPBLOCKSHIFT;
+	xh = (tmbbox[BOXRIGHT] - bmaporgx)>>MAPBLOCKSHIFT;
+	yl = (tmbbox[BOXBOTTOM] - bmaporgy)>>MAPBLOCKSHIFT;
+	yh = (tmbbox[BOXTOP] - bmaporgy)>>MAPBLOCKSHIFT;
+
+	for (bx = xl; bx <= xh; bx++)
+	{
+		for (by = yl; by <= yh; by++)
+		{
+			if (!P_BlockLinesIterator (bx, by, PIT_CheckLine))
+				return false;
+		}
+	}
+	return true;
+}
+
+//=============================================================================
+//
+// P_CheckOnmobj(mobj_t *thing)
+//
+// Checks if the new Z position is legal
+//=============================================================================
+
+mobj_t *P_CheckOnmobj(mobj_t *thing)
+{
+	int		xl, xh, yl, yh, bx, by;
+	subsector_t		*newsubsec;
+	fixed_t				x;
+	fixed_t				y;
+	mobj_t			oldmo;
+
+	x = thing->x;
+	y = thing->y;
+	tmthing = thing;
+	tmflags = thing->flags;
+	oldmo = *thing; // save the old mobj before the fake zmovement
+	P_FakeZMovement(tmthing);
+
+	tmx = x;
+	tmy = y;
+
+	tmbbox[BOXTOP] = y + tmthing->radius;
+	tmbbox[BOXBOTTOM] = y - tmthing->radius;
+	tmbbox[BOXRIGHT] = x + tmthing->radius;
+	tmbbox[BOXLEFT] = x - tmthing->radius;
+
+	newsubsec = R_PointInSubsector (x, y);
+	ceilingline = NULL;
+
+//
+// the base floor / ceiling is from the subsector that contains the
+// point.  Any contacted lines the step closer together will adjust them
+//
+	tmfloorz = tmdropoffz = newsubsec->sector->floorheight;
+	tmceilingz = newsubsec->sector->ceilingheight;
+	tmfloorpic = newsubsec->sector->floorpic;
+
+	validcount++;
+	numspechit = 0;
+
+	if (tmflags & MF_NOCLIP)
+		return NULL;
+
+//
+// check things first, possibly picking things up
+// the bounding box is extended by MAXRADIUS because mobj_ts are grouped
+// into mapblocks based on their origin point, and can overlap into adjacent
+// blocks by up to MAXRADIUS units
+//
+	xl = (tmbbox[BOXLEFT] - bmaporgx - MAXRADIUS)>>MAPBLOCKSHIFT;
+	xh = (tmbbox[BOXRIGHT] - bmaporgx + MAXRADIUS)>>MAPBLOCKSHIFT;
+	yl = (tmbbox[BOXBOTTOM] - bmaporgy - MAXRADIUS)>>MAPBLOCKSHIFT;
+	yh = (tmbbox[BOXTOP] - bmaporgy + MAXRADIUS)>>MAPBLOCKSHIFT;
+
+	for (bx = xl; bx <= xh; bx++)
+	{
+		for (by = yl; by <= yh; by++)
+		{
+			if (!P_BlockThingsIterator(bx, by, PIT_CheckOnmobjZ))
+			{
+				*tmthing = oldmo;
+				return onmobj;
+			}
+		}
+	}
+	*tmthing = oldmo;
+	return NULL;
+}
+
+//=============================================================================
+//
+// P_FakeZMovement
+//
+// Fake the zmovement so that we can check if a move is legal
+//=============================================================================
+
+void P_FakeZMovement(mobj_t *mo)
+{
+	int dist;
+	int delta;
+//
+// adjust height
+//
+	mo->z += mo->momz;
+	if (mo->flags & MF_FLOAT && mo->target)
+	{	// float down towards target if too close
+		if (!(mo->flags & MF_SKULLFLY) && !(mo->flags & MF_INFLOAT))
+		{
+			dist = P_AproxDistance(mo->x - mo->target->x, mo->y - mo->target->y);
+			delta = (mo->target->z + (mo->height >> 1) ) - mo->z;
+			if (delta < 0 && dist < -(delta*3))
+				mo->z -= FLOATSPEED;
+			else if (delta > 0 && dist < (delta*3))
+				mo->z += FLOATSPEED;
+		}
+	}
+	if (mo->player && mo->flags2 & MF2_FLY && !(mo->z <= mo->floorz)
+		&& leveltime & 2)
+	{
+		mo->z += finesine[(FINEANGLES/20*leveltime>>2) & FINEMASK];
+	}
+
+//
+// clip movement
+//
+	if (mo->z <= mo->floorz)
+	{ // Hit the floor
+		mo->z = mo->floorz;
+		if (mo->momz < 0)
+		{
+			mo->momz = 0;
+		}
+		if (mo->flags & MF_SKULLFLY)
+		{ // The skull slammed into something
+			mo->momz = -mo->momz;
+		}
+		if (mo->info->crashstate && (mo->flags & MF_CORPSE))
+		{
+			return;
+		}
+	}
+	else if (mo->flags2 & MF2_LOGRAV)
+	{
+		if (mo->momz == 0)
+			mo->momz = -(GRAVITY>>3)*2;
+		else
+			mo->momz -= GRAVITY>>3;
+	}
+	else if (! (mo->flags & MF_NOGRAVITY) )
+	{
+		if (mo->momz == 0)
+			mo->momz = -GRAVITY*2;
+		else
+			mo->momz -= GRAVITY;
+	}
+
+	if (mo->z + mo->height > mo->ceilingz)
+	{	// hit the ceiling
+		if (mo->momz > 0)
+			mo->momz = 0;
+		mo->z = mo->ceilingz - mo->height;
+		if (mo->flags & MF_SKULLFLY)
+		{	// the skull slammed into something
+			mo->momz = -mo->momz;
+		}
+	}
+}
+
+//===========================================================================
+//
+// CheckForPushSpecial
+//
+//===========================================================================
+
+static void CheckForPushSpecial(line_t *line, int side, mobj_t *mobj)
+{
+	if (line->special)
+	{
+		if (mobj->flags2 & MF2_PUSHWALL)
+		{
+			P_ActivateLine(line, mobj, side, SPAC_PUSH);
+		}
+		else if (mobj->flags2 & MF2_IMPACT)
+		{
+			P_ActivateLine(line, mobj, side, SPAC_IMPACT);
+		}
+	}
+}
+
+/*
+===================
+=
+= P_TryMove
+=
+= Attempt to move to a new position, crossing special lines unless MF_TELEPORT
+= is set
+=
+===================
+*/
+
+boolean P_TryMove (mobj_t *thing, fixed_t x, fixed_t y)
+{
+	fixed_t		oldx, oldy;
+	int		side, oldside;
+	line_t		*ld;
+
+	floatok = false;
+	if (!P_CheckPosition(thing, x, y))
+	{ // Solid wall or thing
+		if (!BlockingMobj || BlockingMobj->player || !thing->player)
+		{
+			goto pushline;
+		}
+		else if (BlockingMobj->z + BlockingMobj->height - thing->z > 24*FRACUNIT
+			|| (BlockingMobj->subsector->sector->ceilingheight -
+				(BlockingMobj->z + BlockingMobj->height) < thing->height)
+			|| (tmceilingz - (BlockingMobj->z + BlockingMobj->height) < thing->height))
+		{
+			goto pushline;
+		}
+	}
+	if (!(thing->flags & MF_NOCLIP))
+	{
+		if (tmceilingz - tmfloorz < thing->height)
+		{ // Doesn't fit
+			goto pushline;
+		}
+		floatok = true;
+		if (!(thing->flags & MF_TELEPORT)
+			&& tmceilingz - thing->z < thing->height
+			&& thing->type != MT_LIGHTNING_CEILING
+			&& !(thing->flags2 & MF2_FLY))
+		{ // mobj must lower itself to fit
+			goto pushline;
+		}
+		if (thing->flags2 & MF2_FLY)
+		{
+			if (thing->z + thing->height > tmceilingz)
+			{
+				thing->momz = -8*FRACUNIT;
+				goto pushline;
+			}
+			else if (thing->z < tmfloorz && tmfloorz - tmdropoffz > 24*FRACUNIT)
+			{
+				thing->momz = 8*FRACUNIT;
+				goto pushline;
+			}
+		}
+		if (!(thing->flags & MF_TELEPORT)
+			// The Minotaur floor fire (MT_MNTRFX2) can step up any amount
+			&& thing->type != MT_MNTRFX2 && thing->type != MT_LIGHTNING_FLOOR
+			&& tmfloorz - thing->z > 24*FRACUNIT)
+		{
+			goto pushline;
+		}
+		if (!(thing->flags & (MF_DROPOFF|MF_FLOAT)) && 
+			(tmfloorz - tmdropoffz > 24*FRACUNIT) &&
+			!(thing->flags2 & MF2_BLASTED))
+		{ // Can't move over a dropoff unless it's been blasted
+				return false;
+		}
+		if (thing->flags2 & MF2_CANTLEAVEFLOORPIC &&
+		    (tmfloorpic != thing->subsector->sector->floorpic || tmfloorz-thing->z != 0))
+		{ // must stay within a sector of a certain floor type
+			return false;
+		}
+	}
+
+//
+// the move is ok, so link the thing into its new position
+//
+	P_UnsetThingPosition (thing);
+
+	oldx = thing->x;
+	oldy = thing->y;
+	thing->floorz = tmfloorz;
+	thing->ceilingz = tmceilingz;
+	thing->floorpic = tmfloorpic;
+	thing->x = x;
+	thing->y = y;
+
+	P_SetThingPosition (thing);
+
+	if (thing->flags2 & MF2_FLOORCLIP)
+	{
+		if (thing->z == thing->subsector->sector->floorheight
+			&& P_GetThingFloorType(thing) >= FLOOR_LIQUID)
+		{
+			thing->floorclip = 10*FRACUNIT;
+		}
+		else 
+		{
+			thing->floorclip = 0;
+		}
+	}
+
+//
+// if any special lines were hit, do the effect
+//
+	if (! (thing->flags & (MF_TELEPORT|MF_NOCLIP)) )
+	{
+		while (numspechit > 0)
+		{
+			numspechit--;
+			// see if the line was crossed
+			ld = spechit[numspechit];
+			side = P_PointOnLineSide (thing->x, thing->y, ld);
+			oldside = P_PointOnLineSide (oldx, oldy, ld);
+			if (side != oldside)
+			{
+				if (ld->special)
+				{
+					if (thing->player)
+					{
+						P_ActivateLine(ld, thing, oldside, SPAC_CROSS);
+					}
+					else if (thing->flags2 & MF2_MCROSS)
+					{
+						P_ActivateLine(ld, thing, oldside, SPAC_MCROSS);
+					}
+					else if (thing->flags2 & MF2_PCROSS)
+					{
+						P_ActivateLine(ld, thing, oldside, SPAC_PCROSS);
+					}
+				}
+			}
+		}
+	}
+	return true;
+
+pushline:
+	if (!(thing->flags & (MF_TELEPORT|MF_NOCLIP)))
+	{
+		int numSpecHitTemp;
+
+		if (tmthing->flags2 & MF2_BLASTED)
+		{
+			P_DamageMobj(tmthing, NULL, NULL, tmthing->info->mass>>5);
+		}
+		numSpecHitTemp = numspechit;
+		while (numSpecHitTemp > 0)
+		{
+			numSpecHitTemp--;
+			// see if the line was crossed
+			ld = spechit[numSpecHitTemp];
+			side = P_PointOnLineSide (thing->x, thing->y, ld);
+			CheckForPushSpecial(ld, side, thing);
+		}
+	}
+	return false;
+}
+
+/*
+==================
+=
+= P_ThingHeightClip
+=
+= Takes a valid thing and adjusts the thing->floorz, thing->ceilingz,
+= anf possibly thing->z
+=
+= This is called for all nearby monsters whenever a sector changes height
+=
+= If the thing doesn't fit, the z will be set to the lowest value and
+= false will be returned
+==================
+*/
+
+static boolean P_ThingHeightClip (mobj_t *thing)
+{
+	boolean		onfloor;
+
+	onfloor = (thing->z == thing->floorz);
+
+	P_CheckPosition (thing, thing->x, thing->y);
+	// what about stranding a monster partially off an edge?
+
+	thing->floorz = tmfloorz;
+	thing->ceilingz = tmceilingz;
+	thing->floorpic = tmfloorpic;
+
+	if (onfloor)
+	{ // walking monsters rise and fall with the floor
+		if ((thing->z-thing->floorz < 9*FRACUNIT)
+			|| (thing->flags & MF_NOGRAVITY))
+		{
+			thing->z = thing->floorz;
+		}
+	}
+	else
+	{	// don't adjust a floating monster unless forced to
+		if (thing->z + thing->height > thing->ceilingz)
+			thing->z = thing->ceilingz - thing->height;
+	}
+
+	if (thing->ceilingz - thing->floorz < thing->height)
+		return false;
+
+	return true;
+}
+
+
+/*
+==============================================================================
+
+							SLIDE MOVE
+
+Allows the player to slide along any angled walls
+
+==============================================================================
+*/
+
+static fixed_t		bestslidefrac, secondslidefrac;
+static line_t		*bestslideline, *secondslideline;
+static mobj_t		*slidemo;
+
+static fixed_t		tmxmove, tmymove;
+
+/*
+==================
+=
+= P_HitSlideLine
+=
+= Adjusts the xmove / ymove so that the next move will slide along the wall
+==================
+*/
+
+static void P_HitSlideLine (line_t *ld)
+{
+	int			side;
+	angle_t		lineangle, moveangle, deltaangle;
+	fixed_t		movelen, newlen;
+
+	if (ld->slopetype == ST_HORIZONTAL)
+	{
+		tmymove = 0;
+		return;
+	}
+	if (ld->slopetype == ST_VERTICAL)
+	{
+		tmxmove = 0;
+		return;
+	}
+
+	side = P_PointOnLineSide (slidemo->x, slidemo->y, ld);
+
+	lineangle = R_PointToAngle2 (0, 0, ld->dx, ld->dy);
+	if (side == 1)
+		lineangle += ANG180;
+	moveangle = R_PointToAngle2 (0, 0, tmxmove, tmymove);
+	deltaangle = moveangle - lineangle;
+	if (deltaangle > ANG180)
+		deltaangle += ANG180;
+//		I_Error ("SlideLine: ang>ANG180");
+
+	lineangle >>= ANGLETOFINESHIFT;
+	deltaangle >>= ANGLETOFINESHIFT;
+
+	movelen = P_AproxDistance (tmxmove, tmymove);
+	newlen = FixedMul (movelen, finecosine[deltaangle]);
+	tmxmove = FixedMul (newlen, finecosine[lineangle]);
+	tmymove = FixedMul (newlen, finesine[lineangle]);
+}
+
+/*
+==============
+=
+= PTR_SlideTraverse
+=
+==============
+*/
+
+static boolean PTR_SlideTraverse (intercept_t *in)
+{
+	line_t	*li;
+
+	if (!in->isaline)
+		I_Error ("PTR_SlideTraverse: not a line?");
+
+	li = in->d.line;
+	if (! (li->flags & ML_TWOSIDED))
+	{
+		if (P_PointOnLineSide (slidemo->x, slidemo->y, li))
+			return true;		// don't hit the back side
+		goto isblocking;
+	}
+
+	P_LineOpening (li);		// set openrange, opentop, openbottom
+	if (openrange < slidemo->height)
+		goto isblocking;		// doesn't fit
+
+	if (opentop - slidemo->z < slidemo->height)
+		goto isblocking;		// mobj is too high
+
+	if (openbottom - slidemo->z > 24*FRACUNIT )
+		goto isblocking;		// too big a step up
+
+	return true;		// this line doesn't block movement
+
+// the line does block movement, see if it is closer than best so far
+isblocking:
+	if (in->frac < bestslidefrac)
+	{
+		secondslidefrac = bestslidefrac;
+		secondslideline = bestslideline;
+		bestslidefrac = in->frac;
+		bestslideline = li;
+	}
+
+	return false;	// stop
+}
+
+
+/*
+==================
+=
+= P_SlideMove
+=
+= The momx / momy move is bad, so try to slide along a wall
+=
+= Find the first line hit, move flush to it, and slide along it
+=
+= This is a kludgy mess.
+==================
+*/
+
+void P_SlideMove (mobj_t *mo)
+{
+	fixed_t		leadx, leady;
+	fixed_t		trailx, traily;
+	fixed_t		newx, newy;
+	int		hitcount;
+
+	slidemo = mo;
+	hitcount = 0;
+retry:
+	if (++hitcount == 3)
+		goto stairstep;			// don't loop forever
+
+//
+// trace along the three leading corners
+//
+	if (mo->momx > 0)
+	{
+		leadx = mo->x + mo->radius;
+		trailx = mo->x - mo->radius;
+	}
+	else
+	{
+		leadx = mo->x - mo->radius;
+		trailx = mo->x + mo->radius;
+	}
+
+	if (mo->momy > 0)
+	{
+		leady = mo->y + mo->radius;
+		traily = mo->y - mo->radius;
+	}
+	else
+	{
+		leady = mo->y - mo->radius;
+		traily = mo->y + mo->radius;
+	}
+
+	bestslidefrac = FRACUNIT + 1;
+
+	P_PathTraverse(leadx, leady, leadx + mo->momx, leady + mo->momy,
+					PT_ADDLINES, PTR_SlideTraverse);
+	P_PathTraverse(trailx, leady, trailx + mo->momx, leady + mo->momy,
+					PT_ADDLINES, PTR_SlideTraverse);
+	P_PathTraverse(leadx, traily, leadx + mo->momx, traily + mo->momy,
+					PT_ADDLINES, PTR_SlideTraverse);
+
+//
+// move up to the wall
+//
+	if (bestslidefrac == FRACUNIT + 1)
+	{ // the move must have hit the middle, so stairstep
+stairstep:
+		if (!P_TryMove(mo, mo->x, mo->y + mo->momy))
+		{
+			P_TryMove(mo, mo->x + mo->momx, mo->y);
+		}
+		return;
+	}
+
+	bestslidefrac -= 0x800;	// fudge a bit to make sure it doesn't hit
+	if (bestslidefrac > 0)
+	{
+		newx = FixedMul (mo->momx, bestslidefrac);
+		newy = FixedMul (mo->momy, bestslidefrac);
+		if (!P_TryMove (mo, mo->x + newx, mo->y + newy))
+			goto stairstep;
+	}
+
+//
+// now continue along the wall
+//
+	bestslidefrac = FRACUNIT - (bestslidefrac + 0x800);	// remainder
+	if (bestslidefrac > FRACUNIT)
+		bestslidefrac = FRACUNIT;
+	if (bestslidefrac <= 0)
+		return;
+
+	tmxmove = FixedMul (mo->momx, bestslidefrac);
+	tmymove = FixedMul (mo->momy, bestslidefrac);
+
+	P_HitSlideLine (bestslideline);				// clip the moves
+
+	mo->momx = tmxmove;
+	mo->momy = tmymove;
+
+	if (!P_TryMove (mo, mo->x + tmxmove, mo->y + tmymove))
+	{
+		goto retry;
+	}
+}
+
+//============================================================================
+//
+// PTR_BounceTraverse
+//
+//============================================================================
+
+static boolean PTR_BounceTraverse(intercept_t *in)
+{
+	line_t	*li;
+
+	if (!in->isaline)
+		I_Error ("PTR_BounceTraverse: not a line?");
+
+	li = in->d.line;
+	if (!(li->flags & ML_TWOSIDED))
+	{
+		if (P_PointOnLineSide (slidemo->x, slidemo->y, li))
+			return true;		// don't hit the back side
+		goto bounceblocking;
+	}
+
+	P_LineOpening (li);		// set openrange, opentop, openbottom
+	if (openrange < slidemo->height)
+		goto bounceblocking;		// doesn't fit
+
+	if (opentop - slidemo->z < slidemo->height)
+		goto bounceblocking;		// mobj is too high
+	return true;		// this line doesn't block movement
+
+// the line does block movement, see if it is closer than best so far
+bounceblocking:
+	if (in->frac < bestslidefrac)
+	{
+		secondslidefrac = bestslidefrac;
+		secondslideline = bestslideline;
+		bestslidefrac = in->frac;
+		bestslideline = li;
+	}
+	return false;	// stop
+}
+
+//============================================================================
+//
+// P_BounceWall
+//
+//============================================================================
+
+void P_BounceWall(mobj_t *mo)
+{
+	fixed_t		leadx, leady;
+	int		side;
+	angle_t		lineangle, moveangle, deltaangle;
+	fixed_t		movelen;
+
+	slidemo = mo;
+
+//
+// trace along the three leading corners
+//
+	if (mo->momx > 0)
+	{
+		leadx = mo->x + mo->radius;
+	}
+	else
+	{
+		leadx = mo->x - mo->radius;
+	}
+	if (mo->momy > 0)
+	{
+		leady = mo->y + mo->radius;
+	}
+	else
+	{
+		leady = mo->y - mo->radius;
+	}
+	bestslidefrac = FRACUNIT+1;
+	P_PathTraverse(leadx, leady, leadx + mo->momx, leady + mo->momy,
+					PT_ADDLINES, PTR_BounceTraverse);
+
+	side = P_PointOnLineSide(mo->x, mo->y, bestslideline);
+	lineangle = R_PointToAngle2(0, 0, bestslideline->dx, bestslideline->dy);
+	if (side == 1)
+		lineangle += ANG180;
+	moveangle = R_PointToAngle2(0, 0, mo->momx, mo->momy);
+	deltaangle = (2*lineangle) - moveangle;
+//	if (deltaangle > ANG180)
+//		deltaangle += ANG180;
+////		I_Error ("SlideLine: ang>ANG180");
+
+	lineangle >>= ANGLETOFINESHIFT;
+	deltaangle >>= ANGLETOFINESHIFT;
+
+	movelen = P_AproxDistance(mo->momx, mo->momy);
+	movelen = FixedMul(movelen, 0.75*FRACUNIT); // friction
+	if (movelen < FRACUNIT)
+		movelen = 2*FRACUNIT;
+	mo->momx = FixedMul(movelen, finecosine[deltaangle]);
+	mo->momy = FixedMul(movelen, finesine[deltaangle]);
+}
+
+
+/*
+==============================================================================
+
+							P_LineAttack
+
+==============================================================================
+*/
+
+
+mobj_t			*PuffSpawned;
+mobj_t			*linetarget;		/* who got hit (or NULL) */
+
+fixed_t			attackrange;
+static fixed_t		aimslope;
+static int		la_damage;
+
+static mobj_t		*shootthing;
+static fixed_t		shootz;			/* height if not aiming up or down */
+							/* ???: use slope for monsters? */
+
+
+/*
+===============================================================================
+=
+= PTR_AimTraverse
+=
+= Sets linetaget and aimslope when a target is aimed at
+===============================================================================
+*/
+
+static boolean PTR_AimTraverse (intercept_t *in)
+{
+	line_t		*li;
+	mobj_t		*th;
+	fixed_t		slope, thingtopslope, thingbottomslope;
+	fixed_t		dist;
+
+	if (in->isaline)
+	{
+		li = in->d.line;
+		if (!(li->flags & ML_TWOSIDED))
+			return false;		// stop
+//
+// crosses a two sided line
+// a two sided line will restrict the possible target ranges
+		P_LineOpening (li);
+
+		if (openbottom >= opentop)
+			return false;		// stop
+
+		dist = FixedMul (attackrange, in->frac);
+
+		if (li->frontsector->floorheight != li->backsector->floorheight)
+		{
+			slope = FixedDiv (openbottom - shootz , dist);
+			if (slope > bottomslope)
+				bottomslope = slope;
+		}
+
+		if (li->frontsector->ceilingheight != li->backsector->ceilingheight)
+		{
+			slope = FixedDiv (opentop - shootz, dist);
+			if (slope < topslope)
+				topslope = slope;
+		}
+
+		if (topslope <= bottomslope)
+			return false;		// stop
+
+		return true;		// shot continues
+	}
+
+//
+// shoot a thing
+//
+	th = in->d.thing;
+	if (th == shootthing)
+		return true;		// can't shoot self
+	if (!(th->flags & MF_SHOOTABLE))
+	{ // corpse or something
+		return true;
+	}
+	if (th->player && netgame && !deathmatch)
+	{ // don't aim at fellow co-op players
+		return true;
+	}
+
+// check angles to see if the thing can be aimed at
+
+	dist = FixedMul (attackrange, in->frac);
+	thingtopslope = FixedDiv (th->z + th->height - shootz, dist);
+	if (thingtopslope < bottomslope)
+		return true;		// shot over the thing
+	thingbottomslope = FixedDiv (th->z - shootz, dist);
+	if (thingbottomslope > topslope)
+		return true;		// shot under the thing
+
+//
+// this thing can be hit!
+//
+	if (thingtopslope > topslope)
+		thingtopslope = topslope;
+	if (thingbottomslope < bottomslope)
+		thingbottomslope = bottomslope;
+
+	aimslope = (thingtopslope + thingbottomslope) / 2;
+	linetarget = th;
+
+	return false;		// don't go any farther
+}
+
+
+/*
+==============================================================================
+=
+= PTR_ShootTraverse
+=
+==============================================================================
+*/
+
+static boolean PTR_ShootTraverse (intercept_t *in)
+{
+	fixed_t		x, y, z;
+	fixed_t		frac;
+	line_t		*li;
+	mobj_t		*th;
+	fixed_t		slope;
+	fixed_t		dist;
+	fixed_t		thingtopslope, thingbottomslope;
+
+	if (in->isaline)
+	{
+		li = in->d.line;
+		if (li->special)
+		{
+			P_ActivateLine(li, shootthing, 0, SPAC_IMPACT);
+		//	P_ShootSpecialLine (shootthing, li);
+		}
+		if (!(li->flags & ML_TWOSIDED))
+			goto hitline;
+
+//
+// crosses a two sided line
+//
+		P_LineOpening (li);
+
+		dist = FixedMul (attackrange, in->frac);
+
+		if (li->frontsector->floorheight != li->backsector->floorheight)
+		{
+			slope = FixedDiv (openbottom - shootz, dist);
+			if (slope > aimslope)
+				goto hitline;
+		}
+
+		if (li->frontsector->ceilingheight != li->backsector->ceilingheight)
+		{
+			slope = FixedDiv (opentop - shootz , dist);
+			if (slope < aimslope)
+				goto hitline;
+		}
+
+		return true;		// shot continues
+//
+// hit line
+//
+hitline:
+		// position a bit closer
+		frac = in->frac - FixedDiv(4*FRACUNIT, attackrange);
+		x = trace.x + FixedMul(trace.dx, frac);
+		y = trace.y + FixedMul(trace.dy, frac);
+		z = shootz  + FixedMul(aimslope, FixedMul(frac, attackrange));
+
+		if (li->frontsector->ceilingpic == skyflatnum)
+		{
+			if (z > li->frontsector->ceilingheight)
+				return false;		// don't shoot the sky!
+			if (li->backsector && li->backsector->ceilingpic == skyflatnum)
+				return false;		// it's a sky hack wall
+		}
+
+		P_SpawnPuff (x, y, z);
+		return false;			// don't go any farther
+	}
+
+//
+// shoot a thing
+//
+	th = in->d.thing;
+	if (th == shootthing)
+		return true;		// can't shoot self
+	if (!(th->flags & MF_SHOOTABLE))
+		return true;		// corpse or something
+
+//
+// check for physical attacks on a ghost
+//
+/*  FIX:  Impliment Heretic 2 weapons here
+	if (th->flags & MF_SHADOW && shootthing->player->readyweapon == wp_staff)
+	{
+		return true;
+	}
+*/
+
+// check angles to see if the thing can be aimed at
+	dist = FixedMul (attackrange, in->frac);
+	thingtopslope = FixedDiv (th->z + th->height - shootz, dist);
+	if (thingtopslope < aimslope)
+		return true;		// shot over the thing
+	thingbottomslope = FixedDiv (th->z - shootz, dist);
+	if (thingbottomslope > aimslope)
+		return true;		// shot under the thing
+
+//
+// hit thing
+//
+	// position a bit closer
+	frac = in->frac - FixedDiv(10*FRACUNIT, attackrange);
+	x = trace.x + FixedMul(trace.dx, frac);
+	y = trace.y + FixedMul(trace.dy, frac);
+	z = shootz  + FixedMul(aimslope, FixedMul(frac, attackrange));
+	P_SpawnPuff(x, y, z);
+	if (la_damage)
+	{
+		if (!(in->d.thing->flags & MF_NOBLOOD) &&
+			!(in->d.thing->flags2 & MF2_INVULNERABLE))
+		{
+			if (PuffType == MT_AXEPUFF || PuffType == MT_AXEPUFF_GLOW)
+			{
+				P_BloodSplatter2(x, y, z, in->d.thing);
+			}
+			if (P_Random() < 192)
+			{
+				P_BloodSplatter(x, y, z, in->d.thing);
+			}
+		}
+		if (PuffType == MT_FLAMEPUFF2)
+		{ // Cleric FlameStrike does fire damage
+			P_DamageMobj(th, &LavaInflictor, shootthing, la_damage);
+		}
+		else
+		{
+			P_DamageMobj(th, shootthing, shootthing, la_damage);
+		}
+	}
+	return false;	// don't go any farther
+}
+
+/*
+=================
+=
+= P_AimLineAttack
+=
+=================
+*/
+
+fixed_t P_AimLineAttack (mobj_t *t1, angle_t angle, fixed_t distance)
+{
+	fixed_t		x2, y2;
+
+	angle >>= ANGLETOFINESHIFT;
+	shootthing = t1;
+	x2 = t1->x + (distance>>FRACBITS)*finecosine[angle];
+	y2 = t1->y + (distance>>FRACBITS)*finesine[angle];
+	shootz = t1->z + (t1->height>>1) + 8*FRACUNIT;
+	topslope = 100*FRACUNIT/160;	// can't shoot outside view angles
+	bottomslope = -100*FRACUNIT/160;
+	attackrange = distance;
+	linetarget = NULL;
+
+	P_PathTraverse (t1->x, t1->y, x2, y2, PT_ADDLINES|PT_ADDTHINGS, PTR_AimTraverse);
+
+	if (linetarget)
+		return aimslope;
+	return 0;
+}
+
+
+/*
+=================
+=
+= P_LineAttack
+=
+= if damage == 0, it is just a test trace that will leave linetarget set
+=
+=================
+*/
+
+void P_LineAttack (mobj_t *t1, angle_t angle, fixed_t distance, fixed_t slope, int damage)
+{
+	fixed_t		x2, y2;
+
+	angle >>= ANGLETOFINESHIFT;
+	shootthing = t1;
+	la_damage = damage;
+	x2 = t1->x + (distance>>FRACBITS)*finecosine[angle];
+	y2 = t1->y + (distance>>FRACBITS)*finesine[angle];
+	shootz = t1->z + (t1->height>>1) + 8*FRACUNIT;
+	shootz -= t1->floorclip;
+	attackrange = distance;
+	aimslope = slope;
+
+	if (P_PathTraverse(t1->x, t1->y, x2, y2, PT_ADDLINES|PT_ADDTHINGS,
+							PTR_ShootTraverse))
+	{
+		switch (PuffType)
+		{
+		case MT_PUNCHPUFF:
+			S_StartSound(t1, SFX_FIGHTER_PUNCH_MISS);
+			break;
+		case MT_HAMMERPUFF:
+		case MT_AXEPUFF:
+		case MT_AXEPUFF_GLOW:
+			S_StartSound(t1, SFX_FIGHTER_HAMMER_MISS);
+			break;
+		case MT_FLAMEPUFF:
+			P_SpawnPuff(x2, y2, shootz + FixedMul(slope, distance));
+			break;
+		default:
+			break;
+		}
+	}
+}
+
+/*
+==============================================================================
+
+							USE LINES
+
+==============================================================================
+*/
+
+static mobj_t		*usething;
+
+static boolean PTR_UseTraverse (intercept_t *in)
+{
+	int sound;
+	fixed_t pheight;
+
+	if (!in->d.line->special)
+	{
+		P_LineOpening (in->d.line);
+		if (openrange <= 0)
+		{
+			if (usething->player)
+			{
+				switch (usething->player->playerclass)
+				{
+				case PCLASS_FIGHTER:
+					sound = SFX_PLAYER_FIGHTER_FAILED_USE;
+					break;
+				case PCLASS_CLERIC:
+					sound = SFX_PLAYER_CLERIC_FAILED_USE;
+					break;
+				case PCLASS_MAGE:
+					sound = SFX_PLAYER_MAGE_FAILED_USE;
+					break;
+				case PCLASS_PIG:
+					sound = SFX_PIG_ACTIVE1;
+					break;
+				default:
+					sound = SFX_NONE;
+					break;
+				}
+				S_StartSound(usething, sound);
+			}
+			return false;	// can't use through a wall
+		}
+		if (usething->player)
+		{
+			pheight = usething->z + (usething->height/2);
+			if ((opentop < pheight) || (openbottom > pheight))
+			{
+				switch (usething->player->playerclass)
+				{
+				case PCLASS_FIGHTER:
+					sound = SFX_PLAYER_FIGHTER_FAILED_USE;
+					break;
+				case PCLASS_CLERIC:
+					sound = SFX_PLAYER_CLERIC_FAILED_USE;
+					break;
+				case PCLASS_MAGE:
+					sound = SFX_PLAYER_MAGE_FAILED_USE;
+					break;
+				case PCLASS_PIG:
+					sound = SFX_PIG_ACTIVE1;
+					break;
+				default:
+					sound = SFX_NONE;
+					break;
+				}
+				S_StartSound(usething, sound);
+			}
+		}
+		return true;		// not a special line, but keep checking
+	}
+
+	if (P_PointOnLineSide (usething->x, usething->y, in->d.line) == 1)
+		return false;		// don't use back sides
+
+//	P_UseSpecialLine (usething, in->d.line);
+	P_ActivateLine(in->d.line, usething, 0, SPAC_USE);
+
+	return false;			// can't use for than one special line in a row
+}
+
+
+/*
+================
+=
+= P_UseLines
+=
+= Looks for special lines in front of the player to activate
+================
+*/
+
+void P_UseLines (player_t *player)
+{
+	int			angle;
+	fixed_t		x1, y1, x2, y2;
+
+	usething = player->mo;
+
+	angle = player->mo->angle >> ANGLETOFINESHIFT;
+	x1 = player->mo->x;
+	y1 = player->mo->y;
+	x2 = x1 + (USERANGE>>FRACBITS)*finecosine[angle];
+	y2 = y1 + (USERANGE>>FRACBITS)*finesine[angle];
+
+	P_PathTraverse (x1, y1, x2, y2, PT_ADDLINES, PTR_UseTraverse);
+}
+
+//==========================================================================
+//
+// PTR_PuzzleItemTraverse
+//
+//==========================================================================
+
+#define USE_PUZZLE_ITEM_SPECIAL		129
+
+static mobj_t		*PuzzleItemUser;
+static int		PuzzleItemType;
+static boolean		PuzzleActivated;
+
+static boolean PTR_PuzzleItemTraverse(intercept_t *in)
+{
+	mobj_t *mobj;
+	int sound;
+
+	if (in->isaline)
+	{ // Check line
+		if (in->d.line->special != USE_PUZZLE_ITEM_SPECIAL)
+		{
+			P_LineOpening(in->d.line);
+			if (openrange <= 0)
+			{
+				sound = SFX_NONE;
+				if (PuzzleItemUser->player)
+				{
+					switch (PuzzleItemUser->player->playerclass)
+					{
+					case PCLASS_FIGHTER:
+						sound = SFX_PUZZLE_FAIL_FIGHTER;
+						break;
+					case PCLASS_CLERIC:
+						sound = SFX_PUZZLE_FAIL_CLERIC;
+						break;
+					case PCLASS_MAGE:
+						sound = SFX_PUZZLE_FAIL_MAGE;
+						break;
+					default:
+						sound = SFX_NONE;
+						break;
+					}
+				}
+				S_StartSound(PuzzleItemUser, sound);
+				return false;	// can't use through a wall
+			}
+			return true;	// Continue searching
+		}
+		if (P_PointOnLineSide(PuzzleItemUser->x, PuzzleItemUser->y,
+							in->d.line) == 1)
+		{ // Don't use back sides
+			return false;
+		}
+		if (PuzzleItemType != in->d.line->arg1)
+		{ // Item type doesn't match
+			return false;
+		}
+		P_StartACS(in->d.line->arg2, 0, &in->d.line->arg3,
+				PuzzleItemUser, in->d.line, 0);
+		in->d.line->special = 0;
+		PuzzleActivated = true;
+		return false;	// Stop searching
+	}
+	// Check thing
+	mobj = in->d.thing;
+	if (mobj->special != USE_PUZZLE_ITEM_SPECIAL)
+	{ // Wrong special
+		return true;
+	}
+	if (PuzzleItemType != mobj->args[0])
+	{ // Item type doesn't match
+		return true;
+	}
+	P_StartACS(mobj->args[1], 0, &mobj->args[2], PuzzleItemUser, NULL, 0);
+	mobj->special = 0;
+	PuzzleActivated = true;
+	return false;	// Stop searching
+}
+
+//==========================================================================
+//
+// P_UsePuzzleItem
+//
+// Returns true if the puzzle item was used on a line or a thing.
+//
+//==========================================================================
+
+boolean P_UsePuzzleItem(player_t *player, int itemType)
+{
+	int angle;
+	fixed_t x1, y1, x2, y2;
+
+	PuzzleItemType = itemType;
+	PuzzleItemUser = player->mo;
+	PuzzleActivated = false;
+	angle = player->mo->angle>>ANGLETOFINESHIFT;
+	x1 = player->mo->x;
+	y1 = player->mo->y;
+	x2 = x1 + (USERANGE>>FRACBITS)*finecosine[angle];
+	y2 = y1 + (USERANGE>>FRACBITS)*finesine[angle];
+	P_PathTraverse(x1, y1, x2, y2, PT_ADDLINES|PT_ADDTHINGS,
+					PTR_PuzzleItemTraverse);
+	return PuzzleActivated;
+}
+
+/*
+==============================================================================
+
+							RADIUS ATTACK
+
+==============================================================================
+*/
+
+static mobj_t		*bombsource;
+static mobj_t		*bombspot;
+static int		bombdamage;
+static int		bombdistance;
+static boolean		DamageSource;
+
+/*
+=================
+=
+= PIT_RadiusAttack
+=
+= Source is the creature that casued the explosion at spot
+=================
+*/
+
+static boolean PIT_RadiusAttack (mobj_t *thing)
+{
+	fixed_t dx, dy, dist;
+	int damage;
+
+	if (!(thing->flags & MF_SHOOTABLE))
+	{
+		return true;
+	}
+//	if (thing->flags2 & MF2_BOSS)
+//	{	// Bosses take no damage from PIT_RadiusAttack
+//		return true;
+//	}
+	if (!DamageSource && thing == bombsource)
+	{ // don't damage the source of the explosion
+		return true;
+	}
+	if (abs((thing->z - bombspot->z)>>FRACBITS) > 2*bombdistance)
+	{ // too high/low
+		return true;
+	}
+	dx = abs(thing->x - bombspot->x);
+	dy = abs(thing->y - bombspot->y);
+	dist = dx > dy ? dx : dy;
+	dist = (dist - thing->radius)>>FRACBITS;
+	if (dist < 0)
+	{
+		dist = 0;
+	}
+	if (dist >= bombdistance)
+	{ // Out of range
+		return true;
+	}
+	if (P_CheckSight(thing, bombspot))
+	{ // OK to damage, target is in direct path
+		damage = (bombdamage * (bombdistance - dist) / bombdistance) + 1;
+		if (thing->player)
+		{
+			damage >>= 2;
+		}
+		P_DamageMobj(thing, bombspot, bombsource, damage);
+	}
+	return true;
+}
+
+/*
+=================
+=
+= P_RadiusAttack
+=
+= Source is the creature that caused the explosion at spot
+=================
+*/
+
+void P_RadiusAttack (mobj_t *spot, mobj_t *source, int damage, int distance,
+							boolean damageSource)
+{
+	int	x, y, xl, xh, yl, yh;
+	fixed_t			dist;
+
+	dist = (distance + MAXRADIUS)<<FRACBITS;
+	yh = (spot->y + dist-bmaporgy)>>MAPBLOCKSHIFT;
+	yl = (spot->y - dist-bmaporgy)>>MAPBLOCKSHIFT;
+	xh = (spot->x + dist-bmaporgx)>>MAPBLOCKSHIFT;
+	xl = (spot->x - dist-bmaporgx)>>MAPBLOCKSHIFT;
+	bombspot = spot;
+	bombsource = source;
+	bombdamage = damage;
+	bombdistance = distance;
+	DamageSource = damageSource;
+	for (y = yl; y <= yh; y++)
+	{
+		for (x = xl; x <= xh; x++)
+		{
+			P_BlockThingsIterator(x, y, PIT_RadiusAttack);
+		}
+	}
+}
+
+/*
+==============================================================================
+
+						SECTOR HEIGHT CHANGING
+
+= After modifying a sectors floor or ceiling height, call this
+= routine to adjust the positions of all things that touch the
+= sector.
+=
+= If anything doesn't fit anymore, true will be returned.
+= If crunch is true, they will take damage as they are being crushed
+= If Crunch is false, you should set the sector height back the way it
+= was and call P_ChangeSector again to undo the changes
+==============================================================================
+*/
+
+static int		crushchange;
+static boolean		nofit;
+
+/*
+===============
+=
+= PIT_ChangeSector
+=
+===============
+*/
+
+static boolean PIT_ChangeSector (mobj_t *thing)
+{
+	mobj_t		*mo;
+
+	if (P_ThingHeightClip (thing))
+		return true;		// keep checking
+
+	// crunch bodies to giblets
+	if ((thing->flags & MF_CORPSE) && (thing->health <= 0))
+	{
+		if (thing->flags & MF_NOBLOOD)
+		{
+			P_RemoveMobj (thing);
+		}
+		else
+		{
+			if (thing->state != &states[S_GIBS1])
+			{
+				P_SetMobjState (thing, S_GIBS1);
+				thing->height = 0;
+				thing->radius = 0;
+				S_StartSound(thing, SFX_PLAYER_FALLING_SPLAT);
+			}
+		}
+		return true;		// keep checking
+	}
+
+	// crunch dropped items
+	if (thing->flags2 & MF2_DROPPED)
+	{
+		P_RemoveMobj (thing);
+		return true;		// keep checking
+	}
+
+	if (!(thing->flags & MF_SHOOTABLE))
+		return true;		// assume it is bloody gibs or something
+
+	nofit = true;
+	if (crushchange && !(leveltime & 3))
+	{
+		P_DamageMobj(thing, NULL, NULL, crushchange);
+		// spray blood in a random direction
+		if ((!(thing->flags & MF_NOBLOOD)) &&
+			(!(thing->flags2 & MF2_INVULNERABLE)))
+		{
+			mo = P_SpawnMobj (thing->x, thing->y, thing->z + thing->height/2,
+										MT_BLOOD);
+			mo->momx = (P_Random() - P_Random())<<12;
+			mo->momy = (P_Random() - P_Random())<<12;
+		}
+	}
+
+	return true;		// keep checking (crush other things)
+}
+
+/*
+===============
+=
+= P_ChangeSector
+=
+===============
+*/
+
+boolean P_ChangeSector (sector_t *sector, int crunch)
+{
+	int		x, y;
+
+	nofit = false;
+	crushchange = crunch;
+
+// recheck heights for all things near the moving sector
+	for (x = sector->blockbox[BOXLEFT]; x <= sector->blockbox[BOXRIGHT]; x++)
+	{
+		for (y = sector->blockbox[BOXBOTTOM]; y <= sector->blockbox[BOXTOP]; y++)
+			P_BlockThingsIterator (x, y, PIT_ChangeSector);
+	}
+
+	return nofit;
+}
+
--- /dev/null
+++ b/p_maputl.c
@@ -1,0 +1,1059 @@
+
+//**************************************************************************
+//**
+//** p_maputl.c : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 491 $
+//** $Date: 2009-05-30 01:10:42 +0300 (Sat, 30 May 2009) $
+//**
+//**************************************************************************
+
+#include "h2stdinc.h"
+#include "h2def.h"
+#include "p_local.h"
+
+
+extern polyblock_t	**PolyBlockMap;
+
+static mobj_t *RoughBlockCheck(mobj_t *mo, int idx);
+
+//===========================================================================
+
+
+/*
+===================
+=
+= P_AproxDistance
+=
+= Gives an estimation of distance (not exact)
+=
+===================
+*/
+
+fixed_t P_AproxDistance (fixed_t dx, fixed_t dy)
+{
+	dx = abs(dx);
+	dy = abs(dy);
+	if (dx < dy)
+		return dx + dy - (dx>>1);
+	return dx + dy - (dy>>1);
+}
+
+
+/*
+==================
+=
+= P_PointOnLineSide
+=
+= Returns 0 or 1
+==================
+*/
+
+int P_PointOnLineSide (fixed_t x, fixed_t y, line_t *line)
+{
+	fixed_t dx, dy;
+	fixed_t left, right;
+
+	if (!line->dx)
+	{
+		if (x <= line->v1->x)
+			return line->dy > 0;
+		return line->dy < 0;
+	}
+	if (!line->dy)
+	{
+		if (y <= line->v1->y)
+			return line->dx < 0;
+		return line->dx > 0;
+	}
+
+	dx = (x - line->v1->x);
+	dy = (y - line->v1->y);
+
+	left = FixedMul (line->dy>>FRACBITS, dx);
+	right = FixedMul (dy, line->dx>>FRACBITS);
+
+	if (right < left)
+		return 0;		// front side
+	return 1;			// back side
+}
+
+
+/*
+=================
+=
+= P_BoxOnLineSide
+=
+= Considers the line to be infinite
+= Returns side 0 or 1, -1 if box crosses the line
+=================
+*/
+
+int P_BoxOnLineSide (fixed_t *tmbox, line_t *ld)
+{
+	int		p1 = 0, p2 = 0;
+
+	switch (ld->slopetype)
+	{
+	case ST_HORIZONTAL:
+		p1 = tmbox[BOXTOP] > ld->v1->y;
+		p2 = tmbox[BOXBOTTOM] > ld->v1->y;
+		if (ld->dx < 0)
+		{
+			p1 ^= 1;
+			p2 ^= 1;
+		}
+		break;
+	case ST_VERTICAL:
+		p1 = tmbox[BOXRIGHT] < ld->v1->x;
+		p2 = tmbox[BOXLEFT] < ld->v1->x;
+		if (ld->dy < 0)
+		{
+			p1 ^= 1;
+			p2 ^= 1;
+		}
+		break;
+	case ST_POSITIVE:
+		p1 = P_PointOnLineSide (tmbox[BOXLEFT], tmbox[BOXTOP], ld);
+		p2 = P_PointOnLineSide (tmbox[BOXRIGHT], tmbox[BOXBOTTOM], ld);
+		break;
+	case ST_NEGATIVE:
+		p1 = P_PointOnLineSide (tmbox[BOXRIGHT], tmbox[BOXTOP], ld);
+		p2 = P_PointOnLineSide (tmbox[BOXLEFT], tmbox[BOXBOTTOM], ld);
+		break;
+	}
+
+	if (p1 == p2)
+		return p1;
+	return -1;
+}
+
+/*
+==================
+=
+= P_PointOnDivlineSide
+=
+= Returns 0 or 1
+==================
+*/
+
+int P_PointOnDivlineSide (fixed_t x, fixed_t y, divline_t *line)
+{
+	fixed_t	dx, dy;
+	fixed_t	left, right;
+
+	if (!line->dx)
+	{
+		if (x <= line->x)
+			return line->dy > 0;
+		return line->dy < 0;
+	}
+	if (!line->dy)
+	{
+		if (y <= line->y)
+			return line->dx < 0;
+		return line->dx > 0;
+	}
+
+	dx = (x - line->x);
+	dy = (y - line->y);
+
+// try to quickly decide by looking at sign bits
+	if ((line->dy ^ line->dx ^ dx ^ dy) & 0x80000000)
+	{
+		if ((line->dy ^ dx) & 0x80000000)
+			return 1;	// (left is negative)
+		return 0;
+	}
+
+	left = FixedMul (line->dy>>8, dx>>8);
+	right = FixedMul (dy>>8, line->dx>>8);
+
+	if (right < left)
+		return 0;		// front side
+	return 1;			// back side
+}
+
+
+/*
+==============
+=
+= P_MakeDivline
+=
+==============
+*/
+
+void P_MakeDivline (line_t *li, divline_t *dl)
+{
+	dl->x = li->v1->x;
+	dl->y = li->v1->y;
+	dl->dx = li->dx;
+	dl->dy = li->dy;
+}
+
+
+/*
+===============
+=
+= P_InterceptVector
+=
+= Returns the fractional intercept point along the first divline
+=
+= This is only called by the addthings and addlines traversers
+===============
+*/
+
+fixed_t P_InterceptVector (divline_t *v2, divline_t *v1)
+{
+#if 1
+	fixed_t frac, num, den;
+
+	den = FixedMul(v1->dy>>8, v2->dx) - FixedMul(v1->dx>>8, v2->dy);
+	if (den == 0)
+		return 0;
+//		I_Error ("P_InterceptVector: parallel");
+	num = FixedMul((v1->x - v2->x)>>8, v1->dy) +
+		FixedMul ((v2->y - v1->y)>>8, v1->dx);
+	frac = FixedDiv (num , den);
+
+	return frac;
+#else
+	float	frac, num, den, v1x, v1y, v1dx, v1dy, v2x, v2y, v2dx, v2dy;
+
+	v1x = (float)v1->x/FRACUNIT;
+	v1y = (float)v1->y/FRACUNIT;
+	v1dx = (float)v1->dx/FRACUNIT;
+	v1dy = (float)v1->dy/FRACUNIT;
+	v2x = (float)v2->x/FRACUNIT;
+	v2y = (float)v2->y/FRACUNIT;
+	v2dx = (float)v2->dx/FRACUNIT;
+	v2dy = (float)v2->dy/FRACUNIT;
+
+	den = v1dy*v2dx - v1dx*v2dy;
+	if (den == 0)
+		return 0;	// parallel
+	num = (v1x - v2x)*v1dy + (v2y - v1y)*v1dx;
+	frac = num / den;
+
+	return frac*FRACUNIT;
+#endif
+}
+
+/*
+==================
+=
+= P_LineOpening
+=
+= Sets opentop and openbottom to the window through a two sided line
+= OPTIMIZE: keep this precalculated
+==================
+*/
+
+fixed_t opentop, openbottom, openrange;
+fixed_t lowfloor;
+
+void P_LineOpening (line_t *ld)
+{
+	sector_t	*front, *back;
+
+	if (ld->sidenum[1] == -1)
+	{	// single sided line
+		openrange = 0;
+		return;
+	}
+
+	front = ld->frontsector;
+	back = ld->backsector;
+
+	if (front->ceilingheight < back->ceilingheight)
+		opentop = front->ceilingheight;
+	else
+		opentop = back->ceilingheight;
+	if (front->floorheight > back->floorheight)
+	{
+		openbottom = front->floorheight;
+		lowfloor = back->floorheight;
+		tmfloorpic = front->floorpic;
+	}
+	else
+	{
+		openbottom = back->floorheight;
+		lowfloor = front->floorheight;
+		tmfloorpic = back->floorpic;
+	}
+
+	openrange = opentop - openbottom;
+}
+
+/*
+===============================================================================
+
+						THING POSITION SETTING
+
+===============================================================================
+*/
+
+/*
+===================
+=
+= P_UnsetThingPosition
+=
+= Unlinks a thing from block map and sectors
+=
+===================
+*/
+
+void P_UnsetThingPosition (mobj_t *thing)
+{
+	int		blockx, blocky;
+
+	if (! (thing->flags & MF_NOSECTOR))
+	{	// inert things don't need to be in blockmap
+	// unlink from subsector
+		if (thing->snext)
+			thing->snext->sprev = thing->sprev;
+		if (thing->sprev)
+			thing->sprev->snext = thing->snext;
+		else
+			thing->subsector->sector->thinglist = thing->snext;
+	}
+
+	if (! (thing->flags & MF_NOBLOCKMAP))
+	{	// inert things don't need to be in blockmap
+	// unlink from block map
+		if (thing->bnext)
+			thing->bnext->bprev = thing->bprev;
+		if (thing->bprev)
+			thing->bprev->bnext = thing->bnext;
+		else
+		{
+			blockx = (thing->x - bmaporgx)>>MAPBLOCKSHIFT;
+			blocky = (thing->y - bmaporgy)>>MAPBLOCKSHIFT;
+			if (blockx >= 0 && blockx < bmapwidth &&
+			    blocky >= 0 && blocky < bmapheight)
+			{
+				blocklinks[blocky*bmapwidth+blockx] = thing->bnext;
+			}
+		}
+	}
+}
+
+
+/*
+===================
+=
+= P_SetThingPosition
+=
+= Links a thing into both a block and a subsector based on it's x y
+= Sets thing->subsector properly
+=
+===================
+*/
+
+void P_SetThingPosition (mobj_t *thing)
+{
+	subsector_t	*ss;
+	sector_t	*sec;
+	int		blockx, blocky;
+	mobj_t		**link;
+
+//
+// link into subsector
+//
+	ss = R_PointInSubsector (thing->x, thing->y);
+	thing->subsector = ss;
+	if (! (thing->flags & MF_NOSECTOR))
+	{	// invisible things don't go into the sector links
+		sec = ss->sector;
+
+		thing->sprev = NULL;
+		thing->snext = sec->thinglist;
+		if (sec->thinglist)
+			sec->thinglist->sprev = thing;
+		sec->thinglist = thing;
+	}
+
+//
+// link into blockmap
+//
+	if (! (thing->flags & MF_NOBLOCKMAP))
+	{	// inert things don't need to be in blockmap
+		blockx = (thing->x - bmaporgx)>>MAPBLOCKSHIFT;
+		blocky = (thing->y - bmaporgy)>>MAPBLOCKSHIFT;
+		if (blockx >= 0 && blockx < bmapwidth && blocky >= 0 && blocky < bmapheight)
+		{
+			link = &blocklinks[blocky*bmapwidth + blockx];
+			thing->bprev = NULL;
+			thing->bnext = *link;
+			if (*link)
+				(*link)->bprev = thing;
+			*link = thing;
+		}
+		else
+		{	// thing is off the map
+			thing->bnext = thing->bprev = NULL;
+		}
+	}
+}
+
+
+/*
+===============================================================================
+
+						BLOCK MAP ITERATORS
+
+For each line/thing in the given mapblock, call the passed function.
+If the function returns false, exit with false without checking anything else.
+
+===============================================================================
+*/
+
+/*
+==================
+=
+= P_BlockLinesIterator
+=
+= The validcount flags are used to avoid checking lines
+= that are marked in multiple mapblocks, so increment validcount before
+= the first call to P_BlockLinesIterator, then make one or more calls to it
+===================
+*/
+
+boolean P_BlockLinesIterator (int x, int y, boolean(*func)(line_t*) )
+{
+	int		offset;
+	short		*list;
+	line_t		*ld;
+
+	int		i;
+	polyblock_t	*polyLink;
+	seg_t		**tempSeg;
+
+	if (x < 0 || y < 0 || x >= bmapwidth || y >= bmapheight)
+		return true;
+	offset = y*bmapwidth + x;
+
+	polyLink = PolyBlockMap[offset];
+	while (polyLink)
+	{
+		if (polyLink->polyobj)
+		{
+			if (polyLink->polyobj->validcount != validcount)
+			{
+				polyLink->polyobj->validcount = validcount;
+				tempSeg = polyLink->polyobj->segs;
+				for (i = 0; i < polyLink->polyobj->numsegs; i++, tempSeg++)
+				{
+					if ((*tempSeg)->linedef->validcount == validcount)
+					{
+						continue;
+					}
+					(*tempSeg)->linedef->validcount = validcount;
+					if (!func((*tempSeg)->linedef))
+					{
+						return false;
+					}
+				}
+			}
+		}
+		polyLink = polyLink->next;
+	}
+
+	offset = *(blockmap+offset);
+
+	for (list = blockmaplump + offset; *list != -1; list++)
+	{
+		ld = &lines[*list];
+		if (ld->validcount == validcount)
+			continue;	// line has already been checked
+		ld->validcount = validcount;
+
+		if ( !func(ld) )
+			return false;
+	}
+
+	return true;			// everything was checked
+}
+
+
+/*
+==================
+=
+= P_BlockThingsIterator
+=
+==================
+*/
+
+boolean P_BlockThingsIterator (int x, int y, boolean(*func)(mobj_t*) )
+{
+	mobj_t		*mobj;
+
+	if (x < 0 || y < 0 || x >= bmapwidth || y >= bmapheight)
+		return true;
+
+	for (mobj = blocklinks[y*bmapwidth + x]; mobj; mobj = mobj->bnext)
+	{
+		if (!func( mobj ) )
+			return false;
+	}
+
+	return true;
+}
+
+/*
+===============================================================================
+
+					INTERCEPT ROUTINES
+
+===============================================================================
+*/
+
+intercept_t	intercepts[MAXINTERCEPTS], *intercept_p;
+divline_t	trace;
+static boolean	earlyout;
+
+/*
+==================
+=
+= PIT_AddLineIntercepts
+=
+= Looks for lines in the given block that intercept the given trace
+= to add to the intercepts list
+= A line is crossed if its endpoints are on opposite sides of the trace
+= Returns true if earlyout and a solid line hit
+==================
+*/
+
+static boolean PIT_AddLineIntercepts (line_t *ld)
+{
+	int		s1, s2;
+	fixed_t		frac;
+	divline_t	dl;
+
+// avoid precision problems with two routines
+	if (trace.dx > FRACUNIT*16 || trace.dy > FRACUNIT*16 ||
+	    trace.dx < -FRACUNIT*16 || trace.dy < -FRACUNIT*16)
+	{
+		s1 = P_PointOnDivlineSide (ld->v1->x, ld->v1->y, &trace);
+		s2 = P_PointOnDivlineSide (ld->v2->x, ld->v2->y, &trace);
+	}
+	else
+	{
+		s1 = P_PointOnLineSide (trace.x, trace.y, ld);
+		s2 = P_PointOnLineSide (trace.x + trace.dx, trace.y + trace.dy, ld);
+	}
+	if (s1 == s2)
+		return true;		// line isn't crossed
+
+//
+// hit the line
+//
+	P_MakeDivline (ld, &dl);
+	frac = P_InterceptVector (&trace, &dl);
+	if (frac < 0)
+		return true;		// behind source
+
+// try to early out the check
+	if (earlyout && frac < FRACUNIT && !ld->backsector)
+		return false;		// stop checking
+
+	intercept_p->frac = frac;
+	intercept_p->isaline = true;
+	intercept_p->d.line = ld;
+	intercept_p++;
+
+	return true;			// continue
+}
+
+
+/*
+==================
+=
+= PIT_AddThingIntercepts
+=
+==================
+*/
+
+static boolean PIT_AddThingIntercepts (mobj_t *thing)
+{
+	fixed_t		x1, y1, x2, y2;
+	int			s1, s2;
+	boolean		tracepositive;
+	divline_t	dl;
+	fixed_t		frac;
+
+	tracepositive = (trace.dx ^ trace.dy) > 0;
+
+	// check a corner to corner crossection for hit
+
+	if (tracepositive)
+	{
+		x1 = thing->x - thing->radius;
+		y1 = thing->y + thing->radius;
+
+		x2 = thing->x + thing->radius;
+		y2 = thing->y - thing->radius;
+	}
+	else
+	{
+		x1 = thing->x - thing->radius;
+		y1 = thing->y - thing->radius;
+
+		x2 = thing->x + thing->radius;
+		y2 = thing->y + thing->radius;
+	}
+	s1 = P_PointOnDivlineSide (x1, y1, &trace);
+	s2 = P_PointOnDivlineSide (x2, y2, &trace);
+	if (s1 == s2)
+		return true;	// line isn't crossed
+
+	dl.x = x1;
+	dl.y = y1;
+	dl.dx = x2 - x1;
+	dl.dy = y2 - y1;
+	frac = P_InterceptVector (&trace, &dl);
+	if (frac < 0)
+		return true;		// behind source
+	intercept_p->frac = frac;
+	intercept_p->isaline = false;
+	intercept_p->d.thing = thing;
+	intercept_p++;
+
+	return true;			// keep going
+}
+
+
+/*
+====================
+=
+= P_TraverseIntercepts
+=
+= Returns true if the traverser function returns true for all lines
+====================
+*/
+
+boolean P_TraverseIntercepts (traverser_t func, fixed_t maxfrac)
+{
+	int			count;
+	fixed_t			dist;
+	intercept_t		*scan, *in;
+
+	count = intercept_p - intercepts;
+	in = NULL;		// shut up compiler warning
+
+	while (count--)
+	{
+		dist = H2MAXINT;
+		for (scan = intercepts; scan < intercept_p; scan++)
+		{
+			if (scan->frac < dist)
+			{
+				dist = scan->frac;
+				in = scan;
+			}
+		}
+
+		if (dist > maxfrac)
+			return true;			// checked everything in range
+#if 0
+		{	// don't check these yet, ther may be others inserted
+			in = scan = intercepts;
+			for (scan = intercepts; scan < intercept_p; scan++)
+			{
+				if (scan->frac > maxfrac)
+					*in++ = *scan;
+			}
+			intercept_p = in;
+			return false;
+		}
+#endif
+
+		if ( !func (in) )
+			return false;			// don't bother going farther
+		in->frac = H2MAXINT;
+	}
+
+	return true;		// everything was traversed
+}
+
+
+/*
+==================
+=
+= P_PathTraverse
+=
+= Traces a line from x1,y1 to x2,y2, calling the traverser function for each
+= Returns true if the traverser function returns true for all lines
+==================
+*/
+
+boolean P_PathTraverse (fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2,
+			int flags, boolean (*trav) (intercept_t *))
+{
+	fixed_t	xt1,yt1,xt2,yt2;
+	fixed_t	xstep,ystep;
+	fixed_t	partial;
+	fixed_t	xintercept, yintercept;
+	int	mapx, mapy, mapxstep, mapystep;
+	int	count;
+
+	earlyout = flags & PT_EARLYOUT;
+
+	validcount++;
+	intercept_p = intercepts;
+
+	if (((x1 - bmaporgx) & (MAPBLOCKSIZE - 1)) == 0)
+		x1 += FRACUNIT;			// don't side exactly on a line
+	if (((y1 - bmaporgy) & (MAPBLOCKSIZE - 1)) == 0)
+		y1 += FRACUNIT;			// don't side exactly on a line
+	trace.x = x1;
+	trace.y = y1;
+	trace.dx = x2 - x1;
+	trace.dy = y2 - y1;
+
+	x1 -= bmaporgx;
+	y1 -= bmaporgy;
+	xt1 = x1>>MAPBLOCKSHIFT;
+	yt1 = y1>>MAPBLOCKSHIFT;
+
+	x2 -= bmaporgx;
+	y2 -= bmaporgy;
+	xt2 = x2>>MAPBLOCKSHIFT;
+	yt2 = y2>>MAPBLOCKSHIFT;
+
+	if (xt2 > xt1)
+	{
+		mapxstep = 1;
+		partial = FRACUNIT - ((x1>>MAPBTOFRAC) & (FRACUNIT - 1));
+		ystep = FixedDiv (y2 - y1, abs(x2 - x1));
+	}
+	else if (xt2 < xt1)
+	{
+		mapxstep = -1;
+		partial = (x1>>MAPBTOFRAC) & (FRACUNIT - 1);
+		ystep = FixedDiv (y2 - y1, abs(x2 - x1));
+	}
+	else
+	{
+		mapxstep = 0;
+		partial = FRACUNIT;
+		ystep = 256*FRACUNIT;
+	}
+	yintercept = (y1>>MAPBTOFRAC) + FixedMul (partial, ystep);
+
+	if (yt2 > yt1)
+	{
+		mapystep = 1;
+		partial = FRACUNIT - ((y1>>MAPBTOFRAC) & (FRACUNIT - 1));
+		xstep = FixedDiv (x2 - x1, abs(y2 - y1));
+	}
+	else if (yt2 < yt1)
+	{
+		mapystep = -1;
+		partial = (y1>>MAPBTOFRAC) & (FRACUNIT - 1);
+		xstep = FixedDiv (x2 - x1, abs(y2 - y1));
+	}
+	else
+	{
+		mapystep = 0;
+		partial = FRACUNIT;
+		xstep = 256*FRACUNIT;
+	}
+	xintercept = (x1>>MAPBTOFRAC) + FixedMul (partial, xstep);
+
+//
+// step through map blocks
+// Count is present to prevent a round off error from skipping the break
+	mapx = xt1;
+	mapy = yt1;
+
+	for (count = 0; count < 64; count++)
+	{
+		if (flags & PT_ADDLINES)
+		{
+			if (!P_BlockLinesIterator (mapx, mapy, PIT_AddLineIntercepts))
+				return false;	// early out
+		}
+		if (flags & PT_ADDTHINGS)
+		{
+			if (!P_BlockThingsIterator (mapx, mapy, PIT_AddThingIntercepts))
+				return false;	// early out
+		}
+
+		if (mapx == xt2 && mapy == yt2)
+			break;
+
+		if ((yintercept >> FRACBITS) == mapy)
+		{
+			yintercept += ystep;
+			mapx += mapxstep;
+		}
+		else if ((xintercept >> FRACBITS) == mapx)
+		{
+			xintercept += xstep;
+			mapy += mapystep;
+		}
+	}
+
+//
+// go through the sorted list
+//
+	return P_TraverseIntercepts (trav, FRACUNIT);
+}
+
+//===========================================================================
+//
+// P_RoughMonsterSearch
+//
+// Searches though the surrounding mapblocks for monsters/players
+//		distance is in MAPBLOCKUNITS
+//===========================================================================
+
+mobj_t *P_RoughMonsterSearch(mobj_t *mo, int distance)
+{
+	int blockX;
+	int blockY;
+	int startX, startY;
+	int blockIndex;
+	int firstStop;
+	int secondStop;
+	int thirdStop;
+	int finalStop;
+	int count;
+	mobj_t *target;
+
+	startX = (mo->x - bmaporgx)>>MAPBLOCKSHIFT;
+	startY = (mo->y - bmaporgy)>>MAPBLOCKSHIFT;
+
+	if (startX >= 0 && startX < bmapwidth && startY >= 0 && startY < bmapheight)
+	{
+		if ((target = RoughBlockCheck(mo, startY*bmapwidth + startX)))
+		{ // found a target right away
+			return target;
+		}
+	}
+	for (count = 1; count <= distance; count++)
+	{
+		blockX = startX - count;
+		blockY = startY - count;
+
+		if (blockY < 0)
+		{
+			blockY = 0;
+		}
+		else if (blockY >= bmapheight)
+		{
+			blockY = bmapheight - 1;
+		}
+		if (blockX < 0)
+		{
+			blockX = 0;
+		}
+		else if (blockX >= bmapwidth)
+		{
+			blockX = bmapwidth - 1;
+		}
+		blockIndex = blockY*bmapwidth + blockX;
+		firstStop = startX + count;
+		if (firstStop < 0)
+		{
+			continue;
+		}
+		if (firstStop >= bmapwidth)
+		{
+			firstStop = bmapwidth - 1;
+		}
+		secondStop = startY + count;
+		if (secondStop < 0)
+		{
+			continue;
+		}
+		if (secondStop >= bmapheight)
+		{
+			secondStop = bmapheight - 1;
+		}
+		thirdStop = secondStop*bmapwidth + blockX;
+		secondStop = secondStop*bmapwidth + firstStop;
+		firstStop += blockY*bmapwidth;
+		finalStop = blockIndex;
+
+		// Trace the first block section (along the top)
+		for ( ; blockIndex <= firstStop; blockIndex++)
+		{
+			if ((target = RoughBlockCheck(mo, blockIndex)))
+			{
+				return target;
+			}
+		}
+		// Trace the second block section (right edge)
+		for (blockIndex--; blockIndex <= secondStop; blockIndex += bmapwidth)
+		{
+			if ((target = RoughBlockCheck(mo, blockIndex)))
+			{
+				return target;
+			}
+		}
+		// Trace the third block section (bottom edge)
+		for (blockIndex -= bmapwidth; blockIndex >= thirdStop; blockIndex--)
+		{
+			if ((target = RoughBlockCheck(mo, blockIndex)))
+			{
+				return target;
+			}
+		}
+		// Trace the final block section (left edge)
+		for (blockIndex++; blockIndex > finalStop; blockIndex -= bmapwidth)
+		{
+			if ((target = RoughBlockCheck(mo, blockIndex)))
+			{
+				return target;
+			}
+		}
+	}
+	return NULL;
+}
+
+//===========================================================================
+//
+// RoughBlockCheck
+//
+//===========================================================================
+
+static mobj_t *RoughBlockCheck(mobj_t *mo, int idx)
+{
+	mobj_t *link;
+	mobj_t *master;
+	angle_t angle;
+
+	link = blocklinks[idx];
+	while (link)
+	{
+		if (mo->player)				// Minotaur looking around player
+		{
+			if ((link->flags & MF_COUNTKILL) ||
+				(link->player && (link != mo)))
+			{
+				if (!(link->flags & MF_SHOOTABLE))
+				{
+					link = link->bnext;
+					continue;
+				}
+				if (link->flags2 & MF2_DORMANT)
+				{
+					link = link->bnext;
+					continue;
+				}
+				if ((link->type == MT_MINOTAUR) &&
+					(((mobj_t *)link->special1) == mo))
+				{
+					link = link->bnext;
+					continue;
+				}
+				if (netgame && !deathmatch && link->player)
+				{
+					link = link->bnext;
+					continue;
+				}
+				if (P_CheckSight(mo, link))
+				{
+					return link;
+				}
+			}
+			link = link->bnext;
+		}
+		else if (mo->type == MT_MINOTAUR)	// looking around minotaur
+		{
+			master = (mobj_t *)mo->special1;
+			if ((link->flags & MF_COUNTKILL) ||
+				(link->player && (link != master)))
+			{
+				if (!(link->flags & MF_SHOOTABLE))
+				{
+					link = link->bnext;
+					continue;
+				}
+				if (link->flags2 & MF2_DORMANT)
+				{
+					link = link->bnext;
+					continue;
+				}
+				if ((link->type == MT_MINOTAUR) &&
+					(link->special1 == mo->special1))
+				{
+					link = link->bnext;
+					continue;
+				}
+				if (netgame && !deathmatch && link->player)
+				{
+					link = link->bnext;
+					continue;
+				}
+				if (P_CheckSight(mo, link))
+				{
+					return link;
+				}
+			}
+			link = link->bnext;
+		}
+		else if (mo->type == MT_MSTAFF_FX2)		// bloodscourge
+		{
+			if ((link->flags & MF_COUNTKILL ||
+				(link->player && link != mo->target))
+				&& !(link->flags2 & MF2_DORMANT))
+			{
+				if (!(link->flags & MF_SHOOTABLE))
+				{
+					link = link->bnext;
+					continue;
+				}
+				if (netgame && !deathmatch && link->player)
+				{
+					link = link->bnext;
+					continue;
+				}
+				else if (P_CheckSight(mo, link))
+				{
+					master = mo->target;
+					angle = R_PointToAngle2(master->x, master->y,
+								link->x, link->y) - master->angle;
+					angle >>= 24;
+					if (angle > 226 || angle < 30)
+					{
+						return link;
+					}
+				}
+			}
+			link = link->bnext;
+		}
+		else	// spirits
+		{
+			if ((link->flags & MF_COUNTKILL ||
+				(link->player && link != mo->target))
+				&& !(link->flags2 & MF2_DORMANT))
+			{
+				if (!(link->flags & MF_SHOOTABLE))
+				{
+					link = link->bnext;
+					continue;
+				}
+				if (netgame && !deathmatch && link->player)
+				{
+					link = link->bnext;
+					continue;
+				}
+				if (link == mo->target)
+				{
+					link = link->bnext;
+					continue;
+				}
+				else if (P_CheckSight(mo, link))
+				{
+					return link;
+				}
+			}
+			link = link->bnext;
+		}
+	}
+	return NULL;
+}
+
--- /dev/null
+++ b/p_mobj.c
@@ -1,0 +1,2491 @@
+
+//**************************************************************************
+//**
+//** p_mobj.c : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 491 $
+//** $Date: 2009-05-30 01:10:42 +0300 (Sat, 30 May 2009) $
+//**
+//**************************************************************************
+
+// HEADER FILES ------------------------------------------------------------
+
+#include "h2stdinc.h"
+#include "h2def.h"
+#include "p_local.h"
+#include "sounds.h"
+#include "soundst.h"
+
+// MACROS ------------------------------------------------------------------
+
+#define MAX_TID_COUNT		200
+
+// TYPES -------------------------------------------------------------------
+
+// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
+
+void G_PlayerReborn(int player);
+void P_MarkAsLeaving(mobj_t *corpse);
+
+// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
+
+void P_SpawnMapThing(mapthing_t *mthing);
+
+// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
+
+static void PlayerLandedOnThing(mobj_t *mo, mobj_t *onmobj);
+
+// EXTERNAL DATA DECLARATIONS ----------------------------------------------
+
+extern boolean	demorecording;
+extern boolean	demoplayback;
+extern mobj_t	LavaInflictor;
+
+extern fixed_t	attackrange;
+
+// PUBLIC DATA DEFINITIONS -------------------------------------------------
+
+mobjtype_t	PuffType;
+mobj_t		*MissileMobj;
+
+fixed_t FloatBobOffsets[64] =
+{
+	0, 51389, 102283, 152192,
+	200636, 247147, 291278, 332604,
+	370727, 405280, 435929, 462380,
+	484378, 501712, 514213, 521763,
+	524287, 521763, 514213, 501712,
+	484378, 462380, 435929, 405280,
+	370727, 332604, 291278, 247147,
+	200636, 152192, 102283, 51389,
+	-1, -51390, -102284, -152193,
+	-200637, -247148, -291279, -332605,
+	-370728, -405281, -435930, -462381,
+	-484380, -501713, -514215, -521764,
+	-524288, -521764, -514214, -501713,
+	-484379, -462381, -435930, -405280,
+	-370728, -332605, -291279, -247148,
+	-200637, -152193, -102284, -51389
+};
+
+// PRIVATE DATA DEFINITIONS ------------------------------------------------
+
+static int TIDList[MAX_TID_COUNT + 1];	/* +1 for termination marker */
+static mobj_t *TIDMobj[MAX_TID_COUNT];
+
+// CODE --------------------------------------------------------------------
+
+//==========================================================================
+//
+// P_SetMobjState
+//
+// Returns true if the mobj is still present.
+//
+//==========================================================================
+
+boolean P_SetMobjState(mobj_t *mobj, statenum_t state)
+{
+	state_t *st;
+
+	if (state == S_NULL)
+	{ // Remove mobj
+		mobj->state = NULL;
+		P_RemoveMobj(mobj);
+		return false;
+	}
+	st = &states[state];
+	mobj->state = st;
+	mobj->tics = st->tics;
+	mobj->sprite = st->sprite;
+	mobj->frame = st->frame;
+	if (st->action)
+	{ // Call action function
+		st->action(mobj, nil);
+	}
+	return true;
+}
+
+//==========================================================================
+//
+// P_SetMobjStateNF
+//
+// Same as P_SetMobjState, but does not call the state function.
+//
+//==========================================================================
+
+boolean P_SetMobjStateNF(mobj_t *mobj, statenum_t state)
+{
+	state_t *st;
+
+	if (state == S_NULL)
+	{ // Remove mobj
+		mobj->state = NULL;
+		P_RemoveMobj(mobj);
+		return false;
+	}
+	st = &states[state];
+	mobj->state = st;
+	mobj->tics = st->tics;
+	mobj->sprite = st->sprite;
+	mobj->frame = st->frame;
+	return true;
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC P_ExplodeMissile
+//
+//----------------------------------------------------------------------------
+
+void P_ExplodeMissile(mobj_t *mo)
+{
+	mo->momx = mo->momy = mo->momz = 0;
+	P_SetMobjState(mo, mobjinfo[mo->type].deathstate);
+	//mo->tics -= P_Random() & 3;
+	mo->flags &= ~MF_MISSILE;
+
+	switch (mo->type)
+	{
+	case MT_SORCBALL1:
+	case MT_SORCBALL2:
+	case MT_SORCBALL3:
+		S_StartSound(NULL, SFX_SORCERER_BIGBALLEXPLODE);
+		break;
+	case MT_SORCFX1:
+		S_StartSound(NULL, SFX_SORCERER_HEADSCREAM);
+		break;
+	default:
+		if (mo->info->deathsound)
+		{
+			S_StartSound(mo, mo->info->deathsound);
+		}
+		break;
+	}
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC P_FloorBounceMissile
+//
+//----------------------------------------------------------------------------
+
+static void P_FloorBounceMissile(mobj_t *mo)
+{
+	if (P_HitFloor(mo) >= FLOOR_LIQUID)
+	{
+		switch (mo->type)
+		{
+		case MT_SORCFX1:
+		case MT_SORCBALL1:
+		case MT_SORCBALL2:
+		case MT_SORCBALL3:
+			break;
+		default:
+			P_RemoveMobj(mo);
+			return;
+		}
+	}
+	switch (mo->type)
+	{
+	case MT_SORCFX1:
+		mo->momz = -mo->momz;		// no energy absorbed
+		break;
+	case MT_SGSHARD1:
+	case MT_SGSHARD2:
+	case MT_SGSHARD3:
+	case MT_SGSHARD4:
+	case MT_SGSHARD5:
+	case MT_SGSHARD6:
+	case MT_SGSHARD7:
+	case MT_SGSHARD8:
+	case MT_SGSHARD9:
+	case MT_SGSHARD0:
+		mo->momz = FixedMul(mo->momz, -0.3*FRACUNIT);
+		if (abs(mo->momz) < (FRACUNIT/2))
+		{
+			P_SetMobjState(mo, S_NULL);
+			return;
+		}
+		break;
+	default:
+		mo->momz = FixedMul(mo->momz, -0.7*FRACUNIT);
+		break;
+	}
+	mo->momx = 2*mo->momx/3;
+	mo->momy = 2*mo->momy/3;
+	if (mo->info->seesound)
+	{
+		switch (mo->type)
+		{
+		case MT_SORCBALL1:
+		case MT_SORCBALL2:
+		case MT_SORCBALL3:
+			if (!mo->args[0])
+				S_StartSound(mo, mo->info->seesound);
+			break;
+		default:
+			S_StartSound(mo, mo->info->seesound);
+			break;
+		}
+		S_StartSound(mo, mo->info->seesound);
+	}
+//	P_SetMobjState(mo, mobjinfo[mo->type].deathstate);
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC P_ThrustMobj
+//
+//----------------------------------------------------------------------------
+
+void P_ThrustMobj(mobj_t *mo, angle_t angle, fixed_t move)
+{
+	angle >>= ANGLETOFINESHIFT;
+	mo->momx += FixedMul(move, finecosine[angle]);
+	mo->momy += FixedMul(move, finesine[angle]);
+}
+
+//----------------------------------------------------------------------------
+//
+// FUNC P_FaceMobj
+//
+// Returns 1 if 'source' needs to turn clockwise, or 0 if 'source' needs
+// to turn counter clockwise.  'delta' is set to the amount 'source'
+// needs to turn.
+//
+//----------------------------------------------------------------------------
+
+int P_FaceMobj(mobj_t *source, mobj_t *target, angle_t *delta)
+{
+	angle_t diff;
+	angle_t angle1;
+	angle_t angle2;
+
+	angle1 = source->angle;
+	angle2 = R_PointToAngle2(source->x, source->y, target->x, target->y);
+	if (angle2 > angle1)
+	{
+		diff = angle2 - angle1;
+		if (diff > ANGLE_180)
+		{
+			*delta = ANGLE_MAX - diff;
+			return 0;
+		}
+		else
+		{
+			*delta = diff;
+			return 1;
+		}
+	}
+	else
+	{
+		diff = angle1 - angle2;
+		if (diff > ANGLE_180)
+		{
+			*delta = ANGLE_MAX - diff;
+			return 1;
+		}
+		else
+		{
+			*delta = diff;
+			return 0;
+		}
+	}
+}
+
+//----------------------------------------------------------------------------
+//
+//
+// The missile special1 field must be mobj_t *target.  Returns true if
+// target was tracked, false if not.
+//
+//----------------------------------------------------------------------------
+
+boolean P_SeekerMissile(mobj_t *actor, angle_t thresh, angle_t turnMax)
+{
+	int dir;
+	int dist;
+	angle_t delta;
+	angle_t angle;
+	mobj_t *target;
+
+	target = (mobj_t *)actor->special1;
+	if (target == NULL)
+	{
+		return false;
+	}
+	if (!(target->flags & MF_SHOOTABLE))
+	{ // Target died
+		actor->special1 = 0;
+		return false;
+	}
+	dir = P_FaceMobj(actor, target, &delta);
+	if (delta > thresh)
+	{
+		delta >>= 1;
+		if (delta > turnMax)
+		{
+			delta = turnMax;
+		}
+	}
+	if (dir)
+	{ // Turn clockwise
+		actor->angle += delta;
+	}
+	else
+	{ // Turn counter clockwise
+		actor->angle -= delta;
+	}
+	angle = actor->angle>>ANGLETOFINESHIFT;
+	actor->momx = FixedMul(actor->info->speed, finecosine[angle]);
+	actor->momy = FixedMul(actor->info->speed, finesine[angle]);
+	if (actor->z + actor->height < target->z
+		|| target->z + target->height < actor->z)
+	{ // Need to seek vertically
+		dist = P_AproxDistance(target->x - actor->x, target->y - actor->y);
+		dist = dist/actor->info->speed;
+		if (dist < 1)
+		{
+			dist = 1;
+		}
+		actor->momz = (target->z + (target->height>>1)
+				- (actor->z + (actor->height>>1)))/dist;
+	}
+	return true;
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC P_XYMovement
+//
+//----------------------------------------------------------------------------
+
+#define STOPSPEED		0x1000
+#define FRICTION_NORMAL		0xe800
+#define FRICTION_LOW		0xf900
+#define FRICTION_FLY		0xeb00
+
+static void P_XYMovement(mobj_t *mo)
+{
+	fixed_t ptryx, ptryy;
+	player_t *player;
+	fixed_t xmove, ymove;
+	int special;
+	angle_t angle;
+	static int windTab[3] = {2048*5, 2048*10, 2048*25};
+
+	if (!mo->momx && !mo->momy)
+	{
+		if (mo->flags & MF_SKULLFLY)
+		{ // A flying mobj slammed into something
+			mo->flags &= ~MF_SKULLFLY;
+			mo->momx = mo->momy = mo->momz = 0;
+			P_SetMobjState(mo, mo->info->seestate);
+		}
+		return;
+	}
+	special = mo->subsector->sector->special;
+	if (mo->flags2 & MF2_WINDTHRUST)
+	{
+		switch (special)
+		{
+		case 40: case 41: case 42: // Wind_East
+			P_ThrustMobj(mo, 0, windTab[special-40]);
+			break;
+		case 43: case 44: case 45: // Wind_North
+			P_ThrustMobj(mo, ANG90, windTab[special-43]);
+			break;
+		case 46: case 47: case 48: // Wind_South
+			P_ThrustMobj(mo, ANG270, windTab[special-46]);
+			break;
+		case 49: case 50: case 51: // Wind_West
+			P_ThrustMobj(mo, ANG180, windTab[special-49]);
+			break;
+		}
+	}
+	player = mo->player;
+	if (mo->momx > MAXMOVE)
+	{
+		mo->momx = MAXMOVE;
+	}
+	else if (mo->momx < -MAXMOVE)
+	{
+		mo->momx = -MAXMOVE;
+	}
+	if (mo->momy > MAXMOVE)
+	{
+		mo->momy = MAXMOVE;
+	}
+	else if (mo->momy < -MAXMOVE)
+	{
+		mo->momy = -MAXMOVE;
+	}
+	xmove = mo->momx;
+	ymove = mo->momy;
+	do
+	{
+		if (xmove > MAXMOVE/2 || ymove > MAXMOVE/2)
+		{
+			ptryx = mo->x + xmove/2;
+			ptryy = mo->y + ymove/2;
+			xmove >>= 1;
+			ymove >>= 1;
+		}
+		else
+		{
+			ptryx = mo->x + xmove;
+			ptryy = mo->y + ymove;
+			xmove = ymove = 0;
+		}
+		if (!P_TryMove(mo, ptryx, ptryy))
+		{ // Blocked move
+			if (mo->flags2 & MF2_SLIDE)
+			{ // Try to slide along it
+				if (BlockingMobj == NULL)
+				{ // Slide against wall
+					P_SlideMove(mo);
+				}
+				else
+				{ // Slide against mobj
+					//if (P_TryMove(mo, mo->x, mo->y + mo->momy))
+					if (P_TryMove(mo, mo->x, ptryy))
+					{
+						mo->momx = 0;
+					}
+					//else if (P_TryMove(mo, mo->x + mo->momx, mo->y))
+					else if (P_TryMove(mo, ptryx, mo->y))
+					{
+						mo->momy = 0;
+					}
+					else
+					{
+						mo->momx = mo->momy = 0;
+					}
+				}
+			}
+			else if (mo->flags & MF_MISSILE)
+			{
+				if (mo->flags2 & MF2_FLOORBOUNCE)
+				{
+					if (BlockingMobj)
+					{
+						if ((BlockingMobj->flags2 & MF2_REFLECTIVE) ||
+							((!BlockingMobj->player) &&
+							(!(BlockingMobj->flags & MF_COUNTKILL))))
+						{
+							fixed_t speed;
+
+							angle = R_PointToAngle2(BlockingMobj->x,
+										BlockingMobj->y, mo->x, mo->y)
+								+ ANGLE_1*((P_Random() % 16) - 8);
+							speed = P_AproxDistance(mo->momx, mo->momy);
+							speed = FixedMul(speed, 0.75*FRACUNIT);
+							mo->angle = angle;
+							angle >>= ANGLETOFINESHIFT;
+							mo->momx = FixedMul(speed, finecosine[angle]);
+							mo->momy = FixedMul(speed, finesine[angle]);
+							if (mo->info->seesound)
+							{
+								S_StartSound(mo, mo->info->seesound);
+							}
+							return;
+						}
+						else
+						{ // Struck a player/creature
+ 							P_ExplodeMissile(mo);
+						}
+					}
+					else
+					{ // Struck a wall
+						P_BounceWall(mo);
+						switch (mo->type)
+						{
+						case MT_SORCBALL1:
+						case MT_SORCBALL2:
+						case MT_SORCBALL3:
+						case MT_SORCFX1:
+							break;
+						default:
+							if (mo->info->seesound)
+							{
+								S_StartSound(mo, mo->info->seesound);
+							}
+							break;
+						}
+						return;
+					}
+				}
+				if (BlockingMobj &&
+					(BlockingMobj->flags2 & MF2_REFLECTIVE))
+				{
+					angle = R_PointToAngle2(BlockingMobj->x,
+								BlockingMobj->y,
+								mo->x, mo->y);
+
+					// Change angle for delflection/reflection
+					switch (BlockingMobj->type)
+					{
+					case MT_CENTAUR:
+					case MT_CENTAURLEADER:
+						if (abs(angle - BlockingMobj->angle)>>24 > 45)
+							goto explode;
+						if (mo->type == MT_HOLY_FX)
+							goto explode;
+							// Drop through to sorcerer full reflection
+					case MT_SORCBOSS:
+						// Deflection
+						if (P_Random() < 128)
+							angle += ANGLE_45;
+						else
+							angle -= ANGLE_45;
+						break;
+					default:
+						// Reflection
+						angle += ANGLE_1 * ((P_Random() % 16) - 8);
+						break;
+					}
+
+					// Reflect the missile along angle
+					mo->angle = angle;
+					angle >>= ANGLETOFINESHIFT;
+					mo->momx = FixedMul(mo->info->speed>>1, finecosine[angle]);
+					mo->momy = FixedMul(mo->info->speed>>1, finesine[angle]);
+				//	mo->momz = -mo->momz;
+					if (mo->flags2 & MF2_SEEKERMISSILE)
+					{
+						mo->special1 = (intptr_t)(mo->target);
+					}
+					mo->target = BlockingMobj;
+					return;
+				}
+explode:
+				// Explode a missile
+				if (ceilingline && ceilingline->backsector
+					&& ceilingline->backsector->ceilingpic == skyflatnum)
+				{ // Hack to prevent missiles exploding against the sky
+					if (mo->type == MT_BLOODYSKULL)
+					{
+						mo->momx = mo->momy = 0;
+						mo->momz = -FRACUNIT;
+					}
+					else if (mo->type == MT_HOLY_FX)
+					{
+						P_ExplodeMissile(mo);
+					}
+					else
+					{
+						P_RemoveMobj(mo);
+					}
+					return;
+				}
+				P_ExplodeMissile(mo);
+			}
+			//else if (mo->info->crashstate)
+			//{
+			//	mo->momx = mo->momy = 0;
+			//	P_SetMobjState(mo, mo->info->crashstate);
+			//	return;
+			//}
+			else
+			{
+				mo->momx = mo->momy = 0;
+			}
+		}
+	} while (xmove || ymove);
+
+	// Friction
+
+	if (player && player->cheats & CF_NOMOMENTUM)
+	{ // Debug option for no sliding at all
+		mo->momx = mo->momy = 0;
+		return;
+	}
+	if (mo->flags & (MF_MISSILE|MF_SKULLFLY))
+	{ // No friction for missiles
+		return;
+	}
+	if (mo->z > mo->floorz && !(mo->flags2 & MF2_FLY) && !(mo->flags2 & MF2_ONMOBJ))
+	{ // No friction when falling
+		if (mo->type != MT_BLASTEFFECT)
+			return;
+	}
+	if (mo->flags & MF_CORPSE)
+	{ // Don't stop sliding if halfway off a step with some momentum
+		if (mo->momx > FRACUNIT/4 || mo->momx < -FRACUNIT/4
+			|| mo->momy > FRACUNIT/4 || mo->momy < -FRACUNIT/4)
+		{
+			if (mo->floorz != mo->subsector->sector->floorheight)
+			{
+				return;
+			}
+		}
+	}
+	if (mo->momx > -STOPSPEED && mo->momx < STOPSPEED
+		&& mo->momy > -STOPSPEED && mo->momy < STOPSPEED
+		&& (!player || (player->cmd.forwardmove == 0
+				&& player->cmd.sidemove == 0)) )
+	{ // If in a walking frame, stop moving
+		if (player)
+		{
+			if ((unsigned)((player->mo->state - states)
+					- PStateRun[player->playerclass]) < 4)
+			{
+				P_SetMobjState(player->mo, PStateNormal[player->playerclass]);
+			}
+		}
+		mo->momx = 0;
+		mo->momy = 0;
+	}
+	else
+	{
+		if (mo->flags2 & MF2_FLY && !(mo->z <= mo->floorz)
+					 && !(mo->flags2 & MF2_ONMOBJ))
+		{
+			mo->momx = FixedMul(mo->momx, FRICTION_FLY);
+			mo->momy = FixedMul(mo->momy, FRICTION_FLY);
+		}
+		else if (P_GetThingFloorType(mo) == FLOOR_ICE)
+		{
+			mo->momx = FixedMul(mo->momx, FRICTION_LOW);
+			mo->momy = FixedMul(mo->momy, FRICTION_LOW);
+		}
+		else
+		{
+			mo->momx = FixedMul(mo->momx, FRICTION_NORMAL);
+			mo->momy = FixedMul(mo->momy, FRICTION_NORMAL);
+		}
+	}
+}
+
+
+// Move this to p_inter ***
+static void P_MonsterFallingDamage(mobj_t *mo)
+{
+	int damage;
+	int mom;
+
+	mom = abs(mo->momz);
+	if (mom > 35*FRACUNIT)
+	{ // automatic death
+		damage = 10000;
+	}
+	else
+	{
+		damage = ((mom - (23*FRACUNIT) )*6)>>FRACBITS;
+	}
+	damage = 10000;	// always kill 'em
+	P_DamageMobj(mo, NULL, NULL, damage);
+}
+
+
+/*
+===============
+=
+= P_ZMovement
+=
+===============
+*/
+
+static void P_ZMovement(mobj_t *mo)
+{
+	int dist;
+	int delta;
+//
+// check for smooth step up
+//
+	if (mo->player && mo->z < mo->floorz)
+	{
+		mo->player->viewheight -= mo->floorz-mo->z;
+		mo->player->deltaviewheight = (VIEWHEIGHT - mo->player->viewheight)>>3;
+	}
+//
+// adjust height
+//
+	mo->z += mo->momz;
+	if (mo->flags & MF_FLOAT && mo->target)
+	{	// float down towards target if too close
+		if (!(mo->flags & MF_SKULLFLY) && !(mo->flags & MF_INFLOAT))
+		{
+			dist = P_AproxDistance(mo->x - mo->target->x, mo->y - mo->target->y);
+			delta = (mo->target->z + (mo->height>>1)) - mo->z;
+			if (delta < 0 && dist < -(delta*3))
+				mo->z -= FLOATSPEED;
+			else if (delta > 0 && dist < (delta*3))
+				mo->z += FLOATSPEED;
+		}
+	}
+	if (mo->player && mo->flags2 & MF2_FLY && !(mo->z <= mo->floorz)
+		&& leveltime & 2)
+	{
+		mo->z += finesine[(FINEANGLES/20*leveltime>>2) & FINEMASK];
+	}
+
+//
+// clip movement
+//
+	if (mo->z <= mo->floorz)
+	{	// Hit the floor
+		if (mo->flags & MF_MISSILE)
+		{
+			mo->z = mo->floorz;
+			if (mo->flags2 & MF2_FLOORBOUNCE)
+			{
+				P_FloorBounceMissile(mo);
+				return;
+			}
+			else if (mo->type == MT_HOLY_FX)
+			{ // The spirit struck the ground
+				mo->momz = 0;
+				P_HitFloor(mo);
+				return;
+			}
+			else if (mo->type == MT_MNTRFX2 || mo->type == MT_LIGHTNING_FLOOR)
+			{ // Minotaur floor fire can go up steps
+				return;
+			}
+			else
+			{
+				P_HitFloor(mo);
+				P_ExplodeMissile(mo);
+				return;
+			}
+		}
+		if (mo->flags & MF_COUNTKILL)		// Blasted mobj falling
+		{
+			if (mo->momz < -(23*FRACUNIT))
+			{
+				P_MonsterFallingDamage(mo);
+			}
+		}
+		if (mo->z-mo->momz > mo->floorz)
+		{ // Spawn splashes, etc.
+			P_HitFloor(mo);
+		}
+		mo->z = mo->floorz;
+		if (mo->momz < 0)
+		{
+			if (mo->flags2 & MF2_ICEDAMAGE && mo->momz < -GRAVITY*8)
+			{
+				mo->tics = 1;
+				mo->momx = 0;
+				mo->momy = 0;
+				mo->momz = 0;
+				return;
+			}
+			if (mo->player)
+			{
+				mo->player->jumpTics = 7;// delay any jumping for a short time
+				if (mo->momz < -GRAVITY*8 && !(mo->flags2 & MF2_FLY))
+				{ // squat down
+					mo->player->deltaviewheight = mo->momz>>3;
+					if (mo->momz < -23*FRACUNIT)
+					{
+						P_FallingDamage(mo->player);
+						P_NoiseAlert(mo, mo);
+					}
+					else if (mo->momz < -GRAVITY*12 && !mo->player->morphTics)
+					{
+						S_StartSound(mo, SFX_PLAYER_LAND);
+						switch (mo->player->playerclass)
+						{
+						case PCLASS_FIGHTER:
+							S_StartSound(mo, SFX_PLAYER_FIGHTER_GRUNT);
+							break;
+						case PCLASS_CLERIC:
+							S_StartSound(mo, SFX_PLAYER_CLERIC_GRUNT);
+							break;
+						case PCLASS_MAGE:
+							S_StartSound(mo, SFX_PLAYER_MAGE_GRUNT);
+							break;
+						default:
+							break;
+						}
+					}
+					else if ((P_GetThingFloorType(mo) < FLOOR_LIQUID) &&
+						 (!mo->player->morphTics) )
+					{
+						S_StartSound(mo, SFX_PLAYER_LAND);
+					}
+					if (mouselook && !demorecording && !demoplayback)
+					{
+						mo->player->centering = false;
+					}
+ 	 				else
+					{
+						mo->player->centering = true;
+					}
+				}
+			}
+			else if (mo->type >= MT_POTTERY1 &&
+				 mo->type <= MT_POTTERY3)
+			{
+				P_DamageMobj(mo, NULL, NULL, 25);
+			}
+			else if (mo->flags & MF_COUNTKILL)
+			{
+				if (mo->momz < -23*FRACUNIT)
+				{
+					// Doesn't get here
+				}
+			}
+			mo->momz = 0;
+		}
+		if (mo->flags & MF_SKULLFLY)
+		{ // The skull slammed into something
+			mo->momz = -mo->momz;
+		}
+		if (mo->info->crashstate &&
+			(mo->flags & MF_CORPSE) &&
+			!(mo->flags2 & MF2_ICEDAMAGE))
+		{
+			P_SetMobjState(mo, mo->info->crashstate);
+			return;
+		}
+	}
+	else if (mo->flags2 & MF2_LOGRAV)
+	{
+		if (mo->momz == 0)
+			mo->momz = -(GRAVITY>>3)*2;
+		else
+			mo->momz -= GRAVITY>>3;
+	}
+	else if (! (mo->flags & MF_NOGRAVITY))
+	{
+		if (mo->momz == 0)
+			mo->momz = -GRAVITY*2;
+		else
+			mo->momz -= GRAVITY;
+	}
+
+	if (mo->z + mo->height > mo->ceilingz)
+	{	// hit the ceiling
+		if (mo->momz > 0)
+			mo->momz = 0;
+		mo->z = mo->ceilingz - mo->height;
+		if (mo->flags2 & MF2_FLOORBOUNCE)
+		{
+			// Maybe reverse momentum here for ceiling bounce
+			// Currently won't happen
+			if (mo->info->seesound)
+			{
+				S_StartSound(mo, mo->info->seesound);
+			}
+			return;
+		}
+		if (mo->flags & MF_SKULLFLY)
+		{	// the skull slammed into something
+			mo->momz = -mo->momz;
+		}
+		if (mo->flags & MF_MISSILE)
+		{
+			if (mo->type == MT_LIGHTNING_CEILING)
+			{
+				return;
+			}
+			if (mo->subsector->sector->ceilingpic == skyflatnum)
+			{
+				if (mo->type == MT_BLOODYSKULL)
+				{
+					mo->momx = mo->momy = 0;
+					mo->momz = -FRACUNIT;
+				}
+				else if (mo->type == MT_HOLY_FX)
+				{
+					P_ExplodeMissile(mo);
+				}
+				else
+				{
+					P_RemoveMobj(mo);
+				}
+				return;
+			}
+			P_ExplodeMissile(mo);
+			return;
+		}
+	}
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC P_BlasterMobjThinker
+//
+//
+//----------------------------------------------------------------------------
+
+void P_BlasterMobjThinker(mobj_t *mobj)
+{
+	int i;
+	fixed_t xfrac;
+	fixed_t yfrac;
+	fixed_t zfrac;
+	fixed_t z;
+	boolean changexy;
+	mobj_t *mo;
+
+	// Handle movement
+	if (mobj->momx || mobj->momy ||
+		(mobj->z != mobj->floorz) || mobj->momz)
+	{
+		xfrac = mobj->momx>>3;
+		yfrac = mobj->momy>>3;
+		zfrac = mobj->momz>>3;
+		changexy = xfrac || yfrac;
+		for (i = 0; i < 8; i++)
+		{
+			if (changexy)
+			{
+				if (!P_TryMove(mobj, mobj->x + xfrac, mobj->y + yfrac))
+				{ // Blocked move
+					P_ExplodeMissile(mobj);
+					return;
+				}
+			}
+			mobj->z += zfrac;
+			if (mobj->z <= mobj->floorz)
+			{ // Hit the floor
+				mobj->z = mobj->floorz;
+				P_HitFloor(mobj);
+				P_ExplodeMissile(mobj);
+				return;
+			}
+			if (mobj->z+mobj->height > mobj->ceilingz)
+			{ // Hit the ceiling
+				mobj->z = mobj->ceilingz-mobj->height;
+				P_ExplodeMissile(mobj);
+				return;
+			}
+			if (changexy)
+			{
+				if (mobj->type == MT_MWAND_MISSILE && (P_Random() < 128))
+				{
+					z = mobj->z - 8*FRACUNIT;
+					if (z < mobj->floorz)
+					{
+						z = mobj->floorz;
+					}
+					P_SpawnMobj(mobj->x, mobj->y, z, MT_MWANDSMOKE);
+				}
+				/*
+				else if (!--mobj->special1)
+
+				jim- allow other things to have BlasterMobjThinker()s (crossbow)
+
+				O.S- FIXME ---	I DON'T NEED AN #ifdef ASSASSIN here, YES ???
+					(also see jim's note in P_CheckMissileSpawn down below.)
+				*/
+				else if ((mobj->type == MT_CFLAME_MISSILE) && !--mobj->special1)
+				{
+					mobj->special1 = 4;
+					z = mobj->z-12*FRACUNIT;
+					if (z < mobj->floorz)
+					{
+						z = mobj->floorz;
+					}
+					mo = P_SpawnMobj(mobj->x, mobj->y, z, MT_CFLAMEFLOOR);
+					if (mo)
+					{
+						mo->angle = mobj->angle;
+					}
+				}
+			}
+		}
+	}
+	// Advance the state
+	if (mobj->tics != -1)
+	{
+		mobj->tics--;
+		while (!mobj->tics)
+		{
+			if (!P_SetMobjState(mobj, mobj->state->nextstate))
+			{ // mobj was removed
+				return;
+			}
+		}
+	}
+}
+
+//===========================================================================
+//
+// PlayerLandedOnThing
+//
+//===========================================================================
+
+static void PlayerLandedOnThing(mobj_t *mo, mobj_t *onmobj)
+{
+	mo->player->deltaviewheight = mo->momz>>3;
+	if (mo->momz < -23*FRACUNIT)
+	{
+		P_FallingDamage(mo->player);
+		P_NoiseAlert(mo, mo);
+	}
+	else if (mo->momz < -GRAVITY*12 &&
+		 !mo->player->morphTics)
+	{
+		S_StartSound(mo, SFX_PLAYER_LAND);
+		switch (mo->player->playerclass)
+		{
+		case PCLASS_FIGHTER:
+			S_StartSound(mo, SFX_PLAYER_FIGHTER_GRUNT);
+			break;
+		case PCLASS_CLERIC:
+			S_StartSound(mo, SFX_PLAYER_CLERIC_GRUNT);
+			break;
+		case PCLASS_MAGE:
+			S_StartSound(mo, SFX_PLAYER_MAGE_GRUNT);
+			break;
+		default:
+			break;
+		}
+	}
+	else if (!mo->player->morphTics)
+	{
+		S_StartSound(mo, SFX_PLAYER_LAND);
+	}
+	if (mouselook && !demorecording && !demoplayback)
+	{
+		mo->player->centering = false;
+	}
+	else
+	{
+		mo->player->centering = true;
+	}
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC P_MobjThinker
+//
+//----------------------------------------------------------------------------
+
+void P_MobjThinker(mobj_t *mobj)
+{
+	mobj_t *onmo;
+
+	/*
+	// Reset to not blasted when momentums are gone
+	if ((mobj->flags2 & MF2_BLASTED) && (!(mobj->momx)) && (!(mobj->momy)))
+		ResetBlasted(mobj);
+	*/
+
+	// Handle X and Y momentums
+	BlockingMobj = NULL;
+	if (mobj->momx || mobj->momy || (mobj->flags & MF_SKULLFLY))
+	{
+		P_XYMovement(mobj);
+		if (mobj->thinker.function == (think_t)-1)
+		{ // mobj was removed
+			return;
+		}
+	}
+	else if (mobj->flags2 & MF2_BLASTED)
+	{ // Reset to not blasted when momentums are gone
+		ResetBlasted(mobj);
+	}
+	if (mobj->flags2 & MF2_FLOATBOB)
+	{ // Floating item bobbing motion (special1 is height)
+		mobj->z = mobj->floorz + mobj->special1 +
+				FloatBobOffsets[(mobj->health++) & 63];
+	}
+	else if ((mobj->z != mobj->floorz) || mobj->momz || BlockingMobj)
+	{	// Handle Z momentum and gravity
+		if (mobj->flags2 & MF2_PASSMOBJ)
+		{
+			if (!(onmo = P_CheckOnmobj(mobj)))
+			{
+				P_ZMovement(mobj);
+				if (mobj->player && mobj->flags & MF2_ONMOBJ)
+				{
+					mobj->flags2 &= ~MF2_ONMOBJ;
+				}
+			}
+			else
+			{
+				if (mobj->player)
+				{
+					if (mobj->momz < -GRAVITY*8 && !(mobj->flags2 & MF2_FLY))
+					{
+						PlayerLandedOnThing(mobj, onmo);
+					}
+					if (onmo->z + onmo->height - mobj->z <= 24*FRACUNIT)
+					{
+						mobj->player->viewheight -= onmo->z + onmo->height
+											- mobj->z;
+						mobj->player->deltaviewheight = 
+							(VIEWHEIGHT - mobj->player->viewheight)>>3;
+						mobj->z = onmo->z + onmo->height;
+						mobj->flags2 |= MF2_ONMOBJ;
+						mobj->momz = 0;
+					}
+					else
+					{ // hit the bottom of the blocking mobj
+						mobj->momz = 0;
+					}
+				}
+				/* Landing on another player, and mimicking his movements
+				if (mobj->player && onmo->player)
+				{
+					mobj->momx = onmo->momx;
+					mobj->momy = onmo->momy;
+					if (onmo->z < onmo->floorz)
+					{
+						mobj->z += onmo->floorz-onmo->z;
+						if (onmo->player)
+						{
+							onmo->player->viewheight -= onmo->floorz - onmo->z;
+							onmo->player->deltaviewheight = 
+								(VIEWHEIGHT - onmo->player->viewheight)>>3;
+						}
+						onmo->z = onmo->floorz;
+					}
+				}
+				*/
+			}
+		}
+		else
+		{
+			P_ZMovement(mobj);
+		}
+		if (mobj->thinker.function == (think_t)-1)
+		{ // mobj was removed
+			return;
+		}
+	}
+
+	// Cycle through states, calling action functions at transitions
+	if (mobj->tics != -1)
+	{
+		mobj->tics--;
+		// you can cycle through multiple states in a tic
+		while (!mobj->tics)
+		{
+			if (!P_SetMobjState(mobj, mobj->state->nextstate))
+			{ // mobj was removed
+				return;
+			}
+		}
+	}
+}
+
+//==========================================================================
+//
+// P_SpawnMobj
+//
+//==========================================================================
+
+mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type)
+{
+	mobj_t *mobj;
+	state_t *st;
+	mobjinfo_t *info;
+	fixed_t space;
+
+	mobj = (mobj_t *) Z_Malloc(sizeof(*mobj), PU_LEVEL, NULL);
+	memset(mobj, 0, sizeof(*mobj));
+	info = &mobjinfo[type];
+	mobj->type = type;
+	mobj->info = info;
+	mobj->x = x;
+	mobj->y = y;
+	mobj->radius = info->radius;
+	mobj->height = info->height;
+	mobj->flags = info->flags;
+	mobj->flags2 = info->flags2;
+	mobj->damage = info->damage;
+	mobj->health = info->spawnhealth;
+	if (gameskill != sk_nightmare)
+	{
+		mobj->reactiontime = info->reactiontime;
+	}
+	mobj->lastlook = P_Random() % MAXPLAYERS;
+
+	// Set the state, but do not use P_SetMobjState, because action
+	// routines can't be called yet.  If the spawnstate has an action
+	// routine, it will not be called.
+	st = &states[info->spawnstate];
+	mobj->state = st;
+	mobj->tics = st->tics;
+	mobj->sprite = st->sprite;
+	mobj->frame = st->frame;
+
+	// Set subsector and/or block links.
+	P_SetThingPosition(mobj);
+	mobj->floorz = mobj->subsector->sector->floorheight;
+	mobj->ceilingz = mobj->subsector->sector->ceilingheight;
+	if (z == ONFLOORZ)
+	{
+		mobj->z = mobj->floorz;
+	}
+	else if (z == ONCEILINGZ)
+	{
+		mobj->z = mobj->ceilingz-mobj->info->height;
+	}
+	else if (z == FLOATRANDZ)
+	{
+		space = ((mobj->ceilingz)-(mobj->info->height))-mobj->floorz;
+		if (space > 48*FRACUNIT)
+		{
+			space -= 40*FRACUNIT;
+			mobj->z = ((space*P_Random())>>8) + mobj->floorz + 40*FRACUNIT;
+		}
+		else
+		{
+			mobj->z = mobj->floorz;
+		}
+	}
+	else if (mobj->flags2 & MF2_FLOATBOB)
+	{
+		mobj->z = mobj->floorz + z;		// artifact z passed in as height
+	}
+	else
+	{
+		mobj->z = z;
+	}
+	if (mobj->flags2 & MF2_FLOORCLIP && P_GetThingFloorType(mobj) >= FLOOR_LIQUID
+		&& mobj->z == mobj->subsector->sector->floorheight)
+	{
+		mobj->floorclip = 10*FRACUNIT;
+	}
+	else
+	{
+		mobj->floorclip = 0;
+	}
+
+	mobj->thinker.function = P_MobjThinker;
+	P_AddThinker(&mobj->thinker);
+	return (mobj);
+}
+
+//==========================================================================
+//
+// P_RemoveMobj
+//
+//==========================================================================
+
+void P_RemoveMobj(mobj_t *mobj)
+{
+	// Remove from creature queue
+	if (mobj->flags & MF_COUNTKILL &&
+		mobj->flags & MF_CORPSE)
+	{
+		A_DeQueueCorpse(mobj);
+	}
+
+	if (mobj->tid)
+	{ // Remove from TID list
+		P_RemoveMobjFromTIDList(mobj);
+	}
+
+	// Unlink from sector and block lists
+	P_UnsetThingPosition(mobj);
+
+	// Stop any playing sound
+	S_StopSound(mobj);
+
+	// Free block
+	P_RemoveThinker((thinker_t *)mobj);
+}
+
+//==========================================================================
+//
+// P_SpawnPlayer
+//
+// Called when a player is spawned on the level.  Most of the player
+// structure stays unchanged between levels.
+//
+//==========================================================================
+
+void P_SpawnPlayer(mapthing_t *mthing)
+{
+	player_t *p;
+	fixed_t x, y, z;
+	mobj_t *mobj;
+
+	if (!playeringame[mthing->type - 1])
+	{ // Not playing
+		return;
+	}
+	p = &players[mthing->type - 1];
+	if (p->playerstate == PST_REBORN)
+	{
+		G_PlayerReborn(mthing->type - 1);
+	}
+	x = mthing->x << FRACBITS;
+	y = mthing->y << FRACBITS;
+	z = ONFLOORZ;
+	if (randomclass && deathmatch)
+	{
+		p->playerclass = P_Random() % NUMCLASSES_HUMAN;
+		if (p->playerclass == PlayerClasses[mthing->type - 1])
+		{
+			p->playerclass = (p->playerclass + 1) % NUMCLASSES_HUMAN;
+		}
+		PlayerClasses[mthing->type - 1] = p->playerclass;
+		SB_SetClassData();
+	}
+	else
+	{
+		p->playerclass = PlayerClasses[mthing->type - 1];
+	}
+	switch (p->playerclass)
+	{
+	case PCLASS_FIGHTER:
+		mobj = P_SpawnMobj(x, y, z, MT_PLAYER_FIGHTER);
+		break;
+	case PCLASS_CLERIC:
+		mobj = P_SpawnMobj(x, y, z, MT_PLAYER_CLERIC);
+		break;
+	case PCLASS_MAGE:
+		mobj = P_SpawnMobj(x, y, z, MT_PLAYER_MAGE);
+		break;
+#ifdef ASSASSIN
+	case PCLASS_ASS:
+		mobj = P_SpawnMobj(x, y, z, MT_PLAYER_ASS);
+		break;
+#endif
+	default:
+		I_Error("P_SpawnPlayer: Unknown class type");
+		mobj = NULL;	/* avoid compiler warning */
+		break;
+	}
+
+	// Set translation table data
+	if (p->playerclass == PCLASS_FIGHTER && (mthing->type == 1 || mthing->type == 3))
+	{
+		// The first type should be blue, and the third should be the
+		// Fighter's original gold color
+		if (mthing->type == 1)
+		{
+			mobj->flags |= 2<<MF_TRANSSHIFT;
+		}
+	}
+	else if (mthing->type > 1)
+	{ // Set color translation bits for player sprites
+		mobj->flags |= (mthing->type - 1)<<MF_TRANSSHIFT;
+	}
+
+	mobj->angle = ANG45 * (mthing->angle/45);
+	mobj->player = p;
+	mobj->health = p->health;
+	p->mo = mobj;
+	p->playerstate = PST_LIVE;
+	p->refire = 0;
+	P_ClearMessage(p);
+	p->damagecount = 0;
+	p->bonuscount = 0;
+	p->poisoncount = 0;
+	p->morphTics = 0;
+	p->extralight = 0;
+	p->fixedcolormap = 0;
+	p->viewheight = VIEWHEIGHT;
+	P_SetupPsprites(p);
+	if (deathmatch)
+	{ // Give all keys in death match mode
+		p->keys = 2047;
+	}
+}
+
+//==========================================================================
+//
+// P_SpawnMapThing
+//
+// The fields of the mapthing should already be in host byte order.
+//
+//==========================================================================
+
+void P_SpawnMapThing(mapthing_t *mthing)
+{
+	int i;
+	unsigned int spawnMask;
+	mobj_t *mobj;
+	fixed_t x, y, z;
+	// Put in Cleric twice, since we can't have an assassin flag.
+	static unsigned int classFlags[] =
+	{
+		MTF_FIGHTER,
+		MTF_CLERIC,
+		MTF_MAGE,
+#ifdef ASSASSIN
+		MTF_CLERIC
+#endif
+	};
+
+	// Count deathmatch start positions
+	if (mthing->type == 11)
+	{
+		if (deathmatch_p < &deathmatchstarts[MAXDEATHMATCHSTARTS])
+		{
+			memcpy(deathmatch_p, mthing, sizeof(*mthing));
+			deathmatch_p++;
+		}
+		return;
+	}
+	if (mthing->type == PO_ANCHOR_TYPE)
+	{ // Polyobj Anchor Pt.
+		return;
+	}
+	else if (mthing->type == PO_SPAWN_TYPE ||
+		 mthing->type == PO_SPAWNCRUSH_TYPE)
+	{ // Polyobj Anchor Pt.
+		po_NumPolyobjs++;
+		return;
+	}
+
+	// Check for player starts 1 to 4
+	if (mthing->type <= 4)
+	{
+		playerstarts[mthing->arg1][mthing->type - 1] = *mthing;
+		if (!deathmatch && !mthing->arg1)
+		{
+			P_SpawnPlayer(mthing);
+		}
+		return;
+	}
+	// Check for player starts 5 to 8
+	if (mthing->type >= 9100 && mthing->type <= 9103)
+	{
+		mthing->type = 5 + mthing->type - 9100; // Translate to 5 - 8
+		playerstarts[mthing->arg1][mthing->type - 1] = *mthing;
+		if (!deathmatch && !mthing->arg1)
+		{
+			P_SpawnPlayer(mthing);
+		}
+		return;
+	}
+
+	if (mthing->type >= 1400 && mthing->type < 1410)
+	{
+		R_PointInSubsector(mthing->x<<FRACBITS, 
+				mthing->y<<FRACBITS)->sector->seqType = mthing->type - 1400;
+		return;
+	}
+
+	// Check current game type with spawn flags
+	if (netgame == false)
+	{
+		spawnMask = MTF_GSINGLE;
+	}
+	else if (deathmatch)
+	{
+		spawnMask = MTF_GDEATHMATCH;
+	}
+	else
+	{
+		spawnMask = MTF_GCOOP;
+	}
+	if (!(mthing->options&spawnMask))
+	{
+		return;
+	}
+
+	// Check current skill with spawn flags
+	if (gameskill == sk_baby || gameskill == sk_easy)
+	{
+		spawnMask = MTF_EASY;
+	}
+	else if (gameskill == sk_hard || gameskill == sk_nightmare)
+	{
+		spawnMask = MTF_HARD;
+	}
+	else
+	{
+		spawnMask = MTF_NORMAL;
+	}
+	if (!(mthing->options&spawnMask))
+	{
+		return;
+	}
+
+	// Check current character classes with spawn flags
+	if (netgame == false)
+	{ // Single player
+		if ((mthing->options&classFlags[PlayerClasses[0]]) == 0)
+		{ // Not for current class
+			return;
+		}
+	}
+	else if (deathmatch == false)
+	{ // Cooperative
+		spawnMask = 0;
+		for (i = 0; i < MAXPLAYERS; i++)
+		{
+			if (playeringame[i])
+			{
+				spawnMask |= classFlags[PlayerClasses[i]];
+			}
+		}
+		if ((mthing->options&spawnMask) == 0)
+		{
+			return;
+		}
+	}
+
+	// Find which type to spawn
+	for (i = 0; i < NUMMOBJTYPES; i++)
+	{
+		if (mthing->type == mobjinfo[i].doomednum)
+		{
+			break;
+		}
+	}
+
+	if (i == NUMMOBJTYPES)
+	{ // Can't find thing type
+		I_Error("P_SpawnMapThing: Unknown type %i at (%i, %i)",
+				mthing->type, mthing->x, mthing->y);
+	}
+
+	// Don't spawn keys and players in deathmatch
+	if (deathmatch && mobjinfo[i].flags & MF_NOTDMATCH)
+	{
+		return;
+	}
+
+	// Don't spawn monsters if -nomonsters
+	if (nomonsters && (mobjinfo[i].flags & MF_COUNTKILL))
+	{
+		return;
+	}
+
+	x = mthing->x<<FRACBITS;
+	y = mthing->y<<FRACBITS;
+	if (mobjinfo[i].flags & MF_SPAWNCEILING)
+	{
+		z = ONCEILINGZ;
+	}
+	else if (mobjinfo[i].flags2 & MF2_SPAWNFLOAT)
+	{
+		z = FLOATRANDZ;
+	}
+	else if (mobjinfo[i].flags2 & MF2_FLOATBOB)
+	{
+		z = mthing->height<<FRACBITS;
+	}
+	else
+	{
+		z = ONFLOORZ;
+	}
+	switch (i)
+	{ // Special stuff
+	case MT_ZLYNCHED_NOHEART:
+		P_SpawnMobj(x, y, ONFLOORZ, MT_BLOODPOOL);
+		break;
+	default:
+		break;
+	}
+	mobj = P_SpawnMobj(x, y, z, i);
+	if (z == ONFLOORZ)
+	{
+		mobj->z += mthing->height<<FRACBITS;
+	}
+	else if (z == ONCEILINGZ)
+	{
+		mobj->z -= mthing->height<<FRACBITS;
+	}
+	mobj->tid = mthing->tid;
+	mobj->special = mthing->special;
+	mobj->args[0] = mthing->arg1;
+	mobj->args[1] = mthing->arg2;
+	mobj->args[2] = mthing->arg3;
+	mobj->args[3] = mthing->arg4;
+	mobj->args[4] = mthing->arg5;
+	if (mobj->flags2 & MF2_FLOATBOB)
+	{ // Seed random starting index for bobbing motion
+		mobj->health = P_Random();
+		mobj->special1 = mthing->height<<FRACBITS;
+	}
+	if (mobj->tics > 0)
+	{
+		mobj->tics = 1 + (P_Random() % mobj->tics);
+	}
+//	if (mobj->flags & MF_COUNTITEM)
+//	{
+//		totalitems++;
+//	}
+	if (mobj->flags & MF_COUNTKILL)
+	{
+		// Quantize angle to 45 degree increments
+		mobj->angle = ANG45*(mthing->angle/45);
+	}
+	else
+	{
+		// Scale angle correctly (source is 0..359)
+		mobj->angle = ((mthing->angle<<8)/360)<<24;
+	}
+	if (mthing->options & MTF_AMBUSH)
+	{
+		mobj->flags |= MF_AMBUSH;
+	}
+	if (mthing->options & MTF_DORMANT)
+	{
+		mobj->flags2 |= MF2_DORMANT;
+		if (mobj->type == MT_ICEGUY)
+		{
+			P_SetMobjState(mobj, S_ICEGUY_DORMANT);
+		}
+		mobj->tics = -1;
+	}
+}
+
+//==========================================================================
+//
+// P_CreateTIDList
+//
+//==========================================================================
+
+void P_CreateTIDList(void)
+{
+	int i;
+	mobj_t *mobj;
+	thinker_t *t;
+
+	i = 0;
+	for (t = thinkercap.next; t != &thinkercap; t = t->next)
+	{ // Search all current thinkers
+		if (t->function != P_MobjThinker)
+		{ // Not a mobj thinker
+			continue;
+		}
+		mobj = (mobj_t *)t;
+		if (mobj->tid != 0)
+		{ // Add to list
+			if (i == MAX_TID_COUNT)
+			{
+				I_Error("P_CreateTIDList: MAX_TID_COUNT (%d) exceeded.",
+									MAX_TID_COUNT);
+			}
+			TIDList[i] = mobj->tid;
+			TIDMobj[i++] = mobj;
+		}
+	}
+	// Add termination marker
+	TIDList[i] = 0;
+}
+
+//==========================================================================
+//
+// P_InsertMobjIntoTIDList
+//
+//==========================================================================
+
+void P_InsertMobjIntoTIDList(mobj_t *mobj, int tid)
+{
+	int i;
+	int idx;
+
+	idx = -1;
+	for (i = 0; TIDList[i] != 0; i++)
+	{
+		if (TIDList[i] == -1)
+		{ // Found empty slot
+			idx = i;
+			break;
+		}
+	}
+	if (idx == -1)
+	{ // Append required
+		if (i == MAX_TID_COUNT)
+		{
+			I_Error("P_InsertMobjIntoTIDList: MAX_TID_COUNT (%d)"
+				"exceeded.", MAX_TID_COUNT);
+		}
+		idx = i;
+		TIDList[idx + 1] = 0;
+	}
+	mobj->tid = tid;
+	TIDList[idx] = tid;
+	TIDMobj[idx] = mobj;
+}
+
+//==========================================================================
+//
+// P_RemoveMobjFromTIDList
+//
+//==========================================================================
+
+void P_RemoveMobjFromTIDList(mobj_t *mobj)
+{
+	int i;
+
+	for (i = 0; TIDList[i] != 0; i++)
+	{
+		if (TIDMobj[i] == mobj)
+		{
+			TIDList[i] = -1;
+			TIDMobj[i] = NULL;
+			mobj->tid = 0;
+			return;
+		}
+	}
+	mobj->tid = 0;
+}
+
+//==========================================================================
+//
+// P_FindMobjFromTID
+//
+//==========================================================================
+
+mobj_t *P_FindMobjFromTID(int tid, int *searchPosition)
+{
+	int i;
+
+	for (i = *searchPosition + 1; TIDList[i] != 0; i++)
+	{
+		if (TIDList[i] == tid)
+		{
+			*searchPosition = i;
+			return TIDMobj[i];
+		}
+	}
+	*searchPosition = -1;
+	return NULL;
+}
+
+/*
+===============================================================================
+
+						GAME SPAWN FUNCTIONS
+
+===============================================================================
+*/
+
+//---------------------------------------------------------------------------
+//
+// PROC P_SpawnPuff
+//
+//---------------------------------------------------------------------------
+
+void P_SpawnPuff(fixed_t x, fixed_t y, fixed_t z)
+{
+	mobj_t *puff;
+
+	z += ((P_Random() - P_Random()) << 10);
+	puff = P_SpawnMobj(x, y, z, PuffType);
+	if (linetarget && puff->info->seesound)
+	{ // Hit thing sound
+		S_StartSound(puff, puff->info->seesound);
+	}
+	else if (puff->info->attacksound)
+	{
+		S_StartSound(puff, puff->info->attacksound);
+	}
+	switch (PuffType)
+	{
+	case MT_PUNCHPUFF:
+		puff->momz = FRACUNIT;
+		break;
+	case MT_HAMMERPUFF:
+		puff->momz = .8*FRACUNIT;
+		break;
+	default:
+		break;
+	}
+	PuffSpawned = puff;
+}
+
+/*
+================
+=
+= P_SpawnBlood
+=
+================
+*/
+
+/*
+void P_SpawnBlood (fixed_t x, fixed_t y, fixed_t z, int damage)
+{
+	mobj_t	*th;
+
+	z += ((P_Random() - P_Random()) << 10);
+	th = P_SpawnMobj (x, y, z, MT_BLOOD);
+	th->momz = FRACUNIT*2;
+	th->tics -= P_Random() & 3;
+
+	if (damage <= 12 && damage >= 9)
+		P_SetMobjState (th, S_BLOOD2);
+	else if (damage < 9)
+		P_SetMobjState (th, S_BLOOD3);
+}
+*/
+
+//---------------------------------------------------------------------------
+//
+// PROC P_BloodSplatter
+//
+//---------------------------------------------------------------------------
+
+void P_BloodSplatter(fixed_t x, fixed_t y, fixed_t z, mobj_t *originator)
+{
+	mobj_t *mo;
+
+	mo = P_SpawnMobj(x, y, z, MT_BLOODSPLATTER);
+	mo->target = originator;
+	mo->momx = (P_Random() - P_Random()) << 10;
+	mo->momy = (P_Random() - P_Random()) << 10;
+	mo->momz = 3*FRACUNIT;
+}
+
+//===========================================================================
+//
+//  P_BloodSplatter2
+//
+//===========================================================================
+
+void P_BloodSplatter2(fixed_t x, fixed_t y, fixed_t z, mobj_t *originator)
+{
+	mobj_t *mo;
+
+	mo = P_SpawnMobj(x + ((P_Random() - 128) <<11),
+			 y + ((P_Random() - 128) <<11),
+			 z, MT_AXEBLOOD);
+	mo->target = originator;
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC P_RipperBlood
+//
+//---------------------------------------------------------------------------
+
+void P_RipperBlood(mobj_t *mo)
+{
+	mobj_t *th;
+	fixed_t x, y, z;
+
+	x = mo->x + ((P_Random() - P_Random()) <<12);
+	y = mo->y + ((P_Random() - P_Random()) <<12);
+	z = mo->z + ((P_Random() - P_Random()) <<12);
+	th = P_SpawnMobj(x, y, z, MT_BLOOD);
+//	th->flags |= MF_NOGRAVITY;
+	th->momx = mo->momx>>1;
+	th->momy = mo->momy>>1;
+	th->tics += P_Random() & 3;
+}
+
+//---------------------------------------------------------------------------
+//
+// FUNC P_GetThingFloorType
+//
+//---------------------------------------------------------------------------
+
+int P_GetThingFloorType(mobj_t *thing)
+{
+	if (thing->floorpic)
+	{
+		return(TerrainTypes[thing->floorpic]);
+	}
+	else
+	{
+		return(TerrainTypes[thing->subsector->sector->floorpic]);
+	}
+	/*
+	if (thing->subsector->sector->floorpic
+			== W_GetNumForName("FLTWAWA1") - firstflat)
+	{
+		return FLOOR_WATER;
+	}
+	else
+	{
+		return FLOOR_SOLID;
+	}
+	*/
+}
+
+//---------------------------------------------------------------------------
+//
+// FUNC P_HitFloor
+//
+//---------------------------------------------------------------------------
+
+#define SMALLSPLASHCLIP		(12 << FRACBITS)
+
+int P_HitFloor(mobj_t *thing)
+{
+	mobj_t *mo;
+	int smallsplash = false;
+
+	if (thing->floorz != thing->subsector->sector->floorheight)
+	{ // don't splash if landing on the edge above water/lava/etc....
+		return FLOOR_SOLID;
+	}
+
+	// Things that don't splash go here
+	switch (thing->type)
+	{
+	case MT_LEAF1:
+	case MT_LEAF2:
+//	case MT_BLOOD:			// I set these to low mass -- pm
+//	case MT_BLOODSPLATTER:
+	case MT_SPLASH:
+	case MT_SLUDGECHUNK:
+		return FLOOR_SOLID;
+	default:
+		break;
+	}
+
+	// Small splash for small masses
+	if (thing->info->mass < 10)
+		smallsplash = true;
+
+	switch (P_GetThingFloorType(thing))
+	{
+	case FLOOR_WATER:
+		if (smallsplash)
+		{
+			mo = P_SpawnMobj(thing->x, thing->y, ONFLOORZ, MT_SPLASHBASE);
+			if (mo)
+				mo->floorclip += SMALLSPLASHCLIP;
+			S_StartSound(mo, SFX_AMBIENT10);	// small drip
+		}
+		else
+		{
+			mo = P_SpawnMobj(thing->x, thing->y, ONFLOORZ, MT_SPLASH);
+			mo->target = thing;
+			mo->momx = (P_Random() - P_Random()) <<8;
+			mo->momy = (P_Random() - P_Random()) <<8;
+			mo->momz = 2*FRACUNIT + (P_Random() <<8);
+			mo = P_SpawnMobj(thing->x, thing->y, ONFLOORZ, MT_SPLASHBASE);
+			if (thing->player)
+				P_NoiseAlert(thing, thing);
+			S_StartSound(mo, SFX_WATER_SPLASH);
+		}
+		return FLOOR_WATER;
+
+	case FLOOR_LAVA:
+		if (smallsplash)
+		{
+			mo = P_SpawnMobj(thing->x, thing->y, ONFLOORZ, MT_LAVASPLASH);
+			if (mo)
+				mo->floorclip += SMALLSPLASHCLIP;
+		}
+		else
+		{
+			mo = P_SpawnMobj(thing->x, thing->y, ONFLOORZ, MT_LAVASMOKE);
+			mo->momz = FRACUNIT + (P_Random() << 7);
+			mo = P_SpawnMobj(thing->x, thing->y, ONFLOORZ, MT_LAVASPLASH);
+			if (thing->player)
+				P_NoiseAlert(thing, thing);
+		}
+		S_StartSound(mo, SFX_LAVA_SIZZLE);
+		if (thing->player && leveltime & 31)
+		{
+			P_DamageMobj(thing, &LavaInflictor, NULL, 5);
+		}
+		return FLOOR_LAVA;
+
+	case FLOOR_SLUDGE:
+		if (smallsplash)
+		{
+			mo = P_SpawnMobj(thing->x, thing->y, ONFLOORZ, MT_SLUDGESPLASH);
+			if (mo)
+				mo->floorclip += SMALLSPLASHCLIP;
+		}
+		else
+		{
+			mo = P_SpawnMobj(thing->x, thing->y, ONFLOORZ, MT_SLUDGECHUNK);
+			mo->target = thing;
+			mo->momx = (P_Random() - P_Random()) <<8;
+			mo->momy = (P_Random() - P_Random()) <<8;
+			mo->momz = FRACUNIT + (P_Random() <<8);
+			mo = P_SpawnMobj(thing->x, thing->y, ONFLOORZ, MT_SLUDGESPLASH);
+			if (thing->player)
+				P_NoiseAlert(thing, thing);
+		}
+		S_StartSound(mo, SFX_SLUDGE_GLOOP);
+		return FLOOR_SLUDGE;
+	}
+
+	return FLOOR_SOLID;
+}
+
+
+//---------------------------------------------------------------------------
+//
+// FUNC P_CheckMissileSpawn
+//
+// Returns true if the missile is at a valid spawn point, otherwise
+// explodes it and returns false.
+//
+//---------------------------------------------------------------------------
+
+boolean P_CheckMissileSpawn(mobj_t *missile)
+{
+	//missile->tics -= P_Random() & 3;
+
+	// move a little forward so an angle can be computed if it
+	// immediately explodes
+
+#if 0	/* original */
+	missile->x += (missile->momx>>1);
+	missile->y += (missile->momy>>1);
+	missile->z += (missile->momz>>1);
+#else
+/*
+ * jim - handle fast missiles with BlasterMobjThinker()s
+ * assume so if momentum > MAXMOVE
+ * this is a horrible kludge, but to be honest so is the BlasterMobjThinker
+ * stuff in the first place
+ */
+/* O.S- FIXME --- THIS SEEMS TO HAVE BEEN DONE FOR the ASSASSIN */
+	if ((missile->momx > MAXMOVE) || (missile->momy > MAXMOVE))
+	{
+		missile->x += (missile->momx>>3);
+		missile->y += (missile->momy>>3);
+		missile->z += (missile->momz>>3);
+	}
+	else
+	{
+		missile->x += (missile->momx>>1);
+		missile->y += (missile->momy>>1);
+		missile->z += (missile->momz>>1);
+	}
+#endif	/* jim */
+
+	if (!P_TryMove(missile, missile->x, missile->y))
+	{
+		P_ExplodeMissile(missile);
+		return false;
+	}
+
+	return true;
+}
+
+//---------------------------------------------------------------------------
+//
+// FUNC P_SpawnMissile
+//
+// Returns NULL if the missile exploded immediately, otherwise returns
+// a mobj_t pointer to the missile.
+//
+//---------------------------------------------------------------------------
+
+mobj_t *P_SpawnMissile(mobj_t *source, mobj_t *dest, mobjtype_t type)
+{
+	fixed_t z;
+	mobj_t *th;
+	angle_t an;
+	int dist;
+
+	switch (type)
+	{
+	case MT_MNTRFX1: // Minotaur swing attack missile
+		z = source->z + 40*FRACUNIT;
+		break;
+	case MT_MNTRFX2: // Minotaur floor fire missile
+		z = ONFLOORZ + source->floorclip;
+		break;
+	case MT_CENTAUR_FX:
+		z = source->z + 45*FRACUNIT;
+		break;
+	case MT_ICEGUY_FX:
+		z = source->z + 40*FRACUNIT;
+		break;
+	case MT_HOLY_MISSILE:
+		z = source->z + 40*FRACUNIT;
+		break;
+	default:
+		z = source->z + 32*FRACUNIT;
+		break;
+	}
+	z -= source->floorclip;
+	th = P_SpawnMobj(source->x, source->y, z, type);
+	if (th->info->seesound)
+	{
+		S_StartSound(th, th->info->seesound);
+	}
+	th->target = source; // Originator
+	an = R_PointToAngle2(source->x, source->y, dest->x, dest->y);
+	if (dest->flags & MF_SHADOW)
+	{ // Invisible target
+		an += (P_Random() - P_Random()) <<21;
+	}
+	th->angle = an;
+	an >>= ANGLETOFINESHIFT;
+	th->momx = FixedMul(th->info->speed, finecosine[an]);
+	th->momy = FixedMul(th->info->speed, finesine[an]);
+	dist = P_AproxDistance(dest->x - source->x, dest->y - source->y);
+	dist = dist/th->info->speed;
+	if (dist < 1)
+	{
+		dist = 1;
+	}
+	th->momz = (dest->z - source->z)/dist;
+	return (P_CheckMissileSpawn(th) ? th : NULL);
+}
+
+//---------------------------------------------------------------------------
+//
+// FUNC P_SpawnMissileXYZ
+//
+// Returns NULL if the missile exploded immediately, otherwise returns
+// a mobj_t pointer to the missile.
+//
+//---------------------------------------------------------------------------
+
+mobj_t *P_SpawnMissileXYZ(fixed_t x, fixed_t y, fixed_t z,
+			mobj_t *source, mobj_t *dest, mobjtype_t type)
+{
+	mobj_t *th;
+	angle_t an;
+	int dist;
+
+	z -= source->floorclip;
+	th = P_SpawnMobj(x, y, z, type);
+	if (th->info->seesound)
+	{
+		S_StartSound(th, th->info->seesound);
+	}
+	th->target = source; // Originator
+	an = R_PointToAngle2(source->x, source->y, dest->x, dest->y);
+	if (dest->flags & MF_SHADOW)
+	{ // Invisible target
+		an += (P_Random() - P_Random()) <<21;
+	}
+	th->angle = an;
+	an >>= ANGLETOFINESHIFT;
+	th->momx = FixedMul(th->info->speed, finecosine[an]);
+	th->momy = FixedMul(th->info->speed, finesine[an]);
+	dist = P_AproxDistance(dest->x - source->x, dest->y - source->y);
+	dist = dist/th->info->speed;
+	if (dist < 1)
+	{
+		dist = 1;
+	}
+	th->momz = (dest->z - source->z)/dist;
+	return (P_CheckMissileSpawn(th) ? th : NULL);
+}
+
+//---------------------------------------------------------------------------
+//
+// FUNC P_SpawnMissileAngle
+//
+// Returns NULL if the missile exploded immediately, otherwise returns
+// a mobj_t pointer to the missile.
+//
+//---------------------------------------------------------------------------
+
+mobj_t *P_SpawnMissileAngle(mobj_t *source, mobjtype_t type,
+				angle_t angle, fixed_t momz)
+{
+	fixed_t z;
+	mobj_t *mo;
+
+	switch (type)
+	{
+	case MT_MNTRFX1: // Minotaur swing attack missile
+		z = source->z + 40*FRACUNIT;
+		break;
+	case MT_MNTRFX2: // Minotaur floor fire missile
+		z = ONFLOORZ + source->floorclip;
+		break;
+	case MT_ICEGUY_FX2: // Secondary Projectiles of the Ice Guy
+		z = source->z + 3*FRACUNIT;
+		break;
+	case MT_MSTAFF_FX2:
+		z = source->z + 40*FRACUNIT;
+		break;
+	default:
+		z = source->z + 32*FRACUNIT;
+		break;
+	}
+	z -= source->floorclip;
+	mo = P_SpawnMobj(source->x, source->y, z, type);
+	if (mo->info->seesound)
+	{
+		S_StartSound(mo, mo->info->seesound);
+	}
+	mo->target = source; // Originator
+	mo->angle = angle;
+	angle >>= ANGLETOFINESHIFT;
+	mo->momx = FixedMul(mo->info->speed, finecosine[angle]);
+	mo->momy = FixedMul(mo->info->speed, finesine[angle]);
+	mo->momz = momz;
+	return (P_CheckMissileSpawn(mo) ? mo : NULL);
+}
+
+//---------------------------------------------------------------------------
+//
+// FUNC P_SpawnMissileAngleSpeed
+//
+// Returns NULL if the missile exploded immediately, otherwise returns
+// a mobj_t pointer to the missile.
+//
+//---------------------------------------------------------------------------
+
+mobj_t *P_SpawnMissileAngleSpeed(mobj_t *source, mobjtype_t type,
+				angle_t angle, fixed_t momz, fixed_t speed)
+{
+	fixed_t z;
+	mobj_t *mo;
+
+	z = source->z;
+	z -= source->floorclip;
+	mo = P_SpawnMobj(source->x, source->y, z, type);
+	if (mo->info->seesound)
+	{
+		//S_StartSound(mo, mo->info->seesound);
+	}
+	mo->target = source; // Originator
+	mo->angle = angle;
+	angle >>= ANGLETOFINESHIFT;
+	mo->momx = FixedMul(speed, finecosine[angle]);
+	mo->momy = FixedMul(speed, finesine[angle]);
+	mo->momz = momz;
+	return (P_CheckMissileSpawn(mo) ? mo : NULL);
+}
+
+
+/*
+================
+=
+= P_SpawnPlayerMissile
+=
+= Tries to aim at a nearby monster
+================
+*/
+
+mobj_t *P_SpawnPlayerMissile(mobj_t *source, mobjtype_t type)
+{
+	angle_t an;
+	fixed_t x, y, z, slope;
+
+	// Try to find a target
+	an = source->angle;
+	slope = P_AimLineAttack(source, an, 16*64*FRACUNIT);
+	if (!linetarget)
+	{
+		an += 1<<26;
+		slope = P_AimLineAttack(source, an, 16*64*FRACUNIT);
+		if (!linetarget)
+		{
+			an -= 2<<26;
+			slope = P_AimLineAttack(source, an, 16*64*FRACUNIT);
+		}
+		if (!linetarget)
+		{
+			an = source->angle;
+			slope = ((source->player->lookdir)<<FRACBITS)/173;
+		}
+	}
+	x = source->x;
+	y = source->y;
+	if (type == MT_LIGHTNING_FLOOR)
+	{
+		z = ONFLOORZ;
+		slope = 0;
+	}
+	else if (type == MT_LIGHTNING_CEILING)
+	{
+		z = ONCEILINGZ;
+		slope = 0;
+	}
+	else
+	{
+		z = source->z + 4*8*FRACUNIT + ((source->player->lookdir)<<FRACBITS)/173;
+		z -= source->floorclip;
+	}
+	MissileMobj = P_SpawnMobj(x, y, z, type);
+	if (MissileMobj->info->seesound)
+	{
+		//S_StartSound(MissileMobj, MissileMobj->info->seesound);
+	}
+	MissileMobj->target = source;
+	MissileMobj->angle = an;
+	MissileMobj->momx = FixedMul(MissileMobj->info->speed, finecosine[an>>ANGLETOFINESHIFT]);
+	MissileMobj->momy = FixedMul(MissileMobj->info->speed, finesine[an>>ANGLETOFINESHIFT]);
+	MissileMobj->momz = FixedMul(MissileMobj->info->speed, slope);
+	if (MissileMobj->type == MT_MWAND_MISSILE 
+		|| MissileMobj->type == MT_CFLAME_MISSILE)
+	{ // Ultra-fast ripper spawning missile
+		MissileMobj->x += (MissileMobj->momx>>3);
+		MissileMobj->y += (MissileMobj->momy>>3);
+		MissileMobj->z += (MissileMobj->momz>>3);
+	}
+	else
+	{ // Normal missile
+		MissileMobj->x += (MissileMobj->momx>>1);
+		MissileMobj->y += (MissileMobj->momy>>1);
+		MissileMobj->z += (MissileMobj->momz>>1);
+	}
+	if (!P_TryMove(MissileMobj, MissileMobj->x, MissileMobj->y))
+	{ // Exploded immediately
+		P_ExplodeMissile(MissileMobj);
+		return NULL;
+	}
+	return (MissileMobj);
+}
+
+
+//----------------------------------------------------------------------------
+//
+// P_SpawnPlayerMinotaur - 
+//
+//	Special missile that has larger blocking than player
+//----------------------------------------------------------------------------
+
+/*
+mobj_t *P_SpawnPlayerMinotaur(mobj_t *source, mobjtype_t type)
+{
+	angle_t an;
+	fixed_t x, y, z;
+	fixed_t dist=0 *FRACUNIT;
+
+	an = source->angle;
+	x = source->x + FixedMul(dist, finecosine[an>>ANGLETOFINESHIFT]);
+	y = source->y + FixedMul(dist, finesine[an>>ANGLETOFINESHIFT]);
+	z = source->z + 4*8*FRACUNIT + ((source->player->lookdir)<<FRACBITS)/173;
+	z -= source->floorclip;
+	MissileMobj = P_SpawnMobj(x, y, z, type);
+	if (MissileMobj->info->seesound)
+	{
+		//S_StartSound(MissileMobj, MissileMobj->info->seesound);
+	}
+	MissileMobj->target = source;
+	MissileMobj->angle = an;
+	MissileMobj->momx = FixedMul(MissileMobj->info->speed, finecosine[an>>ANGLETOFINESHIFT]);
+	MissileMobj->momy = FixedMul(MissileMobj->info->speed, finesine[an>>ANGLETOFINESHIFT]);
+	MissileMobj->momz = 0;
+
+//	MissileMobj->x += (MissileMobj->momx>>3);
+//	MissileMobj->y += (MissileMobj->momy>>3);
+//	MissileMobj->z += (MissileMobj->momz>>3);
+
+	if (!P_TryMove(MissileMobj, MissileMobj->x, MissileMobj->y))
+	{ // Wouln't fit
+
+		return NULL;
+	}
+	return (MissileMobj);
+}
+*/
+
+//---------------------------------------------------------------------------
+//
+// PROC P_SPMAngle
+//
+//---------------------------------------------------------------------------
+
+mobj_t *P_SPMAngle(mobj_t *source, mobjtype_t type, angle_t angle)
+{
+	mobj_t *th;
+	angle_t an;
+	fixed_t x, y, z, slope;
+
+//
+// see which target is to be aimed at
+//
+	an = angle;
+	slope = P_AimLineAttack (source, an, 16*64*FRACUNIT);
+	if (!linetarget)
+	{
+		an += 1<<26;
+		slope = P_AimLineAttack (source, an, 16*64*FRACUNIT);
+		if (!linetarget)
+		{
+			an -= 2<<26;
+			slope = P_AimLineAttack (source, an, 16*64*FRACUNIT);
+		}
+		if (!linetarget)
+		{
+			an = angle;
+			slope = ((source->player->lookdir)<<FRACBITS)/173;
+		}
+	}
+	x = source->x;
+	y = source->y;
+	z = source->z + 4*8*FRACUNIT + ((source->player->lookdir)<<FRACBITS)/173;
+	z -= source->floorclip;
+	th = P_SpawnMobj(x, y, z, type);
+//	if (th->info->seesound)
+//	{
+//		S_StartSound(th, th->info->seesound);
+//	}
+	th->target = source;
+	th->angle = an;
+	th->momx = FixedMul(th->info->speed, finecosine[an>>ANGLETOFINESHIFT]);
+	th->momy = FixedMul(th->info->speed, finesine[an>>ANGLETOFINESHIFT]);
+	th->momz = FixedMul(th->info->speed, slope);
+	return (P_CheckMissileSpawn(th) ? th : NULL);
+}
+
+//===========================================================================
+//
+// P_SPMAngleXYZ
+//
+//===========================================================================
+
+mobj_t *P_SPMAngleXYZ(mobj_t *source, fixed_t x, fixed_t y,
+			fixed_t z, mobjtype_t type, angle_t angle)
+{
+	mobj_t *th;
+	angle_t an;
+	fixed_t slope;
+
+//
+// see which target is to be aimed at
+//
+	an = angle;
+	slope = P_AimLineAttack (source, an, 16*64*FRACUNIT);
+	if (!linetarget)
+	{
+		an += 1<<26;
+		slope = P_AimLineAttack (source, an, 16*64*FRACUNIT);
+		if (!linetarget)
+		{
+			an -= 2<<26;
+			slope = P_AimLineAttack (source, an, 16*64*FRACUNIT);
+		}
+		if (!linetarget)
+		{
+			an = angle;
+			slope = ((source->player->lookdir)<<FRACBITS)/173;
+		}
+	}
+	z += 4*8*FRACUNIT + ((source->player->lookdir)<<FRACBITS)/173;
+	z -= source->floorclip;
+	th = P_SpawnMobj(x, y, z, type);
+//	if (th->info->seesound)
+//	{
+//		S_StartSound(th, th->info->seesound);
+//	}
+	th->target = source;
+	th->angle = an;
+	th->momx = FixedMul(th->info->speed, finecosine[an>>ANGLETOFINESHIFT]);
+	th->momy = FixedMul(th->info->speed, finesine[an>>ANGLETOFINESHIFT]);
+	th->momz = FixedMul(th->info->speed, slope);
+	return (P_CheckMissileSpawn(th) ? th : NULL);
+}
+
+mobj_t *P_SpawnKoraxMissile(fixed_t x, fixed_t y, fixed_t z,
+			mobj_t *source, mobj_t *dest, mobjtype_t type)
+{
+	mobj_t *th;
+	angle_t an;
+	int dist;
+
+	z -= source->floorclip;
+	th = P_SpawnMobj(x, y, z, type);
+	if (th->info->seesound)
+	{
+		S_StartSound(th, th->info->seesound);
+	}
+	th->target = source; // Originator
+	an = R_PointToAngle2(x, y, dest->x, dest->y);
+	if (dest->flags & MF_SHADOW)
+	{ // Invisible target
+		an += (P_Random() - P_Random()) <<21;
+	}
+	th->angle = an;
+	an >>= ANGLETOFINESHIFT;
+	th->momx = FixedMul(th->info->speed, finecosine[an]);
+	th->momy = FixedMul(th->info->speed, finesine[an]);
+	dist = P_AproxDistance(dest->x - x, dest->y - y);
+	dist = dist/th->info->speed;
+	if (dist < 1)
+	{
+		dist = 1;
+	}
+	th->momz = (dest->z - z + (30*FRACUNIT))/dist;
+	return (P_CheckMissileSpawn(th) ? th : NULL);
+}
+
--- /dev/null
+++ b/p_plats.c
@@ -1,0 +1,276 @@
+
+//**************************************************************************
+//**
+//** p_plats.c : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 472 $
+//** $Date: 2009-05-26 15:45:18 +0300 (Tue, 26 May 2009) $
+//**
+//**************************************************************************
+
+#include "h2stdinc.h"
+#include "h2def.h"
+#include "p_local.h"
+#include "soundst.h"
+
+plat_t	*activeplats[MAXPLATS];
+
+//==================================================================
+//
+// Move a plat up and down
+//
+//==================================================================
+
+void T_PlatRaise(plat_t *plat)
+{
+	result_e res;
+
+	switch (plat->status)
+	{
+	case PLAT_UP:
+		res = T_MovePlane(plat->sector, plat->speed, plat->high, plat->crush, 0, 1);
+		if (res == RES_CRUSHED && (!plat->crush))
+		{
+			plat->count = plat->wait;
+			plat->status = PLAT_DOWN;
+			SN_StartSequence((mobj_t *)(void *)&plat->sector->soundorg,
+					 SEQ_PLATFORM + plat->sector->seqType);
+		}
+		else
+		if (res == RES_PASTDEST)
+		{
+			plat->count = plat->wait;
+			plat->status = PLAT_WAITING;
+			SN_StopSequence((mobj_t *)(void *)&plat->sector->soundorg);
+			switch (plat->type)
+			{
+			case PLAT_DOWNWAITUPSTAY:
+			case PLAT_DOWNBYVALUEWAITUPSTAY:
+				P_RemoveActivePlat(plat);
+				break;
+			default:
+				break;
+			}
+		}
+		break;
+
+	case PLAT_DOWN:
+		res = T_MovePlane(plat->sector, plat->speed, plat->low, false, 0, -1);
+		if (res == RES_PASTDEST)
+		{
+			plat->count = plat->wait;
+			plat->status = PLAT_WAITING;
+			switch (plat->type)
+			{
+			case PLAT_UPWAITDOWNSTAY:
+			case PLAT_UPBYVALUEWAITDOWNSTAY:
+				P_RemoveActivePlat(plat);
+				break;
+			default:
+				break;
+			}
+			SN_StopSequence((mobj_t *)(void *)&plat->sector->soundorg);
+		}
+		break;
+
+	case PLAT_WAITING:
+		if (!--plat->count)
+		{
+			if (plat->sector->floorheight == plat->low)
+				plat->status = PLAT_UP;
+			else
+				plat->status = PLAT_DOWN;
+			SN_StartSequence((mobj_t *)(void *)&plat->sector->soundorg,
+					 SEQ_PLATFORM + plat->sector->seqType);
+		}
+
+//	case PLAT_IN_STASIS:
+//		break;
+	}
+}
+
+//==================================================================
+//
+// Do Platforms
+// "amount" is only used for SOME platforms.
+//
+//==================================================================
+
+int EV_DoPlat(line_t *line, byte *args, plattype_e type, int amount)
+{
+	plat_t		*plat;
+	int		secnum;
+	int		rtn;
+	sector_t	*sec;
+
+	secnum = -1;
+	rtn = 0;
+
+	/*
+	//
+	// Activate all <type> plats that are in_stasis
+	//
+	switch (type)
+	{
+	case PLAT_PERPETUALRAISE:
+		P_ActivateInStasis(args[0]);
+		break;
+	default:
+		break;
+	}
+	*/
+
+	while ((secnum = P_FindSectorFromTag(args[0], secnum)) >= 0)
+	{
+		sec = &sectors[secnum];
+		if (sec->specialdata)
+			continue;
+
+		//
+		// Find lowest & highest floors around sector
+		//
+		rtn = 1;
+		plat = (plat_t *) Z_Malloc( sizeof(*plat), PU_LEVSPEC, NULL);
+		P_AddThinker(&plat->thinker);
+
+		plat->type = type;
+		plat->sector = sec;
+		plat->sector->specialdata = plat;
+		plat->thinker.function = T_PlatRaise;
+		plat->crush = false;
+		plat->tag = args[0];
+		plat->speed = args[1]*(FRACUNIT/8);
+		switch (type)
+		{
+		case PLAT_DOWNWAITUPSTAY:
+			plat->low = P_FindLowestFloorSurrounding(sec) + 8*FRACUNIT;
+			if (plat->low > sec->floorheight)
+				plat->low = sec->floorheight;
+			plat->high = sec->floorheight;
+			plat->wait = args[2];
+			plat->status = PLAT_DOWN;
+			break;
+		case PLAT_DOWNBYVALUEWAITUPSTAY:
+			plat->low = sec->floorheight-args[3]*8*FRACUNIT;
+			if (plat->low > sec->floorheight)
+				plat->low = sec->floorheight;
+			plat->high = sec->floorheight;
+			plat->wait = args[2];
+			plat->status = PLAT_DOWN;
+			break;
+		case PLAT_UPWAITDOWNSTAY:
+			plat->high = P_FindHighestFloorSurrounding(sec);
+			if (plat->high < sec->floorheight)
+				plat->high = sec->floorheight;
+			plat->low = sec->floorheight;
+			plat->wait = args[2];
+			plat->status = PLAT_UP;
+			break;
+		case PLAT_UPBYVALUEWAITDOWNSTAY:
+			plat->high = sec->floorheight+args[3]*8*FRACUNIT;
+			if (plat->high < sec->floorheight)
+				plat->high = sec->floorheight;
+			plat->low = sec->floorheight;
+			plat->wait = args[2];
+			plat->status = PLAT_UP;
+			break;
+		case PLAT_PERPETUALRAISE:
+			plat->low = P_FindLowestFloorSurrounding(sec) + 8*FRACUNIT;
+			if (plat->low > sec->floorheight)
+				plat->low = sec->floorheight;
+			plat->high = P_FindHighestFloorSurrounding(sec);
+			if (plat->high < sec->floorheight)
+				plat->high = sec->floorheight;
+			plat->wait = args[2];
+			plat->status = P_Random() & 1;
+			break;
+		}
+		P_AddActivePlat(plat);
+		SN_StartSequence((mobj_t *)(void *)&sec->soundorg, SEQ_PLATFORM + sec->seqType);
+	}
+	return rtn;
+}
+
+#if 0
+void P_ActivateInStasis(int tag)
+{
+	int		i;
+
+	for (i = 0; i < MAXPLATS; i++)
+	{
+		if (activeplats[i] &&
+			(activeplats[i])->tag == tag &&
+			(activeplats[i])->status == PLAT_IN_STASIS)
+		{
+			(activeplats[i])->status = (activeplats[i])->oldstatus;
+			(activeplats[i])->thinker.function = T_PlatRaise;
+		}
+	}
+}
+#endif
+
+void EV_StopPlat(line_t *line, byte *args)
+{
+	int		i;
+
+	for (i = 0; i < MAXPLATS; i++)
+	{
+		if ((activeplats[i])->tag == args[0])
+		{
+			(activeplats[i])->sector->specialdata = NULL;
+			P_TagFinished((activeplats[i])->sector->tag);
+			P_RemoveThinker(&(activeplats[i])->thinker);
+			activeplats[i] = NULL;
+
+			return;
+		}
+	}
+
+	/*
+	int		j;
+
+	for (j = 0; j < MAXPLATS; j++)
+	{
+		if (activeplats[j] && ((activeplats[j])->status != PLAT_IN_STASIS) &&
+			((activeplats[j])->tag == args[0]))
+		{
+			(activeplats[j])->oldstatus = (activeplats[j])->status;
+			(activeplats[j])->status = PLAT_IN_STASIS;
+			(activeplats[j])->thinker.function = NULL;
+			SN_StopSequence((mobj_t *)(void *)&(activeplats[j])->sector->soundorg);
+		}
+	}
+	*/
+}
+
+void P_AddActivePlat(plat_t *plat)
+{
+	int		i;
+	for (i = 0; i < MAXPLATS; i++)
+	{
+		if (activeplats[i] == NULL)
+		{
+			activeplats[i] = plat;
+			return;
+		}
+	}
+	I_Error ("P_AddActivePlat: no more plats!");
+}
+
+void P_RemoveActivePlat(plat_t *plat)
+{
+	int		i;
+	for (i = 0; i < MAXPLATS; i++)
+	{
+		if (plat == activeplats[i])
+		{
+			(activeplats[i])->sector->specialdata = NULL;
+			P_TagFinished(plat->sector->tag);
+			P_RemoveThinker(&(activeplats[i])->thinker);
+			activeplats[i] = NULL;
+			return;
+		}
+	}
+	I_Error ("P_RemoveActivePlat: can't find plat!");
+}
+
--- /dev/null
+++ b/p_pspr.c
@@ -1,0 +1,2703 @@
+
+//**************************************************************************
+//**
+//** p_pspr.c : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 575 $
+//** $Date: 2011-04-13 22:06:28 +0300 (Wed, 13 Apr 2011) $
+//**
+//**************************************************************************
+
+// HEADER FILES ------------------------------------------------------------
+
+#include "h2stdinc.h"
+#include "h2def.h"
+#include "p_local.h"
+#include "soundst.h"
+#include "v_compat.h"	/* V_SetPaletteXXX() macros */
+
+// MACROS ------------------------------------------------------------------
+
+#define LOWERSPEED	FRACUNIT*6
+#define RAISESPEED	FRACUNIT*6
+
+#define WEAPONBOTTOM	128*FRACUNIT
+#define WEAPONTOP	32*FRACUNIT
+
+// TYPES -------------------------------------------------------------------
+
+// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
+
+extern void P_ExplodeMissile(mobj_t *mo);
+extern void A_UnHideThing(mobj_t *actor);
+
+// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
+
+// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
+
+// EXTERNAL DATA DECLARATIONS ----------------------------------------------
+
+extern fixed_t FloatBobOffsets[64];
+
+// PUBLIC DATA DEFINITIONS -------------------------------------------------
+
+weaponinfo_t WeaponInfo[NUMWEAPONS][NUMCLASSES] =
+{
+	{ // First Weapons
+		{ // Fighter First Weapon - Punch
+			MANA_NONE,		// mana
+			S_PUNCHUP,		// upstate
+			S_PUNCHDOWN,		// downstate
+			S_PUNCHREADY,		// readystate
+			S_PUNCHATK1_1,		// atkstate
+			S_PUNCHATK1_1,		// holdatkstate
+			S_NULL			// flashstate
+		},
+		{ // Cleric First Weapon - Mace
+			MANA_NONE,		// mana
+			S_CMACEUP,		// upstate
+			S_CMACEDOWN,		// downstate
+			S_CMACEREADY,		// readystate
+			S_CMACEATK_1,		// atkstate
+			S_CMACEATK_1,		// holdatkstate
+			S_NULL			// flashstate
+		},
+		{ // Mage First Weapon - Wand
+			MANA_NONE,
+			S_MWANDUP,
+			S_MWANDDOWN,
+			S_MWANDREADY,
+			S_MWANDATK_1,
+			S_MWANDATK_1,
+			S_NULL
+		},
+#ifdef ASSASSIN
+		{ // Assassin - Katar
+			MANA_NONE,
+			S_KATARUP,
+			S_KATARDOWN,
+			S_KATARREADY,
+			S_KATARATK1_1,
+			S_KATARATK1_1,
+			S_NULL
+		},
+#endif
+		{ // Pig - Snout
+			MANA_NONE,		// mana
+			S_SNOUTUP,		// upstate
+			S_SNOUTDOWN,		// downstate
+			S_SNOUTREADY,		// readystate
+			S_SNOUTATK1,		// atkstate
+			S_SNOUTATK1,		// holdatkstate
+			S_NULL			// flashstate
+		}
+	},
+
+	{ // Second Weapons
+		{ // Fighter - Axe
+			MANA_NONE,		// mana
+			S_FAXEUP,		// upstate
+			S_FAXEDOWN,		// downstate
+			S_FAXEREADY,		// readystate
+			S_FAXEATK_1,		// atkstate
+			S_FAXEATK_1,		// holdatkstate
+			S_NULL			// flashstate
+		},
+		{ // Cleric - Serpent Staff
+			MANA_1,			// mana
+			S_CSTAFFUP,		// upstate
+			S_CSTAFFDOWN,		// downstate
+			S_CSTAFFREADY,		// readystate
+			S_CSTAFFATK_1,		// atkstate
+			S_CSTAFFATK_1,		// holdatkstate
+			S_NULL			// flashstate
+		},
+		{ // Mage - Cone of shards
+			MANA_1,			// mana
+			S_CONEUP,		// upstate
+			S_CONEDOWN,		// downstate
+			S_CONEREADY,		// readystate
+			S_CONEATK1_1,		// atkstate
+			S_CONEATK1_3,		// holdatkstate
+			S_NULL			// flashstate
+		},
+#ifdef ASSASSIN
+		{ // Assassin - Hand Crossbow
+			MANA_1,
+			S_ACROSSUP,
+			S_ACROSSDOWN,
+			S_ACROSSREADY,
+			S_ACROSSATK_1,
+			S_ACROSSATK_3,
+			S_NULL
+		},
+#endif
+		{ // Pig - Snout
+			MANA_NONE,		// mana
+			S_SNOUTUP,		// upstate
+			S_SNOUTDOWN,		// downstate
+			S_SNOUTREADY,		// readystate
+			S_SNOUTATK1,		// atkstate
+			S_SNOUTATK1,		// holdatkstate
+			S_NULL			// flashstate
+		}
+	},
+
+	{ // Third Weapons
+		{ // Fighter - Hammer
+			MANA_NONE,		// mana
+			S_FHAMMERUP,		// upstate
+			S_FHAMMERDOWN,		// downstate
+			S_FHAMMERREADY,		// readystate
+			S_FHAMMERATK_1,		// atkstate
+			S_FHAMMERATK_1,		// holdatkstate
+			S_NULL			// flashstate
+		},
+		{ // Cleric - Flame Strike
+			MANA_2,			// mana
+			S_CFLAMEUP,		// upstate
+			S_CFLAMEDOWN,		// downstate
+			S_CFLAMEREADY1,		// readystate
+			S_CFLAMEATK_1,		// atkstate
+			S_CFLAMEATK_1,		// holdatkstate
+			S_NULL			// flashstate
+		},
+		{ // Mage - Lightning
+			MANA_2,			// mana
+			S_MLIGHTNINGUP,		// upstate
+			S_MLIGHTNINGDOWN,	// downstate
+			S_MLIGHTNINGREADY,	// readystate
+			S_MLIGHTNINGATK_1,	// atkstate
+			S_MLIGHTNINGATK_1,	// holdatkstate
+			S_NULL			// flashstate
+		},
+#ifdef ASSASSIN
+		{ // Assassin - Grenades
+			MANA_2,
+			S_AGRENUP,
+			S_AGRENDOWN,
+			S_AGRENREADY,
+			S_AGRENATK_1,
+			S_AGRENATK_1,
+			S_NULL
+		},
+#endif
+		{ // Pig - Snout
+			MANA_NONE,		// mana
+			S_SNOUTUP,		// upstate
+			S_SNOUTDOWN,		// downstate
+			S_SNOUTREADY,		// readystate
+			S_SNOUTATK1,		// atkstate
+			S_SNOUTATK1,		// holdatkstate
+			S_NULL			// flashstate
+		}
+	},
+
+	{ // Fourth Weapons
+		{ // Fighter - Rune Sword
+			MANA_BOTH,		// mana
+			S_FSWORDUP,		// upstate
+			S_FSWORDDOWN,		// downstate
+			S_FSWORDREADY,		// readystate
+			S_FSWORDATK_1,		// atkstate
+			S_FSWORDATK_1,		// holdatkstate
+			S_NULL			// flashstate
+		},
+		{ // Cleric - Holy Symbol
+			MANA_BOTH,		// mana
+			S_CHOLYUP,		// upstate
+			S_CHOLYDOWN,		// downstate
+			S_CHOLYREADY,		// readystate
+			S_CHOLYATK_1,		// atkstate
+			S_CHOLYATK_1,		// holdatkstate
+			S_NULL			// flashstate
+		},
+		{ // Mage - Staff
+			MANA_BOTH,		// mana
+			S_MSTAFFUP,		// upstate
+			S_MSTAFFDOWN,		// downstate
+			S_MSTAFFREADY,		// readystate
+			S_MSTAFFATK_1,		// atkstate
+			S_MSTAFFATK_1,		// holdatkstate
+			S_NULL			// flashstate
+		},
+#ifdef ASSASSIN
+		{ // Assassin - Staff of Set
+			MANA_BOTH,
+			S_ASTAFFUP,
+			S_ASTAFFDOWN,
+			S_ASTAFFREADY,
+			S_ASTAFFATK_1,
+			S_ASTAFFATK_1,
+			S_NULL
+		},
+#endif
+		{ // Pig - Snout
+			MANA_NONE,		// mana
+			S_SNOUTUP,		// upstate
+			S_SNOUTDOWN,		// downstate
+			S_SNOUTREADY,		// readystate
+			S_SNOUTATK1,		// atkstate
+			S_SNOUTATK1,		// holdatkstate
+			S_NULL			// flashstate
+		}
+	}
+};
+
+// PRIVATE DATA DEFINITIONS ------------------------------------------------
+
+//fixed_t	bulletslope;	// for P_BulletSlope()
+
+static int WeaponManaUse[NUMCLASSES][NUMWEAPONS] =
+{
+	{ 0, 2, 3, 14 },
+	{ 0, 1, 4, 18 },
+	{ 0, 3, 5, 15 },
+#ifdef ASSASSIN
+	{ 0, 3, 3, 1 },		// True to Hexen II
+#endif
+	{ 0, 0, 0, 0 }
+};
+
+// CODE --------------------------------------------------------------------
+
+//---------------------------------------------------------------------------
+//
+// PROC P_SetPsprite
+//
+//---------------------------------------------------------------------------
+
+void P_SetPsprite(player_t *player, int position, statenum_t stnum)
+{
+	pspdef_t *psp;
+	state_t *state;
+
+	psp = &player->psprites[position];
+	do
+	{
+		if (!stnum)
+		{ // Object removed itself.
+			psp->state = NULL;
+			break;
+		}
+		state = &states[stnum];
+		psp->state = state;
+		psp->tics = state->tics; // could be 0
+		if (state->misc1)
+		{ // Set coordinates.
+			psp->sx = state->misc1<<FRACBITS;
+		}
+		if (state->misc2)
+		{
+			psp->sy = state->misc2<<FRACBITS;
+		}
+		if (state->action)
+		{ // Call action routine.
+			state->action(player, psp);
+			if (!psp->state)
+			{
+				break;
+			}
+		}
+		stnum = psp->state->nextstate;
+	} while (!psp->tics); // An initial state of 0 could cycle through.
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC P_SetPspriteNF
+//
+// Identical to P_SetPsprite, without calling the action function
+//---------------------------------------------------------------------------
+
+void P_SetPspriteNF(player_t *player, int position, statenum_t stnum)
+{
+	pspdef_t *psp;
+	state_t *state;
+
+	psp = &player->psprites[position];
+	do
+	{
+		if (!stnum)
+		{ // Object removed itself.
+			psp->state = NULL;
+			break;
+		}
+		state = &states[stnum];
+		psp->state = state;
+		psp->tics = state->tics; // could be 0
+		if (state->misc1)
+		{ // Set coordinates.
+			psp->sx = state->misc1<<FRACBITS;
+		}
+		if (state->misc2)
+		{
+			psp->sy = state->misc2<<FRACBITS;
+		}
+		stnum = psp->state->nextstate;
+	} while (!psp->tics); // An initial state of 0 could cycle through.
+}
+
+/*
+=================
+=
+= P_CalcSwing
+=
+=================
+*/
+
+/*
+fixed_t		swingx, swingy;
+void P_CalcSwing (player_t *player)
+{
+	fixed_t	swing;
+	int		angle;
+
+// OPTIMIZE: tablify this
+
+	swing = player->bob;
+
+	angle = (FINEANGLES/70*leveltime) & FINEMASK;
+	swingx = FixedMul (swing, finesine[angle]);
+
+	angle = (FINEANGLES/70*leveltime + FINEANGLES/2) & FINEMASK;
+	swingy = -FixedMul (swingx, finesine[angle]);
+}
+*/
+
+//---------------------------------------------------------------------------
+//
+// PROC P_ActivateMorphWeapon
+//
+//---------------------------------------------------------------------------
+
+void P_ActivateMorphWeapon(player_t *player)
+{
+	player->pendingweapon = WP_NOCHANGE;
+	player->psprites[ps_weapon].sy = WEAPONTOP;
+	player->readyweapon = WP_FIRST;	// Snout is the first weapon
+	P_SetPsprite(player, ps_weapon, S_SNOUTREADY);
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC P_PostMorphWeapon
+//
+//---------------------------------------------------------------------------
+
+void P_PostMorphWeapon(player_t *player, weapontype_t weapon)
+{
+	player->pendingweapon = WP_NOCHANGE;
+	player->readyweapon = weapon;
+	player->psprites[ps_weapon].sy = WEAPONBOTTOM;
+	P_SetPsprite(player, ps_weapon, WeaponInfo[weapon][player->playerclass].upstate);
+}
+
+
+//---------------------------------------------------------------------------
+//
+// PROC P_BringUpWeapon
+//
+// Starts bringing the pending weapon up from the bottom of the screen.
+//
+//---------------------------------------------------------------------------
+
+void P_BringUpWeapon(player_t *player)
+{
+	statenum_t newstate;
+
+	if (player->pendingweapon == WP_NOCHANGE)
+	{
+		player->pendingweapon = player->readyweapon;
+	}
+	if (player->playerclass == PCLASS_FIGHTER && player->pendingweapon == WP_SECOND
+						&& player->mana[MANA_1])
+	{
+		newstate = S_FAXEUP_G;
+	}
+	else
+	{
+		newstate = WeaponInfo[player->pendingweapon][player->playerclass].upstate;
+	}
+	player->pendingweapon = WP_NOCHANGE;
+	player->psprites[ps_weapon].sy = WEAPONBOTTOM;
+	P_SetPsprite(player, ps_weapon, newstate);
+}
+
+//---------------------------------------------------------------------------
+//
+// FUNC P_CheckMana
+//
+// Returns true if there is enough mana to shoot.  If not, selects the
+// next weapon to use.
+//
+//---------------------------------------------------------------------------
+
+static boolean P_CheckMana(player_t *player)
+{
+	manatype_t mana;
+	int count;
+
+	mana = WeaponInfo[player->readyweapon][player->playerclass].mana;
+	count = WeaponManaUse[player->playerclass][player->readyweapon];
+	if (mana == MANA_BOTH)
+	{
+		if (player->mana[MANA_1] >= count && player->mana[MANA_2] >= count)
+		{
+			return true;
+		}
+	}
+	else if (mana == MANA_NONE || player->mana[mana] >= count)
+	{
+		return true;
+	}
+	// out of mana, pick a weapon to change to
+	do
+	{
+		if (player->weaponowned[WP_THIRD]
+			&& player->mana[MANA_2] >= WeaponManaUse[player->playerclass][WP_THIRD])
+		{
+			player->pendingweapon = WP_THIRD;
+		}
+		else if (player->weaponowned[WP_SECOND]
+			&& player->mana[MANA_1] >= WeaponManaUse[player->playerclass][WP_SECOND])
+		{
+			player->pendingweapon = WP_SECOND;
+		}
+		else if (player->weaponowned[WP_FOURTH]
+			&& player->mana[MANA_1] >= WeaponManaUse[player->playerclass][WP_FOURTH]
+			&& player->mana[MANA_2] >= WeaponManaUse[player->playerclass][WP_FOURTH])
+		{
+			player->pendingweapon = WP_FOURTH;
+		}
+		else
+		{
+			player->pendingweapon = WP_FIRST;
+		}
+	} while (player->pendingweapon == WP_NOCHANGE);
+	P_SetPsprite(player, ps_weapon,
+			WeaponInfo[player->readyweapon][player->playerclass].downstate);
+	return false;
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC P_FireWeapon
+//
+//---------------------------------------------------------------------------
+
+static void P_FireWeapon(player_t *player)
+{
+	statenum_t attackState;
+
+	if (!P_CheckMana(player))
+	{
+		return;
+	}
+	P_SetMobjState(player->mo, PStateAttack[player->playerclass]); // S_PLAY_ATK1);
+	if (player->playerclass == PCLASS_FIGHTER && player->readyweapon == WP_SECOND
+						&& player->mana[MANA_1] > 0)
+	{ // Glowing axe
+		attackState = S_FAXEATK_G1;
+	}
+	else
+	{
+		attackState = player->refire ? 
+			WeaponInfo[player->readyweapon][player->playerclass].holdatkstate
+			: WeaponInfo[player->readyweapon][player->playerclass].atkstate;
+	}
+	P_SetPsprite(player, ps_weapon, attackState);
+	P_NoiseAlert(player->mo, player->mo);
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC P_DropWeapon
+//
+// The player died, so put the weapon away.
+//
+//---------------------------------------------------------------------------
+
+void P_DropWeapon(player_t *player)
+{
+	P_SetPsprite(player, ps_weapon,
+			WeaponInfo[player->readyweapon][player->playerclass].downstate);
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC A_WeaponReady
+//
+// The player can fire the weapon or change to another weapon at this time.
+//
+//---------------------------------------------------------------------------
+
+void A_WeaponReady(player_t *player, pspdef_t *psp)
+{
+	int angle;
+
+	// Change player from attack state
+	if (player->mo->state >= &states[PStateAttack[player->playerclass]]
+		&& player->mo->state <= &states[PStateAttackEnd[player->playerclass]])
+	{
+		P_SetMobjState(player->mo, PStateNormal[player->playerclass]);
+	}
+	// Put the weapon away if the player has a pending weapon or has
+	// died.
+	if (player->pendingweapon != WP_NOCHANGE || !player->health)
+	{
+		P_SetPsprite(player, ps_weapon,
+			WeaponInfo[player->readyweapon][player->playerclass].downstate);
+		return;
+	}
+
+	// Check for fire. 
+	if (player->cmd.buttons & BT_ATTACK)
+	{
+		player->attackdown = true;
+		P_FireWeapon(player);
+		return;
+	}
+	else
+	{
+		player->attackdown = false;
+	}
+
+	if (!player->morphTics)
+	{
+		// Bob the weapon based on movement speed.
+		angle = (128*leveltime)&FINEMASK;
+		psp->sx = FRACUNIT + FixedMul(player->bob, finecosine[angle]);
+		angle &= FINEANGLES/2 - 1;
+		psp->sy = WEAPONTOP + FixedMul(player->bob, finesine[angle]);
+	}
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC A_ReFire
+//
+// The player can re fire the weapon without lowering it entirely.
+//
+//---------------------------------------------------------------------------
+
+void A_ReFire(player_t *player, pspdef_t *psp)
+{
+	if ((player->cmd.buttons&BT_ATTACK)
+		&& player->pendingweapon == WP_NOCHANGE && player->health)
+	{
+		player->refire++;
+		P_FireWeapon(player);
+	}
+	else
+	{
+		player->refire = 0;
+		P_CheckMana(player);
+	}
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC A_Lower
+//
+//---------------------------------------------------------------------------
+
+void A_Lower(player_t *player, pspdef_t *psp)
+{
+	if (player->morphTics)
+	{
+		psp->sy = WEAPONBOTTOM;
+	}
+	else
+	{
+		psp->sy += LOWERSPEED;
+	}
+	if (psp->sy < WEAPONBOTTOM)
+	{ // Not lowered all the way yet
+		return;
+	}
+	if (player->playerstate == PST_DEAD)
+	{ // Player is dead, so don't bring up a pending weapon
+		psp->sy = WEAPONBOTTOM;
+		return;
+	}
+	if (!player->health)
+	{ // Player is dead, so keep the weapon off screen
+		P_SetPsprite(player,  ps_weapon, S_NULL);
+		return;
+	}
+	player->readyweapon = player->pendingweapon;
+	P_BringUpWeapon(player);
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC A_Raise
+//
+//---------------------------------------------------------------------------
+
+void A_Raise(player_t *player, pspdef_t *psp)
+{
+	psp->sy -= RAISESPEED;
+	if (psp->sy > WEAPONTOP)
+	{ // Not raised all the way yet
+		return;
+	}
+	psp->sy = WEAPONTOP;
+	if (player->playerclass == PCLASS_FIGHTER && player->readyweapon == WP_SECOND
+						&& player->mana[MANA_1])
+	{
+		P_SetPsprite(player, ps_weapon, S_FAXEREADY_G);
+	}
+	else
+	{
+		P_SetPsprite(player, ps_weapon,
+			WeaponInfo[player->readyweapon][player->playerclass].readystate);
+	}
+}
+
+/*
+===============
+=
+= P_BulletSlope
+=
+= Sets a slope so a near miss is at aproximately the height of the
+= intended target
+=
+===============
+*/
+
+/*
+static void P_BulletSlope (mobj_t *mo)
+{
+	angle_t		an;
+
+//
+// see which target is to be aimed at
+//
+	an = mo->angle;
+	bulletslope = P_AimLineAttack (mo, an, 16*64*FRACUNIT);
+	if (!linetarget)
+	{
+		an += 1<<26;
+		bulletslope = P_AimLineAttack (mo, an, 16*64*FRACUNIT);
+		if (!linetarget)
+		{
+			an -= 2<<26;
+			bulletslope = P_AimLineAttack (mo, an, 16*64*FRACUNIT);
+		}
+		if (!linetarget)
+		{
+			an += 1<<26;
+			bulletslope = (mo->player->lookdir<<FRACBITS)/173;
+		}
+	}
+}
+*/
+
+//****************************************************************************
+//
+// WEAPON ATTACKS
+//
+//****************************************************************************
+
+//============================================================================
+//
+//	AdjustPlayerAngle
+//
+//============================================================================
+
+#define MAX_ANGLE_ADJUST	(5*ANGLE_1)
+
+static void AdjustPlayerAngle(mobj_t *pmo)
+{
+	angle_t angle;
+	int difference;
+
+	angle = R_PointToAngle2(pmo->x, pmo->y, linetarget->x, linetarget->y);
+	difference = (int)angle - (int)pmo->angle;
+	if (abs(difference) > MAX_ANGLE_ADJUST)
+	{
+		pmo->angle += difference > 0 ? MAX_ANGLE_ADJUST : -MAX_ANGLE_ADJUST;
+	}
+	else
+	{
+		pmo->angle = angle;
+	}
+}
+
+//============================================================================
+//
+// A_SnoutAttack
+//
+//============================================================================
+
+void A_SnoutAttack(player_t *player, pspdef_t *psp)
+{
+	angle_t angle;
+	int damage;
+	int slope;
+
+	damage = 3 + (P_Random() & 3);
+	angle = player->mo->angle;
+	slope = P_AimLineAttack(player->mo, angle, MELEERANGE);
+	PuffType = MT_SNOUTPUFF;
+	PuffSpawned = NULL;
+	P_LineAttack(player->mo, angle, MELEERANGE, slope, damage);
+	S_StartSound(player->mo, SFX_PIG_ACTIVE1 + (P_Random() & 1));
+	if (linetarget)
+	{
+		AdjustPlayerAngle(player->mo);
+//		player->mo->angle = R_PointToAngle2(player->mo->x,
+//			player->mo->y, linetarget->x, linetarget->y);
+		if (PuffSpawned)
+		{ // Bit something
+			S_StartSound(player->mo, SFX_PIG_ATTACK);
+		}
+	}
+}
+
+//============================================================================
+//
+// A_FHammerAttack
+//
+//============================================================================
+
+#define HAMMER_RANGE	(MELEERANGE+MELEERANGE/2)
+
+void A_FHammerAttack(player_t *player, pspdef_t *psp)
+{
+	angle_t angle;
+	mobj_t *pmo = player->mo;
+	int damage;
+	fixed_t power;
+	int slope;
+	int i;
+
+	damage = 60 + (P_Random() & 63);
+	power = 10*FRACUNIT;
+	PuffType = MT_HAMMERPUFF;
+	for (i = 0; i < 16; i++)
+	{
+		angle = pmo->angle + i*(ANG45/32);
+		slope = P_AimLineAttack(pmo, angle, HAMMER_RANGE);
+		if (linetarget)
+		{
+			P_LineAttack(pmo, angle, HAMMER_RANGE, slope, damage);
+			AdjustPlayerAngle(pmo);
+			if (linetarget->flags & MF_COUNTKILL || linetarget->player)
+			{
+				P_ThrustMobj(linetarget, angle, power);
+			}
+			pmo->special1 = false; // Don't throw a hammer
+			goto hammerdone;
+		}
+		angle = pmo->angle - i*(ANG45/32);
+		slope = P_AimLineAttack(pmo, angle, HAMMER_RANGE);
+		if (linetarget)
+		{
+			P_LineAttack(pmo, angle, HAMMER_RANGE, slope, damage);
+			AdjustPlayerAngle(pmo);
+			if (linetarget->flags & MF_COUNTKILL || linetarget->player)
+			{
+				P_ThrustMobj(linetarget, angle, power);
+			}
+			pmo->special1 = false; // Don't throw a hammer
+			goto hammerdone;
+		}
+	}
+	// didn't find any targets in meleerange, so set to throw out a hammer
+	PuffSpawned = NULL;
+	angle = pmo->angle;
+	slope = P_AimLineAttack(pmo, angle, HAMMER_RANGE);
+	P_LineAttack(pmo, angle, HAMMER_RANGE, slope, damage);
+	if (PuffSpawned)
+	{
+		pmo->special1 = false;
+	}
+	else
+	{
+		pmo->special1 = true;
+	}
+hammerdone:
+	if (player->mana[MANA_2] < 
+			WeaponManaUse[player->playerclass][player->readyweapon])
+	{ // Don't spawn a hammer if the player doesn't have enough mana
+		pmo->special1 = false;
+	}
+	return;
+}
+
+//============================================================================
+//
+// A_FHammerThrow
+//
+//============================================================================
+
+void A_FHammerThrow(player_t *player, pspdef_t *psp)
+{
+	mobj_t *mo;
+
+	if (!player->mo->special1)
+	{
+		return;
+	}
+	player->mana[MANA_2] -= WeaponManaUse[player->playerclass][player->readyweapon];
+	mo = P_SpawnPlayerMissile(player->mo, MT_HAMMER_MISSILE);
+	if (mo)
+	{
+		mo->special1 = 0;
+	}
+}
+
+//============================================================================
+//
+// A_FSwordAttack
+//
+//============================================================================
+
+void A_FSwordAttack(player_t *player, pspdef_t *psp)
+{
+	mobj_t *pmo;
+
+	player->mana[MANA_1] -= WeaponManaUse[player->playerclass][player->readyweapon];
+	player->mana[MANA_2] -= WeaponManaUse[player->playerclass][player->readyweapon];
+	pmo = player->mo;
+	P_SPMAngleXYZ(pmo, pmo->x, pmo->y, pmo->z - 10*FRACUNIT, MT_FSWORD_MISSILE, pmo->angle + ANG45/4);
+	P_SPMAngleXYZ(pmo, pmo->x, pmo->y, pmo->z - 5*FRACUNIT, MT_FSWORD_MISSILE, pmo->angle + ANG45/8);
+	P_SPMAngleXYZ(pmo, pmo->x, pmo->y, pmo->z, MT_FSWORD_MISSILE, pmo->angle);
+	P_SPMAngleXYZ(pmo, pmo->x, pmo->y, pmo->z + 5*FRACUNIT, MT_FSWORD_MISSILE, pmo->angle - ANG45/8);
+	P_SPMAngleXYZ(pmo, pmo->x, pmo->y, pmo->z + 10*FRACUNIT, MT_FSWORD_MISSILE, pmo->angle - ANG45/4);
+	S_StartSound(pmo, SFX_FIGHTER_SWORD_FIRE);
+}
+
+//============================================================================
+//
+// A_FSwordAttack2
+//
+//============================================================================
+
+void A_FSwordAttack2(mobj_t *actor)
+{
+	angle_t angle = actor->angle;
+
+	P_SpawnMissileAngle(actor, MT_FSWORD_MISSILE,angle + ANG45/4, 0);
+	P_SpawnMissileAngle(actor, MT_FSWORD_MISSILE,angle + ANG45/8, 0);
+	P_SpawnMissileAngle(actor, MT_FSWORD_MISSILE,angle,	      0);
+	P_SpawnMissileAngle(actor, MT_FSWORD_MISSILE,angle - ANG45/8, 0);
+	P_SpawnMissileAngle(actor, MT_FSWORD_MISSILE,angle - ANG45/4, 0);
+	S_StartSound(actor, SFX_FIGHTER_SWORD_FIRE);
+}
+
+//============================================================================
+//
+// A_FSwordFlames
+//
+//============================================================================
+
+void A_FSwordFlames(mobj_t *actor)
+{
+	int i;
+
+	for (i = 1 + (P_Random() & 3); i; i--)
+	{
+		P_SpawnMobj(actor->x + ((P_Random() - 128) << 12),
+			    actor->y + ((P_Random() - 128) << 12),
+			    actor->z + ((P_Random() - 128) << 11),
+			    MT_FSWORD_FLAME);
+	}
+}
+
+//============================================================================
+//
+// A_MWandAttack
+//
+//============================================================================
+
+void A_MWandAttack(player_t *player, pspdef_t *psp)
+{
+	mobj_t *mo;
+
+	mo = P_SpawnPlayerMissile(player->mo, MT_MWAND_MISSILE);
+	if (mo)
+	{
+		mo->thinker.function = P_BlasterMobjThinker;
+	}
+	S_StartSound(player->mo, SFX_MAGE_WAND_FIRE);
+}
+
+// ===== Mage Lightning Weapon =====
+
+//============================================================================
+//
+// A_LightningReady
+//
+//============================================================================
+
+void A_LightningReady(player_t *player, pspdef_t *psp)
+{
+	A_WeaponReady(player, psp);
+	if (P_Random() < 160)
+	{
+		S_StartSound(player->mo, SFX_MAGE_LIGHTNING_READY);
+	}
+}
+
+//============================================================================
+//
+// A_LightningClip
+//
+//============================================================================
+
+#define ZAGSPEED	FRACUNIT
+
+void A_LightningClip(mobj_t *actor)
+{
+	mobj_t *cMo;
+	mobj_t *target = NULL;  /* jim added initialiser */
+	int zigZag;
+
+	if (actor->type == MT_LIGHTNING_FLOOR)
+	{
+		actor->z = actor->floorz;
+		target = (mobj_t *)((mobj_t *)actor->special2)->special1;
+	}
+	else if (actor->type == MT_LIGHTNING_CEILING)
+	{
+		actor->z = actor->ceilingz - actor->height;
+		target = (mobj_t *)actor->special1;
+	}
+	if (actor->type == MT_LIGHTNING_FLOOR)
+	{ // floor lightning zig-zags, and forces the ceiling lightning to mimic
+		cMo = (mobj_t *)actor->special2;
+		zigZag = P_Random();
+		if ((zigZag > 128 && actor->special1 < 2) || actor->special1 < -2)
+		{
+			P_ThrustMobj(actor, actor->angle + ANG90, ZAGSPEED);
+			if (cMo)
+			{
+				P_ThrustMobj(cMo, actor->angle + ANG90, ZAGSPEED);
+			}
+			actor->special1++;
+		}
+		else
+		{
+			P_ThrustMobj(actor, actor->angle - ANG90, ZAGSPEED);
+			if (cMo)
+			{
+				P_ThrustMobj(cMo, cMo->angle - ANG90, ZAGSPEED);
+			}
+			actor->special1--;
+		}
+	}
+	if (target)
+	{
+		if (target->health <= 0)
+		{
+			P_ExplodeMissile(actor);
+		}
+		else
+		{
+			actor->angle = R_PointToAngle2(actor->x, actor->y, target->x, target->y);
+			actor->momx = 0;
+			actor->momy = 0;
+			P_ThrustMobj(actor, actor->angle, actor->info->speed>>1);
+		}
+	}
+}
+
+//============================================================================
+//
+// A_LightningZap
+//
+//============================================================================
+
+void A_LightningZap(mobj_t *actor)
+{
+	mobj_t *mo;
+	fixed_t deltaZ;
+
+	A_LightningClip(actor);
+
+	actor->health -= 8;
+	if (actor->health <= 0)
+	{
+		P_SetMobjState(actor, actor->info->deathstate);
+		return;
+	}
+	if (actor->type == MT_LIGHTNING_FLOOR)
+	{
+		deltaZ = 10*FRACUNIT;
+	}
+	else
+	{
+		deltaZ = -10*FRACUNIT;
+	}
+	mo = P_SpawnMobj(actor->x + ((P_Random() - 128) * actor->radius/256),
+			 actor->y + ((P_Random() - 128) * actor->radius/256),
+			 actor->z + deltaZ, MT_LIGHTNING_ZAP);
+	if (mo)
+	{
+		mo->special2 = (intptr_t)actor;
+		mo->momx = actor->momx;
+		mo->momy = actor->momy;
+		mo->target = actor->target;
+		if (actor->type == MT_LIGHTNING_FLOOR)
+		{
+			mo->momz = 20*FRACUNIT;
+		}
+		else
+		{
+			mo->momz = -20*FRACUNIT;
+		}
+	}
+	/*
+	mo = P_SpawnMobj(actor->x + ((P_Random() - 128) * actor->radius/256),
+			 actor->y + ((P_Random() - 128) * actor->radius/256),
+			 actor->z+deltaZ, MT_LIGHTNING_ZAP);
+	if (mo)
+	{
+		mo->special2 = (intptr_t)actor;
+		mo->momx = actor->momx;
+		mo->momy = actor->momy;
+		mo->target = actor->target;
+		if (actor->type == MT_LIGHTNING_FLOOR)
+		{
+			mo->momz = 16*FRACUNIT;
+		}
+		else
+		{
+			mo->momz = -16*FRACUNIT;
+		}
+	}
+	*/
+	if (actor->type == MT_LIGHTNING_FLOOR && P_Random() < 160)
+	{
+		S_StartSound(actor, SFX_MAGE_LIGHTNING_CONTINUOUS);
+	}
+}
+
+//============================================================================
+//
+// A_MLightningAttack2
+//
+//============================================================================
+
+void A_MLightningAttack2(mobj_t *actor)
+{
+	mobj_t *fmo, *cmo;
+
+	fmo = P_SpawnPlayerMissile(actor, MT_LIGHTNING_FLOOR);
+	cmo = P_SpawnPlayerMissile(actor, MT_LIGHTNING_CEILING);
+	if (fmo)
+	{
+		fmo->special1 = 0;
+		fmo->special2 = (intptr_t)cmo;
+		A_LightningZap(fmo);
+	}
+	if (cmo)
+	{
+		cmo->special1 = 0;	// mobj that it will track
+		cmo->special2 = (intptr_t)fmo;
+		A_LightningZap(cmo);
+	}
+	S_StartSound(actor, SFX_MAGE_LIGHTNING_FIRE);
+}
+
+//============================================================================
+//
+// A_MLightningAttack
+//
+//============================================================================
+
+void A_MLightningAttack(player_t *player, pspdef_t *psp)
+{
+	A_MLightningAttack2(player->mo);
+	player->mana[MANA_2] -= WeaponManaUse[player->playerclass][player->readyweapon];
+}
+
+//============================================================================
+//
+// A_ZapMimic
+//
+//============================================================================
+
+void A_ZapMimic(mobj_t *actor)
+{
+	mobj_t *mo;
+
+	mo = (mobj_t *)actor->special2;
+	if (mo)
+	{
+		if (mo->state >= &states[mo->info->deathstate]
+			|| mo->state == &states[S_FREETARGMOBJ])
+		{
+			P_ExplodeMissile(actor);
+		}
+		else
+		{
+			actor->momx = mo->momx;
+			actor->momy = mo->momy;
+		}
+	}
+}
+
+//============================================================================
+//
+// A_LastZap
+//
+//============================================================================
+
+void A_LastZap(mobj_t *actor)
+{
+	mobj_t *mo;
+
+	mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_LIGHTNING_ZAP);
+	if (mo)
+	{
+		P_SetMobjState(mo, S_LIGHTNING_ZAP_X1);
+		mo->momz = 40*FRACUNIT;
+	}
+}
+
+//============================================================================
+//
+// A_LightningRemove
+//
+//============================================================================
+
+void A_LightningRemove(mobj_t *actor)
+{
+	mobj_t *mo;
+
+	mo = (mobj_t *)actor->special2;
+	if (mo)
+	{
+		mo->special2 = 0;
+		P_ExplodeMissile(mo);
+	}
+}
+
+
+//============================================================================
+//
+// MStaffSpawn
+//
+//============================================================================
+
+static void MStaffSpawn(mobj_t *pmo, angle_t angle)
+{
+	mobj_t *mo;
+
+	mo = P_SPMAngle(pmo, MT_MSTAFF_FX2, angle);
+	if (mo)
+	{
+		mo->target = pmo;
+		mo->special1 = (intptr_t)P_RoughMonsterSearch(mo, 10);
+	}
+}
+
+//============================================================================
+//
+// A_MStaffAttack
+//
+//============================================================================
+
+void A_MStaffAttack(player_t *player, pspdef_t *psp)
+{
+	angle_t angle;
+	mobj_t *pmo;
+
+	player->mana[MANA_1] -= WeaponManaUse[player->playerclass][player->readyweapon];
+	player->mana[MANA_2] -= WeaponManaUse[player->playerclass][player->readyweapon];
+	pmo = player->mo;
+	angle = pmo->angle;
+
+	MStaffSpawn(pmo, angle);
+	MStaffSpawn(pmo, angle-ANGLE_1*5);
+	MStaffSpawn(pmo, angle+ANGLE_1*5);
+	S_StartSound(player->mo, SFX_MAGE_STAFF_FIRE);
+	if (player == &players[consoleplayer])
+	{
+		player->damagecount = 0;
+		player->bonuscount = 0;
+		V_SetPaletteShift(STARTSCOURGEPAL);
+	}
+}
+
+//============================================================================
+//
+// A_MStaffPalette
+//
+//============================================================================
+
+void A_MStaffPalette(player_t *player, pspdef_t *psp)
+{
+	int pal;
+
+	if (player == &players[consoleplayer])
+	{
+		pal = STARTSCOURGEPAL + psp->state - (&states[S_MSTAFFATK_2]);
+		if (pal == STARTSCOURGEPAL + 3)
+		{ // reset back to original playpal
+			pal = 0;
+		}
+		V_SetPaletteShift(pal);
+	}
+}
+
+//============================================================================
+//
+// A_MStaffWeave
+//
+//============================================================================
+
+void A_MStaffWeave(mobj_t *actor)
+{
+	fixed_t newX, newY;
+	int weaveXY, weaveZ;
+	int angle;
+
+	weaveXY = actor->special2 >> 16;
+	weaveZ = actor->special2 & 0xFFFF;
+	angle = (actor->angle + ANG90)>>ANGLETOFINESHIFT;
+	newX = actor->x - FixedMul(finecosine[angle], FloatBobOffsets[weaveXY]<<2);
+	newY = actor->y - FixedMul(finesine[angle], FloatBobOffsets[weaveXY]<<2);
+	weaveXY = (weaveXY + 6) & 63;
+	newX += FixedMul(finecosine[angle], FloatBobOffsets[weaveXY]<<2);
+	newY += FixedMul(finesine[angle], FloatBobOffsets[weaveXY]<<2);
+	P_TryMove(actor, newX, newY);
+	actor->z -= FloatBobOffsets[weaveZ]<<1;
+	weaveZ = (weaveZ + 3) & 63;
+	actor->z += FloatBobOffsets[weaveZ]<<1;
+	if (actor->z <= actor->floorz)
+	{
+		actor->z = actor->floorz + FRACUNIT;
+	}
+	actor->special2 = weaveZ + (weaveXY<<16);
+}
+
+//============================================================================
+//
+// A_MStaffTrack
+//
+//============================================================================
+
+void A_MStaffTrack(mobj_t *actor)
+{
+	if ((actor->special1 == 0) && (P_Random() < 50))
+	{
+		actor->special1 = (intptr_t)P_RoughMonsterSearch(actor, 10);
+	}
+	P_SeekerMissile(actor, ANGLE_1*2, ANGLE_1*10);
+}
+
+//============================================================================
+//
+// MStaffSpawn2 - for use by mage class boss
+//
+//============================================================================
+
+static void MStaffSpawn2(mobj_t *actor, angle_t angle)
+{
+	mobj_t *mo;
+
+	mo = P_SpawnMissileAngle(actor, MT_MSTAFF_FX2, angle, 0);
+	if (mo)
+	{
+		mo->target = actor;
+		mo->special1 = (intptr_t)P_RoughMonsterSearch(mo, 10);
+	}
+}
+
+//============================================================================
+//
+// A_MStaffAttack2 - for use by mage class boss
+//
+//============================================================================
+
+void A_MStaffAttack2(mobj_t *actor)
+{
+	angle_t angle;
+	angle = actor->angle;
+	MStaffSpawn2(actor, angle);
+	MStaffSpawn2(actor, angle - ANGLE_1*5);
+	MStaffSpawn2(actor, angle + ANGLE_1*5);
+	S_StartSound(actor, SFX_MAGE_STAFF_FIRE);
+}
+
+//============================================================================
+//
+// A_FPunchAttack
+//
+//============================================================================
+
+void A_FPunchAttack(player_t *player, pspdef_t *psp)
+{
+	angle_t angle;
+	int damage;
+	int slope;
+	mobj_t *pmo = player->mo;
+	fixed_t power;
+	int i;
+
+	damage = 40 + (P_Random() & 15);
+	power = 2*FRACUNIT;
+	PuffType = MT_PUNCHPUFF;
+	for (i = 0; i < 16; i++)
+	{
+		angle = pmo->angle + i*(ANG45/16);
+		slope = P_AimLineAttack(pmo, angle, 2*MELEERANGE);
+		if (linetarget)
+		{
+			player->mo->special1++;
+			if (pmo->special1 == 3)
+			{
+				damage <<= 1;
+				power = 6*FRACUNIT;
+				PuffType = MT_HAMMERPUFF;
+			}
+			P_LineAttack(pmo, angle, 2*MELEERANGE, slope, damage);
+			if (linetarget->flags & MF_COUNTKILL || linetarget->player)
+			{
+				P_ThrustMobj(linetarget, angle, power);
+			}
+			AdjustPlayerAngle(pmo);
+			goto punchdone;
+		}
+		angle = pmo->angle - i*(ANG45/16);
+		slope = P_AimLineAttack(pmo, angle, 2*MELEERANGE);
+		if (linetarget)
+		{
+			pmo->special1++;
+			if (pmo->special1 == 3)
+			{
+				damage <<= 1;
+				power = 6*FRACUNIT;
+				PuffType = MT_HAMMERPUFF;
+			}
+			P_LineAttack(pmo, angle, 2*MELEERANGE, slope, damage);
+			if (linetarget->flags & MF_COUNTKILL || linetarget->player)
+			{
+				P_ThrustMobj(linetarget, angle, power);
+			}
+			AdjustPlayerAngle(pmo);
+			goto punchdone;
+		}
+	}
+	// didn't find any creatures, so try to strike any walls
+	pmo->special1 = 0;
+
+	angle = pmo->angle;
+	slope = P_AimLineAttack(pmo, angle, MELEERANGE);
+	P_LineAttack(pmo, angle, MELEERANGE, slope, damage);
+
+punchdone:
+	if (pmo->special1 == 3)
+	{
+		pmo->special1 = 0;
+		P_SetPsprite(player, ps_weapon, S_PUNCHATK2_1);
+		S_StartSound(pmo, SFX_FIGHTER_GRUNT);
+	}
+	return;
+}
+
+//============================================================================
+//
+// A_FAxeAttack
+//
+//============================================================================
+
+#define AXERANGE	2.25*MELEERANGE
+
+void A_FAxeAttack(player_t *player, pspdef_t *psp)
+{
+	angle_t angle;
+	mobj_t *pmo = player->mo;
+	fixed_t power;
+	int damage;
+	int slope;
+	int i;
+	int useMana;
+
+	damage = 40 + (P_Random() & 15) + (P_Random() & 7);
+	power = 0;
+	if (player->mana[MANA_1] > 0)
+	{
+		damage <<= 1;
+		power = 6*FRACUNIT;
+		PuffType = MT_AXEPUFF_GLOW;
+		useMana = 1;
+	}
+	else
+	{
+		PuffType = MT_AXEPUFF;
+		useMana = 0;
+	}
+	for (i = 0; i < 16; i++)
+	{
+		angle = pmo->angle + i*(ANG45/16);
+		slope = P_AimLineAttack(pmo, angle, AXERANGE);
+		if (linetarget)
+		{
+			P_LineAttack(pmo, angle, AXERANGE, slope, damage);
+			if (linetarget->flags&MF_COUNTKILL || linetarget->player)
+			{
+				P_ThrustMobj(linetarget, angle, power);
+			}
+			AdjustPlayerAngle(pmo);
+			useMana++;
+			goto axedone;
+		}
+		angle = pmo->angle - i*(ANG45/16);
+		slope = P_AimLineAttack(pmo, angle, AXERANGE);
+		if (linetarget)
+		{
+			P_LineAttack(pmo, angle, AXERANGE, slope, damage);
+			if (linetarget->flags & MF_COUNTKILL)
+			{
+				P_ThrustMobj(linetarget, angle, power);
+			}
+			AdjustPlayerAngle(pmo);
+			useMana++;
+			goto axedone;
+		}
+	}
+	// didn't find any creatures, so try to strike any walls
+	pmo->special1 = 0;
+
+	angle = pmo->angle;
+	slope = P_AimLineAttack(pmo, angle, MELEERANGE);
+	P_LineAttack(pmo, angle, MELEERANGE, slope, damage);
+
+axedone:
+	if (useMana == 2)
+	{
+		player->mana[MANA_1] -= 
+			WeaponManaUse[player->playerclass][player->readyweapon];
+		if (player->mana[MANA_1] <= 0)
+		{
+			P_SetPsprite(player, ps_weapon, S_FAXEATK_5);
+		}
+	}
+	return;
+}
+
+//===========================================================================
+//
+// A_CMaceAttack
+//
+//===========================================================================
+
+void A_CMaceAttack(player_t *player, pspdef_t *psp)
+{
+	angle_t angle;
+	int damage;
+	int slope;
+	int i;
+
+	damage = 25 + (P_Random() & 15);
+	PuffType = MT_HAMMERPUFF;
+	for (i = 0; i < 16; i++)
+	{
+		angle = player->mo->angle + i*(ANG45/16);
+		slope = P_AimLineAttack(player->mo, angle, 2*MELEERANGE);
+		if (linetarget)
+		{
+			P_LineAttack(player->mo, angle, 2*MELEERANGE, slope, damage);
+			AdjustPlayerAngle(player->mo);
+//			player->mo->angle = R_PointToAngle2(player->mo->x,
+//				player->mo->y, linetarget->x, linetarget->y);
+			goto macedone;
+		}
+		angle = player->mo->angle - i*(ANG45/16);
+		slope = P_AimLineAttack(player->mo, angle, 2*MELEERANGE);
+		if (linetarget)
+		{
+			P_LineAttack(player->mo, angle, 2*MELEERANGE, slope, damage);
+			AdjustPlayerAngle(player->mo);
+//			player->mo->angle = R_PointToAngle2(player->mo->x,
+//				player->mo->y, linetarget->x, linetarget->y);
+			goto macedone;
+		}
+	}
+	// didn't find any creatures, so try to strike any walls
+	player->mo->special1 = 0;
+
+	angle = player->mo->angle;
+	slope = P_AimLineAttack(player->mo, angle, MELEERANGE);
+	P_LineAttack(player->mo, angle, MELEERANGE, slope, damage);
+
+macedone:
+	return;
+}
+
+//============================================================================
+//
+// A_CStaffCheck
+//
+//============================================================================
+
+void A_CStaffCheck(player_t *player, pspdef_t *psp)
+{
+	mobj_t *pmo;
+	int damage;
+	int newLife;
+	angle_t angle;
+	int slope;
+	int i;
+
+	pmo = player->mo;
+	damage = 20 + (P_Random() & 15);
+	PuffType = MT_CSTAFFPUFF;
+	for (i = 0; i < 3; i++)
+	{
+		angle = pmo->angle + i*(ANG45/16);
+		slope = P_AimLineAttack(pmo, angle, 1.5*MELEERANGE);
+		if (linetarget)
+		{
+			P_LineAttack(pmo, angle, 1.5*MELEERANGE, slope, damage);
+			pmo->angle = R_PointToAngle2(pmo->x, pmo->y, 
+							linetarget->x, linetarget->y);
+			if ((linetarget->player || linetarget->flags & MF_COUNTKILL)
+				&& (!(linetarget->flags2 & (MF2_DORMANT+MF2_INVULNERABLE))))
+			{
+				newLife = player->health + (damage>>3);
+				newLife = newLife > 100 ? 100 : newLife;
+				pmo->health = player->health = newLife;
+				P_SetPsprite(player, ps_weapon, S_CSTAFFATK2_1);
+			}
+			player->mana[MANA_1] -= 
+				WeaponManaUse[player->playerclass][player->readyweapon];
+			break;
+		}
+		angle = pmo->angle - i*(ANG45/16);
+		slope = P_AimLineAttack(player->mo, angle, 1.5*MELEERANGE);
+		if (linetarget)
+		{
+			P_LineAttack(pmo, angle, 1.5*MELEERANGE, slope, damage);
+			pmo->angle = R_PointToAngle2(pmo->x, pmo->y, 
+						linetarget->x, linetarget->y);
+			if (linetarget->player || linetarget->flags & MF_COUNTKILL)
+			{
+				newLife = player->health + (damage>>4);
+				newLife = newLife > 100 ? 100 : newLife;
+				pmo->health = player->health = newLife;
+				P_SetPsprite(player, ps_weapon, S_CSTAFFATK2_1);
+			}
+			player->mana[MANA_1] -= 
+				WeaponManaUse[player->playerclass][player->readyweapon];
+			break;
+		}
+	}
+}
+
+//============================================================================
+//
+// A_CStaffAttack
+//
+//============================================================================
+
+void A_CStaffAttack(player_t *player, pspdef_t *psp)
+{
+	mobj_t *mo;
+	mobj_t *pmo;
+
+	player->mana[MANA_1] -=	WeaponManaUse[player->playerclass][player->readyweapon];
+	pmo = player->mo;
+	mo = P_SPMAngle(pmo, MT_CSTAFF_MISSILE, pmo->angle - (ANG45/15));
+	if (mo)
+	{
+		mo->special2 = 32;
+	}
+	mo = P_SPMAngle(pmo, MT_CSTAFF_MISSILE, pmo->angle + (ANG45/15));
+	if (mo)
+	{
+		mo->special2 = 0;
+	}
+	S_StartSound(player->mo, SFX_CLERIC_CSTAFF_FIRE);
+}
+
+//============================================================================
+//
+// A_CStaffMissileSlither
+//
+//============================================================================
+
+void A_CStaffMissileSlither(mobj_t *actor)
+{
+	fixed_t newX, newY;
+	int weaveXY;
+	int angle;
+
+	weaveXY = actor->special2;
+	angle = (actor->angle + ANG90)>>ANGLETOFINESHIFT;
+	newX = actor->x - FixedMul(finecosine[angle], FloatBobOffsets[weaveXY]);
+	newY = actor->y - FixedMul(finesine[angle], FloatBobOffsets[weaveXY]);
+	weaveXY = (weaveXY + 3) & 63;
+	newX += FixedMul(finecosine[angle], FloatBobOffsets[weaveXY]);
+	newY += FixedMul(finesine[angle], FloatBobOffsets[weaveXY]);
+	P_TryMove(actor, newX, newY);
+	actor->special2 = weaveXY;
+}
+
+//============================================================================
+//
+// A_CStaffInitBlink
+//
+//============================================================================
+
+void A_CStaffInitBlink(player_t *player, pspdef_t *psp)
+{
+	player->mo->special1 = (P_Random()>>1) + 20;
+}
+
+//============================================================================
+//
+// A_CStaffCheckBlink
+//
+//============================================================================
+
+void A_CStaffCheckBlink(player_t *player, pspdef_t *psp)
+{
+	if (!--player->mo->special1)
+	{
+		P_SetPsprite(player, ps_weapon, S_CSTAFFBLINK1);
+		player->mo->special1 = (P_Random() + 50)>>2;
+	}
+}
+
+//============================================================================
+//
+// A_CFlameAttack
+//
+//============================================================================
+
+#define FLAMESPEED	(0.45*FRACUNIT)
+#define CFLAMERANGE	(12*64*FRACUNIT)
+
+void A_CFlameAttack(player_t *player, pspdef_t *psp)
+{
+	mobj_t *mo;
+
+	mo = P_SpawnPlayerMissile(player->mo, MT_CFLAME_MISSILE);
+	if (mo)
+	{
+		mo->thinker.function = P_BlasterMobjThinker;
+		mo->special1 = 2;
+	}
+
+	player->mana[MANA_2] -= WeaponManaUse[player->playerclass][player->readyweapon];
+	S_StartSound(player->mo, SFX_CLERIC_FLAME_FIRE);
+}
+
+//============================================================================
+//
+// A_CFlamePuff
+//
+//============================================================================
+
+void A_CFlamePuff(mobj_t *actor)
+{
+	A_UnHideThing(actor);
+	actor->momx = 0;
+	actor->momy = 0;
+	actor->momz = 0;
+	S_StartSound(actor, SFX_CLERIC_FLAME_EXPLODE);
+}
+
+//============================================================================
+//
+// A_CFlameMissile
+//
+//============================================================================
+
+void A_CFlameMissile(mobj_t *actor)
+{
+	int i;
+	int an;
+//	int an90;
+	fixed_t dist;
+	mobj_t *mo;
+
+	A_UnHideThing(actor);
+	S_StartSound(actor, SFX_CLERIC_FLAME_EXPLODE);
+	if (BlockingMobj && BlockingMobj->flags & MF_SHOOTABLE)
+	{ // Hit something, so spawn the flame circle around the thing
+		dist = BlockingMobj->radius + 18*FRACUNIT;
+		for (i = 0; i < 4; i++)
+		{
+			an = (i*ANG45)>>ANGLETOFINESHIFT;
+		//	an90 = (i*ANG45 + ANG90)>>ANGLETOFINESHIFT;
+			mo = P_SpawnMobj(BlockingMobj->x + FixedMul(dist, finecosine[an]),
+					 BlockingMobj->y + FixedMul(dist, finesine[an]),
+					 BlockingMobj->z + 5*FRACUNIT, MT_CIRCLEFLAME);
+			if (mo)
+			{
+				mo->angle = an<<ANGLETOFINESHIFT;
+				mo->target = actor->target;
+				mo->momx = mo->special1 = FixedMul(finecosine[an], FLAMESPEED);
+				mo->momy = mo->special2 = FixedMul(finesine[an], FLAMESPEED);
+				mo->tics -= P_Random() & 3;
+			}
+			mo = P_SpawnMobj(BlockingMobj->x - FixedMul(dist, finecosine[an]),
+					 BlockingMobj->y - FixedMul(dist, finesine[an]),
+					 BlockingMobj->z + 5*FRACUNIT, MT_CIRCLEFLAME);
+			if (mo)
+			{
+				mo->angle = ANG180 + (an<<ANGLETOFINESHIFT);
+				mo->target = actor->target;
+				mo->momx = mo->special1 = FixedMul(finecosine[an], -FLAMESPEED);
+				mo->momy = mo->special2 = FixedMul(finesine[an], -FLAMESPEED);
+				mo->tics -= P_Random() & 3;
+			}
+		}
+		P_SetMobjState(actor, S_FLAMEPUFF2_1);
+	}
+}
+
+/*
+void A_CFlameAttack(player_t *player, pspdef_t *psp)
+{
+	mobj_t *pmo;
+	angle_t angle;
+	int damage;
+	int i;
+	int an;
+//	int an90;
+	fixed_t dist;
+	mobj_t *mo;
+
+	pmo = player->mo;
+	P_BulletSlope(pmo);
+	damage = 25 + HITDICE(3);
+	angle = pmo->angle;
+	if (player->refire)
+	{
+		angle += (P_Random() - P_Random()) << 17;
+	}
+	P_AimLineAttack(pmo, angle, CFLAMERANGE); // Correctly set linetarget
+	if (!linetarget)
+	{
+		angle += ANGLE_1*2;
+		P_AimLineAttack(pmo, angle, CFLAMERANGE);
+		if (!linetarget)
+		{
+			angle -= ANGLE_1*4;
+			P_AimLineAttack(pmo, angle, CFLAMERANGE);
+			if (!linetarget)
+			{
+				angle += ANGLE_1*2;
+			}
+		}
+	}
+	if (linetarget)
+	{
+		PuffType = MT_FLAMEPUFF2;
+	}
+	else
+	{
+		PuffType = MT_FLAMEPUFF;
+	}
+	P_LineAttack(pmo, angle, CFLAMERANGE, bulletslope, damage);
+	if (linetarget)
+	{ // Hit something, so spawn the flame circle around the thing
+		dist = linetarget->radius + 18*FRACUNIT;
+		for (i = 0; i < 4; i++)
+		{
+			an = (i*ANG45)>>ANGLETOFINESHIFT;
+		//	an90 = (i*ANG45 + ANG90)>>ANGLETOFINESHIFT;
+			mo = P_SpawnMobj(linetarget->x + FixedMul(dist, finecosine[an]),
+					 linetarget->y + FixedMul(dist, finesine[an]),
+					 linetarget->z + 5*FRACUNIT, MT_CIRCLEFLAME);
+			if (mo)
+			{
+				mo->angle = an<<ANGLETOFINESHIFT;
+				mo->target = pmo;
+				mo->momx = mo->special1 = FixedMul(FLAMESPEED, finecosine[an]);
+				mo->momy = mo->special2 = FixedMul(FLAMESPEED, finesine[an]);
+				mo->tics -= P_Random() & 3;
+			}
+			mo = P_SpawnMobj(linetarget->x - FixedMul(dist, finecosine[an]),
+					 linetarget->y - FixedMul(dist, finesine[an]),
+					 linetarget->z + 5*FRACUNIT, MT_CIRCLEFLAME);
+			if (mo)
+			{
+				mo->angle = ANG180 + (an<<ANGLETOFINESHIFT);
+				mo->target = pmo;
+				mo->momx = mo->special1 = FixedMul(-FLAMESPEED, finecosine[an]);
+				mo->momy = mo->special2 = FixedMul(-FLAMESPEED, finesine[an]);
+				mo->tics -= P_Random() & 3;
+			}
+		}
+	}
+// Create a line of flames from the player to the flame puff
+	CFlameCreateFlames(player->mo);
+
+	player->mana[MANA_2] -= WeaponManaUse[player->playerclass][player->readyweapon];
+	S_StartSound(player->mo, SFX_CLERIC_FLAME_FIRE);
+}
+*/
+
+//============================================================================
+//
+// A_CFlameRotate
+//
+//============================================================================
+
+#define FLAMEROTSPEED	2*FRACUNIT
+
+void A_CFlameRotate(mobj_t *actor)
+{
+	int an;
+
+	an = (actor->angle + ANG90)>>ANGLETOFINESHIFT;
+	actor->momx = actor->special1 + FixedMul(FLAMEROTSPEED, finecosine[an]);
+	actor->momy = actor->special2 + FixedMul(FLAMEROTSPEED, finesine[an]);
+	actor->angle += ANG90/15;
+}
+
+
+//============================================================================
+//
+// A_CHolyAttack3
+//
+// 	Spawns the spirits
+//============================================================================
+
+void A_CHolyAttack3(mobj_t *actor)
+{
+	P_SpawnMissile(actor, actor->target, MT_HOLY_MISSILE);
+	S_StartSound(actor, SFX_CHOLY_FIRE);
+}
+
+
+//============================================================================
+//
+// A_CHolyAttack2 
+//
+// 	Spawns the spirits
+//============================================================================
+
+void A_CHolyAttack2(mobj_t *actor)
+{
+	int j;
+	int i;
+	mobj_t *mo;
+	mobj_t *tail, *next;
+
+	for (j = 0; j < 4; j++)
+	{
+		mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_HOLY_FX);
+		if (!mo)
+		{
+			continue;
+		}
+		switch (j)
+		{ // float bob index
+		case 0:
+			mo->special2 = P_Random() & 7;			// upper-left
+			break;
+		case 1:
+			mo->special2 = 32 + (P_Random() & 7);		// upper-right
+			break;
+		case 2:
+			mo->special2 = (32 + (P_Random() & 7)) << 16;	// lower-left
+			break;
+		case 3:
+			mo->special2 = ((32 + (P_Random() & 7)) << 16) + 32 + (P_Random() & 7);
+			break;
+		}
+		mo->z = actor->z;
+		mo->angle = actor->angle + (ANGLE_45 + ANGLE_45/2) - ANGLE_45*j;
+		P_ThrustMobj(mo, mo->angle, mo->info->speed);
+		mo->target = actor->target;
+		mo->args[0] = 10; // initial turn value
+		mo->args[1] = 0; // initial look angle
+		if (deathmatch)
+		{ // Ghosts last slightly less longer in DeathMatch
+			mo->health = 85;
+		}
+		if (linetarget)
+		{
+			mo->special1 = (intptr_t)linetarget;
+			mo->flags |= MF_NOCLIP|MF_SKULLFLY;
+			mo->flags &= ~MF_MISSILE;
+		}
+		tail = P_SpawnMobj(mo->x, mo->y, mo->z, MT_HOLY_TAIL);
+		tail->special2 = (intptr_t)mo;	// parent
+		for (i = 1; i < 3; i++)
+		{
+			next = P_SpawnMobj(mo->x, mo->y, mo->z, MT_HOLY_TAIL);
+			P_SetMobjState(next, next->info->spawnstate + 1);
+			tail->special1 = (intptr_t)next;
+			tail = next;
+		}
+		tail->special1 = 0; // last tail bit
+	}
+}
+
+//============================================================================
+//
+// A_CHolyAttack
+//
+//============================================================================
+
+void A_CHolyAttack(player_t *player, pspdef_t *psp)
+{
+	player->mana[MANA_1] -= WeaponManaUse[player->playerclass][player->readyweapon];
+	player->mana[MANA_2] -= WeaponManaUse[player->playerclass][player->readyweapon];
+	P_SpawnPlayerMissile(player->mo, MT_HOLY_MISSILE);
+	if (player == &players[consoleplayer])
+	{
+		player->damagecount = 0;
+		player->bonuscount = 0;
+		V_SetPaletteShift(STARTHOLYPAL);
+	}
+	S_StartSound(player->mo, SFX_CHOLY_FIRE);
+}
+
+//============================================================================
+//
+// A_CHolyPalette
+//
+//============================================================================
+
+void A_CHolyPalette(player_t *player, pspdef_t *psp)
+{
+	int pal;
+
+	if (player == &players[consoleplayer])
+	{
+		pal = STARTHOLYPAL+psp->state - (&states[S_CHOLYATK_6]);
+		if (pal == STARTHOLYPAL + 3)
+		{ // reset back to original playpal
+			pal = 0;
+		}
+		V_SetPaletteShift(pal);
+	}
+}
+
+//============================================================================
+//
+// CHolyFindTarget
+//
+//============================================================================
+
+static void CHolyFindTarget(mobj_t *actor)
+{
+	mobj_t *target;
+
+	if ((target = P_RoughMonsterSearch(actor, 6)))
+	{
+		actor->special1 = (intptr_t)target;
+		actor->flags |= MF_NOCLIP|MF_SKULLFLY;
+		actor->flags &= ~MF_MISSILE;
+	}
+}
+
+//============================================================================
+//
+// CHolySeekerMissile
+//
+// 	 Similar to P_SeekerMissile, but seeks to a random Z on the target
+//============================================================================
+
+static void CHolySeekerMissile(mobj_t *actor, angle_t thresh, angle_t turnMax)
+{
+	int dir;
+	int dist;
+	angle_t delta;
+	angle_t angle;
+	mobj_t *target;
+	fixed_t newZ;
+	fixed_t deltaZ;
+
+	target = (mobj_t *)actor->special1;
+	if (target == NULL)
+	{
+		return;
+	}
+	if (!(target->flags & MF_SHOOTABLE) ||
+	   (!(target->flags & MF_COUNTKILL) && !target->player))
+	{ // Target died/target isn't a player or creature
+		actor->special1 = 0;
+		actor->flags &= ~(MF_NOCLIP|MF_SKULLFLY);
+		actor->flags |= MF_MISSILE;
+		CHolyFindTarget(actor);
+		return;
+	}
+	dir = P_FaceMobj(actor, target, &delta);
+	if (delta > thresh)
+	{
+		delta >>= 1;
+		if (delta > turnMax)
+		{
+			delta = turnMax;
+		}
+	}
+	if (dir)
+	{ // Turn clockwise
+		actor->angle += delta;
+	}
+	else
+	{ // Turn counter clockwise
+		actor->angle -= delta;
+	}
+	angle = actor->angle>>ANGLETOFINESHIFT;
+	actor->momx = FixedMul(actor->info->speed, finecosine[angle]);
+	actor->momy = FixedMul(actor->info->speed, finesine[angle]);
+	if (!(leveltime & 15)
+		|| actor->z > target->z + (target->height)
+		|| actor->z + actor->height < target->z)
+	{
+		newZ = target->z + ((P_Random()*target->height)>>8);
+		deltaZ = newZ - actor->z;
+		if (abs(deltaZ) > 15*FRACUNIT)
+		{
+			if (deltaZ > 0)
+			{
+				deltaZ = 15*FRACUNIT;
+			}
+			else
+			{
+				deltaZ = -15*FRACUNIT;
+			}
+		}
+		dist = P_AproxDistance(target->x - actor->x, target->y - actor->y);
+		dist = dist / actor->info->speed;
+		if (dist < 1)
+		{
+			dist = 1;
+		}
+		actor->momz = deltaZ / dist;
+	}
+	return;
+}
+
+//============================================================================
+//
+// A_CHolyWeave
+//
+//============================================================================
+
+static void CHolyWeave(mobj_t *actor)
+{
+	fixed_t newX, newY;
+	int weaveXY, weaveZ;
+	int angle;
+
+	weaveXY = actor->special2 >> 16;
+	weaveZ = actor->special2 & 0xFFFF;
+	angle = (actor->angle + ANG90)>>ANGLETOFINESHIFT;
+	newX = actor->x-FixedMul(finecosine[angle], FloatBobOffsets[weaveXY]<<2);
+	newY = actor->y-FixedMul(finesine[angle], FloatBobOffsets[weaveXY]<<2);
+	weaveXY = (weaveXY + (P_Random() % 5)) & 63;
+	newX += FixedMul(finecosine[angle], FloatBobOffsets[weaveXY]<<2);
+	newY += FixedMul(finesine[angle], FloatBobOffsets[weaveXY]<<2);
+	P_TryMove(actor, newX, newY);
+	actor->z -= FloatBobOffsets[weaveZ]<<1;
+	weaveZ = (weaveZ + (P_Random() % 5)) & 63;
+	actor->z += FloatBobOffsets[weaveZ]<<1;
+	actor->special2 = weaveZ + (weaveXY<<16);
+}
+
+//============================================================================
+//
+// A_CHolySeek
+//
+//============================================================================
+
+void A_CHolySeek(mobj_t *actor)
+{
+	actor->health--;
+	if (actor->health <= 0)
+	{
+		actor->momx >>= 2;
+		actor->momy >>= 2;
+		actor->momz = 0;
+		P_SetMobjState(actor, actor->info->deathstate);
+		actor->tics -= P_Random() & 3;
+		return;
+	}
+	if (actor->special1)
+	{
+		CHolySeekerMissile(actor, actor->args[0]*ANGLE_1,
+					actor->args[0]*ANGLE_1*2);
+		if (!((leveltime + 7) & 15))
+		{
+			actor->args[0] = 5 + (P_Random()/20);
+		}
+	}
+	CHolyWeave(actor);
+}
+
+//============================================================================
+//
+// CHolyTailFollow
+//
+//============================================================================
+
+static void CHolyTailFollow(mobj_t *actor, fixed_t dist)
+{
+	mobj_t *child;
+	int an;
+	fixed_t oldDistance, newDistance;
+
+	child = (mobj_t *)actor->special1;
+	if (child)
+	{
+		an = R_PointToAngle2(actor->x, actor->y, child->x, child->y)>>ANGLETOFINESHIFT;
+		oldDistance = P_AproxDistance(child->x - actor->x, child->y - actor->y);
+		if (P_TryMove(child,
+				actor->x + FixedMul(dist, finecosine[an]),
+				actor->y + FixedMul(dist, finesine[an])))
+		{
+			newDistance = P_AproxDistance(child->x-actor->x, child->y-actor->y) - FRACUNIT;
+			if (oldDistance < FRACUNIT)
+			{
+				if (child->z < actor->z)
+				{
+					child->z = actor->z - dist;
+				}
+				else
+				{
+					child->z = actor->z + dist;
+				}
+			}
+			else
+			{
+				child->z = 
+					actor->z + 
+					FixedMul(FixedDiv(newDistance, oldDistance), child->z - actor->z);
+			}
+		}
+		CHolyTailFollow(child, dist - FRACUNIT);
+	}
+}
+
+//============================================================================
+//
+// CHolyTailRemove
+//
+//============================================================================
+
+static void CHolyTailRemove(mobj_t *actor)
+{
+	mobj_t *child;
+
+	child = (mobj_t *)actor->special1;
+	if (child)
+	{
+		CHolyTailRemove(child);
+	}
+	P_RemoveMobj(actor);
+}
+
+//============================================================================
+//
+// A_CHolyTail
+//
+//============================================================================
+
+void A_CHolyTail(mobj_t *actor)
+{
+	mobj_t *parent;
+
+	parent = (mobj_t *)actor->special2;
+
+	if (parent)
+	{
+		if (parent->state >= &states[parent->info->deathstate])
+		{ // Ghost removed, so remove all tail parts
+			CHolyTailRemove(actor);
+			return;
+		}
+		else if (P_TryMove(actor,
+				   parent->x - FixedMul(14*FRACUNIT,
+							finecosine[parent->angle>>ANGLETOFINESHIFT]),
+				   parent->y - FixedMul(14*FRACUNIT,
+							finesine[parent->angle>>ANGLETOFINESHIFT])))
+		{
+			actor->z = parent->z-5*FRACUNIT;
+		}
+		CHolyTailFollow(actor, 10*FRACUNIT);
+	}
+}
+//============================================================================
+//
+// A_CHolyCheckScream
+//
+//============================================================================
+
+void A_CHolyCheckScream(mobj_t *actor)
+{
+	A_CHolySeek(actor);
+	if (P_Random() < 20)
+	{
+		S_StartSound(actor, SFX_SPIRIT_ACTIVE);
+	}
+	if (!actor->special1)
+	{
+		CHolyFindTarget(actor);
+	}
+}
+
+//============================================================================
+//
+// A_CHolySpawnPuff
+//
+//============================================================================
+
+void A_CHolySpawnPuff(mobj_t *actor)
+{
+	P_SpawnMobj(actor->x, actor->y, actor->z, MT_HOLY_MISSILE_PUFF);
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_FireConePL1
+//
+//----------------------------------------------------------------------------
+
+#define SHARDSPAWN_LEFT		1
+#define SHARDSPAWN_RIGHT	2
+#define SHARDSPAWN_UP		4
+#define SHARDSPAWN_DOWN		8
+
+void A_FireConePL1(player_t *player, pspdef_t *psp)
+{
+	angle_t angle;
+	int damage;
+	int slope;
+	int i;
+	mobj_t *pmo, *mo;
+	int conedone = false;
+
+	pmo = player->mo;
+	player->mana[MANA_1] -= WeaponManaUse[player->playerclass][player->readyweapon];
+	S_StartSound(pmo, SFX_MAGE_SHARDS_FIRE);
+
+	damage = 90 + (P_Random() & 15);
+	for (i = 0; i < 16; i++)
+	{
+		angle = pmo->angle + i*(ANG45/16);
+		slope = P_AimLineAttack(pmo, angle, MELEERANGE);
+		(void) slope; /* variable set but not used */
+		if (linetarget)
+		{
+			pmo->flags2 |= MF2_ICEDAMAGE;
+			P_DamageMobj(linetarget, pmo, pmo, damage);
+			pmo->flags2 &= ~MF2_ICEDAMAGE;
+			conedone = true;
+			break;
+		}
+	}
+
+	// didn't find any creatures, so fire projectiles
+	if (!conedone)
+	{
+		mo = P_SpawnPlayerMissile(pmo, MT_SHARDFX1);
+		if (mo)
+		{
+			mo->special1 = SHARDSPAWN_LEFT|SHARDSPAWN_DOWN|SHARDSPAWN_UP
+								|SHARDSPAWN_RIGHT;
+			mo->special2 = 3; // Set sperm count (levels of reproductivity)
+			mo->target = pmo;
+			mo->args[0] = 3;	// Mark Initial shard as super damage
+		}
+	}
+}
+
+void A_ShedShard(mobj_t *actor)
+{
+	mobj_t *mo;
+	int spawndir = actor->special1;
+	int spermcount = actor->special2;
+
+	if (spermcount <= 0)
+		return;			// No sperm left
+	actor->special2 = 0;
+	spermcount--;
+
+	// every so many calls, spawn a new missile in it's set directions
+	if (spawndir & SHARDSPAWN_LEFT)
+	{
+		mo = P_SpawnMissileAngleSpeed(actor, MT_SHARDFX1, actor->angle + (ANG45/9),
+							 0, (20 + 2*spermcount)<<FRACBITS);
+		if (mo)
+		{
+			mo->special1 = SHARDSPAWN_LEFT;
+			mo->special2 = spermcount;
+			mo->momz = actor->momz;
+			mo->target = actor->target;
+			mo->args[0] = (spermcount == 3) ? 2 : 0;
+		}
+	}
+	if (spawndir & SHARDSPAWN_RIGHT)
+	{
+		mo = P_SpawnMissileAngleSpeed(actor, MT_SHARDFX1, actor->angle - (ANG45/9),
+							 0, (20 + 2*spermcount)<<FRACBITS);
+		if (mo)
+		{
+			mo->special1 = SHARDSPAWN_RIGHT;
+			mo->special2 = spermcount;
+			mo->momz = actor->momz;
+			mo->target = actor->target;
+			mo->args[0] = (spermcount == 3) ? 2 : 0;
+		}
+	}
+	if (spawndir & SHARDSPAWN_UP)
+	{
+		mo = P_SpawnMissileAngleSpeed(actor, MT_SHARDFX1, actor->angle,
+							 0, (15 + 2*spermcount)<<FRACBITS);
+		if (mo)
+		{
+			mo->momz = actor->momz;
+			mo->z += 8*FRACUNIT;
+			if (spermcount & 1)			// Every other reproduction
+				mo->special1 = SHARDSPAWN_UP | SHARDSPAWN_LEFT | SHARDSPAWN_RIGHT;
+			else
+				mo->special1 = SHARDSPAWN_UP;
+			mo->special2 = spermcount;
+			mo->target = actor->target;
+			mo->args[0] = (spermcount == 3) ? 2 : 0;
+		}
+	}
+	if (spawndir & SHARDSPAWN_DOWN)
+	{
+		mo = P_SpawnMissileAngleSpeed(actor, MT_SHARDFX1, actor->angle,
+							 0, (15 + 2*spermcount)<<FRACBITS);
+		if (mo)
+		{
+			mo->momz = actor->momz;
+			mo->z -= 4*FRACUNIT;
+			if (spermcount & 1)			// Every other reproduction
+				mo->special1 = SHARDSPAWN_DOWN | SHARDSPAWN_LEFT | SHARDSPAWN_RIGHT;
+			else
+				mo->special1 = SHARDSPAWN_DOWN;
+			mo->special2 = spermcount;
+			mo->target = actor->target;
+			mo->args[0] = (spermcount == 3) ? 2 : 0;
+		}
+	}
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_HideInCeiling
+//
+//----------------------------------------------------------------------------
+
+/*
+void A_HideInCeiling(mobj_t *actor)
+{
+	actor->z = actor->ceilingz + 4*FRACUNIT;
+}
+*/
+
+//----------------------------------------------------------------------------
+//
+// PROC A_FloatPuff
+//
+//----------------------------------------------------------------------------
+
+/*
+void A_FloatPuff(mobj_t *puff)
+{
+	puff->momz += 1.8*FRACUNIT;
+}
+*/
+
+void A_Light0(player_t *player, pspdef_t *psp)
+{
+	player->extralight = 0;
+}
+
+/*
+void A_Light1(player_t *player, pspdef_t *psp)
+{
+	player->extralight = 1;
+}
+*/
+
+/*
+void A_Light2(player_t *player, pspdef_t *psp)
+{
+	player->extralight = 2;
+}
+*/
+
+//------------------------------------------------------------------------
+//
+// PROC P_SetupPsprites
+//
+// Called at start of level for each player
+//
+//------------------------------------------------------------------------
+
+void P_SetupPsprites(player_t *player)
+{
+	int i;
+
+	// Remove all psprites
+	for (i = 0; i < NUMPSPRITES; i++)
+	{
+		player->psprites[i].state = NULL;
+	}
+	// Spawn the ready weapon
+	player->pendingweapon = player->readyweapon;
+	P_BringUpWeapon(player);
+}
+
+//------------------------------------------------------------------------
+//
+// PROC P_MovePsprites
+//
+// Called every tic by player thinking routine
+//
+//------------------------------------------------------------------------
+
+void P_MovePsprites(player_t *player)
+{
+	int i;
+	pspdef_t *psp;
+	state_t *state;
+
+	psp = &player->psprites[0];
+	for (i = 0; i < NUMPSPRITES; i++, psp++)
+	{
+		if ((state = psp->state) != 0)	// a null state means not active
+		{
+			// drop tic count and possibly change state
+			if (psp->tics != -1)	// a -1 tic count never changes
+			{
+				psp->tics--;
+				if (!psp->tics)
+				{
+					P_SetPsprite(player, i, psp->state->nextstate);
+				}
+			}
+		}
+	}
+	player->psprites[ps_flash].sx = player->psprites[ps_weapon].sx;
+	player->psprites[ps_flash].sy = player->psprites[ps_weapon].sy;
+}
+
+
+//============================================================================
+//
+// ASSASSIN WEAPONS / ATTACKS (ADD-ON CLASS FROM HEXEN II)
+//
+//============================================================================
+
+#if defined(ASSASSIN)
+
+//============================================================================
+//
+// A_AKnifeAttack
+//
+// Jim Cameron did most of this one
+//============================================================================
+
+void A_AKnifeAttack(player_t *player, pspdef_t *psp)
+{
+	angle_t angle;
+	int damage;
+	int slope;
+	mobj_t *pmo = player->mo;
+	fixed_t power;
+	int i;
+	boolean oof = false;
+
+	/* jim - the Katar should be a bit feebler */
+	damage = 20 + (P_Random() & 15);
+	power = 2*FRACUNIT;
+	PuffType = MT_PUNCHPUFF;
+
+	for (i = 0; i < 16; i++)
+	{
+		angle = pmo->angle + i*(ANG45/16);
+		slope = P_AimLineAttack(pmo, angle, 2*MELEERANGE);
+		if (linetarget)
+		{
+			player->mo->special1++;
+		/*
+		 * jim - this is the Mighty Blow for the fighter and is
+		 *  not useful here
+		 */
+#if 0
+			if (pmo->special1 == 3)
+			{
+				damage <<= 1;
+				power = 6*FRACUNIT;
+				PuffType = MT_HAMMERPUFF;
+			}
+#endif
+		/*
+		 * jim - instead of that we make the Katar deal more
+		 *  damage to a monster if struck from behind. Assume
+		 *  so if the angle of striking is within 45 degrees
+		 *  of the angle the target is facing in
+		 * OOOPS! but only if it IS a monster! Striking trees from
+		 *  behind might be amusing but doesn't do much for realism 8-)
+		 */
+			if (linetarget->flags & MF_COUNTKILL || linetarget->player)
+			{
+				if ((angle - linetarget->angle < ANG45) ||
+					(linetarget->angle - angle < ANG45))
+				{
+					damage *= 15;
+					power = 6 * FRACUNIT;
+					PuffType = MT_HAMMERPUFF;
+					oof = true;
+				}
+			}
+			P_LineAttack(pmo, angle, 2*MELEERANGE, slope, damage);
+			if (linetarget->flags & MF_COUNTKILL || linetarget->player)
+			{
+				P_ThrustMobj(linetarget, angle, power);
+			}
+			AdjustPlayerAngle(pmo);
+			goto knifedone;
+		}
+
+		angle = pmo->angle - i*(ANG45/16);
+		slope = P_AimLineAttack(pmo, angle, 2*MELEERANGE);
+		if (linetarget)
+		{
+			player->mo->special1++;
+		/*
+		 * jim - this is the Mighty Blow for the fighter and is
+		 *  not useful here
+		 */
+#if 0
+			if (pmo->special1 == 3)
+			{
+				damage <<= 1;
+				power = 6*FRACUNIT;
+				PuffType = MT_HAMMERPUFF;
+			}
+#endif
+		/*
+		 * jim - instead of that we make the Katar deal more
+		 *  damage to a monster if struck from behind. Assume
+		 *  so if the angle of striking is within 45 degrees
+		 *  of the angle the target is facing in
+		 * OOOPS! but only if it IS a monster! Striking trees from
+		 *  behind might be amusing but doesn't do much for realism 8-)
+		 */
+			if (linetarget->flags & MF_COUNTKILL || linetarget->player)
+			{
+				if ((angle - linetarget->angle < ANG45) ||
+					(linetarget->angle - angle < ANG45))
+				{
+					damage *= 15;
+					power = 6 * FRACUNIT;
+					PuffType = MT_HAMMERPUFF;
+					oof = true;
+				}
+			}
+
+			P_LineAttack(pmo, angle, 2*MELEERANGE, slope, damage);
+			if (linetarget->flags & MF_COUNTKILL || linetarget->player)
+			{
+				P_ThrustMobj(linetarget, angle, power);
+			}
+			AdjustPlayerAngle(pmo);
+			goto knifedone;
+		}
+	}
+
+	/* didn't find any creatures, so try to strike any walls*/
+	pmo->special1 = 0;
+
+	angle = pmo->angle;
+	slope = P_AimLineAttack(pmo, angle, MELEERANGE);
+	P_LineAttack(pmo, angle, MELEERANGE, slope, damage);
+
+knifedone:
+	if (oof)
+	{
+		pmo->special1 = 0;
+		P_SetPsprite(player, ps_weapon, S_KATARATK2_1);
+		/* jim - come on, she's a girl! */
+		S_StartSound(pmo, SFX_PLAYER_MAGE_GRUNT);
+	}
+}
+
+
+void A_ACrossAttack(player_t *player, pspdef_t *psp)
+{
+	mobj_t *mo;
+	mobj_t *pmo = player->mo;
+
+	player->mana[MANA_1] -=	WeaponManaUse[player->playerclass][player->readyweapon];
+//	pmo = player->mo;
+//	P_SpawnPlayerMissile(pmo, MT_CSTAFF_MISSILE);
+
+	/*
+	 * jim - special2 is used to control the serpent staff projectiles'
+	 *  `slither' and is not used here
+	 * We do however want to give crossbow missiles BlasterMobjThinker()s
+	 *  instead of the ordinary ones because they are FAST.
+	 */
+	mo = P_SPMAngle(pmo, MT_ACROSS_MISSILE, pmo->angle);
+	if (mo)
+	{
+	/*	mo->special2 = 16; */
+		mo->thinker.function = P_BlasterMobjThinker;
+	}
+	mo = P_SPMAngle(pmo, MT_ACROSS_MISSILE, pmo->angle - (ANG45/10));
+	if (mo)
+	{
+	/*	mo->special2 = 32; */
+		mo->thinker.function = P_BlasterMobjThinker;
+	}
+	mo = P_SPMAngle(pmo, MT_ACROSS_MISSILE, pmo->angle + (ANG45/10));
+	if (mo)
+	{
+	/*	mo->special2 = 0; */
+		mo->thinker.function = P_BlasterMobjThinker;
+	}
+	S_StartSound(player->mo, SFX_CLERIC_CSTAFF_FIRE);
+}
+
+
+void A_AGrenAttack(player_t *player, pspdef_t *psp)
+{
+	mobj_t *mo;
+
+	mo = P_SpawnMobj(player->mo->x, player->mo->y,
+			 player->mo->z - player->mo->floorclip + 35*FRACUNIT,
+			 MT_THROWINGBOMB);
+	if (mo)
+	{
+		mo->angle = player->mo->angle + (((P_Random() & 7) - 4)<<24);
+		mo->momz = 4*FRACUNIT + ((player->lookdir)<<(FRACBITS - 4));
+		mo->z += player->lookdir<<(FRACBITS - 4);
+		P_ThrustMobj(mo, mo->angle, mo->info->speed);
+		mo->momx += player->mo->momx>>1;
+		mo->momy += player->mo->momy>>1;
+		mo->target = player->mo;
+		mo->tics -= P_Random() & 3;
+		P_CheckMissileSpawn(mo);
+	}
+}
+
+void A_AStaffAttack(player_t *player, pspdef_t *psp)
+{
+	angle_t angle;
+	mobj_t *pmo;
+
+/* THIS ISN'T FINISHED YET!! */
+
+	player->mana[MANA_1] -= WeaponManaUse[player->playerclass][player->readyweapon];
+	player->mana[MANA_2] -= WeaponManaUse[player->playerclass][player->readyweapon];
+
+	pmo = player->mo;
+	angle = pmo->angle;
+
+}
+#endif	/* ASSASSIN */
+
--- /dev/null
+++ b/p_setup.c
@@ -1,0 +1,1578 @@
+
+//**************************************************************************
+//**
+//** p_setup.c : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 590 $
+//** $Date: 2012-10-23 23:55:31 +0300 (Tue, 23 Oct 2012) $
+//**
+//**************************************************************************
+
+// HEADER FILES ------------------------------------------------------------
+
+#include "h2stdinc.h"
+#include "h2def.h"
+#include "p_local.h"
+#include "i_cdmus.h"
+#include "soundst.h"
+#ifdef RENDER3D
+#include "ogl_def.h"
+#endif
+
+
+// MACROS ------------------------------------------------------------------
+
+#define MAPINFO_SCRIPT_NAME	"MAPINFO"
+#define MCMD_SKY1		1
+#define MCMD_SKY2		2
+#define MCMD_LIGHTNING		3
+#define MCMD_FADETABLE		4
+#define MCMD_DOUBLESKY		5
+#define MCMD_CLUSTER		6
+#define MCMD_WARPTRANS		7
+#define MCMD_NEXT		8
+#define MCMD_CDTRACK		9
+#define MCMD_CD_STARTTRACK	10
+#define MCMD_CD_END1TRACK	11
+#define MCMD_CD_END2TRACK	12
+#define MCMD_CD_END3TRACK	13
+#define MCMD_CD_INTERTRACK	14
+#define MCMD_CD_TITLETRACK	15
+
+#define UNKNOWN_MAP_NAME	"DEVELOPMENT MAP"
+#define DEFAULT_SKY_NAME	"SKY1"
+#define DEFAULT_SKY_DEMO	"SKY2"
+#define DEFAULT_SONG_LUMP	"DEFSONG"
+#define DEFAULT_FADE_TABLE	"COLORMAP"
+
+// TYPES -------------------------------------------------------------------
+
+typedef struct mapInfo_s mapInfo_t;
+struct mapInfo_s
+{
+	short	cluster;
+	short	warpTrans;
+	short	nextMap;
+	short	cdTrack;
+	char	name[32];
+	short	sky1Texture;
+	short	sky2Texture;
+	fixed_t	sky1ScrollDelta;
+	fixed_t	sky2ScrollDelta;
+	boolean	doubleSky;
+	boolean	lightning;
+	int	fadetable;
+	char	songLump[10];
+};
+
+// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
+
+void P_SpawnMapThing(mapthing_t *mthing);
+
+// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
+
+// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
+
+static int QualifyMap(int map);
+#ifdef RENDER3D
+static float P_AccurateDistance(fixed_t dx, fixed_t dy);
+#endif
+
+
+// EXTERNAL DATA DECLARATIONS ----------------------------------------------
+
+// PUBLIC DATA DEFINITIONS -------------------------------------------------
+
+int		MapCount;
+mapthing_t	deathmatchstarts[MAXDEATHMATCHSTARTS], *deathmatch_p;
+mapthing_t	playerstarts[MAX_PLAYER_STARTS][MAXPLAYERS];
+
+int		numvertexes;
+vertex_t	*vertexes;
+
+int		numsegs;
+seg_t		*segs;
+
+int		numsectors;
+sector_t	*sectors;
+
+int		numsubsectors;
+subsector_t	*subsectors;
+
+int		numnodes;
+node_t		*nodes;
+
+int		numlines;
+line_t		*lines;
+
+int		numsides;
+side_t		*sides;
+
+short		*blockmaplump;		// offsets in blockmap are from here
+short		*blockmap;
+int		bmapwidth, bmapheight;	// in mapblocks
+fixed_t		bmaporgx, bmaporgy;	// origin of block map
+mobj_t		**blocklinks;		// for thing chains
+byte		*rejectmatrix;		// for fast sight rejection
+
+// PRIVATE DATA DEFINITIONS ------------------------------------------------
+
+static mapInfo_t MapInfo[99];
+static const char *MapCmdNames[] =
+{
+	"SKY1",
+	"SKY2",
+	"DOUBLESKY",
+	"LIGHTNING",
+	"FADETABLE",
+	"CLUSTER",
+	"WARPTRANS",
+	"NEXT",
+	"CDTRACK",
+	"CD_START_TRACK",
+	"CD_END1_TRACK",
+	"CD_END2_TRACK",
+	"CD_END3_TRACK",
+	"CD_INTERMISSION_TRACK",
+	"CD_TITLE_TRACK",
+	NULL
+};
+
+static int MapCmdIDs[] =
+{
+	MCMD_SKY1,
+	MCMD_SKY2,
+	MCMD_DOUBLESKY,
+	MCMD_LIGHTNING,
+	MCMD_FADETABLE,
+	MCMD_CLUSTER,
+	MCMD_WARPTRANS,
+	MCMD_NEXT,
+	MCMD_CDTRACK,
+	MCMD_CD_STARTTRACK,
+	MCMD_CD_END1TRACK,
+	MCMD_CD_END2TRACK,
+	MCMD_CD_END3TRACK,
+	MCMD_CD_INTERTRACK,
+	MCMD_CD_TITLETRACK
+};
+
+static int cd_NonLevelTracks[6];	// Non-level specific song cd track numbers
+
+
+// CODE --------------------------------------------------------------------
+
+
+/*
+=================
+=
+= P_LoadVertexes
+=
+=================
+*/
+
+static void P_LoadVertexes (int lump)
+{
+	void		*data;
+	int		i;
+	mapvertex_t	*ml;
+	vertex_t	*li;
+
+	numvertexes = W_LumpLength (lump) / sizeof(mapvertex_t);
+	vertexes = (vertex_t *) Z_Malloc (numvertexes*sizeof(vertex_t), PU_LEVEL, NULL);
+	data = W_CacheLumpNum (lump, PU_STATIC);
+
+	ml = (mapvertex_t *)data;
+	li = vertexes;
+	for (i = 0; i < numvertexes; i++, li++, ml++)
+	{
+		li->x = SHORT(ml->x)<<FRACBITS;
+		li->y = SHORT(ml->y)<<FRACBITS;
+	}
+
+	Z_Free (data);
+}
+
+
+/*
+=================
+=
+= P_LoadSegs
+=
+=================
+*/
+
+static void P_LoadSegs (int lump)
+{
+	void		*data;
+	int		i;
+	mapseg_t	*ml;
+	seg_t		*li;
+	line_t		*ldef;
+	int		_linedef, side;
+
+	numsegs = W_LumpLength (lump) / sizeof(mapseg_t);
+	segs = (seg_t *) Z_Malloc (numsegs*sizeof(seg_t), PU_LEVEL, NULL);
+	memset (segs, 0, numsegs*sizeof(seg_t));
+	data = W_CacheLumpNum (lump, PU_STATIC);
+
+	ml = (mapseg_t *)data;
+	li = segs;
+	for (i = 0; i < numsegs; i++, li++, ml++)
+	{
+		li->v1 = &vertexes[SHORT(ml->v1)];
+		li->v2 = &vertexes[SHORT(ml->v2)];
+
+		li->angle = (SHORT(ml->angle))<<16;
+		li->offset = (SHORT(ml->offset))<<16;
+		_linedef = SHORT(ml->linedef);
+		ldef = &lines[_linedef];
+		li->linedef = ldef;
+		side = SHORT(ml->side);
+		li->sidedef = &sides[ldef->sidenum[side]];
+		li->frontsector = sides[ldef->sidenum[side]].sector;
+		if (ldef-> flags & ML_TWOSIDED)
+			li->backsector = sides[ldef->sidenum[side^1]].sector;
+		else
+			li->backsector = 0;
+
+#ifdef RENDER3D
+	// Calculate the length of the segment. We need this for
+	// the texture coordinates. -jk
+		li->len = P_AccurateDistance(li->v2->x - li->v1->x, li->v2->y - li->v1->y);
+#endif
+	}
+
+	Z_Free (data);
+}
+
+
+/*
+=================
+=
+= P_LoadSubsectors
+=
+=================
+*/
+
+static void P_LoadSubsectors (int lump)
+{
+	void			*data;
+	int			i;
+	mapsubsector_t		*ms;
+	subsector_t		*ss;
+
+	numsubsectors = W_LumpLength (lump) / sizeof(mapsubsector_t);
+	subsectors = (subsector_t *) Z_Malloc (numsubsectors*sizeof(subsector_t), PU_LEVEL, NULL);
+	data = W_CacheLumpNum (lump, PU_STATIC);
+
+	ms = (mapsubsector_t *)data;
+	memset (subsectors, 0, numsubsectors*sizeof(subsector_t));
+	ss = subsectors;
+	for (i = 0; i < numsubsectors; i++, ss++, ms++)
+	{
+		ss->numlines = SHORT(ms->numsegs);
+		ss->firstline = SHORT(ms->firstseg);
+	}
+
+	Z_Free (data);
+}
+
+
+/*
+=================
+=
+= P_LoadSectors
+=
+=================
+*/
+
+static void P_LoadSectors (int lump)
+{
+	void			*data;
+	int			i;
+	mapsector_t		*ms;
+	sector_t		*ss;
+
+	numsectors = W_LumpLength (lump) / sizeof(mapsector_t);
+	sectors = (sector_t *) Z_Malloc (numsectors*sizeof(sector_t), PU_LEVEL, NULL);
+	memset (sectors, 0, numsectors*sizeof(sector_t));
+	data = W_CacheLumpNum (lump, PU_STATIC);
+
+	ms = (mapsector_t *)data;
+	ss = sectors;
+
+	// Make sure primary lumps are used for flat searching
+	W_UsePrimary();
+
+	for (i = 0; i < numsectors; i++, ss++, ms++)
+	{
+		ss->floorheight = SHORT(ms->floorheight)<<FRACBITS;
+		ss->ceilingheight = SHORT(ms->ceilingheight)<<FRACBITS;
+		ss->floorpic = R_FlatNumForName(ms->floorpic);
+		ss->ceilingpic = R_FlatNumForName(ms->ceilingpic);
+		ss->lightlevel = SHORT(ms->lightlevel);
+		ss->special = SHORT(ms->special);
+		ss->tag = SHORT(ms->tag);
+		ss->thinglist = NULL;
+		ss->seqType = SEQTYPE_STONE;	// default seqType
+
+#ifdef RENDER3D
+		ss->flatoffx = ss->flatoffy = 0;// Flat scrolling.
+		ss->skyfix = 0;			// Set if needed.
+#endif
+	}
+	if (DevMaps)
+	{
+		W_UseAuxiliary();
+	}
+	Z_Free(data);
+}
+
+
+/*
+=================
+=
+= P_LoadNodes
+=
+=================
+*/
+
+static void P_LoadNodes (int lump)
+{
+	void		*data;
+	int		i, j, k;
+	mapnode_t	*mn;
+	node_t		*no;
+
+	numnodes = W_LumpLength (lump) / sizeof(mapnode_t);
+	nodes = (node_t *) Z_Malloc (numnodes*sizeof(node_t), PU_LEVEL, NULL);
+	data = W_CacheLumpNum (lump, PU_STATIC);
+
+	mn = (mapnode_t *)data;
+	no = nodes;
+	for (i = 0; i < numnodes; i++, no++, mn++)
+	{
+		no->x = SHORT(mn->x)<<FRACBITS;
+		no->y = SHORT(mn->y)<<FRACBITS;
+		no->dx = SHORT(mn->dx)<<FRACBITS;
+		no->dy = SHORT(mn->dy)<<FRACBITS;
+		for (j = 0; j < 2; j++)
+		{
+			no->children[j] = SHORT(mn->children[j]);
+			for (k = 0; k < 4; k++)
+				no->bbox[j][k] = SHORT(mn->bbox[j][k])<<FRACBITS;
+		}
+	}
+	Z_Free (data);
+}
+
+//==========================================================================
+//
+// P_LoadThings
+//
+//==========================================================================
+
+static void P_LoadThings(int lump)
+{
+	void		*data;
+	int		i;
+	mapthing_t	*mt;
+	int		numthings;
+	int		playerCount;
+	int		deathSpotsCount;
+
+	data = W_CacheLumpNum(lump, PU_STATIC);
+	numthings = W_LumpLength(lump) / sizeof(mapthing_t);
+
+	mt = (mapthing_t *)data;
+	for (i = 0; i < numthings; i++, mt++)
+	{
+		mt->tid = SHORT(mt->tid);
+		mt->x = SHORT(mt->x);
+		mt->y = SHORT(mt->y);
+		mt->height = SHORT(mt->height);
+		mt->angle = SHORT(mt->angle);
+		mt->type = SHORT(mt->type);
+		mt->options = SHORT(mt->options);
+		P_SpawnMapThing(mt);
+	}
+	P_CreateTIDList();
+	P_InitCreatureCorpseQueue(false);	// false = do NOT scan for corpses
+	Z_Free(data);
+
+	if (!deathmatch)
+	{
+		return;				// Don't need to check deathmatch spots
+	}
+	playerCount = 0;
+	for (i = 0; i < MAXPLAYERS; i++)
+	{
+		playerCount += playeringame[i];
+	}
+	deathSpotsCount = deathmatch_p - deathmatchstarts;
+	if (deathSpotsCount < playerCount)
+	{
+		I_Error("P_LoadThings: Player count (%d) exceeds deathmatch "
+			"spots (%d)", playerCount, deathSpotsCount);
+	}
+}
+
+/*
+=================
+=
+= P_LoadLineDefs
+=
+=================
+*/
+
+static void P_LoadLineDefs(int lump)
+{
+	void		*data;
+	int		i;
+	maplinedef_t	*mld;
+	line_t		*ld;
+	vertex_t	*v1, *v2;
+
+	numlines = W_LumpLength(lump) / sizeof(maplinedef_t);
+	lines = (line_t *) Z_Malloc(numlines*sizeof(line_t), PU_LEVEL, NULL);
+	memset(lines, 0, numlines*sizeof(line_t));
+	data = W_CacheLumpNum(lump, PU_STATIC);
+
+	mld = (maplinedef_t *)data;
+	ld = lines;
+	for (i = 0; i < numlines; i++, mld++, ld++)
+	{
+		ld->flags = SHORT(mld->flags);
+
+		// Old line special info ...
+		//ld->special = SHORT(mld->special);
+		//ld->tag = SHORT(mld->tag);
+
+		// New line special info ...
+		ld->special = mld->special;
+		ld->arg1 = mld->arg1;
+		ld->arg2 = mld->arg2;
+		ld->arg3 = mld->arg3;
+		ld->arg4 = mld->arg4;
+		ld->arg5 = mld->arg5;
+
+		v1 = ld->v1 = &vertexes[SHORT(mld->v1)];
+		v2 = ld->v2 = &vertexes[SHORT(mld->v2)];
+		ld->dx = v2->x - v1->x;
+		ld->dy = v2->y - v1->y;
+		if (!ld->dx)
+			ld->slopetype = ST_VERTICAL;
+		else if (!ld->dy)
+			ld->slopetype = ST_HORIZONTAL;
+		else
+		{
+			if (FixedDiv (ld->dy , ld->dx) > 0)
+				ld->slopetype = ST_POSITIVE;
+			else
+				ld->slopetype = ST_NEGATIVE;
+		}
+
+		if (v1->x < v2->x)
+		{
+			ld->bbox[BOXLEFT] = v1->x;
+			ld->bbox[BOXRIGHT] = v2->x;
+		}
+		else
+		{
+			ld->bbox[BOXLEFT] = v2->x;
+			ld->bbox[BOXRIGHT] = v1->x;
+		}
+		if (v1->y < v2->y)
+		{
+			ld->bbox[BOXBOTTOM] = v1->y;
+			ld->bbox[BOXTOP] = v2->y;
+		}
+		else
+		{
+			ld->bbox[BOXBOTTOM] = v2->y;
+			ld->bbox[BOXTOP] = v1->y;
+		}
+		ld->sidenum[0] = SHORT(mld->sidenum[0]);
+		ld->sidenum[1] = SHORT(mld->sidenum[1]);
+		if (ld->sidenum[0] != -1)
+			ld->frontsector = sides[ld->sidenum[0]].sector;
+		else
+			ld->frontsector = 0;
+		if (ld->sidenum[1] != -1)
+			ld->backsector = sides[ld->sidenum[1]].sector;
+		else
+			ld->backsector = 0;
+	}
+
+	Z_Free (data);
+}
+
+
+/*
+=================
+=
+= P_LoadSideDefs
+=
+=================
+*/
+
+static void P_LoadSideDefs (int lump)
+{
+	void		*data;
+	int		i;
+	mapsidedef_t	*msd;
+	side_t		*sd;
+
+	numsides = W_LumpLength (lump) / sizeof(mapsidedef_t);
+	sides = (side_t *) Z_Malloc (numsides*sizeof(side_t), PU_LEVEL, NULL);
+	memset (sides, 0, numsides*sizeof(side_t));
+	data = W_CacheLumpNum (lump, PU_STATIC);
+
+	msd = (mapsidedef_t *)data;
+	sd = sides;
+
+	// Make sure primary lumps are used for texture searching
+	W_UsePrimary();
+
+	for (i = 0; i < numsides; i++, msd++, sd++)
+	{
+		sd->textureoffset = SHORT(msd->textureoffset)<<FRACBITS;
+		sd->rowoffset = SHORT(msd->rowoffset)<<FRACBITS;
+		sd->toptexture = R_TextureNumForName(msd->toptexture);
+		sd->bottomtexture = R_TextureNumForName(msd->bottomtexture);
+		sd->midtexture = R_TextureNumForName(msd->midtexture);
+		sd->sector = &sectors[SHORT(msd->sector)];
+	}
+	if (DevMaps)
+	{
+		W_UseAuxiliary();
+	}
+	Z_Free(data);
+}
+
+/*
+=================
+=
+= P_LoadBlockMap
+=
+=================
+*/
+
+static void P_LoadBlockMap (int lump)
+{
+	int		i, count;
+
+	blockmaplump = (short *) W_CacheLumpNum (lump, PU_LEVEL);
+	blockmap = blockmaplump + 4;
+	count = W_LumpLength (lump) / 2;
+	for (i = 0; i < count; i++)
+		blockmaplump[i] = SHORT(blockmaplump[i]);
+
+	bmaporgx = blockmaplump[0]<<FRACBITS;
+	bmaporgy = blockmaplump[1]<<FRACBITS;
+	bmapwidth = blockmaplump[2];
+	bmapheight = blockmaplump[3];
+
+// clear out mobj chains
+	count = sizeof(*blocklinks) * bmapwidth * bmapheight;
+	blocklinks = (mobj_t **) Z_Malloc (count, PU_LEVEL, NULL);
+	memset (blocklinks, 0, count);
+}
+
+
+/*
+=================
+=
+= P_GroupLines
+=
+= Builds sector line lists and subsector sector numbers
+= Finds block bounding boxes for sectors
+=================
+*/
+
+static void P_GroupLines (void)
+{
+	line_t		**linebuffer;
+	int		i, j, total;
+	line_t		*li;
+	sector_t	*sector;
+	subsector_t	*ss;
+	seg_t		*seg;
+	fixed_t		bbox[4];
+	int		block;
+
+// look up sector number for each subsector
+	ss = subsectors;
+	for (i = 0; i < numsubsectors; i++, ss++)
+	{
+		seg = &segs[ss->firstline];
+		ss->sector = seg->sidedef->sector;
+	}
+
+// count number of lines in each sector
+	li = lines;
+	total = 0;
+	for (i = 0; i < numlines; i++, li++)
+	{
+		total++;
+		li->frontsector->linecount++;
+		if (li->backsector && li->backsector != li->frontsector)
+		{
+			li->backsector->linecount++;
+			total++;
+		}
+	}
+
+// build line tables for each sector
+	linebuffer = (line_t **) Z_Malloc (total * sizeof(line_t *), PU_LEVEL, NULL);
+	sector = sectors;
+	for (i = 0; i < numsectors; i++, sector++)
+	{
+		M_ClearBox (bbox);
+		sector->lines = linebuffer;
+		li = lines;
+		for (j = 0; j < numlines; j++, li++)
+		{
+			if (li->frontsector == sector || li->backsector == sector)
+			{
+				*linebuffer++ = li;
+				M_AddToBox (bbox, li->v1->x, li->v1->y);
+				M_AddToBox (bbox, li->v2->x, li->v2->y);
+			}
+		}
+		if (linebuffer - sector->lines != sector->linecount)
+			I_Error ("P_GroupLines: miscounted");
+
+		// set the degenmobj_t to the middle of the bounding box
+		sector->soundorg.x = (bbox[BOXRIGHT] + bbox[BOXLEFT]) / 2;
+		sector->soundorg.y = (bbox[BOXTOP] + bbox[BOXBOTTOM]) / 2;
+
+		// adjust bounding box to map blocks
+		block = (bbox[BOXTOP] - bmaporgy + MAXRADIUS) >> MAPBLOCKSHIFT;
+		block = block >= bmapheight ? bmapheight - 1 : block;
+		sector->blockbox[BOXTOP] = block;
+
+		block = (bbox[BOXBOTTOM] - bmaporgy - MAXRADIUS) >> MAPBLOCKSHIFT;
+		block = block < 0 ? 0 : block;
+		sector->blockbox[BOXBOTTOM] = block;
+
+		block = (bbox[BOXRIGHT] - bmaporgx + MAXRADIUS) >> MAPBLOCKSHIFT;
+		block = block >= bmapwidth ? bmapwidth - 1 : block;
+		sector->blockbox[BOXRIGHT] = block;
+
+		block = (bbox[BOXLEFT] - bmaporgx - MAXRADIUS) >> MAPBLOCKSHIFT;
+		block = block < 0 ? 0 : block;
+		sector->blockbox[BOXLEFT] = block;
+	}
+}
+
+
+#if defined(RENDER3D)
+
+#define MAX_CC_SIDES	64
+
+static float P_AccurateDistance(fixed_t dx, fixed_t dy)
+{
+	float fx = FIX2FLT(dx), fy = FIX2FLT(dy);
+	return (float)sqrt(fx*fx + fy*fy);
+}
+
+static int __no_optimize detSideFloat(fvertex_t *pnt, fdivline_t *dline)
+{
+	/*
+	    (AY-CY)(BX-AX)-(AX-CX)(BY-AY)
+	s = -----------------------------
+			L**2
+
+	If s < 0  C is left of AB (you can just check the numerator)
+	If s > 0  C is right of AB
+	If s = 0  C is on AB
+
+	We'll return false if the point c is on the left side.
+	*/
+	float s = (dline->y - pnt->y) * dline->dx - (dline->x - pnt->x) * dline->dy;
+	if (s < 0)
+		return 0;
+	return 1;
+}
+
+// Lines start-end and fdiv must intersect.
+static float __no_optimize findIntersectionVertex(fvertex_t *start, fvertex_t *end,
+						  fdivline_t *fdiv, fvertex_t *inter)
+{
+	float ax = start->x, ay = start->y, bx = end->x, by = end->y;
+	float cx = fdiv->x, cy = fdiv->y, dx = cx + fdiv->dx, dy = cy + fdiv->dy;
+	/*
+	    (YA-YC)(XD-XC)-(XA-XC)(YD-YC)
+	r = -----------------------------  (eqn 1)
+	    (XB-XA)(YD-YC)-(YB-YA)(XD-XC)
+	*/
+	float r = ((ay - cy) * (dx-cx) - (ax-cx) * (dy-cy)) /
+		((bx - ax) * (dy - cy) - (by - ay) * (dx-cx));
+	/*
+	XI=XA+r(XB-XA)
+	YI=YA+r(YB-YA)
+	*/
+	inter->x = ax + r * (bx - ax);
+	inter->y = ay + r * (by - ay);
+	return r;
+}
+
+static void P_ConvexCarver(subsector_t *ssec, int num, divline_t *list)
+{
+	int		numclippers = num + ssec->numlines;
+	fdivline_t	*clippers = (fdivline_t *) malloc(numclippers*sizeof(fdivline_t));
+	int		i, k, numedgepoints;
+	fvertex_t	*edgepoints;
+	unsigned char	sidelist[MAX_CC_SIDES];
+
+// Convert the divlines to float, in reverse order.
+	OGL_DEBUG("%d clippers (%d pls, %d segs):\n", numclippers, num, ssec->numlines);
+	for (i = 0; i < numclippers; i++)
+	{
+		if (i < num)
+		{
+			clippers[i].x = FIX2FLT(list[num - i - 1].x);
+			clippers[i].y = FIX2FLT(list[num - i - 1].y);
+			clippers[i].dx = FIX2FLT(list[num - i - 1].dx);
+			clippers[i].dy = FIX2FLT(list[num - i - 1].dy);
+		}
+		else
+		{
+			seg_t *seg = segs + (ssec->firstline + i - num);
+			clippers[i].x = FIX2FLT(seg->v1->x);
+			clippers[i].y = FIX2FLT(seg->v1->y);
+			clippers[i].dx = FIX2FLT(seg->v2->x - seg->v1->x);
+			clippers[i].dy = FIX2FLT(seg->v2->y - seg->v1->y);
+		}
+		OGL_DEBUG("  %d: x=%f y=%f dx=%f dy=%f\n",
+			  i, clippers[i].x, clippers[i].y, clippers[i].dx, clippers[i].dy);
+	}
+	OGL_DEBUG("\n");
+
+// Setup the 'worldwide' polygon.
+	numedgepoints = 4;
+	edgepoints = (fvertex_t *) malloc(numedgepoints*sizeof(fvertex_t));
+
+	edgepoints[0].x = -32768;
+	edgepoints[0].y = 32768;
+
+	edgepoints[1].x = 32768;
+	edgepoints[1].y = 32768;
+
+	edgepoints[2].x = 32768;
+	edgepoints[2].y = -32768;
+
+	edgepoints[3].x = -32768;
+	edgepoints[3].y = -32768;
+
+// We'll now clip the polygon with each of the divlines. The left side of
+// each divline is discarded.
+
+	OGL_DEBUG("carving (with %d clippers):\n", numclippers);
+	for (i = 0; i < numclippers; i++)
+	{
+		fdivline_t *curclip = clippers + i;
+
+		// First we'll determine the side of each vertex.
+		// Points are allowed to be on the line.
+		for (k = 0; k < numedgepoints; k++)
+		{
+			sidelist[k] = detSideFloat(edgepoints + k, curclip);
+			OGL_DEBUG( "%d: %d, ", k, sidelist[k]);
+		}
+		OGL_DEBUG("\n");
+
+		for (k = 0; k < numedgepoints; k++)
+		{
+			int startIdx = k, endIdx = k + 1;
+
+			// Check the end index.
+			if (endIdx == numedgepoints)
+				endIdx = 0;	// Wrap-around.
+
+			// Clipping will happen when the ends are on different sides.
+			if (sidelist[startIdx] != sidelist[endIdx])
+			{
+				fvertex_t newvert;
+				OGL_DEBUG("  clipping %d - %d\n", startIdx, endIdx);
+			// Find the intersection point of intersecting lines.
+				findIntersectionVertex(edgepoints + startIdx, edgepoints + endIdx, curclip, &newvert);
+
+			// Add the new vertex. Also modify the sidelist.
+				edgepoints = (fvertex_t *) realloc(edgepoints, (++numedgepoints)*sizeof(fvertex_t));
+				if (numedgepoints >= MAX_CC_SIDES)
+					I_Error("Too many points in carver.\n");
+
+			// Make room for the new vertex.
+				memmove(edgepoints + endIdx + 1, edgepoints + endIdx,
+					(numedgepoints - endIdx - 1)*sizeof(fvertex_t));
+				memcpy (edgepoints + endIdx, &newvert, sizeof(newvert));
+
+				memmove(sidelist + endIdx + 1, sidelist + endIdx, numedgepoints - endIdx - 1);
+				sidelist[endIdx] = 1;
+
+			// Skip over the new vertex.
+				k++;
+			}
+		}
+
+	// Now we must discard the points that are on the wrong side.
+		for (k = 0; k < numedgepoints; k++)
+		{
+			if (!sidelist[k])
+			{
+				memmove(edgepoints + k, edgepoints + k + 1, (numedgepoints-k-1)*sizeof(fvertex_t));
+				memmove(sidelist + k, sidelist + k + 1, numedgepoints - k - 1);
+				numedgepoints--;
+				k--;
+			}
+		} 
+	}
+
+	if (!numedgepoints)
+	{
+	//	I_Error("All carved away!\n");
+		printf( "All carved away: subsector %p\n", ssec);
+		ssec->numedgeverts = 0;
+		ssec->edgeverts = 0;
+		ssec->origedgeverts = 0;
+	}
+	else
+	{
+		// Screen out consecutive identical points.
+		for (i = 0; i < numedgepoints; i++)
+		{
+			int previdx = i - 1;
+			if (previdx < 0)
+				previdx = numedgepoints - 1;
+			if (edgepoints[i].x == edgepoints[previdx].x &&
+			    edgepoints[i].y == edgepoints[previdx].y)
+			{
+			// This point (i) must be removed.
+				memmove(edgepoints + i, edgepoints + i + 1,
+					sizeof(fvertex_t)*(numedgepoints - i - 1));
+				numedgepoints--;
+				i--;
+			}
+		}
+		// We need these with dynamic lights.
+		ssec->origedgeverts = (fvertex_t *) Z_Malloc(sizeof(fvertex_t)*numedgepoints, PU_LEVEL, NULL);
+		memcpy(ssec->origedgeverts, edgepoints, sizeof(fvertex_t)*numedgepoints);
+
+		// Find the center point. Do this by first finding the bounding box.
+		ssec->bbox[0].x = ssec->bbox[1].x = edgepoints[0].x;
+		ssec->bbox[0].y = ssec->bbox[1].y = edgepoints[0].y;
+		for (i = 1; i < numedgepoints; i++)
+		{
+			OGL_DEBUG("  %i: (%f, %f)\n", i, edgepoints[i].x, edgepoints[i].y);
+			if (edgepoints[i].x < ssec->bbox[0].x)
+				ssec->bbox[0].x = edgepoints[i].x;
+			if (edgepoints[i].y < ssec->bbox[0].y)
+				ssec->bbox[0].y = edgepoints[i].y;
+			if (edgepoints[i].x > ssec->bbox[1].x)
+				ssec->bbox[1].x = edgepoints[i].x;
+			if (edgepoints[i].y > ssec->bbox[1].y)
+				ssec->bbox[1].y = edgepoints[i].y;
+		}
+		ssec->midpoint.x = (ssec->bbox[1].x + ssec->bbox[0].x) / 2;
+		ssec->midpoint.y = (ssec->bbox[1].y + ssec->bbox[0].y) / 2;
+
+		// Make slight adjustments to patch up those ugly, small gaps.
+		for (i = 0; i < numedgepoints; i++)
+		{
+			float dx = edgepoints[i].x - ssec->midpoint.x,
+			      dy = edgepoints[i].y - ssec->midpoint.y;
+			float dlen = (float) sqrt(dx*dx + dy*dy) * 3;
+			if (dlen)
+			{
+				edgepoints[i].x += dx / dlen;
+				edgepoints[i].y += dy / dlen;
+			}
+		}
+
+		ssec->numedgeverts = numedgepoints;
+		ssec->edgeverts = (fvertex_t *) Z_Malloc(sizeof(fvertex_t)*numedgepoints, PU_LEVEL, NULL);
+		memcpy(ssec->edgeverts, edgepoints, sizeof(fvertex_t)*numedgepoints);
+	}
+
+	// We're done, free the edgepoints memory.
+	free(clippers);
+	free(edgepoints);
+}
+
+static void P_CreateFloorsAndCeilings(int bspnode, int numdivlines, divline_t* divlines)
+{
+	node_t		*nod;
+	divline_t	*childlist, *dl;
+	int		childlistsize = numdivlines + 1;
+
+	// If this is a subsector we are dealing with, begin carving with the
+	// given list.
+	if (bspnode & NF_SUBSECTOR)
+	{
+	// We have arrived at a subsector. The divline list contains all
+	// the partition lines that carve out the subsector.
+		int ssidx = bspnode & (~NF_SUBSECTOR);
+		OGL_DEBUG("subsector %d: %d divlines\n", ssidx, numdivlines);
+	//	if (ssidx < 10)
+		P_ConvexCarver(subsectors+ssidx, numdivlines, divlines);
+
+		OGL_DEBUG("subsector %d: %d edgeverts\n", ssidx, subsectors[ssidx].numedgeverts);
+		return;	// This leaf is done.
+	}
+
+	// Get a pointer to the node.
+	nod = nodes + bspnode;
+
+	// Allocate a new list for each child.
+	childlist = (divline_t *) malloc(childlistsize*sizeof(divline_t));
+
+	// Copy the previous lines.
+	if (divlines)
+		memcpy(childlist, divlines, numdivlines*sizeof(divline_t));
+
+	dl = childlist + numdivlines;
+	dl->x = nod->x;
+	dl->y = nod->y;
+	// The right child gets the original line (LEFT side clipped).
+	dl->dx = nod->dx;
+	dl->dy = nod->dy;
+	P_CreateFloorsAndCeilings(nod->children[0], childlistsize, childlist);
+
+	// The left side. We must reverse the line, otherwise the wrong
+	// side would get clipped.
+	dl->dx = -nod->dx;
+	dl->dy = -nod->dy;
+	P_CreateFloorsAndCeilings(nod->children[1], childlistsize, childlist);
+
+	// We are finishing with this node, free the allocated list.
+	free(childlist);
+}
+
+static void P_SkyFix(void)
+{
+	int		i;
+
+	// We need to check all the linedefs.
+	for (i = 0; i < numlines; i++)
+	{
+		line_t *line = lines + i;
+		sector_t *front = line->frontsector, *back = line->backsector;
+		int fix = 0;
+		// The conditions!
+		if (!front || !back)
+			continue;
+		// Both the front and back sectors must have the sky ceiling.
+		if (front->ceilingpic != skyflatnum || back->ceilingpic != skyflatnum)
+			continue;
+		// Operate on the lower sector.
+		OGL_DEBUG("Line %d (f:%d, b:%d).\n", i, front->ceilingheight >> FRACBITS,
+							 back->ceilingheight >> FRACBITS);
+		if (front->ceilingheight < back->ceilingheight)
+		{
+			fix = (back->ceilingheight - front->ceilingheight) >> FRACBITS;
+			if (fix > front->skyfix)
+				front->skyfix = fix;
+		}
+		else if (front->ceilingheight > back->ceilingheight)
+		{
+			fix = (front->ceilingheight - back->ceilingheight) >> FRACBITS;
+			if (fix > back->skyfix)
+				back->skyfix = fix;
+		}
+	}
+}
+#endif	/* RENDER3D */
+
+//=============================================================================
+
+/*
+=================
+=
+= P_SetupLevel
+=
+=================
+*/
+
+void P_SetupLevel(int episode, int map, int playermask, skill_t skill)
+{
+	int		i;
+	int		parm;
+	char		lumpname[9];
+	char		auxName[128];
+	int		lumpnum;
+	mobj_t		*mobj;
+
+	for (i = 0; i < MAXPLAYERS; i++)
+	{
+		players[i].killcount = players[i].secretcount = players[i].itemcount = 0;
+	}
+	players[consoleplayer].viewz = 1;	// will be set by player think
+
+	if (!i_CDMusic || !cdaudio)
+	{
+		S_StartSongName("chess", true);	// Waiting-for-level-load song
+	}
+
+	Z_FreeTags(PU_LEVEL, PU_PURGELEVEL - 1);
+
+#ifdef RENDER3D
+	OGL_ResetData();
+#endif
+
+	P_InitThinkers();
+	leveltime = 0;
+
+	if (DevMaps)
+	{
+		snprintf(auxName, sizeof(auxName), "%smap%02d.wad", DevMapsDir, map);
+		W_OpenAuxiliary(auxName);
+	}
+	snprintf(lumpname, sizeof(lumpname), "MAP%02d", map);
+	lumpnum = W_GetNumForName(lumpname);
+	//
+	// Begin processing map lumps
+	// Note: most of this ordering is important
+	//
+	P_LoadBlockMap(lumpnum + ML_BLOCKMAP);
+	P_LoadVertexes(lumpnum + ML_VERTEXES);
+	P_LoadSectors(lumpnum + ML_SECTORS);
+	P_LoadSideDefs(lumpnum + ML_SIDEDEFS);
+	P_LoadLineDefs(lumpnum + ML_LINEDEFS);
+	P_LoadSubsectors(lumpnum + ML_SSECTORS);
+	P_LoadNodes(lumpnum + ML_NODES);
+	P_LoadSegs(lumpnum + ML_SEGS);
+
+#ifdef RENDER3D
+	// We need to carve out the floor/ceiling polygons of each subsector.
+	// Walk the tree to do this.
+	//OGL_DEBUG("Floor/ceiling creation: begin at %d, ", ticcount);
+	P_CreateFloorsAndCeilings(numnodes - 1, 0, 0);
+	// Also check if the sky needs a fix.
+	P_SkyFix();
+#endif
+
+	rejectmatrix = (byte *) W_CacheLumpNum(lumpnum + ML_REJECT, PU_LEVEL);
+	P_GroupLines();
+	bodyqueslot = 0;
+	po_NumPolyobjs = 0;
+	deathmatch_p = deathmatchstarts;
+	P_LoadThings(lumpnum + ML_THINGS);
+	PO_Init(lumpnum + ML_THINGS);	// Initialize the polyobjs
+	P_LoadACScripts(lumpnum + ML_BEHAVIOR); // ACS object code
+	//
+	// End of map lump processing
+	//
+	if (DevMaps)
+	{
+		// Close the auxiliary file, but don't free its loaded lumps.
+		// The next call to W_OpenAuxiliary() will do a full shutdown
+		// of the current auxiliary WAD (free lumps and info lists).
+		W_CloseAuxiliaryFile();
+		W_UsePrimary();
+	}
+
+	// If deathmatch, randomly spawn the active players
+	TimerGame = 0;
+	if (deathmatch)
+	{
+		for (i = 0; i < MAXPLAYERS; i++)
+		{
+			if (playeringame[i])
+			{   // must give a player spot before deathmatchspawn
+				mobj = P_SpawnMobj (playerstarts[0][i].x<<16,
+						    playerstarts[0][i].y<<16,
+						    0, MT_PLAYER_FIGHTER);
+				players[i].mo = mobj;
+				G_DeathMatchSpawnPlayer (i);
+				P_RemoveMobj (mobj);
+			}
+		}
+		parm = M_CheckParm("-timer");
+		if (parm && parm < myargc - 1)
+		{
+			TimerGame = atoi(myargv[parm + 1]) * 35 * 60;
+		}
+	}
+
+// set up world state
+	P_SpawnSpecials ();
+
+// build subsector connect matrix
+//	P_ConnectSubsectors ();
+
+// Load colormap and set the fullbright flag
+	i = P_GetMapFadeTable(gamemap);
+	W_ReadLump(i, colormaps);
+	if (i == W_GetNumForName("COLORMAP"))
+	{
+		LevelUseFullBright = true;
+#ifdef RENDER3D
+		OGL_UseWhiteFog(false);
+#endif
+	}
+	else
+	{ // Probably fog ... don't use fullbright sprites
+		LevelUseFullBright = false;
+#ifdef RENDER3D
+		if (i == W_GetNumForName("FOGMAP"))
+		{
+		// Tell the renderer to turn on the fog.
+			OGL_UseWhiteFog(true);
+		}
+#endif
+	}
+
+// preload graphics
+	if (precache)
+		R_PrecacheLevel ();
+
+	// Check if the level is a lightning level
+	P_InitLightning();
+
+	S_StopAllSound();
+	SN_StopAllSequences();
+	S_StartSong(gamemap, true);
+
+//	printf ("free memory: 0x%x\n", Z_FreeMemory());
+}
+
+//==========================================================================
+//
+// InitMapInfo
+//
+//==========================================================================
+
+static void InitMapInfo(void)
+{
+	int		map;
+	int		mapMax;
+	int		mcmdValue;
+	mapInfo_t	*info;
+	char	songMulch[10];
+
+	mapMax = 1;
+
+	// Put defaults into MapInfo[0]
+	info = MapInfo;
+	info->cluster = 0;
+	info->warpTrans = 0;
+	info->nextMap = 1;	// Always go to map 1 if not specified
+	info->cdTrack = 1;
+	info->sky1Texture = R_TextureNumForName((shareware && oldwad_10) ? DEFAULT_SKY_DEMO : DEFAULT_SKY_NAME);
+	info->sky2Texture = info->sky1Texture;
+	info->sky1ScrollDelta = 0;
+	info->sky2ScrollDelta = 0;
+	info->doubleSky = false;
+	info->lightning = false;
+	info->fadetable = W_GetNumForName(DEFAULT_FADE_TABLE);
+	strcpy(info->name, UNKNOWN_MAP_NAME);
+
+//	strcpy(info->songLump, DEFAULT_SONG_LUMP);
+	SC_Open(MAPINFO_SCRIPT_NAME);
+	while (SC_GetString())
+	{
+		if (SC_Compare("MAP") == false)
+		{
+			SC_ScriptError(NULL);
+		}
+		SC_MustGetNumber();
+		if (sc_Number < 1 || sc_Number > 99)
+		{
+			SC_ScriptError(NULL);
+		}
+		map = sc_Number;
+
+		info = &MapInfo[map];
+
+		// Save song lump name
+		strcpy(songMulch, info->songLump);
+
+		// Copy defaults to current map definition
+		memcpy(info, &MapInfo[0], sizeof(*info));
+
+		// Restore song lump name
+		strcpy(info->songLump, songMulch);
+
+		// The warp translation defaults to the map number
+		info->warpTrans = map;
+
+		// Map name must follow the number
+		SC_MustGetString();
+		strcpy(info->name, sc_String);
+
+		// Process optional tokens
+		while (SC_GetString())
+		{
+			if (SC_Compare("MAP"))
+			{ // Start next map definition
+				SC_UnGet();
+				break;
+			}
+			mcmdValue = MapCmdIDs[SC_MustMatchString(MapCmdNames)];
+			switch (mcmdValue)
+			{
+			case MCMD_CLUSTER:
+				SC_MustGetNumber();
+				info->cluster = sc_Number;
+				break;
+			case MCMD_WARPTRANS:
+				SC_MustGetNumber();
+				info->warpTrans = sc_Number;
+				break;
+			case MCMD_NEXT:
+				SC_MustGetNumber();
+				info->nextMap = sc_Number;
+				break;
+			case MCMD_CDTRACK:
+				SC_MustGetNumber();
+				info->cdTrack = sc_Number;
+				break;
+			case MCMD_SKY1:
+				SC_MustGetString();
+				info->sky1Texture = R_TextureNumForName(sc_String);
+				SC_MustGetNumber();
+				info->sky1ScrollDelta = sc_Number<<8;
+				break;
+			case MCMD_SKY2:
+				SC_MustGetString();
+				info->sky2Texture = R_TextureNumForName(sc_String);
+				SC_MustGetNumber();
+				info->sky2ScrollDelta = sc_Number<<8;
+				break;
+			case MCMD_DOUBLESKY:
+				info->doubleSky = true;
+				break;
+			case MCMD_LIGHTNING:
+				info->lightning = true;
+				break;
+			case MCMD_FADETABLE:
+				SC_MustGetString();
+				info->fadetable = W_GetNumForName(sc_String);
+				break;
+			case MCMD_CD_STARTTRACK:
+			case MCMD_CD_END1TRACK:
+			case MCMD_CD_END2TRACK:
+			case MCMD_CD_END3TRACK:
+			case MCMD_CD_INTERTRACK:
+			case MCMD_CD_TITLETRACK:
+				SC_MustGetNumber();
+				cd_NonLevelTracks[mcmdValue - MCMD_CD_STARTTRACK] = sc_Number;
+				break;
+			}
+		}
+		mapMax = map > mapMax ? map : mapMax;
+	}
+	SC_Close();
+	MapCount = mapMax;
+}
+
+//==========================================================================
+//
+// P_GetMapCluster
+//
+//==========================================================================
+
+int P_GetMapCluster(int map)
+{
+	return MapInfo[QualifyMap(map)].cluster;
+}
+
+//==========================================================================
+//
+// P_GetMapCDTrack
+//
+//==========================================================================
+
+int P_GetMapCDTrack(int map)
+{
+	return MapInfo[QualifyMap(map)].cdTrack;
+}
+
+//==========================================================================
+//
+// P_GetMapWarpTrans
+//
+//==========================================================================
+
+int P_GetMapWarpTrans(int map)
+{
+	return MapInfo[QualifyMap(map)].warpTrans;
+}
+
+//==========================================================================
+//
+// P_GetMapNextMap
+//
+//==========================================================================
+
+int P_GetMapNextMap(int map)
+{
+	return MapInfo[QualifyMap(map)].nextMap;
+}
+
+//==========================================================================
+//
+// P_TranslateMap
+//
+// Returns the actual map number given a warp map number.
+//
+//==========================================================================
+
+int P_TranslateMap(int map)
+{
+	int		i;
+
+	for (i = 1; i < 99; i++)	// Make this a macro
+	{
+		if (MapInfo[i].warpTrans == map)
+		{
+			return i;
+		}
+	}
+	// Not found
+	return -1;
+}
+
+//==========================================================================
+//
+// P_GetMapSky1Texture
+//
+//==========================================================================
+
+int P_GetMapSky1Texture(int map)
+{
+	return MapInfo[QualifyMap(map)].sky1Texture;
+}
+
+//==========================================================================
+//
+// P_GetMapSky2Texture
+//
+//==========================================================================
+
+int P_GetMapSky2Texture(int map)
+{
+	return MapInfo[QualifyMap(map)].sky2Texture;
+}
+
+//==========================================================================
+//
+// P_GetMapName
+//
+//==========================================================================
+
+const char *P_GetMapName(int map)
+{
+	return MapInfo[QualifyMap(map)].name;
+}
+
+//==========================================================================
+//
+// P_GetMapSky1ScrollDelta
+//
+//==========================================================================
+
+fixed_t P_GetMapSky1ScrollDelta(int map)
+{
+	return MapInfo[QualifyMap(map)].sky1ScrollDelta;
+}
+
+//==========================================================================
+//
+// P_GetMapSky2ScrollDelta
+//
+//==========================================================================
+
+fixed_t P_GetMapSky2ScrollDelta(int map)
+{
+	return MapInfo[QualifyMap(map)].sky2ScrollDelta;
+}
+
+//==========================================================================
+//
+// P_GetMapDoubleSky
+//
+//==========================================================================
+
+boolean P_GetMapDoubleSky(int map)
+{
+	return MapInfo[QualifyMap(map)].doubleSky;
+}
+
+//==========================================================================
+//
+// P_GetMapLightning
+//
+//==========================================================================
+
+boolean P_GetMapLightning(int map)
+{
+	return MapInfo[QualifyMap(map)].lightning;
+}
+
+//==========================================================================
+//
+// P_GetMapFadeTable
+//
+//==========================================================================
+
+boolean P_GetMapFadeTable(int map)
+{
+	return MapInfo[QualifyMap(map)].fadetable;
+}
+
+//==========================================================================
+//
+// P_GetMapSongLump
+//
+//==========================================================================
+
+const char *P_GetMapSongLump(int map)
+{
+	if (!strcasecmp(MapInfo[QualifyMap(map)].songLump, DEFAULT_SONG_LUMP))
+	{
+		return NULL;
+	}
+	else
+	{
+		return MapInfo[QualifyMap(map)].songLump;
+	}
+}
+
+//==========================================================================
+//
+// P_PutMapSongLump
+//
+//==========================================================================
+
+void P_PutMapSongLump(int map, const char *lumpName)
+{
+	if (map < 1 || map > MapCount)
+	{
+		return;
+	}
+	strcpy(MapInfo[map].songLump, lumpName);
+}
+
+//==========================================================================
+//
+// P_GetCDStartTrack
+//
+//==========================================================================
+
+int P_GetCDStartTrack(void)
+{
+	return cd_NonLevelTracks[MCMD_CD_STARTTRACK - MCMD_CD_STARTTRACK];
+}
+
+//==========================================================================
+//
+// P_GetCDEnd1Track
+//
+//==========================================================================
+
+int P_GetCDEnd1Track(void)
+{
+	return cd_NonLevelTracks[MCMD_CD_END1TRACK - MCMD_CD_STARTTRACK];
+}
+
+//==========================================================================
+//
+// P_GetCDEnd2Track
+//
+//==========================================================================
+
+int P_GetCDEnd2Track(void)
+{
+	return cd_NonLevelTracks[MCMD_CD_END2TRACK - MCMD_CD_STARTTRACK];
+}
+
+//==========================================================================
+//
+// P_GetCDEnd3Track
+//
+//==========================================================================
+
+int P_GetCDEnd3Track(void)
+{
+	return cd_NonLevelTracks[MCMD_CD_END3TRACK - MCMD_CD_STARTTRACK];
+}
+
+//==========================================================================
+//
+// P_GetCDIntermissionTrack
+//
+//==========================================================================
+
+int P_GetCDIntermissionTrack(void)
+{
+	return cd_NonLevelTracks[MCMD_CD_INTERTRACK - MCMD_CD_STARTTRACK];
+}
+
+//==========================================================================
+//
+// P_GetCDTitleTrack
+//
+//==========================================================================
+
+int P_GetCDTitleTrack(void)
+{
+	return cd_NonLevelTracks[MCMD_CD_TITLETRACK - MCMD_CD_STARTTRACK];
+}
+
+//==========================================================================
+//
+// QualifyMap
+//
+//==========================================================================
+
+static int QualifyMap(int map)
+{
+	return (map < 1 || map > MapCount) ? 0 : map;
+}
+
+//==========================================================================
+//
+// P_Init
+//
+//==========================================================================
+
+void P_Init(void)
+{
+	InitMapInfo();
+	P_InitSwitchList();
+	P_InitFTAnims();	// Init flat and texture animations
+	P_InitTerrainTypes();
+	P_InitLava();
+	R_InitSprites(sprnames);
+}
+
+// Special early initializer needed to start sound before R_Init()
+void InitMapMusicInfo(void)
+{
+	int		i;
+
+	for (i = 0; i < 99; i++)
+	{
+		strcpy(MapInfo[i].songLump, DEFAULT_SONG_LUMP);
+	}
+	MapCount = 98;
+}
+
+/*
+void My_Debug(void)
+{
+	int		i;
+
+	printf("My debug stuff ----------------------\n");
+	printf("gamemap=%d\n", gamemap);
+	for (i = 0; i < 10; i++)
+	{
+		printf("i=%d  songlump=%s\n", i, MapInfo[i].songLump);
+	}
+}
+*/
+
--- /dev/null
+++ b/p_sight.c
@@ -1,0 +1,388 @@
+
+//**************************************************************************
+//**
+//** p_sight.c : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 373 $
+//** $Date: 2009-05-19 21:14:28 +0300 (Tue, 19 May 2009) $
+//**
+//**************************************************************************
+
+#include "h2stdinc.h"
+#include "h2def.h"
+#include "p_local.h"
+
+/*
+==============================================================================
+
+P_CheckSight
+
+This uses specialized forms of the maputils routines for optimized performance
+
+==============================================================================
+*/
+
+extern polyblock_t	**PolyBlockMap;
+
+static int		sightcounts[3];
+static fixed_t		sightzstart;		/* eye z of looker */
+
+fixed_t			topslope, bottomslope;
+				  /* slopes to top and bottom of target */
+
+
+/*
+==============
+=
+= PTR_SightTraverse
+=
+==============
+*/
+
+static boolean PTR_SightTraverse (intercept_t *in)
+{
+	line_t	*li;
+	fixed_t	slope;
+
+	li = in->d.line;
+
+//
+// crosses a two sided line
+//
+	P_LineOpening (li);
+
+	if (openbottom >= opentop)	// quick test for totally closed doors
+		return false;	// stop
+
+	if (li->frontsector->floorheight != li->backsector->floorheight)
+	{
+		slope = FixedDiv (openbottom - sightzstart, in->frac);
+		if (slope > bottomslope)
+			bottomslope = slope;
+	}
+
+	if (li->frontsector->ceilingheight != li->backsector->ceilingheight)
+	{
+		slope = FixedDiv (opentop - sightzstart, in->frac);
+		if (slope < topslope)
+			topslope = slope;
+	}
+
+	if (topslope <= bottomslope)
+		return false;	// stop
+
+	return true;	// keep going
+}
+
+
+/*
+==================
+=
+= P_SightBlockLinesIterator
+=
+===================
+*/
+
+static boolean P_SightBlockLinesIterator (int x, int y)
+{
+	int		offset;
+	short		*list;
+	line_t		*ld;
+	int		s1, s2;
+	divline_t	dl;
+
+	polyblock_t	*polyLink;
+	seg_t		**segList;
+	int		i;
+
+	offset = y*bmapwidth + x;
+
+	polyLink = PolyBlockMap[offset];
+	while (polyLink)
+	{
+		if (polyLink->polyobj)
+		{ // only check non-empty links
+			if (polyLink->polyobj->validcount != validcount)
+			{
+				segList = polyLink->polyobj->segs;
+				for (i = 0; i < polyLink->polyobj->numsegs; i++, segList++)
+				{
+					ld = (*segList)->linedef;
+					if (ld->validcount == validcount)
+					{
+						continue;
+					}
+					ld->validcount = validcount;
+					s1 = P_PointOnDivlineSide (ld->v1->x, ld->v1->y, &trace);
+					s2 = P_PointOnDivlineSide (ld->v2->x, ld->v2->y, &trace);
+					if (s1 == s2)
+						continue;		// line isn't crossed
+					P_MakeDivline (ld, &dl);
+					s1 = P_PointOnDivlineSide (trace.x, trace.y, &dl);
+					s2 = P_PointOnDivlineSide (trace.x + trace.dx, trace.y + trace.dy, &dl);
+					if (s1 == s2)
+						continue;		// line isn't crossed
+
+				// try to early out the check
+					if (!ld->backsector)
+						return false;	// stop checking
+
+				// store the line for later intersection testing
+					intercept_p->d.line = ld;
+					intercept_p++;
+				}
+				polyLink->polyobj->validcount = validcount;
+			}
+		}
+		polyLink = polyLink->next;
+	}
+
+	offset = *(blockmap + offset);
+
+	for (list = blockmaplump+offset; *list != -1; list++)
+	{
+		ld = &lines[*list];
+		if (ld->validcount == validcount)
+			continue;		// line has already been checked
+		ld->validcount = validcount;
+
+		s1 = P_PointOnDivlineSide (ld->v1->x, ld->v1->y, &trace);
+		s2 = P_PointOnDivlineSide (ld->v2->x, ld->v2->y, &trace);
+		if (s1 == s2)
+			continue;		// line isn't crossed
+		P_MakeDivline (ld, &dl);
+		s1 = P_PointOnDivlineSide (trace.x, trace.y, &dl);
+		s2 = P_PointOnDivlineSide (trace.x + trace.dx, trace.y + trace.dy, &dl);
+		if (s1 == s2)
+			continue;		// line isn't crossed
+
+	// try to early out the check
+		if (!ld->backsector)
+			return false;	// stop checking
+
+	// store the line for later intersection testing
+		intercept_p->d.line = ld;
+		intercept_p++;
+	}
+
+	return true;			// everything was checked
+}
+
+/*
+====================
+=
+= P_SightTraverseIntercepts
+=
+= Returns true if the traverser function returns true for all lines
+====================
+*/
+
+static boolean P_SightTraverseIntercepts (void)
+{
+	int		count;
+	fixed_t		dist;
+	intercept_t	*scan, *in;
+	divline_t	dl;
+
+	count = intercept_p - intercepts;
+//
+// calculate intercept distance
+//
+	for (scan = intercepts; scan < intercept_p; scan++)
+	{
+		P_MakeDivline (scan->d.line, &dl);
+		scan->frac = P_InterceptVector (&trace, &dl);
+	}
+
+//
+// go through in order
+//
+	in = NULL;		// shut up compiler warning
+
+	while (count--)
+	{
+		dist = H2MAXINT;
+		for (scan = intercepts; scan < intercept_p; scan++)
+		{
+			if (scan->frac < dist)
+			{
+				dist = scan->frac;
+				in = scan;
+			}
+		}
+
+		if ( !PTR_SightTraverse (in) )
+			return false;                   // don't bother going farther
+		in->frac = H2MAXINT;
+	}
+
+	return true;		// everything was traversed
+}
+
+
+/*
+==================
+=
+= P_SightPathTraverse
+=
+= Traces a line from x1,y1 to x2,y2, calling the traverser function for each
+= Returns true if the traverser function returns true for all lines
+==================
+*/
+
+static boolean P_SightPathTraverse (fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2)
+{
+	fixed_t	xt1,yt1,xt2,yt2;
+	fixed_t	xstep,ystep;
+	fixed_t	partial;
+	fixed_t	xintercept, yintercept;
+	int	mapx, mapy, mapxstep, mapystep;
+	int	count;
+
+	validcount++;
+	intercept_p = intercepts;
+
+	if (((x1 - bmaporgx) & (MAPBLOCKSIZE - 1)) == 0)
+		x1 += FRACUNIT;			// don't side exactly on a line
+	if (((y1 - bmaporgy) & (MAPBLOCKSIZE - 1)) == 0)
+		y1 += FRACUNIT;			// don't side exactly on a line
+	trace.x = x1;
+	trace.y = y1;
+	trace.dx = x2 - x1;
+	trace.dy = y2 - y1;
+
+	x1 -= bmaporgx;
+	y1 -= bmaporgy;
+	xt1 = x1>>MAPBLOCKSHIFT;
+	yt1 = y1>>MAPBLOCKSHIFT;
+
+	x2 -= bmaporgx;
+	y2 -= bmaporgy;
+	xt2 = x2>>MAPBLOCKSHIFT;
+	yt2 = y2>>MAPBLOCKSHIFT;
+
+// points should never be out of bounds, but check once instead of
+// each block
+	if (xt1 < 0 || yt1 < 0 || xt1 >= bmapwidth || yt1 >= bmapheight ||
+	    xt2 < 0 || yt2 < 0 || xt2 >= bmapwidth || yt2 >= bmapheight)
+		return false;
+
+	if (xt2 > xt1)
+	{
+		mapxstep = 1;
+		partial = FRACUNIT - ((x1>>MAPBTOFRAC) & (FRACUNIT - 1));
+		ystep = FixedDiv (y2 - y1, abs(x2 - x1));
+	}
+	else if (xt2 < xt1)
+	{
+		mapxstep = -1;
+		partial = (x1>>MAPBTOFRAC) & (FRACUNIT - 1);
+		ystep = FixedDiv (y2 - y1, abs(x2 - x1));
+	}
+	else
+	{
+		mapxstep = 0;
+		partial = FRACUNIT;
+		ystep = 256*FRACUNIT;
+	}
+	yintercept = (y1>>MAPBTOFRAC) + FixedMul (partial, ystep);
+
+	if (yt2 > yt1)
+	{
+		mapystep = 1;
+		partial = FRACUNIT - ((y1>>MAPBTOFRAC) & (FRACUNIT - 1));
+		xstep = FixedDiv (x2 - x1, abs(y2 - y1));
+	}
+	else if (yt2 < yt1)
+	{
+		mapystep = -1;
+		partial = (y1>>MAPBTOFRAC) & (FRACUNIT - 1);
+		xstep = FixedDiv (x2 - x1, abs(y2 - y1));
+	}
+	else
+	{
+		mapystep = 0;
+		partial = FRACUNIT;
+		xstep = 256*FRACUNIT;
+	}
+	xintercept = (x1>>MAPBTOFRAC) + FixedMul (partial, xstep);
+
+//
+// step through map blocks
+// Count is present to prevent a round off error from skipping the break
+	mapx = xt1;
+	mapy = yt1;
+
+	for (count = 0; count < 64; count++)
+	{
+		if (!P_SightBlockLinesIterator (mapx, mapy))
+		{
+			sightcounts[1]++;
+			return false;   // early out
+		}
+
+		if (mapx == xt2 && mapy == yt2)
+			break;
+
+		if ((yintercept >> FRACBITS) == mapy)
+		{
+			yintercept += ystep;
+			mapx += mapxstep;
+		}
+		else if ((xintercept >> FRACBITS) == mapx)
+		{
+			xintercept += xstep;
+			mapy += mapystep;
+		}
+	}
+
+//
+// couldn't early out, so go through the sorted list
+//
+	sightcounts[2]++;
+
+	return P_SightTraverseIntercepts ();
+}
+
+
+/*
+=====================
+=
+= P_CheckSight
+=
+= Returns true if a straight line between t1 and t2 is unobstructed
+= look from eyes of t1 to any part of t2
+=
+=====================
+*/
+
+boolean P_CheckSight (mobj_t *t1, mobj_t *t2)
+{
+	int		s1, s2;
+	int		pnum, bytenum, bitnum;
+
+//
+// check for trivial rejection
+//
+	s1 = (t1->subsector->sector - sectors);
+	s2 = (t2->subsector->sector - sectors);
+	pnum = s1*numsectors + s2;
+	bytenum = pnum>>3;
+	bitnum = 1 << (pnum & 7);
+
+	if (rejectmatrix[bytenum] & bitnum)
+	{
+		sightcounts[0]++;
+		return false;		// can't possibly be connected
+	}
+
+//
+// check precisely
+//
+	sightzstart = t1->z + t1->height - (t1->height>>2);
+	topslope = (t2->z + t2->height) - sightzstart;
+	bottomslope = (t2->z) - sightzstart;
+
+	return P_SightPathTraverse (t1->x, t1->y, t2->x, t2->y);
+}
+
--- /dev/null
+++ b/p_spec.c
@@ -1,0 +1,1176 @@
+
+//**************************************************************************
+//**
+//** p_spec.c : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 584 $
+//** $Date: 2012-02-17 12:01:51 +0200 (Fri, 17 Feb 2012) $
+//**
+//**************************************************************************
+
+// HEADER FILES ------------------------------------------------------------
+
+#include "h2stdinc.h"
+#include "h2def.h"
+#include "p_local.h"
+#include "soundst.h"
+
+// MACROS ------------------------------------------------------------------
+
+#define MAX_TAGGED_LINES	64
+
+// TYPES -------------------------------------------------------------------
+
+// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
+
+extern const char *TextKeyMessages[11];
+
+// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
+
+// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
+
+static boolean CheckedLockedDoor(mobj_t *mo, byte lock);
+
+// EXTERNAL DATA DECLARATIONS ----------------------------------------------
+
+// PUBLIC DATA DEFINITIONS -------------------------------------------------
+
+int *TerrainTypes;
+mobj_t LavaInflictor;
+
+// PRIVATE DATA DEFINITIONS ------------------------------------------------
+
+static struct
+{
+	const char	*name;
+	int		type;
+} TerrainTypeDefs[] =
+{
+	{ "X_005", FLOOR_WATER },
+	{ "X_001", FLOOR_LAVA },
+	{ "X_009", FLOOR_SLUDGE },
+	{ "F_033", FLOOR_ICE },
+	{ "END", -1 }
+};
+
+static struct
+{
+	line_t *line;
+	int  lineTag;
+} TaggedLines[MAX_TAGGED_LINES];
+
+static int TaggedLineCount;
+
+// CODE --------------------------------------------------------------------
+
+//==========================================================================
+//
+// P_InitLava
+//
+//==========================================================================
+
+void P_InitLava(void)
+{
+	memset(&LavaInflictor, 0, sizeof(mobj_t));
+	LavaInflictor.type = MT_CIRCLEFLAME;
+	LavaInflictor.flags2 = MF2_FIREDAMAGE|MF2_NODMGTHRUST;
+}
+
+//==========================================================================
+//
+// P_InitTerrainTypes
+//
+//==========================================================================
+
+void P_InitTerrainTypes(void)
+{
+	int i;
+	int lump;
+	int size;
+
+	size = (numflats + 1) * sizeof(int);
+	TerrainTypes = (int *) Z_Malloc(size, PU_STATIC, NULL);
+	memset(TerrainTypes, 0, size);
+	for (i = 0; TerrainTypeDefs[i].type != -1; i++)
+	{
+		lump = W_CheckNumForName(TerrainTypeDefs[i].name);
+		if (lump != -1)
+		{
+			TerrainTypes[lump - firstflat] = TerrainTypeDefs[i].type;
+		}
+	}
+}
+
+//==========================================================================
+//
+// getSide
+//
+// Will return a side_t* given the number of the current sector, the
+// line number, and the side (0/1) that you want.
+//
+//==========================================================================
+
+/*
+side_t *getSide(int currentSector, int line, int side)
+{
+	return &sides[ (sectors[currentSector].lines[line])->sidenum[side] ];
+}
+*/
+
+//==========================================================================
+//
+// getSector
+//
+// Will return a sector_t* given the number of the current sector, the
+// line number, and the side (0/1) that you want.
+//
+//==========================================================================
+
+/*
+sector_t *getSector(int currentSector, int line, int side)
+{
+	return sides[ (sectors[currentSector].lines[line])->sidenum[side] ].sector;
+}
+*/
+
+//==========================================================================
+//
+// twoSided
+//
+// Given the sector number and the line number, will tell you whether
+// the line is two-sided or not.
+//
+//==========================================================================
+
+/*
+int twoSided(int sector, int line)
+{
+	return (sectors[sector].lines[line])->flags & ML_TWOSIDED;
+}
+*/
+
+//==================================================================
+//
+// Return sector_t * of sector next to current. NULL if not two-sided line
+//
+//==================================================================
+
+sector_t *getNextSector(line_t *line,sector_t *sec)
+{
+	if (!(line->flags & ML_TWOSIDED))
+		return NULL;
+
+	if (line->frontsector == sec)
+		return line->backsector;
+
+	return line->frontsector;
+}
+
+//==================================================================
+//
+// FIND LOWEST FLOOR HEIGHT IN SURROUNDING SECTORS
+//
+//==================================================================
+
+fixed_t P_FindLowestFloorSurrounding(sector_t *sec)
+{
+	int		i;
+	line_t		*check;
+	sector_t	*other;
+	fixed_t		floor = sec->floorheight;
+
+	for (i = 0; i < sec->linecount; i++)
+	{
+		check = sec->lines[i];
+		other = getNextSector(check,sec);
+		if (!other)
+			continue;
+		if (other->floorheight < floor)
+			floor = other->floorheight;
+	}
+	return floor;
+}
+
+//==================================================================
+//
+// FIND HIGHEST FLOOR HEIGHT IN SURROUNDING SECTORS
+//
+//==================================================================
+
+fixed_t P_FindHighestFloorSurrounding(sector_t *sec)
+{
+	int		i;
+	line_t		*check;
+	sector_t	*other;
+	fixed_t		floor = -500*FRACUNIT;
+
+	for (i = 0; i < sec->linecount; i++)
+	{
+		check = sec->lines[i];
+		other = getNextSector(check,sec);
+		if (!other)
+			continue;
+		if (other->floorheight > floor)
+			floor = other->floorheight;
+	}
+	return floor;
+}
+
+//==================================================================
+//
+// FIND NEXT HIGHEST FLOOR IN SURROUNDING SECTORS
+//
+//==================================================================
+
+
+#define MAX_ADJOINING_SECTORS	20	/* 20 adjoining sectors max! */
+
+fixed_t P_FindNextHighestFloor(sector_t *sec,int currentheight)
+{
+	int		i;
+	int		h;
+	int		min;
+	line_t		*check;
+	sector_t	*other;
+	fixed_t		height = currentheight;
+	fixed_t		heightlist[MAX_ADJOINING_SECTORS];
+
+	for (i = 0, h = 0; i < sec->linecount; i++)
+	{
+		check = sec->lines[i];
+		other = getNextSector(check,sec);
+		if (!other)
+			continue;
+		if (other->floorheight > height)
+			heightlist[h++] = other->floorheight;
+		if (h >= MAX_ADJOINING_SECTORS)
+		{
+			fprintf(stderr, "Sector with more than %d adjoining sectors\n",
+					 MAX_ADJOINING_SECTORS);
+			break;
+		}
+	}
+
+	//
+	// Find lowest height in list
+	//
+	if(!h)
+		return currentheight;
+
+	min = heightlist[0];
+	for (i = 1; i < h; i++)
+	{
+		if (heightlist[i] < min)
+			min = heightlist[i];
+	}
+
+	return min;
+}
+
+//==================================================================
+//
+// FIND LOWEST CEILING IN THE SURROUNDING SECTORS
+//
+//==================================================================
+
+fixed_t P_FindLowestCeilingSurrounding(sector_t *sec)
+{
+	int		i;
+	line_t		*check;
+	sector_t	*other;
+	fixed_t		height = H2MAXINT;
+
+	for (i = 0; i < sec->linecount; i++)
+	{
+		check = sec->lines[i];
+		other = getNextSector(check,sec);
+		if (!other)
+			continue;
+		if (other->ceilingheight < height)
+			height = other->ceilingheight;
+	}
+	return height;
+}
+
+//==================================================================
+//
+// FIND HIGHEST CEILING IN THE SURROUNDING SECTORS
+//
+//==================================================================
+
+fixed_t P_FindHighestCeilingSurrounding(sector_t *sec)
+{
+	int		i;
+	line_t		*check;
+	sector_t	*other;
+	fixed_t		height = 0;
+
+	for (i = 0; i < sec->linecount; i++)
+	{
+		check = sec->lines[i];
+		other = getNextSector(check,sec);
+		if (!other)
+			continue;
+		if (other->ceilingheight > height)
+			height = other->ceilingheight;
+	}
+	return height;
+}
+
+//==================================================================
+//
+// RETURN NEXT SECTOR # THAT LINE TAG REFERS TO
+//
+//==================================================================
+
+/*
+int P_FindSectorFromLineTag(line_t  *line,int start)
+{
+	int     i;
+
+	for (i = start + 1; i < numsectors; i++)
+	{
+		if (sectors[i].tag == line->arg1)
+			return i;
+	}
+	return -1;
+}
+*/
+
+//=========================================================================
+//
+// P_FindSectorFromTag
+//
+//=========================================================================
+
+int P_FindSectorFromTag(int tag, int start)
+{
+	int i;
+
+	for (i = start + 1; i < numsectors; i++)
+	{
+		if (sectors[i].tag == tag)
+		{
+			return i;
+		}
+	}
+	return -1;
+}
+
+//==================================================================
+//
+// Find minimum light from an adjacent sector
+//
+//==================================================================
+
+/*
+int P_FindMinSurroundingLight(sector_t *sector,int max)
+{
+	int		i;
+	int		min;
+	line_t		*line;
+	sector_t	*check;
+
+	min = max;
+	for (i = 0; i < sector->linecount; i++)
+	{
+		line = sector->lines[i];
+		check = getNextSector(line,sector);
+		if (!check)
+			continue;
+		if (check->lightlevel < min)
+			min = check->lightlevel;
+	}
+	return min;
+}
+*/
+
+//=========================================================================
+//
+// EV_SectorSoundChange
+//
+//=========================================================================
+
+static boolean EV_SectorSoundChange(byte *args)
+{
+	int secNum;
+	boolean rtn;
+
+	if (!args[0])
+	{
+		return false;
+	}
+	secNum = -1;
+	rtn = false;
+	while ((secNum = P_FindSectorFromTag(args[0], secNum)) >= 0)
+	{
+		sectors[secNum].seqType = args[1];
+		rtn = true;
+	}
+	return rtn;
+}
+
+//============================================================================
+//
+// CheckedLockedDoor
+//
+//============================================================================
+
+static boolean CheckedLockedDoor(mobj_t *mo, byte lock)
+{
+	char LockedBuffer[80];
+
+	if (!mo->player)
+	{
+		return false;
+	}
+	if (!lock)
+	{
+		return true;
+	}
+	if (!(mo->player->keys & (1<<(lock-1))))
+	{
+		snprintf(LockedBuffer, sizeof(LockedBuffer),
+			 "YOU NEED THE %s\n", TextKeyMessages[lock-1]);
+		P_SetMessage(mo->player, LockedBuffer, true);
+		S_StartSound(mo, SFX_DOOR_LOCKED);
+		return false;
+	}
+	return true;
+}
+
+//==========================================================================
+//
+// EV_LineSearchForPuzzleItem
+//
+//==========================================================================
+
+static boolean EV_LineSearchForPuzzleItem(line_t *line, byte *args, mobj_t *mo)
+{
+	player_t *player;
+	int i;
+	artitype_t type, arti;
+
+	if (!mo)
+		return false;
+	player = mo->player;
+	if (!player)
+		return false;
+
+	// Search player's inventory for puzzle items
+	for (i = 0; i < player->artifactCount; i++)
+	{
+		arti = player->inventory[i].type;
+		if (arti < arti_firstpuzzitem)
+			continue;
+		type = arti - arti_firstpuzzitem;
+		//if (type < 0)
+		//	continue;
+		if (type == line->arg1)
+		{
+			// A puzzle item was found for the line
+			if (P_UseArtifact(player, arti))
+			{
+				// A puzzle item was found for the line
+				P_PlayerRemoveArtifact(player, i);
+				if (player == &players[consoleplayer])
+				{
+					if (arti < arti_firstpuzzitem)
+					{
+						S_StartSound(NULL, SFX_ARTIFACT_USE);
+					}
+					else
+					{
+						S_StartSound(NULL, SFX_PUZZLE_SUCCESS);
+					}
+					ArtifactFlash = 4;
+				}
+				return true;
+			}
+		}
+	}
+	return false;
+}
+
+
+/*
+==============================================================================
+
+EVENTS
+
+Events are operations triggered by using, crossing, or shooting special lines,
+or by timed thinkers
+
+==============================================================================
+*/
+
+//============================================================================
+//
+// P_ExecuteLineSpecial
+//
+//============================================================================
+
+boolean P_ExecuteLineSpecial(int special, byte *args, line_t *line, int side,
+								mobj_t *mo)
+{
+	boolean buttonSuccess;
+
+	buttonSuccess = false;
+	switch (special)
+	{
+	case 1: // Poly Start Line
+		break;
+	case 2: // Poly Rotate Left
+		buttonSuccess = EV_RotatePoly(line, args, 1, false);
+		break;
+	case 3: // Poly Rotate Right
+		buttonSuccess = EV_RotatePoly(line, args, -1, false);
+		break;
+	case 4: // Poly Move
+		buttonSuccess = EV_MovePoly(line, args, false, false);
+		break;
+	case 5: // Poly Explicit Line:  Only used in initialization
+		break;
+	case 6: // Poly Move Times 8
+		buttonSuccess = EV_MovePoly(line, args, true, false);
+		break;
+	case 7: // Poly Door Swing
+		buttonSuccess = EV_OpenPolyDoor(line, args, PODOOR_SWING);
+		break;
+	case 8: // Poly Door Slide
+		buttonSuccess = EV_OpenPolyDoor(line, args, PODOOR_SLIDE);
+		break;
+	case 10: // Door Close
+		buttonSuccess = EV_DoDoor(line, args, DREV_CLOSE);
+		break;
+	case 11: // Door Open
+		if (!args[0])
+		{
+			buttonSuccess = EV_VerticalDoor(line, mo);
+		}
+		else
+		{
+			buttonSuccess = EV_DoDoor(line, args, DREV_OPEN);
+		}
+		break;
+	case 12: // Door Raise
+		if (!args[0])
+		{
+			buttonSuccess = EV_VerticalDoor(line, mo);
+		}
+		else
+		{
+			buttonSuccess = EV_DoDoor(line, args, DREV_NORMAL);
+		}
+		break;
+	case 13: // Door Locked_Raise
+		if (CheckedLockedDoor(mo, args[3]))
+		{
+			if (!args[0])
+			{
+				buttonSuccess = EV_VerticalDoor(line, mo);
+			}
+			else
+			{
+				buttonSuccess = EV_DoDoor(line, args, DREV_NORMAL);
+			}
+		}
+		break;
+	case 20: // Floor Lower by Value
+		buttonSuccess = EV_DoFloor(line, args, FLEV_LOWERFLOORBYVALUE);
+		break;
+	case 21: // Floor Lower to Lowest
+		buttonSuccess = EV_DoFloor(line, args, FLEV_LOWERFLOORTOLOWEST);
+		break;
+	case 22: // Floor Lower to Nearest
+		buttonSuccess = EV_DoFloor(line, args, FLEV_LOWERFLOOR);
+		break;
+	case 23: // Floor Raise by Value
+		buttonSuccess = EV_DoFloor(line, args, FLEV_RAISEFLOORBYVALUE);
+		break;
+	case 24: // Floor Raise to Highest
+		buttonSuccess = EV_DoFloor(line, args, FLEV_RAISEFLOOR);
+		break;
+	case 25: // Floor Raise to Nearest
+		buttonSuccess = EV_DoFloor(line, args, FLEV_RAISEFLOORTONEAREST);
+		break;
+	case 26: // Stairs Build Down Normal
+		buttonSuccess = EV_BuildStairs(line, args, -1, STAIRS_NORMAL);
+		break;
+	case 27: // Build Stairs Up Normal
+		buttonSuccess = EV_BuildStairs(line, args, 1, STAIRS_NORMAL);
+		break;
+	case 28: // Floor Raise and Crush
+		buttonSuccess = EV_DoFloor(line, args, FLEV_RAISEFLOORCRUSH);
+		break;
+	case 29: // Build Pillar (no crushing)
+		buttonSuccess = EV_BuildPillar(line, args, false);
+		break;
+	case 30: // Open Pillar
+		buttonSuccess = EV_OpenPillar(line, args);
+		break;
+	case 31: // Stairs Build Down Sync
+		buttonSuccess = EV_BuildStairs(line, args, -1, STAIRS_SYNC);
+		break;
+	case 32: // Build Stairs Up Sync
+		buttonSuccess = EV_BuildStairs(line, args, 1, STAIRS_SYNC);
+		break;
+	case 35: // Raise Floor by Value Times 8
+		buttonSuccess = EV_DoFloor(line, args, FLEV_RAISEBYVALUETIMES8);
+		break;
+	case 36: // Lower Floor by Value Times 8
+		buttonSuccess = EV_DoFloor(line, args, FLEV_LOWERBYVALUETIMES8);
+		break;
+	case 40: // Ceiling Lower by Value
+		buttonSuccess = EV_DoCeiling(line, args, CLEV_LOWERBYVALUE);
+		break;
+	case 41: // Ceiling Raise by Value
+		buttonSuccess = EV_DoCeiling(line, args, CLEV_RAISEBYVALUE);
+		break;
+	case 42: // Ceiling Crush and Raise
+		buttonSuccess = EV_DoCeiling(line, args, CLEV_CRUSHANDRAISE);
+		break;
+	case 43: // Ceiling Lower and Crush
+		buttonSuccess = EV_DoCeiling(line, args, CLEV_LOWERANDCRUSH);
+		break;
+	case 44: // Ceiling Crush Stop
+		buttonSuccess = EV_CeilingCrushStop(line, args);
+		break;
+	case 45: // Ceiling Crush Raise and Stay
+		buttonSuccess = EV_DoCeiling(line, args, CLEV_CRUSHRAISEANDSTAY);
+		break;
+	case 46: // Floor Crush Stop
+		buttonSuccess = EV_FloorCrushStop(line, args);
+		break;
+	case 60: // Plat Perpetual Raise
+		buttonSuccess = EV_DoPlat(line, args, PLAT_PERPETUALRAISE, 0);
+		break;
+	case 61: // Plat Stop
+		EV_StopPlat(line, args);
+		break;
+	case 62: // Plat Down-Wait-Up-Stay
+		buttonSuccess = EV_DoPlat(line, args, PLAT_DOWNWAITUPSTAY, 0);
+		break;
+	case 63: // Plat Down-by-Value*8-Wait-Up-Stay
+		buttonSuccess = EV_DoPlat(line, args, PLAT_DOWNBYVALUEWAITUPSTAY, 0);
+		break;
+	case 64: // Plat Up-Wait-Down-Stay
+		buttonSuccess = EV_DoPlat(line, args, PLAT_UPWAITDOWNSTAY, 0);
+		break;
+	case 65: // Plat Up-by-Value*8-Wait-Down-Stay
+		buttonSuccess = EV_DoPlat(line, args, PLAT_UPBYVALUEWAITDOWNSTAY, 0);
+		break;
+	case 66: // Floor Lower Instant * 8
+		buttonSuccess = EV_DoFloor(line, args, FLEV_LOWERTIMES8INSTANT);
+		break;
+	case 67: // Floor Raise Instant * 8
+		buttonSuccess = EV_DoFloor(line, args, FLEV_RAISETIMES8INSTANT);
+		break;
+	case 68: // Floor Move to Value * 8
+		buttonSuccess = EV_DoFloor(line, args, FLEV_MOVETOVALUETIMES8);
+		break;
+	case 69: // Ceiling Move to Value * 8
+		buttonSuccess = EV_DoCeiling(line, args, CLEV_MOVETOVALUETIMES8);
+		break;
+	case 70: // Teleport
+		if (side == 0)
+		{ // Only teleport when crossing the front side of a line
+			buttonSuccess = EV_Teleport(args[0], mo, true);
+		}
+		break;
+	case 71: // Teleport, no fog
+		if (side == 0)
+		{ // Only teleport when crossing the front side of a line
+			buttonSuccess = EV_Teleport(args[0], mo, false);
+		}
+		break;
+	case 72: // Thrust Mobj
+		if (!side) // Only thrust on side 0
+		{
+			P_ThrustMobj(mo, args[0]*(ANGLE_90/64), args[1]<<FRACBITS);
+			buttonSuccess = 1;
+		}
+		break;
+	case 73: // Damage Mobj
+		if (args[0])
+		{
+			P_DamageMobj(mo, NULL, NULL, args[0]);
+		}
+		else
+		{ // If arg1 is zero, then guarantee a kill
+			P_DamageMobj(mo, NULL, NULL, 10000);
+		}
+		buttonSuccess = 1;
+		break;
+	case 74: // Teleport_NewMap
+		if (side == 0)
+		{ // Only teleport when crossing the front side of a line
+			// Players must be alive to teleport
+			if (!(mo && mo->player && mo->player->playerstate == PST_DEAD))
+			{
+				G_Completed(args[0], args[1]);
+				buttonSuccess = true;
+			}
+		}
+		break;
+	case 75: // Teleport_EndGame
+		if (side == 0)
+		{ // Only teleport when crossing the front side of a line
+			// Players must be alive to teleport
+			if (!(mo && mo->player && mo->player->playerstate == PST_DEAD))
+			{
+				buttonSuccess = true;
+				if (deathmatch)
+				{ // Winning in deathmatch just goes back to map 1
+					G_Completed(1, 0);
+				}
+				else
+				{ // Passing -1, -1 to G_Completed() starts the Finale
+					G_Completed(-1, -1);
+				}
+			}
+		}
+		break;
+	case 80: // ACS_Execute
+		buttonSuccess = P_StartACS(args[0], args[1], &args[2], mo, line, side);
+		break;
+	case 81: // ACS_Suspend
+		buttonSuccess = P_SuspendACS(args[0], args[1]);
+		break;
+	case 82: // ACS_Terminate
+		buttonSuccess = P_TerminateACS(args[0], args[1]);
+		break;
+	case 83: // ACS_LockedExecute
+		buttonSuccess = P_StartLockedACS(line, args, mo, side);
+		break;
+	case 90: // Poly Rotate Left Override
+		buttonSuccess = EV_RotatePoly(line, args, 1, true);
+		break;
+	case 91: // Poly Rotate Right Override
+		buttonSuccess = EV_RotatePoly(line, args, -1, true);
+		break;
+	case 92: // Poly Move Override
+		buttonSuccess = EV_MovePoly(line, args, false, true);
+		break;
+	case 93: // Poly Move Times 8 Override
+		buttonSuccess = EV_MovePoly(line, args, true, true);
+		break;
+	case 94: // Build Pillar Crush
+		buttonSuccess = EV_BuildPillar(line, args, true);
+		break;
+	case 95: // Lower Floor and Ceiling
+		buttonSuccess = EV_DoFloorAndCeiling(line, args, false);
+		break;
+	case 96: // Raise Floor and Ceiling
+		buttonSuccess = EV_DoFloorAndCeiling(line, args, true);
+		break;
+	case 109: // Force Lightning
+		buttonSuccess = true;
+		P_ForceLightning();
+		break;
+	case 110: // Light Raise by Value
+		buttonSuccess = EV_SpawnLight(line, args, LITE_RAISEBYVALUE);
+		break;
+	case 111: // Light Lower by Value
+		buttonSuccess = EV_SpawnLight(line, args, LITE_LOWERBYVALUE);
+		break;
+	case 112: // Light Change to Value
+		buttonSuccess = EV_SpawnLight(line, args, LITE_CHANGETOVALUE);
+		break;
+	case 113: // Light Fade
+		buttonSuccess = EV_SpawnLight(line, args, LITE_FADE);
+		break;
+	case 114: // Light Glow
+		buttonSuccess = EV_SpawnLight(line, args, LITE_GLOW);
+		break;
+	case 115: // Light Flicker
+		buttonSuccess = EV_SpawnLight(line, args, LITE_FLICKER);
+		break;
+	case 116: // Light Strobe
+		buttonSuccess = EV_SpawnLight(line, args, LITE_STROBE);
+		break;
+	case 120: // Quake Tremor
+		buttonSuccess = A_LocalQuake(args, mo);
+		break;
+	case 129: // UsePuzzleItem
+		buttonSuccess = EV_LineSearchForPuzzleItem(line, args, mo);
+		break;
+	case 130: // Thing_Activate
+		buttonSuccess = EV_ThingActivate(args[0]);
+		break;
+	case 131: // Thing_Deactivate
+		buttonSuccess = EV_ThingDeactivate(args[0]);
+		break;
+	case 132: // Thing_Remove
+		buttonSuccess = EV_ThingRemove(args[0]);
+		break;
+	case 133: // Thing_Destroy
+		buttonSuccess = EV_ThingDestroy(args[0]);
+		break;
+	case 134: // Thing_Projectile
+		buttonSuccess = EV_ThingProjectile(args, 0);
+		break;
+	case 135: // Thing_Spawn
+		buttonSuccess = EV_ThingSpawn(args, 1);
+		break;
+	case 136: // Thing_ProjectileGravity
+		buttonSuccess = EV_ThingProjectile(args, 1);
+		break;
+	case 137: // Thing_SpawnNoFog
+		buttonSuccess = EV_ThingSpawn(args, 0);
+		break;
+	case 138: // Floor_Waggle
+		buttonSuccess = EV_StartFloorWaggle(args[0], args[1], args[2],
+						    args[3], args[4]);
+		break;
+	case 140: // Sector_SoundChange
+		buttonSuccess = EV_SectorSoundChange(args);
+		break;
+
+	// Line specials only processed during level initialization
+	// 100: Scroll_Texture_Left
+	// 101: Scroll_Texture_Right
+	// 102: Scroll_Texture_Up
+	// 103: Scroll_Texture_Down
+	// 121: Line_SetIdentification
+
+	// Inert Line specials
+	default:
+		break;
+	}
+	return buttonSuccess;
+}
+
+//============================================================================
+//
+// P_ActivateLine
+//
+//============================================================================
+
+boolean P_ActivateLine(line_t *line, mobj_t *mo, int side, int activationType)
+{
+	int lineActivation;
+	boolean repeat;
+	boolean buttonSuccess;
+
+	lineActivation = GET_SPAC(line->flags);
+	if (lineActivation != activationType)
+	{
+		return false;
+	}
+	if (!mo->player && !(mo->flags&MF_MISSILE))
+	{
+		if (lineActivation != SPAC_MCROSS)
+		{ // currently, monsters can only activate the MCROSS activation type
+			return false;
+		}
+		if (line->flags & ML_SECRET)
+			return false;		// never open secret doors
+	}
+	repeat = line->flags & ML_REPEAT_SPECIAL;
+	buttonSuccess = false;
+
+	buttonSuccess = P_ExecuteLineSpecial(line->special, &line->arg1, line, side, mo);
+	if (!repeat && buttonSuccess)
+	{ // clear the special on non-retriggerable lines
+		line->special = 0;
+	}
+	if ((lineActivation == SPAC_USE || lineActivation == SPAC_IMPACT) && buttonSuccess)
+	{
+		P_ChangeSwitchTexture(line, repeat);
+	}
+	return true;
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC P_PlayerInSpecialSector
+//
+// Called every tic frame that the player origin is in a special sector.
+//
+//----------------------------------------------------------------------------
+
+void P_PlayerInSpecialSector(player_t *player)
+{
+	sector_t *sector;
+	static int pushTab[3] =
+	{
+		2048*5,
+		2048*10,
+		2048*25
+	};
+
+	sector = player->mo->subsector->sector;
+	if (player->mo->z != sector->floorheight)
+	{ // Player is not touching the floor
+		return;
+	}
+	switch (sector->special)
+	{
+	case 9: // SecretArea
+		player->secretcount++;
+		sector->special = 0;
+		break;
+
+	case 201: case 202: case 203: // Scroll_North_xxx
+		P_Thrust(player, ANG90, pushTab[sector->special-201]);
+		break;
+	case 204: case 205: case 206: // Scroll_East_xxx
+		P_Thrust(player, 0, pushTab[sector->special-204]);
+		break;
+	case 207: case 208: case 209: // Scroll_South_xxx
+		P_Thrust(player, ANG270, pushTab[sector->special-207]);
+		break;
+	case 210: case 211: case 212: // Scroll_West_xxx
+		P_Thrust(player, ANG180, pushTab[sector->special-210]);
+		break;
+	case 213: case 214: case 215: // Scroll_NorthWest_xxx
+		P_Thrust(player, ANG90+ANG45, pushTab[sector->special-213]);
+		break;
+	case 216: case 217: case 218: // Scroll_NorthEast_xxx
+		P_Thrust(player, ANG45, pushTab[sector->special-216]);
+		break;
+	case 219: case 220: case 221: // Scroll_SouthEast_xxx
+		P_Thrust(player, ANG270+ANG45, pushTab[sector->special-219]);
+		break;
+	case 222: case 223: case 224: // Scroll_SouthWest_xxx
+		P_Thrust(player, ANG180+ANG45, pushTab[sector->special-222]);
+		break;
+
+	case 40: case 41: case 42: case 43: case 44: case 45:
+	case 46: case 47: case 48: case 49: case 50: case 51:
+		// Wind specials are handled in (P_mobj):P_XYMovement
+		break;
+
+	case 26: // Stairs_Special1
+	case 27: // Stairs_Special2
+		// Used in (P_floor):ProcessStairSector
+		break;
+
+	case 198: // Lightning Special
+	case 199: // Lightning Flash special
+	case 200: // Sky2
+		// Used in (R_plane):R_Drawplanes
+		break;
+
+	default:
+		I_Error("P_PlayerInSpecialSector: "
+			"unknown special %i", sector->special);
+	}
+}
+
+//============================================================================
+//
+// P_PlayerOnSpecialFlat
+//
+//============================================================================
+
+void P_PlayerOnSpecialFlat(player_t *player, int floorType)
+{
+	if (player->mo->z != player->mo->floorz)
+	{ // Player is not touching the floor
+		return;
+	}
+	switch (floorType)
+	{
+	case FLOOR_LAVA:
+		if (!(leveltime & 31))
+		{
+			P_DamageMobj(player->mo, &LavaInflictor, NULL, 10);
+			S_StartSound(player->mo, SFX_LAVA_SIZZLE);
+		}
+		break;
+	default:
+		break;
+	}
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC P_UpdateSpecials
+//
+//----------------------------------------------------------------------------
+
+void P_UpdateSpecials(void)
+{
+	int i;
+
+	// Handle buttons
+	for (i = 0; i < MAXBUTTONS; i++)
+	{
+		if (buttonlist[i].btimer)
+		{
+			buttonlist[i].btimer--;
+			if (!buttonlist[i].btimer)
+			{
+				switch (buttonlist[i].where)
+				{
+				case SWTCH_TOP:
+					sides[buttonlist[i].line->sidenum[0]].toptexture =
+							buttonlist[i].btexture;
+					break;
+				case SWTCH_MIDDLE:
+					sides[buttonlist[i].line->sidenum[0]].midtexture =
+							buttonlist[i].btexture;
+					break;
+				case SWTCH_BOTTOM:
+					sides[buttonlist[i].line->sidenum[0]].bottomtexture =
+							buttonlist[i].btexture;
+					break;
+				}
+				//S_StartSound(buttonlist[i].soundorg, sfx_switch);
+				memset(&buttonlist[i], 0, sizeof(button_t));
+			}
+		}
+	}
+}
+
+/*
+==============================================================================
+
+							SPECIAL SPAWNING
+
+==============================================================================
+*/
+
+/*
+================================================================================
+= P_SpawnSpecials
+=
+= After the map has been loaded, scan for specials that
+= spawn thinkers
+=
+===============================================================================
+*/
+
+short	numlinespecials;
+line_t	*linespeciallist[MAXLINEANIMS];
+
+void P_SpawnSpecials (void)
+{
+	sector_t	*sector;
+	int		i;
+
+	//
+	// Init special SECTORs
+	//
+	sector = sectors;
+	for (i = 0; i < numsectors; i++, sector++)
+	{
+		if (!sector->special)
+			continue;
+		switch (sector->special)
+		{
+		case 1: // Phased light
+			// Hardcoded base, use sector->lightlevel as the index
+			P_SpawnPhasedLight(sector, 80, -1);
+			break;
+		case 2: // Phased light sequence start
+			P_SpawnLightSequence(sector, 1);
+			break;
+		// Specials 3 & 4 are used by the phased light sequences
+
+		/*
+		case 1:		// FLICKERING LIGHTS
+			P_SpawnLightFlash (sector);
+			break;
+		case 2:		// STROBE FAST
+			P_SpawnStrobeFlash(sector, FASTDARK, 0);
+			break;
+		case 3:		// STROBE SLOW
+			P_SpawnStrobeFlash(sector, SLOWDARK, 0);
+			break;
+		case 4:		// STROBE FAST/DEATH SLIME
+			P_SpawnStrobeFlash(sector, FASTDARK, 0);
+			sector->special = 4;
+			break;
+		case 8:		// GLOWING LIGHT
+			P_SpawnGlowingLight(sector);
+			break;
+		case 9:		// SECRET SECTOR
+			totalsecret++;
+			break;
+		case 10:	// DOOR CLOSE IN 30 SECONDS
+			P_SpawnDoorCloseIn30 (sector);
+			break;
+		case 12:	// SYNC STROBE SLOW
+			P_SpawnStrobeFlash(sector, SLOWDARK, 1);
+			break;
+		case 13:	// SYNC STROBE FAST
+			P_SpawnStrobeFlash(sector, FASTDARK, 1);
+			break;
+		case 14:	// DOOR RAISE IN 5 MINUTES
+			P_SpawnDoorRaiseIn5Mins (sector, i);
+			break;
+		*/
+		}
+	}
+
+	//
+	// Init line EFFECTs
+	//
+	numlinespecials = 0;
+	TaggedLineCount = 0;
+	for (i = 0; i < numlines; i++)
+	{
+		switch (lines[i].special)
+		{
+		case 100: // Scroll_Texture_Left
+		case 101: // Scroll_Texture_Right
+		case 102: // Scroll_Texture_Up
+		case 103: // Scroll_Texture_Down
+			linespeciallist[numlinespecials] = &lines[i];
+			numlinespecials++;
+			break;
+		case 121: // Line_SetIdentification
+			if (lines[i].arg1)
+			{
+				if (TaggedLineCount == MAX_TAGGED_LINES)
+				{
+					I_Error("P_SpawnSpecials: MAX_TAGGED_LINES "
+						"(%d) exceeded.", MAX_TAGGED_LINES);
+				}
+				TaggedLines[TaggedLineCount].line = &lines[i];
+				TaggedLines[TaggedLineCount++].lineTag = lines[i].arg1;
+			}
+			lines[i].special = 0;
+			break;
+		}
+	}
+
+	//
+	// Init other misc stuff
+	//
+	for (i = 0; i < MAXCEILINGS; i++)
+		activeceilings[i] = NULL;
+	for (i = 0; i < MAXPLATS; i++)
+		activeplats[i] = NULL;
+	for (i = 0; i < MAXBUTTONS; i++)
+		memset(&buttonlist[i], 0, sizeof(button_t));
+
+	// Initialize flat and texture animations
+	P_InitFTAnims();
+}
+
+//==========================================================================
+//
+// P_FindLine
+//
+//==========================================================================
+
+line_t *P_FindLine(int lineTag, int *searchPosition)
+{
+	int i;
+
+	for (i = *searchPosition + 1; i < TaggedLineCount; i++)
+	{
+		if (TaggedLines[i].lineTag == lineTag)
+		{
+			*searchPosition = i;
+			return TaggedLines[i].line;
+		}
+	}
+	*searchPosition = -1;
+	return NULL;
+}
+
--- /dev/null
+++ b/p_spec.h
@@ -1,0 +1,529 @@
+
+//**************************************************************************
+//**
+//** p_spec.h : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 491 $
+//** $Date: 2009-05-30 01:10:42 +0300 (Sat, 30 May 2009) $
+//**
+//**************************************************************************
+
+#ifndef __P_SPEC__
+#define __P_SPEC__
+
+extern	int		*TerrainTypes;
+
+
+/* scrolling line specials */
+
+#define MAXLINEANIMS		64
+
+extern	short		numlinespecials;
+extern	line_t		*linespeciallist[MAXLINEANIMS];
+
+/* Define values for map objects */
+#define MO_TELEPORTMAN		14
+
+/* at game start */
+void P_InitTerrainTypes(void);
+void P_InitLava(void);
+
+/* at map load */
+void P_SpawnSpecials(void);
+
+/* every tic */
+void P_UpdateSpecials(void);
+
+/* when needed */
+boolean P_ExecuteLineSpecial(int special, byte *args, line_t *line, int side, mobj_t *mo);
+boolean P_ActivateLine(line_t *ld, mobj_t *mo, int side, int activationType);
+/*
+boolean P_UseSpecialLine ( mobj_t *thing, line_t *line);
+void P_ShootSpecialLine ( mobj_t *thing, line_t *line);
+void P_CrossSpecialLine (int linenum, int side, mobj_t *thing);
+*/
+
+void P_PlayerInSpecialSector(player_t *player);
+void P_PlayerOnSpecialFlat(player_t *player, int floorType);
+
+/*
+int twoSided(int sector,int line);
+sector_t *getSector(int currentSector,int line,int side);
+side_t *getSide(int currentSector,int line, int side);
+*/
+fixed_t P_FindLowestFloorSurrounding(sector_t *sec);
+fixed_t P_FindHighestFloorSurrounding(sector_t *sec);
+fixed_t P_FindNextHighestFloor(sector_t *sec,int currentheight);
+fixed_t P_FindLowestCeilingSurrounding(sector_t *sec);
+fixed_t P_FindHighestCeilingSurrounding(sector_t *sec);
+int P_FindSectorFromTag(int tag, int start);
+/*
+int P_FindSectorFromLineTag(line_t  *line,int start);
+int P_FindMinSurroundingLight(sector_t *sector,int max);
+*/
+sector_t *getNextSector(line_t *line,sector_t *sec);
+line_t *P_FindLine(int lineTag, int *searchPosition);
+
+
+/* ---- SPECIAL ---- */
+
+/*
+int EV_DoDonut(line_t *line);
+*/
+
+
+/* ---- P_anim.c ---- */
+
+void P_AnimateSurfaces(void);
+void P_InitFTAnims(void);
+void P_InitLightning(void);
+void P_ForceLightning(void);
+
+
+/* ---- P_LIGHTS ---- */
+
+typedef enum
+{
+	LITE_RAISEBYVALUE,
+	LITE_LOWERBYVALUE,
+	LITE_CHANGETOVALUE,
+	LITE_FADE,
+	LITE_GLOW,
+	LITE_FLICKER,
+	LITE_STROBE
+} lighttype_t;
+
+typedef struct
+{
+	thinker_t	thinker;
+	sector_t	*sector;
+	lighttype_t	type;
+	int		value1;
+	int		value2;
+	int		tics1;
+	int		tics2;
+	int		count;
+} light_t;
+
+typedef struct
+{
+	thinker_t	thinker;
+	sector_t	*sector;
+	int		index;
+	int		base;
+} phase_t;
+
+#define LIGHT_SEQUENCE_START	2
+#define LIGHT_SEQUENCE		3
+#define LIGHT_SEQUENCE_ALT	4
+
+void T_Phase(phase_t *phase);
+void T_Light(light_t *light);
+void P_SpawnPhasedLight(sector_t *sector, int base, int idx);
+void P_SpawnLightSequence(sector_t *sector, int indexStep);
+boolean EV_SpawnLight(line_t *line, byte *arg, lighttype_t type);
+
+#if 0
+typedef struct
+{
+	thinker_t	thinker;
+	sector_t	*sector;
+	int		count;
+	int		maxlight;
+	int		minlight;
+	int		maxtime;
+	int		mintime;
+} lightflash_t;
+
+typedef struct
+{
+	thinker_t	thinker;
+	sector_t	*sector;
+	int		count;
+	int		minlight;
+	int		maxlight;
+	int		darktime;
+	int		brighttime;
+} strobe_t;
+
+typedef struct
+{
+	thinker_t	thinker;
+	sector_t	*sector;
+	int		minlight;
+	int		maxlight;
+	int		direction;
+} glow_t;
+
+#define GLOWSPEED		8
+#define STROBEBRIGHT		5
+#define FASTDARK		15
+#define SLOWDARK		35
+
+void T_LightFlash (lightflash_t *flash);
+void P_SpawnLightFlash (sector_t *sector);
+void T_StrobeFlash (strobe_t *flash);
+void P_SpawnStrobeFlash (sector_t *sector, int fastOrSlow, int inSync);
+void EV_StartLightStrobing(line_t *line);
+void EV_TurnTagLightsOff(line_t *line);
+void EV_LightTurnOn(line_t *line, int bright);
+void T_Glow(glow_t *g);
+void P_SpawnGlowingLight(sector_t *sector);
+void T_Phase(phase_t *phase);
+void P_SpawnPhasedLight(sector_t *sector, int base, int idx);
+void P_SpawnLightSequence(sector_t *sector, int indexStep);
+#endif
+
+
+/* ---- P_SWITCH ---- */
+
+typedef struct
+{
+	const char	name1[9];
+	const char	name2[9];
+	int		soundID;
+} switchlist_t;
+
+typedef enum
+{
+	SWTCH_TOP,
+	SWTCH_MIDDLE,
+	SWTCH_BOTTOM
+} bwhere_e;
+
+typedef struct
+{
+	line_t		*line;
+	bwhere_e	where;
+	int		btexture;
+	int		btimer;
+	mobj_t		*soundorg;
+} button_t;
+
+#define MAXSWITCHES	50	/* max # of wall switches in a level */
+#define MAXBUTTONS	16	/* 4 players, 4 buttons each at once, max. */
+#define BUTTONTIME	35	/* 1 second */
+
+extern	button_t	buttonlist[MAXBUTTONS];
+
+void P_ChangeSwitchTexture(line_t *line, int useAgain);
+void P_InitSwitchList(void);
+
+
+/* ---- P_PLATS ---- */
+
+typedef enum
+{
+	PLAT_UP,
+	PLAT_DOWN,
+	PLAT_WAITING,
+	/*
+	PLAT_IN_STASIS
+	*/
+} plat_e;
+
+typedef enum
+{
+	PLAT_PERPETUALRAISE,
+	PLAT_DOWNWAITUPSTAY,
+	PLAT_DOWNBYVALUEWAITUPSTAY,
+	PLAT_UPWAITDOWNSTAY,
+	PLAT_UPBYVALUEWAITDOWNSTAY,
+	/*
+	PLAT_RAISEANDCHANGE,
+	PLAT_RAISETONEARESTANDCHANGE
+	*/
+} plattype_e;
+
+typedef struct
+{
+	thinker_t	thinker;
+	sector_t	*sector;
+	fixed_t		speed;
+	fixed_t		low;
+	fixed_t		high;
+	int		wait;
+	int		count;
+	plat_e		status;
+	plat_e		oldstatus;
+	int		crush;
+	int		tag;
+	plattype_e	type;
+} plat_t;
+
+#define PLATWAIT	3
+#define PLATSPEED	FRACUNIT
+#define MAXPLATS	30
+
+extern	plat_t		*activeplats[MAXPLATS];
+
+void T_PlatRaise(plat_t *plat);
+int EV_DoPlat(line_t *line, byte *args, plattype_e type, int amount);
+void P_AddActivePlat(plat_t *plat);
+void P_RemoveActivePlat(plat_t *plat);
+void EV_StopPlat(line_t *line, byte *args);
+
+
+/* ---- P_DOORS ---- */
+
+typedef enum
+{
+	DREV_NORMAL,
+	DREV_CLOSE30THENOPEN,
+	DREV_CLOSE,
+	DREV_OPEN,
+	DREV_RAISEIN5MINS
+} vldoor_e;
+
+typedef struct
+{
+	thinker_t	thinker;
+	sector_t	*sector;
+	vldoor_e	type;
+	fixed_t		topheight;
+	fixed_t		speed;
+	int		direction;	/* 1 = up, 0 = waiting at top, -1 = down */
+	int		topwait;	/* tics to wait at the top (keep in case a door going down is reset) */
+	int		topcountdown;	/* when it reaches 0, start going down */
+} vldoor_t;
+
+#define VDOORSPEED	(FRACUNIT * 2)
+#define VDOORWAIT	150
+
+boolean EV_VerticalDoor(line_t *line, mobj_t *thing);
+int EV_DoDoor(line_t *line, byte *args, vldoor_e type);
+void T_VerticalDoor(vldoor_t *door);
+/*
+void P_SpawnDoorCloseIn30(sector_t *sec);
+void P_SpawnDoorRaiseIn5Mins(sector_t *sec, int secnum);
+*/
+
+
+/* ---- P_CEILNG ---- */
+
+typedef enum
+{
+	CLEV_LOWERTOFLOOR,
+	CLEV_RAISETOHIGHEST,
+	CLEV_LOWERANDCRUSH,
+	CLEV_CRUSHANDRAISE,
+	CLEV_LOWERBYVALUE,
+	CLEV_RAISEBYVALUE,
+	CLEV_CRUSHRAISEANDSTAY,
+	CLEV_MOVETOVALUETIMES8
+} ceiling_e;
+
+typedef struct
+{
+	thinker_t	thinker;
+	sector_t	*sector;
+	ceiling_e	type;
+	fixed_t		bottomheight, topheight;
+	fixed_t		speed;
+	int		crush;
+	int		direction;	/* 1 = up, 0 = waiting, -1 = down */
+	int		tag;		/* ID */
+	int		olddirection;
+} ceiling_t;
+
+#define CEILSPEED	FRACUNIT
+#define CEILWAIT	150
+#define MAXCEILINGS	30
+
+extern	ceiling_t	*activeceilings[MAXCEILINGS];
+
+int EV_DoCeiling(line_t *line, byte *args, ceiling_e type);
+void T_MoveCeiling(ceiling_t *ceiling);
+void P_AddActiveCeiling(ceiling_t *c);
+void P_RemoveActiveCeiling(ceiling_t *c);
+int EV_CeilingCrushStop(line_t *line, byte *args);
+
+
+/* ---- P_FLOOR ---- */
+
+typedef enum
+{
+	FLEV_LOWERFLOOR,		/* lower floor to highest surrounding floor */
+	FLEV_LOWERFLOORTOLOWEST,	/* lower floor to lowest surrounding floor */
+	FLEV_LOWERFLOORBYVALUE,
+	FLEV_RAISEFLOOR,		/* raise floor to lowest surrounding CEILING */
+	FLEV_RAISEFLOORTONEAREST,	/* raise floor to next highest surrounding floor */
+	FLEV_RAISEFLOORBYVALUE,
+	FLEV_RAISEFLOORCRUSH,
+	FLEV_RAISEBUILDSTEP,		/* One step of a staircase */
+	FLEV_RAISEBYVALUETIMES8,
+	FLEV_LOWERBYVALUETIMES8,
+	FLEV_LOWERTIMES8INSTANT,
+	FLEV_RAISETIMES8INSTANT,
+	FLEV_MOVETOVALUETIMES8
+} floor_e;
+
+typedef struct
+{
+	thinker_t	thinker;
+	sector_t	*sector;
+	floor_e		type;
+	int		crush;
+	int		direction;
+	int		newspecial;
+	short		texture;
+	fixed_t		floordestheight;
+	fixed_t		speed;
+	int		delayCount;
+	int		delayTotal;
+	fixed_t		stairsDelayHeight;
+	fixed_t		stairsDelayHeightDelta;
+	fixed_t		resetHeight;
+	short		resetDelay;
+	short		resetDelayCount;
+	byte		textureChange;
+} floormove_t;
+
+typedef struct
+{
+	thinker_t	thinker;
+	sector_t	*sector;
+	int		ceilingSpeed;
+	int		floorSpeed;
+	int		floordest;
+	int		ceilingdest;
+	int		direction;
+	int		crush;
+} pillar_t;
+
+typedef struct
+{
+	thinker_t	thinker;
+	sector_t	*sector;
+	fixed_t		originalHeight;
+	fixed_t		accumulator;
+	fixed_t		accDelta;
+	fixed_t		targetScale;
+	fixed_t		scale;
+	fixed_t		scaleDelta;
+	int		ticker;
+	int		state;
+} floorWaggle_t;
+
+#define FLOORSPEED	FRACUNIT
+
+typedef enum
+{
+	RES_OK,
+	RES_CRUSHED,
+	RES_PASTDEST
+} result_e;
+
+typedef enum
+{
+	STAIRS_NORMAL,
+	STAIRS_SYNC,
+	STAIRS_PHASED
+} stairs_e;
+
+result_e T_MovePlane(sector_t *sector, fixed_t speed,
+			fixed_t dest, int crush, int floorOrCeiling, int direction);
+
+int EV_BuildStairs(line_t *line, byte *args, int direction, stairs_e type);
+int EV_DoFloor(line_t *line, byte *args, floor_e floortype);
+void T_MoveFloor(floormove_t *floor);
+void T_BuildPillar(pillar_t *pillar);
+void T_FloorWaggle(floorWaggle_t *waggle);
+int EV_BuildPillar(line_t *line, byte *args, boolean crush);
+int EV_OpenPillar(line_t *line, byte *args);
+int EV_DoFloorAndCeiling(line_t *line, byte *args, boolean raise);
+int EV_FloorCrushStop(line_t *line, byte *args);
+boolean EV_StartFloorWaggle(int tag, int height, int speed, int offset, int timer);
+
+
+/* ---- p_telept ---- */
+
+boolean P_Teleport(mobj_t *thing, fixed_t x, fixed_t y, angle_t angle, boolean useFog);
+boolean EV_Teleport(int tid, mobj_t *thing, boolean fog);
+
+
+/* ---- p_acs ---- */
+
+#define MAX_ACS_SCRIPT_VARS	10
+#define MAX_ACS_MAP_VARS	32
+#define MAX_ACS_WORLD_VARS	64
+#define ACS_STACK_DEPTH		32
+#define MAX_ACS_STORE		20
+
+typedef enum
+{
+	ASTE_INACTIVE,
+	ASTE_RUNNING,
+	ASTE_SUSPENDED,
+	ASTE_WAITINGFORTAG,
+	ASTE_WAITINGFORPOLY,
+	ASTE_WAITINGFORSCRIPT,
+	ASTE_TERMINATING
+} aste_t;
+
+typedef struct acs_s acs_t;
+typedef struct acsInfo_s acsInfo_t;
+
+struct acsInfo_s
+{
+	int		number;
+	byte		*address;
+	int		argCount;
+	aste_t		state;
+	int		waitValue;
+};
+
+struct acs_s
+{
+	thinker_t	thinker;
+	mobj_t		*activator;
+	line_t		*line;
+	int		side;
+	int		number;
+	int		infoIndex;
+	int		delayCount;
+	int		stack[ACS_STACK_DEPTH];
+	int		stackPtr;
+	int		vars[MAX_ACS_SCRIPT_VARS];
+	byte		*ip;
+};
+
+typedef struct
+{
+	int		map;		/* Target map */
+	int		script;		/* Script number on target map */
+	byte		args[4];	/* Padded to 4 for alignment */
+} acsstore_t;
+
+void P_LoadACScripts(int lump);
+boolean P_StartACS(int number, int map, byte *args, mobj_t *activator, line_t *line, int side);
+boolean P_StartLockedACS(line_t *line, byte *args, mobj_t *mo, int side);
+boolean P_TerminateACS(int number, int map);
+boolean P_SuspendACS(int number, int map);
+void T_InterpretACS(acs_t *script);
+void P_TagFinished(int tag);
+void P_PolyobjFinished(int po);
+void P_ACSInitNewGame(void);
+void P_CheckACSStore(void);
+
+extern	int		ACScriptCount;
+extern	byte		*ActionCodeBase;
+extern	acsInfo_t	*ACSInfo;
+extern	int		MapVars[MAX_ACS_MAP_VARS];
+extern	int		WorldVars[MAX_ACS_WORLD_VARS];
+extern	acsstore_t	ACSStore[MAX_ACS_STORE + 1];	/* +1 for termination marker */
+
+
+/* ---- p_things ---- */
+
+extern	mobjtype_t	TranslateThingType[];
+
+boolean EV_ThingProjectile(byte *args, boolean gravity);
+boolean EV_ThingSpawn(byte *args, boolean fog);
+boolean EV_ThingActivate(int tid);
+boolean EV_ThingDeactivate(int tid);
+boolean EV_ThingRemove(int tid);
+boolean EV_ThingDestroy(int tid);
+
+#endif	/* __P_SPEC__ */
+
--- /dev/null
+++ b/p_switch.c
@@ -1,0 +1,166 @@
+
+//**************************************************************************
+//**
+//** p_switch.c : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 491 $
+//** $Date: 2009-05-30 01:10:42 +0300 (Sat, 30 May 2009) $
+//**
+//**************************************************************************
+
+#include "h2stdinc.h"
+#include "h2def.h"
+#include "p_local.h"
+#include "soundst.h"
+
+//==================================================================
+//
+//      CHANGE THE TEXTURE OF A WALL SWITCH TO ITS OPPOSITE
+//
+//==================================================================
+
+static switchlist_t alphSwitchListDemo[] =
+{
+	{ "SW_1_UP", "SW_1_DN", SFX_SWITCH1 },
+	{ "SW_2_UP", "SW_2_DN", SFX_SWITCH1 },
+	{ "SW52_OFF", "SW52_ON", SFX_SWITCH2 },
+	{ "\0", "\0", 0}
+};
+
+static switchlist_t alphSwitchListFull[] =
+{
+	{ "SW_1_UP", "SW_1_DN", SFX_SWITCH1 },
+	{ "SW_2_UP", "SW_2_DN", SFX_SWITCH1 },
+	{ "VALVE1", "VALVE2", SFX_VALVE_TURN },
+	{ "SW51_OFF", "SW51_ON", SFX_SWITCH2 },
+	{ "SW52_OFF", "SW52_ON", SFX_SWITCH2 },
+	{ "SW53_UP", "SW53_DN", SFX_ROPE_PULL },
+	{ "PUZZLE5", "PUZZLE9", SFX_SWITCH1 },
+	{ "PUZZLE6", "PUZZLE10", SFX_SWITCH1 },
+	{ "PUZZLE7", "PUZZLE11", SFX_SWITCH1 },
+	{ "PUZZLE8", "PUZZLE12", SFX_SWITCH1 },
+	{ "\0", "\0", 0}
+};
+
+static switchlist_t *alphSwitchList = NULL;
+
+static int switchlist[MAXSWITCHES * 2];
+static int numswitches;
+
+button_t	buttonlist[MAXBUTTONS];
+
+
+/*
+===============
+=
+= P_InitSwitchList
+=
+= Only called at game initialization
+=
+===============
+*/
+
+void P_InitSwitchList(void)
+{
+	int		i;
+	int		idx;
+
+	if (alphSwitchList == NULL)
+	{
+		alphSwitchList = (shareware && oldwad_10) ? alphSwitchListDemo : alphSwitchListFull;
+	}
+
+	for (idx = 0, i = 0; i < MAXSWITCHES; i++)
+	{
+		if (!alphSwitchList[i].soundID)
+		{
+			numswitches = idx/2;
+			switchlist[idx] = -1;
+			break;
+		}
+		switchlist[idx++] = R_TextureNumForName(alphSwitchList[i].name1);
+		switchlist[idx++] = R_TextureNumForName(alphSwitchList[i].name2);
+	}
+}
+
+//==================================================================
+//
+// Start a button counting down till it turns off.
+//
+//==================================================================
+
+void P_StartButton(line_t *line, bwhere_e w, int texture, int timer)
+{
+	int		i;
+
+	for (i = 0;i < MAXBUTTONS;i++)
+	{
+		if (!buttonlist[i].btimer)
+		{
+			buttonlist[i].line = line;
+			buttonlist[i].where = w;
+			buttonlist[i].btexture = texture;
+			buttonlist[i].btimer = timer;
+			buttonlist[i].soundorg = (mobj_t *)(void *)&line->frontsector->soundorg;
+			return;
+		}
+	}
+	I_Error("P_StartButton: no button slots left!");
+}
+
+//==================================================================
+//
+// Function that changes wall texture.
+// Tell it if switch is ok to use again (1=yes, it's a button).
+//
+//==================================================================
+
+void P_ChangeSwitchTexture(line_t *line, int useAgain)
+{
+	int	texTop;
+	int	texMid;
+	int	texBot;
+	int	i;
+
+	texTop = sides[line->sidenum[0]].toptexture;
+	texMid = sides[line->sidenum[0]].midtexture;
+	texBot = sides[line->sidenum[0]].bottomtexture;
+
+	for (i = 0; i < numswitches*2; i++)
+	{
+		if (switchlist[i] == texTop)
+		{
+			S_StartSound((mobj_t *)(void *)&line->frontsector->soundorg,
+							alphSwitchList[i/2].soundID);
+			sides[line->sidenum[0]].toptexture = switchlist[i^1];
+			if (useAgain)
+			{
+				P_StartButton(line, SWTCH_TOP, switchlist[i], BUTTONTIME);
+			}
+			return;
+		}
+		else if (switchlist[i] == texMid)
+		{
+			S_StartSound((mobj_t *)(void *)&line->frontsector->soundorg,
+							alphSwitchList[i/2].soundID);
+			sides[line->sidenum[0]].midtexture = switchlist[i^1];
+			if (useAgain)
+			{
+				P_StartButton(line, SWTCH_MIDDLE, switchlist[i], BUTTONTIME);
+			}
+			return;
+		}
+		else if (switchlist[i] == texBot)
+		{
+			S_StartSound((mobj_t *)(void *)&line->frontsector->soundorg,
+							alphSwitchList[i/2].soundID);
+			sides[line->sidenum[0]].bottomtexture = switchlist[i^1];
+			if (useAgain)
+			{
+				P_StartButton(line, SWTCH_BOTTOM, switchlist[i], BUTTONTIME);
+			}
+			return;
+		}
+	}
+}
+
--- /dev/null
+++ b/p_telept.c
@@ -1,0 +1,177 @@
+
+//**************************************************************************
+//**
+//** p_telept.c : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 373 $
+//** $Date: 2009-05-19 21:14:28 +0300 (Tue, 19 May 2009) $
+//**
+//**************************************************************************
+
+// HEADER FILES ------------------------------------------------------------
+
+#include "h2stdinc.h"
+#include "h2def.h"
+#include "p_local.h"
+#include "soundst.h"
+
+// MACROS ------------------------------------------------------------------
+
+// TYPES -------------------------------------------------------------------
+
+// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
+
+// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
+
+// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
+
+// EXTERNAL DATA DECLARATIONS ----------------------------------------------
+
+// PUBLIC DATA DEFINITIONS -------------------------------------------------
+
+// PRIVATE DATA DEFINITIONS ------------------------------------------------
+
+// CODE --------------------------------------------------------------------
+
+//==========================================================================
+//
+// P_Teleport
+//
+//==========================================================================
+
+boolean P_Teleport(mobj_t *thing, fixed_t x, fixed_t y, angle_t angle,
+							boolean useFog)
+{
+	fixed_t oldx;
+	fixed_t oldy;
+	fixed_t oldz;
+	fixed_t aboveFloor;
+	fixed_t fogDelta;
+	player_t *player;
+	unsigned int an;
+	mobj_t *fog;
+
+	oldx = thing->x;
+	oldy = thing->y;
+	oldz = thing->z;
+	aboveFloor = thing->z - thing->floorz;
+	if (!P_TeleportMove(thing, x, y))
+	{
+		return false;
+	}
+	if (thing->player)
+	{
+		player = thing->player;
+		if (player->powers[pw_flight] && aboveFloor)
+		{
+			thing->z = thing->floorz+aboveFloor;
+			if (thing->z + thing->height > thing->ceilingz)
+			{
+				thing->z = thing->ceilingz - thing->height;
+			}
+			player->viewz = thing->z + player->viewheight;
+		}
+		else
+		{
+			thing->z = thing->floorz;
+			player->viewz = thing->z + player->viewheight;
+			if (useFog)
+			{
+				player->lookdir = 0;
+			}
+		}
+	}
+	else if (thing->flags & MF_MISSILE)
+	{
+		thing->z = thing->floorz + aboveFloor;
+		if (thing->z + thing->height > thing->ceilingz)
+		{
+			thing->z = thing->ceilingz - thing->height;
+		}
+	}
+	else
+	{
+		thing->z = thing->floorz;
+	}
+	// Spawn teleport fog at source and destination
+	if (useFog)
+	{
+		fogDelta = (thing->flags & MF_MISSILE) ? 0 : TELEFOGHEIGHT;
+		fog = P_SpawnMobj(oldx, oldy, oldz + fogDelta, MT_TFOG);
+		S_StartSound(fog, SFX_TELEPORT);
+		an = angle >> ANGLETOFINESHIFT;
+		fog = P_SpawnMobj(x + 20*finecosine[an], y + 20*finesine[an], thing->z + fogDelta, MT_TFOG);
+		S_StartSound(fog, SFX_TELEPORT);
+		if (thing->player && !thing->player->powers[pw_speed])
+		{ // Freeze player for about .5 sec
+			thing->reactiontime = 18;
+		}
+		thing->angle = angle;
+	}
+	if (thing->flags2 & MF2_FLOORCLIP)
+	{
+		if (thing->z == thing->subsector->sector->floorheight 
+			&& P_GetThingFloorType(thing) > FLOOR_SOLID)
+		{
+			thing->floorclip = 10*FRACUNIT;
+		}
+		else
+		{
+			thing->floorclip = 0;
+		}
+	}
+	if (thing->flags & MF_MISSILE)
+	{
+		angle >>= ANGLETOFINESHIFT;
+		thing->momx = FixedMul(thing->info->speed, finecosine[angle]);
+		thing->momy = FixedMul(thing->info->speed, finesine[angle]);
+	}
+	else if (useFog) // no fog doesn't alter the player's momentums
+	{
+		thing->momx = thing->momy = thing->momz = 0;
+	}
+	return true;
+}
+
+//==========================================================================
+//
+// EV_Teleport
+//
+//==========================================================================
+
+boolean EV_Teleport(int tid, mobj_t *thing, boolean fog)
+{
+	int i;
+	int count;
+	mobj_t *mo = NULL;
+	int searcher;
+
+	if (!thing)
+	{ // Teleport function called with an invalid mobj
+		return false;
+	}
+	if (thing->flags2 & MF2_NOTELEPORT)
+	{
+		return false;
+	}
+	count = 0;
+	searcher = -1;
+	while (P_FindMobjFromTID(tid, &searcher) != NULL)
+	{
+		count++;
+	}
+	if (count == 0)
+	{
+		return false;
+	}
+	count = 1 + (P_Random() % count);
+	searcher = -1;
+	for (i = 0; i < count; i++)
+	{
+		mo = P_FindMobjFromTID(tid, &searcher);
+	}
+	if (!mo)
+		I_Error("Can't find teleport mapspot\n");
+	return P_Teleport(thing, mo->x, mo->y, mo->angle, fog);
+}
+
--- /dev/null
+++ b/p_things.c
@@ -1,0 +1,530 @@
+
+//**************************************************************************
+//**
+//** p_things.c : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 373 $
+//** $Date: 2009-05-19 21:14:28 +0300 (Tue, 19 May 2009) $
+//**
+//**************************************************************************
+
+// HEADER FILES ------------------------------------------------------------
+
+#include "h2stdinc.h"
+#include "h2def.h"
+#include "p_local.h"
+#include "soundst.h"
+
+// MACROS ------------------------------------------------------------------
+
+// TYPES -------------------------------------------------------------------
+
+// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
+
+// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
+
+// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
+
+static boolean ActivateThing(mobj_t *mobj);
+static boolean DeactivateThing(mobj_t *mobj);
+
+// EXTERNAL DATA DECLARATIONS ----------------------------------------------
+
+// PUBLIC DATA DEFINITIONS -------------------------------------------------
+
+mobjtype_t TranslateThingType[] =
+{
+	MT_MAPSPOT,		/* T_NONE		*/
+	MT_CENTAUR,		/* T_CENTAUR		*/
+	MT_CENTAURLEADER,	/* T_CENTAURLEADER	*/
+	MT_DEMON,		/* T_DEMON		*/
+	MT_ETTIN,		/* T_ETTIN		*/
+	MT_FIREDEMON,		/* T_FIREGARGOYLE	*/
+	MT_SERPENT,		/* T_WATERLURKER	*/
+	MT_SERPENTLEADER,	/* T_WATERLURKERLEADER	*/
+	MT_WRAITH,		/* T_WRAITH		*/
+	MT_WRAITHB,		/* T_WRAITHBURIED	*/
+	MT_FIREBALL1,		/* T_FIREBALL1		*/
+	MT_MANA1,		/* T_MANA1		*/
+	MT_MANA2,		/* T_MANA2		*/
+	MT_SPEEDBOOTS,		/* T_ITEMBOOTS		*/
+	MT_ARTIEGG,		/* T_ITEMEGG		*/
+	MT_ARTIFLY,		/* T_ITEMFLIGHT		*/
+	MT_SUMMONMAULATOR,	/* T_ITEMSUMMON		*/
+	MT_TELEPORTOTHER,	/* T_ITEMTPORTOTHER	*/
+	MT_ARTITELEPORT,	/* T_ITEMTELEPORT	*/
+	MT_BISHOP,		/* T_BISHOP		*/
+	MT_ICEGUY,		/* T_ICEGOLEM		*/
+	MT_BRIDGE,		/* T_BRIDGE		*/
+	MT_BOOSTARMOR,		/* T_DRAGONSKINBRACERS	*/
+	MT_HEALINGBOTTLE,	/* T_ITEMHEALTHPOTION	*/
+	MT_HEALTHFLASK,		/* T_ITEMHEALTHFLASK	*/
+	MT_ARTISUPERHEAL,	/* T_ITEMHEALTHFULL	*/
+	MT_BOOSTMANA,		/* T_ITEMBOOSTMANA	*/
+	MT_FW_AXE,		/* T_FIGHTERAXE		*/
+	MT_FW_HAMMER,		/* T_FIGHTERHAMMER	*/
+	MT_FW_SWORD1,		/* T_FIGHTERSWORD1	*/
+	MT_FW_SWORD2,		/* T_FIGHTERSWORD2	*/
+	MT_FW_SWORD3,		/* T_FIGHTERSWORD3	*/
+	MT_CW_SERPSTAFF,	/* T_CLERICSTAFF	*/
+	MT_CW_HOLY1,		/* T_CLERICHOLY1	*/
+	MT_CW_HOLY2,		/* T_CLERICHOLY2	*/
+	MT_CW_HOLY3,		/* T_CLERICHOLY3	*/
+	MT_MW_CONE,		/* T_MAGESHARDS		*/
+	MT_MW_STAFF1,		/* T_MAGESTAFF1		*/
+	MT_MW_STAFF2,		/* T_MAGESTAFF2		*/
+	MT_MW_STAFF3,		/* T_MAGESTAFF3		*/
+	MT_EGGFX,		/* T_MORPHBLAST		*/
+	MT_ROCK1,		/* T_ROCK1		*/
+	MT_ROCK2,		/* T_ROCK2		*/
+	MT_ROCK3,		/* T_ROCK3		*/
+	MT_DIRT1,		/* T_DIRT1		*/
+	MT_DIRT2,		/* T_DIRT2		*/
+	MT_DIRT3,		/* T_DIRT3		*/
+	MT_DIRT4,		/* T_DIRT4		*/
+	MT_DIRT5,		/* T_DIRT5		*/
+	MT_DIRT6,		/* T_DIRT6		*/
+	MT_ARROW,		/* T_ARROW		*/
+	MT_DART,		/* T_DART		*/
+	MT_POISONDART,		/* T_POISONDART		*/
+	MT_RIPPERBALL,		/* T_RIPPERBALL		*/
+	MT_SGSHARD1,		/* T_STAINEDGLASS1	*/
+	MT_SGSHARD2,		/* T_STAINEDGLASS2	*/
+	MT_SGSHARD3,		/* T_STAINEDGLASS3	*/
+	MT_SGSHARD4,		/* T_STAINEDGLASS4	*/
+	MT_SGSHARD5,		/* T_STAINEDGLASS5	*/
+	MT_SGSHARD6,		/* T_STAINEDGLASS6	*/
+	MT_SGSHARD7,		/* T_STAINEDGLASS7	*/
+	MT_SGSHARD8,		/* T_STAINEDGLASS8	*/
+	MT_SGSHARD9,		/* T_STAINEDGLASS9	*/
+	MT_SGSHARD0,		/* T_STAINEDGLASS0	*/
+	MT_PROJECTILE_BLADE,	/* T_BLADE		*/
+	MT_ICESHARD,		/* T_ICESHARD		*/
+	MT_FLAME_SMALL,		/* T_FLAME_SMALL	*/
+	MT_FLAME_LARGE,		/* T_FLAME_LARGE	*/
+	MT_ARMOR_1,		/* T_MESHARMOR		*/
+	MT_ARMOR_2,		/* T_FALCONSHIELD	*/
+	MT_ARMOR_3,		/* T_PLATINUMHELM	*/
+	MT_ARMOR_4,		/* T_AMULETOFWARDING	*/
+	MT_ARTIPOISONBAG,	/* T_ITEMFLECHETTE	*/
+	MT_ARTITORCH,		/* T_ITEMTORCH		*/
+	MT_BLASTRADIUS,		/* T_ITEMREPULSION	*/
+	MT_MANA3,		/* T_MANA3		*/
+	MT_ARTIPUZZSKULL,	/* T_PUZZSKULL		*/
+	MT_ARTIPUZZGEMBIG,	/* T_PUZZGEMBIG		*/
+	MT_ARTIPUZZGEMRED,	/* T_PUZZGEMRED		*/
+	MT_ARTIPUZZGEMGREEN1,	/* T_PUZZGEMGREEN1	*/
+	MT_ARTIPUZZGEMGREEN2,	/* T_PUZZGEMGREEN2	*/
+	MT_ARTIPUZZGEMBLUE1,	/* T_PUZZGEMBLUE1	*/
+	MT_ARTIPUZZGEMBLUE2,	/* T_PUZZGEMBLUE2	*/
+	MT_ARTIPUZZBOOK1,	/* T_PUZZBOOK1		*/
+	MT_ARTIPUZZBOOK2,	/* T_PUZZBOOK2		*/
+	MT_KEY1,		/* T_METALKEY		*/
+	MT_KEY2,		/* T_SMALLMETALKEY	*/
+	MT_KEY3,		/* T_AXEKEY		*/
+	MT_KEY4,		/* T_FIREKEY		*/
+	MT_KEY5,		/* T_GREENKEY		*/
+	MT_KEY6,		/* T_MACEKEY		*/
+	MT_KEY7,		/* T_SILVERKEY		*/
+	MT_KEY8,		/* T_RUSTYKEY		*/
+	MT_KEY9,		/* T_HORNKEY		*/
+	MT_KEYA,		/* T_SERPENTKEY		*/
+	MT_WATER_DRIP,		/* T_WATERDRIP		*/
+	MT_FLAME_SMALL_TEMP,	/* T_TEMPSMALLFLAME	*/
+	MT_FLAME_SMALL,		/* T_PERMSMALLFLAME	*/
+	MT_FLAME_LARGE_TEMP,	/* T_TEMPLARGEFLAME	*/
+	MT_FLAME_LARGE,		/* T_PERMLARGEFLAME	*/
+	MT_DEMON_MASH,		/* T_DEMON_MASH		*/
+	MT_DEMON2_MASH,		/* T_DEMON2_MASH	*/
+	MT_ETTIN_MASH,		/* T_ETTIN_MASH		*/
+	MT_CENTAUR_MASH,	/* T_CENTAUR_MASH	*/
+	MT_THRUSTFLOOR_UP,	/* T_THRUSTSPIKEUP	*/
+	MT_THRUSTFLOOR_DOWN,	/* T_THRUSTSPIKEDOWN	*/
+	MT_WRAITHFX4,		/* T_FLESH_DRIP1	*/
+	MT_WRAITHFX5,		/* T_FLESH_DRIP2	*/
+	MT_WRAITHFX2		/* T_SPARK_DRIP		*/
+};
+
+// PRIVATE DATA DEFINITIONS ------------------------------------------------
+
+// CODE --------------------------------------------------------------------
+
+//==========================================================================
+//
+// EV_ThingProjectile
+//
+//==========================================================================
+
+boolean EV_ThingProjectile(byte *args, boolean gravity)
+{
+	int tid;
+	angle_t angle;
+	int fineAngle;
+	fixed_t speed;
+	fixed_t vspeed;
+	mobjtype_t moType;
+	mobj_t *mobj;
+	mobj_t *newMobj;
+	int searcher;
+	boolean success;
+
+	success = false;
+	searcher = -1;
+	tid = args[0];
+	moType = TranslateThingType[args[1]];
+	if (nomonsters && (mobjinfo[moType].flags & MF_COUNTKILL))
+	{ // Don't spawn monsters if -nomonsters
+		return false;
+	}
+	angle = (int)args[2]<<24;
+	fineAngle = angle>>ANGLETOFINESHIFT;
+	speed = (int)args[3]<<13;
+	vspeed = (int)args[4]<<13;
+	while ((mobj = P_FindMobjFromTID(tid, &searcher)) != NULL)
+	{
+		newMobj = P_SpawnMobj(mobj->x, mobj->y, mobj->z, moType);
+		if (newMobj->info->seesound)
+		{
+			S_StartSound(newMobj, newMobj->info->seesound);
+		}
+		newMobj->target = mobj; // Originator
+		newMobj->angle = angle;
+		newMobj->momx = FixedMul(speed, finecosine[fineAngle]);
+		newMobj->momy = FixedMul(speed, finesine[fineAngle]);
+		newMobj->momz = vspeed;
+		newMobj->flags2 |= MF2_DROPPED; // Don't respawn
+		if (gravity == true)
+		{
+			newMobj->flags &= ~MF_NOGRAVITY;
+			newMobj->flags2 |= MF2_LOGRAV;
+		}
+		if (P_CheckMissileSpawn(newMobj) == true)
+		{
+			success = true;
+		}
+	}
+	return success;
+}
+
+//==========================================================================
+//
+// EV_ThingSpawn
+//
+//==========================================================================
+
+boolean EV_ThingSpawn(byte *args, boolean fog)
+{
+	int tid;
+	angle_t angle;
+	mobj_t *mobj;
+	mobj_t *newMobj;
+	mobj_t *fogMobj;
+	mobjtype_t moType;
+	int searcher;
+	boolean success;
+	fixed_t z;
+
+	success = false;
+	searcher = -1;
+	tid = args[0];
+	moType = TranslateThingType[args[1]];
+	if (nomonsters && (mobjinfo[moType].flags & MF_COUNTKILL))
+	{ // Don't spawn monsters if -nomonsters
+		return false;
+	}
+	angle = (int)args[2]<<24;
+	while ((mobj = P_FindMobjFromTID(tid, &searcher)) != NULL)
+	{
+		if (mobjinfo[moType].flags2 & MF2_FLOATBOB)
+		{
+			z = mobj->z - mobj->floorz;
+		}
+		else
+		{
+			z = mobj->z;
+		}
+		newMobj = P_SpawnMobj(mobj->x, mobj->y, z, moType);
+		if (P_TestMobjLocation(newMobj) == false)
+		{ // Didn't fit
+			P_RemoveMobj(newMobj);
+		}
+		else
+		{
+			newMobj->angle = angle;
+			if (fog == true)
+			{
+				fogMobj = P_SpawnMobj(mobj->x, mobj->y, mobj->z + TELEFOGHEIGHT, MT_TFOG);
+				S_StartSound(fogMobj, SFX_TELEPORT);
+			}
+			newMobj->flags2 |= MF2_DROPPED; // Don't respawn
+			if (newMobj->flags2 & MF2_FLOATBOB)
+			{
+				newMobj->special1 = newMobj->z - newMobj->floorz;
+			}
+			success = true;
+		}
+	}
+	return success;
+}
+
+//==========================================================================
+//
+// EV_ThingActivate
+//
+//==========================================================================
+
+boolean EV_ThingActivate(int tid)
+{
+	mobj_t *mobj;
+	int searcher;
+	boolean success;
+
+	success = false;
+	searcher = -1;
+	while ((mobj = P_FindMobjFromTID(tid, &searcher)) != NULL)
+	{
+		if (ActivateThing(mobj) == true)
+		{
+			success = true;
+		}
+	}
+	return success;
+}
+
+//==========================================================================
+//
+// EV_ThingDeactivate
+//
+//==========================================================================
+
+boolean EV_ThingDeactivate(int tid)
+{
+	mobj_t *mobj;
+	int searcher;
+	boolean success;
+
+	success = false;
+	searcher = -1;
+	while ((mobj = P_FindMobjFromTID(tid, &searcher)) != NULL)
+	{
+		if (DeactivateThing(mobj) == true)
+		{
+			success = true;
+		}
+	}
+	return success;
+}
+
+//==========================================================================
+//
+// EV_ThingRemove
+//
+//==========================================================================
+
+boolean EV_ThingRemove(int tid)
+{
+	mobj_t *mobj;
+	int searcher;
+	boolean success;
+
+	success = false;
+	searcher = -1;
+	while ((mobj = P_FindMobjFromTID(tid, &searcher)) != NULL)
+	{
+		if (mobj->type == MT_BRIDGE)
+		{
+			A_BridgeRemove(mobj);
+			return true;
+		}
+		P_RemoveMobj(mobj);
+		success = true;
+	}
+	return success;
+}
+
+//==========================================================================
+//
+// EV_ThingDestroy
+//
+//==========================================================================
+
+boolean EV_ThingDestroy(int tid)
+{
+	mobj_t *mobj;
+	int searcher;
+	boolean success;
+
+	success = false;
+	searcher = -1;
+	while ((mobj = P_FindMobjFromTID(tid, &searcher)) != NULL)
+	{
+		if (mobj->flags & MF_SHOOTABLE)
+		{
+			P_DamageMobj(mobj, NULL, NULL, 10000);
+			success = true;
+		}
+	}
+	return success;
+}
+
+//==========================================================================
+//
+// EV_ThingMove
+//
+// arg[0] = tid
+// arg[1] = speed
+// arg[2] = angle (255 = use mobj angle)
+// arg[3] = distance (pixels>>2)
+//
+//==========================================================================
+
+/*
+boolean EV_ThingMove(byte *args)
+{
+	return false;
+}
+*/
+
+//==========================================================================
+//
+// ActivateThing
+//
+//==========================================================================
+
+static boolean ActivateThing(mobj_t *mobj)
+{
+	if (mobj->flags & MF_COUNTKILL)
+	{ // Monster
+		if (mobj->flags2 & MF2_DORMANT)
+		{
+			mobj->flags2 &= ~MF2_DORMANT;
+			mobj->tics = 1;
+			return true;
+		}
+		return false;
+	}
+	switch (mobj->type)
+	{
+	case MT_ZTWINEDTORCH:
+	case MT_ZTWINEDTORCH_UNLIT:
+		P_SetMobjState(mobj, S_ZTWINEDTORCH_1);
+		S_StartSound(mobj, SFX_IGNITE);
+		break;
+	case MT_ZWALLTORCH:
+	case MT_ZWALLTORCH_UNLIT:
+		P_SetMobjState(mobj, S_ZWALLTORCH1);
+		S_StartSound(mobj, SFX_IGNITE);
+		break;
+	case MT_ZGEMPEDESTAL:
+		P_SetMobjState(mobj, S_ZGEMPEDESTAL2);
+		break;
+	case MT_ZWINGEDSTATUENOSKULL:
+		P_SetMobjState(mobj, S_ZWINGEDSTATUENOSKULL2);
+		break;
+	case MT_THRUSTFLOOR_UP:
+	case MT_THRUSTFLOOR_DOWN:
+		if (mobj->args[0] == 0)
+		{
+			S_StartSound(mobj, SFX_THRUSTSPIKE_LOWER);
+			mobj->flags2 &= ~MF2_DONTDRAW;
+			if (mobj->args[1])
+				P_SetMobjState(mobj, S_BTHRUSTRAISE1);
+			else
+				P_SetMobjState(mobj, S_THRUSTRAISE1);
+		}
+		break;
+	case MT_ZFIREBULL:
+	case MT_ZFIREBULL_UNLIT:
+		P_SetMobjState(mobj, S_ZFIREBULL_BIRTH);
+		S_StartSound(mobj, SFX_IGNITE);
+		break;
+	case MT_ZBELL:
+		if (mobj->health > 0)
+		{
+			P_DamageMobj(mobj, NULL, NULL, 10); // 'ring' the bell
+		}
+		break;
+	case MT_ZCAULDRON:
+	case MT_ZCAULDRON_UNLIT:
+		P_SetMobjState(mobj, S_ZCAULDRON1);
+		S_StartSound(mobj, SFX_IGNITE);
+		break;
+	case MT_FLAME_SMALL:
+		S_StartSound(mobj, SFX_IGNITE);
+		P_SetMobjState(mobj, S_FLAME_SMALL1);
+		break;
+	case MT_FLAME_LARGE:
+		S_StartSound(mobj, SFX_IGNITE);
+		P_SetMobjState(mobj, S_FLAME_LARGE1);
+		break;
+	case MT_BAT_SPAWNER:
+		P_SetMobjState(mobj, S_SPAWNBATS1);
+		break;
+	default:
+		return false;
+	}
+	return true;
+}
+
+//==========================================================================
+//
+// DeactivateThing
+//
+//==========================================================================
+
+static boolean DeactivateThing(mobj_t *mobj)
+{
+	if (mobj->flags & MF_COUNTKILL)
+	{ // Monster
+		if (!(mobj->flags2 & MF2_DORMANT))
+		{
+			mobj->flags2 |= MF2_DORMANT;
+			mobj->tics = -1;
+			return true;
+		}
+		return false;
+	}
+	switch (mobj->type)
+	{
+	case MT_ZTWINEDTORCH:
+	case MT_ZTWINEDTORCH_UNLIT:
+		P_SetMobjState(mobj, S_ZTWINEDTORCH_UNLIT);
+		break;
+	case MT_ZWALLTORCH:
+	case MT_ZWALLTORCH_UNLIT:
+		P_SetMobjState(mobj, S_ZWALLTORCH_U);
+		break;
+	case MT_THRUSTFLOOR_UP:
+	case MT_THRUSTFLOOR_DOWN:
+		if (mobj->args[0] == 1)
+		{
+			S_StartSound(mobj, SFX_THRUSTSPIKE_RAISE);
+			if (mobj->args[1])
+				P_SetMobjState(mobj, S_BTHRUSTLOWER);
+			else
+				P_SetMobjState(mobj, S_THRUSTLOWER);
+		}
+		break;
+	case MT_ZFIREBULL:
+	case MT_ZFIREBULL_UNLIT:
+		P_SetMobjState(mobj, S_ZFIREBULL_DEATH);
+		break;
+	case MT_ZCAULDRON:
+	case MT_ZCAULDRON_UNLIT:
+		P_SetMobjState(mobj, S_ZCAULDRON_U);
+		break;
+	case MT_FLAME_SMALL:
+		P_SetMobjState(mobj, S_FLAME_SDORM1);
+		break;
+	case MT_FLAME_LARGE:
+		P_SetMobjState(mobj, S_FLAME_LDORM1);
+		break;
+	case MT_BAT_SPAWNER:
+		P_SetMobjState(mobj, S_SPAWNBATS_OFF);
+		break;
+	default:
+		return false;
+	}
+	return true;
+}
+
--- /dev/null
+++ b/p_tick.c
@@ -1,0 +1,142 @@
+
+//**************************************************************************
+//**
+//** p_tick.c : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 373 $
+//** $Date: 2009-05-19 21:14:28 +0300 (Tue, 19 May 2009) $
+//**
+//**************************************************************************
+
+// HEADER FILES ------------------------------------------------------------
+
+#include "h2stdinc.h"
+#include "h2def.h"
+#include "p_local.h"
+
+// MACROS ------------------------------------------------------------------
+
+// TYPES -------------------------------------------------------------------
+
+// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
+
+// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
+
+// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
+
+static void RunThinkers(void);
+
+// EXTERNAL DATA DECLARATIONS ----------------------------------------------
+
+// PUBLIC DATA DEFINITIONS -------------------------------------------------
+
+int leveltime;
+int TimerGame;
+thinker_t thinkercap;	/* The head and tail of the thinker list */
+
+// PRIVATE DATA DEFINITIONS ------------------------------------------------
+
+// CODE --------------------------------------------------------------------
+
+//==========================================================================
+//
+// P_Ticker
+//
+//==========================================================================
+
+void P_Ticker(void)
+{
+	int i;
+
+	if (paused)
+	{
+		return;
+	}
+	for (i = 0; i < MAXPLAYERS; i++)
+	{
+		if (playeringame[i])
+		{
+			P_PlayerThink(&players[i]);
+		}
+	}
+	if (TimerGame)
+	{
+		if (!--TimerGame)
+		{
+			G_Completed(P_TranslateMap(P_GetMapNextMap(gamemap)), 0);
+		}
+	}
+	RunThinkers();
+	P_UpdateSpecials();
+	P_AnimateSurfaces();
+	leveltime++;
+}
+
+//==========================================================================
+//
+// RunThinkers
+//
+//==========================================================================
+
+static void RunThinkers(void)
+{
+	thinker_t *currentthinker;
+
+	currentthinker = thinkercap.next;
+	while (currentthinker != &thinkercap)
+	{
+		if (currentthinker->function == (think_t)-1)
+		{ // Time to remove it
+			currentthinker->next->prev = currentthinker->prev;
+			currentthinker->prev->next = currentthinker->next;
+			Z_Free(currentthinker);
+		}
+		else if (currentthinker->function)
+		{
+			currentthinker->function(currentthinker);
+		}
+		currentthinker = currentthinker->next;
+	}
+}
+
+//==========================================================================
+//
+// P_InitThinkers
+//
+//==========================================================================
+
+void P_InitThinkers(void)
+{
+	thinkercap.prev = thinkercap.next  = &thinkercap;
+}
+
+//==========================================================================
+//
+// P_AddThinker
+//
+// Adds a new thinker at the end of the list.
+//
+//==========================================================================
+
+void P_AddThinker(thinker_t *thinker)
+{
+	thinkercap.prev->next = thinker;
+	thinker->next = &thinkercap;
+	thinker->prev = thinkercap.prev;
+	thinkercap.prev = thinker;
+}
+
+//==========================================================================
+//
+// P_RemoveThinker
+//
+// Deallocation is lazy -- it will not actually be freed until its
+// thinking turn comes up.
+//
+//==========================================================================
+
+void P_RemoveThinker(thinker_t *thinker)
+{
+	thinker->function = (think_t)-1;
+}
+
--- /dev/null
+++ b/p_user.c
@@ -1,0 +1,1690 @@
+
+//**************************************************************************
+//**
+//** p_user.c : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 458 $
+//** $Date: 2009-05-25 15:35:27 +0300 (Mon, 25 May 2009) $
+//**
+//**************************************************************************
+
+#include "h2stdinc.h"
+#include "h2def.h"
+#include "p_local.h"
+#include "soundst.h"
+#include "v_compat.h"	/* for the V_SetPaletteXXX() macros */
+
+// Macros
+
+#define MAXBOB		0x100000	/* 16 pixels of bob */
+
+// Extern Data
+
+extern int		inv_ptr;
+extern int		curpos;
+
+// Private Data
+
+static boolean		onground;
+static int		newtorch;	/* used in the torch flicker effect. */
+static int		newtorchdelta;
+
+// Global Data
+
+int PStateNormal[NUMCLASSES] =
+{
+	S_FPLAY,
+	S_CPLAY,
+	S_MPLAY,
+#ifdef ASSASSIN
+	S_APLAY,
+#endif
+	S_PIGPLAY
+};
+
+int PStateRun[NUMCLASSES] =
+{
+	S_FPLAY_RUN1,
+	S_CPLAY_RUN1,
+	S_MPLAY_RUN1,
+#ifdef ASSASSIN
+	S_APLAY_RUN1,
+#endif
+	S_PIGPLAY_RUN1
+};
+
+int PStateAttack[NUMCLASSES] =
+{
+	S_FPLAY_ATK1,
+	S_CPLAY_ATK1,
+	S_MPLAY_ATK1,
+#ifdef ASSASSIN
+	S_APLAY_ATK1,
+#endif
+	S_PIGPLAY_ATK1
+};
+
+int PStateAttackEnd[NUMCLASSES] =
+{
+	S_FPLAY_ATK2,
+	S_CPLAY_ATK3,
+	S_MPLAY_ATK2,
+#ifdef ASSASSIN
+	S_APLAY_ATK3,
+#endif
+	S_PIGPLAY_ATK1
+};
+
+int ArmorMax[NUMCLASSES] =
+{
+		20,
+		18,
+		16,
+#ifdef ASSASSIN
+		17,
+#endif
+		1
+};
+
+// Global Functions
+
+void P_PlayerNextArtifact(player_t *player);
+
+
+//==========================================================================
+
+
+/*
+==================
+=
+= P_Thrust
+=
+= moves the given origin along a given angle
+=
+==================
+*/
+
+void P_Thrust(player_t *player, angle_t angle, fixed_t move)
+{
+	angle >>= ANGLETOFINESHIFT;
+	if (player->powers[pw_flight] && !(player->mo->z <= player->mo->floorz))
+	{
+		player->mo->momx += FixedMul(move, finecosine[angle]);
+		player->mo->momy += FixedMul(move, finesine[angle]);
+	}
+	else if (P_GetThingFloorType(player->mo) == FLOOR_ICE)	// Friction_Low
+	{
+		player->mo->momx += FixedMul(move>>1, finecosine[angle]);
+		player->mo->momy += FixedMul(move>>1, finesine[angle]);
+	}
+	else
+	{
+		player->mo->momx += FixedMul(move, finecosine[angle]);
+		player->mo->momy += FixedMul(move, finesine[angle]);
+	}
+}
+
+
+/*
+==================
+=
+= P_CalcHeight
+=
+Calculate the walking / running height adjustment
+=
+==================
+*/
+
+static void P_CalcHeight (player_t *player)
+{
+	int		angle;
+	fixed_t	bob;
+
+//
+// regular movement bobbing (needs to be calculated for gun swing even
+// if not on ground)
+// OPTIMIZE: tablify angle
+
+	player->bob = FixedMul (player->mo->momx, player->mo->momx) +
+			FixedMul (player->mo->momy,player->mo->momy);
+	player->bob >>= 2;
+	if (player->bob > MAXBOB)
+		player->bob = MAXBOB;
+	if (player->mo->flags2 & MF2_FLY && !onground)
+	{
+		player->bob = FRACUNIT/2;
+	}
+
+	if ((player->cheats & CF_NOMOMENTUM))
+	{
+		player->viewz = player->mo->z + VIEWHEIGHT;
+		if (player->viewz > player->mo->ceilingz - 4*FRACUNIT)
+			player->viewz = player->mo->ceilingz - 4*FRACUNIT;
+		player->viewz = player->mo->z + player->viewheight;
+		return;
+	}
+
+	angle = (FINEANGLES/20*leveltime) & FINEMASK;
+	bob = FixedMul (player->bob/2, finesine[angle]);
+
+//
+// move viewheight
+//
+	if (player->playerstate == PST_LIVE)
+	{
+		player->viewheight += player->deltaviewheight;
+		if (player->viewheight > VIEWHEIGHT)
+		{
+			player->viewheight = VIEWHEIGHT;
+			player->deltaviewheight = 0;
+		}
+		if (player->viewheight < VIEWHEIGHT/2)
+		{
+			player->viewheight = VIEWHEIGHT/2;
+			if (player->deltaviewheight <= 0)
+				player->deltaviewheight = 1;
+		}
+
+		if (player->deltaviewheight)
+		{
+			player->deltaviewheight += FRACUNIT/4;
+			if (!player->deltaviewheight)
+				player->deltaviewheight = 1;
+		}
+	}
+
+	if (player->morphTics)
+	{
+		player->viewz = player->mo->z + player->viewheight - (20*FRACUNIT);
+	}
+	else
+	{
+		player->viewz = player->mo->z + player->viewheight + bob;
+	}
+	if (player->mo->floorclip && player->playerstate != PST_DEAD
+		&& player->mo->z <= player->mo->floorz)
+	{
+		player->viewz -= player->mo->floorclip;
+	}
+	if (player->viewz > player->mo->ceilingz - 4*FRACUNIT)
+	{
+		player->viewz = player->mo->ceilingz - 4*FRACUNIT;
+	}
+	if (player->viewz < player->mo->floorz + 4*FRACUNIT)
+	{
+		player->viewz = player->mo->floorz + 4*FRACUNIT;
+	}
+}
+
+/*
+=================
+=
+= P_MovePlayer
+=
+=================
+*/
+
+static void P_MovePlayer(player_t *player)
+{
+	int look;
+	int fly;
+	ticcmd_t *cmd;
+
+	cmd = &player->cmd;
+	player->mo->angle += (cmd->angleturn<<16);
+
+	onground = (player->mo->z <= player->mo->floorz
+			|| (player->mo->flags2&MF2_ONMOBJ));
+
+	if (cmd->forwardmove)
+	{
+		if (onground || player->mo->flags2 & MF2_FLY)
+		{
+			P_Thrust(player, player->mo->angle, cmd->forwardmove*2048);
+		}
+		else
+		{
+			P_Thrust(player, player->mo->angle, FRACUNIT>>8);
+		}
+	}
+	if (cmd->sidemove)
+	{
+		if (onground || player->mo->flags2 & MF2_FLY)
+		{
+			P_Thrust(player, player->mo->angle - ANG90, cmd->sidemove*2048);
+		}
+		else
+		{
+			P_Thrust(player, player->mo->angle, FRACUNIT>>8);
+		}
+	}
+	if (cmd->forwardmove || cmd->sidemove)
+	{
+		if (player->mo->state == &states[PStateNormal[player->playerclass]])
+		{
+			P_SetMobjState(player->mo, PStateRun[player->playerclass]);
+		}
+	}
+
+	look = cmd->lookfly & 15;
+	if (look > 7)
+	{
+		look -= 16;
+	}
+	if (look)
+	{
+		if (look == TOCENTER)
+		{
+			player->centering = true;
+		}
+		else
+		{
+			player->lookdir += 5*look;
+			if (player->lookdir > 90 || player->lookdir < -110)
+			{
+				player->lookdir -= 5*look;
+			}
+		}
+	}
+	if (player->centering)
+	{
+		if (player->lookdir > 0)
+		{
+			player->lookdir -= 8;
+		}
+		else if (player->lookdir < 0)
+		{
+			player->lookdir += 8;
+		}
+		if (abs(player->lookdir) < 8)
+		{
+			player->lookdir = 0;
+			player->centering = false;
+		}
+	}
+	fly = cmd->lookfly>>4;
+	if (fly > 7)
+	{
+		fly -= 16;
+	}
+	if (fly && player->powers[pw_flight])
+	{
+		if (fly != TOCENTER)
+		{
+			player->flyheight = fly*2;
+			if (!(player->mo->flags2 & MF2_FLY))
+			{
+				player->mo->flags2 |= MF2_FLY;
+				player->mo->flags |= MF_NOGRAVITY;
+				if (player->mo->momz <= -39*FRACUNIT)
+				{ // stop falling scream
+					S_StopSound(player->mo);
+				}
+			}
+		}
+		else
+		{
+			player->mo->flags2 &= ~MF2_FLY;
+			player->mo->flags &= ~MF_NOGRAVITY;
+		}
+	}
+	else if (fly > 0)
+	{
+		P_PlayerUseArtifact(player, arti_fly);
+	}
+	if (player->mo->flags2 & MF2_FLY)
+	{
+		player->mo->momz = player->flyheight*FRACUNIT;
+		if (player->flyheight)
+		{
+			player->flyheight /= 2;
+		}
+	}
+}
+
+//==========================================================================
+//
+// P_DeathThink
+//
+//==========================================================================
+
+static void P_DeathThink(player_t *player)
+{
+	int dir;
+	angle_t delta;
+	int lookDelta;
+
+	P_MovePsprites(player);
+
+	onground = (player->mo->z <= player->mo->floorz);
+	if (player->mo->type == MT_BLOODYSKULL || player->mo->type == MT_ICECHUNK)
+	{ // Flying bloody skull or flying ice chunk
+		player->viewheight = 6*FRACUNIT;
+		player->deltaviewheight = 0;
+		//player->damagecount = 20;
+		if (onground)
+		{
+			if (player->lookdir < 60)
+			{
+				lookDelta = (60 - player->lookdir)/8;
+				if (lookDelta < 1 && (leveltime & 1))
+				{
+					lookDelta = 1;
+				}
+				else if (lookDelta > 6)
+				{
+					lookDelta = 6;
+				}
+				player->lookdir += lookDelta;
+			}
+		}
+	}
+	else if (!(player->mo->flags2 & MF2_ICEDAMAGE))
+	{ // Fall to ground (if not frozen)
+		player->deltaviewheight = 0;
+		if (player->viewheight > 6*FRACUNIT)
+		{
+			player->viewheight -= FRACUNIT;
+		}
+		if (player->viewheight < 6*FRACUNIT)
+		{
+			player->viewheight = 6*FRACUNIT;
+		}
+		if (player->lookdir > 0)
+		{
+			player->lookdir -= 6;
+		}
+		else if (player->lookdir < 0)
+		{
+			player->lookdir += 6;
+		}
+		if (abs(player->lookdir) < 6)
+		{
+			player->lookdir = 0;
+		}
+	}
+	P_CalcHeight(player);
+
+	if (player->attacker && player->attacker != player->mo)
+	{ // Watch killer
+		dir = P_FaceMobj(player->mo, player->attacker, &delta);
+		if (delta < ANGLE_1*10)
+		{ // Looking at killer, so fade damage and poison counters
+			if (player->damagecount)
+			{
+				player->damagecount--;
+			}
+			if (player->poisoncount)
+			{
+				player->poisoncount--;
+			}
+		}
+		delta = delta/8;
+		if (delta > ANGLE_1*5)
+		{
+			delta = ANGLE_1*5;
+		}
+		if (dir)
+		{ // Turn clockwise
+			player->mo->angle += delta;
+		}
+		else
+		{ // Turn counter clockwise
+			player->mo->angle -= delta;
+		}
+	}
+	else if (player->damagecount || player->poisoncount)
+	{
+		if (player->damagecount)
+		{
+			player->damagecount--;
+		}
+		else
+		{
+			player->poisoncount--;
+		}
+	}
+
+	if (player->cmd.buttons & BT_USE)
+	{
+		if (player == &players[consoleplayer])
+		{
+			V_SetPaletteBase();
+			inv_ptr = 0;
+			curpos = 0;
+			newtorch = 0;
+			newtorchdelta = 0;
+		}
+		player->playerstate = PST_REBORN;
+		player->mo->special1 = player->playerclass;
+		if (player->mo->special1 > 2)
+		{
+		// O.S. --  FIXME: HARDCODED NUMBER: 2 == PCLASS_MAGE
+			player->mo->special1 = 0;
+		}
+		// Let the mobj know the player has entered the reborn state.
+		// Some mobjs need to know when it's ok to remove themselves.
+		player->mo->special2 = 666;
+	}
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC P_MorphPlayerThink
+//
+//----------------------------------------------------------------------------
+
+static void P_MorphPlayerThink(player_t *player)
+{
+	mobj_t *pmo;
+
+	if (player->morphTics & 15)
+	{
+		return;
+	}
+	pmo = player->mo;
+	if (!(pmo->momx + pmo->momy) && P_Random() < 64)
+	{ // Snout sniff
+		P_SetPspriteNF(player, ps_weapon, S_SNOUTATK2);
+		S_StartSound(pmo, SFX_PIG_ACTIVE1); // snort
+		return;
+	}
+	if (P_Random() < 48)
+	{
+		if (P_Random() < 128)
+		{
+			S_StartSound(pmo, SFX_PIG_ACTIVE1);
+		}
+		else
+		{
+			S_StartSound(pmo, SFX_PIG_ACTIVE2);
+		}
+	}
+}
+
+//----------------------------------------------------------------------------
+//
+// FUNC P_GetPlayerNum
+//
+//----------------------------------------------------------------------------
+
+int P_GetPlayerNum(player_t *player)
+{
+	int i;
+
+	for (i = 0; i < MAXPLAYERS; i++)
+	{
+		if (player == &players[i])
+		{
+			return i;
+		}
+	}
+	return 0;
+}
+
+//----------------------------------------------------------------------------
+//
+// FUNC P_UndoPlayerMorph
+//
+//----------------------------------------------------------------------------
+
+boolean P_UndoPlayerMorph(player_t *player)
+{
+	mobj_t *fog;
+	mobj_t *mo;
+	mobj_t *pmo;
+	fixed_t x;
+	fixed_t y;
+	fixed_t z;
+	angle_t angle;
+	int playerNum;
+	weapontype_t weapon;
+	int oldFlags;
+	int oldFlags2;
+	int oldBeast;
+
+	pmo = player->mo;
+	x = pmo->x;
+	y = pmo->y;
+	z = pmo->z;
+	angle = pmo->angle;
+	weapon = pmo->special1;
+	oldFlags = pmo->flags;
+	oldFlags2 = pmo->flags2;
+	oldBeast = pmo->type;
+	P_SetMobjState(pmo, S_FREETARGMOBJ);
+	playerNum = P_GetPlayerNum(player);
+	switch (PlayerClasses[playerNum])
+	{
+	case PCLASS_FIGHTER:
+		mo = P_SpawnMobj(x, y, z, MT_PLAYER_FIGHTER);
+		break;
+	case PCLASS_CLERIC:
+		mo = P_SpawnMobj(x, y, z, MT_PLAYER_CLERIC);
+		break;
+	case PCLASS_MAGE:
+		mo = P_SpawnMobj(x, y, z, MT_PLAYER_MAGE);
+		break;
+#ifdef ASSASSIN
+	case PCLASS_ASS:
+		mo = P_SpawnMobj(x, y, z, MT_PLAYER_ASS);
+		break;
+#endif
+	default:
+		I_Error("P_UndoPlayerMorph:  Unknown player class %d\n", player->playerclass);
+		mo = NULL;	/* avoid compiler warning */
+		break;
+	}
+	if (P_TestMobjLocation(mo) == false)
+	{ // Didn't fit
+		P_RemoveMobj(mo);
+		mo = P_SpawnMobj(x, y, z, oldBeast);
+		mo->angle = angle;
+		mo->health = player->health;
+		mo->special1 = weapon;
+		mo->player = player;
+		mo->flags = oldFlags;
+		mo->flags2 = oldFlags2;
+		player->mo = mo;
+		player->morphTics = 2*35;
+		return false;
+	}
+	if (player->playerclass == PCLASS_FIGHTER)
+	{
+		// The first type should be blue, and the third should be the
+		// Fighter's original gold color
+		if (playerNum == 0)
+		{
+			mo->flags |= 2<<MF_TRANSSHIFT;
+		}
+		else if (playerNum != 2)
+		{
+			mo->flags |= playerNum<<MF_TRANSSHIFT;
+		}
+	}
+	else if (playerNum)
+	{ // Set color translation bits for player sprites
+		mo->flags |= playerNum<<MF_TRANSSHIFT;
+	}
+	mo->angle = angle;
+	mo->player = player;
+	mo->reactiontime = 18;
+	if (oldFlags2 & MF2_FLY)
+	{
+		mo->flags2 |= MF2_FLY;
+		mo->flags |= MF_NOGRAVITY;
+	}
+	player->morphTics = 0;
+	player->health = mo->health = MAXHEALTH;
+	player->mo = mo;
+	player->playerclass = PlayerClasses[playerNum];
+	angle >>= ANGLETOFINESHIFT;
+	fog = P_SpawnMobj(x + 20*finecosine[angle],
+			  y + 20*finesine[angle],
+			  z + TELEFOGHEIGHT, MT_TFOG);
+	S_StartSound(fog, SFX_TELEPORT);
+	P_PostMorphWeapon(player, weapon);
+	return true;
+}
+
+
+//----------------------------------------------------------------------------
+//
+// PROC P_PlayerThink
+//
+//----------------------------------------------------------------------------
+
+void P_PlayerThink(player_t *player)
+{
+	ticcmd_t *cmd;
+	weapontype_t newweapon;
+	int floorType;
+	mobj_t *pmo;
+
+	// No-clip cheat
+	if (player->cheats & CF_NOCLIP)
+	{
+		player->mo->flags |= MF_NOCLIP;
+	}
+	else
+	{
+		player->mo->flags &= ~MF_NOCLIP;
+	}
+	cmd = &player->cmd;
+	if (player->mo->flags & MF_JUSTATTACKED)
+	{ // Gauntlets attack auto forward motion
+		cmd->angleturn = 0;
+		cmd->forwardmove = 0xc800 / 512;
+		cmd->sidemove = 0;
+		player->mo->flags &= ~MF_JUSTATTACKED;
+	}
+// messageTics is above the rest of the counters so that messages will 
+// 		go away, even in death.
+	player->messageTics--; // Can go negative
+	if (!player->messageTics || player->messageTics == -1)
+	{ // Refresh the screen when a message goes away
+		player->ultimateMessage = false; // clear out any chat messages.
+		player->yellowMessage = false;
+		if (player == &players[consoleplayer])
+		{
+			BorderTopRefresh = true;
+		}
+	}
+	player->worldTimer++;
+	if (player->playerstate == PST_DEAD)
+	{
+		P_DeathThink(player);
+		return;
+	}
+	if (player->jumpTics)
+	{
+		player->jumpTics--;
+	}
+	if (player->morphTics)
+	{
+		P_MorphPlayerThink(player);
+	}
+	// Handle movement
+	if (player->mo->reactiontime)
+	{ // Player is frozen
+		player->mo->reactiontime--;
+	}
+	else
+	{
+		P_MovePlayer(player);
+		pmo = player->mo;
+		if (player->powers[pw_speed] && !(leveltime & 1)
+			&& P_AproxDistance(pmo->momx, pmo->momy) > 12*FRACUNIT)
+		{
+			mobj_t *speedMo;
+			int playerNum;
+
+			speedMo = P_SpawnMobj(pmo->x, pmo->y, pmo->z, MT_PLAYER_SPEED);
+			if (speedMo)
+			{
+				speedMo->angle = pmo->angle;
+				playerNum = P_GetPlayerNum(player);
+				if (player->playerclass == PCLASS_FIGHTER)
+				{
+					// The first type should be blue, and the 
+					// third should be the Fighter's original gold color
+					if (playerNum == 0)
+					{
+						speedMo->flags |= 2<<MF_TRANSSHIFT;
+					}
+					else if (playerNum != 2)
+					{
+						speedMo->flags |= playerNum<<MF_TRANSSHIFT;
+					}
+				}
+				else if (playerNum)
+				{ // Set color translation bits for player sprites
+					speedMo->flags |= playerNum<<MF_TRANSSHIFT;
+				}
+				speedMo->target = pmo;
+				speedMo->special1 = player->playerclass;
+				if (speedMo->special1 > 2)
+				{
+				// O.S. --  FIXME: HARDCODED NUMBER: 2 == PCLASS_MAGE
+					speedMo->special1 = 0;
+				}
+				speedMo->sprite = pmo->sprite;
+				speedMo->floorclip = pmo->floorclip;
+				if (player == &players[consoleplayer])
+				{
+					speedMo->flags2 |= MF2_DONTDRAW;
+				}
+			}
+		}
+	}
+	P_CalcHeight(player);
+	if (player->mo->subsector->sector->special)
+	{
+		P_PlayerInSpecialSector(player);
+	}
+	if ((floorType = P_GetThingFloorType(player->mo)) != FLOOR_SOLID)
+	{
+		P_PlayerOnSpecialFlat(player, floorType);
+	}
+	switch (player->playerclass)
+	{
+	case PCLASS_FIGHTER:
+		if (player->mo->momz <= -35*FRACUNIT && player->mo->momz >= -40*FRACUNIT
+			&& !player->morphTics
+			&& !S_GetSoundPlayingInfo(player->mo, SFX_PLAYER_FIGHTER_FALLING_SCREAM))
+		{
+			S_StartSound(player->mo, SFX_PLAYER_FIGHTER_FALLING_SCREAM);
+		}
+		break;
+	case PCLASS_CLERIC:
+		if (player->mo->momz <= -35*FRACUNIT && player->mo->momz >= -40*FRACUNIT
+			&& !player->morphTics
+			&& !S_GetSoundPlayingInfo(player->mo, SFX_PLAYER_CLERIC_FALLING_SCREAM))
+		{
+			S_StartSound(player->mo, SFX_PLAYER_CLERIC_FALLING_SCREAM);
+		}
+		break;
+	case PCLASS_MAGE:
+		if (player->mo->momz <= -35*FRACUNIT && player->mo->momz >= -40*FRACUNIT
+			&& !player->morphTics
+			&& !S_GetSoundPlayingInfo(player->mo, SFX_PLAYER_MAGE_FALLING_SCREAM))
+		{
+			S_StartSound(player->mo, SFX_PLAYER_MAGE_FALLING_SCREAM);
+		}
+#ifdef ASSASSIN
+	case PCLASS_ASS:
+		if (player->mo->momz <= -35*FRACUNIT && player->mo->momz >= -40*FRACUNIT
+			&& !player->morphTics
+			&& !S_GetSoundPlayingInfo(player->mo, SFX_PLAYER_MAGE_FALLING_SCREAM))
+		{
+			S_StartSound(player->mo, SFX_PLAYER_MAGE_FALLING_SCREAM);
+		}
+		break;
+#endif
+	default:
+		break;
+	}
+	if (cmd->arti)
+	{ // Use an artifact
+		if ((cmd->arti & AFLAG_JUMP) && onground && !player->jumpTics)
+		{
+			if (player->morphTics)
+			{
+				player->mo->momz = 6*FRACUNIT;
+			}
+			else
+			{
+				player->mo->momz = 9*FRACUNIT;
+			}
+			player->mo->flags2 &= ~MF2_ONMOBJ;
+			player->jumpTics = 18;
+		}
+		else if (cmd->arti & AFLAG_SUICIDE)
+		{
+			P_DamageMobj(player->mo, NULL, NULL, 10000);
+		}
+		if (cmd->arti == NUMARTIFACTS)
+		{ // use one of each artifact (except puzzle artifacts)
+			int i;
+			for (i = 1; i < arti_firstpuzzitem; i++)
+			{
+				P_PlayerUseArtifact(player, i);
+			}
+		}
+		else
+		{
+			P_PlayerUseArtifact(player, cmd->arti & AFLAG_MASK);
+		}
+	}
+	// Check for weapon change
+	if (cmd->buttons & BT_SPECIAL)
+	{ // A special event has no other buttons
+		cmd->buttons = 0;
+	}
+	if (cmd->buttons & BT_CHANGE && !player->morphTics)
+	{
+		// The actual changing of the weapon is done when the weapon
+		// psprite can do it (A_WeaponReady), so it doesn't happen in
+		// the middle of an attack.
+		newweapon = (cmd->buttons & BT_WEAPONMASK)>>BT_WEAPONSHIFT;
+		if (player->weaponowned[newweapon]
+			&& newweapon != player->readyweapon)
+		{
+			player->pendingweapon = newweapon;
+		}
+	}
+	// Check for use
+	if (cmd->buttons & BT_USE)
+	{
+		if (!player->usedown)
+		{
+			P_UseLines(player);
+			player->usedown = true;
+		}
+	}
+	else
+	{
+		player->usedown = false;
+	}
+	// Morph counter
+	if (player->morphTics)
+	{
+		if (!--player->morphTics)
+		{ // Attempt to undo the pig
+			P_UndoPlayerMorph(player);
+		}
+	}
+	// Cycle psprites
+	P_MovePsprites(player);
+	// Other Counters
+	if (player->powers[pw_invulnerability])
+	{
+		if (player->playerclass == PCLASS_CLERIC)
+		{
+			if (!(leveltime & 7) && player->mo->flags & MF_SHADOW
+				&& !(player->mo->flags2 & MF2_DONTDRAW))
+			{
+				player->mo->flags &= ~MF_SHADOW;
+				if (!(player->mo->flags & MF_ALTSHADOW))
+				{
+					player->mo->flags2 |= MF2_DONTDRAW|MF2_NONSHOOTABLE;
+				}
+			}
+			if (!(leveltime & 31))
+			{
+				if (player->mo->flags2 & MF2_DONTDRAW)
+				{
+					if (!(player->mo->flags & MF_SHADOW))
+					{
+						player->mo->flags |= MF_SHADOW|MF_ALTSHADOW;
+					}
+					else
+					{
+						player->mo->flags2 &= ~(MF2_DONTDRAW|MF2_NONSHOOTABLE);
+					}
+				}
+				else
+				{
+					player->mo->flags |= MF_SHADOW;
+					player->mo->flags &= ~MF_ALTSHADOW;
+				}
+			}
+		}
+		if (!(--player->powers[pw_invulnerability]))
+		{
+			player->mo->flags2 &= ~(MF2_INVULNERABLE|MF2_REFLECTIVE);
+			if (player->playerclass == PCLASS_CLERIC)
+			{
+				player->mo->flags2 &= ~(MF2_DONTDRAW|MF2_NONSHOOTABLE);
+				player->mo->flags &= ~(MF_SHADOW|MF_ALTSHADOW);
+			}
+		}
+	}
+	if (player->powers[pw_minotaur])
+	{
+		player->powers[pw_minotaur]--;
+	}
+	if (player->powers[pw_infrared])
+	{
+		player->powers[pw_infrared]--;
+	}
+	if (player->powers[pw_flight] && netgame)
+	{
+		if (!--player->powers[pw_flight])
+		{
+		//	if (player->mo->z != player->mo->floorz) { }
+			player->mo->flags2 &= ~MF2_FLY;
+			player->mo->flags &= ~MF_NOGRAVITY;
+			BorderTopRefresh = true; //make sure the sprite's cleared out
+		}
+	}
+	if (player->powers[pw_speed])
+	{
+		player->powers[pw_speed]--;
+	}
+	if (player->damagecount)
+	{
+		player->damagecount--;
+	}
+	if (player->bonuscount)
+	{
+		player->bonuscount--;
+	}
+	if (player->poisoncount && !(leveltime & 15))
+	{
+		player->poisoncount -= 5;
+		if (player->poisoncount < 0)
+		{
+			player->poisoncount = 0;
+		}
+		P_PoisonDamage(player, player->poisoner, 1, true); 
+	}
+	// Colormaps
+//	if (player->powers[pw_invulnerability])
+//	{
+//		if (player->powers[pw_invulnerability] > BLINKTHRESHOLD
+//			|| (player->powers[pw_invulnerability] & 8))
+//		{
+//			player->fixedcolormap = INVERSECOLORMAP;
+//		}
+//		else
+//		{
+//			player->fixedcolormap = 0;
+//		}
+//	}
+//	else 
+	if (player->powers[pw_infrared])
+	{
+		if (player->powers[pw_infrared] <= BLINKTHRESHOLD)
+		{
+			if (player->powers[pw_infrared] & 8)
+			{
+				player->fixedcolormap = 0;
+			}
+			else
+			{
+				player->fixedcolormap = 1;
+			}
+		}
+		else if (!(leveltime & 16) && player == &players[consoleplayer])
+		{
+			if (newtorch)
+			{
+				if (player->fixedcolormap + newtorchdelta > 7
+					|| player->fixedcolormap + newtorchdelta < 1
+					|| newtorch == player->fixedcolormap)
+				{
+					newtorch = 0;
+				}
+				else
+				{
+					player->fixedcolormap += newtorchdelta;
+				}
+			}
+			else
+			{
+				newtorch = (M_Random() & 7) + 1;
+				newtorchdelta = (newtorch == player->fixedcolormap) ?
+						0 : ((newtorch > player->fixedcolormap) ? 1 : -1);
+			}
+		}
+	}
+	else
+	{
+		player->fixedcolormap = 0;
+	}
+}
+
+
+//----------------------------------------------------------------------------
+//
+// PROC P_ArtiTele
+//
+//----------------------------------------------------------------------------
+
+static void P_ArtiTele(player_t *player)
+{
+	int i;
+	int selections;
+	fixed_t destX;
+	fixed_t destY;
+	angle_t destAngle;
+
+	if (deathmatch)
+	{
+		selections = deathmatch_p - deathmatchstarts;
+		i = P_Random() % selections;
+		destX = deathmatchstarts[i].x<<FRACBITS;
+		destY = deathmatchstarts[i].y<<FRACBITS;
+		destAngle = ANG45*(deathmatchstarts[i].angle/45);
+	}
+	else
+	{
+		destX = playerstarts[0][0].x<<FRACBITS;
+		destY = playerstarts[0][0].y<<FRACBITS;
+		destAngle = ANG45*(playerstarts[0][0].angle/45);
+	}
+	P_Teleport(player->mo, destX, destY, destAngle, true);
+	if (player->morphTics)
+	{ // Teleporting away will undo any morph effects (pig)
+		P_UndoPlayerMorph(player);
+	}
+	//S_StartSound(NULL, sfx_wpnup); // Full volume laugh
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC P_ArtiTeleportOther
+//
+//----------------------------------------------------------------------------
+
+static void P_ArtiTeleportOther(player_t *player)
+{
+	mobj_t *mo;
+
+	mo = P_SpawnPlayerMissile(player->mo, MT_TELOTHER_FX1);
+	if (mo)
+	{
+		mo->target = player->mo;
+	}
+}
+
+static void P_TeleportToPlayerStarts(mobj_t *victim)
+{
+	int i, selections = 0;
+	fixed_t destX, destY;
+	angle_t destAngle;
+
+	for (i = 0; i < MAXPLAYERS; i++)
+	{
+		if (!playeringame[i])
+			continue;
+		selections++;
+	}
+	i = P_Random() % selections;
+	destX = playerstarts[0][i].x<<FRACBITS;
+	destY = playerstarts[0][i].y<<FRACBITS;
+	destAngle = ANG45*(playerstarts[0][i].angle/45);
+	P_Teleport(victim, destX, destY, destAngle, true);
+	//S_StartSound(NULL, sfx_wpnup); // Full volume laugh
+}
+
+static void P_TeleportToDeathmatchStarts(mobj_t *victim)
+{
+	int i, selections;
+	fixed_t destX, destY;
+	angle_t destAngle;
+
+	selections = deathmatch_p-deathmatchstarts;
+	if (selections)
+	{
+		i = P_Random() % selections;
+		destX = deathmatchstarts[i].x<<FRACBITS;
+		destY = deathmatchstarts[i].y<<FRACBITS;
+		destAngle = ANG45*(deathmatchstarts[i].angle/45);
+		P_Teleport(victim, destX, destY, destAngle, true);
+		//S_StartSound(NULL, sfx_wpnup); // Full volume laugh
+	}
+	else
+	{
+		P_TeleportToPlayerStarts(victim);
+	}
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC P_TeleportOther
+//
+//----------------------------------------------------------------------------
+
+void P_TeleportOther(mobj_t *victim)
+{
+	if (victim->player)
+	{
+		if (deathmatch)
+			P_TeleportToDeathmatchStarts(victim);
+		else
+			P_TeleportToPlayerStarts(victim);
+	}
+	else
+	{
+		// If death action, run it upon teleport
+		if (victim->flags & MF_COUNTKILL && victim->special)
+		{
+			P_RemoveMobjFromTIDList(victim);
+			P_ExecuteLineSpecial(victim->special, victim->args,
+							NULL, 0, victim);
+			victim->special = 0;
+		}
+
+		// Send all monsters to deathmatch spots
+		P_TeleportToDeathmatchStarts(victim);
+	}
+}
+
+
+#define BLAST_RADIUS_DIST	255*FRACUNIT
+#define BLAST_SPEED		20*FRACUNIT
+#define BLAST_FULLSTRENGTH	255
+
+void ResetBlasted(mobj_t *mo)
+{
+	mo->flags2 &= ~MF2_BLASTED;
+	if (!(mo->flags & MF_ICECORPSE))
+	{
+		mo->flags2 &= ~MF2_SLIDE;
+	}
+}
+
+static void P_BlastMobj(mobj_t *source, mobj_t *victim, fixed_t strength)
+{
+	angle_t angle, ang;
+	mobj_t *mo;
+	fixed_t x, y, z;
+
+	angle = R_PointToAngle2(source->x, source->y, victim->x, victim->y);
+	angle >>= ANGLETOFINESHIFT;
+	if (strength < BLAST_FULLSTRENGTH)
+	{
+		victim->momx = FixedMul(strength, finecosine[angle]);
+		victim->momy = FixedMul(strength, finesine[angle]);
+		if (victim->player)
+		{
+			// Players handled automatically
+		}
+		else
+		{
+			victim->flags2 |= MF2_SLIDE;
+			victim->flags2 |= MF2_BLASTED;
+		}
+	}
+	else		// full strength blast from artifact
+	{
+		if (victim->flags & MF_MISSILE)
+		{
+			switch (victim->type)
+			{
+			case MT_SORCBALL1:	// don't blast sorcerer balls
+			case MT_SORCBALL2:
+			case MT_SORCBALL3:
+				return;
+			case MT_MSTAFF_FX2:	// Reflect to originator
+				victim->special1 = (intptr_t)victim->target;
+				victim->target = source;
+				break;
+			default:
+				break;
+			}
+		}
+		if (victim->type == MT_HOLY_FX)
+		{
+			if ((mobj_t *)(victim->special1) == source)
+			{
+				victim->special1 = (intptr_t)victim->target;
+				victim->target = source;
+			}
+		}
+		victim->momx = FixedMul(BLAST_SPEED, finecosine[angle]);
+		victim->momy = FixedMul(BLAST_SPEED, finesine[angle]);
+
+		// Spawn blast puff
+		ang = R_PointToAngle2(victim->x, victim->y, source->x, source->y);
+		ang >>= ANGLETOFINESHIFT;
+		x = victim->x + FixedMul(victim->radius + FRACUNIT, finecosine[ang]);
+		y = victim->y + FixedMul(victim->radius + FRACUNIT, finesine[ang]);
+		z = victim->z - victim->floorclip + (victim->height>>1);
+		mo = P_SpawnMobj(x, y, z, MT_BLASTEFFECT);
+		if (mo)
+		{
+			mo->momx = victim->momx;
+			mo->momy = victim->momy;
+		}
+
+		if (victim->flags & MF_MISSILE)
+		{
+			victim->momz = 8*FRACUNIT;
+			mo->momz = victim->momz;
+		}
+		else
+		{
+			victim->momz = (1000/victim->info->mass)<<FRACBITS;
+		}
+		if (victim->player)
+		{
+			// Players handled automatically
+		}
+		else
+		{
+			victim->flags2 |= MF2_SLIDE;
+			victim->flags2 |= MF2_BLASTED;
+		}
+	}
+}
+
+// Blast all mobj things away
+static void P_BlastRadius(player_t *player)
+{
+	mobj_t *mo;
+	mobj_t *pmo = player->mo;
+	thinker_t *think;
+	fixed_t dist;
+
+	S_StartSound(pmo, SFX_ARTIFACT_BLAST);
+	P_NoiseAlert(player->mo, player->mo);
+
+	for (think = thinkercap.next; think != &thinkercap; think = think->next)
+	{
+		if (think->function != P_MobjThinker)
+		{ // Not a mobj thinker
+			continue;
+		}
+		mo = (mobj_t *)think;
+		if ((mo == pmo) || (mo->flags2 & MF2_BOSS))
+		{ // Not a valid monster
+			continue;
+		}
+		if ((mo->type == MT_POISONCLOUD) ||	// poison cloud
+			(mo->type == MT_HOLY_FX) ||	// holy fx
+			(mo->flags&MF_ICECORPSE))	// frozen corpse
+		{
+			// Let these special cases go
+		}
+		else if ((mo->flags & MF_COUNTKILL) &&
+				(mo->health <= 0))
+		{
+			continue;
+		}
+		else if (!(mo->flags & MF_COUNTKILL) &&
+				!(mo->player) &&
+				!(mo->flags & MF_MISSILE))
+		{	// Must be monster, player, or missile
+			continue;
+		}
+		if (mo->flags2 & MF2_DORMANT)
+		{
+			continue;		// no dormant creatures
+		}
+		if ((mo->type == MT_WRAITHB) && (mo->flags2 & MF2_DONTDRAW))
+		{
+			continue;		// no underground wraiths
+		}
+		if ((mo->type == MT_SPLASHBASE) ||
+			(mo->type == MT_SPLASH))
+		{
+			continue;
+		}
+		if (mo->type == MT_SERPENT || mo->type == MT_SERPENTLEADER)
+		{
+			continue;
+		}
+		dist = P_AproxDistance(pmo->x - mo->x, pmo->y - mo->y);
+		if (dist > BLAST_RADIUS_DIST)
+		{ // Out of range
+			continue;
+		}
+		P_BlastMobj(pmo, mo, BLAST_FULLSTRENGTH);
+	}
+}
+
+
+#define HEAL_RADIUS_DIST	255*FRACUNIT
+
+// Do class specific effect for everyone in radius
+static boolean P_HealRadius(player_t *player)
+{
+	mobj_t *mo;
+	mobj_t *pmo = player->mo;
+	thinker_t *think;
+	fixed_t dist;
+	int effective = false;
+	int amount;
+
+	for (think = thinkercap.next; think != &thinkercap; think = think->next)
+	{
+		if (think->function != P_MobjThinker)
+		{ // Not a mobj thinker
+			continue;
+		}
+		mo = (mobj_t *)think;
+
+		if (!mo->player)
+			continue;
+		if (mo->health <= 0)
+			continue;
+		dist = P_AproxDistance(pmo->x - mo->x, pmo->y - mo->y);
+		if (dist > HEAL_RADIUS_DIST)
+		{ // Out of range
+			continue;
+		}
+
+		switch (player->playerclass)
+		{
+		case PCLASS_FIGHTER:	// Radius armor boost
+			if ((P_GiveArmor(mo->player, ARMOR_ARMOR, 1)) ||
+				(P_GiveArmor(mo->player, ARMOR_SHIELD, 1)) ||
+				(P_GiveArmor(mo->player, ARMOR_HELMET, 1)) ||
+				(P_GiveArmor(mo->player, ARMOR_AMULET, 1)))
+			{
+				effective = true;
+				S_StartSound(mo, SFX_MYSTICINCANT);
+			}
+			break;
+		case PCLASS_CLERIC:	// Radius heal
+			amount = 50 + (P_Random() % 50);
+			if (P_GiveBody(mo->player, amount))
+			{
+				effective = true;
+				S_StartSound(mo, SFX_MYSTICINCANT);
+			}
+			break;
+		case PCLASS_MAGE:	// Radius mana boost
+			amount = 50 + (P_Random() % 50);
+			if ((P_GiveMana(mo->player, MANA_1, amount)) ||
+				(P_GiveMana(mo->player, MANA_2, amount)))
+			{
+				effective = true;
+				S_StartSound(mo, SFX_MYSTICINCANT);
+			}
+			break;
+#ifdef ASSASSIN
+		case PCLASS_ASS:	// Also Radius heal
+			amount = 50 + (P_Random() % 50);
+			if (P_GiveBody(mo->player, amount))
+			{
+				effective = true;
+				S_StartSound(mo, SFX_MYSTICINCANT);
+			}
+			break;
+#endif
+		case PCLASS_PIG:
+		default:
+			break;
+		}
+	}
+	return effective;
+}
+
+
+//----------------------------------------------------------------------------
+//
+// PROC P_PlayerNextArtifact
+//
+//----------------------------------------------------------------------------
+
+void P_PlayerNextArtifact(player_t *player)
+{
+	if (player == &players[consoleplayer])
+	{
+		inv_ptr--;
+		if (inv_ptr < 6)
+		{
+			curpos--;
+			if (curpos < 0)
+			{
+				curpos = 0;
+			}
+		}
+		if (inv_ptr < 0)
+		{
+			inv_ptr = player->inventorySlotNum - 1;
+			if (inv_ptr < 6)
+			{
+				curpos = inv_ptr;
+			}
+			else
+			{
+				curpos = 6;
+			}
+		}
+		player->readyArtifact =
+			player->inventory[inv_ptr].type;
+	}
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC P_PlayerRemoveArtifact
+//
+//----------------------------------------------------------------------------
+
+void P_PlayerRemoveArtifact(player_t *player, int slot)
+{
+	int i;
+
+	player->artifactCount--;
+	if (!(--player->inventory[slot].count))
+	{ // Used last of a type - compact the artifact list
+		player->readyArtifact = arti_none;
+		player->inventory[slot].type = arti_none;
+		for (i = slot + 1; i < player->inventorySlotNum; i++)
+		{
+			player->inventory[i-1] = player->inventory[i];
+		}
+		player->inventorySlotNum--;
+		if (player == &players[consoleplayer])
+		{ // Set position markers and get next readyArtifact
+			inv_ptr--;
+			if (inv_ptr < 6)
+			{
+				curpos--;
+				if (curpos < 0)
+				{
+					curpos = 0;
+				}
+			}
+			if (inv_ptr >= player->inventorySlotNum)
+			{
+				inv_ptr = player->inventorySlotNum - 1;
+			}
+			if (inv_ptr < 0)
+			{
+				inv_ptr = 0;
+			}
+			player->readyArtifact =
+				player->inventory[inv_ptr].type;
+		}
+	}
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC P_PlayerUseArtifact
+//
+//----------------------------------------------------------------------------
+
+void P_PlayerUseArtifact(player_t *player, artitype_t arti)
+{
+	int i;
+
+	for (i = 0; i < player->inventorySlotNum; i++)
+	{
+		if (player->inventory[i].type == arti)
+		{ // Found match - try to use
+			if (P_UseArtifact(player, arti))
+			{ // Artifact was used - remove it from inventory
+				P_PlayerRemoveArtifact(player, i);
+				if (player == &players[consoleplayer])
+				{
+					if (arti < arti_firstpuzzitem)
+					{
+						S_StartSound(NULL, SFX_ARTIFACT_USE);
+					}
+					else
+					{
+						S_StartSound(NULL, SFX_PUZZLE_SUCCESS);
+					}
+					ArtifactFlash = 4;
+				}
+			}
+			else if (arti < arti_firstpuzzitem)
+			{ // Unable to use artifact, advance pointer
+				P_PlayerNextArtifact(player);
+			}
+			break;
+		}
+	}
+}
+
+//==========================================================================
+//
+// P_UseArtifact
+//
+// Returns true if the artifact was used.
+//
+//==========================================================================
+
+boolean P_UseArtifact(player_t *player, artitype_t arti)
+{
+	mobj_t *mo;
+	angle_t angle;
+	int i;
+	int count;
+
+	switch (arti)
+	{
+	case arti_invulnerability:
+		if (!P_GivePower(player, pw_invulnerability))
+		{
+			return false;
+		}
+		break;
+	case arti_health:
+		if (!P_GiveBody(player, 25))
+		{
+			return false;
+		}
+		break;
+	case arti_superhealth:
+		if (!P_GiveBody(player, 100))
+		{
+			return false;
+		}
+		break;
+	case arti_healingradius:
+		if (!P_HealRadius(player))
+		{
+			return false;
+		}
+		break;
+	case arti_torch:
+		if (!P_GivePower(player, pw_infrared))
+		{
+			return false;
+		}
+		break;
+	case arti_egg:
+		mo = player->mo;
+		P_SpawnPlayerMissile(mo, MT_EGGFX);
+		P_SPMAngle(mo, MT_EGGFX, mo->angle - (ANG45/6));
+		P_SPMAngle(mo, MT_EGGFX, mo->angle + (ANG45/6));
+		P_SPMAngle(mo, MT_EGGFX, mo->angle - (ANG45/3));
+		P_SPMAngle(mo, MT_EGGFX, mo->angle + (ANG45/3));
+		break;
+	case arti_fly:
+		if (!P_GivePower(player, pw_flight))
+		{
+			return false;
+		}
+		if (player->mo->momz <= -35*FRACUNIT)
+		{ // stop falling scream
+			S_StopSound(player->mo);
+		}
+		break;
+	case arti_summon:
+		mo = P_SpawnPlayerMissile(player->mo, MT_SUMMON_FX);
+		if (mo)
+		{
+			mo->target = player->mo;
+			mo->special1 = (intptr_t)(player->mo);
+			mo->momz = 5*FRACUNIT;
+		}
+		break;
+	case arti_teleport:
+		P_ArtiTele(player);
+		break;
+	case arti_teleportother:
+		P_ArtiTeleportOther(player);
+		break;
+	case arti_poisonbag:
+		angle = player->mo->angle>>ANGLETOFINESHIFT;
+		if (player->playerclass == PCLASS_CLERIC)
+		{
+			mo = P_SpawnMobj(player->mo->x + 16*finecosine[angle],
+					 player->mo->y + 24*finesine[angle],
+					 player->mo->z - player->mo->floorclip + 8*FRACUNIT,
+					 MT_POISONBAG);
+			if (mo)
+			{
+				mo->target = player->mo;
+			}
+		}
+		else if (player->playerclass == PCLASS_MAGE)
+		{
+			mo = P_SpawnMobj(player->mo->x + 16*finecosine[angle],
+					 player->mo->y + 24*finesine[angle],
+					 player->mo->z - player->mo->floorclip + 8*FRACUNIT,
+					 MT_FIREBOMB);
+			if (mo)
+			{
+				mo->target = player->mo;
+			}
+		}
+		else // PCLASS_FIGHTER, obviously (also pig, not so obviously)
+		{
+			mo = P_SpawnMobj(player->mo->x, player->mo->y,
+					 player->mo->z - player->mo->floorclip + 35*FRACUNIT,
+					 MT_THROWINGBOMB);
+			if (mo)
+			{
+				mo->angle = player->mo->angle + (((P_Random() & 7) - 4) << 24);
+				mo->momz = 4*FRACUNIT + ((player->lookdir) << (FRACBITS - 4));
+				mo->z += player->lookdir << (FRACBITS - 4);
+				P_ThrustMobj(mo, mo->angle, mo->info->speed);
+				mo->momx += player->mo->momx>>1;
+				mo->momy += player->mo->momy>>1;
+				mo->target = player->mo;
+				mo->tics -= P_Random() & 3;
+				P_CheckMissileSpawn(mo);
+			}
+		}
+		break;
+	case arti_speed:
+		if (!P_GivePower(player, pw_speed))
+		{
+			return false;
+		}
+		break;
+	case arti_boostmana:
+		if (!P_GiveMana(player, MANA_1, MAX_MANA))
+		{
+			if (!P_GiveMana(player, MANA_2, MAX_MANA))
+			{
+				return false;
+			}
+		}
+		else
+		{
+			P_GiveMana(player, MANA_2, MAX_MANA);
+		}
+		break;
+	case arti_boostarmor:
+		count = 0;
+		for (i = 0; i < NUMARMOR; i++)
+		{
+			count += P_GiveArmor(player, i, 1); // 1 point per armor type
+		}
+		if (!count)
+		{
+			return false;
+		}
+		break;
+	case arti_blastradius:
+		P_BlastRadius(player);
+		break;
+
+	case arti_puzzskull:
+	case arti_puzzgembig:
+	case arti_puzzgemred:
+	case arti_puzzgemgreen1:
+	case arti_puzzgemgreen2:
+	case arti_puzzgemblue1:
+	case arti_puzzgemblue2:
+	case arti_puzzbook1:
+	case arti_puzzbook2:
+	case arti_puzzskull2:
+	case arti_puzzfweapon:
+	case arti_puzzcweapon:
+	case arti_puzzmweapon:
+	case arti_puzzgear1:
+	case arti_puzzgear2:
+	case arti_puzzgear3:
+	case arti_puzzgear4:
+		if (P_UsePuzzleItem(player, arti - arti_firstpuzzitem))
+		{
+			return true;
+		}
+		else
+		{
+			P_SetYellowMessage(player, TXT_USEPUZZLEFAILED, false);
+			return false;
+		}
+		break;
+	default:
+		return false;
+	}
+	return true;
+}
+
+//============================================================================
+//
+// A_SpeedFade
+//
+//============================================================================
+
+void A_SpeedFade(mobj_t *actor)
+{
+	actor->flags |= MF_SHADOW;
+	actor->flags &= ~MF_ALTSHADOW;
+	actor->sprite = actor->target->sprite;
+}
+
--- /dev/null
+++ b/po_man.c
@@ -1,0 +1,1453 @@
+
+//**************************************************************************
+//**
+//** PO_MAN.C : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 575 $
+//** $Date: 2011-04-13 22:06:28 +0300 (Wed, 13 Apr 2011) $
+//**
+//**************************************************************************
+
+// HEADER FILES ------------------------------------------------------------
+
+#include "h2stdinc.h"
+#include "h2def.h"
+#include "p_local.h"
+#include "r_local.h"
+
+// MACROS ------------------------------------------------------------------
+
+#define PO_MAXPOLYSEGS		64
+
+// TYPES -------------------------------------------------------------------
+
+// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
+
+// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
+
+boolean PO_MovePolyobj(int num, int x, int y);
+boolean PO_RotatePolyobj(int num, angle_t angle);
+void PO_Init(int lump);
+
+// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
+
+static polyobj_t *GetPolyobj(int polyNum);
+static int GetPolyobjMirror(int poly);
+static void ThrustMobj(mobj_t *mobj, seg_t *seg, polyobj_t *po);
+static void UpdateSegBBox(seg_t *seg);
+static void RotatePt(int an, fixed_t *x, fixed_t *y, fixed_t startSpotX, fixed_t startSpotY);
+static void UnLinkPolyobj(polyobj_t *po);
+static void LinkPolyobj(polyobj_t *po);
+static boolean CheckMobjBlocking(seg_t *seg, polyobj_t *po);
+static void InitBlockMap(void);
+static void IterFindPolySegs(int x, int y, seg_t **segList);
+static void SpawnPolyobj(int idx, int tag, boolean crush);
+static void TranslateToStartSpot(int tag, int originX, int originY);
+
+// EXTERNAL DATA DECLARATIONS ----------------------------------------------
+
+extern seg_t	*segs;
+
+// PUBLIC DATA DEFINITIONS -------------------------------------------------
+
+polyblock_t	**PolyBlockMap;
+polyobj_t	*polyobjs; // list of all poly-objects on the level
+int		po_NumPolyobjs;
+
+// PRIVATE DATA DEFINITIONS ------------------------------------------------
+
+static int	PolySegCount;
+static fixed_t	PolyStartX;
+static fixed_t	PolyStartY;
+
+// CODE --------------------------------------------------------------------
+
+// ===== Polyobj Event Code =====
+
+//==========================================================================
+//
+// T_RotatePoly
+//
+//==========================================================================
+
+void T_RotatePoly(polyevent_t *pe)
+{
+	int absSpeed;
+	polyobj_t *poly;
+
+	if (PO_RotatePolyobj(pe->polyobj, pe->speed))
+	{
+		absSpeed = abs(pe->speed);
+
+		if (pe->dist == -1)
+		{ // perpetual polyobj
+			return;
+		}
+		pe->dist -= absSpeed;
+		if (pe->dist <= 0)
+		{
+			poly = GetPolyobj(pe->polyobj);
+			if (poly->specialdata == pe)
+			{
+				poly->specialdata = NULL;
+			}
+			SN_StopSequence((mobj_t *)&poly->startSpot);
+			P_PolyobjFinished(poly->tag);
+			P_RemoveThinker(&pe->thinker);
+		}
+		if (pe->dist < absSpeed)
+		{
+			pe->speed = pe->dist*(pe->speed < 0 ? -1 : 1);
+		}
+	}
+}
+
+//==========================================================================
+//
+// EV_RotatePoly
+//
+//==========================================================================
+
+boolean EV_RotatePoly(line_t *line, byte *args, int direction, boolean overRide)
+{
+	int mirror;
+	int polyNum;
+	polyevent_t *pe;
+	polyobj_t *poly;
+
+	polyNum = args[0];
+	if ((poly = GetPolyobj(polyNum)))
+	{
+		if (poly->specialdata && !overRide)
+		{ // poly is already moving
+			return false;
+		}
+	}
+	else
+	{
+		I_Error("EV_RotatePoly:  Invalid polyobj num: %d\n", polyNum);
+	}
+	pe = (polyevent_t *) Z_Malloc(sizeof(polyevent_t), PU_LEVSPEC, NULL);
+	P_AddThinker(&pe->thinker);
+	pe->thinker.function = T_RotatePoly;
+	pe->polyobj = polyNum;
+	if (args[2])
+	{
+		if (args[2] == 255)
+		{
+			pe->dist = -1;
+		}
+		else
+		{
+			pe->dist = args[2]*(ANGLE_90/64); // Angle
+		}
+	}
+	else
+	{
+		pe->dist = ANGLE_MAX-1;
+	}
+	pe->speed = (args[1]*direction*(ANGLE_90/64))>>3;
+	poly->specialdata = pe;
+	SN_StartSequence((mobj_t *)&poly->startSpot, SEQ_DOOR_STONE + poly->seqType);
+
+	while ((mirror = GetPolyobjMirror(polyNum)))
+	{
+		poly = GetPolyobj(mirror);
+		if (poly && poly->specialdata && !overRide)
+		{ // mirroring poly is already in motion
+			break;
+		}
+		pe = (polyevent_t *) Z_Malloc(sizeof(polyevent_t), PU_LEVSPEC, NULL);
+		P_AddThinker(&pe->thinker);
+		pe->thinker.function = T_RotatePoly;
+		poly->specialdata = pe;
+		pe->polyobj = mirror;
+		if (args[2])
+		{
+			if (args[2] == 255)
+			{
+				pe->dist = -1;
+			}
+			else
+			{
+				pe->dist = args[2]*(ANGLE_90/64); // Angle
+			}
+		}
+		else
+		{
+			pe->dist = ANGLE_MAX-1;
+		}
+		if ((poly = GetPolyobj(polyNum)))
+		{
+			poly->specialdata = pe;
+		}
+		else
+		{
+			I_Error("EV_RotatePoly:  Invalid polyobj num: %d\n", polyNum);
+		}
+		direction = -direction;
+		pe->speed = (args[1]*direction*(ANGLE_90/64))>>3;
+		polyNum = mirror;
+		SN_StartSequence((mobj_t *)&poly->startSpot, SEQ_DOOR_STONE + poly->seqType);
+	}
+	return true;
+}
+
+//==========================================================================
+//
+// T_MovePoly
+//
+//==========================================================================
+
+void T_MovePoly(polyevent_t *pe)
+{
+	int absSpeed;
+	polyobj_t *poly;
+
+	if (PO_MovePolyobj(pe->polyobj, pe->xSpeed, pe->ySpeed))
+	{
+		absSpeed = abs(pe->speed);
+		pe->dist -= absSpeed;
+		if (pe->dist <= 0)
+		{
+			poly = GetPolyobj(pe->polyobj);
+			if (poly->specialdata == pe)
+			{
+				poly->specialdata = NULL;
+			}
+			SN_StopSequence((mobj_t *)&poly->startSpot);
+			P_PolyobjFinished(poly->tag);
+			P_RemoveThinker(&pe->thinker);
+		}
+		if (pe->dist < absSpeed)
+		{
+			pe->speed = pe->dist*(pe->speed < 0 ? -1 : 1);
+			pe->xSpeed = FixedMul(pe->speed, finecosine[pe->angle]);
+			pe->ySpeed = FixedMul(pe->speed, finesine[pe->angle]);
+		}
+	}
+}
+
+//==========================================================================
+//
+// EV_MovePoly
+//
+//==========================================================================
+
+boolean EV_MovePoly(line_t *line, byte *args, boolean timesEight, boolean overRide)
+{
+	int mirror;
+	int polyNum;
+	polyevent_t *pe;
+	polyobj_t *poly;
+	angle_t an;
+
+	polyNum = args[0];
+	if ((poly = GetPolyobj(polyNum)))
+	{
+		if (poly->specialdata && !overRide)
+		{ // poly is already moving
+			return false;
+		}
+	}
+	else
+	{
+		I_Error("EV_MovePoly:  Invalid polyobj num: %d\n", polyNum);
+	}
+	pe = (polyevent_t *) Z_Malloc(sizeof(polyevent_t), PU_LEVSPEC, NULL);
+	P_AddThinker(&pe->thinker);
+	pe->thinker.function = T_MovePoly;
+	pe->polyobj = polyNum;
+	if (timesEight)
+	{
+		pe->dist = args[3]*8*FRACUNIT;
+	}
+	else
+	{
+		pe->dist = args[3]*FRACUNIT; // Distance
+	}
+	pe->speed = args[1]*(FRACUNIT/8);
+	poly->specialdata = pe;
+
+	an = args[2]*(ANGLE_90/64);
+
+	pe->angle = an>>ANGLETOFINESHIFT;
+	pe->xSpeed = FixedMul(pe->speed, finecosine[pe->angle]);
+	pe->ySpeed = FixedMul(pe->speed, finesine[pe->angle]);
+	SN_StartSequence((mobj_t *)&poly->startSpot, SEQ_DOOR_STONE + poly->seqType);
+
+	while ((mirror = GetPolyobjMirror(polyNum)))
+	{
+		poly = GetPolyobj(mirror);
+		if (poly && poly->specialdata && !overRide)
+		{ // mirroring poly is already in motion
+			break;
+		}
+		pe = (polyevent_t *) Z_Malloc(sizeof(polyevent_t), PU_LEVSPEC, NULL);
+		P_AddThinker(&pe->thinker);
+		pe->thinker.function = T_MovePoly;
+		pe->polyobj = mirror;
+		poly->specialdata = pe;
+		if (timesEight)
+		{
+			pe->dist = args[3]*8*FRACUNIT;
+		}
+		else
+		{
+			pe->dist = args[3]*FRACUNIT; // Distance
+		}
+		pe->speed = args[1]*(FRACUNIT/8);
+		an = an + ANGLE_180; // reverse the angle
+		pe->angle = an>>ANGLETOFINESHIFT;
+		pe->xSpeed = FixedMul(pe->speed, finecosine[pe->angle]);
+		pe->ySpeed = FixedMul(pe->speed, finesine[pe->angle]);
+		polyNum = mirror;
+		SN_StartSequence((mobj_t *)&poly->startSpot, SEQ_DOOR_STONE + poly->seqType);
+	}
+	return true;
+}
+
+//==========================================================================
+//
+// T_PolyDoor
+//
+//==========================================================================
+
+void T_PolyDoor(polydoor_t *pd)
+{
+	int absSpeed;
+	polyobj_t *poly;
+
+	if (pd->tics)
+	{
+		if (!--pd->tics)
+		{
+			poly = GetPolyobj(pd->polyobj);
+			SN_StartSequence((mobj_t *)&poly->startSpot, SEQ_DOOR_STONE + poly->seqType);
+		}
+		return;
+	}
+	switch (pd->type)
+	{
+	case PODOOR_SLIDE:
+		if (PO_MovePolyobj(pd->polyobj, pd->xSpeed, pd->ySpeed))
+		{
+			absSpeed = abs(pd->speed);
+			pd->dist -= absSpeed;
+			if (pd->dist <= 0)
+			{
+				poly = GetPolyobj(pd->polyobj);
+				SN_StopSequence((mobj_t *)&poly->startSpot);
+				if (!pd->close)
+				{
+					pd->dist = pd->totalDist;
+					pd->close = true;
+					pd->tics = pd->waitTics;
+					pd->direction = (ANGLE_MAX>>ANGLETOFINESHIFT) - pd->direction;
+					pd->xSpeed = -pd->xSpeed;
+					pd->ySpeed = -pd->ySpeed;
+				}
+				else
+				{
+					if (poly->specialdata == pd)
+					{
+						poly->specialdata = NULL;
+					}
+					P_PolyobjFinished(poly->tag);
+					P_RemoveThinker(&pd->thinker);
+				}
+			}
+		}
+		else
+		{
+			poly = GetPolyobj(pd->polyobj);
+			if (poly->crush || !pd->close)
+			{ // continue moving if the poly is a crusher, or is opening
+				return;
+			}
+			else
+			{ // open back up
+				pd->dist = pd->totalDist-pd->dist;
+				pd->direction = (ANGLE_MAX>>ANGLETOFINESHIFT) - pd->direction;
+				pd->xSpeed = -pd->xSpeed;
+				pd->ySpeed = -pd->ySpeed;
+				pd->close = false;
+				SN_StartSequence((mobj_t *)&poly->startSpot, SEQ_DOOR_STONE + poly->seqType);
+			}
+		}
+		break;
+
+	case PODOOR_SWING:
+		if (PO_RotatePolyobj(pd->polyobj, pd->speed))
+		{
+			absSpeed = abs(pd->speed);
+			if (pd->dist == -1)
+			{ // perpetual polyobj
+				return;
+			}
+			pd->dist -= absSpeed;
+			if (pd->dist <= 0)
+			{
+				poly = GetPolyobj(pd->polyobj);
+				SN_StopSequence((mobj_t *)&poly->startSpot);
+				if (!pd->close)
+				{
+					pd->dist = pd->totalDist;
+					pd->close = true;
+					pd->tics = pd->waitTics;
+					pd->speed = -pd->speed;
+				}
+				else
+				{
+					if (poly->specialdata == pd)
+					{
+						poly->specialdata = NULL;
+					}
+					P_PolyobjFinished(poly->tag);
+					P_RemoveThinker(&pd->thinker);
+				}
+			}
+		}
+		else
+		{
+			poly = GetPolyobj(pd->polyobj);
+			if (poly->crush || !pd->close)
+			{ // continue moving if the poly is a crusher, or is opening
+				return;
+			}
+			else
+			{ // open back up and rewait
+				pd->dist = pd->totalDist-pd->dist;
+				pd->speed = -pd->speed;
+				pd->close = false;
+				SN_StartSequence((mobj_t *)&poly->startSpot, SEQ_DOOR_STONE + poly->seqType);
+			}
+		}
+		break;
+
+	default:
+		break;
+	}
+}
+
+//==========================================================================
+//
+// EV_OpenPolyDoor
+//
+//==========================================================================
+
+boolean EV_OpenPolyDoor(line_t *line, byte *args, podoortype_t type)
+{
+	int mirror;
+	int polyNum;
+	polydoor_t *pd;
+	polyobj_t *poly;
+	angle_t an = 0;
+
+	polyNum = args[0];
+	if ((poly = GetPolyobj(polyNum)))
+	{
+		if (poly->specialdata)
+		{ // poly is already moving
+			return false;
+		}
+	}
+	else
+	{
+		I_Error("EV_OpenPolyDoor:  Invalid polyobj num: %d\n", polyNum);
+	}
+	pd = (polydoor_t *) Z_Malloc(sizeof(polydoor_t), PU_LEVSPEC, NULL);
+	memset(pd, 0, sizeof(polydoor_t));
+	P_AddThinker(&pd->thinker);
+	pd->thinker.function = T_PolyDoor;
+	pd->type = type;
+	pd->polyobj = polyNum;
+	if (type == PODOOR_SLIDE)
+	{
+		pd->waitTics = args[4];
+		pd->speed = args[1]*(FRACUNIT/8);
+		pd->totalDist = args[3]*FRACUNIT; // Distance
+		pd->dist = pd->totalDist;
+		an = args[2]*(ANGLE_90/64);
+		pd->direction = an>>ANGLETOFINESHIFT;
+		pd->xSpeed = FixedMul(pd->speed, finecosine[pd->direction]);
+		pd->ySpeed = FixedMul(pd->speed, finesine[pd->direction]);
+		SN_StartSequence((mobj_t *)&poly->startSpot, SEQ_DOOR_STONE + poly->seqType);
+	}
+	else if (type == PODOOR_SWING)
+	{
+		pd->waitTics = args[3];
+		pd->direction = 1; // ADD:  PODOOR_SWINGL, PODOOR_SWINGR
+		pd->speed = (args[1]*pd->direction*(ANGLE_90/64))>>3;
+		pd->totalDist = args[2]*(ANGLE_90/64);
+		pd->dist = pd->totalDist;
+		SN_StartSequence((mobj_t *)&poly->startSpot, SEQ_DOOR_STONE + poly->seqType);
+	}
+
+	poly->specialdata = pd;
+
+	while ((mirror = GetPolyobjMirror(polyNum)))
+	{
+		poly = GetPolyobj(mirror);
+		if (poly && poly->specialdata)
+		{ // mirroring poly is already in motion
+			break;
+		}
+		pd = (polydoor_t *) Z_Malloc(sizeof(polydoor_t), PU_LEVSPEC, NULL);
+		memset(pd, 0, sizeof(polydoor_t));
+		P_AddThinker(&pd->thinker);
+		pd->thinker.function = T_PolyDoor;
+		pd->polyobj = mirror;
+		pd->type = type;
+		poly->specialdata = pd;
+		if (type == PODOOR_SLIDE)
+		{
+			pd->waitTics = args[4];
+			pd->speed = args[1]*(FRACUNIT/8);
+			pd->totalDist = args[3]*FRACUNIT; // Distance
+			pd->dist = pd->totalDist;
+			an = an+ANGLE_180; // reverse the angle
+			pd->direction = an>>ANGLETOFINESHIFT;
+			pd->xSpeed = FixedMul(pd->speed, finecosine[pd->direction]);
+			pd->ySpeed = FixedMul(pd->speed, finesine[pd->direction]);
+			SN_StartSequence((mobj_t *)&poly->startSpot, SEQ_DOOR_STONE + poly->seqType);
+		}
+		else if (type == PODOOR_SWING)
+		{
+			pd->waitTics = args[3];
+			pd->direction = -1; // ADD:  same as above
+			pd->speed = (args[1]*pd->direction*(ANGLE_90/64))>>3;
+			pd->totalDist = args[2]*(ANGLE_90/64);
+			pd->dist = pd->totalDist;
+			SN_StartSequence((mobj_t *)&poly->startSpot, SEQ_DOOR_STONE + poly->seqType);
+		}
+		polyNum = mirror;
+	}
+	return true;
+}
+
+// ===== Higher Level Poly Interface code =====
+
+//==========================================================================
+//
+// GetPolyobj
+//
+//==========================================================================
+
+static polyobj_t *GetPolyobj(int polyNum)
+{
+	int i;
+
+	for (i = 0; i < po_NumPolyobjs; i++)
+	{
+		if (polyobjs[i].tag == polyNum)
+		{
+			return &polyobjs[i];
+		}
+	}
+	return NULL;
+}
+
+//==========================================================================
+//
+// GetPolyobjMirror
+//
+//==========================================================================
+
+static int GetPolyobjMirror(int poly)
+{
+	int i;
+
+	for (i = 0; i < po_NumPolyobjs; i++)
+	{
+		if (polyobjs[i].tag == poly)
+		{
+			return ((*polyobjs[i].segs)->linedef->arg2);
+		}
+	}
+	return 0;
+}
+
+//==========================================================================
+//
+// ThrustMobj
+//
+//==========================================================================
+
+static void ThrustMobj(mobj_t *mobj, seg_t *seg, polyobj_t *po)
+{
+	int thrustAngle;
+	int thrustX;
+	int thrustY;
+	polyevent_t *pe;
+	int force;
+
+	if (!(mobj->flags&MF_SHOOTABLE) && !mobj->player)
+	{
+		return;
+	}
+	thrustAngle = (seg->angle - ANGLE_90)>>ANGLETOFINESHIFT;
+
+	pe = (polyevent_t *) po->specialdata;
+	if (pe)
+	{
+		if (pe->thinker.function == T_RotatePoly)
+		{
+			force = pe->speed>>8;
+		}
+		else
+		{
+			force = pe->speed>>3;
+		}
+		if (force < FRACUNIT)
+		{
+			force = FRACUNIT;
+		}
+		else if (force > 4*FRACUNIT)
+		{
+			force = 4*FRACUNIT;
+		}
+	}
+	else
+	{
+		force = FRACUNIT;
+	}
+
+	thrustX = FixedMul(force, finecosine[thrustAngle]);
+	thrustY = FixedMul(force, finesine[thrustAngle]);
+	mobj->momx += thrustX;
+	mobj->momy += thrustY;
+	if (po->crush)
+	{
+		if (!P_CheckPosition(mobj, mobj->x + thrustX, mobj->y + thrustY))
+		{
+			P_DamageMobj(mobj, NULL, NULL, 3);
+		}
+	}
+}
+
+//==========================================================================
+//
+// UpdateSegBBox
+//
+//==========================================================================
+
+static void UpdateSegBBox(seg_t *seg)
+{
+	line_t *line;
+
+	line = seg->linedef;
+
+	if (seg->v1->x < seg->v2->x)
+	{
+		line->bbox[BOXLEFT] = seg->v1->x;
+		line->bbox[BOXRIGHT] = seg->v2->x;
+	}
+	else
+	{
+		line->bbox[BOXLEFT] = seg->v2->x;
+		line->bbox[BOXRIGHT] = seg->v1->x;
+	}
+	if (seg->v1->y < seg->v2->y)
+	{
+		line->bbox[BOXBOTTOM] = seg->v1->y;
+		line->bbox[BOXTOP] = seg->v2->y;
+	}
+	else
+	{
+		line->bbox[BOXBOTTOM] = seg->v2->y;
+		line->bbox[BOXTOP] = seg->v1->y;
+	}
+
+	// Update the line's slopetype
+	line->dx = line->v2->x - line->v1->x;
+	line->dy = line->v2->y - line->v1->y;
+	if (!line->dx)
+	{
+		line->slopetype = ST_VERTICAL;
+	}
+	else if (!line->dy)
+	{
+		line->slopetype = ST_HORIZONTAL;
+	}
+	else
+	{
+		if (FixedDiv(line->dy, line->dx) > 0)
+		{
+			line->slopetype = ST_POSITIVE;
+		}
+		else
+		{
+			line->slopetype = ST_NEGATIVE;
+		}
+	}
+}
+
+//==========================================================================
+//
+// PO_MovePolyobj
+//
+//==========================================================================
+
+boolean PO_MovePolyobj(int num, int x, int y)
+{
+	int count;
+	seg_t **segList;
+	seg_t **veryTempSeg;
+	polyobj_t *po;
+	vertex_t *prevPts;
+	boolean blocked;
+
+	if (!(po = GetPolyobj(num)))
+	{
+		I_Error("PO_MovePolyobj:  Invalid polyobj number: %d\n", num);
+	}
+
+	UnLinkPolyobj(po);
+
+	segList = po->segs;
+	prevPts = po->prevPts;
+	blocked = false;
+
+	validcount++;
+	for (count = po->numsegs; count; count--, segList++, prevPts++)
+	{
+		if ((*segList)->linedef->validcount != validcount)
+		{
+			(*segList)->linedef->bbox[BOXTOP] += y;
+			(*segList)->linedef->bbox[BOXBOTTOM] += y;
+			(*segList)->linedef->bbox[BOXLEFT] += x;
+			(*segList)->linedef->bbox[BOXRIGHT] += x;
+			(*segList)->linedef->validcount = validcount;
+		}
+		for (veryTempSeg = po->segs; veryTempSeg != segList; veryTempSeg++)
+		{
+			if ((*veryTempSeg)->v1 == (*segList)->v1)
+			{
+				break;
+			}
+		}
+		if (veryTempSeg == segList)
+		{
+			(*segList)->v1->x += x;
+			(*segList)->v1->y += y;
+		}
+		(*prevPts).x += x;	// previous points are unique for each seg
+		(*prevPts).y += y;
+	}
+	segList = po->segs;
+	for (count = po->numsegs; count; count--, segList++)
+	{
+		if (CheckMobjBlocking(*segList, po))
+		{
+			blocked = true;
+		}
+	}
+	if (blocked)
+	{
+		count = po->numsegs;
+		segList = po->segs;
+		prevPts = po->prevPts;
+		validcount++;
+		while (count--)
+		{
+			if ((*segList)->linedef->validcount != validcount)
+			{
+				(*segList)->linedef->bbox[BOXTOP] -= y;
+				(*segList)->linedef->bbox[BOXBOTTOM] -= y;
+				(*segList)->linedef->bbox[BOXLEFT] -= x;
+				(*segList)->linedef->bbox[BOXRIGHT] -= x;
+				(*segList)->linedef->validcount = validcount;
+			}
+			for (veryTempSeg = po->segs; veryTempSeg != segList; veryTempSeg++)
+			{
+				if ((*veryTempSeg)->v1 == (*segList)->v1)
+				{
+					break;
+				}
+			}
+			if (veryTempSeg == segList)
+			{
+				(*segList)->v1->x -= x;
+				(*segList)->v1->y -= y;
+			}
+			(*prevPts).x -= x;
+			(*prevPts).y -= y;
+			segList++;
+			prevPts++;
+		}
+		LinkPolyobj(po);
+		return false;
+	}
+	po->startSpot.x += x;
+	po->startSpot.y += y;
+	LinkPolyobj(po);
+	return true;
+}
+
+//==========================================================================
+//
+// RotatePt
+//
+//==========================================================================
+
+static void RotatePt(int an, fixed_t *x, fixed_t *y, fixed_t startSpotX, fixed_t startSpotY)
+{
+	fixed_t xtr, ytr;
+	fixed_t gxt, gyt;
+
+	xtr = *x;
+	ytr = *y;
+
+	gxt = FixedMul(xtr, finecosine[an]);
+	gyt = FixedMul(ytr, finesine[an]);
+	*x = (gxt - gyt) + startSpotX;
+
+	gxt = FixedMul(xtr, finesine[an]);
+	gyt = FixedMul(ytr, finecosine[an]);
+	*y = (gyt + gxt) + startSpotY;
+}
+
+//==========================================================================
+//
+// PO_RotatePolyobj
+//
+//==========================================================================
+
+boolean PO_RotatePolyobj(int num, angle_t angle)
+{
+	int count;
+	seg_t **segList;
+	vertex_t *originalPts;
+	vertex_t *prevPts;
+	int an;
+	polyobj_t *po;
+	boolean blocked;
+
+	if (!(po = GetPolyobj(num)))
+	{
+		I_Error("PO_RotatePolyobj:  Invalid polyobj number: %d\n", num);
+	}
+	an = (po->angle + angle)>>ANGLETOFINESHIFT;
+
+	UnLinkPolyobj(po);
+
+	segList = po->segs;
+	originalPts = po->originalPts;
+	prevPts = po->prevPts;
+
+	for (count = po->numsegs; count; count--, segList++, originalPts++, prevPts++)
+	{
+		prevPts->x = (*segList)->v1->x;
+		prevPts->y = (*segList)->v1->y;
+		(*segList)->v1->x = originalPts->x;
+		(*segList)->v1->y = originalPts->y;
+		RotatePt(an, &(*segList)->v1->x, &(*segList)->v1->y, po->startSpot.x, po->startSpot.y);
+	}
+	segList = po->segs;
+	blocked = false;
+	validcount++;
+	for (count = po->numsegs; count; count--, segList++)
+	{
+		if (CheckMobjBlocking(*segList, po))
+		{
+			blocked = true;
+		}
+		if ((*segList)->linedef->validcount != validcount)
+		{
+			UpdateSegBBox(*segList);
+			(*segList)->linedef->validcount = validcount;
+		}
+		(*segList)->angle += angle;
+	}
+	if (blocked)
+	{
+		segList = po->segs;
+		prevPts = po->prevPts;
+		for (count = po->numsegs; count; count--, segList++, prevPts++)
+		{
+			(*segList)->v1->x = prevPts->x;
+			(*segList)->v1->y = prevPts->y;
+		}
+		segList = po->segs;
+		validcount++;
+		for (count = po->numsegs; count; count--, segList++, prevPts++)
+		{
+			if ((*segList)->linedef->validcount != validcount)
+			{
+				UpdateSegBBox(*segList);
+				(*segList)->linedef->validcount = validcount;
+			}
+			(*segList)->angle -= angle;
+		}
+		LinkPolyobj(po);
+		return false;
+	}
+	po->angle += angle;
+	LinkPolyobj(po);
+	return true;
+}
+
+//==========================================================================
+//
+// UnLinkPolyobj
+//
+//==========================================================================
+
+static void UnLinkPolyobj(polyobj_t *po)
+{
+	polyblock_t *link;
+	int i, j;
+	int idx;
+
+	// remove the polyobj from each blockmap section
+	for (j = po->bbox[BOXBOTTOM]; j <= po->bbox[BOXTOP]; j++)
+	{
+		idx = j * bmapwidth;
+		for (i = po->bbox[BOXLEFT]; i <= po->bbox[BOXRIGHT]; i++)
+		{
+			if (i >= 0 && i < bmapwidth && j >= 0 && j < bmapheight)
+			{
+				link = PolyBlockMap[idx + i];
+				while (link != NULL && link->polyobj != po)
+				{
+					link = link->next;
+				}
+				if (link == NULL)
+				{ // polyobj not located in the link cell
+					continue;
+				}
+				link->polyobj = NULL;
+			}
+		}
+	}
+}
+
+//==========================================================================
+//
+// LinkPolyobj
+//
+//==========================================================================
+
+static void LinkPolyobj(polyobj_t *po)
+{
+	int leftX, rightX;
+	int topY, bottomY;
+	seg_t **tempSeg;
+	polyblock_t **link;
+	polyblock_t *tempLink;
+	int i, j;
+
+	// calculate the polyobj bbox
+	tempSeg = po->segs;
+	rightX = leftX = (*tempSeg)->v1->x;
+	topY = bottomY = (*tempSeg)->v1->y;
+
+	for (i = 0; i < po->numsegs; i++, tempSeg++)
+	{
+		if ((*tempSeg)->v1->x > rightX)
+		{
+			rightX = (*tempSeg)->v1->x;
+		}
+		if ((*tempSeg)->v1->x < leftX)
+		{
+			leftX = (*tempSeg)->v1->x;
+		}
+		if ((*tempSeg)->v1->y > topY)
+		{
+			topY = (*tempSeg)->v1->y;
+		}
+		if ((*tempSeg)->v1->y < bottomY)
+		{
+			bottomY = (*tempSeg)->v1->y;
+		}
+	}
+	po->bbox[BOXRIGHT] = (rightX - bmaporgx)>>MAPBLOCKSHIFT;
+	po->bbox[BOXLEFT] = (leftX - bmaporgx)>>MAPBLOCKSHIFT;
+	po->bbox[BOXTOP] = (topY - bmaporgy)>>MAPBLOCKSHIFT;
+	po->bbox[BOXBOTTOM] = (bottomY - bmaporgy)>>MAPBLOCKSHIFT;
+	// add the polyobj to each blockmap section
+	for (j = po->bbox[BOXBOTTOM]*bmapwidth; j <= po->bbox[BOXTOP]*bmapwidth;
+								j += bmapwidth)
+	{
+		for (i = po->bbox[BOXLEFT]; i <= po->bbox[BOXRIGHT]; i++)
+		{
+			if (i >= 0 && i < bmapwidth && j >= 0 && j < bmapheight*bmapwidth)
+			{
+				link = &PolyBlockMap[j + i];
+				if (!(*link))
+				{ // Create a new link at the current block cell
+					*link = (polyblock_t *) Z_Malloc(sizeof(polyblock_t), PU_LEVEL, NULL);
+					(*link)->next = NULL;
+					(*link)->prev = NULL;
+					(*link)->polyobj = po;
+					continue;
+				}
+				else
+				{
+					tempLink = *link;
+					while (tempLink->next != NULL && tempLink->polyobj != NULL)
+					{
+						tempLink = tempLink->next;
+					}
+				}
+				if (tempLink->polyobj == NULL)
+				{
+					tempLink->polyobj = po;
+					continue;
+				}
+				else
+				{
+					tempLink->next = (polyblock_t *) Z_Malloc(sizeof(polyblock_t), PU_LEVEL, NULL);
+					tempLink->next->next = NULL;
+					tempLink->next->prev = tempLink;
+					tempLink->next->polyobj = po;
+				}
+			}
+			// else, don't link the polyobj, since it's off the map
+		}
+	}
+}
+
+//==========================================================================
+//
+// CheckMobjBlocking
+//
+//==========================================================================
+
+static boolean CheckMobjBlocking(seg_t *seg, polyobj_t *po)
+{
+	mobj_t *mobj;
+	int i, j;
+	int left, right, top, bottom;
+	int tmbbox[4];
+	line_t *ld;
+	boolean blocked;
+
+	ld = seg->linedef;
+
+	top = (ld->bbox[BOXTOP] - bmaporgy + MAXRADIUS)>>MAPBLOCKSHIFT;
+	bottom = (ld->bbox[BOXBOTTOM] - bmaporgy - MAXRADIUS)>>MAPBLOCKSHIFT;
+	left = (ld->bbox[BOXLEFT] - bmaporgx - MAXRADIUS)>>MAPBLOCKSHIFT;
+	right = (ld->bbox[BOXRIGHT] - bmaporgx + MAXRADIUS)>>MAPBLOCKSHIFT;
+
+	blocked = false;
+
+	bottom = bottom < 0 ? 0 : bottom;
+	bottom = bottom >= bmapheight ? bmapheight - 1 : bottom;
+	top = top < 0 ? 0 : top;
+	top = top >= bmapheight  ? bmapheight - 1 : top;
+	left = left < 0 ? 0 : left;
+	left = left >= bmapwidth ? bmapwidth - 1 : left;
+	right = right < 0 ? 0 : right;
+	right = right >= bmapwidth ?  bmapwidth - 1 : right;
+
+	for (j = bottom*bmapwidth; j <= top*bmapwidth; j += bmapwidth)
+	{
+		for (i = left; i <= right; i++)
+		{
+			for (mobj = blocklinks[j+i]; mobj; mobj = mobj->bnext)
+			{
+				if (mobj->flags&MF_SOLID || mobj->player)
+				{
+					tmbbox[BOXTOP] = mobj->y + mobj->radius;
+					tmbbox[BOXBOTTOM] = mobj->y - mobj->radius;
+					tmbbox[BOXLEFT] = mobj->x - mobj->radius;
+					tmbbox[BOXRIGHT] = mobj->x + mobj->radius;
+
+					if (tmbbox[BOXRIGHT] <= ld->bbox[BOXLEFT]
+						|| tmbbox[BOXLEFT] >= ld->bbox[BOXRIGHT]
+						|| tmbbox[BOXTOP] <= ld->bbox[BOXBOTTOM]
+						|| tmbbox[BOXBOTTOM] >= ld->bbox[BOXTOP])
+					{
+						continue;
+					}
+					if (P_BoxOnLineSide(tmbbox, ld) != -1)
+					{
+						continue;
+					}
+					ThrustMobj(mobj, seg, po);
+					blocked = true;
+				}
+			}
+		}
+	}
+	return blocked;
+}
+
+//==========================================================================
+//
+// InitBlockMap
+//
+//==========================================================================
+
+static void InitBlockMap(void)
+{
+	int i;
+	int j;
+	seg_t **segList;
+//	int area;
+	int leftX, rightX;
+	int topY, bottomY;
+
+	PolyBlockMap = (polyblock_t **) Z_Malloc(bmapwidth*bmapheight*sizeof(polyblock_t *), PU_LEVEL, NULL);
+	memset(PolyBlockMap, 0, bmapwidth*bmapheight*sizeof(polyblock_t *));
+
+	for (i = 0; i < po_NumPolyobjs; i++)
+	{
+		LinkPolyobj(&polyobjs[i]);
+
+		// calculate a rough area
+		// right now, working like shit...gotta fix this...
+		segList = polyobjs[i].segs;
+		leftX = rightX = (*segList)->v1->x;
+		topY = bottomY = (*segList)->v1->y;
+		for (j = 0; j < polyobjs[i].numsegs; j++, segList++)
+		{
+			if ((*segList)->v1->x < leftX)
+			{
+				leftX = (*segList)->v1->x;
+			}
+			if ((*segList)->v1->x > rightX)
+			{
+				rightX = (*segList)->v1->x;
+			}
+			if ((*segList)->v1->y < bottomY)
+			{
+				bottomY = (*segList)->v1->y;
+			}
+			if ((*segList)->v1->y > topY)
+			{
+				topY = (*segList)->v1->y;
+			}
+		}
+//		area = ((rightX>>FRACBITS) - (leftX>>FRACBITS)) * ((topY>>FRACBITS) - (bottomY>>FRACBITS));
+//		fprintf(stdaux, "Area of Polyobj[%d]: %d\n", polyobjs[i].tag, area);
+//		fprintf(stdaux, "\t[%d]\n[%d]\t\t[%d]\n\t[%d]\n",
+//				 topY>>FRACBITS, leftX>>FRACBITS,
+//				 rightX>>FRACBITS, bottomY>>FRACBITS);
+	}
+}
+
+//==========================================================================
+//
+// IterFindPolySegs
+//
+// Passing NULL for segList will cause IterFindPolySegs to
+// count the number of segs in the polyobj
+//==========================================================================
+
+static void IterFindPolySegs(int x, int y, seg_t **segList)
+{
+	int i;
+
+	if (x == PolyStartX && y == PolyStartY)
+	{
+		return;
+	}
+	for (i = 0; i < numsegs; i++)
+	{
+		if (segs[i].v1->x == x && segs[i].v1->y == y)
+		{
+			if (!segList)
+			{
+				PolySegCount++;
+			}
+			else
+			{
+				*segList++ = &segs[i];
+			}
+			IterFindPolySegs(segs[i].v2->x, segs[i].v2->y, segList);
+			return;
+		}
+	}
+	I_Error("IterFindPolySegs:  Non-closed Polyobj located.\n");
+}
+
+
+//==========================================================================
+//
+// SpawnPolyobj
+//
+//==========================================================================
+
+static void SpawnPolyobj(int idx, int tag, boolean crush)
+{
+	int i;
+	int j;
+	int psIndex;
+	int psIndexOld;
+	seg_t *polySegList[PO_MAXPOLYSEGS];
+
+	for (i = 0; i < numsegs; i++)
+	{
+		if (segs[i].linedef->special == PO_LINE_START &&
+			segs[i].linedef->arg1 == tag)
+		{
+			if (polyobjs[idx].segs)
+			{
+				I_Error("SpawnPolyobj:  Polyobj %d already spawned.\n", tag);
+			}
+			segs[i].linedef->special = 0;
+			segs[i].linedef->arg1 = 0;
+			PolySegCount = 1;
+			PolyStartX = segs[i].v1->x;
+			PolyStartY = segs[i].v1->y;
+			IterFindPolySegs(segs[i].v2->x, segs[i].v2->y, NULL);
+
+			polyobjs[idx].numsegs = PolySegCount;
+			polyobjs[idx].segs = (seg_t **) Z_Malloc(PolySegCount*sizeof(seg_t *), PU_LEVEL, NULL);
+			*(polyobjs[idx].segs) = &segs[i]; // insert the first seg
+			IterFindPolySegs(segs[i].v2->x, segs[i].v2->y, polyobjs[idx].segs + 1);
+			polyobjs[idx].crush = crush;
+			polyobjs[idx].tag = tag;
+			polyobjs[idx].seqType = segs[i].linedef->arg3;
+			if (polyobjs[idx].seqType < 0 
+				|| polyobjs[idx].seqType >= SEQTYPE_NUMSEQ)
+			{
+				polyobjs[idx].seqType = 0;
+			}
+			break;
+		}
+	}
+	if (!polyobjs[idx].segs)
+	{ // didn't find a polyobj through PO_LINE_START
+		psIndex = 0;
+		polyobjs[idx].numsegs = 0;
+		for (j = 1; j < PO_MAXPOLYSEGS; j++)
+		{
+			psIndexOld = psIndex;
+			for (i = 0; i < numsegs; i++)
+			{
+				if (segs[i].linedef->special == PO_LINE_EXPLICIT &&
+					segs[i].linedef->arg1 == tag)
+				{
+					if (!segs[i].linedef->arg2)
+					{
+						I_Error("SpawnPolyobj:  Explicit line missing order number (probably %d) in poly %d.\n",
+							j + 1, tag);
+					}
+					if (segs[i].linedef->arg2 == j)
+					{
+						polySegList[psIndex] = &segs[i];
+						polyobjs[idx].numsegs++;
+						psIndex++;
+						if (psIndex > PO_MAXPOLYSEGS)
+						{
+							I_Error("SpawnPolyobj:  psIndex > PO_MAXPOLYSEGS\n");
+						}
+					}
+				}
+			}
+			// Clear out any specials for these segs...we cannot clear them out
+			//	in the above loop, since we aren't guaranteed one seg per
+			//		linedef.
+			for (i = 0; i < numsegs; i++)
+			{
+				if (segs[i].linedef->special == PO_LINE_EXPLICIT &&
+					segs[i].linedef->arg1 == tag && segs[i].linedef->arg2 == j)
+				{
+					segs[i].linedef->special = 0;
+					segs[i].linedef->arg1 = 0;
+				}
+			}
+			if (psIndex == psIndexOld)
+			{ // Check if an explicit line order has been skipped
+				// A line has been skipped if there are any more explicit
+				// lines with the current tag value
+				for (i = 0; i < numsegs; i++)
+				{
+					if (segs[i].linedef->special == PO_LINE_EXPLICIT &&
+						segs[i].linedef->arg1 == tag)
+					{
+						I_Error("SpawnPolyobj:  Missing explicit line %d for poly %d\n",
+							j, tag);
+					}
+				}
+			}
+		}
+		if (polyobjs[idx].numsegs)
+		{
+			PolySegCount = polyobjs[idx].numsegs; // PolySegCount used globally
+			polyobjs[idx].crush = crush;
+			polyobjs[idx].tag = tag;
+			polyobjs[idx].segs = (seg_t **) Z_Malloc(polyobjs[idx].numsegs*sizeof(seg_t *), PU_LEVEL, NULL);
+			for (i = 0; i < polyobjs[idx].numsegs; i++)
+			{
+				polyobjs[idx].segs[i] = polySegList[i];
+			}
+			polyobjs[idx].seqType = (*polyobjs[idx].segs)->linedef->arg4;
+		}
+		// Next, change the polyobjs first line to point to a mirror
+		//		if it exists
+		(*polyobjs[idx].segs)->linedef->arg2 = (*polyobjs[idx].segs)->linedef->arg3;
+	}
+}
+
+//==========================================================================
+//
+// TranslateToStartSpot
+//
+//==========================================================================
+
+static void TranslateToStartSpot(int tag, int originX, int originY)
+{
+	seg_t **tempSeg;
+	seg_t **veryTempSeg;
+	vertex_t *tempPt;
+	subsector_t *sub;
+	polyobj_t *po;
+	int deltaX;
+	int deltaY;
+	vertex_t avg; // used to find a polyobj's center, and hence subsector
+	int i;
+
+	po = NULL;
+	for (i = 0; i < po_NumPolyobjs; i++)
+	{
+		if (polyobjs[i].tag == tag)
+		{
+			po = &polyobjs[i];
+			break;
+		}
+	}
+	if (!po)
+	{ // didn't match the tag with a polyobj tag
+		I_Error("TranslateToStartSpot:  Unable to match polyobj tag: %d\n", tag);
+	}
+	if (po->segs == NULL)
+	{
+		I_Error("TranslateToStartSpot:  Anchor point located without a StartSpot point: %d\n", tag);
+	}
+	po->originalPts = (vertex_t *) Z_Malloc(po->numsegs*sizeof(vertex_t), PU_LEVEL, NULL);
+	po->prevPts = (vertex_t *) Z_Malloc(po->numsegs*sizeof(vertex_t), PU_LEVEL, NULL);
+	deltaX = originX-po->startSpot.x;
+	deltaY = originY-po->startSpot.y;
+
+	tempSeg = po->segs;
+	tempPt = po->originalPts;
+	avg.x = 0;
+	avg.y = 0;
+
+	validcount++;
+	for (i = 0; i < po->numsegs; i++, tempSeg++, tempPt++)
+	{
+		if ((*tempSeg)->linedef->validcount != validcount)
+		{
+			(*tempSeg)->linedef->bbox[BOXTOP] -= deltaY;
+			(*tempSeg)->linedef->bbox[BOXBOTTOM] -= deltaY;
+			(*tempSeg)->linedef->bbox[BOXLEFT] -= deltaX;
+			(*tempSeg)->linedef->bbox[BOXRIGHT] -= deltaX;
+			(*tempSeg)->linedef->validcount = validcount;
+		}
+		for (veryTempSeg = po->segs; veryTempSeg != tempSeg; veryTempSeg++)
+		{
+			if ((*veryTempSeg)->v1 == (*tempSeg)->v1)
+			{
+				break;
+			}
+		}
+		if (veryTempSeg == tempSeg)
+		{ // the point hasn't been translated, yet
+			(*tempSeg)->v1->x -= deltaX;
+			(*tempSeg)->v1->y -= deltaY;
+		}
+		avg.x += (*tempSeg)->v1->x>>FRACBITS;
+		avg.y += (*tempSeg)->v1->y>>FRACBITS;
+		// the original Pts are based off the startSpot Pt, and are
+		// unique to each seg, not each linedef
+		tempPt->x = (*tempSeg)->v1->x - po->startSpot.x;
+		tempPt->y = (*tempSeg)->v1->y - po->startSpot.y;
+	}
+	avg.x /= po->numsegs;
+	avg.y /= po->numsegs;
+	sub = R_PointInSubsector(avg.x<<FRACBITS, avg.y<<FRACBITS);
+	if (sub->poly != NULL)
+	{
+		I_Error("PO_TranslateToStartSpot:  Multiple polyobjs in a single subsector.\n");
+	}
+	sub->poly = po;
+}
+
+//==========================================================================
+//
+// PO_Init
+//
+//==========================================================================
+
+void PO_Init(int lump)
+{
+	void		*data;
+	int		i;
+	mapthing_t	*mt;
+	int		numthings;
+	int		polyIndex;
+
+	polyobjs = (polyobj_t *) Z_Malloc(po_NumPolyobjs*sizeof(polyobj_t), PU_LEVEL, NULL);
+	memset(polyobjs, 0, po_NumPolyobjs*sizeof(polyobj_t));
+
+	data = W_CacheLumpNum(lump, PU_STATIC);
+	numthings = W_LumpLength(lump)/sizeof(mapthing_t);
+	mt = (mapthing_t *)data;
+	polyIndex = 0; // index polyobj number
+	// Find the startSpot points, and spawn each polyobj
+	for (i = 0; i < numthings; i++, mt++)
+	{
+		mt->x = SHORT(mt->x);
+		mt->y = SHORT(mt->y);
+		mt->angle = SHORT(mt->angle);
+		mt->type = SHORT(mt->type);
+
+		// 3001 = no crush, 3002 = crushing
+		if (mt->type == PO_SPAWN_TYPE || mt->type == PO_SPAWNCRUSH_TYPE)
+		{ // Polyobj StartSpot Pt.
+			polyobjs[polyIndex].startSpot.x = mt->x<<FRACBITS;
+			polyobjs[polyIndex].startSpot.y = mt->y<<FRACBITS;
+			SpawnPolyobj(polyIndex, mt->angle, (mt->type == PO_SPAWNCRUSH_TYPE));
+			polyIndex++;
+		}
+	}
+	mt = (mapthing_t *)data;
+	for (i = 0; i < numthings; i++, mt++)
+	{
+		/* NOTE: we byte swapped the fields in
+		the above loop, don't swap here again */
+		if (mt->type == PO_ANCHOR_TYPE)
+		{ // Polyobj Anchor Pt.
+			TranslateToStartSpot(mt->angle, mt->x<<FRACBITS, mt->y<<FRACBITS);
+		}
+	}
+	Z_Free (data);
+	// check for a startspot without an anchor point
+	for (i = 0; i < po_NumPolyobjs; i++)
+	{
+		if (!polyobjs[i].originalPts)
+		{
+			I_Error("PO_Init:  StartSpot located without an Anchor point: %d\n",
+				polyobjs[i].tag);
+		}
+	}
+	InitBlockMap();
+}
+
+//==========================================================================
+//
+// PO_Busy
+//
+//==========================================================================
+
+boolean PO_Busy(int polyobj)
+{
+	polyobj_t *poly;
+
+	poly = GetPolyobj(polyobj);
+	if (!poly->specialdata)
+	{
+		return false;
+	}
+	else
+	{
+		return true;
+	}
+}
+
--- /dev/null
+++ b/r_bsp.c
@@ -1,0 +1,491 @@
+
+//**************************************************************************
+//**
+//** r_bsp.c : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 373 $
+//** $Date: 2009-05-19 21:14:28 +0300 (Tue, 19 May 2009) $
+//**
+//**************************************************************************
+
+#include "h2stdinc.h"
+
+#ifndef RENDER3D
+
+#include "h2def.h"
+#include "r_local.h"
+
+seg_t		*curline;
+side_t		*sidedef;
+line_t		*linedef;
+sector_t	*frontsector, *backsector;
+
+drawseg_t	drawsegs[MAXDRAWSEGS], *ds_p;
+
+void R_StoreWallRange (int start, int stop);	/* r_segs.c */
+
+/*
+====================
+=
+= R_ClearDrawSegs
+=
+====================
+*/
+
+void R_ClearDrawSegs (void)
+{
+	ds_p = drawsegs;
+}
+
+//=============================================================================
+
+
+/*
+===============================================================================
+=
+= ClipWallSegment
+=
+= Clips the given range of columns and includes it in the new clip list
+===============================================================================
+*/
+
+typedef struct
+{
+	int	first, last;
+} cliprange_t;
+
+#define MAXSEGS		32
+
+static cliprange_t	solidsegs[MAXSEGS], *newend;	// newend is one past the last valid seg
+
+
+static void R_ClipSolidWallSegment (int first, int last)
+{
+	cliprange_t	*next, *start;
+
+// find the first range that touches the range (adjacent pixels are touching)
+	start = solidsegs;
+	while (start->last < first - 1)
+		start++;
+
+	if (first < start->first)
+	{
+		if (last < start->first - 1)
+		{	// post is entirely visible (above start), so insert a new clippost
+			R_StoreWallRange (first, last);
+			next = newend;
+			newend++;
+			while (next != start)
+			{
+				*next = *(next - 1);
+				next--;
+			}
+			next->first = first;
+			next->last = last;
+			return;
+		}
+
+		// there is a fragment above *start
+		R_StoreWallRange (first, start->first - 1);
+		start->first = first;		// adjust the clip size
+	}
+
+	if (last <= start->last)
+		return;			// bottom contained in start
+
+	next = start;
+	while (last >= (next + 1)->first - 1)
+	{
+		// there is a fragment between two posts
+		R_StoreWallRange (next->last + 1, (next + 1)->first - 1);
+		next++;
+		if (last <= next->last)
+		{	// bottom is contained in next
+			start->last = next->last;	// adjust the clip size
+			goto crunch;
+		}
+	}
+
+	// there is a fragment after *next
+	R_StoreWallRange (next->last + 1, last);
+	start->last = last;		// adjust the clip size
+
+// remove start+1 to next from the clip list,
+// because start now covers their area
+crunch:
+	if (next == start)
+		return;			// post just extended past the bottom of one post
+
+	while (next++ != newend)	// remove a post
+		*++start = *next;
+	newend = start + 1;
+}
+
+/*
+===============================================================================
+=
+= R_ClipPassWallSegment
+=
+= Clips the given range of columns, but does not includes it in the clip list
+===============================================================================
+*/
+
+static void R_ClipPassWallSegment (int first, int last)
+{
+	cliprange_t	*start;
+
+// find the first range that touches the range (adjacent pixels are touching)
+	start = solidsegs;
+	while (start->last < first - 1)
+		start++;
+
+	if (first < start->first)
+	{
+		if (last < start->first - 1)
+		{	// post is entirely visible (above start)
+			R_StoreWallRange (first, last);
+			return;
+		}
+
+		// there is a fragment above *start
+		R_StoreWallRange (first, start->first - 1);
+	}
+
+	if (last <= start->last)
+		return;			// bottom contained in start
+
+	while (last >= (start + 1)->first - 1)
+	{
+		// there is a fragment between two posts
+		R_StoreWallRange (start->last + 1, (start + 1)->first - 1);
+		start++;
+		if (last <= start->last)
+			return;
+	}
+
+	// there is a fragment after *next
+	R_StoreWallRange (start->last + 1, last);
+}
+
+
+/*
+====================
+=
+= R_ClearClipSegs
+=
+====================
+*/
+
+void R_ClearClipSegs (void)
+{
+	solidsegs[0].first = -0x7fffffff;
+	solidsegs[0].last = -1;
+	solidsegs[1].first = viewwidth;
+	solidsegs[1].last = 0x7fffffff;
+	newend = solidsegs + 2;
+}
+
+
+//=============================================================================
+
+/*
+======================
+=
+= R_AddLine
+=
+= Clips the given segment and adds any visible pieces to the line list
+=
+======================
+*/
+
+static void R_AddLine (seg_t *line)
+{
+	int		x1, x2;
+	angle_t		angle1, angle2, span, tspan;
+
+	curline = line;
+
+// OPTIMIZE: quickly reject orthogonal back sides
+
+	angle1 = R_PointToAngle (line->v1->x, line->v1->y);
+	angle2 = R_PointToAngle (line->v2->x, line->v2->y);
+
+//
+// clip to view edges
+// OPTIMIZE: make constant out of 2*clipangle (FIELDOFVIEW)
+	span = angle1 - angle2;
+	if (span >= ANG180)
+		return;		// back side
+
+	rw_angle1 = angle1;	// global angle needed by segcalc
+	angle1 -= viewangle;
+	angle2 -= viewangle;
+
+	tspan = angle1 + clipangle;
+	if (tspan > 2*clipangle)
+	{
+		tspan -= 2*clipangle;
+		if (tspan >= span)
+			return;	// totally off the left edge
+		angle1 = clipangle;
+	}
+	tspan = clipangle - angle2;
+	if (tspan > 2*clipangle)
+	{
+		tspan -= 2*clipangle;
+		if (tspan >= span)
+			return;	// totally off the left edge
+		angle2 = -clipangle;
+	}
+
+//
+// the seg is in the view range, but not necessarily visible
+//
+	angle1 = (angle1 + ANG90)>>ANGLETOFINESHIFT;
+	angle2 = (angle2 + ANG90)>>ANGLETOFINESHIFT;
+	x1 = viewangletox[angle1];
+	x2 = viewangletox[angle2];
+	if (x1 == x2)
+		return;		// does not cross a pixel
+
+	backsector = line->backsector;
+
+	if (!backsector)
+		goto clipsolid;	// single sided line
+
+	if (backsector->ceilingheight <= frontsector->floorheight ||
+	    backsector->floorheight >= frontsector->ceilingheight)
+		goto clipsolid;	// closed door
+
+	if (backsector->ceilingheight != frontsector->ceilingheight ||
+	    backsector->floorheight != frontsector->floorheight)
+		goto clippass;	// window
+
+// reject empty lines used for triggers and special events
+	if (backsector->ceilingpic == frontsector->ceilingpic &&
+	    backsector->floorpic == frontsector->floorpic &&
+	    backsector->lightlevel == frontsector->lightlevel &&
+	    backsector->special == frontsector->special &&
+	    curline->sidedef->midtexture == 0)
+		return;
+
+clippass:
+	R_ClipPassWallSegment (x1, x2 - 1);
+	return;
+
+clipsolid:
+	R_ClipSolidWallSegment (x1, x2 - 1);
+}
+
+//============================================================================
+
+
+/*
+===============================================================================
+=
+= R_CheckBBox
+=
+= Returns true if some part of the bbox might be visible
+=
+===============================================================================
+*/
+
+static int checkcoord[12][4] =
+{
+	{3,0, 2,1},
+	{3,0, 2,0},
+	{3,1, 2,0},
+	{0},
+	{2,0, 2,1},
+	{0,0,0,0},
+	{3,1, 3,0},
+	{0},
+	{2,0, 3,1},
+	{2,1, 3,1},
+	{2,1, 3,0}
+};
+
+static boolean R_CheckBBox (fixed_t *bspcoord)
+{
+	int		boxx, boxy, boxpos;
+	fixed_t		x1, y1, x2, y2;
+	angle_t		angle1, angle2, span, tspan;
+	cliprange_t	*start;
+	int		sx1, sx2;
+
+// find the corners of the box that define the edges from current viewpoint
+	if (viewx <= bspcoord[BOXLEFT])
+		boxx = 0;
+	else if (viewx < bspcoord[BOXRIGHT])
+		boxx = 1;
+	else
+		boxx = 2;
+
+	if (viewy >= bspcoord[BOXTOP])
+		boxy = 0;
+	else if (viewy > bspcoord[BOXBOTTOM])
+		boxy = 1;
+	else
+		boxy = 2;
+
+	boxpos = (boxy<<2) + boxx;
+	if (boxpos == 5)
+		return true;
+
+	x1 = bspcoord[checkcoord[boxpos][0]];
+	y1 = bspcoord[checkcoord[boxpos][1]];
+	x2 = bspcoord[checkcoord[boxpos][2]];
+	y2 = bspcoord[checkcoord[boxpos][3]];
+
+//
+// check clip list for an open space
+//
+	angle1 = R_PointToAngle (x1, y1) - viewangle;
+	angle2 = R_PointToAngle (x2, y2) - viewangle;
+
+	span = angle1 - angle2;
+	if (span >= ANG180)
+		return true;	// sitting on a line
+	tspan = angle1 + clipangle;
+	if (tspan > 2*clipangle)
+	{
+		tspan -= 2*clipangle;
+		if (tspan >= span)
+			return false;	// totally off the left edge
+		angle1 = clipangle;
+	}
+	tspan = clipangle - angle2;
+	if (tspan > 2*clipangle)
+	{
+		tspan -= 2*clipangle;
+		if (tspan >= span)
+			return false;	// totally off the left edge
+		angle2 = -clipangle;
+	}
+
+// find the first clippost that touches the source post (adjacent pixels are touching)
+	angle1 = (angle1 + ANG90)>>ANGLETOFINESHIFT;
+	angle2 = (angle2 + ANG90)>>ANGLETOFINESHIFT;
+	sx1 = viewangletox[angle1];
+	sx2 = viewangletox[angle2];
+	if (sx1 == sx2)
+		return false;		// does not cross a pixel
+	sx2--;
+
+	start = solidsegs;
+	while (start->last < sx2)
+		start++;
+	if (sx1 >= start->first && sx2 <= start->last)
+		return false;		// the clippost contains the new span
+
+	return true;
+}
+
+
+/*
+================
+=
+= R_Subsector
+=
+= Draw one or more segments
+================
+*/
+
+static void R_Subsector (int num)
+{
+	int		count;
+	seg_t		*line;
+	subsector_t	*sub;
+	int		polyCount;
+	seg_t		**polySeg;
+
+#ifdef RANGECHECK
+	if (num >= numsubsectors)
+		I_Error ("R_Subsector: ss %i with numss = %i", num, numsubsectors);
+#endif
+
+	sscount++;
+	sub = &subsectors[num];
+	frontsector = sub->sector;
+	count = sub->numlines;
+	line = &segs[sub->firstline];
+
+	if (frontsector->floorheight < viewz)
+	{
+		floorplane = R_FindPlane(frontsector->floorheight,
+					 frontsector->floorpic,
+					 frontsector->lightlevel,
+					 frontsector->special);
+	}
+	else
+	{
+		floorplane = NULL;
+	}
+
+	if (frontsector->ceilingheight > viewz ||
+	    frontsector->ceilingpic == skyflatnum)
+	{
+		ceilingplane = R_FindPlane(frontsector->ceilingheight,
+					   frontsector->ceilingpic,
+					   frontsector->lightlevel, 0);
+	}
+	else
+	{
+		ceilingplane = NULL;
+	}
+
+	R_AddSprites(frontsector);
+	if (sub->poly)
+	{ // Render the polyobj in the subsector first
+		polyCount = sub->poly->numsegs;
+		polySeg = sub->poly->segs;
+		while (polyCount--)
+		{
+			R_AddLine(*polySeg++);
+		}
+	}
+	while (count--)
+	{
+		R_AddLine (line);
+		line++;
+	}
+}
+
+
+/*
+===============================================================================
+=
+= RenderBSPNode
+=
+===============================================================================
+*/
+
+void R_RenderBSPNode (int bspnum)
+{
+	node_t		*bsp;
+	int		side;
+
+	if (bspnum & NF_SUBSECTOR)
+	{
+		if (bspnum == -1)
+			R_Subsector (0);
+		else
+			R_Subsector (bspnum & (~NF_SUBSECTOR));
+		return;
+	}
+
+	bsp = &nodes[bspnum];
+
+//
+// decide which side the view point is on
+//
+	side = R_PointOnSide (viewx, viewy, bsp);
+
+	R_RenderBSPNode (bsp->children[side]);	// recursively divide front space
+
+	if (R_CheckBBox (bsp->bbox[side^1]))	// possibly divide back space
+		R_RenderBSPNode (bsp->children[side^1]);
+}
+
+#endif	/* RENDER3D */
+
--- /dev/null
+++ b/r_data.c
@@ -1,0 +1,672 @@
+
+//**************************************************************************
+//**
+//** r_data.c : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 575 $
+//** $Date: 2011-04-13 22:06:28 +0300 (Wed, 13 Apr 2011) $
+//**
+//**************************************************************************
+
+#include "h2stdinc.h"
+#include "h2def.h"
+#include "r_local.h"
+#include "p_local.h"
+
+
+int		firstflat, lastflat, numflats;
+int		firstpatch, lastpatch, numpatches;
+int		firstspritelump, lastspritelump, numspritelumps;
+
+int		numtextures;
+texture_t	**textures;
+
+lighttable_t	*colormaps;
+
+int		*flattranslation;	// for global animation
+int		*texturetranslation;	// for global animation
+
+fixed_t		*spritewidth;		// needed for pre rendering
+fixed_t		*spriteoffset;
+fixed_t		*spritetopoffset;
+
+fixed_t		*textureheight;		// needed for texture pegging
+
+static int	*texturewidthmask;
+static int	*texturecompositesize;
+static short	**texturecolumnlump;
+static unsigned short	**texturecolumnofs;
+static byte	**texturecomposite;
+
+
+/*
+==============================================================================
+
+						MAPTEXTURE_T CACHING
+
+when a texture is first needed, it counts the number of composite columns
+required in the texture and allocates space for a column directory and any
+new columns.  The directory will simply point inside other patches if there
+is only one patch in a given column, but any columns with multiple patches
+will have new column_ts generated.
+
+==============================================================================
+*/
+
+/*
+===================
+=
+= R_DrawColumnInCache
+=
+= Clip and draw a column from a patch into a cached post
+=
+===================
+*/
+
+static void R_DrawColumnInCache (column_t *patch, byte *cache, int originy, int cacheheight)
+{
+	int	count, position;
+	byte	*source;
+//	byte	*dest = (byte *)cache + 3;
+
+	while (patch->topdelta != 0xff)
+	{
+		source = (byte *)patch + 3;
+		count = patch->length;
+		position = originy + patch->topdelta;
+		if (position < 0)
+		{
+			count += position;
+			position = 0;
+		}
+		if (position + count > cacheheight)
+			count = cacheheight - position;
+		if (count > 0)
+			memcpy (cache + position, source, count);
+
+		patch = (column_t *)(  (byte *)patch + patch->length + 4);
+	}
+}
+
+
+/*
+===================
+=
+= R_GenerateComposite
+=
+===================
+*/
+
+static void R_GenerateComposite (int texnum)
+{
+	byte		*block;
+	texture_t	*texture;
+	texpatch_t	*patch;
+	patch_t		*realpatch;
+	int		x, x1, x2;
+	int			i;
+	column_t	*patchcol;
+	short		*collump;
+	unsigned short	*colofs;
+
+	texture = textures[texnum];
+	block = (byte *) Z_Malloc (texturecompositesize[texnum], PU_STATIC, &texturecomposite[texnum]);
+	collump = texturecolumnlump[texnum];
+	colofs = texturecolumnofs[texnum];
+
+//
+// composite the columns together
+//
+	patch = texture->patches;
+
+	for (i = 0, patch = texture->patches; i < texture->patchcount; i++, patch++)
+	{
+		realpatch = (patch_t *) W_CacheLumpNum (patch->patch, PU_CACHE);
+		x1 = patch->originx;
+		x2 = x1 + SHORT(realpatch->width);
+
+		if (x1 < 0)
+			x = 0;
+		else
+			x = x1;
+		if (x2 > texture->width)
+			x2 = texture->width;
+
+		for ( ; x < x2 ; x++)
+		{
+			if (collump[x] >= 0)
+				continue;		// column does not have multiple patches
+			patchcol = (column_t *)((byte *)realpatch + LONG(realpatch->columnofs[x - x1]));
+			R_DrawColumnInCache (patchcol, block + colofs[x], patch->originy, texture->height);
+		}
+	}
+
+// now that the texture has been built, it is purgable
+	Z_ChangeTag (block, PU_CACHE);
+}
+
+
+/*
+===================
+=
+= R_GenerateLookup
+=
+===================
+*/
+
+static void R_GenerateLookup (int texnum)
+{
+	texture_t	*texture;
+	byte		*patchcount;		// [texture->width]
+	texpatch_t	*patch;	
+	patch_t		*realpatch;
+	int		x, x1, x2;
+	int			i;
+	short		*collump;
+	unsigned short	*colofs;
+
+	texture = textures[texnum];
+
+	texturecomposite[texnum] = 0;	// composited not created yet
+	texturecompositesize[texnum] = 0;
+	collump = texturecolumnlump[texnum];
+	colofs = texturecolumnofs[texnum];
+
+//
+// count the number of columns that are covered by more than one patch
+// fill in the lump / offset, so columns with only a single patch are
+// all done
+//
+	patchcount = (byte *)malloc (texture->width);
+	memset (patchcount, 0, texture->width);
+	patch = texture->patches;
+
+	for (i = 0, patch = texture->patches; i < texture->patchcount; i++, patch++)
+	{
+		realpatch = (patch_t *) W_CacheLumpNum (patch->patch, PU_CACHE);
+		x1 = patch->originx;
+		x2 = x1 + SHORT(realpatch->width);
+		if (x1 < 0)
+			x = 0;
+		else
+			x = x1;
+		if (x2 > texture->width)
+			x2 = texture->width;
+		for ( ; x < x2 ; x++)
+		{
+			patchcount[x]++;
+			collump[x] = patch->patch;
+			colofs[x] = LONG(realpatch->columnofs[x - x1]) + 3;
+		}
+	}
+
+	for (x = 0; x < texture->width; x++)
+	{
+		if (!patchcount[x])
+		{
+			char	name[9];
+			name[8] = 0;
+			memcpy (name, texture->name, 8);
+		//	I_Error ("R_GenerateLookup: column without a patch");
+			ST_Message ("R_GenerateLookup: column without a patch (%s)\n", name);
+			free (patchcount);
+			return;
+		}
+		if (patchcount[x] > 1)
+		{
+			collump[x] = -1;	// use the cached block
+			colofs[x] = texturecompositesize[texnum];
+			if (texturecompositesize[texnum] > 0x10000 - texture->height)
+				I_Error ("R_GenerateLookup: texture %i is >64k", texnum);
+			texturecompositesize[texnum] += texture->height;
+		}
+	}
+	free (patchcount);
+}
+
+
+/*
+================
+=
+= R_GetColumn
+=
+================
+*/
+
+byte *R_GetColumn (int tex, int col)
+{
+	int	lump, ofs;
+
+	col &= texturewidthmask[tex];
+	lump = texturecolumnlump[tex][col];
+	ofs = texturecolumnofs[tex][col];
+	if (lump > 0)
+		return (byte *)W_CacheLumpNum(lump, PU_CACHE) + ofs;
+	if (!texturecomposite[tex])
+		R_GenerateComposite (tex);
+	return texturecomposite[tex] + ofs;
+}
+
+
+/*
+==================
+=
+= R_InitTextures
+=
+= Initializes the texture list with the textures from the world map
+=
+==================
+*/
+
+static void R_InitTextures (void)
+{
+	maptexture_t	*mtexture;
+	texture_t	*texture;
+	mappatch_t	*mpatch;
+	texpatch_t	*patch;
+	int		i, j;
+	int		*maptex, *maptex2, *maptex1;
+	byte		*names;
+	char		name[9], *name_p;
+	int		*patchlookup;
+	int		totalwidth;
+	int		nummappatches;
+	int		offset, maxoff, maxoff2;
+	int		numtextures1, numtextures2;
+	int		*directory;
+
+//
+// load the patch names from pnames.lmp
+//
+	name[8] = 0;
+	names = (byte *) W_CacheLumpName ("PNAMES", PU_STATIC);
+	nummappatches = READ_INT32(names);
+	name_p = (char *)names + 4;
+	patchlookup = (int *)malloc(nummappatches*sizeof(*patchlookup));
+	for (i = 0; i < nummappatches; i++)
+	{
+		strncpy (name, name_p + i*8, 8);
+		patchlookup[i] = W_CheckNumForName (name);
+	}
+	Z_Free (names);
+
+//
+// load the map texture definitions from textures.lmp
+//
+	maptex = maptex1 = (int *) W_CacheLumpName ("TEXTURE1", PU_STATIC);
+	numtextures1 = LONG(*maptex);
+	maxoff = W_LumpLength (W_GetNumForName ("TEXTURE1"));
+	directory = maptex + 1;
+
+	if (W_CheckNumForName ("TEXTURE2") != -1)
+	{
+		maptex2 = (int *) W_CacheLumpName ("TEXTURE2", PU_STATIC);
+		numtextures2 = LONG(*maptex2);
+		maxoff2 = W_LumpLength (W_GetNumForName ("TEXTURE2"));
+	}
+	else
+	{
+		maptex2 = NULL;
+		numtextures2 = 0;
+		maxoff2 = 0;
+	}
+	numtextures = numtextures1 + numtextures2;
+
+	textures = (texture_t **) Z_Malloc (numtextures*sizeof(texture_t *), PU_STATIC, NULL);
+	texturecolumnlump = (short **) Z_Malloc (numtextures*sizeof(short *), PU_STATIC, NULL);
+	texturecolumnofs = (unsigned short **) Z_Malloc (numtextures*sizeof(short *), PU_STATIC, NULL);
+	texturecomposite = (byte **) Z_Malloc (numtextures*sizeof(byte *), PU_STATIC, NULL);
+	texturecompositesize = (int *) Z_Malloc (numtextures*sizeof(int), PU_STATIC, NULL);
+	texturewidthmask = (int *) Z_Malloc (numtextures*sizeof(int), PU_STATIC, NULL);
+	textureheight = (fixed_t *) Z_Malloc (numtextures*sizeof(fixed_t), PU_STATIC, NULL);
+
+	totalwidth = 0;
+
+	for (i = 0; i < numtextures; i++, directory++)
+	{
+		if (i == numtextures1)
+		{	// start looking in second texture file
+			maptex = maptex2;
+			maxoff = maxoff2;
+			directory = maptex + 1;
+		}
+
+		offset = LONG(*directory);
+		if (offset > maxoff)
+			I_Error ("R_InitTextures: bad texture directory");
+		mtexture = (maptexture_t *) ( (byte *)maptex + offset);
+		j = SHORT(mtexture->patchcount);
+		texture = textures[i] = (texture_t *) 
+			Z_Malloc (sizeof(texture_t) + sizeof(texpatch_t)*(j - 1), PU_STATIC, NULL);
+		texture->width = SHORT(mtexture->width);
+		texture->height = SHORT(mtexture->height);
+		texture->patchcount = SHORT(mtexture->patchcount);
+		name_p = (char *)maptex + offset;
+		memcpy (texture->name, name_p, sizeof(texture->name));
+		mpatch = &mtexture->patches[0];
+		patch = &texture->patches[0];
+		for (j = 0; j < texture->patchcount; j++, mpatch++, patch++)
+		{
+			patch->originx = SHORT(mpatch->originx);
+			patch->originy = SHORT(mpatch->originy);
+			patch->patch = patchlookup[SHORT(mpatch->patch)];
+			if (patch->patch == -1)
+			{
+				memcpy (name, texture->name, 8);
+				I_Error ("R_InitTextures: Missing patch in texture %s", name);
+			}
+		}
+		texturecolumnlump[i] = (short *) Z_Malloc (texture->width*2, PU_STATIC, NULL);
+		texturecolumnofs[i] = (unsigned short *) Z_Malloc (texture->width*2, PU_STATIC, NULL);
+		j = 1;
+		while (j*2 <= texture->width)
+			j<<=1;
+		texturewidthmask[i] = j - 1;
+		textureheight[i] = texture->height<<FRACBITS;
+
+		totalwidth += texture->width;
+	}
+
+	Z_Free (maptex1);
+	if (maptex2)
+		Z_Free (maptex2);
+
+//
+// precalculate whatever possible
+//
+	for (i = 0; i < numtextures; i++)
+	{
+		R_GenerateLookup (i);
+		if (!(i & 31))
+			ST_Progress();
+	}
+
+//
+// translation table for global animation
+//
+	texturetranslation = (int *) Z_Malloc ((numtextures + 1)*sizeof(int), PU_STATIC, NULL);
+	for (i = 0; i < numtextures; i++)
+		texturetranslation[i] = i;
+
+	free (patchlookup);
+}
+
+
+/*
+================
+=
+= R_InitFlats
+=
+=================
+*/
+
+static void R_InitFlats (void)
+{
+	int		i;
+
+	firstflat = W_GetNumForName ("F_START") + 1;
+	lastflat = W_GetNumForName ("F_END") - 1;
+	numflats = lastflat - firstflat + 1;
+
+// translation table for global animation
+	flattranslation = (int *) Z_Malloc ((numflats + 1) * sizeof(int), PU_STATIC, NULL);
+	for (i = 0; i < numflats; i++)
+		flattranslation[i] = i;
+}
+
+
+/*
+================
+=
+= R_InitSpriteLumps
+=
+= Finds the width and hoffset of all sprites in the wad, so the sprite doesn't
+= need to be cached just for the header during rendering
+=================
+*/
+
+static void R_InitSpriteLumps (void)
+{
+	int		i;
+	patch_t	*patch;
+
+	firstspritelump = W_GetNumForName ("S_START") + 1;
+	lastspritelump = W_GetNumForName ("S_END") - 1;
+	numspritelumps = lastspritelump - firstspritelump + 1;
+	spritewidth = (fixed_t *) Z_Malloc (numspritelumps*sizeof(fixed_t), PU_STATIC, NULL);
+	spriteoffset = (fixed_t *) Z_Malloc (numspritelumps*sizeof(fixed_t), PU_STATIC, NULL);
+	spritetopoffset = (fixed_t *) Z_Malloc (numspritelumps*sizeof(fixed_t), PU_STATIC, NULL);
+
+	for (i = 0; i < numspritelumps; i++)
+	{
+		if (!(i & 127))
+			ST_Progress();
+		patch = (patch_t *) W_CacheLumpNum (firstspritelump + i, PU_CACHE);
+		spritewidth[i] = SHORT(patch->width)<<FRACBITS;
+		spriteoffset[i] = SHORT(patch->leftoffset)<<FRACBITS;
+		spritetopoffset[i] = SHORT(patch->topoffset)<<FRACBITS;
+	}
+}
+
+
+/*
+================
+=
+= R_InitColormaps
+=
+=================
+*/
+
+static void R_InitColormaps (void)
+{
+	int	lump, length;
+//
+// load in the light tables
+// 256 byte align tables
+//
+	lump = W_GetNumForName("COLORMAP");
+	length = W_LumpLength (lump) + 255;
+	colormaps = (lighttable_t *) Z_Malloc (length, PU_STATIC, NULL);
+	colormaps = (byte *)( ((intptr_t)colormaps + 255) & ~0xff);
+	W_ReadLump (lump, colormaps);
+}
+
+
+/*
+================
+=
+= R_InitData
+=
+= Locates all the lumps that will be used by all views
+= Must be called after W_Init
+=================
+*/
+
+void R_InitData (void)
+{
+	R_InitTextures();
+	R_InitFlats();
+	R_InitSpriteLumps();
+	R_InitColormaps();
+}
+
+//=============================================================================
+
+/*
+================
+=
+= R_FlatNumForName
+=
+================
+*/
+
+int R_FlatNumForName (const char *name)
+{
+	int		i;
+	char	namet[9];
+
+	i = W_CheckNumForName (name);
+	if (i == -1)
+	{
+		namet[8] = 0;
+		memcpy (namet, name,8);
+		I_Error ("R_FlatNumForName: %s not found", namet);
+	}
+	return i - firstflat;
+}
+
+
+/*
+================
+=
+= R_CheckTextureNumForName
+=
+================
+*/
+
+int R_CheckTextureNumForName (const char *name)
+{
+	int		i;
+
+	if (name[0] == '-')		// no texture marker
+		return 0;
+
+	for (i = 0; i < numtextures; i++)
+	{
+		if (!strncasecmp(textures[i]->name, name, 8))
+			return i;
+	}
+
+	return -1;
+}
+
+
+/*
+================
+=
+= R_TextureNumForName
+=
+================
+*/
+
+int R_TextureNumForName (const char *name)
+{
+	int		i;
+
+	i = R_CheckTextureNumForName (name);
+	if (i == -1)
+		I_Error ("R_TextureNumForName: %s not found", name);
+
+	return i;
+}
+
+
+/*
+=================
+=
+= R_PrecacheLevel
+=
+= Preloads all relevent graphics for the level
+=================
+*/
+
+static int	flatmemory, texturememory, spritememory;
+
+void R_PrecacheLevel (void)
+{
+	char		*flatpresent;
+	char		*texturepresent;
+	char		*spritepresent;
+	int		i, j, k, lump;
+	texture_t	*texture;
+	thinker_t	*th;
+	spriteframe_t	*sf;
+
+	if (demoplayback)
+		return;
+
+//
+// precache flats
+//
+	flatpresent = (char*)malloc(numflats);
+	memset (flatpresent, 0, numflats);
+	for (i = 0; i < numsectors; i++)
+	{
+		flatpresent[sectors[i].floorpic] = 1;
+		flatpresent[sectors[i].ceilingpic] = 1;
+	}
+
+	flatmemory = 0;
+	for (i = 0; i < numflats; i++)
+	{
+		if (flatpresent[i])
+		{
+			lump = firstflat + i;
+			flatmemory += lumpinfo[lump].size;
+			W_CacheLumpNum(lump, PU_CACHE);
+		}
+	}
+
+//
+// precache textures
+//
+	texturepresent = (char*) malloc(numtextures);
+	memset (texturepresent, 0, numtextures);
+
+	for (i = 0; i < numsides; i++)
+	{
+		texturepresent[sides[i].toptexture] = 1;
+		texturepresent[sides[i].midtexture] = 1;
+		texturepresent[sides[i].bottomtexture] = 1;
+	}
+
+	texturepresent[Sky1Texture] = 1;
+	texturepresent[Sky2Texture] = 1;
+
+	texturememory = 0;
+	for (i = 0; i < numtextures; i++)
+	{
+		if (!texturepresent[i])
+			continue;
+		texture = textures[i];
+		for (j = 0; j < texture->patchcount; j++)
+		{
+			lump = texture->patches[j].patch;
+			texturememory += lumpinfo[lump].size;
+			W_CacheLumpNum(lump, PU_CACHE);
+		}
+	}
+
+//
+// precache sprites
+//
+	spritepresent = (char*)malloc(numsprites);
+	memset (spritepresent, 0, numsprites);
+
+	for (th = thinkercap.next; th != &thinkercap; th = th->next)
+	{
+		if (th->function == P_MobjThinker)
+			spritepresent[((mobj_t *)th)->sprite] = 1;
+	}
+
+	spritememory = 0;
+	for (i = 0; i < numsprites; i++)
+	{
+		if (!spritepresent[i])
+			continue;
+		for (j = 0; j < sprites[i].numframes; j++)
+		{
+			sf = &sprites[i].spriteframes[j];
+			for (k = 0; k < 8; k++)
+			{
+				lump = firstspritelump + sf->lump[k];
+				spritememory += lumpinfo[lump].size;
+				W_CacheLumpNum(lump, PU_CACHE);
+			}
+		}
+	}
+	free (flatpresent);
+	free (texturepresent);
+	free (spritepresent);
+}
+
--- /dev/null
+++ b/r_draw.c
@@ -1,0 +1,583 @@
+
+//**************************************************************************
+//**
+//** r_draw.c : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 373 $
+//** $Date: 2009-05-19 21:14:28 +0300 (Tue, 19 May 2009) $
+//**
+//**************************************************************************
+
+#include "h2stdinc.h"
+
+#ifndef RENDER3D
+
+#include "h2def.h"
+#include "r_local.h"
+
+/*
+
+All drawing to the view buffer is accomplished in this file.  The other refresh
+files only know about ccordinates, not the architecture of the frame buffer.
+
+*/
+
+int	viewwidth, scaledviewwidth, viewheight, viewwindowx, viewwindowy;
+
+byte	*ylookup[MAXHEIGHT];
+int	columnofs[MAXWIDTH];
+byte	*tinttable;		// used for translucent sprites
+
+
+/*
+==================
+=
+= R_DrawColumn
+=
+= Source is the top of the column to scale
+=
+==================
+*/
+
+lighttable_t	*dc_colormap;
+int			dc_x;
+int			dc_yl;
+int			dc_yh;
+fixed_t		dc_iscale;
+fixed_t		dc_texturemid;
+byte		*dc_source;		// first pixel in a column (possibly virtual)
+
+//int		dccount;		// just for profiling
+
+
+//#ifndef __i386
+//#ifndef __m68k
+void R_DrawColumn (void)
+{
+	int		count;
+	byte		*dest;
+	fixed_t		frac, fracstep;
+
+	count = dc_yh - dc_yl;
+	if (count < 0)
+		return;
+
+#ifdef RANGECHECK
+	if ((unsigned)dc_x >= SCREENWIDTH || dc_yl < 0 || dc_yh >= SCREENHEIGHT)
+		I_Error ("R_DrawColumn: %i to %i at %i", dc_yl, dc_yh, dc_x);
+#endif
+
+	dest = ylookup[dc_yl] + columnofs[dc_x]; 
+
+	fracstep = dc_iscale;
+	frac = dc_texturemid + (dc_yl - centery)*fracstep;
+
+	do
+	{
+		*dest = dc_colormap[dc_source[(frac>>FRACBITS) & 127]];
+		dest += SCREENWIDTH;
+		frac += fracstep;
+	} while (count--);
+}
+//#endif	// __m68k
+//#endif	// __i386
+
+void R_DrawColumnLow (void)
+{
+	int		count;
+	byte		*dest;
+	fixed_t		frac, fracstep;
+
+	count = dc_yh - dc_yl;
+	if (count < 0)
+		return;
+
+#ifdef RANGECHECK
+	if ((unsigned)dc_x >= SCREENWIDTH || dc_yl < 0 || dc_yh >= SCREENHEIGHT)
+		I_Error ("R_DrawColumn: %i to %i at %i", dc_yl, dc_yh, dc_x);
+//	dccount++;
+#endif
+
+	dest = ylookup[dc_yl] + columnofs[dc_x];
+
+	fracstep = dc_iscale;
+	frac = dc_texturemid + (dc_yl - centery)*fracstep;
+
+	do
+	{
+		*dest = dc_colormap[dc_source[(frac>>FRACBITS) & 127]];
+		dest += SCREENWIDTH;
+		frac += fracstep;
+	} while (count--);
+}
+
+/*
+#define FUZZTABLE		50
+#define FUZZOFF		(SCREENWIDTH)
+static int	fuzzoffset[FUZZTABLE] =
+{
+	FUZZOFF,-FUZZOFF,FUZZOFF,-FUZZOFF,FUZZOFF,FUZZOFF,-FUZZOFF,
+	FUZZOFF,FUZZOFF,-FUZZOFF,FUZZOFF,FUZZOFF,FUZZOFF,-FUZZOFF,
+	FUZZOFF,FUZZOFF,FUZZOFF,-FUZZOFF,-FUZZOFF,-FUZZOFF,-FUZZOFF,
+	FUZZOFF,-FUZZOFF,-FUZZOFF,FUZZOFF,FUZZOFF,FUZZOFF,FUZZOFF,-FUZZOFF,
+	FUZZOFF,-FUZZOFF,FUZZOFF,FUZZOFF,-FUZZOFF,-FUZZOFF,FUZZOFF,
+	FUZZOFF,-FUZZOFF,-FUZZOFF,-FUZZOFF,-FUZZOFF,FUZZOFF,FUZZOFF,
+	FUZZOFF,FUZZOFF,-FUZZOFF,FUZZOFF,FUZZOFF,-FUZZOFF,FUZZOFF
+};
+static int	fuzzpos = 0;
+*/
+
+void R_DrawFuzzColumn (void)
+{
+	int		count;
+	byte		*dest;
+	fixed_t		frac, fracstep;
+
+	if (!dc_yl)
+		dc_yl = 1;
+	if (dc_yh == viewheight - 1)
+		dc_yh = viewheight - 2;
+
+	count = dc_yh - dc_yl;
+	if (count < 0)
+		return;
+
+#ifdef RANGECHECK
+	if ((unsigned)dc_x >= SCREENWIDTH || dc_yl < 0 || dc_yh >= SCREENHEIGHT)
+		I_Error ("R_DrawFuzzColumn: %i to %i at %i", dc_yl, dc_yh, dc_x);
+#endif
+
+	dest = ylookup[dc_yl] + columnofs[dc_x];
+
+	fracstep = dc_iscale;
+	frac = dc_texturemid + (dc_yl - centery)*fracstep;
+
+// OLD FUZZY INVISO SPRITE STUFF
+/*
+	do
+	{
+		*dest = colormaps[6*256 + dest[fuzzoffset[fuzzpos]]];
+		if (++fuzzpos == FUZZTABLE)
+			fuzzpos = 0;
+		dest += SCREENWIDTH;
+		frac += fracstep;
+	} while (count--);
+*/
+	do
+	{
+		*dest = tinttable[*dest + (dc_colormap[dc_source[(frac>>FRACBITS) & 127]]<<8)];
+		dest += SCREENWIDTH;
+		frac += fracstep;
+	} while (count--);
+}
+
+
+//============================================================================
+//
+// R_DrawAltFuzzColumn
+//
+//============================================================================
+
+void R_DrawAltFuzzColumn (void)
+{
+	int		count;
+	byte		*dest;
+	fixed_t		frac, fracstep;
+
+	if (!dc_yl)
+		dc_yl = 1;
+	if (dc_yh == viewheight - 1)
+		dc_yh = viewheight - 2;
+
+	count = dc_yh - dc_yl;
+	if (count < 0)
+		return;
+
+#ifdef RANGECHECK
+	if ((unsigned)dc_x >= SCREENWIDTH || dc_yl < 0 || dc_yh >= SCREENHEIGHT)
+		I_Error ("R_DrawFuzzColumn: %i to %i at %i", dc_yl, dc_yh, dc_x);
+#endif
+
+	dest = ylookup[dc_yl] + columnofs[dc_x];
+
+	fracstep = dc_iscale;
+	frac = dc_texturemid + (dc_yl - centery)*fracstep;
+
+	do
+	{
+		*dest = tinttable[((*dest)<<8) + dc_colormap[dc_source[(frac>>FRACBITS) & 127]]];
+		dest += SCREENWIDTH;
+		frac += fracstep;
+	} while (count--);
+}
+
+/*
+========================
+=
+= R_DrawTranslatedColumn
+=
+========================
+*/
+
+byte	*dc_translation;
+byte	*translationtables;
+
+void R_DrawTranslatedColumn (void)
+{
+	int		count;
+	byte		*dest;
+	fixed_t		frac, fracstep;
+
+	count = dc_yh - dc_yl;
+	if (count < 0)
+		return;
+
+#ifdef RANGECHECK
+	if ((unsigned)dc_x >= SCREENWIDTH || dc_yl < 0 || dc_yh >= SCREENHEIGHT)
+		I_Error ("R_DrawColumn: %i to %i at %i", dc_yl, dc_yh, dc_x);
+#endif
+
+	dest = ylookup[dc_yl] + columnofs[dc_x];
+
+	fracstep = dc_iscale;
+	frac = dc_texturemid + (dc_yl - centery)*fracstep;
+
+	do
+	{
+		*dest = dc_colormap[dc_translation[dc_source[frac>>FRACBITS]]];
+		dest += SCREENWIDTH;
+		frac += fracstep;
+	} while (count--);
+}
+
+//============================================================================
+//
+// R_DrawTranslatedFuzzColumn
+//
+//============================================================================
+
+void R_DrawTranslatedFuzzColumn (void)
+{
+	int		count;
+	byte		*dest;
+	fixed_t		frac, fracstep;
+
+	count = dc_yh - dc_yl;
+	if (count < 0)
+		return;
+
+#ifdef RANGECHECK
+	if ((unsigned)dc_x >= SCREENWIDTH || dc_yl < 0 || dc_yh >= SCREENHEIGHT)
+		I_Error ("R_DrawColumn: %i to %i at %i", dc_yl, dc_yh, dc_x);
+#endif
+
+	dest = ylookup[dc_yl] + columnofs[dc_x];
+
+	fracstep = dc_iscale;
+	frac = dc_texturemid + (dc_yl - centery)*fracstep;
+
+	do
+	{
+		*dest = tinttable[((*dest)<<8) + dc_colormap[dc_translation[dc_source[frac>>FRACBITS]]]];
+		dest += SCREENWIDTH;
+		frac += fracstep;
+	} while (count--);
+}
+
+//============================================================================
+//
+// R_DrawTranslatedAltFuzzColumn
+//
+//============================================================================
+
+/*
+void R_DrawTranslatedAltFuzzColumn (void)
+{
+	int		count;
+	byte		*dest;
+	fixed_t		frac, fracstep;
+
+	count = dc_yh - dc_yl;
+	if (count < 0)
+		return;
+
+#ifdef RANGECHECK
+	if ((unsigned)dc_x >= SCREENWIDTH || dc_yl < 0 || dc_yh >= SCREENHEIGHT)
+		I_Error ("R_DrawColumn: %i to %i at %i", dc_yl, dc_yh, dc_x);
+#endif
+
+	dest = ylookup[dc_yl] + columnofs[dc_x];
+
+	fracstep = dc_iscale;
+	frac = dc_texturemid + (dc_yl - centery)*fracstep;
+
+	do
+	{
+		*dest = tinttable[*dest + (dc_colormap[dc_translation[dc_source[frac>>FRACBITS]]]<<8)];
+		dest += SCREENWIDTH;
+		frac += fracstep;
+	} while (count--);
+}
+*/
+
+//--------------------------------------------------------------------------
+//
+// PROC R_InitTranslationTables
+//
+//--------------------------------------------------------------------------
+
+/* version 1.0 wad has 9 lumps: trantbl0 ... trantbl8 */
+#if 0
+static byte transtable10[256 * 3 * (MAXPLAYERS_10 - 1)] =
+{
+#  include "transtb10.h"
+};
+#endif
+/* version 1.1 wad has 21 lumps: trantbl0 .. trantbl9 
+			    and  trantbla .. trantblk */
+#if (MAXPLAYERS == MAXPLAYERS_11)
+static byte transtable11[256 * 3 * (MAXPLAYERS_11 - 1)] =
+{
+#  include "transtb11.h"
+};
+#define TRANTBL11_OFS	(256 * 3 * (MAXPLAYERS_10 - 1))
+#define TRANTBL11_CNT	(256 * 3 * (MAXPLAYERS_11 - MAXPLAYERS_10))
+#endif
+
+void R_InitTranslationTables (void)
+{
+	int		i;
+	byte	*transLump;
+
+	// Load tint table
+	tinttable = (byte *) W_CacheLumpName("TINTTAB", PU_STATIC);
+
+	// Allocate translation tables
+	translationtables = (byte *) Z_Malloc(256 * 3 * (MAXPLAYERS - 1) + 255, PU_STATIC, NULL);
+	translationtables = (byte *)(((intptr_t)translationtables + 255) & ~255);
+
+	for (i = 0; i < 3 * (MAXPLAYERS - 1); i++)
+	{
+#if (MAXPLAYERS == MAXPLAYERS_11)
+		if (oldwad_10 && i == 3 * (MAXPLAYERS_10 - 1))
+		{
+			/* HACK !! ---  old 1.0 wad doesn't have TRANTBL9
+			 *		to TRANTBLK. Let's just copy from
+			 *		the extracted v1.1 data.	*/
+			memcpy (translationtables + TRANTBL11_OFS,
+				transtable11 + TRANTBL11_OFS, TRANTBL11_CNT);
+			break;
+		}
+#endif	/* 8-players */
+		transLump = (byte *) W_CacheLumpNum(W_GetNumForName("trantbl0") + i, PU_STATIC);
+		memcpy(translationtables + i*256, transLump, 256);
+		Z_Free(transLump);
+	}
+}
+
+/*
+================
+=
+= R_DrawSpan
+=
+================
+*/
+
+int			ds_y;
+int			ds_x1;
+int			ds_x2;
+lighttable_t	*ds_colormap;
+fixed_t			ds_xfrac;
+fixed_t			ds_yfrac;
+fixed_t			ds_xstep;
+fixed_t			ds_ystep;
+byte			*ds_source;		// start of a 64*64 tile image
+
+//int			dscount;		// just for profiling
+
+
+//#ifndef __i386
+//#ifndef __m68k
+void R_DrawSpan (void)
+{
+	fixed_t		xfrac, yfrac;
+	byte		*dest;
+	int		count, spot;
+
+#ifdef RANGECHECK
+	if (ds_x2 < ds_x1 || ds_x1 < 0 || ds_x2 >= SCREENWIDTH || (unsigned)ds_y > SCREENHEIGHT)
+		I_Error ("R_DrawSpan: %i to %i at %i", ds_x1, ds_x2, ds_y);
+//	dscount++;
+#endif
+
+	xfrac = ds_xfrac;
+	yfrac = ds_yfrac;
+
+	dest = ylookup[ds_y] + columnofs[ds_x1];
+	count = ds_x2 - ds_x1;
+	do
+	{
+		spot = ((yfrac>>(16-6)) & (63*64)) + ((xfrac>>16) & 63);
+		*dest++ = ds_colormap[ds_source[spot]];
+		xfrac += ds_xstep;
+		yfrac += ds_ystep;
+	} while (count--);
+}
+//#endif
+//#endif
+
+void R_DrawSpanLow (void)
+{
+	fixed_t		xfrac, yfrac;
+	byte		*dest;
+	int		count, spot;
+
+#ifdef RANGECHECK
+	if (ds_x2 < ds_x1 || ds_x1 < 0 || ds_x2 >= SCREENWIDTH || (unsigned)ds_y > SCREENHEIGHT)
+		I_Error ("R_DrawSpan: %i to %i at %i", ds_x1, ds_x2, ds_y);
+//	dscount++;
+#endif
+
+	xfrac = ds_xfrac;
+	yfrac = ds_yfrac;
+
+	dest = ylookup[ds_y] + columnofs[ds_x1];
+	count = ds_x2 - ds_x1;
+	do
+	{
+		spot = ((yfrac>>(16-6)) & (63*64)) + ((xfrac>>16) & 63);
+		*dest++ = ds_colormap[ds_source[spot]];
+		xfrac += ds_xstep;
+		yfrac += ds_ystep;
+	} while (count--);
+}
+
+
+/*
+================
+=
+= R_InitBuffer
+=
+=================
+*/
+
+void R_InitBuffer (int width, int height)
+{
+	int		i;
+
+	viewwindowx = (SCREENWIDTH - width) >> 1;
+	for (i = 0; i < width; i++)
+		columnofs[i] = viewwindowx + i;
+	if (width == SCREENWIDTH)
+		viewwindowy = 0;
+	else
+		viewwindowy = (SCREENHEIGHT - SBARHEIGHT - height) >> 1;
+	for (i = 0; i < height; i++)
+		ylookup[i] = screen + (i + viewwindowy)*SCREENWIDTH;
+}
+
+
+/*
+==================
+=
+= R_DrawViewBorder
+=
+= Draws the border around the view for different size windows
+==================
+*/
+
+boolean		BorderNeedRefresh;
+
+void R_DrawViewBorder (void)
+{
+	byte	*src, *dest;
+	int		x, y;
+
+	if (scaledviewwidth == SCREENWIDTH)
+		return;
+
+	src = (byte *) W_CacheLumpName("F_022", PU_CACHE);
+	dest = screen;
+
+	for (y = 0 ; y < SCREENHEIGHT - SBARHEIGHT; y++)
+	{
+		for (x = 0; x < SCREENWIDTH/64; x++)
+		{
+			memcpy (dest, src + ((y & 63)<<6), 64);
+			dest += 64;
+		}
+		if (SCREENWIDTH & 63)
+		{
+			memcpy (dest, src + ((y & 63)<<6), SCREENWIDTH & 63);
+			dest += (SCREENWIDTH & 63);
+		}
+	}
+	for (x = viewwindowx; x < viewwindowx + viewwidth; x += 16)
+	{
+		V_DrawPatch(x, viewwindowy - 4, (patch_t *)W_CacheLumpName("bordt", PU_CACHE));
+		V_DrawPatch(x, viewwindowy + viewheight, (patch_t *)W_CacheLumpName("bordb", PU_CACHE));
+	}
+	for (y = viewwindowy; y < viewwindowy + viewheight; y += 16)
+	{
+		V_DrawPatch(viewwindowx - 4, y, (patch_t *)W_CacheLumpName("bordl", PU_CACHE));
+		V_DrawPatch(viewwindowx+viewwidth, y, (patch_t *)W_CacheLumpName("bordr", PU_CACHE));
+	}
+	V_DrawPatch(viewwindowx - 4, viewwindowy - 4, (patch_t *)W_CacheLumpName("bordtl", PU_CACHE));
+	V_DrawPatch(viewwindowx + viewwidth, viewwindowy - 4, (patch_t *)W_CacheLumpName("bordtr", PU_CACHE));
+	V_DrawPatch(viewwindowx + viewwidth, viewwindowy + viewheight, (patch_t *)W_CacheLumpName("bordbr", PU_CACHE));
+	V_DrawPatch(viewwindowx - 4, viewwindowy + viewheight, (patch_t *)W_CacheLumpName("bordbl", PU_CACHE));
+}
+
+/*
+==================
+=
+= R_DrawTopBorder
+=
+= Draws the top border around the view for different size windows
+==================
+*/
+
+boolean		BorderTopRefresh;
+
+void R_DrawTopBorder (void)
+{
+	byte	*src, *dest;
+	int		x, y;
+
+	if (scaledviewwidth == SCREENWIDTH)
+		return;
+
+	src = (byte *) W_CacheLumpName("F_022", PU_CACHE);
+	dest = screen;
+
+	for (y = 0; y < 34; y++)
+	{
+		for (x = 0; x < SCREENWIDTH/64; x++)
+		{
+			memcpy (dest, src + ((y & 63)<<6), 64);
+			dest += 64;
+		}
+		if (SCREENWIDTH & 63)
+		{
+			memcpy (dest, src + ((y & 63)<<6), SCREENWIDTH & 63);
+			dest += (SCREENWIDTH & 63);
+		}
+	}
+	if (viewwindowy < 35)
+	{
+		for (x = viewwindowx; x < viewwindowx + viewwidth; x += 16)
+		{
+			V_DrawPatch(x, viewwindowy - 4, (patch_t *)W_CacheLumpName("bordt", PU_CACHE));
+		}
+		V_DrawPatch(viewwindowx-4, viewwindowy, (patch_t *)W_CacheLumpName("bordl", PU_CACHE));
+		V_DrawPatch(viewwindowx + viewwidth, viewwindowy, (patch_t *)W_CacheLumpName("bordr", PU_CACHE));
+		V_DrawPatch(viewwindowx - 4, viewwindowy + 16, (patch_t *)W_CacheLumpName("bordl", PU_CACHE));
+		V_DrawPatch(viewwindowx + viewwidth, viewwindowy + 16, (patch_t *)W_CacheLumpName("bordr", PU_CACHE));
+
+		V_DrawPatch(viewwindowx - 4, viewwindowy - 4, (patch_t *)W_CacheLumpName("bordtl", PU_CACHE));
+		V_DrawPatch(viewwindowx + viewwidth, viewwindowy - 4, (patch_t *)W_CacheLumpName("bordtr", PU_CACHE));
+	}
+}
+
+#endif	/* RENDER3D */
+
--- /dev/null
+++ b/r_local.h
@@ -1,0 +1,563 @@
+
+//**************************************************************************
+//**
+//** r_local.h : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 373 $
+//** $Date: 2009-05-19 21:14:28 +0300 (Tue, 19 May 2009) $
+//**
+//**************************************************************************
+
+#ifndef __R_LOCAL__
+#define __R_LOCAL__
+
+#define ANGLETOSKYSHIFT		22	/* sky map is 256*128*4 maps */
+
+#define BASEYCENTER		100
+
+#define MAXWIDTH		1120
+#define MAXHEIGHT		832
+
+#define PI			3.141592657
+
+#define CENTERY			(SCREENHEIGHT / 2)
+
+#define MINZ			(FRACUNIT * 4)
+
+#define FIELDOFVIEW		2048	/* fineangles in the SCREENWIDTH wide window */
+
+/* lighting constants */
+#define LIGHTLEVELS		16
+#define LIGHTSEGSHIFT		4
+#define MAXLIGHTSCALE		48
+#define LIGHTSCALESHIFT		12
+#define MAXLIGHTZ		128
+#define LIGHTZSHIFT		20
+#define NUMCOLORMAPS		32	/* number of diminishing */
+#define INVERSECOLORMAP		32
+
+
+/* ------ INTERNAL MAP TYPES ------ */
+
+/* ----  used by play and refresh ---- */
+
+typedef struct
+{
+	fixed_t         x,y;
+} vertex_t;
+
+struct line_s;
+
+typedef struct
+{
+	fixed_t	floorheight, ceilingheight;
+	short	floorpic, ceilingpic;
+	short	lightlevel;
+	short	special, tag;
+
+	int	soundtraversed;		/* 0 = untraversed, 1,2 = sndlines -1 */
+	mobj_t	*soundtarget;		/* thing that made a sound (or null)  */
+	seqtype_t seqType;			/* stone, metal, heavy, etc.. */
+
+	int	blockbox[4];		/* mapblock bounding box for height changes */
+	degenmobj_t soundorg;		/* for any sounds played by the sector */
+	int	validcount;		/* if == validcount, already checked */
+	mobj_t	*thinglist;		/* list of mobjs in sector */
+	void	*specialdata;		/* thinker_t for reversable actions */
+	int	linecount;
+	struct line_s **lines;		/* [linecount] size */
+
+#ifdef RENDER3D
+	int	flatoffx, flatoffy;	/* Scrolling flats. */
+	int	skyfix;			/* Offset to ceiling height rendering w/sky. */
+#endif
+
+} sector_t;
+
+typedef struct
+{
+	fixed_t		textureoffset;	/* add this to the calculated texture col */
+	fixed_t		rowoffset;	/* add this to the calculated texture top */
+	short		toptexture, bottomtexture, midtexture;
+	sector_t	*sector;
+} side_t;
+
+typedef enum
+{
+	ST_HORIZONTAL,
+	ST_VERTICAL,
+	ST_POSITIVE,
+	ST_NEGATIVE
+} slopetype_t;
+
+/*
+typedef struct line_s
+{
+	vertex_t	*v1, *v2;
+	fixed_t		dx,dy;		// v2 - v1 for side checking
+	short		flags;
+	short		special, tag;
+	short		sidenum[2];	// sidenum[1] will be -1 if one sided
+	fixed_t		bbox[4];
+	slopetype_t	slopetype;	// to aid move clipping
+	sector_t	*frontsector, *backsector;
+	int		validcount;	// if == validcount, already checked
+	void		*specialdata;	// thinker_t for reversable actions
+} line_t;
+*/
+
+typedef struct line_s
+{
+	vertex_t *v1;
+	vertex_t *v2;
+	fixed_t dx;
+	fixed_t dy;
+	short flags;
+	byte special;
+	byte arg1;
+	byte arg2;
+	byte arg3;
+	byte arg4;
+	byte arg5;
+	short sidenum[2];
+	fixed_t bbox[4];
+	slopetype_t slopetype;
+	sector_t *frontsector;
+	sector_t *backsector;
+	int validcount;
+	void *specialdata;
+} line_t;
+
+typedef struct
+{
+	vertex_t	*v1, *v2;
+	fixed_t		offset;
+	angle_t		angle;
+	side_t		*sidedef;
+	line_t		*linedef;
+	sector_t	*frontsector;
+	sector_t	*backsector;	/* NULL for one sided lines */
+#ifdef RENDER3D
+	float		len;		/* Length of the segment (v1 -> v2) for texture mapping. */
+#endif
+} seg_t;
+
+
+/* ---- Polyobj data ---- */
+
+typedef struct
+{
+	int numsegs;
+	seg_t **segs;
+	degenmobj_t startSpot;
+	vertex_t *originalPts;	/* used as the base for the rotations */
+	vertex_t *prevPts;	/* use to restore the old point values */
+	angle_t angle;
+	int tag;		/* reference tag assigned in HereticEd */
+	int bbox[4];
+	int validcount;
+	boolean crush;		/* should the polyobj attempt to crush mobjs? */
+	int seqType;
+	fixed_t size;		/* polyobj size (area of POLY_AREAUNIT == size of FRACUNIT) */
+	void *specialdata;	/* pointer a thinker, if the poly is moving */
+} polyobj_t;
+
+typedef struct polyblock_s
+{
+	polyobj_t *polyobj;
+	struct polyblock_s *prev;
+	struct polyblock_s *next;
+} polyblock_t;
+
+
+#ifdef RENDER3D
+typedef struct
+{
+	float	x, y;
+} fvertex_t;
+#endif
+
+typedef struct subsector_s
+{
+	sector_t	*sector;
+	short		numlines;
+	short		firstline;
+	polyobj_t	*poly;
+#ifdef RENDER3D
+	/* Sorted edge vertices for rendering floors and ceilings. */
+	char	numedgeverts;
+	fvertex_t	*edgeverts;     /* A list of edge vertices. */
+	fvertex_t	*origedgeverts; /* Unmodified, accurate edge vertices. */
+	fvertex_t	bbox[2];        /* Min and max points. */
+	fvertex_t	midpoint;       /* Center of bounding box. */
+#endif
+} subsector_t;
+
+typedef struct
+{
+	fixed_t		x, y, dx, dy;	/* partition line */
+	fixed_t		bbox[2][4];	/* bounding box for each child */
+	unsigned short  children[2];	/* if NF_SUBSECTOR its a subsector */
+} node_t;
+
+
+/* ------ OTHER TYPES ------ */
+
+typedef byte	lighttable_t;		/* this could be wider for >8 bit display */
+
+#define MAXVISPLANES		160
+#define MAXOPENINGS		(SCREENWIDTH * 64)
+
+typedef struct
+{
+	fixed_t		height;
+	int		picnum;
+	int		lightlevel;
+	int		special;
+	int		minx, maxx;
+	byte		pad1;		/* leave pads for [minx-1]/[maxx+1] */
+	byte		top[SCREENWIDTH];
+	byte		pad2;
+	byte		pad3;
+	byte		bottom[SCREENWIDTH];
+	byte		pad4;
+} visplane_t;
+
+typedef struct drawseg_s
+{
+	seg_t		*curline;
+	int		x1, x2;
+	fixed_t		scale1, scale2, scalestep;
+	int		silhouette;			/* 0 = none, 1 = bottom, 2 = top, 3 = both */
+	fixed_t		bsilheight;			/* don't clip sprites above this */
+	fixed_t		tsilheight;			/* don't clip sprites below this */
+	/* pointers to lists for sprite clipping */
+	short		*sprtopclip;		/* adjusted so [x1] is first value */
+	short		*sprbottomclip;		/* adjusted so [x1] is first value */
+	short		*maskedtexturecol;	/* adjusted so [x1] is first value */
+} drawseg_t;
+
+#define SIL_NONE	0
+#define SIL_BOTTOM	1
+#define SIL_TOP		2
+#define SIL_BOTH	3
+
+#define MAXDRAWSEGS	256
+
+/* A vissprite_t is a thing that will be drawn during a refresh */
+typedef struct vissprite_s
+{
+	struct vissprite_s	*prev, *next;
+	int			x1, x2;
+	fixed_t		gx, gy;			/* for line side calculation */
+	fixed_t		gz, gzt;		/* global bottom / top for silhouette clipping */
+	fixed_t		startfrac;		/* horizontal position of x1 */
+	fixed_t		scale;
+	fixed_t		xiscale;		/* negative if flipped */
+	fixed_t		texturemid;
+	int			patch;
+#ifdef RENDER3D
+	int		lightlevel;
+	float		v1[2], v2[2];		/* The vertices (v1 is the left one). */
+	float		secfloor, secceil;
+#else
+	lighttable_t	*colormap;
+#endif
+	int		mobjflags;		/* for color translation and shadow draw */
+	boolean		psprite;		/* true if psprite */
+	int		playerclass;		/* player class (used in translation) */
+	fixed_t		floorclip;
+} vissprite_t;
+
+
+extern	visplane_t	*floorplane, *ceilingplane;
+
+/* Sprites are patches with a special naming convention so they can be
+ * recognized by R_InitSprites.  The sprite and frame specified by a
+ * thing_t is range checked at run time.
+ * a sprite is a patch_t that is assumed to represent a three dimensional
+ * object and may have multiple rotations pre drawn.  Horizontal flipping
+ * is used to save space. Some sprites will only have one picture used
+ * for all views.
+ */
+typedef struct
+{
+	boolean		rotate;		/* if false use 0 for any position */
+	short		lump[8];	/* lump to use for view angles 0-7 */
+	byte		flip[8];	/* flip (1 = flip) to use for view angles 0-7 */
+} spriteframe_t;
+
+typedef struct
+{
+	int			numframes;
+	spriteframe_t	*spriteframes;
+} spritedef_t;
+
+extern	spritedef_t	*sprites;
+extern	int		numsprites;
+
+/*============================================================================*/
+
+extern	int		numvertexes;
+extern	vertex_t	*vertexes;
+
+extern	int		numsegs;
+extern	seg_t		*segs;
+
+extern	int		numsectors;
+extern	sector_t	*sectors;
+
+extern	int		numsubsectors;
+extern	subsector_t	*subsectors;
+
+extern	int		numnodes;
+extern	node_t		*nodes;
+
+extern	int		numlines;
+extern	line_t		*lines;
+
+extern	int		numsides;
+extern	side_t		*sides;
+
+
+extern	fixed_t		viewx, viewy, viewz;
+extern	angle_t		viewangle;
+extern	player_t	*viewplayer;
+
+#ifdef RENDER3D
+extern	float		viewpitch;
+extern	int		sbarscale;
+#endif
+
+extern	angle_t		clipangle;
+
+extern	int		viewangletox[FINEANGLES / 2];
+extern	angle_t		xtoviewangle[SCREENWIDTH + 1];
+extern	fixed_t		finetangent[FINEANGLES / 2];
+
+extern	fixed_t		rw_distance;
+extern	angle_t		rw_normalangle;
+
+
+/* ---- R_main.c ---- */
+
+extern	int		viewwidth, viewheight, viewwindowx, viewwindowy;
+extern	int		centerx, centery;
+extern	fixed_t		centerxfrac;
+extern	fixed_t		centeryfrac;
+extern	fixed_t		projection;
+
+extern	int		validcount;
+
+extern	int		sscount, linecount, loopcount;
+extern	lighttable_t	*scalelight[LIGHTLEVELS][MAXLIGHTSCALE];
+extern	lighttable_t	*scalelightfixed[MAXLIGHTSCALE];
+extern	lighttable_t	*zlight[LIGHTLEVELS][MAXLIGHTZ];
+
+extern	int		extralight;
+extern	lighttable_t	*fixedcolormap;
+
+extern	fixed_t		viewcos, viewsin;
+
+extern	int		detailshift;	/* 0 = high, 1 = low */
+
+extern	void		(*colfunc) (void);
+extern	void		(*basecolfunc) (void);
+extern	void		(*fuzzcolfunc) (void);
+extern	void		(*spanfunc) (void);
+
+int R_PointOnSide (fixed_t x, fixed_t y, node_t *node);
+int R_PointOnSegSide (fixed_t x, fixed_t y, seg_t *line);
+angle_t R_PointToAngle (fixed_t x, fixed_t y);
+angle_t R_PointToAngle2 (fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2);
+fixed_t R_PointToDist (fixed_t x, fixed_t y);
+fixed_t R_ScaleFromGlobalAngle (angle_t visangle);
+subsector_t *R_PointInSubsector (fixed_t x, fixed_t y);
+/*
+void R_AddPointToBox (int x, int y, fixed_t *box);
+*/
+
+
+/* ---- R_bsp.c ---- */
+
+extern	seg_t		*curline;
+extern	side_t		*sidedef;
+extern	line_t		*linedef;
+extern	sector_t	*frontsector, *backsector;
+
+extern	int		rw_x;
+extern	int		rw_stopx;
+
+extern	boolean		segtextured;
+extern	boolean		markfloor;	/* false if the back side is the same plane */
+extern	boolean		markceiling;
+extern	boolean		skymap;
+
+extern	drawseg_t	drawsegs[MAXDRAWSEGS], *ds_p;
+
+extern	lighttable_t	**hscalelight, **vscalelight, **dscalelight;
+
+typedef void (*drawfunc_t) (int start, int stop);
+void R_ClearClipSegs (void);
+
+void R_ClearDrawSegs (void);
+void R_InitSkyMap (void);
+void R_RenderBSPNode (int bspnum);
+
+
+/* ---- R_segs.c ---- */
+
+extern	int		rw_angle1;	/* angle to line origin */
+extern	int		TransTextureStart;
+extern	int		TransTextureEnd;
+
+void R_RenderMaskedSegRange (drawseg_t *ds, int x1, int x2);
+
+
+/* ---- R_plane.c ---- */
+
+typedef void (*planefunction_t) (int top, int bottom);
+extern	planefunction_t		floorfunc, ceilingfunc;
+
+extern	int		skyflatnum;
+
+extern	short		openings[MAXOPENINGS], *lastopening;
+
+extern	short		floorclip[SCREENWIDTH];
+extern	short		ceilingclip[SCREENWIDTH];
+
+extern	fixed_t		yslope[SCREENHEIGHT];
+extern	fixed_t		distscale[SCREENWIDTH];
+
+void R_InitPlanes (void);
+void R_ClearPlanes (void);
+void R_MapPlane (int y, int x1, int x2);
+void R_MakeSpans (int x, int t1, int b1, int t2, int b2);
+void R_DrawPlanes (void);
+
+visplane_t *R_FindPlane (fixed_t height, int picnum, int lightlevel, int special);
+visplane_t *R_CheckPlane (visplane_t *pl, int start, int stop);
+
+
+/* ---- R_data.c ---- */
+
+typedef struct
+{
+	int	originx;	/* block origin (allways UL), which has allready */
+	int	originy;	/* accounted  for the patch's internal origin */
+	int	patch;
+} texpatch_t;
+
+/* a maptexturedef_t describes a rectangular texture, which is composed of one
+ * or more mappatch_t structures that arrange graphic patches
+ */
+typedef struct
+{
+	char	name[8];	/* for switch changing, etc */
+	short	width;
+	short	height;
+	short	patchcount;
+	texpatch_t patches[1];	/* [patchcount] drawn back to front */
+					/*  into the cached texture */
+#ifdef RENDER3D
+	boolean	masked;		/* from maptexture_t */
+#endif
+} texture_t;
+
+extern	fixed_t		*textureheight;		/* needed for texture pegging */
+extern	fixed_t		*spritewidth;		/* needed for pre rendering (fracs) */
+extern	fixed_t		*spriteoffset;
+extern	fixed_t		*spritetopoffset;
+extern	lighttable_t	*colormaps;
+extern	int		viewwidth, scaledviewwidth, viewheight;
+extern	int		firstflat;
+extern	int		numflats;
+
+extern	int		*flattranslation;	/* for global animation */
+extern	int		*texturetranslation;	/* for global animation */
+
+extern	int		firstspritelump, lastspritelump, numspritelumps;
+extern	boolean		LevelUseFullBright;
+
+byte *R_GetColumn (int tex, int col);
+void R_InitData (void);
+void R_PrecacheLevel (void);
+
+
+/* ---- R_things.c ---- */
+
+#define MAXVISSPRITES		192
+
+extern	vissprite_t	vissprites[MAXVISSPRITES], *vissprite_p;
+extern	vissprite_t	vsprsortedhead;
+
+/* constant arrays used for psprite clipping and initializing clipping */
+extern	short	negonearray[SCREENWIDTH];
+extern	short	screenheightarray[SCREENWIDTH];
+
+/* vars for R_DrawMaskedColumn */
+extern	short		*mfloorclip;
+extern	short		*mceilingclip;
+extern	fixed_t		spryscale;
+extern	fixed_t		sprtopscreen;
+extern	fixed_t		sprbotscreen;
+
+extern	fixed_t		pspritescale, pspriteiscale;
+
+
+void R_DrawMaskedColumn (column_t *column, signed int baseclip);
+
+void R_SortVisSprites (void);
+
+void R_AddSprites (sector_t *sec);
+void R_AddPSprites (void);
+void R_DrawSprites (void);
+void R_InitSprites (const char **namelist);
+void R_ClearSprites (void);
+void R_DrawMasked (void);
+void R_ClipVisSprite (vissprite_t *vis, int xl, int xh);
+
+
+/* ---- R_draw.c ---- */
+
+extern	lighttable_t	*dc_colormap;
+extern	int		dc_x;
+extern	int		dc_yl;
+extern	int		dc_yh;
+extern	fixed_t		dc_iscale;
+extern	fixed_t		dc_texturemid;
+extern	byte		*dc_source;	/* first pixel in a column */
+
+void R_DrawColumn (void);
+void R_DrawColumnLow (void);
+void R_DrawFuzzColumn (void);
+void R_DrawFuzzColumnLow (void);
+void R_DrawTranslatedColumn (void);
+void R_DrawTranslatedFuzzColumn (void);
+void R_DrawTranslatedColumnLow (void);
+void R_DrawAltFuzzColumn(void);
+/*
+void R_DrawTranslatedAltFuzzColumn(void);
+*/
+
+extern	int		ds_y;
+extern	int		ds_x1;
+extern	int		ds_x2;
+extern	lighttable_t	*ds_colormap;
+extern	fixed_t		ds_xfrac;
+extern	fixed_t		ds_yfrac;
+extern	fixed_t		ds_xstep;
+extern	fixed_t		ds_ystep;
+extern	byte		*ds_source;	/* start of a 64*64 tile image */
+
+extern	byte		*translationtables;
+extern	byte		*dc_translation;
+
+void R_DrawSpan (void);
+void R_DrawSpanLow (void);
+
+void R_InitBuffer (int width, int height);
+void R_InitTranslationTables (void);
+
+#endif	/* __R_LOCAL__ */
+
--- /dev/null
+++ b/r_main.c
@@ -1,0 +1,831 @@
+
+//**************************************************************************
+//**
+//** r_main.c : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 373 $
+//** $Date: 2009-05-19 21:14:28 +0300 (Tue, 19 May 2009) $
+//**
+//**************************************************************************
+
+#include "h2stdinc.h"
+
+#ifndef RENDER3D
+
+#include "h2def.h"
+#include "r_local.h"
+
+int			viewangleoffset;
+
+int			validcount = 1;		// increment every time a check is made
+
+lighttable_t		*fixedcolormap;
+extern	lighttable_t	**walllights;
+
+int			centerx, centery;
+fixed_t			centerxfrac, centeryfrac;
+fixed_t			projection;
+
+int			framecount;		// just for profiling purposes
+
+int			sscount, linecount, loopcount;
+
+fixed_t			viewx, viewy, viewz;
+angle_t			viewangle;
+fixed_t			viewcos, viewsin;
+player_t		*viewplayer;
+
+int			detailshift;		// 0 = high, 1 = low
+
+//
+// precalculated math tables
+//
+angle_t			clipangle;
+
+// The viewangletox[viewangle + FINEANGLES/4] lookup maps the visible view
+// angles  to screen X coordinates, flattening the arc to a flat projection
+// plane.  There will be many angles mapped to the same X.
+int			viewangletox[FINEANGLES/2];
+
+// The xtoviewangleangle[] table maps a screen pixel to the lowest viewangle
+// that maps back to x ranges from clipangle to -clipangle
+angle_t			xtoviewangle[SCREENWIDTH+1];
+
+// the finetangentgent[angle+FINEANGLES/4] table holds the fixed_t tangent
+// values for view angles, ranging from H2MININT to 0 to H2MAXINT.
+// fixed_t		finetangent[FINEANGLES/2];
+
+// fixed_t		finesine[5*FINEANGLES/4];
+fixed_t			*finecosine = &finesine[FINEANGLES/4];
+
+lighttable_t		*scalelight[LIGHTLEVELS][MAXLIGHTSCALE];
+lighttable_t		*scalelightfixed[MAXLIGHTSCALE];
+lighttable_t		*zlight[LIGHTLEVELS][MAXLIGHTZ];
+
+int			extralight;		// bumped light from gun blasts
+
+void			(*colfunc) (void);
+void			(*basecolfunc) (void);
+void			(*fuzzcolfunc) (void);
+void			(*transcolfunc) (void);
+void			(*spanfunc) (void);
+
+/*
+===================
+=
+= R_AddPointToBox
+=
+===================
+*/
+
+/*
+void R_AddPointToBox (int x, int y, fixed_t *box)
+{
+	if (x < box[BOXLEFT])
+		box[BOXLEFT] = x;
+	if (x > box[BOXRIGHT])
+		box[BOXRIGHT] = x;
+	if (y < box[BOXBOTTOM])
+		box[BOXBOTTOM] = y;
+	if (y > box[BOXTOP])
+		box[BOXTOP] = y;
+}
+*/
+
+
+/*
+===============================================================================
+=
+= R_PointOnSide
+=
+= Returns side 0 (front) or 1 (back)
+===============================================================================
+*/
+
+int	R_PointOnSide (fixed_t x, fixed_t y, node_t *node)
+{
+	fixed_t	dx, dy;
+	fixed_t	left, right;
+
+	if (!node->dx)
+	{
+		if (x <= node->x)
+			return node->dy > 0;
+		return node->dy < 0;
+	}
+	if (!node->dy)
+	{
+		if (y <= node->y)
+			return node->dx < 0;
+		return node->dx > 0;
+	}
+
+	dx = (x - node->x);
+	dy = (y - node->y);
+
+// try to quickly decide by looking at sign bits
+	if ((node->dy ^ node->dx ^ dx ^ dy) & 0x80000000)
+	{
+		if ((node->dy ^ dx) & 0x80000000)
+			return 1;	// (left is negative)
+		return 0;
+	}
+
+	left = FixedMul (node->dy>>FRACBITS , dx);
+	right = FixedMul (dy , node->dx>>FRACBITS);
+
+	if (right < left)
+		return 0;		// front side
+	return 1;			// back side
+}
+
+
+int	R_PointOnSegSide (fixed_t x, fixed_t y, seg_t *line)
+{
+	fixed_t	lx, ly;
+	fixed_t	ldx, ldy;
+	fixed_t	dx, dy;
+	fixed_t	left, right;
+
+	lx = line->v1->x;
+	ly = line->v1->y;
+
+	ldx = line->v2->x - lx;
+	ldy = line->v2->y - ly;
+
+	if (!ldx)
+	{
+		if (x <= lx)
+			return ldy > 0;
+		return ldy < 0;
+	}
+	if (!ldy)
+	{
+		if (y <= ly)
+			return ldx < 0;
+		return ldx > 0;
+	}
+
+	dx = (x - lx);
+	dy = (y - ly);
+
+// try to quickly decide by looking at sign bits
+	if ((ldy ^ ldx ^ dx ^ dy) & 0x80000000)
+	{
+		if ((ldy ^ dx) & 0x80000000)
+			return 1;	// (left is negative)
+		return 0;
+	}
+
+	left = FixedMul (ldy>>FRACBITS, dx);
+	right = FixedMul (dy, ldx>>FRACBITS);
+
+	if (right < left)
+		return 0;		// front side
+	return 1;			// back side
+}
+
+
+/*
+===============================================================================
+=
+= R_PointToAngle
+=
+===============================================================================
+*/
+
+// to get a global angle from cartesian coordinates, the coordinates are
+// flipped until they are in the first octant of the coordinate system, then
+// the y (<=x) is scaled and divided by x to get a tangent (slope) value
+// which is looked up in the tantoangle[] table.  The +1 size is to handle
+// the case when x==y without additional checking.
+#define	SLOPERANGE	2048
+#define	SLOPEBITS	11
+#define	DBITS		(FRACBITS-SLOPEBITS)
+
+extern	int	tantoangle[SLOPERANGE+1];		// get from tables.c
+
+//int	tantoangle[SLOPERANGE+1];
+
+static int SlopeDiv (unsigned num, unsigned den)
+{
+	unsigned ans;
+	if (den < 512)
+		return SLOPERANGE;
+	ans = (num<<3) / (den>>8);
+	return ans <= SLOPERANGE ? ans : SLOPERANGE;
+}
+
+angle_t R_PointToAngle (fixed_t x, fixed_t y)
+{
+	x -= viewx;
+	y -= viewy;
+	if ( (!x) && (!y) )
+		return 0;
+	if (x >= 0)
+	{	// x >= 0
+		if (y >= 0)
+		{	// y >= 0
+			if (x > y)
+				return tantoangle[SlopeDiv(y,x)];	// octant 0
+			else
+				return ANG90 - 1 - tantoangle[SlopeDiv(x,y)];	// octant 1
+		}
+		else
+		{	// y < 0
+			y = -y;
+			if (x > y)
+				return -tantoangle[SlopeDiv(y,x)];	// octant 8
+			else
+				return ANG270 + tantoangle[SlopeDiv(x,y)];	// octant 7
+		}
+	}
+	else
+	{	// x < 0
+		x = -x;
+		if (y >= 0)
+		{	// y >= 0
+			if (x > y)
+				return ANG180 - 1 - tantoangle[SlopeDiv(y,x)];	// octant 3
+			else
+				return ANG90 + tantoangle[SlopeDiv(x,y)];	// octant 2
+		}
+		else
+		{	// y < 0
+			y = -y;
+			if (x > y)
+				return ANG180 + tantoangle[SlopeDiv(y,x)];	// octant 4
+			else
+				return ANG270 - 1 - tantoangle[SlopeDiv(x,y)];	// octant 5
+		}
+	}
+
+	return 0;
+}
+
+
+angle_t R_PointToAngle2 (fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2)
+{
+	viewx = x1;
+	viewy = y1;
+	return R_PointToAngle (x2, y2);
+}
+
+
+fixed_t	R_PointToDist (fixed_t x, fixed_t y)
+{
+	int		angle;
+	fixed_t	dx, dy, temp;
+	fixed_t	dist;
+
+	dx = abs(x - viewx);
+	dy = abs(y - viewy);
+
+	if (dy > dx)
+	{
+		temp = dx;
+		dx = dy;
+		dy = temp;
+	}
+
+	angle = (tantoangle[ FixedDiv(dy,dx)>>DBITS ]+ANG90) >> ANGLETOFINESHIFT;
+
+	dist = FixedDiv (dx, finesine[angle]);	// use as cosine
+
+	return dist;
+}
+
+
+/*
+=================
+=
+= R_InitPointToAngle
+=
+=================
+*/
+
+void R_InitPointToAngle (void)
+{
+// now getting from tables.c
+#if 0
+	int	i;
+	int	t;	/* int32_t */
+	float	f;
+//
+// slope (tangent) to angle lookup
+//
+	for (i = 0; i <= SLOPERANGE; i++)
+	{
+		f = atan((float)i / SLOPERANGE) / (3.141592657*2);
+		t = 0xffffffff * f;
+		tantoangle[i] = t;
+	}
+#endif
+}
+
+//=============================================================================
+
+/*
+================
+=
+= R_ScaleFromGlobalAngle
+=
+= Returns the texture mapping scale for the current line at the given angle
+= rw_distance must be calculated first
+================
+*/
+
+fixed_t R_ScaleFromGlobalAngle (angle_t visangle)
+{
+	fixed_t		scale;
+	int		anglea, angleb;
+	int		sinea, sineb;
+	fixed_t		num, den;
+
+#if 0
+{
+	fixed_t		dist, z;
+	fixed_t		sinv, cosv;
+
+	sinv = finesine[(visangle - rw_normalangle)>>ANGLETOFINESHIFT];
+	dist = FixedDiv (rw_distance, sinv);
+	cosv = finecosine[(viewangle - visangle)>>ANGLETOFINESHIFT];
+	z = abs(FixedMul (dist, cosv));
+	scale = FixedDiv(projection, z);
+	return scale;
+}
+#endif
+
+	anglea = ANG90 + (visangle - viewangle);
+	angleb = ANG90 + (visangle - rw_normalangle);
+// bothe sines are allways positive
+	sinea = finesine[anglea>>ANGLETOFINESHIFT];
+	sineb = finesine[angleb>>ANGLETOFINESHIFT];
+	num = FixedMul(projection, sineb)<<detailshift;
+	den = FixedMul(rw_distance, sinea);
+	if (den > num>>16)
+	{
+		scale = FixedDiv (num, den);
+		if (scale > 64*FRACUNIT)
+			scale = 64*FRACUNIT;
+		else if (scale < 256)
+			scale = 256;
+	}
+	else
+		scale = 64*FRACUNIT;
+
+	return scale;
+}
+
+
+/*
+=================
+=
+= R_InitTables
+=
+=================
+*/
+
+void R_InitTables (void)
+{
+// now getting from tables.c
+#if 0
+	int		i;
+	float		a, fv;
+	int		t;
+
+//
+// viewangle tangent table
+//
+	for (i = 0; i < FINEANGLES/2; i++)
+	{
+		a = (i - FINEANGLES/4 + 0.5) * PI * 2 / FINEANGLES;
+		fv = FRACUNIT * tan(a);
+		t = fv;
+		finetangent[i] = t;
+	}
+
+//
+// finesine table
+//
+	for (i = 0; i < 5*FINEANGLES/4; i++)
+	{
+// OPTIMIZE: mirror...
+		a = (i + 0.5) * PI * 2 / FINEANGLES;
+		t = FRACUNIT * sin(a);
+		finesine[i] = t;
+	}
+#endif
+}
+
+
+/*
+=================
+=
+= R_InitTextureMapping
+=
+=================
+*/
+
+void R_InitTextureMapping (void)
+{
+	int			i;
+	int			x;
+	int			t;
+	fixed_t		focallength;
+
+//
+// use tangent table to generate viewangletox
+// viewangletox will give the next greatest x after the view angle
+//
+	// calc focallength so FIELDOFVIEW angles covers SCREENWIDTH
+	focallength = FixedDiv (centerxfrac, finetangent[FINEANGLES/4 + FIELDOFVIEW/2]);
+
+	for (i = 0; i < FINEANGLES/2; i++)
+	{
+		if (finetangent[i] > FRACUNIT*2)
+			t = -1;
+		else if (finetangent[i] < -FRACUNIT*2)
+			t = viewwidth + 1;
+		else
+		{
+			t = FixedMul (finetangent[i], focallength);
+			t = (centerxfrac - t + FRACUNIT - 1)>>FRACBITS;
+			if (t < -1)
+				t = -1;
+			else if (t > viewwidth + 1)
+				t = viewwidth + 1;
+		}
+		viewangletox[i] = t;
+	}
+
+//
+// scan viewangletox[] to generate xtoviewangleangle[]
+//
+// xtoviewangle will give the smallest view angle that maps to x
+	for (x = 0; x <= viewwidth; x++)
+	{
+		i = 0;
+		while (viewangletox[i] > x)
+			i++;
+		xtoviewangle[x] = (i<<ANGLETOFINESHIFT) - ANG90;
+	}
+
+//
+// take out the fencepost cases from viewangletox
+//
+	for (i = 0; i < FINEANGLES/2; i++)
+	{
+		t = FixedMul (finetangent[i], focallength);
+		t = centerx - t;
+		if (viewangletox[i] == -1)
+			viewangletox[i] = 0;
+		else if (viewangletox[i] == viewwidth + 1)
+			viewangletox[i]  = viewwidth;
+	}
+
+	clipangle = xtoviewangle[0];
+}
+
+//=============================================================================
+
+/*
+====================
+=
+= R_InitLightTables
+=
+= Only inits the zlight table, because the scalelight table changes
+= with view size
+=
+====================
+*/
+
+#define	DISTMAP		2
+
+void R_InitLightTables (void)
+{
+	int		i, j, level, start_map;
+	int		scale;
+
+//
+// Calculate the light levels to use for each level / distance combination
+//
+	for (i = 0; i < LIGHTLEVELS; i++)
+	{
+		start_map = ((LIGHTLEVELS - 1 - i) * 2) * NUMCOLORMAPS / LIGHTLEVELS;
+		for (j = 0; j < MAXLIGHTZ; j++)
+		{
+			scale = FixedDiv ((SCREENWIDTH/2*FRACUNIT), (j + 1)<<LIGHTZSHIFT);
+			scale >>= LIGHTSCALESHIFT;
+			level = start_map - scale/DISTMAP;
+			if (level < 0)
+				level = 0;
+			if (level >= NUMCOLORMAPS)
+				level = NUMCOLORMAPS-1;
+			zlight[i][j] = colormaps + level*256;
+		}
+	}
+}
+
+
+/*
+==============
+=
+= R_SetViewSize
+=
+= Don't really change anything here, because i might be in the middle of
+= a refresh.  The change will take effect next refresh.
+=
+==============
+*/
+
+static int	setblocks, setdetail;
+boolean		setsizeneeded;
+
+void R_SetViewSize (int blocks, int detail)
+{
+	setsizeneeded = true;
+	setblocks = blocks;
+	setdetail = detail;
+}
+
+/*
+==============
+=
+= R_ExecuteSetViewSize
+=
+==============
+*/
+
+void R_ExecuteSetViewSize (void)
+{
+	fixed_t	cosadj, dy;
+	int		i, j, level, start_map;
+
+	setsizeneeded = false;
+
+	if (setblocks == 11)
+	{
+		scaledviewwidth = SCREENWIDTH;
+		viewheight = SCREENHEIGHT;
+	}
+	else
+	{
+		scaledviewwidth = setblocks*32;
+		viewheight = (setblocks*161/10);
+	}
+
+	detailshift = setdetail;
+	viewwidth = scaledviewwidth>>detailshift;
+
+	centery = viewheight/2;
+	centerx = viewwidth/2;
+	centerxfrac = centerx<<FRACBITS;
+	centeryfrac = centery<<FRACBITS;
+	projection = centerxfrac;
+
+	if (!detailshift)
+	{
+		colfunc = basecolfunc = R_DrawColumn;
+		fuzzcolfunc = R_DrawFuzzColumn;
+		transcolfunc = R_DrawTranslatedColumn;
+		spanfunc = R_DrawSpan;
+	}
+	else
+	{
+		colfunc = basecolfunc = R_DrawColumnLow;
+		fuzzcolfunc = R_DrawFuzzColumn;
+		transcolfunc = R_DrawTranslatedColumn;
+		spanfunc = R_DrawSpanLow;
+	}
+
+	R_InitBuffer (scaledviewwidth, viewheight);
+
+	R_InitTextureMapping ();
+
+//
+// psprite scales
+//
+	pspritescale = FRACUNIT*viewwidth/SCREENWIDTH;
+	pspriteiscale = FRACUNIT*SCREENWIDTH/viewwidth;
+
+//
+// thing clipping
+//
+	for (i = 0; i < viewwidth; i++)
+		screenheightarray[i] = viewheight;
+
+//
+// planes
+//
+	for (i = 0; i < viewheight; i++)
+	{
+		dy = ((i - viewheight/2)<<FRACBITS) + FRACUNIT/2;
+		dy = abs(dy);
+		yslope[i] = FixedDiv ((viewwidth<<detailshift)/2*FRACUNIT, dy);
+	}
+
+	for (i = 0; i < viewwidth; i++)
+	{
+		cosadj = abs(finecosine[xtoviewangle[i]>>ANGLETOFINESHIFT]);
+		distscale[i] = FixedDiv (FRACUNIT, cosadj);
+	}
+
+//
+// Calculate the light levels to use for each level / scale combination
+//
+	for (i = 0; i < LIGHTLEVELS; i++)
+	{
+		start_map = ((LIGHTLEVELS - 1 - i) * 2) * NUMCOLORMAPS / LIGHTLEVELS;
+		for (j = 0; j < MAXLIGHTSCALE; j++)
+		{
+			level = start_map - j*SCREENWIDTH/(viewwidth<<detailshift)/DISTMAP;
+			if (level < 0)
+				level = 0;
+			if (level >= NUMCOLORMAPS)
+				level = NUMCOLORMAPS-1;
+			scalelight[i][j] = colormaps + level*256;
+		}
+	}
+
+//
+// draw the border
+//
+	R_DrawViewBorder ();	// erase old menu stuff
+}
+
+
+/*
+==============
+=
+= R_Init
+=
+==============
+*/
+
+int detailLevel;
+int screenblocks;
+
+void R_Init(void)
+{
+	R_InitData();
+	R_InitPointToAngle();
+	R_InitTables();
+	// viewwidth / viewheight / detailLevel are set by the defaults
+	R_SetViewSize(screenblocks, detailLevel);
+	R_InitPlanes();
+	R_InitLightTables();
+	R_InitSkyMap();
+	R_InitTranslationTables();
+	framecount = 0;
+}
+
+/*
+==============
+=
+= R_PointInSubsector
+=
+==============
+*/
+
+subsector_t *R_PointInSubsector (fixed_t x, fixed_t y)
+{
+	node_t	*node;
+	int		side, nodenum;
+
+	if (!numnodes)	// single subsector is a special case
+		return subsectors;
+
+	nodenum = numnodes - 1;
+
+	while (! (nodenum & NF_SUBSECTOR) )
+	{
+		node = &nodes[nodenum];
+		side = R_PointOnSide (x, y, node);
+		nodenum = node->children[side];
+	}
+
+	return &subsectors[nodenum & ~NF_SUBSECTOR];
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC R_SetupFrame
+//
+//----------------------------------------------------------------------------
+
+void R_SetupFrame(player_t *player)
+{
+	int i;
+	int tableAngle;
+	int tempCentery;
+	int intensity;
+
+	viewplayer = player;
+	viewangle = player->mo->angle + viewangleoffset;
+	tableAngle = viewangle>>ANGLETOFINESHIFT;
+	viewx = player->mo->x;
+	viewy = player->mo->y;
+
+	if (localQuakeHappening[displayplayer] && !paused)
+	{
+		intensity = localQuakeHappening[displayplayer];
+		viewx += ((M_Random() % (intensity<<2)) - (intensity<<1)) << FRACBITS;
+		viewy += ((M_Random() % (intensity<<2)) - (intensity<<1)) << FRACBITS;
+	}
+
+	extralight = player->extralight;
+	viewz = player->viewz;
+
+	tempCentery = viewheight/2 + (player->lookdir)*screenblocks/10;
+	if (centery != tempCentery)
+	{
+		centery = tempCentery;
+		centeryfrac = centery<<FRACBITS;
+		for (i = 0; i < viewheight; i++)
+		{
+			yslope[i] = FixedDiv (  (viewwidth<<detailshift)/2*FRACUNIT,
+						abs(((i - centery)<<FRACBITS) + FRACUNIT/2) );
+		}
+	}
+	viewsin = finesine[tableAngle];
+	viewcos = finecosine[tableAngle];
+	sscount = 0;
+	if (player->fixedcolormap)
+	{
+		fixedcolormap = colormaps + player->fixedcolormap*256*sizeof(lighttable_t);
+		walllights = scalelightfixed;
+		for (i = 0; i < MAXLIGHTSCALE; i++)
+		{
+			scalelightfixed[i] = fixedcolormap;
+		}
+	}
+	else
+	{
+		fixedcolormap = 0;
+	}
+	framecount++;
+	validcount++;
+	if (BorderNeedRefresh)
+	{
+		if (setblocks < 10)
+		{
+			R_DrawViewBorder();
+		}
+		BorderNeedRefresh = false;
+		BorderTopRefresh = false;
+		UpdateState |= I_FULLSCRN;
+	}
+	if (BorderTopRefresh)
+	{
+		if (setblocks < 10)
+		{
+			R_DrawTopBorder();
+		}
+		BorderTopRefresh = false;
+		UpdateState |= I_MESSAGES;
+	}
+}
+
+/*
+==============
+=
+= R_RenderView
+=
+==============
+*/
+
+void R_RenderPlayerView (player_t *player)
+{
+	R_SetupFrame (player);
+
+	R_ClearClipSegs ();
+	R_ClearDrawSegs ();
+	R_ClearPlanes ();
+
+	R_ClearSprites ();
+	NetUpdate ();	// check for new console commands
+
+	// Make displayed player invisible locally
+	if (localQuakeHappening[displayplayer] && gamestate == GS_LEVEL)
+	{
+		players[displayplayer].mo->flags2 |= MF2_DONTDRAW;
+		R_RenderBSPNode (numnodes - 1);	// head node is the last node output
+		players[displayplayer].mo->flags2 &= ~MF2_DONTDRAW;
+	}
+	else
+	{
+		R_RenderBSPNode (numnodes - 1);	// head node is the last node output
+	}
+
+	NetUpdate ();	// check for new console commands
+
+	R_DrawPlanes ();
+	NetUpdate ();	// check for new console commands
+
+	R_DrawMasked ();
+	NetUpdate ();	// check for new console commands
+}
+
+#endif	/* RENDER3D */
+
--- /dev/null
+++ b/r_plane.c
@@ -1,0 +1,550 @@
+
+//**************************************************************************
+//**
+//** r_plane.c : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 491 $
+//** $Date: 2009-05-30 01:10:42 +0300 (Sat, 30 May 2009) $
+//**
+//**************************************************************************
+
+// HEADER FILES ------------------------------------------------------------
+
+#include "h2stdinc.h"
+
+#ifndef RENDER3D
+
+#include "h2def.h"
+#include "r_local.h"
+
+// MACROS ------------------------------------------------------------------
+
+// TYPES -------------------------------------------------------------------
+
+// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
+
+// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
+
+// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
+
+// EXTERNAL DATA DECLARATIONS ----------------------------------------------
+
+extern fixed_t		Sky1ScrollDelta;
+extern fixed_t		Sky2ScrollDelta;
+
+extern byte		*ylookup[MAXHEIGHT];
+extern int		columnofs[MAXWIDTH];
+
+// PUBLIC DATA DEFINITIONS -------------------------------------------------
+
+int			Sky1Texture;
+int			Sky2Texture;
+fixed_t			Sky1ColumnOffset;
+fixed_t			Sky2ColumnOffset;
+int			skyflatnum;
+int			skytexturemid;
+fixed_t			skyiscale;
+boolean			DoubleSky;
+planefunction_t		floorfunc, ceilingfunc;
+
+// Opening
+visplane_t		visplanes[MAXVISPLANES], *lastvisplane;
+visplane_t		*floorplane, *ceilingplane;
+short			openings[MAXOPENINGS], *lastopening;
+
+// Clip values are the solid pixel bounding the range.
+// floorclip start out SCREENHEIGHT
+// ceilingclip starts out -1
+short			floorclip[SCREENWIDTH];
+short			ceilingclip[SCREENWIDTH];
+
+// spanstart holds the start of a plane span, initialized to 0
+int			spanstart[SCREENHEIGHT];
+int			spanstop[SCREENHEIGHT];
+
+// Texture mapping
+lighttable_t		**planezlight;
+fixed_t			planeheight;
+fixed_t			yslope[SCREENHEIGHT];
+fixed_t			distscale[SCREENWIDTH];
+fixed_t			basexscale, baseyscale;
+fixed_t			cachedheight[SCREENHEIGHT];
+fixed_t			cacheddistance[SCREENHEIGHT];
+fixed_t			cachedxstep[SCREENHEIGHT];
+fixed_t			cachedystep[SCREENHEIGHT];
+
+// PRIVATE DATA DEFINITIONS ------------------------------------------------
+
+// CODE --------------------------------------------------------------------
+
+//==========================================================================
+//
+// R_InitSky
+//
+// Called at level load.
+//
+//==========================================================================
+
+void R_InitSky(int map)
+{
+	Sky1Texture = P_GetMapSky1Texture(map);
+	Sky2Texture = P_GetMapSky2Texture(map);
+	Sky1ScrollDelta = P_GetMapSky1ScrollDelta(map);
+	Sky2ScrollDelta = P_GetMapSky2ScrollDelta(map);
+	Sky1ColumnOffset = 0;
+	Sky2ColumnOffset = 0;
+	DoubleSky = P_GetMapDoubleSky(map);
+}
+
+//==========================================================================
+//
+// R_InitSkyMap
+//
+// Called whenever the view size changes.
+//
+//==========================================================================
+
+void R_InitSkyMap(void)
+{
+	skyflatnum = R_FlatNumForName("F_SKY");
+	skytexturemid = 200*FRACUNIT;
+	skyiscale = FRACUNIT;
+}
+
+//==========================================================================
+//
+// R_InitPlanes
+//
+// Called at game startup.
+//
+//==========================================================================
+
+void R_InitPlanes(void)
+{
+}
+
+//==========================================================================
+//
+// R_MapPlane
+//
+// Globals used: planeheight, ds_source, basexscale, baseyscale,
+// viewx, viewy.
+//
+//==========================================================================
+
+void R_MapPlane(int y, int x1, int x2)
+{
+	angle_t angle;
+	fixed_t distance, length;
+	unsigned idx;
+
+#ifdef RANGECHECK
+	if (x2 < x1 || x1 < 0 || x2 >= viewwidth || (unsigned)y > viewheight)
+	{
+		I_Error("R_MapPlane: %i, %i at %i", x1, x2, y);
+	}
+#endif
+
+	if (planeheight != cachedheight[y])
+	{
+		cachedheight[y] = planeheight;
+		distance = cacheddistance[y] = FixedMul(planeheight, yslope[y]);
+		ds_xstep = cachedxstep[y] = FixedMul(distance, basexscale);
+		ds_ystep = cachedystep[y] = FixedMul(distance, baseyscale);
+	}
+	else
+	{
+		distance = cacheddistance[y];
+		ds_xstep = cachedxstep[y];
+		ds_ystep = cachedystep[y];
+	}
+
+	length = FixedMul(distance, distscale[x1]);
+	angle = (viewangle+xtoviewangle[x1])>>ANGLETOFINESHIFT;
+	ds_xfrac = viewx+FixedMul(finecosine[angle], length);
+	ds_yfrac = -viewy-FixedMul(finesine[angle], length);
+
+	if (fixedcolormap)
+	{
+		ds_colormap = fixedcolormap;
+	}
+	else
+	{
+		idx = distance >> LIGHTZSHIFT;
+		if (idx >= MAXLIGHTZ)
+		{
+			idx = MAXLIGHTZ-1;
+		}
+		ds_colormap = planezlight[idx];
+	}
+
+	ds_y = y;
+	ds_x1 = x1;
+	ds_x2 = x2;
+
+	spanfunc();	// High or low detail
+}
+
+//==========================================================================
+//
+// R_ClearPlanes
+//
+// Called at the beginning of each frame.
+//
+//==========================================================================
+
+void R_ClearPlanes(void)
+{
+	int i;
+	angle_t angle;
+
+	// Opening / clipping determination
+	for (i = 0; i < viewwidth; i++)
+	{
+		floorclip[i] = viewheight;
+		ceilingclip[i] = -1;
+	}
+
+	lastvisplane = visplanes;
+	lastopening = openings;
+
+	// Texture calculation
+	memset(cachedheight, 0, sizeof(cachedheight));
+	angle = (viewangle - ANG90)>>ANGLETOFINESHIFT;	// left to right mapping
+	// Scale will be unit scale at SCREENWIDTH/2 distance
+	basexscale = FixedDiv(finecosine[angle], centerxfrac);
+	baseyscale = -FixedDiv(finesine[angle], centerxfrac);
+}
+
+//==========================================================================
+//
+// R_FindPlane
+//
+//==========================================================================
+
+visplane_t *R_FindPlane(fixed_t height, int picnum,
+			int lightlevel, int special)
+{
+	visplane_t *check;
+
+	if (special < 150)
+	{ // Don't let low specials affect search
+		special = 0;
+	}
+
+	if (picnum == skyflatnum)
+	{ // All skies map together
+		height = 0;
+		lightlevel = 0;
+	}
+
+	for (check = visplanes; check < lastvisplane; check++)
+	{
+		if (height == check->height &&
+		    picnum == check->picnum &&
+		    lightlevel == check->lightlevel &&
+		    special == check->special)
+			break;
+	}
+
+	if (check < lastvisplane)
+	{
+		return check;
+	}
+
+	if (lastvisplane - visplanes == MAXVISPLANES)
+	{
+		I_Error("R_FindPlane: no more visplanes");
+	}
+
+	lastvisplane++;
+	check->height = height;
+	check->picnum = picnum;
+	check->lightlevel = lightlevel;
+	check->special = special;
+	check->minx = SCREENWIDTH;
+	check->maxx = -1;
+	memset(check->top, 0xff, sizeof(check->top));
+	return check;
+}
+
+//==========================================================================
+//
+// R_CheckPlane
+//
+//==========================================================================
+
+visplane_t *R_CheckPlane(visplane_t *pl, int start, int stop)
+{
+	int intrl, intrh;
+	int unionl, unionh;
+	int x;
+
+	if (start < pl->minx)
+	{
+		intrl = pl->minx;
+		unionl = start;
+	}
+	else
+	{
+		unionl = pl->minx;
+		intrl = start;
+	}
+	if (stop > pl->maxx)
+	{
+		intrh = pl->maxx;
+		unionh = stop;
+	}
+	else
+	{
+		unionh = pl->maxx;
+		intrh = stop;
+	}
+
+	for (x = intrl; x <= intrh; x++)
+	{
+		if (pl->top[x] != 0xff)
+		{
+			break;
+		}
+	}
+
+	if (x > intrh)
+	{
+		pl->minx = unionl;
+		pl->maxx = unionh;
+		return pl;	// use the same visplane
+	}
+
+	// Make a new visplane
+	lastvisplane->height = pl->height;
+	lastvisplane->picnum = pl->picnum;
+	lastvisplane->lightlevel = pl->lightlevel;
+	lastvisplane->special = pl->special;
+	pl = lastvisplane++;
+	pl->minx = start;
+	pl->maxx = stop;
+	memset(pl->top, 0xff, sizeof(pl->top));
+
+	return pl;
+}
+
+//==========================================================================
+//
+// R_MakeSpans
+//
+//==========================================================================
+
+void R_MakeSpans(int x, int t1, int b1, int t2, int b2)
+{
+	while (t1 < t2 && t1 <= b1)
+	{
+		R_MapPlane(t1, spanstart[t1], x - 1);
+		t1++;
+	}
+	while (b1 > b2 && b1 >= t1)
+	{
+		R_MapPlane(b1, spanstart[b1], x - 1);
+		b1--;
+	}
+	while (t2 < t1 && t2 <= b2)
+	{
+		spanstart[t2] = x;
+		t2++;
+	}
+	while (b2 > b1 && b2 >= t2)
+	{
+		spanstart[b2] = x;
+		b2--;
+	}
+}
+
+//==========================================================================
+//
+// R_DrawPlanes
+//
+//==========================================================================
+
+#define SKYTEXTUREMIDSHIFTED	200
+
+void R_DrawPlanes(void)
+{
+	visplane_t *pl;
+	int light;
+	int x, stop;
+	int angle;
+	byte *tempSource;
+	byte *source;
+	byte *source2;
+	byte *dest;
+	int count;
+	int offset;
+	int skyTexture;
+	int offset2;
+	int skyTexture2;
+	int scrollOffset;
+
+#ifdef RANGECHECK
+	if (ds_p - drawsegs > MAXDRAWSEGS)
+	{
+		I_Error("R_DrawPlanes: drawsegs overflow (%i)", ds_p - drawsegs);
+	}
+	if (lastvisplane - visplanes > MAXVISPLANES)
+	{
+		I_Error("R_DrawPlanes: visplane overflow (%i)", lastvisplane - visplanes);
+	}
+	if (lastopening - openings > MAXOPENINGS)
+	{
+		I_Error("R_DrawPlanes: opening overflow (%i)", lastopening - openings);
+	}
+#endif
+
+	for (pl = visplanes; pl < lastvisplane; pl++)
+	{
+		if (pl->minx > pl->maxx)
+		{
+			continue;
+		}
+		if (pl->picnum == skyflatnum)
+		{ // Sky flat
+			if (DoubleSky)
+			{ // Render 2 layers, sky 1 in front
+				offset = Sky1ColumnOffset>>16;
+				skyTexture = texturetranslation[Sky1Texture];
+				offset2 = Sky2ColumnOffset>>16;
+				skyTexture2 = texturetranslation[Sky2Texture];
+				for (x = pl->minx; x <= pl->maxx; x++)
+				{
+					dc_yl = pl->top[x];
+					dc_yh = pl->bottom[x];
+					if (dc_yl <= dc_yh)
+					{
+						count = dc_yh - dc_yl;
+						if (count < 0)
+						{
+							return;
+						}
+						angle = (viewangle + xtoviewangle[x])>>ANGLETOSKYSHIFT;
+						source = R_GetColumn(skyTexture, angle + offset)
+								+ SKYTEXTUREMIDSHIFTED + (dc_yl - centery);
+						source2 = R_GetColumn(skyTexture2, angle + offset2)
+								+ SKYTEXTUREMIDSHIFTED + (dc_yl - centery);
+						dest = ylookup[dc_yl] + columnofs[x];
+						do
+						{
+							if (*source)
+							{
+								*dest = *source++;
+								source2++;
+							}
+							else
+							{
+								*dest = *source2++;
+								source++;
+							}
+							dest += SCREENWIDTH;
+						} while (count--);
+					}
+				}
+				continue; // Next visplane
+			}
+			else
+			{ // Render single layer
+				if (pl->special == 200)
+				{ // Use sky 2
+					offset = Sky2ColumnOffset>>16;
+					skyTexture = texturetranslation[Sky2Texture];
+				}
+				else
+				{ // Use sky 1
+					offset = Sky1ColumnOffset>>16;
+					skyTexture = texturetranslation[Sky1Texture];
+				}
+				for (x = pl->minx; x <= pl->maxx; x++)
+				{
+					dc_yl = pl->top[x];
+					dc_yh = pl->bottom[x];
+					if (dc_yl <= dc_yh)
+					{
+						count = dc_yh - dc_yl;
+						if (count < 0)
+						{
+							return;
+						}
+						angle = (viewangle + xtoviewangle[x])>>ANGLETOSKYSHIFT;
+						source = R_GetColumn(skyTexture, angle + offset)
+								+ SKYTEXTUREMIDSHIFTED + (dc_yl - centery);
+						dest = ylookup[dc_yl] + columnofs[x];
+						do
+						{
+							*dest = *source++;
+							dest += SCREENWIDTH;
+						} while (count--);
+					}
+				}
+				continue; // Next visplane
+			}
+		}
+		// Regular flat
+		tempSource = (byte *) W_CacheLumpNum(firstflat + flattranslation[pl->picnum], PU_STATIC);
+		scrollOffset = leveltime>>1 & 63;
+		switch (pl->special)
+		{ // Handle scrolling flats
+		case 201: case 202: case 203: // Scroll_North_xxx
+			ds_source = tempSource + ((scrollOffset<<(pl->special - 201) & 63)<<6);
+			break;
+		case 204: case 205: case 206: // Scroll_East_xxx
+			ds_source = tempSource + ((63 - scrollOffset)<<(pl->special - 204) & 63);
+			break;
+		case 207: case 208: case 209: // Scroll_South_xxx
+			ds_source = tempSource + (((63 - scrollOffset)<<(pl->special - 207) & 63)<<6);
+			break;
+		case 210: case 211: case 212: // Scroll_West_xxx
+			ds_source = tempSource + (scrollOffset<<(pl->special - 210) & 63);
+			break;
+		case 213: case 214: case 215: // Scroll_NorthWest_xxx
+			ds_source = tempSource + (scrollOffset<<(pl->special - 213) & 63)
+						+ ((scrollOffset<<(pl->special - 213) & 63)<<6);
+			break;
+		case 216: case 217: case 218: // Scroll_NorthEast_xxx
+			ds_source = tempSource + ((63 - scrollOffset)<<(pl->special - 216) & 63)
+						+ ((scrollOffset<<(pl->special - 216) & 63)<<6);
+			break;
+		case 219: case 220: case 221: // Scroll_SouthEast_xxx
+			ds_source = tempSource + ((63 - scrollOffset)<<(pl->special - 219) & 63)
+						+ (((63 - scrollOffset)<<(pl->special - 219) & 63)<<6);
+			break;
+		case 222: case 223: case 224: // Scroll_SouthWest_xxx
+			ds_source = tempSource + (scrollOffset<<(pl->special - 222) & 63)
+						+ (((63 - scrollOffset)<<(pl->special - 222) & 63)<<6);
+			break;
+		default:
+			ds_source = tempSource;
+			break;
+		}
+		planeheight = abs(pl->height - viewz);
+		light = (pl->lightlevel >> LIGHTSEGSHIFT) + extralight;
+		if (light >= LIGHTLEVELS)
+		{
+			light = LIGHTLEVELS-1;
+		}
+		if (light < 0)
+		{
+			light = 0;
+		}
+		planezlight = zlight[light];
+
+		pl->top[pl->maxx + 1] = 0xff;
+		pl->top[pl->minx - 1] = 0xff;
+
+		stop = pl->maxx + 1;
+		for (x = pl->minx; x <= stop; x++)
+		{
+			R_MakeSpans(x, pl->top[x - 1], pl->bottom[x - 1],
+					pl->top[x], pl->bottom[x]);
+		}
+		Z_ChangeTag(tempSource, PU_CACHE);
+	}
+}
+#endif	/* !RENDER3D */
+
--- /dev/null
+++ b/r_segs.c
@@ -1,0 +1,642 @@
+
+//**************************************************************************
+//**
+//** r_segs.c : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 491 $
+//** $Date: 2009-05-30 01:10:42 +0300 (Sat, 30 May 2009) $
+//**
+//** This version has the tall-sector-crossing-precision-bug fixed.
+//**
+//**************************************************************************
+
+#include "h2stdinc.h"
+
+#ifndef RENDER3D
+
+#include "h2def.h"
+#include "r_local.h"
+
+// OPTIMIZE: closed two sided lines as single sided
+
+boolean		segtextured;	// true if any of the segs textures might be vis
+boolean		markfloor;	// false if the back side is the same plane
+boolean		markceiling;
+boolean		maskedtexture;
+int		toptexture, bottomtexture, midtexture;
+
+angle_t		rw_normalangle;
+int		rw_angle1;	// angle to line origin
+
+//
+// wall
+//
+int		rw_x;
+int		rw_stopx;
+angle_t		rw_centerangle;
+fixed_t		rw_offset;
+fixed_t		rw_distance;
+fixed_t		rw_scale;
+fixed_t		rw_scalestep;
+fixed_t		rw_midtexturemid;
+fixed_t		rw_toptexturemid;
+fixed_t		rw_bottomtexturemid;
+
+int		worldtop, worldbottom, worldhigh, worldlow;
+
+fixed_t		pixhigh, pixlow;
+fixed_t		pixhighstep, pixlowstep;
+fixed_t		topfrac, topstep;
+fixed_t		bottomfrac, bottomstep;
+
+lighttable_t	**walllights;
+
+short		*maskedtexturecol;
+
+
+/*
+================
+=
+= R_RenderMaskedSegRange
+=
+================
+*/
+
+void R_RenderMaskedSegRange (drawseg_t *ds, int x1, int x2)
+{
+	unsigned	idx;
+	column_t	*col;
+	int		lightnum;
+	int		texnum;
+
+//
+// calculate light table
+// use different light tables for horizontal / vertical / diagonal
+// OPTIMIZE: get rid of LIGHTSEGSHIFT globally
+	curline = ds->curline;
+	frontsector = curline->frontsector;
+	backsector = curline->backsector;
+	texnum = texturetranslation[curline->sidedef->midtexture];
+
+	lightnum = (frontsector->lightlevel >> LIGHTSEGSHIFT) + extralight;
+	//if (curline->v1->y == curline->v2->y)
+	//	lightnum--;
+	//else if (curline->v1->x == curline->v2->x)
+	//	lightnum++;
+	//if (lightnum < 0)
+	//	walllights = scalelight[0];
+	if (lightnum >= LIGHTLEVELS)
+		walllights = scalelight[LIGHTLEVELS-1];
+	else
+		walllights = scalelight[lightnum];
+
+	maskedtexturecol = ds->maskedtexturecol;
+
+	rw_scalestep = ds->scalestep;
+	spryscale = ds->scale1 + (x1 - ds->x1)*rw_scalestep;
+	mfloorclip = ds->sprbottomclip;
+	mceilingclip = ds->sprtopclip;
+
+//
+// find positioning
+//
+	if (curline->linedef->flags & ML_DONTPEGBOTTOM)
+	{
+		dc_texturemid = frontsector->floorheight > backsector->floorheight ?
+				frontsector->floorheight : backsector->floorheight;
+		dc_texturemid = dc_texturemid + textureheight[texnum] - viewz;
+	}
+	else
+	{
+		dc_texturemid = frontsector->ceilingheight < backsector->ceilingheight ?
+				frontsector->ceilingheight : backsector->ceilingheight;
+		dc_texturemid = dc_texturemid - viewz;
+	}
+	dc_texturemid += curline->sidedef->rowoffset;
+
+	if (fixedcolormap)
+		dc_colormap = fixedcolormap;
+//
+// draw the columns
+//
+	for (dc_x = x1 ; dc_x <= x2 ; dc_x++)
+	{
+	// calculate lighting
+		if (maskedtexturecol[dc_x] != H2MAXSHORT)
+		{
+			if (!fixedcolormap)
+			{
+				idx = spryscale>>LIGHTSCALESHIFT;
+				if (idx >=  MAXLIGHTSCALE)
+					idx = MAXLIGHTSCALE-1;
+				dc_colormap = walllights[idx];
+			}
+
+			sprtopscreen = centeryfrac - FixedMul(dc_texturemid, spryscale);
+			dc_iscale = 0xffffffffu / (unsigned)spryscale;
+
+	//
+	// draw the texture
+	//
+			col = (column_t *)(
+				(byte *)R_GetColumn(texnum,maskedtexturecol[dc_x]) -3);
+
+			R_DrawMaskedColumn (col, -1);
+			maskedtexturecol[dc_x] = H2MAXSHORT;
+		}
+		spryscale += rw_scalestep;
+	}
+}
+
+/*
+================
+=
+= R_RenderSegLoop
+=
+= Draws zero, one, or two textures (and possibly a masked texture) for walls
+= Can draw or mark the starting pixel of floor and ceiling textures
+=
+= CALLED: CORE LOOPING ROUTINE
+================
+*/
+
+#define HEIGHTBITS	12
+#define HEIGHTUNIT	(1<<HEIGHTBITS)
+
+void R_RenderSegLoop (void)
+{
+	angle_t		angle;
+	unsigned	idx;
+	int		yl, yh, mid;
+	fixed_t		texturecolumn;
+	int		top, bottom;
+
+	texturecolumn = 0;			// shut up compiler warning
+
+	for ( ; rw_x < rw_stopx ; rw_x++)
+	{
+//
+// mark floor / ceiling areas
+//
+		yl = (topfrac + HEIGHTUNIT - 1)>>HEIGHTBITS;
+		if (yl < ceilingclip[rw_x] + 1)
+			yl = ceilingclip[rw_x] + 1;	// no space above wall
+		if (markceiling)
+		{
+			top = ceilingclip[rw_x] + 1;
+			bottom = yl - 1;
+			if (bottom >= floorclip[rw_x])
+				bottom = floorclip[rw_x] - 1;
+			if (top <= bottom)
+			{
+				ceilingplane->top[rw_x] = top;
+				ceilingplane->bottom[rw_x] = bottom;
+			}
+		}
+
+		yh = bottomfrac>>HEIGHTBITS;
+		if (yh >= floorclip[rw_x])
+			yh = floorclip[rw_x] - 1;
+		if (markfloor)
+		{
+			top = yh + 1;
+			bottom = floorclip[rw_x] - 1;
+			if (top <= ceilingclip[rw_x])
+				top = ceilingclip[rw_x] + 1;
+			if (top <= bottom)
+			{
+				floorplane->top[rw_x] = top;
+				floorplane->bottom[rw_x] = bottom;
+			}
+		}
+
+//
+// texturecolumn and lighting are independent of wall tiers
+//
+		if (segtextured)
+		{
+		// calculate texture offset
+			angle = (rw_centerangle + xtoviewangle[rw_x])>>ANGLETOFINESHIFT;
+			texturecolumn = rw_offset - FixedMul(finetangent[angle], rw_distance);
+			texturecolumn >>= FRACBITS;
+		// calculate lighting
+			idx = rw_scale>>LIGHTSCALESHIFT;
+			if (idx >=  MAXLIGHTSCALE)
+				idx = MAXLIGHTSCALE - 1;
+			dc_colormap = walllights[idx];
+			dc_x = rw_x;
+			dc_iscale = 0xffffffffu / (unsigned)rw_scale;
+		}
+
+//
+// draw the wall tiers
+//
+		if (midtexture)
+		{	// single sided line
+			dc_yl = yl;
+			dc_yh = yh;
+			dc_texturemid = rw_midtexturemid;
+			dc_source = R_GetColumn(midtexture, texturecolumn);
+			colfunc ();
+			ceilingclip[rw_x] = viewheight;
+			floorclip[rw_x] = -1;
+		}
+		else
+		{	// two sided line
+			if (toptexture)
+			{	// top wall
+				mid = pixhigh>>HEIGHTBITS;
+				pixhigh += pixhighstep;
+				if (mid >= floorclip[rw_x])
+					mid = floorclip[rw_x] - 1;
+				if (mid >= yl)
+				{
+					dc_yl = yl;
+					dc_yh = mid;
+					dc_texturemid = rw_toptexturemid;
+					dc_source = R_GetColumn(toptexture, texturecolumn);
+					colfunc ();
+					ceilingclip[rw_x] = mid;
+				}
+				else
+					ceilingclip[rw_x] = yl - 1;
+			}
+			else
+			{	// no top wall
+				if (markceiling)
+					ceilingclip[rw_x] = yl - 1;
+			}
+
+			if (bottomtexture)
+			{	// bottom wall
+				mid = (pixlow+HEIGHTUNIT-1)>>HEIGHTBITS;
+				pixlow += pixlowstep;
+				if (mid <= ceilingclip[rw_x])
+					mid = ceilingclip[rw_x] + 1;	// no space above wall
+				if (mid <= yh)
+				{
+					dc_yl = mid;
+					dc_yh = yh;
+					dc_texturemid = rw_bottomtexturemid;
+					dc_source = R_GetColumn(bottomtexture, texturecolumn);
+					colfunc ();
+					floorclip[rw_x] = mid;
+				}
+				else
+					floorclip[rw_x] = yh + 1;
+			}
+			else
+			{	// no bottom wall
+				if (markfloor)
+					floorclip[rw_x] = yh + 1;
+			}
+
+			if (maskedtexture)
+			{	// save texturecol for backdrawing of masked mid texture
+				maskedtexturecol[rw_x] = texturecolumn;
+			}
+		}
+
+		rw_scale += rw_scalestep;
+		topfrac += topstep;
+		bottomfrac += bottomstep;
+	}
+}
+
+
+/*
+=====================
+=
+= R_StoreWallRange
+=
+= A wall segment will be drawn between start and stop pixels (inclusive)
+=
+======================
+*/
+
+void R_StoreWallRange (int start, int stop)
+{
+	fixed_t		hyp;
+	fixed_t		sineval;
+	angle_t		distangle, offsetangle;
+	fixed_t		vtop;
+	int		lightnum;
+
+	if (ds_p == &drawsegs[MAXDRAWSEGS])
+		return;		// don't overflow and crash
+
+#ifdef RANGECHECK
+	if (start >=viewwidth || start > stop)
+		I_Error ("Bad R_RenderWallRange: %i to %i", start , stop);
+#endif
+
+	sidedef = curline->sidedef;
+	linedef = curline->linedef;
+
+// mark the segment as visible for auto map
+	linedef->flags |= ML_MAPPED;
+
+//
+// calculate rw_distance for scale calculation
+//
+	rw_normalangle = curline->angle + ANG90;
+	offsetangle = abs(rw_normalangle - rw_angle1);
+	if (offsetangle > ANG90)
+		offsetangle = ANG90;
+	distangle = ANG90 - offsetangle;
+	hyp = R_PointToDist (curline->v1->x, curline->v1->y);
+	sineval = finesine[distangle>>ANGLETOFINESHIFT];
+	rw_distance = FixedMul (hyp, sineval);
+
+	ds_p->x1 = rw_x = start;
+	ds_p->x2 = stop;
+	ds_p->curline = curline;
+	rw_stopx = stop + 1;
+
+//
+// calculate scale at both ends and step
+//
+	ds_p->scale1 = rw_scale =
+		R_ScaleFromGlobalAngle (viewangle + xtoviewangle[start]);
+	if (stop > start)
+	{
+		ds_p->scale2 = R_ScaleFromGlobalAngle (viewangle + xtoviewangle[stop]);
+		ds_p->scalestep = rw_scalestep =
+			(ds_p->scale2 - rw_scale) / (stop-start);
+	}
+	else
+	{
+	//
+	// try to fix the stretched line bug
+	//
+#if 0
+		if (rw_distance < FRACUNIT/2)
+		{
+			fixed_t		xtr, ytr;
+			fixed_t		gxt, gyt;
+
+			xtr = curline->v1->x - viewx;
+			ytr = curline->v1->y - viewy;
+
+			gxt = FixedMul(xtr, viewcos);
+			gyt = -FixedMul(ytr, viewsin);
+			ds_p->scale1 = FixedDiv(projection, gxt - gyt);
+		}
+#endif
+		ds_p->scale2 = ds_p->scale1;
+	}
+
+//
+// calculate texture boundaries and decide if floor / ceiling marks
+// are needed
+//
+	worldtop = frontsector->ceilingheight - viewz;
+	worldbottom = frontsector->floorheight - viewz;
+
+	midtexture = toptexture = bottomtexture = maskedtexture = 0;
+	ds_p->maskedtexturecol = NULL;
+
+	if (!backsector)
+	{
+//
+// single sided line
+//
+		midtexture = texturetranslation[sidedef->midtexture];
+		// a single sided line is terminal, so it must mark ends
+		markfloor = markceiling = true;
+		if (linedef->flags & ML_DONTPEGBOTTOM)
+		{
+			vtop = frontsector->floorheight + textureheight[sidedef->midtexture];
+			rw_midtexturemid = vtop - viewz;	// bottom of texture at bottom
+		}
+		else
+			rw_midtexturemid = worldtop;		// top of texture at top
+		rw_midtexturemid += sidedef->rowoffset;
+		ds_p->silhouette = SIL_BOTH;
+		ds_p->sprtopclip = screenheightarray;
+		ds_p->sprbottomclip = negonearray;
+		ds_p->bsilheight = H2MAXINT;
+		ds_p->tsilheight = H2MININT;
+	}
+	else
+	{
+//
+// two sided line
+//
+		ds_p->sprtopclip = ds_p->sprbottomclip = NULL;
+		ds_p->silhouette = 0;
+		if (frontsector->floorheight > backsector->floorheight)
+		{
+			ds_p->silhouette = SIL_BOTTOM;
+			ds_p->bsilheight = frontsector->floorheight;
+		}
+		else if (backsector->floorheight > viewz)
+		{
+			ds_p->silhouette = SIL_BOTTOM;
+			ds_p->bsilheight = H2MAXINT;
+//			ds_p->sprbottomclip = negonearray;
+		}
+		if (frontsector->ceilingheight < backsector->ceilingheight)
+		{
+			ds_p->silhouette |= SIL_TOP;
+			ds_p->tsilheight = frontsector->ceilingheight;
+		}
+		else if (backsector->ceilingheight < viewz)
+		{
+			ds_p->silhouette |= SIL_TOP;
+			ds_p->tsilheight = H2MININT;
+//			ds_p->sprtopclip = screenheightarray;
+		}
+
+		if (backsector->ceilingheight <= frontsector->floorheight)
+		{
+			ds_p->sprbottomclip = negonearray;
+			ds_p->bsilheight = H2MAXINT;
+			ds_p->silhouette |= SIL_BOTTOM;
+		}
+		if (backsector->floorheight >= frontsector->ceilingheight)
+		{
+			ds_p->sprtopclip = screenheightarray;
+			ds_p->tsilheight = H2MININT;
+			ds_p->silhouette |= SIL_TOP;
+		}
+		worldhigh = backsector->ceilingheight - viewz;
+		worldlow = backsector->floorheight - viewz;
+
+		// hack to allow height changes in outdoor areas
+		if (frontsector->ceilingpic == skyflatnum &&
+		    backsector->ceilingpic == skyflatnum)
+			worldtop = worldhigh;
+
+		if (worldlow != worldbottom ||
+		    backsector->floorpic != frontsector->floorpic ||
+		    backsector->lightlevel != frontsector->lightlevel ||
+		    backsector->special != frontsector->special)
+			markfloor = true;
+		else
+			markfloor = false;			// same plane on both sides
+
+		if (worldhigh != worldtop ||
+		    backsector->ceilingpic != frontsector->ceilingpic ||
+		    backsector->lightlevel != frontsector->lightlevel)
+			markceiling = true;
+		else
+			markceiling = false;			// same plane on both sides
+
+		if (backsector->ceilingheight <= frontsector->floorheight ||
+		    backsector->floorheight >= frontsector->ceilingheight)
+			markceiling = markfloor = true;		// closed door
+
+		if (worldhigh < worldtop)
+		{	// top texture
+			toptexture = texturetranslation[sidedef->toptexture];
+			if (linedef->flags & ML_DONTPEGTOP)
+				rw_toptexturemid = worldtop;		// top of texture at top
+			else
+			{
+				vtop = backsector->ceilingheight +
+					textureheight[sidedef->toptexture];
+				rw_toptexturemid = vtop - viewz;	// bottom of texture
+			}
+		}
+		if (worldlow > worldbottom)
+		{	// bottom texture
+			bottomtexture = texturetranslation[sidedef->bottomtexture];
+			if (linedef->flags & ML_DONTPEGBOTTOM)
+			{	// bottom of texture at bottom
+				rw_bottomtexturemid = worldtop;		// top of texture at top
+			}
+			else	// top of texture at top
+				rw_bottomtexturemid = worldlow;
+		}
+		rw_toptexturemid += sidedef->rowoffset;
+		rw_bottomtexturemid += sidedef->rowoffset;
+
+		//
+		// allocate space for masked texture tables
+		//
+		if (sidedef->midtexture)
+		{	// masked midtexture
+			maskedtexture = true;
+			ds_p->maskedtexturecol = maskedtexturecol = lastopening - rw_x;
+			lastopening += rw_stopx - rw_x;
+		}
+	}
+
+//
+// calculate rw_offset (only needed for textured lines)
+//
+	segtextured = midtexture | toptexture | bottomtexture | maskedtexture;
+
+	if (segtextured)
+	{
+		offsetangle = rw_normalangle - rw_angle1;
+		if (offsetangle > ANG180)
+			offsetangle = -offsetangle;
+		if (offsetangle > ANG90)
+			offsetangle = ANG90;
+		sineval = finesine[offsetangle >>ANGLETOFINESHIFT];
+		rw_offset = FixedMul (hyp, sineval);
+		if (rw_normalangle - rw_angle1 < ANG180)
+			rw_offset = -rw_offset;
+		rw_offset += sidedef->textureoffset + curline->offset;
+		rw_centerangle = ANG90 + viewangle - rw_normalangle;
+
+	//
+	// calculate light table
+	// use different light tables for horizontal / vertical / diagonal
+	// OPTIMIZE: get rid of LIGHTSEGSHIFT globally
+		if (!fixedcolormap)
+		{
+			lightnum = (frontsector->lightlevel >> LIGHTSEGSHIFT) + extralight;
+			//if (curline->v1->y == curline->v2->y)
+			//	lightnum--;
+			//else if (curline->v1->x == curline->v2->x)
+			//	lightnum++;
+			//if (lightnum < 0)
+			//	walllights = scalelight[0];
+			if (lightnum >= LIGHTLEVELS)
+				walllights = scalelight[LIGHTLEVELS-1];
+			else
+				walllights = scalelight[lightnum];
+		}
+	}
+
+//
+// if a floor / ceiling plane is on the wrong side of the view plane
+// it is definately invisible and doesn't need to be marked
+//
+	if (frontsector->floorheight >= viewz)
+		markfloor = false;			// above view plane
+	if (frontsector->ceilingheight <= viewz &&
+	    frontsector->ceilingpic != skyflatnum)
+		markceiling = false;			// below view plane
+
+//
+// calculate incremental stepping values for texture edges
+//
+	worldtop >>= 4;
+	worldbottom >>= 4;
+
+	topstep = -FixedMul (rw_scalestep, worldtop);
+	topfrac = (centeryfrac>>4) - FixedMul (worldtop, rw_scale);
+
+	bottomstep = -FixedMul (rw_scalestep, worldbottom);
+	bottomfrac = (centeryfrac>>4) - FixedMul (worldbottom, rw_scale);
+
+	if (backsector)
+	{
+		worldhigh >>= 4;
+		worldlow >>= 4;
+
+		if (worldhigh < worldtop)
+		{
+			pixhigh = (centeryfrac>>4) - FixedMul (worldhigh, rw_scale);
+			pixhighstep = -FixedMul (rw_scalestep,worldhigh);
+		}
+		if (worldlow > worldbottom)
+		{
+			pixlow = (centeryfrac>>4) - FixedMul (worldlow, rw_scale);
+			pixlowstep = -FixedMul (rw_scalestep, worldlow);
+		}
+	}
+
+//
+// render it
+//
+	if (markceiling)
+		ceilingplane = R_CheckPlane (ceilingplane, rw_x, rw_stopx - 1);
+	if (markfloor)
+		floorplane = R_CheckPlane (floorplane, rw_x, rw_stopx - 1);
+
+	R_RenderSegLoop ();
+
+//
+// save sprite clipping info
+//
+	if ( ((ds_p->silhouette & SIL_TOP) || maskedtexture) && !ds_p->sprtopclip)
+	{
+		memcpy (lastopening, ceilingclip + start, 2*(rw_stopx - start));
+		ds_p->sprtopclip = lastopening - start;
+		lastopening += rw_stopx - start;
+	}
+	if ( ((ds_p->silhouette & SIL_BOTTOM) || maskedtexture) && !ds_p->sprbottomclip)
+	{
+		memcpy (lastopening, floorclip + start, 2*(rw_stopx - start));
+		ds_p->sprbottomclip = lastopening - start;
+		lastopening += rw_stopx - start;
+	}
+	if (maskedtexture && !(ds_p->silhouette & SIL_TOP))
+	{
+		ds_p->silhouette |= SIL_TOP;
+		ds_p->tsilheight = H2MININT;
+	}
+	if (maskedtexture && !(ds_p->silhouette & SIL_BOTTOM))
+	{
+		ds_p->silhouette |= SIL_BOTTOM;
+		ds_p->bsilheight = H2MAXINT;
+	}
+	ds_p++;
+}
+#endif	/* !RENDER3D */
+
--- /dev/null
+++ b/r_things.c
@@ -1,0 +1,1196 @@
+
+//**************************************************************************
+//**
+//** r_things.c : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 575 $
+//** $Date: 2011-04-13 22:06:28 +0300 (Wed, 13 Apr 2011) $
+//**
+//**************************************************************************
+
+#include "h2stdinc.h"
+#include "h2def.h"
+#include "r_local.h"
+#ifdef RENDER3D
+#include "ogl_def.h"
+#endif
+
+void R_DrawColumn (void);
+void R_DrawFuzzColumn (void);
+void R_DrawAltFuzzColumn(void);
+//void R_DrawTranslatedAltFuzzColumn(void);
+
+typedef struct
+{
+	int		x1, x2;
+
+	int		column;
+	int		topclip;
+	int		bottomclip;
+} maskdraw_t;
+
+/*
+
+Sprite rotation 0 is facing the viewer, rotation 1 is one angle turn CLOCKWISE around the axis.
+This is not the same as the angle, which increases counter clockwise
+(protractor).  There was a lot of stuff grabbed wrong, so I changed it...
+
+*/
+
+fixed_t			pspritescale, pspriteiscale;
+
+// constant arrays used for psprite clipping and initializing clipping
+#ifndef RENDER3D
+short			negonearray[SCREENWIDTH];
+short			screenheightarray[SCREENWIDTH];
+#endif
+
+boolean			LevelUseFullBright;
+
+// variables used to look up and range check thing_t sprites patches
+spritedef_t		*sprites;
+int			numsprites;
+
+#ifndef RENDER3D
+static lighttable_t	**spritelights;
+#endif
+
+static spriteframe_t	sprtemp[30];
+static int		maxframe;
+static const char	*spritename;
+
+
+/*
+===============================================================================
+
+						INITIALIZATION FUNCTIONS
+
+===============================================================================
+*/
+
+/*
+=================
+=
+= R_InstallSpriteLump
+=
+= Local function for R_InitSprites
+=================
+*/
+
+void R_InstallSpriteLump (int lump, unsigned frame, unsigned rotation, boolean flipped)
+{
+	int		r;
+
+	if (frame >= 30 || rotation > 8)
+		I_Error ("R_InstallSpriteLump: Bad frame characters in lump %i", lump);
+
+	if ((int)frame > maxframe)
+		maxframe = frame;
+
+	if (rotation == 0)
+	{
+	// the lump should be used for all rotations
+		if (sprtemp[frame].rotate == false)
+		{
+			I_Error ("R_InitSprites: Sprite %s frame %c has multip rot=0 lump",
+				 spritename, 'A'+frame);
+		}
+		if (sprtemp[frame].rotate == true)
+		{
+			I_Error ("R_InitSprites: Sprite %s frame %c has rotations and a rot=0 lump",
+				 spritename, 'A'+frame);
+		}
+
+		sprtemp[frame].rotate = false;
+		for (r = 0; r < 8; r++)
+		{
+			sprtemp[frame].lump[r] = lump - firstspritelump;
+			sprtemp[frame].flip[r] = (byte)flipped;
+		}
+		return;
+	}
+
+	// the lump is only used for one rotation
+	if (sprtemp[frame].rotate == false)
+	{
+		I_Error ("R_InitSprites: Sprite %s frame %c has rotations and a rot=0 lump",
+			 spritename, 'A'+frame);
+	}
+
+	sprtemp[frame].rotate = true;
+
+	rotation--;		// make 0 based
+	if (sprtemp[frame].lump[rotation] != -1)
+	{
+		I_Error ("R_InitSprites: Sprite %s : %c : %c has two lumps mapped to it",
+			 spritename, 'A'+frame, '1' + rotation);
+	}
+
+	sprtemp[frame].lump[rotation] = lump - firstspritelump;
+	sprtemp[frame].flip[rotation] = (byte)flipped;
+}
+
+/*
+=================
+=
+= R_InitSpriteDefs
+=
+= Pass a null terminated list of sprite names (4 chars exactly) to be used
+= Builds the sprite rotation matrixes to account for horizontally flipped
+= sprites.  Will report an error if the lumps are inconsistant
+=
+Only called at startup
+=
+= Sprite lump names are 4 characters for the actor, a letter for the frame,
+= and a number for the rotation, A sprite that is flippable will have an
+= additional letter/number appended.  The rotation character can be 0 to
+= signify no rotations
+=================
+*/
+
+void R_InitSpriteDefs (const char **namelist)
+{
+	const char	**check;
+	int		i, l, frame, rotation;
+	int		start, end;
+
+// count the number of sprite names
+	check = namelist;
+	while (*check != NULL)
+		check++;
+	numsprites = check - namelist;
+
+	if (!numsprites)
+		return;
+
+	sprites = (spritedef_t *) Z_Malloc(numsprites *sizeof(*sprites), PU_STATIC, NULL);
+
+	start = firstspritelump - 1;
+	end = lastspritelump + 1;
+
+// scan all the lump names for each of the names, noting the highest
+// frame letter
+// Just compare 4 characters as ints
+	for (i = 0; i < numsprites; i++)
+	{
+		spritename = namelist[i];
+		memset (sprtemp, -1, sizeof(sprtemp));
+
+		maxframe = -1;
+
+		//
+		// scan the lumps, filling in the frames for whatever is found
+		//
+		for (l = start + 1; l < end; l++)
+		{
+			if (memcmp(lumpinfo[l].name, namelist[i], 4) == 0)
+			{
+				frame = lumpinfo[l].name[4] - 'A';
+				rotation = lumpinfo[l].name[5] - '0';
+				R_InstallSpriteLump (l, frame, rotation, false);
+				if (lumpinfo[l].name[6])
+				{
+					frame = lumpinfo[l].name[6] - 'A';
+					rotation = lumpinfo[l].name[7] - '0';
+					R_InstallSpriteLump (l, frame, rotation, true);
+				}
+			}
+		}
+
+		//
+		// check the frames that were found for completeness
+		//
+		if (maxframe == -1)
+		{
+			//continue;
+			sprites[i].numframes = 0;
+			if (shareware)
+				continue;
+			I_Error ("R_InitSprites: No lumps found for sprite %s", namelist[i]);
+		}
+
+		maxframe++;
+		for (frame = 0; frame < maxframe; frame++)
+		{
+			switch ((int)sprtemp[frame].rotate)
+			{
+			case -1:	// no rotations were found for that frame at all
+				I_Error ("R_InitSprites: No patches found for %s frame %c",
+					 namelist[i], frame+'A');
+			case 0:	// only the first rotation is needed
+				break;
+
+			case 1:	// must have all 8 frames
+				for (rotation = 0; rotation < 8; rotation++)
+				{
+					if (sprtemp[frame].lump[rotation] == -1)
+					{
+						I_Error ("R_InitSprites: Sprite %s frame %c is missing rotations",
+							 namelist[i], frame+'A');
+					}
+				}
+			}
+		}
+
+		//
+		// allocate space for the frames present and copy sprtemp to it
+		//
+		sprites[i].numframes = maxframe;
+		sprites[i].spriteframes =
+			(spriteframe_t *) Z_Malloc (maxframe * sizeof(spriteframe_t), PU_STATIC, NULL);
+		memcpy (sprites[i].spriteframes, sprtemp, maxframe*sizeof(spriteframe_t));
+	}
+}
+
+
+/*
+===============================================================================
+
+							GAME FUNCTIONS
+
+===============================================================================
+*/
+
+vissprite_t	vissprites[MAXVISSPRITES], *vissprite_p;
+
+/*
+===================
+=
+= R_InitSprites
+=
+= Called at program start
+===================
+*/
+
+void R_InitSprites (const char **namelist)
+{
+#ifndef RENDER3D
+	int		i;
+
+	for (i = 0; i < SCREENWIDTH; i++)
+	{
+		negonearray[i] = -1;
+	}
+#endif
+	R_InitSpriteDefs (namelist);
+}
+
+
+/*
+===================
+=
+= R_ClearSprites
+=
+= Called at frame start
+===================
+*/
+
+void R_ClearSprites (void)
+{
+	vissprite_p = vissprites;
+}
+
+
+/*
+===================
+=
+= R_NewVisSprite
+=
+===================
+*/
+
+static vissprite_t	overflowsprite;
+
+static vissprite_t *R_NewVisSprite (void)
+{
+	if (vissprite_p == &vissprites[MAXVISSPRITES])
+		return &overflowsprite;
+	vissprite_p++;
+	return vissprite_p - 1;
+}
+
+
+#ifndef RENDER3D
+/*
+================
+=
+= R_DrawMaskedColumn
+=
+= Used for sprites and masked mid textures
+================
+*/
+
+short		*mfloorclip;
+short		*mceilingclip;
+fixed_t		spryscale;
+fixed_t		sprtopscreen;
+fixed_t		sprbotscreen;
+
+void R_DrawMaskedColumn (column_t *column, signed int baseclip)
+{
+	int		topscreen, bottomscreen;
+	fixed_t	basetexturemid;
+
+	basetexturemid = dc_texturemid;
+
+	for ( ; column->topdelta != 0xff ; )
+	{
+	// calculate unclipped screen coordinates for post
+		topscreen = sprtopscreen + spryscale*column->topdelta;
+		bottomscreen = topscreen + spryscale*column->length;
+		dc_yl = (topscreen + FRACUNIT - 1)>>FRACBITS;
+		dc_yh = (bottomscreen - 1)>>FRACBITS;
+
+		if (dc_yh >= mfloorclip[dc_x])
+			dc_yh = mfloorclip[dc_x] - 1;
+		if (dc_yl <= mceilingclip[dc_x])
+			dc_yl = mceilingclip[dc_x] + 1;
+
+		if (dc_yh >= baseclip && baseclip != -1)
+			dc_yh = baseclip;
+
+		if (dc_yl <= dc_yh)
+		{
+			dc_source = (byte *)column + 3;
+			dc_texturemid = basetexturemid - (column->topdelta<<FRACBITS);
+		//	dc_source = (byte *)column + 3 - column->topdelta;
+			colfunc ();		// either R_DrawColumn or R_DrawFuzzColumn
+		}
+		column = (column_t *)(  (byte *)column + column->length + 4);
+	}
+
+	dc_texturemid = basetexturemid;
+}
+
+
+/*
+================
+=
+= R_DrawVisSprite
+=
+= mfloorclip and mceilingclip should also be set
+================
+*/
+
+void R_DrawVisSprite (vissprite_t *vis, int x1, int x2)
+{
+	column_t	*column;
+	int		texturecolumn;
+	fixed_t		frac;
+	patch_t		*patch;
+	fixed_t		baseclip;
+
+	patch = (patch_t *) W_CacheLumpNum(vis->patch + firstspritelump, PU_CACHE);
+
+	dc_colormap = vis->colormap;
+
+//	if (!dc_colormap)
+//		colfunc = fuzzcolfunc;	// NULL colormap = shadow draw
+
+	if (vis->mobjflags & (MF_SHADOW|MF_ALTSHADOW))
+	{
+		if (vis->mobjflags & MF_TRANSLATION)
+		{
+			colfunc = R_DrawTranslatedFuzzColumn;
+			dc_translation = translationtables - 256 + vis->playerclass * ((MAXPLAYERS - 1) * 256) +
+					 ((vis->mobjflags & MF_TRANSLATION)>>(MF_TRANSSHIFT - 8));
+		}
+		else if (vis->mobjflags & MF_SHADOW)
+		{ // Draw using shadow column function
+			colfunc = fuzzcolfunc;
+		}
+		else
+		{
+			colfunc = R_DrawAltFuzzColumn;
+		}
+	}
+	else if (vis->mobjflags & MF_TRANSLATION)
+	{
+		// Draw using translated column function
+		colfunc = R_DrawTranslatedColumn;
+		dc_translation = translationtables - 256 + vis->playerclass * ((MAXPLAYERS - 1) * 256) +
+				 ((vis->mobjflags & MF_TRANSLATION)>>(MF_TRANSSHIFT - 8));
+	}
+
+	dc_iscale = abs(vis->xiscale) >> detailshift;
+	dc_texturemid = vis->texturemid;
+	frac = vis->startfrac;
+	spryscale = vis->scale;
+
+	sprtopscreen = centeryfrac - FixedMul(dc_texturemid, spryscale);
+
+	// check to see if vissprite is a weapon
+	if (vis->psprite)
+	{
+		dc_texturemid += FixedMul(((centery-viewheight/2)<<FRACBITS), vis->xiscale);
+		sprtopscreen += (viewheight/2 - centery)<<FRACBITS;
+	}
+
+	if (vis->floorclip && !vis->psprite)
+	{
+		sprbotscreen = sprtopscreen + FixedMul(SHORT(patch->height)<<FRACBITS, spryscale);
+		baseclip = (sprbotscreen - FixedMul(vis->floorclip, spryscale))>>FRACBITS;
+	}
+	else
+	{
+		baseclip = -1;
+	}
+
+	for (dc_x = vis->x1; dc_x <= vis->x2; dc_x++, frac += vis->xiscale)
+	{
+		texturecolumn = frac>>FRACBITS;
+#ifdef RANGECHECK
+		if (texturecolumn < 0 || texturecolumn >= SHORT(patch->width))
+			I_Error ("R_DrawSpriteRange: bad texturecolumn");
+#endif
+		column = (column_t *) ((byte *)patch + LONG(patch->columnofs[texturecolumn]));
+		R_DrawMaskedColumn (column, baseclip);
+	}
+
+	colfunc = basecolfunc;
+}
+#endif	/* RENDER3D */
+
+
+/*
+===================
+=
+= R_ProjectSprite
+=
+= Generates a vissprite for a thing if it might be visible
+=
+===================
+*/
+
+void R_ProjectSprite (mobj_t *thing)
+{
+	fixed_t		xtr, ytr;
+	fixed_t		gxt, gyt;
+	fixed_t		tz;
+	fixed_t		xscale;
+	int		x1 = 0, x2 = 0;
+	spritedef_t	*sprdef;
+	spriteframe_t	*sprframe;
+	int		lump;
+	unsigned int	rot;
+	boolean		flip;
+#ifndef RENDER3D
+	fixed_t		tx;
+	int		idx;
+#endif
+	vissprite_t	*vis;
+	angle_t		ang;
+	fixed_t		iscale;
+#ifdef RENDER3D
+	float		v1[2], v2[2];
+	float		sinrv, cosrv, thangle;	// rv = real value
+#endif
+
+	if (thing->flags2 & MF2_DONTDRAW)
+	{ // Never make a vissprite when MF2_DONTDRAW is flagged.
+		return;
+	}
+
+//
+// transform the origin point
+//
+	xtr = thing->x - viewx;
+	ytr = thing->y - viewy;
+
+	gxt = FixedMul(xtr,viewcos);
+	gyt = -FixedMul(ytr,viewsin);
+	tz = gxt - gyt;
+
+#ifdef RENDER3D
+	if (tz < 0)
+		tz = -tz;	// Make it positive. The clipper will handle backside.
+	if (tz < FRACUNIT)
+		tz = FRACUNIT;
+#else
+	if (tz < MINZ)
+		return;		// thing is behind view plane
+#endif
+	xscale = FixedDiv(projection, tz);
+
+#ifndef RENDER3D
+	gxt = -FixedMul(xtr,viewsin);
+	gyt = FixedMul(ytr,viewcos);
+	tx = -(gyt + gxt);
+
+	if (abs(tx) > (tz<<2))
+		return;		// too far off the side
+#endif
+
+//
+// decide which patch to use for sprite reletive to player
+//
+#ifdef RANGECHECK
+	if ((unsigned int)thing->sprite >= numsprites)
+		I_Error ("R_ProjectSprite: invalid sprite number %i ", thing->sprite);
+#endif
+	sprdef = &sprites[thing->sprite];
+#ifdef RANGECHECK
+	if ((thing->frame&FF_FRAMEMASK) >= sprdef->numframes)
+		I_Error ("R_ProjectSprite: invalid sprite frame %i : %i ", thing->sprite, thing->frame);
+#endif
+	sprframe = &sprdef->spriteframes[thing->frame & FF_FRAMEMASK];
+
+	if (sprframe->rotate)
+	{	// choose a different rotation based on player view
+		ang = R_PointToAngle (thing->x, thing->y);
+		rot = (ang - thing->angle + (unsigned int)(ANG45/2)*9) >> 29;
+		lump = sprframe->lump[rot];
+		flip = !!(sprframe->flip[rot]);
+	}
+	else
+	{	// use single rotation for all views
+		lump = sprframe->lump[0];
+		flip = !!(sprframe->flip[0]);
+	}
+
+//
+// calculate edges of the shape
+//
+#ifdef RENDER3D
+	v1[VX] = FIX2FLT(thing->x);
+	v1[VY] = FIX2FLT(thing->y);
+//	thangle = BANG2RAD(bamsAtan2((v1[VY]-FIX2FLT(viewy))*10, (v1[VX]-FIX2FLT(viewx))*10)) - PI/2;
+	thangle = BANG2RAD(bamsAtan2(FIX2FLT(ytr)*10, FIX2FLT(xtr)*10)) - PI/2;
+	sinrv = sin(thangle);
+	cosrv = cos(thangle);
+	v1[VX] -= cosrv*(spriteoffset[lump]>>FRACBITS);
+	v1[VY] -= sinrv*(spriteoffset[lump]>>FRACBITS);
+	v2[VX] = v1[VX] + cosrv*(spritewidth[lump]>>FRACBITS);
+	v2[VY] = v1[VY] + sinrv*(spritewidth[lump]>>FRACBITS);
+ 	// Check for visibility.
+	if (!C_CheckViewRelSeg(v1[VX], v1[VY], v2[VX], v2[VY]))
+	//if (!C_IsAngleVisible(RAD2BANG(thangle+PI/2)))
+		return;		// Isn't visible.
+#else
+	tx -= spriteoffset[lump];
+	x1 = (centerxfrac + FixedMul (tx,xscale) ) >>FRACBITS;
+	if (x1 > viewwidth)
+		return;		// off the right side
+	tx +=  spritewidth[lump];
+	x2 = ((centerxfrac + FixedMul (tx,xscale) ) >>FRACBITS) - 1;
+	if (x2 < 0)
+		return;		// off the left side
+#endif
+
+//
+// store information in a vissprite
+//
+	vis = R_NewVisSprite ();
+	vis->mobjflags = thing->flags;
+	vis->psprite = false;
+	vis->scale = xscale<<detailshift;
+	vis->gx = thing->x;
+	vis->gy = thing->y;
+	vis->gz = thing->z;
+	vis->gzt = thing->z + spritetopoffset[lump];
+
+#ifdef RENDER3D
+	vis->secfloor = FIX2FLT(thing->subsector->sector->floorheight);
+	vis->secceil  = FIX2FLT(thing->subsector->sector->ceilingheight);
+#endif
+
+	if (thing->flags & MF_TRANSLATION)
+	{
+		if (thing->player)
+		{
+			vis->playerclass = thing->player->playerclass;
+		}
+		else
+		{
+			vis->playerclass = thing->special1;
+		}
+		if (vis->playerclass > 2)
+		{
+		// O.S. --  FIXME: HARDCODED NUMBER: 2 == PCLASS_MAGE
+			vis->playerclass = 0;
+		}
+	}
+	// foot clipping
+	vis->floorclip = thing->floorclip;
+	vis->texturemid = vis->gzt - viewz - vis->floorclip;
+
+#ifdef RENDER3D
+	// The start and end vertices.
+	vis->v1[VX] = v1[VX];
+	vis->v1[VY] = v1[VY];
+	vis->v2[VX] = v2[VX];
+	vis->v2[VY] = v2[VY];
+#endif
+
+	vis->x1 = x1 < 0 ? 0 : x1;
+	vis->x2 = x2 >= viewwidth ? viewwidth-1 : x2;
+	iscale = FixedDiv (FRACUNIT, xscale);
+	if (flip)
+	{
+		vis->startfrac = spritewidth[lump]-1;
+		vis->xiscale = -iscale;
+	}
+	else
+	{
+		vis->startfrac = 0;
+		vis->xiscale = iscale;
+	}
+	if (vis->x1 > x1)
+		vis->startfrac += vis->xiscale*(vis->x1 - x1);
+	vis->patch = lump;
+//
+// get light level
+//
+
+//	if (thing->flags & MF_SHADOW)
+//		vis->colormap = NULL;			// shadow draw
+//	else ...
+
+#ifdef RENDER3D
+	if (thing->frame & FF_FULLBRIGHT)
+	{	// full bright
+		vis->lightlevel = -1;
+	}
+	else
+	{	// diminished light
+		vis->lightlevel = thing->subsector->sector->lightlevel;
+	}
+#else
+	if (fixedcolormap)
+		vis->colormap = fixedcolormap;	// fixed map
+	else if (LevelUseFullBright && thing->frame & FF_FULLBRIGHT)
+		vis->colormap = colormaps;	// full bright
+	else
+	{	// diminished light
+		idx = xscale>>(LIGHTSCALESHIFT - detailshift);
+		if (idx >= MAXLIGHTSCALE)
+			idx = MAXLIGHTSCALE-1;
+		vis->colormap = spritelights[idx];
+	}
+#endif
+}
+
+
+/*
+========================
+=
+= R_AddSprites
+=
+========================
+*/
+
+void R_AddSprites (sector_t *sec)
+{
+	if (sec->validcount == validcount)
+	{
+		return;		// already added
+	}
+	else
+	{
+		mobj_t		*thing;
+#ifndef RENDER3D
+		int		lightnum;
+
+		lightnum = (sec->lightlevel >> LIGHTSEGSHIFT) + extralight;
+		if (lightnum < 0)
+			spritelights = scalelight[0];
+		else if (lightnum >= LIGHTLEVELS)
+			spritelights = scalelight[LIGHTLEVELS-1];
+		else
+			spritelights = scalelight[lightnum];
+#endif
+
+		sec->validcount = validcount;
+
+		for (thing = sec->thinglist ; thing ; thing = thing->snext)
+			R_ProjectSprite (thing);
+	}
+}
+
+
+/*
+========================
+=
+= R_DrawPSprite
+=
+========================
+*/
+
+/* Y-adjustment values for full screen (4 weapons) */
+static int PSpriteSY[NUMCLASSES][NUMWEAPONS] =
+{
+	{		0, -12 * FRACUNIT, -10 * FRACUNIT, 10 * FRACUNIT },	/* Fighter	*/
+	{   -8 * FRACUNIT,  10 * FRACUNIT,  10 * FRACUNIT,  0		 },	/* Cleric	*/
+	{    9 * FRACUNIT,  20 * FRACUNIT,  20 * FRACUNIT, 20 * FRACUNIT },	/* Mage		*/
+	{   10 * FRACUNIT,  10 * FRACUNIT,  10 * FRACUNIT, 10 * FRACUNIT }	/* Pig		*/
+};
+
+void R_DrawPSprite (pspdef_t *psp)
+{
+	fixed_t		tx;
+	int		x1;
+#ifndef RENDER3D
+	int		x2;
+#endif
+	spritedef_t	*sprdef;
+	spriteframe_t	*sprframe;
+	int		lump;
+	boolean		flip;
+#ifdef RENDER3D
+	float		light, alpha;
+	int		y;
+#else
+	vissprite_t	*vis, avis;
+#endif
+	int		tempangle;
+
+//
+// decide which patch to use
+//
+#ifdef RANGECHECK
+	if ( (unsigned int)psp->state->sprite >= numsprites)
+		I_Error ("R_ProjectSprite: invalid sprite number %i ", psp->state->sprite);
+#endif
+	sprdef = &sprites[psp->state->sprite];
+#ifdef RANGECHECK
+	if ( (psp->state->frame & FF_FRAMEMASK)  >= sprdef->numframes)
+		I_Error ("R_ProjectSprite: invalid sprite frame %i : %i ", psp->state->sprite, psp->state->frame);
+#endif
+	sprframe = &sprdef->spriteframes[psp->state->frame & FF_FRAMEMASK];
+
+	lump = sprframe->lump[0];
+	flip = !!(sprframe->flip[0]);
+
+//
+// calculate edges of the shape
+//
+	tx = psp->sx - 160*FRACUNIT;
+
+	tx -= spriteoffset[lump];
+	if (viewangleoffset)
+	{
+		tempangle = ((centerxfrac/1024)*(viewangleoffset>>ANGLETOFINESHIFT));
+	}
+	else
+	{
+		tempangle = 0;
+	}
+	x1 = (centerxfrac + FixedMul (tx,pspritescale)+tempangle ) >>FRACBITS;
+
+#ifdef RENDER3D
+	// Set the OpenGL color & alpha.
+	light = 1;
+	alpha = 1;
+	if (viewplayer->powers[pw_invulnerability] &&
+		viewplayer->playerclass == PCLASS_CLERIC)
+	{
+		if (viewplayer->powers[pw_invulnerability] > 4*32)
+		{
+			if (viewplayer->mo->flags2 & MF2_DONTDRAW)
+			{ // don't draw the psprite
+				alpha = .333f;
+			}
+			else if (viewplayer->mo->flags & MF_SHADOW)
+			{
+				alpha = .666f;
+			}
+		}
+		else if (viewplayer->powers[pw_invulnerability] & 8)
+		{
+			alpha = .333f;
+		}
+	}
+	else if (fixedcolormap)
+	{
+		// Fixed color
+		light = 1;
+	}
+	else if (psp->state->frame & FF_FULLBRIGHT)
+	{
+		// Full bright
+		light = 1;
+	}
+	else
+	{
+		// local light
+		light = viewplayer->mo->subsector->sector->lightlevel / 255.0;
+	}
+
+//
+// do some OpenGL rendering, oh yeah
+//
+	y = -(spritetopoffset[lump]>>FRACBITS) + (psp->sy>>FRACBITS);
+	if (viewheight == SCREENHEIGHT)
+	{
+		y += PSpriteSY[viewplayer->playerclass][players[consoleplayer].readyweapon] >> FRACBITS;
+	}
+	else
+		y -= 39/2;
+ 
+	light += .1f;	// Add some extra light.
+	OGL_SetColorAndAlpha(light, light, light, alpha);
+	OGL_DrawPSprite(x1, y, 1, flip, lump);
+
+#else
+
+	if (x1 > viewwidth)
+		return;		// off the right side
+	tx +=  spritewidth[lump];
+	x2 = ((centerxfrac + FixedMul(tx, pspritescale) + tempangle) >>FRACBITS) - 1;
+	if (x2 < 0)
+		return;		// off the left side
+
+//
+// store information in a vissprite
+//
+	vis = &avis;
+	vis->mobjflags = 0;
+	vis->playerclass = 0;
+	vis->psprite = true;
+	vis->texturemid = (BASEYCENTER<<FRACBITS)+FRACUNIT/2 - (psp->sy-spritetopoffset[lump]);
+	if (viewheight == SCREENHEIGHT)
+	{
+		vis->texturemid -= PSpriteSY[viewplayer->playerclass][players[consoleplayer].readyweapon];
+	}
+	vis->x1 = x1 < 0 ? 0 : x1;
+	vis->x2 = x2 >= viewwidth ? viewwidth-1 : x2;
+	vis->scale = pspritescale<<detailshift;
+	if (flip)
+	{
+		vis->xiscale = -pspriteiscale;
+		vis->startfrac = spritewidth[lump]-1;
+	}
+	else
+	{
+		vis->xiscale = pspriteiscale;
+		vis->startfrac = 0;
+	}
+	if (vis->x1 > x1)
+		vis->startfrac += vis->xiscale*(vis->x1 - x1);
+	vis->patch = lump;
+
+	if (viewplayer->powers[pw_invulnerability] &&
+		viewplayer->playerclass == PCLASS_CLERIC)
+	{
+		vis->colormap = spritelights[MAXLIGHTSCALE-1];
+		if (viewplayer->powers[pw_invulnerability] > 4*32)
+		{
+			if (viewplayer->mo->flags2 & MF2_DONTDRAW)
+			{ // don't draw the psprite
+				vis->mobjflags |= MF_SHADOW;
+			}
+			else if (viewplayer->mo->flags & MF_SHADOW)
+			{
+				vis->mobjflags |= MF_ALTSHADOW;
+			}
+		}
+		else if (viewplayer->powers[pw_invulnerability] & 8)
+		{
+			vis->mobjflags |= MF_SHADOW;
+		}
+	}
+	else if (fixedcolormap)
+	{
+		// Fixed color
+		vis->colormap = fixedcolormap;
+	}
+	else if (psp->state->frame & FF_FULLBRIGHT)
+	{
+		// Full bright
+		vis->colormap = colormaps;
+	}
+	else
+	{
+		// local light
+		vis->colormap = spritelights[MAXLIGHTSCALE-1];
+	}
+	R_DrawVisSprite(vis, vis->x1, vis->x2);
+#endif
+}
+
+/*
+========================
+=
+= R_DrawPlayerSprites
+=
+========================
+*/
+
+void R_DrawPlayerSprites (void)
+{
+	int		i;
+	pspdef_t	*psp;
+#ifndef RENDER3D
+	int		lightnum;
+
+//
+// get light level
+//
+	lightnum = (viewplayer->mo->subsector->sector->lightlevel >> LIGHTSEGSHIFT) + extralight;
+	if (lightnum < 0)
+		spritelights = scalelight[0];
+	else if (lightnum >= LIGHTLEVELS)
+		spritelights = scalelight[LIGHTLEVELS-1];
+	else
+		spritelights = scalelight[lightnum];
+//
+// clip to screen bounds
+//
+	mfloorclip = screenheightarray;
+	mceilingclip = negonearray;
+#endif
+
+//
+// add all active psprites
+//
+	for (i = 0, psp = viewplayer->psprites; i < NUMPSPRITES; i++, psp++)
+	{
+		if (psp->state)
+			R_DrawPSprite (psp);
+	}
+}
+
+
+/*
+========================
+=
+= R_SortVisSprites
+=
+========================
+*/
+
+vissprite_t	vsprsortedhead;
+
+void R_SortVisSprites (void)
+{
+	int		i, count;
+	vissprite_t	*ds, *best;
+	vissprite_t	unsorted;
+	fixed_t		bestscale;
+
+	count = vissprite_p - vissprites;
+
+	unsorted.next = unsorted.prev = &unsorted;
+	if (!count)
+		return;
+
+	for (ds = vissprites; ds < vissprite_p; ds++)
+	{
+		ds->next = ds + 1;
+		ds->prev = ds - 1;
+	}
+	vissprites[0].prev = &unsorted;
+	unsorted.next = &vissprites[0];
+	(vissprite_p - 1)->next = &unsorted;
+	unsorted.prev = vissprite_p - 1;
+
+//
+// pull the vissprites out by scale
+//
+	best = 0;		// shut up the compiler warning
+	vsprsortedhead.next = vsprsortedhead.prev = &vsprsortedhead;
+	for (i = 0; i < count; i++)
+	{
+		bestscale = H2MAXINT;
+		for (ds = unsorted.next; ds != &unsorted; ds = ds->next)
+		{
+			if (ds->scale < bestscale)
+			{
+				bestscale = ds->scale;
+				best = ds;
+			}
+		}
+		best->next->prev = best->prev;
+		best->prev->next = best->next;
+		best->next = &vsprsortedhead;
+		best->prev = vsprsortedhead.prev;
+		vsprsortedhead.prev->next = best;
+		vsprsortedhead.prev = best;
+	}
+}
+
+
+#ifndef RENDER3D
+/*
+========================
+=
+= R_DrawSprite
+=
+========================
+*/
+
+void R_DrawSprite (vissprite_t *spr)
+{
+	drawseg_t	*ds;
+	short		clipbot[SCREENWIDTH], cliptop[SCREENWIDTH];
+	int		x, r1, r2;
+	fixed_t		scale, lowscale;
+	int		silhouette;
+
+	for (x = spr->x1; x <= spr->x2; x++)
+		clipbot[x] = cliptop[x] = -2;
+
+//
+// scan drawsegs from end to start for obscuring segs
+// the first drawseg that has a greater scale is the clip seg
+//
+	for (ds = ds_p - 1; ds >= drawsegs; ds--)
+	{
+		//
+		// determine if the drawseg obscures the sprite
+		//
+		if (ds->x1 > spr->x2 || ds->x2 < spr->x1 ||
+				(!ds->silhouette && !ds->maskedtexturecol))
+			continue;			// doesn't cover sprite
+
+		r1 = ds->x1 < spr->x1 ? spr->x1 : ds->x1;
+		r2 = ds->x2 > spr->x2 ? spr->x2 : ds->x2;
+		if (ds->scale1 > ds->scale2)
+		{
+			lowscale = ds->scale2;
+			scale = ds->scale1;
+		}
+		else
+		{
+			lowscale = ds->scale1;
+			scale = ds->scale2;
+		}
+
+		if (scale < spr->scale || ( lowscale < spr->scale
+				&& !R_PointOnSegSide(spr->gx, spr->gy, ds->curline) ) )
+		{
+			if (ds->maskedtexturecol)	// masked mid texture
+				R_RenderMaskedSegRange (ds, r1, r2);
+			continue;			// seg is behind sprite
+		}
+
+//
+// clip this piece of the sprite
+//
+		silhouette = ds->silhouette;
+		if (spr->gz >= ds->bsilheight)
+			silhouette &= ~SIL_BOTTOM;
+		if (spr->gzt <= ds->tsilheight)
+			silhouette &= ~SIL_TOP;
+
+		if (silhouette == 1)
+		{	// bottom sil
+			for (x = r1; x <= r2; x++)
+			{
+				if (clipbot[x] == -2)
+					clipbot[x] = ds->sprbottomclip[x];
+			}
+		}
+		else if (silhouette == 2)
+		{	// top sil
+			for (x = r1; x <= r2; x++)
+			{
+				if (cliptop[x] == -2)
+					cliptop[x] = ds->sprtopclip[x];
+			}
+		}
+		else if (silhouette == 3)
+		{	// both
+			for (x = r1; x <= r2; x++)
+			{
+				if (clipbot[x] == -2)
+					clipbot[x] = ds->sprbottomclip[x];
+				if (cliptop[x] == -2)
+					cliptop[x] = ds->sprtopclip[x];
+			}
+		}
+	}
+
+//
+// all clipping has been performed, so draw the sprite
+//
+
+// check for unclipped columns
+	for (x = spr->x1; x <= spr->x2; x++)
+	{
+		if (clipbot[x] == -2)
+			clipbot[x] = viewheight;
+		if (cliptop[x] == -2)
+			cliptop[x] = -1;
+	}
+
+	mfloorclip = clipbot;
+	mceilingclip = cliptop;
+	R_DrawVisSprite (spr, spr->x1, spr->x2);
+}
+#endif	/* !RENDER3D */
+
+
+/*
+========================
+=
+= R_DrawMasked
+=
+========================
+*/
+
+void R_DrawMasked (void)
+{
+	vissprite_t		*spr;
+
+#ifdef RENDER3D
+	extern boolean willRenderSprites;
+
+	if (!willRenderSprites)
+		return;
+
+	R_SortVisSprites();
+
+	if (vissprite_p > vissprites)
+	{
+	// draw all vissprites back to front
+		glDepthMask(GL_FALSE);
+
+		for (spr = vsprsortedhead.next; spr != &vsprsortedhead;
+							spr = spr->next)
+		{
+			R_RenderSprite(spr);
+		}
+
+		glDepthMask(GL_TRUE);
+	}
+#else
+	drawseg_t		*ds;
+
+	R_SortVisSprites ();
+
+	if (vissprite_p > vissprites)
+	{
+	// draw all vissprites back to front
+		for (spr = vsprsortedhead.next; spr != &vsprsortedhead;
+							spr = spr->next)
+		{
+			R_DrawSprite (spr);
+		}
+	}
+
+//
+// render any remaining masked mid textures
+//
+	for (ds = ds_p - 1; ds >= drawsegs; ds--)
+	{
+		if (ds->maskedtexturecol)
+			R_RenderMaskedSegRange (ds, ds->x1, ds->x2);
+	}
+
+//
+// draw the psprites on top of everything
+//
+// Added for the sideviewing with an external device
+	if (viewangleoffset <= 1024<<ANGLETOFINESHIFT ||
+		viewangleoffset >= -1024<<ANGLETOFINESHIFT)
+	{
+	// don't draw on side views
+		R_DrawPlayerSprites ();
+	}
+
+//	if (!viewangleoffset)		// don't draw on side views
+//		R_DrawPlayerSprites ();
+#endif
+}
+
--- /dev/null
+++ b/s_sound.c
@@ -1,0 +1,1260 @@
+//**************************************************************************
+//**
+//** S_SOUND.C:  MUSIC & SFX API
+//**
+//** $Revision: 590 $
+//** $Date: 2012-10-23 23:55:31 +0300 (Tue, 23 Oct 2012) $
+//**
+//**************************************************************************
+
+// HEADER FILES ------------------------------------------------------------
+
+#include "h2stdinc.h"
+#include "h2def.h"
+#include "p_local.h"	/* P_AproxDistance() */
+#include "sounds.h"
+#include "i_sound.h"
+#include "i_cdmus.h"
+#include "soundst.h"
+
+// MACROS ------------------------------------------------------------------
+
+#define DEFAULT_ARCHIVEPATH	"o:\\sound\\archive\\"
+#define PRIORITY_MAX_ADJUST	10
+#define DIST_ADJUST	(MAX_SND_DIST/PRIORITY_MAX_ADJUST)
+
+// TYPES -------------------------------------------------------------------
+
+// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
+
+// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
+
+// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
+
+static boolean S_StopSoundID(int sound_id, int priority);
+
+// EXTERNAL DATA DECLARATIONS ----------------------------------------------
+
+extern int	snd_MaxVolume;
+extern int	snd_MusicVolume;
+extern int	snd_Channels;
+
+#ifdef __WATCOMC__
+extern int	snd_SfxDevice;
+extern int	snd_MusicDevice;
+extern int	snd_DesiredSfxDevice;
+extern int	snd_DesiredMusicDevice;
+extern int	tsm_ID;
+#endif
+
+extern void	**lumpcache;
+
+extern int	startepisode;
+extern int	startmap;
+
+// PUBLIC DATA DEFINITIONS -------------------------------------------------
+
+/* Sound info */
+sfxinfo_t S_sfx[] =
+{
+	/* tagname, lumpname, priority, usefulness, snd_ptr, lumpnum, numchannels, */
+	/*		pitchshift						   */
+	{ "", "", 0, -1, NULL, 0, 0, 0 },
+	{ "PlayerFighterNormalDeath", "", 256, -1, NULL, 0, 2, 1 },
+	{ "PlayerFighterCrazyDeath", "", 256, -1, NULL, 0, 2, 1 },
+	{ "PlayerFighterExtreme1Death", "", 256, -1, NULL, 0, 2, 1 },
+	{ "PlayerFighterExtreme2Death", "", 256, -1, NULL, 0, 2, 1 },
+	{ "PlayerFighterExtreme3Death", "", 256, -1, NULL, 0, 2, 1 },
+	{ "PlayerFighterBurnDeath", "", 256, -1, NULL, 0, 2, 1 },
+	{ "PlayerClericNormalDeath", "", 256, -1, NULL, 0, 2, 1 },
+	{ "PlayerClericCrazyDeath", "", 256, -1, NULL, 0, 2, 1 },
+	{ "PlayerClericExtreme1Death", "", 256, -1, NULL, 0, 2, 1 },
+	{ "PlayerClericExtreme2Death", "", 256, -1, NULL, 0, 2, 1 },
+	{ "PlayerClericExtreme3Death", "", 256, -1, NULL, 0, 2, 1 },
+	{ "PlayerClericBurnDeath", "", 256, -1, NULL, 0, 2, 1 },
+	{ "PlayerMageNormalDeath", "", 256, -1, NULL, 0, 2, 0 },
+	{ "PlayerMageCrazyDeath", "", 256, -1, NULL, 0, 2, 0 },
+	{ "PlayerMageExtreme1Death", "", 256, -1, NULL, 0, 2, 0 },
+	{ "PlayerMageExtreme2Death", "", 256, -1, NULL, 0, 2, 0 },
+	{ "PlayerMageExtreme3Death", "", 256, -1, NULL, 0, 2, 0 },
+	{ "PlayerMageBurnDeath", "", 256, -1, NULL, 0, 2, 0 },
+	{ "PlayerFighterPain", "", 256, -1, NULL, 0, 2, 1 },
+	{ "PlayerClericPain", "", 256, -1, NULL, 0, 2, 1 },
+	{ "PlayerMagePain", "", 256, -1, NULL, 0, 2, 0 },
+	{ "PlayerFighterGrunt", "", 256, -1, NULL, 0, 2, 1 },
+	{ "PlayerClericGrunt", "", 256, -1, NULL, 0, 2, 1 },
+	{ "PlayerMageGrunt", "", 256, -1, NULL, 0, 2, 0 },
+	{ "PlayerLand", "", 32, -1, NULL, 0, 2, 1 },
+	{ "PlayerPoisonCough", "", 256, -1, NULL, 0, 2, 1 },
+	{ "PlayerFighterFallingScream", "", 256, -1, NULL, 0, 2, 1 },
+	{ "PlayerClericFallingScream", "", 256, -1, NULL, 0, 2, 1 },
+	{ "PlayerMageFallingScream", "", 256, -1, NULL, 0, 2, 0 },
+	{ "PlayerFallingSplat", "", 256, -1, NULL, 0, 2, 1 },
+	{ "PlayerFighterFailedUse", "", 256, -1, NULL, 0, 1, 1 },
+	{ "PlayerClericFailedUse", "", 256, -1, NULL, 0, 1, 1 },
+	{ "PlayerMageFailedUse", "", 256, -1, NULL, 0, 1, 0 },
+	{ "PlatformStart", "", 36, -1, NULL, 0, 2, 1 },
+	{ "PlatformStartMetal", "", 36, -1, NULL, 0, 2, 1 },
+	{ "PlatformStop", "", 40, -1, NULL, 0, 2, 1 },
+	{ "StoneMove", "", 32, -1, NULL, 0, 2, 1 },
+	{ "MetalMove", "", 32, -1, NULL, 0, 2, 1 },
+	{ "DoorOpen", "", 36, -1, NULL, 0, 2, 1 },
+	{ "DoorLocked", "", 36, -1, NULL, 0, 2, 1 },
+	{ "DoorOpenMetal", "", 36, -1, NULL, 0, 2, 1 },
+	{ "DoorCloseMetal", "", 36, -1, NULL, 0, 2, 1 },
+	{ "DoorCloseLight", "", 36, -1, NULL, 0, 2, 1 },
+	{ "DoorCloseHeavy", "", 36, -1, NULL, 0, 2, 1 },
+	{ "DoorCreak", "", 36, -1, NULL, 0, 2, 1 },
+	{ "PickupWeapon", "", 36, -1, NULL, 0, 2, 0 },
+	{ "PickupArtifact", "", 36, -1, NULL, 0, 2, 1 },
+	{ "PickupKey", "", 36, -1, NULL, 0, 2, 1 },
+	{ "PickupItem", "", 36, -1, NULL, 0, 2, 1 },
+	{ "PickupPiece", "", 36, -1, NULL, 0, 2, 0 },
+	{ "WeaponBuild", "", 36, -1, NULL, 0, 2, 0 },
+	{ "UseArtifact", "", 36, -1, NULL, 0, 2, 1 },
+	{ "BlastRadius", "", 36, -1, NULL, 0, 2, 1 },
+	{ "Teleport", "", 256, -1, NULL, 0, 2, 1 },
+	{ "ThunderCrash", "", 30, -1, NULL, 0, 2, 1 },
+	{ "FighterPunchMiss", "", 80, -1, NULL, 0, 2, 1 },
+	{ "FighterPunchHitThing", "", 80, -1, NULL, 0, 2, 1 },
+	{ "FighterPunchHitWall", "", 80, -1, NULL, 0, 2, 1 },
+	{ "FighterGrunt", "", 80, -1, NULL, 0, 2, 1 },
+	{ "FighterAxeHitThing", "", 80, -1, NULL, 0, 2, 1 },
+	{ "FighterHammerMiss", "", 80, -1, NULL, 0, 2, 1 },
+	{ "FighterHammerHitThing", "", 80, -1, NULL, 0, 2, 1 },
+	{ "FighterHammerHitWall", "", 80, -1, NULL, 0, 2, 1 },
+	{ "FighterHammerContinuous", "", 32, -1, NULL, 0, 2, 1 },
+	{ "FighterHammerExplode", "", 80, -1, NULL, 0, 2, 1 },
+	{ "FighterSwordFire", "", 80, -1, NULL, 0, 2, 1 },
+	{ "FighterSwordExplode", "", 80, -1, NULL, 0, 2, 1 },
+	{ "ClericCStaffFire", "", 80, -1, NULL, 0, 2, 1 },
+	{ "ClericCStaffExplode", "", 40, -1, NULL, 0, 2, 1 },
+	{ "ClericCStaffHitThing", "", 80, -1, NULL, 0, 2, 1 },
+	{ "ClericFlameFire", "", 80, -1, NULL, 0, 2, 1 },
+	{ "ClericFlameExplode", "", 80, -1, NULL, 0, 2, 1 },
+	{ "ClericFlameCircle", "", 80, -1, NULL, 0, 2, 1 },
+	{ "MageWandFire", "", 80, -1, NULL, 0, 2, 1 },
+	{ "MageLightningFire", "", 80, -1, NULL, 0, 2, 1 },
+	{ "MageLightningZap", "", 32, -1, NULL, 0, 2, 1 },
+	{ "MageLightningContinuous", "", 32, -1, NULL, 0, 2, 1 },
+	{ "MageLightningReady", "", 30, -1, NULL, 0, 2, 1 },
+	{ "MageShardsFire","", 80, -1, NULL, 0, 2, 1 },
+	{ "MageShardsExplode","", 36, -1, NULL, 0, 2, 1 },
+	{ "MageStaffFire","", 80, -1, NULL, 0, 2, 1 },
+	{ "MageStaffExplode","", 40, -1, NULL, 0, 2, 1 },
+	{ "Switch1", "", 32, -1, NULL, 0, 2, 1 },
+	{ "Switch2", "", 32, -1, NULL, 0, 2, 1 },
+	{ "SerpentSight", "", 32, -1, NULL, 0, 2, 1 },
+	{ "SerpentActive", "", 32, -1, NULL, 0, 2, 1 },
+	{ "SerpentPain", "", 32, -1, NULL, 0, 2, 1 },
+	{ "SerpentAttack", "", 32, -1, NULL, 0, 2, 1 },
+	{ "SerpentMeleeHit", "", 32, -1, NULL, 0, 2, 1 },
+	{ "SerpentDeath", "", 40, -1, NULL, 0, 2, 1 },
+	{ "SerpentBirth", "", 32, -1, NULL, 0, 2, 1 },
+	{ "SerpentFXContinuous", "", 32, -1, NULL, 0, 2, 1 },
+	{ "SerpentFXHit", "", 32, -1, NULL, 0, 2, 1 },
+	{ "PotteryExplode", "", 32, -1, NULL, 0, 2, 1 },
+	{ "Drip", "", 32, -1, NULL, 0, 2, 1 },
+	{ "CentaurSight", "", 32, -1, NULL, 0, 2, 1 },
+	{ "CentaurActive", "", 32, -1, NULL, 0, 2, 1 },
+	{ "CentaurPain", "", 32, -1, NULL, 0, 2, 1 },
+	{ "CentaurAttack", "", 32, -1, NULL, 0, 2, 1 },
+	{ "CentaurDeath", "", 40, -1, NULL, 0, 2, 1 },
+	{ "CentaurLeaderAttack", "", 32, -1, NULL, 0, 2, 1 },
+	{ "CentaurMissileExplode", "", 32, -1, NULL, 0, 2, 1 },
+	{ "Wind", "", 1, -1, NULL, 0, 2, 1 },
+	{ "BishopSight", "", 32, -1, NULL, 0, 2, 1 },
+	{ "BishopActive", "", 32, -1, NULL, 0, 2, 1 },
+	{ "BishopPain", "", 32, -1, NULL, 0, 2, 1 },
+	{ "BishopAttack", "", 32, -1, NULL, 0, 2, 1 },
+	{ "BishopDeath", "", 40, -1, NULL, 0, 2, 1 },
+	{ "BishopMissileExplode", "", 32, -1, NULL, 0, 2, 1 },
+	{ "BishopBlur", "", 32, -1, NULL, 0, 2, 1 },
+	{ "DemonSight", "", 32, -1, NULL, 0, 2, 1 },
+	{ "DemonActive", "", 32, -1, NULL, 0, 2, 1 },
+	{ "DemonPain", "", 32, -1, NULL, 0, 2, 1 },
+	{ "DemonAttack", "", 32, -1, NULL, 0, 2, 1 },
+	{ "DemonMissileFire", "", 32, -1, NULL, 0, 2, 1 },
+	{ "DemonMissileExplode", "", 32, -1, NULL, 0, 2, 1 },
+	{ "DemonDeath", "", 40, -1, NULL, 0, 2, 1 },
+	{ "WraithSight", "", 32, -1, NULL, 0, 2, 1 },
+	{ "WraithActive", "", 32, -1, NULL, 0, 2, 1 },
+	{ "WraithPain", "", 32, -1, NULL, 0, 2, 1 },
+	{ "WraithAttack", "", 32, -1, NULL, 0, 2, 1 },
+	{ "WraithMissileFire", "", 32, -1, NULL, 0, 2, 1 },
+	{ "WraithMissileExplode", "", 32, -1, NULL, 0, 2, 1 },
+	{ "WraithDeath", "", 40, -1, NULL, 0, 2, 1 },
+	{ "PigActive1", "", 32, -1, NULL, 0, 2, 1 },
+	{ "PigActive2", "", 32, -1, NULL, 0, 2, 1 },
+	{ "PigPain", "", 32, -1, NULL, 0, 2, 1 },
+	{ "PigAttack", "", 32, -1, NULL, 0, 2, 1 },
+	{ "PigDeath", "", 40, -1, NULL, 0, 2, 1 },
+	{ "MaulatorSight", "", 32, -1, NULL, 0, 2, 1 },
+	{ "MaulatorActive", "", 32, -1, NULL, 0, 2, 1 },
+	{ "MaulatorPain", "", 32, -1, NULL, 0, 2, 1 },
+	{ "MaulatorHamSwing", "", 32, -1, NULL, 0, 2, 1 },
+	{ "MaulatorHamHit", "", 32, -1, NULL, 0, 2, 1 },
+	{ "MaulatorMissileHit", "", 32, -1, NULL, 0, 2, 1 },
+	{ "MaulatorDeath", "", 40, -1, NULL, 0, 2, 1 },
+	{ "FreezeDeath", "", 40, -1, NULL, 0, 2, 1 },
+	{ "FreezeShatter", "", 40, -1, NULL, 0, 2, 1 },
+	{ "EttinSight", "", 32, -1, NULL, 0, 2, 1 },
+	{ "EttinActive", "", 32, -1, NULL, 0, 2, 1 },
+	{ "EttinPain", "", 32, -1, NULL, 0, 2, 1 },
+	{ "EttinAttack", "", 32, -1, NULL, 0, 2, 1 },
+	{ "EttinDeath", "", 40, -1, NULL, 0, 2, 1 },
+	{ "FireDemonSpawn", "", 32, -1, NULL, 0, 2, 1 },
+	{ "FireDemonActive", "", 32, -1, NULL, 0, 2, 1 },
+	{ "FireDemonPain", "", 32, -1, NULL, 0, 2, 1 },
+	{ "FireDemonAttack", "", 32, -1, NULL, 0, 2, 1 },
+	{ "FireDemonMissileHit", "", 32, -1, NULL, 0, 2, 1 },
+	{ "FireDemonDeath", "", 40, -1, NULL, 0, 2, 1 },
+	{ "IceGuySight", "", 32, -1, NULL, 0, 2, 1 },
+	{ "IceGuyActive", "", 32, -1, NULL, 0, 2, 1 },
+	{ "IceGuyAttack", "", 32, -1, NULL, 0, 2, 1 },
+	{ "IceGuyMissileExplode", "", 32, -1, NULL, 0, 2, 1 },
+	{ "SorcererSight", "", 256, -1, NULL, 0, 2, 1 },
+	{ "SorcererActive", "", 256, -1, NULL, 0, 2, 1 },
+	{ "SorcererPain", "", 256, -1, NULL, 0, 2, 1 },
+	{ "SorcererSpellCast", "", 256, -1, NULL, 0, 2, 1 },
+	{ "SorcererBallWoosh", "", 256, -1, NULL, 0, 4, 1 },
+	{ "SorcererDeathScream", "", 256, -1, NULL, 0, 2, 1 },
+	{ "SorcererBishopSpawn", "", 80, -1, NULL, 0, 2, 1 },
+	{ "SorcererBallPop", "", 80, -1, NULL, 0, 2, 1 },
+	{ "SorcererBallBounce", "", 80, -1, NULL, 0, 3, 1 },
+	{ "SorcererBallExplode", "", 80, -1, NULL, 0, 3, 1 },
+	{ "SorcererBigBallExplode", "", 80, -1, NULL, 0, 3, 1 },
+	{ "SorcererHeadScream", "", 256, -1, NULL, 0, 2, 1 },
+	{ "DragonSight", "", 64, -1, NULL, 0, 2, 1 },
+	{ "DragonActive", "", 64, -1, NULL, 0, 2, 1 },
+	{ "DragonWingflap", "", 64, -1, NULL, 0, 2, 1 },
+	{ "DragonAttack", "", 64, -1, NULL, 0, 2, 1 },
+	{ "DragonPain", "", 64, -1, NULL, 0, 2, 1 },
+	{ "DragonDeath", "", 64, -1, NULL, 0, 2, 1 },
+	{ "DragonFireballExplode", "", 32, -1, NULL, 0, 2, 1 },
+	{ "KoraxSight", "", 256, -1, NULL, 0, 2, 1 },
+	{ "KoraxActive", "", 256, -1, NULL, 0, 2, 1 },
+	{ "KoraxPain", "", 256, -1, NULL, 0, 2, 1 },
+	{ "KoraxAttack", "", 256, -1, NULL, 0, 2, 1 },
+	{ "KoraxCommand", "", 256, -1, NULL, 0, 2, 1 },
+	{ "KoraxDeath", "", 256, -1, NULL, 0, 2, 1 },
+	{ "KoraxStep", "", 128, -1, NULL, 0, 2, 1 },
+	{ "ThrustSpikeRaise", "", 32, -1, NULL, 0, 2, 1 },
+	{ "ThrustSpikeLower", "", 32, -1, NULL, 0, 2, 1 },
+	{ "GlassShatter", "", 32, -1, NULL, 0, 2, 1 },
+	{ "FlechetteBounce", "", 32, -1, NULL, 0, 2, 1 },
+	{ "FlechetteExplode", "", 32, -1, NULL, 0, 2, 1 },
+	{ "LavaMove", "", 36, -1, NULL, 0, 2, 1 },
+	{ "WaterMove", "", 36, -1, NULL, 0, 2, 1 },
+	{ "IceStartMove", "", 36, -1, NULL, 0, 2, 1 },
+	{ "EarthStartMove", "", 36, -1, NULL, 0, 2, 1 },
+	{ "WaterSplash", "", 32, -1, NULL, 0, 2, 1 },
+	{ "LavaSizzle", "", 32, -1, NULL, 0, 2, 1 },
+	{ "SludgeGloop", "", 32, -1, NULL, 0, 2, 1 },
+	{ "HolySymbolFire", "", 64, -1, NULL, 0, 2, 1 },
+	{ "SpiritActive", "", 32, -1, NULL, 0, 2, 1 },
+	{ "SpiritAttack", "", 32, -1, NULL, 0, 2, 1 },
+	{ "SpiritDie", "", 32, -1, NULL, 0, 2, 1 },
+	{ "ValveTurn", "", 36, -1, NULL, 0, 2, 1 },
+	{ "RopePull", "", 36, -1, NULL, 0, 2, 1 },
+	{ "FlyBuzz", "", 20, -1, NULL, 0, 2, 1 },
+	{ "Ignite", "", 32, -1, NULL, 0, 2, 1 },
+	{ "PuzzleSuccess", "", 256, -1, NULL, 0, 2, 1 },
+	{ "PuzzleFailFighter", "", 256, -1, NULL, 0, 2, 1 },
+	{ "PuzzleFailCleric", "", 256, -1, NULL, 0, 2, 1 },
+	{ "PuzzleFailMage", "", 256, -1, NULL, 0, 2, 1 },
+	{ "Earthquake", "", 32, -1, NULL, 0, 2, 1 },
+	{ "BellRing", "", 32, -1, NULL, 0, 2, 0 },
+	{ "TreeBreak", "", 32, -1, NULL, 0, 2, 1 },
+	{ "TreeExplode", "", 32, -1, NULL, 0, 2, 1 },
+	{ "SuitofArmorBreak", "", 32, -1, NULL, 0, 2, 1 },
+	{ "PoisonShroomPain", "", 20, -1, NULL, 0, 2, 1 },
+	{ "PoisonShroomDeath", "", 32, -1, NULL, 0, 2, 1 },
+	{ "Ambient1", "", 1, -1, NULL, 0, 1, 1 },
+	{ "Ambient2", "", 1, -1, NULL, 0, 1, 1 },
+	{ "Ambient3", "", 1, -1, NULL, 0, 1, 1 },
+	{ "Ambient4", "", 1, -1, NULL, 0, 1, 1 },
+	{ "Ambient5", "", 1, -1, NULL, 0, 1, 1 },
+	{ "Ambient6", "", 1, -1, NULL, 0, 1, 1 },
+	{ "Ambient7", "", 1, -1, NULL, 0, 1, 1 },
+	{ "Ambient8", "", 1, -1, NULL, 0, 1, 1 },
+	{ "Ambient9", "", 1, -1, NULL, 0, 1, 1 },
+	{ "Ambient10", "", 1, -1, NULL, 0, 1, 1 },
+	{ "Ambient11", "", 1, -1, NULL, 0, 1, 1 },
+	{ "Ambient12", "", 1, -1, NULL, 0, 1, 1 },
+	{ "Ambient13", "", 1, -1, NULL, 0, 1, 1 },
+	{ "Ambient14", "", 1, -1, NULL, 0, 1, 1 },
+	{ "Ambient15", "", 1, -1, NULL, 0, 1, 1 },
+	{ "StartupTick", "", 32, -1, NULL, 0, 2, 1 },
+	{ "SwitchOtherLevel", "", 32, -1, NULL, 0, 2, 1 },
+	{ "Respawn", "", 32, -1, NULL, 0, 2, 1 },
+	{ "KoraxVoiceGreetings", "", 512, -1, NULL, 0, 2, 1 },
+	{ "KoraxVoiceReady", "", 512, -1, NULL, 0, 2, 1 },
+	{ "KoraxVoiceBlood", "", 512, -1, NULL, 0, 2, 1 },
+	{ "KoraxVoiceGame", "", 512, -1, NULL, 0, 2, 1 },
+	{ "KoraxVoiceBoard", "", 512, -1, NULL, 0, 2, 1 },
+	{ "KoraxVoiceWorship", "", 512, -1, NULL, 0, 2, 1 },
+	{ "KoraxVoiceMaybe", "", 512, -1, NULL, 0, 2, 1 },
+	{ "KoraxVoiceStrong", "", 512, -1, NULL, 0, 2, 1 },
+	{ "KoraxVoiceFace", "", 512, -1, NULL, 0, 2, 1 },
+	{ "BatScream", "", 32, -1, NULL, 0, 2, 1 },
+	{ "Chat", "", 512, -1, NULL, 0, 2, 1 },
+	{ "MenuMove", "", 32, -1, NULL, 0, 2, 1 },
+	{ "ClockTick", "", 32, -1, NULL, 0, 2, 1 },
+	{ "Fireball", "", 32, -1, NULL, 0, 2, 1 },
+	{ "PuppyBeat", "", 30, -1, NULL, 0, 2, 1 },
+	{ "MysticIncant", "", 32, -1, NULL, 0, 4, 1 }
+};
+
+// PRIVATE DATA DEFINITIONS ------------------------------------------------
+
+static channel_t Channel[MAX_CHANNELS];
+static int	RegisteredSong;	/* the current registered song. */
+static int	isExternalSong;
+static int	NextCleanup;
+static boolean	MusicPaused;
+static int	Mus_Song = -1;
+static int	Mus_LumpNum;
+static void	*Mus_SndPtr;
+static byte	*SoundCurve;
+
+static boolean	UseSndScript;
+static char	ArchivePath[MAX_OSPATH];
+
+// CODE --------------------------------------------------------------------
+
+//==========================================================================
+//
+// S_Init
+//
+//==========================================================================
+
+void S_Init(void)
+{
+	SoundCurve = (byte *) W_CacheLumpName("SNDCURVE", PU_STATIC);
+//	SoundCurve = (byte *) Z_Malloc(MAX_SND_DIST, PU_STATIC, NULL);
+	I_StartupSound();
+	if (snd_Channels > 8)
+	{
+		snd_Channels = 8;
+	}
+	I_SetChannels(snd_Channels);
+	I_SetMusicVolume(snd_MusicVolume);
+
+	// Attempt to setup CD music
+	ST_Message("Initializing CD Audio: ");
+	i_CDMusic = (I_CDMusInit() != -1);
+	if (i_CDMusic)
+	{
+		ST_Message("success.\n");
+	}
+	else
+	{
+		ST_Message("failed.\n");
+	}
+}
+
+//==========================================================================
+//
+// S_InitScript
+//
+//==========================================================================
+
+void S_InitScript(void)
+{
+	int p;
+	int i;
+
+	strcpy(ArchivePath, DEFAULT_ARCHIVEPATH);
+	p = M_CheckParm("-devsnd");
+	if (p && p < myargc - 1)
+	{
+		UseSndScript = true;
+		SC_OpenFile(myargv[p+1]);
+	}
+	else
+	{
+		UseSndScript = false;
+		SC_OpenLump("sndinfo");
+	}
+	while (SC_GetString())
+	{
+		if (*sc_String == '$')
+		{
+			if (!strcasecmp(sc_String, "$ARCHIVEPATH"))
+			{
+				SC_MustGetString();
+				strcpy(ArchivePath, sc_String);
+			}
+			else if (!strcasecmp(sc_String, "$MAP"))
+			{
+				SC_MustGetNumber();
+				SC_MustGetString();
+				if (sc_Number)
+				{
+					P_PutMapSongLump(sc_Number, sc_String);
+				}
+			}
+			continue;
+		}
+		else
+		{
+			for (i = 0; i < NUMSFX; i++)
+			{
+				if (!strcmp(S_sfx[i].tagName, sc_String))
+				{
+					SC_MustGetString();
+					if (*sc_String != '?')
+					{
+						strcpy(S_sfx[i].lumpname, sc_String);
+					}
+					else
+					{
+						strcpy(S_sfx[i].lumpname, "default");
+					}
+					break;
+				}
+			}
+			if (i == NUMSFX)
+			{
+				SC_MustGetString();
+			}
+		}
+	}
+	SC_Close();
+
+	for (i = 0; i < NUMSFX; i++)
+	{
+		if (!strcmp(S_sfx[i].lumpname, ""))
+		{
+			strcpy(S_sfx[i].lumpname, "default");
+		}
+	}
+}
+
+//==========================================================================
+//
+// S_ShutDown
+//
+//==========================================================================
+
+void S_ShutDown(void)
+{
+	if (i_CDMusic)
+	{
+		I_CDMusStop();
+	}
+	I_CDMusShutdown();
+#ifdef __WATCOMC__
+	if (tsm_ID == -1)
+		return;
+#endif
+	if (RegisteredSong)
+	{
+		I_StopSong(RegisteredSong);
+		I_UnRegisterSong(RegisteredSong);
+	}
+	I_ShutdownSound();
+}
+
+//==========================================================================
+//
+// S_Start
+//
+//==========================================================================
+
+void S_Start(void)
+{
+	S_StopAllSound();
+	S_StartSong(gamemap, true);
+}
+
+//==========================================================================
+//
+// S_StartSong
+//
+//==========================================================================
+
+void S_StartSong(int song, boolean loop)
+{
+	const char *songLump;
+	int track;
+
+	if (i_CDMusic && cdaudio)
+	{ // Play a CD track, instead
+		if (i_CDTrack)
+		{ // Default to the player-chosen track
+			track = i_CDTrack;
+		}
+		else
+		{
+			track = P_GetMapCDTrack(gamemap);
+		}
+		if (track == i_CDCurrentTrack && i_CDMusicLength > 0)
+		{
+			return;
+		}
+		if (!I_CDMusPlay(track))
+		{
+			/*
+			if (loop)
+			{
+			//	i_CDMusicLength = 35*I_CDMusTrackLength(track);
+				oldTic = gametic;
+			}
+			else
+			{
+				i_CDMusicLength = -1;
+			}
+			*/
+			i_CDCurrentTrack = track;
+		}
+	}
+	else
+	{
+		if (song == Mus_Song)
+		{ // don't replay an old song
+			return;
+		}
+		if (RegisteredSong)
+		{
+			I_StopSong(RegisteredSong);
+			I_UnRegisterSong(RegisteredSong);
+			if (!isExternalSong)
+			{
+				if (UseSndScript)
+				{
+					Z_Free(Mus_SndPtr);
+				}
+				else
+				{
+					Z_ChangeTag(lumpcache[Mus_LumpNum], PU_CACHE);
+				}
+#ifdef __WATCOMC__
+				_dpmi_unlockregion(Mus_SndPtr, lumpinfo[Mus_LumpNum].size);
+#endif
+			}
+			RegisteredSong = 0;
+		}
+		songLump = P_GetMapSongLump(song);
+		if (!songLump)
+		{
+			return;
+		}
+		isExternalSong = I_RegisterExternalSong(songLump);
+		if (isExternalSong)
+		{
+			RegisteredSong = isExternalSong;
+			I_PlaySong(RegisteredSong, loop);
+			Mus_Song = song;
+			return;
+		}
+		if (UseSndScript)
+		{
+			char name[MAX_OSPATH];
+			snprintf(name, sizeof(name), "%s%s.lmp", ArchivePath, songLump);
+			M_ReadFile(name, &Mus_SndPtr);
+		}
+		else
+		{
+			Mus_LumpNum = W_GetNumForName(songLump);
+			Mus_SndPtr = W_CacheLumpNum(Mus_LumpNum, PU_MUSIC);
+		}
+#ifdef __WATCOMC__
+		_dpmi_lockregion(Mus_SndPtr, lumpinfo[Mus_LumpNum].size);
+#endif
+		RegisteredSong = I_RegisterSong(Mus_SndPtr);
+		I_PlaySong(RegisteredSong, loop);	// 'true' denotes endless looping.
+		Mus_Song = song;
+	}
+}
+
+//==========================================================================
+//
+// S_StartSongName
+//
+//==========================================================================
+
+void S_StartSongName(const char *songLump, boolean loop)
+{
+	int cdTrack;
+
+	if (!songLump)
+	{
+		return;
+	}
+	if (i_CDMusic && cdaudio)
+	{
+		cdTrack = 0;
+
+		if (!strcmp(songLump, "hexen"))
+		{
+			cdTrack = P_GetCDTitleTrack();
+		}
+		else if (!strcmp(songLump, "hub"))
+		{
+			cdTrack = P_GetCDIntermissionTrack();
+		}
+		else if (!strcmp(songLump, "hall"))
+		{
+			cdTrack = P_GetCDEnd1Track();
+		}
+		else if (!strcmp(songLump, "orb"))
+		{
+			cdTrack = P_GetCDEnd2Track();
+		}
+		else if (!strcmp(songLump, "chess") && !i_CDTrack)
+		{
+			cdTrack = P_GetCDEnd3Track();
+		}
+/*	Uncomment this, if Kevin writes a specific song for startup
+		else if (!strcmp(songLump, "start"))
+		{
+			cdTrack = P_GetCDStartTrack();
+		}
+*/
+		if (!cdTrack || (cdTrack == i_CDCurrentTrack && i_CDMusicLength > 0))
+		{
+			return;
+		}
+		if (!I_CDMusPlay(cdTrack))
+		{
+			/*
+			if (loop)
+			{
+				i_CDMusicLength = 35*I_CDMusTrackLength(cdTrack);
+				oldTic = gametic;
+			}
+			else
+			{
+				i_CDMusicLength = -1;
+			}
+			*/
+			i_CDCurrentTrack = cdTrack;
+			i_CDTrack = false;
+		}
+	}
+	else
+	{
+		if (RegisteredSong)
+		{
+			I_StopSong(RegisteredSong);
+			I_UnRegisterSong(RegisteredSong);
+			if (!isExternalSong)
+			{
+				if (UseSndScript)
+				{
+					Z_Free(Mus_SndPtr);
+				}
+				else
+				{
+					Z_ChangeTag(lumpcache[Mus_LumpNum], PU_CACHE);
+				}
+			}
+#ifdef __WATCOMC__
+			_dpmi_unlockregion(Mus_SndPtr, lumpinfo[Mus_LumpNum].size);
+#endif
+			RegisteredSong = 0;
+		}
+		isExternalSong = I_RegisterExternalSong(songLump);
+		if (isExternalSong)
+		{
+			RegisteredSong = isExternalSong;
+			I_PlaySong(RegisteredSong, loop);
+			Mus_Song = -1;
+			return;
+		}
+		if (UseSndScript)
+		{
+			char name[MAX_OSPATH];
+			snprintf(name, sizeof(name), "%s%s.lmp", ArchivePath, songLump);
+			M_ReadFile(name, &Mus_SndPtr);
+		}
+		else
+		{
+			Mus_LumpNum = W_GetNumForName(songLump);
+			Mus_SndPtr = W_CacheLumpNum(Mus_LumpNum, PU_MUSIC);
+		}
+#ifdef __WATCOMC__
+		_dpmi_lockregion(Mus_SndPtr, lumpinfo[Mus_LumpNum].size);
+#endif
+		RegisteredSong = I_RegisterSong(Mus_SndPtr);
+		I_PlaySong(RegisteredSong, loop);	// 'true' denotes endless looping.
+		Mus_Song = -1;
+	}
+}
+
+//==========================================================================
+//
+// S_GetSoundID
+//
+//==========================================================================
+
+int S_GetSoundID(const char *name)
+{
+	int i;
+
+	for (i = 0; i < NUMSFX; i++)
+	{
+		if (!strcmp(S_sfx[i].tagName, name))
+		{
+			return i;
+		}
+	}
+	return 0;
+}
+
+//==========================================================================
+//
+// S_StartSound
+//
+//==========================================================================
+
+void S_StartSound(mobj_t *origin, int sound_id)
+{
+	S_StartSoundAtVolume(origin, sound_id, 127);
+}
+
+//==========================================================================
+//
+// S_StartSoundAtVolume
+//
+//==========================================================================
+
+void S_StartSoundAtVolume(mobj_t *origin, int sound_id, int volume)
+{
+	static int sndcount = 0;
+
+	int i;
+	int dist, vol, chan;
+	int priority;
+	int angle, sep;
+	int absx, absy;
+
+	if (sound_id == 0 || snd_MaxVolume == 0)
+		return;
+#if 0
+	if (origin == NULL)
+	{
+		origin = players[displayplayer].mo;
+	// this can be uninitialized when we are newly
+	// started before the demos start playing !...
+	}
+#endif
+	if (volume == 0)
+	{
+		return;
+	}
+
+	// calculate the distance before other stuff so that we can throw out
+	// sounds that are beyond the hearing range.
+	if (origin)
+	{
+		absx = abs(origin->x - players[displayplayer].mo->x);
+		absy = abs(origin->y - players[displayplayer].mo->y);
+	}
+	else
+	{
+		absx = absy = 0;
+	}
+	dist = absx + absy - (absx > absy ? absy>>1 : absx>>1);
+	dist >>= FRACBITS;
+	if (dist >= MAX_SND_DIST)
+	{
+		return;	// sound is beyond the hearing range...
+	}
+	if (dist < 0)
+	{
+		dist = 0;
+	}
+	priority = S_sfx[sound_id].priority;
+	priority *= (PRIORITY_MAX_ADJUST - (dist / DIST_ADJUST));
+	if (!S_StopSoundID(sound_id, priority))
+	{
+		return;	// other sounds have greater priority
+	}
+	for (i = 0; i < snd_Channels; i++)
+	{
+		if (!origin || origin->player)
+		{
+			i = snd_Channels;
+			break;	// let the player have more than one sound.
+		}
+		if (origin == Channel[i].mo)
+		{ // only allow other mobjs one sound
+			S_StopSound(Channel[i].mo);
+			break;
+		}
+	}
+	if (i >= snd_Channels)
+	{
+		for (i = 0; i < snd_Channels; i++)
+		{
+			if (Channel[i].mo == NULL)
+			{
+				break;
+			}
+		}
+		if (i >= snd_Channels)
+		{
+			// look for a lower priority sound to replace.
+			sndcount++;
+			if (sndcount >= snd_Channels)
+			{
+				sndcount = 0;
+			}
+			for (chan = 0; chan < snd_Channels; chan++)
+			{
+				i = (sndcount + chan) % snd_Channels;
+				if (priority >= Channel[i].priority)
+				{
+					chan = -1;	// denote that sound should be replaced.
+					break;
+				}
+			}
+			if (chan != -1)
+			{
+				return;	// no free channels.
+			}
+			else	// replace the lower priority sound.
+			{
+				if (Channel[i].handle)
+				{
+					if (I_SoundIsPlaying(Channel[i].handle))
+					{
+						I_StopSound(Channel[i].handle);
+					}
+					if (S_sfx[Channel[i].sound_id].usefulness > 0)
+					{
+						S_sfx[Channel[i].sound_id].usefulness--;
+					}
+				}
+			}
+		}
+	}
+	if (S_sfx[sound_id].lumpnum == 0)
+	{
+		S_sfx[sound_id].lumpnum = I_GetSfxLumpNum(&S_sfx[sound_id]);
+	}
+	if (S_sfx[sound_id].snd_ptr == NULL)
+	{
+		if (UseSndScript)
+		{
+			char name[MAX_OSPATH];
+			int len;
+			snprintf(name, sizeof(name), "%s%s.lmp",
+				 ArchivePath, S_sfx[sound_id].lumpname);
+			len = M_ReadFile(name, &S_sfx[sound_id].snd_ptr);
+			if (len <= 8)
+			{
+				I_Error("broken sound lump #%d (%s)\n",
+					S_sfx[sound_id].lumpnum, name);
+			}
+		}
+		else
+		{
+			if (W_LumpLength(S_sfx[sound_id].lumpnum) <= 8)
+			{
+			//	I_Error("broken sound lump #%d (%s)\n",
+				fprintf(stderr, "broken sound lump #%d (%s)\n",
+						S_sfx[sound_id].lumpnum,
+						S_sfx[sound_id].lumpname);
+				return;
+			}
+			S_sfx[sound_id].snd_ptr =
+				W_CacheLumpNum(S_sfx[sound_id].lumpnum, PU_SOUND);
+		}
+#ifdef __WATCOMC__
+		_dpmi_lockregion(S_sfx[sound_id].snd_ptr,
+				 lumpinfo[S_sfx[sound_id].lumpnum].size);
+#endif
+	}
+
+	vol = (SoundCurve[dist] * (snd_MaxVolume * 8) * volume)>>14;
+	if (!origin || origin == players[displayplayer].mo)
+	{
+		sep = 128;
+	//	vol = (volume*(snd_MaxVolume+1)*8)>>7;
+	}
+	else
+	{
+		angle = R_PointToAngle2(players[displayplayer].mo->x,
+					players[displayplayer].mo->y,
+					origin->x, origin->y);
+		angle = (angle - viewangle)>>24;
+		sep = angle*2 - 128;
+		if (sep < 64)
+			sep = -sep;
+		if (sep > 192)
+			sep = 512-sep;
+	//	vol = SoundCurve[dist];
+	}
+
+	if (S_sfx[sound_id].changePitch)
+	{
+		Channel[i].pitch = (byte)(127 + (M_Random() & 7) - (M_Random() & 7));
+	}
+	else
+	{
+		Channel[i].pitch = 127;
+	}
+	Channel[i].handle = I_StartSound(sound_id, S_sfx[sound_id].snd_ptr, vol,
+					 sep, Channel[i].pitch, 0);
+	Channel[i].mo = origin;
+	Channel[i].sound_id = sound_id;
+	Channel[i].priority = priority;
+	Channel[i].volume = volume;
+	if (S_sfx[sound_id].usefulness < 0)
+	{
+		S_sfx[sound_id].usefulness = 1;
+	}
+	else
+	{
+		S_sfx[sound_id].usefulness++;
+	}
+}
+
+//==========================================================================
+//
+// S_StopSoundID
+//
+//==========================================================================
+
+static boolean S_StopSoundID(int sound_id, int priority)
+{
+	int i;
+	int lp; //least priority
+	int found;
+
+	if (S_sfx[sound_id].numchannels == -1)
+	{
+		return true;
+	}
+	lp = -1; //denote the argument sound_id
+	found = 0;
+	for (i = 0; i < snd_Channels; i++)
+	{
+		if (Channel[i].sound_id == sound_id && Channel[i].mo)
+		{
+			found++; //found one.  Now, should we replace it??
+			if (priority >= Channel[i].priority)
+			{ // if we're gonna kill one, then this'll be it
+				lp = i;
+				priority = Channel[i].priority;
+			}
+		}
+	}
+	if (found < S_sfx[sound_id].numchannels)
+	{
+		return true;
+	}
+	else if (lp == -1)
+	{
+		return false;	// don't replace any sounds
+	}
+	if (Channel[lp].handle)
+	{
+		if (I_SoundIsPlaying(Channel[lp].handle))
+		{
+			I_StopSound(Channel[lp].handle);
+		}
+		if (S_sfx[Channel[lp].sound_id].usefulness > 0)
+		{
+			S_sfx[Channel[lp].sound_id].usefulness--;
+		}
+		Channel[lp].mo = NULL;
+	}
+	return true;
+}
+
+//==========================================================================
+//
+// S_StopSound
+//
+//==========================================================================
+
+void S_StopSound(mobj_t *origin)
+{
+	int i;
+
+	for (i = 0; i < snd_Channels; i++)
+	{
+		if (Channel[i].mo == origin)
+		{
+			I_StopSound(Channel[i].handle);
+			if (S_sfx[Channel[i].sound_id].usefulness > 0)
+			{
+				S_sfx[Channel[i].sound_id].usefulness--;
+			}
+			Channel[i].handle = 0;
+			Channel[i].mo = NULL;
+		}
+	}
+}
+
+//==========================================================================
+//
+// S_StopAllSound
+//
+//==========================================================================
+
+void S_StopAllSound(void)
+{
+	int i;
+
+	//stop all sounds
+	for (i = 0; i < snd_Channels; i++)
+	{
+		if (Channel[i].handle)
+		{
+			S_StopSound(Channel[i].mo);
+		}
+	}
+	memset(Channel, 0, 8*sizeof(channel_t));
+}
+
+//==========================================================================
+//
+// S_SoundLink
+//
+//==========================================================================
+
+void S_SoundLink(mobj_t *oldactor, mobj_t *newactor)
+{
+	int i;
+
+	for (i = 0; i < snd_Channels; i++)
+	{
+		if (Channel[i].mo == oldactor)
+			Channel[i].mo = newactor;
+	}
+}
+
+//==========================================================================
+//
+// S_PauseSound
+//
+//==========================================================================
+
+void S_PauseSound(void)
+{
+	I_CDMusStop();
+	I_PauseSong(RegisteredSong);
+}
+
+//==========================================================================
+//
+// S_ResumeSound
+//
+//==========================================================================
+
+void S_ResumeSound(void)
+{
+	if (i_CDMusic && cdaudio)
+	{
+		I_CDMusResume();
+	}
+	else
+	{
+		I_ResumeSong(RegisteredSong);
+	}
+}
+
+//==========================================================================
+//
+// S_UpdateSounds
+//
+//==========================================================================
+
+void S_UpdateSounds(mobj_t *listener)
+{
+	int i, dist, vol;
+	int angle, sep;
+	int priority;
+	int absx, absy;
+
+	if (i_CDMusic)
+	{
+		I_CDMusUpdate();
+	}
+	if (snd_MaxVolume == 0)
+	{
+		return;
+	}
+
+	// Update any Sequences
+	SN_UpdateActiveSequences();
+
+	if (NextCleanup < gametic)
+	{
+		if (UseSndScript)
+		{
+			for (i = 0; i < NUMSFX; i++)
+			{
+				if (S_sfx[i].usefulness == 0 && S_sfx[i].snd_ptr)
+				{
+					S_sfx[i].usefulness = -1;
+				}
+			}
+		}
+		else
+		{
+			for (i = 0; i < NUMSFX; i++)
+			{
+				if (S_sfx[i].usefulness == 0 && S_sfx[i].snd_ptr)
+				{
+					if (lumpcache[S_sfx[i].lumpnum])
+					{
+						if (((memblock_t *) ((byte*)(lumpcache[S_sfx[i].lumpnum]) -
+									sizeof(memblock_t)))->id == ZONEID)
+						{ // taken directly from the Z_ChangeTag macro
+							Z_ChangeTag2(lumpcache[S_sfx[i].lumpnum], PU_CACHE);
+#ifdef __WATCOMC__
+							_dpmi_unlockregion(S_sfx[i].snd_ptr,
+									   lumpinfo[S_sfx[i].lumpnum].size);
+#endif
+						}
+					}
+					S_sfx[i].usefulness = -1;
+					S_sfx[i].snd_ptr = NULL;
+				}
+			}
+		}
+		NextCleanup = gametic + 35*30;	// every 30 seconds
+	}
+	for (i = 0; i < snd_Channels; i++)
+	{
+		if (!Channel[i].handle || S_sfx[Channel[i].sound_id].usefulness == -1)
+		{
+			continue;
+		}
+		if (!I_SoundIsPlaying(Channel[i].handle))
+		{
+			if (S_sfx[Channel[i].sound_id].usefulness > 0)
+			{
+				S_sfx[Channel[i].sound_id].usefulness--;
+			}
+			Channel[i].handle = 0;
+			Channel[i].mo = NULL;
+			Channel[i].sound_id = 0;
+		}
+		if (Channel[i].mo == NULL || Channel[i].sound_id == 0
+			|| Channel[i].mo == listener)
+		{
+			continue;
+		}
+		else
+		{
+			absx = abs(Channel[i].mo->x - listener->x);
+			absy = abs(Channel[i].mo->y - listener->y);
+			dist = absx+absy-(absx > absy ? absy>>1 : absx>>1);
+			dist >>= FRACBITS;
+
+			if (dist >= MAX_SND_DIST)
+			{
+				S_StopSound(Channel[i].mo);
+				continue;
+			}
+			if (dist < 0)
+			{
+				dist = 0;
+			}
+			//vol = SoundCurve[dist];
+			vol = (SoundCurve[dist] * (snd_MaxVolume * 8) * Channel[i].volume)>>14;
+			if (Channel[i].mo == listener)
+			{
+				sep = 128;
+			}
+			else
+			{
+				angle = R_PointToAngle2(listener->x, listener->y,
+							Channel[i].mo->x, Channel[i].mo->y);
+				angle = (angle-viewangle)>>24;
+				sep = angle*2-128;
+				if (sep < 64)
+					sep = -sep;
+				if (sep > 192)
+					sep = 512-sep;
+			}
+			I_UpdateSoundParams(Channel[i].handle, vol, sep, Channel[i].pitch);
+			priority = S_sfx[Channel[i].sound_id].priority;
+			priority *= PRIORITY_MAX_ADJUST - (dist / DIST_ADJUST);
+			Channel[i].priority = priority;
+		}
+	}
+}
+
+//==========================================================================
+//
+// S_GetChannelInfo
+//
+//==========================================================================
+
+void S_GetChannelInfo(SoundInfo_t *s)
+{
+	int i;
+	ChanInfo_t *c;
+
+	s->channelCount = snd_Channels;
+	s->musicVolume = snd_MusicVolume;
+	s->soundVolume = snd_MaxVolume;
+	for (i = 0; i < snd_Channels; i++)
+	{
+		c = &s->chan[i];
+		c->id = Channel[i].sound_id;
+		c->priority = Channel[i].priority;
+		c->name = S_sfx[c->id].lumpname;
+		c->mo = Channel[i].mo;
+		c->distance = P_AproxDistance(c->mo->x-viewx, c->mo->y-viewy)>>FRACBITS;
+	}
+}
+
+//==========================================================================
+//
+// S_GetSoundPlayingInfo
+//
+//==========================================================================
+
+boolean S_GetSoundPlayingInfo(mobj_t *mobj, int sound_id)
+{
+	int i;
+
+	for (i = 0; i < snd_Channels; i++)
+	{
+		if (Channel[i].sound_id == sound_id && Channel[i].mo == mobj)
+		{
+			if (I_SoundIsPlaying(Channel[i].handle))
+			{
+				return true;
+			}
+		}
+	}
+	return false;
+}
+
+//==========================================================================
+//
+// S_SetMusicVolume
+//
+//==========================================================================
+
+void S_SetMusicVolume(void)
+{
+	if (i_CDMusic)
+		I_CDMusSetVolume(snd_MusicVolume*16);	// 0-255
+	I_SetMusicVolume(snd_MusicVolume);
+	if (snd_MusicVolume == 0)
+	{
+		I_PauseSong(RegisteredSong);
+		MusicPaused = true;
+	}
+	else if (MusicPaused)
+	{
+		if (!i_CDMusic || !cdaudio)
+		{
+			I_ResumeSong(RegisteredSong);
+		}
+		MusicPaused = false;
+	}
+}
+
--- /dev/null
+++ b/sb_bar.c
@@ -1,0 +1,2242 @@
+
+//**************************************************************************
+//**
+//** sb_bar.c : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 575 $
+//** $Date: 2011-04-13 22:06:28 +0300 (Wed, 13 Apr 2011) $
+//**
+//**************************************************************************
+
+// HEADER FILES ------------------------------------------------------------
+
+#include "h2stdinc.h"
+#include "h2def.h"
+#include "p_local.h"
+#include "soundst.h"
+#include "i_cdmus.h"	/* for CD track cheat */
+
+#define PLAYPAL_NUM		PlayPalette
+#include "v_compat.h"
+
+// MACROS ------------------------------------------------------------------
+
+#if defined(RENDER3D)
+#define V_DrawPatch(x,y,p)		OGL_DrawPatch((x),(y),(p))
+#define V_DrawFuzzPatch(x,y,p)		OGL_DrawFuzzPatch((x),(y),(p))
+#define V_DrawAltFuzzPatch(x,y,p)	OGL_DrawAltFuzzPatch((x),(y),(p))
+#endif	/* RENDER3D */
+
+#define CHEAT_ENCRYPT(a)		\
+		((((a) & 1  ) << 2) +	\
+		 (((a) & 2  ) >> 1) +	\
+		 (((a) & 4  ) << 5) +	\
+		 (((a) & 8  ) << 2) +	\
+		 (((a) & 16 ) >> 3) +	\
+		 (((a) & 32 ) << 1) +	\
+		 (((a) & 64 ) >> 3) +	\
+		 (((a) & 128) >> 3))
+
+// TYPES -------------------------------------------------------------------
+
+typedef struct Cheat_s
+{
+	void (*func)(player_t *player, struct Cheat_s *cheat);
+	byte *sequence;
+	byte *pos;
+	int args[2];
+	int currentArg;
+} Cheat_t;
+
+// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
+
+extern boolean P_UndoPlayerMorph(player_t *player);
+
+// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
+
+void SB_PaletteFlash(boolean forceChange);
+
+// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
+
+static void DrawSoundInfo(void);
+static void DrINumber(signed int val, int x, int y);
+static void DrRedINumber(signed int val, int x, int y);
+static void DrBNumber(signed int val, int x, int y);
+static void DrawCommonBar(void);
+static void DrawMainBar(void);
+static void DrawInventoryBar(void);
+static void DrawKeyBar(void);
+static void DrawWeaponPieces(void);
+static void DrawFullScreenStuff(void);
+static void DrawAnimatedIcons(void);
+static boolean HandleCheats(byte key);
+static boolean CheatAddKey(Cheat_t *cheat, byte key, boolean *eat);
+static void CheatGodFunc(player_t *player, Cheat_t *cheat);
+static void CheatNoClipFunc(player_t *player, Cheat_t *cheat);
+static void CheatWeaponsFunc(player_t *player, Cheat_t *cheat);
+static void CheatHealthFunc(player_t *player, Cheat_t *cheat);
+static void CheatKeysFunc(player_t *player, Cheat_t *cheat);
+static void CheatSoundFunc(player_t *player, Cheat_t *cheat);
+static void CheatTickerFunc(player_t *player, Cheat_t *cheat);
+static void CheatArtifactAllFunc(player_t *player, Cheat_t *cheat);
+static void CheatPuzzleFunc(player_t *player, Cheat_t *cheat);
+static void CheatWarpFunc(player_t *player, Cheat_t *cheat);
+static void CheatPigFunc(player_t *player, Cheat_t *cheat);
+static void CheatMassacreFunc(player_t *player, Cheat_t *cheat);
+static void CheatIDKFAFunc(player_t *player, Cheat_t *cheat);
+static void CheatQuickenFunc1(player_t *player, Cheat_t *cheat);
+static void CheatQuickenFunc2(player_t *player, Cheat_t *cheat);
+static void CheatQuickenFunc3(player_t *player, Cheat_t *cheat);
+static void CheatClassFunc1(player_t *player, Cheat_t *cheat);
+static void CheatClassFunc2(player_t *player, Cheat_t *cheat);
+static void CheatInitFunc(player_t *player, Cheat_t *cheat);
+static void CheatInitFunc(player_t *player, Cheat_t *cheat);
+static void CheatVersionFunc(player_t *player, Cheat_t *cheat);
+static void CheatDebugFunc(player_t *player, Cheat_t *cheat);
+static void CheatScriptFunc1(player_t *player, Cheat_t *cheat);
+static void CheatScriptFunc2(player_t *player, Cheat_t *cheat);
+static void CheatScriptFunc3(player_t *player, Cheat_t *cheat);
+static void CheatRevealFunc(player_t *player, Cheat_t *cheat);
+static void CheatTrackFunc1(player_t *player, Cheat_t *cheat);
+static void CheatTrackFunc2(player_t *player, Cheat_t *cheat);
+
+// EXTERNAL DATA DECLARATIONS ----------------------------------------------
+
+extern byte *screen;
+extern int ArmorIncrement[NUMCLASSES][NUMARMOR];
+extern int AutoArmorSave[NUMCLASSES];
+
+// PUBLIC DATA DECLARATIONS ------------------------------------------------
+
+boolean DebugSound;	/* Debug flag for displaying sound info */
+boolean inventory;
+int curpos;
+int inv_ptr;
+int ArtifactFlash;
+
+// PRIVATE DATA DEFINITIONS ------------------------------------------------
+
+static byte CheatLookup[256];
+static int HealthMarker;
+static player_t *CPlayer;
+static int SpinFlylump;
+static int SpinMinotaurLump;
+static int SpinSpeedLump;
+static int SpinDefenseLump;
+
+static int FontBNumBase;
+static int PlayPalette;
+
+static PATCH_REF PatchH2BAR;
+static PATCH_REF PatchH2TOP;
+static PATCH_REF PatchLFEDGE;
+static PATCH_REF PatchRTEDGE;
+static PATCH_REF PatchARMCLEAR;
+static PATCH_REF PatchARTICLEAR;
+static PATCH_REF PatchMANACLEAR;
+static PATCH_REF PatchKILLS;
+static PATCH_REF PatchMANAVIAL1;
+static PATCH_REF PatchMANAVIAL2;
+static PATCH_REF PatchMANAVIALDIM1;
+static PATCH_REF PatchMANAVIALDIM2;
+static PATCH_REF PatchMANADIM1;
+static PATCH_REF PatchMANADIM2;
+static PATCH_REF PatchMANABRIGHT1;
+static PATCH_REF PatchMANABRIGHT2;
+static PATCH_REF PatchCHAIN;
+static PATCH_REF PatchSTATBAR;
+static PATCH_REF PatchKEYBAR;
+static PATCH_REF PatchLIFEGEM;
+static PATCH_REF PatchSELECTBOX;
+static PATCH_REF PatchINumbers[10];
+static PATCH_REF PatchNEGATIVE;
+static PATCH_REF PatchSmNumbers[10];
+static PATCH_REF PatchINVBAR;
+static PATCH_REF PatchWEAPONSLOT;
+static PATCH_REF PatchWEAPONFULL;
+static PATCH_REF PatchPIECE1;
+static PATCH_REF PatchPIECE2;
+static PATCH_REF PatchPIECE3;
+static PATCH_REF PatchINVLFGEM1;
+static PATCH_REF PatchINVLFGEM2;
+static PATCH_REF PatchINVRTGEM1;
+static PATCH_REF PatchINVRTGEM2;
+
+/* Toggle god mode */
+static byte CheatGodSeq[] =
+{
+	CHEAT_ENCRYPT('s'),
+	CHEAT_ENCRYPT('a'),
+	CHEAT_ENCRYPT('t'),
+	CHEAT_ENCRYPT('a'),
+	CHEAT_ENCRYPT('n'),
+	0xff
+};
+
+/* Toggle no clipping mode */
+static byte CheatNoClipSeq[] =
+{
+	CHEAT_ENCRYPT('c'),
+	CHEAT_ENCRYPT('a'),
+	CHEAT_ENCRYPT('s'),
+	CHEAT_ENCRYPT('p'),
+	CHEAT_ENCRYPT('e'),
+	CHEAT_ENCRYPT('r'),
+	0xff
+};
+
+/* Get all weapons and mana */
+static byte CheatWeaponsSeq[] =
+{
+	CHEAT_ENCRYPT('n'),
+	CHEAT_ENCRYPT('r'),
+	CHEAT_ENCRYPT('a'),
+	0xff
+};
+
+/* Get full health */
+static byte CheatHealthSeq[] =
+{
+	CHEAT_ENCRYPT('c'),
+	CHEAT_ENCRYPT('l'),
+	CHEAT_ENCRYPT('u'),
+	CHEAT_ENCRYPT('b'),
+	CHEAT_ENCRYPT('m'),
+	CHEAT_ENCRYPT('e'),
+	CHEAT_ENCRYPT('d'),
+	0xff
+};
+
+/* Get all keys */
+static byte CheatKeysSeq[] =
+{
+	CHEAT_ENCRYPT('l'),
+	CHEAT_ENCRYPT('o'),
+	CHEAT_ENCRYPT('c'),
+	CHEAT_ENCRYPT('k'),
+	CHEAT_ENCRYPT('s'),
+	CHEAT_ENCRYPT('m'),
+	CHEAT_ENCRYPT('i'),
+	CHEAT_ENCRYPT('t'),
+	CHEAT_ENCRYPT('h'),
+	0xff, 0
+};
+
+/* Toggle sound debug info */
+static byte CheatSoundSeq[] =
+{
+	CHEAT_ENCRYPT('n'),
+	CHEAT_ENCRYPT('o'),
+	CHEAT_ENCRYPT('i'),
+	CHEAT_ENCRYPT('s'),
+	CHEAT_ENCRYPT('e'),
+	0xff
+};
+
+/* Toggle ticker */
+static byte CheatTickerSeq[] =
+{
+	CHEAT_ENCRYPT('t'),
+	CHEAT_ENCRYPT('i'),
+	CHEAT_ENCRYPT('c'),
+	CHEAT_ENCRYPT('k'),
+	CHEAT_ENCRYPT('e'),
+	CHEAT_ENCRYPT('r'),
+	0xff, 0
+};
+
+/* Get all artifacts */
+static byte CheatArtifactAllSeq[] =
+{
+	CHEAT_ENCRYPT('i'),
+	CHEAT_ENCRYPT('n'),
+	CHEAT_ENCRYPT('d'),
+	CHEAT_ENCRYPT('i'),
+	CHEAT_ENCRYPT('a'),
+	CHEAT_ENCRYPT('n'),
+	CHEAT_ENCRYPT('a'),
+	0xff, 0
+};
+
+/* Get all puzzle pieces */
+static byte CheatPuzzleSeq[] =
+{
+	CHEAT_ENCRYPT('s'),
+	CHEAT_ENCRYPT('h'),
+	CHEAT_ENCRYPT('e'),
+	CHEAT_ENCRYPT('r'),
+	CHEAT_ENCRYPT('l'),
+	CHEAT_ENCRYPT('o'),
+	CHEAT_ENCRYPT('c'),
+	CHEAT_ENCRYPT('k'),
+	0xff, 0
+};
+
+/* Warp to new level */
+static byte CheatWarpSeq[] =
+{
+	CHEAT_ENCRYPT('v'),
+	CHEAT_ENCRYPT('i'),
+	CHEAT_ENCRYPT('s'),
+	CHEAT_ENCRYPT('i'),
+	CHEAT_ENCRYPT('t'),
+	0, 0, 0xff, 0
+};
+
+/* Become a pig */
+static byte CheatPigSeq[] =
+{
+	CHEAT_ENCRYPT('d'),
+	CHEAT_ENCRYPT('e'),
+	CHEAT_ENCRYPT('l'),
+	CHEAT_ENCRYPT('i'),
+	CHEAT_ENCRYPT('v'),
+	CHEAT_ENCRYPT('e'),
+	CHEAT_ENCRYPT('r'),
+	CHEAT_ENCRYPT('a'),
+	CHEAT_ENCRYPT('n'),
+	CHEAT_ENCRYPT('c'),
+	CHEAT_ENCRYPT('e'),
+	0xff, 0
+};
+
+/* Kill all monsters */
+static byte CheatMassacreSeq[] =
+{
+	CHEAT_ENCRYPT('b'),
+	CHEAT_ENCRYPT('u'),
+	CHEAT_ENCRYPT('t'),
+	CHEAT_ENCRYPT('c'),
+	CHEAT_ENCRYPT('h'),
+	CHEAT_ENCRYPT('e'),
+	CHEAT_ENCRYPT('r'),
+	0xff, 0
+};
+
+static byte CheatIDKFASeq[] =
+{
+	CHEAT_ENCRYPT('c'),
+	CHEAT_ENCRYPT('o'),
+	CHEAT_ENCRYPT('n'),
+	CHEAT_ENCRYPT('a'),
+	CHEAT_ENCRYPT('n'),
+	0xff, 0
+};
+
+static byte CheatQuickenSeq1[] =
+{
+	CHEAT_ENCRYPT('m'),
+	CHEAT_ENCRYPT('a'),
+	CHEAT_ENCRYPT('r'),
+	CHEAT_ENCRYPT('t'),
+	CHEAT_ENCRYPT('e'),
+	CHEAT_ENCRYPT('k'),
+	0xff, 0
+};
+
+static byte CheatQuickenSeq2[] =
+{
+	CHEAT_ENCRYPT('m'),
+	CHEAT_ENCRYPT('a'),
+	CHEAT_ENCRYPT('r'),
+	CHEAT_ENCRYPT('t'),
+	CHEAT_ENCRYPT('e'),
+	CHEAT_ENCRYPT('k'),
+	CHEAT_ENCRYPT('m'),
+	CHEAT_ENCRYPT('a'),
+	CHEAT_ENCRYPT('r'),
+	CHEAT_ENCRYPT('t'),
+	CHEAT_ENCRYPT('e'),
+	CHEAT_ENCRYPT('k'),
+	0xff, 0
+};
+
+static byte CheatQuickenSeq3[] =
+{
+	CHEAT_ENCRYPT('m'),
+	CHEAT_ENCRYPT('a'),
+	CHEAT_ENCRYPT('r'),
+	CHEAT_ENCRYPT('t'),
+	CHEAT_ENCRYPT('e'),
+	CHEAT_ENCRYPT('k'),
+	CHEAT_ENCRYPT('m'),
+	CHEAT_ENCRYPT('a'),
+	CHEAT_ENCRYPT('r'),
+	CHEAT_ENCRYPT('t'),
+	CHEAT_ENCRYPT('e'),
+	CHEAT_ENCRYPT('k'),
+	CHEAT_ENCRYPT('m'),
+	CHEAT_ENCRYPT('a'),
+	CHEAT_ENCRYPT('r'),
+	CHEAT_ENCRYPT('t'),
+	CHEAT_ENCRYPT('e'),
+	CHEAT_ENCRYPT('k'),
+	0xff, 0
+};
+
+/* New class */
+static byte CheatClass1Seq[] =
+{
+	CHEAT_ENCRYPT('s'),
+	CHEAT_ENCRYPT('h'),
+	CHEAT_ENCRYPT('a'),
+	CHEAT_ENCRYPT('d'),
+	CHEAT_ENCRYPT('o'),
+	CHEAT_ENCRYPT('w'),
+	CHEAT_ENCRYPT('c'),
+	CHEAT_ENCRYPT('a'),
+	CHEAT_ENCRYPT('s'),
+	CHEAT_ENCRYPT('t'),
+	CHEAT_ENCRYPT('e'),
+	CHEAT_ENCRYPT('r'),
+	0xff, 0
+};
+
+static byte CheatClass2Seq[] =
+{
+	CHEAT_ENCRYPT('s'),
+	CHEAT_ENCRYPT('h'),
+	CHEAT_ENCRYPT('a'),
+	CHEAT_ENCRYPT('d'),
+	CHEAT_ENCRYPT('o'),
+	CHEAT_ENCRYPT('w'),
+	CHEAT_ENCRYPT('c'),
+	CHEAT_ENCRYPT('a'),
+	CHEAT_ENCRYPT('s'),
+	CHEAT_ENCRYPT('t'),
+	CHEAT_ENCRYPT('e'),
+	CHEAT_ENCRYPT('r'),
+	0, 0xff, 0
+};
+
+static byte CheatInitSeq[] =
+{
+	CHEAT_ENCRYPT('i'),
+	CHEAT_ENCRYPT('n'),
+	CHEAT_ENCRYPT('i'),
+	CHEAT_ENCRYPT('t'),
+	0xff, 0
+};
+
+static byte CheatVersionSeq[] =
+{
+	CHEAT_ENCRYPT('m'),
+	CHEAT_ENCRYPT('r'),
+	CHEAT_ENCRYPT('j'),
+	CHEAT_ENCRYPT('o'),
+	CHEAT_ENCRYPT('n'),
+	CHEAT_ENCRYPT('e'),
+	CHEAT_ENCRYPT('s'),
+	0xff, 0
+};
+
+static byte CheatDebugSeq[] =
+{
+	CHEAT_ENCRYPT('w'),
+	CHEAT_ENCRYPT('h'),
+	CHEAT_ENCRYPT('e'),
+	CHEAT_ENCRYPT('r'),
+	CHEAT_ENCRYPT('e'),
+	0xff, 0
+};
+
+static byte CheatScriptSeq1[] =
+{
+	CHEAT_ENCRYPT('p'),
+	CHEAT_ENCRYPT('u'),
+	CHEAT_ENCRYPT('k'),
+	CHEAT_ENCRYPT('e'),
+	0xff, 0
+};
+
+static byte CheatScriptSeq2[] =
+{
+	CHEAT_ENCRYPT('p'),
+	CHEAT_ENCRYPT('u'),
+	CHEAT_ENCRYPT('k'),
+	CHEAT_ENCRYPT('e'),
+	0, 0xff, 0
+};
+
+static byte CheatScriptSeq3[] =
+{
+	CHEAT_ENCRYPT('p'),
+	CHEAT_ENCRYPT('u'),
+	CHEAT_ENCRYPT('k'),
+	CHEAT_ENCRYPT('e'),
+	0, 0, 0xff,
+};
+
+static byte CheatRevealSeq[] =
+{
+	CHEAT_ENCRYPT('m'),
+	CHEAT_ENCRYPT('a'),
+	CHEAT_ENCRYPT('p'),
+	CHEAT_ENCRYPT('s'),
+	CHEAT_ENCRYPT('c'),
+	CHEAT_ENCRYPT('o'),
+	0xff, 0
+};
+
+static byte CheatTrackSeq1[] = 
+{
+	CHEAT_ENCRYPT('`'),
+	0xff, 0
+};
+
+static byte CheatTrackSeq2[] =
+{
+	CHEAT_ENCRYPT('`'),
+	0, 0, 0xff, 0
+};
+
+static Cheat_t Cheats[] =
+{
+	{ CheatTrackFunc1, CheatTrackSeq1, NULL, {0, 0}, 0 },
+	{ CheatTrackFunc2, CheatTrackSeq2, NULL, {0, 0}, 0 },
+	{ CheatGodFunc, CheatGodSeq, NULL, {0, 0}, 0 },
+	{ CheatNoClipFunc, CheatNoClipSeq, NULL, {0, 0}, 0 },
+	{ CheatWeaponsFunc, CheatWeaponsSeq, NULL, {0, 0}, 0 },
+	{ CheatHealthFunc, CheatHealthSeq, NULL, {0, 0}, 0 },
+	{ CheatKeysFunc, CheatKeysSeq, NULL, {0, 0}, 0 },
+	{ CheatSoundFunc, CheatSoundSeq, NULL, {0, 0}, 0 },
+	{ CheatTickerFunc, CheatTickerSeq, NULL, {0, 0}, 0 },
+	{ CheatArtifactAllFunc, CheatArtifactAllSeq, NULL, {0, 0}, 0 },
+	{ CheatPuzzleFunc, CheatPuzzleSeq, NULL, {0, 0}, 0 },
+	{ CheatWarpFunc, CheatWarpSeq, NULL, {0, 0}, 0 },
+	{ CheatPigFunc, CheatPigSeq, NULL, {0, 0}, 0 },
+	{ CheatMassacreFunc, CheatMassacreSeq, NULL, {0, 0}, 0 },
+	{ CheatIDKFAFunc, CheatIDKFASeq, NULL, {0, 0}, 0 },
+	{ CheatQuickenFunc1, CheatQuickenSeq1, NULL, {0, 0}, 0 },
+	{ CheatQuickenFunc2, CheatQuickenSeq2, NULL, {0, 0}, 0 },
+	{ CheatQuickenFunc3, CheatQuickenSeq3, NULL, {0, 0}, 0 },
+	{ CheatClassFunc1, CheatClass1Seq, NULL, {0, 0}, 0 },
+	{ CheatClassFunc2, CheatClass2Seq, NULL, {0, 0}, 0 },
+	{ CheatInitFunc, CheatInitSeq, NULL, {0, 0}, 0 },
+	{ CheatVersionFunc, CheatVersionSeq, NULL, {0, 0}, 0 },
+	{ CheatDebugFunc, CheatDebugSeq, NULL, {0, 0}, 0 },
+	{ CheatScriptFunc1, CheatScriptSeq1, NULL, {0, 0}, 0 },
+	{ CheatScriptFunc2, CheatScriptSeq2, NULL, {0, 0}, 0 },
+	{ CheatScriptFunc3, CheatScriptSeq3, NULL, {0, 0}, 0 },
+	{ CheatRevealFunc, CheatRevealSeq, NULL, {0, 0}, 0 },
+	{ NULL, NULL, NULL, {0, 0}, 0 }	/* Terminator */
+};
+
+// CODE --------------------------------------------------------------------
+
+//==========================================================================
+//
+// SB_Init
+//
+//==========================================================================
+
+void SB_Init(void)
+{
+	int i;
+	int startLump;
+
+	PatchH2BAR	= (PATCH_REF) WR_CacheLumpName("H2BAR", PU_STATIC);
+	PatchH2TOP	= (PATCH_REF) WR_CacheLumpName("H2TOP", PU_STATIC);
+	PatchINVBAR	= (PATCH_REF) WR_CacheLumpName("INVBAR", PU_STATIC);
+	PatchLFEDGE	= (PATCH_REF) WR_CacheLumpName("LFEDGE", PU_STATIC);
+	PatchRTEDGE	= (PATCH_REF) WR_CacheLumpName("RTEDGE", PU_STATIC);
+	PatchSTATBAR	= (PATCH_REF) WR_CacheLumpName("STATBAR", PU_STATIC);
+	PatchKEYBAR	= (PATCH_REF) WR_CacheLumpName("KEYBAR", PU_STATIC);
+	PatchSELECTBOX	= (PATCH_REF) WR_CacheLumpName("SELECTBOX", PU_STATIC);
+	PatchARTICLEAR	= (PATCH_REF) WR_CacheLumpName("ARTICLS", PU_STATIC);
+	PatchARMCLEAR	= (PATCH_REF) WR_CacheLumpName("ARMCLS", PU_STATIC);
+	PatchMANACLEAR	= (PATCH_REF) WR_CacheLumpName("MANACLS", PU_STATIC);
+	PatchMANAVIAL1	= (PATCH_REF) WR_CacheLumpName("MANAVL1", PU_STATIC);
+	PatchMANAVIAL2	= (PATCH_REF) WR_CacheLumpName("MANAVL2", PU_STATIC);
+	PatchMANAVIALDIM1 = (PATCH_REF) WR_CacheLumpName("MANAVL1D", PU_STATIC);
+	PatchMANAVIALDIM2 = (PATCH_REF) WR_CacheLumpName("MANAVL2D", PU_STATIC);
+	PatchMANADIM1	= (PATCH_REF) WR_CacheLumpName("MANADIM1", PU_STATIC);
+	PatchMANADIM2	= (PATCH_REF) WR_CacheLumpName("MANADIM2", PU_STATIC);
+	PatchMANABRIGHT1 = (PATCH_REF) WR_CacheLumpName("MANABRT1", PU_STATIC);
+	PatchMANABRIGHT2 = (PATCH_REF) WR_CacheLumpName("MANABRT2", PU_STATIC);
+	PatchINVLFGEM1	= (PATCH_REF) WR_CacheLumpName("invgeml1", PU_STATIC);
+	PatchINVLFGEM2	= (PATCH_REF) WR_CacheLumpName("invgeml2", PU_STATIC);
+	PatchINVRTGEM1	= (PATCH_REF) WR_CacheLumpName("invgemr1", PU_STATIC);
+	PatchINVRTGEM2	= (PATCH_REF) WR_CacheLumpName("invgemr2", PU_STATIC);
+
+	startLump = W_GetNumForName("IN0");
+	for (i = 0; i < 10; i++)
+	{
+		PatchINumbers[i] = (PATCH_REF) WR_CacheLumpNum(startLump + i, PU_STATIC);
+	}
+	PatchNEGATIVE = (PATCH_REF) WR_CacheLumpName("NEGNUM", PU_STATIC);
+	FontBNumBase = W_GetNumForName("FONTB16");
+	startLump = W_GetNumForName("SMALLIN0");
+	for (i = 0; i < 10; i++)
+	{
+		PatchSmNumbers[i] = (PATCH_REF) WR_CacheLumpNum(startLump + i, PU_STATIC);
+	}
+	PlayPalette = W_GetNumForName("PLAYPAL");
+	SpinFlylump = W_GetNumForName("SPFLY0");
+	SpinMinotaurLump = W_GetNumForName("SPMINO0");
+	SpinSpeedLump = W_GetNumForName("SPBOOT0");
+	SpinDefenseLump = W_GetNumForName("SPSHLD0");
+
+	for (i = 0; i < 256; i++)
+	{
+		CheatLookup[i] = CHEAT_ENCRYPT(i);
+	}
+
+	if (deathmatch)
+	{
+		PatchKILLS = (PATCH_REF) WR_CacheLumpName("KILLS", PU_STATIC);
+	}
+	SB_SetClassData();
+}
+
+//==========================================================================
+//
+// SB_SetClassData
+//
+//==========================================================================
+
+void SB_SetClassData(void)
+{
+	int pClass;
+	int max_players;
+
+	pClass = PlayerClasses[consoleplayer];	// original player class (not pig)
+#ifdef ASSASSIN
+	if (pClass == PCLASS_ASS)
+		pClass = PCLASS_FIGHTER;	// Use FIghter chain and gem for now
+#endif
+
+	max_players = ((MAXPLAYERS > MAXPLAYERS_10) && oldwad_10) ? MAXPLAYERS_10 : MAXPLAYERS;
+
+	PatchWEAPONSLOT = (PATCH_REF) WR_CacheLumpNum(W_GetNumForName("wpslot0") + pClass, PU_STATIC);
+	PatchWEAPONFULL = (PATCH_REF) WR_CacheLumpNum(W_GetNumForName("wpfull0") + pClass, PU_STATIC);
+	PatchPIECE1	= (PATCH_REF) WR_CacheLumpNum(W_GetNumForName("wpiecef1")+ pClass, PU_STATIC);
+	PatchPIECE2	= (PATCH_REF) WR_CacheLumpNum(W_GetNumForName("wpiecef2")+ pClass, PU_STATIC);
+	PatchPIECE3	= (PATCH_REF) WR_CacheLumpNum(W_GetNumForName("wpiecef3")+ pClass, PU_STATIC);
+	PatchCHAIN	= (PATCH_REF) WR_CacheLumpNum(W_GetNumForName("chain")   + pClass, PU_STATIC);
+
+	if (!netgame)
+	{ // single player game uses red life gem (the second gem)
+	  PatchLIFEGEM = (PATCH_REF) WR_CacheLumpNum(W_GetNumForName("lifegem") + max_players*pClass + 1, PU_STATIC);
+	}
+	else
+	{
+	  PatchLIFEGEM = (PATCH_REF) WR_CacheLumpNum(W_GetNumForName("lifegem") + max_players*pClass + consoleplayer, PU_STATIC);
+	}
+	SB_state = -1;
+	UpdateState |= I_FULLSCRN;
+}
+
+//==========================================================================
+//
+// SB_Ticker
+//
+//==========================================================================
+
+void SB_Ticker(void)
+{
+	int delta;
+	int curHealth;
+
+	curHealth = players[consoleplayer].mo->health;
+	if (curHealth < 0)
+	{
+		curHealth = 0;
+	}
+	if (curHealth < HealthMarker)
+	{
+		delta = (HealthMarker - curHealth)>>2;
+		if (delta < 1)
+		{
+			delta = 1;
+		}
+		else if (delta > 6)
+		{
+			delta = 6;
+		}
+		HealthMarker -= delta;
+	}
+	else if (curHealth > HealthMarker)
+	{
+		delta = (curHealth - HealthMarker)>>2;
+		if (delta < 1)
+		{
+			delta = 1;
+		}
+		else if (delta > 6)
+		{
+			delta = 6;
+		}
+		HealthMarker += delta;
+	}
+}
+
+//==========================================================================
+//
+// DrINumber
+//
+// Draws a three digit number.
+//
+//==========================================================================
+
+static void DrINumber(signed int val, int x, int y)
+{
+	PATCH_REF patch;
+	int oldval;
+
+	oldval = val;
+	if (val < 0)
+	{
+		val = -val;
+		if (val > 99)
+		{
+			val = 99;
+		}
+		if (val > 9)
+		{
+			patch = PatchINumbers[val/10];
+			V_DrawPatch(x + 8, y, patch);
+			V_DrawPatch(x, y, PatchNEGATIVE);
+		}
+		else
+		{
+			V_DrawPatch(x + 8, y, PatchNEGATIVE);
+		}
+		val = val % 10;
+		patch = PatchINumbers[val];
+		V_DrawPatch(x + 16, y, patch);
+		return;
+	}
+	if (val > 99)
+	{
+		patch = PatchINumbers[val/100];
+		V_DrawPatch(x, y, patch);
+	}
+	val = val % 100;
+	if (val > 9 || oldval > 99)
+	{
+		patch = PatchINumbers[val/10];
+		V_DrawPatch(x + 8, y, patch);
+	}
+	val = val % 10;
+	patch = PatchINumbers[val];
+	V_DrawPatch(x + 16, y, patch);
+}
+
+//==========================================================================
+//
+// DrRedINumber
+//
+// Draws a three digit number using the red font
+//
+//==========================================================================
+
+static void DrRedINumber(signed int val, int x, int y)
+{
+	PATCH_REF patch;
+	int oldval;
+
+	oldval = val;
+	if (val < 0)
+	{
+		val = 0;
+	}
+	if (val > 99)
+	{
+		patch = (PATCH_REF) WR_CacheLumpNum(W_GetNumForName("inred0") + val/100, PU_CACHE);
+		V_DrawPatch(x, y, patch);
+	}
+	val = val % 100;
+	if (val > 9 || oldval > 99)
+	{
+		patch = (PATCH_REF) WR_CacheLumpNum(W_GetNumForName("inred0") + val/10, PU_CACHE);
+		V_DrawPatch(x + 8, y, patch);
+	}
+	val = val % 10;
+	patch = (PATCH_REF) WR_CacheLumpNum(W_GetNumForName("inred0") + val, PU_CACHE);
+	V_DrawPatch(x + 16, y, patch);
+}
+
+//==========================================================================
+//
+// DrBNumber
+//
+// Draws a three digit number using FontB
+//
+//==========================================================================
+
+static void DrBNumber(signed int val, int x, int y)
+{
+	patch_t* patch;
+	int xpos;
+	int oldval;
+	int width;
+
+	oldval = val;
+	xpos = x;
+	if (val < 0)
+	{
+		val = 0;
+	}
+	if (val > 99)
+	{
+		patch = (patch_t *) W_CacheLumpNum(FontBNumBase + val/100, PU_CACHE);
+		width = SHORT(patch->width) / 2;
+#ifdef RENDER3D
+		OGL_DrawShadowedPatch(xpos + 6 - width, y, FontBNumBase + val/100);
+#else
+		V_DrawShadowedPatch(xpos + 6 - width, y, patch);
+#endif
+	}
+	val = val % 100;
+	xpos += 12;
+	if (val > 9 || oldval > 99)
+	{
+		patch = (patch_t *) W_CacheLumpNum(FontBNumBase + val/10, PU_CACHE);
+		width = SHORT(patch->width) / 2;
+#ifdef RENDER3D
+		OGL_DrawShadowedPatch(xpos + 6 - width, y, FontBNumBase + val/10);
+#else
+		V_DrawShadowedPatch(xpos + 6 - width, y, patch);
+#endif
+	}
+	val = val % 10;
+	xpos += 12;
+	patch = (patch_t *) W_CacheLumpNum(FontBNumBase + val, PU_CACHE);
+	width = SHORT(patch->width) / 2;
+#ifdef RENDER3D
+	OGL_DrawShadowedPatch(xpos + 6 - width, y, FontBNumBase + val/1);
+#else
+	V_DrawShadowedPatch(xpos + 6 - width, y, patch);
+#endif
+}
+
+//==========================================================================
+//
+// DrSmallNumber
+//
+// Draws a small two digit number.
+//
+//==========================================================================
+
+static void DrSmallNumber(int val, int x, int y)
+{
+	PATCH_REF patch;
+
+	if (val <= 0)
+	{
+		return;
+	}
+	if (val > 999)
+	{
+		val %= 1000;
+	}
+	if (val > 99)
+	{
+		patch = PatchSmNumbers[val/100];
+		V_DrawPatch(x, y, patch);
+		patch = PatchSmNumbers[(val % 100) / 10];
+		V_DrawPatch(x + 4, y, patch);
+	}
+	else if (val > 9)
+	{
+		patch = PatchSmNumbers[val/10];
+		V_DrawPatch(x + 4, y, patch);
+	}
+	val %= 10;
+	patch = PatchSmNumbers[val];
+	V_DrawPatch(x + 8, y, patch);
+}
+
+//==========================================================================
+//
+// DrawSoundInfo
+//
+// Displays sound debugging information.
+//
+//==========================================================================
+
+static void DrawSoundInfo(void)
+{
+	int i;
+	SoundInfo_t s;
+	ChanInfo_t *c;
+	char text[32];
+	int x;
+	int y;
+	int xPos[7] = {1, 75, 112, 156, 200, 230, 260};
+
+	if (leveltime & 16)
+	{
+		MN_DrTextA("*** SOUND DEBUG INFO ***", xPos[0], 20);
+	}
+	S_GetChannelInfo(&s);
+	if (s.channelCount == 0)
+	{
+		return;
+	}
+	x = 0;
+	MN_DrTextA("NAME", xPos[x++], 30);
+	MN_DrTextA("MO.T", xPos[x++], 30);
+	MN_DrTextA("MO.X", xPos[x++], 30);
+	MN_DrTextA("MO.Y", xPos[x++], 30);
+	MN_DrTextA("ID", xPos[x++], 30);
+	MN_DrTextA("PRI", xPos[x++], 30);
+	MN_DrTextA("DIST", xPos[x++], 30);
+	for (i = 0; i < s.channelCount; i++)
+	{
+		c = &s.chan[i];
+		x = 0;
+		y = 40 + i*10;
+		if (c->mo == NULL)
+		{ // Channel is unused
+			MN_DrTextA("------", xPos[0], y);
+			continue;
+		}
+		snprintf(text, sizeof(text), "%s", c->name);
+		M_ForceUppercase(text);
+		MN_DrTextA(text, xPos[x++], y);
+		snprintf(text, sizeof(text), "%d", c->mo->type);
+		MN_DrTextA(text, xPos[x++], y);
+		snprintf(text, sizeof(text), "%d", c->mo->x>>FRACBITS);
+		MN_DrTextA(text, xPos[x++], y);
+		snprintf(text, sizeof(text), "%d", c->mo->y>>FRACBITS);
+		MN_DrTextA(text, xPos[x++], y);
+		snprintf(text, sizeof(text), "%d", c->id);
+		MN_DrTextA(text, xPos[x++], y);
+		snprintf(text, sizeof(text), "%d", c->priority);
+		MN_DrTextA(text, xPos[x++], y);
+		snprintf(text, sizeof(text), "%d", c->distance);
+		MN_DrTextA(text, xPos[x++], y);
+	}
+	UpdateState |= I_FULLSCRN;
+	BorderNeedRefresh = true;
+}
+
+//==========================================================================
+//
+// SB_Drawer
+//
+//==========================================================================
+
+static const char patcharti[][10] =
+{
+	{ "ARTIBOX" },		/* none			*/
+	{ "ARTIINVU" },		/* invulnerability	*/
+	{ "ARTIPTN2" },		/* health		*/
+	{ "ARTISPHL" },		/* superhealth		*/
+	{ "ARTIHRAD" },		/* healing radius	*/
+	{ "ARTISUMN" },		/* summon maulator	*/
+	{ "ARTITRCH" },		/* torch		*/
+	{ "ARTIPORK" },		/* egg			*/
+	{ "ARTISOAR" },		/* fly			*/
+	{ "ARTIBLST" },		/* blast radius		*/
+	{ "ARTIPSBG" },		/* poison bag		*/
+	{ "ARTITELO" },		/* teleport other	*/
+	{ "ARTISPED" },		/* speed		*/
+	{ "ARTIBMAN" },		/* boost mana		*/
+	{ "ARTIBRAC" },		/* boost armor		*/
+	{ "ARTIATLP" },		/* teleport		*/
+	{ "ARTISKLL" },		/* arti_puzzskull	*/
+	{ "ARTIBGEM" },		/* arti_puzzgembig	*/
+	{ "ARTIGEMR" },		/* arti_puzzgemred	*/
+	{ "ARTIGEMG" },		/* arti_puzzgemgreen1	*/
+	{ "ARTIGMG2" },		/* arti_puzzgemgreen2	*/
+	{ "ARTIGEMB" },		/* arti_puzzgemblue1	*/
+	{ "ARTIGMB2" },		/* arti_puzzgemblue2	*/
+	{ "ARTIBOK1" },		/* arti_puzzbook1	*/
+	{ "ARTIBOK2" },		/* arti_puzzbook2	*/
+	{ "ARTISKL2" },		/* arti_puzzskull2	*/
+	{ "ARTIFWEP" },		/* arti_puzzfweapon	*/
+	{ "ARTICWEP" },		/* arti_puzzcweapon	*/
+	{ "ARTIMWEP" },		/* arti_puzzmweapon	*/
+	{ "ARTIGEAR" },		/* arti_puzzgear1	*/
+	{ "ARTIGER2" },		/* arti_puzzgear2	*/
+	{ "ARTIGER3" },		/* arti_puzzgear3	*/
+	{ "ARTIGER4" },		/* arti_puzzgear4	*/
+};
+
+int SB_state = -1;
+#ifndef RENDER3D
+static int oldfrags = -9999;
+static int oldmana1 = -1;
+static int oldmana2 = -1;
+static int oldhealth = -1;
+static int oldlife = -1;
+static int oldpieces = -1;
+static int oldweapon = -1;
+#endif
+static int oldarti = 0;
+static int oldartiCount = 0;
+static int oldkeys = -1;
+static int oldarmor = -1;
+
+void SB_Drawer(void)
+{
+	// Sound info debug stuff
+	if (DebugSound == true)
+	{
+		DrawSoundInfo();
+	}
+	CPlayer = &players[consoleplayer];
+	if (viewheight == SCREENHEIGHT && !automapactive)
+	{
+		DrawFullScreenStuff();
+		SB_state = -1;
+	}
+	else
+	{
+#ifndef RENDER3D
+		if (SB_state == -1)
+		{
+#endif
+			V_DrawPatch(0, 134, PatchH2BAR);
+#ifndef RENDER3D
+			oldhealth = -1;
+		}
+#endif
+		DrawCommonBar();
+
+		if (!inventory)
+		{
+#ifndef RENDER3D
+			if (SB_state != 0)
+			{
+#endif
+				// Main interface
+				if (!automapactive)
+				{
+					V_DrawPatch(38, 162, PatchSTATBAR);
+				}
+				else
+				{
+					V_DrawPatch(38, 162, PatchKEYBAR);
+				}
+#ifndef RENDER3D
+				oldarti = 0;
+				oldmana1 = -1;
+				oldmana2 = -1;
+				oldarmor = -1;
+				oldpieces = -1;
+				oldfrags = -9999; //can't use -1, 'cuz of negative frags
+				oldlife = -1;
+				oldweapon = -1;
+				oldkeys = -1;
+			}
+#endif
+			if (!automapactive)
+			{
+				DrawMainBar();
+			}
+			else
+			{
+				DrawKeyBar();
+			}
+			SB_state = 0;
+		}
+		else
+		{
+			DrawInventoryBar();
+			SB_state = 1;
+		}
+	}
+	SB_PaletteFlash(false);
+	DrawAnimatedIcons();
+}
+
+//==========================================================================
+//
+// DrawAnimatedIcons
+//
+//==========================================================================
+
+static void DrawAnimatedIcons(void)
+{
+	int frame;
+	static boolean hitCenterFrame;
+
+	// Wings of wrath
+	if (CPlayer->powers[pw_flight])
+	{
+		if (CPlayer->powers[pw_flight] > BLINKTHRESHOLD
+			|| !(CPlayer->powers[pw_flight] & 16))
+		{
+			frame = (leveltime / 3) & 15;
+			if (CPlayer->mo->flags2 & MF2_FLY)
+			{
+				if (hitCenterFrame && (frame != 15 && frame != 0))
+				{
+					V_DrawPatch(20, 19, (PATCH_REF)WR_CacheLumpNum(SpinFlylump + 15, PU_CACHE));
+				}
+				else
+				{
+					V_DrawPatch(20, 19, (PATCH_REF)WR_CacheLumpNum(SpinFlylump + frame, PU_CACHE));
+					hitCenterFrame = false;
+				}
+			}
+			else
+			{
+				if (!hitCenterFrame && (frame != 15 && frame != 0))
+				{
+					V_DrawPatch(20, 19, (PATCH_REF)WR_CacheLumpNum(SpinFlylump + frame, PU_CACHE));
+					hitCenterFrame = false;
+				}
+				else
+				{
+					V_DrawPatch(20, 19, (PATCH_REF)WR_CacheLumpNum(SpinFlylump + 15, PU_CACHE));
+					hitCenterFrame = true;
+				}
+			}
+		}
+		BorderTopRefresh = true;
+		UpdateState |= I_MESSAGES;
+	}
+
+	// Speed Boots
+	if (CPlayer->powers[pw_speed])
+	{
+		if (CPlayer->powers[pw_speed] > BLINKTHRESHOLD
+			|| !(CPlayer->powers[pw_speed] & 16))
+		{
+			frame = (leveltime / 3) & 15;
+			V_DrawPatch(60, 19, (PATCH_REF)WR_CacheLumpNum(SpinSpeedLump + frame, PU_CACHE));
+		}
+		BorderTopRefresh = true;
+		UpdateState |= I_MESSAGES;
+	}
+
+	// Defensive power
+	if (CPlayer->powers[pw_invulnerability])
+	{
+		if (CPlayer->powers[pw_invulnerability] > BLINKTHRESHOLD
+			|| !(CPlayer->powers[pw_invulnerability] & 16))
+		{
+			frame = (leveltime / 3) & 15;
+			V_DrawPatch(260, 19, (PATCH_REF)WR_CacheLumpNum(SpinDefenseLump + frame, PU_CACHE));
+		}
+		BorderTopRefresh = true;
+		UpdateState |= I_MESSAGES;
+	}
+
+	// Minotaur Active
+	if (CPlayer->powers[pw_minotaur])
+	{
+		if (CPlayer->powers[pw_minotaur] > BLINKTHRESHOLD
+			|| !(CPlayer->powers[pw_minotaur] & 16))
+		{
+			frame = (leveltime / 3) & 15;
+			V_DrawPatch(300, 19, (PATCH_REF)WR_CacheLumpNum(SpinMinotaurLump + frame, PU_CACHE));
+		}
+		BorderTopRefresh = true;
+		UpdateState |= I_MESSAGES;
+	}
+}
+
+//==========================================================================
+//
+// SB_PaletteFlash
+//
+// Sets the new palette based upon the current values of
+// consoleplayer->damagecount and consoleplayer->bonuscount.
+//
+//==========================================================================
+
+void SB_PaletteFlash(boolean forceChange)
+{
+	static int sb_palette = 0;
+	int palette;
+
+	if (forceChange)
+	{
+		sb_palette = -1;
+	}
+	if (gamestate == GS_LEVEL)
+	{
+		CPlayer = &players[consoleplayer];
+		if (CPlayer->poisoncount)
+		{
+			palette = 0;
+			palette = (CPlayer->poisoncount + 7)>>3;
+			if (palette >= NUMPOISONPALS)
+			{
+				palette = NUMPOISONPALS - 1;
+			}
+			palette += STARTPOISONPALS;
+		}
+		else if (CPlayer->damagecount)
+		{
+			palette = (CPlayer->damagecount + 7)>>3;
+			if (palette >= NUMREDPALS)
+			{
+				palette = NUMREDPALS - 1;
+			}
+			palette += STARTREDPALS;
+		}
+		else if (CPlayer->bonuscount)
+		{
+			palette = (CPlayer->bonuscount + 7)>>3;
+			if (palette >= NUMBONUSPALS)
+			{
+				palette = NUMBONUSPALS - 1;
+			}
+			palette += STARTBONUSPALS;
+		}
+		else if (CPlayer->mo->flags2 & MF2_ICEDAMAGE)
+		{ // Frozen player
+			palette = STARTICEPAL;
+		}
+		else
+		{
+			palette = 0;
+		}
+	}
+	else
+	{
+		palette = 0;
+	}
+	if (palette != sb_palette)
+	{
+		sb_palette = palette;
+		V_SetPaletteShift(palette);
+	}
+}
+
+//==========================================================================
+//
+// DrawCommonBar
+//
+//==========================================================================
+
+void DrawCommonBar(void)
+{
+	int healthPos;
+
+#ifndef RENDER3D
+	V_DrawPatch(0, 134, PatchH2TOP);
+
+	if (oldhealth != HealthMarker)
+	{
+		oldhealth = HealthMarker;
+#endif
+		healthPos = HealthMarker;
+		if (healthPos < 0)
+		{
+			healthPos = 0;
+		}
+		if (healthPos > 100)
+		{
+			healthPos = 100;
+		}
+		V_DrawPatch(28 + (((healthPos * 196) / 100) % 9), 193, PatchCHAIN);
+		V_DrawPatch( 7 + ((healthPos * 11) / 5), 193, PatchLIFEGEM);
+		V_DrawPatch(0, 193, PatchLFEDGE);
+		V_DrawPatch(277, 193, PatchRTEDGE);
+#ifndef RENDER3D
+		UpdateState |= I_STATBAR;
+	}
+#endif
+}
+
+//==========================================================================
+//
+// DrawMainBar
+//
+//==========================================================================
+
+void DrawMainBar(void)
+{
+	PATCH_REF manaPatch1		= INVALID_PATCH;
+	PATCH_REF manaPatch2		= INVALID_PATCH;
+	PATCH_REF manaVialPatch1	= INVALID_PATCH;
+	PATCH_REF manaVialPatch2	= INVALID_PATCH;
+	int				i, temp;
+
+	// Ready artifact
+	if (ArtifactFlash)
+	{
+#ifndef RENDER3D
+		V_DrawPatch(144, 160, PatchARTICLEAR);
+#endif
+		V_DrawPatch(148, 164, (PATCH_REF)WR_CacheLumpNum(W_GetNumForName("useartia") + ArtifactFlash - 1, PU_CACHE));
+		ArtifactFlash--;
+		oldarti = -1;	/* so that the correct artifact fills in after the flash */
+		UpdateState |= I_STATBAR;
+	}
+	else if (oldarti != CPlayer->readyArtifact ||
+		 oldartiCount != CPlayer->inventory[inv_ptr].count)
+	{
+#ifndef RENDER3D
+		V_DrawPatch(144, 160, PatchARTICLEAR);
+#endif
+		if (CPlayer->readyArtifact > 0)
+		{
+			V_DrawPatch(143, 163, (PATCH_REF)WR_CacheLumpName(patcharti[CPlayer->readyArtifact], PU_CACHE));
+			if (CPlayer->inventory[inv_ptr].count > 1)
+			{
+				DrSmallNumber(CPlayer->inventory[inv_ptr].count, 162, 184);
+			}
+		}
+#ifndef RENDER3D
+		oldarti = CPlayer->readyArtifact;
+		oldartiCount = CPlayer->inventory[inv_ptr].count;
+		UpdateState |= I_STATBAR;
+#endif
+	}
+
+	// Frags
+	if (deathmatch)
+	{
+		temp = 0;
+		for (i = 0; i < MAXPLAYERS; i++)
+		{
+			temp += CPlayer->frags[i];
+		}
+#ifndef RENDER3D
+		if (temp != oldfrags)
+		{
+#endif
+			V_DrawPatch(38, 162, PatchKILLS);
+			DrINumber(temp, 40, 176);
+#ifndef RENDER3D
+			oldfrags = temp;
+			UpdateState |= I_STATBAR;
+		}
+#endif
+	}
+	else
+	{
+		temp = HealthMarker;
+		if (temp < 0)
+		{
+			temp = 0;
+		}
+		else if (temp > 100)
+		{
+			temp = 100;
+		}
+#ifndef RENDER3D
+		if (oldlife != temp)
+		{
+			oldlife = temp;
+#endif
+			V_DrawPatch(41, 178, PatchARMCLEAR);
+			if (temp >= 25)
+			{
+				DrINumber(temp, 40, 176);
+			}
+			else
+			{
+				DrRedINumber(temp, 40, 176);
+			}
+#ifndef RENDER3D
+			UpdateState |= I_STATBAR;
+		}
+#endif
+	}
+	// Mana
+	temp = CPlayer->mana[0];
+#ifndef RENDER3D
+	if (oldmana1 != temp)
+	{
+#endif
+		V_DrawPatch(77, 178, PatchMANACLEAR);
+		DrSmallNumber(temp, 79, 181);
+#ifndef RENDER3D
+		manaVialPatch1 = (patch_t *)1; // force a vial update
+#endif
+		if (temp == 0)
+		{ // Draw Dim Mana icon
+			manaPatch1 = PatchMANADIM1;
+		}
+#ifndef RENDER3D
+		else if (oldmana1 == 0)
+		{
+			manaPatch1 = PatchMANABRIGHT1;
+		}
+		oldmana1 = temp;
+		UpdateState |= I_STATBAR;
+	}
+#endif
+	temp = CPlayer->mana[1];
+#ifndef RENDER3D
+	if (oldmana2 != temp)
+	{
+#endif
+		V_DrawPatch(109, 178, PatchMANACLEAR);
+		DrSmallNumber(temp, 111, 181);
+#ifndef RENDER3D
+		manaVialPatch1 = (patch_t *)1; // force a vial update
+#endif
+		if (temp == 0)
+		{ // Draw Dim Mana icon
+			manaPatch2 = PatchMANADIM2;
+		}
+#ifndef RENDER3D
+		else if (oldmana2 == 0)
+		{
+			manaPatch2 = PatchMANABRIGHT2;
+		}
+		oldmana2 = temp;
+		UpdateState |= I_STATBAR;
+	}
+#endif
+#ifndef RENDER3D
+	if (oldweapon != CPlayer->readyweapon || manaPatch1 || manaPatch2
+		|| manaVialPatch1)
+	{ // Update mana graphics based upon mana count/weapon type
+#endif
+		if (CPlayer->readyweapon == WP_FIRST)
+		{
+			manaPatch1 = PatchMANADIM1;
+			manaPatch2 = PatchMANADIM2;
+			manaVialPatch1 = PatchMANAVIALDIM1;
+			manaVialPatch2 = PatchMANAVIALDIM2;
+		}
+		else if (CPlayer->readyweapon == WP_SECOND)
+		{
+			if (!manaPatch1)
+			{
+				manaPatch1 = PatchMANABRIGHT1;
+			}
+			manaVialPatch1 = PatchMANAVIAL1;
+			manaPatch2 = PatchMANADIM2;
+			manaVialPatch2 = PatchMANAVIALDIM2;
+		}
+		else if (CPlayer->readyweapon == WP_THIRD)
+		{
+			manaPatch1 = PatchMANADIM1;
+			manaVialPatch1 = PatchMANAVIALDIM1;
+			if (!manaPatch2)
+			{
+				manaPatch2 = PatchMANABRIGHT2;
+			}
+			manaVialPatch2 = PatchMANAVIAL2;
+		}
+		else
+		{
+			manaVialPatch1 = PatchMANAVIAL1;
+			manaVialPatch2 = PatchMANAVIAL2;
+			if (!manaPatch1)
+			{
+				manaPatch1 = PatchMANABRIGHT1;
+			}
+			if (!manaPatch2)
+			{
+				manaPatch2 = PatchMANABRIGHT2;
+			}
+		}
+		V_DrawPatch(77, 164, manaPatch1);
+		V_DrawPatch(110, 164, manaPatch2);
+		V_DrawPatch(94, 164, manaVialPatch1);
+#ifndef RENDER3D
+		for (i = 165; i < 187 - (22*CPlayer->mana[0]) / MAX_MANA; i++)
+		{
+			screen[i*SCREENWIDTH+95] = 0;
+			screen[i*SCREENWIDTH+96] = 0;
+			screen[i*SCREENWIDTH+97] = 0;
+		}
+#endif
+		V_DrawPatch(102, 164, manaVialPatch2);
+#ifndef RENDER3D
+		for (i = 165; i < 187-(22*CPlayer->mana[1])/MAX_MANA; i++)
+		{
+			screen[i*SCREENWIDTH+103] = 0;
+			screen[i*SCREENWIDTH+104] = 0;
+			screen[i*SCREENWIDTH+105] = 0;
+		}
+		oldweapon = CPlayer->readyweapon;
+		UpdateState |= I_STATBAR;
+	}
+#endif
+
+	// Armor
+	temp = AutoArmorSave[CPlayer->playerclass]
+		+ CPlayer->armorpoints[ARMOR_ARMOR] + CPlayer->armorpoints[ARMOR_SHIELD]
+		+ CPlayer->armorpoints[ARMOR_HELMET]+ CPlayer->armorpoints[ARMOR_AMULET];
+#ifndef RENDER3D
+	if (oldarmor != temp)
+	{
+		oldarmor = temp;
+#endif
+		V_DrawPatch(255, 178, PatchARMCLEAR);
+		DrINumber(FixedDiv(temp, 5*FRACUNIT)>>FRACBITS, 250, 176);
+#ifndef RENDER3D
+		UpdateState |= I_STATBAR;
+	}
+#endif
+
+	// Weapon Pieces
+#ifndef RENDER3D
+	if (oldpieces != CPlayer->pieces)
+	{
+#endif
+		DrawWeaponPieces();
+#ifndef RENDER3D
+		oldpieces = CPlayer->pieces;
+		UpdateState |= I_STATBAR;
+	}
+#endif
+}
+
+//==========================================================================
+//
+// DrawInventoryBar
+//
+//==========================================================================
+
+void DrawInventoryBar(void)
+{
+	int i;
+	int x;
+
+	x = inv_ptr - curpos;
+	UpdateState |= I_STATBAR;
+	V_DrawPatch(38, 162, PatchINVBAR);
+	for (i = 0; i < 7; i++)
+	{
+	//	V_DrawPatch(50 + i*31, 160, (PATCH_REF)WR_CacheLumpName("ARTIBOX", PU_CACHE));
+		if (CPlayer->inventorySlotNum > x + i
+			&& CPlayer->inventory[x + i].type != arti_none)
+		{
+			V_DrawPatch(50 + i*31, 163, (PATCH_REF)WR_CacheLumpName(patcharti[CPlayer->inventory[x + i].type], PU_CACHE));
+			if (CPlayer->inventory[x + i].count > 1)
+			{
+				DrSmallNumber(CPlayer->inventory[x + i].count, 68 + i*31, 185);
+			}
+		}
+	}
+	V_DrawPatch(50 + curpos*31, 163, PatchSELECTBOX);
+	if (x != 0)
+	{
+		V_DrawPatch(42, 163, !(leveltime & 4) ? PatchINVLFGEM1 : PatchINVLFGEM2);
+	}
+	if (CPlayer->inventorySlotNum - x > 7)
+	{
+		V_DrawPatch(269, 163, !(leveltime & 4) ? PatchINVRTGEM1 : PatchINVRTGEM2);
+	}
+}
+
+//==========================================================================
+//
+// DrawKeyBar
+//
+//==========================================================================
+
+void DrawKeyBar(void)
+{
+	int i;
+	int xPosition;
+#ifdef RENDER3D
+	int temp;
+
+	if (oldkeys != CPlayer->keys)
+	{
+#endif
+		xPosition = 46;
+		for (i = 0; i < NUMKEYS && xPosition <= 126; i++)
+		{
+			if (CPlayer->keys & (1 << i))
+			{
+				V_DrawPatch(xPosition, 164, (PATCH_REF)WR_CacheLumpNum(W_GetNumForName("keyslot1") + i, PU_CACHE));
+				xPosition += 20;
+			}
+		}
+#ifdef RENDER3D
+		oldkeys = CPlayer->keys;
+		UpdateState |= I_STATBAR;
+	}
+	temp = AutoArmorSave[CPlayer->playerclass]
+		+ CPlayer->armorpoints[ARMOR_ARMOR] + CPlayer->armorpoints[ARMOR_SHIELD]
+		+ CPlayer->armorpoints[ARMOR_HELMET]+ CPlayer->armorpoints[ARMOR_AMULET];
+	if (oldarmor != temp)
+	{
+#endif
+		for (i = 0; i < NUMARMOR; i++)
+		{
+			if (!CPlayer->armorpoints[i])
+			{
+				continue;
+			}
+			if (CPlayer->armorpoints[i] <= (ArmorIncrement[CPlayer->playerclass][i]>>2))
+			{
+				V_DrawFuzzPatch(150 + 31*i, 164, (PATCH_REF)WR_CacheLumpNum(W_GetNumForName("armslot1") + i, PU_CACHE));
+			}
+			else if (CPlayer->armorpoints[i] <= (ArmorIncrement[CPlayer->playerclass][i]>>1))
+			{
+				V_DrawAltFuzzPatch(150 + 31*i, 164, (PATCH_REF)WR_CacheLumpNum(W_GetNumForName("armslot1") + i, PU_CACHE));
+			}
+			else
+			{
+				V_DrawPatch(150 + 31*i, 164, (PATCH_REF)WR_CacheLumpNum(W_GetNumForName("armslot1") + i, PU_CACHE));
+			}
+		}
+#ifdef RENDER3D
+		oldarmor = temp;
+		UpdateState |= I_STATBAR;
+	}
+#endif
+}
+
+//==========================================================================
+//
+// DrawWeaponPieces
+//
+//==========================================================================
+
+static int PieceX[NUMCLASSES][3] =
+{
+	{ 190, 225, 234 },
+	{ 190, 212, 225 },
+	{ 190, 205, 224 },
+#ifdef ASSASSIN
+	{ 190, 205, 224 },	/* Use mage xpositions for now */
+#endif
+	{ 0, 0, 0 }		/* Pig is never used */
+};
+
+static void DrawWeaponPieces(void)
+{
+	if (CPlayer->pieces == 7)
+	{
+		V_DrawPatch(190, 162, PatchWEAPONFULL);
+		return;
+	}
+	V_DrawPatch(190, 162, PatchWEAPONSLOT);
+	if (CPlayer->pieces & WPIECE1)
+	{
+		V_DrawPatch(PieceX[PlayerClasses[consoleplayer]][0], 162, PatchPIECE1);
+	}
+	if (CPlayer->pieces & WPIECE2)
+	{
+		V_DrawPatch(PieceX[PlayerClasses[consoleplayer]][1], 162, PatchPIECE2);
+	}
+	if (CPlayer->pieces & WPIECE3)
+	{
+		V_DrawPatch(PieceX[PlayerClasses[consoleplayer]][2], 162, PatchPIECE3);
+	}
+}
+
+//==========================================================================
+//
+// DrawFullScreenStuff
+//
+//==========================================================================
+
+void DrawFullScreenStuff(void)
+{
+	int i;
+	int x;
+	int temp;
+
+	UpdateState |= I_FULLSCRN;
+	if (CPlayer->mo->health > 0)
+	{
+		DrBNumber(CPlayer->mo->health, 5, 180);
+	}
+	else
+	{
+		DrBNumber(0, 5, 180);
+	}
+	if (deathmatch)
+	{
+		temp = 0;
+		for (i = 0; i < MAXPLAYERS; i++)
+		{
+			if (playeringame[i])
+			{
+				temp += CPlayer->frags[i];
+			}
+		}
+		DrINumber(temp, 45, 185);
+	}
+	if (!inventory)
+	{
+		if (CPlayer->readyArtifact > 0)
+		{
+			V_DrawFuzzPatch(286, 170, (PATCH_REF)WR_CacheLumpName("ARTIBOX", PU_CACHE));
+			V_DrawPatch(284, 169, (PATCH_REF)WR_CacheLumpName(patcharti[CPlayer->readyArtifact], PU_CACHE));
+			if (CPlayer->inventory[inv_ptr].count > 1)
+			{
+				DrSmallNumber(CPlayer->inventory[inv_ptr].count, 302, 192);
+			}
+		}
+	}
+	else
+	{
+		x = inv_ptr - curpos;
+		for (i = 0; i < 7; i++)
+		{
+			V_DrawFuzzPatch(50 + i*31, 168, (PATCH_REF)WR_CacheLumpName("ARTIBOX", PU_CACHE));
+			if (CPlayer->inventorySlotNum > x + i
+				&& CPlayer->inventory[x + i].type != arti_none)
+			{
+				V_DrawPatch(49 + i*31, 167, (PATCH_REF)WR_CacheLumpName(patcharti[CPlayer->inventory[x + i].type], PU_CACHE));
+				if (CPlayer->inventory[x + i].count > 1)
+				{
+					DrSmallNumber(CPlayer->inventory[x + i].count, 66 + i*31, 188);
+				}
+			}
+		}
+		V_DrawPatch(50 + curpos*31, 167, PatchSELECTBOX);
+		if (x != 0)
+		{
+			V_DrawPatch(40, 167, !(leveltime & 4) ? PatchINVLFGEM1 : PatchINVLFGEM2);
+		}
+		if (CPlayer->inventorySlotNum - x > 7)
+		{
+			V_DrawPatch(268, 167, !(leveltime & 4) ? PatchINVRTGEM1 : PatchINVRTGEM2);
+		}
+	}
+}
+
+
+//==========================================================================
+//
+// Draw_TeleportIcon
+//
+//==========================================================================
+void Draw_TeleportIcon(void)
+{
+	PATCH_REF patch;
+	patch = (PATCH_REF) WR_CacheLumpNum(W_GetNumForName("teleicon"), PU_CACHE);
+	V_DrawPatch(100, 68, patch);
+	UpdateState |= I_FULLSCRN;
+	I_Update();
+	UpdateState |= I_FULLSCRN;
+}
+
+//==========================================================================
+//
+// Draw_SaveIcon
+//
+//==========================================================================
+
+void Draw_SaveIcon(void)
+{
+	PATCH_REF patch;
+	patch = (PATCH_REF) WR_CacheLumpNum(W_GetNumForName("saveicon"), PU_CACHE);
+	V_DrawPatch(100, 68, patch);
+	UpdateState |= I_FULLSCRN;
+	I_Update();
+	UpdateState |= I_FULLSCRN;
+}
+
+//==========================================================================
+//
+// Draw_LoadIcon
+//
+//==========================================================================
+
+void Draw_LoadIcon(void)
+{
+	PATCH_REF patch;
+	patch = (PATCH_REF) WR_CacheLumpNum(W_GetNumForName("loadicon"), PU_CACHE);
+	V_DrawPatch(100, 68, patch);
+	UpdateState |= I_FULLSCRN;
+	I_Update();
+	UpdateState |= I_FULLSCRN;
+}
+
+
+//==========================================================================
+//
+// SB_Responder
+//
+//==========================================================================
+
+boolean SB_Responder(event_t *event)
+{
+	if (event->type == ev_keydown)
+	{
+		if (HandleCheats(event->data1))
+		{ // Need to eat the key
+			return true;
+		}
+	}
+	return false;
+}
+
+//==========================================================================
+//
+// HandleCheats
+//
+// Returns true if the caller should eat the key.
+//
+//==========================================================================
+
+static boolean HandleCheats(byte key)
+{
+	int i;
+	boolean eat;
+
+	if (gameskill == sk_nightmare)
+	{ // Can't cheat in nightmare mode
+		return false;
+	}
+	else if (netgame)
+	{ // change CD track is the only cheat available in deathmatch
+		eat = false;
+		if (i_CDMusic && cdaudio)
+		{
+			if (CheatAddKey(&Cheats[0], key, &eat))
+			{
+				Cheats[0].func(&players[consoleplayer], &Cheats[0]);
+				S_StartSound(NULL, SFX_PLATFORM_STOP);
+			}
+			if (CheatAddKey(&Cheats[1], key, &eat))
+			{
+				Cheats[1].func(&players[consoleplayer], &Cheats[1]);
+				S_StartSound(NULL, SFX_PLATFORM_STOP);
+			}
+		}
+		return eat;
+	}
+	if (players[consoleplayer].health <= 0)
+	{ // Dead players can't cheat
+		return false;
+	}
+	eat = false;
+	for (i = 0; Cheats[i].func != NULL; i++)
+	{
+		if (CheatAddKey(&Cheats[i], key, &eat))
+		{
+			Cheats[i].func(&players[consoleplayer], &Cheats[i]);
+			S_StartSound(NULL, SFX_PLATFORM_STOP);
+		}
+	}
+	return eat;
+}
+
+//==========================================================================
+//
+// CheatAddkey
+//
+// Returns true if the added key completed the cheat, false otherwise.
+//
+//==========================================================================
+
+static boolean CheatAddKey(Cheat_t *cheat, byte key, boolean *eat)
+{
+	if (!cheat->pos)
+	{
+		cheat->pos = cheat->sequence;
+		cheat->currentArg = 0;
+	}
+	if (*cheat->pos == 0)
+	{
+		*eat = true;
+		cheat->args[cheat->currentArg++] = key;
+		cheat->pos++;
+	}
+	else if (CheatLookup[key] == *cheat->pos)
+	{
+		cheat->pos++;
+	}
+	else
+	{
+		cheat->pos = cheat->sequence;
+		cheat->currentArg = 0;
+	}
+	if (*cheat->pos == 0xff)
+	{
+		cheat->pos = cheat->sequence;
+		cheat->currentArg = 0;
+		return true;
+	}
+	return false;
+}
+
+//==========================================================================
+//
+// CHEAT FUNCTIONS
+//
+//==========================================================================
+
+static void CheatGodFunc(player_t *player, Cheat_t *cheat)
+{
+	player->cheats ^= CF_GODMODE;
+	if (player->cheats & CF_GODMODE)
+	{
+		P_SetMessage(player, TXT_CHEATGODON, true);
+	}
+	else
+	{
+		P_SetMessage(player, TXT_CHEATGODOFF, true);
+	}
+	SB_state = -1;
+}
+
+static void CheatNoClipFunc(player_t *player, Cheat_t *cheat)
+{
+	player->cheats ^= CF_NOCLIP;
+	if (player->cheats & CF_NOCLIP)
+	{
+		P_SetMessage(player, TXT_CHEATNOCLIPON, true);
+	}
+	else
+	{
+		P_SetMessage(player, TXT_CHEATNOCLIPOFF, true);
+	}
+}
+
+static void CheatWeaponsFunc(player_t *player, Cheat_t *cheat)
+{
+	int i;
+	//extern boolean *WeaponInShareware;
+
+	for (i = 0; i < NUMARMOR; i++)
+	{
+		player->armorpoints[i] = ArmorIncrement[player->playerclass][i];
+	}
+	for (i = 0; i < NUMWEAPONS; i++)
+	{
+		player->weaponowned[i] = true;
+	}
+	for (i = 0; i < NUMMANA; i++)
+	{
+		player->mana[i] = MAX_MANA;
+	}
+	P_SetMessage(player, TXT_CHEATWEAPONS, true);
+}
+
+static void CheatHealthFunc(player_t *player, Cheat_t *cheat)
+{
+	if (player->morphTics)
+	{
+		player->health = player->mo->health = MAXMORPHHEALTH;
+	}
+	else
+	{
+		player->health = player->mo->health = MAXHEALTH;
+	}
+	P_SetMessage(player, TXT_CHEATHEALTH, true);
+}
+
+static void CheatKeysFunc(player_t *player, Cheat_t *cheat)
+{
+	player->keys = 2047;
+	P_SetMessage(player, TXT_CHEATKEYS, true);
+}
+
+static void CheatSoundFunc(player_t *player, Cheat_t *cheat)
+{
+	DebugSound = !DebugSound;
+	if (DebugSound)
+	{
+		P_SetMessage(player, TXT_CHEATSOUNDON, true);
+	}
+	else
+	{
+		P_SetMessage(player, TXT_CHEATSOUNDOFF, true);
+	}
+}
+
+static void CheatTickerFunc(player_t *player, Cheat_t *cheat)
+{
+	extern int DisplayTicker;
+
+	DisplayTicker = !DisplayTicker;
+	if (DisplayTicker)
+	{
+		P_SetMessage(player, TXT_CHEATTICKERON, true);
+	}
+	else
+	{
+		P_SetMessage(player, TXT_CHEATTICKEROFF, true);
+	}
+}
+
+static void CheatArtifactAllFunc(player_t *player, Cheat_t *cheat)
+{
+	int i;
+	int j;
+
+	for (i = arti_none + 1; i < arti_firstpuzzitem; i++)
+	{
+		for (j = 0; j < 25; j++)
+		{
+			P_GiveArtifact(player, i, NULL);
+		}
+	}
+	P_SetMessage(player, TXT_CHEATARTIFACTS3, true);
+}
+
+static void CheatPuzzleFunc(player_t *player, Cheat_t *cheat)
+{
+	int i;
+
+	for (i = arti_firstpuzzitem; i < NUMARTIFACTS; i++)
+	{
+		P_GiveArtifact(player, i, NULL);
+	}
+	P_SetMessage(player, TXT_CHEATARTIFACTS3, true);
+}
+
+static void CheatInitFunc(player_t *player, Cheat_t *cheat)
+{
+	G_DeferedInitNew(gameskill, gameepisode, gamemap);
+	P_SetMessage(player, TXT_CHEATWARP, true);
+}
+
+static void CheatWarpFunc(player_t *player, Cheat_t *cheat)
+{
+	int tens;
+	int ones;
+	int map;
+	char mapName[9];
+	char auxName[MAX_OSPATH];
+	FILE *fp;
+
+	tens = cheat->args[0] - '0';
+	ones = cheat->args[1] - '0';
+	if (tens < 0 || tens > 9 || ones < 0 || ones > 9)
+	{ // Bad map
+		P_SetMessage(player, TXT_CHEATBADINPUT, true);
+		return;
+	}
+	map = P_TranslateMap((cheat->args[0] - '0')*10 + cheat->args[1] - '0');
+	if (map == -1)
+	{ // Not found
+		P_SetMessage(player, TXT_CHEATNOMAP, true);
+		return;
+	}
+	if (map == gamemap)
+	{ // Don't try to teleport to current map
+		P_SetMessage(player, TXT_CHEATBADINPUT, true);
+		return;
+	}
+	if (DevMaps)
+	{ // Search map development directory
+		snprintf(auxName, sizeof(auxName), "%smap%02d.wad", DevMapsDir, map);
+		fp = fopen(auxName, "rb");
+		if (fp)
+		{
+			fclose(fp);
+		}
+		else
+		{ // Can't find
+			P_SetMessage(player, TXT_CHEATNOMAP, true);
+			return;
+		}
+	}
+	else
+	{ // Search primary lumps
+		snprintf(mapName, sizeof(mapName), "MAP%02d", map);
+		if (W_CheckNumForName(mapName) == -1)
+		{ // Can't find
+			P_SetMessage(player, TXT_CHEATNOMAP, true);
+			return;
+		}
+	}
+	P_SetMessage(player, TXT_CHEATWARP, true);
+	G_TeleportNewMap(map, 0);
+}
+
+static void CheatPigFunc(player_t *player, Cheat_t *cheat)
+{
+	if (player->morphTics)
+	{
+		P_UndoPlayerMorph(player);
+	}
+	else
+	{
+		P_MorphPlayer(player);
+	}
+	P_SetMessage(player, "SQUEAL!!", true);
+}
+
+static void CheatMassacreFunc(player_t *player, Cheat_t *cheat)
+{
+	int count;
+	char buffer[80];
+
+	count = P_Massacre();
+	snprintf(buffer, sizeof(buffer), "%d MONSTERS KILLED\n", count);
+	P_SetMessage(player, buffer, true);
+}
+
+static void CheatIDKFAFunc(player_t *player, Cheat_t *cheat)
+{
+	int i;
+	if (player->morphTics)
+	{
+		return;
+	}
+	for (i = 1; i < NUMWEAPONS; i++)
+	{
+		player->weaponowned[i] = false;
+	}
+	player->pendingweapon = WP_FIRST;
+	P_SetMessage(player, TXT_CHEATIDKFA, true);
+}
+
+static void CheatQuickenFunc1(player_t *player, Cheat_t *cheat)
+{
+	P_SetMessage(player, "TRYING TO CHEAT?  THAT'S ONE....", true);
+}
+
+static void CheatQuickenFunc2(player_t *player, Cheat_t *cheat)
+{
+	P_SetMessage(player, "THAT'S TWO....", true);
+}
+
+static void CheatQuickenFunc3(player_t *player, Cheat_t *cheat)
+{
+	P_DamageMobj(player->mo, NULL, player->mo, 10000);
+	P_SetMessage(player, "THAT'S THREE!  TIME TO DIE.", true);
+}
+
+static void CheatClassFunc1(player_t *player, Cheat_t *cheat)
+{
+/* P_SetMessage isn't variably arg'ed: set the messages by hand: */
+#ifdef ASSASSIN
+	P_SetMessage(player, "ENTER NEW PLAYER CLASS (0 - 3)", true);
+#else
+	P_SetMessage(player, "ENTER NEW PLAYER CLASS (0 - 2)", true);
+#endif
+}
+
+static void CheatClassFunc2(player_t *player, Cheat_t *cheat)
+{
+	int i;
+	int pClass;
+
+	if (player->morphTics)
+	{ // don't change class if the player is morphed
+		return;
+	}
+	pClass = cheat->args[0] - '0';
+	if (pClass > NUMCLASSES_HUMAN - 1 || pClass < 0)
+	{
+		P_SetMessage(player, "INVALID PLAYER CLASS", true);
+		return;
+	}
+	player->playerclass = pClass;
+	for (i = 0; i < NUMARMOR; i++)
+	{
+		player->armorpoints[i] = 0;
+	}
+	PlayerClasses[consoleplayer] = pClass;
+	P_PostMorphWeapon(player, WP_FIRST);
+	SB_SetClassData();
+	SB_state = -1;
+	UpdateState |= I_FULLSCRN;
+}
+
+static void CheatVersionFunc(player_t *player, Cheat_t *cheat)
+{
+	P_SetMessage(player, VERSIONTEXT, true);
+}
+
+static void CheatDebugFunc(player_t *player, Cheat_t *cheat)
+{
+	char textBuffer[50];
+	snprintf(textBuffer, sizeof(textBuffer), "MAP %d (%d)  X:%5d  Y:%5d  Z:%5d",
+				P_GetMapWarpTrans(gamemap),
+				gamemap,
+				player->mo->x >> FRACBITS,
+				player->mo->y >> FRACBITS,
+				player->mo->z >> FRACBITS);
+	P_SetMessage(player, textBuffer, true);
+}
+
+static void CheatScriptFunc1(player_t *player, Cheat_t *cheat)
+{
+	P_SetMessage(player, "RUN WHICH SCRIPT(01-99)?", true);
+}
+
+static void CheatScriptFunc2(player_t *player, Cheat_t *cheat)
+{
+	P_SetMessage(player, "RUN WHICH SCRIPT(01-99)?", true);
+}
+
+static void CheatScriptFunc3(player_t *player, Cheat_t *cheat)
+{
+	int script;
+	byte args[3];
+	int tens, ones;
+	char textBuffer[40];
+
+	tens = cheat->args[0] - '0';
+	ones = cheat->args[1] - '0';
+	script = tens*10 + ones;
+	if (script < 1)
+		return;
+	if (script > 99)
+		return;
+	args[0] = args[1] = args[2] = 0;
+
+	if (P_StartACS(script, 0, args, player->mo, NULL, 0))
+	{
+		snprintf(textBuffer, sizeof(textBuffer), "RUNNING SCRIPT %.2d", script);
+		P_SetMessage(player, textBuffer, true);
+	}
+}
+
+extern int cheating;
+
+static void CheatRevealFunc(player_t *player, Cheat_t *cheat)
+{
+	cheating = (cheating + 1) % 3;
+}
+
+//===========================================================================
+//
+// CheatTrackFunc1
+//
+//===========================================================================
+
+static void CheatTrackFunc1(player_t *player, Cheat_t *cheat)
+{
+	char buffer[80];
+
+	if (!i_CDMusic || !cdaudio)
+	{
+		return;
+	}
+	snprintf(buffer, sizeof(buffer), "ENTER DESIRED CD TRACK (%.2d - %.2d):\n",
+					  I_CDMusFirstTrack(), I_CDMusLastTrack());
+	P_SetMessage(player, buffer, true);
+}
+
+//===========================================================================
+//
+// CheatTrackFunc2
+//
+//===========================================================================
+
+static void CheatTrackFunc2(player_t *player, Cheat_t *cheat)
+{
+	char buffer[80];
+	int track;
+
+	if (!i_CDMusic || !cdaudio)
+	{
+		return;
+	}
+	track = (cheat->args[0] - '0') * 10 + (cheat->args[1] - '0');
+	if (track < I_CDMusFirstTrack() || track > I_CDMusLastTrack())
+	{
+		P_SetMessage(player, "INVALID TRACK NUMBER\n", true);
+		return;
+	}
+	if (track == i_CDCurrentTrack)
+	{
+		return;
+	}
+	if (I_CDMusPlay(track))
+	{
+		snprintf(buffer, sizeof(buffer), "ERROR WHILE TRYING TO PLAY CD TRACK: %.2d\n", track);
+		P_SetMessage(player, buffer, true);
+	}
+	else
+	{ // No error encountered while attempting to play the track
+		snprintf(buffer, sizeof(buffer), "PLAYING TRACK: %.2d\n", track);
+		P_SetMessage(player, buffer, true);
+	//	i_CDMusicLength = 35*I_CDMusTrackLength(track);
+	//	oldTic = gametic;
+		i_CDTrack = track;
+		i_CDCurrentTrack = track;
+	}
+}
+
--- /dev/null
+++ b/sc_man.c
@@ -1,0 +1,482 @@
+
+//**************************************************************************
+//**
+//** sc_man.c : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 373 $
+//** $Date: 2009-05-19 21:14:28 +0300 (Tue, 19 May 2009) $
+//**
+//**************************************************************************
+
+// HEADER FILES ------------------------------------------------------------
+
+#include "h2stdinc.h"
+#include "h2def.h"
+
+// MACROS ------------------------------------------------------------------
+
+#define MAX_STRING_SIZE		64
+#define ASCII_COMMENT		(';')
+#define ASCII_QUOTE		(34)
+#define LUMP_SCRIPT		1
+#define FILE_ZONE_SCRIPT	2
+#define FILE_CLIB_SCRIPT	3
+
+// TYPES -------------------------------------------------------------------
+
+// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
+
+// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
+
+// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
+
+static void CheckOpen(void);
+static void OpenScript(const char *name, int type);
+
+// EXTERNAL DATA DECLARATIONS ----------------------------------------------
+
+// PUBLIC DATA DEFINITIONS -------------------------------------------------
+
+char *sc_String;
+int sc_Number;
+int sc_Line;
+boolean sc_End;
+boolean sc_Crossed;
+boolean sc_FileScripts = false;
+const char *sc_ScriptsDir = "";	// "scripts/";
+
+// PRIVATE DATA DEFINITIONS ------------------------------------------------
+
+static char ScriptName[16];
+static void *ScriptBuffer;
+static char *ScriptPtr;
+static char *ScriptEndPtr;
+static char StringBuffer[MAX_STRING_SIZE];
+static boolean ScriptOpen = false;
+static boolean ScriptFreeCLib; // true = de-allocate using free()
+static int ScriptSize;
+static boolean AlreadyGot = false;
+
+// CODE --------------------------------------------------------------------
+
+//==========================================================================
+//
+// SC_Open
+//
+//==========================================================================
+
+void SC_Open(const char *name)
+{
+	char fileName[MAX_OSPATH];
+
+	if (sc_FileScripts == true)
+	{
+		sprintf(fileName, "%s%s.txt", sc_ScriptsDir, name);
+		SC_OpenFile(fileName);
+	}
+	else
+	{
+		SC_OpenLump(name);
+	}
+}
+
+//==========================================================================
+//
+// SC_OpenLump
+//
+// Loads a script (from the WAD files) and prepares it for parsing.
+//
+//==========================================================================
+
+void SC_OpenLump(const char *name)
+{
+	OpenScript(name, LUMP_SCRIPT);
+}
+
+//==========================================================================
+//
+// SC_OpenFile
+//
+// Loads a script (from a file) and prepares it for parsing.  Uses the
+// zone memory allocator for memory allocation and de-allocation.
+//
+//==========================================================================
+
+void SC_OpenFile(const char *name)
+{
+	OpenScript(name, FILE_ZONE_SCRIPT);
+}
+
+//==========================================================================
+//
+// SC_OpenFileCLib
+//
+// Loads a script (from a file) and prepares it for parsing.  Uses C
+// library function calls for memory allocation and de-allocation.
+//
+//==========================================================================
+
+void SC_OpenFileCLib(const char *name)
+{
+	OpenScript(name, FILE_CLIB_SCRIPT);
+}
+
+//==========================================================================
+//
+// OpenScript
+//
+//==========================================================================
+
+static void OpenScript(const char *name, int type)
+{
+	SC_Close();
+	if (type == LUMP_SCRIPT)
+	{ // Lump script
+		ScriptBuffer = W_CacheLumpName(name, PU_STATIC);
+		ScriptSize = W_LumpLength(W_GetNumForName(name));
+		strcpy(ScriptName, name);
+		ScriptFreeCLib = false; // De-allocate using Z_Free()
+	}
+	else if (type == FILE_ZONE_SCRIPT)
+	{ // File script - zone
+		ScriptSize = M_ReadFile(name, &ScriptBuffer);
+		M_ExtractFileBase(name, ScriptName);
+		ScriptFreeCLib = false; // De-allocate using Z_Free()
+	}
+	else
+	{ // File script - clib
+		ScriptSize = M_ReadFileCLib(name, &ScriptBuffer);
+		M_ExtractFileBase(name, ScriptName);
+		ScriptFreeCLib = true; // De-allocate using free()
+	}
+	ScriptPtr = (char *) ScriptBuffer;
+	ScriptEndPtr = ScriptPtr+ScriptSize;
+	sc_Line = 1;
+	sc_End = false;
+	ScriptOpen = true;
+	sc_String = StringBuffer;
+	AlreadyGot = false;
+}
+
+//==========================================================================
+//
+// SC_Close
+//
+//==========================================================================
+
+void SC_Close(void)
+{
+	if (ScriptOpen)
+	{
+		if (ScriptFreeCLib == true)
+		{
+			free(ScriptBuffer);
+		}
+		else
+		{
+			Z_Free(ScriptBuffer);
+		}
+		ScriptOpen = false;
+	}
+}
+
+//==========================================================================
+//
+// SC_GetString
+//
+//==========================================================================
+
+boolean SC_GetString(void)
+{
+	char *text;
+	boolean foundToken;
+
+	CheckOpen();
+	if (AlreadyGot)
+	{
+		AlreadyGot = false;
+		return true;
+	}
+	foundToken = false;
+	sc_Crossed = false;
+	if (ScriptPtr >= ScriptEndPtr)
+	{
+		sc_End = true;
+		return false;
+	}
+	while (foundToken == false)
+	{
+		while (*ScriptPtr <= 32)
+		{
+			if (ScriptPtr >= ScriptEndPtr)
+			{
+				sc_End = true;
+				return false;
+			}
+			if (*ScriptPtr++ == '\n')
+			{
+				sc_Line++;
+				sc_Crossed = true;
+			}
+		}
+		if (ScriptPtr >= ScriptEndPtr)
+		{
+			sc_End = true;
+			return false;
+		}
+		if (*ScriptPtr != ASCII_COMMENT)
+		{ // Found a token
+			foundToken = true;
+		}
+		else
+		{ // Skip comment
+			while (*ScriptPtr++ != '\n')
+			{
+				if (ScriptPtr >= ScriptEndPtr)
+				{
+					sc_End = true;
+					return false;
+				}
+			}
+			sc_Line++;
+			sc_Crossed = true;
+		}
+	}
+	text = sc_String;
+	if (*ScriptPtr == ASCII_QUOTE)
+	{ // Quoted string
+		ScriptPtr++;
+		while (*ScriptPtr != ASCII_QUOTE)
+		{
+			*text++ = *ScriptPtr++;
+			if (ScriptPtr == ScriptEndPtr
+				|| text == &sc_String[MAX_STRING_SIZE-1])
+			{
+				break;
+			}
+		}
+		ScriptPtr++;
+	}
+	else
+	{ // Normal string
+		while ((*ScriptPtr > 32) && (*ScriptPtr != ASCII_COMMENT))
+		{
+			*text++ = *ScriptPtr++;
+			if (ScriptPtr == ScriptEndPtr
+				|| text == &sc_String[MAX_STRING_SIZE-1])
+			{
+				break;
+			}
+		}
+	}
+	*text = 0;
+	return true;
+}
+
+//==========================================================================
+//
+// SC_MustGetString
+//
+//==========================================================================
+
+void SC_MustGetString(void)
+{
+	if (SC_GetString() == false)
+	{
+		SC_ScriptError("Missing string.");
+	}
+}
+
+//==========================================================================
+//
+// SC_MustGetStringName
+//
+//==========================================================================
+
+void SC_MustGetStringName(const char *name)
+{
+	SC_MustGetString();
+	if (SC_Compare(name) == false)
+	{
+		SC_ScriptError(NULL);
+	}
+}
+
+//==========================================================================
+//
+// SC_GetNumber
+//
+//==========================================================================
+
+boolean SC_GetNumber(void)
+{
+	char *stopper;
+
+	CheckOpen();
+	if (SC_GetString())
+	{
+		sc_Number = strtol(sc_String, &stopper, 0);
+		if (*stopper != 0)
+		{
+			I_Error("SC_GetNumber: Bad numeric constant \"%s\".\n"
+				"Script %s, Line %d", sc_String, ScriptName, sc_Line);
+		}
+		return true;
+	}
+	else
+	{
+		return false;
+	}
+}
+
+//==========================================================================
+//
+// SC_MustGetNumber
+//
+//==========================================================================
+
+void SC_MustGetNumber(void)
+{
+	if (SC_GetNumber() == false)
+	{
+		SC_ScriptError("Missing integer.");
+	}
+}
+
+//==========================================================================
+//
+// SC_UnGet
+//
+// Assumes there is a valid string in sc_String.
+//
+//==========================================================================
+
+void SC_UnGet(void)
+{
+	AlreadyGot = true;
+}
+
+//==========================================================================
+//
+// SC_Check
+//
+// Returns true if another token is on the current line.
+//
+//==========================================================================
+
+/*
+boolean SC_Check(void)
+{
+	char *text;
+
+	CheckOpen();
+	text = ScriptPtr;
+	if (text >= ScriptEndPtr)
+	{
+		return false;
+	}
+	while (*text <= 32)
+	{
+		if (*text == '\n')
+		{
+			return false;
+		}
+		text++;
+		if (text == ScriptEndPtr)
+		{
+			return false;
+		}
+	}
+	if (*text == ASCII_COMMENT)
+	{
+		return false;
+	}
+	return true;
+}
+*/
+
+//==========================================================================
+//
+// SC_MatchString
+//
+// Returns the index of the first match to sc_String from the passed
+// array of strings, or -1 if not found.
+//
+//==========================================================================
+
+int SC_MatchString(const char **strings)
+{
+	int i;
+
+	for (i = 0; *strings != NULL; i++)
+	{
+		if (SC_Compare(*strings++))
+		{
+			return i;
+		}
+	}
+	return -1;
+}
+
+//==========================================================================
+//
+// SC_MustMatchString
+//
+//==========================================================================
+
+int SC_MustMatchString(const char **strings)
+{
+	int i;
+
+	i = SC_MatchString(strings);
+	if (i == -1)
+	{
+		SC_ScriptError(NULL);
+	}
+	return i;
+}
+
+//==========================================================================
+//
+// SC_Compare
+//
+//==========================================================================
+
+boolean SC_Compare(const char *text)
+{
+	if (strcasecmp(text, sc_String) == 0)
+	{
+		return true;
+	}
+	return false;
+}
+
+//==========================================================================
+//
+// SC_ScriptError
+//
+//==========================================================================
+
+void SC_ScriptError(const char *message)
+{
+	if (message == NULL)
+	{
+		message = "Bad syntax.";
+	}
+	I_Error("Script error, \"%s\" line %d: %s", ScriptName, sc_Line, message);
+}
+
+//==========================================================================
+//
+// CheckOpen
+//
+//==========================================================================
+
+static void CheckOpen(void)
+{
+	if (ScriptOpen == false)
+	{
+		I_Error("SC_ call before SC_Open().");
+	}
+}
+
--- /dev/null
+++ b/sn_sonix.c
@@ -1,0 +1,502 @@
+
+//**************************************************************************
+//**
+//** sn_sonix.c : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 373 $
+//** $Date: 2009-05-19 21:14:28 +0300 (Tue, 19 May 2009) $
+//**
+//**************************************************************************
+
+// HEADER FILES ------------------------------------------------------------
+
+#include "h2stdinc.h"
+#include "h2def.h"
+#include "soundst.h"
+
+// MACROS ------------------------------------------------------------------
+
+#define SS_MAX_SCRIPTS		64
+#define SS_TEMPBUFFER_SIZE	1024
+#define SS_SEQUENCE_NAME_LENGTH	32
+
+#define SS_SCRIPT_NAME		"SNDSEQ"
+#define SS_STRING_PLAY		"play"
+#define SS_STRING_PLAYUNTILDONE	"playuntildone"
+#define SS_STRING_PLAYTIME	"playtime"
+#define SS_STRING_PLAYREPEAT	"playrepeat"
+#define SS_STRING_DELAY		"delay"
+#define SS_STRING_DELAYRAND	"delayrand"
+#define SS_STRING_VOLUME	"volume"
+#define SS_STRING_END		"end"
+#define SS_STRING_STOPSOUND	"stopsound"
+
+// TYPES -------------------------------------------------------------------
+
+typedef enum
+{
+	SS_CMD_NONE,
+	SS_CMD_PLAY,
+	SS_CMD_WAITUNTILDONE,	/* used by PLAYUNTILDONE */
+	SS_CMD_PLAYTIME,
+	SS_CMD_PLAYREPEAT,
+	SS_CMD_DELAY,
+	SS_CMD_DELAYRAND,
+	SS_CMD_VOLUME,
+	SS_CMD_STOPSOUND,
+	SS_CMD_END
+} sscmds_t;
+
+// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
+
+// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
+
+// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
+
+static void VerifySequencePtr(int *base, int *ptr);
+static int GetSoundOffset(const char *name);
+
+// EXTERNAL DATA DECLARATIONS ----------------------------------------------
+
+extern sfxinfo_t S_sfx[];
+
+// PUBLIC DATA DEFINITIONS -------------------------------------------------
+
+// PRIVATE DATA DEFINITIONS ------------------------------------------------
+
+static struct
+{
+	const char	name[SS_SEQUENCE_NAME_LENGTH];
+	int				scriptNum;
+	int				stopSound;
+} SequenceTranslate[SEQ_NUMSEQ] =
+{
+	{ "Platform", 0, 0 },
+	{ "Platform", 0, 0 },		/* a 'heavy' platform is just a platform */
+	{ "PlatformMetal", 0, 0 },
+	{ "Platform", 0, 0 },		/* same with a 'creak' platform */
+	{ "Silence", 0, 0 },
+	{ "Lava", 0, 0 },
+	{ "Water", 0, 0 },
+	{ "Ice", 0, 0 },
+	{ "Earth", 0, 0 },
+	{ "PlatformMetal2", 0, 0 },
+	{ "DoorNormal", 0, 0 },
+	{ "DoorHeavy", 0, 0 },
+	{ "DoorMetal", 0, 0 },
+	{ "DoorCreak", 0, 0 },
+	{ "Silence", 0, 0 },
+	{ "Lava", 0, 0 },
+	{ "Water", 0, 0},
+	{ "Ice", 0, 0 },
+	{ "Earth", 0, 0},
+	{ "DoorMetal2", 0, 0 },
+	{ "Wind", 0, 0 }
+};
+
+static int *SequenceData[SS_MAX_SCRIPTS];
+
+int ActiveSequences;
+seqnode_t *SequenceListHead;
+
+// CODE --------------------------------------------------------------------
+
+//==========================================================================
+//
+// VerifySequencePtr
+//
+//   Verifies the integrity of the temporary ptr, and ensures that the ptr
+// 		isn't exceeding the size of the temporary buffer
+//==========================================================================
+
+static void VerifySequencePtr(int *base, int *ptr)
+{
+	if (ptr-base > SS_TEMPBUFFER_SIZE)
+	{
+		I_Error("VerifySequencePtr:  tempPtr >= %d\n", SS_TEMPBUFFER_SIZE);
+	}
+}
+
+//==========================================================================
+//
+// GetSoundOffset
+//
+//==========================================================================
+
+static int GetSoundOffset(const char *name)
+{
+	int i;
+
+	for (i = 0; i < NUMSFX; i++)
+	{
+		if (!strcasecmp(name, S_sfx[i].tagName))
+		{
+			return i;
+		}
+	}
+	SC_ScriptError("GetSoundOffset:  Unknown sound name\n");
+	return 0;
+}
+
+//==========================================================================
+//
+// SN_InitSequenceScript
+//
+//==========================================================================
+
+void SN_InitSequenceScript(void)
+{
+	int i, j;
+	int inSequence;
+	int *tempDataStart = NULL; /* jim added initialiser */
+	int *tempDataPtr   = NULL; /* jim added initialiser */
+
+	inSequence = -1;
+	ActiveSequences = 0;
+	for (i = 0; i < SS_MAX_SCRIPTS; i++)
+	{
+		SequenceData[i] = NULL;
+	}
+	SC_Open(SS_SCRIPT_NAME);
+	while (SC_GetString())
+	{
+		if (*sc_String == ':')
+		{
+			if (inSequence != -1)
+			{
+				SC_ScriptError("SN_InitSequenceScript:  Nested Script Error");
+			}
+			tempDataStart = (int *)Z_Malloc(SS_TEMPBUFFER_SIZE, PU_STATIC, NULL);
+			memset(tempDataStart, 0, SS_TEMPBUFFER_SIZE);
+			tempDataPtr = tempDataStart;
+			for (i = 0; i < SS_MAX_SCRIPTS; i++)
+			{
+				if (SequenceData[i] == NULL)
+				{
+					break;
+				}
+			}
+			if (i == SS_MAX_SCRIPTS)
+			{
+				I_Error("Number of SS Scripts >= SS_MAX_SCRIPTS");
+			}
+			for (j = 0; j < SEQ_NUMSEQ; j++)
+			{
+				if (!strcasecmp(SequenceTranslate[j].name, sc_String+1))
+				{
+					SequenceTranslate[j].scriptNum = i;
+					inSequence = j;
+					break;
+				}
+			}
+			continue; // parse the next command
+		}
+		if (inSequence == -1)
+		{
+			continue;
+		}
+		if (SC_Compare(SS_STRING_PLAYUNTILDONE))
+		{
+			VerifySequencePtr(tempDataStart, tempDataPtr);
+			SC_MustGetString();
+			*tempDataPtr++ = SS_CMD_PLAY;
+			*tempDataPtr++ = GetSoundOffset(sc_String);
+			*tempDataPtr++ = SS_CMD_WAITUNTILDONE;
+		}
+		else if (SC_Compare(SS_STRING_PLAY))
+		{
+			VerifySequencePtr(tempDataStart, tempDataPtr);
+			SC_MustGetString();
+			*tempDataPtr++ = SS_CMD_PLAY;
+			*tempDataPtr++ = GetSoundOffset(sc_String);
+		}
+		else if (SC_Compare(SS_STRING_PLAYTIME))
+		{
+			VerifySequencePtr(tempDataStart, tempDataPtr);
+			SC_MustGetString();
+			*tempDataPtr++ = SS_CMD_PLAY;
+			*tempDataPtr++ = GetSoundOffset(sc_String);
+			SC_MustGetNumber();
+			*tempDataPtr++ = SS_CMD_DELAY;
+			*tempDataPtr++ = sc_Number;
+		}
+		else if (SC_Compare(SS_STRING_PLAYREPEAT))
+		{
+			VerifySequencePtr(tempDataStart, tempDataPtr);
+			SC_MustGetString();
+			*tempDataPtr++ = SS_CMD_PLAYREPEAT;
+			*tempDataPtr++ = GetSoundOffset(sc_String);
+		}
+		else if (SC_Compare(SS_STRING_DELAY))
+		{
+			VerifySequencePtr(tempDataStart, tempDataPtr);
+			*tempDataPtr++ = SS_CMD_DELAY;
+			SC_MustGetNumber();
+			*tempDataPtr++ = sc_Number;
+		}
+		else if (SC_Compare(SS_STRING_DELAYRAND))
+		{
+			VerifySequencePtr(tempDataStart, tempDataPtr);
+			*tempDataPtr++ = SS_CMD_DELAYRAND;
+			SC_MustGetNumber();
+			*tempDataPtr++ = sc_Number;
+			SC_MustGetNumber();
+			*tempDataPtr++ = sc_Number;
+		}
+		else if (SC_Compare(SS_STRING_VOLUME))
+		{
+			VerifySequencePtr(tempDataStart, tempDataPtr);
+			*tempDataPtr++ = SS_CMD_VOLUME;
+			SC_MustGetNumber();
+			*tempDataPtr++ = sc_Number;
+		}
+		else if (SC_Compare(SS_STRING_END))
+		{
+			int dataSize;
+
+			*tempDataPtr++ = SS_CMD_END;
+			dataSize = (tempDataPtr - tempDataStart) * sizeof(int);
+			SequenceData[i] = (int *)Z_Malloc(dataSize, PU_STATIC, NULL);
+			memcpy(SequenceData[i], tempDataStart, dataSize);
+			Z_Free(tempDataStart);
+			inSequence = -1;
+		}
+		else if (SC_Compare(SS_STRING_STOPSOUND))
+		{
+			SC_MustGetString();
+			SequenceTranslate[inSequence].stopSound = GetSoundOffset(sc_String);
+			*tempDataPtr++ = SS_CMD_STOPSOUND;
+		}
+		else
+		{
+			SC_ScriptError("SN_InitSequenceScript:  Unknown commmand.\n");
+		}
+	}
+}
+
+//==========================================================================
+//
+//  SN_StartSequence
+//
+//==========================================================================
+
+void SN_StartSequence(mobj_t *mobj, int sequence)
+{
+	seqnode_t *node;
+
+	SN_StopSequence(mobj); // Stop any previous sequence
+	node = (seqnode_t *)Z_Malloc(sizeof(seqnode_t), PU_STATIC, NULL);
+	node->sequencePtr = SequenceData[SequenceTranslate[sequence].scriptNum];
+	node->sequence = sequence;
+	node->mobj = mobj;
+	node->delayTics = 0;
+	node->stopSound = SequenceTranslate[sequence].stopSound;
+	node->volume = 127; // Start at max volume
+
+	if (!SequenceListHead)
+	{
+		SequenceListHead = node;
+		node->next = node->prev = NULL;
+	}
+	else
+	{
+		SequenceListHead->prev = node;
+		node->next = SequenceListHead;
+		node->prev = NULL;
+		SequenceListHead = node;
+	}
+	ActiveSequences++;
+	return;
+}
+
+//==========================================================================
+//
+//  SN_StartSequenceName
+//
+//==========================================================================
+
+void SN_StartSequenceName(mobj_t *mobj, const char *name)
+{
+	int i;
+
+	for (i = 0; i < SEQ_NUMSEQ; i++)
+	{
+		if (!strcmp(name, SequenceTranslate[i].name))
+		{
+			SN_StartSequence(mobj, i);
+			return;
+		}
+	}
+}
+
+//==========================================================================
+//
+//  SN_StopSequence
+//
+//==========================================================================
+
+void SN_StopSequence(mobj_t *mobj)
+{
+	seqnode_t *node;
+
+	for (node = SequenceListHead; node; node = node->next)
+	{
+		if (node->mobj == mobj)
+		{
+			S_StopSound(mobj);
+			if (node->stopSound)
+			{
+				S_StartSoundAtVolume(mobj, node->stopSound, node->volume);
+			}
+			if (SequenceListHead == node)
+			{
+				SequenceListHead = node->next;
+			}
+			if (node->prev)
+			{
+				node->prev->next = node->next;
+			}
+			if (node->next)
+			{
+				node->next->prev = node->prev;
+			}
+			Z_Free(node);
+			ActiveSequences--;
+		}
+	}
+}
+
+//==========================================================================
+//
+//  SN_UpdateActiveSequences
+//
+//==========================================================================
+
+void SN_UpdateActiveSequences(void)
+{
+	seqnode_t *node;
+	boolean sndPlaying;
+
+	if (!ActiveSequences || paused)
+	{ // No sequences currently playing/game is paused
+		return;
+	}
+	for (node = SequenceListHead; node; node = node->next)
+	{
+		if (node->delayTics)
+		{
+			node->delayTics--;
+			continue;
+		}
+		sndPlaying = S_GetSoundPlayingInfo(node->mobj, node->currentSoundID);
+		switch (*node->sequencePtr)
+		{
+		case SS_CMD_PLAY:
+			if (!sndPlaying)
+			{
+				node->currentSoundID = *(node->sequencePtr + 1);
+				S_StartSoundAtVolume(node->mobj, node->currentSoundID,
+									node->volume);
+			}
+			node->sequencePtr += 2;
+			break;
+		case SS_CMD_WAITUNTILDONE:
+			if (!sndPlaying)
+			{
+				node->sequencePtr++;
+				node->currentSoundID = 0;
+			}
+			break;
+		case SS_CMD_PLAYREPEAT:
+			if (!sndPlaying)
+			{
+				node->currentSoundID = *(node->sequencePtr + 1);
+				S_StartSoundAtVolume(node->mobj, node->currentSoundID,
+									node->volume);
+			}
+			break;
+		case SS_CMD_DELAY:
+			node->delayTics = *(node->sequencePtr + 1);
+			node->sequencePtr += 2;
+			node->currentSoundID = 0;
+			break;
+		case SS_CMD_DELAYRAND:
+			node->delayTics = *(node->sequencePtr + 1) +
+					  M_Random() % (*(node->sequencePtr + 2) - *(node->sequencePtr + 1));
+			node->sequencePtr += 2;
+			node->currentSoundID = 0;
+			break;
+		case SS_CMD_VOLUME:
+			node->volume = (127 * (*(node->sequencePtr + 1))) / 100;
+			node->sequencePtr += 2;
+			break;
+		case SS_CMD_STOPSOUND:
+			// Wait until something else stops the sequence
+			break;
+		case SS_CMD_END:
+			SN_StopSequence(node->mobj);
+			break;
+		default:
+			break;
+		}
+	}
+}
+
+//==========================================================================
+//
+//  SN_StopAllSequences
+//
+//==========================================================================
+
+void SN_StopAllSequences(void)
+{
+	seqnode_t *node;
+
+	for (node = SequenceListHead; node; node = node->next)
+	{
+		node->stopSound = 0; // don't play any stop sounds
+		SN_StopSequence(node->mobj);
+	}
+}
+
+//==========================================================================
+//
+//  SN_GetSequenceOffset
+//
+//==========================================================================
+
+int SN_GetSequenceOffset(int sequence, int *sequencePtr)
+{
+	return (sequencePtr - SequenceData[SequenceTranslate[sequence].scriptNum]);
+}
+
+//==========================================================================
+//
+//  SN_ChangeNodeData
+//
+// 	nodeNum zero is the first node
+//==========================================================================
+
+void SN_ChangeNodeData (int nodeNum, int seqOffset, int delayTics, int volume,
+			int currentSoundID)
+{
+	int i;
+	seqnode_t *node;
+
+	i = 0;
+	node = SequenceListHead;
+	while (node && i < nodeNum)
+	{
+		node = node->next;
+		i++;
+	}
+	if (!node)
+	{ // reach the end of the list before finding the nodeNum-th node
+		return;
+	}
+	node->delayTics = delayTics;
+	node->volume = volume;
+	node->sequencePtr += seqOffset;
+	node->currentSoundID = currentSoundID;
+}
+
--- /dev/null
+++ b/sounds.h
@@ -1,0 +1,310 @@
+
+//**************************************************************************
+//**
+//** sounds.h : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 373 $
+//** $Date: 2009-05-19 21:14:28 +0300 (Tue, 19 May 2009) $
+//**
+//**************************************************************************
+
+#ifndef __SOUNDSH__
+#define __SOUNDSH__
+
+#include "soundst.h"
+
+#define MAX_SND_DIST	2025
+#define MAX_CHANNELS	16
+
+/* ---- Music identifiers ---- */
+
+typedef enum
+{
+	mus_e1m1,
+	mus_e1m2,
+	mus_e1m3,
+	mus_e1m4,
+	mus_e1m5,
+	mus_e1m6,
+	mus_e1m7,
+	mus_e1m8,
+	mus_e1m9,
+	mus_e2m1,
+	mus_e2m2,
+	mus_e2m3,
+	mus_e2m4,
+	mus_e2m5,
+	mus_e2m6,
+	mus_e2m7,
+	mus_e2m8,
+	mus_e2m9,
+	mus_e3m1,
+	mus_e3m2,
+	mus_e3m3,
+	mus_e3m4,
+	mus_e3m5,
+	mus_e3m6,
+	mus_e3m7,
+	mus_e3m8,
+	mus_e3m9,
+	mus_e4m1,
+	mus_titl,
+	mus_intr,
+	mus_cptd,
+	NUMMUSIC
+} musicenum_t;
+
+/* ---- Sound identifiers ---- */
+
+typedef enum
+{
+	SFX_NONE,
+	SFX_PLAYER_FIGHTER_NORMAL_DEATH,	/* class specific death screams */
+	SFX_PLAYER_FIGHTER_CRAZY_DEATH,
+	SFX_PLAYER_FIGHTER_EXTREME1_DEATH,
+	SFX_PLAYER_FIGHTER_EXTREME2_DEATH,
+	SFX_PLAYER_FIGHTER_EXTREME3_DEATH,
+	SFX_PLAYER_FIGHTER_BURN_DEATH,
+	SFX_PLAYER_CLERIC_NORMAL_DEATH,
+	SFX_PLAYER_CLERIC_CRAZY_DEATH,
+	SFX_PLAYER_CLERIC_EXTREME1_DEATH,
+	SFX_PLAYER_CLERIC_EXTREME2_DEATH,
+	SFX_PLAYER_CLERIC_EXTREME3_DEATH,
+	SFX_PLAYER_CLERIC_BURN_DEATH,
+	SFX_PLAYER_MAGE_NORMAL_DEATH,
+	SFX_PLAYER_MAGE_CRAZY_DEATH,
+	SFX_PLAYER_MAGE_EXTREME1_DEATH,
+	SFX_PLAYER_MAGE_EXTREME2_DEATH,
+	SFX_PLAYER_MAGE_EXTREME3_DEATH,
+	SFX_PLAYER_MAGE_BURN_DEATH,
+	SFX_PLAYER_FIGHTER_PAIN,
+	SFX_PLAYER_CLERIC_PAIN,
+	SFX_PLAYER_MAGE_PAIN,
+	SFX_PLAYER_FIGHTER_GRUNT,
+	SFX_PLAYER_CLERIC_GRUNT,
+	SFX_PLAYER_MAGE_GRUNT,
+	SFX_PLAYER_LAND,
+	SFX_PLAYER_POISONCOUGH,
+	SFX_PLAYER_FIGHTER_FALLING_SCREAM,	/* class specific falling screams */
+	SFX_PLAYER_CLERIC_FALLING_SCREAM,
+	SFX_PLAYER_MAGE_FALLING_SCREAM,
+	SFX_PLAYER_FALLING_SPLAT,
+	SFX_PLAYER_FIGHTER_FAILED_USE,
+	SFX_PLAYER_CLERIC_FAILED_USE,
+	SFX_PLAYER_MAGE_FAILED_USE,
+	SFX_PLATFORM_START,
+	SFX_PLATFORM_STARTMETAL,
+	SFX_PLATFORM_STOP,
+	SFX_STONE_MOVE,
+	SFX_METAL_MOVE,
+	SFX_DOOR_OPEN,
+	SFX_DOOR_LOCKED,
+	SFX_DOOR_METAL_OPEN,
+	SFX_DOOR_METAL_CLOSE,
+	SFX_DOOR_LIGHT_CLOSE,
+	SFX_DOOR_HEAVY_CLOSE,
+	SFX_DOOR_CREAK,
+	SFX_PICKUP_WEAPON,
+	SFX_PICKUP_ARTIFACT,
+	SFX_PICKUP_KEY,
+	SFX_PICKUP_ITEM,
+	SFX_PICKUP_PIECE,
+	SFX_WEAPON_BUILD,
+	SFX_ARTIFACT_USE,
+	SFX_ARTIFACT_BLAST,
+	SFX_TELEPORT,
+	SFX_THUNDER_CRASH,
+	SFX_FIGHTER_PUNCH_MISS,
+	SFX_FIGHTER_PUNCH_HITTHING,
+	SFX_FIGHTER_PUNCH_HITWALL,
+	SFX_FIGHTER_GRUNT,	
+	SFX_FIGHTER_AXE_HITTHING,	
+	SFX_FIGHTER_HAMMER_MISS,
+	SFX_FIGHTER_HAMMER_HITTHING,
+	SFX_FIGHTER_HAMMER_HITWALL,
+	SFX_FIGHTER_HAMMER_CONTINUOUS,
+	SFX_FIGHTER_HAMMER_EXPLODE,
+	SFX_FIGHTER_SWORD_FIRE,
+	SFX_FIGHTER_SWORD_EXPLODE,
+	SFX_CLERIC_CSTAFF_FIRE,
+	SFX_CLERIC_CSTAFF_EXPLODE,
+	SFX_CLERIC_CSTAFF_HITTHING,
+	SFX_CLERIC_FLAME_FIRE,
+	SFX_CLERIC_FLAME_EXPLODE,
+	SFX_CLERIC_FLAME_CIRCLE,
+	SFX_MAGE_WAND_FIRE,
+	SFX_MAGE_LIGHTNING_FIRE,
+	SFX_MAGE_LIGHTNING_ZAP,
+	SFX_MAGE_LIGHTNING_CONTINUOUS,
+	SFX_MAGE_LIGHTNING_READY,
+	SFX_MAGE_SHARDS_FIRE,
+	SFX_MAGE_SHARDS_EXPLODE,
+	SFX_MAGE_STAFF_FIRE,
+	SFX_MAGE_STAFF_EXPLODE,
+	SFX_SWITCH1,
+	SFX_SWITCH2,
+	SFX_SERPENT_SIGHT,
+	SFX_SERPENT_ACTIVE,
+	SFX_SERPENT_PAIN,
+	SFX_SERPENT_ATTACK,
+	SFX_SERPENT_MELEEHIT,
+	SFX_SERPENT_DEATH,
+	SFX_SERPENT_BIRTH,
+	SFX_SERPENTFX_CONTINUOUS,
+	SFX_SERPENTFX_HIT,
+	SFX_POTTERY_EXPLODE,
+	SFX_DRIP,
+	SFX_CENTAUR_SIGHT,
+	SFX_CENTAUR_ACTIVE,
+	SFX_CENTAUR_PAIN,
+	SFX_CENTAUR_ATTACK,
+	SFX_CENTAUR_DEATH,
+	SFX_CENTAURLEADER_ATTACK,
+	SFX_CENTAUR_MISSILE_EXPLODE,
+	SFX_WIND,
+	SFX_BISHOP_SIGHT,
+	SFX_BISHOP_ACTIVE,
+	SFX_BISHOP_PAIN,
+	SFX_BISHOP_ATTACK,
+	SFX_BISHOP_DEATH,
+	SFX_BISHOP_MISSILE_EXPLODE,
+	SFX_BISHOP_BLUR,
+	SFX_DEMON_SIGHT,
+	SFX_DEMON_ACTIVE,
+	SFX_DEMON_PAIN,
+	SFX_DEMON_ATTACK,
+	SFX_DEMON_MISSILE_FIRE,
+	SFX_DEMON_MISSILE_EXPLODE,
+	SFX_DEMON_DEATH,
+	SFX_WRAITH_SIGHT,
+	SFX_WRAITH_ACTIVE,
+	SFX_WRAITH_PAIN,
+	SFX_WRAITH_ATTACK,
+	SFX_WRAITH_MISSILE_FIRE,
+	SFX_WRAITH_MISSILE_EXPLODE,
+	SFX_WRAITH_DEATH,
+	SFX_PIG_ACTIVE1,
+	SFX_PIG_ACTIVE2,
+	SFX_PIG_PAIN,
+	SFX_PIG_ATTACK,
+	SFX_PIG_DEATH,
+	SFX_MAULATOR_SIGHT,
+	SFX_MAULATOR_ACTIVE,
+	SFX_MAULATOR_PAIN,
+	SFX_MAULATOR_HAMMER_SWING,
+	SFX_MAULATOR_HAMMER_HIT,
+	SFX_MAULATOR_MISSILE_HIT,
+	SFX_MAULATOR_DEATH,
+	SFX_FREEZE_DEATH,
+	SFX_FREEZE_SHATTER,
+	SFX_ETTIN_SIGHT,
+	SFX_ETTIN_ACTIVE,
+	SFX_ETTIN_PAIN,
+	SFX_ETTIN_ATTACK,
+	SFX_ETTIN_DEATH,
+	SFX_FIRED_SPAWN,
+	SFX_FIRED_ACTIVE,
+	SFX_FIRED_PAIN,
+	SFX_FIRED_ATTACK,
+	SFX_FIRED_MISSILE_HIT,
+	SFX_FIRED_DEATH,
+	SFX_ICEGUY_SIGHT,
+	SFX_ICEGUY_ACTIVE,
+	SFX_ICEGUY_ATTACK,
+	SFX_ICEGUY_FX_EXPLODE,
+	SFX_SORCERER_SIGHT,
+	SFX_SORCERER_ACTIVE,
+	SFX_SORCERER_PAIN,
+	SFX_SORCERER_SPELLCAST,
+	SFX_SORCERER_BALLWOOSH,
+	SFX_SORCERER_DEATHSCREAM,
+	SFX_SORCERER_BISHOPSPAWN,
+	SFX_SORCERER_BALLPOP,
+	SFX_SORCERER_BALLBOUNCE,
+	SFX_SORCERER_BALLEXPLODE,
+	SFX_SORCERER_BIGBALLEXPLODE,
+	SFX_SORCERER_HEADSCREAM,
+	SFX_DRAGON_SIGHT,
+	SFX_DRAGON_ACTIVE,
+	SFX_DRAGON_WINGFLAP,
+	SFX_DRAGON_ATTACK,
+	SFX_DRAGON_PAIN,
+	SFX_DRAGON_DEATH,
+	SFX_DRAGON_FIREBALL_EXPLODE,
+	SFX_KORAX_SIGHT,
+	SFX_KORAX_ACTIVE,
+	SFX_KORAX_PAIN,
+	SFX_KORAX_ATTACK,
+	SFX_KORAX_COMMAND,
+	SFX_KORAX_DEATH,
+	SFX_KORAX_STEP,
+	SFX_THRUSTSPIKE_RAISE,
+	SFX_THRUSTSPIKE_LOWER,
+	SFX_STAINEDGLASS_SHATTER,
+	SFX_FLECHETTE_BOUNCE,
+	SFX_FLECHETTE_EXPLODE,
+	SFX_LAVA_MOVE,
+	SFX_WATER_MOVE,
+	SFX_ICE_STARTMOVE,
+	SFX_EARTH_STARTMOVE,
+	SFX_WATER_SPLASH,
+	SFX_LAVA_SIZZLE,
+	SFX_SLUDGE_GLOOP,
+	SFX_CHOLY_FIRE,
+	SFX_SPIRIT_ACTIVE,
+	SFX_SPIRIT_ATTACK,
+	SFX_SPIRIT_DIE,
+	SFX_VALVE_TURN,
+	SFX_ROPE_PULL,
+	SFX_FLY_BUZZ,
+	SFX_IGNITE,
+	SFX_PUZZLE_SUCCESS,
+	SFX_PUZZLE_FAIL_FIGHTER,
+	SFX_PUZZLE_FAIL_CLERIC,
+	SFX_PUZZLE_FAIL_MAGE,
+	SFX_EARTHQUAKE,
+	SFX_BELLRING,
+	SFX_TREE_BREAK,
+	SFX_TREE_EXPLODE,
+	SFX_SUITOFARMOR_BREAK,
+	SFX_POISONSHROOM_PAIN,
+	SFX_POISONSHROOM_DEATH,
+	SFX_AMBIENT1,
+	SFX_AMBIENT2,
+	SFX_AMBIENT3,
+	SFX_AMBIENT4,
+	SFX_AMBIENT5,
+	SFX_AMBIENT6,
+	SFX_AMBIENT7,
+	SFX_AMBIENT8,
+	SFX_AMBIENT9,
+	SFX_AMBIENT10,
+	SFX_AMBIENT11,
+	SFX_AMBIENT12,
+	SFX_AMBIENT13,
+	SFX_AMBIENT14,
+	SFX_AMBIENT15,
+	SFX_STARTUP_TICK,
+	SFX_SWITCH_OTHERLEVEL,
+	SFX_RESPAWN,
+	SFX_KORAX_VOICE_1,
+	SFX_KORAX_VOICE_2,
+	SFX_KORAX_VOICE_3,
+	SFX_KORAX_VOICE_4,
+	SFX_KORAX_VOICE_5,
+	SFX_KORAX_VOICE_6,
+	SFX_KORAX_VOICE_7,
+	SFX_KORAX_VOICE_8,
+	SFX_KORAX_VOICE_9,
+	SFX_BAT_SCREAM,
+	SFX_CHAT,
+	SFX_MENU_MOVE,
+	SFX_CLOCK_TICK,
+	SFX_FIREBALL,
+	SFX_PUPPYBEAT,
+	SFX_MYSTICINCANT,
+	NUMSFX
+} sfxenum_t;
+
+#endif	/* __SOUNDSH__ */
+
--- /dev/null
+++ b/soundst.h
@@ -1,0 +1,80 @@
+//**************************************************************************
+//**
+//** soundst.h : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 505 $
+//** $Date: 2009-06-03 22:41:58 +0300 (Wed, 03 Jun 2009) $
+//**
+//**************************************************************************
+
+#ifndef __SOUNDSTH__
+#define __SOUNDSTH__
+
+typedef struct
+{
+	const char	name[8];
+	int		p1;
+} musicinfo_t;
+
+typedef struct sfxinfo_s
+{
+	const char	tagName[32];
+	char	lumpname[12];	/* Only need 9 bytes, but padded out to be dword aligned */
+//	struct sfxinfo_s *link;	/* Make alias for another sound */
+	int	priority;	/* Higher priority takes precendence */
+	int	usefulness;	/* Determines when a sound should be cached out */
+	void	*snd_ptr;
+	int	lumpnum;
+	int	numchannels;	/* total number of channels a sound type may occupy */
+	boolean	changePitch;
+} sfxinfo_t;
+
+typedef struct
+{
+	mobj_t		*mo;
+	int		sound_id;
+	int		handle;
+	int		volume;
+	int		pitch;
+	int		priority;
+} channel_t;
+
+typedef struct
+{
+	int		id;
+	unsigned short	priority;
+	const char	*name;
+	mobj_t		*mo;
+	int		distance;
+} ChanInfo_t;
+
+typedef struct
+{
+	int	channelCount;
+	int	musicVolume;
+	int	soundVolume;
+	ChanInfo_t	chan[8];
+} SoundInfo_t;
+
+extern	int		snd_MaxVolume;
+extern	int		snd_MusicVolume;
+
+void S_Init(void);
+void S_ShutDown(void);
+void S_Start(void);
+void S_StartSound(mobj_t *origin, int sound_id);
+int S_GetSoundID(const char *name);
+void S_StartSoundAtVolume(mobj_t *origin, int sound_id, int volume);
+void S_StopSound(mobj_t *origin);
+void S_StopAllSound(void);
+void S_PauseSound(void);
+void S_ResumeSound(void);
+void S_UpdateSounds(mobj_t *listener);
+void S_StartSong(int song, boolean loop);
+void S_StartSongName(const char *songLump, boolean loop);
+void S_GetChannelInfo(SoundInfo_t *s);
+void S_SetMusicVolume(void);
+boolean S_GetSoundPlayingInfo(mobj_t *mobj, int sound_id);
+
+#endif	/* __SOUNDSTH__ */
+
--- /dev/null
+++ b/st_start.c
@@ -1,0 +1,329 @@
+
+//**************************************************************************
+//**
+//** st_start.c : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 373 $
+//** $Date: 2009-05-19 21:14:28 +0300 (Tue, 19 May 2009) $
+//**
+//**************************************************************************
+
+
+// HEADER FILES ------------------------------------------------------------
+
+#if 0
+/* I doubt I'll readd DOS support, but who knows */
+#include <libc.h>
+#include <ctype.h>
+#endif
+#include "h2stdinc.h"
+#include "h2def.h"
+#include "st_start.h"
+
+
+// MACROS ------------------------------------------------------------------
+
+#define ST_MAX_NOTCHES		32
+#define ST_NOTCH_WIDTH		16
+#define ST_NOTCH_HEIGHT		23
+#define ST_PROGRESS_X		64	/* Start of notches x screen pos. */
+#define ST_PROGRESS_Y		441	/* Start of notches y screen pos. */
+
+#define ST_NETPROGRESS_X	288
+#define ST_NETPROGRESS_Y	32
+#define ST_NETNOTCH_WIDTH	8
+#define ST_NETNOTCH_HEIGHT	16
+#define ST_MAX_NETNOTCHES	8
+
+// TYPES -------------------------------------------------------------------
+
+// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
+
+#if defined(__WATCOMC__) || defined(__DJGPP__) || defined(__DOS__)
+extern void SetVideoModeHR(void);
+extern void ClearScreenHR(void);
+extern void SlamHR(char *buffer);
+extern void SlamBlockHR(int x, int y, int w, int h, char *src);
+extern void InitPaletteHR(void);
+extern void SetPaletteHR(byte *palette);
+extern void GetPaletteHR(byte *palette);
+extern void FadeToPaletteHR(byte *palette);
+extern void FadeToBlackHR(void);
+extern void BlackPaletteHR(void);
+extern void I_StartupReadKeys(void);
+#endif	/* DOS :  I_IBM.C */
+
+// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
+
+// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
+char *ST_LoadScreen(void);
+void ST_UpdateNotches(int notchPosition);
+void ST_UpdateNetNotches(int notchPosition);
+
+// EXTERNAL DATA DECLARATIONS ----------------------------------------------
+
+// PUBLIC DATA DEFINITIONS -------------------------------------------------
+
+// PRIVATE DATA DEFINITIONS ------------------------------------------------
+
+#if defined(__WATCOMC__) || defined(__DJGPP__) || defined(__DOS__)
+static char *bitmap = NULL;
+
+static char notchTable[] =
+{
+	/* plane 0 */
+	0x00, 0x80, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x40,
+	0x02, 0x40, 0x02, 0x40, 0x02, 0x40, 0x02, 0x40, 0x02, 0x40, 0x03, 0xC0,
+	0x0F, 0x90, 0x1B, 0x68, 0x3D, 0xBC, 0x3F, 0xFC, 0x20, 0x08, 0x20, 0x08,
+	0x2F, 0xD8, 0x37, 0xD8, 0x37, 0xF8, 0x1F, 0xF8, 0x1C, 0x50,
+
+	/* plane 1 */
+	0x00, 0x80, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x02, 0x40, 0x02, 0x40,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0xA0,
+	0x30, 0x6C, 0x24, 0x94, 0x42, 0x4A, 0x60, 0x0E, 0x60, 0x06, 0x7F, 0xF6,
+	0x7F, 0xF6, 0x7F, 0xF6, 0x5E, 0xF6, 0x38, 0x16, 0x23, 0xAC,
+
+	/* plane 2 */
+	0x00, 0x80, 0x01, 0x80, 0x01, 0x80, 0x00, 0x00, 0x02, 0x40, 0x02, 0x40,
+	0x02, 0x40, 0x02, 0x40, 0x02, 0x40, 0x02, 0x40, 0x02, 0x40, 0x03, 0xE0,
+	0x30, 0x6C, 0x24, 0x94, 0x52, 0x6A, 0x7F, 0xFE, 0x60, 0x0E, 0x60, 0x0E,
+	0x6F, 0xD6, 0x77, 0xD6, 0x56, 0xF6, 0x38, 0x36, 0x23, 0xAC,
+
+	/* plane 3 */
+	0x00, 0x00, 0x00, 0x00, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80,
+	0x03, 0xC0, 0x03, 0xC0, 0x03, 0xC0, 0x03, 0xC0, 0x03, 0x80, 0x02, 0x40,
+	0x0F, 0x90, 0x1B, 0x68, 0x3D, 0xB4, 0x1F, 0xF0, 0x1F, 0xF8, 0x1F, 0xF8,
+	0x10, 0x28, 0x08, 0x28, 0x29, 0x08, 0x07, 0xE8, 0x1C, 0x50
+};
+
+/* Red Network Progress notches */
+static char netnotchTable[] =
+{
+	/* plane 0 */
+	0x80, 0x50, 0xD0, 0xf0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xD0, 0xF0, 0xC0,
+	0x70, 0x50, 0x80, 0x60,
+
+	/* plane 1 */
+	0x60, 0xE0, 0xE0, 0xA0, 0xA0, 0xA0, 0xE0, 0xA0, 0xA0, 0xA0, 0xE0, 0xA0,
+	0xA0, 0xE0, 0x60, 0x00,
+
+	/* plane 2 */
+	0x80, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00,
+	0x10, 0x10, 0x80, 0x60,
+
+	/* plane 3 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00
+};
+#endif	/* DOS :  I_IBM.C */
+
+// CODE --------------------------------------------------------------------
+
+
+//--------------------------------------------------------------------------
+//
+// Startup Screen Functions
+//
+//--------------------------------------------------------------------------
+
+//==========================================================================
+//
+// ST_Init - Do the startup screen
+//
+//==========================================================================
+
+void ST_Init(void)
+{
+#if defined(__WATCOMC__) || defined(__DJGPP__) || defined(__DOS__)
+	char *pal;
+	char *buffer;
+
+	if (!debugmode)
+	{
+		/* Set 640x480x16 mode */
+		SetVideoModeHR();
+		ClearScreenHR();
+		InitPaletteHR();
+		BlackPaletteHR();
+
+		/* Load graphic */
+		buffer = ST_LoadScreen();
+		pal = buffer;
+		bitmap = buffer + 16*3;
+
+		SlamHR(bitmap);
+		FadeToPaletteHR(pal);
+		Z_Free(buffer);
+	}
+#endif	/* DOS :  I_IBM.C */
+}
+
+
+void ST_Done(void)
+{
+#if defined(__WATCOMC__) || defined(__DJGPP__) || defined(__DOS__)
+	ClearScreenHR();
+#endif	/* DOS :  I_IBM.C */
+}
+
+
+//==========================================================================
+//
+// ST_UpdateNotches
+//
+//==========================================================================
+
+void ST_UpdateNotches(int notchPosition)
+{
+#if defined(__WATCOMC__) || defined(__DJGPP__) || defined(__DOS__)
+	int x = ST_PROGRESS_X + notchPosition*ST_NOTCH_WIDTH;
+	int y = ST_PROGRESS_Y;
+	SlamBlockHR(x,y, ST_NOTCH_WIDTH,ST_NOTCH_HEIGHT, notchTable);
+#endif	/* DOS :  I_IBM.C */
+}
+
+
+//==========================================================================
+//
+// ST_UpdateNetNotches - indicates network progress
+//
+//==========================================================================
+
+void ST_UpdateNetNotches(int notchPosition)
+{
+#if defined(__WATCOMC__) || defined(__DJGPP__) || defined(__DOS__)
+	int x = ST_NETPROGRESS_X + notchPosition*ST_NETNOTCH_WIDTH;
+	int y = ST_NETPROGRESS_Y;
+	SlamBlockHR(x,y, ST_NETNOTCH_WIDTH, ST_NETNOTCH_HEIGHT, netnotchTable);
+#endif	/* DOS :  I_IBM.C */
+}
+
+
+//==========================================================================
+//
+// ST_Progress - increments progress indicator
+//
+//==========================================================================
+
+void ST_Progress(void)
+{
+#if defined(__WATCOMC__) || defined(__DJGPP__) || defined(__DOS__)
+	static int notchPosition = 0;
+
+	/* Check for ESC press -- during startup all events eaten here */
+	I_StartupReadKeys();
+
+	if (debugmode)
+	{
+		printf(".");
+	}
+	else
+	{
+		if (notchPosition < ST_MAX_NOTCHES)
+		{
+			ST_UpdateNotches(notchPosition);
+			S_StartSound(NULL, SFX_STARTUP_TICK);
+			notchPosition++;
+		}
+	}
+#else	/* DOS :  I_IBM.C */
+	putchar ('.');
+#endif
+}
+
+
+//==========================================================================
+//
+// ST_NetProgress - indicates network progress
+//
+//==========================================================================
+
+void ST_NetProgress(void)
+{
+#if defined(__WATCOMC__) || defined(__DJGPP__) || defined(__DOS__)
+	static int netnotchPosition = 0;
+	if (debugmode)
+	{
+		printf("*");
+	}
+	else
+	{
+		if (netnotchPosition < ST_MAX_NETNOTCHES)
+		{
+			ST_UpdateNetNotches(netnotchPosition);
+			S_StartSound(NULL, SFX_DRIP);
+			netnotchPosition++;
+		}
+	}
+#endif	/* DOS :  I_IBM.C */
+}
+
+
+//==========================================================================
+//
+// ST_NetDone - net progress complete
+//
+//==========================================================================
+
+void ST_NetDone(void)
+{
+	S_StartSound(NULL, SFX_PICKUP_WEAPON);
+}
+
+
+//==========================================================================
+//
+// ST_Message - gives debug message
+//
+//==========================================================================
+
+void ST_Message(const char *message, ...)
+{
+	va_list argptr;
+	char buffer[MAX_ST_MSG];
+
+	va_start(argptr, message);
+	vsnprintf(buffer, sizeof(buffer), message, argptr);
+	va_end(argptr);
+
+//	if (debugmode)
+		printf("%s", buffer);
+}
+
+//==========================================================================
+//
+// ST_RealMessage - gives user message
+//
+//==========================================================================
+
+void ST_RealMessage(const char *message, ...)
+{
+	va_list argptr;
+	char buffer[MAX_ST_MSG];
+
+	va_start(argptr, message);
+	vsnprintf(buffer, sizeof(buffer), message, argptr);
+	va_end(argptr);
+
+	printf("%s", buffer);		// Always print these messages
+}
+
+
+//==========================================================================
+//
+// ST_LoadScreen - loads startup graphic
+//
+//==========================================================================
+
+char *ST_LoadScreen(void)
+{
+	int length, lump;
+	char *buffer;
+
+	lump = W_GetNumForName("STARTUP");
+	length = W_LumpLength(lump);
+	buffer = (char *)Z_Malloc(length, PU_STATIC, NULL);
+	W_ReadLump(lump, buffer);
+	return (buffer);
+}
+
--- /dev/null
+++ b/st_start.h
@@ -1,0 +1,29 @@
+
+//**************************************************************************
+//**
+//** st_start.h : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 543 $
+//** $Date: 2010-01-11 20:44:55 +0200 (Mon, 11 Jan 2010) $
+//**
+//**************************************************************************
+
+#ifndef __ST_START__
+#define __ST_START__
+
+extern void ST_Init(void);
+extern void ST_Done(void);
+
+extern void ST_Progress(void);
+extern void ST_NetProgress(void);
+extern void ST_NetDone(void);
+
+/* Maximum size of a debug message */
+#define	MAX_ST_MSG		256
+
+/* These two doesn't add a '\n' to the message, the caller must add it by himself */
+extern void ST_Message(const char *message, ...);
+extern void ST_RealMessage(const char *message, ...);
+
+#endif	/* __ST_START__ */
+
--- /dev/null
+++ b/sv_save.c
@@ -1,0 +1,2478 @@
+
+//**************************************************************************
+//**
+//** sv_save.c : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 522 $
+//** $Date: 2009-06-08 11:45:17 +0300 (Mon, 08 Jun 2009) $
+//**
+//** Games are always saved Little Endian, with 32 bit offsets.
+//** The saved games then can be properly read on 64 bit and/or
+//** Big Endian machines all the same.
+//** See the file SAVEGAME for notes and/or issues.
+//**
+//**************************************************************************
+
+// HEADER FILES ------------------------------------------------------------
+
+#include "h2stdinc.h"
+#include "h2def.h"
+#include "p_local.h"
+#include "sv_save.h"
+
+// MACROS ------------------------------------------------------------------
+
+#define MAX_TARGET_PLAYERS	512
+#define MOBJ_NULL		-1
+#define MOBJ_XX_PLAYER		-2
+
+#define MAX_MAPS		99
+#define BASE_SLOT		6
+#define REBORN_SLOT		7
+#define REBORN_DESCRIPTION	"TEMP GAME"
+#define MAX_THINKER_SIZE	256
+
+// TYPES -------------------------------------------------------------------
+
+typedef enum
+{
+	ASEG_GAME_HEADER = 101,
+	ASEG_MAP_HEADER,
+	ASEG_WORLD,
+	ASEG_POLYOBJS,
+	ASEG_MOBJS,
+	ASEG_THINKERS,
+	ASEG_SCRIPTS,
+	ASEG_PLAYERS,
+	ASEG_SOUNDS,
+	ASEG_MISC,
+	ASEG_END
+} gameArchiveSegment_t;
+
+typedef enum
+{
+	TC_NULL,
+	TC_MOVE_CEILING,
+	TC_VERTICAL_DOOR,
+	TC_MOVE_FLOOR,
+	TC_PLAT_RAISE,
+	TC_INTERPRET_ACS,
+	TC_FLOOR_WAGGLE,
+	TC_LIGHT,
+	TC_PHASE,
+	TC_BUILD_PILLAR,
+	TC_ROTATE_POLY,
+	TC_MOVE_POLY,
+	TC_POLY_DOOR
+} thinkClass_t;
+
+typedef struct
+{
+	thinkClass_t tClass;
+	think_t thinkerFunc;
+	void (*mangleFunc)(void *, void *);
+	void (*restoreFunc)(void *, void *);
+	size_t realsize, savesize;
+} thinkInfo_t;
+
+typedef struct
+{
+	thinker_t thinker;
+	sector_t *sector;
+} ssthinker_t;
+
+// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
+
+void P_SpawnPlayer(mapthing_t *mthing);
+
+// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
+
+// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
+
+static void ArchiveWorld(void);
+static void UnarchiveWorld(void);
+static void ArchivePolyobjs(void);
+static void UnarchivePolyobjs(void);
+static void ArchiveMobjs(void);
+static void UnarchiveMobjs(void);
+static void ArchiveThinkers(void);
+static void UnarchiveThinkers(void);
+static void ArchiveScripts(void);
+static void UnarchiveScripts(void);
+static void ArchivePlayers(void);
+static void UnarchivePlayers(void);
+static void ArchiveSounds(void);
+static void UnarchiveSounds(void);
+static void ArchiveMisc(void);
+static void UnarchiveMisc(void);
+static void SetMobjArchiveNums(void);
+static void RemoveAllThinkers(void);
+static void MangleMobj(mobj_t *mobj, save_mobj_t *temp);
+static void RestoreMobj(mobj_t *mobj, save_mobj_t *temp);
+static int32_t GetMobjNum(mobj_t *mobj);
+static mobj_t *GetMobjPtr(int32_t archiveNum, intptr_t *target);
+static void MangleFloorMove(void *arg1, void *arg2);
+static void RestoreFloorMove(void *arg1, void *arg2);
+static void MangleLight(void *arg1, void *arg2);
+static void RestoreLight(void *arg1, void *arg2);
+static void MangleVerticalDoor(void *arg1, void *arg2);
+static void RestoreVerticalDoor(void *arg1, void *arg2);
+static void ManglePhase(void *arg1, void *arg2);
+static void RestorePhase(void *arg1, void *arg2);
+static void ManglePillar(void *arg1, void *arg2);
+static void RestorePillar(void *arg1, void *arg2);
+static void MangleFloorWaggle(void *arg1, void *arg2);
+static void RestoreFloorWaggle(void *arg1, void *arg2);
+static void ManglePolyEvent(void *arg1, void *arg2);
+static void RestorePolyEvent(void *arg1, void *arg2);
+static void ManglePolyDoor(void *arg1, void *arg2);
+static void RestorePolyDoor(void *arg1, void *arg2);
+static void MangleScript(void *arg1, void *arg2);
+static void RestoreScript(void *arg1, void *arg2);
+static void ManglePlatRaise(void *arg1, void *arg2);
+static void RestorePlatRaise(void *arg1, void *arg2);
+static void MangleMoveCeiling(void *arg1, void *arg2);
+static void RestoreMoveCeiling(void *arg1, void *arg2);
+static void AssertSegment(gameArchiveSegment_t segType);
+static void ClearSaveSlot(int slot);
+static void CopySaveSlot(int sourceSlot, int destSlot);
+static void CopyFile(const char *sourceName, const char *destName);
+static boolean ExistingFile(const char *name);
+static void OpenStreamOut(const char *fileName);
+static void CloseStreamOut(void);
+static void StreamOutBuffer(const void *buffer, size_t size);
+static void StreamOutByte(byte val);
+static void StreamOutWord(uint16_t val);
+static void StreamOutLong(uint32_t val);
+
+// EXTERNAL DATA DECLARATIONS ----------------------------------------------
+
+extern int ACScriptCount;
+extern byte *ActionCodeBase;
+extern acsInfo_t *ACSInfo;
+
+// PUBLIC DATA DEFINITIONS -------------------------------------------------
+
+// PRIVATE DATA DEFINITIONS ------------------------------------------------
+
+static int MobjCount;
+static mobj_t **MobjList;
+static intptr_t **TargetPlayerAddrs;
+static int TargetPlayerCount;
+static void *SaveBuffer;
+static boolean SavingPlayers;
+static byte *SavePtr;
+static FILE *SavingFP;
+
+// This list has been prioritized using frequency estimates
+static thinkInfo_t ThinkerInfo[] =
+{
+	{
+		TC_MOVE_FLOOR,
+		T_MoveFloor,
+		MangleFloorMove,
+		RestoreFloorMove,
+		sizeof(floormove_t),
+		sizeof(save_floormove_t)
+	},
+	{
+		TC_PLAT_RAISE,
+		T_PlatRaise,
+		ManglePlatRaise,
+		RestorePlatRaise,
+		sizeof(plat_t),
+		sizeof(save_plat_t)
+	},
+	{
+		TC_MOVE_CEILING,
+		T_MoveCeiling,
+		MangleMoveCeiling,
+		RestoreMoveCeiling,
+		sizeof(ceiling_t),
+		sizeof(save_ceiling_t)
+	},
+	{
+		TC_LIGHT,
+		T_Light,
+		MangleLight,
+		RestoreLight,
+		sizeof(light_t),
+		sizeof(save_light_t)
+	},
+	{
+		TC_VERTICAL_DOOR,
+		T_VerticalDoor,
+		MangleVerticalDoor,
+		RestoreVerticalDoor,
+		sizeof(vldoor_t),
+		sizeof(save_vldoor_t)
+	},
+	{
+		TC_PHASE,
+		T_Phase,
+		ManglePhase,
+		RestorePhase,
+		sizeof(phase_t),
+		sizeof(save_phase_t)
+	},
+	{
+		TC_INTERPRET_ACS,
+		T_InterpretACS,
+		MangleScript,
+		RestoreScript,
+		sizeof(acs_t),
+		sizeof(save_acs_t)
+	},
+	{
+		TC_ROTATE_POLY,
+		T_RotatePoly,
+		ManglePolyEvent,
+		RestorePolyEvent,
+		sizeof(polyevent_t),
+		sizeof(save_polyevent_t)
+	},
+	{
+		TC_BUILD_PILLAR,
+		T_BuildPillar,
+		ManglePillar,
+		RestorePillar,
+		sizeof(pillar_t),
+		sizeof(save_pillar_t)
+	},
+	{
+		TC_MOVE_POLY,
+		T_MovePoly,
+		ManglePolyEvent,
+		RestorePolyEvent,
+		sizeof(polyevent_t),
+		sizeof(save_polyevent_t)
+	},
+	{
+		TC_POLY_DOOR,
+		T_PolyDoor,
+		ManglePolyDoor,
+		RestorePolyDoor,
+		sizeof(polydoor_t),
+		sizeof(save_polydoor_t)
+	},
+	{
+		TC_FLOOR_WAGGLE,
+		T_FloorWaggle,
+		MangleFloorWaggle,
+		RestoreFloorWaggle,
+		sizeof(floorWaggle_t),
+		sizeof(save_floorWaggle_t)
+	},
+	{ // Terminator
+		TC_NULL, NULL, NULL, NULL, 0
+	}
+};
+
+// CODE --------------------------------------------------------------------
+
+static inline byte GET_BYTE (void)
+{
+	return *SavePtr++;
+}
+
+static inline int16_t GET_WORD (void)
+{
+	uint16_t val = READ_INT16(SavePtr);
+	INCR_INT16(SavePtr);
+	return (int16_t) val;
+}
+
+static inline int32_t GET_LONG (void)
+{
+	uint32_t val = READ_INT32(SavePtr);
+	INCR_INT32(SavePtr);
+	return (int32_t) val;
+}
+
+//==========================================================================
+//
+// SV_SaveGame
+//
+//==========================================================================
+
+void SV_SaveGame(int slot, const char *description)
+{
+	int i;
+	char fileName[MAX_OSPATH];
+	char versionText[HXS_VERSION_TEXT_LENGTH];
+
+	// Open the output file
+	snprintf(fileName, sizeof(fileName), "%shex6.hxs", basePath);
+	OpenStreamOut(fileName);
+
+	// Write game save description
+	StreamOutBuffer(description, HXS_DESCRIPTION_LENGTH);
+
+	// Write version info
+	memset(versionText, 0, HXS_VERSION_TEXT_LENGTH);
+	strcpy(versionText, HXS_VERSION_TEXT);
+	StreamOutBuffer(versionText, HXS_VERSION_TEXT_LENGTH);
+
+	// Place a header marker
+	StreamOutLong(ASEG_GAME_HEADER);
+
+	// Write current map and difficulty
+	StreamOutByte(gamemap);
+	StreamOutByte(gameskill);
+
+	// Write global script info
+	for (i = 0; i < MAX_ACS_WORLD_VARS; i++)
+	{
+		StreamOutLong(WorldVars[i]);
+	}
+	for (i = 0; i <= MAX_ACS_STORE; i++)
+	{
+		StreamOutLong(ACSStore[i].map);
+		StreamOutLong(ACSStore[i].script);
+		StreamOutBuffer(ACSStore[i].args, 4);
+	}
+
+	ArchivePlayers();
+
+	// Place a termination marker
+	StreamOutLong(ASEG_END);
+
+	// Close the output file
+	CloseStreamOut();
+
+	// Save out the current map
+	SV_SaveMap(true); // true = save player info
+
+	// Clear all save files at destination slot
+	ClearSaveSlot(slot);
+
+	// Copy base slot to destination slot
+	CopySaveSlot(BASE_SLOT, slot);
+}
+
+//==========================================================================
+//
+// SV_SaveMap
+//
+//==========================================================================
+
+void SV_SaveMap(boolean savePlayers)
+{
+	char fileName[MAX_OSPATH];
+
+	SavingPlayers = savePlayers;
+
+	// Open the output file
+	snprintf(fileName, sizeof(fileName), "%shex6%02d.hxs", basePath, gamemap);
+	OpenStreamOut(fileName);
+
+	// Place a header marker
+	StreamOutLong(ASEG_MAP_HEADER);
+
+	// Write the level timer
+	StreamOutLong(leveltime);
+
+	// Set the mobj archive numbers
+	SetMobjArchiveNums();
+
+	ArchiveWorld();
+	ArchivePolyobjs();
+	ArchiveMobjs();
+	ArchiveThinkers();
+	ArchiveScripts();
+	ArchiveSounds();
+	ArchiveMisc();
+
+	// Place a termination marker
+	StreamOutLong(ASEG_END);
+
+	// Close the output file
+	CloseStreamOut();
+}
+
+//==========================================================================
+//
+// SV_LoadGame
+//
+//==========================================================================
+
+void SV_LoadGame(int slot)
+{
+	int i;
+	char fileName[MAX_OSPATH];
+	player_t playerBackup[MAXPLAYERS];
+	mobj_t *mobj;
+
+	// Copy all needed save files to the base slot
+	if (slot != BASE_SLOT)
+	{
+		ClearSaveSlot(BASE_SLOT);
+		CopySaveSlot(slot, BASE_SLOT);
+	}
+
+	// Create the name
+	snprintf(fileName, sizeof(fileName), "%shex6.hxs", basePath);
+
+	// Load the file
+	M_ReadFile(fileName, &SaveBuffer);
+
+	// Set the save pointer and skip the description field
+	SavePtr = (byte *)SaveBuffer + HXS_DESCRIPTION_LENGTH;
+
+	// Check the version text
+	if (strcmp((char *)SavePtr, HXS_VERSION_TEXT))
+	{ // Bad version
+		return;
+	}
+	SavePtr += HXS_VERSION_TEXT_LENGTH;
+
+	AssertSegment(ASEG_GAME_HEADER);
+
+	gameepisode = 1;
+	gamemap = GET_BYTE();
+	gameskill = GET_BYTE();
+
+	// Read global script info
+	memcpy(WorldVars, SavePtr, sizeof(WorldVars));
+	SavePtr += sizeof(WorldVars);
+	memcpy(ACSStore, SavePtr, sizeof(ACSStore));
+	SavePtr += sizeof(ACSStore);
+	for (i = 0; i < MAX_ACS_WORLD_VARS; i++)
+	{
+		WorldVars[i] = (int) LONG(WorldVars[i]);
+	}
+	for (i = 0; i <= MAX_ACS_STORE; i++)
+	{
+		ACSStore[i].map = (int) LONG(ACSStore[i].map);
+		ACSStore[i].script = (int) LONG(ACSStore[i].script);
+	}
+
+	// Read the player structures
+	UnarchivePlayers();
+
+	AssertSegment(ASEG_END);
+
+	Z_Free(SaveBuffer);
+
+	// Save player structs
+	for (i = 0; i < MAXPLAYERS; i++)
+	{
+		playerBackup[i] = players[i];
+	}
+
+	// Load the current map
+	SV_LoadMap();
+
+	// Don't need the player mobj relocation info for load game
+	Z_Free(TargetPlayerAddrs);
+	TargetPlayerAddrs = NULL;
+
+	// Restore player structs
+	inv_ptr = 0;
+	curpos = 0;
+	for (i = 0; i < MAXPLAYERS; i++)
+	{
+		mobj = players[i].mo;
+		players[i] = playerBackup[i];
+		players[i].mo = mobj;
+		if (i == consoleplayer)
+		{
+			players[i].readyArtifact = players[i].inventory[inv_ptr].type;
+		}
+	}
+}
+
+//==========================================================================
+//
+// SV_UpdateRebornSlot
+//
+// Copies the base slot to the reborn slot.
+//
+//==========================================================================
+
+void SV_UpdateRebornSlot(void)
+{
+	ClearSaveSlot(REBORN_SLOT);
+	CopySaveSlot(BASE_SLOT, REBORN_SLOT);
+}
+
+//==========================================================================
+//
+// SV_ClearRebornSlot
+//
+//==========================================================================
+
+void SV_ClearRebornSlot(void)
+{
+	ClearSaveSlot(REBORN_SLOT);
+}
+
+//==========================================================================
+//
+// SV_MapTeleport
+//
+//==========================================================================
+
+void SV_MapTeleport(int map, int position)
+{
+	int i;
+	int j;
+	char fileName[MAX_OSPATH];
+	player_t playerBackup[MAXPLAYERS];
+	mobj_t *mobj;
+	mobj_t *targetPlayerMobj;
+	int inventoryPtr;
+	int currentInvPos;
+	boolean rClass;
+	boolean playerWasReborn;
+	boolean oldWeaponowned[NUMWEAPONS];
+	int oldKeys   = 0; /* jim added initialiser */
+	int oldPieces = 0; /* jim added initialiser */
+	int bestWeapon;
+
+	if (!deathmatch)
+	{
+		if (P_GetMapCluster(gamemap) == P_GetMapCluster(map))
+		{ // Same cluster - save map without saving player mobjs
+			SV_SaveMap(false);
+		}
+		else
+		{ // Entering new cluster - clear base slot
+			ClearSaveSlot(BASE_SLOT);
+		}
+	}
+
+	// Store player structs for later
+	rClass = randomclass;
+	randomclass = false;
+	for (i = 0; i < MAXPLAYERS; i++)
+	{
+		playerBackup[i] = players[i];
+	}
+
+	// Save some globals that get trashed during the load
+	inventoryPtr = inv_ptr;
+	currentInvPos = curpos;
+
+	gamemap = map;
+	snprintf(fileName, sizeof(fileName), "%shex6%02d.hxs", basePath, gamemap);
+	if (!deathmatch && ExistingFile(fileName))
+	{ // Unarchive map
+		SV_LoadMap();
+	}
+	else
+	{ // New map
+		G_InitNew(gameskill, gameepisode, gamemap);
+
+		// Destroy all freshly spawned players
+		for (i = 0; i < MAXPLAYERS; i++)
+		{
+			if (playeringame[i])
+			{
+				P_RemoveMobj(players[i].mo);
+			}
+		}
+	}
+
+	// Restore player structs
+	targetPlayerMobj = NULL;
+	for (i = 0; i < MAXPLAYERS; i++)
+	{
+		if (!playeringame[i])
+		{
+			continue;
+		}
+		players[i] = playerBackup[i];
+		P_ClearMessage(&players[i]);
+		players[i].attacker = NULL;
+		players[i].poisoner = NULL;
+
+		if (netgame)
+		{
+			if (players[i].playerstate == PST_DEAD)
+			{ // In a network game, force all players to be alive
+				players[i].playerstate = PST_REBORN;
+			}
+			if (!deathmatch)
+			{ // Cooperative net-play, retain keys and weapons
+				oldKeys = players[i].keys;
+				oldPieces = players[i].pieces;
+				for (j = 0; j < NUMWEAPONS; j++)
+				{
+					oldWeaponowned[j] = players[i].weaponowned[j];
+				}
+			}
+		}
+		playerWasReborn = (players[i].playerstate == PST_REBORN);
+		if (deathmatch)
+		{
+			memset(players[i].frags, 0, sizeof(players[i].frags));
+			mobj = P_SpawnMobj(playerstarts[0][i].x<<16,
+				playerstarts[0][i].y<<16, 0, MT_PLAYER_FIGHTER);
+			players[i].mo = mobj;
+			G_DeathMatchSpawnPlayer(i);
+			P_RemoveMobj(mobj);
+		}
+		else
+		{
+			P_SpawnPlayer(&playerstarts[position][i]);
+		}
+
+		if (playerWasReborn && netgame && !deathmatch)
+		{ // Restore keys and weapons when reborn in co-op
+			players[i].keys = oldKeys;
+			players[i].pieces = oldPieces;
+			for (bestWeapon = 0, j = 0; j < NUMWEAPONS; j++)
+			{
+				if (oldWeaponowned[j])
+				{
+					bestWeapon = j;
+					players[i].weaponowned[j] = true;
+				}
+			}
+			players[i].mana[MANA_1] = 25;
+			players[i].mana[MANA_2] = 25;
+			if (bestWeapon)
+			{ // Bring up the best weapon
+				players[i].pendingweapon = bestWeapon;
+			}
+		}
+
+		if (targetPlayerMobj == NULL)
+		{ // The poor sap
+			targetPlayerMobj = players[i].mo;
+		}
+	}
+	randomclass = rClass;
+
+	// Redirect anything targeting a player mobj
+	if (TargetPlayerAddrs)
+	{
+		for (i = 0; i < TargetPlayerCount; i++)
+		{
+			*TargetPlayerAddrs[i] = (intptr_t)targetPlayerMobj;
+		}
+		Z_Free(TargetPlayerAddrs);
+		TargetPlayerAddrs = NULL;
+	}
+
+	// Destroy all things touching players
+	for (i = 0; i < MAXPLAYERS; i++)
+	{
+		if (playeringame[i])
+		{
+			P_TeleportMove(players[i].mo, players[i].mo->x, players[i].mo->y);
+		}
+	}
+
+	// Restore trashed globals
+	inv_ptr = inventoryPtr;
+	curpos = currentInvPos;
+
+	// Launch waiting scripts
+	if (!deathmatch)
+	{
+		P_CheckACSStore();
+	}
+
+	// For single play, save immediately into the reborn slot
+	if (!netgame)
+	{
+		SV_SaveGame(REBORN_SLOT, REBORN_DESCRIPTION);
+	}
+}
+
+//==========================================================================
+//
+// SV_GetRebornSlot
+//
+//==========================================================================
+
+int SV_GetRebornSlot(void)
+{
+	return (REBORN_SLOT);
+}
+
+//==========================================================================
+//
+// SV_RebornSlotAvailable
+//
+// Returns true if the reborn slot is available.
+//
+//==========================================================================
+
+boolean SV_RebornSlotAvailable(void)
+{
+	char fileName[MAX_OSPATH];
+
+	snprintf(fileName, sizeof(fileName), "%shex%d.hxs", basePath, REBORN_SLOT);
+	return ExistingFile(fileName);
+}
+
+//==========================================================================
+//
+// SV_LoadMap
+//
+//==========================================================================
+
+void SV_LoadMap(void)
+{
+	char fileName[MAX_OSPATH];
+
+	// Load a base level
+	G_InitNew(gameskill, gameepisode, gamemap);
+
+	// Remove all thinkers
+	RemoveAllThinkers();
+
+	// Create the name
+	snprintf(fileName, sizeof(fileName), "%shex6%02d.hxs", basePath, gamemap);
+
+	// Load the file
+	M_ReadFile(fileName, &SaveBuffer);
+	SavePtr = (byte *) SaveBuffer;
+
+	AssertSegment(ASEG_MAP_HEADER);
+
+	// Read the level timer
+	leveltime = GET_LONG();
+
+	UnarchiveWorld();
+	UnarchivePolyobjs();
+	UnarchiveMobjs();
+	UnarchiveThinkers();
+	UnarchiveScripts();
+	UnarchiveSounds();
+	UnarchiveMisc();
+
+	AssertSegment(ASEG_END);
+
+	// Free mobj list and save buffer
+	Z_Free(MobjList);
+	Z_Free(SaveBuffer);
+}
+
+//==========================================================================
+//
+// SV_InitBaseSlot
+//
+//==========================================================================
+
+void SV_InitBaseSlot(void)
+{
+	ClearSaveSlot(BASE_SLOT);
+}
+
+//==========================================================================
+//
+// ArchivePlayers
+//
+//==========================================================================
+
+static void ArchivePlayers(void)
+{
+	int i, j;
+	save_player_t savp;
+	player_t *p;
+
+	StreamOutLong(ASEG_PLAYERS);
+	for (i = 0; i < MAXPLAYERS; i++)
+	{
+		StreamOutByte(playeringame[i]);
+	}
+	for (i = 0; i < MAXPLAYERS; i++)
+	{
+		if (!playeringame[i])
+		{
+			continue;
+		}
+		StreamOutByte(PlayerClasses[i]);
+
+		p = &players[i];
+		savp.mo_idx = 0;
+		savp.poisoner_idx = 0;
+		savp.attacker_idx = 0;
+		savp.playerstate	= (int) LONG(p->playerstate);
+		savp.cmd.forwardmove	= p->cmd.forwardmove;
+		savp.cmd.sidemove	= p->cmd.sidemove;
+		savp.cmd.angleturn	= (short) SHORT(p->cmd.angleturn);
+		savp.cmd.consistancy	= (short) SHORT(p->cmd.consistancy);
+		savp.cmd.chatchar	= p->cmd.chatchar;
+		savp.cmd.buttons	= p->cmd.buttons;
+		savp.cmd.lookfly	= p->cmd.lookfly;
+		savp.cmd.arti		= p->cmd.arti;
+		savp.playerclass	= (int) LONG(p->playerclass);
+		savp.viewz		= (fixed_t) LONG(p->viewz);
+		savp.viewheight		= (fixed_t) LONG(p->viewheight);
+		savp.deltaviewheight	= (fixed_t) LONG(p->deltaviewheight);
+		savp.bob		= (fixed_t) LONG(p->bob);
+		savp.flyheight		= (int) LONG(p->flyheight);
+		savp.lookdir		= (int) LONG(p->lookdir);
+		savp.centering		= (int) LONG(p->centering);
+		savp.health		= (int) LONG(p->health);
+		for (j = 0; j < NUMARMOR; j++)
+		{
+			savp.armorpoints[j] = (int) LONG(p->armorpoints[j]);
+		}
+		for (j = 0; j < NUMINVENTORYSLOTS; j++)
+		{
+			savp.inventory[j].type = (int) LONG(p->inventory[j].type);
+			savp.inventory[j].count = (int) LONG(p->inventory[j].count);
+		}
+		savp.readyArtifact	= (int) LONG(p->readyArtifact);
+		savp.inventorySlotNum	= (int) LONG(p->inventorySlotNum);
+		savp.artifactCount	= (int) LONG(p->artifactCount);
+		for (j = 0; j < NUMPOWERS; j++)
+		{
+			savp.powers[j]	= (int) LONG(p->powers[j]);
+		}
+		savp.keys		= (int) LONG(p->keys);
+		savp.pieces		= (int) LONG(p->pieces);
+		for (j = 0; j < MAXPLAYERS; j++)
+		{
+			savp.frags[j]	= (signed int) LONG(p->frags[j]);
+		}
+		savp.readyweapon	= (int) LONG(p->readyweapon);
+		savp.pendingweapon	= (int) LONG(p->pendingweapon);
+		for (j = 0; j < NUMWEAPONS; j++)
+		{
+			savp.weaponowned[j] = (int) LONG(p->weaponowned[j]);
+		}
+		for (j = 0; j < NUMMANA; j++)
+		{
+			savp.mana[j]	= (int) LONG(p->mana[j]);
+		}
+		savp.attackdown		= (int) LONG(p->attackdown);
+		savp.usedown		= (int) LONG(p->usedown);
+		savp.cheats		= (int) LONG(p->cheats);
+		savp.refire		= (int) LONG(p->refire);
+		savp.killcount		= (int) LONG(p->killcount);
+		savp.itemcount		= (int) LONG(p->itemcount);
+		savp.secretcount	= (int) LONG(p->secretcount);
+		memcpy (savp.message, p->message, 80);
+		savp.messageTics	= (int) LONG(p->messageTics);
+		savp.ultimateMessage	= (short) SHORT(p->ultimateMessage);
+		savp.yellowMessage	= (short) SHORT(p->yellowMessage);
+		savp.damagecount	= (int) LONG(p->damagecount);
+		savp.bonuscount		= (int) LONG(p->bonuscount);
+		savp.poisoncount	= (int) LONG(p->poisoncount);
+		savp.extralight		= (int) LONG(p->extralight);
+		savp.fixedcolormap	= (int) LONG(p->fixedcolormap);
+		savp.colormap		= (int) LONG(p->colormap);
+		savp.morphTics		= (int) LONG(p->morphTics);
+		savp.jumpTics		= (unsigned int) LONG(p->jumpTics);
+		savp.worldTimer		= (unsigned int) LONG(p->worldTimer);
+		for (j = 0; j < NUMPSPRITES; j++)
+		{
+			savp.psprites[j].tics = (int) LONG(p->psprites[j].tics);
+			savp.psprites[j].sx = (fixed_t) LONG(p->psprites[j].sx);
+			savp.psprites[j].sy = (fixed_t) LONG(p->psprites[j].sy);
+			if (p->psprites[j].state)
+			{
+				savp.psprites[j].state_idx =
+					LONG((int32_t) (p->psprites[j].state - states));
+			}
+			else
+			{
+				savp.psprites[j].state_idx = 0;
+			}
+		}
+		StreamOutBuffer(&savp, sizeof(save_player_t));
+	}
+}
+
+//==========================================================================
+//
+// UnarchivePlayers
+//
+//==========================================================================
+
+static void UnarchivePlayers(void)
+{
+	int i, j;
+	save_player_t savp;
+	player_t *p;
+
+	AssertSegment(ASEG_PLAYERS);
+	for (i = 0; i < MAXPLAYERS; i++)
+	{
+		playeringame[i] = GET_BYTE();
+	}
+	for (i = 0; i < MAXPLAYERS; i++)
+	{
+		if (!playeringame[i])
+		{
+			continue;
+		}
+		PlayerClasses[i] = GET_BYTE();
+		memcpy(&savp, SavePtr, sizeof(save_player_t));
+		SavePtr += sizeof(save_player_t);
+
+		p = &players[i];
+		p->mo = NULL; // Will be set when unarc thinker
+		p->attacker = NULL;
+		p->poisoner = NULL;
+		p->playerstate		= (playerstate_t) LONG(savp.playerstate);
+		p->cmd.forwardmove	= savp.cmd.forwardmove;
+		p->cmd.sidemove		= savp.cmd.sidemove;
+		p->cmd.angleturn	= (short) SHORT(savp.cmd.angleturn);
+		p->cmd.consistancy	= (short) SHORT(savp.cmd.consistancy);
+		p->cmd.chatchar		= savp.cmd.chatchar;
+		p->cmd.buttons		= savp.cmd.buttons;
+		p->cmd.lookfly		= savp.cmd.lookfly;
+		p->cmd.arti		= savp.cmd.arti;
+		p->playerclass		= (pclass_t) LONG(savp.playerclass);
+		p->viewz		= (fixed_t) LONG(savp.viewz);
+		p->viewheight		= (fixed_t) LONG(savp.viewheight);
+		p->deltaviewheight	= (fixed_t) LONG(savp.deltaviewheight);
+		p->bob			= (fixed_t) LONG(savp.bob);
+		p->flyheight		= (int) LONG(savp.flyheight);
+		p->lookdir		= (int) LONG(savp.lookdir);
+		p->centering		= !!(LONG(savp.centering));
+		p->health		= (int) LONG(savp.health);
+		for (j = 0; j < NUMARMOR; j++)
+		{
+			p->armorpoints[j] = (int) LONG(savp.armorpoints[j]);
+		}
+		for (j = 0; j < NUMINVENTORYSLOTS; j++)
+		{
+			p->inventory[j].type = (int) LONG(savp.inventory[j].type);
+			p->inventory[j].count = (int) LONG(savp.inventory[j].count);
+		}
+		p->readyArtifact	= (artitype_t) LONG(savp.readyArtifact);
+		p->artifactCount	= (int) LONG(savp.artifactCount);
+		p->inventorySlotNum	= (int) LONG(savp.inventorySlotNum);
+		for (j = 0; j < NUMPOWERS; j++)
+		{
+			p->powers[j]	= (int) LONG(savp.powers[j]);
+		}
+		p->keys			= (int) LONG(savp.keys);
+		p->pieces		= (int) LONG(savp.pieces);
+		for (j = 0; j < MAXPLAYERS; j++)
+		{
+			p->frags[j]	= (signed int) LONG(savp.frags[j]);
+		}
+		p->readyweapon		= (weapontype_t) LONG(savp.readyweapon);
+		p->pendingweapon	= (weapontype_t) LONG(savp.pendingweapon);
+		for (j = 0; j < NUMWEAPONS; j++)
+		{
+			p->weaponowned[j] = !!(LONG(savp.weaponowned[j]));
+		}
+		for (j = 0; j < NUMMANA; j++)
+		{
+			p->mana[j]	= (int) LONG(savp.mana[j]);
+		}
+		p->attackdown		= (int) LONG(savp.attackdown);
+		p->usedown		= (int) LONG(savp.usedown);
+		p->cheats		= (int) LONG(savp.cheats);
+		p->refire		= (int) LONG(savp.refire);
+		p->killcount		= (int) LONG(savp.killcount);
+		p->itemcount		= (int) LONG(savp.itemcount);
+		p->secretcount		= (int) LONG(savp.secretcount);
+		memcpy (p->message, savp.message, 80);
+		p->messageTics		= (int) LONG(savp.messageTics);
+		p->ultimateMessage	= (short) SHORT(savp.ultimateMessage);
+		p->yellowMessage	= (short) SHORT(savp.yellowMessage);
+		p->damagecount		= (int) LONG(savp.damagecount);
+		p->bonuscount		= (int) LONG(savp.bonuscount);
+		p->poisoncount		= (int) LONG(savp.poisoncount);
+		p->extralight		= (int) LONG(savp.extralight);
+		p->fixedcolormap	= (int) LONG(savp.fixedcolormap);
+		p->colormap		= (int) LONG(savp.colormap);
+		p->morphTics		= (int) LONG(savp.morphTics);
+		p->jumpTics		= (unsigned int) LONG(savp.jumpTics);
+		p->worldTimer		= (unsigned int) LONG(savp.worldTimer);
+		P_ClearMessage(p);
+		for (j = 0; j < NUMPSPRITES; j++)
+		{
+			p->psprites[j].tics = (int) LONG(savp.psprites[j].tics);
+			p->psprites[j].sx = (fixed_t) LONG(savp.psprites[j].sx);
+			p->psprites[j].sy = (fixed_t) LONG(savp.psprites[j].sy);
+			if (savp.psprites[j].state_idx)
+			{
+				savp.psprites[j].state_idx =
+					LONG(savp.psprites[j].state_idx);
+				p->psprites[j].state =
+					&states[savp.psprites[j].state_idx];
+			}
+			else
+			{
+				p->psprites[j].state = NULL;
+			}
+		}
+	}
+}
+
+//==========================================================================
+//
+// ArchiveWorld
+//
+//==========================================================================
+
+static void ArchiveWorld(void)
+{
+	int i;
+	int j;
+	sector_t *sec;
+	line_t *li;
+	side_t *si;
+
+	StreamOutLong(ASEG_WORLD);
+	for (i = 0, sec = sectors; i < numsectors; i++, sec++)
+	{
+		StreamOutWord(sec->floorheight>>FRACBITS);
+		StreamOutWord(sec->ceilingheight>>FRACBITS);
+		StreamOutWord(sec->floorpic);
+		StreamOutWord(sec->ceilingpic);
+		StreamOutWord(sec->lightlevel);
+		StreamOutWord(sec->special);
+		StreamOutWord(sec->tag);
+		StreamOutWord(sec->seqType);
+	}
+	for (i = 0, li = lines; i < numlines; i++, li++)
+	{
+		StreamOutWord(li->flags);
+		StreamOutByte(li->special);
+		StreamOutByte(li->arg1);
+		StreamOutByte(li->arg2);
+		StreamOutByte(li->arg3);
+		StreamOutByte(li->arg4);
+		StreamOutByte(li->arg5);
+		for (j = 0; j < 2; j++)
+		{
+			if (li->sidenum[j] == -1)
+			{
+				continue;
+			}
+			si = &sides[li->sidenum[j]];
+			StreamOutWord(si->textureoffset>>FRACBITS);
+			StreamOutWord(si->rowoffset>>FRACBITS);
+			StreamOutWord(si->toptexture);
+			StreamOutWord(si->bottomtexture);
+			StreamOutWord(si->midtexture);
+		}
+	}
+}
+
+//==========================================================================
+//
+// UnarchiveWorld
+//
+//==========================================================================
+
+static void UnarchiveWorld(void)
+{
+	int i;
+	int j;
+	sector_t *sec;
+	line_t *li;
+	side_t *si;
+
+	AssertSegment(ASEG_WORLD);
+	for (i = 0, sec = sectors; i < numsectors; i++, sec++)
+	{
+		sec->floorheight = ((fixed_t) GET_WORD())<<FRACBITS;
+		sec->ceilingheight = ((fixed_t) GET_WORD())<<FRACBITS;
+		sec->floorpic = GET_WORD();
+		sec->ceilingpic = GET_WORD();
+		sec->lightlevel = GET_WORD();
+		sec->special = GET_WORD();
+		sec->tag = GET_WORD();
+		sec->seqType = GET_WORD();
+		sec->specialdata = NULL;
+		sec->soundtarget = NULL;
+	}
+	for (i = 0, li = lines; i < numlines; i++, li++)
+	{
+		li->flags = GET_WORD();
+		li->special = GET_BYTE();
+		li->arg1 = GET_BYTE();
+		li->arg2 = GET_BYTE();
+		li->arg3 = GET_BYTE();
+		li->arg4 = GET_BYTE();
+		li->arg5 = GET_BYTE();
+		for (j = 0; j < 2; j++)
+		{
+			if (li->sidenum[j] == -1)
+			{
+				continue;
+			}
+			si = &sides[li->sidenum[j]];
+			si->textureoffset = ((fixed_t) GET_WORD())<<FRACBITS;
+			si->rowoffset = ((fixed_t) GET_WORD())<<FRACBITS;
+			si->toptexture = GET_WORD();
+			si->bottomtexture = GET_WORD();
+			si->midtexture = GET_WORD();
+		}
+	}
+}
+
+//==========================================================================
+//
+// SetMobjArchiveNums
+//
+// Sets the archive numbers in all mobj structs.  Also sets the MobjCount
+// global.  Ignores player mobjs if SavingPlayers is false.
+//
+//==========================================================================
+
+static void SetMobjArchiveNums(void)
+{
+	mobj_t *mobj;
+	thinker_t *thinker;
+
+	MobjCount = 0;
+	for (thinker = thinkercap.next; thinker != &thinkercap;
+					thinker = thinker->next)
+	{
+		if (thinker->function == P_MobjThinker)
+		{
+			mobj = (mobj_t *)thinker;
+			if (mobj->player && !SavingPlayers)
+			{ // Skipping player mobjs
+				continue;
+			}
+			mobj->archiveNum = MobjCount++;
+		}
+	}
+}
+
+//==========================================================================
+//
+// ArchiveMobjs
+//
+//==========================================================================
+
+static void ArchiveMobjs(void)
+{
+	int count;
+	thinker_t *thinker;
+	save_mobj_t tempMobj;
+	mobj_t *mobj;
+
+	StreamOutLong(ASEG_MOBJS);
+	StreamOutLong(MobjCount);
+	count = 0;
+	for (thinker = thinkercap.next; thinker != &thinkercap;
+					thinker = thinker->next)
+	{
+		if (thinker->function != P_MobjThinker)
+		{ // Not a mobj thinker
+			continue;
+		}
+		mobj = (mobj_t *)thinker;
+		if (mobj->player && !SavingPlayers)
+		{ // Skipping player mobjs
+			continue;
+		}
+		count++;
+		memset(&tempMobj, 0, sizeof(save_mobj_t));
+		MangleMobj(mobj, &tempMobj);
+		StreamOutBuffer(&tempMobj, sizeof(save_mobj_t));
+	}
+	if (count != MobjCount)
+	{
+		I_Error("ArchiveMobjs: bad mobj count");
+	}
+}
+
+//==========================================================================
+//
+// UnarchiveMobjs
+//
+//==========================================================================
+
+static void UnarchiveMobjs(void)
+{
+	int i;
+	save_mobj_t tempMobj;
+	mobj_t *mobj;
+
+	AssertSegment(ASEG_MOBJS);
+	TargetPlayerAddrs = (intptr_t **) Z_Malloc(MAX_TARGET_PLAYERS*sizeof(intptr_t *), PU_STATIC, NULL);
+	TargetPlayerCount = 0;
+	MobjCount = GET_LONG();
+	MobjList = (mobj_t **) Z_Malloc(MobjCount*sizeof(mobj_t *), PU_STATIC, NULL);
+	for (i = 0; i < MobjCount; i++)
+	{
+		MobjList[i] = (mobj_t *) Z_Malloc(sizeof(mobj_t), PU_LEVEL, NULL);
+	}
+	for (i = 0; i < MobjCount; i++)
+	{
+		mobj = MobjList[i];
+		memset(&tempMobj, 0, sizeof(save_mobj_t));
+		memset(mobj, 0, sizeof(mobj_t));
+		memcpy(&tempMobj, SavePtr, sizeof(save_mobj_t));
+		SavePtr += sizeof(save_mobj_t);
+		RestoreMobj(mobj, &tempMobj);
+		P_AddThinker(&mobj->thinker);
+	}
+	P_CreateTIDList();
+	P_InitCreatureCorpseQueue(true); // true = scan for corpses
+}
+
+//==========================================================================
+//
+// MangleMobj
+//
+//==========================================================================
+
+static void MangleMobj(mobj_t *mobj, save_mobj_t *temp)
+{
+	boolean corpse;
+
+	temp->x			= (fixed_t) LONG(mobj->x);
+	temp->y			= (fixed_t) LONG(mobj->y);
+	temp->z			= (fixed_t) LONG(mobj->z);
+	temp->angle		= (angle_t) LONG(mobj->angle);
+	temp->sprite		= (int) LONG(mobj->sprite);
+	temp->frame		= (int) LONG(mobj->frame);
+	temp->floorpic		= (fixed_t) LONG(mobj->floorpic);
+	temp->radius		= (fixed_t) LONG(mobj->radius);
+	temp->height		= (fixed_t) LONG(mobj->height);
+	temp->momx		= (fixed_t) LONG(mobj->momx);
+	temp->momy		= (fixed_t) LONG(mobj->momy);
+	temp->momz		= (fixed_t) LONG(mobj->momz);
+	temp->validcount	= (int) LONG(mobj->validcount);
+	temp->type		= (int) LONG(mobj->type);
+	temp->tics		= (int) LONG(mobj->tics);
+	temp->damage		= (int) LONG(mobj->damage);
+	temp->flags		= (int) LONG(mobj->flags);
+	temp->flags2		= (int) LONG(mobj->flags2);
+	temp->health		= (int) LONG(mobj->health);
+	temp->movedir		= (int) LONG(mobj->movedir);
+	temp->movecount		= (int) LONG(mobj->movecount);
+	temp->reactiontime	= (int) LONG(mobj->reactiontime);
+	temp->threshold		= (int) LONG(mobj->threshold);
+	temp->lastlook		= (int) LONG(mobj->lastlook);
+	temp->floorclip		= (fixed_t) LONG(mobj->floorclip);
+	temp->archiveNum	= (int) LONG(mobj->archiveNum);
+	temp->tid		= (short) SHORT(mobj->tid);
+	temp->special		= mobj->special;
+	temp->args[0]		= mobj->args[0];
+	temp->args[1]		= mobj->args[1];
+	temp->args[2]		= mobj->args[2];
+	temp->args[3]		= mobj->args[3];
+	temp->args[4]		= mobj->args[4];
+
+	corpse = mobj->flags & MF_CORPSE;
+	temp->state_idx = LONG((int32_t)(mobj->state - states));
+	if (mobj->player)
+	{
+		temp->player_idx = LONG((int32_t)((mobj->player - players) + 1));
+	}
+	if (corpse)
+	{
+		temp->target_idx = (int32_t) LONG(MOBJ_NULL);
+	}
+	else
+	{
+		temp->target_idx = (int32_t) LONG(GetMobjNum(mobj->target));
+	}
+	switch (mobj->type)
+	{
+	// Just special1
+	case MT_BISH_FX:
+	case MT_HOLY_FX:
+	case MT_DRAGON:
+	case MT_THRUSTFLOOR_UP:
+	case MT_THRUSTFLOOR_DOWN:
+	case MT_MINOTAUR:
+	case MT_SORCFX1:
+	case MT_MSTAFF_FX2:
+		if (corpse)
+		{
+			temp->special1 = (int32_t) LONG(MOBJ_NULL);
+		}
+		else
+		{
+			temp->special1 = (int32_t) LONG(GetMobjNum((mobj_t *)mobj->special1));
+		}
+		break;
+
+	// Just special2
+	case MT_LIGHTNING_FLOOR:
+	case MT_LIGHTNING_ZAP:
+		if (corpse)
+		{
+			temp->special2 = (int32_t) LONG(MOBJ_NULL);
+		}
+		else
+		{
+			temp->special2 = (int32_t) LONG(GetMobjNum((mobj_t *)mobj->special2));
+		}
+		break;
+
+	// Both special1 and special2
+	case MT_HOLY_TAIL:
+	case MT_LIGHTNING_CEILING:
+		if (corpse)
+		{
+			temp->special1 = (int32_t) LONG(MOBJ_NULL);
+			temp->special2 = (int32_t) LONG(MOBJ_NULL);
+		}
+		else
+		{
+			temp->special1 = (int32_t) LONG(GetMobjNum((mobj_t *)mobj->special1));
+			temp->special2 = (int32_t) LONG(GetMobjNum((mobj_t *)mobj->special2));
+		}
+		break;
+
+	// Miscellaneous
+	case MT_KORAX:
+		temp->special1 = 0; // Searching index
+		break;
+
+	default:
+		break;
+	}
+}
+
+//==========================================================================
+//
+// GetMobjNum
+//
+//==========================================================================
+
+static int32_t GetMobjNum(mobj_t *mobj)
+{
+	if (mobj == NULL)
+	{
+		return MOBJ_NULL;
+	}
+	if (mobj->player && !SavingPlayers)
+	{
+		return MOBJ_XX_PLAYER;
+	}
+	return mobj->archiveNum;
+}
+
+//==========================================================================
+//
+// RestoreMobj
+//
+//==========================================================================
+
+static void RestoreMobj(mobj_t *mobj, save_mobj_t *temp)
+{
+	mobj->x			= (fixed_t) LONG(temp->x);
+	mobj->y			= (fixed_t) LONG(temp->y);
+	mobj->z			= (fixed_t) LONG(temp->z);
+	mobj->angle		= (angle_t) LONG(temp->angle);
+	mobj->sprite		= (spritenum_t) LONG(temp->sprite);
+	mobj->frame		= (int) LONG(temp->frame);
+	mobj->floorpic		= (fixed_t) LONG(temp->floorpic);
+	mobj->radius		= (fixed_t) LONG(temp->radius);
+	mobj->height		= (fixed_t) LONG(temp->height);
+	mobj->momx		= (fixed_t) LONG(temp->momx);
+	mobj->momy		= (fixed_t) LONG(temp->momy);
+	mobj->momz		= (fixed_t) LONG(temp->momz);
+	mobj->validcount	= (int) LONG(temp->validcount);
+	mobj->type		= (mobjtype_t) LONG(temp->type);
+	mobj->tics		= (int) LONG(temp->tics);
+	mobj->damage		= (int) LONG(temp->damage);
+	mobj->flags		= (int) LONG(temp->flags);
+	mobj->flags2		= (int) LONG(temp->flags2);
+	mobj->health		= (int) LONG(temp->health);
+	mobj->movedir		= (int) LONG(temp->movedir);
+	mobj->movecount		= (int) LONG(temp->movecount);
+	mobj->reactiontime	= (int) LONG(temp->reactiontime);
+	mobj->threshold		= (int) LONG(temp->threshold);
+	mobj->lastlook		= (int) LONG(temp->lastlook);
+	mobj->floorclip		= (fixed_t) LONG(temp->floorclip);
+	mobj->archiveNum	= (int) LONG(temp->archiveNum);
+	mobj->tid		= (short) SHORT(temp->tid);
+	mobj->special		= temp->special;
+	mobj->args[0]		= temp->args[0];
+	mobj->args[1]		= temp->args[1];
+	mobj->args[2]		= temp->args[2];
+	mobj->args[3]		= temp->args[3];
+	mobj->args[4]		= temp->args[4];
+
+	temp->state_idx		= (int32_t) LONG(temp->state_idx);
+	temp->player_idx	= (int32_t) LONG(temp->player_idx);
+	temp->target_idx	= (int32_t) LONG(temp->target_idx);
+	temp->special1		= (int32_t) LONG(temp->special1);
+	temp->special2		= (int32_t) LONG(temp->special2);
+
+	mobj->thinker.function	= P_MobjThinker;
+	mobj->state		= &states[temp->state_idx];
+	if (temp->player_idx)
+	{
+		mobj->player	= &players[temp->player_idx - 1];
+		mobj->player->mo = mobj;
+	}
+	P_SetThingPosition(mobj);
+	mobj->info = &mobjinfo[mobj->type];
+	mobj->floorz = mobj->subsector->sector->floorheight;
+	mobj->ceilingz = mobj->subsector->sector->ceilingheight;
+	mobj->target = GetMobjPtr(temp->target_idx, (intptr_t *)(void *)&mobj->target);
+	switch (mobj->type)
+	{
+	// Just special1
+	case MT_BISH_FX:
+	case MT_HOLY_FX:
+	case MT_DRAGON:
+	case MT_THRUSTFLOOR_UP:
+	case MT_THRUSTFLOOR_DOWN:
+	case MT_MINOTAUR:
+	case MT_SORCFX1:
+		mobj->special1 = (intptr_t) GetMobjPtr(temp->special1, &mobj->special1);
+		break;
+
+	// Just special2
+	case MT_LIGHTNING_FLOOR:
+	case MT_LIGHTNING_ZAP:
+		mobj->special2 = (intptr_t) GetMobjPtr(temp->special2, &mobj->special2);
+		break;
+
+	// Both special1 and special2
+	case MT_HOLY_TAIL:
+	case MT_LIGHTNING_CEILING:
+		mobj->special1 = (intptr_t) GetMobjPtr(temp->special1, &mobj->special1);
+		mobj->special2 = (intptr_t) GetMobjPtr(temp->special2, &mobj->special2);
+		break;
+
+	default:
+		break;
+	}
+}
+
+//==========================================================================
+//
+// GetMobjPtr
+//
+//==========================================================================
+
+static mobj_t *GetMobjPtr(int32_t archiveNum, intptr_t *target)
+{
+	if (archiveNum == MOBJ_NULL)
+	{
+		return NULL;
+	}
+	if (archiveNum == MOBJ_XX_PLAYER)
+	{
+		if (TargetPlayerCount == MAX_TARGET_PLAYERS)
+		{
+			I_Error("RestoreMobj: exceeded MAX_TARGET_PLAYERS");
+		}
+		TargetPlayerAddrs[TargetPlayerCount++] = target;
+		return NULL;
+	}
+	return MobjList[archiveNum];
+}
+
+//==========================================================================
+//
+// ArchiveThinkers
+//
+//==========================================================================
+
+static void ArchiveThinkers(void)
+{
+	thinker_t *thinker;
+	thinkInfo_t *info;
+	byte buffer[MAX_THINKER_SIZE];
+
+	StreamOutLong(ASEG_THINKERS);
+	for (thinker = thinkercap.next; thinker != &thinkercap;
+					thinker = thinker->next)
+	{
+		for (info = ThinkerInfo; info->tClass != TC_NULL; info++)
+		{
+			if (thinker->function == info->thinkerFunc)
+			{
+				StreamOutByte(info->tClass);
+				memset(buffer, 0, sizeof(buffer));
+				info->mangleFunc(thinker, buffer);
+				StreamOutBuffer(buffer, info->savesize);
+				break;
+			}
+		}
+	}
+	// Add a termination marker
+	StreamOutByte(TC_NULL);
+}
+
+//==========================================================================
+//
+// UnarchiveThinkers
+//
+//==========================================================================
+
+static void UnarchiveThinkers(void)
+{
+	int tClass;
+	thinker_t *thinker;
+	thinkInfo_t *info;
+	byte buffer[MAX_THINKER_SIZE];
+
+	AssertSegment(ASEG_THINKERS);
+	while ((tClass = GET_BYTE()) != TC_NULL)
+	{
+		for (info = ThinkerInfo; info->tClass != TC_NULL; info++)
+		{
+			if (tClass == info->tClass)
+			{
+				thinker = (thinker_t *) Z_Malloc(info->realsize, PU_LEVEL, NULL);
+				memset(thinker, 0, info->realsize);
+				memset(buffer, 0, sizeof(buffer));
+				memcpy(buffer, SavePtr, info->savesize);
+				SavePtr += info->savesize;
+				thinker->function = info->thinkerFunc;
+				info->restoreFunc(thinker, buffer);
+				P_AddThinker(thinker);
+				break;
+			}
+		}
+		if (info->tClass == TC_NULL)
+		{
+			I_Error("UnarchiveThinkers: Unknown tClass %d in savegame", tClass);
+		}
+	}
+}
+
+//==========================================================================
+//
+// MangleFloorMove
+//
+//==========================================================================
+
+static void MangleFloorMove(void *arg1, void *arg2)
+{
+	floormove_t	*fm	= (floormove_t *)	arg1;
+	save_floormove_t *temp	= (save_floormove_t *)	arg2;
+
+	temp->sector_idx	= LONG((int32_t)(fm->sector - sectors));
+	temp->type		= (int) LONG(fm->type);
+	temp->crush		= (int) LONG(fm->crush);
+	temp->direction		= (int) LONG(fm->direction);
+	temp->newspecial	= (int) LONG(fm->newspecial);
+	temp->texture		= (short) SHORT(fm->texture);
+	temp->floordestheight	= (fixed_t) LONG(fm->floordestheight);
+	temp->speed		= (fixed_t) LONG(fm->speed);
+	temp->delayCount	= (int) LONG(fm->delayCount);
+	temp->delayTotal	= (int) LONG(fm->delayTotal);
+	temp->stairsDelayHeight	= (fixed_t) LONG(fm->stairsDelayHeight);
+	temp->stairsDelayHeightDelta = (fixed_t) LONG(fm->stairsDelayHeightDelta);
+	temp->resetHeight	= (fixed_t) LONG(fm->resetHeight);
+	temp->resetDelay	= (short) SHORT(fm->resetDelay);
+	temp->resetDelayCount	= (short) SHORT(fm->resetDelayCount);
+	temp->textureChange	= fm->textureChange;
+}
+
+//==========================================================================
+//
+// RestoreFloorMove
+//
+//==========================================================================
+
+static void RestoreFloorMove(void *arg1, void *arg2)
+{
+	floormove_t	*fm	= (floormove_t *)	arg1;
+	save_floormove_t *temp	= (save_floormove_t *)	arg2;
+
+	temp->sector_idx	= LONG(temp->sector_idx);
+	fm->sector		= &sectors[temp->sector_idx];
+	fm->sector->specialdata	= T_MoveFloor;	//fm->thinker.function
+	fm->type		= (floor_e) LONG(temp->type);
+	fm->crush		= (int) LONG(temp->crush);
+	fm->direction		= (int) LONG(temp->direction);
+	fm->newspecial		= (int) LONG(temp->newspecial);
+	fm->texture		= (short) SHORT(temp->texture);
+	fm->floordestheight	= (fixed_t) LONG(temp->floordestheight);
+	fm->speed		= (fixed_t) LONG(temp->speed);
+	fm->delayCount		= (int) LONG(temp->delayCount);
+	fm->delayTotal		= (int) LONG(temp->delayTotal);
+	fm->stairsDelayHeight	= (fixed_t) LONG(temp->stairsDelayHeight);
+	fm->stairsDelayHeightDelta = (fixed_t) LONG(temp->stairsDelayHeightDelta);
+	fm->resetHeight		= (fixed_t) LONG(temp->resetHeight);
+	fm->resetDelay		= (short) SHORT(temp->resetDelay);
+	fm->resetDelayCount	= (short) SHORT(temp->resetDelayCount);
+	fm->textureChange	= temp->textureChange;
+}
+
+//==========================================================================
+//
+// MangleLight
+//
+//==========================================================================
+
+static void MangleLight(void *arg1, void *arg2)
+{
+	light_t		*light	= (light_t *)	arg1;
+	save_light_t	*temp	= (save_light_t *) arg2;
+
+	temp->sector_idx	= LONG((int32_t)(light->sector - sectors));
+	temp->type		= (int) LONG(light->type);
+	temp->value1		= (int) LONG(light->value1);
+	temp->value2		= (int) LONG(light->value2);
+	temp->tics1		= (int) LONG(light->tics1);
+	temp->tics2		= (int) LONG(light->tics2);
+	temp->count		= (int) LONG(light->count);
+}
+
+//==========================================================================
+//
+// RestoreLight
+//
+//==========================================================================
+
+static void RestoreLight(void *arg1, void *arg2)
+{
+	light_t		*light	= (light_t *)	arg1;
+	save_light_t	*temp	= (save_light_t *) arg2;
+
+	temp->sector_idx	= LONG(temp->sector_idx);
+	light->sector		= &sectors[temp->sector_idx];
+	light->type		= (lighttype_t) LONG(temp->type);
+	light->value1		= (int) LONG(temp->value1);
+	light->value2		= (int) LONG(temp->value2);
+	light->tics1		= (int) LONG(temp->tics1);
+	light->tics2		= (int) LONG(temp->tics2);
+	light->count		= (int) LONG(temp->count);
+}
+
+//==========================================================================
+//
+// MangleVerticalDoor
+//
+//==========================================================================
+
+static void MangleVerticalDoor(void *arg1, void *arg2)
+{
+	vldoor_t	*vldoor = (vldoor_t *)	arg1;
+	save_vldoor_t	*temp	= (save_vldoor_t *) arg2;
+
+	temp->sector_idx	= LONG((int32_t)(vldoor->sector - sectors));
+	temp->type		= (int) LONG(vldoor->type);
+	temp->topheight		= (fixed_t) LONG(vldoor->topheight);
+	temp->speed		= (fixed_t) LONG(vldoor->speed);
+	temp->direction		= (int) LONG(vldoor->direction);
+	temp->topwait		= (int) LONG(vldoor->topwait);
+	temp->topcountdown	= (int) LONG(vldoor->topcountdown);
+}
+
+//==========================================================================
+//
+// RestoreVerticalDoor
+//
+//==========================================================================
+
+static void RestoreVerticalDoor(void *arg1, void *arg2)
+{
+	vldoor_t	*vldoor = (vldoor_t *)	arg1;
+	save_vldoor_t	*temp	= (save_vldoor_t *) arg2;
+
+	temp->sector_idx	= LONG(temp->sector_idx);
+	vldoor->sector		= &sectors[temp->sector_idx];
+	vldoor->sector->specialdata = T_VerticalDoor;	//vldoor->thinker.function
+	vldoor->type		= (vldoor_e) LONG(temp->type);
+	vldoor->topheight	= (fixed_t) LONG(temp->topheight);
+	vldoor->speed		= (fixed_t) LONG(temp->speed);
+	vldoor->direction	= (int) LONG(temp->direction);
+	vldoor->topwait		= (int) LONG(temp->topwait);
+	vldoor->topcountdown	= (int) LONG(temp->topcountdown);
+}
+
+//==========================================================================
+//
+// ManglePhase
+//
+//==========================================================================
+
+static void ManglePhase(void *arg1, void *arg2)
+{
+	phase_t		*phase	= (phase_t *)	arg1;
+	save_phase_t	*temp	= (save_phase_t *) arg2;
+
+	temp->sector_idx	= LONG((int32_t)(phase->sector - sectors));
+	temp->index		= (int) LONG(phase->index);
+	temp->base		= (int) LONG(phase->base);
+}
+
+//==========================================================================
+//
+// RestorePhase
+//
+//==========================================================================
+
+static void RestorePhase(void *arg1, void *arg2)
+{
+	phase_t		*phase	= (phase_t *)	arg1;
+	save_phase_t	*temp	= (save_phase_t *) arg2;
+
+	temp->sector_idx	= LONG(temp->sector_idx);
+	phase->sector		= &sectors[temp->sector_idx];
+	phase->index		= (int) LONG(temp->index);
+	phase->base		= (int) LONG(temp->base);
+}
+
+//==========================================================================
+//
+// ManglePillar
+//
+//==========================================================================
+
+static void ManglePillar(void *arg1, void *arg2)
+{
+	pillar_t	*pillar = (pillar_t *)	arg1;
+	save_pillar_t	*temp	= (save_pillar_t *) arg2;
+
+	temp->sector_idx	= LONG((int32_t)(pillar->sector - sectors));
+	temp->ceilingSpeed	= (int) LONG(pillar->ceilingSpeed);
+	temp->floorSpeed	= (int) LONG(pillar->floorSpeed);
+	temp->floordest		= (int) LONG(pillar->floordest);
+	temp->ceilingdest	= (int) LONG(pillar->ceilingdest);
+	temp->direction		= (int) LONG(pillar->direction);
+	temp->crush		= (int) LONG(pillar->crush);
+}
+
+//==========================================================================
+//
+// RestorePillar
+//
+//==========================================================================
+
+static void RestorePillar(void *arg1, void *arg2)
+{
+	pillar_t	*pillar = (pillar_t *)	arg1;
+	save_pillar_t	*temp	= (save_pillar_t *) arg2;
+
+	temp->sector_idx	= LONG(temp->sector_idx);
+	pillar->sector		= &sectors[temp->sector_idx];
+	pillar->sector->specialdata = T_BuildPillar;	//pillar->thinker.function
+	pillar->ceilingSpeed	= (int) LONG(temp->ceilingSpeed);
+	pillar->floorSpeed	= (int) LONG(temp->floorSpeed);
+	pillar->floordest	= (int) LONG(temp->floordest);
+	pillar->ceilingdest	= (int) LONG(temp->ceilingdest);
+	pillar->direction	= (int) LONG(temp->direction);
+	pillar->crush		= (int) LONG(temp->crush);
+}
+
+//==========================================================================
+//
+// MangleFloorWaggle
+//
+//==========================================================================
+
+static void MangleFloorWaggle(void *arg1, void *arg2)
+{
+	floorWaggle_t	*fw	= (floorWaggle_t *)	arg1;
+	save_floorWaggle_t *temp = (save_floorWaggle_t *) arg2;
+
+	temp->sector_idx	= LONG((int32_t)(fw->sector - sectors));
+	temp->originalHeight	= (fixed_t) LONG(fw->originalHeight);
+	temp->accumulator	= (fixed_t) LONG(fw->accumulator);
+	temp->accDelta		= (fixed_t) LONG(fw->accDelta);
+	temp->targetScale	= (fixed_t) LONG(fw->targetScale);
+	temp->scale		= (fixed_t) LONG(fw->scale);
+	temp->scaleDelta	= (fixed_t) LONG(fw->scaleDelta);
+	temp->ticker		= (int) LONG(fw->ticker);
+	temp->state		= (int) LONG(fw->state);
+}
+
+//==========================================================================
+//
+// RestoreFloorWaggle
+//
+//==========================================================================
+
+static void RestoreFloorWaggle(void *arg1, void *arg2)
+{
+	floorWaggle_t	*fw	= (floorWaggle_t *)	arg1;
+	save_floorWaggle_t *temp = (save_floorWaggle_t *) arg2;
+
+	temp->sector_idx	= LONG(temp->sector_idx);
+	fw->sector		= &sectors[temp->sector_idx];
+	fw->sector->specialdata = T_FloorWaggle;	//fw->thinker.function
+	fw->originalHeight	= (fixed_t) LONG(temp->originalHeight);
+	fw->accumulator		= (fixed_t) LONG(temp->accumulator);
+	fw->accDelta		= (fixed_t) LONG(temp->accDelta);
+	fw->targetScale		= (fixed_t) LONG(temp->targetScale);
+	fw->scale		= (fixed_t) LONG(temp->scale);
+	fw->scaleDelta		= (fixed_t) LONG(temp->scaleDelta);
+	fw->ticker		= (int) LONG(temp->ticker);
+	fw->state		= (int) LONG(temp->state);
+}
+
+//==========================================================================
+//
+// ManglePolyEvent
+//
+//==========================================================================
+
+static void ManglePolyEvent(void *arg1, void *arg2)
+{
+	polyevent_t	*pe	= (polyevent_t *) arg1;
+	save_polyevent_t *temp	= (save_polyevent_t *) arg2;
+
+	temp->polyobj		= LONG(pe->polyobj);
+	temp->speed		= LONG(pe->speed);
+	temp->dist		= LONG(pe->dist);
+	temp->angle		= LONG(pe->angle);
+	temp->xSpeed		= LONG(pe->xSpeed);
+	temp->ySpeed		= LONG(pe->ySpeed);
+}
+
+//==========================================================================
+//
+// RestorePolyEvent
+//
+//==========================================================================
+
+static void RestorePolyEvent(void *arg1, void *arg2)
+{
+	polyevent_t	*pe	= (polyevent_t *) arg1;
+	save_polyevent_t *temp	= (save_polyevent_t *) arg2;
+
+	pe->polyobj		= (int) LONG(temp->polyobj);
+	pe->speed		= (int) LONG(temp->speed);
+	pe->dist		= (unsigned int) LONG(temp->dist);
+	pe->angle		= (int) LONG(temp->angle);
+	pe->xSpeed		= (fixed_t) LONG(temp->xSpeed);
+	pe->ySpeed		= (fixed_t) LONG(temp->ySpeed);
+}
+
+//==========================================================================
+//
+// ManglePolyDoor
+//
+//==========================================================================
+
+static void ManglePolyDoor(void *arg1, void *arg2)
+{
+	polydoor_t	*pd	= (polydoor_t *) arg1;
+	save_polydoor_t *temp	= (save_polydoor_t *) arg2;
+
+	temp->polyobj		= (int) LONG(pd->polyobj);
+	temp->speed		= (int) LONG(pd->speed);
+	temp->dist		= (int) LONG(pd->dist);
+	temp->totalDist		= (int) LONG(pd->totalDist);
+	temp->direction		= (int) LONG(pd->direction);
+	temp->xSpeed		= (fixed_t) LONG(pd->xSpeed);
+	temp->ySpeed		= (fixed_t) LONG(pd->ySpeed);
+	temp->tics		= (int) LONG(pd->tics);
+	temp->waitTics		= (int) LONG(pd->waitTics);
+	temp->type		= (int) LONG(pd->type);
+	temp->close		= (int) LONG(pd->close);
+}
+
+//==========================================================================
+//
+// RestorePolyEvent
+//
+//==========================================================================
+
+static void RestorePolyDoor(void *arg1, void *arg2)
+{
+	polydoor_t	*pd	= (polydoor_t *) arg1;
+	save_polydoor_t *temp	= (save_polydoor_t *) arg2;
+
+	pd->polyobj		= (int) LONG(temp->polyobj);
+	pd->speed		= (int) LONG(temp->speed);
+	pd->dist		= (int) LONG(temp->dist);
+	pd->totalDist		= (int) LONG(temp->totalDist);
+	pd->direction		= (int) LONG(temp->direction);
+	pd->xSpeed		= (fixed_t) LONG(temp->xSpeed);
+	pd->ySpeed		= (fixed_t) LONG(temp->ySpeed);
+	pd->tics		= (int) LONG(temp->tics);
+	pd->waitTics		= (int) LONG(temp->waitTics);
+	pd->type		= (podoortype_t) LONG(temp->type);
+	pd->close		= !!(LONG(temp->close));
+}
+
+//==========================================================================
+//
+// MangleScript
+//
+//==========================================================================
+
+static void MangleScript(void *arg1, void *arg2)
+{
+	int		i;
+	acs_t 	*script		= (acs_t *)	arg1;
+	save_acs_t *temp	= (save_acs_t *) arg2;
+
+	temp->ip_idx		= LONG((int32_t)((intptr_t)(script->ip) - (intptr_t)ActionCodeBase));
+	temp->line_idx		= script->line ? LONG((int32_t)(script->line - lines)) : (int32_t)LONG(-1);
+	temp->activator_idx	= (int32_t) LONG(GetMobjNum(script->activator));
+	temp->side		= (int) LONG(script->side);
+	temp->number		= (int) LONG(script->number);
+	temp->infoIndex		= (int) LONG(script->infoIndex);
+	temp->delayCount	= (int) LONG(script->delayCount);
+	temp->stackPtr		= (int) LONG(script->stackPtr);
+	for (i = 0; i < ACS_STACK_DEPTH; i++)
+	{
+		temp->stack[i]	= (int) LONG(script->stack[i]);
+	}
+	for (i = 0; i < MAX_ACS_SCRIPT_VARS; i++)
+	{
+		temp->vars[i]	= (int) LONG(script->vars[i]);
+	}
+}
+
+//==========================================================================
+//
+// RestoreScript
+//
+//==========================================================================
+
+static void RestoreScript(void *arg1, void *arg2)
+{
+	int		i;
+	acs_t	*script		= (acs_t *)	arg1;
+	save_acs_t *temp	= (save_acs_t *) arg2;
+
+	temp->ip_idx		= (int32_t) LONG(temp->ip_idx);
+	temp->line_idx		= (int32_t) LONG(temp->line_idx);
+	temp->activator_idx	= (int32_t) LONG(temp->activator_idx);
+	script->ip		= ActionCodeBase + temp->ip_idx;
+	if (temp->line_idx == -1)
+	{
+		script->line	= NULL;
+	}
+	else
+	{
+		script->line	= &lines[temp->line_idx];
+	}
+	script->activator	= GetMobjPtr(temp->activator_idx, (intptr_t *)(void *)&script->activator);
+	script->side		= (int) LONG(temp->side);
+	script->number		= (int) LONG(temp->number);
+	script->infoIndex	= (int) LONG(temp->infoIndex);
+	script->delayCount	= (int) LONG(temp->delayCount);
+	script->stackPtr	= (int) LONG(temp->stackPtr);
+	for (i = 0; i < ACS_STACK_DEPTH; i++)
+	{
+		script->stack[i] = (int) LONG(temp->stack[i]);
+	}
+	for (i = 0; i < MAX_ACS_SCRIPT_VARS; i++)
+	{
+		script->vars[i]	= (int) LONG(temp->vars[i]);
+	}
+}
+
+//==========================================================================
+//
+// ManglePlatRaise
+//
+//==========================================================================
+
+static void ManglePlatRaise(void *arg1, void *arg2)
+{
+	plat_t		*plat	= (plat_t *)	arg1;
+	save_plat_t	*temp	= (save_plat_t *) arg2;
+
+	temp->sector_idx	= LONG((int32_t)(plat->sector - sectors));
+	temp->speed		= (fixed_t) LONG(plat->speed);
+	temp->low		= (fixed_t) LONG(plat->low);
+	temp->high		= (fixed_t) LONG(plat->high);
+	temp->wait		= (int) LONG(plat->wait);
+	temp->count		= (int) LONG(plat->count);
+	temp->status		= (int) LONG(plat->status);
+	temp->oldstatus		= (int) LONG(plat->oldstatus);
+	temp->crush		= (int) LONG(plat->crush);
+	temp->tag		= (int) LONG(plat->tag);
+	temp->type		= (int) LONG(plat->type);
+}
+
+//==========================================================================
+//
+// RestorePlatRaise
+//
+//==========================================================================
+
+static void RestorePlatRaise(void *arg1, void *arg2)
+{
+	plat_t		*plat	= (plat_t *)	arg1;
+	save_plat_t	*temp	= (save_plat_t *) arg2;
+
+	temp->sector_idx	= LONG(temp->sector_idx);
+	plat->sector		= &sectors[temp->sector_idx];
+	plat->sector->specialdata = T_PlatRaise;
+	plat->speed		= (fixed_t) LONG(temp->speed);
+	plat->low		= (fixed_t) LONG(temp->low);
+	plat->high		= (fixed_t) LONG(temp->high);
+	plat->wait		= (int) LONG(temp->wait);
+	plat->count		= (int) LONG(temp->count);
+	plat->status		= (plat_e) LONG(temp->status);
+	plat->oldstatus		= (plat_e) LONG(temp->oldstatus);
+	plat->crush		= (int) LONG(temp->crush);
+	plat->tag		= (int) LONG(temp->tag);
+	plat->type		= (plattype_e) LONG(temp->type);
+	P_AddActivePlat(plat);
+}
+
+//==========================================================================
+//
+// MangleMoveCeiling
+//
+//==========================================================================
+
+static void MangleMoveCeiling(void *arg1, void *arg2)
+{
+	ceiling_t	*ceiling = (ceiling_t *) arg1;
+	save_ceiling_t	*temp	= (save_ceiling_t *) arg2;
+
+	temp->sector_idx	= LONG((int32_t)(ceiling->sector - sectors));
+	temp->type		= (int) LONG(ceiling->type);
+	temp->bottomheight	= (fixed_t) LONG(ceiling->bottomheight);
+	temp->topheight		= (fixed_t) LONG(ceiling->topheight);
+	temp->speed		= (fixed_t) LONG(ceiling->speed);
+	temp->crush		= (int) LONG(ceiling->crush);
+	temp->direction		= (int) LONG(ceiling->direction);
+	temp->tag		= (int) LONG(ceiling->tag);
+	temp->olddirection	= (int) LONG(ceiling->olddirection);
+}
+
+//==========================================================================
+//
+// RestoreMoveCeiling
+//
+//==========================================================================
+
+static void RestoreMoveCeiling(void *arg1, void *arg2)
+{
+	ceiling_t	*ceiling = (ceiling_t *) arg1;
+	save_ceiling_t	*temp	= (save_ceiling_t *) arg2;
+
+	temp->sector_idx	= LONG(temp->sector_idx);
+	ceiling->sector		= &sectors[temp->sector_idx];
+	ceiling->sector->specialdata = T_MoveCeiling;
+	ceiling->type		= (ceiling_e) LONG(temp->type);
+	ceiling->bottomheight	= (fixed_t) LONG(temp->bottomheight);
+	ceiling->topheight	= (fixed_t) LONG(temp->topheight);
+	ceiling->speed		= (fixed_t) LONG(temp->speed);
+	ceiling->crush		= (int) LONG(temp->crush);
+	ceiling->direction	= (int) LONG(temp->direction);
+	ceiling->tag		= (int) LONG(temp->tag);
+	ceiling->olddirection	= (int) LONG(temp->olddirection);
+	P_AddActiveCeiling(ceiling);
+}
+
+//==========================================================================
+//
+// ArchiveScripts
+//
+//==========================================================================
+
+static void ArchiveScripts(void)
+{
+	int i;
+
+	StreamOutLong(ASEG_SCRIPTS);
+	for (i = 0; i < ACScriptCount; i++)
+	{
+		StreamOutWord(ACSInfo[i].state);
+		StreamOutWord(ACSInfo[i].waitValue);
+	}
+	for (i = 0; i < MAX_ACS_MAP_VARS; i++)
+	{
+		StreamOutLong(MapVars[i]);
+	}
+}
+
+//==========================================================================
+//
+// UnarchiveScripts
+//
+//==========================================================================
+
+static void UnarchiveScripts(void)
+{
+	int i;
+
+	AssertSegment(ASEG_SCRIPTS);
+	for (i = 0; i < ACScriptCount; i++)
+	{
+		ACSInfo[i].state = GET_WORD();
+		ACSInfo[i].waitValue = GET_WORD();
+	}
+	for (i = 0; i < MAX_ACS_MAP_VARS; i++)
+	{
+		MapVars[i] = GET_LONG();
+	}
+}
+
+//==========================================================================
+//
+// ArchiveMisc
+//
+//==========================================================================
+
+static void ArchiveMisc(void)
+{
+	int ix;
+
+	StreamOutLong(ASEG_MISC);
+	for (ix = 0; ix < MAXPLAYERS; ix++)
+	{
+		StreamOutLong(localQuakeHappening[ix]);
+	}
+}
+
+//==========================================================================
+//
+// UnarchiveMisc
+//
+//==========================================================================
+
+static void UnarchiveMisc(void)
+{
+	int ix;
+
+	AssertSegment(ASEG_MISC);
+	for (ix = 0; ix < MAXPLAYERS; ix++)
+	{
+		localQuakeHappening[ix] = GET_LONG();
+	}
+}
+
+//==========================================================================
+//
+// RemoveAllThinkers
+//
+//==========================================================================
+
+static void RemoveAllThinkers(void)
+{
+	thinker_t *thinker;
+	thinker_t *nextThinker;
+
+	thinker = thinkercap.next;
+	while (thinker != &thinkercap)
+	{
+		nextThinker = thinker->next;
+		if (thinker->function == P_MobjThinker)
+		{
+			P_RemoveMobj((mobj_t *)thinker);
+		}
+		else
+		{
+			Z_Free(thinker);
+		}
+		thinker = nextThinker;
+	}
+	P_InitThinkers();
+}
+
+//==========================================================================
+//
+// ArchiveSounds
+//
+//==========================================================================
+
+static void ArchiveSounds(void)
+{
+	seqnode_t *node;
+	sector_t *sec;
+	int difference;
+	int i;
+
+	StreamOutLong(ASEG_SOUNDS);
+
+	// Save the sound sequences
+	StreamOutLong(ActiveSequences);
+	for (node = SequenceListHead; node; node = node->next)
+	{
+		StreamOutLong(node->sequence);
+		StreamOutLong(node->delayTics);
+		StreamOutLong(node->volume);
+		StreamOutLong(SN_GetSequenceOffset(node->sequence, node->sequencePtr));
+		StreamOutLong(node->currentSoundID);
+		for (i = 0; i < po_NumPolyobjs; i++)
+		{
+			if (node->mobj == (mobj_t *)&polyobjs[i].startSpot)
+			{
+				break;
+			}
+		}
+		if (i == po_NumPolyobjs)
+		{ // Sound is attached to a sector, not a polyobj
+			sec = R_PointInSubsector(node->mobj->x, node->mobj->y)->sector;
+			difference = (int)(((byte *)sec - (byte *)&sectors[0]) / sizeof(sector_t));
+			StreamOutLong(0); // 0 -- sector sound origin
+		}
+		else
+		{
+			StreamOutLong(1); // 1 -- polyobj sound origin
+			difference = i;
+		}
+		StreamOutLong(difference);
+	}
+}
+
+//==========================================================================
+//
+// UnarchiveSounds
+//
+//==========================================================================
+
+static void UnarchiveSounds(void)
+{
+	int i;
+	int numSequences;
+	int sequence;
+	int delayTics;
+	int volume;
+	int seqOffset;
+	int soundID;
+	int polySnd;
+	int secNum;
+	mobj_t *sndMobj;
+
+	AssertSegment(ASEG_SOUNDS);
+
+	// Reload and restart all sound sequences
+	numSequences = GET_LONG();
+	i = 0;
+	while (i < numSequences)
+	{
+		sequence = GET_LONG();
+		delayTics = GET_LONG();
+		volume = GET_LONG();
+		seqOffset = GET_LONG();
+
+		soundID = GET_LONG();
+		polySnd = GET_LONG();
+		secNum = GET_LONG();
+		if (!polySnd)
+		{
+			sndMobj = (mobj_t *)(void *)&sectors[secNum].soundorg;
+		}
+		else
+		{
+			sndMobj = (mobj_t *)&polyobjs[secNum].startSpot;
+		}
+		SN_StartSequence(sndMobj, sequence);
+		SN_ChangeNodeData(i, seqOffset, delayTics, volume, soundID);
+		i++;
+	}
+}
+
+//==========================================================================
+//
+// ArchivePolyobjs
+//
+//==========================================================================
+
+static void ArchivePolyobjs(void)
+{
+	int i;
+
+	StreamOutLong(ASEG_POLYOBJS);
+	StreamOutLong(po_NumPolyobjs);
+	for (i = 0; i < po_NumPolyobjs; i++)
+	{
+		StreamOutLong(polyobjs[i].tag);
+		StreamOutLong(polyobjs[i].angle);
+		StreamOutLong(polyobjs[i].startSpot.x);
+		StreamOutLong(polyobjs[i].startSpot.y);
+	}
+}
+
+//==========================================================================
+//
+// UnarchivePolyobjs
+//
+//==========================================================================
+
+static void UnarchivePolyobjs(void)
+{
+	int i;
+	fixed_t deltaX;
+	fixed_t deltaY;
+
+	AssertSegment(ASEG_POLYOBJS);
+	if (GET_LONG() != po_NumPolyobjs)
+	{
+		I_Error("UnarchivePolyobjs: Bad polyobj count");
+	}
+	for (i = 0; i < po_NumPolyobjs; i++)
+	{
+		if (GET_LONG() != polyobjs[i].tag)
+		{
+			I_Error("UnarchivePolyobjs: Invalid polyobj tag");
+		}
+		PO_RotatePolyobj(polyobjs[i].tag, (angle_t)GET_LONG());
+		deltaX = GET_LONG() - polyobjs[i].startSpot.x;
+		deltaY = GET_LONG() - polyobjs[i].startSpot.y;
+		PO_MovePolyobj(polyobjs[i].tag, deltaX, deltaY);
+	}
+}
+
+//==========================================================================
+//
+// AssertSegment
+//
+//==========================================================================
+
+static void AssertSegment(gameArchiveSegment_t segType)
+{
+	if (GET_LONG() != segType)
+	{
+		I_Error("Corrupt save game: Segment [%d] failed alignment check", segType);
+	}
+}
+
+//==========================================================================
+//
+// ClearSaveSlot
+//
+// Deletes all save game files associated with a slot number.
+//
+//==========================================================================
+
+static void ClearSaveSlot(int slot)
+{
+	int i;
+	char fileName[MAX_OSPATH];
+
+	for (i = 0; i < MAX_MAPS; i++)
+	{
+		snprintf(fileName, sizeof(fileName), "%shex%d%02d.hxs", basePath, slot, i);
+		remove(fileName);
+	}
+	snprintf(fileName, sizeof(fileName), "%shex%d.hxs", basePath, slot);
+	remove(fileName);
+}
+
+//==========================================================================
+//
+// CopySaveSlot
+//
+// Copies all the save game files from one slot to another.
+//
+//==========================================================================
+
+static void CopySaveSlot(int sourceSlot, int destSlot)
+{
+	int i;
+	char sourceName[MAX_OSPATH];
+	char destName[MAX_OSPATH];
+
+	for (i = 0; i < MAX_MAPS; i++)
+	{
+		snprintf(sourceName, sizeof(sourceName), "%shex%d%02d.hxs", basePath,sourceSlot, i);
+		if (ExistingFile(sourceName))
+		{
+			snprintf(destName, sizeof(destName), "%shex%d%02d.hxs", basePath,destSlot, i);
+			CopyFile(sourceName, destName);
+		}
+	}
+	snprintf(sourceName, sizeof(sourceName), "%shex%d.hxs", basePath, sourceSlot);
+	if (ExistingFile(sourceName))
+	{
+		snprintf(destName, sizeof(destName), "%shex%d.hxs", basePath, destSlot);
+		CopyFile(sourceName, destName);
+	}
+}
+
+//==========================================================================
+//
+// CopyFile
+//
+//==========================================================================
+
+static void CopyFile(const char *sourceName, const char *destName)
+{
+	int length;
+	void *buffer;
+
+	length = M_ReadFile(sourceName, &buffer);
+	M_WriteFile(destName, buffer, length);
+	Z_Free(buffer);
+}
+
+//==========================================================================
+//
+// ExistingFile
+//
+//==========================================================================
+
+static boolean ExistingFile(const char *name)
+{
+	FILE *fp;
+
+	if ((fp = fopen(name, "rb")) != NULL)
+	{
+		fclose(fp);
+		return true;
+	}
+	else
+	{
+		return false;
+	}
+}
+
+//==========================================================================
+//
+// OpenStreamOut
+//
+//==========================================================================
+
+static void OpenStreamOut(const char *fileName)
+{
+	SavingFP = fopen(fileName, "wb");
+}
+
+//==========================================================================
+//
+// CloseStreamOut
+//
+//==========================================================================
+
+static void CloseStreamOut(void)
+{
+	if (SavingFP)
+	{
+		fclose(SavingFP);
+	}
+}
+
+//==========================================================================
+//
+// StreamOutBuffer
+//
+//==========================================================================
+
+static void StreamOutBuffer(const void *buffer, size_t size)
+{
+	fwrite(buffer, size, 1, SavingFP);
+}
+
+//==========================================================================
+//
+// StreamOutByte
+//
+//==========================================================================
+
+static void StreamOutByte(byte val)
+{
+	fwrite(&val, sizeof(byte), 1, SavingFP);
+}
+
+//==========================================================================
+//
+// StreamOutWord
+//
+//==========================================================================
+
+static void StreamOutWord(uint16_t val)
+{
+	uint16_t tmp = (uint16_t) SHORT(val);
+	fwrite(&tmp, sizeof(uint16_t), 1, SavingFP);
+}
+
+//==========================================================================
+//
+// StreamOutLong
+//
+//==========================================================================
+
+static void StreamOutLong(uint32_t val)
+{
+	uint32_t tmp = (uint32_t) LONG(val);
+	fwrite(&tmp, sizeof(uint32_t), 1, SavingFP);
+}
+
--- /dev/null
+++ b/sv_save.h
@@ -1,0 +1,293 @@
+/*
+	sv_save.h: Heretic 2 (Hexen)
+	Structures used for saved games.
+
+	$Revision: 543 $
+	$Date: 2010-01-11 20:44:55 +0200 (Mon, 11 Jan 2010) $
+
+	See the file SAVEGAME for notes and/or issues.
+*/
+
+#ifndef __SAVE_DEFS
+#define __SAVE_DEFS
+
+#ifndef _DOSSAVE_COMPAT
+#define __compat_doshexen
+#else
+#define __compat_doshexen	__attribute__((__packed__))
+#endif
+
+typedef struct
+{
+	int32_t	state_idx;				/* state_t	*state */
+	int	tics;
+	fixed_t	sx, sy;
+} save_pspdef_t;
+
+typedef struct
+{
+	int32_t		prev_idx, next_idx;		/* struct thinker_s *prev, *next; */
+	int32_t		function_idx;			/* think_t	function; */
+} save_thinker_t;
+
+typedef struct
+{
+	save_thinker_t		thinker;		/* thinker_t	thinker; */
+
+	fixed_t			x, y, z;
+	int32_t		snext_idx, sprev_idx;		/* struct mobj_s *snext, *sprev; */
+	angle_t			angle;
+	int			sprite;			/* spritenum_t	sprite */
+	int			frame;
+
+	int32_t		bnext_idx, bprev_idx;		/* struct mobj_s *bnext, *bprev; */
+	int32_t		subsector_idx;			/* struct subsector_s *subsector; */
+	fixed_t			floorz, ceilingz;
+	fixed_t			floorpic;
+	fixed_t			radius, height;
+	fixed_t			momx, momy, momz;
+	int			validcount;
+	int			type;			/* mobjtype_t	type */
+	int32_t			info_idx;		/* mobjinfo_t	*info; */
+	int			tics;
+	int32_t			state_idx;		/* state_t	*state; */
+	int			damage;
+	int			flags;
+	int			flags2;
+	int32_t			special1;		/* intptr_t	special1; */
+	int32_t			special2;		/* intptr_t	special2; */
+	int			health;
+	int			movedir;
+	int			movecount;
+	int32_t			target_idx;		/* struct mobj_s *target; */
+	int			reactiontime;
+	int			threshold;
+	int32_t			player_idx;		/* struct player_s *player; */
+	int			lastlook;
+	fixed_t			floorclip;
+	int			archiveNum;
+	short			tid;
+	byte			special;
+	byte			args[5];
+} __compat_doshexen save_mobj_t;
+#if !(defined(VERSION10_WAD) || defined(_DOSSAVE_COMPAT))
+/* make sure the struct is of 176 bytes size, so that all our
+   saved games are uniform. */
+#endif
+
+typedef struct
+{
+	int32_t		mo_idx;				/* mobj_t	*mo; */
+	int		playerstate;			/* playerstate_t playerstate */
+	ticcmd_t	cmd;	/* note: sizeof(ticcmd_t) is
+				   10, not 4 byte aligned. */
+
+	int		playerclass;			/* pclass_t	playerclass */
+
+	fixed_t		viewz;
+	fixed_t		viewheight;
+	fixed_t		deltaviewheight;
+	fixed_t		bob;
+
+	int		flyheight;
+	int		lookdir;
+	int		centering;			/* boolean	centering */
+	int		health;
+	int		armorpoints[NUMARMOR];
+
+	inventory_t	inventory[NUMINVENTORYSLOTS];
+	int		readyArtifact;			/* artitype_t	readyArtifact */
+	int		artifactCount;
+	int		inventorySlotNum;
+	int		powers[NUMPOWERS];
+	int		keys;
+	int		pieces;
+	signed int	frags[MAXPLAYERS];
+	int		readyweapon;			/* weapontype_t	readyweapon */
+	int		pendingweapon;			/* weapontype_t	pendingweapon */
+	int		weaponowned[NUMWEAPONS];	/* boolean	weaponowned[NUMWEAPONS] */
+	int		mana[NUMMANA];
+	int		attackdown, usedown;
+	int		cheats;
+
+	int		refire;
+
+	int		killcount, itemcount, secretcount;
+	char		message[80];
+	int		messageTics;
+	short		ultimateMessage;
+	short		yellowMessage;
+	int		damagecount, bonuscount;
+	int		poisoncount;
+	int32_t		poisoner_idx;			/* mobj_t	*poisoner; */
+	int32_t		attacker_idx;			/* mobj_t	*attacker; */
+	int		extralight;
+	int		fixedcolormap;
+	int		colormap;
+	save_pspdef_t	psprites[NUMPSPRITES];		/* pspdef_t	psprites[NUMPSPRITES]; */
+	int		morphTics;
+	unsigned int	jumpTics;
+	unsigned int	worldTimer;
+} __compat_doshexen save_player_t;
+#if !(defined(VERSION10_WAD) || defined(_DOSSAVE_COMPAT))
+/* make sure the struct is of 648 bytes size, so that all our saved
+   games are uniform: Raven's DOS versions seem to have this struct
+   packed, with sizeof(player_t) == 646 and offsetof playerclass at
+   18 instead of 20. */
+#endif
+
+typedef struct
+{
+	save_thinker_t	thinker;			/* thinker_t	thinker; */
+	int32_t		sector_idx;			/* sector_t	*sector; */
+	int		type;				/* floor_e	type; */
+	int		crush;
+	int		direction;
+	int		newspecial;
+	short		texture;		/*  */
+	fixed_t		floordestheight;
+	fixed_t		speed;
+	int		delayCount;
+	int		delayTotal;
+	fixed_t		stairsDelayHeight;
+	fixed_t		stairsDelayHeightDelta;
+	fixed_t		resetHeight;
+	short		resetDelay;
+	short		resetDelayCount;
+	byte		textureChange;		/*  */
+} __compat_doshexen save_floormove_t;
+#if !(defined(VERSION10_WAD) || defined(_DOSSAVE_COMPAT))
+/* make sure the struct is of 72 bytes size, so that all our saved
+   games are uniform. */
+#endif
+
+typedef struct
+{
+	save_thinker_t	thinker;			/* thinker_t	thinker; */
+	int32_t		sector_idx;			/* sector_t	*sector; */
+	int		ceilingSpeed;
+	int		floorSpeed;
+	int		floordest;
+	int		ceilingdest;
+	int		direction;
+	int		crush;
+} save_pillar_t;
+
+typedef struct
+{
+	save_thinker_t	thinker;			/* thinker_t	thinker; */
+	int32_t		sector_idx;			/* sector_t	*sector; */
+	fixed_t		originalHeight;
+	fixed_t		accumulator;
+	fixed_t		accDelta;
+	fixed_t		targetScale;
+	fixed_t		scale;
+	fixed_t		scaleDelta;
+	int		ticker;
+	int		state;
+} save_floorWaggle_t;
+
+typedef struct
+{
+	save_thinker_t	thinker;			/* thinker_t	thinker; */
+	int32_t		sector_idx;			/* sector_t	*sector; */
+	fixed_t		speed;
+	fixed_t		low;
+	fixed_t		high;
+	int		wait;
+	int		count;
+	int		status;				/* plat_e	status; */
+	int		oldstatus;			/* plat_e	oldstatus; */
+	int		crush;
+	int		tag;
+	int		type;				/* plattype_e	type; */
+} save_plat_t;
+
+typedef struct
+{
+	save_thinker_t	thinker;			/* thinker_t	thinker; */
+	int32_t		sector_idx;			/* sector_t	*sector; */
+	int		type;				/* ceiling_e	type; */
+	fixed_t		bottomheight, topheight;
+	fixed_t		speed;
+	int		crush;
+	int		direction;
+	int		tag;
+	int		olddirection;
+} save_ceiling_t;
+
+typedef struct
+{
+	save_thinker_t	thinker;			/* thinker_t	thinker; */
+	int32_t		sector_idx;			/* sector_t	*sector; */
+	int		type;				/* lighttype_t	type; */
+	int		value1;
+	int		value2;
+	int		tics1;
+	int		tics2;
+	int		count;
+} save_light_t;
+
+typedef struct
+{
+	save_thinker_t	thinker;			/* thinker_t	thinker; */
+	int32_t		sector_idx;			/* sector_t	*sector; */
+	int		index;
+	int		base;
+} save_phase_t;
+
+typedef struct
+{
+	save_thinker_t	thinker;			/* thinker_t	thinker; */
+	int32_t		sector_idx;			/* sector_t	*sector; */
+	int		type;				/* vldoor_e	type; */
+	fixed_t		topheight;
+	fixed_t		speed;
+	int		direction;
+	int		topwait;
+	int		topcountdown;
+} save_vldoor_t;
+
+typedef struct
+{
+	save_thinker_t thinker;				/* thinker_t thinker; */
+	int polyobj;
+	int speed;
+	unsigned int dist;
+	int angle;
+	fixed_t xSpeed;
+	fixed_t ySpeed;
+} save_polyevent_t;
+
+typedef struct
+{
+	save_thinker_t thinker;				/* thinker_t thinker; */
+	int polyobj;
+	int speed;
+	int dist;
+	int totalDist;
+	int direction;
+	fixed_t xSpeed, ySpeed;
+	int tics;
+	int waitTics;
+	int type;					/* podoortype_t type; */
+	int close;					/* boolean	close; */
+} save_polydoor_t;
+
+typedef struct
+{
+	save_thinker_t	thinker;			/* thinker_t	thinker; */
+	int32_t		activator_idx;			/* mobj_t	*activator; */
+	int32_t		line_idx;			/* line_t	*line; */
+	int		side;
+	int		number;
+	int		infoIndex;
+	int		delayCount;
+	int		stack[ACS_STACK_DEPTH];
+	int		stackPtr;
+	int		vars[MAX_ACS_SCRIPT_VARS];
+	int32_t		ip_idx;				/* byte		*ip; */
+} save_acs_t;
+
+#endif	/* __SAVE_DEFS */
+
--- /dev/null
+++ b/tables.c
@@ -1,0 +1,2074 @@
+
+//**************************************************************************
+//**
+//** tables.c : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 373 $
+//** $Date: 2009-05-19 21:14:28 +0300 (Tue, 19 May 2009) $
+//**
+//**************************************************************************
+
+#include "h2stdinc.h"
+#include "h2def.h"
+
+int finetangent[4096] =
+{
+-170910304,-56965752,-34178904,-24413316,-18988036,-15535599,-13145455,-11392683,
+-10052327,-8994149,-8137527,-7429880,-6835455,-6329090,-5892567,-5512368,
+-5178251,-4882318,-4618375,-4381502,-4167737,-3973855,-3797206,-3635590,
+-3487165,-3350381,-3223918,-3106651,-2997613,-2895966,-2800983,-2712030,
+-2628549,-2550052,-2476104,-2406322,-2340362,-2277919,-2218719,-2162516,
+-2109087,-2058233,-2009771,-1963536,-1919378,-1877161,-1836758,-1798063,
+-1760956,-1725348,-1691149,-1658278,-1626658,-1596220,-1566898,-1538632,
+-1511367,-1485049,-1459630,-1435065,-1411312,-1388330,-1366084,-1344537,
+-1323658,-1303416,-1283783,-1264730,-1246234,-1228269,-1210813,-1193846,
+-1177345,-1161294,-1145673,-1130465,-1115654,-1101225,-1087164,-1073455,
+-1060087,-1047046,-1034322,-1021901,-1009774,-997931,-986361,-975054,
+-964003,-953199,-942633,-932298,-922186,-912289,-902602,-893117,
+-883829,-874730,-865817,-857081,-848520,-840127,-831898,-823827,
+-815910,-808143,-800521,-793041,-785699,-778490,-771411,-764460,
+-757631,-750922,-744331,-737853,-731486,-725227,-719074,-713023,
+-707072,-701219,-695462,-689797,-684223,-678737,-673338,-668024,
+-662792,-657640,-652568,-647572,-642651,-637803,-633028,-628323,
+-623686,-619117,-614613,-610174,-605798,-601483,-597229,-593033,
+-588896,-584815,-580789,-576818,-572901,-569035,-565221,-561456,
+-557741,-554074,-550455,-546881,-543354,-539870,-536431,-533034,
+-529680,-526366,-523094,-519861,-516667,-513512,-510394,-507313,
+-504269,-501261,-498287,-495348,-492443,-489571,-486732,-483925,
+-481150,-478406,-475692,-473009,-470355,-467730,-465133,-462565,
+-460024,-457511,-455024,-452564,-450129,-447720,-445337,-442978,
+-440643,-438332,-436045,-433781,-431540,-429321,-427125,-424951,
+-422798,-420666,-418555,-416465,-414395,-412344,-410314,-408303,
+-406311,-404338,-402384,-400448,-398530,-396630,-394747,-392882,
+-391034,-389202,-387387,-385589,-383807,-382040,-380290,-378555,
+-376835,-375130,-373440,-371765,-370105,-368459,-366826,-365208,
+-363604,-362013,-360436,-358872,-357321,-355783,-354257,-352744,
+-351244,-349756,-348280,-346816,-345364,-343924,-342495,-341078,
+-339671,-338276,-336892,-335519,-334157,-332805,-331464,-330133,
+-328812,-327502,-326201,-324910,-323629,-322358,-321097,-319844,
+-318601,-317368,-316143,-314928,-313721,-312524,-311335,-310154,
+-308983,-307819,-306664,-305517,-304379,-303248,-302126,-301011,
+-299904,-298805,-297714,-296630,-295554,-294485,-293423,-292369,
+-291322,-290282,-289249,-288223,-287204,-286192,-285186,-284188,
+-283195,-282210,-281231,-280258,-279292,-278332,-277378,-276430,
+-275489,-274553,-273624,-272700,-271782,-270871,-269965,-269064,
+-268169,-267280,-266397,-265519,-264646,-263779,-262917,-262060,
+-261209,-260363,-259522,-258686,-257855,-257029,-256208,-255392,
+-254581,-253774,-252973,-252176,-251384,-250596,-249813,-249035,
+-248261,-247492,-246727,-245966,-245210,-244458,-243711,-242967,
+-242228,-241493,-240763,-240036,-239314,-238595,-237881,-237170,
+-236463,-235761,-235062,-234367,-233676,-232988,-232304,-231624,
+-230948,-230275,-229606,-228941,-228279,-227621,-226966,-226314,
+-225666,-225022,-224381,-223743,-223108,-222477,-221849,-221225,
+-220603,-219985,-219370,-218758,-218149,-217544,-216941,-216341,
+-215745,-215151,-214561,-213973,-213389,-212807,-212228,-211652,
+-211079,-210509,-209941,-209376,-208815,-208255,-207699,-207145,
+-206594,-206045,-205500,-204956,-204416,-203878,-203342,-202809,
+-202279,-201751,-201226,-200703,-200182,-199664,-199149,-198636,
+-198125,-197616,-197110,-196606,-196105,-195606,-195109,-194614,
+-194122,-193631,-193143,-192658,-192174,-191693,-191213,-190736,
+-190261,-189789,-189318,-188849,-188382,-187918,-187455,-186995,
+-186536,-186080,-185625,-185173,-184722,-184274,-183827,-183382,
+-182939,-182498,-182059,-181622,-181186,-180753,-180321,-179891,
+-179463,-179037,-178612,-178190,-177769,-177349,-176932,-176516,
+-176102,-175690,-175279,-174870,-174463,-174057,-173653,-173251,
+-172850,-172451,-172053,-171657,-171263,-170870,-170479,-170089,
+-169701,-169315,-168930,-168546,-168164,-167784,-167405,-167027,
+-166651,-166277,-165904,-165532,-165162,-164793,-164426,-164060,
+-163695,-163332,-162970,-162610,-162251,-161893,-161537,-161182,
+-160828,-160476,-160125,-159775,-159427,-159079,-158734,-158389,
+-158046,-157704,-157363,-157024,-156686,-156349,-156013,-155678,
+-155345,-155013,-154682,-154352,-154024,-153697,-153370,-153045,
+-152722,-152399,-152077,-151757,-151438,-151120,-150803,-150487,
+-150172,-149859,-149546,-149235,-148924,-148615,-148307,-148000,
+-147693,-147388,-147084,-146782,-146480,-146179,-145879,-145580,
+-145282,-144986,-144690,-144395,-144101,-143808,-143517,-143226,
+-142936,-142647,-142359,-142072,-141786,-141501,-141217,-140934,
+-140651,-140370,-140090,-139810,-139532,-139254,-138977,-138701,
+-138426,-138152,-137879,-137607,-137335,-137065,-136795,-136526,
+-136258,-135991,-135725,-135459,-135195,-134931,-134668,-134406,
+-134145,-133884,-133625,-133366,-133108,-132851,-132594,-132339,
+-132084,-131830,-131576,-131324,-131072,-130821,-130571,-130322,
+-130073,-129825,-129578,-129332,-129086,-128841,-128597,-128353,
+-128111,-127869,-127627,-127387,-127147,-126908,-126669,-126432,
+-126195,-125959,-125723,-125488,-125254,-125020,-124787,-124555,
+-124324,-124093,-123863,-123633,-123404,-123176,-122949,-122722,
+-122496,-122270,-122045,-121821,-121597,-121374,-121152,-120930,
+-120709,-120489,-120269,-120050,-119831,-119613,-119396,-119179,
+-118963,-118747,-118532,-118318,-118104,-117891,-117678,-117466,
+-117254,-117044,-116833,-116623,-116414,-116206,-115998,-115790,
+-115583,-115377,-115171,-114966,-114761,-114557,-114354,-114151,
+-113948,-113746,-113545,-113344,-113143,-112944,-112744,-112546,
+-112347,-112150,-111952,-111756,-111560,-111364,-111169,-110974,
+-110780,-110586,-110393,-110200,-110008,-109817,-109626,-109435,
+-109245,-109055,-108866,-108677,-108489,-108301,-108114,-107927,
+-107741,-107555,-107369,-107184,-107000,-106816,-106632,-106449,
+-106266,-106084,-105902,-105721,-105540,-105360,-105180,-105000,
+-104821,-104643,-104465,-104287,-104109,-103933,-103756,-103580,
+-103404,-103229,-103054,-102880,-102706,-102533,-102360,-102187,
+-102015,-101843,-101671,-101500,-101330,-101159,-100990,-100820,
+-100651,-100482,-100314,-100146,-99979,-99812,-99645,-99479,
+-99313,-99148,-98982,-98818,-98653,-98489,-98326,-98163,
+-98000,-97837,-97675,-97513,-97352,-97191,-97030,-96870,
+-96710,-96551,-96391,-96233,-96074,-95916,-95758,-95601,
+-95444,-95287,-95131,-94975,-94819,-94664,-94509,-94354,
+-94200,-94046,-93892,-93739,-93586,-93434,-93281,-93129,
+-92978,-92826,-92675,-92525,-92375,-92225,-92075,-91926,
+-91777,-91628,-91480,-91332,-91184,-91036,-90889,-90742,
+-90596,-90450,-90304,-90158,-90013,-89868,-89724,-89579,
+-89435,-89292,-89148,-89005,-88862,-88720,-88577,-88435,
+-88294,-88152,-88011,-87871,-87730,-87590,-87450,-87310,
+-87171,-87032,-86893,-86755,-86616,-86479,-86341,-86204,
+-86066,-85930,-85793,-85657,-85521,-85385,-85250,-85114,
+-84980,-84845,-84710,-84576,-84443,-84309,-84176,-84043,
+-83910,-83777,-83645,-83513,-83381,-83250,-83118,-82987,
+-82857,-82726,-82596,-82466,-82336,-82207,-82078,-81949,
+-81820,-81691,-81563,-81435,-81307,-81180,-81053,-80925,
+-80799,-80672,-80546,-80420,-80294,-80168,-80043,-79918,
+-79793,-79668,-79544,-79420,-79296,-79172,-79048,-78925,
+-78802,-78679,-78557,-78434,-78312,-78190,-78068,-77947,
+-77826,-77705,-77584,-77463,-77343,-77223,-77103,-76983,
+-76864,-76744,-76625,-76506,-76388,-76269,-76151,-76033,
+-75915,-75797,-75680,-75563,-75446,-75329,-75213,-75096,
+-74980,-74864,-74748,-74633,-74517,-74402,-74287,-74172,
+-74058,-73944,-73829,-73715,-73602,-73488,-73375,-73262,
+-73149,-73036,-72923,-72811,-72699,-72587,-72475,-72363,
+-72252,-72140,-72029,-71918,-71808,-71697,-71587,-71477,
+-71367,-71257,-71147,-71038,-70929,-70820,-70711,-70602,
+-70494,-70385,-70277,-70169,-70061,-69954,-69846,-69739,
+-69632,-69525,-69418,-69312,-69205,-69099,-68993,-68887,
+-68781,-68676,-68570,-68465,-68360,-68255,-68151,-68046,
+-67942,-67837,-67733,-67629,-67526,-67422,-67319,-67216,
+-67113,-67010,-66907,-66804,-66702,-66600,-66498,-66396,
+-66294,-66192,-66091,-65989,-65888,-65787,-65686,-65586,
+-65485,-65385,-65285,-65185,-65085,-64985,-64885,-64786,
+-64687,-64587,-64488,-64389,-64291,-64192,-64094,-63996,
+-63897,-63799,-63702,-63604,-63506,-63409,-63312,-63215,
+-63118,-63021,-62924,-62828,-62731,-62635,-62539,-62443,
+-62347,-62251,-62156,-62060,-61965,-61870,-61775,-61680,
+-61585,-61491,-61396,-61302,-61208,-61114,-61020,-60926,
+-60833,-60739,-60646,-60552,-60459,-60366,-60273,-60181,
+-60088,-59996,-59903,-59811,-59719,-59627,-59535,-59444,
+-59352,-59261,-59169,-59078,-58987,-58896,-58805,-58715,
+-58624,-58534,-58443,-58353,-58263,-58173,-58083,-57994,
+-57904,-57815,-57725,-57636,-57547,-57458,-57369,-57281,
+-57192,-57104,-57015,-56927,-56839,-56751,-56663,-56575,
+-56487,-56400,-56312,-56225,-56138,-56051,-55964,-55877,
+-55790,-55704,-55617,-55531,-55444,-55358,-55272,-55186,
+-55100,-55015,-54929,-54843,-54758,-54673,-54587,-54502,
+-54417,-54333,-54248,-54163,-54079,-53994,-53910,-53826,
+-53741,-53657,-53574,-53490,-53406,-53322,-53239,-53156,
+-53072,-52989,-52906,-52823,-52740,-52657,-52575,-52492,
+-52410,-52327,-52245,-52163,-52081,-51999,-51917,-51835,
+-51754,-51672,-51591,-51509,-51428,-51347,-51266,-51185,
+-51104,-51023,-50942,-50862,-50781,-50701,-50621,-50540,
+-50460,-50380,-50300,-50221,-50141,-50061,-49982,-49902,
+-49823,-49744,-49664,-49585,-49506,-49427,-49349,-49270,
+-49191,-49113,-49034,-48956,-48878,-48799,-48721,-48643,
+-48565,-48488,-48410,-48332,-48255,-48177,-48100,-48022,
+-47945,-47868,-47791,-47714,-47637,-47560,-47484,-47407,
+-47331,-47254,-47178,-47102,-47025,-46949,-46873,-46797,
+-46721,-46646,-46570,-46494,-46419,-46343,-46268,-46193,
+-46118,-46042,-45967,-45892,-45818,-45743,-45668,-45593,
+-45519,-45444,-45370,-45296,-45221,-45147,-45073,-44999,
+-44925,-44851,-44778,-44704,-44630,-44557,-44483,-44410,
+-44337,-44263,-44190,-44117,-44044,-43971,-43898,-43826,
+-43753,-43680,-43608,-43535,-43463,-43390,-43318,-43246,
+-43174,-43102,-43030,-42958,-42886,-42814,-42743,-42671,
+-42600,-42528,-42457,-42385,-42314,-42243,-42172,-42101,
+-42030,-41959,-41888,-41817,-41747,-41676,-41605,-41535,
+-41465,-41394,-41324,-41254,-41184,-41113,-41043,-40973,
+-40904,-40834,-40764,-40694,-40625,-40555,-40486,-40416,
+-40347,-40278,-40208,-40139,-40070,-40001,-39932,-39863,
+-39794,-39726,-39657,-39588,-39520,-39451,-39383,-39314,
+-39246,-39178,-39110,-39042,-38973,-38905,-38837,-38770,
+-38702,-38634,-38566,-38499,-38431,-38364,-38296,-38229,
+-38161,-38094,-38027,-37960,-37893,-37826,-37759,-37692,
+-37625,-37558,-37491,-37425,-37358,-37291,-37225,-37158,
+-37092,-37026,-36959,-36893,-36827,-36761,-36695,-36629,
+-36563,-36497,-36431,-36365,-36300,-36234,-36168,-36103,
+-36037,-35972,-35907,-35841,-35776,-35711,-35646,-35580,
+-35515,-35450,-35385,-35321,-35256,-35191,-35126,-35062,
+-34997,-34932,-34868,-34803,-34739,-34675,-34610,-34546,
+-34482,-34418,-34354,-34289,-34225,-34162,-34098,-34034,
+-33970,-33906,-33843,-33779,-33715,-33652,-33588,-33525,
+-33461,-33398,-33335,-33272,-33208,-33145,-33082,-33019,
+-32956,-32893,-32830,-32767,-32705,-32642,-32579,-32516,
+-32454,-32391,-32329,-32266,-32204,-32141,-32079,-32017,
+-31955,-31892,-31830,-31768,-31706,-31644,-31582,-31520,
+-31458,-31396,-31335,-31273,-31211,-31150,-31088,-31026,
+-30965,-30904,-30842,-30781,-30719,-30658,-30597,-30536,
+-30474,-30413,-30352,-30291,-30230,-30169,-30108,-30048,
+-29987,-29926,-29865,-29805,-29744,-29683,-29623,-29562,
+-29502,-29441,-29381,-29321,-29260,-29200,-29140,-29080,
+-29020,-28959,-28899,-28839,-28779,-28719,-28660,-28600,
+-28540,-28480,-28420,-28361,-28301,-28241,-28182,-28122,
+-28063,-28003,-27944,-27884,-27825,-27766,-27707,-27647,
+-27588,-27529,-27470,-27411,-27352,-27293,-27234,-27175,
+-27116,-27057,-26998,-26940,-26881,-26822,-26763,-26705,
+-26646,-26588,-26529,-26471,-26412,-26354,-26295,-26237,
+-26179,-26120,-26062,-26004,-25946,-25888,-25830,-25772,
+-25714,-25656,-25598,-25540,-25482,-25424,-25366,-25308,
+-25251,-25193,-25135,-25078,-25020,-24962,-24905,-24847,
+-24790,-24732,-24675,-24618,-24560,-24503,-24446,-24389,
+-24331,-24274,-24217,-24160,-24103,-24046,-23989,-23932,
+-23875,-23818,-23761,-23704,-23647,-23591,-23534,-23477,
+-23420,-23364,-23307,-23250,-23194,-23137,-23081,-23024,
+-22968,-22911,-22855,-22799,-22742,-22686,-22630,-22573,
+-22517,-22461,-22405,-22349,-22293,-22237,-22181,-22125,
+-22069,-22013,-21957,-21901,-21845,-21789,-21733,-21678,
+-21622,-21566,-21510,-21455,-21399,-21343,-21288,-21232,
+-21177,-21121,-21066,-21010,-20955,-20900,-20844,-20789,
+-20734,-20678,-20623,-20568,-20513,-20457,-20402,-20347,
+-20292,-20237,-20182,-20127,-20072,-20017,-19962,-19907,
+-19852,-19797,-19742,-19688,-19633,-19578,-19523,-19469,
+-19414,-19359,-19305,-19250,-19195,-19141,-19086,-19032,
+-18977,-18923,-18868,-18814,-18760,-18705,-18651,-18597,
+-18542,-18488,-18434,-18380,-18325,-18271,-18217,-18163,
+-18109,-18055,-18001,-17946,-17892,-17838,-17784,-17731,
+-17677,-17623,-17569,-17515,-17461,-17407,-17353,-17300,
+-17246,-17192,-17138,-17085,-17031,-16977,-16924,-16870,
+-16817,-16763,-16710,-16656,-16603,-16549,-16496,-16442,
+-16389,-16335,-16282,-16229,-16175,-16122,-16069,-16015,
+-15962,-15909,-15856,-15802,-15749,-15696,-15643,-15590,
+-15537,-15484,-15431,-15378,-15325,-15272,-15219,-15166,
+-15113,-15060,-15007,-14954,-14901,-14848,-14795,-14743,
+-14690,-14637,-14584,-14531,-14479,-14426,-14373,-14321,
+-14268,-14215,-14163,-14110,-14057,-14005,-13952,-13900,
+-13847,-13795,-13742,-13690,-13637,-13585,-13533,-13480,
+-13428,-13375,-13323,-13271,-13218,-13166,-13114,-13062,
+-13009,-12957,-12905,-12853,-12800,-12748,-12696,-12644,
+-12592,-12540,-12488,-12436,-12383,-12331,-12279,-12227,
+-12175,-12123,-12071,-12019,-11967,-11916,-11864,-11812,
+-11760,-11708,-11656,-11604,-11552,-11501,-11449,-11397,
+-11345,-11293,-11242,-11190,-11138,-11086,-11035,-10983,
+-10931,-10880,-10828,-10777,-10725,-10673,-10622,-10570,
+-10519,-10467,-10415,-10364,-10312,-10261,-10209,-10158,
+-10106,-10055,-10004,-9952,-9901,-9849,-9798,-9747,
+-9695,-9644,-9592,-9541,-9490,-9438,-9387,-9336,
+-9285,-9233,-9182,-9131,-9080,-9028,-8977,-8926,
+-8875,-8824,-8772,-8721,-8670,-8619,-8568,-8517,
+-8466,-8414,-8363,-8312,-8261,-8210,-8159,-8108,
+-8057,-8006,-7955,-7904,-7853,-7802,-7751,-7700,
+-7649,-7598,-7547,-7496,-7445,-7395,-7344,-7293,
+-7242,-7191,-7140,-7089,-7038,-6988,-6937,-6886,
+-6835,-6784,-6733,-6683,-6632,-6581,-6530,-6480,
+-6429,-6378,-6327,-6277,-6226,-6175,-6124,-6074,
+-6023,-5972,-5922,-5871,-5820,-5770,-5719,-5668,
+-5618,-5567,-5517,-5466,-5415,-5365,-5314,-5264,
+-5213,-5162,-5112,-5061,-5011,-4960,-4910,-4859,
+-4808,-4758,-4707,-4657,-4606,-4556,-4505,-4455,
+-4404,-4354,-4303,-4253,-4202,-4152,-4101,-4051,
+-4001,-3950,-3900,-3849,-3799,-3748,-3698,-3648,
+-3597,-3547,-3496,-3446,-3395,-3345,-3295,-3244,
+-3194,-3144,-3093,-3043,-2992,-2942,-2892,-2841,
+-2791,-2741,-2690,-2640,-2590,-2539,-2489,-2439,
+-2388,-2338,-2288,-2237,-2187,-2137,-2086,-2036,
+-1986,-1935,-1885,-1835,-1784,-1734,-1684,-1633,
+-1583,-1533,-1483,-1432,-1382,-1332,-1281,-1231,
+-1181,-1131,-1080,-1030,-980,-929,-879,-829,
+-779,-728,-678,-628,-578,-527,-477,-427,
+-376,-326,-276,-226,-175,-125,-75,-25,
+25,75,125,175,226,276,326,376,
+427,477,527,578,628,678,728,779,
+829,879,929,980,1030,1080,1131,1181,
+1231,1281,1332,1382,1432,1483,1533,1583,
+1633,1684,1734,1784,1835,1885,1935,1986,
+2036,2086,2137,2187,2237,2288,2338,2388,
+2439,2489,2539,2590,2640,2690,2741,2791,
+2841,2892,2942,2992,3043,3093,3144,3194,
+3244,3295,3345,3395,3446,3496,3547,3597,
+3648,3698,3748,3799,3849,3900,3950,4001,
+4051,4101,4152,4202,4253,4303,4354,4404,
+4455,4505,4556,4606,4657,4707,4758,4808,
+4859,4910,4960,5011,5061,5112,5162,5213,
+5264,5314,5365,5415,5466,5517,5567,5618,
+5668,5719,5770,5820,5871,5922,5972,6023,
+6074,6124,6175,6226,6277,6327,6378,6429,
+6480,6530,6581,6632,6683,6733,6784,6835,
+6886,6937,6988,7038,7089,7140,7191,7242,
+7293,7344,7395,7445,7496,7547,7598,7649,
+7700,7751,7802,7853,7904,7955,8006,8057,
+8108,8159,8210,8261,8312,8363,8414,8466,
+8517,8568,8619,8670,8721,8772,8824,8875,
+8926,8977,9028,9080,9131,9182,9233,9285,
+9336,9387,9438,9490,9541,9592,9644,9695,
+9747,9798,9849,9901,9952,10004,10055,10106,
+10158,10209,10261,10312,10364,10415,10467,10519,
+10570,10622,10673,10725,10777,10828,10880,10931,
+10983,11035,11086,11138,11190,11242,11293,11345,
+11397,11449,11501,11552,11604,11656,11708,11760,
+11812,11864,11916,11967,12019,12071,12123,12175,
+12227,12279,12331,12383,12436,12488,12540,12592,
+12644,12696,12748,12800,12853,12905,12957,13009,
+13062,13114,13166,13218,13271,13323,13375,13428,
+13480,13533,13585,13637,13690,13742,13795,13847,
+13900,13952,14005,14057,14110,14163,14215,14268,
+14321,14373,14426,14479,14531,14584,14637,14690,
+14743,14795,14848,14901,14954,15007,15060,15113,
+15166,15219,15272,15325,15378,15431,15484,15537,
+15590,15643,15696,15749,15802,15856,15909,15962,
+16015,16069,16122,16175,16229,16282,16335,16389,
+16442,16496,16549,16603,16656,16710,16763,16817,
+16870,16924,16977,17031,17085,17138,17192,17246,
+17300,17353,17407,17461,17515,17569,17623,17677,
+17731,17784,17838,17892,17946,18001,18055,18109,
+18163,18217,18271,18325,18380,18434,18488,18542,
+18597,18651,18705,18760,18814,18868,18923,18977,
+19032,19086,19141,19195,19250,19305,19359,19414,
+19469,19523,19578,19633,19688,19742,19797,19852,
+19907,19962,20017,20072,20127,20182,20237,20292,
+20347,20402,20457,20513,20568,20623,20678,20734,
+20789,20844,20900,20955,21010,21066,21121,21177,
+21232,21288,21343,21399,21455,21510,21566,21622,
+21678,21733,21789,21845,21901,21957,22013,22069,
+22125,22181,22237,22293,22349,22405,22461,22517,
+22573,22630,22686,22742,22799,22855,22911,22968,
+23024,23081,23137,23194,23250,23307,23364,23420,
+23477,23534,23591,23647,23704,23761,23818,23875,
+23932,23989,24046,24103,24160,24217,24274,24331,
+24389,24446,24503,24560,24618,24675,24732,24790,
+24847,24905,24962,25020,25078,25135,25193,25251,
+25308,25366,25424,25482,25540,25598,25656,25714,
+25772,25830,25888,25946,26004,26062,26120,26179,
+26237,26295,26354,26412,26471,26529,26588,26646,
+26705,26763,26822,26881,26940,26998,27057,27116,
+27175,27234,27293,27352,27411,27470,27529,27588,
+27647,27707,27766,27825,27884,27944,28003,28063,
+28122,28182,28241,28301,28361,28420,28480,28540,
+28600,28660,28719,28779,28839,28899,28959,29020,
+29080,29140,29200,29260,29321,29381,29441,29502,
+29562,29623,29683,29744,29805,29865,29926,29987,
+30048,30108,30169,30230,30291,30352,30413,30474,
+30536,30597,30658,30719,30781,30842,30904,30965,
+31026,31088,31150,31211,31273,31335,31396,31458,
+31520,31582,31644,31706,31768,31830,31892,31955,
+32017,32079,32141,32204,32266,32329,32391,32454,
+32516,32579,32642,32705,32767,32830,32893,32956,
+33019,33082,33145,33208,33272,33335,33398,33461,
+33525,33588,33652,33715,33779,33843,33906,33970,
+34034,34098,34162,34225,34289,34354,34418,34482,
+34546,34610,34675,34739,34803,34868,34932,34997,
+35062,35126,35191,35256,35321,35385,35450,35515,
+35580,35646,35711,35776,35841,35907,35972,36037,
+36103,36168,36234,36300,36365,36431,36497,36563,
+36629,36695,36761,36827,36893,36959,37026,37092,
+37158,37225,37291,37358,37425,37491,37558,37625,
+37692,37759,37826,37893,37960,38027,38094,38161,
+38229,38296,38364,38431,38499,38566,38634,38702,
+38770,38837,38905,38973,39042,39110,39178,39246,
+39314,39383,39451,39520,39588,39657,39726,39794,
+39863,39932,40001,40070,40139,40208,40278,40347,
+40416,40486,40555,40625,40694,40764,40834,40904,
+40973,41043,41113,41184,41254,41324,41394,41465,
+41535,41605,41676,41747,41817,41888,41959,42030,
+42101,42172,42243,42314,42385,42457,42528,42600,
+42671,42743,42814,42886,42958,43030,43102,43174,
+43246,43318,43390,43463,43535,43608,43680,43753,
+43826,43898,43971,44044,44117,44190,44263,44337,
+44410,44483,44557,44630,44704,44778,44851,44925,
+44999,45073,45147,45221,45296,45370,45444,45519,
+45593,45668,45743,45818,45892,45967,46042,46118,
+46193,46268,46343,46419,46494,46570,46646,46721,
+46797,46873,46949,47025,47102,47178,47254,47331,
+47407,47484,47560,47637,47714,47791,47868,47945,
+48022,48100,48177,48255,48332,48410,48488,48565,
+48643,48721,48799,48878,48956,49034,49113,49191,
+49270,49349,49427,49506,49585,49664,49744,49823,
+49902,49982,50061,50141,50221,50300,50380,50460,
+50540,50621,50701,50781,50862,50942,51023,51104,
+51185,51266,51347,51428,51509,51591,51672,51754,
+51835,51917,51999,52081,52163,52245,52327,52410,
+52492,52575,52657,52740,52823,52906,52989,53072,
+53156,53239,53322,53406,53490,53574,53657,53741,
+53826,53910,53994,54079,54163,54248,54333,54417,
+54502,54587,54673,54758,54843,54929,55015,55100,
+55186,55272,55358,55444,55531,55617,55704,55790,
+55877,55964,56051,56138,56225,56312,56400,56487,
+56575,56663,56751,56839,56927,57015,57104,57192,
+57281,57369,57458,57547,57636,57725,57815,57904,
+57994,58083,58173,58263,58353,58443,58534,58624,
+58715,58805,58896,58987,59078,59169,59261,59352,
+59444,59535,59627,59719,59811,59903,59996,60088,
+60181,60273,60366,60459,60552,60646,60739,60833,
+60926,61020,61114,61208,61302,61396,61491,61585,
+61680,61775,61870,61965,62060,62156,62251,62347,
+62443,62539,62635,62731,62828,62924,63021,63118,
+63215,63312,63409,63506,63604,63702,63799,63897,
+63996,64094,64192,64291,64389,64488,64587,64687,
+64786,64885,64985,65085,65185,65285,65385,65485,
+65586,65686,65787,65888,65989,66091,66192,66294,
+66396,66498,66600,66702,66804,66907,67010,67113,
+67216,67319,67422,67526,67629,67733,67837,67942,
+68046,68151,68255,68360,68465,68570,68676,68781,
+68887,68993,69099,69205,69312,69418,69525,69632,
+69739,69846,69954,70061,70169,70277,70385,70494,
+70602,70711,70820,70929,71038,71147,71257,71367,
+71477,71587,71697,71808,71918,72029,72140,72252,
+72363,72475,72587,72699,72811,72923,73036,73149,
+73262,73375,73488,73602,73715,73829,73944,74058,
+74172,74287,74402,74517,74633,74748,74864,74980,
+75096,75213,75329,75446,75563,75680,75797,75915,
+76033,76151,76269,76388,76506,76625,76744,76864,
+76983,77103,77223,77343,77463,77584,77705,77826,
+77947,78068,78190,78312,78434,78557,78679,78802,
+78925,79048,79172,79296,79420,79544,79668,79793,
+79918,80043,80168,80294,80420,80546,80672,80799,
+80925,81053,81180,81307,81435,81563,81691,81820,
+81949,82078,82207,82336,82466,82596,82726,82857,
+82987,83118,83250,83381,83513,83645,83777,83910,
+84043,84176,84309,84443,84576,84710,84845,84980,
+85114,85250,85385,85521,85657,85793,85930,86066,
+86204,86341,86479,86616,86755,86893,87032,87171,
+87310,87450,87590,87730,87871,88011,88152,88294,
+88435,88577,88720,88862,89005,89148,89292,89435,
+89579,89724,89868,90013,90158,90304,90450,90596,
+90742,90889,91036,91184,91332,91480,91628,91777,
+91926,92075,92225,92375,92525,92675,92826,92978,
+93129,93281,93434,93586,93739,93892,94046,94200,
+94354,94509,94664,94819,94975,95131,95287,95444,
+95601,95758,95916,96074,96233,96391,96551,96710,
+96870,97030,97191,97352,97513,97675,97837,98000,
+98163,98326,98489,98653,98818,98982,99148,99313,
+99479,99645,99812,99979,100146,100314,100482,100651,
+100820,100990,101159,101330,101500,101671,101843,102015,
+102187,102360,102533,102706,102880,103054,103229,103404,
+103580,103756,103933,104109,104287,104465,104643,104821,
+105000,105180,105360,105540,105721,105902,106084,106266,
+106449,106632,106816,107000,107184,107369,107555,107741,
+107927,108114,108301,108489,108677,108866,109055,109245,
+109435,109626,109817,110008,110200,110393,110586,110780,
+110974,111169,111364,111560,111756,111952,112150,112347,
+112546,112744,112944,113143,113344,113545,113746,113948,
+114151,114354,114557,114761,114966,115171,115377,115583,
+115790,115998,116206,116414,116623,116833,117044,117254,
+117466,117678,117891,118104,118318,118532,118747,118963,
+119179,119396,119613,119831,120050,120269,120489,120709,
+120930,121152,121374,121597,121821,122045,122270,122496,
+122722,122949,123176,123404,123633,123863,124093,124324,
+124555,124787,125020,125254,125488,125723,125959,126195,
+126432,126669,126908,127147,127387,127627,127869,128111,
+128353,128597,128841,129086,129332,129578,129825,130073,
+130322,130571,130821,131072,131324,131576,131830,132084,
+132339,132594,132851,133108,133366,133625,133884,134145,
+134406,134668,134931,135195,135459,135725,135991,136258,
+136526,136795,137065,137335,137607,137879,138152,138426,
+138701,138977,139254,139532,139810,140090,140370,140651,
+140934,141217,141501,141786,142072,142359,142647,142936,
+143226,143517,143808,144101,144395,144690,144986,145282,
+145580,145879,146179,146480,146782,147084,147388,147693,
+148000,148307,148615,148924,149235,149546,149859,150172,
+150487,150803,151120,151438,151757,152077,152399,152722,
+153045,153370,153697,154024,154352,154682,155013,155345,
+155678,156013,156349,156686,157024,157363,157704,158046,
+158389,158734,159079,159427,159775,160125,160476,160828,
+161182,161537,161893,162251,162610,162970,163332,163695,
+164060,164426,164793,165162,165532,165904,166277,166651,
+167027,167405,167784,168164,168546,168930,169315,169701,
+170089,170479,170870,171263,171657,172053,172451,172850,
+173251,173653,174057,174463,174870,175279,175690,176102,
+176516,176932,177349,177769,178190,178612,179037,179463,
+179891,180321,180753,181186,181622,182059,182498,182939,
+183382,183827,184274,184722,185173,185625,186080,186536,
+186995,187455,187918,188382,188849,189318,189789,190261,
+190736,191213,191693,192174,192658,193143,193631,194122,
+194614,195109,195606,196105,196606,197110,197616,198125,
+198636,199149,199664,200182,200703,201226,201751,202279,
+202809,203342,203878,204416,204956,205500,206045,206594,
+207145,207699,208255,208815,209376,209941,210509,211079,
+211652,212228,212807,213389,213973,214561,215151,215745,
+216341,216941,217544,218149,218758,219370,219985,220603,
+221225,221849,222477,223108,223743,224381,225022,225666,
+226314,226966,227621,228279,228941,229606,230275,230948,
+231624,232304,232988,233676,234367,235062,235761,236463,
+237170,237881,238595,239314,240036,240763,241493,242228,
+242967,243711,244458,245210,245966,246727,247492,248261,
+249035,249813,250596,251384,252176,252973,253774,254581,
+255392,256208,257029,257855,258686,259522,260363,261209,
+262060,262917,263779,264646,265519,266397,267280,268169,
+269064,269965,270871,271782,272700,273624,274553,275489,
+276430,277378,278332,279292,280258,281231,282210,283195,
+284188,285186,286192,287204,288223,289249,290282,291322,
+292369,293423,294485,295554,296630,297714,298805,299904,
+301011,302126,303248,304379,305517,306664,307819,308983,
+310154,311335,312524,313721,314928,316143,317368,318601,
+319844,321097,322358,323629,324910,326201,327502,328812,
+330133,331464,332805,334157,335519,336892,338276,339671,
+341078,342495,343924,345364,346816,348280,349756,351244,
+352744,354257,355783,357321,358872,360436,362013,363604,
+365208,366826,368459,370105,371765,373440,375130,376835,
+378555,380290,382040,383807,385589,387387,389202,391034,
+392882,394747,396630,398530,400448,402384,404338,406311,
+408303,410314,412344,414395,416465,418555,420666,422798,
+424951,427125,429321,431540,433781,436045,438332,440643,
+442978,445337,447720,450129,452564,455024,457511,460024,
+462565,465133,467730,470355,473009,475692,478406,481150,
+483925,486732,489571,492443,495348,498287,501261,504269,
+507313,510394,513512,516667,519861,523094,526366,529680,
+533034,536431,539870,543354,546881,550455,554074,557741,
+561456,565221,569035,572901,576818,580789,584815,588896,
+593033,597229,601483,605798,610174,614613,619117,623686,
+628323,633028,637803,642651,647572,652568,657640,662792,
+668024,673338,678737,684223,689797,695462,701219,707072,
+713023,719074,725227,731486,737853,744331,750922,757631,
+764460,771411,778490,785699,793041,800521,808143,815910,
+823827,831898,840127,848520,857081,865817,874730,883829,
+893117,902602,912289,922186,932298,942633,953199,964003,
+975054,986361,997931,1009774,1021901,1034322,1047046,1060087,
+1073455,1087164,1101225,1115654,1130465,1145673,1161294,1177345,
+1193846,1210813,1228269,1246234,1264730,1283783,1303416,1323658,
+1344537,1366084,1388330,1411312,1435065,1459630,1485049,1511367,
+1538632,1566898,1596220,1626658,1658278,1691149,1725348,1760956,
+1798063,1836758,1877161,1919378,1963536,2009771,2058233,2109087,
+2162516,2218719,2277919,2340362,2406322,2476104,2550052,2628549,
+2712030,2800983,2895966,2997613,3106651,3223918,3350381,3487165,
+3635590,3797206,3973855,4167737,4381502,4618375,4882318,5178251,
+5512368,5892567,6329090,6835455,7429880,8137527,8994149,10052327,
+11392683,13145455,15535599,18988036,24413316,34178904,56965752,170910304
+};
+
+int finesine[10240] =
+{
+25,75,125,175,226,276,326,376,
+427,477,527,578,628,678,728,779,
+829,879,929,980,1030,1080,1130,1181,
+1231,1281,1331,1382,1432,1482,1532,1583,
+1633,1683,1733,1784,1834,1884,1934,1985,
+2035,2085,2135,2186,2236,2286,2336,2387,
+2437,2487,2537,2587,2638,2688,2738,2788,
+2839,2889,2939,2989,3039,3090,3140,3190,
+3240,3291,3341,3391,3441,3491,3541,3592,
+3642,3692,3742,3792,3843,3893,3943,3993,
+4043,4093,4144,4194,4244,4294,4344,4394,
+4445,4495,4545,4595,4645,4695,4745,4796,
+4846,4896,4946,4996,5046,5096,5146,5197,
+5247,5297,5347,5397,5447,5497,5547,5597,
+5647,5697,5748,5798,5848,5898,5948,5998,
+6048,6098,6148,6198,6248,6298,6348,6398,
+6448,6498,6548,6598,6648,6698,6748,6798,
+6848,6898,6948,6998,7048,7098,7148,7198,
+7248,7298,7348,7398,7448,7498,7548,7598,
+7648,7697,7747,7797,7847,7897,7947,7997,
+8047,8097,8147,8196,8246,8296,8346,8396,
+8446,8496,8545,8595,8645,8695,8745,8794,
+8844,8894,8944,8994,9043,9093,9143,9193,
+9243,9292,9342,9392,9442,9491,9541,9591,
+9640,9690,9740,9790,9839,9889,9939,9988,
+10038,10088,10137,10187,10237,10286,10336,10386,
+10435,10485,10534,10584,10634,10683,10733,10782,
+10832,10882,10931,10981,11030,11080,11129,11179,
+11228,11278,11327,11377,11426,11476,11525,11575,
+11624,11674,11723,11773,11822,11872,11921,11970,
+12020,12069,12119,12168,12218,12267,12316,12366,
+12415,12464,12514,12563,12612,12662,12711,12760,
+12810,12859,12908,12957,13007,13056,13105,13154,
+13204,13253,13302,13351,13401,13450,13499,13548,
+13597,13647,13696,13745,13794,13843,13892,13941,
+13990,14040,14089,14138,14187,14236,14285,14334,
+14383,14432,14481,14530,14579,14628,14677,14726,
+14775,14824,14873,14922,14971,15020,15069,15118,
+15167,15215,15264,15313,15362,15411,15460,15509,
+15557,15606,15655,15704,15753,15802,15850,15899,
+15948,15997,16045,16094,16143,16191,16240,16289,
+16338,16386,16435,16484,16532,16581,16629,16678,
+16727,16775,16824,16872,16921,16970,17018,17067,
+17115,17164,17212,17261,17309,17358,17406,17455,
+17503,17551,17600,17648,17697,17745,17793,17842,
+17890,17939,17987,18035,18084,18132,18180,18228,
+18277,18325,18373,18421,18470,18518,18566,18614,
+18663,18711,18759,18807,18855,18903,18951,19000,
+19048,19096,19144,19192,19240,19288,19336,19384,
+19432,19480,19528,19576,19624,19672,19720,19768,
+19816,19864,19912,19959,20007,20055,20103,20151,
+20199,20246,20294,20342,20390,20438,20485,20533,
+20581,20629,20676,20724,20772,20819,20867,20915,
+20962,21010,21057,21105,21153,21200,21248,21295,
+21343,21390,21438,21485,21533,21580,21628,21675,
+21723,21770,21817,21865,21912,21960,22007,22054,
+22102,22149,22196,22243,22291,22338,22385,22433,
+22480,22527,22574,22621,22668,22716,22763,22810,
+22857,22904,22951,22998,23045,23092,23139,23186,
+23233,23280,23327,23374,23421,23468,23515,23562,
+23609,23656,23703,23750,23796,23843,23890,23937,
+23984,24030,24077,24124,24171,24217,24264,24311,
+24357,24404,24451,24497,24544,24591,24637,24684,
+24730,24777,24823,24870,24916,24963,25009,25056,
+25102,25149,25195,25241,25288,25334,25381,25427,
+25473,25520,25566,25612,25658,25705,25751,25797,
+25843,25889,25936,25982,26028,26074,26120,26166,
+26212,26258,26304,26350,26396,26442,26488,26534,
+26580,26626,26672,26718,26764,26810,26856,26902,
+26947,26993,27039,27085,27131,27176,27222,27268,
+27313,27359,27405,27450,27496,27542,27587,27633,
+27678,27724,27770,27815,27861,27906,27952,27997,
+28042,28088,28133,28179,28224,28269,28315,28360,
+28405,28451,28496,28541,28586,28632,28677,28722,
+28767,28812,28858,28903,28948,28993,29038,29083,
+29128,29173,29218,29263,29308,29353,29398,29443,
+29488,29533,29577,29622,29667,29712,29757,29801,
+29846,29891,29936,29980,30025,30070,30114,30159,
+30204,30248,30293,30337,30382,30426,30471,30515,
+30560,30604,30649,30693,30738,30782,30826,30871,
+30915,30959,31004,31048,31092,31136,31181,31225,
+31269,31313,31357,31402,31446,31490,31534,31578,
+31622,31666,31710,31754,31798,31842,31886,31930,
+31974,32017,32061,32105,32149,32193,32236,32280,
+32324,32368,32411,32455,32499,32542,32586,32630,
+32673,32717,32760,32804,32847,32891,32934,32978,
+33021,33065,33108,33151,33195,33238,33281,33325,
+33368,33411,33454,33498,33541,33584,33627,33670,
+33713,33756,33799,33843,33886,33929,33972,34015,
+34057,34100,34143,34186,34229,34272,34315,34358,
+34400,34443,34486,34529,34571,34614,34657,34699,
+34742,34785,34827,34870,34912,34955,34997,35040,
+35082,35125,35167,35210,35252,35294,35337,35379,
+35421,35464,35506,35548,35590,35633,35675,35717,
+35759,35801,35843,35885,35927,35969,36011,36053,
+36095,36137,36179,36221,36263,36305,36347,36388,
+36430,36472,36514,36555,36597,36639,36681,36722,
+36764,36805,36847,36889,36930,36972,37013,37055,
+37096,37137,37179,37220,37262,37303,37344,37386,
+37427,37468,37509,37551,37592,37633,37674,37715,
+37756,37797,37838,37879,37920,37961,38002,38043,
+38084,38125,38166,38207,38248,38288,38329,38370,
+38411,38451,38492,38533,38573,38614,38655,38695,
+38736,38776,38817,38857,38898,38938,38979,39019,
+39059,39100,39140,39180,39221,39261,39301,39341,
+39382,39422,39462,39502,39542,39582,39622,39662,
+39702,39742,39782,39822,39862,39902,39942,39982,
+40021,40061,40101,40141,40180,40220,40260,40300,
+40339,40379,40418,40458,40497,40537,40576,40616,
+40655,40695,40734,40773,40813,40852,40891,40931,
+40970,41009,41048,41087,41127,41166,41205,41244,
+41283,41322,41361,41400,41439,41478,41517,41556,
+41595,41633,41672,41711,41750,41788,41827,41866,
+41904,41943,41982,42020,42059,42097,42136,42174,
+42213,42251,42290,42328,42366,42405,42443,42481,
+42520,42558,42596,42634,42672,42711,42749,42787,
+42825,42863,42901,42939,42977,43015,43053,43091,
+43128,43166,43204,43242,43280,43317,43355,43393,
+43430,43468,43506,43543,43581,43618,43656,43693,
+43731,43768,43806,43843,43880,43918,43955,43992,
+44029,44067,44104,44141,44178,44215,44252,44289,
+44326,44363,44400,44437,44474,44511,44548,44585,
+44622,44659,44695,44732,44769,44806,44842,44879,
+44915,44952,44989,45025,45062,45098,45135,45171,
+45207,45244,45280,45316,45353,45389,45425,45462,
+45498,45534,45570,45606,45642,45678,45714,45750,
+45786,45822,45858,45894,45930,45966,46002,46037,
+46073,46109,46145,46180,46216,46252,46287,46323,
+46358,46394,46429,46465,46500,46536,46571,46606,
+46642,46677,46712,46747,46783,46818,46853,46888,
+46923,46958,46993,47028,47063,47098,47133,47168,
+47203,47238,47273,47308,47342,47377,47412,47446,
+47481,47516,47550,47585,47619,47654,47688,47723,
+47757,47792,47826,47860,47895,47929,47963,47998,
+48032,48066,48100,48134,48168,48202,48237,48271,
+48305,48338,48372,48406,48440,48474,48508,48542,
+48575,48609,48643,48676,48710,48744,48777,48811,
+48844,48878,48911,48945,48978,49012,49045,49078,
+49112,49145,49178,49211,49244,49278,49311,49344,
+49377,49410,49443,49476,49509,49542,49575,49608,
+49640,49673,49706,49739,49771,49804,49837,49869,
+49902,49935,49967,50000,50032,50065,50097,50129,
+50162,50194,50226,50259,50291,50323,50355,50387,
+50420,50452,50484,50516,50548,50580,50612,50644,
+50675,50707,50739,50771,50803,50834,50866,50898,
+50929,50961,50993,51024,51056,51087,51119,51150,
+51182,51213,51244,51276,51307,51338,51369,51401,
+51432,51463,51494,51525,51556,51587,51618,51649,
+51680,51711,51742,51773,51803,51834,51865,51896,
+51926,51957,51988,52018,52049,52079,52110,52140,
+52171,52201,52231,52262,52292,52322,52353,52383,
+52413,52443,52473,52503,52534,52564,52594,52624,
+52653,52683,52713,52743,52773,52803,52832,52862,
+52892,52922,52951,52981,53010,53040,53069,53099,
+53128,53158,53187,53216,53246,53275,53304,53334,
+53363,53392,53421,53450,53479,53508,53537,53566,
+53595,53624,53653,53682,53711,53739,53768,53797,
+53826,53854,53883,53911,53940,53969,53997,54026,
+54054,54082,54111,54139,54167,54196,54224,54252,
+54280,54308,54337,54365,54393,54421,54449,54477,
+54505,54533,54560,54588,54616,54644,54672,54699,
+54727,54755,54782,54810,54837,54865,54892,54920,
+54947,54974,55002,55029,55056,55084,55111,55138,
+55165,55192,55219,55246,55274,55300,55327,55354,
+55381,55408,55435,55462,55489,55515,55542,55569,
+55595,55622,55648,55675,55701,55728,55754,55781,
+55807,55833,55860,55886,55912,55938,55965,55991,
+56017,56043,56069,56095,56121,56147,56173,56199,
+56225,56250,56276,56302,56328,56353,56379,56404,
+56430,56456,56481,56507,56532,56557,56583,56608,
+56633,56659,56684,56709,56734,56760,56785,56810,
+56835,56860,56885,56910,56935,56959,56984,57009,
+57034,57059,57083,57108,57133,57157,57182,57206,
+57231,57255,57280,57304,57329,57353,57377,57402,
+57426,57450,57474,57498,57522,57546,57570,57594,
+57618,57642,57666,57690,57714,57738,57762,57785,
+57809,57833,57856,57880,57903,57927,57950,57974,
+57997,58021,58044,58067,58091,58114,58137,58160,
+58183,58207,58230,58253,58276,58299,58322,58345,
+58367,58390,58413,58436,58459,58481,58504,58527,
+58549,58572,58594,58617,58639,58662,58684,58706,
+58729,58751,58773,58795,58818,58840,58862,58884,
+58906,58928,58950,58972,58994,59016,59038,59059,
+59081,59103,59125,59146,59168,59190,59211,59233,
+59254,59276,59297,59318,59340,59361,59382,59404,
+59425,59446,59467,59488,59509,59530,59551,59572,
+59593,59614,59635,59656,59677,59697,59718,59739,
+59759,59780,59801,59821,59842,59862,59883,59903,
+59923,59944,59964,59984,60004,60025,60045,60065,
+60085,60105,60125,60145,60165,60185,60205,60225,
+60244,60264,60284,60304,60323,60343,60363,60382,
+60402,60421,60441,60460,60479,60499,60518,60537,
+60556,60576,60595,60614,60633,60652,60671,60690,
+60709,60728,60747,60766,60785,60803,60822,60841,
+60859,60878,60897,60915,60934,60952,60971,60989,
+61007,61026,61044,61062,61081,61099,61117,61135,
+61153,61171,61189,61207,61225,61243,61261,61279,
+61297,61314,61332,61350,61367,61385,61403,61420,
+61438,61455,61473,61490,61507,61525,61542,61559,
+61577,61594,61611,61628,61645,61662,61679,61696,
+61713,61730,61747,61764,61780,61797,61814,61831,
+61847,61864,61880,61897,61913,61930,61946,61963,
+61979,61995,62012,62028,62044,62060,62076,62092,
+62108,62125,62141,62156,62172,62188,62204,62220,
+62236,62251,62267,62283,62298,62314,62329,62345,
+62360,62376,62391,62407,62422,62437,62453,62468,
+62483,62498,62513,62528,62543,62558,62573,62588,
+62603,62618,62633,62648,62662,62677,62692,62706,
+62721,62735,62750,62764,62779,62793,62808,62822,
+62836,62850,62865,62879,62893,62907,62921,62935,
+62949,62963,62977,62991,63005,63019,63032,63046,
+63060,63074,63087,63101,63114,63128,63141,63155,
+63168,63182,63195,63208,63221,63235,63248,63261,
+63274,63287,63300,63313,63326,63339,63352,63365,
+63378,63390,63403,63416,63429,63441,63454,63466,
+63479,63491,63504,63516,63528,63541,63553,63565,
+63578,63590,63602,63614,63626,63638,63650,63662,
+63674,63686,63698,63709,63721,63733,63745,63756,
+63768,63779,63791,63803,63814,63825,63837,63848,
+63859,63871,63882,63893,63904,63915,63927,63938,
+63949,63960,63971,63981,63992,64003,64014,64025,
+64035,64046,64057,64067,64078,64088,64099,64109,
+64120,64130,64140,64151,64161,64171,64181,64192,
+64202,64212,64222,64232,64242,64252,64261,64271,
+64281,64291,64301,64310,64320,64330,64339,64349,
+64358,64368,64377,64387,64396,64405,64414,64424,
+64433,64442,64451,64460,64469,64478,64487,64496,
+64505,64514,64523,64532,64540,64549,64558,64566,
+64575,64584,64592,64601,64609,64617,64626,64634,
+64642,64651,64659,64667,64675,64683,64691,64699,
+64707,64715,64723,64731,64739,64747,64754,64762,
+64770,64777,64785,64793,64800,64808,64815,64822,
+64830,64837,64844,64852,64859,64866,64873,64880,
+64887,64895,64902,64908,64915,64922,64929,64936,
+64943,64949,64956,64963,64969,64976,64982,64989,
+64995,65002,65008,65015,65021,65027,65033,65040,
+65046,65052,65058,65064,65070,65076,65082,65088,
+65094,65099,65105,65111,65117,65122,65128,65133,
+65139,65144,65150,65155,65161,65166,65171,65177,
+65182,65187,65192,65197,65202,65207,65212,65217,
+65222,65227,65232,65237,65242,65246,65251,65256,
+65260,65265,65270,65274,65279,65283,65287,65292,
+65296,65300,65305,65309,65313,65317,65321,65325,
+65329,65333,65337,65341,65345,65349,65352,65356,
+65360,65363,65367,65371,65374,65378,65381,65385,
+65388,65391,65395,65398,65401,65404,65408,65411,
+65414,65417,65420,65423,65426,65429,65431,65434,
+65437,65440,65442,65445,65448,65450,65453,65455,
+65458,65460,65463,65465,65467,65470,65472,65474,
+65476,65478,65480,65482,65484,65486,65488,65490,
+65492,65494,65496,65497,65499,65501,65502,65504,
+65505,65507,65508,65510,65511,65513,65514,65515,
+65516,65518,65519,65520,65521,65522,65523,65524,
+65525,65526,65527,65527,65528,65529,65530,65530,
+65531,65531,65532,65532,65533,65533,65534,65534,
+65534,65535,65535,65535,65535,65535,65535,65535,
+65535,65535,65535,65535,65535,65535,65535,65534,
+65534,65534,65533,65533,65532,65532,65531,65531,
+65530,65530,65529,65528,65527,65527,65526,65525,
+65524,65523,65522,65521,65520,65519,65518,65516,
+65515,65514,65513,65511,65510,65508,65507,65505,
+65504,65502,65501,65499,65497,65496,65494,65492,
+65490,65488,65486,65484,65482,65480,65478,65476,
+65474,65472,65470,65467,65465,65463,65460,65458,
+65455,65453,65450,65448,65445,65442,65440,65437,
+65434,65431,65429,65426,65423,65420,65417,65414,
+65411,65408,65404,65401,65398,65395,65391,65388,
+65385,65381,65378,65374,65371,65367,65363,65360,
+65356,65352,65349,65345,65341,65337,65333,65329,
+65325,65321,65317,65313,65309,65305,65300,65296,
+65292,65287,65283,65279,65274,65270,65265,65260,
+65256,65251,65246,65242,65237,65232,65227,65222,
+65217,65212,65207,65202,65197,65192,65187,65182,
+65177,65171,65166,65161,65155,65150,65144,65139,
+65133,65128,65122,65117,65111,65105,65099,65094,
+65088,65082,65076,65070,65064,65058,65052,65046,
+65040,65033,65027,65021,65015,65008,65002,64995,
+64989,64982,64976,64969,64963,64956,64949,64943,
+64936,64929,64922,64915,64908,64902,64895,64887,
+64880,64873,64866,64859,64852,64844,64837,64830,
+64822,64815,64808,64800,64793,64785,64777,64770,
+64762,64754,64747,64739,64731,64723,64715,64707,
+64699,64691,64683,64675,64667,64659,64651,64642,
+64634,64626,64617,64609,64600,64592,64584,64575,
+64566,64558,64549,64540,64532,64523,64514,64505,
+64496,64487,64478,64469,64460,64451,64442,64433,
+64424,64414,64405,64396,64387,64377,64368,64358,
+64349,64339,64330,64320,64310,64301,64291,64281,
+64271,64261,64252,64242,64232,64222,64212,64202,
+64192,64181,64171,64161,64151,64140,64130,64120,
+64109,64099,64088,64078,64067,64057,64046,64035,
+64025,64014,64003,63992,63981,63971,63960,63949,
+63938,63927,63915,63904,63893,63882,63871,63859,
+63848,63837,63825,63814,63803,63791,63779,63768,
+63756,63745,63733,63721,63709,63698,63686,63674,
+63662,63650,63638,63626,63614,63602,63590,63578,
+63565,63553,63541,63528,63516,63504,63491,63479,
+63466,63454,63441,63429,63416,63403,63390,63378,
+63365,63352,63339,63326,63313,63300,63287,63274,
+63261,63248,63235,63221,63208,63195,63182,63168,
+63155,63141,63128,63114,63101,63087,63074,63060,
+63046,63032,63019,63005,62991,62977,62963,62949,
+62935,62921,62907,62893,62879,62865,62850,62836,
+62822,62808,62793,62779,62764,62750,62735,62721,
+62706,62692,62677,62662,62648,62633,62618,62603,
+62588,62573,62558,62543,62528,62513,62498,62483,
+62468,62453,62437,62422,62407,62391,62376,62360,
+62345,62329,62314,62298,62283,62267,62251,62236,
+62220,62204,62188,62172,62156,62141,62125,62108,
+62092,62076,62060,62044,62028,62012,61995,61979,
+61963,61946,61930,61913,61897,61880,61864,61847,
+61831,61814,61797,61780,61764,61747,61730,61713,
+61696,61679,61662,61645,61628,61611,61594,61577,
+61559,61542,61525,61507,61490,61473,61455,61438,
+61420,61403,61385,61367,61350,61332,61314,61297,
+61279,61261,61243,61225,61207,61189,61171,61153,
+61135,61117,61099,61081,61062,61044,61026,61007,
+60989,60971,60952,60934,60915,60897,60878,60859,
+60841,60822,60803,60785,60766,60747,60728,60709,
+60690,60671,60652,60633,60614,60595,60576,60556,
+60537,60518,60499,60479,60460,60441,60421,60402,
+60382,60363,60343,60323,60304,60284,60264,60244,
+60225,60205,60185,60165,60145,60125,60105,60085,
+60065,60045,60025,60004,59984,59964,59944,59923,
+59903,59883,59862,59842,59821,59801,59780,59759,
+59739,59718,59697,59677,59656,59635,59614,59593,
+59572,59551,59530,59509,59488,59467,59446,59425,
+59404,59382,59361,59340,59318,59297,59276,59254,
+59233,59211,59190,59168,59146,59125,59103,59081,
+59059,59038,59016,58994,58972,58950,58928,58906,
+58884,58862,58840,58818,58795,58773,58751,58729,
+58706,58684,58662,58639,58617,58594,58572,58549,
+58527,58504,58481,58459,58436,58413,58390,58367,
+58345,58322,58299,58276,58253,58230,58207,58183,
+58160,58137,58114,58091,58067,58044,58021,57997,
+57974,57950,57927,57903,57880,57856,57833,57809,
+57785,57762,57738,57714,57690,57666,57642,57618,
+57594,57570,57546,57522,57498,57474,57450,57426,
+57402,57377,57353,57329,57304,57280,57255,57231,
+57206,57182,57157,57133,57108,57083,57059,57034,
+57009,56984,56959,56935,56910,56885,56860,56835,
+56810,56785,56760,56734,56709,56684,56659,56633,
+56608,56583,56557,56532,56507,56481,56456,56430,
+56404,56379,56353,56328,56302,56276,56250,56225,
+56199,56173,56147,56121,56095,56069,56043,56017,
+55991,55965,55938,55912,55886,55860,55833,55807,
+55781,55754,55728,55701,55675,55648,55622,55595,
+55569,55542,55515,55489,55462,55435,55408,55381,
+55354,55327,55300,55274,55246,55219,55192,55165,
+55138,55111,55084,55056,55029,55002,54974,54947,
+54920,54892,54865,54837,54810,54782,54755,54727,
+54699,54672,54644,54616,54588,54560,54533,54505,
+54477,54449,54421,54393,54365,54337,54308,54280,
+54252,54224,54196,54167,54139,54111,54082,54054,
+54026,53997,53969,53940,53911,53883,53854,53826,
+53797,53768,53739,53711,53682,53653,53624,53595,
+53566,53537,53508,53479,53450,53421,53392,53363,
+53334,53304,53275,53246,53216,53187,53158,53128,
+53099,53069,53040,53010,52981,52951,52922,52892,
+52862,52832,52803,52773,52743,52713,52683,52653,
+52624,52594,52564,52534,52503,52473,52443,52413,
+52383,52353,52322,52292,52262,52231,52201,52171,
+52140,52110,52079,52049,52018,51988,51957,51926,
+51896,51865,51834,51803,51773,51742,51711,51680,
+51649,51618,51587,51556,51525,51494,51463,51432,
+51401,51369,51338,51307,51276,51244,51213,51182,
+51150,51119,51087,51056,51024,50993,50961,50929,
+50898,50866,50834,50803,50771,50739,50707,50675,
+50644,50612,50580,50548,50516,50484,50452,50420,
+50387,50355,50323,50291,50259,50226,50194,50162,
+50129,50097,50065,50032,50000,49967,49935,49902,
+49869,49837,49804,49771,49739,49706,49673,49640,
+49608,49575,49542,49509,49476,49443,49410,49377,
+49344,49311,49278,49244,49211,49178,49145,49112,
+49078,49045,49012,48978,48945,48911,48878,48844,
+48811,48777,48744,48710,48676,48643,48609,48575,
+48542,48508,48474,48440,48406,48372,48338,48304,
+48271,48237,48202,48168,48134,48100,48066,48032,
+47998,47963,47929,47895,47860,47826,47792,47757,
+47723,47688,47654,47619,47585,47550,47516,47481,
+47446,47412,47377,47342,47308,47273,47238,47203,
+47168,47133,47098,47063,47028,46993,46958,46923,
+46888,46853,46818,46783,46747,46712,46677,46642,
+46606,46571,46536,46500,46465,46429,46394,46358,
+46323,46287,46252,46216,46180,46145,46109,46073,
+46037,46002,45966,45930,45894,45858,45822,45786,
+45750,45714,45678,45642,45606,45570,45534,45498,
+45462,45425,45389,45353,45316,45280,45244,45207,
+45171,45135,45098,45062,45025,44989,44952,44915,
+44879,44842,44806,44769,44732,44695,44659,44622,
+44585,44548,44511,44474,44437,44400,44363,44326,
+44289,44252,44215,44178,44141,44104,44067,44029,
+43992,43955,43918,43880,43843,43806,43768,43731,
+43693,43656,43618,43581,43543,43506,43468,43430,
+43393,43355,43317,43280,43242,43204,43166,43128,
+43091,43053,43015,42977,42939,42901,42863,42825,
+42787,42749,42711,42672,42634,42596,42558,42520,
+42481,42443,42405,42366,42328,42290,42251,42213,
+42174,42136,42097,42059,42020,41982,41943,41904,
+41866,41827,41788,41750,41711,41672,41633,41595,
+41556,41517,41478,41439,41400,41361,41322,41283,
+41244,41205,41166,41127,41088,41048,41009,40970,
+40931,40891,40852,40813,40773,40734,40695,40655,
+40616,40576,40537,40497,40458,40418,40379,40339,
+40300,40260,40220,40180,40141,40101,40061,40021,
+39982,39942,39902,39862,39822,39782,39742,39702,
+39662,39622,39582,39542,39502,39462,39422,39382,
+39341,39301,39261,39221,39180,39140,39100,39059,
+39019,38979,38938,38898,38857,38817,38776,38736,
+38695,38655,38614,38573,38533,38492,38451,38411,
+38370,38329,38288,38248,38207,38166,38125,38084,
+38043,38002,37961,37920,37879,37838,37797,37756,
+37715,37674,37633,37592,37551,37509,37468,37427,
+37386,37344,37303,37262,37220,37179,37137,37096,
+37055,37013,36972,36930,36889,36847,36805,36764,
+36722,36681,36639,36597,36556,36514,36472,36430,
+36388,36347,36305,36263,36221,36179,36137,36095,
+36053,36011,35969,35927,35885,35843,35801,35759,
+35717,35675,35633,35590,35548,35506,35464,35421,
+35379,35337,35294,35252,35210,35167,35125,35082,
+35040,34997,34955,34912,34870,34827,34785,34742,
+34699,34657,34614,34571,34529,34486,34443,34400,
+34358,34315,34272,34229,34186,34143,34100,34057,
+34015,33972,33929,33886,33843,33799,33756,33713,
+33670,33627,33584,33541,33498,33454,33411,33368,
+33325,33281,33238,33195,33151,33108,33065,33021,
+32978,32934,32891,32847,32804,32760,32717,32673,
+32630,32586,32542,32499,32455,32411,32368,32324,
+32280,32236,32193,32149,32105,32061,32017,31974,
+31930,31886,31842,31798,31754,31710,31666,31622,
+31578,31534,31490,31446,31402,31357,31313,31269,
+31225,31181,31136,31092,31048,31004,30959,30915,
+30871,30826,30782,30738,30693,30649,30604,30560,
+30515,30471,30426,30382,30337,30293,30248,30204,
+30159,30114,30070,30025,29980,29936,29891,29846,
+29801,29757,29712,29667,29622,29577,29533,29488,
+29443,29398,29353,29308,29263,29218,29173,29128,
+29083,29038,28993,28948,28903,28858,28812,28767,
+28722,28677,28632,28586,28541,28496,28451,28405,
+28360,28315,28269,28224,28179,28133,28088,28042,
+27997,27952,27906,27861,27815,27770,27724,27678,
+27633,27587,27542,27496,27450,27405,27359,27313,
+27268,27222,27176,27131,27085,27039,26993,26947,
+26902,26856,26810,26764,26718,26672,26626,26580,
+26534,26488,26442,26396,26350,26304,26258,26212,
+26166,26120,26074,26028,25982,25936,25889,25843,
+25797,25751,25705,25658,25612,25566,25520,25473,
+25427,25381,25334,25288,25241,25195,25149,25102,
+25056,25009,24963,24916,24870,24823,24777,24730,
+24684,24637,24591,24544,24497,24451,24404,24357,
+24311,24264,24217,24171,24124,24077,24030,23984,
+23937,23890,23843,23796,23750,23703,23656,23609,
+23562,23515,23468,23421,23374,23327,23280,23233,
+23186,23139,23092,23045,22998,22951,22904,22857,
+22810,22763,22716,22668,22621,22574,22527,22480,
+22433,22385,22338,22291,22243,22196,22149,22102,
+22054,22007,21960,21912,21865,21817,21770,21723,
+21675,21628,21580,21533,21485,21438,21390,21343,
+21295,21248,21200,21153,21105,21057,21010,20962,
+20915,20867,20819,20772,20724,20676,20629,20581,
+20533,20485,20438,20390,20342,20294,20246,20199,
+20151,20103,20055,20007,19959,19912,19864,19816,
+19768,19720,19672,19624,19576,19528,19480,19432,
+19384,19336,19288,19240,19192,19144,19096,19048,
+19000,18951,18903,18855,18807,18759,18711,18663,
+18614,18566,18518,18470,18421,18373,18325,18277,
+18228,18180,18132,18084,18035,17987,17939,17890,
+17842,17793,17745,17697,17648,17600,17551,17503,
+17455,17406,17358,17309,17261,17212,17164,17115,
+17067,17018,16970,16921,16872,16824,16775,16727,
+16678,16629,16581,16532,16484,16435,16386,16338,
+16289,16240,16191,16143,16094,16045,15997,15948,
+15899,15850,15802,15753,15704,15655,15606,15557,
+15509,15460,15411,15362,15313,15264,15215,15167,
+15118,15069,15020,14971,14922,14873,14824,14775,
+14726,14677,14628,14579,14530,14481,14432,14383,
+14334,14285,14236,14187,14138,14089,14040,13990,
+13941,13892,13843,13794,13745,13696,13646,13597,
+13548,13499,13450,13401,13351,13302,13253,13204,
+13154,13105,13056,13007,12957,12908,12859,12810,
+12760,12711,12662,12612,12563,12514,12464,12415,
+12366,12316,12267,12218,12168,12119,12069,12020,
+11970,11921,11872,11822,11773,11723,11674,11624,
+11575,11525,11476,11426,11377,11327,11278,11228,
+11179,11129,11080,11030,10981,10931,10882,10832,
+10782,10733,10683,10634,10584,10534,10485,10435,
+10386,10336,10286,10237,10187,10137,10088,10038,
+9988,9939,9889,9839,9790,9740,9690,9640,
+9591,9541,9491,9442,9392,9342,9292,9243,
+9193,9143,9093,9043,8994,8944,8894,8844,
+8794,8745,8695,8645,8595,8545,8496,8446,
+8396,8346,8296,8246,8196,8147,8097,8047,
+7997,7947,7897,7847,7797,7747,7697,7648,
+7598,7548,7498,7448,7398,7348,7298,7248,
+7198,7148,7098,7048,6998,6948,6898,6848,
+6798,6748,6698,6648,6598,6548,6498,6448,
+6398,6348,6298,6248,6198,6148,6098,6048,
+5998,5948,5898,5848,5798,5748,5697,5647,
+5597,5547,5497,5447,5397,5347,5297,5247,
+5197,5146,5096,5046,4996,4946,4896,4846,
+4796,4745,4695,4645,4595,4545,4495,4445,
+4394,4344,4294,4244,4194,4144,4093,4043,
+3993,3943,3893,3843,3792,3742,3692,3642,
+3592,3541,3491,3441,3391,3341,3291,3240,
+3190,3140,3090,3039,2989,2939,2889,2839,
+2788,2738,2688,2638,2587,2537,2487,2437,
+2387,2336,2286,2236,2186,2135,2085,2035,
+1985,1934,1884,1834,1784,1733,1683,1633,
+1583,1532,1482,1432,1382,1331,1281,1231,
+1181,1130,1080,1030,980,929,879,829,
+779,728,678,628,578,527,477,427,
+376,326,276,226,175,125,75,25,
+-25,-75,-125,-175,-226,-276,-326,-376,
+-427,-477,-527,-578,-628,-678,-728,-779,
+-829,-879,-929,-980,-1030,-1080,-1130,-1181,
+-1231,-1281,-1331,-1382,-1432,-1482,-1532,-1583,
+-1633,-1683,-1733,-1784,-1834,-1884,-1934,-1985,
+-2035,-2085,-2135,-2186,-2236,-2286,-2336,-2387,
+-2437,-2487,-2537,-2588,-2638,-2688,-2738,-2788,
+-2839,-2889,-2939,-2989,-3039,-3090,-3140,-3190,
+-3240,-3291,-3341,-3391,-3441,-3491,-3541,-3592,
+-3642,-3692,-3742,-3792,-3843,-3893,-3943,-3993,
+-4043,-4093,-4144,-4194,-4244,-4294,-4344,-4394,
+-4445,-4495,-4545,-4595,-4645,-4695,-4745,-4796,
+-4846,-4896,-4946,-4996,-5046,-5096,-5146,-5197,
+-5247,-5297,-5347,-5397,-5447,-5497,-5547,-5597,
+-5647,-5697,-5748,-5798,-5848,-5898,-5948,-5998,
+-6048,-6098,-6148,-6198,-6248,-6298,-6348,-6398,
+-6448,-6498,-6548,-6598,-6648,-6698,-6748,-6798,
+-6848,-6898,-6948,-6998,-7048,-7098,-7148,-7198,
+-7248,-7298,-7348,-7398,-7448,-7498,-7548,-7598,
+-7648,-7697,-7747,-7797,-7847,-7897,-7947,-7997,
+-8047,-8097,-8147,-8196,-8246,-8296,-8346,-8396,
+-8446,-8496,-8545,-8595,-8645,-8695,-8745,-8794,
+-8844,-8894,-8944,-8994,-9043,-9093,-9143,-9193,
+-9243,-9292,-9342,-9392,-9442,-9491,-9541,-9591,
+-9640,-9690,-9740,-9790,-9839,-9889,-9939,-9988,
+-10038,-10088,-10137,-10187,-10237,-10286,-10336,-10386,
+-10435,-10485,-10534,-10584,-10634,-10683,-10733,-10782,
+-10832,-10882,-10931,-10981,-11030,-11080,-11129,-11179,
+-11228,-11278,-11327,-11377,-11426,-11476,-11525,-11575,
+-11624,-11674,-11723,-11773,-11822,-11872,-11921,-11970,
+-12020,-12069,-12119,-12168,-12218,-12267,-12316,-12366,
+-12415,-12464,-12514,-12563,-12612,-12662,-12711,-12760,
+-12810,-12859,-12908,-12957,-13007,-13056,-13105,-13154,
+-13204,-13253,-13302,-13351,-13401,-13450,-13499,-13548,
+-13597,-13647,-13696,-13745,-13794,-13843,-13892,-13941,
+-13990,-14040,-14089,-14138,-14187,-14236,-14285,-14334,
+-14383,-14432,-14481,-14530,-14579,-14628,-14677,-14726,
+-14775,-14824,-14873,-14922,-14971,-15020,-15069,-15118,
+-15167,-15215,-15264,-15313,-15362,-15411,-15460,-15509,
+-15557,-15606,-15655,-15704,-15753,-15802,-15850,-15899,
+-15948,-15997,-16045,-16094,-16143,-16191,-16240,-16289,
+-16338,-16386,-16435,-16484,-16532,-16581,-16629,-16678,
+-16727,-16775,-16824,-16872,-16921,-16970,-17018,-17067,
+-17115,-17164,-17212,-17261,-17309,-17358,-17406,-17455,
+-17503,-17551,-17600,-17648,-17697,-17745,-17793,-17842,
+-17890,-17939,-17987,-18035,-18084,-18132,-18180,-18228,
+-18277,-18325,-18373,-18421,-18470,-18518,-18566,-18614,
+-18663,-18711,-18759,-18807,-18855,-18903,-18951,-19000,
+-19048,-19096,-19144,-19192,-19240,-19288,-19336,-19384,
+-19432,-19480,-19528,-19576,-19624,-19672,-19720,-19768,
+-19816,-19864,-19912,-19959,-20007,-20055,-20103,-20151,
+-20199,-20246,-20294,-20342,-20390,-20438,-20485,-20533,
+-20581,-20629,-20676,-20724,-20772,-20819,-20867,-20915,
+-20962,-21010,-21057,-21105,-21153,-21200,-21248,-21295,
+-21343,-21390,-21438,-21485,-21533,-21580,-21628,-21675,
+-21723,-21770,-21817,-21865,-21912,-21960,-22007,-22054,
+-22102,-22149,-22196,-22243,-22291,-22338,-22385,-22433,
+-22480,-22527,-22574,-22621,-22668,-22716,-22763,-22810,
+-22857,-22904,-22951,-22998,-23045,-23092,-23139,-23186,
+-23233,-23280,-23327,-23374,-23421,-23468,-23515,-23562,
+-23609,-23656,-23703,-23750,-23796,-23843,-23890,-23937,
+-23984,-24030,-24077,-24124,-24171,-24217,-24264,-24311,
+-24357,-24404,-24451,-24497,-24544,-24591,-24637,-24684,
+-24730,-24777,-24823,-24870,-24916,-24963,-25009,-25056,
+-25102,-25149,-25195,-25241,-25288,-25334,-25381,-25427,
+-25473,-25520,-25566,-25612,-25658,-25705,-25751,-25797,
+-25843,-25889,-25936,-25982,-26028,-26074,-26120,-26166,
+-26212,-26258,-26304,-26350,-26396,-26442,-26488,-26534,
+-26580,-26626,-26672,-26718,-26764,-26810,-26856,-26902,
+-26947,-26993,-27039,-27085,-27131,-27176,-27222,-27268,
+-27313,-27359,-27405,-27450,-27496,-27542,-27587,-27633,
+-27678,-27724,-27770,-27815,-27861,-27906,-27952,-27997,
+-28042,-28088,-28133,-28179,-28224,-28269,-28315,-28360,
+-28405,-28451,-28496,-28541,-28586,-28632,-28677,-28722,
+-28767,-28812,-28858,-28903,-28948,-28993,-29038,-29083,
+-29128,-29173,-29218,-29263,-29308,-29353,-29398,-29443,
+-29488,-29533,-29577,-29622,-29667,-29712,-29757,-29801,
+-29846,-29891,-29936,-29980,-30025,-30070,-30114,-30159,
+-30204,-30248,-30293,-30337,-30382,-30426,-30471,-30515,
+-30560,-30604,-30649,-30693,-30738,-30782,-30826,-30871,
+-30915,-30959,-31004,-31048,-31092,-31136,-31181,-31225,
+-31269,-31313,-31357,-31402,-31446,-31490,-31534,-31578,
+-31622,-31666,-31710,-31754,-31798,-31842,-31886,-31930,
+-31974,-32017,-32061,-32105,-32149,-32193,-32236,-32280,
+-32324,-32368,-32411,-32455,-32499,-32542,-32586,-32630,
+-32673,-32717,-32760,-32804,-32847,-32891,-32934,-32978,
+-33021,-33065,-33108,-33151,-33195,-33238,-33281,-33325,
+-33368,-33411,-33454,-33498,-33541,-33584,-33627,-33670,
+-33713,-33756,-33799,-33843,-33886,-33929,-33972,-34015,
+-34057,-34100,-34143,-34186,-34229,-34272,-34315,-34358,
+-34400,-34443,-34486,-34529,-34571,-34614,-34657,-34699,
+-34742,-34785,-34827,-34870,-34912,-34955,-34997,-35040,
+-35082,-35125,-35167,-35210,-35252,-35294,-35337,-35379,
+-35421,-35464,-35506,-35548,-35590,-35633,-35675,-35717,
+-35759,-35801,-35843,-35885,-35927,-35969,-36011,-36053,
+-36095,-36137,-36179,-36221,-36263,-36305,-36347,-36388,
+-36430,-36472,-36514,-36555,-36597,-36639,-36681,-36722,
+-36764,-36805,-36847,-36889,-36930,-36972,-37013,-37055,
+-37096,-37137,-37179,-37220,-37262,-37303,-37344,-37386,
+-37427,-37468,-37509,-37551,-37592,-37633,-37674,-37715,
+-37756,-37797,-37838,-37879,-37920,-37961,-38002,-38043,
+-38084,-38125,-38166,-38207,-38248,-38288,-38329,-38370,
+-38411,-38451,-38492,-38533,-38573,-38614,-38655,-38695,
+-38736,-38776,-38817,-38857,-38898,-38938,-38979,-39019,
+-39059,-39100,-39140,-39180,-39221,-39261,-39301,-39341,
+-39382,-39422,-39462,-39502,-39542,-39582,-39622,-39662,
+-39702,-39742,-39782,-39822,-39862,-39902,-39942,-39982,
+-40021,-40061,-40101,-40141,-40180,-40220,-40260,-40299,
+-40339,-40379,-40418,-40458,-40497,-40537,-40576,-40616,
+-40655,-40695,-40734,-40773,-40813,-40852,-40891,-40931,
+-40970,-41009,-41048,-41087,-41127,-41166,-41205,-41244,
+-41283,-41322,-41361,-41400,-41439,-41478,-41517,-41556,
+-41595,-41633,-41672,-41711,-41750,-41788,-41827,-41866,
+-41904,-41943,-41982,-42020,-42059,-42097,-42136,-42174,
+-42213,-42251,-42290,-42328,-42366,-42405,-42443,-42481,
+-42520,-42558,-42596,-42634,-42672,-42711,-42749,-42787,
+-42825,-42863,-42901,-42939,-42977,-43015,-43053,-43091,
+-43128,-43166,-43204,-43242,-43280,-43317,-43355,-43393,
+-43430,-43468,-43506,-43543,-43581,-43618,-43656,-43693,
+-43731,-43768,-43806,-43843,-43880,-43918,-43955,-43992,
+-44029,-44067,-44104,-44141,-44178,-44215,-44252,-44289,
+-44326,-44363,-44400,-44437,-44474,-44511,-44548,-44585,
+-44622,-44659,-44695,-44732,-44769,-44806,-44842,-44879,
+-44915,-44952,-44989,-45025,-45062,-45098,-45135,-45171,
+-45207,-45244,-45280,-45316,-45353,-45389,-45425,-45462,
+-45498,-45534,-45570,-45606,-45642,-45678,-45714,-45750,
+-45786,-45822,-45858,-45894,-45930,-45966,-46002,-46037,
+-46073,-46109,-46145,-46180,-46216,-46252,-46287,-46323,
+-46358,-46394,-46429,-46465,-46500,-46536,-46571,-46606,
+-46642,-46677,-46712,-46747,-46783,-46818,-46853,-46888,
+-46923,-46958,-46993,-47028,-47063,-47098,-47133,-47168,
+-47203,-47238,-47273,-47308,-47342,-47377,-47412,-47446,
+-47481,-47516,-47550,-47585,-47619,-47654,-47688,-47723,
+-47757,-47792,-47826,-47860,-47895,-47929,-47963,-47998,
+-48032,-48066,-48100,-48134,-48168,-48202,-48236,-48271,
+-48304,-48338,-48372,-48406,-48440,-48474,-48508,-48542,
+-48575,-48609,-48643,-48676,-48710,-48744,-48777,-48811,
+-48844,-48878,-48911,-48945,-48978,-49012,-49045,-49078,
+-49112,-49145,-49178,-49211,-49244,-49278,-49311,-49344,
+-49377,-49410,-49443,-49476,-49509,-49542,-49575,-49608,
+-49640,-49673,-49706,-49739,-49771,-49804,-49837,-49869,
+-49902,-49935,-49967,-50000,-50032,-50065,-50097,-50129,
+-50162,-50194,-50226,-50259,-50291,-50323,-50355,-50387,
+-50420,-50452,-50484,-50516,-50548,-50580,-50612,-50644,
+-50675,-50707,-50739,-50771,-50803,-50834,-50866,-50898,
+-50929,-50961,-50993,-51024,-51056,-51087,-51119,-51150,
+-51182,-51213,-51244,-51276,-51307,-51338,-51369,-51401,
+-51432,-51463,-51494,-51525,-51556,-51587,-51618,-51649,
+-51680,-51711,-51742,-51773,-51803,-51834,-51865,-51896,
+-51926,-51957,-51988,-52018,-52049,-52079,-52110,-52140,
+-52171,-52201,-52231,-52262,-52292,-52322,-52353,-52383,
+-52413,-52443,-52473,-52503,-52534,-52564,-52594,-52624,
+-52653,-52683,-52713,-52743,-52773,-52803,-52832,-52862,
+-52892,-52922,-52951,-52981,-53010,-53040,-53069,-53099,
+-53128,-53158,-53187,-53216,-53246,-53275,-53304,-53334,
+-53363,-53392,-53421,-53450,-53479,-53508,-53537,-53566,
+-53595,-53624,-53653,-53682,-53711,-53739,-53768,-53797,
+-53826,-53854,-53883,-53911,-53940,-53969,-53997,-54026,
+-54054,-54082,-54111,-54139,-54167,-54196,-54224,-54252,
+-54280,-54308,-54337,-54365,-54393,-54421,-54449,-54477,
+-54505,-54533,-54560,-54588,-54616,-54644,-54672,-54699,
+-54727,-54755,-54782,-54810,-54837,-54865,-54892,-54920,
+-54947,-54974,-55002,-55029,-55056,-55084,-55111,-55138,
+-55165,-55192,-55219,-55246,-55274,-55300,-55327,-55354,
+-55381,-55408,-55435,-55462,-55489,-55515,-55542,-55569,
+-55595,-55622,-55648,-55675,-55701,-55728,-55754,-55781,
+-55807,-55833,-55860,-55886,-55912,-55938,-55965,-55991,
+-56017,-56043,-56069,-56095,-56121,-56147,-56173,-56199,
+-56225,-56250,-56276,-56302,-56328,-56353,-56379,-56404,
+-56430,-56456,-56481,-56507,-56532,-56557,-56583,-56608,
+-56633,-56659,-56684,-56709,-56734,-56760,-56785,-56810,
+-56835,-56860,-56885,-56910,-56935,-56959,-56984,-57009,
+-57034,-57059,-57083,-57108,-57133,-57157,-57182,-57206,
+-57231,-57255,-57280,-57304,-57329,-57353,-57377,-57402,
+-57426,-57450,-57474,-57498,-57522,-57546,-57570,-57594,
+-57618,-57642,-57666,-57690,-57714,-57738,-57762,-57785,
+-57809,-57833,-57856,-57880,-57903,-57927,-57950,-57974,
+-57997,-58021,-58044,-58067,-58091,-58114,-58137,-58160,
+-58183,-58207,-58230,-58253,-58276,-58299,-58322,-58345,
+-58367,-58390,-58413,-58436,-58459,-58481,-58504,-58527,
+-58549,-58572,-58594,-58617,-58639,-58662,-58684,-58706,
+-58729,-58751,-58773,-58795,-58818,-58840,-58862,-58884,
+-58906,-58928,-58950,-58972,-58994,-59016,-59038,-59059,
+-59081,-59103,-59125,-59146,-59168,-59190,-59211,-59233,
+-59254,-59276,-59297,-59318,-59340,-59361,-59382,-59404,
+-59425,-59446,-59467,-59488,-59509,-59530,-59551,-59572,
+-59593,-59614,-59635,-59656,-59677,-59697,-59718,-59739,
+-59759,-59780,-59801,-59821,-59842,-59862,-59883,-59903,
+-59923,-59944,-59964,-59984,-60004,-60025,-60045,-60065,
+-60085,-60105,-60125,-60145,-60165,-60185,-60205,-60225,
+-60244,-60264,-60284,-60304,-60323,-60343,-60363,-60382,
+-60402,-60421,-60441,-60460,-60479,-60499,-60518,-60537,
+-60556,-60576,-60595,-60614,-60633,-60652,-60671,-60690,
+-60709,-60728,-60747,-60766,-60785,-60803,-60822,-60841,
+-60859,-60878,-60897,-60915,-60934,-60952,-60971,-60989,
+-61007,-61026,-61044,-61062,-61081,-61099,-61117,-61135,
+-61153,-61171,-61189,-61207,-61225,-61243,-61261,-61279,
+-61297,-61314,-61332,-61350,-61367,-61385,-61403,-61420,
+-61438,-61455,-61473,-61490,-61507,-61525,-61542,-61559,
+-61577,-61594,-61611,-61628,-61645,-61662,-61679,-61696,
+-61713,-61730,-61747,-61764,-61780,-61797,-61814,-61831,
+-61847,-61864,-61880,-61897,-61913,-61930,-61946,-61963,
+-61979,-61995,-62012,-62028,-62044,-62060,-62076,-62092,
+-62108,-62125,-62141,-62156,-62172,-62188,-62204,-62220,
+-62236,-62251,-62267,-62283,-62298,-62314,-62329,-62345,
+-62360,-62376,-62391,-62407,-62422,-62437,-62453,-62468,
+-62483,-62498,-62513,-62528,-62543,-62558,-62573,-62588,
+-62603,-62618,-62633,-62648,-62662,-62677,-62692,-62706,
+-62721,-62735,-62750,-62764,-62779,-62793,-62808,-62822,
+-62836,-62850,-62865,-62879,-62893,-62907,-62921,-62935,
+-62949,-62963,-62977,-62991,-63005,-63019,-63032,-63046,
+-63060,-63074,-63087,-63101,-63114,-63128,-63141,-63155,
+-63168,-63182,-63195,-63208,-63221,-63235,-63248,-63261,
+-63274,-63287,-63300,-63313,-63326,-63339,-63352,-63365,
+-63378,-63390,-63403,-63416,-63429,-63441,-63454,-63466,
+-63479,-63491,-63504,-63516,-63528,-63541,-63553,-63565,
+-63578,-63590,-63602,-63614,-63626,-63638,-63650,-63662,
+-63674,-63686,-63698,-63709,-63721,-63733,-63745,-63756,
+-63768,-63779,-63791,-63803,-63814,-63825,-63837,-63848,
+-63859,-63871,-63882,-63893,-63904,-63915,-63927,-63938,
+-63949,-63960,-63971,-63981,-63992,-64003,-64014,-64025,
+-64035,-64046,-64057,-64067,-64078,-64088,-64099,-64109,
+-64120,-64130,-64140,-64151,-64161,-64171,-64181,-64192,
+-64202,-64212,-64222,-64232,-64242,-64252,-64261,-64271,
+-64281,-64291,-64301,-64310,-64320,-64330,-64339,-64349,
+-64358,-64368,-64377,-64387,-64396,-64405,-64414,-64424,
+-64433,-64442,-64451,-64460,-64469,-64478,-64487,-64496,
+-64505,-64514,-64523,-64532,-64540,-64549,-64558,-64566,
+-64575,-64584,-64592,-64601,-64609,-64617,-64626,-64634,
+-64642,-64651,-64659,-64667,-64675,-64683,-64691,-64699,
+-64707,-64715,-64723,-64731,-64739,-64747,-64754,-64762,
+-64770,-64777,-64785,-64793,-64800,-64808,-64815,-64822,
+-64830,-64837,-64844,-64852,-64859,-64866,-64873,-64880,
+-64887,-64895,-64902,-64908,-64915,-64922,-64929,-64936,
+-64943,-64949,-64956,-64963,-64969,-64976,-64982,-64989,
+-64995,-65002,-65008,-65015,-65021,-65027,-65033,-65040,
+-65046,-65052,-65058,-65064,-65070,-65076,-65082,-65088,
+-65094,-65099,-65105,-65111,-65117,-65122,-65128,-65133,
+-65139,-65144,-65150,-65155,-65161,-65166,-65171,-65177,
+-65182,-65187,-65192,-65197,-65202,-65207,-65212,-65217,
+-65222,-65227,-65232,-65237,-65242,-65246,-65251,-65256,
+-65260,-65265,-65270,-65274,-65279,-65283,-65287,-65292,
+-65296,-65300,-65305,-65309,-65313,-65317,-65321,-65325,
+-65329,-65333,-65337,-65341,-65345,-65349,-65352,-65356,
+-65360,-65363,-65367,-65371,-65374,-65378,-65381,-65385,
+-65388,-65391,-65395,-65398,-65401,-65404,-65408,-65411,
+-65414,-65417,-65420,-65423,-65426,-65429,-65431,-65434,
+-65437,-65440,-65442,-65445,-65448,-65450,-65453,-65455,
+-65458,-65460,-65463,-65465,-65467,-65470,-65472,-65474,
+-65476,-65478,-65480,-65482,-65484,-65486,-65488,-65490,
+-65492,-65494,-65496,-65497,-65499,-65501,-65502,-65504,
+-65505,-65507,-65508,-65510,-65511,-65513,-65514,-65515,
+-65516,-65518,-65519,-65520,-65521,-65522,-65523,-65524,
+-65525,-65526,-65527,-65527,-65528,-65529,-65530,-65530,
+-65531,-65531,-65532,-65532,-65533,-65533,-65534,-65534,
+-65534,-65535,-65535,-65535,-65535,-65535,-65535,-65535,
+-65535,-65535,-65535,-65535,-65535,-65535,-65535,-65534,
+-65534,-65534,-65533,-65533,-65532,-65532,-65531,-65531,
+-65530,-65530,-65529,-65528,-65527,-65527,-65526,-65525,
+-65524,-65523,-65522,-65521,-65520,-65519,-65518,-65516,
+-65515,-65514,-65513,-65511,-65510,-65508,-65507,-65505,
+-65504,-65502,-65501,-65499,-65497,-65496,-65494,-65492,
+-65490,-65488,-65486,-65484,-65482,-65480,-65478,-65476,
+-65474,-65472,-65470,-65467,-65465,-65463,-65460,-65458,
+-65455,-65453,-65450,-65448,-65445,-65442,-65440,-65437,
+-65434,-65431,-65429,-65426,-65423,-65420,-65417,-65414,
+-65411,-65408,-65404,-65401,-65398,-65395,-65391,-65388,
+-65385,-65381,-65378,-65374,-65371,-65367,-65363,-65360,
+-65356,-65352,-65349,-65345,-65341,-65337,-65333,-65329,
+-65325,-65321,-65317,-65313,-65309,-65305,-65300,-65296,
+-65292,-65287,-65283,-65279,-65274,-65270,-65265,-65260,
+-65256,-65251,-65246,-65242,-65237,-65232,-65227,-65222,
+-65217,-65212,-65207,-65202,-65197,-65192,-65187,-65182,
+-65177,-65171,-65166,-65161,-65155,-65150,-65144,-65139,
+-65133,-65128,-65122,-65117,-65111,-65105,-65099,-65094,
+-65088,-65082,-65076,-65070,-65064,-65058,-65052,-65046,
+-65040,-65033,-65027,-65021,-65015,-65008,-65002,-64995,
+-64989,-64982,-64976,-64969,-64963,-64956,-64949,-64943,
+-64936,-64929,-64922,-64915,-64908,-64902,-64895,-64887,
+-64880,-64873,-64866,-64859,-64852,-64844,-64837,-64830,
+-64822,-64815,-64808,-64800,-64793,-64785,-64777,-64770,
+-64762,-64754,-64747,-64739,-64731,-64723,-64715,-64707,
+-64699,-64691,-64683,-64675,-64667,-64659,-64651,-64642,
+-64634,-64626,-64617,-64609,-64601,-64592,-64584,-64575,
+-64566,-64558,-64549,-64540,-64532,-64523,-64514,-64505,
+-64496,-64487,-64478,-64469,-64460,-64451,-64442,-64433,
+-64424,-64414,-64405,-64396,-64387,-64377,-64368,-64358,
+-64349,-64339,-64330,-64320,-64310,-64301,-64291,-64281,
+-64271,-64261,-64252,-64242,-64232,-64222,-64212,-64202,
+-64192,-64181,-64171,-64161,-64151,-64140,-64130,-64120,
+-64109,-64099,-64088,-64078,-64067,-64057,-64046,-64035,
+-64025,-64014,-64003,-63992,-63981,-63971,-63960,-63949,
+-63938,-63927,-63915,-63904,-63893,-63882,-63871,-63859,
+-63848,-63837,-63825,-63814,-63803,-63791,-63779,-63768,
+-63756,-63745,-63733,-63721,-63709,-63698,-63686,-63674,
+-63662,-63650,-63638,-63626,-63614,-63602,-63590,-63578,
+-63565,-63553,-63541,-63528,-63516,-63504,-63491,-63479,
+-63466,-63454,-63441,-63429,-63416,-63403,-63390,-63378,
+-63365,-63352,-63339,-63326,-63313,-63300,-63287,-63274,
+-63261,-63248,-63235,-63221,-63208,-63195,-63182,-63168,
+-63155,-63141,-63128,-63114,-63101,-63087,-63074,-63060,
+-63046,-63032,-63019,-63005,-62991,-62977,-62963,-62949,
+-62935,-62921,-62907,-62893,-62879,-62865,-62850,-62836,
+-62822,-62808,-62793,-62779,-62764,-62750,-62735,-62721,
+-62706,-62692,-62677,-62662,-62648,-62633,-62618,-62603,
+-62588,-62573,-62558,-62543,-62528,-62513,-62498,-62483,
+-62468,-62453,-62437,-62422,-62407,-62391,-62376,-62360,
+-62345,-62329,-62314,-62298,-62283,-62267,-62251,-62236,
+-62220,-62204,-62188,-62172,-62156,-62141,-62125,-62108,
+-62092,-62076,-62060,-62044,-62028,-62012,-61995,-61979,
+-61963,-61946,-61930,-61913,-61897,-61880,-61864,-61847,
+-61831,-61814,-61797,-61780,-61764,-61747,-61730,-61713,
+-61696,-61679,-61662,-61645,-61628,-61611,-61594,-61577,
+-61559,-61542,-61525,-61507,-61490,-61473,-61455,-61438,
+-61420,-61403,-61385,-61367,-61350,-61332,-61314,-61297,
+-61279,-61261,-61243,-61225,-61207,-61189,-61171,-61153,
+-61135,-61117,-61099,-61081,-61062,-61044,-61026,-61007,
+-60989,-60971,-60952,-60934,-60915,-60897,-60878,-60859,
+-60841,-60822,-60803,-60785,-60766,-60747,-60728,-60709,
+-60690,-60671,-60652,-60633,-60614,-60595,-60576,-60556,
+-60537,-60518,-60499,-60479,-60460,-60441,-60421,-60402,
+-60382,-60363,-60343,-60323,-60304,-60284,-60264,-60244,
+-60225,-60205,-60185,-60165,-60145,-60125,-60105,-60085,
+-60065,-60045,-60025,-60004,-59984,-59964,-59944,-59923,
+-59903,-59883,-59862,-59842,-59821,-59801,-59780,-59759,
+-59739,-59718,-59697,-59677,-59656,-59635,-59614,-59593,
+-59572,-59551,-59530,-59509,-59488,-59467,-59446,-59425,
+-59404,-59382,-59361,-59340,-59318,-59297,-59276,-59254,
+-59233,-59211,-59189,-59168,-59146,-59125,-59103,-59081,
+-59059,-59038,-59016,-58994,-58972,-58950,-58928,-58906,
+-58884,-58862,-58840,-58818,-58795,-58773,-58751,-58729,
+-58706,-58684,-58662,-58639,-58617,-58594,-58572,-58549,
+-58527,-58504,-58481,-58459,-58436,-58413,-58390,-58367,
+-58345,-58322,-58299,-58276,-58253,-58230,-58207,-58183,
+-58160,-58137,-58114,-58091,-58067,-58044,-58021,-57997,
+-57974,-57950,-57927,-57903,-57880,-57856,-57833,-57809,
+-57785,-57762,-57738,-57714,-57690,-57666,-57642,-57618,
+-57594,-57570,-57546,-57522,-57498,-57474,-57450,-57426,
+-57402,-57377,-57353,-57329,-57304,-57280,-57255,-57231,
+-57206,-57182,-57157,-57133,-57108,-57083,-57059,-57034,
+-57009,-56984,-56959,-56935,-56910,-56885,-56860,-56835,
+-56810,-56785,-56760,-56734,-56709,-56684,-56659,-56633,
+-56608,-56583,-56557,-56532,-56507,-56481,-56456,-56430,
+-56404,-56379,-56353,-56328,-56302,-56276,-56250,-56225,
+-56199,-56173,-56147,-56121,-56095,-56069,-56043,-56017,
+-55991,-55965,-55938,-55912,-55886,-55860,-55833,-55807,
+-55781,-55754,-55728,-55701,-55675,-55648,-55622,-55595,
+-55569,-55542,-55515,-55489,-55462,-55435,-55408,-55381,
+-55354,-55327,-55300,-55274,-55246,-55219,-55192,-55165,
+-55138,-55111,-55084,-55056,-55029,-55002,-54974,-54947,
+-54920,-54892,-54865,-54837,-54810,-54782,-54755,-54727,
+-54699,-54672,-54644,-54616,-54588,-54560,-54533,-54505,
+-54477,-54449,-54421,-54393,-54365,-54337,-54308,-54280,
+-54252,-54224,-54196,-54167,-54139,-54111,-54082,-54054,
+-54026,-53997,-53969,-53940,-53911,-53883,-53854,-53826,
+-53797,-53768,-53739,-53711,-53682,-53653,-53624,-53595,
+-53566,-53537,-53508,-53479,-53450,-53421,-53392,-53363,
+-53334,-53304,-53275,-53246,-53216,-53187,-53158,-53128,
+-53099,-53069,-53040,-53010,-52981,-52951,-52922,-52892,
+-52862,-52832,-52803,-52773,-52743,-52713,-52683,-52653,
+-52624,-52594,-52564,-52534,-52503,-52473,-52443,-52413,
+-52383,-52353,-52322,-52292,-52262,-52231,-52201,-52171,
+-52140,-52110,-52079,-52049,-52018,-51988,-51957,-51926,
+-51896,-51865,-51834,-51803,-51773,-51742,-51711,-51680,
+-51649,-51618,-51587,-51556,-51525,-51494,-51463,-51432,
+-51401,-51369,-51338,-51307,-51276,-51244,-51213,-51182,
+-51150,-51119,-51087,-51056,-51024,-50993,-50961,-50929,
+-50898,-50866,-50834,-50803,-50771,-50739,-50707,-50675,
+-50644,-50612,-50580,-50548,-50516,-50484,-50452,-50420,
+-50387,-50355,-50323,-50291,-50259,-50226,-50194,-50162,
+-50129,-50097,-50065,-50032,-50000,-49967,-49935,-49902,
+-49869,-49837,-49804,-49771,-49739,-49706,-49673,-49640,
+-49608,-49575,-49542,-49509,-49476,-49443,-49410,-49377,
+-49344,-49311,-49278,-49244,-49211,-49178,-49145,-49112,
+-49078,-49045,-49012,-48978,-48945,-48911,-48878,-48844,
+-48811,-48777,-48744,-48710,-48676,-48643,-48609,-48575,
+-48542,-48508,-48474,-48440,-48406,-48372,-48338,-48305,
+-48271,-48237,-48202,-48168,-48134,-48100,-48066,-48032,
+-47998,-47963,-47929,-47895,-47860,-47826,-47792,-47757,
+-47723,-47688,-47654,-47619,-47585,-47550,-47516,-47481,
+-47446,-47412,-47377,-47342,-47307,-47273,-47238,-47203,
+-47168,-47133,-47098,-47063,-47028,-46993,-46958,-46923,
+-46888,-46853,-46818,-46783,-46747,-46712,-46677,-46642,
+-46606,-46571,-46536,-46500,-46465,-46429,-46394,-46358,
+-46323,-46287,-46251,-46216,-46180,-46145,-46109,-46073,
+-46037,-46002,-45966,-45930,-45894,-45858,-45822,-45786,
+-45750,-45714,-45678,-45642,-45606,-45570,-45534,-45498,
+-45462,-45425,-45389,-45353,-45316,-45280,-45244,-45207,
+-45171,-45135,-45098,-45062,-45025,-44989,-44952,-44915,
+-44879,-44842,-44806,-44769,-44732,-44695,-44659,-44622,
+-44585,-44548,-44511,-44474,-44437,-44400,-44363,-44326,
+-44289,-44252,-44215,-44178,-44141,-44104,-44067,-44029,
+-43992,-43955,-43918,-43880,-43843,-43806,-43768,-43731,
+-43693,-43656,-43618,-43581,-43543,-43506,-43468,-43430,
+-43393,-43355,-43317,-43280,-43242,-43204,-43166,-43128,
+-43091,-43053,-43015,-42977,-42939,-42901,-42863,-42825,
+-42787,-42749,-42711,-42672,-42634,-42596,-42558,-42520,
+-42481,-42443,-42405,-42366,-42328,-42290,-42251,-42213,
+-42174,-42136,-42097,-42059,-42020,-41982,-41943,-41904,
+-41866,-41827,-41788,-41750,-41711,-41672,-41633,-41595,
+-41556,-41517,-41478,-41439,-41400,-41361,-41322,-41283,
+-41244,-41205,-41166,-41127,-41087,-41048,-41009,-40970,
+-40931,-40891,-40852,-40813,-40773,-40734,-40695,-40655,
+-40616,-40576,-40537,-40497,-40458,-40418,-40379,-40339,
+-40299,-40260,-40220,-40180,-40141,-40101,-40061,-40021,
+-39982,-39942,-39902,-39862,-39822,-39782,-39742,-39702,
+-39662,-39622,-39582,-39542,-39502,-39462,-39422,-39382,
+-39341,-39301,-39261,-39221,-39180,-39140,-39100,-39059,
+-39019,-38979,-38938,-38898,-38857,-38817,-38776,-38736,
+-38695,-38655,-38614,-38573,-38533,-38492,-38451,-38411,
+-38370,-38329,-38288,-38248,-38207,-38166,-38125,-38084,
+-38043,-38002,-37961,-37920,-37879,-37838,-37797,-37756,
+-37715,-37674,-37633,-37592,-37550,-37509,-37468,-37427,
+-37386,-37344,-37303,-37262,-37220,-37179,-37137,-37096,
+-37055,-37013,-36972,-36930,-36889,-36847,-36805,-36764,
+-36722,-36681,-36639,-36597,-36556,-36514,-36472,-36430,
+-36388,-36347,-36305,-36263,-36221,-36179,-36137,-36095,
+-36053,-36011,-35969,-35927,-35885,-35843,-35801,-35759,
+-35717,-35675,-35633,-35590,-35548,-35506,-35464,-35421,
+-35379,-35337,-35294,-35252,-35210,-35167,-35125,-35082,
+-35040,-34997,-34955,-34912,-34870,-34827,-34785,-34742,
+-34699,-34657,-34614,-34571,-34529,-34486,-34443,-34400,
+-34358,-34315,-34272,-34229,-34186,-34143,-34100,-34057,
+-34015,-33972,-33929,-33886,-33843,-33799,-33756,-33713,
+-33670,-33627,-33584,-33541,-33498,-33454,-33411,-33368,
+-33325,-33281,-33238,-33195,-33151,-33108,-33065,-33021,
+-32978,-32934,-32891,-32847,-32804,-32760,-32717,-32673,
+-32630,-32586,-32542,-32499,-32455,-32411,-32368,-32324,
+-32280,-32236,-32193,-32149,-32105,-32061,-32017,-31974,
+-31930,-31886,-31842,-31798,-31754,-31710,-31666,-31622,
+-31578,-31534,-31490,-31446,-31402,-31357,-31313,-31269,
+-31225,-31181,-31136,-31092,-31048,-31004,-30959,-30915,
+-30871,-30826,-30782,-30738,-30693,-30649,-30604,-30560,
+-30515,-30471,-30426,-30382,-30337,-30293,-30248,-30204,
+-30159,-30114,-30070,-30025,-29980,-29936,-29891,-29846,
+-29801,-29757,-29712,-29667,-29622,-29577,-29533,-29488,
+-29443,-29398,-29353,-29308,-29263,-29218,-29173,-29128,
+-29083,-29038,-28993,-28948,-28903,-28858,-28812,-28767,
+-28722,-28677,-28632,-28586,-28541,-28496,-28451,-28405,
+-28360,-28315,-28269,-28224,-28179,-28133,-28088,-28042,
+-27997,-27952,-27906,-27861,-27815,-27770,-27724,-27678,
+-27633,-27587,-27542,-27496,-27450,-27405,-27359,-27313,
+-27268,-27222,-27176,-27131,-27085,-27039,-26993,-26947,
+-26902,-26856,-26810,-26764,-26718,-26672,-26626,-26580,
+-26534,-26488,-26442,-26396,-26350,-26304,-26258,-26212,
+-26166,-26120,-26074,-26028,-25982,-25936,-25889,-25843,
+-25797,-25751,-25705,-25658,-25612,-25566,-25520,-25473,
+-25427,-25381,-25334,-25288,-25241,-25195,-25149,-25102,
+-25056,-25009,-24963,-24916,-24870,-24823,-24777,-24730,
+-24684,-24637,-24591,-24544,-24497,-24451,-24404,-24357,
+-24311,-24264,-24217,-24171,-24124,-24077,-24030,-23984,
+-23937,-23890,-23843,-23796,-23750,-23703,-23656,-23609,
+-23562,-23515,-23468,-23421,-23374,-23327,-23280,-23233,
+-23186,-23139,-23092,-23045,-22998,-22951,-22904,-22857,
+-22810,-22763,-22716,-22668,-22621,-22574,-22527,-22480,
+-22432,-22385,-22338,-22291,-22243,-22196,-22149,-22102,
+-22054,-22007,-21960,-21912,-21865,-21817,-21770,-21723,
+-21675,-21628,-21580,-21533,-21485,-21438,-21390,-21343,
+-21295,-21248,-21200,-21153,-21105,-21057,-21010,-20962,
+-20915,-20867,-20819,-20772,-20724,-20676,-20629,-20581,
+-20533,-20485,-20438,-20390,-20342,-20294,-20246,-20199,
+-20151,-20103,-20055,-20007,-19959,-19912,-19864,-19816,
+-19768,-19720,-19672,-19624,-19576,-19528,-19480,-19432,
+-19384,-19336,-19288,-19240,-19192,-19144,-19096,-19048,
+-19000,-18951,-18903,-18855,-18807,-18759,-18711,-18663,
+-18614,-18566,-18518,-18470,-18421,-18373,-18325,-18277,
+-18228,-18180,-18132,-18084,-18035,-17987,-17939,-17890,
+-17842,-17793,-17745,-17697,-17648,-17600,-17551,-17503,
+-17455,-17406,-17358,-17309,-17261,-17212,-17164,-17115,
+-17067,-17018,-16970,-16921,-16872,-16824,-16775,-16727,
+-16678,-16629,-16581,-16532,-16484,-16435,-16386,-16338,
+-16289,-16240,-16191,-16143,-16094,-16045,-15997,-15948,
+-15899,-15850,-15802,-15753,-15704,-15655,-15606,-15557,
+-15509,-15460,-15411,-15362,-15313,-15264,-15215,-15167,
+-15118,-15069,-15020,-14971,-14922,-14873,-14824,-14775,
+-14726,-14677,-14628,-14579,-14530,-14481,-14432,-14383,
+-14334,-14285,-14236,-14187,-14138,-14089,-14040,-13990,
+-13941,-13892,-13843,-13794,-13745,-13696,-13647,-13597,
+-13548,-13499,-13450,-13401,-13351,-13302,-13253,-13204,
+-13154,-13105,-13056,-13007,-12957,-12908,-12859,-12810,
+-12760,-12711,-12662,-12612,-12563,-12514,-12464,-12415,
+-12366,-12316,-12267,-12217,-12168,-12119,-12069,-12020,
+-11970,-11921,-11872,-11822,-11773,-11723,-11674,-11624,
+-11575,-11525,-11476,-11426,-11377,-11327,-11278,-11228,
+-11179,-11129,-11080,-11030,-10981,-10931,-10882,-10832,
+-10782,-10733,-10683,-10634,-10584,-10534,-10485,-10435,
+-10386,-10336,-10286,-10237,-10187,-10137,-10088,-10038,
+-9988,-9939,-9889,-9839,-9790,-9740,-9690,-9640,
+-9591,-9541,-9491,-9442,-9392,-9342,-9292,-9243,
+-9193,-9143,-9093,-9043,-8994,-8944,-8894,-8844,
+-8794,-8745,-8695,-8645,-8595,-8545,-8496,-8446,
+-8396,-8346,-8296,-8246,-8196,-8147,-8097,-8047,
+-7997,-7947,-7897,-7847,-7797,-7747,-7697,-7648,
+-7598,-7548,-7498,-7448,-7398,-7348,-7298,-7248,
+-7198,-7148,-7098,-7048,-6998,-6948,-6898,-6848,
+-6798,-6748,-6698,-6648,-6598,-6548,-6498,-6448,
+-6398,-6348,-6298,-6248,-6198,-6148,-6098,-6048,
+-5998,-5948,-5898,-5848,-5798,-5747,-5697,-5647,
+-5597,-5547,-5497,-5447,-5397,-5347,-5297,-5247,
+-5197,-5146,-5096,-5046,-4996,-4946,-4896,-4846,
+-4796,-4745,-4695,-4645,-4595,-4545,-4495,-4445,
+-4394,-4344,-4294,-4244,-4194,-4144,-4093,-4043,
+-3993,-3943,-3893,-3843,-3792,-3742,-3692,-3642,
+-3592,-3541,-3491,-3441,-3391,-3341,-3291,-3240,
+-3190,-3140,-3090,-3039,-2989,-2939,-2889,-2839,
+-2788,-2738,-2688,-2638,-2588,-2537,-2487,-2437,
+-2387,-2336,-2286,-2236,-2186,-2135,-2085,-2035,
+-1985,-1934,-1884,-1834,-1784,-1733,-1683,-1633,
+-1583,-1532,-1482,-1432,-1382,-1331,-1281,-1231,
+-1181,-1130,-1080,-1030,-980,-929,-879,-829,
+-779,-728,-678,-628,-578,-527,-477,-427,
+-376,-326,-276,-226,-175,-125,-75,-25,
+25,75,125,175,226,276,326,376,
+427,477,527,578,628,678,728,779,
+829,879,929,980,1030,1080,1130,1181,
+1231,1281,1331,1382,1432,1482,1532,1583,
+1633,1683,1733,1784,1834,1884,1934,1985,
+2035,2085,2135,2186,2236,2286,2336,2387,
+2437,2487,2537,2587,2638,2688,2738,2788,
+2839,2889,2939,2989,3039,3090,3140,3190,
+3240,3291,3341,3391,3441,3491,3542,3592,
+3642,3692,3742,3792,3843,3893,3943,3993,
+4043,4093,4144,4194,4244,4294,4344,4394,
+4445,4495,4545,4595,4645,4695,4745,4796,
+4846,4896,4946,4996,5046,5096,5146,5197,
+5247,5297,5347,5397,5447,5497,5547,5597,
+5647,5697,5747,5798,5848,5898,5948,5998,
+6048,6098,6148,6198,6248,6298,6348,6398,
+6448,6498,6548,6598,6648,6698,6748,6798,
+6848,6898,6948,6998,7048,7098,7148,7198,
+7248,7298,7348,7398,7448,7498,7548,7598,
+7648,7697,7747,7797,7847,7897,7947,7997,
+8047,8097,8147,8196,8246,8296,8346,8396,
+8446,8496,8545,8595,8645,8695,8745,8794,
+8844,8894,8944,8994,9043,9093,9143,9193,
+9243,9292,9342,9392,9442,9491,9541,9591,
+9640,9690,9740,9790,9839,9889,9939,9988,
+10038,10088,10137,10187,10237,10286,10336,10386,
+10435,10485,10534,10584,10634,10683,10733,10782,
+10832,10882,10931,10981,11030,11080,11129,11179,
+11228,11278,11327,11377,11426,11476,11525,11575,
+11624,11674,11723,11773,11822,11872,11921,11970,
+12020,12069,12119,12168,12218,12267,12316,12366,
+12415,12464,12514,12563,12612,12662,12711,12760,
+12810,12859,12908,12957,13007,13056,13105,13154,
+13204,13253,13302,13351,13401,13450,13499,13548,
+13597,13647,13696,13745,13794,13843,13892,13941,
+13990,14040,14089,14138,14187,14236,14285,14334,
+14383,14432,14481,14530,14579,14628,14677,14726,
+14775,14824,14873,14922,14971,15020,15069,15118,
+15167,15215,15264,15313,15362,15411,15460,15509,
+15557,15606,15655,15704,15753,15802,15850,15899,
+15948,15997,16045,16094,16143,16191,16240,16289,
+16338,16386,16435,16484,16532,16581,16629,16678,
+16727,16775,16824,16872,16921,16970,17018,17067,
+17115,17164,17212,17261,17309,17358,17406,17455,
+17503,17551,17600,17648,17697,17745,17793,17842,
+17890,17939,17987,18035,18084,18132,18180,18228,
+18277,18325,18373,18421,18470,18518,18566,18614,
+18663,18711,18759,18807,18855,18903,18951,19000,
+19048,19096,19144,19192,19240,19288,19336,19384,
+19432,19480,19528,19576,19624,19672,19720,19768,
+19816,19864,19912,19959,20007,20055,20103,20151,
+20199,20246,20294,20342,20390,20438,20485,20533,
+20581,20629,20676,20724,20772,20819,20867,20915,
+20962,21010,21057,21105,21153,21200,21248,21295,
+21343,21390,21438,21485,21533,21580,21628,21675,
+21723,21770,21817,21865,21912,21960,22007,22054,
+22102,22149,22196,22243,22291,22338,22385,22432,
+22480,22527,22574,22621,22668,22716,22763,22810,
+22857,22904,22951,22998,23045,23092,23139,23186,
+23233,23280,23327,23374,23421,23468,23515,23562,
+23609,23656,23703,23750,23796,23843,23890,23937,
+23984,24030,24077,24124,24171,24217,24264,24311,
+24357,24404,24451,24497,24544,24591,24637,24684,
+24730,24777,24823,24870,24916,24963,25009,25056,
+25102,25149,25195,25241,25288,25334,25381,25427,
+25473,25520,25566,25612,25658,25705,25751,25797,
+25843,25889,25936,25982,26028,26074,26120,26166,
+26212,26258,26304,26350,26396,26442,26488,26534,
+26580,26626,26672,26718,26764,26810,26856,26902,
+26947,26993,27039,27085,27131,27176,27222,27268,
+27313,27359,27405,27450,27496,27542,27587,27633,
+27678,27724,27770,27815,27861,27906,27952,27997,
+28042,28088,28133,28179,28224,28269,28315,28360,
+28405,28451,28496,28541,28586,28632,28677,28722,
+28767,28812,28858,28903,28948,28993,29038,29083,
+29128,29173,29218,29263,29308,29353,29398,29443,
+29488,29533,29577,29622,29667,29712,29757,29801,
+29846,29891,29936,29980,30025,30070,30114,30159,
+30204,30248,30293,30337,30382,30427,30471,30516,
+30560,30604,30649,30693,30738,30782,30826,30871,
+30915,30959,31004,31048,31092,31136,31181,31225,
+31269,31313,31357,31402,31446,31490,31534,31578,
+31622,31666,31710,31754,31798,31842,31886,31930,
+31974,32017,32061,32105,32149,32193,32236,32280,
+32324,32368,32411,32455,32499,32542,32586,32630,
+32673,32717,32760,32804,32847,32891,32934,32978,
+33021,33065,33108,33151,33195,33238,33281,33325,
+33368,33411,33454,33498,33541,33584,33627,33670,
+33713,33756,33799,33843,33886,33929,33972,34015,
+34057,34100,34143,34186,34229,34272,34315,34358,
+34400,34443,34486,34529,34571,34614,34657,34699,
+34742,34785,34827,34870,34912,34955,34997,35040,
+35082,35125,35167,35210,35252,35294,35337,35379,
+35421,35464,35506,35548,35590,35633,35675,35717,
+35759,35801,35843,35885,35927,35969,36011,36053,
+36095,36137,36179,36221,36263,36305,36347,36388,
+36430,36472,36514,36556,36597,36639,36681,36722,
+36764,36805,36847,36889,36930,36972,37013,37055,
+37096,37137,37179,37220,37262,37303,37344,37386,
+37427,37468,37509,37551,37592,37633,37674,37715,
+37756,37797,37838,37879,37920,37961,38002,38043,
+38084,38125,38166,38207,38248,38288,38329,38370,
+38411,38451,38492,38533,38573,38614,38655,38695,
+38736,38776,38817,38857,38898,38938,38979,39019,
+39059,39100,39140,39180,39221,39261,39301,39341,
+39382,39422,39462,39502,39542,39582,39622,39662,
+39702,39742,39782,39822,39862,39902,39942,39982,
+40021,40061,40101,40141,40180,40220,40260,40299,
+40339,40379,40418,40458,40497,40537,40576,40616,
+40655,40695,40734,40773,40813,40852,40891,40931,
+40970,41009,41048,41087,41127,41166,41205,41244,
+41283,41322,41361,41400,41439,41478,41517,41556,
+41595,41633,41672,41711,41750,41788,41827,41866,
+41904,41943,41982,42020,42059,42097,42136,42174,
+42213,42251,42290,42328,42366,42405,42443,42481,
+42520,42558,42596,42634,42672,42711,42749,42787,
+42825,42863,42901,42939,42977,43015,43053,43091,
+43128,43166,43204,43242,43280,43317,43355,43393,
+43430,43468,43506,43543,43581,43618,43656,43693,
+43731,43768,43806,43843,43880,43918,43955,43992,
+44029,44067,44104,44141,44178,44215,44252,44289,
+44326,44363,44400,44437,44474,44511,44548,44585,
+44622,44659,44695,44732,44769,44806,44842,44879,
+44915,44952,44989,45025,45062,45098,45135,45171,
+45207,45244,45280,45316,45353,45389,45425,45462,
+45498,45534,45570,45606,45642,45678,45714,45750,
+45786,45822,45858,45894,45930,45966,46002,46037,
+46073,46109,46145,46180,46216,46252,46287,46323,
+46358,46394,46429,46465,46500,46536,46571,46606,
+46642,46677,46712,46747,46783,46818,46853,46888,
+46923,46958,46993,47028,47063,47098,47133,47168,
+47203,47238,47273,47308,47342,47377,47412,47446,
+47481,47516,47550,47585,47619,47654,47688,47723,
+47757,47792,47826,47861,47895,47929,47963,47998,
+48032,48066,48100,48134,48168,48202,48237,48271,
+48305,48338,48372,48406,48440,48474,48508,48542,
+48575,48609,48643,48676,48710,48744,48777,48811,
+48844,48878,48911,48945,48978,49012,49045,49078,
+49112,49145,49178,49211,49244,49278,49311,49344,
+49377,49410,49443,49476,49509,49542,49575,49608,
+49640,49673,49706,49739,49771,49804,49837,49869,
+49902,49935,49967,50000,50032,50064,50097,50129,
+50162,50194,50226,50259,50291,50323,50355,50387,
+50420,50452,50484,50516,50548,50580,50612,50644,
+50675,50707,50739,50771,50803,50834,50866,50898,
+50929,50961,50993,51024,51056,51087,51119,51150,
+51182,51213,51244,51276,51307,51338,51369,51401,
+51432,51463,51494,51525,51556,51587,51618,51649,
+51680,51711,51742,51773,51803,51834,51865,51896,
+51926,51957,51988,52018,52049,52079,52110,52140,
+52171,52201,52231,52262,52292,52322,52353,52383,
+52413,52443,52473,52503,52534,52564,52594,52624,
+52653,52683,52713,52743,52773,52803,52832,52862,
+52892,52922,52951,52981,53010,53040,53069,53099,
+53128,53158,53187,53216,53246,53275,53304,53334,
+53363,53392,53421,53450,53479,53508,53537,53566,
+53595,53624,53653,53682,53711,53739,53768,53797,
+53826,53854,53883,53912,53940,53969,53997,54026,
+54054,54082,54111,54139,54167,54196,54224,54252,
+54280,54309,54337,54365,54393,54421,54449,54477,
+54505,54533,54560,54588,54616,54644,54672,54699,
+54727,54755,54782,54810,54837,54865,54892,54920,
+54947,54974,55002,55029,55056,55084,55111,55138,
+55165,55192,55219,55246,55274,55300,55327,55354,
+55381,55408,55435,55462,55489,55515,55542,55569,
+55595,55622,55648,55675,55701,55728,55754,55781,
+55807,55833,55860,55886,55912,55938,55965,55991,
+56017,56043,56069,56095,56121,56147,56173,56199,
+56225,56250,56276,56302,56328,56353,56379,56404,
+56430,56456,56481,56507,56532,56557,56583,56608,
+56633,56659,56684,56709,56734,56760,56785,56810,
+56835,56860,56885,56910,56935,56959,56984,57009,
+57034,57059,57083,57108,57133,57157,57182,57206,
+57231,57255,57280,57304,57329,57353,57377,57402,
+57426,57450,57474,57498,57522,57546,57570,57594,
+57618,57642,57666,57690,57714,57738,57762,57785,
+57809,57833,57856,57880,57903,57927,57950,57974,
+57997,58021,58044,58067,58091,58114,58137,58160,
+58183,58207,58230,58253,58276,58299,58322,58345,
+58367,58390,58413,58436,58459,58481,58504,58527,
+58549,58572,58594,58617,58639,58662,58684,58706,
+58729,58751,58773,58795,58818,58840,58862,58884,
+58906,58928,58950,58972,58994,59016,59038,59059,
+59081,59103,59125,59146,59168,59190,59211,59233,
+59254,59276,59297,59318,59340,59361,59382,59404,
+59425,59446,59467,59488,59509,59530,59551,59572,
+59593,59614,59635,59656,59677,59697,59718,59739,
+59759,59780,59801,59821,59842,59862,59883,59903,
+59923,59944,59964,59984,60004,60025,60045,60065,
+60085,60105,60125,60145,60165,60185,60205,60225,
+60244,60264,60284,60304,60323,60343,60363,60382,
+60402,60421,60441,60460,60479,60499,60518,60537,
+60556,60576,60595,60614,60633,60652,60671,60690,
+60709,60728,60747,60766,60785,60803,60822,60841,
+60859,60878,60897,60915,60934,60952,60971,60989,
+61007,61026,61044,61062,61081,61099,61117,61135,
+61153,61171,61189,61207,61225,61243,61261,61279,
+61297,61314,61332,61350,61367,61385,61403,61420,
+61438,61455,61473,61490,61507,61525,61542,61559,
+61577,61594,61611,61628,61645,61662,61679,61696,
+61713,61730,61747,61764,61780,61797,61814,61831,
+61847,61864,61880,61897,61913,61930,61946,61963,
+61979,61995,62012,62028,62044,62060,62076,62092,
+62108,62125,62141,62156,62172,62188,62204,62220,
+62236,62251,62267,62283,62298,62314,62329,62345,
+62360,62376,62391,62407,62422,62437,62453,62468,
+62483,62498,62513,62528,62543,62558,62573,62588,
+62603,62618,62633,62648,62662,62677,62692,62706,
+62721,62735,62750,62764,62779,62793,62808,62822,
+62836,62850,62865,62879,62893,62907,62921,62935,
+62949,62963,62977,62991,63005,63019,63032,63046,
+63060,63074,63087,63101,63114,63128,63141,63155,
+63168,63182,63195,63208,63221,63235,63248,63261,
+63274,63287,63300,63313,63326,63339,63352,63365,
+63378,63390,63403,63416,63429,63441,63454,63466,
+63479,63491,63504,63516,63528,63541,63553,63565,
+63578,63590,63602,63614,63626,63638,63650,63662,
+63674,63686,63698,63709,63721,63733,63745,63756,
+63768,63779,63791,63803,63814,63825,63837,63848,
+63859,63871,63882,63893,63904,63915,63927,63938,
+63949,63960,63971,63981,63992,64003,64014,64025,
+64035,64046,64057,64067,64078,64088,64099,64109,
+64120,64130,64140,64151,64161,64171,64181,64192,
+64202,64212,64222,64232,64242,64252,64261,64271,
+64281,64291,64301,64310,64320,64330,64339,64349,
+64358,64368,64377,64387,64396,64405,64414,64424,
+64433,64442,64451,64460,64469,64478,64487,64496,
+64505,64514,64523,64532,64540,64549,64558,64566,
+64575,64584,64592,64600,64609,64617,64626,64634,
+64642,64651,64659,64667,64675,64683,64691,64699,
+64707,64715,64723,64731,64739,64747,64754,64762,
+64770,64777,64785,64793,64800,64808,64815,64822,
+64830,64837,64844,64852,64859,64866,64873,64880,
+64887,64895,64902,64908,64915,64922,64929,64936,
+64943,64949,64956,64963,64969,64976,64982,64989,
+64995,65002,65008,65015,65021,65027,65033,65040,
+65046,65052,65058,65064,65070,65076,65082,65088,
+65094,65099,65105,65111,65117,65122,65128,65133,
+65139,65144,65150,65155,65161,65166,65171,65177,
+65182,65187,65192,65197,65202,65207,65212,65217,
+65222,65227,65232,65237,65242,65246,65251,65256,
+65260,65265,65270,65274,65279,65283,65287,65292,
+65296,65300,65305,65309,65313,65317,65321,65325,
+65329,65333,65337,65341,65345,65349,65352,65356,
+65360,65363,65367,65371,65374,65378,65381,65385,
+65388,65391,65395,65398,65401,65404,65408,65411,
+65414,65417,65420,65423,65426,65429,65431,65434,
+65437,65440,65442,65445,65448,65450,65453,65455,
+65458,65460,65463,65465,65467,65470,65472,65474,
+65476,65478,65480,65482,65484,65486,65488,65490,
+65492,65494,65496,65497,65499,65501,65502,65504,
+65505,65507,65508,65510,65511,65513,65514,65515,
+65516,65518,65519,65520,65521,65522,65523,65524,
+65525,65526,65527,65527,65528,65529,65530,65530,
+65531,65531,65532,65532,65533,65533,65534,65534,
+65534,65535,65535,65535,65535,65535,65535,65535
+};
+
+int tantoangle[2049] =
+{
+0,333772,667544,1001315,1335086,1668857,2002626,2336395,
+2670163,3003929,3337694,3671457,4005219,4338979,4672736,5006492,
+5340245,5673995,6007743,6341488,6675230,7008968,7342704,7676435,
+8010164,8343888,8677609,9011325,9345037,9678744,10012447,10346145,
+10679838,11013526,11347209,11680887,12014558,12348225,12681885,13015539,
+13349187,13682829,14016464,14350092,14683714,15017328,15350936,15684536,
+16018129,16351714,16685291,17018860,17352422,17685974,18019518,18353054,
+18686582,19020100,19353610,19687110,20020600,20354080,20687552,21021014,
+21354466,21687906,22021338,22354758,22688168,23021568,23354956,23688332,
+24021698,24355052,24688396,25021726,25355046,25688352,26021648,26354930,
+26688200,27021456,27354702,27687932,28021150,28354356,28687548,29020724,
+29353888,29687038,30020174,30353296,30686404,31019496,31352574,31685636,
+32018684,32351718,32684734,33017736,33350722,33683692,34016648,34349584,
+34682508,35015412,35348300,35681172,36014028,36346868,36679688,37012492,
+37345276,37678044,38010792,38343524,38676240,39008936,39341612,39674272,
+40006912,40339532,40672132,41004716,41337276,41669820,42002344,42334848,
+42667332,42999796,43332236,43664660,43997060,44329444,44661800,44994140,
+45326456,45658752,45991028,46323280,46655512,46987720,47319908,47652072,
+47984212,48316332,48648428,48980500,49312548,49644576,49976580,50308556,
+50640512,50972444,51304352,51636236,51968096,52299928,52631740,52963524,
+53295284,53627020,53958728,54290412,54622068,54953704,55285308,55616888,
+55948444,56279972,56611472,56942948,57274396,57605816,57937212,58268576,
+58599916,58931228,59262512,59593768,59924992,60256192,60587364,60918508,
+61249620,61580704,61911760,62242788,62573788,62904756,63235692,63566604,
+63897480,64228332,64559148,64889940,65220696,65551424,65882120,66212788,
+66543420,66874024,67204600,67535136,67865648,68196120,68526568,68856984,
+69187360,69517712,69848024,70178304,70508560,70838776,71168960,71499112,
+71829224,72159312,72489360,72819376,73149360,73479304,73809216,74139096,
+74468936,74798744,75128520,75458264,75787968,76117632,76447264,76776864,
+77106424,77435952,77765440,78094888,78424304,78753688,79083032,79412336,
+79741608,80070840,80400032,80729192,81058312,81387392,81716432,82045440,
+82374408,82703336,83032224,83361080,83689896,84018664,84347400,84676096,
+85004760,85333376,85661952,85990488,86318984,86647448,86975864,87304240,
+87632576,87960872,88289128,88617344,88945520,89273648,89601736,89929792,
+90257792,90585760,90913688,91241568,91569408,91897200,92224960,92552672,
+92880336,93207968,93535552,93863088,94190584,94518040,94845448,95172816,
+95500136,95827416,96154648,96481832,96808976,97136080,97463136,97790144,
+98117112,98444032,98770904,99097736,99424520,99751256,100077944,100404592,
+100731192,101057744,101384248,101710712,102037128,102363488,102689808,103016080,
+103342312,103668488,103994616,104320696,104646736,104972720,105298656,105624552,
+105950392,106276184,106601928,106927624,107253272,107578872,107904416,108229920,
+108555368,108880768,109206120,109531416,109856664,110181872,110507016,110832120,
+111157168,111482168,111807112,112132008,112456856,112781648,113106392,113431080,
+113755720,114080312,114404848,114729328,115053760,115378136,115702464,116026744,
+116350960,116675128,116999248,117323312,117647320,117971272,118295176,118619024,
+118942816,119266560,119590248,119913880,120237456,120560984,120884456,121207864,
+121531224,121854528,122177784,122500976,122824112,123147200,123470224,123793200,
+124116120,124438976,124761784,125084528,125407224,125729856,126052432,126374960,
+126697424,127019832,127342184,127664472,127986712,128308888,128631008,128953072,
+129275080,129597024,129918912,130240744,130562520,130884232,131205888,131527480,
+131849016,132170496,132491912,132813272,133134576,133455816,133776992,134098120,
+134419184,134740176,135061120,135382000,135702816,136023584,136344272,136664912,
+136985488,137306016,137626464,137946864,138267184,138587456,138907664,139227808,
+139547904,139867920,140187888,140507776,140827616,141147392,141467104,141786752,
+142106336,142425856,142745312,143064720,143384048,143703312,144022512,144341664,
+144660736,144979744,145298704,145617584,145936400,146255168,146573856,146892480,
+147211040,147529536,147847968,148166336,148484640,148802880,149121056,149439152,
+149757200,150075168,150393072,150710912,151028688,151346400,151664048,151981616,
+152299136,152616576,152933952,153251264,153568496,153885680,154202784,154519824,
+154836784,155153696,155470528,155787296,156104000,156420624,156737200,157053696,
+157370112,157686480,158002768,158318976,158635136,158951216,159267232,159583168,
+159899040,160214848,160530592,160846256,161161840,161477376,161792832,162108208,
+162423520,162738768,163053952,163369040,163684080,163999040,164313936,164628752,
+164943504,165258176,165572784,165887312,166201776,166516160,166830480,167144736,
+167458912,167773008,168087040,168400992,168714880,169028688,169342432,169656096,
+169969696,170283216,170596672,170910032,171223344,171536576,171849728,172162800,
+172475808,172788736,173101600,173414384,173727104,174039728,174352288,174664784,
+174977200,175289536,175601792,175913984,176226096,176538144,176850096,177161984,
+177473792,177785536,178097200,178408784,178720288,179031728,179343088,179654368,
+179965568,180276704,180587744,180898720,181209616,181520448,181831184,182141856,
+182452448,182762960,183073408,183383760,183694048,184004240,184314368,184624416,
+184934400,185244288,185554096,185863840,186173504,186483072,186792576,187102000,
+187411344,187720608,188029808,188338912,188647936,188956896,189265760,189574560,
+189883264,190191904,190500448,190808928,191117312,191425632,191733872,192042016,
+192350096,192658096,192966000,193273840,193581584,193889264,194196848,194504352,
+194811792,195119136,195426400,195733584,196040688,196347712,196654656,196961520,
+197268304,197574992,197881616,198188144,198494592,198800960,199107248,199413456,
+199719584,200025616,200331584,200637456,200943248,201248960,201554576,201860128,
+202165584,202470960,202776256,203081456,203386592,203691632,203996592,204301472,
+204606256,204910976,205215600,205520144,205824592,206128960,206433248,206737456,
+207041584,207345616,207649568,207953424,208257216,208560912,208864512,209168048,
+209471488,209774832,210078112,210381296,210684384,210987408,211290336,211593184,
+211895936,212198608,212501184,212803680,213106096,213408432,213710672,214012816,
+214314880,214616864,214918768,215220576,215522288,215823920,216125472,216426928,
+216728304,217029584,217330784,217631904,217932928,218233856,218534704,218835472,
+219136144,219436720,219737216,220037632,220337952,220638192,220938336,221238384,
+221538352,221838240,222138032,222437728,222737344,223036880,223336304,223635664,
+223934912,224234096,224533168,224832160,225131072,225429872,225728608,226027232,
+226325776,226624240,226922608,227220880,227519056,227817152,228115168,228413088,
+228710912,229008640,229306288,229603840,229901312,230198688,230495968,230793152,
+231090256,231387280,231684192,231981024,232277760,232574416,232870960,233167440,
+233463808,233760096,234056288,234352384,234648384,234944304,235240128,235535872,
+235831504,236127056,236422512,236717888,237013152,237308336,237603424,237898416,
+238193328,238488144,238782864,239077488,239372016,239666464,239960816,240255072,
+240549232,240843312,241137280,241431168,241724960,242018656,242312256,242605776,
+242899200,243192512,243485744,243778896,244071936,244364880,244657744,244950496,
+245243168,245535744,245828224,246120608,246412912,246705104,246997216,247289216,
+247581136,247872960,248164688,248456320,248747856,249039296,249330640,249621904,
+249913056,250204128,250495088,250785968,251076736,251367424,251658016,251948512,
+252238912,252529200,252819408,253109520,253399536,253689456,253979280,254269008,
+254558640,254848176,255137632,255426976,255716224,256005376,256294432,256583392,
+256872256,257161024,257449696,257738272,258026752,258315136,258603424,258891600,
+259179696,259467696,259755600,260043392,260331104,260618704,260906224,261193632,
+261480960,261768176,262055296,262342320,262629248,262916080,263202816,263489456,
+263776000,264062432,264348784,264635024,264921168,265207216,265493168,265779024,
+266064784,266350448,266636000,266921472,267206832,267492096,267777264,268062336,
+268347312,268632192,268916960,269201632,269486208,269770688,270055072,270339360,
+270623552,270907616,271191616,271475488,271759296,272042976,272326560,272610048,
+272893440,273176736,273459936,273743040,274026048,274308928,274591744,274874432,
+275157024,275439520,275721920,276004224,276286432,276568512,276850528,277132416,
+277414240,277695936,277977536,278259040,278540448,278821728,279102944,279384032,
+279665056,279945952,280226752,280507456,280788064,281068544,281348960,281629248,
+281909472,282189568,282469568,282749440,283029248,283308960,283588544,283868032,
+284147424,284426720,284705920,284985024,285264000,285542912,285821696,286100384,
+286378976,286657440,286935840,287214112,287492320,287770400,288048384,288326240,
+288604032,288881696,289159264,289436768,289714112,289991392,290268576,290545632,
+290822592,291099456,291376224,291652896,291929440,292205888,292482272,292758528,
+293034656,293310720,293586656,293862496,294138240,294413888,294689440,294964864,
+295240192,295515424,295790560,296065600,296340512,296615360,296890080,297164704,
+297439200,297713632,297987936,298262144,298536256,298810240,299084160,299357952,
+299631648,299905248,300178720,300452128,300725408,300998592,301271680,301544640,
+301817536,302090304,302362976,302635520,302908000,303180352,303452608,303724768,
+303996800,304268768,304540608,304812320,305083968,305355520,305626944,305898272,
+306169472,306440608,306711616,306982528,307253344,307524064,307794656,308065152,
+308335552,308605856,308876032,309146112,309416096,309685984,309955744,310225408,
+310494976,310764448,311033824,311303072,311572224,311841280,312110208,312379040,
+312647776,312916416,313184960,313453376,313721696,313989920,314258016,314526016,
+314793920,315061728,315329408,315597024,315864512,316131872,316399168,316666336,
+316933408,317200384,317467232,317733984,318000640,318267200,318533632,318799968,
+319066208,319332352,319598368,319864288,320130112,320395808,320661408,320926912,
+321192320,321457632,321722816,321987904,322252864,322517760,322782528,323047200,
+323311744,323576192,323840544,324104800,324368928,324632992,324896928,325160736,
+325424448,325688096,325951584,326215008,326478304,326741504,327004608,327267584,
+327530464,327793248,328055904,328318496,328580960,328843296,329105568,329367712,
+329629760,329891680,330153536,330415264,330676864,330938400,331199808,331461120,
+331722304,331983392,332244384,332505280,332766048,333026752,333287296,333547776,
+333808128,334068384,334328544,334588576,334848512,335108352,335368064,335627712,
+335887200,336146624,336405920,336665120,336924224,337183200,337442112,337700864,
+337959552,338218112,338476576,338734944,338993184,339251328,339509376,339767296,
+340025120,340282848,340540480,340797984,341055392,341312704,341569888,341826976,
+342083968,342340832,342597600,342854272,343110848,343367296,343623648,343879904,
+344136032,344392064,344648000,344903808,345159520,345415136,345670656,345926048,
+346181344,346436512,346691616,346946592,347201440,347456224,347710880,347965440,
+348219872,348474208,348728448,348982592,349236608,349490528,349744320,349998048,
+350251648,350505152,350758528,351011808,351264992,351518048,351771040,352023872,
+352276640,352529280,352781824,353034272,353286592,353538816,353790944,354042944,
+354294880,354546656,354798368,355049952,355301440,355552800,355804096,356055264,
+356306304,356557280,356808128,357058848,357309504,357560032,357810464,358060768,
+358311008,358561088,358811104,359060992,359310784,359560480,359810048,360059520,
+360308896,360558144,360807296,361056352,361305312,361554144,361802880,362051488,
+362300032,362548448,362796736,363044960,363293056,363541024,363788928,364036704,
+364284384,364531936,364779392,365026752,365274016,365521152,365768192,366015136,
+366261952,366508672,366755296,367001792,367248192,367494496,367740704,367986784,
+368232768,368478656,368724416,368970080,369215648,369461088,369706432,369951680,
+370196800,370441824,370686752,370931584,371176288,371420896,371665408,371909792,
+372154080,372398272,372642336,372886304,373130176,373373952,373617600,373861152,
+374104608,374347936,374591168,374834304,375077312,375320224,375563040,375805760,
+376048352,376290848,376533248,376775520,377017696,377259776,377501728,377743584,
+377985344,378227008,378468544,378709984,378951328,379192544,379433664,379674688,
+379915584,380156416,380397088,380637696,380878176,381118560,381358848,381599040,
+381839104,382079072,382318912,382558656,382798304,383037856,383277280,383516640,
+383755840,383994976,384233984,384472896,384711712,384950400,385188992,385427488,
+385665888,385904160,386142336,386380384,386618368,386856224,387093984,387331616,
+387569152,387806592,388043936,388281152,388518272,388755296,388992224,389229024,
+389465728,389702336,389938816,390175200,390411488,390647680,390883744,391119712,
+391355584,391591328,391826976,392062528,392297984,392533312,392768544,393003680,
+393238720,393473632,393708448,393943168,394177760,394412256,394646656,394880960,
+395115136,395349216,395583200,395817088,396050848,396284512,396518080,396751520,
+396984864,397218112,397451264,397684288,397917248,398150080,398382784,398615424,
+398847936,399080320,399312640,399544832,399776928,400008928,400240832,400472608,
+400704288,400935872,401167328,401398720,401629984,401861120,402092192,402323136,
+402553984,402784736,403015360,403245888,403476320,403706656,403936896,404167008,
+404397024,404626944,404856736,405086432,405316032,405545536,405774912,406004224,
+406233408,406462464,406691456,406920320,407149088,407377760,407606336,407834784,
+408063136,408291392,408519520,408747584,408975520,409203360,409431072,409658720,
+409886240,410113664,410340992,410568192,410795296,411022304,411249216,411476032,
+411702720,411929312,412155808,412382176,412608480,412834656,413060736,413286720,
+413512576,413738336,413964000,414189568,414415040,414640384,414865632,415090784,
+415315840,415540800,415765632,415990368,416215008,416439552,416663968,416888288,
+417112512,417336640,417560672,417784576,418008384,418232096,418455712,418679200,
+418902624,419125920,419349120,419572192,419795200,420018080,420240864,420463552,
+420686144,420908608,421130976,421353280,421575424,421797504,422019488,422241344,
+422463104,422684768,422906336,423127776,423349120,423570400,423791520,424012576,
+424233536,424454368,424675104,424895744,425116288,425336736,425557056,425777280,
+425997408,426217440,426437376,426657184,426876928,427096544,427316064,427535488,
+427754784,427974016,428193120,428412128,428631040,428849856,429068544,429287168,
+429505664,429724064,429942368,430160576,430378656,430596672,430814560,431032352,
+431250048,431467616,431685120,431902496,432119808,432336992,432554080,432771040,
+432987936,433204736,433421408,433637984,433854464,434070848,434287104,434503296,
+434719360,434935360,435151232,435367008,435582656,435798240,436013696,436229088,
+436444352,436659520,436874592,437089568,437304416,437519200,437733856,437948416,
+438162880,438377248,438591520,438805696,439019744,439233728,439447584,439661344,
+439875008,440088576,440302048,440515392,440728672,440941824,441154880,441367872,
+441580736,441793472,442006144,442218720,442431168,442643552,442855808,443067968,
+443280032,443492000,443703872,443915648,444127296,444338880,444550336,444761696,
+444972992,445184160,445395232,445606176,445817056,446027840,446238496,446449088,
+446659552,446869920,447080192,447290400,447500448,447710432,447920320,448130112,
+448339776,448549376,448758848,448968224,449177536,449386720,449595808,449804800,
+450013664,450222464,450431168,450639776,450848256,451056640,451264960,451473152,
+451681248,451889248,452097152,452304960,452512672,452720288,452927808,453135232,
+453342528,453549760,453756864,453963904,454170816,454377632,454584384,454791008,
+454997536,455203968,455410304,455616544,455822688,456028704,456234656,456440512,
+456646240,456851904,457057472,457262912,457468256,457673536,457878688,458083744,
+458288736,458493600,458698368,458903040,459107616,459312096,459516480,459720768,
+459924960,460129056,460333056,460536960,460740736,460944448,461148064,461351584,
+461554976,461758304,461961536,462164640,462367680,462570592,462773440,462976160,
+463178816,463381344,463583776,463786144,463988384,464190560,464392608,464594560,
+464796448,464998208,465199872,465401472,465602944,465804320,466005600,466206816,
+466407904,466608896,466809824,467010624,467211328,467411936,467612480,467812896,
+468013216,468213440,468413600,468613632,468813568,469013440,469213184,469412832,
+469612416,469811872,470011232,470210528,470409696,470608800,470807776,471006688,
+471205472,471404192,471602784,471801312,471999712,472198048,472396288,472594400,
+472792448,472990400,473188256,473385984,473583648,473781216,473978688,474176064,
+474373344,474570528,474767616,474964608,475161504,475358336,475555040,475751648,
+475948192,476144608,476340928,476537184,476733312,476929376,477125344,477321184,
+477516960,477712640,477908224,478103712,478299104,478494400,478689600,478884704,
+479079744,479274656,479469504,479664224,479858880,480053408,480247872,480442240,
+480636512,480830656,481024736,481218752,481412640,481606432,481800128,481993760,
+482187264,482380704,482574016,482767264,482960416,483153472,483346432,483539296,
+483732064,483924768,484117344,484309856,484502240,484694560,484886784,485078912,
+485270944,485462880,485654720,485846464,486038144,486229696,486421184,486612576,
+486803840,486995040,487186176,487377184,487568096,487758912,487949664,488140320,
+488330880,488521312,488711712,488901984,489092160,489282240,489472256,489662176,
+489851968,490041696,490231328,490420896,490610336,490799712,490988960,491178144,
+491367232,491556224,491745120,491933920,492122656,492311264,492499808,492688256,
+492876608,493064864,493253056,493441120,493629120,493817024,494004832,494192544,
+494380160,494567712,494755136,494942496,495129760,495316928,495504000,495691008,
+495877888,496064704,496251424,496438048,496624608,496811040,496997408,497183680,
+497369856,497555936,497741920,497927840,498113632,498299360,498484992,498670560,
+498856000,499041376,499226656,499411840,499596928,499781920,499966848,500151680,
+500336416,500521056,500705600,500890080,501074464,501258752,501442944,501627040,
+501811072,501995008,502178848,502362592,502546240,502729824,502913312,503096704,
+503280000,503463232,503646368,503829408,504012352,504195200,504377984,504560672,
+504743264,504925760,505108192,505290496,505472736,505654912,505836960,506018944,
+506200832,506382624,506564320,506745952,506927488,507108928,507290272,507471552,
+507652736,507833824,508014816,508195744,508376576,508557312,508737952,508918528,
+509099008,509279392,509459680,509639904,509820032,510000064,510180000,510359872,
+510539648,510719328,510898944,511078432,511257856,511437216,511616448,511795616,
+511974688,512153664,512332576,512511392,512690112,512868768,513047296,513225792,
+513404160,513582432,513760640,513938784,514116800,514294752,514472608,514650368,
+514828064,515005664,515183168,515360608,515537952,515715200,515892352,516069440,
+516246432,516423328,516600160,516776896,516953536,517130112,517306592,517482976,
+517659264,517835488,518011616,518187680,518363648,518539520,518715296,518891008,
+519066624,519242144,519417600,519592960,519768256,519943424,520118528,520293568,
+520468480,520643328,520818112,520992800,521167392,521341888,521516320,521690656,
+521864896,522039072,522213152,522387168,522561056,522734912,522908640,523082304,
+523255872,523429376,523602784,523776096,523949312,524122464,524295552,524468512,
+524641440,524814240,524986976,525159616,525332192,525504640,525677056,525849344,
+526021568,526193728,526365792,526537760,526709632,526881440,527053152,527224800,
+527396352,527567840,527739200,527910528,528081728,528252864,528423936,528594880,
+528765760,528936576,529107296,529277920,529448480,529618944,529789344,529959648,
+530129856,530300000,530470048,530640000,530809888,530979712,531149440,531319072,
+531488608,531658080,531827488,531996800,532166016,532335168,532504224,532673184,
+532842080,533010912,533179616,533348288,533516832,533685312,533853728,534022048,
+534190272,534358432,534526496,534694496,534862400,535030240,535197984,535365632,
+535533216,535700704,535868128,536035456,536202720,536369888,536536992,536704000,
+536870912
+};
+
--- /dev/null
+++ b/template.c
@@ -1,0 +1,33 @@
+
+//**************************************************************************
+//**
+//** TEMPLATE.C
+//**
+//**************************************************************************
+
+// HEADER FILES ------------------------------------------------------------
+
+// MACROS ------------------------------------------------------------------
+
+// TYPES -------------------------------------------------------------------
+
+// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
+
+// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
+
+// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
+
+// EXTERNAL DATA DECLARATIONS ----------------------------------------------
+
+// PUBLIC DATA DEFINITIONS -------------------------------------------------
+
+// PRIVATE DATA DEFINITIONS ------------------------------------------------
+
+// CODE --------------------------------------------------------------------
+
+//==========================================================================
+//
+//
+//
+//==========================================================================
+
--- /dev/null
+++ b/textdefs.h
@@ -1,0 +1,161 @@
+//**************************************************************************
+//**
+//** textdefs.h : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 477 $
+//** $Date: 2009-05-27 19:55:37 +0300 (Wed, 27 May 2009) $
+//**
+//**************************************************************************
+
+#ifndef __TEXTDEFS_H
+#define __TEXTDEFS_H
+
+/* ---- MN_menu.c ---- */
+
+#define TXT_GAMMA_LEVEL_OFF	"GAMMA CORRECTION OFF"
+#define TXT_GAMMA_LEVEL_1	"GAMMA CORRECTION LEVEL 1"
+#define TXT_GAMMA_LEVEL_2	"GAMMA CORRECTION LEVEL 2"
+#define TXT_GAMMA_LEVEL_3	"GAMMA CORRECTION LEVEL 3"
+#define TXT_GAMMA_LEVEL_4	"GAMMA CORRECTION LEVEL 4"
+
+
+/* ---- P_inter.c ---- */
+
+/* Mana */
+
+#define TXT_MANA_1		"BLUE MANA"
+#define TXT_MANA_2		"GREEN MANA"
+#define TXT_MANA_BOTH		"COMBINED MANA"
+
+/* Keys */
+
+#define TXT_KEY_STEEL		"STEEL KEY"
+#define TXT_KEY_CAVE		"CAVE KEY"
+#define TXT_KEY_AXE		"AXE KEY"
+#define TXT_KEY_FIRE		"FIRE KEY"
+#define TXT_KEY_EMERALD		"EMERALD KEY"
+#define TXT_KEY_DUNGEON		"DUNGEON KEY"
+#define TXT_KEY_SILVER		"SILVER KEY"
+#define TXT_KEY_RUSTED		"RUSTED KEY"
+#define TXT_KEY_HORN		"HORN KEY"
+#define TXT_KEY_SWAMP		"SWAMP KEY"
+#define TXT_KEY_CASTLE		"CASTLE KEY"
+
+/* Artifacts */
+
+#define TXT_ARTIINVULNERABILITY	"ICON OF THE DEFENDER"
+#define TXT_ARTIHEALTH		"QUARTZ FLASK"
+#define TXT_ARTISUPERHEALTH	"MYSTIC URN"
+#define TXT_ARTISUMMON		"DARK SERVANT"
+#define TXT_ARTITORCH		"TORCH"
+#define TXT_ARTIEGG		"PORKALATOR"
+#define TXT_ARTIFLY		"WINGS OF WRATH"
+#define TXT_ARTITELEPORT	"CHAOS DEVICE"
+#define TXT_ARTIPOISONBAG	"FLECHETTE"
+#define TXT_ARTITELEPORTOTHER	"BANISHMENT DEVICE"
+#define TXT_ARTISPEED		"BOOTS OF SPEED"
+#define TXT_ARTIBOOSTMANA	"KRATER OF MIGHT"
+#define TXT_ARTIBOOSTARMOR	"DRAGONSKIN BRACERS"
+#define TXT_ARTIBLASTRADIUS	"DISC OF REPULSION"
+#define TXT_ARTIHEALINGRADIUS	"MYSTIC AMBIT INCANT"
+
+/* Puzzle artifacts */
+
+#define TXT_ARTIPUZZSKULL	"YORICK'S SKULL"
+#define TXT_ARTIPUZZGEMBIG	"HEART OF D'SPARIL"
+#define TXT_ARTIPUZZGEMRED	"RUBY PLANET"
+#define TXT_ARTIPUZZGEMGREEN1	"EMERALD PLANET"
+#define TXT_ARTIPUZZGEMGREEN2	"EMERALD PLANET"
+#define TXT_ARTIPUZZGEMBLUE1	"SAPPHIRE PLANET"
+#define TXT_ARTIPUZZGEMBLUE2	"SAPPHIRE PLANET"
+#define TXT_ARTIPUZZBOOK1	"DAEMON CODEX"
+#define TXT_ARTIPUZZBOOK2	"LIBER OSCURA"
+#define TXT_ARTIPUZZSKULL2	"FLAME MASK"
+#define TXT_ARTIPUZZFWEAPON	"GLAIVE SEAL"
+#define TXT_ARTIPUZZCWEAPON	"HOLY RELIC"
+#define TXT_ARTIPUZZMWEAPON	"SIGIL OF THE MAGUS"
+#define TXT_ARTIPUZZGEAR	"CLOCK GEAR"
+#define TXT_USEPUZZLEFAILED	"YOU CANNOT USE THIS HERE"
+
+/* Items */
+
+#define TXT_ITEMHEALTH		"CRYSTAL VIAL"
+#define TXT_ITEMBAGOFHOLDING	"BAG OF HOLDING"
+#define TXT_ITEMSHIELD1		"SILVER SHIELD"
+#define TXT_ITEMSHIELD2		"ENCHANTED SHIELD"
+#define TXT_ITEMSUPERMAP	"MAP SCROLL"
+#define TXT_ARMOR1		"MESH ARMOR"
+#define TXT_ARMOR2		"FALCON SHIELD"
+#define TXT_ARMOR3		"PLATINUM HELMET"
+#define TXT_ARMOR4		"AMULET OF WARDING"
+
+/* Weapons */
+
+#define TXT_WEAPON_F2		"TIMON'S AXE"
+#define TXT_WEAPON_F3		"HAMMER OF RETRIBUTION"
+#define TXT_WEAPON_F4		"QUIETUS ASSEMBLED"
+#define TXT_WEAPON_C2		"SERPENT STAFF"
+#define TXT_WEAPON_C3		"FIRESTORM"
+#define TXT_WEAPON_C4		"WRAITHVERGE ASSEMBLED"
+#define TXT_WEAPON_M2		"FROST SHARDS"
+#define TXT_WEAPON_M3		"ARC OF DEATH"
+#define TXT_WEAPON_M4		"BLOODSCOURGE ASSEMBLED"
+#define TXT_WEAPON_A2		"HAND CROSSBOW"
+#define TXT_WEAPON_A3		"GRENADES"
+#define TXT_WEAPON_A4		"STAFF OF SET ASSEMBLED"
+#define TXT_QUIETUS_PIECE	"SEGMENT OF QUIETUS"
+#define TXT_WRAITHVERGE_PIECE	"SEGMENT OF WRAITHVERGE"
+#define TXT_BLOODSCOURGE_PIECE	"SEGMENT OF BLOODSCOURGE"
+#define TXT_STAFFOFSET_PIECE	"SEGMENT OF STAFF OF SET"
+
+
+/* ---- SB_bar.c ---- */
+
+#define TXT_CHEATGODON		"GOD MODE ON"
+#define TXT_CHEATGODOFF		"GOD MODE OFF"
+#define TXT_CHEATNOCLIPON	"NO CLIPPING ON"
+#define TXT_CHEATNOCLIPOFF	"NO CLIPPING OFF"
+#define TXT_CHEATWEAPONS	"ALL WEAPONS"
+#define TXT_CHEATHEALTH		"FULL HEALTH"
+#define TXT_CHEATKEYS		"ALL KEYS"
+#define TXT_CHEATSOUNDON	"SOUND DEBUG ON"
+#define TXT_CHEATSOUNDOFF	"SOUND DEBUG OFF"
+#define TXT_CHEATTICKERON	"TICKER ON"
+#define TXT_CHEATTICKEROFF	"TICKER OFF"
+#define TXT_CHEATARTIFACTS3	"ALL ARTIFACTS"
+#define TXT_CHEATARTIFACTSFAIL	"BAD INPUT"
+#define TXT_CHEATWARP		"LEVEL WARP"
+#define TXT_CHEATSCREENSHOT	"SCREENSHOT"
+#define TXT_CHEATIDDQD		"TRYING TO CHEAT, EH?  NOW YOU DIE!"
+#define TXT_CHEATIDKFA		"CHEATER - YOU DON'T DESERVE WEAPONS"
+#define TXT_CHEATBADINPUT	"BAD INPUT"
+#define TXT_CHEATNOMAP		"CAN'T FIND MAP"
+
+
+/* ---- G_game.c ---- */
+
+#define TXT_GAMESAVED		"GAME SAVED"
+
+
+/* ---- M_misc.c ---- */
+
+#define HUSTR_CHATMACRO1	"I'm ready to kick butt!"
+#define HUSTR_CHATMACRO2	"I'm OK."
+#define HUSTR_CHATMACRO3	"I'm not looking too good!"
+#define HUSTR_CHATMACRO4	"Help!"
+#define HUSTR_CHATMACRO5	"You suck!"
+#define HUSTR_CHATMACRO6	"Next time, scumbag..."
+#define HUSTR_CHATMACRO7	"Come here!"
+#define HUSTR_CHATMACRO8	"I'll take care of it."
+#define HUSTR_CHATMACRO9	"Yes"
+#define HUSTR_CHATMACRO0	"No"
+
+
+/* ---- AM_map.c ---- */
+
+#define AMSTR_FOLLOWON		"FOLLOW MODE ON"
+#define AMSTR_FOLLOWOFF		"FOLLOW MODE OFF"
+
+
+#endif	/* __TEXTDEFS_H */
+
--- /dev/null
+++ b/transtb10.h
@@ -1,0 +1,167 @@
+/*
+ * translation table from hexen.wad version 1.0
+ * MAXPLAYERS == 4, 3 * (MAXPLAYERS - 1) == 9 entries
+ */
+
+	/* TRANTBL0 */
+	0x01,0x01,0x02,0x03,0x05,0x21,0x06,0x07,0x08,0x09,0x24,0x0b,0x0c,0x26,0x0e,0x0f,
+	0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,
+	0x20,0x21,0x22,0x09,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
+	0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
+	0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,
+	0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f,
+	0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,
+	0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,
+	0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,
+	0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,0x9f,
+	0xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,
+	0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf,
+	0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf,
+	0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xdf,
+	0xe0,0xe1,0xe2,0xe3,0xe4,0xd1,0xe6,0xe7,0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,
+	0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xac,0xae,0x01,
+
+	/* TRANTBL1 */
+	0x01,0x01,0x02,0x03,0x05,0x21,0x06,0x07,0x08,0x09,0x24,0x0b,0x0c,0x26,0x0e,0x0f,
+	0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,
+	0x20,0x21,0x22,0x09,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
+	0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
+	0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,
+	0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f,
+	0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,
+	0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,
+	0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,
+	0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,0x9f,
+	0xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,
+	0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf,
+	0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf,
+	0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xdf,
+	0xe0,0xe1,0xe2,0xe3,0xe4,0xd1,0xe6,0xe7,0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,
+	0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0x92,0x93,0x94,0x95,0x96,0x97,0x99,0x9b,0x9d,0x01,
+
+	/* TRANTBL2 */
+	0x01,0x01,0x02,0x03,0x05,0x21,0x06,0x07,0x08,0x09,0x24,0x0b,0x0c,0x26,0x0e,0x0f,
+	0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,
+	0x20,0x21,0x22,0x09,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
+	0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
+	0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,
+	0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f,
+	0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,
+	0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,
+	0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,
+	0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,0x9f,
+	0xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,
+	0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf,
+	0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf,
+	0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xdf,
+	0xe0,0xe1,0xe2,0xe3,0xe4,0xd1,0xe6,0xe7,0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,
+	0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3b,0x3d,0x01,
+
+	/* TRANTBL3 */
+	0x01,0x01,0x02,0x03,0x05,0x21,0x06,0x07,0x08,0x09,0x24,0x0b,0x0c,0x26,0x0e,0x0f,
+	0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,
+	0x20,0x21,0x22,0x09,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
+	0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
+	0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,
+	0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f,
+	0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,
+	0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,
+	0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,
+	0x90,0x91,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,0xb0,0xb1,
+	0xb2,0xb3,0xb4,0xb5,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,
+	0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf,
+	0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf,
+	0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xdf,
+	0xe0,0xe1,0xe2,0xe3,0xe4,0xd1,0xe6,0xe7,0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,
+	0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0x01,
+
+	/* TRANTBL4 */
+	0x01,0x01,0x02,0x03,0x05,0x21,0x06,0x07,0x08,0x09,0x24,0x0b,0x0c,0x26,0x0e,0x0f,
+	0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,
+	0x20,0x21,0x22,0x09,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
+	0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
+	0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,
+	0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f,
+	0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,
+	0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,
+	0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,
+	0x90,0x91,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,
+	0x88,0x89,0x8a,0x8b,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,
+	0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf,
+	0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf,
+	0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xdf,
+	0xe0,0xe1,0xe2,0xe3,0xe4,0xd1,0xe6,0xe7,0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,
+	0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0x01,
+
+	/* TRANTBL5 */
+	0x01,0x01,0x02,0x03,0x05,0x21,0x06,0x07,0x08,0x09,0x24,0x0b,0x0c,0x26,0x0e,0x0f,
+	0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,
+	0x20,0x21,0x22,0x09,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
+	0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
+	0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,
+	0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f,
+	0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,
+	0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,
+	0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,
+	0x90,0x91,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,0x40,
+	0x41,0x42,0xc7,0xc8,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,
+	0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf,
+	0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf,
+	0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xdf,
+	0xe0,0xe1,0xe2,0xe3,0xe4,0xd1,0xe6,0xe7,0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,
+	0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0x01,
+
+	/* TRANTBL6 */
+	0x01,0x01,0x02,0x03,0x05,0x21,0x06,0x07,0x08,0x09,0x24,0x0b,0x0c,0x26,0x0e,0x0f,
+	0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,
+	0x20,0x21,0x22,0x09,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
+	0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
+	0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,
+	0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f,
+	0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,
+	0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,
+	0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,
+	0x90,0x91,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,0xb0,0xb1,
+	0xb2,0xb3,0xb4,0xb5,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,
+	0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf,
+	0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf,
+	0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xdf,
+	0xe0,0xe1,0xe2,0xe3,0xe4,0xd1,0xe6,0xe7,0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,
+	0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0x01,
+
+	/* TRANTBL7 */
+	0x01,0x01,0x02,0x03,0x05,0x21,0x06,0x07,0x08,0x09,0x24,0x0b,0x0c,0x26,0x0e,0x0f,
+	0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,
+	0x20,0x21,0x22,0x09,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
+	0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
+	0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,
+	0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f,
+	0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,
+	0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,
+	0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,
+	0x90,0x91,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,
+	0x88,0x89,0x8a,0x8b,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,
+	0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf,
+	0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf,
+	0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xdf,
+	0xe0,0xe1,0xe2,0xe3,0xe4,0xd1,0xe6,0xe7,0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,
+	0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0x01,
+
+	/* TRANTBL8 */
+	0x01,0x01,0x02,0x03,0x05,0x21,0x06,0x07,0x08,0x09,0x24,0x0b,0x0c,0x26,0x0e,0x0f,
+	0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,
+	0x20,0x21,0x22,0x09,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
+	0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
+	0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,
+	0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f,
+	0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,
+	0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,
+	0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,
+	0x90,0x91,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,0x40,
+	0x41,0x42,0xc7,0xc8,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,
+	0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf,
+	0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf,
+	0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xdf,
+	0xe0,0xe1,0xe2,0xe3,0xe4,0xd1,0xe6,0xe7,0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,
+	0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0x01,
+
--- /dev/null
+++ b/transtb11.h
@@ -1,0 +1,383 @@
+/*
+ * translation table from hexen.wad version 1.0
+ * MAXPLAYERS == 8, 3 * (MAXPLAYERS - 1) == 21 entries
+ */
+
+	/* TRANTBL0 */
+	0x01,0x01,0x02,0x03,0x05,0x21,0x06,0x07,0x08,0x09,0x24,0x0b,0x0c,0x26,0x0e,0x0f,
+	0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,
+	0x20,0x21,0x22,0x09,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
+	0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
+	0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,
+	0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f,
+	0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,
+	0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,
+	0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,
+	0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,0x9f,
+	0xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,
+	0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf,
+	0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf,
+	0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xdf,
+	0xe0,0xe1,0xe2,0xe3,0xe4,0xd1,0xe6,0xe7,0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,
+	0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xac,0xae,0x01,
+
+	/* TRANTBL1 */
+	0x01,0x01,0x02,0x03,0x05,0x21,0x06,0x07,0x08,0x09,0x24,0x0b,0x0c,0x26,0x0e,0x0f,
+	0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,
+	0x20,0x21,0x22,0x09,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
+	0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
+	0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,
+	0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f,
+	0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,
+	0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,
+	0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,
+	0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,0x9f,
+	0xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,
+	0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf,
+	0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf,
+	0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xdf,
+	0xe0,0xe1,0xe2,0xe3,0xe4,0xd1,0xe6,0xe7,0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,
+	0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0x93,0x95,0x97,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,0x01,
+
+	/* TRANTBL2 */
+	0x01,0x01,0x02,0x03,0x05,0x21,0x06,0x07,0x08,0x09,0x24,0x0b,0x0c,0x26,0x0e,0x0f,
+	0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,
+	0x20,0x21,0x22,0x09,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
+	0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
+	0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,
+	0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f,
+	0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,
+	0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,
+	0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,
+	0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,0x9f,
+	0xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,
+	0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf,
+	0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf,
+	0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xdf,
+	0xe0,0xe1,0xe2,0xe3,0xe4,0xd1,0xe6,0xe7,0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,
+	0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0x33,0x35,0x36,0x37,0x38,0x39,0x3b,0x3e,0x40,0x01,
+
+	/* TRANTBL3 */
+	0x01,0x01,0x02,0x03,0x05,0x21,0x06,0x07,0x08,0x09,0x24,0x0b,0x0c,0x26,0x0e,0x0f,
+	0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,
+	0x20,0x21,0x22,0x09,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
+	0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
+	0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,
+	0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f,
+	0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,
+	0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,
+	0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,
+	0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,0x9f,
+	0xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,
+	0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf,
+	0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf,
+	0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xdf,
+	0xe0,0xe1,0xe2,0xe3,0xe4,0xd1,0xe6,0xe7,0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,
+	0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xbd,0xbf,0xc1,0xc3,0xc5,0xc6,0xc7,0xc8,0xc9,0x01,
+
+	/* TRANTBL4 */
+	0x01,0x01,0x02,0x03,0x05,0x21,0x06,0x07,0x08,0x09,0x24,0x0b,0x0c,0x26,0x0e,0x0f,
+	0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,
+	0x20,0x21,0x22,0x09,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
+	0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
+	0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,
+	0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f,
+	0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,
+	0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,
+	0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,
+	0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,0x9f,
+	0xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,
+	0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf,
+	0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf,
+	0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xdf,
+	0xe0,0xe1,0xe2,0xe3,0xe4,0xd1,0xe6,0xe7,0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,
+	0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0x06,0x09,0x0b,0x26,0x27,0x29,0x2b,0x2d,0x2f,0x01,
+
+	/* TRANTBL5 */
+	0x01,0x01,0x02,0x03,0x05,0x21,0x06,0x07,0x08,0x09,0x24,0x0b,0x0c,0x26,0x0e,0x0f,
+	0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,
+	0x20,0x21,0x22,0x09,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
+	0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
+	0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,
+	0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f,
+	0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,
+	0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,
+	0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,
+	0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,0x9f,
+	0xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,
+	0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf,
+	0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf,
+	0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xdf,
+	0xe0,0xe1,0xe2,0xe3,0xe4,0xd1,0xe6,0xe7,0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,
+	0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0x61,0x63,0x66,0x69,0x6a,0x6b,0x6c,0x6f,0x71,0x00,
+
+	/* TRANTBL6 */
+	0x01,0x01,0x02,0x03,0x05,0x21,0x06,0x07,0x08,0x09,0x24,0x0b,0x0c,0x26,0x0e,0x0f,
+	0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,
+	0x20,0x21,0x22,0x09,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
+	0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
+	0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,
+	0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f,
+	0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,
+	0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,
+	0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,
+	0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,0x9f,
+	0xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,
+	0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf,
+	0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf,
+	0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xdf,
+	0xe0,0xe1,0xe2,0xe3,0xe4,0xd1,0xe6,0xe7,0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,
+	0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xe7,0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,0x00,
+
+	/* TRANTBL7 */
+	0x01,0x01,0x02,0x03,0x05,0x21,0x06,0x07,0x08,0x09,0x24,0x0b,0x0c,0x26,0x0e,0x0f,
+	0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,
+	0x20,0x21,0x22,0x09,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
+	0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
+	0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,
+	0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f,
+	0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,
+	0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,
+	0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,
+	0x90,0x91,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,0xb0,0xb1,
+	0xb2,0xb3,0xb4,0xb5,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,
+	0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf,
+	0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf,
+	0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xdf,
+	0xe0,0xe1,0xe2,0xe3,0xe4,0xd1,0xe6,0xe7,0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,
+	0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0x01,
+
+	/* TRANTBL8 */
+	0x01,0x01,0x02,0x03,0x05,0x21,0x06,0x07,0x08,0x09,0x24,0x0b,0x0c,0x26,0x0e,0x0f,
+	0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,
+	0x20,0x21,0x22,0x09,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
+	0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
+	0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,
+	0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f,
+	0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,
+	0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,
+	0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,
+	0x90,0x91,0x7a,0x7b,0x7d,0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,
+	0x8b,0x8c,0x8d,0x8f,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,
+	0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf,
+	0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf,
+	0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xdf,
+	0xe0,0xe1,0xe2,0xe3,0xe4,0xd1,0xe6,0xe7,0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,
+	0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0x01,
+
+	/* TRANTBL9 */
+	0x01,0x01,0x02,0x03,0x05,0x21,0x06,0x07,0x08,0x09,0x24,0x0b,0x0c,0x26,0x0e,0x0f,
+	0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,
+	0x20,0x21,0x22,0x09,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
+	0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
+	0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,
+	0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f,
+	0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,
+	0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,
+	0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,
+	0x90,0x91,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,0x40,
+	0x41,0x41,0x42,0x42,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,
+	0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf,
+	0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf,
+	0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xdf,
+	0xe0,0xe1,0xe2,0xe3,0xe4,0xd1,0xe6,0xe7,0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,
+	0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0x01,
+
+	/* TRANTBLA */
+	0x01,0x01,0x02,0x03,0x05,0x21,0x06,0x07,0x08,0x09,0x24,0x0b,0x0c,0x26,0x0e,0x0f,
+	0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,
+	0x20,0x21,0x22,0x09,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
+	0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
+	0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,
+	0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f,
+	0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,
+	0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,
+	0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,
+	0x90,0x91,0xba,0xbb,0xbc,0xbd,0xbe,0xbf,0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,
+	0xc8,0xc9,0xca,0xd5,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,
+	0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf,
+	0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf,
+	0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xdf,
+	0xe0,0xe1,0xe2,0xe3,0xe4,0xd1,0xe6,0xe7,0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,
+	0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0x01,
+
+	/* TRANTBLB */
+	0x01,0x01,0x02,0x03,0x05,0x21,0x06,0x07,0x08,0x09,0x24,0x0b,0x0c,0x26,0x0e,0x0f,
+	0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,
+	0x20,0x21,0x22,0x09,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
+	0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
+	0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,
+	0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f,
+	0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,
+	0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,
+	0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,
+	0x90,0x91,0x21,0x22,0x09,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,
+	0x2f,0x30,0x31,0x32,0x01,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,
+	0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf,
+	0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf,
+	0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xdf,
+	0xe0,0xe1,0xe2,0xe3,0xe4,0xd1,0xe6,0xe7,0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,
+	0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0x01,
+
+	/* TRANTBLC */
+	0x01,0x01,0x02,0x03,0x05,0x21,0x06,0x07,0x08,0x09,0x24,0x0b,0x0c,0x26,0x0e,0x0f,
+	0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,
+	0x20,0x21,0x22,0x09,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
+	0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
+	0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,
+	0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f,
+	0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,
+	0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,
+	0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,
+	0x90,0x91,0x61,0x62,0x63,0x64,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,
+	0x70,0x72,0x74,0x76,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,
+	0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf,
+	0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf,
+	0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xdf,
+	0xe0,0xe1,0xe2,0xe3,0xe4,0xd1,0xe6,0xe7,0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,
+	0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0x01,
+
+	/* TRANTBLD */
+	0x01,0x01,0x02,0x03,0x05,0x21,0x06,0x07,0x08,0x09,0x24,0x0b,0x0c,0x26,0x0e,0x0f,
+	0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,
+	0x20,0x21,0x22,0x09,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
+	0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
+	0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,
+	0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f,
+	0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,
+	0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,
+	0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,
+	0x90,0x91,0xe7,0xe7,0xe8,0xe8,0xe9,0xe9,0xea,0xea,0xeb,0xeb,0xec,0xec,0xed,0xed,
+	0xee,0xee,0xef,0xef,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,
+	0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf,
+	0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf,
+	0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xdf,
+	0xe0,0xe1,0xe2,0xe3,0xe4,0xd1,0xe6,0xe7,0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,
+	0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0x01,
+
+	/* TRANTBLE */
+	0x01,0x01,0x02,0x03,0x05,0x21,0x06,0x07,0x08,0x09,0x24,0x0b,0x0c,0x26,0x0e,0x0f,
+	0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,
+	0x20,0x21,0x22,0x09,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
+	0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
+	0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,
+	0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f,
+	0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,
+	0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,
+	0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,
+	0x90,0x91,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,0xb0,0xb1,
+	0xb2,0xb3,0xb4,0xb5,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,
+	0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf,
+	0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf,
+	0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xdf,
+	0xe0,0xe1,0xe2,0xe3,0xe4,0xd1,0xe6,0xe7,0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,
+	0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0x01,
+
+	/* TRANTBLF */
+	0x01,0x01,0x02,0x03,0x05,0x21,0x06,0x07,0x08,0x09,0x24,0x0b,0x0c,0x26,0x0e,0x0f,
+	0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,
+	0x20,0x21,0x22,0x09,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
+	0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
+	0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,
+	0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f,
+	0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,
+	0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,
+	0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,
+	0x90,0x91,0x7a,0x7b,0x7d,0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,
+	0x8b,0x8c,0x8d,0x8f,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,
+	0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf,
+	0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf,
+	0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xdf,
+	0xe0,0xe1,0xe2,0xe3,0xe4,0xd1,0xe6,0xe7,0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,
+	0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0x01,
+
+	/* TRANTBLG */
+	0x01,0x01,0x02,0x03,0x05,0x21,0x06,0x07,0x08,0x09,0x24,0x0b,0x0c,0x26,0x0e,0x0f,
+	0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,
+	0x20,0x21,0x22,0x09,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
+	0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
+	0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,
+	0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f,
+	0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,
+	0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,
+	0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,
+	0x90,0x91,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,0x40,
+	0x41,0x41,0x42,0x42,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,
+	0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf,
+	0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf,
+	0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xdf,
+	0xe0,0xe1,0xe2,0xe3,0xe4,0xd1,0xe6,0xe7,0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,
+	0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0x01,
+
+	/* TRANTBLH */
+	0x01,0x01,0x02,0x03,0x05,0x21,0x06,0x07,0x08,0x09,0x24,0x0b,0x0c,0x26,0x0e,0x0f,
+	0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,
+	0x20,0x21,0x22,0x09,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
+	0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
+	0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,
+	0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f,
+	0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,
+	0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,
+	0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,
+	0x90,0x91,0xba,0xbb,0xbc,0xbd,0xbe,0xbf,0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,
+	0xc8,0xc9,0xca,0xd5,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,
+	0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf,
+	0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf,
+	0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xdf,
+	0xe0,0xe1,0xe2,0xe3,0xe4,0xd1,0xe6,0xe7,0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,
+	0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0x01,
+
+	/* TRANTBLI */
+	0x01,0x01,0x02,0x03,0x05,0x21,0x06,0x07,0x08,0x09,0x24,0x0b,0x0c,0x26,0x0e,0x0f,
+	0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,
+	0x20,0x21,0x22,0x09,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
+	0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
+	0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,
+	0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f,
+	0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,
+	0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,
+	0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,
+	0x90,0x91,0x21,0x22,0x09,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,
+	0x2f,0x30,0x31,0x32,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,
+	0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf,
+	0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf,
+	0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xdf,
+	0xe0,0xe1,0xe2,0xe3,0xe4,0xd1,0xe6,0xe7,0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,
+	0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0x01,
+
+	/* TRANTBLJ */
+	0x01,0x01,0x02,0x03,0x05,0x21,0x06,0x07,0x08,0x09,0x24,0x0b,0x0c,0x26,0x0e,0x0f,
+	0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,
+	0x20,0x21,0x22,0x09,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
+	0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
+	0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,
+	0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f,
+	0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,
+	0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,
+	0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,
+	0x90,0x91,0x61,0x62,0x63,0x64,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,
+	0x70,0x72,0x74,0x76,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,
+	0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf,
+	0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf,
+	0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xdf,
+	0xe0,0xe1,0xe2,0xe3,0xe4,0xd1,0xe6,0xe7,0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,
+	0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0x01,
+
+	/* TRANTBLK */
+	0x01,0x01,0x02,0x03,0x05,0x21,0x06,0x07,0x08,0x09,0x24,0x0b,0x0c,0x26,0x0e,0x0f,
+	0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,
+	0x20,0x21,0x22,0x09,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
+	0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
+	0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,
+	0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f,
+	0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,
+	0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,
+	0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,
+	0x90,0x91,0xe7,0xe7,0xe8,0xe8,0xe9,0xe9,0xea,0xea,0xeb,0xeb,0xec,0xec,0xed,0xed,
+	0xee,0xee,0xef,0xef,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,
+	0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf,
+	0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf,
+	0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xdf,
+	0xe0,0xe1,0xe2,0xe3,0xe4,0xd1,0xe6,0xe7,0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,
+	0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0x01,
+
--- /dev/null
+++ b/v_compat.h
@@ -1,0 +1,55 @@
+
+//**************************************************************************
+//**
+//** v_compat.h
+//**
+//** $Revision: 458 $
+//** $Date: 2009-05-25 15:35:27 +0300 (Mon, 25 May 2009) $
+//**
+//**************************************************************************
+
+#ifndef __V_COMPAT_H
+#define __V_COMPAT_H
+
+#if defined(RENDER3D)
+#include "ogl_def.h"
+#endif
+
+/* SetPalette */
+
+#ifndef PLAYPAL_NUM
+#define PLAYPAL_NUM		W_GetNumForName("PLAYPAL")
+#endif
+
+#if defined(RENDER3D)
+#define V_SetPaletteBase()	OGL_SetFilter(0)
+#define V_SetPaletteShift(num)	OGL_SetFilter((num))
+#else
+#define V_SetPaletteBase()	I_SetPalette((byte *)W_CacheLumpName("PLAYPAL", PU_CACHE))
+#define V_SetPaletteShift(num)	I_SetPalette((byte *)W_CacheLumpNum(PLAYPAL_NUM, PU_CACHE) + (num)*768)
+#endif
+
+/* Minimal definitions for DrawPatch / DrawRawScreen stuff. */
+#if defined(RENDER3D)
+#define PATCH_REF		int
+#define INVALID_PATCH		0
+#define BYTE_REF		int
+#else
+#define BYTE_REF		byte*
+#define PATCH_REF		patch_t*
+#define INVALID_PATCH		NULL
+#endif
+
+/* Minimal definitions for CacheLumpName / CacheLumpNum stuff. */
+#if defined(RENDER3D)
+#define ZR_ChangeTag(a,b)
+#define WR_CacheLumpName(a,b)		W_GetNumForName((a))
+#define WR_CacheLumpNum(a,b)		(a)
+#else
+#define ZR_ChangeTag			Z_ChangeTag
+#define WR_CacheLumpName		W_CacheLumpName
+#define WR_CacheLumpNum			W_CacheLumpNum
+#endif
+
+#endif	/* __V_COMPAT_H */
+
--- /dev/null
+++ b/v_video.c
@@ -1,0 +1,414 @@
+
+//**************************************************************************
+//**
+//** v_video.c : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 373 $
+//** $Date: 2009-05-19 21:14:28 +0300 (Tue, 19 May 2009) $
+//**
+//**************************************************************************
+
+#include "h2stdinc.h"
+#include "h2def.h"
+
+#define SC_INDEX	0x3c4
+
+int	usegamma;
+
+byte gammatable[5][256] =
+{
+	{   1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16,
+	   17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32,
+	   33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
+	   49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64,
+	   65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80,
+	   81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96,
+	   97, 98, 99,100,101,102,103,104,105,106,107,108,109,110,111,112,
+	  113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,
+	  128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,
+	  144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,
+	  160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,
+	  176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,
+	  192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,
+	  208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,
+	  224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,
+	  240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255
+	},
+
+	{   2,  4,  5,  7,  8, 10, 11, 12, 14, 15, 16, 18, 19, 20, 21, 23,
+	   24, 25, 26, 27, 29, 30, 31, 32, 33, 34, 36, 37, 38, 39, 40, 41,
+	   42, 44, 45, 46, 47, 48, 49, 50, 51, 52, 54, 55, 56, 57, 58, 59,
+	   60, 61, 62, 63, 64, 65, 66, 67, 69, 70, 71, 72, 73, 74, 75, 76,
+	   77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92,
+	   93, 94, 95, 96, 97, 98, 99,100,101,102,103,104,105,106,107,108,
+	  109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,
+	  125,126,127,128,129,129,130,131,132,133,134,135,136,137,138,139,
+	  140,141,142,143,144,145,146,147,148,148,149,150,151,152,153,154,
+	  155,156,157,158,159,160,161,162,163,163,164,165,166,167,168,169,
+	  170,171,172,173,174,175,175,176,177,178,179,180,181,182,183,184,
+	  185,186,186,187,188,189,190,191,192,193,194,195,196,196,197,198,
+	  199,200,201,202,203,204,205,205,206,207,208,209,210,211,212,213,
+	  214,214,215,216,217,218,219,220,221,222,222,223,224,225,226,227,
+	  228,229,230,230,231,232,233,234,235,236,237,237,238,239,240,241,
+	  242,243,244,245,245,246,247,248,249,250,251,252,252,253,254,255
+	},
+
+	{   4,  7,  9, 11, 13, 15, 17, 19, 21, 22, 24, 26, 27, 29, 30, 32,
+	   33, 35, 36, 38, 39, 40, 42, 43, 45, 46, 47, 48, 50, 51, 52, 54,
+	   55, 56, 57, 59, 60, 61, 62, 63, 65, 66, 67, 68, 69, 70, 72, 73,
+	   74, 75, 76, 77, 78, 79, 80, 82, 83, 84, 85, 86, 87, 88, 89, 90,
+	   91, 92, 93, 94, 95, 96, 97, 98,100,101,102,103,104,105,106,107,
+	  108,109,110,111,112,113,114,114,115,116,117,118,119,120,121,122,
+	  123,124,125,126,127,128,129,130,131,132,133,133,134,135,136,137,
+	  138,139,140,141,142,143,144,144,145,146,147,148,149,150,151,152,
+	  153,153,154,155,156,157,158,159,160,160,161,162,163,164,165,166,
+	  166,167,168,169,170,171,172,172,173,174,175,176,177,178,178,179,
+	  180,181,182,183,183,184,185,186,187,188,188,189,190,191,192,193,
+	  193,194,195,196,197,197,198,199,200,201,201,202,203,204,205,206,
+	  206,207,208,209,210,210,211,212,213,213,214,215,216,217,217,218,
+	  219,220,221,221,222,223,224,224,225,226,227,228,228,229,230,231,
+	  231,232,233,234,235,235,236,237,238,238,239,240,241,241,242,243,
+	  244,244,245,246,247,247,248,249,250,251,251,252,253,254,254,255
+	},
+
+	{   8, 12, 16, 19, 22, 24, 27, 29, 31, 34, 36, 38, 40, 41, 43, 45,
+	   47, 49, 50, 52, 53, 55, 57, 58, 60, 61, 63, 64, 65, 67, 68, 70,
+	   71, 72, 74, 75, 76, 77, 79, 80, 81, 82, 84, 85, 86, 87, 88, 90,
+	   91, 92, 93, 94, 95, 96, 98, 99,100,101,102,103,104,105,106,107,
+	  108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,
+	  124,125,126,127,128,129,130,131,132,133,134,135,135,136,137,138,
+	  139,140,141,142,143,143,144,145,146,147,148,149,150,150,151,152,
+	  153,154,155,155,156,157,158,159,160,160,161,162,163,164,165,165,
+	  166,167,168,169,169,170,171,172,173,173,174,175,176,176,177,178,
+	  179,180,180,181,182,183,183,184,185,186,186,187,188,189,189,190,
+	  191,192,192,193,194,195,195,196,197,197,198,199,200,200,201,202,
+	  202,203,204,205,205,206,207,207,208,209,210,210,211,212,212,213,
+	  214,214,215,216,216,217,218,219,219,220,221,221,222,223,223,224,
+	  225,225,226,227,227,228,229,229,230,231,231,232,233,233,234,235,
+	  235,236,237,237,238,238,239,240,240,241,242,242,243,244,244,245,
+	  246,246,247,247,248,249,249,250,251,251,252,253,253,254,254,255
+	},
+
+	{  16, 23, 28, 32, 36, 39, 42, 45, 48, 50, 53, 55, 57, 60, 62, 64,
+	   66, 68, 69, 71, 73, 75, 76, 78, 80, 81, 83, 84, 86, 87, 89, 90,
+	   92, 93, 94, 96, 97, 98,100,101,102,103,105,106,107,108,109,110,
+	  112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,128,
+	  128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,
+	  143,144,145,146,147,148,149,150,150,151,152,153,154,155,155,156,
+	  157,158,159,159,160,161,162,163,163,164,165,166,166,167,168,169,
+	  169,170,171,172,172,173,174,175,175,176,177,177,178,179,180,180,
+	  181,182,182,183,184,184,185,186,187,187,188,189,189,190,191,191,
+	  192,193,193,194,195,195,196,196,197,198,198,199,200,200,201,202,
+	  202,203,203,204,205,205,206,207,207,208,208,209,210,210,211,211,
+	  212,213,213,214,214,215,216,216,217,217,218,219,219,220,220,221,
+	  221,222,223,223,224,224,225,225,226,227,227,228,228,229,229,230,
+	  230,231,232,232,233,233,234,234,235,235,236,236,237,237,238,239,
+	  239,240,240,241,241,242,242,243,243,244,244,245,245,246,246,247,
+	  247,248,248,249,249,250,250,251,251,252,252,253,254,254,255,255
+	}
+};
+
+#if defined(RENDER3D)
+
+void V_Init(void)
+{
+	/* OpenGL: NOTHING TO DO HERE. */
+}
+
+#else	/* RENDER3D */
+
+byte	*screen;
+int	dirtybox[4];
+
+//---------------------------------------------------------------------------
+//
+// PROC V_Init
+//
+//---------------------------------------------------------------------------
+
+void V_Init(void)
+{
+	// I_AllocLow will put screen in low dos memory on PCs.
+	screen = I_AllocLow(SCREENWIDTH*SCREENHEIGHT);
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC V_DrawPatch
+//
+// Draws a column based masked pic to the screen.
+//
+//---------------------------------------------------------------------------
+
+void V_DrawPatch(int x, int y, patch_t *patch)
+{
+	int count;
+	int col;
+	column_t *column;
+	byte *desttop;
+	byte *dest;
+	byte *source;
+	int w;
+
+	y -= SHORT(patch->topoffset);
+	x -= SHORT(patch->leftoffset);
+	if (x < 0 || x + SHORT(patch->width) > SCREENWIDTH || y < 0
+		  || y + SHORT(patch->height) > SCREENHEIGHT)
+	{
+		I_Error("Bad V_DrawPatch");
+	}
+
+	col = 0;
+	desttop = screen + y*SCREENWIDTH + x;
+	w = SHORT(patch->width);
+
+	for ( ; col < w; x++, col++, desttop++)
+	{
+		column = (column_t *)((byte *)patch + LONG(patch->columnofs[col]));
+		// Step through the posts in a column
+		while (column->topdelta != 0xff)
+		{
+			source = (byte *)column + 3;
+			dest = desttop + column->topdelta*SCREENWIDTH;
+			count = column->length;
+			while (count--)
+			{
+				*dest = *source++;
+				dest += SCREENWIDTH;
+			}
+			column = (column_t *)((byte *)column + column->length + 4);
+		}
+	}
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC V_DrawPatchBuffer
+//
+// Draws a column based masked pic to a specified buffer.
+//
+//---------------------------------------------------------------------------
+
+void V_DrawPatchBuffer(int x, int y, patch_t *patch, byte *buffer)
+{
+	int count;
+	int col;
+	column_t *column;
+	byte *desttop;
+	byte *dest;
+	byte *source;
+	int w;
+
+	col = 0;
+	desttop = buffer + y*SCREENWIDTH + x;
+	w = SHORT(patch->width);
+
+	for ( ; col < w; x++, col++, desttop++)
+	{
+		column = (column_t *)((byte *)patch + LONG(patch->columnofs[col]));
+		// Step through the posts in a column
+		while (column->topdelta != 0xff)
+		{
+			source = (byte *)column + 3;
+			dest = desttop + column->topdelta*SCREENWIDTH;
+			count = column->length;
+			while (count--)
+			{
+				*dest = *source++;
+				dest += SCREENWIDTH;
+			}
+			column = (column_t *)((byte *)column + column->length + 4);
+		}
+	}
+}
+
+/*
+==================
+=
+= V_DrawFuzzPatch
+=
+= Masks a column based translucent masked pic to the screen.
+=
+==================
+*/
+extern byte *tinttable;
+
+void V_DrawFuzzPatch (int x, int y, patch_t *patch)
+{
+	int		count,col;
+	column_t	*column;
+	byte		*desttop, *dest, *source;
+	int		w;
+	
+	y -= SHORT(patch->topoffset);
+	x -= SHORT(patch->leftoffset);
+
+	if (x < 0 || x + SHORT(patch->width) > SCREENWIDTH || y < 0
+		  || y + SHORT(patch->height) > SCREENHEIGHT)
+	{
+		I_Error ("Bad V_DrawPatch");
+	}
+
+	col = 0;
+	desttop = screen + y*SCREENWIDTH + x;
+	w = SHORT(patch->width);
+
+	for ( ; col < w; x++, col++, desttop++)
+	{
+		column = (column_t *)((byte *)patch + LONG(patch->columnofs[col]));
+
+		// step through the posts in a column
+		while (column->topdelta != 0xff )
+		{
+			source = (byte *)column + 3;
+			dest = desttop + column->topdelta*SCREENWIDTH;
+			count = column->length;
+
+			while (count--)
+			{
+				*dest = tinttable[*dest + ((*source++)<<8)];
+				dest += SCREENWIDTH;
+			}
+			column = (column_t *)((byte *)column + column->length + 4);
+		}
+	}
+}
+
+/*
+==================
+=
+= V_DrawAltFuzzPatch
+=
+= Masks a column based translucent masked pic to the screen.
+=
+==================
+*/
+extern byte *tinttable;
+
+void V_DrawAltFuzzPatch (int x, int y, patch_t *patch)
+{
+	int		count,col;
+	column_t	*column;
+	byte		*desttop, *dest, *source;
+	int		w;
+
+	y -= SHORT(patch->topoffset);
+	x -= SHORT(patch->leftoffset);
+
+	if (x < 0 || x + SHORT(patch->width) > SCREENWIDTH || y < 0
+		  || y + SHORT(patch->height)> SCREENHEIGHT)
+	{
+		I_Error ("Bad V_DrawPatch");
+	}
+
+	col = 0;
+	desttop = screen + y*SCREENWIDTH + x;
+	w = SHORT(patch->width);
+
+	for ( ; col < w; x++, col++, desttop++)
+	{
+		column = (column_t *)((byte *)patch + LONG(patch->columnofs[col]));
+
+		// step through the posts in a column
+		while (column->topdelta != 0xff )
+		{
+			source = (byte *)column + 3;
+			dest = desttop + column->topdelta*SCREENWIDTH;
+			count = column->length;
+
+			while (count--)
+			{
+				*dest = tinttable[((*dest)<<8) + *source++];
+				dest += SCREENWIDTH;
+			}
+			column = (column_t *)((byte *)column + column->length + 4);
+		}
+	}
+}
+
+/*
+==================
+=
+= V_DrawShadowedPatch
+=
+= Masks a column based masked pic to the screen.
+=
+==================
+*/
+
+void V_DrawShadowedPatch(int x, int y, patch_t *patch)
+{
+	int		count,col;
+	column_t	*column;
+	byte		*desttop, *dest, *source;
+	byte		*desttop2, *dest2;
+	int		w;
+
+	y -= SHORT(patch->topoffset);
+	x -= SHORT(patch->leftoffset);
+
+	if (x < 0 || x + SHORT(patch->width) > SCREENWIDTH || y < 0
+		  || y + SHORT(patch->height) > SCREENHEIGHT)
+	{
+		I_Error ("Bad V_DrawPatch");
+	}
+
+	col = 0;
+	desttop = screen+y*SCREENWIDTH+x;
+	desttop2 = screen+(y+2)*SCREENWIDTH+x+2;
+	w = SHORT(patch->width);
+
+	for ( ; col < w; x++, col++, desttop++, desttop2++)
+	{
+		column = (column_t *)((byte *)patch + LONG(patch->columnofs[col]));
+
+		// step through the posts in a column
+		while (column->topdelta != 0xff )
+		{
+			source = (byte *)column + 3;
+			dest = desttop + column->topdelta*SCREENWIDTH;
+			dest2 = desttop2 + column->topdelta*SCREENWIDTH;
+			count = column->length;
+
+			while (count--)
+			{
+				*dest2 = tinttable[((*dest2)<<8)];
+				dest2 += SCREENWIDTH;
+				*dest = *source++;
+				dest += SCREENWIDTH;
+
+			}
+			column = (column_t *)(  (byte *)column + column->length + 4);
+		}
+	}
+}
+
+void V_BlitToScreen (int x, int y, byte *buffer, int width, int height)
+{
+	int	i, j;
+	byte	*dest;
+
+	dest = screen + x + SCREENWIDTH*y;
+	for (i = 0; i < height; i++)
+	{
+		for (j = 0; j < width; j++)
+		{
+			*dest++ = *buffer++;
+		}
+		dest += (SCREENWIDTH-width);
+	}
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC V_DrawRawScreen
+//
+//---------------------------------------------------------------------------
+
+void V_DrawRawScreen(byte *raw)
+{
+	memcpy(screen, raw, SCREENWIDTH*SCREENHEIGHT);
+}
+
+#endif	/* ! RENDER3D */
+
--- /dev/null
+++ b/w_wad.c
@@ -1,0 +1,811 @@
+
+//**************************************************************************
+//**
+//** w_wad.c : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 586 $
+//** $Date: 2012-08-31 21:51:13 +0300 (Fri, 31 Aug 2012) $
+//**
+//**************************************************************************
+
+// HEADER FILES ------------------------------------------------------------
+
+#include "h2stdinc.h"
+#include "h2def.h"
+
+// MACROS ------------------------------------------------------------------
+
+/* Old (beta) PC demo from hexen.zip, "Released October 2nd, 1995" */
+#define	OLDDEMO_LUMPS	2762
+#define	OLDDEMO_WADSIZE	10615976
+/* PC Shareware from hexndemo.zip, "Re-released October 18th, 1995" */
+#define	PCDEMO_LUMPS	2856
+#define	PCDEMO_WADSIZE	10644136
+/* Mac Shareware: */
+#define	MACDEMO_LUMPS	3500
+#define	MACDEMO_WADSIZE	13596228
+/* PC Retail, original: */
+#define	RETAIL10_LUMPS	4249
+#define	RETAIL10_SIZE	20128392
+/* PC Retail, patched : */
+#define	RETAIL11_LUMPS	4270
+#define	RETAIL11_SIZE	20083672
+/* Macintosh, retail : */
+#define	MACRETAIL_LUMPS	4567
+#define	MACRETAIL_SIZE	21078584
+/* DeathKings, original: */
+#define	DKINGS10_LUMPS	325
+#define	DKINGS10_SIZE	4429700
+/* DeathKings, patched : */
+#define	DKINGS11_LUMPS	326
+#define	DKINGS11_SIZE	4440584
+
+// TYPES -------------------------------------------------------------------
+
+typedef struct
+{
+	char identification[4];
+	int numlumps;
+	int infotableofs;
+} wadinfo_t;
+
+typedef struct
+{
+	int filepos;
+	int size;
+	char name[8];
+} filelump_t;
+
+// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
+
+// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
+
+// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
+
+static void W_MergeLumps(const char *start, const char *end);
+
+// EXTERNAL DATA DECLARATIONS ----------------------------------------------
+
+// PUBLIC DATA DEFINITIONS -------------------------------------------------
+
+const char *waddir;
+lumpinfo_t *lumpinfo;
+int numlumps;
+void **lumpcache;
+
+// PRIVATE DATA DEFINITIONS ------------------------------------------------
+
+static lumpinfo_t *PrimaryLumpInfo;
+static int PrimaryNumLumps;
+static void **PrimaryLumpCache;
+static lumpinfo_t *AuxiliaryLumpInfo;
+static int AuxiliaryNumLumps;
+static void **AuxiliaryLumpCache;
+static int AuxiliaryHandle = 0;
+boolean AuxiliaryOpened = false;
+
+// CODE --------------------------------------------------------------------
+
+boolean W_IsWadPresent(const char *filename)
+{
+	char path[MAX_OSPATH];
+	int handle = -1;
+
+	/* try the directory from the command line or
+	 *  from the shared data environment variable.
+	 */
+	if (waddir && *waddir)
+	{
+		snprintf (path, sizeof(path), "%s/%s", waddir, filename);
+		handle = open(path, OREAD);
+	}
+#if !defined(_NO_USERDIRS)
+	if (handle == -1)	/* Try UserDIR */
+	{
+		snprintf (path, sizeof(path), "%s%s", basePath, filename);
+		handle = open(path, OREAD);
+	}
+#endif	/* !_NO_USERDIRS */
+	if (handle == -1)	/* Now try CWD */
+	{
+		handle = open(filename, OREAD);
+	}
+	if (handle == -1)
+		return false;	/* Didn't find the file. */
+	close(handle);
+	return true;
+}
+
+//==========================================================================
+//
+// W_AddFile
+//
+// Files with a .wad extension are wadlink files with multiple lumps,
+// other files are single lumps with the base filename for the lump name.
+//
+//==========================================================================
+
+void W_AddFile(const char *filename)
+{
+	wadinfo_t header;
+	lumpinfo_t *lump_p;
+	char path[MAX_OSPATH];
+	int handle, length, flength;
+	int startlump;
+	filelump_t *fileinfo, singleinfo;
+	filelump_t *freeFileInfo;
+	int	i, j;
+	byte	*c;
+
+	handle = -1;
+	/* try the directory from the command line or
+	 *  from the shared data environment variable.
+	 */
+	if (waddir && *waddir)
+	{
+		snprintf (path, sizeof(path), "%s/%s", waddir, filename);
+		handle = open(path, OREAD);
+	}
+#if !defined(_NO_USERDIRS)
+	if (handle == -1)	/* Try UserDIR */
+	{
+		snprintf (path, sizeof(path), "%s%s", basePath, filename);
+		handle = open(path, OREAD);
+	}
+#endif	/* !_NO_USERDIRS */
+	if (handle == -1)	/* Now try CWD */
+	{
+		handle = open(filename, OREAD);
+	}
+	if (handle == -1)
+		return;		/* Didn't find the file. */
+
+	flength = filelength(handle);
+	startlump = numlumps;
+	if (strcmp(filename + strlen(filename) - 3, "wad") != 0)
+	{ // Single lump file
+		fileinfo = &singleinfo;
+		freeFileInfo = NULL;
+		singleinfo.filepos = 0;
+		singleinfo.size = LONG(flength);
+		M_ExtractFileBase(filename, singleinfo.name);
+		numlumps++;
+	}
+	else
+	{ // WAD file
+		read(handle, &header, sizeof(header));
+		if (strncmp(header.identification, "IWAD", 4) != 0)
+		{
+			if (strncmp(header.identification, "PWAD", 4) != 0)
+			{ // Bad file id
+				I_Error("Wad file %s doesn't have IWAD or PWAD id\n", filename);
+			}
+		}
+		header.numlumps = LONG(header.numlumps);
+		header.infotableofs = LONG(header.infotableofs);
+		length = header.numlumps * sizeof(filelump_t);
+		if (strncmp(header.identification, "IWAD", 4) == 0 &&
+		    header.numlumps == PCDEMO_LUMPS && flength == PCDEMO_WADSIZE)
+		{
+			shareware = true;
+			ST_Message("Shareware WAD detected (4 level 1.0 PC version).\n");
+		}
+		else if (strncmp(header.identification, "IWAD", 4) == 0 &&
+			 header.numlumps == MACDEMO_LUMPS && flength == MACDEMO_WADSIZE)
+		{
+			shareware = true;
+			ST_Message("Shareware WAD detected (4 level 1.1 Mac version).\n");
+		}
+		else if (strncmp(header.identification, "IWAD", 4) == 0 &&
+			 header.numlumps == OLDDEMO_LUMPS && flength == OLDDEMO_WADSIZE)
+		{
+			shareware = true;
+			/* This old beta version is not supported: it is missing
+			 * at least the FONTAY_S, chess and orb lumps. Its demos
+			 * do not play correctly, either. Just reject it. */
+			I_Error("Beta Shareware WAD from 2 Oct. 1995 not supported.");
+		}
+		fileinfo = (filelump_t *) malloc(length);
+		if (!fileinfo)
+		{
+			I_Error("W_AddFile: fileinfo malloc failed\n");
+		}
+		freeFileInfo = fileinfo;
+		seek(handle, header.infotableofs, 0);
+		read(handle, fileinfo, length);
+		numlumps += header.numlumps;
+	}
+
+	// Fill in lumpinfo
+	lumpinfo = (lumpinfo_t *) realloc(lumpinfo, numlumps * sizeof(lumpinfo_t));
+	if (!lumpinfo)
+	{
+		I_Error("Couldn't realloc lumpinfo");
+	}
+	lump_p = &lumpinfo[startlump];
+	for (i = startlump; i < numlumps; i++, lump_p++, fileinfo++)
+	{
+		memset(lump_p->name, 0, 8);
+		lump_p->handle = handle;
+		lump_p->position = LONG(fileinfo->filepos);
+		lump_p->size = LONG(fileinfo->size);
+		strncpy(lump_p->name, fileinfo->name, 8);
+		/* In the Mac demo wad, many (1784) of the lump names
+		 * have their first character with the high bit (0x80)
+		 * set.  I don't know the reason for that..  We must
+		 * clear the high bits for such Mac wad files to work
+		 * in this engine. This shouldn't break other wads. */
+		c = (byte *)lump_p->name;
+		for (j = 0; j < 8; c++, j++)
+			*c &= 0x7f;
+	}
+	if (freeFileInfo)
+	{
+		free(freeFileInfo);
+	}
+}
+
+//==========================================================================
+//
+// W_InitMultipleFiles
+//
+// Pass a null terminated list of files to use.  All files are optional,
+// but at least one file must be found.  Lump names can appear multiple
+// times.  The name searcher looks backwards, so a later file can
+// override an earlier one.
+//
+//==========================================================================
+
+void W_InitMultipleFiles(const char **filenames)
+{
+	int size;
+
+	// Open all the files, load headers, and count lumps
+	numlumps = 0;
+	lumpinfo = (lumpinfo_t *) malloc(1); // Will be realloced as lumps are added
+
+	for ( ; *filenames; filenames++)
+	{
+		W_AddFile(*filenames);
+	}
+	if (!numlumps)
+	{
+		I_Error("W_InitMultipleFiles: no files found");
+	}
+
+	// Merge lumps for flats and sprites
+	W_MergeLumps("S_START","S_END");
+	W_MergeLumps("F_START","F_END");
+
+	// Set up caching
+	size = numlumps * sizeof(*lumpcache);
+	lumpcache = (void **) malloc(size);
+	if (!lumpcache)
+	{
+		I_Error("Couldn't allocate lumpcache");
+	}
+	memset(lumpcache, 0, size);
+
+	PrimaryLumpInfo = lumpinfo;
+	PrimaryLumpCache = lumpcache;
+	PrimaryNumLumps = numlumps;
+}
+
+//==========================================================================
+//
+// IsMarker
+//
+// From BOOM/xdoom.  Finds an S_START or SS_START marker
+//
+//==========================================================================
+
+static int IsMarker(const char *marker, const char *name)
+{
+	return !strncmp(name, marker, 8) ||
+		(*name == *marker && !strncmp(name + 1, marker, 7));
+}
+
+//==========================================================================
+//
+// W_MergeLumps
+//
+// From xdoom/BOOM again.  Merges all sprite lumps into one big 'ol block
+//
+//==========================================================================
+
+static void W_MergeLumps(const char *start, const char *end)
+{
+	lumpinfo_t *newlumpinfo;
+	int newlumps, oldlumps;
+	int in_block = 0;
+	int i;
+
+	oldlumps = newlumps = 0;
+	newlumpinfo = (lumpinfo_t *) malloc(numlumps * sizeof(lumpinfo_t));
+	if (!newlumpinfo)
+	{
+		I_Error("W_MergeLumps: newlumpinfo malloc failed");
+	}
+
+	for (i = 0; i < numlumps; i++)
+	{
+		//process lumps in global namespace
+		if (!in_block)
+		{
+			//check for start of block
+			if (IsMarker(start, lumpinfo[i].name))
+			{
+				in_block = 1;
+				if (!newlumps)
+				{
+					newlumps++;
+					memset(newlumpinfo[0].name, 0, 8);
+					strcpy(newlumpinfo[0].name, start);
+					newlumpinfo[0].handle = -1;
+					newlumpinfo[0].position = newlumpinfo[0].size = 0;
+				}
+			}
+			// else copy it
+			else
+			{
+				lumpinfo[oldlumps++] = lumpinfo[i];
+			}
+		}
+		// process lumps in sprites or flats namespace
+		else
+		{
+			// check for end of block
+			if (IsMarker(end, lumpinfo[i].name))
+			{
+				in_block = 0;
+			}
+			else if (i && lumpinfo[i].handle != lumpinfo[i-1].handle)
+			{
+				in_block = 0;
+				lumpinfo[oldlumps++] = lumpinfo[i];
+			}
+			else
+			{
+				newlumpinfo[newlumps++] = lumpinfo[i];
+			}
+		}
+	}
+
+	// now copy the merged lumps to the end of the old list
+	if (newlumps)
+	{
+		if (oldlumps + newlumps > numlumps)
+			lumpinfo = (lumpinfo_t *) realloc(lumpinfo, (oldlumps + newlumps) * sizeof(lumpinfo_t));
+		memcpy(lumpinfo + oldlumps, newlumpinfo, sizeof(lumpinfo_t) * newlumps);
+
+		numlumps = oldlumps + newlumps;
+
+		memset(lumpinfo[numlumps].name, 0, 8);
+		strcpy(lumpinfo[numlumps].name, end);
+		lumpinfo[numlumps].handle = -1;
+		lumpinfo[numlumps].position = lumpinfo[numlumps].size = 0;
+		numlumps++;
+	}
+	free (newlumpinfo);
+}
+
+//==========================================================================
+//
+// W_InitFile
+//
+// Initialize the primary from a single file.
+//
+//==========================================================================
+
+void W_InitFile(const char *filename)
+{
+	const char *names[2];
+
+	names[0] = filename;
+	names[1] = NULL;
+	W_InitMultipleFiles(names);
+}
+
+//==========================================================================
+//
+// W_OpenAuxiliary
+//
+//==========================================================================
+
+void W_OpenAuxiliary(const char *filename)
+{
+	int i;
+	int size;
+	wadinfo_t header;
+	int handle;
+	int length;
+	filelump_t *fileinfo;
+	filelump_t *sourceLump;
+	lumpinfo_t *destLump;
+
+	if (AuxiliaryOpened)
+	{
+		W_CloseAuxiliary();
+	}
+	if ((handle = open(filename, OREAD)) == -1)
+	{
+		I_Error("W_OpenAuxiliary: %s not found.", filename);
+		return;
+	}
+	AuxiliaryHandle = handle;
+	read(handle, &header, sizeof(header));
+	if (strncmp(header.identification, "IWAD", 4))
+	{
+		if (strncmp(header.identification, "PWAD", 4))
+		{ // Bad file id
+			I_Error("Wad file %s doesn't have IWAD or PWAD id\n",
+				filename);
+		}
+	}
+	header.numlumps = LONG(header.numlumps);
+	header.infotableofs = LONG(header.infotableofs);
+	length = header.numlumps*sizeof(filelump_t);
+	fileinfo = (filelump_t *) Z_Malloc(length, PU_STATIC, NULL);
+	seek(handle, header.infotableofs, 0);
+	read(handle, fileinfo, length);
+	numlumps = header.numlumps;
+
+	// Init the auxiliary lumpinfo array
+	lumpinfo = (lumpinfo_t *) Z_Malloc(numlumps*sizeof(lumpinfo_t), PU_STATIC, NULL);
+	sourceLump = fileinfo;
+	destLump = lumpinfo;
+	for (i = 0; i < numlumps; i++, destLump++, sourceLump++)
+	{
+		destLump->handle = handle;
+		destLump->position = LONG(sourceLump->filepos);
+		destLump->size = LONG(sourceLump->size);
+		strncpy(destLump->name, sourceLump->name, 8);
+	}
+	Z_Free(fileinfo);
+
+	// Allocate the auxiliary lumpcache array
+	size = numlumps*sizeof(*lumpcache);
+	lumpcache = (void **) Z_Malloc(size, PU_STATIC, NULL);
+	memset(lumpcache, 0, size);
+
+	AuxiliaryLumpInfo = lumpinfo;
+	AuxiliaryLumpCache = lumpcache;
+	AuxiliaryNumLumps = numlumps;
+	AuxiliaryOpened = true;
+}
+
+//==========================================================================
+//
+// W_CloseAuxiliary
+//
+//==========================================================================
+
+void W_CloseAuxiliary(void)
+{
+	int i;
+
+	if (AuxiliaryOpened)
+	{
+		W_UseAuxiliary();
+		for (i = 0; i < numlumps; i++)
+		{
+			if (lumpcache[i])
+			{
+				Z_Free(lumpcache[i]);
+			}
+		}
+		Z_Free(AuxiliaryLumpInfo);
+		Z_Free(AuxiliaryLumpCache);
+		W_CloseAuxiliaryFile();
+		AuxiliaryOpened = false;
+	}
+	W_UsePrimary();
+}
+
+//==========================================================================
+//
+// W_CloseAuxiliaryFile
+//
+// WARNING: W_CloseAuxiliary() must be called before any further
+// auxiliary lump processing.
+//
+//==========================================================================
+
+void W_CloseAuxiliaryFile(void)
+{
+	if (AuxiliaryHandle)
+	{
+		close(AuxiliaryHandle);
+		AuxiliaryHandle = 0;
+	}
+}
+
+//==========================================================================
+//
+// W_UsePrimary
+//
+//==========================================================================
+
+void W_UsePrimary(void)
+{
+	lumpinfo = PrimaryLumpInfo;
+	numlumps = PrimaryNumLumps;
+	lumpcache = PrimaryLumpCache;
+}
+
+//==========================================================================
+//
+// W_UseAuxiliary
+//
+//==========================================================================
+
+void W_UseAuxiliary(void)
+{
+	if (AuxiliaryOpened == false)
+	{
+		I_Error("W_UseAuxiliary: WAD not opened.");
+	}
+	lumpinfo = AuxiliaryLumpInfo;
+	numlumps = AuxiliaryNumLumps;
+	lumpcache = AuxiliaryLumpCache;
+}
+
+//==========================================================================
+//
+// W_NumLumps
+//
+//==========================================================================
+
+int	W_NumLumps(void)
+{
+	return numlumps;
+}
+
+//==========================================================================
+//
+// W_CheckNumForName
+//
+// Returns -1 if name not found.
+//
+//==========================================================================
+
+int W_CheckNumForName(const char *name)
+{
+	char name8[9];
+	lumpinfo_t *lump_p;
+
+	// Make the name into two integers for easy compares
+	memset(name8, 0, sizeof(name8));
+	strncpy(name8, name, 8);
+	strupr(name8); // case insensitive
+
+	// Scan backwards so patch lump files take precedence
+	lump_p = lumpinfo + numlumps;
+	while (lump_p-- != lumpinfo)
+	{
+		if (memcmp(lump_p->name, name8, 8) == 0)
+		{
+			return (int)(lump_p - lumpinfo);
+		}
+	}
+	return -1;
+}
+
+//==========================================================================
+//
+// W_GetNumForName
+//
+// Calls W_CheckNumForName, but bombs out if not found.
+//
+//==========================================================================
+
+int	W_GetNumForName (const char *name)
+{
+	int	i;
+
+	i = W_CheckNumForName(name);
+	if (i != -1)
+	{
+		return i;
+	}
+	I_Error("W_GetNumForName: %s not found!", name);
+	return -1;
+}
+
+//==========================================================================
+//
+// W_LumpLength
+//
+// Returns the buffer size needed to load the given lump.
+//
+//==========================================================================
+
+int W_LumpLength(int lump)
+{
+	if (lump >= numlumps)
+	{
+		I_Error("W_LumpLength: %i >= numlumps", lump);
+	}
+	return lumpinfo[lump].size;
+}
+
+//==========================================================================
+//
+// W_ReadLump
+//
+// Loads the lump into the given buffer, which must be >= W_LumpLength().
+//
+//==========================================================================
+
+void W_ReadLump(int lump, void *dest)
+{
+	int c;
+	lumpinfo_t *l;
+
+	if (lump >= numlumps)
+	{
+		I_Error("W_ReadLump: %i >= numlumps", lump);
+	}
+	l = lumpinfo+lump;
+	//I_BeginRead();
+	lseek(l->handle, l->position, SEEK_SET);
+	c = read(l->handle, dest, l->size);
+	if (c < l->size)
+	{
+		I_Error("W_ReadLump: only read %i of %i on lump %i",
+			c, l->size, lump);
+	}
+	//I_EndRead();
+}
+
+//==========================================================================
+//
+// W_CacheLumpNum
+//
+//==========================================================================
+
+void *W_CacheLumpNum(int lump, int tag)
+{
+	if ((unsigned)lump >= numlumps)
+	{
+		I_Error("W_CacheLumpNum: %i >= numlumps", lump);
+	}
+	if (!lumpcache[lump])
+	{ // Need to read the lump in
+		Z_Malloc(W_LumpLength(lump), tag, &lumpcache[lump]);
+		W_ReadLump(lump, lumpcache[lump]);
+	}
+	else
+	{
+		Z_ChangeTag(lumpcache[lump], tag);
+	}
+	return lumpcache[lump];
+}
+
+//==========================================================================
+//
+// W_CacheLumpName
+//
+//==========================================================================
+
+void *W_CacheLumpName(const char *name, int tag)
+{
+	return W_CacheLumpNum(W_GetNumForName(name), tag);
+}
+
+void W_CheckWADFiles (void)
+{
+	char	lumpmsg[10];
+	int		i;
+
+	if (W_CheckNumForName("PRSGCRED") != -1)
+		mac_hexen = true;	/* credits page lump for Mac port by Presage is present. */
+
+	strcpy (lumpmsg, "CLUS1MSG");
+	for (i = 1; i <= 4 && oldwad_10 != true; i++)
+	{
+		lumpmsg[4] = '0' + i;
+		if (W_CheckNumForName(lumpmsg) == -1)
+			oldwad_10 = true;
+	}
+
+	strcpy (lumpmsg, "WIN1MSG");
+	for (i = 1; i <= 3 && oldwad_10 != true; i++)
+	{
+		lumpmsg[3] = '0' + i;
+		if (W_CheckNumForName(lumpmsg) == -1)
+			oldwad_10 = true;
+	}
+
+#if 0
+	if (shareware)
+	{
+		ST_Message ("\n========================================================================\n");
+		ST_Message ("                      Hexen:  Beyond Heretic\n\n");
+		ST_Message ("                       4 Level Demo Version\n");
+		ST_Message ("                    Press any key to continue.\n");
+		ST_Message ("========================================================================\n\n");
+		getchar();
+	}
+#endif
+
+#if defined(DEMO_VERSION)
+	if (shareware != true)
+		I_Error ("\nShareware WAD not detected.\nThis exe is configured only for the DEMO version of Hexen!\n");
+#endif	/* Shareware-only */
+
+#if defined(VERSION10_WAD)
+	if (oldwad_10 != true)
+		I_Error ("\nThis exe is configured only for Hexen 1.0 (4-player-only) wad files!\n");
+	ST_Message ("Running with 4-player-only Version 1.0 hexen.wad files.\n");
+#else
+	if (oldwad_10 == true)
+	{
+		ST_Message ("\nIt appears that you are using a 4-player-only Version 1.0 hexen.wad.\n");
+		ST_Message ("Running HHexen without a Version 1.1 wadfile can cause many problems.\n");
+		ST_Message ("\nPress <ENTER> to continue.\n");
+		getchar();
+	}
+#endif
+}
+
+//==========================================================================
+//
+// W_Profile
+//
+//==========================================================================
+
+// Ripped out for Heretic
+/*
+static int	info[2500][10];
+static int	profilecount;
+
+void W_Profile (void)
+{
+	int		i;
+	memblock_t	*block;
+	void	*ptr;
+	char	ch;
+	FILE	*f;
+	int		j;
+	char	name[9];
+
+	for (i = 0; i < numlumps; i++)
+	{
+		ptr = lumpcache[i];
+		if (!ptr)
+		{
+			ch = ' ';
+			continue;
+		}
+		else
+		{
+			block = (memblock_t *) ( (byte *)ptr - sizeof(memblock_t));
+			if (block->tag < PU_PURGELEVEL)
+				ch = 'S';
+			else
+				ch = 'P';
+		}
+		info[i][profilecount] = ch;
+	}
+	profilecount++;
+
+	f = fopen ("waddump.txt","w");
+	name[8] = 0;
+	for (i = 0; i < numlumps; i++)
+	{
+		memcpy (name, lumpinfo[i].name, 8);
+		for (j = 0; j < 8; j++)
+			if (!name[j])
+				break;
+		for ( ; j < 8; j++)
+			name[j] = ' ';
+		fprintf (f,"%s ",name);
+		for (j = 0; j < profilecount; j++)
+			fprintf (f,"    %c",info[i][j]);
+		fprintf (f,"\n");
+	}
+	fclose (f);
+}
+*/
+
--- /dev/null
+++ b/xddefs.h
@@ -1,0 +1,216 @@
+
+//**************************************************************************
+//**
+//** xddefs.h : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 543 $
+//** $Date: 2010-01-11 20:44:55 +0200 (Mon, 11 Jan 2010) $
+//**
+//**************************************************************************
+
+#ifndef __XDDEFS__
+#define __XDDEFS__
+
+#include "h2stdinc.h"
+#include "h2def.h"
+
+/* ---- Map level types ---- */
+
+/* lump order in a map wad */
+enum
+{
+	ML_LABEL,
+	ML_THINGS,
+	ML_LINEDEFS,
+	ML_SIDEDEFS,
+	ML_VERTEXES,
+	ML_SEGS,
+	ML_SSECTORS,
+	ML_NODES,
+	ML_SECTORS,
+	ML_REJECT,
+	ML_BLOCKMAP,
+	ML_BEHAVIOR
+};
+
+typedef struct
+{
+	short		x;
+	short		y;
+} mapvertex_t;
+
+#pragma pack on
+
+typedef struct
+{
+	short		textureoffset;
+	short		rowoffset;
+	char		toptexture[8];
+	char		bottomtexture[8];
+	char		midtexture[8];
+	short		sector;	/* on viewer's side */
+} mapsidedef_t;
+
+#pragma pack off
+
+typedef struct
+{
+	short		v1;
+	short		v2;
+	short		flags;
+	byte		special;
+	byte		arg1;
+	byte		arg2;
+	byte		arg3;
+	byte		arg4;
+	byte		arg5;
+	short		sidenum[2];	/* sidenum[1] will be -1 if one sided */
+} maplinedef_t;
+
+#define	ML_BLOCKING		0x0001
+#define	ML_BLOCKMONSTERS	0x0002
+#define	ML_TWOSIDED		0x0004
+#define	ML_DONTPEGTOP		0x0008
+#define	ML_DONTPEGBOTTOM	0x0010
+#define ML_SECRET		0x0020	/* don't map as two sided: IT'S A SECRET! */
+#define ML_SOUNDBLOCK		0x0040	/* don't let sound cross two of these */
+#define	ML_DONTDRAW		0x0080	/* don't draw on the automap */
+#define	ML_MAPPED		0x0100	/* set if already drawn in automap */
+#define ML_REPEAT_SPECIAL	0x0200	/* special is repeatable */
+#define ML_SPAC_SHIFT		10
+#define ML_SPAC_MASK		0x1c00
+#define GET_SPAC(flags)		(((flags) & ML_SPAC_MASK) >> ML_SPAC_SHIFT)
+
+/* Special activation types */
+#define SPAC_CROSS		0	/* when player crosses line */
+#define SPAC_USE		1	/* when player uses line */
+#define SPAC_MCROSS		2	/* when monster crosses line */
+#define SPAC_IMPACT		3	/* when projectile hits line */
+#define SPAC_PUSH		4	/* when player/monster pushes line */
+#define SPAC_PCROSS		5	/* when projectile crosses line */
+
+typedef	struct
+{
+	short		floorheight;
+	short		ceilingheight;
+	char		floorpic[8];
+	char		ceilingpic[8];
+	short		lightlevel;
+	short		special;
+	short		tag;
+} __attribute__((__packed__)) mapsector_t;
+
+typedef struct
+{
+	short		numsegs;
+	short		firstseg;	/* segs are stored sequentially */
+} mapsubsector_t;
+
+typedef struct
+{
+	short		v1;
+	short		v2;
+	short		angle;
+	short		linedef;
+	short		side;
+	short		offset;
+} mapseg_t;
+
+/* bbox coordinates */
+enum
+{
+	BOXTOP,
+	BOXBOTTOM,
+	BOXLEFT,
+	BOXRIGHT
+};
+
+#define	NF_SUBSECTOR	0x8000
+typedef struct
+{
+	short		x, y, dx, dy;	/* partition line */
+	short		bbox[2][4];	/* bounding box for each child */
+	unsigned short	children[2];	/* if NF_SUBSECTOR its a subsector */
+} mapnode_t;
+
+typedef struct
+{
+	short		tid;
+	short		x;
+	short		y;
+	short		height;
+	short		angle;
+	short		type;
+	short		options;
+	byte		special;
+	byte		arg1;
+	byte		arg2;
+	byte		arg3;
+	byte		arg4;
+	byte		arg5;
+} mapthing_t;
+
+#define MTF_EASY		1
+#define MTF_NORMAL		2
+#define MTF_HARD		4
+#define MTF_AMBUSH		8
+#define MTF_DORMANT		16
+#define MTF_FIGHTER		32
+#define MTF_CLERIC		64
+#define MTF_MAGE		128
+#define MTF_GSINGLE		256
+#define MTF_GCOOP		512
+#define MTF_GDEATHMATCH		1024
+
+
+/* ---- Texture definition ---- */
+
+typedef struct
+{
+	short		originx;
+	short		originy;
+	short		patch;
+	short		stepdir;
+	short		colormap;
+} __attribute__((__packed__)) mappatch_t;
+
+typedef struct
+{
+	char		name[8];
+	boolean		masked;	
+	short		width;
+	short		height;
+	int32_t		columndirectory;	/* OBSOLETE */
+	short		patchcount;
+	mappatch_t	patches[1];
+} __attribute__((__packed__)) maptexture_t;
+
+
+/* ---- Graphics ---- */
+
+/* posts are runs of non masked source pixels */
+typedef struct
+{
+	byte		topdelta;	/* -1 is the last post in a column */
+	byte		length;
+	/* length data bytes follows */
+} __attribute__((__packed__)) post_t;
+
+/* column_t is a list of 0 or more post_t, (byte)-1 terminated */
+typedef post_t	column_t;
+
+/* a patch holds one or more columns
+ * patches are used for sprites and all masked pictures
+ */
+typedef struct
+{
+	short		width;			/* bounding box size */
+	short		height;
+	short		leftoffset;		/* pixels to the left of origin */
+	short		topoffset;		/* pixels below the origin */
+	int		columnofs[8];		/* only [width] used */
+							/* the [0] is &columnofs[width] */
+} patch_t;
+
+#endif	/* __XDDEFS__ */
+
--- /dev/null
+++ b/z_zone.c
@@ -1,0 +1,393 @@
+
+//**************************************************************************
+//**
+//** z_zone.c : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 491 $
+//** $Date: 2009-05-30 01:10:42 +0300 (Sat, 30 May 2009) $
+//**
+//**************************************************************************
+
+#include "h2stdinc.h"
+#include "h2def.h"
+
+/*
+==============================================================================
+
+						ZONE MEMORY ALLOCATION
+
+There is never any space between memblocks, and there will never be two
+contiguous free memblocks.
+
+The rover can be left pointing at a non-empty block
+
+It is of no value to free a cachable block, because it will get overwritten
+automatically if needed
+
+==============================================================================
+*/
+
+
+typedef struct
+{
+	int		size;		// total bytes malloced, including header
+	memblock_t	blocklist;		// start / end cap for linked list
+	memblock_t	*rover;
+} memzone_t;
+
+static memzone_t	*mainzone;
+
+/*
+========================
+=
+= Z_ClearZone
+=
+========================
+*/
+
+/*
+void Z_ClearZone (memzone_t *zone)
+{
+	memblock_t	*block;
+
+// set the entire zone to one free block
+
+	zone->blocklist.next = zone->blocklist.prev = block =
+		(memblock_t *)( (byte *)zone + sizeof(memzone_t) );
+	zone->blocklist.user = (void **)zone;
+	zone->blocklist.tag = PU_STATIC;
+	zone->rover = block;
+
+	block->prev = block->next = &zone->blocklist;
+	block->user = NULL;	// free block
+	block->size = zone->size - sizeof(memzone_t);
+}
+*/
+
+
+/*
+========================
+=
+= Z_Init
+=
+========================
+*/
+
+void Z_Init (void)
+{
+	memblock_t	*block;
+	int		size;
+
+	mainzone = (memzone_t *)I_ZoneBase (&size);
+	mainzone->size = size;
+
+// set the entire zone to one free block
+
+	mainzone->blocklist.next = mainzone->blocklist.prev = block =
+		(memblock_t *)( (byte *)mainzone + sizeof(memzone_t) );
+	mainzone->blocklist.user = (void **)mainzone;
+	mainzone->blocklist.tag = PU_STATIC;
+	mainzone->rover = block;
+
+	block->prev = block->next = &mainzone->blocklist;
+	block->user = NULL;	// free block
+	block->size = mainzone->size - sizeof(memzone_t);
+}
+
+
+/*
+========================
+=
+= Z_Free
+=
+========================
+*/
+
+void Z_Free (void *ptr)
+{
+	memblock_t	*block, *other;
+
+	block = (memblock_t *) ( (byte *)ptr - sizeof(memblock_t));
+	if (block->id != ZONEID)
+		I_Error ("Z_Free: freed a pointer without ZONEID");
+
+	if (block->user > (void **)0x100)	// smaller values are not pointers
+		*block->user = 0;		// clear the user's mark
+	block->user = NULL;	// mark as free
+	block->tag = 0;
+	block->id = 0;
+
+	other = block->prev;
+	if (!other->user)
+	{	// merge with previous free block
+		other->size += block->size;
+		other->next = block->next;
+		other->next->prev = other;
+		if (block == mainzone->rover)
+			mainzone->rover = other;
+		block = other;
+	}
+
+	other = block->next;
+	if (!other->user)
+	{	// merge the next free block onto the end
+		block->size += other->size;
+		block->next = other->next;
+		block->next->prev = block;
+		if (other == mainzone->rover)
+			mainzone->rover = block;
+	}
+}
+
+
+/*
+========================
+=
+= Z_Malloc
+=
+= You can pass a NULL user if the tag is < PU_PURGELEVEL
+========================
+*/
+
+#define MINFRAGMENT	64
+
+void *Z_Malloc (int size, int tag, void *user)
+{
+	int		extra;
+	memblock_t	*start, *rover, *newblock, *base;
+
+//
+// scan through the block list looking for the first free block
+// of sufficient size, throwing out any purgable blocks along the way
+//
+	size += sizeof(memblock_t);	// account for size of block header
+	size = (size + 7) & ~7;		// align to 8-byte boundary
+
+//
+// if there is a free block behind the rover, back up over them
+//
+	base = mainzone->rover;
+	if (!base->prev->user)
+		base = base->prev;
+
+	rover = base;
+	start = base->prev;
+
+	do
+	{
+		if (rover == start)	// scaned all the way around the list
+			I_Error ("Z_Malloc: failed on allocation of %i bytes", size);
+		if (rover->user)
+		{
+			if (rover->tag < PU_PURGELEVEL)
+			// hit a block that can't be purged, so move base past it
+				base = rover = rover->next;
+			else
+			{
+			// free the rover block (adding the size to base)
+				base = base->prev;	// the rover can be the base block
+				Z_Free ((byte *)rover + sizeof(memblock_t));
+				base = base->next;
+				rover = base->next;
+			}
+		}
+		else
+			rover = rover->next;
+	} while (base->user || base->size < size);
+
+//
+// found a block big enough
+//
+	extra = base->size - size;
+	if (extra >  MINFRAGMENT)
+	{	// there will be a free fragment after the allocated block
+		newblock = (memblock_t *) ((byte *)base + size);
+		newblock->size = extra;
+		newblock->user = NULL;		// free block
+		newblock->tag = 0;
+		newblock->prev = base;
+		newblock->next = base->next;
+		newblock->next->prev = newblock;
+		base->next = newblock;
+		base->size = size;
+	}
+
+	if (user)
+	{
+		base->user = (void **)user;	// mark as an in use block
+		*(void **)user = (void *) ((byte *)base + sizeof(memblock_t));
+	}
+	else
+	{
+		if (tag >= PU_PURGELEVEL)
+			I_Error ("Z_Malloc: an owner is required for purgable blocks");
+		base->user = (void **) 2;	// mark as in use, but unowned
+	}
+	base->tag = tag;
+
+	mainzone->rover = base->next;	// next allocation will start looking here
+
+	base->id = ZONEID;
+	return (void *) ((byte *)base + sizeof(memblock_t));
+}
+
+
+/*
+========================
+=
+= Z_FreeTags
+=
+========================
+*/
+
+void Z_FreeTags (int lowtag, int hightag)
+{
+	memblock_t	*block, *next;
+
+	for (block = mainzone->blocklist.next ; block != &mainzone->blocklist; block = next)
+	{
+		next = block->next;		// get link before freeing
+		if (!block->user)
+			continue;		// free block
+		if (block->tag >= lowtag && block->tag <= hightag)
+			Z_Free ( (byte *)block+sizeof(memblock_t));
+	}
+}
+
+/*
+========================
+=
+= Z_DumpHeap
+=
+========================
+*/
+
+/*
+void Z_DumpHeap (int lowtag, int hightag)
+{
+	memblock_t	*block;
+
+	printf ("zone size: %i  location: %p\n", mainzone->size,mainzone);
+	printf ("tag range: %i to %i\n", lowtag, hightag);
+
+	for (block = mainzone->blocklist.next ; ; block = block->next)
+	{
+		if (block->tag >= lowtag && block->tag <= hightag)
+			printf ("block:%p    size:%7i    user:%p    tag:%3i\n",
+				block, block->size, block->user, block->tag);
+
+		if (block->next == &mainzone->blocklist)
+			break;			// all blocks have been hit
+		if ( (byte *)block + block->size != (byte *)block->next)
+			printf ("ERROR: block size does not touch the next block\n");
+		if ( block->next->prev != block)
+			printf ("ERROR: next block doesn't have proper back link\n");
+		if (!block->user && !block->next->user)
+			printf ("ERROR: two consecutive free blocks\n");
+	}
+}
+*/
+
+/*
+========================
+=
+= Z_FileDumpHeap
+=
+========================
+*/
+
+/*
+void Z_FileDumpHeap (FILE *f)
+{
+	memblock_t	*block;
+
+	fprintf (f, "zone size: %i  location: %p\n", mainzone->size, mainzone);
+
+	for (block = mainzone->blocklist.next ; ; block = block->next)
+	{
+		fprintf (f, "block:%p    size:%7i    user:%p    tag:%3i\n",
+			 block, block->size, block->user, block->tag);
+
+		if (block->next == &mainzone->blocklist)
+			break;			// all blocks have been hit
+		if ( (byte *)block + block->size != (byte *)block->next)
+			fprintf (f, "ERROR: block size does not touch the next block\n");
+		if ( block->next->prev != block)
+			fprintf (f, "ERROR: next block doesn't have proper back link\n");
+		if (!block->user && !block->next->user)
+			fprintf (f, "ERROR: two consecutive free blocks\n");
+	}
+}
+*/
+
+/*
+========================
+=
+= Z_CheckHeap
+=
+========================
+*/
+
+void Z_CheckHeap (void)
+{
+	memblock_t	*block;
+
+	for (block = mainzone->blocklist.next ; ; block = block->next)
+	{
+		if (block->next == &mainzone->blocklist)
+			break;			// all blocks have been hit
+		if ( (byte *)block + block->size != (byte *)block->next)
+			I_Error ("Z_CheckHeap: block size does not touch the next block\n");
+		if ( block->next->prev != block)
+			I_Error ("Z_CheckHeap: next block doesn't have proper back link\n");
+		if (!block->user && !block->next->user)
+			I_Error ("Z_CheckHeap: two consecutive free blocks\n");
+	}
+}
+
+
+/*
+========================
+=
+= Z_ChangeTag
+=
+========================
+*/
+
+void Z_ChangeTag2 (void *ptr, int tag)
+{
+	memblock_t	*block;
+
+	block = (memblock_t *) ( (byte *)ptr - sizeof(memblock_t));
+	if (block->id != ZONEID)
+		I_Error ("Z_ChangeTag: freed a pointer without ZONEID");
+	if (tag >= PU_PURGELEVEL && (uintptr_t)block->user < 0x100)
+		I_Error ("Z_ChangeTag: an owner is required for purgable blocks");
+	block->tag = tag;
+}
+
+
+/*
+========================
+=
+= Z_FreeMemory
+=
+========================
+*/
+
+/*
+int Z_FreeMemory (void)
+{
+	memblock_t	*block;
+	int		freemem;
+
+	freemem = 0;
+	for (block = mainzone->blocklist.next ; block != &mainzone->blocklist; block = block->next)
+	{
+		if (!block->user || block->tag >= PU_PURGELEVEL)
+			freemem += block->size;
+	}
+	return freemem;
+}
+*/
+