Ignore the gradient Surface (cache) when in OpenGL (as asked by Ryan).
[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 <cassert>
21 #include <iostream>
22
23 #include "SDL.h"
24
25 #include "defines.h"
26 #include "special.h"
27 #include "camera.h"
28 #include "gameloop.h"
29 #include "screen/screen.h"
30 #include "sound.h"
31 #include "scene.h"
32 #include "globals.h"
33 #include "player.h"
34 #include "sector.h"
35 #include "sprite_manager.h"
36 #include "resources.h"
37
38 Sprite* img_firebullet;
39 Sprite* img_icebullet;
40 Sprite* img_star;
41 Sprite* img_growup;
42 Sprite* img_iceflower;
43 Sprite* img_fireflower;
44 Sprite* img_1up;
45
46 #define GROWUP_SPEED 1.0f
47
48 #define BULLET_STARTING_YM 0
49 #define BULLET_XM 6
50
51 Bullet::Bullet(const Vector& pos, float xm, int dir, int kind_)
52 {
53   life_count = 3;
54   base.width = 4;
55   base.height = 4;
56   
57   if (kind == ICE_BULLET)
58     life_count = 6; //ice-bullets get "extra lives" for bumping off walls
59
60   if (dir == RIGHT)
61     {
62       base.x = pos.x + 32;
63       physic.set_velocity_x(BULLET_XM + xm);
64     }
65   else
66     {
67       base.x = pos.x;
68       physic.set_velocity_x(-BULLET_XM + xm);
69     }
70
71   base.y = pos.y;
72   physic.set_velocity_y(-BULLET_STARTING_YM);
73   old_base = base;
74   kind = kind_;
75 }
76
77 void
78 Bullet::action(float elapsed_time)
79 {
80   elapsed_time *= 0.5f;
81
82   float old_y = base.y;
83
84   physic.apply(elapsed_time, base.x, base.y);
85   collision_swept_object_map(&old_base,&base);
86       
87   if (issolid(base.x, base.y + 4) || issolid(base.x, base.y))
88     {
89       base.y  = old_y;
90       physic.set_velocity_y(-physic.get_velocity_y());
91       life_count -= 1;
92     }
93
94   if(kind == FIRE_BULLET)
95     // @not framerate independant :-/
96     physic.set_velocity_y(physic.get_velocity_y() - 0.5 * elapsed_time);
97   if(physic.get_velocity_y() > 9)
98     physic.set_velocity_y(9);
99   else if(physic.get_velocity_y() < -9)
100     physic.set_velocity_y(-9);
101
102   float scroll_x =
103     Sector::current()->camera->get_translation().x;
104   float scroll_y =
105     Sector::current()->camera->get_translation().y;
106   if (base.x < scroll_x ||
107       base.x > scroll_x + screen->w ||
108       base.y < scroll_y ||
109       base.y > scroll_y + screen->h ||
110       life_count <= 0)
111     {
112       remove_me();
113     }
114   if (issolid(base.x + 4, base.y + 2) || 
115       issolid(base.x, base.y + 2))
116      {
117        if (kind == FIRE_BULLET)
118          remove_me();
119        else if (kind == ICE_BULLET)
120          {
121            physic.set_velocity_x(physic.get_velocity_x() * -1);
122          }
123      }
124 }
125
126 void 
127 Bullet::draw(DrawingContext& context)
128 {
129   Sprite* sprite = kind == FIRE_BULLET ? img_firebullet : img_icebullet;
130  
131   sprite->draw(context, Vector(base.x, base.y), LAYER_OBJECTS);
132 }
133
134 void
135 Bullet::collision(const MovingObject& , int)
136 {
137   // later
138 }
139
140 void
141 Bullet::collision(int c_object)
142 {
143   if(c_object == CO_BADGUY) {
144     remove_me();
145   }
146 }
147
148 //---------------------------------------------------------------------------
149
150 Upgrade::Upgrade(const Vector& pos, Direction dir_, UpgradeKind kind_)
151 {
152   kind = kind_;
153   dir = dir_;
154
155   base.width = 32;
156   base.height = 0;
157   base.x = pos.x;
158   base.y = pos.y;
159   old_base = base;
160
161   physic.reset();
162   physic.enable_gravity(false);
163
164   if(kind == UPGRADE_1UP || kind == UPGRADE_HERRING) {
165     physic.set_velocity(dir == LEFT ? -1 : 1, 4);
166     physic.enable_gravity(true);
167     base.height = 32;
168   } else if (kind == UPGRADE_ICEFLOWER || kind == UPGRADE_FIREFLOWER) {
169     // nothing
170   } else if (kind == UPGRADE_GROWUP) {
171     physic.set_velocity(dir == LEFT ? -GROWUP_SPEED : GROWUP_SPEED, 0);
172   } else {
173     physic.set_velocity(dir == LEFT ? -2 : 2, 0);
174   }
175 }
176
177 Upgrade::~Upgrade()
178 {
179 }
180
181 void
182 Upgrade::action(float elapsed_time)
183 {
184   if (kind == UPGRADE_ICEFLOWER || kind == UPGRADE_FIREFLOWER
185       || kind == UPGRADE_GROWUP) {
186     if (base.height < 32) {
187       /* Rise up! */
188       base.height = base.height + 0.7 * elapsed_time;
189       if(base.height > 32)
190         base.height = 32;
191
192       return;
193     }
194   }
195
196   /* Away from the screen? Kill it! */
197   float scroll_x =
198     Sector::current()->camera->get_translation().x;
199   float scroll_y =                                                        
200     Sector::current()->camera->get_translation().y;
201   
202   if(base.x < scroll_x - X_OFFSCREEN_DISTANCE ||
203       base.x > scroll_x + screen->w + X_OFFSCREEN_DISTANCE ||
204       base.y < scroll_y - Y_OFFSCREEN_DISTANCE ||
205       base.y > scroll_y + screen->h + Y_OFFSCREEN_DISTANCE)
206     {
207     remove_me();
208     return;
209     }
210
211   /* Move around? */
212   physic.apply(elapsed_time, base.x, base.y);
213   if(kind == UPGRADE_GROWUP) {
214     collision_swept_object_map(&old_base, &base);
215   }
216
217   // fall down?
218   if(kind == UPGRADE_GROWUP || kind == UPGRADE_HERRING) {
219     // falling?
220     if(physic.get_velocity_y() != 0) {
221       if(issolid(base.x, base.y + base.height)) {
222         base.y = int(base.y / 32) * 32;
223         old_base = base;                         
224         if(kind == UPGRADE_GROWUP) {
225           physic.enable_gravity(false);
226           physic.set_velocity(dir == LEFT ? -GROWUP_SPEED : GROWUP_SPEED, 0);
227         } else if(kind == UPGRADE_HERRING) {
228           physic.set_velocity(dir == LEFT ? -2 : 2, 3);
229         }
230       }
231     } else {
232       if((physic.get_velocity_x() < 0
233             && !issolid(base.x+base.width, base.y + base.height))
234         || (physic.get_velocity_x() > 0
235             && !issolid(base.x, base.y + base.height))) {
236         physic.enable_gravity(true);
237       }
238     }
239   }
240
241   // horizontal bounce?
242   if(kind == UPGRADE_GROWUP || kind == UPGRADE_HERRING) {
243     if (  (physic.get_velocity_x() < 0
244           && issolid(base.x, (int) base.y + base.height/2)) 
245         ||  (physic.get_velocity_x() > 0
246           && issolid(base.x + base.width, (int) base.y + base.height/2))) {
247         physic.set_velocity(-physic.get_velocity_x(),physic.get_velocity_y());
248         dir = dir == LEFT ? RIGHT : LEFT;
249     }
250   }
251 }
252
253 void
254 Upgrade::draw(DrawingContext& context)
255 {
256   Sprite* sprite;
257   switch(kind) {
258     case UPGRADE_GROWUP: sprite = img_growup; break;
259     case UPGRADE_ICEFLOWER: sprite = img_iceflower; break;
260     case UPGRADE_FIREFLOWER: sprite = img_fireflower; break;
261     case UPGRADE_HERRING: sprite = img_star; break;
262     case UPGRADE_1UP: sprite = img_1up; break;
263     default:
264       assert(!"wrong type in Powerup::draw()");
265   }
266
267   if(base.height < 32) // still raising up?
268     sprite->draw(context, Vector(base.x, base.y + (32 - base.height)),
269         LAYER_TILES - 10);
270   else
271     sprite->draw(context, Vector(base.x, base.y), LAYER_OBJECTS);
272 }
273
274 void
275 Upgrade::bump(Player* player)
276 {
277   // these can't be bumped
278   if(kind != UPGRADE_GROWUP)
279     return;
280
281   sound_manager->play_sound(sounds[SND_BUMP_UPGRADE], Vector(base.x, base.y));
282   
283   // determine new direction
284   Direction old_dir = dir;
285   if (player->base.x + player->base.width/2 > base.x + base.width/2)
286     dir = LEFT;
287   else
288     dir = RIGHT;
289
290   // do a little jump and change direction (if necessary)
291   if (dir != old_dir)
292     physic.set_velocity(-physic.get_velocity_x(), 3);
293   else
294     physic.set_velocity_y(3);
295
296   physic.enable_gravity(true);
297 }
298
299 void
300 Upgrade::collision(const MovingObject& , int)
301 {
302   // later
303 }
304
305 void
306 Upgrade::collision(void* p_c_object, int c_object, CollisionType type)
307 {
308   Player* pplayer = NULL;
309
310   if(type == COLLISION_BUMP) {
311     if(c_object == CO_PLAYER)
312       pplayer = (Player*) p_c_object;
313     bump(pplayer);
314     return;
315   }
316
317   switch (c_object)
318     {
319     case CO_PLAYER:
320       /* Remove the upgrade: */
321
322       /* p_c_object is CO_PLAYER, so assign it to pplayer */
323       pplayer = (Player*) p_c_object;
324
325       /* Affect the player: */
326
327       if (kind == UPGRADE_GROWUP)
328         {
329           sound_manager->play_sound(sounds[SND_EXCELLENT]);
330           pplayer->grow(true);
331         }
332       else if (kind == UPGRADE_FIREFLOWER)
333         {
334           sound_manager->play_sound(sounds[SND_COFFEE]);
335           pplayer->grow(true);
336           pplayer->got_power = pplayer->FIRE_POWER;
337         }
338       else if (kind == UPGRADE_ICEFLOWER)
339         {
340           sound_manager->play_sound(sounds[SND_COFFEE]);
341           pplayer->grow(true);
342           pplayer->got_power = pplayer->ICE_POWER;
343         }
344       else if (kind == UPGRADE_FIREFLOWER)
345         {
346           sound_manager->play_sound(sounds[SND_COFFEE]);
347           pplayer->grow(true);
348           pplayer->got_power = pplayer->FIRE_POWER;
349         }
350       else if (kind == UPGRADE_HERRING)
351         {
352           sound_manager->play_sound(sounds[SND_HERRING]);
353           pplayer->invincible_timer.start(TUX_INVINCIBLE_TIME);
354           Sector::current()->play_music(HERRING_MUSIC);
355         }
356       else if (kind == UPGRADE_1UP)
357         {
358           if(player_status.lives < MAX_LIVES) {
359             player_status.lives++;
360             sound_manager->play_sound(sounds[SND_LIFEUP]);
361           }
362         }
363
364       remove_me();
365       return;
366     }
367 }
368
369 void load_special_gfx()
370 {
371   img_growup    = sprite_manager->load("egg");
372   img_iceflower = sprite_manager->load("iceflower");
373   img_fireflower = sprite_manager->load("fireflower");
374   img_star      = sprite_manager->load("star");
375   img_1up       = sprite_manager->load("1up");
376
377   img_firebullet = sprite_manager->load("firebullet");
378   img_icebullet  = sprite_manager->load("icebullet");
379 }
380
381 void free_special_gfx()
382 {
383 }
384