/****************************************************************************
*
* RAIN.C
*
*    VERSION : 00.00
*    CREATED : 13/05/98
*   MODIFIED : 13/05/98
*	   TABS : 5
*
* DESCRIPTION
*
*****************************************************************************/

/*---------------------------------------------------------------------------
 * Import Headers
\*--------------------------------------------------------------------------*/

#ifdef PSX_VERSION
#include "..\spec_psx\typedefs.h"
#include "..\spec_psx\malloc.h"
#include "..\spec_psx\memory.h"
#include "..\spec_psx\gpu.h"
#else
#include "../specific/stypes.h"
#endif

#include "items.h"
#include "room.h"

#ifdef PSX_VERSION
//#include "..\spec_psx\include.h"
#include "..\spec_psx\maths.h"
#endif

#ifdef PC_VERSION
typedef unsigned short WORD;
typedef int LONG;
typedef unsigned char UBYTE;
#endif

/*---------------------------------------------------------------------------
 * Constants
\*--------------------------------------------------------------------------*/

#define OUTSIDE_Z 32	// z depth of outside table

#define X 0
#define Y 1
#define Z	2
#define XYZ 3

#define CENTREX 256
#define CENTREY 120

/*---------------------------------------------------------------------------
 * Externals
\*--------------------------------------------------------------------------*/


#ifdef PSX_VERSION
	extern VECTOR3D CamPos, CamTgt;
#endif

extern WORD rcossin_tbl[];
extern	long	SmokeWindX, SmokeWindZ;

/*---------------------------------------------------------------------------
 * Globals
\*--------------------------------------------------------------------------*/

#ifdef PSX_VERSION
	LONG RainYAdd=1024;
	LONG RainAngDiv=1023;
	LONG RainAngAdd=512;
	LONG scale;
#endif

/*---------------------------------------------------------------------------
 * Locals
\*--------------------------------------------------------------------------*/

char *OutsideRoomTable;
short OutsideRoomOffsets[27*27];	// -1 = no rooms
short IsRoomOutsideNo;

/*---------------------------------------------------------------------------
 * Macros
\*--------------------------------------------------------------------------*/

/*---------------------------------------------------------------------------
 * Local Functions
\*--------------------------------------------------------------------------*/

/****************************************************************************
* IsRoomOutside
*
* SYNOPSIS
*	LONG IsRoomOutside(LONG x, LONG y, LONG z)
*
* PURPOSE
*	Determines if a room, at a given position, is outside
*
* INPUTS
*	x	= world x
*	y	= world y
*	z	= world z
*
* RETURNS
*	!0 if room is outside
*/

#ifdef PSX_VERISION
static LONG IsRoomOutside(LONG x, LONG y, LONG z)
#else
LONG IsRoomOutside(LONG x, LONG y, LONG z)
#endif

{
	WORD offset;
	ROOM_INFO *r;

	if ((offset = OutsideRoomOffsets[((x>>12)*27)+(z>>12)]) == -1)
		return 0;

/* -------- handle single entry */

	if (offset < 0)
	{
		r = &room[(offset&0x7fff)];

		if (((r->maxceiling < y) && (r->minfloor > y))
		&&  ((r->z < z) && ((r->z+((r->x_size)*1024)) > z))
		&&  ((r->x < x) && ((r->x+((r->y_size)*1024)) > x)))
		{
			IsRoomOutsideNo = offset&0x7fff;
			return 1;
		}
		else
			return 0;
	}

/* -------- handle multiple entries */

	else
	{
		UBYTE *s = &OutsideRoomTable[offset];

		while (*s != 0xff)
		{
			r = &room[*s];

			if (((r->maxceiling <= y) && (r->minfloor >= y))
			&&  ((r->z < z) && ((r->z+((r->x_size)*1024)) > z))
			&&  ((r->x < x) && ((r->x+((r->y_size)*1024)) > x)))
			{
				IsRoomOutsideNo = *s;
				return 1;
			}
			s++;
		}
		return 0;
	}
}

