/*		   ACK-3D ( Animation Construction Kit 3D )		      */
/* Object routines    */
/* 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"

/****************************************************************************
** Runs the list of objects generated during xRay and yRay to determine if **
** they are really visible, what column should be displayed and which	   **
** bitmap to use.							   **
**									   **
** First the object coordinates are translated to be 0,0 relative to	   **
** the player coordinates.						   **
**									   **
** Next the object coordinates are rotated to the player angle. This	   **
** allows the tangent of the angle to be used to determine the column of   **
** the bitmap. Some checks are made to insure the column and distance are  **
** not out of bounds.							   **
**									   **
** The width of the object is determined from the same table as the height **
** to keep the object (which is 64x64 for now) in the same ratio as the	   **
** walls.								   **
**									   **
** If the object has multiple sides the angle is used to determine which   **
** side to display. This value is then used to get the correct bitmap	   **
** number to display. The current object center row is also used to allow  **
** objects to bounce up and down.					   **
**									   **
** Finally the objects is displayed if it will fit on the display and the  **
** distance is closer than the corresonding wall slice.			   **
**									   **
****************************************************************************/
void FindObject(int xPlayer,int yPlayer,int PlayerAngle)
{
    int	    i,j,count,SaveCenter;
    int	    ObjX,ObjY,ObjNum;
    int	    NewX,NewY;
    int	    MaxOpp,Column;
    int	    wt,ObjIndex;
    long    deltax,deltay;
    long    xp,yp,distance;
    long    SinValue,CosValue;

if (!TotalObjects)	/* No objects found during ray casts */
    return;

SinValue = SinTable[PlayerAngle];
CosValue = CosTable[PlayerAngle];

for (i = 0; i < TotalObjects; i++)
    {
    ObjIndex = ObjNumber[i];
    ObjNum = ObjList[ObjIndex].bmNum[ObjList[ObjIndex].CurNum];
    ObjX = ObjList[ObjIndex].x;
    ObjY = ObjList[ObjIndex].y;

/* Translate coordinates to 0,0 */
    NewX = ObjX - xPlayer;
    NewY = ObjY - yPlayer;


/* Rotate coordinates to current player angle */
    xp = ((NewX * CosValue) + (NewY * SinValue)) >> FP_SHIFT;
    yp = ((NewY * CosValue) - (NewX * SinValue)) >> FP_SHIFT;

    deltax = xp;
    deltay = yp;
    distance = long_sqrt((deltax * deltax) + (deltay * deltay));

    MaxOpp = ((LongTanTable[INT_ANGLE_30] * (long)deltax) >> FP_SHIFT);

    if (NewY < ObjY)
	MaxOpp = -MaxOpp;

    Column = 160;

    if (MaxOpp)
	Column = 160 - ((deltay * 160) / MaxOpp);

    yp = ViewCosTable[Column];
    xp = distance;
    if (yp)
	{
	distance = distance * yp;

	xp = distance >> 14;
	if (distance - (xp << 14) >= 8096)
	    xp++;

	}
    distance = xp;

    if (distance < 0)
	continue;

    if (distance >= (MAX_DISTANCE - 10))
	distance = MAX_DISTANCE-11;

    wt = DistanceTable[distance];

    if (wt > 300)
	continue;

    if (wt < 16) wt = 16;
    if (wt > 300) wt = 300;

    yp = AdjustTable[distance];
    xp = 0;
    wt >>= 1;
    NewX = Column;

    if (ObjList[ObjIndex].Sides)
	ObjNum =
	 ObjList[ObjIndex].bmNum[((PlayerAngle / ObjList[ObjIndex].Sides) & 7)];

    SaveCenter = CenterRow;
    CenterRow = ObjList[ObjIndex].VidRow;

    for (Column = NewX - wt; Column < NewX + wt; Column++)
	{
	if (Column >= 0 && Column < 320)
	    {
	    if (distance < (Walls[Column].Distance + 10))
		DrawOneObject(ObjNum,xp >> FP_SHIFT,distance,Column,PageNum);
	    }
	xp += yp;
	}

    CenterRow = SaveCenter;
    }

}


