/*--------------------------------------------------------------------------*/
/*																			*/
/*					F l y i n g   T o a s t e r s							*/
/*																			*/
/*																			*/
/*																			*/
/*--------------------------------------------------------------------------*/
/*	MAIN.c																	*/
/*--------------------------------------------------------------------------*/
/* Note: A big part of this code was taken of the Flying Toaster	*/
/* programm by								*/

#include	<exec/types.h>
#include	<dos/dos.h>
#include	<intuition/intuition.h>
#include	<intuition/gadgetclass.h>
#include	<graphics/gfx.h>
#include	<graphics/gfxbase.h>
#include	<graphics/gfxmacros.h>
#include	<graphics/rastport.h>
#include	<graphics/displayinfo.h>
#include	<hardware/custom.h>
#include	<clib/exec_protos.h>
#include	<clib/intuition_protos.h>
#include	"/includes/struct.h"
#include	"/includes/tom_gadget.h"

char	p_ver[]="$VER: FlyingToaster v1.0 (30/01/93)";

#define LOCAL
/*
#include	"ft.h"
*/
#include	"FlyingToaster.dark.h"
#ifndef custom
#define custom (*(struct Custom *)0xDFF000)
#endif	/* custom */

#define WIDTH	640
#define HEIGHT	256
#define	BOOLEAN	int
#define	INT	int

#define	IM_WIDTH	64
#define	IM_HEIGHT	64
#define	IM_RADIUS	120

#define	LOOPRATE	10
#define	FACERATE	10

#define	RATE_DEC	5

#define	FT_SPEED	(urand(4)+1)
#define	FT_RATE(x)	(2*(4-ft[x].speed))

int	delay_rate=2;

struct	RastPort	*rp;
struct	Screen	*s,*scr;
struct	Window	*win;
extern	struct	appel_proc	*p_data_proc;
extern	struct	GfxBase	*GfxBase;

#define	MAX_FT	40
typedef	struct	object{
	int	delay;
	int	x,y;
	int	old_x,old_y;
	int	speed;
	int	rate;
	int	phase;
	int	rate_count;
	struct	sequence	*seq;
};
struct	object	ft[MAX_FT];

char	*p_text_info=
"    'Flying Toaster'\n"
"\n"
"A lot of code have been take\n"
"from the FlyingToaster blanker\n"
"by Gernot Reisinger (himself\n"
"inspired form the AfterDark's\n"
"FlyingToaster!  :-)\n";

struct tom_gadget my_gadg[]={
	{"_Number of objects:",SLIDER,  185,14,60,9,20, 1,MAX_FT,0,0},
	{"_Speed"	      ,SLIDER,  185,35,60,9,2, 1,3,0,0},
	{0,		END_LISTE,  0,  0,   0, 0, 0,0,0,0,0}
};

USHORT	nr_objects=20;


/*--------------------------------------------------------------------------
							V A R I A B L E S
  --------------------------------------------------------------------------*/
LOCAL struct TagItem    win_tags[] = {
	WA_Left,          0,									// 0
	WA_Top,           0,									// 1
	WA_Width,         640,									// 2
	WA_Height,        512,									// 3
	WA_IDCMP,         0,									// 4
	WA_Flags,         WFLG_SIMPLE_REFRESH|WFLG_BORDERLESS|
					  WFLG_ACTIVATE,						// 5
	WA_ScreenTitle,   0L,									// 6
	WA_CustomScreen,  0L,									// 7
	TAG_DONE };


LOCAL struct ColorSpec  scr_cols[] = {
     0, 0x00, 0x00, 0x00,
     1, 0x0F, 0x0F, 0x0F,
    ~0, 0x00, 0x00, 0x00 };

LOCAL UWORD	dri_pens[] = {
    ~0 };


LOCAL struct TagItem    scr_tags[] = {
	SA_Left,		0,										// 0
	SA_Top,			0,										// 1
	SA_Depth,		1,										// 2
	SA_Behind,		TRUE,									// 3
	SA_Quiet,		TRUE,									// 4
	SA_Overscan,	OSCAN_MAX,								// 5
	SA_Colors,		(LONG) scr_cols,						// 6
	SA_Type,		CUSTOMSCREEN,							// 7
	SA_DisplayID,	HIRESLACE_KEY,							// 8
	SA_Pens,		(LONG) dri_pens,						// 9
    TAG_DONE
	};


