1 /* $Id: laser.c,v 1.51 2004/08/13 15:27:39 oohara Exp $ */
2 
3 #include <stdio.h>
4 /* malloc, rand */
5 #include <stdlib.h>
6 
7 #include "const.h"
8 #include "tenm_object.h"
9 #include "tenm_math.h"
10 #include "tenm_graphic.h"
11 #include "util.h"
12 #include "tenm_primitive.h"
13 
14 #include "laser.h"
15 
16 #define NEAR_ZERO 0.0001
17 
18 static int laser_move(tenm_object *my, double turn_per_frame);
19 static int laser_act(tenm_object *my, const tenm_object *player);
20 static int laser_draw(tenm_object *my, int priority);
21 
22 /* speed must be positive --- use laser_new instead if you want a laser
23  * that doesn't move
24  */
25 tenm_object *
laser_angle_new(double x,double y,double speed,int theta,double length,int color)26 laser_angle_new(double x, double y, double speed, int theta,
27                 double length, int color)
28 {
29   /* sanity check */
30   if (speed < NEAR_ZERO)
31   {
32     fprintf(stderr, "laser_angle_new: speed is non-positive (%f)\n",
33             speed);
34     return NULL;
35   }
36   if (length <= NEAR_ZERO)
37   {
38     fprintf(stderr, "laser_angle_new: length is non-positive (%f)\n",
39             length);
40     return NULL;
41   }
42 
43   return laser_new(x, y,
44                    speed * tenm_cos(theta),
45                    speed * tenm_sin(theta),
46                    length * tenm_cos(theta),
47                    length * tenm_sin(theta),
48                    color, -2, 0);
49 }
50 
51 /* speed must be positive --- use laser_new instead if you want a laser
52  * that doesn't move
53  * if (x, y) and (target_x, target_y) are very close, shoot at a random
54  * direction
55  */
56 tenm_object *
laser_point_new(double x,double y,double speed,double target_x,double target_y,double length,int color)57 laser_point_new(double x, double y, double speed,
58                 double target_x, double target_y,
59                 double length, int color)
60 {
61   double dx;
62   double dy;
63   double temp;
64   int temp_theta;
65 
66   /* sanity check */
67   if (speed < NEAR_ZERO)
68   {
69     fprintf(stderr, "laser_point_new: speed is non-positive (%f)\n", speed);
70     return NULL;
71   }
72   if (length <= NEAR_ZERO)
73   {
74     fprintf(stderr, "laser_point_new: length is non-positive (%f)\n", length);
75     return NULL;
76   }
77 
78   dx = target_x - x;
79   dy = target_y - y;
80   temp = tenm_sqrt((int) (dx * dx + dy * dy));
81   if (temp <= NEAR_ZERO)
82   {
83     /* shoot at a random direction */
84     temp_theta = rand() % 360;
85     dx = tenm_cos(temp_theta);
86     dy = tenm_sin(temp_theta);
87     temp = 1.0;
88   }
89 
90   return laser_new(x, y,
91                    speed * dx / temp,
92                    speed * dy / temp,
93                    length * dx / temp,
94                    length * dy / temp,
95                    color, -2, 0);
96 }
97 
98 /* list of count
99  * [0] color
100  * [1] life
101  */
102 /* list of count_d
103  * [0] speed x
104  * [1] speed y
105  */
106 /* if life > 0 when created, the shot disappears after _life frames
107  * when immortal > 0, the shot does not disappear even if
108  * it is out of the window
109  */
110 tenm_object *
laser_new(double x,double y,double speed_x,double speed_y,double length_x,double length_y,int color,int life,int immortal_time)111 laser_new(double x, double y, double speed_x, double speed_y,
112           double length_x, double length_y,
113           int color, int life, int immortal_time)
114 {
115   tenm_primitive **p = NULL;
116   tenm_object *new = NULL;
117   int *count = NULL;
118   double *count_d = NULL;
119 
120   /* sanity check */
121   if (life == 0)
122   {
123     fprintf(stderr, "laser_new: life is 0\n");
124     return NULL;
125   }
126 
127   p = (tenm_primitive **) malloc(sizeof(tenm_primitive *) * 1);
128   if (p == NULL)
129   {
130     fprintf(stderr, "laser_new: malloc(p) failed\n");
131     return NULL;
132   }
133 
134   p[0] = (tenm_primitive *) tenm_segment_new(x, y,
135                                              x + length_x, y + length_y);
136   if (p[0] == NULL)
137   {
138     fprintf(stderr, "laser_new: cannot set p[0]\n");
139     free(p);
140     return NULL;
141   }
142 
143   count = (int *) malloc(sizeof(int) * 3);
144   if (count == NULL)
145   {
146     fprintf(stderr, "laser_new: malloc(count) failed\n");
147     (p[0])->delete(p[0]);
148     free(p);
149     return NULL;
150   }
151   count_d = (double *) malloc(sizeof(double) * 2);
152   if (count_d == NULL)
153   {
154     fprintf(stderr, "laser_new: malloc(count_d) failed\n");
155     free(count);
156     (p[0])->delete(p[0]);
157     free(p);
158     return NULL;
159   }
160 
161   count[0] = color;
162   count[1] = life;
163   count[2] = immortal_time;
164 
165   count_d[0] = speed_x;
166   count_d[1] = speed_y;
167 
168   new = tenm_object_new("laser", ATTR_ENEMY_SHOT, 0,
169                         1, x, y,
170                         3, count, 2, count_d, 1, p,
171                         (int (*)(tenm_object *, double)) (&laser_move),
172                         NULL,
173                         (int (*)(tenm_object *, const tenm_object *))
174                         (&laser_act),
175                         (int (*)(tenm_object *, int)) (&laser_draw));
176   if (new == NULL)
177   {
178     fprintf(stderr, "laser_new: tenm_object_new failed\n");
179     free(count_d);
180     free(count);
181     (p[0])->delete(p[0]);
182     free(p);
183     return NULL;
184   }
185 
186   return new;
187 }
188 
189 static int
laser_move(tenm_object * my,double turn_per_frame)190 laser_move(tenm_object *my, double turn_per_frame)
191 {
192   double dx_temp;
193   double dy_temp;
194 
195   /* sanity check */
196   if (my == NULL)
197   {
198     fprintf(stderr, "laser_move: my is NULL\n");
199     return 0;
200   }
201   if (turn_per_frame <= 0.5)
202   {
203     fprintf(stderr, "laser_move: strange turn_per_frame (%f)\n",
204             turn_per_frame);
205     return 0;
206   }
207 
208   dx_temp = my->count_d[0] / turn_per_frame;
209   dy_temp = my->count_d[1] / turn_per_frame;
210   my->x += dx_temp;
211   my->y += dy_temp;
212   tenm_move_mass(my->mass, dx_temp, dy_temp);
213 
214   if ((my->count[2] <= 0) && (!in_window_object(my)))
215     return 1;
216   return 0;
217 }
218 
219 static int
laser_act(tenm_object * my,const tenm_object * player)220 laser_act(tenm_object *my, const tenm_object *player)
221 {
222   /* sanity check */
223   if (my == NULL)
224   {
225     fprintf(stderr, "laser_act: my is NULL\n");
226     return 0;
227   }
228   /* player == NULL is OK */
229 
230   if (my->count[1] > 0)
231   {
232     (my->count[1])--;
233     if (my->count[1] <= 0)
234       return 1;
235   }
236 
237   if (my->count[2] > 0)
238     (my->count[2])--;
239 
240   return 0;
241 }
242 
243 static int
laser_draw(tenm_object * my,int priority)244 laser_draw(tenm_object *my, int priority)
245 {
246   int status = 0;
247   tenm_color color;
248 
249   /* sanity check */
250   if (my == NULL)
251   {
252     fprintf(stderr, "laser_draw: my is NULL\n");
253     return 0;
254   }
255   if (my->mass == NULL)
256   {
257     fprintf(stderr, "laser_draw: my->mass is NULL\n");
258     return 0;
259   }
260 
261   /* return if it is not my turn */
262   if (priority != 1)
263     return 0;
264 
265   switch (my->count[0])
266   {
267   case 0:
268     color = tenm_map_color(49, 191, 0);
269     color = tenm_map_color(0, 223, 55);
270     color = tenm_map_color(0, 191, 47);
271     break;
272   case 1:
273     color = tenm_map_color(0, 223, 55);
274     color = tenm_map_color(0, 191, 127);
275     break;
276   case 2:
277     color = tenm_map_color(0, 191, 255);
278     color = tenm_map_color(0, 167, 223);
279     break;
280   case 3:
281     color = tenm_map_color(0, 127, 255);
282     color = tenm_map_color(0, 111, 223);
283     break;
284   case 4:
285     color = tenm_map_color(70, 0, 223);
286     color = tenm_map_color(75, 0, 239);
287     break;
288   case 5:
289     color = tenm_map_color(163, 0, 223);
290     color = tenm_map_color(175, 0, 239);
291     break;
292   default:
293     fprintf(stderr, "laser_draw: strange my->count[0] (%d)\n", my->count[0]);
294     color = tenm_map_color(0, 0, 0);
295     break;
296   }
297 
298   /* width > 1 costs much, but width = 1 looks too bad */
299   if (tenm_draw_line((int) (((tenm_segment *) my->mass->p[0])->a->x),
300                      (int) (((tenm_segment *) my->mass->p[0])->a->y),
301                      (int) (((tenm_segment *) my->mass->p[0])->b->x),
302                      (int) (((tenm_segment *) my->mass->p[0])->b->y),
303                      3, color) != 0)
304     status = 1;
305   /*
306   if (tenm_draw_primitive(my->mass->p[0], tenm_map_color(0, 0, 0)) != 0)
307     status = 1;
308   */
309   return status;
310 }
311