/*
Copyright 2012 Jan Ove Saltvedt
This file is part of KBot.
KBot is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
KBot is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with KBot. If not, see <http://www.gnu.org/licenses/>.
*/
package com.kbotpro.scriptsystem;
import com.kbotpro.bot.BotEnvironment;
import com.kbotpro.bot.RenderData;
import com.kbotpro.hooks.Client;
import com.kbotpro.hooks.Plane;
import com.kbotpro.scriptsystem.wrappers.IComponent;
import com.kbotpro.scriptsystem.wrappers.Tile;
import java.awt.*;
/**
* Created by IntelliJ IDEA.
* User: Jan Ove Saltvedt
* Date: Sep 19, 2009
* Time: 11:13:44 AM
* To change this template use File | Settings | File Templates.
*/
public class Calculations {
public static int[] CURVE_COS;
public static int[] CURVE_SIN;
private BotEnvironment bot;
public Calculations(BotEnvironment bot) {
this.bot = bot;
}
/**
* Gets random number between min and max (exclusive)
*
* @param min
* @param max
* @return
*/
public static int random(int min, int max) {
return ((int) (Math.random() * (max - min))) + min;
}
/**
* Converts a 3D point to a 2D point on screen
*
* @param x The relative to plane x coord
* @param z This is actually the y coord. The difference is in the conversion from 3D to 2D plane axises. This is the relative to plane y coord
* @param height the height above ground.
* @return
*/
public Point worldToScreen(int x, int z, final int height) {
return worldToScreen(x, z, height, false);
}
/**
* Converts a 3D point to a 2D point on screen
*
* @param x The relative to plane x coord
* @param z This is actually the y coord. The difference is in the conversion from 3D to 2D plane axises. This is the relative to plane y coord
* @param height the height above ground.
* @return
*/
public Point worldToScreen(int x, int z, final int height, boolean includedGroundHeight) {
Client client = bot.client;
RenderData renderData = bot.renderData;
if (renderData == null
// || renderVars == null
|| x < 512
|| z < 512
|| x > 52224
|| z > 52224) {
return new Point(-1, -1);
}
final int y = includedGroundHeight?-height:(getTileHeight(client.getCurrentPlane(), x, z) - height);
Point p = null;
int detail = 0;
if (detail == 0) { // Low detail
final int distanceToPoint = renderData.zOff + (renderData.x3 * x
+ renderData.y3 * y + renderData.z3 * z >> 14);
// Here there should be done clipping if it was rendering but not needed for worldToScreen
if (distanceToPoint == 0) { // We don't devide by zero!
return new Point(-1, -1);
}
final int calcX = (renderData.screenFactorX
* (renderData.xOff + (((renderData.x1 * x)
+ (renderData.y1 * y) + (renderData.z1 * z)) >> 14))) / distanceToPoint;
final int calcY = (renderData.screenFactorY
* (renderData.yOff + (renderData.x2 * x
+ renderData.y2 * y + renderData.z2 * z >> 14))) / distanceToPoint;
int minX = renderData.minX;
int minY = renderData.minY;
if (calcX >= minX && calcX <= renderData.maxX
&& calcY >= minY && calcY <= renderData.maxY) {
int screenx = calcX - minX;
int screeny = calcY - minY;
if (bot.game.isFixedMode()) {
// Fixed mode
return new Point(screenx + 4, screeny + 4);
}
return new Point(screenx,
screeny);
}
} else if (detail == 1) { // High detail
p = new Point(-1, -1); // High detail is not yet supported
}
if (p != null)
return p;
return new Point(-1, -1);
}
public int getTileHeight(int plane, int X, int Y) {
final Client client = bot.client;
Plane[] planes = client.getPlaneArray();
if (planes == null)
return 0;
int x1 = X >> 9;
int y1 = Y >> 9;
if (x1 < 0 || y1 < 0 || x1 > 103 || y1 > 103)
return 0;
int x2 = X & 0x1ff;
int y2 = Y & 0x1ff;
int zIndex = plane;
if (zIndex <= 3 && (client.getGroundSettingsArray()[1][x1][y1] & 2) == 2)
zIndex++;
while(planes[zIndex] == null){
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
}
planes = client.getPlaneArray();
}
final int[][] groundHeights = planes[zIndex].getTileHeights();
if (groundHeights == null) {
return 0;
}
int height1 = ((groundHeights[x1][y1] * (512 - x2)) + (groundHeights[x1 + 1][y1] * x2)) >> 9;
int height2 = ((groundHeights[x1][(y1 + 1)] * (512 - x2)) + (groundHeights[1 + x1][(y1 + 1)] * x2)) >> 9;
return ((height1 * (512 - y2)) + (y2 * height2)) >> 9;
}
public Point worldToMinimap(double x, double y) {
x -= bot.client.getBaseX();
y -= bot.client.getBaseY();
final int calculatedX = (int) (x * 4 + 2)
- bot.client.getMyPlayer().getPosX() / 128;
final int calculatedY = (int) (y * 4 + 2)
- bot.client.getMyPlayer().getPosY() / 128;
try {
final com.kbotpro.hooks.IComponent mm = bot.interfaces.getCoreMinimapIComponent();
if (mm == null) {
return new Point(-1, -1);
}
final IComponent mm2 = bot.interfaces.getComponentByUID(mm.getUID());
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) bot.client.getCompassAngle();
if (bot.client.getMinimapSetting() != 4) {
angle = 0x3fff & bot.client.getMinimapOffset()
+ (int) bot.client.getCompassAngle();
}
int cs = Calculations.CURVE_SIN[angle];
int cc = Calculations.CURVE_COS[angle];
if (bot.client.getMinimapSetting() != 4) {
final int fact = 256 + bot.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;
Rectangle bounds = mm2.getBounds();
// Check if its really inside the minimap
if (bounds.contains(screenx, screeny)) {
// Check if point is within the circel of the minimap instead of
// the
// rectangle!
if ((Math.max(calcCenterY, -calcCenterY) <= (((mm2.getWidth()) / 2.0) * .8))
&& (Math.max(calcCenterX, -calcCenterX) <= (((mm2
.getHeight()) / 2) * .8))) {
return new Point(screenx, screeny);
} else {
return new Point(-1, -1);
}
}
else{
return new Point(-1, -1);
}
}
} catch (final NullPointerException ignore) {
}
return new Point(-1, -1);// not on minimap
}
public Point tileToScreen(int tileX, int tileY, double dX, double dY, int height) {
return worldToScreen((int) ((tileX - bot.client.getBaseX() + dX) * 512), (int) ((tileY
- bot.client.getBaseY() + dY) * 512), height);
}
public Point tileToScreen(Tile t) {
return tileToScreen(t.getX(), t.getY(), 0.5, 0.5, 0);
}
public Point tileToMinimap(Tile tile) {
return worldToMinimap(tile.getX(), tile.getY());
}
static {
CURVE_COS = new int[16384];
CURVE_SIN = new int[16384];
double d = 0.00038349519697141029D;
for (int i = 0; i < 16384; i++) {
CURVE_COS[i] = (int) (32768D * Math.cos((double) i * d));
CURVE_SIN[i] = (int) (32768D * Math.sin((double) i * d));
}
}
public static double random(double min, double max) {
return Math.random() * (max - min) + min;
}
public boolean onScreen(Point point) {
return point.x > 0 && point.y > 0 && point.y < bot.appletHeight && point.x < bot.appletWidth;
}
/**
* Determines if a point is inside the playing area of the game, ie: not on the minimap, tabs, chatbox, etc.
* @param p Point on screen
* @return Returns true if the point is inside the game area.
*/
public boolean isInGameArea(Point p) {
return getGameScreenShape().contains(p);
}
/**
* Forms a Shape around the interfaces in the game, return the area in game where you can perform actions on the ground.
* @return
*/
public Shape getGameScreenShape() {
IComponent fixed = bot.interfaces.getComponent(548, 3);
if (bot.game.isFixedMode() && fixed != null && fixed.isVisible() && bot.game.isLoggedIn()) {
return fixed.getBounds();
}
Polygon clickable = new Polygon();
clickable.addPoint(0,0);
IComponent m = bot.interfaces.getComponent(746,9);
IComponent t = bot.interfaces.getComponent(746,19);
IComponent c = bot.interfaces.getComponent(751,0);
IComponent cb = bot.interfaces.getComponent(137,50);
IComponent tab = bot.interfaces.getComponent(746, 82);
if (!bot.game.isLoggedIn() || m == null || t == null || c == null || cb == null || tab == null ) {
return new Rectangle(0, 0, bot.appletWidth, bot.appletHeight);
}
//Minimap
clickable.addPoint(m.getAbsoluteX(),0);
clickable.addPoint(m.getAbsoluteX(),m.getAbsoluteY()+m.getHeight());
clickable.addPoint(m.getAbsoluteX()+m.getWidth(),m.getAbsoluteY()+m.getHeight());
//Minimap
//Tab bar
clickable.addPoint(t.getAbsoluteX()+t.getWidth(),t.getAbsoluteY());
if (bot.game.getCurrentTab() != 16) {
int y = tab.getAbsoluteY();
if (y <= m.getHeight()) {
y = y+(m.getHeight() - y);
}
clickable.addPoint(tab.getAbsoluteX()+tab.getWidth(), y+tab.getHeight());
clickable.addPoint(tab.getAbsoluteX()+tab.getWidth(), y);
clickable.addPoint(tab.getAbsoluteX(), y);
clickable.addPoint(tab.getAbsoluteX(), y+tab.getHeight());
}
clickable.addPoint(t.getAbsoluteX(),t.getAbsoluteY());
clickable.addPoint(t.getAbsoluteX(),t.getAbsoluteY()+t.getHeight());
//Tab bar
//chat bar
clickable.addPoint(c.getAbsoluteX()+c.getWidth(),c.getAbsoluteY()+c.getHeight());
clickable.addPoint(c.getAbsoluteX()+c.getWidth(),c.getAbsoluteY());
//chat bar
//chatbox
boolean chatup = false;
IComponent[] chat = bot.interfaces.getInterface(751).getComponents();
for (IComponent aChat : chat) {
if (aChat.getTextureID() == 1022) {
chatup = true;
}
}
if (chatup) {
clickable.addPoint(cb.getAbsoluteX()+cb.getWidth(),cb.getAbsoluteY()+cb.getWidth());
clickable.addPoint(cb.getAbsoluteX()+cb.getWidth(),cb.getAbsoluteY());
clickable.addPoint(0,cb.getAbsoluteY());
} else {
clickable.addPoint(0,c.getAbsoluteY());
}
//chatbox
return clickable;
}
/**
* Determines if a tile is reachable.
* @param dest Destination tile
* @param isObject True if the tile has an object on it.
* @return True if you're able to reach the tile.
*/
public boolean canReach(Tile dest, boolean isObject) {
final int startX = bot.players.getMyPlayer().getLocation().getX() - bot.client.getBaseX() + 1;
final int startY = bot.players.getMyPlayer().getLocation().getY() - bot.client.getBaseY() + 1;
final int destX = dest.getX() - bot.client.getBaseX() + 1;
final int destY = dest.getY() - bot.client.getBaseY() + 1;
final int[][] via = new int[104][104];
final int[][] cost = new int[104][104];
final int[] tileQueueX = new int[4000];
final int[] tileQueueY = new int[4000];
for (int xx = 0; xx < 104; xx++) {
for (int yy = 0; yy < 104; yy++) {
via[xx][yy] = 0;
cost[xx][yy] = 99999999;
}
}
int curX;
int curY;
via[startX][startY] = 99;
cost[startX][startY] = 0;
int head = 0;
int tail = 0;
tileQueueX[head] = startX;
tileQueueY[head] = startY;
head++;
final int pathLength = tileQueueX.length;
final int blocks[][] = bot.client.getMapDataArray()[bot.client.getCurrentPlane()].getTileData();
while (tail != head) {
curX = tileQueueX[tail];
curY = tileQueueY[tail];
if (!isObject && (curX == destX) && (curY == destY))
return true;
else if (isObject) {
if (((curX == destX) && (curY == destY + 1)) || ((curX == destX) && (curY == destY - 1)) || ((curX == destX + 1) && (curY == destY)) || ((curX == destX - 1) && (curY == destY)))
return true;
}
tail = (tail + 1) % pathLength;
// Big and ugly block of code
final int thisCost = cost[curX][curY] + 1;
// Can go south (by determining, whether the north side of the
// south tile is blocked :P)
if ((curY > 0) && (via[curX][curY - 1] == 0) && ((blocks[curX][curY - 1] & 0x1280102) == 0)) {
tileQueueX[head] = curX;
tileQueueY[head] = curY - 1;
head = (head + 1) % pathLength;
via[curX][curY - 1] = 1;
cost[curX][curY - 1] = thisCost;
}
// Can go west
if ((curX > 0) && (via[curX - 1][curY] == 0) && ((blocks[curX - 1][curY] & 0x1280108) == 0)) {
tileQueueX[head] = curX - 1;
tileQueueY[head] = curY;
head = (head + 1) % pathLength;
via[curX - 1][curY] = 2;
cost[curX - 1][curY] = thisCost;
}
// Can go north
if ((curY < 104 - 1) && (via[curX][curY + 1] == 0) && ((blocks[curX][curY + 1] & 0x1280120) == 0)) {
tileQueueX[head] = curX;
tileQueueY[head] = curY + 1;
head = (head + 1) % pathLength;
via[curX][curY + 1] = 4;
cost[curX][curY + 1] = thisCost;
}
// Can go east
if ((curX < 104 - 1) && (via[curX + 1][curY] == 0) && ((blocks[curX + 1][curY] & 0x1280180) == 0)) {
tileQueueX[head] = curX + 1;
tileQueueY[head] = curY;
head = (head + 1) % pathLength;
via[curX + 1][curY] = 8;
cost[curX + 1][curY] = thisCost;
}
// Can go southwest
if ((curX > 0) && (curY > 0) && (via[curX - 1][curY - 1] == 0) && ((blocks[curX - 1][curY - 1] & 0x128010e) == 0) && ((blocks[curX - 1][curY] & 0x1280108) == 0) && ((blocks[curX][curY - 1] & 0x1280102) == 0)) {
tileQueueX[head] = curX - 1;
tileQueueY[head] = curY - 1;
head = (head + 1) % pathLength;
via[curX - 1][curY - 1] = 3;
cost[curX - 1][curY - 1] = thisCost;
}
// Can go northwest
if ((curX > 0) && (curY < 104 - 1) && (via[curX - 1][curY + 1] == 0) && ((blocks[curX - 1][curY + 1] & 0x1280138) == 0) && ((blocks[curX - 1][curY] & 0x1280108) == 0) && ((blocks[curX][curY + 1] & 0x1280120) == 0)) {
tileQueueX[head] = curX - 1;
tileQueueY[head] = curY + 1;
head = (head + 1) % pathLength;
via[curX - 1][curY + 1] = 6;
cost[curX - 1][curY + 1] = thisCost;
}
// Can go southeast
if ((curX < 104 - 1) && (curY > 0) && (via[curX + 1][curY - 1] == 0) && ((blocks[curX + 1][curY - 1] & 0x1280183) == 0) && ((blocks[curX + 1][curY] & 0x1280180) == 0) && ((blocks[curX][curY - 1] & 0x1280102) == 0)) {
tileQueueX[head] = curX + 1;
tileQueueY[head] = curY - 1;
head = (head + 1) % pathLength;
via[curX + 1][curY - 1] = 9;
cost[curX + 1][curY - 1] = thisCost;
}
// can go northeast
if ((curX < 104 - 1) && (curY < 104 - 1) && (via[curX + 1][curY + 1] == 0) && ((blocks[curX + 1][curY + 1] & 0x12801e0) == 0) && ((blocks[curX + 1][curY] & 0x1280180) == 0) && ((blocks[curX][curY + 1] & 0x1280120) == 0)) {
tileQueueX[head] = curX + 1;
tileQueueY[head] = curY + 1;
head = (head + 1) % pathLength;
via[curX + 1][curY + 1] = 12;
cost[curX + 1][curY + 1] = thisCost;
}
}
return false;
}
public static boolean inArea(Tile target, Tile[] bounds) {
Polygon poly = new Polygon();
Point curr;
for (Tile t : bounds) {
curr = t.toPoint();
poly.addPoint(curr.x, curr.y);
}
return poly.contains(target.toPoint());
}
}