fix player-pivoted rope
authorterom
Mon, 08 Dec 2008 23:21:49 +0000
changeset 328 51d644c8d5a2
parent 327 09a3b5055862
child 329 42ad4965424f
fix player-pivoted rope
src/Network/Client.cc
src/Network/Object.cc
src/Network/Object.hh
src/Network/Protocol.hh
src/Network/Server.cc
src/Rope.cc
src/Rope.hh
--- a/src/Network/Client.cc	Mon Dec 08 23:11:40 2008 +0000
+++ b/src/Network/Client.cc	Mon Dec 08 23:21:49 2008 +0000
@@ -222,16 +222,25 @@
 
     Engine::log(INFO, "client_player.on_rope_throw") << this << ": position=" << position << ", velocity=" << velocity << ", length=" << length;
 
-    rope.updateState(ROPE_FLYING, position, velocity, length);
+    rope.updateState(ROPE_FLYING, position, velocity, length, NULL);
 }
 
 void NetworkClientPlayerBase::on_rope_fixed (NetworkPacketInput &pkt) {
     Vector position = pkt.read_vector();
     float length = pkt.read_float32();
+    NetworkObject *player_obj = controller.read_object(pkt);
+
+    NetworkClientPlayerBase *player = NULL;
+
+    if (player_obj != NULL && (player = dynamic_cast<NetworkClientPlayerBase*>(player_obj)) == NULL) {
+        Engine::log(ERROR, "client.on_rope_fixed") << this << ": Unknown player object";
+        return;
+    }
     
-    Engine::log(INFO, "client_player.on_rope_fixed") << this << ": position=" << position << ", length=" << length;
+    Engine::log(INFO, "client_player.on_rope_fixed") << this << ": position=" << position << ", length=" << length 
+        << ", player=" << player;
 
-    rope.updateState(ROPE_FIXED, position, Vector(0, 0), length);
+    rope.updateState(ROPE_FIXED, position, Vector(0, 0), length, player);
 }
 
 void NetworkClientPlayerBase::on_rope_released (NetworkPacketInput &pkt) {
@@ -240,7 +249,7 @@
     Engine::log(INFO, "client_player.on_rope_released") << this;
     
     // use rope.getPosition() instead of e.g. Vector(0, 0) because it will collide there...
-    rope.updateState(ROPE_FOLDED, rope.getPosition(), Vector(0, 0), 0);
+    rope.updateState(ROPE_FOLDED, rope.getPosition(), Vector(0, 0), 0, NULL);
 }
 
 void NetworkClientPlayerBase::on_rope_length (NetworkPacketInput &pkt) {
--- a/src/Network/Object.cc	Mon Dec 08 23:11:40 2008 +0000
+++ b/src/Network/Object.cc	Mon Dec 08 23:21:49 2008 +0000
@@ -32,14 +32,14 @@
     uint32_t obj_id = pkt.read_uint32();
 
     // lookup object
-    NetworkObject *obj = objects[obj_id];
+    NetworkObject *obj = obj_id ? objects[obj_id] : NULL;
     
     // return
     return obj;
 }
         
 void NetworkObjectController::write_object (NetworkPacketOutput &pkt, NetworkObject *obj) {
-    pkt.write_uint32(obj->obj_id);
+    pkt.write_uint32(obj ? obj->obj_id : 0);
 }
 
 /* 
--- a/src/Network/Object.hh	Mon Dec 08 23:11:40 2008 +0000
+++ b/src/Network/Object.hh	Mon Dec 08 23:21:49 2008 +0000
@@ -79,13 +79,18 @@
 
     public:
         /**
-         * Read an NetworkObjectID from the given packet, and return the corresponding NetworkObject, or NULL if we
-         * don't know it.
+         * Read an NetworkObjectID from the given packet, and return the corresponding NetworkObject, or NULL if:
+         *  * it was zero
+         *  * we don't know the object (should this thrown an exception instead?)
+         *
+         * @return the NetworkObject* corresponding to the NetworkObjectID in the packet, or NULL if zero/not found
          */
         NetworkObject* read_object (NetworkPacketInput &pkt);
 
         /**
-         * Write the given Object's NetworkObjectID to the given packet
+         * Write the given Object's NetworkObjectID (or 0, if the obj is NULL) to the given packet
+         *
+         * @param the NetworkObject* whose NetworkObjectID to write to the packet, or NULL to write zero
          */
         void write_object (NetworkPacketOutput &pkt, NetworkObject *obj);
 };
--- a/src/Network/Protocol.hh	Mon Dec 08 23:11:40 2008 +0000
+++ b/src/Network/Protocol.hh	Mon Dec 08 23:21:49 2008 +0000
@@ -119,6 +119,7 @@
      *
      * Vector   position
      * float    length
+     * Object?  player
      */
     NETMSG_PLAYER_ROPE_FIXED    = 0x0332,
 
