/*
* 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.HashMap;
import java.util.List;
import java.util.Random;
import me.eccentric_nz.TARDIS.TARDIS;
import me.eccentric_nz.TARDIS.chameleon.TARDISChameleonCircuit;
import me.eccentric_nz.TARDIS.database.QueryFactory;
import me.eccentric_nz.TARDIS.database.ResultSetTardis;
import me.eccentric_nz.TARDIS.database.data.Tardis;
import me.eccentric_nz.TARDIS.destroyers.TARDISDeinstaPreset;
import me.eccentric_nz.TARDIS.enumeration.COMPASS;
import me.eccentric_nz.TARDIS.enumeration.PRESET;
import me.eccentric_nz.TARDIS.junk.TARDISJunkBuilder;
import me.eccentric_nz.TARDIS.utility.TARDISMessage;
import me.eccentric_nz.TARDIS.utility.TARDISSounds;
import org.bukkit.Chunk;
import org.bukkit.Material;
import org.bukkit.block.Biome;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
/**
* The Wibbly lever was a part of The Doctor's TARDIS console. The lever had at
* least two functions: opening and closing doors and controlling implosions
* used to revert paradoxes in which the TARDIS had materialised within itself.
*
* @author eccentric_nz
*/
public class TARDISPresetBuilderFactory {
private final TARDIS plugin;
HashMap<COMPASS, BlockFace[]> face_map = new HashMap<COMPASS, BlockFace[]>();
public final List<PRESET> no_block_under_door;
public final List<PRESET> notSubmarinePresets;
Random rand;
public TARDISPresetBuilderFactory(TARDIS plugin) {
this.plugin = plugin;
this.rand = new Random();
face_map.put(COMPASS.NORTH, new BlockFace[]{BlockFace.SOUTH_WEST, BlockFace.SOUTH_SOUTH_WEST, BlockFace.SOUTH, BlockFace.SOUTH_SOUTH_EAST, BlockFace.SOUTH_EAST});
face_map.put(COMPASS.WEST, new BlockFace[]{BlockFace.SOUTH_EAST, BlockFace.EAST_SOUTH_EAST, BlockFace.EAST, BlockFace.EAST_NORTH_EAST, BlockFace.NORTH_EAST});
face_map.put(COMPASS.SOUTH, new BlockFace[]{BlockFace.NORTH_EAST, BlockFace.NORTH_NORTH_EAST, BlockFace.NORTH, BlockFace.NORTH_NORTH_WEST, BlockFace.NORTH_WEST});
face_map.put(COMPASS.EAST, new BlockFace[]{BlockFace.NORTH_WEST, BlockFace.WEST_NORTH_WEST, BlockFace.WEST, BlockFace.WEST_SOUTH_WEST, BlockFace.SOUTH_WEST});
no_block_under_door = new ArrayList<PRESET>();
no_block_under_door.add(PRESET.ANGEL);
no_block_under_door.add(PRESET.DUCK);
no_block_under_door.add(PRESET.GAZEBO);
no_block_under_door.add(PRESET.HELIX);
no_block_under_door.add(PRESET.LIBRARY);
no_block_under_door.add(PRESET.PANDORICA);
no_block_under_door.add(PRESET.ROBOT);
no_block_under_door.add(PRESET.TORCH);
no_block_under_door.add(PRESET.WELL);
notSubmarinePresets = new ArrayList<PRESET>();
notSubmarinePresets.add(PRESET.LAMP);
notSubmarinePresets.add(PRESET.MINESHAFT);
}
/**
* Builds the TARDIS Police Box.
*
* @param bd the TARDIS build data
*/
public void buildPreset(final BuildData bd) {
HashMap<String, Object> where = new HashMap<String, Object>();
where.put("tardis_id", bd.getTardisID());
ResultSetTardis rs = new ResultSetTardis(plugin, where, "", false, 0);
if (rs.resultSet()) {
Tardis tardis = rs.getTardis();
PRESET preset = tardis.getPreset();
Biome biome;
// keep the chunk this Police box is in loaded
Chunk thisChunk = bd.getLocation().getChunk();
while (!thisChunk.isLoaded()) {
thisChunk.load();
}
if (bd.isRebuild()) {
biome = bd.getLocation().getWorld().getBlockAt(bd.getLocation()).getRelative(getOppositeFace(bd.getDirection()), 2).getBiome();
} else {
biome = bd.getLocation().getWorld().getBiome(bd.getLocation().getBlockX(), bd.getLocation().getBlockZ());
}
bd.setBiome(biome);
if (plugin.getConfig().getBoolean("police_box.set_biome") && !bd.isRebuild()) {
// remember the current biome (unless rebuilding)
new QueryFactory(plugin).saveBiome(tardis.getTardis_id(), biome.toString());
}
if (tardis.isAdapti_on()) {
preset = adapt(biome, preset);
}
PRESET demat = tardis.getDemat();
int cham_id = tardis.getChameleon_id();
byte cham_data = tardis.getChameleon_data();
if (bd.isChameleon() && (preset.equals(PRESET.NEW) || preset.equals(PRESET.OLD) || preset.equals(PRESET.SUBMERGED))) {
Block chameleonBlock;
// chameleon circuit is on - get block under TARDIS
if (bd.getLocation().getBlock().getType() == Material.SNOW) {
chameleonBlock = bd.getLocation().getBlock();
} else {
chameleonBlock = bd.getLocation().getBlock().getRelative(BlockFace.DOWN);
}
// determine cham_id
TARDISChameleonCircuit tcc = new TARDISChameleonCircuit(plugin);
int[] b_data = tcc.getChameleonBlock(chameleonBlock, bd.getPlayer(), false);
cham_id = b_data[0];
cham_data = (byte) b_data[1];
}
boolean hidden = tardis.isHidden();
// get submarine preferences
if (bd.isSubmarine() && notSubmarinePresets.contains(preset)) {
preset = PRESET.YELLOW;
TARDISMessage.send(bd.getPlayer().getPlayer(), "SUB_UNSUITED");
}
/*
* We can always add the chunk, as List.remove() only removes the
* first occurence - and we want the chunk to remain loaded if there
* are other Police Boxes in it.
*/
while (!thisChunk.isLoaded()) {
thisChunk.load();
}
plugin.getGeneralKeeper().getTardisChunkList().add(thisChunk);
if (bd.isRebuild()) {
// always destroy it first as the player may just be switching presets
if (!hidden) {
TARDISDeinstaPreset deinsta = new TARDISDeinstaPreset(plugin);
deinsta.instaDestroyPreset(bd, false, demat);
}
plugin.getTrackerKeeper().getMaterialising().add(bd.getTardisID());
TARDISMaterialisationPreset runnable = new TARDISMaterialisationPreset(plugin, bd, preset, cham_id, cham_data, 3);
int taskID = plugin.getServer().getScheduler().scheduleSyncRepeatingTask(plugin, runnable, 10L, 20L);
runnable.setTask(taskID);
TARDISSounds.playTARDISSound(bd.getLocation(), "tardis_land_fast");
if (plugin.getUtils().inTARDISWorld(bd.getPlayer().getPlayer())) {
TARDISSounds.playTARDISSound(bd.getPlayer().getPlayer().getLocation(), "tardis_land_fast");
}
} else if (!preset.equals(PRESET.INVISIBLE)) {
plugin.getTrackerKeeper().getMaterialising().add(bd.getTardisID());
if (preset.equals(PRESET.JUNK)) {
TARDISJunkBuilder runnable = new TARDISJunkBuilder(plugin, bd);
int taskID = plugin.getServer().getScheduler().scheduleSyncRepeatingTask(plugin, runnable, 10L, 20L);
runnable.setTask(taskID);
} else {
TARDISMaterialisationPreset runnable = new TARDISMaterialisationPreset(plugin, bd, preset, cham_id, cham_data, 18);
int taskID = plugin.getServer().getScheduler().scheduleSyncRepeatingTask(plugin, runnable, 10L, 20L);
runnable.setTask(taskID);
}
} else {
final int id = cham_id;
final byte data = cham_data;
// delay by the usual time so handbrake message shows after materialisation sound
plugin.getServer().getScheduler().scheduleSyncDelayedTask(plugin, new Runnable() {
@Override
public void run() {
plugin.getTrackerKeeper().getMaterialising().add(bd.getTardisID());
TARDISInstaPreset insta = new TARDISInstaPreset(plugin, bd, PRESET.INVISIBLE, id, data, false);
insta.buildPreset();
}
}, 375L);
}
// update demat so it knows about the current preset after it has changed
HashMap<String, Object> whered = new HashMap<String, Object>();
whered.put("tardis_id", bd.getTardisID());
HashMap<String, Object> set = new HashMap<String, Object>();
set.put("chameleon_demat", preset.toString());
new QueryFactory(plugin).doUpdate("tardis", set, whered);
}
}
public PRESET adapt(Biome biome, PRESET preset) {
switch (biome) {
case DEEP_OCEAN:
case FROZEN_OCEAN:
case OCEAN:
return PRESET.YELLOW;
case DESERT:
case DESERT_HILLS:
return PRESET.DESERT;
case HELL:
return PRESET.NETHER;
case JUNGLE:
case JUNGLE_HILLS:
return PRESET.JUNGLE;
case PLAINS:
return PRESET.VILLAGE;
case MUSHROOM_ISLAND:
case MUSHROOM_ISLAND_SHORE:
return PRESET.SHROOM;
case SWAMPLAND:
return PRESET.SWAMP;
case SKY:
return PRESET.THEEND;
default:
return preset;
}
}
public BlockFace getSkullDirection(COMPASS d) {
BlockFace[] faces = face_map.get(d);
return faces[rand.nextInt(5)];
}
private BlockFace getOppositeFace(COMPASS d) {
switch (d) {
case SOUTH:
return BlockFace.NORTH;
case WEST:
return BlockFace.EAST;
case NORTH:
return BlockFace.SOUTH;
default:
return BlockFace.WEST;
}
}
}