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