- memleak fix and menu fix from MatzeB
[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   base.width = 4;
49   base.height = 4;
50
51   if (dir == RIGHT)
52     {
53       base.x = x + 32;
54       base.xm = BULLET_XM + xm;
55     }
56   else
57     {
58       base.x = x;
59       base.xm = -BULLET_XM + xm;
60     }
61
62   base.y = y;
63   base.ym = BULLET_STARTING_YM;
64   old_base = base;
65 }
66
67 void
68 Bullet::remove_me()
69 {
70   std::vector<Bullet>& bullets = World::current()->bullets;
71   for(std::vector<Bullet>::iterator i = bullets.begin();
72          i != bullets.end(); ++i) {
73     if( & (*i) == this) {
74       bullets.erase(i);
75       return;
76     }
77   }
78
79   assert(false);
80 }
81
82 void
83 Bullet::action(double frame_ratio)
84 {
85   frame_ratio *= 0.5f;
86
87   float old_y = base.y;
88
89   base.x = base.x + base.xm * frame_ratio;
90   base.y = base.y + base.ym * frame_ratio;
91
92   collision_swept_object_map(&old_base,&base);
93       
94   if (issolid(base.x, base.y + 4) || issolid(base.x, base.y))
95     {
96       base.y  = old_y;
97       base.ym = -base.ym;     
98       if (base.ym > 13)
99         base.ym = 13;
100       else if (base.ym < -13)
101         base.ym = -13;
102     }
103
104   base.ym = base.ym + 0.5 * frame_ratio;
105
106   if (base.x < scroll_x ||
107       base.x > scroll_x + screen->w ||
108       base.y < 0 ||
109       base.y > screen->h ||
110       issolid(base.x + 4, base.y + 2) ||
111       issolid(base.x, base.y + 2))
112     {
113       remove_me();
114     }
115
116 }
117
118 void 
119 Bullet::draw()
120 {
121   if (base.x >= scroll_x - base.width &&
122       base.x <= scroll_x + screen->w)
123     {
124       img_bullet->draw(base.x - scroll_x, base.y);
125     }
126 }
127
128 void
129 Bullet::collision(int c_object)
130 {
131   if(c_object == CO_BADGUY) {
132     remove_me();
133   }
134 }
135
136 void
137 Upgrade::init(float x_, float y_, Direction dir_, UpgradeKind kind_)
138 {
139   kind = kind_;
140   dir = dir_;
141
142   base.width = 32;
143   base.height = 0;
144   base.x = x_;
145   base.y = y_;
146   old_base = base;
147
148   physic.reset();
149   physic.enable_gravity(false);
150
151   if(kind == UPGRADE_1UP || kind == UPGRADE_HERRING) {
152     physic.set_velocity(dir == LEFT ? -1 : 1, 4);
153     physic.enable_gravity(true);
154     base.height = 32;
155   } else if (kind == UPGRADE_ICEFLOWER) {
156     // nothing
157   } else if (kind == UPGRADE_GROWUP) {
158     physic.set_velocity(dir == LEFT ? -GROWUP_SPEED : GROWUP_SPEED, 0);
159   } else {
160     physic.set_velocity(dir == LEFT ? -2 : 2, 0);
161   }
162 }
163
164 void
165 Upgrade::remove_me()
166 {
167   std::vector<Upgrade>& upgrades = World::current()->upgrades;
168   for(std::vector<Upgrade>::iterator i = upgrades.begin();
169          i != upgrades.end(); ++i) {
170     if( & (*i) == this) {
171       upgrades.erase(i);
172       return;
173     }
174   }
175
176   assert(false);
177 }
178
179 void
180 Upgrade::action(double frame_ratio)
181 {
182   if (kind == UPGRADE_ICEFLOWER || kind == UPGRADE_GROWUP) {
183     if (base.height < 32) {
184       /* Rise up! */
185       base.height = base.height + 0.7 * frame_ratio;
186       if(base.height > 32)
187         base.height = 32;
188
189       return;
190     }
191   }
192
193   /* Off screen? Kill it! */
194   if(base.x < scroll_x - base.width || base.y > screen->h) {
195     remove_me();
196     return;
197   }
198
199   /* Move around? */
200   physic.apply(frame_ratio, base.x, base.y);
201   if(kind == UPGRADE_GROWUP) {
202     collision_swept_object_map(&old_base, &base);
203   }
204
205   // fall down?
206   if(kind == UPGRADE_GROWUP || kind == UPGRADE_HERRING) {
207     // falling?
208     if(physic.get_velocity_y() != 0) {
209       if(issolid(base.x, base.y + base.height)) {
210         base.y = int(base.y / 32) * 32;
211         old_base = base;                         
212         if(kind == UPGRADE_GROWUP) {
213           physic.enable_gravity(false);
214           physic.set_velocity(dir == LEFT ? -GROWUP_SPEED : GROWUP_SPEED, 0);
215         } else if(kind == UPGRADE_HERRING) {
216           physic.set_velocity(dir == LEFT ? -2 : 2, 3);
217         }
218       }
219     } else {
220       if((physic.get_velocity_x() < 0
221             && !issolid(base.x+base.width, base.y + base.height))
222         || (physic.get_velocity_x() > 0
223             && !issolid(base.x, base.y + base.height))) {
224         physic.enable_gravity(true);
225       }
226     }
227   }
228
229   // horizontal bounce?
230   if(kind == UPGRADE_GROWUP || kind == UPGRADE_HERRING) {
231     if (  (physic.get_velocity_x() < 0
232           && issolid(base.x, (int) base.y + base.height/2)) 
233         ||  (physic.get_velocity_x() > 0
234           && issolid(base.x + base.width, (int) base.y + base.height/2))) {
235         physic.set_velocity(-physic.get_velocity_x(),physic.get_velocity_y());
236         dir = dir == LEFT ? RIGHT : LEFT;
237     }
238   }
239 }
240
241 void
242 Upgrade::draw()
243 {
244   SDL_Rect dest;
245   if (base.height < 32)
246     {
247       /* Rising up... */
248
249       dest.x = (int)(base.x - scroll_x);
250       dest.y = (int)(base.y + 32 - base.height);
251       dest.w = 32;
252       dest.h = (int)base.height;
253
254       if (kind == UPGRADE_GROWUP)
255         img_growup->draw_part(0,0,dest.x,dest.y,dest.w,dest.h);
256       else if (kind == UPGRADE_ICEFLOWER)
257         img_iceflower->draw_part(0,0,dest.x,dest.y,dest.w,dest.h);
258       else if (kind == UPGRADE_HERRING)
259         img_star->draw_part(0,0,dest.x,dest.y,dest.w,dest.h);
260       else if (kind == UPGRADE_1UP)
261         img_1up->draw_part( 0, 0, dest.x, dest.y, dest.w, dest.h);
262     }
263   else
264     {
265       if (kind == UPGRADE_GROWUP)
266         {
267           img_growup->draw(
268                        base.x - scroll_x, base.y);
269         }
270       else if (kind == UPGRADE_ICEFLOWER)
271         {
272           img_iceflower->draw(
273                        base.x - scroll_x, base.y);
274         }
275       else if (kind == UPGRADE_HERRING)
276         {
277           img_star->draw(
278                        base.x - scroll_x, base.y);
279         }
280       else if (kind == UPGRADE_1UP)
281         {
282           img_1up->draw( base.x - scroll_x, base.y);
283         }
284     }
285 }
286
287 void
288 Upgrade::collision(void* p_c_object, int c_object)
289 {
290   Player* pplayer = NULL;
291
292   switch (c_object)
293     {
294     case CO_PLAYER:
295       /* Remove the upgrade: */
296
297       /* p_c_object is CO_PLAYER, so assign it to pplayer */
298       pplayer = (Player*) p_c_object;
299
300       /* Affect the player: */
301
302       if (kind == UPGRADE_GROWUP)
303         {
304           play_sound(sounds[SND_EXCELLENT], SOUND_CENTER_SPEAKER);
305           pplayer->size = BIG;
306           pplayer->base.height = 64;
307           pplayer->base.y -= 32;
308           if(collision_object_map(pplayer->base))
309             {
310               pplayer->base.height = 32;
311               pplayer->base.y += 32;
312               pplayer->duck = true;
313             }
314         }
315       else if (kind == UPGRADE_ICEFLOWER)
316         {
317           play_sound(sounds[SND_COFFEE], SOUND_CENTER_SPEAKER);
318           pplayer->got_coffee = true;
319           pplayer->size = BIG;
320           pplayer->base.height = 64;
321           pplayer->base.y -= 32;
322           if(collision_object_map(pplayer->base))
323             {
324               pplayer->base.height = 32;
325               pplayer->base.y += 32;
326               pplayer->duck = true;
327             }
328         }
329       else if (kind == UPGRADE_HERRING)
330         {
331           play_sound(sounds[SND_HERRING], SOUND_CENTER_SPEAKER);
332           pplayer->invincible_timer.start(TUX_INVINCIBLE_TIME);
333           World::current()->play_music(HERRING_MUSIC);
334         }
335       else if (kind == UPGRADE_1UP)
336         {
337           if(player_status.lives < MAX_LIVES) {
338             player_status.lives++;
339             play_sound(sounds[SND_LIFEUP], SOUND_CENTER_SPEAKER);
340           }
341         }
342
343       remove_me();
344       return;
345     }
346 }
347
348 void load_special_gfx()
349 {
350   img_growup    = sprite_manager->load("egg");
351   img_iceflower = sprite_manager->load("iceflower");
352   img_star      = sprite_manager->load("star");
353   img_1up       = sprite_manager->load("1up");
354
355   img_bullet    = sprite_manager->load("bullet");
356 }
357
358 void free_special_gfx()
359 {
360   delete img_bullet;
361 }
362