1 /**
2  * @file extra_gun.c
3  * @brief Handle extra guns positioned on the sides of the spaceship
4  * @created 2006-11-25
5  * @date 2012-08-25
6  * @author Jean-Michel Martin de Santero
7  * @author Bruno Ethvignot
8  */
9 /*
10  * copyright (c) 1998-2015 TLK Games all rights reserved
11  * $Id: extra_gun.c,v 1.26 2012/08/25 15:55:00 gurumeditation Exp $
12  *
13  * Powermanga is free software; you can redistribute it and/or modify
14  * it under the terms of the GNU General Public License as published by
15  * the Free Software Foundation; either version 3 of the License, or
16  * (at your option) any later version.
17  *
18  * Powermanga is distributed in the hope that it will be useful, but
19  * WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software
25  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
26  * MA  02110-1301, USA.
27  */
28 #include "config.h"
29 #include "powermanga.h"
30 #include "tools.h"
31 #include "images.h"
32 #include "enemies.h"
33 #include "bonus.h"
34 #include "display.h"
35 #include "electrical_shock.h"
36 #include "energy_gauge.h"
37 #include "explosions.h"
38 #include "log_recorder.h"
39 #include "shots.h"
40 #include "extra_gun.h"
41 #include "gfx_wrapper.h"
42 #include "images.h"
43 #include "menu.h"
44 #include "options_panel.h"
45 #include "spaceship.h"
46 
47 /** Maximum number guns active at any time */
48 #define GUNS_MAXOF 2
49 /** Number of types of differents guns */
50 #define GUNS_NUMOF_TYPES 5
51 /** Extra gun sprite's number of images  */
52 #define GUNS_NUMOF_IMAGES 16
53 
54 /**
55  * Structure io the side extra gun
56  */
57 typedef struct gun_struct
58 {
59   /** Display extra gun */
60   bool is_visible;
61   /** Display extra gun's white mask */
62   bool is_white_mask_displayed;
63   /** Power of destruction (collision) */
64   Sint16 pow_of_dest;
65   /** Damage status  (<= 0 destroyed gun) */
66   Sint16 energy_level;
67   /** Number of images of the sprite */
68   Sint16 numof_images;
69   /** Current image index */
70   Sint16 current_image;
71   /** Delay before next image */
72   Sint16 anim_speed;
73   /** Delay's counter */
74   Sint16 anim_count;
75   /** Structures of images extra gun */
76   image *img[IMAGES_MAXOF];
77   /** X-coordinates */
78   Sint32 xcoord;
79   /** Y-coordinates */
80   Sint32 ycoord;
81   /** Shot delay counter */
82   Sint32 fire_rate_count;
83   Sint32 fire_rate;
84   /** 0=right side / 1=left side */
85   Sint32 position;
86   /** Previous element of the chained list */
87   struct gun_struct *previous;
88   /** Next element of the chained list */
89   struct gun_struct *next;
90   /** TRUE if the element is already chained */
91   bool is_enabled;
92 }
93 gun_struct;
94 
95 /** Data structures of all extra guns */
96 static gun_struct *extra_guns = NULL;
97 static gun_struct *gun_first = NULL;
98 static gun_struct *gun_last = NULL;
99 /** Data structure of the sprites images's guns */
100 static image guns_images[GUNS_NUMOF_TYPES][GUNS_NUMOF_IMAGES];
101 static gun_struct *gun_get (void);
102 static void gun_del (gun_struct * egun);
103 
104 /**
105  * Allocate buffers and initialize structure of the extras guns
106  * @return TRUE if it completed successfully or FALSE otherwise
107  */
108 bool
guns_once_init(void)109 guns_once_init (void)
110 {
111   guns_free ();
112 
113   /* extract extra guns sprites images (28,450 bytes) */
114   if (!image_load
115       ("graphics/sprites/extra_guns.spr", &guns_images[0][0],
116        GUNS_NUMOF_TYPES, GUNS_NUMOF_IMAGES))
117     {
118       return FALSE;
119     }
120 
121   /* allocate extra guns data structure */
122   if (extra_guns == NULL)
123     {
124       extra_guns =
125         (gun_struct *) memory_allocation (GUNS_MAXOF * sizeof (gun_struct));
126       if (extra_guns == NULL)
127         {
128           LOG_ERR ("not enough memory to allocate 'gun_struct'");
129           return FALSE;
130         }
131     }
132 
133   guns_init ();
134   return TRUE;
135 }
136 
137 /**
138  * Convert extra guns from data image to PNG file
139  * @return TRUE if successful
140  */
141 #ifdef PNG_EXPORT_ENABLE
142 bool
guns_extract(void)143 guns_extract (void)
144 {
145   Uint32 type, frame;
146   const char *model = EXPORT_DIR "/extra-guns/extra-gun-x/extra-gun-xx.png";
147   char *filename = memory_allocation (strlen (model) + 1);
148   if (filename == NULL)
149     {
150       LOG_ERR ("not enough memory to allocate %i bytes\n",
151                (Uint32) (strlen (model) + 1));
152       return FALSE;
153     }
154   if (!create_dir (EXPORT_DIR "/extra-guns"))
155     {
156       free_memory (filename);
157       return FALSE;
158     }
159   for (type = 0; type < GUNS_NUMOF_TYPES; type++)
160     {
161       sprintf (filename, EXPORT_DIR "/extra-guns/extra-gun-%01d", type + 1);
162       if (!create_dir (filename))
163         {
164           free_memory (filename);
165           return FALSE;
166         }
167       for (frame = 0; frame < GUNS_NUMOF_IMAGES; frame++)
168         {
169           sprintf (filename,
170                    EXPORT_DIR "/extra-guns/extra-gun-%01d/extra-gun-%02d.png",
171                    type + 1, frame);
172           if (!image_to_png (&guns_images[type][frame], filename))
173             {
174               free_memory (filename);
175               return FALSE;
176             }
177         }
178     }
179   free_memory (filename);
180   return TRUE;
181 }
182 #endif
183 
184 /**
185  * Release memory of images and structures used for the etra guns
186  */
187 void
guns_free(void)188 guns_free (void)
189 {
190   if (extra_guns != NULL)
191     {
192       free_memory ((char *) extra_guns);
193       extra_guns = NULL;
194     }
195   images_free (&guns_images[0][0], GUNS_NUMOF_TYPES, GUNS_NUMOF_IMAGES,
196                GUNS_NUMOF_IMAGES);
197 }
198 
199 /**
200  * Initialize structures of the extra guns
201  */
202 void
guns_init(void)203 guns_init (void)
204 {
205   Sint32 i;
206   gun_struct *egun;
207   spaceship_struct *ship = spaceship_get ();
208 
209   /* release all extra guns */
210   for (i = 0; i < GUNS_MAXOF; i++)
211     {
212       egun = &extra_guns[i];
213       egun->is_enabled = FALSE;
214     }
215   /* clear the number of extra guns */
216   ship->num_of_extraguns = 0;
217 }
218 
219 /**
220  * Handle the extra gun positioned on the sides of the player's spaceship
221  */
222 void
guns_handle(void)223 guns_handle (void)
224 {
225   Sint32 i, k, l;
226   gun_struct *egun;
227   shot_struct *bullet;
228   image *egun_img;
229   spaceship_struct *ship = spaceship_get ();
230   egun = gun_first;
231   if (egun == NULL)
232     {
233       return;
234     }
235   for (i = 0; i < ship->num_of_extraguns; i++, egun = egun->next)
236     {
237 #ifdef UNDER_DEVELOPMENT
238       if (egun == NULL && i < (ship->num_of_extraguns - 1))
239         {
240           LOG_ERR ("egun->next is null %i/%i", i, ship->num_of_extraguns);
241           break;
242         }
243 #endif
244       egun_img = egun->img[egun->current_image];
245 
246       /* update vertical coordinate of the gun */
247       egun->ycoord =
248         (Sint16) (ship->spr.ycoord) +
249         ship->spr.img[ship->spr.current_image]->h - egun_img->h;
250 
251       /* update horizontal coordinate of the right gun */
252       if (egun->position == 0)
253         {
254           egun->xcoord =
255             (Sint16) (ship->spr.xcoord) +
256             ship->spr.img[ship->spr.current_image]->w;
257         }
258 
259       /* update horizontal coordinate of the left gun */
260       if (egun->position == 1)
261         {
262           egun->xcoord = (Sint16) (ship->spr.xcoord) - egun_img->w;
263         }
264 
265       if (!player_pause && menu_status == MENU_OFF)
266         {
267           /* decrease counter of delay between two shots */
268           egun->fire_rate_count--;
269           /* check if the satellite fire or not a shot */
270           if (egun->fire_rate_count <= 0)
271             {
272               /* reset counter of delay between two shots */
273               egun->fire_rate_count = egun->fire_rate;
274               /* process each origin of the shot (location of the cannon) */
275               for (k = 0; k < egun_img->numof_cannons; k++)
276                 {
277                   if (num_of_shots < (MAX_OF_SHOTS - 1))
278                     {
279                       /* get a new shot */
280                       bullet = shot_get ();
281                       if (bullet == NULL)
282                         {
283                           break;
284                         }
285                       /* animated sprite (flicker shot) */
286                       bullet->is_blinking = TRUE;
287                       /* indicate that is friend sprite */
288                       bullet->spr.type = FRIEND;
289                       /* fixed trajectory */
290                       bullet->spr.trajectory = 0;
291                       /* set number of images of the sprite */
292                       bullet->spr.numof_images = 32;
293 
294                       /* initialize power of the shot */
295                       switch (ship->type)
296                         {
297                         case SPACESHIP_TYPE_1:
298                           bullet->spr.pow_of_dest = 2;
299                           break;
300                         case SPACESHIP_TYPE_2:
301                           bullet->spr.pow_of_dest = 3;
302                           break;
303                         case SPACESHIP_TYPE_3:
304                           bullet->spr.pow_of_dest = 4;
305                           break;
306                         case SPACESHIP_TYPE_4:
307                           bullet->spr.pow_of_dest = 3;
308                           break;
309                         case SPACESHIP_TYPE_5:
310                           bullet->spr.pow_of_dest = 4;
311                           break;
312                         }
313                       /* set addresses of the sprites images buffer */
314                       for (l = 0; l < bullet->spr.numof_images; l++)
315                         {
316                           /* shot 2 force 1 */
317                           bullet->spr.img[l] = (image *) & fire[V1TN1][l];
318                         }
319                       /* set energy level of the sprite */
320                       bullet->spr.energy_level = bullet->spr.pow_of_dest;
321                       /* set current image index */
322                       bullet->spr.current_image = 0;
323                       /* set value of delay between two images */
324                       bullet->spr.anim_speed = 4;
325                       /* set delay counter between two images */
326                       bullet->spr.anim_count = 0;
327                       bullet->img_angle = egun_img->cannons_angles[k];
328                       bullet->img_old_angle = bullet->img_angle;
329                       /* set x and y coordinates */
330                       bullet->spr.xcoord =
331                         (float) (egun->xcoord +
332                                  egun_img->cannons_coords[k][XCOORD] -
333                                  bullet->spr.img[bullet->img_angle]->x_gc);
334                       bullet->spr.ycoord =
335                         (float) (egun->ycoord +
336                                  egun_img->cannons_coords[k][YCOORD] -
337                                  bullet->spr.img[bullet->img_angle]->y_gc);
338                       bullet->timelife = 400;
339                       /* set angle of the projectile */
340                       bullet->angle = PI_BY_16 * bullet->img_angle;
341                       /* set speed of the displacement */
342                       bullet->spr.speed = 9.0;
343                     }
344                 }
345             }
346         }
347 
348       /* check if the sprite is visible or not */
349       if ((egun->xcoord + egun->img[0]->w) <
350           offscreen_startx
351           || (egun->ycoord + egun->img[0]->h) <
352           offscreen_starty
353           || egun->xcoord >
354           (offscreen_startx + offscreen_width_visible - 1)
355           || egun->ycoord > (offscreen_starty + offscreen_height_visible - 1))
356         {
357           /* extra gun not visible, don't perform the tests of collision */
358           egun->is_visible = FALSE;
359         }
360       else
361         {
362           /* extra gun is visible, perform the tests of collision */
363           egun->is_visible = TRUE;
364           /* increase counter delay between two images */
365           egun->anim_count++;
366           /* value of delay between two images reached? */
367           if (egun->anim_count >= egun->anim_speed)
368             {
369               /* clear counter delay between two images */
370               egun->anim_count = 0;
371               /* flip to the next image */
372               egun->current_image++;
373               /* check if last image has been reached  */
374               if (egun->current_image >= egun->numof_images)
375                 {
376                   /* resets the animation to the first image of the animation
377                    * sequence */
378                   egun->current_image = 0;
379                 }
380             }
381 
382           /* display extra gun */
383           if (egun->is_white_mask_displayed)
384             {
385               draw_sprite_mask (coulor[WHITE], egun->img[egun->current_image],
386                                 egun->xcoord, egun->ycoord);
387               egun->is_white_mask_displayed = 0;
388             }
389           else
390             {
391               draw_sprite (egun->img[egun->current_image], egun->xcoord,
392                            egun->ycoord);
393             }
394         }
395     }
396 }
397 
398 /**
399  * Add an extra gun on the player's spaceship side
400  * @return TRUE if a extra gun was added
401  */
402 bool
gun_add(void)403 gun_add (void)
404 {
405   Sint32 i;
406   gun_struct *egun;
407   spaceship_struct *ship = spaceship_get ();
408   /* get an extra gun, cannot install more than 2 guns */
409   if (ship->num_of_extraguns >= 2)
410     {
411       return FALSE;
412     }
413   /* get new extra gun index */
414   egun = gun_get ();
415   if (egun == NULL)
416     {
417       return FALSE;
418     }
419   /* set level of energy (zero correspond to destruction of the gun) */
420   egun->energy_level = (Sint16) (100 + ship->type * 10);
421   /* set power of the gun's shot */
422   egun->pow_of_dest = (Sint16) (30 + ship->type * 5);
423   /* set number of images of the sprite */
424   egun->numof_images = GUNS_NUMOF_IMAGES;
425   /* set current image */
426   egun->current_image = 0;
427   /* value of delay between two images */
428   egun->anim_speed = 10;
429   /* counter of delay between two images */
430   egun->anim_count = 0;
431   /* set shot time-frequency */
432   egun->fire_rate = 25 - (ship->type << 1);
433   egun->fire_rate_count = egun->fire_rate;
434   /* set addresses of the images buffer */
435   for (i = 0; i < egun->numof_images; i++)
436     {
437       egun->img[i] = (image *) & guns_images[ship->type][i];
438     }
439   /* position the gun on the side of the player's spaceship */
440   switch (ship->num_of_extraguns)
441     {
442     case 1:
443       /* gun's positioned on the right */
444       egun->position = 0;
445       break;
446     case 2:
447       if (gun_first->position == 0)
448         {
449           egun->position = 1;
450         }
451       else
452         {
453           egun->position = 0;
454         }
455       break;
456     }
457   return TRUE;
458 }
459 
460 /**
461  * Check validty of extra_gun chained list
462  */
463 #ifdef UNDER_DEVELOPMENT
464 static void
gun_check_chained_list(void)465 gun_check_chained_list (void)
466 {
467   Uint32 i;
468   gun_struct *egun;
469   spaceship_struct *ship = spaceship_get ();
470   Sint32 count = 0;
471   for (i = 0; i < GUNS_MAXOF; i++)
472     {
473       egun = &extra_guns[i];
474       if (egun->is_enabled)
475         {
476           count++;
477         }
478     }
479   if (count != ship->num_of_extraguns)
480     {
481       LOG_ERR ("Counting of the enabled elements failed!"
482                "count=%i, ship->num_of_extraguns=%i",
483                count, ship->num_of_extraguns);
484     }
485   count = 0;
486   egun = gun_first;
487   do
488     {
489       count++;
490       egun = egun->next;
491     }
492   while (egun != NULL && count <= (GUNS_MAXOF + 1));
493   if (count != ship->num_of_extraguns)
494     {
495       LOG_ERR ("Counting of the next elements failed!"
496                "count=%i, ship->num_of_extraguns=%i", count,
497                ship->num_of_extraguns);
498     }
499   count = 0;
500   egun = gun_last;
501   do
502     {
503       count++;
504       egun = egun->previous;
505     }
506   while (egun != NULL && count <= (GUNS_MAXOF + 1));
507   if (count != ship->num_of_extraguns)
508     {
509       LOG_ERR ("Counting of the previous elements failed!"
510                "count=%i, ship->num_of_extraguns=%i", count,
511                ship->num_of_extraguns);
512     }
513 }
514 #endif
515 
516 /**
517  * Return a free extra gun element
518  * @return Pointer to a gun structure, NULL if not gun available
519  */
520 static gun_struct *
gun_get(void)521 gun_get (void)
522 {
523   Uint32 i;
524   gun_struct *egun;
525   spaceship_struct *ship = spaceship_get ();
526   for (i = 0; i < GUNS_MAXOF; i++)
527     {
528       egun = &extra_guns[i];
529       if (egun->is_enabled)
530         {
531           continue;
532         }
533       egun->is_enabled = TRUE;
534       egun->next = NULL;
535       if (ship->num_of_extraguns == 0)
536         {
537           gun_first = egun;
538           gun_last = egun;
539           gun_last->previous = NULL;
540         }
541       else
542         {
543           gun_last->next = egun;
544           egun->previous = gun_last;
545           gun_last = egun;
546         }
547       ship->num_of_extraguns++;
548 #ifdef UNDER_DEVELOPMENT
549       gun_check_chained_list ();
550 #endif
551       return egun;
552     }
553   LOG_ERR ("no more element gun is available");
554   return NULL;
555 }
556 
557 /**
558  * Remove a extra gun element from list
559  * @param Pointer to a extra gun structure
560  */
561 static void
gun_del(gun_struct * egun)562 gun_del (gun_struct * egun)
563 {
564   spaceship_struct *ship = spaceship_get ();
565   egun->is_enabled = FALSE;
566   ship->num_of_extraguns--;
567   if (gun_first == egun)
568     {
569       gun_first = egun->next;
570     }
571   if (gun_last == egun)
572     {
573       gun_last = egun->previous;
574     }
575   if (egun->previous != NULL)
576     {
577       egun->previous->next = egun->next;
578     }
579   if (egun->next != NULL)
580     {
581       egun->next->previous = egun->previous;
582     }
583 }
584 
585 /**
586  * Collisions between extra guns and an enemy
587  * @param foe pointer to the structure of an enemy
588  * @param num_of_fragments number of fragments to add if enemy is destroyed
589  * @return TRUE if enemy is destroyed
590  */
591 bool
guns_enemy_collisions(enemy * foe,Sint32 num_of_fragments)592 guns_enemy_collisions (enemy * foe, Sint32 num_of_fragments)
593 {
594   Sint32 i, l, m, x1, y1, x2, y2;
595   gun_struct *egun;
596   spaceship_struct *ship = spaceship_get ();
597   egun = gun_first;
598   if (egun == NULL)
599     {
600       return FALSE;
601     }
602   /* process each extra gun */
603   for (i = 0; i < ship->num_of_extraguns; i++, egun = egun->next)
604     {
605 #ifdef UNDER_DEVELOPMENT
606       if (egun == NULL && i < (ship->num_of_extraguns - 1))
607         {
608           LOG_ERR ("egun->next is null %i/%i", i, ship->num_of_extraguns);
609           break;
610         }
611 #endif
612       /* if extra gun is invisible, don't perform the tests of collision */
613       if (!egun->is_visible)
614         {
615           continue;
616         }
617       for (l = 0; l < egun->img[egun->current_image]->numof_collisions_points;
618            l++)
619         {
620           /* coordinates of the collision point of the gun */
621           x1 =
622             egun->xcoord +
623             egun->img[egun->current_image]->collisions_points[l][XCOORD];
624           y1 =
625             egun->ycoord +
626             egun->img[egun->current_image]->collisions_points[l][YCOORD];
627           /* for each collision zone of the enemy */
628           for (m = 0;
629                m <
630                foe->spr.img[foe->spr.current_image]->numof_collisions_zones;
631                m++)
632             {
633               /* coordinates of the collision zone of the enemy */
634               x2 =
635                 (Sint32) foe->spr.xcoord +
636                 foe->spr.img[foe->spr.current_image]->
637                 collisions_coords[m][XCOORD];
638               y2 =
639                 (Sint32) foe->spr.ycoord +
640                 foe->spr.img[foe->spr.current_image]->
641                 collisions_coords[m][YCOORD];
642               /* check if gun collision point is into enemy collision zone */
643               if (x1 >= x2 && y1 >= y2
644                   && x1 <
645                   (x2 +
646                    foe->spr.img[foe->spr.current_image]->collisions_sizes[m]
647                    [IMAGE_WIDTH])
648                   && y1 <
649                   (y2 +
650                    foe->spr.img[foe->spr.
651                                 current_image]->collisions_sizes[m]
652                    [IMAGE_HEIGHT]))
653                 {
654                   /* decrease energy level of enemy */
655                   foe->spr.energy_level =
656                     (Sint16) (foe->spr.energy_level - egun->pow_of_dest);
657                   if (foe->type >= THANIKEE)
658                     {
659                       energy_gauge_guard_is_update = TRUE;
660                     }
661                   /* decrease energy level of gun */
662                   egun->energy_level =
663                     (Sint16) (egun->energy_level - foe->spr.pow_of_dest);
664                   /* check if gun is destroyed */
665                   if (egun->energy_level <= 0)
666                     {
667                       /* remove gun from the list */
668                       gun_del (egun);
669                       break;
670                     }
671                   else
672                     {
673                       /* gun not destroyed, display white mask */
674                       egun->is_white_mask_displayed = TRUE;
675                     }
676                   /* check if enemy is destroyed */
677                   if (foe->spr.energy_level <= 0)
678                     {
679                       /* check if the enemy is a meteor */
680                       if ((foe->type >= BIGMETEOR && foe->type <= SMALLMETEOR)
681                           || foe->type >= THANIKEE)
682                         {
683                           /* add a bonus gem or a lonely foe */
684                           bonus_meteor_add (foe);
685                           if (num_of_fragments > 0)
686                             {
687                               explosions_fragments_add (foe->spr.xcoord +
688                                                         foe->spr.img[foe->spr.
689                                                                      current_image]->x_gc
690                                                         - 8,
691                                                         foe->spr.ycoord +
692                                                         foe->spr.img[foe->spr.
693                                                                      current_image]->y_gc
694                                                         - 8, 1.0,
695                                                         num_of_fragments, 0,
696                                                         2);
697                             }
698                         }
699                       else
700                         {
701                           /* add a bonus gem or a lonely foe */
702                           bonus_add (foe);
703                         }
704                       player_score +=
705                         foe->spr.pow_of_dest << 2 << score_multiplier;
706                       /* enemy destroyed! */
707                       return TRUE;
708                     }
709                   else
710                     {
711                       /* enemy not destroyed, display white mask */
712                       foe->is_white_mask_displayed = TRUE;
713                     }
714                   explosion_add ((float) x1, (float) y1, 0.3f,
715                                  EXPLOSION_SMALL, 0);
716                   break;
717                 }
718             }
719         }
720     }
721   return FALSE;
722 }
723 
724 /**
725  * Collisions between extra guns and a shot
726  * @param x1 x coordinate of the collision point of the shot
727  * @param y1 y coordinate of the collision point of the shot
728  * @param bullet pointer to the structure of an shot
729  * @return TRUE if the shot touched a extra gun
730  */
731 bool
guns_shot_collisions(Sint32 x1,Sint32 y1,shot_struct * bullet)732 guns_shot_collisions (Sint32 x1, Sint32 y1, shot_struct * bullet)
733 {
734   Sint32 i, j, x2, y2;
735   gun_struct *egun;
736   spaceship_struct *ship = spaceship_get ();
737   egun = gun_first;
738   if (egun == NULL)
739     {
740       return FALSE;
741     }
742 
743   /* process each extra gun */
744   for (i = 0; i < ship->num_of_extraguns; i++, egun = egun->next)
745     {
746 #ifdef UNDER_DEVELOPMENT
747       if (egun == NULL && i < (ship->num_of_extraguns - 1))
748         {
749           LOG_ERR ("egun->next is null %i/%i", i, ship->num_of_extraguns);
750           break;
751         }
752 #endif
753       /* if extra gun is invisible, don't perform the tests of collision */
754       if (!egun->is_visible)
755         {
756           continue;
757         }
758       /* for each collision zone of the gun */
759       for (j = 0; j < egun->img[egun->current_image]->numof_collisions_zones;
760            j++)
761         {
762           /* coordinates of the collision zone of the gun */
763           x2 =
764             egun->xcoord +
765             egun->img[egun->current_image]->collisions_coords[j][XCOORD];
766           y2 =
767             egun->ycoord +
768             egun->img[egun->current_image]->collisions_coords[j][YCOORD];
769           /* check if shot collision point is into gun collision zone */
770           if (x1 >= x2 &&
771               y1 >= y2 &&
772               x1 <
773               (x2 +
774                egun->img[egun->current_image]->
775                collisions_sizes[j][IMAGE_WIDTH])
776               && y1 <
777               (y2 +
778                egun->img[egun->current_image]->
779                collisions_sizes[j][IMAGE_HEIGHT]))
780             {
781               /* decrease energy level of gun */
782               egun->energy_level =
783                 (Sint16) (egun->energy_level - bullet->spr.pow_of_dest);
784               /* check if gun is destroyed */
785               if (egun->energy_level <= 0)
786                 {
787                   gun_del (egun);
788                 }
789               else
790                 {
791                   /* gun not destroyed, display white mask */
792                   egun->is_white_mask_displayed = TRUE;
793                 }
794               explosion_add (bullet->spr.xcoord, bullet->spr.ycoord, 0.35f,
795                              EXPLOSION_SMALL, 0);
796               return TRUE;
797             }
798         }
799     }
800   return FALSE;
801 }
802