[comp.sources.amiga] Workbench Lander

peter@sugar.UUCP (Peter DaSilva) (06/29/87)

    Here is a nice little game by Peter DaSilva.  Running this and
Robotroff at the same time is quit a comination! ;-)  Great to play
while your bored downloading...  The "makefile.manx" is my own makefile
which you may have more luck with!
    Have fun!
	-Doc


#	This is a shell archive.
#	Remove everything above and including the cut line.
#	Then run the rest of the file through sh.
#----cut here-----cut here-----cut here-----cut here----#
#!/bin/sh
# Xshar: Extended Shell Archiver.
#	Run the following text with /bin/sh to create:
#	dumpsprite.c
#	makefile
#	makefile.manx
#	notes
#	rocket.c
# This archive created: Fri Jun 19 17:17:46 1987
# By: Craig Norborg (Purdue University Computing Center)
cat << \SHAR_EOF > dumpsprite.c
#include <intuition/intuition.h>
#define INTUITION_REV 1 
struct IntuitionBase *IntuitionBase;

main()
{
	struct Preferences prefs;
	int i;

	IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library", INTUITION_REV);
	if( IntuitionBase == NULL )
	{
		puts("can't open intuition\n");
		exit(-1);
	}

	GetPrefs(&prefs, sizeof prefs);
	printf("USHORT sprite_colors[3] = { 0x%04x, 0x%04x, 0x%04x };\n",
		prefs.color17, prefs.color18, prefs.color19);
	printf("USHORT sprite[%d] = {\n", POINTERSIZE);
	for(i = 0; i < POINTERSIZE; i += 2)
		printf("\t0x%04x, 0x%04x%s\n",
			prefs.PointerMatrix[i],
			prefs.PointerMatrix[i+1],
			(i+2<POINTERSIZE)?",":"");
	printf("};\n");
}
SHAR_EOF
cat << \SHAR_EOF > makefile
SUFFIXES:
SUFFIXES: .c .o .h

c.o:
	@-ram:c/del $*.o
	cc +P -S -B -DAMIGA $*.c

rocket : rocket.o
        ln -o rocket rocket.o -lcl32

dumpsprite : dumpsprite.o
        ln -o dumpsprite dumpsprite.o -lcl32
SHAR_EOF
cat << \SHAR_EOF > makefile.manx
CFLAGS = +P -S -B -DAMIGA

all: rocket dumpsprite

rocket : rocket.o
        ln -o rocket rocket.o -lcl32

dumpsprite : dumpsprite.o
        ln -o dumpsprite dumpsprite.o -lcl32
SHAR_EOF
cat << \SHAR_EOF > notes
This is the first program I ever wrote for the Amiga. A good part of it has
been cannibalised from YaBoing!. The images were generated by editing the
mouse cursor with preferences and the using the dumpsprite program to
turn them into 'C' structs. Make of it what you will.
SHAR_EOF
cat << \SHAR_EOF > rocket.c
#include <exec/types.h>
#include <exec/memory.h>
#include <intuition/intuition.h>
#include <graphics/sprite.h>
#include <hardware/custom.h>
#include <stdio.h> 
#include <ctype.h> 

#define INTUITION_REV 1 
#define GRAPHICS_REV  1 

#define SAUCERSPEED 200
#define SAUCERDELAY 200
#define ROCKETHEIGHT 16
#define SPRWIDTH 32
#define PIXRATIO 2
#define SCALEFACTOR 100
#define XMAX (640*SCALEFACTOR)
#define YMAX (200*SCALEFACTOR)
#define XMIN (-(SPRWIDTH/PIXRATIO)*SCALEFACTOR)
#define YMIN (-ROCKETHEIGHT*SCALEFACTOR)

#define OK 0
#define LANDED 1
#define CRASHEDGOOD 2
#define CRASHEDBAD 3
#define CRASHEDSAUCER 4

