1 /* -*- Mode: C; tab-width: 4 -*- */
2 /* pyro --- fireworks */
3
4 #if 0
5 static const char sccsid[] = "@(#)pyro.c 5.00 2000/11/01 xlockmore";
6 #endif
7
8 /*-
9 * Copyright (c) 1991 by Patrick J. Naughton.
10 *
11 * Permission to use, copy, modify, and distribute this software and its
12 * documentation for any purpose and without fee is hereby granted,
13 * provided that the above copyright notice appear in all copies and that
14 * both that copyright notice and this permission notice appear in
15 * supporting documentation.
16 *
17 * This file is provided AS IS with no warranties of any kind. The author
18 * shall have no liability with respect to the infringement of copyrights,
19 * trade secrets or any patents by this file or any part thereof. In no
20 * event will the author be liable for any lost revenue or profits or
21 * other special, indirect and consequential damages.
22 *
23 * Revision History:
24 * 01-Nov-2000: Allocation checks
25 * 15-May-1997: jwz AT jwz.org: turned into a standalone program.
26 * 05-Sep-1996: Added 3d support Henrik Theiling <theiling@coli.uni-sb.de>
27 * 16-Mar-1991: Written, received from David Brooks <brooks@osf.org>
28 */
29
30 /*-
31 * The physics of the rockets is a little bogus, but it looks OK. Each is
32 * given an initial velocity impetus. They decelerate slightly (gravity
33 * overcomes the rocket's impulse) and explode as the rocket's main fuse
34 * gives out (we could add a ballistic stage, maybe). The individual
35 * stars fan out from the rocket, and they decelerate less quickly.
36 * That's called buoyancy, but really it's again a visual preference.
37 */
38
39 #ifdef STANDALONE
40 #define MODE_pyro
41 #define DEFAULTS "*delay: 15000 \n" \
42 "*count: 100 \n" \
43 "*size: -3 \n" \
44 "*ncolors: 200 \n" \
45 "*use3d: False \n" \
46 "*delta3d: 1.5 \n" \
47 "*right3d: red \n" \
48 "*left3d: blue \n" \
49 "*both3d: magenta \n" \
50 "*none3d: black \n" \
51
52 # define free_pyro 0
53 # define reshape_pyro 0
54 # define pyro_handle_event 0
55 # define UNIFORM_COLORS
56 # include "xlockmore.h" /* in xscreensaver distribution */
57 #else /* STANDALONE */
58 # include "xlock.h" /* in xlockmore distribution */
59 #endif /* STANDALONE */
60
61 #ifdef MODE_pyro
62
63 ENTRYPOINT ModeSpecOpt pyro_opts =
64 {0, (XrmOptionDescRec *) NULL, 0, (argtype *) NULL, (OptionStruct *) NULL};
65
66 #ifdef USE_MODULES
67 ModStruct pyro_description =
68 {"pyro", "init_pyro", "draw_pyro", "release_pyro",
69 "refresh_pyro", "init_pyro", (char *) NULL, &pyro_opts,
70 15000, 100, 1, -3, 64, 1.0, "",
71 "Shows fireworks", 0, NULL};
72
73 #endif
74
75 #define ORANGE (5 * MI_NPIXELS(mi) / 64)
76
77 #define MINROCKETS 1
78 #define MINSIZE 1
79
80 #define SILENT 0
81 #define REDGLARE 1
82 #define BURSTINGINAIR 2
83
84 #define CLOUD 0
85 #define DOUBLECLOUD 1
86 #define COLORCLOUD 2
87 /* Clearly other types and other fascinating visual effects could be added... */
88
89 /* P_xxx parameters represent the reciprocal of the probability... */
90 #define P_IGNITE 5000 /* ...of ignition per cycle */
91 #define P_DOUBLECLOUD 10 /* ...of an ignition being double */
92 #define P_COLORCLOUD 5 /* ...of an ignition being full color */
93 #define P_MULTI 75 /* ...of an ignition being several @ once */
94 #define P_FUSILLADE 250 /* ...of an ignition starting a fusillade */
95
96 #define ROCKETW 2 /* Dimensions of rocket */
97 #define ROCKETH 4
98 #define XVELFACTOR 0.0025 /* Max horizontal velocity / screen width */
99 #define ZVELFACTOR 0.0025
100 #define MINZVAL 250 /* absolute minimum of z values */
101 #define MINZVALSTART 300 /* range where they start */
102 #define MAXZVALSTART 1000
103 #define SCREENZ 400
104 /* the z-component still gets too small sometimes */
105 #define GETZDIFFAUX(z) (MI_DELTA3D(mi)*20.0*(1.0-(SCREENZ)/(z)))
106 #define GETZDIFF(z) ((z)<MINZVAL?GETZDIFFAUX(MINZVAL):GETZDIFFAUX(z))
107 #define MINYVELFACTOR 0.016 /* Min vertical velocity / screen height */
108 #define MAXYVELFACTOR 0.018
109 #define GRAVFACTOR 0.0002 /* delta v / screen height */
110 #define MINFUSE 50 /* range of fuse lengths for rocket */
111 #define MAXFUSE 100
112
113 #define FUSILFACTOR 10 /* Generate fusillade by reducing P_IGNITE */
114 #define FUSILLEN 100 /* Length of fusillade, in ignitions */
115
116 #define SVELFACTOR 0.1 /* Max star velocity / yvel */
117 #define BUOYANCY 0.2 /* Reduction in grav deceleration for stars */
118 #define MAXSTARS 150 /* Number of stars issued from a shell */
119 #define MINSTARS 50
120 #define MINSFUSE 50 /* Range of fuse lengths for stars */
121 #define MAXSFUSE 100
122
123 #define INTRAND(min,max) (NRAND((max+1)-(min))+(min))
124 #define FLOATRAND(min,max) ((min)+((double) LRAND()/((double) MAXRAND))*((max)-(min)))
125 #define INCZ(val,add) if((val)+(add)>MINZVAL) val+=(add)
126 #define ADDZ(val,add) (((val)+(add)>MINZVAL)?(val)+(add):(val))
127 #define TWOPI (2.0*M_PI)
128
129 typedef struct {
130 unsigned long color;
131 float sx, sy, sz; /* Distance from notional center */
132 float sxvel, syvel, szvel; /* Relative to notional center */
133 } star;
134
135 typedef struct {
136 int state;
137 int shelltype;
138 int fuse;
139 float xvel, yvel, zvel;
140 float x, y, z;
141 unsigned long color[2];
142 int nstars;
143 XRectangle Xpoints[2][MAXSTARS];
144 XRectangle Xpointsleft[2][MAXSTARS];
145 star stars[MAXSTARS];
146 } rocket;
147
148 typedef struct {
149 int p_ignite;
150 unsigned long rockpixel;
151 int nflying, nrockets;
152 int fusilcount;
153 int width, height;
154 int lmargin, rmargin;
155 int star_size;
156 float minvelx, maxvelx;
157 float minvely, maxvely;
158 float minvelz, maxvelz;
159 float maxsvel;
160 float rockdecel, stardecel;
161 rocket *rockq;
162 } pyrostruct;
163
164 static void shootup(ModeInfo * mi, pyrostruct * pp, rocket * rp);
165 static void burst(ModeInfo * mi, pyrostruct * pp, rocket * rp);
166
167 static pyrostruct *pyros = (pyrostruct *) NULL;
168 static int orig_p_ignite;
169 static int just_started = True; /* Greet the user right away */
170
171 static void
ignite(ModeInfo * mi,pyrostruct * pp)172 ignite(ModeInfo * mi, pyrostruct * pp)
173 {
174 rocket *rp;
175 int multi, shelltype, nstars, fuse, pix;
176 unsigned long color[2];
177 float xvel, yvel, x, zvel = 0.0, z = 0.0;
178
179 x = NRAND(pp->width);
180 xvel = FLOATRAND(-pp->maxvelx, pp->maxvelx);
181 /* All this to stop too many rockets going offscreen: */
182 if ((x < pp->lmargin && xvel < 0.0) || (x > pp->rmargin && xvel > 0.0))
183 xvel = -xvel;
184 yvel = FLOATRAND(pp->minvely, pp->maxvely);
185 if (MI_IS_USE3D(mi)) {
186 z = FLOATRAND(MINZVALSTART, MAXZVALSTART);
187 zvel = FLOATRAND(pp->minvelz, pp->maxvelz);
188 }
189 fuse = INTRAND(MINFUSE, MAXFUSE);
190 nstars = INTRAND(MINSTARS, MAXSTARS);
191 if (MI_NPIXELS(mi) > 2) {
192 pix = NRAND(MI_NPIXELS(mi));
193 color[0] = MI_PIXEL(mi, pix);
194 color[1] = MI_PIXEL(mi,
195 ((pix + (MI_NPIXELS(mi) / 2)) % MI_NPIXELS(mi)));
196 } else {
197 color[0] = color[1] = MI_WHITE_PIXEL(mi);
198 }
199
200 multi = 1;
201 if (NRAND(P_DOUBLECLOUD) == 0)
202 shelltype = DOUBLECLOUD;
203 else {
204 shelltype = CLOUD;
205 if (NRAND(P_MULTI) == 0)
206 multi = INTRAND(5, 15);
207 }
208 if (NRAND(P_COLORCLOUD) == 0)
209 shelltype |= COLORCLOUD;
210
211 rp = pp->rockq;
212 while (multi--) {
213 if (pp->nflying >= pp->nrockets)
214 return;
215 while (rp->state != SILENT)
216 rp++;
217 pp->nflying++;
218 rp->shelltype = shelltype;
219 rp->state = REDGLARE;
220 rp->color[0] = color[0];
221 rp->color[1] = color[1];
222 rp->xvel = xvel;
223 rp->yvel = FLOATRAND(yvel * 0.97, yvel * 1.03);
224 rp->fuse = INTRAND((fuse * 90) / 100, (fuse * 110) / 100);
225 rp->x = x + FLOATRAND(multi * 7.6, multi * 8.4);
226 rp->y = pp->height - 1;
227 if (MI_IS_USE3D(mi)) {
228 rp->zvel = FLOATRAND(zvel * 0.97, zvel * 1.03);
229 rp->z = z;
230 }
231 rp->nstars = nstars;
232 }
233 }
234
235 static void
animate(ModeInfo * mi,pyrostruct * pp,rocket * rp)236 animate(ModeInfo * mi, pyrostruct * pp, rocket * rp)
237 {
238 int starn, diff;
239 float r, theta;
240
241 if (rp->state == REDGLARE) {
242 shootup(mi, pp, rp);
243
244 /* Handle setup for explosion */
245 if (rp->state == BURSTINGINAIR) {
246 for (starn = 0; starn < rp->nstars; starn++) {
247 rp->stars[starn].sx = rp->stars[starn].sy = 0.0;
248 if (MI_IS_USE3D(mi)) {
249 rp->stars[starn].sz = 0.0;
250 diff = (int) GETZDIFF(rp->z);
251 rp->Xpoints[0][starn].x = (int) rp->x + diff;
252 rp->Xpointsleft[0][starn].x = (int) rp->x - diff;
253 rp->Xpoints[0][starn].y =
254 rp->Xpointsleft[0][starn].y = (int) rp->y;
255 if (rp->shelltype & DOUBLECLOUD) {
256 rp->Xpoints[1][starn].x = (int) rp->x + diff;
257 rp->Xpointsleft[1][starn].x = (int) rp->x - diff;
258 rp->Xpoints[1][starn].y =
259 rp->Xpointsleft[1][starn].y = (int) rp->y;
260 }
261 /* this isn't really a 3d direction. it's */
262 /* very much the same as in worm. */
263 r = FLOATRAND(0.0, pp->maxsvel);
264 theta = FLOATRAND(0.0, TWOPI);
265 rp->stars[starn].sxvel = r * COSF(theta);
266 rp->stars[starn].syvel = r * SINF(theta);
267 theta = FLOATRAND(0.0, TWOPI);
268 rp->stars[starn].szvel = FLOATRAND(0.0, pp->maxsvel) * SINF(theta);
269 } else {
270 rp->Xpoints[0][starn].x = (int) rp->x;
271 rp->Xpoints[0][starn].y = (int) rp->y;
272 if ((rp->shelltype & COLORCLOUD) && (MI_NPIXELS(mi) > 2)) {
273 if (NRAND(6) < 1)
274 rp->stars[starn].color = MI_WHITE_PIXEL(mi);
275 else
276 rp->stars[starn].color = MI_PIXEL(mi, NRAND(MI_NPIXELS(mi)));
277 }
278 if (rp->shelltype & DOUBLECLOUD) {
279 rp->Xpoints[1][starn].x = (int) rp->x;
280 rp->Xpoints[1][starn].y = (int) rp->y;
281 }
282 r = FLOATRAND(0.0, pp->maxsvel);
283 theta = FLOATRAND(0.0, TWOPI);
284 rp->stars[starn].sxvel = r * COSF(theta);
285 rp->stars[starn].syvel = r * SINF(theta);
286 }
287 /* This isn't accurate solid geometry, but it looks OK. */
288 }
289 rp->fuse = INTRAND(MINSFUSE, MAXSFUSE);
290 }
291 }
292 if (rp->state == BURSTINGINAIR) {
293 burst(mi, pp, rp);
294 }
295 }
296
297 static void
shootup(ModeInfo * mi,pyrostruct * pp,rocket * rp)298 shootup(ModeInfo * mi, pyrostruct * pp, rocket * rp)
299 {
300 Display *display = MI_DISPLAY(mi);
301 Window window = MI_WINDOW(mi);
302 GC gc = MI_GC(mi);
303 int diff, h;
304
305 if (MI_IS_INSTALL(mi) && MI_IS_USE3D(mi))
306 XSetForeground(display, gc, MI_NONE_COLOR(mi));
307 else
308 XSetForeground(display, gc, MI_BLACK_PIXEL(mi));
309 if (MI_IS_USE3D(mi)) {
310 diff = (int) GETZDIFF(rp->z);
311 XFillRectangle(display, window, gc, (int) (rp->x) + diff, (int) (rp->y),
312 ROCKETW, ROCKETH + 3);
313 XFillRectangle(display, window, gc, (int) (rp->x) - diff, (int) (rp->y),
314 ROCKETW, ROCKETH + 3);
315 } else
316 XFillRectangle(display, window, gc, (int) (rp->x), (int) (rp->y),
317 ROCKETW, ROCKETH + 3);
318
319 if (rp->fuse-- <= 0) {
320 rp->state = BURSTINGINAIR;
321 return;
322 }
323 rp->x += rp->xvel;
324 rp->y += rp->yvel;
325 rp->yvel += pp->rockdecel;
326 if (MI_IS_USE3D(mi)) {
327 INCZ(rp->z, rp->zvel);
328 diff = (int) GETZDIFF(rp->z);
329 h = (int) (ROCKETH + NRAND(4));
330 if (MI_IS_INSTALL(mi))
331 XSetFunction(display, gc, GXor);
332 XSetForeground(display, gc, MI_RIGHT_COLOR(mi));
333 XFillRectangle(display, window, gc, (int) (rp->x) + diff, (int) (rp->y),
334 ROCKETW, h);
335 XSetForeground(display, gc, MI_LEFT_COLOR(mi));
336 XFillRectangle(display, window, gc, (int) (rp->x) - diff, (int) (rp->y),
337 ROCKETW, h);
338 if (MI_IS_INSTALL(mi))
339 XSetFunction(display, gc, GXcopy);
340 } else {
341 XSetForeground(display, gc, pp->rockpixel);
342 XFillRectangle(display, window, gc, (int) (rp->x), (int) (rp->y),
343 ROCKETW, (int) (ROCKETH + NRAND(4)));
344 }
345 }
346
347 static void
burst(ModeInfo * mi,pyrostruct * pp,rocket * rp)348 burst(ModeInfo * mi, pyrostruct * pp, rocket * rp)
349 {
350 Display *display = MI_DISPLAY(mi);
351 Window window = MI_WINDOW(mi);
352 GC gc = MI_GC(mi);
353 register int starn;
354 register int nstars, stype;
355 register float rx, ry, rz = 0.0, sd; /* Help compiler optimize :-) */
356 register float sx, sy, sz;
357 int diff;
358
359 nstars = rp->nstars;
360 stype = rp->shelltype;
361 if (MI_IS_INSTALL(mi) && MI_IS_USE3D(mi))
362 XSetForeground(display, gc, MI_NONE_COLOR(mi));
363 else
364 XSetForeground(display, gc, MI_BLACK_PIXEL(mi));
365
366 XFillRectangles(display, window, gc, rp->Xpoints[0], nstars);
367 if (stype & DOUBLECLOUD)
368 XFillRectangles(display, window, gc, rp->Xpoints[1], nstars);
369 if (MI_IS_USE3D(mi)) {
370 XFillRectangles(display, window, gc, rp->Xpointsleft[0], nstars);
371 if (stype & DOUBLECLOUD)
372 XFillRectangles(display, window, gc, rp->Xpointsleft[1], nstars);
373 }
374 if (rp->fuse-- <= 0) {
375 rp->state = SILENT;
376 pp->nflying--;
377 return;
378 }
379 /* Stagger the stars' decay */
380 if (rp->fuse <= 7) {
381 if ((rp->nstars = nstars = nstars * 90 / 100) == 0)
382 return;
383 }
384 rx = rp->x;
385 ry = rp->y;
386 if (MI_IS_USE3D(mi)) {
387 rz = rp->z;
388 }
389 sd = pp->stardecel;
390 for (starn = 0; starn < nstars; starn++) {
391 sx = rp->stars[starn].sx += rp->stars[starn].sxvel;
392 sy = rp->stars[starn].sy += rp->stars[starn].syvel;
393 rp->stars[starn].syvel += sd;
394 if (MI_IS_USE3D(mi)) {
395 if (rz + rp->stars[starn].sz + rp->stars[starn].szvel > MINZVAL)
396 rp->stars[starn].sz += rp->stars[starn].szvel;
397 sz = rp->stars[starn].sz;
398 diff = (int) GETZDIFF(rz + sz);
399 rp->Xpoints[0][starn].x = (int) (rx + sx + diff);
400 rp->Xpointsleft[0][starn].x = (int) (rx + sx - diff);
401 rp->Xpoints[0][starn].y =
402 rp->Xpointsleft[0][starn].y = (int) (ry + sy);
403 if (stype & DOUBLECLOUD) {
404 rp->Xpoints[1][starn].x = (int) (rx + 1.7 * sx) + diff;
405 rp->Xpointsleft[1][starn].x = (int) (rx + 1.7 * sx) - diff;
406 rp->Xpoints[1][starn].y =
407 rp->Xpointsleft[1][starn].y = (int) (ry + 1.7 * sy);
408 }
409 } else {
410
411 rp->Xpoints[0][starn].x = (int) (rx + sx);
412 rp->Xpoints[0][starn].y = (int) (ry + sy);
413 if (stype & DOUBLECLOUD) {
414 rp->Xpoints[1][starn].x = (int) (rx + 1.7 * sx);
415 rp->Xpoints[1][starn].y = (int) (ry + 1.7 * sy);
416 }
417 }
418 }
419 rp->x = rx + rp->xvel;
420 rp->y = ry + rp->yvel;
421 if (MI_IS_USE3D(mi)) {
422 rp->z = ADDZ(rz, rp->zvel);
423 }
424 rp->yvel += sd;
425
426 if (MI_IS_USE3D(mi)) {
427 if (MI_IS_INSTALL(mi))
428 XSetFunction(display, gc, GXor);
429 XSetForeground(display, gc, MI_RIGHT_COLOR(mi));
430 XFillRectangles(display, window, gc, rp->Xpoints[0], nstars);
431 if (stype & DOUBLECLOUD) {
432 XFillRectangles(display, window, gc, rp->Xpoints[1], nstars);
433 }
434 XSetForeground(display, gc, MI_LEFT_COLOR(mi));
435 XFillRectangles(display, window, gc, rp->Xpointsleft[0], nstars);
436 if (stype & DOUBLECLOUD) {
437 XFillRectangles(display, window, gc, rp->Xpointsleft[1], nstars);
438 }
439 if (MI_IS_INSTALL(mi))
440 XSetFunction(display, gc, GXcopy);
441 } else {
442
443 if ((stype & COLORCLOUD) && (MI_NPIXELS(mi) > 2)) {
444 for (starn = 0; starn < nstars; starn++) {
445 XSetForeground(display, gc, rp->stars[starn].color);
446 XFillRectangle(display, window, gc,
447 rp->Xpoints[0][starn].x, rp->Xpoints[0][starn].y,
448 rp->Xpoints[0][starn].width, rp->Xpoints[0][starn].height);
449 }
450 } else {
451 XSetForeground(display, gc, rp->color[0]);
452 XFillRectangles(display, window, gc, rp->Xpoints[0], nstars);
453 }
454 if (stype & DOUBLECLOUD) {
455 XSetForeground(display, gc, rp->color[1]);
456 XFillRectangles(display, window, gc, rp->Xpoints[1], nstars);
457 }
458 }
459 }
460
461 static void
free_pyro_screen(pyrostruct * pp)462 free_pyro_screen(pyrostruct * pp)
463 {
464 if (pp == NULL) {
465 return;
466 }
467 if (pp->rockq != NULL) {
468 free(pp->rockq);
469 }
470 pp = NULL;
471 }
472
473 ENTRYPOINT void
init_pyro(ModeInfo * mi)474 init_pyro(ModeInfo * mi)
475 {
476 int rockn, starn;
477 int size = MI_SIZE(mi);
478 rocket *rp;
479 pyrostruct *pp;
480
481 MI_INIT(mi, pyros);
482 pp = &pyros[MI_SCREEN(mi)];
483
484 pp->width = MI_WIDTH(mi);
485 pp->height = MI_HEIGHT(mi);
486 pp->lmargin = pp->width / 16;
487 pp->rmargin = pp->width - pp->lmargin;
488
489 pp->nrockets = MI_COUNT(mi);
490 if (pp->nrockets < -MINROCKETS) {
491 if (pp->rockq) {
492 free(pp->rockq);
493 pp->rockq = (rocket *) NULL;
494 }
495 pp->nrockets = NRAND(-pp->nrockets - MINROCKETS + 1) + MINROCKETS;
496 } else if (pp->nrockets < MINROCKETS)
497 pp->nrockets = MINROCKETS;
498 if (size < -MINSIZE)
499 pp->star_size = NRAND(MIN(-size, MAX(MINSIZE,
500 MIN(pp->width, pp->height) / 64)) - MINSIZE + 1) + MINSIZE;
501 else if (size < MINSIZE) {
502 if (!size)
503 pp->star_size = MAX(MINSIZE, MIN(pp->width, pp->height) / 64);
504 else
505 pp->star_size = MINSIZE;
506 } else
507 pp->star_size = MIN(size, MAX(MINSIZE, MIN(pp->width, pp->height) / 64));
508 orig_p_ignite = P_IGNITE / pp->nrockets;
509 if (orig_p_ignite <= 0)
510 orig_p_ignite = 1;
511 pp->p_ignite = orig_p_ignite;
512
513 if (!pp->rockq) {
514 if ((pp->rockq = (rocket *) malloc(pp->nrockets *
515 sizeof (rocket))) == NULL) {
516 return;
517 }
518 }
519 pp->nflying = pp->fusilcount = 0;
520
521 for (rockn = 0, rp = pp->rockq; rockn < pp->nrockets; rockn++, rp++) {
522 rp->state = SILENT;
523 for (starn = 0; starn < MAXSTARS; starn++) {
524 rp->Xpoints[0][starn].width = rp->Xpoints[0][starn].height =
525 rp->Xpoints[1][starn].width = rp->Xpoints[1][starn].height =
526 pp->star_size;
527 if (MI_IS_USE3D(mi)) {
528 rp->Xpointsleft[0][starn].width = rp->Xpointsleft[0][starn].height =
529 rp->Xpointsleft[1][starn].width = rp->Xpointsleft[1][starn].height =
530 pp->star_size;
531 }
532 }
533 }
534
535 if (MI_NPIXELS(mi) > 3)
536 pp->rockpixel = MI_PIXEL(mi, ORANGE);
537 else
538 pp->rockpixel = MI_WHITE_PIXEL(mi);
539
540 /* Geometry-dependent physical data: */
541 pp->maxvelx = (float) (pp->width) * XVELFACTOR;
542 pp->minvelx = -pp->maxvelx;
543 pp->minvely = -(float) (pp->height) * MINYVELFACTOR;
544 pp->maxvely = -(float) (pp->height) * MAXYVELFACTOR;
545 if (MI_IS_USE3D(mi)) {
546 pp->maxvelz = (float) (MAXZVALSTART - MINZVALSTART) * ZVELFACTOR;
547 pp->minvelz = -pp->maxvelz;
548 }
549 pp->maxsvel = pp->minvely * SVELFACTOR;
550 pp->rockdecel = (float) (pp->height) * GRAVFACTOR;
551 pp->stardecel = pp->rockdecel * BUOYANCY;
552 if (MI_IS_INSTALL(mi) && MI_IS_USE3D(mi)) {
553 MI_CLEARWINDOWCOLOR(mi, MI_NONE_COLOR(mi));
554 } else {
555 MI_CLEARWINDOW(mi);
556 }
557 }
558
559 /* ARGSUSED */
560 ENTRYPOINT void
draw_pyro(ModeInfo * mi)561 draw_pyro(ModeInfo * mi)
562 {
563 rocket *rp;
564 int rockn;
565 pyrostruct *pp;
566
567 if (pyros == NULL)
568 return;
569 pp = &pyros[MI_SCREEN(mi)];
570 if (pp->rockq == NULL)
571 return;
572
573 MI_IS_DRAWN(mi) = True;
574 if (just_started || (NRAND(pp->p_ignite) == 0)) {
575 just_started = False;
576 if (NRAND(P_FUSILLADE) == 0) {
577 pp->p_ignite = orig_p_ignite / FUSILFACTOR;
578 if (pp->p_ignite <= 0)
579 pp->p_ignite = 1;
580 pp->fusilcount = INTRAND(FUSILLEN * 9 / 10, FUSILLEN * 11 / 10);
581 }
582 ignite(mi, pp);
583 if (pp->fusilcount > 0) {
584 if (--pp->fusilcount == 0)
585 pp->p_ignite = orig_p_ignite;
586 }
587 }
588 for (rockn = pp->nflying, rp = pp->rockq; rockn > 0; rp++) {
589 if (rp->state != SILENT) {
590 animate(mi, pp, rp);
591 rockn--;
592 }
593 }
594 }
595
596 ENTRYPOINT void
release_pyro(ModeInfo * mi)597 release_pyro(ModeInfo * mi)
598 {
599 if (pyros != NULL) {
600 int screen;
601
602 for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++)
603 free_pyro_screen(&pyros[screen]);
604 free(pyros);
605 pyros = (pyrostruct *) NULL;
606 }
607 }
608
609 #ifndef STANDALONE
610 ENTRYPOINT void
refresh_pyro(ModeInfo * mi)611 refresh_pyro(ModeInfo * mi)
612 {
613 if (MI_IS_INSTALL(mi) && MI_IS_USE3D(mi)) {
614 MI_CLEARWINDOWCOLOR(mi, MI_NONE_COLOR(mi));
615 } else {
616 MI_CLEARWINDOW(mi);
617 }
618 }
619 #endif
620
621 XSCREENSAVER_MODULE ("Pyro", pyro)
622
623 #endif /* MODE_pyro */
624