1 /**
2  * @file meteors_phase.c
3  * @brief Handle the meteor storm
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: meteors_phase.c,v 1.27 2012/08/25 19:18:32 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 "config_file.h"
32 #include "curve_phase.h"
33 #include "display.h"
34 #include "enemies.h"
35 #include "shots.h"
36 #include "grid_phase.h"
37 #include "guardians.h"
38 #include "images.h"
39 #include "log_recorder.h"
40 #include "meteors_phase.h"
41 #include "spaceship.h"
42 #include "starfield.h"
43 #include "texts.h"
44 
45 bool meteor_activity = FALSE;
46 Sint32 num_of_meteors = 0;
47 
48 /** Maximum number of differents meteors: big, medium and small */
49 #define METEOR_MAXOF_TYPES 3
50 
51 static image meteor_images[METEOR_MAXOF_TYPES][METEOR_NUMOF_IMAGES];
52 static Sint32 meteor_delay_next = 0;
53 static bool next_level_without_guardian (void);
54 
55 /**
56  * First initialization of meteors
57  */
58 bool
meteors_once_init(void)59 meteors_once_init (void)
60 {
61   meteors_free ();
62   return TRUE;
63 }
64 
65 /**
66  * Release memory used for the meteors
67  */
68 void
meteors_free(void)69 meteors_free (void)
70 {
71   meteors_images_free ();
72 }
73 
74 /**
75  * Generate big, medium or small meteors
76  */
77 void
meteors_handle(void)78 meteors_handle (void)
79 {
80   Sint32 k, meteor_size;
81   enemy *foe;
82   spaceship_struct *ship = spaceship_get ();
83   /* meteors phase currently in progress? */
84   if (!meteor_activity)
85     {
86       /* meteors phase not enable */
87       return;
88     }
89 
90   /* appearance of new a meteor? */
91   if (meteor_delay_next <= (12 + (MAX_NUM_OF_LEVELS - num_level)))
92     {
93       meteor_delay_next++;
94       return;
95     }
96   meteor_delay_next = 1;
97 
98   /* max. of meteors reached? */
99   if (num_of_meteors >= (40 + (num_level << 1)))
100     {
101       return;
102     }
103 
104   /* get new enemy element */
105   foe = enemy_get ();
106   if (foe == NULL)
107     {
108       return;
109     }
110 
111   /* size of the meteor: 0, 1 or 2 */
112   meteor_size = rand () % 3;
113   switch (meteor_size)
114     {
115     case 0:
116       /* set meteor's power of destruction */
117       foe->spr.pow_of_dest = (Sint16) (6 + (num_level >> 1));
118       /* set vertical speed of the displacement */
119       foe->y_speed = 0.7f + (float) ((float) num_level / 25.0);
120       /* value of delay between two images */
121       foe->spr.anim_speed = 5;
122       break;
123     case 1:
124       foe->spr.pow_of_dest = (Sint16) (4 + (num_level >> 1));
125       foe->y_speed = 0.6f + (float) ((float) num_level / 30.0);
126       foe->spr.anim_speed = 4;
127       break;
128     case 2:
129       foe->spr.pow_of_dest = (Sint16) (2 + (num_level >> 1));
130       foe->y_speed = 0.5f + (float) ((float) num_level / 35.0);
131       foe->spr.anim_speed = 3;
132       break;
133     }
134   /* set level of energy (zero correspond to destruction of the metor) */
135   foe->spr.energy_level =
136     (Sint16) ((ship->type << 1) + (foe->spr.pow_of_dest << 3) / 5);
137   /* set number of images of the metor sprite */
138   foe->spr.numof_images = METEOR_NUMOF_IMAGES;
139   /* set current image */
140   foe->spr.current_image = (Sint16) (rand () % METEOR_NUMOF_IMAGES);
141   /* clear counter delay before next image */
142   foe->spr.anim_count = 0;
143   /* set addresses of the images buffer */
144   for (k = 0; k < foe->spr.numof_images; k++)
145     {
146       foe->spr.img[k] = (image *) & meteor_images[meteor_size][k];
147     }
148 
149   /* set shot time-frequency: meteor has never shot */
150   foe->fire_rate = 10000;
151   /* set counter of delay between two shots */
152   foe->fire_rate_count = foe->fire_rate;
153   /* set type of displacement:
154    * meteors are identified like lonely foe */
155   foe->displacement = DISPLACEMENT_LONELY_FOE;
156   /* set x and y coordinates of the meteor  */
157   foe->spr.xcoord =
158     offscreen_startx +
159     (float) (rand () % (offscreen_width_visible - foe->spr.img[0]->w));
160   foe->spr.ycoord = (float) (offscreen_starty - 64);
161   /* clear horizontal speed of the displacement */
162   foe->x_speed = 0.0;
163   /* set type of meteor */
164   foe->type = BIGMETEOR + meteor_size;
165   /* set delay time before destruction */
166   foe->timelife = 210;
167 
168   /* set animation direction */
169   if (rand () % 2)
170     {
171       /* reverse animation direction */
172       foe->sens_anim = -1;
173     }
174   else
175     {
176       /* forward animation direction */
177       foe->sens_anim = 1;
178     }
179   num_of_meteors++;
180 }
181 
182 /**
183  * Prepare the next phase: curve phase or guardian phase
184  * this function is also called to begin a new game
185  */
186 bool
meteors_finished(void)187 meteors_finished (void)
188 {
189   /* meteors phase currently in progress? */
190   if (!meteor_activity)
191     {
192       /* meteors phase not enable */
193       return TRUE;
194     }
195 
196   /* next phase */
197   if (num_level != -1)
198     {
199       /* number of meteors reached? */
200       if (num_of_meteors >= (40 + (num_level << 1)))
201         {
202           switch (num_level)
203             {
204             case 3:
205               guardian_new (1);
206               break;
207             case 7:
208               guardian_new (2);
209               break;
210             case 11:
211               guardian_new (3);
212               break;
213             case 15:
214               guardian_new (4);
215               break;
216             case 19:
217               guardian_new (5);
218               break;
219             case 23:
220               guardian_new (6);
221               break;
222             case 27:
223               guardian_new (7);
224               break;
225             case 31:
226               guardian_new (8);
227               break;
228             case 35:
229               guardian_new (9);
230               break;
231             case 39:
232               guardian_new (10);
233               break;
234             case 41:
235               guardian_new (11);
236               break;
237             default:
238               if (!next_level_without_guardian ())
239                 {
240                   return FALSE;
241                 }
242               break;
243             }
244         }
245     }
246 
247   /*
248    * start a new game: first level of the game
249    */
250   else
251     {
252       if (num_of_meteors >= (40 + (num_level << 1)))
253         {
254           num_level++;
255           if (num_level > MAX_NUM_OF_LEVELS)
256             {
257               num_level = 0;
258             }
259           /* load first guardian */
260           if (!guardian_load (1))
261             {
262               return FALSE;
263             }
264           /* load grid phase */
265           if (!grid_load (num_level))
266             {
267               return FALSE;
268             }
269           if (!curve_load_level (num_level))
270             {
271               return FALSE;
272             }
273           if (!meteors_load (num_level))
274             {
275               return FALSE;
276             }
277           /* enable the curve phase */
278           curve_enable_level ();
279           courbe.activity = TRUE;
280           grid.is_enable = FALSE;
281           meteor_activity = FALSE;
282           guardian->number = 0;
283         }
284     }
285   return TRUE;
286 }
287 
288 /**
289  * Release meteors sprite data
290  */
291 void
meteors_images_free(void)292 meteors_images_free (void)
293 {
294   Sint32 i, j;
295   for (i = 0; i < (METEOR_MAXOF_TYPES); i++)
296     {
297       for (j = 0; j < METEOR_NUMOF_IMAGES; j++)
298         {
299           if (meteor_images[i][j].img != NULL)
300             {
301               free_memory (meteor_images[i][j].img);
302               meteor_images[i][j].img = NULL;
303             }
304           if (meteor_images[i][j].compress != NULL)
305             {
306               free_memory (meteor_images[i][j].compress);
307               meteor_images[i][j].compress = NULL;
308             }
309         }
310     }
311 }
312 
313 /**
314  * Load meteors sprite data
315  * @param num_meteor Meteors level number from 0 to 42
316  * @return TRUE if it completed successfully or FALSE otherwise
317  */
318 bool
meteors_load(Sint32 num_meteor)319 meteors_load (Sint32 num_meteor)
320 {
321   char *file, *data;
322   meteors_images_free ();
323   if (num_meteor > MAX_NUM_OF_LEVELS || num_meteor < 0)
324     {
325       num_meteor = 0;
326     }
327   file =
328     loadfile_num ("graphics/sprites/meteors/meteor_%02d.spr", num_meteor);
329   if (file == NULL)
330     {
331       return FALSE;
332     }
333   data =
334     images_read (&meteor_images[0][0], METEOR_MAXOF_TYPES,
335                  METEOR_NUMOF_IMAGES, file, METEOR_NUMOF_IMAGES);
336   free_memory (file);
337   if (data == NULL)
338     {
339       return FALSE;
340     }
341   return TRUE;
342 }
343 
344 
345 /**
346  * Convert meteors from data image to PNG file
347  * @return TRUE if successful
348  */
349 #ifdef PNG_EXPORT_ENABLE
350 bool
meteors_extract(void)351 meteors_extract (void)
352 {
353   Uint32 i, type, frame;
354   const char *model =
355     EXPORT_DIR "/meteors/level-%02d/type-%01d/meteor-%01d.png";
356   char *filename = memory_allocation (strlen (model) + 1);
357   if (filename == NULL)
358     {
359       LOG_ERR ("not enough memory to allocate %i bytes",
360                (Uint32) (strlen (model) + 1));
361       return FALSE;
362     }
363   if (!create_dir (EXPORT_DIR "/meteors"))
364     {
365       return FALSE;
366     }
367 
368   for (i = 0; i < MAX_NUM_OF_LEVELS; i++)
369     {
370       if (!meteors_load (i))
371         {
372           free_memory (filename);
373           return FALSE;
374         }
375       sprintf (filename, EXPORT_DIR "/meteors/level-%02d", i);
376       if (!create_dir (filename))
377         {
378           return FALSE;
379         }
380       for (type = 0; type < METEOR_MAXOF_TYPES; type++)
381         {
382           sprintf (filename, EXPORT_DIR "/meteors/level-%02d/type-%01d", i,
383                    type + 1);
384           if (!create_dir (filename))
385             {
386               return FALSE;
387             }
388           for (frame = 0; frame < METEOR_NUMOF_IMAGES; frame++)
389             {
390               sprintf (filename,
391                        EXPORT_DIR
392                        "/meteors/level-%02d/type-%01d/meteor-%02d.png", i,
393                        type + 1, frame);
394               if (!image_to_png (&meteor_images[type][frame], filename))
395                 {
396                   free_memory (filename);
397                   return FALSE;
398                 }
399             }
400         }
401 
402     }
403   free_memory (filename);
404   return TRUE;
405 }
406 #endif
407 
408 /**
409  * Jump to next level without loading a guardian
410  * @return TRUE if it completed successfully or FALSE otherwise
411  */
412 static bool
next_level_without_guardian(void)413 next_level_without_guardian (void)
414 {
415   bool is_finished;
416   spaceship_disappears = TRUE;
417   is_finished = text_level_move (num_level);
418   if (starfield_speed == 0.0 && is_finished)
419     {
420       /* next level */
421       num_level++;
422       LOG_INF ("level number: %i", num_level);
423       if (num_level > MAX_NUM_OF_LEVELS)
424         {
425           num_level = 0;
426         }
427       /* load grid phase */
428       if (!grid_load (num_level))
429         {
430           return FALSE;
431         }
432       /* load curve phase level file (little skirmish) */
433       if (!curve_load_level (num_level))
434         {
435           return FALSE;
436         }
437       if (!meteors_load (num_level))
438         {
439           return FALSE;
440         }
441       /* enable the curve level file loaded previously */
442       curve_enable_level ();
443       /* grid phase enable */
444       courbe.activity = TRUE;
445       grid.is_enable = FALSE;
446       meteor_activity = FALSE;
447       spaceship_show ();
448     }
449   return TRUE;
450 }
451