USHORT rocket_image[ROCKETHEIGHT*2] = {
	0x0000, 0x0000,
	0x0000, 0x0000,
	0x0100, 0x0100,
	0x0100, 0x0100,
	0x0380, 0x0380,
	0x0380, 0x0380,
	0x07c0, 0x07c0,
	0x07c0, 0x07c0,
	0x0fe0, 0x0fe0,
	0x0fe0, 0x0fe0,
	0x0820, 0x0820,
	0x0820, 0x0820,
	0x0820, 0x0820,
	0x0000, 0x0000,
	0x0000, 0x0000,
	0x0000, 0x0000,
};
USHORT flame[3][ROCKETHEIGHT*2] = {
{
	0x0000, 0x0000,
	0x0000, 0x0000,
	0x0100, 0x0100,
	0x0100, 0x0100,
	0x0380, 0x0380,
	0x0380, 0x0380,
	0x07c0, 0x07c0,
	0x0fc0, 0x37c0,
	0x0fe0, 0x0fe0,
	0x0fe0, 0x0fe0,
	0x0820, 0x0820,
	0x0820, 0x0820,
	0x0820, 0x0820,
	0x0000, 0x0000,
	0x0000, 0x0000,
	0x0000, 0x0000,
},
{
	0x0000, 0x0000,
	0x0000, 0x0000,
	0x0100, 0x0100,
	0x0100, 0x0100,
	0x0380, 0x0380,
	0x0380, 0x0380,
	0x07c0, 0x07c0,
	0x07e0, 0x07d8,
	0x0fe0, 0x0fe0,
	0x0fe0, 0x0fe0,
	0x0820, 0x0820,
	0x0820, 0x0820,
	0x0820, 0x0820,
	0x0000, 0x0000,
	0x0000, 0x0000,
	0x0000, 0x0000,
},
{
	0x0000, 0x0000,
	0x0000, 0x0000,
	0x0100, 0x0100,
	0x0100, 0x0100,
	0x0380, 0x0380,
	0x0380, 0x0380,
	0x07c0, 0x07c0,
	0x07c0, 0x07c0,
	0x0fe0, 0x0fe0,
	0x0fe0, 0x0fe0,
	0x0ba0, 0x0c60,
	0x0920, 0x0ee0,
	0x0920, 0x0aa0,
	0x0000, 0x0380,
	0x0000, 0x0100,
	0x0000, 0x0100,
}
};
USHORT sprite_colors[3] = { 0x0f95, 0x0d44, 0x0fff };
#define SAUCERHEIGHT 5
USHORT saucer_image[3][SAUCERHEIGHT*2] = {
{
	0x0ff0, 0x0ff0,
	0xffff, 0xffff,
	0xb6db, 0x6db6,
	0xffff, 0xffff,
	0x0ff0, 0x0ff0
},
{
	0x0ff0, 0x0ff0,
	0xffff, 0xffff,
	0x6db6, 0xdb6d,
	0xffff, 0xffff,
	0x0ff0, 0x0ff0
},
{
	0x0ff0, 0x0ff0,
	0xffff, 0xffff,
	0xdb6d, 0xb6db,
	0xffff, 0xffff,
	0x0ff0, 0x0ff0
}
};

UWORD *rbuf, *sbuf;
struct SimpleSprite rocket, saucer;
int rocket_sprite, saucer_sprite;
struct Window *window, *badwindow;
struct ViewPort *viewport;
struct Remember *Memory;

/*   Intuition always wants to see these declarations */
struct IntuitionBase *IntuitionBase;
struct GfxBase *GfxBase;

/* my window structure */
struct NewWindow NewWindow = {
	160,  50, 
	240,  10, 
	0,    1, 
	INTUITICKS | CLOSEWINDOW | RAWKEY | ACTIVEWINDOW | INACTIVEWINDOW,
	WINDOWCLOSE | SMART_REFRESH | ACTIVATE | WINDOWDRAG | WINDOWDEPTH,
	NULL, 
	NULL, 
	"Workbench Lander", 
	NULL, 
	NULL, 
	0, 0, 
	0, 0, 
	WBENCHSCREEN, 
};

struct NewWindow BadWindow = {
	160, 11,
	240, 10,
	0, 1,
	ACTIVEWINDOW | INACTIVEWINDOW | CLOSEWINDOW,
	WINDOWCLOSE | SMART_REFRESH | WINDOWDRAG | WINDOWDEPTH,
	NULL,
	NULL,
	"Don't land here...",
	NULL,
	NULL,
	0, 0,
	0, 0,
	WBENCHSCREEN,
};
struct IntuiMessage *NewMessage;

/******************************************************/
/*                   Main Program                     */
/*                                                    */
/*      This is the main body of the program.         */
/******************************************************/

int x, y, vx, vy, ax, ay;
int buttons = 0;

