initial commit
This commit is contained in:
parent
3c9ee26b06
commit
22186c33b9
1458 changed files with 282792 additions and 0 deletions
96
java/src/game/ai/AIFireballAttack.java
Executable file
96
java/src/game/ai/AIFireballAttack.java
Executable file
|
@ -0,0 +1,96 @@
|
|||
package game.ai;
|
||||
|
||||
import game.entity.npc.EntityNPC;
|
||||
import game.entity.projectile.EntityFireball;
|
||||
import game.entity.types.EntityLiving;
|
||||
import game.init.Items;
|
||||
import game.item.ItemStack;
|
||||
import game.world.BlockPos;
|
||||
import game.world.Vec3;
|
||||
import game.world.World;
|
||||
|
||||
public class AIFireballAttack extends EntityAIBase
|
||||
{
|
||||
public final int power;
|
||||
public final int delay;
|
||||
public final double distance;
|
||||
public final double velocity;
|
||||
private final EntityNPC parentEntity;
|
||||
public int attackTimer;
|
||||
|
||||
public AIFireballAttack(EntityNPC entity, int power, int delay, double distance, double velocity)
|
||||
{
|
||||
this.parentEntity = entity;
|
||||
this.power = power;
|
||||
this.delay = delay;
|
||||
this.distance = distance;
|
||||
this.velocity = velocity;
|
||||
// this.setMutexBits(3);
|
||||
}
|
||||
|
||||
public boolean shouldExecute()
|
||||
{
|
||||
return this.parentEntity.getAttackTarget() != null;
|
||||
}
|
||||
|
||||
public void startExecuting()
|
||||
{
|
||||
this.attackTimer = 0;
|
||||
}
|
||||
|
||||
public void resetTask()
|
||||
{
|
||||
this.parentEntity.setItemNoUpdate(0, null);
|
||||
}
|
||||
|
||||
public void updateTask()
|
||||
{
|
||||
EntityLiving target = this.parentEntity.getAttackTarget();
|
||||
// double d0 = 64.0D;
|
||||
|
||||
if (target.getDistanceSqToEntity(this.parentEntity) < this.distance * this.distance && this.parentEntity.canEntityBeSeen(target))
|
||||
{
|
||||
World world = this.parentEntity.worldObj;
|
||||
++this.attackTimer;
|
||||
|
||||
if (this.attackTimer == this.delay)
|
||||
{
|
||||
world.playAuxSFX(1007, new BlockPos(this.parentEntity), 0);
|
||||
this.parentEntity.setItemNoUpdate(0, new ItemStack(Items.orb));
|
||||
}
|
||||
|
||||
if (this.attackTimer == this.delay * 2)
|
||||
{
|
||||
this.parentEntity.swingItem();
|
||||
this.parentEntity.setItemNoUpdate(0, null);
|
||||
double d1 = 1.0D;
|
||||
Vec3 vec3 = this.parentEntity.getLook(1.0F);
|
||||
double d2 = target.posX - (this.parentEntity.posX + vec3.xCoord * d1);
|
||||
double d3 = target.getEntityBoundingBox().minY + (double)(target.height / 2.0F) - (this.parentEntity.posY + (double)this.parentEntity.getEyeHeight());
|
||||
double d4 = target.posZ - (this.parentEntity.posZ + vec3.zCoord * d1);
|
||||
world.playAuxSFX(1008, new BlockPos(this.parentEntity), 0);
|
||||
EntityFireball fireball = new EntityFireball(world, this.parentEntity, d2, d3, d4, this.velocity);
|
||||
// 0.0, 0.0, 0.0);
|
||||
// fireball.setAcceleration(d2 + this.parentEntity.getRNG().gaussian() * 0.1D,
|
||||
// d3 + this.parentEntity.getRNG().gaussian() * 0.1D,
|
||||
// d4 + this.parentEntity.getRNG().gaussian() * 0.1D);
|
||||
// fireball.accelerationX *= this.velocity;
|
||||
// fireball.accelerationY *= this.velocity;
|
||||
// fireball.accelerationZ *= this.velocity;
|
||||
fireball.explosionPower = this.power;
|
||||
fireball.posX = this.parentEntity.posX + vec3.xCoord * d1;
|
||||
fireball.posY = this.parentEntity.posY + (double)this.parentEntity.getEyeHeight();
|
||||
fireball.posZ = this.parentEntity.posZ + vec3.zCoord * d1;
|
||||
world.spawnEntityInWorld(fireball);
|
||||
this.attackTimer = -this.delay * this.parentEntity.getRNG().range(1, 4);
|
||||
}
|
||||
this.parentEntity.getLookHelper().setLookPositionWithEntity(target, 30.0f, 30.0f);
|
||||
}
|
||||
else if (this.attackTimer > 0)
|
||||
{
|
||||
--this.attackTimer;
|
||||
}
|
||||
|
||||
this.parentEntity.setItemNoUpdate(0, this.attackTimer > this.delay ? new ItemStack(Items.orb) : null);
|
||||
}
|
||||
}
|
91
java/src/game/ai/AIFlyingBoxAttack.java
Executable file
91
java/src/game/ai/AIFlyingBoxAttack.java
Executable file
|
@ -0,0 +1,91 @@
|
|||
package game.ai;
|
||||
|
||||
import game.entity.npc.EntityNPC;
|
||||
import game.entity.projectile.EntityBox;
|
||||
import game.entity.types.EntityLiving;
|
||||
import game.world.BlockPos;
|
||||
|
||||
public class AIFlyingBoxAttack extends EntityAIBase
|
||||
{
|
||||
private EntityNPC entity;
|
||||
private int delay;
|
||||
private int charge;
|
||||
|
||||
public AIFlyingBoxAttack(EntityNPC entity)
|
||||
{
|
||||
this.entity = entity;
|
||||
// this.setMutexBits(3);
|
||||
}
|
||||
|
||||
public boolean shouldExecute()
|
||||
{
|
||||
EntityLiving tgt = this.entity.getAttackTarget();
|
||||
return tgt != null && tgt.isEntityAlive();
|
||||
}
|
||||
|
||||
public void startExecuting()
|
||||
{
|
||||
this.delay = 0;
|
||||
this.charge = 0;
|
||||
}
|
||||
|
||||
public void updateTask()
|
||||
{
|
||||
if (this.delay <= 0)
|
||||
{
|
||||
this.delay = this.entity.getRNG().excl(10, 20);
|
||||
|
||||
int k3 = this.charge;
|
||||
++this.charge;
|
||||
|
||||
if (k3 > 15)
|
||||
{
|
||||
float f = 10.0F;
|
||||
float f1 = 5.0F;
|
||||
double d0 = this.entity.getRNG().drange(this.entity.posX - (double)f, this.entity.posX + (double)f);
|
||||
double d1 = this.entity.getRNG().drange(this.entity.posY - (double)f1, this.entity.posY + (double)f1);
|
||||
double d2 = this.entity.getRNG().drange(this.entity.posZ - (double)f, this.entity.posZ + (double)f);
|
||||
this.launchBoxToCoords(d0, d1, d2, true);
|
||||
this.charge = 0;
|
||||
}
|
||||
|
||||
EntityLiving entity = this.entity.getAttackTarget();
|
||||
|
||||
if (entity != null && entity.isEntityAlive() && this.entity.getDistanceSqToEntity(entity) <= 900.0D && this.entity.canEntityBeSeen(entity))
|
||||
{
|
||||
this.launchBoxToEntity(entity);
|
||||
this.delay = this.entity.getRNG().excl(5, 10);
|
||||
this.charge = 0;
|
||||
this.entity.getLookHelper().setLookPositionWithEntity(entity, 30.0F, 30.0F);
|
||||
}
|
||||
}
|
||||
else {
|
||||
--this.delay;
|
||||
}
|
||||
|
||||
super.updateTask();
|
||||
}
|
||||
|
||||
private void launchBoxToEntity(EntityLiving p_82216_2_)
|
||||
{
|
||||
this.launchBoxToCoords(p_82216_2_.posX, p_82216_2_.posY + (double)p_82216_2_.getEyeHeight() * 0.5D, p_82216_2_.posZ,
|
||||
this.entity.getRNG().chance(100));
|
||||
}
|
||||
|
||||
private void launchBoxToCoords(double x, double y, double z, boolean invulnerable)
|
||||
{
|
||||
this.entity.swingItem();
|
||||
this.entity.worldObj.playAuxSFX(1014, new BlockPos(this.entity), 0);
|
||||
double d0 = this.entity.posX;
|
||||
double d1 = this.entity.posY + this.entity.height + 0.8;
|
||||
double d2 = this.entity.posZ;
|
||||
double d3 = x - d0;
|
||||
double d4 = y - d1;
|
||||
double d5 = z - d2;
|
||||
EntityBox skull = new EntityBox(this.entity.worldObj, this.entity, d3, d4, d5, invulnerable);
|
||||
skull.posY = d1;
|
||||
skull.posX = d0;
|
||||
skull.posZ = d2;
|
||||
this.entity.worldObj.spawnEntityInWorld(skull);
|
||||
}
|
||||
}
|
122
java/src/game/ai/AIRangedAttack.java
Executable file
122
java/src/game/ai/AIRangedAttack.java
Executable file
|
@ -0,0 +1,122 @@
|
|||
package game.ai;
|
||||
|
||||
import game.ExtMath;
|
||||
import game.entity.npc.EntityNPC;
|
||||
import game.entity.types.EntityLiving;
|
||||
|
||||
public class AIRangedAttack extends EntityAIBase
|
||||
{
|
||||
private final EntityNPC entity;
|
||||
private EntityLiving target;
|
||||
private int delay;
|
||||
private double speed;
|
||||
private int timeout;
|
||||
private int minDelay;
|
||||
private int maxDelay;
|
||||
private float distance;
|
||||
private float distanceSq;
|
||||
|
||||
public AIRangedAttack(EntityNPC attacker, double movespeed, int minDelay, int maxDelay, float maxAttackDistanceIn)
|
||||
{
|
||||
this.delay = -1;
|
||||
this.entity = attacker;
|
||||
this.speed = movespeed;
|
||||
this.minDelay = minDelay;
|
||||
this.maxDelay = maxDelay;
|
||||
this.distance = maxAttackDistanceIn;
|
||||
this.distanceSq = maxAttackDistanceIn * maxAttackDistanceIn;
|
||||
this.setMutexBits(3);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the EntityAIBase should begin execution.
|
||||
*/
|
||||
public boolean shouldExecute()
|
||||
{
|
||||
if(this.entity.isFleeing())
|
||||
return false;
|
||||
EntityLiving entitylivingbase = this.entity.getAttackTarget();
|
||||
|
||||
if (entitylivingbase == null || entitylivingbase.dead)
|
||||
{
|
||||
this.target = null;
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.target = entitylivingbase;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether an in-progress EntityAIBase should continue executing
|
||||
*/
|
||||
public boolean continueExecuting()
|
||||
{
|
||||
return this.shouldExecute() || (!this.entity.isFleeing() && !this.entity.getNavigator().noPath() && this.target != null && !this.target.dead);
|
||||
}
|
||||
|
||||
public void startExecuting()
|
||||
{
|
||||
this.entity.setUsingItem(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the task
|
||||
*/
|
||||
public void resetTask()
|
||||
{
|
||||
this.target = null;
|
||||
this.timeout = 0;
|
||||
this.delay = -1;
|
||||
this.entity.setUsingItem(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the task
|
||||
*/
|
||||
public void updateTask()
|
||||
{
|
||||
double d0 = this.entity.getDistanceSq(this.target.posX, this.target.getEntityBoundingBox().minY, this.target.posZ);
|
||||
boolean flag = this.entity.getEntitySenses().canSee(this.target);
|
||||
|
||||
if (flag)
|
||||
{
|
||||
++this.timeout;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.timeout = 0;
|
||||
}
|
||||
|
||||
if (d0 <= (double)this.distanceSq && this.timeout >= 20)
|
||||
{
|
||||
this.entity.getNavigator().clearPathEntity();
|
||||
}
|
||||
else
|
||||
{
|
||||
this.entity.getNavigator().tryMoveToEntityLiving(this.target, this.speed);
|
||||
}
|
||||
|
||||
this.entity.getLookHelper().setLookPositionWithEntity(this.target, 30.0F, 30.0F);
|
||||
|
||||
if (--this.delay == 0)
|
||||
{
|
||||
if (d0 > (double)this.distanceSq || !flag)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
float f = ExtMath.sqrtd(d0) / this.distance;
|
||||
float lvt_5_1_ = ExtMath.clampf(f, 0.1F, 1.0F);
|
||||
this.entity.attackEntityWithRangedAttack(this.target, lvt_5_1_);
|
||||
this.delay = ExtMath.floorf(f * (float)(this.maxDelay - this.minDelay) + (float)this.minDelay);
|
||||
}
|
||||
else if (this.delay < 0)
|
||||
{
|
||||
float f2 = ExtMath.sqrtd(d0) / this.distance;
|
||||
this.delay = ExtMath.floorf(f2 * (float)(this.maxDelay - this.minDelay) + (float)this.minDelay);
|
||||
}
|
||||
}
|
||||
}
|
105
java/src/game/ai/AISmallFireballAttack.java
Executable file
105
java/src/game/ai/AISmallFireballAttack.java
Executable file
|
@ -0,0 +1,105 @@
|
|||
package game.ai;
|
||||
|
||||
import game.entity.npc.EntityNPC;
|
||||
import game.entity.projectile.EntityFireCharge;
|
||||
import game.entity.types.EntityLiving;
|
||||
import game.world.BlockPos;
|
||||
|
||||
public class AISmallFireballAttack extends EntityAIBase
|
||||
{
|
||||
private EntityNPC entity;
|
||||
private int timer;
|
||||
private int charge;
|
||||
private int amount;
|
||||
|
||||
public AISmallFireballAttack(EntityNPC entity)
|
||||
{
|
||||
this.entity = entity;
|
||||
this.setMutexBits(3);
|
||||
}
|
||||
|
||||
public boolean shouldExecute()
|
||||
{
|
||||
EntityLiving tgt = this.entity.getAttackTarget();
|
||||
return tgt != null && tgt.isEntityAlive();
|
||||
}
|
||||
|
||||
public void startExecuting()
|
||||
{
|
||||
this.timer = 0;
|
||||
}
|
||||
|
||||
public void resetTask()
|
||||
{
|
||||
this.entity.setAttacking(false);
|
||||
}
|
||||
|
||||
public void updateTask()
|
||||
{
|
||||
--this.charge;
|
||||
EntityLiving target = this.entity.getAttackTarget();
|
||||
double d0 = this.entity.getDistanceSqToEntity(target);
|
||||
|
||||
if (d0 < 4.0D)
|
||||
{
|
||||
if (this.charge <= 0)
|
||||
{
|
||||
this.charge = this.entity.getRNG().range(8, 20);
|
||||
this.entity.attackEntityAsMob(target);
|
||||
}
|
||||
|
||||
this.entity.getMoveHelper().setMoveTo(target.posX, target.posY, target.posZ, 1.0D);
|
||||
}
|
||||
else if (d0 < 256.0D)
|
||||
{
|
||||
double d1 = target.posX - this.entity.posX;
|
||||
double d2 = target.getEntityBoundingBox().minY + (double)(target.height / 2.0F) - (this.entity.posY + (double)(this.entity.height / 2.0F));
|
||||
double d3 = target.posZ - this.entity.posZ;
|
||||
|
||||
if (this.charge <= 0)
|
||||
{
|
||||
++this.timer;
|
||||
|
||||
if (this.timer == 1)
|
||||
{
|
||||
this.charge = this.entity.getRNG().range(10, 20); // 60
|
||||
this.entity.setAttacking(true);
|
||||
this.amount = this.entity.getRNG().range(5, 25);
|
||||
}
|
||||
else if (this.timer <= this.amount)
|
||||
{
|
||||
this.charge = this.entity.getRNG().range(2, 6); // 6
|
||||
}
|
||||
else
|
||||
{
|
||||
this.charge = this.entity.getRNG().range(2, 6); // 100
|
||||
this.timer = 0;
|
||||
this.entity.setAttacking(false);
|
||||
}
|
||||
|
||||
if (this.timer > 1)
|
||||
{
|
||||
this.entity.swingItem();
|
||||
// float f = MathHelper.sqrt_float(MathHelper.sqrt_double(d0)) * 0.5F;
|
||||
this.entity.worldObj.playAuxSFX(1009, new BlockPos((int)this.entity.posX, (int)this.entity.posY, (int)this.entity.posZ), 0);
|
||||
|
||||
for (int i = 0; i < 1; ++i)
|
||||
{
|
||||
EntityFireCharge entitysmallfireball = new EntityFireCharge(this.entity.worldObj, this.entity, d1 /* + this.entity.getRNG().gaussian() * (double)f */, d2, d3 /* + this.entity.getRNG().gaussian() * (double)f */);
|
||||
entitysmallfireball.posY = this.entity.posY + (double)(this.entity.height / 2.0F) + 0.5D;
|
||||
this.entity.worldObj.spawnEntityInWorld(entitysmallfireball);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.entity.getLookHelper().setLookPositionWithEntity(target, 30.0F, 30.0F);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.entity.getNavigator().clearPathEntity();
|
||||
this.entity.getMoveHelper().setMoveTo(target.posX, target.posY, target.posZ, 1.0D);
|
||||
}
|
||||
|
||||
super.updateTask();
|
||||
}
|
||||
}
|
167
java/src/game/ai/EntityAIAttackOnCollide.java
Executable file
167
java/src/game/ai/EntityAIAttackOnCollide.java
Executable file
|
@ -0,0 +1,167 @@
|
|||
package game.ai;
|
||||
|
||||
import game.entity.Entity;
|
||||
import game.entity.types.EntityLiving;
|
||||
import game.pathfinding.PathEntity;
|
||||
import game.world.BlockPos;
|
||||
import game.world.World;
|
||||
|
||||
public class EntityAIAttackOnCollide extends EntityAIBase
|
||||
{
|
||||
World worldObj;
|
||||
protected EntityLiving attacker;
|
||||
|
||||
/**
|
||||
* An amount of decrementing ticks that allows the entity to attack once the tick reaches 0.
|
||||
*/
|
||||
int attackTick;
|
||||
|
||||
/** The speed with which the mob will approach the target */
|
||||
double speedTowardsTarget;
|
||||
|
||||
/**
|
||||
* When true, the mob will continue chasing its target, even if it can't find a path to them right now.
|
||||
*/
|
||||
boolean longMemory;
|
||||
private final boolean swing;
|
||||
|
||||
/** The PathEntity of our entity. */
|
||||
PathEntity entityPathEntity;
|
||||
Class <? extends Entity > classTarget;
|
||||
private int delayCounter;
|
||||
private double targetX;
|
||||
private double targetY;
|
||||
private double targetZ;
|
||||
|
||||
public EntityAIAttackOnCollide(EntityLiving creature, Class <? extends Entity > targetClass, double speedIn, boolean useLongMemory, boolean swingItem)
|
||||
{
|
||||
this(creature, speedIn, useLongMemory, swingItem);
|
||||
this.classTarget = targetClass;
|
||||
}
|
||||
|
||||
public EntityAIAttackOnCollide(EntityLiving creature, double speedIn, boolean useLongMemory, boolean swingItem)
|
||||
{
|
||||
this.attacker = creature;
|
||||
this.worldObj = creature.worldObj;
|
||||
this.speedTowardsTarget = speedIn;
|
||||
this.longMemory = useLongMemory;
|
||||
this.swing = swingItem;
|
||||
this.setMutexBits(3);
|
||||
}
|
||||
|
||||
public EntityAIAttackOnCollide(EntityLiving creature, Class <? extends Entity > targetClass, double speedIn, boolean useLongMemory)
|
||||
{
|
||||
this(creature, speedIn, useLongMemory);
|
||||
this.classTarget = targetClass;
|
||||
}
|
||||
|
||||
public EntityAIAttackOnCollide(EntityLiving creature, double speedIn, boolean useLongMemory)
|
||||
{
|
||||
this(creature, speedIn, useLongMemory, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the EntityAIBase should begin execution.
|
||||
*/
|
||||
public boolean shouldExecute()
|
||||
{
|
||||
EntityLiving entitylivingbase = this.attacker.getAttackTarget();
|
||||
|
||||
if (entitylivingbase == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if (!entitylivingbase.isEntityAlive())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if (this.classTarget != null && !this.classTarget.isAssignableFrom(entitylivingbase.getClass()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.entityPathEntity = this.attacker.getNavigator().getPathToEntityLiving(entitylivingbase);
|
||||
return this.entityPathEntity != null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether an in-progress EntityAIBase should continue executing
|
||||
*/
|
||||
public boolean continueExecuting()
|
||||
{
|
||||
EntityLiving entitylivingbase = this.attacker.getAttackTarget();
|
||||
return entitylivingbase == null ? false : (!entitylivingbase.isEntityAlive() ? false : (!this.longMemory ? !this.attacker.getNavigator().noPath() : this.attacker.isWithinHomeDistanceFromPosition(new BlockPos(entitylivingbase))));
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a one shot task or start executing a continuous task
|
||||
*/
|
||||
public void startExecuting()
|
||||
{
|
||||
this.attacker.getNavigator().setPath(this.entityPathEntity, this.speedTowardsTarget);
|
||||
this.delayCounter = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the task
|
||||
*/
|
||||
public void resetTask()
|
||||
{
|
||||
this.attacker.getNavigator().clearPathEntity();
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the task
|
||||
*/
|
||||
public void updateTask()
|
||||
{
|
||||
EntityLiving entitylivingbase = this.attacker.getAttackTarget();
|
||||
this.attacker.getLookHelper().setLookPositionWithEntity(entitylivingbase, 30.0F, 30.0F);
|
||||
double d0 = this.attacker.getDistanceSq(entitylivingbase.posX, entitylivingbase.getEntityBoundingBox().minY, entitylivingbase.posZ);
|
||||
double d1 = this.getAttackRange(entitylivingbase);
|
||||
--this.delayCounter;
|
||||
|
||||
if ((this.longMemory || this.attacker.getEntitySenses().canSee(entitylivingbase)) && this.delayCounter <= 0 && (this.targetX == 0.0D && this.targetY == 0.0D && this.targetZ == 0.0D || entitylivingbase.getDistanceSq(this.targetX, this.targetY, this.targetZ) >= 1.0D || this.attacker.getRNG().floatv() < 0.05F))
|
||||
{
|
||||
this.targetX = entitylivingbase.posX;
|
||||
this.targetY = entitylivingbase.getEntityBoundingBox().minY;
|
||||
this.targetZ = entitylivingbase.posZ;
|
||||
this.delayCounter = 4 + this.attacker.getRNG().zrange(7);
|
||||
|
||||
if (d0 > 1024.0D)
|
||||
{
|
||||
this.delayCounter += 10;
|
||||
}
|
||||
else if (d0 > 256.0D)
|
||||
{
|
||||
this.delayCounter += 5;
|
||||
}
|
||||
|
||||
if (!this.attacker.getNavigator().tryMoveToEntityLiving(entitylivingbase, this.speedTowardsTarget))
|
||||
{
|
||||
this.delayCounter += 15;
|
||||
}
|
||||
}
|
||||
|
||||
this.attackTick = Math.max(this.attackTick - 1, 0);
|
||||
|
||||
if (d0 <= d1 && this.attackTick <= 0)
|
||||
{
|
||||
this.attackTick = 20;
|
||||
|
||||
// if (this.attacker.getHeldItem() != null)
|
||||
// {
|
||||
this.attacker.swingItem();
|
||||
// }
|
||||
|
||||
this.attacker.attackEntityAsMob(entitylivingbase);
|
||||
}
|
||||
}
|
||||
|
||||
protected double getAttackRange(EntityLiving attackTarget)
|
||||
{
|
||||
return (double)(this.attacker.width * 2.0F * this.attacker.width * 2.0F + attackTarget.width);
|
||||
}
|
||||
}
|
126
java/src/game/ai/EntityAIAvoidEntity.java
Executable file
126
java/src/game/ai/EntityAIAvoidEntity.java
Executable file
|
@ -0,0 +1,126 @@
|
|||
package game.ai;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import game.Predicates;
|
||||
import game.entity.Entity;
|
||||
import game.entity.types.EntityLiving;
|
||||
import game.pathfinding.PathEntity;
|
||||
import game.pathfinding.PathNavigate;
|
||||
import game.world.Vec3;
|
||||
|
||||
public class EntityAIAvoidEntity<T extends Entity> extends EntityAIBase
|
||||
{
|
||||
private final Predicate<Entity> canBeSeenSelector;
|
||||
|
||||
/** The entity we are attached to */
|
||||
protected EntityLiving theEntity;
|
||||
private double farSpeed;
|
||||
private double nearSpeed;
|
||||
protected T closestLivingEntity;
|
||||
private float avoidDistance;
|
||||
|
||||
/** The PathEntity of our entity */
|
||||
private PathEntity entityPathEntity;
|
||||
|
||||
/** The PathNavigate of our entity */
|
||||
private PathNavigate entityPathNavigate;
|
||||
private Class<T> classToAvoid;
|
||||
private Predicate <? super T > avoidTargetSelector;
|
||||
|
||||
public EntityAIAvoidEntity(EntityLiving theEntityIn, Class<T> classToAvoidIn, float avoidDistanceIn, double farSpeedIn, double nearSpeedIn)
|
||||
{
|
||||
this(theEntityIn, classToAvoidIn, Predicates.<T>alwaysTrue(), avoidDistanceIn, farSpeedIn, nearSpeedIn);
|
||||
}
|
||||
|
||||
public EntityAIAvoidEntity(EntityLiving theEntityIn, Class<T> classToAvoidIn, Predicate <? super T > avoidTargetSelectorIn, float avoidDistanceIn, double farSpeedIn, double nearSpeedIn)
|
||||
{
|
||||
this.canBeSeenSelector = new Predicate<Entity>()
|
||||
{
|
||||
public boolean test(Entity p_apply_1_)
|
||||
{
|
||||
return p_apply_1_.isEntityAlive() && EntityAIAvoidEntity.this.theEntity.getEntitySenses().canSee(p_apply_1_);
|
||||
}
|
||||
};
|
||||
this.theEntity = theEntityIn;
|
||||
this.classToAvoid = classToAvoidIn;
|
||||
this.avoidTargetSelector = avoidTargetSelectorIn;
|
||||
this.avoidDistance = avoidDistanceIn;
|
||||
this.farSpeed = farSpeedIn;
|
||||
this.nearSpeed = nearSpeedIn;
|
||||
this.entityPathNavigate = theEntityIn.getNavigator();
|
||||
this.setMutexBits(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the EntityAIBase should begin execution.
|
||||
*/
|
||||
public boolean shouldExecute()
|
||||
{
|
||||
List<T> list = this.theEntity.worldObj.<T>getEntitiesWithinAABB(this.classToAvoid, this.theEntity.getEntityBoundingBox().expand((double)this.avoidDistance, 3.0D, (double)this.avoidDistance), Predicates.and(new Predicate[] {this.canBeSeenSelector, this.avoidTargetSelector}));
|
||||
|
||||
if (list.isEmpty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.closestLivingEntity = list.get(0);
|
||||
Vec3 vec3 = RandomPositionGenerator.findRandomTargetBlockAwayFrom(this.theEntity, 16, 7, new Vec3(this.closestLivingEntity.posX, this.closestLivingEntity.posY, this.closestLivingEntity.posZ));
|
||||
|
||||
if (vec3 == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if (this.closestLivingEntity.getDistanceSq(vec3.xCoord, vec3.yCoord, vec3.zCoord) < this.closestLivingEntity.getDistanceSqToEntity(this.theEntity))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.entityPathEntity = this.entityPathNavigate.getPathToXYZ(vec3.xCoord, vec3.yCoord, vec3.zCoord);
|
||||
return this.entityPathEntity == null ? false : this.entityPathEntity.isDestinationSame(vec3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether an in-progress EntityAIBase should continue executing
|
||||
*/
|
||||
public boolean continueExecuting()
|
||||
{
|
||||
return !this.entityPathNavigate.noPath();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a one shot task or start executing a continuous task
|
||||
*/
|
||||
public void startExecuting()
|
||||
{
|
||||
this.entityPathNavigate.setPath(this.entityPathEntity, this.farSpeed);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the task
|
||||
*/
|
||||
public void resetTask()
|
||||
{
|
||||
this.closestLivingEntity = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the task
|
||||
*/
|
||||
public void updateTask()
|
||||
{
|
||||
if (this.theEntity.getDistanceSqToEntity(this.closestLivingEntity) < 49.0D)
|
||||
{
|
||||
this.theEntity.getNavigator().setSpeed(this.nearSpeed);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.theEntity.getNavigator().setSpeed(this.farSpeed);
|
||||
}
|
||||
}
|
||||
}
|
71
java/src/game/ai/EntityAIBase.java
Executable file
71
java/src/game/ai/EntityAIBase.java
Executable file
|
@ -0,0 +1,71 @@
|
|||
package game.ai;
|
||||
|
||||
public abstract class EntityAIBase
|
||||
{
|
||||
/**
|
||||
* A bitmask telling which other tasks may not run concurrently. The test is a simple bitwise AND - if it yields
|
||||
* zero, the two tasks may run concurrently, if not - they must run exclusively from each other.
|
||||
*/
|
||||
private int mutexBits;
|
||||
|
||||
/**
|
||||
* Returns whether the EntityAIBase should begin execution.
|
||||
*/
|
||||
public abstract boolean shouldExecute();
|
||||
|
||||
/**
|
||||
* Returns whether an in-progress EntityAIBase should continue executing
|
||||
*/
|
||||
public boolean continueExecuting()
|
||||
{
|
||||
return this.shouldExecute();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if this AI Task is interruptible by a higher (= lower value) priority task. All vanilla AITask have
|
||||
* this value set to true.
|
||||
*/
|
||||
public boolean isInterruptible()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a one shot task or start executing a continuous task
|
||||
*/
|
||||
public void startExecuting()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the task
|
||||
*/
|
||||
public void resetTask()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the task
|
||||
*/
|
||||
public void updateTask()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a bitmask telling which other tasks may not run concurrently. The test is a simple bitwise AND - if it
|
||||
* yields zero, the two tasks may run concurrently, if not - they must run exclusively from each other.
|
||||
*/
|
||||
public void setMutexBits(int mutexBitsIn)
|
||||
{
|
||||
this.mutexBits = mutexBitsIn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a bitmask telling which other tasks may not run concurrently. The test is a simple bitwise AND - if it yields
|
||||
* zero, the two tasks may run concurrently, if not - they must run exclusively from each other.
|
||||
*/
|
||||
public int getMutexBits()
|
||||
{
|
||||
return this.mutexBits;
|
||||
}
|
||||
}
|
77
java/src/game/ai/EntityAIBeg.java
Executable file
77
java/src/game/ai/EntityAIBeg.java
Executable file
|
@ -0,0 +1,77 @@
|
|||
package game.ai;
|
||||
|
||||
import game.entity.animal.EntityWolf;
|
||||
import game.entity.npc.EntityNPC;
|
||||
import game.init.Items;
|
||||
import game.item.ItemStack;
|
||||
import game.world.World;
|
||||
|
||||
public class EntityAIBeg extends EntityAIBase
|
||||
{
|
||||
private EntityWolf theWolf;
|
||||
private EntityNPC thePlayer;
|
||||
private World worldObject;
|
||||
private float minPlayerDistance;
|
||||
private int timeoutCounter;
|
||||
|
||||
public EntityAIBeg(EntityWolf wolf, float minDistance)
|
||||
{
|
||||
this.theWolf = wolf;
|
||||
this.worldObject = wolf.worldObj;
|
||||
this.minPlayerDistance = minDistance;
|
||||
this.setMutexBits(2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the EntityAIBase should begin execution.
|
||||
*/
|
||||
public boolean shouldExecute()
|
||||
{
|
||||
this.thePlayer = this.worldObject.getClosestPlayerToEntity(this.theWolf, (double)this.minPlayerDistance);
|
||||
return this.thePlayer == null ? false : this.hasPlayerGotBoneInHand(this.thePlayer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether an in-progress EntityAIBase should continue executing
|
||||
*/
|
||||
public boolean continueExecuting()
|
||||
{
|
||||
return !this.thePlayer.isEntityAlive() ? false : (this.theWolf.getDistanceSqToEntity(this.thePlayer) > (double)(this.minPlayerDistance * this.minPlayerDistance) ? false : this.timeoutCounter > 0 && this.hasPlayerGotBoneInHand(this.thePlayer));
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a one shot task or start executing a continuous task
|
||||
*/
|
||||
public void startExecuting()
|
||||
{
|
||||
this.theWolf.setBegging(true);
|
||||
this.timeoutCounter = 40 + this.theWolf.getRNG().zrange(40);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the task
|
||||
*/
|
||||
public void resetTask()
|
||||
{
|
||||
this.theWolf.setBegging(false);
|
||||
this.thePlayer = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the task
|
||||
*/
|
||||
public void updateTask()
|
||||
{
|
||||
this.theWolf.getLookHelper().setLookPosition(this.thePlayer.posX, this.thePlayer.posY + (double)this.thePlayer.getEyeHeight(), this.thePlayer.posZ, 10.0F, (float)this.theWolf.getVerticalFaceSpeed());
|
||||
--this.timeoutCounter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets if the Player has the Bone in the hand.
|
||||
*/
|
||||
private boolean hasPlayerGotBoneInHand(EntityNPC player)
|
||||
{
|
||||
ItemStack itemstack = player.inventory.getCurrentItem();
|
||||
return itemstack == null ? false : (!this.theWolf.isTamed() && itemstack.getItem() == Items.bone ? true : this.theWolf.isBreedingItem(itemstack));
|
||||
}
|
||||
}
|
226
java/src/game/ai/EntityAIControlledByPlayer.java
Executable file
226
java/src/game/ai/EntityAIControlledByPlayer.java
Executable file
|
@ -0,0 +1,226 @@
|
|||
package game.ai;
|
||||
|
||||
import game.ExtMath;
|
||||
import game.block.Block;
|
||||
import game.block.BlockSlab;
|
||||
import game.block.BlockStairs;
|
||||
import game.entity.npc.EntityNPC;
|
||||
import game.entity.types.EntityLiving;
|
||||
import game.init.Items;
|
||||
import game.item.ItemStack;
|
||||
import game.material.Material;
|
||||
import game.pathfinding.WalkNodeProcessor;
|
||||
import game.world.BlockPos;
|
||||
|
||||
public class EntityAIControlledByPlayer extends EntityAIBase
|
||||
{
|
||||
private final EntityLiving thisEntity;
|
||||
private final float maxSpeed;
|
||||
private float currentSpeed;
|
||||
|
||||
/** Whether the entity's speed is boosted. */
|
||||
private boolean speedBoosted;
|
||||
|
||||
/**
|
||||
* Counter for speed boosting, upon reaching maxSpeedBoostTime the speed boost will be disabled
|
||||
*/
|
||||
private int speedBoostTime;
|
||||
|
||||
/** Maximum time the entity's speed should be boosted for. */
|
||||
private int maxSpeedBoostTime;
|
||||
|
||||
public EntityAIControlledByPlayer(EntityLiving entitylivingIn, float maxspeed)
|
||||
{
|
||||
this.thisEntity = entitylivingIn;
|
||||
this.maxSpeed = maxspeed;
|
||||
this.setMutexBits(7);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a one shot task or start executing a continuous task
|
||||
*/
|
||||
public void startExecuting()
|
||||
{
|
||||
this.currentSpeed = 0.0F;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the task
|
||||
*/
|
||||
public void resetTask()
|
||||
{
|
||||
this.speedBoosted = false;
|
||||
this.currentSpeed = 0.0F;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the EntityAIBase should begin execution.
|
||||
*/
|
||||
public boolean shouldExecute()
|
||||
{
|
||||
return this.thisEntity.isEntityAlive() && this.thisEntity.passenger != null && this.thisEntity.passenger.isPlayer() && (this.speedBoosted || this.thisEntity.canBeSteered());
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the task
|
||||
*/
|
||||
public void updateTask()
|
||||
{
|
||||
EntityNPC entityplayer = (EntityNPC)this.thisEntity.passenger;
|
||||
EntityLiving entitycreature = (EntityLiving)this.thisEntity;
|
||||
float f = ExtMath.wrapf(entityplayer.rotYaw - this.thisEntity.rotYaw) * 0.5F;
|
||||
|
||||
if (f > 5.0F)
|
||||
{
|
||||
f = 5.0F;
|
||||
}
|
||||
|
||||
if (f < -5.0F)
|
||||
{
|
||||
f = -5.0F;
|
||||
}
|
||||
|
||||
this.thisEntity.rotYaw = ExtMath.wrapf(this.thisEntity.rotYaw + f);
|
||||
|
||||
if (this.currentSpeed < this.maxSpeed)
|
||||
{
|
||||
this.currentSpeed += (this.maxSpeed - this.currentSpeed) * 0.01F;
|
||||
}
|
||||
|
||||
if (this.currentSpeed > this.maxSpeed)
|
||||
{
|
||||
this.currentSpeed = this.maxSpeed;
|
||||
}
|
||||
|
||||
int i = ExtMath.floord(this.thisEntity.posX);
|
||||
int j = ExtMath.floord(this.thisEntity.posY);
|
||||
int k = ExtMath.floord(this.thisEntity.posZ);
|
||||
float f1 = this.currentSpeed;
|
||||
|
||||
if (this.speedBoosted)
|
||||
{
|
||||
if (this.speedBoostTime++ > this.maxSpeedBoostTime)
|
||||
{
|
||||
this.speedBoosted = false;
|
||||
}
|
||||
|
||||
f1 += f1 * 1.15F * ExtMath.sin((float)this.speedBoostTime / (float)this.maxSpeedBoostTime * (float)Math.PI);
|
||||
}
|
||||
|
||||
float f2 = 0.91F;
|
||||
|
||||
if (this.thisEntity.onGround)
|
||||
{
|
||||
f2 = this.thisEntity.worldObj.getState(new BlockPos(ExtMath.floorf((float)i), ExtMath.floorf((float)j) - 1, ExtMath.floorf((float)k))).getBlock().slipperiness * 0.91F;
|
||||
}
|
||||
|
||||
float f3 = 0.16277136F / (f2 * f2 * f2);
|
||||
float f4 = ExtMath.sin(entitycreature.rotYaw * (float)Math.PI / 180.0F);
|
||||
float f5 = ExtMath.cos(entitycreature.rotYaw * (float)Math.PI / 180.0F);
|
||||
float f6 = entitycreature.getAIMoveSpeed() * f3;
|
||||
float f7 = Math.max(f1, 1.0F);
|
||||
f7 = f6 / f7;
|
||||
float f8 = f1 * f7;
|
||||
float f9 = -(f8 * f4);
|
||||
float f10 = f8 * f5;
|
||||
|
||||
if (ExtMath.absf(f9) > ExtMath.absf(f10))
|
||||
{
|
||||
if (f9 < 0.0F)
|
||||
{
|
||||
f9 -= this.thisEntity.width / 2.0F;
|
||||
}
|
||||
|
||||
if (f9 > 0.0F)
|
||||
{
|
||||
f9 += this.thisEntity.width / 2.0F;
|
||||
}
|
||||
|
||||
f10 = 0.0F;
|
||||
}
|
||||
else
|
||||
{
|
||||
f9 = 0.0F;
|
||||
|
||||
if (f10 < 0.0F)
|
||||
{
|
||||
f10 -= this.thisEntity.width / 2.0F;
|
||||
}
|
||||
|
||||
if (f10 > 0.0F)
|
||||
{
|
||||
f10 += this.thisEntity.width / 2.0F;
|
||||
}
|
||||
}
|
||||
|
||||
int l = ExtMath.floord(this.thisEntity.posX + (double)f9);
|
||||
int i1 = ExtMath.floord(this.thisEntity.posZ + (double)f10);
|
||||
int j1 = ExtMath.floorf(this.thisEntity.width + 1.0F);
|
||||
int k1 = ExtMath.floorf(this.thisEntity.height + entityplayer.height + 1.0F);
|
||||
int l1 = ExtMath.floorf(this.thisEntity.width + 1.0F);
|
||||
|
||||
if (i != l || k != i1)
|
||||
{
|
||||
Block block = this.thisEntity.worldObj.getState(new BlockPos(i, j, k)).getBlock();
|
||||
boolean flag = !this.isStairOrSlab(block) && (block.getMaterial() != Material.air || !this.isStairOrSlab(this.thisEntity.worldObj.getState(new BlockPos(i, j - 1, k)).getBlock()));
|
||||
|
||||
if (flag && 0 == WalkNodeProcessor.getColliding(this.thisEntity.worldObj, this.thisEntity, l, j, i1, j1, k1, l1, false, false, true) && 1 == WalkNodeProcessor.getColliding(this.thisEntity.worldObj, this.thisEntity, i, j + 1, k, j1, k1, l1, false, false, true) && 1 == WalkNodeProcessor.getColliding(this.thisEntity.worldObj, this.thisEntity, l, j + 1, i1, j1, k1, l1, false, false, true))
|
||||
{
|
||||
entitycreature.getJumpHelper().setJumping();
|
||||
}
|
||||
}
|
||||
|
||||
if (/* !entityplayer.creative && */ this.currentSpeed >= this.maxSpeed * 0.5F && this.thisEntity.getRNG().floatv() < 0.006F && !this.speedBoosted)
|
||||
{
|
||||
ItemStack itemstack = entityplayer.getHeldItem();
|
||||
|
||||
if (itemstack != null && itemstack.getItem() == Items.carrot_on_a_stick)
|
||||
{
|
||||
itemstack.damageItem(1, entityplayer);
|
||||
|
||||
if (itemstack.stackSize == 0)
|
||||
{
|
||||
ItemStack itemstack1 = new ItemStack(Items.fishing_rod);
|
||||
itemstack1.setTagCompound(itemstack.getTagCompound());
|
||||
entityplayer.inventory.mainInventory[entityplayer.inventory.currentItem] = itemstack1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.thisEntity.moveEntityWithHeading(0.0F, f1);
|
||||
}
|
||||
|
||||
/**
|
||||
* True if the block is a stair block or a slab block
|
||||
*/
|
||||
private boolean isStairOrSlab(Block blockIn)
|
||||
{
|
||||
return blockIn instanceof BlockStairs || blockIn instanceof BlockSlab;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether the entity's speed is boosted.
|
||||
*/
|
||||
public boolean isSpeedBoosted()
|
||||
{
|
||||
return this.speedBoosted;
|
||||
}
|
||||
|
||||
/**
|
||||
* Boost the entity's movement speed.
|
||||
*/
|
||||
public void boostSpeed()
|
||||
{
|
||||
this.speedBoosted = true;
|
||||
this.speedBoostTime = 0;
|
||||
this.maxSpeedBoostTime = this.thisEntity.getRNG().zrange(841) + 140;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether the entity is being controlled by a player.
|
||||
*/
|
||||
public boolean isControlledByPlayer()
|
||||
{
|
||||
return !this.isSpeedBoosted() && this.currentSpeed > this.maxSpeed * 0.3F;
|
||||
}
|
||||
}
|
118
java/src/game/ai/EntityAIDoorInteract.java
Executable file
118
java/src/game/ai/EntityAIDoorInteract.java
Executable file
|
@ -0,0 +1,118 @@
|
|||
package game.ai;
|
||||
|
||||
import game.block.Block;
|
||||
import game.block.BlockDoor;
|
||||
import game.entity.types.EntityLiving;
|
||||
import game.material.Material;
|
||||
import game.pathfinding.PathEntity;
|
||||
import game.pathfinding.PathNavigateGround;
|
||||
import game.pathfinding.PathPoint;
|
||||
import game.world.BlockPos;
|
||||
|
||||
public abstract class EntityAIDoorInteract extends EntityAIBase
|
||||
{
|
||||
protected EntityLiving theEntity;
|
||||
protected BlockPos doorPosition = BlockPos.ORIGIN;
|
||||
|
||||
/** The wooden door block */
|
||||
protected BlockDoor doorBlock;
|
||||
|
||||
/**
|
||||
* If is true then the Entity has stopped Door Interaction and compoleted the task.
|
||||
*/
|
||||
boolean hasStoppedDoorInteraction;
|
||||
float entityPositionX;
|
||||
float entityPositionZ;
|
||||
|
||||
public EntityAIDoorInteract(EntityLiving entityIn)
|
||||
{
|
||||
this.theEntity = entityIn;
|
||||
|
||||
if (!(entityIn.getNavigator() instanceof PathNavigateGround))
|
||||
{
|
||||
throw new IllegalArgumentException("Unsupported mob type for DoorInteractGoal");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the EntityAIBase should begin execution.
|
||||
*/
|
||||
public boolean shouldExecute()
|
||||
{
|
||||
if (!this.theEntity.collidedHorizontally)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
PathNavigateGround pathnavigateground = (PathNavigateGround)this.theEntity.getNavigator();
|
||||
PathEntity pathentity = pathnavigateground.getPath();
|
||||
|
||||
if (pathentity != null && !pathentity.isFinished() && pathnavigateground.getEnterDoors())
|
||||
{
|
||||
for (int i = 0; i < Math.min(pathentity.getCurrentPathIndex() + 2, pathentity.getCurrentPathLength()); ++i)
|
||||
{
|
||||
PathPoint pathpoint = pathentity.getPathPointFromIndex(i);
|
||||
this.doorPosition = new BlockPos(pathpoint.xCoord, pathpoint.yCoord + 1, pathpoint.zCoord);
|
||||
|
||||
if (this.theEntity.getDistanceSq((double)this.doorPosition.getX(), this.theEntity.posY, (double)this.doorPosition.getZ()) <= 2.25D)
|
||||
{
|
||||
this.doorBlock = this.getBlockDoor(this.doorPosition);
|
||||
|
||||
if (this.doorBlock != null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.doorPosition = (new BlockPos(this.theEntity)).up();
|
||||
this.doorBlock = this.getBlockDoor(this.doorPosition);
|
||||
return this.doorBlock != null;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether an in-progress EntityAIBase should continue executing
|
||||
*/
|
||||
public boolean continueExecuting()
|
||||
{
|
||||
return !this.hasStoppedDoorInteraction;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a one shot task or start executing a continuous task
|
||||
*/
|
||||
public void startExecuting()
|
||||
{
|
||||
this.hasStoppedDoorInteraction = false;
|
||||
this.entityPositionX = (float)((double)((float)this.doorPosition.getX() + 0.5F) - this.theEntity.posX);
|
||||
this.entityPositionZ = (float)((double)((float)this.doorPosition.getZ() + 0.5F) - this.theEntity.posZ);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the task
|
||||
*/
|
||||
public void updateTask()
|
||||
{
|
||||
float f = (float)((double)((float)this.doorPosition.getX() + 0.5F) - this.theEntity.posX);
|
||||
float f1 = (float)((double)((float)this.doorPosition.getZ() + 0.5F) - this.theEntity.posZ);
|
||||
float f2 = this.entityPositionX * f + this.entityPositionZ * f1;
|
||||
|
||||
if (f2 < 0.0F)
|
||||
{
|
||||
this.hasStoppedDoorInteraction = true;
|
||||
}
|
||||
}
|
||||
|
||||
private BlockDoor getBlockDoor(BlockPos pos)
|
||||
{
|
||||
Block block = this.theEntity.worldObj.getState(pos).getBlock();
|
||||
return block instanceof BlockDoor && block.getMaterial() == Material.wood ? (BlockDoor)block : null;
|
||||
}
|
||||
}
|
118
java/src/game/ai/EntityAIEatGrass.java
Executable file
118
java/src/game/ai/EntityAIEatGrass.java
Executable file
|
@ -0,0 +1,118 @@
|
|||
package game.ai;
|
||||
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import game.Predicates;
|
||||
import game.block.BlockTallGrass;
|
||||
import game.entity.animal.EntitySheep;
|
||||
import game.init.BlockRegistry;
|
||||
import game.init.Blocks;
|
||||
import game.init.Config;
|
||||
import game.pattern.BlockStateHelper;
|
||||
import game.world.BlockPos;
|
||||
import game.world.State;
|
||||
import game.world.World;
|
||||
|
||||
public class EntityAIEatGrass extends EntityAIBase
|
||||
{
|
||||
private static final Predicate<State> field_179505_b = BlockStateHelper.forBlock(Blocks.tallgrass).where(BlockTallGrass.TYPE, Predicates.equalTo(BlockTallGrass.EnumType.GRASS));
|
||||
|
||||
private EntitySheep grassEaterEntity;
|
||||
private World entityWorld;
|
||||
int eatingGrassTimer;
|
||||
|
||||
public EntityAIEatGrass(EntitySheep grassEaterEntityIn)
|
||||
{
|
||||
this.grassEaterEntity = grassEaterEntityIn;
|
||||
this.entityWorld = grassEaterEntityIn.worldObj;
|
||||
this.setMutexBits(7);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the EntityAIBase should begin execution.
|
||||
*/
|
||||
public boolean shouldExecute()
|
||||
{
|
||||
if (this.grassEaterEntity.getRNG().zrange(this.grassEaterEntity.isChild() ? 50 : 1000) != 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
BlockPos blockpos = new BlockPos(this.grassEaterEntity.posX, this.grassEaterEntity.posY, this.grassEaterEntity.posZ);
|
||||
return field_179505_b.test(this.entityWorld.getState(blockpos)) ? true : this.entityWorld.getState(blockpos.down()).getBlock() == Blocks.grass;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a one shot task or start executing a continuous task
|
||||
*/
|
||||
public void startExecuting()
|
||||
{
|
||||
this.eatingGrassTimer = 40;
|
||||
this.entityWorld.setEntityState(this.grassEaterEntity, (byte)10);
|
||||
this.grassEaterEntity.getNavigator().clearPathEntity();
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the task
|
||||
*/
|
||||
public void resetTask()
|
||||
{
|
||||
this.eatingGrassTimer = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether an in-progress EntityAIBase should continue executing
|
||||
*/
|
||||
public boolean continueExecuting()
|
||||
{
|
||||
return this.eatingGrassTimer > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Number of ticks since the entity started to eat grass
|
||||
*/
|
||||
public int getEatingGrassTimer()
|
||||
{
|
||||
return this.eatingGrassTimer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the task
|
||||
*/
|
||||
public void updateTask()
|
||||
{
|
||||
this.eatingGrassTimer = Math.max(0, this.eatingGrassTimer - 1);
|
||||
|
||||
if (this.eatingGrassTimer == 4)
|
||||
{
|
||||
BlockPos blockpos = new BlockPos(this.grassEaterEntity.posX, this.grassEaterEntity.posY, this.grassEaterEntity.posZ);
|
||||
|
||||
if (field_179505_b.test(this.entityWorld.getState(blockpos)))
|
||||
{
|
||||
if (Config.mobGrief)
|
||||
{
|
||||
this.entityWorld.destroyBlock(blockpos, false);
|
||||
}
|
||||
|
||||
this.grassEaterEntity.eatGrassBonus();
|
||||
}
|
||||
else
|
||||
{
|
||||
BlockPos blockpos1 = blockpos.down();
|
||||
|
||||
if (this.entityWorld.getState(blockpos1).getBlock() == Blocks.grass)
|
||||
{
|
||||
if (Config.mobGrief)
|
||||
{
|
||||
this.entityWorld.playAuxSFX(2001, blockpos1, BlockRegistry.getIdFromBlock(Blocks.grass));
|
||||
this.entityWorld.setState(blockpos1, Blocks.dirt.getState(), 2);
|
||||
}
|
||||
|
||||
this.grassEaterEntity.eatGrassBonus();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
65
java/src/game/ai/EntityAIExplode.java
Executable file
65
java/src/game/ai/EntityAIExplode.java
Executable file
|
@ -0,0 +1,65 @@
|
|||
package game.ai;
|
||||
|
||||
import game.entity.npc.EntityHaunter;
|
||||
import game.entity.types.EntityLiving;
|
||||
|
||||
public class EntityAIExplode extends EntityAIBase
|
||||
{
|
||||
EntityHaunter entity;
|
||||
EntityLiving target;
|
||||
|
||||
public EntityAIExplode(EntityHaunter entity)
|
||||
{
|
||||
this.entity = entity;
|
||||
this.setMutexBits(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the EntityAIBase should begin execution.
|
||||
*/
|
||||
public boolean shouldExecute()
|
||||
{
|
||||
EntityLiving entitylivingbase = this.entity.getAttackTarget();
|
||||
return this.entity.getExplodeState() > 0 || entitylivingbase != null && this.entity.getDistanceSqToEntity(entitylivingbase) < 9.0D;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a one shot task or start executing a continuous task
|
||||
*/
|
||||
public void startExecuting()
|
||||
{
|
||||
this.entity.getNavigator().clearPathEntity();
|
||||
this.target = this.entity.getAttackTarget();
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the task
|
||||
*/
|
||||
public void resetTask()
|
||||
{
|
||||
this.target = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the task
|
||||
*/
|
||||
public void updateTask()
|
||||
{
|
||||
if (this.target == null)
|
||||
{
|
||||
this.entity.setExplodeState(-1);
|
||||
}
|
||||
else if (this.entity.getDistanceSqToEntity(this.target) > 49.0D)
|
||||
{
|
||||
this.entity.setExplodeState(-1);
|
||||
}
|
||||
else if (!this.entity.getEntitySenses().canSee(this.target))
|
||||
{
|
||||
this.entity.setExplodeState(-1);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.entity.setExplodeState(1);
|
||||
}
|
||||
}
|
||||
}
|
111
java/src/game/ai/EntityAIFindEntityNearest.java
Executable file
111
java/src/game/ai/EntityAIFindEntityNearest.java
Executable file
|
@ -0,0 +1,111 @@
|
|||
package game.ai;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import game.entity.attributes.AttributeInstance;
|
||||
import game.entity.attributes.Attributes;
|
||||
import game.entity.types.EntityLiving;
|
||||
|
||||
public class EntityAIFindEntityNearest extends EntityAIBase
|
||||
{
|
||||
private EntityLiving mob;
|
||||
private final Predicate<EntityLiving> field_179443_c;
|
||||
private final EntityAINearestAttackableTarget.Sorter field_179440_d;
|
||||
private EntityLiving target;
|
||||
private Class <? extends EntityLiving > field_179439_f;
|
||||
|
||||
public EntityAIFindEntityNearest(EntityLiving mobIn, Class <? extends EntityLiving > p_i45884_2_)
|
||||
{
|
||||
this.mob = mobIn;
|
||||
this.field_179439_f = p_i45884_2_;
|
||||
|
||||
// if (mobIn instanceof EntityCreature)
|
||||
// {
|
||||
// Log.CONFIG.warn("Nutze NearestAttackableTargetGoal.class für PathfinderMob-Mobs!");
|
||||
// }
|
||||
|
||||
this.field_179443_c = new Predicate<EntityLiving>()
|
||||
{
|
||||
public boolean test(EntityLiving p_apply_1_)
|
||||
{
|
||||
double d0 = EntityAIFindEntityNearest.this.getFollowRange();
|
||||
|
||||
if (p_apply_1_.isSneaking())
|
||||
{
|
||||
d0 *= 0.800000011920929D;
|
||||
}
|
||||
|
||||
return (double)p_apply_1_.getDistanceToEntity(EntityAIFindEntityNearest.this.mob) > d0 ? false : EntityAITarget.isSuitableTarget(EntityAIFindEntityNearest.this.mob, p_apply_1_, true);
|
||||
}
|
||||
};
|
||||
this.field_179440_d = new EntityAINearestAttackableTarget.Sorter(mobIn);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the EntityAIBase should begin execution.
|
||||
*/
|
||||
public boolean shouldExecute()
|
||||
{
|
||||
double d0 = this.getFollowRange();
|
||||
List<EntityLiving> list = this.mob.worldObj.<EntityLiving>getEntitiesWithinAABB(this.field_179439_f, this.mob.getEntityBoundingBox().expand(d0, 4.0D, d0), this.field_179443_c);
|
||||
Collections.sort(list, this.field_179440_d);
|
||||
|
||||
if (list.isEmpty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.target = (EntityLiving)list.get(0);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether an in-progress EntityAIBase should continue executing
|
||||
*/
|
||||
public boolean continueExecuting()
|
||||
{
|
||||
EntityLiving entitylivingbase = this.mob.getAttackTarget();
|
||||
|
||||
if (entitylivingbase == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if (!entitylivingbase.isEntityAlive())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
double d0 = this.getFollowRange();
|
||||
return this.mob.getDistanceSqToEntity(entitylivingbase) <= d0 * d0; // ? false : !(entitylivingbase.isPlayer()) || !((EntityNPCMP)entitylivingbase).creative;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a one shot task or start executing a continuous task
|
||||
*/
|
||||
public void startExecuting()
|
||||
{
|
||||
this.mob.setAttackTarget(this.target);
|
||||
super.startExecuting();
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the task
|
||||
*/
|
||||
public void resetTask()
|
||||
{
|
||||
this.mob.setAttackTarget((EntityLiving)null);
|
||||
super.startExecuting();
|
||||
}
|
||||
|
||||
protected double getFollowRange()
|
||||
{
|
||||
AttributeInstance iattributeinstance = this.mob.getEntityAttribute(Attributes.FOLLOW_RANGE);
|
||||
return iattributeinstance == null ? 16.0D : iattributeinstance.getAttributeValue();
|
||||
}
|
||||
}
|
95
java/src/game/ai/EntityAIFleeSun.java
Executable file
95
java/src/game/ai/EntityAIFleeSun.java
Executable file
|
@ -0,0 +1,95 @@
|
|||
package game.ai;
|
||||
|
||||
import game.entity.types.EntityLiving;
|
||||
import game.rng.Random;
|
||||
import game.world.BlockPos;
|
||||
import game.world.Vec3;
|
||||
import game.world.World;
|
||||
import game.world.WorldServer;
|
||||
|
||||
public class EntityAIFleeSun extends EntityAIBase
|
||||
{
|
||||
private EntityLiving theCreature;
|
||||
private double shelterX;
|
||||
private double shelterY;
|
||||
private double shelterZ;
|
||||
private double movementSpeed;
|
||||
private World theWorld;
|
||||
|
||||
public EntityAIFleeSun(EntityLiving theCreatureIn, double movementSpeedIn)
|
||||
{
|
||||
this.theCreature = theCreatureIn;
|
||||
this.movementSpeed = movementSpeedIn;
|
||||
this.theWorld = theCreatureIn.worldObj;
|
||||
this.setMutexBits(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the EntityAIBase should begin execution.
|
||||
*/
|
||||
public boolean shouldExecute()
|
||||
{
|
||||
if (!((WorldServer)this.theWorld).isDaytime())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if (!this.theCreature.isBurning())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if (!this.theWorld.canSeeSky(new BlockPos(this.theCreature.posX, this.theCreature.getEntityBoundingBox().minY, this.theCreature.posZ)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
Vec3 vec3 = this.findPossibleShelter();
|
||||
|
||||
if (vec3 == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.shelterX = vec3.xCoord;
|
||||
this.shelterY = vec3.yCoord;
|
||||
this.shelterZ = vec3.zCoord;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether an in-progress EntityAIBase should continue executing
|
||||
*/
|
||||
public boolean continueExecuting()
|
||||
{
|
||||
return !this.theCreature.getNavigator().noPath();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a one shot task or start executing a continuous task
|
||||
*/
|
||||
public void startExecuting()
|
||||
{
|
||||
this.theCreature.getNavigator().tryMoveToXYZ(this.shelterX, this.shelterY, this.shelterZ, this.movementSpeed);
|
||||
}
|
||||
|
||||
private Vec3 findPossibleShelter()
|
||||
{
|
||||
Random random = this.theCreature.getRNG();
|
||||
BlockPos blockpos = new BlockPos(this.theCreature.posX, this.theCreature.getEntityBoundingBox().minY, this.theCreature.posZ);
|
||||
|
||||
for (int i = 0; i < 10; ++i)
|
||||
{
|
||||
BlockPos blockpos1 = blockpos.add(random.zrange(20) - 10, random.zrange(6) - 3, random.zrange(20) - 10);
|
||||
|
||||
if (!this.theWorld.canSeeSky(blockpos1) && this.theCreature.getBlockPathWeight(blockpos1) < 0.0F)
|
||||
{
|
||||
return new Vec3((double)blockpos1.getX(), (double)blockpos1.getY(), (double)blockpos1.getZ());
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
148
java/src/game/ai/EntityAIFollowOwner.java
Executable file
148
java/src/game/ai/EntityAIFollowOwner.java
Executable file
|
@ -0,0 +1,148 @@
|
|||
package game.ai;
|
||||
|
||||
import game.block.Block;
|
||||
import game.entity.types.EntityLiving;
|
||||
import game.entity.types.EntityTameable;
|
||||
import game.init.Blocks;
|
||||
import game.pathfinding.PathNavigate;
|
||||
import game.pathfinding.PathNavigateGround;
|
||||
import game.world.BlockPos;
|
||||
import game.world.State;
|
||||
import game.world.World;
|
||||
|
||||
public class EntityAIFollowOwner extends EntityAIBase
|
||||
{
|
||||
private EntityTameable thePet;
|
||||
private EntityLiving theOwner;
|
||||
World theWorld;
|
||||
private double followSpeed;
|
||||
private PathNavigate petPathfinder;
|
||||
private int field_75343_h;
|
||||
float maxDist;
|
||||
float minDist;
|
||||
private boolean field_75344_i;
|
||||
|
||||
public EntityAIFollowOwner(EntityTameable thePetIn, double followSpeedIn, float minDistIn, float maxDistIn)
|
||||
{
|
||||
this.thePet = thePetIn;
|
||||
this.theWorld = thePetIn.worldObj;
|
||||
this.followSpeed = followSpeedIn;
|
||||
this.petPathfinder = thePetIn.getNavigator();
|
||||
this.minDist = minDistIn;
|
||||
this.maxDist = maxDistIn;
|
||||
this.setMutexBits(3);
|
||||
|
||||
if (!(thePetIn.getNavigator() instanceof PathNavigateGround))
|
||||
{
|
||||
throw new IllegalArgumentException("Unsupported mob type for FollowOwnerGoal");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the EntityAIBase should begin execution.
|
||||
*/
|
||||
public boolean shouldExecute()
|
||||
{
|
||||
EntityLiving entitylivingbase = this.thePet.getOwner();
|
||||
|
||||
if (entitylivingbase == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// else if (entitylivingbase.isPlayer() && ((EntityNPC)entitylivingbase).isSpectator())
|
||||
// {
|
||||
// return false;
|
||||
// }
|
||||
else if (this.thePet.isSitting())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if (this.thePet.getDistanceSqToEntity(entitylivingbase) < (double)(this.minDist * this.minDist))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.theOwner = entitylivingbase;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether an in-progress EntityAIBase should continue executing
|
||||
*/
|
||||
public boolean continueExecuting()
|
||||
{
|
||||
return !this.petPathfinder.noPath() && this.thePet.getDistanceSqToEntity(this.theOwner) > (double)(this.maxDist * this.maxDist) && !this.thePet.isSitting();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a one shot task or start executing a continuous task
|
||||
*/
|
||||
public void startExecuting()
|
||||
{
|
||||
this.field_75343_h = 0;
|
||||
this.field_75344_i = ((PathNavigateGround)this.thePet.getNavigator()).getAvoidsWater();
|
||||
((PathNavigateGround)this.thePet.getNavigator()).setAvoidsWater(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the task
|
||||
*/
|
||||
public void resetTask()
|
||||
{
|
||||
this.theOwner = null;
|
||||
this.petPathfinder.clearPathEntity();
|
||||
((PathNavigateGround)this.thePet.getNavigator()).setAvoidsWater(true);
|
||||
}
|
||||
|
||||
private boolean func_181065_a(BlockPos p_181065_1_)
|
||||
{
|
||||
State iblockstate = this.theWorld.getState(p_181065_1_);
|
||||
Block block = iblockstate.getBlock();
|
||||
return block == Blocks.air ? true : !block.isFullCube();
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the task
|
||||
*/
|
||||
public void updateTask()
|
||||
{
|
||||
this.thePet.getLookHelper().setLookPositionWithEntity(this.theOwner, 10.0F, (float)this.thePet.getVerticalFaceSpeed());
|
||||
|
||||
if (!this.thePet.isSitting())
|
||||
{
|
||||
if (--this.field_75343_h <= 0)
|
||||
{
|
||||
this.field_75343_h = 10;
|
||||
|
||||
if (!this.petPathfinder.tryMoveToEntityLiving(this.theOwner, this.followSpeed))
|
||||
{
|
||||
this.petPathfinder.clearPathEntity();
|
||||
// if (!this.thePet.getLeashed())
|
||||
// {
|
||||
// if (this.thePet.getDistanceSqToEntity(this.theOwner) >= 144.0D)
|
||||
// {
|
||||
// int i = ExtMath.floord(this.theOwner.posX) - 2;
|
||||
// int j = ExtMath.floord(this.theOwner.posZ) - 2;
|
||||
// int k = ExtMath.floord(this.theOwner.getEntityBoundingBox().minY);
|
||||
//
|
||||
// for (int l = 0; l <= 4; ++l)
|
||||
// {
|
||||
// for (int i1 = 0; i1 <= 4; ++i1)
|
||||
// {
|
||||
// if ((l < 1 || i1 < 1 || l > 3 || i1 > 3) && this.theWorld.isBlockSolid(new BlockPos(i + l, k - 1, j + i1)) && this.func_181065_a(new BlockPos(i + l, k, j + i1)) && this.func_181065_a(new BlockPos(i + l, k + 1, j + i1)))
|
||||
// {
|
||||
// this.thePet.setLocationAndAngles((double)((float)(i + l) + 0.5F), (double)k, (double)((float)(j + i1) + 0.5F), this.thePet.rotYaw, this.thePet.rotPitch);
|
||||
// this.petPathfinder.clearPathEntity();
|
||||
// return;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
112
java/src/game/ai/EntityAIFollowParent.java
Executable file
112
java/src/game/ai/EntityAIFollowParent.java
Executable file
|
@ -0,0 +1,112 @@
|
|||
package game.ai;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import game.entity.types.EntityAnimal;
|
||||
|
||||
public class EntityAIFollowParent extends EntityAIBase
|
||||
{
|
||||
private EntityAnimal childAnimal;
|
||||
private EntityAnimal parentAnimal;
|
||||
private double speed;
|
||||
private int delay;
|
||||
|
||||
public EntityAIFollowParent(EntityAnimal animal, double speed)
|
||||
{
|
||||
this.childAnimal = animal;
|
||||
this.speed = speed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the EntityAIBase should begin execution.
|
||||
*/
|
||||
public boolean shouldExecute()
|
||||
{
|
||||
if (!this.childAnimal.isChild())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
List<EntityAnimal> list = this.childAnimal.worldObj.<EntityAnimal>getEntitiesWithinAABB(this.childAnimal.getClass(), this.childAnimal.getEntityBoundingBox().expand(8.0D, 4.0D, 8.0D));
|
||||
EntityAnimal entityanimal = null;
|
||||
double d0 = Double.MAX_VALUE;
|
||||
|
||||
for (EntityAnimal entityanimal1 : list)
|
||||
{
|
||||
if (!entityanimal1.isChild())
|
||||
{
|
||||
double d1 = this.childAnimal.getDistanceSqToEntity(entityanimal1);
|
||||
|
||||
if (d1 <= d0)
|
||||
{
|
||||
d0 = d1;
|
||||
entityanimal = entityanimal1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (entityanimal == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if (d0 < 9.0D)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.parentAnimal = entityanimal;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether an in-progress EntityAIBase should continue executing
|
||||
*/
|
||||
public boolean continueExecuting()
|
||||
{
|
||||
if (!this.childAnimal.isChild())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if (!this.parentAnimal.isEntityAlive())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
double d0 = this.childAnimal.getDistanceSqToEntity(this.parentAnimal);
|
||||
return d0 >= 9.0D && d0 <= 256.0D;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a one shot task or start executing a continuous task
|
||||
*/
|
||||
public void startExecuting()
|
||||
{
|
||||
this.delay = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the task
|
||||
*/
|
||||
public void resetTask()
|
||||
{
|
||||
this.parentAnimal = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the task
|
||||
*/
|
||||
public void updateTask()
|
||||
{
|
||||
if (--this.delay <= 0)
|
||||
{
|
||||
this.delay = 10;
|
||||
this.childAnimal.getNavigator().tryMoveToEntityLiving(this.parentAnimal, this.speed);
|
||||
}
|
||||
}
|
||||
}
|
159
java/src/game/ai/EntityAIHarvestFarmland.java
Executable file
159
java/src/game/ai/EntityAIHarvestFarmland.java
Executable file
|
@ -0,0 +1,159 @@
|
|||
package game.ai;
|
||||
|
||||
import game.entity.types.EntityLiving;
|
||||
import game.world.BlockPos;
|
||||
import game.world.World;
|
||||
|
||||
public class EntityAIHarvestFarmland extends EntityAIMoveToBlock
|
||||
{
|
||||
// /** Villager that is harvesting */
|
||||
// private final EntityVillager theVillager;
|
||||
// private boolean hasFarmItem;
|
||||
// private boolean field_179503_e;
|
||||
// private int field_179501_f;
|
||||
//
|
||||
public EntityAIHarvestFarmland(EntityLiving entity, double speedIn)
|
||||
{
|
||||
super(entity, speedIn, 16);
|
||||
// this.theVillager = theVillagerIn;
|
||||
}
|
||||
//
|
||||
// /**
|
||||
// * Returns whether the EntityAIBase should begin execution.
|
||||
// */
|
||||
// public boolean shouldExecute()
|
||||
// {
|
||||
// if (this.runDelay <= 0)
|
||||
// {
|
||||
// if (!Config.mobGriefing || this.theVillager.isChild())
|
||||
// {
|
||||
// return false;
|
||||
// }
|
||||
//
|
||||
// this.field_179501_f = -1;
|
||||
// this.hasFarmItem = this.theVillager.hasFarmItem();
|
||||
// this.field_179503_e = this.theVillager.needsMoreItems();
|
||||
// }
|
||||
//
|
||||
// return super.shouldExecute();
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * Returns whether an in-progress EntityAIBase should continue executing
|
||||
// */
|
||||
// public boolean continueExecuting()
|
||||
// {
|
||||
// return this.field_179501_f >= 0 && super.continueExecuting();
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * Execute a one shot task or start executing a continuous task
|
||||
// */
|
||||
// public void startExecuting()
|
||||
// {
|
||||
// super.startExecuting();
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * Resets the task
|
||||
// */
|
||||
// public void resetTask()
|
||||
// {
|
||||
// super.resetTask();
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * Updates the task
|
||||
// */
|
||||
// public void updateTask()
|
||||
// {
|
||||
// super.updateTask();
|
||||
// this.theVillager.getLookHelper().setLookPosition((double)this.destinationBlock.getX() + 0.5D, (double)(this.destinationBlock.getY() + 1), (double)this.destinationBlock.getZ() + 0.5D, 10.0F, (float)this.theVillager.getVerticalFaceSpeed());
|
||||
//
|
||||
// if (this.getIsAboveDestination())
|
||||
// {
|
||||
// World world = this.theVillager.worldObj;
|
||||
// BlockPos blockpos = this.destinationBlock.up();
|
||||
// IBlockState iblockstate = world.getBlockState(blockpos);
|
||||
// Block block = iblockstate.getBlock();
|
||||
//
|
||||
// if (this.field_179501_f == 0 && block instanceof BlockCrops && ((Integer)iblockstate.getValue(BlockCrops.AGE)).intValue() == 7)
|
||||
// {
|
||||
// world.destroyBlock(blockpos, true);
|
||||
// }
|
||||
// else if (this.field_179501_f == 1 && block == Blocks.air)
|
||||
// {
|
||||
// InventoryBasic inventorybasic = this.theVillager.getFarmInventory();
|
||||
//
|
||||
// for (int i = 0; i < inventorybasic.getSizeInventory(); ++i)
|
||||
// {
|
||||
// ItemStack itemstack = inventorybasic.getStackInSlot(i);
|
||||
// boolean flag = false;
|
||||
//
|
||||
// if (itemstack != null)
|
||||
// {
|
||||
// if (itemstack.getItem() == Items.wheat_seeds)
|
||||
// {
|
||||
// world.setBlockState(blockpos, Blocks.wheat.getDefaultState(), 3);
|
||||
// flag = true;
|
||||
// }
|
||||
// else if (itemstack.getItem() == Items.potato)
|
||||
// {
|
||||
// world.setBlockState(blockpos, Blocks.potatoes.getDefaultState(), 3);
|
||||
// flag = true;
|
||||
// }
|
||||
// else if (itemstack.getItem() == Items.carrot)
|
||||
// {
|
||||
// world.setBlockState(blockpos, Blocks.carrots.getDefaultState(), 3);
|
||||
// flag = true;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// if (flag)
|
||||
// {
|
||||
// --itemstack.stackSize;
|
||||
//
|
||||
// if (itemstack.stackSize <= 0)
|
||||
// {
|
||||
// inventorybasic.setInventorySlotContents(i, (ItemStack)null);
|
||||
// }
|
||||
//
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// this.field_179501_f = -1;
|
||||
// this.runDelay = 10;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * Return true to set given position as destination
|
||||
// */
|
||||
protected boolean shouldMoveTo(World worldIn, BlockPos pos)
|
||||
{
|
||||
// Block block = worldIn.getBlockState(pos).getBlock();
|
||||
//
|
||||
// if (block == Blocks.farmland)
|
||||
// {
|
||||
// pos = pos.up();
|
||||
// IBlockState iblockstate = worldIn.getBlockState(pos);
|
||||
// block = iblockstate.getBlock();
|
||||
//
|
||||
// if (block instanceof BlockCrops && ((Integer)iblockstate.getValue(BlockCrops.AGE)).intValue() == 7 && this.field_179503_e && (this.field_179501_f == 0 || this.field_179501_f < 0))
|
||||
// {
|
||||
// this.field_179501_f = 0;
|
||||
// return true;
|
||||
// }
|
||||
//
|
||||
// if (block == Blocks.air && this.hasFarmItem && (this.field_179501_f == 1 || this.field_179501_f < 0))
|
||||
// {
|
||||
// this.field_179501_f = 1;
|
||||
// return true;
|
||||
// }
|
||||
// }
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
73
java/src/game/ai/EntityAIHurtByTarget.java
Executable file
73
java/src/game/ai/EntityAIHurtByTarget.java
Executable file
|
@ -0,0 +1,73 @@
|
|||
package game.ai;
|
||||
|
||||
import game.entity.types.EntityLiving;
|
||||
import game.world.BoundingBox;
|
||||
|
||||
public class EntityAIHurtByTarget extends EntityAITarget
|
||||
{
|
||||
private boolean entityCallsForHelp;
|
||||
|
||||
/** Store the previous revengeTimer value */
|
||||
private int revengeTimerOld;
|
||||
private final Class[] targetClasses;
|
||||
|
||||
public EntityAIHurtByTarget(EntityLiving creatureIn, boolean entityCallsForHelpIn, Class... targetClassesIn)
|
||||
{
|
||||
super(creatureIn, false);
|
||||
this.entityCallsForHelp = entityCallsForHelpIn;
|
||||
this.targetClasses = targetClassesIn;
|
||||
this.setMutexBits(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the EntityAIBase should begin execution.
|
||||
*/
|
||||
public boolean shouldExecute()
|
||||
{
|
||||
int i = this.taskOwner.getAttackedTime();
|
||||
return i != this.revengeTimerOld && this.isSuitableTarget(this.taskOwner.getAttackedBy());
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a one shot task or start executing a continuous task
|
||||
*/
|
||||
public void startExecuting()
|
||||
{
|
||||
this.taskOwner.setAttackTarget(this.taskOwner.getAttackedBy());
|
||||
this.revengeTimerOld = this.taskOwner.getAttackedTime();
|
||||
|
||||
if (this.entityCallsForHelp)
|
||||
{
|
||||
double d0 = this.getTargetDistance();
|
||||
|
||||
for (EntityLiving entitycreature : this.taskOwner.worldObj.getEntitiesWithinAABB(this.taskOwner.getClass(), (new BoundingBox(this.taskOwner.posX, this.taskOwner.posY, this.taskOwner.posZ, this.taskOwner.posX + 1.0D, this.taskOwner.posY + 1.0D, this.taskOwner.posZ + 1.0D)).expand(d0, 10.0D, d0)))
|
||||
{
|
||||
if (this.taskOwner != entitycreature && /* !(entitycreature.isPlayer()) && */ entitycreature.getAttackTarget() == null) // && !entitycreature.isOnSameTeam(this.taskOwner.getAITarget()))
|
||||
{
|
||||
boolean flag = false;
|
||||
|
||||
for (Class oclass : this.targetClasses)
|
||||
{
|
||||
if (entitycreature.getClass() == oclass)
|
||||
{
|
||||
flag = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!flag)
|
||||
{
|
||||
this.setEntityAttackTarget(entitycreature, this.taskOwner.getAttackedBy());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
super.startExecuting();
|
||||
}
|
||||
|
||||
protected void setEntityAttackTarget(EntityLiving creatureIn, EntityLiving entityLivingBaseIn)
|
||||
{
|
||||
creatureIn.setAttackTarget(entityLivingBaseIn);
|
||||
}
|
||||
}
|
62
java/src/game/ai/EntityAILeapAtTarget.java
Executable file
62
java/src/game/ai/EntityAILeapAtTarget.java
Executable file
|
@ -0,0 +1,62 @@
|
|||
package game.ai;
|
||||
|
||||
import game.ExtMath;
|
||||
import game.entity.types.EntityLiving;
|
||||
|
||||
public class EntityAILeapAtTarget extends EntityAIBase
|
||||
{
|
||||
/** The entity that is leaping. */
|
||||
EntityLiving leaper;
|
||||
|
||||
/** The entity that the leaper is leaping towards. */
|
||||
EntityLiving leapTarget;
|
||||
|
||||
/** The entity's motionY after leaping. */
|
||||
float leapMotionY;
|
||||
|
||||
public EntityAILeapAtTarget(EntityLiving leapingEntity, float leapMotionYIn)
|
||||
{
|
||||
this.leaper = leapingEntity;
|
||||
this.leapMotionY = leapMotionYIn;
|
||||
this.setMutexBits(5);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the EntityAIBase should begin execution.
|
||||
*/
|
||||
public boolean shouldExecute()
|
||||
{
|
||||
this.leapTarget = this.leaper.getAttackTarget();
|
||||
|
||||
if (this.leapTarget == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
double d0 = this.leaper.getDistanceSqToEntity(this.leapTarget);
|
||||
return d0 >= 4.0D && d0 <= 16.0D ? (!this.leaper.onGround ? false : this.leaper.getRNG().zrange(5) == 0) : false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether an in-progress EntityAIBase should continue executing
|
||||
*/
|
||||
public boolean continueExecuting()
|
||||
{
|
||||
return !this.leaper.onGround;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a one shot task or start executing a continuous task
|
||||
*/
|
||||
public void startExecuting()
|
||||
{
|
||||
double d0 = this.leapTarget.posX - this.leaper.posX;
|
||||
double d1 = this.leapTarget.posZ - this.leaper.posZ;
|
||||
float f = ExtMath.sqrtd(d0 * d0 + d1 * d1);
|
||||
this.leaper.motionX += d0 / (double)f * 0.5D * 0.800000011920929D + this.leaper.motionX * 0.20000000298023224D;
|
||||
this.leaper.motionZ += d1 / (double)f * 0.5D * 0.800000011920929D + this.leaper.motionZ * 0.20000000298023224D;
|
||||
this.leaper.motionY = (double)this.leapMotionY;
|
||||
}
|
||||
}
|
27
java/src/game/ai/EntityAILookAtTalkingPlayer.java
Executable file
27
java/src/game/ai/EntityAILookAtTalkingPlayer.java
Executable file
|
@ -0,0 +1,27 @@
|
|||
package game.ai;
|
||||
|
||||
import game.entity.npc.EntityNPC;
|
||||
|
||||
public class EntityAILookAtTalkingPlayer extends EntityAIWatchClosest
|
||||
{
|
||||
private final EntityNPC npc;
|
||||
|
||||
public EntityAILookAtTalkingPlayer(EntityNPC npc)
|
||||
{
|
||||
super(npc, null, 8.0F);
|
||||
this.npc = npc;
|
||||
}
|
||||
|
||||
public boolean shouldExecute()
|
||||
{
|
||||
if (this.npc.isTalking() && this.npc.getAttackTarget() == null)
|
||||
{
|
||||
this.closestEntity = this.npc.getTalking();
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
62
java/src/game/ai/EntityAILookIdle.java
Executable file
62
java/src/game/ai/EntityAILookIdle.java
Executable file
|
@ -0,0 +1,62 @@
|
|||
package game.ai;
|
||||
|
||||
import game.entity.types.EntityLiving;
|
||||
|
||||
public class EntityAILookIdle extends EntityAIBase
|
||||
{
|
||||
/** The entity that is looking idle. */
|
||||
private EntityLiving idleEntity;
|
||||
|
||||
/** X offset to look at */
|
||||
private double lookX;
|
||||
|
||||
/** Z offset to look at */
|
||||
private double lookZ;
|
||||
|
||||
/**
|
||||
* A decrementing tick that stops the entity from being idle once it reaches 0.
|
||||
*/
|
||||
private int idleTime;
|
||||
|
||||
public EntityAILookIdle(EntityLiving entitylivingIn)
|
||||
{
|
||||
this.idleEntity = entitylivingIn;
|
||||
this.setMutexBits(3);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the EntityAIBase should begin execution.
|
||||
*/
|
||||
public boolean shouldExecute()
|
||||
{
|
||||
return this.idleEntity.getRNG().floatv() < 0.02F;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether an in-progress EntityAIBase should continue executing
|
||||
*/
|
||||
public boolean continueExecuting()
|
||||
{
|
||||
return this.idleTime >= 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a one shot task or start executing a continuous task
|
||||
*/
|
||||
public void startExecuting()
|
||||
{
|
||||
double d0 = (Math.PI * 2D) * this.idleEntity.getRNG().doublev();
|
||||
this.lookX = Math.cos(d0);
|
||||
this.lookZ = Math.sin(d0);
|
||||
this.idleTime = 20 + this.idleEntity.getRNG().zrange(20);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the task
|
||||
*/
|
||||
public void updateTask()
|
||||
{
|
||||
--this.idleTime;
|
||||
this.idleEntity.getLookHelper().setLookPosition(this.idleEntity.posX + this.lookX, this.idleEntity.posY + (double)this.idleEntity.getEyeHeight(), this.idleEntity.posZ + this.lookZ, 10.0F, (float)this.idleEntity.getVerticalFaceSpeed());
|
||||
}
|
||||
}
|
167
java/src/game/ai/EntityAIMate.java
Executable file
167
java/src/game/ai/EntityAIMate.java
Executable file
|
@ -0,0 +1,167 @@
|
|||
package game.ai;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import game.entity.item.EntityXp;
|
||||
import game.entity.npc.EntityNPC;
|
||||
import game.entity.types.EntityAnimal;
|
||||
import game.entity.types.EntityLiving;
|
||||
import game.init.Config;
|
||||
import game.renderer.particle.ParticleType;
|
||||
import game.rng.Random;
|
||||
import game.world.World;
|
||||
|
||||
public class EntityAIMate extends EntityAIBase
|
||||
{
|
||||
private EntityAnimal theAnimal;
|
||||
World theWorld;
|
||||
private EntityAnimal targetMate;
|
||||
|
||||
/**
|
||||
* Delay preventing a baby from spawning immediately when two mate-able animals find each other.
|
||||
*/
|
||||
int spawnBabyDelay;
|
||||
|
||||
/** The speed the creature moves at during mating behavior. */
|
||||
double moveSpeed;
|
||||
|
||||
public EntityAIMate(EntityAnimal animal, double speedIn)
|
||||
{
|
||||
this.theAnimal = animal;
|
||||
this.theWorld = animal.worldObj;
|
||||
this.moveSpeed = speedIn;
|
||||
this.setMutexBits(3);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the EntityAIBase should begin execution.
|
||||
*/
|
||||
public boolean shouldExecute()
|
||||
{
|
||||
if (!this.theAnimal.isInLove())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.targetMate = this.getNearbyMate();
|
||||
return this.targetMate != null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether an in-progress EntityAIBase should continue executing
|
||||
*/
|
||||
public boolean continueExecuting()
|
||||
{
|
||||
return this.targetMate.isEntityAlive() && this.targetMate.isInLove() && this.spawnBabyDelay < 60;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the task
|
||||
*/
|
||||
public void resetTask()
|
||||
{
|
||||
this.targetMate = null;
|
||||
this.spawnBabyDelay = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the task
|
||||
*/
|
||||
public void updateTask()
|
||||
{
|
||||
this.theAnimal.getLookHelper().setLookPositionWithEntity(this.targetMate, 10.0F, (float)this.theAnimal.getVerticalFaceSpeed());
|
||||
this.theAnimal.getNavigator().tryMoveToEntityLiving(this.targetMate, this.moveSpeed);
|
||||
++this.spawnBabyDelay;
|
||||
|
||||
if (this.spawnBabyDelay >= 60 && this.theAnimal.getDistanceSqToEntity(this.targetMate) < 9.0D)
|
||||
{
|
||||
this.spawnBaby();
|
||||
}
|
||||
}
|
||||
|
||||
protected int getGrowingAge() {
|
||||
return 24000;
|
||||
}
|
||||
|
||||
protected int getMatingCooldown() {
|
||||
return 6000;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loops through nearby animals and finds another animal of the same type that can be mated with. Returns the first
|
||||
* valid mate found.
|
||||
*/
|
||||
private EntityAnimal getNearbyMate()
|
||||
{
|
||||
float f = 8.0F;
|
||||
List<EntityAnimal> list = this.theWorld.<EntityAnimal>getEntitiesWithinAABB(this.theAnimal.getClass(), this.theAnimal.getEntityBoundingBox().expand((double)f, (double)f, (double)f));
|
||||
double d0 = Double.MAX_VALUE;
|
||||
EntityAnimal entityanimal = null;
|
||||
|
||||
for (EntityAnimal entityanimal1 : list)
|
||||
{
|
||||
if (this.theAnimal.canMateWith(entityanimal1) && this.theAnimal.getDistanceSqToEntity(entityanimal1) < d0)
|
||||
{
|
||||
entityanimal = entityanimal1;
|
||||
d0 = this.theAnimal.getDistanceSqToEntity(entityanimal1);
|
||||
}
|
||||
}
|
||||
|
||||
return entityanimal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Spawns a baby animal of the same type.
|
||||
*/
|
||||
private void spawnBaby()
|
||||
{
|
||||
EntityLiving entityageable = this.theAnimal.createChild(this.targetMate);
|
||||
|
||||
if (entityageable != null)
|
||||
{
|
||||
EntityNPC entityplayer = this.theAnimal.getPlayerInLove();
|
||||
|
||||
if (entityplayer == null && this.targetMate.getPlayerInLove() != null)
|
||||
{
|
||||
entityplayer = this.targetMate.getPlayerInLove();
|
||||
}
|
||||
|
||||
// if (entityplayer != null)
|
||||
// {
|
||||
// entityplayer.triggerAchievement(StatRegistry.animalsBredStat);
|
||||
//
|
||||
//// if (this.theAnimal instanceof EntityCow)
|
||||
//// {
|
||||
//// entityplayer.triggerAchievement(AchievementList.breedCow);
|
||||
//// }
|
||||
// }
|
||||
|
||||
this.theAnimal.setGrowingAge(this.getMatingCooldown());
|
||||
this.targetMate.setGrowingAge(this.getMatingCooldown());
|
||||
this.theAnimal.resetInLove();
|
||||
this.targetMate.resetInLove();
|
||||
entityageable.setGrowingAge(-this.getGrowingAge());
|
||||
entityageable.setLocationAndAngles(this.theAnimal.posX, this.theAnimal.posY, this.theAnimal.posZ, 0.0F, 0.0F);
|
||||
this.theWorld.spawnEntityInWorld(entityageable);
|
||||
Random random = this.theAnimal.getRNG();
|
||||
|
||||
for (int i = 0; i < 7; ++i)
|
||||
{
|
||||
double d0 = random.gaussian() * 0.02D;
|
||||
double d1 = random.gaussian() * 0.02D;
|
||||
double d2 = random.gaussian() * 0.02D;
|
||||
double d3 = random.doublev() * (double)this.theAnimal.width * 2.0D - (double)this.theAnimal.width;
|
||||
double d4 = 0.5D + random.doublev() * (double)this.theAnimal.height;
|
||||
double d5 = random.doublev() * (double)this.theAnimal.width * 2.0D - (double)this.theAnimal.width;
|
||||
this.theWorld.spawnParticle(ParticleType.HEART, this.theAnimal.posX + d3, this.theAnimal.posY + d4, this.theAnimal.posZ + d5, d0, d1, d2);
|
||||
}
|
||||
|
||||
if (entityplayer != null && Config.breedingXP) // FIX xp
|
||||
{
|
||||
this.theWorld.spawnEntityInWorld(new EntityXp(this.theWorld, this.theAnimal.posX, this.theAnimal.posY, this.theAnimal.posZ, random.zrange(7) + 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
104
java/src/game/ai/EntityAIMoveIndoors.java
Executable file
104
java/src/game/ai/EntityAIMoveIndoors.java
Executable file
|
@ -0,0 +1,104 @@
|
|||
package game.ai;
|
||||
|
||||
import game.entity.types.EntityLiving;
|
||||
import game.village.Village;
|
||||
import game.village.VillageDoorInfo;
|
||||
import game.world.BlockPos;
|
||||
import game.world.Vec3;
|
||||
import game.world.WorldServer;
|
||||
|
||||
public class EntityAIMoveIndoors extends EntityAIBase
|
||||
{
|
||||
private EntityLiving entityObj;
|
||||
private VillageDoorInfo doorInfo;
|
||||
private int insidePosX = -1;
|
||||
private int insidePosZ = -1;
|
||||
|
||||
public EntityAIMoveIndoors(EntityLiving entityObjIn)
|
||||
{
|
||||
this.entityObj = entityObjIn;
|
||||
this.setMutexBits(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the EntityAIBase should begin execution.
|
||||
*/
|
||||
public boolean shouldExecute()
|
||||
{
|
||||
BlockPos blockpos = new BlockPos(this.entityObj);
|
||||
|
||||
if ((!((WorldServer)this.entityObj.worldObj).isDaytime() /* || this.entityObj.worldObj.isRaining() && !this.entityObj.worldObj.getBiomeGenForCoords(blockpos).canRain() */) && !this.entityObj.worldObj.dimension.hasNoLight())
|
||||
{
|
||||
if (this.entityObj.getRNG().zrange(50) != 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if (this.insidePosX != -1 && this.entityObj.getDistanceSq((double)this.insidePosX, this.entityObj.posY, (double)this.insidePosZ) < 4.0D)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
Village village = ((WorldServer)this.entityObj.worldObj).getNearestVillage(blockpos, 14);
|
||||
|
||||
if (village == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.doorInfo = village.getDoorInfo(blockpos);
|
||||
return this.doorInfo != null;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether an in-progress EntityAIBase should continue executing
|
||||
*/
|
||||
public boolean continueExecuting()
|
||||
{
|
||||
return !this.entityObj.getNavigator().noPath();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a one shot task or start executing a continuous task
|
||||
*/
|
||||
public void startExecuting()
|
||||
{
|
||||
this.insidePosX = -1;
|
||||
BlockPos blockpos = this.doorInfo.getInsideBlockPos();
|
||||
int i = blockpos.getX();
|
||||
int j = blockpos.getY();
|
||||
int k = blockpos.getZ();
|
||||
|
||||
if (this.entityObj.getDistanceSq(blockpos) > 256.0D)
|
||||
{
|
||||
Vec3 vec3 = RandomPositionGenerator.findRandomTargetBlockTowards(this.entityObj, 14, 3, new Vec3((double)i + 0.5D, (double)j, (double)k + 0.5D));
|
||||
|
||||
if (vec3 != null)
|
||||
{
|
||||
this.entityObj.getNavigator().tryMoveToXYZ(vec3.xCoord, vec3.yCoord, vec3.zCoord, 1.0D);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
this.entityObj.getNavigator().tryMoveToXYZ((double)i + 0.5D, (double)j, (double)k + 0.5D, 1.0D);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the task
|
||||
*/
|
||||
public void resetTask()
|
||||
{
|
||||
this.insidePosX = this.doorInfo.getInsideBlockPos().getX();
|
||||
this.insidePosZ = this.doorInfo.getInsideBlockPos().getZ();
|
||||
this.doorInfo = null;
|
||||
}
|
||||
}
|
174
java/src/game/ai/EntityAIMoveThroughVillage.java
Executable file
174
java/src/game/ai/EntityAIMoveThroughVillage.java
Executable file
|
@ -0,0 +1,174 @@
|
|||
package game.ai;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import game.ExtMath;
|
||||
import game.collect.Lists;
|
||||
import game.entity.types.EntityLiving;
|
||||
import game.pathfinding.PathEntity;
|
||||
import game.pathfinding.PathNavigateGround;
|
||||
import game.village.Village;
|
||||
import game.village.VillageDoorInfo;
|
||||
import game.world.BlockPos;
|
||||
import game.world.Vec3;
|
||||
import game.world.WorldServer;
|
||||
|
||||
public class EntityAIMoveThroughVillage extends EntityAIBase
|
||||
{
|
||||
private EntityLiving theEntity;
|
||||
private double movementSpeed;
|
||||
|
||||
/** The PathNavigate of our entity. */
|
||||
private PathEntity entityPathNavigate;
|
||||
private VillageDoorInfo doorInfo;
|
||||
private boolean isNocturnal;
|
||||
private List<VillageDoorInfo> doorList = Lists.<VillageDoorInfo>newArrayList();
|
||||
|
||||
public EntityAIMoveThroughVillage(EntityLiving theEntityIn, double movementSpeedIn, boolean isNocturnalIn)
|
||||
{
|
||||
this.theEntity = theEntityIn;
|
||||
this.movementSpeed = movementSpeedIn;
|
||||
this.isNocturnal = isNocturnalIn;
|
||||
this.setMutexBits(1);
|
||||
|
||||
if (!(theEntityIn.getNavigator() instanceof PathNavigateGround))
|
||||
{
|
||||
throw new IllegalArgumentException("Unsupported mob for MoveThroughVillageGoal");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the EntityAIBase should begin execution.
|
||||
*/
|
||||
public boolean shouldExecute()
|
||||
{
|
||||
this.resizeDoorList();
|
||||
|
||||
if (this.isNocturnal && ((WorldServer)this.theEntity.worldObj).isDaytime())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
Village village = ((WorldServer)this.theEntity.worldObj).getNearestVillage(new BlockPos(this.theEntity), 0);
|
||||
|
||||
if (village == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.doorInfo = this.findNearestDoor(village);
|
||||
|
||||
if (this.doorInfo == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
PathNavigateGround pathnavigateground = (PathNavigateGround)this.theEntity.getNavigator();
|
||||
boolean flag = pathnavigateground.getEnterDoors();
|
||||
pathnavigateground.setBreakDoors(false);
|
||||
this.entityPathNavigate = pathnavigateground.getPathToPos(this.doorInfo.getDoorBlockPos());
|
||||
pathnavigateground.setBreakDoors(flag);
|
||||
|
||||
if (this.entityPathNavigate != null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
Vec3 vec3 = RandomPositionGenerator.findRandomTargetBlockTowards(this.theEntity, 10, 7, new Vec3((double)this.doorInfo.getDoorBlockPos().getX(), (double)this.doorInfo.getDoorBlockPos().getY(), (double)this.doorInfo.getDoorBlockPos().getZ()));
|
||||
|
||||
if (vec3 == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
pathnavigateground.setBreakDoors(false);
|
||||
this.entityPathNavigate = this.theEntity.getNavigator().getPathToXYZ(vec3.xCoord, vec3.yCoord, vec3.zCoord);
|
||||
pathnavigateground.setBreakDoors(flag);
|
||||
return this.entityPathNavigate != null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether an in-progress EntityAIBase should continue executing
|
||||
*/
|
||||
public boolean continueExecuting()
|
||||
{
|
||||
if (this.theEntity.getNavigator().noPath())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
float f = this.theEntity.width + 4.0F;
|
||||
return this.theEntity.getDistanceSq(this.doorInfo.getDoorBlockPos()) > (double)(f * f);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a one shot task or start executing a continuous task
|
||||
*/
|
||||
public void startExecuting()
|
||||
{
|
||||
this.theEntity.getNavigator().setPath(this.entityPathNavigate, this.movementSpeed);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the task
|
||||
*/
|
||||
public void resetTask()
|
||||
{
|
||||
if (this.theEntity.getNavigator().noPath() || this.theEntity.getDistanceSq(this.doorInfo.getDoorBlockPos()) < 16.0D)
|
||||
{
|
||||
this.doorList.add(this.doorInfo);
|
||||
}
|
||||
}
|
||||
|
||||
private VillageDoorInfo findNearestDoor(Village villageIn)
|
||||
{
|
||||
VillageDoorInfo villagedoorinfo = null;
|
||||
int i = Integer.MAX_VALUE;
|
||||
|
||||
for (VillageDoorInfo villagedoorinfo1 : villageIn.getDoorList())
|
||||
{
|
||||
int j = villagedoorinfo1.getDistanceSquared(ExtMath.floord(this.theEntity.posX), ExtMath.floord(this.theEntity.posY), ExtMath.floord(this.theEntity.posZ));
|
||||
|
||||
if (j < i && !this.doesDoorListContain(villagedoorinfo1))
|
||||
{
|
||||
villagedoorinfo = villagedoorinfo1;
|
||||
i = j;
|
||||
}
|
||||
}
|
||||
|
||||
return villagedoorinfo;
|
||||
}
|
||||
|
||||
private boolean doesDoorListContain(VillageDoorInfo doorInfoIn)
|
||||
{
|
||||
for (VillageDoorInfo villagedoorinfo : this.doorList)
|
||||
{
|
||||
if (doorInfoIn.getDoorBlockPos().equals(villagedoorinfo.getDoorBlockPos()))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private void resizeDoorList()
|
||||
{
|
||||
if (this.doorList.size() > 15)
|
||||
{
|
||||
this.doorList.remove(0);
|
||||
}
|
||||
}
|
||||
}
|
137
java/src/game/ai/EntityAIMoveToBlock.java
Executable file
137
java/src/game/ai/EntityAIMoveToBlock.java
Executable file
|
@ -0,0 +1,137 @@
|
|||
package game.ai;
|
||||
|
||||
import game.entity.types.EntityLiving;
|
||||
import game.world.BlockPos;
|
||||
import game.world.World;
|
||||
|
||||
public abstract class EntityAIMoveToBlock extends EntityAIBase
|
||||
{
|
||||
private final EntityLiving theEntity;
|
||||
private final double movementSpeed;
|
||||
|
||||
/** Controls task execution delay */
|
||||
protected int runDelay;
|
||||
private int timeoutCounter;
|
||||
private int field_179490_f;
|
||||
|
||||
/** Block to move to */
|
||||
protected BlockPos destinationBlock = BlockPos.ORIGIN;
|
||||
private boolean isAboveDestination;
|
||||
private int searchLength;
|
||||
|
||||
public EntityAIMoveToBlock(EntityLiving creature, double speedIn, int length)
|
||||
{
|
||||
this.theEntity = creature;
|
||||
this.movementSpeed = speedIn;
|
||||
this.searchLength = length;
|
||||
this.setMutexBits(5);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the EntityAIBase should begin execution.
|
||||
*/
|
||||
public boolean shouldExecute()
|
||||
{
|
||||
if (this.runDelay > 0)
|
||||
{
|
||||
--this.runDelay;
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.runDelay = 200 + this.theEntity.getRNG().zrange(200);
|
||||
return this.searchForDestination();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether an in-progress EntityAIBase should continue executing
|
||||
*/
|
||||
public boolean continueExecuting()
|
||||
{
|
||||
return this.timeoutCounter >= -this.field_179490_f && this.timeoutCounter <= 1200 && this.shouldMoveTo(this.theEntity.worldObj, this.destinationBlock);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a one shot task or start executing a continuous task
|
||||
*/
|
||||
public void startExecuting()
|
||||
{
|
||||
this.theEntity.getNavigator().tryMoveToXYZ((double)((float)this.destinationBlock.getX()) + 0.5D, (double)(this.destinationBlock.getY() + 1), (double)((float)this.destinationBlock.getZ()) + 0.5D, this.movementSpeed);
|
||||
this.timeoutCounter = 0;
|
||||
this.field_179490_f = this.theEntity.getRNG().zrange(this.theEntity.getRNG().zrange(1200) + 1200) + 1200;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the task
|
||||
*/
|
||||
public void resetTask()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the task
|
||||
*/
|
||||
public void updateTask()
|
||||
{
|
||||
if (this.theEntity.getDistanceSqToCenter(this.destinationBlock.up()) > 1.0D)
|
||||
{
|
||||
this.isAboveDestination = false;
|
||||
++this.timeoutCounter;
|
||||
|
||||
if (this.timeoutCounter % 40 == 0)
|
||||
{
|
||||
this.theEntity.getNavigator().tryMoveToXYZ((double)((float)this.destinationBlock.getX()) + 0.5D, (double)(this.destinationBlock.getY() + 1), (double)((float)this.destinationBlock.getZ()) + 0.5D, this.movementSpeed);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
this.isAboveDestination = true;
|
||||
--this.timeoutCounter;
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean getIsAboveDestination()
|
||||
{
|
||||
return this.isAboveDestination;
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches and sets new destination block and returns true if a suitable block (specified in {@link
|
||||
* game.ai.EntityAIMoveToBlock#shouldMoveTo(World, BlockPos) EntityAIMoveToBlock#shouldMoveTo(World,
|
||||
* BlockPos)}) can be found.
|
||||
*/
|
||||
protected boolean searchForDestination()
|
||||
{
|
||||
int i = this.searchLength;
|
||||
int j = 1;
|
||||
BlockPos blockpos = new BlockPos(this.theEntity);
|
||||
|
||||
for (int k = 0; k <= 1; k = k > 0 ? -k : 1 - k)
|
||||
{
|
||||
for (int l = 0; l < i; ++l)
|
||||
{
|
||||
for (int i1 = 0; i1 <= l; i1 = i1 > 0 ? -i1 : 1 - i1)
|
||||
{
|
||||
for (int j1 = i1 < l && i1 > -l ? l : 0; j1 <= l; j1 = j1 > 0 ? -j1 : 1 - j1)
|
||||
{
|
||||
BlockPos blockpos1 = blockpos.add(i1, k - 1, j1);
|
||||
|
||||
if (this.theEntity.isWithinHomeDistanceFromPosition(blockpos1) && this.shouldMoveTo(this.theEntity.worldObj, blockpos1))
|
||||
{
|
||||
this.destinationBlock = blockpos1;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true to set given position as destination
|
||||
*/
|
||||
protected abstract boolean shouldMoveTo(World worldIn, BlockPos pos);
|
||||
}
|
65
java/src/game/ai/EntityAIMoveTowardsRestriction.java
Executable file
65
java/src/game/ai/EntityAIMoveTowardsRestriction.java
Executable file
|
@ -0,0 +1,65 @@
|
|||
package game.ai;
|
||||
|
||||
import game.entity.types.EntityLiving;
|
||||
import game.world.BlockPos;
|
||||
import game.world.Vec3;
|
||||
|
||||
public class EntityAIMoveTowardsRestriction extends EntityAIBase
|
||||
{
|
||||
private EntityLiving theEntity;
|
||||
private double movePosX;
|
||||
private double movePosY;
|
||||
private double movePosZ;
|
||||
private double movementSpeed;
|
||||
|
||||
public EntityAIMoveTowardsRestriction(EntityLiving creatureIn, double speedIn)
|
||||
{
|
||||
this.theEntity = creatureIn;
|
||||
this.movementSpeed = speedIn;
|
||||
this.setMutexBits(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the EntityAIBase should begin execution.
|
||||
*/
|
||||
public boolean shouldExecute()
|
||||
{
|
||||
if (this.theEntity.isWithinHomeDistanceCurrentPosition())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
BlockPos blockpos = this.theEntity.getHomePosition();
|
||||
Vec3 vec3 = RandomPositionGenerator.findRandomTargetBlockTowards(this.theEntity, 16, 7, new Vec3((double)blockpos.getX(), (double)blockpos.getY(), (double)blockpos.getZ()));
|
||||
|
||||
if (vec3 == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.movePosX = vec3.xCoord;
|
||||
this.movePosY = vec3.yCoord;
|
||||
this.movePosZ = vec3.zCoord;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether an in-progress EntityAIBase should continue executing
|
||||
*/
|
||||
public boolean continueExecuting()
|
||||
{
|
||||
return !this.theEntity.getNavigator().noPath();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a one shot task or start executing a continuous task
|
||||
*/
|
||||
public void startExecuting()
|
||||
{
|
||||
this.theEntity.getNavigator().tryMoveToXYZ(this.movePosX, this.movePosY, this.movePosZ, this.movementSpeed);
|
||||
}
|
||||
}
|
84
java/src/game/ai/EntityAIMoveTowardsTarget.java
Executable file
84
java/src/game/ai/EntityAIMoveTowardsTarget.java
Executable file
|
@ -0,0 +1,84 @@
|
|||
package game.ai;
|
||||
|
||||
import game.entity.types.EntityLiving;
|
||||
import game.world.Vec3;
|
||||
|
||||
public class EntityAIMoveTowardsTarget extends EntityAIBase
|
||||
{
|
||||
private EntityLiving theEntity;
|
||||
private EntityLiving targetEntity;
|
||||
private double movePosX;
|
||||
private double movePosY;
|
||||
private double movePosZ;
|
||||
private double speed;
|
||||
|
||||
/**
|
||||
* If the distance to the target entity is further than this, this AI task will not run.
|
||||
*/
|
||||
private float maxTargetDistance;
|
||||
|
||||
public EntityAIMoveTowardsTarget(EntityLiving creature, double speedIn, float targetMaxDistance)
|
||||
{
|
||||
this.theEntity = creature;
|
||||
this.speed = speedIn;
|
||||
this.maxTargetDistance = targetMaxDistance;
|
||||
this.setMutexBits(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the EntityAIBase should begin execution.
|
||||
*/
|
||||
public boolean shouldExecute()
|
||||
{
|
||||
this.targetEntity = this.theEntity.getAttackTarget();
|
||||
|
||||
if (this.targetEntity == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if (this.targetEntity.getDistanceSqToEntity(this.theEntity) > (double)(this.maxTargetDistance * this.maxTargetDistance))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
Vec3 vec3 = RandomPositionGenerator.findRandomTargetBlockTowards(this.theEntity, 16, 7, new Vec3(this.targetEntity.posX, this.targetEntity.posY, this.targetEntity.posZ));
|
||||
|
||||
if (vec3 == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.movePosX = vec3.xCoord;
|
||||
this.movePosY = vec3.yCoord;
|
||||
this.movePosZ = vec3.zCoord;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether an in-progress EntityAIBase should continue executing
|
||||
*/
|
||||
public boolean continueExecuting()
|
||||
{
|
||||
return !this.theEntity.getNavigator().noPath() && this.targetEntity.isEntityAlive() && this.targetEntity.getDistanceSqToEntity(this.theEntity) < (double)(this.maxTargetDistance * this.maxTargetDistance);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the task
|
||||
*/
|
||||
public void resetTask()
|
||||
{
|
||||
this.targetEntity = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a one shot task or start executing a continuous task
|
||||
*/
|
||||
public void startExecuting()
|
||||
{
|
||||
this.theEntity.getNavigator().tryMoveToXYZ(this.movePosX, this.movePosY, this.movePosZ, this.speed);
|
||||
}
|
||||
}
|
50
java/src/game/ai/EntityAINagPlayer.java
Executable file
50
java/src/game/ai/EntityAINagPlayer.java
Executable file
|
@ -0,0 +1,50 @@
|
|||
package game.ai;
|
||||
|
||||
import game.entity.npc.EntityNPC;
|
||||
import game.inventory.ContainerMerchant;
|
||||
|
||||
public class EntityAINagPlayer extends EntityAIBase
|
||||
{
|
||||
private EntityNPC npc;
|
||||
|
||||
public EntityAINagPlayer(EntityNPC npc)
|
||||
{
|
||||
this.npc = npc;
|
||||
this.setMutexBits(5);
|
||||
}
|
||||
|
||||
public boolean shouldExecute()
|
||||
{
|
||||
if (!this.npc.isEntityAlive())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if (this.npc.isInLiquid())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if (!this.npc.onGround)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if (this.npc.veloChanged)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
EntityNPC entityplayer = this.npc.getTalking();
|
||||
return entityplayer == null ? false : (this.npc.getDistanceSqToEntity(entityplayer) > 16.0D ? false : entityplayer.openContainer instanceof ContainerMerchant);
|
||||
}
|
||||
}
|
||||
|
||||
public void startExecuting()
|
||||
{
|
||||
this.npc.getNavigator().clearPathEntity();
|
||||
}
|
||||
|
||||
public void resetTask()
|
||||
{
|
||||
this.npc.setTalking(null);
|
||||
}
|
||||
}
|
133
java/src/game/ai/EntityAINearestAttackableTarget.java
Executable file
133
java/src/game/ai/EntityAINearestAttackableTarget.java
Executable file
|
@ -0,0 +1,133 @@
|
|||
package game.ai;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import game.entity.Entity;
|
||||
import game.entity.types.EntityLiving;
|
||||
|
||||
public class EntityAINearestAttackableTarget<T extends EntityLiving> extends EntityAITarget
|
||||
{
|
||||
protected final Class<T> targetClass;
|
||||
private final int targetChance;
|
||||
|
||||
/** Instance of EntityAINearestAttackableTargetSorter. */
|
||||
protected final EntityAINearestAttackableTarget.Sorter theNearestAttackableTargetSorter;
|
||||
protected Predicate <? super T > targetEntitySelector;
|
||||
protected EntityLiving targetEntity;
|
||||
|
||||
public EntityAINearestAttackableTarget(EntityLiving creature, Class<T> classTarget, boolean checkSight)
|
||||
{
|
||||
this(creature, classTarget, checkSight, false);
|
||||
}
|
||||
|
||||
public EntityAINearestAttackableTarget(EntityLiving creature, Class<T> classTarget, boolean checkSight, boolean onlyNearby)
|
||||
{
|
||||
this(creature, classTarget, 10, checkSight, onlyNearby, (Predicate <? super T >)null);
|
||||
}
|
||||
|
||||
public EntityAINearestAttackableTarget(EntityLiving creature, Class<T> classTarget, int chance, boolean checkSight, boolean onlyNearby, final Predicate <? super T > targetSelector)
|
||||
{
|
||||
super(creature, checkSight, onlyNearby);
|
||||
this.targetClass = classTarget;
|
||||
this.targetChance = chance;
|
||||
this.theNearestAttackableTargetSorter = new EntityAINearestAttackableTarget.Sorter(creature);
|
||||
this.setMutexBits(1);
|
||||
this.targetEntitySelector = new Predicate<T>()
|
||||
{
|
||||
public boolean test(T p_apply_1_)
|
||||
{
|
||||
if (targetSelector != null && !targetSelector.test(p_apply_1_))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (p_apply_1_.isPlayer())
|
||||
{
|
||||
double d0 = EntityAINearestAttackableTarget.this.getTargetDistance();
|
||||
|
||||
if (p_apply_1_.isSneaking())
|
||||
{
|
||||
d0 *= 0.800000011920929D;
|
||||
}
|
||||
|
||||
// if (p_apply_1_.isInvisible())
|
||||
// {
|
||||
// float f = ((EntityNPC)p_apply_1_).getArmorVisibility();
|
||||
//
|
||||
// if (f < 0.1F)
|
||||
// {
|
||||
// f = 0.1F;
|
||||
// }
|
||||
//
|
||||
// d0 *= (double)(0.7F * f);
|
||||
// }
|
||||
|
||||
if ((double)p_apply_1_.getDistanceToEntity(EntityAINearestAttackableTarget.this.taskOwner) > d0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return EntityAINearestAttackableTarget.this.isSuitableTarget(p_apply_1_);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the EntityAIBase should begin execution.
|
||||
*/
|
||||
public boolean shouldExecute()
|
||||
{
|
||||
if (this.targetChance > 0 && this.taskOwner.getRNG().zrange(this.targetChance) != 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
double d0 = this.getTargetDistance();
|
||||
List<T> list = this.taskOwner.worldObj.<T>getEntitiesWithinAABB(this.targetClass, this.taskOwner.getEntityBoundingBox().expand(d0, 4.0D, d0), this.targetEntitySelector);
|
||||
Collections.sort(list, this.theNearestAttackableTargetSorter);
|
||||
|
||||
if (list.isEmpty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.targetEntity = (EntityLiving)list.get(0);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a one shot task or start executing a continuous task
|
||||
*/
|
||||
public void startExecuting()
|
||||
{
|
||||
this.taskOwner.setAttackTarget(this.targetEntity);
|
||||
super.startExecuting();
|
||||
}
|
||||
|
||||
public static class Sorter implements Comparator<Entity>
|
||||
{
|
||||
private final Entity theEntity;
|
||||
|
||||
public Sorter(Entity theEntityIn)
|
||||
{
|
||||
this.theEntity = theEntityIn;
|
||||
}
|
||||
|
||||
public int compare(Entity p_compare_1_, Entity p_compare_2_)
|
||||
{
|
||||
double d0 = this.theEntity.getDistanceSqToEntity(p_compare_1_);
|
||||
double d1 = this.theEntity.getDistanceSqToEntity(p_compare_2_);
|
||||
return d0 < d1 ? -1 : (d0 > d1 ? 1 : 0);
|
||||
}
|
||||
}
|
||||
}
|
56
java/src/game/ai/EntityAINpcInteract.java
Executable file
56
java/src/game/ai/EntityAINpcInteract.java
Executable file
|
@ -0,0 +1,56 @@
|
|||
package game.ai;
|
||||
|
||||
import game.entity.npc.EntityNPC;
|
||||
|
||||
public class EntityAINpcInteract extends EntityAIWatchClosest2
|
||||
{
|
||||
private int interactionDelay;
|
||||
private EntityNPC npc;
|
||||
|
||||
public EntityAINpcInteract(EntityNPC npc)
|
||||
{
|
||||
super(npc, EntityNPC.class, 3.0F, 0.02F);
|
||||
this.npc = npc;
|
||||
}
|
||||
|
||||
// public boolean shouldExecute()
|
||||
// {
|
||||
// if(super.shouldExecute()) {
|
||||
// if(this.closestEntity.isPlayer()) {
|
||||
// this.closestEntity = null;
|
||||
// return false;
|
||||
// }
|
||||
// return true;
|
||||
// }
|
||||
// return false;
|
||||
// }
|
||||
|
||||
public void startExecuting()
|
||||
{
|
||||
super.startExecuting();
|
||||
|
||||
if (this.closestEntity instanceof EntityNPC)
|
||||
{
|
||||
this.interactionDelay = 10;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.interactionDelay = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public void updateTask()
|
||||
{
|
||||
super.updateTask();
|
||||
|
||||
if (this.interactionDelay > 0)
|
||||
{
|
||||
--this.interactionDelay;
|
||||
|
||||
if (this.interactionDelay == 0)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
108
java/src/game/ai/EntityAINpcMate.java
Executable file
108
java/src/game/ai/EntityAINpcMate.java
Executable file
|
@ -0,0 +1,108 @@
|
|||
package game.ai;
|
||||
|
||||
import game.entity.Entity;
|
||||
import game.entity.npc.EntityNPC;
|
||||
import game.world.World;
|
||||
import game.world.WorldServer;
|
||||
|
||||
public class EntityAINpcMate extends EntityAIBase
|
||||
{
|
||||
private EntityNPC npc;
|
||||
private EntityNPC mate;
|
||||
private World worldObj;
|
||||
private int matingTimeout;
|
||||
|
||||
public EntityAINpcMate(EntityNPC npc)
|
||||
{
|
||||
this.npc = npc;
|
||||
this.worldObj = npc.worldObj;
|
||||
this.setMutexBits(3);
|
||||
}
|
||||
|
||||
public boolean shouldExecute()
|
||||
{
|
||||
if (this.npc.getGrowingAge() != 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if (this.npc.getRNG().zrange(100) != 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (this.npc.getIsWillingToMate(true))
|
||||
{
|
||||
Entity entity = ((WorldServer)this.worldObj).findNearestEntityWithinAABB(EntityNPC.class, this.npc.getEntityBoundingBox().expand(8.0D, 3.0D, 8.0D), this.npc);
|
||||
|
||||
if (entity == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.mate = (EntityNPC)entity;
|
||||
return this.mate.getGrowingAge() == 0 && this.mate.getIsWillingToMate(true);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void startExecuting()
|
||||
{
|
||||
this.matingTimeout = 250;
|
||||
this.npc.setMating(true);
|
||||
}
|
||||
|
||||
public void resetTask()
|
||||
{
|
||||
this.mate = null;
|
||||
this.npc.setMating(false);
|
||||
}
|
||||
|
||||
public boolean continueExecuting()
|
||||
{
|
||||
return this.matingTimeout >= 0 && this.npc.getGrowingAge() == 0 && this.npc.getIsWillingToMate(false);
|
||||
}
|
||||
|
||||
public void updateTask()
|
||||
{
|
||||
--this.matingTimeout;
|
||||
this.npc.getLookHelper().setLookPositionWithEntity(this.mate, 10.0F, 30.0F);
|
||||
|
||||
if (this.npc.getDistanceSqToEntity(this.mate) > 2.25D)
|
||||
{
|
||||
this.npc.getNavigator().tryMoveToEntityLiving(this.mate, 0.25D);
|
||||
}
|
||||
else if (this.matingTimeout >= 6)
|
||||
{
|
||||
this.matingTimeout -= 5;
|
||||
}
|
||||
else if (this.matingTimeout == 0 && this.mate.isMating())
|
||||
{
|
||||
this.giveBirth();
|
||||
}
|
||||
|
||||
// if (this.npc.getRNG().nextInt(35) == 0)
|
||||
// {
|
||||
// this.worldObj.setEntityState(this.npc, (byte)12);
|
||||
// }
|
||||
}
|
||||
|
||||
private void giveBirth()
|
||||
{
|
||||
EntityNPC entity = this.npc.createChild(this.mate);
|
||||
this.mate.setGrowingAge(100);
|
||||
this.npc.setGrowingAge(100);
|
||||
this.mate.setIsWillingToMate(false);
|
||||
this.npc.setIsWillingToMate(false);
|
||||
entity.setGrowingAge(-24000);
|
||||
entity.setLocationAndAngles(this.npc.posX, this.npc.posY, this.npc.posZ, 0.0F, 0.0F);
|
||||
this.worldObj.spawnEntityInWorld(entity);
|
||||
this.worldObj.setEntityState(entity, (byte)12);
|
||||
}
|
||||
}
|
86
java/src/game/ai/EntityAIOcelotAttack.java
Executable file
86
java/src/game/ai/EntityAIOcelotAttack.java
Executable file
|
@ -0,0 +1,86 @@
|
|||
package game.ai;
|
||||
|
||||
import game.entity.types.EntityLiving;
|
||||
import game.world.World;
|
||||
|
||||
public class EntityAIOcelotAttack extends EntityAIBase
|
||||
{
|
||||
World theWorld;
|
||||
EntityLiving theEntity;
|
||||
EntityLiving theVictim;
|
||||
int attackCountdown;
|
||||
|
||||
public EntityAIOcelotAttack(EntityLiving theEntityIn)
|
||||
{
|
||||
this.theEntity = theEntityIn;
|
||||
this.theWorld = theEntityIn.worldObj;
|
||||
this.setMutexBits(3);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the EntityAIBase should begin execution.
|
||||
*/
|
||||
public boolean shouldExecute()
|
||||
{
|
||||
EntityLiving entitylivingbase = this.theEntity.getAttackTarget();
|
||||
|
||||
if (entitylivingbase == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.theVictim = entitylivingbase;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether an in-progress EntityAIBase should continue executing
|
||||
*/
|
||||
public boolean continueExecuting()
|
||||
{
|
||||
return !this.theVictim.isEntityAlive() ? false : (this.theEntity.getDistanceSqToEntity(this.theVictim) > 225.0D ? false : !this.theEntity.getNavigator().noPath() || this.shouldExecute());
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the task
|
||||
*/
|
||||
public void resetTask()
|
||||
{
|
||||
this.theVictim = null;
|
||||
this.theEntity.getNavigator().clearPathEntity();
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the task
|
||||
*/
|
||||
public void updateTask()
|
||||
{
|
||||
this.theEntity.getLookHelper().setLookPositionWithEntity(this.theVictim, 30.0F, 30.0F);
|
||||
double d0 = (double)(this.theEntity.width * 2.0F * this.theEntity.width * 2.0F);
|
||||
double d1 = this.theEntity.getDistanceSq(this.theVictim.posX, this.theVictim.getEntityBoundingBox().minY, this.theVictim.posZ);
|
||||
double d2 = 0.8D;
|
||||
|
||||
if (d1 > d0 && d1 < 16.0D)
|
||||
{
|
||||
d2 = 1.33D;
|
||||
}
|
||||
else if (d1 < 225.0D)
|
||||
{
|
||||
d2 = 0.6D;
|
||||
}
|
||||
|
||||
this.theEntity.getNavigator().tryMoveToEntityLiving(this.theVictim, d2);
|
||||
this.attackCountdown = Math.max(this.attackCountdown - 1, 0);
|
||||
|
||||
if (d1 <= d0)
|
||||
{
|
||||
if (this.attackCountdown <= 0)
|
||||
{
|
||||
this.attackCountdown = 20;
|
||||
this.theEntity.attackEntityAsMob(this.theVictim);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
114
java/src/game/ai/EntityAIOcelotSit.java
Executable file
114
java/src/game/ai/EntityAIOcelotSit.java
Executable file
|
@ -0,0 +1,114 @@
|
|||
package game.ai;
|
||||
|
||||
import game.block.Block;
|
||||
import game.block.BlockBed;
|
||||
import game.entity.animal.EntityOcelot;
|
||||
import game.init.Blocks;
|
||||
import game.tileentity.TileEntity;
|
||||
import game.tileentity.TileEntityChest;
|
||||
import game.world.BlockPos;
|
||||
import game.world.State;
|
||||
import game.world.World;
|
||||
|
||||
public class EntityAIOcelotSit extends EntityAIMoveToBlock
|
||||
{
|
||||
private final EntityOcelot ocelot;
|
||||
|
||||
public EntityAIOcelotSit(EntityOcelot ocelotIn, double p_i45315_2_)
|
||||
{
|
||||
super(ocelotIn, p_i45315_2_, 8);
|
||||
this.ocelot = ocelotIn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the EntityAIBase should begin execution.
|
||||
*/
|
||||
public boolean shouldExecute()
|
||||
{
|
||||
return this.ocelot.isTamed() && !this.ocelot.isSitting() && super.shouldExecute();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether an in-progress EntityAIBase should continue executing
|
||||
*/
|
||||
public boolean continueExecuting()
|
||||
{
|
||||
return super.continueExecuting();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a one shot task or start executing a continuous task
|
||||
*/
|
||||
public void startExecuting()
|
||||
{
|
||||
super.startExecuting();
|
||||
this.ocelot.getAISit().setSitting(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the task
|
||||
*/
|
||||
public void resetTask()
|
||||
{
|
||||
super.resetTask();
|
||||
this.ocelot.setSitting(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the task
|
||||
*/
|
||||
public void updateTask()
|
||||
{
|
||||
super.updateTask();
|
||||
this.ocelot.getAISit().setSitting(false);
|
||||
|
||||
if (!this.getIsAboveDestination())
|
||||
{
|
||||
this.ocelot.setSitting(false);
|
||||
}
|
||||
else if (!this.ocelot.isSitting())
|
||||
{
|
||||
this.ocelot.setSitting(true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true to set given position as destination
|
||||
*/
|
||||
protected boolean shouldMoveTo(World worldIn, BlockPos pos)
|
||||
{
|
||||
if (!worldIn.isAirBlock(pos.up()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
State iblockstate = worldIn.getState(pos);
|
||||
Block block = iblockstate.getBlock();
|
||||
|
||||
if (block == Blocks.chest)
|
||||
{
|
||||
TileEntity tileentity = worldIn.getTileEntity(pos);
|
||||
|
||||
if (tileentity instanceof TileEntityChest && ((TileEntityChest)tileentity).numPlayersUsing < 1)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (block == Blocks.lit_furnace)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (block instanceof BlockBed && iblockstate.getValue(BlockBed.PART) != BlockBed.EnumPartType.HEAD)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
58
java/src/game/ai/EntityAIOpenDoor.java
Executable file
58
java/src/game/ai/EntityAIOpenDoor.java
Executable file
|
@ -0,0 +1,58 @@
|
|||
package game.ai;
|
||||
|
||||
import game.entity.types.EntityLiving;
|
||||
|
||||
public class EntityAIOpenDoor extends EntityAIDoorInteract
|
||||
{
|
||||
/** If the entity close the door */
|
||||
boolean closeDoor;
|
||||
|
||||
/**
|
||||
* The temporisation before the entity close the door (in ticks, always 20 = 1 second)
|
||||
*/
|
||||
int closeDoorTemporisation;
|
||||
|
||||
public EntityAIOpenDoor(EntityLiving entitylivingIn, boolean shouldClose)
|
||||
{
|
||||
super(entitylivingIn);
|
||||
this.theEntity = entitylivingIn;
|
||||
this.closeDoor = shouldClose;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether an in-progress EntityAIBase should continue executing
|
||||
*/
|
||||
public boolean continueExecuting()
|
||||
{
|
||||
return this.closeDoor && this.closeDoorTemporisation > 0 && super.continueExecuting();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a one shot task or start executing a continuous task
|
||||
*/
|
||||
public void startExecuting()
|
||||
{
|
||||
this.closeDoorTemporisation = 20;
|
||||
this.doorBlock.toggleDoor(this.theEntity.worldObj, this.doorPosition, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the task
|
||||
*/
|
||||
public void resetTask()
|
||||
{
|
||||
if (this.closeDoor)
|
||||
{
|
||||
this.doorBlock.toggleDoor(this.theEntity.worldObj, this.doorPosition, false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the task
|
||||
*/
|
||||
public void updateTask()
|
||||
{
|
||||
--this.closeDoorTemporisation;
|
||||
super.updateTask();
|
||||
}
|
||||
}
|
60
java/src/game/ai/EntityAIOwnerHurtByTarget.java
Executable file
60
java/src/game/ai/EntityAIOwnerHurtByTarget.java
Executable file
|
@ -0,0 +1,60 @@
|
|||
package game.ai;
|
||||
|
||||
import game.entity.types.EntityLiving;
|
||||
import game.entity.types.EntityTameable;
|
||||
|
||||
public class EntityAIOwnerHurtByTarget extends EntityAITarget
|
||||
{
|
||||
EntityTameable theDefendingTameable;
|
||||
EntityLiving theOwnerAttacker;
|
||||
private int field_142051_e;
|
||||
|
||||
public EntityAIOwnerHurtByTarget(EntityTameable theDefendingTameableIn)
|
||||
{
|
||||
super(theDefendingTameableIn, false);
|
||||
this.theDefendingTameable = theDefendingTameableIn;
|
||||
this.setMutexBits(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the EntityAIBase should begin execution.
|
||||
*/
|
||||
public boolean shouldExecute()
|
||||
{
|
||||
if (!this.theDefendingTameable.isTamed())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
EntityLiving entitylivingbase = this.theDefendingTameable.getOwner();
|
||||
|
||||
if (entitylivingbase == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.theOwnerAttacker = entitylivingbase.getAttackedBy();
|
||||
int i = entitylivingbase.getAttackedTime();
|
||||
return i != this.field_142051_e && this.isSuitableTarget(this.theOwnerAttacker) && this.theDefendingTameable.shouldAttackEntity(this.theOwnerAttacker, entitylivingbase);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a one shot task or start executing a continuous task
|
||||
*/
|
||||
public void startExecuting()
|
||||
{
|
||||
this.taskOwner.setAttackTarget(this.theOwnerAttacker);
|
||||
EntityLiving entitylivingbase = this.theDefendingTameable.getOwner();
|
||||
|
||||
if (entitylivingbase != null)
|
||||
{
|
||||
this.field_142051_e = entitylivingbase.getAttackedTime();
|
||||
}
|
||||
|
||||
super.startExecuting();
|
||||
}
|
||||
}
|
60
java/src/game/ai/EntityAIOwnerHurtTarget.java
Executable file
60
java/src/game/ai/EntityAIOwnerHurtTarget.java
Executable file
|
@ -0,0 +1,60 @@
|
|||
package game.ai;
|
||||
|
||||
import game.entity.types.EntityLiving;
|
||||
import game.entity.types.EntityTameable;
|
||||
|
||||
public class EntityAIOwnerHurtTarget extends EntityAITarget
|
||||
{
|
||||
EntityTameable theEntityTameable;
|
||||
EntityLiving theTarget;
|
||||
private int field_142050_e;
|
||||
|
||||
public EntityAIOwnerHurtTarget(EntityTameable theEntityTameableIn)
|
||||
{
|
||||
super(theEntityTameableIn, false);
|
||||
this.theEntityTameable = theEntityTameableIn;
|
||||
this.setMutexBits(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the EntityAIBase should begin execution.
|
||||
*/
|
||||
public boolean shouldExecute()
|
||||
{
|
||||
if (!this.theEntityTameable.isTamed())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
EntityLiving entitylivingbase = this.theEntityTameable.getOwner();
|
||||
|
||||
if (entitylivingbase == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.theTarget = entitylivingbase.getLastAttack();
|
||||
int i = entitylivingbase.getLastAttackTime();
|
||||
return i != this.field_142050_e && this.isSuitableTarget(this.theTarget) && this.theEntityTameable.shouldAttackEntity(this.theTarget, entitylivingbase);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a one shot task or start executing a continuous task
|
||||
*/
|
||||
public void startExecuting()
|
||||
{
|
||||
this.taskOwner.setAttackTarget(this.theTarget);
|
||||
EntityLiving entitylivingbase = this.theEntityTameable.getOwner();
|
||||
|
||||
if (entitylivingbase != null)
|
||||
{
|
||||
this.field_142050_e = entitylivingbase.getLastAttackTime();
|
||||
}
|
||||
|
||||
super.startExecuting();
|
||||
}
|
||||
}
|
63
java/src/game/ai/EntityAIPanic.java
Executable file
63
java/src/game/ai/EntityAIPanic.java
Executable file
|
@ -0,0 +1,63 @@
|
|||
package game.ai;
|
||||
|
||||
import game.entity.types.EntityLiving;
|
||||
import game.world.Vec3;
|
||||
|
||||
public class EntityAIPanic extends EntityAIBase
|
||||
{
|
||||
private EntityLiving theEntityCreature;
|
||||
protected double speed;
|
||||
private double randPosX;
|
||||
private double randPosY;
|
||||
private double randPosZ;
|
||||
|
||||
public EntityAIPanic(EntityLiving creature, double speedIn)
|
||||
{
|
||||
this.theEntityCreature = creature;
|
||||
this.speed = speedIn;
|
||||
this.setMutexBits(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the EntityAIBase should begin execution.
|
||||
*/
|
||||
public boolean shouldExecute()
|
||||
{
|
||||
if (this.theEntityCreature.getAttackedBy() == null && !this.theEntityCreature.isBurning())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
Vec3 vec3 = RandomPositionGenerator.findRandomTarget(this.theEntityCreature, 5, 4);
|
||||
|
||||
if (vec3 == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.randPosX = vec3.xCoord;
|
||||
this.randPosY = vec3.yCoord;
|
||||
this.randPosZ = vec3.zCoord;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a one shot task or start executing a continuous task
|
||||
*/
|
||||
public void startExecuting()
|
||||
{
|
||||
this.theEntityCreature.getNavigator().tryMoveToXYZ(this.randPosX, this.randPosY, this.randPosZ, this.speed);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether an in-progress EntityAIBase should continue executing
|
||||
*/
|
||||
public boolean continueExecuting()
|
||||
{
|
||||
return !this.theEntityCreature.getNavigator().noPath();
|
||||
}
|
||||
}
|
72
java/src/game/ai/EntityAIPlay.java
Executable file
72
java/src/game/ai/EntityAIPlay.java
Executable file
|
@ -0,0 +1,72 @@
|
|||
package game.ai;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import game.entity.npc.EntityNPC;
|
||||
import game.entity.types.EntityLiving;
|
||||
import game.world.Vec3;
|
||||
|
||||
public class EntityAIPlay extends EntityAIBase {
|
||||
private EntityNPC entity;
|
||||
private EntityLiving target;
|
||||
private double speed;
|
||||
private int time;
|
||||
|
||||
public EntityAIPlay(EntityNPC entity, double speed) {
|
||||
this.entity = entity;
|
||||
this.speed = speed;
|
||||
this.setMutexBits(1);
|
||||
}
|
||||
|
||||
public boolean shouldExecute() {
|
||||
if(!this.entity.canPlay() || this.entity.getRNG().zrange(400) != 0)
|
||||
return false;
|
||||
List<EntityNPC> list = this.entity.worldObj.<EntityNPC>getEntitiesWithinAABB(EntityNPC.class,
|
||||
this.entity.getEntityBoundingBox().expand(6.0D, 3.0D, 6.0D));
|
||||
double d0 = Double.MAX_VALUE;
|
||||
for(EntityNPC npc : list) {
|
||||
if(npc != this.entity && !npc.isPlaying() && npc.canPlay() && !this.entity.canAttack(npc) && !npc.canAttack(this.entity)) {
|
||||
double d1 = npc.getDistanceSqToEntity(this.entity);
|
||||
if(d1 <= d0) {
|
||||
d0 = d1;
|
||||
this.target = npc;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(this.target == null) {
|
||||
Vec3 vec = RandomPositionGenerator.findRandomTarget(this.entity, 16, 3);
|
||||
if(vec == null)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean continueExecuting() {
|
||||
return this.time > 0;
|
||||
}
|
||||
|
||||
public void startExecuting() {
|
||||
if(this.target != null)
|
||||
this.entity.setPlaying(true);
|
||||
this.time = 1000;
|
||||
}
|
||||
|
||||
public void resetTask() {
|
||||
this.entity.setPlaying(false);
|
||||
this.target = null;
|
||||
}
|
||||
|
||||
public void updateTask() {
|
||||
--this.time;
|
||||
if(this.target != null) {
|
||||
if(this.entity.getDistanceSqToEntity(this.target) > 4.0D)
|
||||
this.entity.getNavigator().tryMoveToEntityLiving(this.target, this.speed);
|
||||
}
|
||||
else if(this.entity.getNavigator().noPath()) {
|
||||
Vec3 vec = RandomPositionGenerator.findRandomTarget(this.entity, 16, 3);
|
||||
if(vec == null)
|
||||
return;
|
||||
this.entity.getNavigator().tryMoveToXYZ(vec.xCoord, vec.yCoord, vec.zCoord, this.speed);
|
||||
}
|
||||
}
|
||||
}
|
85
java/src/game/ai/EntityAIRestrictOpenDoor.java
Executable file
85
java/src/game/ai/EntityAIRestrictOpenDoor.java
Executable file
|
@ -0,0 +1,85 @@
|
|||
package game.ai;
|
||||
|
||||
import game.entity.types.EntityLiving;
|
||||
import game.pathfinding.PathNavigateGround;
|
||||
import game.village.Village;
|
||||
import game.village.VillageDoorInfo;
|
||||
import game.world.BlockPos;
|
||||
import game.world.WorldServer;
|
||||
|
||||
public class EntityAIRestrictOpenDoor extends EntityAIBase
|
||||
{
|
||||
private EntityLiving entityObj;
|
||||
private VillageDoorInfo frontDoor;
|
||||
|
||||
public EntityAIRestrictOpenDoor(EntityLiving creatureIn)
|
||||
{
|
||||
this.entityObj = creatureIn;
|
||||
|
||||
if (!(creatureIn.getNavigator() instanceof PathNavigateGround))
|
||||
{
|
||||
throw new IllegalArgumentException("Unsupported mob type for RestrictOpenDoorGoal");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the EntityAIBase should begin execution.
|
||||
*/
|
||||
public boolean shouldExecute()
|
||||
{
|
||||
if (((WorldServer)this.entityObj.worldObj).isDaytime())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
BlockPos blockpos = new BlockPos(this.entityObj);
|
||||
Village village = ((WorldServer)this.entityObj.worldObj).getNearestVillage(blockpos, 16);
|
||||
|
||||
if (village == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.frontDoor = village.getNearestDoor(blockpos);
|
||||
return this.frontDoor == null ? false : (double)this.frontDoor.getDistanceToInsideBlockSq(blockpos) < 2.25D;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether an in-progress EntityAIBase should continue executing
|
||||
*/
|
||||
public boolean continueExecuting()
|
||||
{
|
||||
return ((WorldServer)this.entityObj.worldObj).isDaytime() ? false : !this.frontDoor.getIsDetachedFromVillageFlag() && this.frontDoor.func_179850_c(new BlockPos(this.entityObj));
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a one shot task or start executing a continuous task
|
||||
*/
|
||||
public void startExecuting()
|
||||
{
|
||||
((PathNavigateGround)this.entityObj.getNavigator()).setBreakDoors(false);
|
||||
((PathNavigateGround)this.entityObj.getNavigator()).setEnterDoors(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the task
|
||||
*/
|
||||
public void resetTask()
|
||||
{
|
||||
((PathNavigateGround)this.entityObj.getNavigator()).setBreakDoors(true);
|
||||
((PathNavigateGround)this.entityObj.getNavigator()).setEnterDoors(true);
|
||||
this.frontDoor = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the task
|
||||
*/
|
||||
public void updateTask()
|
||||
{
|
||||
this.frontDoor.incrementDoorOpeningRestrictionCounter();
|
||||
}
|
||||
}
|
39
java/src/game/ai/EntityAIRestrictSun.java
Executable file
39
java/src/game/ai/EntityAIRestrictSun.java
Executable file
|
@ -0,0 +1,39 @@
|
|||
package game.ai;
|
||||
|
||||
import game.entity.types.EntityLiving;
|
||||
import game.pathfinding.PathNavigateGround;
|
||||
import game.world.WorldServer;
|
||||
|
||||
public class EntityAIRestrictSun extends EntityAIBase
|
||||
{
|
||||
private EntityLiving theEntity;
|
||||
|
||||
public EntityAIRestrictSun(EntityLiving creature)
|
||||
{
|
||||
this.theEntity = creature;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the EntityAIBase should begin execution.
|
||||
*/
|
||||
public boolean shouldExecute()
|
||||
{
|
||||
return ((WorldServer)this.theEntity.worldObj).isDaytime();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a one shot task or start executing a continuous task
|
||||
*/
|
||||
public void startExecuting()
|
||||
{
|
||||
((PathNavigateGround)this.theEntity.getNavigator()).setAvoidSun(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the task
|
||||
*/
|
||||
public void resetTask()
|
||||
{
|
||||
((PathNavigateGround)this.theEntity.getNavigator()).setAvoidSun(false);
|
||||
}
|
||||
}
|
94
java/src/game/ai/EntityAIRunAroundLikeCrazy.java
Executable file
94
java/src/game/ai/EntityAIRunAroundLikeCrazy.java
Executable file
|
@ -0,0 +1,94 @@
|
|||
package game.ai;
|
||||
|
||||
import game.entity.Entity;
|
||||
import game.entity.animal.EntityHorse;
|
||||
import game.entity.npc.EntityNPC;
|
||||
import game.world.Vec3;
|
||||
|
||||
public class EntityAIRunAroundLikeCrazy extends EntityAIBase
|
||||
{
|
||||
private EntityHorse horseHost;
|
||||
private double speed;
|
||||
private double targetX;
|
||||
private double targetY;
|
||||
private double targetZ;
|
||||
|
||||
public EntityAIRunAroundLikeCrazy(EntityHorse horse, double speedIn)
|
||||
{
|
||||
this.horseHost = horse;
|
||||
this.speed = speedIn;
|
||||
this.setMutexBits(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the EntityAIBase should begin execution.
|
||||
*/
|
||||
public boolean shouldExecute()
|
||||
{
|
||||
if (!this.horseHost.isTame() && this.horseHost.passenger != null)
|
||||
{
|
||||
Vec3 vec3 = RandomPositionGenerator.findRandomTarget(this.horseHost, 5, 4);
|
||||
|
||||
if (vec3 == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.targetX = vec3.xCoord;
|
||||
this.targetY = vec3.yCoord;
|
||||
this.targetZ = vec3.zCoord;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a one shot task or start executing a continuous task
|
||||
*/
|
||||
public void startExecuting()
|
||||
{
|
||||
this.horseHost.getNavigator().tryMoveToXYZ(this.targetX, this.targetY, this.targetZ, this.speed);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether an in-progress EntityAIBase should continue executing
|
||||
*/
|
||||
public boolean continueExecuting()
|
||||
{
|
||||
return !this.horseHost.getNavigator().noPath() && this.horseHost.passenger != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the task
|
||||
*/
|
||||
public void updateTask()
|
||||
{
|
||||
if (this.horseHost.getRNG().zrange(50) == 0)
|
||||
{
|
||||
if (this.horseHost.passenger instanceof EntityNPC)
|
||||
{
|
||||
int i = this.horseHost.getTemper();
|
||||
int j = this.horseHost.getMaxTemper();
|
||||
|
||||
if (j > 0 && this.horseHost.getRNG().zrange(j) < i)
|
||||
{
|
||||
this.horseHost.setHorseTamed(true);
|
||||
this.horseHost.worldObj.setEntityState(this.horseHost, (byte)7);
|
||||
return;
|
||||
}
|
||||
|
||||
this.horseHost.increaseTemper(5);
|
||||
}
|
||||
|
||||
this.horseHost.passenger.mountEntity((Entity)null);
|
||||
this.horseHost.passenger = null;
|
||||
this.horseHost.makeHorseRearWithSound();
|
||||
this.horseHost.worldObj.setEntityState(this.horseHost, (byte)6);
|
||||
}
|
||||
}
|
||||
}
|
101
java/src/game/ai/EntityAIShareItems.java
Executable file
101
java/src/game/ai/EntityAIShareItems.java
Executable file
|
@ -0,0 +1,101 @@
|
|||
package game.ai;
|
||||
|
||||
import game.ExtMath;
|
||||
import game.entity.item.EntityItem;
|
||||
import game.entity.npc.EntityNPC;
|
||||
import game.init.Items;
|
||||
import game.inventory.InventoryBasic;
|
||||
import game.item.Item;
|
||||
import game.item.ItemStack;
|
||||
|
||||
public class EntityAIShareItems extends EntityAIWatchClosest2
|
||||
{
|
||||
private int interactionDelay;
|
||||
private EntityNPC entity;
|
||||
|
||||
public EntityAIShareItems(EntityNPC npc)
|
||||
{
|
||||
super(npc, EntityNPC.class, 3.0F, 0.02F);
|
||||
this.entity = npc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a one shot task or start executing a continuous task
|
||||
*/
|
||||
public void startExecuting()
|
||||
{
|
||||
super.startExecuting();
|
||||
|
||||
// if (this.entity.canShareItems() && this.closestEntity instanceof EntityNPC && ((EntityNPC)this.closestEntity).needsMoreItems())
|
||||
// {
|
||||
// this.interactionDelay = 10;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// this.interactionDelay = 0;
|
||||
// }
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the task
|
||||
*/
|
||||
public void updateTask()
|
||||
{
|
||||
super.updateTask();
|
||||
|
||||
if (this.interactionDelay > 0)
|
||||
{
|
||||
--this.interactionDelay;
|
||||
|
||||
if (this.interactionDelay == 0)
|
||||
{
|
||||
InventoryBasic inventorybasic = this.entity.getExtendedInventory();
|
||||
|
||||
for (int i = 0; i < inventorybasic.getSizeInventory(); ++i)
|
||||
{
|
||||
ItemStack itemstack = inventorybasic.getStackInSlot(i);
|
||||
ItemStack itemstack1 = null;
|
||||
|
||||
if (itemstack != null)
|
||||
{
|
||||
Item item = itemstack.getItem();
|
||||
|
||||
if ((item == Items.bread || item == Items.potato || item == Items.carrot) && itemstack.stackSize > 3)
|
||||
{
|
||||
int l = itemstack.stackSize / 2;
|
||||
itemstack.stackSize -= l;
|
||||
itemstack1 = new ItemStack(item, l, itemstack.getMetadata());
|
||||
}
|
||||
else if (item == Items.wheats && itemstack.stackSize > 5)
|
||||
{
|
||||
int j = itemstack.stackSize / 2 / 3 * 3;
|
||||
int k = j / 3;
|
||||
itemstack.stackSize -= j;
|
||||
itemstack1 = new ItemStack(Items.bread, k, 0);
|
||||
}
|
||||
|
||||
if (itemstack.stackSize <= 0)
|
||||
{
|
||||
inventorybasic.setInventorySlotContents(i, (ItemStack)null);
|
||||
}
|
||||
}
|
||||
|
||||
if (itemstack1 != null)
|
||||
{
|
||||
double d0 = this.entity.posY - 0.30000001192092896D + (double)this.entity.getEyeHeight();
|
||||
EntityItem entityitem = new EntityItem(this.entity.worldObj, this.entity.posX, d0, this.entity.posZ, itemstack1);
|
||||
float f = 0.3F;
|
||||
float f1 = this.entity.headYaw;
|
||||
float f2 = this.entity.rotPitch;
|
||||
entityitem.motionX = (double)(-ExtMath.sin(f1 / 180.0F * (float)Math.PI) * ExtMath.cos(f2 / 180.0F * (float)Math.PI) * f);
|
||||
entityitem.motionZ = (double)(ExtMath.cos(f1 / 180.0F * (float)Math.PI) * ExtMath.cos(f2 / 180.0F * (float)Math.PI) * f);
|
||||
entityitem.motionY = (double)(-ExtMath.sin(f2 / 180.0F * (float)Math.PI) * f + 0.1F);
|
||||
entityitem.setDefaultPickupDelay();
|
||||
this.entity.worldObj.spawnEntityInWorld(entityitem);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
67
java/src/game/ai/EntityAISit.java
Executable file
67
java/src/game/ai/EntityAISit.java
Executable file
|
@ -0,0 +1,67 @@
|
|||
package game.ai;
|
||||
|
||||
import game.entity.types.EntityLiving;
|
||||
import game.entity.types.EntityTameable;
|
||||
|
||||
public class EntityAISit extends EntityAIBase
|
||||
{
|
||||
private EntityTameable theEntity;
|
||||
|
||||
/** If the EntityTameable is sitting. */
|
||||
private boolean isSitting;
|
||||
|
||||
public EntityAISit(EntityTameable entityIn)
|
||||
{
|
||||
this.theEntity = entityIn;
|
||||
this.setMutexBits(5);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the EntityAIBase should begin execution.
|
||||
*/
|
||||
public boolean shouldExecute()
|
||||
{
|
||||
if (!this.theEntity.isTamed())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if (this.theEntity.isInLiquid())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if (!this.theEntity.onGround)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
EntityLiving entitylivingbase = this.theEntity.getOwner();
|
||||
return entitylivingbase == null ? true : (this.theEntity.getDistanceSqToEntity(entitylivingbase) < 144.0D && entitylivingbase.getAttackedBy() != null ? false : this.isSitting);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a one shot task or start executing a continuous task
|
||||
*/
|
||||
public void startExecuting()
|
||||
{
|
||||
this.theEntity.getNavigator().clearPathEntity();
|
||||
this.theEntity.setSitting(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the task
|
||||
*/
|
||||
public void resetTask()
|
||||
{
|
||||
this.theEntity.setSitting(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the sitting flag.
|
||||
*/
|
||||
public void setSitting(boolean sitting)
|
||||
{
|
||||
this.isSitting = sitting;
|
||||
}
|
||||
}
|
35
java/src/game/ai/EntityAISwimming.java
Executable file
35
java/src/game/ai/EntityAISwimming.java
Executable file
|
@ -0,0 +1,35 @@
|
|||
package game.ai;
|
||||
|
||||
import game.entity.types.EntityLiving;
|
||||
import game.pathfinding.PathNavigateGround;
|
||||
|
||||
public class EntityAISwimming extends EntityAIBase
|
||||
{
|
||||
private EntityLiving theEntity;
|
||||
|
||||
public EntityAISwimming(EntityLiving entitylivingIn)
|
||||
{
|
||||
this.theEntity = entitylivingIn;
|
||||
this.setMutexBits(4);
|
||||
((PathNavigateGround)entitylivingIn.getNavigator()).setCanSwim(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the EntityAIBase should begin execution.
|
||||
*/
|
||||
public boolean shouldExecute()
|
||||
{
|
||||
return this.theEntity.isInLiquid() || this.theEntity.isInMolten();
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the task
|
||||
*/
|
||||
public void updateTask()
|
||||
{
|
||||
if (this.theEntity.getRNG().floatv() < 0.8F)
|
||||
{
|
||||
this.theEntity.getJumpHelper().setJumping();
|
||||
}
|
||||
}
|
||||
}
|
162
java/src/game/ai/EntityAITakePlace.java
Executable file
162
java/src/game/ai/EntityAITakePlace.java
Executable file
|
@ -0,0 +1,162 @@
|
|||
package game.ai;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import game.ExtMath;
|
||||
import game.block.Block;
|
||||
import game.collect.Maps;
|
||||
import game.entity.npc.EntityNPC;
|
||||
import game.init.Blocks;
|
||||
import game.init.Config;
|
||||
import game.init.ItemRegistry;
|
||||
import game.item.ItemStack;
|
||||
import game.material.Material;
|
||||
import game.rng.Random;
|
||||
import game.world.BlockPos;
|
||||
import game.world.State;
|
||||
import game.world.World;
|
||||
|
||||
public class EntityAITakePlace extends EntityAIBase
|
||||
{
|
||||
private static class StackKey {
|
||||
public String item;
|
||||
public int meta;
|
||||
|
||||
public StackKey(String str) {
|
||||
String[] tok = str.split(":", 2);
|
||||
this.item = tok[0];
|
||||
this.meta = tok.length > 1 ? Integer.parseInt(tok[1]) : -1;
|
||||
}
|
||||
|
||||
public StackKey(ItemStack stack) {
|
||||
this.item = ItemRegistry.REGISTRY.getNameForObject(stack.getItem()).toString();
|
||||
this.meta = stack.getItem().getMaxDamage() <= 0 ? stack.getMetadata() : -1;
|
||||
}
|
||||
|
||||
// public boolean isSame(ItemStack stack) {
|
||||
// return this.item.equals(ItemRegistry.REGISTRY.getNameForObject(stack.getItem()).toString()) &&
|
||||
// (stack.getItem().getMaxDamage() > 0 || stack.getMetadata() == this.meta);
|
||||
// }
|
||||
|
||||
public boolean equals(Object other) {
|
||||
return other instanceof StackKey && ((StackKey)other).item.equals(this.item) && ((StackKey)other).meta == this.meta;
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return this.item.hashCode() ^ (this.meta << 8);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return this.item + (this.meta == -1 ? "" : (":" + this.meta));
|
||||
}
|
||||
}
|
||||
|
||||
private static final Map<State, ItemStack> STEALABLE = Maps.newHashMap();
|
||||
private static final Map<StackKey, State> PLACEABLE = Maps.newHashMap();
|
||||
|
||||
private static void addPlaceable(State state, ItemStack stack) {
|
||||
STEALABLE.put(state, stack);
|
||||
PLACEABLE.put(new StackKey(stack), state);
|
||||
}
|
||||
|
||||
private static void addPlaceable(Block block) {
|
||||
addPlaceable(block.getState(), new ItemStack(block));
|
||||
}
|
||||
|
||||
static {
|
||||
addPlaceable(Blocks.flower);
|
||||
addPlaceable(Blocks.brown_mushroom);
|
||||
addPlaceable(Blocks.red_mushroom);
|
||||
addPlaceable(Blocks.blue_mushroom);
|
||||
}
|
||||
|
||||
private EntityNPC entity;
|
||||
private boolean place;
|
||||
|
||||
public EntityAITakePlace(EntityNPC placer)
|
||||
{
|
||||
this.entity = placer;
|
||||
}
|
||||
|
||||
public boolean shouldExecute()
|
||||
{
|
||||
if(!Config.mobGrief || this.entity.getAttackTarget() != null)
|
||||
return false;
|
||||
if(this.entity.getHeldItem() == null) {
|
||||
this.place = false;
|
||||
return this.entity.getRNG().chance(20);
|
||||
}
|
||||
else if(this.entity.getRNG().chance(200) && PLACEABLE.containsKey(new StackKey(this.entity.getHeldItem()))) {
|
||||
this.place = this.entity.getRNG().rarity(10);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void updateTask()
|
||||
{
|
||||
Random random = this.entity.getRNG();
|
||||
World world = this.entity.worldObj;
|
||||
int i = ExtMath.floord(this.entity.posX - (this.place ? 1.0 : 2.0) + random.doublev() * (this.place ? 2.0 : 4.0));
|
||||
int j = ExtMath.floord(this.entity.posY + random.doublev() * (this.place ? 2.0 : 3.0));
|
||||
int k = ExtMath.floord(this.entity.posZ - (this.place ? 1.0 : 2.0) + random.doublev() * (this.place ? 2.0 : 4.0));
|
||||
BlockPos blockpos = new BlockPos(i, j, k);
|
||||
if(this.place) {
|
||||
ItemStack stack = this.entity.getHeldItem();
|
||||
if(stack == null || !PLACEABLE.containsKey(new StackKey(this.entity.getHeldItem())))
|
||||
return;
|
||||
Block replace = world.getState(blockpos).getBlock();
|
||||
Block below = world.getState(blockpos.down()).getBlock();
|
||||
State state = PLACEABLE.get(new StackKey(this.entity.getHeldItem()));
|
||||
if (state.getBlock().canPlaceBlockAt(world, blockpos) && replace.getMaterial() == Material.air &&
|
||||
below.getMaterial() != Material.air && below.isFullCube())
|
||||
{
|
||||
this.entity.getLookHelper().setLookPosition((double)i + 0.5, (double)j + 0.5, (double)k + 0.5, 10.0F,
|
||||
(float)this.entity.getVerticalFaceSpeed());
|
||||
this.entity.swingItem();
|
||||
world.setState(blockpos, state, 3);
|
||||
--stack.stackSize;
|
||||
if(stack.stackSize <= 0)
|
||||
this.entity.setItemNoUpdate(0, null);
|
||||
}
|
||||
}
|
||||
else {
|
||||
State state = world.getState(blockpos);
|
||||
Block block = state.getBlock();
|
||||
|
||||
if (STEALABLE.containsKey(state) &&
|
||||
(this.entity.getHeldItem() == null || (ItemStack.areItemsEqual(STEALABLE.get(state),
|
||||
this.entity.getHeldItem()) && this.entity.getHeldItem().stackSize < this.entity.getHeldItem().getMaxStackSize())))
|
||||
{
|
||||
this.entity.getLookHelper().setLookPosition((double)i + 0.5, (double)j + 0.5, (double)k + 0.5, 10.0F,
|
||||
(float)this.entity.getVerticalFaceSpeed());
|
||||
this.entity.swingItem();
|
||||
world.setState(blockpos, Blocks.air.getState());
|
||||
if(this.entity.getHeldItem() != null)
|
||||
++this.entity.getHeldItem().stackSize;
|
||||
else
|
||||
this.entity.setItemNoUpdate(0, STEALABLE.get(state).copy());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//private boolean shouldAttackPlayer(EntityNPC player)
|
||||
//{
|
||||
// ItemStack itemstack = player.inventory.armorInventory[3];
|
||||
//
|
||||
// if (itemstack != null && itemstack.getItem() == ItemRegistry.getItemFromBlock(Blocks.pumpkin))
|
||||
// {
|
||||
// return false;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// Vec3 vec3 = player.getLook(1.0F).normalize();
|
||||
// Vec3 vec31 = new Vec3(this.posX - player.posX, this.getEntityBoundingBox().minY + (double)(this.height / 2.0F) - (player.posY + (double)player.getEyeHeight()), this.posZ - player.posZ);
|
||||
// double d0 = vec31.lengthVector();
|
||||
// vec31 = vec31.normalize();
|
||||
// double d1 = vec3.dotProduct(vec31);
|
||||
// return d1 > 1.0D - 0.025D / d0 ? player.canEntityBeSeen(this) : false;
|
||||
// }
|
||||
//}
|
||||
//
|
||||
}
|
255
java/src/game/ai/EntityAITarget.java
Executable file
255
java/src/game/ai/EntityAITarget.java
Executable file
|
@ -0,0 +1,255 @@
|
|||
package game.ai;
|
||||
|
||||
import game.ExtMath;
|
||||
import game.entity.attributes.AttributeInstance;
|
||||
import game.entity.attributes.Attributes;
|
||||
import game.entity.types.EntityLiving;
|
||||
import game.entity.types.IEntityOwnable;
|
||||
import game.init.Config;
|
||||
import game.pathfinding.PathEntity;
|
||||
import game.pathfinding.PathPoint;
|
||||
import game.world.BlockPos;
|
||||
|
||||
public abstract class EntityAITarget extends EntityAIBase
|
||||
{
|
||||
/** The entity that this task belongs to */
|
||||
protected final EntityLiving taskOwner;
|
||||
|
||||
/**
|
||||
* If true, EntityAI targets must be able to be seen (cannot be blocked by walls) to be suitable targets.
|
||||
*/
|
||||
protected boolean shouldCheckSight;
|
||||
|
||||
/**
|
||||
* When true, only entities that can be reached with minimal effort will be targetted.
|
||||
*/
|
||||
private boolean nearbyOnly;
|
||||
|
||||
/**
|
||||
* When nearbyOnly is true: 0 -> No target, but OK to search; 1 -> Nearby target found; 2 -> Target too far.
|
||||
*/
|
||||
private int targetSearchStatus;
|
||||
|
||||
/**
|
||||
* When nearbyOnly is true, this throttles target searching to avoid excessive pathfinding.
|
||||
*/
|
||||
private int targetSearchDelay;
|
||||
|
||||
/**
|
||||
* If @shouldCheckSight is true, the number of ticks before the interuption of this AITastk when the entity does't
|
||||
* see the target
|
||||
*/
|
||||
private int targetUnseenTicks;
|
||||
|
||||
public EntityAITarget(EntityLiving creature, boolean checkSight)
|
||||
{
|
||||
this(creature, checkSight, false);
|
||||
}
|
||||
|
||||
public EntityAITarget(EntityLiving creature, boolean checkSight, boolean onlyNearby)
|
||||
{
|
||||
this.taskOwner = creature;
|
||||
this.shouldCheckSight = checkSight;
|
||||
this.nearbyOnly = onlyNearby;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether an in-progress EntityAIBase should continue executing
|
||||
*/
|
||||
public boolean continueExecuting()
|
||||
{
|
||||
EntityLiving entitylivingbase = this.taskOwner.getAttackTarget();
|
||||
|
||||
if (entitylivingbase == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if (!entitylivingbase.isEntityAlive())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Team team = this.taskOwner.getTeam();
|
||||
// Team team1 = entitylivingbase.getTeam();
|
||||
//
|
||||
// if (team != null && team1 == team)
|
||||
// {
|
||||
// return false;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
double d0 = this.getTargetDistance();
|
||||
|
||||
if (this.taskOwner.getDistanceSqToEntity(entitylivingbase) > d0 * d0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (this.shouldCheckSight)
|
||||
{
|
||||
if (this.taskOwner.getEntitySenses().canSee(entitylivingbase))
|
||||
{
|
||||
this.targetUnseenTicks = 0;
|
||||
}
|
||||
else if (++this.targetUnseenTicks > 60)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return Config.mobAttacks;
|
||||
}
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
protected double getTargetDistance()
|
||||
{
|
||||
AttributeInstance iattributeinstance = this.taskOwner.getEntityAttribute(Attributes.FOLLOW_RANGE);
|
||||
return iattributeinstance == null ? 16.0D : iattributeinstance.getAttributeValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a one shot task or start executing a continuous task
|
||||
*/
|
||||
public void startExecuting()
|
||||
{
|
||||
this.targetSearchStatus = 0;
|
||||
this.targetSearchDelay = 0;
|
||||
this.targetUnseenTicks = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the task
|
||||
*/
|
||||
public void resetTask()
|
||||
{
|
||||
this.taskOwner.setAttackTarget((EntityLiving)null);
|
||||
}
|
||||
|
||||
/**
|
||||
* A static method used to see if an entity is a suitable target through a number of checks.
|
||||
*/
|
||||
public static boolean isSuitableTarget(EntityLiving attacker, EntityLiving target, boolean checkSight)
|
||||
{
|
||||
if (target == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if (target == attacker)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if (!target.isEntityAlive())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if (!Config.infight && target.getClass() == attacker.getClass())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Team team = attacker.getTeam();
|
||||
// Team team1 = target.getTeam();
|
||||
//
|
||||
// if (team != null && team1 == team)
|
||||
// {
|
||||
// return false;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
if (attacker instanceof IEntityOwnable // ) // && ((IEntityOwnable)attacker).getOwnerId() != null && !((IEntityOwnable)attacker).getOwnerId().isEmpty())
|
||||
// {
|
||||
// if (target instanceof IEntityOwnable && ((IEntityOwnable)attacker).getOwnerId().equalsIgnoreCase(((IEntityOwnable)target).getOwnerId()))
|
||||
// {
|
||||
// return false;
|
||||
// }
|
||||
|
||||
// if (
|
||||
&& target == ((IEntityOwnable)attacker).getOwner())
|
||||
{
|
||||
return false;
|
||||
// }
|
||||
}
|
||||
else if (!Config.mobAttacks)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return !checkSight || attacker.getEntitySenses().canSee(target);
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A method used to see if an entity is a suitable target through a number of checks. Args : entity,
|
||||
* canTargetInvinciblePlayer
|
||||
*/
|
||||
protected boolean isSuitableTarget(EntityLiving target)
|
||||
{
|
||||
if (!isSuitableTarget(this.taskOwner, target, this.shouldCheckSight))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if (!this.taskOwner.isWithinHomeDistanceFromPosition(new BlockPos(target)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (this.nearbyOnly)
|
||||
{
|
||||
if (--this.targetSearchDelay <= 0)
|
||||
{
|
||||
this.targetSearchStatus = 0;
|
||||
}
|
||||
|
||||
if (this.targetSearchStatus == 0)
|
||||
{
|
||||
this.targetSearchStatus = this.canEasilyReach(target) ? 1 : 2;
|
||||
}
|
||||
|
||||
if (this.targetSearchStatus == 2)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks to see if this entity can find a short path to the given target.
|
||||
*
|
||||
* @param target the entity to find a path to
|
||||
*/
|
||||
private boolean canEasilyReach(EntityLiving target)
|
||||
{
|
||||
this.targetSearchDelay = 10 + this.taskOwner.getRNG().zrange(5);
|
||||
PathEntity pathentity = this.taskOwner.getNavigator().getPathToEntityLiving(target);
|
||||
|
||||
if (pathentity == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
PathPoint pathpoint = pathentity.getFinalPathPoint();
|
||||
|
||||
if (pathpoint == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
int i = pathpoint.xCoord - ExtMath.floord(target.posX);
|
||||
int j = pathpoint.zCoord - ExtMath.floord(target.posZ);
|
||||
return (double)(i * i + j * j) <= 2.25D;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
25
java/src/game/ai/EntityAITargetNonTamed.java
Executable file
25
java/src/game/ai/EntityAITargetNonTamed.java
Executable file
|
@ -0,0 +1,25 @@
|
|||
package game.ai;
|
||||
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import game.entity.types.EntityLiving;
|
||||
import game.entity.types.EntityTameable;
|
||||
|
||||
public class EntityAITargetNonTamed<T extends EntityLiving> extends EntityAINearestAttackableTarget
|
||||
{
|
||||
private EntityTameable theTameable;
|
||||
|
||||
public EntityAITargetNonTamed(EntityTameable entityIn, Class<T> classTarget, boolean checkSight, Predicate <? super T > targetSelector)
|
||||
{
|
||||
super(entityIn, classTarget, 10, checkSight, false, targetSelector);
|
||||
this.theTameable = entityIn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the EntityAIBase should begin execution.
|
||||
*/
|
||||
public boolean shouldExecute()
|
||||
{
|
||||
return !this.theTameable.isTamed() && super.shouldExecute();
|
||||
}
|
||||
}
|
173
java/src/game/ai/EntityAITasks.java
Executable file
173
java/src/game/ai/EntityAITasks.java
Executable file
|
@ -0,0 +1,173 @@
|
|||
package game.ai;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import game.collect.Lists;
|
||||
|
||||
public class EntityAITasks
|
||||
{
|
||||
private List<EntityAITasks.EntityAITaskEntry> taskEntries = Lists.<EntityAITasks.EntityAITaskEntry>newArrayList();
|
||||
private List<EntityAITasks.EntityAITaskEntry> executingTaskEntries = Lists.<EntityAITasks.EntityAITaskEntry>newArrayList();
|
||||
private int tickCount;
|
||||
private int tickRate = 3;
|
||||
|
||||
/**
|
||||
* Add a now AITask. Args : priority, task
|
||||
*/
|
||||
public void addTask(int priority, EntityAIBase task)
|
||||
{
|
||||
this.taskEntries.add(new EntityAITasks.EntityAITaskEntry(priority, task));
|
||||
}
|
||||
|
||||
/**
|
||||
* removes the indicated task from the entity's AI tasks.
|
||||
*/
|
||||
public void removeTask(EntityAIBase task)
|
||||
{
|
||||
Iterator<EntityAITasks.EntityAITaskEntry> iterator = this.taskEntries.iterator();
|
||||
|
||||
while (iterator.hasNext())
|
||||
{
|
||||
EntityAITasks.EntityAITaskEntry entityaitasks$entityaitaskentry = (EntityAITasks.EntityAITaskEntry)iterator.next();
|
||||
EntityAIBase entityaibase = entityaitasks$entityaitaskentry.action;
|
||||
|
||||
if (entityaibase == task)
|
||||
{
|
||||
if (this.executingTaskEntries.contains(entityaitasks$entityaitaskentry))
|
||||
{
|
||||
entityaibase.resetTask();
|
||||
this.executingTaskEntries.remove(entityaitasks$entityaitaskentry);
|
||||
}
|
||||
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void onUpdateTasks()
|
||||
{
|
||||
// this.theProfiler.start("goalSetup");
|
||||
|
||||
if (this.tickCount++ % this.tickRate == 0)
|
||||
{
|
||||
Iterator iterator = this.taskEntries.iterator();
|
||||
label38:
|
||||
|
||||
while (true)
|
||||
{
|
||||
EntityAITasks.EntityAITaskEntry entityaitasks$entityaitaskentry;
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (!iterator.hasNext())
|
||||
{
|
||||
break label38;
|
||||
}
|
||||
|
||||
entityaitasks$entityaitaskentry = (EntityAITasks.EntityAITaskEntry)iterator.next();
|
||||
boolean flag = this.executingTaskEntries.contains(entityaitasks$entityaitaskentry);
|
||||
|
||||
if (!flag)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (!this.canUse(entityaitasks$entityaitaskentry) || !this.canContinue(entityaitasks$entityaitaskentry))
|
||||
{
|
||||
entityaitasks$entityaitaskentry.action.resetTask();
|
||||
this.executingTaskEntries.remove(entityaitasks$entityaitaskentry);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.canUse(entityaitasks$entityaitaskentry) && entityaitasks$entityaitaskentry.action.shouldExecute())
|
||||
{
|
||||
entityaitasks$entityaitaskentry.action.startExecuting();
|
||||
this.executingTaskEntries.add(entityaitasks$entityaitaskentry);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Iterator<EntityAITasks.EntityAITaskEntry> iterator1 = this.executingTaskEntries.iterator();
|
||||
|
||||
while (iterator1.hasNext())
|
||||
{
|
||||
EntityAITasks.EntityAITaskEntry entityaitasks$entityaitaskentry1 = (EntityAITasks.EntityAITaskEntry)iterator1.next();
|
||||
|
||||
if (!this.canContinue(entityaitasks$entityaitaskentry1))
|
||||
{
|
||||
entityaitasks$entityaitaskentry1.action.resetTask();
|
||||
iterator1.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// this.theProfiler.end();
|
||||
// this.theProfiler.start("goalTick");
|
||||
|
||||
for (EntityAITasks.EntityAITaskEntry entityaitasks$entityaitaskentry2 : this.executingTaskEntries)
|
||||
{
|
||||
entityaitasks$entityaitaskentry2.action.updateTask();
|
||||
}
|
||||
|
||||
// this.theProfiler.end();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if a specific AI Task should continue being executed.
|
||||
*/
|
||||
private boolean canContinue(EntityAITasks.EntityAITaskEntry taskEntry)
|
||||
{
|
||||
boolean flag = taskEntry.action.continueExecuting();
|
||||
return flag;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if a specific AI Task can be executed, which means that all running higher (= lower int value) priority
|
||||
* tasks are compatible with it or all lower priority tasks can be interrupted.
|
||||
*/
|
||||
private boolean canUse(EntityAITasks.EntityAITaskEntry taskEntry)
|
||||
{
|
||||
for (EntityAITasks.EntityAITaskEntry entityaitasks$entityaitaskentry : this.taskEntries)
|
||||
{
|
||||
if (entityaitasks$entityaitaskentry != taskEntry)
|
||||
{
|
||||
if (taskEntry.priority >= entityaitasks$entityaitaskentry.priority)
|
||||
{
|
||||
if (!this.areTasksCompatible(taskEntry, entityaitasks$entityaitaskentry) && this.executingTaskEntries.contains(entityaitasks$entityaitaskentry))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (!entityaitasks$entityaitaskentry.action.isInterruptible() && this.executingTaskEntries.contains(entityaitasks$entityaitaskentry))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether two EntityAITaskEntries can be executed concurrently
|
||||
*/
|
||||
private boolean areTasksCompatible(EntityAITasks.EntityAITaskEntry taskEntry1, EntityAITasks.EntityAITaskEntry taskEntry2)
|
||||
{
|
||||
return (taskEntry1.action.getMutexBits() & taskEntry2.action.getMutexBits()) == 0;
|
||||
}
|
||||
|
||||
class EntityAITaskEntry
|
||||
{
|
||||
public EntityAIBase action;
|
||||
public int priority;
|
||||
|
||||
public EntityAITaskEntry(int priorityIn, EntityAIBase task)
|
||||
{
|
||||
this.priority = priorityIn;
|
||||
this.action = task;
|
||||
}
|
||||
}
|
||||
}
|
181
java/src/game/ai/EntityAITempt.java
Executable file
181
java/src/game/ai/EntityAITempt.java
Executable file
|
@ -0,0 +1,181 @@
|
|||
package game.ai;
|
||||
|
||||
import game.entity.npc.EntityNPC;
|
||||
import game.entity.types.EntityLiving;
|
||||
import game.item.Item;
|
||||
import game.item.ItemStack;
|
||||
import game.pathfinding.PathNavigateGround;
|
||||
|
||||
public class EntityAITempt extends EntityAIBase
|
||||
{
|
||||
/** The entity using this AI that is tempted by the player. */
|
||||
private EntityLiving temptedEntity;
|
||||
private double speed;
|
||||
|
||||
/** X position of player tempting this mob */
|
||||
private double targetX;
|
||||
|
||||
/** Y position of player tempting this mob */
|
||||
private double targetY;
|
||||
|
||||
/** Z position of player tempting this mob */
|
||||
private double targetZ;
|
||||
|
||||
/** Tempting player's pitch */
|
||||
private double pitch;
|
||||
|
||||
/** Tempting player's yaw */
|
||||
private double yaw;
|
||||
|
||||
/** The player that is tempting the entity that is using this AI. */
|
||||
private EntityNPC temptingPlayer;
|
||||
|
||||
/**
|
||||
* A counter that is decremented each time the shouldExecute method is called. The shouldExecute method will always
|
||||
* return false if delayTemptCounter is greater than 0.
|
||||
*/
|
||||
private int delayTemptCounter;
|
||||
|
||||
/** True if this EntityAITempt task is running */
|
||||
private boolean isRunning;
|
||||
private Item temptItem;
|
||||
private double range;
|
||||
private double distance;
|
||||
|
||||
/**
|
||||
* Whether the entity using this AI will be scared by the tempter's sudden movement.
|
||||
*/
|
||||
private boolean scaredByPlayerMovement;
|
||||
private boolean avoidWater;
|
||||
|
||||
public EntityAITempt(EntityLiving temptedEntityIn, double speedIn, Item temptItemIn, boolean scaredByPlayerMovementIn) {
|
||||
this(temptedEntityIn, speedIn, temptItemIn, 2.5, 10.0, scaredByPlayerMovementIn);
|
||||
}
|
||||
|
||||
public EntityAITempt(EntityLiving temptedEntityIn, double speedIn, Item temptItemIn, double distance, double range, boolean scaredByPlayerMovementIn)
|
||||
{
|
||||
this.temptedEntity = temptedEntityIn;
|
||||
this.speed = speedIn;
|
||||
this.temptItem = temptItemIn;
|
||||
this.distance = distance * distance;
|
||||
this.range = range;
|
||||
this.scaredByPlayerMovement = scaredByPlayerMovementIn;
|
||||
this.setMutexBits(3);
|
||||
|
||||
if (!(temptedEntityIn.getNavigator() instanceof PathNavigateGround))
|
||||
{
|
||||
throw new IllegalArgumentException("Unsupported mob type for TemptGoal");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the EntityAIBase should begin execution.
|
||||
*/
|
||||
public boolean shouldExecute()
|
||||
{
|
||||
if (this.delayTemptCounter > 0)
|
||||
{
|
||||
--this.delayTemptCounter;
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.temptingPlayer = this.temptedEntity.worldObj.getClosestPlayerToEntity(this.temptedEntity, this.distance);
|
||||
|
||||
if (this.temptingPlayer == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(this.temptItem == null)
|
||||
return this.temptedEntity.getDistanceSqToEntity(this.temptingPlayer) >= this.distance;
|
||||
ItemStack itemstack = this.temptingPlayer.getCurrentEquippedItem();
|
||||
return itemstack == null ? false : itemstack.getItem() == this.temptItem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether an in-progress EntityAIBase should continue executing
|
||||
*/
|
||||
public boolean continueExecuting()
|
||||
{
|
||||
if (this.scaredByPlayerMovement)
|
||||
{
|
||||
if (this.temptedEntity.getDistanceSqToEntity(this.temptingPlayer) < 36.0D)
|
||||
{
|
||||
if (this.temptingPlayer.getDistanceSq(this.targetX, this.targetY, this.targetZ) > 0.010000000000000002D)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Math.abs((double)this.temptingPlayer.rotPitch - this.pitch) > 5.0D || Math.abs((double)this.temptingPlayer.rotYaw - this.yaw) > 5.0D)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
this.targetX = this.temptingPlayer.posX;
|
||||
this.targetY = this.temptingPlayer.posY;
|
||||
this.targetZ = this.temptingPlayer.posZ;
|
||||
}
|
||||
|
||||
this.pitch = (double)this.temptingPlayer.rotPitch;
|
||||
this.yaw = (double)this.temptingPlayer.rotYaw;
|
||||
}
|
||||
|
||||
return this.shouldExecute();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a one shot task or start executing a continuous task
|
||||
*/
|
||||
public void startExecuting()
|
||||
{
|
||||
this.targetX = this.temptingPlayer.posX;
|
||||
this.targetY = this.temptingPlayer.posY;
|
||||
this.targetZ = this.temptingPlayer.posZ;
|
||||
this.isRunning = true;
|
||||
this.avoidWater = ((PathNavigateGround)this.temptedEntity.getNavigator()).getAvoidsWater();
|
||||
((PathNavigateGround)this.temptedEntity.getNavigator()).setAvoidsWater(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the task
|
||||
*/
|
||||
public void resetTask()
|
||||
{
|
||||
this.temptingPlayer = null;
|
||||
this.temptedEntity.getNavigator().clearPathEntity();
|
||||
this.delayTemptCounter = 5; // 100;
|
||||
this.isRunning = false;
|
||||
((PathNavigateGround)this.temptedEntity.getNavigator()).setAvoidsWater(this.avoidWater);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the task
|
||||
*/
|
||||
public void updateTask()
|
||||
{
|
||||
this.temptedEntity.getLookHelper().setLookPositionWithEntity(this.temptingPlayer, 30.0F, (float)this.temptedEntity.getVerticalFaceSpeed());
|
||||
|
||||
if (this.temptedEntity.getDistanceSqToEntity(this.temptingPlayer) < this.distance)
|
||||
{
|
||||
this.temptedEntity.getNavigator().clearPathEntity();
|
||||
}
|
||||
else
|
||||
{
|
||||
this.temptedEntity.getNavigator().tryMoveToEntityLiving(this.temptingPlayer, this.speed);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see #isRunning
|
||||
*/
|
||||
public boolean isRunning()
|
||||
{
|
||||
return this.isRunning;
|
||||
}
|
||||
}
|
94
java/src/game/ai/EntityAIWander.java
Executable file
94
java/src/game/ai/EntityAIWander.java
Executable file
|
@ -0,0 +1,94 @@
|
|||
package game.ai;
|
||||
|
||||
import game.entity.types.EntityLiving;
|
||||
import game.world.Vec3;
|
||||
|
||||
public class EntityAIWander extends EntityAIBase
|
||||
{
|
||||
private EntityLiving entity;
|
||||
private double xPosition;
|
||||
private double yPosition;
|
||||
private double zPosition;
|
||||
private double speed;
|
||||
private int executionChance;
|
||||
// private boolean mustUpdate;
|
||||
|
||||
public EntityAIWander(EntityLiving creatureIn, double speedIn)
|
||||
{
|
||||
this(creatureIn, speedIn, 120);
|
||||
}
|
||||
|
||||
public EntityAIWander(EntityLiving creatureIn, double speedIn, int chance)
|
||||
{
|
||||
this.entity = creatureIn;
|
||||
this.speed = speedIn;
|
||||
this.executionChance = chance;
|
||||
this.setMutexBits(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the EntityAIBase should begin execution.
|
||||
*/
|
||||
public boolean shouldExecute()
|
||||
{
|
||||
// if (!this.mustUpdate)
|
||||
// {
|
||||
// if (this.entity.getAge() >= 100)
|
||||
// {
|
||||
// return false;
|
||||
// }
|
||||
|
||||
if (this.entity.getRNG().zrange(this.executionChance) != 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// }
|
||||
|
||||
Vec3 vec3 = RandomPositionGenerator.findRandomTarget(this.entity, 10, 7);
|
||||
|
||||
if (vec3 == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.xPosition = vec3.xCoord;
|
||||
this.yPosition = vec3.yCoord;
|
||||
this.zPosition = vec3.zCoord;
|
||||
// this.mustUpdate = false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether an in-progress EntityAIBase should continue executing
|
||||
*/
|
||||
public boolean continueExecuting()
|
||||
{
|
||||
return !this.entity.getNavigator().noPath();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a one shot task or start executing a continuous task
|
||||
*/
|
||||
public void startExecuting()
|
||||
{
|
||||
this.entity.getNavigator().tryMoveToXYZ(this.xPosition, this.yPosition, this.zPosition, this.speed);
|
||||
}
|
||||
|
||||
// /**
|
||||
// * Makes task to bypass chance
|
||||
// */
|
||||
// public void makeUpdate()
|
||||
// {
|
||||
// this.mustUpdate = true;
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * Changes task random possibility for execution
|
||||
// */
|
||||
// public void setExecutionChance(int newchance)
|
||||
// {
|
||||
// this.executionChance = newchance;
|
||||
// }
|
||||
}
|
99
java/src/game/ai/EntityAIWatchClosest.java
Executable file
99
java/src/game/ai/EntityAIWatchClosest.java
Executable file
|
@ -0,0 +1,99 @@
|
|||
package game.ai;
|
||||
|
||||
import game.entity.Entity;
|
||||
import game.entity.types.EntityLiving;
|
||||
import game.world.WorldServer;
|
||||
|
||||
public class EntityAIWatchClosest extends EntityAIBase
|
||||
{
|
||||
protected EntityLiving theWatcher;
|
||||
|
||||
/** The closest entity which is being watched by this one. */
|
||||
protected Entity closestEntity;
|
||||
|
||||
/** This is the Maximum distance that the AI will look for the Entity */
|
||||
protected float maxDistanceForPlayer;
|
||||
private int lookTime;
|
||||
private float chance;
|
||||
protected Class <? extends Entity > watchedClass;
|
||||
|
||||
public EntityAIWatchClosest(EntityLiving entitylivingIn, Class <? extends Entity > watchTargetClass, float maxDistance)
|
||||
{
|
||||
this.theWatcher = entitylivingIn;
|
||||
this.watchedClass = watchTargetClass;
|
||||
this.maxDistanceForPlayer = maxDistance;
|
||||
this.chance = 0.02F;
|
||||
this.setMutexBits(2);
|
||||
}
|
||||
|
||||
public EntityAIWatchClosest(EntityLiving entitylivingIn, Class <? extends Entity > watchTargetClass, float maxDistance, float chanceIn)
|
||||
{
|
||||
this.theWatcher = entitylivingIn;
|
||||
this.watchedClass = watchTargetClass;
|
||||
this.maxDistanceForPlayer = maxDistance;
|
||||
this.chance = chanceIn;
|
||||
this.setMutexBits(2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the EntityAIBase should begin execution.
|
||||
*/
|
||||
public boolean shouldExecute()
|
||||
{
|
||||
if (this.theWatcher.getRNG().floatv() >= this.chance)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (this.theWatcher.getAttackTarget() != null)
|
||||
{
|
||||
this.closestEntity = this.theWatcher.getAttackTarget();
|
||||
}
|
||||
|
||||
if (this.watchedClass == null)
|
||||
{
|
||||
this.closestEntity = this.theWatcher.worldObj.getClosestPlayerToEntity(this.theWatcher, (double)this.maxDistanceForPlayer);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.closestEntity = ((WorldServer)this.theWatcher.worldObj).findNearestEntityWithinAABB(this.watchedClass, this.theWatcher.getEntityBoundingBox().expand((double)this.maxDistanceForPlayer, 3.0D, (double)this.maxDistanceForPlayer), this.theWatcher);
|
||||
}
|
||||
|
||||
return this.closestEntity != null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether an in-progress EntityAIBase should continue executing
|
||||
*/
|
||||
public boolean continueExecuting()
|
||||
{
|
||||
return !this.closestEntity.isEntityAlive() ? false : (this.theWatcher.getDistanceSqToEntity(this.closestEntity) > (double)(this.maxDistanceForPlayer * this.maxDistanceForPlayer) ? false : this.lookTime > 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a one shot task or start executing a continuous task
|
||||
*/
|
||||
public void startExecuting()
|
||||
{
|
||||
this.lookTime = 40 + this.theWatcher.getRNG().zrange(40);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the task
|
||||
*/
|
||||
public void resetTask()
|
||||
{
|
||||
this.closestEntity = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the task
|
||||
*/
|
||||
public void updateTask()
|
||||
{
|
||||
this.theWatcher.getLookHelper().setLookPosition(this.closestEntity.posX, this.closestEntity.posY + (double)this.closestEntity.getEyeHeight(), this.closestEntity.posZ, 10.0F, (float)this.theWatcher.getVerticalFaceSpeed());
|
||||
--this.lookTime;
|
||||
}
|
||||
}
|
13
java/src/game/ai/EntityAIWatchClosest2.java
Executable file
13
java/src/game/ai/EntityAIWatchClosest2.java
Executable file
|
@ -0,0 +1,13 @@
|
|||
package game.ai;
|
||||
|
||||
import game.entity.Entity;
|
||||
import game.entity.types.EntityLiving;
|
||||
|
||||
public class EntityAIWatchClosest2 extends EntityAIWatchClosest
|
||||
{
|
||||
public EntityAIWatchClosest2(EntityLiving entitylivingIn, Class <? extends Entity > watchTargetClass, float maxDistance, float chanceIn)
|
||||
{
|
||||
super(entitylivingIn, watchTargetClass, maxDistance, chanceIn);
|
||||
this.setMutexBits(3);
|
||||
}
|
||||
}
|
28
java/src/game/ai/EntityJumpHelper.java
Executable file
28
java/src/game/ai/EntityJumpHelper.java
Executable file
|
@ -0,0 +1,28 @@
|
|||
package game.ai;
|
||||
|
||||
import game.entity.types.EntityLiving;
|
||||
|
||||
public class EntityJumpHelper
|
||||
{
|
||||
private EntityLiving entity;
|
||||
protected boolean isJumping;
|
||||
|
||||
public EntityJumpHelper(EntityLiving entityIn)
|
||||
{
|
||||
this.entity = entityIn;
|
||||
}
|
||||
|
||||
public void setJumping()
|
||||
{
|
||||
this.isJumping = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called to actually make the entity jump if isJumping is true.
|
||||
*/
|
||||
public void doJump()
|
||||
{
|
||||
this.entity.setJumping(this.isJumping);
|
||||
this.isJumping = false;
|
||||
}
|
||||
}
|
143
java/src/game/ai/EntityLookHelper.java
Executable file
143
java/src/game/ai/EntityLookHelper.java
Executable file
|
@ -0,0 +1,143 @@
|
|||
package game.ai;
|
||||
|
||||
import game.ExtMath;
|
||||
import game.entity.Entity;
|
||||
import game.entity.types.EntityLiving;
|
||||
|
||||
public class EntityLookHelper
|
||||
{
|
||||
private EntityLiving entity;
|
||||
|
||||
/**
|
||||
* The amount of change that is made each update for an entity facing a direction.
|
||||
*/
|
||||
private float deltaLookYaw;
|
||||
|
||||
/**
|
||||
* The amount of change that is made each update for an entity facing a direction.
|
||||
*/
|
||||
private float deltaLookPitch;
|
||||
|
||||
/** Whether or not the entity is trying to look at something. */
|
||||
private boolean isLooking;
|
||||
private double posX;
|
||||
private double posY;
|
||||
private double posZ;
|
||||
|
||||
public EntityLookHelper(EntityLiving entitylivingIn)
|
||||
{
|
||||
this.entity = entitylivingIn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets position to look at using entity
|
||||
*/
|
||||
public void setLookPositionWithEntity(Entity entityIn, float deltaYaw, float deltaPitch)
|
||||
{
|
||||
this.posX = entityIn.posX;
|
||||
|
||||
if (entityIn instanceof EntityLiving)
|
||||
{
|
||||
this.posY = entityIn.posY + (double)entityIn.getEyeHeight();
|
||||
}
|
||||
else
|
||||
{
|
||||
this.posY = (entityIn.getEntityBoundingBox().minY + entityIn.getEntityBoundingBox().maxY) / 2.0D;
|
||||
}
|
||||
|
||||
this.posZ = entityIn.posZ;
|
||||
this.deltaLookYaw = deltaYaw;
|
||||
this.deltaLookPitch = deltaPitch;
|
||||
this.isLooking = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets position to look at
|
||||
*/
|
||||
public void setLookPosition(double x, double y, double z, float deltaYaw, float deltaPitch)
|
||||
{
|
||||
this.posX = x;
|
||||
this.posY = y;
|
||||
this.posZ = z;
|
||||
this.deltaLookYaw = deltaYaw;
|
||||
this.deltaLookPitch = deltaPitch;
|
||||
this.isLooking = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates look
|
||||
*/
|
||||
public void onUpdateLook()
|
||||
{
|
||||
this.entity.rotPitch = 0.0F;
|
||||
|
||||
if (this.isLooking)
|
||||
{
|
||||
this.isLooking = false;
|
||||
double d0 = this.posX - this.entity.posX;
|
||||
double d1 = this.posY - (this.entity.posY + (double)this.entity.getEyeHeight());
|
||||
double d2 = this.posZ - this.entity.posZ;
|
||||
double d3 = (double)ExtMath.sqrtd(d0 * d0 + d2 * d2);
|
||||
float f = (float)(ExtMath.atan2(d2, d0) * 180.0D / Math.PI) - 90.0F;
|
||||
float f1 = (float)(-(ExtMath.atan2(d1, d3) * 180.0D / Math.PI));
|
||||
this.entity.rotPitch = this.updateRotation(this.entity.rotPitch, f1, this.deltaLookPitch);
|
||||
this.entity.headYaw = this.updateRotation(this.entity.headYaw, f, this.deltaLookYaw);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.entity.headYaw = this.updateRotation(this.entity.headYaw, this.entity.yawOffset, 10.0F);
|
||||
}
|
||||
|
||||
float f2 = ExtMath.wrapf(this.entity.headYaw - this.entity.yawOffset);
|
||||
|
||||
if (!this.entity.getNavigator().noPath())
|
||||
{
|
||||
if (f2 < -75.0F)
|
||||
{
|
||||
this.entity.headYaw = this.entity.yawOffset - 75.0F;
|
||||
}
|
||||
|
||||
if (f2 > 75.0F)
|
||||
{
|
||||
this.entity.headYaw = this.entity.yawOffset + 75.0F;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private float updateRotation(float p_75652_1_, float p_75652_2_, float p_75652_3_)
|
||||
{
|
||||
float f = ExtMath.wrapf(p_75652_2_ - p_75652_1_);
|
||||
|
||||
if (f > p_75652_3_)
|
||||
{
|
||||
f = p_75652_3_;
|
||||
}
|
||||
|
||||
if (f < -p_75652_3_)
|
||||
{
|
||||
f = -p_75652_3_;
|
||||
}
|
||||
|
||||
return p_75652_1_ + f;
|
||||
}
|
||||
|
||||
public boolean getIsLooking()
|
||||
{
|
||||
return this.isLooking;
|
||||
}
|
||||
|
||||
public double getLookPosX()
|
||||
{
|
||||
return this.posX;
|
||||
}
|
||||
|
||||
public double getLookPosY()
|
||||
{
|
||||
return this.posY;
|
||||
}
|
||||
|
||||
public double getLookPosZ()
|
||||
{
|
||||
return this.posZ;
|
||||
}
|
||||
}
|
121
java/src/game/ai/EntityMoveHelper.java
Executable file
121
java/src/game/ai/EntityMoveHelper.java
Executable file
|
@ -0,0 +1,121 @@
|
|||
package game.ai;
|
||||
|
||||
import game.ExtMath;
|
||||
import game.entity.attributes.Attributes;
|
||||
import game.entity.types.EntityLiving;
|
||||
|
||||
public class EntityMoveHelper
|
||||
{
|
||||
/** The EntityLiving that is being moved */
|
||||
protected EntityLiving entity;
|
||||
protected double posX;
|
||||
protected double posY;
|
||||
protected double posZ;
|
||||
|
||||
/** The speed at which the entity should move */
|
||||
protected double speed;
|
||||
protected boolean update;
|
||||
|
||||
public EntityMoveHelper(EntityLiving entitylivingIn)
|
||||
{
|
||||
this.entity = entitylivingIn;
|
||||
this.posX = entitylivingIn.posX;
|
||||
this.posY = entitylivingIn.posY;
|
||||
this.posZ = entitylivingIn.posZ;
|
||||
}
|
||||
|
||||
public boolean isUpdating()
|
||||
{
|
||||
return this.update;
|
||||
}
|
||||
|
||||
public double getSpeed()
|
||||
{
|
||||
return this.speed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the speed and location to move to
|
||||
*/
|
||||
public void setMoveTo(double x, double y, double z, double speedIn)
|
||||
{
|
||||
this.posX = x;
|
||||
this.posY = y;
|
||||
this.posZ = z;
|
||||
this.speed = speedIn;
|
||||
this.update = true;
|
||||
}
|
||||
|
||||
public void onUpdateMoveHelper()
|
||||
{
|
||||
this.entity.setMoveForward(0.0F);
|
||||
|
||||
if (this.update)
|
||||
{
|
||||
this.update = false;
|
||||
int i = ExtMath.floord(this.entity.getEntityBoundingBox().minY + 0.5D);
|
||||
double d0 = this.posX - this.entity.posX;
|
||||
double d1 = this.posZ - this.entity.posZ;
|
||||
double d2 = this.posY - (double)i;
|
||||
double d3 = d0 * d0 + d2 * d2 + d1 * d1;
|
||||
|
||||
if (d3 >= 2.500000277905201E-7D)
|
||||
{
|
||||
float f = (float)(ExtMath.atan2(d1, d0) * 180.0D / Math.PI) - 90.0F;
|
||||
this.entity.rotYaw = this.limitAngle(this.entity.rotYaw, f, 30.0F);
|
||||
this.entity.setAIMoveSpeed((float)(this.speed * this.entity.getEntityAttribute(Attributes.MOVEMENT_SPEED).getAttributeValue()));
|
||||
|
||||
if (d2 > 0.0D && d0 * d0 + d1 * d1 < 1.0D)
|
||||
{
|
||||
this.entity.getJumpHelper().setJumping();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Limits the given angle to a upper and lower limit.
|
||||
*/
|
||||
protected float limitAngle(float p_75639_1_, float p_75639_2_, float p_75639_3_)
|
||||
{
|
||||
float f = ExtMath.wrapf(p_75639_2_ - p_75639_1_);
|
||||
|
||||
if (f > p_75639_3_)
|
||||
{
|
||||
f = p_75639_3_;
|
||||
}
|
||||
|
||||
if (f < -p_75639_3_)
|
||||
{
|
||||
f = -p_75639_3_;
|
||||
}
|
||||
|
||||
float f1 = p_75639_1_ + f;
|
||||
|
||||
if (f1 < 0.0F)
|
||||
{
|
||||
f1 += 360.0F;
|
||||
}
|
||||
else if (f1 > 360.0F)
|
||||
{
|
||||
f1 -= 360.0F;
|
||||
}
|
||||
|
||||
return f1;
|
||||
}
|
||||
|
||||
public double getX()
|
||||
{
|
||||
return this.posX;
|
||||
}
|
||||
|
||||
public double getY()
|
||||
{
|
||||
return this.posY;
|
||||
}
|
||||
|
||||
public double getZ()
|
||||
{
|
||||
return this.posZ;
|
||||
}
|
||||
}
|
60
java/src/game/ai/EntitySenses.java
Executable file
60
java/src/game/ai/EntitySenses.java
Executable file
|
@ -0,0 +1,60 @@
|
|||
package game.ai;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import game.collect.Lists;
|
||||
import game.entity.Entity;
|
||||
import game.entity.types.EntityLiving;
|
||||
|
||||
public class EntitySenses
|
||||
{
|
||||
EntityLiving entityObj;
|
||||
List<Entity> seenEntities = Lists.<Entity>newArrayList();
|
||||
List<Entity> unseenEntities = Lists.<Entity>newArrayList();
|
||||
|
||||
public EntitySenses(EntityLiving entityObjIn)
|
||||
{
|
||||
this.entityObj = entityObjIn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears canSeeCachePositive and canSeeCacheNegative.
|
||||
*/
|
||||
public void clearSensingCache()
|
||||
{
|
||||
this.seenEntities.clear();
|
||||
this.unseenEntities.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks, whether 'our' entity can see the entity given as argument (true) or not (false), caching the result.
|
||||
*/
|
||||
public boolean canSee(Entity entityIn)
|
||||
{
|
||||
if (this.seenEntities.contains(entityIn))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else if (this.unseenEntities.contains(entityIn))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// this.entityObj.worldObj.profiler.start("canSee");
|
||||
boolean flag = this.entityObj.canEntityBeSeen(entityIn);
|
||||
// this.entityObj.worldObj.profiler.end();
|
||||
|
||||
if (flag)
|
||||
{
|
||||
this.seenEntities.add(entityIn);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.unseenEntities.add(entityIn);
|
||||
}
|
||||
|
||||
return flag;
|
||||
}
|
||||
}
|
||||
}
|
129
java/src/game/ai/RandomPositionGenerator.java
Executable file
129
java/src/game/ai/RandomPositionGenerator.java
Executable file
|
@ -0,0 +1,129 @@
|
|||
package game.ai;
|
||||
|
||||
import game.ExtMath;
|
||||
import game.entity.types.EntityLiving;
|
||||
import game.rng.Random;
|
||||
import game.world.BlockPos;
|
||||
import game.world.Vec3;
|
||||
|
||||
public class RandomPositionGenerator
|
||||
{
|
||||
/**
|
||||
* used to store a driection when the user passes a point to move towards or away from. WARNING: NEVER THREAD SAFE.
|
||||
* MULTIPLE findTowards and findAway calls, will share this var
|
||||
*/
|
||||
private static Vec3 staticVector = new Vec3(0.0D, 0.0D, 0.0D);
|
||||
|
||||
/**
|
||||
* finds a random target within par1(x,z) and par2 (y) blocks
|
||||
*/
|
||||
public static Vec3 findRandomTarget(EntityLiving entitycreatureIn, int xz, int y)
|
||||
{
|
||||
return findRandomTargetBlock(entitycreatureIn, xz, y, (Vec3)null);
|
||||
}
|
||||
|
||||
/**
|
||||
* finds a random target within par1(x,z) and par2 (y) blocks in the direction of the point par3
|
||||
*/
|
||||
public static Vec3 findRandomTargetBlockTowards(EntityLiving entitycreatureIn, int xz, int y, Vec3 targetVec3)
|
||||
{
|
||||
staticVector = targetVec3.subtract(entitycreatureIn.posX, entitycreatureIn.posY, entitycreatureIn.posZ);
|
||||
return findRandomTargetBlock(entitycreatureIn, xz, y, staticVector);
|
||||
}
|
||||
|
||||
/**
|
||||
* finds a random target within par1(x,z) and par2 (y) blocks in the reverse direction of the point par3
|
||||
*/
|
||||
public static Vec3 findRandomTargetBlockAwayFrom(EntityLiving entitycreatureIn, int xz, int y, Vec3 targetVec3)
|
||||
{
|
||||
staticVector = (new Vec3(entitycreatureIn.posX, entitycreatureIn.posY, entitycreatureIn.posZ)).subtract(targetVec3);
|
||||
return findRandomTargetBlock(entitycreatureIn, xz, y, staticVector);
|
||||
}
|
||||
|
||||
/**
|
||||
* searches 10 blocks at random in a within par1(x,z) and par2 (y) distance, ignores those not in the direction of
|
||||
* par3Vec3, then points to the tile for which creature.getBlockPathWeight returns the highest number
|
||||
*/
|
||||
private static Vec3 findRandomTargetBlock(EntityLiving entitycreatureIn, int xz, int y, Vec3 targetVec3)
|
||||
{
|
||||
Random random = entitycreatureIn.getRNG();
|
||||
boolean flag = false;
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
int k = 0;
|
||||
float f = -99999.0F;
|
||||
boolean flag1;
|
||||
|
||||
if (entitycreatureIn.hasHome())
|
||||
{
|
||||
double d0 = entitycreatureIn.getHomePosition().distanceSq((double)ExtMath.floord(entitycreatureIn.posX), (double)ExtMath.floord(entitycreatureIn.posY), (double)ExtMath.floord(entitycreatureIn.posZ)) + 4.0D;
|
||||
double d1 = (double)(entitycreatureIn.getMaximumHomeDistance() + (float)xz);
|
||||
flag1 = d0 < d1 * d1;
|
||||
}
|
||||
else
|
||||
{
|
||||
flag1 = false;
|
||||
}
|
||||
|
||||
for (int j1 = 0; j1 < 10; ++j1)
|
||||
{
|
||||
int l = random.zrange(2 * xz + 1) - xz;
|
||||
int k1 = random.zrange(2 * y + 1) - y;
|
||||
int i1 = random.zrange(2 * xz + 1) - xz;
|
||||
|
||||
if (targetVec3 == null || (double)l * targetVec3.xCoord + (double)i1 * targetVec3.zCoord >= 0.0D)
|
||||
{
|
||||
if (entitycreatureIn.hasHome() && xz > 1)
|
||||
{
|
||||
BlockPos blockpos = entitycreatureIn.getHomePosition();
|
||||
|
||||
if (entitycreatureIn.posX > (double)blockpos.getX())
|
||||
{
|
||||
l -= random.zrange(xz / 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
l += random.zrange(xz / 2);
|
||||
}
|
||||
|
||||
if (entitycreatureIn.posZ > (double)blockpos.getZ())
|
||||
{
|
||||
i1 -= random.zrange(xz / 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
i1 += random.zrange(xz / 2);
|
||||
}
|
||||
}
|
||||
|
||||
l = l + ExtMath.floord(entitycreatureIn.posX);
|
||||
k1 = k1 + ExtMath.floord(entitycreatureIn.posY);
|
||||
i1 = i1 + ExtMath.floord(entitycreatureIn.posZ);
|
||||
BlockPos blockpos1 = new BlockPos(l, k1, i1);
|
||||
|
||||
if (!flag1 || entitycreatureIn.isWithinHomeDistanceFromPosition(blockpos1))
|
||||
{
|
||||
float f1 = entitycreatureIn.getBlockPathWeight(blockpos1);
|
||||
|
||||
if (f1 > f)
|
||||
{
|
||||
f = f1;
|
||||
i = l;
|
||||
j = k1;
|
||||
k = i1;
|
||||
flag = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (flag)
|
||||
{
|
||||
return new Vec3((double)i, (double)j, (double)k);
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue