341
352
m->color.green = 0xFFFF;
342
353
m->color.red = 0xFFFF;
343
354
m->color.flags = DoRed | DoGreen | DoBlue;
344
if (!XAllocColor (dpy, cmap, &m->color)) {
345
m->color.pixel = WhitePixel (dpy, DefaultScreen (dpy));
355
if (!XAllocColor (st->dpy, st->cmap, &m->color)) {
356
m->color.pixel = WhitePixel (st->dpy, DefaultScreen (st->dpy));
346
357
m->color.red = m->color.green = m->color.blue = 0xFFFF;
353
init_penetrate(Display *dpy, Window window)
364
penetrate_init (Display *dpy, Window window)
366
struct state *st = (struct state *) calloc (1, sizeof(*st));
356
368
/*char *fontname = "-*-new century schoolbook-*-r-*-*-*-380-*-*-*-*-*-*"; */
357
369
char *fontname = "-*-courier-*-r-*-*-*-380-*-*-*-*-*-*";
362
371
XWindowAttributes xgwa;
363
XGetWindowAttributes (dpy, window, &xgwa);
364
cmap = xgwa.colormap;
366
if (get_string_resource("smart","String")!=NULL && get_string_resource("smart","String")[0]!=0)
368
bgrowth = get_integer_resource ("bgrowth", "Integer");
369
lrate = get_integer_resource ("lrate", "Integer");
370
if (bgrowth < 0) bgrowth = 2;
371
if (lrate < 0) lrate = 2;
374
if (!fontname || !(font = XLoadQueryFont(dpy, fontname))) {
375
list = XListFonts(dpy, FONT_NAME, 32767, &foo);
376
for (i = 0; i < foo; i++)
377
if ((font = XLoadQueryFont(dpy, list[i])))
380
fprintf (stderr, "%s: Can't find a large font.", progname);
383
XFreeFontNames(list);
386
if (!(scoreFont = XLoadQueryFont(dpy, "-*-times-*-r-*-*-*-180-*-*-*-*-*-*")))
376
XGetWindowAttributes (st->dpy, st->window, &xgwa);
377
st->cmap = xgwa.colormap;
380
st->nextBonus = kFirstBonus;
383
st->smart = get_boolean_resource(st->dpy, "smart","Boolean");
384
st->bgrowth = get_integer_resource (st->dpy, "bgrowth", "Integer");
385
st->lrate = get_integer_resource (st->dpy, "lrate", "Integer");
386
if (st->bgrowth < 0) st->bgrowth = 2;
387
if (st->lrate < 0) st->lrate = 2;
388
st->startlrate = st->lrate;
390
if (!fontname || !*fontname)
391
fprintf (stderr, "%s: no font specified.\n", progname);
392
st->font = XLoadQueryFont(st->dpy, fontname);
394
fprintf (stderr, "%s: could not load font %s.\n", progname, fontname);
396
if (!(st->scoreFont = XLoadQueryFont(st->dpy, "-*-times-*-r-*-*-*-180-*-*-*-*-*-*")))
387
397
fprintf(stderr, "%s: Can't load Times font.", progname);
389
399
for (i = 0; i < kMaxMissiles; i++)
390
missile[i].alive = 0;
400
st->missile[i].alive = 0;
392
402
for (i = 0; i < kMaxLasers; i++)
403
st->laser[i].alive = 0;
395
405
for (i = 0; i < kMaxBooms; i++)
406
st->boom[i].alive = 0;
398
408
for (i = 0; i < kNumCities; i++) {
409
City *m = &st->city[i];
401
411
m->color.red = m->color.green = m->color.blue = 0xFFFF;
402
412
m->color.blue = 0x1111; m->color.green = 0x8888;
403
413
m->color.flags = DoRed | DoGreen | DoBlue;
404
if (!XAllocColor (dpy, cmap, &m->color)) {
405
m->color.pixel = WhitePixel (dpy, DefaultScreen (dpy));
414
if (!XAllocColor (st->dpy, st->cmap, &m->color)) {
415
m->color.pixel = WhitePixel (st->dpy, DefaultScreen (st->dpy));
406
416
m->color.red = m->color.green = m->color.blue = 0xFFFF;
410
gcv.foreground = default_fg_pixel =
411
get_pixel_resource("foreground", "Foreground", dpy, cmap);
412
gcv.font = scoreFont->fid;
413
draw_gc = XCreateGC(dpy, window, GCForeground | GCFont, &gcv);
414
gcv.font = font->fid;
415
level_gc = XCreateGC(dpy, window, GCForeground | GCFont, &gcv);
416
XSetForeground (dpy, level_gc, city[0].color.pixel);
417
gcv.foreground = get_pixel_resource("background", "Background", dpy, cmap);
418
erase_gc = XCreateGC(dpy, window, GCForeground, &gcv);
420
gcv.foreground = st->default_fg_pixel =
421
get_pixel_resource(st->dpy, st->cmap, "foreground", "Foreground");
422
gcv.font = st->scoreFont->fid;
423
st->draw_gc = XCreateGC(st->dpy, st->window, GCForeground | GCFont, &gcv);
424
gcv.font = st->font->fid;
425
st->level_gc = XCreateGC(st->dpy, st->window, GCForeground | GCFont, &gcv);
426
XSetForeground (st->dpy, st->level_gc, st->city[0].color.pixel);
427
gcv.foreground = get_pixel_resource(st->dpy, st->cmap, "background", "Background");
428
st->erase_gc = XCreateGC(st->dpy, st->window, GCForeground, &gcv);
431
jwxyz_XSetAntiAliasing (st->dpy, st->erase_gc, False);
432
jwxyz_XSetAntiAliasing (st->dpy, st->draw_gc, False);
420
436
/* make a gray color for score */
422
scoreColor.red = scoreColor.green = scoreColor.blue = 0xAAAA;
423
scoreColor.flags = DoRed | DoGreen | DoBlue;
424
if (!XAllocColor (dpy, cmap, &scoreColor)) {
425
scoreColor.pixel = WhitePixel (dpy, DefaultScreen (dpy));
426
scoreColor.red = scoreColor.green = scoreColor.blue = 0xFFFF;
438
st->scoreColor.red = st->scoreColor.green = st->scoreColor.blue = 0xAAAA;
439
st->scoreColor.flags = DoRed | DoGreen | DoBlue;
440
if (!XAllocColor (st->dpy, st->cmap, &st->scoreColor)) {
441
st->scoreColor.pixel = WhitePixel (st->dpy, DefaultScreen (st->dpy));
442
st->scoreColor.red = st->scoreColor.green = st->scoreColor.blue = 0xFFFF;
430
XClearWindow(dpy, window);
446
XClearWindow(st->dpy, st->window);
434
static void DrawScore(Display *dpy, Window window, Colormap cmap, int xlim, int ylim)
450
static void DrawScore(struct state *st, int xlim, int ylim)
437
453
int width, height;
438
sprintf(buf, "%ld", score);
439
width = XTextWidth(scoreFont, buf, strlen(buf));
440
height = font_height(scoreFont);
441
XSetForeground (dpy, draw_gc, scoreColor.pixel);
442
XFillRectangle(dpy, window, erase_gc,
454
sprintf(buf, "%ld", st->score);
455
width = XTextWidth(st->scoreFont, buf, strlen(buf));
456
height = font_height(st->scoreFont);
457
XSetForeground (st->dpy, st->draw_gc, st->scoreColor.pixel);
458
XFillRectangle(st->dpy, st->window, st->erase_gc,
443
459
xlim - width - 6, ylim - height - 2, width + 6, height + 2);
444
XDrawString(dpy, window, draw_gc, xlim - width - 2, ylim - 2,
460
XDrawString(st->dpy, st->window, st->draw_gc, xlim - width - 2, ylim - 2,
445
461
buf, strlen(buf));
447
sprintf(buf, "%ld", highscore);
448
width = XTextWidth(scoreFont, buf, strlen(buf));
449
XFillRectangle(dpy, window, erase_gc,
463
sprintf(buf, "%ld", st->highscore);
464
width = XTextWidth(st->scoreFont, buf, strlen(buf));
465
XFillRectangle(st->dpy, st->window, st->erase_gc,
450
466
4, ylim - height - 2, width + 4, height + 2);
451
XDrawString(dpy, window, draw_gc, 4, ylim - 2,
467
XDrawString(st->dpy, st->window, st->draw_gc, 4, ylim - 2,
452
468
buf, strlen(buf));
455
static void AddScore(Display *dpy, Window window, Colormap cmap, int xlim, int ylim, long dif)
471
static void AddScore(struct state *st, int xlim, int ylim, long dif)
457
473
int i, sumlive = 0;
458
474
for (i=0;i<kNumCities;i++)
459
sumlive += city[i].alive;
475
sumlive += st->city[i].alive;
460
476
if (sumlive == 0)
461
477
return; /* no cities, not possible to score */
464
if (score > highscore)
466
DrawScore(dpy, window, cmap, xlim, ylim);
480
if (st->score > st->highscore)
481
st->highscore = st->score;
482
DrawScore(st, xlim, ylim);
469
static void DrawCity(Display *dpy, Window window, Colormap cmap, int x, int y, XColor col)
485
static void DrawCity(struct state *st, int x, int y, XColor col)
471
XSetForeground (dpy, draw_gc, col.pixel);
472
XFillRectangle(dpy, window, draw_gc,
487
XSetForeground (st->dpy, st->draw_gc, col.pixel);
488
XFillRectangle(st->dpy, st->window, st->draw_gc,
473
489
x - 30, y - 40, 60, 40);
474
XFillRectangle(dpy, window, draw_gc,
490
XFillRectangle(st->dpy, st->window, st->draw_gc,
475
491
x - 20, y - 50, 10, 10);
476
XFillRectangle(dpy, window, draw_gc,
492
XFillRectangle(st->dpy, st->window, st->draw_gc,
477
493
x + 10, y - 50, 10, 10);
480
static void DrawCities(Display *dpy, Window window, Colormap cmap, int xlim, int ylim)
496
static void DrawCities(struct state *st, int xlim, int ylim)
483
499
for (i = 0; i < kNumCities; i++) {
500
City *m = &st->city[i];
487
503
x = (i + 1) * (xlim / (kNumCities + 1));
490
DrawCity(dpy, window, cmap, x, ylim, m->color);
506
DrawCity(st, x, ylim, m->color);
494
static void LoopMissiles(Display *dpy, Window window, Colormap cmap, int xlim, int ylim)
510
static void LoopMissiles(struct state *st, int xlim, int ylim)
496
512
int i, j, max = 0;
497
513
for (i = 0; i < kMaxMissiles; i++) {
498
514
int old_x, old_y;
499
Missile *m = &missile[i];
515
Missile *m = &st->missile[i];
624
639
if (dx * dx + dy * dy < r * r) {
626
641
/* one less enemy on this missile -- it probably didn't make it */
627
if (missile[m->target].alive)
628
missile[m->target].enemies--;
642
if (st->missile[m->target].alive)
643
st->missile[m->target].enemies--;
633
648
if (m->alive == 0) {
634
649
/* we just died */
635
XDrawLine(dpy, window, erase_gc,
650
XDrawLine(st->dpy, st->window, st->erase_gc,
636
651
m->x, m->y, x, y);
637
Explode(m->x, m->y, kBoomRad, m->color, 1);
652
Explode(st, m->x, m->y, kBoomRad, m->color, 1);
642
static void LoopBooms(Display *dpy, Window window, Colormap cmap, int xlim, int ylim)
657
static void LoopBooms(struct state *st, int xlim, int ylim)
645
660
for (i = 0; i < kMaxBooms; i++) {
661
Boom *m = &st->boom[i];
651
666
if (m->outgoing) {
653
668
if (m->rad >= m->max)
655
XSetLineAttributes(dpy, draw_gc, 1, 0,0,0);
656
XSetForeground (dpy, draw_gc, m->color.pixel);
657
XDrawArc(dpy, window, draw_gc, m->x - m->rad, m->y - m->rad, m->rad * 2, m->rad * 2, 0, 360 * 64);
670
XSetLineAttributes(st->dpy, st->draw_gc, 1, 0,0,0);
671
XSetForeground (st->dpy, st->draw_gc, m->color.pixel);
672
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);
660
XSetLineAttributes(dpy, erase_gc, 1, 0,0,0);
661
XDrawArc(dpy, window, erase_gc, m->x - m->rad, m->y - m->rad, m->rad * 2, m->rad * 2, 0, 360 * 64);
675
XSetLineAttributes(st->dpy, st->erase_gc, 1, 0,0,0);
676
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);
670
int level = 0, levMissiles, levFreq;
672
686
/* after they die, let's change a few things */
673
static void Improve(void)
687
static void Improve(struct state *st)
678
692
return; /* no need, really */
680
if (level <= 2) aim -= 8;
681
if (level <= 5) aim -= 6;
686
if (level <= 5) choosypersen += 3;
689
if (startlrate < kMinRate) {
690
if (lrate < startlrate)
694
if (st->level <= 2) st->aim -= 8;
695
if (st->level <= 5) st->aim -= 6;
698
st->carefulpersen += 6;
699
st->choosypersen += 4;
700
if (st->level <= 5) st->choosypersen += 3;
703
if (st->startlrate < kMinRate) {
704
if (st->lrate < st->startlrate)
705
st->lrate = st->startlrate;
694
if (lrate < kMinRate)
708
if (st->lrate < kMinRate)
709
st->lrate = kMinRate;
697
if (level <= 5) econpersen += 3;
698
if (aim < 1) aim = 1;
699
if (choosypersen > 100) choosypersen = 100;
700
if (carefulpersen > 100) carefulpersen = 100;
701
if (econpersen > 100) econpersen = 100;
711
if (st->level <= 5) st->econpersen += 3;
712
if (st->aim < 1) st->aim = 1;
713
if (st->choosypersen > 100) st->choosypersen = 100;
714
if (st->carefulpersen > 100) st->carefulpersen = 100;
715
if (st->econpersen > 100) st->econpersen = 100;
704
static void NewLevel(Display *dpy, Window window, Colormap cmap, int xlim, int ylim)
718
static void NewLevel(struct state *st, int xlim, int ylim)
707
721
int width, i, sumlive = 0;
708
722
int liv[kNumCities];
709
723
int freecity = 0;
725
if (st->level == 0) {
716
730
/* check for a free city */
717
if (score >= nextBonus) {
719
nextBonus += kFirstBonus * numBonus;
731
if (st->score >= st->nextBonus) {
733
st->nextBonus += kFirstBonus * st->numBonus;
723
737
for (i=0;i<kNumCities;i++) {
725
city[i].alive = blive[i];
726
liv[i] = city[i].alive;
739
st->city[i].alive = st->blive[i];
740
liv[i] = st->city[i].alive;
727
741
sumlive += liv[i];
743
st->city[i].alive = 0;
732
746
/* print out screen */
733
XFillRectangle(dpy, window, erase_gc,
747
XFillRectangle(st->dpy, st->window, st->erase_gc,
734
748
0, 0, xlim, ylim);
736
750
sprintf(buf, "Bonus Round Over");
738
752
if (sumlive || freecity)
739
sprintf(buf, "Level %d Cleared", level);
753
sprintf(buf, "Level %d Cleared", st->level);
741
755
sprintf(buf, "GAME OVER");
744
width = XTextWidth(font, buf, strlen(buf));
745
XDrawString(dpy, window, level_gc, xlim / 2 - width / 2, ylim / 2 - font_height(font) / 2,
758
width = XTextWidth(st->font, buf, strlen(buf));
759
XDrawString(st->dpy, st->window, st->level_gc, xlim / 2 - width / 2, ylim / 2 - font_height(st->font) / 2,
746
760
buf, strlen(buf));
748
screenhack_handle_events(dpy);
761
XSync(st->dpy, False);
753
766
if (sumlive || freecity) {
755
768
/* draw live cities */
756
XFillRectangle(dpy, window, erase_gc,
769
XFillRectangle(st->dpy, st->window, st->erase_gc,
757
770
0, ylim - 100, xlim, 100);
759
sprintf(buf, "X %ld", level * 100L);
772
sprintf(buf, "X %ld", st->level * 100L);
760
773
/* how much they get */
761
sumwidth = XTextWidth(font, buf, strlen(buf));
774
sumwidth = XTextWidth(st->font, buf, strlen(buf));
762
775
/* add width of city */
766
DrawCity(dpy, window, cmap, xlim / 2 - sumwidth / 2 + 30, ylim * 0.70, city[0].color);
767
XDrawString(dpy, window, level_gc, xlim / 2 - sumwidth / 2 + 40 + 60, ylim * 0.7, buf, strlen(buf));
779
DrawCity(st, xlim / 2 - sumwidth / 2 + 30, ylim * 0.70, st->city[0].color);
780
XDrawString(st->dpy, st->window, st->level_gc, xlim / 2 - sumwidth / 2 + 40 + 60, ylim * 0.7, buf, strlen(buf));
768
781
for (i=0;i<kNumCities;i++) {
771
AddScore(dpy, window, cmap, xlim, ylim, 100 * level);
772
DrawCities(dpy, window, cmap, xlim, ylim);
774
screenhack_handle_events(dpy);
783
st->city[i].alive = 1;
784
AddScore(st, xlim, ylim, 100 * st->level);
785
DrawCities(st, xlim, ylim);
786
XSync(st->dpy, False);
775
787
usleep(kCityPause);
781
screenhack_handle_events(dpy);
783
screenhack_handle_events(dpy);
787
798
for (i=0;i<kNumCities;i++)
792
nextBonus = kFirstBonus;
794
DrawCities(dpy, window, cmap, xlim, ylim);
799
st->city[i].alive = 1;
803
st->nextBonus = kFirstBonus;
805
DrawCities(st, xlim, ylim);
799
810
if (freecity && sumlive < 5) {
800
811
int ncnt = random() % (5 - sumlive) + 1;
801
812
for (i=0;i<kNumCities;i++)
813
if (!st->city[i].alive)
815
st->city[i].alive = 1;
805
816
strcpy(buf, "Bonus City");
806
width = XTextWidth(font, buf, strlen(buf));
807
XDrawString(dpy, window, level_gc, xlim / 2 - width / 2, ylim / 4, buf, strlen(buf));
808
DrawCities(dpy, window, cmap, xlim, ylim);
810
screenhack_handle_events(dpy);
817
width = XTextWidth(st->font, buf, strlen(buf));
818
XDrawString(st->dpy, st->window, st->level_gc, xlim / 2 - width / 2, ylim / 4, buf, strlen(buf));
819
DrawCities(st, xlim, ylim);
820
XSync(st->dpy, False);
814
XFillRectangle(dpy, window, erase_gc,
824
XFillRectangle(st->dpy, st->window, st->erase_gc,
815
825
0, 0, xlim, ylim - 100);
820
nextBonus = kFirstBonus;
829
if (st->level == 1) {
830
st->nextBonus = kFirstBonus;
823
if (level > 3 && (level % 5 == 1)) {
826
DrawCities(dpy, window, cmap, xlim, ylim);
833
if (st->level > 3 && (st->level % 5 == 1)) {
836
DrawCities(st, xlim, ylim);
829
839
/* bonus round */
831
levMissiles = 20 + level * 10;
841
st->levMissiles = 20 + st->level * 10;
833
843
for (i=0;i<kNumCities;i++)
834
blive[i] = city[i].alive;
844
st->blive[i] = st->city[i].alive;
835
845
sprintf(buf, "Bonus Round");
836
width = XTextWidth(font, buf, strlen(buf));
837
XDrawString(dpy, window, level_gc, xlim / 2 - width / 2, ylim / 2 - font_height(font) / 2, buf, strlen(buf));
839
screenhack_handle_events(dpy);
841
XFillRectangle(dpy, window, erase_gc,
846
width = XTextWidth(st->font, buf, strlen(buf));
847
XDrawString(st->dpy, st->window, st->level_gc, xlim / 2 - width / 2, ylim / 2 - font_height(st->font) / 2, buf, strlen(buf));
848
XSync(st->dpy, False);
850
XFillRectangle(st->dpy, st->window, st->erase_gc,
842
851
0, 0, xlim, ylim - 100);
849
levMissiles = 5 + level * 3;
851
levMissiles += level * 5;
858
st->levMissiles = 5 + st->level * 3;
860
st->levMissiles += st->level * 5;
852
861
/* levMissiles = 2; */
853
levFreq = 120 - level * 5;
862
st->levFreq = 120 - st->level * 5;
863
if (st->levFreq < 30)
858
867
/* ready to fire */
862
static void penetrate(Display *dpy, Window window, Colormap cmap)
873
penetrate_draw (Display *dpy, Window window, void *closure)
875
struct state *st = (struct state *) closure;
864
876
XWindowAttributes xgwa;
865
static int xlim, ylim;
867
XGetWindowAttributes(dpy, window, &xgwa);
881
DrawCities(st, st->draw_xlim, st->draw_ylim);
884
XGetWindowAttributes(st->dpy, st->window, &xgwa);
885
st->draw_xlim = xgwa.width;
886
st->draw_ylim = xgwa.height;
871
888
/* see if just started */
874
choosypersen = econpersen = carefulpersen = 100;
875
lrate = kMinRate; aim = 1;
891
st->choosypersen = st->econpersen = st->carefulpersen = 100;
892
st->lrate = kMinRate; st->aim = 1;
877
NewLevel(dpy, window, cmap, xlim, ylim);
878
DrawScore(dpy, window, cmap, xlim, ylim);
894
NewLevel(st, st->draw_xlim, st->draw_ylim);
895
DrawScore(st, st->draw_xlim, st->draw_ylim);
883
if (levMissiles == 0) {
900
if (st->levMissiles == 0) {
884
901
/* see if anything's still on the screen, to know when to end level */
886
903
for (i=0;i<kMaxMissiles;i++)
887
if (missile[i].alive)
904
if (st->missile[i].alive)
889
906
for (i=0;i<kMaxBooms;i++)
907
if (st->boom[i].alive)
892
909
for (i=0;i<kMaxLasers;i++)
910
if (st->laser[i].alive)
895
912
/* okay, nothing's alive, start end of level countdown */
896
screenhack_handle_events(dpy);
898
NewLevel(dpy, window, cmap, xlim, ylim);
913
usleep(kLevelPause*1000000);
914
NewLevel(st, st->draw_xlim, st->draw_ylim);
902
else if ((random() % levFreq) == 0) {
903
launch(xlim, ylim, dpy, cmap, -1);
907
if (loop - lastLaser >= lrate) {
908
if (fire(xlim, ylim, dpy, window, cmap))
913
screenhack_handle_events(dpy);
918
DrawCities(dpy, window, cmap, xlim, ylim);
919
LoopMissiles(dpy, window, cmap, xlim, ylim);
920
LoopLasers(dpy, window, cmap, xlim, ylim);
921
LoopBooms(dpy, window, cmap, xlim, ylim);
924
char *progclass = "Penetrate";
926
char *defaults [] = {
918
else if ((random() % st->levFreq) == 0) {
919
launch(st, st->draw_xlim, st->draw_ylim, -1);
923
if (st->loop - st->lastLaser >= st->lrate) {
924
if (fire(st, st->draw_xlim, st->draw_ylim))
925
st->lastLaser = st->loop;
928
if ((st->loop & 7) == 0)
931
LoopMissiles(st, st->draw_xlim, st->draw_ylim);
932
LoopLasers(st, st->draw_xlim, st->draw_ylim);
933
LoopBooms(st, st->draw_xlim, st->draw_ylim);
940
penetrate_reshape (Display *dpy, Window window, void *closure,
941
unsigned int w, unsigned int h)
946
penetrate_event (Display *dpy, Window window, void *closure, XEvent *event)
952
penetrate_free (Display *dpy, Window window, void *closure)
954
struct state *st = (struct state *) closure;
959
static const char *penetrate_defaults [] = {
927
960
".background: black",
928
961
".foreground: white",
931
965
"*geometry: 800x500",
935
XrmOptionDescRec options [] = {
969
static XrmOptionDescRec penetrate_options [] = {
936
970
{ "-bgrowth", ".bgrowth", XrmoptionSepArg, 0 },
937
971
{ "-lrate", ".lrate", XrmoptionSepArg, 0 },
938
{"-smart", ".smart", XrmoptionIsArg,0},
972
{"-smart", ".smart", XrmoptionNoArg, "True" },
943
screenhack (Display *dpy, Window window)
945
Colormap cmap = init_penetrate(dpy, window);
947
penetrate(dpy, window, cmap);
976
XSCREENSAVER_MODULE ("Penetrate", penetrate)