* other special, indirect and consequential damages.
*
* Revision History:
+ * 11-Aug-2004: Added support for pixmap ghost. jenglish@myself.com
* 13-May-2002: Added -trackmouse feature thanks to code from 'maze.c'.
* splitted up code into several files. Retouched AI code, cleaned
* up code.
/* TODO:
1. add "bonus" dots
- 2. make better ghost sprites (eyes, waving dress)
- 3. make a bit better pacman sprite (mouth should be larger)
- 4. think of a better level generation algorithm
+ 2. make a bit better pacman sprite (mouth should be larger)
+ 3. think of a better level generation algorithm
*/
+#define DEF_TRACKMOUSE "False"
+
#ifdef STANDALONE
# define MODE_pacman
# define PROGCLASS "Pacman"
# define DEFAULTS "*delay: 10000 \n" \
"*size: 0 \n" \
"*ncolors: 6 \n" \
- "*trackmouse: False \n"
+ "*trackmouse: " DEF_TRACKMOUSE "\n"
# define UNIFORM_COLORS
# define BRIGHT_COLORS
+
# include "xlockmore.h" /* in xscreensaver distribution */
#else /* STANDALONE */
# include "xlock.h" /* in xlockmore distribution */
#include "pacman_ai.h"
#include "pacman_level.h"
+#if defined(HAVE_GDK_PIXBUF) || defined(HAVE_XPM)
+#define USE_PIXMAP
+#include "xpm-pixmap.h"
+#else
+#if defined(USE_PIXMAP)
+#undef USE_PIXMAP
+#endif
+#endif
+
+#if defined(USE_PIXMAP)
+# include "images/pacman/ghost-u1.xpm"
+# include "images/pacman/ghost-u2.xpm"
+# include "images/pacman/ghost-r1.xpm"
+# include "images/pacman/ghost-r2.xpm"
+# include "images/pacman/ghost-l1.xpm"
+# include "images/pacman/ghost-l2.xpm"
+# include "images/pacman/ghost-d1.xpm"
+# include "images/pacman/ghost-d2.xpm"
+# include "images/pacman/ghost-mask.xpm" /* Used to clean up the dust left by wag. */
+#endif
+
+static const struct { int dx, dy; } dirvecs[DIRVECS] =
+ { {-1, 0}, {0, 1}, {1, 0}, {0, -1}};
+
#ifdef DISABLE_INTERACTIVE
ModeSpecOpt pacman_opts = {
0,
#else
static XrmOptionDescRec opts[] =
{
- {(char *) "-trackmouse", (char *) ".pacman.trackmouse", XrmoptionNoArg,
- (caddr_t) "on"},
- {(char *) "+trackmouse", (char *) ".pacman.trackmouse", XrmoptionNoArg,
- (caddr_t) "off"}
+ {"-trackmouse", ".pacman.trackmouse", XrmoptionNoArg, "on"},
+ {"+trackmouse", ".pacman.trackmouse", XrmoptionNoArg, "off"}
};
static argtype vars[] =
{
- {(caddr_t *) & trackmouse, (char *) "trackmouse", (char *) "TrackMouse",
- (char *) DEF_TRACKMOUSE, t_Bool}
+ {&trackmouse, "trackmouse", "TrackMouse", DEF_TRACKMOUSE, t_Bool}
};
static OptionStruct desc[] =
{
- {(char *) "-/+trackmouse", (char *) "turn on/off the tracking of the "
- "mouse"}
+ {"-/+trackmouse", "turn on/off the tracking of the mouse"}
};
ModeSpecOpt pacman_opts =
};
#endif
+
+Bool trackmouse;
+pacmangamestruct *pacmangames = (pacmangamestruct *) NULL;
+
+
+static void repopulate(ModeInfo * mi);
+static void drawlevel(ModeInfo * mi);
+
+
static void
free_pacman(Display *display, pacmangamestruct *pp)
{
- int dir, mouth;
+ int dir, mouth, i, j, k;
if (pp->ghosts != NULL) {
free(pp->ghosts);
pp->ghosts = (ghoststruct *) NULL;
}
if (pp->stippledGC != None) {
- XFreeGC(display, pp->stippledGC);
+ XFreeGC(display, pp->stippledGC);
pp->stippledGC = None;
}
- if (pp->ghostPixmap != None) {
- XFreePixmap(display, pp->ghostPixmap);
- pp->ghostPixmap = None;
+ for (i = 0; i < 4; i++){
+ for (j = 0; j < MAXGDIR; j++){
+ for (k = 0; k < MAXGWAG; k++){
+ if (pp->ghostPixmap[i][j][k] != None) {
+ XFreePixmap(display, pp->ghostPixmap[i][j][k]);
+ pp->ghostPixmap[i][j][k] = None;
+ }
+ }
+ }
}
for (dir = 0; dir < 4; dir++)
for (mouth = 0; mouth < MAXMOUTH; mouth++)
}
}
+
/* Checks for death of any ghosts/pacman and updates. It also makes a new
level if all ghosts are dead or all dots are eaten. */
static void
pp->pacman.oldrf = pp->pacman.rf;
}
+#if defined(USE_PIXMAP)
+static void
+draw_ghost_sprite(ModeInfo * mi, const unsigned ghost){
+ Display *display = MI_DISPLAY(mi);
+ Window window = MI_WINDOW(mi);
+ pacmangamestruct *pp = &pacmangames[MI_SCREEN(mi)];
+ static int wag = 0;
+#define MAX_WAG_COUNT 50
+ static int wag_count = 0;
+ unsigned int dir = 0;
+
+ dir = (ABS(pp->ghosts[ghost].cfactor) * (2 - pp->ghosts[ghost].cfactor) +
+ ABS(pp->ghosts[ghost].rfactor) * (1 + pp->ghosts[ghost].rfactor)) % 4;
+
+ pp->ghosts[ghost].cf =
+ pp->ghosts[ghost].col * pp->xs + pp->ghosts[ghost].delta.x *
+ pp->ghosts[ghost].cfactor + pp->xb + pp->spritedx;
+ pp->ghosts[ghost].rf =
+ pp->ghosts[ghost].row * pp->ys + pp->ghosts[ghost].delta.y *
+ pp->ghosts[ghost].rfactor + pp->yb + pp->spritedy;
+ XSetForeground(display,
+ pp->stippledGC,
+ MI_BLACK_PIXEL(mi));
+
+ XSetClipMask(display, pp->stippledGC, pp->ghostMask);
+ XSetClipOrigin(display, pp->stippledGC,
+ pp->ghosts[ghost].oldcf, pp->ghosts[ghost].oldrf);
+ XFillRectangle(display,
+ window,
+ pp->stippledGC,
+ pp->ghosts[ghost].oldcf,
+ pp->ghosts[ghost].oldrf,
+ pp->spritexs, pp->spriteys);
+ XSetClipOrigin(display, pp->stippledGC,
+ pp->ghosts[ghost].cf, pp->ghosts[ghost].rf);
+ XCopyArea(display, pp->ghostPixmap[ghost][dir][wag], window,
+ pp->stippledGC,0,0,pp->spritexs,pp->spriteys,
+ pp->ghosts[ghost].cf, pp->ghosts[ghost].rf);
+ XSetClipMask(display, pp->stippledGC, None);
+ drawlevelblock(mi, pp,
+ (unsigned int)pp->ghosts[ghost].col,
+ (unsigned int)pp->ghosts[ghost].row);
+ pp->ghosts[ghost].oldcf = pp->ghosts[ghost].cf;
+ pp->ghosts[ghost].oldrf = pp->ghosts[ghost].rf;
+ if (wag_count++ == MAX_WAG_COUNT){
+ wag = !wag;
+ wag_count = 0;
+ }
+}
+
+#else
+
/* Draws a ghost sprite, removing the previous sprite and restores the level. */
static void
draw_ghost_sprite(ModeInfo * mi, const unsigned ghost) {
XSetForeground(display,
pp->stippledGC,
MI_BLACK_PIXEL(mi));
+ XFillRectangle(display,
+ window,
+ pp->stippledGC,
+ pp->ghosts[ghost].cf,
+ pp->ghosts[ghost].rf,
+ pp->spritexs, pp->spriteys);
if (pp->ghosts[ghost].oldcf != NOWHERE ||
pp->ghosts[ghost].oldrf != NOWHERE) {
MI_WHITE_PIXEL(mi));
XSetStipple(display, pp->stippledGC,
- pp->ghostPixmap);
+ pp->ghostPixmap[0][0][0]);
#ifdef FLASH
XSetFillStyle(display,
pp->ghosts[ghost].oldcf = pp->ghosts[ghost].cf;
pp->ghosts[ghost].oldrf = pp->ghosts[ghost].rf;
}
+#endif
/* Does all drawing of moving sprites in the level. */
static void
(void)XFlush(display);
}
+#if defined(USE_PIXMAP)
+/* Grabbed the scaling routine off of usenet.
+ * Changed it so that the information specific
+ * to the source pixmap does not have to be a parameter.
+ *
+ * There is probable a better way to scale pixmaps.
+ * From: Chris Fiddyment (cxf@itd.dsto.gov.au)
+ * Subject: Scaling Pixmap Algorithm.
+ * Newsgroups: comp.graphics.algorithms
+ * Date: 1994-07-06 18:51:38 PST
+ * -jeremy
+ */
+
+static Pixmap
+scale_pixmap( Display **dpy, GC gc, Pixmap source, int dwidth, int dheight)
+{
+ Pixmap temp,dest;
+ int j,end;
+ float i;
+ float xscale, yscale;
+ unsigned int swidth, sheight;
+ Window window;
+ int x, y;
+ unsigned border_width_return, depth;
+ XGetGeometry(*dpy, source, &window, &x, &y, &swidth, &sheight, &border_width_return, &depth);
+
+ xscale = (float) swidth / (float) dwidth; /* Scaling factors */
+ yscale = (float) sheight / (float) dheight;
+
+ dest = XCreatePixmap(*dpy,window,dwidth,dheight,depth);
+ if (!dest){
+ fprintf(stderr, "%s Could not scale image", progname);
+ }
+ temp = XCreatePixmap(*dpy,window,dwidth,sheight,depth);
+ if (!temp){
+ fprintf(stderr, "%s Could not scale image", progname);
+ }
+
+ j = 0;
+ end = dwidth*xscale;
+ /* Scale width of source into temp pixmap */
+ for(i=0;i<end;i+=xscale)
+ XCopyArea(*dpy,source,temp,gc,i,0,1,sheight,j++,0);
+
+ j = 0;
+ end = dheight*yscale;
+ /* Scale height of temp into dest pixmap */
+ for(i=0;i<end;i+=yscale)
+ XCopyArea(*dpy,temp,dest,gc,0,i,dwidth,1,0,j++);
+
+ XFreePixmap( *dpy, temp );
+ return (Pixmap) dest;
+}
+
+/* Load any needed pixmaps and their mask. */
+static void
+load_pixmaps(Display **dpy, Window window, pacmangamestruct **ps)
+{
+ pacmangamestruct *pp = *ps;
+ Display *display = *dpy;
+ static char *colors[]= {
+ ". c #FF0000", /*Red*/
+ ". c #00FFDE", /*Blue*/
+ ". c #FFB847", /*Orange*/
+ ". c #FFB8DE", /*Pink*/
+ };
+
+ static char **bits[] = {
+ ghost_u1_xpm, ghost_u2_xpm, ghost_r1_xpm, ghost_r2_xpm,
+ ghost_d1_xpm, ghost_d2_xpm, ghost_l1_xpm, ghost_l2_xpm
+ };
+ int i, j, k, m;
+ int w = pp->spritexs;
+ int h = pp->spriteys;
+ GC gc = 0;
+ Pixmap temp;
+
+ for (i = 0; i < 4; i++){
+ m = 0;
+ for ( j = 0; j < MAXGDIR; j++){
+ for ( k = 0; k < MAXGWAG; k++){
+ bits[m][2] = colors[i];
+ pp->ghostPixmap[i][j][k] = xpm_data_to_pixmap (display, window, bits[m],
+ &w, &h, &pp->ghostMask);
+ if (!pp->ghostPixmap[i][j][k])
+ {
+ fprintf (stderr, "%s: Can't load ghost images\n", progname);
+ exit(1);
+ }
+
+ pp->ghostPixmap[i][j][k] = scale_pixmap(&display, pp->stippledGC,
+ pp->ghostPixmap[i][j][k], pp->spritexs, pp->spriteys);
+ if (!pp->ghostPixmap[i][j][k])
+ {
+ fprintf (stderr, "%s: Can't load ghost images\n", progname);
+ exit(1);
+ }
+
+ m++;
+ }
+ }
+ }
+ /* We really only need a single mask. This saves the headache of getting the bottom of the ghost
+ * to clip just right. What we'll do is mask the top portion of the ghost, but the bottom of the
+ * the ghost will be solid. I did this by setting the pixels between the fringe of their sheets
+ * to black instead of none. -jeremy
+ */
+ temp = xpm_data_to_pixmap (display, window, ghost_mask_xpm,
+ &w, &h, &pp->ghostMask);
+ if (!temp)
+ {
+ fprintf (stderr, "%s: Can't load ghost images\n", progname);
+ exit(1);
+ }
+
+ temp = scale_pixmap(&display, pp->stippledGC,
+ temp, pp->spritexs, pp->spriteys);
+ if (!temp)
+ {
+ fprintf (stderr, "%s: Can't load ghost images\n", progname);
+ exit(1);
+ }
+ gc = XCreateGC(display, pp->ghostMask, 0, 0);
+ pp->ghostMask = scale_pixmap(&display, gc, pp->ghostMask,
+ pp->spritexs, pp->spriteys);
+ XFreePixmap(display, temp);
+}
+#endif
+
/* Hook function, sets state to initial position. */
void
init_pacman(ModeInfo * mi)
int size = MI_SIZE(mi);
pacmangamestruct *pp;
XGCValues gcv;
- int dir, mouth;
+ int dir, mouth, i, j, k;
GC fg_gc, bg_gc;
- XPoint points[9];
+/* XPoint points[9]; */
if (pacmangames == NULL) {
if ((pacmangames = (pacmangamestruct *)
pp = &pacmangames[MI_SCREEN(mi)];
pp->width = (unsigned short)MI_WIDTH(mi);
- pp->height = (unsigned short)MI_HEIGHT(mi);
- if (pp->ghostPixmap != None) {
- XFreePixmap(display, pp->ghostPixmap);
- pp->ghostPixmap = None;
- pp->graphics_format = 0 /*IS_NONE*/;
+ pp->height = (unsigned short)MI_HEIGHT(mi);
+ for (i = 0; i < 4; i++){
+ for (j = 0; j < MAXGDIR; j++){
+ for (k = 0; k < MAXGWAG; k++){
+ if (pp->ghostPixmap[i][j][k] != None) {
+ XFreePixmap(display, pp->ghostPixmap[i][j][k]);
+ pp->ghostPixmap[i][j][k] = None;
+ pp->graphics_format = 0 /*IS_NONE*/;
+ }
+ }
+ }
}
-
if (size == 0 ||
MINGRIDSIZE * size > (int)pp->width ||
MINGRIDSIZE * size > (int)pp->height) {
pp->spritedx = (pp->xs - pp->spritexs) >> 1;
pp->spritedy = (pp->ys - pp->spriteys) >> 1;
- if ((pp->ghostPixmap = XCreatePixmap(display, window,
+ if (!pp->stippledGC) {
+ gcv.foreground = MI_BLACK_PIXEL(mi);
+ gcv.background = MI_BLACK_PIXEL(mi);
+ if ((pp->stippledGC = XCreateGC(display, window,
+ GCForeground | GCBackground, &gcv)) == None) {
+ free_pacman(display, pp);
+ return;
+ }
+ }
+
+#if defined(USE_PIXMAP)
+ load_pixmaps(&display,window,&pp);
+#else
+ if ((pp->ghostPixmap[0][0][0] = XCreatePixmap(display, window,
pp->spritexs, pp->spriteys, 1)) == None) {
free_pacman(display, pp);
return;
gcv.foreground = 0;
gcv.background = 1;
- if ((bg_gc = XCreateGC(display, pp->ghostPixmap,
+ if ((bg_gc = XCreateGC(display, pp->ghostPixmap[0][0][0],
GCForeground | GCBackground, &gcv)) == None) {
free_pacman(display, pp);
return;
gcv.foreground = 1;
gcv.background = 0;
- if ((fg_gc = XCreateGC(display, pp->ghostPixmap,
+ if ((fg_gc = XCreateGC(display, pp->ghostPixmap[0][0][0],
GCForeground | GCBackground, &gcv)) == None) {
XFreeGC(display, bg_gc);
free_pacman(display, pp);
SETPOINT(points[7], pp->spritexs, pp->spriteys / 2);
SETPOINT(points[8], 1, pp->spriteys / 2);
- XFillRectangle(display, pp->ghostPixmap, bg_gc,
+ XFillRectangle(display, pp->ghostPixmap[0][0][0], bg_gc,
0, 0, pp->spritexs, pp->spriteys);
- XFillArc(display, pp->ghostPixmap, fg_gc,
+ XFillArc(display, pp->ghostPixmap[0][0][0], fg_gc,
0, 0, pp->spritexs, pp->spriteys, 0, 11520);
- XFillPolygon(display, pp->ghostPixmap, fg_gc,
+ XFillPolygon(display, pp->ghostPixmap[0][0][0], fg_gc,
points, 9, Nonconvex, CoordModeOrigin);
XFreeGC(display, bg_gc);
XFreeGC(display, fg_gc);
+#endif
+
- if (!pp->stippledGC) {
- gcv.foreground = MI_BLACK_PIXEL(mi);
- gcv.background = MI_BLACK_PIXEL(mi);
- if ((pp->stippledGC = XCreateGC(display, window,
- GCForeground | GCBackground, &gcv)) == None) {
- free_pacman(display, pp);
- return;
- }
- }
if (pp->pacmanPixmap[0][0] != None)
for (dir = 0; dir < 4; dir++)
for (mouth = 0; mouth < MAXMOUTH; mouth++)