// Example using Watcom FLAT model Animation Construction Kit
// Started: 01/02/94
//  Author: Lary Myers
//  Module: FDEMO.C
// (c) CopyRight 1994 All Rights Reserved

#include <stdlib.h>
#include <stdio.h>
#include <malloc.h>
#include <mem.h>
#include <string.h>
#include <dos.h>
#include <time.h>
#include <io.h>
#include <fcntl.h>
#include <sys\stat.h>
#include "ack3d.h"
#include "ackeng.h"
#include "kit.h"
#include "modplay.h"

#define DEMO_RESOURCE	69
#define HAND1_RESOURCE	135
#define HAND2_RESOURCE	136

#define KEYBD  0x9    /* INTERRUPT 9 */
#define RIGHT_ARROW_KEY	    77
#define UP_ARROW_KEY	    72
#define LEFT_ARROW_KEY	    75
#define DOWN_ARROW_KEY	    80
#define MINUS_KEY	    74
#define PLUS_KEY	    78
#define NUMBER_5_KEY	    76
#define ESCAPE_KEY	    1
#define PGUP_KEY	    73
#define PGDN_KEY	    81
#define B_KEY		    48
#define C_KEY		    46
#define F_KEY		    33
#define I_KEY		    23
#define R_KEY		    19
#define S_KEY		    31
#define W_KEY		    17
#define NUM_1_KEY	    2
#define NUM_2_KEY	    3
#define NUM_3_KEY	    4
#define NUM_4_KEY	    5
#define NUM_5_KEY	    6
#define NUM_6_KEY	    7
#define NUM_7_KEY	    8
#define NUM_8_KEY	    9
#define NUM_9_KEY	    10

typedef struct {
    int	    mdx;
    int	    mdy;
    int	    mButtons;
} MOUSE;

#define MAX_AMOUNT	64
#define MAX_MAG_AMOUNT	64
#define MAX_STR_AMOUNT	128
#define MAX_STR_HALF_AMOUNT 64

extern	long	AckMemUsed;	    // Running total of memory used
extern	short	AckDisplayErrors;   // 1 = sw to text mode and display error

extern	long	mFactor;
extern	long	dFactor;

extern	long	zdTable[VIEW_WIDTH][200];

extern	UCHAR	colordat[];
extern	UINT	*ObjGrid;
extern	UINT	*Grid;
extern	UINT	FloorMap[];
extern	short	ViewHeight;
extern	short	CeilingHeight;
extern	short	Resolution;
extern	long	kduFactor;
extern	long	kdvFactor;
extern	long	kxFactor;
extern	long	kyFactor;
extern	short	tuFactor;
extern	short	tvFactor;
extern	short	rsHandle;
extern	ULONG	*rbaTable;
extern	UCHAR	*BackArray[];
extern	long	*xNextTable;
extern	long	*yNextTable;
extern	UINT	*Grid;
extern	long	*CosTable;
extern	long	*SinTable;

	ACKENG	*ae;

// These are the ranges used for distance shading. Will need to be modified
// for the new color palette used.
#if 0
ColorRange  ranges[64] = {
	16,16,
	32,16,
	48,16,
	64,16,
	80,16,
	96,8,
	104,8,
	112,8,
	120,8,
	128,8,
	136,8,
	144,8,
	152,8,
	160,8,
	168,8,
	176,8,
	184,8,
	192,16,
	208,16,
	224,8,
	232,8,
	0,0
	};
#endif

ColorRange  ranges[64] = {
	16,15,
	32,16,
	48,16,
	64,16,
	80,16,
	96,8,
	104,8,
	112,8,
	120,8,
	128,8,
	136,8,
	144,8,
	152,8,
	160,8,
	168,8,
	176,8,
	184,16,
	200,16,
	216,16,
	232,16,
	248,16,
	0,0
	};



    UCHAR   scanCode;
    UCHAR   KeyPressed;
    UCHAR   MiniKey;
    UCHAR   Keys[128];
    int	    HaveMouse;
    short   FlashIndex;
    short   FlashCount;
    UCHAR   *bmFlash[2];
    UCHAR   *bmFlash1[2];
    char    LineBuffer[200];
    char    *smFont;
    UCHAR   FontTransparent;
    UCHAR   FontColor;
    UCHAR   TextBGcolor;
    int	    Throwing;
    int	    Shooting;
    int	    ShutDownFlag;
    short   MagAmount;
    short   StrAmount;
    int	    ShowHitFlag;
    int	    MapResource;
    int	    PalResource;
    int	    ResScreenBack;
    int	    ResScrollBack;
    void    *BGmusic;

    UCHAR   *DemoPtr;
    short   Demoht;
    short   Demowt;
    UCHAR   *pHand1;
    short   Handw1;
    short   Handh1;
    UCHAR   *pHand2;
    short   Handw2;
    short   Handh2;

    long    TimerCounter;
    long    ObjCounter[64];
    void    (__interrupt __far *oldvec)();
    void    __interrupt __far myInt();

    void    (__interrupt __far *oldTimer)();
    void    __interrupt __far myTimer();

    short   LastObjectIndex;

//-----------------------------------------------------------------------------
// Globals used by the frame counting routines
//-----------------------------------------------------------------------------
volatile short framespersec = 0;
volatile short cframes=0, count=0, ticks=0;
volatile short AckTmCount=0, AckTmDelay=0;

    char    *ErrorMsgs[] = {
		"ERR_BADFILE      ",
		"ERR_BADCOMMAND   ",
		"ERR_BADOBJNUMBER ",
		"ERR_BADSYNTAX    ",
		"ERR_LOADINGBITMAP",
		"ERR_BADDIRECTION ",
		"ERR_BADSTARTX    ",
		"ERR_BADSTARTY    ",
		"ERR_BADANGLE     ",
		"ERR_BADMAPFILE   ",
		"ERR_READINGMAP   ",
		"ERR_BADPICNAME   ",
		"ERR_INVALIDFORM  ",
		"ERR_NOPBM        ",
		"ERR_BADPICFILE   ",
		"ERR_NOMEMORY     ",
		"ERR_BADPALFILE   ",
		"ERR_BADWINDOWSIZE",
		"ERR_TOMANYVIEWS  ",
		"ERR_BADOBJECTNUM ",
		"ERR_BADOBJTYPE   "
		 };


void AckRegisterStructure(ACKENG *ae);
void AckSpeedUp(short);
void AckSlowDown(void);

//=============================================================================
// Keyboard interrupt 9
//=============================================================================
void __interrupt __far myInt(void)
{
  register char x;

//oldvec();    // Use when screen captures are wanted - calls orig vector

scanCode = inp(0x60); // read keyboard data port
x = inp(0x61);
outp(0x61, (x | 0x80));
outp(0x61, x);
outp(0x20, 0x20);

Keys[scanCode & 127] = 1;
KeyPressed = 1;
if (scanCode & 128)
    {
    Keys[scanCode & 127] = 0;
    KeyPressed = 0;
    }
else
    MiniKey = 1;

}

//=============================================================================
// Timer interrupt - simply increments a counter for use in program
// Calls the old timer after X iterations have cycled so clock stays correct
//=============================================================================
void __interrupt __far myTimer(void)
{
if (ShutDownFlag)
    {
    _enable();
    outp(0x20,0x20);
    return;
    }

TimerCounter++;

AckTmCount++;
if (AckTmCount > AckTmDelay)
    {
    oldTimer();
    AckTmCount -= AckTmDelay;
    }
else
    {
    _enable();
    outp(0x20,0x20);
    }

}

