diff --git a/common/src/common/ai/IEntityNode.java b/common/src/common/ai/IEntityNode.java deleted file mode 100644 index d4d89ee..0000000 --- a/common/src/common/ai/IEntityNode.java +++ /dev/null @@ -1,17 +0,0 @@ -package common.ai; - -import common.entity.DamageSource; -import common.entity.types.EntityLiving; -import common.nbt.NBTTagCompound; - -public interface IEntityNode { - void update(); - void updateRenderAngles(); - void updateLeashedState(); - void setLeashTag(NBTTagCompound tag); - EntityLiving getAttacking(); - EntityLiving getAttackTarget(); - void resetCombat(); - void trackDamage(DamageSource source, int amount); - void sendDeathMessage(); -} diff --git a/common/src/common/entity/Entity.java b/common/src/common/entity/Entity.java index 61d7871..b142d3d 100755 --- a/common/src/common/entity/Entity.java +++ b/common/src/common/entity/Entity.java @@ -2428,6 +2428,14 @@ public abstract class Entity return true; } + /** + * The maximum height from where the entity is alowed to jump (used in pathfinder) + */ + public int getMaxFallHeight() + { + return 3; + } + // public Vec3 getLastPortal() // { // return this.portalVec != null ? this.portalVec : new Vec3(0.0d, 0.0d, 0.0d); diff --git a/common/src/common/entity/animal/EntityHorse.java b/common/src/common/entity/animal/EntityHorse.java index 66cb983..ed9d625 100755 --- a/common/src/common/entity/animal/EntityHorse.java +++ b/common/src/common/entity/animal/EntityHorse.java @@ -258,6 +258,14 @@ public class EntityHorse extends EntityAnimal implements IInvBasic return !this.isUndead() && super.allowLeashing(); } + protected void onUpdateLeashed(float distance) + { + if (distance > 6.0F && this.isEatingHaystack()) + { + this.setEatingHaystack(false); + } + } + public boolean isChested() { return this.getHorseWatchableBoolean(8); diff --git a/common/src/common/entity/npc/EntityArachnoid.java b/common/src/common/entity/npc/EntityArachnoid.java index 0fcd081..becd804 100755 --- a/common/src/common/entity/npc/EntityArachnoid.java +++ b/common/src/common/entity/npc/EntityArachnoid.java @@ -35,6 +35,11 @@ public class EntityArachnoid extends EntityNPC // return 0.9375f * this.height / 1.6f; // } + protected PathNavigate getNewNavigator(World worldIn) + { + return new PathNavigateClimber(this, worldIn); + } + protected void entityInit() { super.entityInit(); diff --git a/common/src/common/entity/npc/EntityHaunter.java b/common/src/common/entity/npc/EntityHaunter.java index ca79e08..4f1e389 100755 --- a/common/src/common/entity/npc/EntityHaunter.java +++ b/common/src/common/entity/npc/EntityHaunter.java @@ -30,6 +30,11 @@ public class EntityHaunter extends EntityNPC { super.applyEntityAttributes(); this.getEntityAttribute(Attributes.MOVEMENT_SPEED).setBaseValue(0.25D); } + + public int getMaxFallHeight() + { + return this.getAttackTarget() == null ? 3 : 3 + (this.getHealth() - 1); + } public void fall(float distance, float damageMultiplier) { diff --git a/common/src/common/entity/npc/EntityNPC.java b/common/src/common/entity/npc/EntityNPC.java index ffd5e7b..f261a8b 100755 --- a/common/src/common/entity/npc/EntityNPC.java +++ b/common/src/common/entity/npc/EntityNPC.java @@ -133,11 +133,47 @@ public abstract class EntityNPC extends EntityLiving // public static String getSpeciesName(String character) { // return (character.substring(0, 1).toUpperCase() + character.substring(1)).replace('_', ' ').replaceAll("( [a-z])", "$1"); // } + + protected final EntityAIAttackOnCollide aiMelee = new EntityAIAttackOnCollide(this, EntityLiving.class, 1.0D, true, true) { + public boolean shouldExecute() + { + return !EntityNPC.this.fleeing && super.shouldExecute(); + } + + public boolean continueExecuting() + { + return !EntityNPC.this.fleeing && super.shouldExecute(); + } + }; + protected final AIRangedAttack aiRanged = new AIRangedAttack(this, 1.0D, this.getAttackSpeed(), this.getAttackSpeed() * 3, 15.0F) { +// public void startExecuting() +// { +// super.startExecuting(); +// EntityNPC.this.setUsingItem(true); +// } +// +// public void resetTask() +// { +// super.resetTask(); +// EntityNPC.this.setUsingItem(false); +// } + + public boolean shouldExecute() + { + return !EntityNPC.this.fleeing && super.shouldExecute(); + } + + public boolean continueExecuting() + { + return !EntityNPC.this.fleeing && super.shouldExecute(); + } + }; protected final SpeciesInfo species; private EntityNPC talkingPlayer; private boolean isWilling; + private boolean fleeing; private boolean playing; protected boolean noPickup; private ItemStack[] equipment = new ItemStack[5]; @@ -219,6 +255,120 @@ public abstract class EntityNPC extends EntityLiving // this.setCharacter(""); if(this.species != null) this.setSize(this.getSpeciesBaseSize() * this.species.renderer.width / this.species.renderer.height, this.getSpeciesBaseSize()); // /* 0.6F, */ 1.8F); + if(this.getNavigator() instanceof PathNavigateGround) { + ((PathNavigateGround)this.getNavigator()).setBreakDoors(true); + ((PathNavigateGround)this.getNavigator()).setAvoidsWater(true); + } + this.tasks.addTask(0, new EntityAISwimming(this)); +// this.tasks.addTask(1, new EntityAIAttackOnCollide(this, EntityNPC.class, 0.6D, true, true)); +// this.tasks.addTask(1, new EntityAIAttackOnCollide(this, EntityLivingBase.class, 0.6D, true, true)); + this.tasks.addTask(1, new EntityAINpcMate(this)); + this.tasks.addTask(2, new EntityAIAvoidEntity(this, EntityLiving.class, new Predicate() { + public boolean test(EntityLiving entity) { + return entity != EntityNPC.this && EntityNPC.this.shouldFlee(entity); + } + }, 8.0F, 1.1D, 1.1D) { + { + this.setMutexBits(0); + } + + public void startExecuting() { + EntityNPC.this.setAttackTarget(null); + EntityNPC.this.fleeing = true; + } + + public boolean continueExecuting() { + return false; + } + + public void updateTask() + { + } + +// public void resetTask() { +// super.resetTask(); +// EntityNPC.this.isFleeing = false; +// } + }); + this.tasks.addTask(3, new EntityAIAvoidEntity(this, EntityLiving.class, new Predicate() { + public boolean test(EntityLiving entity) { + return entity != EntityNPC.this && EntityNPC.this.shouldFlee(entity); + } + }, 8.0F, 1.1D, 1.1D) { + public void startExecuting() { + super.startExecuting(); + EntityNPC.this.setAttackTarget(null); + EntityNPC.this.fleeing = true; + } + + public void resetTask() { + super.resetTask(); + EntityNPC.this.fleeing = false; + } + }); +// this.tasks.addTask(2, new EntityAITempt(this, 1.0D, Items.golden_apple, false)); + this.tasks.addTask(4, new EntityAIOpenDoor(this, true)); + this.tasks.addTask(5, new EntityAINagPlayer(this)); + this.tasks.addTask(5, new EntityAILookAtTalkingPlayer(this)); + this.tasks.addTask(6, new EntityAIWatchClosest2(this, null, 3.0F, 1.0F) { + private int sneakTime; + + public void updateTask() + { + super.updateTask(); + boolean flag = this.closestEntity.isPlayer() && this.closestEntity.isSneaking(); + if(this.sneakTime > 0) { + if(--this.sneakTime == 0) { + EntityNPC.this.setSneaking(false); + } + } + else if(EntityNPC.this.getAttackTarget() == null && EntityNPC.this.rand.chance(flag ? 5 : 200)) { + EntityNPC.this.setSneaking(true); + this.sneakTime = EntityNPC.this.rand.range(60, flag ? 160 : 120); + } + else if(EntityNPC.this.getAttackTarget() != null) { + EntityNPC.this.setSneaking(false); + this.sneakTime = 0; + } + } + + public void resetTask() + { + super.resetTask(); + EntityNPC.this.setSneaking(false); + } + }); + this.tasks.addTask(7, new EntityAINpcInteract(this)); + this.tasks.addTask(8, new EntityAIWander(this, 1.0D)); + this.tasks.addTask(8, new EntityAIPlay(this, 1.1D)); + this.tasks.addTask(9, new EntityAIWatchClosest(this, EntityLiving.class, 8.0F)); + this.targets.addTask(1, new EntityAIHurtByTarget(this, false, /* EntityNPC.class, */ EntityLiving.class) { + protected boolean isSuitableTarget(EntityLiving entity) { + if(entity != null && entity != EntityNPC.this && EntityNPC.this.shouldFlee(entity)) { + EntityNPC.this.setAttackTarget(null); + EntityNPC.this.fleeing = true; + return false; + } + return entity != null && entity != EntityNPC.this && (!(entity.isPlayer()) || EntityNPC.this.rand.chance(entity.getAttackedBy() == EntityNPC.this ? 2 : 4)) + && EntityNPC.this.canCounter(entity) && super.isSuitableTarget(entity); + } + }); + this.targets.addTask(2, new EntityAINearestAttackableTarget(this, EntityLiving.class, 10, true, false, new Predicate() { + public boolean test(EntityLiving entity) { + if(entity != null && entity != EntityNPC.this && EntityNPC.this.shouldFlee(entity)) { + EntityNPC.this.setAttackTarget(null); + EntityNPC.this.fleeing = true; + return false; + } + return entity != null && entity != EntityNPC.this && !EntityNPC.this.fleeing && EntityNPC.this.canAmbush(entity) && EntityNPC.this.canAttack(entity); + } + })); +// this.setCanPickUpLoot(true); + + if (worldIn != null && !worldIn.client) + { + this.setCombatTask(); + } } @@ -507,7 +657,7 @@ public abstract class EntityNPC extends EntityLiving } else if (!flag && !this.isPlayer() && this.isEntityAlive() && !this.isTalking()) { - if (!this.worldObj.client && this.canTrade() && this.node.getAttackTarget() == null) + if (!this.worldObj.client && this.canTrade() && this.getAttackTarget() == null) { this.setTalking(player); player.connection.displayTradeGui(this); @@ -1018,6 +1168,10 @@ public abstract class EntityNPC extends EntityLiving return this.playing; } + public boolean isFleeing() { + return this.fleeing; + } + // public boolean canPlay() { // return ; // } @@ -1878,8 +2032,7 @@ public abstract class EntityNPC extends EntityLiving { // float f1 = this.getHealth(); this.setHealth(this.getHealth() - damageAmount); - if(this.node != null) - this.node.trackDamage(damageSrc, damageAmount); + this.trackDamage(damageSrc, damageAmount); // if ((float)damageAmount < 3.4028235E37F) // { @@ -2682,7 +2835,7 @@ public abstract class EntityNPC extends EntityLiving else { this.setItemNoUpdate(slot, stack); if(!this.worldObj.client && slot == 0) - this.node.setCombatTask(); + this.setCombatTask(); } } @@ -3290,7 +3443,7 @@ public abstract class EntityNPC extends EntityLiving this.skin = tagCompund.getByteArray("Skin"); // this.setCanPickUpLoot(true); - this.node.setCombatTask(); + this.setCombatTask(); if(this.isPlayer()) { // this.entityUniqueID = getOfflineUUID(this.user); @@ -4308,6 +4461,16 @@ public abstract class EntityNPC extends EntityLiving { return !this.isPlayer() && super.interactFirst(playerIn); } + + public int getMaxFallHeight() + { + return this.isPlayer() ? 3 : super.getMaxFallHeight(); + } + + protected void updateLeashedState() { + if(!this.isPlayer()) + super.updateLeashedState(); + } public void setLeashedTo(Entity entity, boolean pkt) { if(!this.isPlayer()) @@ -4323,15 +4486,14 @@ public abstract class EntityNPC extends EntityLiving super.clearLeashed(pkt, dropLead); } - protected void updateDistance(float p_110146_1_, float p_110146_2_) + protected float updateDistance(float p_110146_1_, float p_110146_2_) { - if(!this.isPlayer()) { - super.updateDistance(p_110146_1_, p_110146_2_); - return; - } + if(!this.isPlayer()) + return super.updateDistance(p_110146_1_, p_110146_2_); float f = ExtMath.wrapf(p_110146_1_ - this.yawOffset); this.yawOffset += f * 0.3F; float f1 = ExtMath.wrapf(this.rotYaw - this.yawOffset); + boolean flag = f1 < -90.0F || f1 >= 90.0F; if (f1 < -75.0F) { @@ -4349,6 +4511,13 @@ public abstract class EntityNPC extends EntityLiving { this.yawOffset += f1 * 0.2F; } + + if (flag) + { + p_110146_2_ *= -1.0F; + } + + return p_110146_2_; } public boolean getCanSpawnHere() { @@ -4417,6 +4586,24 @@ public abstract class EntityNPC extends EntityLiving if(!this.isPlayer()) this.equipment[slot] = stack; } + + public void setCombatTask() + { + if(!this.isPlayer()) { + this.tasks.removeTask(this.aiMelee); + this.tasks.removeTask(this.aiRanged); + ItemStack itemstack = this.getHeldItem(); + + if (this.isRangedWeapon(itemstack)) + { + this.tasks.addTask(3, this.aiRanged); + } + else + { + this.tasks.addTask(3, this.aiMelee); + } + } + } public abstract int getBaseHealth(Random rand); // { // return 20; @@ -4462,6 +4649,10 @@ public abstract class EntityNPC extends EntityLiving public int getColor() { return this.isPlayer() ? 0xff00ff : 0x5000ad; } + + public void sendDeathMessage() { + this.sendDeathMessage(this.isPlayer(), true); + } protected boolean canRegenerateHealth() { return this.isPlayer(); diff --git a/common/src/common/entity/types/EntityLiving.java b/common/src/common/entity/types/EntityLiving.java index 96d6709..c99cbb5 100755 --- a/common/src/common/entity/types/EntityLiving.java +++ b/common/src/common/entity/types/EntityLiving.java @@ -6,14 +6,22 @@ import java.util.List; import java.util.Map; import java.util.function.Predicate; -import common.ai.IEntityNode; +import common.ai.EntityAIBase; +import common.ai.EntityAIMoveTowardsRestriction; +import common.ai.EntityAITasks; +import common.ai.EntityJumpHelper; +import common.ai.EntityLookHelper; +import common.ai.EntityMoveHelper; +import common.ai.EntitySenses; import common.block.Block; import common.block.SoundType; +import common.collect.Lists; import common.collect.Maps; import common.color.TextColor; import common.enchantment.EnchantmentHelper; import common.entity.DamageSource; import common.entity.Entity; +import common.entity.EntityDamageSource; import common.entity.animal.EntityWolf; import common.entity.attributes.Attribute; import common.entity.attributes.AttributeInstance; @@ -42,9 +50,12 @@ import common.material.Material; import common.model.ParticleType; import common.nbt.NBTTagCompound; import common.nbt.NBTTagList; +import common.network.IPlayer; import common.packet.S1BPacketEntityAttach; import common.packet.SPacketAnimation; import common.packet.SPacketCollectItem; +import common.pathfinding.PathNavigate; +import common.pathfinding.PathNavigateGround; import common.potion.Potion; import common.potion.PotionEffect; import common.potion.PotionHelper; @@ -61,13 +72,23 @@ public abstract class EntityLiving extends Entity { private static final ItemStack[] EMPTY_INV = new ItemStack[5]; - protected IEntityNode node; private AttributeMap attributes; + private final List combat = Lists.newArrayList(); private final Map effects = Maps.newEnumMap(Potion.class); public int soundTimer; protected int xpValue; + private EntityLookHelper lookHelper; + protected EntityMoveHelper moveHelper; + protected EntityJumpHelper jumpHelper; + private EntityBodyHelper bodyHelper; + protected PathNavigate navigator; + protected final EntityAITasks tasks; + protected final EntityAITasks targets; + private EntityLiving target; + private EntitySenses senses; private boolean leashed; private Entity leashedTo; + private NBTTagCompound leashTag; public float prevCamPitch; public float camPitch; @@ -79,6 +100,8 @@ public abstract class EntityLiving extends Entity protected float landMovement; protected float prevGroundFactor; protected float groundFactor; + protected float movedDist; + protected float prevMovedDist; protected boolean jumping; public float moveStrafe; public float moveForward; @@ -112,13 +135,18 @@ public abstract class EntityLiving extends Entity private int lastAttacked; private EntityLiving attacker; private int lastAttackTime; + private int lastDamaged; // protected int entityAge; private int absorptionAmount; private boolean effectsDirty = true; protected boolean firstEffectUpdate = true; + private boolean attacked; + private boolean damaged; private String description; + + private String blockType; private float radiation; @@ -128,6 +156,8 @@ public abstract class EntityLiving extends Entity protected int growingAge; private float ageWidth = -1.0F; private float ageHeight; + private EntityAIBase aiBase = new EntityAIMoveTowardsRestriction(this, 1.0D); + private boolean isMovementAITaskSet; public EntityLiving(World worldIn) { @@ -141,6 +171,15 @@ public abstract class EntityLiving extends Entity this.rotYaw = (float)(Math.random() * Math.PI * 2.0D); this.headYaw = this.rotYaw; this.stepHeight = 0.6F; + + this.tasks = new EntityAITasks(); + this.targets = new EntityAITasks(); + this.lookHelper = new EntityLookHelper(this); + this.moveHelper = new EntityMoveHelper(this); + this.jumpHelper = new EntityJumpHelper(this); + this.bodyHelper = new EntityBodyHelper(this); + this.navigator = this.getNewNavigator(worldIn); + this.senses = new EntitySenses(this); } protected void entityInit() @@ -355,6 +394,7 @@ public abstract class EntityLiving extends Entity this.radiation = 0.0f; } this.updateEffects(); + this.prevMovedDist = this.movedDist; this.prevYawOffset = this.yawOffset; this.prevHeadYaw = this.headYaw; this.prevYaw = this.rotYaw; @@ -626,7 +666,7 @@ public abstract class EntityLiving extends Entity this.leashed = tagCompund.getBoolean("Leashed"); if(this.leashed && tagCompund.hasKey("Leash", 10)) { - this.node.setLeashTag(tagCompund.getCompoundTag("Leash")); + this.leashTag = tagCompund.getCompoundTag("Leash"); } } @@ -1069,12 +1109,11 @@ public abstract class EntityLiving extends Entity entity.onKillEntity(this); } - if(!this.worldObj.client) { - this.node.sendDeathMessage(); + if(!this.worldObj.client) + this.sendDeathMessage(); // this.noPickup = true; - this.node.resetCombat(); - } + this.resetCombat(); if (!this.worldObj.client) { @@ -1329,8 +1368,7 @@ public abstract class EntityLiving extends Entity { // float f1 = this.getHealth(); this.setHealth(this.getHealth() - damageAmount); - if(this.node != null) - this.node.trackDamage(damageSrc, damageAmount); + this.trackDamage(damageSrc, damageAmount); this.setAbsorptionAmount(this.getAbsorptionAmount() - damageAmount); } // } @@ -1338,7 +1376,7 @@ public abstract class EntityLiving extends Entity public EntityLiving getAttackingEntity() { - return (EntityLiving)(this.node.getAttacking() != null ? this.node.getAttacking() : (this.playerAttacker != null ? this.playerAttacker : (this.attackedBy != null ? this.attackedBy : null))); + return (EntityLiving)(this.getAttacking() != null ? this.getAttacking() : (this.playerAttacker != null ? this.playerAttacker : (this.attackedBy != null ? this.attackedBy : null))); } public final int getMaxHealth() @@ -1878,7 +1916,7 @@ public abstract class EntityLiving extends Entity if (this.ticksExisted % 20 == 0) { - this.node.resetCombat(); + this.resetCombat(); } } @@ -1910,7 +1948,7 @@ public abstract class EntityLiving extends Entity this.groundFactor += (f3 - this.groundFactor) * 0.3F; // this.worldObj.profiler.start("headTurn"); - this.updateDistance(f1, f2); + f2 = this.updateDistance(f1, f2); // this.worldObj.profiler.end(); // this.worldObj.profiler.start("rangeChecks"); @@ -1955,9 +1993,10 @@ public abstract class EntityLiving extends Entity } // this.worldObj.profiler.end(); + this.movedDist += f2; if(!this.worldObj.client) { - this.node.updateLeashedState(); + this.updateLeashedState(); } } @@ -2391,6 +2430,159 @@ public abstract class EntityLiving extends Entity public void clearRadiation() { this.radiation = 0.0f; } + + public void trackDamage(DamageSource source, int amount) { + this.resetCombat(); + this.blockType = null; + if(this.isOnLadder()) { + Block block = this.worldObj + .getState(new BlockPos(this.posX, this.getEntityBoundingBox().minY, this.posZ)).getBlock(); + if(block == Blocks.ladder) + this.blockType = "von einer Leiter"; + else if(block == Blocks.vine) + this.blockType = "von Ranken"; + } + else if(this.isInLiquid()) { + this.blockType = "aus dem Wasser"; + } + CombatEntry entry = new CombatEntry(source, amount, this.blockType, this.fallDistance); + this.combat.add(entry); + this.lastDamaged = this.ticksExisted; + this.damaged = true; + if(entry.getSource().getEntity() instanceof EntityLiving && !this.attacked && this.isEntityAlive()) + this.attacked = true; + } + + protected void sendDeathMessage() { + this.sendDeathMessage(false, false); + } + + protected void sendDeathMessage(boolean natural, boolean forAll) { + if(this.worldObj.client) + return; + String msg; + String kill; + IPlayer receiver = null; + if(this.combat.size() == 0) { + msg = kill = natural ? String.format("%s starb", this.getColoredName(TextColor.LGRAY)) : null; + } + else { + CombatEntry strong = null; + CombatEntry block = null; + int min = 0; + float max = 0.0F; + + for(int z = 0; z < this.combat.size(); ++z) { + CombatEntry entry = (CombatEntry)this.combat.get(z); + CombatEntry last = z > 0 ? (CombatEntry)this.combat.get(z - 1) : null; + + if((entry.getSource() == DamageSource.fall || entry.getSource() == DamageSource.outOfWorld) && + entry.getFallDistance() > 0.0F && (strong == null || entry.getFallDistance() > max)) { + if(z > 0) { + strong = last; + } + else { + strong = entry; + } + + max = entry.getFallDistance(); + } + + if(entry.getBlockType() != null && (block == null || entry.getDamage() > min)) { + block = entry; + } + } + CombatEntry fall = max > 5.0F && strong != null ? strong : (min > 5 && block != null ? block : null); + CombatEntry last = (CombatEntry)this.combat.get(this.combat.size() - 1); + Entity lastEnt = last.getSource().getEntity(); + + if(fall != null && last.getSource() == DamageSource.fall) { + if(fall.getSource() != DamageSource.fall && fall.getSource() != DamageSource.outOfWorld) { + Entity fallEnt = fall.getSource().getEntity(); + if(fallEnt != null && (lastEnt == null || fallEnt != lastEnt)) { + ItemStack fallItem = fallEnt instanceof EntityLiving ? ((EntityLiving)fallEnt).getHeldItem() : null; + receiver = fallEnt.isPlayer() ? ((EntityNPC)fallEnt).connection : null; + if(fallItem != null) { // && fallItem.hasDisplayName()) { + msg = String.format("%s wurde von %s mit %s zum Fallen verdammt", this.getColoredName(TextColor.CYAN), + fallEnt.getColoredName(TextColor.CYAN), fallItem.getColoredName(TextColor.CYAN)); + kill = String.format(TextColor.CYAN + "* %s mit %s zum Fallen verdammt", + this.getColoredName(TextColor.CYAN), fallItem.getColoredName(TextColor.CYAN)); + } + else { + msg = String.format("%s wurde von %s zum Fallen verdammt", this.getColoredName(TextColor.CYAN), + fallEnt.getColoredName(TextColor.CYAN)); + kill = String.format(TextColor.CYAN + "* %s zum Fallen verdammt", + this.getColoredName(TextColor.CYAN)); + } + } + else if(lastEnt != null) { + ItemStack lastItem = lastEnt instanceof EntityLiving ? ((EntityLiving)lastEnt).getHeldItem() : null; + receiver = lastEnt.isPlayer() ? ((EntityNPC)lastEnt).connection : null; + if(lastItem != null) { // && lastItem.hasDisplayName()) { + msg = String.format("%s fiel zu tief und wurde von %s mit %s erledigt", + this.getColoredName(TextColor.BLUE), + lastEnt.getColoredName(TextColor.BLUE), lastItem.getColoredName(TextColor.BLUE)); + kill = String.format(TextColor.BLUE + "* %s mit %s erledigt", + this.getColoredName(TextColor.BLUE), lastItem.getColoredName(TextColor.BLUE)); + } + else { + msg = String.format("%s fiel zu tief und wurde von %s erledigt", this.getColoredName(TextColor.BLUE), + lastEnt.getColoredName(TextColor.BLUE)); + kill = String.format(TextColor.BLUE + "%s erledigt", this.getColoredName(TextColor.BLUE)); + } + } + else { + msg = kill = natural ? String.format("%s wurde zum Fallen verdammt", this.getColoredName(TextColor.CYAN)) : null; + } + } + else { + msg = kill = natural ? String.format("%s fiel " + (fall.getBlockType() == null ? "aus zu großer Höhe" : fall.getBlockType()), + this.getColoredName(TextColor.NEON)) : null; + } + } + else { + receiver = last.getSource().getEntity() != null && last.getSource().getEntity().isPlayer() ? ((EntityNPC)last.getSource().getEntity()).connection : null; + msg = natural || (last.getSource() instanceof EntityDamageSource ? last.getSource().getEntity() != null : this.getAttackingEntity() != null) ? last.getSource().getDeathMessage(this) : null; + kill = msg == null ? null : last.getSource().getKillMessage(this); + } + } + if(msg == null) + return; + if(receiver != null) + receiver.addFeed(kill); + if(forAll) + for(IPlayer player : ((WorldServer)this.worldObj).getServer().getIPlayers()) { + if(player != receiver) + player.addFeed(msg); + } + } + + public EntityLiving getAttacking() { + EntityLiving entity = null; + EntityNPC player = null; + int edmg = 0; + int pdmg = 0; + for(CombatEntry entry : this.combat) { + if(entry.getSource().getEntity() != null && entry.getSource().getEntity().isPlayer() && (player == null || entry.getDamage() > pdmg)) { + pdmg = entry.getDamage(); + player = (EntityNPC)entry.getSource().getEntity(); + } + if(entry.getSource().getEntity() instanceof EntityLiving && (entity == null || entry.getDamage() > edmg)) { + edmg = entry.getDamage(); + entity = (EntityLiving)entry.getSource().getEntity(); + } + } + return player != null && pdmg >= edmg / 3 ? player : entity; + } + + public void resetCombat() { + int timeout = this.attacked ? 300 : 100; + if(this.damaged && (!this.isEntityAlive() || this.ticksExisted - this.lastDamaged > timeout)) { + this.damaged = false; + this.attacked = false; + this.combat.clear(); + } + } public boolean isSneakingVisually() { return this.isSneaking(); @@ -2612,6 +2804,22 @@ public abstract class EntityLiving extends Entity return 4; } + public int getMaxFallHeight() { + if(this.getAttackTarget() == null) { + return 3; + } + else { + int i = (int)((float)this.getHealth() - (float)this.getMaxHealth() * 0.33F); +// i = i - (3 - this.worldObj.getDifficulty().getId()) * 4; + + if(i < 0) { + i = 0; + } + + return i + 3; + } + } + // public boolean getCanSpawnHere() { // return true; // } @@ -2674,8 +2882,34 @@ public abstract class EntityLiving extends Entity } protected void updateEntityActionState() { - if(this.node != null) - this.node.update(); +// ++this.entityAge; +// this.worldObj.profiler.start("checkDespawn"); +// this.despawnEntity(); +// this.worldObj.profiler.end(); +// this.worldObj.profiler.start("sensing"); + this.senses.clearSensingCache(); +// this.worldObj.profiler.end(); +// this.worldObj.profiler.start("targetSelector"); + this.targets.onUpdateTasks(); +// this.worldObj.profiler.end(); +// this.worldObj.profiler.start("goalSelector"); + this.tasks.onUpdateTasks(); +// this.worldObj.profiler.end(); +// this.worldObj.profiler.start("navigation"); + this.navigator.onUpdateNavigation(); +// this.worldObj.profiler.end(); +// this.worldObj.profiler.start("mob tick"); + this.updateAITasks(); +// this.worldObj.profiler.end(); +// this.worldObj.profiler.start("controls"); +// this.worldObj.profiler.start("move"); + this.moveHelper.onUpdateMoveHelper(); +// this.worldObj.profiler.next("look"); + this.lookHelper.onUpdateLook(); +// this.worldObj.profiler.next("jump"); + this.jumpHelper.doJump(); +// this.worldObj.profiler.end(); +// this.worldObj.profiler.end(); } // protected void despawnEntity() { @@ -2733,12 +2967,123 @@ public abstract class EntityLiving extends Entity // super.applyEntityAttributes(); // this.getAttributeMap().registerAttribute(Attributes.FOLLOW_RANGE).setBaseValue(16.0D); // } + + protected PathNavigate getNewNavigator(World worldIn) { + return new PathNavigateGround(this, worldIn); + } + + public EntityLookHelper getLookHelper() { + return this.lookHelper; + } + + public EntityMoveHelper getMoveHelper() { + return this.moveHelper; + } + + public EntityJumpHelper getJumpHelper() { + return this.jumpHelper; + } + + public PathNavigate getNavigator() { + return this.navigator; + } + + public EntitySenses getEntitySenses() { + return this.senses; + } + + public EntityLiving getAttackTarget() { + return this.target; + } + + public void setAttackTarget(EntityLiving entitylivingbaseIn) { + this.target = entitylivingbaseIn; + } // public boolean canAttackClass(Class cls) { // return /* cls != EntityFireDemon.class && */ // ; // } + protected void updateLeashedState() { + if(this.leashTag != null) { + this.recreateLeash(); + } + + if(this.leashed) { + if(!this.isEntityAlive()) { + this.clearLeashed(true, true); + } + + if(this.leashedTo == null || this.leashedTo.dead) { + this.clearLeashed(true, true); + } + } + + if (this.getLeashed() && this.getLeashedTo() != null && this.getLeashedTo().worldObj == this.worldObj) + { + Entity entity = this.getLeashedTo(); + this.setHomePosAndDistance(new BlockPos((int)entity.posX, (int)entity.posY, (int)entity.posZ), 5); + float f = this.getDistanceToEntity(entity); + + if (this instanceof EntityTameable && ((EntityTameable)this).isSitting()) + { + if (f > 10.0F) + { + this.clearLeashed(true, true); + } + + return; + } + + if (!this.isMovementAITaskSet) + { + this.tasks.addTask(2, this.aiBase); + + if (this.getNavigator() instanceof PathNavigateGround) + { + ((PathNavigateGround)this.getNavigator()).setAvoidsWater(false); + } + + this.isMovementAITaskSet = true; + } + + this.onUpdateLeashed(f); + + if (f > 4.0F) + { + this.getNavigator().tryMoveToEntityLiving(entity, 1.0D); + } + + if (f > 6.0F) + { + double d0 = (entity.posX - this.posX) / (double)f; + double d1 = (entity.posY - this.posY) / (double)f; + double d2 = (entity.posZ - this.posZ) / (double)f; + this.motionX += d0 * Math.abs(d0) * 0.4D; + this.motionY += d1 * Math.abs(d1) * 0.4D; + this.motionZ += d2 * Math.abs(d2) * 0.4D; + } + + if (f > 10.0F) + { + this.clearLeashed(true, true); + } + } + else if (!this.getLeashed() && this.isMovementAITaskSet) + { + this.isMovementAITaskSet = false; + this.tasks.removeTask(this.aiBase); + + if (this.getNavigator() instanceof PathNavigateGround) + { + ((PathNavigateGround)this.getNavigator()).setAvoidsWater(true); + } + + this.detachHome(); + } + } + public void clearLeashed(boolean pkt, boolean dropLead) { if(this.leashed) { this.leashed = false; @@ -2775,9 +3120,43 @@ public abstract class EntityLiving extends Entity } } - protected void updateDistance(float p_110146_1_, float p_110146_2_) { - if(this.node != null) - this.node.updateRenderAngles(); + private void recreateLeash() { + if(this.leashed && this.leashTag != null) { +// if(this.leashTag.hasKey("PlayerName", 8)) { +// String id = this.leashTag.getString("PlayerName"); +// if(!id.isEmpty()) { +// for(EntityNPC entitylivingbase : this.worldObj.getEntitiesWithinAABB(EntityNPC.class, +// this.getEntityBoundingBox().expand(10.0D, 10.0D, 10.0D))) { +// if(entitylivingbase.getUser().equals(id)) { +// this.leashedTo = entitylivingbase; +// break; +// } +// } +// } +// } +// else + if(this.leashTag.hasKey("X", 99) && this.leashTag.hasKey("Y", 99) && this.leashTag.hasKey("Z", 99)) { + BlockPos blockpos = new BlockPos(this.leashTag.getInteger("X"), this.leashTag.getInteger("Y"), + this.leashTag.getInteger("Z")); + EntityLeashKnot entityleashknot = EntityLeashKnot.getKnotForPosition(this.worldObj, blockpos); + + if(entityleashknot == null) { + entityleashknot = EntityLeashKnot.createKnot(this.worldObj, blockpos); + } + + this.leashedTo = entityleashknot; + } + else { + this.clearLeashed(false, true); + } + } + + this.leashTag = null; + } + + protected float updateDistance(float p_110146_1_, float p_110146_2_) { + this.bodyHelper.updateRenderAngles(); + return p_110146_2_; } public ItemStack[] getInventory() { @@ -2908,6 +3287,11 @@ public abstract class EntityLiving extends Entity { return this.getBlockPathWeight(new BlockPos(this.posX, this.getEntityBoundingBox().minY, this.posZ)) >= 0.0F; } + + public boolean hasPath() + { + return !this.navigator.noPath(); + } public boolean isWithinHomeDistanceCurrentPosition() { @@ -2944,6 +3328,10 @@ public abstract class EntityLiving extends Entity { return this.maximumHomeDistance != -1.0F; } + + protected void onUpdateLeashed(float distance) + { + } protected void setSize(float width, float height) { diff --git a/common/src/common/pathfinding/PathNavigateGround.java b/common/src/common/pathfinding/PathNavigateGround.java index c9631ee..f12b1c8 100755 --- a/common/src/common/pathfinding/PathNavigateGround.java +++ b/common/src/common/pathfinding/PathNavigateGround.java @@ -11,7 +11,7 @@ import common.util.Vec3; import common.world.World; public class PathNavigateGround extends PathNavigate -{ +{ protected WalkNodeProcessor nodeProcessor; private boolean shouldAvoidSun; diff --git a/server/src/server/ai/EntityNPCNode.java b/server/src/server/ai/EntityNPCNode.java deleted file mode 100644 index b314cdc..0000000 --- a/server/src/server/ai/EntityNPCNode.java +++ /dev/null @@ -1,224 +0,0 @@ -package server.ai; - -import java.util.function.Predicate; - -import common.ai.AIRangedAttack; -import common.ai.EntityAIAttackOnCollide; -import common.ai.EntityAIAvoidEntity; -import common.ai.EntityAIHurtByTarget; -import common.ai.EntityAILookAtTalkingPlayer; -import common.ai.EntityAINagPlayer; -import common.ai.EntityAINearestAttackableTarget; -import common.ai.EntityAINpcInteract; -import common.ai.EntityAINpcMate; -import common.ai.EntityAIOpenDoor; -import common.ai.EntityAIPlay; -import common.ai.EntityAISwimming; -import common.ai.EntityAIWander; -import common.ai.EntityAIWatchClosest; -import common.ai.EntityAIWatchClosest2; -import common.entity.npc.EntityNPC; -import common.entity.types.EntityLiving; -import common.item.ItemStack; -import common.pathfinding.PathNavigateGround; - -public class EntityNPCNode extends EntityNode { - protected final EntityAIAttackOnCollide aiMelee; - protected final AIRangedAttack aiRanged; - private boolean fleeing; - - public EntityNPCNode(EntityNPC entity) { - super(entity); - this.aiMelee = new EntityAIAttackOnCollide(entity, EntityLiving.class, 1.0D, true, true) { - public boolean shouldExecute() - { - return !EntityNPCNode.this.fleeing && super.shouldExecute(); - } - - public boolean continueExecuting() - { - return !EntityNPCNode.this.fleeing && super.shouldExecute(); - } - }; - this.aiRanged = new AIRangedAttack(entity, 1.0D, entity.getAttackSpeed(), entity.getAttackSpeed() * 3, 15.0F) { -// public void startExecuting() -// { -// super.startExecuting(); -// EntityNPC.this.setUsingItem(true); -// } -// -// public void resetTask() -// { -// super.resetTask(); -// EntityNPC.this.setUsingItem(false); -// } - - public boolean shouldExecute() - { - return !EntityNPCNode.this.fleeing && super.shouldExecute(); - } - - public boolean continueExecuting() - { - return !EntityNPCNode.this.fleeing && super.shouldExecute(); - } - }; - } - - public EntityNPC getEntity() { - return (EntityNPC)this.entity; - } - - protected void registerTasks() { - if(this.getNavigator() instanceof PathNavigateGround) { - ((PathNavigateGround)this.getNavigator()).setBreakDoors(true); - ((PathNavigateGround)this.getNavigator()).setAvoidsWater(true); - } - this.tasks.addTask(0, new EntityAISwimming(this.getEntity())); -// this.tasks.addTask(1, new EntityAIAttackOnCollide(this, EntityNPC.class, 0.6D, true, true)); -// this.tasks.addTask(1, new EntityAIAttackOnCollide(this, EntityLivingBase.class, 0.6D, true, true)); - this.tasks.addTask(1, new EntityAINpcMate(this.getEntity())); - this.tasks.addTask(2, new EntityAIAvoidEntity(this.getEntity(), EntityLiving.class, new Predicate() { - public boolean test(EntityLiving entity) { - return entity != EntityNPCNode.this.entity && EntityNPC.this.shouldFlee(entity); - } - }, 8.0F, 1.1D, 1.1D) { - { - this.setMutexBits(0); - } - - public void startExecuting() { - EntityNPCNode.this.setAttackTarget(null); - EntityNPCNode.this.fleeing = true; - } - - public boolean continueExecuting() { - return false; - } - - public void updateTask() - { - } - -// public void resetTask() { -// super.resetTask(); -// EntityNPC.this.isFleeing = false; -// } - }); - this.tasks.addTask(3, new EntityAIAvoidEntity(this, EntityLiving.class, new Predicate() { - public boolean test(EntityLiving entity) { - return entity != EntityNPC.this && EntityNPC.this.shouldFlee(entity); - } - }, 8.0F, 1.1D, 1.1D) { - public void startExecuting() { - super.startExecuting(); - EntityNPC.this.setAttackTarget(null); - EntityNPC.this.fleeing = true; - } - - public void resetTask() { - super.resetTask(); - EntityNPC.this.fleeing = false; - } - }); -// this.tasks.addTask(2, new EntityAITempt(this, 1.0D, Items.golden_apple, false)); - this.tasks.addTask(4, new EntityAIOpenDoor(this, true)); - this.tasks.addTask(5, new EntityAINagPlayer(this)); - this.tasks.addTask(5, new EntityAILookAtTalkingPlayer(this)); - this.tasks.addTask(6, new EntityAIWatchClosest2(this, null, 3.0F, 1.0F) { - private int sneakTime; - - public void updateTask() - { - super.updateTask(); - boolean flag = this.closestEntity.isPlayer() && this.closestEntity.isSneaking(); - if(this.sneakTime > 0) { - if(--this.sneakTime == 0) { - EntityNPC.this.setSneaking(false); - } - } - else if(EntityNPC.this.getAttackTarget() == null && EntityNPC.this.rand.chance(flag ? 5 : 200)) { - EntityNPC.this.setSneaking(true); - this.sneakTime = EntityNPC.this.rand.range(60, flag ? 160 : 120); - } - else if(EntityNPC.this.getAttackTarget() != null) { - EntityNPC.this.setSneaking(false); - this.sneakTime = 0; - } - } - - public void resetTask() - { - super.resetTask(); - EntityNPC.this.setSneaking(false); - } - }); - this.tasks.addTask(7, new EntityAINpcInteract(this)); - this.tasks.addTask(8, new EntityAIWander(this, 1.0D)); - this.tasks.addTask(8, new EntityAIPlay(this, 1.1D)); - this.tasks.addTask(9, new EntityAIWatchClosest(this, EntityLiving.class, 8.0F)); - this.targets.addTask(1, new EntityAIHurtByTarget(this, false, /* EntityNPC.class, */ EntityLiving.class) { - protected boolean isSuitableTarget(EntityLiving entity) { - if(entity != null && entity != EntityNPC.this && EntityNPC.this.shouldFlee(entity)) { - EntityNPC.this.setAttackTarget(null); - EntityNPC.this.fleeing = true; - return false; - } - return entity != null && entity != EntityNPC.this && (!(entity.isPlayer()) || EntityNPC.this.rand.chance(entity.getAttackedBy() == EntityNPC.this ? 2 : 4)) - && EntityNPC.this.canCounter(entity) && super.isSuitableTarget(entity); - } - }); - this.targets.addTask(2, new EntityAINearestAttackableTarget(this, EntityLiving.class, 10, true, false, new Predicate() { - public boolean test(EntityLiving entity) { - if(entity != null && entity != EntityNPC.this && EntityNPC.this.shouldFlee(entity)) { - EntityNPC.this.setAttackTarget(null); - EntityNPC.this.fleeing = true; - return false; - } - return entity != null && entity != EntityNPC.this && !EntityNPC.this.fleeing && EntityNPC.this.canAmbush(entity) && EntityNPC.this.canAttack(entity); - } - })); -// this.setCanPickUpLoot(true); - - if (worldIn != null && !worldIn.client) - { - this.setCombatTask(); - } - } - - public void updateLeashedState() { - if(!this.player) - super.updateLeashedState(); - } - - public void sendDeathMessage() { - this.sendDeathMessage(this.player, true); - } - - public int getMaxFallHeight() - { - return this.player ? 3 : super.getMaxFallHeight(); - } - - public void setCombatTask() - { - if(!this.player) { - this.tasks.removeTask(this.aiMelee); - this.tasks.removeTask(this.aiRanged); - ItemStack itemstack = this.getEntity().getHeldItem(); - - if (this.getEntity().isRangedWeapon(itemstack)) - { - this.tasks.addTask(3, this.aiRanged); - } - else - { - this.tasks.addTask(3, this.aiMelee); - } - } - } - - public boolean isFleeing() { - return this.fleeing; - } -} diff --git a/server/src/server/ai/EntityNode.java b/server/src/server/ai/EntityNode.java deleted file mode 100644 index 2f4c0a7..0000000 --- a/server/src/server/ai/EntityNode.java +++ /dev/null @@ -1,436 +0,0 @@ -package server.ai; - -import java.util.List; - -import common.ai.EntityAIBase; -import common.ai.EntityAIMoveTowardsRestriction; -import common.ai.EntityAITasks; -import common.ai.EntityJumpHelper; -import common.ai.EntityLookHelper; -import common.ai.EntityMoveHelper; -import common.ai.EntitySenses; -import common.ai.IEntityNode; -import common.block.Block; -import common.collect.Lists; -import common.color.TextColor; -import common.entity.DamageSource; -import common.entity.Entity; -import common.entity.EntityDamageSource; -import common.entity.item.EntityLeashKnot; -import common.entity.npc.EntityNPC; -import common.entity.types.CombatEntry; -import common.entity.types.EntityBodyHelper; -import common.entity.types.EntityLiving; -import common.entity.types.EntityTameable; -import common.init.Blocks; -import common.item.ItemStack; -import common.nbt.NBTTagCompound; -import common.network.IPlayer; -import common.pathfinding.PathNavigate; -import common.pathfinding.PathNavigateGround; -import common.util.BlockPos; -import common.world.WorldServer; - -public abstract class EntityNode implements IEntityNode { - protected final EntityLiving entity; - protected final boolean player; - private final List combat = Lists.newArrayList(); - private EntityLookHelper lookHelper; - protected EntityMoveHelper moveHelper; - protected EntityJumpHelper jumpHelper; - private EntityBodyHelper bodyHelper; - protected PathNavigate navigator; - protected final EntityAITasks tasks; - protected final EntityAITasks targets; - private EntityLiving target; - private EntitySenses senses; - private Runnable tickFunc; - private NBTTagCompound leashTag; - private boolean isMovementAITaskSet; - private EntityAIBase aiBase; - private boolean attacked; - private boolean damaged; - private String blockType; - private int lastDamaged; - - public EntityNode(EntityLiving entity) { - this.entity = entity; - this.player = entity.isPlayer(); - this.tasks = new EntityAITasks(); - this.targets = new EntityAITasks(); - this.lookHelper = new EntityLookHelper(entity); - this.moveHelper = new EntityMoveHelper(entity); - this.jumpHelper = new EntityJumpHelper(entity); - this.bodyHelper = new EntityBodyHelper(entity); - this.navigator = this.getNewNavigator(); - this.senses = new EntitySenses(entity); - this.aiBase = new EntityAIMoveTowardsRestriction(entity, 1.0D); - this.registerTasks(); - } - - protected PathNavigate getNewNavigator() { - return new PathNavigateGround(this.entity, this.entity.worldObj); - } - -// protected PathNavigate getNewNavigator() { EntityArachnoid -// return new PathNavigateClimber(this.entity, this.entity.worldObj); -// } - - protected abstract void registerTasks(); - - public void setTickFunction(Runnable func) { - this.tickFunc = func; - } - - public EntityLookHelper getLookHelper() { - return this.lookHelper; - } - - public EntityMoveHelper getMoveHelper() { - return this.moveHelper; - } - - public EntityJumpHelper getJumpHelper() { - return this.jumpHelper; - } - - public PathNavigate getNavigator() { - return this.navigator; - } - - public EntitySenses getEntitySenses() { - return this.senses; - } - - public EntityLiving getAttackTarget() { - return this.target; - } - - public void setAttackTarget(EntityLiving entitylivingbaseIn) { - this.target = entitylivingbaseIn; - } - - public boolean hasPath() - { - return !this.navigator.noPath(); - } - - public void updateRenderAngles() { - this.bodyHelper.updateRenderAngles(); - } - - public void update() { - this.senses.clearSensingCache(); - this.targets.onUpdateTasks(); - this.tasks.onUpdateTasks(); - this.navigator.onUpdateNavigation(); - if(this.tickFunc != null) - this.tickFunc.run(); - this.moveHelper.onUpdateMoveHelper(); - this.lookHelper.onUpdateLook(); - this.jumpHelper.doJump(); - } - - public void setLeashTag(NBTTagCompound tag) { - this.leashTag = tag; - } - - private void recreateLeash() { - if(this.entity.getLeashed() && this.leashTag != null) { -// if(this.leashTag.hasKey("PlayerName", 8)) { -// String id = this.leashTag.getString("PlayerName"); -// if(!id.isEmpty()) { -// for(EntityNPC entitylivingbase : this.worldObj.getEntitiesWithinAABB(EntityNPC.class, -// this.getEntityBoundingBox().expand(10.0D, 10.0D, 10.0D))) { -// if(entitylivingbase.getUser().equals(id)) { -// this.leashedTo = entitylivingbase; -// break; -// } -// } -// } -// } -// else - if(this.leashTag.hasKey("X", 99) && this.leashTag.hasKey("Y", 99) && this.leashTag.hasKey("Z", 99)) { - BlockPos blockpos = new BlockPos(this.leashTag.getInteger("X"), this.leashTag.getInteger("Y"), - this.leashTag.getInteger("Z")); - EntityLeashKnot entityleashknot = EntityLeashKnot.getKnotForPosition(this.entity.worldObj, blockpos); - - if(entityleashknot == null) { - entityleashknot = EntityLeashKnot.createKnot(this.entity.worldObj, blockpos); - } - - this.entity.setLeashedTo(entityleashknot, false); - } - else { - this.entity.clearLeashed(false, true); - } - } - - this.leashTag = null; - } - - protected void onUpdateLeashed(float distance) - { - } - -// protected void onUpdateLeashed(float distance) EntityHorse -// { -// if (distance > 6.0F && this.entity.isEatingHaystack()) -// { -// this.entity.setEatingHaystack(false); -// } -// } - - public void updateLeashedState() { - if(this.leashTag != null) { - this.recreateLeash(); - } - - if(this.entity.getLeashed()) { - if(!this.entity.isEntityAlive()) { - this.entity.clearLeashed(true, true); - } - - if(this.entity.getLeashedTo() == null || this.entity.getLeashedTo().dead) { - this.entity.clearLeashed(true, true); - } - } - - if (this.entity.getLeashed() && this.entity.getLeashedTo() != null && this.entity.getLeashedTo().worldObj == this.entity.worldObj) - { - Entity entity = this.entity.getLeashedTo(); - this.entity.setHomePosAndDistance(new BlockPos((int)entity.posX, (int)entity.posY, (int)entity.posZ), 5); - float f = this.entity.getDistanceToEntity(entity); - - if (this.entity instanceof EntityTameable && ((EntityTameable)this.entity).isSitting()) - { - if (f > 10.0F) - { - this.entity.clearLeashed(true, true); - } - - return; - } - - if (!this.isMovementAITaskSet) - { - this.tasks.addTask(2, this.aiBase); - - if (this.getNavigator() instanceof PathNavigateGround) - { - ((PathNavigateGround)this.getNavigator()).setAvoidsWater(false); - } - - this.isMovementAITaskSet = true; - } - - this.onUpdateLeashed(f); - - if (f > 4.0F) - { - this.getNavigator().tryMoveToEntityLiving(entity, 1.0D); - } - - if (f > 6.0F) - { - double d0 = (entity.posX - this.entity.posX) / (double)f; - double d1 = (entity.posY - this.entity.posY) / (double)f; - double d2 = (entity.posZ - this.entity.posZ) / (double)f; - this.entity.motionX += d0 * Math.abs(d0) * 0.4D; - this.entity.motionY += d1 * Math.abs(d1) * 0.4D; - this.entity.motionZ += d2 * Math.abs(d2) * 0.4D; - } - - if (f > 10.0F) - { - this.entity.clearLeashed(true, true); - } - } - else if (!this.entity.getLeashed() && this.isMovementAITaskSet) - { - this.isMovementAITaskSet = false; - this.tasks.removeTask(this.aiBase); - - if (this.getNavigator() instanceof PathNavigateGround) - { - ((PathNavigateGround)this.getNavigator()).setAvoidsWater(true); - } - - this.entity.detachHome(); - } - } - - public void trackDamage(DamageSource source, int amount) { - this.resetCombat(); - this.blockType = null; - if(this.entity.isOnLadder()) { - Block block = this.entity.worldObj - .getState(new BlockPos(this.entity.posX, this.entity.getEntityBoundingBox().minY, this.entity.posZ)).getBlock(); - if(block == Blocks.ladder) - this.blockType = "von einer Leiter"; - else if(block == Blocks.vine) - this.blockType = "von Ranken"; - } - else if(this.entity.isInLiquid()) { - this.blockType = "aus dem Wasser"; - } - CombatEntry entry = new CombatEntry(source, amount, this.blockType, this.entity.fallDistance); - this.combat.add(entry); - this.lastDamaged = this.entity.ticksExisted; - this.damaged = true; - if(entry.getSource().getEntity() instanceof EntityLiving && !this.attacked && this.entity.isEntityAlive()) - this.attacked = true; - } - - public void sendDeathMessage() { - this.sendDeathMessage(false, false); - } - - protected void sendDeathMessage(boolean natural, boolean forAll) { -// if(this.entity.worldObj.client) -// return; - String msg; - String kill; - IPlayer receiver = null; - if(this.combat.size() == 0) { - msg = kill = natural ? String.format("%s starb", this.entity.getColoredName(TextColor.LGRAY)) : null; - } - else { - CombatEntry strong = null; - CombatEntry block = null; - int min = 0; - float max = 0.0F; - - for(int z = 0; z < this.combat.size(); ++z) { - CombatEntry entry = (CombatEntry)this.combat.get(z); - CombatEntry last = z > 0 ? (CombatEntry)this.combat.get(z - 1) : null; - - if((entry.getSource() == DamageSource.fall || entry.getSource() == DamageSource.outOfWorld) && - entry.getFallDistance() > 0.0F && (strong == null || entry.getFallDistance() > max)) { - if(z > 0) { - strong = last; - } - else { - strong = entry; - } - - max = entry.getFallDistance(); - } - - if(entry.getBlockType() != null && (block == null || entry.getDamage() > min)) { - block = entry; - } - } - CombatEntry fall = max > 5.0F && strong != null ? strong : (min > 5 && block != null ? block : null); - CombatEntry last = (CombatEntry)this.combat.get(this.combat.size() - 1); - Entity lastEnt = last.getSource().getEntity(); - - if(fall != null && last.getSource() == DamageSource.fall) { - if(fall.getSource() != DamageSource.fall && fall.getSource() != DamageSource.outOfWorld) { - Entity fallEnt = fall.getSource().getEntity(); - if(fallEnt != null && (lastEnt == null || fallEnt != lastEnt)) { - ItemStack fallItem = fallEnt instanceof EntityLiving ? ((EntityLiving)fallEnt).getHeldItem() : null; - receiver = fallEnt.isPlayer() ? ((EntityNPC)fallEnt).connection : null; - if(fallItem != null) { // && fallItem.hasDisplayName()) { - msg = String.format("%s wurde von %s mit %s zum Fallen verdammt", this.entity.getColoredName(TextColor.CYAN), - fallEnt.getColoredName(TextColor.CYAN), fallItem.getColoredName(TextColor.CYAN)); - kill = String.format(TextColor.CYAN + "* %s mit %s zum Fallen verdammt", - this.entity.getColoredName(TextColor.CYAN), fallItem.getColoredName(TextColor.CYAN)); - } - else { - msg = String.format("%s wurde von %s zum Fallen verdammt", this.entity.getColoredName(TextColor.CYAN), - fallEnt.getColoredName(TextColor.CYAN)); - kill = String.format(TextColor.CYAN + "* %s zum Fallen verdammt", - this.entity.getColoredName(TextColor.CYAN)); - } - } - else if(lastEnt != null) { - ItemStack lastItem = lastEnt instanceof EntityLiving ? ((EntityLiving)lastEnt).getHeldItem() : null; - receiver = lastEnt.isPlayer() ? ((EntityNPC)lastEnt).connection : null; - if(lastItem != null) { // && lastItem.hasDisplayName()) { - msg = String.format("%s fiel zu tief und wurde von %s mit %s erledigt", - this.entity.getColoredName(TextColor.BLUE), - lastEnt.getColoredName(TextColor.BLUE), lastItem.getColoredName(TextColor.BLUE)); - kill = String.format(TextColor.BLUE + "* %s mit %s erledigt", - this.entity.getColoredName(TextColor.BLUE), lastItem.getColoredName(TextColor.BLUE)); - } - else { - msg = String.format("%s fiel zu tief und wurde von %s erledigt", this.entity.getColoredName(TextColor.BLUE), - lastEnt.getColoredName(TextColor.BLUE)); - kill = String.format(TextColor.BLUE + "%s erledigt", this.entity.getColoredName(TextColor.BLUE)); - } - } - else { - msg = kill = natural ? String.format("%s wurde zum Fallen verdammt", this.entity.getColoredName(TextColor.CYAN)) : null; - } - } - else { - msg = kill = natural ? String.format("%s fiel " + (fall.getBlockType() == null ? "aus zu großer Höhe" : fall.getBlockType()), - this.entity.getColoredName(TextColor.NEON)) : null; - } - } - else { - receiver = last.getSource().getEntity() != null && last.getSource().getEntity().isPlayer() ? ((EntityNPC)last.getSource().getEntity()).connection : null; - msg = natural || (last.getSource() instanceof EntityDamageSource ? last.getSource().getEntity() != null : this.entity.getAttackingEntity() != null) ? last.getSource().getDeathMessage(this.entity) : null; - kill = msg == null ? null : last.getSource().getKillMessage(this.entity); - } - } - if(msg == null) - return; - if(receiver != null) - receiver.addFeed(kill); - if(forAll) - for(IPlayer player : ((WorldServer)this.entity.worldObj).getServer().getIPlayers()) { - if(player != receiver) - player.addFeed(msg); - } - } - - public EntityLiving getAttacking() { - EntityLiving entity = null; - EntityNPC player = null; - int edmg = 0; - int pdmg = 0; - for(CombatEntry entry : this.combat) { - if(entry.getSource().getEntity() != null && entry.getSource().getEntity().isPlayer() && (player == null || entry.getDamage() > pdmg)) { - pdmg = entry.getDamage(); - player = (EntityNPC)entry.getSource().getEntity(); - } - if(entry.getSource().getEntity() instanceof EntityLiving && (entity == null || entry.getDamage() > edmg)) { - edmg = entry.getDamage(); - entity = (EntityLiving)entry.getSource().getEntity(); - } - } - return player != null && pdmg >= edmg / 3 ? player : entity; - } - - public void resetCombat() { - int timeout = this.attacked ? 300 : 100; - if(this.damaged && (!this.entity.isEntityAlive() || this.entity.ticksExisted - this.lastDamaged > timeout)) { - this.damaged = false; - this.attacked = false; - this.combat.clear(); - } - } - - public int getMaxFallHeight() { - if(this.target == null) { - return 3; - } - else { - int i = (int)((float)this.entity.getHealth() - (float)this.entity.getMaxHealth() * 0.33F); -// i = i - (3 - this.worldObj.getDifficulty().getId()) * 4; - - if(i < 0) { - i = 0; - } - - return i + 3; - } - } - -// public int getMaxFallHeight() EntityHaunter -// { -// return this.getAttackTarget() == null ? 3 : 3 + (this.getHealth() - 1); -// } -}