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