Package org.rsbot.script.methods

Source Code of org.rsbot.script.methods.Calculations$Render

package org.rsbot.script.methods;

import org.rsbot.client.TileData;
import org.rsbot.script.wrappers.RSCharacter;
import org.rsbot.script.wrappers.RSComponent;
import org.rsbot.script.wrappers.RSObject;
import org.rsbot.script.wrappers.RSTile;

import java.awt.*;

/**
* Game world and projection calculations.
*/
public class Calculations extends MethodProvider {
  public static class Render {
    public float absoluteX1 = 0, absoluteX2 = 0;
    public float absoluteY1 = 0, absoluteY2 = 0;
    public int xMultiplier = 512, yMultiplier = 512;
    public int zNear = 50, zFar = 3500;
  }

  public static class RenderData {
    public float xOff = 0, xX = 32768, xY = 0, xZ = 0;
    public float yOff = 0, yX = 0, yY = 32768, yZ = 0;
    public float zOff = 0, zX = 0, zY = 0, zZ = 32768;
  }

  public static final int[] SIN_TABLE = new int[16384];
  public static final int[] COS_TABLE = new int[16384];

  static {
    final double d = 0.00038349519697141029D;
    for (int i = 0; i < 16384; i++) {
      Calculations.SIN_TABLE[i] = (int) (32768D * Math.sin(i * d));
      Calculations.COS_TABLE[i] = (int) (32768D * Math.cos(i * d));
    }
  }

  public final Render render = new Render();
  public final RenderData renderData = new RenderData();

  Calculations(final MethodContext ctx) {
    super(ctx);
  }

  /**
   * Returns the angle to a given tile in degrees anti-clockwise from the
   * positive x axis (where the x-axis is from west to east).
   *
   * @param t The target tile
   * @return The angle in degrees
   */
  public int angleToTile(final RSTile t) {
    final RSTile me = methods.players.getMyPlayer().getLocation();
    final int angle = (int) Math.toDegrees(Math.atan2(t.getY() - me.getY(), t.getX() - me.getX()));
    return angle >= 0 ? angle : 360 + angle;
  }

  /**
   * Determines whether or not a given RSTile is reachable by the player.
   *
   * @param dest     The <code>RSTile</code> to check.
   * @param isObject True if an instance of <code>RSObject</code>.
   * @return <tt>true</tt> if a path can be made to the specified tile; otherwise <tt>false</tt>.
   */
  public boolean canReach(final RSTile dest, final boolean isObject) {
    return pathLengthTo(dest, isObject) != -1;
  }

  /**
   * Calculates the distance between two points.
   *
   * @param curr The first point.
   * @param dest The second point.
   * @return The distance between the two points, using the distance formula.
   * @see #distanceBetween(RSTile, RSTile)
   */
  public double distanceBetween(final Point curr, final Point dest) {
    return Math.sqrt((curr.x - dest.x) * (curr.x - dest.x) + (curr.y - dest.y) * (curr.y - dest.y));
  }

  /**
   * Returns the diagonal distance (hypot) between two RSTiles.
   *
   * @param curr The starting tile.
   * @param dest The destination tile.
   * @return The diagonal distance between the two <code>RSTile</code>s.
   * @see #distanceBetween(Point, Point)
   */
  public double distanceBetween(final RSTile curr, final RSTile dest) {
    return Math.sqrt((curr.getX() - dest.getX()) * (curr.getX() - dest.getX()) + (curr.getY() - dest.getY()) * (curr.getY() - dest.getY()));
  }

  /**
   * Returns the diagonal distance to a given RSCharacter.
   *
   * @param c The destination character.
   * @return Distance to <code>RSCharacter</code>.
   * @see #distanceTo(RSTile)
   */
  public int distanceTo(final RSCharacter c) {
    return c == null ? -1 : distanceTo(c.getLocation());
  }

  /**
   * Returns the diagonal distance to a given RSObject.
   *
   * @param o The destination object.
   * @return Distance to <code>RSObject</code>.
   * @see #distanceTo(RSTile)
   */
  public int distanceTo(final RSObject o) {
    return o == null ? -1 : distanceTo(o.getLocation());
  }

