;/*
sc RESOPT IGNORE=73 DATA=NEAR NMINC UCHAR CONSTLIB STREQ STRMERGE NOSTKCHK NOSTDIO OPTIMIZE OPTSIZE balls.c
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.3  (Client for BServer)

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

 This was reworked as Aristotelis Grammatikakhs asked.
*/

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

#include <proto/exec.h>
#include <proto/intuition.h>
#include <proto/graphics.h>
#include <clib/alib_protos.h>
#include <time.h>

#include "/include/client.h"

extern UWORD __stdargs RangeRand( ULONG );

char *ver = "$VER: Balls 1.2 "__AMIGADATE__;

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
#define BALLDIM 0x1D
#define HALFDIM 0x0E

struct Ball {
	WORD X, Y;
	WORD OldX, OldY;
	WORD VelX;
	WORD VelY;
	WORD Kin, Pot;
	} 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 - BALLDIM );
	balls[n].Y = RangeRand( sheight - BALLDIM );
	balls[n].OldX = balls[n].OldY = 0;
	balls[n].VelX = RangeRand( 16 ) - 8;
	balls[n].VelY = 0;
	}
}


void DrawAllBalls( struct Screen *actscr )
{
register int n;
SetRast( &actscr->RastPort, 0 );
for ( n = 0; n < MAXBALLS; n++ )
	BltMaskBitMapRastPort( &ballbmap, 0, 0,
			&actscr->RastPort, balls[n].X, balls[n].Y,
			BALLDIM, BALLDIM, (ABC|ABNC|ANBC), (PLANEPTR)ball_mask );
}


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

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

for ( n = 0; n < MAXBALLS; n++ )
	{
	balls[n].OldX = balls[n].X;
	balls[n].OldY = balls[n].Y;

	/* Nell'ipotesi di urti con le pareti perfettamente elastici ;-) */

	if ( (balls[n].VelX >= 0 && ( balls[n].X + balls[n].VelX >= swidth - BALLDIM )) ||
		(balls[n].VelX < 0 && balls[n].X + balls[n].VelX < 0) )
		balls[n].VelX *= -1;
	else
		balls[n].X += balls[n].VelX;

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

	balls[n].VelY += 1;
	if ( (balls[n].VelY >= 0 && ( balls[n].Y + balls[n].VelY >= sheight - BALLDIM )) ||
		(balls[n].VelY < 0 && balls[n].Y + balls[n].VelY < 0) )
		balls[n].VelY *= -1;
	else
		balls[n].Y += balls[n].VelY;

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

	do	{
		bchg = FALSE;
		for ( n = 0; n < MAXBALLS; n++ )
			{
			thisBallX = balls[n].X;
			thisBallY = balls[n].Y;

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

				if ( (thisBallX <= otherBallX && otherBallX <= thisBallX + BALLDIM) &&
					(thisBallY <= otherBallY && otherBallY <= thisBallY + BALLDIM) )
					{
					bchg = TRUE;
					temp = balls[n].VelX;
					balls[n].VelX = balls[m].VelX;
					balls[m].VelX = temp;
					temp = balls[n].VelY;
					balls[n].VelY = balls[m].VelY;
					balls[m].VelY = temp;

					diffX = BALLDIM - (otherBallX > thisBallX ? otherBallX - thisBallX : thisBallX - otherBallX);
					diffY = BALLDIM - (otherBallY > thisBallY ? otherBallY - thisBallY : thisBallY - otherBallY);

					if ( thisBallX < otherBallX )
						{
						balls[n].X -= 1 + (diffX/2);
						if ( balls[n].X < 0 )
							balls[n].X = 0;
						balls[m].X += 1 + (diffX/2);
						if ( balls[m].X >= swidth - BALLDIM )
							balls[m].X = swidth - BALLDIM - 1;
						}
					else
						{
						balls[n].X += 1 + (diffX/2);
						if ( balls[n].X >= swidth - BALLDIM )
							balls[n].X = swidth - BALLDIM - 1;
						balls[m].X -= 1 + (diffX/2);
						if ( balls[m].X < 0 )
							balls[m].X = 0;
						}

					if ( thisBallY < otherBallY )
						{
						balls[n].Y -= 1 + (diffY/2);
						if ( balls[n].Y < 0 )
							balls[n].Y = 0;
						balls[m].Y += 1 + (diffY/2);
						if ( balls[m].Y >= sheight - BALLDIM )
							balls[m].Y = sheight - BALLDIM - 1;
						}
					else
						{
						balls[n].Y += 1 + (diffY/2);
						if ( balls[n].Y >= sheight - BALLDIM )
							balls[n].Y = sheight - BALLDIM - 1;
						balls[m].Y -= 1 + (diffY/2);
						if ( balls[m].Y < 0 )
							balls[m].Y = 0;
						}
					}
				}
			}
		} while( bchg );
}


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

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

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*brightness/100, 15*brightness/100 );
	SetRGB4( &scr1->ViewPort, 2, 0, 4*brightness/100, 10*brightness/100 );
	SetRGB4( &scr1->ViewPort, 3, 0, 0, 8*brightness/100 );
	SetRGB4( &scr2->ViewPort, 0, 0, 0, 0 );
	SetRGB4( &scr2->ViewPort, 1, 0, 8*brightness/100, 15*brightness/100 );
	SetRGB4( &scr2->ViewPort, 2, 0, 4*brightness/100, 10*brightness/100 );
	SetRGB4( &scr2->ViewPort, 3, 0, 0, 8*brightness/100 );

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

	while( STILL_BLANKING )
		{
		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, BALLDIM, BALLDIM );
			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 );
	}
}
