/*
* Copyright (C) 2016 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.builders;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Random;
import java.util.UUID;
import me.eccentric_nz.TARDIS.TARDIS;
import me.eccentric_nz.TARDIS.TARDISConstants;
import me.eccentric_nz.TARDIS.chameleon.TARDISChameleonColumn;
import me.eccentric_nz.TARDIS.chameleon.TARDISConstructColumn;
import me.eccentric_nz.TARDIS.database.QueryFactory;
import me.eccentric_nz.TARDIS.database.ResultSetDoors;
import me.eccentric_nz.TARDIS.database.ResultSetTardis;
import me.eccentric_nz.TARDIS.database.ResultSetTravellers;
import me.eccentric_nz.TARDIS.database.data.Tardis;
import me.eccentric_nz.TARDIS.enumeration.COMPASS;
import me.eccentric_nz.TARDIS.enumeration.PRESET;
import me.eccentric_nz.TARDIS.travel.TARDISDoorLocation;
import me.eccentric_nz.TARDIS.utility.TARDISBlockSetters;
import me.eccentric_nz.TARDIS.utility.TARDISMessage;
import me.eccentric_nz.TARDIS.utility.TARDISStaticUtils;
import org.bukkit.ChatColor;
import org.bukkit.Chunk;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.block.Biome;
import org.bukkit.block.Block;
import org.bukkit.block.Sign;
import org.bukkit.block.Skull;
import org.bukkit.entity.Player;
/**
* A police box is a telephone kiosk that can be used by members of the public
* wishing to get help from the police. Early in the First Doctor's travels, the
* TARDIS assumed the exterior shape of a police box during a five-month
* stopover in 1963 London. Due a malfunction in its chameleon circuit, the
* TARDIS became locked into that shape.
*
* @author eccentric_nz
*/
public class TARDISInstaPreset {
private final TARDIS plugin;
private final BuildData bd;
private final int cham_id;
private final byte cham_data;
private final boolean rebuild;
private Block sponge;
private final PRESET preset;
private TARDISChameleonColumn column;
private final byte[] colours;
private final Random rand;
private final byte random_colour;
private final ChatColor sign_colour;
private final List<ProblemBlock> do_at_end = new ArrayList<ProblemBlock>();
private final List<Integer> doors = Arrays.asList(64, 71, 193, 194, 195, 196, 197);
public TARDISInstaPreset(TARDIS plugin, BuildData bd, PRESET preset, int cham_id, byte cham_data, boolean rebuild) {
this.plugin = plugin;
this.bd = bd;
this.preset = preset;
this.cham_id = cham_id;
this.cham_data = cham_data;
this.rebuild = rebuild;
colours = new byte[]{0, 1, 2, 3, 4, 5, 6, 9, 10, 11, 12, 13, 14};
rand = new Random();
random_colour = colours[rand.nextInt(13)];
this.sign_colour = plugin.getUtils().getSignColour();
}
/**
* Builds the TARDIS Preset.
*/
public void buildPreset() {
if (preset.equals(PRESET.ANGEL)) {
plugin.getPresets().setR(rand.nextInt(2));
}
if (preset.equals(PRESET.CONSTRUCT)) {
column = new TARDISConstructColumn(plugin, bd.getTardisID(), "blueprint", bd.getDirection()).getColumn();
} else {
column = plugin.getPresets().getColumn(preset, bd.getDirection());
}
int plusx, minusx, x, plusz, y, minusz, z;
// get relative locations
x = bd.getLocation().getBlockX();
plusx = (bd.getLocation().getBlockX() + 1);
minusx = (bd.getLocation().getBlockX() - 1);
if (preset.equals(PRESET.SUBMERGED)) {
y = bd.getLocation().getBlockY() - 1;
} else {
y = bd.getLocation().getBlockY();
}
z = (bd.getLocation().getBlockZ());
plusz = (bd.getLocation().getBlockZ() + 1);
minusz = (bd.getLocation().getBlockZ() - 1);
final World world = bd.getLocation().getWorld();
int signx = 0, signz = 0;
QueryFactory qf = new QueryFactory(plugin);
// if configured and it's a Whovian preset set biome
if (plugin.getConfig().getBoolean("police_box.set_biome") && (preset.equals(PRESET.NEW) || preset.equals(PRESET.OLD) || preset.equals(PRESET.PANDORICA)) && bd.useTexture()) {
List<Chunk> chunks = new ArrayList<Chunk>();
Chunk chunk = bd.getLocation().getChunk();
chunks.add(chunk);
// load the chunk
final int cx = bd.getLocation().getBlockX() >> 4;
final int cz = bd.getLocation().getBlockZ() >> 4;
if (!world.loadChunk(cx, cz, false)) {
world.loadChunk(cx, cz, true);
}
while (!chunk.isLoaded()) {
world.loadChunk(chunk);
}
// set the biome
for (int c = -1; c < 2; c++) {
for (int r = -1; r < 2; r++) {
world.setBiome(x + c, z + r, Biome.DEEP_OCEAN);
// TODO check re-adding umbrella if rebuilding
if (TARDISConstants.NO_RAIN.contains(bd.getBiome())) {
// add an invisible roof
plugin.getBlockUtils().setBlockAndRemember(world, x + c, 255, z + r, Material.BARRIER, (byte) 0, bd.getTardisID());
}
Chunk tmp_chunk = world.getChunkAt(new Location(world, x + c, 64, z + r));
if (!chunks.contains(tmp_chunk)) {
chunks.add(tmp_chunk);
}
}
}
// refresh the chunks
for (Chunk c : chunks) {
//world.refreshChunk(c.getX(), c.getZ());
plugin.getTardisHelper().refreshChunk(c);
}
}
// rescue player?
if (plugin.getTrackerKeeper().getRescue().containsKey(bd.getTardisID())) {
UUID playerUUID = plugin.getTrackerKeeper().getRescue().get(bd.getTardisID());
Player saved = plugin.getServer().getPlayer(playerUUID);
if (saved != null) {
TARDISDoorLocation idl = plugin.getGeneralKeeper().getDoorListener().getDoor(1, bd.getTardisID());
Location l = idl.getL();
plugin.getGeneralKeeper().getDoorListener().movePlayer(saved, l, false, world, false, 0, bd.useMinecartSounds());
// put player into travellers table
HashMap<String, Object> set = new HashMap<String, Object>();
set.put("tardis_id", bd.getTardisID());
set.put("uuid", playerUUID.toString());
qf.doInsert("travellers", set);
}
plugin.getTrackerKeeper().getRescue().remove(bd.getTardisID());
}
switch (bd.getDirection()) {
case SOUTH:
//if (yaw >= 315 || yaw < 45)
signx = x;
signz = (minusz - 1);
break;
case EAST:
//if (yaw >= 225 && yaw < 315)
signx = (minusx - 1);
signz = z;
break;
case NORTH:
//if (yaw >= 135 && yaw < 225)
signx = x;
signz = (plusz + 1);
break;
case WEST:
//if (yaw >= 45 && yaw < 135)
signx = (plusx + 1);
signz = z;
break;
}
int xx, zz;
int[][] ids = column.getId();
byte[][] datas = column.getData();
for (int i = 0; i < 10; i++) {
int[] colids = ids[i];
byte[] coldatas = datas[i];
switch (i) {
case 0:
xx = minusx;
zz = minusz;
break;
case 1:
xx = x;
zz = minusz;
break;
case 2:
xx = plusx;
zz = minusz;
break;
case 3:
xx = plusx;
zz = z;
break;
case 4:
xx = plusx;
zz = plusz;
break;
case 5:
xx = x;
zz = plusz;
break;
case 6:
xx = minusx;
zz = plusz;
break;
case 7:
xx = minusx;
zz = z;
break;
case 8:
xx = x;
zz = z;
break;
default:
xx = signx;
zz = signz;
break;
}
for (int yy = 0; yy < 4; yy++) {
boolean change = true;
if (yy == 0 && i == 9) {
Block rail = world.getBlockAt(xx, y, zz);
if (rail.getType().equals(Material.RAILS) || rail.getType().equals(Material.POWERED_RAIL)) {
change = false;
plugin.getBlockUtils().setBlockAndRemember(world, xx, y, zz, rail.getTypeId(), rail.getData(), bd.getTardisID());
}
}
if (yy == 0 && i == 8 && !plugin.getPresetBuilder().no_block_under_door.contains(preset)) {
plugin.getBlockUtils().setUnderDoorBlock(world, xx, (y - 1), zz, bd.getTardisID(), true);
}
// update door location if invisible
if (yy == 0 && (i == 1 || i == 3 || i == 5 || i == 7) && preset.equals(PRESET.INVISIBLE) && colids[yy] == 0) {
String invisible_door = world.getName() + ":" + xx + ":" + y + ":" + zz;
processDoor(invisible_door, qf);
// if tardis is in the air add under door
plugin.getBlockUtils().setUnderDoorBlock(world, xx, (y - 1), zz, bd.getTardisID(), true);
}
switch (colids[yy]) {
case 2:
case 3:
int subi = (preset.equals(PRESET.SUBMERGED)) ? cham_id : colids[yy];
byte subd = (preset.equals(PRESET.SUBMERGED)) ? cham_data : coldatas[yy];
plugin.getBlockUtils().setBlockAndRemember(world, xx, (y + yy), zz, subi, subd, bd.getTardisID());
break;
case 7:
if (preset.equals(PRESET.THEEND)) {
plugin.getBlockUtils().setBlockAndRemember(world, xx, (y + yy), zz, 7, (byte) 5, bd.getTardisID());
world.getBlockAt(xx, (y + yy + 1), zz).setType(Material.FIRE);
} else {
plugin.getBlockUtils().setBlockAndRemember(world, xx, (y + yy), zz, colids[yy], coldatas[yy], bd.getTardisID());
}
break;
case 35:
int chai = (preset.equals(PRESET.NEW) || preset.equals(PRESET.OLD)) ? cham_id : colids[yy];
byte chad = (preset.equals(PRESET.NEW) || preset.equals(PRESET.OLD)) ? cham_data : coldatas[yy];
if (preset.equals(PRESET.PARTY) || (preset.equals(PRESET.FLOWER) && coldatas[yy] == 0)) {
chad = random_colour;
}
if (bd.shouldUseCTM() && i == TARDISStaticUtils.getCol(bd.getDirection()) && yy == 1 && cham_id == 35 && (cham_data == (byte) 11 || cham_data == (byte) 3) && (preset.equals(PRESET.NEW) || preset.equals(PRESET.OLD)) && plugin.getConfig().getBoolean("police_box.set_biome")) {
// set a quartz pillar block instead
byte pillar = (bd.getDirection().equals(COMPASS.EAST) || bd.getDirection().equals(COMPASS.WEST)) ? (byte) 3 : (byte) 4;
plugin.getBlockUtils().setBlockAndRemember(world, xx, (y + yy), zz, 155, pillar, bd.getTardisID());
} else {
plugin.getBlockUtils().setBlockAndRemember(world, xx, (y + yy), zz, chai, chad, bd.getTardisID());
}
break;
case 50: // lamps, glowstone and torches
case 89:
case 124:
Material light;
byte ld;
if (bd.isSubmarine() && colids[yy] == 50) {
light = Material.GLOWSTONE;
ld = 0;
} else {
light = (preset.equals(PRESET.NEW) || preset.equals(PRESET.OLD)) ? bd.getLamp() : Material.getMaterial(colids[yy]);
ld = coldatas[yy];
}
if (colids[yy] == 50) {
do_at_end.add(new ProblemBlock(new Location(world, xx, (y + yy), zz), light, ld));
} else {
plugin.getBlockUtils().setBlockAndRemember(world, xx, (y + yy), zz, light, ld, bd.getTardisID());
}
break;
case 64: // wood, iron & trap doors, rails
case 66:
case 71:
case 96:
case 193:
case 194:
case 195:
case 196:
case 197:
if (coldatas[yy] < 8 || colids[yy] == 96) {
if (colids[yy] != 66) {
// remember the door location
String doorloc = world.getName() + ":" + xx + ":" + (y + yy) + ":" + zz;
processDoor(doorloc, qf);
}
// place block under door if block is in list of blocks an iron door cannot go on
if (yy == 0) {
if (bd.isSubmarine() && plugin.isWorldGuardOnServer()) {
int sy = y - 1;
plugin.getBlockUtils().setBlockAndRemember(world, xx, sy, zz, 19, (byte) 0, bd.getTardisID());
sponge = world.getBlockAt(xx, sy, zz);
plugin.getWorldGuardUtils().sponge(sponge, true);
} else if (!plugin.getPresetBuilder().no_block_under_door.contains(preset)) {
plugin.getBlockUtils().setUnderDoorBlock(world, xx, (y - 1), zz, bd.getTardisID(), false);
}
}
}
if (doors.contains(colids[yy]) && coldatas[yy] > 8) {
plugin.getBlockUtils().setBlockAndRemember(world, xx, (y + yy), zz, colids[yy], bd.getDirection().getUpperData(), bd.getTardisID());
} else if (colids[yy] == 66) {
do_at_end.add(new ProblemBlock(new Location(world, xx, (y + yy), zz), Material.getMaterial(colids[yy]), coldatas[yy]));
} else {
plugin.getBlockUtils().setBlockAndRemember(world, xx, (y + yy), zz, colids[yy], coldatas[yy], bd.getTardisID());
}
break;
case 63:
if (preset.equals(PRESET.APPERTURE)) {
plugin.getBlockUtils().setUnderDoorBlock(world, xx, (y - 1), zz, bd.getTardisID(), false);
}
break;
case 68: // sign - if there is one
if (bd.shouldAddSign()) {
TARDISBlockSetters.setBlock(world, xx, (y + yy), zz, colids[yy], coldatas[yy]);
Block sign = world.getBlockAt(xx, (y + yy), zz);
if (sign.getType().equals(Material.WALL_SIGN) || sign.getType().equals(Material.SIGN_POST)) {
Sign s = (Sign) sign.getState();
if (plugin.getConfig().getBoolean("police_box.name_tardis")) {
HashMap<String, Object> wheret = new HashMap<String, Object>();
wheret.put("tardis_id", bd.getTardisID());
ResultSetTardis rst = new ResultSetTardis(plugin, wheret, "", false, 0);
if (rst.resultSet()) {
Tardis tardis = rst.getTardis();
String player_name = plugin.getGeneralKeeper().getUUIDCache().getNameCache().get(tardis.getUuid());
if (player_name == null) {
// cache lookup failed, player may have disconnected
player_name = tardis.getOwner();
}
String owner;
if (preset.equals(PRESET.GRAVESTONE) || preset.equals(PRESET.PUNKED) || preset.equals(PRESET.ROBOT)) {
owner = (player_name.length() > 14) ? player_name.substring(0, 14) : player_name;
} else {
owner = (player_name.length() > 14) ? player_name.substring(0, 12) + "'s" : player_name + "'s";
}
switch (preset) {
case GRAVESTONE:
s.setLine(3, owner);
break;
case ANGEL:
case JAIL:
s.setLine(2, owner);
break;
default:
s.setLine(0, owner);
break;
}
}
}
String line1;
String line2;
if (preset.equals(PRESET.CUSTOM)) {
line1 = plugin.getPresets().custom.getFirstLine();
line2 = plugin.getPresets().custom.getSecondLine();
} else {
line1 = preset.getFirstLine();
line2 = preset.getSecondLine();
}
switch (preset) {
case ANGEL:
s.setLine(0, sign_colour + line1);
s.setLine(1, sign_colour + line2);
s.setLine(3, sign_colour + "TARDIS");
break;
case APPERTURE:
s.setLine(1, sign_colour + line1);
s.setLine(2, sign_colour + line2);
s.setLine(3, sign_colour + "LAB");
break;
case JAIL:
s.setLine(0, sign_colour + line1);
s.setLine(1, sign_colour + line2);
s.setLine(3, sign_colour + "CAPTURE");
break;
case THEEND:
s.setLine(1, sign_colour + line1);
s.setLine(2, sign_colour + line2);
s.setLine(3, sign_colour + "HOT ROD");
break;
default:
s.setLine(1, sign_colour + line1);
s.setLine(2, sign_colour + line2);
break;
}
s.update();
}
}
break;
case 87:
plugin.getBlockUtils().setBlockAndRemember(world, xx, (y + yy), zz, colids[yy], coldatas[yy], bd.getTardisID());
if (preset.equals(PRESET.TORCH)) {
world.getBlockAt(xx, (y + yy + 1), zz).setType(Material.FIRE);
}
break;
case 90:
plugin.getBlockUtils().setBlockAndRemember(world, xx, (y + yy + 1), zz, 49, (byte) 0, bd.getTardisID());
plugin.getBlockUtils().setBlockAndRemember(world, xx, (y + yy), zz, colids[yy], coldatas[yy], bd.getTardisID());
break;
case 144:
if (bd.isSubmarine()) {
TARDISBlockSetters.setBlock(world, xx, (y + yy), zz, 89, (byte) 0);
} else {
plugin.getBlockUtils().setBlockAndRemember(world, xx, (y + yy), zz, colids[yy], coldatas[yy], bd.getTardisID());
Skull skull = (Skull) world.getBlockAt(xx, (y + yy), zz).getState();
skull.setRotation(plugin.getPresetBuilder().getSkullDirection(bd.getDirection()));
skull.update();
}
break;
case 152:
if (!bd.getLamp().equals(Material.REDSTONE_LAMP_OFF) && (preset.equals(PRESET.NEW) || preset.equals(PRESET.OLD))) {
plugin.getBlockUtils().setBlockAndRemember(world, xx, (y + yy), zz, cham_id, cham_data, bd.getTardisID());
} else {
plugin.getBlockUtils().setBlockAndRemember(world, xx, (y + yy), zz, colids[yy], coldatas[yy], bd.getTardisID());
}
break;
default: // everything else
if (change) {
if (colids[yy] == 69 || colids[yy] == 77 || colids[yy] == 143) {
do_at_end.add(new ProblemBlock(new Location(world, xx, (y + yy), zz), Material.getMaterial(colids[yy]), coldatas[yy]));
} else {
plugin.getBlockUtils().setBlockAndRemember(world, xx, (y + yy), zz, colids[yy], coldatas[yy], bd.getTardisID());
}
}
break;
}
}
}
for (ProblemBlock pb : do_at_end) {
plugin.getBlockUtils().setBlockAndRemember(pb.getL().getWorld(), pb.getL().getBlockX(), pb.getL().getBlockY(), pb.getL().getBlockZ(), pb.getId(), pb.getData(), bd.getTardisID());
}
if (!rebuild) {
// message travellers in tardis
HashMap<String, Object> where = new HashMap<String, Object>();
where.put("tardis_id", bd.getTardisID());
ResultSetTravellers rst = new ResultSetTravellers(plugin, where, true);
if (rst.resultSet()) {
final List<UUID> travellers = rst.getData();
plugin.getServer().getScheduler().scheduleSyncDelayedTask(plugin, new Runnable() {
@Override
public void run() {
for (UUID s : travellers) {
Player trav = plugin.getServer().getPlayer(s);
if (trav != null) {
String message = (bd.isMalfunction()) ? "MALFUNCTION" : "HANDBRAKE_LEFT_CLICK";
TARDISMessage.send(trav, message);
// TARDIS has travelled so add players to list so they can receive Artron on exit
if (!plugin.getTrackerKeeper().getHasTravelled().contains(s)) {
plugin.getTrackerKeeper().getHasTravelled().add(s);
}
}
}
}
}, 30L);
}
}
plugin.getTrackerKeeper().getMaterialising().removeAll(Collections.singleton(bd.getTardisID()));
plugin.getTrackerKeeper().getDematerialising().removeAll(Collections.singleton(bd.getTardisID()));
plugin.getTrackerKeeper().getInVortex().removeAll(Collections.singleton(bd.getTardisID()));
if (plugin.getTrackerKeeper().getDestinationVortex().containsKey(bd.getTardisID())) {
plugin.getTrackerKeeper().getDestinationVortex().remove(bd.getTardisID());
}
}
private void processDoor(String doorloc, QueryFactory qf) {
// should insert the door when tardis is first made, and then update the location there after!
HashMap<String, Object> whered = new HashMap<String, Object>();
whered.put("door_type", 0);
whered.put("tardis_id", bd.getTardisID());
ResultSetDoors rsd = new ResultSetDoors(plugin, whered, false);
HashMap<String, Object> setd = new HashMap<String, Object>();
setd.put("door_location", doorloc);
setd.put("door_direction", bd.getDirection().toString());
if (rsd.resultSet()) {
HashMap<String, Object> whereid = new HashMap<String, Object>();
whereid.put("door_id", rsd.getDoor_id());
qf.doUpdate("doors", setd, whereid);
} else {
setd.put("tardis_id", bd.getTardisID());
setd.put("door_type", 0);
qf.doInsert("doors", setd);
}
}
private class ProblemBlock {
Location l;
Material id;
byte data;
public ProblemBlock(Location l, Material id, byte data) {
this.l = l;
this.id = id;
this.data = data;
}
public Location getL() {
return l;
}
public Material getId() {
return id;
}
public byte getData() {
return data;
}
}
}