  /**
   * Returns the diagonal distance to a given RSTile.
   *
   * @param t The destination tile.
   * @return Distance to <code>RSTile</code>.
   */
  public int distanceTo(final RSTile t) {
    return t == null ? -1 : (int) distanceBetween(methods.players.getMyPlayer().getLocation(), t);
  }

  /**
   * Will return the closest tile that is on screen to the given tile.
   *
   * @param tile Tile you want to get to.
   * @return <code>RSTile</code> that is onScreen.
   */
  public RSTile getTileOnScreen(final RSTile tile) {
    try {
      if (tileOnScreen(tile)) {
        return tile;
      } else {
        final RSTile loc = methods.players.getMyPlayer().getLocation();
        final RSTile halfWayTile = new RSTile((tile.getX() + loc.getX()) / 2, (tile.getY() + loc.getY()) / 2);
        if (tileOnScreen(halfWayTile)) {
          return halfWayTile;
        } else {
          return getTileOnScreen(halfWayTile);
        }
      }
    } catch (final StackOverflowError soe) {
      return null;
    }
  }

  /**
   * Returns the screen location of a given point on the ground. This accounts
   * for the height of the ground at the given location.
   *
   * @param x      x value based on the game plane.
   * @param y      y value based on the game plane.
   * @param height height offset (normal to the ground).
   * @return <code>Point</code> based on screen; otherwise <code>new Point(-1, -1)</code>.
   */
  public Point groundToScreen(final int x, final int y, final int height) {
    if (methods.client.getGroundByteArray() == null || methods.client.getTileData() == null || x < 512 || y < 512 || x > 52224 || y > 52224) {
      return new Point(-1, -1);
    }
    final int z = tileHeight(x, y) + height;
    return worldToScreen(x, y, z);
  }

  /**
   * Returns the length of the path generated to a given RSTile.
   *
   * @param dest     The destination tile.
   * @param isObject <tt>true</tt> if reaching any tile adjacent to the destination should be accepted.
   * @return <tt>true</tt> if reaching any tile adjacent to the destination should be accepted.
   */
  public int pathLengthTo(final RSTile dest, final boolean isObject) {
    final RSTile curPos = methods.players.getMyPlayer().getLocation();
    return pathLengthBetween(curPos, dest, isObject);
  }

  /**
   * Returns the length of the path generates between two RSTiles.
   *
   * @param start    The starting tile.
   * @param dest     The destination tile.
   * @param isObject <tt>true</tt> if reaching any tile adjacent to the destination should be accepted.
   * @return <tt>true</tt> if reaching any tile adjacent to the destination should be accepted.
   */
  public int pathLengthBetween(final RSTile start, final RSTile dest, final boolean isObject) {
    return dijkstraDist(start.getX() - methods.client.getBaseX(), // startX
        start.getY() - methods.client.getBaseY(), // startY
        dest.getX() - methods.client.getBaseX(), // destX
        dest.getY() - methods.client.getBaseY(), // destY
        isObject); // if it's an object, accept any adjacent tile
  }

  /**
   * Checks whether a point is within the rectangle that determines the bounds
   * of game screen. This will work fine when in fixed mode. In resizable mode
   * it will exclude any points that are less than 253 pixels from the right
   * of the screen or less than 169 pixels from the bottom of the screen,
   * giving a rough area.
   *
   * @param check The point to check.
   * @return <tt>true</tt> if the point is within the rectangle; otherwise
   *         <tt>false</tt>.
   */
  public boolean pointOnScreen(final Point check) {
    final int x = check.x, y = check.y;
    if (methods.game.isFixed()) {
      return x > 4 && x < methods.game.getWidth() - 253 && y > 4 && y < methods.game.getHeight() - 169;
    } else {
      return x > 0 && x < methods.game.getWidth() - 260 && y > 0 && y < methods.game.getHeight() - 149;
    }
  }

