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