//=============================================================================
//
//=============================================================================
/* MOD loading routines */
void *MODLoadModule(char *Path)
{
    int handle;
    unsigned modsize;
    void *modfile = NULL;
    if ((handle = open(Path,O_RDONLY | O_BINARY)) != -1) {
	modsize = lseek(handle,0L,SEEK_END);
	lseek(handle,0L,SEEK_SET);
	if ((modfile=(void*)AckMalloc(modsize)) != NULL) {
	    if (read(handle,modfile,modsize) != modsize) {
		AckFree(modfile);
                modfile = NULL;
            }
	}
	close(handle);
    }
    return modfile;
}

//=============================================================================
//
//=============================================================================
void MODFreeModule(void *Module)
{
    if (Module) AckFree(Module);
}

//=============================================================================
//
//=============================================================================
short StartBGmusic(void)
{
if ((BGmusic = MODLoadModule("SAHARA.MOD")) == NULL)
    return(-1);

if (MODPlayModule(BGmusic,5,22000,0x220,5,1))
    return(-2);

return(0);
}

//=============================================================================
//
//=============================================================================
void EndBGmusic(void)
{

if (BGmusic == NULL)
    return;

MODStopModule();
MODFreeModule(BGmusic);

}


//=============================================================================
//
//=============================================================================
short LoadSmallFont(void)
{
    short   ht,wt;
    int	    len;

ht = 2;
smFont = AckReadiff((UCHAR *)ht);
if (smFont == NULL)
    return(-1);

ht = (*(short *)smFont);
wt = (*(short *)&smFont[2]);
len = ht * wt;
memmove(smFont,&smFont[4],len);

return(0);
}

//=============================================================================
//
//=============================================================================
void smWriteChar(short x,short y,unsigned char ch)
{
		int	 FontOffset,VidOffset;
		int	 row,col;
		UCHAR	 *Video;

VidOffset = (y * 320) + x;
Video = (UCHAR *)0xA0000;
Video += VidOffset;
FontOffset = ((ch-32) * 5);

if (FontTransparent)
    Video = ae->ScreenBuffer + VidOffset;

for (row = 0; row < 5; row++)
    {
    if (!FontTransparent)
	{
	Video[0] = TextBGcolor;
	Video[1] = TextBGcolor;
	Video[2] = TextBGcolor;
	Video[3] = TextBGcolor;
	}

    if (smFont[FontOffset])
	Video[0] = FontColor;
    if (smFont[FontOffset+1])
	Video[1] = FontColor;
    if (smFont[FontOffset+2])
	Video[2] = FontColor;
    if (smFont[FontOffset+3])
	Video[3] = FontColor;

    Video += 320;
    FontOffset += 294;
    }


}

//=============================================================================
//
//=============================================================================
short smWriteString(short x,short y,char *s)
{
    short   OrgX;
    char    ch;

OrgX = x;

while (*s)
    {
    ch = *s++;

    if (ch == 10)
	{
	x = OrgX;
	y += 8;
	continue;
	}

    if (ch < ' ')
	continue;

    ch = toupper(ch);
    smWriteChar(x,y,ch);
    x += 5;
    }

return(y);
}

//=============================================================================
//
//=============================================================================
void smWriteHUD(short x,short y,UCHAR color,char *s)
{
FontTransparent = 1;
FontColor = color;
smWriteString(x,y,s);
FontTransparent = 0;
FontColor = 15;
}

//=============================================================================
// Checks mouse movement and calculates delta movement in X and Y directions
//=============================================================================
void CheckMouse(MOUSE *m)
{
    int	    dx,dy;
    short   x,y,buttons;


buttons = ReadMouseCursor(&y,&x);
dx = x - 160;
dy = y - 120;
m->mButtons = buttons;
SetMouseCursor(120,160);

if (abs(dy) > 10 && abs(dx) < 32)
    dx >>= 2;

m->mdx = dx;
m->mdy = dy;

}

//=============================================================================
// Reads a text line from the resource file
//=============================================================================
int ReadLine(void)
{
    int	    len;
    char    ch;

len = 0;
while (len < 200)
    {
    if (read(rsHandle,&LineBuffer[len],1) != 1)
	break;

    ch = LineBuffer[len];
    if (ch == 10)
	continue;

    if (ch == 13)
	break;

    len++;
    }

LineBuffer[len] = '\0';

return(len);
}

//=============================================================================
// Skips to the next parameter in a text line
//=============================================================================
char *GetNextParm(char *s)
{
    char    ch;

while (*s)
    {
    ch = *s++;
    if (ch == ',')
	{
	while (*s)
	    {
	    ch = *s;
	    if (ch != ',' && ch != ' ' && ch != '\t')
		return(s);
	    s++;
	    }
	return(NULL);
	}

    }

return(NULL);
}

//=============================================================================
// Loads a wall bitmap specified in info file
//=============================================================================
int LoadWall(void)
{
    int	    wnum,rnum,result;
    long    pos;
    char    *lb;


lb = LineBuffer;	    // Info file buffer
wnum = atoi(lb);	    // Wall number to load into

lb = GetNextParm(lb);

if (lb == NULL)
    return(-1);

rnum = atoi(lb);	    // Resource number

pos = lseek(rsHandle,0L,SEEK_CUR);
result = AckLoadWall(ae,wnum,(char *)rnum);
lseek(rsHandle,pos,SEEK_SET);

return(result);
}


//=============================================================================
// Loads an object bitmap specified in info file
//=============================================================================
int LoadObject(void)
{
    int	    onum,rnum,result;
    long    pos;
    char    *lb;

lb = LineBuffer;
onum = atoi(lb);	    // Object bitmap number

lb = GetNextParm(lb);

if (lb == NULL)
    return(-2);

rnum = atoi(lb);	    // Resource number
pos = lseek(rsHandle,0L,SEEK_CUR);
result = AckLoadObject(ae,onum,(char *)rnum);
lseek(rsHandle,pos,SEEK_SET);

return(result);
}


//=============================================================================
// Skip any leading spaces in the string
// NOTE: Actually modifies the string passed!
//=============================================================================
char *SkipSpaces(char *s)
{

while (*s == ' ' || *s == '\t' || *s == ',')
    strcpy(s,&s[1]);

return(s);
}


