/** Copyright (C) <2017> <coolAlias> This file is part of coolAlias' Zelda Sword Skills Minecraft Mod; as such, you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ package zeldaswordskills.block; import java.util.Random; import net.minecraft.block.Block; import net.minecraft.block.material.Material; import net.minecraft.block.properties.PropertyInteger; import net.minecraft.block.state.BlockState; import net.minecraft.block.state.IBlockState; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.ItemStack; import net.minecraft.util.AxisAlignedBB; import net.minecraft.util.BlockPos; import net.minecraft.util.EnumFacing; import net.minecraft.world.IBlockAccess; import net.minecraft.world.World; import net.minecraftforge.fml.common.eventhandler.Event.Result; import zeldaswordskills.ZSSAchievements; import zeldaswordskills.api.block.BlockWeight; import zeldaswordskills.api.block.IHookable; import zeldaswordskills.api.block.ISmashable; import zeldaswordskills.api.block.IWhipBlock; import zeldaswordskills.api.item.ISmashBlock; import zeldaswordskills.creativetab.ZSSCreativeTabs; import zeldaswordskills.entity.projectile.EntityWhip; import zeldaswordskills.ref.Sounds; /** * * A block that can be smashed into the ground and eventually broken. * Each smash increments the meta until it reaches MAX_STATE, after which * any blow that is at least a level higher than the weight can destroy it. * * If not destroyed, the peg will eventually pop back up. * */ public class BlockPeg extends Block implements IDungeonBlock, IHookable, ISmashable, IWhipBlock { /** Maximum number of 'hits' before a peg is considered fully smashed down */ private static final int MAX_HITS = 3; /** Current number of hits taken, 0 being fully up, 3 fully smashed into the ground */ public static final PropertyInteger HITS_TAKEN = PropertyInteger.create("hits_taken", 0, MAX_HITS); /** The weight of this block, i.e. the difficulty of smashing this block */ private final BlockWeight weight; public BlockPeg(Material material, BlockWeight weight) { super(material); this.weight = weight; disableStats(); setTickRandomly(true); setBlockUnbreakable(); setResistance(BlockWeight.IMPOSSIBLE.weight); setStepSound(soundTypeStone); setCreativeTab(ZSSCreativeTabs.tabBlocks); setBlockBounds(0.25F, 0.0F, 0.25F, 0.75F, 0.8125F, 0.75F); } /** Returns appropriate sound based on block material */ private String getHitSound() { return blockMaterial == ZSSBlockMaterials.pegRustyMaterial ? Sounds.HIT_RUSTY : Sounds.HIT_PEG; } @Override public Result canGrabBlock(HookshotType type, World world, BlockPos pos, EnumFacing face) { if (face == EnumFacing.UP || face == EnumFacing.DOWN || ((Integer) world.getBlockState(pos).getValue(HITS_TAKEN)).intValue() > 0) { return Result.DENY; } return (type.getBaseType() == HookshotType.MULTI_SHOT ? Result.ALLOW : Result.DEFAULT); } @Override public Result canDestroyBlock(HookshotType type, World world, BlockPos pos, EnumFacing face) { return Result.DENY; } @Override public Material getHookableMaterial(HookshotType type, World world, BlockPos pos, EnumFacing face) { return (blockMaterial == ZSSBlockMaterials.pegWoodMaterial ? Material.wood : Material.iron); } @Override public BlockWeight getSmashWeight(EntityPlayer player, ItemStack stack, IBlockState state, EnumFacing face) { return weight; } @Override public Result onSmashed(World world, EntityPlayer player, ItemStack stack, BlockPos pos, IBlockState state, EnumFacing face) { world.playSoundEffect(pos.getX(), pos.getY(), pos.getZ(), getHitSound(), (world.rand.nextFloat() * 0.4F + 0.5F), 1.0F / (world.rand.nextFloat() * 0.4F + 0.5F)); if (face != EnumFacing.UP) { return Result.DENY; } boolean flag = false; int hits = world.getBlockState(pos).getValue(HITS_TAKEN).intValue(); int impact = 1 + ((ISmashBlock) stack.getItem()).getSmashStrength(player, stack, state, face).ordinal() - weight.ordinal(); if (impact > 0) { flag = hits < MAX_HITS; hits += impact; if (hits >= MAX_HITS) { player.triggerAchievement(ZSSAchievements.hammerTime); if (weight.compareTo(BlockWeight.LIGHT) > 0) { // i.e. at least MEDIUM player.triggerAchievement(ZSSAchievements.hardHitter); } } } if (hits > MAX_HITS && impact > 1) { flag = true; world.destroyBlock(pos, false); } else { world.setBlockState(pos, state.withProperty(HITS_TAKEN, Integer.valueOf(Math.min(hits, MAX_HITS))), 3); } return (flag ? Result.ALLOW : Result.DENY); } @Override public boolean canBreakBlock(WhipType whip, EntityLivingBase thrower, World world, BlockPos pos, EnumFacing face) { return false; } @Override public boolean canGrabBlock(WhipType whip, EntityLivingBase thrower, World world, BlockPos pos, EnumFacing face) { return (face.getAxis().isHorizontal() && world.getBlockState(pos).getValue(HITS_TAKEN).intValue() < MAX_HITS); } @Override public Result shouldSwing(EntityWhip whip, World world, BlockPos pos, int ticksInGround) { if (world.getBlockState(pos).getValue(HITS_TAKEN).intValue() >= MAX_HITS) { whip.setDead(); return Result.DENY; } return Result.DEFAULT; } @Override public void updateTick(World world, BlockPos pos, IBlockState state, Random rand) { int hits = state.getValue(HITS_TAKEN).intValue(); if (hits > 0) { world.setBlockState(pos, state.withProperty(HITS_TAKEN, Integer.valueOf(hits - 1)), 3); } } @Override public int tickRate(World world) { return 60; } @Override public boolean isOpaqueCube() { return false; } @Override public boolean isFullCube() { return false; } @Override public boolean canEntityDestroy(IBlockAccess world, BlockPos pos, Entity entity) { return false; } @Override public AxisAlignedBB getCollisionBoundingBox(World world, BlockPos pos, IBlockState state) { int hits = state.getValue(HITS_TAKEN).intValue(); if (hits == 0) { return new AxisAlignedBB(pos.getX() + minX, pos.getY() + minY, pos.getZ() + minZ, pos.getX() + maxX, pos.getY() + maxY + 0.5D, pos.getZ() + maxZ); } else if (hits >= MAX_HITS) { return null; } else { return super.getCollisionBoundingBox(world, pos, state); } } @Override public void setBlockBoundsBasedOnState(IBlockAccess world, BlockPos pos) { int hits = Math.min(world.getBlockState(pos).getValue(HITS_TAKEN).intValue(), MAX_HITS); setBlockBounds(0.25F, 0.0F, 0.25F, 0.75F, 0.8125F - (hits * 0.1875F), 0.75F); } @Override public void setBlockBoundsForItemRender() { setBlockBounds(0.25F, 0.0F, 0.25F, 0.75F, 0.8125F, 0.75F); } @Override public boolean isSameVariant(World world, BlockPos pos, IBlockState state, int meta) { return true; } @Override public IBlockState getStateFromMeta(int meta) { return getDefaultState().withProperty(HITS_TAKEN, Integer.valueOf(Math.min(meta, MAX_HITS))); } @Override public int getMetaFromState(IBlockState state) { return state.getValue(HITS_TAKEN).intValue(); } @Override protected BlockState createBlockState() { return new BlockState(this, HITS_TAKEN); } }