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