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.GuiMerchant;
009import net.minecraft.client.gui.GuiRepair;
010import net.minecraft.client.gui.GuiScreen;
011import net.minecraft.client.gui.GuiScreenBook;
012import net.minecraft.client.gui.inventory.GuiBeacon;
013import net.minecraft.client.gui.inventory.GuiBrewingStand;
014import net.minecraft.client.gui.inventory.GuiChest;
015import net.minecraft.client.gui.inventory.GuiCrafting;
016import net.minecraft.client.gui.inventory.GuiDispenser;
017import net.minecraft.client.gui.inventory.GuiEditSign;
018import net.minecraft.client.gui.inventory.GuiFurnace;
019import net.minecraft.client.particle.EntityCrit2FX;
020import net.minecraft.client.particle.EntityPickupFX;
021import net.minecraft.entity.Entity;
022import net.minecraft.entity.IMerchant;
023import net.minecraft.entity.player.EntityPlayer;
024import net.minecraft.inventory.IInventory;
025import net.minecraft.item.Item;
026import net.minecraft.item.ItemStack;
027import net.minecraft.potion.Potion;
028import net.minecraft.stats.Achievement;
029import net.minecraft.stats.AchievementList;
030import net.minecraft.stats.StatBase;
031import net.minecraft.tileentity.TileEntity;
032import net.minecraft.tileentity.TileEntityBeacon;
033import net.minecraft.tileentity.TileEntityBrewingStand;
034import net.minecraft.tileentity.TileEntityCommandBlock;
035import net.minecraft.tileentity.TileEntityDispenser;
036import net.minecraft.tileentity.TileEntityFurnace;
037import net.minecraft.tileentity.TileEntitySign;
038import net.minecraft.util.ChunkCoordinates;
039import net.minecraft.util.DamageSource;
040import net.minecraft.util.MathHelper;
041import net.minecraft.util.MouseFilter;
042import net.minecraft.util.MovementInput;
043import net.minecraft.util.Session;
044import net.minecraft.util.StringUtils;
045import net.minecraft.world.World;
046
047@SideOnly(Side.CLIENT)
048public 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 position for this command sender.
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}