Added ownership to the Sentient Specter and improved its AI. Also enabled it to use a bow.
This commit is contained in:
parent
bc37851bd6
commit
38f4ea6bac
|
@ -23,7 +23,7 @@ public class RenderSentientSpecter extends RenderBiped<EntitySentientSpecter>
|
||||||
|
|
||||||
public RenderSentientSpecter(RenderManager renderManager)
|
public RenderSentientSpecter(RenderManager renderManager)
|
||||||
{
|
{
|
||||||
super(renderManager, new ModelBiped(0.0F), 0.5F);
|
super(renderManager, new ModelBiped(0.0F), 0.1F);
|
||||||
this.addLayer(new LayerBipedArmor(this));
|
this.addLayer(new LayerBipedArmor(this));
|
||||||
this.addLayer(new LayerHeldItem(this));
|
this.addLayer(new LayerHeldItem(this));
|
||||||
this.addLayer(new LayerArrow(this));
|
this.addLayer(new LayerArrow(this));
|
||||||
|
|
|
@ -0,0 +1,167 @@
|
||||||
|
package WayofTime.bloodmagic.entity.ai;
|
||||||
|
|
||||||
|
import net.minecraft.entity.EntityLivingBase;
|
||||||
|
import net.minecraft.entity.ai.EntityAIBase;
|
||||||
|
import net.minecraft.item.ItemBow;
|
||||||
|
import net.minecraft.util.EnumHand;
|
||||||
|
import WayofTime.bloodmagic.entity.mob.EntitySentientSpecter;
|
||||||
|
|
||||||
|
public class EntityAIAttackRangedBow extends EntityAIBase
|
||||||
|
{
|
||||||
|
private final EntitySentientSpecter entity;
|
||||||
|
private final double moveSpeedAmp;
|
||||||
|
private int attackCooldown;
|
||||||
|
private final float maxAttackDistance;
|
||||||
|
private int attackTime = -1;
|
||||||
|
private int seeTime;
|
||||||
|
private boolean strafingClockwise;
|
||||||
|
private boolean strafingBackwards;
|
||||||
|
private int strafingTime = -1;
|
||||||
|
|
||||||
|
public EntityAIAttackRangedBow(EntitySentientSpecter specter, double speedAmplifier, int delay, float maxDistance)
|
||||||
|
{
|
||||||
|
this.entity = specter;
|
||||||
|
this.moveSpeedAmp = speedAmplifier;
|
||||||
|
this.attackCooldown = delay;
|
||||||
|
this.maxAttackDistance = maxDistance * maxDistance;
|
||||||
|
this.setMutexBits(3);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAttackCooldown(int p_189428_1_)
|
||||||
|
{
|
||||||
|
this.attackCooldown = p_189428_1_;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether the EntityAIBase should begin execution.
|
||||||
|
*/
|
||||||
|
public boolean shouldExecute()
|
||||||
|
{
|
||||||
|
return this.entity.getAttackTarget() == null ? false : this.isBowInMainhand();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean isBowInMainhand()
|
||||||
|
{
|
||||||
|
return this.entity.getHeldItemMainhand() != null && this.entity.getHeldItemMainhand().getItem() instanceof ItemBow;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether an in-progress EntityAIBase should continue executing
|
||||||
|
*/
|
||||||
|
public boolean continueExecuting()
|
||||||
|
{
|
||||||
|
return (this.shouldExecute() || !this.entity.getNavigator().noPath()) && this.isBowInMainhand();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute a one shot task or start executing a continuous task
|
||||||
|
*/
|
||||||
|
public void startExecuting()
|
||||||
|
{
|
||||||
|
super.startExecuting();
|
||||||
|
// this.entity.setSwingingArms(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resets the task
|
||||||
|
*/
|
||||||
|
public void resetTask()
|
||||||
|
{
|
||||||
|
super.startExecuting();
|
||||||
|
// this.entity.setSwingingArms(false);
|
||||||
|
this.seeTime = 0;
|
||||||
|
this.attackTime = -1;
|
||||||
|
this.entity.resetActiveHand();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the task
|
||||||
|
*/
|
||||||
|
public void updateTask()
|
||||||
|
{
|
||||||
|
EntityLivingBase entitylivingbase = this.entity.getAttackTarget();
|
||||||
|
|
||||||
|
if (entitylivingbase != null)
|
||||||
|
{
|
||||||
|
double d0 = this.entity.getDistanceSq(entitylivingbase.posX, entitylivingbase.getEntityBoundingBox().minY, entitylivingbase.posZ);
|
||||||
|
boolean flag = this.entity.getEntitySenses().canSee(entitylivingbase);
|
||||||
|
boolean flag1 = this.seeTime > 0;
|
||||||
|
|
||||||
|
if (flag != flag1)
|
||||||
|
{
|
||||||
|
this.seeTime = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flag)
|
||||||
|
{
|
||||||
|
++this.seeTime;
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
--this.seeTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (d0 <= (double) this.maxAttackDistance && this.seeTime >= 20)
|
||||||
|
{
|
||||||
|
this.entity.getNavigator().clearPathEntity();
|
||||||
|
++this.strafingTime;
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
this.entity.getNavigator().tryMoveToEntityLiving(entitylivingbase, this.moveSpeedAmp);
|
||||||
|
this.strafingTime = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.strafingTime >= 20)
|
||||||
|
{
|
||||||
|
if ((double) this.entity.getRNG().nextFloat() < 0.3D)
|
||||||
|
{
|
||||||
|
this.strafingClockwise = !this.strafingClockwise;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((double) this.entity.getRNG().nextFloat() < 0.3D)
|
||||||
|
{
|
||||||
|
this.strafingBackwards = !this.strafingBackwards;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.strafingTime = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.strafingTime > -1)
|
||||||
|
{
|
||||||
|
if (d0 > (double) (this.maxAttackDistance * 0.75F))
|
||||||
|
{
|
||||||
|
this.strafingBackwards = false;
|
||||||
|
} else if (d0 < (double) (this.maxAttackDistance * 0.25F))
|
||||||
|
{
|
||||||
|
this.strafingBackwards = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.entity.getMoveHelper().strafe(this.strafingBackwards ? -0.5F : 0.5F, this.strafingClockwise ? 0.5F : -0.5F);
|
||||||
|
this.entity.faceEntity(entitylivingbase, 30.0F, 30.0F);
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
this.entity.getLookHelper().setLookPositionWithEntity(entitylivingbase, 30.0F, 30.0F);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.entity.isHandActive())
|
||||||
|
{
|
||||||
|
if (!flag && this.seeTime < -60)
|
||||||
|
{
|
||||||
|
this.entity.resetActiveHand();
|
||||||
|
} else if (flag)
|
||||||
|
{
|
||||||
|
int i = this.entity.getItemInUseMaxCount();
|
||||||
|
|
||||||
|
if (i >= 20)
|
||||||
|
{
|
||||||
|
this.entity.resetActiveHand();
|
||||||
|
this.entity.attackEntityWithRangedAttack(entitylivingbase, ItemBow.getArrowVelocity(i));
|
||||||
|
this.attackTime = this.attackCooldown;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (--this.attackTime <= 0 && this.seeTime >= -60)
|
||||||
|
{
|
||||||
|
this.entity.setActiveHand(EnumHand.MAIN_HAND);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,147 @@
|
||||||
|
package WayofTime.bloodmagic.entity.ai;
|
||||||
|
|
||||||
|
import net.minecraft.block.Block;
|
||||||
|
import net.minecraft.block.state.IBlockState;
|
||||||
|
import net.minecraft.entity.EntityLivingBase;
|
||||||
|
import net.minecraft.entity.ai.EntityAIBase;
|
||||||
|
import net.minecraft.entity.player.EntityPlayer;
|
||||||
|
import net.minecraft.init.Blocks;
|
||||||
|
import net.minecraft.pathfinding.PathNavigate;
|
||||||
|
import net.minecraft.pathfinding.PathNavigateGround;
|
||||||
|
import net.minecraft.pathfinding.PathNodeType;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import net.minecraft.util.math.MathHelper;
|
||||||
|
import net.minecraft.world.World;
|
||||||
|
import WayofTime.bloodmagic.entity.mob.EntitySentientSpecter;
|
||||||
|
|
||||||
|
public class EntityAIFollowOwner extends EntityAIBase
|
||||||
|
{
|
||||||
|
private EntitySentientSpecter thePet;
|
||||||
|
private EntityLivingBase theOwner;
|
||||||
|
World theWorld;
|
||||||
|
private double followSpeed;
|
||||||
|
private PathNavigate petPathfinder;
|
||||||
|
private int timeToRecalcPath;
|
||||||
|
float maxDist;
|
||||||
|
float minDist;
|
||||||
|
private float oldWaterCost;
|
||||||
|
|
||||||
|
public EntityAIFollowOwner(EntitySentientSpecter 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()
|
||||||
|
{
|
||||||
|
EntityLivingBase entitylivingbase = this.thePet.getOwner();
|
||||||
|
|
||||||
|
if (entitylivingbase == null)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
} else if (entitylivingbase instanceof EntityPlayer && ((EntityPlayer) entitylivingbase).isSpectator())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
} else if (this.thePet.isStationary())
|
||||||
|
{
|
||||||
|
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.isStationary();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute a one shot task or start executing a continuous task
|
||||||
|
*/
|
||||||
|
public void startExecuting()
|
||||||
|
{
|
||||||
|
this.timeToRecalcPath = 0;
|
||||||
|
this.oldWaterCost = this.thePet.getPathPriority(PathNodeType.WATER);
|
||||||
|
this.thePet.setPathPriority(PathNodeType.WATER, 0.0F);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resets the task
|
||||||
|
*/
|
||||||
|
public void resetTask()
|
||||||
|
{
|
||||||
|
this.theOwner = null;
|
||||||
|
this.petPathfinder.clearPathEntity();
|
||||||
|
this.thePet.setPathPriority(PathNodeType.WATER, this.oldWaterCost);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isEmptyBlock(BlockPos pos)
|
||||||
|
{
|
||||||
|
IBlockState iblockstate = this.theWorld.getBlockState(pos);
|
||||||
|
Block block = iblockstate.getBlock();
|
||||||
|
return block == Blocks.AIR ? true : !iblockstate.isFullCube();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the task
|
||||||
|
*/
|
||||||
|
public void updateTask()
|
||||||
|
{
|
||||||
|
this.thePet.getLookHelper().setLookPositionWithEntity(this.theOwner, 10.0F, (float) this.thePet.getVerticalFaceSpeed());
|
||||||
|
|
||||||
|
if (!this.thePet.isStationary())
|
||||||
|
{
|
||||||
|
if (--this.timeToRecalcPath <= 0)
|
||||||
|
{
|
||||||
|
this.timeToRecalcPath = 10;
|
||||||
|
|
||||||
|
if (!this.petPathfinder.tryMoveToEntityLiving(this.theOwner, this.followSpeed))
|
||||||
|
{
|
||||||
|
if (!this.thePet.getLeashed())
|
||||||
|
{
|
||||||
|
if (this.thePet.getDistanceSqToEntity(this.theOwner) >= 144.0D)
|
||||||
|
{
|
||||||
|
int i = MathHelper.floor_double(this.theOwner.posX) - 2;
|
||||||
|
int j = MathHelper.floor_double(this.theOwner.posZ) - 2;
|
||||||
|
int k = MathHelper.floor_double(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.getBlockState(new BlockPos(i + l, k - 1, j + i1)).isFullyOpaque() && this.isEmptyBlock(new BlockPos(i + l, k, j + i1)) && this.isEmptyBlock(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.rotationYaw, this.thePet.rotationPitch);
|
||||||
|
this.petPathfinder.clearPathEntity();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,59 @@
|
||||||
|
package WayofTime.bloodmagic.entity.ai;
|
||||||
|
|
||||||
|
import net.minecraft.entity.EntityLivingBase;
|
||||||
|
import net.minecraft.entity.ai.EntityAITarget;
|
||||||
|
import WayofTime.bloodmagic.entity.mob.EntitySentientSpecter;
|
||||||
|
|
||||||
|
public class EntityAIOwnerHurtByTarget extends EntityAITarget
|
||||||
|
{
|
||||||
|
EntitySentientSpecter theDefendingTameable;
|
||||||
|
EntityLivingBase theOwnerAttacker;
|
||||||
|
private int timestamp;
|
||||||
|
|
||||||
|
public EntityAIOwnerHurtByTarget(EntitySentientSpecter 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
|
||||||
|
{
|
||||||
|
EntityLivingBase owner = this.theDefendingTameable.getOwner();
|
||||||
|
|
||||||
|
if (owner == null)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
this.theOwnerAttacker = owner.getAITarget();
|
||||||
|
int i = owner.getRevengeTimer();
|
||||||
|
return i != this.timestamp && this.isSuitableTarget(this.theOwnerAttacker, false) && this.theDefendingTameable.shouldAttackEntity(this.theOwnerAttacker, owner);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute a one shot task or start executing a continuous task
|
||||||
|
*/
|
||||||
|
public void startExecuting()
|
||||||
|
{
|
||||||
|
this.taskOwner.setAttackTarget(this.theOwnerAttacker);
|
||||||
|
EntityLivingBase owner = this.theDefendingTameable.getOwner();
|
||||||
|
|
||||||
|
if (owner != null)
|
||||||
|
{
|
||||||
|
this.timestamp = owner.getRevengeTimer();
|
||||||
|
}
|
||||||
|
|
||||||
|
super.startExecuting();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,59 @@
|
||||||
|
package WayofTime.bloodmagic.entity.ai;
|
||||||
|
|
||||||
|
import net.minecraft.entity.EntityLivingBase;
|
||||||
|
import net.minecraft.entity.ai.EntityAITarget;
|
||||||
|
import WayofTime.bloodmagic.entity.mob.EntitySentientSpecter;
|
||||||
|
|
||||||
|
public class EntityAIOwnerHurtTarget extends EntityAITarget
|
||||||
|
{
|
||||||
|
EntitySentientSpecter theEntitySentientSpecter;
|
||||||
|
EntityLivingBase theTarget;
|
||||||
|
private int timestamp;
|
||||||
|
|
||||||
|
public EntityAIOwnerHurtTarget(EntitySentientSpecter theEntitySentientSpecterIn)
|
||||||
|
{
|
||||||
|
super(theEntitySentientSpecterIn, false);
|
||||||
|
this.theEntitySentientSpecter = theEntitySentientSpecterIn;
|
||||||
|
this.setMutexBits(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether the EntityAIBase should begin execution.
|
||||||
|
*/
|
||||||
|
public boolean shouldExecute()
|
||||||
|
{
|
||||||
|
if (!this.theEntitySentientSpecter.isTamed())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
EntityLivingBase entitylivingbase = this.theEntitySentientSpecter.getOwner();
|
||||||
|
|
||||||
|
if (entitylivingbase == null)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
this.theTarget = entitylivingbase.getLastAttacker();
|
||||||
|
int i = entitylivingbase.getLastAttackerTime();
|
||||||
|
return i != this.timestamp && this.isSuitableTarget(this.theTarget, false) && this.theEntitySentientSpecter.shouldAttackEntity(this.theTarget, entitylivingbase);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute a one shot task or start executing a continuous task
|
||||||
|
*/
|
||||||
|
public void startExecuting()
|
||||||
|
{
|
||||||
|
this.taskOwner.setAttackTarget(this.theTarget);
|
||||||
|
EntityLivingBase entitylivingbase = this.theEntitySentientSpecter.getOwner();
|
||||||
|
|
||||||
|
if (entitylivingbase != null)
|
||||||
|
{
|
||||||
|
this.timestamp = entitylivingbase.getLastAttackerTime();
|
||||||
|
}
|
||||||
|
|
||||||
|
super.startExecuting();
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,11 @@
|
||||||
package WayofTime.bloodmagic.entity.mob;
|
package WayofTime.bloodmagic.entity.mob;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
import net.minecraft.block.Block;
|
import net.minecraft.block.Block;
|
||||||
|
import net.minecraft.enchantment.EnchantmentHelper;
|
||||||
|
import net.minecraft.entity.EntityLivingBase;
|
||||||
|
import net.minecraft.entity.IEntityOwnable;
|
||||||
import net.minecraft.entity.SharedMonsterAttributes;
|
import net.minecraft.entity.SharedMonsterAttributes;
|
||||||
import net.minecraft.entity.ai.EntityAIAttackMelee;
|
import net.minecraft.entity.ai.EntityAIAttackMelee;
|
||||||
import net.minecraft.entity.ai.EntityAIHurtByTarget;
|
import net.minecraft.entity.ai.EntityAIHurtByTarget;
|
||||||
|
@ -9,39 +14,78 @@ import net.minecraft.entity.ai.EntityAINearestAttackableTarget;
|
||||||
import net.minecraft.entity.ai.EntityAISwimming;
|
import net.minecraft.entity.ai.EntityAISwimming;
|
||||||
import net.minecraft.entity.ai.EntityAIWander;
|
import net.minecraft.entity.ai.EntityAIWander;
|
||||||
import net.minecraft.entity.ai.EntityAIWatchClosest;
|
import net.minecraft.entity.ai.EntityAIWatchClosest;
|
||||||
import net.minecraft.entity.item.EntityBoat;
|
import net.minecraft.entity.monster.EntityCreeper;
|
||||||
|
import net.minecraft.entity.monster.EntityGhast;
|
||||||
import net.minecraft.entity.monster.EntityMob;
|
import net.minecraft.entity.monster.EntityMob;
|
||||||
import net.minecraft.entity.passive.EntityAnimal;
|
import net.minecraft.entity.passive.EntityHorse;
|
||||||
import net.minecraft.entity.passive.EntityVillager;
|
import net.minecraft.entity.passive.EntityTameable;
|
||||||
|
import net.minecraft.entity.passive.EntityWolf;
|
||||||
import net.minecraft.entity.player.EntityPlayer;
|
import net.minecraft.entity.player.EntityPlayer;
|
||||||
|
import net.minecraft.entity.projectile.EntityTippedArrow;
|
||||||
|
import net.minecraft.init.Enchantments;
|
||||||
|
import net.minecraft.init.Items;
|
||||||
|
import net.minecraft.init.MobEffects;
|
||||||
import net.minecraft.init.SoundEvents;
|
import net.minecraft.init.SoundEvents;
|
||||||
import net.minecraft.inventory.EntityEquipmentSlot;
|
import net.minecraft.inventory.EntityEquipmentSlot;
|
||||||
|
import net.minecraft.item.ItemBow;
|
||||||
import net.minecraft.item.ItemStack;
|
import net.minecraft.item.ItemStack;
|
||||||
import net.minecraft.nbt.NBTTagCompound;
|
import net.minecraft.nbt.NBTTagCompound;
|
||||||
import net.minecraft.pathfinding.PathNavigateGround;
|
import net.minecraft.network.datasync.DataParameter;
|
||||||
|
import net.minecraft.network.datasync.DataSerializers;
|
||||||
|
import net.minecraft.network.datasync.EntityDataManager;
|
||||||
|
import net.minecraft.potion.PotionEffect;
|
||||||
|
import net.minecraft.server.management.PreYggdrasilConverter;
|
||||||
|
import net.minecraft.util.EnumHand;
|
||||||
import net.minecraft.util.SoundEvent;
|
import net.minecraft.util.SoundEvent;
|
||||||
import net.minecraft.util.math.BlockPos;
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import net.minecraft.util.math.MathHelper;
|
||||||
|
import net.minecraft.world.EnumDifficulty;
|
||||||
import net.minecraft.world.World;
|
import net.minecraft.world.World;
|
||||||
|
import WayofTime.bloodmagic.entity.ai.EntityAIAttackRangedBow;
|
||||||
|
import WayofTime.bloodmagic.entity.ai.EntityAIFollowOwner;
|
||||||
|
import WayofTime.bloodmagic.entity.ai.EntityAIOwnerHurtByTarget;
|
||||||
|
import WayofTime.bloodmagic.entity.ai.EntityAIOwnerHurtTarget;
|
||||||
|
|
||||||
public class EntitySentientSpecter extends EntityMob
|
import com.google.common.base.Optional;
|
||||||
|
|
||||||
|
public class EntitySentientSpecter extends EntityMob implements IEntityOwnable
|
||||||
{
|
{
|
||||||
|
protected static final DataParameter<Byte> TAMED = EntityDataManager.<Byte>createKey(EntityTameable.class, DataSerializers.BYTE);
|
||||||
|
protected static final DataParameter<Optional<UUID>> OWNER_UNIQUE_ID = EntityDataManager.<Optional<UUID>>createKey(EntityTameable.class, DataSerializers.OPTIONAL_UNIQUE_ID);
|
||||||
|
|
||||||
|
private final EntityAIAttackRangedBow aiArrowAttack = new EntityAIAttackRangedBow(this, 1.0D, 20, 15.0F);
|
||||||
|
private final EntityAIAttackMelee aiAttackOnCollide = new EntityAIAttackMelee(this, 1.0D, false);
|
||||||
|
|
||||||
|
private final int attackPriority = 2;
|
||||||
|
|
||||||
public EntitySentientSpecter(World worldIn)
|
public EntitySentientSpecter(World worldIn)
|
||||||
{
|
{
|
||||||
super(worldIn);
|
super(worldIn);
|
||||||
this.setSize(0.6F, 1.95F);
|
this.setSize(0.6F, 1.95F);
|
||||||
// ((PathNavigateGround) getNavigator()).setCanSwim(false);
|
// ((PathNavigateGround) getNavigator()).setCanSwim(false);
|
||||||
this.tasks.addTask(0, new EntityAISwimming(this));
|
this.tasks.addTask(0, new EntityAISwimming(this));
|
||||||
this.tasks.addTask(2, new EntityAIAttackMelee(this, 1, false));
|
this.tasks.addTask(attackPriority, aiAttackOnCollide);
|
||||||
// this.tasks.addTask(2, new AIAttackOnCollide(this, EntityPlayer.class, 1.0D, false));
|
this.tasks.addTask(3, new EntityAIFollowOwner(this, 1.0D, 10.0F, 2.0F));
|
||||||
// this.tasks.addTask(3, new AIAttackOnCollide(this, EntityVillager.class, 1.0D, true));
|
|
||||||
this.tasks.addTask(5, new EntityAIWander(this, 1.0D));
|
this.tasks.addTask(5, new EntityAIWander(this, 1.0D));
|
||||||
this.tasks.addTask(6, new EntityAIWatchClosest(this, EntityPlayer.class, 6.0F));
|
this.tasks.addTask(6, new EntityAIWatchClosest(this, EntityPlayer.class, 6.0F));
|
||||||
this.tasks.addTask(7, new EntityAILookIdle(this));
|
this.tasks.addTask(7, new EntityAILookIdle(this));
|
||||||
// this.tasks.addTask(8, new AIAttackOnCollide(this, EntityAnimal.class, 1.0D, false));
|
|
||||||
this.targetTasks.addTask(0, new EntityAIHurtByTarget(this, true, new Class[0]));
|
this.targetTasks.addTask(1, new EntityAIOwnerHurtByTarget(this));
|
||||||
this.targetTasks.addTask(2, new EntityAINearestAttackableTarget(this, EntityPlayer.class, true));
|
this.targetTasks.addTask(2, new EntityAIOwnerHurtTarget(this));
|
||||||
this.targetTasks.addTask(2, new EntityAINearestAttackableTarget(this, EntityVillager.class, false));
|
this.targetTasks.addTask(3, new EntityAINearestAttackableTarget<EntityPlayer>(this, EntityPlayer.class, true));
|
||||||
this.targetTasks.addTask(8, new EntityAINearestAttackableTarget(this, EntityAnimal.class, false));
|
|
||||||
|
this.targetTasks.addTask(3, new EntityAIHurtByTarget(this, true, new Class[0]));
|
||||||
|
|
||||||
|
this.setCombatTask();
|
||||||
|
// this.targetTasks.addTask(8, new EntityAINearestAttackableTarget<EntityAnimal>(this, EntityAnimal.class, false));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void entityInit()
|
||||||
|
{
|
||||||
|
super.entityInit();
|
||||||
|
this.dataManager.register(TAMED, Byte.valueOf((byte) 0));
|
||||||
|
this.dataManager.register(OWNER_UNIQUE_ID, Optional.<UUID>absent());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -53,16 +97,184 @@ public class EntitySentientSpecter extends EntityMob
|
||||||
getEntityAttribute(SharedMonsterAttributes.MOVEMENT_SPEED).setBaseValue(0.27D);
|
getEntityAttribute(SharedMonsterAttributes.MOVEMENT_SPEED).setBaseValue(0.27D);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setCombatTask()
|
||||||
|
{
|
||||||
|
if (this.worldObj != null && !this.worldObj.isRemote)
|
||||||
|
{
|
||||||
|
this.tasks.removeTask(this.aiAttackOnCollide);
|
||||||
|
this.tasks.removeTask(this.aiArrowAttack);
|
||||||
|
ItemStack itemstack = this.getHeldItemMainhand();
|
||||||
|
|
||||||
|
if (itemstack != null && itemstack.getItem() instanceof ItemBow)
|
||||||
|
{
|
||||||
|
int i = 20;
|
||||||
|
|
||||||
|
if (this.worldObj.getDifficulty() != EnumDifficulty.HARD)
|
||||||
|
{
|
||||||
|
i = 40;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.aiArrowAttack.setAttackCooldown(i);
|
||||||
|
this.tasks.addTask(attackPriority, this.aiArrowAttack);
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
this.tasks.addTask(attackPriority, this.aiAttackOnCollide);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setItemStackToSlot(EntityEquipmentSlot slotIn, ItemStack stack)
|
||||||
|
{
|
||||||
|
super.setItemStackToSlot(slotIn, stack);
|
||||||
|
|
||||||
|
if (!this.worldObj.isRemote && slotIn == EntityEquipmentSlot.MAINHAND)
|
||||||
|
{
|
||||||
|
this.setCombatTask();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isStationary()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean canDespawn()
|
||||||
|
{
|
||||||
|
//TODO: Change so that it despawns if not tamed after testing.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void writeEntityToNBT(NBTTagCompound tag)
|
public void writeEntityToNBT(NBTTagCompound tag)
|
||||||
{
|
{
|
||||||
super.writeEntityToNBT(tag);
|
super.writeEntityToNBT(tag);
|
||||||
|
|
||||||
|
if (this.getOwnerId() == null)
|
||||||
|
{
|
||||||
|
tag.setString("OwnerUUID", "");
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
tag.setString("OwnerUUID", this.getOwnerId().toString());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void readEntityFromNBT(NBTTagCompound tag)
|
public void readEntityFromNBT(NBTTagCompound tag)
|
||||||
{
|
{
|
||||||
super.readEntityFromNBT(tag);
|
super.readEntityFromNBT(tag);
|
||||||
|
|
||||||
|
String s = "";
|
||||||
|
|
||||||
|
if (tag.hasKey("OwnerUUID", 8))
|
||||||
|
{
|
||||||
|
s = tag.getString("OwnerUUID");
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
String s1 = tag.getString("Owner");
|
||||||
|
s = PreYggdrasilConverter.convertMobOwnerIfNeeded(this.getServer(), s1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!s.isEmpty())
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
this.setOwnerId(UUID.fromString(s));
|
||||||
|
this.setTamed(true);
|
||||||
|
} catch (Throwable var4)
|
||||||
|
{
|
||||||
|
this.setTamed(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setCombatTask();
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO: Change to fit the given AI
|
||||||
|
public boolean shouldAttackEntity(EntityLivingBase attacker, EntityLivingBase owner)
|
||||||
|
{
|
||||||
|
if (!(attacker instanceof EntityCreeper) && !(attacker instanceof EntityGhast))
|
||||||
|
{
|
||||||
|
if (attacker instanceof EntityWolf)
|
||||||
|
{
|
||||||
|
EntityWolf entitywolf = (EntityWolf) attacker;
|
||||||
|
|
||||||
|
if (entitywolf.isTamed() && entitywolf.getOwner() == owner)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return attacker instanceof EntityPlayer && owner instanceof EntityPlayer && !((EntityPlayer) owner).canAttackPlayer((EntityPlayer) attacker) ? false : !(attacker instanceof EntityHorse) || !((EntityHorse) attacker).isTame();
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void attackEntityWithRangedAttack(EntityLivingBase target, float p_82196_2_)
|
||||||
|
{
|
||||||
|
EntityTippedArrow entitytippedarrow = new EntityTippedArrow(this.worldObj, this); //TODO: Change to an arrow created by the Sentient Bow
|
||||||
|
double d0 = target.posX - this.posX;
|
||||||
|
double d1 = target.getEntityBoundingBox().minY + (double) (target.height / 3.0F) - entitytippedarrow.posY;
|
||||||
|
double d2 = target.posZ - this.posZ;
|
||||||
|
double d3 = (double) MathHelper.sqrt_double(d0 * d0 + d2 * d2);
|
||||||
|
entitytippedarrow.setThrowableHeading(d0, d1 + d3 * 0.2, d2, 1.6F, (float) (14 - this.worldObj.getDifficulty().getDifficultyId() * 4));
|
||||||
|
int i = EnchantmentHelper.getMaxEnchantmentLevel(Enchantments.POWER, this);
|
||||||
|
int j = EnchantmentHelper.getMaxEnchantmentLevel(Enchantments.PUNCH, this);
|
||||||
|
entitytippedarrow.setDamage((double) (p_82196_2_ * 2.0F) + this.rand.nextGaussian() * 0.25D + (double) ((float) this.worldObj.getDifficulty().getDifficultyId() * 0.11F));
|
||||||
|
|
||||||
|
if (i > 0)
|
||||||
|
{
|
||||||
|
entitytippedarrow.setDamage(entitytippedarrow.getDamage() + (double) i * 0.5D + 0.5D);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (j > 0)
|
||||||
|
{
|
||||||
|
entitytippedarrow.setKnockbackStrength(j);
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean burning = this.isBurning();
|
||||||
|
burning = burning || EnchantmentHelper.getMaxEnchantmentLevel(Enchantments.FLAME, this) > 0;
|
||||||
|
|
||||||
|
if (burning)
|
||||||
|
{
|
||||||
|
entitytippedarrow.setFire(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
ItemStack itemstack = this.getHeldItem(EnumHand.OFF_HAND);
|
||||||
|
|
||||||
|
if (itemstack != null && itemstack.getItem() == Items.TIPPED_ARROW)
|
||||||
|
{
|
||||||
|
entitytippedarrow.setPotionEffect(itemstack);
|
||||||
|
} else if (true) //TODO: Add potion effects to the arrows
|
||||||
|
{
|
||||||
|
entitytippedarrow.addEffect(new PotionEffect(MobEffects.SLOWNESS, 600));
|
||||||
|
}
|
||||||
|
|
||||||
|
this.playSound(SoundEvents.ENTITY_SKELETON_SHOOT, 1.0F, 1.0F / (this.getRNG().nextFloat() * 0.4F + 0.8F));
|
||||||
|
this.worldObj.spawnEntityInWorld(entitytippedarrow);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isTamed()
|
||||||
|
{
|
||||||
|
return (((Byte) this.dataManager.get(TAMED)).byteValue() & 4) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTamed(boolean tamed)
|
||||||
|
{
|
||||||
|
byte b0 = ((Byte) this.dataManager.get(TAMED)).byteValue();
|
||||||
|
|
||||||
|
if (tamed)
|
||||||
|
{
|
||||||
|
this.dataManager.set(TAMED, Byte.valueOf((byte) (b0 | 4)));
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
this.dataManager.set(TAMED, Byte.valueOf((byte) (b0 & -5)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// this.setupTamedAI();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -97,4 +309,33 @@ public class EntitySentientSpecter extends EntityMob
|
||||||
{
|
{
|
||||||
return 0.4F;
|
return 0.4F;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UUID getOwnerId()
|
||||||
|
{
|
||||||
|
return (UUID) (this.dataManager.get(OWNER_UNIQUE_ID)).orNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOwnerId(UUID uuid)
|
||||||
|
{
|
||||||
|
this.dataManager.set(OWNER_UNIQUE_ID, Optional.fromNullable(uuid));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public EntityLivingBase getOwner()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
UUID uuid = this.getOwnerId();
|
||||||
|
return uuid == null ? null : this.worldObj.getPlayerEntityByUUID(uuid);
|
||||||
|
} catch (IllegalArgumentException var2)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOwner(EntityPlayer player)
|
||||||
|
{
|
||||||
|
setOwnerId(player.getUniqueID());
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -70,7 +70,7 @@ public class ItemSentientSword extends ItemSword implements IDemonWillWeapon, IM
|
||||||
|
|
||||||
public static double[] movementSpeed = new double[] { 0.05, 0.1, 0.15, 0.2, 0.25, 0.3, 0.4 };
|
public static double[] movementSpeed = new double[] { 0.05, 0.1, 0.15, 0.2, 0.25, 0.3, 0.4 };
|
||||||
|
|
||||||
public static final boolean spawnSpecterOnClick = false;
|
public static final boolean spawnSpecterOnClick = true;
|
||||||
|
|
||||||
public ItemSentientSword()
|
public ItemSentientSword()
|
||||||
{
|
{
|
||||||
|
@ -253,7 +253,9 @@ public class ItemSentientSword extends ItemSword implements IDemonWillWeapon, IM
|
||||||
specterEntity.setPosition(player.posX, player.posY, player.posZ);
|
specterEntity.setPosition(player.posX, player.posY, player.posZ);
|
||||||
world.spawnEntityInWorld(specterEntity);
|
world.spawnEntityInWorld(specterEntity);
|
||||||
System.out.println("Spawning Specter...");
|
System.out.println("Spawning Specter...");
|
||||||
specterEntity.setItemStackToSlot(EntityEquipmentSlot.MAINHAND, new ItemStack(ModItems.sentientSword));
|
specterEntity.setItemStackToSlot(EntityEquipmentSlot.MAINHAND, new ItemStack(ModItems.sentientBow));
|
||||||
|
specterEntity.setOwner(player);
|
||||||
|
specterEntity.setTamed(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
return super.onItemRightClick(stack, world, player, hand);
|
return super.onItemRightClick(stack, world, player, hand);
|
||||||
|
|
Loading…
Reference in a new issue