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