#include "loadbtr.h"

terrain *terr;

int terrainheight (int x, int z) {
  return terrain_hei (terr, x, z);
}

int isdiagonalstraight (int x, int z) {
  x = (x < 0 ? x * -1 : x);
  z = (z < 0 ? z * -1 : z);
  return !((x + z) % 2);
}

int terrainy (int x, int z) {
  double cx = 0, cz = 0, b = 0, ay = 0, wx = 0, wy = 0, wz = 0;
  cx = (int) floorf ((float) x / 1000);
  cz = (int) floorf ((float) z / 1000);
  if (x % 1000 == 0 && z % 1000 == 0) { /* Corner */
    return terrainheight (cx, cz);
  } else if (x % 1000 == 0) { /* Vertical edge */
    if (terrainheight (cx, cz) == terrainheight (cx, cz + 1))
      return terrainheight (cx, cz);
    else if (terrainheight (cx, cz) < terrainheight (cx, cz + 1)) {
      ay = terrainheight (cx, cz + 1) - terrainheight (cx, cz);
      b = z - (cz * 1000);
      return ay * b / 1000 + terrainheight (cx, cz);
    } else {
      ay = terrainheight (cx, cz) - terrainheight (cx, cz + 1);
      b = (cz + 1) * 1000 - z;
      return ay * b / 1000 + terrainheight (cx, cz + 1);
    }
  } else if (z % 1000 == 0) { /* Horizontal edge */
    if (terrainheight (cx, cz) == terrainheight (cx + 1, cz))
      return terrainheight (cx, cz);
    else if (terrainheight (cx, cz) < terrainheight (cx + 1, cz)) {
      ay = terrainheight (cx + 1, cz) - terrainheight (cx, cz);
      b = x - (cx * 1000);
      return ay * b / 1000 + terrainheight (cx, cz);
    } else {
      ay = terrainheight (cx, cz) - terrainheight (cx + 1, cz);
      b = (cx + 1) * 1000 - x;
      return ay * b / 1000 + terrainheight (cx + 1, cz);
    }
  } else {
    x -= 1000*cx;
    z -= 1000*cz;
    if (isdiagonalstraight (cx, cz)) {
      if (z == x) { /* Diagonal */
        if (terrainheight (cx, cz) == terrainheight (cx + 1, cz + 1))
          return terrainheight (cx, cz);
        else if (terrainheight (cx, cz) < terrainheight (cx + 1, cz + 1)) {
          ay = terrainheight (cx + 1, cz + 1) - terrainheight (cx, cz);
          b = (int) sqrtf (2 * z*z);
          return ay * b / 1414.21 + terrainheight (cx, cz);
        } else {
          ay = terrainheight (cx, cz) - terrainheight (cx + 1, cz + 1);
          b = (int) sqrtf (2 * z*z);
          return ay * b / 1414.21 + terrainheight (cx + 1, cz + 1);
        }
      } else if (z > x) { /* Upper */
        if (terrainheight (cx, cz) == terrainheight (cx, cz + 1) && terrainheight (cx, cz) == terrainheight (cx + 1, cz + 1))
          return terrainheight (cx, cz);
        else {
          wx = (terrainheight (cx + 1, cz + 1) - terrainheight (cx, cz)) * 1000 - (terrainheight (cx, cz + 1) - terrainheight (cx, cz)) * 1000;
          wy = -1000000;
          wz = (terrainheight (cx, cz + 1) - terrainheight (cx, cz)) * 1000;
          return (-x * wx + terrainheight (cx, cz) * wy - z * wz) / wy;
        }
      } else { /* Lower */
        if (terrainheight (cx, cz) == terrainheight (cx + 1, cz) && terrainheight (cx, cz) == terrainheight (cx + 1, cz + 1))
          return terrainheight (cx, cz);
        else {
          wx = (terrainheight (cx + 1, cz) - terrainheight (cx, cz)) * -1000;
          wy = 1000000;
          wz = (terrainheight (cx + 1, cz) - terrainheight (cx, cz)) * 1000 - (terrainheight (cx + 1, cz + 1) - terrainheight (cx, cz)) * 1000;
          return (-x * wx + terrainheight (cx, cz) * wy - z * wz) / wy;
        }
      }
    } else {
      if (z == 1000 - x) { /* Diagonal */
        if (terrainheight (cx + 1, cz) == terrainheight (cx, cz + 1))
          return terrainheight (cx + 1, cz);
        else if (terrainheight (cx + 1, cz) < terrainheight (cx, cz + 1)) {
          ay = terrainheight (cx, cz + 1) - terrainheight (cx + 1, cz);
          b = (int) sqrtf (2 * z*z);
          return ay * b / 1414.21 + terrainheight (cx + 1, cz);
        } else {
          ay = terrainheight (cx + 1, cz) - terrainheight (cx, cz + 1);
          b = (int) sqrtf (2 * z*z);
          return ay * b / 1414.21 + terrainheight (cx, cz + 1);
        }
      } else if (z > 1000 - x) { /* Upper */
        if (terrainheight (cx + 1, cz + 1) == terrainheight (cx + 1, cz) && terrainheight (cx + 1, cz + 1) == terrainheight (cx, cz + 1))
          return terrainheight (cx + 1, cz + 1);
        else {
          wx = (terrainheight (cx, cz + 1) - terrainheight (cx + 1, cz + 1)) * 1000;
          wy = 1000000;
          wz = (terrainheight (cx + 1, cz) - terrainheight (cx + 1, cz + 1)) * 1000;
          return ((1000-x) * wx + terrainheight (cx + 1, cz + 1) * wy + (1000-z) * wz) / wy;
        }
      } else { /* Lower */
        if (terrainheight (cx, cz) == terrainheight (cx + 1, cz) && terrainheight (cx, cz) == terrainheight (cx, cz + 1))
          return terrainheight (cx, cz);
        else {
          wx = (terrainheight (cx + 1, cz) - terrainheight (cx, cz)) * 1000;
          wy = -1000000;
          wz = (terrainheight (cx, cz + 1) - terrainheight (cx, cz)) * 1000;
          return (-x * wx + terrainheight (cx, cz) * wy - z * wz) / wy;
        }
      }
    }
  }
}

int main () {
  terr = loadbtr ("myterrain"); /* Change filename to a BTR filename in the same path */

  /* Your program here, with calls to terrainy */

  terr = clearterrain (terr);
}

