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 DEFAULTS "*delay: 10000 \n" \
54 # define UNIFORM_COLORS
55 # define BRIGHT_COLORS
56 # define reshape_pacman 0
57 # define pacman_handle_event 0
58 # include "xlockmore.h" /* in xscreensaver distribution */
60 #else /* STANDALONE */
61 # include "xlock.h" /* in xlockmore distribution */
62 #endif /* STANDALONE */
67 #include "pacman_ai.h"
68 #include "pacman_level.h"
70 #if defined(USE_PIXMAP) /* computed in pacman.h */
71 # include "images/pacman/ghost-u1.xpm"
72 # include "images/pacman/ghost-u2.xpm"
73 # include "images/pacman/ghost-r1.xpm"
74 # include "images/pacman/ghost-r2.xpm"
75 # include "images/pacman/ghost-l1.xpm"
76 # include "images/pacman/ghost-l2.xpm"
77 # include "images/pacman/ghost-d1.xpm"
78 # include "images/pacman/ghost-d2.xpm"
79 /* Used to clean up the dust left by wag. */
80 # include "images/pacman/ghost-mask.xpm"
81 # include "images/pacman/pacman-u1.xpm"
82 # include "images/pacman/pacman-u2.xpm"
83 # include "images/pacman/pacman-r1.xpm"
84 # include "images/pacman/pacman-r2.xpm"
85 # include "images/pacman/pacman-l1.xpm"
86 # include "images/pacman/pacman-l2.xpm"
87 # include "images/pacman/pacman-d1.xpm"
88 # include "images/pacman/pacman-d2.xpm"
89 # include "images/pacman/pacman-0.xpm"
90 # include "images/pacman/ghost-s1.xpm"
91 # include "images/pacman/ghost-s2.xpm"
92 # include "images/pacman/ghost-sf1.xpm"
93 # include "images/pacman/ghost-sf2.xpm"
94 # include "images/pacman/eyes-l.xpm"
95 # include "images/pacman/eyes-r.xpm"
96 # include "images/pacman/eyes-u.xpm"
97 # include "images/pacman/eyes-d.xpm"
98 # include "images/pacman/pacman-ds1.xpm"
99 # include "images/pacman/pacman-ds2.xpm"
100 # include "images/pacman/pacman-ds3.xpm"
101 # include "images/pacman/pacman-ds4.xpm"
102 # include "images/pacman/pacman-ds5.xpm"
103 # include "images/pacman/pacman-ds6.xpm"
104 # include "images/pacman/pacman-ds7.xpm"
105 # include "images/pacman/pacman-ds8.xpm"
111 } dirvecs[DIRVECS] = { { -1, 0},
116 #ifdef DISABLE_INTERACTIVE
117 ENTRYPOINT ModeSpecOpt pacman_opts = {
119 (XrmOptionDescRec *) NULL,
122 (OptionStruct *) NULL
125 static XrmOptionDescRec opts[] = {
126 {"-trackmouse", ".pacman.trackmouse", XrmoptionNoArg, "on"},
127 {"+trackmouse", ".pacman.trackmouse", XrmoptionNoArg, "off"}
130 static argtype vars[] = {
131 {&trackmouse, "trackmouse", "TrackMouse", DEF_TRACKMOUSE, t_Bool}
134 static OptionStruct desc[] = {
135 {"-/+trackmouse", "turn on/off the tracking of the mouse"}
138 ENTRYPOINT ModeSpecOpt pacman_opts =
139 { sizeof opts / sizeof opts[0], opts, sizeof vars / sizeof vars[0], vars,
144 ModStruct pacman_description = {
145 "pacman", /* *cmdline_arg; */
146 "init_pacman", /* *init_name; */
147 "draw_pacman", /* *callback_name; */
148 "release_pacman", /* *release_name; */
149 "refresh_pacman", /* *refresh_name; */
150 "change_pacman", /* *change_name; */
151 (char *) NULL, /* *unused_name; */
152 &pacman_opts, /* *msopts */
153 10000, 4, 1, 0, 64, 1.0, "", "Shows Pacman(tm)", 0, NULL
159 pacmangamestruct *pacmangames = (pacmangamestruct *) NULL;
161 static void repopulate (ModeInfo * mi);
162 static void drawlevel (ModeInfo * mi);
166 free_pacman (Display * display, pacmangamestruct * pp)
168 int dir, mouth, i, j, k;
170 if (pp->ghosts != NULL) {
172 pp->ghosts = (ghoststruct *) NULL;
174 if (pp->stippledGC != None) {
175 XFreeGC (display, pp->stippledGC);
176 pp->stippledGC = None;
178 for (i = 0; i < 4; i++) {
179 for (j = 0; j < MAXGDIR; j++) {
180 for (k = 0; k < MAXGWAG; k++) {
181 if (pp->ghostPixmap[i][j][k] != None) {
182 XFreePixmap (display, pp->ghostPixmap[i][j][k]);
183 pp->ghostPixmap[i][j][k] = None;
188 for (dir = 0; dir < 4; dir++)
189 for (mouth = 0; mouth < MAXMOUTH; mouth++)
190 if (pp->pacmanPixmap[dir][mouth] != None) {
191 XFreePixmap (display, pp->pacmanPixmap[dir][mouth]);
192 pp->pacmanPixmap[dir][mouth] = None;
196 /* set pacman and the ghost in there starting positions, but don't draw a new
199 reset_level (ModeInfo * mi, int n, int pac_init)
201 pacmangamestruct *pp = &pacmangames[MI_SCREEN (mi)];
207 pp->gamestate = GHOST_DANGER;
210 pp->pacman.row = (LEVHEIGHT + JAILHEIGHT) / 2 - n;
211 pp->pacman.init_row = pp->pacman.row;
214 pp->pacman.row = pp->pacman.init_row;
216 pp->pacman.col = (LEVWIDTH / 2);
217 pp->pacman.nextrow = NOWHERE;
218 pp->pacman.nextcol = NOWHERE;
219 pp->pacman.cf = NOWHERE;
220 pp->pacman.rf = NOWHERE;
221 pp->pacman.oldcf = NOWHERE;
222 pp->pacman.oldrf = NOWHERE;
223 pp->pacman.oldlx = NOWHERE;
224 pp->pacman.oldly = NOWHERE;
225 pp->pacman.aistate = ps_eating;
226 pp->pacman.cur_trace = 0;
227 pp->pacman.roundscore = 0;
228 pp->pacman.speed = 4;
229 pp->pacman.lastturn = 0;
230 pp->pacman.delta.x = 0;
231 pp->pacman.delta.y = 0;
233 for (ghost = 0; ghost < pp->nghosts; ghost++) {
234 pp->ghosts[ghost].col = (LEVWIDTH / 2);
235 pp->ghosts[ghost].row = (LEVHEIGHT / 2);
236 pp->ghosts[ghost].nextcol = NOWHERE;
237 pp->ghosts[ghost].nextrow = NOWHERE;
238 pp->ghosts[ghost].dead = 0;
239 pp->ghosts[ghost].lastbox = START;
240 pp->ghosts[ghost].cf = NOWHERE;
241 pp->ghosts[ghost].rf = NOWHERE;
242 pp->ghosts[ghost].oldcf = NOWHERE;
243 pp->ghosts[ghost].oldrf = NOWHERE;
244 pp->ghosts[ghost].aistate = inbox;
245 pp->ghosts[ghost].timeleft = ghost * 20;
246 pp->ghosts[ghost].speed = 3;
247 pp->ghosts[ghost].delta.x = 0;
248 pp->ghosts[ghost].delta.y = 0;
249 pp->ghosts[ghost].flash_scared = False;
250 pp->ghosts[ghost].wait_pos = False;
251 ghost_update (pp, &(pp->ghosts[ghost]));
253 pac_update (mi, pp, &(pp->pacman));
257 pacman_ghost_collision(unsigned int ghost, pacmangamestruct * pp)
259 return (((pp->ghosts[ghost].nextrow == pp->pacman.nextrow) &&
260 (pp->ghosts[ghost].nextcol == pp->pacman.nextcol)) ||
261 ((pp->ghosts[ghost].nextrow == pp->pacman.row) &&
262 (pp->ghosts[ghost].nextcol == pp->pacman.col) &&
263 (pp->ghosts[ghost].row == pp->pacman.nextrow) &&
264 (pp->ghosts[ghost].col == pp->pacman.nextcol)));
268 /* Checks for death of any ghosts/pacman and updates. It also makes a new
269 level if all ghosts are dead or all dots are eaten. */
271 check_death (ModeInfo * mi, pacmangamestruct * pp)
273 Display *display = MI_DISPLAY (mi);
274 Window window = MI_WINDOW (mi);
278 if (pp->pacman.aistate == ps_dieing) return;
281 for (ghost = 0; ghost < pp->nghosts; ghost++) {
283 /* The ghost have to be scared before you can kill them */
284 if ( pacman_ghost_collision ( ghost, pp ) ) {
285 if (pp->ghosts[ghost].aistate == goingin) continue;
287 if (pp->ghosts[ghost].aistate == hiding) {
288 pp->ghosts[ghost].dead = 1;
289 pp->ghosts[ghost].aistate = goingin;
290 pp->ghosts[ghost].wait_pos = True;
291 XSetForeground (display, pp->stippledGC, MI_BLACK_PIXEL (mi));
292 XFillRectangle (display, window,
294 pp->ghosts[ghost].cf,
295 pp->ghosts[ghost].rf,
296 pp->spritexs, pp->spriteys);
301 pp->pacman.aistate = ps_dieing;
313 /* Resets state of ghosts + pacman. Creates a new level, draws that level. */
315 repopulate (ModeInfo * mi)
317 pacmangamestruct *pp = &pacmangames[MI_SCREEN (mi)];
318 pp->pacman.deaths = 0;
319 reset_level (mi, createnewlevel (pp), True);
320 check_death (mi, pp);
323 /* Sets the color to the color of a wall. */
325 setwallcolor (ModeInfo * mi)
327 Display *display = MI_DISPLAY (mi);
328 pacmangamestruct *pp = &pacmangames[MI_SCREEN (mi)];
330 if (MI_NPIXELS (mi) > 2)
331 XSetForeground (display, pp->stippledGC, MI_PIXEL (mi, BLUE));
333 XSetForeground (display, pp->stippledGC, MI_WHITE_PIXEL (mi));
336 /* Sets the color to the color of a dot. */
338 setdotcolor (ModeInfo * mi)
340 Display *display = MI_DISPLAY (mi);
341 pacmangamestruct *pp = &pacmangames[MI_SCREEN (mi)];
343 XSetForeground (display, pp->stippledGC, MI_WHITE_PIXEL (mi));
347 cleardotcolor (ModeInfo * mi)
349 Display *display = MI_DISPLAY (mi);
350 pacmangamestruct *pp = &pacmangames[MI_SCREEN (mi)];
352 XSetForeground (display, pp->stippledGC, MI_BLACK_PIXEL (mi));
357 draw_position (ModeInfo * mi, int x, int y, int color)
359 Display *display = MI_DISPLAY (mi);
360 Window window = MI_WINDOW (mi);
361 pacmangamestruct *pp = &pacmangames[MI_SCREEN (mi)];
362 XFontStruct *font = NULL;
363 char *f_name = "-*-utopia-*-r-*-*-*-600-*-*-p-*-*-*";
366 font = XLoadQueryFont (display, f_name);
367 assert (font != NULL);
369 s = (char *) malloc (256);
371 sprintf (s, "(%d,%d)", x, y);
372 XSetForeground (display, pp->stippledGC, color);
373 XDrawString (display, window, pp->stippledGC, x, y, s, strlen (s));
380 draw_number (ModeInfo * mi, int x, int y, int num, int color)
382 Display *display = MI_DISPLAY (mi);
383 Window window = MI_WINDOW (mi);
384 pacmangamestruct *pp = &pacmangames[MI_SCREEN (mi)];
385 XFontStruct *font = NULL;
386 char *f_name = "-*-utopia-*-r-*-*-*-600-*-*-p-*-*-*";
389 font = XLoadQueryFont (display, f_name);
390 assert (font != NULL);
392 s = (char *) malloc (256);
394 sprintf (s, "%d", num);
395 XSetForeground (display, pp->stippledGC, color);
396 XDrawString (display, window, pp->stippledGC, x, y, s, strlen (s));
403 /* draw_grid - draws a grid on top of the playing field.
404 * Used so that I can determine if I'm converting from rows and columns to x and y
405 * coordinates correctly.
408 draw_grid (ModeInfo * mi)
410 Display *display = MI_DISPLAY (mi);
411 Window window = MI_WINDOW (mi);
412 pacmangamestruct *pp = &pacmangames[MI_SCREEN (mi)];
413 int h = MI_HEIGHT (mi);
414 int w = MI_WIDTH (mi);
417 XSetForeground (display, pp->stippledGC, 0xff0000);
420 XDrawLine (display, window, pp->stippledGC, x, 0, x, h);
424 XDrawLine (display, window, pp->stippledGC, 0, y, w, y);
432 draw_string (ModeInfo * mi, int x, int y, char *s, int color)
434 Display *display = MI_DISPLAY (mi);
435 Window window = MI_WINDOW (mi);
436 pacmangamestruct *pp = &pacmangames[MI_SCREEN (mi)];
437 XFontStruct *font = NULL;
438 char *f_name = "-*-utopia-*-r-*-*-*-600-*-*-p-*-*-*";
440 font = XLoadQueryFont (display, f_name);
441 assert (font != NULL);
444 XSetForeground (display, pp->stippledGC, color);
445 XDrawString (display, window, pp->stippledGC, x, y, s, strlen (s));
449 /* I think this function has a memory leak. Be careful if you enable it. */
450 /* I only used it briefly to help me debug the ghost's aistate. It prints */
451 /* the state of each ghost on the left hand side of the screen */
453 print_ghost_stats (ModeInfo *mi, ghoststruct *g , int ghost_num)
457 sprintf (s, "GHOST: %d", ghost_num );
460 sprintf (s, "%s inbox", s);
463 sprintf (s, "%s goingout", s);
466 sprintf (s, "%s randdir", s);
469 sprintf (s, "%s chasing", s);
472 sprintf (s, "%s hiding", s);
475 sprintf (s, "%s goingin",s);
478 draw_string (mi, 0, (ghost_num *3) *10+50, g->last_stat, 0x000000);
479 draw_string (mi, 0, (ghost_num *3) *10+50, s, 0xff0000);
480 strcpy(g->last_stat,s);
483 /* prints the number of times pacman has died and his aistate on the left hand */
484 /* side of the screen */
486 print_pac_stats ( ModeInfo *mi, pacmanstruct *pac )
488 pacmangamestruct *pp = &pacmangames[MI_SCREEN (mi)];
490 sprintf (s, "Pacman, Deaths: %d", pac->deaths );
491 switch ( pac->aistate ){
493 sprintf(s, "%s ps_eating",s );
496 sprintf(s, "%s ps_chasing",s );
499 sprintf(s, "%s ps_hiding",s );
502 sprintf(s, "%s ps_random",s );
505 sprintf(s, "%s ps_dieing",s );
508 draw_string ( mi, 0, 200, pp->last_pac_stat, 0x000000);
509 draw_string ( mi, 0, 200, s, 0xff0000);
510 strcpy(pp->last_pac_stat, s );
515 /*Ok, yeah whatever?*/
516 /*dot_rc_to_pixel - magic that converts row and columns into
517 *the x and y coordinates of the screen.
520 dot_rc_to_pixel (ModeInfo * mi, int *x, int *y)
522 pacmangamestruct *pp = &pacmangames[MI_SCREEN (mi)];
524 (pp->xs / 2) - (pp->xs > 32 ? (pp->xs / 16) : 1) + pp->xb;
526 (pp->ys / 2) - (pp->ys > 32 ? (pp->ys / 16) : 1) + pp->yb;
529 /* dot_width_height - magic used to get the width and height of
530 * a dot. This dot can also be scaled by a value.
533 dot_width_height (ModeInfo *mi, int *w, int *h)
535 pacmangamestruct *pp = &pacmangames[MI_SCREEN (mi)];
537 *w = *h = (pp->xs / 32 );
544 bonus_dot_width_height (ModeInfo *mi, int *w, int *h )
546 *w = *h = MI_HEIGHT (mi) / 65;
552 draw_dot (ModeInfo * mi, pacmangamestruct * pp, int x, int y,
553 void (*width_height)(ModeInfo * mi, int *w, int *h),
554 int (*arc_func) (Display * display, Drawable d, GC gc,
555 int x, int y, unsigned int width,
556 unsigned int height, int angle1,
559 Display *display = MI_DISPLAY (mi);
560 Window window = MI_WINDOW (mi);
562 dot_rc_to_pixel (mi, &x, &y);
563 width_height(mi, &w, &h);
564 (void) arc_func (display, window, pp->stippledGC,
565 x, y, w, h, 0, 23040);
569 draw_bonus_dot (ModeInfo * mi, pacmangamestruct * pp, int x, int y)
574 draw_dot (mi, pp, x, y, bonus_dot_width_height, XFillArc);
575 dot_rc_to_pixel (mi, &x2, &y2);
577 draw_position (mi, x2, y2, 0xff0000);
582 clear_bonus_dot (ModeInfo * mi, pacmangamestruct * pp, int x, int y)
585 draw_dot (mi, pp, x, y, bonus_dot_width_height, XFillArc);
589 draw_regular_dot (ModeInfo * mi, pacmangamestruct * pp, int x, int y)
592 draw_dot (mi, pp, x, y, dot_width_height, XDrawArc);
595 /* Draws a block in the level at the specified x and y locations. */
597 drawlevelblock (ModeInfo * mi, pacmangamestruct * pp,
598 const unsigned x, const unsigned y)
600 Display *display = MI_DISPLAY (mi);
601 Window window = MI_WINDOW (mi);
610 XSetFillStyle (display, pp->stippledGC, FillSolid);
611 #endif /* !HAVE_COCOA */
612 XSetLineAttributes (display, pp->stippledGC, pp->wallwidth,
613 LineSolid, CapRound, JoinMiter);
615 if (pp->xs < 2 || pp->ys < 2) {
616 switch (pp->level[y * LEVWIDTH + x]) {
622 (void) XDrawPoint (display, window,
624 x * pp->xs + pp->xb, y * pp->ys + pp->yb);
628 (void) XDrawPoint (display, window,
630 x * pp->xs + pp->xb, y * pp->ys + pp->yb);
636 switch (pp->level[y * LEVWIDTH + x]) {
643 if (pp->xs < 8 || pp->ys < 8) {
644 (void) XDrawPoint (display, window,
646 x * pp->xs + pp->xb +
647 pp->xs / 2, y * pp->ys + pp->yb + pp->ys / 2);
651 draw_regular_dot (mi, pp, x, y);
653 /* What we will probably want to do here is have the pp->level store a 'o' for
654 * the bonus dots. The we can use the drawing routine above just with a bigger
658 draw_bonus_dot (mi, pp, x, y);
664 (void) XDrawLine (display, window, pp->stippledGC,
665 (pp->xs * x) + pp->xb,
666 (pp->ys * y) + (pp->ys / 2) + pp->yb,
667 (pp->xs * (x + 1)) + pp->xb,
668 (pp->ys * y) + (pp->ys / 2) + pp->yb);
673 (void) XDrawLine (display, window, pp->stippledGC,
674 (pp->xs * x) + (pp->xs / 2) + pp->xb,
675 (pp->ys * y) + pp->yb,
676 (pp->xs * x) + (pp->xs / 2) + pp->xb,
677 (pp->ys * (y + 1)) + pp->yb);
682 (void) XDrawArc (display, window, pp->stippledGC,
683 (pp->xs * x) - (pp->ys / 2) + pp->xb + dx,
684 (pp->ys * y) + (pp->ys / 2) + pp->yb,
685 pp->xs, pp->ys, 0 * 64, 90 * 64);
690 (void) XDrawArc (display, window, pp->stippledGC,
691 (pp->xs * x) + (pp->ys / 2) + pp->xb,
692 (pp->ys * y) + (pp->ys / 2) + pp->yb,
693 pp->xs, pp->ys, 90 * 64, 90 * 64);
698 (void) XDrawArc (display, window, pp->stippledGC,
699 (pp->xs * x) + (pp->ys / 2) + pp->xb,
700 (pp->ys * y) - (pp->ys / 2) + pp->yb + dy,
701 pp->xs, pp->ys, 180 * 64, 90 * 64);
706 (void) XDrawArc (display, window, pp->stippledGC,
707 (pp->xs * x) - (pp->ys / 2) + pp->xb + dx,
708 (pp->ys * y) - (pp->ys / 2) + pp->yb + dy,
709 pp->xs, pp->ys, 270 * 64, 90 * 64);
715 /* Draws a complete level. */
717 drawlevel (ModeInfo * mi)
719 pacmangamestruct *pp = &pacmangames[MI_SCREEN (mi)];
722 for (y = 0; y < LEVHEIGHT; y++)
723 for (x = 0; x < LEVWIDTH; x++)
724 drawlevelblock (mi, pp, x, y);
727 /* There is some overlap so it can be made more efficient */
728 #define ERASE_IMAGE(d,w,g,x,y,xl,yl,xs,ys) \
730 (y<(yl+ys))?XFillRectangle(d,w,g,xl,yl,xs,y-(yl)): \
731 XFillRectangle(d,w,g,xl,yl,xs,ys); \
733 (y>(yl-(ys)))?XFillRectangle(d,w,g,xl,y+ys,xs,yl-(y)): \
734 XFillRectangle(d,w,g,xl,yl,xs,ys); \
736 (x<(xl+xs))?XFillRectangle(d,w,g,xl,yl,x-(xl),ys): \
737 XFillRectangle(d,w,g,xl,yl,xs,ys); \
739 (x>(xl-(xs)))?XFillRectangle(d,w,g,x+xs,yl,xl-(x),ys): \
740 XFillRectangle(d,w,g,xl,yl,xs,ys)
743 /* Draws the pacman sprite, removing the previous location. */
744 #if defined(USE_PIXMAP)
747 draw_pacman_sprite (ModeInfo * mi)
749 Display *display = MI_DISPLAY (mi);
750 Window window = MI_WINDOW (mi);
751 pacmangamestruct *pp = &pacmangames[MI_SCREEN (mi)];
752 unsigned int dir = 0;
753 int old_mask_dir = 0;
754 int old_mask_mouth = 0;
755 Pixmap old_mask, new_mask;
758 #define MAX_MOUTH_DELAY 2
759 #define MAX_DEATH_DELAY 20
761 if (pp->pacman.aistate == ps_dieing){
762 pp->pacman.cf = pp->pacman.oldcf;
763 pp->pacman.rf = pp->pacman.oldrf;
766 pp->pacman.cf = pp->pacman.col * pp->xs + pp->pacman.delta.x *
767 pp->pacman.cfactor + pp->xb + pp->spritedx;
768 pp->pacman.rf = pp->pacman.row * pp->ys + pp->pacman.delta.y *
769 pp->pacman.rfactor + pp->yb + pp->spritedy;
772 dir = (ABS (pp->pacman.cfactor) * (2 - pp->pacman.cfactor) +
773 ABS (pp->pacman.rfactor) * (1 + pp->pacman.rfactor)) % 4;
775 if (pp->pm_mouth_delay == MAX_MOUTH_DELAY) {
776 if (pp->pm_mouth == (MAXMOUTH - 1) || pp->pm_mouth == 0) {
777 pp->pm_open_mouth = !pp->pm_open_mouth;
779 pp->pm_open_mouth ? pp->pm_mouth++ : pp->pm_mouth--;
780 pp->pm_mouth_delay = 0;
783 pp->pm_mouth_delay++;
786 if (pp->pacman.aistate == ps_dieing){
787 if (pp->pm_death_frame >= PAC_DEATH_FRAMES) {
788 pp->pacman.aistate = ps_eating;
789 pp->pm_death_frame = 0;
790 pp->pm_death_delay = 0;
791 reset_level (mi, 0, False);
795 old_mask = pp->pacmanMask[0][0];
796 new_mask = pp->pacmanMask[0][0];
797 pacman = pp->pacman_ds[pp->pm_death_frame];
798 if (pp->pm_death_delay == MAX_DEATH_DELAY){
799 pp->pm_death_frame++;
800 pp->pm_death_delay = 0;
803 pp->pm_death_delay++;
808 old_mask = pp->pacmanMask[old_mask_dir][old_mask_mouth];
809 new_mask = pp->pacmanMask[dir][pp->pm_mouth];
810 pacman = pp->pacmanPixmap[dir][pp->pm_mouth];
813 XSetForeground (display, pp->stippledGC, MI_BLACK_PIXEL (mi));
815 XSetClipMask (display, pp->stippledGC, old_mask);
817 XSetClipOrigin (display, pp->stippledGC, pp->pacman.oldcf,
819 XFillRectangle (display, window, pp->stippledGC, pp->pacman.oldcf,
820 pp->pacman.oldrf, pp->spritexs, pp->spriteys);
821 XSetClipMask (display, pp->stippledGC, new_mask);
822 XSetClipOrigin (display, pp->stippledGC, pp->pacman.cf, pp->pacman.rf);
823 XCopyArea (display, pacman, window,
824 pp->stippledGC, 0, 0, pp->spritexs, pp->spriteys,
825 pp->pacman.cf, pp->pacman.rf);
826 XSetClipMask (display, pp->stippledGC, None);
827 if (pp->pacman.aistate != ps_dieing){
828 pp->pacman.oldcf = pp->pacman.cf;
829 pp->pacman.oldrf = pp->pacman.rf;
832 old_mask_mouth = pp->pm_mouth;
837 draw_ghost_position (ModeInfo * mi, ghoststruct * ghost)
839 draw_position (mi, ghost->oldcf, ghost->oldrf, MI_BLACK_PIXEL (mi));
840 draw_position (mi, ghost->cf, ghost->rf, 0x00ff00);
845 draw_ghost_ndirs ( ModeInfo *mi, ghoststruct * ghost)
847 draw_number (mi, ghost->oldcf, ghost->oldrf, ghost->oldndirs, MI_BLACK_PIXEL (mi));
848 ghost->oldndirs = ghost->ndirs;
849 draw_number (mi, ghost->cf, ghost->rf, ghost->ndirs, 0x00ff00);
855 draw_ghost_sprite (ModeInfo * mi, const unsigned ghost)
857 Display *display = MI_DISPLAY (mi);
858 Window window = MI_WINDOW (mi);
859 pacmangamestruct *pp = &pacmangames[MI_SCREEN (mi)];
860 #define MAX_WAG_COUNT 50
861 unsigned int dir = 0;
862 unsigned int fs = 0; /*flash scared*/
863 Pixmap g_pix; /*ghost pixmap*/
866 dir = (ABS (pp->ghosts[ghost].cfactor) * (2 - pp->ghosts[ghost].cfactor) +
867 ABS (pp->ghosts[ghost].rfactor) * (1 + pp->ghosts[ghost].rfactor)) % 4;
870 fs = pp->ghosts[ghost].flash_scared;
871 assert (fs == 0 || fs == 1);
873 /* Choose the pixmap */
874 switch (pp->ghosts[ghost].aistate){
876 g_pix = pp->s_ghostPixmap[fs][pp->gh_wag];
879 g_pix = pp->ghostEyes[dir];
883 while ( i < pp->ghosts[ghost].trace_idx ){
884 XFillRectangle (display,
887 pp->ghosts[ghost].trace[i].vx,
888 pp->ghosts[ghost].trace[i].vy,
889 pp->spritexs, pp->spriteys);
898 g_pix = pp->ghostPixmap[ghost][dir][pp->gh_wag];
901 pp->ghosts[ghost].cf =
902 pp->ghosts[ghost].col * pp->xs + pp->ghosts[ghost].delta.x *
903 pp->ghosts[ghost].cfactor + pp->xb + pp->spritedx;
904 pp->ghosts[ghost].rf =
905 pp->ghosts[ghost].row * pp->ys + pp->ghosts[ghost].delta.y *
906 pp->ghosts[ghost].rfactor + pp->yb + pp->spritedy;
908 XSetForeground (display, pp->stippledGC, MI_BLACK_PIXEL (mi));
910 XSetClipMask (display, pp->stippledGC, pp->ghostMask);
911 XSetClipOrigin (display, pp->stippledGC,
912 pp->ghosts[ghost].oldcf, pp->ghosts[ghost].oldrf);
913 XFillRectangle (display,
916 pp->ghosts[ghost].oldcf,
917 pp->ghosts[ghost].oldrf, pp->spritexs, pp->spriteys);
920 if (pp->pacman.aistate != ps_dieing) {
921 drawlevelblock (mi, pp,
922 (unsigned int) pp->ghosts[ghost].col,
923 (unsigned int) pp->ghosts[ghost].row);
927 XSetClipOrigin (display, pp->stippledGC,
928 pp->ghosts[ghost].cf, pp->ghosts[ghost].rf);
930 XCopyArea (display, g_pix, window, pp->stippledGC, 0, 0,
931 pp->spritexs, pp->spriteys, pp->ghosts[ghost].cf,
932 pp->ghosts[ghost].rf);
934 XSetClipMask (display, pp->stippledGC, None);
937 draw_ghost_position (mi, &(pp->ghosts[ghost]));
941 draw_ghost_ndirs ( mi, &(pp->ghosts[ghost]));
944 if (pp->pacman.aistate != ps_dieing) {
945 pp->ghosts[ghost].oldcf = pp->ghosts[ghost].cf;
946 pp->ghosts[ghost].oldrf = pp->ghosts[ghost].rf;
947 if (pp->gh_wag_count++ == MAX_WAG_COUNT) {
948 pp->gh_wag = !pp->gh_wag;
949 pp->gh_wag_count = 0;
954 #else /* USE_PIXMAP */
956 /* Draws the pacman sprite, removing the previous location. */
958 draw_pacman_sprite (ModeInfo * mi)
960 Display *display = MI_DISPLAY (mi);
961 Window window = MI_WINDOW (mi);
962 pacmangamestruct *pp = &pacmangames[MI_SCREEN (mi)];
965 pp->pacman.cf = pp->pacman.col * pp->xs + pp->pacman.delta.x *
966 pp->pacman.cfactor + pp->xb + pp->spritedx;
967 pp->pacman.rf = pp->pacman.row * pp->ys + pp->pacman.delta.y *
968 pp->pacman.rfactor + pp->yb + pp->spritedy;
970 dir = (ABS (pp->pacman.cfactor) * (2 - pp->pacman.cfactor) +
971 ABS (pp->pacman.rfactor) * (1 + pp->pacman.rfactor)) % 4;
973 XSetForeground (display, pp->stippledGC, MI_BLACK_PIXEL (mi));
974 if (pp->pacman.oldcf != NOWHERE && pp->pacman.oldrf != NOWHERE) {
976 ERASE_IMAGE (display, window, pp->stippledGC,
977 pp->pacman.cf, pp->pacman.rf,
978 pp->pacman.oldcf, pp->pacman.oldrf,
979 pp->spritexs, pp->spriteys);
982 if (MI_NPIXELS (mi) > 2)
983 XSetForeground (display, pp->stippledGC, MI_PIXEL (mi, YELLOW));
985 XSetForeground (display, pp->stippledGC, MI_WHITE_PIXEL (mi));
987 XSetFillStyle (display, pp->stippledGC, FillOpaqueStippled);
989 if (pp->xs < 2 || pp->ys < 2)
990 XDrawPoint (display, window, pp->stippledGC,
991 pp->pacman.cf, pp->pacman.rf);
993 XFillRectangle (display, window, pp->stippledGC,
994 pp->pacman.cf, pp->pacman.rf,
995 pp->spritexs, pp->spriteys);
996 pp->pacman.mouthstage += pp->pacman.mouthdirection;
997 if ((pp->pacman.mouthstage >= MAXMOUTH) || (pp->pacman.mouthstage < 0)) {
998 pp->pacman.mouthdirection *= -1;
999 pp->pacman.mouthstage += pp->pacman.mouthdirection * 2;
1001 pp->pacman.oldcf = pp->pacman.cf;
1002 pp->pacman.oldrf = pp->pacman.rf;
1005 /* Draws a ghost sprite, removing the previous sprite and restores the level. */
1007 draw_ghost_sprite (ModeInfo * mi, const unsigned ghost)
1009 Display *display = MI_DISPLAY (mi);
1010 Window window = MI_WINDOW (mi);
1011 pacmangamestruct *pp = &pacmangames[MI_SCREEN (mi)];
1013 pp->ghosts[ghost].cf =
1014 pp->ghosts[ghost].col * pp->xs + pp->ghosts[ghost].delta.x *
1015 pp->ghosts[ghost].cfactor + pp->xb + pp->spritedx;
1016 pp->ghosts[ghost].rf =
1017 pp->ghosts[ghost].row * pp->ys + pp->ghosts[ghost].delta.y *
1018 pp->ghosts[ghost].rfactor + pp->yb + pp->spritedy;
1020 XSetForeground (display, pp->stippledGC, MI_BLACK_PIXEL (mi));
1021 XFillRectangle (display,
1024 pp->ghosts[ghost].cf,
1025 pp->ghosts[ghost].rf, pp->spritexs, pp->spriteys);
1027 if (pp->ghosts[ghost].oldcf != NOWHERE ||
1028 pp->ghosts[ghost].oldrf != NOWHERE) {
1030 ERASE_IMAGE (display, window, pp->stippledGC,
1031 pp->ghosts[ghost].cf, pp->ghosts[ghost].rf,
1032 pp->ghosts[ghost].oldcf, pp->ghosts[ghost].oldrf,
1033 pp->spritexs, pp->spriteys);
1036 drawlevelblock (mi, pp,
1037 (unsigned int) pp->ghosts[ghost].col,
1038 (unsigned int) pp->ghosts[ghost].row);
1040 if (MI_NPIXELS (mi) > 2)
1041 XSetForeground (display, pp->stippledGC, MI_PIXEL (mi, GREEN));
1043 XSetForeground (display, pp->stippledGC, MI_WHITE_PIXEL (mi));
1045 XSetFillStyle (display, pp->stippledGC, FillOpaqueStippled);
1047 if (pp->xs < 2 || pp->ys < 2)
1048 XDrawPoint (display, window, pp->stippledGC,
1049 pp->ghosts[ghost].cf, pp->ghosts[ghost].rf);
1051 XFillRectangle (display,
1054 pp->ghosts[ghost].cf,
1055 pp->ghosts[ghost].rf, pp->spritexs, pp->spriteys);
1057 pp->ghosts[ghost].oldcf = pp->ghosts[ghost].cf;
1058 pp->ghosts[ghost].oldrf = pp->ghosts[ghost].rf;
1060 #endif /* USE_PIXMAP */
1063 ghost_over (ModeInfo * mi, int x, int y)
1067 pacmangamestruct *pp = &pacmangames[MI_SCREEN (mi)];
1068 dot_rc_to_pixel (mi, &x, &y);
1069 for (ghost = 0; ghost < pp->nghosts; ghost++) {
1070 if ((pp->ghosts[ghost].cf <= x
1071 && x <= pp->ghosts[ghost].cf + pp->spritexs)
1072 && (pp->ghosts[ghost].rf <= y
1073 && y <= pp->ghosts[ghost].rf + pp->spriteys)) {
1083 flash_bonus_dots (ModeInfo * mi)
1085 #define MAX_FLASH_COUNT 25
1086 pacmangamestruct *pp = &pacmangames[MI_SCREEN (mi)];
1088 for (i = 0; i < NUM_BONUS_DOTS; i++) {
1089 if (!bonus_dot_eaten (pp, i)) {
1090 bonus_dot_pos (pp, i, &x, &y);
1091 if (ghost_over (mi, x, y))
1094 draw_bonus_dot (mi, pp, x, y);
1096 clear_bonus_dot (mi, pp, x, y);
1099 if (pp->bd_flash_count-- == 0) {
1100 pp->bd_flash_count = MAX_FLASH_COUNT;
1101 pp->bd_on = !pp->bd_on;
1106 ate_bonus_dot (ModeInfo * mi)
1108 /*Check pacman's position. If it is over a bonus dot and that dot
1109 *has not been eaten, then return true
1111 unsigned int ret = 0;
1113 pacmangamestruct *pp = &pacmangames[MI_SCREEN (mi)];
1114 if (is_bonus_dot (pp, pp->pacman.col, pp->pacman.row, &idx)) {
1115 ret = !bonus_dot_eaten (pp, idx);
1116 eat_bonus_dot (pp, idx);
1122 ghost_scared (ModeInfo * mi)
1125 pacmangamestruct *pp = &pacmangames[MI_SCREEN (mi)];
1126 for (ghost = 0; ghost < pp->nghosts; ghost++) {
1127 if (pp->ghosts[ghost].aistate == goingin ||
1128 pp->ghosts[ghost].aistate == goingout ||
1129 pp->ghosts[ghost].aistate == inbox ) continue;
1130 pp->ghosts[ghost].aistate = hiding;
1131 pp->ghosts[ghost].flash_scared = 0;
1132 if (pp->pacman.aistate != ps_dieing)
1133 pp->pacman.aistate = ps_chasing;
1138 ghost_not_scared (ModeInfo * mi)
1141 pacmangamestruct *pp = &pacmangames[MI_SCREEN (mi)];
1142 for (ghost = 0; ghost < pp->nghosts; ghost++){
1143 if (pp->ghosts[ghost].aistate == goingin ||
1144 pp->ghosts[ghost].aistate == goingout ||
1145 pp->ghosts[ghost].aistate == inbox ) continue;
1146 pp->ghosts[ghost].aistate = chasing;
1148 if (pp->pacman.aistate != ps_dieing)
1149 pp->pacman.aistate = ps_eating;
1154 ghost_flash_scared (ModeInfo * mi)
1157 pacmangamestruct *pp = &pacmangames[MI_SCREEN (mi)];
1158 for (ghost = 0; ghost < pp->nghosts; ghost++)
1159 pp->ghosts[ghost].flash_scared = !pp->ghosts[ghost].flash_scared;
1162 /* Does all drawing of moving sprites in the level. */
1164 pacman_tick (ModeInfo * mi)
1166 #define DEFAULT_SCARED_TIME 500
1167 #define START_FLASH 200
1168 #define FLASH_COUNT 25
1170 pacmangamestruct *pp = &pacmangames[MI_SCREEN (mi)];
1175 for (ghost = 0; ghost < pp->nghosts; ghost++) {
1176 draw_ghost_sprite (mi, ghost);
1178 print_ghost_stats (mi, &(pp->ghosts[ghost]), ghost);
1182 print_pac_stats (mi, &(pp->pacman));
1184 draw_pacman_sprite (mi);
1185 flash_bonus_dots (mi);
1186 if (ate_bonus_dot (mi)) {
1187 pp->ghost_scared_timer = (random () % 100) + DEFAULT_SCARED_TIME;
1191 if (pp->ghost_scared_timer > 0) {
1192 if (--pp->ghost_scared_timer == 0)
1193 ghost_not_scared (mi);
1194 else if (pp->ghost_scared_timer <= START_FLASH) {
1195 if (pp->flash_timer <= 0) {
1196 pp->flash_timer = FLASH_COUNT;
1197 ghost_flash_scared (mi);
1204 We don't want to miss the last death sequence. So if pacman has died three times
1205 we wait for his state to change from dieing to something else before we repopulate
1206 the level. If pacman ate all of the dots then we just repopulate.
1209 if (pp->dotsleft == 0 )
1211 else if (pp->pacman.deaths >= 3){
1212 if (pp->old_pac_state == ps_dieing && pp->pacman.aistate != ps_dieing)
1216 pp->old_pac_state = pp->pacman.aistate;
1220 /* CODE TO LOAD AND SCALE THE PIXMAPS
1223 #if defined(USE_PIXMAP)
1224 /* Grabbed the scaling routine off of usenet.
1225 * Changed it so that the information specific
1226 * to the source pixmap does not have to be a parameter.
1228 * There is probably a better way to scale pixmaps.
1229 * From: Chris Fiddyment (cxf@itd.dsto.gov.au)
1230 * Subject: Scaling Pixmap Algorithm.
1231 * Newsgroups: comp.graphics.algorithms
1232 * Date: 1994-07-06 18:51:38 PST
1237 scale_pixmap (Display ** dpy, GC gc, Pixmap source, int dwidth, int dheight)
1242 float xscale, yscale;
1243 unsigned int swidth, sheight;
1246 unsigned border_width_return, depth;
1247 XGetGeometry (*dpy, source, &window, &x, &y, &swidth, &sheight,
1248 &border_width_return, &depth);
1250 xscale = (float) swidth / (float) dwidth; /* Scaling factors */
1251 yscale = (float) sheight / (float) dheight;
1253 dest = XCreatePixmap (*dpy, window, dwidth, dheight, depth);
1255 fprintf (stderr, "%s Could not scale image", progname);
1257 temp = XCreatePixmap (*dpy, window, dwidth, sheight, depth);
1259 fprintf (stderr, "%s Could not scale image", progname);
1263 end = dwidth * xscale;
1264 /* Scale width of source into temp pixmap */
1265 for (i = 0; i <= end; i += xscale)
1266 XCopyArea (*dpy, source, temp, gc, i, 0, 1, sheight, j++, 0);
1269 end = dheight * yscale;
1270 /* Scale height of temp into dest pixmap */
1271 for (i = 0; i <= end; i += yscale)
1272 XCopyArea (*dpy, temp, dest, gc, 0, i, swidth, 1, 0, j++);
1274 XFreePixmap (*dpy, temp);
1275 return (Pixmap) dest;
1279 pacman_fail (char *s)
1281 fprintf (stderr, "%s: %s\n", progname, s);
1285 /* Load the ghost pixmaps and their mask. */
1287 load_ghost_pixmaps (Display ** dpy, Window window, pacmangamestruct ** ps)
1289 pacmangamestruct *pp = *ps;
1290 Display *display = *dpy;
1292 ". c #FF0000", /*Red */
1293 ". c #00FFDE", /*Blue */
1294 ". c #FFB847", /*Orange */
1295 ". c #FFB8DE", /*Pink */
1299 ghost_u1_xpm, ghost_u2_xpm, ghost_r1_xpm, ghost_r2_xpm,
1300 ghost_d1_xpm, ghost_d2_xpm, ghost_l1_xpm, ghost_l2_xpm
1302 char * const *s_bits[] = {
1303 ghost_s1_xpm, ghost_s2_xpm,
1304 ghost_sf1_xpm, ghost_sf2_xpm
1306 char * const *e_bits[] = {
1307 eyes_u_xpm, eyes_r_xpm, eyes_d_xpm, eyes_l_xpm
1311 int w = pp->spritexs;
1312 int h = pp->spriteys;
1316 for (i = 0; i < 4; i++) {
1318 for (j = 0; j < MAXGDIR; j++) {
1319 for (k = 0; k < MAXGWAG; k++) {
1320 bits[m][2] = colors[i];
1321 pp->ghostPixmap[i][j][k] =
1322 xpm_data_to_pixmap (display, window, bits[m], &w, &h,
1325 if (!pp->ghostPixmap[i][j][k])
1326 pacman_fail ("Cannot load ghost images");
1328 pp->ghostPixmap[i][j][k] =
1329 scale_pixmap (&display, pp->stippledGC,
1330 pp->ghostPixmap[i][j][k], pp->spritexs,
1333 if (!pp->ghostPixmap[i][j][k])
1334 pacman_fail ("Cannot scale ghost images");
1339 /* load the scared ghost */
1341 for (i = 0; i < MAXGFLASH; i++) {
1342 for (j = 0; j < MAXGWAG; j++) {
1343 pp->s_ghostPixmap[i][j] =
1344 xpm_data_to_pixmap (display, window, s_bits[m++], &w, &h,
1347 if (!pp->s_ghostPixmap[i][j])
1348 pacman_fail ("Cannot Scare Ghost images");
1349 pp->s_ghostPixmap[i][j] = scale_pixmap (&display, pp->stippledGC,
1350 pp->s_ghostPixmap[i][j],
1354 if (!pp->s_ghostPixmap[i][j])
1355 pacman_fail ("Cannot scale Scared Ghost images");
1358 /* load the ghost eyes */
1359 for (i = 0; i < MAXGDIR; i++) {
1361 xpm_data_to_pixmap (display, window, e_bits[i], &w, &h,
1364 if (!pp->ghostEyes[i])
1365 pacman_fail ("Cannot open ghost eye images");
1367 pp->ghostEyes[i] = scale_pixmap (&display, pp->stippledGC,
1372 if (!pp->ghostEyes[i])
1373 pacman_fail ("Cannot open ghost eye images");
1378 /* We really only need a single mask. This saves the headache of getting the
1379 * bottom of the ghost to clip just right. What we'll do is mask
1380 * the top portion of the ghost, but the bottom of the ghost will be solid.
1381 * I did this by setting the pixels between the fringe of their sheets
1382 * to black instead of none. -jeremy
1384 temp = xpm_data_to_pixmap (display, window, ghost_mask_xpm,
1385 &w, &h, &pp->ghostMask);
1388 pacman_fail ("Cannot load temporary ghost image");
1390 temp = scale_pixmap (&display, pp->stippledGC,
1391 temp, pp->spritexs, pp->spriteys);
1394 pacman_fail ("Cannot scale temporary ghost image");
1396 gc = XCreateGC (display, pp->ghostMask, 0, 0);
1398 pp->ghostMask = scale_pixmap (&display, gc, pp->ghostMask,
1399 pp->spritexs, pp->spriteys);
1400 XFreePixmap (display, temp);
1403 /* Load the pacman pixmaps and their mask. */
1405 load_pacman_pixmaps (Display ** dpy, Window window, pacmangamestruct ** ps)
1407 pacmangamestruct *pp = *ps;
1408 Display *display = *dpy;
1411 pacman_0_xpm, pacman_u1_xpm, pacman_u2_xpm,
1412 pacman_0_xpm, pacman_r1_xpm, pacman_r2_xpm,
1413 pacman_0_xpm, pacman_d1_xpm, pacman_d2_xpm,
1414 pacman_0_xpm, pacman_l1_xpm, pacman_l2_xpm
1417 char * const *ds_bits[] = {
1418 pacman_ds1_xpm, pacman_ds2_xpm, pacman_ds3_xpm, pacman_ds4_xpm,
1419 pacman_ds5_xpm, pacman_ds6_xpm, pacman_ds7_xpm, pacman_ds8_xpm
1423 int w = pp->spritexs;
1424 int h = pp->spriteys;
1428 for (i = 0; i < 4; i++) {
1429 for (j = 0; j < MAXMOUTH; j++) {
1430 pp->pacmanPixmap[i][j] =
1431 xpm_data_to_pixmap (display, window, bits[m++], &w, &h,
1432 &pp->pacmanMask[i][j]);
1434 if (!pp->pacmanPixmap[i][j])
1435 pacman_fail ("Cannot load pacman pixmap.");
1437 pp->pacmanPixmap[i][j] = scale_pixmap (&display, pp->stippledGC,
1438 pp->pacmanPixmap[i][j],
1442 if (!pp->pacmanPixmap[i][j])
1443 pacman_fail ("Cannot scale pacman pixmap.");
1446 gc = XCreateGC (display, pp->pacmanMask[i][j], 0, 0);
1448 pp->pacmanMask[i][j] =
1449 scale_pixmap (&display, gc, pp->pacmanMask[i][j],
1450 pp->spritexs, pp->spriteys);
1454 /* Load pacman death sequence */
1455 for ( i = 0; i < PAC_DEATH_FRAMES; i++ ){
1457 xpm_data_to_pixmap (display, window, ds_bits[i], &w, &h,
1458 &pp->pacman_ds_mask[i]);
1460 if (!pp->pacman_ds[i])
1461 pacman_fail ("Cannot load pacman death frame.");
1463 pp->pacman_ds[i] = scale_pixmap ( &display, pp->stippledGC,
1468 if (!pp->pacman_ds[i])
1469 pacman_fail ("Cannot scale pixmap.");
1472 gc = XCreateGC (display, pp->pacman_ds_mask[i], 0, 0);
1474 pp->pacman_ds_mask[i] =
1475 scale_pixmap (&display, gc, pp->pacman_ds_mask[i],
1476 pp->spritexs, pp->spriteys);
1480 #endif /* USE_PIXMAP */
1482 /* Hook function, sets state to initial position. */
1484 init_pacman (ModeInfo * mi)
1486 Display *display = MI_DISPLAY (mi);
1487 Window window = MI_WINDOW (mi);
1488 int size = MI_SIZE (mi);
1489 pacmangamestruct *pp;
1493 #if (! defined( USE_PIXMAP ))
1499 if (pacmangames == NULL) {
1500 if ((pacmangames = (pacmangamestruct *)
1501 calloc ((size_t) MI_NUM_SCREENS (mi),
1502 sizeof (pacmangamestruct))) == NULL)
1505 pp = &pacmangames[MI_SCREEN (mi)];
1507 pp->width = (unsigned short) MI_WIDTH (mi);
1508 pp->height = (unsigned short) MI_HEIGHT (mi);
1509 for (i = 0; i < 4; i++) {
1510 for (j = 0; j < MAXGDIR; j++) {
1511 for (k = 0; k < MAXGWAG; k++) {
1512 if (pp->ghostPixmap[i][j][k] != None) {
1513 XFreePixmap (display, pp->ghostPixmap[i][j][k]);
1514 pp->ghostPixmap[i][j][k] = None;
1515 pp->graphics_format = 0 /*IS_NONE */ ;
1521 for (i = 0; i < MAXGFLASH; i++) {
1522 for (j = 0; j < MAXGWAG; j++) {
1523 if (pp->s_ghostPixmap[i][j] != None) {
1524 XFreePixmap (display, pp->s_ghostPixmap[i][j]);
1525 pp->s_ghostPixmap[i][j] = None;
1531 MINGRIDSIZE * size > (int) pp->width ||
1532 MINGRIDSIZE * size > (int) pp->height) {
1534 pp->ys = pp->xs = MAX (MIN (pp->width / LEVWIDTH,
1535 pp->height / LEVHEIGHT), 1);
1538 if (size < -MINSIZE)
1539 pp->ys = (short) (NRAND (MIN (-size, MAX (MINSIZE,
1543 - MINSIZE + 1) + MINSIZE);
1544 else if (size < MINSIZE)
1547 pp->ys = (short) (MIN (size,
1548 MAX (MINSIZE, MIN (pp->width, pp->height) /
1553 pp->wallwidth = (unsigned int) (pp->xs + pp->ys) >> 4;
1554 if (pp->wallwidth < 1)
1556 pp->incx = (pp->xs >> 3) + 1;
1557 pp->incy = (pp->ys >> 3) + 1;
1558 pp->ncols = (unsigned short) MAX (LEVWIDTH, 2);
1559 pp->nrows = (unsigned short) MAX (LEVHEIGHT, 2);
1560 pp->xb = (pp->width - pp->ncols * pp->xs) >> 1;
1561 pp->yb = (pp->height - pp->nrows * pp->ys) >> 1;
1562 pp->spritexs = MAX (pp->xs + (pp->xs >> 1) - 1, 1);
1563 pp->spriteys = MAX (pp->ys + (pp->ys >> 1) - 1, 1);
1564 pp->spritedx = (pp->xs - pp->spritexs) >> 1;
1565 pp->spritedy = (pp->ys - pp->spriteys) >> 1;
1566 pp->old_pac_state = chasing;
1568 if (!pp->stippledGC) {
1569 gcv.foreground = MI_BLACK_PIXEL (mi);
1570 gcv.background = MI_BLACK_PIXEL (mi);
1571 if ((pp->stippledGC = XCreateGC (display, window,
1572 GCForeground | GCBackground,
1574 free_pacman (display, pp);
1580 jwxyz_XSetAntiAliasing (display, pp->stippledGC, False);
1583 #if defined(USE_PIXMAP)
1584 load_ghost_pixmaps (&display, window, &pp);
1585 load_pacman_pixmaps (&display, window, &pp);
1587 if ((pp->ghostPixmap[0][0][0] = XCreatePixmap (display, window,
1588 pp->spritexs, pp->spriteys,
1590 free_pacman (display, pp);
1596 if ((bg_gc = XCreateGC (display, pp->ghostPixmap[0][0][0],
1597 GCForeground | GCBackground, &gcv)) == None) {
1598 free_pacman (display, pp);
1604 if ((fg_gc = XCreateGC (display, pp->ghostPixmap[0][0][0],
1605 GCForeground | GCBackground, &gcv)) == None) {
1606 XFreeGC (display, bg_gc);
1607 free_pacman (display, pp);
1611 #define SETPOINT(p, xp, yp) p.x = xp; p.y = yp
1613 /* draw the triangles on the bottom (scalable) */
1614 SETPOINT (points[0], 1, pp->spriteys * 5 / 6);
1615 SETPOINT (points[1], pp->spritexs / 6, pp->spriteys);
1616 SETPOINT (points[2], pp->spritexs / 3, pp->spriteys * 5 / 6);
1617 SETPOINT (points[3], pp->spritexs / 2, pp->spriteys);
1618 SETPOINT (points[4], pp->spritexs * 2 / 3, pp->spriteys * 5 / 6);
1619 SETPOINT (points[5], pp->spritexs * 5 / 6, pp->spriteys);
1620 SETPOINT (points[6], pp->spritexs, pp->spriteys * 5 / 6);
1621 SETPOINT (points[7], pp->spritexs, pp->spriteys / 2);
1622 SETPOINT (points[8], 1, pp->spriteys / 2);
1624 XFillRectangle (display, pp->ghostPixmap[0][0][0], bg_gc,
1625 0, 0, pp->spritexs, pp->spriteys);
1626 XFillArc (display, pp->ghostPixmap[0][0][0], fg_gc,
1627 0, 0, pp->spritexs, pp->spriteys, 0, 11520);
1628 XFillPolygon (display, pp->ghostPixmap[0][0][0], fg_gc,
1629 points, 9, Nonconvex, CoordModeOrigin);
1630 XFreeGC (display, bg_gc);
1631 XFreeGC (display, fg_gc);
1634 if (pp->pacmanPixmap[0][0] != None)
1635 for (dir = 0; dir < 4; dir++)
1636 for (mouth = 0; mouth < MAXMOUTH; mouth++)
1637 XFreePixmap (display, pp->pacmanPixmap[dir]
1640 for (dir = 0; dir < 4; dir++)
1641 for (mouth = 0; mouth < MAXMOUTH; mouth++) {
1642 if ((pp->pacmanPixmap[dir][mouth] =
1643 XCreatePixmap (display, MI_WINDOW (mi), pp->spritexs,
1644 pp->spriteys, 1)) == None) {
1645 free_pacman (display, pp);
1650 if ((fg_gc = XCreateGC (display, pp->pacmanPixmap[dir][mouth],
1651 GCForeground | GCBackground,
1653 free_pacman (display, pp);
1658 if ((bg_gc = XCreateGC (display,
1659 pp->pacmanPixmap[dir][mouth],
1661 GCBackground, &gcv)) == None) {
1662 XFreeGC (display, fg_gc);
1663 free_pacman (display, pp);
1666 XFillRectangle (display,
1667 pp->pacmanPixmap[dir][mouth], bg_gc,
1668 0, 0, pp->spritexs, pp->spriteys);
1669 if (pp->spritexs == 1 && pp->spriteys == 1)
1670 XFillRectangle (display,
1671 pp->pacmanPixmap[dir][mouth],
1672 fg_gc, 0, 0, pp->spritexs, pp->spriteys);
1675 pp->pacmanPixmap[dir][mouth],
1677 0, 0, pp->spritexs, pp->spriteys,
1678 ((90 - dir * 90) + mouth * 5) * 64,
1679 (360 + (-2 * mouth * 5)) * 64);
1680 XFreeGC (display, fg_gc);
1681 XFreeGC (display, bg_gc);
1683 #endif /* USE_PIXMAP */
1685 pp->pacman.lastbox = START;
1686 pp->pacman.mouthdirection = 1;
1687 pp->pacman.nextcol = NOWHERE;
1688 pp->pacman.nextrow = NOWHERE;
1690 if (pp->ghosts != NULL) {
1692 pp->ghosts = (ghoststruct *) NULL;
1694 pp->nghosts = GHOSTS;
1697 if ((pp->ghosts = (ghoststruct *) calloc ((size_t) pp->nghosts,
1698 sizeof (ghoststruct))) ==
1700 free_pacman (display, pp);
1704 pp->pacman.mouthstage = MAXMOUTH - 1;
1706 MI_CLEARWINDOW (mi);
1710 /* Callback function called for each tick. This is the complete machinery of
1711 everything that moves. */
1713 draw_pacman (ModeInfo * mi)
1716 pacmangamestruct *pp;
1718 if (pacmangames == NULL)
1720 pp = &pacmangames[MI_SCREEN (mi)];
1721 if (pp->ghosts == NULL)
1724 pp->pacman.err.x = (pp->pacman.err.x + 1) % pp->pacman.speed;
1725 pp->pacman.err.y = (pp->pacman.err.y + 1) % pp->pacman.speed;
1726 pp->pacman.delta.x += pp->pacman.err.x != 0 ? pp->incx : 0;
1727 pp->pacman.delta.y += pp->pacman.err.y != 0 ? pp->incy : 0;
1729 if (pp->pacman.delta.x >= pp->xs && pp->pacman.delta.y >= pp->ys) {
1730 pac_update (mi, pp, &(pp->pacman));
1731 check_death (mi, pp);
1732 pp->pacman.delta.x = pp->incx;
1733 pp->pacman.delta.y = pp->incy;
1736 if (pp->pacman.delta.x > pp->xs + pp->incx)
1737 pp->pacman.delta.x = pp->xs + pp->incx;
1738 if (pp->pacman.delta.y > pp->ys + pp->incy)
1739 pp->pacman.delta.y = pp->ys + pp->incy;
1741 for (g = 0; g < pp->nghosts; g++) {
1742 pp->ghosts[g].err.x = (pp->ghosts[g].err.x + 1) % pp->ghosts[g].speed;
1743 pp->ghosts[g].err.y = (pp->ghosts[g].err.y + 1) % pp->ghosts[g].speed;
1744 pp->ghosts[g].delta.x += pp->ghosts[g].err.x != 0 ? pp->incx : 0;
1745 pp->ghosts[g].delta.y += pp->ghosts[g].err.y != 0 ? pp->incy : 0;
1747 if (pp->ghosts[g].delta.x >= pp->xs &&
1748 pp->ghosts[g].delta.y >= pp->ys) {
1749 ghost_update (pp, &(pp->ghosts[g]));
1750 pp->ghosts[g].delta.x = pp->incx;
1751 pp->ghosts[g].delta.y = pp->incy;
1754 if (pp->ghosts[g].delta.x > pp->xs + pp->incx)
1755 pp->ghosts[g].delta.x = pp->xs + pp->incx;
1756 if (pp->ghosts[g].delta.y > pp->ys + pp->incy)
1757 pp->ghosts[g].delta.y = pp->ys + pp->incy;
1762 /* Releases resources. */
1764 release_pacman (ModeInfo * mi)
1766 if (pacmangames != NULL) {
1769 for (screen = 0; screen < MI_NUM_SCREENS (mi); screen++)
1770 free_pacman (MI_DISPLAY (mi), &pacmangames[screen]);
1772 pacmangames = (pacmangamestruct *) NULL;
1776 /* Refresh current level. */
1778 refresh_pacman (ModeInfo * mi)
1785 /* Callback to change level. */
1787 change_pacman (ModeInfo * mi)
1789 MI_CLEARWINDOW (mi);
1792 #endif /* !STANDALONE */
1795 XSCREENSAVER_MODULE ("Pacman", pacman)
1797 #endif /* MODE_pacman */