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:
parent
cbd2609fe2
commit
d6c1d59e5d
11 changed files with 652 additions and 31 deletions
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)));
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue