#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"
#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");
}
}
}
- 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<Portable*> (&other);
+ MovingObject* moving_object = dynamic_cast<MovingObject*> (&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<BadGuy*> (&other);
if(badguy) {
badguy->kill_fall();
}
+
+ // Coins get collected
Coin* coin = dynamic_cast<Coin*> (&other);
if(coin) {
coin->collect();
}
+
+ //Eggs get jumped
+ GrowUp* growup = dynamic_cast<GrowUp*> (&other);
+ if(growup) {
+ growup->do_jump();
+ }
+
}
return SOLID;
{
if(!bouncing)
return;
-
+
float offset = original_y - get_pos().y;
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);
}
}
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<MovingObject*>(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;
}
//---------------------------------------------------------------------------
log_warning << "Invalid box contents" << std::endl;
contents = CONTENT_COIN;
break;
- }
+ }
}
BonusBlock::BonusBlock(const lisp::Lisp& lisp)
} else {
log_warning << "Invalid element '" << token << "' in bonusblock" << std::endl;
}
- }
+ }
}
if(contents == CONTENT_CUSTOM && object == 0)
throw std::runtime_error("Need to specify content object for custom block");
-
+
bbox.set_pos(pos);
}
HitResponse
BonusBlock::collision(GameObject& other, const CollisionHit& hit){
BadGuy* badguy = dynamic_cast<BadGuy*> (&other);
- if(badguy) {
+ if(badguy) {
// hit contains no information for collisions with blocks.
// Badguy's bottom has to be below the top of the bonusblock
// +7 is required to slide over one tile gaps.
try_open();
}
}
+ Portable* portable = dynamic_cast<Portable*> (&other);
+ if(portable) {
+ MovingObject* moving = dynamic_cast<MovingObject*> (&other);
+ if(moving->get_bbox().get_top() > get_bbox().get_bottom() - 7.0) {
+ try_open();
+ }
+ }
return Block::collision(other, hit);
}
sound_manager->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;
+
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:
if(player.get_status()->bonus == NO_BONUS) {
- SpecialRiser* riser = new SpecialRiser(get_pos(), new GrowUp());
+ SpecialRiser* riser = new SpecialRiser(get_pos(), new GrowUp(direction));
sector->add_object(riser);
} else {
SpecialRiser* riser = new SpecialRiser(
case CONTENT_ICEGROW:
if(player.get_status()->bonus == NO_BONUS) {
- SpecialRiser* riser = new SpecialRiser(get_pos(), new GrowUp());
- sector->add_object(riser);
+ SpecialRiser* riser = new SpecialRiser(get_pos(), new GrowUp(direction));
+ sector->add_object(riser);
} else {
SpecialRiser* riser = new SpecialRiser(
get_pos(), new Flower(ICE_BONUS));
sector->add_object(riser);
- }
+ }
sound_manager->play("sounds/upgrade.wav");
break;
case CONTENT_STAR:
- sector->add_object(new Star(get_pos() + Vector(0, -32)));
+ sector->add_object(new Star(get_pos() + Vector(0, -32), direction));
break;
case CONTENT_1UP:
- sector->add_object(new OneUp(get_pos()));
+ sector->add_object(new OneUp(get_pos(), direction));
break;
case CONTENT_CUSTOM:
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");
//---------------------------------------------------------------------------
}
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<Player*> (&other);
+ if (player) {
+ if (player->does_buttjump) try_break();
+ }
+
BadGuy* badguy = dynamic_cast<BadGuy*> (&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<Portable*> (&other);
+ if(portable) {
+ MovingObject* moving = dynamic_cast<MovingObject*> (&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();
}
}
//IMPLEMENT_FACTORY(Brick, "brick");
-