1 /* $Id: watcher-below.c,v 1.107 2005/05/03 16:21:43 oohara Exp $ */
2 /* [easy] Watcher Below */
3 
4 #include <stdio.h>
5 /* malloc, rand */
6 #include <stdlib.h>
7 /* strlen, strcmp */
8 #include <string.h>
9 
10 #include "const.h"
11 #include "tenm_object.h"
12 #include "tenm_graphic.h"
13 #include "tenm_primitive.h"
14 #include "util.h"
15 #include "player-shot.h"
16 #include "tenm_table.h"
17 #include "background.h"
18 #include "chain.h"
19 #include "laser.h"
20 #include "normal-shot.h"
21 #include "tenm_math.h"
22 #include "fragment.h"
23 #include "explosion.h"
24 #include "stage-clear.h"
25 #include "score.h"
26 
27 #include "watcher-below.h"
28 
29 #define NEAR_ZERO 0.0001
30 
31 static int watcher_below_move(tenm_object *my, double turn_per_frame);
32 static int watcher_below_hit(tenm_object *my, tenm_object *your);
33 static void watcher_below_next(tenm_object *my);
34 static int watcher_below_signal(tenm_object *my, int n);
35 static int watcher_below_act(tenm_object *my, const tenm_object *player);
36 static int watcher_below_in_territory(double x, double y, double r);
37 static int watcher_below_draw(tenm_object *my, int priority);
38 static int watcher_below_green(const tenm_object *my);
39 
40 static tenm_object *watcher_below_bit_new(double x, double y,
41                                           double speed_x, double speed_y,
42                                           int table_index, int what);
43 static int watcher_below_bit_move(tenm_object *my, double turn_per_frame);
44 static int watcher_below_bit_hit(tenm_object *my, tenm_object *your);
45 static void watcher_below_bit_explode(tenm_object *my);
46 static int watcher_below_bit_signal(tenm_object *my, int n);
47 static int watcher_below_bit_act(tenm_object *my, const tenm_object *player);
48 static int watcher_below_bit_draw(tenm_object *my, int priority);
49 static int watcher_below_bit_green(const tenm_object *my);
50 
51 tenm_object *
watcher_below_new(void)52 watcher_below_new(void)
53 {
54   int i;
55   tenm_primitive **p = NULL;
56   tenm_object *new = NULL;
57   int *count = NULL;
58   double *count_d = NULL;
59   double x = (double) (WINDOW_WIDTH / 2);
60   double y = ((double) (WINDOW_HEIGHT / 2)) + 20.0;
61 
62   p = (tenm_primitive **) malloc(sizeof(tenm_primitive *) * 1);
63   if (p == NULL)
64   {
65     fprintf(stderr, "watcher_below_new: malloc(p) failed\n");
66     return NULL;
67   }
68 
69   p[0] = (tenm_primitive *) tenm_circle_new(x, y, 45.0);
70   if (p[0] == NULL)
71   {
72     fprintf(stderr, "watcher_below_new: cannot set p[0]\n");
73     free(p);
74     return NULL;
75   }
76 
77   count = (int *) malloc(sizeof(int) * 9);
78   if (count == NULL)
79   {
80     fprintf(stderr, "watcher_below_new: malloc(count) failed\n");
81     (p[0])->delete(p[0]);
82     free(p);
83     return NULL;
84   }
85   count_d = (double *) malloc(sizeof(double) * 2);
86   if (count_d == NULL)
87   {
88     fprintf(stderr, "watcher_below_new: malloc(count_d) failed\n");
89     free(count);
90     (p[0])->delete(p[0]);
91     free(p);
92     return NULL;
93   }
94 
95   /* list of count
96    * [0] for deal_damage
97    * [1] "damaged" timer
98    * [2] life mode
99    * [3] life timer
100    * [4] number of bits killed
101    * [5 -- 7] bit index
102    * [8] "was green when killed" flag
103    */
104   /* list of count_d
105    * [0] speed x
106    * [1] speed y
107    */
108 
109   count[0] = 0;
110   count[1] = 0;
111   count[2] = 0;
112   count[3] = 5;
113   count[4] = 0;
114   for (i = 5; i < 8; i++)
115     count[i] = -1;
116   count[8] = 0;
117 
118   count_d[0] = 0.0;
119   count_d[1] = 0.0;
120 
121   new = tenm_object_new("Watcher Below", 0, 0,
122                         600, x, y,
123                         9, count, 2, count_d, 1, p,
124                         (int (*)(tenm_object *, double))
125                         (&watcher_below_move),
126                         (int (*)(tenm_object *, tenm_object *))
127                         (&watcher_below_hit),
128                         (int (*)(tenm_object *, const tenm_object *))
129                         (&watcher_below_act),
130                         (int (*)(tenm_object *, int))
131                         (&watcher_below_draw));
132 
133   if (new == NULL)
134   {
135     fprintf(stderr, "watcher_below_new: tenm_object_new failed\n");
136     if (count_d != NULL)
137       free(count_d);
138     if (count != NULL)
139       free(count);
140     (p[0])->delete(p[0]);
141     free(p);
142     return NULL;
143   }
144 
145   return new;
146 }
147 
148 static int
watcher_below_move(tenm_object * my,double turn_per_frame)149 watcher_below_move(tenm_object *my, double turn_per_frame)
150 {
151   double dx_temp;
152   double dy_temp;
153 
154   /* sanity check */
155   if (my == NULL)
156   {
157     fprintf(stderr, "watcher_below_move: my is NULL\n");
158     return 0;
159   }
160   if (turn_per_frame <= 0.5)
161   {
162     fprintf(stderr, "watcher_below_move: strange turn_per_frame (%f)\n",
163             turn_per_frame);
164     return 0;
165   }
166 
167   dx_temp = my->count_d[0] / turn_per_frame;
168   dy_temp = my->count_d[1] / turn_per_frame;
169   my->x += dx_temp;
170   my->y += dy_temp;
171   if (my->mass != NULL)
172     tenm_move_mass(my->mass, dx_temp, dy_temp);
173 
174   return 0;
175 }
176 
177 static int
watcher_below_hit(tenm_object * my,tenm_object * your)178 watcher_below_hit(tenm_object *my, tenm_object *your)
179 {
180   /* sanity check */
181   if (my == NULL)
182   {
183     fprintf(stderr, "watcher_below_hit: my is NULL\n");
184     return 0;
185   }
186   if (your == NULL)
187   {
188     fprintf(stderr, "watcher_below_hit: your is NULL\n");
189     return 0;
190   }
191 
192   if (!(your->attr & ATTR_PLAYER_SHOT))
193     return 0;
194   if (my->count[2] != 1)
195     return 0;
196 
197   deal_damage(my, your, 0);
198   if (watcher_below_green(my))
199     add_chain(my, your);
200   my->count[1] = 2;
201 
202   if (my->hit_point <= 0)
203   {
204     add_score(10000);
205     set_background(1);
206     watcher_below_next(my);
207     return 0;
208   }
209 
210   return 0;
211 }
212 
213 static void
watcher_below_next(tenm_object * my)214 watcher_below_next(tenm_object *my)
215 {
216   int i;
217   int n;
218 
219   /* sanity check */
220   if (my == NULL)
221   {
222     fprintf(stderr, "watcher_below_next: my is NULL\n");
223     return;
224   }
225 
226   /* set "was green" flag before we change the life mode */
227   if (watcher_below_green(my))
228   {
229     n = 8;
230     my->count[8] = 1;
231   }
232   else
233   {
234     n = 7;
235     my->count[8] = 0;
236   }
237 
238   tenm_table_add(explosion_new(my->x, my->y, 0.0, 0.0,
239                                1, 5000, n, 10.0, 6));
240 
241   tenm_table_apply_all((int (*)(tenm_object *, int)) (&delete_enemy_shot), 0);
242   tenm_table_apply_all((int (*)(tenm_object *, int)) (&delete_enemy), 0);
243 
244   for (i = 5; i < 8; i++)
245     if (my->count[i] >= 0)
246       tenm_table_apply(my->count[i],
247                        (int (*)(tenm_object *, int)) (&watcher_below_signal),
248                        0);
249 
250   my->count[2] = 2;
251   my->count[3] = 0;
252   my->count[1] = 0;
253   my->count_d[0] = 0.0;
254   my->count_d[1] = 0.5;
255 
256   my->attr = ATTR_BOSS;
257   my->hit_mask = ATTR_PLAYER_SHOT;
258   tenm_mass_delete(my->mass);
259   my->mass = NULL;
260 }
261 
262 static int
watcher_below_signal(tenm_object * my,int n)263 watcher_below_signal(tenm_object *my, int n)
264 {
265   /* sanity check */
266   if (my == NULL)
267     return 0;
268   if (strcmp(my->name, "Watcher Below bit") != 0)
269     return 0;
270 
271   /* the explosion should be brown since this is a suicide */
272   my->count[2] = 1;
273   watcher_below_bit_explode(my);
274 
275   return 1;
276 }
277 
278 static int
watcher_below_act(tenm_object * my,const tenm_object * player)279 watcher_below_act(tenm_object *my, const tenm_object *player)
280 {
281   int i;
282   int j;
283   int theta;
284   int dtheta;
285   int direction;
286   double x;
287   double y;
288   double dx;
289   double dy;
290   double result[2];
291   double v[2];
292   double a[2];
293   double temp;
294 
295   /* sanity check */
296   if (my == NULL)
297   {
298     fprintf(stderr, "watcher_below_act: my is NULL\n");
299     return 0;
300   }
301   if (player == NULL)
302     return 0;
303 
304   /* for deal_damage */
305   my->count[0] = 0;
306 
307   /* "damaged" count down */
308   if (my->count[1] > 0)
309     (my->count[1])--;
310 
311   (my->count[3])++;
312 
313   /* dead */
314   if (my->count[2] == 2)
315   {
316     if (watcher_below_green(my))
317       i = 8;
318     else
319       i = 7;
320 
321     if ((my->count[3] >= 30) && (my->count[3] <= 75)
322         && (my->count[3] % 15 == 0))
323     {
324       theta = rand() % 360;
325       tenm_table_add(explosion_new(my->x + 30.0 * tenm_cos(theta),
326                                    my->y + 30.0 * tenm_sin(theta),
327                                    0.0, 0.0,
328                                    2, 300, i, 5.0, 8));
329     }
330 
331     if (my->count[3] > 120)
332     {
333       tenm_table_add(explosion_new(my->x, my->y,
334                                    0.0, 0.0,
335                                    1, 3000, i, 10.0, 8));
336       tenm_table_add(explosion_new(my->x, my->y,
337                                    0.0, 0.0,
338                                    2, 800, i, 6.0, 8));
339 
340       tenm_table_add(stage_clear_new(100));
341       return 1;
342     }
343 
344     return 0;
345   }
346 
347   /* phasing */
348   if (my->count[2] == 1)
349   {
350     if (watcher_below_in_territory(my->x, my->y, 45.0))
351     {
352       my->attr = ATTR_BOSS;
353       my->hit_mask = ATTR_PLAYER_SHOT;
354     }
355     else
356     {
357       my->attr = 0;
358       my->hit_mask = 0;
359     }
360   }
361 
362   /* add bit */
363   if ((my->count[2] == 1) && (my->count[3] >= 180) && (my->count[3] <= 300)
364       && (my->count[3] % 60== 0))
365   {
366     if (my->count[3] == 180)
367       theta = 40;
368     else if (my->count[3] == 240)
369       theta = 155;
370     else
371       theta = 55;
372     x = my->x;
373     y = my->y;
374     if (x - 10.0 < 0.0)
375       x = 10.0;
376     if (x + 10.0 > (double) WINDOW_WIDTH)
377       x = ((double) WINDOW_WIDTH) - 10.0;
378     if (y - 10.0 < 0.0)
379       y = 10.0;
380     if (y + 10.0 > ((double) WINDOW_HEIGHT))
381       y = ((double) WINDOW_HEIGHT) - 10.0;
382     i = 2 + my->count[3] / 60;
383     my->count[i] = tenm_table_add(watcher_below_bit_new(x, y,
384                                                         6.0 * tenm_cos(theta),
385                                                         6.0 * tenm_sin(theta),
386                                                         my->table_index,
387                                                         my->count[3]/60 - 3));
388   }
389 
390   /* move direction change  */
391   v[0] = my->count_d[0];
392   v[1] = my->count_d[1];
393   result[0] = v[0];
394   result[1] = v[1];
395   if ((my->count[2] == 1)
396       && (my->x - 10.0 > 0.0) && (my->x + 10.0 < (double) WINDOW_WIDTH)
397       && (my->y - 10.0 > 0.0)
398       && (my->y + 10.0 < (double) WINDOW_HEIGHT))
399   {
400     if (my->attr != 0)
401     {
402       /* chase player */
403       v[0] = my->count_d[0];
404       v[1] = my->count_d[1];
405       a[0] = player->x - my->x;
406       a[1] = player->y - my->y;
407       result[0] = v[0];
408       result[1] = v[1];
409       vector_rotate_bounded(result, v, a, 1);
410     }
411     else if ((my->count_d[0] > 0.0) && (my->count_d[0] < 1.0))
412     {
413       /* force a good direction */
414       if (my->count_d[1] > 0.0)
415         vector_rotate(result, v, -1);
416       else
417         vector_rotate(result, v, 1);
418     }
419     else if ((my->count_d[0] > -1.0) && (my->count_d[0] < NEAR_ZERO))
420     {
421       if (my->count_d[1] > 0.0)
422         vector_rotate(result, v, 1);
423       else
424         vector_rotate(result, v, -1);
425     }
426     else if ((my->count_d[1] > 0.0) && (my->count_d[1] < 1.0))
427     {
428       if (my->count_d[0] > 0.0)
429         vector_rotate(result, v, 1);
430     else
431       vector_rotate(result, v, -1);
432     }
433     else if ((my->count_d[1] > -1.0) && (my->count_d[1] < NEAR_ZERO))
434     {
435       if (my->count_d[0] > 0.0)
436         vector_rotate(result, v, -1);
437       else
438         vector_rotate(result, v, 1);
439     }
440   }
441   my->count_d[0] = result[0];
442   my->count_d[1] = result[1];
443 
444   /* reflect */
445   if ((my->x < 0.0) || (my->x > (double) WINDOW_WIDTH))
446     my->count_d[0] *= -1.0;
447   if ((my->y < 0.0) || (my->y > (double) WINDOW_HEIGHT))
448     my->count_d[1] *= -1.0;
449 
450   /* encounter */
451   if (my->count[2] == 0)
452   {
453     if (my->count[3] == 45)
454     {
455       my->count_d[0] = 4.0;
456       my->count_d[1] = 3.0;
457     }
458     if (my->count[3] >= 180)
459     {
460       my->count[2] = 1;
461       my->count[3] = 0;
462     }
463     return 0;
464   }
465 
466   /* self-destruction */
467   if ((my->count[2] == 1) && (my->count[3] >= 4130))
468   {
469     set_background(2);
470     clear_chain();
471     watcher_below_next(my);
472     return 0;
473   }
474 
475   /* shoot */
476   if (my->attr == 0)
477     return 0;
478   if (my->count[2] != 1)
479     return 0;
480   if (my->count[3] > 4000)
481     return 0;
482 
483   if (((my->count[4] >= 2) && (my->count[3] % 38 == 0))
484       || ((my->count[4] >= 3) && (my->count[3] % 19 == 0)))
485   {
486     dx = player->x - my->x;
487     dy = player->y - my->y;
488     temp = tenm_sqrt((int) (dx * dx + dy * dy));
489     if (temp < NEAR_ZERO)
490       temp = 1.0;
491     v[0] = dx / temp;
492     v[1] = dy / temp;
493     result[0] = v[0];
494     result[1] = v[1];
495     if (my->count[3] % 38 == 0)
496       vector_rotate(result, v, (60 + rand() % 61) * (2 * (rand() % 2) - 1));
497     dx = result[0];
498     dy = result[1];
499 
500     theta = rand() % 360;
501     if (rand() % 2)
502       direction = 1;
503     else
504       direction = -1;
505     if (rand() % 2)
506     {
507       for (i = 0; i < 3; i++)
508         for (j = 0; j < 4; j++)
509         {
510           dtheta = (i * 120 + j * 30) * direction;
511           x = my->x + 40.0 * tenm_cos(theta + dtheta);
512           y = my->y + 40.0 * tenm_sin(theta + dtheta);
513           dx = 4.0 * result[0];
514           dy = 4.0 * result[1];
515           dx -= 0.6 * ((double) (j + 1)) * tenm_cos(theta + dtheta);
516           dy -= 0.6 * ((double) (j + 1)) * tenm_sin(theta + dtheta);
517           tenm_table_add(normal_shot_new(x, y, dx, dy, 1, -2, 0));
518         }
519     }
520     else
521     {
522       for (i = 0; i < 6; i++)
523         for (j = 0; j < 2; j++)
524         {
525 
526           dtheta = i * 60 + j * 30;
527           if (j == 0)
528           {
529             x = my->x + 40.0 * tenm_cos(theta + dtheta);
530             y = my->y + 40.0 * tenm_sin(theta + dtheta);
531             dx = 3.0 * result[0];
532             dy = 3.0 * result[1];
533             dx -= 1.0 * tenm_cos(theta + dtheta);
534             dy -= 1.0 * tenm_sin(theta + dtheta);
535           }
536           else
537           {
538             x = my->x;
539             y = my->y;
540             dx = 3.0 * result[0];
541             dy = 3.0 * result[1];
542             dx += 1.0 * tenm_cos(theta + dtheta);
543             dy += 1.0 * tenm_sin(theta + dtheta);
544           }
545           tenm_table_add(normal_shot_new(x, y, dx, dy, 2, -2, 0));
546         }
547     }
548   }
549 
550   if ((my->count[4] >= 1) && (my->count[3] % 11 == 0))
551   {
552     dx = my->count_d[0];
553     dy = my->count_d[1];
554     temp = tenm_sqrt((int) (dx * dx + dy * dy));
555     if (temp < NEAR_ZERO)
556       temp = 1.0;
557     v[0] = dx / temp;
558     v[1] = dy / temp;
559     for (i = -1; i <= 1; i += 2)
560     {
561       result[0] = v[0];
562       result[1] = v[1];
563       vector_rotate(result, v, 120 * i);
564       tenm_table_add(laser_new(my->x, my->y,
565                                7.5 * result[0], 7.5 * result[1],
566                                30.0 * result[0], 30.0 * result[1],
567                                4, -2, 0));
568     }
569   }
570 
571   return 0;
572 }
573 
574 /* return 1 (true) or 0 (false) */
575 static int
watcher_below_in_territory(double x,double y,double r)576 watcher_below_in_territory(double x, double y, double r)
577 {
578   double x1;
579   double y1;
580 
581   /* sanity check */
582   if (r < NEAR_ZERO)
583   {
584     fprintf(stderr, "watcher_below_in_territory: r is non-positive (%f)\n", r);
585     return 0;
586   }
587 
588   x1 = (x - (double) (WINDOW_WIDTH / 2)) * 7.0 / tenm_sqrt(50)
589     + (y - (double) (WINDOW_HEIGHT / 2)) * (-1.0) / tenm_sqrt(50);
590   y1 = -(x - (double) (WINDOW_WIDTH / 2)) * (-1.0) / tenm_sqrt(50)
591     + (y - (double) (WINDOW_HEIGHT / 2)) * 7.0 / tenm_sqrt(50);
592 
593   if ((x1 - r > -212.1320) && (x1 + r < 212.1320)
594       && (y1 - r > -212.1320) && (y1 + r < 212.1320))
595     return 1;
596 
597   return 0;
598 }
599 
600 static int
watcher_below_draw(tenm_object * my,int priority)601 watcher_below_draw(tenm_object *my, int priority)
602 {
603   int status = 0;
604   tenm_color color;
605   char temp[32];
606   int width;
607   int r;
608   int c;
609 
610   /* sanity check */
611   if (my == NULL)
612   {
613     fprintf(stderr, "watcher_below_draw: my is NULL\n");
614     return 0;
615   }
616 
617   /* territory */
618   if ((priority == -1)
619       && (((my->count[2] == 0) && (my->count[3] >= 90))
620           || (my->count[2] == 1)))
621   {
622     c = 0;
623     color = tenm_map_color(182, 147, 123);
624     if (my->count[2] == 0)
625     {
626       color = tenm_map_color(158, 158, 158);
627       c = 180 - my->count[3];
628       if (c < 0)
629         c = 0;
630       if (c > 90)
631         c = 90;
632     }
633 
634     if (tenm_draw_line((500 * (90 - c) + WINDOW_WIDTH * c) / 90,
635                        (0 * (90 - c) + 0 * c) / 90,
636                        (560 * (90 - c) + WINDOW_WIDTH * c) / 90,
637                        (420 * (90 - c) + WINDOW_HEIGHT * c) / 90,
638                        1, color) != 0)
639       status = 1;
640     if (tenm_draw_line((560 * (90 - c) + WINDOW_WIDTH * c) / 90,
641                        (420 * (90 - c) + WINDOW_HEIGHT * c) / 90,
642                        (140 * (90 - c) + 0 * c) / 90,
643                        (480 * (90 - c) + WINDOW_HEIGHT * c) / 90,
644                        1, color) != 0)
645       status = 1;
646     if (tenm_draw_line((140 * (90 - c) + 0 * c) / 90,
647                        (480 * (90 - c) + WINDOW_HEIGHT * c) / 90,
648                        (80 * (90 - c) + 0 * c) / 90,
649                        (60 * (90 - c) + 0 * c) / 90,
650                        1, color) != 0)
651       status = 1;
652     if (tenm_draw_line((80 * (90 - c) + 0 * c) / 90,
653                        (60 * (90 - c) + 0 * c) / 90,
654                        (500 * (90 - c) + WINDOW_WIDTH * c) / 90,
655                        (0 * (90 - c) + 0 * c) / 90,
656                        1, color) != 0)
657       status = 1;
658   }
659 
660   /* body */
661   /* dead enemy has low priority */
662   if (((my->count[2] <= 1) && (priority == 0))
663       || ((my->count[2] > 1) && (priority == -1)))
664   {
665     if (watcher_below_green(my))
666     {
667       if (my->count[1] >= 1)
668         color = tenm_map_color(109, 125, 9);
669       else
670         color = tenm_map_color(61, 95, 13);
671     }
672     else
673     {
674       if (my->count[1] >= 1)
675         color = tenm_map_color(135, 89, 9);
676       else
677         color = tenm_map_color(95, 47, 13);
678     }
679 
680     if (my->attr != 0)
681       width = 3;
682     else
683       width = 1;
684 
685     r = 45;
686     if (my->count[2] == 0)
687     {
688       r = my->count[3];
689       if (r < 5)
690         r = 5;
691       if (r > 45)
692         r = 45;
693     }
694 
695     if (tenm_draw_circle((int) (my->x), (int) (my->y), r, width, color) != 0)
696       status = 1;
697   }
698 
699   /* hit point stat */
700   if ((priority == 0) && (my->count[2] == 1))
701   {
702     sprintf(temp, "%d", my->hit_point);
703     if (draw_string(((int) my->x) - 10, (int) my->y,
704                     temp, (int) strlen(temp)) != 0)
705     {
706       fprintf(stderr, "watcher_below_draw: draw_string failed\n");
707       status = 1;
708     }
709   }
710 
711   return status;
712 }
713 
714 /* return 1 (true) or 0 (false) */
715 static int
watcher_below_green(const tenm_object * my)716 watcher_below_green(const tenm_object *my)
717 {
718   /* sanity check */
719   if (my == NULL)
720     return 0;
721 
722   if ((my->count[2] == 1) && (my->count[4] >= 3)
723       && (my->count[3] <= 4100))
724     return 1;
725   if ((my->count[2] == 2) && (my->count[8] != 0))
726     return 1;
727 
728   return 0;
729 }
730 
731 static tenm_object *
watcher_below_bit_new(double x,double y,double speed_x,double speed_y,int table_index,int what)732 watcher_below_bit_new(double x, double y,
733                       double speed_x, double speed_y,
734                       int table_index, int what)
735 {
736   tenm_primitive **p = NULL;
737   tenm_object *new = NULL;
738   int *count = NULL;
739   double *count_d = NULL;
740   int attr;
741   int hit_mask;
742 
743   /* sanity check */
744   if (speed_x * speed_x + speed_y * speed_y < NEAR_ZERO)
745   {
746     fprintf(stderr, "watcher_below_bit_new: speed is too small (%f, %f)\n",
747             speed_x, speed_y);
748     return NULL;
749   }
750   if (table_index < 0)
751   {
752     fprintf(stderr, "watcher_below_bit_new: table_index is negative (%d)\n",
753             table_index);
754     return NULL;
755   }
756 
757   p = (tenm_primitive **) malloc(sizeof(tenm_primitive *) * 1);
758   if (p == NULL)
759   {
760     fprintf(stderr, "watcher_below_bit_new: malloc(p) failed\n");
761     return NULL;
762   }
763 
764   p[0] = (tenm_primitive *) tenm_circle_new(x, y, 25.0);
765   if (p[0] == NULL)
766   {
767     fprintf(stderr, "watcher_below_bit_new: cannot set p[0]\n");
768     free(p);
769     return NULL;
770   }
771 
772   count = (int *) malloc(sizeof(int) * 6);
773   if (count == NULL)
774   {
775     fprintf(stderr, "watcher_below_bit_new: malloc(count) failed\n");
776     (p[0])->delete(p[0]);
777     free(p);
778     return NULL;
779   }
780   count_d = (double *) malloc(sizeof(double) * 2);
781   if (count_d == NULL)
782   {
783     fprintf(stderr, "watcher_below_bit_new: malloc(count_d) failed\n");
784     free(count);
785     (p[0])->delete(p[0]);
786     free(p);
787     return NULL;
788   }
789 
790   if (watcher_below_in_territory(x, y, 25.0))
791   {
792     attr = ATTR_BOSS;
793     hit_mask = ATTR_PLAYER_SHOT;
794   }
795   else
796   {
797     attr = 0;
798     hit_mask = 0;
799   }
800 
801   /* list of count
802    * [0] for deal_damage
803    * [1] "damaged" timer
804    * [2] life mode
805    * [3] life timer
806    * [4] core index
807    * [5] what
808    */
809   /* list of count_d
810    * [0] speed x
811    * [1] speed y
812    */
813 
814   count[0] = 0;
815   count[1] = 0;
816   count[2] = 0;
817   count[3] = 0;
818   count[4] = table_index;
819   count[5] = what;
820 
821   count_d[0] = speed_x;
822   count_d[1] = speed_y;
823 
824   new = tenm_object_new("Watcher Below bit", attr, hit_mask,
825                         200, x, y,
826                         6, count, 2, count_d, 1, p,
827                         (int (*)(tenm_object *, double))
828                         (&watcher_below_bit_move),
829                         (int (*)(tenm_object *, tenm_object *))
830                         (&watcher_below_bit_hit),
831                         (int (*)(tenm_object *, const tenm_object *))
832                         (&watcher_below_bit_act),
833                         (int (*)(tenm_object *, int))
834                         (&watcher_below_bit_draw));
835 
836   if (new == NULL)
837   {
838     fprintf(stderr, "watcher_below_bit_new: tenm_object_new failed\n");
839     if (count_d != NULL)
840       free(count_d);
841     if (count != NULL)
842       free(count);
843     (p[0])->delete(p[0]);
844     free(p);
845     return NULL;
846   }
847 
848   return new;
849 }
850 
851 static int
watcher_below_bit_move(tenm_object * my,double turn_per_frame)852 watcher_below_bit_move(tenm_object *my, double turn_per_frame)
853 {
854   double dx_temp;
855   double dy_temp;
856 
857   /* sanity check */
858   if (my == NULL)
859   {
860     fprintf(stderr, "watcher_below_bit_move: my is NULL\n");
861     return 0;
862   }
863   if (turn_per_frame <= 0.5)
864   {
865     fprintf(stderr, "watcher_below_bit_move: strange turn_per_frame (%f)\n",
866             turn_per_frame);
867     return 0;
868   }
869 
870   dx_temp = my->count_d[0] / turn_per_frame;
871   dy_temp = my->count_d[1] / turn_per_frame;
872   my->x += dx_temp;
873   my->y += dy_temp;
874   if (my->mass != NULL)
875     tenm_move_mass(my->mass, dx_temp, dy_temp);
876 
877   return 0;
878 }
879 
880 static int
watcher_below_bit_hit(tenm_object * my,tenm_object * your)881 watcher_below_bit_hit(tenm_object *my, tenm_object *your)
882 {
883   /* sanity check */
884   if (my == NULL)
885   {
886     fprintf(stderr, "watcher_below_bit_hit: my is NULL\n");
887     return 0;
888   }
889   if (your == NULL)
890   {
891     fprintf(stderr, "watcher_below_bit_hit: your is NULL\n");
892     return 0;
893   }
894 
895   if (!(your->attr & ATTR_PLAYER_SHOT))
896     return 0;
897 
898   deal_damage(my, your, 0);
899   if (watcher_below_bit_green(my))
900     add_chain(my, your);
901   my->count[1] = 41;
902 
903   if (my->hit_point <= 0)
904   {
905     add_score(7500);
906     watcher_below_bit_explode(my);
907     tenm_table_apply(my->count[4],
908                      (int (*)(tenm_object *, int)) (&watcher_below_bit_signal),
909                      my->table_index);
910     return 1;
911   }
912 
913   return 0;
914 }
915 
916 static void
watcher_below_bit_explode(tenm_object * my)917 watcher_below_bit_explode(tenm_object *my)
918 {
919   int n;
920 
921   /* sanity check */
922   if (my == NULL)
923   {
924     fprintf(stderr, "watcher_below_bit_explode: my is NULL\n");
925     return;
926   }
927 
928   if (watcher_below_bit_green(my))
929     n = 8;
930   else
931     n = 7;
932 
933   tenm_table_add(explosion_new(my->x, my->y,
934                                my->count_d[0] * 0.5,
935                                my->count_d[1] * 0.5,
936                                1, 1000, n, 8.0, 6));
937   tenm_table_add(explosion_new(my->x, my->y,
938                                my->count_d[0] * 0.5,
939                                my->count_d[1] * 0.5,
940                                2, 300, n, 5.0, 8));
941 }
942 
943 static int
watcher_below_bit_signal(tenm_object * my,int n)944 watcher_below_bit_signal(tenm_object *my, int n)
945 {
946   int i;
947 
948   /* sanity check */
949   if (my == NULL)
950     return 0;
951   if (strcmp(my->name, "Watcher Below") != 0)
952     return 0;
953 
954   (my->count[4])++;
955   for (i = 5; i < 8; i++)
956     if (my->count[i] == n)
957       my->count[i] = -1;
958 
959   return 0;
960 }
961 
962 static int
watcher_below_bit_act(tenm_object * my,const tenm_object * player)963 watcher_below_bit_act(tenm_object *my, const tenm_object *player)
964 {
965   int i;
966   double dx;
967   double dy;
968   double result[2];
969   double v[2];
970   double temp;
971 
972   /* sanity check */
973   if (my == NULL)
974   {
975     fprintf(stderr, "watcher_below_bit_act: my is NULL\n");
976     return 0;
977   }
978   if (player == NULL)
979     return 0;
980 
981   /* for deal_damage */
982   my->count[0] = 0;
983 
984   /* "damaged" count down */
985   if (my->count[1] > 0)
986     (my->count[1])--;
987 
988   (my->count[3])++;
989 
990   /* phasing */
991   if (watcher_below_in_territory(my->x, my->y, 25.0))
992   {
993     my->attr = ATTR_BOSS;
994     my->hit_mask = ATTR_PLAYER_SHOT;
995   }
996   else
997   {
998     my->attr = 0;
999     my->hit_mask = 0;
1000   }
1001 
1002   /* reflect */
1003   if ((my->x < 0.0) || (my->x > (double) WINDOW_WIDTH))
1004     my->count_d[0] *= -1.0;
1005   if ((my->y < 0.0) || (my->y > (double) WINDOW_HEIGHT))
1006     my->count_d[1] *= -1.0;
1007 
1008   /* shoot */
1009   if (my->attr == 0)
1010     return 0;
1011   if (my->count[2] != 0)
1012     return 0;
1013   if ((my->count[3] < 100) || (my->count[3] > 4000 - (my->count[5]*60 + 180)))
1014     return 0;
1015 
1016   if (my->count[3] % 11 == 0)
1017   {
1018     dx = my->count_d[0];
1019     dy = my->count_d[1];
1020     temp = tenm_sqrt((int) (dx * dx + dy * dy));
1021     if (temp < NEAR_ZERO)
1022       temp = 1.0;
1023     v[0] = dx / temp;
1024     v[1] = dy / temp;
1025     for (i = -1; i <= 1; i += 2)
1026     {
1027       result[0] = v[0];
1028       result[1] = v[1];
1029       vector_rotate(result, v, 120 * i);
1030       tenm_table_add(laser_new(my->x, my->y,
1031                                4.5 * result[0], 4.5 * result[1],
1032                                25.0 * result[0], 25.0 * result[1],
1033                                3, -2, 0));
1034     }
1035   }
1036 
1037   if (my->count[3] % 17 == 0)
1038   {
1039     tenm_table_add(normal_shot_point_new(my->x, my->y, 3.5,
1040                                          player->x, player->y,
1041                                          5));
1042   }
1043 
1044   return 0;
1045 }
1046 
1047 static int
watcher_below_bit_draw(tenm_object * my,int priority)1048 watcher_below_bit_draw(tenm_object *my, int priority)
1049 {
1050   int status = 0;
1051   tenm_color color;
1052   char temp[32];
1053   int width;
1054 
1055   /* sanity check */
1056   if (my == NULL)
1057   {
1058     fprintf(stderr, "watcher_below_bit_draw: my is NULL\n");
1059     return 0;
1060   }
1061 
1062   /* decoration */
1063   if ((priority == 0) && (my->count[2] <= 1))
1064   {
1065     if (watcher_below_bit_green(my))
1066     {
1067       if (my->count[1] >= 40)
1068         color = tenm_map_color(181, 190, 92);
1069       else
1070         color = tenm_map_color(157, 182, 123);
1071     }
1072     else
1073     {
1074       if (my->count[1] >= 40)
1075         color = tenm_map_color(200, 164, 92);
1076       else
1077         color = tenm_map_color(182, 147, 123);
1078     }
1079   }
1080 
1081   /* body */
1082   if (priority == 0)
1083   {
1084     if (watcher_below_bit_green(my))
1085     {
1086       if (my->count[1] >= 1)
1087         color = tenm_map_color(109, 125, 9);
1088       else
1089         color = tenm_map_color(61, 95, 13);
1090     }
1091     else
1092     {
1093       if (my->count[1] >= 1)
1094         color = tenm_map_color(135, 89, 9);
1095       else
1096         color = tenm_map_color(95, 47, 13);
1097     }
1098 
1099     if (my->attr != 0)
1100       width = 3;
1101     else
1102       width = 1;
1103 
1104     if (tenm_draw_circle((int) (my->x), (int) (my->y), 25, width, color) != 0)
1105       status = 1;
1106   }
1107 
1108   /* hit point stat */
1109   if ((priority == 0) && (my->count[1] >= 1))
1110   {
1111     sprintf(temp, "%d", my->hit_point);
1112     if (draw_string(((int) my->x) - 10, (int) my->y,
1113                     temp, (int) strlen(temp)) != 0)
1114     {
1115       fprintf(stderr, "watcher_below_bit_draw: draw_string failed\n");
1116       status = 1;
1117     }
1118   }
1119 
1120   return status;
1121 }
1122 
1123 /* return 1 (true) or 0 (false) */
1124 static int
watcher_below_bit_green(const tenm_object * my)1125 watcher_below_bit_green(const tenm_object *my)
1126 {
1127   /* sanity check */
1128   if (my == NULL)
1129     return 0;
1130 
1131   if ((my->count[2] == 0)
1132       && (my->count[3] >= 100)
1133       && (my->count[3] <= 4100 - (my->count[5] * 60 + 180)))
1134     return 1;
1135 
1136   return 0;
1137 }
1138