char *cycle[] = {
	"Workbench Lander",
	"Use cursor keys to",
	"Land on this window",
	"Workbench Lander",
	"Don't hit too hard",
	"Workbench Lander",
	"Don't fall over",
	"Workbench Lander",
	"Don't get caught",
	"Workbench Lander",
	"Space is big",
	"Space is dark",
	"It's hard to find",
	"A place to park",
	"BURMA SHAVE",
	"Workbench Lander",
	"Another fine hack",
	"by Peter da Silva",
	0
};

addflame(n)
int n;
{
	buttons |= n;
	recalc_rocket();
}

delflame(n)
int n;
{
	buttons &= ~n;
	recalc_rocket();
}

recalc_rocket()
{
	int b, i;
	rbuf[0] = rbuf[1] = 0;
	for(i = 0; i < 2*ROCKETHEIGHT; i++)
		rbuf[i+2] = rocket_image[i];
	rbuf[2*ROCKETHEIGHT+2] = 0;
	rbuf[2*ROCKETHEIGHT+3] = 0;

	for(b = 0; b < 3; b++)
		if(buttons & (1<<b))
			for(i = 0; i < 2*ROCKETHEIGHT; i++)
				rbuf[i+2] |= flame[b][i];

	ChangeSprite(viewport, &rocket, rbuf);
}

set_saucer(n)
int n;
{
	int i;

	sbuf[0] = sbuf[1] = 0;
	for(i = 0; i < 2*SAUCERHEIGHT; i++)
		sbuf[i+2] = saucer_image[n][i];
	sbuf[2*SAUCERHEIGHT+2] = 0;
	sbuf[2*SAUCERHEIGHT+3] = 0;

	ChangeSprite(viewport, &saucer, sbuf);
}

#define BEGIN_EXPLOSION 0
#define IN_EXPLOSION 1
#define END_EXPLOSION 2
int exploding;
int coloregs;
int counter;

int KeepGoing;
int timeout;
int cycle_position, cycle_timeout;
int saucer_timeout, saucer_x, saucer_y, saucer_cycle, saucer_up;

explode()
{
	int i;
	if(!exploding) {
		counter = 21;
		exploding = 1;
	}
	if(counter-- < 0) {
		exploding = 0;
		x = y = 200;
		vx = 100;
		vy = 0;
		ax = 0;
		ay = 10;
		saucer_timeout = SAUCERDELAY;
		timeout = 10;
		for(i = 0; i < 3; i++)
			SetRGB4(viewport, coloregs+1+i,
				sprite_colors[i]&0x000F,
				(sprite_colors[i]&0x00F0)>>4,
				(sprite_colors[i]&0x0F00)>>8);
	} else {
		for(i = 0; i < 3; i++)
			SetRGB4(viewport, coloregs+1+i,
				RangeRand(16),
				RangeRand(16),
				RangeRand(16));
	}
}

