ewhac@well.UUCP (03/21/87)
[ You watch: Reagan will get munched by a line eater. ] This is BIG. A lot bigger than I had originally anticipated or desired. Nevertheless, people seem to like it, and I finally "finished" it. It's my latest display hack. It's called "Robotroff". By the way, when is someone going to notice all this code I've been writing and offer me a job? I can write serious programs too, you know. While I do enjoy writing this stuff, I'd enjoy it even more if someone were paying me for it. Anyway, I think you'll like this one. Hope you haven't thrown away your Manx 3.20a compiler yet. Schwab ------------------ Andy Finkel will know what to do here. ---------------- #! /bin/sh # This is a shell archive, meaning: # 1. Remove everything above the #! /bin/sh line. # 2. Save the resulting text in a file. # 3. Execute the file with /bin/sh (not csh) to create: # README # robotroff.doc # makefile # robotroff.h # _main.c # functions.c # robotroff.c # sprites.c # rnd.asm # This archive created: Sat Mar 21 00:39:13 1987 # By: Leo 'Bols Ewhac' Schwab () export PATH; PATH=/bin:/usr/bin:$PATH if test -f 'README' then echo shar: "will not over-write existing file 'README'" else cat << \SHAR_EOF > 'README' Hello again. A friend of mine suggested that I write this. So I did. I'm rather proud of this one. It's my most ambitious display hack yet. It's called "Robotroff". I'd tell you what this does, but much of the enjoyment of this program is derived from its surprise value. Therefore, I think you'll be better served if you compile and/or run this program without first trying to determine what it does. If your curiosity level won't permit that, then read the robotroff.doc file for instructions. MANUFACTURE Here's how to make this monstrosity: 1> make There. That wasn't so bad, was it? USEAGE Just type "robotroff" at a CLI prompt. Trust me. If you're absolutely convinced that nothing happened, try again, using "robotroff -i". CAVEATS This program compiles under Manx 3.20a --==>> ONLY. <<==-- I'm almost positive it won't compile/link under Manx 3.40 without modification to the _main.c file. (Aside: You can safely eliminate the _main.c file, but you lose one of the major features of the program by doing this. Check the source for more information.) If there's enough demand, and if I ever get my 3.40 upgrade, I'll create a version that will work with that. Further, I suspect that this will never work under Lattice without a major re-write. (Postscript: Jim Goodnow II handed me a copy of 3.40 at the last BADGE meeting, and I've had a chance to look at it. It will take me a few day to get up to speed on 3.40, but I will be posting a 3.40-compatible version of _main.c. Look for it in about a week or two (or three...).) Also, there apparently is a problem with invoking this program from a Resident-CLI. It may or may not crash the system if invoked this way. Moral: Invoke from a normal CLI and save your aspirin. I hope you like this one. I do. I hope my friend does. _-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_ ________ ___ Leo L. Schwab \ /___--__ The Guy in The Cape ___ ___ /\ ---##\ ihnp4!ptsfa!well!ewhac / X \_____ | __ _---)) ..or.. / /_\-- -----+==____\ // \ _ well ---\ ___ ( o---+------------------O/ \/ \ dual ----> !unicom!ewhac \ / ___ \_ (`o ) hplabs -/ ("AE-wack") ____ \___/ \_/ Recumbent Bikes: "Work FOR? I don't work FOR The _O_n_l_y Way To Fly! anybody! I'm just having fun." SHAR_EOF fi if test -f 'robotroff.doc' then echo shar: "will not over-write existing file 'robotroff.doc'" else cat << \SHAR_EOF > 'robotroff.doc' ROBOTROFF(1) Amiga User's Manual ROBOTROFF(1) NAME robotroff - insidious display hack SYNOPSIS robotroff [-h[n]] [-l[n]] [-p[n]] [-i] [-kill] DESCRIPTION Robotroff is yet another display hack from the warped mind of Leo Schwab. Upon invocation, robotroff installs itself in the background and returns your CLI prompt. It can also be run from the WorkBench. Robotroff continues to run until killed off. Robotroff consumes very little CPU, even when active, so it may be left running until a reset or power-off. Subsequent invocations of robotroff will attempt to locate the original invocation, and pass information to it. Thus, it is possible to modify the operating parameters of the program while it runs in the background. The following options are supported: -h[n] Sets the "highwater" time delay length. The amount of time between activity will be no longer than n seconds. If n is not supplied, or is negative or zero, a default of two minutes will be used. -l[n] Sets the "lowater" time delay length. The amount of time between activity will be no shorter than n seconds. If n is not supplied, or is negative or zero, a default of thirty seconds will be used. -p[n] Sets the task priority. This permits the user to make robotroff consume even less CPU. If n is absent, zero is assumed. -i Force activity to occur right now (immediately). -kill Kills off the original robotroff invocation. Robotroff will announce that it has been terminated, then exit, freeing all allocated resources. This option is meaningless and therefore ignored if supplied when first running robotroff. Malformed or unrecognized arguments are silently ignored. EXAMPLES robotroff Starts background robotroff process. robotroff -i Makes background process active immediately. robotroff -h10 -l5 Reconfigures operating parameters. robotroff -p-2 Sets priority to -2. robotroff -kill Terminates background process. AUTHOR Leo L. Schwab BUGS Probably. Report them to the author as they are encountered. Note that lack of a desired feature is not considered a bug. SHAR_EOF fi if test -f 'makefile' then echo shar: "will not over-write existing file 'makefile'" else cat << \SHAR_EOF > 'makefile' # :ts=8 # Makefile for robotroff. I'm not an expert at makefiles, # so please forgive my stupidity. OBJECTS = _main.o robotroff.o functions.o sprites.o rnd.o robotroff: $(OBJECTS) ln $(OBJECTS) +cd -lc -o robotroff robotroff.o functions.o: robotroff.h SHAR_EOF fi if test -f 'robotroff.h' then echo shar: "will not over-write existing file 'robotroff.h'" else cat << \SHAR_EOF > 'robotroff.h' /* :ts=8 bk=0 * * robotroff.h Various defines. * * Leo L. Schwab 8703.16 */ #define PORTNAME "Robotroff Control Port" #define CMDSIG (1L << cmdport -> mp_SigBit) #define TIMESIG (1L << timeport -> mp_SigBit) #define DEFAULTHIGHWATER 120 #define DEFAULTLOWATER 30 #define HULKHEIGHT 16 #define GRUNTHEIGHT 13 #define NFORCEHEIGHT 13 #define MINX -20 #define MINY -20 #define COLLISION 0x0200 #define collision() (cstm -> clxdat & COLLISION) #define getcbase(sn) (((sn) >> 1 << 2) + 16) #define getr(c) (((c) & 0x0f00) >> 8) #define getg(c) (((c) & 0x00f0) >> 4) #define getb(c) ((c) & 0x000f) #define abs(n) ((n) < 0 ? -(n) : (n)) #define sgn(n) ((n) < 0 ? -1 : (n) > 0) struct control { /* Control block to alter operating parameters */ struct Message msg; UWORD actions; int highwater, lowater, newpri; }; #define SETHIGH 1 #define SETLOW (1<<1) #define SETPRI (1<<2) #define DOSOMETHING (1<<3) #define SUICIDE (1<<4) extern void *OpenLibrary(), *OpenWindow(), *ViewPortAddress(), *CreateStdIO(), *CreateExtIO(), *CreatePort(), *FindPort(), *GetMsg(), *FindTask(); extern long Wait(), GetSprite(), VBeamPos(), OpenDevice(); extern short rnd(); SHAR_EOF fi if test -f '_main.c' then echo shar: "will not over-write existing file '_main.c'" else cat << \SHAR_EOF > '_main.c' /* :ts=8 bk=0 * * Copyright (C) 1986,1987 by Manx Software Systems, Inc. * Modified and made available for general use with permission of * Manx Software Systems, Inc. * *------------------------------------------------------------------------ * * This is special code which can be run from the Workbench or from the * CLI. When run from the CLI, the program detaches itself from the CLI * and starts running in the background (giving your CLI prompt back). * This means that all I/O from the program must be through windows * created by the program. * * This startup routine correctly handles a start from the WorkBench. * If started from the CLI, it will pass the command line arguments to the * "child" process. This routine also handles quoted arguments (in a * rather primitive way). * * This suceesfully compiles and runs under MANX 3.20a. Not guaranteed * to work with other compilers. Probably won't work with MANX 3.40, * either (without modification). * * Original version by (and profuse thanks to) * Jim Goodnow II 86??.?? * Severely enhanced by Leo L. Schwab 8703.12 */ #include <ctype.h> #include <fcntl.h> #include <exec/alerts.h> #include <exec/memory.h> #include <libraries/dosextens.h> #include <workbench/startup.h> #define ERRSTR "Improperly quoted argument.\n" #define ERRLEN 28L #define FATALSTR "Fatal error on startup.\n" #define FATALEN 24L extern long _Open(), _Input(), _Output(), _CurrentDir(), CreateProc(); extern void *_OpenLibrary(), *_GetMsg(), *_AllocMem(), *_FindTask(); struct _dev { long fd; short mode; } _devtab[20]; struct _preserve { struct Message msg; char **av, *ab; long cd; int ac, al; }; long _savsp; int errno, Enable_Abort; void *SysBase, *DOSBase, *MathBase, *MathTransBase; static struct WBStartup *WBenchMsg; static int argc, arglen; static char **argv, *argbuf; static char unique[] = "Highly Unlikely Program Invocation Name"; _main(alen, aptr) long alen; char *aptr; { register struct Process *pp; register struct CommandLineInterface *cli; register long l; register unsigned short c; register char *cp; struct FileHandle *fp; struct MemList *mm; struct _preserve *p; static long cdir = 0; long *lp; void *sav; if (!(DOSBase = _OpenLibrary (DOSNAME, 0L))) { Alert (AG_OpenLib | AO_DOSLib, 0L); _exit (100); } pp = _FindTask(0L); if (pp->pr_CLI) { /* CLI invocation (first run) */ cdir = _CurrentDir (0L); _CurrentDir (cdir); /* Parse out command line arguments */ cli = (struct CommandLineInterface *) ((long)pp->pr_CLI << 2); cp = (char *) ((long) cli -> cli_CommandName << 2); arglen = *cp + alen + 2; /* *cp is BSTR len */ argbuf = _AllocMem ((long) arglen, MEMF_PUBLIC | MEMF_CLEAR); strncpy (argbuf, cp+1, *cp); /* Copy command name */ strcpy (argbuf + *cp, " "); /* Space separator */ strncat (argbuf, aptr, (int) alen+1); /* Copy args */ argbuf[*cp] = '\0'; /* Terminate full cmd name */ for (argc=1, cp=argbuf + *cp + 1;; argc++) { while (isspace (*cp)) cp++; if (*cp < ' ') { *cp = 0; break; /* Stop on ctl char */ } if (*cp == '"') { /* Handle quoted args */ *cp = ' '; /* Squash quote mark */ while ((c = *cp) && c != '"') cp++; if (!c) { /* No matching quote */ _Write (_Output(), ERRSTR, ERRLEN); _exit (200); } *cp++ = 0; } else { while ((c = *cp) && !isspace (c)) cp++; *cp++ = 0; if (!c) break; /* Stop at end-of-line */ } } /* Assemble argv[] array */ argv = _AllocMem ((long) (argc+1) * sizeof (*argv), MEMF_PUBLIC); for (c=0, cp=argbuf; c<argc; c++) { while (isspace (*cp)) cp++; argv[c] = cp; cp += strlen (cp) + 1; } argv[c] = 0; /* Preserve argument environment */ if (!(p = _AllocMem ((long) sizeof (*p), MEMF_PUBLIC))) { Alert (AG_NoMemory, 0L); _exit (100); } p -> ac = argc; p -> av = argv; p -> ab = argbuf; p -> al = arglen; p -> cd = cdir; /* Argument list finished. Detatch program. */ l = cli -> cli_Module; if (!(sav = _OpenLibrary (DOSNAME, 33L))) { /* Malarkee for 1.1 DOS braindamage */ lp = (long *)*((long *)*((long *)*((long *)*((long *) _savsp+2)+1)-3)-3)+107; if (*lp != cli -> cli_Module) { _Write (_Output(), FATALSTR, FATALEN); _exit (300); } } else { _CloseLibrary (sav); lp = 0; } /* Prevent DOS from unloading us */ if (lp) *lp = 0; cli -> cli_Module = 0; #asm move.l __savsp,-(sp) #endasm _Forbid (); PutMsg (CreateProc (unique, 0L, l, 5120L), p); _CloseLibrary (DOSBase); #asm move.l (sp)+,sp rts #endasm } else /* Check if this is this is the second time through */ if (!strcmp (pp->pr_Task.tc_Node.ln_Name, unique)) { /* Recover parent's arguments */ _WaitPort (&pp -> pr_MsgPort); p = _GetMsg (&pp -> pr_MsgPort); argv = p -> av; argc = p -> ac; argbuf = p -> ab; arglen = p -> al; cdir = p -> cd; _FreeMem (p, (long) sizeof (*p)); /* Change process name to something reasonable */ pp -> pr_Task.tc_Node.ln_Name = argv[0]; /* Convert DOS's seglist to MemList */ lp = (long *) ((long) pp -> pr_SegList << 2); lp = (long *) (lp[3] << 2); sav = lp; c = 0; while (lp) { lp = (long *) (*lp << 2); c++; } mm = _AllocMem ((long) sizeof (struct MemList)+ (c-1)*sizeof (struct MemEntry), MEMF_PUBLIC); lp = sav; mm -> ml_NumEntries = c; c = 0; while (lp) { mm -> ml_me[c].me_Addr = (APTR) lp - 1; mm -> ml_me[c].me_Length = lp[-1]; lp = (long *) (*lp << 2); c++; } /* Add MemList to task structure to force auto-unload */ AddTail (&((struct Task *)pp)->tc_MemEntry, mm); _CurrentDir (cdir); main (argc, argv); _exit (0); } else { /* Started from WorkBench */ _WaitPort (&pp -> pr_MsgPort); WBenchMsg = _GetMsg (&pp -> pr_MsgPort); if (WBenchMsg -> sm_ArgList) _CurrentDir (WBenchMsg -> sm_ArgList -> wa_Lock); if (WBenchMsg -> sm_ToolWindow) if (_devtab[0].fd = _Open (WBenchMsg->sm_ToolWindow, MODE_OLDFILE)) { _devtab[1].fd = _devtab[2].fd = _devtab[0].fd; _devtab[0].mode = 0x8000; _devtab[1].mode = _devtab[2].mode = 0x8001; fp=(struct FileHandle *) (_devtab[0].fd << 2); pp -> pr_ConsoleTask = (APTR) fp -> fh_Type; } main (0, WBenchMsg); _exit (0); } } void (*_cln)() = 0; _exit (code) { int fd; for (fd = 0; fd < 20; fd++) close (fd); if (_cln) (*_cln)(); if (MathTransBase) _CloseLibrary (MathTransBase); if (MathBase) _CloseLibrary (MathBase); if (DOSBase) _CloseLibrary (DOSBase); if (!WBenchMsg) { /* Free the argument list */ _FreeMem (argbuf, (long) arglen); if (argv) _FreeMem (argv, (long) (argc+1) * sizeof (*argv)); } else { _Forbid (); _ReplyMsg (WBenchMsg); } #asm move.l 8(a5),d0 ; Get return code move.l __savsp,sp ; Restore original stack pointer rts ; Bye-bye! #endasm } SHAR_EOF fi if test -f 'functions.c' then echo shar: "will not over-write existing file 'functions.c'" else cat << \SHAR_EOF > 'functions.c' /* :ts=8 bk=0 * * functions.c: Functions to do obscene things to mouse pointer. * * Leo L. Schwab 8703.18 (415)-456-6565 */ #include <exec/types.h> #include <intuition/intuition.h> #include <graphics/sprite.h> #include <hardware/custom.h> #include "robotroff.h" extern UWORD hr1[], hr2[], hr3[], hl1[], hl2[], hl3[], hu1[], hu2[], hu3[], gr1[], gr2[], gr3[], nforce[], hulkcolor[], gruntcolor[], nforcecolor[]; extern struct IOStdReq *ioreq; extern struct InputEvent mouse; extern struct SimpleSprite spr; extern struct Preferences prefs; extern struct Window *win; extern struct Screen *wbs; extern long sprnum; extern int wide, high; extern void *vp; struct Custom *cstm = 0xdff000; UWORD *leftseq[] = { hl1, hl2, hl1, hl3 }; UWORD *rightseq[] = { hr1, hr2, hr1, hr3 }; UWORD *udseq[] = { hu1, hu2, hu1, hu3 }; UWORD *gruntseq[] = { gr1, gr2, gr1, gr3 }; static int idxsav, dirchange; /* * This particular piece of code turned out to be gut-wrenchingly messy. * But it's the only way I could think of to make it work the way I wanted. * If you know of a cleaner algorithm, write it, send it to me, and I'll * use it in a revised version of the program. */ dohulk () { register UWORD **sequence; register int idx = 0, dx, dy; int mx, my, ox, oy, dhx, dhy, x1, y1, x2, y2, flag = 0; setcolors (vp, (int) sprnum, hulkcolor); startxy (&spr.x, &spr.y); if (spr.x == MINX || spr.x == wide) /* Determine starting dir */ flag = 1; spr.height = HULKHEIGHT; ChangeSprite (0L, &spr, leftseq[idx]); mx = cstm -> clxdat; /* Clear collision status */ trackmouse: while (1) { getmousexy (&mx, &my, HULKHEIGHT); dx = mx - spr.x; dy = my - spr.y; dhx = 4 * sgn (dx); dhy = 2 * sgn (dy); if (flag) { x1 = x2 = rnd (abs (dx)) * sgn (dx) + spr.x; y1 = spr.y; y2 = my; } else { y1 = y2 = rnd (abs (dy)) * sgn (dy) + spr.y; x1 = spr.x; x2 = mx; } ox = mx; oy = my; if (flag) { dx = dhx; dy = 0; if (walkhulkx (spr.x, x1, dhx)) break; getmousexy (&mx, &my, HULKHEIGHT); if (mx != ox || my != oy) continue; dx = 0; dy = dhy; if (walkhulky (y1, y2, dhy)) break; getmousexy (&mx, &my, HULKHEIGHT); if (mx != ox || my != oy) continue; dx = dhx; dy = 0; if (walkhulkx (x2, mx, dhx)) break; } else { dx = 0; dy = dhy; if (walkhulky (spr.y, y1, dhy)) break; getmousexy (&mx, &my, HULKHEIGHT); if (mx != ox || my != oy) continue; dx = dhx; dy = 0; if (walkhulkx (x1, x2, dhx)) break; getmousexy (&mx, &my, HULKHEIGHT); if (mx != ox || my != oy) continue; dx = 0; dy = dhy; if (walkhulky (y2, my, dhy)) break; } flag = rnd (2); } if (dx) sequence = dx>0 ? rightseq : leftseq; else sequence = udseq; idx = idxsav; ox = oy = -9999; while (1) { spr.x += dx; spr.y += dy; idx = ++idx & 3; ChangeSprite (0L, &spr, sequence[idx]); movemouse (dx, dy); mx = collision(); Delay (6L); if (!collision()) { idxsav = idx; goto trackmouse; } getmousexy (&mx, &my, HULKHEIGHT); if (mx == ox && my == oy) /* Mouse at limit */ break; ox = mx; oy = my; } /* Finish walking hulk off screen */ while ((int) spr.x < wide && (int) spr.x > MINX && (int) spr.y < high && (int) spr.y > -HULKHEIGHT) { spr.x += dx; spr.y += dy; idx = ++idx & 3; ChangeSprite (0L, &spr, sequence[idx]); Delay (6L); } } dogrunt () { register int idx = 0; int gx, gy, mx, my; setcolors (vp, (int) sprnum, gruntcolor); startxy (&gx, &gy); spr.x = gx; spr.y = gy; spr.height = GRUNTHEIGHT; ChangeSprite (0L, &spr, gruntseq[idx]); mx = cstm -> clxdat; /* Clear collision status */ /* This will keep chasing you around until it gets you :-> */ while (!collision()) { idx = ++idx & 3; getmousexy (&mx, &my, GRUNTHEIGHT); if (mx != gx) gx += mx > gx ? 4 : -4; if (my != gy) gy += my > gy ? 4 : -4; spr.x = gx; spr.y = gy; ChangeSprite (0L, &spr, gruntseq[idx]); Delay (rnd (7) + 4L); } flashpointer (); MoveSprite (0L, &spr, (long) MINX, 0L); } enforce () { register int track, lim, inc; int mx, my, ox = -999, oy = -999, ex, ey, dx, dy, flag = 0; setcolors (vp, (int) sprnum, nforcecolor); startxy (&ex, &ey); spr.x = ex; spr.y = ey; spr.height = NFORCEHEIGHT; ChangeSprite (0L, &spr, nforce); mx = cstm -> clxdat; /* Clear collision bits */ /* * This is a DDA algorithm that attempts to track the mouse pointer * in a straight line, no matter where it is. It keeps tracking * until it gets it. */ while (!collision()) { getmousexy (&mx, &my, NFORCEHEIGHT); if (mx != ox || my != oy) { /* Mouse moved */ dx = mx - ex; dy = my - ey; if (abs (dx) > abs (dy)) { flag = 1; lim = abs (dx); inc = abs (dy); } else { flag = 0; lim = abs (dy); inc = abs (dx); } track = lim/2; ox = mx; oy = my; } if (flag) { ex += sgn (dx); if ((track += inc) > lim) { track -= lim; ey += sgn (dy); } } else { ey += sgn (dy); if ((track += inc) > lim) { track -= lim; ex += sgn (dx); } } MoveSprite (0L, &spr, (long) ex, (long) ey); WaitTOF (); } flashpointer (); MoveSprite (0L, &spr, (long) MINX, 0L); } walkhulkx (startx, endx, dx) { register UWORD **sequence; register int x, idx = 0; if (dirchange) idx = idxsav; dirchange = 1; sequence = dx>0 ? rightseq : leftseq; for (x=startx; dx>0 ? x<endx : x>endx; x+=dx, idx = ++idx & 3) { spr.x = x; ChangeSprite (0L, &spr, sequence[idx]); Delay (6L); if (collision()) { idxsav = idx; return (1); } } idxsav = idx; return (0); } walkhulky (starty, endy, dy) { register int y, idx = 0; if (!dirchange) idx = idxsav; dirchange = 0; for (y=starty; dy>0 ? y<endy : y>endy; y+=dy, idx = ++idx & 3) { spr.y = y; ChangeSprite (0L, &spr, udseq[idx]); Delay (6L); if (collision()) { idxsav = idx; return (1); } } idxsav = idx; return (0); } startxy (x, y) register int *x, *y; { if (rnd (2)) { *x = rnd (2) ? MINX : wide; *y = rnd (200); } else { *y = rnd (2) ? MINY : high; *x = rnd (320); } } getmousexy (x, y, sprheight) register int *x, *y; { register struct Screen *s = wbs; *x = (s -> MouseX >> 1) - 8; if (s -> ViewPort.Modes & LACE) *y = (s -> MouseY >> 1) + s -> TopEdge - sprheight/2; else *y = s -> MouseY + s -> TopEdge - sprheight/2; } setcolors (vp, spritenum, clist) void *vp; register UWORD *clist; { long r, g, b, colorbase; register int i; colorbase = getcbase (spritenum); for (i=1; i<4; i++) { r = getr (clist[i]); g = getg (clist[i]); b = getb (clist[i]); SetRGB4 (vp, colorbase + i, r, g, b); } } flashpointer () { long rs, gs, bs, dr, dg, db, rd, gd, bd; register int i, n; rs = gs = bs = 15; rd = getr (prefs.color0); gd = getg (prefs.color0); bd = getb (prefs.color0); /* Compute increments */ dr = rd - rs; dg = gd - gs; db = bd - bs; for (n=15; n>6; n--) { /* First flash */ for (i=0; i<3; i++) SetRGB4 (vp, 17L + i, (long) n, (long) n, (long) n); WaitTOF (); } rs <<= 4; gs <<= 4; bs <<= 4; for (n=0; n<16; n++) { /* Fade to background */ rs += dr; gs += dg; bs += db; for (i=0; i<3; i++) SetRGB4 (vp, 17L + i, rs>>4, gs>>4, bs>>4); WaitTOF (); WaitTOF (); WaitTOF (); WaitTOF (); } Delay (150L); SetRGB4 (vp, 17L, (long) getr (prefs.color17), /* Yuck! */ (long) getg (prefs.color17), (long) getb (prefs.color17)); SetRGB4 (vp, 18L, (long) getr (prefs.color18), (long) getg (prefs.color18), (long) getb (prefs.color18)); SetRGB4 (vp, 19L, (long) getr (prefs.color19), (long) getg (prefs.color19), (long) getb (prefs.color19)); } movemouse (dx, dy) { mouse.ie_NextEvent = 0; mouse.ie_Class = IECLASS_RAWMOUSE; mouse.ie_TimeStamp.tv_secs = mouse.ie_TimeStamp.tv_micro = 0; mouse.ie_Code = IECODE_NOBUTTON; mouse.ie_Qualifier = IEQUALIFIER_RELATIVEMOUSE; mouse.ie_X = prefs.PointerTicks * (dx + dx); /* Is this *really* right? */ mouse.ie_Y = prefs.PointerTicks * (dy + dy); if (DoIO (ioreq)) die ("I/O error."); } SHAR_EOF fi if test -f 'robotroff.c' then echo shar: "will not over-write existing file 'robotroff.c'" else cat << \SHAR_EOF > 'robotroff.c' /* :ts=8 bk=0 * * robotroff.c: Insidious display hack. * * Leo L. Schwab 8703.17 (415)-456-6565 * * Public Domain. Reproduce at will. However, the author would greatly * appreciate it if: * 1) All parts of the program are made available free of charge * (or for cost of media), * 2) You don't use this in a commercial product unless you at least * tell me about it, * 3) This notice and the author's name are preserved, even across * subsequent revisions (I want to be famous, you see). * * Naturally, you don't *have* to abide by these terms. Just remember * that if you do violate them, it means you are morally bankrupt. You * wouldn't want people to think that about you, would you? * ************************************************************************* A few notes on the code: Bits of it are extremely messy. Some of it looks unnecessary or wrong. As it turns out, this program works as written. Hope you can understand the code; some of it is instructive. Watch out for ternary operators; I've used quite a few of them. Since this is supposed to be a background display hack, it was important to me to make it as small as I could and still do interesting things. This meant leaving out a couple of features I would have liked. It would have been nice to have an explosion noise when the grunt or enforcer ran into the mouse. I was also thinking about arranging things so that, if you plugged in a joystick at port 2 and tilted it around, you could shoot the enemy sprites. These are ideas that the more ambitious among you might want to add in. Some of you may have even more insidious ideas. Go right ahead. I encountered some odd behavior in the system I never noticed before. For example, if you AbortIO() an I/O request, the reply gets posted to your reply port, and the signal you might Wait() on gets set. WaitIO() does not clear this signal apparently; I had to do it myself. Also, when moving the mouse pointer with false InputEvents, I noticed that the mouse pointer, even in a 200-line screen, assumes it's in a 400-line screen, and therefore a "movement" of 2 results in an actual pointer movement of 1. Odd. Does anyone have an explanation for this? I tried to write the code in a such a way that it *should* work on an interlaced screen, as well as one that's been 'morerows'ed. However, since 'morerows' causes overscan, which tromps sprite DMA, this may not work on an overscan screen. Oddly enough, it also seems to work with any combination of screens, no matter their arrangement. I had fun writing this program. I hope you like it at least as much as you liked Oing. "If you've enjoyed this program just half as much as I've enjoyed writing it, then I'll have enjoyed it twice as much as you." Have fun, Leo L. Schwab *************************************************************************/ #include <ctype.h> #include <exec/types.h> #include <exec/alerts.h> #include <intuition/intuition.h> #include <graphics/sprite.h> #include <devices/input.h> #include "robotroff.h" /* We're just opening this to get a pointer to the WorkBench ViewPort */ struct NewWindow windef = { 0, 0, 3, 10, -1, -1, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, 0, 0, WBENCHSCREEN }; struct MsgPort *ioport, *timeport, *cmdport; struct IOStdReq *ioreq; struct timerequest *timereq; struct control *ctl; struct InputEvent mouse; struct SimpleSprite spr; struct Preferences prefs; struct Screen *wbs; struct Window *win; long sprnum = -1; int wide, high; void *vp; void *IntuitionBase, *GfxBase; /* I take so many liberties with void *'s, it's scary. */ main (ac, av) char **av; { void *daemon; if (daemon = FindPort (PORTNAME)) reconfigure (ac, av, daemon); else { dodaemon (ac, av); postmessage ("Robotroff daemon terminated."); } closestuff (); } dodaemon (ac, av) char **av; { /* * cmdport in this context means the port at which commands arrive * for the daemon to act on. */ register struct control *msg; long csig, tsig, signals; int hw = DEFAULTHIGHWATER, lw = DEFAULTLOWATER, now = 0; void *me, *oldms; openstuff (); rnd ((short) -VBeamPos()); /* Seed generator */ me = FindTask (NULL); /* Parse command args */ if (ac) while (++av, --ac) { if (!strncmp (*av, "-h", 2)) { hw = atoi (&(*av)[2]); if (hw <= 0) hw = DEFAULTHIGHWATER; } else if (!strncmp (*av, "-l", 2)) { lw = atoi (&(*av)[2]); if (lw <= 0) lw = DEFAULTLOWATER; } else if (!strncmp (*av, "-p", 2)) SetTaskPri (me, (long) atoi (&(*av)[2])); else if (!strcmp (*av, "-i")) now = 1; } if (hw < lw) /* hw time must not be shorter than lw time */ lw = hw; tsig = TIMESIG; csig = CMDSIG; while (1) { if (now) { now = 0; goto dosomething; } timereq -> tr_time.tv_secs = rnd (hw-lw+1) + lw; timereq -> tr_time.tv_micro = 0; SendIO (timereq); signals = Wait (tsig | csig); if (signals & csig) { /* Command from another task (user) */ msg = GetMsg (cmdport); AbortIO (timereq); WaitIO (timereq); /* * The I/O reply causes a signal to be * raised, which screws things up. So * we clear it. */ Wait (tsig); if (msg -> actions & SUICIDE) { ReplyMsg (msg); break; } if (msg -> actions & SETHIGH) hw = msg -> highwater; if (msg -> actions & SETLOW) lw = msg -> lowater; if (hw < lw) lw = hw; if (msg -> actions & SETPRI) SetTaskPri (me, (long) msg -> newpri); if (msg -> actions & DOSOMETHING) now = 1; ReplyMsg (msg); } if (signals & tsig) { /* Timer went off, time to do something weird */ WaitIO (timereq); dosomething: switch (rnd (5)) { case 0: case 1: dohulk (); break; case 2: case 3: dogrunt (); break; case 4: enforce (); } } } } reconfigure (ac, av, daemonport) char **av; void *daemonport; { /* * cmdport in this context means the reply port for commands to * the daemon. */ if (ac < 2) /* Nothing to do */ return; /* In order to use die(), we have to open Intuition. */ if (!(IntuitionBase = OpenLibrary ("intuition.library", 0L))) { Alert (AG_OpenLib | AO_Intuition, 0L); closestuff (); exit (20); } GetPrefs (&prefs, (long) sizeof (prefs)); if (!(cmdport = CreatePort (NULL, NULL))) die ("Can't create command reply port."); if (!(ctl = CreateExtIO (cmdport, (long) sizeof (*ctl)))) die ("Can't create command block."); /* Parse command line args */ while (++av, --ac) { if (!strncmp (*av, "-h", 2)) { ctl -> highwater = atoi (&(*av)[2]); if (ctl -> highwater <= 0) ctl -> highwater = DEFAULTHIGHWATER; ctl -> actions |= SETHIGH; } else if (!strncmp (*av, "-l", 2)) { ctl -> lowater = atoi (&(*av)[2]); if (ctl -> lowater <= 0) ctl -> lowater = DEFAULTLOWATER; ctl -> actions |= SETLOW; } else if (!strncmp (*av, "-p", 2)) { ctl -> newpri = atoi (&(*av)[2]); ctl -> actions |= SETPRI; } else if (!strcmp (*av, "-i")) ctl -> actions |= DOSOMETHING; else if (!strcmp (*av, "-kill")) ctl -> actions |= SUICIDE; } /* Send command to daemon */ PutMsg (daemonport, ctl); WaitPort (cmdport); GetMsg (cmdport); } openstuff () { if (!(IntuitionBase = OpenLibrary ("intuition.library", 0L))) { Alert (AG_OpenLib | AO_Intuition, 0L); closestuff (); exit (20); } GetPrefs (&prefs, (long) sizeof (prefs)); if (!(GfxBase = OpenLibrary ("graphics.library", 0L))) die ("Art shop closed."); /* Set up a few environment things based on screen info */ if (!(win = OpenWindow (&windef))) die ("Window painted shut."); vp = ViewPortAddress (win); wbs = win -> WScreen; CloseWindow (win); win = 0; high = wbs -> Height; wide = wbs -> Width; if (wbs -> ViewPort.Modes & HIRES) wide /= 2; if (wbs -> ViewPort.Modes & LACE) high /= 2; if ((sprnum = GetSprite (&spr, 2L)) < 0) die ("Couldn't get sprite."); if (!(cmdport = CreatePort (PORTNAME))) die ("Can't create command port."); if (!(timeport = CreatePort (NULL, NULL))) die ("Can'r create time port."); if (!(timereq = CreateExtIO (timeport, (long) sizeof (*timereq)))) die ("Can't make timer I/O."); if (OpenDevice (TIMERNAME, UNIT_VBLANK, timereq, 0L)) { timereq -> tr_node.io_Device = 0; die ("Can't open timer device."); } timereq -> tr_node.io_Command = TR_ADDREQUEST; if (!(ioport = CreatePort (NULL, NULL))) die ("Can't create I/O port."); if (!(ioreq = CreateStdIO (ioport))) die ("Can't make I/O request."); if (OpenDevice ("input.device", 0L, ioreq, 0L)) { ioreq -> io_Device = 0; die ("Can't generate input."); } ioreq -> io_Command = IND_WRITEEVENT; ioreq -> io_Flags = 0; ioreq -> io_Length = sizeof (struct InputEvent); ioreq -> io_Data = (APTR) &mouse; } closestuff () { if (ioreq) { if (ioreq -> io_Device) CloseDevice (ioreq); DeleteStdIO (ioreq); } if (timereq) { if (timereq -> tr_node.io_Device) CloseDevice (timereq); DeleteExtIO (timereq, (long) sizeof (*timereq)); } if (ctl) DeleteExtIO (ctl, (long) sizeof (*ctl)); if (cmdport) DeletePort (cmdport); if (ioport) DeletePort (ioport); if (timeport) DeletePort (timeport); if (sprnum >= 0) FreeSprite (sprnum); if (win) CloseWindow (win); if (GfxBase) CloseLibrary (GfxBase); if (IntuitionBase) CloseLibrary (IntuitionBase); } die (str) char *str; { postmessage (str); closestuff (); exit (10); } postmessage (str) char *str; { if (win) CloseWindow (win); /* Should never happen */ windef.TopEdge = 0; windef.Height = 10; windef.Width = 8 + strlen (str) * (prefs.FontHeight == TOPAZ_SIXTY ? 10 : 8); windef.LeftEdge = (640 - windef.Width) / 2; windef.DetailPen = 1; windef.BlockPen = 3; windef.Flags |= ACTIVATE; windef.Title = (UBYTE *) str; if (!(win = OpenWindow (&windef))) /* Crash system and let user worry about it */ Alert (AN_OpenWindow, 0L); Delay (200L); CloseWindow (win); win = 0; } SHAR_EOF fi if test -f 'sprites.c' then echo shar: "will not over-write existing file 'sprites.c'" else cat << \SHAR_EOF > 'sprites.c' /* :ts=8 bk=0 * * sprites.c: Sprite data. Painted in DPaint and dumped out with 'gi' * ('ilbmdump' didn't work for me). * * Leo L. Schwab 8703.16 */ #include <exec/types.h> /* Hulk sprites (16) */ UWORD hulkcolor[] = { 0x0000, 0x00f0, 0x0fff, 0x0f00 }; /* Left walking hulks */ UWORD hl1[] = { 0x0000,0x0000, 0x0000,0x03e0, 0x0080,0x0080, 0x0080,0x0080, 0x1e3c,0x01c0, 0x1e3c,0x01c0, 0x1e3c,0x01c0, 0x1e3c,0x01c0, 0x1e3c,0x01c0, 0x1e3c,0x01c0, 0x1c3c,0x03c0, 0x01c0,0x01c0, 0x01c0,0x01c0, 0x01c0,0x01c0, 0x07c0,0x07c0, 0x0000,0x0000, 0x0000,0x0000, 0x0000,0x0000 }; UWORD hl2[] = { 0x0000,0x0000, 0x03e0,0x0000, 0x0080,0x0080, 0x0080,0x0080, 0x1e3c,0x01c0, 0x1c7c,0x0380, 0x18fc,0x0700, 0x11fc,0x0e00, 0x03fc,0x5c02, 0x07fc,0x3803, 0x0ffc,0x1000, 0x0370,0x0370, 0x661c,0x661c, 0x3c06,0x3c06, 0x181c,0x181c, 0x0000,0x0000, 0x0000,0x0000, 0x0000,0x0000 }; UWORD hl3[] = { 0x0000,0x0000, 0x03e0,0x03e0, 0x0080,0x0080, 0x0080,0x0080, 0x1f1c,0x00e0, 0x1f8c,0x0070, 0x1fc4,0x0038, 0x1fe0,0x001c, 0x1ff0,0x200e, 0x1ff8,0x6006, 0x1ffc,0x0000, 0x0370,0x0370, 0x661c,0x661c, 0x3c06,0x3c06, 0x181c,0x181c, 0x0000,0x0000, 0x0000,0x0000, 0x0000,0x0000 }; /* Right walking hulks */ UWORD hr1[] = { 0x0000,0x0000, 0x0000,0x07c0, 0x0100,0x0100, 0x0100,0x0100, 0x3c78,0x0380, 0x3c78,0x0380, 0x3c78,0x0380, 0x3c78,0x0380, 0x3c78,0x0380, 0x3c78,0x0380, 0x3c38,0x03c0, 0x0380,0x0380, 0x0380,0x0380, 0x0380,0x0380, 0x03e0,0x03e0, 0x0000,0x0000, 0x0000,0x0000, 0x0000,0x0000 }; UWORD hr2[] = { 0x0000,0x0000, 0x07c0,0x0000, 0x0100,0x0100, 0x0100,0x0100, 0x3c78,0x0380, 0x3e38,0x01c0, 0x3f18,0x00e0, 0x3f88,0x0070, 0x3fc0,0x403a, 0x3fe0,0xc01c, 0x3ff0,0x0008, 0x0ec0,0x0ec0, 0x3866,0x3866, 0x603c,0x603c, 0x3818,0x3818, 0x0000,0x0000, 0x0000,0x0000, 0x0000,0x0000 }; UWORD hr3[] = { 0x0000,0x0000, 0x07c0,0x07c0, 0x0100,0x0100, 0x0100,0x0100, 0x38f8,0x0700, 0x31f8,0x0e00, 0x23f8,0x1c00, 0x07f8,0x3800, 0x0ff8,0x7004, 0x1ff8,0x6006, 0x3ff8,0x0000, 0x0ec0,0x0ec0, 0x3866,0x3866, 0x603c,0x603c, 0x3818,0x3818, 0x0000,0x0000, 0x0000,0x0000, 0x0000,0x0000 }; /* Up and down walking hulks */ UWORD hu1[] = { 0x0000,0x0000, 0x0000,0x07c0, 0x0100,0x0100, 0x0100,0x0100, 0x1ff0,0xe00e, 0x1ff0,0xc006, 0x1ff0,0xc006, 0x1ff0,0xc006, 0x1ff0,0xc006, 0x1ff0,0xe00e, 0x1ff0,0xa00a, 0x06c0,0xa6ca, 0x06c0,0x06c0, 0x06c0,0x06c0, 0x1ef0,0x1ef0, 0x0000,0x0000, 0x0000,0x0000, 0x0000,0x0000 }; UWORD hu2[] = { 0x0000,0x0000, 0x07c0,0x0000, 0x0100,0x0100, 0x0100,0x0100, 0x1ff0,0xe00e, 0x1ff0,0xc006, 0x1ff0,0xc006, 0x1ff0,0xc006, 0x1ff0,0xc006, 0x1ff0,0xe00e, 0x1ff0,0xa00a, 0x06c0,0xa6ca, 0x1ec0,0x1ec0, 0x00c0,0x00c0, 0x00c0,0x00c0, 0x00c0,0x00c0, 0x00f0,0x00f0, 0x0000,0x0000 }; UWORD hu3[] = { 0x0000,0x0000, 0x07c0,0x07c0, 0x0100,0x0100, 0x0100,0x0100, 0x1ff0,0xe00e, 0x1ff0,0xc006, 0x1ff0,0xc006, 0x1ff0,0xc006, 0x1ff0,0xc006, 0x1ff0,0xe00e, 0x1ff0,0xa00a, 0x06c0,0xa6ca, 0x06f0,0x06f0, 0x0600,0x0600, 0x0600,0x0600, 0x0600,0x0600, 0x1e00,0x1e00, 0x0000,0x0000 }; /* Grunt sprites (13) */ USHORT gruntcolor[] = { 0x0000, 0x0fff, 0x0ff0, 0x0f00 }; UWORD gr1[] = { 0x0000,0x0000, 0x0780,0x0780, 0x0000,0x0fc0, 0x0fc0,0x0000, 0x0780,0x0780, 0x7ff8,0x6798, 0x3ff0,0x7878, 0x1fe0,0x5ce8, 0x0fc0,0x4fc8, 0x0fc0,0x0fc0, 0x1ce0,0x1ce0, 0x1ce0,0x1ce0, 0x0000,0x3cf0, 0x0000,0x0000, 0x0000,0x0000, }; UWORD gr2[] = { 0x0000,0x0000, 0x0780,0x0780, 0x0000,0x0fc0, 0x0000,0x0fc0, 0x0780,0x0780, 0x7ff8,0x6798, 0x3ff0,0x7878, 0x1fe0,0x5ce8, 0x0fc0,0x4fc8, 0x1fc0,0x1fc0, 0x1ce0,0x1ce0, 0x00e0,0x3ce0, 0x00e0,0x00e0, 0x0000,0x00f0, 0x0000,0x0000 }; UWORD gr3[] = { 0x0000,0x0000, 0x0780,0x0780, 0x0000,0x0fc0, 0x0fc0,0x0fc0, 0x0780,0x0780, 0x7ff8,0x6798, 0x3ff0,0x7878, 0x1fe0,0x5ce8, 0x0fc0,0x4fc8, 0x0fe0,0x0fe0, 0x1ce0,0x1ce0, 0x1c00,0x1cf0, 0x1c00,0x1c00, 0x0000,0x3c00, 0x0000,0x0000 }; /* Enforcer sprite (13) */ USHORT nforcecolor[] = { 0x0000, 0x0fff, 0x0a0f, 0x033f }; UWORD nforce[] = { 0x0000,0x0000, 0x0000,0x0100, 0x0000,0x0380, 0x0000,0x07c0, 0x0000,0x0fe0, 0x07c0,0x1ff0, 0x0fe0,0x3018, 0x0000,0x07c0, 0x610c,0x0fe0, 0x1ff0,0x0380, 0x6fec,0x0fe0, 0x0100,0x0000, 0x1ff0,0x0000, 0x3ff8,0x0000, 0x0000,0x0000 }; SHAR_EOF fi if test -f 'rnd.asm' then echo shar: "will not over-write existing file 'rnd.asm'" else cat << \SHAR_EOF > 'rnd.asm' *\ * :ts=8 * Yet Another random number generator. By Leo Schwab. * Based on an idea posted on the USENET (Thanks, Sam Dicker!) * For the Manx assembler. * * Calling convention: * short rnd (range); * short range; * * 8606.30 */ public _rnd _rnd lea rndseed,a0 ; Get address of seed move.w 4(sp),d1 ; Get range argument tst.w d1 ble.s setseed ; Go reset seed move.l (a0),d0 ; Get seed ADD.L D0,D0 BHI.S over EORI.L #$1D872B41,D0 over move.l d0,(a0) ; Save new seed andi.l #$ffff,d0 ; Coerce into word divu d1,d0 ; Divide by range swap d0 ; and get remainder (modulus) rts setseed neg.w d1 ; Probably don't need this move.l d1,(a0) rts dseg rndseed dc.l 0 cseg SHAR_EOF fi exit 0 # End of shell archive