2 Xroach - A game of skill. Try to find the roaches under your windows.
3 Ported to Nano-X by Greg Haerr
5 Copyright 1991 by J.T. Anderson
8 This program may be freely distributed provided that all
9 copyright notices are retained.
11 Dedicated to Greg McFarlane. (gregm@otc.otca.oz.au)
13 char Copyright[] = "nxroach\nCopyright 1991 J.T. Anderson";
20 #define MWINCLUDECOLORS
24 #define Pixmap GR_WINDOW_ID
27 #define SCAMPER_EVENT 99
29 typedef struct Roach {
41 GR_COORD display_width, display_height;
43 GR_COLOR roachColor = BLACK;
44 GR_REGION_ID rootVisible = 0;
45 GR_BOOL done = GR_FALSE;
46 GR_BOOL eventBlock = GR_FALSE;
51 float roachSpeed = 20.0;
54 void SigHandler(int sig);
56 void MoveRoach(int Rx);
57 void DrawRoaches(void);
59 int CalcRootVisible(void);
60 int MarkHiddenRoaches(void);
63 main(int ac, char **av)
76 Process command line options.
78 for (ax=1; ax<ac; ax++) {
80 if (strcmp(arg, "-rc") == 0) {
81 roachColor = atoi(av[++ax]);
83 else if (strcmp(arg, "-speed") == 0) {
84 roachSpeed = atof(av[++ax]);
86 else if (strcmp(arg, "-roaches") == 0) {
87 maxRoaches = strtol(av[++ax], (char **)NULL, 0);
94 srand((int)time((long *)NULL));
97 Catch some signals so we can erase any visible roaches.
99 signal(SIGKILL, SigHandler);
100 signal(SIGINT, SigHandler);
101 signal(SIGTERM, SigHandler);
102 signal(SIGHUP, SigHandler);
105 fprintf(stderr, "can't open graphics\n");
109 GrGetScreenInfo(&sinfo);
110 display_width = sinfo.cols;
111 display_height = sinfo.rows;
114 Create roach pixmaps at several orientations.
116 for (ax=0; ax<360; ax+=ROACH_ANGLE) {
117 rx = ax / ROACH_ANGLE;
118 angle = rx * 0.261799387799;
120 rp->pixmap = GrNewPixmapFromData(rp->width, rp->height, WHITE, BLACK,
121 rp->roachBits, GR_BMDATA_BYTEREVERSE|GR_BMDATA_BYTESWAP);
122 rp->sine = sin(angle);
123 rp->cosine = cos(angle);
126 roaches = (Roach *)malloc(sizeof(Roach) * maxRoaches);
130 while (curRoaches < maxRoaches)
133 GrSelectEvents(GR_ROOT_WINDOW_ID, GR_EVENT_MASK_EXPOSURE | GR_EVENT_MASK_CHLD_UPDATE);
137 if (GrPeekEvent(&ev))
141 needCalc = CalcRootVisible();
143 nVis = MarkHiddenRoaches();
145 ev.type = SCAMPER_EVENT;
149 eventBlock = GR_TRUE;
151 eventBlock = GR_FALSE;
157 for (rx=0; rx<curRoaches; rx++) {
158 if (!roaches[rx].hidden)
165 case GR_EVENT_TYPE_EXPOSURE:
166 case GR_EVENT_TYPE_CHLD_UPDATE:
181 fprintf(stderr, "Usage: nxroach [options]\n\n");
182 fprintf(stderr, "Options:\n");
183 fprintf(stderr, " -rc roachcolor\n");
184 fprintf(stderr, " -roaches numroaches\n");
185 fprintf(stderr, " -speed roachspeed\n");
194 If we are blocked, no roaches are visible and we can just bail
195 out. If we are not blocked, then let the main procedure clean
208 Generate random integer between 0 and maxVal-1.
213 return rand() % maxVal;
217 Check for roach completely in specified rectangle.
220 RoachInRect(Roach *roach, int rx, int ry, int x, int y,
221 unsigned int width, unsigned int height)
223 if (rx < x) return 0;
224 if ((rx + roach->rp->width) > (x + width)) return 0;
225 if (ry < y) return 0;
226 if ((ry + roach->rp->height) > (y + height)) return 0;
232 Check for roach overlapping specified rectangle.
235 RoachOverRect(Roach *roach, int rx, int ry, int x, int y,
236 unsigned int width, unsigned int height)
238 if (rx >= (x + width)) return 0;
239 if ((rx + roach->rp->width) <= x) return 0;
240 if (ry >= (y + height)) return 0;
241 if ((ry + roach->rp->height) <= y) return 0;
247 Give birth to a roach.
254 if (curRoaches < maxRoaches) {
255 r = &roaches[curRoaches++];
256 r->index = RandInt(ROACH_HEADINGS);
257 r->rp = &roachPix[r->index];
258 r->x = RandInt(display_width - r->rp->width);
259 r->y = RandInt(display_height - r->rp->height);
263 r->steps = RandInt(200);
264 r->turnLeft = RandInt(100) >= 50;
272 TurnRoach(Roach *roach)
274 if (roach->index != (roach->rp - roachPix)) return;
276 if (roach->turnLeft) {
277 roach->index += (RandInt(30) / 10) + 1;
278 if (roach->index >= ROACH_HEADINGS)
279 roach->index -= ROACH_HEADINGS;
282 roach->index -= (RandInt(30) / 10) + 1;
283 if (roach->index < 0)
284 roach->index += ROACH_HEADINGS;
300 roach = &roaches[rx];
301 newX = roach->x + (roachSpeed * roach->rp->cosine);
302 newY = roach->y - (roachSpeed * roach->rp->sine);
304 if (RoachInRect(roach, (int)newX, (int)newY,
305 0, 0, display_width, display_height)) {
310 if (roach->steps-- <= 0) {
312 roach->steps = RandInt(200);
315 for (ii=rx+1; ii<curRoaches; ii++) {
317 if (RoachOverRect(roach, (int)newX, (int)newY,
318 r2->intX, r2->intY, r2->rp->width, r2->rp->height)) {
338 for (rx=0; rx<curRoaches; rx++) {
339 roach = &roaches[rx];
341 if (roach->intX >= 0) {
342 GrClearArea(GR_ROOT_WINDOW_ID, roach->intX, roach->intY,
343 roach->rp->width, roach->rp->height, GR_FALSE);
347 for (rx=0; rx<curRoaches; rx++) {
348 roach = &roaches[rx];
350 if (!roach->hidden) {
351 int size = roach->rp->width * roach->rp->height;
352 GR_PIXELVAL roachbuf[size];
353 GR_PIXELVAL screenbuf[size];
356 roach->intX = roach->x;
357 roach->intY = roach->y;
358 roach->rp = &roachPix[roach->index];
361 //XSetForeground(display, gc, AllocNamedColor(roachColor, black));
362 //XSetFillStyle(display, gc, FillStippled);
363 //XSetStipple(display, gc, roach->rp->pixmap);
364 //XSetTSOrigin(display, gc, roach->intX, roach->intY);
365 //XFillRectangle(display, rootWin, gc,
366 //roach->intX, roach->intY, roach->rp->width, roach->rp->height);
369 /* read roach bitmap*/
370 GrReadArea(roach->rp->pixmap, 0, 0,
371 roach->rp->width, roach->rp->height, roachbuf);
373 /* read root window*/
374 GrReadArea(GR_ROOT_WINDOW_ID, roach->intX, roach->intY,
375 roach->rp->width, roach->rp->height, screenbuf);
377 /* convert fg roach bitmap bits to roach color on root window bits*/
378 for (i=0; i<size; ++i)
379 if (roachbuf[i] != BLACK)
380 screenbuf[i] = roachColor;
382 /* write root window*/
383 GrArea(GR_ROOT_WINDOW_ID, gc, roach->intX, roach->intY,
384 roach->rp->width, roach->rp->height, screenbuf, MWPF_PIXELVAL);
394 Cover root window to erase roaches.
399 GR_WINDOW_ID roachWin;
401 roachWin = GrNewWindow(GR_ROOT_WINDOW_ID, 0, 0, display_width, display_height,
403 GrLowerWindow(roachWin);
404 GrMapWindow(roachWin);
409 Calculate Visible region of root window.
412 CalcRootVisible(void)
414 GR_REGION_ID covered;
415 GR_REGION_ID visible;
417 GR_WINDOW_ID *children;
424 Get children of root.
426 GrQueryTree(GR_ROOT_WINDOW_ID, &parent, &children, &nChildren);
429 For each mapped child, add the window rectangle to the covered
432 covered = GrNewRegion();
433 for (wx=0; wx<nChildren; wx++) {
434 GrGetWindowInfo(children[wx], &info);
435 if (info.unmapcount == 0) {
438 rect.width = info.width;
439 rect.height = info.height;
440 GrUnionRectWithRegion(covered, &rect);
446 Subtract the covered region from the root window region.
448 visible = GrNewRegion();
451 rect.width = display_width;
452 rect.height = display_height;
453 GrUnionRectWithRegion(visible, &rect);
454 GrSubtractRegion(visible, visible, covered);
455 GrDestroyRegion(covered);
458 Save visible region globally.
461 GrDestroyRegion(rootVisible);
462 rootVisible = visible;
465 Mark all roaches visible.
467 for (wx=0; wx<curRoaches; wx++)
468 roaches[wx].hidden = 0;
477 MarkHiddenRoaches(void)
484 for (rx=0; rx<curRoaches; rx++) {
488 if (r->intX > 0 && GrRectInRegion(rootVisible, r->intX, r->intY,
489 r->rp->width, r->rp->height) == MWRECT_OUT) {