X-Git-Url: http://git.hungrycats.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=hacks%2Fpacman.c;h=b079605f14c73bdc15ce9e5ffa755620e4dbab46;hb=bc7b7a8eb122206d239ec0e693676bcce31be1aa;hp=43ca2cd4bb7c34c435c36bc6c31a6781764a24ca;hpb=e4fa2ac140f7bc56571373a7b7eb585fa4500e38;p=xscreensaver diff --git a/hacks/pacman.c b/hacks/pacman.c index 43ca2cd4..b079605f 100644 --- a/hacks/pacman.c +++ b/hacks/pacman.c @@ -1,10 +1,7 @@ /* -*- Mode: C; tab-width: 4 -*- */ /* pacman --- Mr. Pacman and his ghost friends */ -#if !defined( lint ) && !defined( SABER ) -static const char sccsid[] = "@(#)pacman.c 5.00 2000/11/01 xlockmore"; - -#endif +/*static const char sccsid[] = "@(#)pacman.c 5.00 2000/11/01 xlockmore";*/ /*- * Copyright (c) 2002 by Edwin de Jong . @@ -22,6 +19,8 @@ static const char sccsid[] = "@(#)pacman.c 5.00 2000/11/01 xlockmore"; * other special, indirect and consequential damages. * * Revision History: + * 15-Aug-2004: Added support for pixmap pacman. Jeremy English jenglish@myself.com + * 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. @@ -34,11 +33,11 @@ static const char sccsid[] = "@(#)pacman.c 5.00 2000/11/01 xlockmore"; /* 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. think of a better level generation algorithm */ +#define DEF_TRACKMOUSE "False" + #ifdef STANDALONE # define MODE_pacman # define PROGCLASS "Pacman" @@ -48,9 +47,10 @@ static const char sccsid[] = "@(#)pacman.c 5.00 2000/11/01 xlockmore"; # 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 */ @@ -62,6 +62,36 @@ static const char sccsid[] = "@(#)pacman.c 5.00 2000/11/01 xlockmore"; #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. */ +# include "images/pacman/pacman-u1.xpm" +# include "images/pacman/pacman-u2.xpm" +# include "images/pacman/pacman-r1.xpm" +# include "images/pacman/pacman-r2.xpm" +# include "images/pacman/pacman-l1.xpm" +# include "images/pacman/pacman-l2.xpm" +# include "images/pacman/pacman-d1.xpm" +# include "images/pacman/pacman-d2.xpm" +# include "images/pacman/pacman-0.xpm" +#endif + #ifdef DISABLE_INTERACTIVE ModeSpecOpt pacman_opts = { 0, @@ -73,22 +103,18 @@ ModeSpecOpt pacman_opts = { #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 = @@ -109,22 +135,37 @@ ModStruct pacman_description = { }; #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++) @@ -135,6 +176,7 @@ free_pacman(Display *display, pacmangamestruct *pp) } } + /* 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 @@ -417,6 +459,121 @@ drawlevel(ModeInfo * mi) XFillRectangle(d,w,g,xl,yl,xs,ys) +/* Draws the pacman sprite, removing the previous location. */ +#if defined(USE_PIXMAP) + +static void +draw_pacman_sprite(ModeInfo * mi) +{ + Display *display = MI_DISPLAY(mi); + Window window = MI_WINDOW(mi); + pacmangamestruct *pp = &pacmangames[MI_SCREEN(mi)]; + unsigned int dir = 0; + int old_mask_dir = 0; + int old_mask_mouth = 0; + static int mouth = 0; + static int mouth_delay = 0; + static int open_mouth = 0; + +#define MAX_MOUTH_DELAY 10 + + pp->pacman.cf = pp->pacman.col * pp->xs + pp->pacman.delta.x * + pp->pacman.cfactor + pp->xb + pp->spritedx; + pp->pacman.rf = pp->pacman.row * pp->ys + pp->pacman.delta.y * + pp->pacman.rfactor + pp->yb + pp->spritedy; + + dir = (ABS(pp->pacman.cfactor) * (2 - pp->pacman.cfactor) + + ABS(pp->pacman.rfactor) * (1 + pp->pacman.rfactor)) % 4; + + if (mouth_delay == MAX_MOUTH_DELAY){ + if (mouth == (MAXMOUTH - 1)|| mouth == 0){ + open_mouth = !open_mouth; + } + open_mouth ? mouth++ : mouth--; + mouth_delay = 0; + }else { + mouth_delay++; + } + + XSetForeground(display, + pp->stippledGC, + MI_BLACK_PIXEL(mi)); + + XSetClipMask(display, pp->stippledGC, pp->pacmanMask[old_mask_dir][old_mask_mouth]); + XSetClipOrigin(display, pp->stippledGC, + pp->pacman.oldcf, pp->pacman.oldrf); + XFillRectangle(display, + window, + pp->stippledGC, + pp->pacman.oldcf, + pp->pacman.oldrf, + pp->spritexs, pp->spriteys); + XSetClipMask(display, pp->stippledGC, pp->pacmanMask[dir][mouth]); + XSetClipOrigin(display, pp->stippledGC, + pp->pacman.cf, pp->pacman.rf); + XCopyArea(display, pp->pacmanPixmap[dir][mouth], window, + pp->stippledGC,0,0,pp->spritexs,pp->spriteys, + pp->pacman.cf, pp->pacman.rf); + XSetClipMask(display, pp->stippledGC, None); + pp->pacman.oldcf = pp->pacman.cf; + pp->pacman.oldrf = pp->pacman.rf; + old_mask_dir = dir; + old_mask_mouth = mouth; +} + + + +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); + drawlevelblock(mi, pp, + (unsigned int)pp->ghosts[ghost].col, + (unsigned int)pp->ghosts[ghost].row); + 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); + 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 /* USE_PIXMAP */ + /* Draws the pacman sprite, removing the previous location. */ static void draw_pacman_sprite(ModeInfo * mi) @@ -500,6 +657,12 @@ 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) { @@ -533,7 +696,7 @@ draw_ghost_sprite(ModeInfo * mi, const unsigned ghost) { MI_WHITE_PIXEL(mi)); XSetStipple(display, pp->stippledGC, - pp->ghostPixmap); + pp->ghostPixmap[0][0][0]); #ifdef FLASH XSetFillStyle(display, @@ -559,6 +722,7 @@ draw_ghost_sprite(ModeInfo * mi, const unsigned ghost) { pp->ghosts[ghost].oldcf = pp->ghosts[ghost].cf; pp->ghosts[ghost].oldrf = pp->ghosts[ghost].rf; } +#endif /* USE_PIXMAP */ /* Does all drawing of moving sprites in the level. */ static void @@ -579,6 +743,170 @@ pacman_tick(ModeInfo * mi) (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 probably 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;ispritexs; + 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]) pacman_fail("Cannot load ghost images"); + + 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]) pacman_fail("Cannot scale ghost images"); + 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) pacman_fail("Cannot load temporary ghost image"); + + temp = scale_pixmap(&display, pp->stippledGC, + temp, pp->spritexs, pp->spriteys); + + if (!temp) pacman_fail("Cannot scale temporary ghost image"); + + gc = XCreateGC(display, pp->ghostMask, 0, 0); + + pp->ghostMask = scale_pixmap(&display, gc, pp->ghostMask, + pp->spritexs, pp->spriteys); + XFreePixmap(display, temp); +} + +/* Load the pacman pixmaps and their mask. */ +static void +load_pacman_pixmaps(Display **dpy, Window window, pacmangamestruct **ps) +{ + pacmangamestruct *pp = *ps; + Display *display = *dpy; + + static char **bits[] = { + pacman_0_xpm, pacman_u1_xpm, pacman_u2_xpm, + pacman_0_xpm, pacman_r1_xpm, pacman_r2_xpm, + pacman_0_xpm, pacman_d1_xpm, pacman_d2_xpm, + pacman_0_xpm, pacman_l1_xpm, pacman_l2_xpm + }; + int i, j, m; + int w = pp->spritexs; + int h = pp->spriteys; + GC gc = 0; + + m = 0; + for (i = 0; i < 4; i++){ + for ( j = 0; j < MAXMOUTH; j++){ + pp->pacmanPixmap[i][j] = xpm_data_to_pixmap (display, window, bits[m++], + &w, &h, &pp->pacmanMask[i][j]); + + if (!pp->pacmanPixmap[i][j]) pacman_fail("Cannot load pacman pixmap."); + + pp->pacmanPixmap[i][j] = scale_pixmap(&display, pp->stippledGC, + pp->pacmanPixmap[i][j], pp->spritexs, pp->spriteys); + + if (!pp->pacmanPixmap[i][j]) pacman_fail("Cannot scale pacman pixmap."); + + if (!gc) + gc = XCreateGC(display, pp->pacmanMask[i][j], 0, 0); + + pp->pacmanMask[i][j] = scale_pixmap(&display, gc, pp->pacmanMask[i][j], + pp->spritexs, pp->spriteys); + } + } +} +#endif /* USE_PIXMAP */ + /* Hook function, sets state to initial position. */ void init_pacman(ModeInfo * mi) @@ -588,9 +916,13 @@ init_pacman(ModeInfo * mi) int size = MI_SIZE(mi); pacmangamestruct *pp; XGCValues gcv; - int dir, mouth; + int i, j, k; + +#if (! defined( USE_PIXMAP )) GC fg_gc, bg_gc; XPoint points[9]; + int dir, mouth; +#endif if (pacmangames == NULL) { if ((pacmangames = (pacmangamestruct *) @@ -601,13 +933,18 @@ init_pacman(ModeInfo * mi) 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) { @@ -641,7 +978,21 @@ init_pacman(ModeInfo * mi) 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_ghost_pixmaps(&display,window,&pp); + load_pacman_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; @@ -649,7 +1000,7 @@ init_pacman(ModeInfo * mi) 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; @@ -657,7 +1008,7 @@ init_pacman(ModeInfo * mi) 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); @@ -677,24 +1028,16 @@ init_pacman(ModeInfo * mi) 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); - 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++) @@ -747,6 +1090,7 @@ init_pacman(ModeInfo * mi) XFreeGC(display, fg_gc); XFreeGC(display, bg_gc); } +#endif /* USE_PIXMAP */ pp->pacman.lastbox = START; pp->pacman.mouthdirection = 1;