71a2e5e8a4c4e30cda0417acd2954cee24dc8bbf
[supertux.git] / src / special.cpp
1 //  $Id$
2 //
3 //  SuperTux -  A Jump'n Run
4 //  Copyright (C) 2003 Tobias Glaesser <tobi.web@gmx.de>
5 //
6 //  This program is free software; you can redistribute it and/or
7 //  modify it under the terms of the GNU General Public License
8 //  as published by the Free Software Foundation; either version 2
9 //  of the License, or (at your option) any later version.
10 //
11 //  This program is distributed in the hope that it will be useful,
12 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
13 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 //  GNU General Public License for more details.
15 //
16 //  You should have received a copy of the GNU General Public License
17 //  along with this program; if not, write to the Free Software
18 //  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19
20 #include <assert.h>
21 #include <iostream>
22 #include "SDL.h"
23 #include "defines.h"
24 #include "special.h"
25 #include "gameloop.h"
26 #include "screen.h"
27 #include "sound.h"
28 #include "scene.h"
29 #include "globals.h"
30 #include "player.h"
31 #include "sprite_manager.h"
32 #include "resources.h"
33
34 Sprite* img_bullet;
35 Sprite* img_star;
36 Sprite* img_growup;
37 Sprite* img_iceflower;
38 Sprite* img_1up;
39
40 #define GROWUP_SPEED 1.0f
41
42 #define BULLET_STARTING_YM 0
43 #define BULLET_XM 6
44
45 void
46 Bullet::init(float x, float y, float xm, Direction dir)
47 {
48   life_count = 3;
49   base.width = 4;
50   base.height = 4;
51
52   if (dir == RIGHT)
53     {
54       base.x = x + 32;
55       base.xm = BULLET_XM + xm;
56     }
57   else
58     {
59       base.x = x;
60       base.xm = -BULLET_XM + xm;
61     }
62
63   base.y = y;
64   base.ym = BULLET_STARTING_YM;
65   old_base = base;
66 }
67
68 void
69 Bullet::remove_me()
70 {
71   std::vector<Bullet>& bullets = World::current()->bullets;
72   for(std::vector<Bullet>::iterator i = bullets.begin();
73          i != bullets.end(); ++i) {
74     if( & (*i) == this) {
75       bullets.erase(i);
76       return;
77     }
78   }
79
80   assert(false);
81 }
82
83 void
84 Bullet::action(double frame_ratio)
85 {
86   frame_ratio *= 0.5f;
87
88   float old_y = base.y;
89
90   base.x = base.x + base.xm * frame_ratio;
91   base.y = base.y + base.ym * frame_ratio;
92
93   collision_swept_object_map(&old_base,&base);
94       
95   if (issolid(base.x, base.y + 4) || issolid(base.x, base.y))
96     {
97       base.y  = old_y;
98       base.ym = -base.ym;     
99       if (base.ym > 9)
100         base.ym = 9;
101       else if (base.ym < -9)
102         base.ym = -9;
103       life_count -= 1;
104     }
105
106   base.ym = base.ym + 0.5 * frame_ratio;
107
108   if (base.x < scroll_x ||
109       base.x > scroll_x + screen->w ||
110       base.y < 0 ||
111       base.y > screen->h ||
112       issolid(base.x + 4, base.y + 2) ||
113       issolid(base.x, base.y + 2) ||
114       life_count <= 0)
115     {
116       remove_me();
117     }
118
119 }
120
121 void 
122 Bullet::draw()
123 {
124   if (base.x >= scroll_x - base.width &&
125       base.x <= scroll_x + screen->w)
126     {
127       img_bullet->draw(base.x - scroll_x, base.y);
128     }
129 }
130
131 void
132 Bullet::collision(int c_object)
133 {
134   if(c_object == CO_BADGUY) {
135     remove_me();
136   }
137 }
138
139 void
140 Upgrade::init(float x_, float y_, Direction dir_, UpgradeKind kind_)
141 {
142   kind = kind_;
143   dir = dir_;
144
145   base.width = 32;
146   base.height = 0;
147   base.x = x_;
148   base.y = y_;
149   old_base = base;
150
151   physic.reset();
152   physic.enable_gravity(false);
153
154   if(kind == UPGRADE_1UP || kind == UPGRADE_HERRING) {
155     physic.set_velocity(dir == LEFT ? -1 : 1, 4);
156     physic.enable_gravity(true);
157     base.height = 32;
158   } else if (kind == UPGRADE_ICEFLOWER) {
159     // nothing
160   } else if (kind == UPGRADE_GROWUP) {
161     physic.set_velocity(dir == LEFT ? -GROWUP_SPEED : GROWUP_SPEED, 0);
162   } else {
163     physic.set_velocity(dir == LEFT ? -2 : 2, 0);
164   }
165 }
166
167 void
168 Upgrade::remove_me()
169 {
170   std::vector<Upgrade>& upgrades = World::current()->upgrades;
171   for(std::vector<Upgrade>::iterator i = upgrades.begin();
172          i != upgrades.end(); ++i) {
173     if( & (*i) == this) {
174       upgrades.erase(i);
175       return;
176     }
177   }
178
179   assert(false);
180 }
181
182 void
183 Upgrade::action(double frame_ratio)
184 {
185   if (kind == UPGRADE_ICEFLOWER || kind == UPGRADE_GROWUP) {
186     if (base.height < 32) {
187       /* Rise up! */
188       base.height = base.height + 0.7 * frame_ratio;
189       if(base.height > 32)
190         base.height = 32;
191
192       return;
193     }
194   }
195
196   /* Away from the screen? Kill it! */
197   if(base.x < scroll_x - OFFSCREEN_DISTANCE) {
198       remove_me();
199       return;
200   }
201   if(base.y > screen->h) {
202     remove_me();
203     return;
204   }
205
206   /* Move around? */
207   physic.apply(frame_ratio, base.x, base.y);
208   if(kind == UPGRADE_GROWUP) {
209     collision_swept_object_map(&old_base, &base);
210   }
211
212   // fall down?
213   if(kind == UPGRADE_GROWUP || kind == UPGRADE_HERRING) {
214     // falling?
215     if(physic.get_velocity_y() != 0) {
216       if(issolid(base.x, base.y + base.height)) {
217         base.y = int(base.y / 32) * 32;
218         old_base = base;                         
219         if(kind == UPGRADE_GROWUP) {
220           physic.enable_gravity(false);
221           physic.set_velocity(dir == LEFT ? -GROWUP_SPEED : GROWUP_SPEED, 0);
222         } else if(kind == UPGRADE_HERRING) {
223           physic.set_velocity(dir == LEFT ? -2 : 2, 3);
224         }
225       }
226     } else {
227       if((physic.get_velocity_x() < 0
228             && !issolid(base.x+base.width, base.y + base.height))
229         || (physic.get_velocity_x() > 0
230             && !issolid(base.x, base.y + base.height))) {
231         physic.enable_gravity(true);
232       }
233     }
234   }
235
236   // horizontal bounce?
237   if(kind == UPGRADE_GROWUP || kind == UPGRADE_HERRING) {
238     if (  (physic.get_velocity_x() < 0
239           && issolid(base.x, (int) base.y + base.height/2)) 
240         ||  (physic.get_velocity_x() > 0
241           && issolid(base.x + base.width, (int) base.y + base.height/2))) {
242         physic.set_velocity(-physic.get_velocity_x(),physic.get_velocity_y());
243         dir = dir == LEFT ? RIGHT : LEFT;
244     }
245   }
246 }
247
248 void
249 Upgrade::draw()
250 {
251   SDL_Rect dest;
252   if (base.height < 32)
253     {
254       /* Rising up... */
255
256       dest.x = (int)(base.x - scroll_x);
257       dest.y = (int)(base.y + 32 - base.height);
258       dest.w = 32;
259       dest.h = (int)base.height;
260
261       if (kind == UPGRADE_GROWUP)
262         img_growup->draw_part(0,0,dest.x,dest.y,dest.w,dest.h);
263       else if (kind == UPGRADE_ICEFLOWER)
264         img_iceflower->draw_part(0,0,dest.x,dest.y,dest.w,dest.h);
265       else if (kind == UPGRADE_HERRING)
266         img_star->draw_part(0,0,dest.x,dest.y,dest.w,dest.h);
267       else if (kind == UPGRADE_1UP)
268         img_1up->draw_part( 0, 0, dest.x, dest.y, dest.w, dest.h);
269     }
270   else
271     {
272       if (kind == UPGRADE_GROWUP)
273         {
274           img_growup->draw(
275                        base.x - scroll_x, base.y);
276         }
277       else if (kind == UPGRADE_ICEFLOWER)
278         {
279           img_iceflower->draw(
280                        base.x - scroll_x, base.y);
281         }
282       else if (kind == UPGRADE_HERRING)
283         {
284           img_star->draw(
285                        base.x - scroll_x, base.y);
286         }
287       else if (kind == UPGRADE_1UP)
288         {
289           img_1up->draw( base.x - scroll_x, base.y);
290         }
291     }
292 }
293
294 void
295 Upgrade::bump(Player* )
296 {
297   // these can't be bumped
298   if(kind != UPGRADE_GROWUP)
299     return;
300
301   play_sound(sounds[SND_BUMP_UPGRADE], SOUND_CENTER_SPEAKER);
302   
303   // do a little jump and change direction
304   physic.set_velocity(-physic.get_velocity_x(), 3);
305   dir = dir == LEFT ? RIGHT : LEFT;
306   physic.enable_gravity(true);
307 }
308
309 void
310 Upgrade::collision(void* p_c_object, int c_object, CollisionType type)
311 {
312   Player* pplayer = NULL;
313
314   if(type == COLLISION_BUMP) {
315     if(c_object == CO_PLAYER)
316       pplayer = (Player*) p_c_object;
317     bump(pplayer);
318     return;
319   }
320
321   switch (c_object)
322     {
323     case CO_PLAYER:
324       /* Remove the upgrade: */
325
326       /* p_c_object is CO_PLAYER, so assign it to pplayer */
327       pplayer = (Player*) p_c_object;
328
329       /* Affect the player: */
330
331       if (kind == UPGRADE_GROWUP)
332         {
333           play_sound(sounds[SND_EXCELLENT], SOUND_CENTER_SPEAKER);
334           pplayer->size = BIG;
335           pplayer->base.height = 64;
336           pplayer->base.y -= 32;
337           if(collision_object_map(pplayer->base))
338             {
339               pplayer->base.height = 32;
340               pplayer->base.y += 32;
341               pplayer->duck = true;
342             }
343         }
344       else if (kind == UPGRADE_ICEFLOWER)
345         {
346           play_sound(sounds[SND_COFFEE], SOUND_CENTER_SPEAKER);
347           pplayer->got_coffee = true;
348           if (pplayer->size == SMALL)
349             {
350               pplayer->size = BIG;
351               pplayer->base.height = 64;
352               pplayer->base.y -= 32;
353             }
354           if(collision_object_map(pplayer->base))
355             {
356               pplayer->base.height = 32;
357               pplayer->base.y += 32;
358               pplayer->duck = true;
359             }
360         }
361       else if (kind == UPGRADE_HERRING)
362         {
363           play_sound(sounds[SND_HERRING], SOUND_CENTER_SPEAKER);
364           pplayer->invincible_timer.start(TUX_INVINCIBLE_TIME);
365           World::current()->play_music(HERRING_MUSIC);
366         }
367       else if (kind == UPGRADE_1UP)
368         {
369           if(player_status.lives < MAX_LIVES) {
370             player_status.lives++;
371             play_sound(sounds[SND_LIFEUP], SOUND_CENTER_SPEAKER);
372           }
373         }
374
375       remove_me();
376       return;
377     }
378 }
379
380 void load_special_gfx()
381 {
382   img_growup    = sprite_manager->load("egg");
383   img_iceflower = sprite_manager->load("iceflower");
384   img_star      = sprite_manager->load("star");
385   img_1up       = sprite_manager->load("1up");
386
387   img_bullet    = sprite_manager->load("bullet");
388 }
389
390 void free_special_gfx()
391 {
392 }
393