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 }