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