@Override
  /** Alters block type. */
  protected boolean onHammerRightClick(TEBase TE, EntityPlayer entityPlayer) {
    int slopeID = TE.getData();
    Slope slope = Slope.slopesList[slopeID];

    /* Transform slope to next type. */
    slopeID = slope.slopeType.onHammerRightClick(slope, slopeID);

    TE.setData(slopeID);

    return true;
  }
  @Override
  /** Alters block direction. */
  protected boolean onHammerLeftClick(TEBase TE, EntityPlayer entityPlayer) {
    int slopeID = TE.getData();
    Slope slope = Slope.slopesList[slopeID];

    /* Cycle between slope types based on current slope. */
    slopeID = slope.slopeType.onHammerLeftClick(slope, slopeID);

    TE.setData(slopeID);

    return true;
  }
  @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;
  }
  @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) {
    TEBase TE = getTileEntity(world, x, y, z);

    if (TE != null) {

      int slopeID = 0;
      int metadata = world.getBlockMetadata(x, y, z);

      boolean isPositive =
          EventHandler.eventFace > 1 && EventHandler.hitY < 0.5F || EventHandler.eventFace == 1;
      int corner = getCorner(entityLiving.rotationYaw);

      ForgeDirection dir = EntityLivingUtil.getFacing(entityLiving).getOpposite();

      switch (metadata) {
        case META_WEDGE:
          slopeID =
              getWedgeOrientation(
                  dir,
                  EventHandler.eventFace,
                  EventHandler.hitX,
                  EventHandler.hitY,
                  EventHandler.hitZ);

          if (!entityLiving.isSneaking()) {
            slopeID = SlopeTransform.transformWedge(world, slopeID, x, y, z);
            TE.setData(slopeID);
            SlopeTransform.transformAdjacentWedges(world, slopeID, x, y, z);
          }

          break;
        case META_OBLIQUE_INT:
          switch (corner) {
            case CORNER_SE:
              slopeID = isPositive ? Slope.ID_OBL_INT_POS_SE : Slope.ID_OBL_INT_NEG_SE;
              break;
            case CORNER_NE:
              slopeID = isPositive ? Slope.ID_OBL_INT_POS_NE : Slope.ID_OBL_INT_NEG_NE;
              break;
            case CORNER_NW:
              slopeID = isPositive ? Slope.ID_OBL_INT_POS_NW : Slope.ID_OBL_INT_NEG_NW;
              break;
            case CORNER_SW:
              slopeID = isPositive ? Slope.ID_OBL_INT_POS_SW : Slope.ID_OBL_INT_NEG_SW;
              break;
          }

          break;
        case META_OBLIQUE_EXT:
          switch (corner) {
            case CORNER_SE:
              slopeID = isPositive ? Slope.ID_OBL_EXT_POS_SE : Slope.ID_OBL_EXT_NEG_SE;
              break;
            case CORNER_NE:
              slopeID = isPositive ? Slope.ID_OBL_EXT_POS_NE : Slope.ID_OBL_EXT_NEG_NE;
              break;
            case CORNER_NW:
              slopeID = isPositive ? Slope.ID_OBL_EXT_POS_NW : Slope.ID_OBL_EXT_NEG_NW;
              break;
            case CORNER_SW:
              slopeID = isPositive ? Slope.ID_OBL_EXT_POS_SW : Slope.ID_OBL_EXT_NEG_SW;
              break;
          }

          break;
        case META_PRISM:
          if (isPositive) {

            slopeID = Slope.ID_PRISM_POS;

            if (!entityLiving.isSneaking()) {
              slopeID = SlopeTransform.transformPrism(world, slopeID, x, y, z);
              TE.setData(slopeID);
              SlopeTransform.transformAdjacentPrisms(world, x, y, z);
            }

          } else {

            slopeID = Slope.ID_PRISM_NEG;
          }

          break;
        case META_PRISM_SLOPE:
          switch (dir) {
            case NORTH:
              slopeID = Slope.ID_PRISM_WEDGE_POS_S;
              break;
            case SOUTH:
              slopeID = Slope.ID_PRISM_WEDGE_POS_N;
              break;
            case WEST:
              slopeID = Slope.ID_PRISM_WEDGE_POS_E;
              break;
            case EAST:
              slopeID = Slope.ID_PRISM_WEDGE_POS_W;
              break;
            default:
              {
              }
          }

          break;
      }

      TE.setData(slopeID);
    }

    super.onBlockPlacedBy(world, x, y, z, entityLiving, itemStack);
  }