  /**
   * Returns a random double in a specified range
   *
   * @param min Minimum value (inclusive).
   * @param max Maximum value (exclusive).
   * @return The random <code>double</code> generated.
   */
  @Override
  public double random(final double min, final double max) {
    return Math.min(min, max) + methods.random.nextDouble() * Math.abs(max - min);
  }

  /**
   * Returns the height of the ground at the given location in the game world.
   *
   * @param x x value based on the game plane.
   * @param y y value based on the game plane.
   * @return The ground height at the given location; otherwise <code>0</code>.
   */
  public int tileHeight(final int x, final int y) {
    int p = methods.client.getPlane();
    final int x1 = x >> 9;
    final int y1 = y >> 9;
    final byte[][][] settings = methods.client.getGroundByteArray();
    if (settings != null && x1 >= 0 && x1 < 104 && y1 >= 0 && y1 < 104) {
      if (p <= 3 && (settings[1][x1][y1] & 2) != 0) {
        ++p;
      }
      final TileData[] planes = methods.client.getTileData();
      if (planes != null && p < planes.length && planes[p] != null) {
        final int[][] heights = planes[p].getHeights();
        if (heights != null) {
          final int x2 = x & 512 - 1;
          final int y2 = y & 512 - 1;
          final int start_h = heights[x1][y1] * (512 - x2) + heights[x1 + 1][y1] * x2 >> 9;
          final int end_h = heights[x1][1 + y1] * (512 - x2) + heights[x1 + 1][y1 + 1] * x2 >> 9;
          return start_h * (512 - y2) + end_h * y2 >> 9;
        }
      }
    }
    return 0;
  }

  /**
   * Checks whether or not a given tile is on the minimap.
   *
   * @param t The RSTile to check.
   * @return <tt>true</tt> if the RSTile is on the minimap; otherwise <tt>false</tt>.
   * @see #tileToMinimap(RSTile)
   */
  public boolean tileOnMap(final RSTile t) {
    return distanceTo(t) < 15;
  }

  /**
   * Checks whether or not the centroid of a given tile is on the screen.
   *
   * @param t The RSTile to check.
   * @return <tt>true</tt> if the RSTile is on the screen; otherwise <tt>false</tt>.
   */
  public boolean tileOnScreen(final RSTile t) {
    return pointOnScreen(tileToScreen(t, 0.5, 0.5, 0));
  }

  /**
   * Returns the Point on screen where a given tile is shown on the minimap.
   *
   * @param t The RSTile to check.
   * @return <tt>Point</tt> within minimap; otherwise <tt>new Point(-1, -1)</tt>.
   */
  public Point tileToMinimap(final RSTile t) {
    return worldToMinimap(t.getX(), t.getY());
  }

  /**
   * Returns the screen location of a Tile with given 3D x, y and height
   * offset values.
   *
   * @param tile   RSTile for which the screen location should be calculated.
   * @param dX     Distance from bottom left of the tile to bottom right. Ranges from 0-1;
   * @param dY     Distance from bottom left of the tile to top left. Ranges from 0-1;
   * @param height Height offset (normal to the ground) to return the <code>Point</code> at.
   * @return <code>Point</code> based on position on the game plane; otherwise <code>new Point(-1, -1)</code>.
   */
  public Point tileToScreen(final RSTile tile, final double dX, final double dY, final int height) {
    return groundToScreen((int) ((tile.getX() - methods.client.getBaseX() + dX) * 512),
        (int) ((tile.getY() - methods.client.getBaseY() + dY) * 512), height);
  }

  /**
   * Returns the screen location of a Tile with a given 3D height offset.
   *
   * @param tile   RSTile for which the screen location should be calculated.
   * @param height Height offset (normal to the ground) to return the <code>Point</code> at.
   * @return <code>Point</code> based on position on the game plane; if null <code>new Point(-1, -1)</code>.
   * @see #tileToScreen(RSTile, double, double, int)
   */
  public Point tileToScreen(final RSTile tile, final int height) {
    return tileToScreen(tile, 0.5, 0.5, height);
  }

