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