1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* pacman --- Mr. Pacman and his ghost friends */
4 #if !defined( lint ) && !defined( SABER )
5 static const char sccsid[] = "@(#)pacman.c 5.00 2000/11/01 xlockmore";
10 * Copyright (c) 2002 by Edwin de Jong <mauddib@gmx.net>.
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.
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.
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
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
44 1. think of a better level generation algorithm
47 #define DEF_TRACKMOUSE "False"
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" \
59 # define UNIFORM_COLORS
60 # define BRIGHT_COLORS
65 # include "xlockmore.h" /* in xscreensaver distribution */
66 #else /* STANDALONE */
67 # include "xlock.h" /* in xlockmore distribution */
68 #endif /* STANDALONE */
73 #include "pacman_ai.h"
74 #include "pacman_level.h"
76 #if defined(HAVE_GDK_PIXBUF) || defined(HAVE_XPM)
78 #include "xpm-pixmap.h"
80 #if defined(USE_PIXMAP)
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"
126 } dirvecs[DIRVECS] = { {
132 #ifdef DISABLE_INTERACTIVE
133 ModeSpecOpt pacman_opts = {
135 (XrmOptionDescRec *) NULL,
138 (OptionStruct *) NULL
141 static XrmOptionDescRec opts[] = {
142 {"-trackmouse", ".pacman.trackmouse", XrmoptionNoArg, "on"},
143 {"+trackmouse", ".pacman.trackmouse", XrmoptionNoArg, "off"}
146 static argtype vars[] = {
147 {&trackmouse, "trackmouse", "TrackMouse", DEF_TRACKMOUSE, t_Bool}
150 static OptionStruct desc[] = {
151 {"-/+trackmouse", "turn on/off the tracking of the mouse"}
154 ModeSpecOpt pacman_opts =
155 { sizeof opts / sizeof opts[0], opts, sizeof vars / sizeof vars[0], vars,
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
175 pacmangamestruct *pacmangames = (pacmangamestruct *) NULL;
178 static void repopulate (ModeInfo * mi);
179 static void drawlevel (ModeInfo * mi);
183 free_pacman (Display * display, pacmangamestruct * pp)
185 int dir, mouth, i, j, k;
187 if (pp->ghosts != NULL) {
189 pp->ghosts = (ghoststruct *) NULL;
191 if (pp->stippledGC != None) {
192 XFreeGC (display, pp->stippledGC);
193 pp->stippledGC = None;
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;
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;
213 /* set pacman and the ghost in there starting positions, but don't draw a new
216 reset_level (ModeInfo * mi, int n, int pac_init)
218 pacmangamestruct *pp = &pacmangames[MI_SCREEN (mi)];
224 pp->gamestate = GHOST_DANGER;
227 pp->pacman.row = (LEVHEIGHT + JAILHEIGHT) / 2 - n;
228 pp->pacman.init_row = pp->pacman.row;
231 pp->pacman.row = pp->pacman.init_row;
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;
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]));
270 pac_update (mi, pp, &(pp->pacman));
274 pacman_ghost_collision(unsigned int ghost, pacmangamestruct * pp)
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)));
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. */
288 check_death (ModeInfo * mi, pacmangamestruct * pp)
290 Display *display = MI_DISPLAY (mi);
291 Window window = MI_WINDOW (mi);
295 if (pp->pacman.aistate == ps_dieing) return;
298 for (ghost = 0; ghost < pp->nghosts; ghost++) {
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;
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,
311 pp->ghosts[ghost].cf,
312 pp->ghosts[ghost].rf,
313 pp->spritexs, pp->spriteys);
318 pp->pacman.aistate = ps_dieing;
330 /* Resets state of ghosts + pacman. Creates a new level, draws that level. */
332 repopulate (ModeInfo * mi)
334 pacmangamestruct *pp = &pacmangames[MI_SCREEN (mi)];
335 pp->pacman.deaths = 0;
336 reset_level (mi, createnewlevel (mi), True);
337 check_death (mi, pp);
340 /* Sets the color to the color of a wall. */
342 setwallcolor (ModeInfo * mi)
344 Display *display = MI_DISPLAY (mi);
345 pacmangamestruct *pp = &pacmangames[MI_SCREEN (mi)];
347 if (MI_NPIXELS (mi) > 2)
348 XSetForeground (display, pp->stippledGC, MI_PIXEL (mi, BLUE));
350 XSetForeground (display, pp->stippledGC, MI_WHITE_PIXEL (mi));
353 /* Sets the color to the color of a dot. */
355 setdotcolor (ModeInfo * mi)
357 Display *display = MI_DISPLAY (mi);
358 pacmangamestruct *pp = &pacmangames[MI_SCREEN (mi)];
360 XSetForeground (display, pp->stippledGC, MI_WHITE_PIXEL (mi));
364 cleardotcolor (ModeInfo * mi)
366 Display *display = MI_DISPLAY (mi);
367 pacmangamestruct *pp = &pacmangames[MI_SCREEN (mi)];
369 XSetForeground (display, pp->stippledGC, MI_BLACK_PIXEL (mi));
374 draw_position (ModeInfo * mi, int x, int y, int color)
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-*-*-*";
383 font = XLoadQueryFont (display, f_name);
384 assert (font != NULL);
386 s = (char *) malloc (256);
388 sprintf (s, "(%d,%d)", x, y);
389 XSetForeground (display, pp->stippledGC, color);
390 XDrawString (display, window, pp->stippledGC, x, y, s, strlen (s));
397 draw_number (ModeInfo * mi, int x, int y, int num, int color)
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-*-*-*";
406 font = XLoadQueryFont (display, f_name);
407 assert (font != NULL);
409 s = (char *) malloc (256);
411 sprintf (s, "%d", num);
412 XSetForeground (display, pp->stippledGC, color);
413 XDrawString (display, window, pp->stippledGC, x, y, s, strlen (s));
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.
425 draw_grid (ModeInfo * mi)
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);
434 XSetForeground (display, pp->stippledGC, 0xff0000);
437 XDrawLine (display, window, pp->stippledGC, x, 0, x, h);
441 XDrawLine (display, window, pp->stippledGC, 0, y, w, y);
449 draw_string (ModeInfo * mi, int x, int y, char *s, int color)
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-*-*-*";
457 font = XLoadQueryFont (display, f_name);
458 assert (font != NULL);
461 XSetForeground (display, pp->stippledGC, color);
462 XDrawString (display, window, pp->stippledGC, x, y, s, strlen (s));
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 */
470 print_ghost_stats (ModeInfo *mi, ghoststruct *g , int ghost_num)
474 sprintf (s, "GHOST: %d", ghost_num );
477 sprintf (s, "%s inbox", s);
480 sprintf (s, "%s goingout", s);
483 sprintf (s, "%s randdir", s);
486 sprintf (s, "%s chasing", s);
489 sprintf (s, "%s hiding", s);
492 sprintf (s, "%s goingin",s);
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);
500 /* prints the number of times pacman has died and his aistate on the left hand */
501 /* side of the screen */
503 print_pac_stats ( ModeInfo *mi, pacmanstruct *pac )
505 static char last_pac_stat[1024] = "\0";
507 sprintf (s, "Pacman, Deaths: %d", pac->deaths );
508 switch ( pac->aistate ){
510 sprintf(s, "%s ps_eating",s );
513 sprintf(s, "%s ps_chasing",s );
516 sprintf(s, "%s ps_hiding",s );
519 sprintf(s, "%s ps_random",s );
522 sprintf(s, "%s ps_dieing",s );
525 draw_string ( mi, 0, 200, last_pac_stat, 0x000000);
526 draw_string ( mi, 0, 200, s, 0xff0000);
527 strcpy(last_pac_stat, s );
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.
537 dot_rc_to_pixel (ModeInfo * mi, int *x, int *y)
539 pacmangamestruct *pp = &pacmangames[MI_SCREEN (mi)];
541 (pp->xs / 2) - (pp->xs > 32 ? (pp->xs / 16) : 1) + pp->xb;
543 (pp->ys / 2) - (pp->ys > 32 ? (pp->ys / 16) : 1) + pp->yb;
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.
550 dot_width_height (ModeInfo *mi, int *w, int *h)
552 pacmangamestruct *pp = &pacmangames[MI_SCREEN (mi)];
554 *w = *h = (pp->xs / 32 );
561 bonus_dot_width_height (ModeInfo *mi, int *w, int *h )
563 *w = *h = MI_HEIGHT (mi) / 65;
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,
576 Display *display = MI_DISPLAY (mi);
577 Window window = MI_WINDOW (mi);
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);
586 draw_bonus_dot (ModeInfo * mi, pacmangamestruct * pp, int x, int y)
591 draw_dot (mi, pp, x, y, bonus_dot_width_height, XFillArc);
592 dot_rc_to_pixel (mi, &x2, &y2);
594 draw_position (mi, x2, y2, 0xff0000);
599 clear_bonus_dot (ModeInfo * mi, pacmangamestruct * pp, int x, int y)
602 draw_dot (mi, pp, x, y, bonus_dot_width_height, XFillArc);
606 draw_regular_dot (ModeInfo * mi, pacmangamestruct * pp, int x, int y)
609 draw_dot (mi, pp, x, y, dot_width_height, XDrawArc);
612 /* Draws a block in the level at the specified x and y locations. */
614 drawlevelblock (ModeInfo * mi, pacmangamestruct * pp,
615 const unsigned x, const unsigned y)
617 Display *display = MI_DISPLAY (mi);
618 Window window = MI_WINDOW (mi);
626 XSetFillStyle (display, pp->stippledGC, FillSolid);
627 XSetLineAttributes (display, pp->stippledGC, pp->wallwidth,
628 LineSolid, CapRound, JoinMiter);
630 if (pp->xs < 2 || pp->ys < 2) {
631 switch (pp->level[y * LEVWIDTH + x]) {
637 (void) XDrawPoint (display, window,
639 x * pp->xs + pp->xb, y * pp->ys + pp->yb);
643 (void) XDrawPoint (display, window,
645 x * pp->xs + pp->xb, y * pp->ys + pp->yb);
651 switch (pp->level[y * LEVWIDTH + x]) {
658 if (pp->xs < 8 || pp->ys < 8) {
659 (void) XDrawPoint (display, window,
661 x * pp->xs + pp->xb +
662 pp->xs / 2, y * pp->ys + pp->yb + pp->ys / 2);
666 draw_regular_dot (mi, pp, x, y);
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
673 draw_bonus_dot (mi, pp, x, y);
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);
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);
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);
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);
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);
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);
730 /* Draws a complete level. */
732 drawlevel (ModeInfo * mi)
734 pacmangamestruct *pp = &pacmangames[MI_SCREEN (mi)];
737 for (y = 0; y < LEVHEIGHT; y++)
738 for (x = 0; x < LEVWIDTH; x++)
739 drawlevelblock (mi, pp, x, y);
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) \
745 (y<(yl+ys))?XFillRectangle(d,w,g,xl,yl,xs,y-(yl)): \
746 XFillRectangle(d,w,g,xl,yl,xs,ys); \
748 (y>(yl-(ys)))?XFillRectangle(d,w,g,xl,y+ys,xs,yl-(y)): \
749 XFillRectangle(d,w,g,xl,yl,xs,ys); \
751 (x<(xl+xs))?XFillRectangle(d,w,g,xl,yl,x-(xl),ys): \
752 XFillRectangle(d,w,g,xl,yl,xs,ys); \
754 (x>(xl-(xs)))?XFillRectangle(d,w,g,x+xs,yl,xl-(x),ys): \
755 XFillRectangle(d,w,g,xl,yl,xs,ys)
758 /* Draws the pacman sprite, removing the previous location. */
759 #if defined(USE_PIXMAP)
762 draw_pacman_sprite (ModeInfo * mi)
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;
778 #define MAX_MOUTH_DELAY 2
779 #define MAX_DEATH_DELAY 20
781 if (pp->pacman.aistate == ps_dieing){
782 pp->pacman.cf = pp->pacman.oldcf;
783 pp->pacman.rf = pp->pacman.oldrf;
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;
792 dir = (ABS (pp->pacman.cfactor) * (2 - pp->pacman.cfactor) +
793 ABS (pp->pacman.rfactor) * (1 + pp->pacman.rfactor)) % 4;
795 if (mouth_delay == MAX_MOUTH_DELAY) {
796 if (mouth == (MAXMOUTH - 1) || mouth == 0) {
797 open_mouth = !open_mouth;
799 open_mouth ? mouth++ : mouth--;
806 if (pp->pacman.aistate == ps_dieing){
807 if (death_frame >= PAC_DEATH_FRAMES) {
808 pp->pacman.aistate = ps_eating;
811 reset_level (mi, 0, False);
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){
828 old_mask = pp->pacmanMask[old_mask_dir][old_mask_mouth];
829 new_mask = pp->pacmanMask[dir][mouth];
830 pacman = pp->pacmanPixmap[dir][mouth];
833 XSetForeground (display, pp->stippledGC, MI_BLACK_PIXEL (mi));
835 XSetClipMask (display, pp->stippledGC, old_mask);
837 XSetClipOrigin (display, pp->stippledGC, pp->pacman.oldcf,
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;
852 old_mask_mouth = mouth;
857 draw_ghost_position (ModeInfo * mi, ghoststruct * ghost)
859 draw_position (mi, ghost->oldcf, ghost->oldrf, MI_BLACK_PIXEL (mi));
860 draw_position (mi, ghost->cf, ghost->rf, 0x00ff00);
865 draw_ghost_ndirs ( ModeInfo *mi, ghoststruct * ghost)
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);
875 draw_ghost_sprite (ModeInfo * mi, const unsigned ghost)
877 Display *display = MI_DISPLAY (mi);
878 Window window = MI_WINDOW (mi);
879 pacmangamestruct *pp = &pacmangames[MI_SCREEN (mi)];
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*/
888 dir = (ABS (pp->ghosts[ghost].cfactor) * (2 - pp->ghosts[ghost].cfactor) +
889 ABS (pp->ghosts[ghost].rfactor) * (1 + pp->ghosts[ghost].rfactor)) % 4;
892 fs = pp->ghosts[ghost].flash_scared;
893 assert (fs == 0 || fs == 1);
895 /* Choose the pixmap */
896 switch (pp->ghosts[ghost].aistate){
898 g_pix = pp->s_ghostPixmap[fs][wag];
901 g_pix = pp->ghostEyes[dir];
905 while ( i < pp->ghosts[ghost].trace_idx ){
906 XFillRectangle (display,
909 pp->ghosts[ghost].trace[i].vx,
910 pp->ghosts[ghost].trace[i].vy,
911 pp->spritexs, pp->spriteys);
920 g_pix = pp->ghostPixmap[ghost][dir][wag];
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;
930 XSetForeground (display, pp->stippledGC, MI_BLACK_PIXEL (mi));
932 XSetClipMask (display, pp->stippledGC, pp->ghostMask);
933 XSetClipOrigin (display, pp->stippledGC,
934 pp->ghosts[ghost].oldcf, pp->ghosts[ghost].oldrf);
935 XFillRectangle (display,
938 pp->ghosts[ghost].oldcf,
939 pp->ghosts[ghost].oldrf, pp->spritexs, pp->spriteys);
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);
949 XSetClipOrigin (display, pp->stippledGC,
950 pp->ghosts[ghost].cf, pp->ghosts[ghost].rf);
952 XCopyArea (display, g_pix, window, pp->stippledGC, 0, 0,
953 pp->spritexs, pp->spriteys, pp->ghosts[ghost].cf,
954 pp->ghosts[ghost].rf);
956 XSetClipMask (display, pp->stippledGC, None);
959 draw_ghost_position (mi, &(pp->ghosts[ghost]));
963 draw_ghost_ndirs ( mi, &(pp->ghosts[ghost]));
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) {
976 #else /* USE_PIXMAP */
978 /* Draws the pacman sprite, removing the previous location. */
980 draw_pacman_sprite (ModeInfo * mi)
982 Display *display = MI_DISPLAY (mi);
983 Window window = MI_WINDOW (mi);
984 pacmangamestruct *pp = &pacmangames[MI_SCREEN (mi)];
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;
992 dir = (ABS (pp->pacman.cfactor) * (2 - pp->pacman.cfactor) +
993 ABS (pp->pacman.rfactor) * (1 + pp->pacman.rfactor)) % 4;
995 XSetForeground (display, pp->stippledGC, MI_BLACK_PIXEL (mi));
996 if (pp->pacman.oldcf != NOWHERE && pp->pacman.oldrf != NOWHERE) {
998 XFillRectangle (display, window, pp->stippledGC,
999 pp->pacman.oldcf, pp->pacman.oldrf,
1000 pp->spritexs, pp->spriteys);
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);
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));
1013 XSetForeground (display, pp->stippledGC, MI_WHITE_PIXEL (mi));
1015 XSetStipple (display, pp->stippledGC,
1016 pp->pacmanPixmap[dir][pp->pacman.mouthstage]);
1018 XSetFillStyle (display, pp->stippledGC, FillStippled);
1020 XSetFillStyle (display, pp->stippledGC, FillOpaqueStippled);
1022 if (pp->xs < 2 || pp->ys < 2)
1023 XDrawPoint (display, window, pp->stippledGC,
1024 pp->pacman.cf, pp->pacman.rf);
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;
1034 pp->pacman.oldcf = pp->pacman.cf;
1035 pp->pacman.oldrf = pp->pacman.rf;
1038 /* Draws a ghost sprite, removing the previous sprite and restores the level. */
1040 draw_ghost_sprite (ModeInfo * mi, const unsigned ghost)
1042 Display *display = MI_DISPLAY (mi);
1043 Window window = MI_WINDOW (mi);
1044 pacmangamestruct *pp = &pacmangames[MI_SCREEN (mi)];
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;
1053 XSetForeground (display, pp->stippledGC, MI_BLACK_PIXEL (mi));
1054 XFillRectangle (display,
1057 pp->ghosts[ghost].cf,
1058 pp->ghosts[ghost].rf, pp->spritexs, pp->spriteys);
1060 if (pp->ghosts[ghost].oldcf != NOWHERE ||
1061 pp->ghosts[ghost].oldrf != NOWHERE) {
1063 XFillRectangle (display, window,
1064 pp->stippledGC, pp->ghosts[ghost].oldcf,
1065 pp->ghosts[ghost].oldrf, pp->spritexs, pp->spriteys);
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);
1074 drawlevelblock (mi, pp,
1075 (unsigned int) pp->ghosts[ghost].col,
1076 (unsigned int) pp->ghosts[ghost].row);
1078 XSetTSOrigin (display, pp->stippledGC,
1079 pp->ghosts[ghost].cf, pp->ghosts[ghost].rf);
1081 if (MI_NPIXELS (mi) > 2)
1082 XSetForeground (display, pp->stippledGC, MI_PIXEL (mi, GREEN));
1084 XSetForeground (display, pp->stippledGC, MI_WHITE_PIXEL (mi));
1086 XSetStipple (display, pp->stippledGC, pp->ghostPixmap[0][0][0]);
1089 XSetFillStyle (display, pp->stippledGC, FillStippled);
1091 XSetFillStyle (display, pp->stippledGC, FillOpaqueStippled);
1093 if (pp->xs < 2 || pp->ys < 2)
1094 XDrawPoint (display, window, pp->stippledGC,
1095 pp->ghosts[ghost].cf, pp->ghosts[ghost].rf);
1097 XFillRectangle (display,
1100 pp->ghosts[ghost].cf,
1101 pp->ghosts[ghost].rf, pp->spritexs, pp->spriteys);
1103 pp->ghosts[ghost].oldcf = pp->ghosts[ghost].cf;
1104 pp->ghosts[ghost].oldrf = pp->ghosts[ghost].rf;
1106 #endif /* USE_PIXMAP */
1109 ghost_over (ModeInfo * mi, int x, int y)
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)) {
1129 flash_bonus_dots (ModeInfo * mi)
1131 #define MAX_FLASH_COUNT 25
1132 static int flash_count = 0;
1134 pacmangamestruct *pp = &pacmangames[MI_SCREEN (mi)];
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))
1142 draw_bonus_dot (mi, pp, x, y);
1144 clear_bonus_dot (mi, pp, x, y);
1147 if (flash_count-- == 0) {
1148 flash_count = MAX_FLASH_COUNT;
1154 ate_bonus_dot (ModeInfo * mi)
1156 /*Check pacman's position. If it is over a bonus dot and that dot
1157 *has not been eaten, then return true
1159 unsigned int ret = 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);
1170 ghost_scared (ModeInfo * mi)
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;
1186 ghost_not_scared (ModeInfo * mi)
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;
1196 if (pp->pacman.aistate != ps_dieing)
1197 pp->pacman.aistate = ps_eating;
1202 ghost_flash_scared (ModeInfo * mi)
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;
1210 /* Does all drawing of moving sprites in the level. */
1212 pacman_tick (ModeInfo * mi)
1214 #define DEFAULT_SCARED_TIME 500
1215 #define START_FLASH 200
1216 #define FLASH_COUNT 25
1218 Display *display = MI_DISPLAY (mi);
1219 pacmangamestruct *pp = &pacmangames[MI_SCREEN (mi)];
1221 static int ghost_scared_timer = 0;
1222 static int flash_timer = 0;
1223 static PacmanState old_pac_state = chasing;
1227 for (ghost = 0; ghost < pp->nghosts; ghost++) {
1228 draw_ghost_sprite (mi, ghost);
1230 print_ghost_stats (mi, &(pp->ghosts[ghost]), ghost);
1234 print_pac_stats (mi, &(pp->pacman));
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;
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);
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.
1261 if (pp->dotsleft == 0 )
1263 else if (pp->pacman.deaths >= 3){
1264 if (old_pac_state == ps_dieing && pp->pacman.aistate != ps_dieing)
1268 old_pac_state = pp->pacman.aistate;
1270 (void) XFlush (display);
1274 /* CODE TO LOAD AND SCALE THE PIXMAPS
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.
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
1291 scale_pixmap (Display ** dpy, GC gc, Pixmap source, int dwidth, int dheight)
1296 float xscale, yscale;
1297 unsigned int swidth, sheight;
1300 unsigned border_width_return, depth;
1301 XGetGeometry (*dpy, source, &window, &x, &y, &swidth, &sheight,
1302 &border_width_return, &depth);
1304 xscale = (float) swidth / (float) dwidth; /* Scaling factors */
1305 yscale = (float) sheight / (float) dheight;
1307 dest = XCreatePixmap (*dpy, window, dwidth, dheight, depth);
1309 fprintf (stderr, "%s Could not scale image", progname);
1311 temp = XCreatePixmap (*dpy, window, dwidth, sheight, depth);
1313 fprintf (stderr, "%s Could not scale image", progname);
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);
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++);
1328 XFreePixmap (*dpy, temp);
1329 return (Pixmap) dest;
1333 pacman_fail (char *s)
1335 fprintf (stderr, "%s: %s\n", progname, s);
1339 /* Load the ghost pixmaps and their mask. */
1341 load_ghost_pixmaps (Display ** dpy, Window window, pacmangamestruct ** ps)
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 */
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
1356 static char **s_bits[] = {
1357 ghost_s1_xpm, ghost_s2_xpm,
1358 ghost_sf1_xpm, ghost_sf2_xpm
1360 static char **e_bits[] = {
1361 eyes_u_xpm, eyes_r_xpm, eyes_d_xpm, eyes_l_xpm
1365 int w = pp->spritexs;
1366 int h = pp->spriteys;
1370 for (i = 0; i < 4; i++) {
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,
1379 if (!pp->ghostPixmap[i][j][k])
1380 pacman_fail ("Cannot load ghost images");
1382 pp->ghostPixmap[i][j][k] =
1383 scale_pixmap (&display, pp->stippledGC,
1384 pp->ghostPixmap[i][j][k], pp->spritexs,
1387 if (!pp->ghostPixmap[i][j][k])
1388 pacman_fail ("Cannot scale ghost images");
1393 /* load the scared ghost */
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,
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],
1408 if (!pp->s_ghostPixmap[i][j])
1409 pacman_fail ("Cannot scale Scared Ghost images");
1412 /* load the ghost eyes */
1413 for (i = 0; i < MAXGDIR; i++) {
1415 xpm_data_to_pixmap (display, window, e_bits[i], &w, &h,
1418 if (!pp->ghostEyes[i])
1419 pacman_fail ("Cannot open ghost eye images");
1421 pp->ghostEyes[i] = scale_pixmap (&display, pp->stippledGC,
1426 if (!pp->ghostEyes[i])
1427 pacman_fail ("Cannot open ghost eye images");
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
1438 temp = xpm_data_to_pixmap (display, window, ghost_mask_xpm,
1439 &w, &h, &pp->ghostMask);
1442 pacman_fail ("Cannot load temporary ghost image");
1444 temp = scale_pixmap (&display, pp->stippledGC,
1445 temp, pp->spritexs, pp->spriteys);
1448 pacman_fail ("Cannot scale temporary ghost image");
1450 gc = XCreateGC (display, pp->ghostMask, 0, 0);
1452 pp->ghostMask = scale_pixmap (&display, gc, pp->ghostMask,
1453 pp->spritexs, pp->spriteys);
1454 XFreePixmap (display, temp);
1457 /* Load the pacman pixmaps and their mask. */
1459 load_pacman_pixmaps (Display ** dpy, Window window, pacmangamestruct ** ps)
1461 pacmangamestruct *pp = *ps;
1462 Display *display = *dpy;
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
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
1477 int w = pp->spritexs;
1478 int h = pp->spriteys;
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]);
1488 if (!pp->pacmanPixmap[i][j])
1489 pacman_fail ("Cannot load pacman pixmap.");
1491 pp->pacmanPixmap[i][j] = scale_pixmap (&display, pp->stippledGC,
1492 pp->pacmanPixmap[i][j],
1496 if (!pp->pacmanPixmap[i][j])
1497 pacman_fail ("Cannot scale pacman pixmap.");
1500 gc = XCreateGC (display, pp->pacmanMask[i][j], 0, 0);
1502 pp->pacmanMask[i][j] =
1503 scale_pixmap (&display, gc, pp->pacmanMask[i][j],
1504 pp->spritexs, pp->spriteys);
1508 /* Load pacman death sequence */
1509 for ( i = 0; i < PAC_DEATH_FRAMES; i++ ){
1511 xpm_data_to_pixmap (display, window, ds_bits[i], &w, &h,
1512 &pp->pacman_ds_mask[i]);
1514 if (!pp->pacman_ds[i])
1515 pacman_fail ("Cannot load pacman death frame.");
1517 pp->pacman_ds[i] = scale_pixmap ( &display, pp->stippledGC,
1522 if (!pp->pacman_ds[i])
1523 pacman_fail ("Cannot scale pixmap.");
1526 gc = XCreateGC (display, pp->pacman_ds_mask[i], 0, 0);
1528 pp->pacman_ds_mask[i] =
1529 scale_pixmap (&display, gc, pp->pacman_ds_mask[i],
1530 pp->spritexs, pp->spriteys);
1534 #endif /* USE_PIXMAP */
1536 /* Hook function, sets state to initial position. */
1538 init_pacman (ModeInfo * mi)
1540 Display *display = MI_DISPLAY (mi);
1541 Window window = MI_WINDOW (mi);
1542 int size = MI_SIZE (mi);
1543 pacmangamestruct *pp;
1547 #if (! defined( USE_PIXMAP ))
1553 if (pacmangames == NULL) {
1554 if ((pacmangames = (pacmangamestruct *)
1555 calloc ((size_t) MI_NUM_SCREENS (mi),
1556 sizeof (pacmangamestruct))) == NULL)
1559 pp = &pacmangames[MI_SCREEN (mi)];
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 */ ;
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;
1585 MINGRIDSIZE * size > (int) pp->width ||
1586 MINGRIDSIZE * size > (int) pp->height) {
1588 pp->ys = pp->xs = MAX (MIN (pp->width / LEVWIDTH,
1589 pp->height / LEVHEIGHT), 1);
1592 if (size < -MINSIZE)
1593 pp->ys = (short) (NRAND (MIN (-size, MAX (MINSIZE,
1597 - MINSIZE + 1) + MINSIZE);
1598 else if (size < MINSIZE)
1601 pp->ys = (short) (MIN (size,
1602 MAX (MINSIZE, MIN (pp->width, pp->height) /
1607 pp->wallwidth = (unsigned int) (pp->xs + pp->ys) >> 4;
1608 if (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;
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,
1627 free_pacman (display, pp);
1632 #if defined(USE_PIXMAP)
1633 load_ghost_pixmaps (&display, window, &pp);
1634 load_pacman_pixmaps (&display, window, &pp);
1636 if ((pp->ghostPixmap[0][0][0] = XCreatePixmap (display, window,
1637 pp->spritexs, pp->spriteys,
1639 free_pacman (display, pp);
1645 if ((bg_gc = XCreateGC (display, pp->ghostPixmap[0][0][0],
1646 GCForeground | GCBackground, &gcv)) == None) {
1647 free_pacman (display, pp);
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);
1660 #define SETPOINT(p, xp, yp) p.x = xp; p.y = yp
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);
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);
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]
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);
1699 if ((fg_gc = XCreateGC (display, pp->pacmanPixmap[dir][mouth],
1700 GCForeground | GCBackground,
1702 free_pacman (display, pp);
1707 if ((bg_gc = XCreateGC (display,
1708 pp->pacmanPixmap[dir][mouth],
1710 GCBackground, &gcv)) == None) {
1711 XFreeGC (display, fg_gc);
1712 free_pacman (display, pp);
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);
1724 pp->pacmanPixmap[dir][mouth],
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);
1732 #endif /* USE_PIXMAP */
1734 pp->pacman.lastbox = START;
1735 pp->pacman.mouthdirection = 1;
1736 pp->pacman.nextcol = NOWHERE;
1737 pp->pacman.nextrow = NOWHERE;
1739 if (pp->ghosts != NULL) {
1741 pp->ghosts = (ghoststruct *) NULL;
1743 pp->nghosts = GHOSTS;
1746 if ((pp->ghosts = (ghoststruct *) calloc ((size_t) pp->nghosts,
1747 sizeof (ghoststruct))) ==
1749 free_pacman (display, pp);
1753 pp->pacman.mouthstage = MAXMOUTH - 1;
1755 MI_CLEARWINDOW (mi);
1759 /* Callback function called for each tick. This is the complete machinery of
1760 everything that moves. */
1762 draw_pacman (ModeInfo * mi)
1765 pacmangamestruct *pp;
1767 if (pacmangames == NULL)
1769 pp = &pacmangames[MI_SCREEN (mi)];
1770 if (pp->ghosts == NULL)
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;
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;
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;
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;
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;
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;
1811 /* Releases resources. */
1813 release_pacman (ModeInfo * mi)
1815 if (pacmangames != NULL) {
1818 for (screen = 0; screen < MI_NUM_SCREENS (mi); screen++)
1819 free_pacman (MI_DISPLAY (mi), &pacmangames[screen]);
1821 pacmangames = (pacmangamestruct *) NULL;
1825 /* Refresh current level. */
1827 refresh_pacman (ModeInfo * mi)
1833 /* Callback to change level. */
1835 change_pacman (ModeInfo * mi)
1837 MI_CLEARWINDOW (mi);
1841 #endif /* MODE_pacman */