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