// This source file contains the functions needed to process doors.
// (c) 1995 ACK Software (Lary Myers)
#include <windows.h>
#include <stdlib.h>
#include <stdio.h>
#include <dos.h>
#include <mem.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"

extern DOORS *gDoor;

//北北北北北北北北北北北北北北北北北北北北北北北北北北北北北北北北北北北北
// Check all the active doors to see what current state they are in. If a
// door's column offset is non-zero, it is either opening or closing,
// so the speed of the door is added in and the door is checked to
// see if it is fully opened or fully closed.
//北北北北北北北北北北北北北北北北北北北北北北北北北北北北北北北北北北北北
void CheckDoors (void)
{
    short   i, MapPosn, mPos, mPos1;
    short   mx, my, DeltaGrid;
    short   xPlayer, yPlayer;
    DOORS   *dPtr;

xPlayer = xPglobal;
yPlayer = yPglobal;
dPtr = &gDoor[0];

for (i = 0; i < MAX_DOORS; i++)
    {
    if (dPtr->ColOffset)    // Door is not closed
        {  // Add speed to door column offset
        dPtr->ColOffset += dPtr->Speed;
        mPos = dPtr->mPos;       // Get grid position of door
        mPos1 = dPtr->mPos1;

        // Door is closing and is visible. Put old codes back to make non-passable
        if (dPtr->Speed < 1 && dPtr->ColOffset < 65)
            {  // Get corner of grid
            MapPosn = (yPlayer & 0xFFC0) + (xPlayer >> BITMAP_SHIFT);
            // Is player in same grid square that the door is in?
            if (MapPosn == mPos || MapPosn == mPos1)
                {
                dPtr->ColOffset -= dPtr->Speed;  // Reduce column offset
                continue;
                }
            // Is the door along an x wall
            if (dPtr->Type == DOOR_XCODE)
                {  // Store bitmap ids for doors
                xGridGlobal[mPos] = dPtr->mCode;
                xGridGlobal[mPos1] = dPtr->mCode1;
                }
            else
                {  // Door is along a y wall
                yGridGlobal[mPos] = dPtr->mCode;
                yGridGlobal[mPos1] = dPtr->mCode1;
                }

            // Door is close enough to fully closed to get rid
            // of the door from the array
            if (dPtr->ColOffset < 3)
                {
                dPtr->ColOffset = 0;  // Close door
                dPtr->mPos = -1;
                dPtr->mPos1 = -1;
                dPtr->Flags = 0;
                }
            }
          // Door is fully opened--time to start closing it
        if (dPtr->ColOffset > 0xA0)
            {
            dPtr->Speed = -dPtr->Speed;   // Start to reduce speed
            dPtr->Flags &= ~DOOR_OPENING; // Set flag to indicate door closing
            dPtr->Flags |= DOOR_CLOSING;
            }
        }
    dPtr++;    // Advance to check next door
    }

//=============================================================================
// 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 += aeGlobal->DoorSpeed;
        }
    else
        {
        mPos = xSecretmPos;
        DeltaGrid = 0;
        xSecretColumn -= aeGlobal->DoorSpeed;
        }

    my = mPos & 0xFFC0;
    mx = (mPos - my) << 6;

    if (abs (xSecretColumn) > BITMAP_WIDTH)   // Beyond one grid square
        {
        mx += xSecretColumn;
        my = my + (mx >> BITMAP_SHIFT);
        if (xGridGlobal[my])  // No further, an obstruction
            {
            xGridGlobal[xSecretmPos] = 0;
            xGridGlobal[xSecretmPos1] = 0;
            my += DeltaGrid;
            xGridGlobal[my] = aeGlobal->NonSecretCode;
            xGridGlobal[my + 1] = aeGlobal->NonSecretCode;
            yGridGlobal[my] = aeGlobal->NonSecretCode;
            yGridGlobal[my + GRID_WIDTH] = aeGlobal->NonSecretCode;
            xSecretColumn = 0;
            }
        else
            {
            if (my != mPos)
                {
                xGridGlobal[xSecretmPos] = 0;
                xGridGlobal[xSecretmPos1] = 0;
                if (xSecretColumn > 0)
                    {
                    xSecretColumn -= (BITMAP_WIDTH - 1);
                    xGridGlobal[my] = DOOR_TYPE_SECRET + 1;
                    xSecretmPos1 = my;
                    my--;
                    xGridGlobal[my] = DOOR_TYPE_SECRET + 1;
                    xSecretmPos = my;
                    }
                else
                    {
                    xSecretColumn += (BITMAP_WIDTH - 1);
                    xGridGlobal[my] = DOOR_TYPE_SECRET + 1;
                    xGridGlobal[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 += aeGlobal->DoorSpeed;
        }
    else
        {
        mPos = ySecretmPos;
        DeltaGrid = 0;
        ySecretColumn -= aeGlobal->DoorSpeed;
        }

    my = mPos & 0xFFC0;
    mx = (mPos - my) << 6;

    if (abs (ySecretColumn) > BITMAP_WIDTH)
        {
        my += ySecretColumn;
        my = (my & 0xFFC0) + (mx >> 6);
        if (yGridGlobal[my])
            {
            yGridGlobal[ySecretmPos] = 0;
            yGridGlobal[ySecretmPos1] = 0;
            my += DeltaGrid;
            xGridGlobal[my] = aeGlobal->NonSecretCode;
            xGridGlobal[my + 1] = aeGlobal->NonSecretCode;
            yGridGlobal[my] = aeGlobal->NonSecretCode;
            yGridGlobal[my + GRID_WIDTH] = aeGlobal->NonSecretCode;
            ySecretColumn = 0;
            }
        else
            {
            if (my != mPos)
                {
                yGridGlobal[ySecretmPos] = 0;
                yGridGlobal[ySecretmPos1] = 0;
                if (ySecretColumn > 0)
                    {
                    ySecretColumn -= (BITMAP_WIDTH - 1);
                    yGridGlobal[my] = DOOR_TYPE_SECRET + 1;
                    ySecretmPos1 = my;
                    my -= GRID_WIDTH;
                    yGridGlobal[my] = DOOR_TYPE_SECRET + 1;
                    ySecretmPos = my;
                    }
                else
                    {
                    ySecretColumn += (BITMAP_WIDTH - 1);
                    yGridGlobal[my] = DOOR_TYPE_SECRET + 1;
                    yGridGlobal[my + GRID_WIDTH] = DOOR_TYPE_SECRET + 1;
                    ySecretmPos = my;
                    ySecretmPos = my + GRID_WIDTH;
                    }
                }
            }
        }
    }

}


//北北北北北北北北北北北北北北北北北北北北北北北北北北北北北北北北北北
// Internal function called by FindDoorSlot(). This function
// locates a door from its map coordinate and return the index.
//北北北北北北北北北北北北北北北北北北北北北北北北北北北北北北北北北北
short FindDoor (short MapPosn)
{
    short   index;

for (index = 0; index < MAX_DOORS; index++)
    {
    if (MapPosn == gDoor[index].mPos ||
        MapPosn == gDoor[index].mPos1)
        {
        return (index);
        }
    }
return (-1);
}

//北北北北北北北北北北北北北北北北北北北北北北北北北北北北北北北北北北
// Internal routine called by AckCheckDoorOpen() This function
// finds an empty slot for a door. If the door already occupies a slot
// and it is in a non-closed state, an error is returned.
//北北北北北北北北北北北北北北北北北北北北北北北北北北北北北北北北北北
short FindDoorSlot (short MapPosn)
{
    short   index;

index = FindDoor (MapPosn);
if (index >= 0 && gDoor[index].ColOffset)
    return (-1);

for (index = 0; index < MAX_DOORS; index++)
    {
    if (gDoor[index].mPos == -1)
        return (index);
    }
return (-1);
}

//北北北北北北北北北北北北北北北北北北北北北北北北北北北北北北北北北北北北
// Checks directly in front of the POV to see if a door is there. If so,
// and the door is not locked, the door is set to begin opening.
//北北北北北北北北北北北北北北北北北北北北北北北北北北北北北北北北北北北北
short AckCheckDoorOpen (short xPlayer, short yPlayer, short PlayerAngle)
{
    short   i,j,DoorCode;

DoorCode = POV_NODOOR;
// Check to see if player is close to a wall
i = AckCheckHit (xPlayer, yPlayer, PlayerAngle);
// A secret door is found along an x wall
if (i == 1 && xGridGlobal[xMapPosn] & DOOR_TYPE_SECRET)
    {
    if (xSecretColumn == 0) // Player is on the right side of door
        {
        DoorCode = POV_XSECRETDOOR;
        // Secret door is locked; can't open
        if (xGridGlobal[xMapPosn] & DOOR_LOCKED)
            return (DoorCode | POV_DOORLOCKED);
        // Get grid map position that corresponds with the x wall
        // position of where the door starts
        xSecretmPos = xMapPosn;
        if (iLastX > xPlayer)   // Door is to the right of player
            {
            xSecretmPos1 = xMapPosn + 1;
            LastMapPosn = xMapPosn;
            xSecretColumn = 1;   // Set to indicate player is on right side
            yGridGlobal[xMapPosn] = yGridGlobal[xMapPosn - GRID_WIDTH];
            }
        else
            { // Door is to the left of the player
            LastMapPosn = xSecretmPos1 = xMapPosn - 1;
            xSecretColumn = -1;
            yGridGlobal[xSecretmPos1] = yGridGlobal[xSecretmPos1 - GRID_WIDTH];
            }
        }
    }

// A secret door is found along a y wall
if (i == 2 && yGridGlobal[yMapPosn] & DOOR_TYPE_SECRET)
    {
    if (ySecretColumn == 0)
        {
        DoorCode = POV_YSECRETDOOR;

        if (yGridGlobal[yMapPosn] & DOOR_LOCKED)
            return (DoorCode | POV_DOORLOCKED);

        ySecretmPos = yMapPosn;
        if (iLastY > yPlayer)
            {
            LastMapPosn = yMapPosn;
            ySecretmPos1 = yMapPosn + GRID_WIDTH;
            xGridGlobal[yMapPosn] = xGridGlobal[yMapPosn - 1];
            ySecretColumn = 1;
            }
        else
            {
            LastMapPosn = ySecretmPos1 = yMapPosn - GRID_WIDTH;
            xGridGlobal[ySecretmPos1] = xGridGlobal[ySecretmPos1 - 1];
            ySecretColumn = -1;
            }
        }
    }

// A sliding or split door is found along an x wall
if (i == 1 && (xGridGlobal[xMapPosn] & (DOOR_TYPE_SLIDE + DOOR_TYPE_SPLIT)))
    {
    j = FindDoorSlot (xMapPosn);
    if (j >= 0)
        {
        DoorCode = POV_XDOOR;

        LastMapPosn = gDoor[j].mPos = xMapPosn;
        if ((short) iLastX > xPlayer)
            i = xMapPosn + 1;
        else
            LastMapPosn = i = xMapPosn - 1;
        if (xGridGlobal[xMapPosn] & DOOR_LOCKED)
            {
            gDoor[j].mPos = -1;
            return (DoorCode | POV_DOORLOCKED);
            }
        // Update door data structure
        gDoor[j].mCode = xGridGlobal[xMapPosn];
        gDoor[j].mCode1 = xGridGlobal[i];
        gDoor[j].mPos1 = i;
        gDoor[j].ColOffset = 1;
        gDoor[j].Speed = aeGlobal->DoorSpeed;
        gDoor[j].Type = DOOR_XCODE;
        gDoor[j].Flags = DOOR_OPENING;
        }
    }

// A sliding or split door is found along a y wall
if (i == 2 && (yGridGlobal[yMapPosn] & (DOOR_TYPE_SLIDE + DOOR_TYPE_SPLIT)))
    {
    j = FindDoorSlot (yMapPosn);
    if (j >= 0)
        {
        DoorCode = POV_YDOOR;
        LastMapPosn = gDoor[j].mPos = yMapPosn;
        if ((short) iLastY > yPlayer)
            i = yMapPosn + GRID_WIDTH;
        else
            LastMapPosn = i = yMapPosn - GRID_WIDTH;

        if (yGridGlobal[yMapPosn] & DOOR_LOCKED)
            {
            gDoor[j].mPos = -1;
            return (DoorCode | POV_DOORLOCKED);
            }

        gDoor[j].mCode = yGridGlobal[yMapPosn];
        gDoor[j].mCode1 = yGridGlobal[i];
        gDoor[j].mPos1 = i;
        gDoor[j].ColOffset = 1;
        gDoor[j].Speed = aeGlobal->DoorSpeed;
        gDoor[j].Type = DOOR_YCODE;
        gDoor[j].Flags = DOOR_OPENING;
        }
    }
return (DoorCode);
}
// **** End of Source ****

