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