//=============================================================================
// Creates and object of the desired style
//=============================================================================
int CreateObject(void)
{
    int	    onum,vnum,speed;
    short   result,oType;
    short   NumViews,bmPerView;
    UINT    flags;
    char    *lb;
    OBJSEQ  os;

lb = LineBuffer;

if (!strnicmp(lb,"NUMBER:",7))
    {
    lb = &lb[7];
    onum = atoi(lb);
    if (onum < 1 || onum > MAX_OBJECTS)
	return(-3);

    result = AckCreateObject(ae,onum);
    if (result)
	return(result);

    LastObjectIndex = onum;
    lb = GetNextParm(lb);
    if (lb == NULL)
	return(-4);

    ae->ObjList[onum]->Speed = atoi(lb);
    return(0);
    }

onum = LastObjectIndex;		// Object number

oType = 0;

if (!strnicmp(lb,"CREATE:",7))
    {
    oType = NO_CREATE;
    lb = &lb[7];
    }

if (!strnicmp(lb,"DESTROY:",8))
    {
    oType = NO_DESTROY;
    lb = &lb[8];
    }

if (!strnicmp(lb,"WALK:",5))
    {
    oType = NO_WALK;
    lb = &lb[5];
    }

if (!strnicmp(lb,"ATTACK:",7))
    {
    oType = NO_ATTACK;
    lb = &lb[7];
    }

if (!strnicmp(lb,"INTERACT:",9))
    {
    oType = NO_INTERACT;
    lb = &lb[9];
    }


if (!oType)
    return(-5);



lb = SkipSpaces(lb);
if (lb == NULL)
    return(-6);

flags = 0;
strupr(lb);

if (strstr(lb,"ANIMATE") != NULL)
    flags |= OF_ANIMATE;

if (strstr(lb,"MOVEABLE") != NULL)
    flags |= OF_MOVEABLE;

if (strstr(lb,"PASSABLE") != NULL)
    flags |= OF_PASSABLE;

if (strstr(lb,"MULTIVIEW") != NULL)
    flags |= OF_MULTIVIEW;

if (strstr(lb,"SHOWONCE") != NULL)
    flags |= OF_ANIMONCE;

lb = GetNextParm(lb);
if (lb == NULL)
    return(-5);

NumViews = atoi(lb);
if (NumViews < 1)
    return(-6);

lb = GetNextParm(lb);
if (lb == NULL)
    return(-7);

bmPerView = atoi(lb);
if (bmPerView < 1)
    return(-7);

vnum = NumViews * bmPerView;
if (vnum > MAX_OBJ_BITMAPS)
    return(-8);

lb = GetNextParm(lb);
if (lb == NULL)
    return(-9);

vnum = 0;

while (lb != NULL && vnum < MAX_OBJ_BITMAPS)
    {
    os.bitmaps[vnum++] = atoi(lb);
    lb = GetNextParm(lb);
    }

os.bmBitmapsPerView = bmPerView;
os.flags = flags;
os.MaxBitmaps = bmPerView;
os.bmSides = NumViews;

result = AckSetupObject(ae,onum,oType,&os);

return(result);
}

//=============================================================================
// Reads the ASCII info file and processes the commands.
//=============================================================================
int ProcessInfoFile(short QuietFlag)
{
    int	    result;
    int	    mode;
    long    pos;
    char    *lb;


// Position to start of info file within resource file
lseek(rsHandle,rbaTable[0],SEEK_SET);

mode = result = 0;

while (!result)
    {
    if (!ReadLine())
	continue;

    if (*LineBuffer == ';')
	continue;

    if (!strnicmp(LineBuffer,"END:",4))
	break;

    if (!QuietFlag)
	printf(".");

    switch (mode)
	{

	case 1:		// Read walls
	    if (!strnicmp(LineBuffer,"LOADTYPE:",9))
		{
		ae->bmLoadType = atoi(&LineBuffer[9]);	// Sets for GIF or BBM
		break;
		}

	    if (!strnicmp(LineBuffer,"ENDBITMAPS:",11))
		mode = 4;
	    else
		result = LoadWall();
	    break;

	case 2:		// Object bitmaps
	    if (!strnicmp(LineBuffer,"LOADTYPE:",9))	// Sets for GIF or BBM
		{
		ae->bmLoadType = atoi(&LineBuffer[9]);
		break;
		}
	    if (!strnicmp(LineBuffer,"ENDBITMAPS:",11))
		mode = 5;
	    else
		result = LoadObject();
	    break;

	case 3:		// Create Object
	    if (!strnicmp(LineBuffer,"ENDDESC:",8))
		mode = 5;
	    else
		result = CreateObject();
	    break;

	case 4:		// Walls topic
	    if (!strnicmp(LineBuffer,"BITMAPS:",8))
		mode = 1;

	    if (!strnicmp(LineBuffer,"ENDWALLS:",9))
		mode = 0;
	    break;


	case 5:		// Objects topic
	    if (!strnicmp(LineBuffer,"BITMAPS:",8))
		mode = 2;

	    if (!strnicmp(LineBuffer,"OBJDESC:",8))
		mode = 3;

	    if (!strnicmp(LineBuffer,"ENDOBJECTS:",11))
		mode = 0;
	    break;


	default:
	    if (!strnicmp(LineBuffer,"WALLS:",6))
		{
		mode = 4;
		break;
		}

	    if (!strnicmp(LineBuffer,"OBJECTS:",8))
		{
		mode = 5;
		break;
		}

	    if (!strnicmp(LineBuffer,"MAPFILE:",8))
		{
		MapResource = atoi(&LineBuffer[8]);
		pos = lseek(rsHandle,0L,SEEK_CUR);
		result = AckReadMapFile(ae,(char *)MapResource);
		lseek(rsHandle,pos,SEEK_SET);
		break;
		}

	    if (!strnicmp(LineBuffer,"PALFILE:",8))
		{
		PalResource = atoi(&LineBuffer[8]);
		break;
		}

	    if (!strnicmp(LineBuffer,"XPLAYER:",8))
		{
		ae->xPlayer = atoi(&LineBuffer[8]);
		break;
		}

	    if (!strnicmp(LineBuffer,"YPLAYER:",8))
		{
		ae->yPlayer = atoi(&LineBuffer[8]);
		break;
		}

	    if (!strnicmp(LineBuffer,"PLAYERANGLE:",12))
		{
		ae->PlayerAngle = atoi(&LineBuffer[12]);
		break;
		}

	    if (!strnicmp(LineBuffer,"SCREENBACK:",11))
		{
		ResScreenBack = atoi(&LineBuffer[11]);
		break;
		}

	    if (!strnicmp(LineBuffer,"SCROLLBACK:",11))
		{
		ResScrollBack = atoi(&LineBuffer[11]);
		break;
		}

	    if (!strnicmp(LineBuffer,"TOPCOLOR:",9))
		{
		ae->TopColor = atoi(&LineBuffer[9]);
		break;
		}

	    if (!strnicmp(LineBuffer,"BOTTOMCOLOR:",12))
		{
		ae->BottomColor = atoi(&LineBuffer[12]);
		break;
		}

	    if (!strnicmp(LineBuffer,"SHADING:",8))
		{
		strupr(LineBuffer);
		if (strstr(&LineBuffer[8],"OFF") != NULL)
		    ae->LightFlag = SHADING_OFF;
		else
		    ae->LightFlag = SHADING_ON;
		break;
		}

	    if (!strnicmp(LineBuffer,"FLOORS:",7))
		{
		strupr(LineBuffer);
		if (strstr(&LineBuffer[7],"OFF") != NULL)
		    ae->SysFlags |= SYS_SOLID_FLOOR;
		else
		    {
		    ae->SysFlags &= ~SYS_SOLID_FLOOR;
		    }
		break;
		}

	    if (!strnicmp(LineBuffer,"RESOLUTION:",11))
		{
		Resolution = atoi(&LineBuffer[11]);
		break;
		}

	    if (!strnicmp(LineBuffer,"LOADTYPE:",9))
		{
		ae->bmLoadType = atoi(&LineBuffer[9]);	// Sets for GIF or BBM
		break;
		}

	    break;

	}

    }

if (!result)
    {
    result = AckCreateObject(ae,0);	// Create a dummy object for later
    if (!result)
	ae->ObjList[0]->Active = 0;	 // Turn off checking the object
    }

if (!QuietFlag)
    printf("done\n");
return(result);
}

