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