3 // SuperTux - A Jump'n Run
4 // Copyright (C) 2004 Matthias Braun <matze@braunis.de
6 // This program is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU General Public License
8 // as published by the Free Software Foundation; either version 2
9 // of the License, or (at your option) any later version.
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
16 // You should have received a copy of the GNU General Public License
17 // along with this program; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
27 #include "app/globals.h"
29 #include "utils/lispreader.h"
34 #include "background.h"
35 #include "particlesystem.h"
38 #include "audio/sound_manager.h"
40 #include "resources.h"
41 #include "interactive_object.h"
43 #include "statistics.h"
45 Sector* Sector::_current = 0;
48 : end_sequence_animation_type(NONE_ENDSEQ_ANIM),
49 gravity(10), player(0), solids(0), background(0), camera(0),
50 currentmusic(LEVEL_MUSIC)
52 song_title = "Mortimers_chipdisko.mod";
53 player = new Player();
59 for(GameObjects::iterator i = gameobjects.begin(); i != gameobjects.end();
63 for(SpawnPoints::iterator i = spawnpoints.begin(); i != spawnpoints.end();
71 Sector *Sector::create(const std::string& name, size_t width, size_t height)
73 Sector *sector = new Sector;
75 TileMap *background = new TileMap(LAYER_BACKGROUNDTILES, false, width, height);
76 TileMap *interactive = new TileMap(LAYER_TILES, true, width, height);
77 TileMap *foreground = new TileMap(LAYER_FOREGROUNDTILES, false, width, height);
78 sector->add_object(background);
79 sector->add_object(interactive);
80 sector->add_object(foreground);
81 sector->solids = interactive;
82 sector->camera = new Camera(sector);
83 sector->add_object(sector->camera);
84 sector->update_game_objects();
89 Sector::parse(LispReader& lispreader)
93 for(lisp_object_t* cur = lispreader.get_lisp(); !lisp_nil_p(cur);
94 cur = lisp_cdr(cur)) {
95 std::string token = lisp_symbol(lisp_car(lisp_car(cur)));
96 // FIXME: doesn't handle empty data
97 lisp_object_t* data = lisp_car(lisp_cdr(lisp_car(cur)));
98 LispReader reader(lisp_cdr(lisp_car(cur)));
100 if(token == "name") {
101 name = lisp_string(data);
102 } else if(token == "gravity") {
103 gravity = lisp_real(data);
104 } else if(token == "music") {
105 song_title = lisp_string(data);
107 } else if(token == "end-sequence-animation") {
108 std::string end_seq_anim = lisp_string(data);
109 if(end_seq_anim == "fireworks")
110 end_sequence_animation_type = FIREWORKS_ENDSEQ_ANIM;
111 } else if(token == "camera") {
113 std::cerr << "Warning: More than 1 camera defined in sector.\n";
116 camera = new Camera(this);
117 camera->read(reader);
119 } else if(token == "background") {
120 background = new Background(reader);
121 add_object(background);
122 } else if(token == "spawn-points") {
123 SpawnPoint* sp = new SpawnPoint;
124 reader.read_string("name", sp->name);
125 reader.read_float("x", sp->pos.x);
126 reader.read_float("y", sp->pos.y);
127 spawnpoints.push_back(sp);
128 } else if(token == "tilemap") {
129 TileMap* tilemap = new TileMap(reader);
132 if(tilemap->is_solid()) {
134 std::cerr << "Warning multiple solid tilemaps in sector.\n";
139 } else if(badguykind_from_string(token) != BAD_INVALID) {
140 add_object(new BadGuy(badguykind_from_string(token), reader));
141 } else if(token == "trampoline") {
142 add_object(new Trampoline(reader));
143 } else if(token == "flying-platform") {
144 add_object(new FlyingPlatform(reader));
145 } else if(token == "particles-snow") {
146 SnowParticleSystem* partsys = new SnowParticleSystem();
147 partsys->parse(reader);
149 } else if(token == "particles-clouds") {
150 CloudParticleSystem* partsys = new CloudParticleSystem();
151 partsys->parse(reader);
153 } else if(token == "door") {
154 add_object(new Door(reader));
156 std::cerr << "Unknown object type '" << token << "'.\n";
161 std::cerr << "sector '" << name << "' does not contain a camera.\n";
162 camera = new Camera(this);
166 throw std::runtime_error("sector does not contain a solid tile layer.");
170 Sector::parse_old_format(LispReader& reader)
175 reader.read_float("gravity", gravity);
177 std::string backgroundimage;
178 reader.read_string("background", backgroundimage);
180 reader.read_float("bkgd_speed", bgspeed);
183 Color bkgd_top, bkgd_bottom;
184 int r = 0, g = 0, b = 128;
185 reader.read_int("bkgd_red_top", r);
186 reader.read_int("bkgd_green_top", g);
187 reader.read_int("bkgd_blue_top", b);
192 reader.read_int("bkgd_red_bottom", r);
193 reader.read_int("bkgd_green_bottom", g);
194 reader.read_int("bkgd_blue_bottom", b);
196 bkgd_bottom.green = g;
197 bkgd_bottom.blue = b;
199 if(backgroundimage != "") {
200 background = new Background;
201 background->set_image(backgroundimage, bgspeed);
202 add_object(background);
204 background = new Background;
205 background->set_gradient(bkgd_top, bkgd_bottom);
206 add_object(background);
209 std::string end_seq_anim;
210 reader.read_string("end-sequence-animation", end_seq_anim);
211 if(end_seq_anim == "fireworks")
212 end_sequence_animation_type = FIREWORKS_ENDSEQ_ANIM;
214 // end_sequence_animation = NONE_ENDSEQ_ANIM;
216 std::string particlesystem;
217 reader.read_string("particle_system", particlesystem);
218 if(particlesystem == "clouds")
219 add_object(new CloudParticleSystem());
220 else if(particlesystem == "snow")
221 add_object(new SnowParticleSystem());
223 Vector startpos(100, 170);
224 reader.read_float("start_pos_x", startpos.x);
225 reader.read_float("start_pos_y", startpos.y);
227 SpawnPoint* spawn = new SpawnPoint;
228 spawn->pos = startpos;
229 spawn->name = "main";
230 spawnpoints.push_back(spawn);
232 song_title = "Mortimers_chipdisko.mod";
233 reader.read_string("music", song_title);
236 int width, height = 15;
237 reader.read_int("width", width);
238 reader.read_int("height", height);
240 std::vector<unsigned int> tiles;
241 if(reader.read_int_vector("interactive-tm", tiles)
242 || reader.read_int_vector("tilemap", tiles)) {
243 TileMap* tilemap = new TileMap();
244 tilemap->set(width, height, tiles, LAYER_TILES, true);
249 if(reader.read_int_vector("background-tm", tiles)) {
250 TileMap* tilemap = new TileMap();
251 tilemap->set(width, height, tiles, LAYER_BACKGROUNDTILES, false);
255 if(reader.read_int_vector("foreground-tm", tiles)) {
256 TileMap* tilemap = new TileMap();
257 tilemap->set(width, height, tiles, LAYER_FOREGROUNDTILES, false);
261 // read reset-points (now spawn-points)
263 lisp_object_t* cur = 0;
264 if(reader.read_lisp("reset-points", cur)) {
265 while(!lisp_nil_p(cur)) {
266 lisp_object_t* data = lisp_car(cur);
267 LispReader reader(lisp_cdr(data));
270 if(reader.read_float("x", sp_pos.x) && reader.read_float("y", sp_pos.y))
272 SpawnPoint* sp = new SpawnPoint;
275 spawnpoints.push_back(sp);
285 lisp_object_t* cur = 0;
286 if(reader.read_lisp("objects", cur)) {
287 while(!lisp_nil_p(cur)) {
288 lisp_object_t* data = lisp_car(cur);
289 std::string object_type = lisp_symbol(lisp_car(data));
291 LispReader reader(lisp_cdr(data));
293 if(object_type == "trampoline") {
294 add_object(new Trampoline(reader));
296 else if(object_type == "flying-platform") {
297 add_object(new FlyingPlatform(reader));
300 BadGuyKind kind = badguykind_from_string(object_type);
301 add_object(new BadGuy(kind, reader));
310 camera = new Camera(this);
315 Sector::write(LispWriter& writer)
317 writer.write_string("name", name);
318 writer.write_float("gravity", gravity);
319 writer.write_string("music", song_title);
322 for(SpawnPoints::iterator i = spawnpoints.begin(); i != spawnpoints.end();
324 SpawnPoint* spawn = *i;
325 writer.start_list("spawn-points");
326 writer.write_string("name", spawn->name);
327 writer.write_float("x", spawn->pos.x);
328 writer.write_float("y", spawn->pos.y);
329 writer.end_list("spawn-points");
333 for(GameObjects::iterator i = gameobjects.begin();
334 i != gameobjects.end(); ++i) {
335 Serializable* serializable = dynamic_cast<Serializable*> (*i);
337 serializable->write(writer);
342 Sector::do_vertical_flip()
344 for(GameObjects::iterator i = gameobjects_new.begin(); i != gameobjects_new.end(); ++i)
346 TileMap* tilemap = dynamic_cast<TileMap*> (*i);
349 tilemap->do_vertical_flip();
352 BadGuy* badguy = dynamic_cast<BadGuy*> (*i);
354 badguy->start_position.y = solids->get_height()*32 - badguy->start_position.y - 32;
355 Trampoline* trampoline = dynamic_cast<Trampoline*> (*i);
357 trampoline->base.y = solids->get_height()*32 - trampoline->base.y - 32;
358 FlyingPlatform* flying_platform = dynamic_cast<FlyingPlatform*> (*i);
360 flying_platform->base.y = solids->get_height()*32 - flying_platform->base.y - 32;
361 Door* door = dynamic_cast<Door*> (*i);
363 door->set_area(door->get_area().x, solids->get_height()*32 - door->get_area().y - 32);
366 for(SpawnPoints::iterator i = spawnpoints.begin(); i != spawnpoints.end();
368 SpawnPoint* spawn = *i;
369 spawn->pos.y = solids->get_height()*32 - spawn->pos.y - 32;
374 Sector::add_object(GameObject* object)
376 gameobjects_new.push_back(object);
380 Sector::activate(const std::string& spawnpoint)
384 // Apply bonuses from former levels
385 switch (player_status.bonus)
387 case PlayerStatus::NO_BONUS:
390 case PlayerStatus::FLOWER_BONUS:
391 player->got_power = Player::FIRE_POWER; // FIXME: add ice power to here
394 case PlayerStatus::GROWUP_BONUS:
400 for(SpawnPoints::iterator i = spawnpoints.begin(); i != spawnpoints.end();
402 if((*i)->name == spawnpoint) {
408 std::cerr << "Spawnpoint '" << spawnpoint << "' not found.\n";
410 player->move(sp->pos);
413 camera->reset(Vector(player->base.x, player->base.y));
417 Sector::get_best_spawn_point(Vector pos)
419 Vector best_reset_point = Vector(-1,-1);
421 for(SpawnPoints::iterator i = spawnpoints.begin(); i != spawnpoints.end();
423 if((*i)->name != "main")
425 if((*i)->pos.x > best_reset_point.x && (*i)->pos.x < pos.x)
426 best_reset_point = (*i)->pos;
429 return best_reset_point;
433 Sector::action(float elapsed_time)
435 player->check_bounds(camera);
437 /* update objects (don't use iterators here, because the list might change
438 * during the iteration)
440 for(size_t i = 0; i < gameobjects.size(); ++i)
441 if(gameobjects[i]->is_valid())
442 gameobjects[i]->action(elapsed_time);
444 /* Handle all possible collisions. */
447 update_game_objects();
451 Sector::update_game_objects()
453 /** cleanup marked objects */
454 for(std::vector<GameObject*>::iterator i = gameobjects.begin();
455 i != gameobjects.end(); /* nothing */) {
456 if((*i)->is_valid() == false) {
457 BadGuy* badguy = dynamic_cast<BadGuy*> (*i);
459 badguys.erase(std::remove(badguys.begin(), badguys.end(), badguy),
462 Bullet* bullet = dynamic_cast<Bullet*> (*i);
465 std::remove(bullets.begin(), bullets.end(), bullet),
468 InteractiveObject* interactive_object =
469 dynamic_cast<InteractiveObject*> (*i);
470 if(interactive_object) {
471 interactive_objects.erase(
472 std::remove(interactive_objects.begin(), interactive_objects.end(),
473 interactive_object), interactive_objects.end());
475 Upgrade* upgrade = dynamic_cast<Upgrade*> (*i);
478 std::remove(upgrades.begin(), upgrades.end(), upgrade),
481 Trampoline* trampoline = dynamic_cast<Trampoline*> (*i);
484 std::remove(trampolines.begin(), trampolines.end(), trampoline),
487 FlyingPlatform* flying_platform= dynamic_cast<FlyingPlatform*> (*i);
488 if(flying_platform) {
489 flying_platforms.erase(
490 std::remove(flying_platforms.begin(), flying_platforms.end(), flying_platform),
491 flying_platforms.end());
493 SmokeCloud* smoke_cloud = dynamic_cast<SmokeCloud*> (*i);
496 std::remove(smoke_clouds.begin(), smoke_clouds.end(), smoke_cloud),
499 Particles* particle = dynamic_cast<Particles*> (*i);
502 std::remove(particles.begin(), particles.end(), particle),
507 i = gameobjects.erase(i);
513 /* add newly created objects */
514 for(std::vector<GameObject*>::iterator i = gameobjects_new.begin();
515 i != gameobjects_new.end(); ++i)
517 BadGuy* badguy = dynamic_cast<BadGuy*> (*i);
519 badguys.push_back(badguy);
520 Bullet* bullet = dynamic_cast<Bullet*> (*i);
522 bullets.push_back(bullet);
523 Upgrade* upgrade = dynamic_cast<Upgrade*> (*i);
525 upgrades.push_back(upgrade);
526 Trampoline* trampoline = dynamic_cast<Trampoline*> (*i);
528 trampolines.push_back(trampoline);
529 FlyingPlatform* flying_platform = dynamic_cast<FlyingPlatform*> (*i);
531 flying_platforms.push_back(flying_platform);
532 InteractiveObject* interactive_object
533 = dynamic_cast<InteractiveObject*> (*i);
534 if(interactive_object)
535 interactive_objects.push_back(interactive_object);
536 SmokeCloud* smoke_cloud = dynamic_cast<SmokeCloud*> (*i);
538 smoke_clouds.push_back(smoke_cloud);
539 Particles* particle = dynamic_cast<Particles*> (*i);
541 particles.push_back(particle);
543 gameobjects.push_back(*i);
545 gameobjects_new.clear();
549 Sector::draw(DrawingContext& context)
551 context.push_transform();
552 context.set_translation(camera->get_translation());
554 for(GameObjects::iterator i = gameobjects.begin();
555 i != gameobjects.end(); ++i) {
556 if( (*i)->is_valid() )
560 context.pop_transform();
564 Sector::collision_handler()
566 // CO_BULLET & CO_BADGUY check
567 for(unsigned int i = 0; i < bullets.size(); ++i)
569 for (BadGuys::iterator j = badguys.begin(); j != badguys.end(); ++j)
571 if((*j)->dying != DYING_NOT)
574 if(rectcollision(bullets[i]->base, (*j)->base))
576 // We have detected a collision and now call the
577 // collision functions of the collided objects.
578 (*j)->collision(bullets[i], CO_BULLET, COLLISION_NORMAL);
579 bullets[i]->collision(CO_BADGUY);
580 break; // bullet is invalid now, so break
585 /* CO_BADGUY & CO_BADGUY check */
586 for (BadGuys::iterator i = badguys.begin(); i != badguys.end(); ++i)
588 if((*i)->dying != DYING_NOT)
591 BadGuys::iterator j = i;
593 for (; j != badguys.end(); ++j)
595 if(j == i || (*j)->dying != DYING_NOT)
598 if(rectcollision((*i)->base, (*j)->base))
600 // We have detected a collision and now call the
601 // collision functions of the collided objects.
602 (*j)->collision(*i, CO_BADGUY);
603 (*i)->collision(*j, CO_BADGUY);
607 if(player->dying != DYING_NOT) return;
609 // CO_BADGUY & CO_PLAYER check
610 for (BadGuys::iterator i = badguys.begin(); i != badguys.end(); ++i)
612 if((*i)->dying != DYING_NOT)
615 if(rectcollision_offset((*i)->base, player->base, 0, 0))
617 // We have detected a collision and now call the collision
618 // functions of the collided objects.
619 if (player->previous_base.y < player->base.y &&
620 player->previous_base.y + player->previous_base.height
621 < (*i)->base.y + (*i)->base.height/2
622 && !player->invincible_timer.started())
624 (*i)->collision(player, CO_PLAYER, COLLISION_SQUISH);
628 player->collision(*i, CO_BADGUY);
629 (*i)->collision(player, CO_PLAYER, COLLISION_NORMAL);
634 // CO_UPGRADE & CO_PLAYER check
635 for(unsigned int i = 0; i < upgrades.size(); ++i)
637 if(rectcollision(upgrades[i]->base, player->base))
639 // We have detected a collision and now call the collision
640 // functions of the collided objects.
641 upgrades[i]->collision(player, CO_PLAYER, COLLISION_NORMAL);
645 // CO_TRAMPOLINE & (CO_PLAYER or CO_BADGUY)
646 for (Trampolines::iterator i = trampolines.begin(); i != trampolines.end(); ++i)
648 if (rectcollision((*i)->base, player->base))
650 if (player->previous_base.y < player->base.y &&
651 player->previous_base.y + player->previous_base.height
652 < (*i)->base.y + (*i)->base.height/2)
654 (*i)->collision(player, CO_PLAYER, COLLISION_SQUISH);
656 else if (player->previous_base.y <= player->base.y)
658 player->collision(*i, CO_TRAMPOLINE);
659 (*i)->collision(player, CO_PLAYER, COLLISION_NORMAL);
664 // CO_FLYING_PLATFORM & (CO_PLAYER or CO_BADGUY)
665 for (FlyingPlatforms::iterator i = flying_platforms.begin(); i != flying_platforms.end(); ++i)
667 if (rectcollision((*i)->base, player->base))
669 if (player->previous_base.y < player->base.y &&
670 player->previous_base.y + player->previous_base.height
671 < (*i)->base.y + (*i)->base.height/2)
673 (*i)->collision(player, CO_PLAYER, COLLISION_SQUISH);
674 player->collision(*i, CO_FLYING_PLATFORM);
676 /* else if (player->previous_base.y <= player->base.y)
684 Sector::add_score(const Vector& pos, int s)
686 global_stats.add_points(SCORE_STAT, s);
688 add_object(new FloatingText(pos, s));
692 Sector::add_bouncy_distro(const Vector& pos)
694 add_object(new BouncyDistro(pos));
698 Sector::add_broken_brick(const Vector& pos, Tile* tile)
700 add_broken_brick_piece(pos, Vector(-1, -4), tile);
701 add_broken_brick_piece(pos + Vector(0, 16), Vector(-1.5, -3), tile);
703 add_broken_brick_piece(pos + Vector(16, 0), Vector(1, -4), tile);
704 add_broken_brick_piece(pos + Vector(16, 16), Vector(1.5, -3), tile);
708 Sector::add_broken_brick_piece(const Vector& pos, const Vector& movement,
711 add_object(new BrokenBrick(tile, pos, movement));
715 Sector::add_bouncy_brick(const Vector& pos)
717 add_object(new BouncyBrick(pos));
721 Sector::add_bad_guy(float x, float y, BadGuyKind kind, bool activate)
723 BadGuy* badguy = new BadGuy(kind, x, y);
726 badguy->activate(LEFT);
731 Sector::add_upgrade(const Vector& pos, Direction dir, UpgradeKind kind)
733 add_object(new Upgrade(pos, dir, kind));
737 Sector::add_bullet(const Vector& pos, float xm, Direction dir)
739 if(player->got_power == Player::FIRE_POWER)
741 if(bullets.size() > MAX_FIRE_BULLETS-1)
744 else if(player->got_power == Player::ICE_POWER)
746 if(bullets.size() > MAX_ICE_BULLETS-1)
750 Bullet* new_bullet = 0;
751 if(player->got_power == Player::FIRE_POWER)
752 new_bullet = new Bullet(pos, xm, dir, FIRE_BULLET);
753 else if(player->got_power == Player::ICE_POWER)
754 new_bullet = new Bullet(pos, xm, dir, ICE_BULLET);
756 throw std::runtime_error("wrong bullet type.");
757 add_object(new_bullet);
759 SoundManager::get()->play_sound(IDToSound(SND_SHOOT));
765 Sector::add_smoke_cloud(const Vector& pos)
767 add_object(new SmokeCloud(pos));
772 Sector::add_particles(const Vector& epicenter, int min_angle, int max_angle, const Vector& initial_velocity, const Vector& acceleration, int number, Color color, int size, int life_time, int drawing_layer)
774 add_object(new Particles(epicenter, min_angle, max_angle, initial_velocity, acceleration, number, color, size, life_time, drawing_layer));
779 Sector::add_floating_text(const Vector& pos, const std::string& text)
781 add_object(new FloatingText(pos, text));
786 Sector::trybreakbrick(const Vector& pos, bool small)
788 Tile* tile = solids->get_tile_at(pos);
792 sprintf(errmsg, "Invalid tile at %i,%i", (int)((pos.x+1)/32*32), (int)((pos.y+1)/32*32));
793 throw SuperTuxException(errmsg, __FILE__, __LINE__);
796 if (tile->attributes & Tile::BRICK)
800 /* Get a distro from it: */
802 Vector(((int)(pos.x + 1) / 32) * 32, (int)(pos.y / 32) * 32));
804 // TODO: don't handle this in a global way but per-tile...
805 if (!counting_distros)
807 counting_distros = true;
815 if (distro_counter <= 0)
817 counting_distros = false;
818 solids->change_at(pos, tile->next_tile);
821 SoundManager::get()->play_sound(IDToSound(SND_DISTRO));
822 global_stats.add_points(SCORE_STAT, SCORE_DISTRO);
823 global_stats.add_points(COINS_COLLECTED_STAT, 1);
824 player_status.distros++;
830 solids->change_at(pos, tile->next_tile);
832 /* Replace it with broken bits: */
833 add_broken_brick(Vector(
834 ((int)(pos.x + 1) / 32) * 32,
835 (int)(pos.y / 32) * 32), tile);
837 /* Get some score: */
838 SoundManager::get()->play_sound(IDToSound(SND_BRICK));
839 global_stats.add_points(SCORE_STAT, SCORE_BRICK);
850 Sector::tryemptybox(const Vector& pos, Direction col_side)
852 Tile* tile = solids->get_tile_at(pos);
856 sprintf(errmsg, "Invalid tile at %i,%i", (int)((pos.x+1)/32*32), (int)((pos.y+1)/32*32));
857 throw SuperTuxException(errmsg, __FILE__, __LINE__);
861 if (!(tile->attributes & Tile::FULLBOX))
864 // according to the collision side, set the upgrade direction
870 int posx = ((int)(pos.x+1) / 32) * 32;
871 int posy = (int)(pos.y/32) * 32 - 32;
874 case 1: // Box with a distro!
875 add_bouncy_distro(Vector(posx, posy));
876 SoundManager::get()->play_sound(IDToSound(SND_DISTRO));
877 global_stats.add_points(SCORE_STAT, SCORE_DISTRO);
878 global_stats.add_points(COINS_COLLECTED_STAT, 1);
879 player_status.distros++;
882 case 2: // Add a fire flower upgrade!
883 if (player->size == SMALL) /* Tux is small, add mints! */
884 add_upgrade(Vector(posx, posy), col_side, UPGRADE_GROWUP);
885 else /* Tux is big, add a fireflower: */
886 add_upgrade(Vector(posx, posy), col_side, UPGRADE_FIREFLOWER);
887 SoundManager::get()->play_sound(IDToSound(SND_UPGRADE));
890 case 5: // Add an ice flower upgrade!
891 if (player->size == SMALL) /* Tux is small, add mints! */
892 add_upgrade(Vector(posx, posy), col_side, UPGRADE_GROWUP);
893 else /* Tux is big, add an iceflower: */
894 add_upgrade(Vector(posx, posy), col_side, UPGRADE_ICEFLOWER);
895 SoundManager::get()->play_sound(IDToSound(SND_UPGRADE));
898 case 3: // Add a golden herring
899 add_upgrade(Vector(posx, posy), col_side, UPGRADE_STAR);
902 case 4: // Add a 1up extra
903 add_upgrade(Vector(posx, posy), col_side, UPGRADE_1UP);
910 solids->change_at(pos, tile->next_tile);
913 /* Try to grab a distro: */
915 Sector::trygrabdistro(const Vector& pos, int bounciness)
917 Tile* tile = solids->get_tile_at(pos);
921 sprintf(errmsg, "Invalid tile at %i,%i", (int)((pos.x+1)/32*32), (int)((pos.y+1)/32*32));
922 throw SuperTuxException(errmsg, __FILE__, __LINE__); */
924 //Bad tiles (i.e. tiles that are not defined in supertux.stgt but appear in the map) are changed to ID 0 (blank tile)
925 std::cout << "Warning: Undefined tile at " <<(int)pos.x/32 << "/" << (int)pos.y/32 << " (ID: " << (int)solids->get_tile_id_at(pos).id << ")" << std::endl;
926 solids->change_at(pos,0);
927 tile = solids->get_tile_at(pos);
931 if (!(tile->attributes & Tile::COIN))
934 solids->change_at(pos, tile->next_tile);
935 SoundManager::get()->play_sound(IDToSound(SND_DISTRO));
937 if (bounciness == BOUNCE)
939 add_bouncy_distro(Vector(((int)(pos.x + 1) / 32) * 32,
940 (int)(pos.y / 32) * 32));
943 global_stats.add_points(SCORE_STAT, SCORE_DISTRO);
944 global_stats.add_points(COINS_COLLECTED_STAT, 1);
945 player_status.distros++;
949 /* Try to bump a bad guy from below: */
951 Sector::trybumpbadguy(const Vector& pos)
954 for (BadGuys::iterator i = badguys.begin(); i != badguys.end(); ++i)
956 if ((*i)->base.x >= pos.x - 32 && (*i)->base.x <= pos.x + 32 &&
957 (*i)->base.y >= pos.y - 16 && (*i)->base.y <= pos.y + 16)
959 (*i)->collision(player, CO_PLAYER, COLLISION_BUMP);
964 for (unsigned int i = 0; i < upgrades.size(); i++)
966 if (upgrades[i]->base.height == 32 &&
967 upgrades[i]->base.x >= pos.x - 32 && upgrades[i]->base.x <= pos.x + 32 &&
968 upgrades[i]->base.y >= pos.y - 16 && upgrades[i]->base.y <= pos.y + 16)
970 upgrades[i]->collision(player, CO_PLAYER, COLLISION_BUMP);
981 level_song = SoundManager::get()->load_music(datadir + "/music/" + song_title);
983 song_path = (char *) malloc(sizeof(char) * datadir.length() +
984 strlen(song_title.c_str()) + 8 + 5);
985 song_subtitle = strdup(song_title.c_str());
986 strcpy(strstr(song_subtitle, "."), "\0");
987 sprintf(song_path, "%s/music/%s-fast%s", datadir.c_str(),
988 song_subtitle, strstr(song_title.c_str(), "."));
989 if(!SoundManager::get()->exists_music(song_path)) {
990 level_song_fast = level_song;
992 level_song_fast = SoundManager::get()->load_music(song_path);
999 Sector::play_music(int type)
1001 currentmusic = type;
1002 switch(currentmusic) {
1004 SoundManager::get()->play_music(level_song_fast);
1007 SoundManager::get()->play_music(level_song);
1010 SoundManager::get()->play_music(herring_song);
1013 SoundManager::get()->halt_music();
1019 Sector::get_music_type()
1021 return currentmusic;
1025 Sector::get_total_badguys()
1027 int total_badguys = 0;
1028 for(GameObjects::iterator i = gameobjects_new.begin(); i != gameobjects_new.end(); ++i)
1030 BadGuy* badguy = dynamic_cast<BadGuy*> (*i);
1034 return total_badguys;