Added a corrupted chicken, which hits very hard but stealths itself in between attacks.

This commit is contained in:
WayofTime 2016-09-20 17:28:58 -04:00
parent 6f5e96bd52
commit 9538e9aa0d
12 changed files with 672 additions and 2 deletions

View file

@ -0,0 +1,53 @@
package WayofTime.bloodmagic.entity.ai;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.ai.EntityAIAttackMelee;
import net.minecraft.util.EnumHand;
import WayofTime.bloodmagic.entity.mob.EntityCorruptedChicken;
public class EntityAIAttackStealthMelee extends EntityAIAttackMelee
{
protected EntityCorruptedChicken chicken;
public EntityAIAttackStealthMelee(EntityCorruptedChicken creature, double speedIn, boolean useLongMemory)
{
super(creature, speedIn, useLongMemory);
chicken = creature;
}
@Override
public boolean shouldExecute()
{
return chicken.attackStateMachine == 1 && super.shouldExecute();
}
@Override
public boolean continueExecuting()
{
return chicken.attackStateMachine == 1 && super.continueExecuting();
}
@Override
public void resetTask()
{
if (chicken.attackStateMachine == 1)
{
chicken.attackStateMachine = 0;
}
}
@Override
protected void func_190102_a(EntityLivingBase attacked, double distance)
{
double d0 = this.getAttackReachSqr(attacked);
if (distance <= d0 && this.attackTick <= 0)
{
this.attackTick = 20;
this.attacker.swingArm(EnumHand.MAIN_HAND);
this.attacker.attackEntityAsMob(attacked);
chicken.attackStateMachine = 2;
}
}
}

View file

@ -0,0 +1,106 @@
package WayofTime.bloodmagic.entity.ai;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.ai.EntityAIBase;
import net.minecraft.entity.ai.RandomPositionGenerator;
import net.minecraft.pathfinding.Path;
import net.minecraft.pathfinding.PathNavigate;
import net.minecraft.util.math.Vec3d;
import WayofTime.bloodmagic.entity.mob.EntityCorruptedChicken;
public class EntityAIStealthRetreat extends EntityAIBase
{
/** The entity we are attached to */
protected EntityCorruptedChicken entity;
private final double farSpeed;
private final double nearSpeed;
private final float avoidDistance;
/** The PathEntity of our entity */
private Path entityPathEntity;
/** The PathNavigate of our entity */
private final PathNavigate entityPathNavigate;
private int ticksLeft = 0;
public EntityAIStealthRetreat(EntityCorruptedChicken theEntityIn, float avoidDistanceIn, double farSpeedIn, double nearSpeedIn)
{
this.entity = theEntityIn;
this.avoidDistance = avoidDistanceIn;
this.farSpeed = farSpeedIn;
this.nearSpeed = nearSpeedIn;
this.entityPathNavigate = theEntityIn.getNavigator();
this.setMutexBits(1);
}
@Override
public boolean shouldExecute()
{
if (this.entity.attackStateMachine == 2)
{
EntityLivingBase attacked = this.entity.getAttackTarget();
if (attacked == null)
{
return false;
}
Vec3d vec3d = RandomPositionGenerator.findRandomTargetBlockAwayFrom(this.entity, 16, 7, new Vec3d(attacked.posX, attacked.posY, attacked.posZ));
if (vec3d == null)
{
return false;
} else if (attacked.getDistanceSq(vec3d.xCoord, vec3d.yCoord, vec3d.zCoord) < attacked.getDistanceSqToEntity(this.entity))
{
return false;
} else
{
this.entityPathEntity = this.entityPathNavigate.getPathToXYZ(vec3d.xCoord, vec3d.yCoord, vec3d.zCoord);
return this.entityPathEntity != null;
}
}
return false;
}
@Override
public boolean continueExecuting()
{
if (this.entityPathNavigate.noPath())
{
this.entity.attackStateMachine = 0;
return false;
}
return this.entity.attackStateMachine == 2;
}
@Override
public void resetTask()
{
ticksLeft = 0;
}
@Override
public void startExecuting()
{
ticksLeft = this.entity.worldObj.rand.nextInt(100) + 100;
this.entityPathNavigate.setPath(this.entityPathEntity, this.farSpeed);
}
@Override
public void updateTask()
{
ticksLeft--;
if (ticksLeft <= 0)
{
this.entity.attackStateMachine = 0;
}
if (this.entity.getDistanceSqToEntity(this.entity.getAttackTarget()) < 49.0D)
{
this.entity.getNavigator().setSpeed(this.nearSpeed);
} else
{
this.entity.getNavigator().setSpeed(this.farSpeed);
}
}
}

