1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* pacman --- Mr. Pacman and his ghost friends */
5 static const char sccsid[] = "@(#)pacman.c 5.00 2000/11/01 xlockmore";
9 * Copyright (c) 2002 by Edwin de Jong <mauddib@gmx.net>.
11 * Permission to use, copy, modify, and distribute this software and its
12 * documentation for any purpose and without fee is hereby granted,
13 * provided that the above copyright notice appear in all copies and that
14 * both that copyright notice and this permission notice appear in
15 * supporting documentation.
17 * This file is provided AS IS with no warranties of any kind. The author
18 * shall have no liability with respect to the infringement of copyrights,
19 * trade secrets or any patents by this file or any part thereof. In no
20 * event will the author be liable for any lost revenue or profits or
21 * other special, indirect and consequential damages.
24 * 25-Feb-2005: Added bonus dots. I am using a recursive back track algorithm
25 * to help the ghost find there way home. This also means that
26 * they do not know the shorts path.
27 * Jeremy English jhe@jeremyenglish.org
28 * 15-Aug-2004: Added support for pixmap pacman.
29 * Jeremy English jhe@jeremyenglish.org
30 * 11-Aug-2004: Added support for pixmap ghost.
31 * Jeremy English jhe@jeremyenglish.org
32 * 13-May-2002: Added -trackmouse feature thanks to code from 'maze.c'.
33 * splitted up code into several files. Retouched AI code, cleaned
35 * 3-May-2002: Added AI to pacman and ghosts, slowed down ghosts.
36 * 26-Nov-2001: Random level generator added
37 * 01-Nov-2000: Allocation checks
38 * 04-Jun-1997: Compatible with xscreensaver
43 1. think of a better level generation algorithm
46 #define DEF_TRACKMOUSE "False"
50 # define DEFAULTS "*delay: 10000 \n" \
54 "*fpsSolid: true \n" \
56 # define UNIFORM_COLORS
57 # define BRIGHT_COLORS
58 # define release_pacman 0
59 # define pacman_handle_event 0
60 # include "xlockmore.h" /* in xscreensaver distribution */
62 #else /* STANDALONE */
63 # include "xlock.h" /* in xlockmore distribution */
64 #endif /* STANDALONE */
69 #include "pacman_ai.h"
70 #include "pacman_level.h"
72 #if defined(USE_PIXMAP) /* computed in pacman.h */
73 # include "images/pacman/ghost-u1.xpm"
74 # include "images/pacman/ghost-u2.xpm"
75 # include "images/pacman/ghost-r1.xpm"
76 # include "images/pacman/ghost-r2.xpm"
77 # include "images/pacman/ghost-l1.xpm"
78 # include "images/pacman/ghost-l2.xpm"
79 # include "images/pacman/ghost-d1.xpm"
80 # include "images/pacman/ghost-d2.xpm"
81 /* Used to clean up the dust left by wag. */
82 # include "images/pacman/ghost-mask.xpm"
83 # include "images/pacman/pacman-u1.xpm"
84 # include "images/pacman/pacman-u2.xpm"
85 # include "images/pacman/pacman-r1.xpm"
86 # include "images/pacman/pacman-r2.xpm"
87 # include "images/pacman/pacman-l1.xpm"
88 # include "images/pacman/pacman-l2.xpm"
89 # include "images/pacman/pacman-d1.xpm"
90 # include "images/pacman/pacman-d2.xpm"
91 # include "images/pacman/pacman-0.xpm"
92 # include "images/pacman/ghost-s1.xpm"
93 # include "images/pacman/ghost-s2.xpm"
94 # include "images/pacman/ghost-sf1.xpm"
95 # include "images/pacman/ghost-sf2.xpm"
96 # include "images/pacman/eyes-l.xpm"
97 # include "images/pacman/eyes-r.xpm"
98 # include "images/pacman/eyes-u.xpm"
99 # include "images/pacman/eyes-d.xpm"
100 # include "images/pacman/pacman-ds1.xpm"
101 # include "images/pacman/pacman-ds2.xpm"
102 # include "images/pacman/pacman-ds3.xpm"
103 # include "images/pacman/pacman-ds4.xpm"
104 # include "images/pacman/pacman-ds5.xpm"
105 # include "images/pacman/pacman-ds6.xpm"
106 # include "images/pacman/pacman-ds7.xpm"
107 # include "images/pacman/pacman-ds8.xpm"
114 } dirvecs[DIRVECS] = { { -1, 0},
120 #ifdef DISABLE_INTERACTIVE
121 ENTRYPOINT ModeSpecOpt pacman_opts = {
123 (XrmOptionDescRec *) NULL,
126 (OptionStruct *) NULL
129 static XrmOptionDescRec opts[] = {
130 {"-trackmouse", ".pacman.trackmouse", XrmoptionNoArg, "on"},
131 {"+trackmouse", ".pacman.trackmouse", XrmoptionNoArg, "off"}
134 static argtype vars[] = {
135 {&pacman_trackmouse, "trackmouse", "TrackMouse", DEF_TRACKMOUSE, t_Bool}
138 static OptionStruct desc[] = {
139 {"-/+trackmouse", "turn on/off the tracking of the mouse"}
142 ENTRYPOINT ModeSpecOpt pacman_opts =
143 { sizeof opts / sizeof opts[0], opts, sizeof vars / sizeof vars[0], vars,
148 ModStruct pacman_description = {
149 "pacman", /* *cmdline_arg; */
150 "init_pacman", /* *init_name; */
151 "draw_pacman", /* *callback_name; */
152 (char *) NULL, /* *release_name; */
153 "refresh_pacman", /* *refresh_name; */
154 "change_pacman", /* *change_name; */
155 (char *) NULL, /* *unused_name; */
156 &pacman_opts, /* *msopts */
157 10000, 4, 1, 0, 64, 1.0, "", "Shows Pacman(tm)", 0, NULL
162 Bool pacman_trackmouse;
163 pacmangamestruct *pacman_games = (pacmangamestruct *) NULL;
165 static void repopulate (ModeInfo * mi);
166 static void drawlevel (ModeInfo * mi);
170 free_pacman (ModeInfo * mi)
172 Display * display = MI_DISPLAY (mi);
173 pacmangamestruct * pp = &pacman_games[MI_SCREEN (mi)];
174 int dir, mouth, i, j, k;
176 if (pp->ghosts != NULL) {
178 pp->ghosts = (ghoststruct *) NULL;
180 if (pp->stippledGC != None) {
181 XFreeGC (display, pp->stippledGC);
182 pp->stippledGC = None;
184 for (i = 0; i < 4; i++) {
185 for (j = 0; j < MAXGDIR; j++) {
186 for (k = 0; k < MAXGWAG; k++) {
187 if (pp->ghostPixmap[i][j][k] != None) {
188 XFreePixmap (display, pp->ghostPixmap[i][j][k]);
189 pp->ghostPixmap[i][j][k] = None;
194 for (dir = 0; dir < 4; dir++)
195 for (mouth = 0; mouth < MAXMOUTH; mouth++)
196 if (pp->pacmanPixmap[dir][mouth] != None) {
197 XFreePixmap (display, pp->pacmanPixmap[dir][mouth]);
198 pp->pacmanPixmap[dir][mouth] = None;
202 /* set pacman and the ghost in there starting positions, but don't draw a new
205 reset_level (ModeInfo * mi, int n, int pac_init)
207 pacmangamestruct *pp = &pacman_games[MI_SCREEN (mi)];
213 pp->gamestate = GHOST_DANGER;
216 pp->pacman.row = (LEVHEIGHT + JAILHEIGHT) / 2 - n;
217 pp->pacman.init_row = pp->pacman.row;
220 pp->pacman.row = pp->pacman.init_row;
222 pp->pacman.col = (LEVWIDTH / 2);
223 pp->pacman.nextrow = NOWHERE;
224 pp->pacman.nextcol = NOWHERE;
225 pp->pacman.cf = NOWHERE;
226 pp->pacman.rf = NOWHERE;
227 pp->pacman.oldcf = NOWHERE;
228 pp->pacman.oldrf = NOWHERE;
229 pp->pacman.oldlx = NOWHERE;
230 pp->pacman.oldly = NOWHERE;
231 pp->pacman.aistate = ps_eating;
232 pp->pacman.cur_trace = 0;
233 pp->pacman.roundscore = 0;
234 pp->pacman.speed = 4;
235 pp->pacman.lastturn = 0;
236 pp->pacman.delta.x = 0;
237 pp->pacman.delta.y = 0;
239 for (ghost = 0; ghost < pp->nghosts; ghost++) {
240 pp->ghosts[ghost].col = (LEVWIDTH / 2);
241 pp->ghosts[ghost].row = (LEVHEIGHT / 2);
242 pp->ghosts[ghost].nextcol = NOWHERE;
243 pp->ghosts[ghost].nextrow = NOWHERE;
244 pp->ghosts[ghost].dead = 0;
245 pp->ghosts[ghost].lastbox = START;
246 pp->ghosts[ghost].cf = NOWHERE;
247 pp->ghosts[ghost].rf = NOWHERE;
248 pp->ghosts[ghost].oldcf = NOWHERE;
249 pp->ghosts[ghost].oldrf = NOWHERE;
250 pp->ghosts[ghost].aistate = inbox;
251 pp->ghosts[ghost].timeleft = ghost * 20;
252 pp->ghosts[ghost].speed = 3;
253 pp->ghosts[ghost].delta.x = 0;
254 pp->ghosts[ghost].delta.y = 0;
255 pp->ghosts[ghost].flash_scared = False;
256 pp->ghosts[ghost].wait_pos = False;
257 pacman_ghost_update (pp, &(pp->ghosts[ghost]));
259 pacman_update (mi, pp, &(pp->pacman));
263 pacman_ghost_collision(unsigned int ghost, pacmangamestruct * pp)
265 return (((pp->ghosts[ghost].nextrow == pp->pacman.nextrow) &&
266 (pp->ghosts[ghost].nextcol == pp->pacman.nextcol)) ||
267 ((pp->ghosts[ghost].nextrow == pp->pacman.row) &&
268 (pp->ghosts[ghost].nextcol == pp->pacman.col) &&
269 (pp->ghosts[ghost].row == pp->pacman.nextrow) &&
270 (pp->ghosts[ghost].col == pp->pacman.nextcol)));
274 /* Checks for death of any ghosts/pacman and updates. It also makes a new
275 level if all ghosts are dead or all dots are eaten. */
277 check_death (ModeInfo * mi, pacmangamestruct * pp)
279 Display *display = MI_DISPLAY (mi);
280 Window window = MI_WINDOW (mi);
283 if (pp->pacman.aistate == ps_dieing) return;
285 for (ghost = 0; ghost < pp->nghosts; ghost++) {
287 /* The ghost have to be scared before you can kill them */
288 if ( pacman_ghost_collision ( ghost, pp ) ) {
289 if (pp->ghosts[ghost].aistate == goingin) continue;
291 if (pp->ghosts[ghost].aistate == hiding) {
292 pp->ghosts[ghost].dead = 1;
293 pp->ghosts[ghost].aistate = goingin;
294 pp->ghosts[ghost].wait_pos = True;
295 XSetForeground (display, pp->stippledGC, MI_BLACK_PIXEL (mi));
296 XFillRectangle (display, window,
298 pp->ghosts[ghost].cf,
299 pp->ghosts[ghost].rf,
300 pp->spritexs, pp->spriteys);
305 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 = &pacman_games[MI_SCREEN (mi)];
318 pp->pacman.deaths = 0;
319 reset_level (mi, pacman_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 = &pacman_games[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 = &pacman_games[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 = &pacman_games[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 = &pacman_games[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 = &pacman_games[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 = &pacman_games[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 = &pacman_games[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 = &pacman_games[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 = &pacman_games[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 = &pacman_games[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_JWXYZ */
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 = &pacman_games[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 = &pacman_games[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;
835 draw_ghost_position (ModeInfo * mi, ghoststruct * ghost)
837 draw_position (mi, ghost->oldcf, ghost->oldrf, MI_BLACK_PIXEL (mi));
838 draw_position (mi, ghost->cf, ghost->rf, 0x00ff00);
843 draw_ghost_ndirs ( ModeInfo *mi, ghoststruct * ghost)
845 draw_number (mi, ghost->oldcf, ghost->oldrf, ghost->oldndirs, MI_BLACK_PIXEL (mi));
846 ghost->oldndirs = ghost->ndirs;
847 draw_number (mi, ghost->cf, ghost->rf, ghost->ndirs, 0x00ff00);
853 draw_ghost_sprite (ModeInfo * mi, const unsigned ghost)
855 Display *display = MI_DISPLAY (mi);
856 Window window = MI_WINDOW (mi);
857 pacmangamestruct *pp = &pacman_games[MI_SCREEN (mi)];
858 #define MAX_WAG_COUNT 50
859 unsigned int dir = 0;
860 unsigned int fs = 0; /*flash scared*/
861 Pixmap g_pix; /*ghost pixmap*/
864 dir = (ABS (pp->ghosts[ghost].cfactor) * (2 - pp->ghosts[ghost].cfactor) +
865 ABS (pp->ghosts[ghost].rfactor) * (1 + pp->ghosts[ghost].rfactor)) % 4;
868 fs = pp->ghosts[ghost].flash_scared;
869 assert (fs == 0 || fs == 1);
871 /* Choose the pixmap */
872 switch (pp->ghosts[ghost].aistate){
874 g_pix = pp->s_ghostPixmap[fs][pp->gh_wag];
877 g_pix = pp->ghostEyes[dir];
881 while ( i < pp->ghosts[ghost].trace_idx ){
882 XFillRectangle (display,
885 pp->ghosts[ghost].trace[i].vx,
886 pp->ghosts[ghost].trace[i].vy,
887 pp->spritexs, pp->spriteys);
896 g_pix = pp->ghostPixmap[ghost][dir][pp->gh_wag];
899 pp->ghosts[ghost].cf =
900 pp->ghosts[ghost].col * pp->xs + pp->ghosts[ghost].delta.x *
901 pp->ghosts[ghost].cfactor + pp->xb + pp->spritedx;
902 pp->ghosts[ghost].rf =
903 pp->ghosts[ghost].row * pp->ys + pp->ghosts[ghost].delta.y *
904 pp->ghosts[ghost].rfactor + pp->yb + pp->spritedy;
906 XSetForeground (display, pp->stippledGC, MI_BLACK_PIXEL (mi));
908 XSetClipMask (display, pp->stippledGC, pp->ghostMask);
909 XSetClipOrigin (display, pp->stippledGC,
910 pp->ghosts[ghost].oldcf, pp->ghosts[ghost].oldrf);
911 XFillRectangle (display,
914 pp->ghosts[ghost].oldcf,
915 pp->ghosts[ghost].oldrf, pp->spritexs, pp->spriteys);
918 if (pp->pacman.aistate != ps_dieing) {
919 drawlevelblock (mi, pp,
920 (unsigned int) pp->ghosts[ghost].col,
921 (unsigned int) pp->ghosts[ghost].row);
925 XSetClipOrigin (display, pp->stippledGC,
926 pp->ghosts[ghost].cf, pp->ghosts[ghost].rf);
928 XCopyArea (display, g_pix, window, pp->stippledGC, 0, 0,
929 pp->spritexs, pp->spriteys, pp->ghosts[ghost].cf,
930 pp->ghosts[ghost].rf);
932 XSetClipMask (display, pp->stippledGC, None);
935 draw_ghost_position (mi, &(pp->ghosts[ghost]));
939 draw_ghost_ndirs ( mi, &(pp->ghosts[ghost]));
942 if (pp->pacman.aistate != ps_dieing) {
943 pp->ghosts[ghost].oldcf = pp->ghosts[ghost].cf;
944 pp->ghosts[ghost].oldrf = pp->ghosts[ghost].rf;
945 if (pp->gh_wag_count++ == MAX_WAG_COUNT) {
946 pp->gh_wag = !pp->gh_wag;
947 pp->gh_wag_count = 0;
952 #else /* USE_PIXMAP */
954 /* Draws the pacman sprite, removing the previous location. */
956 draw_pacman_sprite (ModeInfo * mi)
958 Display *display = MI_DISPLAY (mi);
959 Window window = MI_WINDOW (mi);
960 pacmangamestruct *pp = &pacman_games[MI_SCREEN (mi)];
962 pp->pacman.cf = pp->pacman.col * pp->xs + pp->pacman.delta.x *
963 pp->pacman.cfactor + pp->xb + pp->spritedx;
964 pp->pacman.rf = pp->pacman.row * pp->ys + pp->pacman.delta.y *
965 pp->pacman.rfactor + pp->yb + pp->spritedy;
967 XSetForeground (display, pp->stippledGC, MI_BLACK_PIXEL (mi));
968 if (pp->pacman.oldcf != NOWHERE && pp->pacman.oldrf != NOWHERE) {
970 ERASE_IMAGE (display, window, pp->stippledGC,
971 pp->pacman.cf, pp->pacman.rf,
972 pp->pacman.oldcf, pp->pacman.oldrf,
973 pp->spritexs, pp->spriteys);
976 if (MI_NPIXELS (mi) > 2)
977 XSetForeground (display, pp->stippledGC, MI_PIXEL (mi, YELLOW));
979 XSetForeground (display, pp->stippledGC, MI_WHITE_PIXEL (mi));
981 XSetFillStyle (display, pp->stippledGC, FillOpaqueStippled);
983 if (pp->xs < 2 || pp->ys < 2)
984 XDrawPoint (display, window, pp->stippledGC,
985 pp->pacman.cf, pp->pacman.rf);
987 XFillRectangle (display, window, pp->stippledGC,
988 pp->pacman.cf, pp->pacman.rf,
989 pp->spritexs, pp->spriteys);
990 pp->pacman.mouthstage += pp->pacman.mouthdirection;
991 if ((pp->pacman.mouthstage >= MAXMOUTH) || (pp->pacman.mouthstage < 0)) {
992 pp->pacman.mouthdirection *= -1;
993 pp->pacman.mouthstage += pp->pacman.mouthdirection * 2;
995 pp->pacman.oldcf = pp->pacman.cf;
996 pp->pacman.oldrf = pp->pacman.rf;
999 /* Draws a ghost sprite, removing the previous sprite and restores the level. */
1001 draw_ghost_sprite (ModeInfo * mi, const unsigned ghost)
1003 Display *display = MI_DISPLAY (mi);
1004 Window window = MI_WINDOW (mi);
1005 pacmangamestruct *pp = &pacman_games[MI_SCREEN (mi)];
1007 pp->ghosts[ghost].cf =
1008 pp->ghosts[ghost].col * pp->xs + pp->ghosts[ghost].delta.x *
1009 pp->ghosts[ghost].cfactor + pp->xb + pp->spritedx;
1010 pp->ghosts[ghost].rf =
1011 pp->ghosts[ghost].row * pp->ys + pp->ghosts[ghost].delta.y *
1012 pp->ghosts[ghost].rfactor + pp->yb + pp->spritedy;
1014 XSetForeground (display, pp->stippledGC, MI_BLACK_PIXEL (mi));
1015 XFillRectangle (display,
1018 pp->ghosts[ghost].cf,
1019 pp->ghosts[ghost].rf, pp->spritexs, pp->spriteys);
1021 if (pp->ghosts[ghost].oldcf != NOWHERE ||
1022 pp->ghosts[ghost].oldrf != NOWHERE) {
1024 ERASE_IMAGE (display, window, pp->stippledGC,
1025 pp->ghosts[ghost].cf, pp->ghosts[ghost].rf,
1026 pp->ghosts[ghost].oldcf, pp->ghosts[ghost].oldrf,
1027 pp->spritexs, pp->spriteys);
1030 drawlevelblock (mi, pp,
1031 (unsigned int) pp->ghosts[ghost].col,
1032 (unsigned int) pp->ghosts[ghost].row);
1034 if (MI_NPIXELS (mi) > 2)
1035 XSetForeground (display, pp->stippledGC, MI_PIXEL (mi, GREEN));
1037 XSetForeground (display, pp->stippledGC, MI_WHITE_PIXEL (mi));
1039 XSetFillStyle (display, pp->stippledGC, FillOpaqueStippled);
1041 if (pp->xs < 2 || pp->ys < 2)
1042 XDrawPoint (display, window, pp->stippledGC,
1043 pp->ghosts[ghost].cf, pp->ghosts[ghost].rf);
1045 XFillRectangle (display,
1048 pp->ghosts[ghost].cf,
1049 pp->ghosts[ghost].rf, pp->spritexs, pp->spriteys);
1051 pp->ghosts[ghost].oldcf = pp->ghosts[ghost].cf;
1052 pp->ghosts[ghost].oldrf = pp->ghosts[ghost].rf;
1054 #endif /* USE_PIXMAP */
1057 ghost_over (ModeInfo * mi, int x, int y)
1061 pacmangamestruct *pp = &pacman_games[MI_SCREEN (mi)];
1062 dot_rc_to_pixel (mi, &x, &y);
1063 for (ghost = 0; ghost < pp->nghosts; ghost++) {
1064 if ((pp->ghosts[ghost].cf <= x
1065 && x <= pp->ghosts[ghost].cf + pp->spritexs)
1066 && (pp->ghosts[ghost].rf <= y
1067 && y <= pp->ghosts[ghost].rf + pp->spriteys)) {
1077 flash_bonus_dots (ModeInfo * mi)
1079 #define MAX_FLASH_COUNT 25
1080 pacmangamestruct *pp = &pacman_games[MI_SCREEN (mi)];
1082 for (i = 0; i < NUM_BONUS_DOTS; i++) {
1083 if (!pacman_bonus_dot_eaten (pp, i)) {
1084 pacman_bonus_dot_pos (pp, i, &x, &y);
1085 if (ghost_over (mi, x, y))
1088 draw_bonus_dot (mi, pp, x, y);
1090 clear_bonus_dot (mi, pp, x, y);
1093 if (pp->bd_flash_count-- == 0) {
1094 pp->bd_flash_count = MAX_FLASH_COUNT;
1095 pp->bd_on = !pp->bd_on;
1100 ate_bonus_dot (ModeInfo * mi)
1102 /*Check pacman's position. If it is over a bonus dot and that dot
1103 *has not been eaten, then return true
1105 unsigned int ret = 0;
1107 pacmangamestruct *pp = &pacman_games[MI_SCREEN (mi)];
1108 if (pacman_is_bonus_dot (pp, pp->pacman.col, pp->pacman.row, &idx)) {
1109 ret = !pacman_bonus_dot_eaten (pp, idx);
1110 pacman_eat_bonus_dot (pp, idx);
1116 ghost_scared (ModeInfo * mi)
1119 pacmangamestruct *pp = &pacman_games[MI_SCREEN (mi)];
1120 for (ghost = 0; ghost < pp->nghosts; ghost++) {
1121 if (pp->ghosts[ghost].aistate == goingin ||
1122 pp->ghosts[ghost].aistate == goingout ||
1123 pp->ghosts[ghost].aistate == inbox ) continue;
1124 pp->ghosts[ghost].aistate = hiding;
1125 pp->ghosts[ghost].flash_scared = 0;
1126 if (pp->pacman.aistate != ps_dieing)
1127 pp->pacman.aistate = ps_chasing;
1132 ghost_not_scared (ModeInfo * mi)
1135 pacmangamestruct *pp = &pacman_games[MI_SCREEN (mi)];
1136 for (ghost = 0; ghost < pp->nghosts; ghost++){
1137 if (pp->ghosts[ghost].aistate == goingin ||
1138 pp->ghosts[ghost].aistate == goingout ||
1139 pp->ghosts[ghost].aistate == inbox ) continue;
1140 pp->ghosts[ghost].aistate = chasing;
1142 if (pp->pacman.aistate != ps_dieing)
1143 pp->pacman.aistate = ps_eating;
1148 ghost_flash_scared (ModeInfo * mi)
1151 pacmangamestruct *pp = &pacman_games[MI_SCREEN (mi)];
1152 for (ghost = 0; ghost < pp->nghosts; ghost++)
1153 pp->ghosts[ghost].flash_scared = !pp->ghosts[ghost].flash_scared;
1156 /* Does all drawing of moving sprites in the level. */
1158 pacman_tick (ModeInfo * mi)
1160 #define DEFAULT_SCARED_TIME 500
1161 #define START_FLASH 200
1162 #define FLASH_COUNT 25
1164 pacmangamestruct *pp = &pacman_games[MI_SCREEN (mi)];
1169 for (ghost = 0; ghost < pp->nghosts; ghost++) {
1170 draw_ghost_sprite (mi, ghost);
1172 print_ghost_stats (mi, &(pp->ghosts[ghost]), ghost);
1176 print_pac_stats (mi, &(pp->pacman));
1178 draw_pacman_sprite (mi);
1179 flash_bonus_dots (mi);
1180 if (ate_bonus_dot (mi)) {
1181 pp->ghost_scared_timer = (random () % 100) + DEFAULT_SCARED_TIME;
1185 if (pp->ghost_scared_timer > 0) {
1186 if (--pp->ghost_scared_timer == 0)
1187 ghost_not_scared (mi);
1188 else if (pp->ghost_scared_timer <= START_FLASH) {
1189 if (pp->flash_timer <= 0) {
1190 pp->flash_timer = FLASH_COUNT;
1191 ghost_flash_scared (mi);
1198 We don't want to miss the last death sequence. So if pacman has died three times
1199 we wait for his state to change from dieing to something else before we repopulate
1200 the level. If pacman ate all of the dots then we just repopulate.
1203 if (pp->dotsleft == 0 )
1205 else if (pp->pacman.deaths >= 3){
1206 if (pp->old_pac_state == ps_dieing && pp->pacman.aistate != ps_dieing)
1210 pp->old_pac_state = pp->pacman.aistate;
1214 /* CODE TO LOAD AND SCALE THE PIXMAPS
1217 #if defined(USE_PIXMAP)
1218 /* Grabbed the scaling routine off of usenet.
1219 * Changed it so that the information specific
1220 * to the source pixmap does not have to be a parameter.
1222 * There is probably a better way to scale pixmaps.
1223 * From: Chris Fiddyment (cxf@itd.dsto.gov.au)
1224 * Subject: Scaling Pixmap Algorithm.
1225 * Newsgroups: comp.graphics.algorithms
1226 * Date: 1994-07-06 18:51:38 PST
1231 scale_pixmap (Display ** dpy, GC gc, Pixmap source, int dwidth, int dheight)
1236 float xscale, yscale;
1237 unsigned int swidth, sheight;
1240 unsigned border_width_return, depth;
1241 XGetGeometry (*dpy, source, &window, &x, &y, &swidth, &sheight,
1242 &border_width_return, &depth);
1244 xscale = (float) swidth / (float) dwidth; /* Scaling factors */
1245 yscale = (float) sheight / (float) dheight;
1247 dest = XCreatePixmap (*dpy, window, dwidth, dheight, depth);
1249 fprintf (stderr, "%s Could not scale image", progname);
1251 temp = XCreatePixmap (*dpy, window, dwidth, sheight, depth);
1253 fprintf (stderr, "%s Could not scale image", progname);
1257 end = dwidth * xscale;
1258 /* Scale width of source into temp pixmap */
1259 for (i = 0; i <= end; i += xscale)
1260 XCopyArea (*dpy, source, temp, gc, i, 0, 1, sheight, j++, 0);
1263 end = dheight * yscale;
1264 /* Scale height of temp into dest pixmap */
1265 for (i = 0; i <= end; i += yscale)
1266 XCopyArea (*dpy, temp, dest, gc, 0, i, dwidth, 1, 0, j++);
1268 XFreePixmap (*dpy, temp);
1269 return (Pixmap) dest;
1273 pacman_fail (char *s)
1275 fprintf (stderr, "%s: %s\n", progname, s);
1279 /* Load the ghost pixmaps and their mask. */
1281 load_ghost_pixmaps (Display ** dpy, Window window, pacmangamestruct ** ps)
1283 pacmangamestruct *pp = *ps;
1284 Display *display = *dpy;
1286 ". c #FF0000", /*Red */
1287 ". c #00FFDE", /*Blue */
1288 ". c #FFB847", /*Orange */
1289 ". c #FFB8DE", /*Pink */
1293 ghost_u1_xpm, ghost_u2_xpm, ghost_r1_xpm, ghost_r2_xpm,
1294 ghost_d1_xpm, ghost_d2_xpm, ghost_l1_xpm, ghost_l2_xpm
1296 char * const *s_bits[] = {
1297 ghost_s1_xpm, ghost_s2_xpm,
1298 ghost_sf1_xpm, ghost_sf2_xpm
1300 char * const *e_bits[] = {
1301 eyes_u_xpm, eyes_r_xpm, eyes_d_xpm, eyes_l_xpm
1305 int w = pp->spritexs;
1306 int h = pp->spriteys;
1310 for (i = 0; i < 4; i++) {
1312 for (j = 0; j < MAXGDIR; j++) {
1313 for (k = 0; k < MAXGWAG; k++) {
1314 bits[m][2] = colors[i];
1315 pp->ghostPixmap[i][j][k] =
1316 xpm_data_to_pixmap (display, window, bits[m], &w, &h,
1319 if (!pp->ghostPixmap[i][j][k])
1320 pacman_fail ("Cannot load ghost images");
1322 pp->ghostPixmap[i][j][k] =
1323 scale_pixmap (&display, pp->stippledGC,
1324 pp->ghostPixmap[i][j][k], pp->spritexs,
1327 if (!pp->ghostPixmap[i][j][k])
1328 pacman_fail ("Cannot scale ghost images");
1333 /* load the scared ghost */
1335 for (i = 0; i < MAXGFLASH; i++) {
1336 for (j = 0; j < MAXGWAG; j++) {
1337 pp->s_ghostPixmap[i][j] =
1338 xpm_data_to_pixmap (display, window, s_bits[m++], &w, &h,
1341 if (!pp->s_ghostPixmap[i][j])
1342 pacman_fail ("Cannot Scare Ghost images");
1343 pp->s_ghostPixmap[i][j] = scale_pixmap (&display, pp->stippledGC,
1344 pp->s_ghostPixmap[i][j],
1348 if (!pp->s_ghostPixmap[i][j])
1349 pacman_fail ("Cannot scale Scared Ghost images");
1352 /* load the ghost eyes */
1353 for (i = 0; i < MAXGDIR; i++) {
1355 xpm_data_to_pixmap (display, window, e_bits[i], &w, &h,
1358 if (!pp->ghostEyes[i])
1359 pacman_fail ("Cannot open ghost eye images");
1361 pp->ghostEyes[i] = scale_pixmap (&display, pp->stippledGC,
1366 if (!pp->ghostEyes[i])
1367 pacman_fail ("Cannot open ghost eye images");
1372 /* We really only need a single mask. This saves the headache of getting the
1373 * bottom of the ghost to clip just right. What we'll do is mask
1374 * the top portion of the ghost, but the bottom of the ghost will be solid.
1375 * I did this by setting the pixels between the fringe of their sheets
1376 * to black instead of none. -jeremy
1378 temp = xpm_data_to_pixmap (display, window, ghost_mask_xpm,
1379 &w, &h, &pp->ghostMask);
1382 pacman_fail ("Cannot load temporary ghost image");
1384 temp = scale_pixmap (&display, pp->stippledGC,
1385 temp, pp->spritexs, pp->spriteys);
1388 pacman_fail ("Cannot scale temporary ghost image");
1390 gc = XCreateGC (display, pp->ghostMask, 0, 0);
1392 pp->ghostMask = scale_pixmap (&display, gc, pp->ghostMask,
1393 pp->spritexs, pp->spriteys);
1394 XFreePixmap (display, temp);
1397 /* Load the pacman pixmaps and their mask. */
1399 load_pacman_pixmaps (Display ** dpy, Window window, pacmangamestruct ** ps)
1401 pacmangamestruct *pp = *ps;
1402 Display *display = *dpy;
1405 pacman_0_xpm, pacman_u1_xpm, pacman_u2_xpm,
1406 pacman_0_xpm, pacman_r1_xpm, pacman_r2_xpm,
1407 pacman_0_xpm, pacman_d1_xpm, pacman_d2_xpm,
1408 pacman_0_xpm, pacman_l1_xpm, pacman_l2_xpm
1411 char * const *ds_bits[] = {
1412 pacman_ds1_xpm, pacman_ds2_xpm, pacman_ds3_xpm, pacman_ds4_xpm,
1413 pacman_ds5_xpm, pacman_ds6_xpm, pacman_ds7_xpm, pacman_ds8_xpm
1417 int w = pp->spritexs;
1418 int h = pp->spriteys;
1422 for (i = 0; i < 4; i++) {
1423 for (j = 0; j < MAXMOUTH; j++) {
1424 pp->pacmanPixmap[i][j] =
1425 xpm_data_to_pixmap (display, window, bits[m++], &w, &h,
1426 &pp->pacmanMask[i][j]);
1428 if (!pp->pacmanPixmap[i][j])
1429 pacman_fail ("Cannot load pacman pixmap.");
1431 pp->pacmanPixmap[i][j] = scale_pixmap (&display, pp->stippledGC,
1432 pp->pacmanPixmap[i][j],
1436 if (!pp->pacmanPixmap[i][j])
1437 pacman_fail ("Cannot scale pacman pixmap.");
1440 gc = XCreateGC (display, pp->pacmanMask[i][j], 0, 0);
1442 pp->pacmanMask[i][j] =
1443 scale_pixmap (&display, gc, pp->pacmanMask[i][j],
1444 pp->spritexs, pp->spriteys);
1448 /* Load pacman death sequence */
1449 for ( i = 0; i < PAC_DEATH_FRAMES; i++ ){
1451 xpm_data_to_pixmap (display, window, ds_bits[i], &w, &h,
1452 &pp->pacman_ds_mask[i]);
1454 if (!pp->pacman_ds[i])
1455 pacman_fail ("Cannot load pacman death frame.");
1457 pp->pacman_ds[i] = scale_pixmap ( &display, pp->stippledGC,
1462 if (!pp->pacman_ds[i])
1463 pacman_fail ("Cannot scale pixmap.");
1466 gc = XCreateGC (display, pp->pacman_ds_mask[i], 0, 0);
1468 pp->pacman_ds_mask[i] =
1469 scale_pixmap (&display, gc, pp->pacman_ds_mask[i],
1470 pp->spritexs, pp->spriteys);
1474 #endif /* USE_PIXMAP */
1476 /* Hook function, sets state to initial position. */
1478 init_pacman (ModeInfo * mi)
1480 Display *display = MI_DISPLAY (mi);
1481 Window window = MI_WINDOW (mi);
1482 long size = MI_SIZE (mi);
1483 pacmangamestruct *pp;
1487 #if (! defined( USE_PIXMAP ))
1493 MI_INIT (mi, pacman_games, free_pacman);
1494 pp = &pacman_games[MI_SCREEN (mi)];
1496 pp->width = (unsigned short) MI_WIDTH (mi);
1497 pp->height = (unsigned short) MI_HEIGHT (mi);
1498 for (i = 0; i < 4; i++) {
1499 for (j = 0; j < MAXGDIR; j++) {
1500 for (k = 0; k < MAXGWAG; k++) {
1501 if (pp->ghostPixmap[i][j][k] != None) {
1502 XFreePixmap (display, pp->ghostPixmap[i][j][k]);
1503 pp->ghostPixmap[i][j][k] = None;
1504 pp->graphics_format = 0 /*IS_NONE */ ;
1510 for (i = 0; i < MAXGFLASH; i++) {
1511 for (j = 0; j < MAXGWAG; j++) {
1512 if (pp->s_ghostPixmap[i][j] != None) {
1513 XFreePixmap (display, pp->s_ghostPixmap[i][j]);
1514 pp->s_ghostPixmap[i][j] = None;
1520 MINGRIDSIZE * size > (int) pp->width ||
1521 MINGRIDSIZE * size > (int) pp->height) {
1523 pp->ys = pp->xs = MAX (MIN (pp->width / LEVWIDTH,
1524 pp->height / LEVHEIGHT), 1);
1527 if (size < -MINSIZE)
1528 pp->ys = (short) (NRAND (MIN (-size, MAX (MINSIZE,
1532 - MINSIZE + 1) + MINSIZE);
1533 else if (size < MINSIZE)
1536 pp->ys = (short) (MIN (size,
1537 MAX (MINSIZE, MIN (pp->width, pp->height) /
1542 pp->wallwidth = (unsigned int) (pp->xs + pp->ys) >> 4;
1543 if (pp->wallwidth < 1)
1545 pp->incx = (pp->xs >> 3) + 1;
1546 pp->incy = (pp->ys >> 3) + 1;
1547 pp->ncols = (unsigned short) MAX (LEVWIDTH, 2);
1548 pp->nrows = (unsigned short) MAX (LEVHEIGHT, 2);
1549 pp->xb = (pp->width - pp->ncols * pp->xs) >> 1;
1550 pp->yb = (pp->height - pp->nrows * pp->ys) >> 1;
1551 pp->spritexs = MAX (pp->xs + (pp->xs >> 1) - 1, 1);
1552 pp->spriteys = MAX (pp->ys + (pp->ys >> 1) - 1, 1);
1553 pp->spritedx = (pp->xs - pp->spritexs) >> 1;
1554 pp->spritedy = (pp->ys - pp->spriteys) >> 1;
1555 pp->old_pac_state = ps_chasing;
1557 if (!pp->stippledGC) {
1558 gcv.foreground = MI_BLACK_PIXEL (mi);
1559 gcv.background = MI_BLACK_PIXEL (mi);
1560 if ((pp->stippledGC = XCreateGC (display, window,
1561 GCForeground | GCBackground,
1569 jwxyz_XSetAntiAliasing (display, pp->stippledGC, False);
1572 #if defined(USE_PIXMAP)
1573 load_ghost_pixmaps (&display, window, &pp);
1574 load_pacman_pixmaps (&display, window, &pp);
1576 if ((pp->ghostPixmap[0][0][0] = XCreatePixmap (display, window,
1577 pp->spritexs, pp->spriteys,
1585 if ((bg_gc = XCreateGC (display, pp->ghostPixmap[0][0][0],
1586 GCForeground | GCBackground, &gcv)) == None) {
1593 if ((fg_gc = XCreateGC (display, pp->ghostPixmap[0][0][0],
1594 GCForeground | GCBackground, &gcv)) == None) {
1595 XFreeGC (display, bg_gc);
1600 #define SETPOINT(p, xp, yp) p.x = xp; p.y = yp
1602 /* draw the triangles on the bottom (scalable) */
1603 SETPOINT (points[0], 1, pp->spriteys * 5 / 6);
1604 SETPOINT (points[1], pp->spritexs / 6, pp->spriteys);
1605 SETPOINT (points[2], pp->spritexs / 3, pp->spriteys * 5 / 6);
1606 SETPOINT (points[3], pp->spritexs / 2, pp->spriteys);
1607 SETPOINT (points[4], pp->spritexs * 2 / 3, pp->spriteys * 5 / 6);
1608 SETPOINT (points[5], pp->spritexs * 5 / 6, pp->spriteys);
1609 SETPOINT (points[6], pp->spritexs, pp->spriteys * 5 / 6);
1610 SETPOINT (points[7], pp->spritexs, pp->spriteys / 2);
1611 SETPOINT (points[8], 1, pp->spriteys / 2);
1613 XFillRectangle (display, pp->ghostPixmap[0][0][0], bg_gc,
1614 0, 0, pp->spritexs, pp->spriteys);
1615 XFillArc (display, pp->ghostPixmap[0][0][0], fg_gc,
1616 0, 0, pp->spritexs, pp->spriteys, 0, 11520);
1617 XFillPolygon (display, pp->ghostPixmap[0][0][0], fg_gc,
1618 points, 9, Nonconvex, CoordModeOrigin);
1619 XFreeGC (display, bg_gc);
1620 XFreeGC (display, fg_gc);
1623 if (pp->pacmanPixmap[0][0] != None)
1624 for (dir = 0; dir < 4; dir++)
1625 for (mouth = 0; mouth < MAXMOUTH; mouth++)
1626 XFreePixmap (display, pp->pacmanPixmap[dir]
1629 for (dir = 0; dir < 4; dir++)
1630 for (mouth = 0; mouth < MAXMOUTH; mouth++) {
1631 if ((pp->pacmanPixmap[dir][mouth] =
1632 XCreatePixmap (display, MI_WINDOW (mi), pp->spritexs,
1633 pp->spriteys, 1)) == None) {
1639 if ((fg_gc = XCreateGC (display, pp->pacmanPixmap[dir][mouth],
1640 GCForeground | GCBackground,
1647 if ((bg_gc = XCreateGC (display,
1648 pp->pacmanPixmap[dir][mouth],
1650 GCBackground, &gcv)) == None) {
1651 XFreeGC (display, fg_gc);
1655 XFillRectangle (display,
1656 pp->pacmanPixmap[dir][mouth], bg_gc,
1657 0, 0, pp->spritexs, pp->spriteys);
1658 if (pp->spritexs == 1 && pp->spriteys == 1)
1659 XFillRectangle (display,
1660 pp->pacmanPixmap[dir][mouth],
1661 fg_gc, 0, 0, pp->spritexs, pp->spriteys);
1664 pp->pacmanPixmap[dir][mouth],
1666 0, 0, pp->spritexs, pp->spriteys,
1667 ((90 - dir * 90) + mouth * 5) * 64,
1668 (360 + (-2 * mouth * 5)) * 64);
1669 XFreeGC (display, fg_gc);
1670 XFreeGC (display, bg_gc);
1672 #endif /* USE_PIXMAP */
1674 pp->pacman.lastbox = START;
1675 pp->pacman.mouthdirection = 1;
1676 pp->pacman.nextcol = NOWHERE;
1677 pp->pacman.nextrow = NOWHERE;
1679 if (pp->ghosts != NULL) {
1681 pp->ghosts = (ghoststruct *) NULL;
1683 pp->nghosts = GHOSTS;
1686 if ((pp->ghosts = (ghoststruct *) calloc ((size_t) pp->nghosts,
1687 sizeof (ghoststruct))) ==
1693 pp->pacman.mouthstage = MAXMOUTH - 1;
1695 MI_CLEARWINDOW (mi);
1699 /* Callback function called for each tick. This is the complete machinery of
1700 everything that moves. */
1702 draw_pacman (ModeInfo * mi)
1705 pacmangamestruct *pp;
1707 if (pacman_games == NULL)
1709 pp = &pacman_games[MI_SCREEN (mi)];
1710 if (pp->ghosts == NULL)
1713 pp->pacman.err.x = (pp->pacman.err.x + 1) % pp->pacman.speed;
1714 pp->pacman.err.y = (pp->pacman.err.y + 1) % pp->pacman.speed;
1715 pp->pacman.delta.x += pp->pacman.err.x != 0 ? pp->incx : 0;
1716 pp->pacman.delta.y += pp->pacman.err.y != 0 ? pp->incy : 0;
1718 if (pp->pacman.delta.x >= pp->xs && pp->pacman.delta.y >= pp->ys) {
1719 pacman_update (mi, pp, &(pp->pacman));
1720 check_death (mi, pp);
1721 pp->pacman.delta.x = pp->incx;
1722 pp->pacman.delta.y = pp->incy;
1725 if (pp->pacman.delta.x > pp->xs + pp->incx)
1726 pp->pacman.delta.x = pp->xs + pp->incx;
1727 if (pp->pacman.delta.y > pp->ys + pp->incy)
1728 pp->pacman.delta.y = pp->ys + pp->incy;
1730 for (g = 0; g < pp->nghosts; g++) {
1731 pp->ghosts[g].err.x = (pp->ghosts[g].err.x + 1) % pp->ghosts[g].speed;
1732 pp->ghosts[g].err.y = (pp->ghosts[g].err.y + 1) % pp->ghosts[g].speed;
1733 pp->ghosts[g].delta.x += pp->ghosts[g].err.x != 0 ? pp->incx : 0;
1734 pp->ghosts[g].delta.y += pp->ghosts[g].err.y != 0 ? pp->incy : 0;
1736 if (pp->ghosts[g].delta.x >= pp->xs &&
1737 pp->ghosts[g].delta.y >= pp->ys) {
1738 pacman_ghost_update (pp, &(pp->ghosts[g]));
1739 pp->ghosts[g].delta.x = pp->incx;
1740 pp->ghosts[g].delta.y = pp->incy;
1743 if (pp->ghosts[g].delta.x > pp->xs + pp->incx)
1744 pp->ghosts[g].delta.x = pp->xs + pp->incx;
1745 if (pp->ghosts[g].delta.y > pp->ys + pp->incy)
1746 pp->ghosts[g].delta.y = pp->ys + pp->incy;
1751 /* Refresh current level. */
1753 refresh_pacman (ModeInfo * mi)
1760 reshape_pacman(ModeInfo * mi, int width, int height)
1762 pacmangamestruct *pp = &pacman_games[MI_SCREEN (mi)];
1764 pp->height = height;
1765 pp->xb = (pp->width - pp->ncols * pp->xs) >> 1;
1766 pp->yb = (pp->height - pp->nrows * pp->ys) >> 1;
1767 MI_CLEARWINDOW (mi);
1768 /* repopulate (mi); */
1773 /* Callback to change level. */
1775 change_pacman (ModeInfo * mi)
1777 MI_CLEARWINDOW (mi);
1780 #endif /* !STANDALONE */
1783 XSCREENSAVER_MODULE ("Pacman", pacman)
1785 #endif /* MODE_pacman */