// 3D_GAME.C

#include "3D_DEF.H"
#pragma hdrstop

#ifdef MYPROFILE
#include <TIME.H>
#endif

/*
=============================================================================

						 LOCAL CONSTANTS

=============================================================================
*/

#define LOCATION_TEXT_COLOR 0xAF
extern char far prep_msg[];
extern char LS_current,LS_total;
void Died (void);

/*
=============================================================================

						 GLOBAL VARIABLES

=============================================================================
*/

#if IN_DEVELOPMENT
int db_count=0;
#ifdef DEBUG_STATICS
classtype far debug_bonus[2][800];
#endif
#endif

fargametype far gamestuff;
gametype gamestate;
boolean		ingame,fizzlein;
unsigned	latchpics[NUMLATCHPICS];
eaWallInfo eaList[MAXEAWALLS];
char NumEAWalls;

tilecoord_t far GoldieList[GOLDIE_MAX_SPAWNS];	 
GoldsternInfo_t GoldsternInfo;

extern unsigned scan_value;


//
// ELEVATOR BACK MAPS - REMEMBER (-1)!!
//
// int ElevatorBackTo[]={1,1,7,3,5,3};

void ScanInfoPlane (void);
void SetupGameLevel (void);
void DrawPlayScreen (boolean InitInfoMsg);
void LoadLatchMem (void);
void GameLoop (void);

/*
=============================================================================

						 LOCAL VARIABLES

=============================================================================
*/



//
// NOTE: This array indexs the "statinfo" array in ACT1.C and is indexed
//		   upon tile number/values.
//

char far ExpCrateShapes[] =	 
{
	42,			// Chicken Leg
	44,			// Ham/Steak
	26,			// Clip
	24,			// Pistol
	27,			// Pulse
	28,			// ION
   46,			// Grenade
   62,			// Money Bag
   63,			// Loot
   64,			// Gold
   65,			// Bonus
   71,			// Gore 1
   74,			// Gore 2
	32,			// red key
	33,			// yel key
   52-23,		// grn key
   35,			// blu key
   488-375,		// gld key
};





//===========================================================================
//===========================================================================


/*
==========================
=
= SetSoundLoc - Given the location of an object (in terms of global
=	coordinates, held in globalsoundx and globalsoundy), munges the values
=	for an approximate distance from the left and right ear, and puts
=	those values into leftchannel and rightchannel.
=
= JAB
=
==========================
*/

	fixed	globalsoundx,globalsoundy;
	int		leftchannel,rightchannel;
#define ATABLEMAX 15
byte righttable[ATABLEMAX][ATABLEMAX * 2] = {
{ 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 6, 0, 0, 0, 0, 0, 1, 3, 5, 8, 8, 8, 8, 8, 8, 8, 8},
{ 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 6, 4, 0, 0, 0, 0, 0, 2, 4, 6, 8, 8, 8, 8, 8, 8, 8, 8},
{ 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 6, 6, 4, 1, 0, 0, 0, 1, 2, 4, 6, 8, 8, 8, 8, 8, 8, 8, 8},
{ 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 6, 5, 4, 2, 1, 0, 1, 2, 3, 5, 7, 8, 8, 8, 8, 8, 8, 8, 8},
{ 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 6, 5, 4, 3, 2, 2, 3, 3, 5, 6, 8, 8, 8, 8, 8, 8, 8, 8, 8},
{ 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 6, 6, 5, 4, 4, 4, 4, 5, 6, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8},
{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 6, 6, 5, 5, 5, 6, 6, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 6, 6, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8}
};
byte lefttable[ATABLEMAX][ATABLEMAX * 2] = {
{ 8, 8, 8, 8, 8, 8, 8, 8, 5, 3, 1, 0, 0, 0, 0, 0, 6, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8},
{ 8, 8, 8, 8, 8, 8, 8, 8, 6, 4, 2, 0, 0, 0, 0, 0, 4, 6, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8},
{ 8, 8, 8, 8, 8, 8, 8, 8, 6, 4, 2, 1, 0, 0, 0, 1, 4, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8},
{ 8, 8, 8, 8, 8, 8, 8, 8, 7, 5, 3, 2, 1, 0, 1, 2, 4, 5, 6, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8},
{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 6, 5, 3, 3, 2, 2, 3, 4, 5, 6, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8},
{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 6, 5, 4, 4, 4, 4, 5, 6, 6, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8},
{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 6, 6, 5, 5, 5, 6, 6, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8},
{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 6, 6, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8}
};

void
SetSoundLoc(fixed gx,fixed gy)
{
	fixed	xt,yt;
	int		x,y;

//
// translate point to view centered coordinates
//
	gx -= viewx;
	gy -= viewy;

//
// calculate newx
//
	xt = FixedByFrac(gx,viewcos);
	yt = FixedByFrac(gy,viewsin);
	x = (xt - yt) >> TILESHIFT;

//
// calculate newy
//
	xt = FixedByFrac(gx,viewsin);
	yt = FixedByFrac(gy,viewcos);
	y = (yt + xt) >> TILESHIFT;

	if (y >= ATABLEMAX)
		y = ATABLEMAX - 1;
	else if (y <= -ATABLEMAX)
		y = -ATABLEMAX;
	if (x < 0)
		x = -x;
	if (x >= ATABLEMAX)
		x = ATABLEMAX - 1;
	leftchannel  =  lefttable[x][y + ATABLEMAX];
	rightchannel = righttable[x][y + ATABLEMAX];

#if 0
	CenterWindow(8,1);
	US_PrintSigned(leftchannel);
	US_Print(",");
	US_PrintSigned(rightchannel);
	VW_UpdateScreen();
#endif
}

/*
==========================
=
= SetSoundLocGlobal - Sets up globalsoundx & globalsoundy and then calls
=	UpdateSoundLoc() to transform that into relative channel volumes. Those
=	values are then passed to the Sound Manager so that they'll be used for
=	the next sound played (if possible).
=
= JAB
=
==========================
*/
void PlaySoundLocGlobal(word s,fixed gx,fixed gy)
{
	SetSoundLoc(gx,gy);
	SD_PositionSound(leftchannel,rightchannel);
	if (SD_PlaySound(s))
	{
		globalsoundx = gx;
		globalsoundy = gy;
	}
}

void UpdateSoundLoc(void)
{
	if (SoundPositioned)
	{
		SetSoundLoc(globalsoundx,globalsoundy);
		SD_SetPosition(leftchannel,rightchannel);
	}
}

/*
**	JAB End
*/


/*
==========================
=
= ClearMemory
=
==========================
*/

void ClearMemory (void)
{
	PM_UnlockMainMem();
	SD_StopDigitized();
	MM_SortMem ();
}

#if 0

//-------------------------------------------------------------------------
// FreeAllMemory() - This is an attempt to FREE All possible memory
//							for memory hungry routines (ie. MOVIE_Play())
//
// NOTE: If any sounds, music, etc are currently playing, they will
//			adbruply cut off.
//-------------------------------------------------------------------------
void FreeAllMemory(void)
{
	StopMusic();
	SD_StopSound();
	ClearMemory();
}

#endif

#ifdef TRACK_ENEMY_COUNT
short numEnemy[gold_morphingobj];
#endif

/*
==========================
=
= ScanInfoPlane
=
= Spawn all actors and mark down special places
=
==========================
*/

#define INVALID_ACTOR_ERR Quit("Invalid actor: %d %d",x,y)

