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 Block block = Block.blocksList[i1]; 124 125 if (block == null || !block.isBeaconBase(worldObj, k, j, l, xCoord, yCoord, zCoord)) 126 { 127 flag = false; 128 break; 129 } 130 } 131 } 132 133 if (!flag) 134 { 135 break; 136 } 137 } 138 139 if (this.levels == 0) 140 { 141 this.isBeaconActive = false; 142 } 143 } 144 } 145 146 @SideOnly(Side.CLIENT) 147 public float func_82125_v_() 148 { 149 if (!this.isBeaconActive) 150 { 151 return 0.0F; 152 } 153 else 154 { 155 int i = (int)(this.worldObj.getTotalWorldTime() - this.field_82137_b); 156 this.field_82137_b = this.worldObj.getTotalWorldTime(); 157 158 if (i > 1) 159 { 160 this.field_82138_c -= (float)i / 40.0F; 161 162 if (this.field_82138_c < 0.0F) 163 { 164 this.field_82138_c = 0.0F; 165 } 166 } 167 168 this.field_82138_c += 0.025F; 169 170 if (this.field_82138_c > 1.0F) 171 { 172 this.field_82138_c = 1.0F; 173 } 174 175 return this.field_82138_c; 176 } 177 } 178 179 /** 180 * Return the primary potion effect given by this beacon. 181 */ 182 public int getPrimaryEffect() 183 { 184 return this.primaryEffect; 185 } 186 187 /** 188 * Return the secondary potion effect given by this beacon. 189 */ 190 public int getSecondaryEffect() 191 { 192 return this.secondaryEffect; 193 } 194 195 /** 196 * Return the levels of this beacon's pyramid. 197 */ 198 public int getLevels() 199 { 200 return this.levels; 201 } 202 203 @SideOnly(Side.CLIENT) 204 205 /** 206 * Set the levels of this beacon's pyramid. 207 */ 208 public void setLevels(int par1) 209 { 210 this.levels = par1; 211 } 212 213 public void setPrimaryEffect(int par1) 214 { 215 this.primaryEffect = 0; 216 217 for (int j = 0; j < this.levels && j < 3; ++j) 218 { 219 Potion[] apotion = effectsList[j]; 220 int k = apotion.length; 221 222 for (int l = 0; l < k; ++l) 223 { 224 Potion potion = apotion[l]; 225 226 if (potion.id == par1) 227 { 228 this.primaryEffect = par1; 229 return; 230 } 231 } 232 } 233 } 234 235 public void setSecondaryEffect(int par1) 236 { 237 this.secondaryEffect = 0; 238 239 if (this.levels >= 4) 240 { 241 for (int j = 0; j < 4; ++j) 242 { 243 Potion[] apotion = effectsList[j]; 244 int k = apotion.length; 245 246 for (int l = 0; l < k; ++l) 247 { 248 Potion potion = apotion[l]; 249 250 if (potion.id == par1) 251 { 252 this.secondaryEffect = par1; 253 return; 254 } 255 } 256 } 257 } 258 } 259 260 /** 261 * Overriden in a sign to provide the text. 262 */ 263 public Packet getDescriptionPacket() 264 { 265 NBTTagCompound nbttagcompound = new NBTTagCompound(); 266 this.writeToNBT(nbttagcompound); 267 return new Packet132TileEntityData(this.xCoord, this.yCoord, this.zCoord, 3, nbttagcompound); 268 } 269 270 @SideOnly(Side.CLIENT) 271 public double getMaxRenderDistanceSquared() 272 { 273 return 65536.0D; 274 } 275 276 /** 277 * Reads a tile entity from NBT. 278 */ 279 public void readFromNBT(NBTTagCompound par1NBTTagCompound) 280 { 281 super.readFromNBT(par1NBTTagCompound); 282 this.primaryEffect = par1NBTTagCompound.getInteger("Primary"); 283 this.secondaryEffect = par1NBTTagCompound.getInteger("Secondary"); 284 this.levels = par1NBTTagCompound.getInteger("Levels"); 285 } 286 287 /** 288 * Writes a tile entity to NBT. 289 */ 290 public void writeToNBT(NBTTagCompound par1NBTTagCompound) 291 { 292 super.writeToNBT(par1NBTTagCompound); 293 par1NBTTagCompound.setInteger("Primary", this.primaryEffect); 294 par1NBTTagCompound.setInteger("Secondary", this.secondaryEffect); 295 par1NBTTagCompound.setInteger("Levels", this.levels); 296 } 297 298 /** 299 * Returns the number of slots in the inventory. 300 */ 301 public int getSizeInventory() 302 { 303 return 1; 304 } 305 306 /** 307 * Returns the stack in slot i 308 */ 309 public ItemStack getStackInSlot(int par1) 310 { 311 return par1 == 0 ? this.payment : null; 312 } 313 314 /** 315 * Removes from an inventory slot (first arg) up to a specified number (second arg) of items and returns them in a 316 * new stack. 317 */ 318 public ItemStack decrStackSize(int par1, int par2) 319 { 320 if (par1 == 0 && this.payment != null) 321 { 322 if (par2 >= this.payment.stackSize) 323 { 324 ItemStack itemstack = this.payment; 325 this.payment = null; 326 return itemstack; 327 } 328 else 329 { 330 this.payment.stackSize -= par2; 331 return new ItemStack(this.payment.itemID, par2, this.payment.getItemDamage()); 332 } 333 } 334 else 335 { 336 return null; 337 } 338 } 339 340 /** 341 * When some containers are closed they call this on each slot, then drop whatever it returns as an EntityItem - 342 * like when you close a workbench GUI. 343 */ 344 public ItemStack getStackInSlotOnClosing(int par1) 345 { 346 if (par1 == 0 && this.payment != null) 347 { 348 ItemStack itemstack = this.payment; 349 this.payment = null; 350 return itemstack; 351 } 352 else 353 { 354 return null; 355 } 356 } 357 358 /** 359 * Sets the given item stack to the specified slot in the inventory (can be crafting or armor sections). 360 */ 361 public void setInventorySlotContents(int par1, ItemStack par2ItemStack) 362 { 363 if (par1 == 0) 364 { 365 this.payment = par2ItemStack; 366 } 367 } 368 369 /** 370 * Returns the name of the inventory. 371 */ 372 public String getInvName() 373 { 374 return this.isInvNameLocalized() ? this.field_94048_i : "container.beacon"; 375 } 376 377 /** 378 * If this returns false, the inventory name will be used as an unlocalized name, and translated into the player's 379 * language. Otherwise it will be used directly. 380 */ 381 public boolean isInvNameLocalized() 382 { 383 return this.field_94048_i != null && this.field_94048_i.length() > 0; 384 } 385 386 public void func_94047_a(String par1Str) 387 { 388 this.field_94048_i = par1Str; 389 } 390 391 /** 392 * Returns the maximum stack size for a inventory slot. Seems to always be 64, possibly will be extended. *Isn't 393 * this more of a set than a get?* 394 */ 395 public int getInventoryStackLimit() 396 { 397 return 1; 398 } 399 400 /** 401 * Do not make give this method the name canInteractWith because it clashes with Container 402 */ 403 public boolean isUseableByPlayer(EntityPlayer par1EntityPlayer) 404 { 405 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; 406 } 407 408 public void openChest() {} 409 410 public void closeChest() {} 411 412 /** 413 * Returns true if automation is allowed to insert the given stack (ignoring stack size) into the given slot. 414 */ 415 public boolean isStackValidForSlot(int par1, ItemStack par2ItemStack) 416 { 417 return par2ItemStack.itemID == Item.emerald.itemID || par2ItemStack.itemID == Item.diamond.itemID || par2ItemStack.itemID == Item.ingotGold.itemID || par2ItemStack.itemID == Item.ingotIron.itemID; 418 } 419}