X-Git-Url: https://git.verplant.org/?a=blobdiff_plain;f=src%2Fobject%2Fblock.cpp;h=61bf7c35819d6c28afb6eb226abd7edc51e09dde;hb=ae7bd4f460fdd93934fc0abc9589758a49309bda;hp=4bd14094bdc59998b5c6ddc066bc0fd043f571c3;hpb=a113d3bd1feddd510e3b2852b0d42522735eee40;p=supertux.git diff --git a/src/object/block.cpp b/src/object/block.cpp index 4bd14094b..61bf7c358 100644 --- a/src/object/block.cpp +++ b/src/object/block.cpp @@ -32,6 +32,8 @@ #include "video/drawing_context.hpp" #include "lisp/lisp.hpp" #include "gameobjs.hpp" +#include "portable.hpp" +#include "moving_object.hpp" #include "specialriser.hpp" #include "growup.hpp" #include "flower.hpp" @@ -43,17 +45,18 @@ #include "object_factory.hpp" #include "lisp/list_iterator.hpp" #include "object_factory.hpp" +#include "level.hpp" -static const float BOUNCY_BRICK_MAX_OFFSET=8; -static const float BOUNCY_BRICK_SPEED=90; -static const float EPSILON = .0001; +static const float BOUNCY_BRICK_MAX_OFFSET = 8; +static const float BOUNCY_BRICK_SPEED = 90; +static const float EPSILON = .0001f; +static const float BUMP_ROTATION_ANGLE = 10; Block::Block(Sprite* newsprite) - : sprite(newsprite), bouncing(false), bounce_dir(0), bounce_offset(0) + : sprite(newsprite), bouncing(false), breaking(false), bounce_dir(0), bounce_offset(0), original_y(-1) { - bbox.set_size(32, 32.1); + bbox.set_size(32, 32.1f); set_group(COLGROUP_STATIC); - flags |= FLAG_SOLID; sound_manager->preload("sounds/upgrade.wav"); sound_manager->preload("sounds/brick.wav"); } @@ -73,15 +76,34 @@ Block::collision(GameObject& other, const CollisionHit& ) } } - if(bouncing) { + // only interact with other objects if... + // 1) we are bouncing + // 2) the object is not portable (either never or not currently) + // 3) the object is being hit from below (baguys don't get killed for activating boxes) + Portable* portable = dynamic_cast (&other); + MovingObject* moving_object = dynamic_cast (&other); + bool is_portable = ((portable != 0) && portable->is_portable()); + bool hit_mo_from_below = ((moving_object == 0) || (moving_object->get_bbox().get_bottom() < (get_bbox().get_top() + 7.0))); + if(bouncing && !is_portable && hit_mo_from_below) { + + // Badguys get killed BadGuy* badguy = dynamic_cast (&other); if(badguy) { badguy->kill_fall(); } + + // Coins get collected Coin* coin = dynamic_cast (&other); if(coin) { coin->collect(); } + + //Eggs get jumped + GrowUp* growup = dynamic_cast (&other); + if(growup) { + growup->do_jump(); + } + } return SOLID; @@ -97,10 +119,14 @@ Block::update(float elapsed_time) if(offset > BOUNCY_BRICK_MAX_OFFSET) { bounce_dir = BOUNCY_BRICK_SPEED; movement = Vector(0, bounce_dir * elapsed_time); + if(breaking){ + break_me(); + } } else if(offset < BOUNCY_BRICK_SPEED * elapsed_time && bounce_dir > 0) { movement = Vector(0, offset); bounce_dir = 0; bouncing = false; + sprite->set_angle(0); } else { movement = Vector(0, bounce_dir * elapsed_time); } @@ -113,12 +139,28 @@ Block::draw(DrawingContext& context) } void -Block::start_bounce() +Block::start_bounce(GameObject* hitter) { - original_y = bbox.p1.y; + if(original_y == -1){ + original_y = bbox.p1.y; + } bouncing = true; bounce_dir = -BOUNCY_BRICK_SPEED; bounce_offset = 0; + + MovingObject* hitter_mo = dynamic_cast(hitter); + if (hitter_mo) { + float center_of_hitter = hitter_mo->get_bbox().get_middle().x; + float offset = (get_bbox().get_middle().x - center_of_hitter)*2 / get_bbox().get_width(); + sprite->set_angle(BUMP_ROTATION_ANGLE*offset); + } +} + +void +Block::start_break(GameObject* hitter) +{ + start_bounce(hitter); + breaking = true; } //--------------------------------------------------------------------------- @@ -213,6 +255,13 @@ BonusBlock::collision(GameObject& other, const CollisionHit& hit){ try_open(); } } + Portable* portable = dynamic_cast (&other); + if(portable) { + MovingObject* moving = dynamic_cast (&other); + if(moving->get_bbox().get_top() > get_bbox().get_bottom() - 7.0) { + try_open(); + } + } return Block::collision(other, hit); } @@ -232,8 +281,9 @@ BonusBlock::try_open() switch(contents) { case CONTENT_COIN: - Sector::current()->add_object(new BouncyCoin(get_pos())); + Sector::current()->add_object(new BouncyCoin(get_pos(), true)); player.get_status()->add_coins(1); + Sector::current()->get_level()->stats.coins++; break; case CONTENT_FIREGROW: @@ -276,10 +326,28 @@ BonusBlock::try_open() break; } - start_bounce(); + start_bounce(&player); sprite->set_action("empty"); } +void +Block::break_me() +{ + Sector* sector = Sector::current(); + sector->add_object( + new BrokenBrick(new Sprite(*sprite), get_pos(), Vector(-100, -400))); + sector->add_object( + new BrokenBrick(new Sprite(*sprite), get_pos() + Vector(0, 16), + Vector(-150, -300))); + sector->add_object( + new BrokenBrick(new Sprite(*sprite), get_pos() + Vector(16, 0), + Vector(100, -400))); + sector->add_object( + new BrokenBrick(new Sprite(*sprite), get_pos() + Vector(16, 16), + Vector(150, -300))); + remove_me(); +} + IMPLEMENT_FACTORY(BonusBlock, "bonusblock"); //--------------------------------------------------------------------------- @@ -296,62 +364,68 @@ Brick::Brick(const Vector& pos, int data) } void -Brick::hit(Player& ) +Brick::hit(Player& player) { if(sprite->get_action() == "empty") return; - try_break(true); + try_break(&player); } HitResponse Brick::collision(GameObject& other, const CollisionHit& hit){ + + Player* player = dynamic_cast (&other); + if (player) { + if (player->does_buttjump) try_break(); + } + BadGuy* badguy = dynamic_cast (&other); if(badguy) { // hit contains no information for collisions with blocks. // Badguy's bottom has to be below the top of the brick // +7 is required to slide over one tile gaps. if( badguy->can_break() && ( badguy->get_bbox().get_bottom() > get_bbox().get_top() + 7.0 ) ){ - try_break(false); + try_break(); + } + } + Portable* portable = dynamic_cast (&other); + if(portable) { + MovingObject* moving = dynamic_cast (&other); + if(moving->get_bbox().get_top() > get_bbox().get_bottom() - 7.0) { + try_break(); } } return Block::collision(other, hit); } void -Brick::try_break(bool playerhit) +Brick::try_break(Player* player) { if(sprite->get_action() == "empty") return; sound_manager->play("sounds/brick.wav"); Sector* sector = Sector::current(); - Player& player = *(sector->player); + Player& player_one = *(sector->player); if(coin_counter > 0) { - sector->add_object(new BouncyCoin(get_pos())); + sector->add_object(new BouncyCoin(get_pos(),true)); coin_counter--; - player.get_status()->add_coins(1); + player_one.get_status()->add_coins(1); if(coin_counter == 0) sprite->set_action("empty"); - start_bounce(); + start_bounce(player); } else if(breakable) { - if(playerhit && !player.is_big()) { - start_bounce(); - return; + if(player){ + if(player->is_big()){ + start_break(player); + return; + } else { + start_bounce(player); + return; + } } - - sector->add_object( - new BrokenBrick(new Sprite(*sprite), get_pos(), Vector(-100, -400))); - sector->add_object( - new BrokenBrick(new Sprite(*sprite), get_pos() + Vector(0, 16), - Vector(-150, -300))); - sector->add_object( - new BrokenBrick(new Sprite(*sprite), get_pos() + Vector(16, 0), - Vector(100, -400))); - sector->add_object( - new BrokenBrick(new Sprite(*sprite), get_pos() + Vector(16, 16), - Vector(150, -300))); - remove_me(); + break_me(); } }