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    }