blob: e71a18773f762af0555c91bb28c396d4943f9e8b [file] [log] [blame] [raw]
package net.glowstone.generator.trees;
import net.glowstone.util.BlockStateDelegate;
import org.bukkit.Material;
import org.bukkit.World;
import java.util.Random;
public class SpruceTree extends GenericTree {
private final int maxRadius;
private final int leavesHeight;
public SpruceTree(Random random, BlockStateDelegate delegate) {
super(random, delegate);
setOverridables(
Material.AIR,
Material.LEAVES
);
setHeight(random.nextInt(4) + 6);
maxRadius = random.nextInt(2) + 2;
leavesHeight = random.nextInt(2) + 1;
}
@Override
public boolean canPlaceAt(World world, int sourceX, int sourceY, int sourceZ) {
for (int y = sourceY; y <= sourceY + 1 + height; y++) {
// Space requirement
int radius; // default radius if above first block
if (y - sourceY < leavesHeight) {
radius = 0; // radius is 0 for trunk below leaves
} else {
radius = maxRadius;
}
// check for block collision on horizontal slices
for (int x = sourceX - radius; x <= sourceX + radius; x++) {
for (int z = sourceZ - radius; z <= sourceZ + radius; z++) {
if (y >= 0 && y < 256) {
// we can overlap some blocks around
final Material type = delegate.getBlockState(world, x, y, z).getType();
if (!overridables.contains(type)) {
return false;
}
} else { // height out of range
return false;
}
}
}
}
return true;
}
@Override
public boolean generate(World world, int sourceX, int sourceY, int sourceZ) {
// check height range
if (!canHeightFitAt(sourceY)) {
return false;
}
// check below block
if (!canPlaceOn(world, sourceX, sourceY - 1, sourceZ)) {
return false;
}
// check for sufficient space around
if (!canPlaceAt(world, sourceX, sourceY, sourceZ)) {
return false;
}
// generate the leaves
int radius = random.nextInt(2);
int peakRadius = 1;
int minRadius = 0;
for (int y = sourceY + height; y >= sourceY + leavesHeight; y--) {
// leaves are built from top to bottom
for (int x = sourceX - radius; x <= sourceX + radius; x++) {
for (int z = sourceZ - radius; z <= sourceZ + radius; z++) {
if ((Math.abs(x - sourceX) != radius || Math.abs(z - sourceZ) != radius || radius <= 0) &&
delegate.getBlockState(world, x, y, z).getType() == Material.AIR) {
delegate.setTypeAndRawData(world, x, y, z, Material.LEAVES, 1);
}
}
}
if (radius >= peakRadius) {
radius = minRadius;
minRadius = 1; // after the peak radius is reached once, the min radius increases
peakRadius++; // the peak radius increases each time it's reached
if (peakRadius > maxRadius) {
peakRadius = maxRadius;
}
} else {
radius++;
}
}
// generate the trunk
for (int y = 0; y < height - random.nextInt(3); y++) {
final Material material = delegate.getBlockState(world, sourceX, sourceY + y, sourceZ).getType();
if (material == Material.AIR || material == Material.LEAVES) {
delegate.setTypeAndRawData(world, sourceX, sourceY + y, sourceZ, Material.LOG, 1);
}
}
// block below trunk is always dirt
delegate.setTypeAndRawData(world, sourceX, sourceY - 1, sourceZ, Material.DIRT, 0);
return true;
}
}