Generalized the demon entity AI logic. Also improved the behaviour of the mimic entities.

This commit is contained in:
WayofTime 2016-08-29 18:56:21 -04:00
parent 043c4cab6a
commit 7d690ad598
11 changed files with 457 additions and 270 deletions

View file

@ -2,6 +2,10 @@
Version 2.0.4-57 Version 2.0.4-57
------------------------------------------------------ ------------------------------------------------------
- Changed the Demon Will Aura Gauge so it refreshes based on the player's ticks existed - Changed the Demon Will Aura Gauge so it refreshes based on the player's ticks existed
- Made Draft of Angelus craftable with gold dust
- Fixed Elytra upgrade
- Added the Mimics - the real ones
- Implemented a bit of framework for some T5 shenanigans.
------------------------------------------------------ ------------------------------------------------------
Version 2.0.4-56 Version 2.0.4-56

View file

@ -4,11 +4,11 @@ import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.ai.EntityAIBase; import net.minecraft.entity.ai.EntityAIBase;
import net.minecraft.item.ItemBow; import net.minecraft.item.ItemBow;
import net.minecraft.util.EnumHand; import net.minecraft.util.EnumHand;
import WayofTime.bloodmagic.entity.mob.EntitySentientSpecter; import WayofTime.bloodmagic.entity.mob.EntityDemonBase;
public class EntityAIAttackRangedBow extends EntityAIBase public class EntityAIAttackRangedBow extends EntityAIBase
{ {
private final EntitySentientSpecter entity; private final EntityDemonBase entity;
private final double moveSpeedAmp; private final double moveSpeedAmp;
private int attackCooldown; private int attackCooldown;
private final float maxAttackDistance; private final float maxAttackDistance;
@ -18,9 +18,9 @@ public class EntityAIAttackRangedBow extends EntityAIBase
private boolean strafingBackwards; private boolean strafingBackwards;
private int strafingTime = -1; private int strafingTime = -1;
public EntityAIAttackRangedBow(EntitySentientSpecter specter, double speedAmplifier, int delay, float maxDistance) public EntityAIAttackRangedBow(EntityDemonBase entityDemonBase, double speedAmplifier, int delay, float maxDistance)
{ {
this.entity = specter; this.entity = entityDemonBase;
this.moveSpeedAmp = speedAmplifier; this.moveSpeedAmp = speedAmplifier;
this.attackCooldown = delay; this.attackCooldown = delay;
this.maxAttackDistance = maxDistance * maxDistance; this.maxAttackDistance = maxDistance * maxDistance;

View file

@ -12,11 +12,11 @@ import net.minecraft.pathfinding.PathNodeType;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.MathHelper;
import net.minecraft.world.World; import net.minecraft.world.World;
import WayofTime.bloodmagic.entity.mob.EntitySentientSpecter; import WayofTime.bloodmagic.entity.mob.EntityDemonBase;
public class EntityAIFollowOwner extends EntityAIBase public class EntityAIFollowOwner extends EntityAIBase
{ {
private EntitySentientSpecter thePet; private EntityDemonBase thePet;
private EntityLivingBase theOwner; private EntityLivingBase theOwner;
World theWorld; World theWorld;
private double followSpeed; private double followSpeed;
@ -26,7 +26,7 @@ public class EntityAIFollowOwner extends EntityAIBase
float minDist; float minDist;
private float oldWaterCost; private float oldWaterCost;
public EntityAIFollowOwner(EntitySentientSpecter thePetIn, double followSpeedIn, float minDistIn, float maxDistIn) public EntityAIFollowOwner(EntityDemonBase thePetIn, double followSpeedIn, float minDistIn, float maxDistIn)
{ {
this.thePet = thePetIn; this.thePet = thePetIn;
this.theWorld = thePetIn.worldObj; this.theWorld = thePetIn.worldObj;

View file

@ -0,0 +1,32 @@
package WayofTime.bloodmagic.entity.ai;
import net.minecraft.entity.ai.EntityAIBase;
import net.minecraft.util.math.BlockPos;
import WayofTime.bloodmagic.entity.mob.EntityMimic;
public class EntityAIMimicReform extends EntityAIBase
{
private final EntityMimic theEntity;
public EntityAIMimicReform(EntityMimic creatureIn)
{
this.theEntity = creatureIn;
this.setMutexBits(2);
}
@Override
public boolean shouldExecute()
{
return this.theEntity.ticksExisted > 100 && this.theEntity.hasHome() && this.theEntity.isWithinHomeDistanceCurrentPosition();
}
@Override
public void startExecuting()
{
BlockPos homePos = this.theEntity.getHomePosition();
if (theEntity.reformIntoMimicBlock(homePos))
{
this.theEntity.setDead();
}
}
}

View file

@ -2,15 +2,15 @@ package WayofTime.bloodmagic.entity.ai;
import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.ai.EntityAITarget; import net.minecraft.entity.ai.EntityAITarget;
import WayofTime.bloodmagic.entity.mob.EntitySentientSpecter; import WayofTime.bloodmagic.entity.mob.EntityDemonBase;
public class EntityAIOwnerHurtByTarget extends EntityAITarget public class EntityAIOwnerHurtByTarget extends EntityAITarget
{ {
EntitySentientSpecter theDefendingTameable; EntityDemonBase theDefendingTameable;
EntityLivingBase theOwnerAttacker; EntityLivingBase theOwnerAttacker;
private int timestamp; private int timestamp;
public EntityAIOwnerHurtByTarget(EntitySentientSpecter theDefendingTameableIn) public EntityAIOwnerHurtByTarget(EntityDemonBase theDefendingTameableIn)
{ {
super(theDefendingTameableIn, false); super(theDefendingTameableIn, false);
this.theDefendingTameable = theDefendingTameableIn; this.theDefendingTameable = theDefendingTameableIn;

View file

@ -2,18 +2,18 @@ package WayofTime.bloodmagic.entity.ai;
import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.ai.EntityAITarget; import net.minecraft.entity.ai.EntityAITarget;
import WayofTime.bloodmagic.entity.mob.EntitySentientSpecter; import WayofTime.bloodmagic.entity.mob.EntityDemonBase;
public class EntityAIOwnerHurtTarget extends EntityAITarget public class EntityAIOwnerHurtTarget extends EntityAITarget
{ {
EntitySentientSpecter theEntitySentientSpecter; EntityDemonBase theEntityDemonBase;
EntityLivingBase theTarget; EntityLivingBase theTarget;
private int timestamp; private int timestamp;
public EntityAIOwnerHurtTarget(EntitySentientSpecter theEntitySentientSpecterIn) public EntityAIOwnerHurtTarget(EntityDemonBase theEntityDemonBaseIn)
{ {
super(theEntitySentientSpecterIn, false); super(theEntityDemonBaseIn, false);
this.theEntitySentientSpecter = theEntitySentientSpecterIn; this.theEntityDemonBase = theEntityDemonBaseIn;
this.setMutexBits(1); this.setMutexBits(1);
} }
@ -22,12 +22,12 @@ public class EntityAIOwnerHurtTarget extends EntityAITarget
*/ */
public boolean shouldExecute() public boolean shouldExecute()
{ {
if (!this.theEntitySentientSpecter.isTamed()) if (!this.theEntityDemonBase.isTamed())
{ {
return false; return false;
} else } else
{ {
EntityLivingBase entitylivingbase = this.theEntitySentientSpecter.getOwner(); EntityLivingBase entitylivingbase = this.theEntityDemonBase.getOwner();
if (entitylivingbase == null) if (entitylivingbase == null)
{ {
@ -36,7 +36,7 @@ public class EntityAIOwnerHurtTarget extends EntityAITarget
{ {
this.theTarget = entitylivingbase.getLastAttacker(); this.theTarget = entitylivingbase.getLastAttacker();
int i = entitylivingbase.getLastAttackerTime(); int i = entitylivingbase.getLastAttackerTime();
return i != this.timestamp && this.isSuitableTarget(this.theTarget, false) && this.theEntitySentientSpecter.shouldAttackEntity(this.theTarget, entitylivingbase); return i != this.timestamp && this.isSuitableTarget(this.theTarget, false) && this.theEntityDemonBase.shouldAttackEntity(this.theTarget, entitylivingbase);
} }
} }
} }
@ -47,7 +47,7 @@ public class EntityAIOwnerHurtTarget extends EntityAITarget
public void startExecuting() public void startExecuting()
{ {
this.taskOwner.setAttackTarget(this.theTarget); this.taskOwner.setAttackTarget(this.theTarget);
EntityLivingBase entitylivingbase = this.theEntitySentientSpecter.getOwner(); EntityLivingBase entitylivingbase = this.theEntityDemonBase.getOwner();
if (entitylivingbase != null) if (entitylivingbase != null)
{ {

View file

@ -11,7 +11,7 @@ import net.minecraft.pathfinding.Path;
import net.minecraft.pathfinding.PathNavigate; import net.minecraft.pathfinding.PathNavigate;
import net.minecraft.util.EntitySelectors; import net.minecraft.util.EntitySelectors;
import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3d;
import WayofTime.bloodmagic.entity.mob.EntitySentientSpecter; import WayofTime.bloodmagic.entity.mob.EntityDemonBase;
import com.google.common.base.Predicate; import com.google.common.base.Predicate;
import com.google.common.base.Predicates; import com.google.common.base.Predicates;
@ -20,7 +20,7 @@ public class EntityAIRetreatToHeal<T extends Entity> extends EntityAIBase
{ {
private final Predicate<Entity> canBeSeenSelector; private final Predicate<Entity> canBeSeenSelector;
/** The entity we are attached to */ /** The entity we are attached to */
protected EntitySentientSpecter theEntity; protected EntityDemonBase theEntity;
private double farSpeed; private double farSpeed;
private double nearSpeed; private double nearSpeed;
private double safeHealDistance = 3; private double safeHealDistance = 3;
@ -33,12 +33,12 @@ public class EntityAIRetreatToHeal<T extends Entity> extends EntityAIBase
private Class<T> classToAvoid; private Class<T> classToAvoid;
private Predicate<? super T> avoidTargetSelector; private Predicate<? super T> avoidTargetSelector;
public EntityAIRetreatToHeal(EntitySentientSpecter theEntityIn, Class<T> classToAvoidIn, float avoidDistanceIn, double farSpeedIn, double nearSpeedIn) public EntityAIRetreatToHeal(EntityDemonBase theEntityIn, Class<T> classToAvoidIn, float avoidDistanceIn, double farSpeedIn, double nearSpeedIn)
{ {
this(theEntityIn, classToAvoidIn, Predicates.<T>alwaysTrue(), avoidDistanceIn, farSpeedIn, nearSpeedIn); this(theEntityIn, classToAvoidIn, Predicates.<T>alwaysTrue(), avoidDistanceIn, farSpeedIn, nearSpeedIn);
} }
public EntityAIRetreatToHeal(EntitySentientSpecter theEntityIn, Class<T> classToAvoidIn, Predicate<? super T> avoidTargetSelectorIn, float avoidDistanceIn, double farSpeedIn, double nearSpeedIn) public EntityAIRetreatToHeal(EntityDemonBase theEntityIn, Class<T> classToAvoidIn, Predicate<? super T> avoidTargetSelectorIn, float avoidDistanceIn, double farSpeedIn, double nearSpeedIn)
{ {
this.canBeSeenSelector = new Predicate<Entity>() this.canBeSeenSelector = new Predicate<Entity>()
{ {
@ -63,7 +63,7 @@ public class EntityAIRetreatToHeal<T extends Entity> extends EntityAIBase
@Override @Override
public boolean shouldExecute() public boolean shouldExecute()
{ {
if (!this.theEntity.shouldSelfHeal()) if (!this.theEntity.shouldEmergencyHeal())
{ {
return false; return false;
} }
@ -99,7 +99,7 @@ public class EntityAIRetreatToHeal<T extends Entity> extends EntityAIBase
@Override @Override
public boolean continueExecuting() public boolean continueExecuting()
{ {
return this.theEntity.shouldSelfHeal();//!this.entityPathNavigate.noPath(); return this.theEntity.shouldEmergencyHeal();//!this.entityPathNavigate.noPath();
} }
/** /**

View file

@ -0,0 +1,361 @@
package WayofTime.bloodmagic.entity.mob;
import java.util.UUID;
import net.minecraft.block.Block;
import net.minecraft.enchantment.EnchantmentHelper;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityCreature;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.IEntityOwnable;
import net.minecraft.entity.SharedMonsterAttributes;
import net.minecraft.entity.monster.EntityCreeper;
import net.minecraft.entity.monster.EntityGhast;
import net.minecraft.entity.monster.EntityMob;
import net.minecraft.entity.passive.EntityHorse;
import net.minecraft.entity.passive.EntityTameable;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.init.Items;
import net.minecraft.init.SoundEvents;
import net.minecraft.inventory.EntityEquipmentSlot;
import net.minecraft.item.ItemAxe;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
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.DamageSource;
import net.minecraft.util.EnumParticleTypes;
import net.minecraft.util.SoundEvent;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper;
import net.minecraft.world.Explosion;
import net.minecraft.world.World;
import net.minecraft.world.WorldServer;
import com.google.common.base.Optional;
import com.google.common.base.Predicate;
public class EntityDemonBase extends EntityCreature 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);
public EntityDemonBase(World worldIn)
{
super(worldIn);
}
@Override
protected void entityInit()
{
super.entityInit();
this.dataManager.register(TAMED, Byte.valueOf((byte) 0));
this.dataManager.register(OWNER_UNIQUE_ID, Optional.<UUID>absent());
}
@Override
protected void applyEntityAttributes()
{
super.applyEntityAttributes();
this.getAttributeMap().registerAttribute(SharedMonsterAttributes.ATTACK_DAMAGE);
}
public void setCombatTask()
{
}
@Override
public boolean isPotionApplicable(PotionEffect effect)
{
return super.isPotionApplicable(effect);
}
@Override
public void onLivingUpdate()
{
this.updateArmSwingProgress();
super.onLivingUpdate();
}
@Override
public boolean attackEntityFrom(DamageSource source, float amount)
{
return this.isEntityInvulnerable(source) ? false : super.attackEntityFrom(source, amount);
}
/**
* Redone from EntityMob to prevent despawning on peaceful.
*/
@Override
public boolean attackEntityAsMob(Entity attackedEntity)
{
float f = (float) this.getEntityAttribute(SharedMonsterAttributes.ATTACK_DAMAGE).getAttributeValue();
int i = 0;
if (attackedEntity instanceof EntityLivingBase)
{
f += EnchantmentHelper.getModifierForCreature(this.getHeldItemMainhand(), ((EntityLivingBase) attackedEntity).getCreatureAttribute());
i += EnchantmentHelper.getKnockbackModifier(this);
}
boolean flag = attackedEntity.attackEntityFrom(DamageSource.causeMobDamage(this), f);
if (flag)
{
if (i > 0 && attackedEntity instanceof EntityLivingBase)
{
((EntityLivingBase) attackedEntity).knockBack(this, (float) i * 0.5F, (double) MathHelper.sin(this.rotationYaw * 0.017453292F), (double) (-MathHelper.cos(this.rotationYaw * 0.017453292F)));
this.motionX *= 0.6D;
this.motionZ *= 0.6D;
}
int j = EnchantmentHelper.getFireAspectModifier(this);
if (j > 0)
{
attackedEntity.setFire(j * 4);
}
if (attackedEntity instanceof EntityPlayer)
{
EntityPlayer entityplayer = (EntityPlayer) attackedEntity;
ItemStack itemstack = this.getHeldItemMainhand();
ItemStack itemstack1 = entityplayer.isHandActive() ? entityplayer.getActiveItemStack() : null;
if (itemstack != null && itemstack1 != null && itemstack.getItem() instanceof ItemAxe && itemstack1.getItem() == Items.SHIELD)
{
float f1 = 0.25F + (float) EnchantmentHelper.getEfficiencyModifier(this) * 0.05F;
if (this.rand.nextFloat() < f1)
{
entityplayer.getCooldownTracker().setCooldown(Items.SHIELD, 100);
this.worldObj.setEntityState(entityplayer, (byte) 30);
}
}
}
this.applyEnchantments(this, attackedEntity);
}
return flag;
}
@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;
}
public boolean absorbExplosion(Explosion explosion)
{
return false;
}
public void performEmergencyHeal(double toHeal)
{
this.heal((float) toHeal);
if (worldObj instanceof WorldServer)
{
WorldServer server = (WorldServer) worldObj;
server.spawnParticle(EnumParticleTypes.HEART, this.posX + (double) (this.rand.nextFloat() * this.width * 2.0F) - (double) this.width, this.posY + 0.5D + (double) (this.rand.nextFloat() * this.height), this.posZ + (double) (this.rand.nextFloat() * this.width * 2.0F) - (double) this.width, 7, 0.2, 0.2, 0.2, 0, new int[0]);
}
}
public boolean shouldEmergencyHeal()
{
return this.getHealth() < this.getMaxHealth() * 0.5;
}
@Override
protected boolean canDespawn()
{
return !this.isTamed() && super.canDespawn();
}
@Override
public void writeEntityToNBT(NBTTagCompound tag)
{
super.writeEntityToNBT(tag);
if (this.getOwnerId() == null)
{
tag.setString("OwnerUUID", "");
} else
{
tag.setString("OwnerUUID", this.getOwnerId().toString());
}
}
@Override
public void readEntityFromNBT(NBTTagCompound 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 IEntityOwnable)
{
IEntityOwnable entityOwnable = (IEntityOwnable) attacker;
if (entityOwnable.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 velocity)
{
}
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
protected SoundEvent getAmbientSound()
{
return SoundEvents.ENTITY_COW_AMBIENT;
}
@Override
protected SoundEvent getHurtSound()
{
return SoundEvents.ENTITY_COW_HURT;
}
@Override
protected SoundEvent getDeathSound()
{
return SoundEvents.ENTITY_COW_DEATH;
}
@Override
protected void playStepSound(BlockPos pos, Block block)
{
this.playSound(SoundEvents.ENTITY_COW_STEP, 0.15F, 1.0F);
}
/**
* Returns the volume for the sounds this mob makes.
*/
@Override
protected float getSoundVolume()
{
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());
}
public class TargetPredicate implements Predicate<EntityMob>
{
EntityDemonBase entity;
public TargetPredicate(EntityDemonBase entity)
{
this.entity = entity;
}
@Override
public boolean apply(EntityMob input)
{
return entity.shouldAttackEntity(input, this.entity.getOwner());
}
}
}

View file

@ -9,12 +9,12 @@ import net.minecraft.entity.ai.EntityAIAttackMelee;
import net.minecraft.entity.ai.EntityAIHurtByTarget; import net.minecraft.entity.ai.EntityAIHurtByTarget;
import net.minecraft.entity.ai.EntityAILeapAtTarget; import net.minecraft.entity.ai.EntityAILeapAtTarget;
import net.minecraft.entity.ai.EntityAILookIdle; import net.minecraft.entity.ai.EntityAILookIdle;
import net.minecraft.entity.ai.EntityAIMoveTowardsRestriction;
import net.minecraft.entity.ai.EntityAINearestAttackableTarget; 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.monster.EntityIronGolem; import net.minecraft.entity.monster.EntityIronGolem;
import net.minecraft.entity.monster.EntityMob;
import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.init.MobEffects; import net.minecraft.init.MobEffects;
import net.minecraft.init.SoundEvents; import net.minecraft.init.SoundEvents;
@ -34,10 +34,11 @@ import net.minecraft.util.math.BlockPos;
import net.minecraft.world.EnumDifficulty; import net.minecraft.world.EnumDifficulty;
import net.minecraft.world.World; import net.minecraft.world.World;
import WayofTime.bloodmagic.block.BlockMimic; import WayofTime.bloodmagic.block.BlockMimic;
import WayofTime.bloodmagic.entity.ai.EntityAIMimicReform;
import WayofTime.bloodmagic.registry.ModBlocks; import WayofTime.bloodmagic.registry.ModBlocks;
import WayofTime.bloodmagic.tile.TileMimic; import WayofTime.bloodmagic.tile.TileMimic;
public class EntityMimic extends EntityMob public class EntityMimic extends EntityDemonBase
{ {
/** /**
* Copy of EntitySpider's AI (should be pretty evident...) * Copy of EntitySpider's AI (should be pretty evident...)
@ -53,16 +54,16 @@ public class EntityMimic extends EntityMob
{ {
super(worldIn); super(worldIn);
this.setSize(0.9F, 0.9F); this.setSize(0.9F, 0.9F);
}
protected void initEntityAI()
{
this.tasks.addTask(1, new EntityAISwimming(this)); this.tasks.addTask(1, new EntityAISwimming(this));
this.tasks.addTask(3, new EntityAILeapAtTarget(this, 0.4F)); this.tasks.addTask(3, new EntityAILeapAtTarget(this, 0.4F));
this.tasks.addTask(4, new EntityMimic.AISpiderAttack(this)); this.tasks.addTask(4, new EntityMimic.AISpiderAttack(this));
this.tasks.addTask(5, new EntityAIWander(this, 0.8D)); this.tasks.addTask(5, new EntityAIMoveTowardsRestriction(this, 1));
this.tasks.addTask(6, new EntityAIWatchClosest(this, EntityPlayer.class, 8.0F)); this.tasks.addTask(6, new EntityAIWander(this, 0.8D));
this.tasks.addTask(6, new EntityAILookIdle(this)); this.tasks.addTask(8, new EntityAIWatchClosest(this, EntityPlayer.class, 8.0F));
this.tasks.addTask(8, new EntityAILookIdle(this));
this.tasks.addTask(7, new EntityAIMimicReform(this));
this.targetTasks.addTask(1, new EntityAIHurtByTarget(this, false, new Class[0])); this.targetTasks.addTask(1, new EntityAIHurtByTarget(this, false, new Class[0]));
this.targetTasks.addTask(2, new EntityMimic.AISpiderTarget(this, EntityPlayer.class)); this.targetTasks.addTask(2, new EntityMimic.AISpiderTarget(this, EntityPlayer.class));
this.targetTasks.addTask(3, new EntityMimic.AISpiderTarget(this, EntityIronGolem.class)); this.targetTasks.addTask(3, new EntityMimic.AISpiderTarget(this, EntityIronGolem.class));
@ -95,7 +96,7 @@ public class EntityMimic extends EntityMob
return this.getItemStackFromSlot(EntityEquipmentSlot.CHEST); return this.getItemStackFromSlot(EntityEquipmentSlot.CHEST);
} }
public void setItemStack(ItemStack stack) public void setMimicItemStack(ItemStack stack)
{ {
this.setItemStackToSlot(EntityEquipmentSlot.CHEST, stack); this.setItemStackToSlot(EntityEquipmentSlot.CHEST, stack);
} }
@ -128,19 +129,18 @@ public class EntityMimic extends EntityMob
return false; return false;
} }
public void initializeMimic(ItemStack heldStack, NBTTagCompound tileTag, boolean dropItemsOnBreak, int metaOfReplacedBlock, int playerCheckRadius) public void initializeMimic(ItemStack heldStack, NBTTagCompound tileTag, boolean dropItemsOnBreak, int metaOfReplacedBlock, int playerCheckRadius, BlockPos homePosition)
{ {
this.setItemStack(heldStack); this.setMimicItemStack(heldStack);
this.tileTag = tileTag; this.tileTag = tileTag;
this.dropItemsOnBreak = dropItemsOnBreak; this.dropItemsOnBreak = dropItemsOnBreak;
this.metaOfReplacedBlock = metaOfReplacedBlock; this.metaOfReplacedBlock = metaOfReplacedBlock;
this.playerCheckRadius = playerCheckRadius; this.playerCheckRadius = playerCheckRadius;
this.setHomePosAndDistance(homePosition, 2); //TODO: Save this.
} }
public void reformIntoMimicBlock() public boolean reformIntoMimicBlock(BlockPos centerPos)
{ {
BlockPos centerPos = this.getPosition();
int horizontalRadius = 1; int horizontalRadius = 1;
int verticalRadius = 1; int verticalRadius = 1;
@ -162,13 +162,15 @@ public class EntityMimic extends EntityMob
BlockPos newPos = centerPos.add(i, j, k); BlockPos newPos = centerPos.add(i, j, k);
if (spawnMimicBlockAtPosition(worldObj, newPos)) if (spawnMimicBlockAtPosition(worldObj, newPos))
{ {
return; return true;
} }
} }
} }
} }
} }
} }
return false;
} }
@Override @Override
@ -246,8 +248,10 @@ public class EntityMimic extends EntityMob
{ {
if (!this.worldObj.isRemote && this.worldObj.getDifficulty() == EnumDifficulty.PEACEFUL) if (!this.worldObj.isRemote && this.worldObj.getDifficulty() == EnumDifficulty.PEACEFUL)
{ {
reformIntoMimicBlock(); if (reformIntoMimicBlock(this.getPosition()))
this.setDead(); {
this.setDead();
}
} }
super.onUpdate(); super.onUpdate();
@ -366,20 +370,13 @@ public class EntityMimic extends EntityMob
/** /**
* Returns whether an in-progress EntityAIBase should continue executing * Returns whether an in-progress EntityAIBase should continue executing
*/ */
@Override
public boolean continueExecuting() public boolean continueExecuting()
{ {
float f = this.attacker.getBrightness(1.0F); return super.continueExecuting();
if (f >= 0.5F && this.attacker.getRNG().nextInt(100) == 0)
{
this.attacker.setAttackTarget((EntityLivingBase) null);
return false;
} else
{
return super.continueExecuting();
}
} }
@Override
protected double getAttackReachSqr(EntityLivingBase attackTarget) protected double getAttackReachSqr(EntityLivingBase attackTarget)
{ {
return (double) (4.0F + attackTarget.width); return (double) (4.0F + attackTarget.width);
@ -398,8 +395,7 @@ public class EntityMimic extends EntityMob
*/ */
public boolean shouldExecute() public boolean shouldExecute()
{ {
float f = this.taskOwner.getBrightness(1.0F); return super.shouldExecute();
return f >= 0.5F ? false : super.shouldExecute();
} }
} }
} }

View file

@ -2,7 +2,6 @@ package WayofTime.bloodmagic.entity.mob;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.UUID;
import javax.annotation.Nullable; import javax.annotation.Nullable;
@ -13,7 +12,6 @@ import net.minecraft.enchantment.EnchantmentHelper;
import net.minecraft.entity.Entity; import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityCreature; import net.minecraft.entity.EntityCreature;
import net.minecraft.entity.EntityLivingBase; 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.EntityAILookIdle; import net.minecraft.entity.ai.EntityAILookIdle;
@ -23,26 +21,17 @@ import net.minecraft.entity.ai.EntityAIWander;
import net.minecraft.entity.ai.EntityAIWatchClosest; import net.minecraft.entity.ai.EntityAIWatchClosest;
import net.minecraft.entity.monster.EntityCreeper; import net.minecraft.entity.monster.EntityCreeper;
import net.minecraft.entity.monster.EntityGhast; import net.minecraft.entity.monster.EntityGhast;
import net.minecraft.entity.monster.EntityMob;
import net.minecraft.entity.passive.EntityHorse;
import net.minecraft.entity.passive.EntityTameable;
import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.projectile.EntityTippedArrow; import net.minecraft.entity.projectile.EntityTippedArrow;
import net.minecraft.init.Enchantments; import net.minecraft.init.Enchantments;
import net.minecraft.init.Items;
import net.minecraft.init.MobEffects; 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.ItemAxe;
import net.minecraft.item.ItemBow; 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.network.datasync.DataParameter;
import net.minecraft.network.datasync.DataSerializers;
import net.minecraft.network.datasync.EntityDataManager;
import net.minecraft.potion.Potion; import net.minecraft.potion.Potion;
import net.minecraft.potion.PotionEffect; import net.minecraft.potion.PotionEffect;
import net.minecraft.server.management.PreYggdrasilConverter;
import net.minecraft.util.DamageSource; import net.minecraft.util.DamageSource;
import net.minecraft.util.EnumHand; import net.minecraft.util.EnumHand;
import net.minecraft.util.EnumParticleTypes; import net.minecraft.util.EnumParticleTypes;
@ -66,14 +55,8 @@ import WayofTime.bloodmagic.entity.ai.EntityAIRetreatToHeal;
import WayofTime.bloodmagic.item.soul.ItemSentientBow; import WayofTime.bloodmagic.item.soul.ItemSentientBow;
import WayofTime.bloodmagic.registry.ModItems; import WayofTime.bloodmagic.registry.ModItems;
import com.google.common.base.Optional; public class EntitySentientSpecter extends EntityDemonBase
import com.google.common.base.Predicate;
public class EntitySentientSpecter extends EntityCreature 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);
@Getter @Getter
@Setter @Setter
protected EnumDemonWillType type = EnumDemonWillType.DESTRUCTIVE; protected EnumDemonWillType type = EnumDemonWillType.DESTRUCTIVE;
@ -111,24 +94,16 @@ public class EntitySentientSpecter extends EntityCreature implements IEntityOwna
// this.targetTasks.addTask(8, new EntityAINearestAttackableTarget<EntityMob>(this, EntityMob.class, 10, true, false, new TargetPredicate(this))); // this.targetTasks.addTask(8, new EntityAINearestAttackableTarget<EntityMob>(this, EntityMob.class, 10, true, false, new TargetPredicate(this)));
} }
@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
protected void applyEntityAttributes() protected void applyEntityAttributes()
{ {
super.applyEntityAttributes(); super.applyEntityAttributes();
this.getAttributeMap().registerAttribute(SharedMonsterAttributes.ATTACK_DAMAGE);
getEntityAttribute(SharedMonsterAttributes.MAX_HEALTH).setBaseValue(40.0D); getEntityAttribute(SharedMonsterAttributes.MAX_HEALTH).setBaseValue(40.0D);
getEntityAttribute(SharedMonsterAttributes.ATTACK_DAMAGE).setBaseValue(6.0D); getEntityAttribute(SharedMonsterAttributes.ATTACK_DAMAGE).setBaseValue(6.0D);
getEntityAttribute(SharedMonsterAttributes.MOVEMENT_SPEED).setBaseValue(0.27D); getEntityAttribute(SharedMonsterAttributes.MOVEMENT_SPEED).setBaseValue(0.27D);
} }
@Override
public void setCombatTask() public void setCombatTask()
{ {
if (this.worldObj != null && !this.worldObj.isRemote) if (this.worldObj != null && !this.worldObj.isRemote)
@ -301,20 +276,6 @@ public class EntitySentientSpecter extends EntityCreature implements IEntityOwna
return arrowEffects; return arrowEffects;
} }
@Override
public void onLivingUpdate()
{
this.updateArmSwingProgress();
float f = this.getBrightness(1.0F);
if (f > 0.5F)
{
this.entityAge += 2;
}
super.onLivingUpdate();
}
@Override @Override
public boolean attackEntityFrom(DamageSource source, float amount) public boolean attackEntityFrom(DamageSource source, float amount)
{ {
@ -327,53 +288,7 @@ public class EntitySentientSpecter extends EntityCreature implements IEntityOwna
@Override @Override
public boolean attackEntityAsMob(Entity attackedEntity) public boolean attackEntityAsMob(Entity attackedEntity)
{ {
float f = (float) this.getEntityAttribute(SharedMonsterAttributes.ATTACK_DAMAGE).getAttributeValue(); boolean flag = super.attackEntityAsMob(attackedEntity);
int i = 0;
if (attackedEntity instanceof EntityLivingBase)
{
f += EnchantmentHelper.getModifierForCreature(this.getHeldItemMainhand(), ((EntityLivingBase) attackedEntity).getCreatureAttribute());
i += EnchantmentHelper.getKnockbackModifier(this);
}
boolean flag = attackedEntity.attackEntityFrom(DamageSource.causeMobDamage(this), f);
if (flag)
{
if (i > 0 && attackedEntity instanceof EntityLivingBase)
{
((EntityLivingBase) attackedEntity).knockBack(this, (float) i * 0.5F, (double) MathHelper.sin(this.rotationYaw * 0.017453292F), (double) (-MathHelper.cos(this.rotationYaw * 0.017453292F)));
this.motionX *= 0.6D;
this.motionZ *= 0.6D;
}
int j = EnchantmentHelper.getFireAspectModifier(this);
if (j > 0)
{
attackedEntity.setFire(j * 4);
}
if (attackedEntity instanceof EntityPlayer)
{
EntityPlayer entityplayer = (EntityPlayer) attackedEntity;
ItemStack itemstack = this.getHeldItemMainhand();
ItemStack itemstack1 = entityplayer.isHandActive() ? entityplayer.getActiveItemStack() : null;
if (itemstack != null && itemstack1 != null && itemstack.getItem() instanceof ItemAxe && itemstack1.getItem() == Items.SHIELD)
{
float f1 = 0.25F + (float) EnchantmentHelper.getEfficiencyModifier(this) * 0.05F;
if (this.rand.nextFloat() < f1)
{
entityplayer.getCooldownTracker().setCooldown(Items.SHIELD, 100);
this.worldObj.setEntityState(entityplayer, (byte) 30);
}
}
}
this.applyEnchantments(this, attackedEntity);
}
if (flag) if (flag)
{ {
@ -390,17 +305,6 @@ public class EntitySentientSpecter extends EntityCreature implements IEntityOwna
} }
} }
@Override
public void setItemStackToSlot(EntityEquipmentSlot slotIn, ItemStack stack)
{
super.setItemStackToSlot(slotIn, stack);
if (!this.worldObj.isRemote && slotIn == EntityEquipmentSlot.MAINHAND)
{
this.setCombatTask();
}
}
@Override @Override
public void onDeath(DamageSource cause) public void onDeath(DamageSource cause)
{ {
@ -412,11 +316,13 @@ public class EntitySentientSpecter extends EntityCreature implements IEntityOwna
} }
} }
@Override
public boolean isStationary() public boolean isStationary()
{ {
return false; return false;
} }
@Override
public boolean absorbExplosion(Explosion explosion) public boolean absorbExplosion(Explosion explosion)
{ {
if (this.type == EnumDemonWillType.DESTRUCTIVE) if (this.type == EnumDemonWillType.DESTRUCTIVE)
@ -468,19 +374,16 @@ public class EntitySentientSpecter extends EntityCreature implements IEntityOwna
return super.isEntityInvulnerable(source) && (this.type == EnumDemonWillType.DESTRUCTIVE && source.isExplosion()); return super.isEntityInvulnerable(source) && (this.type == EnumDemonWillType.DESTRUCTIVE && source.isExplosion());
} }
@Override
public void performEmergencyHeal(double toHeal) public void performEmergencyHeal(double toHeal)
{ {
this.heal((float) toHeal); this.heal((float) toHeal);
// double d0 = this.rand.nextGaussian() * 0.02D;
// double d1 = this.rand.nextGaussian() * 0.02D;
// double d2 = this.rand.nextGaussian() * 0.02D;
if (worldObj instanceof WorldServer) if (worldObj instanceof WorldServer)
{ {
WorldServer server = (WorldServer) worldObj; WorldServer server = (WorldServer) worldObj;
server.spawnParticle(EnumParticleTypes.HEART, this.posX + (double) (this.rand.nextFloat() * this.width * 2.0F) - (double) this.width, this.posY + 0.5D + (double) (this.rand.nextFloat() * this.height), this.posZ + (double) (this.rand.nextFloat() * this.width * 2.0F) - (double) this.width, 7, 0.2, 0.2, 0.2, 0, new int[0]); server.spawnParticle(EnumParticleTypes.HEART, this.posX + (double) (this.rand.nextFloat() * this.width * 2.0F) - (double) this.width, this.posY + 0.5D + (double) (this.rand.nextFloat() * this.height), this.posZ + (double) (this.rand.nextFloat() * this.width * 2.0F) - (double) this.width, 7, 0.2, 0.2, 0.2, 0, new int[0]);
} }
// this.worldObj.spawnParticle(EnumParticleTypes.HEART, this.posX + (double) (this.rand.nextFloat() * this.width * 2.0F) - (double) this.width, this.posY + 0.5D + (double) (this.rand.nextFloat() * this.height), this.posZ + (double) (this.rand.nextFloat() * this.width * 2.0F) - (double) this.width, d0, d1, d2, new int[0]);
} }
/** /**
@ -513,11 +416,6 @@ public class EntitySentientSpecter extends EntityCreature implements IEntityOwna
return 0; return 0;
} }
public boolean shouldSelfHeal()
{
return this.getHealth() < this.getMaxHealth() * 0.5;
}
public double getWillToHealth() public double getWillToHealth()
{ {
return 2; return 2;
@ -544,14 +442,6 @@ public class EntitySentientSpecter extends EntityCreature implements IEntityOwna
{ {
super.writeEntityToNBT(tag); super.writeEntityToNBT(tag);
if (this.getOwnerId() == null)
{
tag.setString("OwnerUUID", "");
} else
{
tag.setString("OwnerUUID", this.getOwnerId().toString());
}
tag.setString(Constants.NBT.WILL_TYPE, type.toString()); tag.setString(Constants.NBT.WILL_TYPE, type.toString());
tag.setBoolean("sentientArmour", wasGivenSentientArmour); tag.setBoolean("sentientArmour", wasGivenSentientArmour);
@ -562,29 +452,6 @@ public class EntitySentientSpecter extends EntityCreature implements IEntityOwna
{ {
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);
}
}
if (!tag.hasKey(Constants.NBT.WILL_TYPE)) if (!tag.hasKey(Constants.NBT.WILL_TYPE))
{ {
type = EnumDemonWillType.DEFAULT; type = EnumDemonWillType.DEFAULT;
@ -599,27 +466,19 @@ public class EntitySentientSpecter extends EntityCreature implements IEntityOwna
} }
//TODO: Change to fit the given AI //TODO: Change to fit the given AI
@Override
public boolean shouldAttackEntity(EntityLivingBase attacker, EntityLivingBase owner) public boolean shouldAttackEntity(EntityLivingBase attacker, EntityLivingBase owner)
{ {
if (!(attacker instanceof EntityCreeper) && !(attacker instanceof EntityGhast)) if (!(attacker instanceof EntityCreeper) && !(attacker instanceof EntityGhast))
{ {
if (attacker instanceof IEntityOwnable) return super.shouldAttackEntity(attacker, owner);
{
IEntityOwnable entityOwnable = (IEntityOwnable) attacker;
if (entityOwnable.getOwner() == owner)
{
return false;
}
}
return attacker instanceof EntityPlayer && owner instanceof EntityPlayer && !((EntityPlayer) owner).canAttackPlayer((EntityPlayer) attacker) ? false : !(attacker instanceof EntityHorse) || !((EntityHorse) attacker).isTame();
} else } else
{ {
return false; return false;
} }
} }
@Override
public void attackEntityWithRangedAttack(EntityLivingBase target, float velocity) public void attackEntityWithRangedAttack(EntityLivingBase target, float velocity)
{ {
ItemStack heldStack = this.getItemStackFromSlot(EntityEquipmentSlot.MAINHAND); ItemStack heldStack = this.getItemStackFromSlot(EntityEquipmentSlot.MAINHAND);
@ -677,26 +536,6 @@ public class EntitySentientSpecter extends EntityCreature implements IEntityOwna
} }
} }
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
protected SoundEvent getAmbientSound() protected SoundEvent getAmbientSound()
{ {
@ -729,49 +568,4 @@ public class EntitySentientSpecter extends EntityCreature implements IEntityOwna
{ {
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());
}
public class TargetPredicate implements Predicate<EntityMob>
{
EntitySentientSpecter entity;
public TargetPredicate(EntitySentientSpecter entity)
{
this.entity = entity;
}
@Override
public boolean apply(EntityMob input)
{
return entity.shouldAttackEntity(input, this.entity.getOwner());
}
}
} }

View file

@ -256,7 +256,7 @@ public class TileMimic extends TileInventory implements ITickable
EntityMimic mimicEntity = new EntityMimic(worldObj); EntityMimic mimicEntity = new EntityMimic(worldObj);
mimicEntity.setPosition(pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5); mimicEntity.setPosition(pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5);
mimicEntity.initializeMimic(getStackInSlot(0), tileTag, dropItemsOnBreak, metaOfReplacedBlock, playerCheckRadius); mimicEntity.initializeMimic(getStackInSlot(0), tileTag, dropItemsOnBreak, metaOfReplacedBlock, playerCheckRadius, pos);
tileTag = null; tileTag = null;
mimicedTile = null; mimicedTile = null;
this.setInventorySlotContents(0, null); this.setInventorySlotContents(0, null);