
/* fish.c */
/* Lloyd and Peter Linstrom */

#include "exec/types.h"
#include "intuition/intuition.h"
#include "graphics/sprite.h"
#include "exec/memory.h"

SHORT sprgot[8];		/* -1 means invalid sprite  */
UWORD *sprdata[8];		/* eight pointers to sprite data */
SHORT xmove[8];			/* used for speed of x movement */
SHORT ymove[ ] = {1, 1, 30, 25, 20, 35, 35, 30};
				/* used for speed of y movement */
SHORT count;			/* Counter used in moving sprites */
struct SimpleSprite sprite[8];	/* seven simple sprites */
struct SimpleSprite *spr;	/* pointer to a sprite */
short sheigth[ ] = {0, 10, 12, 11, 9, 15, 19, 10};	/* height of sprite */
short sdatasize[ ] = {0, 48, 56, 52, 44, 68, 84, 48}; /* size of sprite data */
short xstep[8];			/* Fish Movement increment for x */
short ystep[8];			/* Fish Movement increment for y */
short fishspeed[ ] = {0, 6, 4, 3, 2, 5, 4, 2};
					/* Bias for fish speed */
short eventtime[8];	/* Counts until next scheduled movement change */
short eventtype[8];	/* Type of event to occur at eventtime */ 
short stopcode[ ] = {0, 0, 0, 0, 0, 0, 0, 0}; 	/* 1=fish stopped */

UWORD swtchex[ ] = { 0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 
			3, 11, 7, 15 };	/* Bit reversed hex digits */

struct Window *w,*OpenWindow();		/* pointer to a window */
struct RastPort *rp;			/* pointer to a RastPort */
struct Screen *s,*picture();		/* pointer to a screen */
struct ViewPort *vport;			/* pointer to a ViewPort */


LONG GfxBase;
LONG IntuitionBase;

UWORD bottomfish[ ] = {
			0, 0,			/* position control */
			0x01c0, 0x0000,	
			0x07c1, 0x0001,
			0x0443, 0x1ff3,
			0x1217, 0x6fff,
			0x848f, 0xffff,
			0x2daf, 0xf7ff,
			0xcd7f, 0x3bff,
			0x3bd3, 0x1df3,
			0x5101, 0x0001,
			0x8800, 0x0000,
			0, 0
};


UWORD bluefish[ ] = {
			0, 0,			/* position control */
			0x0080, 0x0080,
			0x0380, 0x0381,
    			0x0001, 0x1ff2,
			0x1003, 0x7ffc,
			0x0003, 0xfffc,
			0x0ff3, 0xf00c,
			0x7ff1, 0x0002,
			0x07c0, 0x07c1,
			0x01c0, 0x01c0,
			0, 0			/* end of structure */
};

UWORD bluetwo[ ] = {
			0, 0,			/* position */
			0x0060, 0x0020,
			0x01e0, 0x00e0,
			0x07e0, 0x03c0,
			0x0fe1, 0x0021,
			0x3ff1, 0x0002,
			0x6ff5, 0x0003,
			0xfdf7, 0x028b,
			0xfbeb, 0x2635,
			0x4eb7, 0xb9cb,
			0x3765, 0x6ab3,
			0x19c1, 0x0ea2,
			0x0681, 0x0301,
			0x0100, 0x0100,
			0x0080, 0x0080,
			0x0040, 0x0040,
			0, 0			/* End of structure */
};


UWORD goldfish[ ] = {
			0, 0,			/* position control */
			0x0180, 0x0000,
			0x03c0, 0x0000,
			0x07c0, 0x0001,
			0x0001, 0x1fe2,
			0x0003, 0x7ff4,
			0x1003, 0xeffc,
			0x0407, 0xfbf8,
			0x0403, 0xfbfc,
			0x0c03, 0x73fc,
			0x0001, 0x1fe2,
			0x07c0, 0x0001,
			0x00c0, 0x0000,
			0, 0			/* end of structure */
};


UWORD goldtwo[ ] = {
			0, 0,			/* position control */
			0x01c0, 0x0000,
			0x0781, 0x0000,
			0x16c3, 0x0900,
			0x16c7, 0x6920,
			0x925b, 0x4da4,
			0x9b6e, 0x6490,
			0xcdab, 0x3254,
			0x6da7, 0x1240,
			0x0dc3, 0x1200,
			0x0381, 0x0000,
			0x01c0, 0x0000,
			0, 0			/* End of structure */
};
			
UWORD angelfish[ ] = {
			0, 0,			/* position control */
			0x0000, 0x00c0,
			0x0000, 0x0100,
			0x0000, 0x0200,
			0x0000, 0x0400,
			0x0101, 0x0f80,
			0x1203, 0x1fc0,
			0x1247, 0x3fe1,
			0x1495, 0x5ffa,
			0xa4ae, 0x7ff4,
			0xa4a2, 0x7ffc,
			0xa4ae, 0x7ff4,
			0x76d7, 0x2dba,
			0x3fe7, 0x3241,
			0x0f83, 0x0a40,
			0x0601, 0x0780,
			0x0200, 0x0200,
			0x0100, 0x0100,
			0x00c0, 0x00c0,
			0x0030, 0x0030,
			0, 0			/* end of structure */
};