/*---------------------------------------------------------------------------
 * Public Functions
\*--------------------------------------------------------------------------*/

/****************************************************************************
* BuildOutsideTable
*
* SYNOPSIS
*	void BuildOutsideTable()
*
* PURPOSE
*	Creates a table of outside rooms
*
* INPUTS
*	None
*
* RETURNS
*	Nothing
*/
#if	0
void BuildOutsideTable()
{
	unsigned char *s;
	int x, y, i;

	OutsideRoomTable = (unsigned char *)game_malloc(27*27*OUTSIDE_Z, 0);
	S_MemSet(OutsideRoomTable, 0xff, 27*27*OUTSIDE_Z);

/* -------- determine outside rooms within a grid pos */

	for ( y=0 ; y<108 ; y+=4 )
	{
		for ( x=0 ; x<108 ; x+=4 )
		{
			for ( i=0 ; i<number_rooms ; i++ )
			{
				unsigned char *d;
				int rx, ry, j;
				ROOM_INFO *r = &room[i];

				rx = r->z >> 10;
				ry = r->x >> 10;

				if ((!(r->flags & NOT_INSIDE))
				|| ((rx + r->x_size) < x)
				||  (rx > x)
				|| ((ry + r->y_size) < y)
				||  (ry > y))
					continue;

#if defined(GAMEDEBUG) || defined(EZORAY)
				if (i == 255)
				{
					printf("ERROR : Room 255 fuckeroony - go tell Chris\n");
					exit(0);
				}
#endif
				d = &OutsideRoomTable[((x>>2)*OUTSIDE_Z) + ((y>>2)*(27*OUTSIDE_Z))];

				for ( j=0 ; j<OUTSIDE_Z ; j++ )
				{
					if (d[j] == 0xff)
					{
						d[j] = i;
						break;
					}
				}

#if defined(GAMEDEBUG) || defined(EZORAY)
				if (j == OUTSIDE_Z)
				{
					printf("ERROR : Buffer shittage - go tell Chris\n");
					exit(0);
				}
#endif
			}
		}
	}

/* -------- create outside room table */

	s = OutsideRoomTable;

	for ( y=0 ; y<27 ; y++ )
	{
		for ( x=0 ; x<27 ; x++ )
		{
			int z=0;
			unsigned char *d, *p;

			i = (y*27)+x;
			d = &OutsideRoomTable[(x*OUTSIDE_Z) + (y*(27*OUTSIDE_Z))];

			while (d[z] != 0xff)
				z++;

			if (z == 0)
				OutsideRoomOffsets[i] = 0xffff;
			else if (z == 1)
				OutsideRoomOffsets[i] = *d | 0x8000;
			else
			{

			/* -------- pack string */

				p = OutsideRoomTable;

				while (p < s)
				{
					if (memcmp(p, d, z) == 0)
					{
						OutsideRoomOffsets[i] = (long)p-(long)OutsideRoomTable;
						break;
					}
					else
					{
						int z2=0;

						while (p[z2] != 0xff)
							z2++;

						p+=z2+1;
					}
				}

			/* -------- add a new string */

				if (p >= s)
				{
					OutsideRoomOffsets[i] = (long)s-(long)OutsideRoomTable;

					for ( ; z ; z-- )
						*s++ = *d++;

					*s++ = 0xff;
				}
			}
		}
	}

	game_free((((27*27*OUTSIDE_Z)-((long)s-(long)OutsideRoomTable))+3)&~3, 0);

#if defined(GAMEDEBUG) || defined(EZORAY)
	printf("Ouside room table = %d bytes\n", (long)s-(long)OutsideRoomTable);
#endif
}

#endif
/****************************************************************************
* DoRain
*
* SYNOPSIS
*	void DoRain()
*
* PURPOSE
*	Displays a load of lovely raindrops
*
* INPUTS
*	None
*
* RETURNS
*	Nothing
*/

#ifdef PSX_VERSION

