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