/*--------------------------------------------------------------------------
								G L O B A L S
  --------------------------------------------------------------------------*/
char	*ver = "Ver 1.0 (18.12.66)";

struct	sequence *seq_list[] = {
	NULL,											// free flight
	&default_seq,
	&loop_seq,
	&face_seq
	};

													// detach code
LONG	_priority = 0L;
LONG	_BackGroundIO = 1L;
GLOBAL	BPTR	_Backstdout;



/*--------------------------------------------------------------------------*/
/*	open_display															*/
/*--------------------------------------------------------------------------*/
BOOLEAN open_display(void)
	{

	if ((scr = OpenScreenTagList(NULL,scr_tags)) == NULL)
		return(FALSE);

	win_tags[7].ti_Data = (LONG) scr;
	win_tags[2].ti_Data = (LONG) scr->Width;
	win_tags[3].ti_Data = (LONG) scr->Height;

	if ((win = OpenWindowTagList(NULL,win_tags)) == NULL)
		return(FALSE);

	FreeSprite (0);
	GfxBase->SpriteReserved|=1;
	ScreenToFront(scr);

	SetAPen(win->RPort,0);

	WaitTOF();

	FreeSprite (0);
	GfxBase->SpriteReserved|=1;
/*	SetPointer(win,pointer_data,POINTER_HEIGHT,POINTER_WIDTH,1,1);*/

	return(TRUE);

	}	/* open_display */



/*--------------------------------------------------------------------------*/
/*	close_display															*/
/*--------------------------------------------------------------------------*/
void close_display(void)
	{

	if (win != NULL) {
		CloseWindow(win);
		win = NULL;
		}

	if (scr != NULL) {
		DCloseScreen(scr);
		scr = NULL;
		}
	}	/* close_display */


/*--------------------------------------------------------------------------*/
/*	urand																	*/
/*--------------------------------------------------------------------------*/
int urand(int limit)
	{
	static LONG random_seed = 0xDEAD0123;

	random_seed = random_seed * custom.vhposr + 0xe153766f;

	return ((int) ((unsigned int) random_seed % limit));

	}	/* urand */




/*--------------------------------------------------------------------------*/
/*	check_collision															*/
/*--------------------------------------------------------------------------*/
INT check_collision(INT i,INT x, INT y)
	{
	INT		j,
			jx,jy;


	x += IM_WIDTH / 2;
	y += IM_HEIGHT / 2;

	for (j = 0; j < nr_objects; j++) {
		if (j != i && ft[j].delay == 0) {
			jx = ft[j].x + IM_WIDTH / 2;
			jy = ft[j].y + IM_HEIGHT / 2;

			if (((jx - x) * (jx - x) + (jy - y) * (jy - y)) <= (4 * IM_RADIUS * IM_RADIUS))
				return(j);
			}
		}
	return(-1);
	}	/* check_collision */



/*--------------------------------------------------------------------------*/
/*	calc_new_pos															*/
/*--------------------------------------------------------------------------*/
void calc_new_pos(INT i)
	{
	INT		x,y,
			c;


	x = ft[i].x - ft[i].speed;
	y = ft[i].y + 2;

	ft[i].old_x = ft[i].x;
	ft[i].old_y = ft[i].y;

	if ((c = check_collision(i,x,y)) != -1) {
		x = ft[i].x;
		y += 2;
		if ((c = check_collision(i,x,y)) != -1) {
			y = ft[i].y - 4;
			if ((c = check_collision(i,x,y)) != -1)
				return;
			}
		}

	ft[i].x = x;
	ft[i].y = y;

	}	/* calc_new_pos */