//=============================================================================
// Quick routine to display a bitmap into the desired buffer. Handles
// transparent colors. Currently used to display the ACK3D Demo bitmap.
//=============================================================================
void ShowBitmap(short x,short y,UCHAR *dst,short ht,short wt,UCHAR *bm)
{
    int	    offset,col;
    short   endy;
    UCHAR   ch;

offset = (y*320) + x;
dst += offset;
endy = ae->WinEndY + 2;

while (ht-- > 0 && y++ <= endy)
    {
    for (col = 0; col < wt; col++)
	{
	ch = *bm++;
	if (ch)
	    dst[col] = ch;
	}
    dst += 320;
    }


}


//=============================================================================
//
//=============================================================================
void LoadDemoBitmap(void)
{
    UCHAR   *d;

DemoPtr = AckReadiff((char *)DEMO_RESOURCE);
if (DemoPtr == NULL)
    return;

d = DemoPtr;
Demowt = (*(short *)d);
d += 2;
Demoht = (*(short *)d);

pHand1 = AckReadiff((char *)HAND1_RESOURCE);
if (pHand1 == NULL)
    return;

d = pHand1;
Handw1 = (*(short *)d);
d += 2;
Handh1 = (*(short *)d);

pHand2 = AckReadiff((char *)HAND2_RESOURCE);
if (pHand2 == NULL)
    return;

d = pHand2;
Handw2 = (*(short *)d);
d += 2;
Handh2 = (*(short *)d);

}

//=============================================================================
//
//=============================================================================
short Initialize(short iFlag)
{
    short     i,bnum;

if (MouseInstalled() != -1)
    {
    printf("Mouse is required to run.\n");
    return(1);
    }

ae = AckMalloc(sizeof(ACKENG));
if (ae == NULL)
    {
    printf("Unable to get required memory.\n");
    return(2);
    }

memset(ae,0,sizeof(ACKENG));

ae->WinStartX = 20;
ae->WinEndX = 299;
ae->WinStartY = 0;
ae->WinEndY = 156;

// ae->WinStartX = 0;
// ae->WinEndX = 319;
// ae->WinStartY = 0;
// ae->WinEndY = 156;

ae->LightFlag = SHADING_OFF;
ae->xPlayer = 192;
ae->yPlayer = 640;
ae->PlayerAngle = 0;
ae->TopColor = 0;
ae->BottomColor = 24;
ae->DoorSpeed = 6;
ae->NonSecretCode = 1;
ae->SysFlags |= SYS_SOLID_BACK;

if (iFlag & 1)
    {
    ae->SysFlags |= SYS_SINGLE_BMP;
    ae->FloorBitmap = 33;
    ae->CeilBitmap = 45;
    }

printf("Initializing.\n");

i = AckOpenResource("kit.ovl");
if (i)
    {
    printf("Unable to open resource KIT.OVL\n");
    return(3);
    }

i = LoadSmallFont();
if (i)
    {
    printf("Error loading font BBM.\n");
    return(5);
    }

i = AckInitialize(ae);

AckCloseResource();

if (i)
    {
    printf("Error initializing. Error code: %d\n",i);
    return(3);
    }

printf("Processing DTF file ");

i = AckOpenResource("pics.dtf");
if (i)
    {
    printf("Unable to open resource PICS.DTF\n");
    return(3);
    }

i = ProcessInfoFile(0);
if (i)
    {
    printf("Error reading INF file.\n");
    if (i > 100 && i < 121)
	printf("Last error was %s\n",ErrorMsgs[i-100]);
    else
	printf("Error code: %d\n",i);

    printf("Line was: \"%s\"\n",LineBuffer);

    return(4);
    }

bmFlash[0] = ae->bMaps[4];
bmFlash[1] = ae->bMaps[8];
bmFlash1[0] = ae->bMaps[24];
bmFlash1[1] = ae->bMaps[2];
FlashIndex = 0;
LoadDemoBitmap();

return(0);
}

//=============================================================================
// Loads and displays the full screen picture and sets the palette to the one
// loaded with the picture.
//=============================================================================
short LoadAndShow(char *fName)
{
    short   i,j;
    UINT    pos,begpos;
    UCHAR   pMask;
    UCHAR   *buf,*bPtr;
    UCHAR   *Video;

buf = AckReadiff(fName);
if (buf == NULL)
    return(-1);

Video = (char *)0xA0000;
memmove(Video,&buf[4],64000);

AckSetPalette(colordat);

AckFree(buf);
return(0);
}

//=============================================================================
// Loads a background image (mountains) and processes the image into the
// separate slices for use at display time. Currently a background image
// can be 640 columns wide. This number can be made dynamic if needbe and would
// need to be changed in the routine below and in the DrawBackground routine
// in the ACK engine.
//=============================================================================
int LoadBackDrop(void)
{
	int	result;
	int	i,j,pos;
	UCHAR	*bPtr;
	UCHAR	*aPtr;

result = 0;

if (ResScrollBack)
    {
    printf("Loading background image....\n");
    bPtr = AckReadiff((char *)ResScrollBack);
    printf("Processing background image.\n");
    if (bPtr != NULL)
	{
	for (i = 0; i < 320; i++)
	    {
	    pos = i + 4;
	    aPtr = BackArray[i];
	    for (j = 0; j < 100; j++)
		{
		*aPtr++ = bPtr[pos];
		pos += 320;
		}
	    }

	for (i = 320; i < 640; i++)
	    {
	    pos = (i - 320) + 32004;
	    aPtr = BackArray[i];
	    for (j = 0; j < 100; j++)
		{
		*aPtr++ = bPtr[pos];
		pos += 320;
		}
	    }

	AckFree(bPtr);
	}
    else
	{
	printf("Unable to load background image.\n");
	result = 8;
	}
    }

return(result);
}

//=============================================================================
//
//=============================================================================
void ShowHit(void)
{
    int	    x,y,result,wNum;
    int	    flag;
    short   oNum,mPos;

ae->ObjList[0]->x = ae->xPlayer;
ae->ObjList[0]->y = ae->yPlayer;

wNum = 32;
oNum = 0;
flag = 0;

while (wNum--)
    {
    result = AckMoveObjectPOV(0,ae->PlayerAngle,12);

    if (result == POV_OBJECT)
	{
	flag = 1;
	oNum = AckGetObjectHit();
	break;
	}

    if (result == POV_XWALL)
	{
	flag = 2;
	oNum = ae->xGrid[AckGetWallHit()];
	if (oNum & (DOOR_TYPE_SLIDE+DOOR_TYPE_SPLIT))
	    flag = 4;
	oNum &= 0xFF;
	break;
	}

    if (result == POV_YWALL)
	{
	flag = 3;
	oNum = ae->yGrid[AckGetWallHit()];
	if (oNum & (DOOR_TYPE_SLIDE+DOOR_TYPE_SPLIT))
	    flag = 4;
	oNum &= 0xFF;
	break;
	}
    }


if (flag)
    {
    mPos = (ae->ObjList[0]->y & 0xFFC0) + (ae->ObjList[0]->x >> 6);

    switch (flag)
	{

	case 1:
	    sprintf(LineBuffer,"Object %d hit\nat location %d",oNum,mPos);
	    break;

	case 2:
	    sprintf(LineBuffer,"Xwall %d hit\nat location %d",oNum,mPos);
	    break;

	case 3:
	    sprintf(LineBuffer,"Ywall %d hit\nat location %d",oNum,mPos);
	    break;

	case 4:
	    sprintf(LineBuffer,"Door %d hit\nat location %d",oNum,mPos);
	    break;

	default:
	    *LineBuffer = '\0';
	    break;
	}

    ShowHitFlag = 1;
    }


}

