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