1 /* $Id: p-can.c,v 1.37 2011/08/23 20:14:16 oohara Exp $ */
2 /* [easiest] P-can */
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 "p-can.h"
28 
29 static int p_can_move(tenm_object *my, double turn_per_frame);
30 static int p_can_hit(tenm_object *my, tenm_object *your);
31 static void p_can_next(tenm_object *my);
32 static int p_can_act(tenm_object *my, const tenm_object *player);
33 static int p_can_draw(tenm_object *my, int priority);
34 static int p_can_green(const tenm_object *my);
35 
36 tenm_object *
p_can_new(void)37 p_can_new(void)
38 {
39   tenm_primitive **p = NULL;
40   tenm_object *new = NULL;
41   int *count = NULL;
42   double *count_d = NULL;
43   double x = (double) (WINDOW_WIDTH / 2);
44   double y = -49.0;
45 
46   p = (tenm_primitive **) malloc(sizeof(tenm_primitive *) * 1);
47   if (p == NULL)
48   {
49     fprintf(stderr, "p_can_new: malloc(p) failed\n");
50     return NULL;
51   }
52 
53   p[0] = (tenm_primitive *) tenm_polygon_new(4,
54                                              x + 50.0, y - 50.0,
55                                              x + 50.0, y + 50.0,
56                                              x - 50.0, y + 50.0,
57                                              x - 50.0, y - 50.0);
58   if (p[0] == NULL)
59   {
60     fprintf(stderr, "p_can_new: cannot set p[0]\n");
61     free(p);
62     return NULL;
63   }
64 
65   count = (int *) malloc(sizeof(int) * 5);
66   if (count == NULL)
67   {
68     fprintf(stderr, "p_can_new: malloc(count) failed\n");
69     (p[0])->delete(p[0]);
70     free(p);
71     return NULL;
72   }
73   count_d = (double *) malloc(sizeof(double) * 4);
74   if (count_d == NULL)
75   {
76     fprintf(stderr, "p_can_new: malloc(count_d) failed\n");
77     free(count);
78     (p[0])->delete(p[0]);
79     free(p);
80     return NULL;
81   }
82 
83   /* list of count
84    * [0] for deal_damage
85    * [1] "damaged" timer
86    * [2] life mode
87    * [3] life timer
88    * [4] "was green when killed" flag
89    */
90   /* list of count_d
91    * [0] speed x
92    * [1] speed y
93    * [2] turret aim x
94    * [3] turret aim y
95    */
96 
97   count[0] = 0;
98   count[1] = 0;
99   count[2] = 0;
100   count[3] = 0;
101   count[4] = 0;
102 
103   count_d[0] = 0.0;
104   count_d[1] = (((double) (WINDOW_HEIGHT / 4)) - y) / 90.0;
105   count_d[2] = 40.0;
106   count_d[3] = 0.0;
107 
108   new = tenm_object_new("P-can", ATTR_BOSS, ATTR_PLAYER_SHOT,
109                         400, x, y,
110                         5, count, 4, count_d, 1, p,
111                         (int (*)(tenm_object *, double))
112                         (&p_can_move),
113                         (int (*)(tenm_object *, tenm_object *))
114                         (&p_can_hit),
115                         (int (*)(tenm_object *, const tenm_object *))
116                         (&p_can_act),
117                         (int (*)(tenm_object *, int))
118                         (&p_can_draw));
119 
120   if (new == NULL)
121   {
122     fprintf(stderr, "p_can_new: tenm_object_new failed\n");
123     if (count_d != NULL)
124       free(count_d);
125     if (count != NULL)
126       free(count);
127     (p[0])->delete(p[0]);
128     free(p);
129     return NULL;
130   }
131 
132   return new;
133 }
134 
135 static int
p_can_move(tenm_object * my,double turn_per_frame)136 p_can_move(tenm_object *my, double turn_per_frame)
137 {
138   double dx_temp;
139   double dy_temp;
140 
141   /* sanity check */
142   if (my == NULL)
143   {
144     fprintf(stderr, "p_can_move: my is NULL\n");
145     return 0;
146   }
147   if (turn_per_frame <= 0.5)
148   {
149     fprintf(stderr, "p_can_move: strange turn_per_frame (%f)\n",
150             turn_per_frame);
151     return 0;
152   }
153 
154   dx_temp = my->count_d[0] / turn_per_frame;
155   dy_temp = my->count_d[1] / turn_per_frame;
156   my->x += dx_temp;
157   my->y += dy_temp;
158   if (my->mass != NULL)
159     tenm_move_mass(my->mass, dx_temp, dy_temp);
160 
161   return 0;
162 }
163 
164 static int
p_can_hit(tenm_object * my,tenm_object * your)165 p_can_hit(tenm_object *my, tenm_object *your)
166 {
167   /* sanity check */
168   if (my == NULL)
169   {
170     fprintf(stderr, "p_can_hit: my is NULL\n");
171     return 0;
172   }
173   if (your == NULL)
174   {
175     fprintf(stderr, "p_can_hit: your is NULL\n");
176     return 0;
177   }
178 
179   if (!(your->attr & ATTR_PLAYER_SHOT))
180     return 0;
181   if (my->count[2] != 1)
182     return 0;
183 
184   deal_damage(my, your, 0);
185   if (p_can_green(my))
186     add_chain(my, your);
187   my->count[1] = 2;
188 
189   if (my->hit_point <= 0)
190   {
191     add_score(1500);
192     set_background(1);
193     p_can_next(my);
194     return 0;
195   }
196 
197   return 0;
198 }
199 
200 static void
p_can_next(tenm_object * my)201 p_can_next(tenm_object *my)
202 {
203   int n;
204 
205   /* sanity check */
206   if (my == NULL)
207   {
208     fprintf(stderr, "p_can_next: my is NULL\n");
209     return;
210   }
211 
212   tenm_table_apply_all((int (*)(tenm_object *, int)) (&delete_enemy_shot), 0);
213   tenm_table_apply_all((int (*)(tenm_object *, int)) (&delete_enemy), 0);
214 
215   /* set "was green" flag before we change the life mode */
216   if (p_can_green(my))
217   {
218     n = 8;
219     my->count[4] = 1;
220   }
221   else
222   {
223     n = 7;
224     my->count[4] = 0;
225   }
226 
227   tenm_table_add(explosion_new(my->x, my->y, 0.0, 0.0,
228                                1, 5000, n, 10.0, 6));
229 
230   my->count[2] = 2;
231   my->count[3] = 0;
232   my->count[1] = 0;
233   my->count_d[0] = 0.0;
234   my->count_d[1] = 0.5;
235 
236   /* don't modify my->attr or my->hit_mask here, or the player shot
237    * may fly through the enemy */
238   tenm_mass_delete(my->mass);
239   my->mass = NULL;
240 }
241 
242 static int
p_can_act(tenm_object * my,const tenm_object * player)243 p_can_act(tenm_object *my, const tenm_object *player)
244 {
245   int i;
246   int j;
247   int theta;
248   double v[2];
249   double a[2];
250   double result[2];
251   double x;
252   double y;
253 
254   /* sanity check */
255   if (my == NULL)
256   {
257     fprintf(stderr, "p_can_act: my is NULL\n");
258     return 0;
259   }
260   if (player == NULL)
261     return 0;
262 
263   /* for deal_damage */
264   my->count[0] = 0;
265 
266   /* "damaged" count down */
267   if (my->count[1] > 0)
268     (my->count[1])--;
269 
270   (my->count[3])++;
271 
272   /* encounter */
273   if (my->count[2] == 0)
274   {
275     if (my->count[3] >= 90)
276     {
277       my->count[2] = 1;
278       my->count[3] = 0;
279       my->count_d[0] = 0.0;
280       my->count_d[1] = 0.0;
281       return 0;
282     }
283     return 0;
284   }
285 
286   /* dead */
287   if (my->count[2] == 2)
288   {
289     if (p_can_green(my))
290       i = 8;
291     else
292       i = 7;
293 
294     if ((my->count[3] >= 30) && (my->count[3] <= 75)
295         && (my->count[3] % 15 == 0))
296     {
297       theta = rand() % 360;
298       tenm_table_add(explosion_new(my->x + 30.0 * tenm_cos(theta),
299                                    my->y + 30.0 * tenm_sin(theta),
300                                    0.0, 0.0,
301                                    2, 300, i, 5.0, 8));
302     }
303 
304     if (my->count[3] > 120)
305     {
306       tenm_table_add(explosion_new(my->x, my->y,
307                                    0.0, 0.0,
308                                    1, 3000, i, 10.0, 8));
309       tenm_table_add(fragment_new(my->x, my->y, 0.0, 0.0,
310                                   30.0, 100, i, 4.0, 0.0, 16));
311       tenm_table_add(fragment_new(my->x, my->y, 0.0, 0.0,
312                                   50.0, 30, i, 2.5, 0.0, 12));
313 
314       tenm_table_add(stage_clear_new(100));
315       return 1;
316     }
317 
318     return 0;
319   }
320 
321   /* self-destruction */
322   if ((my->count[2] == 1) && (my->count[3] >= 2980))
323   {
324     set_background(2);
325     clear_chain();
326     p_can_next(my);
327     return 0;
328   }
329 
330   /* aim at the player */
331   v[0] = my->count_d[2];
332   v[1] = my->count_d[3];
333   if ((my->count[3] >= 1300) && (my->count[3] <= 1360))
334   {
335     a[0] = -40.0;
336     a[1] = 0.0;
337   }
338   else if ((my->count[3] >= 2700) && (my->count[3] <= 2760))
339   {
340     a[0] = 40.0;
341     a[1] = 0.0;
342   }
343   else
344   {
345     a[0] = player->x - my->x;
346     a[1] = player->y - my->y;
347   }
348   result[0] = v[0];
349   result[1] = v[1];
350   if (((my->count[3] >= 100) && (my->count[3] <= 160))
351       || ((my->count[3] >= 1300) && (my->count[3] <= 1360))
352       || ((my->count[3] >= 1500) && (my->count[3] <= 1560))
353       || ((my->count[3] >= 2700) && (my->count[3] <= 2760)))
354     vector_rotate_bounded(result, v, a, 3);
355   else if (((my->count[3] > 160) && (my->count[3] < 1300))
356            || ((my->count[3] > 1560) && (my->count[3] <= 2700)))
357     vector_rotate_bounded(result, v, a, 1);
358   else if ((my->count[3] >= 1400) && (my->count[3] < 1490))
359     vector_rotate(result, v, -2);
360   else if ((my->count[3] >= 2800) && (my->count[3] < 2890))
361     vector_rotate(result, v, 2);
362   my->count_d[2] = result[0];
363   my->count_d[3] = result[1];
364   if (my->count_d[3] < 0.0)
365   {
366     if (my->count_d[2] > 0.0)
367     {
368       my->count_d[2] = 40.0;
369       my->count_d[3] = 0.0;
370     }
371     else
372     {
373       my->count_d[2] = -40.0;
374       my->count_d[3] = 0.0;
375     }
376   }
377 
378   /* shoot */
379   if (((my->count[3] <= 51) && (my->count[3] % 17 == 0))
380       || ((my->count[3] >= 160) && (my->count[3] < 1233)
381           && ((my->count[3] - 160) % 37 == 0))
382       || ((my->count[3] >= 1400) && (my->count[3] < 1490)
383           && ((my->count[3] - 1400) % 13 == 0))
384       || ((my->count[3] >= 1560) && (my->count[3] < 2633)
385           && ((my->count[3] - 1560) % 37 == 0))
386       || ((my->count[3] >= 2800) && (my->count[3] < 2890)
387           && ((my->count[3] - 2800) % 13 == 0)))
388   {
389     for (i = -1; i <= 1; i += 2)
390     {
391       for (j = -45; j <= 45; j += 45)
392       {
393         x = my->x + my->count_d[2] + my->count_d[3] * 3.0/4.0 * ((double) i);
394         y = my->y + my->count_d[3] - my->count_d[2] * 3.0/4.0 * ((double) i);
395         v[0] = my->count_d[2];
396         v[1] = my->count_d[3];
397         result[0] = v[0];
398         result[1] = v[1];
399         vector_rotate(result, v, j);
400         tenm_table_add(laser_point_new(x, y, 3.0,
401                                        x + result[0], y + result[1],
402                                        25.0, 2));
403       }
404     }
405   }
406   if (((my->count[3] >= 160) && (my->count[3] < 1233)
407        && ((my->count[3] - 160) % 29 == 0))
408       || ((my->count[3] >= 1560) && (my->count[3] < 2633)
409           && ((my->count[3] - 1560) % 29 == 0))
410       || (my->count[3] == 1370) || (my->count[3] == 2770))
411   {
412     tenm_table_add(normal_shot_point_new(my->x, my->y, 2.5,
413                                          player->x, player->y,
414                                          4));
415   }
416 
417   return 0;
418 }
419 
420 static int
p_can_draw(tenm_object * my,int priority)421 p_can_draw(tenm_object *my, int priority)
422 {
423   int status = 0;
424   tenm_color color;
425   char temp[32];
426 
427   /* sanity check */
428   if (my == NULL)
429   {
430     fprintf(stderr, "p_can_draw: my is NULL\n");
431     return 0;
432   }
433 
434   /* dead enemy has low priority */
435   if (((my->count[2] <= 1) && (priority != 0))
436       || ((my->count[2] > 1) && (priority != -1)))
437     return 0;
438 
439   if (p_can_green(my))
440   {
441     if (my->count[1] >= 1)
442       color = tenm_map_color(109, 125, 9);
443     else
444       color = tenm_map_color(61, 95, 13);
445   }
446   else
447   {
448     if (my->count[1] >= 1)
449       color = tenm_map_color(135, 89, 9);
450     else
451       color = tenm_map_color(95, 47, 13);
452   }
453 
454   /* turret */
455   if (tenm_draw_circle((int) (my->x), (int) (my->y), 50, 1, color) != 0)
456     status = 1;
457 
458   if (tenm_draw_line((int) (my->x + my->count_d[2] + my->count_d[3] * 3.0/4.0),
459                      (int) (my->y + my->count_d[3] - my->count_d[2] * 3.0/4.0),
460                      (int) (my->x + my->count_d[2] - my->count_d[3] * 3.0/4.0),
461                      (int) (my->y + my->count_d[3] + my->count_d[2] * 3.0/4.0),
462                      1, color) != 0)
463     status = 1;
464   if (tenm_draw_line((int) (my->x + my->count_d[2] - my->count_d[3] * 3.0/4.0),
465                      (int) (my->y + my->count_d[3] + my->count_d[2] * 3.0/4.0),
466                      (int) (my->x - my->count_d[2] - my->count_d[3] * 3.0/4.0),
467                      (int) (my->y - my->count_d[3] + my->count_d[2] * 3.0/4.0),
468                      1, color) != 0)
469     status = 1;
470   if (tenm_draw_line((int) (my->x - my->count_d[2] - my->count_d[3] * 3.0/4.0),
471                      (int) (my->y - my->count_d[3] + my->count_d[2] * 3.0/4.0),
472                      (int) (my->x - my->count_d[2] + my->count_d[3] * 3.0/4.0),
473                      (int) (my->y - my->count_d[3] - my->count_d[2] * 3.0/4.0),
474                      1, color) != 0)
475     status = 1;
476   if (tenm_draw_line((int) (my->x - my->count_d[2] + my->count_d[3] * 3.0/4.0),
477                      (int) (my->y - my->count_d[3] - my->count_d[2] * 3.0/4.0),
478                      (int) (my->x + my->count_d[2] + my->count_d[3] * 3.0/4.0),
479                      (int) (my->y + my->count_d[3] - my->count_d[2] * 3.0/4.0),
480                      1, color) != 0)
481     status = 1;
482 
483   if (tenm_draw_line((int) (my->x + my->count_d[2] * 30.0 / 40.0
484                             + my->count_d[3] * 3.0 / 4.0),
485                      (int) (my->y + my->count_d[3] * 30.0 / 40.0
486                             - my->count_d[2] * 3.0 / 4.0),
487                      (int) (my->x + my->count_d[2] * 30.0 / 40.0
488                             - my->count_d[3] * 3.0 / 4.0),
489                      (int) (my->y + my->count_d[3] * 30.0 / 40.0
490                             + my->count_d[2] * 3.0 / 4.0),
491                      1, color) != 0)
492     status = 1;
493 
494   /* body */
495   if (tenm_draw_line((int) (my->x + 50.0), (int) (my->y - 50.0),
496                      (int) (my->x + 50.0), (int) (my->y + 50.0),
497                      3, color) != 0)
498     status = 1;
499   if (tenm_draw_line((int) (my->x + 50.0), (int) (my->y + 50.0),
500                      (int) (my->x - 50.0), (int) (my->y + 50.0),
501                      3, color) != 0)
502     status = 1;
503   if (tenm_draw_line((int) (my->x - 50.0), (int) (my->y + 50.0),
504                      (int) (my->x - 50.0), (int) (my->y - 50.0),
505                      3, color) != 0)
506     status = 1;
507   if (tenm_draw_line((int) (my->x - 50.0), (int) (my->y - 50.0),
508                      (int) (my->x + 50.0), (int) (my->y - 50.0),
509                      3, color) != 0)
510     status = 1;
511 
512   /* hit point stat */
513   if (my->count[2] == 1)
514   {
515     sprintf(temp, "%d", my->hit_point);
516     if (draw_string(((int) my->x) - 10, (int) my->y,
517                     temp, (int) strlen(temp)) != 0)
518     {
519       fprintf(stderr, "p_can_draw: draw_string failed\n");
520       status = 1;
521     }
522   }
523 
524   return status;
525 }
526 
527 /* return 1 (true) or 0 (false) */
528 static int
p_can_green(const tenm_object * my)529 p_can_green(const tenm_object *my)
530 {
531   /* sanity check */
532   if (my == NULL)
533     return 0;
534 
535   if ((my->count[2] == 1)
536       && (my->count[3] >= 1370) && (my->count[3] < 2950))
537     return 1;
538   if ((my->count[2] == 2) && (my->count[4] != 0))
539     return 1;
540 
541   return 0;
542 }
543