1449e1153a8907de59e9f7f8e52ce8d4ff2ed499
[xscreensaver] / hacks / blaster.c
1 /* -*- mode: C; tab-width: 2 -*-
2  * blaster, Copyright (c) 1999 Jonathan H. Lin <jonlin@tesuji.org>
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  *  Robots that move randomly and shoot lasers at each other. If the
13  *  mothership is active, it will fly back and forth horizontally, 
14  *  firing 8 lasers in the 8 cardinal directions. The explosions are
15  *  a 20 frame animation. Robots regenerate after the explosion is finished
16  *  and all of its lasers have left the screen.
17  */
18
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <math.h>
22 #include "screenhack.h"
23
24 struct laser_state {
25         int active;
26         int start_x,start_y;
27         int end_x, end_y;
28 };
29
30 struct robot_state {
31         int alive;
32         int death;
33
34         int move_style;
35         int target;
36
37         int old_x, old_y;
38         int new_x, new_y;
39
40         int radius;
41         GC robot_color;
42         GC laser_color;
43         struct laser_state *lasers;
44 };
45
46 struct mother_ship_state {
47         int active;
48         int death;
49         int old_x,new_x;
50         int y;
51         GC ship_color;
52         GC laser_color;
53         struct laser_state *lasers;
54 };
55
56
57
58
59 struct state {
60   Display *dpy;
61   Window window;
62
63   GC r_color0, r_color1, r_color2, r_color3, r_color4, r_color5, l_color0, l_color1;
64   GC s_color;
65   GC black;
66
67   int delay;
68
69   int NUM_ROBOTS;
70   int NUM_LASERS;
71
72   int MOTHER_SHIP;
73   int MOTHER_SHIP_WIDTH;
74   int MOTHER_SHIP_HEIGHT;
75   int MOTHER_SHIP_LASER;
76   int MOTHER_SHIP_PERIOD;
77   int MOTHER_SHIP_HITS;
78
79   int LINE_MOVE_STYLE;
80   int RANDOM_MOVE_STYLE;
81   int NUM_MOVE_STYLES;
82
83   int EXPLODE_SIZE_1;
84   int EXPLODE_SIZE_2;
85   int EXPLODE_SIZE_3;
86   GC EXPLODE_COLOR_1;
87   GC EXPLODE_COLOR_2;
88
89   XArc *stars;
90   int NUM_STARS;
91   int MOVE_STARS;
92   int MOVE_STARS_X;
93   int MOVE_STARS_Y;
94   int MOVE_STARS_RANDOM;
95
96   struct mother_ship_state *mother;
97
98   struct robot_state *robots;
99
100   XWindowAttributes xgwa;
101
102   int initted;
103
104   int draw_x;
105   int draw_y;
106   int draw_z;
107 };
108
109
110 /* creates a new robot. It starts out on one of the edges somewhere and
111         has no initial velocity. A target is randomly picked. */
112 static void make_new_robot(struct state *st, int index)
113 {
114         int laser_check = 0;
115         int x=0;
116
117         for(x=0;x<st->NUM_LASERS;x++) {
118                 if(st->robots[index].lasers[x].active) {
119                         x=st->NUM_LASERS;
120                         laser_check = 1;
121                 }
122         }
123         if(laser_check==0) {
124                 st->robots[index].alive=1;
125
126                 st->robots[index].radius = 7+(random()%7);
127
128                 st->robots[index].move_style = random()%st->NUM_MOVE_STYLES;
129                 if(random()%2==0) {
130                         st->robots[index].new_x=random()%(st->xgwa.width-st->robots[index].radius);
131                         st->robots[index].old_x=st->robots[index].new_x;
132                         if(random()%2==0) {
133                                 st->robots[index].new_y=0;
134                                 st->robots[index].old_y=0;
135                         }
136                         else {
137                                 st->robots[index].new_y=st->xgwa.height-st->robots[index].radius;
138                                 st->robots[index].old_y = st->robots[index].new_y;
139                         }
140                 }
141                 else {
142                         st->robots[index].new_y=random()%(st->xgwa.height-st->robots[index].radius);
143                         st->robots[index].old_y = st->robots[index].new_y;
144                         if(random()%2) {
145                                 st->robots[index].new_x=0;
146                                 st->robots[index].old_x=0;
147                         }
148                         else {
149                                 st->robots[index].new_x=st->xgwa.width-st->robots[index].radius;
150                                 st->robots[index].old_x=st->robots[index].new_x;
151                         }
152                 }
153                         
154                 x=random()%6;
155                 if(x==0) {
156                         st->robots[index].robot_color = st->r_color0;
157                 }
158                 else if(x==1) {
159                         st->robots[index].robot_color = st->r_color1;
160                 }
161                 else if(x==2) {
162                         st->robots[index].robot_color = st->r_color2;
163                 }
164                 else if(x==3) {
165                         st->robots[index].robot_color = st->r_color3;
166                 }
167                 else if(x==4) {
168                         st->robots[index].robot_color = st->r_color4;
169                 }
170                 else if(x==5) {
171                         st->robots[index].robot_color = st->r_color5;
172                 }
173
174                 if(random()%2==0) {
175                         st->robots[index].laser_color = st->l_color0;
176                 }
177                 else {
178                         st->robots[index].laser_color = st->l_color1;
179                 }
180
181                 if(st->NUM_ROBOTS>1) {
182                         st->robots[index].target = random()%st->NUM_ROBOTS;
183                         while(st->robots[index].target==index) {
184                                 st->robots[index].target = random()%st->NUM_ROBOTS;
185                         }       
186                 }
187         }
188 }
189
190 /* moves each robot, randomly changing its direction and velocity.
191         At random a laser is shot toward that robot's target. Also at random
192         the target can change. */
193 static void move_robots(struct state *st)
194 {
195         int x=0;
196         int y=0;
197         int dx=0;
198         int dy=0;
199         int target_x = 0;
200         int target_y = 0;
201         double slope = 0;
202
203         for(x=0;x<st->NUM_ROBOTS;x++) {
204                 if(st->robots[x].alive) {
205                         if((st->robots[x].new_x == st->robots[x].old_x) && (st->robots[x].new_y == st->robots[x].old_y)) {
206                                 if(st->robots[x].new_x==0) {
207                                         st->robots[x].old_x = -((random()%3)+1);
208                                 }
209                                 else {
210                                         st->robots[x].old_x = st->robots[x].old_x + (random()%3)+1;
211                                 }
212                                 if(st->robots[x].new_y==0) {
213                                         st->robots[x].old_y = -((random()%3)+1);
214                                 }
215                                 else {
216                                         st->robots[x].old_y = st->robots[x].old_y + (random()%3)+1;
217                                 }
218                         }
219                         if(st->robots[x].move_style==st->LINE_MOVE_STYLE) {
220                                 dx = st->robots[x].new_x - st->robots[x].old_x;
221                                 dy = st->robots[x].new_y - st->robots[x].old_y;
222                                 if(dx > 3) {
223                                         dx = 3;
224                                 }
225                                 else if(dx < -3) {
226                                         dx = -3;
227                                 }
228                                 if(dy > 3) {
229                                         dy = 3;
230                                 }
231                                 else if(dy < -3) {
232                                         dy = -3;
233                                 }
234                                 st->robots[x].old_x = st->robots[x].new_x;
235                                 st->robots[x].old_y = st->robots[x].new_y;
236
237                                 st->robots[x].new_x = st->robots[x].new_x + dx;
238                                 st->robots[x].new_y = st->robots[x].new_y + dy;
239                         }
240                         else if(st->robots[x].move_style==st->RANDOM_MOVE_STYLE) {
241                                 dx = st->robots[x].new_x - st->robots[x].old_x;
242                                 dy = st->robots[x].new_y - st->robots[x].old_y;
243                                 y=random()%3;
244                                 if(y==0) {
245                                         dx = dx - ((random()%7)+1);
246                                 }
247                                 else if(y==1){
248                                         dx = dx + ((random()%7)+1);
249                                 }
250                                 else {
251                                         dx = (-1)*dx;
252                                 }
253                                 if(dx > 3) {
254                                         dx = 3;
255                                 }
256                                 else if(dx < -3) {
257                                         dx = -3;
258                                 }
259
260                                 y = random()%3;
261                                 if(y==0) {
262                                         dy = dy - ((random()%7)+1);
263                                 }
264                                 else if(y==1){
265                                         dy = dy + ((random()%7)+1);
266                                 }
267                                 else {
268                                         dx = (-1)*dx;
269                                 }
270                                 if(dy > 3) {
271                                         dy = 3;
272                                 }
273                                 else if(dy < -3) {
274                                         dy = -3;
275                                 }
276                                 st->robots[x].old_x = st->robots[x].new_x;
277                                 st->robots[x].old_y = st->robots[x].new_y;
278
279                                 st->robots[x].new_x = st->robots[x].new_x + dx;
280                                 st->robots[x].new_y = st->robots[x].new_y + dy;
281                         }
282
283                         /* bounds corrections */
284                         if(st->robots[x].new_x >= st->xgwa.width-st->robots[x].radius) {
285                                 st->robots[x].new_x = st->xgwa.width - st->robots[x].radius;
286                         }
287                         else if(st->robots[x].new_x < 0) {
288                                 st->robots[x].new_x = 0;
289                         }
290                         if(st->robots[x].new_y >= st->xgwa.height-st->robots[x].radius) {
291                                 st->robots[x].new_y = st->xgwa.height - st->robots[x].radius;
292                         }
293                         else if(st->robots[x].new_y < 0) {
294                                 st->robots[x].new_y = 0;
295                         }
296                 
297                         if(random()%10==0) {
298                                 st->robots[x].move_style = 1;
299                         }
300                         else {
301                                 st->robots[x].move_style = 0;
302                         }
303
304                         if(st->NUM_ROBOTS>1) {
305                                 if(random()%2==0) {
306                                         if(random()%200==0) {
307                                                 st->robots[x].target = random()%st->NUM_ROBOTS;
308                                                 while(st->robots[x].target==x) {
309                                                         st->robots[x].target = random()%st->NUM_ROBOTS;
310                                                 }       
311                                                 for(y=0;y<st->NUM_LASERS;y++) {
312                                                         if(st->robots[x].lasers[y].active == 0) {
313                                                                 st->robots[x].lasers[y].active = 1;
314                                                                 if(random()%2==0) {
315                                                                         if(random()%2==0) {
316                                                                                 st->robots[x].lasers[y].start_x = st->robots[x].new_x+st->robots[x].radius;
317                                                                                 st->robots[x].lasers[y].start_y = st->robots[x].new_y+st->robots[x].radius;
318                                                                                 st->robots[x].lasers[y].end_x = st->robots[x].lasers[y].start_x+7;
319                                                                                 st->robots[x].lasers[y].end_y = st->robots[x].lasers[y].start_y+7;
320                                                                         }
321                                                                         else {
322                                                                                 st->robots[x].lasers[y].start_x = st->robots[x].new_x-st->robots[x].radius;
323                                                                                 st->robots[x].lasers[y].start_y = st->robots[x].new_y+st->robots[x].radius;
324                                                                                 st->robots[x].lasers[y].end_x = st->robots[x].lasers[y].start_x-7;
325                                                                                 st->robots[x].lasers[y].end_y = st->robots[x].lasers[y].start_y+7;
326                                                                         }
327                                                                 }
328                                                                 else {
329                                                                         if(random()%2==0) {
330                                                                                 st->robots[x].lasers[y].start_x = st->robots[x].new_x-st->robots[x].radius;
331                                                                                 st->robots[x].lasers[y].start_y = st->robots[x].new_y-st->robots[x].radius;
332                                                                                 st->robots[x].lasers[y].end_x = st->robots[x].lasers[y].start_x-7;
333                                                                                 st->robots[x].lasers[y].end_y = st->robots[x].lasers[y].start_y-7;
334                                                                         }
335                                                                         else {
336                                                                                 st->robots[x].lasers[y].start_x = st->robots[x].new_x+st->robots[x].radius;
337                                                                                 st->robots[x].lasers[y].start_y = st->robots[x].new_y-st->robots[x].radius;
338                                                                                 st->robots[x].lasers[y].end_x = st->robots[x].lasers[y].start_x+7;
339                                                                                 st->robots[x].lasers[y].end_y = st->robots[x].lasers[y].start_y-7;
340                                                                         }
341                                                                 }
342                                                                 y = st->NUM_LASERS;
343                                                         }
344                                                 }
345                                         }
346                                         else {
347                                                 for(y=0;y<st->NUM_LASERS;y++) {
348                                                         if(st->robots[x].lasers[y].active==0) {
349                                                                 target_x = st->robots[st->robots[x].target].new_x;
350                                                                 target_y = st->robots[st->robots[x].target].new_y;
351                                                                 if((target_x-st->robots[x].new_x)!=0) {
352                                                                         slope = ((double)target_y-st->robots[x].new_y)/((double)(target_x-st->robots[x].new_x));
353
354                                                                         if((slope<1) && (slope>-1)) {
355                                                                                 if(target_x>st->robots[x].new_x) {
356                                                                                         st->robots[x].lasers[y].start_x = st->robots[x].radius;
357                                                                                         st->robots[x].lasers[y].end_x = st->robots[x].lasers[y].start_x + 7;
358                                                                                 }
359                                                                                 else {
360                                                                                         st->robots[x].lasers[y].start_x = -st->robots[x].radius;
361                                                                                         st->robots[x].lasers[y].end_x = st->robots[x].lasers[y].start_x - 7;
362                                                                                 }
363                                                                                 st->robots[x].lasers[y].start_y = (int)(st->robots[x].lasers[y].start_x * slope);
364                                                                                 st->robots[x].lasers[y].end_y = (int)(st->robots[x].lasers[y].end_x * slope);
365                                                                         }
366                                                                         else {
367                                                                                 slope = (target_x-st->robots[x].new_x)/(target_y-st->robots[x].new_y);
368                                                                                 if(target_y>st->robots[x].new_y) {
369                                                                                         st->robots[x].lasers[y].start_y = st->robots[x].radius;
370                                                                                         st->robots[x].lasers[y].end_y = st->robots[x].lasers[y].start_y + 7;
371                                                                                 }
372                                                                                 else {
373                                                                                         st->robots[x].lasers[y].start_y = -st->robots[x].radius;
374                                                                                         st->robots[x].lasers[y].end_y = st->robots[x].lasers[y].start_y - 7;
375                                                                                 }
376                                                                                 st->robots[x].lasers[y].start_x = (int)(st->robots[x].lasers[y].start_y * slope);;
377                                                                                 st->robots[x].lasers[y].end_x = (int)(st->robots[x].lasers[y].end_y * slope);
378                                                                         }
379                                                                         st->robots[x].lasers[y].start_x = st->robots[x].lasers[y].start_x + st->robots[x].new_x;
380                                                                         st->robots[x].lasers[y].start_y = st->robots[x].lasers[y].start_y + st->robots[x].new_y;
381                                                                         st->robots[x].lasers[y].end_x = st->robots[x].lasers[y].end_x + st->robots[x].new_x;
382                                                                         st->robots[x].lasers[y].end_y = st->robots[x].lasers[y].end_y + st->robots[x].new_y;
383                                                                 }
384                                                                 else {
385                                                                         if(target_y > st->robots[x].new_y) {
386                                                                                 st->robots[x].lasers[y].start_x = st->robots[x].new_x;
387                                                                                 st->robots[x].lasers[y].start_y = st->robots[x].new_y+st->robots[x].radius;
388                                                                                 st->robots[x].lasers[y].end_x = st->robots[x].new_x;
389                                                                                 st->robots[x].lasers[y].end_y = st->robots[x].lasers[y].start_y+7;
390                                                                         }
391                                                                         else {
392                                                                                 st->robots[x].lasers[y].start_x = st->robots[x].new_x;
393                                                                                 st->robots[x].lasers[y].start_y = st->robots[x].new_y-st->robots[x].radius;
394                                                                                 st->robots[x].lasers[y].end_x = st->robots[x].new_x;
395                                                                                 st->robots[x].lasers[y].end_y = st->robots[x].lasers[y].start_y-7;
396                                                                         }
397                                                                 }
398                                                         
399                                                                 if((((st->robots[x].lasers[y].start_x - st->robots[x].lasers[y].end_x) > 7) || 
400                                                                          ((st->robots[x].lasers[y].end_x - st->robots[x].lasers[y].start_x) > 7)) &&  
401                                                                         (((st->robots[x].lasers[y].start_y - st->robots[x].lasers[y].end_y) > 7) || 
402                                                                          ((st->robots[x].lasers[y].end_y - st->robots[x].lasers[y].start_y) > 7))) {
403                                                                 }
404                                                                 else {
405                                                                         st->robots[x].lasers[y].active = 1;
406                                                                         y = st->NUM_LASERS;
407                                                                 }
408                                                         }
409                                                 }
410                                         }
411                                 }
412                         }
413                 }
414                 else {
415                         if(st->robots[x].death==0) {
416                                 make_new_robot(st,x);
417                         }
418                 }
419         }
420
421 }
422
423 /* This moves a single laser one frame. collisions with other robots or
424         the mothership is checked. */
425 static void move_laser(struct state *st, int rindex, int index)
426 {
427         int x=0;
428         int y=0;
429         int z=0;
430         int dx=0;
431         int dy=0;
432         struct laser_state *laser;
433         if(rindex>=0) {
434                 laser = st->robots[rindex].lasers;
435         }
436         else {
437                 laser = st->mother->lasers;
438         }
439         if(laser[index].active) {
440                 /* collision with other robots are checked here */
441                 for(x=0;x<st->NUM_ROBOTS;x++) {
442                         if(x!=rindex) {
443                                 if(st->robots[x].alive) {
444                                         y = laser[index].start_x-st->robots[x].new_x;
445                                         if(y<0) {
446                                                 y = st->robots[x].new_x-laser[index].start_x;
447                                         }
448                                         z = laser[index].start_y-st->robots[x].new_y;
449                                         if(z<0) {
450                                                 z = st->robots[x].new_y-laser[index].start_y;
451                                         }
452                                         if((z<st->robots[x].radius-1)&&(y<st->robots[x].radius-1)) {
453                                                 st->robots[x].alive = 0;
454                                                 st->robots[x].death = 20;
455             if (st->black) XFillArc(st->dpy, st->window, st->black, st->robots[x].old_x, st->robots[x].old_y, st->robots[x].radius, st->robots[x].radius, 0, 360*64);
456             if (st->black) XFillArc(st->dpy, st->window, st->black, st->robots[x].new_x, st->robots[x].new_y, st->robots[x].radius, st->robots[x].radius, 0, 360*64);
457                                                 laser[index].active = 0;
458                                                 x = st->NUM_ROBOTS;
459                                         }
460                                         else {
461                                                 y = laser[index].end_x-st->robots[x].new_x;
462                                                 if(y<0) {
463                                                         y = st->robots[x].new_x-laser[index].end_x;
464                                                 }
465                                                 z = laser[index].end_y-st->robots[x].new_y;
466                                                 if(z<0) {
467                                                         z = st->robots[x].new_y-laser[index].end_y;
468                                                 }
469                                                 if((z<st->robots[x].radius-1)&&(y<st->robots[x].radius-1)) {
470                                                         st->robots[x].alive = 0;
471                                                         st->robots[x].death = 20;
472             if (st->black) XFillArc(st->dpy, st->window, st->black, st->robots[x].old_x, st->robots[x].old_y, st->robots[x].radius, st->robots[x].radius, 0, 360*64);
473             if (st->black) XFillArc(st->dpy, st->window, st->black, st->robots[x].new_x, st->robots[x].new_y, st->robots[x].radius, st->robots[x].radius, 0, 360*64);
474                                                         laser[index].active = 0;
475                                                         x = st->NUM_ROBOTS;
476                                                 }
477                                         }
478                                 }
479                         }
480                 }
481                 if((st->MOTHER_SHIP)&&(rindex!=-1)) {
482                         if(laser[index].active) {
483                                 if(st->mother->active) {
484                                         y = laser[index].start_x-st->mother->new_x;
485                                         if(y<0) {
486                                                 y = st->mother->new_x-laser[index].start_x;
487                                         }
488                                         z = laser[index].start_y-st->mother->y;
489                                         if(z<0) {
490                                                 z = st->mother->y-laser[index].start_y;
491                                         }
492                                         if((z<st->MOTHER_SHIP_HEIGHT-1)&&(y<st->MOTHER_SHIP_WIDTH-1)) {
493                                                 laser[index].active = 0;
494                                                 st->mother->active--;
495                                         }
496                                         else {
497                                                 y = laser[index].end_x-st->mother->new_x;
498                                                 if(y<0) {
499                                                         y = st->mother->new_x-laser[index].end_x;
500                                                 }
501                                                 z = laser[index].end_y-st->mother->y;
502                                                 if(z<0) {
503                                                         z = st->mother->y-laser[index].end_y;
504                                                 }
505                                                 if((z<st->MOTHER_SHIP_HEIGHT-1)&&(y<st->MOTHER_SHIP_WIDTH-1)) {
506                                                         laser[index].active = 0;
507                                                         st->mother->active--;
508                                                 }
509                                         }
510
511                                         if(st->mother->active==0) {
512                                                 st->mother->death=20;
513                                         }
514                                 }
515                         }
516                 }
517
518                 if(laser[index].active) {
519                         dx = laser[index].start_x - laser[index].end_x;
520                         dy = laser[index].start_y - laser[index].end_y;
521                 
522                         laser[index].start_x = laser[index].end_x;
523                         laser[index].start_y = laser[index].end_y;
524                         laser[index].end_x = laser[index].end_x-dx;
525                         laser[index].end_y = laser[index].end_y-dy;
526                         
527                         if((laser[index].end_x < 0) || (laser[index].end_x >= st->xgwa.width) ||
528                                 (laser[index].end_y < 0) || (laser[index].end_y >= st->xgwa.height)) {
529                                 laser[index].active = 0;
530                         }                               
531                 }
532         }
533 }
534
535 /* All the robots are drawn, including the mother ship and the explosions.
536         After all the robots have been drawn, their laser banks are check and
537         the active lasers are drawn. */
538 static void draw_robots(struct state *st)
539 {
540         int x=0;
541         int y=0;
542
543         for(x=0;x<st->NUM_ROBOTS;x++) {
544                 if(st->robots[x].alive) {
545       if (st->black) XFillArc(st->dpy, st->window, st->black, st->robots[x].old_x, st->robots[x].old_y, st->robots[x].radius, st->robots[x].radius, 0, 360*64);
546                         XFillArc(st->dpy, st->window, st->robots[x].robot_color, st->robots[x].new_x, st->robots[x].new_y, st->robots[x].radius, st->robots[x].radius, 0, 360*64);
547                 }
548                 else {
549                         if (st->black) XFillArc(st->dpy, st->window, st->black, st->robots[x].old_x, st->robots[x].old_y, st->robots[x].radius, st->robots[x].radius, 0, 360*64);
550                         if(st->robots[x].death) {
551                                 if(st->robots[x].death==20) {
552                                         XFillArc(st->dpy, st->window, st->EXPLODE_COLOR_1, st->robots[x].new_x+(st->robots[x].radius/3), st->robots[x].new_y+(st->robots[x].radius/3), st->EXPLODE_SIZE_1, st->EXPLODE_SIZE_1, 0, 360*64);
553                                 }
554                                 else if(st->robots[x].death==18) {
555                                         XFillArc(st->dpy, st->window, st->EXPLODE_COLOR_2, st->robots[x].new_x+(st->robots[x].radius/3), st->robots[x].new_y+(st->robots[x].radius/3), st->EXPLODE_SIZE_1, st->EXPLODE_SIZE_1, 0, 360*64);
556                                 }
557                                 else if(st->robots[x].death==17) {
558                                         XFillArc(st->dpy, st->window, st->EXPLODE_COLOR_1, st->robots[x].new_x+(st->robots[x].radius/3), st->robots[x].new_y+(st->robots[x].radius/3), st->EXPLODE_SIZE_1, st->EXPLODE_SIZE_1, 0, 360*64);
559                                 }
560                                 else if(st->robots[x].death==15) {
561                                         if (st->black) XFillArc(st->dpy, st->window, st->black, st->robots[x].new_x+(st->robots[x].radius/3), st->robots[x].new_y+(st->robots[x].radius/3), st->EXPLODE_SIZE_1, st->EXPLODE_SIZE_1, 0, 360*64);
562                                 }
563                                 else if(st->robots[x].death==14) {
564                                         XFillArc(st->dpy, st->window, st->EXPLODE_COLOR_2, st->robots[x].new_x+(st->robots[x].radius/3), st->robots[x].new_y+(st->robots[x].radius/3), st->EXPLODE_SIZE_1, st->EXPLODE_SIZE_1, 0, 360*64);
565                                 }
566                                 else if(st->robots[x].death==13) {
567           if (st->black) XFillArc(st->dpy, st->window, st->black, st->robots[x].new_x+(st->robots[x].radius/3), st->robots[x].new_y+(st->robots[x].radius/3), st->EXPLODE_SIZE_1, st->EXPLODE_SIZE_1, 0, 360*64);
568                                 }
569                                 else if(st->robots[x].death==12) {
570                                         XFillArc(st->dpy, st->window, st->EXPLODE_COLOR_1, st->robots[x].new_x+(st->robots[x].radius/3), st->robots[x].new_y+(st->robots[x].radius/3), st->EXPLODE_SIZE_1, st->EXPLODE_SIZE_1, 0, 360*64);
571                                 }
572                                 else if(st->robots[x].death==11) {
573                                         if (st->black) XFillArc(st->dpy, st->window, st->black, st->robots[x].new_x+(st->robots[x].radius/3), st->robots[x].new_y+(st->robots[x].radius/3), st->EXPLODE_SIZE_1, st->EXPLODE_SIZE_1, 0, 360*64);
574                                 }
575                                 else if(st->robots[x].death==10) {
576                                         XFillArc(st->dpy, st->window, st->EXPLODE_COLOR_2, st->robots[x].new_x+(st->robots[x].radius/3), st->robots[x].new_y+(st->robots[x].radius/3), st->EXPLODE_SIZE_1, st->EXPLODE_SIZE_1, 0, 360*64);
577                                 }
578                                 else if(st->robots[x].death==9) {
579           if (st->black) XFillArc(st->dpy, st->window, st->black, st->robots[x].new_x+(st->robots[x].radius/3), st->robots[x].new_y+(st->robots[x].radius/3), st->EXPLODE_SIZE_1, st->EXPLODE_SIZE_1, 0, 360*64);
580                                 }
581                                 else if(st->robots[x].death==8) {
582                                         XFillArc(st->dpy, st->window, st->EXPLODE_COLOR_1, st->robots[x].new_x+(st->robots[x].radius/3), st->robots[x].new_y+(st->robots[x].radius/3), st->EXPLODE_SIZE_1, st->EXPLODE_SIZE_1, 0, 360*64);
583                                 }
584                                 else if(st->robots[x].death==7) {
585                                         if (st->black) XFillArc(st->dpy, st->window, st->black, st->robots[x].new_x+(st->robots[x].radius/3), st->robots[x].new_y+(st->robots[x].radius/3), st->EXPLODE_SIZE_1, st->EXPLODE_SIZE_1, 0, 360*64);
586                                 }
587                                 else if(st->robots[x].death==6) {
588                                         XFillArc(st->dpy, st->window, st->EXPLODE_COLOR_2, st->robots[x].new_x+(st->robots[x].radius/3), st->robots[x].new_y+(st->robots[x].radius/3), st->EXPLODE_SIZE_2, st->EXPLODE_SIZE_2, 0, 360*64);
589                                 }
590                                 else if(st->robots[x].death==4) {
591                                         if (st->black) XFillArc(st->dpy, st->window, st->black, st->robots[x].new_x+(st->robots[x].radius/3), st->robots[x].new_y+(st->robots[x].radius/3), st->EXPLODE_SIZE_2, st->EXPLODE_SIZE_2, 0, 360*64);
592                                 }
593                                 else if(st->robots[x].death==3) {
594                                         XFillArc(st->dpy, st->window, st->EXPLODE_COLOR_1, st->robots[x].new_x+(st->robots[x].radius/3), st->robots[x].new_y+(st->robots[x].radius/3), st->EXPLODE_SIZE_2, st->EXPLODE_SIZE_2, 0, 360*64);
595                                 }
596                                 else if(st->robots[x].death==2) {
597                                         if (st->black) XFillArc(st->dpy, st->window, st->black, st->robots[x].new_x+(st->robots[x].radius/3), st->robots[x].new_y+(st->robots[x].radius/3), st->EXPLODE_SIZE_2, st->EXPLODE_SIZE_2, 0, 360*64);
598                                         XFillArc(st->dpy, st->window, st->EXPLODE_COLOR_2, st->robots[x].new_x+(1.7*st->robots[x].radius/2), st->robots[x].new_y+(1.7*st->robots[x].radius/2), st->EXPLODE_SIZE_3, st->EXPLODE_SIZE_3, 0, 360*64);
599                                 }
600                                 else if(st->robots[x].death==1) {
601           if (st->black) XFillArc(st->dpy, st->window, st->black, st->robots[x].new_x+(1.7*st->robots[x].radius/2), st->robots[x].new_y+(1.7*st->robots[x].radius/2), st->EXPLODE_SIZE_3, st->EXPLODE_SIZE_3, 0, 360*64);
602                                 }
603                                 st->robots[x].death--;
604                         }
605                 }
606         }
607
608         for(x=0;x<st->NUM_ROBOTS;x++) {
609                 for(y=0;y<st->NUM_LASERS;y++) {
610                         if(st->robots[x].lasers[y].active) {
611                                 if (st->black) XDrawLine(st->dpy, st->window, st->black, st->robots[x].lasers[y].start_x,
612                                                          st->robots[x].lasers[y].start_y,
613                                                          st->robots[x].lasers[y].end_x,
614                                                          st->robots[x].lasers[y].end_y);
615                                 move_laser(st, x, y);
616                                 if(st->robots[x].lasers[y].active) {
617                                         XDrawLine(st->dpy, st->window, st->robots[x].laser_color, st->robots[x].lasers[y].start_x,
618                                                                  st->robots[x].lasers[y].start_y,
619                                                                  st->robots[x].lasers[y].end_x,
620                                                                  st->robots[x].lasers[y].end_y);
621                                 }
622                                 else {
623                                         if (st->black) XDrawLine(st->dpy, st->window, st->black, st->robots[x].lasers[y].start_x,
624                                                                  st->robots[x].lasers[y].start_y,
625                                                                  st->robots[x].lasers[y].end_x,
626                                                                  st->robots[x].lasers[y].end_y);
627                                 }                                       
628                         }
629                 }
630         }
631
632         if(st->MOTHER_SHIP) {
633                 if(st->mother->active) {
634                         if (st->black) XFillArc(st->dpy, st->window, st->black, st->mother->old_x, st->mother->y, st->MOTHER_SHIP_WIDTH, st->MOTHER_SHIP_HEIGHT, 0 , 360*64);
635                         XFillArc(st->dpy, st->window, st->mother->ship_color, st->mother->new_x, st->mother->y, st->MOTHER_SHIP_WIDTH, st->MOTHER_SHIP_HEIGHT, 0 , 360*64);
636                 }
637                 else {
638                         if(st->mother->death) {
639                                 if (st->black) XFillArc(st->dpy, st->window, st->black, st->mother->old_x, st->mother->y, st->MOTHER_SHIP_WIDTH, st->MOTHER_SHIP_HEIGHT, 0 , 360*64);
640                                 if(st->mother->death==20) {
641                                         XFillArc(st->dpy, st->window, st->EXPLODE_COLOR_1, st->mother->new_x+1, st->mother->y+1, st->EXPLODE_SIZE_1, st->EXPLODE_SIZE_1, 0, 360*64);
642                                 }
643                                 else if(st->mother->death==18) {
644                                         XFillArc(st->dpy, st->window, st->EXPLODE_COLOR_2, st->mother->new_x+1, st->mother->y+1, st->EXPLODE_SIZE_1, st->EXPLODE_SIZE_1, 0, 360*64);
645                                 }
646                                 else if(st->mother->death==17) {
647                                         XFillArc(st->dpy, st->window, st->EXPLODE_COLOR_1, st->mother->new_x+1, st->mother->y+1, st->EXPLODE_SIZE_1, st->EXPLODE_SIZE_1, 0, 360*64);
648                                 }
649                                 else if(st->mother->death==15) {
650                                         if (st->black) XFillArc(st->dpy, st->window, st->black, st->mother->new_x+1, st->mother->y+1, st->EXPLODE_SIZE_1, st->EXPLODE_SIZE_1, 0, 360*64);
651                                 }
652                                 else if(st->mother->death==14) {
653                                         XFillArc(st->dpy, st->window, st->EXPLODE_COLOR_2, st->mother->new_x+1, st->mother->y+1, st->EXPLODE_SIZE_1, st->EXPLODE_SIZE_1, 0, 360*64);
654                                 }
655                                 else if(st->mother->death==13) {
656                                         if (st->black) XFillArc(st->dpy, st->window, st->black, st->mother->new_x+1, st->mother->y+1, st->EXPLODE_SIZE_1, st->EXPLODE_SIZE_1, 0, 360*64);
657                                 }
658                                 else if(st->mother->death==12) {
659                                         XFillArc(st->dpy, st->window, st->EXPLODE_COLOR_1, st->mother->new_x+1, st->mother->y+1, st->EXPLODE_SIZE_1, st->EXPLODE_SIZE_1, 0, 360*64);
660                                 }
661                                 else if(st->mother->death==11) {
662                                         if (st->black) XFillArc(st->dpy, st->window, st->black, st->mother->new_x+1, st->mother->y+1, st->EXPLODE_SIZE_1, st->EXPLODE_SIZE_1, 0, 360*64);
663                                 }
664                                 else if(st->mother->death==10) {
665                                         XFillArc(st->dpy, st->window, st->EXPLODE_COLOR_2, st->mother->new_x+1, st->mother->y+1, st->EXPLODE_SIZE_1, st->EXPLODE_SIZE_1, 0, 360*64);
666                                 }
667                                 else if(st->mother->death==9) {
668                                         if (st->black) XFillArc(st->dpy, st->window, st->black, st->mother->new_x+1, st->mother->y+1, st->EXPLODE_SIZE_1, st->EXPLODE_SIZE_1, 0, 360*64);
669                                 }
670                                 else if(st->mother->death==8) {
671                                         XFillArc(st->dpy, st->window, st->EXPLODE_COLOR_1, st->mother->new_x+1, st->mother->y+1, st->EXPLODE_SIZE_1, st->EXPLODE_SIZE_1, 0, 360*64);
672                                 }
673                                 else if(st->mother->death==7) {
674                                         if (st->black) XFillArc(st->dpy, st->window, st->black, st->mother->new_x+1, st->mother->y+1, st->EXPLODE_SIZE_1, st->EXPLODE_SIZE_1, 0, 360*64);
675                                 }
676                                 else if(st->mother->death==6) {
677                                         XFillArc(st->dpy, st->window, st->EXPLODE_COLOR_2, st->mother->new_x+1, st->mother->y+1, st->EXPLODE_SIZE_2, st->EXPLODE_SIZE_2, 0, 360*64);
678                                 }
679                                 else if(st->mother->death==4) {
680                                         if (st->black) XFillArc(st->dpy, st->window, st->black, st->mother->new_x+1, st->mother->y+1, st->EXPLODE_SIZE_2, st->EXPLODE_SIZE_2, 0, 360*64);
681                                 }
682                                 else if(st->mother->death==3) {
683                                         XFillArc(st->dpy, st->window, st->EXPLODE_COLOR_1, st->mother->new_x+1, st->mother->y+1, st->EXPLODE_SIZE_2, st->EXPLODE_SIZE_2, 0, 360*64);
684                                 }
685                                 else if(st->mother->death==2) {
686                                         if (st->black) XFillArc(st->dpy, st->window, st->black, st->mother->new_x+1, st->mother->y+1, st->EXPLODE_SIZE_2, st->EXPLODE_SIZE_2, 0, 360*64);
687                                         XFillArc(st->dpy, st->window, st->EXPLODE_COLOR_2, st->mother->new_x+(1.7*st->MOTHER_SHIP_WIDTH/2), st->mother->y+(1.7*st->MOTHER_SHIP_HEIGHT/2), st->EXPLODE_SIZE_3, st->EXPLODE_SIZE_3, 0, 360*64);
688                                 }
689                                 else if(st->mother->death==1) {
690                                         if (st->black) XFillArc(st->dpy, st->window, st->black, st->mother->new_x+(1.7*st->MOTHER_SHIP_WIDTH/2), st->mother->y+(1.7*st->MOTHER_SHIP_HEIGHT/2), st->EXPLODE_SIZE_3, st->EXPLODE_SIZE_3, 0, 360*64);
691                                 }
692                                 st->mother->death--;
693                         }
694                 }
695                 for(y=0;y<8;y++) {
696                         if(st->mother->lasers[y].active) {
697                                 if (st->black) XDrawLine(st->dpy, st->window, st->black, st->mother->lasers[y].start_x,
698                                                          st->mother->lasers[y].start_y,
699                                                          st->mother->lasers[y].end_x,
700                                                          st->mother->lasers[y].end_y);
701                                 move_laser(st, -1,y);
702                                 if(st->mother->lasers[y].active) {
703                                 XDrawLine(st->dpy, st->window, st->mother->laser_color, st->mother->lasers[y].start_x,
704                                                          st->mother->lasers[y].start_y,
705                                                          st->mother->lasers[y].end_x,
706                                                          st->mother->lasers[y].end_y);
707                                 }
708                                 else {
709                                         if (st->black) XDrawLine(st->dpy, st->window, st->black, st->mother->lasers[y].start_x,
710                                                                  st->mother->lasers[y].start_y,
711                                                                  st->mother->lasers[y].end_x,
712                                                                  st->mother->lasers[y].end_y);
713                                 }
714                         }
715                 }
716         }
717 }
718
719 static void
720 init_stars(struct state *st)
721 {
722   if(st->NUM_STARS) {
723     if (! st->stars)
724       st->stars = (XArc *) malloc (st->NUM_STARS * sizeof(XArc));
725     for(st->draw_x=0;st->draw_x<st->NUM_STARS;st->draw_x++) {
726       st->stars[st->draw_x].x = random()%st->xgwa.width;
727       st->stars[st->draw_x].y = random()%st->xgwa.height;
728       st->stars[st->draw_x].width = random()%4 + 1;
729       st->stars[st->draw_x].height = st->stars[st->draw_x].width;
730       st->stars[st->draw_x].angle1 = 0;
731       st->stars[st->draw_x].angle2 = 360 * 64;
732     }
733   }
734 }
735
736
737 static unsigned long
738 blaster_draw (Display *dpy, Window window, void *closure)
739 {
740   struct state *st = (struct state *) closure;
741
742 #ifdef HAVE_COCOA       /* Don't second-guess Quartz's double-buffering */
743   XClearWindow (dpy, window);
744 #endif
745
746   if (!st->initted) 
747     {
748       st->initted = 1;
749
750       st->robots = (struct robot_state *) malloc(st->NUM_ROBOTS * sizeof (struct robot_state));
751       for(st->draw_x=0;st->draw_x<st->NUM_ROBOTS;st->draw_x++) {
752         st->robots[st->draw_x].alive = 0;
753         st->robots[st->draw_x].death = 0;
754         st->robots[st->draw_x].lasers = (struct laser_state *) malloc (st->NUM_LASERS * sizeof(struct laser_state));
755         for(st->draw_y=0;st->draw_y<st->NUM_LASERS;st->draw_y++) {
756           st->robots[st->draw_x].lasers[st->draw_y].active = 0;
757         }
758       }
759
760       init_stars(st);
761     }
762
763                 if(st->NUM_STARS) {
764                         if(st->MOVE_STARS) {
765                                 if (st->black) XFillArcs(st->dpy,st->window,st->black,st->stars,st->NUM_STARS);
766                                 if(st->MOVE_STARS_RANDOM) {
767                                         st->draw_y = st->MOVE_STARS_X;
768                                         st->draw_z = st->MOVE_STARS_Y;
769                                         if(random()%167==0) {
770                                                 st->draw_y = (-1)*st->draw_y;
771                                         }
772                                         if(random()%173==0) {
773                                                 st->draw_z = (-1)*st->draw_z;
774                                         }
775                                         if(random()%50==0) {
776                                                 if(random()%2) {
777                                                         st->draw_y++;
778                                                         if(st->draw_y>st->MOVE_STARS_RANDOM) {
779                                                                 st->draw_y = st->MOVE_STARS_RANDOM;
780                                                         }
781                                                 }
782                                                 else {
783                                                         st->draw_y--;
784                                                         if(st->draw_y < -(st->MOVE_STARS_RANDOM)) {
785                                                                 st->draw_y = -(st->MOVE_STARS_RANDOM);
786                                                         }
787                                                 }
788                                         }
789                                         if(random()%50==0) {
790                                                 if(random()%2) {
791                                                         st->draw_z++;
792                                                         if(st->draw_z>st->MOVE_STARS_RANDOM) {
793                                                                 st->draw_z = st->MOVE_STARS_RANDOM;
794                                                         }
795                                                 }
796                                                 else {
797                                                         st->draw_z--;
798                                                         if(st->draw_z < -st->MOVE_STARS_RANDOM) {
799                                                                 st->draw_z = -st->MOVE_STARS_RANDOM;
800                                                         }
801                                                 }
802                                         }
803                                         st->MOVE_STARS_X = st->draw_y;
804                                         st->MOVE_STARS_Y = st->draw_z;
805                                         for(st->draw_x=0;st->draw_x<st->NUM_STARS;st->draw_x++) {
806                                                 st->stars[st->draw_x].x = st->stars[st->draw_x].x + st->draw_y;
807                                                 st->stars[st->draw_x].y = st->stars[st->draw_x].y + st->draw_z;
808                                                 if(st->stars[st->draw_x].x<0) {
809                                                         st->stars[st->draw_x].x = st->stars[st->draw_x].x + st->xgwa.width;
810                                                 }
811                                                 else if(st->stars[st->draw_x].x>st->xgwa.width) {
812                                                         st->stars[st->draw_x].x = st->stars[st->draw_x].x - st->xgwa.width;
813                                                 }
814                                                 if(st->stars[st->draw_x].y<0) {
815                                                         st->stars[st->draw_x].y = st->stars[st->draw_x].y + st->xgwa.height;
816                                                 }
817                                                 else if(st->stars[st->draw_x].y>st->xgwa.height) {
818                                                         st->stars[st->draw_x].y = st->stars[st->draw_x].y - st->xgwa.height;
819                                                 }
820                                         }
821                                 }
822                                 else {
823                                         for(st->draw_x=0;st->draw_x<st->NUM_STARS;st->draw_x++) {
824                                                 st->stars[st->draw_x].x = st->stars[st->draw_x].x + st->MOVE_STARS_X;
825                                                 st->stars[st->draw_x].y = st->stars[st->draw_x].y + st->MOVE_STARS_Y;
826                                                 if(st->stars[st->draw_x].x<0) {
827                                                         st->stars[st->draw_x].x = st->stars[st->draw_x].x + st->xgwa.width;
828                                                 }
829                                                 else if(st->stars[st->draw_x].x>st->xgwa.width) {
830                                                         st->stars[st->draw_x].x = st->stars[st->draw_x].x - st->xgwa.width;
831                                                 }
832                                                 if(st->stars[st->draw_x].y<0) {
833                                                         st->stars[st->draw_x].y = st->stars[st->draw_x].y + st->xgwa.height;
834                                                 }
835                                                 else if(st->stars[st->draw_x].y>st->xgwa.height) {
836                                                         st->stars[st->draw_x].y = st->stars[st->draw_x].y - st->xgwa.height;
837                                                 }
838                                         }
839                                 }
840                                 XFillArcs(st->dpy,st->window,st->s_color,st->stars,st->NUM_STARS);
841                         }
842                         else {
843                                 XFillArcs(st->dpy,st->window,st->s_color,st->stars,st->NUM_STARS);
844                         }
845                 }
846
847                 if(st->MOTHER_SHIP) {
848                         if(random()%st->MOTHER_SHIP_PERIOD==0) {
849                                 if((st->mother->active==0)&&(st->mother->death==0)) {
850                                         st->mother->active = st->MOTHER_SHIP_HITS;
851                                         st->mother->y = random()%(st->xgwa.height-7);
852                                         if(random()%2==0) {
853                                                 st->mother->old_x=0;
854                                                 st->mother->new_x=0;
855                                         }
856                                         else {
857                                                 st->mother->old_x=st->xgwa.width-25;
858                                                 st->mother->new_x=st->xgwa.width-25;
859                                         }
860                                 }
861                         }
862                 }
863                 move_robots(st);
864                 if(st->MOTHER_SHIP) {
865                         if(st->mother->active) {
866                                 if(st->mother->old_x==st->mother->new_x) {
867                                         if(st->mother->old_x==0) {
868                                                 st->mother->new_x=3;
869                                         }
870                                         else {
871                                                 st->mother->new_x=st->mother->new_x-3;
872                                         }
873                                 }
874                                 else {
875                                         if(st->mother->old_x>st->mother->new_x) {
876                                                 st->mother->old_x = st->mother->new_x;
877                                                 st->mother->new_x = st->mother->new_x-3;
878                                                 if(st->mother->new_x<0) {
879                                                         st->mother->active=0;
880                                                         if (st->black) XFillArc(st->dpy, st->window, st->black, st->mother->old_x, st->mother->y, st->MOTHER_SHIP_WIDTH, st->MOTHER_SHIP_HEIGHT, 0 , 360*64);
881                                                         if (st->black) XFillArc(st->dpy, st->window, st->black, st->mother->new_x, st->mother->y, st->MOTHER_SHIP_WIDTH, st->MOTHER_SHIP_HEIGHT, 0 , 360*64);
882                                                 }
883                                         }
884                                         else {
885                                                 st->mother->old_x = st->mother->new_x;
886                                                 st->mother->new_x = st->mother->new_x+3;
887                                                 if(st->mother->new_x>st->xgwa.width) {
888                                                         st->mother->active=0;
889                                                         if (st->black) XFillArc(st->dpy, st->window, st->black, st->mother->old_x, st->mother->y, st->MOTHER_SHIP_WIDTH, st->MOTHER_SHIP_HEIGHT, 0 , 360*64);
890                                                         if (st->black) XFillArc(st->dpy, st->window, st->black, st->mother->new_x, st->mother->y, st->MOTHER_SHIP_WIDTH, st->MOTHER_SHIP_HEIGHT, 0 , 360*64);
891                                                 }
892                                         }
893                                 }
894                                 st->draw_y=0;
895                                 for(st->draw_x=0;st->draw_x<8;st->draw_x++) {
896                                         if(st->mother->lasers[st->draw_x].active) {
897                                                 st->draw_y=1;
898                                                 st->draw_x=8;
899                                         }
900                                 }
901                                 if(st->draw_y==0) {
902                                         for(st->draw_x=0;st->draw_x<8;st->draw_x++) {
903                                                 st->mother->lasers[st->draw_x].active = 1;
904                                                 st->mother->lasers[st->draw_x].start_x=st->mother->new_x+(st->MOTHER_SHIP_WIDTH/2);
905                                                 st->mother->lasers[st->draw_x].start_y=st->mother->y+(st->MOTHER_SHIP_HEIGHT/2);
906                                         }
907                                         st->draw_y = (int)(st->MOTHER_SHIP_LASER/1.5);
908                                         st->mother->lasers[0].end_x=st->mother->lasers[0].start_x-st->MOTHER_SHIP_LASER;
909                                         st->mother->lasers[0].end_y=st->mother->lasers[0].start_y;
910                                         st->mother->lasers[1].end_x=st->mother->lasers[1].start_x-st->draw_y;
911                                         st->mother->lasers[1].end_y=st->mother->lasers[1].start_y-st->draw_y;
912                                         st->mother->lasers[2].end_x=st->mother->lasers[2].start_x;
913                                         st->mother->lasers[2].end_y=st->mother->lasers[2].start_y-st->MOTHER_SHIP_LASER;
914                                         st->mother->lasers[3].end_x=st->mother->lasers[3].start_x+st->draw_y;
915                                         st->mother->lasers[3].end_y=st->mother->lasers[3].start_y-st->draw_y;
916                                         st->mother->lasers[4].end_x=st->mother->lasers[4].start_x+st->MOTHER_SHIP_LASER;
917                                         st->mother->lasers[4].end_y=st->mother->lasers[4].start_y;
918                                         st->mother->lasers[5].end_x=st->mother->lasers[5].start_x+st->draw_y;
919                                         st->mother->lasers[5].end_y=st->mother->lasers[5].start_y+st->draw_y;
920                                         st->mother->lasers[6].end_x=st->mother->lasers[6].start_x;
921                                         st->mother->lasers[6].end_y=st->mother->lasers[6].start_y+st->MOTHER_SHIP_LASER;
922                                         st->mother->lasers[7].end_x=st->mother->lasers[7].start_x-st->draw_y;
923                                         st->mother->lasers[7].end_y=st->mother->lasers[7].start_y+st->draw_y;
924                                 }
925                         }
926                 }
927                 draw_robots(st);
928
929     return st->delay;
930 }
931
932 static void *
933 blaster_init (Display *d, Window w)
934 {
935   struct state *st = (struct state *) calloc (1, sizeof(*st));
936         XGCValues gcv;
937         Colormap cmap;
938         unsigned long bg;
939
940         st->dpy = d;
941         st->window = w;
942         XGetWindowAttributes(st->dpy, st->window, &st->xgwa);
943         cmap = st->xgwa.colormap;
944
945   st->NUM_ROBOTS=5;
946   st->NUM_LASERS=3;
947
948   st->MOTHER_SHIP_WIDTH=25;
949   st->MOTHER_SHIP_HEIGHT=7;
950   st->MOTHER_SHIP_LASER=15;
951   st->MOTHER_SHIP_PERIOD=150;
952   st->MOTHER_SHIP_HITS=10;
953
954   st->RANDOM_MOVE_STYLE=1;
955   st->NUM_MOVE_STYLES=2;
956
957   st->EXPLODE_SIZE_1=27;
958   st->EXPLODE_SIZE_2=19;
959   st->EXPLODE_SIZE_3=7;
960
961
962         st->delay = get_integer_resource(st->dpy, "delay", "Integer");
963         if(st->delay==0) {
964                 st->delay=10000;
965         }
966         st->NUM_ROBOTS = get_integer_resource(st->dpy, "num_robots","Integer");
967         if(st->NUM_ROBOTS==0) {
968                 st->NUM_ROBOTS=5;
969         }
970         st->NUM_LASERS = get_integer_resource(st->dpy, "num_lasers","Integer");
971         st->EXPLODE_SIZE_1 = get_integer_resource(st->dpy, "explode_size_1","Integer");
972         st->EXPLODE_SIZE_2 = get_integer_resource(st->dpy, "explode_size_2","Integer");
973         st->EXPLODE_SIZE_3 = get_integer_resource(st->dpy, "explode_size_3","Integer");
974
975         st->NUM_STARS = get_integer_resource(st->dpy, "num_stars","Integer");
976         if(get_boolean_resource(st->dpy, "move_stars","Boolean")) {
977                 st->MOVE_STARS = 1;
978                 st->MOVE_STARS_X = get_integer_resource(st->dpy, "move_stars_x","Integer");
979                 st->MOVE_STARS_Y = get_integer_resource(st->dpy, "move_stars_y","Integer");
980                 st->MOVE_STARS_RANDOM = get_integer_resource(st->dpy, "move_stars_random","Integer");
981         }
982         else {
983                 st->MOVE_STARS = 0;
984         }
985
986
987         bg = get_pixel_resource(st->dpy, cmap, "background","Background");
988         gcv.function = GXcopy;
989
990 #define make_gc(color,name) \
991         gcv.foreground = get_pixel_resource (st->dpy, cmap, (name), "Foreground"); \
992         color = XCreateGC (st->dpy, st->window, GCForeground|GCFunction, &gcv)
993
994         if(mono_p) {
995                 gcv.foreground = bg;
996                 st->black = XCreateGC(st->dpy, st->window, GCForeground|GCFunction, &gcv);
997                 gcv.foreground = get_pixel_resource(st->dpy, cmap, "foreground", "Foreground");
998                 st->r_color0 = st->r_color1 = st->r_color2 = st->r_color3 = st->r_color4 = st->r_color5 = st->l_color0 = st->l_color1 = st->s_color=
999                         XCreateGC(st->dpy, st->window, GCForeground|GCFunction, &gcv);
1000                 if(get_boolean_resource(st->dpy, "mother_ship","Boolean")) {
1001                         st->MOTHER_SHIP_WIDTH=get_integer_resource(st->dpy, "mother_ship_width","Integer");
1002                         st->MOTHER_SHIP_HEIGHT=get_integer_resource(st->dpy, "mother_ship_height","Integer");
1003                         st->MOTHER_SHIP_LASER=get_integer_resource(st->dpy, "mother_ship_laser","Integer");
1004                         st->MOTHER_SHIP_PERIOD=get_integer_resource(st->dpy, "mother_ship_period","Integer");
1005                         st->MOTHER_SHIP_HITS=get_integer_resource(st->dpy, "mother_ship_hits","Integer");
1006                         st->MOTHER_SHIP=1;
1007                         st->mother = (struct mother_ship_state *) malloc(sizeof(struct mother_ship_state));
1008                         st->mother->lasers = (struct laser_state *) malloc(8*sizeof(struct laser_state));
1009                         st->mother->active = 0;
1010                         st->mother->death = 0;
1011                         st->mother->ship_color = st->r_color0;
1012                         st->mother->laser_color = st->r_color0;
1013                 }
1014         }
1015         else {
1016                 if(get_boolean_resource(st->dpy, "mother_ship","Boolean")) {
1017                         st->MOTHER_SHIP_WIDTH=get_integer_resource(st->dpy, "mother_ship_width","Integer");
1018                         st->MOTHER_SHIP_HEIGHT=get_integer_resource(st->dpy, "mother_ship_height","Integer");
1019                         st->MOTHER_SHIP_LASER=get_integer_resource(st->dpy, "mother_ship_laser","Integer");
1020                         st->MOTHER_SHIP_PERIOD=get_integer_resource(st->dpy, "mother_ship_period","Integer");
1021                         st->MOTHER_SHIP_HITS=get_integer_resource(st->dpy, "mother_ship_hits","Integer");
1022                         st->MOTHER_SHIP=1;
1023                         st->mother = (struct mother_ship_state *) malloc(sizeof(struct mother_ship_state));
1024                         st->mother->lasers = (struct laser_state *) malloc(8*sizeof(struct laser_state));
1025                         st->mother->active = 0;
1026                         st->mother->death = 0;
1027                         make_gc(st->mother->ship_color,"mother_ship_color0");
1028                         make_gc(st->mother->laser_color,"mother_ship_color1");          
1029                 }
1030
1031                 make_gc (st->s_color,"star_color");
1032                 
1033                 make_gc (st->EXPLODE_COLOR_1,"explode_color_1");
1034                 make_gc (st->EXPLODE_COLOR_2,"explode_color_2");
1035                 
1036       make_gc (st->r_color0,"r_color0");
1037       make_gc (st->r_color1,"r_color1");
1038       make_gc (st->r_color2,"r_color2");
1039       make_gc (st->r_color3,"r_color3");
1040       make_gc (st->r_color4,"r_color4");
1041       make_gc (st->r_color5,"r_color5");
1042       make_gc (st->l_color0,"l_color0");
1043       make_gc (st->l_color1,"l_color1");
1044 #ifdef HAVE_COCOA       /* Don't second-guess Quartz's double-buffering */
1045     st->black = 0;
1046 #else
1047                 make_gc (st->black,"background");
1048 #endif
1049         }
1050
1051   return st;
1052 }
1053
1054
1055 static void
1056 blaster_reshape (Display *dpy, Window window, void *closure, 
1057                  unsigned int w, unsigned int h)
1058 {
1059   struct state *st = (struct state *) closure;
1060         XGetWindowAttributes (dpy, window, &st->xgwa);
1061   XClearWindow (dpy, window);
1062   init_stars (st);
1063 }
1064
1065 static Bool
1066 blaster_event (Display *dpy, Window window, void *closure, XEvent *event)
1067 {
1068   return False;
1069 }
1070
1071 static void
1072 blaster_free (Display *dpy, Window window, void *closure)
1073 {
1074   struct state *st = (struct state *) closure;
1075   int i;
1076   if (st->r_color0) XFreeGC (dpy, st->r_color0);
1077   if (st->r_color1) XFreeGC (dpy, st->r_color1);
1078   if (st->r_color2) XFreeGC (dpy, st->r_color2);
1079   if (st->r_color3) XFreeGC (dpy, st->r_color3);
1080   if (st->r_color4) XFreeGC (dpy, st->r_color4);
1081   if (st->r_color5) XFreeGC (dpy, st->r_color5);
1082   if (st->l_color0) XFreeGC (dpy, st->l_color0);
1083   if (st->l_color1) XFreeGC (dpy, st->l_color1);
1084   if (st->s_color)  XFreeGC (dpy, st->s_color);
1085   if (st->black)    XFreeGC (dpy, st->black);
1086   if (st->stars) free (st->stars);
1087   if (st->mother) {
1088     free (st->mother->lasers);
1089     free (st->mother);
1090   }
1091   for (i = 0; i < st->NUM_ROBOTS; i++)
1092     free (st->robots[i].lasers);
1093   free (st->robots);
1094   free (st);
1095 }
1096
1097
1098 static const char *blaster_defaults [] = {
1099   ".background: black",
1100   ".foreground: white",
1101   "*fpsSolid:   true",
1102   "*r_color0:   #FF00FF",
1103   "*r_color1:   #FFA500",
1104   "*r_color2:   #FFFF00",
1105   "*r_color3:   #FFFFFF",
1106   "*r_color4:   #0000FF",
1107   "*r_color5:   #00FFFF",
1108   "*l_color0:   #00FF00",
1109   "*l_color1:   #FF0000",
1110   "*mother_ship_color0: #00008B",
1111   "*mother_ship_color1: #FFFFFF",
1112   "*explode_color_1: #FFFF00",
1113   "*explode_color_2: #FFA500",
1114   "*delay: 10000",
1115   "*num_robots: 5",
1116   "*num_lasers: 3",
1117   "*mother_ship: false",
1118   "*mother_ship_width: 25",
1119   "*mother_ship_height: 7",
1120   "*mother_ship_laser: 15",
1121   "*mother_ship_period: 150",
1122   "*mother_ship_hits: 10",  
1123   "*explode_size_1: 27",
1124   "*explode_size_2: 19",
1125   "*explode_size_3: 7",
1126   "*num_stars: 50",
1127   "*star_color: white",
1128   "*move_stars: true",
1129   "*move_stars_x: 2",
1130   "*move_stars_y: 1",
1131   "*move_stars_random: 0",
1132   0
1133 };
1134
1135 static XrmOptionDescRec blaster_options [] = {
1136         /* These are the 6 robot colors */
1137   { "-r_color0",                ".r_color0",    XrmoptionSepArg, 0 },
1138   { "-r_color1",                ".r_color1",    XrmoptionSepArg, 0 },
1139   { "-r_color2",                ".r_color2",    XrmoptionSepArg, 0 },
1140   { "-r_color3",                ".r_color3",    XrmoptionSepArg, 0 },
1141   { "-r_color4",                ".r_color4",    XrmoptionSepArg, 0 },
1142   { "-r_color5",                ".r_color5",    XrmoptionSepArg, 0 },
1143   /* These are the 2 laser colors that robots have */
1144   { "-l_color0",                ".l_color0",    XrmoptionSepArg, 0 },
1145   { "-l_color1",                ".l_color1",    XrmoptionSepArg, 0 },
1146   /* These are the colors for the mothership and the mothership lasers */
1147   { "-mother_ship_color0",   ".mother_ship_color0",  XrmoptionSepArg, 0},
1148   { "-mother_ship_color1",   ".mother_ship_color1",  XrmoptionSepArg, 0},
1149   /* These are the two colors of the animated explosion */
1150   { "-explode_color_1",  ".explode_color_1",    XrmoptionSepArg, 0 },
1151   { "-explode_color_2",  ".explode_color_2",    XrmoptionSepArg, 0 },
1152   /* This is the delay in the main loop */
1153   { "-delay",           ".delay",       XrmoptionSepArg, 0 },
1154   /* The number of robots and the number of lasers each robot has */
1155   { "-num_robots",   ".num_robots",  XrmoptionSepArg, 0},
1156   { "-num_lasers",   ".num_lasers",  XrmoptionSepArg, 0},
1157   /* If this is set, a mothership will appear, otherwise no mothership */
1158   { "-mother_ship",   ".mother_ship",  XrmoptionNoArg, "true"},
1159   { "-no_mother_ship",   ".mother_ship",  XrmoptionNoArg, "false"},
1160   /* This is the width, height, and laser length of the mothership */
1161   { "-mother_ship_width",   ".mother_ship_width",  XrmoptionSepArg, 0},
1162   { "-mother_ship_height",   ".mother_ship_height",  XrmoptionSepArg, 0},
1163   { "-mother_ship_laser",   ".mother_ship_laser",  XrmoptionSepArg, 0},
1164   /* This is the period which the mothership comes out, higher period==less often */
1165   { "-mother_ship_period",   ".mother_ship_period",  XrmoptionSepArg, 0},
1166   /* This is the number of hits it takes to destroy the mothership */
1167   { "-mother_ship_hits",   ".mother_ship_hits",  XrmoptionSepArg, 0},
1168   /* These are the size of the radius of the animated explosions */
1169   { "-explode_size_1", ".explode_size_1",   XrmoptionSepArg, 0},
1170   { "-explode_size_2", ".explode_size_2",   XrmoptionSepArg, 0},
1171   { "-explode_size_3", ".explode_size_3",   XrmoptionSepArg, 0},
1172   /* This sets the number of stars in the star field, if this is set to 0, there will be no stars */
1173   { "-num_stars", ".num_stars", XrmoptionSepArg, 0},
1174   /* This is the color of the stars */
1175   { "-star_color", ".star_color", XrmoptionSepArg, 0},
1176   /* If this is true, the stars will move */
1177   { "-move_stars", ".move_stars", XrmoptionNoArg, "true"},
1178   /* This is the amount the stars will move in the x and y direction */
1179   { "-move_stars_x", ".move_stars_x", XrmoptionSepArg, 0},
1180   { "-move_stars_y", ".move_stars_y", XrmoptionSepArg, 0},
1181   /* If this is non-zero, the stars will move randomly, but will not move more than this number in 
1182           either the x or y direction */
1183   { "-move_stars_random", ".move_stars_random", XrmoptionSepArg, 0},
1184   { 0, 0, 0, 0 }
1185 };
1186
1187 XSCREENSAVER_MODULE ("Blaster", blaster)