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 func_82115_m()
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.func_94042_c() ? this.field_94048_i : "container.beacon";
375    }
376
377    public boolean func_94042_c()
378    {
379        return this.field_94048_i != null && this.field_94048_i.length() > 0;
380    }
381
382    public void func_94047_a(String par1Str)
383    {
384        this.field_94048_i = par1Str;
385    }
386
387    /**
388     * Returns the maximum stack size for a inventory slot. Seems to always be 64, possibly will be extended. *Isn't
389     * this more of a set than a get?*
390     */
391    public int getInventoryStackLimit()
392    {
393        return 1;
394    }
395
396    /**
397     * Do not make give this method the name canInteractWith because it clashes with Container
398     */
399    public boolean isUseableByPlayer(EntityPlayer par1EntityPlayer)
400    {
401        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;
402    }
403
404    public void openChest() {}
405
406    public void closeChest() {}
407
408    public boolean func_94041_b(int par1, ItemStack par2ItemStack)
409    {
410        return par2ItemStack.itemID == Item.emerald.itemID || par2ItemStack.itemID == Item.diamond.itemID || par2ItemStack.itemID == Item.ingotGold.itemID || par2ItemStack.itemID == Item.ingotIron.itemID;
411    }
412}