    001    package net.minecraft.entity.passive;
    002
    003    import java.util.Calendar;
    004    import net.minecraft.entity.Entity;
    005    import net.minecraft.entity.player.EntityPlayer;
    006    import net.minecraft.nbt.NBTTagCompound;
    007    import net.minecraft.util.ChunkCoordinates;
    008    import net.minecraft.util.DamageSource;
    009    import net.minecraft.util.MathHelper;
    010    import net.minecraft.world.World;
    011
    012    public class EntityBat extends EntityAmbientCreature
    013    {
    014        /**
    015         * randomly selected ChunkCoordinates in a 7x6x7 box around the bat (y offset -2 to 4) towards which it will fly.
    016         * upon getting close a new target will be selected
    017         */
    018        private ChunkCoordinates currentFlightTarget;
    019
    020        public EntityBat(World par1World)
    021        {
    022            super(par1World);
    023            this.texture = "/mob/bat.png";
    024            this.setSize(0.5F, 0.9F);
    025            this.setIsBatHanging(true);
    026        }
    027
    028        protected void entityInit()
    029        {
    030            super.entityInit();
    031            this.dataWatcher.addObject(16, new Byte((byte)0));
    032        }
    033
    034        /**
    035         * Returns the volume for the sounds this mob makes.
    036         */
    037        protected float getSoundVolume()
    038        {
    039            return 0.1F;
    040        }
    041
    042        /**
    043         * Gets the pitch of living sounds in living entities.
    044         */
    045        protected float getSoundPitch()
    046        {
    047            return super.getSoundPitch() * 0.95F;
    048        }
    049
    050        /**
    051         * Returns the sound this mob makes while it's alive.
    052         */
    053        protected String getLivingSound()
    054        {
    055            return this.getIsBatHanging() && this.rand.nextInt(4) != 0 ? null : "mob.bat.idle";
    056        }
    057
    058        /**
    059         * Returns the sound this mob makes when it is hurt.
    060         */
    061        protected String getHurtSound()
    062        {
    063            return "mob.bat.hurt";
    064        }
    065
    066        /**
    067         * Returns the sound this mob makes on death.
    068         */
    069        protected String getDeathSound()
    070        {
    071            return "mob.bat.death";
    072        }
    073
    074        /**
    075         * Returns true if this entity should push and be pushed by other entities when colliding.
    076         */
    077        public boolean canBePushed()
    078        {
    079            return false;
    080        }
    081
    082        protected void collideWithEntity(Entity par1Entity) {}
    083
    084        protected void func_85033_bc() {}
    085
    086        public int getMaxHealth()
    087        {
    088            return 6;
    089        }
    090
    091        public boolean getIsBatHanging()
    092        {
    093            return (this.dataWatcher.getWatchableObjectByte(16) & 1) != 0;
    094        }
    095
    096        public void setIsBatHanging(boolean par1)
    097        {
    098            byte var2 = this.dataWatcher.getWatchableObjectByte(16);
    099
    100            if (par1)
    101            {
    102                this.dataWatcher.updateObject(16, Byte.valueOf((byte)(var2 | 1)));
    103            }
    104            else
    105            {
    106                this.dataWatcher.updateObject(16, Byte.valueOf((byte)(var2 & -2)));
    107            }
    108        }
    109
    110        /**
    111         * Returns true if the newer Entity AI code should be run
    112         */
    113        protected boolean isAIEnabled()
    114        {
    115            return true;
    116        }
    117
    118        /**
    119         * Called to update the entity's position/logic.
    120         */
    121        public void onUpdate()
    122        {
    123            super.onUpdate();
    124
    125            if (this.getIsBatHanging())
    126            {
    127                this.motionX = this.motionY = this.motionZ = 0.0D;
    128                this.posY = (double)MathHelper.floor_double(this.posY) + 1.0D - (double)this.height;
    129            }
    130            else
    131            {
    132                this.motionY *= 0.6000000238418579D;
    133            }
    134        }
    135
    136        protected void updateAITasks()
    137        {
    138            super.updateAITasks();
    139
    140            if (this.getIsBatHanging())
    141            {
    142                if (!this.worldObj.isBlockNormalCube(MathHelper.floor_double(this.posX), (int)this.posY + 1, MathHelper.floor_double(this.posZ)))
    143                {
    144                    this.setIsBatHanging(false);
    145                    this.worldObj.playAuxSFXAtEntity((EntityPlayer)null, 1015, (int)this.posX, (int)this.posY, (int)this.posZ, 0);
    146                }
    147                else
    148                {
    149                    if (this.rand.nextInt(200) == 0)
    150                    {
    151                        this.rotationYawHead = (float)this.rand.nextInt(360);
    152                    }
    153
    154                    if (this.worldObj.getClosestPlayerToEntity(this, 4.0D) != null)
    155                    {
    156                        this.setIsBatHanging(false);
    157                        this.worldObj.playAuxSFXAtEntity((EntityPlayer)null, 1015, (int)this.posX, (int)this.posY, (int)this.posZ, 0);
    158                    }
    159                }
    160            }
    161            else
    162            {
    163                if (this.currentFlightTarget != null && (!this.worldObj.isAirBlock(this.currentFlightTarget.posX, this.currentFlightTarget.posY, this.currentFlightTarget.posZ) || this.currentFlightTarget.posY < 1))
    164                {
    165                    this.currentFlightTarget = null;
    166                }
    167
    168                if (this.currentFlightTarget == null || this.rand.nextInt(30) == 0 || this.currentFlightTarget.getDistanceSquared((int)this.posX, (int)this.posY, (int)this.posZ) < 4.0F)
    169                {
    170                    this.currentFlightTarget = new ChunkCoordinates((int)this.posX + this.rand.nextInt(7) - this.rand.nextInt(7), (int)this.posY + this.rand.nextInt(6) - 2, (int)this.posZ + this.rand.nextInt(7) - this.rand.nextInt(7));
    171                }
    172
    173                double var1 = (double)this.currentFlightTarget.posX + 0.5D - this.posX;
    174                double var3 = (double)this.currentFlightTarget.posY + 0.1D - this.posY;
    175                double var5 = (double)this.currentFlightTarget.posZ + 0.5D - this.posZ;
    176                this.motionX += (Math.signum(var1) * 0.5D - this.motionX) * 0.10000000149011612D;
    177                this.motionY += (Math.signum(var3) * 0.699999988079071D - this.motionY) * 0.10000000149011612D;
    178                this.motionZ += (Math.signum(var5) * 0.5D - this.motionZ) * 0.10000000149011612D;
    179                float var7 = (float)(Math.atan2(this.motionZ, this.motionX) * 180.0D / Math.PI) - 90.0F;
    180                float var8 = MathHelper.wrapAngleTo180_float(var7 - this.rotationYaw);
    181                this.moveForward = 0.5F;
    182                this.rotationYaw += var8;
    183
    184                if (this.rand.nextInt(100) == 0 && this.worldObj.isBlockNormalCube(MathHelper.floor_double(this.posX), (int)this.posY + 1, MathHelper.floor_double(this.posZ)))
    185                {
    186                    this.setIsBatHanging(true);
    187                }
    188            }
    189        }
    190
    191        /**
    192         * returns if this entity triggers Block.onEntityWalking on the blocks they walk on. used for spiders and wolves to
    193         * prevent them from trampling crops
    194         */
    195        protected boolean canTriggerWalking()
    196        {
    197            return false;
    198        }
    199
    200        /**
    201         * Called when the mob is falling. Calculates and applies fall damage.
    202         */
    203        protected void fall(float par1) {}
    204
    205        /**
    206         * Takes in the distance the entity has fallen this tick and whether its on the ground to update the fall distance
    207         * and deal fall damage if landing on the ground.  Args: distanceFallenThisTick, onGround
    208         */
    209        protected void updateFallState(double par1, boolean par3) {}
    210
    211        /**
    212         * Return whether this entity should NOT trigger a pressure plate or a tripwire.
    213         */
    214        public boolean doesEntityNotTriggerPressurePlate()
    215        {
    216            return true;
    217        }
    218
    219        /**
    220         * Called when the entity is attacked.
    221         */
    222        public boolean attackEntityFrom(DamageSource par1DamageSource, int par2)
    223        {
    224            if (this.func_85032_ar())
    225            {
    226                return false;
    227            }
    228            else
    229            {
    230                if (!this.worldObj.isRemote && this.getIsBatHanging())
    231                {
    232                    this.setIsBatHanging(false);
    233                }
    234
    235                return super.attackEntityFrom(par1DamageSource, par2);
    236            }
    237        }
    238
    239        /**
    240         * (abstract) Protected helper method to read subclass entity data from NBT.
    241         */
    242        public void readEntityFromNBT(NBTTagCompound par1NBTTagCompound)
    243        {
    244            super.readEntityFromNBT(par1NBTTagCompound);
    245            this.dataWatcher.updateObject(16, Byte.valueOf(par1NBTTagCompound.getByte("BatFlags")));
    246        }
    247
    248        /**
    249         * (abstract) Protected helper method to write subclass entity data to NBT.
    250         */
    251        public void writeEntityToNBT(NBTTagCompound par1NBTTagCompound)
    252        {
    253            super.writeEntityToNBT(par1NBTTagCompound);
    254            par1NBTTagCompound.setByte("BatFlags", this.dataWatcher.getWatchableObjectByte(16));
    255        }
    256
    257        /**
    258         * Checks if the entity's current position is a valid location to spawn this entity.
    259         */
    260        public boolean getCanSpawnHere()
    261        {
    262            int var1 = MathHelper.floor_double(this.boundingBox.minY);
    263
    264            if (var1 >= 63)
    265            {
    266                return false;
    267            }
    268            else
    269            {
    270                int var2 = MathHelper.floor_double(this.posX);
    271                int var3 = MathHelper.floor_double(this.posZ);
    272                int var4 = this.worldObj.getBlockLightValue(var2, var1, var3);
    273                byte var5 = 4;
    274                Calendar var6 = this.worldObj.getCurrentDate();
    275
    276                if ((var6.get(2) + 1 != 10 || var6.get(5) < 20) && (var6.get(2) + 1 != 11 || var6.get(5) > 3))
    277                {
    278                    if (this.rand.nextBoolean())
    279                    {
    280                        return false;
    281                    }
    282                }
    283                else
    284                {
    285                    var5 = 7;
    286                }
    287
    288                return var4 > this.rand.nextInt(var5) ? false : super.getCanSpawnHere();
    289            }
    290        }
    291
    292        /**
    293         * Initialize this creature.
    294         */
    295        public void initCreature() {}
    296    }