vp_terrain_query

From Virtual Paradise Wiki
Jump to navigation Jump to search
Method call snippet vp_terrain_query(instance, x, z);

Query a terrain tile.

Parameters

These are the parameters that this method requires:

Parameter Usage
VPInstance
instance
Pointer to the instance this method call is intended for
int
tile_x
X tile coordinate (with no terrain scaling, divide coordinates in decameter by 32 to get tile coordinates)
int
tile_z
Z tile coordinate
int[4][4]
revision
16 node revision numbers (4x4: revision[z][x])

Used attributes

This method uses data set in these attributes when called:

Attribute Usage
VP_REFERENCE_NUMBER Is passed to the callback to identify for which method call it is fired

Returns

This method returns a return code integer, which indicates whether the call was successful or errored for any reason:

Return code Cause
VP_RC_SUCCESS Successful call (for methods that have a registered callback, it only means the request has been sent)
VP_RC_NOT_IN_WORLD Bot is not currently in a world

Behavior

Examples

/*
 *  This example will monitor avatars within the area from 0X 0Z to 32X 32Z and teleport them above ground when they go more than 2 meters below the terrain height.
 *  Note: The code assumes that the terrain has not been scaled or offset!
 */

float g_heights[32][32]; // All the heights inside the queried terrain tile (in this example it is a square from coordinate 0,0 to 32,32)

void handle_terrain_node(VPInstance sdk)
{
  int offset_x, offset_z; // Offset cell x and z for storing current node in g_heights

  offset_x = vp_int(sdk, VP_TERRAIN_NODE_X) * 8; 
  offset_z = vp_int(sdk, VP_TERRAIN_NODE_Z) * 8;

  int length; // Not used in this example

  vp_terrain_cell_t (*cell)[8][8] = (vp_terrain_cell_t(*)[8][8])vp_data(sdk, VP_TERRAIN_NODE_DATA, &length);

  for (int i = 0; i < 8; i++)
    for (int j = 0; j < 8; j++)
      g_heights[i + offset_z][j + offset_x] = (*cell)[i][j].height;
}

float get_height(double x, double z)
{
  int x_cell, z_cell; // Terrain cell coordinate is simply the truncated coordinate in decameters

  x_cell = (int)x;
  z_cell = (int)z;

  if (x_cell < 0 || x_cell > 30) // Check if x coordinate is within the queried tile
    return INFINITY;

  if (z_cell < 0 || z_cell > 30) // Check if z coordinate is within the queried tile
    return INFINITY;

  double x_rel, z_rel; // Coordinate within the cell (for calculating the height)

  x_rel = x - trunc(x);
  z_rel = z - trunc(z);

  double base, x_diff, z_diff; // Base height, maximum difference toward x and z.

  // Four cases, depending on what cell it is and which half of the cell
	
  if ((x_cell + z_cell) % 2)
  {
    // Odd cell, diagonal goes from 0,0 to 1,1

    if ((1.0 - x_rel) + z_rel > 1)
    {
      // Upper half of the cell
      base = g_heights[z_cell + 1][x_cell];
      x_diff = g_heights[z_cell + 1][x_cell + 1] - base;
      z_diff = g_heights[z_cell][x_cell] - base;

      z_rel = 1.0 - z_rel;
    }
    else
    {
      // Lower half of the cell
      base = g_heights[z_cell][x_cell + 1];
      x_diff = g_heights[z_cell][x_cell] - base;
      z_diff = g_heights[z_cell + 1][x_cell + 1] - base;

      x_rel = 1.0 - x_rel;
    }
  }
  else
  {
    // Even cell, diagonal goes from 1,0 to 0,1

    if (x_rel + z_rel > 1)
    {
      // Upper half of the cell
      base = g_heights[z_cell + 1][x_cell + 1];
      x_diff = g_heights[z_cell + 1][x_cell] - base;
      z_diff = g_heights[z_cell][x_cell + 1] - base;

      x_rel = 1.0 - x_rel;
      z_rel = 1.0 - z_rel;
    }
    else
    {
      // Lower half of the cell
      base = g_heights[z_cell][x_cell];
      x_diff = g_heights[z_cell][x_cell + 1] - base;
      z_diff = g_heights[z_cell + 1][x_cell] - base;
    }
  }

  return (float)(base + x_diff * x_rel + z_diff * z_rel);
}

void handle_avatar_change(VPInstance sdk)
{
  double x, y, z;

  x = vp_double(sdk, VP_AVATAR_X);
  y = vp_double(sdk, VP_AVATAR_Y);
  z = vp_double(sdk, VP_AVATAR_Z);

  float y_calc;

  y_calc = get_height(x, z);

  if (y_calc != INFINITY) // Inside queried area
  {
    if (y < y_calc - 0.2) //Below the terrain (assuming avatar is shorter than 2 meters)
    {
      printf("WARNING: \"%s\" was moving around below the terrain!\n", vp_string(sdk, VP_AVATAR_NAME));
      vp_teleport_avatar(sdk,
                         vp_int(sdk, VP_AVATAR_SESSION),
                         "",
                         x,
                         y_calc,
                         z,
                         vp_double(sdk, VP_AVATAR_YAW),
                         vp_double(sdk, VP_AVATAR_PITCH)); // Teleport avatar up above ground
    }
  }
}

int main(int argc, const char* argv[])
{
  //...

  vp_event_set(sdk, VP_EVENT_AVATAR_CHANGE, handle_avatar_change);
  vp_event_set(sdk, VP_EVENT_TERRAIN_NODE, handle_terrain_node);

  int rev[4][4];

  memset(rev, 0, sizeof(rev));
  vp_terrain_query(sdk, 0, 0, rev);

  //...
}

See also