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