/*--------------------------------------------------------------------------*/
/*	find_launch_pos															*/
/*--------------------------------------------------------------------------*/
BOOLEAN find_launch_pos(INT i)
	{
	BOOLEAN	colides;
	INT		j,
			x,y,
			ix,iy,
			jx,jy;


	x = win->Width;
/*	y = (urand(7) - 1) * IM_HEIGHT;*/
	y = (urand(win->Height));

	FOREVER {
		if (x <= (2 * IM_WIDTH) && y <= - IM_HEIGHT)
			return(FALSE);

		ix = x + IM_WIDTH / 2;
		iy = y + IM_HEIGHT / 2;

		colides = FALSE;
		for (j = 0; j < nr_objects && ! colides; j++) {
			if (i != j) {
				jx = ft[j].x + IM_WIDTH / 2;
				jy = ft[j].y + IM_HEIGHT / 2;

				if (((jx - ix) * (jx - ix) + (jy - iy) * (jy - iy)) <=
						(4 * IM_RADIUS * IM_RADIUS)) {
					colides = TRUE;
					}
				}
			}

		if (! colides) {
			ft[i].x = ft[i].old_x = x;
			ft[i].y = ft[i].old_y = y;
			return(TRUE);
			}

		if (y > - IM_HEIGHT)
			y -= IM_HEIGHT;
		else
			x -= IM_WIDTH;

		}
	}	/* find_launch_pos */




/*--------------------------------------------------------------------------*/
/*	goto_next_img															*/
/*--------------------------------------------------------------------------*/
void goto_next_img(struct object *obj, struct sequence *next_seq)
	{
	obj->phase++;
	if (obj->phase >= obj->seq->img_count) {
		obj->phase = 0;
		if (next_seq == NULL) {
			obj->seq = obj->seq->next_sequence;
			if (urand(LOOPRATE) == 0) {
				obj->rate = RATE_DEC - 1;
				obj->seq = &loop_seq;
				}
			else if (urand(FACERATE) == 0) {
				obj->rate = RATE_DEC - 1;
				obj->seq = &face_seq;
				}
			}
		else
			obj->seq = next_seq;
		}
	}	/* goto_next_img */



/*--------------------------------------------------------------------------*/
/*	run_ft																	*/
/*--------------------------------------------------------------------------*/
void	dark(void)
	{
	INT		i;

	if (! open_display()) {
		close_display();
		return;
	}

	nr_objects=my_gadg[0].value;
	delay_rate=my_gadg[1].value;

	for (i = 0; i < nr_objects; i++) {
		memset(&ft[i],'\0',sizeof(ft[0]));

		if (! find_launch_pos(i)){
			ft[i].delay = 30;
		}else{
			ft[i].delay = urand(50);
		}
		ft[i].phase = urand(IMAGEMAX);
		ft[i].seq = &default_seq;
		ft[i].speed = FT_SPEED;
		ft[i].rate = ft[i].rate_count = FT_RATE(i);
	}

	while(tst_end()==FALSE){
		for (i = 0; i < nr_objects; i++) {
			if (ft[i].delay == 0) {
				calc_new_pos(i);

				ft[i].rate_count -= RATE_DEC;
				if (ft[i].rate_count < 0) {
					ft[i].rate_count = ft[i].rate;
					goto_next_img(&ft[i], NULL);
					}

				if ((ft[i].old_x != ft[i].x || ft[i].old_y != ft[i].y)) {

					if (ft[i].y > ft[i].old_y) {
						EraseRect(win->RPort,ft[i].old_x,ft[i].old_y,
								ft[i].old_x + IM_WIDTH,ft[i].y + 1);
						}
					if (ft[i].x < ft[i].old_x) {
						EraseRect(win->RPort,ft[i].x + IM_WIDTH - 1,ft[i].y,
								ft[i].old_x + IM_WIDTH,ft[i].old_y + IM_HEIGHT);
						}
					}

				DrawImage(win->RPort,ft[i].seq->img[ft[i].phase],ft[i].x,ft[i].y);

				if (ft[i].x < - (IM_WIDTH + 1) || ft[i].y > win->Height)
					ft[i].delay = urand(50);
				}
			else {
				ft[i].delay--;
				if (ft[i].delay == 0) {
					if (find_launch_pos(i)) {
						ft[i].speed = FT_SPEED;
						ft[i].rate = ft[i].rate_count = FT_RATE(i);
						}
					else
						ft[i].delay = 30;
					}
				}
			}

		Delay(delay_rate);

	}

	close_display();


}	/* run_ft */


void	proc_init()
{
	p_data_proc->type_screen=SCR_OWN;
	p_data_proc->code_ret=DARK_WB_20;
}
void	proc_save()
{
}

void	proc_end()
{
}