void DoRain()
{
	LINE_G2 *lineg2;
	long	result[XYZ];
	long	result2[XYZ];
	long	lp, distance;
	long	x, y, z, radius;
	long	screencoords[XYZ];
	long screencoords2[XYZ];
	long dir, angle, roomno;

/* -------- determine distance (this is wank - do it properly after E3) */

	if (OutsideRoomOffsets[((CamPos.x>>12)*27)+(CamPos.z>>12)] != -1)
		distance = 3072;
	else
		distance = 4096;

	SetRotMatrix(Matrix);
	SetTransMatrix(Matrix);

	dir = CamRot.y;

	if (CamRot.x < 2048)
	{
		scale = CamRot.x;

		RainYAdd = ((2048 * scale) >> 10) + 1024;
		RainAngDiv = ((3072 * scale) >> 10) + 1024;
		RainAngAdd = ((1536 * scale) >> 10) + 512;

		distance -= CamRot.x << 2;
	}
	else
	{
		scale = -(3072-CamRot.x);

		RainYAdd = ((2048 * scale) >> 10) - 1024;
		RainAngDiv = 2048 - ((1024 * scale) >> 10);
		RainAngAdd = 1024 - ((512 * scale) >> 10);

		distance -= (4096 - CamRot.x) << 2;
	}


	for ( lp=0 ; lp<128 ; lp++ )
	{
//		y = -(rand() & 2047)+1024;
		y = -(rand() & 2047)+RainYAdd;

//		angle = ((dir + (rand()&2047) - 1024) & 4095);
		radius = (rand()&4095) + distance - 2048;
		angle = ((dir + (rand()%RainAngDiv) - RainAngAdd) & 4095);

		z = (((rcossin_tbl[(angle<<1)+1])*radius)>>12);
		x = -(((rcossin_tbl[(angle<<1)])*radius)>>12);

//		roomno = get_room(z+CamPos.z, y+CamPos.y, x+CamPos.x);

//		if (roomno == -1 || !(room[roomno].flags & 2))
//			continue;

		if (IsRoomOutside(CamPos.x+x, CamPos.y+y, CamPos.z+z))
		{
			mCalcPoint(x+CamPos.x+(SmokeWindX<<2), y+CamPos.y, z+CamPos.z+(SmokeWindZ<<2), &result[0]);
			ProjectPCoord(result[X],result[Y],result[Z],screencoords,CENTREX,CENTREY,phd_persp);

			result[Z] >>= 3;

  			y += -((rand()&127)+128);

			mCalcPoint(x+CamPos.x, y+CamPos.y, z+CamPos.z, &result2[0]);
			ProjectPCoord(result2[X],result2[Y],result2[Z],screencoords2,CENTREX,CENTREY,phd_persp);

			if (result[Z] > 2048 || result[Z] < 32 || (result2[Z]>>3) < 32 ||
				screencoords[X] < -32 || screencoords2[X] < -32 ||
				screencoords[X] > 512+32 || screencoords2[X] > 512+32 ||
				screencoords[Y] < -64 || screencoords2[Y] < -64		||
				screencoords[Y] > 256+64 || screencoords2[Y] > 256+64)
			{
				continue;
			}

			lineg2 = (LINE_G2 *)db.polyptr;
			setlen(lineg2, 4);
			setcode(lineg2, 0x52);
			setRGB1(lineg2,0,0,0);
			x = (rand()&24);
			setRGB0(lineg2,32+x,48+x,48+x);
			setXY2(lineg2,screencoords[X],screencoords[Y],screencoords2[X],screencoords2[Y]);
			MyaddPrim(db.ot, result[Z], lineg2);
			lineg2++;
			db.polyptr = (char *)lineg2;

			setDrawTPage((DR_TPAGE *)db.polyptr, 0, 1, getTPage(0, 1, 0, 0));
			MyaddPrim(db.ot, result[Z], (DR_TPAGE *)db.polyptr);
			db.polyptr += sizeof(DR_TPAGE);
		}
	}
}

#endif
