;/*
if not exists LemmingData.o
	sc DATA=FAR LemmingData.c
endif
;sc RESOPT IGNORE=73 DATA=NEAR NMINC UCHAR CONSTLIB STREQ STRMERGE NOSTKCHK NOSTDIO OPTIMIZE OPTSIZE Lemming.c
sc RESOPT IGNORE=73 DATA=NEAR NMINC UCHAR CONSTLIB STREQ STRMERGE NOSTKCHK Lemming.c
slink from LIB:c.o Lemming.o LemmingData.o to ///Clients/Lemming LIB LIB:sc.lib LIB:amiga.lib //lib/client.lib SC SD NOICONS STRIPDEBUG
quit

 Lemming 1.0  (Client for BServer)

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

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

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

#include <stdio.h>

#include "//include/client.h"
#include "//include/bitmap/bitmap.h"
#include "//include/bitmap/bitmap_pragmas.h"

extern ULONG Lemming_cmap32[16][3];

#define IMGW 0x20
#define IMGH 0x24

#define BITPLSIZE ((((IMGW+15)>>4)<<1)*IMGH)

extern UWORD l1_imgdata[], l2_imgdata[], l3_imgdata[], l4_imgdata[], l5_imgdata[], 
             l1_mask[], l2_mask[], l3_mask[], l4_mask[], l5_mask[], 
             lj1_imgdata[], lj2_imgdata[], lj3_imgdata[], lj4_imgdata[], lj5_imgdata[], 
             lj1_mask[], lj2_mask[], lj3_mask[], lj4_mask[], lj5_mask[], 
             le1_imgdata[], le2_imgdata[], le3_imgdata[], le4_imgdata[], le5_imgdata[], le6_imgdata[],
             le1_mask[], le2_mask[], le3_mask[], le4_mask[], le5_mask[], le6_mask[],
             wallbrk_imgdata[], wallbrk_mask[];

char *ver = "$VER: Lemming 1.0 "__AMIGADATE__;

struct { UWORD *frame, *mask; } FrameAndMask[] = {
	{ l1_imgdata, l1_mask }, { l2_imgdata, l2_mask },
	{ l3_imgdata, l3_mask }, { l4_imgdata, l4_mask },
	{ l5_imgdata, l5_mask }, { lj1_imgdata, lj1_mask },
	{ lj2_imgdata, lj2_mask }, { lj3_imgdata, lj3_mask },
	{ lj4_imgdata, lj4_mask }, { lj5_imgdata, lj5_mask },
	{ le1_imgdata, le1_mask }, { le2_imgdata, le2_mask },
	{ le3_imgdata, le3_mask }, { le4_imgdata, le4_mask },
	{ le5_imgdata, le5_mask }, { le6_imgdata, le6_mask } };

UBYTE WhichFrame[] = {
0, 1, 2, 3, 4, 3, 2, 1, 5, 6, 7, 8, 9, 8, 7, 6, 10, 11, 12, 13, 14, 15 };

#define WALK1  0
#define WALK2  1
#define WALK3  2
#define WALK4  3
#define WALK5  4
#define WALK6  5
#define WALK7  6
#define WALK8  7
#define JUMP1  8
#define JUMP2  9
#define JUMP3  10
#define JUMP4  11
#define JUMP5  12
#define JUMP6  13
#define JUMP7  14
#define JUMP8  15
#define EXPL1  16
#define EXPL2  17
#define EXPL3  18
#define EXPL4  19
#define EXPL5  20
#define EXPL6  21

UBYTE *mem_ptr;
struct IntuitionBase *IntuitionBase;
struct GfxBase *GfxBase;
struct Library *BitMapBase, *IconBase;
struct DisplayIDInformation *dinfo;
BOOL blanking = TRUE;

extern ULONG RangeSeed;
struct Screen *scr;
struct BitMap *Lemmingsbm, *storebm, *shadowbm, *scalebm, *breakbm, *scalebreakbm;
WORD x, y, dirx,
     blitx, blity, sizex, sizey, xoffs, yoffs;
UBYTE scaleX = 0, scaleY = 0;
struct BitMapScaleInfo bsi;
UBYTE depth, frame;
struct RastPort *rp;
PLANEPTR mask;


void MoveLemming( void )
{
x += dirx * 1<<scaleX;
if ( x < -((IMGW<<scaleX)>>1) )
	{
	x = -((IMGW<<scaleX)>>1);
	dirx = RangeRand( 4 ) + 1;
	bsi.bsi_Flags = 0L;
	}
if ( x >= scr->Width - 1 - (IMGW>>1) )
	{
	x = scr->Width - 1 - (IMGW>>1);
	dirx = - RangeRand( 4 ) - 1;
	bsi.bsi_Flags = BSIF_INVERTHOR;
	}
}


void BreakWall( void )
{
WORD hitx = x, hity = y;

/*if ( bsi.bsi_Flags & BSIF_INVERTHOR )
	hitx += 16 << scaleX;*/

