diff --git a/src/main/java/biomesoplenty/api/biome/BOPBiomes.java b/src/main/java/biomesoplenty/api/biome/BOPBiomes.java index 553c28155..733bf75c2 100644 --- a/src/main/java/biomesoplenty/api/biome/BOPBiomes.java +++ b/src/main/java/biomesoplenty/api/biome/BOPBiomes.java @@ -40,6 +40,7 @@ public class BOPBiomes public static Optional fungi_forest = Optional.absent(); public static Optional garden = Optional.absent(); public static Optional grassland = Optional.absent(); + public static Optional grove = Optional.absent(); public static Optional heathland = Optional.absent(); public static Optional highland = Optional.absent(); public static Optional jade_cliffs = Optional.absent(); diff --git a/src/main/java/biomesoplenty/common/biome/overworld/BiomeGenGrove.java b/src/main/java/biomesoplenty/common/biome/overworld/BiomeGenGrove.java new file mode 100644 index 000000000..e0852ab9a --- /dev/null +++ b/src/main/java/biomesoplenty/common/biome/overworld/BiomeGenGrove.java @@ -0,0 +1,98 @@ +/******************************************************************************* + * Copyright 2015, the Biomes O' Plenty Team + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International Public License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/4.0/. + ******************************************************************************/ + +package biomesoplenty.common.biome.overworld; + +import net.minecraft.block.BlockDoublePlant; +import net.minecraft.block.BlockPlanks; +import net.minecraft.block.BlockTallGrass; +import net.minecraft.util.BlockPos; +import biomesoplenty.api.biome.BOPBiome; +import biomesoplenty.api.biome.generation.GeneratorStage; +import biomesoplenty.api.biome.generation.GeneratorWeighted; +import biomesoplenty.common.enums.BOPClimates; +import biomesoplenty.common.enums.BOPFlowers; +import biomesoplenty.common.enums.BOPGems; +import biomesoplenty.common.enums.BOPPlants; +import biomesoplenty.common.world.BOPWorldSettings; +import biomesoplenty.common.world.feature.GeneratorDoubleFlora; +import biomesoplenty.common.world.feature.GeneratorFlora; +import biomesoplenty.common.world.feature.GeneratorGrass; +import biomesoplenty.common.world.feature.GeneratorOreSingle; +import biomesoplenty.common.world.feature.tree.GeneratorBush; +import biomesoplenty.common.world.feature.tree.GeneratorProfileTree; + +public class BiomeGenGrove extends BOPBiome +{ + + public BiomeGenGrove() + { + // terrain + this.terrainSettings.avgHeight(66).heightVariation(8, 20).octaves(0, 1, 2, 2, 1, 0).sidewaysNoise(0.1D); + + this.setColor(0x517F51); + this.setTemperatureRainfall(0.7F, 0.8F); + + this.addWeight(BOPClimates.WET_TEMPERATE, 10); + + // other plants + this.addGenerator("sprouts", GeneratorStage.FLOWERS,(new GeneratorFlora.Builder()).amountPerChunk(0.1F).with(BOPPlants.SPROUT).create()); + this.addGenerator("berry_bushes", GeneratorStage.FLOWERS,(new GeneratorFlora.Builder()).amountPerChunk(0.2F).with(BOPPlants.BERRYBUSH).create()); + this.addGenerator("shrubs", GeneratorStage.FLOWERS,(new GeneratorFlora.Builder()).amountPerChunk(0.3F).with(BOPPlants.SHRUB).create()); + this.addGenerator("clover_patches", GeneratorStage.FLOWERS,(new GeneratorFlora.Builder()).amountPerChunk(3.0F).with(BOPPlants.CLOVERPATCH).create()); + this.addGenerator("leaf_piles", GeneratorStage.FLOWERS,(new GeneratorFlora.Builder()).amountPerChunk(0.5F).with(BOPPlants.LEAFPILE).create()); + + // trees + GeneratorWeighted treeGenerator = new GeneratorWeighted(3); + this.addGenerator("trees", GeneratorStage.TREE, treeGenerator); + treeGenerator.add("dark_poplar", 1, (new GeneratorProfileTree.Builder()).minHeight(6).maxHeight(14).log(BlockPlanks.EnumType.DARK_OAK).leaves(BlockPlanks.EnumType.DARK_OAK).profile(GeneratorProfileTree.TreeProfile.POPLAR).create()); + treeGenerator.add("poplar", 1, (new GeneratorProfileTree.Builder()).minHeight(8).maxHeight(18).log(BlockPlanks.EnumType.BIRCH).leaves(BlockPlanks.EnumType.BIRCH).profile(GeneratorProfileTree.TreeProfile.POPLAR).create()); + treeGenerator.add("bush", 1, (new GeneratorBush.Builder()).create()); + + + // flowers + GeneratorWeighted flowerGenerator = new GeneratorWeighted(5.0F); + this.addGenerator("flowers", GeneratorStage.GRASS, flowerGenerator); + flowerGenerator.add("clover", 4, (new GeneratorFlora.Builder().with(BOPFlowers.CLOVER).create())); + flowerGenerator.add("white_anemones", 2, (new GeneratorFlora.Builder().with(BOPFlowers.WHITE_ANEMONE).create())); + flowerGenerator.add("paeonias", 1, (new GeneratorDoubleFlora.Builder()).with(BlockDoublePlant.EnumPlantType.PAEONIA).create()); + + // grasses + GeneratorWeighted grassGenerator = new GeneratorWeighted(2.0F); + this.addGenerator("grass", GeneratorStage.GRASS, grassGenerator); + grassGenerator.add("mediumgrass", 2, (new GeneratorGrass.Builder()).with(BOPPlants.MEDIUMGRASS).create()); + grassGenerator.add("wheatgrass", 1, (new GeneratorGrass.Builder()).with(BOPPlants.WHEATGRASS).create()); + grassGenerator.add("dampgrass", 1, (new GeneratorGrass.Builder()).with(BOPPlants.DAMPGRASS).create()); + grassGenerator.add("tallgrass", 1, (new GeneratorGrass.Builder()).with(BlockTallGrass.EnumType.GRASS).create()); + + // gem + this.addGenerator("amber", GeneratorStage.SAND, (new GeneratorOreSingle.Builder()).amountPerChunk(12).with(BOPGems.AMBER).create()); + + } + + @Override + public void applySettings(BOPWorldSettings settings) + { + if (!settings.generateBopGems) {this.removeGenerator("amber");} + } + + @Override + public int getGrassColorAtPos(BlockPos pos) + { + double noise = field_180281_af.func_151601_a((double)pos.getX() * 0.0225D, (double)pos.getZ() * 0.0225D); + return noise < -0.1D ? 0x517F51 : 0x609E58; + } + + @Override + public int getFoliageColorAtPos(BlockPos pos) + { + double noise = field_180281_af.func_151601_a((double)pos.getX() * 0.0225D, (double)pos.getZ() * 0.0225D); + return noise < -0.1D ? 0x619961 : 0x75B569; + } + +} diff --git a/src/main/java/biomesoplenty/common/block/BlockBOPLeaves.java b/src/main/java/biomesoplenty/common/block/BlockBOPLeaves.java index 496e895e4..805a0768b 100644 --- a/src/main/java/biomesoplenty/common/block/BlockBOPLeaves.java +++ b/src/main/java/biomesoplenty/common/block/BlockBOPLeaves.java @@ -12,7 +12,6 @@ import java.util.List; import java.util.Random; import biomesoplenty.api.block.IBOPBlock; -import biomesoplenty.common.block.BlockBOPDoubleDecoration.Half; import biomesoplenty.common.enums.BOPTrees; import biomesoplenty.common.item.ItemBOPBlock; import biomesoplenty.common.util.block.VariantPagingHelper; diff --git a/src/main/java/biomesoplenty/common/init/ModBiomes.java b/src/main/java/biomesoplenty/common/init/ModBiomes.java index 20b11e5c4..a12ea67bc 100644 --- a/src/main/java/biomesoplenty/common/init/ModBiomes.java +++ b/src/main/java/biomesoplenty/common/init/ModBiomes.java @@ -165,6 +165,7 @@ public class ModBiomes fungi_forest = registerBOPBiome(new BiomeGenFungiForest(), "Fungi Forest"); garden = registerBOPBiome(new BiomeGenGarden(), "Garden"); grassland = registerBOPBiome(new BiomeGenGrassland(), "Grassland"); + grove = registerBOPBiome(new BiomeGenGrove(), "Grove"); heathland = registerBOPBiome(new BiomeGenHeathland(), "Heathland"); highland = registerBOPBiome(new BiomeGenHighland(), "Highland"); jade_cliffs = registerBOPBiome(new BiomeGenJadeCliffs(), "Jade Cliffs"); diff --git a/src/main/java/biomesoplenty/common/init/ModGenerators.java b/src/main/java/biomesoplenty/common/init/ModGenerators.java index 432d28c3a..1d1c1967c 100644 --- a/src/main/java/biomesoplenty/common/init/ModGenerators.java +++ b/src/main/java/biomesoplenty/common/init/ModGenerators.java @@ -29,6 +29,7 @@ public class ModGenerators registerGenerator("mega_jungle_tree", GeneratorMegaJungleTree.class, new GeneratorMegaJungleTree.Builder()); registerGenerator("bayou_tree", GeneratorBayouTree.class, new GeneratorBayouTree.Builder()); registerGenerator("taiga_tree", GeneratorTaigaTree.class, new GeneratorTaigaTree.Builder()); + registerGenerator("profile_tree", GeneratorProfileTree.class, new GeneratorProfileTree.Builder()); registerGenerator("flora", GeneratorFlora.class, new GeneratorFlora.Builder()); registerGenerator("double_flora", GeneratorDoubleFlora.class, new GeneratorDoubleFlora.Builder()); registerGenerator("grass", GeneratorGrass.class, new GeneratorGrass.Builder()); diff --git a/src/main/java/biomesoplenty/common/world/feature/tree/GeneratorProfileTree.java b/src/main/java/biomesoplenty/common/world/feature/tree/GeneratorProfileTree.java new file mode 100644 index 000000000..3c46849bd --- /dev/null +++ b/src/main/java/biomesoplenty/common/world/feature/tree/GeneratorProfileTree.java @@ -0,0 +1,174 @@ +/******************************************************************************* + * Copyright 2015, the Biomes O' Plenty Team + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International Public License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/4.0/. + ******************************************************************************/ + +package biomesoplenty.common.world.feature.tree; + +import java.util.Random; + +import net.minecraft.block.state.IBlockState; +import net.minecraft.init.Blocks; +import net.minecraft.util.BlockPos; +import net.minecraft.world.World; +import biomesoplenty.api.block.BlockQueries; +import biomesoplenty.common.util.biome.GeneratorUtils; +import biomesoplenty.common.util.block.BlockQuery.*; +import biomesoplenty.common.util.config.BOPConfig.IConfigObj; + +public class GeneratorProfileTree extends GeneratorTreeBase +{ + + public static class Builder extends GeneratorTreeBase.InnerBuilder implements IGeneratorBuilder + { + protected TreeProfile profile; + + public Builder profile(TreeProfile a) {this.profile = a; return this.self();} + + public Builder() + { + this.amountPerChunk = 1.0F; + this.minHeight = 6; + this.maxHeight = 12; + this.placeOn = BlockQueries.fertile; + this.replace = BlockQueries.airOrLeaves; + this.log = Blocks.log.getDefaultState(); + this.leaves = Blocks.leaves.getDefaultState(); + this.vine = null; + this.profile = TreeProfile.POPLAR; + } + + @Override + public GeneratorProfileTree create() { + return new GeneratorProfileTree(this.amountPerChunk, this.placeOn, this.replace, this.log, this.leaves, this.vine, this.minHeight, this.maxHeight, this.profile); + } + + } + + protected TreeProfile profile; + + public GeneratorProfileTree(float amountPerChunk, IBlockPosQuery placeOn, IBlockPosQuery replace, IBlockState log, IBlockState leaves, IBlockState vine, int minHeight, int maxHeight, TreeProfile profile) + { + super(amountPerChunk, placeOn, replace, log, leaves, vine, minHeight, maxHeight); + this.profile = profile; + } + + public static enum TreeProfile + { + POPLAR; + + public int radius(int height, int maxHeight) + { + switch (this) + { + case POPLAR: default: + float x = (float)height / (float)maxHeight; + float maxRadius = 1.0F + maxHeight * 0.10F; + // this function creates a curved profile which has its widest point 1/4 from the bottom and a pointy top + float r = maxRadius * 0.6667F * x * (1/(x*x + 0.08173F) - 0.9244F); + return (int)(r + 0.5F); + } + } + } + + + @Override + public boolean generate(World world, Random random, BlockPos pos) + { + + // Move down until we reach the ground + while (pos.getY() > 1 && world.isAirBlock(pos) || world.getBlockState(pos).getBlock().isLeaves(world, pos)) {pos = pos.down();} + + if (!this.placeOn.matches(world, pos)) + { + // Abandon if we can't place the tree on this block + return false; + } + + // Choose heights and width + int height = GeneratorUtils.nextIntBetween(random, this.minHeight, this.maxHeight); + if (height < 4) {return false;} + int baseHeight = height / (2 + random.nextInt(3)); + int leavesHeight = height - baseHeight; + + // Move up to space above ground + pos = pos.up(); + + if (!this.checkSpace(world, pos, baseHeight, height)) + { + // Abandon if there isn't enough room + return false; + } + + // Generate bottom of tree (trunk only) + for(int i = 0; i < baseHeight; i++) + { + this.setLog(world, pos); + pos = pos.up(); + } + + // Generate middle of the tree + for(int i = 0; i < leavesHeight; i++) + { + int radius = this.profile.radius(i, leavesHeight); + this.generateLeafLayer(world, pos, radius); + if (leavesHeight - i > 2) {this.setLog(world, pos);} + pos = pos.up(); + } + + return true; + } + + public boolean checkSpace(World world, BlockPos pos, int baseHeight, int height) + { + for (int y = 0; y <= height; y++) + { + // require 3x3 for the leaves, 1x1 for the trunk + int radius = (y <= baseHeight ? 0 : 1); + for (int x = -radius; x <= radius; x++) + { + for (int z = -radius; z <= radius; z++) + { + BlockPos pos1 = pos.add(x, y, z); + // note, there may be a sapling on the first layer - make sure this.replace matches it! + if (pos1.getY() >= 255 || !this.replace.matches(world, pos1)) + { + return false; + } + } + } + } + return true; + } + + // generates a layer of leafs with the given radius + public void generateLeafLayer(World world, BlockPos pos, int radius) + { + for(int x = -radius; x <= radius; x++) + { + for(int z = -radius; z <= radius; z++) + { + if (x*x + z*z <= radius*radius) + { + this.setLeaves(world, pos.add(x, 0, z)); + } + } + } + } + + @Override + public void configure(IConfigObj conf) + { + this.amountPerChunk = conf.getFloat("amountPerChunk", this.amountPerChunk); + this.minHeight = conf.getInt("minHeight", this.minHeight); + this.maxHeight = conf.getInt("minHeight", this.maxHeight); + this.placeOn = conf.getBlockPosQuery("placeOn", this.placeOn); + this.replace = conf.getBlockPosQuery("replace", this.replace); + this.log = conf.getBlockState("logState", this.log); + this.leaves = conf.getBlockState("leavesState", this.leaves); + this.profile = conf.getEnum("profile", this.profile, TreeProfile.class); + } +} \ No newline at end of file