View file

@ -0,0 +1,104 @@
package WayofTime.bloodmagic.entity.ai;
import net.minecraft.entity.EntityCreature;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.ai.EntityAIBase;
import net.minecraft.entity.ai.RandomPositionGenerator;
import net.minecraft.util.math.Vec3d;
import WayofTime.bloodmagic.entity.mob.EntityCorruptedChicken;
public class EntityAIStealthTowardsTarget extends EntityAIBase
{
private final EntityCorruptedChicken entity;
private double xPosition;
private double yPosition;
private double zPosition;
private final double speed;
private int ticksLeft = 0;
public EntityAIStealthTowardsTarget(EntityCorruptedChicken creatureIn, double speedIn)
{
this.entity = creatureIn;
this.speed = speedIn;
this.setMutexBits(1);
}
@Override
public boolean shouldExecute()
{
if (this.entity.attackStateMachine != 0 || this.entity.getAttackTarget() == null)
{
return false;
}
EntityLivingBase target = this.entity.getAttackTarget();
Vec3d vec3d = null;
if (target instanceof EntityCreature)
{
vec3d = RandomPositionGenerator.findRandomTarget((EntityCreature) target, 10, 7);
} else
{
vec3d = RandomPositionGenerator.findRandomTarget(this.entity, 10, 7);
}
if (vec3d == null)
{
return false;
} else
{
ticksLeft = this.entity.worldObj.rand.nextInt(200) + 100;
this.xPosition = vec3d.xCoord;
this.yPosition = vec3d.yCoord;
this.zPosition = vec3d.zCoord;
return true;
}
}
@Override
public void resetTask()
{
ticksLeft = 0;
}
@Override
public boolean continueExecuting()
{
ticksLeft--;
if (ticksLeft <= 0)
{
this.entity.attackStateMachine = 1;
}
this.entity.cloak();
if (this.entity.getNavigator().noPath())
{
EntityLivingBase target = this.entity.getAttackTarget();
Vec3d vec3d = null;
if (target instanceof EntityCreature)
{
vec3d = RandomPositionGenerator.findRandomTarget((EntityCreature) target, 10, 7);
} else
{
vec3d = RandomPositionGenerator.findRandomTarget(this.entity, 10, 7);
}
if (vec3d != null)
{
this.xPosition = vec3d.xCoord;
this.yPosition = vec3d.yCoord;
this.zPosition = vec3d.zCoord;
this.entity.getNavigator().tryMoveToXYZ(this.xPosition, this.yPosition, this.zPosition, this.speed);
}
}
return this.entity.attackStateMachine == 0;
}
@Override
public void startExecuting()
{
this.entity.getNavigator().tryMoveToXYZ(this.xPosition, this.yPosition, this.zPosition, this.speed);
}
}

View file

