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