  /**
   * Returns the screen location of the south-west corner of the given tile.
   *
   * @param tile RSTile for which the screen location should be calculated.
   * @return Center <code>Point</code> of the RSTile at a height of 0; if null <code>new Point(-1, -1)</code>.
   * @see #tileToScreen(RSTile, int)
   */
  public Point tileToScreen(final RSTile tile) {
    return tileToScreen(tile, 0);
  }

  /**
   * Updates the rendering data. For internal use only.
   *
   * @param r  The client graphics toolkit.
   * @param rd The client viewport.
   */
  public void updateRenderInfo(final org.rsbot.client.Render r, final org.rsbot.client.RenderData rd) {
    if (r == null || rd == null) {
      return;
    }
    render.absoluteX1 = r.getAbsoluteX1();
    render.absoluteX2 = r.getAbsoluteX2();
    render.absoluteY1 = r.getAbsoluteY1();
    render.absoluteY2 = r.getAbsoluteY2();
    render.xMultiplier = r.getXMultiplier();
    render.yMultiplier = r.getYMultiplier();
    render.zNear = r.getZNear();
    render.zFar = r.getZFar();
    renderData.xOff = rd.getXOff();
    renderData.xX = rd.getXX();
    renderData.xY = rd.getXY();
    renderData.xZ = rd.getXZ();
    renderData.yOff = rd.getYOff();
    renderData.yX = rd.getYX();
    renderData.yY = rd.getYY();
    renderData.yZ = rd.getYZ();
    renderData.zOff = rd.getZOff();
    renderData.zX = rd.getZX();
    renderData.zY = rd.getZY();
    renderData.zZ = rd.getZZ();
  }

  /**
   * Returns the screen Point of given absolute x and y values in the game's
   * 3D plane.
   *
   * @param x x value based on the game plane.
   * @param y y value based on the game plane.
   * @return <code>Point</code> within minimap; otherwise <tt>new Point(-1, -1)</tt>.
   */
  public Point worldToMinimap(double x, double y) {
    if (distanceBetween(methods.players.getMyPlayer().getLocation(), new RSTile((int) x, (int) y)) > 17) {
      return new Point(-1, -1);
    }
    x -= methods.client.getBaseX();
    y -= methods.client.getBaseY();
    final int calculatedX = (int) (x * 4 + 2) - methods.client.getMyRSPlayer().getX() / 128;
    final int calculatedY = (int) (y * 4 + 2) - methods.client.getMyRSPlayer().getY() / 128;
    try {
      final org.rsbot.client.RSInterface mm = methods.gui.getMinimapInterface();
      if (mm == null) {
        return new Point(-1, -1);
      }
      final RSComponent mm2 = methods.interfaces.getComponent(mm.getID());
      final int actDistSq = calculatedX * calculatedX + calculatedY * calculatedY;
      final int mmDist = 10 + Math.max(mm2.getWidth() / 2, mm2.getHeight() / 2);
      if (mmDist * mmDist >= actDistSq) {
        int angle = 0x3fff & (int) methods.client.getMinimapAngle();
        if (methods.client.getMinimapSetting() != 4) {
          angle = 0x3fff & methods.client.getMinimapOffset() + (int) methods.client.getMinimapAngle();
        }
        int cs = Calculations.SIN_TABLE[angle];
        int cc = Calculations.COS_TABLE[angle];
        if (methods.client.getMinimapSetting() != 4) {
          final int fact = 256 + methods.client.getMinimapScale();
          cs = 256 * cs / fact;
          cc = 256 * cc / fact;
        }
        final int calcCenterX = cc * calculatedX + cs * calculatedY >> 15;
        final int calcCenterY = cc * calculatedY - cs * calculatedX >> 15;
        final int screenx = calcCenterX + mm2.getAbsoluteX() + mm2.getWidth() / 2;
        final int screeny = -calcCenterY + mm2.getAbsoluteY() + mm2.getHeight() / 2;
        return new Point(screenx, screeny);
      }
    } catch (final NullPointerException ignored) {
    }

    return new Point(-1, -1);
  }

