;/*
sc balls.c IGNORE=73 DATA=FAR NMINC STRMERGE NOSTKCHK IGNORE=73 STRUCTUREEQUIVALENCE NOSTDIO DEBUG=LINE
Slink from LIB:c.o balls.o to //Clients/Balls LIB LIB:sc.lib LIB:amiga.lib /lib/client.lib SC SD NOICONS STRIPDEBUG
delete balls.o
quit

 Bouncing Balls 1.2  (Client for BServer)

 Copyright © 1994 by Stefano Reksten of 3AM - The Three Amigos!!!
 All rights reserved.
*/

#include <exec/types.h>
#include <exec/memory.h>

#include <clib/exec_protos.h>
#include <clib/intuition_protos.h>
#include <clib/graphics_protos.h>
#include <clib/alib_protos.h>
#include <time.h>

#include "/include/client.h"

UWORD chip ball_imgdata[116] = {
 0x1F, 0xC000,
 0xE0, 0x3800,
 0x103, 0xC400,
 0x60F, 0xF300,
 0x800, 0x7C80,
 0x1000, 0xE40,
 0x1000, 0x740,
 0x2000, 0x3A0,
 0x4000, 0x1D0,
 0x5000, 0xD0,
 0x5000, 0xF0,
 0xB000, 0xE8,
 0xB000, 0x68,
 0xB000, 0x68,
 0xB800, 0x68,
 0xB800, 0x48,
 0xB800, 0x48,
 0xB800, 0x8,
 0x7800, 0x10,
 0x5C00, 0x10,
 0x5C00, 0x10,
 0x2E00, 0x20,
 0x1700, 0x40,
 0x13C0, 0x40,
 0x9FE, 0x80,
 0x6FF, 0xE300,
 0x13F, 0xC400,
 0xE0, 0x3800,
 0x1F, 0xC000,
 0x1F, 0xC000,
 0xFF, 0xF800,
 0x1FC, 0x3C00,
 0x7F0, 0xF00,
 0xFFF, 0x8380,
 0x1FFF, 0xF1C0,
 0x1FFF, 0xF8C0,
 0x3FFF, 0xFC60,
 0x7FFF, 0xFE30,
 0x7FFF, 0xFF30,
 0x7FFF, 0xFF10,
 0xFFFF, 0xFF18,
 0xFFFF, 0xFF98,
 0xFFFF, 0xFF98,
 0xFFFF, 0xFF98,
 0xFFFF, 0xFFB8,
 0xFFFF, 0xFFB8,
 0xFFFF, 0xFFF8,
 0x7FFF, 0xFFF0,
 0x7FFF, 0xFFF0,
 0x7FFF, 0xFFF0,
 0x3FFF, 0xFFE0,
 0x1FFF, 0xFFC0,
 0x1FFF, 0xFFC0,
 0xFFF, 0xFF80,
 0x7FF, 0xFF00,
 0x1FF, 0xFC00,
 0xFF, 0xF800,
 0x1F, 0xC000
 };

UWORD chip ball_mask[58] = {
 0x1F, 0xC000,
 0xFF, 0xF800,
 0x1FF, 0xFC00,
 0x7FF, 0xFF00,
 0xFFF, 0xFF80,
 0x1FFF, 0xFFC0,
 0x1FFF, 0xFFC0,
 0x3FFF, 0xFFE0,
 0x7FFF, 0xFFF0,
 0x7FFF, 0xFFF0,
 0x7FFF, 0xFFF0,
 0xFFFF, 0xFFF8,
 0xFFFF, 0xFFF8,
 0xFFFF, 0xFFF8,
 0xFFFF, 0xFFF8,
 0xFFFF, 0xFFF8,
 0xFFFF, 0xFFF8,
 0xFFFF, 0xFFF8,
 0x7FFF, 0xFFF0,
 0x7FFF, 0xFFF0,
 0x7FFF, 0xFFF0,
 0x3FFF, 0xFFE0,
 0x1FFF, 0xFFC0,
 0x1FFF, 0xFFC0,
 0xFFF, 0xFF80,
 0x7FF, 0xFF00,
 0x1FF, 0xFC00,
 0xFF, 0xF800,
 0x1F, 0xC000
 };

struct IntuitionBase *IntuitionBase;
struct GfxBase *GfxBase;

struct DisplayIDInformation *dinfo;

struct Screen *scr1, *scr2;

#define MAXBALLS 8

struct Ball {
	WORD X, Y;
	WORD OldX, OldY;
	BYTE DirX;
	BYTE DirY;
	UWORD VelX;
	UWORD VelY;
	} balls[MAXBALLS];

struct BitMap ballbmap;

extern ULONG RangeSeed;

UWORD swidth, sheight;


void SetAllBalls( void )
{
register UBYTE n;

for ( n = 0; n < MAXBALLS; n++ )
	{
	balls[n].X = RangeRand( swidth - 29 );
	balls[n].Y = RangeRand( sheight - 29);
	balls[n].OldX = balls[n].OldY = 0;
	balls[n].DirX = ( RangeRand( 2 ) ? -1 : 1 );
	balls[n].DirY = 1;
	balls[n].VelX = RangeRand( 8 );
	balls[n].VelY = 0;
	}
}


