2025-03-11 00:23:54 +01:00
|
|
|
package game.entity.npc;
|
|
|
|
|
|
|
|
import java.util.List;
|
2025-03-16 17:40:47 +01:00
|
|
|
import com.google.common.base.Predicate;
|
2025-03-11 00:23:54 +01:00
|
|
|
|
|
|
|
import game.ai.EntityAIMoveThroughVillage;
|
|
|
|
import game.entity.DamageSource;
|
|
|
|
import game.entity.animal.EntityChicken;
|
|
|
|
import game.entity.attributes.AttributeModifier;
|
|
|
|
import game.entity.attributes.Attributes;
|
|
|
|
import game.entity.types.EntityLiving;
|
|
|
|
import game.init.Config;
|
|
|
|
import game.rng.Random;
|
2025-03-11 10:26:48 +01:00
|
|
|
import game.util.ExtMath;
|
2025-03-11 00:23:54 +01:00
|
|
|
import game.world.BlockPos;
|
|
|
|
import game.world.World;
|
|
|
|
import game.world.WorldServer;
|
|
|
|
|
|
|
|
public class EntityZombie extends EntityNPC
|
|
|
|
{
|
|
|
|
public EntityZombie(World worldIn)
|
|
|
|
{
|
|
|
|
super(worldIn);
|
|
|
|
this.tasks.addTask(6, new EntityAIMoveThroughVillage(this, 1.0D, false));
|
|
|
|
}
|
|
|
|
|
|
|
|
protected void applyEntityAttributes()
|
|
|
|
{
|
|
|
|
super.applyEntityAttributes();
|
|
|
|
this.getEntityAttribute(Attributes.FOLLOW_RANGE).setBaseValue(28.0D);
|
|
|
|
this.getEntityAttribute(Attributes.MOVEMENT_SPEED).setBaseValue(0.23000000417232513D);
|
|
|
|
this.getEntityAttribute(Attributes.ATTACK_DAMAGE).setBaseValue(3.0D);
|
|
|
|
this.getAttributeMap().registerAttribute(Attributes.REINFORCEMENT_CHANCE).setBaseValue(this.rand.doublev() * 0.10000000149011612D);
|
|
|
|
}
|
|
|
|
|
|
|
|
public void onLivingUpdate()
|
|
|
|
{
|
|
|
|
if(this.isRiding() && this.getAttackTarget() != null && this.vehicle instanceof EntityChicken)
|
|
|
|
((EntityLiving)this.vehicle).getNavigator().setPath(this.getNavigator().getPath(), 1.5D);
|
|
|
|
if(!this.worldObj.client)
|
|
|
|
this.setAttacking(this.getAttackTarget() != null);
|
|
|
|
super.onLivingUpdate();
|
|
|
|
}
|
|
|
|
|
|
|
|
public boolean attackEntityFrom(DamageSource source, int amount)
|
|
|
|
{
|
|
|
|
if (super.attackEntityFrom(source, amount))
|
|
|
|
{
|
|
|
|
EntityLiving entitylivingbase = this.getAttackTarget();
|
|
|
|
|
|
|
|
if (entitylivingbase == null && source.getEntity() instanceof EntityLiving)
|
|
|
|
{
|
|
|
|
entitylivingbase = (EntityLiving)source.getEntity();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (entitylivingbase != null && /* this.worldObj.getDifficulty() == Difficulty.HARD && */ (double)this.rand.floatv() < this.getEntityAttribute(Attributes.REINFORCEMENT_CHANCE).getAttributeValue() && Config.mobs && Config.spawnMoreZombie)
|
|
|
|
{
|
|
|
|
int i = ExtMath.floord(this.posX);
|
|
|
|
int j = ExtMath.floord(this.posY);
|
|
|
|
int k = ExtMath.floord(this.posZ);
|
|
|
|
EntityZombie entityzombie = new EntityZombie(this.worldObj);
|
|
|
|
|
|
|
|
for (int l = 0; l < 50; ++l)
|
|
|
|
{
|
|
|
|
int i1 = i + this.rand.range(7, 40) * this.rand.range(-1, 1);
|
|
|
|
int j1 = j + this.rand.range(7, 40) * this.rand.range(-1, 1);
|
|
|
|
int k1 = k + this.rand.range(7, 40) * this.rand.range(-1, 1);
|
|
|
|
|
|
|
|
if (this.worldObj.isBlockSolid(new BlockPos(i1, j1 - 1, k1)) && this.worldObj.getLightFromNeighbors(new BlockPos(i1, j1, k1)) < 10)
|
|
|
|
{
|
|
|
|
entityzombie.setPosition((double)i1, (double)j1, (double)k1);
|
|
|
|
|
|
|
|
if (!this.worldObj.isAnyPlayerWithinRangeAt((double)i1, (double)j1, (double)k1, 7.0D) && this.worldObj.checkNoEntityCollision(entityzombie.getEntityBoundingBox(), entityzombie) && this.worldObj.getCollidingBoundingBoxes(entityzombie, entityzombie.getEntityBoundingBox()).isEmpty() && !this.worldObj.isAnyLiquid(entityzombie.getEntityBoundingBox()))
|
|
|
|
{
|
|
|
|
this.worldObj.spawnEntityInWorld(entityzombie);
|
|
|
|
entityzombie.setAttackTarget(entitylivingbase);
|
|
|
|
entityzombie.onInitialSpawn(null);
|
|
|
|
this.getEntityAttribute(Attributes.REINFORCEMENT_CHANCE).applyModifier(new AttributeModifier("Zombie reinforcement caller charge", -0.05000000074505806D, false));
|
|
|
|
entityzombie.getEntityAttribute(Attributes.REINFORCEMENT_CHANCE).applyModifier(new AttributeModifier("Zombie reinforcement callee charge", -0.05000000074505806D, false));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// public boolean attackEntityAsMob(Entity entityIn)
|
|
|
|
// {
|
|
|
|
// boolean flag = super.attackEntityAsMob(entityIn);
|
|
|
|
//
|
|
|
|
// if (flag)
|
|
|
|
// {
|
|
|
|
// int i = this.worldObj.getDifficulty().getId();
|
|
|
|
//
|
|
|
|
// if (this.getHeldItem() == null && this.isBurning() && this.rand.floatv() < (float)i * 0.3F)
|
|
|
|
// {
|
|
|
|
// entityIn.setFire(2 * i);
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// return flag;
|
|
|
|
// }
|
|
|
|
|
|
|
|
// /**
|
|
|
|
// * Returns the sound this mob makes while it's alive.
|
|
|
|
// */
|
|
|
|
// protected String getLivingSound()
|
|
|
|
// {
|
|
|
|
// return "mob.zombie.say";
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// /**
|
|
|
|
// * Returns the sound this mob makes when it is hurt.
|
|
|
|
// */
|
|
|
|
// protected String getHurtSound()
|
|
|
|
// {
|
|
|
|
// return "mob.zombie.hurt";
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// /**
|
|
|
|
// * Returns the sound this mob makes on death.
|
|
|
|
// */
|
|
|
|
// protected String getDeathSound()
|
|
|
|
// {
|
|
|
|
// return "mob.zombie.death";
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// protected void playStepSound(BlockPos pos, Block blockIn)
|
|
|
|
// {
|
|
|
|
// this.playSound("mob.zombie.step", 0.15F, 1.0F);
|
|
|
|
// }
|
|
|
|
|
|
|
|
public void onKillEntity(EntityLiving entityLivingIn)
|
|
|
|
{
|
|
|
|
super.onKillEntity(entityLivingIn);
|
|
|
|
|
|
|
|
if (/* (this.worldObj.getDifficulty() == Difficulty.NORMAL || this.worldObj.getDifficulty() == Difficulty.HARD) && */ entityLivingIn instanceof EntityNPC && !(entityLivingIn.isPlayer()) && Config.convertZombie)
|
|
|
|
{
|
|
|
|
// if (this.worldObj.getDifficulty() != Difficulty.HARD && this.rand.chance())
|
|
|
|
// {
|
|
|
|
// return;
|
|
|
|
// }
|
|
|
|
|
|
|
|
EntityNPC entityliving = (EntityNPC)entityLivingIn;
|
|
|
|
EntityZombie entityzombie = new EntityZombie(this.worldObj);
|
|
|
|
entityzombie.copyLocationAndAnglesFrom(entityLivingIn);
|
|
|
|
this.worldObj.removeEntity(entityLivingIn);
|
|
|
|
entityzombie.onInitialSpawn(null);
|
|
|
|
// entityzombie.setVillager(true);
|
|
|
|
|
|
|
|
// if(entityLivingIn instanceof EntityNPC) {
|
|
|
|
entityzombie.setGrowingAge(entityliving.getGrowingAge());
|
|
|
|
// }
|
|
|
|
// else if (entityLivingIn.isChild()) {
|
|
|
|
// entityzombie.setGrowingAge(-24000);
|
|
|
|
// }
|
|
|
|
|
|
|
|
// entityzombie.setNoAI(entityliving.isAIDisabled());
|
|
|
|
|
|
|
|
if (entityliving.hasCustomName())
|
|
|
|
{
|
|
|
|
entityzombie.setCustomNameTag(entityliving.getCustomNameTag());
|
|
|
|
// entityzombie.setAlwaysRenderNameTag(entityliving.getAlwaysRenderNameTag());
|
|
|
|
}
|
|
|
|
|
|
|
|
this.worldObj.spawnEntityInWorld(entityzombie);
|
|
|
|
this.worldObj.playAuxSFX(1016, new BlockPos((int)this.posX, (int)this.posY, (int)this.posZ), 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// protected boolean canPickUpItem(ItemStack stack)
|
|
|
|
// {
|
|
|
|
// return stack.getItem() == Items.egg && this.isRiding() ? false : super.canPickUpItem(stack);
|
|
|
|
// }
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Called only once on an entity when first time spawned, via egg, mob spawner, natural spawning etc, but not called
|
|
|
|
* when entity is reloaded from nbt. Mainly used for initializing attributes and inventory
|
|
|
|
*/
|
|
|
|
public Object onInitialSpawn(Object livingdata)
|
|
|
|
{
|
|
|
|
livingdata = super.onInitialSpawn(livingdata);
|
|
|
|
// float f = difficulty.getDifficulty();
|
|
|
|
// this.setCanPickUpLoot(this.rand.floatv() < 0.55F * f);
|
|
|
|
|
|
|
|
if (livingdata == null)
|
|
|
|
{
|
|
|
|
livingdata = new EntityZombie.GroupData(this.worldObj.rand.floatv() < 0.05F); //, this.worldObj.rand.floatv() < 0.05F);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (livingdata instanceof EntityZombie.GroupData)
|
|
|
|
{
|
|
|
|
EntityZombie.GroupData entityzombie$groupdata = (EntityZombie.GroupData)livingdata;
|
|
|
|
|
|
|
|
// if (entityzombie$groupdata.isVillager)
|
|
|
|
// {
|
|
|
|
// this.setVillager(true);
|
|
|
|
// }
|
|
|
|
|
|
|
|
if (entityzombie$groupdata.isChild)
|
|
|
|
{
|
|
|
|
this.setGrowingAge(-24000);
|
|
|
|
|
|
|
|
if ((double)this.worldObj.rand.floatv() < 0.05D)
|
|
|
|
{
|
|
|
|
List<EntityChicken> list = this.worldObj.<EntityChicken>getEntitiesWithinAABB(EntityChicken.class, this.getEntityBoundingBox().expand(5.0D, 3.0D, 5.0D), new Predicate<EntityChicken>() {
|
2025-03-16 17:40:47 +01:00
|
|
|
public boolean apply(EntityChicken entity) {
|
2025-03-11 00:23:54 +01:00
|
|
|
return entity.isEntityAlive() && entity.passenger == null && entity.vehicle == null;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
if (!list.isEmpty())
|
|
|
|
{
|
|
|
|
EntityChicken entitychicken = (EntityChicken)list.get(0);
|
|
|
|
entitychicken.setChickenJockey(true);
|
|
|
|
this.mountEntity(entitychicken);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if ((double)this.worldObj.rand.floatv() < 0.05D)
|
|
|
|
{
|
|
|
|
EntityChicken entitychicken1 = new EntityChicken(this.worldObj);
|
|
|
|
entitychicken1.setLocationAndAngles(this.posX, this.posY, this.posZ, this.rotYaw, 0.0F);
|
|
|
|
entitychicken1.onInitialSpawn(null);
|
|
|
|
entitychicken1.setChickenJockey(true);
|
|
|
|
this.worldObj.spawnEntityInWorld(entitychicken1);
|
|
|
|
this.mountEntity(entitychicken1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// this.setBreakDoorsAItask(this.rand.floatv() < f * 0.1F);
|
|
|
|
// this.setEquipmentBasedOnDifficulty(difficulty);
|
|
|
|
// this.setEnchantmentBasedOnDifficulty(difficulty);
|
|
|
|
|
|
|
|
// if (Config.useHalloween && this.getItem(4) == null)
|
|
|
|
// {
|
|
|
|
// Calendar calendar = World.getCurrentDate();
|
|
|
|
//
|
|
|
|
// if (calendar.get(2) + 1 == 10 && calendar.get(5) == 31 && this.rand.floatv() < 0.25F)
|
|
|
|
// {
|
|
|
|
// this.setItem(4, new ItemStack(this.rand.floatv() < 0.1F ? Blocks.lit_pumpkin : Blocks.pumpkin));
|
|
|
|
// this.dropChances[4] = 0.0F;
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
|
|
|
|
this.getEntityAttribute(Attributes.KNOCKBACK_RESISTANCE).applyModifier(new AttributeModifier("Random spawn bonus", this.rand.doublev() * 0.05000000074505806D, false));
|
|
|
|
double d0 = this.rand.doublev() * 15.0;
|
|
|
|
|
|
|
|
if (d0 > 1.0D)
|
|
|
|
{
|
|
|
|
this.getEntityAttribute(Attributes.FOLLOW_RANGE).applyModifier(new AttributeModifier("Random zombie-spawn bonus", d0, false));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (this.rand.chance(30))
|
|
|
|
{
|
|
|
|
this.getEntityAttribute(Attributes.REINFORCEMENT_CHANCE).applyModifier(new AttributeModifier("Leader zombie bonus", this.rand.doublev() * 0.25D + 0.5D, false));
|
|
|
|
this.getEntityAttribute(Attributes.MAX_HEALTH).applyModifier(new AttributeModifier("Leader zombie bonus", this.rand.roll(4), true));
|
|
|
|
// this.setBreakDoorsAItask(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
return livingdata;
|
|
|
|
}
|
|
|
|
|
|
|
|
public int getColor() {
|
|
|
|
return 0xff0000;
|
|
|
|
}
|
|
|
|
|
|
|
|
// public boolean isAggressive() {
|
|
|
|
// return true;
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// public boolean isPeaceful() {
|
|
|
|
// return false;
|
|
|
|
// }
|
|
|
|
|
|
|
|
public boolean isAggressive(Class<? extends EntityNPC> clazz) {
|
|
|
|
return clazz == EntityHuman.class || clazz == EntityElf.class;
|
|
|
|
}
|
|
|
|
|
|
|
|
public boolean isPeaceful(Class<? extends EntityNPC> clazz) {
|
|
|
|
return clazz == EntityCultivator.class;
|
|
|
|
}
|
|
|
|
|
|
|
|
// public boolean canInfight(Alignment align) {
|
|
|
|
// return false;
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// public boolean canMurder(Alignment align) {
|
|
|
|
// return false;
|
|
|
|
// }
|
|
|
|
|
|
|
|
// public boolean canUseMagic() {
|
|
|
|
// return false;
|
|
|
|
// }
|
|
|
|
|
|
|
|
public int getBaseHealth(Random rand) {
|
|
|
|
return rand.range(16, 36);
|
|
|
|
}
|
|
|
|
|
|
|
|
// public int getBaseEnergy(Random rand) {
|
|
|
|
// return 0;
|
|
|
|
// }
|
|
|
|
|
|
|
|
public float getHeightDeviation(Random rand) {
|
|
|
|
return rand.frange(-0.2f, 0.2f);
|
|
|
|
}
|
|
|
|
|
|
|
|
public Alignment getNaturalAlign(Random rand) {
|
|
|
|
return rand.pick(Alignment.CHAOTIC_EVIL, Alignment.EVIL);
|
|
|
|
}
|
|
|
|
|
|
|
|
public boolean getCanSpawnHere() {
|
|
|
|
return !((WorldServer)this.worldObj).isDaytime();
|
|
|
|
}
|
|
|
|
|
|
|
|
// public boolean canAmbush(EntityLiving entity) {
|
|
|
|
// return true;
|
|
|
|
// }
|
|
|
|
|
|
|
|
public boolean arePotionsInverted() {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
public boolean hasArmsRaised() {
|
|
|
|
return this.isAttacking();
|
|
|
|
}
|
|
|
|
|
|
|
|
class GroupData
|
|
|
|
{
|
|
|
|
public boolean isChild;
|
|
|
|
|
|
|
|
private GroupData(boolean isBaby)
|
|
|
|
{
|
|
|
|
this.isChild = isBaby;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|