  /**
   * Returns the screen location of a given 3D point in the game world.
   *
   * @param x x value on the game plane.
   * @param y y value on the game plane.
   * @param z z value on the game plane.
   * @return <code>Point</code> based on screen; otherwise <code>new Point(-1, -1)</code>.
   */
  public Point worldToScreen(final int x, final int y, final int z) {
    // perspective projection: hooked viewport values are calculated in
    // client based on camera state
    // (so no need to project using camera values and sin/cos)
    // old developers named these fields very poorly
    final float _z = renderData.zOff + (int) (renderData.zX * x + renderData.zY * z + renderData.zZ * y);
    if (_z >= render.zNear && _z <= render.zFar) {
      final int _x = (int) (render.xMultiplier * ((int) renderData.xOff + (int) (renderData.xX * x + renderData.xY
          * z + renderData.xZ * y)) / _z);
      final int _y = (int) (render.yMultiplier * ((int) renderData.yOff + (int) (renderData.yX * x + renderData.yY
          * z + renderData.yZ * y)) / _z);
      if (_x >= render.absoluteX1 && _x <= render.absoluteX2 && _y >= render.absoluteY1 && _y <= render.absoluteY2) {
        if (methods.game.isFixed()) {
          return new Point((int) (_x - render.absoluteX1) + 4, (int) (_y - render.absoluteY1) + 4);
        } else {
          final int sx = (int) (_x - render.absoluteX1), sy = (int) (_y - render.absoluteY1);
          return new Point(sx, sy);
        }
      }
    }
    return new Point(-1, -1);
  }

