2020-04-15 14:22:03 +02:00
|
|
|
package com.minelittlepony.unicopia.block;
|
2019-03-02 17:45:28 +01:00
|
|
|
|
|
|
|
import java.util.Random;
|
|
|
|
|
2020-04-15 14:22:03 +02:00
|
|
|
import com.minelittlepony.unicopia.EquinePredicates;
|
|
|
|
import com.minelittlepony.unicopia.USounds;
|
|
|
|
import com.minelittlepony.unicopia.util.MagicalDamageSource;
|
|
|
|
import com.minelittlepony.unicopia.util.PosHelper;
|
2019-03-02 17:45:28 +01:00
|
|
|
|
2020-04-16 00:30:04 +02:00
|
|
|
import net.fabricmc.fabric.api.block.FabricBlockSettings;
|
2019-03-02 17:45:28 +01:00
|
|
|
import net.minecraft.block.Block;
|
2020-04-16 00:30:04 +02:00
|
|
|
import net.minecraft.block.BlockRenderLayer;
|
2020-01-16 12:35:46 +01:00
|
|
|
import net.minecraft.block.BlockState;
|
2019-03-02 17:45:28 +01:00
|
|
|
import net.minecraft.entity.Entity;
|
2020-04-16 00:30:04 +02:00
|
|
|
import net.minecraft.entity.EntityContext;
|
2020-01-16 12:35:46 +01:00
|
|
|
import net.minecraft.entity.LivingEntity;
|
2020-04-16 00:30:04 +02:00
|
|
|
import net.minecraft.entity.player.PlayerEntity;
|
2019-03-03 23:33:40 +01:00
|
|
|
import net.minecraft.item.ItemStack;
|
2020-04-16 00:30:04 +02:00
|
|
|
import net.minecraft.item.Items;
|
|
|
|
import net.minecraft.nbt.CompoundTag;
|
2020-01-16 12:35:46 +01:00
|
|
|
import net.minecraft.particle.ParticleTypes;
|
2020-04-16 00:30:04 +02:00
|
|
|
import net.minecraft.sound.BlockSoundGroup;
|
2020-04-15 14:22:03 +02:00
|
|
|
import net.minecraft.sound.SoundCategory;
|
2020-04-16 00:30:04 +02:00
|
|
|
import net.minecraft.state.StateFactory;
|
2020-01-16 12:35:46 +01:00
|
|
|
import net.minecraft.state.property.EnumProperty;
|
|
|
|
import net.minecraft.state.property.IntProperty;
|
|
|
|
import net.minecraft.util.StringIdentifiable;
|
2020-04-16 00:30:04 +02:00
|
|
|
import net.minecraft.util.TagHelper;
|
2020-01-16 12:35:46 +01:00
|
|
|
import net.minecraft.util.math.Box;
|
2020-04-16 00:30:04 +02:00
|
|
|
import net.minecraft.util.math.Direction;
|
2019-03-02 17:45:28 +01:00
|
|
|
import net.minecraft.util.math.BlockPos;
|
|
|
|
import net.minecraft.util.math.Vec3d;
|
2020-04-16 00:30:04 +02:00
|
|
|
import net.minecraft.util.shape.VoxelShape;
|
2020-01-16 12:35:46 +01:00
|
|
|
import net.minecraft.world.BlockView;
|
2020-04-16 00:30:04 +02:00
|
|
|
import net.minecraft.world.ViewableWorld;
|
2019-03-02 17:45:28 +01:00
|
|
|
import net.minecraft.world.World;
|
|
|
|
|
|
|
|
public class BlockGrowingCuccoon extends Block {
|
|
|
|
|
2020-01-16 12:35:46 +01:00
|
|
|
public static final IntProperty AGE = IntProperty.of("age", 0, 7);
|
|
|
|
public static final EnumProperty<Shape> SHAPE = EnumProperty.of("shape", Shape.class);
|
2019-03-02 17:45:28 +01:00
|
|
|
|
2020-04-16 00:30:04 +02:00
|
|
|
public static final VoxelShape[] SHAFTS = new VoxelShape[] {
|
|
|
|
Block.createCuboidShape(7, 0, 7, 9, 16, 7),
|
|
|
|
Block.createCuboidShape(6, 0, 6, 10, 16, 10),
|
|
|
|
Block.createCuboidShape(5, 0, 5, 11, 16, 11),
|
|
|
|
Block.createCuboidShape(4, 0, 4, 12, 16, 12)
|
2019-03-02 17:45:28 +01:00
|
|
|
};
|
2020-04-16 00:30:04 +02:00
|
|
|
public static final VoxelShape[] BULBS = new VoxelShape[] {
|
|
|
|
Block.createCuboidShape(6, 1, 6, 10, 8, 10),
|
|
|
|
Block.createCuboidShape(4, 0, 4, 12, 9, 12),
|
|
|
|
Block.createCuboidShape(3, 0, 3, 13, 10, 13),
|
|
|
|
Block.createCuboidShape(2, 0, 2, 14, 12, 14),
|
2019-03-02 17:45:28 +01:00
|
|
|
};
|
|
|
|
|
2020-04-16 00:30:04 +02:00
|
|
|
@SuppressWarnings("deprecation")
|
2020-01-27 17:37:22 +01:00
|
|
|
public BlockGrowingCuccoon() {
|
2020-04-16 00:30:04 +02:00
|
|
|
super(FabricBlockSettings.of(UMaterials.HIVE)
|
|
|
|
.ticksRandomly()
|
|
|
|
.breakInstantly()
|
|
|
|
.lightLevel(9)
|
|
|
|
.slipperiness(0.5F)
|
|
|
|
.sounds(BlockSoundGroup.SLIME)
|
|
|
|
.breakByTool(net.fabricmc.fabric.api.tools.FabricToolTags.SHOVELS, 2)
|
|
|
|
.build()
|
|
|
|
);
|
|
|
|
|
|
|
|
setDefaultState(stateFactory.getDefaultState()
|
2020-01-16 12:35:46 +01:00
|
|
|
.with(AGE, 0)
|
|
|
|
.with(SHAPE, Shape.BULB));
|
2019-03-02 17:45:28 +01:00
|
|
|
}
|
|
|
|
|
2020-04-16 00:30:04 +02:00
|
|
|
// TODO: loot table
|
|
|
|
/*
|
2019-03-02 17:45:28 +01:00
|
|
|
@Override
|
2020-04-16 00:30:04 +02:00
|
|
|
public int quantityDropped(BlockState state, int fortune, Random random) {
|
|
|
|
return random.nextInt(3) == 0 ? state.get(AGE) : 0;
|
2019-03-02 17:45:28 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2020-04-16 00:30:04 +02:00
|
|
|
public Item getItemDropped(BlockState state, Random rand, int fortune) {
|
|
|
|
return Items.SLIME_BALL;
|
|
|
|
}*/
|
2019-03-02 17:45:28 +01:00
|
|
|
|
|
|
|
@Override
|
2020-04-16 00:30:04 +02:00
|
|
|
public boolean isTranslucent(BlockState state, BlockView view, BlockPos pos) {
|
|
|
|
return true;
|
2019-03-02 17:45:28 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public BlockRenderLayer getRenderLayer() {
|
|
|
|
return BlockRenderLayer.TRANSLUCENT;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2020-04-16 00:30:04 +02:00
|
|
|
public Block.OffsetType getOffsetType() {
|
|
|
|
return Block.OffsetType.XZ;
|
2019-03-02 17:45:28 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2020-04-16 00:30:04 +02:00
|
|
|
public void onScheduledTick(BlockState state, World world, BlockPos pos, Random rand) {
|
2019-03-02 17:45:28 +01:00
|
|
|
if (!checkSupport(world, pos)) {
|
2019-03-02 18:18:29 +01:00
|
|
|
breakConnected(world, pos);
|
2019-03-02 17:45:28 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-01-16 12:35:46 +01:00
|
|
|
int age = state.get(AGE);
|
2019-03-02 17:45:28 +01:00
|
|
|
|
|
|
|
BlockPos below = pos.down();
|
|
|
|
|
|
|
|
if (world.isBlockLoaded(below)) {
|
2020-04-15 14:22:03 +02:00
|
|
|
boolean spaceBelow = world.isAir(below);
|
2019-03-02 17:45:28 +01:00
|
|
|
|
2020-01-16 12:35:46 +01:00
|
|
|
Shape shape = state.get(SHAPE);
|
2019-03-02 17:45:28 +01:00
|
|
|
|
|
|
|
if (shape == Shape.STRING && spaceBelow) {
|
2020-01-16 12:35:46 +01:00
|
|
|
world.setBlockState(pos, state.with(SHAPE, Shape.BULB).with(AGE, age / 2));
|
2019-03-02 17:45:28 +01:00
|
|
|
} else if (shape == Shape.BULB && !spaceBelow) {
|
2020-01-16 12:35:46 +01:00
|
|
|
world.setBlockState(pos, state.with(SHAPE, Shape.STRING).with(AGE, age / 2));
|
2019-03-02 17:45:28 +01:00
|
|
|
} else if (age >= 7) {
|
|
|
|
if (rand.nextInt(12) == 0 && spaceBelow) {
|
2020-01-16 12:35:46 +01:00
|
|
|
world.setBlockState(below, state.with(AGE, age / 2));
|
|
|
|
world.setBlockState(pos, getDefaultState().with(AGE, age / 2).with(SHAPE, Shape.STRING));
|
2019-03-02 17:45:28 +01:00
|
|
|
world.playSound(null, pos, USounds.SLIME_ADVANCE, SoundCategory.BLOCKS, 1, 1);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (age < getMaximumAge(world, pos, state, spaceBelow)) {
|
|
|
|
if (rand.nextInt(5 * (age + 1)) == 0) {
|
2020-04-15 14:22:03 +02:00
|
|
|
world.setBlockState(pos, state.cycle(AGE));
|
2019-03-02 17:45:28 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-02 18:18:29 +01:00
|
|
|
protected void breakConnected(World world, BlockPos pos) {
|
2020-04-16 00:30:04 +02:00
|
|
|
world.breakBlock(pos, true);
|
2019-03-02 18:18:29 +01:00
|
|
|
|
|
|
|
pos = pos.down();
|
|
|
|
if (world.getBlockState(pos).getBlock() == this) {
|
|
|
|
breakConnected(world, pos);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-16 16:46:24 +01:00
|
|
|
protected int getMaximumAge(World world, BlockPos pos, BlockState state, boolean spaceBelow) {
|
2020-01-16 12:35:46 +01:00
|
|
|
if (state.get(SHAPE) == Shape.STRING) {
|
2020-01-16 16:46:24 +01:00
|
|
|
BlockState higher = world.getBlockState(pos.up());
|
2019-03-02 17:45:28 +01:00
|
|
|
|
|
|
|
if (higher.getBlock() != this) {
|
|
|
|
return 7;
|
|
|
|
}
|
|
|
|
|
2020-01-16 12:35:46 +01:00
|
|
|
return Math.min(higher.get(AGE),
|
2019-03-02 18:18:29 +01:00
|
|
|
((BlockGrowingCuccoon)higher.getBlock()).getMaximumAge(world, pos.up(), higher, false) - 1
|
|
|
|
);
|
2019-03-02 17:45:28 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!spaceBelow) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 7;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2020-04-16 00:30:04 +02:00
|
|
|
public boolean canPlaceAt(BlockState state, ViewableWorld world, BlockPos pos) {
|
|
|
|
return super.canPlaceAt(state, world, pos) && checkSupport(world, pos);
|
2019-03-02 17:45:28 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2020-04-16 00:30:04 +02:00
|
|
|
public void neighborUpdate(BlockState state, World world, BlockPos pos, Block otherBlock, BlockPos otherPos, boolean change) {
|
|
|
|
super.neighborUpdate(state, world, pos, otherBlock, otherPos, change);
|
|
|
|
if (!checkSupport(world, pos)) {
|
|
|
|
breakConnected(world, pos);
|
2019-03-02 17:45:28 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2020-04-16 00:30:04 +02:00
|
|
|
public void onBlockRemoved(BlockState state, World world, BlockPos pos, BlockState replacement, boolean boolean_1) {
|
|
|
|
world.updateNeighborsAlways(pos, this);
|
|
|
|
super.onBlockRemoved(state, world, pos, replacement, boolean_1);
|
2019-03-02 17:45:28 +01:00
|
|
|
}
|
|
|
|
|
2019-03-03 23:33:40 +01:00
|
|
|
@Override
|
2020-04-16 00:30:04 +02:00
|
|
|
public void onEntityCollision(BlockState state, World world, BlockPos pos, Entity entity) {
|
2020-01-17 14:27:26 +01:00
|
|
|
if (entity instanceof LivingEntity && !entity.removed) {
|
2020-01-16 12:35:46 +01:00
|
|
|
LivingEntity living = (LivingEntity)entity;
|
2019-03-03 23:33:40 +01:00
|
|
|
|
2020-01-17 14:27:26 +01:00
|
|
|
if (!EquinePredicates.BUGGY.test(living) && living.getHealth() > 0) {
|
|
|
|
living.damage(MagicalDamageSource.ACID, 1);
|
2020-04-16 00:30:04 +02:00
|
|
|
living.slowMovement(state, new Vec3d(0.25D, 0.05000000074505806D, 0.25D));
|
2019-03-03 23:33:40 +01:00
|
|
|
|
2020-01-16 12:35:46 +01:00
|
|
|
if (!world.isClient) {
|
2019-03-03 23:33:40 +01:00
|
|
|
if (living.getHealth() <= 0) {
|
|
|
|
living.dropItem(Items.BONE, 3);
|
|
|
|
|
2020-01-16 16:46:24 +01:00
|
|
|
if (living instanceof PlayerEntity) {
|
2020-04-16 00:30:04 +02:00
|
|
|
if (world.random.nextInt(13000) == 0) {
|
|
|
|
ItemStack skull = new ItemStack(Items.PLAYER_HEAD);
|
2020-01-16 16:46:24 +01:00
|
|
|
PlayerEntity player = (PlayerEntity)living;
|
2019-03-03 23:33:40 +01:00
|
|
|
|
2020-04-16 00:30:04 +02:00
|
|
|
skull.setTag(new CompoundTag());
|
|
|
|
skull.getTag().put("SkullOwner", TagHelper.serializeProfile(new CompoundTag(), player.getGameProfile()));
|
|
|
|
player.dropItem(skull, true);
|
2019-03-03 23:33:40 +01:00
|
|
|
} else {
|
2020-04-16 00:30:04 +02:00
|
|
|
living.dropItem(Items.SKELETON_SKULL, 1);
|
2019-03-03 23:33:40 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-16 16:46:24 +01:00
|
|
|
public boolean checkSupport(BlockView world, BlockPos pos) {
|
2019-03-02 17:45:28 +01:00
|
|
|
|
2020-04-16 00:30:04 +02:00
|
|
|
if (PosHelper.some(pos, p -> !world.getBlockState(p).isAir(), Direction.NORTH, Direction.SOUTH, Direction.EAST, Direction.WEST)) {
|
2019-03-02 17:45:28 +01:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
pos = pos.up();
|
|
|
|
|
2020-01-16 16:46:24 +01:00
|
|
|
BlockState above = world.getBlockState(pos);
|
2019-03-02 17:45:28 +01:00
|
|
|
|
|
|
|
if (above.getBlock() == this || above.getBlock() == UBlocks.hive) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2020-04-16 00:30:04 +02:00
|
|
|
return Block.isFaceFullSquare(above.getCollisionShape(world, pos), Direction.DOWN);
|
2019-03-02 17:45:28 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@Override
|
2020-04-16 00:30:04 +02:00
|
|
|
public VoxelShape getOutlineShape(BlockState state, BlockView view, BlockPos pos, EntityContext ePos) {
|
|
|
|
Vec3d offset = getOffsetPos(state, view, pos);
|
|
|
|
|
2019-03-02 17:45:28 +01:00
|
|
|
|
2020-01-16 12:35:46 +01:00
|
|
|
if (state.get(SHAPE) == Shape.BULB) {
|
2020-04-16 00:30:04 +02:00
|
|
|
return BULBS[state.get(AGE) / 2].offset(offset.x, offset.y, offset.z);
|
2019-03-02 17:45:28 +01:00
|
|
|
}
|
|
|
|
|
2020-04-16 00:30:04 +02:00
|
|
|
return SHAFTS[state.get(AGE) / 2].offset(offset.x, offset.y, offset.z);
|
2019-03-02 17:45:28 +01:00
|
|
|
}
|
|
|
|
|
2020-04-16 00:30:04 +02:00
|
|
|
|
2019-03-02 17:45:28 +01:00
|
|
|
@Override
|
2020-04-16 00:30:04 +02:00
|
|
|
protected void appendProperties(StateFactory.Builder<Block, BlockState> builder) {
|
|
|
|
builder.add(AGE, SHAPE);
|
2019-03-02 17:45:28 +01:00
|
|
|
}
|
|
|
|
|
2020-04-15 14:22:03 +02:00
|
|
|
// TODO: isLadder
|
|
|
|
/*@Override
|
2020-01-16 12:35:46 +01:00
|
|
|
public boolean isLadder(BlockState state, BlockView world, BlockPos pos, LivingEntity entity) {
|
2019-03-02 18:18:29 +01:00
|
|
|
return true;
|
2020-04-15 14:22:03 +02:00
|
|
|
}*/
|
2019-03-02 18:18:29 +01:00
|
|
|
|
2020-01-16 12:35:46 +01:00
|
|
|
@Override
|
|
|
|
public void randomDisplayTick(BlockState state, World world, BlockPos pos, Random rand) {
|
|
|
|
if (state.get(SHAPE) == Shape.BULB) {
|
2019-03-02 18:18:29 +01:00
|
|
|
if (rand.nextInt(8) == 0) {
|
|
|
|
|
2020-04-16 00:30:04 +02:00
|
|
|
Vec3d offset = state.getOffsetPos(world, pos).add(pos.getX(), pos.getY(), pos.getZ());
|
2020-01-16 12:35:46 +01:00
|
|
|
Box bounds = BULBS[state.get(AGE) / 2]
|
2020-04-16 00:30:04 +02:00
|
|
|
.offset(offset.x, offset.y, offset.z)
|
|
|
|
.getBoundingBox();
|
2019-03-02 18:18:29 +01:00
|
|
|
|
|
|
|
double x = bounds.minX + (bounds.maxX - bounds.minX) * rand.nextFloat();
|
|
|
|
double y = bounds.minY;
|
|
|
|
double z = bounds.minZ + (bounds.maxZ - bounds.minZ) * rand.nextFloat();
|
|
|
|
|
2020-01-16 12:35:46 +01:00
|
|
|
world.addParticle(ParticleTypes.DRIPPING_LAVA, x, y, z, 0, 0, 0);
|
2019-03-02 18:18:29 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-16 12:35:46 +01:00
|
|
|
enum Shape implements StringIdentifiable {
|
2019-03-02 17:45:28 +01:00
|
|
|
BULB,
|
|
|
|
STRING;
|
|
|
|
|
|
|
|
static final Shape[] VALUES = values();
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public String toString() {
|
2020-01-16 12:35:46 +01:00
|
|
|
return asString();
|
2019-03-02 17:45:28 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2020-01-16 12:35:46 +01:00
|
|
|
public String asString() {
|
2019-03-02 17:45:28 +01:00
|
|
|
return name().toLowerCase();
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|