package net.glowstone.block.blocktype;
import net.glowstone.EventFactory;
import net.glowstone.block.GlowBlock;
import net.glowstone.block.GlowBlockState;
import net.glowstone.entity.GlowPlayer;
import org.bukkit.CropState;
import org.bukkit.Material;
import org.bukkit.block.BlockFace;
import org.bukkit.event.block.BlockGrowEvent;
import org.bukkit.inventory.ItemStack;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
public class BlockCrops extends BlockNeedsAttached implements IBlockGrowable {
@Override
public boolean canPlaceAt(GlowBlock block, BlockFace against) {
if (block.getRelative(BlockFace.DOWN).getType() == Material.SOIL) {
return true;
}
return false;
}
@Override
public Collection<ItemStack> getDrops(GlowBlock block, ItemStack tool) {
if (block.getData() >= CropState.RIPE.ordinal()) {
return Collections.unmodifiableList(Arrays.asList(new ItemStack(Material.SEEDS, random.nextInt(4)),
new ItemStack(Material.WHEAT, 1)));
} else {
return Collections.unmodifiableList(Arrays.asList(new ItemStack(Material.SEEDS, 1)));
}
}
@Override
public boolean isFertilizable(GlowBlock block) {
return block.getData() != CropState.RIPE.ordinal();
}
@Override
public boolean canGrowWithChance(GlowBlock block) {
return true;
}
@Override
public void grow(GlowPlayer player, GlowBlock block) {
final GlowBlockState state = block.getState();
int cropState = block.getData()
+ (random.nextInt(CropState.MEDIUM.ordinal())
+ CropState.VERY_SMALL.ordinal());
if (cropState > CropState.RIPE.ordinal()) {
cropState = CropState.RIPE.ordinal();
}
state.setRawData((byte) cropState);
BlockGrowEvent growEvent = new BlockGrowEvent(block, state);
EventFactory.callEvent(growEvent);
if (!growEvent.isCancelled()) {
state.update(true);
}
}
@Override
public boolean canTickRandomly() {
return true;
}
@Override
public void updateBlock(GlowBlock block) {
final GlowBlockState state = block.getState();
int cropState = block.getData();
// we check light level on the above block, meaning crops needs at least one free block above it
// in order to grow naturally (vanilla behavior)
if (cropState < CropState.RIPE.ordinal() && block.getRelative(BlockFace.UP).getLightLevel() >= 9 &&
random.nextInt((int) (25.0F / getGrowthRateModifier(block)) + 1) == 0) {
cropState++;
if (cropState > CropState.RIPE.ordinal()) {
cropState = CropState.RIPE.ordinal();
}
state.setRawData((byte) cropState);
BlockGrowEvent growEvent = new BlockGrowEvent(block, state);
EventFactory.callEvent(growEvent);
if (!growEvent.isCancelled()) {
state.update(true);
}
}
// we check for insufficient light on the block itself, then drop
if (block.getLightLevel() < 8) {
block.breakNaturally();
}
}
protected float getGrowthRateModifier(GlowBlock block) {
float modifier = 1;
// check for soil around (increase the chance modifier to 10 in the best conditions)
for (int x = -1; x <= 1; x++) {
for (int z = -1; z <= 1; z++) {
final GlowBlock b = block.getWorld().getBlockAt(block.getX() + x, block.getY() - 1, block.getZ() + z);
float soilBonus = 0;
if (b.getType() == Material.SOIL) {
soilBonus = 1;
// check if soil is wet for more bonus
if (b.getData() > 0) {
soilBonus = 3;
}
// more chances if the soil the crop is planted on is wet
if (x != 0 || z != 0) {
soilBonus /= 4.0F;
}
}
// this will add 0.25 points for dry soil around, 0.75 points for wet soil around
// and 1 point for dry soil under the stem, 3 points for wet soil under stem
modifier += soilBonus;
}
}
// check for crops around, decrease chances by 50% if a crop of the same type is found on
// both NS and EW axis, or a crop is found on a diagonal block
boolean cropOnDiagonalBlock = false;
boolean cropOnNorthOrSouth = false;
boolean cropOnEastOrWest = false;
for (int x = -1; x <= 1; x++) {
for (int z = -1; z <= 1; z++) {
if (x != 0 || z != 0) {
if (block.getWorld().getBlockAt(block.getX() + x, block.getY(), block.getZ() + z).getType() == getMaterial()) {
if (x != 0 && z != 0) {
cropOnDiagonalBlock = true;
} else if (x == 0 && z != 0) {
cropOnNorthOrSouth = true;
} else if (x != 0 && z == 0) {
cropOnEastOrWest = true;
}
}
}
}
}
if ((cropOnNorthOrSouth && cropOnEastOrWest) || cropOnDiagonalBlock) {
return modifier / 2.0F;
}
return modifier;
}
}