package com.ssbot.script.methods;
import com.ssbot.script.wrappers.Locatable;
import com.ssbot.script.wrappers.Tile;
import java.awt.*;
/**
* Game world and projection calculations.
*/
public class Calculations extends MethodProvider {
public static final int[] SIN_TABLE = new int[16384];
public static final int[] COS_TABLE = new int[16384];
public final Render render = new Render();
public final RenderData renderData = new RenderData();
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));
}
//*/
double d = 0.00038349519697141029;
for (int i = 0; i < 16384; i++) {
SIN_TABLE[i] = (int) (32768 * Math.sin(i * d));
COS_TABLE[i] = (int) (32768 * Math.cos(i * d));
}
}
protected 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 Tile t) {
final Tile 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;
}
/**
* 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(Tile, Tile)
*/
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 Tiles.
*
* @param curr The starting tile.
* @param dest The destination tile.
* @return The diagonal distance between the two <code>Tile</code>s.
* @see #distanceBetween(java.awt.Point, java.awt.Point)
*/
public double distanceBetween(final Tile curr, final Tile 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 Tile.
*
* @param l The destination tile.
* @return Distance to <code>Tile</code>.
*/
public int distanceTo(final Locatable l) {
return l == null ? -1 : (int) distanceBetween(methods.players.getMyPlayer().getLocation(), l.getLocation());
}
/**
* 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);
}
/**
* Checks whether or not a given tile is on the minimap.
*
* @param t The Tile to check.
* @return <tt>true</tt> if the Tile is on the minimap; otherwise <tt>false</tt>.
*/
public boolean isTileOnMap(final Tile t) {
return distanceTo(t) < 15;
}
public boolean isPointOnScreen(Point p) {
return p.x > 0 && p.x < methods.bot.getClient().getSize().width && p.y > 0 && p.y < methods.bot.getClient().getSize().height;
}
/**
* Use this
*/
public Point tileToScreen(int x, int y, height) {
return worldToScreen((x - methods.botClient.getBaseX()) * 128, (y - methods.botClient.getBaseY()) * 128, height);
}
public Point worldToScreen(double X, double Y, int height) {
if (X < 128 || Y < 128 || X > 13056 || Y > 13056) {
return new Point(-1, -1);
}
int tileCalculation = tileHeight((int) X, (int) Y) - height;
X -= methods.botClient.getCameraX();
tileCalculation -= methods.camera.getCameraZ();
int curvexsin = CURVESIN[methods.camera.getCameraCurveX()];
int curvexcos = CURVECOS[methods.camera.getCameraCurveX()];
Y -= methods.camera.getCameraY();
int curveysin = CURVESIN[methods.camera.getCameraCurveY()];
int curveycos = CURVECOS[methods.camera.getCameraCurveY()];
int calculation = curvexsin * (int) Y + ((int) X * curvexcos) >> 16;
Y = -(curvexsin * (int) X) + (int) Y * curvexcos >> 16;
X = calculation;
calculation = curveycos * tileCalculation - curveysin * (int) Y >> 16;
Y = curveysin * tileCalculation + ((int) Y * curveycos) >> 16;
tileCalculation = calculation;
if (Y < 50) return new Point(-1, -1);
int ScreenX = ((int) X << 9) / (int) Y + 256;
int ScreenY = (tileCalculation << 9) / (int) Y + 167;
Point p = new Point(ScreenX, ScreenY);
return p;
}
public int tileHeight(int x, int y, int plane) {
int[][][] ground = methods.botClient.getGroundIntArray();
int realX = x >> 7;
int realY = y >> 7;
if(realX >= 0 && realY >= 0 && realX <= 103 && realY <= 103) {
if(plane < 3 && (methods.botClient.getGroundShortArray()[1][realX][realY] & 2) == 2) {
plane++;
}
int var6 = x & 127;
int var7 = y & 127;
int var8 = ground[plane][realX][realY] * (128 - var6) + ground[plane][realX + 1][realY] * var6 >> 7;
int var9 = ground[plane][realX][realY + 1] * (128 - var6) + ground[plane][realX + 1][realY + 1] * var6 >> 7;
return var8 * (128 - var7) + var9 * var7 >> 7;
} else {
return 0;
}
}
public int tileHeight(int x, int y) {
return tileHeight(x, y, methods.botClient.getPlane());
}
/**
* 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) {
return new Point((int) (_x - render.absoluteX1) + 4, (int) (_y - render.absoluteY1) + 4);
}
}
return new Point(-1, -1);
}
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;
}
}