/*
* Copyright (C) 2014 eccentric_nz
*
* 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 me.eccentric_nz.TARDIS.travel;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import me.eccentric_nz.TARDIS.TARDIS;
import me.eccentric_nz.TARDIS.database.ResultSetCurrentLocation;
import me.eccentric_nz.TARDIS.enumeration.COMPASS;
import me.eccentric_nz.TARDIS.utility.TARDISMessage;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.WorldType;
import org.bukkit.block.BlockFace;
import org.bukkit.entity.Player;
/**
*
* @author eccentric_nz
*/
public class TARDISCaveFinder {
private final TARDIS plugin;
public TARDISCaveFinder(TARDIS plugin) {
this.plugin = plugin;
}
public Location searchCave(Player p, int id) {
Location l = null;
// get the current TARDIS location
HashMap<String, Object> where = new HashMap<String, Object>();
where.put("tardis_id", id);
ResultSetCurrentLocation rsc = new ResultSetCurrentLocation(plugin, where);
if (rsc.resultSet()) {
World w = rsc.getWorld();
int startx = rsc.getX();
int startz = rsc.getZ();
COMPASS d = rsc.getDirection();
// Assume all non-nether/non-end world environments are NORMAL
boolean hoth = (w.getGenerator() != null && w.getGenerator().getClass().getName().contains("hothgenerator"));
if (!w.getEnvironment().equals(World.Environment.NETHER) && !w.getEnvironment().equals(World.Environment.THE_END) && !hoth) {
if (!w.getWorldType().equals(WorldType.FLAT) && worldCheck(w)) {
int limitx = 2000;
int limitz = 2000;
int step = 25;
// search in a random direction
Integer[] directions = new Integer[]{0, 1, 2, 3};
Collections.shuffle(Arrays.asList(directions));
for (int i = 0; i < 4; i++) {
switch (directions[i]) {
case 0:
// east
TARDISMessage.send(p, "LOOK_E");
for (int east = startx; east < east + limitx; east += step) {
Check chk = isThereRoom(w, east, startz, d);
if (chk.isSafe()) {
TARDISMessage.send(p, "CAVE_E");
return new Location(w, east, chk.getY(), startz);
}
}
break;
case 1:
// south
TARDISMessage.send(p, "LOOK_S");
for (int south = startz; south < south + limitz; south += step) {
Check chk = isThereRoom(w, startx, south, d);
if (chk.isSafe()) {
TARDISMessage.send(p, "CAVE_S");
return new Location(w, startx, chk.getY(), south);
}
}
break;
case 2:
// west
TARDISMessage.send(p, "LOOK_W");
for (int west = startx; west > west - limitx; west -= step) {
Check chk = isThereRoom(w, west, startz, d);
if (chk.isSafe()) {
TARDISMessage.send(p, "CAVE_W");
return new Location(w, west, chk.getY(), startz);
}
}
break;
case 3:
// north
TARDISMessage.send(p, "LOOK_N");
for (int north = startz; north > north - limitz; north -= step) {
Check chk = isThereRoom(w, startx, north, d);
if (chk.isSafe()) {
TARDISMessage.send(p, "CAVE_N");
return new Location(w, startx, chk.getY(), north);
}
}
break;
}
}
}
} else {
String env = (w.getGenerator().getClass().getName().contains("hothgenerator")) ? "Hoth World System" : w.getEnvironment().toString();
TARDISMessage.send(p, "CAVE_NO_TRAVEL", env);
}
} else {
TARDISMessage.send(p, "CURRENT_NOT_FOUND");
}
return l;
}
private Check isThereRoom(World w, int x, int z, COMPASS d) {
Check ret = new Check();
ret.setSafe(false);
for (int y = 35; y > 14; y--) {
if (w.getBlockAt(x, y, z).getType().equals(Material.AIR)) {
int yy = getLowestAirBlock(w, x, y, z);
// check there is enough height for the police box
if (yy <= y - 3 && !w.getBlockAt(x - 1, yy - 1, z - 1).getType().equals(Material.STONE)) {
// check there is room for the police box
if (w.getBlockAt(x - 1, yy, z - 1).getType().equals(Material.AIR)
&& w.getBlockAt(x - 1, yy, z).getType().equals(Material.AIR)
&& w.getBlockAt(x - 1, yy, z + 1).getType().equals(Material.AIR)
&& w.getBlockAt(x, yy, z - 1).getType().equals(Material.AIR)
&& w.getBlockAt(x, yy, z + 1).getType().equals(Material.AIR)
&& w.getBlockAt(x + 1, yy, z - 1).getType().equals(Material.AIR)
&& w.getBlockAt(x + 1, yy, z).getType().equals(Material.AIR)
&& w.getBlockAt(x + 1, yy, z + 1).getType().equals(Material.AIR)) {
// finally check there is space to exit the police box
boolean safe = false;
switch (d) {
case NORTH:
if (w.getBlockAt(x - 1, yy, z + 2).getType().equals(Material.AIR)
&& w.getBlockAt(x, yy, z + 2).getType().equals(Material.AIR)
&& w.getBlockAt(x + 1, yy, z + 2).getType().equals(Material.AIR)) {
safe = true;
}
break;
case WEST:
if (w.getBlockAt(x + 2, yy, z - 1).getType().equals(Material.AIR)
&& w.getBlockAt(x + 2, yy, z).getType().equals(Material.AIR)
&& w.getBlockAt(x + 2, yy, z + 1).getType().equals(Material.AIR)) {
safe = true;
}
break;
case SOUTH:
if (w.getBlockAt(x - 1, yy, z - 2).getType().equals(Material.AIR)
&& w.getBlockAt(x, yy, z - 2).getType().equals(Material.AIR)
&& w.getBlockAt(x + 1, yy, z - 2).getType().equals(Material.AIR)) {
safe = true;
}
break;
default:
if (w.getBlockAt(x - 2, yy, z - 1).getType().equals(Material.AIR)
&& w.getBlockAt(x - 2, yy, z).getType().equals(Material.AIR)
&& w.getBlockAt(x - 2, yy, z + 1).getType().equals(Material.AIR)) {
safe = true;
}
break;
}
if (safe) {
ret.setSafe(true);
ret.setY(yy);
}
}
}
}
}
return ret;
}
private int getLowestAirBlock(World w, int x, int y, int z) {
int yy = y;
while (w.getBlockAt(x, yy, z).getRelative(BlockFace.DOWN).getType().equals(Material.AIR) && yy > 7) {
yy--;
}
return yy;
}
private boolean worldCheck(World w) {
Location spawn = w.getSpawnLocation();
int y = w.getHighestBlockYAt(spawn);
if (y < 15) {
return false;
} else if (w.getBlockAt(spawn.getBlockX(), 0, spawn.getBlockZ()).getType().equals(Material.AIR)) {
return false;
} else {
// move 20 blocks north
spawn.setZ(spawn.getBlockZ() - 100);
int ny = w.getHighestBlockYAt(spawn);
spawn.setX(spawn.getBlockX() + 100);
int ey = w.getHighestBlockYAt(spawn);
spawn.setZ(spawn.getBlockZ() + 100);
int sy = w.getHighestBlockYAt(spawn);
return (y != ny || y != ey || y != sy);
}
}
private class Check {
private boolean safe;
private int y;
public boolean isSafe() {
return safe;
}
public void setSafe(boolean safe) {
this.safe = safe;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
}
}