f96a72cf7e995b0818d1455554b4fe09a6d74bda
[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   for (int i = 0; i < TRAMPOLINE_FRAMES; i++)
224   {
225     char sprite_name[16];
226     sprintf(sprite_name, "trampoline-%i", i+1);
227     img_trampoline[i] = sprite_manager->load(sprite_name);
228   }
229 }
230
231 void
232 Trampoline::init(float x, float y)
233 {
234   base.x = x;
235   base.y = y;
236   base.width = 32;
237   base.height = 32;
238
239   frame = 0;
240   mode = M_NORMAL;
241   physic.reset();
242 }
243
244 void
245 Trampoline::draw()
246 {
247   img_trampoline[frame]->draw((int)base.x, (int)base.y);
248
249   frame = 0;
250
251   if (debug_mode)
252     fillrect(base.x - scroll_x, base.y - scroll_y, base.width, base.height, 75, 75, 0, 150);
253 }
254
255 void
256 Trampoline::action(double frame_ratio)
257 {
258   physic.apply(frame_ratio, base.x, base.y);
259
260   // Falling
261   if (mode != M_HELD)
262   {
263     if (issolid(base.x + base.width/2, base.y + base.height))
264     {
265       base.y = int((base.y + base.height)/32) * 32 - base.height;
266
267       physic.enable_gravity(false);
268       physic.set_velocity_y(0.0f);
269
270       physic.set_velocity_x(0);
271     }
272     else
273     {
274       physic.enable_gravity(true);
275     }
276   }
277   else // Player is carrying us around
278   {
279     /* FIXME: The trampoline object shouldn't know about pplayer objects. */
280     /* If we're holding the iceblock */
281     Player& tux = *World::current()->get_tux();
282     Direction dir = tux.dir;
283
284     if(dir == RIGHT)
285     {
286       base.x = tux.base.x + 16;
287       base.y = tux.base.y + tux.base.height/1.5 - base.height;
288     }
289     else /* facing left */
290     {
291       base.x = tux.base.x - 16;
292       base.y = tux.base.y + tux.base.height/1.5 - base.height;
293     }
294
295     if(collision_object_map(base))
296     {
297       base.x = tux.base.x;
298       base.y = tux.base.y + tux.base.height/1.5 - base.height;
299     }
300   }
301 }
302
303 void
304 Trampoline::collision(void *p_c_object, int c_object, CollisionType type)
305 {
306   Player* pplayer_c = NULL;
307   switch (c_object)
308   {
309     case CO_PLAYER:
310       pplayer_c = (Player*) p_c_object;
311
312       if (type == COLLISION_NORMAL)
313       {
314         // Pick up if HELD (done in Player)
315       }
316
317       else if (type == COLLISION_SQUISH)
318       {
319         int squish_amount = (32 - (int)pplayer_c->base.y % 32);
320
321         if (squish_amount < 24)
322           frame = 3;
323         else if (squish_amount < 28)
324           frame = 2;
325         else if (squish_amount < 30)
326           frame = 1;
327         else
328           frame = 0;
329
330         if (squish_amount < 24)
331           pplayer_c->physic.set_velocity_y(power);
332         else if (pplayer_c->physic.get_velocity_y() < 0)
333           pplayer_c->physic.set_velocity_y(-squish_amount/32);
334       }
335
336       break;
337
338     default:
339       break;
340     
341   }
342 }
343
344 /* EOF */
345