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 pacman_handle_event 0
59 # include "xlockmore.h" /* in xscreensaver distribution */
61 #else /* STANDALONE */
62 # include "xlock.h" /* in xlockmore distribution */
63 #endif /* STANDALONE */
68 #include "pacman_ai.h"
69 #include "pacman_level.h"
71 #if defined(USE_PIXMAP) /* computed in pacman.h */
72 # include "images/pacman/ghost-u1.xpm"
73 # include "images/pacman/ghost-u2.xpm"
74 # include "images/pacman/ghost-r1.xpm"
75 # include "images/pacman/ghost-r2.xpm"
76 # include "images/pacman/ghost-l1.xpm"
77 # include "images/pacman/ghost-l2.xpm"
78 # include "images/pacman/ghost-d1.xpm"
79 # include "images/pacman/ghost-d2.xpm"
80 /* Used to clean up the dust left by wag. */
81 # include "images/pacman/ghost-mask.xpm"
82 # include "images/pacman/pacman-u1.xpm"
83 # include "images/pacman/pacman-u2.xpm"
84 # include "images/pacman/pacman-r1.xpm"
85 # include "images/pacman/pacman-r2.xpm"
86 # include "images/pacman/pacman-l1.xpm"
87 # include "images/pacman/pacman-l2.xpm"
88 # include "images/pacman/pacman-d1.xpm"
89 # include "images/pacman/pacman-d2.xpm"
90 # include "images/pacman/pacman-0.xpm"
91 # include "images/pacman/ghost-s1.xpm"
92 # include "images/pacman/ghost-s2.xpm"
93 # include "images/pacman/ghost-sf1.xpm"
94 # include "images/pacman/ghost-sf2.xpm"
95 # include "images/pacman/eyes-l.xpm"
96 # include "images/pacman/eyes-r.xpm"
97 # include "images/pacman/eyes-u.xpm"
98 # include "images/pacman/eyes-d.xpm"
99 # include "images/pacman/pacman-ds1.xpm"
100 # include "images/pacman/pacman-ds2.xpm"
101 # include "images/pacman/pacman-ds3.xpm"
102 # include "images/pacman/pacman-ds4.xpm"
103 # include "images/pacman/pacman-ds5.xpm"
104 # include "images/pacman/pacman-ds6.xpm"
105 # include "images/pacman/pacman-ds7.xpm"
106 # include "images/pacman/pacman-ds8.xpm"
113 } 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 {&pacman_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
161 Bool pacman_trackmouse;
162 pacmangamestruct *pacman_games = (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 = &pacman_games[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 pacman_ghost_update (pp, &(pp->ghosts[ghost]));
256 pacman_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);
280 if (pp->pacman.aistate == ps_dieing) return;
282 for (ghost = 0; ghost < pp->nghosts; ghost++) {
284 /* The ghost have to be scared before you can kill them */
285 if ( pacman_ghost_collision ( ghost, pp ) ) {
286 if (pp->ghosts[ghost].aistate == goingin) continue;
288 if (pp->ghosts[ghost].aistate == hiding) {
289 pp->ghosts[ghost].dead = 1;
290 pp->ghosts[ghost].aistate = goingin;
291 pp->ghosts[ghost].wait_pos = True;
292 XSetForeground (display, pp->stippledGC, MI_BLACK_PIXEL (mi));
293 XFillRectangle (display, window,
295 pp->ghosts[ghost].cf,
296 pp->ghosts[ghost].rf,
297 pp->spritexs, pp->spriteys);
302 pp->pacman.aistate = ps_dieing;
310 /* Resets state of ghosts + pacman. Creates a new level, draws that level. */
312 repopulate (ModeInfo * mi)
314 pacmangamestruct *pp = &pacman_games[MI_SCREEN (mi)];
315 pp->pacman.deaths = 0;
316 reset_level (mi, pacman_createnewlevel (pp), True);
317 check_death (mi, pp);
320 /* Sets the color to the color of a wall. */
322 setwallcolor (ModeInfo * mi)
324 Display *display = MI_DISPLAY (mi);
325 pacmangamestruct *pp = &pacman_games[MI_SCREEN (mi)];
327 if (MI_NPIXELS (mi) > 2)
328 XSetForeground (display, pp->stippledGC, MI_PIXEL (mi, BLUE));
330 XSetForeground (display, pp->stippledGC, MI_WHITE_PIXEL (mi));
333 /* Sets the color to the color of a dot. */
335 setdotcolor (ModeInfo * mi)
337 Display *display = MI_DISPLAY (mi);
338 pacmangamestruct *pp = &pacman_games[MI_SCREEN (mi)];
340 XSetForeground (display, pp->stippledGC, MI_WHITE_PIXEL (mi));
344 cleardotcolor (ModeInfo * mi)
346 Display *display = MI_DISPLAY (mi);
347 pacmangamestruct *pp = &pacman_games[MI_SCREEN (mi)];
349 XSetForeground (display, pp->stippledGC, MI_BLACK_PIXEL (mi));
354 draw_position (ModeInfo * mi, int x, int y, int color)
356 Display *display = MI_DISPLAY (mi);
357 Window window = MI_WINDOW (mi);
358 pacmangamestruct *pp = &pacman_games[MI_SCREEN (mi)];
359 XFontStruct *font = NULL;
360 char *f_name = "-*-utopia-*-r-*-*-*-600-*-*-p-*-*-*";
363 font = XLoadQueryFont (display, f_name);
364 assert (font != NULL);
366 s = (char *) malloc (256);
368 sprintf (s, "(%d,%d)", x, y);
369 XSetForeground (display, pp->stippledGC, color);
370 XDrawString (display, window, pp->stippledGC, x, y, s, strlen (s));
377 draw_number (ModeInfo * mi, int x, int y, int num, int color)
379 Display *display = MI_DISPLAY (mi);
380 Window window = MI_WINDOW (mi);
381 pacmangamestruct *pp = &pacman_games[MI_SCREEN (mi)];
382 XFontStruct *font = NULL;
383 char *f_name = "-*-utopia-*-r-*-*-*-600-*-*-p-*-*-*";
386 font = XLoadQueryFont (display, f_name);
387 assert (font != NULL);
389 s = (char *) malloc (256);
391 sprintf (s, "%d", num);
392 XSetForeground (display, pp->stippledGC, color);
393 XDrawString (display, window, pp->stippledGC, x, y, s, strlen (s));
400 /* draw_grid - draws a grid on top of the playing field.
401 * Used so that I can determine if I'm converting from rows and columns to x and y
402 * coordinates correctly.
405 draw_grid (ModeInfo * mi)
407 Display *display = MI_DISPLAY (mi);
408 Window window = MI_WINDOW (mi);
409 pacmangamestruct *pp = &pacman_games[MI_SCREEN (mi)];
410 int h = MI_HEIGHT (mi);
411 int w = MI_WIDTH (mi);
414 XSetForeground (display, pp->stippledGC, 0xff0000);
417 XDrawLine (display, window, pp->stippledGC, x, 0, x, h);
421 XDrawLine (display, window, pp->stippledGC, 0, y, w, y);
429 draw_string (ModeInfo * mi, int x, int y, char *s, int color)
431 Display *display = MI_DISPLAY (mi);
432 Window window = MI_WINDOW (mi);
433 pacmangamestruct *pp = &pacman_games[MI_SCREEN (mi)];
434 XFontStruct *font = NULL;
435 char *f_name = "-*-utopia-*-r-*-*-*-600-*-*-p-*-*-*";
437 font = XLoadQueryFont (display, f_name);
438 assert (font != NULL);
441 XSetForeground (display, pp->stippledGC, color);
442 XDrawString (display, window, pp->stippledGC, x, y, s, strlen (s));
446 /* I think this function has a memory leak. Be careful if you enable it. */
447 /* I only used it briefly to help me debug the ghost's aistate. It prints */
448 /* the state of each ghost on the left hand side of the screen */
450 print_ghost_stats (ModeInfo *mi, ghoststruct *g , int ghost_num)
454 sprintf (s, "GHOST: %d", ghost_num );
457 sprintf (s, "%s inbox", s);
460 sprintf (s, "%s goingout", s);
463 sprintf (s, "%s randdir", s);
466 sprintf (s, "%s chasing", s);
469 sprintf (s, "%s hiding", s);
472 sprintf (s, "%s goingin",s);
475 draw_string (mi, 0, (ghost_num *3) *10+50, g->last_stat, 0x000000);
476 draw_string (mi, 0, (ghost_num *3) *10+50, s, 0xff0000);
477 strcpy(g->last_stat,s);
480 /* prints the number of times pacman has died and his aistate on the left hand */
481 /* side of the screen */
483 print_pac_stats ( ModeInfo *mi, pacmanstruct *pac )
485 pacmangamestruct *pp = &pacman_games[MI_SCREEN (mi)];
487 sprintf (s, "Pacman, Deaths: %d", pac->deaths );
488 switch ( pac->aistate ){
490 sprintf(s, "%s ps_eating",s );
493 sprintf(s, "%s ps_chasing",s );
496 sprintf(s, "%s ps_hiding",s );
499 sprintf(s, "%s ps_random",s );
502 sprintf(s, "%s ps_dieing",s );
505 draw_string ( mi, 0, 200, pp->last_pac_stat, 0x000000);
506 draw_string ( mi, 0, 200, s, 0xff0000);
507 strcpy(pp->last_pac_stat, s );
512 /*Ok, yeah whatever?*/
513 /*dot_rc_to_pixel - magic that converts row and columns into
514 *the x and y coordinates of the screen.
517 dot_rc_to_pixel (ModeInfo * mi, int *x, int *y)
519 pacmangamestruct *pp = &pacman_games[MI_SCREEN (mi)];
521 (pp->xs / 2) - (pp->xs > 32 ? (pp->xs / 16) : 1) + pp->xb;
523 (pp->ys / 2) - (pp->ys > 32 ? (pp->ys / 16) : 1) + pp->yb;
526 /* dot_width_height - magic used to get the width and height of
527 * a dot. This dot can also be scaled by a value.
530 dot_width_height (ModeInfo *mi, int *w, int *h)
532 pacmangamestruct *pp = &pacman_games[MI_SCREEN (mi)];
534 *w = *h = (pp->xs / 32 );
541 bonus_dot_width_height (ModeInfo *mi, int *w, int *h )
543 *w = *h = MI_HEIGHT (mi) / 65;
549 draw_dot (ModeInfo * mi, pacmangamestruct * pp, int x, int y,
550 void (*width_height)(ModeInfo * mi, int *w, int *h),
551 int (*arc_func) (Display * display, Drawable d, GC gc,
552 int x, int y, unsigned int width,
553 unsigned int height, int angle1,
556 Display *display = MI_DISPLAY (mi);
557 Window window = MI_WINDOW (mi);
559 dot_rc_to_pixel (mi, &x, &y);
560 width_height(mi, &w, &h);
561 (void) arc_func (display, window, pp->stippledGC,
562 x, y, w, h, 0, 23040);
566 draw_bonus_dot (ModeInfo * mi, pacmangamestruct * pp, int x, int y)
571 draw_dot (mi, pp, x, y, bonus_dot_width_height, XFillArc);
572 dot_rc_to_pixel (mi, &x2, &y2);
574 draw_position (mi, x2, y2, 0xff0000);
579 clear_bonus_dot (ModeInfo * mi, pacmangamestruct * pp, int x, int y)
582 draw_dot (mi, pp, x, y, bonus_dot_width_height, XFillArc);
586 draw_regular_dot (ModeInfo * mi, pacmangamestruct * pp, int x, int y)
589 draw_dot (mi, pp, x, y, dot_width_height, XDrawArc);
592 /* Draws a block in the level at the specified x and y locations. */
594 drawlevelblock (ModeInfo * mi, pacmangamestruct * pp,
595 const unsigned x, const unsigned y)
597 Display *display = MI_DISPLAY (mi);
598 Window window = MI_WINDOW (mi);
607 XSetFillStyle (display, pp->stippledGC, FillSolid);
608 #endif /* !HAVE_JWXYZ */
609 XSetLineAttributes (display, pp->stippledGC, pp->wallwidth,
610 LineSolid, CapRound, JoinMiter);
612 if (pp->xs < 2 || pp->ys < 2) {
613 switch (pp->level[y * LEVWIDTH + x]) {
619 (void) XDrawPoint (display, window,
621 x * pp->xs + pp->xb, y * pp->ys + pp->yb);
625 (void) XDrawPoint (display, window,
627 x * pp->xs + pp->xb, y * pp->ys + pp->yb);
633 switch (pp->level[y * LEVWIDTH + x]) {
640 if (pp->xs < 8 || pp->ys < 8) {
641 (void) XDrawPoint (display, window,
643 x * pp->xs + pp->xb +
644 pp->xs / 2, y * pp->ys + pp->yb + pp->ys / 2);
648 draw_regular_dot (mi, pp, x, y);
650 /* What we will probably want to do here is have the pp->level store a 'o' for
651 * the bonus dots. The we can use the drawing routine above just with a bigger
655 draw_bonus_dot (mi, pp, x, y);
661 (void) XDrawLine (display, window, pp->stippledGC,
662 (pp->xs * x) + pp->xb,
663 (pp->ys * y) + (pp->ys / 2) + pp->yb,
664 (pp->xs * (x + 1)) + pp->xb,
665 (pp->ys * y) + (pp->ys / 2) + pp->yb);
670 (void) XDrawLine (display, window, pp->stippledGC,
671 (pp->xs * x) + (pp->xs / 2) + pp->xb,
672 (pp->ys * y) + pp->yb,
673 (pp->xs * x) + (pp->xs / 2) + pp->xb,
674 (pp->ys * (y + 1)) + pp->yb);
679 (void) XDrawArc (display, window, pp->stippledGC,
680 (pp->xs * x) - (pp->ys / 2) + pp->xb + dx,
681 (pp->ys * y) + (pp->ys / 2) + pp->yb,
682 pp->xs, pp->ys, 0 * 64, 90 * 64);
687 (void) XDrawArc (display, window, pp->stippledGC,
688 (pp->xs * x) + (pp->ys / 2) + pp->xb,
689 (pp->ys * y) + (pp->ys / 2) + pp->yb,
690 pp->xs, pp->ys, 90 * 64, 90 * 64);
695 (void) XDrawArc (display, window, pp->stippledGC,
696 (pp->xs * x) + (pp->ys / 2) + pp->xb,
697 (pp->ys * y) - (pp->ys / 2) + pp->yb + dy,
698 pp->xs, pp->ys, 180 * 64, 90 * 64);
703 (void) XDrawArc (display, window, pp->stippledGC,
704 (pp->xs * x) - (pp->ys / 2) + pp->xb + dx,
705 (pp->ys * y) - (pp->ys / 2) + pp->yb + dy,
706 pp->xs, pp->ys, 270 * 64, 90 * 64);
712 /* Draws a complete level. */
714 drawlevel (ModeInfo * mi)
716 pacmangamestruct *pp = &pacman_games[MI_SCREEN (mi)];
719 for (y = 0; y < LEVHEIGHT; y++)
720 for (x = 0; x < LEVWIDTH; x++)
721 drawlevelblock (mi, pp, x, y);
724 /* There is some overlap so it can be made more efficient */
725 #define ERASE_IMAGE(d,w,g,x,y,xl,yl,xs,ys) \
727 (y<(yl+ys))?XFillRectangle(d,w,g,xl,yl,xs,y-(yl)): \
728 XFillRectangle(d,w,g,xl,yl,xs,ys); \
730 (y>(yl-(ys)))?XFillRectangle(d,w,g,xl,y+ys,xs,yl-(y)): \
731 XFillRectangle(d,w,g,xl,yl,xs,ys); \
733 (x<(xl+xs))?XFillRectangle(d,w,g,xl,yl,x-(xl),ys): \
734 XFillRectangle(d,w,g,xl,yl,xs,ys); \
736 (x>(xl-(xs)))?XFillRectangle(d,w,g,x+xs,yl,xl-(x),ys): \
737 XFillRectangle(d,w,g,xl,yl,xs,ys)
740 /* Draws the pacman sprite, removing the previous location. */
741 #if defined(USE_PIXMAP)
744 draw_pacman_sprite (ModeInfo * mi)
746 Display *display = MI_DISPLAY (mi);
747 Window window = MI_WINDOW (mi);
748 pacmangamestruct *pp = &pacman_games[MI_SCREEN (mi)];
749 unsigned int dir = 0;
750 int old_mask_dir = 0;
751 int old_mask_mouth = 0;
752 Pixmap old_mask, new_mask;
755 #define MAX_MOUTH_DELAY 2
756 #define MAX_DEATH_DELAY 20
758 if (pp->pacman.aistate == ps_dieing){
759 pp->pacman.cf = pp->pacman.oldcf;
760 pp->pacman.rf = pp->pacman.oldrf;
763 pp->pacman.cf = pp->pacman.col * pp->xs + pp->pacman.delta.x *
764 pp->pacman.cfactor + pp->xb + pp->spritedx;
765 pp->pacman.rf = pp->pacman.row * pp->ys + pp->pacman.delta.y *
766 pp->pacman.rfactor + pp->yb + pp->spritedy;
769 dir = (ABS (pp->pacman.cfactor) * (2 - pp->pacman.cfactor) +
770 ABS (pp->pacman.rfactor) * (1 + pp->pacman.rfactor)) % 4;
772 if (pp->pm_mouth_delay == MAX_MOUTH_DELAY) {
773 if (pp->pm_mouth == (MAXMOUTH - 1) || pp->pm_mouth == 0) {
774 pp->pm_open_mouth = !pp->pm_open_mouth;
776 pp->pm_open_mouth ? pp->pm_mouth++ : pp->pm_mouth--;
777 pp->pm_mouth_delay = 0;
780 pp->pm_mouth_delay++;
783 if (pp->pacman.aistate == ps_dieing){
784 if (pp->pm_death_frame >= PAC_DEATH_FRAMES) {
785 pp->pacman.aistate = ps_eating;
786 pp->pm_death_frame = 0;
787 pp->pm_death_delay = 0;
788 reset_level (mi, 0, False);
792 old_mask = pp->pacmanMask[0][0];
793 new_mask = pp->pacmanMask[0][0];
794 pacman = pp->pacman_ds[pp->pm_death_frame];
795 if (pp->pm_death_delay == MAX_DEATH_DELAY){
796 pp->pm_death_frame++;
797 pp->pm_death_delay = 0;
800 pp->pm_death_delay++;
805 old_mask = pp->pacmanMask[old_mask_dir][old_mask_mouth];
806 new_mask = pp->pacmanMask[dir][pp->pm_mouth];
807 pacman = pp->pacmanPixmap[dir][pp->pm_mouth];
810 XSetForeground (display, pp->stippledGC, MI_BLACK_PIXEL (mi));
812 XSetClipMask (display, pp->stippledGC, old_mask);
814 XSetClipOrigin (display, pp->stippledGC, pp->pacman.oldcf,
816 XFillRectangle (display, window, pp->stippledGC, pp->pacman.oldcf,
817 pp->pacman.oldrf, pp->spritexs, pp->spriteys);
818 XSetClipMask (display, pp->stippledGC, new_mask);
819 XSetClipOrigin (display, pp->stippledGC, pp->pacman.cf, pp->pacman.rf);
820 XCopyArea (display, pacman, window,
821 pp->stippledGC, 0, 0, pp->spritexs, pp->spriteys,
822 pp->pacman.cf, pp->pacman.rf);
823 XSetClipMask (display, pp->stippledGC, None);
824 if (pp->pacman.aistate != ps_dieing){
825 pp->pacman.oldcf = pp->pacman.cf;
826 pp->pacman.oldrf = pp->pacman.rf;
832 draw_ghost_position (ModeInfo * mi, ghoststruct * ghost)
834 draw_position (mi, ghost->oldcf, ghost->oldrf, MI_BLACK_PIXEL (mi));
835 draw_position (mi, ghost->cf, ghost->rf, 0x00ff00);
840 draw_ghost_ndirs ( ModeInfo *mi, ghoststruct * ghost)
842 draw_number (mi, ghost->oldcf, ghost->oldrf, ghost->oldndirs, MI_BLACK_PIXEL (mi));
843 ghost->oldndirs = ghost->ndirs;
844 draw_number (mi, ghost->cf, ghost->rf, ghost->ndirs, 0x00ff00);
850 draw_ghost_sprite (ModeInfo * mi, const unsigned ghost)
852 Display *display = MI_DISPLAY (mi);
853 Window window = MI_WINDOW (mi);
854 pacmangamestruct *pp = &pacman_games[MI_SCREEN (mi)];
855 #define MAX_WAG_COUNT 50
856 unsigned int dir = 0;
857 unsigned int fs = 0; /*flash scared*/
858 Pixmap g_pix; /*ghost pixmap*/
861 dir = (ABS (pp->ghosts[ghost].cfactor) * (2 - pp->ghosts[ghost].cfactor) +
862 ABS (pp->ghosts[ghost].rfactor) * (1 + pp->ghosts[ghost].rfactor)) % 4;
865 fs = pp->ghosts[ghost].flash_scared;
866 assert (fs == 0 || fs == 1);
868 /* Choose the pixmap */
869 switch (pp->ghosts[ghost].aistate){
871 g_pix = pp->s_ghostPixmap[fs][pp->gh_wag];
874 g_pix = pp->ghostEyes[dir];
878 while ( i < pp->ghosts[ghost].trace_idx ){
879 XFillRectangle (display,
882 pp->ghosts[ghost].trace[i].vx,
883 pp->ghosts[ghost].trace[i].vy,
884 pp->spritexs, pp->spriteys);
893 g_pix = pp->ghostPixmap[ghost][dir][pp->gh_wag];
896 pp->ghosts[ghost].cf =
897 pp->ghosts[ghost].col * pp->xs + pp->ghosts[ghost].delta.x *
898 pp->ghosts[ghost].cfactor + pp->xb + pp->spritedx;
899 pp->ghosts[ghost].rf =
900 pp->ghosts[ghost].row * pp->ys + pp->ghosts[ghost].delta.y *
901 pp->ghosts[ghost].rfactor + pp->yb + pp->spritedy;
903 XSetForeground (display, pp->stippledGC, MI_BLACK_PIXEL (mi));
905 XSetClipMask (display, pp->stippledGC, pp->ghostMask);
906 XSetClipOrigin (display, pp->stippledGC,
907 pp->ghosts[ghost].oldcf, pp->ghosts[ghost].oldrf);
908 XFillRectangle (display,
911 pp->ghosts[ghost].oldcf,
912 pp->ghosts[ghost].oldrf, pp->spritexs, pp->spriteys);
915 if (pp->pacman.aistate != ps_dieing) {
916 drawlevelblock (mi, pp,
917 (unsigned int) pp->ghosts[ghost].col,
918 (unsigned int) pp->ghosts[ghost].row);
922 XSetClipOrigin (display, pp->stippledGC,
923 pp->ghosts[ghost].cf, pp->ghosts[ghost].rf);
925 XCopyArea (display, g_pix, window, pp->stippledGC, 0, 0,
926 pp->spritexs, pp->spriteys, pp->ghosts[ghost].cf,
927 pp->ghosts[ghost].rf);
929 XSetClipMask (display, pp->stippledGC, None);
932 draw_ghost_position (mi, &(pp->ghosts[ghost]));
936 draw_ghost_ndirs ( mi, &(pp->ghosts[ghost]));
939 if (pp->pacman.aistate != ps_dieing) {
940 pp->ghosts[ghost].oldcf = pp->ghosts[ghost].cf;
941 pp->ghosts[ghost].oldrf = pp->ghosts[ghost].rf;
942 if (pp->gh_wag_count++ == MAX_WAG_COUNT) {
943 pp->gh_wag = !pp->gh_wag;
944 pp->gh_wag_count = 0;
949 #else /* USE_PIXMAP */
951 /* Draws the pacman sprite, removing the previous location. */
953 draw_pacman_sprite (ModeInfo * mi)
955 Display *display = MI_DISPLAY (mi);
956 Window window = MI_WINDOW (mi);
957 pacmangamestruct *pp = &pacman_games[MI_SCREEN (mi)];
959 pp->pacman.cf = pp->pacman.col * pp->xs + pp->pacman.delta.x *
960 pp->pacman.cfactor + pp->xb + pp->spritedx;
961 pp->pacman.rf = pp->pacman.row * pp->ys + pp->pacman.delta.y *
962 pp->pacman.rfactor + pp->yb + pp->spritedy;
964 XSetForeground (display, pp->stippledGC, MI_BLACK_PIXEL (mi));
965 if (pp->pacman.oldcf != NOWHERE && pp->pacman.oldrf != NOWHERE) {
967 ERASE_IMAGE (display, window, pp->stippledGC,
968 pp->pacman.cf, pp->pacman.rf,
969 pp->pacman.oldcf, pp->pacman.oldrf,
970 pp->spritexs, pp->spriteys);
973 if (MI_NPIXELS (mi) > 2)
974 XSetForeground (display, pp->stippledGC, MI_PIXEL (mi, YELLOW));
976 XSetForeground (display, pp->stippledGC, MI_WHITE_PIXEL (mi));
978 XSetFillStyle (display, pp->stippledGC, FillOpaqueStippled);
980 if (pp->xs < 2 || pp->ys < 2)
981 XDrawPoint (display, window, pp->stippledGC,
982 pp->pacman.cf, pp->pacman.rf);
984 XFillRectangle (display, window, pp->stippledGC,
985 pp->pacman.cf, pp->pacman.rf,
986 pp->spritexs, pp->spriteys);
987 pp->pacman.mouthstage += pp->pacman.mouthdirection;
988 if ((pp->pacman.mouthstage >= MAXMOUTH) || (pp->pacman.mouthstage < 0)) {
989 pp->pacman.mouthdirection *= -1;
990 pp->pacman.mouthstage += pp->pacman.mouthdirection * 2;
992 pp->pacman.oldcf = pp->pacman.cf;
993 pp->pacman.oldrf = pp->pacman.rf;
996 /* Draws a ghost sprite, removing the previous sprite and restores the level. */
998 draw_ghost_sprite (ModeInfo * mi, const unsigned ghost)
1000 Display *display = MI_DISPLAY (mi);
1001 Window window = MI_WINDOW (mi);
1002 pacmangamestruct *pp = &pacman_games[MI_SCREEN (mi)];
1004 pp->ghosts[ghost].cf =
1005 pp->ghosts[ghost].col * pp->xs + pp->ghosts[ghost].delta.x *
1006 pp->ghosts[ghost].cfactor + pp->xb + pp->spritedx;
1007 pp->ghosts[ghost].rf =
1008 pp->ghosts[ghost].row * pp->ys + pp->ghosts[ghost].delta.y *
1009 pp->ghosts[ghost].rfactor + pp->yb + pp->spritedy;
1011 XSetForeground (display, pp->stippledGC, MI_BLACK_PIXEL (mi));
1012 XFillRectangle (display,
1015 pp->ghosts[ghost].cf,
1016 pp->ghosts[ghost].rf, pp->spritexs, pp->spriteys);
1018 if (pp->ghosts[ghost].oldcf != NOWHERE ||
1019 pp->ghosts[ghost].oldrf != NOWHERE) {
1021 ERASE_IMAGE (display, window, pp->stippledGC,
1022 pp->ghosts[ghost].cf, pp->ghosts[ghost].rf,
1023 pp->ghosts[ghost].oldcf, pp->ghosts[ghost].oldrf,
1024 pp->spritexs, pp->spriteys);
1027 drawlevelblock (mi, pp,
1028 (unsigned int) pp->ghosts[ghost].col,
1029 (unsigned int) pp->ghosts[ghost].row);
1031 if (MI_NPIXELS (mi) > 2)
1032 XSetForeground (display, pp->stippledGC, MI_PIXEL (mi, GREEN));
1034 XSetForeground (display, pp->stippledGC, MI_WHITE_PIXEL (mi));
1036 XSetFillStyle (display, pp->stippledGC, FillOpaqueStippled);
1038 if (pp->xs < 2 || pp->ys < 2)
1039 XDrawPoint (display, window, pp->stippledGC,
1040 pp->ghosts[ghost].cf, pp->ghosts[ghost].rf);
1042 XFillRectangle (display,
1045 pp->ghosts[ghost].cf,
1046 pp->ghosts[ghost].rf, pp->spritexs, pp->spriteys);
1048 pp->ghosts[ghost].oldcf = pp->ghosts[ghost].cf;
1049 pp->ghosts[ghost].oldrf = pp->ghosts[ghost].rf;
1051 #endif /* USE_PIXMAP */
1054 ghost_over (ModeInfo * mi, int x, int y)
1058 pacmangamestruct *pp = &pacman_games[MI_SCREEN (mi)];
1059 dot_rc_to_pixel (mi, &x, &y);
1060 for (ghost = 0; ghost < pp->nghosts; ghost++) {
1061 if ((pp->ghosts[ghost].cf <= x
1062 && x <= pp->ghosts[ghost].cf + pp->spritexs)
1063 && (pp->ghosts[ghost].rf <= y
1064 && y <= pp->ghosts[ghost].rf + pp->spriteys)) {
1074 flash_bonus_dots (ModeInfo * mi)
1076 #define MAX_FLASH_COUNT 25
1077 pacmangamestruct *pp = &pacman_games[MI_SCREEN (mi)];
1079 for (i = 0; i < NUM_BONUS_DOTS; i++) {
1080 if (!pacman_bonus_dot_eaten (pp, i)) {
1081 pacman_bonus_dot_pos (pp, i, &x, &y);
1082 if (ghost_over (mi, x, y))
1085 draw_bonus_dot (mi, pp, x, y);
1087 clear_bonus_dot (mi, pp, x, y);
1090 if (pp->bd_flash_count-- == 0) {
1091 pp->bd_flash_count = MAX_FLASH_COUNT;
1092 pp->bd_on = !pp->bd_on;
1097 ate_bonus_dot (ModeInfo * mi)
1099 /*Check pacman's position. If it is over a bonus dot and that dot
1100 *has not been eaten, then return true
1102 unsigned int ret = 0;
1104 pacmangamestruct *pp = &pacman_games[MI_SCREEN (mi)];
1105 if (pacman_is_bonus_dot (pp, pp->pacman.col, pp->pacman.row, &idx)) {
1106 ret = !pacman_bonus_dot_eaten (pp, idx);
1107 pacman_eat_bonus_dot (pp, idx);
1113 ghost_scared (ModeInfo * mi)
1116 pacmangamestruct *pp = &pacman_games[MI_SCREEN (mi)];
1117 for (ghost = 0; ghost < pp->nghosts; ghost++) {
1118 if (pp->ghosts[ghost].aistate == goingin ||
1119 pp->ghosts[ghost].aistate == goingout ||
1120 pp->ghosts[ghost].aistate == inbox ) continue;
1121 pp->ghosts[ghost].aistate = hiding;
1122 pp->ghosts[ghost].flash_scared = 0;
1123 if (pp->pacman.aistate != ps_dieing)
1124 pp->pacman.aistate = ps_chasing;
1129 ghost_not_scared (ModeInfo * mi)
1132 pacmangamestruct *pp = &pacman_games[MI_SCREEN (mi)];
1133 for (ghost = 0; ghost < pp->nghosts; ghost++){
1134 if (pp->ghosts[ghost].aistate == goingin ||
1135 pp->ghosts[ghost].aistate == goingout ||
1136 pp->ghosts[ghost].aistate == inbox ) continue;
1137 pp->ghosts[ghost].aistate = chasing;
1139 if (pp->pacman.aistate != ps_dieing)
1140 pp->pacman.aistate = ps_eating;
1145 ghost_flash_scared (ModeInfo * mi)
1148 pacmangamestruct *pp = &pacman_games[MI_SCREEN (mi)];
1149 for (ghost = 0; ghost < pp->nghosts; ghost++)
1150 pp->ghosts[ghost].flash_scared = !pp->ghosts[ghost].flash_scared;
1153 /* Does all drawing of moving sprites in the level. */
1155 pacman_tick (ModeInfo * mi)
1157 #define DEFAULT_SCARED_TIME 500
1158 #define START_FLASH 200
1159 #define FLASH_COUNT 25
1161 pacmangamestruct *pp = &pacman_games[MI_SCREEN (mi)];
1166 for (ghost = 0; ghost < pp->nghosts; ghost++) {
1167 draw_ghost_sprite (mi, ghost);
1169 print_ghost_stats (mi, &(pp->ghosts[ghost]), ghost);
1173 print_pac_stats (mi, &(pp->pacman));
1175 draw_pacman_sprite (mi);
1176 flash_bonus_dots (mi);
1177 if (ate_bonus_dot (mi)) {
1178 pp->ghost_scared_timer = (random () % 100) + DEFAULT_SCARED_TIME;
1182 if (pp->ghost_scared_timer > 0) {
1183 if (--pp->ghost_scared_timer == 0)
1184 ghost_not_scared (mi);
1185 else if (pp->ghost_scared_timer <= START_FLASH) {
1186 if (pp->flash_timer <= 0) {
1187 pp->flash_timer = FLASH_COUNT;
1188 ghost_flash_scared (mi);
1195 We don't want to miss the last death sequence. So if pacman has died three times
1196 we wait for his state to change from dieing to something else before we repopulate
1197 the level. If pacman ate all of the dots then we just repopulate.
1200 if (pp->dotsleft == 0 )
1202 else if (pp->pacman.deaths >= 3){
1203 if (pp->old_pac_state == ps_dieing && pp->pacman.aistate != ps_dieing)
1207 pp->old_pac_state = pp->pacman.aistate;
1211 /* CODE TO LOAD AND SCALE THE PIXMAPS
1214 #if defined(USE_PIXMAP)
1215 /* Grabbed the scaling routine off of usenet.
1216 * Changed it so that the information specific
1217 * to the source pixmap does not have to be a parameter.
1219 * There is probably a better way to scale pixmaps.
1220 * From: Chris Fiddyment (cxf@itd.dsto.gov.au)
1221 * Subject: Scaling Pixmap Algorithm.
1222 * Newsgroups: comp.graphics.algorithms
1223 * Date: 1994-07-06 18:51:38 PST
1228 scale_pixmap (Display ** dpy, GC gc, Pixmap source, int dwidth, int dheight)
1233 float xscale, yscale;
1234 unsigned int swidth, sheight;
1237 unsigned border_width_return, depth;
1238 XGetGeometry (*dpy, source, &window, &x, &y, &swidth, &sheight,
1239 &border_width_return, &depth);
1241 xscale = (float) swidth / (float) dwidth; /* Scaling factors */
1242 yscale = (float) sheight / (float) dheight;
1244 dest = XCreatePixmap (*dpy, window, dwidth, dheight, depth);
1246 fprintf (stderr, "%s Could not scale image", progname);
1248 temp = XCreatePixmap (*dpy, window, dwidth, sheight, depth);
1250 fprintf (stderr, "%s Could not scale image", progname);
1254 end = dwidth * xscale;
1255 /* Scale width of source into temp pixmap */
1256 for (i = 0; i <= end; i += xscale)
1257 XCopyArea (*dpy, source, temp, gc, i, 0, 1, sheight, j++, 0);
1260 end = dheight * yscale;
1261 /* Scale height of temp into dest pixmap */
1262 for (i = 0; i <= end; i += yscale)
1263 XCopyArea (*dpy, temp, dest, gc, 0, i, dwidth, 1, 0, j++);
1265 XFreePixmap (*dpy, temp);
1266 return (Pixmap) dest;
1270 pacman_fail (char *s)
1272 fprintf (stderr, "%s: %s\n", progname, s);
1276 /* Load the ghost pixmaps and their mask. */
1278 load_ghost_pixmaps (Display ** dpy, Window window, pacmangamestruct ** ps)
1280 pacmangamestruct *pp = *ps;
1281 Display *display = *dpy;
1283 ". c #FF0000", /*Red */
1284 ". c #00FFDE", /*Blue */
1285 ". c #FFB847", /*Orange */
1286 ". c #FFB8DE", /*Pink */
1290 ghost_u1_xpm, ghost_u2_xpm, ghost_r1_xpm, ghost_r2_xpm,
1291 ghost_d1_xpm, ghost_d2_xpm, ghost_l1_xpm, ghost_l2_xpm
1293 char * const *s_bits[] = {
1294 ghost_s1_xpm, ghost_s2_xpm,
1295 ghost_sf1_xpm, ghost_sf2_xpm
1297 char * const *e_bits[] = {
1298 eyes_u_xpm, eyes_r_xpm, eyes_d_xpm, eyes_l_xpm
1302 int w = pp->spritexs;
1303 int h = pp->spriteys;
1307 for (i = 0; i < 4; i++) {
1309 for (j = 0; j < MAXGDIR; j++) {
1310 for (k = 0; k < MAXGWAG; k++) {
1311 bits[m][2] = colors[i];
1312 pp->ghostPixmap[i][j][k] =
1313 xpm_data_to_pixmap (display, window, bits[m], &w, &h,
1316 if (!pp->ghostPixmap[i][j][k])
1317 pacman_fail ("Cannot load ghost images");
1319 pp->ghostPixmap[i][j][k] =
1320 scale_pixmap (&display, pp->stippledGC,
1321 pp->ghostPixmap[i][j][k], pp->spritexs,
1324 if (!pp->ghostPixmap[i][j][k])
1325 pacman_fail ("Cannot scale ghost images");
1330 /* load the scared ghost */
1332 for (i = 0; i < MAXGFLASH; i++) {
1333 for (j = 0; j < MAXGWAG; j++) {
1334 pp->s_ghostPixmap[i][j] =
1335 xpm_data_to_pixmap (display, window, s_bits[m++], &w, &h,
1338 if (!pp->s_ghostPixmap[i][j])
1339 pacman_fail ("Cannot Scare Ghost images");
1340 pp->s_ghostPixmap[i][j] = scale_pixmap (&display, pp->stippledGC,
1341 pp->s_ghostPixmap[i][j],
1345 if (!pp->s_ghostPixmap[i][j])
1346 pacman_fail ("Cannot scale Scared Ghost images");
1349 /* load the ghost eyes */
1350 for (i = 0; i < MAXGDIR; i++) {
1352 xpm_data_to_pixmap (display, window, e_bits[i], &w, &h,
1355 if (!pp->ghostEyes[i])
1356 pacman_fail ("Cannot open ghost eye images");
1358 pp->ghostEyes[i] = scale_pixmap (&display, pp->stippledGC,
1363 if (!pp->ghostEyes[i])
1364 pacman_fail ("Cannot open ghost eye images");
1369 /* We really only need a single mask. This saves the headache of getting the
1370 * bottom of the ghost to clip just right. What we'll do is mask
1371 * the top portion of the ghost, but the bottom of the ghost will be solid.
1372 * I did this by setting the pixels between the fringe of their sheets
1373 * to black instead of none. -jeremy
1375 temp = xpm_data_to_pixmap (display, window, ghost_mask_xpm,
1376 &w, &h, &pp->ghostMask);
1379 pacman_fail ("Cannot load temporary ghost image");
1381 temp = scale_pixmap (&display, pp->stippledGC,
1382 temp, pp->spritexs, pp->spriteys);
1385 pacman_fail ("Cannot scale temporary ghost image");
1387 gc = XCreateGC (display, pp->ghostMask, 0, 0);
1389 pp->ghostMask = scale_pixmap (&display, gc, pp->ghostMask,
1390 pp->spritexs, pp->spriteys);
1391 XFreePixmap (display, temp);
1394 /* Load the pacman pixmaps and their mask. */
1396 load_pacman_pixmaps (Display ** dpy, Window window, pacmangamestruct ** ps)
1398 pacmangamestruct *pp = *ps;
1399 Display *display = *dpy;
1402 pacman_0_xpm, pacman_u1_xpm, pacman_u2_xpm,
1403 pacman_0_xpm, pacman_r1_xpm, pacman_r2_xpm,
1404 pacman_0_xpm, pacman_d1_xpm, pacman_d2_xpm,
1405 pacman_0_xpm, pacman_l1_xpm, pacman_l2_xpm
1408 char * const *ds_bits[] = {
1409 pacman_ds1_xpm, pacman_ds2_xpm, pacman_ds3_xpm, pacman_ds4_xpm,
1410 pacman_ds5_xpm, pacman_ds6_xpm, pacman_ds7_xpm, pacman_ds8_xpm
1414 int w = pp->spritexs;
1415 int h = pp->spriteys;
1419 for (i = 0; i < 4; i++) {
1420 for (j = 0; j < MAXMOUTH; j++) {
1421 pp->pacmanPixmap[i][j] =
1422 xpm_data_to_pixmap (display, window, bits[m++], &w, &h,
1423 &pp->pacmanMask[i][j]);
1425 if (!pp->pacmanPixmap[i][j])
1426 pacman_fail ("Cannot load pacman pixmap.");
1428 pp->pacmanPixmap[i][j] = scale_pixmap (&display, pp->stippledGC,
1429 pp->pacmanPixmap[i][j],
1433 if (!pp->pacmanPixmap[i][j])
1434 pacman_fail ("Cannot scale pacman pixmap.");
1437 gc = XCreateGC (display, pp->pacmanMask[i][j], 0, 0);
1439 pp->pacmanMask[i][j] =
1440 scale_pixmap (&display, gc, pp->pacmanMask[i][j],
1441 pp->spritexs, pp->spriteys);
1445 /* Load pacman death sequence */
1446 for ( i = 0; i < PAC_DEATH_FRAMES; i++ ){
1448 xpm_data_to_pixmap (display, window, ds_bits[i], &w, &h,
1449 &pp->pacman_ds_mask[i]);
1451 if (!pp->pacman_ds[i])
1452 pacman_fail ("Cannot load pacman death frame.");
1454 pp->pacman_ds[i] = scale_pixmap ( &display, pp->stippledGC,
1459 if (!pp->pacman_ds[i])
1460 pacman_fail ("Cannot scale pixmap.");
1463 gc = XCreateGC (display, pp->pacman_ds_mask[i], 0, 0);
1465 pp->pacman_ds_mask[i] =
1466 scale_pixmap (&display, gc, pp->pacman_ds_mask[i],
1467 pp->spritexs, pp->spriteys);
1471 #endif /* USE_PIXMAP */
1473 /* Hook function, sets state to initial position. */
1475 init_pacman (ModeInfo * mi)
1477 Display *display = MI_DISPLAY (mi);
1478 Window window = MI_WINDOW (mi);
1479 long size = MI_SIZE (mi);
1480 pacmangamestruct *pp;
1484 #if (! defined( USE_PIXMAP ))
1490 if (pacman_games == NULL) {
1491 if ((pacman_games = (pacmangamestruct *)
1492 calloc ((size_t) MI_NUM_SCREENS (mi),
1493 sizeof (pacmangamestruct))) == NULL)
1496 pp = &pacman_games[MI_SCREEN (mi)];
1498 pp->width = (unsigned short) MI_WIDTH (mi);
1499 pp->height = (unsigned short) MI_HEIGHT (mi);
1500 for (i = 0; i < 4; i++) {
1501 for (j = 0; j < MAXGDIR; j++) {
1502 for (k = 0; k < MAXGWAG; k++) {
1503 if (pp->ghostPixmap[i][j][k] != None) {
1504 XFreePixmap (display, pp->ghostPixmap[i][j][k]);
1505 pp->ghostPixmap[i][j][k] = None;
1506 pp->graphics_format = 0 /*IS_NONE */ ;
1512 for (i = 0; i < MAXGFLASH; i++) {
1513 for (j = 0; j < MAXGWAG; j++) {
1514 if (pp->s_ghostPixmap[i][j] != None) {
1515 XFreePixmap (display, pp->s_ghostPixmap[i][j]);
1516 pp->s_ghostPixmap[i][j] = None;
1522 MINGRIDSIZE * size > (int) pp->width ||
1523 MINGRIDSIZE * size > (int) pp->height) {
1525 pp->ys = pp->xs = MAX (MIN (pp->width / LEVWIDTH,
1526 pp->height / LEVHEIGHT), 1);
1529 if (size < -MINSIZE)
1530 pp->ys = (short) (NRAND (MIN (-size, MAX (MINSIZE,
1534 - MINSIZE + 1) + MINSIZE);
1535 else if (size < MINSIZE)
1538 pp->ys = (short) (MIN (size,
1539 MAX (MINSIZE, MIN (pp->width, pp->height) /
1544 pp->wallwidth = (unsigned int) (pp->xs + pp->ys) >> 4;
1545 if (pp->wallwidth < 1)
1547 pp->incx = (pp->xs >> 3) + 1;
1548 pp->incy = (pp->ys >> 3) + 1;
1549 pp->ncols = (unsigned short) MAX (LEVWIDTH, 2);
1550 pp->nrows = (unsigned short) MAX (LEVHEIGHT, 2);
1551 pp->xb = (pp->width - pp->ncols * pp->xs) >> 1;
1552 pp->yb = (pp->height - pp->nrows * pp->ys) >> 1;
1553 pp->spritexs = MAX (pp->xs + (pp->xs >> 1) - 1, 1);
1554 pp->spriteys = MAX (pp->ys + (pp->ys >> 1) - 1, 1);
1555 pp->spritedx = (pp->xs - pp->spritexs) >> 1;
1556 pp->spritedy = (pp->ys - pp->spriteys) >> 1;
1557 pp->old_pac_state = ps_chasing;
1559 if (!pp->stippledGC) {
1560 gcv.foreground = MI_BLACK_PIXEL (mi);
1561 gcv.background = MI_BLACK_PIXEL (mi);
1562 if ((pp->stippledGC = XCreateGC (display, window,
1563 GCForeground | GCBackground,
1565 free_pacman (display, pp);
1571 jwxyz_XSetAntiAliasing (display, pp->stippledGC, False);
1574 #if defined(USE_PIXMAP)
1575 load_ghost_pixmaps (&display, window, &pp);
1576 load_pacman_pixmaps (&display, window, &pp);
1578 if ((pp->ghostPixmap[0][0][0] = XCreatePixmap (display, window,
1579 pp->spritexs, pp->spriteys,
1581 free_pacman (display, pp);
1587 if ((bg_gc = XCreateGC (display, pp->ghostPixmap[0][0][0],
1588 GCForeground | GCBackground, &gcv)) == None) {
1589 free_pacman (display, pp);
1595 if ((fg_gc = XCreateGC (display, pp->ghostPixmap[0][0][0],
1596 GCForeground | GCBackground, &gcv)) == None) {
1597 XFreeGC (display, bg_gc);
1598 free_pacman (display, pp);
1602 #define SETPOINT(p, xp, yp) p.x = xp; p.y = yp
1604 /* draw the triangles on the bottom (scalable) */
1605 SETPOINT (points[0], 1, pp->spriteys * 5 / 6);
1606 SETPOINT (points[1], pp->spritexs / 6, pp->spriteys);
1607 SETPOINT (points[2], pp->spritexs / 3, pp->spriteys * 5 / 6);
1608 SETPOINT (points[3], pp->spritexs / 2, pp->spriteys);
1609 SETPOINT (points[4], pp->spritexs * 2 / 3, pp->spriteys * 5 / 6);
1610 SETPOINT (points[5], pp->spritexs * 5 / 6, pp->spriteys);
1611 SETPOINT (points[6], pp->spritexs, pp->spriteys * 5 / 6);
1612 SETPOINT (points[7], pp->spritexs, pp->spriteys / 2);
1613 SETPOINT (points[8], 1, pp->spriteys / 2);
1615 XFillRectangle (display, pp->ghostPixmap[0][0][0], bg_gc,
1616 0, 0, pp->spritexs, pp->spriteys);
1617 XFillArc (display, pp->ghostPixmap[0][0][0], fg_gc,
1618 0, 0, pp->spritexs, pp->spriteys, 0, 11520);
1619 XFillPolygon (display, pp->ghostPixmap[0][0][0], fg_gc,
1620 points, 9, Nonconvex, CoordModeOrigin);
1621 XFreeGC (display, bg_gc);
1622 XFreeGC (display, fg_gc);
1625 if (pp->pacmanPixmap[0][0] != None)
1626 for (dir = 0; dir < 4; dir++)
1627 for (mouth = 0; mouth < MAXMOUTH; mouth++)
1628 XFreePixmap (display, pp->pacmanPixmap[dir]
1631 for (dir = 0; dir < 4; dir++)
1632 for (mouth = 0; mouth < MAXMOUTH; mouth++) {
1633 if ((pp->pacmanPixmap[dir][mouth] =
1634 XCreatePixmap (display, MI_WINDOW (mi), pp->spritexs,
1635 pp->spriteys, 1)) == None) {
1636 free_pacman (display, pp);
1641 if ((fg_gc = XCreateGC (display, pp->pacmanPixmap[dir][mouth],
1642 GCForeground | GCBackground,
1644 free_pacman (display, pp);
1649 if ((bg_gc = XCreateGC (display,
1650 pp->pacmanPixmap[dir][mouth],
1652 GCBackground, &gcv)) == None) {
1653 XFreeGC (display, fg_gc);
1654 free_pacman (display, pp);
1657 XFillRectangle (display,
1658 pp->pacmanPixmap[dir][mouth], bg_gc,
1659 0, 0, pp->spritexs, pp->spriteys);
1660 if (pp->spritexs == 1 && pp->spriteys == 1)
1661 XFillRectangle (display,
1662 pp->pacmanPixmap[dir][mouth],
1663 fg_gc, 0, 0, pp->spritexs, pp->spriteys);
1666 pp->pacmanPixmap[dir][mouth],
1668 0, 0, pp->spritexs, pp->spriteys,
1669 ((90 - dir * 90) + mouth * 5) * 64,
1670 (360 + (-2 * mouth * 5)) * 64);
1671 XFreeGC (display, fg_gc);
1672 XFreeGC (display, bg_gc);
1674 #endif /* USE_PIXMAP */
1676 pp->pacman.lastbox = START;
1677 pp->pacman.mouthdirection = 1;
1678 pp->pacman.nextcol = NOWHERE;
1679 pp->pacman.nextrow = NOWHERE;
1681 if (pp->ghosts != NULL) {
1683 pp->ghosts = (ghoststruct *) NULL;
1685 pp->nghosts = GHOSTS;
1688 if ((pp->ghosts = (ghoststruct *) calloc ((size_t) pp->nghosts,
1689 sizeof (ghoststruct))) ==
1691 free_pacman (display, pp);
1695 pp->pacman.mouthstage = MAXMOUTH - 1;
1697 MI_CLEARWINDOW (mi);
1701 /* Callback function called for each tick. This is the complete machinery of
1702 everything that moves. */
1704 draw_pacman (ModeInfo * mi)
1707 pacmangamestruct *pp;
1709 if (pacman_games == NULL)
1711 pp = &pacman_games[MI_SCREEN (mi)];
1712 if (pp->ghosts == NULL)
1715 pp->pacman.err.x = (pp->pacman.err.x + 1) % pp->pacman.speed;
1716 pp->pacman.err.y = (pp->pacman.err.y + 1) % pp->pacman.speed;
1717 pp->pacman.delta.x += pp->pacman.err.x != 0 ? pp->incx : 0;
1718 pp->pacman.delta.y += pp->pacman.err.y != 0 ? pp->incy : 0;
1720 if (pp->pacman.delta.x >= pp->xs && pp->pacman.delta.y >= pp->ys) {
1721 pacman_update (mi, pp, &(pp->pacman));
1722 check_death (mi, pp);
1723 pp->pacman.delta.x = pp->incx;
1724 pp->pacman.delta.y = pp->incy;
1727 if (pp->pacman.delta.x > pp->xs + pp->incx)
1728 pp->pacman.delta.x = pp->xs + pp->incx;
1729 if (pp->pacman.delta.y > pp->ys + pp->incy)
1730 pp->pacman.delta.y = pp->ys + pp->incy;
1732 for (g = 0; g < pp->nghosts; g++) {
1733 pp->ghosts[g].err.x = (pp->ghosts[g].err.x + 1) % pp->ghosts[g].speed;
1734 pp->ghosts[g].err.y = (pp->ghosts[g].err.y + 1) % pp->ghosts[g].speed;
1735 pp->ghosts[g].delta.x += pp->ghosts[g].err.x != 0 ? pp->incx : 0;
1736 pp->ghosts[g].delta.y += pp->ghosts[g].err.y != 0 ? pp->incy : 0;
1738 if (pp->ghosts[g].delta.x >= pp->xs &&
1739 pp->ghosts[g].delta.y >= pp->ys) {
1740 pacman_ghost_update (pp, &(pp->ghosts[g]));
1741 pp->ghosts[g].delta.x = pp->incx;
1742 pp->ghosts[g].delta.y = pp->incy;
1745 if (pp->ghosts[g].delta.x > pp->xs + pp->incx)
1746 pp->ghosts[g].delta.x = pp->xs + pp->incx;
1747 if (pp->ghosts[g].delta.y > pp->ys + pp->incy)
1748 pp->ghosts[g].delta.y = pp->ys + pp->incy;
1753 /* Releases resources. */
1755 release_pacman (ModeInfo * mi)
1757 if (pacman_games != NULL) {
1760 for (screen = 0; screen < MI_NUM_SCREENS (mi); screen++)
1761 free_pacman (MI_DISPLAY (mi), &pacman_games[screen]);
1762 free (pacman_games);
1763 pacman_games = (pacmangamestruct *) NULL;
1767 /* Refresh current level. */
1769 refresh_pacman (ModeInfo * mi)
1776 reshape_pacman(ModeInfo * mi, int width, int height)
1778 pacmangamestruct *pp = &pacman_games[MI_SCREEN (mi)];
1780 pp->height = height;
1781 pp->xb = (pp->width - pp->ncols * pp->xs) >> 1;
1782 pp->yb = (pp->height - pp->nrows * pp->ys) >> 1;
1783 MI_CLEARWINDOW (mi);
1784 /* repopulate (mi); */
1789 /* Callback to change level. */
1791 change_pacman (ModeInfo * mi)
1793 MI_CLEARWINDOW (mi);
1796 #endif /* !STANDALONE */
1799 XSCREENSAVER_MODULE ("Pacman", pacman)
1801 #endif /* MODE_pacman */