void ScanInfoPlane (void)
{
	unsigned	x,y,i,j;
	int			tile;
	unsigned	far	*start, far *floor;

#if 0 // FS: Compiler warning
	boolean gotlight = false;
#endif
	boolean gottextures = false;

#ifdef CEILING_FLOOR_COLORS
	boolean gotcolors=false;
#endif

#if IN_DEVELOPMENT
	db_count=0;
#endif
	detonators_spawned = 0;

#ifdef TRACK_ENEMY_COUNT
memset(numEnemy,0,sizeof(numEnemy));
#endif

	new=NULL;
	start = mapsegs[1];
	for (y=0;y<mapheight;y++)
		for (x=0;x<mapwidth;x++)
		{
			sci_mCacheInfo *ci;
			scientist_t *st;
			unsigned char tilehi,tilelo,block;


         tile = *start++;
         //
         // Check for tiles/icons to ignore...
         //
         switch ((unsigned)*(mapsegs[0]+farmapylookup[y]+x))
         {
         	case DOORTRIGGERTILE:
				case SMART_OFF_TRIGGER:
				case SMART_ON_TRIGGER:
            	// Ignore all values/icons on top of these tiles...
           	continue;
         }
			tilehi = (tile&0xff00)>>8;
			tilelo = (tile&0xff);

			if ((*start & 0xff00) == 0xfa00)
				scan_value = *start & 0x00ff;
			else
				scan_value = 0xffff;

#pragma warn -rch
			switch (tilehi)
			{


//				case 0xff:											// Special background
//					continue;
//				break;

#ifdef CEILING_FLOOR_COLORS
				case 0xfe:								// Top/Bottom colors
					if (gotcolors)
						break;
					x++;
					tile = *start++;
					TopColor = tile&0xff00;
					TopColor |= TopColor>>8;
					BottomColor = tile&0xff;
					BottomColor |= BottomColor<<8;
					gotcolors=true;
					continue;
				break;
#else
				case 0xfe:								// Top/Bottom colors
					x++;
					tile = *start++;
               // Give error
					continue;
				break;
#endif


				case 0xFB:								// Global Ceiling/Floor textures
					if (gottextures)
						break;
					x++;
					tile = *start++;

					CeilingTile = START_TEXTURES+((tile&0xff00)>>8);
					if (CeilingTile > NUM_TILES-1)
						GAME_ERROR(CEILING_TILE_OUT_OF_RANGE);

					FloorTile = START_TEXTURES+(tile&0xff);
               if (FloorTile > NUM_TILES-1)
						GAME_ERROR(FLOOR_TILE_OUT_OF_RANGE);

					gottextures = true;
					continue;
				break;


				case 0xf5:									// IntraLevel warp
					*(start-1) = *start;					// Move Coord right on top
					*start = 0;
					continue;
				break;

#if 0
				case 0xF6:									// Lighting effects
					if (gotlight)
						break;
					x++;
					tile = *start++;
					normalshade_div = (tile&0xff00)>>8 ;
					if (normalshade_div > 12)
						AGENT_ERROR(NORMAL_SHADE_TOO_BIG);

					shade_max = tile&0xff;
					if (shade_max > 63 || shade_max < 5)
						AGENT_ERROR(SHADEMAX_VALUE_BAD);

					normalshade=(3*(maxscale>>2))/normalshade_div;
					gotlight = true;
					continue;
				break;
#endif

				case 0xfa:
					continue;

				case 0xf1:		// Informant messages
				case 0xf2:		// "Nice" scientist messages
				case 0xf3:		// "Mean" scientist messages
					switch (tilehi)
					{
						case 0xf1:
							block=INFORMANT_HINTS;
							st=&InfHintList;
						break;

						case 0xf2:
							block=NICE_SCIE_HINTS;
							st=&NiceSciList;
						break;

						case 0xf3:
							block=MEAN_SCIE_HINTS;
							st=&MeanSciList;
						break;
					}

					ci = &st->smInfo[st->NumMsgs];
					ci->mInfo.local_val = 0xff;
					ci->mInfo.global_val = tilelo;
					if (!ReuseMsg((mCacheInfo *)ci,st->NumMsgs,sizeof(sci_mCacheInfo)))
					{
						CacheMsg((mCacheInfo *)ci,block,ci->mInfo.global_val);
						ci->mInfo.local_val = InfHintList.NumMsgs;
					}

					if (++st->NumMsgs > MAX_CACHE_MSGS)
						GAME_ERROR(SCANINFO_CACHE_MSG_OVERFLOW);

					ci->areanumber=GetAreaNumber(x,y);

					if (ci->areanumber >= NUMAREAS)
						ci->areanumber = 0xff;
					continue;
				break;

				case 0:
					if (!tilelo)
						continue;
				break;
			}

#pragma warn +rch

			//
			// SPECIAL SPAWN CODING FOR BLASTABLE CRATES...
			//

			if (tile >=432 && tile <=485)
			{
#if GAME_VERSION != SHAREWARE_VERSION
				if (tile>=468)
				{
					SpawnOffsetObj(en_crate3,x,y);
					new->temp2 = ExpCrateShapes[tile - 468];
					new->temp3 = (unsigned)ReserveStatic();

					if ((tile >= 475) && (tile <= 478))
						tile=(tile-475)+bo_money_bag;
					else
						tile=0;
				}
				else
				if (tile >=450)
				{
					SpawnOffsetObj(en_crate2,x,y);
					new->temp2 = ExpCrateShapes[tile - 450];
					new->temp3 = (unsigned)ReserveStatic();

					if ((tile >= 457) && (tile <= 460))
						tile=(tile-457)+bo_money_bag;
					else
						tile=0;
				}
				else
#endif
#if GAME_VERSION == SHAREWARE_VERSION
#if IN_DEVELOPMENT
				if (tile >= 450)
					INVALID_ACTOR_ERR;
				else
#endif
#endif
				if (tile >= 432)
				{
					SpawnOffsetObj(en_crate1,x,y);
					new->temp2 = ExpCrateShapes[tile - 432];
					new->temp3 = (unsigned)ReserveStatic();

					if ((tile >= 439) && (tile <= 442))
						tile=(tile-439)+bo_money_bag;
					else
						tile=0;
				}

				if (tile)
				{
					if (tile > bo_loot)
						tile += 3;
					tile -= bo_money_bag;
					AddTotalPoints(static_points[tile]);
#if IN_DEVELOPMENT
#ifdef DEBUG_STATICS
					debug_bonus[0][db_count++] = static_points[tile];
#endif
#endif
				}

				continue;
			}

			switch (tile)
			{
			case 19:
			case 20:
			case 21:
			case 22:
				SpawnPlayer(x,y,NORTH+tile-19);
			break;

			case 85:					// Money bag
			case 86:					// Loot
			case 87:					// Gold
			case 88:					// Bonus
					AddTotalPoints(static_points[statinfo[tile-23].type-bo_money_bag]);
#if IN_DEVELOPMENT
#ifdef DEBUG_STATICS
					debug_bonus[0][db_count++] = static_points[statinfo[tile-23].type-bo_money_bag];
#endif
#endif

			case 23:
			case 24:
			case 25:
			case 26:
			case 27:
			case 28:
			case 29:


#if GAME_VERSION != SHAREWARE_VERSION
			case 30:									// Yellow Puddle
#endif

			case 31:
			case 32:
			case 33:
			case 34:
			case 35:
			case 36:
			case 37:
			case 38:

			case 39:
			case 40:
			case 41:
			case 42:
			case 43:
			case 44:
			case 45:
			case 46:

			case 47:
			case 48:
			case 49:
			case 50:
			case 51:
			case 52:
			case 53:
			case 54:

			case 55:
			case 56:
			case 57:
			case 58:
			case 59:
			case 60:
			case 61:
			case 62:

			case 63:
			case 64:
			case 65:
			case 66:
			case 67:
			case 68:
			case 69:
			case 70:
         case 71:					// BFG Weapon		  
			case 72:					// Gurney Mutant
			case 73:             // Large Canister
			case 74:             // Small Canister
			case 75:             // Empty Gurney
			case 76:					// Empty Large Canister
			case 77:					// Empty Small Canister
			case 78:					// Dead Gen. Sci.

			case 80:
			case 83:					// Floor Grate
			case 84:					// Floor Pipe
				SpawnStatic(x,y,tile-23);
			break;

			case 399:				// gold 1
			case 400:				// gold 2
			case 401:				// gold 3
					AddTotalPoints(static_points[statinfo[tile-315].type-bo_money_bag]);
#if IN_DEVELOPMENT
#ifdef DEBUG_STATICS
					debug_bonus[0][db_count++] = static_points[statinfo[tile-315].type-bo_money_bag];
#endif
#endif

			case 381:
			case 382:
			case 383:
			case 384:
			case 385:
			case 386:
			case 387:
			case 388:
//			case 389:
			case 390:      		// candy bar
			case 391:				// sandwich

			case 395:				// Table
			case 396:				// Chair
			case 397:				// Stool
			case 398:				// Gore

			case 402:				//
			case 403:				//
			case 404:				//
			case 405:				//
			case 406:				//
			case 407:				//
			case 408:				//
			case 409:				//
			case 410:				//
			case 411:				//
			case 412:				//
			case 413:				//
			case 414:				//
			case 415:				//
			case 416:				//
			case 417:				//
			case 418:				//
			case 419:				//
			case 420:				//
			case 421:				//
			case 422:				//
			case 423:				// bo_coin
			case 424:				// bo_coin5
				SpawnStatic(x,y,tile-315);
			break;

			case 486:				// Plasma Detonator
				SpawnHiddenOfs(en_plasma_detonator_reserve, x, y);			// Spawn a reserve  
				SpawnStatic(x,y,486-375);
			break;

			case 487:				// Door rubble
         case 488:				// AutoMapper Bonus #1
         case 489:				// BonziTree
         case 490:				// Yellow Potted plant
         case 491:				// Tube Plant
         case 492:				// HiTech Chair
         case 493:				// AOG: Rent A Cop - Dead.
         case 494:				// AOG: Pro Guard - Dead.
			case 495:				// AOG: Swat Guard - Dead.
				SpawnStatic(x,y,tile-375);
			break;


			case 393:				// crate 2
			case 394:				// crate 3
#if GAME_VERSION == SHAREWARE_VERSION
#if IN_DEVELOPMENT
				INVALID_ACTOR_ERR;
#endif
#endif
			case 392:				// crate 1
				SpawnStatic(x,y,tile-315);
			break;

			case 81:
			case 82:
				SpawnOffsetObj(en_bloodvent+tile-81,x,y);
			break;


			//
			// GREEN OOZE
			//

			case 208:
				if (gamestate.difficulty<gd_hard)
					break;
			case 207:
				if (gamestate.difficulty<gd_medium)
					break;
			case 206:
				SpawnOffsetObj(en_green_ooze,x,y);
			break;


			//
			// BLACK OOZE
			//

			case 212:
				if (gamestate.difficulty<gd_hard)
					break;
			case 211:
				if (gamestate.difficulty<gd_medium)
					break;
			case 210:
				SpawnOffsetObj(en_black_ooze,x,y);
			break;



		// Flickering Light
		//
			case 79:
				SpawnOffsetObj(en_flickerlight,x,y);
            new->lighting = LAMP_ON_SHADING;
			break;



		// Arc Barrier
		//
			case 174:
         case 175:
         	//
            // 174=off,175=on
            //
				SpawnBarrier(en_post_barrier,x,y,tile-174);
			break;

		// Plasma Post Barrier
		//
			case 138:
         case 139:
         	//
            // 138=off,139=on
            //
				SpawnBarrier(en_arc_barrier,x,y,tile-138);
			break;


		//
      // VPOST Barrier
      //

         //
         // Switchable
         //
			case 563:	// On
			case 562:   // Off
				SpawnBarrier(en_vpost_barrier,x,y,tile-562);
				break;


         //
         // Cycle
         //
      	case 567:
				if (gamestate.difficulty<gd_hard)
					break;
         case 566:
				if (gamestate.difficulty<gd_medium)
					break;
			case 565:
				SpawnBarrier(en_vpost_barrier,x,y,0);
				break;

		//
      // VSPIKE Barrier
      //

      	//
         // Switchable
         //
			case 426:	// On
			case 425:	// Off
				SpawnBarrier(en_vspike_barrier,x,y,tile-425);
				break;


			//
         // Cycle
         //
			case 430:
				if (gamestate.difficulty<gd_hard)
					break;
			case 429:
				if (gamestate.difficulty<gd_medium)
					break;
			case 428:
				SpawnBarrier(en_vspike_barrier,x,y,0);
				break;


		//
		// STEAM GRATE
		//

			case 178:
				SpawnStand(en_steamgrate,x,y,0);
			break;

		//
		// STEAM PIPE
		//

			case 179:
				SpawnStand(en_steampipe,x,y,0);
			break;


		//
		// GOLDFIRE SPAWN SITES
		//
			case 124:
         	if (!loadedgame)
            {
					if (GoldsternInfo.SpawnCnt == GOLDIE_MAX_SPAWNS)
						GAME_ERROR(SETUPGAME_MAX_GOLDIE_SPAWNS);
					GoldsternInfo.flags = GS_FIRSTTIME;
					if (gamestate.mapon==9)
						GoldsternInfo.WaitTime = 60;
					else
						GoldsternInfo.WaitTime = MIN_GOLDIE_FIRST_WAIT + Random(MAX_GOLDIE_FIRST_WAIT-MIN_GOLDIE_FIRST_WAIT);
					GoldieList[GoldsternInfo.SpawnCnt].tilex=x;
					GoldieList[GoldsternInfo.SpawnCnt].tiley=y;
					GoldsternInfo.SpawnCnt++;

					if (gamestate.mapon == GOLD_MORPH_LEVEL)
					{
						AddTotalPoints(actor_points[goldsternobj-rentacopobj]);
						AddTotalEnemy(1);
#ifdef TRACK_ENEMY_COUNT
numEnemy[goldsternobj]++;
#endif
					}
				}
				break;

		//
		// GOLDFIRE SPAWN - IMMEDEATLY
		//

			case 141:
				if (!loadedgame)
				{
					if (GoldsternInfo.GoldSpawned)
						GAME_ERROR(TOO_MANY_FAST_GOLD_SPAWNS);

					if (GoldsternInfo.SpawnCnt == GOLDIE_MAX_SPAWNS)
						GAME_ERROR(SETUPGAME_MAX_GOLDIE_SPAWNS);

					GoldieList[GoldsternInfo.SpawnCnt].tilex=x;
					GoldieList[GoldsternInfo.SpawnCnt].tiley=y;

					GoldsternInfo.LastIndex = GoldsternInfo.SpawnCnt++;
					GoldsternInfo.flags = GS_COORDFOUND;

					SpawnStand(en_goldstern, x, y, 0);
					GoldsternInfo.GoldSpawned = true;
					new = NULL;
				}
				break;

//
// P wall
//
//			case 98:
//				if (!loadedgame)
//				  gamestate.secrettotal++;
//				break;



		//
		// SECURITY LIGHT
		//
			case 160:
				SpawnOffsetObj(en_security_light,x,y);
				break;



		//
		// Rotating Cube
		//

			case 177:
				SpawnOffsetObj(en_rotating_cube,x,y);
				new = NULL;
			break;

		//
		// RENT-A-COP
		//
			case 180:
			case 181:
			case 182:
			case 183:
				if (gamestate.difficulty<gd_hard)
					break;
				tile -= 36;
			case 144:
			case 145:
			case 146:
			case 147:
				if (gamestate.difficulty<gd_medium)
					break;
				tile -= 36;
			case 108:
			case 109:
			case 110:
			case 111:
				SpawnStand(en_rentacop,x,y,tile-108);
				break;


			case 184:
			case 185:
			case 186:
			case 187:
				if (gamestate.difficulty<gd_hard)
					break;
				tile -= 36;
			case 148:
			case 149:
			case 150:
			case 151:
				if (gamestate.difficulty<gd_medium)
					break;
				tile -= 36;
			case 112:
			case 113:
			case 114:
			case 115:
				SpawnPatrol(en_rentacop,x,y,tile-112);
				break;


//			case 124:
//				SpawnDeadGuard (x,y);
//				break;






		//
		// officer
		//
			case 188:
			case 189:
			case 190:
			case 191:
				if (gamestate.difficulty<gd_hard)
					break;
				tile -= 36;
			case 152:
			case 153:
			case 154:
			case 155:
				if (gamestate.difficulty<gd_medium)
					break;
				tile -= 36;
			case 116:
			case 117:
			case 118:
			case 119:
				SpawnStand(en_gen_scientist,x,y,tile-116);
				if (new->flags & FL_INFORMANT)
				{
					AddTotalInformants(1);
					new=NULL;
				}
			break;


			case 192:
			case 193:
			case 194:
			case 195:
				if (gamestate.difficulty<gd_hard)
					break;
				tile -= 36;
			case 156:
			case 157:
			case 158:
			case 159:
				if (gamestate.difficulty<gd_medium)
					break;
				tile -= 36;
			case 120:
			case 121:
			case 122:
			case 123:
				SpawnPatrol(en_gen_scientist,x,y,tile-120);
				if (new->flags & FL_INFORMANT)
				{
					AddTotalInformants(1);
					new=NULL;
				}
			break;


		//
		//	PROGUARD
		//
			case 198:
			case 199:
			case 200:
			case 201:
				if (gamestate.difficulty<gd_hard)
					break;
				tile -= 36;
			case 162:
			case 163:
			case 164:
			case 165:
				if (gamestate.difficulty<gd_medium)
					break;
				tile -= 36;
			case 126:
			case 127:
			case 128:
			case 129:
				SpawnStand(en_proguard,x,y,tile-126);
				break;


			case 202:
			case 203:
			case 204:
			case 205:
				if (gamestate.difficulty<gd_hard)
					break;
				tile -= 36;
			case 166:
			case 167:
			case 168:
			case 169:
				if (gamestate.difficulty<gd_medium)
					break;
				tile -= 36;
			case 130:
			case 131:
			case 132:
			case 133:
				SpawnPatrol(en_proguard,x,y,tile-130);
				break;



			case 312:
				if (gamestate.difficulty<gd_hard)
					break;

			case 311:
				if (gamestate.difficulty<gd_medium)
					break;

			case 310:
				SpawnStand(en_electro_alien,x,y,0);
				new=NULL;
			break;


		//
		//		FLOATING BOMB - Stationary
		//

			case 364:
			case 365:
			case 366:
			case 367:
				if (gamestate.difficulty<gd_hard)
					break;
				tile -= 18;
			case 346:
			case 347:
			case 348:
			case 349:
				if (gamestate.difficulty<gd_medium)
					break;
				tile -= 18;
			case 328:
			case 329:
			case 330:
			case 331:
				SpawnStand(en_floatingbomb,x,y,tile-328);
				new->flags |= FL_STATIONARY;
				break;


		//
		//		FLOATING BOMB - Start Stationary
		//

			case 296:
			case 297:
			case 298:
			case 299:
				if (gamestate.difficulty<gd_hard)
					break;
				tile -= 18;
			case 278:
			case 279:
			case 280:
			case 281:
				if (gamestate.difficulty<gd_medium)
					break;
				tile -= 18;
			case 260:
			case 261:
			case 262:
			case 263:
				SpawnStand(en_floatingbomb,x,y,tile-260);
				break;


		//
		//		FLOATING BOMB - Start Moving
		//

			case 300:
			case 301:
			case 302:
			case 303:
				if (gamestate.difficulty<gd_hard)
					break;
				tile -= 18;
			case 282:
			case 283:
			case 284:
			case 285:
				if (gamestate.difficulty<gd_medium)
					break;
				tile -= 18;
			case 264:
			case 265:
			case 266:
			case 267:
				SpawnPatrol(en_floatingbomb,x,y,tile-264);
				break;


		//
		//		VOLATILE MAT. TRANSPORT - Stationary
		//
#if GAME_VERSION != SHAREWARE_VERSION
			case 350:
			case 351:
			case 352:
			case 353:
				if (gamestate.difficulty<gd_hard)
					break;
				tile -= 18;
			case 332:
			case 333:
			case 334:
			case 335:
				if (gamestate.difficulty<gd_medium)
					break;
				tile -= 18;
			case 314:
			case 315:
			case 316:
			case 317:
				SpawnStand(en_volatiletransport,x,y,tile-314);
			break;
#else
#if IN_DEVELOPMENT
			case 350:
			case 351:
			case 352:
			case 353:
			case 332:
			case 333:
			case 334:
			case 335:
			case 314:
			case 315:
			case 316:
			case 317:
				INVALID_ACTOR_ERR;
			break;
#endif
#endif



		//
		//		Black Ooze
		//
			case 313:
				if (gamestate.difficulty<gd_hard)
					break;
				tile -= 18;
			case 295:
				if (gamestate.difficulty<gd_medium)
					break;
				tile -= 18;
			case 277:
				SpawnOffsetObj(en_black2_ooze,x,y);
			break;



		//
		//		Green Ooze
		//
			case 322:
				if (gamestate.difficulty<gd_hard)
					break;
				tile -= 18;
			case 304:
				if (gamestate.difficulty<gd_medium)
					break;
				tile -= 18;
			case 286:
				SpawnOffsetObj(en_green2_ooze,x,y);
			break;



		//
		//		VOLATILE MAT. TRANSPORT - Moving
		//
#if GAME_VERSION != SHAREWARE_VERSION
			case 354:
			case 355:
			case 356:
			case 357:
				if (gamestate.difficulty<gd_hard)
					break;
				tile -= 18;
			case 336:
			case 337:
			case 338:
			case 339:
				if (gamestate.difficulty<gd_medium)
					break;
				tile -= 18;
			case 318:
			case 319:
			case 320:
			case 321:
				SpawnPatrol(en_volatiletransport,x,y,tile-318);
			break;
#else
#if IN_DEVELOPMENT
			case 354:
			case 355:
			case 356:
			case 357:
			case 336:
			case 337:
			case 338:
			case 339:
			case 318:
			case 319:
			case 320:
			case 321:
				INVALID_ACTOR_ERR;
			break;
#endif
#endif

		//
		// Genetic Guard
		//

			case 143:
				if (gamestate.difficulty<gd_hard)
					break;
			case 142:
				if (gamestate.difficulty<gd_medium)
					break;
			case 214:
				SpawnOffsetObj(en_genetic_guard,x,y);
				break;


		//
		// Cyborg Warrior
		//
			case 603:
				if (gamestate.difficulty<gd_hard)
					break;
			case 585:
				if (gamestate.difficulty<gd_medium)
					break;
			case 250:
				SpawnOffsetObj(en_cyborg_warrior,x,y);
				break;


		//
		// Spider Mutant
		//
			case 601:
				if (gamestate.difficulty<gd_hard)
					break;
			case 583:
				if (gamestate.difficulty<gd_medium)
					break;
			case 232:
				SpawnOffsetObj(en_spider_mutant,x,y);
				break;

		//
		// Acid Dragon
		//
			case 605:
				if (gamestate.difficulty<gd_hard)
					break;
			case 587:
				if (gamestate.difficulty<gd_medium)
					break;
			case 268:
				SpawnOffsetObj(en_acid_dragon,x,y);
				break;

		//
		// Breather beast
		//
			case 602:
				if (gamestate.difficulty<gd_hard)
					break;
			case 584:
				if (gamestate.difficulty<gd_medium)
					break;
			case 233:
				SpawnOffsetObj(en_breather_beast,x,y);
				break;

		//
				// Mech Guardian
//
			case 606:
				if (gamestate.difficulty<gd_hard)
					break;
			case 588:
				if (gamestate.difficulty<gd_medium)
					break;
			case 269:
				SpawnOffsetObj(en_mech_guardian,x,y);
				break;

		//
		// Reptilian Warrior,
		//
			case 604:
				if (gamestate.difficulty<gd_hard)
					break;
			case 586:
				if (gamestate.difficulty<gd_medium)
					break;
			case 251:
				SpawnOffsetObj(en_reptilian_warrior,x,y);
				break;


		//
		// Mutant Human type 1
		//

			case 105:
				if (gamestate.difficulty<gd_hard)
					break;
			case 104:
				if (gamestate.difficulty<gd_medium)
					break;
			case 103:
				SpawnOffsetObj(en_mutant_human1,x,y);
				break;


		//
		// Mutant Human type 2
		//
#if GAME_VERSION != SHAREWARE_VERSION
			case 125:
				if (gamestate.difficulty<gd_hard)
					break;
			case 107:
				if (gamestate.difficulty<gd_medium)
					break;
			case 106:
				SpawnOffsetObj(en_mutant_human2,x,y);
			break;
#else
#if IN_DEVELOPMENT
			case 125:
			case 107:
			case 106:
				INVALID_ACTOR_ERR;
			break;
#endif
#endif



		//
		// Small Canister Alien - CONTAINED
		//

			case 136:
				if (gamestate.difficulty<gd_hard)
				{
					SpawnStatic(x,y,74-23);
					break;
				}
			case 135:
				if (gamestate.difficulty<gd_medium)
				{
					SpawnStatic(x,y,74-23);
					break;
				}
			case 134:
				SpawnOffsetObj(en_scan_wait_alien,x,y);
			break;



		//
		// Large Canister Alien - CONTAINED
		//
#if GAME_VERSION != SHAREWARE_VERSION
			case 172:
				if (gamestate.difficulty<gd_hard)
				{
					SpawnStatic(x,y,73-23);
					break;
				}
			case 171:
				if (gamestate.difficulty<gd_medium)
				{
					SpawnStatic(x,y,73-23);
					break;
				}
			case 170:
				SpawnOffsetObj(en_lcan_wait_alien,x,y);
			break;
#else
#if IN_DEVELOPMENT
			case 172:
			case 171:
			case 170:
				INVALID_ACTOR_ERR;
			break;
#endif
#endif


		//
		// Gurney Mutant - ASLEEP
		//

#if GAME_VERSION != SHAREWARE_VERSION
			case 161:
				if (gamestate.difficulty<gd_hard)
				{
					SpawnStatic(x,y,72-23);
					break;
				}
			case 173:
				if (gamestate.difficulty<gd_medium)
				{
					SpawnStatic(x,y,72-23);
					break;
				}
			case 137:
				SpawnOffsetObj(en_gurney_wait,x,y);
				break;
#else
#if IN_DEVELOPMENT
			case 161:
			case 173:
			case 137:
				INVALID_ACTOR_ERR;
			break;
#endif
#endif

		//
		// Small Canister Alien - ACTIVE/WALKING
		//

			case 288:
				if (gamestate.difficulty<gd_hard)
					break;
			case 289:
				if (gamestate.difficulty<gd_medium)
					break;
			case 290:
				SpawnOffsetObj(en_scan_alien,x,y);
				break;


		//
		// Large Canister Alien - ACTIVE/WALKING
		//
#if GAME_VERSION != SHAREWARE_VERSION
			case 270:
				if (gamestate.difficulty<gd_hard)
					break;
			case 271:
				if (gamestate.difficulty<gd_medium)
					break;
			case 272:
				SpawnOffsetObj(en_lcan_alien,x,y);
			break;
#else
#if IN_DEVELOPMENT
			case 270:
			case 271:
			case 272:
				INVALID_ACTOR_ERR;
			break;
#endif
#endif

		//
		// Gurney Mutant - AWAKE
		//
#if GAME_VERSION != SHAREWARE_VERSION
			case 275:
				if (gamestate.difficulty<gd_hard)
					break;
			case 274:
				if (gamestate.difficulty<gd_medium)
					break;
			case 273:
				SpawnOffsetObj(en_gurney,x,y);
			break;
#else
#if IN_DEVELOPMENT
			case 275:
			case 274:
			case 273:
				INVALID_ACTOR_ERR;
			break;
#endif
#endif


#if GAME_VERSION != SHAREWARE_VERSION
			case 293:
				if (gamestate.difficulty<gd_hard)
					break;
			case 292:
				if (gamestate.difficulty<gd_medium)
					break;
			case 291:
				SpawnStand(en_liquid,x,y,0);
			break;
#else
#if IN_DEVELOPMENT
			case 293:
			case 292:
			case 291:
				INVALID_ACTOR_ERR;
			break;
#endif
#endif


		// P.O.D. Alien Egg
		//
			case 294:
				if (gamestate.difficulty<gd_hard)
					scan_value = 0xff;

			case 276:
				if (gamestate.difficulty<gd_medium)
					scan_value = 0xff;

			case 306:
				SpawnOffsetObj(en_podegg,x,y);
				if (scan_value == 0xff)
					new->obclass = deadobj;
				else
				{
					AddTotalPoints(actor_points[podobj-rentacopobj]);
					AddTotalEnemy(1);
#ifdef TRACK_ENEMY_COUNT
numEnemy[podobj]++;
#endif
				}
				scan_value=0xffff;
			break;


		// Morphing Brown/LBlue Post -> Spider Mutant
		//
			case 610:
				if (gamestate.difficulty<gd_hard)
					scan_value = 0xff;

			case 609:
				if (gamestate.difficulty<gd_medium)
					scan_value = 0xff;

			case 608:
				if (scan_value == 0xff)
					SpawnStatic(x,y,402-315);
				else
				{
					AddTotalPoints(actor_points[en_spider_mutant]);
					AddTotalEnemy(1);
					SpawnOffsetObj(en_morphing_spider_mutant,x,y);
#ifdef TRACK_ENEMY_COUNT
numEnemy[new->obclass]++;
#endif
				}
				scan_value=0xffff;
			break;


		// Morphing Gray/Green Post -> Reptilian Warrior
		//
			case 592:
				if (gamestate.difficulty<gd_hard)
					scan_value = 0xff;

			case 591:
				if (gamestate.difficulty<gd_medium)
					scan_value = 0xff;

			case 590:
				if (scan_value == 0xff)
					SpawnStatic(x,y,403-315);
				else
				{
					AddTotalPoints(actor_points[en_reptilian_warrior]);
					AddTotalEnemy(1);
					SpawnOffsetObj(en_morphing_reptilian_warrior,x,y);
#ifdef TRACK_ENEMY_COUNT
numEnemy[new->obclass]++;
#endif
				}
				scan_value=0xffff;
			break;



		// Morphing Statue -> Blue Boy
		//
			case 628:
				if (gamestate.difficulty<gd_hard)
					scan_value = 0xff;

			case 627:
				if (gamestate.difficulty<gd_medium)
					scan_value = 0xff;

			case 626:
				if (scan_value == 0xff)
					SpawnStatic(x,y,48-23);
				else
				{
					AddTotalPoints(actor_points[en_mutant_human2]);
					AddTotalEnemy(1);
					SpawnOffsetObj(en_morphing_mutanthuman2,x,y);
#ifdef TRACK_ENEMY_COUNT
numEnemy[new->obclass]++;
#endif
				}
				scan_value=0xffff;
			break;



		// P.O.D. Alien
		//
			case 309:
				if (gamestate.difficulty<gd_hard)
					break;

			case 308:
				if (gamestate.difficulty<gd_medium)
					break;

			case 307:
				SpawnOffsetObj(en_pod,x,y);
			break;


		// Electro-Sphere - Vertical Hover
		//
			case 360:
				if (gamestate.difficulty<gd_hard)
					break;

			case 342:
				if (gamestate.difficulty<gd_medium)
					break;

			case 324:
				SpawnOffsetObj(en_vertsphere,x,y);
			break;

		// Electro-Sphere - Horizontal Hover
		//
			case 361:
				if (gamestate.difficulty<gd_hard)
					break;

			case 343:
				if (gamestate.difficulty<gd_medium)
					break;

			case 325:
				SpawnOffsetObj(en_horzsphere,x,y);
			break;

		// Electro-Sphere - Diagonal Hover
		//
			case 362:
				if (gamestate.difficulty<gd_hard)
					break;

			case 344:
				if (gamestate.difficulty<gd_medium)
					break;

			case 326:
				SpawnOffsetObj(en_diagsphere,x,y);
			break;




		//
		// Stationary SWAT Guards
		//

			case 252:
			case 253:
			case 254:
			case 255:
				if (gamestate.difficulty<gd_hard)
					break;
				tile -= 18;
			case 234:
			case 235:
			case 236:
			case 237:
				if (gamestate.difficulty<gd_medium)
					break;
				tile -= 18;
			case 216:
			case 217:
			case 218:
			case 219:
				SpawnStand(en_swat,x,y,tile-216);
				break;


		//
		// Roaming SWAT Guards
		//

			case 256:
			case 257:
			case 258:
			case 259:
				if (gamestate.difficulty<gd_hard)
					break;
				tile -= 18;
			case 238:
			case 239:
			case 240:
			case 241:
				if (gamestate.difficulty<gd_medium)
					break;
				tile -= 18;
			case 220:
			case 221:
			case 222:
			case 223:
				SpawnPatrol(en_swat,x,y,tile-220);
				break;

		//
		// STATIONARY HANGING TURRETS
		//
			case 368:
			case 369:
			case 370:
			case 371:
				if (gamestate.difficulty<gd_hard)
					break;
				tile -= 126;
			case 242:
			case 243:
			case 244:
			case 245:
				if (gamestate.difficulty<gd_medium)
					break;
				tile -= 18;
			case 224:
			case 225:
			case 226:
			case 227:
				SpawnStand(en_hang_terrot,x,y,tile-224);
				new->flags |= FL_STATIONARY;
				break;


		//
		// ROTATING HANGING TURRETS
		//
			case 372:
			case 373:
			case 374:
			case 375:
				if (gamestate.difficulty<gd_hard)
					break;
				tile -= 126;
			case 246:
			case 247:
			case 248:
			case 249:
				if (gamestate.difficulty<gd_medium)
					break;
				tile -= 18;
			case 228:
			case 229:
			case 230:
			case 231:
				SpawnStand(en_hang_terrot,x,y,tile-228);
				break;



//--------------------------
// PATH OBJECTS
//--------------------------
			//
			// Swat Guards
			//

			case 540:
			case 541:
			case 542:
			case 543:
				if (gamestate.difficulty<gd_hard)
					break;
				tile -= 18;
			case 522:
			case 523:
			case 524:
			case 525:
				if (gamestate.difficulty<gd_medium)
					break;
				tile -= 18;
			case 504:
			case 505:
			case 506:
			case 507:
				SpawnPatrol(en_swat,x,y,tile-504);
				new->flags &= ~FL_RANDOM_TURN;
				break;

			//
			//		VOLATILE MAT. TRANSPORT
			//

			case 548:
			case 549:
			case 550:
			case 551:
				if (gamestate.difficulty<gd_hard)
					break;
				tile -= 18;
			case 530:
			case 531:
			case 532:
			case 533:
				if (gamestate.difficulty<gd_medium)
					break;
				tile -= 18;
			case 512:
			case 513:
			case 514:
			case 515:
				SpawnPatrol(en_volatiletransport,x,y,tile-512);
				new->flags &= ~FL_RANDOM_TURN;
				break;

			//
			//	FLOATING BOMB -
			//

			case 544:
			case 545:
			case 546:
			case 547:
				if (gamestate.difficulty<gd_hard)
					break;
				tile -= 18;
			case 526:
			case 527:
			case 528:
			case 529:
				if (gamestate.difficulty<gd_medium)
					break;
				tile -= 18;
			case 508:
			case 509:
			case 510:
			case 511:
				SpawnPatrol(en_floatingbomb,x,y,tile-508);
				new->flags &= ~FL_RANDOM_TURN;
				break;

			//
			// PRO GUARD
			//

			case 594:
			case 595:
			case 596:
			case 597:
				if (gamestate.difficulty<gd_hard)
					break;
				tile -= 18;
			case 576:
			case 577:
			case 578:
			case 579:
				if (gamestate.difficulty<gd_medium)
					break;
				tile -= 18;
			case 558:
			case 559:
			case 560:
			case 561:
				SpawnPatrol(en_proguard,x,y,tile-558);
				new->flags &= ~FL_RANDOM_TURN;
				break;


			//
			// RENT-A-COP
			//

			case 552:
			case 553:
			case 554:
			case 555:
				if (gamestate.difficulty<gd_hard)
					break;
				tile -= 18;
			case 534:
			case 535:
			case 536:
			case 537:
				if (gamestate.difficulty<gd_medium)
					break;
				tile -= 18;
			case 516:
			case 517:
			case 518:
			case 519:
				SpawnPatrol(en_rentacop,x,y,tile-516);
				new->flags &= ~FL_RANDOM_TURN;
			break;


//-----------------------
// BOSS ACTORS
//-----------------------

			case 630:	// FINAL BOSS 1
         case 631:	// FINAL BOSS 2
         case 632:	// FINAL BOSS 3
         case 633:	// FINAL BOSS 4
         	SpawnOffsetObj(en_final_boss1+tile-630,x,y);
			break;

			}

		// If "new" is an object that gives points, add those points to level total...
		//
		// "new" is cleared to keep from re-adding points from the previous actor!
		//
			if (new && (new->obclass >= rentacopobj) && (new->obclass<crate1obj))
			{
				classtype obclass=new->obclass;

				switch (obclass)
				{
					case lcan_wait_alienobj:
					case scan_wait_alienobj:
					case gurney_waitobj:
						obclass++;
					break;
				}

				AddTotalPoints(actor_points[obclass-rentacopobj]);
				AddTotalEnemy(1);
#ifdef TRACK_ENEMY_COUNT
numEnemy[new->obclass]++;
#endif
				new = NULL;
			}

		// Skip past FA code...
		//
			if (scan_value != 0xffff)
			{
				x++;
				start++;
			}
		}

	if (!loadedgame)
		gamestuff.level[gamestate.mapon].stats.accum_inf =	gamestuff.level[gamestate.mapon].stats.total_inf;

#if IN_DEVELOPMENT
	db_count=0;
#endif
}

