Link with C++ linker
[oweals/cde.git] / cde / programs / dtscreen / life.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these librararies and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 /* $XConsortium: life.c /main/3 1995/11/02 16:07:44 rswiston $ */
24 /*                                                                      *
25  * (c) Copyright 1993, 1994 Hewlett-Packard Company                     *
26  * (c) Copyright 1993, 1994 International Business Machines Corp.       *
27  * (c) Copyright 1993, 1994 Sun Microsystems, Inc.                      *
28  * (c) Copyright 1993, 1994 Novell, Inc.                                *
29  */
30 /*-
31  * life.c - Conway's game of Life for dtscreen, the X Window System lockscreen.
32  *
33  * Copyright (c) 1991 by Patrick J. Naughton.
34  *
35  * See dtscreen.c for copying information.
36  *
37  * Revision History:
38  * 24-May-91: Added wraparound code from johnson@bugs.comm.mot.com.
39  *            Made old cells stay blue.
40  *            Made batchcount control the number of generations till restart.
41  * 29-Jul-90: support for multiple screens.
42  * 07-Feb-90: remove bogus semi-colon after #include line.
43  * 15-Dec-89: Fix for proper skipping of {White,Black}Pixel() in colors.
44  * 08-Oct-89: Moved seconds() to an extern.
45  * 20-Sep-89: Written (life algorithm courtesy of Jim Graham, flar@sun.com).
46  */
47
48 #include "dtscreen.h"
49 #include "lifeicon.bit"
50
51 static XImage logo = {
52     0, 0,                       /* width, height */
53     0, XYBitmap, 0,             /* xoffset, format, data */
54     LSBFirst, 8,                /* byte-order, bitmap-unit */
55     LSBFirst, 8, 1              /* bitmap-bit-order, bitmap-pad, depth */
56 };
57 #define min(a, b) ((a)<(b)?(a):(b))
58 #define MAXROWS 155
59 #define MAXCOLS 144
60 #define TIMEOUT 30
61
62 typedef struct {
63     int         pixelmode;
64     int         xs;
65     int         ys;
66     int         xb;
67     int         yb;
68     int         generation;
69     long        shooterTime;
70     int         nrows;
71     int         ncols;
72     int         width;
73     int         height;
74     unsigned char buffer[(MAXROWS + 2) * (MAXCOLS + 2) + 2];
75     unsigned char tempbuf[MAXCOLS * 2];
76     unsigned char lastbuf[MAXCOLS];
77     unsigned char agebuf[(MAXROWS + 2) * (MAXCOLS + 2)];
78 }           lifestruct;
79
80 static int  icon_width, icon_height;
81
82 /* Buffer stores the data for each cell. Each cell is stored as
83  * 8 bits representing the presence of a critter in each of it's
84  * surrounding 8 cells. There is an empty row and column around
85  * the whole array to allow stores without bounds checking as well
86  * as an extra row at the end for the fetches into tempbuf.
87  *
88  * Tempbuf stores the data for the next two rows so that we know
89  * the state of those critter before he was modified by the fate
90  * of the critters that have already been processed.
91  *
92  * Agebuf stores the age of each critter.
93  */
94
95 #define UPLT    0x01
96 #define UP      0x02
97 #define UPRT    0x04
98 #define LT      0x08
99 #define RT      0x10
100 #define DNLT    0x20
101 #define DN      0x40
102 #define DNRT    0x80
103
104 /* Fates is a lookup table for the fate of a critter. The 256
105  * entries represent the 256 possible combinations of the 8
106  * neighbor cells. Each entry is one of BIRTH (create a cell
107  * or leave one alive), SAME (leave the cell alive or dead),
108  * or DEATH (kill anything in the cell).
109  */
110 #define BIRTH   0
111 #define SAME    1
112 #define DEATH   2
113 static unsigned char fates[256];
114 static int  initialized = 0;
115
116 const int  patterns[][128] = {
117     {                           /* EIGHT */
118         -3, -3, -2, -3, -1, -3,
119         -3, -2, -2, -2, -1, -2,
120         -3, -1, -2, -1, -1, -1,
121         0, 0, 1, 0, 2, 0,
122         0, 1, 1, 1, 2, 1,
123         0, 2, 1, 2, 2, 2,
124         99
125     },
126     {                           /* PULSAR */
127         1, 1, 2, 1, 3, 1, 4, 1, 5, 1,
128         1, 2, 5, 2,
129         99
130     },
131     {                           /* BARBER */
132         -7, -7, -6, -7,
133         -7, -6, -5, -6,
134         -5, -4, -3, -4,
135         -3, -2, -1, -2,
136         -1, 0, 1, 0,
137         1, 2, 3, 2,
138         3, 4, 5, 4,
139         4, 5, 5, 5,
140         99
141     },
142     {                           /* HERTZ */
143         -2, -6, -1, -6,
144         -2, -5, -1, -5,
145         -7, -3, -6, -3, -2, -3, -1, -3, 0, -3, 1, -3, 5, -3, 6, -3,
146         -7, -2, -5, -2, -3, -2, 2, -2, 4, -2, 6, -2,
147         -5, -1, -3, -1, -2, -1, 2, -1, 4, -1,
148         -7, 0, -5, 0, -3, 0, 2, 0, 4, 0, 6, 0,
149         -7, 1, -6, 1, -2, 1, -1, 1, 0, 1, 1, 1, 5, 1, 6, 1,
150         -2, 3, -1, 3,
151         -2, 4, -1, 4,
152         99
153     },
154     {                           /* TUMBLER */
155         -6, -6, -5, -6, 6, -6, 7, -6,
156         -6, -5, -5, -5, 6, -5, 7, -5,
157         -5, 5, 6, 5,
158         -7, 6, -5, 6, 6, 6, 8, 6,
159         -7, 7, -5, 7, 6, 7, 8, 7,
160         -7, 8, -6, 8, 7, 8, 8, 8,
161         99
162     },
163     {                           /* PERIOD4 */
164         -5, -8, -4, -8,
165         -7, -7, -5, -7,
166         -8, -6, -2, -6,
167         -7, -5, -3, -5, -2, -5,
168         -5, -3, -3, -3,
169         -4, -2,
170         99
171     },
172     {                           /* PERIOD5 */
173         -5, -8, -4, -8,
174         -6, -7, -3, -7,
175         -7, -6, -2, -6,
176         -8, -5, -1, -5,
177         -8, -4, -1, -4,
178         -7, -3, -2, -3,
179         -6, -2, -3, -2,
180         -5, -1, -4, -1,
181         99
182     },
183     {                           /* PERIOD6 */
184         -4, -8, -3, -8,
185         -8, -7, -7, -7, -5, -7,
186         -8, -6, -7, -6, -4, -6, -1, -6,
187         -3, -5, -1, -5,
188         -2, -4,
189         -3, -2, -2, -2,
190         -3, -1, -2, -1,
191         99
192     },
193     {                           /* PINWHEEL */
194         -4, -8, -3, -8,
195         -4, -7, -3, -7,
196         -4, -5, -3, -5, -2, -5, -1, -5,
197         -5, -4, -3, -4, 0, -4, 2, -4, 3, -4,
198         -5, -3, -1, -3, 0, -3, 2, -3, 3, -3,
199         -8, -2, -7, -2, -5, -2, -2, -2, 0, -2,
200         -8, -1, -7, -1, -5, -1, 0, -1,
201         -4, 0, -3, 0, -2, 0, -1, 0,
202         -2, 2, -1, 2,
203         -2, 3, -1, 3,
204         99
205     },
206     {                           /* ] */
207         -1, -1, 0, -1, 1, -1,
208         0, 0, 1, 0,
209         -1, 1, 0, 1, 1, 1,
210         99
211     },
212     {                           /* cc: */
213         -3, -1, -2, -1, -1, -1, 1, -1, 2, -1, 3, -1,
214         -3, 0, -2, 0, 1, 0, 2, 0,
215         -3, 1, -2, 1, -1, 1, 1, 1, 2, 1, 3, 1,
216         99
217     },
218     {                           /* DOLBY */
219         -3, -1, -2, -1, -1, -1, 1, -1, 2, -1, 3, -1,
220         -3, 0, -2, 0, 2, 0, 3, 0,
221         -3, 1, -2, 1, -1, 1, 1, 1, 2, 1, 3, 1,
222         99
223     },
224     {                           /* HORIZON */
225         -15, 0, -14, 0, -13, 0, -12, 0, -11, 0,
226         -10, 0, -9, 0, -8, 0, -7, 0, -6, 0,
227         -5, 0, -4, 0, -3, 0, -2, 0, -1, 0,
228         4, 0, 3, 0, 2, 0, 1, 0, 0, 0,
229         9, 0, 8, 0, 7, 0, 6, 0, 5, 0,
230         14, 0, 13, 0, 12, 0, 11, 0, 10, 0,
231         99
232     },
233     {                           /* SHEAR */
234         -7, -2, -6, -2, -5, -2, -4, -2, -3, -2,
235         -2, -2, -1, -2, 0, -2, 1, -2, 2, -2,
236         -5, -1, -4, -1, -3, -1, -2, -1, -1, -1,
237         0, -1, 1, -1, 2, -1, 3, -1, 4, -1,
238         -3, 0, -2, 0, -1, 0, 0, 0, 1, 0,
239         2, 0, 3, 0, 4, 0, 5, 0, 6, 0,
240         -10, 1, -9, 1, -8, 1, -7, 1, -6, 1,
241         -5, 1, -4, 1, -3, 1, -2, 1, -1, 1,
242         -10, 2, -9, 2, -8, 2, -7, 2, -6, 2,
243         -5, 2, -4, 2, -3, 2, -2, 2, -1, 2,
244         99
245     },
246     {                           /* VERTIGO */
247         0, -7,
248         0, -6,
249         0, -5,
250         0, -4,
251         0, -3,
252         0, -2,
253         0, -1,
254         0, 0,
255         0, 7,
256         0, 6,
257         0, 5,
258         0, 4,
259         0, 3,
260         0, 2,
261         0, 1,
262         99
263     },
264     {                           /* CROSSBAR */
265         -5, 0, -4, 0, -3, 0, -2, 0, -1, 0, 4, 0, 3, 0, 2, 0, 1, 0, 0, 0,
266         99
267     },
268     {                           /* GOALPOSTS */
269         -8, -7, 8, -7,
270         -8, -6, 8, -6,
271         -8, -5, 8, -5,
272         -8, -4, 8, -4,
273         -8, -3, 8, -3,
274         -8, -2, 8, -2,
275         -8, -1, 8, -1,
276         -8, 0, 8, 0,
277         -8, 1, 8, 1,
278         -8, 2, 8, 2,
279         -8, 3, 8, 3,
280         -8, 4, 8, 4,
281         -8, 5, 8, 5,
282         -8, 6, 8, 6,
283         -8, 7, 8, 7,
284         99
285     },
286     {                           /* \ */
287         -8, -8, -7, -8,
288         -7, -7, -6, -7,
289         -6, -6, -5, -6,
290         -5, -5, -4, -5,
291         -4, -4, -3, -4,
292         -3, -3, -2, -3,
293         -2, -2, -1, -2,
294         -1, -1, 0, -1,
295         0, 0, 1, 0,
296         1, 1, 2, 1,
297         2, 2, 3, 2,
298         3, 3, 4, 3,
299         4, 4, 5, 4,
300         5, 5, 6, 5,
301         6, 6, 7, 6,
302         7, 7, 8, 7,
303         99
304     },
305     {                           /* LABYRINTH */
306         -4, -4, -3, -4, -2, -4, -1, -4, 0, -4, 1, -4, 2, -4, 3, -4, 4, -4,
307         -4, -3, 0, -3, 4, -3,
308         -4, -2, -2, -2, -1, -2, 0, -2, 1, -2, 2, -2, 4, -2,
309         -4, -1, -2, -1, 2, -1, 4, -1,
310         -4, 0, -2, 0, -1, 0, 0, 0, 1, 0, 2, 0, 4, 0,
311         -4, 1, -2, 1, 2, 1, 4, 1,
312         -4, 2, -2, 2, -1, 2, 0, 2, 1, 2, 2, 2, 4, 2,
313         -4, 3, 0, 3, 4, 3,
314         -4, 4, -3, 4, -2, 4, -1, 4, 0, 4, 1, 4, 2, 4, 3, 4, 4, 4,
315         99
316     }
317 };
318
319 #define NPATS   (sizeof patterns / sizeof patterns[0])
320
321
322 static void
323 drawcell(pwin, row, col)
324     perwindow *pwin;
325     int         row, col;
326 {
327     lifestruct *lp;
328
329     lp = (lifestruct *)pwin->data;
330     XSetForeground(dsp, pwin->gc, WhitePixelOfScreen(pwin->perscreen->screen));
331     if (!mono && pwin->perscreen->npixels > 2) {
332         unsigned char *loc = lp->buffer + ((row + 1) * (lp->ncols + 2)) + col + 1;
333         unsigned char *ageptr = lp->agebuf + (loc - lp->buffer);
334         unsigned char age = *ageptr;
335
336         /* if we aren't up to blue yet, then keep aging the cell. */
337         if (age < (unsigned char) (pwin->perscreen->npixels * 0.7))
338             ++age;
339
340         XSetForeground(dsp, pwin->gc, pwin->perscreen->pixels[age]);
341         *ageptr = age;
342     }
343     if (lp->pixelmode)
344         XFillRectangle(dsp, pwin->w, pwin->gc,
345                lp->xb + lp->xs * col, lp->yb + lp->ys * row, lp->xs, lp->ys);
346     else
347         XPutImage(dsp, pwin->w, pwin->gc, &logo,
348                   0, 0, lp->xb + lp->xs * col, lp->yb + lp->ys * row,
349                   icon_width, icon_height);
350 }
351
352
353 static void
354 erasecell(pwin, row, col)
355     perwindow *pwin;
356     int         row, col;
357 {
358     lifestruct *lp = (lifestruct *)pwin->data;
359     XSetForeground(dsp, pwin->gc, BlackPixelOfScreen(pwin->perscreen->screen));
360     XFillRectangle(dsp, pwin->w, pwin->gc,
361                lp->xb + lp->xs * col, lp->yb + lp->ys * row, lp->xs, lp->ys);
362 }
363
364
365 static void
366 spawn(pwin, loc)
367     perwindow *pwin;
368     unsigned char *loc;
369 {
370     lifestruct *lp = (lifestruct *)pwin->data;
371     unsigned char *ulloc, *ucloc, *urloc, *clloc, *crloc, *llloc, *lcloc, *lrloc,
372                *arloc;
373     int         off, row, col, lastrow;
374
375     lastrow = (lp->nrows) * (lp->ncols + 2);
376     off = loc - lp->buffer;
377     col = off % (lp->ncols + 2);
378     row = (off - col) / (lp->ncols + 2);
379     ulloc = loc - lp->ncols - 3;
380     ucloc = loc - lp->ncols - 2;
381     urloc = loc - lp->ncols - 1;
382     clloc = loc - 1;
383     crloc = loc + 1;
384     arloc = loc + 1;
385     llloc = loc + lp->ncols + 1;
386     lcloc = loc + lp->ncols + 2;
387     lrloc = loc + lp->ncols + 3;
388     if (row == 1) {
389         ulloc += lastrow;
390         ucloc += lastrow;
391         urloc += lastrow;
392     }
393     if (row == lp->nrows) {
394         llloc -= lastrow;
395         lcloc -= lastrow;
396         lrloc -= lastrow;
397     }
398     if (col == 1) {
399         ulloc += lp->ncols;
400         clloc += lp->ncols;
401         llloc += lp->ncols;
402     }
403     if (col == lp->ncols) {
404         urloc -= lp->ncols;
405         crloc -= lp->ncols;
406         lrloc -= lp->ncols;
407     }
408     *ulloc |= UPLT;
409     *ucloc |= UP;
410     *urloc |= UPRT;
411     *clloc |= LT;
412     *crloc |= RT;
413     *arloc |= RT;
414     *llloc |= DNLT;
415     *lcloc |= DN;
416     *lrloc |= DNRT;
417
418     *(lp->agebuf + (loc - lp->buffer)) = 0;
419 }
420
421
422 static void
423 life_kill(pwin, loc)
424     perwindow *pwin;
425     unsigned char *loc;
426 {
427     lifestruct *lp = (lifestruct *)pwin->data;
428
429     unsigned char *ulloc, *ucloc, *urloc, *clloc, *crloc, *llloc, *lcloc,
430                *lrloc, *arloc;
431     int         off, row, col, lastrow;
432
433     lastrow = (lp->nrows) * (lp->ncols + 2);
434     off = loc - lp->buffer;
435     row = off / (lp->ncols + 2);
436     col = off % (lp->ncols + 2);
437     row = (off - col) / (lp->ncols + 2);
438     ulloc = loc - lp->ncols - 3;
439     ucloc = loc - lp->ncols - 2;
440     urloc = loc - lp->ncols - 1;
441     clloc = loc - 1;
442     crloc = loc + 1;
443     arloc = loc + 1;
444     llloc = loc + lp->ncols + 1;
445     lcloc = loc + lp->ncols + 2;
446     lrloc = loc + lp->ncols + 3;
447     if (row == 1) {
448         ulloc += lastrow;
449         ucloc += lastrow;
450         urloc += lastrow;
451     }
452     if (row == lp->nrows) {
453         llloc -= lastrow;
454         lcloc -= lastrow;
455         lrloc -= lastrow;
456     }
457     if (col == 1) {
458         ulloc += lp->ncols;
459         clloc += lp->ncols;
460         llloc += lp->ncols;
461     }
462     if (col == lp->ncols) {
463         urloc -= lp->ncols;
464         crloc -= lp->ncols;
465         lrloc -= lp->ncols;
466     }
467     *ulloc &= ~UPLT;
468     *ucloc &= ~UP;
469     *urloc &= ~UPRT;
470     *clloc &= ~LT;
471     *crloc &= ~RT;
472     *arloc &= ~RT;
473     *llloc &= ~DNLT;
474     *lcloc &= ~DN;
475     *lrloc &= ~DNRT;
476 }
477
478
479 static void
480 setcell(pwin, row, col)
481     perwindow *pwin;
482     int         row;
483     int         col;
484 {
485     lifestruct *lp = (lifestruct *)pwin->data;
486     unsigned char *loc;
487
488     loc = lp->buffer + ((row + 1) * (lp->ncols + 2)) + col + 1;
489     spawn(pwin, loc);
490     drawcell(pwin, row, col);
491 }
492
493
494 static void
495 init_fates()
496 {
497     int         i, bits, neighbors;
498
499     for (i = 0; i < 256; i++) {
500         neighbors = 0;
501         for (bits = i; bits; bits &= (bits - 1))
502             neighbors++;
503         if (neighbors == 3)
504             fates[i] = BIRTH;
505         else if (neighbors == 2)
506             fates[i] = SAME;
507         else
508             fates[i] = DEATH;
509     }
510 }
511
512
513 void
514 initlife(pwin)
515     perwindow *pwin;
516 {
517     int         row, col;
518     int        *patptr;
519     XWindowAttributes xgwa;
520     lifestruct *lp;
521
522     if (pwin->data) free(pwin->data);
523     pwin->data = (void *)malloc(sizeof(lifestruct));
524     memset(pwin->data, '\0', sizeof(lifestruct));
525     lp = (lifestruct *)pwin->data;
526     lp->generation = 0;
527     lp->shooterTime = seconds();
528     icon_width = lifeicon_width;
529     icon_height = lifeicon_height;
530
531     if (!initialized) {
532         initialized = 1;
533         init_fates();
534         logo.data = (char *) lifeicon_bits;
535         logo.width = icon_width;
536         logo.height = icon_height;
537         logo.bytes_per_line = (icon_width + 7) / 8;
538     }
539     XGetWindowAttributes(dsp, pwin->w, &xgwa);
540     lp->width = xgwa.width;
541     lp->height = xgwa.height;
542     lp->pixelmode = (lp->width < 4 * icon_width);
543     if (lp->pixelmode) {
544         lp->ncols = 32;
545         lp->nrows = 32;
546     } else {
547         lp->ncols = min(lp->width / icon_width, MAXCOLS);
548         lp->nrows = min(lp->height / icon_height, MAXROWS);
549     }
550 /* For the dtstyle preview screen, the rows and columns can 
551  * be less than 32 regardless of the pixelmode calculation.
552  * This can cause the row/column calculations below to go 
553  * negative, which causes very bad things to happen. Until we
554  * get an official fix, this will keep life from core dumping.
555  */
556     if ((lp->ncols < 32) || (lp->nrows < 32)) {
557         lp->pixelmode = 1;
558         lp->ncols = 32;
559         lp->nrows = 32;
560     }
561     lp->xs = lp->width / lp->ncols;
562     lp->ys = lp->height / lp->nrows;
563     lp->xb = (lp->width - lp->xs * lp->ncols) / 2;
564     lp->yb = (lp->height - lp->ys * lp->nrows) / 2;
565
566     XSetForeground(dsp, pwin->gc, BlackPixelOfScreen(pwin->perscreen->screen));
567     XFillRectangle(dsp, pwin->w, pwin->gc, 0, 0, lp->width, lp->height);
568
569     memset(lp->buffer, '\0', sizeof(lp->buffer));
570     patptr = (int *)&patterns[random() % NPATS][0];
571     while ((col = *patptr++) != 99) {
572         row = *patptr++;
573         col += lp->ncols / 2;
574         row += lp->nrows / 2;
575         if ((row >= 0) && (row < lp->nrows) && (col >= 0) && (col < lp->ncols))
576             setcell(pwin, row, col);
577     }
578 }
579
580
581 void
582 drawlife(pwin)
583     perwindow *pwin;
584 {
585     unsigned char *loc, *temploc, *lastloc;
586     int         row, col;
587     unsigned char fate;
588     lifestruct *lp = (lifestruct *)pwin->data;
589
590     loc = lp->buffer + lp->ncols + 2 + 1;
591     temploc = lp->tempbuf;
592     /* copy the first 2 rows to the tempbuf */
593     memcpy(temploc, loc, lp->ncols);
594     memcpy(temploc + lp->ncols, loc + lp->ncols + 2, lp->ncols);
595
596     lastloc = lp->lastbuf;
597     /* copy the last row to another buffer for wraparound */
598     memcpy(lastloc, loc + ((lp->nrows - 1) * (lp->ncols + 2)), lp->ncols);
599
600     for (row = 0; row < lp->nrows; ++row) {
601         for (col = 0; col < lp->ncols; ++col) {
602             fate = fates[*temploc];
603             *temploc = (row == (lp->nrows - 3)) ?
604                 *(lastloc + col) :
605                 *(loc + (lp->ncols + 2) * 2);
606             switch (fate) {
607             case BIRTH:
608                 if (!(*(loc + 1) & RT)) {
609                     spawn(pwin, loc);
610                 }
611                 /* NO BREAK */
612             case SAME:
613                 if (*(loc + 1) & RT) {
614                     drawcell(pwin, row, col);
615                 }
616                 break;
617             case DEATH:
618                 if (*(loc + 1) & RT) {
619                     life_kill(pwin, loc);
620                     erasecell(pwin, row, col);
621                 }
622                 break;
623             }
624             loc++;
625             temploc++;
626         }
627         loc += 2;
628         if (temploc >= lp->tempbuf + lp->ncols * 2)
629             temploc = lp->tempbuf;
630     }
631
632     if (++lp->generation > batchcount)
633         initlife(pwin);
634
635     /*
636      * generate a randomized shooter aimed roughly toward the center of the
637      * screen after timeout.
638      */
639
640     if (seconds() - lp->shooterTime > TIMEOUT) {
641         int         hsp = random() % (lp->ncols - 5) + 3;
642         int         vsp = random() % (lp->nrows - 5) + 3;
643         int         hoff = 1;
644         int         voff = 1;
645         if (vsp > lp->nrows / 2)
646             voff = -1;
647         if (hsp > lp->ncols / 2)
648             hoff = -1;
649         setcell(pwin, vsp + 0 * voff, hsp + 2 * hoff);
650         setcell(pwin, vsp + 1 * voff, hsp + 2 * hoff);
651         setcell(pwin, vsp + 2 * voff, hsp + 2 * hoff);
652         setcell(pwin, vsp + 2 * voff, hsp + 1 * hoff);
653         setcell(pwin, vsp + 1 * voff, hsp + 0 * hoff);
654         lp->shooterTime = seconds();
655     }
656 }