package net.glowstone.generator.populators;
import org.bukkit.Chunk;
import org.bukkit.ChunkSnapshot;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.block.BlockState;
import org.bukkit.block.Chest;
import org.bukkit.block.CreatureSpawner;
import org.bukkit.entity.CreatureType;
import org.bukkit.generator.BlockPopulator;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import org.bukkit.util.noise.SimplexNoiseGenerator;
import java.util.Random;
/**
* A BlockPopulator that places dungeons around the map.
*/
public class DungeonPopulator extends BlockPopulator {
@Override
public void populate(World world, Random random, Chunk source) {
SimplexNoiseGenerator noise = new SimplexNoiseGenerator(world);
ChunkSnapshot snapshot = source.getChunkSnapshot();
// Randomly turn exposed stone to treasure
for (int x = 0; x < 16; x++) {
for (int z = 0; z < 16; z++) {
int y = snapshot.getHighestBlockYAt(x, z);
Block block = source.getBlock(x, y - 1, z);
if (block.getType() == Material.STONE
&& random.nextInt(1024) == 0) {
placeChest(random, block);
}
}
}
// Go go dungeons
double density = noise.noise(source.getX(), source.getZ());
if (density > 0.8) {
int roomCount = (int) (density * 10) - 3;
for (int i = 0; i < roomCount; i++) {
if (random.nextBoolean()) {
int x = (source.getX() << 4) + random.nextInt(16);
int z = (source.getZ() << 4) + random.nextInt(16);
int y = 12 + random.nextInt(22);
int sizeX = random.nextInt(12) + 5;
int sizeY = random.nextInt(6) + 4;
int sizeZ = random.nextInt(12) + 5;
generateRoom(x, y, z, sizeX, sizeY, sizeZ, world, random);
}
}
}
}
private static void generateRoom(int posX, int posY, int posZ, int sizeX, int sizeY, int sizeZ, World world, Random random) {
// Fill with air
for (int x = posX; x < posX + sizeX; x++) {
for (int y = posY; y < posY + sizeY; y++) {
for (int z = posZ; z < posZ + sizeZ; z++) {
placeBlock(world, x, y, z, Material.AIR);
}
}
}
// Spawners
int numSpawners = 1 + random.nextInt(2);
for (int i = 0; i < numSpawners; ++i) {
int x = posX + random.nextInt(sizeX);
int z = posZ + random.nextInt(sizeZ);
placeSpawner(random, world.getBlockAt(x, posY, z));
}
// Chests
int numChests = numSpawners + random.nextInt(2);
for (int i = 0; i < numChests; ++i) {
int x = posX + random.nextInt(sizeX);
int z = posZ + random.nextInt(sizeZ);
placeChest(random, world.getBlockAt(x, posY, z));
}
for (int x = posX - 1; x <= posX + sizeX; x++) {
for (int z = posZ - 1; z <= posZ + sizeZ; z++) {
placeBlock(world, x, posY - 1, z, pickStone(random));
placeBlock(world, x, posY + sizeY, z, pickStone(random));
}
}
for (int y = posY - 1; y <= posY + sizeX; y++) {
for (int z = posZ - 1; z <= posZ + sizeZ; z++) {
placeBlock(world, posX - 1, y, z, pickStone(random));
placeBlock(world, posX + sizeX, y, z, pickStone(random));
}
}
for (int x = posX - 1; x <= posX + sizeX; x++) {
for (int y = posY - 1; y <= posY + sizeY; y++) {
placeBlock(world, x, y, posZ - 1, pickStone(random));
placeBlock(world, x, y, posZ + sizeZ, pickStone(random));
}
}
}
private static Material pickStone(Random random) {
return random.nextInt(6) == 0 ? Material.MOSSY_COBBLESTONE : Material.COBBLESTONE;
}
private static void placeSpawner(Random random, Block block) {
CreatureType[] types = new CreatureType[]{
CreatureType.SKELETON, CreatureType.ZOMBIE,
CreatureType.CREEPER, CreatureType.SPIDER
};
block.setType(Material.MOB_SPAWNER);
BlockState state = block.getState();
if (state instanceof CreatureSpawner) {
((CreatureSpawner) state).setCreatureType(types[random.nextInt(types.length)]);
}
}
private static void placeChest(Random random, Block block) {
block.setType(Material.CHEST);
BlockState state = block.getState();
if (state instanceof Chest) {
Inventory chest = ((Chest) state).getInventory();
for (int i = 0; i < 5; i++) {
chest.setItem(random.nextInt(chest.getSize()), getRandomTool(random, i));
if (i < 5) {
chest.setItem(random.nextInt(chest.getSize()), getRandomArmor(random, i));
}
}
chest.setItem(random.nextInt(chest.getSize()), getRandomOre(random));
}
}
private static ItemStack getRandomOre(Random random) {
int i = random.nextInt(255);
int count = random.nextInt(63) + 1;
if (i > 253) {
return new ItemStack(Material.LAPIS_BLOCK, count);
} else if (i > 230) {
return new ItemStack(Material.DIAMOND_ORE, count);
} else if (i > 190) {
return new ItemStack(Material.GOLD_ORE, count);
} else if (i > 150) {
return new ItemStack(Material.IRON_ORE, count);
} else {
return new ItemStack(Material.COAL, count);
}
}
private static ItemStack getRandomTool(Random random, int index) {
// 0 = sword, 1 = spade, 2 = pickaxe, 3 = axe
int i = random.nextInt(255);
if (i > 245) { // Diamond
return new ItemStack(276 + index, 1);
} else if (i > 230) { // Gold
return new ItemStack(283 + index, 1);
} else if (i > 190) {
if (index == 0) { // Iron sword
return new ItemStack(267, 1);
}
// Iron items
return new ItemStack(255 + index, 1);
} else if (i > 150) { // Stone
return new ItemStack(272 + index, 1);
} else { // Wood
return new ItemStack(268 + index, 1);
}
}
private static ItemStack getRandomArmor(Random random, int index) {
// 0 = helmet, 1 = chestplate, 2 = leggings, 3 = boots
int i = random.nextInt(255);
if (i > 245) { // Diamond
return new ItemStack(310 + index, 1);
} else if (i > 230) { // Chainmail
return new ItemStack(302 + index, 1);
} else if (i > 190) { // Gold
return new ItemStack(314 + index, 1);
} else if (i > 150) { // Iron
return new ItemStack(306 + index, 1);
} else { // Leather
return new ItemStack(298 + index, 1);
}
}
private static void placeBlock(World world, int x, int y, int z, Material mat) {
if (canPlaceBlock(world, x, y, z) && mat != null) {
world.getBlockAt(x, y, z).setType(mat);
}
}
private static boolean canPlaceBlock(World world, int x, int y, int z) {
Block block = world.getBlockAt(x, y, z);
return !block.isLiquid() && block.getType() != Material.MOB_SPAWNER
&& block.getType() != Material.CHEST;
}
}