UWORD brownfish[ ] = {
			0, 0,			/* Position control */
			0x0380, 0x0000,
			0x0380, 0x0401,
			0x1fe0, 0x1fe3,
			0x7ff0, 0x7ff7,
			0xcab9, 0xdffe,
			0xb66a, 0xeddc,
			0x5dd1, 0xa32e,
			0x4a50, 0x7db7,
			0x0180, 0x0ec3,
			0x0100, 0x0001,
			0, 0			/* End of Structure */
};	


int rnum(d)		/* Generate nonzero random number max d */
int d;
{
	int t1;

	if(d <= 0) return(1);
	t1 = rand() % d + 1;
	return(t1);
}


void revsprite(dptr, nbytes)	/* Bit reverse sprite data */
UWORD *dptr;			/* Pointer to sprite data */
SHORT nbytes;			/* Number of data bytes */
{
	short nlft;		/* Number of words to reverse */
	UWORD t1, t2;		

	dptr++;			/* Skip first two words of sprite data */
	dptr++;
	nlft = nbytes/2 - 4;	/* Number of words to reverse */
	while(nlft > 0)
	{
		t1 = *dptr;		/* Bit reverse word */
		t2 = swtchex[t1 & 0xF] << 12;
		t2 += swtchex[(t1 & 0xF0) >> 4] << 8;
		t2 += swtchex[(t1 & 0xF00) >> 8] << 4;
		t2 += swtchex[(t1 & 0xF000) >> 12];
		*dptr++ = t2;
		nlft--;
	}
}


void xevent(i)			/* Handle events in fish movement */
short i;			/* Fish number */
{

	switch(eventtype[i])
	{
	case 1:			/* Stop fish */
		stopcode[i] = 1;
		ystep[i] = 0;
		eventtime[i] = rnum(30);
		eventtype[i] = 2;
		break;
	case 2:			/* Start fish */
		stopcode[i] = 0;
		eventtime[i] = 1;
		eventtype[i] = rnum(3) + 2;
		break;

	case 3:			/* Reverse fish */
		xstep[i] = -1 * xstep[i];
		revsprite(sprdata[i], sdatasize[i]);
		eventtime[i] = 1;
		eventtype[i] = rnum(2) + 3;
		break;

	case 4:			/* Change speed */
		xmove[i] = rnum(3) + fishspeed[i];
		eventtime[i] = 500 + rnum(1500);
		eventtype[i] = 1;
		break;

	case 5:			/* Move in Y */
		xmove[i] = rnum(3) + fishspeed[i];
		ystep[i] = (rnum(2) == 1)? 1 : -1;
		if(spr->y < 50) ystep[i] = 1;
		if(spr->y >150) ystep[i] = -1;
		eventtype[i] = 1;
		eventtime[i] = 100 + rnum(500);
		break;

	default:
		break;
	}
}


movesprites()
{
	short i;
	short newx, newy;

	spr = &sprite[0];		/* Point to first sprite */
	for (i=0; i<8; i++)
	{
		if(sprgot[i] == -1) continue;

		if(--eventtime[i] == 0) xevent(i);
					/* Execute any events for fish */

		if((count % xmove[i]) == 0)
		{
			if(stopcode[i] == 1) break;
			newx = spr->x + xstep[i];/* New sprite pos */
			if((newx <= 0) || (newx >= 304))
			{
				eventtime[i] = 1;
				eventtype[i] = 3;	/* Reverse fish */
			}

			MoveSprite(0, spr, newx, spr->y);
		}

		if((i != 1) && ((count % ymove[i]) == 0))
		{
			if(stopcode[i] == 1) break;
			newy = spr->y + ystep[i];
			if((newy <= 15) || (newy >= 185))
			{
				eventtime[i] = 1;
				eventtype[i] = 5;	/* Change Y movement */
			}
			MoveSprite(0, spr, spr->x, newy);
		}
		spr++;				/* Point to next sprite */
	}
	count = ++count % 5040;		/* 5040 = 7! */
}


#define AZCOLOR 1
#define WHITECOLOR 2

struct NewWindow myWindow = {
	0, 15,
	300, 10,
	-1, 
	-1,
	CLOSEWINDOW,
	WINDOWCLOSE | WINDOWDEPTH | WINDOWSIZING | WINDOWDRAG | ACTIVATE,
	NULL, NULL,
	(UBYTE *) "Fish Tank",
	NULL,
	NULL, 
	100, 
	30, 
	620, 
	200,
	WBENCHSCREEN
};


#include "graphics/gfxmacros.h"

int HandleEvent(code)
	LONG code;	/* provided by main */
{
	switch (code)
	{
	case CLOSEWINDOW:
		return(0);
		break;
	default:
		return(1);
		break;
	}
}