if ( hitx < 0 )
	{ blitx = -hitx; sizex = (IMGW<<scaleX) + hitx; }
else if ( hitx >= scr->Width - (IMGW<<scaleX) )
	{ blitx = 0; sizex = scr->Width - hitx - 1; }
else
	{ blitx = 0; sizex = IMGW<<scaleX; }
if ( hity < 0 )
	{ blity = -hity; sizey = (IMGH<<scaleY) + hity; }
else if ( hity >= scr->Height - (IMGH<<scaleY) )
	{ blity = 0; sizey = scr->Height - hity - 1; }
else
	{ blity = 0; sizey = IMGH<<scaleY; }

if ( sizex && sizey && hitx < scr->Width )
	{
	BltBitMap( storebm, hitx < 0 ? 0 : ( hitx >= scr->Width ? scr->Width - 1 - hitx : hitx ), hity < 0 ? 0 : ( hity >= scr->Height ? scr->Height - 1 - hity : hity ),
		shadowbm, 0, 0,
		IMGW << scaleX, IMGH << scaleY, 0xC0, 0xFF, NULL );
	BltMaskBitMapRastPort( scalebreakbm, blitx, blity,
		rp, 0, 0,
		sizex, sizey, (ABC|ABNC|ANBC), scalebreakbm->Planes[0] );
	BltBitMap( shadowbm, 0, 0,
		storebm, hitx < 0 ? 0 : ( hitx >= scr->Width ? scr->Width - 1 - hitx : hitx ), hity < 0 ? 0 : ( hity >= scr->Height ? scr->Height - 1 - hity : hity ),
		sizex, sizey, 0xC0, 0xFF, NULL );
	}
else
	DisplayBeep( NULL );
}


BOOL CreateFrames( void )
{
BOOL success = FALSE;

if ( breakbm = AllocVec( sizeof(struct BitMap), MEMF_ANY|MEMF_CLEAR ) )
	{
	InitBitMap( breakbm, depth + 1, IMGW, IMGH );
	breakbm->Planes[0] = mem_ptr;
	breakbm->Planes[1] = mem_ptr + BITPLSIZE;
	breakbm->Planes[2] = mem_ptr + 2 * BITPLSIZE;
	breakbm->Planes[3] = mem_ptr + 3 * BITPLSIZE;
	breakbm->Planes[depth] = mem_ptr;

	if ( scalebreakbm = CreateBitMap( IMGW << scaleX, IMGH << scaleY, depth + 1 ) )
		{
		if ( Lemmingsbm = AllocVec( sizeof(struct BitMap), MEMF_ANY|MEMF_CLEAR ) )
			{
			InitBitMap( Lemmingsbm, depth + 1, IMGW, IMGH );
			Lemmingsbm->Planes[0] = mem_ptr;
			Lemmingsbm->Planes[1] = mem_ptr + BITPLSIZE;
			Lemmingsbm->Planes[2] = mem_ptr + 2 * BITPLSIZE;
			Lemmingsbm->Planes[3] = mem_ptr + 3 * BITPLSIZE;
			Lemmingsbm->Planes[depth] = mem_ptr + 4 * BITPLSIZE;

			if ( shadowbm = CreateBitMap( IMGW << scaleX, IMGH << scaleY, depth + 1 ) )
				{
				if ( scalebm = CreateBitMap( IMGW << scaleX, IMGH << scaleY, depth + 1 ) )
					{
					mask = scalebm->Planes[depth];

					bsi.bsi_SrcLeftEdge = 0;
					bsi.bsi_SrcTopEdge = 0;
					bsi.bsi_DestTopEdge = 0;
					bsi.bsi_HorDen = 1;
					bsi.bsi_VertDen = 1;
					bsi.bsi_TempBitMap = shadowbm;
					bsi.bsi_HorNum = 1 << scaleX;
					bsi.bsi_VertNum = 1 << scaleY;
					bsi.bsi_Flags = NULL;
					bsi.bsi_SrcBitMap = breakbm;
					bsi.bsi_DestBitMap = scalebreakbm;
					bsi.bsi_Width = IMGW;
					bsi.bsi_Height = IMGH;

					Decrunch30( mem_ptr, wallbrk_imgdata );
					bsi.bsi_DestLeftEdge = 0;
					bsi.bsi_Flags = NULL;
					ScaleBitMap( &bsi );

					bsi.bsi_SrcBitMap = Lemmingsbm;
					bsi.bsi_DestBitMap = scalebm;

					success = blanking;

					if ( !success ) DisposeBitMap( scalebm );
					}
				if ( !success ) DisposeBitMap( shadowbm );
				}
			if ( !success ) FreeVec( Lemmingsbm );
			}
		if ( !success ) DisposeBitMap( scalebreakbm );
		}
	if ( !success ) FreeVec( breakbm );	
	}

return success;
}


