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