1 /* $Id: player-shot.c,v 1.93 2004/08/30 16:23:27 oohara Exp $ */
2 
3 #include <stdio.h>
4 /* malloc, rand */
5 #include <stdlib.h>
6 /* strcmp */
7 #include <string.h>
8 
9 #include "const.h"
10 #include "tenm_graphic.h"
11 #include "tenm_object.h"
12 #include "tenm_primitive.h"
13 #include "tenm_math.h"
14 #include "tenm_input.h"
15 #include "util.h"
16 #include "score.h"
17 #include "chain.h"
18 
19 #include "player-shot.h"
20 
21 #define NEAR_ZERO 0.0001
22 
23 static int player_shot_move(tenm_object *my, double turn_per_frame);
24 static int player_shot_hit(tenm_object *my, tenm_object *your);
25 static int player_shot_draw(tenm_object *my, int priority);
26 static int player_shot_act(tenm_object *my, const tenm_object *player);
27 
28 static int player_shot_explode(tenm_object *my);
29 
30 static int deal_damage2(tenm_object *my, tenm_object *your);
31 
32 tenm_object *
player_shot_new(double x,double y,int n)33 player_shot_new(double x, double y, int n)
34 {
35   tenm_primitive **p;
36   tenm_object *new;
37   int *count = NULL;
38   double *count_d = NULL;
39 
40   /* sanity check */
41   if ((n < 0) || (n >= 4))
42   {
43     fprintf(stderr, "player_shot_new: strange n (%d)\n", n);
44     return NULL;
45   }
46 
47   p = (tenm_primitive **) malloc(sizeof(tenm_primitive *) * 1);
48   if (p == NULL)
49   {
50     fprintf(stderr, "player_shot_new: malloc(p) failed\n");
51     return NULL;
52   }
53 
54   p[0] = (tenm_primitive *) tenm_circle_new(x, y, 10.0);
55 
56   if (p[0] == NULL)
57   {
58     fprintf(stderr, "player_shot_new: cannot set p[0]\n");
59     free(p);
60     return NULL;
61   }
62 
63   count = (int *) malloc(sizeof(int) * 4);
64   if (count == NULL)
65   {
66     fprintf(stderr, "player_shot_new: malloc(count) failed\n");
67     (p[0])->delete(p[0]);
68     free(p);
69     return NULL;
70   }
71 
72   count_d = (double *) malloc(sizeof(double) * 4);
73   if (count_d == NULL)
74   {
75     fprintf(stderr, "player_new: malloc(count_d) failed\n");
76     (p[0])->delete(p[0]);
77     free(p);
78     if (count != NULL)
79       free(count);
80     return NULL;
81   }
82 
83   count[0] = 1;
84   count[1] = 0;
85   count[2] = 0;
86   count[3] = 0;
87 
88   if (n == 0)
89   {
90     count_d[0] = 0.0;
91     count_d[1] = -52.0;
92   }
93   else if (n == 1)
94   {
95     count_d[0] = 0.0;
96     count_d[1] = 52.0;
97   }
98   else if (n == 2)
99   {
100     count_d[0] = 48.0;
101     count_d[1] = -20.0;
102   }
103   else
104   {
105     count_d[0] = -48.0;
106     count_d[1] = -20.0;
107   }
108 
109   count_d[2] = x;
110   count_d[3] = y;
111 
112   /* list of count
113    * [0] phase (begins with 1)
114    * [1] explosion timer
115    * [2] trail timer
116    * [3] "hit during phase 1" flag
117    */
118   /* list of count_d
119    * [0] speed x
120    * [1] speed y
121    * [2] origin x
122    * [3] origin y
123    */
124 
125   new =tenm_object_new("player shot", ATTR_PLAYER_SHOT,
126                        ATTR_BOSS | ATTR_ENEMY | ATTR_OBSTACLE | ATTR_OPAQUE,
127                        20, x, y,
128                        4, count, 4, count_d, 1, p,
129                        (int (*)(tenm_object *, double)) (&player_shot_move),
130                        (int (*)(tenm_object *, tenm_object *))
131                        (&player_shot_hit),
132                        (int (*)(tenm_object *, const tenm_object *))
133                        (&player_shot_act),
134                        (int (*)(tenm_object *, int)) (&player_shot_draw));
135   if (new == NULL)
136   {
137     fprintf(stderr, "player_shot_new: tenm_object_new failed\n");
138     free(count_d);
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
player_shot_move(tenm_object * my,double turn_per_frame)149 player_shot_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     return 0;
157   if (turn_per_frame <= 0.5)
158     return 0;
159 
160   if (my->count[0] != 1)
161     return 0;
162   if (my->hit_point <= 0)
163     return 0;
164 
165   if (my->count[3] != 0)
166   {
167     my->attr = 0;
168     my->hit_mask = 0;
169     return 0;
170   }
171 
172   dx_temp = my->count_d[0] / turn_per_frame;
173   dy_temp = my->count_d[1] / turn_per_frame;
174   my->x += dx_temp;
175   my->y += dy_temp;
176   tenm_move_mass(my->mass, dx_temp, dy_temp);
177 
178   if (!in_window_object(my))
179   {
180     my->attr = 0;
181     my->hit_mask = 0;
182     my->hit_point = 0;
183 
184     my->count_d[0] = 0.0;
185     my->count_d[1] = 0.0;
186 
187     clear_chain();
188     /* we have to wait for the trail to disappear */
189     return 0;
190   }
191 
192   return 0;
193 }
194 
195 static int
player_shot_hit(tenm_object * my,tenm_object * your)196 player_shot_hit(tenm_object *my, tenm_object *your)
197 {
198   /* sanity check */
199   if (my == NULL)
200     return 0;
201   if (your == NULL)
202     return 0;
203 
204   if (my->count[0] == 1)
205   {
206     /* don't call player_shot_explode() here --- hit() of the enemy
207      * may or may not be called before this
208      */
209     my->count[3] = 1;
210     return 0;
211   }
212 
213   return 0;
214 }
215 
216 static int
player_shot_act(tenm_object * my,const tenm_object * player)217 player_shot_act(tenm_object *my, const tenm_object *player)
218 {
219   /* sanity check */
220   if (my == NULL)
221     return 0;
222   if (player == NULL)
223     return 0;
224   if ((my->count[0] < 1) || (my->count[0] > 2))
225   {
226     fprintf(stderr, "player_shot_act: strange mode (%d)\n", my->count[0]);
227     return 1;
228   }
229 
230   if (my->hit_point > 0)
231   {
232     if (my->count[0] == 1)
233     {
234       /* explode if we hit something */
235       if (my->count[3] != 0)
236         player_shot_explode(my);
237     }
238     else if (my->count[0] == 2)
239     {
240       (my->count[1])++;
241       if (my->count[1] > 30)
242       {
243         my->attr = 0;
244         my->hit_mask = 0;
245         my->hit_point = 0;
246 
247         my->count_d[0] = 0.0;
248         my->count_d[1] = 0.0;
249         /* no "return 1" here --- we have to wait
250          * for the trail to disappear
251          */
252       }
253     }
254   }
255 
256   if (my->count[2] >= 32)
257   {
258     if (my->hit_point <= 0)
259       return 1;
260   }
261   else
262   {
263     (my->count[2])++;
264   }
265 
266   return 0;
267 }
268 
269 static int
player_shot_draw(tenm_object * my,int priority)270 player_shot_draw(tenm_object *my, int priority)
271 {
272   int i;
273   double length;
274   int theta;
275   int red_orig;
276   int green_orig;
277   int blue_orig;
278   tenm_color color;
279   int status = 0;
280 
281   /* sanity check */
282   if (my == NULL)
283     return 0;
284   if ((priority != 0) && (priority != -1))
285     return 0;
286 
287   color = tenm_map_color(134, 215, 170);
288 
289   if (priority == 0)
290   {
291     if ((my->count[0] == 1) && (my->hit_point > 0))
292     {
293       if (tenm_draw_circle((int) my->x, (int) my->y, 10,
294                            1, color) != 0)
295         status = 1;
296     }
297     else if (my->count[0] == 2)
298     {
299       for (i = 0; i < 10 - my->count[1] / 3; i++)
300       {
301         length = 50.0 - 5.0 * ((double) (rand() % 32)) / 32.0;
302         theta = rand() % 360;
303         if (tenm_draw_line((int) my->x, (int) my->y,
304                            (int) (my->x + length * tenm_cos(theta)),
305                            (int) (my->y + length * tenm_sin(theta)),
306                            1, color) != 0)
307           status = 1;
308       }
309       for (i = 0; i < 30 - my->count[1]; i++)
310       {
311         length = 50.0 - 25.0 * ((double) (rand() % 32)) / 32.0;
312         theta = rand() % 360;
313         if (tenm_draw_line((int) my->x, (int) my->y,
314                            (int) (my->x + length * tenm_cos(theta)),
315                            (int) (my->y + length * tenm_sin(theta)),
316                            1, color) != 0)
317           status = 1;
318       }
319 
320       if (tenm_draw_circle((int) my->x, (int) my->y, 50,
321                            1, color) != 0)
322         status = 1;
323     }
324   }
325   else if (priority == -1)
326   {
327     /* don't draw the trail if the shot did not move at all */
328     if ((my->count[2] > 0) && (my->count[2] < 32))
329     {
330       if ((my->count[0] == 1) && (my->hit_point <= 0))
331       {
332         red_orig = 63;
333         green_orig = 63;
334         blue_orig = 63;
335       }
336       else
337       {
338         red_orig = 134;
339         green_orig = 215;
340         blue_orig = 170;
341       }
342 
343       color = tenm_map_color((red_orig * (32- my->count[2])
344                               + DEFAULT_BACKGROUND_RED * my->count[2]) / 32,
345                              (green_orig * (32- my->count[2])
346                               + DEFAULT_BACKGROUND_GREEN * my->count[2]) / 32,
347                              (blue_orig * (32- my->count[2])
348                               + DEFAULT_BACKGROUND_BLUE * my->count[2]) / 32);
349       if (tenm_draw_line((int) (my->x), (int) (my->y),
350                          (int) (my->count_d[2]), (int) (my->count_d[3]),
351                          1, color) != 0)
352         status = 1;
353     }
354   }
355 
356   return status;
357 }
358 
359 /* return 0 on success, 1 on error */
360 static int
player_shot_explode(tenm_object * my)361 player_shot_explode(tenm_object *my)
362 {
363   /* sanity check */
364   if (my == NULL)
365   {
366     fprintf(stderr, "player_shot_explode: my is NULL\n");
367     return 1;
368   }
369   if (my->name == NULL)
370   {
371     fprintf(stderr, "player_shot_explode: my->name is NULL\n");
372     return 1;
373   }
374   if (strcmp(my->name, "player shot") != 0)
375   {
376     fprintf(stderr, "player_shot_explode: my->name is not \"player shot\"\n");
377     return 1;
378   }
379 
380   my->attr = ATTR_PLAYER_SHOT;
381   my->hit_mask = 0;
382 
383   my->hit_point = 1;
384 
385   my->count[0] = 2;
386   my->count[1] = 1;
387 
388   ((tenm_circle *) my->mass->p[0])->r = 50.0;
389 
390   return 0;
391 }
392 
393 /* damage handling function for hit() of an enemy
394  * my is the enemy, your is the player shot
395  * n (arg 3) is the index of count[] for phase 2 boomerang handling
396  * you must set my->count[n] to 0 in act() every frame
397  * warning: turn_per_frame is hard-coded
398  */
399 int
deal_damage(tenm_object * my,tenm_object * your,int n)400 deal_damage(tenm_object *my, tenm_object *your, int n)
401 {
402   /* sanity check */
403   if (my == NULL)
404   {
405     fprintf(stderr, "deal_damage: my is NULL\n");
406     return 0;
407   }
408   if (your == NULL)
409   {
410     fprintf(stderr, "deal_damage: your is NULL\n");
411     return 0;
412   }
413   if ((n < 0) || (n >= my->n))
414   {
415     fprintf(stderr, "deal_damage: strange n (%d)\n", n);
416     return 0;
417   }
418 
419   if (your->count[0] == 1)
420   {
421     deal_damage2(my, your);
422   }
423   else if (your->count[0] == 2)
424   {
425     my->count[n] -= 1;
426     if (my->count[n] <= 0)
427     {
428       deal_damage2(my, your);
429       /* turn_per_frame */
430       my->count[n] = 30;
431     }
432   }
433 
434   return 0;
435 }
436 
437 /* change the hit point of the enemy and add score
438  * my is the enemy, your is the player shot
439  */
440 static int
deal_damage2(tenm_object * my,tenm_object * your)441 deal_damage2(tenm_object *my, tenm_object *your)
442 {
443   /* sanity check */
444   if (my == NULL)
445   {
446     fprintf(stderr, "deal_damage: my is NULL\n");
447     return 0;
448   }
449   if (your == NULL)
450   {
451     fprintf(stderr, "deal_damage: your is NULL\n");
452     return 0;
453   }
454 
455   if (my->hit_point <= your->hit_point)
456   {
457     add_score(my->hit_point - 1);
458     my->hit_point = 0;
459   }
460   else
461   {
462     add_score(your->hit_point);
463     my->hit_point -= your->hit_point;
464   }
465 
466   return 0;
467 }
468