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