628 lines
19 KiB
Java
628 lines
19 KiB
Java
/*
|
|
* This file is part of the L2J Mobius project.
|
|
*
|
|
* This program 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.
|
|
*
|
|
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
package com.l2jmobius.gameserver;
|
|
|
|
import java.nio.file.Files;
|
|
import java.nio.file.Path;
|
|
import java.util.logging.Level;
|
|
import java.util.logging.Logger;
|
|
|
|
import com.l2jmobius.Config;
|
|
import com.l2jmobius.commons.geodriver.Cell;
|
|
import com.l2jmobius.commons.geodriver.GeoDriver;
|
|
import com.l2jmobius.gameserver.data.xml.impl.DoorData;
|
|
import com.l2jmobius.gameserver.instancemanager.WarpedSpaceManager;
|
|
import com.l2jmobius.gameserver.model.L2Object;
|
|
import com.l2jmobius.gameserver.model.L2World;
|
|
import com.l2jmobius.gameserver.model.Location;
|
|
import com.l2jmobius.gameserver.model.instancezone.Instance;
|
|
import com.l2jmobius.gameserver.model.interfaces.ILocational;
|
|
import com.l2jmobius.gameserver.util.GeoUtils;
|
|
import com.l2jmobius.gameserver.util.LinePointIterator;
|
|
import com.l2jmobius.gameserver.util.LinePointIterator3D;
|
|
|
|
/**
|
|
* @author -Nemesiss-, HorridoJoho
|
|
*/
|
|
public class GeoData
|
|
{
|
|
private static final Logger LOGGER = Logger.getLogger(GeoData.class.getName());
|
|
private static final String FILE_NAME_FORMAT = "%d_%d.l2j";
|
|
private static final int ELEVATED_SEE_OVER_DISTANCE = 2;
|
|
private static final int MAX_SEE_OVER_HEIGHT = 48;
|
|
private static final int SPAWN_Z_DELTA_LIMIT = 100;
|
|
|
|
private final GeoDriver _driver = new GeoDriver();
|
|
|
|
protected GeoData()
|
|
{
|
|
int loadedRegions = 0;
|
|
try
|
|
{
|
|
for (int regionX = L2World.TILE_X_MIN; regionX <= L2World.TILE_X_MAX; regionX++)
|
|
{
|
|
for (int regionY = L2World.TILE_Y_MIN; regionY <= L2World.TILE_Y_MAX; regionY++)
|
|
{
|
|
final Path geoFilePath = Config.GEODATA_PATH.resolve(String.format(FILE_NAME_FORMAT, regionX, regionY));
|
|
final Boolean loadFile = Config.GEODATA_REGIONS.get(regionX + "_" + regionY);
|
|
if (loadFile != null)
|
|
{
|
|
if (loadFile)
|
|
{
|
|
LOGGER.info(getClass().getSimpleName() + ": Loading " + geoFilePath.getFileName() + "...");
|
|
_driver.loadRegion(geoFilePath, regionX, regionY);
|
|
loadedRegions++;
|
|
}
|
|
}
|
|
else if (Config.TRY_LOAD_UNSPECIFIED_REGIONS && Files.exists(geoFilePath))
|
|
{
|
|
try
|
|
{
|
|
LOGGER.info(getClass().getSimpleName() + ": Loading " + geoFilePath.getFileName() + "...");
|
|
_driver.loadRegion(geoFilePath, regionX, regionY);
|
|
loadedRegions++;
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
LOGGER.log(Level.WARNING, getClass().getSimpleName() + ": Failed to load " + geoFilePath.getFileName() + "!", e);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
LOGGER.log(Level.SEVERE, getClass().getSimpleName() + ": Failed to load geodata!", e);
|
|
System.exit(1);
|
|
}
|
|
|
|
LOGGER.info(getClass().getSimpleName() + ": Loaded " + loadedRegions + " regions.");
|
|
}
|
|
|
|
public boolean hasGeoPos(int geoX, int geoY)
|
|
{
|
|
return _driver.hasGeoPos(geoX, geoY);
|
|
}
|
|
|
|
public boolean checkNearestNswe(int geoX, int geoY, int worldZ, int nswe)
|
|
{
|
|
return _driver.checkNearestNswe(geoX, geoY, worldZ, nswe);
|
|
}
|
|
|
|
public boolean checkNearestNsweAntiCornerCut(int geoX, int geoY, int worldZ, int nswe)
|
|
{
|
|
boolean can = true;
|
|
if ((nswe & Cell.NSWE_NORTH_EAST) == Cell.NSWE_NORTH_EAST)
|
|
{
|
|
// can = canEnterNeighbors(prevX, prevY - 1, prevGeoZ, Direction.EAST) && canEnterNeighbors(prevX + 1, prevY, prevGeoZ, Direction.NORTH);
|
|
can = checkNearestNswe(geoX, geoY - 1, worldZ, Cell.NSWE_EAST) && checkNearestNswe(geoX + 1, geoY, worldZ, Cell.NSWE_NORTH);
|
|
}
|
|
|
|
if (can && ((nswe & Cell.NSWE_NORTH_WEST) == Cell.NSWE_NORTH_WEST))
|
|
{
|
|
// can = canEnterNeighbors(prevX, prevY - 1, prevGeoZ, Direction.WEST) && canEnterNeighbors(prevX - 1, prevY, prevGeoZ, Direction.NORTH);
|
|
can = checkNearestNswe(geoX, geoY - 1, worldZ, Cell.NSWE_WEST) && checkNearestNswe(geoX, geoY - 1, worldZ, Cell.NSWE_NORTH);
|
|
}
|
|
|
|
if (can && ((nswe & Cell.NSWE_SOUTH_EAST) == Cell.NSWE_SOUTH_EAST))
|
|
{
|
|
// can = canEnterNeighbors(prevX, prevY + 1, prevGeoZ, Direction.EAST) && canEnterNeighbors(prevX + 1, prevY, prevGeoZ, Direction.SOUTH);
|
|
can = checkNearestNswe(geoX, geoY + 1, worldZ, Cell.NSWE_EAST) && checkNearestNswe(geoX + 1, geoY, worldZ, Cell.NSWE_SOUTH);
|
|
}
|
|
|
|
if (can && ((nswe & Cell.NSWE_SOUTH_WEST) == Cell.NSWE_SOUTH_WEST))
|
|
{
|
|
// can = canEnterNeighbors(prevX, prevY + 1, prevGeoZ, Direction.WEST) && canEnterNeighbors(prevX - 1, prevY, prevGeoZ, Direction.SOUTH);
|
|
can = checkNearestNswe(geoX, geoY + 1, worldZ, Cell.NSWE_WEST) && checkNearestNswe(geoX - 1, geoY, worldZ, Cell.NSWE_SOUTH);
|
|
}
|
|
|
|
return can && checkNearestNswe(geoX, geoY, worldZ, nswe);
|
|
}
|
|
|
|
public int getNearestZ(int geoX, int geoY, int worldZ)
|
|
{
|
|
return _driver.getNearestZ(geoX, geoY, worldZ);
|
|
}
|
|
|
|
public int getNextLowerZ(int geoX, int geoY, int worldZ)
|
|
{
|
|
return _driver.getNextLowerZ(geoX, geoY, worldZ);
|
|
}
|
|
|
|
public int getNextHigherZ(int geoX, int geoY, int worldZ)
|
|
{
|
|
return _driver.getNextHigherZ(geoX, geoY, worldZ);
|
|
}
|
|
|
|
public int getGeoX(int worldX)
|
|
{
|
|
return _driver.getGeoX(worldX);
|
|
}
|
|
|
|
public int getGeoY(int worldY)
|
|
{
|
|
return _driver.getGeoY(worldY);
|
|
}
|
|
|
|
public int getGeoZ(int worldZ)
|
|
{
|
|
return _driver.getGeoZ(worldZ);
|
|
}
|
|
|
|
public int getWorldX(int geoX)
|
|
{
|
|
return _driver.getWorldX(geoX);
|
|
}
|
|
|
|
public int getWorldY(int geoY)
|
|
{
|
|
return _driver.getWorldY(geoY);
|
|
}
|
|
|
|
public int getWorldZ(int geoZ)
|
|
{
|
|
return _driver.getWorldZ(geoZ);
|
|
}
|
|
|
|
// ///////////////////
|
|
// L2J METHODS
|
|
/**
|
|
* Gets the height.
|
|
* @param x the x coordinate
|
|
* @param y the y coordinate
|
|
* @param z the z coordinate
|
|
* @return the height
|
|
*/
|
|
public int getHeight(int x, int y, int z)
|
|
{
|
|
return getNearestZ(getGeoX(x), getGeoY(y), z);
|
|
}
|
|
|
|
/**
|
|
* Gets the spawn height.
|
|
* @param x the x coordinate
|
|
* @param y the y coordinate
|
|
* @param z the the z coordinate
|
|
* @return the spawn height
|
|
*/
|
|
public int getSpawnHeight(int x, int y, int z)
|
|
{
|
|
final int geoX = getGeoX(x);
|
|
final int geoY = getGeoY(y);
|
|
|
|
if (!hasGeoPos(geoX, geoY))
|
|
{
|
|
return z;
|
|
}
|
|
|
|
final int nextLowerZ = getNextLowerZ(geoX, geoY, z + 100);
|
|
return Math.abs(nextLowerZ - z) <= SPAWN_Z_DELTA_LIMIT ? nextLowerZ : z;
|
|
}
|
|
|
|
/**
|
|
* Gets the spawn height.
|
|
* @param location the location
|
|
* @return the spawn height
|
|
*/
|
|
public int getSpawnHeight(Location location)
|
|
{
|
|
return getSpawnHeight(location.getX(), location.getY(), location.getZ());
|
|
}
|
|
|
|
/**
|
|
* Can see target. Doors as target always return true. Checks doors between.
|
|
* @param cha the character
|
|
* @param target the target
|
|
* @return {@code true} if the character can see the target (LOS), {@code false} otherwise
|
|
*/
|
|
public boolean canSeeTarget(L2Object cha, L2Object target)
|
|
{
|
|
if (target.isDoor())
|
|
{
|
|
// can always see doors :o
|
|
return true;
|
|
}
|
|
|
|
return canSeeTarget(cha.getX(), cha.getY(), cha.getZ(), cha.getInstanceWorld(), target.getX(), target.getY(), target.getZ(), target.getInstanceWorld());
|
|
}
|
|
|
|
/**
|
|
* Can see target. Checks doors between.
|
|
* @param cha the character
|
|
* @param worldPosition the world position
|
|
* @return {@code true} if the character can see the target at the given world position, {@code false} otherwise
|
|
*/
|
|
public boolean canSeeTarget(L2Object cha, ILocational worldPosition)
|
|
{
|
|
return canSeeTarget(cha.getX(), cha.getY(), cha.getZ(), cha.getInstanceWorld(), worldPosition.getX(), worldPosition.getY(), worldPosition.getZ());
|
|
}
|
|
|
|
/**
|
|
* Can see target. Checks doors between.
|
|
* @param x the x coordinate
|
|
* @param y the y coordinate
|
|
* @param z the z coordinate
|
|
* @param world
|
|
* @param tx the target's x coordinate
|
|
* @param ty the target's y coordinate
|
|
* @param tz the target's z coordinate
|
|
* @param tworld the target's instanceId
|
|
* @return
|
|
*/
|
|
public boolean canSeeTarget(int x, int y, int z, Instance world, int tx, int ty, int tz, Instance tworld)
|
|
{
|
|
return (world != tworld) ? false : canSeeTarget(x, y, z, world, tx, ty, tz);
|
|
}
|
|
|
|
/**
|
|
* Can see target. Checks doors between.
|
|
* @param x the x coordinate
|
|
* @param y the y coordinate
|
|
* @param z the z coordinate
|
|
* @param instance
|
|
* @param tx the target's x coordinate
|
|
* @param ty the target's y coordinate
|
|
* @param tz the target's z coordinate
|
|
* @return {@code true} if there is line of sight between the given coordinate sets, {@code false} otherwise
|
|
*/
|
|
public boolean canSeeTarget(int x, int y, int z, Instance instance, int tx, int ty, int tz)
|
|
{
|
|
if (DoorData.getInstance().checkIfDoorsBetween(x, y, z, tx, ty, tz, instance, true))
|
|
{
|
|
return false;
|
|
}
|
|
return canSeeTarget(x, y, z, tx, ty, tz);
|
|
}
|
|
|
|
private int getLosGeoZ(int prevX, int prevY, int prevGeoZ, int curX, int curY, int nswe)
|
|
{
|
|
if ((((nswe & Cell.NSWE_NORTH) != 0) && ((nswe & Cell.NSWE_SOUTH) != 0)) || (((nswe & Cell.NSWE_WEST) != 0) && ((nswe & Cell.NSWE_EAST) != 0)))
|
|
{
|
|
throw new RuntimeException("Multiple directions!");
|
|
}
|
|
|
|
if (checkNearestNsweAntiCornerCut(prevX, prevY, prevGeoZ, nswe))
|
|
{
|
|
return getNearestZ(curX, curY, prevGeoZ);
|
|
}
|
|
return getNextHigherZ(curX, curY, prevGeoZ);
|
|
}
|
|
|
|
/**
|
|
* Can see target. Does not check doors between.
|
|
* @param x the x coordinate
|
|
* @param y the y coordinate
|
|
* @param z the z coordinate
|
|
* @param tx the target's x coordinate
|
|
* @param ty the target's y coordinate
|
|
* @param tz the target's z coordinate
|
|
* @return {@code true} if there is line of sight between the given coordinate sets, {@code false} otherwise
|
|
*/
|
|
public boolean canSeeTarget(int x, int y, int z, int tx, int ty, int tz)
|
|
{
|
|
int geoX = getGeoX(x);
|
|
int geoY = getGeoY(y);
|
|
int tGeoX = getGeoX(tx);
|
|
int tGeoY = getGeoY(ty);
|
|
|
|
z = getNearestZ(geoX, geoY, z);
|
|
tz = getNearestZ(tGeoX, tGeoY, tz);
|
|
|
|
// fastpath
|
|
if ((geoX == tGeoX) && (geoY == tGeoY))
|
|
{
|
|
if (hasGeoPos(tGeoX, tGeoY))
|
|
{
|
|
return z == tz;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
if (tz > z)
|
|
{
|
|
int tmp = tx;
|
|
tx = x;
|
|
x = tmp;
|
|
|
|
tmp = ty;
|
|
ty = y;
|
|
y = tmp;
|
|
|
|
tmp = tz;
|
|
tz = z;
|
|
z = tmp;
|
|
|
|
tmp = tGeoX;
|
|
tGeoX = geoX;
|
|
geoX = tmp;
|
|
|
|
tmp = tGeoY;
|
|
tGeoY = geoY;
|
|
geoY = tmp;
|
|
}
|
|
|
|
final LinePointIterator3D pointIter = new LinePointIterator3D(geoX, geoY, z, tGeoX, tGeoY, tz);
|
|
// first point is guaranteed to be available, skip it, we can always see our own position
|
|
pointIter.next();
|
|
int prevX = pointIter.x();
|
|
int prevY = pointIter.y();
|
|
final int prevZ = pointIter.z();
|
|
int prevGeoZ = prevZ;
|
|
int ptIndex = 0;
|
|
while (pointIter.next())
|
|
{
|
|
final int curX = pointIter.x();
|
|
final int curY = pointIter.y();
|
|
|
|
if ((curX == prevX) && (curY == prevY))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
final int beeCurZ = pointIter.z();
|
|
int curGeoZ = prevGeoZ;
|
|
|
|
// check if the position has geodata
|
|
if (hasGeoPos(curX, curY))
|
|
{
|
|
final int beeCurGeoZ = getNearestZ(curX, curY, beeCurZ);
|
|
final int nswe = GeoUtils.computeNswe(prevX, prevY, curX, curY); // .computeDirection(prevX, prevY, curX, curY);
|
|
curGeoZ = getLosGeoZ(prevX, prevY, prevGeoZ, curX, curY, nswe);
|
|
int maxHeight;
|
|
if (ptIndex < ELEVATED_SEE_OVER_DISTANCE)
|
|
{
|
|
maxHeight = z + MAX_SEE_OVER_HEIGHT;
|
|
}
|
|
else
|
|
{
|
|
maxHeight = beeCurZ + MAX_SEE_OVER_HEIGHT;
|
|
}
|
|
|
|
boolean canSeeThrough = false;
|
|
if ((curGeoZ <= maxHeight) && (curGeoZ <= beeCurGeoZ))
|
|
{
|
|
if ((nswe & Cell.NSWE_NORTH_EAST) == Cell.NSWE_NORTH_EAST)
|
|
{
|
|
final int northGeoZ = getLosGeoZ(prevX, prevY, prevGeoZ, prevX, prevY - 1, Cell.NSWE_EAST);
|
|
final int eastGeoZ = getLosGeoZ(prevX, prevY, prevGeoZ, prevX + 1, prevY, Cell.NSWE_NORTH);
|
|
canSeeThrough = (northGeoZ <= maxHeight) && (eastGeoZ <= maxHeight) && (northGeoZ <= getNearestZ(prevX, prevY - 1, beeCurZ)) && (eastGeoZ <= getNearestZ(prevX + 1, prevY, beeCurZ));
|
|
}
|
|
else if ((nswe & Cell.NSWE_NORTH_WEST) == Cell.NSWE_NORTH_WEST)
|
|
{
|
|
final int northGeoZ = getLosGeoZ(prevX, prevY, prevGeoZ, prevX, prevY - 1, Cell.NSWE_WEST);
|
|
final int westGeoZ = getLosGeoZ(prevX, prevY, prevGeoZ, prevX - 1, prevY, Cell.NSWE_NORTH);
|
|
canSeeThrough = (northGeoZ <= maxHeight) && (westGeoZ <= maxHeight) && (northGeoZ <= getNearestZ(prevX, prevY - 1, beeCurZ)) && (westGeoZ <= getNearestZ(prevX - 1, prevY, beeCurZ));
|
|
}
|
|
else if ((nswe & Cell.NSWE_SOUTH_EAST) == Cell.NSWE_SOUTH_EAST)
|
|
{
|
|
final int southGeoZ = getLosGeoZ(prevX, prevY, prevGeoZ, prevX, prevY + 1, Cell.NSWE_EAST);
|
|
final int eastGeoZ = getLosGeoZ(prevX, prevY, prevGeoZ, prevX + 1, prevY, Cell.NSWE_SOUTH);
|
|
canSeeThrough = (southGeoZ <= maxHeight) && (eastGeoZ <= maxHeight) && (southGeoZ <= getNearestZ(prevX, prevY + 1, beeCurZ)) && (eastGeoZ <= getNearestZ(prevX + 1, prevY, beeCurZ));
|
|
}
|
|
else if ((nswe & Cell.NSWE_SOUTH_WEST) == Cell.NSWE_SOUTH_WEST)
|
|
{
|
|
final int southGeoZ = getLosGeoZ(prevX, prevY, prevGeoZ, prevX, prevY + 1, Cell.NSWE_WEST);
|
|
final int westGeoZ = getLosGeoZ(prevX, prevY, prevGeoZ, prevX - 1, prevY, Cell.NSWE_SOUTH);
|
|
canSeeThrough = (southGeoZ <= maxHeight) && (westGeoZ <= maxHeight) && (southGeoZ <= getNearestZ(prevX, prevY + 1, beeCurZ)) && (westGeoZ <= getNearestZ(prevX - 1, prevY, beeCurZ));
|
|
}
|
|
else
|
|
{
|
|
canSeeThrough = true;
|
|
}
|
|
}
|
|
|
|
if (!canSeeThrough)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
prevX = curX;
|
|
prevY = curY;
|
|
prevGeoZ = curGeoZ;
|
|
++ptIndex;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Move check.
|
|
* @param x the x coordinate
|
|
* @param y the y coordinate
|
|
* @param z the z coordinate
|
|
* @param tx the target's x coordinate
|
|
* @param ty the target's y coordinate
|
|
* @param tz the target's z coordinate
|
|
* @param instance the instance
|
|
* @return the last Location (x,y,z) where player can walk - just before wall
|
|
*/
|
|
public Location moveCheck(int x, int y, int z, int tx, int ty, int tz, Instance instance)
|
|
{
|
|
final int geoX = getGeoX(x);
|
|
final int geoY = getGeoY(y);
|
|
z = getNearestZ(geoX, geoY, z);
|
|
final int tGeoX = getGeoX(tx);
|
|
final int tGeoY = getGeoY(ty);
|
|
tz = getNearestZ(tGeoX, tGeoY, tz);
|
|
|
|
if (DoorData.getInstance().checkIfDoorsBetween(x, y, z, tx, ty, tz, instance, false))
|
|
{
|
|
return new Location(x, y, getHeight(x, y, z));
|
|
}
|
|
|
|
if (WarpedSpaceManager.getInstance().checkForWarpedSpace(new Location(x, y, z), new Location(tx, ty, tz), instance))
|
|
{
|
|
System.out.println("there is a warp space in path !");
|
|
return new Location(x, y, getHeight(x, y, z));
|
|
}
|
|
|
|
final LinePointIterator pointIter = new LinePointIterator(geoX, geoY, tGeoX, tGeoY);
|
|
// first point is guaranteed to be available
|
|
pointIter.next();
|
|
int prevX = pointIter.x();
|
|
int prevY = pointIter.y();
|
|
int prevZ = z;
|
|
|
|
while (pointIter.next())
|
|
{
|
|
final int curX = pointIter.x();
|
|
final int curY = pointIter.y();
|
|
final int curZ = getNearestZ(curX, curY, prevZ);
|
|
|
|
if (hasGeoPos(prevX, prevY))
|
|
{
|
|
final int nswe = GeoUtils.computeNswe(prevX, prevY, curX, curY);
|
|
if (!checkNearestNsweAntiCornerCut(prevX, prevY, prevZ, nswe))
|
|
{
|
|
// can't move, return previous location
|
|
return new Location(getWorldX(prevX), getWorldY(prevY), prevZ);
|
|
}
|
|
}
|
|
|
|
prevX = curX;
|
|
prevY = curY;
|
|
prevZ = curZ;
|
|
}
|
|
|
|
if (hasGeoPos(prevX, prevY) && (prevZ != tz))
|
|
{
|
|
// different floors, return start location
|
|
return new Location(x, y, z);
|
|
}
|
|
|
|
return new Location(tx, ty, tz);
|
|
}
|
|
|
|
public Location moveCheck(Location startLoc, Location endLoc, Instance instance)
|
|
{
|
|
return moveCheck(startLoc.getX(), startLoc.getY(), startLoc.getZ(), endLoc.getX(), endLoc.getY(), endLoc.getZ(), instance);
|
|
}
|
|
|
|
/**
|
|
* Checks if its possible to move from one location to another.
|
|
* @param fromX the X coordinate to start checking from
|
|
* @param fromY the Y coordinate to start checking from
|
|
* @param fromZ the Z coordinate to start checking from
|
|
* @param toX the X coordinate to end checking at
|
|
* @param toY the Y coordinate to end checking at
|
|
* @param toZ the Z coordinate to end checking at
|
|
* @param instance the instance
|
|
* @return {@code true} if the character at start coordinates can move to end coordinates, {@code false} otherwise
|
|
*/
|
|
public boolean canMove(int fromX, int fromY, int fromZ, int toX, int toY, int toZ, Instance instance)
|
|
{
|
|
final int geoX = getGeoX(fromX);
|
|
final int geoY = getGeoY(fromY);
|
|
fromZ = getNearestZ(geoX, geoY, fromZ);
|
|
final int tGeoX = getGeoX(toX);
|
|
final int tGeoY = getGeoY(toY);
|
|
toZ = getNearestZ(tGeoX, tGeoY, toZ);
|
|
|
|
if (DoorData.getInstance().checkIfDoorsBetween(fromX, fromY, fromZ, toX, toY, toZ, instance, false))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (WarpedSpaceManager.getInstance().checkForWarpedSpace(new Location(fromX, fromY, fromZ), new Location(toX, toY, toZ), instance))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
final LinePointIterator pointIter = new LinePointIterator(geoX, geoY, tGeoX, tGeoY);
|
|
// first point is guaranteed to be available
|
|
pointIter.next();
|
|
int prevX = pointIter.x();
|
|
int prevY = pointIter.y();
|
|
int prevZ = fromZ;
|
|
|
|
while (pointIter.next())
|
|
{
|
|
final int curX = pointIter.x();
|
|
final int curY = pointIter.y();
|
|
final int curZ = getNearestZ(curX, curY, prevZ);
|
|
|
|
if (hasGeoPos(prevX, prevY))
|
|
{
|
|
final int nswe = GeoUtils.computeNswe(prevX, prevY, curX, curY);
|
|
if (!checkNearestNsweAntiCornerCut(prevX, prevY, prevZ, nswe))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
prevX = curX;
|
|
prevY = curY;
|
|
prevZ = curZ;
|
|
}
|
|
|
|
if (hasGeoPos(prevX, prevY) && (prevZ != toZ))
|
|
{
|
|
// different floors
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Checks if its possible to move from one location to another.
|
|
* @param from the {@code WorldObject} to start checking from
|
|
* @param toX the X coordinate to end checking at
|
|
* @param toY the Y coordinate to end checking at
|
|
* @param toZ the Z coordinate to end checking at
|
|
* @return {@code true} if the character at start coordinates can move to end coordinates, {@code false} otherwise
|
|
*/
|
|
public boolean canMove(L2Object from, int toX, int toY, int toZ)
|
|
{
|
|
return canMove(from.getX(), from.getY(), from.getZ(), toX, toY, toZ, from.getInstanceWorld());
|
|
}
|
|
|
|
/**
|
|
* Checks if its possible to move from one location to another.
|
|
* @param from the {@code WorldObject} to start checking from
|
|
* @param to the {@code WorldObject} to end checking at
|
|
* @return {@code true} if the character at start coordinates can move to end coordinates, {@code false} otherwise
|
|
*/
|
|
public boolean canMove(L2Object from, L2Object to)
|
|
{
|
|
return canMove(from, to.getX(), to.getY(), to.getZ());
|
|
}
|
|
|
|
/**
|
|
* Checks the specified position for available geodata.
|
|
* @param x the X coordinate
|
|
* @param y the Y coordinate
|
|
* @return {@code true} if there is geodata for the given coordinates, {@code false} otherwise
|
|
*/
|
|
public boolean hasGeo(int x, int y)
|
|
{
|
|
return hasGeoPos(getGeoX(x), getGeoY(y));
|
|
}
|
|
|
|
public static GeoData getInstance()
|
|
{
|
|
return SingletonHolder._instance;
|
|
}
|
|
|
|
private static class SingletonHolder
|
|
{
|
|
protected final static GeoData _instance = new GeoData();
|
|
}
|
|
}
|