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