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" \
55 "*fpsSolid: true \n" \
57 # define UNIFORM_COLORS
58 # define BRIGHT_COLORS
59 # define reshape_pacman 0
60 # define pacman_handle_event 0
61 # include "xlockmore.h" /* in xscreensaver distribution */
63 #else /* STANDALONE */
64 # include "xlock.h" /* in xlockmore distribution */
65 #endif /* STANDALONE */
70 #include "pacman_ai.h"
71 #include "pacman_level.h"
73 #if defined(USE_PIXMAP) /* computed in pacman.h */
74 # include "images/pacman/ghost-u1.xpm"
75 # include "images/pacman/ghost-u2.xpm"
76 # include "images/pacman/ghost-r1.xpm"
77 # include "images/pacman/ghost-r2.xpm"
78 # include "images/pacman/ghost-l1.xpm"
79 # include "images/pacman/ghost-l2.xpm"
80 # include "images/pacman/ghost-d1.xpm"
81 # include "images/pacman/ghost-d2.xpm"
82 /* Used to clean up the dust left by wag. */
83 # include "images/pacman/ghost-mask.xpm"
84 # include "images/pacman/pacman-u1.xpm"
85 # include "images/pacman/pacman-u2.xpm"
86 # include "images/pacman/pacman-r1.xpm"
87 # include "images/pacman/pacman-r2.xpm"
88 # include "images/pacman/pacman-l1.xpm"
89 # include "images/pacman/pacman-l2.xpm"
90 # include "images/pacman/pacman-d1.xpm"
91 # include "images/pacman/pacman-d2.xpm"
92 # include "images/pacman/pacman-0.xpm"
93 # include "images/pacman/ghost-s1.xpm"
94 # include "images/pacman/ghost-s2.xpm"
95 # include "images/pacman/ghost-sf1.xpm"
96 # include "images/pacman/ghost-sf2.xpm"
97 # include "images/pacman/eyes-l.xpm"
98 # include "images/pacman/eyes-r.xpm"
99 # include "images/pacman/eyes-u.xpm"
100 # include "images/pacman/eyes-d.xpm"
101 # include "images/pacman/pacman-ds1.xpm"
102 # include "images/pacman/pacman-ds2.xpm"
103 # include "images/pacman/pacman-ds3.xpm"
104 # include "images/pacman/pacman-ds4.xpm"
105 # include "images/pacman/pacman-ds5.xpm"
106 # include "images/pacman/pacman-ds6.xpm"
107 # include "images/pacman/pacman-ds7.xpm"
108 # include "images/pacman/pacman-ds8.xpm"
114 } dirvecs[DIRVECS] = { { -1, 0},
119 #ifdef DISABLE_INTERACTIVE
120 ENTRYPOINT ModeSpecOpt pacman_opts = {
122 (XrmOptionDescRec *) NULL,
125 (OptionStruct *) NULL
128 static XrmOptionDescRec opts[] = {
129 {"-trackmouse", ".pacman.trackmouse", XrmoptionNoArg, "on"},
130 {"+trackmouse", ".pacman.trackmouse", XrmoptionNoArg, "off"}
133 static argtype vars[] = {
134 {&trackmouse, "trackmouse", "TrackMouse", DEF_TRACKMOUSE, t_Bool}
137 static OptionStruct desc[] = {
138 {"-/+trackmouse", "turn on/off the tracking of the mouse"}
141 ENTRYPOINT ModeSpecOpt pacman_opts =
142 { sizeof opts / sizeof opts[0], opts, sizeof vars / sizeof vars[0], vars,
147 ModStruct pacman_description = {
148 "pacman", /* *cmdline_arg; */
149 "init_pacman", /* *init_name; */
150 "draw_pacman", /* *callback_name; */
151 "release_pacman", /* *release_name; */
152 "refresh_pacman", /* *refresh_name; */
153 "change_pacman", /* *change_name; */
154 (char *) NULL, /* *unused_name; */
155 &pacman_opts, /* *msopts */
156 10000, 4, 1, 0, 64, 1.0, "", "Shows Pacman(tm)", 0, NULL
162 pacmangamestruct *pacmangames = (pacmangamestruct *) NULL;
164 static void repopulate (ModeInfo * mi);
165 static void drawlevel (ModeInfo * mi);
169 free_pacman (Display * display, pacmangamestruct * pp)
171 int dir, mouth, i, j, k;
173 if (pp->ghosts != NULL) {
175 pp->ghosts = (ghoststruct *) NULL;
177 if (pp->stippledGC != None) {
178 XFreeGC (display, pp->stippledGC);
179 pp->stippledGC = None;
181 for (i = 0; i < 4; i++) {
182 for (j = 0; j < MAXGDIR; j++) {
183 for (k = 0; k < MAXGWAG; k++) {
184 if (pp->ghostPixmap[i][j][k] != None) {
185 XFreePixmap (display, pp->ghostPixmap[i][j][k]);
186 pp->ghostPixmap[i][j][k] = None;
191 for (dir = 0; dir < 4; dir++)
192 for (mouth = 0; mouth < MAXMOUTH; mouth++)
193 if (pp->pacmanPixmap[dir][mouth] != None) {
194 XFreePixmap (display, pp->pacmanPixmap[dir][mouth]);
195 pp->pacmanPixmap[dir][mouth] = None;
199 /* set pacman and the ghost in there starting positions, but don't draw a new
202 reset_level (ModeInfo * mi, int n, int pac_init)
204 pacmangamestruct *pp = &pacmangames[MI_SCREEN (mi)];
210 pp->gamestate = GHOST_DANGER;
213 pp->pacman.row = (LEVHEIGHT + JAILHEIGHT) / 2 - n;
214 pp->pacman.init_row = pp->pacman.row;
217 pp->pacman.row = pp->pacman.init_row;
219 pp->pacman.col = (LEVWIDTH / 2);
220 pp->pacman.nextrow = NOWHERE;
221 pp->pacman.nextcol = NOWHERE;
222 pp->pacman.cf = NOWHERE;
223 pp->pacman.rf = NOWHERE;
224 pp->pacman.oldcf = NOWHERE;
225 pp->pacman.oldrf = NOWHERE;
226 pp->pacman.oldlx = NOWHERE;
227 pp->pacman.oldly = NOWHERE;
228 pp->pacman.aistate = ps_eating;
229 pp->pacman.cur_trace = 0;
230 pp->pacman.roundscore = 0;
231 pp->pacman.speed = 4;
232 pp->pacman.lastturn = 0;
233 pp->pacman.delta.x = 0;
234 pp->pacman.delta.y = 0;
236 for (ghost = 0; ghost < pp->nghosts; ghost++) {
237 pp->ghosts[ghost].col = (LEVWIDTH / 2);
238 pp->ghosts[ghost].row = (LEVHEIGHT / 2);
239 pp->ghosts[ghost].nextcol = NOWHERE;
240 pp->ghosts[ghost].nextrow = NOWHERE;
241 pp->ghosts[ghost].dead = 0;
242 pp->ghosts[ghost].lastbox = START;
243 pp->ghosts[ghost].cf = NOWHERE;
244 pp->ghosts[ghost].rf = NOWHERE;
245 pp->ghosts[ghost].oldcf = NOWHERE;
246 pp->ghosts[ghost].oldrf = NOWHERE;
247 pp->ghosts[ghost].aistate = inbox;
248 pp->ghosts[ghost].timeleft = ghost * 20;
249 pp->ghosts[ghost].speed = 3;
250 pp->ghosts[ghost].delta.x = 0;
251 pp->ghosts[ghost].delta.y = 0;
252 pp->ghosts[ghost].flash_scared = False;
253 pp->ghosts[ghost].wait_pos = False;
254 ghost_update (pp, &(pp->ghosts[ghost]));
256 pac_update (mi, pp, &(pp->pacman));
260 pacman_ghost_collision(unsigned int ghost, pacmangamestruct * pp)
262 return (((pp->ghosts[ghost].nextrow == pp->pacman.nextrow) &&
263 (pp->ghosts[ghost].nextcol == pp->pacman.nextcol)) ||
264 ((pp->ghosts[ghost].nextrow == pp->pacman.row) &&
265 (pp->ghosts[ghost].nextcol == pp->pacman.col) &&
266 (pp->ghosts[ghost].row == pp->pacman.nextrow) &&
267 (pp->ghosts[ghost].col == pp->pacman.nextcol)));
271 /* Checks for death of any ghosts/pacman and updates. It also makes a new
272 level if all ghosts are dead or all dots are eaten. */
274 check_death (ModeInfo * mi, pacmangamestruct * pp)
276 Display *display = MI_DISPLAY (mi);
277 Window window = MI_WINDOW (mi);
281 if (pp->pacman.aistate == ps_dieing) return;
284 for (ghost = 0; ghost < pp->nghosts; ghost++) {
286 /* The ghost have to be scared before you can kill them */
287 if ( pacman_ghost_collision ( ghost, pp ) ) {
288 if (pp->ghosts[ghost].aistate == goingin) continue;
290 if (pp->ghosts[ghost].aistate == hiding) {
291 pp->ghosts[ghost].dead = 1;
292 pp->ghosts[ghost].aistate = goingin;
293 pp->ghosts[ghost].wait_pos = True;
294 XSetForeground (display, pp->stippledGC, MI_BLACK_PIXEL (mi));
295 XFillRectangle (display, window,
297 pp->ghosts[ghost].cf,
298 pp->ghosts[ghost].rf,
299 pp->spritexs, pp->spriteys);
304 pp->pacman.aistate = ps_dieing;
316 /* Resets state of ghosts + pacman. Creates a new level, draws that level. */
318 repopulate (ModeInfo * mi)
320 pacmangamestruct *pp = &pacmangames[MI_SCREEN (mi)];
321 pp->pacman.deaths = 0;
322 reset_level (mi, createnewlevel (pp), True);
323 check_death (mi, pp);
326 /* Sets the color to the color of a wall. */
328 setwallcolor (ModeInfo * mi)
330 Display *display = MI_DISPLAY (mi);
331 pacmangamestruct *pp = &pacmangames[MI_SCREEN (mi)];
333 if (MI_NPIXELS (mi) > 2)
334 XSetForeground (display, pp->stippledGC, MI_PIXEL (mi, BLUE));
336 XSetForeground (display, pp->stippledGC, MI_WHITE_PIXEL (mi));
339 /* Sets the color to the color of a dot. */
341 setdotcolor (ModeInfo * mi)
343 Display *display = MI_DISPLAY (mi);
344 pacmangamestruct *pp = &pacmangames[MI_SCREEN (mi)];
346 XSetForeground (display, pp->stippledGC, MI_WHITE_PIXEL (mi));
350 cleardotcolor (ModeInfo * mi)
352 Display *display = MI_DISPLAY (mi);
353 pacmangamestruct *pp = &pacmangames[MI_SCREEN (mi)];
355 XSetForeground (display, pp->stippledGC, MI_BLACK_PIXEL (mi));
360 draw_position (ModeInfo * mi, int x, int y, int color)
362 Display *display = MI_DISPLAY (mi);
363 Window window = MI_WINDOW (mi);
364 pacmangamestruct *pp = &pacmangames[MI_SCREEN (mi)];
365 XFontStruct *font = NULL;
366 char *f_name = "-*-utopia-*-r-*-*-*-600-*-*-p-*-*-*";
369 font = XLoadQueryFont (display, f_name);
370 assert (font != NULL);
372 s = (char *) malloc (256);
374 sprintf (s, "(%d,%d)", x, y);
375 XSetForeground (display, pp->stippledGC, color);
376 XDrawString (display, window, pp->stippledGC, x, y, s, strlen (s));
383 draw_number (ModeInfo * mi, int x, int y, int num, int color)
385 Display *display = MI_DISPLAY (mi);
386 Window window = MI_WINDOW (mi);
387 pacmangamestruct *pp = &pacmangames[MI_SCREEN (mi)];
388 XFontStruct *font = NULL;
389 char *f_name = "-*-utopia-*-r-*-*-*-600-*-*-p-*-*-*";
392 font = XLoadQueryFont (display, f_name);
393 assert (font != NULL);
395 s = (char *) malloc (256);
397 sprintf (s, "%d", num);
398 XSetForeground (display, pp->stippledGC, color);
399 XDrawString (display, window, pp->stippledGC, x, y, s, strlen (s));
406 /* draw_grid - draws a grid on top of the playing field.
407 * Used so that I can determine if I'm converting from rows and columns to x and y
408 * coordinates correctly.
411 draw_grid (ModeInfo * mi)
413 Display *display = MI_DISPLAY (mi);
414 Window window = MI_WINDOW (mi);
415 pacmangamestruct *pp = &pacmangames[MI_SCREEN (mi)];
416 int h = MI_HEIGHT (mi);
417 int w = MI_WIDTH (mi);
420 XSetForeground (display, pp->stippledGC, 0xff0000);
423 XDrawLine (display, window, pp->stippledGC, x, 0, x, h);
427 XDrawLine (display, window, pp->stippledGC, 0, y, w, y);
435 draw_string (ModeInfo * mi, int x, int y, char *s, int color)
437 Display *display = MI_DISPLAY (mi);
438 Window window = MI_WINDOW (mi);
439 pacmangamestruct *pp = &pacmangames[MI_SCREEN (mi)];
440 XFontStruct *font = NULL;
441 char *f_name = "-*-utopia-*-r-*-*-*-600-*-*-p-*-*-*";
443 font = XLoadQueryFont (display, f_name);
444 assert (font != NULL);
447 XSetForeground (display, pp->stippledGC, color);
448 XDrawString (display, window, pp->stippledGC, x, y, s, strlen (s));
452 /* I think this function has a memory leak. Be careful if you enable it. */
453 /* I only used it briefly to help me debug the ghost's aistate. It prints */
454 /* the state of each ghost on the left hand side of the screen */
456 print_ghost_stats (ModeInfo *mi, ghoststruct *g , int ghost_num)
460 sprintf (s, "GHOST: %d", ghost_num );
463 sprintf (s, "%s inbox", s);
466 sprintf (s, "%s goingout", s);
469 sprintf (s, "%s randdir", s);
472 sprintf (s, "%s chasing", s);
475 sprintf (s, "%s hiding", s);
478 sprintf (s, "%s goingin",s);
481 draw_string (mi, 0, (ghost_num *3) *10+50, g->last_stat, 0x000000);
482 draw_string (mi, 0, (ghost_num *3) *10+50, s, 0xff0000);
483 strcpy(g->last_stat,s);
486 /* prints the number of times pacman has died and his aistate on the left hand */
487 /* side of the screen */
489 print_pac_stats ( ModeInfo *mi, pacmanstruct *pac )
491 pacmangamestruct *pp = &pacmangames[MI_SCREEN (mi)];
493 sprintf (s, "Pacman, Deaths: %d", pac->deaths );
494 switch ( pac->aistate ){
496 sprintf(s, "%s ps_eating",s );
499 sprintf(s, "%s ps_chasing",s );
502 sprintf(s, "%s ps_hiding",s );
505 sprintf(s, "%s ps_random",s );
508 sprintf(s, "%s ps_dieing",s );
511 draw_string ( mi, 0, 200, pp->last_pac_stat, 0x000000);
512 draw_string ( mi, 0, 200, s, 0xff0000);
513 strcpy(pp->last_pac_stat, s );
518 /*Ok, yeah whatever?*/
519 /*dot_rc_to_pixel - magic that converts row and columns into
520 *the x and y coordinates of the screen.
523 dot_rc_to_pixel (ModeInfo * mi, int *x, int *y)
525 pacmangamestruct *pp = &pacmangames[MI_SCREEN (mi)];
527 (pp->xs / 2) - (pp->xs > 32 ? (pp->xs / 16) : 1) + pp->xb;
529 (pp->ys / 2) - (pp->ys > 32 ? (pp->ys / 16) : 1) + pp->yb;
532 /* dot_width_height - magic used to get the width and height of
533 * a dot. This dot can also be scaled by a value.
536 dot_width_height (ModeInfo *mi, int *w, int *h)
538 pacmangamestruct *pp = &pacmangames[MI_SCREEN (mi)];
540 *w = *h = (pp->xs / 32 );
547 bonus_dot_width_height (ModeInfo *mi, int *w, int *h )
549 *w = *h = MI_HEIGHT (mi) / 65;
555 draw_dot (ModeInfo * mi, pacmangamestruct * pp, int x, int y,
556 void (*width_height)(ModeInfo * mi, int *w, int *h),
557 int (*arc_func) (Display * display, Drawable d, GC gc,
558 int x, int y, unsigned int width,
559 unsigned int height, int angle1,
562 Display *display = MI_DISPLAY (mi);
563 Window window = MI_WINDOW (mi);
565 dot_rc_to_pixel (mi, &x, &y);
566 width_height(mi, &w, &h);
567 (void) arc_func (display, window, pp->stippledGC,
568 x, y, w, h, 0, 23040);
572 draw_bonus_dot (ModeInfo * mi, pacmangamestruct * pp, int x, int y)
577 draw_dot (mi, pp, x, y, bonus_dot_width_height, XFillArc);
578 dot_rc_to_pixel (mi, &x2, &y2);
580 draw_position (mi, x2, y2, 0xff0000);
585 clear_bonus_dot (ModeInfo * mi, pacmangamestruct * pp, int x, int y)
588 draw_dot (mi, pp, x, y, bonus_dot_width_height, XFillArc);
592 draw_regular_dot (ModeInfo * mi, pacmangamestruct * pp, int x, int y)
595 draw_dot (mi, pp, x, y, dot_width_height, XDrawArc);
598 /* Draws a block in the level at the specified x and y locations. */
600 drawlevelblock (ModeInfo * mi, pacmangamestruct * pp,
601 const unsigned x, const unsigned y)
603 Display *display = MI_DISPLAY (mi);
604 Window window = MI_WINDOW (mi);
613 XSetFillStyle (display, pp->stippledGC, FillSolid);
614 #endif /* !HAVE_COCOA */
615 XSetLineAttributes (display, pp->stippledGC, pp->wallwidth,
616 LineSolid, CapRound, JoinMiter);
618 if (pp->xs < 2 || pp->ys < 2) {
619 switch (pp->level[y * LEVWIDTH + x]) {
625 (void) XDrawPoint (display, window,
627 x * pp->xs + pp->xb, y * pp->ys + pp->yb);
631 (void) XDrawPoint (display, window,
633 x * pp->xs + pp->xb, y * pp->ys + pp->yb);
639 switch (pp->level[y * LEVWIDTH + x]) {
646 if (pp->xs < 8 || pp->ys < 8) {
647 (void) XDrawPoint (display, window,
649 x * pp->xs + pp->xb +
650 pp->xs / 2, y * pp->ys + pp->yb + pp->ys / 2);
654 draw_regular_dot (mi, pp, x, y);
656 /* What we will probably want to do here is have the pp->level store a 'o' for
657 * the bonus dots. The we can use the drawing routine above just with a bigger
661 draw_bonus_dot (mi, pp, x, y);
667 (void) XDrawLine (display, window, pp->stippledGC,
668 (pp->xs * x) + pp->xb,
669 (pp->ys * y) + (pp->ys / 2) + pp->yb,
670 (pp->xs * (x + 1)) + pp->xb,
671 (pp->ys * y) + (pp->ys / 2) + pp->yb);
676 (void) XDrawLine (display, window, pp->stippledGC,
677 (pp->xs * x) + (pp->xs / 2) + pp->xb,
678 (pp->ys * y) + pp->yb,
679 (pp->xs * x) + (pp->xs / 2) + pp->xb,
680 (pp->ys * (y + 1)) + pp->yb);
685 (void) XDrawArc (display, window, pp->stippledGC,
686 (pp->xs * x) - (pp->ys / 2) + pp->xb + dx,
687 (pp->ys * y) + (pp->ys / 2) + pp->yb,
688 pp->xs, pp->ys, 0 * 64, 90 * 64);
693 (void) XDrawArc (display, window, pp->stippledGC,
694 (pp->xs * x) + (pp->ys / 2) + pp->xb,
695 (pp->ys * y) + (pp->ys / 2) + pp->yb,
696 pp->xs, pp->ys, 90 * 64, 90 * 64);
701 (void) XDrawArc (display, window, pp->stippledGC,
702 (pp->xs * x) + (pp->ys / 2) + pp->xb,
703 (pp->ys * y) - (pp->ys / 2) + pp->yb + dy,
704 pp->xs, pp->ys, 180 * 64, 90 * 64);
709 (void) XDrawArc (display, window, pp->stippledGC,
710 (pp->xs * x) - (pp->ys / 2) + pp->xb + dx,
711 (pp->ys * y) - (pp->ys / 2) + pp->yb + dy,
712 pp->xs, pp->ys, 270 * 64, 90 * 64);
718 /* Draws a complete level. */
720 drawlevel (ModeInfo * mi)
722 pacmangamestruct *pp = &pacmangames[MI_SCREEN (mi)];
725 for (y = 0; y < LEVHEIGHT; y++)
726 for (x = 0; x < LEVWIDTH; x++)
727 drawlevelblock (mi, pp, x, y);
730 /* There is some overlap so it can be made more efficient */
731 #define ERASE_IMAGE(d,w,g,x,y,xl,yl,xs,ys) \
733 (y<(yl+ys))?XFillRectangle(d,w,g,xl,yl,xs,y-(yl)): \
734 XFillRectangle(d,w,g,xl,yl,xs,ys); \
736 (y>(yl-(ys)))?XFillRectangle(d,w,g,xl,y+ys,xs,yl-(y)): \
737 XFillRectangle(d,w,g,xl,yl,xs,ys); \
739 (x<(xl+xs))?XFillRectangle(d,w,g,xl,yl,x-(xl),ys): \
740 XFillRectangle(d,w,g,xl,yl,xs,ys); \
742 (x>(xl-(xs)))?XFillRectangle(d,w,g,x+xs,yl,xl-(x),ys): \
743 XFillRectangle(d,w,g,xl,yl,xs,ys)
746 /* Draws the pacman sprite, removing the previous location. */
747 #if defined(USE_PIXMAP)
750 draw_pacman_sprite (ModeInfo * mi)
752 Display *display = MI_DISPLAY (mi);
753 Window window = MI_WINDOW (mi);
754 pacmangamestruct *pp = &pacmangames[MI_SCREEN (mi)];
755 unsigned int dir = 0;
756 int old_mask_dir = 0;
757 int old_mask_mouth = 0;
758 Pixmap old_mask, new_mask;
761 #define MAX_MOUTH_DELAY 2
762 #define MAX_DEATH_DELAY 20
764 if (pp->pacman.aistate == ps_dieing){
765 pp->pacman.cf = pp->pacman.oldcf;
766 pp->pacman.rf = pp->pacman.oldrf;
769 pp->pacman.cf = pp->pacman.col * pp->xs + pp->pacman.delta.x *
770 pp->pacman.cfactor + pp->xb + pp->spritedx;
771 pp->pacman.rf = pp->pacman.row * pp->ys + pp->pacman.delta.y *
772 pp->pacman.rfactor + pp->yb + pp->spritedy;
775 dir = (ABS (pp->pacman.cfactor) * (2 - pp->pacman.cfactor) +
776 ABS (pp->pacman.rfactor) * (1 + pp->pacman.rfactor)) % 4;
778 if (pp->pm_mouth_delay == MAX_MOUTH_DELAY) {
779 if (pp->pm_mouth == (MAXMOUTH - 1) || pp->pm_mouth == 0) {
780 pp->pm_open_mouth = !pp->pm_open_mouth;
782 pp->pm_open_mouth ? pp->pm_mouth++ : pp->pm_mouth--;
783 pp->pm_mouth_delay = 0;
786 pp->pm_mouth_delay++;
789 if (pp->pacman.aistate == ps_dieing){
790 if (pp->pm_death_frame >= PAC_DEATH_FRAMES) {
791 pp->pacman.aistate = ps_eating;
792 pp->pm_death_frame = 0;
793 pp->pm_death_delay = 0;
794 reset_level (mi, 0, False);
798 old_mask = pp->pacmanMask[0][0];
799 new_mask = pp->pacmanMask[0][0];
800 pacman = pp->pacman_ds[pp->pm_death_frame];
801 if (pp->pm_death_delay == MAX_DEATH_DELAY){
802 pp->pm_death_frame++;
803 pp->pm_death_delay = 0;
806 pp->pm_death_delay++;
811 old_mask = pp->pacmanMask[old_mask_dir][old_mask_mouth];
812 new_mask = pp->pacmanMask[dir][pp->pm_mouth];
813 pacman = pp->pacmanPixmap[dir][pp->pm_mouth];
816 XSetForeground (display, pp->stippledGC, MI_BLACK_PIXEL (mi));
818 XSetClipMask (display, pp->stippledGC, old_mask);
820 XSetClipOrigin (display, pp->stippledGC, pp->pacman.oldcf,
822 XFillRectangle (display, window, pp->stippledGC, pp->pacman.oldcf,
823 pp->pacman.oldrf, pp->spritexs, pp->spriteys);
824 XSetClipMask (display, pp->stippledGC, new_mask);
825 XSetClipOrigin (display, pp->stippledGC, pp->pacman.cf, pp->pacman.rf);
826 XCopyArea (display, pacman, window,
827 pp->stippledGC, 0, 0, pp->spritexs, pp->spriteys,
828 pp->pacman.cf, pp->pacman.rf);
829 XSetClipMask (display, pp->stippledGC, None);
830 if (pp->pacman.aistate != ps_dieing){
831 pp->pacman.oldcf = pp->pacman.cf;
832 pp->pacman.oldrf = pp->pacman.rf;
835 old_mask_mouth = pp->pm_mouth;
840 draw_ghost_position (ModeInfo * mi, ghoststruct * ghost)
842 draw_position (mi, ghost->oldcf, ghost->oldrf, MI_BLACK_PIXEL (mi));
843 draw_position (mi, ghost->cf, ghost->rf, 0x00ff00);
848 draw_ghost_ndirs ( ModeInfo *mi, ghoststruct * ghost)
850 draw_number (mi, ghost->oldcf, ghost->oldrf, ghost->oldndirs, MI_BLACK_PIXEL (mi));
851 ghost->oldndirs = ghost->ndirs;
852 draw_number (mi, ghost->cf, ghost->rf, ghost->ndirs, 0x00ff00);
858 draw_ghost_sprite (ModeInfo * mi, const unsigned ghost)
860 Display *display = MI_DISPLAY (mi);
861 Window window = MI_WINDOW (mi);
862 pacmangamestruct *pp = &pacmangames[MI_SCREEN (mi)];
863 #define MAX_WAG_COUNT 50
864 unsigned int dir = 0;
865 unsigned int fs = 0; /*flash scared*/
866 Pixmap g_pix; /*ghost pixmap*/
869 dir = (ABS (pp->ghosts[ghost].cfactor) * (2 - pp->ghosts[ghost].cfactor) +
870 ABS (pp->ghosts[ghost].rfactor) * (1 + pp->ghosts[ghost].rfactor)) % 4;
873 fs = pp->ghosts[ghost].flash_scared;
874 assert (fs == 0 || fs == 1);
876 /* Choose the pixmap */
877 switch (pp->ghosts[ghost].aistate){
879 g_pix = pp->s_ghostPixmap[fs][pp->gh_wag];
882 g_pix = pp->ghostEyes[dir];
886 while ( i < pp->ghosts[ghost].trace_idx ){
887 XFillRectangle (display,
890 pp->ghosts[ghost].trace[i].vx,
891 pp->ghosts[ghost].trace[i].vy,
892 pp->spritexs, pp->spriteys);
901 g_pix = pp->ghostPixmap[ghost][dir][pp->gh_wag];
904 pp->ghosts[ghost].cf =
905 pp->ghosts[ghost].col * pp->xs + pp->ghosts[ghost].delta.x *
906 pp->ghosts[ghost].cfactor + pp->xb + pp->spritedx;
907 pp->ghosts[ghost].rf =
908 pp->ghosts[ghost].row * pp->ys + pp->ghosts[ghost].delta.y *
909 pp->ghosts[ghost].rfactor + pp->yb + pp->spritedy;
911 XSetForeground (display, pp->stippledGC, MI_BLACK_PIXEL (mi));
913 XSetClipMask (display, pp->stippledGC, pp->ghostMask);
914 XSetClipOrigin (display, pp->stippledGC,
915 pp->ghosts[ghost].oldcf, pp->ghosts[ghost].oldrf);
916 XFillRectangle (display,
919 pp->ghosts[ghost].oldcf,
920 pp->ghosts[ghost].oldrf, pp->spritexs, pp->spriteys);
923 if (pp->pacman.aistate != ps_dieing) {
924 drawlevelblock (mi, pp,
925 (unsigned int) pp->ghosts[ghost].col,
926 (unsigned int) pp->ghosts[ghost].row);
930 XSetClipOrigin (display, pp->stippledGC,
931 pp->ghosts[ghost].cf, pp->ghosts[ghost].rf);
933 XCopyArea (display, g_pix, window, pp->stippledGC, 0, 0,
934 pp->spritexs, pp->spriteys, pp->ghosts[ghost].cf,
935 pp->ghosts[ghost].rf);
937 XSetClipMask (display, pp->stippledGC, None);
940 draw_ghost_position (mi, &(pp->ghosts[ghost]));
944 draw_ghost_ndirs ( mi, &(pp->ghosts[ghost]));
947 if (pp->pacman.aistate != ps_dieing) {
948 pp->ghosts[ghost].oldcf = pp->ghosts[ghost].cf;
949 pp->ghosts[ghost].oldrf = pp->ghosts[ghost].rf;
950 if (pp->gh_wag_count++ == MAX_WAG_COUNT) {
951 pp->gh_wag = !pp->gh_wag;
952 pp->gh_wag_count = 0;
957 #else /* USE_PIXMAP */
959 /* Draws the pacman sprite, removing the previous location. */
961 draw_pacman_sprite (ModeInfo * mi)
963 Display *display = MI_DISPLAY (mi);
964 Window window = MI_WINDOW (mi);
965 pacmangamestruct *pp = &pacmangames[MI_SCREEN (mi)];
968 pp->pacman.cf = pp->pacman.col * pp->xs + pp->pacman.delta.x *
969 pp->pacman.cfactor + pp->xb + pp->spritedx;
970 pp->pacman.rf = pp->pacman.row * pp->ys + pp->pacman.delta.y *
971 pp->pacman.rfactor + pp->yb + pp->spritedy;
973 dir = (ABS (pp->pacman.cfactor) * (2 - pp->pacman.cfactor) +
974 ABS (pp->pacman.rfactor) * (1 + pp->pacman.rfactor)) % 4;
976 XSetForeground (display, pp->stippledGC, MI_BLACK_PIXEL (mi));
977 if (pp->pacman.oldcf != NOWHERE && pp->pacman.oldrf != NOWHERE) {
979 ERASE_IMAGE (display, window, pp->stippledGC,
980 pp->pacman.cf, pp->pacman.rf,
981 pp->pacman.oldcf, pp->pacman.oldrf,
982 pp->spritexs, pp->spriteys);
985 if (MI_NPIXELS (mi) > 2)
986 XSetForeground (display, pp->stippledGC, MI_PIXEL (mi, YELLOW));
988 XSetForeground (display, pp->stippledGC, MI_WHITE_PIXEL (mi));
990 XSetFillStyle (display, pp->stippledGC, FillOpaqueStippled);
992 if (pp->xs < 2 || pp->ys < 2)
993 XDrawPoint (display, window, pp->stippledGC,
994 pp->pacman.cf, pp->pacman.rf);
996 XFillRectangle (display, window, pp->stippledGC,
997 pp->pacman.cf, pp->pacman.rf,
998 pp->spritexs, pp->spriteys);
999 pp->pacman.mouthstage += pp->pacman.mouthdirection;
1000 if ((pp->pacman.mouthstage >= MAXMOUTH) || (pp->pacman.mouthstage < 0)) {
1001 pp->pacman.mouthdirection *= -1;
1002 pp->pacman.mouthstage += pp->pacman.mouthdirection * 2;
1004 pp->pacman.oldcf = pp->pacman.cf;
1005 pp->pacman.oldrf = pp->pacman.rf;
1008 /* Draws a ghost sprite, removing the previous sprite and restores the level. */
1010 draw_ghost_sprite (ModeInfo * mi, const unsigned ghost)
1012 Display *display = MI_DISPLAY (mi);
1013 Window window = MI_WINDOW (mi);
1014 pacmangamestruct *pp = &pacmangames[MI_SCREEN (mi)];
1016 pp->ghosts[ghost].cf =
1017 pp->ghosts[ghost].col * pp->xs + pp->ghosts[ghost].delta.x *
1018 pp->ghosts[ghost].cfactor + pp->xb + pp->spritedx;
1019 pp->ghosts[ghost].rf =
1020 pp->ghosts[ghost].row * pp->ys + pp->ghosts[ghost].delta.y *
1021 pp->ghosts[ghost].rfactor + pp->yb + pp->spritedy;
1023 XSetForeground (display, pp->stippledGC, MI_BLACK_PIXEL (mi));
1024 XFillRectangle (display,
1027 pp->ghosts[ghost].cf,
1028 pp->ghosts[ghost].rf, pp->spritexs, pp->spriteys);
1030 if (pp->ghosts[ghost].oldcf != NOWHERE ||
1031 pp->ghosts[ghost].oldrf != NOWHERE) {
1033 ERASE_IMAGE (display, window, pp->stippledGC,
1034 pp->ghosts[ghost].cf, pp->ghosts[ghost].rf,
1035 pp->ghosts[ghost].oldcf, pp->ghosts[ghost].oldrf,
1036 pp->spritexs, pp->spriteys);
1039 drawlevelblock (mi, pp,
1040 (unsigned int) pp->ghosts[ghost].col,
1041 (unsigned int) pp->ghosts[ghost].row);
1043 if (MI_NPIXELS (mi) > 2)
1044 XSetForeground (display, pp->stippledGC, MI_PIXEL (mi, GREEN));
1046 XSetForeground (display, pp->stippledGC, MI_WHITE_PIXEL (mi));
1048 XSetFillStyle (display, pp->stippledGC, FillOpaqueStippled);
1050 if (pp->xs < 2 || pp->ys < 2)
1051 XDrawPoint (display, window, pp->stippledGC,
1052 pp->ghosts[ghost].cf, pp->ghosts[ghost].rf);
1054 XFillRectangle (display,
1057 pp->ghosts[ghost].cf,
1058 pp->ghosts[ghost].rf, pp->spritexs, pp->spriteys);
1060 pp->ghosts[ghost].oldcf = pp->ghosts[ghost].cf;
1061 pp->ghosts[ghost].oldrf = pp->ghosts[ghost].rf;
1063 #endif /* USE_PIXMAP */
1066 ghost_over (ModeInfo * mi, int x, int y)
1070 pacmangamestruct *pp = &pacmangames[MI_SCREEN (mi)];
1071 dot_rc_to_pixel (mi, &x, &y);
1072 for (ghost = 0; ghost < pp->nghosts; ghost++) {
1073 if ((pp->ghosts[ghost].cf <= x
1074 && x <= pp->ghosts[ghost].cf + pp->spritexs)
1075 && (pp->ghosts[ghost].rf <= y
1076 && y <= pp->ghosts[ghost].rf + pp->spriteys)) {
1086 flash_bonus_dots (ModeInfo * mi)
1088 #define MAX_FLASH_COUNT 25
1089 pacmangamestruct *pp = &pacmangames[MI_SCREEN (mi)];
1091 for (i = 0; i < NUM_BONUS_DOTS; i++) {
1092 if (!bonus_dot_eaten (pp, i)) {
1093 bonus_dot_pos (pp, i, &x, &y);
1094 if (ghost_over (mi, x, y))
1097 draw_bonus_dot (mi, pp, x, y);
1099 clear_bonus_dot (mi, pp, x, y);
1102 if (pp->bd_flash_count-- == 0) {
1103 pp->bd_flash_count = MAX_FLASH_COUNT;
1104 pp->bd_on = !pp->bd_on;
1109 ate_bonus_dot (ModeInfo * mi)
1111 /*Check pacman's position. If it is over a bonus dot and that dot
1112 *has not been eaten, then return true
1114 unsigned int ret = 0;
1116 pacmangamestruct *pp = &pacmangames[MI_SCREEN (mi)];
1117 if (is_bonus_dot (pp, pp->pacman.col, pp->pacman.row, &idx)) {
1118 ret = !bonus_dot_eaten (pp, idx);
1119 eat_bonus_dot (pp, idx);
1125 ghost_scared (ModeInfo * mi)
1128 pacmangamestruct *pp = &pacmangames[MI_SCREEN (mi)];
1129 for (ghost = 0; ghost < pp->nghosts; ghost++) {
1130 if (pp->ghosts[ghost].aistate == goingin ||
1131 pp->ghosts[ghost].aistate == goingout ||
1132 pp->ghosts[ghost].aistate == inbox ) continue;
1133 pp->ghosts[ghost].aistate = hiding;
1134 pp->ghosts[ghost].flash_scared = 0;
1135 if (pp->pacman.aistate != ps_dieing)
1136 pp->pacman.aistate = ps_chasing;
1141 ghost_not_scared (ModeInfo * mi)
1144 pacmangamestruct *pp = &pacmangames[MI_SCREEN (mi)];
1145 for (ghost = 0; ghost < pp->nghosts; ghost++){
1146 if (pp->ghosts[ghost].aistate == goingin ||
1147 pp->ghosts[ghost].aistate == goingout ||
1148 pp->ghosts[ghost].aistate == inbox ) continue;
1149 pp->ghosts[ghost].aistate = chasing;
1151 if (pp->pacman.aistate != ps_dieing)
1152 pp->pacman.aistate = ps_eating;
1157 ghost_flash_scared (ModeInfo * mi)
1160 pacmangamestruct *pp = &pacmangames[MI_SCREEN (mi)];
1161 for (ghost = 0; ghost < pp->nghosts; ghost++)
1162 pp->ghosts[ghost].flash_scared = !pp->ghosts[ghost].flash_scared;
1165 /* Does all drawing of moving sprites in the level. */
1167 pacman_tick (ModeInfo * mi)
1169 #define DEFAULT_SCARED_TIME 500
1170 #define START_FLASH 200
1171 #define FLASH_COUNT 25
1173 pacmangamestruct *pp = &pacmangames[MI_SCREEN (mi)];
1178 for (ghost = 0; ghost < pp->nghosts; ghost++) {
1179 draw_ghost_sprite (mi, ghost);
1181 print_ghost_stats (mi, &(pp->ghosts[ghost]), ghost);
1185 print_pac_stats (mi, &(pp->pacman));
1187 draw_pacman_sprite (mi);
1188 flash_bonus_dots (mi);
1189 if (ate_bonus_dot (mi)) {
1190 pp->ghost_scared_timer = (random () % 100) + DEFAULT_SCARED_TIME;
1194 if (pp->ghost_scared_timer > 0) {
1195 if (--pp->ghost_scared_timer == 0)
1196 ghost_not_scared (mi);
1197 else if (pp->ghost_scared_timer <= START_FLASH) {
1198 if (pp->flash_timer <= 0) {
1199 pp->flash_timer = FLASH_COUNT;
1200 ghost_flash_scared (mi);
1207 We don't want to miss the last death sequence. So if pacman has died three times
1208 we wait for his state to change from dieing to something else before we repopulate
1209 the level. If pacman ate all of the dots then we just repopulate.
1212 if (pp->dotsleft == 0 )
1214 else if (pp->pacman.deaths >= 3){
1215 if (pp->old_pac_state == ps_dieing && pp->pacman.aistate != ps_dieing)
1219 pp->old_pac_state = pp->pacman.aistate;
1223 /* CODE TO LOAD AND SCALE THE PIXMAPS
1226 #if defined(USE_PIXMAP)
1227 /* Grabbed the scaling routine off of usenet.
1228 * Changed it so that the information specific
1229 * to the source pixmap does not have to be a parameter.
1231 * There is probably a better way to scale pixmaps.
1232 * From: Chris Fiddyment (cxf@itd.dsto.gov.au)
1233 * Subject: Scaling Pixmap Algorithm.
1234 * Newsgroups: comp.graphics.algorithms
1235 * Date: 1994-07-06 18:51:38 PST
1240 scale_pixmap (Display ** dpy, GC gc, Pixmap source, int dwidth, int dheight)
1245 float xscale, yscale;
1246 unsigned int swidth, sheight;
1249 unsigned border_width_return, depth;
1250 XGetGeometry (*dpy, source, &window, &x, &y, &swidth, &sheight,
1251 &border_width_return, &depth);
1253 xscale = (float) swidth / (float) dwidth; /* Scaling factors */
1254 yscale = (float) sheight / (float) dheight;
1256 dest = XCreatePixmap (*dpy, window, dwidth, dheight, depth);
1258 fprintf (stderr, "%s Could not scale image", progname);
1260 temp = XCreatePixmap (*dpy, window, dwidth, sheight, depth);
1262 fprintf (stderr, "%s Could not scale image", progname);
1266 end = dwidth * xscale;
1267 /* Scale width of source into temp pixmap */
1268 for (i = 0; i <= end; i += xscale)
1269 XCopyArea (*dpy, source, temp, gc, i, 0, 1, sheight, j++, 0);
1272 end = dheight * yscale;
1273 /* Scale height of temp into dest pixmap */
1274 for (i = 0; i <= end; i += yscale)
1275 XCopyArea (*dpy, temp, dest, gc, 0, i, swidth, 1, 0, j++);
1277 XFreePixmap (*dpy, temp);
1278 return (Pixmap) dest;
1282 pacman_fail (char *s)
1284 fprintf (stderr, "%s: %s\n", progname, s);
1288 /* Load the ghost pixmaps and their mask. */
1290 load_ghost_pixmaps (Display ** dpy, Window window, pacmangamestruct ** ps)
1292 pacmangamestruct *pp = *ps;
1293 Display *display = *dpy;
1295 ". c #FF0000", /*Red */
1296 ". c #00FFDE", /*Blue */
1297 ". c #FFB847", /*Orange */
1298 ". c #FFB8DE", /*Pink */
1302 ghost_u1_xpm, ghost_u2_xpm, ghost_r1_xpm, ghost_r2_xpm,
1303 ghost_d1_xpm, ghost_d2_xpm, ghost_l1_xpm, ghost_l2_xpm
1305 char * const *s_bits[] = {
1306 ghost_s1_xpm, ghost_s2_xpm,
1307 ghost_sf1_xpm, ghost_sf2_xpm
1309 char * const *e_bits[] = {
1310 eyes_u_xpm, eyes_r_xpm, eyes_d_xpm, eyes_l_xpm
1314 int w = pp->spritexs;
1315 int h = pp->spriteys;
1319 for (i = 0; i < 4; i++) {
1321 for (j = 0; j < MAXGDIR; j++) {
1322 for (k = 0; k < MAXGWAG; k++) {
1323 bits[m][2] = colors[i];
1324 pp->ghostPixmap[i][j][k] =
1325 xpm_data_to_pixmap (display, window, bits[m], &w, &h,
1328 if (!pp->ghostPixmap[i][j][k])
1329 pacman_fail ("Cannot load ghost images");
1331 pp->ghostPixmap[i][j][k] =
1332 scale_pixmap (&display, pp->stippledGC,
1333 pp->ghostPixmap[i][j][k], pp->spritexs,
1336 if (!pp->ghostPixmap[i][j][k])
1337 pacman_fail ("Cannot scale ghost images");
1342 /* load the scared ghost */
1344 for (i = 0; i < MAXGFLASH; i++) {
1345 for (j = 0; j < MAXGWAG; j++) {
1346 pp->s_ghostPixmap[i][j] =
1347 xpm_data_to_pixmap (display, window, s_bits[m++], &w, &h,
1350 if (!pp->s_ghostPixmap[i][j])
1351 pacman_fail ("Cannot Scare Ghost images");
1352 pp->s_ghostPixmap[i][j] = scale_pixmap (&display, pp->stippledGC,
1353 pp->s_ghostPixmap[i][j],
1357 if (!pp->s_ghostPixmap[i][j])
1358 pacman_fail ("Cannot scale Scared Ghost images");
1361 /* load the ghost eyes */
1362 for (i = 0; i < MAXGDIR; i++) {
1364 xpm_data_to_pixmap (display, window, e_bits[i], &w, &h,
1367 if (!pp->ghostEyes[i])
1368 pacman_fail ("Cannot open ghost eye images");
1370 pp->ghostEyes[i] = scale_pixmap (&display, pp->stippledGC,
1375 if (!pp->ghostEyes[i])
1376 pacman_fail ("Cannot open ghost eye images");
1381 /* We really only need a single mask. This saves the headache of getting the
1382 * bottom of the ghost to clip just right. What we'll do is mask
1383 * the top portion of the ghost, but the bottom of the ghost will be solid.
1384 * I did this by setting the pixels between the fringe of their sheets
1385 * to black instead of none. -jeremy
1387 temp = xpm_data_to_pixmap (display, window, ghost_mask_xpm,
1388 &w, &h, &pp->ghostMask);
1391 pacman_fail ("Cannot load temporary ghost image");
1393 temp = scale_pixmap (&display, pp->stippledGC,
1394 temp, pp->spritexs, pp->spriteys);
1397 pacman_fail ("Cannot scale temporary ghost image");
1399 gc = XCreateGC (display, pp->ghostMask, 0, 0);
1401 pp->ghostMask = scale_pixmap (&display, gc, pp->ghostMask,
1402 pp->spritexs, pp->spriteys);
1403 XFreePixmap (display, temp);
1406 /* Load the pacman pixmaps and their mask. */
1408 load_pacman_pixmaps (Display ** dpy, Window window, pacmangamestruct ** ps)
1410 pacmangamestruct *pp = *ps;
1411 Display *display = *dpy;
1414 pacman_0_xpm, pacman_u1_xpm, pacman_u2_xpm,
1415 pacman_0_xpm, pacman_r1_xpm, pacman_r2_xpm,
1416 pacman_0_xpm, pacman_d1_xpm, pacman_d2_xpm,
1417 pacman_0_xpm, pacman_l1_xpm, pacman_l2_xpm
1420 char * const *ds_bits[] = {
1421 pacman_ds1_xpm, pacman_ds2_xpm, pacman_ds3_xpm, pacman_ds4_xpm,
1422 pacman_ds5_xpm, pacman_ds6_xpm, pacman_ds7_xpm, pacman_ds8_xpm
1426 int w = pp->spritexs;
1427 int h = pp->spriteys;
1431 for (i = 0; i < 4; i++) {
1432 for (j = 0; j < MAXMOUTH; j++) {
1433 pp->pacmanPixmap[i][j] =
1434 xpm_data_to_pixmap (display, window, bits[m++], &w, &h,
1435 &pp->pacmanMask[i][j]);
1437 if (!pp->pacmanPixmap[i][j])
1438 pacman_fail ("Cannot load pacman pixmap.");
1440 pp->pacmanPixmap[i][j] = scale_pixmap (&display, pp->stippledGC,
1441 pp->pacmanPixmap[i][j],
1445 if (!pp->pacmanPixmap[i][j])
1446 pacman_fail ("Cannot scale pacman pixmap.");
1449 gc = XCreateGC (display, pp->pacmanMask[i][j], 0, 0);
1451 pp->pacmanMask[i][j] =
1452 scale_pixmap (&display, gc, pp->pacmanMask[i][j],
1453 pp->spritexs, pp->spriteys);
1457 /* Load pacman death sequence */
1458 for ( i = 0; i < PAC_DEATH_FRAMES; i++ ){
1460 xpm_data_to_pixmap (display, window, ds_bits[i], &w, &h,
1461 &pp->pacman_ds_mask[i]);
1463 if (!pp->pacman_ds[i])
1464 pacman_fail ("Cannot load pacman death frame.");
1466 pp->pacman_ds[i] = scale_pixmap ( &display, pp->stippledGC,
1471 if (!pp->pacman_ds[i])
1472 pacman_fail ("Cannot scale pixmap.");
1475 gc = XCreateGC (display, pp->pacman_ds_mask[i], 0, 0);
1477 pp->pacman_ds_mask[i] =
1478 scale_pixmap (&display, gc, pp->pacman_ds_mask[i],
1479 pp->spritexs, pp->spriteys);
1483 #endif /* USE_PIXMAP */
1485 /* Hook function, sets state to initial position. */
1487 init_pacman (ModeInfo * mi)
1489 Display *display = MI_DISPLAY (mi);
1490 Window window = MI_WINDOW (mi);
1491 int size = MI_SIZE (mi);
1492 pacmangamestruct *pp;
1496 #if (! defined( USE_PIXMAP ))
1502 if (pacmangames == NULL) {
1503 if ((pacmangames = (pacmangamestruct *)
1504 calloc ((size_t) MI_NUM_SCREENS (mi),
1505 sizeof (pacmangamestruct))) == NULL)
1508 pp = &pacmangames[MI_SCREEN (mi)];
1510 pp->width = (unsigned short) MI_WIDTH (mi);
1511 pp->height = (unsigned short) MI_HEIGHT (mi);
1512 for (i = 0; i < 4; i++) {
1513 for (j = 0; j < MAXGDIR; j++) {
1514 for (k = 0; k < MAXGWAG; k++) {
1515 if (pp->ghostPixmap[i][j][k] != None) {
1516 XFreePixmap (display, pp->ghostPixmap[i][j][k]);
1517 pp->ghostPixmap[i][j][k] = None;
1518 pp->graphics_format = 0 /*IS_NONE */ ;
1524 for (i = 0; i < MAXGFLASH; i++) {
1525 for (j = 0; j < MAXGWAG; j++) {
1526 if (pp->s_ghostPixmap[i][j] != None) {
1527 XFreePixmap (display, pp->s_ghostPixmap[i][j]);
1528 pp->s_ghostPixmap[i][j] = None;
1534 MINGRIDSIZE * size > (int) pp->width ||
1535 MINGRIDSIZE * size > (int) pp->height) {
1537 pp->ys = pp->xs = MAX (MIN (pp->width / LEVWIDTH,
1538 pp->height / LEVHEIGHT), 1);
1541 if (size < -MINSIZE)
1542 pp->ys = (short) (NRAND (MIN (-size, MAX (MINSIZE,
1546 - MINSIZE + 1) + MINSIZE);
1547 else if (size < MINSIZE)
1550 pp->ys = (short) (MIN (size,
1551 MAX (MINSIZE, MIN (pp->width, pp->height) /
1556 pp->wallwidth = (unsigned int) (pp->xs + pp->ys) >> 4;
1557 if (pp->wallwidth < 1)
1559 pp->incx = (pp->xs >> 3) + 1;
1560 pp->incy = (pp->ys >> 3) + 1;
1561 pp->ncols = (unsigned short) MAX (LEVWIDTH, 2);
1562 pp->nrows = (unsigned short) MAX (LEVHEIGHT, 2);
1563 pp->xb = (pp->width - pp->ncols * pp->xs) >> 1;
1564 pp->yb = (pp->height - pp->nrows * pp->ys) >> 1;
1565 pp->spritexs = MAX (pp->xs + (pp->xs >> 1) - 1, 1);
1566 pp->spriteys = MAX (pp->ys + (pp->ys >> 1) - 1, 1);
1567 pp->spritedx = (pp->xs - pp->spritexs) >> 1;
1568 pp->spritedy = (pp->ys - pp->spriteys) >> 1;
1569 pp->old_pac_state = chasing;
1571 if (!pp->stippledGC) {
1572 gcv.foreground = MI_BLACK_PIXEL (mi);
1573 gcv.background = MI_BLACK_PIXEL (mi);
1574 if ((pp->stippledGC = XCreateGC (display, window,
1575 GCForeground | GCBackground,
1577 free_pacman (display, pp);
1583 jwxyz_XSetAntiAliasing (display, pp->stippledGC, False);
1586 #if defined(USE_PIXMAP)
1587 load_ghost_pixmaps (&display, window, &pp);
1588 load_pacman_pixmaps (&display, window, &pp);
1590 if ((pp->ghostPixmap[0][0][0] = XCreatePixmap (display, window,
1591 pp->spritexs, pp->spriteys,
1593 free_pacman (display, pp);
1599 if ((bg_gc = XCreateGC (display, pp->ghostPixmap[0][0][0],
1600 GCForeground | GCBackground, &gcv)) == None) {
1601 free_pacman (display, pp);
1607 if ((fg_gc = XCreateGC (display, pp->ghostPixmap[0][0][0],
1608 GCForeground | GCBackground, &gcv)) == None) {
1609 XFreeGC (display, bg_gc);
1610 free_pacman (display, pp);
1614 #define SETPOINT(p, xp, yp) p.x = xp; p.y = yp
1616 /* draw the triangles on the bottom (scalable) */
1617 SETPOINT (points[0], 1, pp->spriteys * 5 / 6);
1618 SETPOINT (points[1], pp->spritexs / 6, pp->spriteys);
1619 SETPOINT (points[2], pp->spritexs / 3, pp->spriteys * 5 / 6);
1620 SETPOINT (points[3], pp->spritexs / 2, pp->spriteys);
1621 SETPOINT (points[4], pp->spritexs * 2 / 3, pp->spriteys * 5 / 6);
1622 SETPOINT (points[5], pp->spritexs * 5 / 6, pp->spriteys);
1623 SETPOINT (points[6], pp->spritexs, pp->spriteys * 5 / 6);
1624 SETPOINT (points[7], pp->spritexs, pp->spriteys / 2);
1625 SETPOINT (points[8], 1, pp->spriteys / 2);
1627 XFillRectangle (display, pp->ghostPixmap[0][0][0], bg_gc,
1628 0, 0, pp->spritexs, pp->spriteys);
1629 XFillArc (display, pp->ghostPixmap[0][0][0], fg_gc,
1630 0, 0, pp->spritexs, pp->spriteys, 0, 11520);
1631 XFillPolygon (display, pp->ghostPixmap[0][0][0], fg_gc,
1632 points, 9, Nonconvex, CoordModeOrigin);
1633 XFreeGC (display, bg_gc);
1634 XFreeGC (display, fg_gc);
1637 if (pp->pacmanPixmap[0][0] != None)
1638 for (dir = 0; dir < 4; dir++)
1639 for (mouth = 0; mouth < MAXMOUTH; mouth++)
1640 XFreePixmap (display, pp->pacmanPixmap[dir]
1643 for (dir = 0; dir < 4; dir++)
1644 for (mouth = 0; mouth < MAXMOUTH; mouth++) {
1645 if ((pp->pacmanPixmap[dir][mouth] =
1646 XCreatePixmap (display, MI_WINDOW (mi), pp->spritexs,
1647 pp->spriteys, 1)) == None) {
1648 free_pacman (display, pp);
1653 if ((fg_gc = XCreateGC (display, pp->pacmanPixmap[dir][mouth],
1654 GCForeground | GCBackground,
1656 free_pacman (display, pp);
1661 if ((bg_gc = XCreateGC (display,
1662 pp->pacmanPixmap[dir][mouth],
1664 GCBackground, &gcv)) == None) {
1665 XFreeGC (display, fg_gc);
1666 free_pacman (display, pp);
1669 XFillRectangle (display,
1670 pp->pacmanPixmap[dir][mouth], bg_gc,
1671 0, 0, pp->spritexs, pp->spriteys);
1672 if (pp->spritexs == 1 && pp->spriteys == 1)
1673 XFillRectangle (display,
1674 pp->pacmanPixmap[dir][mouth],
1675 fg_gc, 0, 0, pp->spritexs, pp->spriteys);
1678 pp->pacmanPixmap[dir][mouth],
1680 0, 0, pp->spritexs, pp->spriteys,
1681 ((90 - dir * 90) + mouth * 5) * 64,
1682 (360 + (-2 * mouth * 5)) * 64);
1683 XFreeGC (display, fg_gc);
1684 XFreeGC (display, bg_gc);
1686 #endif /* USE_PIXMAP */
1688 pp->pacman.lastbox = START;
1689 pp->pacman.mouthdirection = 1;
1690 pp->pacman.nextcol = NOWHERE;
1691 pp->pacman.nextrow = NOWHERE;
1693 if (pp->ghosts != NULL) {
1695 pp->ghosts = (ghoststruct *) NULL;
1697 pp->nghosts = GHOSTS;
1700 if ((pp->ghosts = (ghoststruct *) calloc ((size_t) pp->nghosts,
1701 sizeof (ghoststruct))) ==
1703 free_pacman (display, pp);
1707 pp->pacman.mouthstage = MAXMOUTH - 1;
1709 MI_CLEARWINDOW (mi);
1713 /* Callback function called for each tick. This is the complete machinery of
1714 everything that moves. */
1716 draw_pacman (ModeInfo * mi)
1719 pacmangamestruct *pp;
1721 if (pacmangames == NULL)
1723 pp = &pacmangames[MI_SCREEN (mi)];
1724 if (pp->ghosts == NULL)
1727 pp->pacman.err.x = (pp->pacman.err.x + 1) % pp->pacman.speed;
1728 pp->pacman.err.y = (pp->pacman.err.y + 1) % pp->pacman.speed;
1729 pp->pacman.delta.x += pp->pacman.err.x != 0 ? pp->incx : 0;
1730 pp->pacman.delta.y += pp->pacman.err.y != 0 ? pp->incy : 0;
1732 if (pp->pacman.delta.x >= pp->xs && pp->pacman.delta.y >= pp->ys) {
1733 pac_update (mi, pp, &(pp->pacman));
1734 check_death (mi, pp);
1735 pp->pacman.delta.x = pp->incx;
1736 pp->pacman.delta.y = pp->incy;
1739 if (pp->pacman.delta.x > pp->xs + pp->incx)
1740 pp->pacman.delta.x = pp->xs + pp->incx;
1741 if (pp->pacman.delta.y > pp->ys + pp->incy)
1742 pp->pacman.delta.y = pp->ys + pp->incy;
1744 for (g = 0; g < pp->nghosts; g++) {
1745 pp->ghosts[g].err.x = (pp->ghosts[g].err.x + 1) % pp->ghosts[g].speed;
1746 pp->ghosts[g].err.y = (pp->ghosts[g].err.y + 1) % pp->ghosts[g].speed;
1747 pp->ghosts[g].delta.x += pp->ghosts[g].err.x != 0 ? pp->incx : 0;
1748 pp->ghosts[g].delta.y += pp->ghosts[g].err.y != 0 ? pp->incy : 0;
1750 if (pp->ghosts[g].delta.x >= pp->xs &&
1751 pp->ghosts[g].delta.y >= pp->ys) {
1752 ghost_update (pp, &(pp->ghosts[g]));
1753 pp->ghosts[g].delta.x = pp->incx;
1754 pp->ghosts[g].delta.y = pp->incy;
1757 if (pp->ghosts[g].delta.x > pp->xs + pp->incx)
1758 pp->ghosts[g].delta.x = pp->xs + pp->incx;
1759 if (pp->ghosts[g].delta.y > pp->ys + pp->incy)
1760 pp->ghosts[g].delta.y = pp->ys + pp->incy;
1765 /* Releases resources. */
1767 release_pacman (ModeInfo * mi)
1769 if (pacmangames != NULL) {
1772 for (screen = 0; screen < MI_NUM_SCREENS (mi); screen++)
1773 free_pacman (MI_DISPLAY (mi), &pacmangames[screen]);
1775 pacmangames = (pacmangamestruct *) NULL;
1779 /* Refresh current level. */
1781 refresh_pacman (ModeInfo * mi)
1788 /* Callback to change level. */
1790 change_pacman (ModeInfo * mi)
1792 MI_CLEARWINDOW (mi);
1795 #endif /* !STANDALONE */
1798 XSCREENSAVER_MODULE ("Pacman", pacman)
1800 #endif /* MODE_pacman */