void MoveAllBalls( struct Screen *actscr, struct Screen *other )
{
register UBYTE n, m;
UWORD temp, thisBallX, thisBallY, otherBallX, otherBallY;

for ( n = 0; n < MAXBALLS; n++ )
	BltMaskBitMapRastPort( &ballbmap, 0, 0,
			&actscr->RastPort, balls[n].X, balls[n].Y,
			0x1D, 0x1D, (ABC|ABNC|ANBC), (PLANEPTR)ball_mask );
ScreenToFront( actscr );
for ( n = 0; n < MAXBALLS; n++ )
	RectFill( &other->RastPort, balls[n].OldX, balls[n].OldY, balls[n].OldX + 29, balls[n].OldY + 29 );

SpritesOff();

for ( n = 0; n < MAXBALLS; n++ )
	{
	/* Nell'ipotesi di urti con le pareti perfettamente elastici ;-) */

	balls[n].OldX = balls[n].X;
	balls[n].OldY = balls[n].Y;

	balls[n].X += balls[n].VelX * balls[n].DirX;
	if ( balls[n].X < 0 )
		{
		balls[n].DirX = 1;
		balls[n].X = 0;
		}
	if ( balls[n].X > swidth - 30 )
		{
		balls[n].DirX = -1;
		balls[n].X = swidth - 30;
		}

	/* Stessa cosa per il pavimento - Ancora piu' incredibile! :-o */

	balls[n].VelY += balls[n].DirY;
	balls[n].Y += balls[n].VelY * balls[n].DirY;
	if ( balls[n].Y > (sheight - 30) )
		{
		balls[n].DirY = -1;
		balls[n].Y = (sheight - 30);
		}
	if ( balls[n].Y < 0 )
		{
		balls[n].Y = 0;
		balls[n].DirY = 1;
		}

	if ( balls[n].VelY <= 0 )
		{
		balls[n].VelY = 0;
		balls[n].DirY = 1;
		}

	/* Urto perfettamente elastico pure tra le palle !!! =8-O */
	/* ...Seppur con qualche semplificazione (qualche???) ;-) */

	thisBallX = balls[n].X + 15;
	thisBallY = balls[n].Y + 15;

	for ( m = 0; m < MAXBALLS; m == n-1 ? m+=2 : m++ )
		{
		otherBallX = balls[m].X + 15;
		otherBallY = balls[m].Y + 15;

		if ( (thisBallX - 0x1D <= otherBallX && otherBallX <= thisBallX + 0x1D) &&
		     (thisBallY - 0x1D <= otherBallY && otherBallY <= thisBallY + 0x1D) )
			{
			temp = balls[n].VelX;
			balls[n].VelX = balls[m].VelX;
			balls[m].VelX = temp;

			temp = balls[n].DirX;
			balls[n].DirX = balls[m].DirX;
			balls[m].DirX = temp;

			temp = balls[n].VelY;
			balls[n].VelY = balls[m].VelY;
			balls[m].VelY = temp;

			temp = balls[n].DirY;
			balls[n].DirY = balls[m].DirY;
			balls[m].DirY = temp;
			}
		}
	}
}


void Blank( void )
{
BOOL success = FALSE;
UBYTE activescr = 0;
struct Rectangle *rect;

rect = GETTXTOSCANRECT(dinfo);
swidth = RECTANGLEWIDTH(rect);
sheight = RECTANGLEHEIGHT(rect);

scr1 = scr2 = NULL;

if ( (scr1 = OpenScreenTags( NULL,
		SA_Width, swidth,
		SA_Height, sheight,
		SA_Depth, 2,
		SA_Type, CUSTOMSCREEN,
		SA_Quiet, TRUE,
		SA_DisplayID, DISPLAYID(dinfo),
		SA_Overscan, OSCAN_TEXT,
		TAG_END ) ) &&
 (scr2 = OpenScreenTags( NULL,
		SA_Width, swidth,
		SA_Height, sheight,
		SA_Depth, 2,
		SA_Type, CUSTOMSCREEN,
		SA_Quiet, TRUE,
		SA_DisplayID, DISPLAYID(dinfo),
		SA_Overscan, OSCAN_TEXT,
		TAG_END ) ) )
	{
	success = TRUE;

	SetRGB4( &scr1->ViewPort, 0, 0, 0, 0 );
	SetRGB4( &scr1->ViewPort, 1, 0, 8, 15 );
	SetRGB4( &scr1->ViewPort, 2, 0, 4, 10 );
	SetRGB4( &scr1->ViewPort, 3, 0, 0, 8 );
	SetRGB4( &scr2->ViewPort, 0, 0, 0, 0 );
	SetRGB4( &scr2->ViewPort, 1, 0, 8, 15 );
	SetRGB4( &scr2->ViewPort, 2, 0, 4, 10 );
	SetRGB4( &scr2->ViewPort, 3, 0, 0, 8 );

	SetAllBalls();
	SetAPen( &scr1->RastPort, 0 );
	SetAPen( &scr2->RastPort, 0 );

	while( STILL_BLANKING )
		{
		WaitTOF();
		if ( activescr == 1 )
			MoveAllBalls( scr1, scr2 );
		else
			MoveAllBalls( scr2, scr1 );
		activescr ^= 1;
		}
	SpritesOn();

	}
if ( scr1 )
	CloseScreen( scr1 );
if ( scr2 )
	CloseScreen( scr2 );
if ( !success )
	SendClientMsg( ACTION_FAILED );
}


void __main( char *line )
{
if ( IntuitionBase = (struct IntuitionBase *)OpenLibrary( "intuition.library", 37L ) )
	{
	if ( GfxBase = (struct GfxBase *)OpenLibrary( "graphics.library", 37L ) )
		{
		if ( dinfo = OpenCommunication() )
			{
			InitBitMap( &ballbmap, 2, 0x1D, 0x1D );
			ballbmap.Planes[0] = (PLANEPTR)(ball_imgdata);
			ballbmap.Planes[1] = (PLANEPTR)(ball_imgdata + 58);

			RangeSeed = time( NULL );
			Blank();
			CloseCommunication( dinfo );
			}
		CloseLibrary( (struct Library *)GfxBase );
		}
	CloseLibrary( (struct Library *)IntuitionBase );
	}
}
