/* * To change this template, choose Tools | Templates * and open the template in the editor. */ package org.pepsoft.worldpainter.layers.trees; import org.pepsoft.minecraft.Direction; import org.pepsoft.minecraft.Material; import org.pepsoft.util.MathUtils; import org.pepsoft.worldpainter.Dimension; import org.pepsoft.worldpainter.exporting.Cursor; import org.pepsoft.worldpainter.exporting.MinecraftWorld; import java.util.Random; import static org.pepsoft.minecraft.Block.BLOCKS; import static org.pepsoft.minecraft.Constants.*; import static org.pepsoft.minecraft.Direction.*; import static org.pepsoft.minecraft.Material.*; /** * * @author pepijn */ public class JungleTree extends TreeType { public JungleTree() { super(WOOD_JUNGLE, LEAVES_JUNGLE); } @Override public void renderTree(int x, int y, int height, int strength, MinecraftWorld world, Dimension dimension, Random random) { int size = (int) (random.nextInt(strength) + Math.pow(random.nextDouble(), 4) * strength * 3 + 0.5); if ((height + size) >= world.getMaxHeight()) { // Tree won't fit under the sky return; } renderTrunk(x, y, height, size, world); if (size < 12) { renderCanopy(x, y, height, size, world, random); } else if (size < 32) { renderCanopy(x, y, height, size, world, random); renderCanopy(x + 1, y, height, size, world, random); renderCanopy(x, y + 1, height, size, world, random); renderCanopy(x + 1, y + 1, height, size, world, random); } else { renderCanopy(x - 1, y, height, size, world, random); renderCanopy(x + 1, y - 1, height, size, world, random); renderCanopy(x + 2, y + 1, height, size, world, random); renderCanopy(x , y + 2, height, size, world, random); } for (int i = 0; i < size / 10 + 1; i++) { renderBranch(x, y, height, size, (float) (random.nextDouble() * Math.PI * 2), world, random); } for (int z = 4; z < size - 2; z++) { if (random.nextInt(5) == 0) { renderBranch(x, y, height, z, (float) (random.nextDouble() * Math.PI * 2), world, random); } } if (size >= 24) { for (int i = 0; i < size / 10 + 1; i++) { renderRoot(x, y, height, size, (float) (random.nextDouble() * Math.PI * 2), world, random); } } renderVines(x, y, height, size, world, random, VINE_INCIDENCE, 5, 5); if ((size < 12) && (random.nextInt(5) == 0)) { renderCocoaPods(x, y, height, size, world, random); } } private void renderRoot(int x, int y, int height, int size, float angle, MinecraftWorld world, Random random) { int h = (int) (size / 5f + 0.5f); Material capMaterial = getCapMaterial(); int i = 1, maxDepth = -1; int previousDx = Integer.MIN_VALUE, previousDy = Integer.MIN_VALUE; while (h > 0) { int dx = (int) (Math.sin(angle) * i + 0.5f); int dy = (int) (Math.cos(angle) * i + 0.5f); if ((dx == previousDx) && (dy == previousDy)) { i++; continue; } else { previousDx = dx; previousDy = dy; } int worldX = x + dx, worldY = y + dy; int depth = 0; for (int z = height + h; z > 0; z--) { if (! BLOCKS[world.getBlockTypeAt(worldX, worldY, z)].veryInsubstantial) { depth++; } world.setMaterialAt(worldX, worldY, z, (z < (height + h)) ? trunkMaterial : capMaterial); if (depth > maxDepth) { break; } } if (random.nextInt(15) == 0) { world.setMaterialAt(worldX, worldY, height + h + 1, random.nextBoolean() ? RED_MUSHROOM : BROWN_MUSHROOM); // System.out.println("Rendered mushroom @ " + worldX + "," + worldY + "," + (height + h + 1)); } h -= (random.nextInt(2) + 1); i++; maxDepth++; } } @Override protected void renderTrunk(int blockInWorldX, int blockInWorldY, int height, int size, MinecraftWorld minecraftWorld) { if (size < 12) { super.renderTrunk(blockInWorldX, blockInWorldY, height, size, minecraftWorld); } else if (size < 32) { minecraftWorld.setMaterialAt(blockInWorldX, blockInWorldY, height, DIRT); minecraftWorld.setMaterialAt(blockInWorldX + 1, blockInWorldY, height, DIRT); minecraftWorld.setMaterialAt(blockInWorldX, blockInWorldY + 1, height, DIRT); minecraftWorld.setMaterialAt(blockInWorldX + 1, blockInWorldY + 1, height, DIRT); for (int i = 1; i < size; i++) { minecraftWorld.setMaterialAt(blockInWorldX, blockInWorldY, height + i, trunkMaterial); minecraftWorld.setMaterialAt(blockInWorldX + 1, blockInWorldY, height + i, trunkMaterial); minecraftWorld.setMaterialAt(blockInWorldX, blockInWorldY + 1, height + i, trunkMaterial); minecraftWorld.setMaterialAt(blockInWorldX + 1, blockInWorldY + 1, height + i, trunkMaterial); } Material capMaterial = getCapMaterial(); minecraftWorld.setMaterialAt(blockInWorldX, blockInWorldY, height + size, capMaterial); minecraftWorld.setMaterialAt(blockInWorldX + 1, blockInWorldY, height + size, capMaterial); minecraftWorld.setMaterialAt(blockInWorldX, blockInWorldY + 1, height + size, capMaterial); minecraftWorld.setMaterialAt(blockInWorldX + 1, blockInWorldY + 1, height + size, capMaterial); } else { Material capMaterial = getCapMaterial(); for (int dx = -1; dx < 3; dx++) { for (int dy = -1; dy < 3; dy++) { if (((dx == -1) || (dx == 2)) && ((dy == -1) || (dy == 2))) { continue; } minecraftWorld.setMaterialAt(blockInWorldX + dx, blockInWorldY + dy, height, DIRT); for (int i = 1; i < size; i++) { minecraftWorld.setMaterialAt(blockInWorldX + dx, blockInWorldY + dy, height + i, trunkMaterial); } minecraftWorld.setMaterialAt(blockInWorldX + dx, blockInWorldY + dy, height + size, capMaterial); } } } } protected void renderCanopy(int x, int y, int height, int size, MinecraftWorld world, Random random) { final int r = Math.max(Math.min(size, 4), 2); int maxZ = world.getMaxHeight() - 1; for (int z = Math.max(size - r, 1); z <= size + r; z++) { // z includes the +1 due to height referring to the block // *underneath* the tree if (height + z > maxZ) { break; } float distance = Math.abs(z - size) * 2; maybePlaceLeaves(x, y, height + z, r, distance, world, random); int maxDistance = Math.min(4 - Math.abs(z - size), r); // if (z > size) { // System.out.print("+"); // } else { // System.out.print("-"); // } for (int d = 1; d <= maxDistance; d++) { for (int i = 0; i < d; i++) { distance = (int) (MathUtils.getDistance(d - i, i, (z - size) * 2) + 0.5f); // System.out.printf("%.1f", distance); maybePlaceLeaves(x - d + i, y - i, height +z, r, distance + random.nextInt(2), world, random); maybePlaceLeaves(x + i, y - d + i, height + z, r, distance + random.nextInt(2), world, random); maybePlaceLeaves(x + d - i, y + i, height + z, r, distance + random.nextInt(2), world, random); maybePlaceLeaves(x - i, y + d - i, height + z, r, distance + random.nextInt(2), world, random); } } } // System.out.println(); } protected void renderBranch(int x, int y, int height, int size, float angle, MinecraftWorld world, Random random) { int l = (int) (size / 5f + 0.5f); Material branchMaterial, capMaterial; if ((trunkMaterial.blockType == BLK_WOOD) || (trunkMaterial.blockType == BLK_WOOD2)) { branchMaterial = ((angle < (0.25 * Math.PI)) || ((angle > (0.75 * Math.PI)) && (angle < (1.25 * Math.PI))) || (angle > (1.75 * Math.PI))) ? Material.get(trunkMaterial.blockType, (trunkMaterial.data & 0x3) | 0x8) : Material.get(trunkMaterial.blockType, (trunkMaterial.data & 0x3) | 0x4); capMaterial = getCapMaterial(); } else { branchMaterial = capMaterial = trunkMaterial; } float slope = random.nextFloat() / 10 - 0.5f; for (int i = 1; i < l; i++) { int dx = (int) (Math.sin(angle) * i + 0.5f); int dy = (int) (Math.cos(angle) * i + 0.5f); int dz = (int) (i * slope); if (! BLOCKS[world.getBlockTypeAt(x + dx, y + dy, height + size + dz + 1)].veryInsubstantial) { continue; } world.setMaterialAt(x + dx, y + dy, height + size + dz, (i < (l - 1)) ? branchMaterial : capMaterial); if (random.nextInt(25) == 0) { world.setMaterialAt(x + dx, y + dy, height + size + dz + 1, random.nextBoolean() ? RED_MUSHROOM : BROWN_MUSHROOM); } if (((i > 1) && (((i - 1) % 3) == 0)) || (i == (l - 1))) { renderCanopy(x + dx, y + dy, height + dz, size, world, random); } } } @Override protected void maybePlaceLeaves(int x, int y, int h, int r, float distance, MinecraftWorld minecraftWorld, Random random) { if (minecraftWorld.getBlockTypeAt(x, y, h) == BLK_AIR) { if (distance <= r) { minecraftWorld.setMaterialAt(x, y, h, leafMaterial); } } } protected void renderCocoaPods(int x, int y, int height, int size, MinecraftWorld world, Random random) { if (size < 12) { renderCocoaPods(x - 1, y, height, size, world, random, EAST); renderCocoaPods(x, y - 1, height, size, world, random, SOUTH); renderCocoaPods(x + 1, y, height, size, world, random, WEST); renderCocoaPods(x, y + 1, height, size, world, random, NORTH); } else if (size < 32) { renderCocoaPods(x - 1, y, height, size, world, random, EAST); renderCocoaPods(x - 1, y + 1, height, size, world, random, EAST); renderCocoaPods(x, y - 1, height, size, world, random, SOUTH); renderCocoaPods(x + 1, y - 1, height, size, world, random, SOUTH); renderCocoaPods(x + 2, y, height, size, world, random, WEST); renderCocoaPods(x + 2, y + 1, height, size, world, random, WEST); renderCocoaPods(x, y + 2, height, size, world, random, NORTH); renderCocoaPods(x + 1, y + 2, height, size, world, random, NORTH); } } protected void renderCocoaPods(int x, int y, int height, int size, MinecraftWorld world, Random random, Direction direction) { Cursor cursor = new Cursor(world, x, y, height + 1, direction); for (int i = 0; i < size; i++) { if ((random.nextInt(15) == 0) && cursor.isFreeOrInsubstantial()) { // System.out.println("Placing cocoa plant @ " + cursor.getX() + "," + cursor.getY() + "," + cursor.getHeight()); cursor.setBlockWithDirection(COCOA_PODS[random.nextInt(3)]); } cursor.up(); } } private static final int VINE_INCIDENCE = 3; private static final Material[] COCOA_PODS = {COCOA_PLANT, COCOA_PLANT_HALF_RIPE, COCOA_PLANT_RIPE}; private static final long serialVersionUID = 1L; }