http://www.jwz.org/xscreensaver/xscreensaver-5.10.tar.gz
[xscreensaver] / hacks / pacman.c
1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* pacman --- Mr. Pacman and his ghost friends */
3
4 #if !defined( lint ) && !defined( SABER )
5 static const char sccsid[] = "@(#)pacman.c      5.00 2000/11/01 xlockmore";
6
7 #endif
8
9 /*-
10  * Copyright (c) 2002 by Edwin de Jong <mauddib@gmx.net>.
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  * 25-Feb-2005: Added bonus dots. I am using a recursive back track algorithm
26  *              to help the ghost find there way home. This also means that
27  *              they do not know the shorts path.
28  *              Jeremy English jhe@jeremyenglish.org
29  * 15-Aug-2004: Added support for pixmap pacman. 
30  *              Jeremy English jhe@jeremyenglish.org
31  * 11-Aug-2004: Added support for pixmap ghost.
32  *              Jeremy English jhe@jeremyenglish.org
33  * 13-May-2002: Added -trackmouse feature thanks to code from 'maze.c'.  
34  *              splitted up code into several files.  Retouched AI code, cleaned
35  *              up code.
36  *  3-May-2002: Added AI to pacman and ghosts, slowed down ghosts.
37  * 26-Nov-2001: Random level generator added
38  * 01-Nov-2000: Allocation checks
39  * 04-Jun-1997: Compatible with xscreensaver
40  *
41  */
42
43 /* TODO:
44    1. think of a better level generation algorithm
45 */
46
47 #define DEF_TRACKMOUSE "False"
48
49 #ifdef STANDALONE
50 #       define MODE_pacman
51 #       define DEFAULTS "*delay:   10000 \n" \
52                                         "*size:    0     \n" \
53                                         "*ncolors: 6     \n" \
54                                         "*fpsTop: true   \n" \
55                                         "*fpsSolid: true \n" \
56
57 #       define UNIFORM_COLORS
58 #       define BRIGHT_COLORS
59 #   define reshape_pacman 0
60 #   define pacman_handle_event 0
61 #       include "xlockmore.h"   /* in xscreensaver distribution */
62 #   include <assert.h>
63 #else /* STANDALONE */
64 #       include "xlock.h"       /* in xlockmore distribution */
65 #endif /* STANDALONE */
66
67 #ifdef MODE_pacman
68
69 #include "pacman.h"
70 #include "pacman_ai.h"
71 #include "pacman_level.h"
72
73 #if defined(USE_PIXMAP) /* computed in pacman.h */
74 # include "images/pacman/ghost-u1.xpm"
75 # include "images/pacman/ghost-u2.xpm"
76 # include "images/pacman/ghost-r1.xpm"
77 # include "images/pacman/ghost-r2.xpm"
78 # include "images/pacman/ghost-l1.xpm"
79 # include "images/pacman/ghost-l2.xpm"
80 # include "images/pacman/ghost-d1.xpm"
81 # include "images/pacman/ghost-d2.xpm"
82 /* Used to clean up the dust left by wag. */
83 # include "images/pacman/ghost-mask.xpm"
84 # include "images/pacman/pacman-u1.xpm"
85 # include "images/pacman/pacman-u2.xpm"
86 # include "images/pacman/pacman-r1.xpm"
87 # include "images/pacman/pacman-r2.xpm"
88 # include "images/pacman/pacman-l1.xpm"
89 # include "images/pacman/pacman-l2.xpm"
90 # include "images/pacman/pacman-d1.xpm"
91 # include "images/pacman/pacman-d2.xpm"
92 # include "images/pacman/pacman-0.xpm"
93 # include "images/pacman/ghost-s1.xpm"
94 # include "images/pacman/ghost-s2.xpm"
95 # include "images/pacman/ghost-sf1.xpm"
96 # include "images/pacman/ghost-sf2.xpm"
97 # include "images/pacman/eyes-l.xpm"
98 # include "images/pacman/eyes-r.xpm"
99 # include "images/pacman/eyes-u.xpm"
100 # include "images/pacman/eyes-d.xpm"
101 # include "images/pacman/pacman-ds1.xpm"
102 # include "images/pacman/pacman-ds2.xpm"
103 # include "images/pacman/pacman-ds3.xpm"
104 # include "images/pacman/pacman-ds4.xpm"
105 # include "images/pacman/pacman-ds5.xpm"
106 # include "images/pacman/pacman-ds6.xpm"
107 # include "images/pacman/pacman-ds7.xpm"
108 # include "images/pacman/pacman-ds8.xpm"
109 #endif
110
111 static const struct
112 {
113     int dx, dy;
114 } dirvecs[DIRVECS] = { { -1, 0},
115                        {  0, 1},
116                        {  1, 0},
117                        {  0, -1}};
118
119 #ifdef DISABLE_INTERACTIVE
120 ENTRYPOINT ModeSpecOpt pacman_opts = {
121     0,
122     (XrmOptionDescRec *) NULL,
123     0,
124     (argtype *) NULL,
125     (OptionStruct *) NULL
126 };
127 #else
128 static XrmOptionDescRec opts[] = {
129     {"-trackmouse", ".pacman.trackmouse", XrmoptionNoArg, "on"},
130     {"+trackmouse", ".pacman.trackmouse", XrmoptionNoArg, "off"}
131 };
132
133 static argtype vars[] = {
134     {&trackmouse, "trackmouse", "TrackMouse", DEF_TRACKMOUSE, t_Bool}
135 };
136
137 static OptionStruct desc[] = {
138     {"-/+trackmouse", "turn on/off the tracking of the mouse"}
139 };
140
141 ENTRYPOINT ModeSpecOpt pacman_opts =
142     { sizeof opts / sizeof opts[0], opts, sizeof vars / sizeof vars[0], vars,
143 desc };
144 #endif
145
146 #ifdef USE_MODULES
147 ModStruct pacman_description = {
148     "pacman",                   /* *cmdline_arg; */
149     "init_pacman",              /* *init_name; */
150     "draw_pacman",              /* *callback_name; */
151     "release_pacman",           /* *release_name; */
152     "refresh_pacman",           /* *refresh_name; */
153     "change_pacman",            /* *change_name; */
154     (char *) NULL,              /* *unused_name; */
155     &pacman_opts,               /* *msopts */
156     10000, 4, 1, 0, 64, 1.0, "", "Shows Pacman(tm)", 0, NULL
157 };
158
159 #endif
160
161 Bool trackmouse;
162 pacmangamestruct *pacmangames = (pacmangamestruct *) NULL;
163
164 static void repopulate (ModeInfo * mi);
165 static void drawlevel (ModeInfo * mi);
166
167
168 static void
169 free_pacman (Display * display, pacmangamestruct * pp)
170 {
171     int dir, mouth, i, j, k;
172
173     if (pp->ghosts != NULL) {
174         free (pp->ghosts);
175         pp->ghosts = (ghoststruct *) NULL;
176     }
177     if (pp->stippledGC != None) {
178         XFreeGC (display, pp->stippledGC);
179         pp->stippledGC = None;
180     }
181     for (i = 0; i < 4; i++) {
182         for (j = 0; j < MAXGDIR; j++) {
183             for (k = 0; k < MAXGWAG; k++) {
184                 if (pp->ghostPixmap[i][j][k] != None) {
185                     XFreePixmap (display, pp->ghostPixmap[i][j][k]);
186                     pp->ghostPixmap[i][j][k] = None;
187                 }
188             }
189         }
190     }
191     for (dir = 0; dir < 4; dir++)
192         for (mouth = 0; mouth < MAXMOUTH; mouth++)
193             if (pp->pacmanPixmap[dir][mouth] != None) {
194                 XFreePixmap (display, pp->pacmanPixmap[dir][mouth]);
195                 pp->pacmanPixmap[dir][mouth] = None;
196             }
197 }
198
199 /* set pacman and the ghost in there starting positions, but don't draw a new
200  level */
201 static void
202 reset_level (ModeInfo * mi, int n, int pac_init)
203 {
204     pacmangamestruct *pp = &pacmangames[MI_SCREEN (mi)];
205     unsigned int ghost;
206
207     MI_CLEARWINDOW (mi);
208     drawlevel (mi);
209
210     pp->gamestate = GHOST_DANGER;
211
212     if ( pac_init ){
213         pp->pacman.row = (LEVHEIGHT + JAILHEIGHT) / 2 - n;
214         pp->pacman.init_row = pp->pacman.row;
215     }
216     else{
217         pp->pacman.row = pp->pacman.init_row;
218     }
219     pp->pacman.col = (LEVWIDTH / 2);
220     pp->pacman.nextrow = NOWHERE;
221     pp->pacman.nextcol = NOWHERE;
222     pp->pacman.cf = NOWHERE;
223     pp->pacman.rf = NOWHERE;
224     pp->pacman.oldcf = NOWHERE;
225     pp->pacman.oldrf = NOWHERE;
226     pp->pacman.oldlx = NOWHERE;
227     pp->pacman.oldly = NOWHERE;
228     pp->pacman.aistate = ps_eating;
229     pp->pacman.cur_trace = 0;
230     pp->pacman.roundscore = 0;
231     pp->pacman.speed = 4;
232     pp->pacman.lastturn = 0;
233     pp->pacman.delta.x = 0;
234     pp->pacman.delta.y = 0;
235
236     for (ghost = 0; ghost < pp->nghosts; ghost++) {
237         pp->ghosts[ghost].col = (LEVWIDTH / 2);
238         pp->ghosts[ghost].row = (LEVHEIGHT / 2);
239         pp->ghosts[ghost].nextcol = NOWHERE;
240         pp->ghosts[ghost].nextrow = NOWHERE;
241         pp->ghosts[ghost].dead = 0;
242         pp->ghosts[ghost].lastbox = START;
243         pp->ghosts[ghost].cf = NOWHERE;
244         pp->ghosts[ghost].rf = NOWHERE;
245         pp->ghosts[ghost].oldcf = NOWHERE;
246         pp->ghosts[ghost].oldrf = NOWHERE;
247         pp->ghosts[ghost].aistate = inbox;
248         pp->ghosts[ghost].timeleft = ghost * 20;
249         pp->ghosts[ghost].speed = 3;
250         pp->ghosts[ghost].delta.x = 0;
251         pp->ghosts[ghost].delta.y = 0;
252         pp->ghosts[ghost].flash_scared = False;
253         pp->ghosts[ghost].wait_pos = False;
254         ghost_update (pp, &(pp->ghosts[ghost]));
255     }
256     pac_update (mi, pp, &(pp->pacman));
257 }
258
259 static int
260 pacman_ghost_collision(unsigned int ghost, pacmangamestruct * pp)
261 {
262     return (((pp->ghosts[ghost].nextrow == pp->pacman.nextrow) &&
263              (pp->ghosts[ghost].nextcol == pp->pacman.nextcol)) ||
264             ((pp->ghosts[ghost].nextrow == pp->pacman.row) &&
265              (pp->ghosts[ghost].nextcol == pp->pacman.col) &&
266              (pp->ghosts[ghost].row == pp->pacman.nextrow) &&
267              (pp->ghosts[ghost].col == pp->pacman.nextcol)));
268 }
269
270
271 /* Checks for death of any ghosts/pacman and updates.  It also makes a new
272    level if all ghosts are dead or all dots are eaten. */
273 static void
274 check_death (ModeInfo * mi, pacmangamestruct * pp)
275 {
276     Display *display = MI_DISPLAY (mi);
277     Window window = MI_WINDOW (mi);
278     unsigned int ghost;
279     int alldead;
280
281     if (pp->pacman.aistate == ps_dieing) return;
282
283     alldead = 1;
284     for (ghost = 0; ghost < pp->nghosts; ghost++) {
285
286         /* The ghost have to be scared before you can kill them */
287         if ( pacman_ghost_collision ( ghost, pp ) ) {
288             if (pp->ghosts[ghost].aistate == goingin) continue;
289
290             if (pp->ghosts[ghost].aistate == hiding) {
291                 pp->ghosts[ghost].dead = 1;
292                 pp->ghosts[ghost].aistate = goingin;
293                 pp->ghosts[ghost].wait_pos = True;
294                 XSetForeground (display, pp->stippledGC, MI_BLACK_PIXEL (mi));
295                 XFillRectangle (display, window,
296                                 pp->stippledGC,
297                                 pp->ghosts[ghost].cf,
298                                 pp->ghosts[ghost].rf,
299                                 pp->spritexs, pp->spriteys);
300             }
301             /* DIE PACMAN... */
302             else {
303                 pp->pacman.deaths++;
304                 pp->pacman.aistate = ps_dieing;
305
306             }
307             continue;
308         }
309         
310         alldead = 0;
311     }
312     
313
314 }
315
316 /* Resets state of ghosts + pacman.  Creates a new level, draws that level. */
317 static void
318 repopulate (ModeInfo * mi)
319 {
320     pacmangamestruct *pp = &pacmangames[MI_SCREEN (mi)];
321     pp->pacman.deaths = 0;
322     reset_level (mi, createnewlevel (pp), True);
323     check_death (mi, pp);
324 }
325
326 /* Sets the color to the color of a wall. */
327 static void
328 setwallcolor (ModeInfo * mi)
329 {
330     Display *display = MI_DISPLAY (mi);
331     pacmangamestruct *pp = &pacmangames[MI_SCREEN (mi)];
332
333     if (MI_NPIXELS (mi) > 2)
334         XSetForeground (display, pp->stippledGC, MI_PIXEL (mi, BLUE));
335     else
336         XSetForeground (display, pp->stippledGC, MI_WHITE_PIXEL (mi));
337 }
338
339 /* Sets the color to the color of a dot. */
340 static void
341 setdotcolor (ModeInfo * mi)
342 {
343     Display *display = MI_DISPLAY (mi);
344     pacmangamestruct *pp = &pacmangames[MI_SCREEN (mi)];
345
346     XSetForeground (display, pp->stippledGC, MI_WHITE_PIXEL (mi));
347 }
348
349 static void
350 cleardotcolor (ModeInfo * mi)
351 {
352     Display *display = MI_DISPLAY (mi);
353     pacmangamestruct *pp = &pacmangames[MI_SCREEN (mi)];
354
355     XSetForeground (display, pp->stippledGC, MI_BLACK_PIXEL (mi));
356 }
357
358 #if 0
359 static void
360 draw_position (ModeInfo * mi, int x, int y, int color)
361 {
362     Display *display = MI_DISPLAY (mi);
363     Window window = MI_WINDOW (mi);
364     pacmangamestruct *pp = &pacmangames[MI_SCREEN (mi)];
365     XFontStruct *font = NULL;
366     char *f_name = "-*-utopia-*-r-*-*-*-600-*-*-p-*-*-*";
367     char *s = NULL;
368
369     font = XLoadQueryFont (display, f_name);
370     assert (font != NULL);
371
372     s = (char *) malloc (256);
373     assert (s != NULL);
374     sprintf (s, "(%d,%d)", x, y);
375     XSetForeground (display, pp->stippledGC, color);
376     XDrawString (display, window, pp->stippledGC, x, y, s, strlen (s));
377     free (s);
378     free (font);
379 }
380 #endif
381 #if 0
382 static void
383 draw_number (ModeInfo * mi, int x, int y, int num, int color)
384 {
385     Display *display = MI_DISPLAY (mi);
386     Window window = MI_WINDOW (mi);
387     pacmangamestruct *pp = &pacmangames[MI_SCREEN (mi)];
388     XFontStruct *font = NULL;
389     char *f_name = "-*-utopia-*-r-*-*-*-600-*-*-p-*-*-*";
390     char *s = NULL;
391
392     font = XLoadQueryFont (display, f_name);
393     assert (font != NULL);
394
395     s = (char *) malloc (256);
396     assert (s != NULL);
397     sprintf (s, "%d", num);
398     XSetForeground (display, pp->stippledGC, color);
399     XDrawString (display, window, pp->stippledGC, x, y, s, strlen (s));
400     free (s);
401     free (font);
402 }
403 #endif
404
405 #if 0
406 /* draw_grid - draws a grid on top of the playing field.
407  * Used so that I can determine if I'm converting from rows and columns to x and y 
408  * coordinates correctly.
409  */
410 static void
411 draw_grid (ModeInfo * mi)
412 {
413     Display *display = MI_DISPLAY (mi);
414     Window window = MI_WINDOW (mi);
415     pacmangamestruct *pp = &pacmangames[MI_SCREEN (mi)];
416     int h = MI_HEIGHT (mi);
417     int w = MI_WIDTH (mi);
418     int y = 0;
419     int x = 0;
420     XSetForeground (display, pp->stippledGC, 0xff0000);
421     while (y < h) {
422         while (x < w) {
423             XDrawLine (display, window, pp->stippledGC, x, 0, x, h);
424             x += 10;
425         }
426         x = 0;
427         XDrawLine (display, window, pp->stippledGC, 0, y, w, y);
428         y += 10;
429     }
430 }
431 #endif
432
433 #if 0
434 static void
435 draw_string (ModeInfo * mi, int x, int y, char *s, int color)
436 {
437     Display *display = MI_DISPLAY (mi);
438     Window window = MI_WINDOW (mi);
439     pacmangamestruct *pp = &pacmangames[MI_SCREEN (mi)];
440     XFontStruct *font = NULL;
441     char *f_name = "-*-utopia-*-r-*-*-*-600-*-*-p-*-*-*";
442
443     font = XLoadQueryFont (display, f_name);
444     assert (font != NULL);
445
446     assert (s != NULL);
447     XSetForeground (display, pp->stippledGC, color);
448     XDrawString (display, window, pp->stippledGC, x, y, s, strlen (s));
449     free (font);
450 }
451
452 /* I think this function has a memory leak. Be careful if you enable it. */
453 /* I only used it briefly to help me debug the ghost's aistate. It prints */
454 /* the state of each ghost on the left hand side of the screen */
455 static void
456 print_ghost_stats (ModeInfo *mi, ghoststruct *g , int ghost_num)
457 {
458     char s[1024];
459
460     sprintf (s, "GHOST: %d", ghost_num ); 
461     switch (g->aistate){
462     case inbox: 
463         sprintf (s, "%s inbox", s);
464         break;
465     case goingout:
466         sprintf (s, "%s goingout", s);
467         break;
468     case randdir:
469         sprintf (s, "%s randdir", s);
470         break;
471     case chasing:
472         sprintf (s, "%s chasing", s);
473         break;
474     case hiding:
475         sprintf (s, "%s hiding", s);
476         break;
477     case goingin:
478         sprintf (s, "%s goingin",s);
479         break;
480     }
481     draw_string (mi, 0, (ghost_num *3) *10+50, g->last_stat, 0x000000);
482     draw_string (mi, 0, (ghost_num *3) *10+50, s, 0xff0000);
483     strcpy(g->last_stat,s);
484 }
485
486 /* prints the number of times pacman has died and his aistate on the left hand */
487 /* side of the screen */
488 static void
489 print_pac_stats ( ModeInfo *mi, pacmanstruct *pac )
490 {
491     pacmangamestruct *pp = &pacmangames[MI_SCREEN (mi)];
492     char s[1024];
493     sprintf (s, "Pacman, Deaths: %d", pac->deaths );
494     switch ( pac->aistate ){
495     case ps_eating:
496         sprintf(s, "%s ps_eating",s );
497         break;
498     case ps_chasing:
499         sprintf(s, "%s ps_chasing",s );
500         break;
501     case ps_hiding:
502         sprintf(s, "%s ps_hiding",s );
503         break;
504     case ps_random:
505         sprintf(s, "%s ps_random",s );
506         break;
507     case ps_dieing:
508         sprintf(s, "%s ps_dieing",s );
509         break;
510     }
511     draw_string ( mi, 0, 200, pp->last_pac_stat, 0x000000);
512     draw_string ( mi, 0, 200, s, 0xff0000);
513     strcpy(pp->last_pac_stat, s );
514 }
515
516 #endif
517
518 /*Ok, yeah whatever?*/
519 /*dot_rc_to_pixel - magic that converts row and columns into
520  *the x and y coordinates of the screen.
521  */
522 static void
523 dot_rc_to_pixel (ModeInfo * mi, int *x, int *y)
524 {
525     pacmangamestruct *pp = &pacmangames[MI_SCREEN (mi)];
526     *x = (pp->xs * *x) +
527         (pp->xs / 2) - (pp->xs > 32 ? (pp->xs / 16) : 1) + pp->xb;
528     *y = (pp->ys * *y) +
529         (pp->ys / 2) - (pp->ys > 32 ? (pp->ys / 16) : 1) + pp->yb;
530 }
531
532 /* dot_width_height - magic used to get the width and height of
533  * a dot. This dot can also be scaled by a value.
534  */
535 static void
536 dot_width_height (ModeInfo *mi, int *w, int *h)
537 {
538     pacmangamestruct *pp = &pacmangames[MI_SCREEN (mi)];
539     if (pp->xs > 32){
540         *w = *h = (pp->xs / 32 );
541     }else {
542         *w = *h = 1;
543     }
544 }
545
546 static void
547 bonus_dot_width_height (ModeInfo *mi, int *w, int *h )
548 {
549     *w = *h = MI_HEIGHT (mi) / 65;
550 }
551
552 \f
553
554 static void
555 draw_dot (ModeInfo * mi, pacmangamestruct * pp, int x, int y,
556           void (*width_height)(ModeInfo * mi, int *w, int *h), 
557           int (*arc_func) (Display * display, Drawable d, GC gc,
558                                       int x, int y, unsigned int width,
559                                       unsigned int height, int angle1,
560                                       int angle2))
561 {
562     Display *display = MI_DISPLAY (mi);
563     Window window = MI_WINDOW (mi);
564     int w, h;
565     dot_rc_to_pixel (mi, &x, &y);
566     width_height(mi, &w, &h);
567     (void) arc_func (display, window, pp->stippledGC,
568                      x, y, w, h, 0, 23040);
569 }
570
571 static void
572 draw_bonus_dot (ModeInfo * mi, pacmangamestruct * pp, int x, int y)
573 {
574     int x2 = x;
575     int y2 = y;
576     setdotcolor (mi);
577     draw_dot (mi, pp, x, y, bonus_dot_width_height,  XFillArc);
578     dot_rc_to_pixel (mi, &x2, &y2);
579 #if 0
580     draw_position (mi, x2, y2, 0xff0000);
581 #endif
582 }
583
584 static void
585 clear_bonus_dot (ModeInfo * mi, pacmangamestruct * pp, int x, int y)
586 {
587     cleardotcolor (mi);
588     draw_dot (mi, pp, x, y, bonus_dot_width_height, XFillArc);
589 }
590
591 static void
592 draw_regular_dot (ModeInfo * mi, pacmangamestruct * pp, int x, int y)
593 {
594     setdotcolor (mi);
595     draw_dot (mi, pp, x, y, dot_width_height, XDrawArc);
596 }
597
598 /* Draws a block in the level at the specified x and y locations. */
599 static void
600 drawlevelblock (ModeInfo * mi, pacmangamestruct * pp,
601                 const unsigned x, const unsigned y)
602 {
603     Display *display = MI_DISPLAY (mi);
604     Window window = MI_WINDOW (mi);
605     int dx = 0, dy = 0;
606
607     if (pp->xs % 2 == 1)
608         dx = -1;
609     if (pp->ys % 2 == 1)
610         dy = -1;
611
612 #ifndef HAVE_COCOA
613     XSetFillStyle (display, pp->stippledGC, FillSolid);
614 #endif /* !HAVE_COCOA */
615     XSetLineAttributes (display, pp->stippledGC, pp->wallwidth,
616                         LineSolid, CapRound, JoinMiter);
617
618     if (pp->xs < 2 || pp->ys < 2) {
619         switch (pp->level[y * LEVWIDTH + x]) {
620         case ' ':
621         case '=':
622             break;
623         case '.':
624             setdotcolor (mi);
625             (void) XDrawPoint (display, window,
626                                pp->stippledGC,
627                                x * pp->xs + pp->xb, y * pp->ys + pp->yb);
628             break;
629         default:
630             setwallcolor (mi);
631             (void) XDrawPoint (display, window,
632                                pp->stippledGC,
633                                x * pp->xs + pp->xb, y * pp->ys + pp->yb);
634         }
635
636         return;
637     }
638
639     switch (pp->level[y * LEVWIDTH + x]) {
640     case ' ':
641     case '=':
642         break;
643
644     case '.':
645         setdotcolor (mi);
646         if (pp->xs < 8 || pp->ys < 8) {
647             (void) XDrawPoint (display, window,
648                                pp->stippledGC,
649                                x * pp->xs + pp->xb +
650                                pp->xs / 2, y * pp->ys + pp->yb + pp->ys / 2);
651             break;
652         }
653
654         draw_regular_dot (mi, pp, x, y);
655         break;
656         /* What we will probably want to do here is have the pp->level store a 'o' for
657          * the bonus dots. The we can use the drawing routine above just with a bigger
658          * radius.
659          */
660     case 'o':
661         draw_bonus_dot (mi, pp, x, y);
662         break;
663
664
665     case '-':
666         setwallcolor (mi);
667         (void) XDrawLine (display, window, pp->stippledGC,
668                           (pp->xs * x) + pp->xb,
669                           (pp->ys * y) + (pp->ys / 2) + pp->yb,
670                           (pp->xs * (x + 1)) + pp->xb,
671                           (pp->ys * y) + (pp->ys / 2) + pp->yb);
672         break;
673
674     case '|':
675         setwallcolor (mi);
676         (void) XDrawLine (display, window, pp->stippledGC,
677                           (pp->xs * x) + (pp->xs / 2) + pp->xb,
678                           (pp->ys * y) + pp->yb,
679                           (pp->xs * x) + (pp->xs / 2) + pp->xb,
680                           (pp->ys * (y + 1)) + pp->yb);
681         break;
682
683     case '_':
684         setwallcolor (mi);
685         (void) XDrawArc (display, window, pp->stippledGC,
686                          (pp->xs * x) - (pp->ys / 2) + pp->xb + dx,
687                          (pp->ys * y) + (pp->ys / 2) + pp->yb,
688                          pp->xs, pp->ys, 0 * 64, 90 * 64);
689         break;
690
691     case ',':
692         setwallcolor (mi);
693         (void) XDrawArc (display, window, pp->stippledGC,
694                          (pp->xs * x) + (pp->ys / 2) + pp->xb,
695                          (pp->ys * y) + (pp->ys / 2) + pp->yb,
696                          pp->xs, pp->ys, 90 * 64, 90 * 64);
697         break;
698
699     case '`':
700         setwallcolor (mi);
701         (void) XDrawArc (display, window, pp->stippledGC,
702                          (pp->xs * x) + (pp->ys / 2) + pp->xb,
703                          (pp->ys * y) - (pp->ys / 2) + pp->yb + dy,
704                          pp->xs, pp->ys, 180 * 64, 90 * 64);
705         break;
706
707     case '\'':
708         setwallcolor (mi);
709         (void) XDrawArc (display, window, pp->stippledGC,
710                          (pp->xs * x) - (pp->ys / 2) + pp->xb + dx,
711                          (pp->ys * y) - (pp->ys / 2) + pp->yb + dy,
712                          pp->xs, pp->ys, 270 * 64, 90 * 64);
713         break;
714
715     }
716 }
717
718 /* Draws a complete level. */
719 static void
720 drawlevel (ModeInfo * mi)
721 {
722     pacmangamestruct *pp = &pacmangames[MI_SCREEN (mi)];
723     unsigned int x, y;
724
725     for (y = 0; y < LEVHEIGHT; y++)
726         for (x = 0; x < LEVWIDTH; x++)
727             drawlevelblock (mi, pp, x, y);
728 }
729
730 /* There is some overlap so it can be made more efficient */
731 #define ERASE_IMAGE(d,w,g,x,y,xl,yl,xs,ys) \
732  if (yl<y) \
733   (y<(yl+ys))?XFillRectangle(d,w,g,xl,yl,xs,y-(yl)): \
734   XFillRectangle(d,w,g,xl,yl,xs,ys); \
735  else if (yl>y) \
736   (y>(yl-(ys)))?XFillRectangle(d,w,g,xl,y+ys,xs,yl-(y)): \
737   XFillRectangle(d,w,g,xl,yl,xs,ys); \
738  if (xl<x) \
739   (x<(xl+xs))?XFillRectangle(d,w,g,xl,yl,x-(xl),ys): \
740   XFillRectangle(d,w,g,xl,yl,xs,ys); \
741  else if (xl>x) \
742   (x>(xl-(xs)))?XFillRectangle(d,w,g,x+xs,yl,xl-(x),ys): \
743   XFillRectangle(d,w,g,xl,yl,xs,ys)
744
745
746 /* Draws the pacman sprite, removing the previous location. */
747 #if defined(USE_PIXMAP)
748
749 static void
750 draw_pacman_sprite (ModeInfo * mi)
751 {
752     Display *display = MI_DISPLAY (mi);
753     Window window = MI_WINDOW (mi);
754     pacmangamestruct *pp = &pacmangames[MI_SCREEN (mi)];
755     unsigned int dir = 0;
756     int old_mask_dir = 0;
757     int old_mask_mouth = 0;
758     Pixmap old_mask, new_mask;
759     Pixmap pacman;
760
761 #define MAX_MOUTH_DELAY 2
762 #define MAX_DEATH_DELAY 20
763
764     if (pp->pacman.aistate == ps_dieing){
765         pp->pacman.cf = pp->pacman.oldcf;
766         pp->pacman.rf = pp->pacman.oldrf;
767     }
768     else {
769         pp->pacman.cf = pp->pacman.col * pp->xs + pp->pacman.delta.x *
770             pp->pacman.cfactor + pp->xb + pp->spritedx;
771         pp->pacman.rf = pp->pacman.row * pp->ys + pp->pacman.delta.y *
772             pp->pacman.rfactor + pp->yb + pp->spritedy;
773     }
774
775     dir = (ABS (pp->pacman.cfactor) * (2 - pp->pacman.cfactor) +
776            ABS (pp->pacman.rfactor) * (1 + pp->pacman.rfactor)) % 4;
777
778     if (pp->pm_mouth_delay == MAX_MOUTH_DELAY) {
779         if (pp->pm_mouth == (MAXMOUTH - 1) || pp->pm_mouth == 0) {
780             pp->pm_open_mouth = !pp->pm_open_mouth;
781         }
782         pp->pm_open_mouth ? pp->pm_mouth++ : pp->pm_mouth--;
783         pp->pm_mouth_delay = 0;
784     }
785     else {
786         pp->pm_mouth_delay++;
787     }
788     
789     if (pp->pacman.aistate == ps_dieing){
790         if (pp->pm_death_frame >= PAC_DEATH_FRAMES) {
791             pp->pacman.aistate = ps_eating;
792             pp->pm_death_frame = 0;
793             pp->pm_death_delay = 0;
794             reset_level (mi, 0, False);
795             return;
796         }
797         else {
798             old_mask   = pp->pacmanMask[0][0];
799             new_mask   = pp->pacmanMask[0][0];
800             pacman     = pp->pacman_ds[pp->pm_death_frame];
801             if (pp->pm_death_delay == MAX_DEATH_DELAY){
802                 pp->pm_death_frame++;
803                 pp->pm_death_delay = 0;
804             }
805             else{
806                 pp->pm_death_delay++;
807             }
808         }
809     }
810     else{
811         old_mask = pp->pacmanMask[old_mask_dir][old_mask_mouth];
812         new_mask = pp->pacmanMask[dir][pp->pm_mouth];
813         pacman   = pp->pacmanPixmap[dir][pp->pm_mouth];
814     }
815
816     XSetForeground (display, pp->stippledGC, MI_BLACK_PIXEL (mi));
817
818     XSetClipMask (display, pp->stippledGC, old_mask);
819                   
820     XSetClipOrigin (display, pp->stippledGC, pp->pacman.oldcf,
821                     pp->pacman.oldrf);
822     XFillRectangle (display, window, pp->stippledGC, pp->pacman.oldcf,
823                     pp->pacman.oldrf, pp->spritexs, pp->spriteys);
824     XSetClipMask (display, pp->stippledGC, new_mask);
825     XSetClipOrigin (display, pp->stippledGC, pp->pacman.cf, pp->pacman.rf);
826     XCopyArea (display, pacman, window,
827                pp->stippledGC, 0, 0, pp->spritexs, pp->spriteys,
828                pp->pacman.cf, pp->pacman.rf);
829     XSetClipMask (display, pp->stippledGC, None);
830     if (pp->pacman.aistate != ps_dieing){
831         pp->pacman.oldcf = pp->pacman.cf;
832         pp->pacman.oldrf = pp->pacman.rf;
833     }
834     old_mask_dir = dir;
835     old_mask_mouth = pp->pm_mouth;
836 }
837
838 #if 0
839 static void
840 draw_ghost_position (ModeInfo * mi, ghoststruct * ghost)
841 {
842     draw_position (mi, ghost->oldcf, ghost->oldrf, MI_BLACK_PIXEL (mi));
843     draw_position (mi, ghost->cf, ghost->rf, 0x00ff00);
844 }
845 #endif
846 #if 0
847 static void
848 draw_ghost_ndirs ( ModeInfo *mi, ghoststruct * ghost)
849 {
850     draw_number (mi, ghost->oldcf, ghost->oldrf, ghost->oldndirs, MI_BLACK_PIXEL (mi));
851     ghost->oldndirs = ghost->ndirs;
852     draw_number (mi, ghost->cf, ghost->rf, ghost->ndirs, 0x00ff00);
853 }
854
855 #endif
856
857 static void
858 draw_ghost_sprite (ModeInfo * mi, const unsigned ghost)
859 {
860     Display *display = MI_DISPLAY (mi);
861     Window window = MI_WINDOW (mi);
862     pacmangamestruct *pp = &pacmangames[MI_SCREEN (mi)];
863 #define MAX_WAG_COUNT 50
864     unsigned int dir = 0;
865     unsigned int fs  = 0; /*flash scared*/
866     Pixmap g_pix; /*ghost pixmap*/
867
868     
869     dir = (ABS (pp->ghosts[ghost].cfactor) * (2 - pp->ghosts[ghost].cfactor) +
870            ABS (pp->ghosts[ghost].rfactor) * (1 + pp->ghosts[ghost].rfactor)) % 4;
871                                              
872
873     fs = pp->ghosts[ghost].flash_scared;
874     assert (fs == 0 || fs == 1);
875
876     /* Choose the pixmap */
877     switch (pp->ghosts[ghost].aistate){
878     case hiding:
879         g_pix = pp->s_ghostPixmap[fs][pp->gh_wag];
880         break;
881     case goingin:
882         g_pix = pp->ghostEyes[dir];
883 #if 1
884         {
885             int i = 0;
886             while ( i < pp->ghosts[ghost].trace_idx ){
887                 XFillRectangle (display,
888                                 window,
889                                 pp->stippledGC,
890                                 pp->ghosts[ghost].trace[i].vx,
891                                 pp->ghosts[ghost].trace[i].vy, 
892                                 pp->spritexs, pp->spriteys);
893
894                 i++;
895             }
896         }
897 #endif
898                 
899         break;
900     default:
901         g_pix = pp->ghostPixmap[ghost][dir][pp->gh_wag];
902     }
903
904     pp->ghosts[ghost].cf =
905         pp->ghosts[ghost].col * pp->xs + pp->ghosts[ghost].delta.x *
906         pp->ghosts[ghost].cfactor + pp->xb + pp->spritedx;
907     pp->ghosts[ghost].rf =
908         pp->ghosts[ghost].row * pp->ys + pp->ghosts[ghost].delta.y *
909         pp->ghosts[ghost].rfactor + pp->yb + pp->spritedy;
910
911     XSetForeground (display, pp->stippledGC, MI_BLACK_PIXEL (mi));
912
913     XSetClipMask (display, pp->stippledGC, pp->ghostMask);
914     XSetClipOrigin (display, pp->stippledGC,
915                     pp->ghosts[ghost].oldcf, pp->ghosts[ghost].oldrf);
916     XFillRectangle (display,
917                     window,
918                     pp->stippledGC,
919                     pp->ghosts[ghost].oldcf,
920                     pp->ghosts[ghost].oldrf, pp->spritexs, pp->spriteys);
921
922     
923     if (pp->pacman.aistate != ps_dieing) {
924         drawlevelblock (mi, pp,
925                         (unsigned int) pp->ghosts[ghost].col,
926                         (unsigned int) pp->ghosts[ghost].row);
927
928
929
930         XSetClipOrigin (display, pp->stippledGC,
931                         pp->ghosts[ghost].cf, pp->ghosts[ghost].rf);
932
933         XCopyArea (display, g_pix, window, pp->stippledGC, 0, 0,
934                    pp->spritexs, pp->spriteys, pp->ghosts[ghost].cf,
935                    pp->ghosts[ghost].rf);
936     }
937     XSetClipMask (display, pp->stippledGC, None);
938
939 #if 0
940     draw_ghost_position (mi, &(pp->ghosts[ghost]));
941 #endif
942
943 #if 0
944     draw_ghost_ndirs ( mi, &(pp->ghosts[ghost]));
945 #endif
946     
947     if (pp->pacman.aistate != ps_dieing) {
948         pp->ghosts[ghost].oldcf = pp->ghosts[ghost].cf;
949         pp->ghosts[ghost].oldrf = pp->ghosts[ghost].rf;
950         if (pp->gh_wag_count++ == MAX_WAG_COUNT) {
951             pp->gh_wag = !pp->gh_wag;
952             pp->gh_wag_count = 0;
953         }
954     }
955 }
956
957 #else /* USE_PIXMAP */
958
959 /* Draws the pacman sprite, removing the previous location. */
960 static void
961 draw_pacman_sprite (ModeInfo * mi)
962 {
963     Display *display = MI_DISPLAY (mi);
964     Window window = MI_WINDOW (mi);
965     pacmangamestruct *pp = &pacmangames[MI_SCREEN (mi)];
966     unsigned int dir;
967
968     pp->pacman.cf = pp->pacman.col * pp->xs + pp->pacman.delta.x *
969         pp->pacman.cfactor + pp->xb + pp->spritedx;
970     pp->pacman.rf = pp->pacman.row * pp->ys + pp->pacman.delta.y *
971         pp->pacman.rfactor + pp->yb + pp->spritedy;
972
973     dir = (ABS (pp->pacman.cfactor) * (2 - pp->pacman.cfactor) +
974            ABS (pp->pacman.rfactor) * (1 + pp->pacman.rfactor)) % 4;
975
976     XSetForeground (display, pp->stippledGC, MI_BLACK_PIXEL (mi));
977     if (pp->pacman.oldcf != NOWHERE && pp->pacman.oldrf != NOWHERE) {
978
979         ERASE_IMAGE (display, window, pp->stippledGC,
980                      pp->pacman.cf, pp->pacman.rf,
981                      pp->pacman.oldcf, pp->pacman.oldrf,
982                      pp->spritexs, pp->spriteys);
983     }
984
985     if (MI_NPIXELS (mi) > 2)
986         XSetForeground (display, pp->stippledGC, MI_PIXEL (mi, YELLOW));
987     else
988         XSetForeground (display, pp->stippledGC, MI_WHITE_PIXEL (mi));
989
990     XSetFillStyle (display, pp->stippledGC, FillOpaqueStippled);
991
992     if (pp->xs < 2 || pp->ys < 2)
993         XDrawPoint (display, window, pp->stippledGC,
994                     pp->pacman.cf, pp->pacman.rf);
995     else
996         XFillRectangle (display, window, pp->stippledGC,
997                         pp->pacman.cf, pp->pacman.rf,
998                         pp->spritexs, pp->spriteys);
999     pp->pacman.mouthstage += pp->pacman.mouthdirection;
1000     if ((pp->pacman.mouthstage >= MAXMOUTH) || (pp->pacman.mouthstage < 0)) {
1001         pp->pacman.mouthdirection *= -1;
1002         pp->pacman.mouthstage += pp->pacman.mouthdirection * 2;
1003     }
1004     pp->pacman.oldcf = pp->pacman.cf;
1005     pp->pacman.oldrf = pp->pacman.rf;
1006 }
1007
1008 /* Draws a ghost sprite, removing the previous sprite and restores the level. */
1009 static void
1010 draw_ghost_sprite (ModeInfo * mi, const unsigned ghost)
1011 {
1012     Display *display = MI_DISPLAY (mi);
1013     Window window = MI_WINDOW (mi);
1014     pacmangamestruct *pp = &pacmangames[MI_SCREEN (mi)];
1015
1016     pp->ghosts[ghost].cf =
1017         pp->ghosts[ghost].col * pp->xs + pp->ghosts[ghost].delta.x *
1018         pp->ghosts[ghost].cfactor + pp->xb + pp->spritedx;
1019     pp->ghosts[ghost].rf =
1020         pp->ghosts[ghost].row * pp->ys + pp->ghosts[ghost].delta.y *
1021         pp->ghosts[ghost].rfactor + pp->yb + pp->spritedy;
1022
1023     XSetForeground (display, pp->stippledGC, MI_BLACK_PIXEL (mi));
1024     XFillRectangle (display,
1025                     window,
1026                     pp->stippledGC,
1027                     pp->ghosts[ghost].cf,
1028                     pp->ghosts[ghost].rf, pp->spritexs, pp->spriteys);
1029
1030     if (pp->ghosts[ghost].oldcf != NOWHERE ||
1031         pp->ghosts[ghost].oldrf != NOWHERE) {
1032
1033         ERASE_IMAGE (display, window, pp->stippledGC,
1034                      pp->ghosts[ghost].cf, pp->ghosts[ghost].rf,
1035                      pp->ghosts[ghost].oldcf, pp->ghosts[ghost].oldrf,
1036                      pp->spritexs, pp->spriteys);
1037     }
1038
1039     drawlevelblock (mi, pp,
1040                     (unsigned int) pp->ghosts[ghost].col,
1041                     (unsigned int) pp->ghosts[ghost].row);
1042
1043     if (MI_NPIXELS (mi) > 2)
1044         XSetForeground (display, pp->stippledGC, MI_PIXEL (mi, GREEN));
1045     else
1046         XSetForeground (display, pp->stippledGC, MI_WHITE_PIXEL (mi));
1047
1048     XSetFillStyle (display, pp->stippledGC, FillOpaqueStippled);
1049
1050     if (pp->xs < 2 || pp->ys < 2)
1051         XDrawPoint (display, window, pp->stippledGC,
1052                     pp->ghosts[ghost].cf, pp->ghosts[ghost].rf);
1053     else
1054         XFillRectangle (display,
1055                         window,
1056                         pp->stippledGC,
1057                         pp->ghosts[ghost].cf,
1058                         pp->ghosts[ghost].rf, pp->spritexs, pp->spriteys);
1059
1060     pp->ghosts[ghost].oldcf = pp->ghosts[ghost].cf;
1061     pp->ghosts[ghost].oldrf = pp->ghosts[ghost].rf;
1062 }
1063 #endif /* USE_PIXMAP */
1064
1065 static int
1066 ghost_over (ModeInfo * mi, int x, int y)
1067 {
1068     int ghost = 0;
1069     int ret = False;
1070     pacmangamestruct *pp = &pacmangames[MI_SCREEN (mi)];
1071     dot_rc_to_pixel (mi, &x, &y);
1072     for (ghost = 0; ghost < pp->nghosts; ghost++) {
1073         if ((pp->ghosts[ghost].cf <= x
1074              && x <= pp->ghosts[ghost].cf + pp->spritexs)
1075             && (pp->ghosts[ghost].rf <= y
1076                 && y <= pp->ghosts[ghost].rf + pp->spriteys)) {
1077             ret = True;
1078             break;
1079         }
1080     }
1081     return ret;
1082 }
1083 \f
1084
1085 static void
1086 flash_bonus_dots (ModeInfo * mi)
1087 {
1088 #define MAX_FLASH_COUNT 25
1089     pacmangamestruct *pp = &pacmangames[MI_SCREEN (mi)];
1090     int i, x, y;
1091     for (i = 0; i < NUM_BONUS_DOTS; i++) {
1092         if (!bonus_dot_eaten (pp, i)) {
1093             bonus_dot_pos (pp, i, &x, &y);
1094             if (ghost_over (mi, x, y))
1095                 continue;
1096             if (pp->bd_on)
1097                 draw_bonus_dot (mi, pp, x, y);
1098             else
1099                 clear_bonus_dot (mi, pp, x, y);
1100         }
1101     }
1102     if (pp->bd_flash_count-- == 0) {
1103         pp->bd_flash_count = MAX_FLASH_COUNT;
1104         pp->bd_on = !pp->bd_on;
1105     }
1106 }
1107
1108 static unsigned int
1109 ate_bonus_dot (ModeInfo * mi)
1110 {
1111     /*Check pacman's position. If it is over a bonus dot and that dot
1112      *has not been eaten, then return true
1113      */
1114     unsigned int ret = 0;
1115     int idx = 0;
1116     pacmangamestruct *pp = &pacmangames[MI_SCREEN (mi)];
1117     if (is_bonus_dot (pp, pp->pacman.col, pp->pacman.row, &idx)) {
1118         ret = !bonus_dot_eaten (pp, idx);
1119         eat_bonus_dot (pp, idx);
1120     }
1121     return ret;
1122 }
1123
1124 static void
1125 ghost_scared (ModeInfo * mi)
1126 {
1127     unsigned int ghost;
1128     pacmangamestruct *pp = &pacmangames[MI_SCREEN (mi)];
1129     for (ghost = 0; ghost < pp->nghosts; ghost++) {
1130         if (pp->ghosts[ghost].aistate == goingin || 
1131             pp->ghosts[ghost].aistate == goingout ||
1132             pp->ghosts[ghost].aistate == inbox ) continue;
1133         pp->ghosts[ghost].aistate = hiding;
1134         pp->ghosts[ghost].flash_scared = 0;
1135         if (pp->pacman.aistate != ps_dieing)
1136             pp->pacman.aistate = ps_chasing;
1137     }
1138 }
1139
1140 static void
1141 ghost_not_scared (ModeInfo * mi)
1142 {
1143     unsigned int ghost;
1144     pacmangamestruct *pp = &pacmangames[MI_SCREEN (mi)];
1145     for (ghost = 0; ghost < pp->nghosts; ghost++){
1146         if (pp->ghosts[ghost].aistate == goingin ||
1147             pp->ghosts[ghost].aistate == goingout ||
1148             pp->ghosts[ghost].aistate == inbox ) continue;
1149         pp->ghosts[ghost].aistate = chasing;
1150     }
1151     if (pp->pacman.aistate != ps_dieing)
1152         pp->pacman.aistate = ps_eating;
1153     
1154 }
1155
1156 static void
1157 ghost_flash_scared (ModeInfo * mi)
1158 {
1159     unsigned int ghost;
1160     pacmangamestruct *pp = &pacmangames[MI_SCREEN (mi)];
1161     for (ghost = 0; ghost < pp->nghosts; ghost++)
1162         pp->ghosts[ghost].flash_scared = !pp->ghosts[ghost].flash_scared;
1163 }
1164
1165 /* Does all drawing of moving sprites in the level. */
1166 static void
1167 pacman_tick (ModeInfo * mi)
1168 {
1169 #define DEFAULT_SCARED_TIME 500
1170 #define START_FLASH 200
1171 #define FLASH_COUNT 25
1172
1173     pacmangamestruct *pp = &pacmangames[MI_SCREEN (mi)];
1174     unsigned int ghost;
1175 #if 0
1176     draw_grid (mi);
1177 #endif
1178     for (ghost = 0; ghost < pp->nghosts; ghost++) {
1179         draw_ghost_sprite (mi, ghost);
1180 #if 0
1181         print_ghost_stats (mi, &(pp->ghosts[ghost]), ghost);
1182 #endif
1183     }
1184 #if 0    
1185     print_pac_stats (mi, &(pp->pacman));
1186 #endif
1187     draw_pacman_sprite (mi);
1188     flash_bonus_dots (mi);
1189     if (ate_bonus_dot (mi)) {
1190         pp->ghost_scared_timer = (random () % 100) + DEFAULT_SCARED_TIME;
1191         ghost_scared (mi);
1192     }
1193
1194     if (pp->ghost_scared_timer > 0) {
1195         if (--pp->ghost_scared_timer == 0)
1196             ghost_not_scared (mi);
1197         else if (pp->ghost_scared_timer <= START_FLASH) {
1198             if (pp->flash_timer <= 0) {
1199                 pp->flash_timer = FLASH_COUNT;
1200                 ghost_flash_scared (mi);
1201             }
1202             pp->flash_timer--;
1203         }
1204     }
1205
1206     /*
1207       We don't want to miss the last death sequence. So if pacman has died three times
1208       we wait for his state to change from dieing to something else before we repopulate
1209       the level. If pacman ate all of the dots then we just repopulate.
1210     */
1211
1212     if (pp->dotsleft == 0 )
1213         repopulate (mi);
1214     else if (pp->pacman.deaths >= 3){
1215         if (pp->old_pac_state == ps_dieing && pp->pacman.aistate != ps_dieing)
1216             repopulate (mi);
1217     }
1218
1219     pp->old_pac_state = pp->pacman.aistate;
1220 }
1221 \f
1222
1223 /* CODE TO LOAD AND SCALE THE PIXMAPS
1224  */
1225
1226 #if defined(USE_PIXMAP)
1227 /*  Grabbed the scaling routine off of usenet. 
1228  *  Changed it so that the information specific 
1229  *  to the source pixmap does not have to be a parameter.
1230  *
1231  *  There is probably a better way to scale pixmaps.
1232  *  From: Chris Fiddyment (cxf@itd.dsto.gov.au)
1233  *  Subject: Scaling Pixmap Algorithm.
1234  *  Newsgroups: comp.graphics.algorithms
1235  *  Date: 1994-07-06 18:51:38 PST 
1236  *  -jeremy
1237  */
1238
1239 static Pixmap
1240 scale_pixmap (Display ** dpy, GC gc, Pixmap source, int dwidth, int dheight)
1241 {
1242     Pixmap temp, dest;
1243     int j, end;
1244     float i;
1245     float xscale, yscale;
1246     unsigned int swidth, sheight;
1247     Window window;
1248     int x, y;
1249     unsigned border_width_return, depth;
1250     XGetGeometry (*dpy, source, &window, &x, &y, &swidth, &sheight,
1251                   &border_width_return, &depth);
1252
1253     xscale = (float) swidth / (float) dwidth;   /* Scaling factors */
1254     yscale = (float) sheight / (float) dheight;
1255
1256     dest = XCreatePixmap (*dpy, window, dwidth, dheight, depth);
1257     if (!dest) {
1258         fprintf (stderr, "%s Could not scale image", progname);
1259     }
1260     temp = XCreatePixmap (*dpy, window, dwidth, sheight, depth);
1261     if (!temp) {
1262         fprintf (stderr, "%s Could not scale image", progname);
1263     }
1264
1265     j = 0;
1266     end = dwidth * xscale;
1267     /* Scale width of source into temp pixmap */
1268     for (i = 0; i <= end; i += xscale)
1269         XCopyArea (*dpy, source, temp, gc, i, 0, 1, sheight, j++, 0);
1270
1271     j = 0;
1272     end = dheight * yscale;
1273     /* Scale height of temp into dest pixmap */
1274     for (i = 0; i <= end; i += yscale)
1275         XCopyArea (*dpy, temp, dest, gc, 0, i, swidth, 1, 0, j++);
1276
1277     XFreePixmap (*dpy, temp);
1278     return (Pixmap) dest;
1279 }
1280
1281 static void
1282 pacman_fail (char *s)
1283 {
1284     fprintf (stderr, "%s: %s\n", progname, s);
1285     exit (1);
1286 }
1287
1288 /* Load the ghost pixmaps and their mask. */
1289 static void
1290 load_ghost_pixmaps (Display ** dpy, Window window, pacmangamestruct ** ps)
1291 {
1292     pacmangamestruct *pp = *ps;
1293     Display *display = *dpy;
1294     char *colors[] = {
1295         ".      c #FF0000",         /*Red */
1296         ".  c #00FFDE",         /*Blue */
1297         ".  c #FFB847",         /*Orange */
1298         ".  c #FFB8DE",         /*Pink */
1299     };
1300
1301     char **bits[] = {
1302         ghost_u1_xpm, ghost_u2_xpm, ghost_r1_xpm, ghost_r2_xpm,
1303         ghost_d1_xpm, ghost_d2_xpm, ghost_l1_xpm, ghost_l2_xpm
1304     };
1305     char * const *s_bits[] = {
1306         ghost_s1_xpm, ghost_s2_xpm,
1307         ghost_sf1_xpm, ghost_sf2_xpm
1308     };
1309     char * const *e_bits[] = {
1310         eyes_u_xpm, eyes_r_xpm, eyes_d_xpm, eyes_l_xpm
1311     };
1312         
1313     int i, j, k, m;
1314     int w = pp->spritexs;
1315     int h = pp->spriteys;
1316     GC gc = 0;
1317     Pixmap temp;
1318
1319     for (i = 0; i < 4; i++) {
1320         m = 0;
1321         for (j = 0; j < MAXGDIR; j++) {
1322             for (k = 0; k < MAXGWAG; k++) {
1323                 bits[m][2] = colors[i];
1324                 pp->ghostPixmap[i][j][k] =
1325                     xpm_data_to_pixmap (display, window, bits[m], &w, &h,
1326                                         &pp->ghostMask);
1327
1328                 if (!pp->ghostPixmap[i][j][k])
1329                     pacman_fail ("Cannot load ghost images");
1330
1331                 pp->ghostPixmap[i][j][k] =
1332                     scale_pixmap (&display, pp->stippledGC,
1333                                   pp->ghostPixmap[i][j][k], pp->spritexs,
1334                                   pp->spriteys);
1335
1336                 if (!pp->ghostPixmap[i][j][k])
1337                     pacman_fail ("Cannot scale ghost images");
1338                 m++;
1339             }
1340         }
1341     }
1342     /* load the scared ghost */
1343     m = 0;
1344     for (i = 0; i < MAXGFLASH; i++) {
1345         for (j = 0; j < MAXGWAG; j++) {
1346             pp->s_ghostPixmap[i][j] =
1347                 xpm_data_to_pixmap (display, window, s_bits[m++], &w, &h,
1348                                     &pp->ghostMask);
1349
1350             if (!pp->s_ghostPixmap[i][j])
1351                 pacman_fail ("Cannot Scare Ghost images");
1352             pp->s_ghostPixmap[i][j] = scale_pixmap (&display, pp->stippledGC,
1353                                                     pp->s_ghostPixmap[i][j],
1354                                                     pp->spritexs,
1355                                                     pp->spriteys);
1356
1357             if (!pp->s_ghostPixmap[i][j])
1358                 pacman_fail ("Cannot scale Scared Ghost images");
1359         }
1360     }
1361     /* load the ghost eyes */
1362     for (i = 0; i < MAXGDIR; i++) {
1363         pp->ghostEyes[i] =
1364             xpm_data_to_pixmap (display, window, e_bits[i], &w, &h,
1365                                 &pp->ghostMask);
1366
1367         if (!pp->ghostEyes[i])
1368             pacman_fail ("Cannot open ghost eye images");
1369
1370         pp->ghostEyes[i] = scale_pixmap (&display, pp->stippledGC,
1371                                          pp->ghostEyes[i],
1372                                          pp->spritexs,
1373                                          pp->spriteys);
1374             
1375         if (!pp->ghostEyes[i])
1376             pacman_fail ("Cannot open ghost eye images");
1377     }
1378
1379
1380
1381     /* We really only need a single mask. This saves the headache of getting the
1382      * bottom of the ghost to clip just right. What we'll do is mask
1383      * the top portion of the ghost, but the bottom of the ghost will be solid.
1384      * I did this by setting the pixels between the fringe of their sheets
1385      * to black instead of none. -jeremy
1386      */
1387     temp = xpm_data_to_pixmap (display, window, ghost_mask_xpm,
1388                                &w, &h, &pp->ghostMask);
1389
1390     if (!temp)
1391         pacman_fail ("Cannot load temporary ghost image");
1392
1393     temp = scale_pixmap (&display, pp->stippledGC,
1394                          temp, pp->spritexs, pp->spriteys);
1395
1396     if (!temp)
1397         pacman_fail ("Cannot scale temporary ghost image");
1398
1399     gc = XCreateGC (display, pp->ghostMask, 0, 0);
1400
1401     pp->ghostMask = scale_pixmap (&display, gc, pp->ghostMask,
1402                                   pp->spritexs, pp->spriteys);
1403     XFreePixmap (display, temp);
1404 }
1405
1406 /* Load the pacman pixmaps and their mask. */
1407 static void
1408 load_pacman_pixmaps (Display ** dpy, Window window, pacmangamestruct ** ps)
1409 {
1410     pacmangamestruct *pp = *ps;
1411     Display *display = *dpy;
1412
1413     char **bits[] = {
1414         pacman_0_xpm, pacman_u1_xpm, pacman_u2_xpm,
1415         pacman_0_xpm, pacman_r1_xpm, pacman_r2_xpm,
1416         pacman_0_xpm, pacman_d1_xpm, pacman_d2_xpm,
1417         pacman_0_xpm, pacman_l1_xpm, pacman_l2_xpm
1418     };
1419  
1420     char * const *ds_bits[] = {
1421         pacman_ds1_xpm, pacman_ds2_xpm, pacman_ds3_xpm, pacman_ds4_xpm,
1422         pacman_ds5_xpm, pacman_ds6_xpm, pacman_ds7_xpm, pacman_ds8_xpm
1423     };
1424
1425     int i, j, m;
1426     int w = pp->spritexs;
1427     int h = pp->spriteys;
1428     GC gc = 0;
1429
1430     m = 0;
1431     for (i = 0; i < 4; i++) {
1432         for (j = 0; j < MAXMOUTH; j++) {
1433             pp->pacmanPixmap[i][j] =
1434                 xpm_data_to_pixmap (display, window, bits[m++], &w, &h,
1435                                     &pp->pacmanMask[i][j]);
1436
1437             if (!pp->pacmanPixmap[i][j])
1438                 pacman_fail ("Cannot load pacman pixmap.");
1439
1440             pp->pacmanPixmap[i][j] = scale_pixmap (&display, pp->stippledGC,
1441                                                    pp->pacmanPixmap[i][j],
1442                                                    pp->spritexs,
1443                                                    pp->spriteys);
1444
1445             if (!pp->pacmanPixmap[i][j])
1446                 pacman_fail ("Cannot scale pacman pixmap.");
1447
1448             if (!gc)
1449                 gc = XCreateGC (display, pp->pacmanMask[i][j], 0, 0);
1450
1451             pp->pacmanMask[i][j] =
1452                 scale_pixmap (&display, gc, pp->pacmanMask[i][j],
1453                               pp->spritexs, pp->spriteys);
1454         }
1455     }
1456     
1457     /* Load pacman death sequence */
1458     for ( i = 0; i < PAC_DEATH_FRAMES; i++ ){
1459         pp->pacman_ds[i] = 
1460             xpm_data_to_pixmap (display, window, ds_bits[i], &w, &h,
1461                                 &pp->pacman_ds_mask[i]);
1462
1463         if (!pp->pacman_ds[i])
1464             pacman_fail ("Cannot load pacman death frame.");
1465         
1466         pp->pacman_ds[i] = scale_pixmap ( &display, pp->stippledGC,
1467                                           pp->pacman_ds[i],
1468                                           pp->spritexs,
1469                                           pp->spriteys);
1470         
1471         if (!pp->pacman_ds[i])
1472             pacman_fail ("Cannot scale pixmap.");
1473
1474         if (!gc)
1475             gc = XCreateGC (display, pp->pacman_ds_mask[i], 0, 0);
1476
1477         pp->pacman_ds_mask[i] = 
1478             scale_pixmap (&display, gc, pp->pacman_ds_mask[i],
1479                           pp->spritexs, pp->spriteys);
1480     }
1481
1482 }
1483 #endif /* USE_PIXMAP */
1484
1485 /* Hook function, sets state to initial position. */
1486 ENTRYPOINT void
1487 init_pacman (ModeInfo * mi)
1488 {
1489     Display *display = MI_DISPLAY (mi);
1490     Window window = MI_WINDOW (mi);
1491     int size = MI_SIZE (mi);
1492     pacmangamestruct *pp;
1493     XGCValues gcv;
1494     int i, j, k;
1495
1496 #if (! defined( USE_PIXMAP ))
1497     GC fg_gc, bg_gc;
1498     XPoint points[9];
1499     int dir, mouth;
1500 #endif
1501
1502     if (pacmangames == NULL) {
1503         if ((pacmangames = (pacmangamestruct *)
1504              calloc ((size_t) MI_NUM_SCREENS (mi),
1505                      sizeof (pacmangamestruct))) == NULL)
1506             return;
1507     }
1508     pp = &pacmangames[MI_SCREEN (mi)];
1509
1510     pp->width = (unsigned short) MI_WIDTH (mi);
1511     pp->height = (unsigned short) MI_HEIGHT (mi);
1512     for (i = 0; i < 4; i++) {
1513         for (j = 0; j < MAXGDIR; j++) {
1514             for (k = 0; k < MAXGWAG; k++) {
1515                 if (pp->ghostPixmap[i][j][k] != None) {
1516                     XFreePixmap (display, pp->ghostPixmap[i][j][k]);
1517                     pp->ghostPixmap[i][j][k] = None;
1518                     pp->graphics_format = 0 /*IS_NONE */ ;
1519                 }
1520             }
1521         }
1522     }
1523
1524     for (i = 0; i < MAXGFLASH; i++) {
1525         for (j = 0; j < MAXGWAG; j++) {
1526             if (pp->s_ghostPixmap[i][j] != None) {
1527                 XFreePixmap (display, pp->s_ghostPixmap[i][j]);
1528                 pp->s_ghostPixmap[i][j] = None;
1529             }
1530         }
1531     }
1532
1533     if (size == 0 ||
1534         MINGRIDSIZE * size > (int) pp->width ||
1535         MINGRIDSIZE * size > (int) pp->height) {
1536
1537         pp->ys = pp->xs = MAX (MIN (pp->width / LEVWIDTH,
1538                                     pp->height / LEVHEIGHT), 1);
1539     }
1540     else {
1541         if (size < -MINSIZE)
1542             pp->ys = (short) (NRAND (MIN (-size, MAX (MINSIZE,
1543                                                       MIN (pp->width,
1544                                                            pp->height) /
1545                                                       MINGRIDSIZE))
1546                                      - MINSIZE + 1) + MINSIZE);
1547         else if (size < MINSIZE)
1548             pp->ys = MINSIZE;
1549         else
1550             pp->ys = (short) (MIN (size,
1551                                    MAX (MINSIZE, MIN (pp->width, pp->height) /
1552                                         MINGRIDSIZE)));
1553         pp->xs = pp->ys;
1554     }
1555
1556     pp->wallwidth = (unsigned int) (pp->xs + pp->ys) >> 4;
1557     if (pp->wallwidth < 1)
1558         pp->wallwidth = 1;
1559     pp->incx = (pp->xs >> 3) + 1;
1560     pp->incy = (pp->ys >> 3) + 1;
1561     pp->ncols = (unsigned short) MAX (LEVWIDTH, 2);
1562     pp->nrows = (unsigned short) MAX (LEVHEIGHT, 2);
1563     pp->xb = (pp->width - pp->ncols * pp->xs) >> 1;
1564     pp->yb = (pp->height - pp->nrows * pp->ys) >> 1;
1565     pp->spritexs = MAX (pp->xs + (pp->xs >> 1) - 1, 1);
1566     pp->spriteys = MAX (pp->ys + (pp->ys >> 1) - 1, 1);
1567     pp->spritedx = (pp->xs - pp->spritexs) >> 1;
1568     pp->spritedy = (pp->ys - pp->spriteys) >> 1;
1569     pp->old_pac_state = chasing;
1570
1571     if (!pp->stippledGC) {
1572         gcv.foreground = MI_BLACK_PIXEL (mi);
1573         gcv.background = MI_BLACK_PIXEL (mi);
1574         if ((pp->stippledGC = XCreateGC (display, window,
1575                                          GCForeground | GCBackground,
1576                                          &gcv)) == None) {
1577             free_pacman (display, pp);
1578             return;
1579         }
1580     }
1581
1582 #ifdef HAVE_COCOA
1583     jwxyz_XSetAntiAliasing (display, pp->stippledGC, False);
1584 #endif
1585
1586 #if defined(USE_PIXMAP)
1587     load_ghost_pixmaps (&display, window, &pp);
1588     load_pacman_pixmaps (&display, window, &pp);
1589 #else
1590     if ((pp->ghostPixmap[0][0][0] = XCreatePixmap (display, window,
1591                                                    pp->spritexs, pp->spriteys,
1592                                                    1)) == None) {
1593         free_pacman (display, pp);
1594         return;
1595     }
1596
1597     gcv.foreground = 0;
1598     gcv.background = 1;
1599     if ((bg_gc = XCreateGC (display, pp->ghostPixmap[0][0][0],
1600                             GCForeground | GCBackground, &gcv)) == None) {
1601         free_pacman (display, pp);
1602         return;
1603     }
1604
1605     gcv.foreground = 1;
1606     gcv.background = 0;
1607     if ((fg_gc = XCreateGC (display, pp->ghostPixmap[0][0][0],
1608                             GCForeground | GCBackground, &gcv)) == None) {
1609         XFreeGC (display, bg_gc);
1610         free_pacman (display, pp);
1611         return;
1612     }
1613
1614 #define SETPOINT(p, xp, yp) p.x = xp; p.y = yp
1615
1616     /* draw the triangles on the bottom (scalable) */
1617     SETPOINT (points[0], 1, pp->spriteys * 5 / 6);
1618     SETPOINT (points[1], pp->spritexs / 6, pp->spriteys);
1619     SETPOINT (points[2], pp->spritexs / 3, pp->spriteys * 5 / 6);
1620     SETPOINT (points[3], pp->spritexs / 2, pp->spriteys);
1621     SETPOINT (points[4], pp->spritexs * 2 / 3, pp->spriteys * 5 / 6);
1622     SETPOINT (points[5], pp->spritexs * 5 / 6, pp->spriteys);
1623     SETPOINT (points[6], pp->spritexs, pp->spriteys * 5 / 6);
1624     SETPOINT (points[7], pp->spritexs, pp->spriteys / 2);
1625     SETPOINT (points[8], 1, pp->spriteys / 2);
1626
1627     XFillRectangle (display, pp->ghostPixmap[0][0][0], bg_gc,
1628                     0, 0, pp->spritexs, pp->spriteys);
1629     XFillArc (display, pp->ghostPixmap[0][0][0], fg_gc,
1630               0, 0, pp->spritexs, pp->spriteys, 0, 11520);
1631     XFillPolygon (display, pp->ghostPixmap[0][0][0], fg_gc,
1632                   points, 9, Nonconvex, CoordModeOrigin);
1633     XFreeGC (display, bg_gc);
1634     XFreeGC (display, fg_gc);
1635
1636
1637     if (pp->pacmanPixmap[0][0] != None)
1638         for (dir = 0; dir < 4; dir++)
1639             for (mouth = 0; mouth < MAXMOUTH; mouth++)
1640                 XFreePixmap (display, pp->pacmanPixmap[dir]
1641                              [mouth]);
1642
1643     for (dir = 0; dir < 4; dir++)
1644         for (mouth = 0; mouth < MAXMOUTH; mouth++) {
1645             if ((pp->pacmanPixmap[dir][mouth] =
1646                  XCreatePixmap (display, MI_WINDOW (mi), pp->spritexs,
1647                                 pp->spriteys, 1)) == None) {
1648                 free_pacman (display, pp);
1649                 return;
1650             }
1651             gcv.foreground = 1;
1652             gcv.background = 0;
1653             if ((fg_gc = XCreateGC (display, pp->pacmanPixmap[dir][mouth],
1654                                     GCForeground | GCBackground,
1655                                     &gcv)) == None) {
1656                 free_pacman (display, pp);
1657                 return;
1658             }
1659             gcv.foreground = 0;
1660             gcv.background = 0;
1661             if ((bg_gc = XCreateGC (display,
1662                                     pp->pacmanPixmap[dir][mouth],
1663                                     GCForeground |
1664                                     GCBackground, &gcv)) == None) {
1665                 XFreeGC (display, fg_gc);
1666                 free_pacman (display, pp);
1667                 return;
1668             }
1669             XFillRectangle (display,
1670                             pp->pacmanPixmap[dir][mouth], bg_gc,
1671                             0, 0, pp->spritexs, pp->spriteys);
1672             if (pp->spritexs == 1 && pp->spriteys == 1)
1673                 XFillRectangle (display,
1674                                 pp->pacmanPixmap[dir][mouth],
1675                                 fg_gc, 0, 0, pp->spritexs, pp->spriteys);
1676             else
1677                 XFillArc (display,
1678                           pp->pacmanPixmap[dir][mouth],
1679                           fg_gc,
1680                           0, 0, pp->spritexs, pp->spriteys,
1681                           ((90 - dir * 90) + mouth * 5) * 64,
1682                           (360 + (-2 * mouth * 5)) * 64);
1683             XFreeGC (display, fg_gc);
1684             XFreeGC (display, bg_gc);
1685         }
1686 #endif /* USE_PIXMAP */
1687
1688     pp->pacman.lastbox = START;
1689     pp->pacman.mouthdirection = 1;
1690     pp->pacman.nextcol = NOWHERE;
1691     pp->pacman.nextrow = NOWHERE;
1692
1693     if (pp->ghosts != NULL) {
1694         free (pp->ghosts);
1695         pp->ghosts = (ghoststruct *) NULL;
1696     }
1697     pp->nghosts = GHOSTS;
1698
1699     if (!pp->ghosts)
1700         if ((pp->ghosts = (ghoststruct *) calloc ((size_t) pp->nghosts,
1701                                                   sizeof (ghoststruct))) ==
1702             NULL) {
1703             free_pacman (display, pp);
1704             return;
1705         }
1706
1707     pp->pacman.mouthstage = MAXMOUTH - 1;
1708
1709     MI_CLEARWINDOW (mi);
1710     repopulate (mi);
1711 }
1712
1713 /* Callback function called for each tick.  This is the complete machinery of
1714    everything that moves. */
1715 ENTRYPOINT void
1716 draw_pacman (ModeInfo * mi)
1717 {
1718     unsigned int g;
1719     pacmangamestruct *pp;
1720
1721     if (pacmangames == NULL)
1722         return;
1723     pp = &pacmangames[MI_SCREEN (mi)];
1724     if (pp->ghosts == NULL)
1725         return;
1726
1727     pp->pacman.err.x = (pp->pacman.err.x + 1) % pp->pacman.speed;
1728     pp->pacman.err.y = (pp->pacman.err.y + 1) % pp->pacman.speed;
1729     pp->pacman.delta.x += pp->pacman.err.x != 0 ? pp->incx : 0;
1730     pp->pacman.delta.y += pp->pacman.err.y != 0 ? pp->incy : 0;
1731
1732     if (pp->pacman.delta.x >= pp->xs && pp->pacman.delta.y >= pp->ys) {
1733         pac_update (mi, pp, &(pp->pacman));
1734         check_death (mi, pp);
1735         pp->pacman.delta.x = pp->incx;
1736         pp->pacman.delta.y = pp->incy;
1737     }
1738
1739     if (pp->pacman.delta.x > pp->xs + pp->incx)
1740         pp->pacman.delta.x = pp->xs + pp->incx;
1741     if (pp->pacman.delta.y > pp->ys + pp->incy)
1742         pp->pacman.delta.y = pp->ys + pp->incy;
1743
1744     for (g = 0; g < pp->nghosts; g++) {
1745         pp->ghosts[g].err.x = (pp->ghosts[g].err.x + 1) % pp->ghosts[g].speed;
1746         pp->ghosts[g].err.y = (pp->ghosts[g].err.y + 1) % pp->ghosts[g].speed;
1747         pp->ghosts[g].delta.x += pp->ghosts[g].err.x != 0 ? pp->incx : 0;
1748         pp->ghosts[g].delta.y += pp->ghosts[g].err.y != 0 ? pp->incy : 0; 
1749         
1750         if (pp->ghosts[g].delta.x >= pp->xs &&
1751             pp->ghosts[g].delta.y >= pp->ys) {
1752             ghost_update (pp, &(pp->ghosts[g]));
1753             pp->ghosts[g].delta.x = pp->incx;
1754             pp->ghosts[g].delta.y = pp->incy;
1755         }
1756
1757         if (pp->ghosts[g].delta.x > pp->xs + pp->incx)
1758             pp->ghosts[g].delta.x = pp->xs + pp->incx;
1759         if (pp->ghosts[g].delta.y > pp->ys + pp->incy)
1760             pp->ghosts[g].delta.y = pp->ys + pp->incy;
1761     }
1762     pacman_tick (mi);
1763 }
1764
1765 /* Releases resources. */
1766 ENTRYPOINT void
1767 release_pacman (ModeInfo * mi)
1768 {
1769     if (pacmangames != NULL) {
1770         int screen;
1771
1772         for (screen = 0; screen < MI_NUM_SCREENS (mi); screen++)
1773             free_pacman (MI_DISPLAY (mi), &pacmangames[screen]);
1774         free (pacmangames);
1775         pacmangames = (pacmangamestruct *) NULL;
1776     }
1777 }
1778
1779 /* Refresh current level. */
1780 ENTRYPOINT void
1781 refresh_pacman (ModeInfo * mi)
1782 {
1783     drawlevel (mi);
1784     pacman_tick (mi);
1785 }
1786
1787 #ifndef STANDALONE
1788 /* Callback to change level. */
1789 ENTRYPOINT void
1790 change_pacman (ModeInfo * mi)
1791 {
1792     MI_CLEARWINDOW (mi);
1793     repopulate (mi);
1794 }
1795 #endif /* !STANDALONE */
1796
1797
1798 XSCREENSAVER_MODULE ("Pacman", pacman)
1799
1800 #endif /* MODE_pacman */