1 /* -*- Mode: C; tab-width: 4 -*- */
2 /* wator --- Dewdney's Wa-Tor, water torus simulation */
3
4 #if 0
5 static const char sccsid[] = "@(#)wator.c 5.24 2007/01/18 xlockmore";
6
7 #endif
8
9 /*-
10 * Copyright (c) 1994 by David Bagley.
11 *
12 * Permission to use, copy, modify, and distribute this software and its
13 * documentation for any purpose and without fee is hereby granted,
14 * provided that the above copyright notice appear in all copies and that
15 * both that copyright notice and this permission notice appear in
16 * supporting documentation.
17 *
18 * This file is provided AS IS with no warranties of any kind. The author
19 * shall have no liability with respect to the infringement of copyrights,
20 * trade secrets or any patents by this file or any part thereof. In no
21 * event will the author be liable for any lost revenue or profits or
22 * other special, indirect and consequential damages.
23 *
24 * Revision History:
25 * 18-Jan-2007: Added vertical option.
26 * 01-Nov-2000: Allocation checks
27 * 10-May-1997: Compatible with xscreensaver
28 * 29-Aug-1995: Efficiency improvements.
29 * 12-Dec-1994: Coded from A.K. Dewdney's "The Armchair Universe, Computer
30 * Recreations from the Pages of Scientific American Magazine"
31 * W.H. Freedman and Company, New York, 1988 (Dec 1984 and
32 * June 1985) also used life.c as a guide.
33 */
34
35 #ifdef STANDALONE
36 #define MODE_wator
37 #define DEFAULTS "*delay: 750000 \n" \
38 "*cycles: 32767 \n" \
39 "*size: 0 \n" \
40 "*ncolors: 200 \n" \
41
42 # define free_wator 0
43 # define reshape_wator 0
44 # define wator_handle_event 0
45 #include "xlockmore.h" /* in xscreensaver distribution */
46 #else /* STANDALONE */
47 #include "xlock.h" /* in xlockmore distribution */
48 #endif /* STANDALONE */
49 #include "automata.h"
50
51 #ifdef MODE_wator
52
53 /*-
54 * neighbors of 0 randomizes it between 3, 4, 6, 8, 9, and 12.
55 */
56 #define DEF_NEIGHBORS "0" /* choose random value */
57 #define DEF_VERTICAL "False"
58
59 static int neighbors;
60 static Bool vertical;
61
62 static XrmOptionDescRec opts[] =
63 {
64 {(char *) "-neighbors", (char *) ".wator.neighbors", XrmoptionSepArg, (caddr_t) NULL},
65 {(char *) "-vertical", (char *) ".wator.vertical", XrmoptionNoArg, (caddr_t) "on"},
66 {(char *) "+vertical", (char *) ".wator.vertical", XrmoptionNoArg, (caddr_t) "off"}
67 };
68
69 static argtype vars[] =
70 {
71 {(void *) & neighbors, (char *) "neighbors", (char *) "Neighbors", (char *) DEF_NEIGHBORS, t_Int},
72 {(void *) & vertical, (char *) "vertical", (char *) "Vertical", (char *) DEF_VERTICAL, t_Bool}
73 };
74
75 static OptionStruct desc[] =
76 {
77 {(char *) "-neighbors num", (char *) "squares 4 or 8, hexagons 6, triangles 3, 9 or 12"},
78 {(char *) "-/+vertical", (char *) "change orientation for hexagons and triangles"}
79 };
80
81 ENTRYPOINT ModeSpecOpt wator_opts =
82 {sizeof opts / sizeof opts[0], opts, sizeof vars / sizeof vars[0], vars, desc};
83
84 #ifdef USE_MODULES
85 ModStruct wator_description =
86 {"wator", "init_wator", "draw_wator", "release_wator",
87 "refresh_wator", "init_wator", (char *) NULL, &wator_opts,
88 750000, 1, 32767, 0, 64, 1.0, "",
89 "Shows Dewdney's Water-Torus planet of fish and sharks", 0, NULL};
90
91 #endif
92
93 #include "bitmaps/fish-0.xbm"
94 #include "bitmaps/fish-1.xbm"
95 #include "bitmaps/fish-2.xbm"
96 #include "bitmaps/fish-3.xbm"
97 #include "bitmaps/fish-4.xbm"
98 #include "bitmaps/fish-5.xbm"
99 #include "bitmaps/fish-6.xbm"
100 #include "bitmaps/fish-7.xbm"
101 #include "bitmaps/shark-0.xbm"
102 #include "bitmaps/shark-1.xbm"
103 #include "bitmaps/shark-2.xbm"
104 #include "bitmaps/shark-3.xbm"
105 #include "bitmaps/shark-4.xbm"
106 #include "bitmaps/shark-5.xbm"
107 #include "bitmaps/shark-6.xbm"
108 #include "bitmaps/shark-7.xbm"
109
110 #define FISH 0
111 #define SHARK 1
112 #define KINDS 2
113 #define ORIENTS 4
114 #define REFLECTS 2
115 #define BITMAPS (ORIENTS*REFLECTS*KINDS)
116 #define KINDBITMAPS (ORIENTS*REFLECTS)
117 #define MINGRIDSIZE 10 /* It is possible for the fish to take over with 3 */
118 #define MINSIZE 4
119 #define NEIGHBORKINDS 6
120
121 static XImage logo[BITMAPS] =
122 {
123 {0, 0, 0, XYBitmap, (char *) fish0_bits, LSBFirst, 8, LSBFirst, 8, 1},
124 {0, 0, 0, XYBitmap, (char *) fish1_bits, LSBFirst, 8, LSBFirst, 8, 1},
125 {0, 0, 0, XYBitmap, (char *) fish2_bits, LSBFirst, 8, LSBFirst, 8, 1},
126 {0, 0, 0, XYBitmap, (char *) fish3_bits, LSBFirst, 8, LSBFirst, 8, 1},
127 {0, 0, 0, XYBitmap, (char *) fish4_bits, LSBFirst, 8, LSBFirst, 8, 1},
128 {0, 0, 0, XYBitmap, (char *) fish5_bits, LSBFirst, 8, LSBFirst, 8, 1},
129 {0, 0, 0, XYBitmap, (char *) fish6_bits, LSBFirst, 8, LSBFirst, 8, 1},
130 {0, 0, 0, XYBitmap, (char *) fish7_bits, LSBFirst, 8, LSBFirst, 8, 1},
131 {0, 0, 0, XYBitmap, (char *) shark0_bits, LSBFirst, 8, LSBFirst, 8, 1},
132 {0, 0, 0, XYBitmap, (char *) shark1_bits, LSBFirst, 8, LSBFirst, 8, 1},
133 {0, 0, 0, XYBitmap, (char *) shark2_bits, LSBFirst, 8, LSBFirst, 8, 1},
134 {0, 0, 0, XYBitmap, (char *) shark3_bits, LSBFirst, 8, LSBFirst, 8, 1},
135 {0, 0, 0, XYBitmap, (char *) shark4_bits, LSBFirst, 8, LSBFirst, 8, 1},
136 {0, 0, 0, XYBitmap, (char *) shark5_bits, LSBFirst, 8, LSBFirst, 8, 1},
137 {0, 0, 0, XYBitmap, (char *) shark6_bits, LSBFirst, 8, LSBFirst, 8, 1},
138 {0, 0, 0, XYBitmap, (char *) shark7_bits, LSBFirst, 8, LSBFirst, 8, 1},
139 };
140
141 /* Fish and shark data */
142 typedef struct {
143 char kind, age, food, direction;
144 unsigned long color;
145 int col, row;
146 } cellstruct;
147
148 /* Doubly linked list */
149 typedef struct _CellList {
150 cellstruct info;
151 struct _CellList *previous, *next;
152 } CellList;
153
154 typedef struct {
155 Bool painted, vertical;
156 int nkind[KINDS]; /* Number of fish and sharks */
157 int breed[KINDS]; /* Breeding time of fish and sharks */
158 int sstarve; /* Time the sharks starve if they don't find a fish */
159 int kind; /* Currently working on fish or sharks? */
160 int xs, ys; /* Size of fish and sharks */
161 int xb, yb; /* Bitmap offset for fish and sharks */
162 int pixelmode;
163 int generation;
164 int ncols, nrows, positions;
165 int width, height;
166 CellList *currkind, *babykind, *lastkind[KINDS + 1], *firstkind[KINDS + 1];
167 CellList **arr; /* 0=empty or pts to a fish or shark */
168 int neighbors, polygon;
169 union {
170 XPoint hexagon[6];
171 XPoint triangle[2][3];
172 } shape;
173 } watorstruct;
174
175 static char plots[NEIGHBORKINDS] =
176 {
177 3, 4, 6, 8, 9, 12 /* Neighborhoods */
178 };
179
180 static watorstruct *wators = (watorstruct *) NULL;
181 static int icon_width, icon_height;
182
183 #if 0
184 /*-
185 * shape either a bitmap or 0 for circle and 1 for polygon
186 * (if triangle shape: -1, 0, 2 or 3 to differentiate left and right)
187 */
188 drawshape(ModeInfo * mi, int x, int y, int sizex, int sizey,
189 int sides, int shape)
190 {
191 Display *display = MI_DISPLAY(mi);
192 Window window = MI_WINDOW(mi);
193 GC gc = MI_GC(mi);
194
195 if (sides == 4 && sizex == 0 && sizey == 0) {
196 (void) XPutImage(display, window, gc, &logo[shape], 0, 0,
197 x - icon_width, y - icon_height / 2, icon_width, icon_height);
198 } else if (sizex < 3 || sizey < 3 || (sides == 4 && shape == 1)) {
199 XFillRectangle(display, window, gc,
200 x - sizex / 2, y - sizey / 2,
201 sizex - (sizey > 3), sizey - (sizey > 3));
202 } else if (sides == 4 && shape == 0) {
203 } else if (sides == 6 && shape == 1) {
204 } else if (sides == 6 && shape == 0) {
205 } else if (sides == 3 && shape == 1) {
206 } else if (sides == 3 && shape == 2) {
207 } else if (sides == 3 && shape == -1) {
208 } else if (sides == 3 && shape == 0) {
209 }
210 }
211 #endif
212
213 static void
drawcell(ModeInfo * mi,int col,int row,unsigned long color,int bitmap,Bool alive)214 drawcell(ModeInfo * mi, int col, int row, unsigned long color, int bitmap,
215 Bool alive)
216 {
217 Display *display = MI_DISPLAY(mi);
218 Window window = MI_WINDOW(mi);
219 GC gc = MI_GC(mi);
220 watorstruct *wp = &wators[MI_SCREEN(mi)];
221 unsigned long colour;
222
223 if (!alive)
224 colour = MI_BLACK_PIXEL(mi);
225 else if (MI_NPIXELS(mi) > 2)
226 colour = MI_PIXEL(mi, color);
227 else
228 colour = MI_WHITE_PIXEL(mi);
229 XSetForeground(display, gc, colour);
230 if (wp->neighbors == 6) {
231 int ccol = 2 * col + !(row & 1), crow = 2 * row;
232
233 if (wp->vertical) {
234 wp->shape.hexagon[0].x = wp->xb + ccol * wp->xs;
235 wp->shape.hexagon[0].y = wp->yb + crow * wp->ys;
236 } else {
237 wp->shape.hexagon[0].y = wp->xb + ccol * wp->xs;
238 wp->shape.hexagon[0].x = wp->yb + crow * wp->ys;
239 }
240 if (wp->xs == 1 && wp->ys == 1)
241 XDrawPoint(display, window, gc,
242 wp->shape.hexagon[0].x,
243 wp->shape.hexagon[0].y);
244 else if (bitmap >= KINDBITMAPS || !alive)
245 XFillPolygon(display, window, gc,
246 wp->shape.hexagon, 6,
247 Convex, CoordModePrevious);
248 else {
249 int ix = 0, iy = 0, sx, sy;
250
251 XSetForeground(display, gc, MI_BLACK_PIXEL(mi));
252 XFillPolygon(display, window, gc,
253 wp->shape.hexagon, 6,
254 Convex, CoordModePrevious);
255 XSetForeground(display, gc, colour);
256 if (wp->vertical) {
257 wp->shape.hexagon[0].x -= wp->xs;
258 wp->shape.hexagon[0].y += wp->ys / 4;
259 sx = 2 * wp->xs - 6;
260 sy = 2 * wp->ys - 2;
261 if (wp->xs <= 6 || wp->ys <= 2) {
262 ix = 3;
263 iy = 1;
264 } else
265 ix = 5;
266 } else {
267 wp->shape.hexagon[0].y -= wp->xs;
268 wp->shape.hexagon[0].x += wp->ys / 4;
269 sy = 2 * wp->xs - 6;
270 sx = 2 * wp->ys - 2;
271 if (wp->xs <= 6 || wp->ys <= 2) {
272 iy = 3;
273 ix = 1;
274 } else
275 iy = 5;
276 }
277 if (wp->xs <= 6 || wp->ys <= 2)
278 XFillRectangle(display, window, gc,
279 wp->shape.hexagon[0].x + ix,
280 wp->shape.hexagon[0].y + iy,
281 wp->xs, wp->ys);
282 else
283 XFillArc(display, window, gc,
284 wp->shape.hexagon[0].x + ix,
285 wp->shape.hexagon[0].y + iy,
286 sx, sy,
287 0, 23040);
288 }
289 } else if (wp->neighbors == 4 || wp->neighbors == 8) {
290 if (wp->pixelmode) {
291 if (bitmap >= KINDBITMAPS || (wp->xs <= 2 || wp->ys <= 2) || !alive)
292 XFillRectangle(display, window, gc,
293 wp->xb + wp->xs * col,
294 wp->yb + wp->ys * row,
295 wp->xs - (wp->xs > 3),
296 wp->ys - (wp->ys > 3));
297 else {
298 XSetForeground(display, gc, MI_BLACK_PIXEL(mi));
299 XFillRectangle(display, window, gc,
300 wp->xb + wp->xs * col,
301 wp->yb + wp->ys * row,
302 wp->xs, wp->ys);
303 XSetForeground(display, gc, colour);
304 XFillArc(display, window, gc,
305 wp->xb + wp->xs * col,
306 wp->yb + wp->ys * row,
307 wp->xs - 1, wp->ys - 1,
308 0, 23040);
309 }
310 } else
311 (void) XPutImage(display, window, gc,
312 &logo[bitmap], 0, 0,
313 wp->xb + wp->xs * col, wp->yb + wp->ys * row,
314 icon_width, icon_height);
315 } else { /* TRI */
316 int orient = (col + row) % 2; /* O left 1 right */
317 Bool small = (wp->xs <= 3 || wp->ys <= 3);
318 int ix = 0, iy = 0;
319
320 if (wp->vertical) {
321 wp->shape.triangle[orient][0].x = wp->xb + col * wp->xs;
322 wp->shape.triangle[orient][0].y = wp->yb + row * wp->ys;
323 if (small)
324 wp->shape.triangle[orient][0].x +=
325 ((orient) ? -1 : 1);
326 else
327 wp->shape.triangle[orient][0].x +=
328 (wp->xs / 2 - 1) * ((orient) ? 1 : -1);
329 } else {
330 wp->shape.triangle[orient][0].y = wp->xb + col * wp->xs;
331 wp->shape.triangle[orient][0].x = wp->yb + row * wp->ys;
332 if (small)
333 wp->shape.triangle[orient][0].y +=
334 ((orient) ? -1 : 1);
335 else
336 wp->shape.triangle[orient][0].y +=
337 (wp->xs / 2 - 1) * ((orient) ? 1 : -1);
338 }
339 if (small)
340 XDrawPoint(display, window, gc,
341 wp->shape.triangle[orient][0].x,
342 wp->shape.triangle[orient][0].y);
343 else {
344 if (bitmap >= KINDBITMAPS || !alive)
345 XFillPolygon(display, window, gc,
346 wp->shape.triangle[orient], 3,
347 Convex, CoordModePrevious);
348 else {
349 XSetForeground(display, gc, MI_BLACK_PIXEL(mi));
350 XFillPolygon(display, window, gc,
351 wp->shape.triangle[orient], 3,
352 Convex, CoordModePrevious);
353 XSetForeground(display, gc, colour);
354 if (wp->vertical) {
355 wp->shape.triangle[orient][0].x += -4 * wp->xs / 5 +
356 ((orient) ? wp->xs / 3 : 3 * wp->xs / 5);
357 wp->shape.triangle[orient][0].y += -wp->ys / 2 + 1;
358 ix = ((orient) ? -wp->xs / 2 : wp->xs / 2);
359 } else {
360 wp->shape.triangle[orient][0].y += -4 * wp->xs / 5 +
361 ((orient) ? wp->xs / 3 : 3 * wp->xs / 5);
362 wp->shape.triangle[orient][0].x += -wp->ys / 2 + 1;
363 iy = ((orient) ? -wp->xs / 2 : wp->xs / 2);
364 }
365 XFillArc(display, window, gc,
366 wp->shape.triangle[orient][0].x + ix,
367 wp->shape.triangle[orient][0].y + iy,
368 wp->ys - 3, wp->ys - 3,
369 0, 23040);
370 }
371 }
372 }
373 }
374
375 static Bool
init_kindlist(watorstruct * wp,int kind)376 init_kindlist(watorstruct * wp, int kind)
377 {
378 /* Waste some space at the beginning and end of list
379 so we do not have to complicated checks against falling off the ends. */
380 if (((wp->lastkind[kind] = (CellList *) malloc(sizeof (CellList))) ==
381 NULL) ||
382 ((wp->firstkind[kind] = (CellList *) malloc(sizeof (CellList))) ==
383 NULL)) {
384 return False;
385 }
386 wp->firstkind[kind]->previous = wp->lastkind[kind]->next =
387 (struct _CellList *) NULL;
388 wp->firstkind[kind]->next = wp->lastkind[kind]->previous =
389 (struct _CellList *) NULL;
390 wp->firstkind[kind]->next = wp->lastkind[kind];
391 wp->lastkind[kind]->previous = wp->firstkind[kind];
392 return True;
393 }
394
395 static Bool
addto_kindlist(watorstruct * wp,int kind,cellstruct info)396 addto_kindlist(watorstruct * wp, int kind, cellstruct info)
397 {
398 if ((wp->currkind = (CellList *) malloc(sizeof (CellList))) == NULL) {
399 return False;
400 }
401 wp->lastkind[kind]->previous->next = wp->currkind;
402 wp->currkind->previous = wp->lastkind[kind]->previous;
403 wp->currkind->next = wp->lastkind[kind];
404 wp->lastkind[kind]->previous = wp->currkind;
405 wp->currkind->info = info;
406 return True;
407 }
408
409 static void
removefrom_kindlist(watorstruct * wp,CellList * ptr)410 removefrom_kindlist(watorstruct * wp, CellList * ptr)
411 {
412 ptr->previous->next = ptr->next;
413 ptr->next->previous = ptr->previous;
414 wp->arr[ptr->info.col + ptr->info.row * wp->ncols] = 0;
415 free(ptr);
416 }
417
418 static Bool
dupin_kindlist(watorstruct * wp)419 dupin_kindlist(watorstruct * wp)
420 {
421 CellList *temp;
422
423 if ((temp = (CellList *) malloc(sizeof (CellList))) == NULL) {
424 return False;
425 }
426 temp->previous = wp->babykind;
427 temp->next = wp->babykind->next;
428 wp->babykind->next = temp;
429 temp->next->previous = temp;
430 temp->info = wp->babykind->info;
431 wp->babykind = temp;
432 return True;
433 }
434
435 /*-
436 * new fish at end of list, this rotates who goes first, young fish go last
437 * this most likely will not change the feel to any real degree
438 */
439 static void
cutfrom_kindlist(watorstruct * wp)440 cutfrom_kindlist(watorstruct * wp)
441 {
442 wp->babykind = wp->currkind;
443 wp->currkind = wp->currkind->previous;
444 wp->currkind->next = wp->babykind->next;
445 wp->babykind->next->previous = wp->currkind;
446 wp->babykind->next = wp->lastkind[KINDS];
447 wp->babykind->previous = wp->lastkind[KINDS]->previous;
448 wp->babykind->previous->next = wp->babykind;
449 wp->babykind->next->previous = wp->babykind;
450 }
451
452 static void
reattach_kindlist(watorstruct * wp,int kind)453 reattach_kindlist(watorstruct * wp, int kind)
454 {
455 wp->currkind = wp->lastkind[kind]->previous;
456 wp->currkind->next = wp->firstkind[KINDS]->next;
457 wp->currkind->next->previous = wp->currkind;
458 wp->lastkind[kind]->previous = wp->lastkind[KINDS]->previous;
459 wp->lastkind[KINDS]->previous->next = wp->lastkind[kind];
460 wp->lastkind[KINDS]->previous = wp->firstkind[KINDS];
461 wp->firstkind[KINDS]->next = wp->lastkind[KINDS];
462 }
463
464 static void
flush_kindlist(watorstruct * wp,int kind)465 flush_kindlist(watorstruct * wp, int kind)
466 {
467 while (wp->lastkind[kind]->previous != wp->firstkind[kind]) {
468 wp->currkind = wp->lastkind[kind]->previous;
469 wp->currkind->previous->next = wp->lastkind[kind];
470 wp->lastkind[kind]->previous = wp->currkind->previous;
471 /* wp->arr[wp->currkind->info.col + wp->currkind->info.row * wp->ncols] = 0; */
472 free(wp->currkind);
473 }
474 }
475
476 static int
positionOfNeighbor(watorstruct * wp,int n,int col,int row)477 positionOfNeighbor(watorstruct * wp, int n, int col, int row)
478 {
479 int dir = n * (360 / wp->neighbors);
480
481 if (wp->polygon == 4 || wp->polygon == 6) {
482 switch (dir) {
483 case 0:
484 col = (col + 1 == wp->ncols) ? 0 : col + 1;
485 break;
486 case 45:
487 col = (col + 1 == wp->ncols) ? 0 : col + 1;
488 row = (!row) ? wp->nrows - 1 : row - 1;
489 break;
490 case 60:
491 if (!(row & 1))
492 col = (col + 1 == wp->ncols) ? 0 : col + 1;
493 row = (!row) ? wp->nrows - 1 : row - 1;
494 break;
495 case 90:
496 row = (!row) ? wp->nrows - 1 : row - 1;
497 break;
498 case 120:
499 if (row & 1)
500 col = (!col) ? wp->ncols - 1 : col - 1;
501 row = (!row) ? wp->nrows - 1 : row - 1;
502 break;
503 case 135:
504 col = (!col) ? wp->ncols - 1 : col - 1;
505 row = (!row) ? wp->nrows - 1 : row - 1;
506 break;
507 case 180:
508 col = (!col) ? wp->ncols - 1 : col - 1;
509 break;
510 case 225:
511 col = (!col) ? wp->ncols - 1 : col - 1;
512 row = (row + 1 == wp->nrows) ? 0 : row + 1;
513 break;
514 case 240:
515 if (row & 1)
516 col = (!col) ? wp->ncols - 1 : col - 1;
517 row = (row + 1 == wp->nrows) ? 0 : row + 1;
518 break;
519 case 270:
520 row = (row + 1 == wp->nrows) ? 0 : row + 1;
521 break;
522 case 300:
523 if (!(row & 1))
524 col = (col + 1 == wp->ncols) ? 0 : col + 1;
525 row = (row + 1 == wp->nrows) ? 0 : row + 1;
526 break;
527 case 315:
528 col = (col + 1 == wp->ncols) ? 0 : col + 1;
529 row = (row + 1 == wp->nrows) ? 0 : row + 1;
530 break;
531 default:
532 (void) fprintf(stderr, "wrong direction %d\n", dir);
533 }
534 } else if (wp->polygon == 3) {
535 if ((col + row) & 1) { /* right */
536 switch (dir) {
537 case 0:
538 col = (!col) ? wp->ncols - 1 : col - 1;
539 break;
540 case 30:
541 case 40:
542 col = (!col) ? wp->ncols - 1 : col - 1;
543 row = (row + 1 == wp->nrows) ? 0 : row + 1;
544 break;
545 case 60:
546 col = (!col) ? wp->ncols - 1 : col - 1;
547 if (row + 1 == wp->nrows)
548 row = 1;
549 else if (row + 2 == wp->nrows)
550 row = 0;
551 else
552 row = row + 2;
553 break;
554 case 80:
555 case 90:
556 if (row + 1 == wp->nrows)
557 row = 1;
558 else if (row + 2 == wp->nrows)
559 row = 0;
560 else
561 row = row + 2;
562 break;
563 case 120:
564 row = (row + 1 == wp->nrows) ? 0 : row + 1;
565 break;
566 case 150:
567 case 160:
568 col = (col + 1 == wp->ncols) ? 0 : col + 1;
569 row = (row + 1 == wp->nrows) ? 0 : row + 1;
570 break;
571 case 180:
572 col = (col + 1 == wp->ncols) ? 0 : col + 1;
573 break;
574 case 200:
575 case 210:
576 col = (col + 1 == wp->ncols) ? 0 : col + 1;
577 row = (!row) ? wp->nrows - 1 : row - 1;
578 break;
579 case 240:
580 row = (!row) ? wp->nrows - 1 : row - 1;
581 break;
582 case 270:
583 case 280:
584 if (!row)
585 row = wp->nrows - 2;
586 else if (!(row - 1))
587 row = wp->nrows - 1;
588 else
589 row = row - 2;
590 break;
591 case 300:
592 col = (!col) ? wp->ncols - 1 : col - 1;
593 if (!row)
594 row = wp->nrows - 2;
595 else if (!(row - 1))
596 row = wp->nrows - 1;
597 else
598 row = row - 2;
599 break;
600 case 320:
601 case 330:
602 col = (!col) ? wp->ncols - 1 : col - 1;
603 row = (!row) ? wp->nrows - 1 : row - 1;
604 break;
605 default:
606 (void) fprintf(stderr, "wrong direction %d\n",
607 dir);
608 }
609 } else { /* left */
610 switch (dir) {
611 case 0:
612 col = (col + 1 == wp->ncols) ? 0 : col + 1;
613 break;
614 case 30:
615 case 40:
616 col = (col + 1 == wp->ncols) ? 0 : col + 1;
617 row = (!row) ? wp->nrows - 1 : row - 1;
618 break;
619 case 60:
620 col = (col + 1 == wp->ncols) ? 0 : col + 1;
621 if (!row)
622 row = wp->nrows - 2;
623 else if (row == 1)
624 row = wp->nrows - 1;
625 else
626 row = row - 2;
627 break;
628 case 80:
629 case 90:
630 if (!row)
631 row = wp->nrows - 2;
632 else if (row == 1)
633 row = wp->nrows - 1;
634 else
635 row = row - 2;
636 break;
637 case 120:
638 row = (!row) ? wp->nrows - 1 : row - 1;
639 break;
640 case 150:
641 case 160:
642 col = (!col) ? wp->ncols - 1 : col - 1;
643 row = (!row) ? wp->nrows - 1 : row - 1;
644 break;
645 case 180:
646 col = (!col) ? wp->ncols - 1 : col - 1;
647 break;
648 case 200:
649 case 210:
650 col = (!col) ? wp->ncols - 1 : col - 1;
651 row = (row + 1 == wp->nrows) ? 0 : row + 1;
652 break;
653 case 240:
654 row = (row + 1 == wp->nrows) ? 0 : row + 1;
655 break;
656 case 270:
657 case 280:
658 if (row + 1 == wp->nrows)
659 row = 1;
660 else if (row + 2 == wp->nrows)
661 row = 0;
662 else
663 row = row + 2;
664 break;
665 case 300:
666 col = (col + 1 == wp->ncols) ? 0 : col + 1;
667 if (row + 1 == wp->nrows)
668 row = 1;
669 else if (row + 2 == wp->nrows)
670 row = 0;
671 else
672 row = row + 2;
673 break;
674 case 320:
675 case 330:
676 col = (col + 1 == wp->ncols) ? 0 : col + 1;
677 row = (row + 1 == wp->nrows) ? 0 : row + 1;
678 break;
679 default:
680 (void) fprintf(stderr, "wrong direction %d\n",
681 dir);
682 }
683 }
684 #if 0
685 } else {
686 int orient = ((row & 1) * 2 + col) % 4;
687 switch (orient) { /* up, down, left, right */
688 case 0:
689 switch (dir) {
690 case 0:
691 col++;
692 break;
693 case 51: /* 7 */
694 case 72: /* 5 */
695 col = (col + 2 >= wp->ncols) ? 0 : col + 2;
696 break;
697 case 102: /* 7 corner */
698 col = (col + 3 >= wp->ncols) ? 1 : col + 3;
699 row = (row == 0) ? wp->nrows - 1 : row - 1;
700 break;
701 case 144: /* 5 */
702 case 153: /* 7 */
703 col++;
704 row = (row == 0) ? wp->nrows - 1 : row - 1;
705 break;
706 case 204: /* 7 */
707 case 216: /* 5 */
708 row = (row == 0) ? wp->nrows - 1 : row - 1;
709 break;
710 case 255: /* 7 */
711 col = (col == 0) ? wp->ncols - 1 : col - 1;
712 row = (row == 0) ? wp->nrows - 1 : row - 1;
713 break;
714 case 288: /* 5 */
715 case 306: /* 7 */
716 col = (col == 0) ? wp->ncols - 1 : col - 1;
717 break;
718 default:
719 (void) fprintf(stderr, "wrong direction %d\n",
720 dir);
721 }
722 break;
723 case 1:
724 switch (dir) {
725 case 0:
726 col--;
727 break;
728 case 51: /* 7 */
729 case 72: /* 5 */
730 col = (col == 1) ? wp->ncols - 1 : col - 2;
731 break;
732 case 102: /* 7 */
733 col = (col == 1) ? wp->ncols - 2 : col - 3;
734 row = (row + 1 == wp->nrows) ? 0 : row + 1;
735 break;
736 case 144: /* 5 */
737 case 153: /* 7 */
738 col--;
739 row = (row + 1 == wp->nrows) ? 0 : row + 1;
740 break;
741 case 204: /* 7 */
742 case 216: /* 5 */
743 row = (row + 1 == wp->nrows) ? 0 : row + 1;
744 break;
745 case 255: /* 7 */
746 col = (col + 1 >= wp->ncols) ? 0 : col + 1;
747 row = (row + 1 == wp->nrows) ? 0 : row + 1;
748 break;
749 case 288: /* 5 */
750 case 306: /* 7 */
751 col = (col + 1 >= wp->ncols) ? 0 : col + 1;
752 break;
753 default:
754 (void) fprintf(stderr, "wrong direction %d\n",
755 dir);
756 }
757 break;
758 case 2:
759 switch (dir) {
760 case 0:
761 col = (col + 1 >= wp->ncols) ? 0 : col + 1;
762 break;
763 case 51: /* 7 */
764 case 72: /* 5 */
765 row = (row == 0) ? wp->nrows - 1 : row - 1;
766 col++;
767 break;
768 case 102: /* 7 */
769 col = (col == 0) ? wp->ncols - 1 : col - 1;
770 row = (row == 0) ? wp->nrows - 1 : row - 1;
771 break;
772 case 144: /* 5 */
773 case 153: /* 7 */
774 col = (col == 0) ? wp->ncols - 2 : col - 2;
775 break;
776 case 204: /* 7 */
777 case 216: /* 5 */
778 col = (col == 0) ? wp->ncols - 1 : col - 1;
779 break;
780 case 255: /* 7 */
781 row = (row + 1 == wp->nrows) ? 0 : row + 1;
782 col = (col == 0) ? wp->ncols - 1 : col - 1;
783 break;
784 case 288: /* 5 */
785 case 306: /* 7 */
786 row = (row + 1 == wp->nrows) ? 0 : row + 1;
787 break;
788 default:
789 (void) fprintf(stderr, "wrong direction %d\n",
790 dir);
791 }
792 break;
793 case 3:
794 switch (dir) {
795 case 0:
796 col--;
797 break;
798 case 51: /* 7 */
799 case 72: /* 5 */
800 col = (col == 0) ? wp->ncols - 1 : col - 1;
801 row = (row + 1 == wp->nrows) ? 0 : row + 1;
802 break;
803 case 102: /* 7 */
804 col = (col + 1 >= wp->ncols) ? 0 : col + 1;
805 row = (row + 1 == wp->nrows) ? 0 : row + 1;
806 break;
807 case 144: /* 5 */
808 case 153: /* 7 */
809 col = (col + 2 >= wp->ncols) ? 1 : col + 2;
810 break;
811 case 204: /* 7 */
812 case 216: /* 5 */
813 col = (col + 1 >= wp->ncols) ? 0 : col + 1;
814 break;
815 case 255: /* 7 */
816 col = (col + 1 >= wp->ncols) ? 0 : col + 1;
817 row = (row == 0) ? wp->nrows - 1 : row - 1;
818 break;
819 case 288: /* 5 */
820 case 306: /* 7 */
821 row = (row == 0) ? wp->nrows - 1 : row - 1;
822 break;
823 default:
824 (void) fprintf(stderr, "wrong direction %d\n",
825 dir);
826 }
827 break;
828 default:
829 (void) fprintf(stderr, "wrong orient %d\n",
830 orient);
831 }
832 #endif
833 }
834 return (row * wp->ncols + col);
835 }
836
837 static void
free_wator_screen(watorstruct * wp)838 free_wator_screen(watorstruct *wp)
839 {
840 int kind;
841
842 if (wp == NULL) {
843 return;
844 }
845 for (kind = 0; kind <= KINDS; kind++) {
846 if (wp->firstkind[kind] != NULL) {
847 flush_kindlist(wp, kind);
848 free(wp->firstkind[kind]);
849 wp->firstkind[kind] = (struct _CellList *) NULL;
850 }
851 if (wp->lastkind[kind] != NULL) {
852 free(wp->lastkind[kind]);
853 wp->lastkind[kind] = (struct _CellList *) NULL;
854 }
855 }
856 if (wp->arr != NULL) {
857 free(wp->arr);
858 wp->arr = (CellList **) NULL;
859 }
860 wp = NULL;
861 }
862
863 ENTRYPOINT void
init_wator(ModeInfo * mi)864 init_wator(ModeInfo * mi)
865 {
866 int size = MI_SIZE(mi);
867 int i, col, row, colrow, kind;
868 cellstruct info;
869 watorstruct *wp;
870
871 MI_INIT(mi, wators);
872 wp = &wators[MI_SCREEN(mi)];
873
874 wp->generation = 0;
875 if (!wp->firstkind[0]) { /* Genesis */
876 icon_width = fish0_width;
877 icon_height = fish0_height;
878 /* Set up what will be a 'triply' linked list.
879 doubly linked list, doubly linked to an array */
880 for (kind = FISH; kind <= KINDS; kind++)
881 if (!init_kindlist(wp, kind)) {
882 free_wator_screen(wp);
883 return;
884 }
885 for (i = 0; i < BITMAPS; i++) {
886 logo[i].width = icon_width;
887 logo[i].height = icon_height;
888 logo[i].bytes_per_line = (icon_width + 7) / 8;
889 }
890 } else /* Exterminate all */
891 for (i = FISH; i <= KINDS; i++)
892 flush_kindlist(wp, i);
893 if (MI_IS_FULLRANDOM(mi)) {
894 wp->vertical = (Bool) (LRAND() & 1);
895 } else {
896 wp->vertical = vertical;
897 }
898 wp->width = MI_WIDTH(mi);
899 wp->height = MI_HEIGHT(mi);
900 if (wp->width < 2)
901 wp->width = 2;
902 if (wp->height < 2)
903 wp->height = 2;
904
905 for (i = 0; i < NEIGHBORKINDS; i++) {
906 if (neighbors == plots[i]) {
907 wp->neighbors = neighbors;
908 break;
909 }
910 if (i == NEIGHBORKINDS - 1) {
911 #if 0
912 wp->neighbors = plots[NRAND(NEIGHBORKINDS)];
913 wp->neighbors = (LRAND() & 1) ? 4 : 8;
914 #else
915 wp->neighbors = 4;
916 #endif
917 break;
918 }
919 }
920
921 if (wp->neighbors == 6) {
922 int nccols, ncrows, sides;
923
924 wp->polygon = 6;
925 if (!wp->vertical) {
926 wp->height = MI_WIDTH(mi);
927 wp->width = MI_HEIGHT(mi);
928 }
929 if (wp->width < 8)
930 wp->width = 8;
931 if (wp->height < 8)
932 wp->height = 8;
933 if (size < -MINSIZE)
934 wp->ys = NRAND(MIN(-size, MAX(MINSIZE, MIN(wp->width, wp->height) /
935 MINGRIDSIZE)) - MINSIZE + 1) + MINSIZE;
936 else if (size < MINSIZE) {
937 if (!size)
938 wp->ys = MAX(MINSIZE, MIN(wp->width, wp->height) / MINGRIDSIZE);
939 else
940 wp->ys = MINSIZE;
941 } else
942 wp->ys = MIN(size, MAX(MINSIZE, MIN(wp->width, wp->height) /
943 MINGRIDSIZE));
944 wp->xs = wp->ys;
945 wp->pixelmode = True;
946 nccols = MAX(wp->width / wp->xs - 2, 2);
947 ncrows = MAX(wp->height / wp->ys - 1, 4);
948 wp->ncols = nccols / 2;
949 wp->nrows = 2 * (ncrows / 4);
950 wp->xb = (wp->width - wp->xs * nccols) / 2 + wp->xs / 2;
951 wp->yb = (wp->height - wp->ys * (ncrows / 2) * 2) / 2 +
952 wp->ys / 3;
953 for (sides = 0; sides < 6; sides++) {
954 if (wp->vertical) {
955 wp->shape.hexagon[sides].x =
956 (wp->xs - 1) * hexagonUnit[sides].x;
957 wp->shape.hexagon[sides].y =
958 ((wp->ys - 1) * hexagonUnit[sides].y /
959 2) * 4 / 3;
960 } else {
961 wp->shape.hexagon[sides].y =
962 (wp->xs - 1) * hexagonUnit[sides].x;
963 wp->shape.hexagon[sides].x =
964 ((wp->ys - 1) * hexagonUnit[sides].y /
965 2) * 4 / 3;
966 }
967 }
968 } else if (wp->neighbors == 4 || wp->neighbors == 8) {
969 wp->polygon = 4;
970 if (wp->width < 2)
971 wp->width = 2;
972 if (wp->height < 2)
973 wp->height = 2;
974 if (size == 0 ||
975 MINGRIDSIZE * size > wp->width || MINGRIDSIZE * size > wp->height) {
976 if (wp->width > MINGRIDSIZE * icon_width &&
977 wp->height > MINGRIDSIZE * icon_height) {
978 wp->pixelmode = False;
979 wp->xs = icon_width;
980 wp->ys = icon_height;
981 } else {
982 wp->pixelmode = True;
983 wp->xs = wp->ys = MAX(MINSIZE, MIN(wp->width, wp->height) /
984 MINGRIDSIZE);
985 }
986 } else {
987 wp->pixelmode = True;
988 if (size < -MINSIZE)
989 wp->ys = NRAND(MIN(-size, MAX(MINSIZE, MIN(wp->width, wp->height) /
990 MINGRIDSIZE)) - MINSIZE + 1) + MINSIZE;
991 else if (size < MINSIZE)
992 wp->ys = MINSIZE;
993 else
994 wp->ys = MIN(size, MAX(MINSIZE, MIN(wp->width, wp->height) /
995 MINGRIDSIZE));
996 wp->xs = wp->ys;
997 }
998 wp->ncols = MAX(wp->width / wp->xs, 2);
999 wp->nrows = MAX(wp->height / wp->ys, 2);
1000 wp->xb = (wp->width - wp->xs * wp->ncols) / 2;
1001 wp->yb = (wp->height - wp->ys * wp->nrows) / 2;
1002 } else { /* TRI */
1003 int orient, sides;
1004
1005 wp->polygon = 3;
1006 if (!wp->vertical) {
1007 wp->height = MI_WIDTH(mi);
1008 wp->width = MI_HEIGHT(mi);
1009 }
1010 if (wp->width < 2)
1011 wp->width = 2;
1012 if (wp->height < 2)
1013 wp->height = 2;
1014 if (size < -MINSIZE)
1015 wp->ys = NRAND(MIN(-size, MAX(MINSIZE, MIN(wp->width, wp->height) /
1016 MINGRIDSIZE)) - MINSIZE + 1) + MINSIZE;
1017 else if (size < MINSIZE) {
1018 if (!size)
1019 wp->ys = MAX(MINSIZE, MIN(wp->width, wp->height) / MINGRIDSIZE);
1020 else
1021 wp->ys = MINSIZE;
1022 } else
1023 wp->ys = MIN(size, MAX(MINSIZE, MIN(wp->width, wp->height) /
1024 MINGRIDSIZE));
1025 wp->xs = (int) (1.52 * wp->ys);
1026 wp->pixelmode = True;
1027 wp->ncols = (MAX(wp->width / wp->xs - 1, 2) / 2) * 2;
1028 wp->nrows = (MAX(wp->height / wp->ys - 1, 2) / 2) * 2;
1029 wp->xb = (wp->width - wp->xs * wp->ncols) / 2 + wp->xs / 2;
1030 wp->yb = (wp->height - wp->ys * wp->nrows) / 2 + wp->ys / 2;
1031 for (orient = 0; orient < 2; orient++) {
1032 for (sides = 0; sides < 3; sides++) {
1033 if (wp->vertical) {
1034 wp->shape.triangle[orient][sides].x =
1035 (wp->xs - 2) * triangleUnit[orient][sides].x;
1036 wp->shape.triangle[orient][sides].y =
1037 (wp->ys - 2) * triangleUnit[orient][sides].y;
1038 } else {
1039 wp->shape.triangle[orient][sides].y =
1040 (wp->xs - 2) * triangleUnit[orient][sides].x;
1041 wp->shape.triangle[orient][sides].x =
1042 (wp->ys - 2) * triangleUnit[orient][sides].y;
1043 }
1044 }
1045 }
1046 }
1047
1048 wp->positions = wp->ncols * wp->nrows;
1049
1050 if (wp->arr != NULL)
1051 free(wp->arr);
1052 if ((wp->arr = (CellList **) calloc(wp->positions,
1053 sizeof (CellList *))) == NULL) {
1054 free_wator_screen(wp);
1055 return;
1056 }
1057
1058 /* Play G-d with these numbers */
1059 wp->nkind[FISH] = wp->positions / 3;
1060 wp->nkind[SHARK] = wp->nkind[FISH] / 10;
1061 wp->kind = FISH;
1062 if (!wp->nkind[SHARK])
1063 wp->nkind[SHARK] = 1;
1064 wp->breed[FISH] = MI_COUNT(mi);
1065 wp->breed[SHARK] = 10;
1066 if (wp->breed[FISH] < 1)
1067 wp->breed[FISH] = 1;
1068 else if (wp->breed[FISH] > wp->breed[SHARK])
1069 wp->breed[FISH] = 4;
1070 wp->sstarve = 3;
1071
1072 MI_CLEARWINDOW(mi);
1073 wp->painted = False;
1074
1075 for (kind = FISH; kind <= SHARK; kind++) {
1076 i = 0;
1077 while (i < wp->nkind[kind]) {
1078 col = NRAND(wp->ncols);
1079 row = NRAND(wp->nrows);
1080 colrow = col + row * wp->ncols;
1081 if (!wp->arr[colrow]) {
1082 i++;
1083 info.kind = kind;
1084 info.age = NRAND(wp->breed[kind]);
1085 info.food = NRAND(wp->sstarve);
1086 info.direction = NRAND(KINDBITMAPS) + kind * KINDBITMAPS;
1087 if (MI_NPIXELS(mi) > 2)
1088 info.color = NRAND(MI_NPIXELS(mi));
1089 else
1090 info.color = 0;
1091 info.col = col;
1092 info.row = row;
1093 if (!addto_kindlist(wp, kind, info)) {
1094 free_wator_screen(wp);
1095 return;
1096 }
1097 wp->arr[colrow] = wp->currkind;
1098 drawcell(mi, col, row,
1099 wp->currkind->info.color, wp->currkind->info.direction, True);
1100 }
1101 }
1102 }
1103 }
1104
1105 ENTRYPOINT void
draw_wator(ModeInfo * mi)1106 draw_wator(ModeInfo * mi)
1107 {
1108 int col, row;
1109 int colrow, cr, position;
1110 int i, numok;
1111 struct {
1112 int pos, dir;
1113 } acell[12];
1114 watorstruct *wp;
1115
1116 if (wators == NULL)
1117 return;
1118 wp = &wators[MI_SCREEN(mi)];
1119 if (wp->arr == NULL)
1120 return;
1121
1122 MI_IS_DRAWN(mi) = True;
1123 wp->painted = True;
1124 /* Alternate updates, fish and sharks live out of phase with each other */
1125 wp->kind = (wp->kind + 1) % KINDS;
1126 {
1127 wp->currkind = wp->firstkind[wp->kind]->next;
1128
1129 while (wp->currkind != wp->lastkind[wp->kind]) {
1130 col = wp->currkind->info.col;
1131 row = wp->currkind->info.row;
1132 colrow = col + row * wp->ncols;
1133 numok = 0;
1134 if (wp->kind == SHARK) { /* Scan for fish */
1135 for (i = 0; i < wp->neighbors; i++) {
1136 position = positionOfNeighbor(wp, i, col, row);
1137 if (wp->arr[position] && wp->arr[position]->info.kind == FISH) {
1138 acell[numok].pos = position;
1139 acell[numok++].dir = i;
1140 }
1141 }
1142 if (numok) { /* No thanks, I'm a vegetarian */
1143 i = NRAND(numok);
1144 wp->nkind[FISH]--;
1145 cr = acell[i].pos;
1146 removefrom_kindlist(wp, wp->arr[cr]);
1147 wp->arr[cr] = wp->currkind;
1148 if (wp->neighbors == 4) {
1149 wp->currkind->info.direction = (5 - acell[i].dir) % ORIENTS +
1150 ((NRAND(REFLECTS)) ? 0 : ORIENTS) + wp->kind * KINDBITMAPS;
1151 } else if (wp->neighbors == 8) {
1152 wp->currkind->info.direction = (char) (5 - (acell[i].dir / 2 +
1153 ((acell[i].dir % 2) ? LRAND() & 1 : 0))) % ORIENTS +
1154 ((NRAND(REFLECTS)) ? 0 : ORIENTS) + wp->kind * KINDBITMAPS;
1155 } else
1156 wp->currkind->info.direction = wp->kind * KINDBITMAPS;
1157 wp->currkind->info.col = acell[i].pos % wp->ncols;
1158 wp->currkind->info.row = acell[i].pos / wp->ncols;
1159 wp->currkind->info.food = wp->sstarve;
1160 drawcell(mi, wp->currkind->info.col, wp->currkind->info.row,
1161 wp->currkind->info.color, wp->currkind->info.direction, True);
1162 if (++(wp->currkind->info.age) >= wp->breed[wp->kind]) { /* breed */
1163 cutfrom_kindlist(wp); /* This rotates out who goes first */
1164 wp->babykind->info.age = 0;
1165 if (!dupin_kindlist(wp)) {
1166 free_wator_screen(wp);
1167 return;
1168 }
1169 wp->arr[colrow] = wp->babykind;
1170 wp->babykind->info.col = col;
1171 wp->babykind->info.row = row;
1172 wp->babykind->info.age = -1; /* Make one a little younger */
1173 #if 0
1174 if (MI_NPIXELS(mi) > 2 && (LRAND() & 1))
1175 /* A color mutation */
1176 if (++(wp->babykind->info.color) >= MI_NPIXELS(mi))
1177 wp->babykind->info.color = 0;
1178 #endif
1179 wp->nkind[wp->kind]++;
1180 } else {
1181 wp->arr[colrow] = 0;
1182 drawcell(mi, col, row, 0, 0, False);
1183 }
1184 } else {
1185 if (wp->currkind->info.food-- < 0) { /* Time to die, Jaws */
1186 /* back up one or else in void */
1187 wp->currkind = wp->currkind->previous;
1188 removefrom_kindlist(wp, wp->arr[colrow]);
1189 wp->arr[colrow] = 0;
1190 drawcell(mi, col, row, 0, 0, False);
1191 wp->nkind[wp->kind]--;
1192 numok = -1; /* Want to escape from next if */
1193 }
1194 }
1195 }
1196 if (!numok) { /* Fish or shark search for a place to go */
1197 for (i = 0; i < wp->neighbors; i++) {
1198 position = positionOfNeighbor(wp, i, col, row);
1199 if (!wp->arr[position]) { /* Found an empty spot */
1200 acell[numok].pos = position;
1201 acell[numok++].dir = i;
1202 }
1203 }
1204 if (numok) { /* Found a place to go */
1205 i = NRAND(numok);
1206 wp->arr[acell[i].pos] = wp->currkind;
1207 if (wp->neighbors == 4) {
1208 wp->currkind->info.direction = (5 - acell[i].dir) % ORIENTS +
1209 ((NRAND(REFLECTS)) ? 0 : ORIENTS) + wp->kind * KINDBITMAPS;
1210 } else if (wp->neighbors == 8) {
1211 wp->currkind->info.direction = (char) (5 - (acell[i].dir / 2 +
1212 ((acell[i].dir % 2) ? LRAND() & 1 : 0))) % ORIENTS +
1213 ((NRAND(REFLECTS)) ? 0 : ORIENTS) + wp->kind * KINDBITMAPS;
1214 } else
1215 wp->currkind->info.direction = wp->kind * KINDBITMAPS;
1216 wp->currkind->info.col = acell[i].pos % wp->ncols;
1217 wp->currkind->info.row = acell[i].pos / wp->ncols;
1218 drawcell(mi,
1219 wp->currkind->info.col, wp->currkind->info.row,
1220 wp->currkind->info.color, wp->currkind->info.direction, True);
1221 if (++(wp->currkind->info.age) >= wp->breed[wp->kind]) { /* breed */
1222 cutfrom_kindlist(wp); /* This rotates out who goes first */
1223 wp->babykind->info.age = 0;
1224 if (!dupin_kindlist(wp)) {
1225 free_wator_screen(wp);
1226 return;
1227 }
1228 wp->arr[colrow] = wp->babykind;
1229 wp->babykind->info.col = col;
1230 wp->babykind->info.row = row;
1231 wp->babykind->info.age = -1; /* Make one a little younger */
1232 wp->nkind[wp->kind]++;
1233 } else {
1234 wp->arr[colrow] = 0;
1235 drawcell(mi, col, row, 0, 0, False);
1236 }
1237 } else {
1238 /* I'll just sit here and wave my tail so you know I am alive */
1239 wp->currkind->info.direction =
1240 (wp->currkind->info.direction + ORIENTS) % KINDBITMAPS +
1241 wp->kind * KINDBITMAPS;
1242 drawcell(mi, col, row, wp->currkind->info.color,
1243 wp->currkind->info.direction, True);
1244 }
1245 }
1246 wp->currkind = wp->currkind->next;
1247 }
1248 reattach_kindlist(wp, wp->kind);
1249 }
1250
1251 if ((wp->nkind[FISH] >= wp->positions) ||
1252 (!wp->nkind[FISH] && !wp->nkind[SHARK]) ||
1253 wp->generation >= MI_CYCLES(mi)) {
1254 init_wator(mi);
1255 }
1256 if (wp->kind == SHARK)
1257 wp->generation++;
1258 }
1259
1260 ENTRYPOINT void
release_wator(ModeInfo * mi)1261 release_wator(ModeInfo * mi)
1262 {
1263 if (wators != NULL) {
1264 int screen;
1265
1266 for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++)
1267 free_wator_screen(&wators[screen]);
1268 free(wators);
1269 wators = (watorstruct *) NULL;
1270 }
1271 }
1272
1273 #ifndef STANDALONE
1274 ENTRYPOINT void
refresh_wator(ModeInfo * mi)1275 refresh_wator(ModeInfo * mi)
1276 {
1277 watorstruct *wp;
1278
1279 if (wators == NULL)
1280 return;
1281 wp = &wators[MI_SCREEN(mi)];
1282
1283 if (wp->painted) {
1284 MI_CLEARWINDOW(mi);
1285 wp->painted = False;
1286 }
1287 }
1288 #endif
1289
1290 XSCREENSAVER_MODULE ("Wator", wator)
1291
1292 #endif /* MODE_wator */
1293