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