Updated the hp/damage/etc logic of the corrupted mobs in general, and made it so the sheep will cast resistance on hurt allies when nearby on a cooldown.

Added an alchemy array layer (WIP) for the sheep when it is casting a "spell".
This commit is contained in:
WayofTime 2016-09-18 18:44:18 -04:00
parent cbd2609fe2
commit d6c1d59e5d
11 changed files with 652 additions and 31 deletions

View file

@ -1,5 +1,7 @@
package WayofTime.bloodmagic.entity.mob;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.SharedMonsterAttributes;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.network.datasync.DataParameter;
import net.minecraft.network.datasync.EntityDataManager;
@ -10,6 +12,8 @@ import WayofTime.bloodmagic.api.Constants;
import WayofTime.bloodmagic.api.soul.EnumDemonWillType;
import WayofTime.bloodmagic.gson.Serializers;
import com.google.common.base.Predicate;
public abstract class EntityAspectedDemonBase extends EntityDemonBase
{
protected static final DataParameter<EnumDemonWillType> TYPE = EntityDataManager.<EnumDemonWillType>createKey(EntityAspectedDemonBase.class, Serializers.WILL_TYPE_SERIALIZER);
@ -41,6 +45,128 @@ public abstract class EntityAspectedDemonBase extends EntityDemonBase
return 0;
}
public double getBaseHP(EnumDemonWillType type)
{
double baseHP = 40;
switch (type)
{
case DEFAULT:
break;
case CORROSIVE:
break;
case DESTRUCTIVE:
break;
case VENGEFUL:
baseHP *= 0.8;
break;
case STEADFAST:
baseHP *= 1.25;
break;
}
return baseHP;
}
public double getBaseMeleeDamage(EnumDemonWillType type)
{
double baseDamage = 8;
switch (type)
{
case DEFAULT:
break;
case CORROSIVE:
baseDamage *= 0.8;
break;
case DESTRUCTIVE:
baseDamage *= 1.5;
break;
case VENGEFUL:
baseDamage *= 0.8;
break;
case STEADFAST:
baseDamage *= 0.6;
break;
}
return baseDamage;
}
public double getBaseSpeed(EnumDemonWillType type)
{
double baseSpeed = 0.27;
switch (type)
{
case DEFAULT:
break;
case CORROSIVE:
break;
case DESTRUCTIVE:
break;
case VENGEFUL:
baseSpeed *= 1.3;
break;
case STEADFAST:
break;
}
return baseSpeed;
}
public double getBaseSprintModifier(EnumDemonWillType type)
{
double baseSprint = 1;
switch (type)
{
case DEFAULT:
break;
case CORROSIVE:
break;
case DESTRUCTIVE:
break;
case VENGEFUL:
baseSprint *= 1.2;
break;
case STEADFAST:
break;
}
return baseSprint;
}
public double getBaseKnockbackResist(EnumDemonWillType type)
{
double baseKnockback = 0;
switch (type)
{
case DEFAULT:
break;
case CORROSIVE:
break;
case DESTRUCTIVE:
break;
case VENGEFUL:
break;
case STEADFAST:
baseKnockback += 0.35;
break;
}
return baseKnockback;
}
public void applyEntityAttributes(EnumDemonWillType type)
{
this.getEntityAttribute(SharedMonsterAttributes.MAX_HEALTH).setBaseValue(this.getBaseHP(type));
this.getEntityAttribute(SharedMonsterAttributes.MOVEMENT_SPEED).setBaseValue(this.getBaseSpeed(type));
this.getEntityAttribute(SharedMonsterAttributes.ATTACK_DAMAGE).setBaseValue(this.getBaseMeleeDamage(type));
this.getEntityAttribute(SharedMonsterAttributes.KNOCKBACK_RESISTANCE).setBaseValue(this.getBaseKnockbackResist(type));
}
@Override
public boolean attackEntityFrom(DamageSource source, float amount)
{
@ -75,6 +201,8 @@ public abstract class EntityAspectedDemonBase extends EntityDemonBase
public void setType(EnumDemonWillType type)
{
this.dataManager.set(TYPE, type);
this.applyEntityAttributes(type);
this.setCombatTask();
}
@Override
@ -98,4 +226,55 @@ public abstract class EntityAspectedDemonBase extends EntityDemonBase
setType(EnumDemonWillType.valueOf(tag.getString(Constants.NBT.WILL_TYPE)));
}
}
public class TeamAttackPredicate implements Predicate<EntityLivingBase>
{
private final EntityAspectedDemonBase demon;
public TeamAttackPredicate(EntityAspectedDemonBase demon)
{
this.demon = demon;
}
//Returns true if this mob can attack the inputted mob.
@Override
public boolean apply(EntityLivingBase input)
{
if (input instanceof EntityAspectedDemonBase)
{
if (((EntityAspectedDemonBase) input).getType() == demon.getType())
{
return false;
}
}
return input != null;
}
}
//Returns true if the inputted mob is on the same team.
public static class WillTypePredicate implements Predicate<EntityLivingBase>
{
private final EnumDemonWillType type;
public WillTypePredicate(EnumDemonWillType type)
{
this.type = type;
}
//Returns true if this mob is the same type.
@Override
public boolean apply(EntityLivingBase input)
{
if (input instanceof EntityAspectedDemonBase)
{
if (((EntityAspectedDemonBase) input).getType() == type)
{
return true;
}
}
return false;
}
}
}

