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