//--------------------------------------------------------------------------
// AddTotalPoints()
//--------------------------------------------------------------------------
void AddTotalPoints(unsigned points)
{
	if (loadedgame)
		return;

	gamestuff.level[gamestate.mapon].stats.total_points += points;
}

//--------------------------------------------------------------------------
// AddTotalInformants()
//--------------------------------------------------------------------------
void AddTotalInformants(char informants)
{
	if (loadedgame)
		return;

	gamestuff.level[gamestate.mapon].stats.total_inf += informants;
}

//--------------------------------------------------------------------------
// AddTotalEnemy()
//--------------------------------------------------------------------------
void AddTotalEnemy(unsigned enemies)
{
	if (loadedgame)
		return;

	gamestuff.level[gamestate.mapon].stats.total_enemy += enemies;	  
}

//==========================================================================

/*
==================
=
= SetupGameLevel
=
==================
*/

short an_offset[8] = {1,-1,64,-64,-65,-63,63,65};

void SetupGameLevel (void)
{
	extern boolean ForceLoadDefault;
   boolean switchon = false;
	memptr hold;
	sci_mCacheInfo *ci = InfHintList.smInfo;
	int	x,y,i;
	unsigned	far *map,tile,spot,icon;
	keytype lock;
	unsigned	far *map1,far *map2;
	char far *temp_ptr;
	short count;

	if (!loadedgame)
	{
		gamestate.flags |= GS_CLIP_WALLS;
		InitGoldsternInfo();
	}

	if (demoplayback || demorecord)
		US_InitRndT (false);
	else
		US_InitRndT (true);

//
// load the level
//
	CA_CacheMap (gamestate.mapon+MAPS_PER_EPISODE*gamestate.episode);
	mapon-=gamestate.episode*MAPS_PER_EPISODE;

	mapwidth = mapheaderseg[mapon]->width;
	mapheight = mapheaderseg[mapon]->height;

	if (mapwidth != 64 || mapheight != 64)
		GAME_ERROR(SETUPGAME_BAD_MAP_SIZE);

	LoadLocationText(gamestate.mapon+MAPS_PER_EPISODE*gamestate.episode);

//
// copy the wall data to a data segment array
//
	_fmemset (TravelTable,0,sizeof(TravelTable));
	_fmemset (gamestate.barrier_table,0xff,sizeof(gamestate.barrier_table));
	_fmemset (gamestate.old_barrier_table,0xff,sizeof(gamestate.old_barrier_table));
	memset (tilemap,0,sizeof(tilemap));
	memset (actorat,0,sizeof(actorat));
	memset (wallheight,0,sizeof(wallheight));

	map = mapsegs[0];
	map2 = mapsegs[1];
	for (y=0;y<mapheight;y++)
		for (x=0;x<mapwidth;x++)
		{
			icon = *map2++;
			tile = *map++;

			if (tile<AREATILE)
			{
			// solid wall
				tilemap[x][y] = tile;

//				if (tile != AMBUSHTILE)
//					(unsigned)actorat[x][y] = tile;

				switch (tile)
				{
					case AMBUSHTILE:
					case RKEY_TILE:
					case YKEY_TILE:
					case BKEY_TILE:
					case BFG_TILE:
					case ION_TILE:
					case DETONATOR_TILE:
					case CLOAK_TILE:
					case LINC_TILE:
					case CLOAK_AMBUSH_TILE:
					break;

					default:
						(unsigned)actorat[x][y] = tile;
					break;
				}

			}

			if (tile<64 || icon==PUSHABLETILE)
				TravelTable[x][y] |= TT_TRAVELED;
		}

//
// spawn doors
//
	InitActorList ();			// start spawning things with a clean slate
	InitDoorList ();

	InitMsgCache((mCacheList *)&ConHintList,sizeof(ConHintList),sizeof(ConHintList.cmInfo[0]));
	InitMsgCache((mCacheList *)&InfHintList,sizeof(InfHintList),sizeof(InfHintList.smInfo[0]));
	InitMsgCache((mCacheList *)&NiceSciList,sizeof(NiceSciList),sizeof(InfHintList.smInfo[0]));
	InitMsgCache((mCacheList *)&MeanSciList,sizeof(MeanSciList),sizeof(InfHintList.smInfo[0]));

	InitStaticList ();

	map = mapsegs[0];
	map1 = mapsegs[1];

	LastInfoAttacker = alerted = NumEAWalls = 0;

	for (y=0;y<mapheight;y++)
		for (x=0;x<mapwidth;x++)
		{
			tile = *map++;
			lock = *map1;

			if (*map==30)
			{
				gamestate.wintilex=x+1;
				gamestate.wintiley=y;
			}

			if (tile >= 88 && tile <= 105)
			{
				//
				// KEYS
				//

				switch (lock)
				{
					case 55:
					case 56:
						lock = kt_red+lock-55;
						*map1 = 0;
						break;

					case 58:
						lock = kt_blue;
						*map1 = 0;
						break;

					default:
						lock = kt_none;
				}

				//
				// DOOR
				//

				switch (tile)
				{

					case 88:
					case 89:
						SpawnDoor (x,y,!(tile%2),lock,dr_bio);
						break;

					case 90:
					case 91:
						SpawnDoor (x,y,!(tile%2),lock,dr_normal);
						break;

					case 92:
					case 93:
						SpawnDoor (x,y,!(tile%2),lock,dr_prison);
						break;

					case 94:
					case 95:
						SpawnDoor (x,y,!(tile%2),lock,dr_elevator);
						break;

					case 96:
					case 97:
						SpawnDoor (x,y,!(tile%2),lock,dr_high_security);
						break;

					case 98:							// oneway left  - Vert
					case 99:							// oneway up    - Horz
					case 100:						// oneway right - Vert
					case 101:						// oneway down  - Horz
						SpawnDoor (x,y,!(tile%2),lock,dr_oneway_left+(tile-98));
						break;

				  case 102:
				  case 103:
						SpawnDoor (x,y,!(tile%2),lock,dr_office);
						break;

				  case 104:
				  case 105:
						SpawnDoor (x,y,!(tile%2),lock,dr_space);
						break;


				}
			}
			else
			switch (tile)
			{
				case SODATILE:
					if (!loadedgame)
					{
						SpawnConcession(x,y,lock,CT_BEVS);
						*map1 = 0;
					}
				break;



				case FOODTILE:
					if (!loadedgame)
					{
						SpawnConcession(x,y,lock,CT_FOOD);
						*map1 = 0;
					}
				break;

				case EATILE:
					eaList[NumEAWalls].tilex=x;
					eaList[NumEAWalls].tiley=y;
					eaList[NumEAWalls].aliens_out=0;
					if ((lock & 0xff00) == 0xfa00)
						eaList[NumEAWalls].delay=60*(lock&0xff);
					else
						eaList[NumEAWalls].delay=60*8+Random(60*22);
					if (NumEAWalls++ == MAXEAWALLS)
						GAME_ERROR(SETUPGAME_MAX_EA_WALLS);
				break;

				case ON_SWITCH:
            	switchon = true;
				case OFF_SWITCH:
					*(map1) = 0xf800 | UpdateBarrierTable((*(map1)>>8),*(map1)&0xff,switchon);

               // Init for next time.

	            switchon = false;
				break;
			}

			map1++;
		}


//
// spawn actors
//

	ScanInfoPlane ();
	ConnectBarriers();

// Init informant stuff
//
	count = InfHintList.NumMsgs;
	LastInfArea=0xff;
	FirstGenInfMsg=0;
	for (;(ci->areanumber != 0xff) && (count--);ci++)
		FirstGenInfMsg++;
	TotalGenInfMsgs=InfHintList.NumMsgs-FirstGenInfMsg;


	//
	// Take out the special tiles that were not used...
	//

	map = mapsegs[0];
	for (y=0;y<mapheight;y++)
		for (x=0;x<mapwidth;x++)
		{
			tile = *map++;
			switch (tile)
			{
         	case AMBUSHTILE:
				case RKEY_TILE:
				case YKEY_TILE:
				case BKEY_TILE:
				case BFG_TILE:
				case ION_TILE:
				case DETONATOR_TILE:
				case CLOAK_TILE:
				case LINC_TILE:
				case CLOAK_AMBUSH_TILE:
					tilemap[x][y] = 0;
					if ( (unsigned)actorat[x][y] == AMBUSHTILE)
						actorat[x][y] = NULL;
					*(map-1) = GetAreaNumber(x,y);
            break;
			}
		}

//
// have the caching manager load and purge stuff to make sure all marks
// are in memory
//
	CA_LoadAllSounds ();

//
// Check and make sure a detonator is in a 'locked' level.
//

   if (gamestate.mapon < 20 && (!detonators_spawned) && gamestuff.level[gamestate.mapon+1].locked)
   	GAME_ERROR(NO_DETONATORS_IN_LEVEL);
}