main()
{
	int i;

	Memory = NULL;

	IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library", INTUITION_REV);
	if( IntuitionBase == NULL )
	{
		puts("can't open intuition\n");
		cleanup_and_exit(50);
	}

	GfxBase = (struct GfxBase *)OpenLibrary("graphics.library",GRAPHICS_REV);
	if( GfxBase == NULL )
	{
		puts("can't open graphics library\n");
		cleanup_and_exit(50);
	}

	if(( window = (struct Window *)OpenWindow(&NewWindow) ) == NULL)
	{
		puts("can't open window\n");
		cleanup_and_exit(50);
	}

	if(( badwindow = (struct Window *)OpenWindow(&BadWindow) ) == NULL)
	{
		puts("can't open obstacle\n");
		cleanup_and_exit(50);
	}

	viewport = ViewPortAddress(window);

	if((rocket_sprite = GetSprite(&rocket, 2)) == -1)
		if((rocket_sprite = GetSprite(&rocket, 4)) == -1)
		if((rocket_sprite = GetSprite(&rocket, 6)) == -1) {
			puts("can't get rocket_sprite\n");
			cleanup_and_exit(50);
		}
	if((saucer_sprite = GetSprite(&saucer, rocket_sprite+1)) == -1) {
		puts("can't get saucer_sprite\n");
		cleanup_and_exit(50);
	}
	rocket.x = 0;
	rocket.y = 0;
	rocket.height = ROCKETHEIGHT;
	saucer.x = 0;
	saucer.y = 0;
	saucer.height = SAUCERHEIGHT;

	coloregs = ((rocket_sprite & 0x06)*2)+16;

	for(i = 0; i < 3; i++)
		SetRGB4(viewport, coloregs+1+i,
			sprite_colors[i]&0x000F,
			(sprite_colors[i]&0x00F0)>>4,
			(sprite_colors[i]&0x0F00)>>8);

	if(!(rbuf = AllocRemember(&Memory, 4L * ROCKETHEIGHT + 8L, MEMF_CHIP)))
		cleanup_and_exit(50);

	if(!(sbuf = AllocRemember(&Memory, 4L * SAUCERHEIGHT + 8L, MEMF_CHIP)))
		cleanup_and_exit(50);

	buttons = 0;
	recalc_rocket();
	set_saucer(0);

	KeepGoing = TRUE;

	timeout = 0;
	cycle_timeout = 10;
	cycle_position = 0;

	saucer_timeout = SAUCERDELAY;
	saucer_up = 0;
	MoveSprite(viewport, &saucer, -20, -20);

	SetWindowTitles(window, -1, "Workbench Lander (C) 1987 by Peter da Silva");
	x = y = 200;
	vx = 100;
	vy = 0;
	ax = 0;
	ay = 10;
	MoveSprite(viewport, &rocket, x/SCALEFACTOR, y/SCALEFACTOR);

	while( KeepGoing )
	{
		Wait((1 << window->UserPort->mp_SigBit) |
		     (1 << badwindow->UserPort->mp_SigBit));
		WaitTOF();

		while( NewMessage=(struct IntuiMessage *)GetMsg(badwindow->UserPort) )
		{
			ReplyMsg( NewMessage );
			switch( NewMessage->Class )
			{
			case CLOSEWINDOW:
				KeepGoing = FALSE;
				break;
			case ACTIVEWINDOW:
				SetWindowTitles(badwindow, "...or click here", -1);
				break;
			case INACTIVEWINDOW:
				SetWindowTitles(badwindow, BadWindow.Title, -1);
				break;
			}
		}

		while( NewMessage=(struct IntuiMessage *)GetMsg(window->UserPort) )
		{
			ReplyMsg( NewMessage );
			switch( NewMessage->Class )
			{
			case CLOSEWINDOW:
				KeepGoing = FALSE;
				break;
			case RAWKEY:
				switch(NewMessage -> Code) {
					case 0x4C:
					    addflame(4);
						ay = -40; 
						break;
					case 0x4C|0x80:
						delflame(4);
						ay = 10; 
						break;
					case 0x4E:
						addflame(1);
						ax = 10;
						break;
					case 0x4F|0x80:
						delflame(3);
						ax = 0;
						break;
					case 0x4E|0x80:
						delflame(3);
						ax = 0;
						break;
					case 0x4F:
						addflame(2);
						ax = -10;
						break;
				}
				break;
			case ACTIVEWINDOW:
				SetWindowTitles(window, cycle[cycle_position], -1);
				break;
			case INACTIVEWINDOW:
				SetWindowTitles(window, "Click me", -1);
				break;
			case INTUITICKS:
				if(exploding) {
					explode();
					break;
				}
				if(timeout > 0) {
					timeout--;
					if(timeout == 0) {
						SetWindowTitles(badwindow, BadWindow.Title, -1);
						SetWindowTitles(window, cycle[cycle_position], -1);
						cycle_timeout = 10;
					}
				} else if(timeout == 0) {
					cycle_timeout--;
					if(cycle_timeout <= 0) {
						cycle_timeout = 10;
						cycle_position++;
						if(cycle[cycle_position]==0)
							cycle_position = 0;
						SetWindowTitles(window, cycle[cycle_position], -1);
					}
				}
				if(saucer_timeout == 0) {
					int dx, dy;
					if(saucer_up == 0) {
						saucer_up = 1;
						saucer_x = 200;
						saucer_y = 200;
						saucer_cycle = 0;
					}
					set_saucer(saucer_cycle++);
					if(saucer_cycle >= 3)
						saucer_cycle = 0;
					dx = dy = 0;
					if(saucer_x < x-SAUCERSPEED)
						dx = SAUCERSPEED;
					else if(saucer_x > x+SAUCERSPEED)
						dx = -SAUCERSPEED;
					if(saucer_y < y-SAUCERSPEED)
						dy = SAUCERSPEED;
					else if(saucer_y > y+SAUCERSPEED)
						dy = -SAUCERSPEED;
					if(dy == 0) dx += dx/2;
					if(dx == 0) dy += dy/2;
					saucer_x += dx;
					saucer_y += dy;
					MoveSprite(viewport, &saucer,
						saucer_x/SCALEFACTOR, saucer_y/SCALEFACTOR);
				} else  {
					if(saucer_timeout != -1)
						saucer_timeout--;
					if(saucer_up) {
						saucer_up = 0;
						MoveSprite(viewport, &saucer, -20, -20);
					}
				}

				x += vx;
				y += vy;
				vx += ax;
				vy += ay;

				if(x > XMAX) x = XMIN;
				if(x < XMIN) x = XMAX;
				if(y < YMIN) y = YMAX;
				if(y > YMAX) y = YMIN;

				switch(HitWindow()) {
					case OK:
						if(ay==0) {
							ay = 10;
							timeout = 10;
							saucer_timeout = SAUCERDELAY;
						}
						break;
					case LANDED:
						if(vy >= -2*SCALEFACTOR && vy < 0) {
							timeout = 10;
							saucer_timeout = SAUCERDELAY;
							break;
						}
					   	if(vy >= 0 && vy <= SCALEFACTOR &&
						   vx >= -20 && vx <= 20) {
							if(timeout >= 0) {
								if(vy <= 30 && vx == 0)
									SetWindowTitles(window, "Great Landing!", -1);
								else if(vy <= 70 && vx == 0)
									SetWindowTitles(window, "Good Landing.", -1);
								else
									SetWindowTitles(window, "Just made it...", -1);
							}
							timeout = -1;
							vx = vy = 0;
							ax = ay = 0;
							saucer_timeout = -1;
							break;
						}
					case CRASHEDGOOD:
						SetWindowTitles(window, "OUCH! That hurt!", -1);
						explode();
						break;
					case CRASHEDBAD:
						SetWindowTitles(badwindow, "OUCH! That hurt!", -1);
						explode();
						break;
					case CRASHEDSAUCER:
						SetWindowTitles(window, "GOTCHA!", -1);
						explode();
						break;
				}
				MoveSprite(viewport, &rocket,
					x/SCALEFACTOR, y/SCALEFACTOR);
				break;
			}   /* end of switch (class) */
		}   /* end of while ( newmessage )*/
	}  /* end while ( keepgoing ) */
	cleanup_and_exit(0);
} /* end of main */

