blob: 811e27d2671154fd80d62181754e91c57f0b5217 [file] [log] [blame] [raw]
package net.glowstone.generator.objects.trees;
import java.util.Random;
import net.glowstone.util.BlockStateDelegate;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.block.BlockFace;
import org.bukkit.block.BlockState;
import org.bukkit.material.Dirt;
import org.bukkit.material.Vine;
import org.bukkit.material.types.DirtType;
public class MegaJungleTree extends GenericTree {
/**
* Initializes this tree with a random height, preparing it to attempt to generate.
* @param random the PRNG
* @param delegate the BlockStateDelegate used to check for space and to fill wood and
*/
public MegaJungleTree(Random random, BlockStateDelegate delegate) {
super(random, delegate);
setHeight(random.nextInt(20) + random.nextInt(3) + 10);
setTypes(3, 3);
}
@Override
public boolean canPlaceOn(BlockState soil) {
return soil.getType() == Material.GRASS || soil.getType() == Material.DIRT;
}
@Override
public boolean canPlace(int baseX, int baseY, int baseZ, World world) {
for (int y = baseY; y <= baseY + 1 + height; y++) {
// Space requirement
int radius = 2; // default radius if above first block
if (y == baseY) {
radius = 1; // radius at source block y is 1 (only trunk)
} else if (y >= baseY + 1 + height - 2) {
radius = 2; // max radius starting at leaves bottom
}
// check for block collision on horizontal slices
for (int x = baseX - radius; x <= baseX + radius; x++) {
for (int z = baseZ - radius; z <= baseZ + radius; z++) {
if (y >= 0 && y < 256) {
// we can overlap some blocks around
Material type = blockTypeAt(x, y, z, world);
if (!overridables.contains(type)) {
return false;
}
} else { // height out of range
return false;
}
}
}
}
return true;
}
@Override
public boolean generate(World world, Random random, int blockX, int blockY, int blockZ) {
if (cannotGenerateAt(blockX, blockY, blockZ, world)) {
return false;
}
// generates the canopy leaves
for (int y = -2; y <= 0; y++) {
generateLeaves(
blockX + 0, blockY + height + y, blockZ, 3 - y,
false, world);
}
// generates the branches
int branchHeight = height - 2 - random.nextInt(4);
while (branchHeight > height / 2) { // branching start at least at middle height
int x = 0;
int z = 0;
// generates a branch
float d = (float) (random.nextFloat() * Math.PI * 2.0F); // random direction
for (int i = 0; i < 5; i++) {
// branches are always longer when facing south or east (positive X or positive Z)
x = (int) (Math.cos(d) * i + 1.5F);
z = (int) (Math.sin(d) * i + 1.5F);
delegate.setTypeAndRawData(world, blockX + x,
blockY + branchHeight - 3 + i / 2,
blockZ + z, Material.LOG,
logType);
}
// generates leaves for this branch
for (int y = branchHeight - (random.nextInt(2) + 1); y <= branchHeight; y++) {
generateLeaves(
blockX + x, blockY + y, blockZ + z,
1 - (y - branchHeight), true, world);
}
branchHeight -= random.nextInt(4) + 2;
}
// generates the trunk
generateTrunk(world, blockX, blockY, blockZ);
// add some vines on the trunk
addVinesOnTrunk(world, blockX, blockY, blockZ, random);
// blocks below trunk are always dirt
generateDirtBelowTrunk(world, blockX, blockY, blockZ);
return true;
}
protected void generateLeaves(int sourceX, int sourceY, int sourceZ, int radius, boolean odd,
World world) {
int n = 1;
if (odd) {
n = 0;
}
for (int x = sourceX - radius; x <= sourceX + radius + n; x++) {
int radiusX = x - sourceX;
for (int z = sourceZ - radius; z <= sourceZ + radius + n; z++) {
int radiusZ = z - sourceZ;
int sqX = radiusX * radiusX;
int sqZ = radiusZ * radiusZ;
int sqR = radius * radius;
int sqXb = (radiusX - n) * (radiusX - n);
int sqZb = (radiusZ - n) * (radiusZ - n);
if (sqX + sqZ <= sqR || sqXb + sqZb <= sqR || sqX + sqZb <= sqR
|| sqXb + sqZ <= sqR) {
replaceIfAirOrLeaves(x, sourceY, z, Material.LEAVES, leavesType, world);
}
}
}
}
protected void generateTrunk(World world, int blockX, int blockY, int blockZ) {
// SELF, SOUTH, EAST, SOUTH EAST
for (int y = 0; y < height + -1; y++) {
Material type = world
.getBlockAt(blockX + 0, blockY + y, blockZ + 0)
.getType();
if (type == Material.AIR || type == Material.LEAVES) {
delegate.setTypeAndRawData(world, blockX + 0, blockY + y,
blockZ, Material.LOG, logType);
}
type = world
.getBlockAt(blockX + 0, blockY + y, blockZ + 1)
.getType();
if (type == Material.AIR || type == Material.LEAVES) {
delegate.setTypeAndRawData(world, blockX + 0, blockY + y,
blockZ + 1, Material.LOG, logType);
}
type = world
.getBlockAt(blockX + 1, blockY + y, blockZ + 0)
.getType();
if (type == Material.AIR || type == Material.LEAVES) {
delegate.setTypeAndRawData(world, blockX + 1, blockY + y,
blockZ, Material.LOG, logType);
}
type = world
.getBlockAt(blockX + 1, blockY + y, blockZ + 1)
.getType();
if (type == Material.AIR || type == Material.LEAVES) {
delegate.setTypeAndRawData(world, blockX + 1, blockY + y,
blockZ + 1, Material.LOG, logType);
}
}
}
protected void generateDirtBelowTrunk(World world, int blockX, int blockY, int blockZ) {
// SELF, SOUTH, EAST, SOUTH EAST
Dirt dirt = new Dirt(DirtType.NORMAL);
delegate
.setTypeAndData(world, blockX + 0,
blockY + -1, blockZ,
Material.DIRT, dirt);
delegate.setTypeAndData(world, blockX + 0, blockY + -1,
blockZ + 1, Material.DIRT, dirt);
delegate.setTypeAndData(world, blockX + 1, blockY + -1,
blockZ, Material.DIRT, dirt);
delegate.setTypeAndData(world, blockX + 1, blockY + -1,
blockZ + 1, Material.DIRT, dirt);
}
private void addVinesOnTrunk(World world, int blockX, int blockY, int blockZ, Random random) {
for (int y = 1; y < height; y++) {
maybePlaceVine(world,
blockX + -1, blockY + y, blockZ + 0, BlockFace.EAST, random
);
maybePlaceVine(world,
blockX + 0, blockY + y, blockZ + -1, BlockFace.SOUTH, random
);
maybePlaceVine(world,
blockX + 2, blockY + y, blockZ + 0, BlockFace.WEST, random
);
maybePlaceVine(world,
blockX + 1, blockY + y, blockZ + -1, BlockFace.SOUTH, random
);
maybePlaceVine(world,
blockX + 2, blockY + y, blockZ + 1, BlockFace.WEST, random
);
maybePlaceVine(world,
blockX + 1, blockY + y, blockZ + 2, BlockFace.NORTH, random
);
maybePlaceVine(world,
blockX + -1, blockY + y, blockZ + 1, BlockFace.EAST, random
);
maybePlaceVine(world,
blockX + 0, blockY + y, blockZ + 2, BlockFace.NORTH, random
);
}
}
private void maybePlaceVine(World world, int absoluteX, int absoluteY,
int absoluteZ, BlockFace facingDirection, Random random) {
if (random.nextInt(3) != 0
&& blockTypeAt(absoluteX, absoluteY, absoluteZ, world)
== Material.AIR) {
delegate.setTypeAndData(world, absoluteX, absoluteY,
absoluteZ, Material.VINE, new Vine(facingDirection));
}
}
}