//------------------------------------------------------------------------
// LoadLocationText()
//------------------------------------------------------------------------
void LoadLocationText(short textNum)
{
	char far *temp;

	LoadMsg(LocationText,LEVEL_DESCS,textNum+1,MAX_LOCATION_DESC_LEN);
	temp = _fstrstr(LocationText,"^XX");
	if (temp)
		*temp = 0;
}


//==========================================================================




/*
===================
=
= DrawPlayBorder
=
===================
*/
void DrawPlayBorder (void)
{
	int	xl,yl;

	if (viewwidth == 320)
	{
		VWB_Bar (0,TOP_STRIP_HEIGHT,320,200-STATUSLINES-TOP_STRIP_HEIGHT,0);    // JTR - Changed
//		VW_Bar (0,TOP_STRIP_HEIGHT,320,200-STATUSLINES-TOP_STRIP_HEIGHT,0);
		return;
	}

	xl = 160-viewwidth/2;
	yl = (200-STATUSLINES+TOP_STRIP_HEIGHT-viewheight)/2;

	BevelBox(0,TOP_STRIP_HEIGHT,320,200-STATUSLINES-TOP_STRIP_HEIGHT,BORDER_HI_COLOR,BORDER_MED_COLOR,BORDER_LO_COLOR);
	BevelBox(xl-1,yl-1,viewwidth+2,viewheight+2,BORDER_LO_COLOR,0,BORDER_HI_COLOR);
}


