    001    package net.minecraft.entity.monster;
    002
    003    import net.minecraft.entity.EntityLiving;
    004    import net.minecraft.entity.player.EntityPlayer;
    005    import net.minecraft.item.Item;
    006    import net.minecraft.nbt.NBTTagCompound;
    007    import net.minecraft.util.DamageSource;
    008    import net.minecraft.util.MathHelper;
    009    import net.minecraft.world.World;
    010    import net.minecraft.world.WorldType;
    011    import net.minecraft.world.biome.BiomeGenBase;
    012    import net.minecraft.world.chunk.Chunk;
    013
    014    public class EntitySlime extends EntityLiving implements IMob
    015    {
    016        public float field_70813_a;
    017        public float field_70811_b;
    018        public float field_70812_c;
    019
    020        /** the time between each jump of the slime */
    021        private int slimeJumpDelay = 0;
    022
    023        public EntitySlime(World par1World)
    024        {
    025            super(par1World);
    026            this.texture = "/mob/slime.png";
    027            int var2 = 1 << this.rand.nextInt(3);
    028            this.yOffset = 0.0F;
    029            this.slimeJumpDelay = this.rand.nextInt(20) + 10;
    030            this.setSlimeSize(var2);
    031        }
    032
    033        protected void entityInit()
    034        {
    035            super.entityInit();
    036            this.dataWatcher.addObject(16, new Byte((byte)1));
    037        }
    038
    039        protected void setSlimeSize(int par1)
    040        {
    041            this.dataWatcher.updateObject(16, new Byte((byte)par1));
    042            this.setSize(0.6F * (float)par1, 0.6F * (float)par1);
    043            this.setPosition(this.posX, this.posY, this.posZ);
    044            this.setEntityHealth(this.getMaxHealth());
    045            this.experienceValue = par1;
    046        }
    047
    048        public int getMaxHealth()
    049        {
    050            int var1 = this.getSlimeSize();
    051            return var1 * var1;
    052        }
    053
    054        /**
    055         * Returns the size of the slime.
    056         */
    057        public int getSlimeSize()
    058        {
    059            return this.dataWatcher.getWatchableObjectByte(16);
    060        }
    061
    062        /**
    063         * (abstract) Protected helper method to write subclass entity data to NBT.
    064         */
    065        public void writeEntityToNBT(NBTTagCompound par1NBTTagCompound)
    066        {
    067            super.writeEntityToNBT(par1NBTTagCompound);
    068            par1NBTTagCompound.setInteger("Size", this.getSlimeSize() - 1);
    069        }
    070
    071        /**
    072         * (abstract) Protected helper method to read subclass entity data from NBT.
    073         */
    074        public void readEntityFromNBT(NBTTagCompound par1NBTTagCompound)
    075        {
    076            super.readEntityFromNBT(par1NBTTagCompound);
    077            this.setSlimeSize(par1NBTTagCompound.getInteger("Size") + 1);
    078        }
    079
    080        /**
    081         * Returns the name of a particle effect that may be randomly created by EntitySlime.onUpdate()
    082         */
    083        protected String getSlimeParticle()
    084        {
    085            return "slime";
    086        }
    087
    088        /**
    089         * Returns the name of the sound played when the slime jumps.
    090         */
    091        protected String getJumpSound()
    092        {
    093            return "mob.slime." + (this.getSlimeSize() > 1 ? "big" : "small");
    094        }
    095
    096        /**
    097         * Called to update the entity's position/logic.
    098         */
    099        public void onUpdate()
    100        {
    101            if (!this.worldObj.isRemote && this.worldObj.difficultySetting == 0 && this.getSlimeSize() > 0)
    102            {
    103                this.isDead = true;
    104            }
    105
    106            this.field_70811_b += (this.field_70813_a - this.field_70811_b) * 0.5F;
    107            this.field_70812_c = this.field_70811_b;
    108            boolean var1 = this.onGround;
    109            super.onUpdate();
    110            int var2;
    111
    112            if (this.onGround && !var1)
    113            {
    114                var2 = this.getSlimeSize();
    115
    116                for (int var3 = 0; var3 < var2 * 8; ++var3)
    117                {
    118                    float var4 = this.rand.nextFloat() * (float)Math.PI * 2.0F;
    119                    float var5 = this.rand.nextFloat() * 0.5F + 0.5F;
    120                    float var6 = MathHelper.sin(var4) * (float)var2 * 0.5F * var5;
    121                    float var7 = MathHelper.cos(var4) * (float)var2 * 0.5F * var5;
    122                    this.worldObj.spawnParticle(this.getSlimeParticle(), this.posX + (double)var6, this.boundingBox.minY, this.posZ + (double)var7, 0.0D, 0.0D, 0.0D);
    123                }
    124
    125                if (this.makesSoundOnLand())
    126                {
    127                    this.func_85030_a(this.getJumpSound(), this.getSoundVolume(), ((this.rand.nextFloat() - this.rand.nextFloat()) * 0.2F + 1.0F) / 0.8F);
    128                }
    129
    130                this.field_70813_a = -0.5F;
    131            }
    132            else if (!this.onGround && var1)
    133            {
    134                this.field_70813_a = 1.0F;
    135            }
    136
    137            this.func_70808_l();
    138
    139            if (this.worldObj.isRemote)
    140            {
    141                var2 = this.getSlimeSize();
    142                this.setSize(0.6F * (float)var2, 0.6F * (float)var2);
    143            }
    144        }
    145
    146        protected void updateEntityActionState()
    147        {
    148            this.despawnEntity();
    149            EntityPlayer var1 = this.worldObj.getClosestVulnerablePlayerToEntity(this, 16.0D);
    150
    151            if (var1 != null)
    152            {
    153                this.faceEntity(var1, 10.0F, 20.0F);
    154            }
    155
    156            if (this.onGround && this.slimeJumpDelay-- <= 0)
    157            {
    158                this.slimeJumpDelay = this.getJumpDelay();
    159
    160                if (var1 != null)
    161                {
    162                    this.slimeJumpDelay /= 3;
    163                }
    164
    165                this.isJumping = true;
    166
    167                if (this.makesSoundOnJump())
    168                {
    169                    this.func_85030_a(this.getJumpSound(), this.getSoundVolume(), ((this.rand.nextFloat() - this.rand.nextFloat()) * 0.2F + 1.0F) * 0.8F);
    170                }
    171
    172                this.moveStrafing = 1.0F - this.rand.nextFloat() * 2.0F;
    173                this.moveForward = (float)(1 * this.getSlimeSize());
    174            }
    175            else
    176            {
    177                this.isJumping = false;
    178
    179                if (this.onGround)
    180                {
    181                    this.moveStrafing = this.moveForward = 0.0F;
    182                }
    183            }
    184        }
    185
    186        protected void func_70808_l()
    187        {
    188            this.field_70813_a *= 0.6F;
    189        }
    190
    191        /**
    192         * Gets the amount of time the slime needs to wait between jumps.
    193         */
    194        protected int getJumpDelay()
    195        {
    196            return this.rand.nextInt(20) + 10;
    197        }
    198
    199        protected EntitySlime createInstance()
    200        {
    201            return new EntitySlime(this.worldObj);
    202        }
    203
    204        /**
    205         * Will get destroyed next tick.
    206         */
    207        public void setDead()
    208        {
    209            int var1 = this.getSlimeSize();
    210
    211            if (!this.worldObj.isRemote && var1 > 1 && this.getHealth() <= 0)
    212            {
    213                int var2 = 2 + this.rand.nextInt(3);
    214
    215                for (int var3 = 0; var3 < var2; ++var3)
    216                {
    217                    float var4 = ((float)(var3 % 2) - 0.5F) * (float)var1 / 4.0F;
    218                    float var5 = ((float)(var3 / 2) - 0.5F) * (float)var1 / 4.0F;
    219                    EntitySlime var6 = this.createInstance();
    220                    var6.setSlimeSize(var1 / 2);
    221                    var6.setLocationAndAngles(this.posX + (double)var4, this.posY + 0.5D, this.posZ + (double)var5, this.rand.nextFloat() * 360.0F, 0.0F);
    222                    this.worldObj.spawnEntityInWorld(var6);
    223                }
    224            }
    225
    226            super.setDead();
    227        }
    228
    229        /**
    230         * Called by a player entity when they collide with an entity
    231         */
    232        public void onCollideWithPlayer(EntityPlayer par1EntityPlayer)
    233        {
    234            if (this.canDamagePlayer())
    235            {
    236                int var2 = this.getSlimeSize();
    237
    238                if (this.canEntityBeSeen(par1EntityPlayer) && this.getDistanceSqToEntity(par1EntityPlayer) < 0.6D * (double)var2 * 0.6D * (double)var2 && par1EntityPlayer.attackEntityFrom(DamageSource.causeMobDamage(this), this.getAttackStrength()))
    239                {
    240                    this.func_85030_a("mob.attack", 1.0F, (this.rand.nextFloat() - this.rand.nextFloat()) * 0.2F + 1.0F);
    241                }
    242            }
    243        }
    244
    245        /**
    246         * Indicates weather the slime is able to damage the player (based upon the slime's size)
    247         */
    248        protected boolean canDamagePlayer()
    249        {
    250            return this.getSlimeSize() > 1;
    251        }
    252
    253        /**
    254         * Gets the amount of damage dealt to the player when "attacked" by the slime.
    255         */
    256        protected int getAttackStrength()
    257        {
    258            return this.getSlimeSize();
    259        }
    260
    261        /**
    262         * Returns the sound this mob makes when it is hurt.
    263         */
    264        protected String getHurtSound()
    265        {
    266            return "mob.slime." + (this.getSlimeSize() > 1 ? "big" : "small");
    267        }
    268
    269        /**
    270         * Returns the sound this mob makes on death.
    271         */
    272        protected String getDeathSound()
    273        {
    274            return "mob.slime." + (this.getSlimeSize() > 1 ? "big" : "small");
    275        }
    276
    277        /**
    278         * Returns the item ID for the item the mob drops on death.
    279         */
    280        protected int getDropItemId()
    281        {
    282            return this.getSlimeSize() == 1 ? Item.slimeBall.shiftedIndex : 0;
    283        }
    284
    285        /**
    286         * Checks if the entity's current position is a valid location to spawn this entity.
    287         */
    288        public boolean getCanSpawnHere()
    289        {
    290            Chunk var1 = this.worldObj.getChunkFromBlockCoords(MathHelper.floor_double(this.posX), MathHelper.floor_double(this.posZ));
    291
    292            if (this.worldObj.getWorldInfo().getTerrainType().handleSlimeSpawnReduction(rand, worldObj))
    293            {
    294                return false;
    295            }
    296            else
    297            {
    298                if (this.getSlimeSize() == 1 || this.worldObj.difficultySetting > 0)
    299                {
    300                    if (this.worldObj.getBiomeGenForCoords(MathHelper.floor_double(this.posX), MathHelper.floor_double(this.posZ)) == BiomeGenBase.swampland && this.posY > 50.0D && this.posY < 70.0D && this.worldObj.getBlockLightValue(MathHelper.floor_double(this.posX), MathHelper.floor_double(this.posY), MathHelper.floor_double(this.posZ)) <= this.rand.nextInt(8))
    301                    {
    302                        return super.getCanSpawnHere();
    303                    }
    304
    305                    if (this.rand.nextInt(10) == 0 && var1.getRandomWithSeed(987234911L).nextInt(10) == 0 && this.posY < 40.0D)
    306                    {
    307                        return super.getCanSpawnHere();
    308                    }
    309                }
    310
    311                return false;
    312            }
    313        }
    314
    315        /**
    316         * Returns the volume for the sounds this mob makes.
    317         */
    318        protected float getSoundVolume()
    319        {
    320            return 0.4F * (float)this.getSlimeSize();
    321        }
    322
    323        /**
    324         * The speed it takes to move the entityliving's rotationPitch through the faceEntity method. This is only currently
    325         * use in wolves.
    326         */
    327        public int getVerticalFaceSpeed()
    328        {
    329            return 0;
    330        }
    331
    332        /**
    333         * Returns true if the slime makes a sound when it jumps (based upon the slime's size)
    334         */
    335        protected boolean makesSoundOnJump()
    336        {
    337            return this.getSlimeSize() > 0;
    338        }
    339
    340        /**
    341         * Returns true if the slime makes a sound when it lands after a jump (based upon the slime's size)
    342         */
    343        protected boolean makesSoundOnLand()
    344        {
    345            return this.getSlimeSize() > 2;
    346        }
    347    }