ced26fb5b5ff431f216ea18adfa3196a3fd14abd
[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   /* Off screen? Kill it! */
197   if(base.x < scroll_x - base.width || base.y > screen->h) {
198     remove_me();
199     return;
200   }
201
202   /* Move around? */
203   physic.apply(frame_ratio, base.x, base.y);
204   if(kind == UPGRADE_GROWUP) {
205     collision_swept_object_map(&old_base, &base);
206   }
207
208   // fall down?
209   if(kind == UPGRADE_GROWUP || kind == UPGRADE_HERRING) {
210     // falling?
211     if(physic.get_velocity_y() != 0) {
212       if(issolid(base.x, base.y + base.height)) {
213         base.y = int(base.y / 32) * 32;
214         old_base = base;                         
215         if(kind == UPGRADE_GROWUP) {
216           physic.enable_gravity(false);
217           physic.set_velocity(dir == LEFT ? -GROWUP_SPEED : GROWUP_SPEED, 0);
218         } else if(kind == UPGRADE_HERRING) {
219           physic.set_velocity(dir == LEFT ? -2 : 2, 3);
220         }
221       }
222     } else {
223       if((physic.get_velocity_x() < 0
224             && !issolid(base.x+base.width, base.y + base.height))
225         || (physic.get_velocity_x() > 0
226             && !issolid(base.x, base.y + base.height))) {
227         physic.enable_gravity(true);
228       }
229     }
230   }
231
232   // horizontal bounce?
233   if(kind == UPGRADE_GROWUP || kind == UPGRADE_HERRING) {
234     if (  (physic.get_velocity_x() < 0
235           && issolid(base.x, (int) base.y + base.height/2)) 
236         ||  (physic.get_velocity_x() > 0
237           && issolid(base.x + base.width, (int) base.y + base.height/2))) {
238         physic.set_velocity(-physic.get_velocity_x(),physic.get_velocity_y());
239         dir = dir == LEFT ? RIGHT : LEFT;
240     }
241   }
242 }
243
244 void
245 Upgrade::draw()
246 {
247   SDL_Rect dest;
248   if (base.height < 32)
249     {
250       /* Rising up... */
251
252       dest.x = (int)(base.x - scroll_x);
253       dest.y = (int)(base.y + 32 - base.height);
254       dest.w = 32;
255       dest.h = (int)base.height;
256
257       if (kind == UPGRADE_GROWUP)
258         img_growup->draw_part(0,0,dest.x,dest.y,dest.w,dest.h);
259       else if (kind == UPGRADE_ICEFLOWER)
260         img_iceflower->draw_part(0,0,dest.x,dest.y,dest.w,dest.h);
261       else if (kind == UPGRADE_HERRING)
262         img_star->draw_part(0,0,dest.x,dest.y,dest.w,dest.h);
263       else if (kind == UPGRADE_1UP)
264         img_1up->draw_part( 0, 0, dest.x, dest.y, dest.w, dest.h);
265     }
266   else
267     {
268       if (kind == UPGRADE_GROWUP)
269         {
270           img_growup->draw(
271                        base.x - scroll_x, base.y);
272         }
273       else if (kind == UPGRADE_ICEFLOWER)
274         {
275           img_iceflower->draw(
276                        base.x - scroll_x, base.y);
277         }
278       else if (kind == UPGRADE_HERRING)
279         {
280           img_star->draw(
281                        base.x - scroll_x, base.y);
282         }
283       else if (kind == UPGRADE_1UP)
284         {
285           img_1up->draw( base.x - scroll_x, base.y);
286         }
287     }
288 }
289
290 void
291 Upgrade::collision(void* p_c_object, int c_object)
292 {
293   Player* pplayer = NULL;
294
295   switch (c_object)
296     {
297     case CO_PLAYER:
298       /* Remove the upgrade: */
299
300       /* p_c_object is CO_PLAYER, so assign it to pplayer */
301       pplayer = (Player*) p_c_object;
302
303       /* Affect the player: */
304
305       if (kind == UPGRADE_GROWUP)
306         {
307           play_sound(sounds[SND_EXCELLENT], SOUND_CENTER_SPEAKER);
308           pplayer->size = BIG;
309           pplayer->base.height = 64;
310           pplayer->base.y -= 32;
311           if(collision_object_map(pplayer->base))
312             {
313               pplayer->base.height = 32;
314               pplayer->base.y += 32;
315               pplayer->duck = true;
316             }
317         }
318       else if (kind == UPGRADE_ICEFLOWER)
319         {
320           play_sound(sounds[SND_COFFEE], SOUND_CENTER_SPEAKER);
321           pplayer->got_coffee = true;
322           if (pplayer->size == SMALL)
323             {
324               pplayer->size = BIG;
325               pplayer->base.height = 64;
326               pplayer->base.y -= 32;
327             }
328           if(collision_object_map(pplayer->base))
329             {
330               pplayer->base.height = 32;
331               pplayer->base.y += 32;
332               pplayer->duck = true;
333             }
334         }
335       else if (kind == UPGRADE_HERRING)
336         {
337           play_sound(sounds[SND_HERRING], SOUND_CENTER_SPEAKER);
338           pplayer->invincible_timer.start(TUX_INVINCIBLE_TIME);
339           World::current()->play_music(HERRING_MUSIC);
340         }
341       else if (kind == UPGRADE_1UP)
342         {
343           if(player_status.lives < MAX_LIVES) {
344             player_status.lives++;
345             play_sound(sounds[SND_LIFEUP], SOUND_CENTER_SPEAKER);
346           }
347         }
348
349       remove_me();
350       return;
351     }
352 }
353
354 void load_special_gfx()
355 {
356   img_growup    = sprite_manager->load("egg");
357   img_iceflower = sprite_manager->load("iceflower");
358   img_star      = sprite_manager->load("star");
359   img_1up       = sprite_manager->load("1up");
360
361   img_bullet    = sprite_manager->load("bullet");
362 }
363
364 void free_special_gfx()
365 {
366   delete img_bullet;
367 }
368