X-Git-Url: https://git.octo.it/?a=blobdiff_plain;f=src%2Fobject%2Fbonus_block.cpp;h=5f067766d8545da8a205c2f0c051589e044b8c14;hb=73cb1e168850018eaa821a42b30bb221dc5186fe;hp=f09cef28f6104773cb2e173beaae74dc09f35cea;hpb=729bc6717bf68314dc9fad25db3a9f728062263e;p=supertux.git diff --git a/src/object/bonus_block.cpp b/src/object/bonus_block.cpp index f09cef28f..5f067766d 100644 --- a/src/object/bonus_block.cpp +++ b/src/object/bonus_block.cpp @@ -1,5 +1,5 @@ // SuperTux -// Copyright (C) 2009 Ingo Ruhnke +// Copyright (C) 2009 Ingo Ruhnke // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -19,25 +19,34 @@ #include "audio/sound_manager.hpp" #include "badguy/badguy.hpp" #include "lisp/list_iterator.hpp" -#include "object/broken_brick.hpp" #include "object/flower.hpp" #include "object/bouncy_coin.hpp" +#include "object/coin_explode.hpp" +#include "object/coin_rain.hpp" #include "object/growup.hpp" #include "object/oneup.hpp" #include "object/player.hpp" #include "object/portable.hpp" +#include "object/powerup.hpp" #include "object/specialriser.hpp" #include "object/star.hpp" +#include "object/trampoline.hpp" #include "sprite/sprite_manager.hpp" #include "supertux/constants.hpp" #include "supertux/level.hpp" #include "supertux/object_factory.hpp" #include "supertux/sector.hpp" +#include + BonusBlock::BonusBlock(const Vector& pos, int data) : - Block(sprite_manager->create("images/objects/bonus_block/bonusblock.sprite")), + Block(SpriteManager::current()->create("images/objects/bonus_block/bonusblock.sprite")), contents(), - object(0) + object(), + hit_counter(1), + sprite_name(), + script(), + lightsprite() { bbox.set_pos(pos); sprite->set_action("normal"); @@ -47,6 +56,26 @@ BonusBlock::BonusBlock(const Vector& pos, int data) : case 3: contents = CONTENT_STAR; break; case 4: contents = CONTENT_1UP; break; case 5: contents = CONTENT_ICEGROW; break; + case 6: contents = CONTENT_LIGHT; + SoundManager::current()->preload("sounds/switch.ogg"); + lightsprite=Surface::create("/images/objects/lightmap_light/bonusblock_light.png"); + break; + case 7: contents = CONTENT_TRAMPOLINE; + //object = new Trampoline(get_pos(), false); //needed if this is to be moved to custom + break; + case 8: contents = CONTENT_CUSTOM; + object = std::make_shared(get_pos(), true); + break; + case 9: contents = CONTENT_CUSTOM; + object = std::make_shared(get_pos(), "images/objects/rock/rock.sprite"); + break; + case 10: contents = CONTENT_RAIN; break; + case 11: contents = CONTENT_EXPLODE; break; + case 12: contents = CONTENT_CUSTOM; + object = std::make_shared(get_pos(), "images/powerups/potions/red-potion.sprite"); + break; + case 13: contents = CONTENT_AIRGROW; break; + case 14: contents = CONTENT_EARTHGROW; break; default: log_warning << "Invalid box contents" << std::endl; contents = CONTENT_COIN; @@ -55,9 +84,13 @@ BonusBlock::BonusBlock(const Vector& pos, int data) : } BonusBlock::BonusBlock(const Reader& lisp) : - Block(sprite_manager->create("images/objects/bonus_block/bonusblock.sprite")), + Block(SpriteManager::current()->create("images/objects/bonus_block/bonusblock.sprite")), contents(), - object(0) + object(0), + hit_counter(1), + sprite_name(), + script(), + lightsprite() { Vector pos; @@ -69,6 +102,13 @@ BonusBlock::BonusBlock(const Reader& lisp) : iter.value()->get(pos.x); } else if(token == "y") { iter.value()->get(pos.y); + } else if(token == "sprite") { + iter.value()->get(sprite_name); + sprite = SpriteManager::current()->create(sprite_name); + } else if(token == "count") { + iter.value()->get(hit_counter); + } else if(token == "script") { + iter.value()->get(script); } else if(token == "contents") { std::string contentstring; iter.value()->get(contentstring); @@ -78,19 +118,34 @@ BonusBlock::BonusBlock(const Reader& lisp) : contents = CONTENT_FIREGROW; } else if(contentstring == "icegrow") { contents = CONTENT_ICEGROW; + } else if(contentstring == "airgrow") { + contents = CONTENT_AIRGROW; + } else if(contentstring == "earthgrow") { + contents = CONTENT_EARTHGROW; } else if(contentstring == "star") { contents = CONTENT_STAR; } else if(contentstring == "1up") { contents = CONTENT_1UP; } else if(contentstring == "custom") { contents = CONTENT_CUSTOM; + } else if(contentstring == "script") { // use when bonusblock is to contain ONLY a script + contents = CONTENT_SCRIPT; + } else if(contentstring == "light") { + contents = CONTENT_LIGHT; + SoundManager::current()->preload("sounds/switch.ogg"); + } else if(contentstring == "trampoline") { + contents = CONTENT_TRAMPOLINE; + } else if(contentstring == "rain") { + contents = CONTENT_RAIN; + } else if(contentstring == "explode") { + contents = CONTENT_EXPLODE; } else { log_warning << "Invalid box contents '" << contentstring << "'" << std::endl; } } else { if(contents == CONTENT_CUSTOM) { - GameObject* game_object = ObjectFactory::instance().create(token, *(iter.lisp())); - object = dynamic_cast (game_object); + GameObjectPtr game_object = ObjectFactory::instance().create(token, *(iter.lisp())); + object = std::dynamic_pointer_cast(game_object); if(object == 0) throw std::runtime_error( "Only MovingObjects are allowed inside BonusBlocks"); @@ -102,27 +157,29 @@ BonusBlock::BonusBlock(const Reader& lisp) : if(contents == CONTENT_CUSTOM && object == 0) throw std::runtime_error("Need to specify content object for custom block"); + if(contents == CONTENT_LIGHT) + lightsprite = Surface::create("/images/objects/lightmap_light/bonusblock_light.png"); bbox.set_pos(pos); } BonusBlock::~BonusBlock() { - delete object; } void -BonusBlock::hit(Player& ) +BonusBlock::hit(Player & player) { - try_open(); + try_open(&player); } HitResponse -BonusBlock::collision(GameObject& other, const CollisionHit& hit){ +BonusBlock::collision(GameObject& other, const CollisionHit& hit_){ Player* player = dynamic_cast (&other); if (player) { - if (player->does_buttjump) try_open(); + if (player->does_buttjump) + try_drop(player); } BadGuy* badguy = dynamic_cast (&other); @@ -131,100 +188,327 @@ BonusBlock::collision(GameObject& other, const CollisionHit& hit){ // Badguy's bottom has to be below the top of the block // SHIFT_DELTA is required to slide over one tile gaps. if( badguy->can_break() && ( badguy->get_bbox().get_bottom() > get_bbox().get_top() + SHIFT_DELTA ) ){ - try_open(); + try_open(player); } } Portable* portable = dynamic_cast (&other); if(portable) { MovingObject* moving = dynamic_cast (&other); if(moving->get_bbox().get_top() > get_bbox().get_bottom() - SHIFT_DELTA) { - try_open(); + try_open(player); } } - return Block::collision(other, hit); + return Block::collision(other, hit_); } void -BonusBlock::try_open() +BonusBlock::try_open(Player *player) { if(sprite->get_action() == "empty") { - sound_manager->play("sounds/brick.wav"); + SoundManager::current()->play("sounds/brick.wav"); return; } Sector* sector = Sector::current(); assert(sector); - assert(sector->player); - Player& player = *(sector->player); - Direction direction = (player.get_bbox().get_middle().x > get_bbox().get_middle().x) ? LEFT : RIGHT; + + if (player == NULL) + player = sector->player; + + if (player == NULL) + return; + + Direction direction = (player->get_bbox().get_middle().x > get_bbox().get_middle().x) ? LEFT : RIGHT; switch(contents) { case CONTENT_COIN: - Sector::current()->add_object(new BouncyCoin(get_pos(), true)); - player.get_status()->add_coins(1); - Sector::current()->get_level()->stats.coins++; + { + Sector::current()->add_object(std::make_shared(get_pos(), true)); + player->get_status()->add_coins(1); + if (hit_counter != 0) + Sector::current()->get_level()->stats.coins++; break; + } case CONTENT_FIREGROW: - if(player.get_status()->bonus == NO_BONUS) { - SpecialRiser* riser = new SpecialRiser(get_pos(), new GrowUp(direction)); + { + if(player->get_status()->bonus == NO_BONUS) { + auto riser = std::make_shared(get_pos(), std::make_shared(direction)); sector->add_object(riser); } else { - SpecialRiser* riser = new SpecialRiser( - get_pos(), new Flower(FIRE_BONUS)); + auto riser = std::make_shared( + get_pos(), std::make_shared(FIRE_BONUS)); sector->add_object(riser); } - sound_manager->play("sounds/upgrade.wav"); + SoundManager::current()->play("sounds/upgrade.wav"); break; + } case CONTENT_ICEGROW: - if(player.get_status()->bonus == NO_BONUS) { - SpecialRiser* riser = new SpecialRiser(get_pos(), new GrowUp(direction)); + { + if(player->get_status()->bonus == NO_BONUS) { + auto riser = std::make_shared(get_pos(), std::make_shared(direction)); sector->add_object(riser); } else { - SpecialRiser* riser = new SpecialRiser( - get_pos(), new Flower(ICE_BONUS)); + auto riser = std::make_shared( + get_pos(), std::make_shared(ICE_BONUS)); sector->add_object(riser); } - sound_manager->play("sounds/upgrade.wav"); + SoundManager::current()->play("sounds/upgrade.wav"); break; + } + + case CONTENT_AIRGROW: + { + if(player->get_status()->bonus == NO_BONUS) { + auto riser = std::make_shared(get_pos(), std::make_shared(direction)); + sector->add_object(riser); + } else { + auto riser = std::make_shared( + get_pos(), std::make_shared(AIR_BONUS)); + sector->add_object(riser); + } + SoundManager::current()->play("sounds/upgrade.wav"); + break; + } + + case CONTENT_EARTHGROW: + { + if(player->get_status()->bonus == NO_BONUS) { + auto riser = std::make_shared(get_pos(), std::make_shared(direction)); + sector->add_object(riser); + } else { + auto riser = std::make_shared( + get_pos(), std::make_shared(EARTH_BONUS)); + sector->add_object(riser); + } + SoundManager::current()->play("sounds/upgrade.wav"); + break; + } case CONTENT_STAR: - sector->add_object(new Star(get_pos() + Vector(0, -32), direction)); + { + sector->add_object(std::make_shared(get_pos() + Vector(0, -32), direction)); + SoundManager::current()->play("sounds/upgrade.wav"); break; + } case CONTENT_1UP: - sector->add_object(new OneUp(get_pos(), direction)); + { + sector->add_object(std::make_shared(get_pos(), direction)); + SoundManager::current()->play("sounds/upgrade.wav"); break; + } case CONTENT_CUSTOM: - SpecialRiser* riser = new SpecialRiser(get_pos(), object); + { + auto riser = std::make_shared(get_pos(), object); object = 0; sector->add_object(riser); - sound_manager->play("sounds/upgrade.wav"); + SoundManager::current()->play("sounds/upgrade.wav"); + break; + } + + case CONTENT_SCRIPT: + { break; } // because scripts always run, this prevents default contents from being assumed + + case CONTENT_LIGHT: + { + if(sprite->get_action() == "on") + sprite->set_action("off"); + else + sprite->set_action("on"); + SoundManager::current()->play("sounds/switch.ogg"); + break; + } + case CONTENT_TRAMPOLINE: + { + auto riser = std::make_shared(get_pos(), std::make_shared(get_pos(), false)); + sector->add_object(riser); + SoundManager::current()->play("sounds/upgrade.wav"); + break; + } + case CONTENT_RAIN: + { + hit_counter = 1; // multiple hits of coin rain is not allowed + Sector::current()->add_object(std::make_shared(get_pos(), true)); + SoundManager::current()->play("sounds/upgrade.wav"); break; + } + case CONTENT_EXPLODE: + { + hit_counter = 1; // multiple hits of coin explode is not allowed + Sector::current()->add_object(std::make_shared(get_pos() + Vector (0, -40))); + SoundManager::current()->play("sounds/upgrade.wav"); + break; + } } - start_bounce(&player); - sprite->set_action("empty"); + if(script != "") { // scripts always run if defined + std::istringstream stream(script); + Sector::current()->run_script(stream, "BonusBlockScript"); + } + + start_bounce(player); + if(hit_counter <= 0 || contents == CONTENT_LIGHT){ //use 0 to allow infinite hits + }else if(hit_counter == 1){ + sprite->set_action("empty"); + }else{ + hit_counter--; + } } void -Block::break_me() +BonusBlock::try_drop(Player *player) { + if(sprite->get_action() == "empty") { + SoundManager::current()->play("sounds/brick.wav"); + return; + } + Sector* sector = Sector::current(); - sector->add_object( - new BrokenBrick(std::auto_ptr(new Sprite(*sprite)), get_pos(), Vector(-100, -400))); - sector->add_object( - new BrokenBrick(std::auto_ptr(new Sprite(*sprite)), get_pos() + Vector(0, 16), - Vector(-150, -300))); - sector->add_object( - new BrokenBrick(std::auto_ptr(new Sprite(*sprite)), get_pos() + Vector(16, 0), - Vector(100, -400))); - sector->add_object( - new BrokenBrick(std::auto_ptr(new Sprite(*sprite)), get_pos() + Vector(16, 16), - Vector(150, -300))); - remove_me(); + assert(sector); + + // First what's below the bonus block, if solid send it up anyway (excepting doll) + Rectf dest_; + dest_.p1.x = bbox.get_left() + 1; + dest_.p1.y = bbox.get_bottom() + 1; + dest_.p2.x = bbox.get_right() - 1; + dest_.p2.y = dest_.p1.y + 30; + if (!Sector::current()->is_free_of_statics(dest_, this, true) && !(contents == CONTENT_1UP)) { + try_open(player); + return; + } + + if (player == NULL) + player = sector->player; + + if (player == NULL) + return; + + Direction direction = (player->get_bbox().get_middle().x > get_bbox().get_middle().x) ? LEFT : RIGHT; + + bool countdown = false; + + switch(contents) { + case CONTENT_COIN: + { + try_open(player); + break; + } + + case CONTENT_FIREGROW: + { + sector->add_object(std::make_shared(get_pos() + Vector(0, 32), "images/powerups/fireflower/fireflower.sprite")); + SoundManager::current()->play("sounds/upgrade.wav"); + countdown = true; + break; + } + + case CONTENT_ICEGROW: + { + sector->add_object(std::make_shared(get_pos() + Vector(0, 32), "images/powerups/iceflower/iceflower.sprite")); + SoundManager::current()->play("sounds/upgrade.wav"); + countdown = true; + break; + } + + case CONTENT_AIRGROW: + { + sector->add_object(std::make_shared(get_pos() + Vector(0, 32), "images/powerups/airflower/airflower.sprite")); + SoundManager::current()->play("sounds/upgrade.wav"); + countdown = true; + break; + } + + case CONTENT_EARTHGROW: + { + sector->add_object(std::make_shared(get_pos() + Vector(0, 32), "images/powerups/earthflower/earthflower.sprite")); + SoundManager::current()->play("sounds/upgrade.wav"); + countdown = true; + break; + } + + case CONTENT_STAR: + { + sector->add_object(std::make_shared(get_pos() + Vector(0, 32), direction)); + SoundManager::current()->play("sounds/upgrade.wav"); + countdown = true; + break; + } + + case CONTENT_1UP: + { + sector->add_object(std::make_shared(get_pos(), DOWN)); + SoundManager::current()->play("sounds/upgrade.wav"); + countdown = true; + break; + } + + case CONTENT_CUSTOM: + { + //NOTE: non-portable trampolines could be moved to CONTENT_CUSTOM, but they should not drop + object->set_pos(get_pos() + Vector(0, 32)); + sector->add_object(object); + object = 0; + SoundManager::current()->play("sounds/upgrade.wav"); + countdown = true; + break; + } + + case CONTENT_SCRIPT: + { break; } // because scripts always run, this prevents default contents from being assumed + + case CONTENT_LIGHT: + { + try_open(player); + break; + } + case CONTENT_TRAMPOLINE: + { + try_open(player); + break; + } + case CONTENT_RAIN: + { + try_open(player); + break; + } + case CONTENT_EXPLODE: + { + hit_counter = 1; // multiple hits of coin explode is not allowed + Sector::current()->add_object(std::make_shared(get_pos() + Vector (0, 40))); + SoundManager::current()->play("sounds/upgrade.wav"); + countdown = true; + break; + } + } + + if(script != "") { // scripts always run if defined + std::istringstream stream(script); + Sector::current()->run_script(stream, "powerup-script"); + } + + if(countdown){ // only decrease hit counter if try_open was not called + if(hit_counter == 1){ + sprite->set_action("empty"); + }else{ + hit_counter--; + } + } } +void +BonusBlock::draw(DrawingContext& context){ + // do the regular drawing first + Block::draw(context); + // then Draw the light if on. + if(sprite->get_action() == "on") { + Vector pos = get_pos() + (bbox.get_size().as_vector() - lightsprite->get_size()) / 2; + context.push_target(); + context.set_target(DrawingContext::LIGHTMAP); + context.draw_surface(lightsprite, pos, 10); + context.pop_target(); + } +} /* EOF */