001 package net.minecraft.src;
002
003 import cpw.mods.fml.common.Side;
004 import cpw.mods.fml.common.asm.SideOnly;
005 import net.minecraft.client.Minecraft;
006
007 @SideOnly(Side.CLIENT)
008 public class EntityPlayerSP extends EntityPlayer
009 {
010 public MovementInput movementInput;
011 protected Minecraft mc;
012
013 /**
014 * Used to tell if the player pressed forward twice. If this is at 0 and it's pressed (And they are allowed to
015 * sprint, aka enough food on the ground etc) it sets this to 7. If it's pressed and it's greater than 0 enable
016 * sprinting.
017 */
018 protected int sprintToggleTimer = 0;
019
020 /** Ticks left before sprinting is disabled. */
021 public int sprintingTicksLeft = 0;
022 public float renderArmYaw;
023 public float renderArmPitch;
024 public float prevRenderArmYaw;
025 public float prevRenderArmPitch;
026 private MouseFilter field_71162_ch = new MouseFilter();
027 private MouseFilter field_71160_ci = new MouseFilter();
028 private MouseFilter field_71161_cj = new MouseFilter();
029
030 /** The amount of time an entity has been in a Portal */
031 public float timeInPortal;
032
033 /** The amount of time an entity has been in a Portal the previous tick */
034 public float prevTimeInPortal;
035
036 public EntityPlayerSP(Minecraft par1Minecraft, World par2World, Session par3Session, int par4)
037 {
038 super(par2World);
039 this.mc = par1Minecraft;
040 this.dimension = par4;
041
042 if (par3Session != null && par3Session.username != null && par3Session.username.length() > 0)
043 {
044 this.skinUrl = "http://skins.minecraft.net/MinecraftSkins/" + StringUtils.stripControlCodes(par3Session.username) + ".png";
045 }
046
047 this.username = par3Session.username;
048 }
049
050 /**
051 * Tries to moves the entity by the passed in displacement. Args: x, y, z
052 */
053 public void moveEntity(double par1, double par3, double par5)
054 {
055 super.moveEntity(par1, par3, par5);
056 }
057
058 public void updateEntityActionState()
059 {
060 super.updateEntityActionState();
061 this.moveStrafing = this.movementInput.moveStrafe;
062 this.moveForward = this.movementInput.moveForward;
063 this.isJumping = this.movementInput.jump;
064 this.prevRenderArmYaw = this.renderArmYaw;
065 this.prevRenderArmPitch = this.renderArmPitch;
066 this.renderArmPitch = (float)((double)this.renderArmPitch + (double)(this.rotationPitch - this.renderArmPitch) * 0.5D);
067 this.renderArmYaw = (float)((double)this.renderArmYaw + (double)(this.rotationYaw - this.renderArmYaw) * 0.5D);
068 }
069
070 /**
071 * Returns whether the entity is in a local (client) world
072 */
073 protected boolean isClientWorld()
074 {
075 return true;
076 }
077
078 /**
079 * Called frequently so the entity can update its state every tick as required. For example, zombies and skeletons
080 * use this to react to sunlight and start to burn.
081 */
082 public void onLivingUpdate()
083 {
084 if (this.sprintingTicksLeft > 0)
085 {
086 --this.sprintingTicksLeft;
087
088 if (this.sprintingTicksLeft == 0)
089 {
090 this.setSprinting(false);
091 }
092 }
093
094 if (this.sprintToggleTimer > 0)
095 {
096 --this.sprintToggleTimer;
097 }
098
099 if (this.mc.playerController.func_78747_a())
100 {
101 this.posX = this.posZ = 0.5D;
102 this.posX = 0.0D;
103 this.posZ = 0.0D;
104 this.rotationYaw = (float)this.ticksExisted / 12.0F;
105 this.rotationPitch = 10.0F;
106 this.posY = 68.5D;
107 }
108 else
109 {
110 if (!this.mc.statFileWriter.hasAchievementUnlocked(AchievementList.openInventory))
111 {
112 this.mc.guiAchievement.queueAchievementInformation(AchievementList.openInventory);
113 }
114
115 this.prevTimeInPortal = this.timeInPortal;
116
117 if (this.inPortal)
118 {
119 if (this.mc.currentScreen != null)
120 {
121 this.mc.displayGuiScreen((GuiScreen)null);
122 }
123
124 if (this.timeInPortal == 0.0F)
125 {
126 this.mc.sndManager.playSoundFX("portal.trigger", 1.0F, this.rand.nextFloat() * 0.4F + 0.8F);
127 }
128
129 this.timeInPortal += 0.0125F;
130
131 if (this.timeInPortal >= 1.0F)
132 {
133 this.timeInPortal = 1.0F;
134 }
135
136 this.inPortal = false;
137 }
138 else if (this.isPotionActive(Potion.confusion) && this.getActivePotionEffect(Potion.confusion).getDuration() > 60)
139 {
140 this.timeInPortal += 0.006666667F;
141
142 if (this.timeInPortal > 1.0F)
143 {
144 this.timeInPortal = 1.0F;
145 }
146 }
147 else
148 {
149 if (this.timeInPortal > 0.0F)
150 {
151 this.timeInPortal -= 0.05F;
152 }
153
154 if (this.timeInPortal < 0.0F)
155 {
156 this.timeInPortal = 0.0F;
157 }
158 }
159
160 if (this.timeUntilPortal > 0)
161 {
162 --this.timeUntilPortal;
163 }
164
165 boolean var1 = this.movementInput.jump;
166 float var2 = 0.8F;
167 boolean var3 = this.movementInput.moveForward >= var2;
168 this.movementInput.updatePlayerMoveState();
169
170 if (this.isUsingItem())
171 {
172 this.movementInput.moveStrafe *= 0.2F;
173 this.movementInput.moveForward *= 0.2F;
174 this.sprintToggleTimer = 0;
175 }
176
177 if (this.movementInput.sneak && this.ySize < 0.2F)
178 {
179 this.ySize = 0.2F;
180 }
181
182 this.pushOutOfBlocks(this.posX - (double)this.width * 0.35D, this.boundingBox.minY + 0.5D, this.posZ + (double)this.width * 0.35D);
183 this.pushOutOfBlocks(this.posX - (double)this.width * 0.35D, this.boundingBox.minY + 0.5D, this.posZ - (double)this.width * 0.35D);
184 this.pushOutOfBlocks(this.posX + (double)this.width * 0.35D, this.boundingBox.minY + 0.5D, this.posZ - (double)this.width * 0.35D);
185 this.pushOutOfBlocks(this.posX + (double)this.width * 0.35D, this.boundingBox.minY + 0.5D, this.posZ + (double)this.width * 0.35D);
186 boolean var4 = (float)this.getFoodStats().getFoodLevel() > 6.0F || this.capabilities.allowFlying;
187
188 if (this.onGround && !var3 && this.movementInput.moveForward >= var2 && !this.isSprinting() && var4 && !this.isUsingItem() && !this.isPotionActive(Potion.blindness))
189 {
190 if (this.sprintToggleTimer == 0)
191 {
192 this.sprintToggleTimer = 7;
193 }
194 else
195 {
196 this.setSprinting(true);
197 this.sprintToggleTimer = 0;
198 }
199 }
200
201 if (this.isSneaking())
202 {
203 this.sprintToggleTimer = 0;
204 }
205
206 if (this.isSprinting() && (this.movementInput.moveForward < var2 || this.isCollidedHorizontally || !var4))
207 {
208 this.setSprinting(false);
209 }
210
211 if (this.capabilities.allowFlying && !var1 && this.movementInput.jump)
212 {
213 if (this.flyToggleTimer == 0)
214 {
215 this.flyToggleTimer = 7;
216 }
217 else
218 {
219 this.capabilities.isFlying = !this.capabilities.isFlying;
220 this.sendPlayerAbilities();
221 this.flyToggleTimer = 0;
222 }
223 }
224
225 if (this.capabilities.isFlying)
226 {
227 if (this.movementInput.sneak)
228 {
229 this.motionY -= 0.15D;
230 }
231
232 if (this.movementInput.jump)
233 {
234 this.motionY += 0.15D;
235 }
236 }
237
238 super.onLivingUpdate();
239
240 if (this.onGround && this.capabilities.isFlying)
241 {
242 this.capabilities.isFlying = false;
243 this.sendPlayerAbilities();
244 }
245 }
246 }
247
248 /**
249 * Gets the player's field of view multiplier. (ex. when flying)
250 */
251 public float getFOVMultiplier()
252 {
253 float var1 = 1.0F;
254
255 if (this.capabilities.isFlying)
256 {
257 var1 *= 1.1F;
258 }
259
260 var1 *= (this.landMovementFactor * this.getSpeedModifier() / this.speedOnGround + 1.0F) / 2.0F;
261
262 if (this.isUsingItem() && this.getItemInUse().itemID == Item.bow.shiftedIndex)
263 {
264 int var2 = this.getItemInUseDuration();
265 float var3 = (float)var2 / 20.0F;
266
267 if (var3 > 1.0F)
268 {
269 var3 = 1.0F;
270 }
271 else
272 {
273 var3 *= var3;
274 }
275
276 var1 *= 1.0F - var3 * 0.15F;
277 }
278
279 return var1;
280 }
281
282 /**
283 * (abstract) Protected helper method to write subclass entity data to NBT.
284 */
285 public void writeEntityToNBT(NBTTagCompound par1NBTTagCompound)
286 {
287 super.writeEntityToNBT(par1NBTTagCompound);
288 par1NBTTagCompound.setInteger("Score", this.score);
289 }
290
291 public void updateCloak()
292 {
293 this.playerCloakUrl = "http://skins.minecraft.net/MinecraftCloaks/" + StringUtils.stripControlCodes(this.username) + ".png";
294 this.cloakUrl = this.playerCloakUrl;
295 }
296
297 /**
298 * (abstract) Protected helper method to read subclass entity data from NBT.
299 */
300 public void readEntityFromNBT(NBTTagCompound par1NBTTagCompound)
301 {
302 super.readEntityFromNBT(par1NBTTagCompound);
303 this.score = par1NBTTagCompound.getInteger("Score");
304 }
305
306 /**
307 * sets current screen to null (used on escape buttons of GUIs)
308 */
309 public void closeScreen()
310 {
311 super.closeScreen();
312 this.mc.displayGuiScreen((GuiScreen)null);
313 }
314
315 /**
316 * Displays the GUI for editing a sign. Args: tileEntitySign
317 */
318 public void displayGUIEditSign(TileEntity par1TileEntity)
319 {
320 if (par1TileEntity instanceof TileEntitySign)
321 {
322 this.mc.displayGuiScreen(new GuiEditSign((TileEntitySign)par1TileEntity));
323 }
324 else if (par1TileEntity instanceof TileEntityCommandBlock)
325 {
326 this.mc.displayGuiScreen(new GuiCommandBlock((TileEntityCommandBlock)par1TileEntity));
327 }
328 }
329
330 /**
331 * Displays the GUI for interacting with a book.
332 */
333 public void displayGUIBook(ItemStack par1ItemStack)
334 {
335 Item var2 = par1ItemStack.getItem();
336
337 if (var2 == Item.writtenBook)
338 {
339 this.mc.displayGuiScreen(new GuiScreenBook(this, par1ItemStack, false));
340 }
341 else if (var2 == Item.writableBook)
342 {
343 this.mc.displayGuiScreen(new GuiScreenBook(this, par1ItemStack, true));
344 }
345 }
346
347 /**
348 * Displays the GUI for interacting with a chest inventory. Args: chestInventory
349 */
350 public void displayGUIChest(IInventory par1IInventory)
351 {
352 this.mc.displayGuiScreen(new GuiChest(this.inventory, par1IInventory));
353 }
354
355 /**
356 * Displays the crafting GUI for a workbench.
357 */
358 public void displayGUIWorkbench(int par1, int par2, int par3)
359 {
360 this.mc.displayGuiScreen(new GuiCrafting(this.inventory, this.worldObj, par1, par2, par3));
361 }
362
363 public void displayGUIEnchantment(int par1, int par2, int par3)
364 {
365 this.mc.displayGuiScreen(new GuiEnchantment(this.inventory, this.worldObj, par1, par2, par3));
366 }
367
368 /**
369 * Displays the GUI for interacting with an anvil.
370 */
371 public void displayGUIAnvil(int par1, int par2, int par3)
372 {
373 this.mc.displayGuiScreen(new GuiRepair(this.inventory, this.worldObj, par1, par2, par3));
374 }
375
376 /**
377 * Displays the furnace GUI for the passed in furnace entity. Args: tileEntityFurnace
378 */
379 public void displayGUIFurnace(TileEntityFurnace par1TileEntityFurnace)
380 {
381 this.mc.displayGuiScreen(new GuiFurnace(this.inventory, par1TileEntityFurnace));
382 }
383
384 /**
385 * Displays the GUI for interacting with a brewing stand.
386 */
387 public void displayGUIBrewingStand(TileEntityBrewingStand par1TileEntityBrewingStand)
388 {
389 this.mc.displayGuiScreen(new GuiBrewingStand(this.inventory, par1TileEntityBrewingStand));
390 }
391
392 /**
393 * Displays the GUI for interacting with a beacon.
394 */
395 public void displayGUIBeacon(TileEntityBeacon par1TileEntityBeacon)
396 {
397 this.mc.displayGuiScreen(new GuiBeacon(this.inventory, par1TileEntityBeacon));
398 }
399
400 /**
401 * Displays the dipsenser GUI for the passed in dispenser entity. Args: TileEntityDispenser
402 */
403 public void displayGUIDispenser(TileEntityDispenser par1TileEntityDispenser)
404 {
405 this.mc.displayGuiScreen(new GuiDispenser(this.inventory, par1TileEntityDispenser));
406 }
407
408 public void displayGUIMerchant(IMerchant par1IMerchant)
409 {
410 this.mc.displayGuiScreen(new GuiMerchant(this.inventory, par1IMerchant, this.worldObj));
411 }
412
413 /**
414 * Called when the player performs a critical hit on the Entity. Args: entity that was hit critically
415 */
416 public void onCriticalHit(Entity par1Entity)
417 {
418 this.mc.effectRenderer.addEffect(new EntityCrit2FX(this.mc.theWorld, par1Entity));
419 }
420
421 public void onEnchantmentCritical(Entity par1Entity)
422 {
423 EntityCrit2FX var2 = new EntityCrit2FX(this.mc.theWorld, par1Entity, "magicCrit");
424 this.mc.effectRenderer.addEffect(var2);
425 }
426
427 /**
428 * Called whenever an item is picked up from walking over it. Args: pickedUpEntity, stackSize
429 */
430 public void onItemPickup(Entity par1Entity, int par2)
431 {
432 this.mc.effectRenderer.addEffect(new EntityPickupFX(this.mc.theWorld, par1Entity, this, -0.5F));
433 }
434
435 /**
436 * Returns if this entity is sneaking.
437 */
438 public boolean isSneaking()
439 {
440 return this.movementInput.sneak && !this.sleeping;
441 }
442
443 /**
444 * Updates health locally.
445 */
446 public void setHealth(int par1)
447 {
448 int var2 = this.getHealth() - par1;
449
450 if (var2 <= 0)
451 {
452 this.setEntityHealth(par1);
453
454 if (var2 < 0)
455 {
456 this.hurtResistantTime = this.maxHurtResistantTime / 2;
457 }
458 }
459 else
460 {
461 this.lastDamage = var2;
462 this.setEntityHealth(this.getHealth());
463 this.hurtResistantTime = this.maxHurtResistantTime;
464 this.damageEntity(DamageSource.generic, var2);
465 this.hurtTime = this.maxHurtTime = 10;
466 }
467 }
468
469 /**
470 * Add a chat message to the player
471 */
472 public void addChatMessage(String par1Str)
473 {
474 this.mc.ingameGUI.getChatGUI().addTranslatedMessage(par1Str, new Object[0]);
475 }
476
477 /**
478 * Adds a value to a statistic field.
479 */
480 public void addStat(StatBase par1StatBase, int par2)
481 {
482 if (par1StatBase != null)
483 {
484 if (par1StatBase.isAchievement())
485 {
486 Achievement var3 = (Achievement)par1StatBase;
487
488 if (var3.parentAchievement == null || this.mc.statFileWriter.hasAchievementUnlocked(var3.parentAchievement))
489 {
490 if (!this.mc.statFileWriter.hasAchievementUnlocked(var3))
491 {
492 this.mc.guiAchievement.queueTakenAchievement(var3);
493 }
494
495 this.mc.statFileWriter.readStat(par1StatBase, par2);
496 }
497 }
498 else
499 {
500 this.mc.statFileWriter.readStat(par1StatBase, par2);
501 }
502 }
503 }
504
505 private boolean isBlockTranslucent(int par1, int par2, int par3)
506 {
507 return this.worldObj.isBlockNormalCube(par1, par2, par3);
508 }
509
510 /**
511 * Adds velocity to push the entity out of blocks at the specified x, y, z position Args: x, y, z
512 */
513 protected boolean pushOutOfBlocks(double par1, double par3, double par5)
514 {
515 int var7 = MathHelper.floor_double(par1);
516 int var8 = MathHelper.floor_double(par3);
517 int var9 = MathHelper.floor_double(par5);
518 double var10 = par1 - (double)var7;
519 double var12 = par5 - (double)var9;
520
521 if (this.isBlockTranslucent(var7, var8, var9) || this.isBlockTranslucent(var7, var8 + 1, var9))
522 {
523 boolean var14 = !this.isBlockTranslucent(var7 - 1, var8, var9) && !this.isBlockTranslucent(var7 - 1, var8 + 1, var9);
524 boolean var15 = !this.isBlockTranslucent(var7 + 1, var8, var9) && !this.isBlockTranslucent(var7 + 1, var8 + 1, var9);
525 boolean var16 = !this.isBlockTranslucent(var7, var8, var9 - 1) && !this.isBlockTranslucent(var7, var8 + 1, var9 - 1);
526 boolean var17 = !this.isBlockTranslucent(var7, var8, var9 + 1) && !this.isBlockTranslucent(var7, var8 + 1, var9 + 1);
527 byte var18 = -1;
528 double var19 = 9999.0D;
529
530 if (var14 && var10 < var19)
531 {
532 var19 = var10;
533 var18 = 0;
534 }
535
536 if (var15 && 1.0D - var10 < var19)
537 {
538 var19 = 1.0D - var10;
539 var18 = 1;
540 }
541
542 if (var16 && var12 < var19)
543 {
544 var19 = var12;
545 var18 = 4;
546 }
547
548 if (var17 && 1.0D - var12 < var19)
549 {
550 var19 = 1.0D - var12;
551 var18 = 5;
552 }
553
554 float var21 = 0.1F;
555
556 if (var18 == 0)
557 {
558 this.motionX = (double)(-var21);
559 }
560
561 if (var18 == 1)
562 {
563 this.motionX = (double)var21;
564 }
565
566 if (var18 == 4)
567 {
568 this.motionZ = (double)(-var21);
569 }
570
571 if (var18 == 5)
572 {
573 this.motionZ = (double)var21;
574 }
575 }
576
577 return false;
578 }
579
580 /**
581 * Set sprinting switch for Entity.
582 */
583 public void setSprinting(boolean par1)
584 {
585 super.setSprinting(par1);
586 this.sprintingTicksLeft = par1 ? 600 : 0;
587 }
588
589 /**
590 * Sets the current XP, total XP, and level number.
591 */
592 public void setXPStats(float par1, int par2, int par3)
593 {
594 this.experience = par1;
595 this.experienceTotal = par2;
596 this.experienceLevel = par3;
597 }
598
599 public void sendChatToPlayer(String par1Str)
600 {
601 this.mc.ingameGUI.getChatGUI().printChatMessage(par1Str);
602 }
603
604 /**
605 * Returns true if the command sender is allowed to use the given command.
606 */
607 public boolean canCommandSenderUseCommand(int par1, String par2Str)
608 {
609 return par1 <= 0;
610 }
611
612 /**
613 * Return the coordinates for this player as ChunkCoordinates.
614 */
615 public ChunkCoordinates getPlayerCoordinates()
616 {
617 return new ChunkCoordinates(MathHelper.floor_double(this.posX + 0.5D), MathHelper.floor_double(this.posY + 0.5D), MathHelper.floor_double(this.posZ + 0.5D));
618 }
619
620 /**
621 * Returns the item that this EntityLiving is holding, if any.
622 */
623 public ItemStack getHeldItem()
624 {
625 return this.inventory.getCurrentItem();
626 }
627 }