001 package net.minecraft.src; 002 003 import cpw.mods.fml.common.Side; 004 import cpw.mods.fml.common.asm.SideOnly; 005 import java.util.Random; 006 007 public class BlockRedstoneRepeater extends BlockDirectional 008 { 009 /** The offsets for the two torches in redstone repeater blocks. */ 010 public static final double[] repeaterTorchOffset = new double[] { -0.0625D, 0.0625D, 0.1875D, 0.3125D}; 011 012 /** The states in which the redstone repeater blocks can be. */ 013 private static final int[] repeaterState = new int[] {1, 2, 3, 4}; 014 015 /** Tells whether the repeater is powered or not */ 016 private final boolean isRepeaterPowered; 017 018 protected BlockRedstoneRepeater(int par1, boolean par2) 019 { 020 super(par1, 6, Material.circuits); 021 this.isRepeaterPowered = par2; 022 this.setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 0.125F, 1.0F); 023 } 024 025 /** 026 * If this block doesn't render as an ordinary block it will return False (examples: signs, buttons, stairs, etc) 027 */ 028 public boolean renderAsNormalBlock() 029 { 030 return false; 031 } 032 033 /** 034 * Checks to see if its valid to put this block at the specified coordinates. Args: world, x, y, z 035 */ 036 public boolean canPlaceBlockAt(World par1World, int par2, int par3, int par4) 037 { 038 return !par1World.doesBlockHaveSolidTopSurface(par2, par3 - 1, par4) ? false : super.canPlaceBlockAt(par1World, par2, par3, par4); 039 } 040 041 /** 042 * Can this block stay at this position. Similar to canPlaceBlockAt except gets checked often with plants. 043 */ 044 public boolean canBlockStay(World par1World, int par2, int par3, int par4) 045 { 046 return !par1World.doesBlockHaveSolidTopSurface(par2, par3 - 1, par4) ? false : super.canBlockStay(par1World, par2, par3, par4); 047 } 048 049 /** 050 * Ticks the block if it's been scheduled 051 */ 052 public void updateTick(World par1World, int par2, int par3, int par4, Random par5Random) 053 { 054 int var6 = par1World.getBlockMetadata(par2, par3, par4); 055 boolean var7 = this.ignoreTick(par1World, par2, par3, par4, var6); 056 057 if (this.isRepeaterPowered && !var7) 058 { 059 par1World.setBlockAndMetadataWithNotify(par2, par3, par4, Block.redstoneRepeaterIdle.blockID, var6); 060 } 061 else if (!this.isRepeaterPowered) 062 { 063 par1World.setBlockAndMetadataWithNotify(par2, par3, par4, Block.redstoneRepeaterActive.blockID, var6); 064 065 if (!var7) 066 { 067 int var8 = (var6 & 12) >> 2; 068 par1World.scheduleBlockUpdate(par2, par3, par4, Block.redstoneRepeaterActive.blockID, repeaterState[var8] * 2); 069 } 070 } 071 } 072 073 /** 074 * From the specified side and block metadata retrieves the blocks texture. Args: side, metadata 075 */ 076 public int getBlockTextureFromSideAndMetadata(int par1, int par2) 077 { 078 return par1 == 0 ? (this.isRepeaterPowered ? 99 : 115) : (par1 == 1 ? (this.isRepeaterPowered ? 147 : 131) : 5); 079 } 080 081 @SideOnly(Side.CLIENT) 082 083 /** 084 * Returns true if the given side of this block type should be rendered, if the adjacent block is at the given 085 * coordinates. Args: blockAccess, x, y, z, side 086 */ 087 public boolean shouldSideBeRendered(IBlockAccess par1IBlockAccess, int par2, int par3, int par4, int par5) 088 { 089 return par5 != 0 && par5 != 1; 090 } 091 092 /** 093 * The type of render function that is called for this block 094 */ 095 public int getRenderType() 096 { 097 return 15; 098 } 099 100 /** 101 * Returns the block texture based on the side being looked at. Args: side 102 */ 103 public int getBlockTextureFromSide(int par1) 104 { 105 return this.getBlockTextureFromSideAndMetadata(par1, 0); 106 } 107 108 /** 109 * Is this block indirectly powering the block on the specified side 110 */ 111 public boolean isIndirectlyPoweringTo(World par1World, int par2, int par3, int par4, int par5) 112 { 113 return this.isPoweringTo(par1World, par2, par3, par4, par5); 114 } 115 116 /** 117 * Is this block powering the block on the specified side 118 */ 119 public boolean isPoweringTo(IBlockAccess par1IBlockAccess, int par2, int par3, int par4, int par5) 120 { 121 if (!this.isRepeaterPowered) 122 { 123 return false; 124 } 125 else 126 { 127 int var6 = getDirection(par1IBlockAccess.getBlockMetadata(par2, par3, par4)); 128 return var6 == 0 && par5 == 3 ? true : (var6 == 1 && par5 == 4 ? true : (var6 == 2 && par5 == 2 ? true : var6 == 3 && par5 == 5)); 129 } 130 } 131 132 /** 133 * Lets the block know when one of its neighbor changes. Doesn't know which neighbor changed (coordinates passed are 134 * their own) Args: x, y, z, neighbor blockID 135 */ 136 public void onNeighborBlockChange(World par1World, int par2, int par3, int par4, int par5) 137 { 138 if (!this.canBlockStay(par1World, par2, par3, par4)) 139 { 140 this.dropBlockAsItem(par1World, par2, par3, par4, par1World.getBlockMetadata(par2, par3, par4), 0); 141 par1World.setBlockWithNotify(par2, par3, par4, 0); 142 par1World.notifyBlocksOfNeighborChange(par2 + 1, par3, par4, this.blockID); 143 par1World.notifyBlocksOfNeighborChange(par2 - 1, par3, par4, this.blockID); 144 par1World.notifyBlocksOfNeighborChange(par2, par3, par4 + 1, this.blockID); 145 par1World.notifyBlocksOfNeighborChange(par2, par3, par4 - 1, this.blockID); 146 par1World.notifyBlocksOfNeighborChange(par2, par3 - 1, par4, this.blockID); 147 par1World.notifyBlocksOfNeighborChange(par2, par3 + 1, par4, this.blockID); 148 } 149 else 150 { 151 int var6 = par1World.getBlockMetadata(par2, par3, par4); 152 boolean var7 = this.ignoreTick(par1World, par2, par3, par4, var6); 153 int var8 = (var6 & 12) >> 2; 154 155 if (this.isRepeaterPowered && !var7 || !this.isRepeaterPowered && var7) 156 { 157 par1World.scheduleBlockUpdate(par2, par3, par4, this.blockID, repeaterState[var8] * 2); 158 } 159 } 160 } 161 162 private boolean ignoreTick(World par1World, int par2, int par3, int par4, int par5) 163 { 164 int var6 = getDirection(par5); 165 166 switch (var6) 167 { 168 case 0: 169 return par1World.isBlockIndirectlyProvidingPowerTo(par2, par3, par4 + 1, 3) || par1World.getBlockId(par2, par3, par4 + 1) == Block.redstoneWire.blockID && par1World.getBlockMetadata(par2, par3, par4 + 1) > 0; 170 case 1: 171 return par1World.isBlockIndirectlyProvidingPowerTo(par2 - 1, par3, par4, 4) || par1World.getBlockId(par2 - 1, par3, par4) == Block.redstoneWire.blockID && par1World.getBlockMetadata(par2 - 1, par3, par4) > 0; 172 case 2: 173 return par1World.isBlockIndirectlyProvidingPowerTo(par2, par3, par4 - 1, 2) || par1World.getBlockId(par2, par3, par4 - 1) == Block.redstoneWire.blockID && par1World.getBlockMetadata(par2, par3, par4 - 1) > 0; 174 case 3: 175 return par1World.isBlockIndirectlyProvidingPowerTo(par2 + 1, par3, par4, 5) || par1World.getBlockId(par2 + 1, par3, par4) == Block.redstoneWire.blockID && par1World.getBlockMetadata(par2 + 1, par3, par4) > 0; 176 default: 177 return false; 178 } 179 } 180 181 /** 182 * Called upon block activation (right click on the block.) 183 */ 184 public boolean onBlockActivated(World par1World, int par2, int par3, int par4, EntityPlayer par5EntityPlayer, int par6, float par7, float par8, float par9) 185 { 186 int var10 = par1World.getBlockMetadata(par2, par3, par4); 187 int var11 = (var10 & 12) >> 2; 188 var11 = var11 + 1 << 2 & 12; 189 par1World.setBlockMetadataWithNotify(par2, par3, par4, var11 | var10 & 3); 190 return true; 191 } 192 193 /** 194 * Can this block provide power. Only wire currently seems to have this change based on its state. 195 */ 196 public boolean canProvidePower() 197 { 198 return true; 199 } 200 201 /** 202 * Called when the block is placed in the world. 203 */ 204 public void onBlockPlacedBy(World par1World, int par2, int par3, int par4, EntityLiving par5EntityLiving) 205 { 206 int var6 = ((MathHelper.floor_double((double)(par5EntityLiving.rotationYaw * 4.0F / 360.0F) + 0.5D) & 3) + 2) % 4; 207 par1World.setBlockMetadataWithNotify(par2, par3, par4, var6); 208 boolean var7 = this.ignoreTick(par1World, par2, par3, par4, var6); 209 210 if (var7) 211 { 212 par1World.scheduleBlockUpdate(par2, par3, par4, this.blockID, 1); 213 } 214 } 215 216 /** 217 * Called whenever the block is added into the world. Args: world, x, y, z 218 */ 219 public void onBlockAdded(World par1World, int par2, int par3, int par4) 220 { 221 par1World.notifyBlocksOfNeighborChange(par2 + 1, par3, par4, this.blockID); 222 par1World.notifyBlocksOfNeighborChange(par2 - 1, par3, par4, this.blockID); 223 par1World.notifyBlocksOfNeighborChange(par2, par3, par4 + 1, this.blockID); 224 par1World.notifyBlocksOfNeighborChange(par2, par3, par4 - 1, this.blockID); 225 par1World.notifyBlocksOfNeighborChange(par2, par3 - 1, par4, this.blockID); 226 par1World.notifyBlocksOfNeighborChange(par2, par3 + 1, par4, this.blockID); 227 } 228 229 /** 230 * Called right before the block is destroyed by a player. Args: world, x, y, z, metaData 231 */ 232 public void onBlockDestroyedByPlayer(World par1World, int par2, int par3, int par4, int par5) 233 { 234 if (this.isRepeaterPowered) 235 { 236 par1World.notifyBlocksOfNeighborChange(par2 + 1, par3, par4, this.blockID); 237 par1World.notifyBlocksOfNeighborChange(par2 - 1, par3, par4, this.blockID); 238 par1World.notifyBlocksOfNeighborChange(par2, par3, par4 + 1, this.blockID); 239 par1World.notifyBlocksOfNeighborChange(par2, par3, par4 - 1, this.blockID); 240 par1World.notifyBlocksOfNeighborChange(par2, par3 - 1, par4, this.blockID); 241 par1World.notifyBlocksOfNeighborChange(par2, par3 + 1, par4, this.blockID); 242 } 243 244 super.onBlockDestroyedByPlayer(par1World, par2, par3, par4, par5); 245 } 246 247 /** 248 * Is this block (a) opaque and (b) a full 1m cube? This determines whether or not to render the shared face of two 249 * adjacent blocks and also whether the player can attach torches, redstone wire, etc to this block. 250 */ 251 public boolean isOpaqueCube() 252 { 253 return false; 254 } 255 256 /** 257 * Returns the ID of the items to drop on destruction. 258 */ 259 public int idDropped(int par1, Random par2Random, int par3) 260 { 261 return Item.redstoneRepeater.shiftedIndex; 262 } 263 264 @SideOnly(Side.CLIENT) 265 266 /** 267 * A randomly called display update to be able to add particles or other items for display 268 */ 269 public void randomDisplayTick(World par1World, int par2, int par3, int par4, Random par5Random) 270 { 271 if (this.isRepeaterPowered) 272 { 273 int var6 = par1World.getBlockMetadata(par2, par3, par4); 274 int var7 = getDirection(var6); 275 double var8 = (double)((float)par2 + 0.5F) + (double)(par5Random.nextFloat() - 0.5F) * 0.2D; 276 double var10 = (double)((float)par3 + 0.4F) + (double)(par5Random.nextFloat() - 0.5F) * 0.2D; 277 double var12 = (double)((float)par4 + 0.5F) + (double)(par5Random.nextFloat() - 0.5F) * 0.2D; 278 double var14 = 0.0D; 279 double var16 = 0.0D; 280 281 if (par5Random.nextInt(2) == 0) 282 { 283 switch (var7) 284 { 285 case 0: 286 var16 = -0.3125D; 287 break; 288 case 1: 289 var14 = 0.3125D; 290 break; 291 case 2: 292 var16 = 0.3125D; 293 break; 294 case 3: 295 var14 = -0.3125D; 296 } 297 } 298 else 299 { 300 int var18 = (var6 & 12) >> 2; 301 302 switch (var7) 303 { 304 case 0: 305 var16 = repeaterTorchOffset[var18]; 306 break; 307 case 1: 308 var14 = -repeaterTorchOffset[var18]; 309 break; 310 case 2: 311 var16 = -repeaterTorchOffset[var18]; 312 break; 313 case 3: 314 var14 = repeaterTorchOffset[var18]; 315 } 316 } 317 318 par1World.spawnParticle("reddust", var8 + var14, var10, var12 + var16, 0.0D, 0.0D, 0.0D); 319 } 320 } 321 322 @SideOnly(Side.CLIENT) 323 324 /** 325 * only called by clickMiddleMouseButton , and passed to inventory.setCurrentItem (along with isCreative) 326 */ 327 public int idPicked(World par1World, int par2, int par3, int par4) 328 { 329 return Item.redstoneRepeater.shiftedIndex; 330 } 331 }