package com.carpentersblocks.block;
import java.util.ArrayList;
import java.util.List;
import net.minecraft.block.Block;
import net.minecraft.block.material.Material;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.util.AxisAlignedBB;
import net.minecraft.world.IBlockAccess;
import net.minecraft.world.World;
import com.carpentersblocks.data.Hinge;
import com.carpentersblocks.tileentity.TEBase;
import com.carpentersblocks.util.handler.ChatHandler;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
public class BlockHinged extends BlockCoverable {
public BlockHinged(Material material)
{
super(material);
}
/**
* Determines whether the bottom-most hinge requires a solid block underneath it.
* @return the result
*/
protected boolean requiresFoundation()
{
return true;
}
@Override
/**
* Alters hinge side.
*/
protected boolean onHammerLeftClick(TEBase TE, EntityPlayer entityPlayer)
{
int hinge = Hinge.getHinge(TE);
setHingeSide(TE, hinge == Hinge.HINGE_LEFT ? Hinge.HINGE_RIGHT : Hinge.HINGE_LEFT);
return true;
}
@Override
/**
* Alters hinge type and redstone behavior.
*/
protected boolean onHammerRightClick(TEBase TE, EntityPlayer entityPlayer)
{
if (entityPlayer.isSneaking()) {
int rigidity = Hinge.getRigidity(TE) == Hinge.HINGED_NONRIGID ? Hinge.HINGED_RIGID : Hinge.HINGED_NONRIGID;
setHingeRigidity(TE, rigidity);
switch (rigidity) {
case Hinge.HINGED_NONRIGID:
ChatHandler.sendMessageToPlayer("message.activation_wood.name", entityPlayer);
break;
case Hinge.HINGED_RIGID:
ChatHandler.sendMessageToPlayer("message.activation_iron.name", entityPlayer);
}
return true;
}
return false;
}
@Override
/**
* Opens or closes hinge on right click.
*/
protected void postOnBlockActivated(TEBase TE, EntityPlayer entityPlayer, int side, float hitX, float hitY, float hitZ, ActionResult actionResult)
{
if (!activationRequiresRedstone(TE)) {
setHingeState(TE, Hinge.getState(TE) == Hinge.STATE_OPEN ? Hinge.STATE_CLOSED : Hinge.STATE_OPEN);
actionResult.setAltered().setNoSound();
}
}
/**
* Returns whether hinge requires redstone activation.
*/
private boolean activationRequiresRedstone(TEBase TE)
{
return Hinge.getRigidity(TE) == Hinge.HINGED_RIGID;
}
/**
* Returns a list of hinge tile entities that make up either a single hinge or two connected double hinges.
*/
private List<TEBase> getHingePieces(TEBase TE)
{
List<TEBase> list = new ArrayList<TEBase>();
World world = TE.getWorldObj();
int piece = Hinge.getPiece(TE);
int facing = Hinge.getFacing(TE);
int hinge = Hinge.getHinge(TE);
int neighbor_offset = piece == Hinge.PIECE_TOP ? -1 : 1;
/* Add source hinge pieces */
list.add(TE);
TEBase TE_neighbor = getTileEntity(world, TE.xCoord, TE.yCoord + neighbor_offset, TE.zCoord);
if (TE_neighbor == null) {
return list;
} else {
list.add(TE_neighbor);
}
/* Begin searching for and adding other neighboring pieces. */
TEBase TE_ZN = getTileEntity(world, TE.xCoord, TE.yCoord, TE.zCoord - 1);
TEBase TE_ZP = getTileEntity(world, TE.xCoord, TE.yCoord, TE.zCoord + 1);
TEBase TE_XN = getTileEntity(world, TE.xCoord - 1, TE.yCoord, TE.zCoord);
TEBase TE_XP = getTileEntity(world, TE.xCoord + 1, TE.yCoord, TE.zCoord);
switch (facing)
{
case Hinge.FACING_XN:
if (TE_ZN != null) {
if (piece == Hinge.getPiece(TE_ZN) && facing == Hinge.getFacing(TE_ZN) && hinge == Hinge.HINGE_LEFT && Hinge.getHinge(TE_ZN) == Hinge.HINGE_RIGHT)
{
list.add(TE_ZN);
list.add((TEBase) world.getTileEntity(TE.xCoord, TE.yCoord + neighbor_offset, TE.zCoord - 1));
}
}
if (TE_ZP != null) {
if (piece == Hinge.getPiece(TE_ZP) && facing == Hinge.getFacing(TE_ZP) && hinge == Hinge.HINGE_RIGHT && Hinge.getHinge(TE_ZP) == Hinge.HINGE_LEFT)
{
list.add(TE_ZP);
list.add((TEBase) world.getTileEntity(TE.xCoord, TE.yCoord + neighbor_offset, TE.zCoord + 1));
}
}
break;
case Hinge.FACING_XP:
if (TE_ZN != null) {
if (piece == Hinge.getPiece(TE_ZN) && facing == Hinge.getFacing(TE_ZN) && hinge == Hinge.HINGE_RIGHT && Hinge.getHinge(TE_ZN) == Hinge.HINGE_LEFT)
{
list.add(TE_ZN);
list.add((TEBase) world.getTileEntity(TE.xCoord, TE.yCoord + neighbor_offset, TE.zCoord - 1));
}
}
if (TE_ZP != null) {
if (piece == Hinge.getPiece(TE_ZP) && facing == Hinge.getFacing(TE_ZP) && hinge == Hinge.HINGE_LEFT && Hinge.getHinge(TE_ZP) == Hinge.HINGE_RIGHT)
{
list.add(TE_ZP);
list.add((TEBase) world.getTileEntity(TE.xCoord, TE.yCoord + neighbor_offset, TE.zCoord + 1));
}
}
break;
case Hinge.FACING_ZN:
{
if (TE_XN != null) {
if (piece == Hinge.getPiece(TE_XN) && facing == Hinge.getFacing(TE_XN) && hinge == Hinge.HINGE_RIGHT && Hinge.getHinge(TE_XN) == Hinge.HINGE_LEFT)
{
list.add(TE_XN);
list.add((TEBase) world.getTileEntity(TE.xCoord - 1, TE.yCoord + neighbor_offset, TE.zCoord));
}
}
if (TE_XP != null) {
if (piece == Hinge.getPiece(TE_XP) && facing == Hinge.getFacing(TE_XP) && hinge == Hinge.HINGE_LEFT && Hinge.getHinge(TE_XP) == Hinge.HINGE_RIGHT)
{
list.add(TE_XP);
list.add((TEBase) world.getTileEntity(TE.xCoord + 1, TE.yCoord + neighbor_offset, TE.zCoord));
}
}
break;
}
case Hinge.FACING_ZP:
if (TE_XN != null) {
if (piece == Hinge.getPiece(TE_XN) && facing == Hinge.getFacing(TE_XN) && hinge == Hinge.HINGE_LEFT && Hinge.getHinge(TE_XN) == Hinge.HINGE_RIGHT)
{
list.add(TE_XN);
list.add((TEBase) world.getTileEntity(TE.xCoord - 1, TE.yCoord + neighbor_offset, TE.zCoord));
}
}
if (TE_XP != null) {
if (piece == Hinge.getPiece(TE_XP) && facing == Hinge.getFacing(TE_XP) && hinge == Hinge.HINGE_RIGHT && Hinge.getHinge(TE_XP) == Hinge.HINGE_LEFT)
{
list.add(TE_XP);
list.add((TEBase) world.getTileEntity(TE.xCoord + 1, TE.yCoord + neighbor_offset, TE.zCoord));
}
}
break;
}
return list;
}
@Override
@SideOnly(Side.CLIENT)
/**
* Returns the bounding box of the wired rectangular prism to render.
*/
public AxisAlignedBB getSelectedBoundingBoxFromPool(World world, int x, int y, int z)
{
if (world.getBlock(x, y, z).equals(this)) {
setBlockBoundsBasedOnState(world, x, y, z);
}
return super.getSelectedBoundingBoxFromPool(world, x, y, z);
}
@Override
/**
* Returns a bounding box from the pool of bounding boxes (this means this box can change after the pool has been
* cleared to be reused)
*/
public AxisAlignedBB getCollisionBoundingBoxFromPool(World world, int x, int y, int z)
{
if (world.getBlock(x, y, z).equals(this)) {
setBlockBoundsBasedOnState(world, x, y, z);
}
return super.getCollisionBoundingBoxFromPool(world, x, y, z);
}
@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) {
int facing = Hinge.getFacing(TE);
int hinge = Hinge.getHinge(TE);
boolean isOpen = Hinge.getState(TE) == Hinge.STATE_OPEN;
float x_low = 0.0F;
float z_low = 0.0F;
float x_high = 1.0F;
float z_high = 1.0F;
switch (facing)
{
case Hinge.FACING_XN:
if (!isOpen) {
x_low = 0.8125F;
} else if (hinge == Hinge.HINGE_RIGHT) {
z_high = 0.1875F;
} else {
z_low = 0.8125F;
}
break;
case Hinge.FACING_XP:
if (!isOpen) {
x_high = 0.1875F;
} else if (hinge == Hinge.HINGE_RIGHT) {
z_low = 0.8125F;
} else {
z_high = 0.1875F;
}
break;
case Hinge.FACING_ZN:
if (!isOpen) {
z_low = 0.8125F;
} else if (hinge == Hinge.HINGE_RIGHT) {
x_low = 0.8125F;
} else {
x_high = 0.1875F;
}
break;
case Hinge.FACING_ZP:
if (!isOpen) {
z_high = 0.1875F;
} else if (hinge == Hinge.HINGE_RIGHT) {
x_high = 0.1875F;
} else {
x_low = 0.8125F;
}
break;
}
setBlockBounds(x_low, 0.0F, z_low, x_high, 1.0F, z_high);
}
}
/**
* Cycle hinge state.
* Will update all connecting hinge pieces.
*/
public void setHingeState(TEBase TE, int state)
{
List<TEBase> hingePieces = getHingePieces(TE);
for (TEBase piece : hingePieces) {
Hinge.setState(piece, state, piece == TE);
}
}
/**
* Updates hinge type.
* Will also update adjoining hinge piece.
*/
public void setHingeType(TEBase TE, int type)
{
Hinge.setType(TE, type);
updateAdjoiningPiece(TE);
}
/**
* Set hinge rigidity.
* Will update all connecting hinge pieces.
*/
public void setHingeRigidity(TEBase TE, int rigidity)
{
List<TEBase> hingePieces = getHingePieces(TE);
for (TEBase piece : hingePieces) {
Hinge.setRigidity(piece, rigidity);
}
}
/**
* Updates hinge hinge side.
* Will also update adjoining hinge piece.
*/
public void setHingeSide(TEBase TE, int side)
{
Hinge.setHingeSide(TE, side);
updateAdjoiningPiece(TE);
}
@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) {
boolean isOpen = Hinge.getState(TE) == Hinge.STATE_OPEN;
/* Check if hinge piece is orphaned. */
if (Hinge.getPiece(TE) == Hinge.PIECE_BOTTOM) {
if (!world.getBlock(x, y + 1, z).equals(this)) {
destroyBlock(world, x, y, z, false);
return;
} else if (requiresFoundation() && !World.doesBlockHaveSolidTopSurface(world, x, y - 1, z)) {
destroyBlock(world, x, y, z, true);
return;
}
} else if (!world.getBlock(x, y - 1, z).equals(this)) {
destroyBlock(world, x, y, z, false);
return;
}
/*
* Create list of hinge pieces and check state of each so
* that they act as a single entity regardless of which
* hinge piece receives this event.
*/
boolean isPowered = false;
List<TEBase> hingePieces = getHingePieces(TE);
for (TEBase piece : hingePieces) {
if (piece != null) {
if (world.isBlockIndirectlyGettingPowered(piece.xCoord, piece.yCoord, piece.zCoord)) {
isPowered = true;
}
}
}
/* Set block open or closed. */
if (block != null && block.canProvidePower() && isPowered != isOpen) {
setHingeState(TE, isOpen ? Hinge.STATE_CLOSED : Hinge.STATE_OPEN);
}
}
}
super.onNeighborBlockChange(world, x, y, z, block);
}
/**
* Updates state, hinge and type for adjoining hinge piece.
*/
private void updateAdjoiningPiece(TEBase TE)
{
int state = Hinge.getState(TE);
int hinge = Hinge.getHinge(TE);
int type = Hinge.getType(TE);
int rigidity = Hinge.getRigidity(TE);
boolean isTop = Hinge.getPiece(TE) == Hinge.PIECE_TOP;
World world = TE.getWorldObj();
TEBase TE_adj;
if (isTop) {
TE_adj = (TEBase) world.getTileEntity(TE.xCoord, TE.yCoord - 1, TE.zCoord);
} else {
TE_adj = (TEBase) world.getTileEntity(TE.xCoord, TE.yCoord + 1, TE.zCoord);
}
if (TE_adj != null) {
Hinge.setState(TE_adj, state, false);
Hinge.setHingeSide(TE_adj, hinge);
Hinge.setType(TE_adj, type);
Hinge.setRigidity(TE_adj, rigidity);
}
}
}