    001package net.minecraft.entity.item;
    002
    003import cpw.mods.fml.relauncher.Side;
    004import cpw.mods.fml.relauncher.SideOnly;
    005import net.minecraft.block.Block;
    006import net.minecraft.block.material.Material;
    007import net.minecraft.entity.Entity;
    008import net.minecraft.entity.player.EntityPlayer;
    009import net.minecraft.nbt.NBTTagCompound;
    010import net.minecraft.util.DamageSource;
    011import net.minecraft.util.MathHelper;
    012import net.minecraft.world.World;
    013
    014public class EntityXPOrb extends Entity
    015{
    016    /**
    017     * A constantly increasing value that RenderXPOrb uses to control the colour shifting (Green / yellow)
    018     */
    019    public int xpColor;
    020
    021    /** The age of the XP orb in ticks. */
    022    public int xpOrbAge = 0;
    023    public int field_70532_c;
    024
    025    /** The health of this XP orb. */
    026    private int xpOrbHealth = 5;
    027
    028    /** This is how much XP this orb has. */
    029    private int xpValue;
    030
    031    /** The closest EntityPlayer to this orb. */
    032    private EntityPlayer closestPlayer;
    033
    034    /** Threshold color for tracking players */
    035    private int xpTargetColor;
    036
    037    public EntityXPOrb(World par1World, double par2, double par4, double par6, int par8)
    038    {
    039        super(par1World);
    040        this.setSize(0.5F, 0.5F);
    041        this.yOffset = this.height / 2.0F;
    042        this.setPosition(par2, par4, par6);
    043        this.rotationYaw = (float)(Math.random() * 360.0D);
    044        this.motionX = (double)((float)(Math.random() * 0.20000000298023224D - 0.10000000149011612D) * 2.0F);
    045        this.motionY = (double)((float)(Math.random() * 0.2D) * 2.0F);
    046        this.motionZ = (double)((float)(Math.random() * 0.20000000298023224D - 0.10000000149011612D) * 2.0F);
    047        this.xpValue = par8;
    048    }
    049
    050    /**
    051     * returns if this entity triggers Block.onEntityWalking on the blocks they walk on. used for spiders and wolves to
    052     * prevent them from trampling crops
    053     */
    054    protected boolean canTriggerWalking()
    055    {
    056        return false;
    057    }
    058
    059    public EntityXPOrb(World par1World)
    060    {
    061        super(par1World);
    062        this.setSize(0.25F, 0.25F);
    063        this.yOffset = this.height / 2.0F;
    064    }
    065
    066    protected void entityInit() {}
    067
    068    @SideOnly(Side.CLIENT)
    069    public int getBrightnessForRender(float par1)
    070    {
    071        float f1 = 0.5F;
    072
    073        if (f1 < 0.0F)
    074        {
    075            f1 = 0.0F;
    076        }
    077
    078        if (f1 > 1.0F)
    079        {
    080            f1 = 1.0F;
    081        }
    082
    083        int i = super.getBrightnessForRender(par1);
    084        int j = i & 255;
    085        int k = i >> 16 & 255;
    086        j += (int)(f1 * 15.0F * 16.0F);
    087
    088        if (j > 240)
    089        {
    090            j = 240;
    091        }
    092
    093        return j | k << 16;
    094    }
    095
    096    /**
    097     * Called to update the entity's position/logic.
    098     */
    099    public void onUpdate()
    100    {
    101        super.onUpdate();
    102
    103        if (this.field_70532_c > 0)
    104        {
    105            --this.field_70532_c;
    106        }
    107
    108        this.prevPosX = this.posX;
    109        this.prevPosY = this.posY;
    110        this.prevPosZ = this.posZ;
    111        this.motionY -= 0.029999999329447746D;
    112
    113        if (this.worldObj.getBlockMaterial(MathHelper.floor_double(this.posX), MathHelper.floor_double(this.posY), MathHelper.floor_double(this.posZ)) == Material.lava)
    114        {
    115            this.motionY = 0.20000000298023224D;
    116            this.motionX = (double)((this.rand.nextFloat() - this.rand.nextFloat()) * 0.2F);
    117            this.motionZ = (double)((this.rand.nextFloat() - this.rand.nextFloat()) * 0.2F);
    118            this.playSound("random.fizz", 0.4F, 2.0F + this.rand.nextFloat() * 0.4F);
    119        }
    120
    121        this.pushOutOfBlocks(this.posX, (this.boundingBox.minY + this.boundingBox.maxY) / 2.0D, this.posZ);
    122        double d0 = 8.0D;
    123
    124        if (this.xpTargetColor < this.xpColor - 20 + this.entityId % 100)
    125        {
    126            if (this.closestPlayer == null || this.closestPlayer.getDistanceSqToEntity(this) > d0 * d0)
    127            {
    128                this.closestPlayer = this.worldObj.getClosestPlayerToEntity(this, d0);
    129            }
    130
    131            this.xpTargetColor = this.xpColor;
    132        }
    133
    134        if (this.closestPlayer != null)
    135        {
    136            double d1 = (this.closestPlayer.posX - this.posX) / d0;
    137            double d2 = (this.closestPlayer.posY + (double)this.closestPlayer.getEyeHeight() - this.posY) / d0;
    138            double d3 = (this.closestPlayer.posZ - this.posZ) / d0;
    139            double d4 = Math.sqrt(d1 * d1 + d2 * d2 + d3 * d3);
    140            double d5 = 1.0D - d4;
    141
    142            if (d5 > 0.0D)
    143            {
    144                d5 *= d5;
    145                this.motionX += d1 / d4 * d5 * 0.1D;
    146                this.motionY += d2 / d4 * d5 * 0.1D;
    147                this.motionZ += d3 / d4 * d5 * 0.1D;
    148            }
    149        }
    150
    151        this.moveEntity(this.motionX, this.motionY, this.motionZ);
    152        float f = 0.98F;
    153
    154        if (this.onGround)
    155        {
    156            f = 0.58800006F;
    157            int i = this.worldObj.getBlockId(MathHelper.floor_double(this.posX), MathHelper.floor_double(this.boundingBox.minY) - 1, MathHelper.floor_double(this.posZ));
    158
    159            if (i > 0)
    160            {
    161                f = Block.blocksList[i].slipperiness * 0.98F;
    162            }
    163        }
    164
    165        this.motionX *= (double)f;
    166        this.motionY *= 0.9800000190734863D;
    167        this.motionZ *= (double)f;
    168
    169        if (this.onGround)
    170        {
    171            this.motionY *= -0.8999999761581421D;
    172        }
    173
    174        ++this.xpColor;
    175        ++this.xpOrbAge;
    176
    177        if (this.xpOrbAge >= 6000)
    178        {
    179            this.setDead();
    180        }
    181    }
    182
    183    /**
    184     * Returns if this entity is in water and will end up adding the waters velocity to the entity
    185     */
    186    public boolean handleWaterMovement()
    187    {
    188        return this.worldObj.handleMaterialAcceleration(this.boundingBox, Material.water, this);
    189    }
    190
    191    /**
    192     * Will deal the specified amount of damage to the entity if the entity isn't immune to fire damage. Args:
    193     * amountDamage
    194     */
    195    protected void dealFireDamage(int par1)
    196    {
    197        this.attackEntityFrom(DamageSource.inFire, par1);
    198    }
    199
    200    /**
    201     * Called when the entity is attacked.
    202     */
    203    public boolean attackEntityFrom(DamageSource par1DamageSource, int par2)
    204    {
    205        if (this.isEntityInvulnerable())
    206        {
    207            return false;
    208        }
    209        else
    210        {
    211            this.setBeenAttacked();
    212            this.xpOrbHealth -= par2;
    213
    214            if (this.xpOrbHealth <= 0)
    215            {
    216                this.setDead();
    217            }
    218
    219            return false;
    220        }
    221    }
    222
    223    /**
    224     * (abstract) Protected helper method to write subclass entity data to NBT.
    225     */
    226    public void writeEntityToNBT(NBTTagCompound par1NBTTagCompound)
    227    {
    228        par1NBTTagCompound.setShort("Health", (short)((byte)this.xpOrbHealth));
    229        par1NBTTagCompound.setShort("Age", (short)this.xpOrbAge);
    230        par1NBTTagCompound.setShort("Value", (short)this.xpValue);
    231    }
    232
    233    /**
    234     * (abstract) Protected helper method to read subclass entity data from NBT.
    235     */
    236    public void readEntityFromNBT(NBTTagCompound par1NBTTagCompound)
    237    {
    238        this.xpOrbHealth = par1NBTTagCompound.getShort("Health") & 255;
    239        this.xpOrbAge = par1NBTTagCompound.getShort("Age");
    240        this.xpValue = par1NBTTagCompound.getShort("Value");
    241    }
    242
    243    /**
    244     * Called by a player entity when they collide with an entity
    245     */
    246    public void onCollideWithPlayer(EntityPlayer par1EntityPlayer)
    247    {
    248        if (!this.worldObj.isRemote)
    249        {
    250            if (this.field_70532_c == 0 && par1EntityPlayer.xpCooldown == 0)
    251            {
    252                par1EntityPlayer.xpCooldown = 2;
    253                this.playSound("random.orb", 0.1F, 0.5F * ((this.rand.nextFloat() - this.rand.nextFloat()) * 0.7F + 1.8F));
    254                par1EntityPlayer.onItemPickup(this, 1);
    255                par1EntityPlayer.addExperience(this.xpValue);
    256                this.setDead();
    257            }
    258        }
    259    }
    260
    261    /**
    262     * Returns the XP value of this XP orb.
    263     */
    264    public int getXpValue()
    265    {
    266        return this.xpValue;
    267    }
    268
    269    @SideOnly(Side.CLIENT)
    270
    271    /**
    272     * Returns a number from 1 to 10 based on how much XP this orb is worth. This is used by RenderXPOrb to determine
    273     * what texture to use.
    274     */
    275    public int getTextureByXP()
    276    {
    277        return this.xpValue >= 2477 ? 10 : (this.xpValue >= 1237 ? 9 : (this.xpValue >= 617 ? 8 : (this.xpValue >= 307 ? 7 : (this.xpValue >= 149 ? 6 : (this.xpValue >= 73 ? 5 : (this.xpValue >= 37 ? 4 : (this.xpValue >= 17 ? 3 : (this.xpValue >= 7 ? 2 : (this.xpValue >= 3 ? 1 : 0)))))))));
    278    }
    279
    280    /**
    281     * Get xp split rate (Is called until the xp drop code in EntityLiving.onEntityUpdate is complete)
    282     */
    283    public static int getXPSplit(int par0)
    284    {
    285        return par0 >= 2477 ? 2477 : (par0 >= 1237 ? 1237 : (par0 >= 617 ? 617 : (par0 >= 307 ? 307 : (par0 >= 149 ? 149 : (par0 >= 73 ? 73 : (par0 >= 37 ? 37 : (par0 >= 17 ? 17 : (par0 >= 7 ? 7 : (par0 >= 3 ? 3 : 1)))))))));
    286    }
    287
    288    /**
    289     * If returns false, the item will not inflict any damage against entities.
    290     */
    291    public boolean canAttackWithItem()
    292    {
    293        return false;
    294    }
    295}