/*
* This file is part of the Illarion project.
*
* Copyright © 2015 - Illarion e.V.
*
* Illarion is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Illarion 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.
*/
package illarion.client.world;
import illarion.client.graphics.MapDisplayManager;
import illarion.common.types.Direction;
import illarion.common.types.ServerCoordinate;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
/**
* This utility class is used to process the map tiles and ensure that they are properly linked and assigned to each
* other.
*
* @author Martin Karing <nitram@illarion.org>
*/
public final class GameMapProcessor2 {
@Nullable
private static MapGroup lastInsideGroup;
private GameMapProcessor2() {
}
/**
* Process a single new tile.
*
* @param tile the tile to process
*/
@SuppressWarnings("StaticMethodOnlyUsedInOneClass")
public static void processTile(@Nonnull MapTile tile) {
ServerCoordinate playerLocation = World.getPlayer().getLocation();
MapTile tileAbove = getFirstTileAbove(tile.getCoordinates(), playerLocation.getZ() + 2, true);
MapTile tileBelow = getFirstTileBelow(tile.getCoordinates(), playerLocation.getZ() - 2, true);
if (tileAbove != null) {
tile.setObstructingTile(tileAbove);
}
if (tileBelow != null) {
tileBelow.setObstructingTile(tile);
}
List<MapGroup> groups = getSurroundingMapGroups(tile.getCoordinates());
MapGroup tileGroup;
if (groups.isEmpty()) {
tileGroup = new MapGroup();
tile.setMapGroup(tileGroup);
} else {
tileGroup = groups.get(0);
assert tileGroup != null;
tile.setMapGroup(tileGroup);
for (int i = 1; i < groups.size(); i++) {
//noinspection ConstantConditions
groups.get(i).setParent(tileGroup);
}
}
if (tileAbove != null) {
MapGroup tileAboveGroup = tileAbove.getMapGroup();
MapGroup tileAboveGroupRoot = (tileAboveGroup == null) ? null : tileAboveGroup.getRootGroup();
if (tileAboveGroupRoot != null) {
tileAboveGroupRoot.addOverwritingGroup(tileGroup);
}
}
if (tileBelow != null) {
MapGroup tileBelowGroup = tileBelow.getMapGroup();
MapGroup tileBelowGroupRoot = (tileBelowGroup == null) ? null : tileBelowGroup.getRootGroup();
if (tileBelowGroupRoot != null) {
tileGroup.addOverwritingGroup(tileBelowGroupRoot);
}
}
}
public static boolean isOutsideOfClipping(@Nonnull MapTile tile) {
if (!World.getPlayer().hasValidLocation()) {
return false;
}
ServerCoordinate playerLoc = World.getPlayer().getLocation();
ServerCoordinate tileLoc = tile.getCoordinates();
/*
* Start checking the clipping of the tiles. In case a tile is found outside the clipping range, its deleted.
*/
if ((playerLoc.getZ() + 2) < tileLoc.getZ()) {
return true;
}
if ((playerLoc.getZ() - 2) > tileLoc.getZ()) {
return true;
}
MapDimensions mapDim = MapDimensions.getInstance();
if ((playerLoc.toMapColumn() + mapDim.getClippingOffsetLeft()) > tileLoc.toMapColumn()) {
return true;
}
if ((playerLoc.toMapColumn() + mapDim.getClippingOffsetRight()) < tileLoc.toMapColumn()) {
return true;
}
int level = (Math.abs(tileLoc.getZ() - playerLoc.getZ()) * 6) + 1;
if ((playerLoc.toMapRow() + mapDim.getClippingOffsetTop()) < (tileLoc.toMapRow() - level)) {
return true;
}
return (playerLoc.toMapRow() + mapDim.getClippingOffsetBottom()) > (tileLoc.toMapRow() + level);
}
public static void checkInside() {
ServerCoordinate playerLocation = World.getPlayer().getLocation();
MapTile tileAbove = getFirstTileAbove(playerLocation, playerLocation.getZ() + 2, false);
MapGroup realTileAboveGroup = (tileAbove == null) ? null : tileAbove.getMapGroup();
MapGroup tileAboveGroup = (realTileAboveGroup == null) ? null : realTileAboveGroup.getRootGroup();
if (tileAboveGroup == null) {
if (lastInsideGroup != null) {
lastInsideGroup.setHidden(false);
lastInsideGroup = null;
}
World.getWeather().setOutside(true);
} else {
if (lastInsideGroup != null) {
if (Objects.equals(lastInsideGroup, tileAboveGroup)) {
return;
}
lastInsideGroup.setHidden(false);
}
tileAboveGroup.setHidden(true);
lastInsideGroup = tileAboveGroup;
World.getWeather().setOutside(false);
}
}
@Nullable
private static MapTile getFirstTileBelow(
@Nonnull ServerCoordinate startLocation, int zLimit, boolean perceptiveOffset) {
if (startLocation.getZ() <= zLimit) {
return null;
}
int currentX = startLocation.getX();
int currentY = startLocation.getY();
int currentZ = startLocation.getZ();
while (currentZ > zLimit) {
if (perceptiveOffset) {
currentX += MapDisplayManager.TILE_PERSPECTIVE_OFFSET;
currentY -= MapDisplayManager.TILE_PERSPECTIVE_OFFSET;
}
currentZ--;
MapTile tile = World.getMap().getMapAt(new ServerCoordinate(currentX, currentY, currentZ));
if (tile != null) {
return tile;
}
}
return null;
}
@Nullable
private static MapTile getFirstTileAbove(
@Nonnull ServerCoordinate startLocation, int zLimit, boolean perceptiveOffset) {
if (startLocation.getZ() >= zLimit) {
return null;
}
int currentX = startLocation.getX();
int currentY = startLocation.getY();
int currentZ = startLocation.getZ();
while (currentZ < zLimit) {
if (perceptiveOffset) {
currentX -= MapDisplayManager.TILE_PERSPECTIVE_OFFSET;
currentY += MapDisplayManager.TILE_PERSPECTIVE_OFFSET;
}
currentZ++;
MapTile tile = World.getMap().getMapAt(new ServerCoordinate(currentX, currentY, currentZ));
if (tile != null) {
return tile;
}
}
return null;
}
@Nonnull
private static List<MapGroup> getSurroundingMapGroups(@Nonnull ServerCoordinate startLocation) {
List<MapGroup> groupList = new ArrayList<>();
GameMap map = World.getMap();
//noinspection ConstantConditions
for (Direction dir : Direction.values()) {
ServerCoordinate newLoc = new ServerCoordinate(startLocation, dir);
MapTile tile = map.getMapAt(newLoc);
if (tile != null) {
MapGroup group = tile.getMapGroup();
if (group != null) {
group = group.getRootGroup();
}
if ((group != null) && !groupList.contains(group)) {
groupList.add(group);
}
}
}
return groupList;
}
}