// $Id$
//
-// SuperTux
+// Zeekling - flyer that swoops down when she spots the player
// Copyright (C) 2005 Matthias Braun <matze@braunis.de>
+// Copyright (C) 2006 Christoph Sommer <supertux@2006.expires.deltadevelopment.de>
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
#include "zeekling.hpp"
-
-//TODO: Make the Zeekling behave more interesting
Zeekling::Zeekling(const lisp::Lisp& reader)
{
reader.get("x", start_position.x);
bbox.set_size(31.8, 31.8);
sprite = sprite_manager->create("zeekling");
set_direction = false;
+ state = FLYING;
}
Zeekling::Zeekling(float pos_x, float pos_y, Direction d)
sprite = sprite_manager->create("zeekling");
set_direction = true;
initial_direction = d;
+ state = FLYING;
}
void
return true;
}
-HitResponse
-Zeekling::collision_solid(GameObject& , const CollisionHit& hit)
-{
- if(fabsf(hit.normal.y) > .5) { // hit floor or roof?
+void
+Zeekling::onBumpHorizontal() {
+ if (state == FLYING) {
+ dir = (dir == LEFT ? RIGHT : LEFT);
+ sprite->set_action(dir == LEFT ? "left" : "right");
+ physic.set_velocity_x(dir == LEFT ? -speed : speed);
+ } else
+ if (state == DIVING) {
+ dir = (dir == LEFT ? RIGHT : LEFT);
+ state = FLYING;
+ sprite->set_action(dir == LEFT ? "left" : "right");
+ physic.set_velocity_x(dir == LEFT ? -speed : speed);
physic.set_velocity_y(0);
- } else { // hit right or left
+ } else
+ if (state == CLIMBING) {
dir = (dir == LEFT ? RIGHT : LEFT);
sprite->set_action(dir == LEFT ? "left" : "right");
physic.set_velocity_x(dir == LEFT ? -speed : speed);
}
+}
+
+void
+Zeekling::onBumpVertical() {
+ if (state == FLYING) {
+ physic.set_velocity_y(0);
+ } else
+ if (state == DIVING) {
+ state = CLIMBING;
+ physic.set_velocity_y(speed);
+ sprite->set_action(dir == LEFT ? "left" : "right");
+ } else
+ if (state == CLIMBING) {
+ state = FLYING;
+ physic.set_velocity_y(0);
+ }
+}
+
+HitResponse
+Zeekling::collision_solid(GameObject& , const CollisionHit& hit)
+{
+ if(fabsf(hit.normal.y) > .5) {
+ onBumpVertical();
+ } else {
+ onBumpHorizontal();
+ }
return CONTINUE;
}
+/**
+ * linear prediction of player and badguy positions to decide if we should enter the DIVING state
+ */
+bool
+Zeekling::should_we_dive() {
+ const MovingObject* player = Sector::current()->player;
+ const MovingObject* badguy = this;
+
+ const Vector playerPos = player->get_pos();
+ const Vector playerMov = player->get_movement();
+
+ const Vector badguyPos = badguy->get_pos();
+ const Vector badguyMov = badguy->get_movement();
+
+ // new vertical speed to test with
+ float vy = -2*fabsf(badguyMov.x);
+
+ // do not dive if we are not above the player
+ float height = playerPos.y - badguyPos.y;
+ if (height <= 0) return false;
+
+ // do not dive if we would not descend faster than the player
+ float relSpeed = -vy + playerMov.y;
+ if (relSpeed <= 0) return false;
+
+ // guess number of frames to descend to same height as player
+ float estFrames = height / relSpeed;
+
+ // guess where the player would be at this time
+ float estPx = (playerPos.x + (estFrames * playerMov.x));
+
+ // guess where we would be at this time
+ float estBx = (badguyPos.x + (estFrames * badguyMov.x));
+
+ // near misses are OK, too
+ if (fabsf(estPx - estBx) < 32) return true;
+
+ return false;
+}
+
+void
+Zeekling::active_update(float elapsed_time) {
+ BadGuy::active_update(elapsed_time);
+
+ if (state == FLYING) {
+ if (should_we_dive()) {
+ state = DIVING;
+ physic.set_velocity_y(-2*fabsf(physic.get_velocity_x()));
+ sprite->set_action(dir == LEFT ? "diving-left" : "diving-right");
+ }
+ return;
+ }
+
+ if (state == DIVING) {
+ return;
+ }
+
+ if (state == CLIMBING) {
+ // stop climbing when we're back at initial height
+ if (get_pos().y <= start_position.y) {
+ state = FLYING;
+ physic.set_velocity_y(0);
+ }
+ return;
+ }
+
+}
+
IMPLEMENT_FACTORY(Zeekling, "zeekling")