- moved gameobjects into there own file
[supertux.git] / src / world.cpp
1 //
2 // C Implementation: world
3 //
4 // Description:
5 //
6 //
7 // Author: Tobias Glaesser <tobi.web@gmx.de>, (C) 2004
8 //
9 // Copyright: See COPYING file that comes with this distribution
10 //
11 //
12
13 #include <math.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include "globals.h"
17 #include "scene.h"
18 #include "screen.h"
19 #include "defines.h"
20 #include "world.h"
21 #include "level.h"
22 #include "tile.h"
23
24 texture_type img_distro[4];
25
26 World* World::current_ = 0;
27
28 World world;
29
30 World::World()
31 {
32   // FIXME: Move this to action and draw and everywhere else where the
33   // world calls child functions
34   current_ = this;
35
36   level = new Level;
37 }
38
39 World::~World()
40 {
41   delete level;
42 }
43
44 void
45 World::set_defaults()
46 {
47   // Set defaults: 
48   scroll_x = 0;
49
50   score_multiplier = 1;
51   timer_init(&super_bkgd_timer, true);
52
53   counting_distros = false;
54   distro_counter = 0;
55
56   endpos = 0;
57
58   /* set current song/music */
59   set_current_music(LEVEL_MUSIC);
60 }
61
62 int
63 World::load(const char* subset, int level_nr)
64 {
65   return level->load(subset, level_nr);
66 }
67
68 int
69 World::load(const std::string& filename)
70 {
71   return level->load(filename);
72 }
73
74 void
75 World::arrays_free(void)
76 {
77   bad_guys.clear();
78   bouncy_distros.clear();
79   broken_bricks.clear();
80   bouncy_bricks.clear();
81   floating_scores.clear();
82   upgrades.clear();
83   bullets.clear();
84   std::vector<ParticleSystem*>::iterator i;
85   for(i = particle_systems.begin(); i != particle_systems.end(); ++i) {
86     delete *i;
87   }
88   particle_systems.clear();
89 }
90
91 void
92 World::activate_bad_guys()
93 {
94   for (std::vector<BadGuyData>::iterator i = level->badguy_data.begin();
95        i != level->badguy_data.end();
96        ++i)
97     {
98       add_bad_guy(i->x, i->y, i->kind);
99     }
100 }
101
102 void
103 World::activate_particle_systems()
104 {
105   if (level->particle_system == "clouds")
106     {
107       particle_systems.push_back(new CloudParticleSystem);
108     }
109   else if (level->particle_system == "snow")
110     {
111       particle_systems.push_back(new SnowParticleSystem);
112     }
113   else if (level->particle_system != "")
114     {
115       st_abort("unknown particle system specified in level", "");
116     }
117 }
118
119 void
120 World::draw()
121 {
122   int y,x;
123
124   /* Draw screen: */
125   if(timer_check(&super_bkgd_timer))
126     texture_draw(&img_super_bkgd, 0, 0);
127   else
128     {
129       /* Draw the real background */
130       if(get_level()->bkgd_image[0] != '\0')
131         {
132           int s = (int)scroll_x / 30;
133           texture_draw_part(&level->img_bkgd, s, 0,0,0,level->img_bkgd.w - s, level->img_bkgd.h);
134           texture_draw_part(&level->img_bkgd, 0, 0,screen->w - s ,0,s,level->img_bkgd.h);
135         }
136       else
137         {
138           clearscreen(level->bkgd_red, level->bkgd_green, level->bkgd_blue);
139         }
140     }
141
142   /* Draw particle systems (background) */
143   std::vector<ParticleSystem*>::iterator p;
144   for(p = particle_systems.begin(); p != particle_systems.end(); ++p)
145     {
146       (*p)->draw(scroll_x, 0, 0);
147     }
148
149   /* Draw background: */
150   for (y = 0; y < 15; ++y)
151     {
152       for (x = 0; x < 21; ++x)
153         {
154           Tile::draw(32*x - fmodf(scroll_x, 32), y * 32,
155                      level->bg_tiles[(int)y][(int)x + (int)(scroll_x / 32)]);
156         }
157     }
158
159   /* Draw interactive tiles: */
160   for (y = 0; y < 15; ++y)
161     {
162       for (x = 0; x < 21; ++x)
163         {
164           Tile::draw(32*x - fmodf(scroll_x, 32), y * 32,
165                      level->ia_tiles[(int)y][(int)x + (int)(scroll_x / 32)]);
166         }
167     }
168
169   /* (Bouncy bricks): */
170   for (unsigned int i = 0; i < bouncy_bricks.size(); ++i)
171     bouncy_brick_draw(&bouncy_bricks[i]);
172
173   for (unsigned int i = 0; i < bad_guys.size(); ++i)
174     bad_guys[i].draw();
175
176   tux.draw();
177
178   for (unsigned int i = 0; i < bullets.size(); ++i)
179     bullet_draw(&bullets[i]);
180
181   for (unsigned int i = 0; i < floating_scores.size(); ++i)
182     floating_score_draw(&floating_scores[i]);
183
184   for (unsigned int i = 0; i < upgrades.size(); ++i)
185     upgrade_draw(&upgrades[i]);
186
187   for (unsigned int i = 0; i < bouncy_distros.size(); ++i)
188     bouncy_distro_draw(&bouncy_distros[i]);
189
190   for (unsigned int i = 0; i < broken_bricks.size(); ++i)
191     broken_brick_draw(&broken_bricks[i]);
192
193   /* Draw foreground: */
194   for (y = 0; y < 15; ++y)
195     {
196       for (x = 0; x < 21; ++x)
197         {
198           Tile::draw(32*x - fmodf(scroll_x, 32), y * 32,
199                      level->fg_tiles[(int)y][(int)x + (int)(scroll_x / 32)]);
200         }
201     }
202
203   /* Draw particle systems (foreground) */
204   for(p = particle_systems.begin(); p != particle_systems.end(); ++p)
205     {
206       (*p)->draw(scroll_x, 0, 1);
207     }
208 }
209
210 void
211 World::action()
212 {
213   /* Handle bouncy distros: */
214   for (unsigned int i = 0; i < bouncy_distros.size(); i++)
215     bouncy_distro_action(&bouncy_distros[i]);
216
217   /* Handle broken bricks: */
218   for (unsigned int i = 0; i < broken_bricks.size(); i++)
219     broken_brick_action(&broken_bricks[i]);
220
221   /* Handle distro counting: */
222   if (counting_distros)
223     {
224       distro_counter--;
225
226       if (distro_counter <= 0)
227         counting_distros = -1;
228     }
229
230   // Handle all kinds of game objects
231   for (unsigned int i = 0; i < bouncy_bricks.size(); i++)
232     bouncy_brick_action(&bouncy_bricks[i]);
233   
234   for (unsigned int i = 0; i < floating_scores.size(); i++)
235     floating_score_action(&floating_scores[i]);
236
237   for (unsigned int i = 0; i < bullets.size(); ++i)
238     bullet_action(&bullets[i]);
239   
240   for (unsigned int i = 0; i < upgrades.size(); i++)
241     upgrade_action(&upgrades[i]);
242
243   for (unsigned int i = 0; i < bad_guys.size(); i++)
244     bad_guys[i].action();
245 }
246
247 void
248 World::add_score(float x, float y, int s)
249 {
250   score += s;
251
252   floating_score_type new_floating_score;
253   floating_score_init(&new_floating_score,x,y,s);
254   floating_scores.push_back(new_floating_score);
255 }
256
257 void
258 World::add_bouncy_distro(float x, float y)
259 {
260   bouncy_distro_type new_bouncy_distro;
261   bouncy_distro_init(&new_bouncy_distro,x,y);
262   bouncy_distros.push_back(new_bouncy_distro);
263 }
264
265 void
266 World::add_broken_brick(Tile* tile, float x, float y)
267 {
268   add_broken_brick_piece(tile, x, y, -1, -4);
269   add_broken_brick_piece(tile, x, y + 16, -1.5, -3);
270
271   add_broken_brick_piece(tile, x + 16, y, 1, -4);
272   add_broken_brick_piece(tile, x + 16, y + 16, 1.5, -3);
273 }
274
275 void
276 World::add_broken_brick_piece(Tile* tile, float x, float y, float xm, float ym)
277 {
278   broken_brick_type new_broken_brick;
279   broken_brick_init(&new_broken_brick, tile, x, y, xm, ym);
280   broken_bricks.push_back(new_broken_brick);
281 }
282
283 void
284 World::add_bouncy_brick(float x, float y)
285 {
286   bouncy_brick_type new_bouncy_brick;
287   bouncy_brick_init(&new_bouncy_brick,x,y);
288   bouncy_bricks.push_back(new_bouncy_brick);
289 }
290
291 void
292 World::add_bad_guy(float x, float y, BadGuyKind kind)
293 {
294   bad_guys.push_back(BadGuy());
295   BadGuy& new_bad_guy = bad_guys.back();
296   
297   new_bad_guy.init(x,y,kind);
298 }
299
300 void
301 World::add_upgrade(float x, float y, int dir, int kind)
302 {
303   upgrade_type new_upgrade;
304   upgrade_init(&new_upgrade,x,y,dir,kind);
305   upgrades.push_back(new_upgrade);
306 }
307
308 void 
309 World::add_bullet(float x, float y, float xm, int dir)
310 {
311   bullet_type new_bullet;
312   bullet_init(&new_bullet,x,y,xm,dir);
313   bullets.push_back(new_bullet);
314   
315   play_sound(sounds[SND_SHOOT], SOUND_CENTER_SPEAKER);
316 }
317
318 /* Break a brick: */
319 void trybreakbrick(float x, float y, bool small)
320 {
321   Level* plevel = World::current()->get_level();
322   
323   Tile* tile = gettile(x, y);
324   if (tile->brick)
325     {
326       if (tile->data > 0)
327         {
328           /* Get a distro from it: */
329           world.add_bouncy_distro(((int)(x + 1) / 32) * 32,
330                                   (int)(y / 32) * 32);
331
332           if (!counting_distros)
333             {
334               counting_distros = true;
335               distro_counter = 50;
336             }
337
338           if (distro_counter <= 0)
339             plevel->change(x, y, TM_IA, tile->next_tile);
340
341           play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
342           score = score + SCORE_DISTRO;
343           distros++;
344         }
345       else if (!small)
346         {
347           /* Get rid of it: */
348           plevel->change(x, y, TM_IA, tile->next_tile);
349           
350           /* Replace it with broken bits: */
351           world.add_broken_brick(tile, 
352                                  ((int)(x + 1) / 32) * 32,
353                                  (int)(y / 32) * 32);
354           
355           /* Get some score: */
356           play_sound(sounds[SND_BRICK], SOUND_CENTER_SPEAKER);
357           score = score + SCORE_BRICK;
358         }
359     }
360 }
361
362 /* Empty a box: */
363 void tryemptybox(float x, float y, int col_side)
364 {
365   Level* plevel = World::current()->get_level();
366
367   Tile* tile = gettile(x,y);
368   if (!tile->fullbox)
369     return;
370
371   // according to the collision side, set the upgrade direction
372   if(col_side == LEFT)
373     col_side = RIGHT;
374   else
375     col_side = LEFT;
376
377   switch(tile->data)
378     {
379     case 1: //'A':      /* Box with a distro! */
380       world.add_bouncy_distro(((int)(x + 1) / 32) * 32, (int)(y / 32) * 32 - 32);
381       play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
382       score = score + SCORE_DISTRO;
383       distros++;
384       break;
385
386     case 2: // 'B':      /* Add an upgrade! */
387       if (tux.size == SMALL)     /* Tux is small, add mints! */
388         world.add_upgrade((int)((x + 1) / 32) * 32, (int)(y / 32) * 32 - 32, col_side, UPGRADE_MINTS);
389       else     /* Tux is big, add coffee: */
390         world.add_upgrade((int)((x + 1) / 32) * 32, (int)(y / 32) * 32 - 32, col_side, UPGRADE_COFFEE);
391       play_sound(sounds[SND_UPGRADE], SOUND_CENTER_SPEAKER);
392       break;
393
394     case 3:// '!':     /* Add a golden herring */
395       world.add_upgrade((int)((x + 1) / 32) * 32, (int)(y / 32) * 32 - 32, col_side, UPGRADE_HERRING);
396       break;
397     default:
398       break;
399     }
400
401   /* Empty the box: */
402   plevel->change(x, y, TM_IA, tile->next_tile);
403 }
404
405 /* Try to grab a distro: */
406 void trygrabdistro(float x, float y, int bounciness)
407 {
408   Level* plevel = World::current()->get_level();
409   Tile* tile = gettile(x, y);
410   if (tile && tile->distro)
411     {
412       plevel->change(x, y, TM_IA, tile->next_tile);
413       play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
414
415       if (bounciness == BOUNCE)
416         {
417           world.add_bouncy_distro(((int)(x + 1) / 32) * 32,
418                                   (int)(y / 32) * 32);
419         }
420
421       score = score + SCORE_DISTRO;
422       distros++;
423     }
424 }
425
426 /* Try to bump a bad guy from below: */
427 void trybumpbadguy(float x, float y)
428 {
429   /* Bad guys: */
430   for (unsigned int i = 0; i < world.bad_guys.size(); i++)
431     {
432       if (world.bad_guys[i].base.x >= x - 32 && world.bad_guys[i].base.x <= x + 32 &&
433           world.bad_guys[i].base.y >= y - 16 && world.bad_guys[i].base.y <= y + 16)
434         {
435           world.bad_guys[i].collision(&tux, CO_PLAYER, COLLISION_BUMP);
436         }
437     }
438
439
440   /* Upgrades: */
441   for (unsigned int i = 0; i < world.upgrades.size(); i++)
442     {
443       if (world.upgrades[i].base.height == 32 &&
444           world.upgrades[i].base.x >= x - 32 && world.upgrades[i].base.x <= x + 32 &&
445           world.upgrades[i].base.y >= y - 16 && world.upgrades[i].base.y <= y + 16)
446         {
447           world.upgrades[i].base.xm = -world.upgrades[i].base.xm;
448           world.upgrades[i].base.ym = -8;
449           play_sound(sounds[SND_BUMP_UPGRADE], SOUND_CENTER_SPEAKER);
450         }
451     }
452 }
453
454 /* EOF */
455