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