001package net.minecraft.block; 002 003import cpw.mods.fml.relauncher.Side; 004import cpw.mods.fml.relauncher.SideOnly; 005import java.util.Random; 006import net.minecraft.block.material.Material; 007import net.minecraft.client.renderer.texture.IconRegister; 008import net.minecraft.entity.EntityLiving; 009import net.minecraft.item.ItemStack; 010import net.minecraft.util.Direction; 011import net.minecraft.util.Icon; 012import net.minecraft.util.MathHelper; 013import net.minecraft.world.IBlockAccess; 014import net.minecraft.world.World; 015 016public abstract class BlockRedstoneLogic extends BlockDirectional 017{ 018 /** Tells whether the repeater is powered or not */ 019 protected final boolean isRepeaterPowered; 020 021 protected BlockRedstoneLogic(int par1, boolean par2) 022 { 023 super(par1, Material.circuits); 024 this.isRepeaterPowered = par2; 025 this.setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 0.125F, 1.0F); 026 } 027 028 /** 029 * If this block doesn't render as an ordinary block it will return False (examples: signs, buttons, stairs, etc) 030 */ 031 public boolean renderAsNormalBlock() 032 { 033 return false; 034 } 035 036 /** 037 * Checks to see if its valid to put this block at the specified coordinates. Args: world, x, y, z 038 */ 039 public boolean canPlaceBlockAt(World par1World, int par2, int par3, int par4) 040 { 041 return !par1World.doesBlockHaveSolidTopSurface(par2, par3 - 1, par4) ? false : super.canPlaceBlockAt(par1World, par2, par3, par4); 042 } 043 044 /** 045 * Can this block stay at this position. Similar to canPlaceBlockAt except gets checked often with plants. 046 */ 047 public boolean canBlockStay(World par1World, int par2, int par3, int par4) 048 { 049 return !par1World.doesBlockHaveSolidTopSurface(par2, par3 - 1, par4) ? false : super.canBlockStay(par1World, par2, par3, par4); 050 } 051 052 /** 053 * Ticks the block if it's been scheduled 054 */ 055 public void updateTick(World par1World, int par2, int par3, int par4, Random par5Random) 056 { 057 int l = par1World.getBlockMetadata(par2, par3, par4); 058 059 if (!this.func_94476_e(par1World, par2, par3, par4, l)) 060 { 061 boolean flag = this.func_94478_d(par1World, par2, par3, par4, l); 062 063 if (this.isRepeaterPowered && !flag) 064 { 065 par1World.setBlockAndMetadataWithNotify(par2, par3, par4, this.func_94484_i().blockID, l, 2); 066 } 067 else if (!this.isRepeaterPowered) 068 { 069 par1World.setBlockAndMetadataWithNotify(par2, par3, par4, this.func_94485_e().blockID, l, 2); 070 071 if (!flag) 072 { 073 par1World.func_82740_a(par2, par3, par4, this.func_94485_e().blockID, this.func_94486_g(l), -1); 074 } 075 } 076 } 077 } 078 079 @SideOnly(Side.CLIENT) 080 081 /** 082 * From the specified side and block metadata retrieves the blocks texture. Args: side, metadata 083 */ 084 public Icon getBlockTextureFromSideAndMetadata(int par1, int par2) 085 { 086 return par1 == 0 ? (this.isRepeaterPowered ? Block.torchRedstoneActive.getBlockTextureFromSide(par1) : Block.torchRedstoneIdle.getBlockTextureFromSide(par1)) : (par1 == 1 ? this.field_94336_cN : Block.stoneDoubleSlab.getBlockTextureFromSide(1)); 087 } 088 089 @SideOnly(Side.CLIENT) 090 public void func_94332_a(IconRegister par1IconRegister) 091 { 092 this.field_94336_cN = par1IconRegister.func_94245_a(this.isRepeaterPowered ? "repeater_lit" : "repeater"); 093 } 094 095 @SideOnly(Side.CLIENT) 096 097 /** 098 * Returns true if the given side of this block type should be rendered, if the adjacent block is at the given 099 * coordinates. Args: blockAccess, x, y, z, side 100 */ 101 public boolean shouldSideBeRendered(IBlockAccess par1IBlockAccess, int par2, int par3, int par4, int par5) 102 { 103 return par5 != 0 && par5 != 1; 104 } 105 106 /** 107 * The type of render function that is called for this block 108 */ 109 public int getRenderType() 110 { 111 return 36; 112 } 113 114 protected boolean func_96470_c(int par1) 115 { 116 return this.isRepeaterPowered; 117 } 118 119 /** 120 * Returns true if the block is emitting direct/strong redstone power on the specified side. Args: World, X, Y, Z, 121 * side. Note that the side is reversed - eg it is 1 (up) when checking the bottom of the block. 122 */ 123 public int isProvidingStrongPower(IBlockAccess par1IBlockAccess, int par2, int par3, int par4, int par5) 124 { 125 return this.isProvidingWeakPower(par1IBlockAccess, par2, par3, par4, par5); 126 } 127 128 /** 129 * Returns true if the block is emitting indirect/weak redstone power on the specified side. If isBlockNormalCube 130 * returns true, standard redstone propagation rules will apply instead and this will not be called. Args: World, X, 131 * Y, Z, side. Note that the side is reversed - eg it is 1 (up) when checking the bottom of the block. 132 */ 133 public int isProvidingWeakPower(IBlockAccess par1IBlockAccess, int par2, int par3, int par4, int par5) 134 { 135 int i1 = par1IBlockAccess.getBlockMetadata(par2, par3, par4); 136 137 if (!this.func_96470_c(i1)) 138 { 139 return 0; 140 } 141 else 142 { 143 int j1 = getDirection(i1); 144 return j1 == 0 && par5 == 3 ? this.func_94480_d(par1IBlockAccess, par2, par3, par4, i1) : (j1 == 1 && par5 == 4 ? this.func_94480_d(par1IBlockAccess, par2, par3, par4, i1) : (j1 == 2 && par5 == 2 ? this.func_94480_d(par1IBlockAccess, par2, par3, par4, i1) : (j1 == 3 && par5 == 5 ? this.func_94480_d(par1IBlockAccess, par2, par3, par4, i1) : 0))); 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.func_94571_i(par2, par3, par4); 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 this.func_94479_f(par1World, par2, par3, par4, par5); 168 } 169 } 170 171 protected void func_94479_f(World par1World, int par2, int par3, int par4, int par5) 172 { 173 int i1 = par1World.getBlockMetadata(par2, par3, par4); 174 175 if (!this.func_94476_e(par1World, par2, par3, par4, i1)) 176 { 177 boolean flag = this.func_94478_d(par1World, par2, par3, par4, i1); 178 179 if ((this.isRepeaterPowered && !flag || !this.isRepeaterPowered && flag) && !par1World.func_94573_a(par2, par3, par4, this.blockID)) 180 { 181 byte b0 = -1; 182 183 if (this.func_83011_d(par1World, par2, par3, par4, i1)) 184 { 185 b0 = -3; 186 } 187 else if (this.isRepeaterPowered) 188 { 189 b0 = -2; 190 } 191 192 par1World.func_82740_a(par2, par3, par4, this.blockID, this.func_94481_j_(i1), b0); 193 } 194 } 195 } 196 197 public boolean func_94476_e(IBlockAccess par1IBlockAccess, int par2, int par3, int par4, int par5) 198 { 199 return false; 200 } 201 202 protected boolean func_94478_d(World par1World, int par2, int par3, int par4, int par5) 203 { 204 return this.ignoreTick(par1World, par2, par3, par4, par5) > 0; 205 } 206 207 protected int ignoreTick(World par1World, int par2, int par3, int par4, int par5) 208 { 209 int i1 = getDirection(par5); 210 int j1 = par2 + Direction.offsetX[i1]; 211 int k1 = par4 + Direction.offsetZ[i1]; 212 int l1 = par1World.isBlockIndirectlyProvidingPowerTo(j1, par3, k1, Direction.headInvisibleFace[i1]); 213 return l1 >= 15 ? l1 : Math.max(l1, par1World.getBlockId(j1, par3, k1) == Block.redstoneWire.blockID ? par1World.getBlockMetadata(j1, par3, k1) : 0); 214 } 215 216 protected int func_94482_f(IBlockAccess par1IBlockAccess, int par2, int par3, int par4, int par5) 217 { 218 int i1 = getDirection(par5); 219 220 switch (i1) 221 { 222 case 0: 223 case 2: 224 return Math.max(this.func_94488_g(par1IBlockAccess, par2 - 1, par3, par4, 4), this.func_94488_g(par1IBlockAccess, par2 + 1, par3, par4, 5)); 225 case 1: 226 case 3: 227 return Math.max(this.func_94488_g(par1IBlockAccess, par2, par3, par4 + 1, 3), this.func_94488_g(par1IBlockAccess, par2, par3, par4 - 1, 2)); 228 default: 229 return 0; 230 } 231 } 232 233 protected int func_94488_g(IBlockAccess par1IBlockAccess, int par2, int par3, int par4, int par5) 234 { 235 int i1 = par1IBlockAccess.getBlockId(par2, par3, par4); 236 return this.func_94477_d(i1) ? (i1 == Block.redstoneWire.blockID ? par1IBlockAccess.getBlockMetadata(par2, par3, par4) : par1IBlockAccess.isBlockProvidingPowerTo(par2, par3, par4, par5)) : 0; 237 } 238 239 /** 240 * Can this block provide power. Only wire currently seems to have this change based on its state. 241 */ 242 public boolean canProvidePower() 243 { 244 return true; 245 } 246 247 /** 248 * Called when the block is placed in the world. 249 */ 250 public void onBlockPlacedBy(World par1World, int par2, int par3, int par4, EntityLiving par5EntityLiving, ItemStack par6ItemStack) 251 { 252 int l = ((MathHelper.floor_double((double)(par5EntityLiving.rotationYaw * 4.0F / 360.0F) + 0.5D) & 3) + 2) % 4; 253 par1World.setBlockMetadataWithNotify(par2, par3, par4, l, 3); 254 boolean flag = this.func_94478_d(par1World, par2, par3, par4, l); 255 256 if (flag) 257 { 258 par1World.scheduleBlockUpdate(par2, par3, par4, this.blockID, 1); 259 } 260 } 261 262 /** 263 * Called whenever the block is added into the world. Args: world, x, y, z 264 */ 265 public void onBlockAdded(World par1World, int par2, int par3, int par4) 266 { 267 this.func_94483_i_(par1World, par2, par3, par4); 268 } 269 270 protected void func_94483_i_(World par1World, int par2, int par3, int par4) 271 { 272 int l = getDirection(par1World.getBlockMetadata(par2, par3, par4)); 273 274 if (l == 1) 275 { 276 par1World.notifyBlockOfNeighborChange(par2 + 1, par3, par4, this.blockID); 277 par1World.func_96439_d(par2 + 1, par3, par4, this.blockID, 4); 278 } 279 280 if (l == 3) 281 { 282 par1World.notifyBlockOfNeighborChange(par2 - 1, par3, par4, this.blockID); 283 par1World.func_96439_d(par2 - 1, par3, par4, this.blockID, 5); 284 } 285 286 if (l == 2) 287 { 288 par1World.notifyBlockOfNeighborChange(par2, par3, par4 + 1, this.blockID); 289 par1World.func_96439_d(par2, par3, par4 + 1, this.blockID, 2); 290 } 291 292 if (l == 0) 293 { 294 par1World.notifyBlockOfNeighborChange(par2, par3, par4 - 1, this.blockID); 295 par1World.func_96439_d(par2, par3, par4 - 1, this.blockID, 3); 296 } 297 } 298 299 /** 300 * Called right before the block is destroyed by a player. Args: world, x, y, z, metaData 301 */ 302 public void onBlockDestroyedByPlayer(World par1World, int par2, int par3, int par4, int par5) 303 { 304 if (this.isRepeaterPowered) 305 { 306 par1World.notifyBlocksOfNeighborChange(par2 + 1, par3, par4, this.blockID); 307 par1World.notifyBlocksOfNeighborChange(par2 - 1, par3, par4, this.blockID); 308 par1World.notifyBlocksOfNeighborChange(par2, par3, par4 + 1, this.blockID); 309 par1World.notifyBlocksOfNeighborChange(par2, par3, par4 - 1, this.blockID); 310 par1World.notifyBlocksOfNeighborChange(par2, par3 - 1, par4, this.blockID); 311 par1World.notifyBlocksOfNeighborChange(par2, par3 + 1, par4, this.blockID); 312 } 313 314 super.onBlockDestroyedByPlayer(par1World, par2, par3, par4, par5); 315 } 316 317 /** 318 * Is this block (a) opaque and (b) a full 1m cube? This determines whether or not to render the shared face of two 319 * adjacent blocks and also whether the player can attach torches, redstone wire, etc to this block. 320 */ 321 public boolean isOpaqueCube() 322 { 323 return false; 324 } 325 326 protected boolean func_94477_d(int par1) 327 { 328 Block block = Block.blocksList[par1]; 329 return block != null && block.canProvidePower(); 330 } 331 332 protected int func_94480_d(IBlockAccess par1IBlockAccess, int par2, int par3, int par4, int par5) 333 { 334 return 15; 335 } 336 337 public static boolean isRedstoneRepeaterBlockID(int par0) 338 { 339 return Block.redstoneRepeaterIdle.func_94487_f(par0) || Block.field_94346_cn.func_94487_f(par0); 340 } 341 342 public boolean func_94487_f(int par1) 343 { 344 return par1 == this.func_94485_e().blockID || par1 == this.func_94484_i().blockID; 345 } 346 347 public boolean func_83011_d(World par1World, int par2, int par3, int par4, int par5) 348 { 349 int i1 = getDirection(par5); 350 351 if (isRedstoneRepeaterBlockID(par1World.getBlockId(par2 - Direction.offsetX[i1], par3, par4 - Direction.offsetZ[i1]))) 352 { 353 int j1 = par1World.getBlockMetadata(par2 - Direction.offsetX[i1], par3, par4 - Direction.offsetZ[i1]); 354 int k1 = getDirection(j1); 355 return k1 != i1; 356 } 357 else 358 { 359 return false; 360 } 361 } 362 363 protected int func_94486_g(int par1) 364 { 365 return this.func_94481_j_(par1); 366 } 367 368 protected abstract int func_94481_j_(int i); 369 370 protected abstract BlockRedstoneLogic func_94485_e(); 371 372 protected abstract BlockRedstoneLogic func_94484_i(); 373 374 public boolean func_94334_h(int par1) 375 { 376 return this.func_94487_f(par1); 377 } 378}