#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) {
if (other->getType() == PLAYER) {
Player *target = dynamic_cast<Player*>(other);
if (target == &(this->player))
return;
this->player.pivot = target;
} else if (other->getType() == PROJECTILE) {
return;
}
} else { // Collided with terrain
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;
}
void Rope::updateState (RopeState new_state, Vector position, Vector velocity, float new_length) {
// update physics enabled/disabled state
if (new_state == ROPE_FOLDED || new_state == ROPE_FIXED)
disable();
else // new_state == ROPE_FLYING
enable();
// update player.pivot
if (new_state == ROPE_FIXED)
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) {
if (state == ROPE_FOLDED)
return;
PixelCoordinate player_pos = player.getCoordinate() - camera;
PixelCoordinate self_pos = getCoordinate() - camera;
g->get_gc()->draw_line(
player_pos.x, player_pos.y,
self_pos.x, self_pos.y,
CL_Color::black
);
}
void Rope::tick (TimeMS dt) {
if (this->state == ROPE_FLYING) {
// super
PhysicsObject::tick(dt);
}
else if (this->state == ROPE_FIXED) {
this->position = player.getPivot()->getPosition();
// If players pivot is not this rope but some other player don't do anything
// (though it should be released atleast when the player dies)
if (player.getPivot() != this)
return;
// If there's not ground on the pivot point anymore, release the rope
if (!world.collides(position)) {
state = ROPE_FLYING;
length = ROPE_LENGTH;
inAir = true;
player.setPivot(NULL);
player.handleRopeState(state);
}
}
else { // ROPE_FOLDED
// Rope shouldn't be ticking if it is folded, but this can still happen
// immediately after the rope has been released
}
}