/* :ts=8 bk=0 * * functions.c: Functions to do obscene things to mouse pointer. * * Leo L. Schwab 8703.18 (415)-456-6565 */ #include #include #include #include #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 ? xendx; 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 ? yendy; 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."); }