2 // C Implementation: world
7 // Author: Tobias Glaesser <tobi.web@gmx.de>, (C) 2004
9 // Copyright: See COPYING file that comes with this distribution
23 texture_type img_distro[4];
38 World::load(const char* subset, int level_nr)
40 return level->load(subset, level_nr);
44 World::load(const std::string& filename)
46 return level->load(filename);
50 World::arrays_free(void)
53 bouncy_distros.clear();
54 broken_bricks.clear();
55 bouncy_bricks.clear();
56 floating_scores.clear();
59 std::vector<ParticleSystem*>::iterator i;
60 for(i = particle_systems.begin(); i != particle_systems.end(); ++i) {
63 particle_systems.clear();
68 World::activate_particle_systems()
70 if (level->particle_system == "clouds")
72 particle_systems.push_back(new CloudParticleSystem);
74 else if (level->particle_system == "snow")
76 particle_systems.push_back(new SnowParticleSystem);
78 else if (level->particle_system != "")
80 st_abort("unknown particle system specified in level", "");
90 if(timer_check(&super_bkgd_timer))
91 texture_draw(&img_super_bkgd, 0, 0);
94 /* Draw the real background */
95 if(get_level()->bkgd_image[0] != '\0')
97 int s = (int)scroll_x / 30;
98 texture_draw_part(&img_bkgd,s,0,0,0,img_bkgd.w - s, img_bkgd.h);
99 texture_draw_part(&img_bkgd,0,0,screen->w - s ,0,s,img_bkgd.h);
103 clearscreen(level->bkgd_red, level->bkgd_green, level->bkgd_blue);
107 /* Draw particle systems (background) */
108 std::vector<ParticleSystem*>::iterator p;
109 for(p = particle_systems.begin(); p != particle_systems.end(); ++p)
111 (*p)->draw(scroll_x, 0, 0);
114 /* Draw background: */
115 for (y = 0; y < 15; ++y)
117 for (x = 0; x < 21; ++x)
119 drawshape(32*x - fmodf(scroll_x, 32), y * 32,
120 level->bg_tiles[(int)y][(int)x + (int)(scroll_x / 32)]);
124 /* Draw interactive tiles: */
125 for (y = 0; y < 15; ++y)
127 for (x = 0; x < 21; ++x)
129 drawshape(32*x - fmodf(scroll_x, 32), y * 32,
130 level->ia_tiles[(int)y][(int)x + (int)(scroll_x / 32)]);
134 /* (Bouncy bricks): */
135 for (unsigned int i = 0; i < bouncy_bricks.size(); ++i)
136 bouncy_brick_draw(&bouncy_bricks[i]);
138 for (unsigned int i = 0; i < bad_guys.size(); ++i)
143 for (unsigned int i = 0; i < bullets.size(); ++i)
144 bullet_draw(&bullets[i]);
146 for (unsigned int i = 0; i < floating_scores.size(); ++i)
147 floating_score_draw(&floating_scores[i]);
149 for (unsigned int i = 0; i < upgrades.size(); ++i)
150 upgrade_draw(&upgrades[i]);
152 for (unsigned int i = 0; i < bouncy_distros.size(); ++i)
153 bouncy_distro_draw(&bouncy_distros[i]);
155 for (unsigned int i = 0; i < broken_bricks.size(); ++i)
156 broken_brick_draw(&broken_bricks[i]);
158 /* Draw foreground: */
159 for (y = 0; y < 15; ++y)
161 for (x = 0; x < 21; ++x)
163 drawshape(32*x - fmodf(scroll_x, 32), y * 32,
164 level->fg_tiles[(int)y][(int)x + (int)(scroll_x / 32)]);
168 /* Draw particle systems (foreground) */
169 for(p = particle_systems.begin(); p != particle_systems.end(); ++p)
171 (*p)->draw(scroll_x, 0, 1);
178 /* Handle bouncy distros: */
179 for (unsigned int i = 0; i < bouncy_distros.size(); i++)
180 bouncy_distro_action(&bouncy_distros[i]);
182 /* Handle broken bricks: */
183 for (unsigned int i = 0; i < broken_bricks.size(); i++)
184 broken_brick_action(&broken_bricks[i]);
186 /* Handle distro counting: */
187 if (counting_distros)
191 if (distro_counter <= 0)
192 counting_distros = -1;
195 // Handle all kinds of game objects
196 for (unsigned int i = 0; i < bouncy_bricks.size(); i++)
197 bouncy_brick_action(&bouncy_bricks[i]);
199 for (unsigned int i = 0; i < floating_scores.size(); i++)
200 floating_score_action(&floating_scores[i]);
202 for (unsigned int i = 0; i < bullets.size(); ++i)
203 bullet_action(&bullets[i]);
205 for (unsigned int i = 0; i < upgrades.size(); i++)
206 upgrade_action(&upgrades[i]);
208 for (unsigned int i = 0; i < bad_guys.size(); i++)
209 bad_guys[i].action();
213 World::add_score(float x, float y, int s)
217 floating_score_type new_floating_score;
218 floating_score_init(&new_floating_score,x,y,s);
219 floating_scores.push_back(new_floating_score);
223 World::add_bouncy_distro(float x, float y)
225 bouncy_distro_type new_bouncy_distro;
226 bouncy_distro_init(&new_bouncy_distro,x,y);
227 bouncy_distros.push_back(new_bouncy_distro);
231 World::add_broken_brick(Tile* tile, float x, float y)
233 add_broken_brick_piece(tile, x, y, -1, -4);
234 add_broken_brick_piece(tile, x, y + 16, -1.5, -3);
236 add_broken_brick_piece(tile, x + 16, y, 1, -4);
237 add_broken_brick_piece(tile, x + 16, y + 16, 1.5, -3);
241 World::add_broken_brick_piece(Tile* tile, float x, float y, float xm, float ym)
243 broken_brick_type new_broken_brick;
244 broken_brick_init(&new_broken_brick, tile, x, y, xm, ym);
245 broken_bricks.push_back(new_broken_brick);
249 World::add_bouncy_brick(float x, float y)
251 bouncy_brick_type new_bouncy_brick;
252 bouncy_brick_init(&new_bouncy_brick,x,y);
253 bouncy_bricks.push_back(new_bouncy_brick);
257 World::add_bad_guy(float x, float y, BadGuyKind kind)
259 bad_guys.push_back(BadGuy());
260 BadGuy& new_bad_guy = bad_guys.back();
262 new_bad_guy.init(x,y,kind);
266 World::add_upgrade(float x, float y, int dir, int kind)
268 upgrade_type new_upgrade;
269 upgrade_init(&new_upgrade,x,y,dir,kind);
270 upgrades.push_back(new_upgrade);
274 World::add_bullet(float x, float y, float xm, int dir)
276 bullet_type new_bullet;
277 bullet_init(&new_bullet,x,y,xm,dir);
278 bullets.push_back(new_bullet);
280 play_sound(sounds[SND_SHOOT], SOUND_CENTER_SPEAKER);
285 void bouncy_distro_init(bouncy_distro_type* pbouncy_distro, float x, float y)
287 pbouncy_distro->base.x = x;
288 pbouncy_distro->base.y = y;
289 pbouncy_distro->base.ym = -2;
292 void bouncy_distro_action(bouncy_distro_type* pbouncy_distro)
294 pbouncy_distro->base.y = pbouncy_distro->base.y + pbouncy_distro->base.ym * frame_ratio;
296 pbouncy_distro->base.ym += 0.1 * frame_ratio;
298 if (pbouncy_distro->base.ym >= 0)
299 world.bouncy_distros.erase(static_cast<std::vector<bouncy_distro_type>::iterator>(pbouncy_distro));
302 void bouncy_distro_draw(bouncy_distro_type* pbouncy_distro)
304 texture_draw(&img_distro[0],
305 pbouncy_distro->base.x - scroll_x,
306 pbouncy_distro->base.y);
309 void broken_brick_init(broken_brick_type* pbroken_brick, Tile* tile,
310 float x, float y, float xm, float ym)
312 pbroken_brick->tile = tile;
313 pbroken_brick->base.x = x;
314 pbroken_brick->base.y = y;
315 pbroken_brick->base.xm = xm;
316 pbroken_brick->base.ym = ym;
318 timer_init(&pbroken_brick->timer, true);
319 timer_start(&pbroken_brick->timer,200);
322 void broken_brick_action(broken_brick_type* pbroken_brick)
324 pbroken_brick->base.x = pbroken_brick->base.x + pbroken_brick->base.xm * frame_ratio;
325 pbroken_brick->base.y = pbroken_brick->base.y + pbroken_brick->base.ym * frame_ratio;
327 if (!timer_check(&pbroken_brick->timer))
328 world.broken_bricks.erase(static_cast<std::vector<broken_brick_type>::iterator>(pbroken_brick));
331 void broken_brick_draw(broken_brick_type* pbroken_brick)
339 dest.x = (int)(pbroken_brick->base.x - scroll_x);
340 dest.y = (int)pbroken_brick->base.y;
344 if (pbroken_brick->tile->images.size() > 0)
345 texture_draw_part(&pbroken_brick->tile->images[0],
346 src.x,src.y,dest.x,dest.y,dest.w,dest.h);
349 void bouncy_brick_init(bouncy_brick_type* pbouncy_brick, float x, float y)
351 pbouncy_brick->base.x = x;
352 pbouncy_brick->base.y = y;
353 pbouncy_brick->offset = 0;
354 pbouncy_brick->offset_m = -BOUNCY_BRICK_SPEED;
355 pbouncy_brick->shape = GameSession::current()->get_level()->gettileid(x, y);
358 void bouncy_brick_action(bouncy_brick_type* pbouncy_brick)
361 pbouncy_brick->offset = (pbouncy_brick->offset +
362 pbouncy_brick->offset_m * frame_ratio);
366 if (pbouncy_brick->offset < -BOUNCY_BRICK_MAX_OFFSET)
367 pbouncy_brick->offset_m = BOUNCY_BRICK_SPEED;
372 if (pbouncy_brick->offset >= 0)
373 world.bouncy_bricks.erase(static_cast<std::vector<bouncy_brick_type>::iterator>(pbouncy_brick));
376 void bouncy_brick_draw(bouncy_brick_type* pbouncy_brick)
381 if (pbouncy_brick->base.x >= scroll_x - 32 &&
382 pbouncy_brick->base.x <= scroll_x + screen->w)
384 dest.x = (int)(pbouncy_brick->base.x - scroll_x);
385 dest.y = (int)pbouncy_brick->base.y;
389 Level* plevel = GameSession::current()->get_level();
391 // FIXME: overdrawing hack to clean the tile from the screen to
392 // paint it later at on offseted position
393 if(plevel->bkgd_image[0] == '\0')
395 fillrect(pbouncy_brick->base.x - scroll_x, pbouncy_brick->base.y,
397 plevel->bkgd_red, plevel->bkgd_green, plevel->bkgd_blue, 0);
401 s = (int)scroll_x / 30;
402 texture_draw_part(&img_bkgd,dest.x + s,dest.y,dest.x,dest.y,dest.w,dest.h);
405 drawshape(pbouncy_brick->base.x - scroll_x,
406 pbouncy_brick->base.y + pbouncy_brick->offset,
407 pbouncy_brick->shape);
411 void floating_score_init(floating_score_type* pfloating_score, float x, float y, int s)
413 pfloating_score->base.x = x;
414 pfloating_score->base.y = y - 16;
415 timer_init(&pfloating_score->timer,true);
416 timer_start(&pfloating_score->timer,1000);
417 pfloating_score->value = s;
420 void floating_score_action(floating_score_type* pfloating_score)
422 pfloating_score->base.y = pfloating_score->base.y - 2 * frame_ratio;
424 if(!timer_check(&pfloating_score->timer))
425 world.floating_scores.erase(static_cast<std::vector<floating_score_type>::iterator>(pfloating_score));
428 void floating_score_draw(floating_score_type* pfloating_score)
431 sprintf(str, "%d", pfloating_score->value);
432 text_draw(&gold_text, str, (int)pfloating_score->base.x + 16 - strlen(str) * 8, (int)pfloating_score->base.y, 1);
436 void trybreakbrick(float x, float y, bool small)
438 Level* plevel = GameSession::current()->get_level();
440 Tile* tile = gettile(x, y);
445 /* Get a distro from it: */
446 world.add_bouncy_distro(((int)(x + 1) / 32) * 32,
449 if (!counting_distros)
451 counting_distros = true;
455 if (distro_counter <= 0)
456 plevel->change(x, y, TM_IA, tile->next_tile);
458 play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
459 score = score + SCORE_DISTRO;
465 plevel->change(x, y, TM_IA, tile->next_tile);
467 /* Replace it with broken bits: */
468 world.add_broken_brick(tile,
469 ((int)(x + 1) / 32) * 32,
472 /* Get some score: */
473 play_sound(sounds[SND_BRICK], SOUND_CENTER_SPEAKER);
474 score = score + SCORE_BRICK;
480 void tryemptybox(float x, float y, int col_side)
482 Level* plevel = GameSession::current()->get_level();
484 Tile* tile = gettile(x,y);
488 // according to the collision side, set the upgrade direction
496 case 1: //'A': /* Box with a distro! */
497 world.add_bouncy_distro(((int)(x + 1) / 32) * 32, (int)(y / 32) * 32 - 32);
498 play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
499 score = score + SCORE_DISTRO;
503 case 2: // 'B': /* Add an upgrade! */
504 if (tux.size == SMALL) /* Tux is small, add mints! */
505 world.add_upgrade((int)((x + 1) / 32) * 32, (int)(y / 32) * 32 - 32, col_side, UPGRADE_MINTS);
506 else /* Tux is big, add coffee: */
507 world.add_upgrade((int)((x + 1) / 32) * 32, (int)(y / 32) * 32 - 32, col_side, UPGRADE_COFFEE);
508 play_sound(sounds[SND_UPGRADE], SOUND_CENTER_SPEAKER);
511 case 3:// '!': /* Add a golden herring */
512 world.add_upgrade((int)((x + 1) / 32) * 32, (int)(y / 32) * 32 - 32, col_side, UPGRADE_HERRING);
519 plevel->change(x, y, TM_IA, tile->next_tile);
522 /* Try to grab a distro: */
523 void trygrabdistro(float x, float y, int bounciness)
525 Level* plevel = GameSession::current()->get_level();
526 Tile* tile = gettile(x, y);
527 if (tile && tile->distro)
529 plevel->change(x, y, TM_IA, tile->next_tile);
530 play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
532 if (bounciness == BOUNCE)
534 world.add_bouncy_distro(((int)(x + 1) / 32) * 32,
538 score = score + SCORE_DISTRO;
543 /* Try to bump a bad guy from below: */
544 void trybumpbadguy(float x, float y)
547 for (unsigned int i = 0; i < world.bad_guys.size(); i++)
549 if (world.bad_guys[i].base.x >= x - 32 && world.bad_guys[i].base.x <= x + 32 &&
550 world.bad_guys[i].base.y >= y - 16 && world.bad_guys[i].base.y <= y + 16)
552 world.bad_guys[i].collision(&tux, CO_PLAYER, COLLISION_BUMP);
558 for (unsigned int i = 0; i < world.upgrades.size(); i++)
560 if (world.upgrades[i].base.height == 32 &&
561 world.upgrades[i].base.x >= x - 32 && world.upgrades[i].base.x <= x + 32 &&
562 world.upgrades[i].base.y >= y - 16 && world.upgrades[i].base.y <= y + 16)
564 world.upgrades[i].base.xm = -world.upgrades[i].base.xm;
565 world.upgrades[i].base.ym = -8;
566 play_sound(sounds[SND_BUMP_UPGRADE], SOUND_CENTER_SPEAKER);