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