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