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