001 package net.minecraft.src;
002
003 public abstract class EntityCreature extends EntityLiving
004 {
005 private PathEntity pathToEntity;
006
007 /** The Entity this EntityCreature is set to attack. */
008 protected Entity entityToAttack;
009
010 /**
011 * returns true if a creature has attacked recently only used for creepers and skeletons
012 */
013 protected boolean hasAttacked = false;
014
015 /** Used to make a creature speed up and wander away when hit. */
016 protected int fleeingTick = 0;
017
018 public EntityCreature(World par1World)
019 {
020 super(par1World);
021 }
022
023 /**
024 * Disables a mob's ability to move on its own while true.
025 */
026 protected boolean isMovementCeased()
027 {
028 return false;
029 }
030
031 protected void updateEntityActionState()
032 {
033 this.worldObj.theProfiler.startSection("ai");
034
035 if (this.fleeingTick > 0)
036 {
037 --this.fleeingTick;
038 }
039
040 this.hasAttacked = this.isMovementCeased();
041 float var1 = 16.0F;
042
043 if (this.entityToAttack == null)
044 {
045 this.entityToAttack = this.findPlayerToAttack();
046
047 if (this.entityToAttack != null)
048 {
049 this.pathToEntity = this.worldObj.getPathEntityToEntity(this, this.entityToAttack, var1, true, false, false, true);
050 }
051 }
052 else if (this.entityToAttack.isEntityAlive())
053 {
054 float var2 = this.entityToAttack.getDistanceToEntity(this);
055
056 if (this.canEntityBeSeen(this.entityToAttack))
057 {
058 this.attackEntity(this.entityToAttack, var2);
059 }
060 }
061 else
062 {
063 this.entityToAttack = null;
064 }
065
066 this.worldObj.theProfiler.endSection();
067
068 if (!this.hasAttacked && this.entityToAttack != null && (this.pathToEntity == null || this.rand.nextInt(20) == 0))
069 {
070 this.pathToEntity = this.worldObj.getPathEntityToEntity(this, this.entityToAttack, var1, true, false, false, true);
071 }
072 else if (!this.hasAttacked && (this.pathToEntity == null && this.rand.nextInt(180) == 0 || this.rand.nextInt(120) == 0 || this.fleeingTick > 0) && this.entityAge < 100)
073 {
074 this.updateWanderPath();
075 }
076
077 int var21 = MathHelper.floor_double(this.boundingBox.minY + 0.5D);
078 boolean var3 = this.isInWater();
079 boolean var4 = this.handleLavaMovement();
080 this.rotationPitch = 0.0F;
081
082 if (this.pathToEntity != null && this.rand.nextInt(100) != 0)
083 {
084 this.worldObj.theProfiler.startSection("followpath");
085 Vec3 var5 = this.pathToEntity.getPosition(this);
086 double var6 = (double)(this.width * 2.0F);
087
088 while (var5 != null && var5.squareDistanceTo(this.posX, var5.yCoord, this.posZ) < var6 * var6)
089 {
090 this.pathToEntity.incrementPathIndex();
091
092 if (this.pathToEntity.isFinished())
093 {
094 var5 = null;
095 this.pathToEntity = null;
096 }
097 else
098 {
099 var5 = this.pathToEntity.getPosition(this);
100 }
101 }
102
103 this.isJumping = false;
104
105 if (var5 != null)
106 {
107 double var8 = var5.xCoord - this.posX;
108 double var10 = var5.zCoord - this.posZ;
109 double var12 = var5.yCoord - (double)var21;
110 float var14 = (float)(Math.atan2(var10, var8) * 180.0D / Math.PI) - 90.0F;
111 float var15 = MathHelper.wrapAngleTo180_float(var14 - this.rotationYaw);
112 this.moveForward = this.moveSpeed;
113
114 if (var15 > 30.0F)
115 {
116 var15 = 30.0F;
117 }
118
119 if (var15 < -30.0F)
120 {
121 var15 = -30.0F;
122 }
123
124 this.rotationYaw += var15;
125
126 if (this.hasAttacked && this.entityToAttack != null)
127 {
128 double var16 = this.entityToAttack.posX - this.posX;
129 double var18 = this.entityToAttack.posZ - this.posZ;
130 float var20 = this.rotationYaw;
131 this.rotationYaw = (float)(Math.atan2(var18, var16) * 180.0D / Math.PI) - 90.0F;
132 var15 = (var20 - this.rotationYaw + 90.0F) * (float)Math.PI / 180.0F;
133 this.moveStrafing = -MathHelper.sin(var15) * this.moveForward * 1.0F;
134 this.moveForward = MathHelper.cos(var15) * this.moveForward * 1.0F;
135 }
136
137 if (var12 > 0.0D)
138 {
139 this.isJumping = true;
140 }
141 }
142
143 if (this.entityToAttack != null)
144 {
145 this.faceEntity(this.entityToAttack, 30.0F, 30.0F);
146 }
147
148 if (this.isCollidedHorizontally && !this.hasPath())
149 {
150 this.isJumping = true;
151 }
152
153 if (this.rand.nextFloat() < 0.8F && (var3 || var4))
154 {
155 this.isJumping = true;
156 }
157
158 this.worldObj.theProfiler.endSection();
159 }
160 else
161 {
162 super.updateEntityActionState();
163 this.pathToEntity = null;
164 }
165 }
166
167 /**
168 * Time remaining during which the Animal is sped up and flees.
169 */
170 protected void updateWanderPath()
171 {
172 this.worldObj.theProfiler.startSection("stroll");
173 boolean var1 = false;
174 int var2 = -1;
175 int var3 = -1;
176 int var4 = -1;
177 float var5 = -99999.0F;
178
179 for (int var6 = 0; var6 < 10; ++var6)
180 {
181 int var7 = MathHelper.floor_double(this.posX + (double)this.rand.nextInt(13) - 6.0D);
182 int var8 = MathHelper.floor_double(this.posY + (double)this.rand.nextInt(7) - 3.0D);
183 int var9 = MathHelper.floor_double(this.posZ + (double)this.rand.nextInt(13) - 6.0D);
184 float var10 = this.getBlockPathWeight(var7, var8, var9);
185
186 if (var10 > var5)
187 {
188 var5 = var10;
189 var2 = var7;
190 var3 = var8;
191 var4 = var9;
192 var1 = true;
193 }
194 }
195
196 if (var1)
197 {
198 this.pathToEntity = this.worldObj.getEntityPathToXYZ(this, var2, var3, var4, 10.0F, true, false, false, true);
199 }
200
201 this.worldObj.theProfiler.endSection();
202 }
203
204 /**
205 * Basic mob attack. Default to touch of death in EntityCreature. Overridden by each mob to define their attack.
206 */
207 protected void attackEntity(Entity par1Entity, float par2) {}
208
209 /**
210 * Takes a coordinate in and returns a weight to determine how likely this creature will try to path to the block.
211 * Args: x, y, z
212 */
213 public float getBlockPathWeight(int par1, int par2, int par3)
214 {
215 return 0.0F;
216 }
217
218 /**
219 * Finds the closest player within 16 blocks to attack, or null if this Entity isn't interested in attacking
220 * (Animals, Spiders at day, peaceful PigZombies).
221 */
222 protected Entity findPlayerToAttack()
223 {
224 return null;
225 }
226
227 /**
228 * Checks if the entity's current position is a valid location to spawn this entity.
229 */
230 public boolean getCanSpawnHere()
231 {
232 int var1 = MathHelper.floor_double(this.posX);
233 int var2 = MathHelper.floor_double(this.boundingBox.minY);
234 int var3 = MathHelper.floor_double(this.posZ);
235 return super.getCanSpawnHere() && this.getBlockPathWeight(var1, var2, var3) >= 0.0F;
236 }
237
238 /**
239 * Returns true if entity has a path to follow
240 */
241 public boolean hasPath()
242 {
243 return this.pathToEntity != null;
244 }
245
246 /**
247 * sets the Entities walk path in EntityCreature
248 */
249 public void setPathToEntity(PathEntity par1PathEntity)
250 {
251 this.pathToEntity = par1PathEntity;
252 }
253
254 /**
255 * Returns current entities target
256 */
257 public Entity getEntityToAttack()
258 {
259 return this.entityToAttack;
260 }
261
262 /**
263 * Sets the entity which is to be attacked.
264 */
265 public void setTarget(Entity par1Entity)
266 {
267 this.entityToAttack = par1Entity;
268 }
269
270 /**
271 * This method returns a value to be applied directly to entity speed, this factor is less than 1 when a slowdown
272 * potion effect is applied, more than 1 when a haste potion effect is applied and 2 for fleeing entities.
273 */
274 public float getSpeedModifier()
275 {
276 float var1 = super.getSpeedModifier();
277
278 if (this.fleeingTick > 0 && !this.isAIEnabled())
279 {
280 var1 *= 2.0F;
281 }
282
283 return var1;
284 }
285 }