blob: 171fb0fa22ce44860c4f4d633dc14c4e09130b57 [file] [log] [blame] [raw]
package codechicken.multipart
import net.minecraft.world.World
import net.minecraft.block.Block
import net.minecraft.world.IBlockAccess
import net.minecraft.util.Direction
import codechicken.lib.vec.Rotation._
/**
* Interface for parts with redstone interaction
*
* Marker interface for TRedstoneTile. This means that if a part is an instance of IRedstonePart, the container tile may be cast to TRedstoneTile
*/
trait IRedstonePart
{
/**
* Returns the strong (indirect, through blocks) signal being emitted by this part to the specified side
*/
def strongPowerLevel(side:Int):Int
/**
* Returns the weak (direct) signal being emitted by this part to the specified side
*/
def weakPowerLevel(side:Int):Int
/**
* Returns true if this part can connect to redstone on the specified side. Blocking parts like covers will be handled by RedstoneInteractions
*/
def canConnectRedstone(side:Int):Boolean
}
/**
* For parts like wires that adhere to a specific face, reduces redstone connections to the specific edge between two faces.
* Should be implemented on parts implementing TFacePart
*/
trait IFaceRedstonePart extends IRedstonePart
{
/**
* Return the face to which this redstone part is attached
*/
def getFace:Int
}
/**
* For parts that want to define their own connection masks (like center-center parts)
*/
trait IMaskedRedstonePart extends IRedstonePart
{
/**
* Returns the redstone connection mask for this part on side. See IRedstoneConnector for mask definition
*/
def getConnectionMask(side:Int):Int
}
/**
* Interface for tile entities which split their redstone connections into a mask for each side (edges and center)
*
* All connection masks are a 5 bit map.
* The lowest 4 bits correspond to the connection toward the face specified Rotation.rotateSide(side&6, b) where b is the bit index from lowest to highest.
* Bit 5 corresponds to a connection opposite side.
*/
trait IRedstoneConnector
{
/**
* Returns the redstone connection mask for this tile on side.
*/
def getConnectionMask(side:Int):Int
/**
* Returns the weak power level provided by this tile on side through mask
*/
def weakPowerLevel(side:Int, mask:Int):Int
}
/**
* Internal interface for TileMultipart instances hosting IRedstonePart
*/
trait IRedstoneTile extends IRedstoneConnector
{
/**
* Returns a mask of spaces through which a wire could connect on side
*/
def openConnections(side:Int):Int
}
/**
* Block version of IRedstoneConnector
*/
trait IRedstoneConnectorBlock
{
def getConnectionMask(world:IBlockAccess, x:Int, y:Int, z:Int, side:Int):Int
def weakPowerLevel(world:IBlockAccess, x:Int, y:Int, z:Int, side:Int, mask:Int):Int
}
/**
* static helper class for calculating various things about redstone.
* Indirect power (also known as strong power) is not handled here, just use world.getIndirectPowerTo
* Masks are defined in IRedstoneConnector
*/
object RedstoneInteractions
{
import net.minecraft.util.Facing._
val vanillaSideMap = Array(-2, -1, 0, 2, 3, 1)
val sideVanillaMap = Array(1, 2, 5, 3, 4)
/**
* Get the direct power to p on side
*/
def getPowerTo(p:TMultiPart, side:Int):Int =
{
val tile = p.tile
return getPowerTo(tile.worldObj, tile.xCoord, tile.yCoord, tile.zCoord, side,
tile.asInstanceOf[IRedstoneTile].openConnections(side)&connectionMask(p, side))
}
/**
* Get the direct power level to space (x, y, z) on side with mask
*/
def getPowerTo(world:World, x:Int, y:Int, z:Int, side:Int, mask:Int):Int =
getPower(world, x+offsetsXForSide(side), y+offsetsYForSide(side), z+offsetsZForSide(side), side^1, mask)
/**
* Get the direct power level provided by space (x, y, z) on side with mask
*/
def getPower(world:World, x:Int, y:Int, z:Int, side:Int, mask:Int):Int =
{
val tile = world.getBlockTileEntity(x, y, z)
if(tile.isInstanceOf[IRedstoneConnector])
return tile.asInstanceOf[IRedstoneConnector].weakPowerLevel(side, mask)
val block = Block.blocksList(world.getBlockId(x, y, z))
if(block == null)
return 0
if(block.isInstanceOf[IRedstoneConnectorBlock])
return block.asInstanceOf[IRedstoneConnectorBlock].weakPowerLevel(world, x, y, z, side, mask)
val vmask = vanillaConnectionMask(block, world, x, y, z, side, true)
if((vmask&mask) > 0)
{
var m = world.getIndirectPowerLevelTo(x, y, z, side^1)
if(m < 15 && block == Block.redstoneWire)
m = Math.max(m, world.getBlockMetadata(x, y, z))//painful vanilla kludge
return m
}
return 0
}
def vanillaToSide(vside:Int) = sideVanillaMap(vside+1)
/**
* Get the connection mask of the block on side of (x, y, z).
* @param power, whether the connection mask is for signal transfer or visual connection. (some blocks accept power without visual connection)
*/
def otherConnectionMask(world:IBlockAccess, x:Int, y:Int, z:Int, side:Int, power:Boolean):Int =
getConnectionMask(world, x+offsetsXForSide(side), y+offsetsYForSide(side), z+offsetsZForSide(side), side^1, power)
/**
* Get the connection mask of part on side
*/
def connectionMask(p:TMultiPart, side:Int):Int =
{
if(p.isInstanceOf[IRedstonePart] && p.asInstanceOf[IRedstonePart].canConnectRedstone(side))
{
if(p.isInstanceOf[IFaceRedstonePart])
{
val fside = p.asInstanceOf[IFaceRedstonePart].getFace
if((side&6) == (fside&6))
return 0x10
return 1<<rotationTo(side&6, fside)
}
else if(p.isInstanceOf[IMaskedRedstonePart])
{
return p.asInstanceOf[IMaskedRedstonePart].getConnectionMask(side)
}
return 0x1F
}
return 0
}
/**
* @param power If true, don't test canConnectRedstone on blocks, just get a power transmission mask rather than a visual connection
*/
def getConnectionMask(world:IBlockAccess, x:Int, y:Int, z:Int, side:Int, power:Boolean):Int =
{
val tile = world.getBlockTileEntity(x, y, z)
if(tile.isInstanceOf[IRedstoneConnector])
return tile.asInstanceOf[IRedstoneConnector].getConnectionMask(side)
val block = Block.blocksList(world.getBlockId(x, y, z))
if(block == null)
return 0
if(block.isInstanceOf[IRedstoneConnectorBlock])
return block.asInstanceOf[IRedstoneConnectorBlock].getConnectionMask(world, x, y, z, side)
return vanillaConnectionMask(block, world, x, y, z, side, power)
}
/**
* Returns the connection mask for a vanilla block
*/
def vanillaConnectionMask(block:Block, world:IBlockAccess, x:Int, y:Int, z:Int, side:Int, power:Boolean):Int =
{
if(block == Block.torchRedstoneActive || block == Block.torchRedstoneIdle || block == Block.lever || block == Block.stoneButton || block == Block.woodenButton)
return 0x1F
if(side == 0)//vanilla doesn't handle side 0
{
if(power)
return 0x1F
return 0
}
if(block == Block.redstoneWire)
{
if(side != 1)
return 4
return 0x1F
}
if(block == Block.redstoneComparatorActive || block == Block.redstoneComparatorIdle)
{
if(side != 1)
return 4
return 0
}
val vside = vanillaSideMap(side)
if(block == Block.redstoneRepeaterActive || block == Block.redstoneRepeaterIdle)//stupid minecraft hardcodes
{
val meta = world.getBlockMetadata(x, y, z)
if(vside == (meta & 3) || vside == Direction.rotateOpposite(meta & 3))
return 4
return 0
}
if(power || block.canConnectRedstone(world, x, y, z, vside))//some blocks accept power without visualising connections
return 0x1F
return 0
}
}