Beispiel #1
0
  /** Objects need to be moved back on a failed push, otherwise riders would continue to slide. */
  public static boolean SV_Push(edict_t pusher, float[] move, float[] amove) {
    int i, e;
    edict_t check, block[];
    float[] mins = {0, 0, 0};
    float[] maxs = {0, 0, 0};
    pushed_t p;
    float[] org = {0, 0, 0};
    float[] org2 = {0, 0, 0};
    float[] move2 = {0, 0, 0};
    float[] forward = {0, 0, 0};
    float[] right = {0, 0, 0};
    float[] up = {0, 0, 0};

    // clamp the move to 1/8 units, so the position will
    // be accurate for client side prediction
    for (i = 0; i < 3; i++) {
      float temp;
      temp = move[i] * 8.0f;
      if (temp > 0.0) temp += 0.5;
      else temp -= 0.5;
      move[i] = 0.125f * (int) temp;
    }

    // find the bounding box
    for (i = 0; i < 3; i++) {
      mins[i] = pusher.absmin[i] + move[i];
      maxs[i] = pusher.absmax[i] + move[i];
    }

    //	   we need this for pushing things later
    Math3D.VectorSubtract(Globals.vec3_origin, amove, org);
    Math3D.AngleVectors(org, forward, right, up);

    //	   save the pusher's original position
    GameBase.pushed[GameBase.pushed_p].ent = pusher;
    Math3D.VectorCopy(pusher.s.origin, GameBase.pushed[GameBase.pushed_p].origin);
    Math3D.VectorCopy(pusher.s.angles, GameBase.pushed[GameBase.pushed_p].angles);

    if (pusher.client != null)
      GameBase.pushed[GameBase.pushed_p].deltayaw =
          pusher.client.ps.pmove.delta_angles[Defines.YAW];

    GameBase.pushed_p++;

    //	   move the pusher to it's final position
    Math3D.VectorAdd(pusher.s.origin, move, pusher.s.origin);
    Math3D.VectorAdd(pusher.s.angles, amove, pusher.s.angles);
    GameBase.gi.linkentity(pusher);

    //	   see if any solid entities are inside the final position

    // check= g_edicts + 1;
    for (e = 1; e < GameBase.num_edicts; e++) {
      check = GameBase.g_edicts[e];
      if (!check.inuse) continue;
      if (check.movetype == Defines.MOVETYPE_PUSH
          || check.movetype == Defines.MOVETYPE_STOP
          || check.movetype == Defines.MOVETYPE_NONE
          || check.movetype == Defines.MOVETYPE_NOCLIP) continue;

      if (check.area.prev == null) continue; // not linked in anywhere

      // if the entity is standing on the pusher, it will definitely be
      // moved
      if (check.groundentity != pusher) {
        // see if the ent needs to be tested
        if (check.absmin[0] >= maxs[0]
            || check.absmin[1] >= maxs[1]
            || check.absmin[2] >= maxs[2]
            || check.absmax[0] <= mins[0]
            || check.absmax[1] <= mins[1]
            || check.absmax[2] <= mins[2]) continue;

        // see if the ent's bbox is inside the pusher's final position
        if (SV_TestEntityPosition(check) == null) continue;
      }

      if ((pusher.movetype == Defines.MOVETYPE_PUSH) || (check.groundentity == pusher)) {
        // move this entity
        GameBase.pushed[GameBase.pushed_p].ent = check;
        Math3D.VectorCopy(check.s.origin, GameBase.pushed[GameBase.pushed_p].origin);
        Math3D.VectorCopy(check.s.angles, GameBase.pushed[GameBase.pushed_p].angles);
        GameBase.pushed_p++;

        // try moving the contacted entity
        Math3D.VectorAdd(check.s.origin, move, check.s.origin);
        if (check.client != null) { // FIXME: doesn't rotate monsters?
          check.client.ps.pmove.delta_angles[Defines.YAW] += amove[Defines.YAW];
        }

        // figure movement due to the pusher's amove
        Math3D.VectorSubtract(check.s.origin, pusher.s.origin, org);
        org2[0] = Math3D.DotProduct(org, forward);
        org2[1] = -Math3D.DotProduct(org, right);
        org2[2] = Math3D.DotProduct(org, up);
        Math3D.VectorSubtract(org2, org, move2);
        Math3D.VectorAdd(check.s.origin, move2, check.s.origin);

        // may have pushed them off an edge
        if (check.groundentity != pusher) check.groundentity = null;

        block = SV_TestEntityPosition(check);
        if (block == null) { // pushed ok
          GameBase.gi.linkentity(check);
          // impact?
          continue;
        }

        // if it is ok to leave in the old position, do it
        // this is only relevent for riding entities, not pushed
        // FIXME: this doesn't acount for rotation
        Math3D.VectorSubtract(check.s.origin, move, check.s.origin);
        block = SV_TestEntityPosition(check);

        if (block == null) {
          GameBase.pushed_p--;
          continue;
        }
      }

      // save off the obstacle so we can call the block function
      GameBase.obstacle = check;

      // move back any entities we already moved
      // go backwards, so if the same entity was pushed
      // twice, it goes back to the original position
      for (int ip = GameBase.pushed_p - 1; ip >= 0; ip--) {
        p = GameBase.pushed[ip];
        Math3D.VectorCopy(p.origin, p.ent.s.origin);
        Math3D.VectorCopy(p.angles, p.ent.s.angles);
        if (p.ent.client != null) {
          p.ent.client.ps.pmove.delta_angles[Defines.YAW] = (short) p.deltayaw;
        }
        GameBase.gi.linkentity(p.ent);
      }
      return false;
    }

    //	  FIXME: is there a better way to handle this?
    // see if anything we moved has touched a trigger
    for (int ip = GameBase.pushed_p - 1; ip >= 0; ip--)
      GameBase.G_TouchTriggers(GameBase.pushed[ip].ent);

    return true;
  }