#include "Player.hh"
#include "Rope.hh"
#include "Engine.hh"
#include "Graphics.hh"
#include <math.h>
#include <stdexcept>
Rope::Rope(Player &player) :
PhysicsObject(player.state.world, ROPE_MASS, Vector(0,0), Vector(0,0), ROPE, 0.00, false),
player(player),
state(ROPE_FOLDED)
{
// XXX: better shape
std::vector<Vector> shape(4);
shape[0] = Vector(-1, -1);
shape[1] = Vector(-1, 1);
shape[2] = Vector(1, 1);
shape[3] = Vector(1, -1);
setShape(shape);
}
void Rope::throwRope (void) {
state = ROPE_FLYING;
// XXX: this should probably be more dynamic?
length = ROPE_LENGTH;
// copy position + velocity from player
setPosition (player.getPosition());
velocity = player.getVelocity() + player.getDirection() * ROPE_VELOCITY;
// we are FLYING
inAir = true;
// enable the physics object
enable();
// inform network
player.handleRopeState(state);
}
void Rope::onCollision (Vector collisionPoint, PhysicsObject *other) {
// Fix the rope to another player if collided with it
if (other != NULL) {
// we collided with another object
if (other->getType() == PLAYER) {
// set our player's pivot to the object that we collided with
Player *target = dynamic_cast<Player*>(other);
// ignore if the rope hits ourself
if (target == &this->player)
return;
// set player's pivot to the other player
player.setPivot(target);
// disable ourselves as we're no longer relevant, don't keep colliding with the player
disable();
} else {
// ignore other objects
return;
}
} else {
// Collided with terrain, set player's pivot to ourselves
player.setPivot(this);
}
// attached to something!
state = ROPE_FIXED;
velocity = Vector(0,0);
// Ropes location will be used as the pivot point, so move the location to the collisionPoint.
// Currently the position is something like one pixel away from the collisionPoint where there isn't ground.
setPosition(collisionPoint);
// inform network
player.handleRopeState(state);
}
void Rope::release (void) {
// Remove the rope from the PhysicsWorld
disable();
state = ROPE_FOLDED;
// player doesn't have a pivot anymore
player.setPivot(NULL);
// inform network
player.handleRopeState(state);
}
void Rope::changeLength (float delta) {
// change length
length += delta;
// minimum length
if (length < 0)
length = 0;
// inform network
player.handleRopeLength(length);
}
RopeState Rope::getState (void) {
return state;
}
float Rope::getLength (void) {
return length;
}
Player *Rope::getPivotPlayer (void) {
if (player.getPivot() == this)
return NULL;
else
return dynamic_cast<Player*>(player.getPivot());
}
void Rope::updateState (RopeState new_state, Vector position, Vector velocity, float new_length, Player *pivot_player) {
// update physics enabled/disabled state
if (new_state == ROPE_FOLDED || new_state == ROPE_FIXED)
disable();
else // new_state == ROPE_FLYING
enable();
// update player.pivot to either the given pivot_player, or this rope
if (new_state == ROPE_FIXED) {
if (pivot_player)
player.setPivot(pivot_player);
else
player.setPivot(this);
} else if (this->state == ROPE_FIXED)
player.setPivot(NULL);
// update position stuff
updatePhysics(position, velocity, true, FACING_RIGHT, 0);
// update vars
this->state = new_state;
this->length = new_length;
}
void Rope::updateLength (float length) {
// update length
this->length = length;
}
void Rope::draw (Graphics *g, PixelCoordinate camera) {
PixelCoordinate player_pos = player.getCoordinate() - camera;
PixelCoordinate target_pos;
if (state == ROPE_FOLDED) {
return;
} else if (state == ROPE_FLYING) {
// target is us
target_pos = getCoordinate();
} else { // state == ROPE_FIXED
// sanity-check
if (player.getPivot() == NULL)
throw Error("Rope::draw in state ROPE_FIXED, yet player.getPivot() is NULL");
// target is our pivot
target_pos = player.getPivot()->getCoordinate();
}
// align with camera
target_pos -= camera;
// draw a line from the player to the target chosen above
g->get_gc()->draw_line(
player_pos.x, player_pos.y,
target_pos.x, target_pos.y,
CL_Color::black
);
}
void Rope::tick (TimeMS dt) {
if (state == ROPE_FLYING) {
// let PhysicsObject handle the flying stage
PhysicsObject::tick(dt);
} else if (state == ROPE_FIXED) {
// if player's pivot is some other player, then don't re-check the terrain
if (player.getPivot() != this)
return;
// If there's no ground on the pivot point anymore, release the rope
if (!world.collides(position)) {
// XXX: move to some new method
state = ROPE_FLYING;
length = ROPE_LENGTH;
inAir = true;
player.setPivot(NULL);
player.handleRopeState(state);
}
} else { // state == ROPE_FOLDED
// ignore ticks when folded
}
}