1 /**
2 * @file spaceship.c
3 * @brief Handle the player's spaceship
4 * @date 2012-08-25
5 * @author Jean-Michel Martin de Santero
6 * @author Bruno Ethvignot
7 */
8 /*
9 * copyright (c) 1998-2015 TLK Games all rights reserved
10 * $Id: spaceship.c,v 1.36 2012/08/25 15:55:00 gurumeditation Exp $
11 *
12 * Powermanga is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 3 of the License, or
15 * (at your option) any later version.
16 *
17 * Powermanga is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
25 * MA 02110-1301, USA.
26 */
27 #include "config.h"
28 #include "powermanga.h"
29 #include "tools.h"
30 #include "images.h"
31 #include "display.h"
32 #include "electrical_shock.h"
33 #include "enemies.h"
34 #include "energy_gauge.h"
35 #include "explosions.h"
36 #include "shots.h"
37 #include "extra_gun.h"
38 #include "gfx_wrapper.h"
39 #include "satellite_protections.h"
40 #include "menu.h"
41 #include "menu_sections.h"
42 #include "log_recorder.h"
43 #include "options_panel.h"
44 #include "sdl_mixer.h"
45 #include "spaceship.h"
46 #include "starfield.h"
47
48 /** Maximum number of images peer spaceship */
49 #define SPACESHIP_MAX_OF_IMAGES 5
50 /** Differents players (always one player) */
51 typedef enum
52 {
53 PLAYER_1,
54 /* never used */
55 PLAYER_2,
56 /** Maximum of players */
57 MAX_OF_PLAYERS
58 } PLAYERS_ENUM;
59 /** The player has lost his spaceship */
60 bool spaceship_is_dead = FALSE;
61 /** If TRUE spaceship disappearing */
62 bool spaceship_disappears = FALSE;
63 /** Time counter of the appearance of the player's spaceship */
64 Sint32 spaceship_appears_count = 0;
65 /** Counter delay of the the increase of the energy level */
66 static Sint32 energy_restore_delay = 0;
67 /** Data structures of the images's spaceship */
68 static image
69 spaceships_sprites[SPACESHIP_NUM_OF_TYPES][SPACESHIP_MAX_OF_IMAGES];
70 /** Data structures of the players spaceships */
71 static spaceship_struct spaceships[MAX_OF_PLAYERS];
72
73 /**
74 * Load sprites images and initialize structure of the player's spaceship
75 * @return TRUE if successful
76 */
77 bool
spaceship_once_init(void)78 spaceship_once_init (void)
79 {
80 Uint32 type, frame;
81 char *filename;
82 const char *model =
83 "graphics/sprites/spaceships/spaceship_%01d_frame_%1d.spr";
84 spaceship_struct *ship = spaceship_get ();
85 spaceship_free ();
86
87 /* allocate a temporary string */
88 filename = memory_allocation (strlen (model) + 1);
89 if (filename == NULL)
90 {
91 LOG_ERR ("not enough memory to allocate %i bytes",
92 (Uint32) (strlen (model) + 1));
93 return FALSE;
94 }
95
96 /* extract all sprites images of the player's spaceship */
97 for (type = 0; type < SPACESHIP_NUM_OF_TYPES; type++)
98 {
99 for (frame = 0; frame < SPACESHIP_MAX_OF_IMAGES; frame++)
100 {
101 sprintf (filename, model, type + 1, frame);
102 if (!image_load_single (filename, &spaceships_sprites[type][frame]))
103 {
104 free_memory (filename);
105 return FALSE;
106 }
107 }
108 }
109 free_memory (filename);
110 spaceship_initialize ();
111 ship->gems_count = 0;
112 return TRUE;
113 }
114
115 /**
116 * Convert from data image to PNG file
117 * @return TRUE if successful
118 */
119 #ifdef PNG_EXPORT_ENABLE
120 bool
spaceship_extract(void)121 spaceship_extract (void)
122 {
123 Uint32 type, frame;
124 const char *model = EXPORT_DIR "/ships/ship-%01d/ship-%01d.png";
125 char *filename = memory_allocation (strlen (model) + 1);
126 if (filename == NULL)
127 {
128 LOG_ERR ("not enough memory to allocate %i bytes\n",
129 (Uint32) (strlen (model) + 1));
130 return FALSE;
131 }
132 if (!create_dir (EXPORT_DIR "/ships"))
133 {
134 free_memory (filename);
135 return FALSE;
136 }
137 for (type = 0; type < SPACESHIP_NUM_OF_TYPES; type++)
138 {
139 sprintf (filename, EXPORT_DIR "/ships/ship-%01d", type + 1);
140 if (!create_dir (filename))
141 {
142 return FALSE;
143 }
144 for (frame = 0; frame < SPACESHIP_MAX_OF_IMAGES; frame++)
145 {
146 sprintf (filename, EXPORT_DIR "/ships/ship-%01d/ship-%01d.png",
147 type + 1, frame);
148 if (!image_to_png (&spaceships_sprites[type][frame], filename))
149 {
150 free_memory (filename);
151 return FALSE;
152 }
153 }
154 }
155 free_memory (filename);
156 return TRUE;
157 }
158 #endif
159
160 /**
161 * Release sprites images and of the player's spaceship
162 * @return TRUE if successful
163 */
164 void
spaceship_free(void)165 spaceship_free (void)
166 {
167 images_free (&spaceships_sprites[0][0], SPACESHIP_NUM_OF_TYPES,
168 SPACESHIP_MAX_OF_IMAGES, SPACESHIP_MAX_OF_IMAGES);
169 }
170
171
172 /**
173 * Return the current player's spaceship
174 * @return Pointer to a spaceship structure
175 */
176 spaceship_struct *
spaceship_get(void)177 spaceship_get (void)
178 {
179 return &spaceships[PLAYER_1];
180 }
181
182 /**
183 * Restores the energy level of the player's spaceship
184 */
185 void
spaceship_energy_restore(void)186 spaceship_energy_restore (void)
187 {
188 spaceship_struct *ship = spaceship_get ();
189 if (gameover_enable || player_pause || menu_status != MENU_OFF)
190 {
191 return;
192 }
193
194 /* increase the energie level of spaceship? */
195 energy_restore_delay += (SPACESHIP_NUM_OF_TYPES - ship->type);
196 if (energy_restore_delay < 150)
197 {
198 return;
199 }
200
201 /* clear counter delay */
202 energy_restore_delay = 0;
203 /* level reach maximum? */
204 if (ship->spr.energy_level < ship->spr.pow_of_dest)
205 {
206 /* increase level */
207 ship->spr.energy_level++;
208 /* maximum energy level: close option box */
209 if (ship->spr.energy_level >= ship->spr.pow_of_dest)
210 {
211 option_anim_init (OPTION_PANEL_REPAIR, TRUE);
212 }
213 /* refresh gauge of energy level */
214 energy_gauge_spaceship_is_update = TRUE;
215 }
216 }
217
218 /**
219 * Handle the temporary invincibility of the player's spaceship
220 */
221 void
spaceship_invincibility(void)222 spaceship_invincibility (void)
223 {
224 Sint32 coordx, coordy;
225 spaceship_struct *ship = spaceship_get ();
226
227 /* spaceship is invincibile? */
228 if (ship->invincibility_delay <= 0)
229 {
230 /* no, spaceship is not invincibile */
231 return;
232 }
233 ship->invincibility_count--;
234
235 /* spaceship is visible? */
236 if (ship->is_visible)
237 {
238 if (ship->invincibility_count <= 0)
239 {
240 /* player's spaceship must become invisible */
241 ship->is_visible = FALSE;
242 ship->invincibility_count = ship->invincibility_delay;
243 }
244 return;
245 }
246
247
248 /*
249 * player's spaceship is not visible
250 */
251 if (ship->invincibility_count <= 0)
252 {
253 /* player's spaceship must become visible */
254 ship->is_visible = TRUE;
255 /* invincibility duration is decreased by one */
256 if (!player_pause && menu_status == MENU_OFF)
257 ship->invincibility_delay--;
258 /* spaceship always invincible? */
259 if (ship->invincibility_delay <= 0)
260 {
261 ship->is_visible = TRUE;
262 /* no change of the spaceship must take place */
263 ship->has_just_upgraded = FALSE;
264 }
265 else
266 {
267 /* spaceship is always invincible */
268 ship->invincibility_count = ship->invincibility_delay;
269 }
270 }
271
272 /* add a star in the explosions list */
273 coordx =
274 (Sint32) ship->spr.xcoord +
275 (Sint32) (((Sint32) rand () %
276 (ship->spr.img[ship->spr.current_image]->w + 16))) - 16;
277 coordy =
278 (Sint32) ship->spr.ycoord +
279 (Sint32) (((Sint32) rand () %
280 (ship->spr.img[ship->spr.current_image]->h + 16))) - 8;
281 if (coordx >= offscreen_clipsize
282 && coordx <= (offscreen_clipsize + offscreen_width_visible)
283 && ship->has_just_upgraded && coordy >= offscreen_clipsize
284 && coordy <= (offscreen_clipsize + offscreen_height_visible))
285 explosion_add ((float) coordx, (float) coordy, 0.7f, STAR_SPACESHIP, 0);
286 }
287
288 /**
289 * Initialise the spaceship structure
290 */
291 void
spaceship_initialize(void)292 spaceship_initialize (void)
293 {
294 Uint32 i;
295 spaceship_struct *ship = spaceship_get ();
296
297 /* the number of bonus collected */
298 ship->gems_count = 4;
299 /* clear number of satellite protections */
300 ship->num_of_satellites = 0;
301 /* clear number of extra guns */
302 ship->num_of_extraguns = 0;
303 /* the first basic spaceship */
304 ship->type = SPACESHIP_TYPE_1;
305
306 /* test only */
307 /* ship->type = SPACESHIP_TYPE_4; */
308
309 /* rate of fire */
310 ship->fire_rate = 50 - (ship->type * 5 + 5);
311 /* speed of the displacement */
312 ship->speed_booster = 2;
313 /* enable front shot force 1 */
314 ship->shot_front_basic = 1;
315 /* disable left shot force 1 */
316 ship->shot_left_basic = 0;
317 /* disable left right force 1 */
318 ship->shot_right_basic = 0;
319 /* disable rear shot force 1 */
320 ship->shot_rear_basic = 0;
321 /* disable front shot force 2 */
322 ship->shot_front_enhanced = 0;
323 /* disable rear shot force 2 */
324 ship->shot_rear_enhanced = 0;
325 /* disable left right force 2 */
326 ship->shot_right_enhanced = 0;
327 /* disable left shot force 2 */
328 ship->shot_left_enhanced = 0;
329
330 /*
331 * initialize sprite data structute
332 */
333 /* indicate that is friend sprite */
334 ship->spr.type = FRIEND;
335 /* trajectory of sprite is calculated */
336 ship->spr.trajectory = 1;
337 /* set power of the destruction */
338 ship->spr.pow_of_dest = (Sint16) (ship->type * 20 + 20);
339 /* set the spaceship's energie level */
340 ship->spr.energy_level = ship->spr.pow_of_dest;
341 /* number of images of the sprite */
342 ship->spr.numof_images = SPACESHIP_MAX_OF_IMAGES;
343 /* set current image index */
344 ship->spr.current_image = 2;
345 /* set value of delay between two images */
346 ship->spr.anim_speed = 10;
347 /* clear counter of delay between two images */
348 ship->spr.anim_count = 0;
349 /* no change of the spaceship must take place */
350 ship->has_just_upgraded = FALSE;
351 /* set addresses of the sprites images buffer */
352 for (i = 0; i < SPACESHIP_MAX_OF_IMAGES; i++)
353 {
354 ship->spr.img[i] = (image *) & spaceships_sprites[ship->type][i];
355 }
356 }
357
358 /**
359 * Start the appearance of the spaceship
360 */
361 void
spaceship_show(void)362 spaceship_show (void)
363 {
364 spaceship_struct *ship = spaceship_get ();
365 ship->spr.xcoord =
366 (float) (offscreen_width_visible - ship->spr.img[2]->w / 2);
367 ship->spr.ycoord = (float) (offscreen_starty - 32);
368 /* vertical speed */
369 ship->y_speed = 1.2f;
370 /* horizontal speed */
371 ship->x_speed = 0.0;
372 spaceship_appears_count = 90;
373 spaceship_disappears = FALSE;
374 }
375
376 /**
377 * First basic spaceship was destroyed, enable the game over
378 */
379 void
spaceship_gameover(void)380 spaceship_gameover (void)
381 {
382 float coordx, coordy;
383 image *ship_img;
384 spaceship_struct *ship = spaceship_get ();
385 ship_img = ship->spr.img[ship->spr.current_image];
386 /* sort the scores and prepares display */
387 menu_section_set (SECTION_GAME_OVER);
388
389 /* add a serie of explosions */
390 explosions_add_serie (NULL);
391
392 /* add many explosions fragments */
393 coordx = ship->spr.xcoord + ship_img->x_gc - 8 * pixel_size;
394 coordy = ship->spr.ycoord + ship_img->y_gc - 8 * pixel_size;
395 explosions_fragments_add (coordx, coordy, 0.5, 5, 0, 3);
396 explosions_fragments_add (coordx, coordy, 1.0, 5, 0, 2);
397 explosions_fragments_add (coordx, coordy, 1.5, 5, 0, 1);
398
399 /* display "GAME OVER" sprites text */
400 gameover_enable = TRUE;
401 /* player's spaceship make invisible */
402 ship->is_visible = FALSE;
403 /* close all options boxes on the right options panel */
404 options_close_all ();
405 /* clear the number of bonus collected */
406 ship->gems_count = 0;
407 /* clear keyboard flags */
408 clear_keymap ();
409 #ifdef USE_SDLMIXER
410 /* play introduction music */
411 sound_music_play (MUSIC_INTRO);
412 #endif
413 }
414
415 /**
416 * Handle the loss and the regression of the spaceship or cause the end
417 * of the game
418 */
419 void
spaceship_downgrading(void)420 spaceship_downgrading (void)
421 {
422 Uint32 i;
423 spaceship_struct *ship = spaceship_get ();
424 if (!spaceship_is_dead || gameover_enable || menu_section != 0)
425 {
426 return;
427 }
428 /* go back to the ship of the previous level */
429 if (ship->type != SPACESHIP_TYPE_1)
430 {
431 ship->type--;
432 #ifdef USE_SDLMIXER
433 sound_play (SOUND_DOWNGRADE_SPACESHIP);
434 #endif
435 /* change of spaceship */
436 ship->has_just_upgraded = TRUE;
437 /* set rate of fire */
438 ship->fire_rate = 50 - (ship->type * 5 + 5);
439 /* set power of the destruction */
440 ship->spr.pow_of_dest = (Sint16) (ship->type * 20 + 20);
441 /* set energy level of the spaceship */
442 ship->spr.energy_level = ship->spr.pow_of_dest;
443 /* clear the score multiplier */
444 score_multiplier = 0;
445 if (!option_boxes[OPTION_PANEL_REPAIR].close_option)
446 {
447 /* close "spaceship repair" option box */
448 option_anim_init (OPTION_PANEL_REPAIR, TRUE);
449 }
450 if (option_boxes[OPTION_PANEL_NEW_SPACESHIP].close_option)
451 {
452 /* open "change of spaceship" option box */
453 option_anim_init (OPTION_PANEL_NEW_SPACESHIP, FALSE);
454 }
455 ship->invincibility_delay = SPACESHIP_INVINCIBILITY_TIME;
456 /* update spaceship's energy gauge */
457 energy_gauge_spaceship_is_update = TRUE;
458 spaceship_is_dead = FALSE;
459 /* set addresses of the sprites images buffer */
460 for (i = 0; i < SPACESHIP_MAX_OF_IMAGES; i++)
461 {
462 ship->spr.img[i] = (image *) & spaceships_sprites[ship->type][i];
463 }
464 /* remove protection satellites */
465 satellites_init ();
466 /* remove extra guns */
467 guns_init ();
468 }
469 else
470 {
471 /* it was the first basic spaceship, the game is over */
472 spaceship_gameover ();
473 }
474 }
475
476 /**
477 * Set invincibility counter of the player's spaceship
478 * @param invincibility Invincibility counter time
479 */
480 void
spaceship_set_invincibility(Sint16 invincibility)481 spaceship_set_invincibility (Sint16 invincibility)
482 {
483 spaceship_struct *ship = spaceship_get ();
484 ship->invincibility_delay = invincibility;
485 }
486
487 /**
488 * Control movements of the player's spaceship
489 */
490 void
spaceship_control_movements(void)491 spaceship_control_movements (void)
492 {
493 spaceship_struct *ship = spaceship_get ();
494 if (spaceship_appears_count <= 0 && !spaceship_disappears)
495 {
496 if (ship->x_speed >= 0.5f)
497 {
498 ship->x_speed -= 0.2f;
499 }
500 if (ship->x_speed <= -0.5f)
501 {
502 ship->x_speed += 0.2f;
503 }
504 if (ship->y_speed >= 0.5f)
505 {
506 ship->y_speed -= 0.2f;
507 }
508 if (ship->y_speed <= -0.5f)
509 {
510 ship->y_speed += 0.2f;
511 }
512 /* player's spaceship is dead? */
513 if (!spaceship_is_dead)
514 {
515 /* keyboard or joystick movement */
516 if (keys_down[K_LEFT] || joy_left)
517 {
518 ship->x_speed -= 0.5f;
519 }
520 if (keys_down[K_RIGHT] || joy_right)
521 {
522 ship->x_speed += 0.5f;
523 }
524 if (keys_down[K_UP] || joy_top)
525 {
526 ship->y_speed -= 0.5f;
527 }
528 if (keys_down[K_DOWN] || joy_down)
529 {
530 ship->y_speed += 0.5f;
531 }
532 if (keys_down[K_CTRL] && keys_down[K_Q])
533 {
534 /* [Crtl]+[Q] force "game over" */
535 spaceship_gameover ();
536 }
537 }
538 }
539 else
540 {
541 if (ship->x_speed >= 0.5f)
542 {
543 ship->x_speed -= 0.4f;
544 }
545 if (ship->x_speed <= -0.5f)
546 {
547 ship->x_speed += 0.4f;
548 }
549 if (ship->y_speed >= 0.5f)
550 {
551 ship->y_speed -= 0.01f;
552 }
553 if (ship->y_speed <= -0.5f)
554 {
555 ship->y_speed += 0.01f;
556 }
557 }
558 }
559
560
561 /**
562 * Get the more powerfull spaceship
563 */
564 void
spaceship_most_powerfull(void)565 spaceship_most_powerfull (void)
566 {
567 spaceship_struct *ship = spaceship_get ();
568 ship->shot_front_basic = 5;
569 ship->shot_left_basic = 5;
570 ship->shot_right_basic = 5;
571 ship->shot_rear_basic = 5;
572 ship->shot_front_enhanced = 5;
573 ship->shot_rear_enhanced = 5;
574 ship->shot_right_enhanced = 5;
575 ship->shot_left_enhanced = 5;
576 while (spaceship_upgrading ())
577 {
578 }
579 energy_gauge_spaceship_is_update = TRUE;
580 satellites_add ();
581 electrical_shock_enable = TRUE;
582 while (gun_add ())
583 {
584 }
585 options_close_all ();
586 }
587
588 /**
589 * Get a new spaceship more resistant and more powerful
590 * @return TRUE if the spaceship were upgraded
591 */
592 bool
spaceship_upgrading(void)593 spaceship_upgrading (void)
594 {
595 Uint32 i;
596 spaceship_struct *ship = spaceship_get ();
597 if (ship->type >= (SPACESHIP_NUM_OF_TYPES - 1))
598 {
599 return FALSE;
600 }
601
602 /* get the ship of the next level */
603 ship->type++;
604 /* notice that spaceship change */
605 ship->has_just_upgraded = TRUE;
606 #ifdef USE_SDLMIXER
607 sound_play (SOUND_UPGRADE_SPACESHIP);
608 #endif
609 ship->invincibility_delay = SPACESHIP_INVINCIBILITY_TIME;
610 /* set shot time-frequency */
611 ship->fire_rate = 50 - (ship->type * 5 + 5);
612 /* set addresses of the images buffer */
613 for (i = 0; i < SPACESHIP_MAX_OF_IMAGES; i++)
614 {
615 ship->spr.img[i] = (image *) & spaceships_sprites[ship->type][i];
616 }
617 /* remove protection satellites */
618 satellites_init ();
619 /* remove extra guns */
620 guns_init ();
621 if (ship->spr.energy_level < ship->spr.pow_of_dest)
622 {
623 /* maximum energy level: start anim of closing option box */
624 option_anim_init (OPTION_PANEL_REPAIR, TRUE);
625 }
626 /* set power of the destruction */
627 ship->spr.pow_of_dest = (Sint16) (ship->type * 20 + 20);
628 /* set level of energy */
629 ship->spr.energy_level = ship->spr.pow_of_dest;
630 energy_gauge_spaceship_is_update = TRUE;
631 /* clear the number of bonus collected */
632 ship->gems_count = 0;
633 option_change = TRUE;
634 if (ship->type >= (SPACESHIP_NUM_OF_TYPES - 1))
635 {
636 /* start the closing anim of the spaceship change option box */
637 option_anim_init (OPTION_PANEL_NEW_SPACESHIP, TRUE);
638 }
639 return TRUE;
640 }
641
642 /**
643 * Collisions between the spaceship and an enemy
644 * @param foe pointer to the structure of an enemy
645 * @param speed_x speed to add to spaceship if collision
646 * @param speed_y speed to add to spaceship if collision
647 * @return TRUE if enemy is destroyed
648 */
649 bool
spaceship_enemy_collision(enemy * foe,float speed_x,float speed_y)650 spaceship_enemy_collision (enemy * foe, float speed_x, float speed_y)
651 {
652 Sint32 i, l, x1, y1, x2, y2;
653 image *ship_img, *foe_img;
654 spaceship_struct *ship = spaceship_get ();
655 ship_img = ship->spr.img[ship->spr.current_image];
656 foe_img = foe->spr.img[foe->spr.current_image];
657
658 /* for each collision point of the spaceship */
659 for (i = 0; i < ship_img->numof_collisions_points; i++)
660 {
661 /* coordinates of the collision point of the spaceship */
662 x1 = (Sint32) ship->spr.xcoord + ship_img->collisions_points[i][XCOORD];
663 y1 = (Sint32) ship->spr.ycoord + ship_img->collisions_points[i][YCOORD];
664
665 /* for each collision zone of the enemy */
666 for (l = 0; l < foe_img->numof_collisions_zones; l++)
667 {
668 /* coordinates of the collision zone of the enemy */
669 x2 =
670 (Sint32) foe->spr.xcoord + foe_img->collisions_coords[l][XCOORD];
671 y2 =
672 (Sint32) foe->spr.ycoord + foe_img->collisions_coords[l][YCOORD];
673
674 /* check if spaceship collision point is into enemy collision zone */
675 if (x1 < x2 ||
676 y1 < y2 ||
677 x1 >= x2 + foe_img->collisions_sizes[l][IMAGE_WIDTH] ||
678 y1 >= y2 + foe_img->collisions_sizes[l][IMAGE_HEIGHT])
679 {
680 continue;
681 }
682 /* decrease energy level of enemy */
683 foe->spr.energy_level -= (ship->spr.pow_of_dest << 1);
684 if (foe->type >= THANIKEE)
685 {
686 energy_gauge_guard_is_update = TRUE;
687 }
688 /* spaceship is it invincible? */
689 if (!ship->invincibility_delay)
690 {
691 if (ship->spr.energy_level == ship->spr.pow_of_dest)
692 {
693 /* energy level was full, start anim of opening option box */
694 option_anim_init (OPTION_PANEL_REPAIR, FALSE);
695 }
696 /* decrease energy level of satellite */
697 ship->spr.energy_level =
698 (Sint16) (ship->spr.energy_level - foe->spr.pow_of_dest);
699 }
700 /* update spaceship's energy gauge */
701 energy_gauge_spaceship_is_update = TRUE;
702 if (ship->spr.energy_level <= 0)
703 {
704 /* spaceship is destroyed: game over */
705 spaceship_is_dead = TRUE;
706 }
707 else
708 {
709 /* spaceship not destroyed, display white mask */
710 ship->is_white_mask_displayed = TRUE;
711 }
712 /* add enemy speed of displacement to spaceship */
713 ship->x_speed += speed_x;
714 ship->y_speed += speed_y;
715
716 /* check if enemy is destroyed */
717 if (foe->spr.energy_level <= 0)
718 {
719 /* update player's score */
720 player_score += foe->spr.pow_of_dest << 2 << score_multiplier;
721 return TRUE;
722 }
723 else
724 {
725 /* draw the sprite mask with a white color */
726 foe->is_white_mask_displayed = TRUE;
727 }
728 return FALSE;
729 }
730 }
731 return FALSE;
732 }
733
734 /**
735 * Collisions between the spaceship and a shot
736 * @param x1 x coordinate of the collision point of the shot
737 * @param y1 y coordinate of the collision point of the shot
738 * @param bullet pointer to the structure of an shot
739 * @return TRUE if the shot touched the spaceship
740 */
741 bool
spaceship_shot_collision(Sint32 x1,Sint32 y1,shot_struct * bullet)742 spaceship_shot_collision (Sint32 x1, Sint32 y1, shot_struct * bullet)
743 {
744 Sint32 i, x2, y2;
745 spaceship_struct *ship = spaceship_get ();
746 image *ship_img = ship->spr.img[ship->spr.current_image];
747
748 for (i = 0; i < ship_img->numof_collisions_zones; i++)
749 {
750 x2 = (Sint32) ship->spr.xcoord + ship_img->collisions_coords[i][XCOORD];
751 y2 = (Sint32) ship->spr.ycoord + ship_img->collisions_coords[i][YCOORD];
752
753 /* check if shot collision point is into spaceship collision zone */
754 if (x1 < x2
755 || x1 >= x2 + ship_img->collisions_sizes[i][IMAGE_WIDTH]
756 || y1 < y2
757 || y1 >= y2 + ship_img->collisions_sizes[i][IMAGE_HEIGHT])
758 {
759 continue;
760 }
761 /* spaceship is it invincible? */
762 if (!ship->invincibility_delay)
763 {
764 if (ship->spr.energy_level == ship->spr.pow_of_dest)
765 {
766 /* energy level was full, start anim
767 * of opening option box */
768 option_anim_init (OPTION_PANEL_REPAIR, FALSE);
769 }
770 /* decrease energy level of spaceship */
771 ship->spr.energy_level =
772 (Sint16) (ship->spr.energy_level - bullet->spr.pow_of_dest);
773 }
774 /* update spaceship's energy gauge */
775 energy_gauge_spaceship_is_update = TRUE;
776 if (ship->spr.energy_level <= 0)
777 {
778 /* spaceship is destroyed: game over */
779 spaceship_is_dead = TRUE;
780 }
781 else
782 {
783 /* spaceship not destroyed, display white mask */
784 ship->is_white_mask_displayed = TRUE;
785 }
786 explosion_add (bullet->spr.xcoord, bullet->spr.ycoord, 0.35f,
787 EXPLOSION_SMALL, 0);
788 /* remove the shot which has just touched the enemy */
789 return TRUE;
790 }
791 return FALSE;
792 }
793
794 /**
795 * Control the speed of the spaceship
796 */
797 void
spaceship_speed_control(void)798 spaceship_speed_control (void)
799 {
800 spaceship_struct *ship = spaceship_get ();
801
802 /* limit maximum right speed of the spaceship */
803 if (ship->x_speed >= (float) ship->speed_booster)
804 {
805 /* max. right speed */
806 ship->x_speed = (float) ship->speed_booster;
807 /* all on the right displacement image */
808 ship->spr.current_image = 4;
809 }
810 else
811 {
812 if (ship->x_speed > 0)
813 {
814 /* right displacement image */
815 ship->spr.current_image = 3;
816 }
817 }
818 if (ship->x_speed <= (float) (-ship->speed_booster))
819 {
820 /* max. left speed */
821 ship->x_speed = (float) (-ship->speed_booster);
822 /* all on the left displacement image */
823 ship->spr.current_image = 0;
824 }
825 else
826 {
827 if (ship->x_speed < 0)
828 {
829 /* left displacement image */
830 ship->spr.current_image = 1;
831 }
832 }
833 /* limit maximum right speed of the spaceship */
834 if (spaceship_appears_count <= 0 && !spaceship_disappears)
835 {
836 if (ship->y_speed > ship->speed_booster)
837 {
838 ship->y_speed = (float) ship->speed_booster;
839 }
840 if (ship->y_speed < (-ship->speed_booster))
841 {
842 ship->y_speed = (float) (-ship->speed_booster);
843 }
844 }
845 if (!player_pause && menu_status == MENU_OFF
846 && menu_section == NO_SECTION_SELECTED)
847 {
848 /* change x and y coordinates */
849 ship->spr.xcoord += ship->x_speed;
850 ship->spr.ycoord += ship->y_speed;
851 if (ship->spr.ycoord < (float) (offscreen_starty - 100))
852 {
853 ship->spr.ycoord = (float) (offscreen_starty - 100);
854 }
855 }
856
857 /* limit minimum speed */
858 if (fabs (ship->x_speed) < 0.5)
859 {
860 ship->x_speed = 0.0;
861 /* center image of the spaceship */
862 ship->spr.current_image = 2;
863 }
864
865 /* spacheship is affected by gravity, and fall to the bottom of the screen */
866 if (spaceship_appears_count <= 0 && !spaceship_disappears)
867 {
868 if (!player_pause && menu_status == MENU_OFF
869 && menu_section == NO_SECTION_SELECTED)
870 {
871 {
872 if (!keys_down[K_DOWN] && !keys_down[K_UP] && !joy_top
873 && !joy_down)
874 if (ship->y_speed <= 0.2f)
875 {
876 ship->y_speed += 0.025f;
877 }
878 }
879 }
880
881 /* clip position of the player's spacheship */
882 if ((Sint16) ship->spr.xcoord < 128)
883 {
884 ship->spr.xcoord = 128.0;
885 ship->x_speed = 0.0;
886 }
887 if (((Sint16) ship->spr.xcoord +
888 (Sint16) ship->spr.img[ship->spr.current_image]->w) >
889 128 + offscreen_width_visible)
890 {
891 ship->spr.xcoord =
892 (float) (offscreen_width_visible + 128.0f -
893 ship->spr.img[ship->spr.current_image]->w);
894 ship->x_speed = 0.0f;
895 }
896 if ((Sint16) ship->spr.ycoord < 128)
897 {
898 ship->spr.ycoord = 128.0;
899 ship->y_speed = 0.0;
900 }
901 if (((Sint16) ship->spr.ycoord +
902 (Sint16) ship->spr.img[ship->spr.current_image]->h) >
903 128 + offscreen_height_visible)
904 {
905 ship->spr.ycoord =
906 (float) (offscreen_height_visible + 128.0f -
907 ship->spr.img[ship->spr.current_image]->h);
908 ship->y_speed = 0.0f;
909 }
910 }
911 }
912
913 /**
914 * Draw the player spaceship
915 */
916 void
spaceship_draw(void)917 spaceship_draw (void)
918 {
919 spaceship_struct *ship = spaceship_get ();
920 /* draw the player spaceship */
921 if (gameover_enable || !ship->is_visible)
922 {
923 return;
924 }
925
926 if (((Sint16) ship->spr.ycoord +
927 ship->spr.img[ship->spr.current_image]->h) >= offscreen_clipsize)
928 {
929 /* display white mask of the sprite */
930 if (ship->is_white_mask_displayed)
931 {
932 draw_sprite_mask (coulor[WHITE],
933 ship->spr.img[ship->spr.current_image],
934 (Sint32) (ship->spr.xcoord),
935 (Sint32) (ship->spr.ycoord));
936 ship->is_white_mask_displayed = FALSE;
937 }
938 /* display the sprite normally */
939 else
940 {
941 draw_sprite (ship->spr.img[ship->spr.current_image],
942 (Uint32) ship->spr.xcoord, (Uint32) ship->spr.ycoord);
943 }
944 }
945 }
946