void GetDir( void )
{
do { dirx = RangeRand( 7 ) - 3; }
while ( !dirx );

if ( dirx > 0 )
	bsi.bsi_Flags = 0L;
else
	bsi.bsi_Flags = BSIF_INVERTHOR;
}


void GetCoords( void )
{
GetDir();
if ( dirx < 0 )
	x = scr->Width - 1;
else
	x = - IMGW + 1;

y = RangeRand( scr->Height ) - (IMGH>>1);
}


int CalcMeanTime( void )
{
ULONG secs1, mics1, secs2, mics2;
ULONG gfxr = GfxBase->DisplayFlags & PAL ? 715909 : 709379;
int tw1, tw2;

bsi.bsi_Flags = NULL;
CurrentTime( &secs1, &mics1 );
ScaleBitMap( &bsi );
CurrentTime( &secs2, &mics2 );
tw1 = ( ( secs2 - secs1 ) * 1000000 + mics2 - mics1 ) / gfxr;
bsi.bsi_Flags = BSIF_INVERTHOR;
CurrentTime( &secs1, &mics1 );
ScaleBitMap( &bsi );
CurrentTime( &secs2, &mics2 );
tw2 = ( ( secs2 - secs1 ) * 1000000 + mics2 - mics1 ) / gfxr;
return (tw2 - tw1);
}


