1 /* $Id: mankanshoku.c,v 1.95 2005/01/06 06:16:42 oohara Exp $ */
2 
3 #include <stdio.h>
4 /* malloc, rand */
5 #include <stdlib.h>
6 /* strlen, strcmp */
7 #include <string.h>
8 
9 #include "const.h"
10 #include "tenm_object.h"
11 #include "tenm_graphic.h"
12 #include "tenm_primitive.h"
13 #include "util.h"
14 #include "player-shot.h"
15 #include "tenm_table.h"
16 #include "background.h"
17 #include "chain.h"
18 #include "laser.h"
19 #include "normal-shot.h"
20 #include "tenm_math.h"
21 #include "fragment.h"
22 #include "explosion.h"
23 #include "normal-enemy.h"
24 #include "score.h"
25 #include "wall-8.h"
26 #include "silver-chimera.h"
27 #include "warning.h"
28 
29 #include "mankanshoku.h"
30 
31 static int mankanshoku_move(tenm_object *my, double turn_per_frame);
32 static int mankanshoku_hit(tenm_object *my, tenm_object *your);
33 static void mankanshoku_next(tenm_object *my);
34 static int mankanshoku_act(tenm_object *my, const tenm_object *player);
35 static int mankanshoku_draw(tenm_object *my, int priority);
36 static int mankanshoku_green(const tenm_object *my);
37 
38 tenm_object *
mankanshoku_new(void)39 mankanshoku_new(void)
40 {
41   tenm_primitive **p = NULL;
42   tenm_object *new = NULL;
43   int *count = NULL;
44   double *count_d = NULL;
45   double x = (double) (WINDOW_WIDTH / 2);
46   double y = -255.0;
47 
48   p = (tenm_primitive **) malloc(sizeof(tenm_primitive *) * 1);
49   if (p == NULL)
50   {
51     fprintf(stderr, "mankanshoku_new: malloc(p) failed\n");
52     return NULL;
53   }
54 
55   p[0] = (tenm_primitive *) tenm_polygon_new(8,
56                                              x + 60.0, y - 15.0,
57                                              x + 60.0, y + 15.0,
58                                              x + 50.0, y + 25.0,
59                                              x - 50.0, y + 25.0,
60                                              x - 60.0, y + 15.0,
61                                              x - 60.0, y - 15.0,
62                                              x - 50.0, y - 25.0,
63                                              x + 50.0, y - 25.0);
64   if (p[0] == NULL)
65   {
66     fprintf(stderr, "mankanshoku_new: cannot set p[0]\n");
67     free(p);
68     return NULL;
69   }
70 
71   count = (int *) malloc(sizeof(int) * 7);
72   if (count == NULL)
73   {
74     fprintf(stderr, "mankanshoku_new: malloc(count) failed\n");
75     (p[0])->delete(p[0]);
76     free(p);
77     return NULL;
78   }
79   count_d = (double *) malloc(sizeof(double) * 3);
80   if (count_d == NULL)
81   {
82     fprintf(stderr, "mankanshoku_new: malloc(count_d) failed\n");
83     free(count);
84     (p[0])->delete(p[0]);
85     free(p);
86     return NULL;
87   }
88 
89   /* list of count
90    * [0] for deal_damage
91    * [1] "damaged" timer
92    * [2] life mode
93    * [3] life timer
94    * [4] the time when we escaped / were killed
95    * [5] add enemy mode
96    * [6] add enemy timer
97    */
98   /* list of count_d
99    * [0] speed x
100    * [1] speed y
101    */
102 
103   count[0] = 0;
104   count[1] = 0;
105   count[2] = 0;
106   count[3] = 0;
107   count[4] = 0;
108   count[5] = (rand() % 2) * 3;
109   count[6] = 0;
110 
111   count_d[0] = 0.0;
112   count_d[1] = 7.5;
113 
114   new = tenm_object_new("Mankanshoku", ATTR_ENEMY | ATTR_OBSTACLE,
115                         ATTR_PLAYER_SHOT,
116                         750, x, y,
117                         7, count, 3, count_d, 1, p,
118                         (int (*)(tenm_object *, double))
119                         (&mankanshoku_move),
120                         (int (*)(tenm_object *, tenm_object *))
121                         (&mankanshoku_hit),
122                         (int (*)(tenm_object *, const tenm_object *))
123                         (&mankanshoku_act),
124                         (int (*)(tenm_object *, int))
125                         (&mankanshoku_draw));
126 
127   if (new == NULL)
128   {
129     fprintf(stderr, "mankanshoku_new: tenm_object_new failed\n");
130     if (count_d != NULL)
131       free(count_d);
132     if (count != NULL)
133       free(count);
134     (p[0])->delete(p[0]);
135     free(p);
136     return NULL;
137   }
138 
139   return new;
140 }
141 
142 static int
mankanshoku_move(tenm_object * my,double turn_per_frame)143 mankanshoku_move(tenm_object *my, double turn_per_frame)
144 {
145   double dx_temp;
146   double dy_temp;
147 
148   /* sanity check */
149   if (my == NULL)
150   {
151     fprintf(stderr, "mankanshoku_move: my is NULL\n");
152     return 0;
153   }
154   if (turn_per_frame <= 0.5)
155   {
156     fprintf(stderr, "mankanshoku_move: strange turn_per_frame (%f)\n",
157             turn_per_frame);
158     return 0;
159   }
160 
161   if (my->count[2] != 0)
162     return 0;
163 
164   dx_temp = my->count_d[0] / turn_per_frame;
165   dy_temp = my->count_d[1] / turn_per_frame;
166   my->x += dx_temp;
167   my->y += dy_temp;
168   if (my->mass != NULL)
169     tenm_move_mass(my->mass, dx_temp, dy_temp);
170 
171   if ((my->count[3] >= 2344) && (my->y > ((double) WINDOW_HEIGHT) + 120.0))
172     mankanshoku_next(my);
173 
174   return 0;
175 }
176 
177 static int
mankanshoku_hit(tenm_object * my,tenm_object * your)178 mankanshoku_hit(tenm_object *my, tenm_object *your)
179 {
180   int n;
181 
182   /* sanity check */
183   if (my == NULL)
184   {
185     fprintf(stderr, "mankanshoku_hit: my is NULL\n");
186     return 0;
187   }
188   if (your == NULL)
189   {
190     fprintf(stderr, "mankanshoku_hit: your is NULL\n");
191     return 0;
192   }
193 
194   if (my->count[2] != 0)
195     return 0;
196   if (!(your->attr & ATTR_PLAYER_SHOT))
197     return 0;
198 
199   deal_damage(my, your, 0);
200   if (mankanshoku_green(my))
201     add_chain(my, your);
202   my->count[1] = 41;
203 
204   if (my->hit_point <= 0)
205   {
206     add_score(100);
207 
208     if (mankanshoku_green(my))
209       n = 8;
210     else
211       n = 7;
212     tenm_table_add(explosion_new(my->x, my->y,
213                                  my->count_d[0] * 0.5,
214                                  my->count_d[1] * 0.5,
215                                  1, 1000, n, 8.0, 6));
216     tenm_table_add(fragment_new(my->x, my->y,
217                                 my->count_d[0] * 0.5, my->count_d[1] * 0.5,
218                                 30.0, 30, n, 5.0, 0.0, 20));
219 
220     mankanshoku_next(my);
221     return 0;
222   }
223 
224   return 0;
225 }
226 
227 static void
mankanshoku_next(tenm_object * my)228 mankanshoku_next(tenm_object *my)
229 {
230   /* sanity check */
231   if (my == NULL)
232     return;
233 
234   /* no explosion here --- this is called when we escape
235    * as well as we are killed
236    */
237   my->count[2] = 1;
238   my->count[4] = my->count[3];
239   if (my->count[4] < 1082)
240     my->count[4] = 1082;
241   my->count[1] = 0;
242 
243   /* don't modify my->attr or my->hit_mask here, or the player shot
244    * may fly through the enemy */
245   tenm_mass_delete(my->mass);
246   my->mass = NULL;
247 }
248 
249 static int
mankanshoku_act(tenm_object * my,const tenm_object * player)250 mankanshoku_act(tenm_object *my, const tenm_object *player)
251 {
252   int i;
253   int t;
254   int theta1;
255   int theta2;
256   int temp;
257   double speed;
258   double dx;
259   double dy;
260   double result[2];
261   double v[2];
262   double x;
263 
264   /* sanity check */
265   if (my == NULL)
266   {
267     fprintf(stderr, "mankanshoku_act: my is NULL\n");
268     return 0;
269   }
270   if (player == NULL)
271     return 0;
272 
273   /* for deal_damage */
274   my->count[0] = 0;
275 
276   /* "damaged" count down */
277   if (my->count[1] > 0)
278     (my->count[1])--;
279 
280   (my->count[3])++;
281 
282   /* dead / escaped */
283   if (my->count[2] == 1)
284   {
285     if (my->count[3] == my->count[4] + 160)
286       tenm_table_add(warning_new());
287 
288     if (my->count[3] == my->count[4] + 290)
289     {
290       tenm_table_add(silver_chimera_new());
291       return 1;
292     }
293   }
294 
295   /* move */
296   if (my->count[3] < 75)
297     my->count_d[1] = 7.5 - ((double) (my->count[3])) * 0.1;
298   else if (my->count[3] < 1032)
299     my->count_d[1] = 0.0;
300   else if (my->count[3] < 1082)
301     my->count_d[1] = ((double) (my->count[3] - 1032)) * 0.1;
302   else if (my->count[3] < 1187)
303     my->count_d[1] = 5.0 - ((double) (my->count[3] - 1082)) * 0.1;
304   else if (my->count[3] < 2344)
305     my->count_d[1] = 0.0;
306   else
307     my->count_d[1] = 7.5;
308 
309   /* add wall */
310   if ((my->count[3] >= 1133) && (my->count[3] < 9999)
311       && ((my->count[2] == 0) || (my->count[3] < my->count[4] + 72))
312       && ((my->count[3] - 1133) % 24 == 0))
313   {
314     tenm_table_add(wall_8_new(30.0, -29.0, 0, my->count[3] + 2458));
315     tenm_table_add(wall_8_new(((double) WINDOW_WIDTH) - 30.0, -29.0, 0,
316                               my->count[3] + 2458));
317   }
318 
319   t = my->count[3] - 1187;
320   if (t < 0)
321     return 0;
322 
323   /* chase the player */
324   if (player->x < 220.0)
325     x = 120.0;
326   else if (player->x < 420.0)
327     x = 320.0;
328   else
329     x = 520.0;
330 
331   if ((my->x + 10.0 > x) && (my->x - 10.0 < x))
332     my->count_d[0] = x - my->x;
333   else if (my->x < x)
334     my->count_d[0] = 10.0;
335   else
336     my->count_d[0] = -10.0;
337   if (my->x + my->count_d[0] < 120.0)
338     my->count_d[0] = 120.0 - my->x;
339   if (my->x + my->count_d[0] > 520.0)
340     my->count_d[0] = 520.0 - my->x;
341   if (t >= 1058)
342     my->count_d[0] = 0.0;
343 
344   /* add normal enemy */
345   if (my->count[5] >= 0)
346   {
347     (my->count[6])++;
348     if ((my->count[2] != 0) && (my->count[6] < 48))
349     {
350       my->count[5] = -1;
351     }
352     else if ((my->count[6] >= 48) && (my->count[6] <= 60)
353         && (my->count[6] % 6 == 0))
354     {
355       switch (my->count[5])
356       {
357       case 0:
358         x = 120.0 + ((double) (my->count[6] - 56)) * 3.0;
359         break;
360       case 1:
361         x = 320.0 - ((double) (my->count[6] - 48)) * 3.0;
362         break;
363       case 2:
364         x = 320.0 + ((double) (my->count[6] - 48)) * 3.0;
365         break;
366       case 3:
367         x = 520.0 - ((double) (my->count[6] - 56)) * 3.0;
368       break;
369       default:
370         fprintf(stderr, "mankanshoku_act: undefined my->count[5] (add enemy) "
371                 "(%d)\n", my->count[5]);
372         x = ((double) (WINDOW_WIDTH / 2));
373         break;
374       }
375       if (my->count[6] == 48)
376         temp = 37;
377       else
378         temp = 9999;
379       tenm_table_add(normal_enemy_new(x, -19.0,
380                                       BALL_SOLDIER, ENEMY_TYPE_WEAK,
381                                       0, -1, 0, -1, 0, 1, 2,
382                                       /* move 0 */
383                                       9999,
384                                       0.0, 7.5, 0.0, 0.0,
385                                       0.0, 0.0, 0.0, 0.0, 0,
386                                       /* shoot 0 */
387                                       21, temp, 34, 0, 0, 1,
388                                       /* shoot 1 */
389                                       9999, temp, 55 % temp, 0, 1, 1));
390     }
391     if (my->count[6] >= 60)
392     {
393       switch (my->count[5])
394       {
395       case 0:
396       case 3:
397         my->count[5] = 1 + rand() % 2;
398         break;
399       case 1:
400         my->count[5] = 0;
401         break;
402       case 2:
403         my->count[5] = 3;
404         break;
405       default:
406         fprintf(stderr, "mankanshoku_act: undefined my->count[5] "
407                 "(mode change) (%d)\n", my->count[5]);
408         my->count[5] = 1;
409         break;
410       }
411       if ((t >= 840) || (my->count[2] != 0))
412         my->count[5] = -1;
413 
414       my->count[6] = 0;
415     }
416   }
417 
418   /* shoot */
419   if (my->count[2] != 0)
420     return 0;
421 
422   if (t < 907)
423   {
424     if (t % 121 == 0)
425     {
426       tenm_table_add(laser_angle_new(my->x - 50.0, my->y, 6.5,
427                                      125, 25.0, 2));
428       tenm_table_add(laser_angle_new(my->x - 50.0, my->y, 6.5,
429                                      146, 25.0, 2));
430       tenm_table_add(laser_angle_new(my->x - 50.0, my->y, 6.5,
431                                      167, 25.0, 2));
432 
433       tenm_table_add(laser_angle_new(my->x + 50.0, my->y, 6.5,
434                                      55, 25.0, 2));
435       tenm_table_add(laser_angle_new(my->x + 50.0, my->y, 6.5,
436                                      34, 25.0, 2));
437       tenm_table_add(laser_angle_new(my->x + 50.0, my->y, 6.5,
438                                      13, 25.0, 2));
439     }
440     if (t % 121 == 11)
441     {
442       tenm_table_add(laser_angle_new(my->x - 50.0, my->y, 6.5,
443                                      95, 25.0, 2));
444       tenm_table_add(laser_angle_new(my->x - 50.0, my->y, 7.5,
445                                      116, 25.0, 2));
446       tenm_table_add(laser_angle_new(my->x - 50.0, my->y, 8.5,
447                                      137, 25.0, 2));
448 
449       tenm_table_add(laser_angle_new(my->x + 50.0, my->y, 6.5,
450                                      85, 25.0, 2));
451       tenm_table_add(laser_angle_new(my->x + 50.0, my->y, 7.5,
452                                      64, 25.0, 2));
453       tenm_table_add(laser_angle_new(my->x + 50.0, my->y, 8.5,
454                                      43, 25.0, 2));
455     }
456     if (t % 121 == 22)
457     {
458       tenm_table_add(laser_angle_new(my->x - 50.0, my->y, 6.5,
459                                      65, 25.0, 2));
460       tenm_table_add(laser_angle_new(my->x - 50.0, my->y, 8.5,
461                                      86, 25.0, 2));
462       tenm_table_add(laser_angle_new(my->x - 50.0, my->y, 10.5,
463                                      107, 25.0, 2));
464 
465       tenm_table_add(laser_angle_new(my->x + 50.0, my->y, 6.5,
466                                      115, 25.0, 2));
467       tenm_table_add(laser_angle_new(my->x + 50.0, my->y, 8.5,
468                                      94, 25.0, 2));
469       tenm_table_add(laser_angle_new(my->x + 50.0, my->y, 10.5,
470                                      73, 25.0, 2));
471     }
472 
473     if ((t % 121 == 55) || (t % 121 == 88))
474     {
475       speed = 6.0;
476       if (t % 121 == 55)
477         theta1 = 45;
478       else
479         theta1 = 77;
480       theta2 = 113;
481 
482       dx = speed * tenm_cos(theta1);
483       dy = speed * tenm_sin(theta1);
484       v[0] = speed * tenm_cos(180 - theta2) * tenm_cos(theta1 - theta2);
485       v[1] = speed * tenm_cos(180 - theta2) * tenm_sin(theta1 - theta2);
486 
487       for (i = 0; i < 6; i++)
488       {
489         result[0] = v[0];
490         result[1] = v[1];
491         vector_rotate(result, v, i * 30);
492         tenm_table_add(normal_shot_new(my->x - 50.0, my->y,
493                                        dx + result[0], dy + result[1],
494                                        1, -2, 0));
495         tenm_table_add(normal_shot_new(my->x + 50.0, my->y,
496                                        -(dx + result[0]), dy + result[1],
497                                        1, -2, 0));
498       }
499     }
500   }
501   else if ((t >= 989) && (t < 1127))
502   {
503     speed = 7.0;
504     if (t % 46 == 0)
505     {
506       tenm_table_add(laser_point_new(my->x + 120.0 * tenm_cos(-15),
507                                      my->y + 120.0 * tenm_sin(-15),
508                                      speed,
509                                      player->x, player->y - 150.0,
510                                      25.0, 0));
511       tenm_table_add(laser_point_new(my->x + 120.0 * tenm_cos(-165),
512                                      my->y + 120.0 * tenm_sin(-165),
513                                      speed,
514                                      player->x, player->y - 150.0,
515                                      25.0, 0));
516       tenm_table_add(laser_point_new(my->x + 120.0 * tenm_cos(-45),
517                                      my->y + 120.0 * tenm_sin(-45),
518                                      speed,
519                                      player->x, player->y - 75.0,
520                                      25.0, 0));
521       tenm_table_add(laser_point_new(my->x + 120.0 * tenm_cos(-135),
522                                      my->y + 120.0 * tenm_sin(-135),
523                                      speed,
524                                      player->x, player->y - 75.0,
525                                      25.0, 0));
526       tenm_table_add(laser_point_new(my->x + 120.0 * tenm_cos(-75),
527                                      my->y + 120.0 * tenm_sin(-75),
528                                      speed,
529                                      player->x, player->y,
530                                      25.0, 0));
531       tenm_table_add(laser_point_new(my->x + 120.0 * tenm_cos(-105),
532                                      my->y + 120.0 * tenm_sin(-105),
533                                      speed,
534                                      player->x, player->y,
535                                      25.0, 0));
536     }
537     if (t % 46 == 23)
538     {
539       tenm_table_add(laser_point_new(my->x + 120.0 * tenm_cos(-15),
540                                      my->y + 120.0 * tenm_sin(-15),
541                                      speed,
542                                      player->x, player->y,
543                                      25.0, 0));
544       tenm_table_add(laser_point_new(my->x + 120.0 * tenm_cos(-165),
545                                      my->y + 120.0 * tenm_sin(-165),
546                                      speed,
547                                      player->x, player->y,
548                                      25.0, 0));
549       tenm_table_add(laser_point_new(my->x + 120.0 * tenm_cos(-45),
550                                      my->y + 120.0 * tenm_sin(-45),
551                                      speed,
552                                      player->x, player->y - 75.0,
553                                      25.0, 0));
554       tenm_table_add(laser_point_new(my->x + 120.0 * tenm_cos(-135),
555                                      my->y + 120.0 * tenm_sin(-135),
556                                      speed,
557                                      player->x, player->y - 75.0,
558                                      25.0, 0));
559       tenm_table_add(laser_point_new(my->x + 120.0 * tenm_cos(-75),
560                                      my->y + 120.0 * tenm_sin(-75),
561                                      speed,
562                                      player->x, player->y - 150.0,
563                                      25.0, 0));
564       tenm_table_add(laser_point_new(my->x + 120.0 * tenm_cos(-105),
565                                      my->y + 120.0 * tenm_sin(-105),
566                                      speed,
567                                      player->x, player->y - 150.0,
568                                      25.0, 0));
569     }
570   }
571 
572   return 0;
573 }
574 
575 static int
mankanshoku_draw(tenm_object * my,int priority)576 mankanshoku_draw(tenm_object *my, int priority)
577 {
578   int status = 0;
579   tenm_color color;
580   char temp[32];
581   int i;
582 
583   /* sanity check */
584   if (my == NULL)
585   {
586     fprintf(stderr, "mankanshoku_draw: my is NULL\n");
587     return 0;
588   }
589 
590   if (priority != 0)
591     return 0;
592   if (my->count[2] != 0)
593     return 0;
594 
595   /* decoration */
596   if (mankanshoku_green(my))
597   {
598     if (my->count[1] >= 40)
599       color = tenm_map_color(181, 190, 92);
600     else
601       color = tenm_map_color(157, 182, 123);
602   }
603   else
604   {
605     if (my->count[1] >= 40)
606       color = tenm_map_color(200, 164, 92);
607     else
608       color = tenm_map_color(182, 147, 123);
609   }
610 
611   for (i = -15; i >= -165; i -= 30)
612     if (tenm_draw_line(((int) (my->x + 80.0 * tenm_cos(i))),
613                        ((int) (my->y + 80.0 * tenm_sin(i))),
614                        ((int) (my->x + 120.0 * tenm_cos(i))),
615                        ((int) (my->y + 120.0 * tenm_sin(i))),
616                        1, color) != 0)
617       status = 1;
618 
619   /* body */
620   if (mankanshoku_green(my))
621   {
622     if (my->count[1] >= 40)
623       color = tenm_map_color(109, 125, 9);
624     else
625       color = tenm_map_color(61, 95, 13);
626   }
627   else
628   {
629     if (my->count[1] >= 40)
630       color = tenm_map_color(135, 89, 9);
631     else
632       color = tenm_map_color(95, 47, 13);
633   }
634 
635   if (tenm_draw_line(((int) (my->x + 60.0)),
636                      ((int) (my->y - 15.0)),
637                      ((int) (my->x + 60.0)),
638                      ((int) (my->y + 15.0)),
639                      3, color) != 0)
640     status = 1;
641   if (tenm_draw_line(((int) (my->x + 60.0)),
642                      ((int) (my->y + 15.0)),
643                      ((int) (my->x + 50.0)),
644                      ((int) (my->y + 25.0)),
645                      3, color) != 0)
646     status = 1;
647   if (tenm_draw_line(((int) (my->x + 50.0)),
648                      ((int) (my->y + 25.0)),
649                      ((int) (my->x - 50.0)),
650                      ((int) (my->y + 25.0)),
651                      3, color) != 0)
652     status = 1;
653   if (tenm_draw_line(((int) (my->x - 50.0)),
654                      ((int) (my->y + 25.0)),
655                      ((int) (my->x - 60.0)),
656                      ((int) (my->y + 15.0)),
657                      3, color) != 0)
658     status = 1;
659   if (tenm_draw_line(((int) (my->x - 60.0)),
660                      ((int) (my->y + 15.0)),
661                      ((int) (my->x - 60.0)),
662                      ((int) (my->y - 15.0)),
663                      3, color) != 0)
664     status = 1;
665   if (tenm_draw_line(((int) (my->x - 60.0)),
666                      ((int) (my->y - 15.0)),
667                      ((int) (my->x - 50.0)),
668                      ((int) (my->y - 25.0)),
669                      3, color) != 0)
670     status = 1;
671   if (tenm_draw_line(((int) (my->x - 50.0)),
672                      ((int) (my->y - 25.0)),
673                      ((int) (my->x + 50.0)),
674                      ((int) (my->y - 25.0)),
675                      3, color) != 0)
676     status = 1;
677   if (tenm_draw_line(((int) (my->x + 50.0)),
678                      ((int) (my->y - 25.0)),
679                      ((int) (my->x + 60.0)),
680                      ((int) (my->y - 15.0)),
681                      3, color) != 0)
682     status = 1;
683 
684   /* hit point stat */
685   if ((priority == 0) && (my->count[1] > 0))
686   {
687     sprintf(temp, "%d", my->hit_point);
688     if (draw_string(((int) my->x) - 10, (int) my->y,
689                     temp, (int) strlen(temp)) != 0)
690     {
691       fprintf(stderr, "mankanshoku_draw: draw_string failed\n");
692       status = 1;
693     }
694   }
695 
696   return status;
697 }
698 
699 /* return 1 (true) or 0 (false) */
700 static int
mankanshoku_green(const tenm_object * my)701 mankanshoku_green(const tenm_object *my)
702 {
703   /* sanity check */
704   if (my == NULL)
705     return 0;
706 
707   if ((my->count[3] >= 1192) && (my->count[3] < 2314))
708     return 1;
709 
710   return 0;
711 }
712