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