package net.scapeemulator.game.model;
/**
* Represents an (immutable) position in-game. Contains x and y-coordinates as well as a height
* level.
*/
public final class Position {
private final int x, y, height;
/**
* Creates a {@link Position} using (x,y,0) as the coordinates.
*
* @param x The x-coordinate of this position.
* @param y The y-coordinate of this position.
*/
public Position(int x, int y) {
this.x = x;
this.y = y;
this.height = 0;
}
/**
* Creates a {@link Position} using (x,y,height) as the coordinates.
*
* @param x The x-coordinate of this position.
* @param y The y-coordinate of this position.
* @param height The height of this position.
*/
public Position(int x, int y, int height) {
this.x = x;
this.y = y;
this.height = height;
}
/**
* Creates a new Position with the current coordinates that are translated with the given
* values. The height is not changed.
*
* @param deltaX the modification to the current x coordinate to apply to the new Position
* @param deltaY the modification to the current y coordinate to apply to the new Position
* @return a new Position based on the given changes
*/
public Position copy(int deltaX, int deltaY) {
return copy(deltaX, deltaY, 0);
}
/**
* Creates a new Position with the current coordinates that are translated with the given
* values.
*
* @param deltaX the modification to the current x coordinate to apply to the new Position
* @param deltaY the modification to the current y coordinate to apply to the new Position
* @param deltaHeight the modification to the current height to apply to the new Position
* @return a new Position based on the given changes
*/
public Position copy(int deltaX, int deltaY, int deltaHeight) {
return new Position(x + deltaX, y + deltaY, height + deltaHeight);
}
/**
* Gets the x-coordinate of this position.
*
* @return The x-coordinate.
*/
public int getX() {
return x;
}
/**
* Gets the y-coordinate of this position.
*
* @return The y-coordinate.
*/
public int getY() {
return y;
}
public int getBaseLocalX() {
return getBaseLocalX(getRegionX());
}
public int getBaseLocalY() {
return getBaseLocalY(getRegionY());
}
public int getBaseLocalX(int centralRegionX) {
return (centralRegionX - 6) * 8;
}
public int getBaseLocalY(int centralRegionY) {
return (centralRegionY - 6) * 8;
}
public int getLocalX() {
return getLocalX(getRegionX());
}
public int getLocalY() {
return getLocalY(getRegionY());
}
public int getLocalX(int centralRegionX) {
return x - ((centralRegionX - 6) * 8);
}
public int getLocalY(int centralRegionY) {
return y - ((centralRegionY - 6) * 8);
}
/**
* Retrieve the X-coordinate of the central of this Region.
*
* @return The x-coordinate of the central of the region.
*/
public int getRegionX() {
return x / 8;
}
/**
* Retrieve the Y-coordinate of the central of this Region.
*
* @return The y-coordinate of the central of the region.
*/
public int getRegionY() {
return y / 8;
}
/**
* Gets the height of this position.
*
* @return The height.
*/
public int getHeight() {
return height;
}
/**
* Whether position is within distance of this. This implies the difference in {@link getX()}
* should be >= -16 && {@literal <}= to 15. And it implies the same for the difference in
* {@link getY()}.
*
* @param position The position to calculate distance with.
* @return Whether the position is within the distance as described above.
*/
public boolean isWithinDistance(Position position) {
if (position.height != height) {
return false;
}
int deltaX = position.x - x;
int deltaY = position.y - y;
return deltaX >= -16 && deltaX <= 15 && deltaY >= -16 && deltaY <= 15;
}
/**
* Whether position is within scene of this. This implies the difference in {@link getX()}
* should be >= -52 && {@literal <}= to 51. And it implies the same for the difference in
* {@link getY()}.
*
* @param position The position to calculate distance with.
* @return Whether the position is within the distance as described above.
*/
public boolean isWithinScene(Position position) {
int deltaX = position.getX() - x;
int deltaY = position.getY() - y;
return deltaX >= -52 && deltaX <= 51 && deltaY >= -52 && deltaY <= 51;
}
/**
* Gets the distance between this and other. Uses {@link Math#floor(double)} on the formula
* Math.sqrt((x1-x2)^2 + (y1-y2)^2)
*
* @param other The other {@link Position} to check the distance with.
* @return The distance calculated rounded down using {@link Math#floor(double)}
*/
public int getDistance(Position other) {
int deltaX = x - other.x;
int deltaY = y - other.y;
// TODO will rounding up interfere with other stuff?
return (int) Math.floor(Math.sqrt(deltaX * deltaX + deltaY * deltaY));
}
public int toPackedInt() {
return (height << 28) | (x << 14) | y;
}
public int blockHash() {
return (x & 0x7) << 4 | y & 0x7;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + height;
result = prime * result + x;
result = prime * result + y;
return result;
}
/**
* Whether this is equal to the provided Object.
*
* @param obj The object to check for equality.
* @return False if obj is null, when {@link getClass()} doesn't match or when the {@link
* getHeight()}, the {@link getX()} or the {@link getY()} don't match. else true.
*/
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
Position other = (Position) obj;
if (height != other.height) {
return false;
}
if (x != other.x) {
return false;
}
if (y != other.y) {
return false;
}
return true;
}
/**
* Gets this representation in String form.
*
* @return using the format "position[x: {@link getX()}, y: {@link getY()}, height: {@link
* getHeight()}]" of this {@link Position}.
*/
@Override
public String toString() {
return "position[x: " + x + ", y: " + y + ", height: " + height + "] region[" + getRegionX() + ", " + getRegionY() + "]";
}
}