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