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.func_82523_e(par1World, par2, par3, par4, var6); 056 057 if (!var7) 058 { 059 boolean var8 = this.ignoreTick(par1World, par2, par3, par4, var6); 060 061 if (this.isRepeaterPowered && !var8) 062 { 063 par1World.setBlockAndMetadataWithNotify(par2, par3, par4, Block.redstoneRepeaterIdle.blockID, var6); 064 } 065 else if (!this.isRepeaterPowered) 066 { 067 par1World.setBlockAndMetadataWithNotify(par2, par3, par4, Block.redstoneRepeaterActive.blockID, var6); 068 069 if (!var8) 070 { 071 int var9 = (var6 & 12) >> 2; 072 par1World.scheduleBlockUpdate(par2, par3, par4, Block.redstoneRepeaterActive.blockID, repeaterState[var9] * 2); 073 } 074 } 075 } 076 } 077 078 /** 079 * From the specified side and block metadata retrieves the blocks texture. Args: side, metadata 080 */ 081 public int getBlockTextureFromSideAndMetadata(int par1, int par2) 082 { 083 return par1 == 0 ? (this.isRepeaterPowered ? 99 : 115) : (par1 == 1 ? (this.isRepeaterPowered ? 147 : 131) : 5); 084 } 085 086 @SideOnly(Side.CLIENT) 087 088 /** 089 * Returns true if the given side of this block type should be rendered, if the adjacent block is at the given 090 * coordinates. Args: blockAccess, x, y, z, side 091 */ 092 public boolean shouldSideBeRendered(IBlockAccess par1IBlockAccess, int par2, int par3, int par4, int par5) 093 { 094 return par5 != 0 && par5 != 1; 095 } 096 097 /** 098 * The type of render function that is called for this block 099 */ 100 public int getRenderType() 101 { 102 return 15; 103 } 104 105 /** 106 * Returns the block texture based on the side being looked at. Args: side 107 */ 108 public int getBlockTextureFromSide(int par1) 109 { 110 return this.getBlockTextureFromSideAndMetadata(par1, 0); 111 } 112 113 /** 114 * Returns true if the block is emitting direct/strong redstone power on the specified side. Args: World, X, Y, Z, 115 * side 116 */ 117 public boolean isProvidingStrongPower(IBlockAccess par1IBlockAccess, int par2, int par3, int par4, int par5) 118 { 119 return this.isProvidingWeakPower(par1IBlockAccess, par2, par3, par4, par5); 120 } 121 122 /** 123 * Returns true if the block is emitting indirect/weak redstone power on the specified side. If isBlockNormalCube 124 * returns true, standard redstone propagation rules will apply instead and this will not be called. Args: World, X, 125 * Y, Z, side 126 */ 127 public boolean isProvidingWeakPower(IBlockAccess par1IBlockAccess, int par2, int par3, int par4, int par5) 128 { 129 if (!this.isRepeaterPowered) 130 { 131 return false; 132 } 133 else 134 { 135 int var6 = getDirection(par1IBlockAccess.getBlockMetadata(par2, par3, par4)); 136 return var6 == 0 && par5 == 3 ? true : (var6 == 1 && par5 == 4 ? true : (var6 == 2 && par5 == 2 ? true : var6 == 3 && par5 == 5)); 137 } 138 } 139 140 /** 141 * Lets the block know when one of its neighbor changes. Doesn't know which neighbor changed (coordinates passed are 142 * their own) Args: x, y, z, neighbor blockID 143 */ 144 public void onNeighborBlockChange(World par1World, int par2, int par3, int par4, int par5) 145 { 146 if (!this.canBlockStay(par1World, par2, par3, par4)) 147 { 148 this.dropBlockAsItem(par1World, par2, par3, par4, par1World.getBlockMetadata(par2, par3, par4), 0); 149 par1World.setBlockWithNotify(par2, par3, par4, 0); 150 par1World.notifyBlocksOfNeighborChange(par2 + 1, par3, par4, this.blockID); 151 par1World.notifyBlocksOfNeighborChange(par2 - 1, par3, par4, this.blockID); 152 par1World.notifyBlocksOfNeighborChange(par2, par3, par4 + 1, this.blockID); 153 par1World.notifyBlocksOfNeighborChange(par2, par3, par4 - 1, this.blockID); 154 par1World.notifyBlocksOfNeighborChange(par2, par3 - 1, par4, this.blockID); 155 par1World.notifyBlocksOfNeighborChange(par2, par3 + 1, par4, this.blockID); 156 } 157 else 158 { 159 int var6 = par1World.getBlockMetadata(par2, par3, par4); 160 boolean var7 = this.func_82523_e(par1World, par2, par3, par4, var6); 161 162 if (!var7) 163 { 164 boolean var8 = this.ignoreTick(par1World, par2, par3, par4, var6); 165 int var9 = (var6 & 12) >> 2; 166 167 if (this.isRepeaterPowered && !var8 || !this.isRepeaterPowered && var8) 168 { 169 byte var10 = 0; 170 171 if (this.func_83011_d(par1World, par2, par3, par4, var6)) 172 { 173 var10 = -1; 174 } 175 176 par1World.func_82740_a(par2, par3, par4, this.blockID, repeaterState[var9] * 2, var10); 177 } 178 } 179 } 180 } 181 182 private boolean ignoreTick(World par1World, int par2, int par3, int par4, int par5) 183 { 184 int var6 = getDirection(par5); 185 186 switch (var6) 187 { 188 case 0: 189 return par1World.isBlockIndirectlyProvidingPowerTo(par2, par3, par4 + 1, 3) || par1World.getBlockId(par2, par3, par4 + 1) == Block.redstoneWire.blockID && par1World.getBlockMetadata(par2, par3, par4 + 1) > 0; 190 case 1: 191 return par1World.isBlockIndirectlyProvidingPowerTo(par2 - 1, par3, par4, 4) || par1World.getBlockId(par2 - 1, par3, par4) == Block.redstoneWire.blockID && par1World.getBlockMetadata(par2 - 1, par3, par4) > 0; 192 case 2: 193 return par1World.isBlockIndirectlyProvidingPowerTo(par2, par3, par4 - 1, 2) || par1World.getBlockId(par2, par3, par4 - 1) == Block.redstoneWire.blockID && par1World.getBlockMetadata(par2, par3, par4 - 1) > 0; 194 case 3: 195 return par1World.isBlockIndirectlyProvidingPowerTo(par2 + 1, par3, par4, 5) || par1World.getBlockId(par2 + 1, par3, par4) == Block.redstoneWire.blockID && par1World.getBlockMetadata(par2 + 1, par3, par4) > 0; 196 default: 197 return false; 198 } 199 } 200 201 public boolean func_82523_e(IBlockAccess par1IBlockAccess, int par2, int par3, int par4, int par5) 202 { 203 int var6 = getDirection(par5); 204 205 switch (var6) 206 { 207 case 0: 208 case 2: 209 return par1IBlockAccess.isBlockProvidingPowerTo(par2 - 1, par3, par4, 4) && func_82524_c(par1IBlockAccess.getBlockId(par2 - 1, par3, par4)) || par1IBlockAccess.isBlockProvidingPowerTo(par2 + 1, par3, par4, 5) && func_82524_c(par1IBlockAccess.getBlockId(par2 + 1, par3, par4)); 210 case 1: 211 case 3: 212 return par1IBlockAccess.isBlockProvidingPowerTo(par2, par3, par4 + 1, 3) && func_82524_c(par1IBlockAccess.getBlockId(par2, par3, par4 + 1)) || par1IBlockAccess.isBlockProvidingPowerTo(par2, par3, par4 - 1, 2) && func_82524_c(par1IBlockAccess.getBlockId(par2, par3, par4 - 1)); 213 default: 214 return false; 215 } 216 } 217 218 /** 219 * Called upon block activation (right click on the block.) 220 */ 221 public boolean onBlockActivated(World par1World, int par2, int par3, int par4, EntityPlayer par5EntityPlayer, int par6, float par7, float par8, float par9) 222 { 223 int var10 = par1World.getBlockMetadata(par2, par3, par4); 224 int var11 = (var10 & 12) >> 2; 225 var11 = var11 + 1 << 2 & 12; 226 par1World.setBlockMetadataWithNotify(par2, par3, par4, var11 | var10 & 3); 227 return true; 228 } 229 230 /** 231 * Can this block provide power. Only wire currently seems to have this change based on its state. 232 */ 233 public boolean canProvidePower() 234 { 235 return true; 236 } 237 238 /** 239 * Called when the block is placed in the world. 240 */ 241 public void onBlockPlacedBy(World par1World, int par2, int par3, int par4, EntityLiving par5EntityLiving) 242 { 243 int var6 = ((MathHelper.floor_double((double)(par5EntityLiving.rotationYaw * 4.0F / 360.0F) + 0.5D) & 3) + 2) % 4; 244 par1World.setBlockMetadataWithNotify(par2, par3, par4, var6); 245 boolean var7 = this.ignoreTick(par1World, par2, par3, par4, var6); 246 247 if (var7) 248 { 249 par1World.scheduleBlockUpdate(par2, par3, par4, this.blockID, 1); 250 } 251 } 252 253 /** 254 * Called whenever the block is added into the world. Args: world, x, y, z 255 */ 256 public void onBlockAdded(World par1World, int par2, int par3, int par4) 257 { 258 par1World.notifyBlocksOfNeighborChange(par2 + 1, par3, par4, this.blockID); 259 par1World.notifyBlocksOfNeighborChange(par2 - 1, par3, par4, this.blockID); 260 par1World.notifyBlocksOfNeighborChange(par2, par3, par4 + 1, this.blockID); 261 par1World.notifyBlocksOfNeighborChange(par2, par3, par4 - 1, this.blockID); 262 par1World.notifyBlocksOfNeighborChange(par2, par3 - 1, par4, this.blockID); 263 par1World.notifyBlocksOfNeighborChange(par2, par3 + 1, par4, this.blockID); 264 } 265 266 /** 267 * Called right before the block is destroyed by a player. Args: world, x, y, z, metaData 268 */ 269 public void onBlockDestroyedByPlayer(World par1World, int par2, int par3, int par4, int par5) 270 { 271 if (this.isRepeaterPowered) 272 { 273 par1World.notifyBlocksOfNeighborChange(par2 + 1, par3, par4, this.blockID); 274 par1World.notifyBlocksOfNeighborChange(par2 - 1, par3, par4, this.blockID); 275 par1World.notifyBlocksOfNeighborChange(par2, par3, par4 + 1, this.blockID); 276 par1World.notifyBlocksOfNeighborChange(par2, par3, par4 - 1, this.blockID); 277 par1World.notifyBlocksOfNeighborChange(par2, par3 - 1, par4, this.blockID); 278 par1World.notifyBlocksOfNeighborChange(par2, par3 + 1, par4, this.blockID); 279 } 280 281 super.onBlockDestroyedByPlayer(par1World, par2, par3, par4, par5); 282 } 283 284 /** 285 * Is this block (a) opaque and (b) a full 1m cube? This determines whether or not to render the shared face of two 286 * adjacent blocks and also whether the player can attach torches, redstone wire, etc to this block. 287 */ 288 public boolean isOpaqueCube() 289 { 290 return false; 291 } 292 293 /** 294 * Returns the ID of the items to drop on destruction. 295 */ 296 public int idDropped(int par1, Random par2Random, int par3) 297 { 298 return Item.redstoneRepeater.shiftedIndex; 299 } 300 301 @SideOnly(Side.CLIENT) 302 303 /** 304 * A randomly called display update to be able to add particles or other items for display 305 */ 306 public void randomDisplayTick(World par1World, int par2, int par3, int par4, Random par5Random) 307 { 308 if (this.isRepeaterPowered) 309 { 310 int var6 = par1World.getBlockMetadata(par2, par3, par4); 311 int var7 = getDirection(var6); 312 double var8 = (double)((float)par2 + 0.5F) + (double)(par5Random.nextFloat() - 0.5F) * 0.2D; 313 double var10 = (double)((float)par3 + 0.4F) + (double)(par5Random.nextFloat() - 0.5F) * 0.2D; 314 double var12 = (double)((float)par4 + 0.5F) + (double)(par5Random.nextFloat() - 0.5F) * 0.2D; 315 double var14 = 0.0D; 316 double var16 = 0.0D; 317 318 if (par5Random.nextInt(2) == 0) 319 { 320 switch (var7) 321 { 322 case 0: 323 var16 = -0.3125D; 324 break; 325 case 1: 326 var14 = 0.3125D; 327 break; 328 case 2: 329 var16 = 0.3125D; 330 break; 331 case 3: 332 var14 = -0.3125D; 333 } 334 } 335 else 336 { 337 int var18 = (var6 & 12) >> 2; 338 339 switch (var7) 340 { 341 case 0: 342 var16 = repeaterTorchOffset[var18]; 343 break; 344 case 1: 345 var14 = -repeaterTorchOffset[var18]; 346 break; 347 case 2: 348 var16 = -repeaterTorchOffset[var18]; 349 break; 350 case 3: 351 var14 = repeaterTorchOffset[var18]; 352 } 353 } 354 355 par1World.spawnParticle("reddust", var8 + var14, var10, var12 + var16, 0.0D, 0.0D, 0.0D); 356 } 357 } 358 359 @SideOnly(Side.CLIENT) 360 361 /** 362 * only called by clickMiddleMouseButton , and passed to inventory.setCurrentItem (along with isCreative) 363 */ 364 public int idPicked(World par1World, int par2, int par3, int par4) 365 { 366 return Item.redstoneRepeater.shiftedIndex; 367 } 368 369 public static boolean func_82524_c(int par0) 370 { 371 return par0 == Block.redstoneRepeaterActive.blockID || par0 == Block.redstoneRepeaterIdle.blockID; 372 } 373 374 public boolean func_83011_d(World par1World, int par2, int par3, int par4, int par5) 375 { 376 int var6 = getDirection(par5); 377 378 if (func_82524_c(par1World.getBlockId(par2 - Direction.offsetX[var6], par3, par4 - Direction.offsetZ[var6]))) 379 { 380 int var7 = par1World.getBlockMetadata(par2 - Direction.offsetX[var6], par3, par4 - Direction.offsetZ[var6]); 381 int var8 = getDirection(var7); 382 return var8 != var6; 383 } 384 else 385 { 386 return false; 387 } 388 } 389 }