//--------------------------------------------------------------------------
// BMAmsg() - These messages are displayed by the Text Presenter!
//--------------------------------------------------------------------------
void BMAmsg(char far *msg)
{
	#define 	BMAx1	0						// outer bevel
	#define	BMAy1	152
	#define	BMAw1	320
	#define	BMAh1	48

	#define 	BMAx2	(BMAx1+7)			// inner bevel
	#define	BMAy2	(BMAy1+4)
	#define	BMAw2	(BMAw1-14)
	#define	BMAh2	(BMAh1-8)

	BevelBox(BMAx1,BMAy1,BMAw1,BMAh1,BORDER_HI_COLOR,BORDER_MED_COLOR,BORDER_LO_COLOR);
	BevelBox(BMAx2,BMAy2,BMAw2,BMAh2,BORDER_LO_COLOR,BORDER_MED_COLOR,BORDER_HI_COLOR);

	if (msg)
	{
		PresenterInfo pi;
		fontstruct _seg *font=(fontstruct _seg *)grsegs[STARTFONT+fontnumber];
		char numlines=1, far *p=msg;
		short cheight;

		memset(&pi,0,sizeof(pi));
		pi.flags = TPF_CACHE_NO_GFX;
		pi.script[0]=p;
		while (*p)
			if (*p++ == TP_RETURN_CHAR)
				numlines++;
		cheight=font->height*numlines+1+(TP_MARGIN*2);

		pi.xl=BMAx2+1;
		pi.yl=BMAy2+(BMAh2-cheight)/2;
		pi.xh=pi.xl+BMAw2-3;
		pi.yh=pi.yl+cheight-1;
		pi.bgcolor = BORDER_MED_COLOR;
		pi.ltcolor = BORDER_HI_COLOR;
		fontcolor = BORDER_TEXT_COLOR;
		pi.shcolor = pi.dkcolor = BORDER_LO_COLOR;
		pi.fontnumber=fontnumber;
		TP_InitScript(&pi);
		TP_Presenter(&pi);
	}
}