void Blank( void )
{
register int n, ticks = 0, twait;
int status = WALK1;
ULONG mode;
Sound *ohno, *youpi;
UBYTE volume = GETVOLUME(dinfo);
BOOL success = FALSE;
UBYTE brightness = GETBRIGHTNESS(dinfo);

if ( scr = GetDeeperFrontmostScreen( brightness, 4 ) )
	{
	depth = scr->RastPort.BitMap->Depth;
	if ( depth <= 7 )
		{
		mode = scr->ViewPort.Modes;
		if ( mode & SUPERHIRES )
			{
			if ( mode & LACE )
				{ scaleX = 2; scaleY = 1; }
			else
				{ scaleX = 2; scaleY = 0; }
			}
		else if ( mode & HIRES )
			{
			if ( mode & LACE )
				{ scaleX = 1; scaleY = 1; }
			else
				{ scaleX = 1; scaleY = 0; }
			}
		else if ( mode & LACE )
			{ scaleX = 0; scaleY = 1; }

		if ( storebm = CreateBitMap( scr->Width, scr->Height, depth ) )
			{
			BltBitMap( scr->RastPort.BitMap, 0, 0,
				storebm, 0, 0,
				scr->Width, scr->Height, 0xC0, 0xFF, NULL );

			if ( CreateFrames() )
				{
				if ( rp = AllocVec( sizeof(struct RastPort), MEMF_ANY|MEMF_CLEAR ) )
					{
					success = TRUE;

					ohno = Open8SVX( "8SVX/Lemming.ohno" );
					youpi = Open8SVX( "8SVX/Lemming.youpi" );

					InitRastPort( rp );
					rp->BitMap = shadowbm;

					SpritesOff();

					for ( n = 1; n < 16; n++ )
						SetRGB32( &scr->ViewPort, n, ((Lemming_cmap32[n][0]>>24)*brightness/100)<<24, ((Lemming_cmap32[n][1]>>24)*brightness/100)<<24, ((Lemming_cmap32[n][2]>>24)*brightness/100)<<24 );

					twait = CalcMeanTime();

					GetCoords();

					while( STILL_BLANKING )
						{
						if ( !(bsi.bsi_Flags + scaleX + scaleY) && ++ticks < 10 - bsi.bsi_Flags ? twait : 0 )
							WaitTOF();
						else
							{
							ticks = 0;

							if ( status == WALK1 )
								{
								n = RangeRand( 10 );
								if ( !n )
									status = JUMP1;
								else if ( n == 2 )
									status = EXPL1;
								else if ( n == 3 )
									{
									status = WALK1;
									GetDir();
									}
								else status = WALK2;
								}
							else if ( status == WALK2 )
								{ MoveLemming(); status = WALK3; }
							else if ( status == WALK3 )
								{ MoveLemming(); status = WALK4; }
							else if ( status == WALK4 )
								{ MoveLemming(); status = WALK5; }
							else if ( status == WALK5 )
								{ MoveLemming(); status = WALK6; }
							else if ( status == WALK6 )
								{ MoveLemming(); status = WALK7; }
							else if ( status == WALK7 )
								{ MoveLemming(); status = WALK8; }
							else if ( status == WALK8 )
								{ MoveLemming(); status = WALK1; }
							else if ( status == JUMP1 )
								{ status = JUMP2; PlayAsynch8SVX( youpi, volume ); }
							else if ( status == JUMP2 )
								status = JUMP3;
							else if ( status == JUMP3 )
								status = JUMP4;
							else if ( status == JUMP4 )
								status = JUMP5;
							else if ( status == JUMP5 )
								status = JUMP6;
							else if ( status == JUMP6 )
								status = JUMP7;
							else if ( status == JUMP7 )
								status = JUMP8;
							else if ( status == JUMP8 )
								status = WALK1;
							else if ( status == EXPL1 )
								{ status = EXPL2; PlayAsynch8SVX( ohno, volume ); }
							else if ( status == EXPL2 )
								status = EXPL3;
							else if ( status == EXPL3 )
								status = EXPL4;
							else if ( status == EXPL4 )
								status = EXPL5;
							else if ( status == EXPL5 )
								{ status = EXPL6; BreakWall(); }
							else if ( status == EXPL6 )
								{ status = WALK1; GetCoords(); }

							if ( x < 0 )
								{ blitx = -x; sizex = (IMGW<<scaleX) + x; }
							else if ( x >= scr->Width - 1 - (IMGW<<scaleX) )
								{ blitx = 0; sizex = scr->Width - x; }
							else
								{ blitx = 0; sizex = IMGW<<scaleX; }

							if ( y < 0 )
								{ blity = -y; sizey = (IMGH<<scaleY) + y; }
							else if ( y >= scr->Height - 1 - (IMGH<<scaleY) )
								{ blity = 0; sizey = scr->Height - y; }
							else
								{ blity = 0; sizey = IMGH<<scaleY; }

							frame = WhichFrame[status];
							if ( !Decrunch30( mem_ptr, FrameAndMask[frame].frame ) )
								CopyMem( FrameAndMask[frame].frame, mem_ptr, 4 * BITPLSIZE );
							if ( !Decrunch30( Lemmingsbm->Planes[depth], FrameAndMask[frame].mask ) )
								CopyMem( FrameAndMask[frame].mask, Lemmingsbm->Planes[depth], BITPLSIZE );

							ScaleBitMap( &bsi );

							BltBitMap( storebm, x < 0 ? 0 : ( x >= scr->Width ? scr->Width - 1 - x : x ), y < 0 ? 0 : ( y >= scr->Height ? scr->Height - 1 - y : y ),
								shadowbm, 0, 0,
								IMGW << scaleX ,IMGH << scaleY, 0xC0, 0xFF, NULL );

							BltMaskBitMapRastPort( scalebm, blitx, blity, rp,
								0, 0, ( IMGW << scaleX ) - blitx, ( IMGH << scaleY ) - blity,
								(ABC|ABNC|ANBC), mask );

							WaitTOF();

							BltBitMap( shadowbm, 0, 0,
								scr->RastPort.BitMap, x < 0 ? 0 : ( x >= scr->Width ? scr->Width - 1 - x : x ), y < 0 ? 0 : ( y >= scr->Height ? scr->Height - 1 - y : y ),
								x < 0 ? IMGW << scaleX : sizex, y < 0 ? IMGH << scaleY : sizey, 0xC0, 0xFF, NULL );
							}
						}
					SpritesOn();

					Close8SVX( ohno );
					Close8SVX( youpi );

					FreeVec( rp );
					}
				DisposeBitMap( scalebm );
				DisposeBitMap( shadowbm );
				FreeVec( Lemmingsbm );
				DisposeBitMap( scalebreakbm );
				FreeVec( breakbm );
				}
			DisposeBitMap( storebm );
			}
		}
	CloseScreen( scr );
	}

if ( !success )
	SendClientMsg( ACTION_FAILED );
}


void __main( void )
{
if ( IntuitionBase = (struct IntuitionBase *)OpenLibrary( "intuition.library", 37L ) )
	{
	if ( GfxBase = (struct GfxBase *)OpenLibrary( "graphics.library", 37L ) )
		{
		if ( BitMapBase = OpenLibrary( "bitmap.library", 0L ) )
			{
			if ( mem_ptr = AllocVec( 5 * BITPLSIZE, MEMF_CHIP | MEMF_CLEAR ) )
				{
				if ( dinfo = OpenCommunication() )
					{
					CurrentTime( &RangeSeed, &RangeSeed );
					Blank();
					CloseCommunication( dinfo );
					}
				FreeVec( mem_ptr );
				}
			CloseLibrary( BitMapBase );
			}
		CloseLibrary( (struct Library *)GfxBase );
		}
	CloseLibrary( (struct Library *)IntuitionBase );
	}
}
