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