//----------------------------------------------------------------------
// CacheBMAmsg() - Caches in a Message Number and displays it using
//						 BMAmsg()
//----------------------------------------------------------------------
void CacheBMAmsg(unsigned MsgNum)
{
	char far *string, far *pos;

	CA_CacheGrChunk(MsgNum);
   string = MK_FP(grsegs[MsgNum],0);

   pos = _fstrstr(string,"^XX");
   *(pos+3) = 0;

   BMAmsg(string);

	UNCACHEGRCHUNK(MsgNum);

}

//--------------------------------------------------------------------------
// BevelBox()
//--------------------------------------------------------------------------
void BevelBox(short xl, short yl, short w, short h, byte hi, byte med, byte lo)
{
	short xh=xl+w-1,yh=yl+h-1;
	byte hc;

	VWB_Bar (xl,yl,w,h,med);				// inside

#if 0
	hc = (hi-lo+1)/2;
	hc = ABS(hc);
	if (hi > lo)
		hc = hi-hc;
	else
		hc = hi+hc;
#else
	hc = med+1;
#endif

	VWB_Hlin (xl,xh,yl,hi);					// top
	VWB_Hlin (xl,xh,yh,lo);					// bottom
	VWB_Vlin (yl,yh,xl,hi);					// left
	VWB_Vlin (yl,yh,xh,lo);					// right
	VWB_Plot (xl,yh,hc);						// lower-left
	VWB_Plot (xh,yl,hc);						// upper-right
}

//--------------------------------------------------------------------------
// ShadowPrintLocationText()
//--------------------------------------------------------------------------
void ShadowPrintLocationText(sp_type type)
{
	char *DemoMsg="-- DEMO --";
   char *DebugText= "-- DEBUG MODE ENABLED --";
	char str[8],far *s,*ls_text[3]={"-- LOADING --","-- SAVING --","-- CHANGE VIEW SIZE --"};
	unsigned w,h;

// Used for all fields...
//
	py = 5;
	fontcolor = 0xaf;

// Print LOCATION info...
//
	switch (type)
	{
		case sp_normal:
		// Print LEVEL info...
		//
			px = 13;
			if (gamestate.mapon>19)
				ShPrint(" SECRET ",0,false);
			else
			{
				ShPrint(" AREA: ",0,false);
				if (!type)
					ShPrint(itoa(gamestate.mapon+1,str,10),0,false);
			}

		// Print LIVES info...
		//
			px = 267;
			ShPrint("LIVES: ",0,false);
			if (!type)
				ShPrint(itoa(gamestate.lives,str,10),0,false);

		// Print location text
      //

			if (demoplayback || demorecord)
         	s = DemoMsg;
         else
#if IN_DEVELOPMENT
         	if (DebugOk)
#else
         	if (DebugOk || (gamestate.flags & (GS_QUICKRUN|GS_STARTLEVEL|GS_TICS_FOR_SCORE|GS_MUSIC_TEST|GS_SHOW_OVERHEAD)))
#endif
					s=DebugText;
            else
					s=LocationText;
		break;

		case sp_changeview:
		case sp_loading:
		case sp_saving:
			s=ls_text[type-sp_loading];
		break;
	}

	VW_MeasurePropString(s,&w,&h);
	px = 160-w/2;
	ShPrint(s,0,false);
}

//--------------------------------------------------------------------------
// DrawTopInfo()
//--------------------------------------------------------------------------
void DrawTopInfo(sp_type type)
{
	char old=fontnumber;

	LatchDrawPic(0,0,TOP_STATUSBARPIC);
	fontnumber=2;
	ShadowPrintLocationText(type);
	fontnumber=old;
}

/*
===================
=
= DrawPlayScreen
=
===================
*/
void DrawPlayScreen (boolean InitInfoMsg)
{
	int	i;
	unsigned temp;

	if (loadedgame)
		return;

	if (playstate != ex_transported)
		VW_FadeOut ();

	temp = bufferofs;
	WindowW = 253;
  	WindowH = 8;
   fontnumber = 2;

	for (i=0;i<3;i++)
	{
		bufferofs = screenloc[i];
		DrawPlayBorder();

		JLatchDrawPic(0,200-STATUSLINES,STATUSBARPIC);
		LatchDrawPic(0,0,TOP_STATUSBARPIC);

		ShadowPrintLocationText(sp_normal);
	}

	bufferofs = temp;

	DrawHealth();
	DrawKeys();
	DrawWeapon();
	DrawScore();

	InitInfoArea();

	if (InitInfoMsg)
		DISPLAY_MSG("R.E.B.A.\rAGENT: BLAKE STONE\rALL SYSTEMS READY.", MP_max_val, MT_NOTHING);
	else
		DisplayNoMoMsgs();

	ForceUpdateStatusBar();
}

