source: trunk/third/xscreensaver/hacks/penetrate.c @ 15683

Revision 15683, 22.9 KB checked in by ghudson, 24 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r15682, which included commits to RCS files with non-trunk default branches.
Line 
1/* Copyright (c) 1999
2 *  Adam Miller adum@aya.yale.edu
3 *
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that
7 * copyright notice and this permission notice appear in supporting
8 * documentation.  No representations are made about the suitability of this
9 * software for any purpose.  It is provided "as is" without express or
10 * implied warranty.
11
12 * penetrate simulates the arcade classic with the cities and the stuff
13 * shooting down from the sky and stuff. The computer plays against itself,
14 * desperately defending the forces of good against those thingies raining
15 * down. Bonus cities are awarded at ever-increasing intervals. Every five
16 * levels appears a bonus round. The computer player gets progressively
17 * more intelligent as the game progresses. Better aim, more economical with
18 * ammo, and better target selection. Points are in the bottom right, and
19 * high score is in the bottom left. Start with -smart to have the computer
20 * player skip the learning process.
21
22 Version: 0.2
23 -- fixed an AI bug that was keeping the computer player a tad weak
24 Version: 0.1
25 -- first release
26
27 */
28
29#include "screenhack.h"
30
31#define kSleepTime 10000
32
33#define font_height(font)               (font->ascent + font->descent)
34#define FONT_NAME                       "-*-times-*-*-*-*-80-*-*-*-*-*-*-*"
35
36#define kCityPause 500000
37#define kLevelPause 1
38#define SCORE_MISSILE 100
39#define kFirstBonus 5000
40#define kMinRate 30
41#define kMaxRadius 100
42
43static XFontStruct *font, *scoreFont;
44static GC draw_gc, erase_gc, level_gc;
45static unsigned int default_fg_pixel;
46static XColor scoreColor;
47
48int bgrowth;
49int lrate = 80, startlrate;
50long loop = 0;
51long score = 0, highscore = 0;
52long nextBonus = kFirstBonus;
53int numBonus = 0;
54int bround = 0;
55long lastLaser = 0;
56int gamez = 0;
57int aim = 180;
58int econpersen = 0;
59int choosypersen = 0;
60int carefulpersen = 0;
61int smart = 0;
62
63typedef struct {
64  int alive;
65  int x, y;
66  int startx, starty;
67  int endx, endy;
68  int dcity;
69  float pos;
70  int enemies;
71  int jenis;
72  int splits;
73  XColor color;
74} Missile;
75
76typedef struct {
77  int alive;
78  int x, y, rad, oflaser;
79  int max, outgoing;
80  XColor color;
81} Boom;
82
83typedef struct {
84  int alive;
85  int x;
86  XColor color;
87} City;
88
89typedef struct {
90  int alive;
91  int x, y;
92  int startx, starty;
93  int endx, endy;
94  int oldx, oldy;
95  int oldx2, oldy2;
96  float velx, vely, fposx, fposy;
97  float lenMul;
98  XColor color;
99  int target;
100} Laser;
101
102#define kMaxMissiles 256
103#define kMaxBooms 512
104#define kMaxLasers 128
105#define kBoomRad 40
106#define kNumCities 5
107
108#define kLaserLength 12
109
110#define kMissileSpeed 0.003
111#define kLaserSpeed (kMissileSpeed * 6)
112
113Missile missile[kMaxMissiles];
114Boom boom[kMaxBooms];
115City city[kNumCities];
116Laser laser[kMaxLasers];
117int blive[kNumCities];
118
119static void Explode(int x, int y, int max, XColor color, int oflaser)
120{
121  int i;
122  Boom *m = 0;
123  for (i=0;i<kMaxBooms;i++)
124         if (!boom[i].alive) {
125                m = &boom[i];
126                break;
127         }
128  if (!m)
129         return;
130
131  m->alive = 1;
132  m->x = x;
133  m->y = y;
134  m->rad = 0;
135  if (max > kMaxRadius)
136         max = kMaxRadius;
137  m->max = max;
138  m->outgoing = 1;
139  m->color = color;
140  m->oflaser = oflaser;
141}
142
143static void launch (int xlim, int ylim,
144        Display *dpy, Colormap cmap, int src)
145{
146  int i;
147  Missile *m = 0, *msrc;
148  for (i=0;i<kMaxMissiles;i++)
149         if (!missile[i].alive) {
150                m = &missile[i];
151                break;
152         }
153  if (!m)
154         return;
155
156  m->alive = 1;
157  m->startx = (random() % xlim);
158  m->starty = 0;
159  m->endy = ylim;
160  m->pos = 0.0;
161  m->jenis = random() % 360;
162  m->splits = 0;
163  if (m->jenis < 50) {
164         m->splits = random() % ((int) (ylim * 0.4));
165         if (m->splits < ylim * 0.08)
166                m->splits = 0;
167  }
168
169  /* special if we're from another missile */
170  if (src >= 0) {
171         int dc = random() % (kNumCities - 1);
172         msrc = &missile[src];
173         if (dc == msrc->dcity)
174                dc++;
175         m->dcity = dc;
176         m->startx = msrc->x;
177         m->starty = msrc->y;
178         if (m->starty > ylim * 0.4 || m->splits <= m->starty)
179                m->splits = 0;  /* too far down already */
180         m->jenis = msrc->jenis;
181  }
182  else
183         m->dcity = random() % kNumCities;
184  m->endx = city[m->dcity].x + (random() % 20) - 10;
185  m->x = m->startx;
186  m->y = m->starty;
187  m->enemies = 0;
188
189  if (!mono_p) {
190         hsv_to_rgb (m->jenis, 1.0, 1.0,
191                                         &m->color.red, &m->color.green, &m->color.blue);
192         m->color.flags = DoRed | DoGreen | DoBlue;
193         if (!XAllocColor (dpy, cmap, &m->color)) {
194                m->color.pixel = WhitePixel (dpy, DefaultScreen (dpy));
195                m->color.red = m->color.green = m->color.blue = 0xFFFF;
196         }
197  }
198}
199
200#define kExpHelp 0.2
201#define kSpeedDiff 3.5
202#define kMaxToGround 0.75
203static int fire(int xlim, int ylim,
204        Display *dpy, Window window, Colormap cmap)
205{
206  int i, j, cnt = 0;
207  int dcity;
208  long dx, dy, ex, ey;
209  Missile *mis = 0;
210  Laser *m = 0;
211  int untargeted = 0;
212  int choosy = 0, economic = 0, careful = 0;
213  int suitor[kMaxMissiles];
214  int livecity = 0;
215  int ytargetmin = ylim * 0.75;
216  int deepest = 0;
217  int misnum = 0;
218
219  choosy = (random() % 100) < choosypersen;
220  economic = (random() % 100) < econpersen;
221  careful = (random() % 100) < carefulpersen;
222
223  /* count our cities */
224  for (i=0;i<kNumCities;i++)
225         livecity += city[i].alive;
226  if (livecity == 0)
227         return 1;  /* no guns */
228
229  for (i=0;i<kMaxLasers;i++)
230         if (!laser[i].alive) {
231                m = &laser[i];
232                break;
233         }
234  if (!m)
235         return 1;
236
237  /* if no missiles on target, no need to be choosy */
238  if (choosy) {
239         int choo = 0;
240         for (j=0;j<kMaxMissiles;j++) {
241                mis = &missile[j];
242                if (!mis->alive || (mis->y > ytargetmin))
243                  continue;
244                if (city[mis->dcity].alive)
245                  choo++;
246         }
247         if (choo == 0)
248                choosy = 0;
249  }
250
251  for (j=0;j<kMaxMissiles;j++) {
252         mis = &missile[j];
253         suitor[j] = 0;
254         if (!mis->alive || (mis->y > ytargetmin))
255                continue;
256         if (choosy && (city[mis->dcity].alive == 0))
257                continue;
258         ey = mis->starty + ((float) (mis->endy - mis->starty)) * (mis->pos + kExpHelp + (1.0 - mis->pos) / kSpeedDiff);
259         if (ey > ylim * kMaxToGround)
260                continue;  /* too far down */
261         cnt++;
262         suitor[j] = 1;
263  }
264
265  /* count missiles that are on target and not being targeted */
266  if (choosy && economic)
267         for (j=0;j<kMaxMissiles;j++)
268                if (suitor[j] && missile[j].enemies == 0)
269                  untargeted++;
270
271  if (economic)
272         for (j=0;j<kMaxMissiles;j++) {
273                if (suitor[j] && cnt > 1)
274                  if (missile[j].enemies > 0)
275                         if (missile[j].enemies > 1 || untargeted == 0) {
276                                suitor[j] = 0;
277                                cnt--;
278                         }
279                /* who's closest? biggest threat */
280                if (suitor[j] && missile[j].y > deepest)
281                  deepest = missile[j].y;
282         }
283
284  if (deepest > 0 && careful) {
285         /* only target deepest missile */
286         cnt = 1;
287         for (j=0;j<kMaxMissiles;j++)
288                if (suitor[j] && missile[j].y != deepest)
289                  suitor[j] = 0;
290  }
291
292  if (cnt == 0)
293         return 1;  /* no targets available */
294  cnt = random() % cnt;
295  for (j=0;j<kMaxMissiles;j++)
296         if (suitor[j])
297                if (cnt-- == 0) {
298                  mis = &missile[j];
299                  misnum = j;
300                  break;
301                }
302
303  if (mis == 0)
304         return 1;  /* shouldn't happen */
305
306  dcity = random() % livecity;
307  for (j=0;j<kNumCities;j++)
308         if (city[j].alive)
309                if (dcity-- == 0) {
310                  dcity = j;
311                  break;
312                }
313  m->startx = city[dcity].x;
314  m->starty = ylim;
315  ex = mis->startx + ((float) (mis->endx - mis->startx)) * (mis->pos + kExpHelp + (1.0 - mis->pos) / kSpeedDiff);
316  ey = mis->starty + ((float) (mis->endy - mis->starty)) * (mis->pos + kExpHelp + (1.0 - mis->pos) / kSpeedDiff);
317  m->endx = ex + random() % 16 - 8 + (random() % aim) - aim / 2;
318  m->endy = ey + random() % 16 - 8 + (random() % aim) - aim / 2;
319  if (ey > ylim * kMaxToGround)
320         return 0;  /* too far down */
321  mis->enemies++;
322  m->target = misnum;
323  m->x = m->startx;
324  m->y = m->starty;
325  m->oldx = -1;
326  m->oldy = -1;
327  m->oldx2 = -1;
328  m->oldy2 = -1;
329  m->fposx = m->x;
330  m->fposy = m->y;
331  dx = (m->endx - m->x);
332  dy = (m->endy - m->y);
333  m->velx = dx / 100.0;
334  m->vely = dy / 100.0;
335  m->alive = 1;
336  /* m->lenMul = (kLaserLength * kLaserLength) / (m->velx * m->velx + m->vely * m->vely); */
337  m->lenMul = -(kLaserLength / m->vely);
338
339  if (!mono_p) {
340         m->color.blue = 0x0000;
341         m->color.green = 0xFFFF;
342         m->color.red = 0xFFFF;
343         m->color.flags = DoRed | DoGreen | DoBlue;
344         if (!XAllocColor (dpy, cmap, &m->color)) {
345                m->color.pixel = WhitePixel (dpy, DefaultScreen (dpy));
346                m->color.red = m->color.green = m->color.blue = 0xFFFF;
347         }
348  }
349  return 1;
350}
351
352static Colormap
353init_penetrate(Display *dpy, Window window)
354{
355  int i;
356  /*char *fontname =   "-*-new century schoolbook-*-r-*-*-*-380-*-*-*-*-*-*"; */
357  char *fontname =   "-*-courier-*-r-*-*-*-380-*-*-*-*-*-*";
358  char **list;
359  int foo;
360  Colormap cmap;
361  XGCValues gcv;
362  XWindowAttributes xgwa;
363  XGetWindowAttributes (dpy, window, &xgwa);
364  cmap = xgwa.colormap;
365
366  if (get_string_resource("smart","String")!=NULL && get_string_resource("smart","String")[0]!=0)
367         smart = 1;
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;
372  startlrate = lrate;
373
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])))
378                  break;
379         if (!font) {
380                fprintf (stderr, "%s: Can't find a large font.", progname);
381            exit (1);
382         }
383         XFreeFontNames(list);
384  }
385
386  if (!(scoreFont = XLoadQueryFont(dpy, "-*-times-*-r-*-*-*-180-*-*-*-*-*-*")))
387         fprintf(stderr, "%s: Can't load Times font.", progname);
388
389  for (i = 0; i < kMaxMissiles; i++)
390    missile[i].alive = 0;
391
392  for (i = 0; i < kMaxLasers; i++)
393    laser[i].alive = 0;
394
395  for (i = 0; i < kMaxBooms; i++)
396    boom[i].alive = 0;
397
398  for (i = 0; i < kNumCities; i++) {
399         City *m = &city[i];
400    m->alive = 1;
401         m->color.red = m->color.green = m->color.blue = 0xFFFF;
402         m->color.blue = 0x1111; m->color.green = 0x8888;
403         m->color.flags = DoRed | DoGreen | DoBlue;
404         if (!XAllocColor (dpy, cmap, &m->color)) {
405                m->color.pixel = WhitePixel (dpy, DefaultScreen (dpy));
406                m->color.red = m->color.green = m->color.blue = 0xFFFF;
407         }
408  }
409
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);
419
420  /* make a gray color for score */
421  if (!mono_p) {
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;
427         }
428  }
429
430  XClearWindow(dpy, window);
431  return cmap;
432}
433
434static void DrawScore(Display *dpy, Window window, Colormap cmap, int xlim, int ylim)
435{
436  char buf[16];
437  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,
443                                  xlim - width - 6, ylim - height - 2, width + 6, height + 2);
444  XDrawString(dpy, window, draw_gc, xlim - width - 2, ylim - 2,
445                    buf, strlen(buf));
446
447  sprintf(buf, "%ld", highscore);
448  width = XTextWidth(scoreFont, buf, strlen(buf));
449  XFillRectangle(dpy, window, erase_gc,
450                                  4, ylim - height - 2, width + 4, height + 2);
451  XDrawString(dpy, window, draw_gc, 4, ylim - 2,
452                    buf, strlen(buf));
453}
454
455static void AddScore(Display *dpy, Window window, Colormap cmap, int xlim, int ylim, long dif)
456{
457  int i, sumlive = 0;
458  for (i=0;i<kNumCities;i++)
459         sumlive += city[i].alive;
460  if (sumlive == 0)
461         return;   /* no cities, not possible to score */
462
463  score += dif;
464  if (score > highscore)
465         highscore = score;
466  DrawScore(dpy, window, cmap, xlim, ylim);
467}
468
469static void DrawCity(Display *dpy, Window window, Colormap cmap, int x, int y, XColor col)
470{
471         XSetForeground (dpy, draw_gc, col.pixel);
472         XFillRectangle(dpy, window, draw_gc,
473                                  x - 30, y - 40, 60, 40);
474         XFillRectangle(dpy, window, draw_gc,
475                                                 x - 20, y - 50, 10, 10);
476         XFillRectangle(dpy, window, draw_gc,
477                                  x + 10, y - 50, 10, 10);
478}
479
480static void DrawCities(Display *dpy, Window window, Colormap cmap, int xlim, int ylim)
481{
482  int i, x;
483  for (i = 0; i < kNumCities; i++) {
484         City *m = &city[i];
485         if (!m->alive)
486                continue;
487         x = (i + 1) * (xlim / (kNumCities + 1));
488         m->x = x;
489
490         DrawCity(dpy, window, cmap, x, ylim, m->color);
491  }
492}
493
494static void LoopMissiles(Display *dpy, Window window, Colormap cmap, int xlim, int ylim)
495{
496  int i, j, max = 0;
497  for (i = 0; i < kMaxMissiles; i++) {
498         int old_x, old_y;
499         Missile *m = &missile[i];
500         if (!m->alive)
501                continue;
502         old_x = m->x;
503         old_y = m->y;
504         m->pos += kMissileSpeed;
505         m->x = m->startx + ((float) (m->endx - m->startx)) * m->pos;
506         m->y = m->starty + ((float) (m->endy - m->starty)) * m->pos;
507
508      /* erase old one */
509
510         XSetLineAttributes(dpy, draw_gc, 4, 0,0,0);
511    XSetForeground (dpy, draw_gc, m->color.pixel);
512         XDrawLine(dpy, window, draw_gc,
513                                  old_x, old_y, m->x, m->y);
514
515         /* maybe split off a new missile? */
516         if (m->splits && (m->y > m->splits)) {
517                m->splits = 0;
518                launch(xlim, ylim, dpy, cmap, i);
519         }
520         
521         if (m->y >= ylim) {
522                m->alive = 0;
523                if (city[m->dcity].alive) {
524                  city[m->dcity].alive = 0;
525                  Explode(m->x, m->y, kBoomRad * 2, m->color, 0);
526                }
527         }
528
529         /* check hitting explosions */
530         for (j=0;j<kMaxBooms;j++) {
531                Boom *b = &boom[j];
532                if (!b->alive)
533                  continue;
534                else {
535                  int dx = abs(m->x - b->x);
536                  int dy = abs(m->y - b->y);
537                  int r = b->rad + 2;
538                  if ((dx < r) && (dy < r))
539                         if (dx * dx + dy * dy < r * r) {
540                                m->alive = 0;
541                                max = b->max + bgrowth - kBoomRad;
542                                AddScore(dpy, window, cmap, xlim, ylim, SCORE_MISSILE);
543                  }
544                }
545         }
546
547         if (m->alive == 0) {
548                int old_x, old_y;
549                float my_pos;
550                /* we just died */
551                Explode(m->x, m->y, kBoomRad + max, m->color, 0);
552                XSetLineAttributes(dpy, erase_gc, 4, 0,0,0);
553                /* In a perfect world, we could simply erase a line from
554                   (m->startx, m->starty) to (m->x, m->y). This is not a
555                   perfect world. */
556                old_x = m->startx;
557                old_y = m->starty;
558                my_pos = kMissileSpeed;
559                while (my_pos <= m->pos) {
560                        m->x = m->startx + ((float) (m->endx - m->startx)) * my_pos;
561                        m->y = m->starty + ((float) (m->endy - m->starty)) * my_pos;
562                        XDrawLine(dpy, window, erase_gc, old_x, old_y, m->x, m->y);
563                        old_x = m->x;
564                        old_y = m->y;
565                        my_pos += kMissileSpeed;
566                }
567         }
568  }
569}
570
571static void LoopLasers(Display *dpy, Window window, Colormap cmap, int xlim, int ylim)
572{
573  int i, j, miny = ylim * 0.8;
574  int x, y;
575  for (i = 0; i < kMaxLasers; i++) {
576         Laser *m = &laser[i];
577         if (!m->alive)
578                continue;
579
580         if (m->oldx != -1) {
581                 XSetLineAttributes(dpy, erase_gc, 2, 0,0,0);
582                 XDrawLine(dpy, window, erase_gc,
583                                  m->oldx2, m->oldy2, m->oldx, m->oldy);
584         }
585
586         m->fposx += m->velx;
587         m->fposy += m->vely;
588         m->x = m->fposx;
589         m->y = m->fposy;
590         
591         x = m->fposx + (-m->velx * m->lenMul);
592         y = m->fposy + (-m->vely * m->lenMul);
593
594         m->oldx = x;
595         m->oldy = y;
596
597         XSetLineAttributes(dpy, draw_gc, 2, 0,0,0);
598    XSetForeground (dpy, draw_gc, m->color.pixel);
599         XDrawLine(dpy, window, draw_gc,
600                                  m->x, m->y, x, y);
601
602         m->oldx2 = m->x;
603         m->oldy2 = m->y;
604         m->oldx = x;
605         m->oldy = y;
606         
607         if (m->y < m->endy) {
608                m->alive = 0;
609         }
610
611         /* check hitting explosions */
612         if (m->y < miny)
613                for (j=0;j<kMaxBooms;j++) {
614                  Boom *b = &boom[j];
615                  if (!b->alive)
616                         continue;
617                  else {
618                         int dx = abs(m->x - b->x);
619                         int dy = abs(m->y - b->y);
620                         int r = b->rad + 2;
621                         if (b->oflaser)
622                                continue;
623                         if ((dx < r) && (dy < r))
624                                if (dx * dx + dy * dy < r * r) {
625                                  m->alive = 0;
626                                  /* one less enemy on this missile -- it probably didn't make it */
627                                  if (missile[m->target].alive)
628                                         missile[m->target].enemies--;
629                                }
630                  }
631                }
632         
633         if (m->alive == 0) {
634                /* we just died */
635                XDrawLine(dpy, window, erase_gc,
636                                  m->x, m->y, x, y);
637                Explode(m->x, m->y, kBoomRad, m->color, 1);
638         }
639  }
640}
641
642static void LoopBooms(Display *dpy, Window window, Colormap cmap, int xlim, int ylim)
643{
644  int i;
645  for (i = 0; i < kMaxBooms; i++) {
646         Boom *m = &boom[i];
647         if (!m->alive)
648                continue;
649         
650         if (loop & 1) {
651                if (m->outgoing) {
652                  m->rad++;
653                  if (m->rad >= m->max)
654                         m->outgoing = 0;
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);
658                }
659                else {
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);
662                  m->rad--;
663                  if (m->rad <= 0)
664                         m->alive = 0;
665                }
666         }
667  }
668}
669
670int level = 0, levMissiles, levFreq;
671
672/* after they die, let's change a few things */
673static void Improve(void)
674{
675  if (smart)
676         return;
677  if (level > 20)
678         return;  /* no need, really */
679  aim -= 4;
680  if (level <= 2) aim -= 8;
681  if (level <= 5) aim -= 6;
682  if (gamez < 3)
683         aim -= 10;
684  carefulpersen += 6;
685  choosypersen += 4;
686  if (level <= 5) choosypersen += 3;
687  econpersen += 4;
688  lrate -= 2;
689  if (startlrate < kMinRate) {
690         if (lrate < startlrate)
691                lrate = startlrate;
692  }
693  else {
694         if (lrate < kMinRate)
695                lrate = kMinRate;
696  }
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;
702}
703
704static void NewLevel(Display *dpy, Window window, Colormap cmap, int xlim, int ylim)
705{
706  char buf[32];
707  int width, i, sumlive = 0;
708  int liv[kNumCities];
709  int freecity = 0;
710
711  if (level == 0) {
712         level++;
713         goto END_LEVEL;
714  }
715
716  /* check for a free city */
717  if (score >= nextBonus) {
718         numBonus++;
719         nextBonus += kFirstBonus * numBonus;
720         freecity = 1;
721  }
722
723  for (i=0;i<kNumCities;i++) {
724         if (bround)
725                city[i].alive = blive[i];
726         liv[i] = city[i].alive;
727         sumlive += liv[i];
728         if (!bround)
729                city[i].alive = 0;
730  }
731
732  /* print out screen */
733  XFillRectangle(dpy, window, erase_gc,
734                                  0, 0, xlim, ylim);
735  if (bround)
736         sprintf(buf, "Bonus Round Over");
737  else {
738         if (sumlive || freecity)
739                sprintf(buf, "Level %d Cleared", level);
740         else
741                sprintf(buf, "GAME OVER");
742  }
743  if (level > 0) {
744         width = XTextWidth(font, buf, strlen(buf));
745         XDrawString(dpy, window, level_gc, xlim / 2 - width / 2, ylim / 2 - font_height(font) / 2,
746                                         buf, strlen(buf));
747         XSync(dpy, False);
748         screenhack_handle_events(dpy);
749         sleep(1);
750  }
751
752  if (!bround) {
753         if (sumlive || freecity) {
754                int sumwidth;
755                /* draw live cities */
756                XFillRectangle(dpy, window, erase_gc,
757                                                        0, ylim - 100, xlim, 100);
758
759                sprintf(buf, "X %ld", level * 100L);
760                /* how much they get */
761                sumwidth = XTextWidth(font, buf, strlen(buf));
762                /* add width of city */
763                sumwidth += 60;
764                /* add spacer */
765                sumwidth += 40;
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));
768                for (i=0;i<kNumCities;i++) {
769                  if (liv[i]) {
770                         city[i].alive = 1;
771                         AddScore(dpy, window, cmap, xlim, ylim, 100 * level);
772                         DrawCities(dpy, window, cmap, xlim, ylim);
773                         XSync(dpy, False);
774                         screenhack_handle_events(dpy);
775                         usleep(kCityPause);
776                  }
777                }
778         }
779         else {
780                /* we're dead */
781                screenhack_handle_events(dpy);
782                sleep(3);
783                screenhack_handle_events(dpy);
784                /* start new */
785                gamez++;
786                Improve();
787                for (i=0;i<kNumCities;i++)
788                  city[i].alive = 1;
789                level = 0;
790                loop = 1;
791                score = 0;
792                nextBonus = kFirstBonus;
793                numBonus = 0;
794                DrawCities(dpy, window, cmap, xlim, ylim);
795         }
796  }
797
798  /* do free city part */
799  if (freecity && sumlive < 5) {
800         int ncnt = random() % (5 - sumlive) + 1;
801         for (i=0;i<kNumCities;i++)
802                if (!city[i].alive)
803                  if (!--ncnt)
804                         city[i].alive = 1;
805         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);
809         XSync(dpy, False);
810         screenhack_handle_events(dpy);
811         sleep(1);
812  }
813
814  XFillRectangle(dpy, window, erase_gc,
815                                          0, 0, xlim, ylim - 100);
816 
817  if (!bround)
818         level++;
819  if (level == 1) {
820         nextBonus = kFirstBonus;
821  }
822
823  if (level > 3 && (level % 5 == 1)) {
824         if (bround) {
825                bround = 0;
826                DrawCities(dpy, window, cmap, xlim, ylim);
827         }
828         else {
829                /* bonus round */
830                bround = 1;
831                levMissiles = 20 + level * 10;
832                levFreq = 10;
833                for (i=0;i<kNumCities;i++)
834                  blive[i] = city[i].alive;
835                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));
838                XSync(dpy, False);
839                screenhack_handle_events(dpy);
840                sleep(1);
841                XFillRectangle(dpy, window, erase_gc,
842                                                        0, 0, xlim, ylim - 100);
843         }
844  }
845
846 END_LEVEL: ;
847
848  if (!bround) {
849         levMissiles = 5 + level * 3;
850         if (level > 5)
851                levMissiles += level * 5;
852         /*  levMissiles = 2; */
853         levFreq = 120 - level * 5;
854         if (levFreq < 30)
855                levFreq = 30;
856  }
857
858  /* ready to fire */
859  lastLaser = 0;
860}
861
862static void penetrate(Display *dpy, Window window, Colormap cmap)
863{
864  XWindowAttributes xgwa;
865  static int xlim, ylim;
866
867  XGetWindowAttributes(dpy, window, &xgwa);
868  xlim = xgwa.width;
869  ylim = xgwa.height;
870
871  /* see if just started */
872  if (loop == 0) {
873         if (smart) {
874                choosypersen = econpersen = carefulpersen = 100;
875                lrate = kMinRate; aim = 1;
876         }
877         NewLevel(dpy, window, cmap, xlim, ylim);
878         DrawScore(dpy, window, cmap, xlim, ylim);
879  }
880
881  loop++;
882
883  if (levMissiles == 0) {
884         /* see if anything's still on the screen, to know when to end level */
885         int i;
886         for (i=0;i<kMaxMissiles;i++)
887                if (missile[i].alive)
888                  goto END_CHECK;
889         for (i=0;i<kMaxBooms;i++)
890                if (boom[i].alive)
891                  goto END_CHECK;
892         for (i=0;i<kMaxLasers;i++)
893                if (laser[i].alive)
894                  goto END_CHECK;
895         /* okay, nothing's alive, start end of level countdown */
896         screenhack_handle_events(dpy);
897         sleep(kLevelPause);
898         NewLevel(dpy, window, cmap, xlim, ylim);
899         return;
900  END_CHECK: ;
901  }
902  else if ((random() % levFreq) == 0) {
903         launch(xlim, ylim, dpy, cmap, -1);
904         levMissiles--;
905  }
906
907  if (loop - lastLaser >= lrate) {
908         if (fire(xlim, ylim, dpy, window, cmap))
909                lastLaser = loop;
910  }
911
912  XSync(dpy, False);
913  screenhack_handle_events(dpy);
914  if (kSleepTime)
915         usleep(kSleepTime);
916
917  if ((loop & 7) == 0)
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);
922}
923
924char *progclass = "Penetrate";
925
926char *defaults [] = {
927  ".background: black",
928  ".foreground: white",
929  "*bgrowth:    5",
930  "*lrate:      80",
931  "*geometry:   800x500",
932  0
933};
934
935XrmOptionDescRec options [] = {
936  { "-bgrowth",         ".bgrowth",     XrmoptionSepArg, 0 },
937  { "-lrate",           ".lrate",       XrmoptionSepArg, 0 },
938        {"-smart", ".smart", XrmoptionIsArg,0},
939  { 0, 0, 0, 0 }
940};
941
942void
943screenhack (Display *dpy, Window window)
944{
945  Colormap cmap = init_penetrate(dpy, window);
946  while (1)
947    penetrate(dpy, window, cmap);
948}
Note: See TracBrowser for help on using the repository browser.