- turned special into classes
[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 "SDL.h"
14 #include "defines.h"
15 #include "special.h"
16 #include "gameloop.h"
17 #include "screen.h"
18 #include "sound.h"
19 #include "scene.h"
20 #include "globals.h"
21 #include "player.h"
22
23 texture_type img_bullet;
24 texture_type img_golden_herring;
25 bitmask* bm_bullet;
26
27 void create_special_bitmasks()
28 {
29   bm_bullet = bitmask_create_SDL(img_bullet.sdl_surface);
30 }
31
32 void
33 Bullet::init(float x, float y, float xm, int dir)
34 {
35   base.width = 4;
36   base.height = 4;
37
38   if (dir == RIGHT)
39     {
40       base.x = x + 32;
41       base.xm = BULLET_XM + xm;
42     }
43   else
44     {
45       base.x = x;
46       base.xm = -BULLET_XM + xm;
47     }
48
49   base.y = y;
50   base.ym = BULLET_STARTING_YM;
51   old_base = base;
52 }
53
54 void
55 Bullet::action()
56 {
57   base.x = base.x + base.xm * frame_ratio;
58   base.y = base.y + base.ym * frame_ratio;
59
60   collision_swept_object_map(&old_base,&base);
61       
62   if (issolid(base.x, base.y + 4) || issolid(base.x, base.y))
63     {
64       base.ym = -base.ym;
65       base.y = (int)(base.y / 32) * 32;
66     }
67
68   base.ym = base.ym + GRAVITY;
69
70   if (base.x < scroll_x ||
71       base.x > scroll_x + screen->w ||
72       base.y < 0 ||
73       base.y > screen->h ||
74       issolid(base.x + 4, base.y + 2) ||
75       issolid(base.x, base.y + 2))
76     {
77       World::current()->bullets.erase(static_cast<std::vector<Bullet>::iterator>(this));
78     }
79
80 }
81
82 void 
83 Bullet::draw()
84 {
85   if (base.x >= scroll_x - base.width &&
86       base.x <= scroll_x + screen->w)
87     {
88       texture_draw(&img_bullet, base.x - scroll_x, base.y, 255,
89                    NO_UPDATE);
90     }
91 }
92
93 void
94 Bullet::collision(int c_object)
95 {
96   if(c_object == CO_BADGUY) {
97     std::vector<Bullet>::iterator i;
98     
99     for(i = World::current()->bullets.begin(); i != World::current()->bullets.end(); ++i) 
100       {
101         if(&(*i) == this) 
102           {
103             World::current()->bullets.erase(i);
104             return;
105           }
106       }
107   }
108 }
109
110 void
111 Upgrade::init(float x_, float y_, int dir_, int kind_)
112 {
113   base.width = 32;
114   base.height = 0;
115   kind = kind_;
116   base.x = x_;
117   base.y = y_;
118
119   if(dir_ == LEFT)
120     base.xm = -2;
121   else
122     base.xm = 2;
123
124   base.ym = -2;
125   base.height = 0;
126   old_base = base;
127 }
128
129 void
130 Upgrade::action()
131 {
132   if (base.height < 32)
133     {
134       /* Rise up! */
135
136       base.height = base.height + 0.7 * frame_ratio;
137       if(base.height > 32)
138         base.height = 32;
139     }
140   else
141     {
142       /* Move around? */
143
144       if (kind == UPGRADE_MINTS ||
145           kind == UPGRADE_HERRING)
146         {
147           base.x = base.x + base.xm * frame_ratio;
148           base.y = base.y + base.ym * frame_ratio;
149
150           collision_swept_object_map(&old_base,&base);
151
152           /* Off the screen?  Kill it! */
153
154           if (base.x < scroll_x - base.width)
155             World::current()->upgrades.erase(static_cast<std::vector<Upgrade>::iterator>(this));
156           if (base.y > screen->h)
157             World::current()->upgrades.erase(static_cast<std::vector<Upgrade>::iterator>(this));
158
159           if (issolid(base.x + 1, base.y + 32.) ||
160               issolid(base.x + 31., base.y + 32.))
161             {
162               if (base.ym > 0)
163                 {
164                   if (kind == UPGRADE_MINTS)
165                     {
166                       base.ym = 0;
167                     }
168                   else if (kind == UPGRADE_HERRING)
169                     {
170                       base.ym = -8;
171                     }
172
173                   base.y = (int)(base.y / 32) * 32;
174                 }
175             }
176           else
177             base.ym = base.ym + GRAVITY * frame_ratio;
178
179           if (issolid(base.x - 1, (int) base.y))
180             {
181               if(base.xm < 0)
182                 base.xm = -base.xm;
183             }
184           else if (issolid(base.x + base.width, (int) base.y))
185             {
186               if(base.xm > 0)
187                 base.xm = -base.xm;
188             }
189         }
190
191     }
192 }
193
194 void
195 Upgrade::draw()
196 {
197   SDL_Rect dest;
198   if (base.height < 32)
199     {
200       /* Rising up... */
201
202       dest.x = (int)(base.x - scroll_x);
203       dest.y = (int)(base.y + 32 - base.height);
204       dest.w = 32;
205       dest.h = (int)base.height;
206
207       if (kind == UPGRADE_MINTS)
208         texture_draw_part(&img_mints,0,0,dest.x,dest.y,dest.w,dest.h);
209       else if (kind == UPGRADE_COFFEE)
210         texture_draw_part(&img_coffee,0,0,dest.x,dest.y,dest.w,dest.h);
211       else if (kind == UPGRADE_HERRING)
212         texture_draw_part(&img_golden_herring,0,0,dest.x,dest.y,dest.w,dest.h);
213     }
214   else
215     {
216       if (kind == UPGRADE_MINTS)
217         {
218           texture_draw(&img_mints,
219                        base.x - scroll_x, base.y);
220         }
221       else if (kind == UPGRADE_COFFEE)
222         {
223           texture_draw(&img_coffee,
224                        base.x - scroll_x, base.y);
225         }
226       else if (kind == UPGRADE_HERRING)
227         {
228           texture_draw(&img_golden_herring,
229                        base.x - scroll_x, base.y);
230         }
231     }
232 }
233
234 void
235 Upgrade::collision(void* p_c_object, int c_object)
236 {
237   Player* pplayer = NULL;
238
239   switch (c_object)
240     {
241     case CO_PLAYER:
242       /* Remove the upgrade: */
243
244       /* p_c_object is CO_PLAYER, so assign it to pplayer */
245       pplayer = (Player*) p_c_object;
246
247       World::current()->upgrades.erase(static_cast<std::vector<Upgrade>::iterator>(this));
248
249       /* Affect the player: */
250
251       if (kind == UPGRADE_MINTS)
252         {
253           play_sound(sounds[SND_EXCELLENT], SOUND_CENTER_SPEAKER);
254           pplayer->size = BIG;
255           pplayer->base.height = 64;
256           pplayer->base.y -= 32;
257           if(collision_object_map(&pplayer->base))
258             {
259               pplayer->base.height = 32;
260               pplayer->base.y += 32;
261               pplayer->duck = true;
262             }
263           timer_start(&super_bkgd_timer, 350);
264         }
265       else if (kind == UPGRADE_COFFEE)
266         {
267           play_sound(sounds[SND_COFFEE], SOUND_CENTER_SPEAKER);
268           pplayer->got_coffee = true;
269           timer_start(&super_bkgd_timer, 250);
270         }
271       else if (kind == UPGRADE_HERRING)
272         {
273           play_sound(sounds[SND_HERRING], SOUND_CENTER_SPEAKER);
274           timer_start(&pplayer->invincible_timer,TUX_INVINCIBLE_TIME);
275           timer_start(&super_bkgd_timer, 250);
276           /* play the herring song ^^ */
277           if (get_current_music() != HURRYUP_MUSIC)
278             {
279               set_current_music(HERRING_MUSIC);
280               play_current_music();
281             }
282         }
283       break;
284     }
285 }
286