--- a/src/Network/Server.cc	Mon Dec 08 23:11:40 2008 +0000
+++ b/src/Network/Server.cc	Mon Dec 08 23:21:49 2008 +0000
@@ -123,7 +123,7 @@
 void NetworkServerPlayer::handleRopeState (RopeState state) {
     NetworkPacket pkt; 
 
-    Engine::log(INFO, "server_player.rope_state") << "state=" << rope.getState() << ", position=" << rope.getPosition() << ", velocity=" << rope.getVelocity() << ", length=" << rope.getLength();
+    Engine::log(INFO, "server_player.rope_state") << "state=" << rope.getState() << ", position=" << rope.getPosition() << ", velocity=" << rope.getVelocity() << ", length=" << rope.getLength() << ", pivotPlayer=" << rope.getPivotPlayer();
 
     switch (state) {
     case ROPE_FLYING:
@@ -135,13 +135,20 @@
         
         break;
 
-    case ROPE_FIXED:
+    case ROPE_FIXED: {
+        Player *player_base = rope.getPivotPlayer();
+        NetworkServerPlayer *player = NULL;
+
+        if (player_base != NULL && (player = dynamic_cast<NetworkServerPlayer*>(player_base)) == NULL)
+            throw Error("NetworkServerPlayer::handleRopeState: rope's pivotPlayer is not a NetworkServerPlayer");
+        
         pkt.write_vector(rope.getPosition());
         pkt.write_float32(rope.getLength());
+        controller.write_object(pkt, player);    // may be NULL
         
         send_all(NETMSG_PLAYER_ROPE_FIXED, pkt, true);
 
-        break;
+    } break;
     
     case ROPE_FOLDED:
         send_all(NETMSG_PLAYER_ROPE_RELEASED, pkt, true);
--- a/src/Rope.cc	Mon Dec 08 23:11:40 2008 +0000
+++ b/src/Rope.cc	Mon Dec 08 23:21:49 2008 +0000
@@ -42,15 +42,28 @@
 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);
-            if (target == &(this->player))
+            
+            // ignore if the rope hits ourself
+            if (target == &this->player)
                 return;
-            this->player.pivot = target;            
-        } else if (other->getType() == PROJECTILE) {
+            
+            // 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
+
+    } else { 
+        // Collided with terrain, set player's pivot to ourselves
         player.setPivot(this);
     }
 
@@ -60,7 +73,7 @@
         
     // 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);
+    setPosition(collisionPoint);
     
     // inform network
     player.handleRopeState(state);
@@ -99,7 +112,14 @@
     return length;
 }
 
-void Rope::updateState (RopeState new_state, Vector position, Vector velocity, float new_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();
@@ -107,11 +127,14 @@
     else // new_state == ROPE_FLYING
         enable();
     
-    // update player.pivot
-    if (new_state == ROPE_FIXED)
-        player.setPivot(this);
+    // 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)
+    } else if (this->state == ROPE_FIXED)
         player.setPivot(NULL);
 
     // update position stuff
@@ -128,44 +151,57 @@
 }
 
 void Rope::draw (Graphics *g, PixelCoordinate camera) {
-    if (state == ROPE_FOLDED)
+    PixelCoordinate player_pos = player.getCoordinate() - camera;
+    PixelCoordinate target_pos;
+
+    if (state == ROPE_FOLDED) {
         return;
 
-    PixelCoordinate player_pos = player.getCoordinate() - camera;
-    PixelCoordinate self_pos = getCoordinate() - camera;
+    } 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,
-        self_pos.x, self_pos.y,
+        target_pos.x, target_pos.y,
         CL_Color::black
     );
 }
 
 void Rope::tick (TimeMS dt) {
-    if (this->state == ROPE_FLYING) {
-        // super
+    if (state == ROPE_FLYING) {
+        // let PhysicsObject handle the flying stage
         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)
+    } 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 not ground on the pivot point anymore, release the rope
+        // 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 { // ROPE_FOLDED
-        // Rope shouldn't be ticking if it is folded, but this can still happen
-        // immediately after the rope has been released
+    } else { // state == ROPE_FOLDED
+        // ignore ticks when folded
     }
 }
+
--- a/src/Rope.hh	Mon Dec 08 23:11:40 2008 +0000
+++ b/src/Rope.hh	Mon Dec 08 23:21:49 2008 +0000
@@ -26,13 +26,13 @@
  */
 class Rope : public PhysicsObject {
 private:
-    // the owner
+    /** the owner */
     Player &player;
 
-    // How long is the rope in its unstrected state
+    /** How long is the rope in its unstreched state */
     float length;
         
-    // basic state
+    /** Current state */
     RopeState state;
 
 protected:
@@ -45,35 +45,40 @@
 public:
     Rope(Player &player);
         
-    /*
+    /**
      * Throw the rope, so it flies up and away: o._-*
      */
     void throwRope (void);
 
-    /*
+    /**
      * Release the rope, so if it's currently fixed or flying, then fold it 
      */
     void release (void);
 
-    /*
+    /**
      * Climb up/down the rope
      */
     void changeLength (float delta);
         
-    /*
+    /**
      * Current state
      */
     RopeState getState (void);
 
-    /*
+    /**
      * Current length
      */
     float getLength (void);
 
+    /**
+     * If this Rope's player is pivoted to another player, return that player-pivot, else return NULL
+     */
+    Player *getPivotPlayer (void);
+
     /*
      * For use by NetworkClient
      */
-    void updateState (RopeState state, Vector position, Vector velocity, float length);
+    void updateState (RopeState state, Vector position, Vector velocity, float length, Player *pivot_player);
     void updateLength (float length);
         
     virtual void tick (TimeMS dt);