/******************* ( Animation Construction Kit 3D ) ***********************/
/*			     Door Routines				     */
/*  CopyRight (c) 1993	   Author: Lary Myers				     */
/*****************************************************************************/

#include <stdlib.h>
#include <stdio.h>
#include <dos.h>
#include <mem.h>
#include <alloc.h>
#include <io.h>
#include <fcntl.h>
#include <time.h>
#include <string.h>
#include <sys\stat.h>
#include "ack3d.h"
#include "ackeng.h"
#include "ackext.h"

/****************************************************************************
** Check all the doors to see what state they are in. If a door's column   **
** offset is non-zero then it is either opening or closing, so add in the  **
** speed of the door and check for fully open and fully closed conditions. **
**									   **
**									   **
****************************************************************************/
void CheckDoors(ACKENG *ae)
{
	 int	i,MapPosn,mPos,mPos1;
	 int	column,mx,my,DeltaGrid;
	 int	xPlayer,yPlayer;
unsigned char	mCode,mCode1;

xPlayer = ae->xPlayer;
yPlayer = ae->yPlayer;

for (i = 0; i < MAX_DOORS; i++)
    {
    if (ae->Door[i].ColOffset)
	{
	ae->Door[i].ColOffset += ae->Door[i].Speed;
	mPos = ae->Door[i].mPos;
	mPos1 = ae->Door[i].mPos1;

   /* Door is closing and is visible. Put old codes back to make non-passable */
	if (ae->Door[i].Speed < 0 && ae->Door[i].ColOffset < 65)
	    {
	    MapPosn = (yPlayer & 0xFFC0) + (xPlayer >> 6);
	    if (MapPosn == mPos ||
		MapPosn == mPos1)
		{
		ae->Door[i].ColOffset -= ae->Door[i].Speed;
		continue;
		}

	    if (ae->Door[i].Type == DOOR_XCODE)
		{
		ae->xGrid[mPos]	 = ae->Door[i].mCode;
		ae->xGrid[mPos1] = ae->Door[i].mCode1;
		}
	    else
		{
		ae->yGrid[mPos]	 = ae->Door[i].mCode;
		ae->yGrid[mPos1] = ae->Door[i].mCode1;
		}

/* Door is close enough to fully closed to get rid of the door from the array */
	    if (ae->Door[i].ColOffset < 3)
		{
		ae->Door[i].ColOffset = 0;
		ae->Door[i].mPos      = -1;
		ae->Door[i].mPos1     = -1;
		ae->Door[i].Flags     = 0;
		}

	    }

    /* Door is fully open, reverse the speed to begin closing */
	if (ae->Door[i].ColOffset > 0xA0)
	    {
	    ae->Door[i].Speed = -ae->Door[i].Speed;
	    ae->Door[i].Flags &= ~DOOR_OPENING;
	    ae->Door[i].Flags |= DOOR_CLOSING;
	    }

	}
    }


/* Now check for any action occuring in a secret door. This is currently  */
/* setup to handle only one door at a time in the X and Y directions, but */
/* it should be fairly straightforward to use a list of doors, similiar	  */
/* to normal doors, to handle more than one.				  */
if (xSecretColumn)
    {
    if (xSecretColumn > 0)	    /* See if the door is to the right of us */
	{
	mPos = xSecretmPos1;
	DeltaGrid = -1;
	xSecretColumn += ae->DoorSpeed;
	}
    else
	{
	mPos = xSecretmPos;
	DeltaGrid = 0;
	xSecretColumn -= ae->DoorSpeed;
	}

    my = mPos & 0xFFC0;
    mx = (mPos - my) << 6;

    if (abs(xSecretColumn) > GRID_SIZE)	    /* Beyond one grid square */
	{
	mx += xSecretColumn;
	my = my + (mx >> 6);
	if (ae->xGrid[my])			/* No further, an obstruction */
	    {
	    ae->xGrid[xSecretmPos] = 0;
	    ae->xGrid[xSecretmPos1] = 0;
	    my += DeltaGrid;
	    ae->xGrid[my] = ae->NonSecretCode;
	    ae->xGrid[my+1] = ae->NonSecretCode;
	    ae->yGrid[my] = ae->NonSecretCode;
	    ae->yGrid[my + GRID_WIDTH] = ae->NonSecretCode;
	    xSecretColumn = 0;
	    }
	else
	    {
	    if (my != mPos)
		{
		ae->xGrid[xSecretmPos] = 0;
		ae->xGrid[xSecretmPos1] = 0;
		if (xSecretColumn > 0)
		    {
		    xSecretColumn -= 63;
		    ae->xGrid[my] = DOOR_TYPE_SECRET + 1;
		    xSecretmPos1 = my;
		    my--;
		    ae->xGrid[my] = DOOR_TYPE_SECRET + 1;
		    xSecretmPos = my;
		    }
		else
		    {
		    xSecretColumn += 63;
		    ae->xGrid[my] = DOOR_TYPE_SECRET + 1;
		    ae->xGrid[my+1] = DOOR_TYPE_SECRET + 1;
		    xSecretmPos = my;
		    xSecretmPos = my+1;
		    }
		}
	    } /* End if (xGrid[my]) ... else ...	 */
	}     /* End if (abs(xSecretColumn) > GRID_SIZE) */
    }	      /* End if (xSecretColumn)			 */

/* Perform same process on a secret door that may be moving in the Y */
/* direction. The same door can move either way, depending on which  */
/* angle the player struck it at.				     */
if (ySecretColumn)
    {
    if (ySecretColumn > 0)
	{
	mPos = ySecretmPos1;
	DeltaGrid = -GRID_WIDTH;
	ySecretColumn += ae->DoorSpeed;
	}
    else
	{
	mPos = ySecretmPos;
	DeltaGrid = 0;
	ySecretColumn -= ae->DoorSpeed;
	}

    my = mPos & 0xFFC0;
    mx = (mPos - my) << 6;

    if (abs(ySecretColumn) > GRID_SIZE)
	{
	my += ySecretColumn;
	my = (my & 0xFFC0) + (mx >> 6);
	if (ae->yGrid[my])
	    {
	    ae->yGrid[ySecretmPos] = 0;
	    ae->yGrid[ySecretmPos1] = 0;
	    my += DeltaGrid;
	    ae->xGrid[my] = ae->NonSecretCode;
	    ae->xGrid[my+1] = ae->NonSecretCode;
	    ae->yGrid[my] = ae->NonSecretCode;
	    ae->yGrid[my + GRID_WIDTH] = ae->NonSecretCode;
	    ySecretColumn = 0;
	    }
	else
	    {
	    if (my != mPos)
		{
		ae->yGrid[ySecretmPos] = 0;
		ae->yGrid[ySecretmPos1] = 0;
		if (ySecretColumn > 0)
		    {
		    ySecretColumn -= 63;
		    ae->yGrid[my] = DOOR_TYPE_SECRET + 1;
		    ySecretmPos1 = my;
		    my -= GRID_WIDTH;
		    ae->yGrid[my] = DOOR_TYPE_SECRET + 1;
		    ySecretmPos = my;
		    }
		else
		    {
		    ySecretColumn += 63;
		    ae->yGrid[my] = DOOR_TYPE_SECRET + 1;
		    ae->yGrid[my+GRID_WIDTH] = DOOR_TYPE_SECRET + 1;
		    ySecretmPos = my;
		    ySecretmPos = my+GRID_WIDTH;
		    }
		}
	    }
	}
    }

}