//=============================================================================
//
//=============================================================================
void UpdateBlast(void)
{
    short   j;

if (ae->ObjList[99]->Flags & OF_ANIMDONE &&
    ae->ObjList[99]->CurrentType != NO_WALK)
    {
    AckSetObjectType(ae,99,NO_WALK);
    ae->ObjList[99]->Flags &= ~OF_ANIMDONE;
    }

j = AckMoveObjectPOV(99,ae->ObjList[99]->Dir,ae->ObjList[99]->Speed);

if (j > 0 && j != POV_PLAYER)
    {
    if (j != POV_OBJECT)
	{
	ae->ObjList[99]->Active = 0;
	Shooting = 0;
	return;
	}

    j = AckGetObjectHit();

    if (j > 4 && j < 13)
	{
	if (ae->ObjList[j]->CurrentType == NO_WALK)
	    {
	    AckSetObjectType(ae,j,NO_INTERACT);
	    ObjCounter[j] = TimerCounter + 18 + (rand() % 120);
	    }
	}

    if (j == 51)
	ae->ObjList[j]->Active = 0;

    ae->ObjList[99]->Active = 0;
    Shooting = 0;
    }

}

//=============================================================================
//
//=============================================================================
void CheckMonsters(void)
{
    int	    i,tFlag,xp,yp;
    int	    pMap,oMap,oRow,oCol;
    int	    row,col,offset;
    long    dx,dy,dx2,dy2,dist;
    short   cType;
    UCHAR   oFlags;

xp = ae->xPlayer;
yp = ae->yPlayer;

pMap = (yp & 0xFFC0) + (xp >> 6);

i = 5;
//for (i = 5; i < 13; i++)
while (1)
    {
    if (ae->ObjList[i]->Active)
	{
	oFlags = ae->ObjList[i]->Flags;
	cType = ae->ObjList[i]->CurrentType;
	dx = xp - ae->ObjList[i]->x;
	dy = yp - ae->ObjList[i]->y;

	dx2 = dx * dx;
	dy2 = dy * dy;
	if ((dx2+dy2) < 128000)
	    {
	    ae->ObjList[i]->Dir = AckGetObjectAngle(dx,dy);
	    if (cType == NO_WALK)
		{
		ae->ObjList[i]->Flags |= OF_ANIMATE;
		oFlags |= OF_ANIMATE;
		}

	    if (cType == NO_CREATE && !(oFlags & OF_ANIMATE))
		{
		if (i < 50)
		    {
		    ae->ObjList[i]->Flags |= OF_ANIMATE;
		    oFlags |= OF_ANIMATE;
		    }
		else
		    AckSetObjectType(ae,i,NO_WALK);
		}

	    }

	if (cType == NO_WALK && (oFlags & OF_ANIMATE))
	    {
	    tFlag = AckMoveObjectPOV(i,ae->ObjList[i]->Dir,8);
	    oRow = ae->ObjList[i]->Dir / INT_ANGLE_90;
	    switch (tFlag)
		{
		case POV_PLAYER:
		    StrAmount--;
		    if (StrAmount < 0) StrAmount = 0;
		    ShowStatus();
		    break;

		case POV_NOTHING:
		    break;

		case POV_SLIDEX:
		    if (oRow > 1) ae->ObjList[i]->Dir = INT_ANGLE_270;
		    else ae->ObjList[i]->Dir = INT_ANGLE_90;
		    break;

		case POV_SLIDEY:
		    if (oRow > 0 && oRow < 3)
			ae->ObjList[i]->Dir = INT_ANGLE_180;
		    else
			ae->ObjList[i]->Dir = 0;
		    break;

		case POV_OBJECT:
		    ae->ObjList[i]->Dir = rand() % INT_ANGLE_360;
		    break;

		default:
		    if (i < 50)
			ae->ObjList[i]->Flags &= ~OF_ANIMATE;
		    break;

		}
	    }
	}

    i++;
    if (i == 13) i = 51;
    if (i == 52) break;
    }

}

//=============================================================================
//
//=============================================================================
void ShowStatus(void)
{
    UCHAR   *Video;
    int	    row,offset,rlen,glen;


offset = (163 * 320) + 34;
glen = MagAmount;
if (glen > MAX_MAG_AMOUNT) glen = MAX_MAG_AMOUNT;
rlen = MAX_MAG_AMOUNT - glen;
Video = (UCHAR *)0xA0000;
Video += offset;

for (row = 0; row < 11; row++)
    {
    if (glen)
	memset(Video,105,glen);
    if (rlen)
	memset(&Video[glen],39,rlen);

    Video += 320;
    }

offset = (183 * 320) + 34;
glen = StrAmount >> 1;
if (glen > MAX_STR_HALF_AMOUNT) glen = MAX_STR_HALF_AMOUNT;
rlen = MAX_STR_HALF_AMOUNT - glen;
Video = (UCHAR *)0xA0000;
Video += offset;

for (row = 0; row < 11; row++)
    {
    if (glen)
	memset(Video,105,glen);
    if (rlen)
	memset(&Video[glen],39,rlen);

    Video += 320;
    }


}

//=============================================================================
//
//=============================================================================
void DrawBmpBox(int x1,int y1,int x2,int y2,long d1,long d2)
{
    long    NumCols,DeltaDist;
    long    htStep,dst;
    long    ht1,ht2,bmht;
    long    offset,xpos,ypos,bmPos,yposLow;
    long    bmCol,bmColStep;
    UCHAR   *Video,*bmp,*VidOrg,*VidEnd;
    UCHAR   *vPtr;

dst = d1;
if (d1 > d2) dst = d2;

bmht = 64 * 256;
DeltaDist = labs(d2 - d1);
ht1 = bmht / dst;
NumCols = ht1;
if (DeltaDist)
    NumCols = (ht1 * (64 - DeltaDist)) / 64;

if (NumCols < 1) NumCols = 1;

bmColStep = (64*65536) / NumCols;
htStep = (DeltaDist<<16) / NumCols;
if (d2 < d1) htStep = -htStep;

bmp = ae->bMaps[1];
VidOrg = Video = ae->ScreenBuffer;
VidEnd = VidOrg + 64000;
offset = (y1 * 320) + x1;
Video += offset;

bmCol = 0;
d2 = (d1<<16);

for (xpos = 0; xpos < NumCols; xpos++)
    {
    vPtr = Video;
    ypos = 0x1FFF;
    yposLow = 0x1F;
    bmPos = (bmCol>>16) * 64;
    d1 = (d2>>16);

    while (yposLow > 0 && vPtr > VidOrg)
	{
	*vPtr = bmp[bmPos+yposLow];
	vPtr -= 320;
	ypos -= d1;
	yposLow = ypos >> 8;
	}

    vPtr = Video + 320;
    ypos = 0x2000;
    yposLow = 0x20;

    while (yposLow < 64 && vPtr < VidEnd)
	{
	*vPtr = bmp[bmPos+yposLow];
	vPtr += 320;
	ypos += d1;
	yposLow = ypos >> 8;
	}

    d2 += htStep;
    bmCol += bmColStep;
    Video++;
    }


}

