home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The Fred Fish Collection 1.5
/
ffcollection-1-5-1992-11.iso
/
ff_disks
/
200-299
/
ff218.lzh
/
Worm
/
worm.c
< prev
next >
Wrap
C/C++ Source or Header
|
1989-06-04
|
12KB
|
429 lines
/*
* worm.c
*
* Adapted from the Scientific American article 12/87. Original for Sun UNIX.
* Original Author - Brad Taylor (sun!brad)
* Adapted to the Amiga by Chuck McManis (sun!cmcmanis)
* Basically there are five switches they are :
* -l n Set the length of the worms to 'n' units, this defaults to 32.
* -s n Set the size of the worm units to n X n, defaults to 1 but try
* some larger sizes too, their kinda neat.
* -n n Set the number of worms on the screen, defaults to 16 worms which
* is fairly slow, 4 is pretty quick. Numbers like 3000 are neat too.
* -r n Set the screen resolution, 0 = low res (320 X 200), 1 = medium (640 X 200)
* and 2 = high (640 X 400)
* -d n Set number of bitplanes, 1-5 are acceptable numbers.
*
* Note this uses a random number generator that Leo used in demo.c
* Copyright (C) 1987 by Charles McManis
* Freely Redistributable if you leave the above comment and following declaration
* intact ...
*/
static char copyright[] = "Copyright (C) 1987, Charles McManis, ok to copy.";
#include <exec/types.h>
#include <exec/memory.h>
#include <intuition/intuition.h>
#include <graphics/gfxbase.h>
#include <graphics/gfx.h>
#include <graphics/rastport.h>
#include <devices/inputevent.h>
#include <libraries/diskfont.h>
#include <stdio.h>
#include <math.h>
#ifdef LATTICE
#include <proto/dos.h>
#include <proto/graphics.h>
#endif
/* Declare the required Intuition pointers */
struct IntuitionBase *IntuitionBase;
struct GfxBase *GfxBase;
struct DiskfontBase *DiskfontBase;
/* Declare some global tool stuff */
struct Window *MyWindow;
struct Menu *MyMenu, *CurrentMenu;
struct Screen *MyScreen;
struct TextFont *MyFont;
/* Declare some defines that make the code a bit more readable */
#define SIGBIT(w) (1L << (w->UserPort->mp_SigBit))
#define GetIntuiMessage(w) (struct IntuiMessage *)GetMsg(w->UserPort)
struct TextAttr ta = {"topaz.font",11,0,0};
#define CMSIZE 30 /* Max color map size */
#define CMFUDGE 2 /* colors needed for borders and background */
#define SEGMENTS 36 /* Size of sin and cos tables */
#define MAXCOLOR 15 /* Most intense color */
extern char *malloc();
int wormlength = 32;
int circsize = 1;
int nworms = 16;
int black,white;
int cmsize;
int sintab[SEGMENTS];
int costab[SEGMENTS];
/*
* Initialized data section. These structures are pre-initialized with
* the values that the program knows ahead of time.
*/
struct NewScreen ns = {
0,0,640,400,3, /* (X,Y) (W,H) (bitplanes) */
1,0, /* Foreground, Background */
0, /* View Modes (defaults to none */
CUSTOMSCREEN, /* What else is new */
NULL, /* Font is set up below */
"Worms, implementation by Chuck McManis V1.0",
NULL, /* No special Gadgets */
NULL /* No Custom Bitmap */
};
struct NewWindow nw = {
0,0,640,400, /* (X,Y) (W,H) */
7,6, /* Foreground, Background */
CLOSEWINDOW+REFRESHWINDOW,
WINDOWCLOSE+SIMPLE_REFRESH+ACTIVATE,
NULL, /* No special Gadgets */
NULL, /* Use the default Checkmark */
"Squiggly Worms, Implementation by Chuck McManis",
NULL, /* This will be our screen pointer */
NULL, /* We'll use the Bitmap we get */
640,400,640,400, /* No resizing going on */
CUSTOMSCREEN /* We'll use our own screen thankyou */
};
/*
* Some declarations for worm,
*/
USHORT colors[32]; /* A place to create the color table */
int ScreenRes = 1; /* Screen Resolution (0=low 2=hi) */
ULONG MaxX, MaxY; /* Window inside dimensions */
struct wormstuff {
int *xcirc;
int *ycirc;
int dir;
int tail;
int x;
int y;
int id;
};
void worm_doit(),drawseg(),goaway(),usage(), color_setup();
short rnd();
struct wormstuff *worm_init();
/*
* Ok, declarations are out of the way, on with the main function
*/
void main(argc,argv)
int argc;
char *argv[];
{
struct IntuiMessage *im; /* Intuimessage pointer */
struct Window *wp; /* Temporary window pointer */
ULONG class; /* Message Class holder */
USHORT code,qual;/* Message Code and qualifiers */
SHORT msx,msy; /* Mouse Co-ordinates for event */
int i, /* Your basic counter variable */
xsize,ysize,
depth; /* How many bitplanes did you want? */
struct wormstuff **worm; /* Worm data */
char *cmd;
cmd = argv[0];
depth = 3; /* default depth */
rnd(0);
if (argc == 0) { /* Started from workbench */
printf("Worm length : ");
scanf("%d",&wormlength);
printf("Number of worms [n] :");
scanf("%d",&nworms);
printf("Worm width [n] :");
scanf("%d",&circsize);
printf("Screen Resolution [0=Low, 1=Medium, 2=High] :");
scanf("%d",&ScreenRes);
printf("Number of bitplanes [1-5 for Low res, 1-4 for medium or high] :");
scanf("%d",&depth);
}
for (i = 1; i < argc; i++) {
if (i == argc - 1 || argv[i][0] != '-' || argv[i][2] != 0) {
usage(cmd);
}
switch (argv[i][1]) {
case 'l':
wormlength = atoi(argv[++i]);
break;
case 'n':
nworms = atoi(argv[++i]);
break;
case 's':
circsize = atoi(argv[++i]);
break;
case 'r':
ScreenRes = atoi(argv[++i]);
break;
case 'd':
depth = atoi(argv[++i]);
if ((depth < 1) || (depth > 5)) usage(cmd);
break;
default:
usage(cmd);
}
}
if ((ScreenRes > 0) && (depth == 5)) depth = 4;
cmsize = (1 << depth) - CMFUDGE;
for (i = 0; i < SEGMENTS; i++) {
sintab[i] = round(circsize * sin(i * 2 * PI / SEGMENTS));
costab[i] = round(circsize * cos(i * 2 * PI / SEGMENTS));
}
/* Open the intuition library first ... */
IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library",0);
if (! IntuitionBase) goaway();
/* Now opening the graphics library ... */
GfxBase = (struct GfxBase *)OpenLibrary("graphics.library",0);
if (! GfxBase) goaway();
/* Now opening the diskfont library ... */
DiskfontBase = (struct DiskfontBase *)OpenLibrary("diskfont.library",0);
if (! DiskfontBase) goaway();
/* This opens a custom screen to the maximum possible size ... */
ns.Depth = depth;
ns.Width = GfxBase->NormalDisplayColumns;
ns.Height = GfxBase->NormalDisplayRows;
switch (ScreenRes) {
case 0 :
ns.Width /= 2;
ta.ta_YSize = 8;
ta.ta_Flags |= FPF_ROMFONT;
ns.Font = &ta;
break;
case 1 :
ns.ViewModes |= HIRES;
/* In medium res use Topaz 8 */
ta.ta_YSize = 8;
ta.ta_Flags |= FPF_ROMFONT;
ns.Font = &ta;
break;
case 2 :
ns.Height *= 2;
ns.ViewModes |= HIRES+LACE;
/* In Interlace mode us Topaz 11 */
ns.Font = &ta;
}
/* Now we open the font we want so that it will be resident when the
* OpenScreen call below needs it.
*/
MyFont = (struct TextFont *) OpenDiskFont(&ta);
MyScreen = (struct Screen *)OpenScreen(&ns);
if (! MyScreen) goaway();
color_setup(); /* Initialize the color map */
/* OK so far, now lets open a full size window ... */
nw.Screen = MyScreen;
nw.TopEdge = 1; /* Leave a row to grab the screen drag bar */
nw.Width = ns.Width;
nw.Height = ns.Height-1;
nw.DetailPen = white; /* initialized by color_setup() */
nw.BlockPen = black;
MyWindow = (struct Window *)OpenWindow(&nw);
if (! MyWindow) goaway();
SetFont(MyWindow->RPort,MyFont); /* This should not be required ! */
MaxX = xsize = MyWindow->Width-MyWindow->BorderLeft-MyWindow->BorderRight;
MaxY = ysize = MyWindow->Height-MyWindow->BorderTop-MyWindow->BorderBottom;
SetAPen(MyWindow->RPort,black);
RectFill(MyWindow->RPort, MyWindow->BorderLeft,MyWindow->BorderTop,
MyWindow->BorderLeft+xsize, MyWindow->BorderTop+ysize);
worm = (struct wormstuff **)malloc((unsigned)(sizeof(struct wormstuff *) * nworms));
for (i = 0; i < nworms; i++) {
worm[i] = worm_init(xsize, ysize, wormlength);
}
if (!cmsize) cmsize = 1;
for (;;) {
for (i = 0; i < nworms; i++) {
worm_doit((void *)MyWindow->RPort, worm[i], xsize, ysize,
(((i * cmsize) / nworms) % cmsize));
}
/* Note: If we are running continuously we don't Wait(), this lets */
/* the program continue to update the screen until the user sends */
/* it some form of request. */
while ((im = GetIntuiMessage(MyWindow)) != NULL) {
class = im->Class; /* Extract relavent info */
code = im->Code;
qual = im->Qualifier; /* Stuff like shift down etc */
msx = im->MouseX; /* And the mouse position */
msy = im->MouseY;
wp = im->IDCMPWindow; /* Figure out which window sent this message */
ReplyMsg(im); /* Reply quickly! */
switch (class) {
case CLOSEWINDOW : /* Process a close window message. */
goaway(); /* Exit the program */
case REFRESHWINDOW :
BeginRefresh(MyWindow);
EndRefresh(MyWindow,TRUE);
break;
default : /* We choose to ignore unknown message classes */
break;
} /* switch statement */
} /* until no messages are still waiting */
}
}
/*
* Utility routines used by the Worm Program...
*/
/*
* Function goaway()
*
* This function shuts down after we are done. Since this can happen at
* anytime, it checks the various global variables and those that have
* been initialized (non-null), it removes/clears etc depending on the
* variable.
*/
void goaway()
{
if (MyWindow) CloseWindow(MyWindow);
if (MyScreen) CloseScreen(MyScreen);
if (GfxBase) CloseLibrary(GfxBase);
if (MyFont) CloseFont(MyFont);
if (DiskfontBase) CloseLibrary(DiskfontBase);
if (IntuitionBase) CloseLibrary(IntuitionBase);
exit(0); /* This cleans up FILE pointers and malloc'd memory */
}
struct wormstuff *
worm_init(xsize, ysize, wormlength)
int xsize;
int ysize;
int wormlength;
{
static int thisworm = 0;
int i;
struct wormstuff *ws;
ws = (struct wormstuff *)malloc((unsigned)sizeof(struct wormstuff));
ws->xcirc = (int *)malloc((unsigned)(wormlength * sizeof(int)));
ws->ycirc = (int *)malloc((unsigned)(wormlength * sizeof(int)));
for (i = 0; i < wormlength; i++) {
ws->xcirc[i] = xsize / 2;
ws->ycirc[i] = ysize / 2;
}
ws->dir = rnd(SEGMENTS);
ws->tail = 0;
ws->x = xsize / 2;
ws->y = ysize / 2;
ws->id = thisworm;
thisworm = (thisworm + 1) % 14;
return (ws);
}
void
worm_doit(h, priv, xsize, ysize, color)
void *h;
void *priv;
int xsize;
int ysize;
int color;
{
int x;
int y;
struct wormstuff *ws = (struct wormstuff *)priv;
ws->tail = (ws->tail + 1) % wormlength;
x = ws->xcirc[ws->tail];
y = ws->ycirc[ws->tail];
drawseg(h, x, y, black);
if ((rnd(32765)&(1<<ws->id)) != 0) {
ws->dir = (ws->dir + 1) % SEGMENTS;
} else {
ws->dir = (ws->dir + SEGMENTS - 1) % SEGMENTS;
}
x = (ws->x + costab[ws->dir] + xsize) % xsize;
y = (ws->y + sintab[ws->dir] + ysize) % ysize;
ws->xcirc[ws->tail] = x;
ws->ycirc[ws->tail] = y;
/* Note when using one bitplane worm_doit gets called with color == 0 */
drawseg(h, x, y, (color != black) ? color : 1);
ws->x = x;
ws->y = y;
}
round(x)
float x;
{
if (x >= 0) return ((int)(x + .5));
return ((int)(x - .5));
}
/* Note that drawseg does it's own clipping... */
void
drawseg(priv, x, y, color)
void *priv;
int x;
int y;
int color;
{
struct RastPort *gfx = (struct RastPort *)priv;
ULONG X,Y;
X = ((unsigned) x % (MaxX-circsize)) + MyWindow->BorderLeft;
Y = ((unsigned) y % (MaxY-circsize)) + MyWindow->BorderTop;
SetAPen(gfx,color);
if (circsize == 1) WritePixel(gfx,X,Y);
else RectFill(gfx,X,Y,X+circsize,Y+circsize);
}
/* Sets up some reasonable colors ... note CMSIZE is max colors and
* cmsize is the actual number of colors
*/
void
color_setup()
{
int i;
for (i = 0; i < cmsize; i++) {
colors[i] = rnd(4096);
}
colors[cmsize] = 0;
colors[cmsize+1] = 4095;
LoadRGB4(&(MyScreen->ViewPort),colors,cmsize+CMFUDGE); /* Load in our colors */
black = cmsize;
white = cmsize+1;
}
void
usage(cmd)
char *cmd;
{
(void)fprintf(stderr,
"usage: %s [-l length] [-s size] [-n number] [-r resolution] [-d depth]\n", cmd);
exit(1);
}