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 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"
113 } dirvecs[DIRVECS] = { { -1, 0},
118 #ifdef DISABLE_INTERACTIVE
119 ENTRYPOINT ModeSpecOpt pacman_opts = {
121 (XrmOptionDescRec *) NULL,
124 (OptionStruct *) NULL
127 static XrmOptionDescRec opts[] = {
128 {"-trackmouse", ".pacman.trackmouse", XrmoptionNoArg, "on"},
129 {"+trackmouse", ".pacman.trackmouse", XrmoptionNoArg, "off"}
132 static argtype vars[] = {
133 {&pacman_trackmouse, "trackmouse", "TrackMouse", DEF_TRACKMOUSE, t_Bool}
136 static OptionStruct desc[] = {
137 {"-/+trackmouse", "turn on/off the tracking of the mouse"}
140 ENTRYPOINT ModeSpecOpt pacman_opts =
141 { sizeof opts / sizeof opts[0], opts, sizeof vars / sizeof vars[0], vars,
146 ModStruct pacman_description = {
147 "pacman", /* *cmdline_arg; */
148 "init_pacman", /* *init_name; */
149 "draw_pacman", /* *callback_name; */
150 "release_pacman", /* *release_name; */
151 "refresh_pacman", /* *refresh_name; */
152 "change_pacman", /* *change_name; */
153 (char *) NULL, /* *unused_name; */
154 &pacman_opts, /* *msopts */
155 10000, 4, 1, 0, 64, 1.0, "", "Shows Pacman(tm)", 0, NULL
160 Bool pacman_trackmouse;
161 pacmangamestruct *pacman_games = (pacmangamestruct *) NULL;
163 static void repopulate (ModeInfo * mi);
164 static void drawlevel (ModeInfo * mi);
168 free_pacman (Display * display, pacmangamestruct * pp)
170 int dir, mouth, i, j, k;
172 if (pp->ghosts != NULL) {
174 pp->ghosts = (ghoststruct *) NULL;
176 if (pp->stippledGC != None) {
177 XFreeGC (display, pp->stippledGC);
178 pp->stippledGC = None;
180 for (i = 0; i < 4; i++) {
181 for (j = 0; j < MAXGDIR; j++) {
182 for (k = 0; k < MAXGWAG; k++) {
183 if (pp->ghostPixmap[i][j][k] != None) {
184 XFreePixmap (display, pp->ghostPixmap[i][j][k]);
185 pp->ghostPixmap[i][j][k] = None;
190 for (dir = 0; dir < 4; dir++)
191 for (mouth = 0; mouth < MAXMOUTH; mouth++)
192 if (pp->pacmanPixmap[dir][mouth] != None) {
193 XFreePixmap (display, pp->pacmanPixmap[dir][mouth]);
194 pp->pacmanPixmap[dir][mouth] = None;
198 /* set pacman and the ghost in there starting positions, but don't draw a new
201 reset_level (ModeInfo * mi, int n, int pac_init)
203 pacmangamestruct *pp = &pacman_games[MI_SCREEN (mi)];
209 pp->gamestate = GHOST_DANGER;
212 pp->pacman.row = (LEVHEIGHT + JAILHEIGHT) / 2 - n;
213 pp->pacman.init_row = pp->pacman.row;
216 pp->pacman.row = pp->pacman.init_row;
218 pp->pacman.col = (LEVWIDTH / 2);
219 pp->pacman.nextrow = NOWHERE;
220 pp->pacman.nextcol = NOWHERE;
221 pp->pacman.cf = NOWHERE;
222 pp->pacman.rf = NOWHERE;
223 pp->pacman.oldcf = NOWHERE;
224 pp->pacman.oldrf = NOWHERE;
225 pp->pacman.oldlx = NOWHERE;
226 pp->pacman.oldly = NOWHERE;
227 pp->pacman.aistate = ps_eating;
228 pp->pacman.cur_trace = 0;
229 pp->pacman.roundscore = 0;
230 pp->pacman.speed = 4;
231 pp->pacman.lastturn = 0;
232 pp->pacman.delta.x = 0;
233 pp->pacman.delta.y = 0;
235 for (ghost = 0; ghost < pp->nghosts; ghost++) {
236 pp->ghosts[ghost].col = (LEVWIDTH / 2);
237 pp->ghosts[ghost].row = (LEVHEIGHT / 2);
238 pp->ghosts[ghost].nextcol = NOWHERE;
239 pp->ghosts[ghost].nextrow = NOWHERE;
240 pp->ghosts[ghost].dead = 0;
241 pp->ghosts[ghost].lastbox = START;
242 pp->ghosts[ghost].cf = NOWHERE;
243 pp->ghosts[ghost].rf = NOWHERE;
244 pp->ghosts[ghost].oldcf = NOWHERE;
245 pp->ghosts[ghost].oldrf = NOWHERE;
246 pp->ghosts[ghost].aistate = inbox;
247 pp->ghosts[ghost].timeleft = ghost * 20;
248 pp->ghosts[ghost].speed = 3;
249 pp->ghosts[ghost].delta.x = 0;
250 pp->ghosts[ghost].delta.y = 0;
251 pp->ghosts[ghost].flash_scared = False;
252 pp->ghosts[ghost].wait_pos = False;
253 pacman_ghost_update (pp, &(pp->ghosts[ghost]));
255 pacman_update (mi, pp, &(pp->pacman));
259 pacman_ghost_collision(unsigned int ghost, pacmangamestruct * pp)
261 return (((pp->ghosts[ghost].nextrow == pp->pacman.nextrow) &&
262 (pp->ghosts[ghost].nextcol == pp->pacman.nextcol)) ||
263 ((pp->ghosts[ghost].nextrow == pp->pacman.row) &&
264 (pp->ghosts[ghost].nextcol == pp->pacman.col) &&
265 (pp->ghosts[ghost].row == pp->pacman.nextrow) &&
266 (pp->ghosts[ghost].col == pp->pacman.nextcol)));
270 /* Checks for death of any ghosts/pacman and updates. It also makes a new
271 level if all ghosts are dead or all dots are eaten. */
273 check_death (ModeInfo * mi, pacmangamestruct * pp)
275 Display *display = MI_DISPLAY (mi);
276 Window window = MI_WINDOW (mi);
279 if (pp->pacman.aistate == ps_dieing) return;
281 for (ghost = 0; ghost < pp->nghosts; ghost++) {
283 /* The ghost have to be scared before you can kill them */
284 if ( pacman_ghost_collision ( ghost, pp ) ) {
285 if (pp->ghosts[ghost].aistate == goingin) continue;
287 if (pp->ghosts[ghost].aistate == hiding) {
288 pp->ghosts[ghost].dead = 1;
289 pp->ghosts[ghost].aistate = goingin;
290 pp->ghosts[ghost].wait_pos = True;
291 XSetForeground (display, pp->stippledGC, MI_BLACK_PIXEL (mi));
292 XFillRectangle (display, window,
294 pp->ghosts[ghost].cf,
295 pp->ghosts[ghost].rf,
296 pp->spritexs, pp->spriteys);
301 pp->pacman.aistate = ps_dieing;
309 /* Resets state of ghosts + pacman. Creates a new level, draws that level. */
311 repopulate (ModeInfo * mi)
313 pacmangamestruct *pp = &pacman_games[MI_SCREEN (mi)];
314 pp->pacman.deaths = 0;
315 reset_level (mi, pacman_createnewlevel (pp), True);
316 check_death (mi, pp);
319 /* Sets the color to the color of a wall. */
321 setwallcolor (ModeInfo * mi)
323 Display *display = MI_DISPLAY (mi);
324 pacmangamestruct *pp = &pacman_games[MI_SCREEN (mi)];
326 if (MI_NPIXELS (mi) > 2)
327 XSetForeground (display, pp->stippledGC, MI_PIXEL (mi, BLUE));
329 XSetForeground (display, pp->stippledGC, MI_WHITE_PIXEL (mi));
332 /* Sets the color to the color of a dot. */
334 setdotcolor (ModeInfo * mi)
336 Display *display = MI_DISPLAY (mi);
337 pacmangamestruct *pp = &pacman_games[MI_SCREEN (mi)];
339 XSetForeground (display, pp->stippledGC, MI_WHITE_PIXEL (mi));
343 cleardotcolor (ModeInfo * mi)
345 Display *display = MI_DISPLAY (mi);
346 pacmangamestruct *pp = &pacman_games[MI_SCREEN (mi)];
348 XSetForeground (display, pp->stippledGC, MI_BLACK_PIXEL (mi));
353 draw_position (ModeInfo * mi, int x, int y, int color)
355 Display *display = MI_DISPLAY (mi);
356 Window window = MI_WINDOW (mi);
357 pacmangamestruct *pp = &pacman_games[MI_SCREEN (mi)];
358 XFontStruct *font = NULL;
359 char *f_name = "-*-utopia-*-r-*-*-*-600-*-*-p-*-*-*";
362 font = XLoadQueryFont (display, f_name);
363 assert (font != NULL);
365 s = (char *) malloc (256);
367 sprintf (s, "(%d,%d)", x, y);
368 XSetForeground (display, pp->stippledGC, color);
369 XDrawString (display, window, pp->stippledGC, x, y, s, strlen (s));
376 draw_number (ModeInfo * mi, int x, int y, int num, int color)
378 Display *display = MI_DISPLAY (mi);
379 Window window = MI_WINDOW (mi);
380 pacmangamestruct *pp = &pacman_games[MI_SCREEN (mi)];
381 XFontStruct *font = NULL;
382 char *f_name = "-*-utopia-*-r-*-*-*-600-*-*-p-*-*-*";
385 font = XLoadQueryFont (display, f_name);
386 assert (font != NULL);
388 s = (char *) malloc (256);
390 sprintf (s, "%d", num);
391 XSetForeground (display, pp->stippledGC, color);
392 XDrawString (display, window, pp->stippledGC, x, y, s, strlen (s));
399 /* draw_grid - draws a grid on top of the playing field.
400 * Used so that I can determine if I'm converting from rows and columns to x and y
401 * coordinates correctly.
404 draw_grid (ModeInfo * mi)
406 Display *display = MI_DISPLAY (mi);
407 Window window = MI_WINDOW (mi);
408 pacmangamestruct *pp = &pacman_games[MI_SCREEN (mi)];
409 int h = MI_HEIGHT (mi);
410 int w = MI_WIDTH (mi);
413 XSetForeground (display, pp->stippledGC, 0xff0000);
416 XDrawLine (display, window, pp->stippledGC, x, 0, x, h);
420 XDrawLine (display, window, pp->stippledGC, 0, y, w, y);
428 draw_string (ModeInfo * mi, int x, int y, char *s, int color)
430 Display *display = MI_DISPLAY (mi);
431 Window window = MI_WINDOW (mi);
432 pacmangamestruct *pp = &pacman_games[MI_SCREEN (mi)];
433 XFontStruct *font = NULL;
434 char *f_name = "-*-utopia-*-r-*-*-*-600-*-*-p-*-*-*";
436 font = XLoadQueryFont (display, f_name);
437 assert (font != NULL);
440 XSetForeground (display, pp->stippledGC, color);
441 XDrawString (display, window, pp->stippledGC, x, y, s, strlen (s));
445 /* I think this function has a memory leak. Be careful if you enable it. */
446 /* I only used it briefly to help me debug the ghost's aistate. It prints */
447 /* the state of each ghost on the left hand side of the screen */
449 print_ghost_stats (ModeInfo *mi, ghoststruct *g , int ghost_num)
453 sprintf (s, "GHOST: %d", ghost_num );
456 sprintf (s, "%s inbox", s);
459 sprintf (s, "%s goingout", s);
462 sprintf (s, "%s randdir", s);
465 sprintf (s, "%s chasing", s);
468 sprintf (s, "%s hiding", s);
471 sprintf (s, "%s goingin",s);
474 draw_string (mi, 0, (ghost_num *3) *10+50, g->last_stat, 0x000000);
475 draw_string (mi, 0, (ghost_num *3) *10+50, s, 0xff0000);
476 strcpy(g->last_stat,s);
479 /* prints the number of times pacman has died and his aistate on the left hand */
480 /* side of the screen */
482 print_pac_stats ( ModeInfo *mi, pacmanstruct *pac )
484 pacmangamestruct *pp = &pacman_games[MI_SCREEN (mi)];
486 sprintf (s, "Pacman, Deaths: %d", pac->deaths );
487 switch ( pac->aistate ){
489 sprintf(s, "%s ps_eating",s );
492 sprintf(s, "%s ps_chasing",s );
495 sprintf(s, "%s ps_hiding",s );
498 sprintf(s, "%s ps_random",s );
501 sprintf(s, "%s ps_dieing",s );
504 draw_string ( mi, 0, 200, pp->last_pac_stat, 0x000000);
505 draw_string ( mi, 0, 200, s, 0xff0000);
506 strcpy(pp->last_pac_stat, s );
511 /*Ok, yeah whatever?*/
512 /*dot_rc_to_pixel - magic that converts row and columns into
513 *the x and y coordinates of the screen.
516 dot_rc_to_pixel (ModeInfo * mi, int *x, int *y)
518 pacmangamestruct *pp = &pacman_games[MI_SCREEN (mi)];
520 (pp->xs / 2) - (pp->xs > 32 ? (pp->xs / 16) : 1) + pp->xb;
522 (pp->ys / 2) - (pp->ys > 32 ? (pp->ys / 16) : 1) + pp->yb;
525 /* dot_width_height - magic used to get the width and height of
526 * a dot. This dot can also be scaled by a value.
529 dot_width_height (ModeInfo *mi, int *w, int *h)
531 pacmangamestruct *pp = &pacman_games[MI_SCREEN (mi)];
533 *w = *h = (pp->xs / 32 );
540 bonus_dot_width_height (ModeInfo *mi, int *w, int *h )
542 *w = *h = MI_HEIGHT (mi) / 65;
548 draw_dot (ModeInfo * mi, pacmangamestruct * pp, int x, int y,
549 void (*width_height)(ModeInfo * mi, int *w, int *h),
550 int (*arc_func) (Display * display, Drawable d, GC gc,
551 int x, int y, unsigned int width,
552 unsigned int height, int angle1,
555 Display *display = MI_DISPLAY (mi);
556 Window window = MI_WINDOW (mi);
558 dot_rc_to_pixel (mi, &x, &y);
559 width_height(mi, &w, &h);
560 (void) arc_func (display, window, pp->stippledGC,
561 x, y, w, h, 0, 23040);
565 draw_bonus_dot (ModeInfo * mi, pacmangamestruct * pp, int x, int y)
570 draw_dot (mi, pp, x, y, bonus_dot_width_height, XFillArc);
571 dot_rc_to_pixel (mi, &x2, &y2);
573 draw_position (mi, x2, y2, 0xff0000);
578 clear_bonus_dot (ModeInfo * mi, pacmangamestruct * pp, int x, int y)
581 draw_dot (mi, pp, x, y, bonus_dot_width_height, XFillArc);
585 draw_regular_dot (ModeInfo * mi, pacmangamestruct * pp, int x, int y)
588 draw_dot (mi, pp, x, y, dot_width_height, XDrawArc);
591 /* Draws a block in the level at the specified x and y locations. */
593 drawlevelblock (ModeInfo * mi, pacmangamestruct * pp,
594 const unsigned x, const unsigned y)
596 Display *display = MI_DISPLAY (mi);
597 Window window = MI_WINDOW (mi);
606 XSetFillStyle (display, pp->stippledGC, FillSolid);
607 #endif /* !HAVE_COCOA */
608 XSetLineAttributes (display, pp->stippledGC, pp->wallwidth,
609 LineSolid, CapRound, JoinMiter);
611 if (pp->xs < 2 || pp->ys < 2) {
612 switch (pp->level[y * LEVWIDTH + x]) {
618 (void) XDrawPoint (display, window,
620 x * pp->xs + pp->xb, y * pp->ys + pp->yb);
624 (void) XDrawPoint (display, window,
626 x * pp->xs + pp->xb, y * pp->ys + pp->yb);
632 switch (pp->level[y * LEVWIDTH + x]) {
639 if (pp->xs < 8 || pp->ys < 8) {
640 (void) XDrawPoint (display, window,
642 x * pp->xs + pp->xb +
643 pp->xs / 2, y * pp->ys + pp->yb + pp->ys / 2);
647 draw_regular_dot (mi, pp, x, y);
649 /* What we will probably want to do here is have the pp->level store a 'o' for
650 * the bonus dots. The we can use the drawing routine above just with a bigger
654 draw_bonus_dot (mi, pp, x, y);
660 (void) XDrawLine (display, window, pp->stippledGC,
661 (pp->xs * x) + pp->xb,
662 (pp->ys * y) + (pp->ys / 2) + pp->yb,
663 (pp->xs * (x + 1)) + pp->xb,
664 (pp->ys * y) + (pp->ys / 2) + pp->yb);
669 (void) XDrawLine (display, window, pp->stippledGC,
670 (pp->xs * x) + (pp->xs / 2) + pp->xb,
671 (pp->ys * y) + pp->yb,
672 (pp->xs * x) + (pp->xs / 2) + pp->xb,
673 (pp->ys * (y + 1)) + pp->yb);
678 (void) XDrawArc (display, window, pp->stippledGC,
679 (pp->xs * x) - (pp->ys / 2) + pp->xb + dx,
680 (pp->ys * y) + (pp->ys / 2) + pp->yb,
681 pp->xs, pp->ys, 0 * 64, 90 * 64);
686 (void) XDrawArc (display, window, pp->stippledGC,
687 (pp->xs * x) + (pp->ys / 2) + pp->xb,
688 (pp->ys * y) + (pp->ys / 2) + pp->yb,
689 pp->xs, pp->ys, 90 * 64, 90 * 64);
694 (void) XDrawArc (display, window, pp->stippledGC,
695 (pp->xs * x) + (pp->ys / 2) + pp->xb,
696 (pp->ys * y) - (pp->ys / 2) + pp->yb + dy,
697 pp->xs, pp->ys, 180 * 64, 90 * 64);
702 (void) XDrawArc (display, window, pp->stippledGC,
703 (pp->xs * x) - (pp->ys / 2) + pp->xb + dx,
704 (pp->ys * y) - (pp->ys / 2) + pp->yb + dy,
705 pp->xs, pp->ys, 270 * 64, 90 * 64);
711 /* Draws a complete level. */
713 drawlevel (ModeInfo * mi)
715 pacmangamestruct *pp = &pacman_games[MI_SCREEN (mi)];
718 for (y = 0; y < LEVHEIGHT; y++)
719 for (x = 0; x < LEVWIDTH; x++)
720 drawlevelblock (mi, pp, x, y);
723 /* There is some overlap so it can be made more efficient */
724 #define ERASE_IMAGE(d,w,g,x,y,xl,yl,xs,ys) \
726 (y<(yl+ys))?XFillRectangle(d,w,g,xl,yl,xs,y-(yl)): \
727 XFillRectangle(d,w,g,xl,yl,xs,ys); \
729 (y>(yl-(ys)))?XFillRectangle(d,w,g,xl,y+ys,xs,yl-(y)): \
730 XFillRectangle(d,w,g,xl,yl,xs,ys); \
732 (x<(xl+xs))?XFillRectangle(d,w,g,xl,yl,x-(xl),ys): \
733 XFillRectangle(d,w,g,xl,yl,xs,ys); \
735 (x>(xl-(xs)))?XFillRectangle(d,w,g,x+xs,yl,xl-(x),ys): \
736 XFillRectangle(d,w,g,xl,yl,xs,ys)
739 /* Draws the pacman sprite, removing the previous location. */
740 #if defined(USE_PIXMAP)
743 draw_pacman_sprite (ModeInfo * mi)
745 Display *display = MI_DISPLAY (mi);
746 Window window = MI_WINDOW (mi);
747 pacmangamestruct *pp = &pacman_games[MI_SCREEN (mi)];
748 unsigned int dir = 0;
749 int old_mask_dir = 0;
750 int old_mask_mouth = 0;
751 Pixmap old_mask, new_mask;
754 #define MAX_MOUTH_DELAY 2
755 #define MAX_DEATH_DELAY 20
757 if (pp->pacman.aistate == ps_dieing){
758 pp->pacman.cf = pp->pacman.oldcf;
759 pp->pacman.rf = pp->pacman.oldrf;
762 pp->pacman.cf = pp->pacman.col * pp->xs + pp->pacman.delta.x *
763 pp->pacman.cfactor + pp->xb + pp->spritedx;
764 pp->pacman.rf = pp->pacman.row * pp->ys + pp->pacman.delta.y *
765 pp->pacman.rfactor + pp->yb + pp->spritedy;
768 dir = (ABS (pp->pacman.cfactor) * (2 - pp->pacman.cfactor) +
769 ABS (pp->pacman.rfactor) * (1 + pp->pacman.rfactor)) % 4;
771 if (pp->pm_mouth_delay == MAX_MOUTH_DELAY) {
772 if (pp->pm_mouth == (MAXMOUTH - 1) || pp->pm_mouth == 0) {
773 pp->pm_open_mouth = !pp->pm_open_mouth;
775 pp->pm_open_mouth ? pp->pm_mouth++ : pp->pm_mouth--;
776 pp->pm_mouth_delay = 0;
779 pp->pm_mouth_delay++;
782 if (pp->pacman.aistate == ps_dieing){
783 if (pp->pm_death_frame >= PAC_DEATH_FRAMES) {
784 pp->pacman.aistate = ps_eating;
785 pp->pm_death_frame = 0;
786 pp->pm_death_delay = 0;
787 reset_level (mi, 0, False);
791 old_mask = pp->pacmanMask[0][0];
792 new_mask = pp->pacmanMask[0][0];
793 pacman = pp->pacman_ds[pp->pm_death_frame];
794 if (pp->pm_death_delay == MAX_DEATH_DELAY){
795 pp->pm_death_frame++;
796 pp->pm_death_delay = 0;
799 pp->pm_death_delay++;
804 old_mask = pp->pacmanMask[old_mask_dir][old_mask_mouth];
805 new_mask = pp->pacmanMask[dir][pp->pm_mouth];
806 pacman = pp->pacmanPixmap[dir][pp->pm_mouth];
809 XSetForeground (display, pp->stippledGC, MI_BLACK_PIXEL (mi));
811 XSetClipMask (display, pp->stippledGC, old_mask);
813 XSetClipOrigin (display, pp->stippledGC, pp->pacman.oldcf,
815 XFillRectangle (display, window, pp->stippledGC, pp->pacman.oldcf,
816 pp->pacman.oldrf, pp->spritexs, pp->spriteys);
817 XSetClipMask (display, pp->stippledGC, new_mask);
818 XSetClipOrigin (display, pp->stippledGC, pp->pacman.cf, pp->pacman.rf);
819 XCopyArea (display, pacman, window,
820 pp->stippledGC, 0, 0, pp->spritexs, pp->spriteys,
821 pp->pacman.cf, pp->pacman.rf);
822 XSetClipMask (display, pp->stippledGC, None);
823 if (pp->pacman.aistate != ps_dieing){
824 pp->pacman.oldcf = pp->pacman.cf;
825 pp->pacman.oldrf = pp->pacman.rf;
831 draw_ghost_position (ModeInfo * mi, ghoststruct * ghost)
833 draw_position (mi, ghost->oldcf, ghost->oldrf, MI_BLACK_PIXEL (mi));
834 draw_position (mi, ghost->cf, ghost->rf, 0x00ff00);
839 draw_ghost_ndirs ( ModeInfo *mi, ghoststruct * ghost)
841 draw_number (mi, ghost->oldcf, ghost->oldrf, ghost->oldndirs, MI_BLACK_PIXEL (mi));
842 ghost->oldndirs = ghost->ndirs;
843 draw_number (mi, ghost->cf, ghost->rf, ghost->ndirs, 0x00ff00);
849 draw_ghost_sprite (ModeInfo * mi, const unsigned ghost)
851 Display *display = MI_DISPLAY (mi);
852 Window window = MI_WINDOW (mi);
853 pacmangamestruct *pp = &pacman_games[MI_SCREEN (mi)];
854 #define MAX_WAG_COUNT 50
855 unsigned int dir = 0;
856 unsigned int fs = 0; /*flash scared*/
857 Pixmap g_pix; /*ghost pixmap*/
860 dir = (ABS (pp->ghosts[ghost].cfactor) * (2 - pp->ghosts[ghost].cfactor) +
861 ABS (pp->ghosts[ghost].rfactor) * (1 + pp->ghosts[ghost].rfactor)) % 4;
864 fs = pp->ghosts[ghost].flash_scared;
865 assert (fs == 0 || fs == 1);
867 /* Choose the pixmap */
868 switch (pp->ghosts[ghost].aistate){
870 g_pix = pp->s_ghostPixmap[fs][pp->gh_wag];
873 g_pix = pp->ghostEyes[dir];
877 while ( i < pp->ghosts[ghost].trace_idx ){
878 XFillRectangle (display,
881 pp->ghosts[ghost].trace[i].vx,
882 pp->ghosts[ghost].trace[i].vy,
883 pp->spritexs, pp->spriteys);
892 g_pix = pp->ghostPixmap[ghost][dir][pp->gh_wag];
895 pp->ghosts[ghost].cf =
896 pp->ghosts[ghost].col * pp->xs + pp->ghosts[ghost].delta.x *
897 pp->ghosts[ghost].cfactor + pp->xb + pp->spritedx;
898 pp->ghosts[ghost].rf =
899 pp->ghosts[ghost].row * pp->ys + pp->ghosts[ghost].delta.y *
900 pp->ghosts[ghost].rfactor + pp->yb + pp->spritedy;
902 XSetForeground (display, pp->stippledGC, MI_BLACK_PIXEL (mi));
904 XSetClipMask (display, pp->stippledGC, pp->ghostMask);
905 XSetClipOrigin (display, pp->stippledGC,
906 pp->ghosts[ghost].oldcf, pp->ghosts[ghost].oldrf);
907 XFillRectangle (display,
910 pp->ghosts[ghost].oldcf,
911 pp->ghosts[ghost].oldrf, pp->spritexs, pp->spriteys);
914 if (pp->pacman.aistate != ps_dieing) {
915 drawlevelblock (mi, pp,
916 (unsigned int) pp->ghosts[ghost].col,
917 (unsigned int) pp->ghosts[ghost].row);
921 XSetClipOrigin (display, pp->stippledGC,
922 pp->ghosts[ghost].cf, pp->ghosts[ghost].rf);
924 XCopyArea (display, g_pix, window, pp->stippledGC, 0, 0,
925 pp->spritexs, pp->spriteys, pp->ghosts[ghost].cf,
926 pp->ghosts[ghost].rf);
928 XSetClipMask (display, pp->stippledGC, None);
931 draw_ghost_position (mi, &(pp->ghosts[ghost]));
935 draw_ghost_ndirs ( mi, &(pp->ghosts[ghost]));
938 if (pp->pacman.aistate != ps_dieing) {
939 pp->ghosts[ghost].oldcf = pp->ghosts[ghost].cf;
940 pp->ghosts[ghost].oldrf = pp->ghosts[ghost].rf;
941 if (pp->gh_wag_count++ == MAX_WAG_COUNT) {
942 pp->gh_wag = !pp->gh_wag;
943 pp->gh_wag_count = 0;
948 #else /* USE_PIXMAP */
950 /* Draws the pacman sprite, removing the previous location. */
952 draw_pacman_sprite (ModeInfo * mi)
954 Display *display = MI_DISPLAY (mi);
955 Window window = MI_WINDOW (mi);
956 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 dir = (ABS (pp->pacman.cfactor) * (2 - pp->pacman.cfactor) +
965 ABS (pp->pacman.rfactor) * (1 + pp->pacman.rfactor)) % 4;
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, swidth, 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 int size = MI_SIZE (mi);
1483 pacmangamestruct *pp;
1487 #if (! defined( USE_PIXMAP ))
1493 if (pacman_games == NULL) {
1494 if ((pacman_games = (pacmangamestruct *)
1495 calloc ((size_t) MI_NUM_SCREENS (mi),
1496 sizeof (pacmangamestruct))) == NULL)
1499 pp = &pacman_games[MI_SCREEN (mi)];
1501 pp->width = (unsigned short) MI_WIDTH (mi);
1502 pp->height = (unsigned short) MI_HEIGHT (mi);
1503 for (i = 0; i < 4; i++) {
1504 for (j = 0; j < MAXGDIR; j++) {
1505 for (k = 0; k < MAXGWAG; k++) {
1506 if (pp->ghostPixmap[i][j][k] != None) {
1507 XFreePixmap (display, pp->ghostPixmap[i][j][k]);
1508 pp->ghostPixmap[i][j][k] = None;
1509 pp->graphics_format = 0 /*IS_NONE */ ;
1515 for (i = 0; i < MAXGFLASH; i++) {
1516 for (j = 0; j < MAXGWAG; j++) {
1517 if (pp->s_ghostPixmap[i][j] != None) {
1518 XFreePixmap (display, pp->s_ghostPixmap[i][j]);
1519 pp->s_ghostPixmap[i][j] = None;
1525 MINGRIDSIZE * size > (int) pp->width ||
1526 MINGRIDSIZE * size > (int) pp->height) {
1528 pp->ys = pp->xs = MAX (MIN (pp->width / LEVWIDTH,
1529 pp->height / LEVHEIGHT), 1);
1532 if (size < -MINSIZE)
1533 pp->ys = (short) (NRAND (MIN (-size, MAX (MINSIZE,
1537 - MINSIZE + 1) + MINSIZE);
1538 else if (size < MINSIZE)
1541 pp->ys = (short) (MIN (size,
1542 MAX (MINSIZE, MIN (pp->width, pp->height) /
1547 pp->wallwidth = (unsigned int) (pp->xs + pp->ys) >> 4;
1548 if (pp->wallwidth < 1)
1550 pp->incx = (pp->xs >> 3) + 1;
1551 pp->incy = (pp->ys >> 3) + 1;
1552 pp->ncols = (unsigned short) MAX (LEVWIDTH, 2);
1553 pp->nrows = (unsigned short) MAX (LEVHEIGHT, 2);
1554 pp->xb = (pp->width - pp->ncols * pp->xs) >> 1;
1555 pp->yb = (pp->height - pp->nrows * pp->ys) >> 1;
1556 pp->spritexs = MAX (pp->xs + (pp->xs >> 1) - 1, 1);
1557 pp->spriteys = MAX (pp->ys + (pp->ys >> 1) - 1, 1);
1558 pp->spritedx = (pp->xs - pp->spritexs) >> 1;
1559 pp->spritedy = (pp->ys - pp->spriteys) >> 1;
1560 pp->old_pac_state = ps_chasing;
1562 if (!pp->stippledGC) {
1563 gcv.foreground = MI_BLACK_PIXEL (mi);
1564 gcv.background = MI_BLACK_PIXEL (mi);
1565 if ((pp->stippledGC = XCreateGC (display, window,
1566 GCForeground | GCBackground,
1568 free_pacman (display, pp);
1574 jwxyz_XSetAntiAliasing (display, pp->stippledGC, False);
1577 #if defined(USE_PIXMAP)
1578 load_ghost_pixmaps (&display, window, &pp);
1579 load_pacman_pixmaps (&display, window, &pp);
1581 if ((pp->ghostPixmap[0][0][0] = XCreatePixmap (display, window,
1582 pp->spritexs, pp->spriteys,
1584 free_pacman (display, pp);
1590 if ((bg_gc = XCreateGC (display, pp->ghostPixmap[0][0][0],
1591 GCForeground | GCBackground, &gcv)) == None) {
1592 free_pacman (display, pp);
1598 if ((fg_gc = XCreateGC (display, pp->ghostPixmap[0][0][0],
1599 GCForeground | GCBackground, &gcv)) == None) {
1600 XFreeGC (display, bg_gc);
1601 free_pacman (display, pp);
1605 #define SETPOINT(p, xp, yp) p.x = xp; p.y = yp
1607 /* draw the triangles on the bottom (scalable) */
1608 SETPOINT (points[0], 1, pp->spriteys * 5 / 6);
1609 SETPOINT (points[1], pp->spritexs / 6, pp->spriteys);
1610 SETPOINT (points[2], pp->spritexs / 3, pp->spriteys * 5 / 6);
1611 SETPOINT (points[3], pp->spritexs / 2, pp->spriteys);
1612 SETPOINT (points[4], pp->spritexs * 2 / 3, pp->spriteys * 5 / 6);
1613 SETPOINT (points[5], pp->spritexs * 5 / 6, pp->spriteys);
1614 SETPOINT (points[6], pp->spritexs, pp->spriteys * 5 / 6);
1615 SETPOINT (points[7], pp->spritexs, pp->spriteys / 2);
1616 SETPOINT (points[8], 1, pp->spriteys / 2);
1618 XFillRectangle (display, pp->ghostPixmap[0][0][0], bg_gc,
1619 0, 0, pp->spritexs, pp->spriteys);
1620 XFillArc (display, pp->ghostPixmap[0][0][0], fg_gc,
1621 0, 0, pp->spritexs, pp->spriteys, 0, 11520);
1622 XFillPolygon (display, pp->ghostPixmap[0][0][0], fg_gc,
1623 points, 9, Nonconvex, CoordModeOrigin);
1624 XFreeGC (display, bg_gc);
1625 XFreeGC (display, fg_gc);
1628 if (pp->pacmanPixmap[0][0] != None)
1629 for (dir = 0; dir < 4; dir++)
1630 for (mouth = 0; mouth < MAXMOUTH; mouth++)
1631 XFreePixmap (display, pp->pacmanPixmap[dir]
1634 for (dir = 0; dir < 4; dir++)
1635 for (mouth = 0; mouth < MAXMOUTH; mouth++) {
1636 if ((pp->pacmanPixmap[dir][mouth] =
1637 XCreatePixmap (display, MI_WINDOW (mi), pp->spritexs,
1638 pp->spriteys, 1)) == None) {
1639 free_pacman (display, pp);
1644 if ((fg_gc = XCreateGC (display, pp->pacmanPixmap[dir][mouth],
1645 GCForeground | GCBackground,
1647 free_pacman (display, pp);
1652 if ((bg_gc = XCreateGC (display,
1653 pp->pacmanPixmap[dir][mouth],
1655 GCBackground, &gcv)) == None) {
1656 XFreeGC (display, fg_gc);
1657 free_pacman (display, pp);
1660 XFillRectangle (display,
1661 pp->pacmanPixmap[dir][mouth], bg_gc,
1662 0, 0, pp->spritexs, pp->spriteys);
1663 if (pp->spritexs == 1 && pp->spriteys == 1)
1664 XFillRectangle (display,
1665 pp->pacmanPixmap[dir][mouth],
1666 fg_gc, 0, 0, pp->spritexs, pp->spriteys);
1669 pp->pacmanPixmap[dir][mouth],
1671 0, 0, pp->spritexs, pp->spriteys,
1672 ((90 - dir * 90) + mouth * 5) * 64,
1673 (360 + (-2 * mouth * 5)) * 64);
1674 XFreeGC (display, fg_gc);
1675 XFreeGC (display, bg_gc);
1677 #endif /* USE_PIXMAP */
1679 pp->pacman.lastbox = START;
1680 pp->pacman.mouthdirection = 1;
1681 pp->pacman.nextcol = NOWHERE;
1682 pp->pacman.nextrow = NOWHERE;
1684 if (pp->ghosts != NULL) {
1686 pp->ghosts = (ghoststruct *) NULL;
1688 pp->nghosts = GHOSTS;
1691 if ((pp->ghosts = (ghoststruct *) calloc ((size_t) pp->nghosts,
1692 sizeof (ghoststruct))) ==
1694 free_pacman (display, pp);
1698 pp->pacman.mouthstage = MAXMOUTH - 1;
1700 MI_CLEARWINDOW (mi);
1704 /* Callback function called for each tick. This is the complete machinery of
1705 everything that moves. */
1707 draw_pacman (ModeInfo * mi)
1710 pacmangamestruct *pp;
1712 if (pacman_games == NULL)
1714 pp = &pacman_games[MI_SCREEN (mi)];
1715 if (pp->ghosts == NULL)
1718 pp->pacman.err.x = (pp->pacman.err.x + 1) % pp->pacman.speed;
1719 pp->pacman.err.y = (pp->pacman.err.y + 1) % pp->pacman.speed;
1720 pp->pacman.delta.x += pp->pacman.err.x != 0 ? pp->incx : 0;
1721 pp->pacman.delta.y += pp->pacman.err.y != 0 ? pp->incy : 0;
1723 if (pp->pacman.delta.x >= pp->xs && pp->pacman.delta.y >= pp->ys) {
1724 pacman_update (mi, pp, &(pp->pacman));
1725 check_death (mi, pp);
1726 pp->pacman.delta.x = pp->incx;
1727 pp->pacman.delta.y = pp->incy;
1730 if (pp->pacman.delta.x > pp->xs + pp->incx)
1731 pp->pacman.delta.x = pp->xs + pp->incx;
1732 if (pp->pacman.delta.y > pp->ys + pp->incy)
1733 pp->pacman.delta.y = pp->ys + pp->incy;
1735 for (g = 0; g < pp->nghosts; g++) {
1736 pp->ghosts[g].err.x = (pp->ghosts[g].err.x + 1) % pp->ghosts[g].speed;
1737 pp->ghosts[g].err.y = (pp->ghosts[g].err.y + 1) % pp->ghosts[g].speed;
1738 pp->ghosts[g].delta.x += pp->ghosts[g].err.x != 0 ? pp->incx : 0;
1739 pp->ghosts[g].delta.y += pp->ghosts[g].err.y != 0 ? pp->incy : 0;
1741 if (pp->ghosts[g].delta.x >= pp->xs &&
1742 pp->ghosts[g].delta.y >= pp->ys) {
1743 pacman_ghost_update (pp, &(pp->ghosts[g]));
1744 pp->ghosts[g].delta.x = pp->incx;
1745 pp->ghosts[g].delta.y = pp->incy;
1748 if (pp->ghosts[g].delta.x > pp->xs + pp->incx)
1749 pp->ghosts[g].delta.x = pp->xs + pp->incx;
1750 if (pp->ghosts[g].delta.y > pp->ys + pp->incy)
1751 pp->ghosts[g].delta.y = pp->ys + pp->incy;
1756 /* Releases resources. */
1758 release_pacman (ModeInfo * mi)
1760 if (pacman_games != NULL) {
1763 for (screen = 0; screen < MI_NUM_SCREENS (mi); screen++)
1764 free_pacman (MI_DISPLAY (mi), &pacman_games[screen]);
1765 free (pacman_games);
1766 pacman_games = (pacmangamestruct *) NULL;
1770 /* Refresh current level. */
1772 refresh_pacman (ModeInfo * mi)
1779 reshape_pacman(ModeInfo * mi, int width, int height)
1781 pacmangamestruct *pp = &pacman_games[MI_SCREEN (mi)];
1783 pp->height = height;
1784 pp->xb = (pp->width - pp->ncols * pp->xs) >> 1;
1785 pp->yb = (pp->height - pp->nrows * pp->ys) >> 1;
1786 MI_CLEARWINDOW (mi);
1787 /* repopulate (mi); */
1792 /* Callback to change level. */
1794 change_pacman (ModeInfo * mi)
1796 MI_CLEARWINDOW (mi);
1799 #endif /* !STANDALONE */
1802 XSCREENSAVER_MODULE ("Pacman", pacman)
1804 #endif /* MODE_pacman */