//=============================================================================
//
//=============================================================================
void ClsBmpBox(int x1,int y1,int x2,int y2)
{
    int	    offset,wt;
    UCHAR   *Video;

Video = (UCHAR *)0xA0000;
offset = (y1 * 320) + x1;
wt = (x2 - x1) + 1;
Video += offset;

while (y1++ <= y2)
    {
    memset(Video,0,wt);
    Video += 320;
    }

}

typedef struct {
    int	    x1;
    int	    y1;
    int	    x2;
    int	    y2;
    int	    d1;
    int	    d2;
    } AWALL;

short near long_sqrt(long v);

//=============================================================================
//
//=============================================================================
void DoTest(void)
{
    int	    done,cnt,Total;
    int	    xp,yp,ColX;
    long    dx,dy;
    UCHAR   *Video;
    AWALL   aw[2];
    short   i,minAngle,maxAngle,objAngle;

AckRegisterStructure(ae);

memset(ae->xGrid,0,(GRID_ARRAY*2));
memset(ae->yGrid,0,(GRID_ARRAY*2));
memset(Grid,0,(GRID_ARRAY*2));

aw[0].x1 = 64;
aw[0].y1 = 128;
aw[0].x2 = 128;
aw[0].y2 = 128;

aw[1].x1 = 128;
aw[1].y1 = 128;
aw[1].x2 = 128;
aw[1].y2 = 64;
Total = 2;
Video = (UCHAR *)0xA0000;
done = 0;
xp = yp = 256;


while (!done)
    {
    memset(ae->ScreenBuffer,0,64000);
    minAngle = ae->PlayerAngle - (INT_ANGLE_32 + 10);
    if (minAngle < 0)
	minAngle += INT_ANGLE_360;

    maxAngle = ae->PlayerAngle + (INT_ANGLE_32 + 10);
    if (maxAngle >= INT_ANGLE_360)
	maxAngle -= INT_ANGLE_360;

    xp = ae->xPlayer;
    yp = ae->yPlayer;

    for (cnt = 0; cnt < Total; cnt++)
	{
	dx = aw[cnt].x1 - xp;
	dy = aw[cnt].y1 - yp;
	aw[cnt].d1 = long_sqrt((dx*dx)+(dy*dy));
	objAngle = AckGetObjectAngle(dx,dy);
	dx = aw[cnt].x2 - xp;
	dy = aw[cnt].y2 - yp;
	aw[cnt].d2 = long_sqrt((dx*dx)+(dy*dy));

	if (minAngle > maxAngle)
	    {
	    if (objAngle >= minAngle)
		ColX = objAngle - minAngle;
	    else
		ColX = (objAngle+INT_ANGLE_360) - minAngle;
	    }
	else
	    {
	    ColX = objAngle - minAngle;
	    }

	if (ColX > -40 && ColX < 320)
	    DrawBmpBox(ColX,100,aw[cnt].x2,100,aw[cnt].d1,aw[cnt].d2);
	}
    memmove(Video,ae->ScreenBuffer,64000);

    if (Keys[ESCAPE_KEY])
	break;

    if (Keys[LEFT_ARROW_KEY])
	{
	ae->PlayerAngle--;
	if (ae->PlayerAngle < 0)
	    ae->PlayerAngle += INT_ANGLE_360;
	}

    if (Keys[RIGHT_ARROW_KEY])
	{
	ae->PlayerAngle++;
	if (ae->PlayerAngle >= INT_ANGLE_360)
	    ae->PlayerAngle -= INT_ANGLE_360;
	}

    if (Keys[UP_ARROW_KEY])
	{
	AckMovePOV(ae->PlayerAngle,16);
	}

    if (Keys[DOWN_ARROW_KEY])
	{
	i = ae->PlayerAngle + INT_ANGLE_180;
	if (i >= INT_ANGLE_360)
	    i -= INT_ANGLE_360;

	AckMovePOV(i,16);
	}

    }


}

//=============================================================================
//
//=============================================================================
short LoadNewLevel(char *LevelName)
{
    short   i;

i = AckOpenResource(LevelName);
if (i)
    return(-1);

for (i = 1; i < MAX_WALLBMPS; i++)
    {
    if (ae->bMaps[i] != NULL)
	{
	AckFree(ae->bMaps[i]);
	ae->bMaps[i] = NULL;
	}
    }

for (i = 1; i < MAX_OBJBMPS; i++)
    {
    if (ae->oMaps[i] != NULL)
	{
	AckFree(ae->oMaps[i]);
	ae->oMaps[i] = NULL;
	}
    }

for (i = 1; i < ae->MaxObjects; i++)
    {
    if (ae->ObjList[i] != NULL)
	{
	AckFree(ae->ObjList[i]);
	ae->ObjList[i] = NULL;
	}
    }

ae->MaxObjects = 0;

for (i = 0; i < (GRID_ARRAY - GRID_WIDTH); i++)
    {
    if (ae->myGrid[i] != NULL)
	AckFree(ae->myGrid[i]);

    ae->mxGrid[i] = NULL;
    ae->mxGrid[i+1] = NULL;
    ae->myGrid[i] = NULL;
    ae->myGrid[i+GRID_WIDTH] = NULL;

    }


i = ProcessInfoFile(1);
if (i)
    return(i);

AckCloseResource();
AckRegisterStructure(ae);
return(0);
}

    short   LevelFlag;