void setspritecolors(vp)
struct ViewPort *vp;
{
	/* Goldfish colors  for sprites 2 & 3 */
	SetRGB4(vp, 22L, 15L, 8L, 2L);
	SetRGB4(vp, 21L, 15L, 11L, 7L);

	/* Bluefish colors for sprites 4 & 5 */
	SetRGB4(vp, 26L, 0L, 7L, 12L);
	SetRGB4(vp, 25L, 7L, 9L, 15L);
	SetRGB4(vp, 27L, 13L, 14L, 14L);

	/* Angelfish colors for sprites 6 & 7 */
	SetRGB4(vp, 30L, 15L, 12L, 9L);
	SetRGB4(vp, 29L, 15L, 13L, 11L);
	SetRGB4(vp, 31L, 7L, 5L, 2L);
}


int init()			/* Open Libraries, Window, and set sprite colors  */
{
	GfxBase = OpenLibrary("graphics.library", 0);
	if(GfxBase == NULL) return(0);

	IntuitionBase = OpenLibrary("intuition.library", 0);
	if(IntuitionBase == NULL) return(0);

	w = OpenWindow(&myWindow);
	if (w == 0) return(0);

	rp = w->RPort;
	vport = ViewPortAddress(w);	/* ViewPort address of current screen */
	setspritecolors(vport);

	return(1);		/* Successful initialization */
}


endit()			/* Close screen, librarys and windows */
{
	if(s) s = picture(1,"background.ilbm");
				   /* Get rid of the background screen */
	if(w) CloseWindow(w);
	if(GfxBase) CloseLibrary(GfxBase);
	if(IntuitionBase) CloseLibrary(IntuitionBase);
	exit(0);
}



cleanup()		/* DeAllocate sprites and sprite memory */
{
	short k;

	for(k=0; k<8; k++)
	{
		if(sprgot[k] == -1) continue;

		FreeSprite(k);  	/* Free Sprite */
		FreeMem(sprdata[k], sdatasize[k]);
						/* Free Sprite memory */
	}
}


main()
{
	struct IntuiMessage *msg;
	LONG  k, result;
	SHORT j, jmax;
	UWORD *src, *dest; 		/* for copying data into ram */


	if (init() == 0) endit(); 	/* Initailize everything */
	srand(time(NULL));		/* Set PRN generator */
	
	s = picture(0,"background.ilbm");   /* Load in background screen */
	if(s != NULL)
	{
		vport = &(s->ViewPort);		/* new viewport */
		setspritecolors(vport);
	}
	count = 0;			/* Initailize counter for movesprite()*/
	spr = &sprite[0];		/* Point to first sprite */

	sprgot[0] = -1;			/* Ignore sprite 0 */
	for(k=1; k<8; k++)
	{
		sprgot[k] = GetSprite(spr, k); 	/* Get a Sprite */
		if(sprgot[k] == -1) continue;	/* Skip if sprite unavailable */
		
		xmove[k] = rnum(3) + fishspeed[k];		/* Set speed */
		xstep[k] = (rnum(2) == 1)? -1 : 1; 	/* Set x  direction */
		ystep[k] = 0;				/* Set y direction */

		spr->x = 25 + rnum(250);	/* Initialize position */
		spr->y = 10 + rnum(170);
		if(k == 1) spr->y = 188;	/* bottomfish on bottom */

		eventtime[k] = rnum(800);	/* time of event */
		eventtype[k] = 1;		/* stop */

		spr->height = sheigth[k];	/* Initialize height */
		switch(k)
		{
		case 1:
			src = bottomfish;
			break;
		case 2:
			src = goldfish;
			break;
		case 3:
			src = goldtwo;
			break;
		case 4:
			src = bluefish;
			break;
		case 5:
			src = bluetwo;
			break;
		case 6: 
			src = angelfish;
			break;
		case 7:
			src = brownfish;
			break;
		}

		sprdata[k] = (UWORD *)AllocMem(sdatasize[k], MEMF_CHIP);
		if(sprdata[k] == NULL)	/* No Chip Ram */
		{
			FreeSprite(k);
			sprgot[k] = -1;	/* Mark sprite as unavailable */
			break;
		}

		dest = sprdata[k];	/* Copy sprite into Chip ram */
		jmax = sdatasize[k] / 2;	/* Num of words to copy */
		for(j=0; j<jmax; j++)
		{
			*dest++ = *src++;
		}
		if(xstep[k] == 1) revsprite(sprdata[k], sdatasize[k]);
				/* Make sure fish points in correct dir */
		ChangeSprite(vport, spr, sprdata[k]);	
		spr++;
	}
	while(1)
	{
		WaitTOF();
		result = 1;
		while((msg = (struct IntuiMessage *)GetMsg(w->UserPort))!=NULL)
		{
			result = result * HandleEvent(msg->Class);
			ReplyMsg(msg);
		}
		if(result == 0)		/* Close Window Flag */
		{
			cleanup();
			endit();
		}
		movesprites();
	}
}
