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