2d90234853303903a41763ac0269479f03b26ca3
[supertux.git] / src / gameobjs.cpp
1 //  $Id$
2 // 
3 //  SuperTux
4 //  Copyright (C) 2000 Bill Kendrick <bill@newbreedsoftware.com>
5 //  Copyright (C) 2004 Tobias Glaesser <tobi.web@gmx.de>
6 //
7 //  This program is free software; you can redistribute it and/or
8 //  modify it under the terms of the GNU General Public License
9 //  as published by the Free Software Foundation; either version 2
10 //  of the License, or (at your option) any later version.
11 //
12 //  This program is distributed in the hope that it will be useful,
13 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
14 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 //  GNU General Public License for more details.
16 // 
17 //  You should have received a copy of the GNU General Public License
18 //  along with this program; if not, write to the Free Software
19 //  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
20 //  02111-1307, USA.
21 #include <algorithm>
22 #include <iostream>
23 #include "world.h"
24 #include "tile.h"
25 #include "gameloop.h"
26 #include "gameobjs.h"
27 #include "sprite_manager.h"
28 #include "resources.h"
29 #include "level.h"
30
31 void
32 BouncyDistro::init(float x, float y)
33 {
34   base.x = x;
35   base.y = y;
36   base.ym = -2;
37 }
38
39 void
40 BouncyDistro::action(double frame_ratio)
41 {
42   base.y = base.y + base.ym * frame_ratio;
43
44   base.ym += 0.1 * frame_ratio;
45
46   if (base.ym >= 0)
47     {
48       std::vector<BouncyDistro*>::iterator i
49         = std::find(World::current()->bouncy_distros.begin(), 
50                     World::current()->bouncy_distros.end(), 
51                     this);
52       if (i != World::current()->bouncy_distros.end())
53         World::current()->bouncy_distros.erase(i);
54     }
55 }
56
57 void
58 BouncyDistro::draw()
59 {
60   img_distro[0]->draw(base.x - scroll_x,
61                       base.y - scroll_y);
62 }
63
64
65 void
66 BrokenBrick::init(Tile* tile_, float x, float y, float xm, float ym)
67 {
68   tile    = tile_;
69   base.x  = x;
70   base.y  = y;
71   base.xm = xm;
72   base.ym = ym;
73
74   timer.init(true);
75   timer.start(200);
76 }
77
78 void
79 BrokenBrick::action(double frame_ratio)
80 {
81   base.x = base.x + base.xm * frame_ratio;
82   base.y = base.y + base.ym * frame_ratio;
83
84   if (!timer.check())
85     {
86       std::vector<BrokenBrick*>::iterator i
87         = std::find(World::current()->broken_bricks.begin(), 
88                     World::current()->broken_bricks.end(), 
89                     this);
90       if (i != World::current()->broken_bricks.end())
91         World::current()->broken_bricks.erase(i);
92     }
93 }
94
95 void
96 BrokenBrick::draw()
97 {
98   SDL_Rect src, dest;
99   src.x = rand() % 16;
100   src.y = rand() % 16;
101   src.w = 16;
102   src.h = 16;
103
104   dest.x = (int)(base.x - scroll_x);
105   dest.y = (int)(base.y  - scroll_y);
106   dest.w = 16;
107   dest.h = 16;
108   
109   if (tile->images.size() > 0)
110     tile->images[0]->draw_part(src.x,src.y,dest.x,dest.y,dest.w,dest.h);
111 }
112
113 void
114 BouncyBrick::init(float x, float y)
115 {
116   base.x   = x;
117   base.y   = y;
118   offset   = 0;
119   offset_m = -BOUNCY_BRICK_SPEED;
120   shape    = World::current()->get_level()->gettileid(x, y);
121 }
122
123 void
124 BouncyBrick::action(double frame_ratio)
125 {
126   offset = (offset + offset_m * frame_ratio);
127
128   /* Go back down? */
129   if (offset < -BOUNCY_BRICK_MAX_OFFSET)
130     offset_m = BOUNCY_BRICK_SPEED;
131
132
133   /* Stop bouncing? */
134   if (offset >= 0)
135     {
136       std::vector<BouncyBrick*>::iterator i
137         = std::find(World::current()->bouncy_bricks.begin(), 
138                     World::current()->bouncy_bricks.end(), 
139                     this);
140       if (i != World::current()->bouncy_bricks.end())
141         World::current()->bouncy_bricks.erase(i);
142     }
143 }
144
145 void
146 BouncyBrick::draw()
147 {
148   SDL_Rect dest;
149   
150   if (base.x >= scroll_x - 32 &&
151       base.x <= scroll_x + screen->w)
152     {
153       dest.x = (int)(base.x - scroll_x);
154       dest.y = (int)(base.y - scroll_y);
155       dest.w = 32;
156       dest.h = 32;
157
158       Level* plevel = World::current()->get_level();
159
160       // FIXME: overdrawing hack to clean the tile from the screen to
161       // paint it later at on offseted position
162       if(plevel->bkgd_image[0] == '\0')
163         {
164           fillrect(base.x - scroll_x, base.y - scroll_y,
165                    32,32, 
166                    plevel->bkgd_top.red, plevel->bkgd_top.green, plevel->bkgd_top.blue, 0);
167 // FIXME: doesn't respect the gradient, futhermore is this necessary at all??
168         }
169       else
170         {
171           int s = ((int)scroll_x / 2)%640;
172           plevel->img_bkgd->draw_part(dest.x + s, dest.y, 
173                                       dest.x, dest.y,dest.w,dest.h);
174         }
175
176       Tile::draw(base.x - scroll_x,
177                  base.y - scroll_y + offset,
178                  shape);
179     }
180 }
181
182 void
183 FloatingScore::init(float x, float y, int s)
184 {
185   base.x = x;
186   base.y = y - 16;
187   timer.init(true);
188   timer.start(1000);
189   value = s;
190 }
191
192 void
193 FloatingScore::action(double frame_ratio)
194 {
195   base.y = base.y - 2 * frame_ratio;
196
197   if(!timer.check())
198     {
199       std::vector<FloatingScore*>::iterator i
200         = std::find(World::current()->floating_scores.begin(), 
201                     World::current()->floating_scores.end(), 
202                     this);
203       if (i != World::current()->floating_scores.end())
204         World::current()->floating_scores.erase(i);
205     }
206 }
207
208 void
209 FloatingScore::draw()
210 {
211   char str[10];
212   sprintf(str, "%d", value);
213   gold_text->draw(str, (int)base.x + 16 - strlen(str) * 8, (int)base.y, 1);
214 }
215
216 /* Trampoline */
217
218 #define TRAMPOLINE_FRAMES 4
219 Sprite *img_trampoline[TRAMPOLINE_FRAMES];
220
221 void load_object_gfx()
222 {
223   char sprite_name[16];
224
225   for (int i = 0; i < TRAMPOLINE_FRAMES; i++)
226   {
227     sprintf(sprite_name, "trampoline-%i", i+1);
228     img_trampoline[i] = sprite_manager->load(sprite_name);
229   }
230 }
231
232 void
233 Trampoline::init(float x, float y)
234 {
235   base.x = x;
236   base.y = y;
237   base.width = 32;
238   base.height = 32;
239
240   frame = 0;
241   mode = M_NORMAL;
242   physic.reset();
243 }
244
245 void
246 Trampoline::draw()
247 {
248   img_trampoline[frame]->draw((int)base.x, (int)base.y);
249
250   frame = 0;
251
252   if (debug_mode)
253     fillrect(base.x - scroll_x, base.y - scroll_y, base.width, base.height, 75, 75, 0, 150);
254 }
255
256 void
257 Trampoline::action(double frame_ratio)
258 {
259   // TODO: Remove if we're too far off the screen
260
261   // Falling
262   if (mode != M_HELD)
263   {
264     if (issolid(base.x + base.width/2, base.y + base.height))
265     {
266       base.y = int((base.y + base.height)/32) * 32 - base.height;
267
268       physic.enable_gravity(false);
269       physic.set_velocity_y(0.0f);
270
271       physic.set_velocity_x(0);
272     }
273     else
274     {
275       physic.enable_gravity(true);
276     }
277   }
278   else // Player is carrying us around
279   {
280     /* FIXME: The trampoline object shouldn't know about pplayer objects. */
281     /* If we're holding the iceblock */
282     Player& tux = *World::current()->get_tux();
283     Direction dir = tux.dir;
284
285     if(dir == RIGHT)
286     {
287       base.x = tux.base.x + 16;
288       base.y = tux.base.y + tux.base.height/1.5 - base.height;
289     }
290     else /* facing left */
291     {
292       base.x = tux.base.x - 16;
293       base.y = tux.base.y + tux.base.height/1.5 - base.height;
294     }
295
296     if(collision_object_map(base))
297     {
298       base.x = tux.base.x;
299       base.y = tux.base.y + tux.base.height/1.5 - base.height;
300     }
301   }
302
303   physic.apply(frame_ratio, base.x, base.y);
304   collision_swept_object_map(&old_base, &base);
305 }
306
307 void
308 Trampoline::collision(void *p_c_object, int c_object, CollisionType type)
309 {
310   Player* pplayer_c = NULL;
311   switch (c_object)
312   {
313     case CO_PLAYER:
314       pplayer_c = (Player*) p_c_object;
315
316       if (type == COLLISION_NORMAL)
317       {
318         // Pick up if HELD (done in Player)
319       }
320
321       else if (type == COLLISION_SQUISH)
322       {
323         int squish_amount = (32 - (int)pplayer_c->base.y % 32);
324
325         if (squish_amount < 24)
326           frame = 3;
327         else if (squish_amount < 28)
328           frame = 2;
329         else if (squish_amount < 30)
330           frame = 1;
331         else
332           frame = 0;
333
334         if (squish_amount < 20)
335           pplayer_c->physic.set_velocity_y(power);
336         else if (pplayer_c->physic.get_velocity_y() < 0)
337           pplayer_c->physic.set_velocity_y(-squish_amount/32);
338       }
339
340       break;
341
342     default:
343       break;
344     
345   }
346 }
347
348 /* EOF */
349