package com.carpentersblocks.block;
import java.util.List;
import net.minecraft.block.material.Material;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.AxisAlignedBB;
import net.minecraft.util.IIcon;
import net.minecraft.util.MathHelper;
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.data.Stairs;
import com.carpentersblocks.tileentity.TEBase;
import com.carpentersblocks.util.registry.BlockRegistry;
import com.carpentersblocks.util.registry.IconRegistry;
import com.carpentersblocks.util.registry.ItemRegistry;
import com.carpentersblocks.util.stairs.StairsTransform;
import com.carpentersblocks.util.stairs.StairsUtil;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
public class BlockCarpentersStairs extends BlockCoverable {
public BlockCarpentersStairs(Material material)
{
super(material);
}
@Override
@SideOnly(Side.CLIENT)
/**
* Returns a base icon that doesn't rely on blockIcon, which
* is set prior to texture stitch events.
*/
public IIcon getIcon()
{
return IconRegistry.icon_uncovered_quartered;
}
@Override
/**
* Alters block direction.
*/
protected boolean onHammerLeftClick(TEBase TE, EntityPlayer entityPlayer)
{
int stairsID = TE.getData();
Stairs stairs = Stairs.stairsList[stairsID];
/* Cycle between stairs direction based on current type. */
switch (stairs.stairsType)
{
case NORMAL_SIDE:
if (++stairsID > Stairs.ID_NORMAL_SW) {
stairsID = Stairs.ID_NORMAL_SE;
}
break;
case NORMAL:
if (stairs.isPositive) {
if (++stairsID > Stairs.ID_NORMAL_POS_E) {
stairsID = Stairs.ID_NORMAL_POS_N;
}
} else {
if (++stairsID > Stairs.ID_NORMAL_NEG_E) {
stairsID = Stairs.ID_NORMAL_NEG_N;
}
}
break;
case NORMAL_INT:
if (stairs.isPositive) {
if (++stairsID > Stairs.ID_NORMAL_INT_POS_SW) {
stairsID = Stairs.ID_NORMAL_INT_POS_SE;
}
} else {
if (++stairsID > Stairs.ID_NORMAL_INT_NEG_SW) {
stairsID = Stairs.ID_NORMAL_INT_NEG_SE;
}
}
break;
case NORMAL_EXT:
if (stairs.isPositive) {
if (++stairsID > Stairs.ID_NORMAL_EXT_POS_SW) {
stairsID = Stairs.ID_NORMAL_EXT_POS_SE;
}
} else {
if (++stairsID > Stairs.ID_NORMAL_EXT_NEG_SW) {
stairsID = Stairs.ID_NORMAL_EXT_NEG_SE;
}
}
break;
}
TE.setData(stairsID);
return true;
}
@Override
/**
* Alters block type.
*/
protected boolean onHammerRightClick(TEBase TE, EntityPlayer entityPlayer)
{
int stairsID = TE.getData();
Stairs stairs = Stairs.stairsList[stairsID];
/* Transform stairs to next type. */
switch (stairs.stairsType)
{
case NORMAL_SIDE:
stairsID += 8;
break;
case NORMAL:
if (stairs.isPositive) {
stairsID -= 4;
} else {
stairsID += 12;
}
break;
case NORMAL_INT:
if (stairs.isPositive) {
stairsID -= 4;
} else {
stairsID += 12;
}
break;
case NORMAL_EXT:
if (stairs.isPositive) {
stairsID -= 4;
} else {
stairsID = Stairs.ID_NORMAL_SE;
}
break;
}
TE.setData(stairsID);
return true;
}
@Override
/**
* Damages hammer with a chance to not damage.
*/
protected void damageItemWithChance(World world, EntityPlayer entityPlayer)
{
if (world.rand.nextFloat() <= ItemRegistry.itemHammerDamageChanceFromStairs) {
super.damageItemWithChance(world, entityPlayer);
}
}
@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)
{
TEBase TE = getTileEntity(world, x, y, z);
MovingObjectPosition finalTrace = null;
if (TE != null) {
Stairs stairs = Stairs.stairsList[TE.getData()];
StairsUtil stairsUtil = new StairsUtil();
double currDist = 0.0D;
double maxDist = 0.0D;
// Determine if ray trace is a hit on stairs
for (int box = 0; box < 3; ++box)
{
float[] bounds = stairsUtil.genBounds(box, stairs);
if (bounds != null)
{
setBlockBounds(bounds[0], bounds[1], bounds[2], bounds[3], bounds[4], bounds[5]);
MovingObjectPosition traceResult = super.collisionRayTrace(world, x, y, z, startVec, endVec);
if (traceResult != null)
{
currDist = traceResult.hitVec.squareDistanceTo(endVec);
if (currDist > maxDist) {
finalTrace = traceResult;
maxDist = currDist;
}
}
}
}
setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F);
}
return finalTrace;
}
@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)
{
TEBase TE = getTileEntity(world, x, y, z);
if (TE != null) {
AxisAlignedBB colBox = null;
Stairs stairs = Stairs.stairsList[TE.getData()];
StairsUtil stairsUtil = new StairsUtil();
for (int box = 0; box < 3; ++box) {
float[] bounds = stairsUtil.genBounds(box, stairs);
if (bounds != null) {
colBox = AxisAlignedBB.getBoundingBox(x + bounds[0], y + bounds[1], z + bounds[2], x + bounds[3], y + bounds[4], z + bounds[5]);
}
if (colBox != null && axisAlignedBB.intersectsWith(colBox)) {
list.add(colBox);
}
}
}
}
@Override
/**
* Checks if the block is a solid face on the given side, used by placement logic.
*/
public boolean isSideSolid(IBlockAccess blockAccess, int x, int y, int z, ForgeDirection side)
{
TEBase TE = getTileEntity(blockAccess, x, y, z);
if (TE != null) {
if (isBlockSolid(blockAccess, x, y, z)) {
return Stairs.stairsList[TE.getData()].isFaceFull(side);
}
}
return false;
}
@Override
/**
* Called when block is placed in world.
* Sets stairs angle depending on click coordinates on block face.
*
* Metadata values:
* 0 - 11 - Identifies stairs angle in x, y, z space.
* 12 - 13 - Top or bottom side of block clicked. onBlockPlacedBy() determines
* direction and sets interpolated value from 0 - 11.
*/
public int onBlockPlaced(World world, int x, int y, int z, int side, float hitX, float hitY, float hitZ, int metadata)
{
// Normalize face coordinates
switch (side) {
case 2:
hitX = 1.0F - hitX;
break;
case 4:
hitX = hitZ;
break;
case 5:
hitX = 1.0F - hitZ;
break;
}
if (side > 1) {
if (hitY > 0.5F && hitX > 1.0F - hitY && hitX < hitY) {
return side + 2;
} else if (hitY < 0.5F && hitX < 1.0F - hitY && hitX > hitY) {
return side + 6;
} else if (hitX < 0.2F) {
return side == 2 ? 1 : side == 3 ? 0 : side == 4 ? 3 : 2;
} else if (hitX > 0.8F){
return side == 2 ? 2 : side == 3 ? 3 : side == 4 ? 1 : 0;
} else if (hitY > 0.5F) {
return side + 2;
} else { // hitY < 0.5F
return side + 6;
}
} else {
return side + 12;
}
}
@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 facing = MathHelper.floor_double(entityLiving.rotationYaw * 4.0F / 360.0F + 0.5D) & 3;
TE.setData(world.getBlockMetadata(x, y, z));
int stairsID = TE.getData();
if (stairsID > 11)
{
switch (facing) {
case 0:
stairsID = stairsID == 12 ? Stairs.ID_NORMAL_NEG_N : Stairs.ID_NORMAL_POS_N;
break;
case 1:
stairsID = stairsID == 12 ? Stairs.ID_NORMAL_NEG_E : Stairs.ID_NORMAL_POS_E;
break;
case 2:
stairsID = stairsID == 12 ? Stairs.ID_NORMAL_NEG_S : Stairs.ID_NORMAL_POS_S;
break;
case 3:
stairsID = stairsID == 12 ? Stairs.ID_NORMAL_NEG_W : Stairs.ID_NORMAL_POS_W;
break;
}
}
TE.setData(stairsID);
/* If shift key is down, skip auto-orientation. */
if (!entityLiving.isSneaking()) {
stairsID = StairsTransform.transformStairs(TE, stairsID, x, y, z);
TE.setData(stairsID);
StairsTransform.transformAdjacentStairs(world, stairsID, x, y, z);
}
}
}
@Override
/**
* Returns whether block can support cover on side.
*/
public boolean canCoverSide(TEBase TE, World world, int x, int y, int z, int side)
{
return true;
}
@Override
/**
* The type of render function that is called for this block
*/
public int getRenderType()
{
return BlockRegistry.carpentersStairsRenderID;
}
@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 data = cbTile.getData();
int dataAngle = data % 4;
switch (axis)
{
case UP:
{
switch (dataAngle)
{
case 0:{cbTile.setData(data+3); break;}
case 1:{cbTile.setData(data+1); break;}
case 2:{cbTile.setData(data-2); break;}
case 3:{cbTile.setData(data-2); break;}
}
break;
}
case DOWN:
{
switch (dataAngle)
{
case 0:{cbTile.setData(data+2); break;}
case 1:{cbTile.setData(data+2); break;}
case 2:{cbTile.setData(data-1); break;}
case 3:{cbTile.setData(data-3); break;}
}
break;
}
default: return false;
}
return true;
}
return false;
}
}