/*		   ACK-3D ( Animation Construction Kit 3D )		      */
/* Main entry point   */
/* Author: Lary Myers */

#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <time.h>
#include <string.h>
#include <sys/stat.h>
#include "ack3d.h"
#include "ackext.h"

/****************************************************************************
**									   **
****************************************************************************/
void main(int argc,char *argv[])
{
int    i,j,done,pos,dflag;
int    TablePosn;
int    xPlayer,yPlayer;
int    PlayerAngle;
int    x1,y1;
int    SkyCount;
int    SkyNumber;
int    DoFlash;
long   CosAngle,SinAngle;
int    Spin,SpinAngle;
int    DoorDelay;
unsigned char    sCode;
long   frames;
time_t t1, tStart, tDraw;


#if DEBUG
	dfp = fopen("x.dst","w");
#else
	dfp = NULL;
#endif

	DoFlash = 1;

	if (argc > 1)
    {
    		for (i = 0; i < argc; i++)
	{
			if (!(strcasecmp(argv[i+1],"-F")))
	    			DoFlash = 0;
		}
    	}

	InitializeMouse();

	strcpy(PalFile,"ack.pal");
	strcpy(GridFile,"ackmap.l01");

	TopColor      = SkyColor = SKY_COLOR;
	BottomColor   = FloorColor = FLOOR_COLOR;
	FlashColor    = SKY_FLASH;
	SkyCount      = 0;
	Spin	      = SpinAngle = 0;
	CenterRow     = 120;
	MaxObjects    = 0;
	DoorSpeed     = DEFAULT_DOOR_SPEED;
	StartX	      = StartY = 96;
	StartAngle    = 0;
	CurrentLevel  = 1;
	NonSecretCode = 1;

	if (BuildTables())
    		exit(1);

	if (ReadMasterFile("ack3d.l01"))
    		exit(1);

	if (ReadMapFile())
    		exit(1);

	BuildXYgrid();

	TopColor    = SkyColor;
	BottomColor = FloorColor;
	xPlayer	    = StartX;
	yPlayer	    = StartY;
	PlayerAngle = StartAngle;
	CosAngle    = CosTable[PlayerAngle];
	SinAngle    = SinTable[PlayerAngle];

	ObjList[0].Sides  = 0;
	ObjList[0].VidRow = CenterRow;

	graphinit(0);


	keyBoardInit();
	
#if 0
	PageNum = 1;
	usepage(PageNum);
#endif

	LoadPalette(PalFile);
	NoWalls = 0;
	done	= 0;

	DrawView(xPlayer,yPlayer,PlayerAngle);
	SkyNumber = drand48()*1000;

	txRay  = 0L;
	tyRay  = 0L;
	tDOW   = 0L;
	tFlip  = 0L;
	frames = 0L;
	tDraw  = 0L;
	tStart = CLOCK_PTR;

	while (!done) {
    		CheckDoors(xPlayer,yPlayer);
    		CheckObjectMovement();

    		sCode = CheckSpecialCodes((yPlayer & 0xFFC0) + (xPlayer >> 6));

    		if (sCode == MAP_DOWNCODE) {
			CurrentLevel++;
			ReadNewLevel();
			TopColor    = SkyColor;
			BottomColor = FloorColor;
			xPlayer	    = StartX;
			yPlayer	    = StartY;
			PlayerAngle = StartAngle;
			CosAngle    = CosTable[PlayerAngle];
			SinAngle    = SinTable[PlayerAngle];
		}

    		if (sCode == MAP_UPCODE) {
			if (CurrentLevel > 1) {
	    			CurrentLevel--;
	    			ReadNewLevel();
	    			TopColor	= SkyColor;
	    			BottomColor = FloorColor;
	    			xPlayer	= StartX;
	    			yPlayer	= StartY;
	    			PlayerAngle = StartAngle;
	    			CosAngle	= CosTable[PlayerAngle];
	    			SinAngle	= SinTable[PlayerAngle];
	    		}
		}

    		if (sCode == MAP_GOALCODE) {
			DoGoalScreen();
			done = 1;
			break;
		}

    		if (Spin) {
			Spin >>= 1;
			PlayerAngle += SpinAngle;
			if (PlayerAngle >= INT_ANGLE_360)
	    			PlayerAngle -= INT_ANGLE_360;
			if (PlayerAngle < 0)
	    			PlayerAngle += INT_ANGLE_360;
				CosAngle = CosTable[PlayerAngle];
			SinAngle = SinTable[PlayerAngle];
		}

    		if (SkyCount) {
			if (!(SkyCount & 1))
	    			TopColor = FlashColor;
			else
	    			TopColor = SkyColor;

			SkyCount--;
		}

    		if (DoFlash) {
			if (!SkyCount && drand48()*32768 == SkyNumber) {
	    			SkyCount = 5;
	    			SkyNumber = drand48()*31000 + 1000;
	    		}
		}

		CheckKeyboard();

    		if(keyBoard.escape)
			break;
	
    		CheckMouse(&mouse);

    		if (mouse.mdx < 0) {
			Spin = -mouse.mdx;
			Spin >>= 3;
			SpinAngle = -INT_ANGLE_2 * Spin;
			Spin = 1;
		}

    		if (mouse.mdx > 0) {
			Spin = mouse.mdx;
			Spin >>= 3;
			SpinAngle = INT_ANGLE_2 * Spin;
			Spin = 1;
		}

    		if (mouse.mdy < 0) {
			i = -mouse.mdy;
			i >>= 2;
			i += 16;
			x1 = xPlayer + (int)((CosAngle * i) >> FP_SHIFT);
			y1 = yPlayer + (int)((SinAngle * i) >> FP_SHIFT);
	
			if ((i = CheckHit(xPlayer,yPlayer,PlayerAngle)) == 0) {
		    		xPlayer = x1;
		    		yPlayer = y1;
		    	} else {
			    	if (i == 3)
					continue;
			    	if (i == 1) {
					x1 = xPlayer;
					if (PlayerAngle < INT_ANGLE_180)
				    		j = INT_ANGLE_90;
					else
				    		j = INT_ANGLE_270;
				} else {
					y1 = yPlayer;
					if (PlayerAngle > INT_ANGLE_270 || PlayerAngle < INT_ANGLE_90)
				    		j = 0;
					else
				    		j = INT_ANGLE_180;
				}


	    			if (!CheckHit(xPlayer,yPlayer,j)) {
					xPlayer = x1;
					yPlayer = y1;
				}
	    		}

		}

    		if (mouse.mdy > 0) {
			i = mouse.mdy;
			i >>= 2;
			i += 16;
			x1 = xPlayer - (int)((CosAngle * i) >> FP_SHIFT);
			y1 = yPlayer - (int)((SinAngle * i) >> FP_SHIFT);
			j = PlayerAngle + INT_ANGLE_180;
			if (j >= INT_ANGLE_360)
			    j -= INT_ANGLE_360;

			if ((i = CheckHit(xPlayer,yPlayer,j)) == 0) {
	    			xPlayer = x1;
	    			yPlayer = y1;
	    		} else {
	    			if (i == 3)
					continue;

	    			if (i == 1) {
					x1 = xPlayer;
					if (j < INT_ANGLE_180)
		    				j = INT_ANGLE_90;
					else
		    				j = INT_ANGLE_270;

				} else {
					y1 = yPlayer;
					if (j > INT_ANGLE_270 || j < INT_ANGLE_90)
		    				j = 0;
					else
		    				j = INT_ANGLE_180;
				}


	    			if (!CheckHit(xPlayer,yPlayer,j)) {
					xPlayer = x1;
					yPlayer = y1;
				}

	    		}


		}

    		if (mouse.mButtons & 2) {
			i = CheckHit(xPlayer,yPlayer,PlayerAngle);

			if (i == 1 && xGrid[xMapPosn] == DOOR_SECRETCODE) {
	    			if (xSecretColumn == 0) {
					xSecretmPos = xMapPosn;
					if (iLastX > xPlayer) {
		    				xSecretmPos1 = xMapPosn + 1;
		    				xSecretColumn = 1;
		    				yGrid[xMapPosn] = yGrid[xMapPosn - GRID_WIDTH];
		    			} else {
		    				xSecretmPos1 = xMapPosn - 1;
		    				xSecretColumn = -1;
		    				yGrid[xSecretmPos1] = yGrid[xSecretmPos1 - GRID_WIDTH];
		    			}
				}
	    		}


			if (i == 2 && yGrid[yMapPosn] == DOOR_SECRETCODE) {
	    			if (ySecretColumn == 0) {
					ySecretmPos = yMapPosn;
					if (iLastY > yPlayer) {
		    				ySecretmPos1 = yMapPosn + GRID_WIDTH;
		    				xGrid[yMapPosn] = xGrid[yMapPosn-1];
		    				ySecretColumn = 1;
		    			} else {
		    				ySecretmPos1 = yMapPosn - GRID_WIDTH;
		    				xGrid[ySecretmPos1] = xGrid[ySecretmPos1 - 1];
		    				ySecretColumn = -1;
		    			}
				}
	    		}

			if (i == 1 && xGrid[xMapPosn] == DOOR_XCODE) {
	    			j = FindDoorSlot(xMapPosn);
	    			if (j >= 0) {
					Door[j].mPos = xMapPosn;
					if ((int)iLastX > xPlayer)
		    				i = xMapPosn + 1;
					else
		    				i = xMapPosn - 1;

					Door[j].mCode = xGrid[xMapPosn];
		Door[j].mCode1 = xGrid[i];
		Door[j].mPos1 = i;
		Door[j].ColOffset = 1;
		Door[j].Speed = DoorSpeed;
		Door[j].Type = DOOR_XCODE;
		}
	    }

	if (i == 2 && yGrid[yMapPosn] == DOOR_YCODE) {
	    j = FindDoorSlot(yMapPosn);
	    if (j >= 0) {
		Door[j].mPos = yMapPosn;
		if ((int)iLastY > yPlayer)
		    i = yMapPosn + GRID_WIDTH;
		else
		    i = yMapPosn - GRID_WIDTH;

		Door[j].mCode = yGrid[yMapPosn];
		Door[j].mCode1 = yGrid[i];
		Door[j].mPos1 = i;
		Door[j].ColOffset = 1;
		Door[j].Speed = DoorSpeed;
		Door[j].Type = DOOR_YCODE;
		}

	    }

	}


    if(keyBoard.rightArrow) {
	if (keyBoard.control)
	    PlayerAngle += INT_ANGLE_45;
	else
	    PlayerAngle += INT_ANGLE_6;

	if (PlayerAngle >= INT_ANGLE_360)
	    PlayerAngle -= INT_ANGLE_360;

	CosAngle = CosTable[PlayerAngle];
	SinAngle = SinTable[PlayerAngle];
	}

    if(keyBoard.leftArrow) {
	if (keyBoard.control)
	    PlayerAngle -= INT_ANGLE_45;
	else
	    PlayerAngle -= INT_ANGLE_6;

	if (PlayerAngle < 0)
	    PlayerAngle += INT_ANGLE_360;


	CosAngle = CosTable[PlayerAngle];
	SinAngle = SinTable[PlayerAngle];
	}

    	if(keyBoard.upArrow) {
		x1 = xPlayer + (short)(CosAngle >> (FP_SHIFT - 4));
		y1 = yPlayer + (short)(SinAngle >> (FP_SHIFT - 4));
		if ((i = CheckHit(xPlayer,yPlayer,PlayerAngle)) == 0) {
	    		xPlayer = x1;
	    		yPlayer = y1;
	    	} else {
	    		if (i == 3)
				continue;

	    		if (i == 1) {
				x1 = xPlayer;
				if (PlayerAngle < INT_ANGLE_180)
		    			j = INT_ANGLE_90;
				else
		    			j = INT_ANGLE_270;

			} else {
				y1 = yPlayer;
				if (PlayerAngle > INT_ANGLE_270 || PlayerAngle < INT_ANGLE_90)
		    			j = 0;
				else
		    			j = INT_ANGLE_180;
			}


	    		if (!CheckHit(xPlayer,yPlayer,j)) {
				xPlayer = x1;
				yPlayer = y1;
			}
	    	}


	}

    if(keyBoard.downArrow) {
	x1 = xPlayer - (int)(CosAngle >> (FP_SHIFT - 4));
	y1 = yPlayer - (int)(SinAngle >> (FP_SHIFT - 4));

	j = PlayerAngle + INT_ANGLE_180;
	if (j >= INT_ANGLE_360)
	    j -= INT_ANGLE_360;

	if ((i = CheckHit(xPlayer,yPlayer,j)) == 0) {
	    xPlayer = x1;
	    yPlayer = y1;
	    } else {
	    if (i == 3)
		continue;

	    if (i == 1) {
		x1 = xPlayer;
		if (j < INT_ANGLE_180)
		    j = INT_ANGLE_90;
		else
		    j = INT_ANGLE_270;

		} else {
		y1 = yPlayer;
		if (j > INT_ANGLE_270 || j < INT_ANGLE_90)
		    j = 0;
		else
		    j = INT_ANGLE_180;
		}


	    if (!CheckHit(xPlayer,yPlayer,j)) {
		xPlayer = x1;
		yPlayer = y1;
		}
	    }

	}

    if (keyBoard.letA) {
	if (CenterRow > 90) {
	    CenterRow--;
	    }
	}

    if (keyBoard.letS) {
	if (CenterRow < 150) {
	    CenterRow++;
	    }
	}

    t1 = CLOCK_PTR;
    DrawView(xPlayer,yPlayer,PlayerAngle);
    tDraw += CLOCK_PTR - t1;
    frames++;
    }

	tStart = CLOCK_PTR - tStart;

	fprintf(stderr, "trying to wrap up\n");
	WrapUp();


	printf("\nFrames  : %ld\n",frames);
	printf("tDrawRtn  : %ld\n",tDraw);
	printf("tTotal    : %ld\n",tStart);
	printf("txRay     : %ld\n",txRay);
	printf("tyRay     : %ld\n",tyRay);
	printf("tDrawWalls: %ld\n",tDOW);
	printf("tFlipPage : %ld\n",tFlip);
}

