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