cleanup_and_exit(flag)
{
	if(saucer_sprite > 0)
		FreeSprite(saucer_sprite);
	if(rocket_sprite > 0)
		FreeSprite(rocket_sprite);
	FreeRemember(&Memory, TRUE);
	if(badwindow)
		CloseWindow(badwindow);
	if(window)
		CloseWindow(window);
	if(GfxBase)
		CloseLibrary(GfxBase);
	if(IntuitionBase)
		CloseLibrary(IntuitionBase);
	exit(flag);
}

HitWindow()
{
	int sx = x/SCALEFACTOR;
	int sy = y/SCALEFACTOR;
	int ret;

	ret = checkwindow(sx, sy, window, 1);
	if(!ret)
		ret = checkwindow(sx, sy, badwindow, 0);
	if(!ret)
		ret = checksaucer();
	return ret;
}

checkwindow(sx, sy, window, canland)
int sx, sy;
struct Window *window;
int canland;
{
	int top = window->TopEdge-ROCKETHEIGHT+3;
	int bottom = window->TopEdge+window->Height - 2;
	int left = window->LeftEdge-SPRWIDTH+4*PIXRATIO;
	int right = window->LeftEdge+window->Width-5*PIXRATIO;

	if(sx<left || sx>right) return OK;
	if(sy>bottom || sy<top) return OK;
	if(canland) {
		if(sy>top+3) return CRASHEDGOOD;
		if(sx<left+7*PIXRATIO || sx>right-7*PIXRATIO) return CRASHEDGOOD;
		return LANDED;
	} else {
		return CRASHEDBAD;
	}
}

checksaucer()
{
	int sx, sy, rx, ry, top, bottom, left, right;

	if(!saucer_up) return OK;

	rx = x/SCALEFACTOR;
	ry = y/SCALEFACTOR;
	sx = saucer_x/SCALEFACTOR;
	sy = saucer_y/SCALEFACTOR;

	top = sy-ROCKETHEIGHT+3;
	bottom = sy+SAUCERHEIGHT - 2;
	left = sx-SPRWIDTH+4*PIXRATIO;
	right = sx+SPRWIDTH-5*PIXRATIO;

	if(rx<left || rx>right) return OK;
	if(ry>bottom || ry<top) return OK;
	return CRASHEDSAUCERKfKfK)$k,k)$;