X-Git-Url: http://git.hungrycats.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=hacks%2Fpenetrate.c;h=0707422bbaac5bf4591c2ccba260d08d43d261a1;hb=6f5482d73adb0165c0130bb47d852644ab0c4869;hp=3e41af80e0461a6a257ca1e54b8697719e7de4b4;hpb=df7adbee81405e2849728a24b498ad2117784b1f;p=xscreensaver diff --git a/hacks/penetrate.c b/hacks/penetrate.c index 3e41af80..0707422b 100644 --- a/hacks/penetrate.c +++ b/hacks/penetrate.c @@ -1,5 +1,4 @@ -/* Copyright (c) 1999 - * Adam Miller adum@aya.yale.edu +/* Copyright (c) 1999 Adam Miller adum@aya.yale.edu * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that @@ -19,14 +18,18 @@ * high score is in the bottom left. Start with -smart to have the computer * player skip the learning process. + Version: 0.2 + -- fixed an AI bug that was keeping the computer player a tad weak + Version: 0.1 + -- first release + */ #include "screenhack.h" -#define kSleepTime 10000 +#define kSleepTime 10000 #define font_height(font) (font->ascent + font->descent) -#define FONT_NAME "-*-times-*-*-*-*-80-*-*-*-*-*-*-*" #define kCityPause 500000 #define kLevelPause 1 @@ -35,26 +38,6 @@ #define kMinRate 30 #define kMaxRadius 100 -static XFontStruct *font, *scoreFont; -static GC draw_gc, erase_gc, level_gc; -static unsigned int default_fg_pixel; -static XColor scoreColor; - -int bgrowth; -int lrate = 80, startlrate; -long loop = 0; -long score = 0, highscore = 0; -long nextBonus = kFirstBonus; -int numBonus = 0; -int bround = 0; -long lastLaser = 0; -int gamez = 0; -int aim = 180; -int econpersen = 0; -int choosypersen = 0; -int carefulpersen = 0; -int smart = 0; - typedef struct { int alive; int x, y; @@ -87,6 +70,7 @@ typedef struct { int startx, starty; int endx, endy; int oldx, oldy; + int oldx2, oldy2; float velx, vely, fposx, fposy; float lenMul; XColor color; @@ -104,19 +88,52 @@ typedef struct { #define kMissileSpeed 0.003 #define kLaserSpeed (kMissileSpeed * 6) -Missile missile[kMaxMissiles]; -Boom boom[kMaxBooms]; -City city[kNumCities]; -Laser laser[kMaxLasers]; -int blive[kNumCities]; -static void Explode(int x, int y, int max, XColor color, int oflaser) +struct state { + Display *dpy; + Window window; + + XFontStruct *font, *scoreFont; + GC draw_gc, erase_gc, level_gc; + unsigned int default_fg_pixel; + XColor scoreColor; + + int bgrowth; + int lrate, startlrate; + long loop; + long score, highscore; + long nextBonus; + int numBonus; + int bround; + long lastLaser; + int gamez; + int aim; + int econpersen; + int choosypersen; + int carefulpersen; + int smart; + Colormap cmap; + + Missile missile[kMaxMissiles]; + Boom boom[kMaxBooms]; + City city[kNumCities]; + Laser laser[kMaxLasers]; + int blive[kNumCities]; + + int level, levMissiles, levFreq; + + int draw_xlim, draw_ylim; + int draw_reset; +}; + + +static void Explode(struct state *st, int x, int y, int max, XColor color, int oflaser) { int i; Boom *m = 0; for (i=0;iboom[i].alive) { + m = &st->boom[i]; break; } if (!m) @@ -134,14 +151,13 @@ static void Explode(int x, int y, int max, XColor color, int oflaser) m->oflaser = oflaser; } -static void launch (int xlim, int ylim, - Display *dpy, Colormap cmap, int src) +static void launch (struct state *st, int xlim, int ylim, int src) { int i; Missile *m = 0, *msrc; for (i=0;imissile[i].alive) { + m = &st->missile[i]; break; } if (!m) @@ -155,7 +171,9 @@ static void launch (int xlim, int ylim, m->jenis = random() % 360; m->splits = 0; if (m->jenis < 50) { - m->splits = random() % ((int) (ylim * 0.4)); + int j = ylim * 0.4; + if (j) + m->splits = random() % j; if (m->splits < ylim * 0.08) m->splits = 0; } @@ -163,7 +181,7 @@ static void launch (int xlim, int ylim, /* special if we're from another missile */ if (src >= 0) { int dc = random() % (kNumCities - 1); - msrc = &missile[src]; + msrc = &st->missile[src]; if (dc == msrc->dcity) dc++; m->dcity = dc; @@ -175,7 +193,7 @@ static void launch (int xlim, int ylim, } else m->dcity = random() % kNumCities; - m->endx = city[m->dcity].x + (random() % 20) - 10; + m->endx = st->city[m->dcity].x + (random() % 20) - 10; m->x = m->startx; m->y = m->starty; m->enemies = 0; @@ -184,15 +202,17 @@ static void launch (int xlim, int ylim, hsv_to_rgb (m->jenis, 1.0, 1.0, &m->color.red, &m->color.green, &m->color.blue); m->color.flags = DoRed | DoGreen | DoBlue; - if (!XAllocColor (dpy, cmap, &m->color)) { - m->color.pixel = WhitePixel (dpy, DefaultScreen (dpy)); + if (!XAllocColor (st->dpy, st->cmap, &m->color)) { + m->color.pixel = WhitePixel (st->dpy, DefaultScreen (st->dpy)); m->color.red = m->color.green = m->color.blue = 0xFFFF; } } } -static int fire(int xlim, int ylim, - Display *dpy, Window window, Colormap cmap) +#define kExpHelp 0.2 +#define kSpeedDiff 3.5 +#define kMaxToGround 0.75 +static int fire(struct state *st, int xlim, int ylim) { int i, j, cnt = 0; int dcity; @@ -207,19 +227,19 @@ static int fire(int xlim, int ylim, int deepest = 0; int misnum = 0; - choosy = (random() % 100) < choosypersen; - economic = (random() % 100) < econpersen; - careful = (random() % 100) < carefulpersen; + choosy = (random() % 100) < st->choosypersen; + economic = (random() % 100) < st->econpersen; + careful = (random() % 100) < st->carefulpersen; /* count our cities */ for (i=0;icity[i].alive; if (livecity == 0) return 1; /* no guns */ for (i=0;ilaser[i].alive) { + m = &st->laser[i]; break; } if (!m) @@ -229,10 +249,10 @@ static int fire(int xlim, int ylim, if (choosy) { int choo = 0; for (j=0;jmissile[j]; if (!mis->alive || (mis->y > ytargetmin)) continue; - if (city[mis->dcity].alive) + if (st->city[mis->dcity].alive) choo++; } if (choo == 0) @@ -240,12 +260,15 @@ static int fire(int xlim, int ylim, } for (j=0;jmissile[j]; suitor[j] = 0; if (!mis->alive || (mis->y > ytargetmin)) continue; - if (choosy && (city[mis->dcity].alive == 0)) + if (choosy && (st->city[mis->dcity].alive == 0)) continue; + ey = mis->starty + ((float) (mis->endy - mis->starty)) * (mis->pos + kExpHelp + (1.0 - mis->pos) / kSpeedDiff); + if (ey > ylim * kMaxToGround) + continue; /* too far down */ cnt++; suitor[j] = 1; } @@ -253,27 +276,27 @@ static int fire(int xlim, int ylim, /* count missiles that are on target and not being targeted */ if (choosy && economic) for (j=0;jmissile[j].enemies == 0) untargeted++; if (economic) for (j=0;j 1) - if (missile[j].enemies > 0) - if (missile[j].enemies > 1 || untargeted == 0) { + if (st->missile[j].enemies > 0) + if (st->missile[j].enemies > 1 || untargeted == 0) { suitor[j] = 0; cnt--; } /* who's closest? biggest threat */ - if (suitor[j] && missile[j].y > deepest) - deepest = missile[j].y; + if (suitor[j] && st->missile[j].y > deepest) + deepest = st->missile[j].y; } if (deepest > 0 && careful) { /* only target deepest missile */ cnt = 1; for (j=0;jmissile[j].y != deepest) suitor[j] = 0; } @@ -283,7 +306,7 @@ static int fire(int xlim, int ylim, for (j=0;jmissile[j]; misnum = j; break; } @@ -293,27 +316,27 @@ static int fire(int xlim, int ylim, dcity = random() % livecity; for (j=0;jcity[j].alive) if (dcity-- == 0) { dcity = j; break; } - m->startx = city[dcity].x; + m->startx = st->city[dcity].x; m->starty = ylim; -#define kExpHelp 0.2 -#define kSpeedDiff 3.5 ex = mis->startx + ((float) (mis->endx - mis->startx)) * (mis->pos + kExpHelp + (1.0 - mis->pos) / kSpeedDiff); ey = mis->starty + ((float) (mis->endy - mis->starty)) * (mis->pos + kExpHelp + (1.0 - mis->pos) / kSpeedDiff); - m->endx = ex + random() % 16 - 8 + (random() % aim) - aim / 2; - m->endy = ey + random() % 16 - 8 + (random() % aim) - aim / 2; - if (ey > ylim * 0.75) + m->endx = ex + random() % 16 - 8 + (random() % st->aim) - st->aim / 2; + m->endy = ey + random() % 16 - 8 + (random() % st->aim) - st->aim / 2; + if (ey > ylim * kMaxToGround) return 0; /* too far down */ mis->enemies++; m->target = misnum; m->x = m->startx; m->y = m->starty; - m->oldx = m->x; - m->oldy = m->y; + m->oldx = -1; + m->oldy = -1; + m->oldx2 = -1; + m->oldy2 = -1; m->fposx = m->x; m->fposy = m->y; dx = (m->endx - m->x); @@ -329,162 +352,176 @@ static int fire(int xlim, int ylim, m->color.green = 0xFFFF; m->color.red = 0xFFFF; m->color.flags = DoRed | DoGreen | DoBlue; - if (!XAllocColor (dpy, cmap, &m->color)) { - m->color.pixel = WhitePixel (dpy, DefaultScreen (dpy)); + if (!XAllocColor (st->dpy, st->cmap, &m->color)) { + m->color.pixel = WhitePixel (st->dpy, DefaultScreen (st->dpy)); m->color.red = m->color.green = m->color.blue = 0xFFFF; } } return 1; } -static Colormap -init_penetrate(Display *dpy, Window window) +static void * +penetrate_init (Display *dpy, Window window) { + struct state *st = (struct state *) calloc (1, sizeof(*st)); int i; - /*char *fontname = "-*-new century schoolbook-*-r-*-*-*-380-*-*-*-*-*-*"; */ - char *fontname = "-*-courier-*-r-*-*-*-380-*-*-*-*-*-*"; - char **list; - int foo; - Colormap cmap; + const char *levelfont = "-*-courier-*-r-*-*-*-380-*-*-*-*-*-*"; + const char *scorefont = "-*-helvetica-*-r-*-*-*-180-*-*-*-*-*-*"; XGCValues gcv; XWindowAttributes xgwa; - XGetWindowAttributes (dpy, window, &xgwa); - cmap = xgwa.colormap; - - if (get_string_resource("smart","String")!=NULL && get_string_resource("smart","String")[0]!=0) - smart = 1; - bgrowth = get_integer_resource ("bgrowth", "Integer"); - lrate = get_integer_resource ("lrate", "Integer"); - if (bgrowth < 0) bgrowth = 2; - if (lrate < 0) lrate = 2; - startlrate = lrate; - - if (!fontname || !(font = XLoadQueryFont(dpy, fontname))) { - list = XListFonts(dpy, FONT_NAME, 32767, &foo); - for (i = 0; i < foo; i++) - if ((font = XLoadQueryFont(dpy, list[i]))) - break; - if (!font) { - fprintf (stderr, "%s: Can't find a large font.", progname); - exit (1); - } - XFreeFontNames(list); + + st->dpy = dpy; + st->window = window; + + XGetWindowAttributes (st->dpy, st->window, &xgwa); + st->cmap = xgwa.colormap; + + st->lrate = 80; + st->nextBonus = kFirstBonus; + st->aim = 180; + + st->smart = get_boolean_resource(st->dpy, "smart","Boolean"); + st->bgrowth = get_integer_resource (st->dpy, "bgrowth", "Integer"); + st->lrate = get_integer_resource (st->dpy, "lrate", "Integer"); + if (st->bgrowth < 0) st->bgrowth = 2; + if (st->lrate < 0) st->lrate = 2; + st->startlrate = st->lrate; + + st->font = XLoadQueryFont(st->dpy, levelfont); + if (!st->font) { + fprintf (stderr, "%s: could not load font %s.\n", progname, levelfont); + st->font = XLoadQueryFont(st->dpy, scorefont); + if (! st->font) + st->font = XLoadQueryFont(st->dpy, "fixed"); + if (! st->font) abort(); } - if (!(scoreFont = XLoadQueryFont(dpy, "-*-times-*-r-*-*-*-180-*-*-*-*-*-*"))) - fprintf(stderr, "%s: Can't load Times font.", progname); + st->scoreFont = XLoadQueryFont(st->dpy, scorefont); + if (!st->scoreFont) { + fprintf (stderr, "%s: could not load font %s.\n", progname, scorefont); + st->scoreFont = XLoadQueryFont(st->dpy, levelfont); + if (! st->scoreFont) + st->scoreFont = XLoadQueryFont(st->dpy, "fixed"); + if (! st->scoreFont) abort(); + } for (i = 0; i < kMaxMissiles; i++) - missile[i].alive = 0; + st->missile[i].alive = 0; for (i = 0; i < kMaxLasers; i++) - laser[i].alive = 0; + st->laser[i].alive = 0; for (i = 0; i < kMaxBooms; i++) - boom[i].alive = 0; + st->boom[i].alive = 0; for (i = 0; i < kNumCities; i++) { - City *m = &city[i]; + City *m = &st->city[i]; m->alive = 1; m->color.red = m->color.green = m->color.blue = 0xFFFF; m->color.blue = 0x1111; m->color.green = 0x8888; m->color.flags = DoRed | DoGreen | DoBlue; - if (!XAllocColor (dpy, cmap, &m->color)) { - m->color.pixel = WhitePixel (dpy, DefaultScreen (dpy)); + if (!XAllocColor (st->dpy, st->cmap, &m->color)) { + m->color.pixel = WhitePixel (st->dpy, DefaultScreen (st->dpy)); m->color.red = m->color.green = m->color.blue = 0xFFFF; } } - gcv.foreground = default_fg_pixel = - get_pixel_resource("foreground", "Foreground", dpy, cmap); - gcv.font = scoreFont->fid; - draw_gc = XCreateGC(dpy, window, GCForeground | GCFont, &gcv); - gcv.font = font->fid; - level_gc = XCreateGC(dpy, window, GCForeground | GCFont, &gcv); - XSetForeground (dpy, level_gc, city[0].color.pixel); - gcv.foreground = get_pixel_resource("background", "Background", dpy, cmap); - erase_gc = XCreateGC(dpy, window, GCForeground, &gcv); + gcv.foreground = st->default_fg_pixel = + get_pixel_resource(st->dpy, st->cmap, "foreground", "Foreground"); + gcv.font = st->scoreFont->fid; + st->draw_gc = XCreateGC(st->dpy, st->window, GCForeground | GCFont, &gcv); + gcv.font = st->font->fid; + st->level_gc = XCreateGC(st->dpy, st->window, GCForeground | GCFont, &gcv); + XSetForeground (st->dpy, st->level_gc, st->city[0].color.pixel); + gcv.foreground = get_pixel_resource(st->dpy, st->cmap, "background", "Background"); + st->erase_gc = XCreateGC(st->dpy, st->window, GCForeground, &gcv); + +# ifdef HAVE_COCOA + jwxyz_XSetAntiAliasing (st->dpy, st->erase_gc, False); + jwxyz_XSetAntiAliasing (st->dpy, st->draw_gc, False); +# endif + /* make a gray color for score */ if (!mono_p) { - scoreColor.red = scoreColor.green = scoreColor.blue = 0xAAAA; - scoreColor.flags = DoRed | DoGreen | DoBlue; - if (!XAllocColor (dpy, cmap, &scoreColor)) { - scoreColor.pixel = WhitePixel (dpy, DefaultScreen (dpy)); - scoreColor.red = scoreColor.green = scoreColor.blue = 0xFFFF; + st->scoreColor.red = st->scoreColor.green = st->scoreColor.blue = 0xAAAA; + st->scoreColor.flags = DoRed | DoGreen | DoBlue; + if (!XAllocColor (st->dpy, st->cmap, &st->scoreColor)) { + st->scoreColor.pixel = WhitePixel (st->dpy, DefaultScreen (st->dpy)); + st->scoreColor.red = st->scoreColor.green = st->scoreColor.blue = 0xFFFF; } } - XClearWindow(dpy, window); - return cmap; + XClearWindow(st->dpy, st->window); + return st; } -static void DrawScore(Display *dpy, Window window, Colormap cmap, int xlim, int ylim) +static void DrawScore(struct state *st, int xlim, int ylim) { char buf[16]; int width, height; - sprintf(buf, "%ld", score); - width = XTextWidth(scoreFont, buf, strlen(buf)); - height = font_height(scoreFont); - XSetForeground (dpy, draw_gc, scoreColor.pixel); - XFillRectangle(dpy, window, erase_gc, + sprintf(buf, "%ld", st->score); + width = XTextWidth(st->scoreFont, buf, strlen(buf)); + height = font_height(st->scoreFont); + XSetForeground (st->dpy, st->draw_gc, st->scoreColor.pixel); + XFillRectangle(st->dpy, st->window, st->erase_gc, xlim - width - 6, ylim - height - 2, width + 6, height + 2); - XDrawString(dpy, window, draw_gc, xlim - width - 2, ylim - 2, + XDrawString(st->dpy, st->window, st->draw_gc, xlim - width - 2, ylim - 2, buf, strlen(buf)); - sprintf(buf, "%ld", highscore); - width = XTextWidth(scoreFont, buf, strlen(buf)); - XFillRectangle(dpy, window, erase_gc, + sprintf(buf, "%ld", st->highscore); + width = XTextWidth(st->scoreFont, buf, strlen(buf)); + XFillRectangle(st->dpy, st->window, st->erase_gc, 4, ylim - height - 2, width + 4, height + 2); - XDrawString(dpy, window, draw_gc, 4, ylim - 2, + XDrawString(st->dpy, st->window, st->draw_gc, 4, ylim - 2, buf, strlen(buf)); } -static void AddScore(Display *dpy, Window window, Colormap cmap, int xlim, int ylim, long dif) +static void AddScore(struct state *st, int xlim, int ylim, long dif) { int i, sumlive = 0; for (i=0;icity[i].alive; if (sumlive == 0) return; /* no cities, not possible to score */ - score += dif; - if (score > highscore) - highscore = score; - DrawScore(dpy, window, cmap, xlim, ylim); + st->score += dif; + if (st->score > st->highscore) + st->highscore = st->score; + DrawScore(st, xlim, ylim); } -static void DrawCity(Display *dpy, Window window, Colormap cmap, int x, int y, XColor col) +static void DrawCity(struct state *st, int x, int y, XColor col) { - XSetForeground (dpy, draw_gc, col.pixel); - XFillRectangle(dpy, window, draw_gc, + XSetForeground (st->dpy, st->draw_gc, col.pixel); + XFillRectangle(st->dpy, st->window, st->draw_gc, x - 30, y - 40, 60, 40); - XFillRectangle(dpy, window, draw_gc, + XFillRectangle(st->dpy, st->window, st->draw_gc, x - 20, y - 50, 10, 10); - XFillRectangle(dpy, window, draw_gc, + XFillRectangle(st->dpy, st->window, st->draw_gc, x + 10, y - 50, 10, 10); } -static void DrawCities(Display *dpy, Window window, Colormap cmap, int xlim, int ylim) +static void DrawCities(struct state *st, int xlim, int ylim) { int i, x; for (i = 0; i < kNumCities; i++) { - City *m = &city[i]; + City *m = &st->city[i]; if (!m->alive) continue; x = (i + 1) * (xlim / (kNumCities + 1)); m->x = x; - DrawCity(dpy, window, cmap, x, ylim, m->color); + DrawCity(st, x, ylim, m->color); } } -static void LoopMissiles(Display *dpy, Window window, Colormap cmap, int xlim, int ylim) +static void LoopMissiles(struct state *st, int xlim, int ylim) { int i, j, max = 0; for (i = 0; i < kMaxMissiles; i++) { int old_x, old_y; - Missile *m = &missile[i]; + Missile *m = &st->missile[i]; if (!m->alive) continue; old_x = m->x; @@ -495,28 +532,28 @@ static void LoopMissiles(Display *dpy, Window window, Colormap cmap, int xlim, i /* erase old one */ - XSetLineAttributes(dpy, draw_gc, 4, 0,0,0); - XSetForeground (dpy, draw_gc, m->color.pixel); - XDrawLine(dpy, window, draw_gc, + XSetLineAttributes(st->dpy, st->draw_gc, 4, 0,0,0); + XSetForeground (st->dpy, st->draw_gc, m->color.pixel); + XDrawLine(st->dpy, st->window, st->draw_gc, old_x, old_y, m->x, m->y); /* maybe split off a new missile? */ if (m->splits && (m->y > m->splits)) { m->splits = 0; - launch(xlim, ylim, dpy, cmap, i); + launch(st, xlim, ylim, i); } if (m->y >= ylim) { m->alive = 0; - if (city[m->dcity].alive) { - city[m->dcity].alive = 0; - Explode(m->x, m->y, kBoomRad * 2, m->color, 0); + if (st->city[m->dcity].alive) { + st->city[m->dcity].alive = 0; + Explode(st, m->x, m->y, kBoomRad * 2, m->color, 0); } } /* check hitting explosions */ for (j=0;jboom[j]; if (!b->alive) continue; else { @@ -526,30 +563,50 @@ static void LoopMissiles(Display *dpy, Window window, Colormap cmap, int xlim, i if ((dx < r) && (dy < r)) if (dx * dx + dy * dy < r * r) { m->alive = 0; - max = b->max + bgrowth - kBoomRad; - AddScore(dpy, window, cmap, xlim, ylim, SCORE_MISSILE); + max = b->max + st->bgrowth - kBoomRad; + AddScore(st, xlim, ylim, SCORE_MISSILE); } } } if (m->alive == 0) { + float my_pos; /* we just died */ - Explode(m->x, m->y, kBoomRad + max, m->color, 0); - XSetLineAttributes(dpy, erase_gc, 5, 0,0,0); - XDrawLine(dpy, window, erase_gc, - m->startx, m->starty, m->x, m->y); + Explode(st, m->x, m->y, kBoomRad + max, m->color, 0); + XSetLineAttributes(st->dpy, st->erase_gc, 4, 0,0,0); + /* In a perfect world, we could simply erase a line from + (m->startx, m->starty) to (m->x, m->y). This is not a + perfect world. */ + old_x = m->startx; + old_y = m->starty; + my_pos = kMissileSpeed; + while (my_pos <= m->pos) { + m->x = m->startx + ((float) (m->endx - m->startx)) * my_pos; + m->y = m->starty + ((float) (m->endy - m->starty)) * my_pos; + XDrawLine(st->dpy, st->window, st->erase_gc, old_x, old_y, m->x, m->y); + old_x = m->x; + old_y = m->y; + my_pos += kMissileSpeed; + } } } } -static void LoopLasers(Display *dpy, Window window, Colormap cmap, int xlim, int ylim) +static void LoopLasers(struct state *st, int xlim, int ylim) { int i, j, miny = ylim * 0.8; int x, y; for (i = 0; i < kMaxLasers; i++) { - Laser *m = &laser[i]; + Laser *m = &st->laser[i]; if (!m->alive) continue; + + if (m->oldx != -1) { + XSetLineAttributes(st->dpy, st->erase_gc, 2, 0,0,0); + XDrawLine(st->dpy, st->window, st->erase_gc, + m->oldx2, m->oldy2, m->oldx, m->oldy); + } + m->fposx += m->velx; m->fposy += m->vely; m->x = m->fposx; @@ -558,16 +615,18 @@ static void LoopLasers(Display *dpy, Window window, Colormap cmap, int xlim, int x = m->fposx + (-m->velx * m->lenMul); y = m->fposy + (-m->vely * m->lenMul); - XSetLineAttributes(dpy, erase_gc, 4, 0,0,0); - XDrawLine(dpy, window, erase_gc, - x, y, m->oldx, m->oldy); m->oldx = x; m->oldy = y; - XSetLineAttributes(dpy, draw_gc, 2, 0,0,0); - XSetForeground (dpy, draw_gc, m->color.pixel); - XDrawLine(dpy, window, draw_gc, + XSetLineAttributes(st->dpy, st->draw_gc, 2, 0,0,0); + XSetForeground (st->dpy, st->draw_gc, m->color.pixel); + XDrawLine(st->dpy, st->window, st->draw_gc, m->x, m->y, x, y); + + m->oldx2 = m->x; + m->oldy2 = m->y; + m->oldx = x; + m->oldy = y; if (m->y < m->endy) { m->alive = 0; @@ -576,7 +635,7 @@ static void LoopLasers(Display *dpy, Window window, Colormap cmap, int xlim, int /* check hitting explosions */ if (m->y < miny) for (j=0;jboom[j]; if (!b->alive) continue; else { @@ -589,173 +648,170 @@ static void LoopLasers(Display *dpy, Window window, Colormap cmap, int xlim, int if (dx * dx + dy * dy < r * r) { m->alive = 0; /* one less enemy on this missile -- it probably didn't make it */ - if (missile[m->target].alive) - missile[m->target].enemies--; + if (st->missile[m->target].alive) + st->missile[m->target].enemies--; } } } if (m->alive == 0) { /* we just died */ - XDrawLine(dpy, window, erase_gc, + XDrawLine(st->dpy, st->window, st->erase_gc, m->x, m->y, x, y); - Explode(m->x, m->y, kBoomRad, m->color, 1); + Explode(st, m->x, m->y, kBoomRad, m->color, 1); } } } -static void LoopBooms(Display *dpy, Window window, Colormap cmap, int xlim, int ylim) +static void LoopBooms(struct state *st, int xlim, int ylim) { int i; for (i = 0; i < kMaxBooms; i++) { - Boom *m = &boom[i]; + Boom *m = &st->boom[i]; if (!m->alive) continue; - if (loop & 1) + if (st->loop & 1) { if (m->outgoing) { m->rad++; if (m->rad >= m->max) m->outgoing = 0; - XSetLineAttributes(dpy, draw_gc, 1, 0,0,0); - XSetForeground (dpy, draw_gc, m->color.pixel); - XDrawArc(dpy, window, draw_gc, m->x - m->rad, m->y - m->rad, m->rad * 2, m->rad * 2, 0, 360 * 64); + XSetLineAttributes(st->dpy, st->draw_gc, 1, 0,0,0); + XSetForeground (st->dpy, st->draw_gc, m->color.pixel); + XDrawArc(st->dpy, st->window, st->draw_gc, m->x - m->rad, m->y - m->rad, m->rad * 2, m->rad * 2, 0, 360 * 64); } else { - XSetLineAttributes(dpy, erase_gc, 1, 0,0,0); - XDrawArc(dpy, window, erase_gc, m->x - m->rad, m->y - m->rad, m->rad * 2, m->rad * 2, 0, 360 * 64); + XSetLineAttributes(st->dpy, st->erase_gc, 1, 0,0,0); + XDrawArc(st->dpy, st->window, st->erase_gc, m->x - m->rad, m->y - m->rad, m->rad * 2, m->rad * 2, 0, 360 * 64); m->rad--; if (m->rad <= 0) m->alive = 0; } + } } } -int level = 0, levMissiles, levFreq; /* after they die, let's change a few things */ -static void Improve(void) +static void Improve(struct state *st) { - if (smart) + if (st->smart) return; - if (level > 20) + if (st->level > 20) return; /* no need, really */ - aim -= 4; - if (level <= 2) aim -= 8; - if (level <= 5) aim -= 6; - if (gamez < 3) - aim -= 10; - carefulpersen += 6; - choosypersen += 4; - if (level <= 5) choosypersen += 3; - econpersen += 4; - lrate -= 2; - if (startlrate < kMinRate) { - if (lrate < startlrate) - lrate = startlrate; + st->aim -= 4; + if (st->level <= 2) st->aim -= 8; + if (st->level <= 5) st->aim -= 6; + if (st->gamez < 3) + st->aim -= 10; + st->carefulpersen += 6; + st->choosypersen += 4; + if (st->level <= 5) st->choosypersen += 3; + st->econpersen += 4; + st->lrate -= 2; + if (st->startlrate < kMinRate) { + if (st->lrate < st->startlrate) + st->lrate = st->startlrate; } else { - if (lrate < kMinRate) - lrate = kMinRate; + if (st->lrate < kMinRate) + st->lrate = kMinRate; } - if (level <= 5) econpersen += 3; - if (aim < 1) aim = 1; - if (choosypersen > 100) choosypersen = 100; - if (carefulpersen > 100) carefulpersen = 100; - if (econpersen > 100) econpersen = 100; + if (st->level <= 5) st->econpersen += 3; + if (st->aim < 1) st->aim = 1; + if (st->choosypersen > 100) st->choosypersen = 100; + if (st->carefulpersen > 100) st->carefulpersen = 100; + if (st->econpersen > 100) st->econpersen = 100; } -static void NewLevel(Display *dpy, Window window, Colormap cmap, int xlim, int ylim) +static void NewLevel(struct state *st, int xlim, int ylim) { char buf[32]; int width, i, sumlive = 0; int liv[kNumCities]; int freecity = 0; - if (level == 0) { - level++; + if (st->level == 0) { + st->level++; goto END_LEVEL; } /* check for a free city */ - if (score >= nextBonus) { - numBonus++; - nextBonus += kFirstBonus * numBonus; + if (st->score >= st->nextBonus) { + st->numBonus++; + st->nextBonus += kFirstBonus * st->numBonus; freecity = 1; } for (i=0;ibround) + st->city[i].alive = st->blive[i]; + liv[i] = st->city[i].alive; sumlive += liv[i]; - if (!bround) - city[i].alive = 0; + if (!st->bround) + st->city[i].alive = 0; } /* print out screen */ - XFillRectangle(dpy, window, erase_gc, + XFillRectangle(st->dpy, st->window, st->erase_gc, 0, 0, xlim, ylim); - if (bround) + if (st->bround) sprintf(buf, "Bonus Round Over"); else { if (sumlive || freecity) - sprintf(buf, "Level %d Cleared", level); + sprintf(buf, "Level %d Cleared", st->level); else sprintf(buf, "GAME OVER"); } - if (level > 0) { - width = XTextWidth(font, buf, strlen(buf)); - XDrawString(dpy, window, level_gc, xlim / 2 - width / 2, ylim / 2 - font_height(font) / 2, + if (st->level > 0) { + width = XTextWidth(st->font, buf, strlen(buf)); + XDrawString(st->dpy, st->window, st->level_gc, xlim / 2 - width / 2, ylim / 2 - font_height(st->font) / 2, buf, strlen(buf)); - XSync(dpy, False); - screenhack_handle_events(dpy); - sleep(1); + XSync(st->dpy, False); + usleep(1000000); } - if (!bround) { + if (!st->bround) { if (sumlive || freecity) { int sumwidth; /* draw live cities */ - XFillRectangle(dpy, window, erase_gc, + XFillRectangle(st->dpy, st->window, st->erase_gc, 0, ylim - 100, xlim, 100); - sprintf(buf, "X %ld", level * 100L); + sprintf(buf, "X %ld", st->level * 100L); /* how much they get */ - sumwidth = XTextWidth(font, buf, strlen(buf)); + sumwidth = XTextWidth(st->font, buf, strlen(buf)); /* add width of city */ sumwidth += 60; /* add spacer */ sumwidth += 40; - DrawCity(dpy, window, cmap, xlim / 2 - sumwidth / 2 + 30, ylim * 0.70, city[0].color); - XDrawString(dpy, window, level_gc, xlim / 2 - sumwidth / 2 + 40 + 60, ylim * 0.7, buf, strlen(buf)); + DrawCity(st, xlim / 2 - sumwidth / 2 + 30, ylim * 0.70, st->city[0].color); + XDrawString(st->dpy, st->window, st->level_gc, xlim / 2 - sumwidth / 2 + 40 + 60, ylim * 0.7, buf, strlen(buf)); for (i=0;icity[i].alive = 1; + AddScore(st, xlim, ylim, 100 * st->level); + DrawCities(st, xlim, ylim); + XSync(st->dpy, False); usleep(kCityPause); } } } else { /* we're dead */ - screenhack_handle_events(dpy); - sleep(3); - screenhack_handle_events(dpy); + usleep(3000000); + /* start new */ - gamez++; - Improve(); + st->gamez++; + Improve(st); for (i=0;icity[i].alive = 1; + st->level = 0; + st->loop = 1; + st->score = 0; + st->nextBonus = kFirstBonus; + st->numBonus = 0; + DrawCities(st, xlim, ylim); } } @@ -763,150 +819,170 @@ static void NewLevel(Display *dpy, Window window, Colormap cmap, int xlim, int y if (freecity && sumlive < 5) { int ncnt = random() % (5 - sumlive) + 1; for (i=0;icity[i].alive) if (!--ncnt) - city[i].alive = 1; + st->city[i].alive = 1; strcpy(buf, "Bonus City"); - width = XTextWidth(font, buf, strlen(buf)); - XDrawString(dpy, window, level_gc, xlim / 2 - width / 2, ylim / 4, buf, strlen(buf)); - DrawCities(dpy, window, cmap, xlim, ylim); - XSync(dpy, False); - screenhack_handle_events(dpy); - sleep(1); + width = XTextWidth(st->font, buf, strlen(buf)); + XDrawString(st->dpy, st->window, st->level_gc, xlim / 2 - width / 2, ylim / 4, buf, strlen(buf)); + DrawCities(st, xlim, ylim); + XSync(st->dpy, False); + usleep(1000000); } - XFillRectangle(dpy, window, erase_gc, + XFillRectangle(st->dpy, st->window, st->erase_gc, 0, 0, xlim, ylim - 100); - if (!bround) - level++; - if (level == 1) { - nextBonus = kFirstBonus; + if (!st->bround) + st->level++; + if (st->level == 1) { + st->nextBonus = kFirstBonus; } - if (level > 3 && (level % 5 == 1)) { - if (bround) { - bround = 0; - DrawCities(dpy, window, cmap, xlim, ylim); + if (st->level > 3 && (st->level % 5 == 1)) { + if (st->bround) { + st->bround = 0; + DrawCities(st, xlim, ylim); } else { /* bonus round */ - bround = 1; - levMissiles = 20 + level * 10; - levFreq = 10; + st->bround = 1; + st->levMissiles = 20 + st->level * 10; + st->levFreq = 10; for (i=0;iblive[i] = st->city[i].alive; sprintf(buf, "Bonus Round"); - width = XTextWidth(font, buf, strlen(buf)); - XDrawString(dpy, window, level_gc, xlim / 2 - width / 2, ylim / 2 - font_height(font) / 2, buf, strlen(buf)); - XSync(dpy, False); - screenhack_handle_events(dpy); - sleep(1); - XFillRectangle(dpy, window, erase_gc, + width = XTextWidth(st->font, buf, strlen(buf)); + XDrawString(st->dpy, st->window, st->level_gc, xlim / 2 - width / 2, ylim / 2 - font_height(st->font) / 2, buf, strlen(buf)); + XSync(st->dpy, False); + usleep(1000000); + XFillRectangle(st->dpy, st->window, st->erase_gc, 0, 0, xlim, ylim - 100); } } END_LEVEL: ; - if (!bround) { - levMissiles = 5 + level * 3; - if (level > 5) - levMissiles += level * 5; + if (!st->bround) { + st->levMissiles = 5 + st->level * 3; + if (st->level > 5) + st->levMissiles += st->level * 5; /* levMissiles = 2; */ - levFreq = 120 - level * 5; - if (levFreq < 30) - levFreq = 30; + st->levFreq = 120 - st->level * 5; + if (st->levFreq < 30) + st->levFreq = 30; } /* ready to fire */ - lastLaser = 0; + st->lastLaser = 0; } -static void penetrate(Display *dpy, Window window, Colormap cmap) + +static unsigned long +penetrate_draw (Display *dpy, Window window, void *closure) { + struct state *st = (struct state *) closure; XWindowAttributes xgwa; - static int xlim, ylim; - XGetWindowAttributes(dpy, window, &xgwa); - xlim = xgwa.width; - ylim = xgwa.height; + if (st->draw_reset) + { + st->draw_reset = 0; + DrawCities(st, st->draw_xlim, st->draw_ylim); + } + + XGetWindowAttributes(st->dpy, st->window, &xgwa); + st->draw_xlim = xgwa.width; + st->draw_ylim = xgwa.height; /* see if just started */ - if (loop == 0) { - if (smart) { - choosypersen = econpersen = carefulpersen = 100; - lrate = kMinRate; aim = 1; + if (st->loop == 0) { + if (st->smart) { + st->choosypersen = st->econpersen = st->carefulpersen = 100; + st->lrate = kMinRate; st->aim = 1; } - NewLevel(dpy, window, cmap, xlim, ylim); - DrawScore(dpy, window, cmap, xlim, ylim); + NewLevel(st, st->draw_xlim, st->draw_ylim); + DrawScore(st, st->draw_xlim, st->draw_ylim); } - loop++; + st->loop++; - if (levMissiles == 0) { + if (st->levMissiles == 0) { /* see if anything's still on the screen, to know when to end level */ int i; for (i=0;imissile[i].alive) goto END_CHECK; for (i=0;iboom[i].alive) goto END_CHECK; for (i=0;ilaser[i].alive) goto END_CHECK; /* okay, nothing's alive, start end of level countdown */ - screenhack_handle_events(dpy); - sleep(kLevelPause); - NewLevel(dpy, window, cmap, xlim, ylim); - return; + usleep(kLevelPause*1000000); + NewLevel(st, st->draw_xlim, st->draw_ylim); + goto END; END_CHECK: ; } - else if ((random() % levFreq) == 0) { - launch(xlim, ylim, dpy, cmap, -1); - levMissiles--; + else if ((random() % st->levFreq) == 0) { + launch(st, st->draw_xlim, st->draw_ylim, -1); + st->levMissiles--; } - if (loop - lastLaser >= lrate) { - if (fire(xlim, ylim, dpy, window, cmap)) - lastLaser = loop; + if (st->loop - st->lastLaser >= st->lrate) { + if (fire(st, st->draw_xlim, st->draw_ylim)) + st->lastLaser = st->loop; } - XSync(dpy, False); - screenhack_handle_events(dpy); - if (kSleepTime) - usleep(kSleepTime); + if ((st->loop & 7) == 0) + st->draw_reset = 1; + + LoopMissiles(st, st->draw_xlim, st->draw_ylim); + LoopLasers(st, st->draw_xlim, st->draw_ylim); + LoopBooms(st, st->draw_xlim, st->draw_ylim); - if ((loop & 7) == 0) - DrawCities(dpy, window, cmap, xlim, ylim); - LoopMissiles(dpy, window, cmap, xlim, ylim); - LoopLasers(dpy, window, cmap, xlim, ylim); - LoopBooms(dpy, window, cmap, xlim, ylim); + END: + return kSleepTime; } -char *progclass = "Penetrate"; +static void +penetrate_reshape (Display *dpy, Window window, void *closure, + unsigned int w, unsigned int h) +{ + XClearWindow (dpy, window); +} -char *defaults [] = { +static Bool +penetrate_event (Display *dpy, Window window, void *closure, XEvent *event) +{ + return False; +} + +static void +penetrate_free (Display *dpy, Window window, void *closure) +{ + struct state *st = (struct state *) closure; + free (st); +} + + +static const char *penetrate_defaults [] = { ".background: black", ".foreground: white", + "*fpsTop: true", + "*fpsSolid: true", "*bgrowth: 5", "*lrate: 80", + "*smart: False", "*geometry: 800x500", 0 }; -XrmOptionDescRec options [] = { +static XrmOptionDescRec penetrate_options [] = { { "-bgrowth", ".bgrowth", XrmoptionSepArg, 0 }, { "-lrate", ".lrate", XrmoptionSepArg, 0 }, - {"-smart", ".smart", XrmoptionIsArg,0}, + {"-smart", ".smart", XrmoptionNoArg, "True" }, { 0, 0, 0, 0 } }; -void -screenhack (Display *dpy, Window window) -{ - Colormap cmap = init_penetrate(dpy, window); - while (1) - penetrate(dpy, window, cmap); -} +XSCREENSAVER_MODULE ("Penetrate", penetrate)