001package net.minecraft.tileentity; 002 003import cpw.mods.fml.relauncher.Side; 004import cpw.mods.fml.relauncher.SideOnly; 005import java.util.Iterator; 006import java.util.List; 007import net.minecraft.block.Block; 008import net.minecraft.entity.player.EntityPlayer; 009import net.minecraft.inventory.IInventory; 010import net.minecraft.item.Item; 011import net.minecraft.item.ItemStack; 012import net.minecraft.nbt.NBTTagCompound; 013import net.minecraft.network.packet.Packet; 014import net.minecraft.network.packet.Packet132TileEntityData; 015import net.minecraft.potion.Potion; 016import net.minecraft.potion.PotionEffect; 017import net.minecraft.util.AxisAlignedBB; 018 019public class TileEntityBeacon extends TileEntity implements IInventory 020{ 021 /** List of effects that Beacon can apply */ 022 public static final Potion[][] effectsList = new Potion[][] {{Potion.moveSpeed, Potion.digSpeed}, {Potion.resistance, Potion.jump}, {Potion.damageBoost}, {Potion.regeneration}}; 023 @SideOnly(Side.CLIENT) 024 private long field_82137_b; 025 @SideOnly(Side.CLIENT) 026 private float field_82138_c; 027 private boolean isBeaconActive; 028 029 /** Level of this beacon's pyramid. */ 030 private int levels = -1; 031 032 /** Primary potion effect given by this beacon. */ 033 private int primaryEffect; 034 035 /** Secondary potion effect given by this beacon. */ 036 private int secondaryEffect; 037 038 /** Item given to this beacon as payment. */ 039 private ItemStack payment; 040 private String field_94048_i; 041 042 /** 043 * Allows the entity to update its state. Overridden in most subclasses, e.g. the mob spawner uses this to count 044 * ticks and creates a new spawn inside its implementation. 045 */ 046 public void updateEntity() 047 { 048 if (this.worldObj.getTotalWorldTime() % 80L == 0L) 049 { 050 this.updateState(); 051 this.addEffectsToPlayers(); 052 } 053 } 054 055 private void addEffectsToPlayers() 056 { 057 if (this.isBeaconActive && this.levels > 0 && !this.worldObj.isRemote && this.primaryEffect > 0) 058 { 059 double d0 = (double)(this.levels * 10 + 10); 060 byte b0 = 0; 061 062 if (this.levels >= 4 && this.primaryEffect == this.secondaryEffect) 063 { 064 b0 = 1; 065 } 066 067 AxisAlignedBB axisalignedbb = AxisAlignedBB.getAABBPool().getAABB((double)this.xCoord, (double)this.yCoord, (double)this.zCoord, (double)(this.xCoord + 1), (double)(this.yCoord + 1), (double)(this.zCoord + 1)).expand(d0, d0, d0); 068 axisalignedbb.maxY = (double)this.worldObj.getHeight(); 069 List list = this.worldObj.getEntitiesWithinAABB(EntityPlayer.class, axisalignedbb); 070 Iterator iterator = list.iterator(); 071 EntityPlayer entityplayer; 072 073 while (iterator.hasNext()) 074 { 075 entityplayer = (EntityPlayer)iterator.next(); 076 entityplayer.addPotionEffect(new PotionEffect(this.primaryEffect, 180, b0, true)); 077 } 078 079 if (this.levels >= 4 && this.primaryEffect != this.secondaryEffect && this.secondaryEffect > 0) 080 { 081 iterator = list.iterator(); 082 083 while (iterator.hasNext()) 084 { 085 entityplayer = (EntityPlayer)iterator.next(); 086 entityplayer.addPotionEffect(new PotionEffect(this.secondaryEffect, 180, 0, true)); 087 } 088 } 089 } 090 } 091 092 /** 093 * Checks if the Beacon has a valid pyramid underneath and direct sunlight above 094 */ 095 private void updateState() 096 { 097 if (!this.worldObj.canBlockSeeTheSky(this.xCoord, this.yCoord + 1, this.zCoord)) 098 { 099 this.isBeaconActive = false; 100 this.levels = 0; 101 } 102 else 103 { 104 this.isBeaconActive = true; 105 this.levels = 0; 106 107 for (int i = 1; i <= 4; this.levels = i++) 108 { 109 int j = this.yCoord - i; 110 111 if (j < 0) 112 { 113 break; 114 } 115 116 boolean flag = true; 117 118 for (int k = this.xCoord - i; k <= this.xCoord + i && flag; ++k) 119 { 120 for (int l = this.zCoord - i; l <= this.zCoord + i; ++l) 121 { 122 int i1 = this.worldObj.getBlockId(k, j, l); 123 124 Block block = Block.blocksList[i1]; 125 126 if (block == null || !block.isBeaconBase(worldObj, k, j, l, xCoord, yCoord, zCoord)) 127 { 128 flag = false; 129 break; 130 } 131 } 132 } 133 134 if (!flag) 135 { 136 break; 137 } 138 } 139 140 if (this.levels == 0) 141 { 142 this.isBeaconActive = false; 143 } 144 } 145 } 146 147 @SideOnly(Side.CLIENT) 148 public float func_82125_v_() 149 { 150 if (!this.isBeaconActive) 151 { 152 return 0.0F; 153 } 154 else 155 { 156 int i = (int)(this.worldObj.getTotalWorldTime() - this.field_82137_b); 157 this.field_82137_b = this.worldObj.getTotalWorldTime(); 158 159 if (i > 1) 160 { 161 this.field_82138_c -= (float)i / 40.0F; 162 163 if (this.field_82138_c < 0.0F) 164 { 165 this.field_82138_c = 0.0F; 166 } 167 } 168 169 this.field_82138_c += 0.025F; 170 171 if (this.field_82138_c > 1.0F) 172 { 173 this.field_82138_c = 1.0F; 174 } 175 176 return this.field_82138_c; 177 } 178 } 179 180 /** 181 * Return the primary potion effect given by this beacon. 182 */ 183 public int getPrimaryEffect() 184 { 185 return this.primaryEffect; 186 } 187 188 /** 189 * Return the secondary potion effect given by this beacon. 190 */ 191 public int getSecondaryEffect() 192 { 193 return this.secondaryEffect; 194 } 195 196 /** 197 * Return the levels of this beacon's pyramid. 198 */ 199 public int getLevels() 200 { 201 return this.levels; 202 } 203 204 @SideOnly(Side.CLIENT) 205 206 /** 207 * Set the levels of this beacon's pyramid. 208 */ 209 public void setLevels(int par1) 210 { 211 this.levels = par1; 212 } 213 214 public void setPrimaryEffect(int par1) 215 { 216 this.primaryEffect = 0; 217 218 for (int j = 0; j < this.levels && j < 3; ++j) 219 { 220 Potion[] apotion = effectsList[j]; 221 int k = apotion.length; 222 223 for (int l = 0; l < k; ++l) 224 { 225 Potion potion = apotion[l]; 226 227 if (potion.id == par1) 228 { 229 this.primaryEffect = par1; 230 return; 231 } 232 } 233 } 234 } 235 236 public void setSecondaryEffect(int par1) 237 { 238 this.secondaryEffect = 0; 239 240 if (this.levels >= 4) 241 { 242 for (int j = 0; j < 4; ++j) 243 { 244 Potion[] apotion = effectsList[j]; 245 int k = apotion.length; 246 247 for (int l = 0; l < k; ++l) 248 { 249 Potion potion = apotion[l]; 250 251 if (potion.id == par1) 252 { 253 this.secondaryEffect = par1; 254 return; 255 } 256 } 257 } 258 } 259 } 260 261 /** 262 * Overriden in a sign to provide the text. 263 */ 264 public Packet getDescriptionPacket() 265 { 266 NBTTagCompound nbttagcompound = new NBTTagCompound(); 267 this.writeToNBT(nbttagcompound); 268 return new Packet132TileEntityData(this.xCoord, this.yCoord, this.zCoord, 3, nbttagcompound); 269 } 270 271 @SideOnly(Side.CLIENT) 272 public double getMaxRenderDistanceSquared() 273 { 274 return 65536.0D; 275 } 276 277 /** 278 * Reads a tile entity from NBT. 279 */ 280 public void readFromNBT(NBTTagCompound par1NBTTagCompound) 281 { 282 super.readFromNBT(par1NBTTagCompound); 283 this.primaryEffect = par1NBTTagCompound.getInteger("Primary"); 284 this.secondaryEffect = par1NBTTagCompound.getInteger("Secondary"); 285 this.levels = par1NBTTagCompound.getInteger("Levels"); 286 } 287 288 /** 289 * Writes a tile entity to NBT. 290 */ 291 public void writeToNBT(NBTTagCompound par1NBTTagCompound) 292 { 293 super.writeToNBT(par1NBTTagCompound); 294 par1NBTTagCompound.setInteger("Primary", this.primaryEffect); 295 par1NBTTagCompound.setInteger("Secondary", this.secondaryEffect); 296 par1NBTTagCompound.setInteger("Levels", this.levels); 297 } 298 299 /** 300 * Returns the number of slots in the inventory. 301 */ 302 public int getSizeInventory() 303 { 304 return 1; 305 } 306 307 /** 308 * Returns the stack in slot i 309 */ 310 public ItemStack getStackInSlot(int par1) 311 { 312 return par1 == 0 ? this.payment : null; 313 } 314 315 /** 316 * Removes from an inventory slot (first arg) up to a specified number (second arg) of items and returns them in a 317 * new stack. 318 */ 319 public ItemStack decrStackSize(int par1, int par2) 320 { 321 if (par1 == 0 && this.payment != null) 322 { 323 if (par2 >= this.payment.stackSize) 324 { 325 ItemStack itemstack = this.payment; 326 this.payment = null; 327 return itemstack; 328 } 329 else 330 { 331 this.payment.stackSize -= par2; 332 return new ItemStack(this.payment.itemID, par2, this.payment.getItemDamage()); 333 } 334 } 335 else 336 { 337 return null; 338 } 339 } 340 341 /** 342 * When some containers are closed they call this on each slot, then drop whatever it returns as an EntityItem - 343 * like when you close a workbench GUI. 344 */ 345 public ItemStack getStackInSlotOnClosing(int par1) 346 { 347 if (par1 == 0 && this.payment != null) 348 { 349 ItemStack itemstack = this.payment; 350 this.payment = null; 351 return itemstack; 352 } 353 else 354 { 355 return null; 356 } 357 } 358 359 /** 360 * Sets the given item stack to the specified slot in the inventory (can be crafting or armor sections). 361 */ 362 public void setInventorySlotContents(int par1, ItemStack par2ItemStack) 363 { 364 if (par1 == 0) 365 { 366 this.payment = par2ItemStack; 367 } 368 } 369 370 /** 371 * Returns the name of the inventory. 372 */ 373 public String getInvName() 374 { 375 return this.isInvNameLocalized() ? this.field_94048_i : "container.beacon"; 376 } 377 378 /** 379 * If this returns false, the inventory name will be used as an unlocalized name, and translated into the player's 380 * language. Otherwise it will be used directly. 381 */ 382 public boolean isInvNameLocalized() 383 { 384 return this.field_94048_i != null && this.field_94048_i.length() > 0; 385 } 386 387 public void func_94047_a(String par1Str) 388 { 389 this.field_94048_i = par1Str; 390 } 391 392 /** 393 * Returns the maximum stack size for a inventory slot. Seems to always be 64, possibly will be extended. *Isn't 394 * this more of a set than a get?* 395 */ 396 public int getInventoryStackLimit() 397 { 398 return 1; 399 } 400 401 /** 402 * Do not make give this method the name canInteractWith because it clashes with Container 403 */ 404 public boolean isUseableByPlayer(EntityPlayer par1EntityPlayer) 405 { 406 return this.worldObj.getBlockTileEntity(this.xCoord, this.yCoord, this.zCoord) != this ? false : par1EntityPlayer.getDistanceSq((double)this.xCoord + 0.5D, (double)this.yCoord + 0.5D, (double)this.zCoord + 0.5D) <= 64.0D; 407 } 408 409 public void openChest() {} 410 411 public void closeChest() {} 412 413 /** 414 * Returns true if automation is allowed to insert the given stack (ignoring stack size) into the given slot. 415 */ 416 public boolean isStackValidForSlot(int par1, ItemStack par2ItemStack) 417 { 418 return par2ItemStack.itemID == Item.emerald.itemID || par2ItemStack.itemID == Item.diamond.itemID || par2ItemStack.itemID == Item.ingotGold.itemID || par2ItemStack.itemID == Item.ingotIron.itemID; 419 } 420}