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