//=============================================================================
//
//=============================================================================
short main(short argc,char **argv)
{
    short   i,j,done,fpos;
    char    ch;
    MOUSE   mouse;
    UCHAR   *Video;
    int	    Spin,MoveAmount;
    int	    SpinAngle,MoveAngle;
    long    TimerEnd;
    short   DemoFlag;
    short   lpx,lpy,lpa;
    int	    StartTime,EndTime,InfoFlag;
    int	    CkStart,CkEnd;
    int	    TurnFactor,MoveFactor,MoveHalfFactor;
    int	    HandX,HandY,HandDY;
    long    x1,y1;

i = 0;
if (argc > 1)
    {
    for (j = 1; j <= argc; j++)
	{
	if (!strnicmp(argv[j],"-1",2))
	    i |= 1;

	}
    }

if ((done = Initialize(i)) != 0)
   return(done);

if ((done = LoadBackDrop()) != 0)
    return(done);

// Do some test setup of our GooMonsters
AckSetObjectType(ae,6,NO_WALK);
ae->ObjList[5]->Flags &= ~OF_ANIMATE;
ae->ObjList[7]->Flags &= ~OF_ANIMATE;
ae->ObjList[8]->Flags &= ~OF_ANIMATE;
ae->ObjList[9]->Flags &= ~OF_ANIMATE;
ae->ObjList[10]->Flags &= ~OF_ANIMATE;
ae->ObjList[11]->Flags &= ~OF_ANIMATE;
ae->ObjList[12]->Flags &= ~OF_ANIMATE;
ae->ObjList[99]->Active = 0;
ae->ObjList[99]->Speed = 48;

Shooting = 0;
MagAmount = MAX_MAG_AMOUNT;
StrAmount = MAX_STR_AMOUNT;

// Setup keyboard and timer interrupts
oldvec=_dos_getvect(KEYBD);
_dos_setvect(KEYBD,myInt);
oldTimer=_dos_getvect(8);
_dos_setvect(8,myTimer);
AckTmDelay = 3;
AckSpeedUp(AckTmDelay);	    // Set the timer interrupt at 3 times normal

StartBGmusic();

// Switch to mode 13
AckSetVGAmode();

// Put up the main screen
LoadAndShow((char *)ResScreenBack);

//DoTest();

// Set palette for shading if needed
AckSetupPalRanges(ae,ranges);

ShowStatus();

LevelFlag = 0;
done = 0;
SpinAngle = Spin = MoveAmount = 0;
MouseReleased();
SetMouseCursor(120,160);
fpos = 64;
DemoFlag = 0;
if (DemoPtr != NULL) DemoFlag = 1;
TimerEnd = TimerCounter + 180;


// MUST register each ACKENG structure once before use and after AckInitialize
AckRegisterStructure(ae);

StartTime = TimerCounter;
AckBuildView();
AckDisplayScreen();
EndTime = TimerCounter - StartTime;

if (!EndTime) EndTime = 1;

TurnFactor = INT_ANGLE_1 * EndTime;
MoveFactor = 3 * EndTime;
MoveHalfFactor = MoveFactor >> 1;

StartTime = clock();
EndTime	  = StartTime;
InfoFlag = 0;

HandX = 134;
HandY = 132;
HandDY = -2;
Throwing = 0;

while (!done)
    {

    if (SpinAngle)
	{
	ae->PlayerAngle += SpinAngle;
	if (ae->PlayerAngle >= INT_ANGLE_360)
	    ae->PlayerAngle -= INT_ANGLE_360;
	if (ae->PlayerAngle < 0)
	    ae->PlayerAngle += INT_ANGLE_360;

	SpinAngle >>= 3;
	if (SpinAngle == -1) SpinAngle = 0;
	}

    if (MoveAmount)
	{
	HandY += HandDY;
	if (HandY < 125) HandDY = 2;
	if (HandY > 132) HandDY = -2;

	j = AckMovePOV(MoveAngle,MoveAmount);
	AckCheckDoorOpen(ae->xPlayer,ae->yPlayer,MoveAngle);
	MoveAmount >>= 1;

	if (j == POV_OBJECT)
	    {
	    j = AckGetObjectHit();

	    if (j > 4 && j < 13)
		{
		StrAmount--;
		if (StrAmount < 0)
		    StrAmount = 0;

		ShowStatus();
		}

	    if (j >= 36 && j <= 49)
		{
		ae->ObjList[j]->Active = 0;
		MagAmount += 4;
		if (MagAmount > MAX_MAG_AMOUNT)
		    MagAmount = MAX_MAG_AMOUNT;
		ShowStatus();
		}

	    if (j == 50 && ae->ObjList[50]->CurrentType == NO_CREATE)
		{
		AckSetObjectType(ae,j,NO_WALK);
		StrAmount = MAX_STR_AMOUNT;
		ShowStatus();
		}

	    }
	}
    else
	{
	if (HandY < 132)
	    HandY++;
	}

    AckCheckObjectMovement();	// Animate objects if needed

    for (j = 5; j < 13; j++)
	{
	if (ae->ObjList[j]->Flags & OF_ANIMDONE &&
	    ae->ObjList[j]->CurrentType == NO_DESTROY)
	    {
	    AckSetObjectType(ae,j,NO_CREATE);
	    ae->ObjList[j]->Flags &= ~OF_ANIMDONE;
	    ae->ObjList[j]->Flags &= ~OF_ANIMATE;
	    ae->ObjList[j]->Active = 0;
	    }

	if (ae->ObjList[j]->Flags & OF_ANIMDONE &&
	    ae->ObjList[j]->CurrentType != NO_WALK)
	    {
	    AckSetObjectType(ae,j,NO_WALK);
	    ae->ObjList[j]->Flags &= ~OF_ANIMDONE;
	    ObjCounter[j] = TimerCounter + 18 + (rand() % 120);
	    }



	if (TimerCounter > ObjCounter[j])
	    {
	    ObjCounter[j] = TimerCounter + 180 + (rand() % 180);
	    if (ae->ObjList[j]->CurrentType == NO_WALK)
		AckSetObjectType(ae,j,NO_ATTACK);
	    else
		{
		if (ae->ObjList[j]->CurrentType == NO_INTERACT)
		    AckSetObjectType(ae,j,NO_DESTROY);

		}
	    }
	}

    if (Shooting)
	UpdateBlast();

    CheckMonsters();

    CkStart = TimerCounter;
    AckBuildView();	// Build floor, ceiling, and walls into ScrnBuffer

    if (DemoFlag)
	{
	switch (DemoFlag)
	    {
	    case 1:
		if (TimerCounter > TimerEnd)
		    {
		    DemoFlag++;
		    TimerEnd = TimerCounter + 540;
		    }
		break;

	    case 2:
		ShowBitmap(130,20,ae->ScreenBuffer,Demoht,Demowt,&DemoPtr[4]);
		if (TimerCounter > TimerEnd)
		    {
		    DemoFlag = 1;
		    TimerEnd = TimerCounter + 2160;
		    }
		break;

	    default:
		break;
	    }

	}

    switch (Throwing)
	{
	case 0:
	    ShowBitmap(HandX,HandY,ae->ScreenBuffer,Handh1,Handw1,&pHand1[4]);
	    break;

	case 1:
	    HandY -= 20;
	    if (HandY < 97)
		{
		HandY = 97;
		Throwing++;
		}
	    ShowBitmap(HandX,HandY,ae->ScreenBuffer,Handh1,Handw1,&pHand1[4]);
	    break;

	case 2:
	    HandY -= 5;
	    Throwing++;
	    ShowBitmap(HandX,HandY,ae->ScreenBuffer,Handh2,Handw2,&pHand2[4]);
	    break;

	case 3:
	    ae->ObjList[99]->Active = 1;
	    ae->ObjList[99]->x = ae->xPlayer;
	    ae->ObjList[99]->y = ae->yPlayer;
	    ae->ObjList[99]->Dir = ae->PlayerAngle;
	    ae->ObjList[99]->mPos = (ae->yPlayer & 0xFFC0) + ae->xPlayer >> 6;
	    AckSetObjectType(ae,99,NO_CREATE);
	    Shooting = 1;
	    MagAmount--;
	    ShowStatus();
	    Throwing++;
	    ShowBitmap(HandX,HandY,ae->ScreenBuffer,Handh2,Handw2,&pHand2[4]);
	    break;

	case 4:
	    HandY += 5;
	    Throwing++;
	    ShowBitmap(HandX,HandY,ae->ScreenBuffer,Handh2,Handw2,&pHand2[4]);
	    break;

	case 5:
	    HandY += 20;
	    if (HandY > 132)
		Throwing = 0;
	    ShowBitmap(HandX,HandY,ae->ScreenBuffer,Handh1,Handw1,&pHand1[4]);
	    break;


	default:
	    break;
	}

    if (InfoFlag)
	{
	EndTime = clock();
	if (EndTime > StartTime+100 )
	    {
	    StartTime = EndTime;
	    cframes = framespersec;
	    framespersec = 0;
	    }

	sprintf(LineBuffer,"FPS: %6ld,%d,%d,%d",
	    (long)cframes,ae->xPlayer,ae->yPlayer,ae->PlayerAngle);
	smWriteHUD(10,20,32,LineBuffer);
	framespersec++;
	}

//  sprintf(LineBuffer,"MEM: %ld",AckMemUsed);
//  smWriteHUD(22,30,32,LineBuffer);

    if (ShowHitFlag)
	smWriteHUD(10,10,32,LineBuffer);


    AckDisplayScreen();	    // Copy ScrnBuffer to actual video
    CkEnd = TimerCounter - CkStart;
    if (!CkEnd) CkEnd = 1;

    TurnFactor = INT_ANGLE_1 * CkEnd;
    MoveFactor = 3 * CkEnd;
    MoveHalfFactor = MoveFactor >> 1;

    i = (ae->yPlayer & 0xFFC0) + (ae->xPlayer >> 6);
    if (FloorMap[i] == 0x28)
	{
	StrAmount--;
	if (StrAmount < 1)
	    break;
	ShowStatus();
	}

    CheckMouse(&mouse);

    if (mouse.mButtons & 1)
	{
	if (!(ae->ObjList[99]->Active) && MagAmount > 0 && !Throwing)
	    {
	    Throwing = 1;
	#if 0
	    ae->ObjList[99]->Active = 1;
	    ae->ObjList[99]->x = ae->xPlayer;
	    ae->ObjList[99]->y = ae->yPlayer;
	    ae->ObjList[99]->Dir = ae->PlayerAngle;
	    ae->ObjList[99]->mPos = (ae->yPlayer & 0xFFC0) + ae->xPlayer >> 6;
	    AckSetObjectType(ae,99,NO_CREATE);
	    Shooting = 1;
	    MagAmount--;
	    ShowStatus();
	#endif
	    }
	}

    if (mouse.mButtons & 2)
	{
	MoveAmount += MoveFactor; // 16;
	if (MoveAmount > MAX_AMOUNT)
	    MoveAmount = MAX_AMOUNT;
	MoveAngle = ae->PlayerAngle;
	}

    if (mouse.mdx < 0)
	{
	Spin = -mouse.mdx;
	Spin >>= 5;
	SpinAngle = -TurnFactor * Spin; // -INT_ANGLE_1 * Spin;
	Spin = 1;
	}

    if (mouse.mdx > 0)
	{
	Spin = mouse.mdx;
	Spin >>= 5;
	SpinAngle = TurnFactor * Spin; // INT_ANGLE_1 * Spin;
	Spin = 1;
	}

    if (mouse.mdy < 0)
	{
	i = -mouse.mdy;
	i >>= 2;
	i += MoveHalfFactor;
	MoveAmount += i;
	if (MoveAmount > MAX_AMOUNT)
	    MoveAmount = MAX_AMOUNT;
	MoveAngle = ae->PlayerAngle;
	}

    if (mouse.mdy > 20)
	{
	i = mouse.mdy;
	i >>= 3;
	i += MoveHalfFactor;
	j = ae->PlayerAngle + INT_ANGLE_180;
	if (j >= INT_ANGLE_360)
	    j -= INT_ANGLE_360;

	MoveAmount += i;
	if (MoveAmount > MAX_AMOUNT)
	    MoveAmount = MAX_AMOUNT;
	MoveAngle = j;
	}

    if (Keys[ESCAPE_KEY])
	break;

    if(Keys[RIGHT_ARROW_KEY])
	{
	Spin += 1;
	SpinAngle += TurnFactor; // INT_ANGLE_1 * Spin;
	}

    if(Keys[LEFT_ARROW_KEY])
	{
	Spin += 1;
	SpinAngle -= TurnFactor; // -INT_ANGLE_1 * Spin;
	}

    if(Keys[UP_ARROW_KEY])
	{
	MoveAmount += (MoveFactor + MoveHalfFactor); // 12;
	if (MoveAmount > MAX_AMOUNT)
	    MoveAmount = MAX_AMOUNT;
	MoveAngle = ae->PlayerAngle;
	}

    if(Keys[DOWN_ARROW_KEY])
	{
	j = ae->PlayerAngle + INT_ANGLE_180;
	if (j >= INT_ANGLE_360)
	    j -= INT_ANGLE_360;

	MoveAmount += (MoveFactor + MoveHalfFactor); // 12;
	if (MoveAmount > MAX_AMOUNT)
	    MoveAmount = MAX_AMOUNT;
	MoveAngle = j;
	}


    if (Keys[C_KEY])
	{
	ae->SysFlags ^= SYS_SOLID_CEIL;
	ae->SysFlags &= ~SYS_SOLID_BACK;
	Keys[C_KEY] = 0;

	if ((ae->SysFlags & SYS_SOLID_CEIL) && (ResScrollBack != 0))
	    ae->SysFlags |= SYS_SOLID_BACK;
	AckRegisterStructure(ae);
	}

    if (Keys[R_KEY])
	{
	Keys[R_KEY] = 0;
	Resolution++;
	if (Resolution > 2)
	    Resolution = 0;
	}

    if (Keys[F_KEY])
	{
	ae->SysFlags ^= SYS_SOLID_FLOOR;
	Keys[F_KEY] = 0;
	AckRegisterStructure(ae);
	}


    if (Keys[PGUP_KEY] && ViewHeight < 60)
	{
	ViewHeight++;
	CeilingHeight++;
	}

    if (Keys[PGDN_KEY] && ViewHeight > 4)
	{
	ViewHeight--;
	CeilingHeight--;
	}

    if (Keys[NUM_1_KEY])
	{
	Keys[NUM_1_KEY]=0;
	dFactor--;
	}

    if (Keys[NUM_2_KEY])
	{
	Keys[NUM_2_KEY]=0;
	dFactor++;
	}


    if (Keys[MINUS_KEY])
	{
	Keys[MINUS_KEY]=0;
	mFactor--;
	}

    if (Keys[PLUS_KEY])
	{
	Keys[PLUS_KEY]=0;
	mFactor++;
	}

    if (Keys[I_KEY])
	{
	Keys[I_KEY] = 0;
	InfoFlag ^= 1;
	}

    if (Keys[B_KEY])
	{
	Keys[B_KEY]=0;
    //	mFactor -= 64;
	if (!LevelFlag)
	    LoadNewLevel("MALL.DTF");
	else
	    {
	    LoadNewLevel("PICS.DTF");
	    ae->ObjList[99]->Active = 0;
	    ae->ObjList[99]->Speed = 48;
	    }
	LevelFlag ^= 1;
	}

    if (Keys[S_KEY])
	{
	Keys[S_KEY] = 0;
	mFactor += 64;
	}
    }

EndBGmusic();
ShutDownFlag = 1;
_disable();
AckSlowDown();			// Set the timer back to normal speed
AckWrapUp(ae);
AckSetTextmode();
_dos_setvect(KEYBD,oldvec);
_dos_setvect(8,oldTimer);
_enable();

return(0);
}

