1 /**
2  * @file sprite_projectile.cc
3  * @brief The fire sprite of the paddle into the bricks level
4  * @date 2007-11-16
5  * @copyright 1991-2014 TLK Games
6  * @author Bruno Ethvignot
7  * @version $Revision: 24 $
8  */
9 /*
10  * copyright (c) 1991-2014 TLK Games all rights reserved
11  * $Id: sprite_projectile.cc 24 2014-09-28 15:30:04Z bruno.ethvignot@gmail.com $
12  *
13  * TecnoballZ 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  * TecnoballZ 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 "../include/sprite_projectile.h"
29 
30 /**
31  * Create the fire sprite object
32  */
sprite_projectile()33 sprite_projectile::sprite_projectile ()
34 {
35   if (total_fire < MAXI_TOTAL_OF_PROJECTILES)
36     {
37       projectiles_list[total_fire] = this;
38       total_fire++;
39     }
40   set_draw_method (DRAW_COLOR_CYCLING_MASK);
41   on_paddle = false;
42 }
43 
44 /**
45  * Release the fire sprite object
46  */
~sprite_projectile()47 sprite_projectile::~sprite_projectile ()
48 {
49 }
50 
51 /**
52  * Enable the power 1 of the projectiles
53  */
54 void
set_power1()55 sprite_projectile::set_power1 ()
56 {
57   frame_index_min = 4;
58   frame_index_max = 7;
59   frame_index = 4;
60   can_destroy_indestructible = false;
61   power = 1;
62   current_cycling = &sprite_object::cycling_02[0];
63 }
64 
65 /**
66  * Enable the power 2 of the projectiles
67  */
68 void
set_power2()69 sprite_projectile::set_power2 ()
70 {
71   frame_index_min = 0;
72   frame_index_max = 3;
73   frame_index = 0;
74   can_destroy_indestructible = true;
75   power = 2;
76   current_cycling = &sprite_object::cycling_01[0];
77 }
78 
79 /**
80  * Clear member a simple
81  */
82 void
init_members(sprite_paddle * pad)83 sprite_projectile::init_members (sprite_paddle * pad)
84 {
85   paddle = pad;
86   indexSinus = 0;
87   fire_Xscie = 0;
88   fire_Yscie = 0;
89   frame_index = 0;
90   frame_index_max = 3;
91   frame_index_min = 0;
92   frame_delay = 10;
93   frame_period = 10;
94   can_destroy_indestructible = false;
95   power = 0;
96 }
97 
98 /**
99  * Static method which initialize all projectiles before a bricks level
100  */
101 void
start_list()102 sprite_projectile::start_list ()
103 {
104   total_fire = 0;
105   for (Uint32 i = 0; i < MAXI_TOTAL_OF_PROJECTILES; i++)
106     {
107       projectiles_list[i] = NULL;
108     }
109 }
110 
111 /**
112  * Static method which manage all projectiles
113  */
114 void
gestionTir()115 sprite_projectile::gestionTir ()
116 {
117   check_outside ();
118   play_projectiles_animations ();
119   check_collisions_with_bricks ();
120   check_collisions_with_ships ();
121 }
122 
123 /**
124  * Static method which check if all projectiles go out of the screen of game
125  */
126 void
check_outside()127 sprite_projectile::check_outside ()
128 {
129   sprite_projectile **projectiles = projectiles_list;
130   Sint32 y1 = 15 * resolution;
131   Sint32 y2 = 232 * resolution;
132   Sint32 x1 = 15 * resolution;
133   Sint32 x2 = 228 * resolution;
134   for (Uint32 i = 0; i < total_fire; i++)
135     {
136       sprite_projectile *blast = *(projectiles++);
137       Sint32 a = blast->y_coord;
138       if (a < y1 || a > y2)
139         {
140           blast->is_enabled = false;
141           continue;
142         }
143       a = blast->x_coord;
144       if (a < x1 || a > x2)
145         {
146           blast->is_enabled = false;
147         }
148     }
149 }
150 
151 /**
152  * Static method which manages the animation played in loop-mode
153  */
154 void
play_projectiles_animations()155 sprite_projectile::play_projectiles_animations ()
156 {
157   sprite_projectile **projectiles = projectiles_list;
158   sprite_projectile *blast = projectiles[0];
159   blast->play_animation_loop ();
160   Sint32 index = blast->get_frame_index ();
161   Sint32 cycle = index & 0X1;
162   if (0 == cycle)
163     {
164       cycle = sprite_object::DRAW_WITH_TABLES;
165     }
166   else
167     {
168       cycle = sprite_object::DRAW_COLOR_CYCLING_MASK;
169     }
170   blast->draw_method = cycle;
171   for (Uint32 i = 1; i < total_fire; i++)
172     {
173       blast = projectiles[i];
174       blast->set_image (index);
175       blast->draw_method = cycle;
176     }
177 }
178 
179 /**
180  * Static method which check collision projectiles between bricks
181  */
182 void
check_collisions_with_bricks()183 sprite_projectile::check_collisions_with_bricks ()
184 {
185   controller_bricks *bricks = controller_bricks::get_instance ();
186   /* brick's width in pixels */
187   Uint32 brick_width = bricks->get_brick_width ();
188   /* y-offset between 2 bricks */
189   /* first indestructible brick */
190   Sint32 indestructible = bricks->get_indestructible_offset ();
191   sprite_projectile **projectiles = projectiles_list;
192   for (Uint32 i = 0; i < total_fire; i++)
193     {
194       sprite_projectile *blast = *(projectiles++);
195       if (!blast->is_enabled)
196         {
197           continue;
198         }
199       Sint32 x = blast->x_coord + 2;
200       Sint32 y = blast->y_coord + 2;
201       brick_redraw *redraw = bricks->get_bricks_redraw ();
202       redraw->xcoord_collision = x;
203       redraw->ycoord_collision = y;
204       brick_info *map = bricks->get_bricks_map(x, y);
205 
206       /* collision between a blast and a brick? */
207       if (map->source_offset == 0)
208         {
209           /* no collision */
210           continue;
211         }
212       if (!blast->on_paddle)
213         {
214           blast->is_enabled = false;
215         }
216       redraw->paddle = blast->paddle;
217       redraw->is_gigablitz_destroyed = false;
218       if (!has_background)
219         {
220           map->sprite->touch ();
221         }
222       if (map->source_offset >= indestructible)
223         {
224           /*
225            * indestructible brick touched!
226            */
227           /* indestructible-destructible bricks? */
228           if (map->source_offset > (Sint32)(indestructible + brick_width))
229             {
230               /* fire destroys the indestructibles-destructibles bricks? */
231               if (blast->can_destroy_indestructible)
232                 {
233                   redraw->is_indestructible = true;
234                   redraw->pixel_offset = map->pixel_offset;
235                   redraw->brick_map = map;
236                   map->source_offset = 0;
237                   redraw->number = map->number;
238                   /* restore background under brick */
239                   redraw->is_background = true;
240                   bricks->bricks_redraw_next ();
241                 }
242               else
243                 {
244 #ifndef SOUNDISOFF
245                   audio->
246                     play_sound (handler_audio::HIT_INDESTRUCTIBLE_BRICK2);
247 #endif
248                 }
249             }
250           else
251             {
252               /* the brick is really indestructible */
253 #ifndef SOUNDISOFF
254               audio->play_sound (handler_audio::HIT_INDESTRUCTIBLE_BRICK1);
255 #endif
256             }
257         }
258       /*
259        * Normal brick touched
260        */
261       else
262         {
263           redraw->is_indestructible = false;
264           redraw->pixel_offset = map->pixel_offset;
265           redraw->brick_map = map;
266           /* fire power: 1 or 2 */
267           x = blast->power;
268           map->h_pos = map->h_pos - (x * 2);
269           if (map->h_pos <= 0)
270             {
271               map->h_pos = 0;
272               map->source_offset = 0;
273               redraw->number = map->number;
274               /* restore background under brick */
275               redraw->is_background = true;
276             }
277           else
278             {
279               map->source_offset = map->source_offset - (x * brick_width);
280               redraw->number = map->source_offset;
281               /* redraw a new brick */
282               redraw->is_background = false;
283             }
284           bricks->bricks_redraw_next ();
285         }
286     }
287 }
288 
289 /**
290  * Static method which check collisions between projectiles and ships
291  */
292 void
check_collisions_with_ships()293 sprite_projectile::check_collisions_with_ships ()
294 {
295   sprite_projectile **projectiles = projectiles_list;
296   controller_ships *ships = controller_ships::get_instance ();
297   Sint32 t = ships->get_max_of_sprites ();
298   sprite_ship **ships_list = ships->get_sprites_list ();
299   for (Uint32 i = 0; i < total_fire; i++)
300     {
301       sprite_projectile *blast = *(projectiles++);
302       if (!blast->is_enabled)
303         {
304           continue;
305         }
306       sprite_ship **ships = ships_list;
307       Sint32 y1 = blast->y_coord;
308       Sint32 y2 = y1 + 3;
309       y1 -= 26;
310       Sint32 x1 = blast->x_coord;
311       Sint32 x2 = x1 + 3;
312       x1 -= 20;
313       for (Sint32 j = 0; j < t; j++)
314         {
315           sprite_ship *ship = *(ships++);
316           if (ship->enable_counter > 0)
317             {
318               continue;
319             }
320           Sint32 k = ship->y_coord;
321           if (k >= y2 || k <= y1)
322             {
323               continue;
324             }
325           k = ship->x_coord;
326           if (k >= x2 || k <= x1)
327             {
328               continue;
329             }
330           if (!blast->on_paddle)
331             {
332               blast->is_enabled = false;
333             }
334           current_player->add_score (100);
335           k = blast->power;
336           ship->strength -= k;
337           if (ship->strength < 1)
338             {
339               ship->destroy (blast);
340             }
341         }
342     }
343 }
344 
345 /**
346  * Static method which disables all projectiles
347  */
348 void
disable_sprites()349 sprite_projectile::disable_sprites ()
350 {
351   sprite_projectile **projectiles = projectiles_list;
352   for (Uint32 i = 0; i < total_fire; i++)
353     {
354       sprite_projectile *blast = *(projectiles++);
355       blast->is_enabled = false;
356     }
357 }
358 
359 Uint32 sprite_projectile::total_fire = 0;
360 sprite_projectile *
361   sprite_projectile::projectiles_list[MAXI_TOTAL_OF_PROJECTILES];
362