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 }