package com.carpentersblocks.block; import java.util.List; import net.minecraft.block.Block; import net.minecraft.block.BlockSlab; import net.minecraft.block.BlockStairs; import net.minecraft.block.material.Material; import net.minecraft.client.renderer.texture.IIconRegister; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.init.Blocks; import net.minecraft.item.ItemStack; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.AxisAlignedBB; import net.minecraft.util.MovingObjectPosition; import net.minecraft.util.Vec3; import net.minecraft.world.IBlockAccess; import net.minecraft.world.World; import net.minecraftforge.common.util.ForgeDirection; import com.carpentersblocks.CarpentersBlocks; import com.carpentersblocks.data.Hatch; import com.carpentersblocks.tileentity.TEBase; import com.carpentersblocks.util.handler.ChatHandler; import com.carpentersblocks.util.registry.BlockRegistry; import com.carpentersblocks.util.registry.IconRegistry; import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; public class BlockCarpentersHatch extends BlockCoverable { public BlockCarpentersHatch(Material material) { super(material); } @SideOnly(Side.CLIENT) @Override /** * When this method is called, your block should register all the icons it needs with the given IconRegister. This * is the only chance you get to register icons. */ public void registerBlockIcons(IIconRegister iconRegister) { IconRegistry.icon_hatch_glass = iconRegister.registerIcon(CarpentersBlocks.MODID + ":" + "hatch/hatch_glass"); IconRegistry.icon_hatch_french_glass = iconRegister.registerIcon(CarpentersBlocks.MODID + ":" + "hatch/hatch_french_glass"); IconRegistry.icon_hatch_screen = iconRegister.registerIcon(CarpentersBlocks.MODID + ":" + "hatch/hatch_screen"); } @Override /** * Alters direction based on valid sides detected. */ protected boolean onHammerLeftClick(TEBase TE, EntityPlayer entityPlayer) { if (!TE.getWorldObj().isRemote) { findNextSideSupportBlock(TE, TE.getWorldObj(), TE.xCoord, TE.yCoord, TE.zCoord); } return true; } @Override /** * Alters hatch type and redstone behavior. */ protected boolean onHammerRightClick(TEBase TE, EntityPlayer entityPlayer) { if (!entityPlayer.isSneaking()) { int type = Hatch.getType(TE); if (++type > 4) { type = 0; } Hatch.setType(TE, type); } else { int rigidity = Hatch.getRigidity(TE) == Hatch.HINGED_NONRIGID ? Hatch.HINGED_RIGID : Hatch.HINGED_NONRIGID; Hatch.setRigidity(TE, rigidity); switch (rigidity) { case Hatch.HINGED_NONRIGID: ChatHandler.sendMessageToPlayer("message.activation_wood.name", entityPlayer); break; case Hatch.HINGED_RIGID: ChatHandler.sendMessageToPlayer("message.activation_iron.name", entityPlayer); } } return true; } @Override /** * Called upon block activation (right click on the block.) */ protected void postOnBlockActivated(TEBase TE, EntityPlayer entityPlayer, int side, float hitX, float hitY, float hitZ, ActionResult actionResult) { if (!activationRequiresRedstone(TE)) { Hatch.setState(TE, Hatch.getState(TE) == Hatch.STATE_CLOSED ? Hatch.STATE_OPEN : Hatch.STATE_CLOSED); actionResult.setAltered().setNoSound(); } } /** * Returns whether hatch requires redstone activation. */ private boolean activationRequiresRedstone(TEBase TE) { return Hatch.getRigidity(TE) == Hatch.HINGED_RIGID; } @Override /** * Updates the blocks bounds based on its current state. Args: world, x, y, z */ public void setBlockBoundsBasedOnState(IBlockAccess blockAccess, int x, int y, int z) { TEBase TE = getTileEntity(blockAccess, x, y, z); if (TE != null) { boolean isHigh = Hatch.getPos(TE) == Hatch.POSITION_HIGH; boolean isOpen = Hatch.getState(TE) == Hatch.STATE_OPEN; int dir = Hatch.getDir(TE); float thickness = 0.1875F; /* Hidden type has reduced dimensions to assist in climbing */ if (Hatch.getType(TE) == Hatch.TYPE_HIDDEN) { thickness = 0.125F; } if (isHigh) { setBlockBounds(0.0F, 1.0F - thickness, 0.0F, 1.0F, 1.0F, 1.0F); } else { setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, thickness, 1.0F); } if (isOpen) { switch (dir) { case 0: setBlockBounds(0.0F, 0.0F, 1.0F - thickness, 1.0F, 1.0F, 1.0F); break; case 1: setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, thickness); break; case 2: setBlockBounds(1.0F - thickness, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F); break; case 3: setBlockBounds(0.0F, 0.0F, 0.0F, thickness, 1.0F, 1.0F); break; } } } } @Override /** * Adds all intersecting collision boxes to a list. (Be sure to only add boxes to the list if they intersect the * mask.) Parameters: World, X, Y, Z, mask, list, colliding entity */ public void addCollisionBoxesToList(World world, int x, int y, int z, AxisAlignedBB axisAlignedBB, List list, Entity entity) { setBlockBoundsBasedOnState(world, x, y, z); super.addCollisionBoxesToList(world, x, y, z, axisAlignedBB, list, entity); } @Override /** * Lets the block know when one of its neighbor changes. Doesn't know which neighbor changed (coordinates passed are * their own) Args: x, y, z, neighbor blockID */ public void onNeighborBlockChange(World world, int x, int y, int z, Block block) { if (!world.isRemote) { TEBase TE = getTileEntity(world, x, y, z); if (TE != null) { int dir = Hatch.getDir(TE); int state = Hatch.getState(TE); int xOffset = x; int zOffset = z; switch (dir) { case Hatch.DIR_Z_NEG: zOffset = z + 1; break; case Hatch.DIR_Z_POS: --zOffset; break; case Hatch.DIR_X_NEG: xOffset = x + 1; break; case Hatch.DIR_X_POS: --xOffset; break; } if (!(isValidSupportBlock(world, x, y, z, world.getBlock(xOffset, y, zOffset)) || world.getBlock(xOffset, y, zOffset).isSideSolid(world, xOffset, y, zOffset, ForgeDirection.getOrientation(dir + 2)))) { findNextSideSupportBlock(TE, world, x, y, z); } boolean isPowered = world.isBlockIndirectlyGettingPowered(x, y, z); boolean isOpen = state == Hatch.STATE_OPEN; if (block != null && block.canProvidePower() && isPowered != isOpen) { Hatch.setState(TE, state == Hatch.STATE_OPEN ? Hatch.STATE_CLOSED : Hatch.STATE_OPEN); } } } super.onNeighborBlockChange(world, x, y, z, block); } @Override /** * Ray traces through the blocks collision from start vector to end vector returning a ray trace hit. Args: world, * x, y, z, startVec, endVec */ public MovingObjectPosition collisionRayTrace(World world, int x, int y, int z, Vec3 startVec, Vec3 endVec) { setBlockBoundsBasedOnState(world, x, y, z); return super.collisionRayTrace(world, x, y, z, startVec, endVec); } @Override /** * Called when a block is placed using its ItemBlock. Args: World, X, Y, Z, side, hitX, hitY, hitZ, block metadata */ public int onBlockPlaced(World world, int x, int y, int z, int side, float hitX, float hitY, float hitZ, int metadata) { int initData = 0; if (side > 1) { initData = side - 2; } // Hatch on upper half of block if (side != 1 && side != 0 && hitY > 0.5F) { initData |= 8; } return initData; } @Override /** * Called when the block is placed in the world. * Uses cardinal direction to adjust metadata if player clicks top or bottom face of block. */ public void onBlockPlacedBy(World world, int x, int y, int z, EntityLivingBase entityLiving, ItemStack itemStack) { super.onBlockPlacedBy(world, x, y, z, entityLiving, itemStack); TEBase TE = getTileEntity(world, x, y, z); if (TE != null) { int metadata = world.getBlockMetadata(x, y, z); Hatch.setDir(TE, metadata & 0x3); if ((metadata & 0x8) > 0) { Hatch.setPos(TE, Hatch.POSITION_HIGH); } } } @Override /** * checks to see if you can place this block can be placed on that side of a block: BlockLever overrides */ public boolean canPlaceBlockOnSide(World world, int x, int y, int z, int side) { switch (side) { case 2: return isValidSupportBlock(world, x, y, z, world.getBlock(x, y, z + 1)) || world.getBlock(x, y, z + 1).isSideSolid(world, x, y, z + 1, ForgeDirection.getOrientation(ForgeDirection.OPPOSITES[3])); case 3: return isValidSupportBlock(world, x, y, z, world.getBlock(x, y, z - 1)) || world.getBlock(x, y, z - 1).isSideSolid(world, x, y, z - 1, ForgeDirection.getOrientation(ForgeDirection.OPPOSITES[2])); case 4: return isValidSupportBlock(world, x, y, z, world.getBlock(x + 1, y, z)) || world.getBlock(x + 1, y, z).isSideSolid(world, x + 1, y, z, ForgeDirection.getOrientation(ForgeDirection.OPPOSITES[5])); case 5: return isValidSupportBlock(world, x, y, z, world.getBlock(x - 1, y, z)) || world.getBlock(x - 1, y, z).isSideSolid(world, x - 1, y, z, ForgeDirection.getOrientation(ForgeDirection.OPPOSITES[4])); } return false; } /** * Will find and set a new direction for hatch if an adjacent block can support it. * If nothing is found, block will break. */ private void findNextSideSupportBlock(TEBase TE, World world, int x, int y, int z) { int dir = Hatch.getDir(TE); if (++dir > 3) { dir = 0; } /* * This block will rotate until it finds a suitable * support block. It will drop if nothing is found. */ int count = 0; while (!canPlaceBlockOnSide(world, x, y, z, dir + 2) && count < 4) { if (++dir > 3) { dir = 0; } ++count; } if (count == 4) { destroyBlock(world, x, y, z, true); } else { Hatch.setDir(TE, dir); } } @Override /** * Checks if a player or entity can use this block to 'climb' like a ladder. * * @param world The current world * @param x X Position * @param y Y position * @param z Z position * @param entity The entity trying to use the ladder, CAN be null. * @return True if the block should act like a ladder */ public boolean isLadder(IBlockAccess blockAccess, int x, int y, int z, EntityLivingBase entityLiving) { TEBase TE = getTileEntity(blockAccess, x, y, z); return TE != null && Hatch.getType(TE) == Hatch.TYPE_HIDDEN && Hatch.getPos(TE) == Hatch.POSITION_HIGH && Hatch.getState(TE) == Hatch.STATE_OPEN; } /** * Checks if the block ID is a valid support block for the hatch to connect with. If it is not the hatch is * dropped into the world. */ private boolean isValidSupportBlock(World world, int x, int y, int z, Block block) { return block == Blocks.glowstone || block instanceof BlockCarpentersStairs || block instanceof BlockCarpentersBlock || block instanceof BlockSlab || block instanceof BlockStairs; } @Override /** * The type of render function that is called for this block */ public int getRenderType() { return BlockRegistry.carpentersHatchRenderID; } @Override public ForgeDirection[] getValidRotations(World worldObj, int x, int y,int z) { ForgeDirection[] axises = {ForgeDirection.UP, ForgeDirection.DOWN}; return axises; } @Override public boolean rotateBlock(World world, int x, int y, int z, ForgeDirection axis) { // to correctly support archimedes' ships mod: // if Axis is DOWN, block rotates to the left, north -> west -> south -> east // if Axis is UP, block rotates to the right: north -> east -> south -> west TileEntity tile = world.getTileEntity(x, y, z); if (tile != null && tile instanceof TEBase) { TEBase cbTile = (TEBase)tile; int direction = Hatch.getDir(cbTile); switch (axis) { case UP: { switch (direction) { case 0:{Hatch.setDir(cbTile, 3); break;} case 1:{Hatch.setDir(cbTile, 2); break;} case 2:{Hatch.setDir(cbTile, 0); break;} case 3:{Hatch.setDir(cbTile, 1); break;} } break; } case DOWN: { switch (direction) { case 0:{Hatch.setDir(cbTile, 2); break;} case 1:{Hatch.setDir(cbTile, 3); break;} case 2:{Hatch.setDir(cbTile, 1); break;} case 3:{Hatch.setDir(cbTile, 0); break;} } break; } default: return false; } return true; } return false; } }