1 /*
2  * itembox.c - item boxes
3  * Copyright (C) 2010  Alexandre Martins <alemartf(at)gmail(dot)com>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License along
16  * with this program; if not, write to the Free Software Foundation, Inc.,
17  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18  */
19 
20 #include "itembox.h"
21 #include "icon.h"
22 #include "../../scenes/level.h"
23 #include "../../core/audio.h"
24 #include "../../core/util.h"
25 #include "../../core/soundfactory.h"
26 
27 /* itembox class */
28 typedef struct itembox_t itembox_t;
29 struct itembox_t {
30     item_t item; /* base class */
31     int anim_id; /* animation id */
32     void (*on_destroy)(item_t*,player_t*); /* strategy pattern */
33 };
34 
35 static item_t* itembox_create(void (*on_destroy)(item_t*,player_t*), int anim_id);
36 static void itembox_init(item_t *item);
37 static void itembox_release(item_t* item);
38 static void itembox_update(item_t* item, player_t** team, int team_size, brick_list_t* brick_list, item_list_t* item_list, enemy_list_t* enemy_list);
39 static void itembox_render(item_t* item, v2d_t camera_position);
40 static int itembox_player_collision(item_t *box, player_t *player);
41 
42 static void lifebox_strategy(item_t *item, player_t *player);
43 static void ringbox_strategy(item_t *item, player_t *player);
44 static void starbox_strategy(item_t *item, player_t *player);
45 static void speedbox_strategy(item_t *item, player_t *player);
46 static void glassesbox_strategy(item_t *item, player_t *player);
47 static void shieldbox_strategy(item_t *item, player_t *player);
48 static void fireshieldbox_strategy(item_t *item, player_t *player);
49 static void thundershieldbox_strategy(item_t *item, player_t *player);
50 static void watershieldbox_strategy(item_t *item, player_t *player);
51 static void acidshieldbox_strategy(item_t *item, player_t *player);
52 static void windshieldbox_strategy(item_t *item, player_t *player);
53 static void trapbox_strategy(item_t *item, player_t *player);
54 static void emptybox_strategy(item_t *item, player_t *player);
55 
56 
57 
58 /* public methods */
lifebox_create()59 item_t* lifebox_create()
60 {
61     return itembox_create(lifebox_strategy, 0); /* (strategy, animation id) */
62 }
63 
ringbox_create()64 item_t* ringbox_create()
65 {
66     return itembox_create(ringbox_strategy, 3);
67 }
68 
starbox_create()69 item_t* starbox_create()
70 {
71     return itembox_create(starbox_strategy, 4);
72 }
73 
speedbox_create()74 item_t* speedbox_create()
75 {
76    return itembox_create(speedbox_strategy, 5);
77 }
78 
glassesbox_create()79 item_t* glassesbox_create()
80 {
81     return itembox_create(glassesbox_strategy, 6);
82 }
83 
shieldbox_create()84 item_t* shieldbox_create()
85 {
86     return itembox_create(shieldbox_strategy, 7);
87 }
88 
trapbox_create()89 item_t* trapbox_create()
90 {
91     return itembox_create(trapbox_strategy, 8);
92 }
93 
emptybox_create()94 item_t* emptybox_create()
95 {
96     return itembox_create(emptybox_strategy, 9);
97 }
98 
fireshieldbox_create()99 item_t* fireshieldbox_create()
100 {
101     return itembox_create(fireshieldbox_strategy, 11);
102 }
103 
thundershieldbox_create()104 item_t* thundershieldbox_create()
105 {
106     return itembox_create(thundershieldbox_strategy, 12);
107 }
108 
watershieldbox_create()109 item_t* watershieldbox_create()
110 {
111     return itembox_create(watershieldbox_strategy, 13);
112 }
113 
acidshieldbox_create()114 item_t* acidshieldbox_create()
115 {
116     return itembox_create(acidshieldbox_strategy, 14);
117 }
118 
windshieldbox_create()119 item_t* windshieldbox_create()
120 {
121     return itembox_create(windshieldbox_strategy, 15);
122 }
123 
124 
125 /* private strategies */
lifebox_strategy(item_t * item,player_t * player)126 void lifebox_strategy(item_t *item, player_t *player)
127 {
128     level_add_to_score(100);
129     player_set_lives( player_get_lives()+1 );
130     level_override_music( soundfactory_get("1up") );
131 }
132 
ringbox_strategy(item_t * item,player_t * player)133 void ringbox_strategy(item_t *item, player_t *player)
134 {
135     level_add_to_score(100);
136     player_set_rings( player_get_rings()+10 );
137     sound_play( soundfactory_get("ring") );
138 }
139 
starbox_strategy(item_t * item,player_t * player)140 void starbox_strategy(item_t *item, player_t *player)
141 {
142     level_add_to_score(100);
143     player->invincible = TRUE;
144     player->invtimer = 0;
145     music_play( music_load("musics/invincible.ogg"), 0 );
146 }
147 
speedbox_strategy(item_t * item,player_t * player)148 void speedbox_strategy(item_t *item, player_t *player)
149 {
150     level_add_to_score(100);
151     player->got_speedshoes = TRUE;
152     player->speedshoes_timer = 0;
153     music_play( music_load("musics/speed.ogg"), 0 );
154 }
155 
glassesbox_strategy(item_t * item,player_t * player)156 void glassesbox_strategy(item_t *item, player_t *player)
157 {
158     level_add_to_score(100);
159     player->got_glasses = TRUE;
160 }
161 
shieldbox_strategy(item_t * item,player_t * player)162 void shieldbox_strategy(item_t *item, player_t *player)
163 {
164     level_add_to_score(100);
165     player->shield_type = SH_SHIELD;
166     sound_play( soundfactory_get("shield") );
167 }
168 
fireshieldbox_strategy(item_t * item,player_t * player)169 void fireshieldbox_strategy(item_t *item, player_t *player)
170 {
171     level_add_to_score(100);
172     player->shield_type = SH_FIRESHIELD;
173     sound_play( soundfactory_get("fire shield") );
174 }
175 
thundershieldbox_strategy(item_t * item,player_t * player)176 void thundershieldbox_strategy(item_t *item, player_t *player)
177 {
178     level_add_to_score(100);
179     player->shield_type = SH_THUNDERSHIELD;
180     sound_play( soundfactory_get("thunder shield") );
181 }
182 
watershieldbox_strategy(item_t * item,player_t * player)183 void watershieldbox_strategy(item_t *item, player_t *player)
184 {
185     level_add_to_score(100);
186     player->shield_type = SH_WATERSHIELD;
187     sound_play( soundfactory_get("water shield") );
188 }
189 
acidshieldbox_strategy(item_t * item,player_t * player)190 void acidshieldbox_strategy(item_t *item, player_t *player)
191 {
192     level_add_to_score(100);
193     player->shield_type = SH_ACIDSHIELD;
194     sound_play( soundfactory_get("acid shield") );
195 }
196 
windshieldbox_strategy(item_t * item,player_t * player)197 void windshieldbox_strategy(item_t *item, player_t *player)
198 {
199     level_add_to_score(100);
200     player->shield_type = SH_WINDSHIELD;
201     sound_play( soundfactory_get("wind shield") );
202 }
203 
trapbox_strategy(item_t * item,player_t * player)204 void trapbox_strategy(item_t *item, player_t *player)
205 {
206     player_hit(player);
207 }
208 
emptybox_strategy(item_t * item,player_t * player)209 void emptybox_strategy(item_t *item, player_t *player)
210 {
211     level_add_to_score(100);
212 }
213 
214 
215 /* private methods */
itembox_create(void (* on_destroy)(item_t *,player_t *),int anim_id)216 item_t* itembox_create(void (*on_destroy)(item_t*,player_t*), int anim_id)
217 {
218     item_t *item = mallocx(sizeof(itembox_t));
219     itembox_t *me = (itembox_t*)item;
220 
221     item->init = itembox_init;
222     item->release = itembox_release;
223     item->update = itembox_update;
224     item->render = itembox_render;
225 
226     me->on_destroy = on_destroy;
227     me->anim_id = anim_id;
228 
229     return item;
230 }
231 
itembox_init(item_t * item)232 void itembox_init(item_t *item)
233 {
234     itembox_t *me = (itembox_t*)item;
235 
236     item->obstacle = TRUE;
237     item->bring_to_back = FALSE;
238     item->preserve = TRUE;
239     item->actor = actor_create();
240 
241     actor_change_animation(item->actor, sprite_get_animation("SD_ITEMBOX", me->anim_id));
242 }
243 
itembox_release(item_t * item)244 void itembox_release(item_t* item)
245 {
246     actor_destroy(item->actor);
247 }
248 
itembox_update(item_t * item,player_t ** team,int team_size,brick_list_t * brick_list,item_list_t * item_list,enemy_list_t * enemy_list)249 void itembox_update(item_t* item, player_t** team, int team_size, brick_list_t* brick_list, item_list_t* item_list, enemy_list_t* enemy_list)
250 {
251     int i;
252     actor_t *act = item->actor;
253     itembox_t *me = (itembox_t*)item;
254 
255     for(i=0; i<team_size; i++) {
256         player_t *player = team[i];
257         if(!(player->actor->is_jumping && player->actor->speed.y < -10)) {
258 
259             /* the player is about to crash this box... */
260             if(item->state == IS_IDLE && itembox_player_collision(item, player) && player_attacking(player)) {
261                 item_t *icon = level_create_item(IT_ICON, v2d_add(act->position, v2d_new(0,-5)));
262                 icon_change_animation(icon, me->anim_id);
263                 level_create_item(IT_EXPLOSION, v2d_add(act->position, v2d_new(0,-20)));
264                 level_create_item(IT_CRUSHEDBOX, act->position);
265 
266                 sound_play( soundfactory_get("destroy") );
267                 if(player->actor->is_jumping)
268                     player_bounce(player);
269 
270                 me->on_destroy(item, player);
271                 item->state = IS_DEAD;
272             }
273 
274         }
275     }
276 
277     /* animation */
278     me->anim_id = me->anim_id < 3 ? level_player_id() : me->anim_id;
279     actor_change_animation(item->actor, sprite_get_animation("SD_ITEMBOX", me->anim_id));
280 }
281 
itembox_render(item_t * item,v2d_t camera_position)282 void itembox_render(item_t* item, v2d_t camera_position)
283 {
284     actor_render(item->actor, camera_position);
285 }
286 
287 /* returns TRUE if player collides with box, or
288  * FALSE otherwise. As fake bricks are created
289  * on top of boxes, a simple actor_collision()
290  * doesn't do the job. */
itembox_player_collision(item_t * box,player_t * player)291 int itembox_player_collision(item_t *box, player_t *player)
292 {
293     /* fake bricks are created on top of
294      * the item boxes. Therefore, boxes need to
295      * be adjusted in order to handle collisions
296      * with the player properly */
297     int collided;
298     actor_t *act = box->actor;
299     v2d_t oldpos = act->position;
300 
301     /* hack */
302     act->position.y -= 5; /* jump fix */
303     if(player->spin) { /* spindash through multiple boxes */
304         if(player->actor->position.x < act->position.x && player->actor->speed.x > 0)
305             act->position.x -= 15;
306         else if(player->actor->position.x > act->position.x && player->actor->speed.x < 0)
307             act->position.x += 15;
308     }
309 
310     /* collision detection */
311     collided = actor_collision(box->actor, player->actor);
312 
313     /* unhack */
314     box->actor->position = oldpos;
315 
316     /* done! */
317     return collided;
318 }
319