/****************************************************************************
** Locate a door from its Map coordinate and return the index to the	   **
** caller.								   **
**									   **
****************************************************************************/
int FindDoor(int MapPosn,ACKENG *ae)
{
    int	    index;

for (index = 0; index < MAX_DOORS; index++)
    {
    if (MapPosn == ae->Door[index].mPos || MapPosn == ae->Door[index].mPos1)
	return(index);
    }

return(-1);
}


/****************************************************************************
** Find an empty slot for a door. If the door already occupies a slot and  **
** it is in a non-closed state then return error.			   **
**									   **
****************************************************************************/
int FindDoorSlot(int MapPosn,ACKENG *ae)
{
    int	    index;

index = FindDoor(MapPosn,ae);
if (index >= 0 && ae->Door[index].ColOffset)
    return(-1);

for (index = 0; index < MAX_DOORS; index++)
    {
    if (ae->Door[index].mPos == -1)
	return(index);

    }

return(-1);
}

/****************************************************************************
** The application performs this call to see if the POV is close enough to **
** a door to begin opening it. (A good time to make this call would be	   **
** when the POV moves). If a door is activated a return code tells the	   **
** application what kind of door it was (for purposes of sound, etc.)	   **
**									   **
****************************************************************************/
int AckCheckDoorOpen(int xPlayer,int yPlayer,int PlayerAngle,ACKENG *ae)
{
    int	    i,j,DoorCode;

DoorCode = POV_NODOOR;	    /* Default - assumes no doors found */

i = AckCheckHit(xPlayer,yPlayer,PlayerAngle,ae);

/* Check secret doors along the X walls */
if (i == 1 && ae->xGrid[xMapPosn] & DOOR_TYPE_SECRET)
    {
    if (xSecretColumn == 0)
	{
	DoorCode = POV_XSECRETDOOR;

	if (ae->xGrid[xMapPosn] & DOOR_LOCKED)
	    return(DoorCode | POV_DOORLOCKED);

	xSecretmPos = xMapPosn;
	if (iLastX > xPlayer)
	    {
	    xSecretmPos1 = xMapPosn + 1;
	    LastMapPosn = xMapPosn;
	    xSecretColumn = 1;
	    ae->yGrid[xMapPosn] = ae->yGrid[xMapPosn - GRID_WIDTH];
	    }
	else
	    {
	    LastMapPosn = xSecretmPos1 = xMapPosn - 1;
	    xSecretColumn = -1;
	    ae->yGrid[xSecretmPos1] = ae->yGrid[xSecretmPos1 - GRID_WIDTH];
	    }
	}

    }

/* Check secret doors along the Y walls */
if (i == 2 && ae->yGrid[yMapPosn] & DOOR_TYPE_SECRET)
    {
    if (ySecretColumn == 0)
	{
	DoorCode = POV_YSECRETDOOR;

	if (ae->yGrid[yMapPosn] & DOOR_LOCKED)
	    return(DoorCode | POV_DOORLOCKED);

	ySecretmPos = yMapPosn;
	if (iLastY > yPlayer)
	    {
	    LastMapPosn = yMapPosn;
	    ySecretmPos1 = yMapPosn + GRID_WIDTH;
	    ae->xGrid[yMapPosn] = ae->xGrid[yMapPosn-1];
	    ySecretColumn = 1;
	    }
	else
	    {
	    LastMapPosn = ySecretmPos1 = yMapPosn - GRID_WIDTH;
	    ae->xGrid[ySecretmPos1] = ae->xGrid[ySecretmPos1 - 1];
	    ySecretColumn = -1;
	    }
	}
    }

/* Check doors along the X walls */
if (i == 1 && (ae->xGrid[xMapPosn] & 0xFF) == DOOR_XCODE)
    {
    j = FindDoorSlot(xMapPosn,ae);
    if (j >= 0)
	{
	DoorCode = POV_XDOOR;

	LastMapPosn = ae->Door[j].mPos = xMapPosn;
	if ((int)iLastX > xPlayer)
	    i = xMapPosn + 1;
	else
	    LastMapPosn = i = xMapPosn - 1;

	if (ae->xGrid[xMapPosn] & DOOR_LOCKED)
	    {
	    ae->Door[j].mPos = -1;
	    return(DoorCode | POV_DOORLOCKED);
	    }

	ae->Door[j].mCode = ae->xGrid[xMapPosn];
	ae->Door[j].mCode1 = ae->xGrid[i];
	ae->Door[j].mPos1 = i;
	ae->Door[j].ColOffset = 1;
	ae->Door[j].Speed = ae->DoorSpeed;
	ae->Door[j].Type = DOOR_XCODE;
	ae->Door[j].Flags = DOOR_OPENING;
	}
    }

/* Check doors along the Y walls */
if (i == 2 && (ae->yGrid[yMapPosn] & 0xFF) == DOOR_YCODE)
    {
    j = FindDoorSlot(yMapPosn,ae);
    if (j >= 0)
	{
	DoorCode = POV_YDOOR;
	LastMapPosn = ae->Door[j].mPos = yMapPosn;
	if ((int)iLastY > yPlayer)
	    i = yMapPosn + GRID_WIDTH;
	else
	    LastMapPosn = i = yMapPosn - GRID_WIDTH;

	if (ae->yGrid[yMapPosn] & DOOR_LOCKED)
	    {
	    ae->Door[j].mPos = -1;
	    return(DoorCode | POV_DOORLOCKED);
	    }

	ae->Door[j].mCode = ae->yGrid[yMapPosn];
	ae->Door[j].mCode1 = ae->yGrid[i];
	ae->Door[j].mPos1 = i;
	ae->Door[j].ColOffset = 1;
	ae->Door[j].Speed = ae->DoorSpeed;
	ae->Door[j].Type = DOOR_YCODE;
	ae->Door[j].Flags = DOOR_OPENING;
	}
    }

return(DoorCode);
}