//---------------------------------------------------------------------------
// void DrawWarpIn(void)
//---------------------------------------------------------------------------
void DrawWarpIn(void)
{
	int	i;
	unsigned temp;

	temp = bufferofs;
	InitInfoArea();
	DisplayInfoMsg("\r\r    TRANSPORTING...",MP_POWERUP,2*60,MT_GENERAL);

	DrawHealth();
	DrawKeys();
	DrawWeapon();
	DrawScore();
	WindowW = 253;
  	WindowH = 8;
   fontnumber = 2;
	for (i=0;i<3;i++)
	{
		bufferofs = screenloc[i];
		VW_Bar ((320-viewwidth)/2,(200-STATUSLINES-viewheight+TOP_STRIP_HEIGHT)/2,viewwidth,viewheight,BLACK);
		JLatchDrawPic(0,200-STATUSLINES,STATUSBARPIC);
		LatchDrawPic(0,0,TOP_STATUSBARPIC);

		ShadowPrintLocationText(sp_normal);
		UpdateStatusBar();
	}

	bufferofs = temp;

	SD_PlaySound(WARPINSND);

	fizzlein = true;

	ThreeDRefresh();

}

//---------------------------------------------------------------------------
// Warped
//---------------------------------------------------------------------------
void Warped(void)
{
	int		iangle,i;

	DisplayInfoMsg("\r\r\r   TRANSPORTING OUT",MP_POWERUP,7*60,MT_GENERAL);
	gamestate.old_weapons[3] = gamestate.weapon;
	gamestate.weapon = -1;			// take away weapon

	ThreeDRefresh();

	if (screenfaded)
		VW_FadeIn();

	iangle = (((player->dir+4) % 8)>>1) * 90;

	RotateView(iangle,2);

	gamestate.weapon = gamestate.old_weapons[3];
	gamestate.attackframe = gamestate.attackcount =	gamestate.weaponframe = 0;

	bufferofs += screenofs;

	VW_Bar (0,0,viewwidth,viewheight,BLACK);

	IN_ClearKeysDown ();
	SD_PlaySound (WARPINSND);

	FizzleFade(bufferofs,displayofs+screenofs,viewwidth,viewheight,70,false);

	bufferofs-= screenofs;

	IN_UserInput(100);
	SD_WaitSoundDone ();
}

//==========================================================================

#if GAME_VERSION == SHAREWARE_VERSION
char	demoname[13] = "DEMO?S.";
#else
char	demoname[13] = "DEMO?.";
#endif

#ifdef DEMOS_EXTERN

/*
==================
=
= StartDemoRecord
=
==================
*/

#define MAXDEMOSIZE	16384

void StartDemoRecord (int levelnumber)
{
	MM_GetPtr (&demobuffer,MAXDEMOSIZE);
	MM_SetLock (&demobuffer,true);
	demoptr = (char far *)demobuffer;
	lastdemoptr = demoptr+MAXDEMOSIZE;

	*demoptr = levelnumber;
	demoptr += 4;				// leave space for length
	demorecord = true;
}


/*
==================
=
= FinishDemoRecord
=
==================
*/

void FinishDemoRecord (void)
{
	char str[3];
	long	length,level;

	demorecord = false;

	length = demoptr - (char far *)demobuffer;

	demoptr = ((char far *)demobuffer)+1;
	*(unsigned far *)demoptr = length;

	VW_FadeIn();

	CenterWindow(24,3);
	PrintY+=6;
	fontnumber = 4;
	US_Print(" Demo number (0-9):");
	VW_UpdateScreen();

	if (US_LineInput (px,py,str,NULL,true,2,0))
	{
		level = atoi (str);
		if (level>=0 && level<=9)
		{
			demoname[4] = '0'+level;
			IO_WriteFile (demoname,(void far *)demobuffer,length);
		}
	}

	VW_FadeOut();

	MM_FreePtr (&demobuffer);
}

//==========================================================================

/*
==================
=
= RecordDemo
=
= Fades the screen out, then starts a demo.  Exits with the screen faded
=
==================
*/


#if 0		// JAM's Modified Version - HELP! - Comment out

void RecordDemo (void)
{
	CenterWindow(26,3);
	PrintY+=6;
	fontnumber=4;

	SETFONTCOLOR(0,15);
	VW_FadeOut ();

	NewGame (gd_hard,gamestate.episode);
	StartDemoRecord (gamestate.mapon);

	DrawPlayScreen (true);
	VW_FadeIn ();

	startgame = false;
	demorecord = true;

	LoadLevel(gamestate.mapon);
	StartMusic(false);
	PM_CheckMainMem ();
	fizzlein = true;

	PlayLoop ();

	demoplayback = false;

	StopMusic ();
	VW_FadeOut ();
	ClearMemory ();

	FinishDemoRecord ();
}

#endif

void RecordDemo (void)
{
	char str[3];
	int level,esc;

	CenterWindow(26,3);
	PrintY+=6;
	fontnumber=4;
	US_Print("  Demo which level(0-23):");
	VW_UpdateScreen();
	VW_FadeIn ();
	esc = !US_LineInput (px,py,str,NULL,true,2,0);
	if (esc)
		return;

	level = atoi (str);
//	level--;
	if (level > 23)
		return;

	SETFONTCOLOR(0,15);
	VW_FadeOut ();

	NewGame (gd_easy,level/MAPS_PER_EPISODE);
	gamestate.mapon = level%MAPS_PER_EPISODE;
	StartDemoRecord (level);

	DrawPlayScreen (true);
	DrawTopInfo(sp_loading);
	DisplayPrepingMsg(prep_msg);
	LS_current = 1;
	LS_total = 20;

	VW_FadeIn ();

	startgame = false;
	demorecord = true;

	LoadLevel(gamestate.mapon);

	VW_FadeOut();
	DrawPlayScreen(true);
	StartMusic(false);
	PM_CheckMainMem ();
	fizzlein = true;

	PlayLoop ();

	demoplayback = false;

	StopMusic ();
	VW_FadeOut ();
	ClearMemory ();

	FinishDemoRecord ();
}

#endif

//==========================================================================

/*
==================
=
= PlayDemo
=
= Fades the screen out, then starts a demo.  Exits with the screen faded
=
==================
*/

void PlayDemo (int demonumber)
{
//   static int numloops=0;
	int length,off;

#ifndef DEMOS_EXTERN
// debug: load chunk
#if GAME_VERSION == SHAREWARE_VERSION
	int dems[4]={T_DEMO0,T_DEMO1,T_DEMO2,T_DEMO3};
#else
	int dems[6]={T_DEMO0,T_DEMO1,T_DEMO2,T_DEMO3,T_DEMO4,T_DEMO5};
#endif

	CA_CacheGrChunk(dems[demonumber]);
	demoptr = grsegs[dems[demonumber]];
#else
	demoname[4] = '0'+demonumber;
	IO_LoadFile (demoname,&demobuffer);
	MM_SetLock (&demobuffer,true);
	demoptr = (char far *)demobuffer;
#endif

	NewGame (1,0);
	gamestate.mapon = *demoptr++;
	gamestate.difficulty = gd_easy;
	length = *((unsigned far *)demoptr)++;
	demoptr++;
	lastdemoptr = demoptr-4+length;

	VW_FadeOut ();

	SETFONTCOLOR(0,15);
	DrawPlayScreen (true);
	DrawTopInfo(sp_loading);
	DisplayPrepingMsg(prep_msg);
	LS_current = 1;
	LS_total = 20;
	VW_FadeIn ();

	startgame = false;
	demoplayback = true;

	StartMusic(false);
	LoadLevel(gamestate.mapon);

	VW_FadeOut();
	DrawPlayScreen(true);
	PM_CheckMainMem ();
	SetPlaneViewSize();
	fizzlein = true;

#ifndef DEMOS_EXTERN
	off = FP_OFF(demoptr);
	demoptr = grsegs[dems[demonumber]];
	demoptr += off;
#endif

	PlayLoop ();

	if (gamestate.health<=0)
		Died();

#ifndef DEMOS_EXTERN
	UNCACHEGRCHUNK(dems[demonumber]);
#else
	MM_FreePtr (&demobuffer);
#endif

	demoplayback = false;
	LS_current = LS_total = -1;

	StopMusic ();
	VW_FadeOut ();
	ClearMemory ();

	playstate = ex_title;
}

//==========================================================================

/*
==================
=
= Died
=
==================
*/

#define DEATHROTATE 2

void Died (void)
{
	float	fangle;
	long	dx,dy;
	int		iangle,curangle,clockwise,counter,change;

	gamestate.weapon = -1;			// take away weapon
	SD_PlaySound (PLAYERDEATHSND);

	iangle = CalcAngle(player,killerobj);

	RotateView(iangle,DEATHROTATE);

//
// fade to red
//
	FinishPaletteShifts ();

	bufferofs += screenofs;
	VW_Bar (0,0,viewwidth,viewheight,0x17);
	IN_ClearKeysDown ();
	FizzleFade(bufferofs,displayofs+screenofs,viewwidth,viewheight,70,false);
	bufferofs -= screenofs;
	if (demoplayback)
		return;
	IN_UserInput(100);

	SD_WaitSoundDone();
	StopMusic();

	gamestate.lives--;

	if (gamestate.lives > -1)
	{
		gamestate.health = 100;
		gamestate.weapons = 1<<wp_autocharge;			// |1<<wp_plasma_detonators;
		gamestate.weapon = gamestate.chosenweapon = wp_autocharge;

		gamestate.ammo = STARTAMMO;
		gamestate.attackframe = gamestate.attackcount =
		gamestate.weaponframe = 0;

		gamestate.flags |= (GS_CLIP_WALLS|GS_ATTACK_INFOAREA);

		DrawHealth();
		DrawKeys();
		DrawWeapon();
		DrawScore();
		DrawKeys();
		ForceUpdateStatusBar();
	}
}