View file

@ -6,19 +6,19 @@ import java.util.Random;
import javax.annotation.Nullable;
import lombok.Getter;
import net.minecraft.block.Block;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.IEntityLivingData;
import net.minecraft.entity.SharedMonsterAttributes;
import net.minecraft.entity.ai.EntityAIEatGrass;
import net.minecraft.entity.ai.EntityAIAttackMelee;
import net.minecraft.entity.ai.EntityAILookIdle;
import net.minecraft.entity.ai.EntityAIPanic;
import net.minecraft.entity.ai.EntityAINearestAttackableTarget;
import net.minecraft.entity.ai.EntityAISwimming;
import net.minecraft.entity.ai.EntityAITempt;
import net.minecraft.entity.ai.EntityAIWander;
import net.minecraft.entity.ai.EntityAIWatchClosest;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.init.Blocks;
import net.minecraft.init.Items;
import net.minecraft.init.MobEffects;
import net.minecraft.init.SoundEvents;
import net.minecraft.item.EnumDyeColor;
import net.minecraft.item.Item;
@ -27,7 +27,7 @@ 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.util.EnumHand;
import net.minecraft.potion.PotionEffect;
import net.minecraft.util.SoundEvent;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper;
@ -36,6 +36,9 @@ import net.minecraft.world.World;
import net.minecraftforge.common.IShearable;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import WayofTime.bloodmagic.api.soul.EnumDemonWillType;
import WayofTime.bloodmagic.entity.ai.EntityAIEatAndCorruptBlock;
import WayofTime.bloodmagic.entity.ai.EntityAIProtectAlly;
import com.google.common.collect.Maps;
@ -49,35 +52,69 @@ public class EntityCorruptedSheep extends EntityAspectedDemonBase implements ISh
* handleHealthUpdate and counts down with each tick.
*/
private int sheepTimer;
private EntityAIEatGrass entityAIEatGrass; //TODO: Change to a new AI
@Getter
private int castTimer = 0;
private EntityAIEatAndCorruptBlock entityAIEatGrass;
private EntityAIProtectAlly entityAIProtectAlly;
private EntityAIAttackMelee aiAttackOnCollide;
private final int attackPriority = 3;
public int protectionCooldown = 0;
public static int maxProtectionCooldown = 90 * 20; //90 second cooldown
public static float[] getDyeRgb(EnumDyeColor dyeColor)
{
return (float[]) DYE_TO_RGB.get(dyeColor);
}
public EntityCorruptedSheep(World worldIn)
public EntityCorruptedSheep(World world)
{
super(worldIn);
this(world, EnumDemonWillType.DEFAULT);
}
public EntityCorruptedSheep(World world, EnumDemonWillType type)
{
super(world);
this.setSize(0.9F, 1.3F);
this.setType(type);
}
protected void initEntityAI()
{
this.entityAIEatGrass = new EntityAIEatGrass(this);
this.entityAIEatGrass = new EntityAIEatAndCorruptBlock(this);
this.entityAIProtectAlly = new EntityAIProtectAlly(this);
this.tasks.addTask(0, new EntityAISwimming(this));
this.tasks.addTask(1, new EntityAIPanic(this, 1.25D));
this.tasks.addTask(3, new EntityAITempt(this, 1.1D, Items.WHEAT, false));
this.tasks.addTask(2, entityAIProtectAlly);
this.tasks.addTask(5, this.entityAIEatGrass);
this.tasks.addTask(6, new EntityAIWander(this, 1.0D));
this.tasks.addTask(7, new EntityAIWatchClosest(this, EntityPlayer.class, 6.0F));
this.tasks.addTask(8, 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 EntityAIAttackMelee(this, this.getBaseSprintModifier(getType()), false);
this.tasks.addTask(attackPriority, aiAttackOnCollide);
}
@Override
protected void updateAITasks()
{
this.sheepTimer = this.entityAIEatGrass.getEatingGrassTimer();
this.castTimer = this.entityAIProtectAlly.getCastTimer();
super.updateAITasks();
}
@ -87,18 +124,57 @@ public class EntityCorruptedSheep extends EntityAspectedDemonBase implements ISh
if (this.worldObj.isRemote)
{
this.sheepTimer = Math.max(0, this.sheepTimer - 1);
this.castTimer = Math.max(0, castTimer - 1);
if (this.castTimer == 70)
{
this.playSound(this.getHurtSound(), this.getSoundVolume() * 2, this.getSoundPitch());
}
}
this.protectionCooldown = Math.max(0, this.protectionCooldown - 1);
super.onLivingUpdate();
}
@Override
protected void applyEntityAttributes()
public boolean canProtectAlly(EntityLivingBase entity)
{
super.applyEntityAttributes();
this.getEntityAttribute(SharedMonsterAttributes.MAX_HEALTH).setBaseValue(30);
this.getEntityAttribute(SharedMonsterAttributes.MOVEMENT_SPEED).setBaseValue(0.25);
this.getEntityAttribute(SharedMonsterAttributes.ATTACK_DAMAGE).setBaseValue(6);
return this.protectionCooldown <= 0 && entity.getHealth() < entity.getMaxHealth() && !entity.isPotionActive(MobEffects.RESISTANCE);
}
public boolean applyProtectionToAlly(EntityLivingBase entity)
{
if (canProtectAlly(entity))
{
entity.addPotionEffect(new PotionEffect(MobEffects.RESISTANCE, 20 * 20, 3));
this.protectionCooldown = maxProtectionCooldown;
}
return false;
}
public double getBaseHP(EnumDemonWillType type)
{
return super.getBaseHP(type) * 0.75;
}
public double getBaseMeleeDamage(EnumDemonWillType type)
{
return super.getBaseMeleeDamage(type) * 0.75;
}
public double getBaseSpeed(EnumDemonWillType type)
{
return super.getBaseSpeed(type);
}
public double getBaseSprintModifier(EnumDemonWillType type)
{
return super.getBaseSprintModifier(type);
}
public double getBaseKnockbackResist(EnumDemonWillType type)
{
return super.getBaseKnockbackResist(type) + 0.2;
}
public double getMeleeResist()
@ -125,6 +201,9 @@ public class EntityCorruptedSheep extends EntityAspectedDemonBase implements ISh
if (id == 10)
{
this.sheepTimer = 40;
} else if (id == 53)
{
this.castTimer = 100;
} else
{
super.handleStatusUpdate(id);
@ -151,19 +230,21 @@ public class EntityCorruptedSheep extends EntityAspectedDemonBase implements ISh
}
@Override
public void writeEntityToNBT(NBTTagCompound compound)
public void writeEntityToNBT(NBTTagCompound tag)
{
super.writeEntityToNBT(compound);
compound.setBoolean("Sheared", this.getSheared());
compound.setByte("Color", (byte) this.getFleeceColor().getMetadata());
super.writeEntityToNBT(tag);
tag.setBoolean("Sheared", this.getSheared());
tag.setByte("Color", (byte) this.getFleeceColor().getMetadata());
tag.setInteger("protection", this.protectionCooldown);
}
@Override
public void readEntityFromNBT(NBTTagCompound compound)
public void readEntityFromNBT(NBTTagCompound tag)
{
super.readEntityFromNBT(compound);
this.setSheared(compound.getBoolean("Sheared"));
this.setFleeceColor(EnumDyeColor.byMetadata(compound.getByte("Color")));
super.readEntityFromNBT(tag);
this.setSheared(tag.getBoolean("Sheared"));
this.setFleeceColor(EnumDyeColor.byMetadata(tag.getByte("Color")));
this.protectionCooldown = tag.getInteger("protection");
}
@Override

View file

@ -51,9 +51,9 @@ public class EntityCorruptedZombie extends EntityAspectedDemonBase
this.tasks.addTask(6, new EntityAIMoveThroughVillage(this, 1.0D, false));
this.targetTasks.addTask(1, new EntityAIHurtByTarget(this, true, new Class[] { EntityPigZombie.class }));
this.targetTasks.addTask(2, new EntityAINearestAttackableTarget(this, EntityPlayer.class, true));
this.targetTasks.addTask(3, new EntityAINearestAttackableTarget(this, EntityVillager.class, false));
this.targetTasks.addTask(3, new EntityAINearestAttackableTarget(this, EntityIronGolem.class, true));
this.targetTasks.addTask(2, new EntityAINearestAttackableTarget<EntityPlayer>(this, EntityPlayer.class, true));
this.targetTasks.addTask(3, new EntityAINearestAttackableTarget<EntityVillager>(this, EntityVillager.class, false));
this.targetTasks.addTask(3, new EntityAINearestAttackableTarget<EntityIronGolem>(this, EntityIronGolem.class, true));
this.setCombatTask();
// this.targetTasks.addTask(8, new EntityAINearestAttackableTarget<EntityMob>(this, EntityMob.class, 10, true, false, new TargetPredicate(this)));