    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}