/****************************************************************************
**									   **
****************************************************************************/
long CheckObjects(int xPlayer,int yPlayer,int PlayerAngle)
{
    int	    i,j,count;
    int	    mPos,ObjX,ObjY,ObjNum;
    int	    NewX,NewY;
    int	    MaxOpp,Column;
    int	    wt,ObjIndex;
    long    MinDistance;
    long    xp,yp,distance;
    long    SinValue,CosValue;

MinDistance = 3000000L;

if (!TotalObjects)
    return(MinDistance);

SinValue = SinTable[PlayerAngle];
CosValue = CosTable[PlayerAngle];

for (i = 0; i < TotalObjects; i++)
    {
    ObjIndex = ObjNumber[i];

    if (Grid[ObjList[ObjIndex].mPos] & 0x40)
	continue;

    ObjX = ObjList[ObjIndex].x;
    ObjY = ObjList[ObjIndex].y;

/* Translate coordinates to 0,0 */
    NewX = ObjX - xPlayer;
    NewY = ObjY - yPlayer;

/* Rotate coordinates to current player angle */
    xp = ((NewX * CosValue) + (NewY * SinValue)) >> FP_SHIFT;
    yp = ((NewY * CosValue) - (NewX * SinValue)) >> FP_SHIFT;

    distance = long_sqrt((xp * xp) + (yp * yp));

    MaxOpp = ((LongTanTable[INT_ANGLE_30] * xp) >> FP_SHIFT);
    if (NewY < ObjY)
	MaxOpp = -MaxOpp;

    Column = 160;

    if (MaxOpp)
	Column = 160 - ((yp * 160) / MaxOpp);

    yp = ViewCosTable[Column];
    xp = distance;
    if (yp)
	{
	distance = distance * yp;

	xp = distance >> 14;
	if (distance - (xp << 14) >= 8096)
	    xp++;

	}
    distance = xp;

    if (distance < 0)
	continue;

    if (distance >= MAX_DISTANCE)
	distance = MAX_DISTANCE-1;

    if (DistanceTable[distance] > 300)
	continue;

    if (distance < MinDistance)
	MinDistance = distance;

    }

return(MinDistance);
}

/****************************************************************************
**									   **
****************************************************************************/
void MoveObject(int Index,int dx,int dy)
{
    int	    Pos,NewPos,x1,y1;

Pos = ObjList[Index].mPos;
ObjList[Index].y += dy;
ObjList[Index].x += dx;

x1 = ObjList[Index].x >> 6;
y1 = ObjList[Index].y >> 6;
NewPos = (y1 * GRID_WIDTH) + x1;
if (NewPos != Pos)
    {
    xObjGrid[Pos] = xObjGrid[Pos-1];
    xObjGrid[Pos+1] = xObjGrid[Pos+2];
    yObjGrid[Pos] = yObjGrid[Pos-GRID_WIDTH];
    yObjGrid[Pos+GRID_WIDTH] = yObjGrid[Pos + (GRID_WIDTH << 1)];
    Grid[Pos] &= 0x7F;

    ObjList[Index].mPos = NewPos;

    xObjGrid[NewPos] = Index;
    xObjGrid[NewPos+1] = Index;
    yObjGrid[NewPos] = Index;
    yObjGrid[NewPos+GRID_WIDTH] = Index;
    Grid[NewPos] |= 0x80;
    }

}

/****************************************************************************
**									   **
****************************************************************************/
void CheckObjectMovement(void)
{
	    int	    i,speed;
	    int	    dx,dy,dir;
	    int	    NewDx,NewDy;

for (i = 1; i < MaxObjects; i++)
    {
    if (!ObjList[i].Active)
	continue;

    if (!(speed = ObjList[i].Speed))
	continue;

    dir = ObjList[i].Dir;

    if (dir == 8)
	{
	ObjList[i].VidRow -= speed;
	if (ObjList[i].VidRow < 110)
	    {
	    ObjList[i].VidRow = 110;
	    ObjList[i].Dir = 9;
	    }
	continue;
	}

    if (dir == 9)
	{
	ObjList[i].VidRow += speed;
	if (ObjList[i].VidRow > 130)
	    {
	    ObjList[i].VidRow = 130;
	    ObjList[i].Dir = 8;
	    }
	continue;
	}

    if (dir == 10)
	{
	dx = ObjList[i].CurNum + 1;
	if (dx > ObjList[i].MaxNum)
	    dx = 0;

	ObjList[i].CurNum = dx;
	continue;
	}

    dx = DirDx[dir] * speed;
    dy = DirDy[dir] * speed;

    NewDx = ObjList[i].x + dx;
    NewDy = ObjList[i].y + dy;

    if (NewDy < 96 ||
	NewDy > 4000 ||
	NewDx < 96 ||
	NewDx > 4000 ||
	CheckHit(ObjList[i].x,ObjList[i].y,DirAngle[dir]))
	{
	dir += 2;
	if (dir > 7)
	    dir = 0;

	if (CheckHit(ObjList[i].x,ObjList[i].y,DirAngle[dir]))
	    {
	    dir -= 4;
	    if (dir < 0)
		dir = 7;
	    }

	ObjList[i].Dir = dir;
	continue;
	}

    MoveObject(i,dx,dy);
    }

}