//--------------------------------------------------------------------------
// LoseScreen()   - Displays the Goldstern/DamagedReba message...
//--------------------------------------------------------------------------
void LoseScreen(void)
{
	PresenterInfo pi;

   VW_FadeOut();

	memset(&pi,0,sizeof(pi));
	pi.flags=TPF_USE_CURRENT|TPF_SHOW_CURSOR|TPF_SCROLL_REGION|TPF_CONTINUE|TPF_TERM_SOUND|TPF_ABORTABLE;
	pi.xl=14;
	pi.yl=141;
	pi.xh=14+293;
	pi.yh=141+32;
	pi.ltcolor=15;
	pi.bgcolor=0;
	pi.dkcolor=1;
	pi.shcolor=1;
	pi.fontnumber=2;
	pi.cur_x = -1;
	pi.print_delay=2;

	ClearMemory();
	StopMusic();

	CA_CacheScreen(LOSEPIC);
	VW_UpdateScreen();

#ifdef ID_CACHE_LOSE
	TP_LoadScript(NULL,&pi,LOSETEXT);
#else
	TP_LoadScript("LOSE.TXT",&pi,0);
#endif

	// Now Presenting... The Loser Prize.. I nice message directly from Dr.
	// ==============    Goldstern himself!  Oooo Ohhhhh <clap> <clap> ...
	//

	VW_FadeIn();
	TP_Presenter(&pi);
	VW_FadeOut();

#ifdef ID_CACHE_LOSE
	TP_FreeScript(&pi,LOSETEXT);
#else
	TP_FreeScript(&pi,0);
#endif

	screenfaded = true;

	IN_ClearKeysDown();
}

//--------------------------------------------------------------------------
// RotateView()
//
// PARAMETERS:
//					DestAngle - Destination angle to rotate player->angle to.
//					RotSpeed  - Rotation Speed
//--------------------------------------------------------------------------
void RotateView(int DestAngle,unsigned char RotSpeed)
{
	int	curangle,clockwise,counter,change;
	objtype *obj;							  
	boolean old_godmode=godmode;		  

	if (player->angle > DestAngle)
	{
		counter = player->angle - DestAngle;
		clockwise = ANGLES-player->angle + DestAngle;
	}
	else
	{
		clockwise = DestAngle - player->angle;
		counter = player->angle + ANGLES-DestAngle;
	}

	godmode = true;		  				 
	curangle = player->angle;

	controly = 0;
	if (clockwise<counter)
	{
	//
	// rotate clockwise
	//
		if (curangle>DestAngle)
			curangle -= ANGLES;
		controlx = -1;				
		do
		{
			change = tics*RotSpeed;
			if (curangle + change > DestAngle)
				change = DestAngle-curangle;

			curangle += change;
			player->angle += change;
			if (player->angle >= ANGLES)
				player->angle -= ANGLES;

			for (obj = player->next;obj;obj = obj->next)
				DoActor (obj);
			ThreeDRefresh ();
			CalcTics ();
		} while (curangle != DestAngle);
	}
	else
	{
	//
	// rotate counterclockwise
	//
		if (curangle<DestAngle)
			curangle += ANGLES;
		controlx = 1;
		do
		{
			change = -tics*RotSpeed;
			if (curangle + change < DestAngle)
				change = DestAngle-curangle;

			curangle += change;
			player->angle += change;
			if (player->angle < 0)
				player->angle += ANGLES;

			for (obj = player->next;obj;obj = obj->next)
				DoActor (obj);
			ThreeDRefresh ();
			CalcTics ();
		} while (curangle != DestAngle);
	}

	controlx = 0;
	player->dir = ((player->angle + 22) % 360)/45;
	godmode = old_godmode;

}

//==========================================================================


/*
===================
=
= GameLoop
=
===================
*/

void GameLoop (void)
{
	extern boolean sqActive;

	char mod;

	int i,xl,yl,xh,yh;
	char Score[13];
	boolean	died;
#ifdef MYPROFILE
	clock_t start,end;
#endif

restartgame:

	ClearMemory();
	SETFONTCOLOR(0,15);
	DrawPlayScreen (true);

	died = false;
restart:
	do
	{
		extern int pickquick;

		ingame = true;

		if (died && pickquick)
		{
				char string[]="  Auto Quick Load?  ";

				WindowX=WindowY=0;
				WindowW=320;
				WindowH=152;

				if (Confirm(string))
				{
					playstate=0;
					DrawPlayBorder();
					VW_UpdateScreen();
					US_ControlPanel(sc_F9);
				}

				DrawPlayBorder();
				VW_UpdateScreen();
		}

		if (!sqActive)
			StartMusic(false);

		if (!(loadedgame || LevelInPlaytemp(gamestate.mapon)))
		{
			gamestate.tic_score = gamestate.score = gamestate.oldscore;
			memcpy(gamestate.numkeys,gamestate.old_numkeys,sizeof(gamestate.numkeys));
			memcpy(gamestate.barrier_table,gamestate.old_barrier_table,sizeof(gamestate.barrier_table));
			gamestate.rpower = gamestate.old_rpower;	
			gamestate.tokens = gamestate.old_tokens;
			gamestate.weapons = gamestate.old_weapons[0];
			gamestate.weapon = gamestate.old_weapons[1];
			gamestate.chosenweapon = gamestate.old_weapons[2];
			gamestate.ammo = gamestate.old_ammo;
			gamestate.plasma_detonators = gamestate.old_plasma_detonators;
			gamestate.boss_key_dropped=gamestate.old_boss_key_dropped;
			_fmemcpy(&gamestuff.level[0],gamestuff.old_levelinfo,sizeof(gamestuff.old_levelinfo));
			DrawKeys();
			DrawScore();
		}

#ifdef MYPROFILE
start = clock();
while (start == clock());
start++;
#endif

		startgame = false;
		if (!loadedgame)
		{
//			ClearMemory();
			if (LS_current==-1)
			{
//				ClearMemory();					
				DrawTopInfo(sp_loading);
				DisplayPrepingMsg(prep_msg);
				LS_current = 1;
				LS_total = 20;
			}
//			ClearMemory();
			LoadLevel(gamestate.mapon);
		}

		LS_current = LS_total = -1;

		PM_CheckMainMem ();
		SetPlaneViewSize();
		if (loadedgame)
			loadedgame=false;

		if (died)
		{
			WindowY=188;
			PreloadUpdate(1,1);
			died = false;
			DrawPlayScreen(true);
		}
		else
		{
			PreloadGraphics();
			if (playstate == ex_transported)
				DrawWarpIn();
			else
				DrawPlayScreen(false);
		}

		if (!sqActive)
			StartMusic(false);

		PlayLoop ();
		LS_current = LS_total = -1;
		died = false;

		StopMusic ();
		ingame = false;

#ifdef MYPROFILE
end = clock();
strcpy (str,"300 frames in 1/18ths:"); // defined in 3d_main.c
itoa(end-start,str2,10);					// defined in 3d_main.c
strcat (str,str2);							// defined in 3d_main.c
		Quit (str);								// defined in 3d_main.c
#endif

#ifdef DEMOS_EXTERN
		if (demorecord && playstate != ex_warped)
			FinishDemoRecord ();
#endif

		if (startgame || loadedgame)
			goto restartgame;

		switch (playstate)
		{

		case ex_transported:				// Same as ex_completed
			Warped();

		case ex_completed:
		case ex_secretlevel:
		case ex_warped:
#if 0
			gamestate.keys = 0;
			DrawKeys ();
			VW_FadeOut ();
#endif
//         StopMusic();			// JTR
			ClearMemory ();
			gamestate.mapon++;
			ClearNClose();
			DrawTopInfo(sp_loading);
			DisplayPrepingMsg(prep_msg);
			WindowY = 181;
			LS_current=1;
			LS_total=38;
			StartMusic(false);
			SaveLevel(gamestate.lastmapon);

			gamestate.old_rpower = gamestate.rpower;
			gamestate.oldscore = gamestate.score;
			memcpy(gamestate.old_numkeys,gamestate.numkeys,sizeof(gamestate.old_numkeys));
			gamestate.old_tokens = gamestate.tokens;
			memcpy(gamestate.old_barrier_table,gamestate.barrier_table,sizeof(gamestate.old_barrier_table));
			gamestate.old_weapons[0] = gamestate.weapons;
			gamestate.old_weapons[1] = gamestate.weapon;
			gamestate.old_weapons[2] = gamestate.chosenweapon;
			gamestate.old_ammo = gamestate.ammo;
			gamestate.old_boss_key_dropped = gamestate.boss_key_dropped;
			_fmemcpy(gamestuff.old_levelinfo,&gamestuff.level[0],sizeof(gamestuff.old_levelinfo));

#if 0
			if (gamestate.mapon == 9)
				gamestate.mapon = ElevatorBackTo[gamestate.episode];	// back from secret
			else if (playstate == ex_secretlevel)
				gamestate.mapon = 9;
			else
#endif
			break;

		case ex_died:
			if (InstantQuit)
				InstantQuit = false;
			else
			{
				Died ();

				died = true;			// don't "get psyched!"

				if (gamestate.lives > -1)
				{
					ClearMemory();
					break;				// more lives left
				}

				LoseScreen();
			}


		case ex_victorious:
			MainMenu[MM_SAVE_MISSION].active=AT_DISABLED;
#pragma warn -sus
			 MainMenu[MM_VIEW_SCORES].routine=&CP_ViewScores;
			_fstrcpy(MainMenu[MM_VIEW_SCORES].string,"HIGH SCORES");
#pragma warn +sus

			if (playstate==ex_victorious)
			{
				ThreeDRefresh();
				ThreeDRefresh();
			}

			ClearMemory ();

			if (playstate==ex_victorious)
			{
				char loop;

				fontnumber=1;
				CA_CacheGrChunk(STARTFONT+1);
				memset (update,0,sizeof(update));
				CacheBMAmsg(YOUWIN_TEXT);
				for (loop=0; loop<2; loop++)
				{
					VW_ScreenToScreen(displayofs,bufferofs,320,200);
					NextBuffer();
				}
				UNCACHEGRCHUNK(STARTFONT+1);
				SD_PlaySound(BONUS1SND);
				SD_WaitSoundDone();
				IN_UserInput(5*60);
				PM_CheckMainMem();
				ClearMemory();
			}

			VW_FadeOut ();
//       StopMusic();			 // JTR

			sprintf(Score,"%ld",gamestate.score);
			piStringTable[0]=Score;

			if (playstate==ex_victorious)
			{
				CA_CacheGrChunk(ENDINGPALETTE);
//				VL_SetPalette (0,256,grsegs[ENDINGPALETTE]);

				DoMovie(mv_final,grsegs[ENDINGPALETTE]);

				UNCACHEGRCHUNK(ENDINGPALETTE);
				NewViewSize(viewsize);		// Recreates & Allocs the ScaleDirectory
				Breifing(BT_WIN,gamestate.episode);
			}

			CheckHighScore (gamestate.score,gamestate.mapon+1);

			return;

		default:
			ClearMemory ();
			break;
		}

	} while (1);

}