@ -0,0 +1,229 @@
package WayofTime.bloodmagic.entity.mob;
import net.minecraft.block.Block;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.ai.EntityAIAttackMelee;
import net.minecraft.entity.ai.EntityAILookIdle;
import net.minecraft.entity.ai.EntityAINearestAttackableTarget;
import net.minecraft.entity.ai.EntityAISwimming;
import net.minecraft.entity.ai.EntityAIWander;
import net.minecraft.entity.ai.EntityAIWatchClosest;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.init.Items;
import net.minecraft.init.MobEffects;
import net.minecraft.init.SoundEvents;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.pathfinding.PathNodeType;
import net.minecraft.potion.PotionEffect;
import net.minecraft.util.SoundEvent;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper;
import net.minecraft.world.World;
import WayofTime.bloodmagic.api.soul.EnumDemonWillType;
import WayofTime.bloodmagic.entity.ai.EntityAIAttackStealthMelee;
import WayofTime.bloodmagic.entity.ai.EntityAIStealthRetreat;
import WayofTime.bloodmagic.entity.ai.EntityAIStealthTowardsTarget;
public class EntityCorruptedChicken extends EntityAspectedDemonBase
{
private EntityAIAttackMelee aiAttackOnCollide;
private final int attackPriority = 3;
public float wingRotation;
public float destPos;
public float oFlapSpeed;
public float oFlap;
public float wingRotDelta = 1.0F;
/** The time until the next egg is spawned. */
public int timeUntilNextEgg;
/*
* 0 means the chicken is casting stealth on itself when targeted, running
* to a random location near the target. 1 means the chicken is running
* after the target, attempting to attack it. 2 means it is running away
* from the target for a certain amount of time, before going back into
* state 0.
*/
public int attackStateMachine = 0;
public EntityCorruptedChicken(World world)
{
this(world, EnumDemonWillType.DEFAULT);
}
public EntityCorruptedChicken(World world, EnumDemonWillType type)
{
super(world);
this.setSize(0.4F, 0.7F);
this.timeUntilNextEgg = this.rand.nextInt(600) + 600;
this.setPathPriority(PathNodeType.WATER, 0.0F);
this.setType(type);
}
protected void initEntityAI()
{
this.tasks.addTask(0, new EntityAISwimming(this));
// this.tasks.addTask(1, new EntityAIPanic(this, 1.4D));
this.tasks.addTask(attackPriority, new EntityAIStealthTowardsTarget(this, 1));
this.tasks.addTask(attackPriority, new EntityAIStealthRetreat(this, 6.0F, 1.4D, 1.4D));
this.tasks.addTask(5, new EntityAIWander(this, 1.0D));
this.tasks.addTask(6, new EntityAIWatchClosest(this, EntityPlayer.class, 6.0F));
this.tasks.addTask(7, new EntityAILookIdle(this));
this.targetTasks.addTask(1, new EntityAINearestAttackableTarget<EntityPlayer>(this, EntityPlayer.class, true));
this.targetTasks.addTask(2, new EntityAINearestAttackableTarget<EntityLivingBase>(this, EntityLivingBase.class, 10, true, false, new EntityAspectedDemonBase.TeamAttackPredicate(this)));
}
@Override
public void setCombatTask()
{
if (aiAttackOnCollide != null)
{
this.tasks.removeTask(aiAttackOnCollide);
}
aiAttackOnCollide = new EntityAIAttackStealthMelee(this, this.getBaseSprintModifier(getType()), false);
this.tasks.addTask(attackPriority, aiAttackOnCollide);
}
public void cloak()
{
this.addPotionEffect(new PotionEffect(MobEffects.INVISIBILITY, 50, 0, false, false));
}
@Override
public double getBaseHP(EnumDemonWillType type)
{
return super.getBaseHP(type) * 0.5;
}
@Override
public double getBaseMeleeDamage(EnumDemonWillType type)
{
return super.getBaseMeleeDamage(type) * 2.5;
}
@Override
public double getBaseSpeed(EnumDemonWillType type)
{
return super.getBaseSpeed(type);
}
@Override
public double getBaseSprintModifier(EnumDemonWillType type)
{
return super.getBaseSprintModifier(type);
}
@Override
public double getBaseKnockbackResist(EnumDemonWillType type)
{
return super.getBaseKnockbackResist(type) + 0.2;
}
@Override
public float getEyeHeight()
{
return this.height;
}
@Override
public void onLivingUpdate()
{
super.onLivingUpdate();
// if (!worldObj.isRemote)
// System.out.println("State machine: " + this.attackStateMachine);
this.oFlap = this.wingRotation;
this.oFlapSpeed = this.destPos;
this.destPos = (float) ((double) this.destPos + (double) (this.onGround ? -1 : 4) * 0.3D);
this.destPos = MathHelper.clamp_float(this.destPos, 0.0F, 1.0F);
if (!this.onGround && this.wingRotDelta < 1.0F)
{
this.wingRotDelta = 1.0F;
}
this.wingRotDelta = (float) ((double) this.wingRotDelta * 0.9D);
if (!this.onGround && this.motionY < 0.0D)
{
this.motionY *= 0.6D;
}
this.wingRotation += this.wingRotDelta * 2.0F;
if (!this.worldObj.isRemote && !this.isChild() && --this.timeUntilNextEgg <= 0)
{
this.playSound(SoundEvents.ENTITY_CHICKEN_EGG, 1.0F, (this.rand.nextFloat() - this.rand.nextFloat()) * 0.2F + 1.0F);
this.dropItem(Items.EGG, 1);
this.timeUntilNextEgg = this.rand.nextInt(600) + 600;
}
}
@Override
public void fall(float distance, float damageMultiplier)
{
}
@Override
protected SoundEvent getAmbientSound()
{
return SoundEvents.ENTITY_CHICKEN_AMBIENT;
}
@Override
protected SoundEvent getHurtSound()
{
return SoundEvents.ENTITY_CHICKEN_HURT;
}
@Override
protected SoundEvent getDeathSound()
{
return SoundEvents.ENTITY_CHICKEN_DEATH;
}
@Override
protected void playStepSound(BlockPos pos, Block blockIn)
{
this.playSound(SoundEvents.ENTITY_CHICKEN_STEP, 0.15F, 1.0F);
}
@Override
public void readEntityFromNBT(NBTTagCompound compound)
{
super.readEntityFromNBT(compound);
if (compound.hasKey("EggLayTime"))
{
this.timeUntilNextEgg = compound.getInteger("EggLayTime");
}
}
@Override
public void writeEntityToNBT(NBTTagCompound compound)
{
super.writeEntityToNBT(compound);
compound.setInteger("EggLayTime", this.timeUntilNextEgg);
}
@Override
public void updatePassenger(Entity passenger)
{
super.updatePassenger(passenger);
float f = MathHelper.sin(this.renderYawOffset * 0.017453292F);
float f1 = MathHelper.cos(this.renderYawOffset * 0.017453292F);
float f2 = 0.1F;
float f3 = 0.0F;
passenger.setPosition(this.posX + (double) (0.1F * f), this.posY + (double) (this.height * 0.5F) + passenger.getYOffset() + 0.0D, this.posZ - (double) (0.1F * f1));
if (passenger instanceof EntityLivingBase)
{
((EntityLivingBase) passenger).renderYawOffset = this.renderYawOffset;
}
}
}

View file

@ -152,36 +152,43 @@ public class EntityCorruptedSheep extends EntityAspectedDemonBase implements ISh
return false;
}
@Override
public double getBaseHP(EnumDemonWillType type)
{
return super.getBaseHP(type) * 0.75;
}
@Override
public double getBaseMeleeDamage(EnumDemonWillType type)
{
return super.getBaseMeleeDamage(type) * 0.75;
}
@Override
public double getBaseSpeed(EnumDemonWillType type)
{
return super.getBaseSpeed(type);
}
@Override
public double getBaseSprintModifier(EnumDemonWillType type)
{
return super.getBaseSprintModifier(type);
}
@Override
public double getBaseKnockbackResist(EnumDemonWillType type)
{
return super.getBaseKnockbackResist(type) + 0.2;
}
@Override
public double getMeleeResist()
{
return 0.2;
}
@Override
public double getProjectileResist()
{
return 0.6;
@ -339,7 +346,7 @@ public class EntityCorruptedSheep extends EntityAspectedDemonBase implements ISh
if (this.isChild())
{
//TODO: Heal
this.heal(3);
}
}