  /**
   * @param startX       the startX (0 < startX < 104)
   * @param startY       the startY (0 < startY < 104)
   * @param destX        the destX (0 < destX < 104)
   * @param destY        the destY (0 < destY < 104)
   * @param findAdjacent if it's an object, it will find path which touches it.
   * @return The distance of the shortest path to the destination; or -1 if no valid path to the destination was found.
   */
  private int dijkstraDist(final int startX, final int startY, final int destX, final int destY, final boolean findAdjacent) {
    try {
      final int[][] prev = new int[104][104];
      final int[][] dist = new int[104][104];
      final int[] path_x = new int[4000];
      final int[] path_y = new int[4000];
      for (int xx = 0; xx < 104; xx++) {
        for (int yy = 0; yy < 104; yy++) {
          prev[xx][yy] = 0;
          dist[xx][yy] = 99999999;
        }
      }
      int curr_x = startX;
      int curr_y = startY;
      prev[startX][startY] = 99;
      dist[startX][startY] = 0;
      int path_ptr = 0;
      int step_ptr = 0;
      path_x[path_ptr] = startX;
      path_y[path_ptr++] = startY;
      final int blocks[][] = methods.client.getRSGroundDataArray()[methods.game.getPlane()].getBlocks();
      final int pathLength = path_x.length;
      boolean foundPath = false;
      while (step_ptr != path_ptr) {
        curr_x = path_x[step_ptr];
        curr_y = path_y[step_ptr];
        if (Math.abs(curr_x - destX) + Math.abs(curr_y - destY) == (findAdjacent ? 1 : 0)) {
          foundPath = true;
          break;
        }
        step_ptr = (step_ptr + 1) % pathLength;
        final int cost = dist[curr_x][curr_y] + 1;
        // south
        if (curr_y > 0 && prev[curr_x][curr_y - 1] == 0 && (blocks[curr_x + 1][curr_y] & 0x1280102) == 0) {
          path_x[path_ptr] = curr_x;
          path_y[path_ptr] = curr_y - 1;
          path_ptr = (path_ptr + 1) % pathLength;
          prev[curr_x][curr_y - 1] = 1;
          dist[curr_x][curr_y - 1] = cost;
        }
        // west
        if (curr_x > 0 && prev[curr_x - 1][curr_y] == 0 && (blocks[curr_x][curr_y + 1] & 0x1280108) == 0) {
          path_x[path_ptr] = curr_x - 1;
          path_y[path_ptr] = curr_y;
          path_ptr = (path_ptr + 1) % pathLength;
          prev[curr_x - 1][curr_y] = 2;
          dist[curr_x - 1][curr_y] = cost;
        }
        // north
        if (curr_y < 104 - 1 && prev[curr_x][curr_y + 1] == 0 && (blocks[curr_x + 1][curr_y + 2] &
            0x1280120) == 0) {
          path_x[path_ptr] = curr_x;
          path_y[path_ptr] = curr_y + 1;
          path_ptr = (path_ptr + 1) % pathLength;
          prev[curr_x][curr_y + 1] = 4;
          dist[curr_x][curr_y + 1] = cost;
        }
        // east
        if (curr_x < 104 - 1 && prev[curr_x + 1][curr_y] == 0 && (blocks[curr_x + 2][curr_y + 1] &
            0x1280180) == 0) {
          path_x[path_ptr] = curr_x + 1;
          path_y[path_ptr] = curr_y;
          path_ptr = (path_ptr + 1) % pathLength;
          prev[curr_x + 1][curr_y] = 8;
          dist[curr_x + 1][curr_y] = cost;
        }
        // south west
        if (curr_x > 0 && curr_y > 0 && prev[curr_x - 1][curr_y - 1] == 0 && (blocks[curr_x][curr_y] &
            0x128010e) == 0 && (blocks[curr_x][curr_y + 1] & 0x1280108) == 0 && (blocks[curr_x +
            1][curr_y] & 0x1280102) == 0) {
          path_x[path_ptr] = curr_x - 1;
          path_y[path_ptr] = curr_y - 1;
          path_ptr = (path_ptr + 1) % pathLength;
          prev[curr_x - 1][curr_y - 1] = 3;
          dist[curr_x - 1][curr_y - 1] = cost;
        }
        // north west
        if (curr_x > 0 && curr_y < 104 - 1 && prev[curr_x - 1][curr_y + 1] == 0 && (blocks[curr_x][curr_y + 2] & 0x1280138) == 0 && (blocks[curr_x][curr_y + 1] & 0x1280108) ==
            0 && (blocks[curr_x + 1][curr_y + 2] & 0x1280120) == 0) {
          path_x[path_ptr] = curr_x - 1;
          path_y[path_ptr] = curr_y + 1;
          path_ptr = (path_ptr + 1) % pathLength;
          prev[curr_x - 1][curr_y + 1] = 6;
          dist[curr_x - 1][curr_y + 1] = cost;
        }
        // south east
        if (curr_x < 104 - 1 && curr_y > 0 && prev[curr_x + 1][curr_y - 1] == 0 && (blocks[curr_x +
            2][curr_y] & 0x1280183) == 0 && (blocks[curr_x + 2][curr_y + 1] & 0x1280180) == 0 && (blocks[curr_x + 1][curr_y] & 0x1280102) == 0) {
          path_x[path_ptr] = curr_x + 1;
          path_y[path_ptr] = curr_y - 1;
          path_ptr = (path_ptr + 1) % pathLength;
          prev[curr_x + 1][curr_y - 1] = 9;
          dist[curr_x + 1][curr_y - 1] = cost;
        }
        // north east
        if (curr_x < 104 - 1 && curr_y < 104 - 1 && prev[curr_x + 1][curr_y + 1] == 0 && (blocks[curr_x
            + 2][curr_y + 2] & 0x12801e0) == 0 && (blocks[curr_x + 2][curr_y + 1] & 0x1280180) == 0 && (blocks[curr_x + 1][curr_y + 2] & 0x1280120) == 0) {
          path_x[path_ptr] = curr_x + 1;
          path_y[path_ptr] = curr_y + 1;
          path_ptr = (path_ptr + 1) % pathLength;
          prev[curr_x + 1][curr_y + 1] = 12;
          dist[curr_x + 1][curr_y + 1] = cost;
        }
      }
      return foundPath ? dist[curr_x][curr_y] : -1;
    } catch (Exception e) {
      return -1;
    }
  }
}
TOP

Related Classes of org.rsbot.script.methods.Calculations$Render

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.