;/*
sc RESOPT IGNORE=73 DATA=NEAR NMINC UCHAR CONSTLIB STREQ STRMERGE NOSTKCHK NOSTDIO OPTIMIZE OPTSIZE Fireworks.c
Slink from LIB:c.o Fireworks.o to //Clients/Fireworks LIB LIB:sc.lib LIB:amiga.lib /lib/client.lib SC SD NOICONS STRIPDEBUG
delete Fireworks.o
quit

 Fireworks 1.2  (Client for BServer)

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

 Reworked as asked by Aristotelis Grammatikakhs.
*/

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


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

#include "/include/client.h"

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

struct IntuitionBase *IntuitionBase;
struct GfxBase *GfxBase;

struct DisplayIDInformation *dinfo;

struct Screen *scr1, *scr2;

#define MAXFWKS 9
#define BITSPERFWK 10
#define TOTALFWKS MAXFWKS * BITSPERFWK
#define SCRDEPTH 3
#define NUMCOLORS 8

/* (1<<SCRDEPTH) + 1 gives the max. # of fireworks */

struct Fire {
	WORD X, Y;
	WORD OldX, OldY, OlderX, OlderY;
	WORD VelX;
	WORD VelY;
	UWORD ExpTime;
	BOOL Active;
	BOOL Exploded;
	UBYTE Drawn;
	UBYTE Color;
	} Fireworks[TOTALFWKS];

extern ULONG RangeSeed;
UWORD swidth, sheight, maxw, maxh;
BOOL lace;
UBYTE brightness;

/* Get a random color in r g b... */

UBYTE r, g, b;

UBYTE RandomColor( UBYTE rng )
{
return( (UBYTE)((RangeRand(rng)+16-rng)*brightness/100) );
}

void SetRGBTriplet( void )
{
r = RandomColor(16);
g = RandomColor(16-r);
b = RandomColor(16);
}


void MoveAllFireworks( struct Screen *scr )
{
register UBYTE n, m;
register struct RastPort *rp;

rp = &(scr->RastPort);

for ( n = 0; n < TOTALFWKS; n += BITSPERFWK )
	{
	if ( !(Fireworks[n].Active) )
		{
		Fireworks[n].X = RangeRand( maxw );
		Fireworks[n].Y = maxh - 1;
		if ( Fireworks[n].X <= (maxw>>1) )
			Fireworks[n].VelX = ( RangeRand( 8 ) );
		else
			Fireworks[n].VelX = ( RangeRand( 8 ) - 8 );
		Fireworks[n].VelY = ( lace ? -60-RangeRand(45) : -40-RangeRand(40) );
		Fireworks[n].Active = TRUE;
		Fireworks[n].Exploded = FALSE;
		Fireworks[n].ExpTime = RangeRand( 15 ) + 15;
		for ( m = 0; m < BITSPERFWK; m++ )
		Fireworks[n+m].Color = n;
		}
	}

WaitTOF();
for ( n = 0; n < TOTALFWKS; n++ )
	{
	if ( Fireworks[n].Active )
		{
		Fireworks[n].OlderX = Fireworks[n].OldX;
		Fireworks[n].OlderY = Fireworks[n].OldY;
		Fireworks[n].OldX = Fireworks[n].X;
		Fireworks[n].OldY = Fireworks[n].Y;
		Fireworks[n].X += Fireworks[n].VelX;
		Fireworks[n].Y += Fireworks[n].VelY;
		Fireworks[n].VelY += 2;

		if ( Fireworks[n].X < 0 || Fireworks[n].X >= maxw ||
			Fireworks[n].Y < 0 || Fireworks[n].Y >= maxh ||
			(Fireworks[n].Exploded && RangeRand( ++Fireworks[n].ExpTime ) >= 60) )
				Fireworks[n].Active = FALSE;

		if ( Fireworks[n].Active )
			{
			if ( !Fireworks[n].Exploded || Fireworks[n].ExpTime % 5 )
				{
				SetAPen( rp, Fireworks[n].Color );
				Move( rp, Fireworks[n].OldX >> 3, Fireworks[n].OldY >> 3 );
				Draw( rp, Fireworks[n].X >> 3, Fireworks[n].Y >> 3 );
				Fireworks[n].Drawn = 2;
				}

			if ( !Fireworks[n].Exploded )
				{
				if ( --Fireworks[n].ExpTime == 0 )
					{
					Fireworks[n].Exploded = TRUE;

					SetRGBTriplet();
					SetRGB4( &scr1->ViewPort, (n/BITSPERFWK)+1, r, g, b );
					SetRGB4( &scr2->ViewPort, (n/BITSPERFWK)+1, r, g, b );

					for ( m = 1; m < BITSPERFWK; m++ )
						{
						Fireworks[n+m].X = Fireworks[n].X;
						Fireworks[n+m].Y = Fireworks[n].Y;
						Fireworks[n+m].VelX = Fireworks[n].VelX + RangeRand( 15 ) - 7;
						Fireworks[n+m].VelY = Fireworks[n].VelY + RangeRand( 7 ) - 3;
						Fireworks[n+m].Exploded = TRUE;
						Fireworks[n+m].Active = TRUE;
						Fireworks[n+m].ExpTime = m;
						}
					}
				}
			}
		}
	}

WaitTOF();
ScreenToFront( scr );
SpritesOff();
rp = (scr == scr1 ? &(scr2->RastPort) : &(scr1->RastPort));
SetAPen( rp, 0 );
for ( n = 0; n < TOTALFWKS; n++ )
	if ( Fireworks[n].Drawn )
		{
		Move( rp, Fireworks[n].OlderX >> 3, Fireworks[n].OlderY >> 3 );
		Draw( rp, Fireworks[n].OldX >> 3, Fireworks[n].OldY >> 3 );
		}
}


void Blank( void )
{
BOOL success = FALSE;
UBYTE n;
ULONG displayID;
struct Screen *activescr;

struct Rectangle *rect;

rect = GETTXTOSCANRECT(dinfo);

swidth = RECTANGLEWIDTH(rect);
sheight = RECTANGLEHEIGHT(rect);
displayID = DISPLAYID(dinfo);
brightness = GETBRIGHTNESS(dinfo);
lace = DISPLAYID(dinfo) & LACE;

/*
if ( !CheckAA() )
	{
	if ( displayID & SUPERHIRES )
		{
		displayID &= ~SUPERHIRES;
		displayID |= HIRES;
		swidth >>= 1;
		}
	}
*/

maxw = swidth << 3;
maxh = sheight << 3;

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

	SetRGB4( &scr1->ViewPort, 0, 0, 0, 0 );
	SetRGB4( &scr2->ViewPort, 0, 0, 0, 0 );
	for ( n = 1; n < NUMCOLORS; n++ )
		{
		SetRGBTriplet();
		SetRGB4( &scr1->ViewPort, n, r, g, b );
		SetRGB4( &scr2->ViewPort, n, r, g, b );
		}

	memset( Fireworks, 0, sizeof(struct Fire) * TOTALFWKS );

	while( STILL_BLANKING )
		{
		MoveAllFireworks( activescr );
		activescr = ( activescr == scr1 ? scr2 : scr1 );
		}

	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() )
			{
			RangeSeed = time( NULL );
			Blank();
			CloseCommunication( dinfo );
			}
		CloseLibrary( (struct Library *)GfxBase );
		}
	CloseLibrary( (struct Library *)IntuitionBase );
	}
}
