diff --git a/src/main/java/noppes/npcs/NoppesUtilServer.java b/src/main/java/noppes/npcs/NoppesUtilServer.java index b4572f305..bb7af2bbf 100644 --- a/src/main/java/noppes/npcs/NoppesUtilServer.java +++ b/src/main/java/noppes/npcs/NoppesUtilServer.java @@ -856,7 +856,7 @@ public class NoppesUtilServer { } public static Entity GetDamageSourcee(DamageSource damagesource) { - Object entity = damagesource.getEntity(); + Entity entity = damagesource.getEntity(); if(entity == null) { entity = damagesource.getSourceOfDamage(); } @@ -867,7 +867,7 @@ public class NoppesUtilServer { entity = ((EntityThrowable)entity).getThrower(); } - return (Entity)entity; + return entity; } public static void isGUIOpen(ByteBuf buffer, EntityPlayer player) throws IOException { diff --git a/src/main/java/noppes/npcs/ai/CombatHandler.java b/src/main/java/noppes/npcs/ai/CombatHandler.java new file mode 100644 index 000000000..5063977ba --- /dev/null +++ b/src/main/java/noppes/npcs/ai/CombatHandler.java @@ -0,0 +1,106 @@ +package noppes.npcs.ai; + +import java.util.HashMap; +import java.util.Map; + +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.util.DamageSource; +import noppes.npcs.NoppesUtilServer; +import noppes.npcs.entity.EntityNPCInterface; + +public class CombatHandler { + + private Map aggressors = new HashMap(); + private EntityNPCInterface npc; + private long startTime = 0; + private int combatResetTimer = 0; + public CombatHandler(EntityNPCInterface npc) { + this.npc = npc; + } + + public void update(){ + if(npc.isKilled()){ + if(npc.isAttacking()){ + reset(); + } + return; + } + if(npc.getAttackTarget() != null && !npc.isAttacking()){ + start(); + } + + if(!shouldCombatContinue()){ + if(combatResetTimer++ > 40){ + reset(); + } + return; + } + combatResetTimer = 0; + } + + + private boolean shouldCombatContinue() { + if(npc.getAttackTarget() == null) + return false; + return isValidTarget(npc.getAttackTarget()); + } + + public void damage(DamageSource source, float damageAmount){ + combatResetTimer = 0; + Entity e = NoppesUtilServer.GetDamageSourcee(source); + System.out.println(e); + if(e instanceof EntityLivingBase){ + EntityLivingBase el = (EntityLivingBase) e; + Float f = aggressors.get(el); + if(f == null) + f = 0f; + aggressors.put(el, f + damageAmount); + } + } + + public void start(){ + combatResetTimer = 0; + startTime = npc.worldObj.getWorldInfo().getWorldTotalTime(); + npc.setBoolFlag(true, 4); + } + + public void reset(){ + combatResetTimer = 0; + aggressors.clear(); + npc.setBoolFlag(true, 4); + } + + public boolean checkTarget() { + if(aggressors.isEmpty() || npc.ticksExisted % 10 != 0) + return false; + EntityLivingBase target = npc.getAttackTarget(); + Float current = 0f; + if(isValidTarget(target)){ + current = aggressors.get(target); + if(current == null) + current = 0f; + } + else + target = null; + for (Map.Entry entry : aggressors.entrySet()){ + if(entry.getValue() > current && isValidTarget(entry.getKey())){ + current = entry.getValue(); + target = entry.getKey(); + } + } + return target == null; + } + + public boolean isValidTarget(EntityLivingBase target){ + if(target == null || !target.isEntityAlive()) + return false; + + if(target instanceof EntityPlayer && ((EntityPlayer)target).capabilities.disableDamage) + return false; + + return npc.isInRange(target, npc.stats.aggroRange); + } + +} diff --git a/src/main/java/noppes/npcs/ai/EntityAIAttackTarget.java b/src/main/java/noppes/npcs/ai/EntityAIAttackTarget.java index a7e411f2a..4ed4d94ce 100644 --- a/src/main/java/noppes/npcs/ai/EntityAIAttackTarget.java +++ b/src/main/java/noppes/npcs/ai/EntityAIAttackTarget.java @@ -12,24 +12,24 @@ import noppes.npcs.entity.EntityNPCInterface; public class EntityAIAttackTarget extends EntityAIBase { - World worldObj; - EntityNPCInterface attacker; - EntityLivingBase entityTarget; + private World world; + private EntityNPCInterface npc; + private EntityLivingBase entityTarget; /** * An amount of decrementing ticks that allows the entity to attack once the tick reaches 0. */ - int attackTick; + private int attackTick; /** The PathEntity of our entity. */ - PathEntity entityPathEntity; + private PathEntity entityPathEntity; private int field_75445_i; private boolean navOverride = false; public EntityAIAttackTarget(EntityNPCInterface par1EntityLiving){ this.attackTick = 0; - this.attacker = par1EntityLiving; - this.worldObj = par1EntityLiving.worldObj; + this.npc = par1EntityLiving; + this.world = par1EntityLiving.worldObj; this.setMutexBits(this.navOverride ? AiMutex.PATHING : AiMutex.LOOK + AiMutex.PASSIVE); } @@ -37,7 +37,7 @@ public class EntityAIAttackTarget extends EntityAIBase * Returns whether the EntityAIBase should begin execution. */ public boolean shouldExecute(){ - EntityLivingBase entitylivingbase = this.attacker.getAttackTarget(); + EntityLivingBase entitylivingbase = this.npc.getAttackTarget(); if (entitylivingbase == null){ return false; @@ -45,21 +45,21 @@ public class EntityAIAttackTarget extends EntityAIBase else if (!entitylivingbase.isEntityAlive()){ return false; } - else if (this.attacker.inventory.getProjectile() != null && this.attacker.ai.useRangeMelee == 0){ + else if (this.npc.inventory.getProjectile() != null && this.npc.ai.useRangeMelee == 0){ return false; } - double var2 = this.attacker.getDistanceSq(entitylivingbase.posX, entitylivingbase.boundingBox.minY, entitylivingbase.posZ); - double var3 = this.attacker.ai.distanceToMelee * this.attacker.ai.distanceToMelee; + double var2 = this.npc.getDistanceSq(entitylivingbase.posX, entitylivingbase.boundingBox.minY, entitylivingbase.posZ); + double var3 = this.npc.ai.distanceToMelee * this.npc.ai.distanceToMelee; - if (this.attacker.ai.useRangeMelee == 1 && var2 > var3){ + if (this.npc.ai.useRangeMelee == 1 && var2 > var3){ return false; } else{ this.entityTarget = entitylivingbase; - this.attacker.getEntityAttribute(SharedMonsterAttributes.followRange).setBaseValue(((EntityNPCInterface) this.attacker).stats.aggroRange); - this.entityPathEntity = this.attacker.getNavigator().getPathToEntityLiving(entitylivingbase); - this.attacker.getEntityAttribute(SharedMonsterAttributes.followRange).setBaseValue(ConfigMain.NpcNavRange); + this.npc.getEntityAttribute(SharedMonsterAttributes.followRange).setBaseValue(((EntityNPCInterface) this.npc).stats.aggroRange); + this.entityPathEntity = this.npc.getNavigator().getPathToEntityLiving(entitylivingbase); + this.npc.getEntityAttribute(SharedMonsterAttributes.followRange).setBaseValue(ConfigMain.NpcNavRange); return this.entityPathEntity != null; } } @@ -69,16 +69,16 @@ public class EntityAIAttackTarget extends EntityAIBase */ public boolean continueExecuting() { - this.entityTarget = this.attacker.getAttackTarget(); + this.entityTarget = this.npc.getAttackTarget(); if(entityTarget == null || !entityTarget.isEntityAlive()) return false; - if(attacker.getDistanceToEntity(entityTarget) > attacker.stats.aggroRange) + if(npc.getDistanceToEntity(entityTarget) > npc.stats.aggroRange) return false; - if (this.attacker.ai.useRangeMelee == 1 && attacker.getDistanceSqToEntity(entityTarget) > (this.attacker.ai.distanceToMelee * this.attacker.ai.distanceToMelee)) + if (this.npc.ai.useRangeMelee == 1 && npc.getDistanceSqToEntity(entityTarget) > (this.npc.ai.distanceToMelee * this.npc.ai.distanceToMelee)) return false; - return this.attacker.isWithinHomeDistance(MathHelper.floor_double(entityTarget.posX), MathHelper.floor_double(entityTarget.posY), MathHelper.floor_double(entityTarget.posZ)); + return this.npc.isWithinHomeDistance(MathHelper.floor_double(entityTarget.posX), MathHelper.floor_double(entityTarget.posY), MathHelper.floor_double(entityTarget.posZ)); } /** @@ -86,11 +86,11 @@ public class EntityAIAttackTarget extends EntityAIBase */ public void startExecuting(){ if(!navOverride) - this.attacker.getNavigator().setPath(this.entityPathEntity, 1.3D); + this.npc.getNavigator().setPath(this.entityPathEntity, 1.3D); this.field_75445_i = 0; - if (this.attacker.getRangedTask() != null && this.attacker.ai.useRangeMelee == 2) + if (this.npc.getRangedTask() != null && this.npc.ai.useRangeMelee == 2) { - this.attacker.getRangedTask().navOverride(true); + this.npc.getRangedTask().navOverride(true); } } @@ -101,11 +101,11 @@ public class EntityAIAttackTarget extends EntityAIBase { this.entityPathEntity = null; this.entityTarget = null; - this.attacker.setAttackTarget(null); - this.attacker.getNavigator().clearPathEntity(); - if (this.attacker.getRangedTask() != null && this.attacker.ai.useRangeMelee == 2) + this.npc.setAttackTarget(null); + this.npc.getNavigator().clearPathEntity(); + if (this.npc.getRangedTask() != null && this.npc.ai.useRangeMelee == 2) { - this.attacker.getRangedTask().navOverride(false); + this.npc.getRangedTask().navOverride(false); } } @@ -114,26 +114,26 @@ public class EntityAIAttackTarget extends EntityAIBase */ public void updateTask() { - this.attacker.getLookHelper().setLookPositionWithEntity(this.entityTarget, 30.0F, 30.0F); + this.npc.getLookHelper().setLookPositionWithEntity(this.entityTarget, 30.0F, 30.0F); if (!navOverride && --this.field_75445_i <= 0) { - this.field_75445_i = 4 + this.attacker.getRNG().nextInt(7); - this.attacker.getNavigator().tryMoveToEntityLiving(this.entityTarget, 1.3f); + this.field_75445_i = 4 + this.npc.getRNG().nextInt(7); + this.npc.getNavigator().tryMoveToEntityLiving(this.entityTarget, 1.3f); } this.attackTick = Math.max(this.attackTick - 1, 0); - double distance = this.attacker.getDistanceSq(this.entityTarget.posX, this.entityTarget.boundingBox.minY, this.entityTarget.posZ); - double range = attacker.stats.attackRange * attacker.stats.attackRange + entityTarget.width; - double minRange = this.attacker.width * 2.0F * this.attacker.width * 2.0F + entityTarget.width; + double distance = this.npc.getDistanceSq(this.entityTarget.posX, this.entityTarget.boundingBox.minY, this.entityTarget.posZ); + double range = npc.stats.attackRange * npc.stats.attackRange + entityTarget.width; + double minRange = this.npc.width * 2.0F * this.npc.width * 2.0F + entityTarget.width; if(minRange > range) range = minRange; - if (distance <= range && (attacker.canSee(this.entityTarget) || distance < minRange)) + if (distance <= range && (npc.canSee(this.entityTarget) || distance < minRange)) { if (this.attackTick <= 0) { - this.attackTick = this.attacker.stats.attackSpeed; - this.attacker.swingItem(); - this.attacker.attackEntityAsMob(this.entityTarget); + this.attackTick = this.npc.stats.attackSpeed; + this.npc.swingItem(); + this.npc.attackEntityAsMob(this.entityTarget); } } } diff --git a/src/main/java/noppes/npcs/ai/EntityAIPounceTarget.java b/src/main/java/noppes/npcs/ai/EntityAIPounceTarget.java new file mode 100644 index 000000000..18e1c34f2 --- /dev/null +++ b/src/main/java/noppes/npcs/ai/EntityAIPounceTarget.java @@ -0,0 +1,63 @@ +package noppes.npcs.ai; + +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.ai.EntityAIBase; +import net.minecraft.util.MathHelper; +import noppes.npcs.entity.EntityNPCInterface; + +public class EntityAIPounceTarget extends EntityAIBase { + private EntityNPCInterface npc; + private EntityLivingBase leapTarget; + private float leapSpeed = 1.2F; + + public EntityAIPounceTarget(EntityNPCInterface leapingEntity){ + this.npc = leapingEntity; + this.setMutexBits(4); + } + + @Override + public boolean shouldExecute(){ + if(!this.npc.onGround) + return false; + + this.leapTarget = this.npc.getAttackTarget(); + + if (this.leapTarget == null || !this.npc.getEntitySenses().canSee(leapTarget)) + return false; + + return !npc.isInRange(leapTarget, 4) && npc.isInRange(leapTarget, 8) && this.npc.getRNG().nextInt(5) == 0; + } + + @Override + public boolean continueExecuting(){ + return !this.npc.onGround; + } + + @Override + public void startExecuting(){ + double varX = this.leapTarget.posX - this.npc.posX; + double varY = this.leapTarget.boundingBox.minY - this.npc.boundingBox.minY; + double varZ = this.leapTarget.posZ - this.npc.posZ; + float varF = MathHelper.sqrt_double(varX * varX + varZ * varZ); + float angle = this.getAngleForXYZ(varX, varY, varZ, varF); + float yaw = (float)(Math.atan2(varX, varZ) * 180.0D / Math.PI); + this.npc.motionX = (double)(MathHelper.sin(yaw / 180.0F * (float)Math.PI) * MathHelper.cos(angle / 180.0F * (float)Math.PI)); + this.npc.motionZ = (double)(MathHelper.cos(yaw / 180.0F * (float)Math.PI) * MathHelper.cos(angle / 180.0F * (float)Math.PI)); + this.npc.motionY = (double)(MathHelper.sin((angle + 1.0F) / 180.0F * (float)Math.PI)); + this.npc.motionX *= this.leapSpeed; + this.npc.motionZ *= this.leapSpeed; + this.npc.motionY *= this.leapSpeed; + } + + public float getAngleForXYZ(double varX, double varY, double varZ, double horiDist) { + float g = 0.1F; + float var1 = this.leapSpeed * this.leapSpeed; + double var2 = (g * horiDist); + double var3 = ((g * horiDist * horiDist) + (2 * varY * var1)); + double var4 = (var1 * var1) - (g * var3); + if (var4 < 0) return 90.0F; + float var6 = var1 - MathHelper.sqrt_double(var4); + float var7 = (float) (Math.atan2(var6 , var2) * 180.0D / Math.PI); + return var7; + } +} \ No newline at end of file diff --git a/src/main/java/noppes/npcs/ai/EntityAISprintToTarget.java b/src/main/java/noppes/npcs/ai/EntityAISprintToTarget.java index b2bf7dfd0..1d615dff7 100644 --- a/src/main/java/noppes/npcs/ai/EntityAISprintToTarget.java +++ b/src/main/java/noppes/npcs/ai/EntityAISprintToTarget.java @@ -8,15 +8,15 @@ import noppes.npcs.entity.EntityNPCInterface; public class EntityAISprintToTarget extends EntityAIBase { /** The entity that is leaping. */ - EntityNPCInterface runner; + private EntityNPCInterface runner; /** The entity that the leaper is leaping towards. */ - EntityLivingBase runTarget; + private EntityLivingBase runTarget; public EntityAISprintToTarget(EntityNPCInterface par1EntityLiving) { this.runner = par1EntityLiving; - this.setMutexBits(AiMutex.PASSIVE + AiMutex.PATHING); + this.setMutexBits(AiMutex.PASSIVE); } /** @@ -37,9 +37,9 @@ public class EntityAISprintToTarget extends EntityAIBase else { switch(this.runner.ai.onAttack) - { - case 0 : return this.runner.getDistanceSqToEntity(this.runTarget) >= 64.0D ? (!this.runner.onGround ? false : true) : false; - case 2 : return this.runner.getDistanceSqToEntity(this.runTarget) <= 49.0D ? (!this.runner.onGround ? false : true) : false; + { + case 0 : return !this.runner.isInRange(runTarget, 8)? (!this.runner.onGround ? false : true) : false; + case 2 : return this.runner.isInRange(runTarget, 7)? (!this.runner.onGround ? false : true) : false; default : return false; } } diff --git a/src/main/java/noppes/npcs/ai/target/EntityAIClearTarget.java b/src/main/java/noppes/npcs/ai/target/EntityAIClearTarget.java index ab38f9feb..ca8a69f9c 100644 --- a/src/main/java/noppes/npcs/ai/target/EntityAIClearTarget.java +++ b/src/main/java/noppes/npcs/ai/target/EntityAIClearTarget.java @@ -16,19 +16,15 @@ public class EntityAIClearTarget extends EntityAITarget @Override public boolean shouldExecute(){ - target = taskOwner.getAttackTarget(); + target = npc.getAttackTarget(); if (target == null) return false; - - if(target instanceof EntityPlayer && ((EntityPlayer)target).capabilities.disableDamage) - return true; - - int distance = npc.stats.aggroRange * 2 * npc.stats.aggroRange; - if(npc.getOwner() != null && npc.getDistanceSqToEntity(npc.getOwner()) > distance){ - return true; + + if(npc.getOwner() != null && !npc.isInRange(npc.getOwner(), npc.stats.aggroRange * 2)){ + return true; } - - return npc.getDistanceSqToEntity(target) > distance; + + return npc.combatHandler.checkTarget(); } @Override diff --git a/src/main/java/noppes/npcs/entity/EntityNPCInterface.java b/src/main/java/noppes/npcs/entity/EntityNPCInterface.java index f37f333c6..eaf41ade2 100644 --- a/src/main/java/noppes/npcs/entity/EntityNPCInterface.java +++ b/src/main/java/noppes/npcs/entity/EntityNPCInterface.java @@ -66,7 +66,7 @@ import noppes.npcs.util.GameProfileAlt; import java.io.IOException; import java.util.*; -public abstract class EntityNPCInterface extends EntityCreature implements IEntityAdditionalSpawnData, ICommandSender, IRangedAttackMob, IBossDisplayData{ +public abstract class EntityNPCInterface extends EntityCreature implements IEntityAdditionalSpawnData, ICommandSender, IRangedAttackMob, IBossDisplayData { public ICustomNpc wrappedNPC; public static final GameProfileAlt chateventProfile = new GameProfileAlt(); @@ -80,6 +80,8 @@ public abstract class EntityNPCInterface extends EntityCreature implements IEnti public DataTransform transform; public DataTimers timers; + public CombatHandler combatHandler = new CombatHandler(this); + public String linkedName = ""; public long linkedLast = 0; public LinkedData linkedData; @@ -295,10 +297,10 @@ public abstract class EntityNPCInterface extends EntityCreature implements IEnti updateTasks(); updateHitbox(); } - setBoolFlag(this.getAttackTarget() != null, 4); + // setBoolFlag(this.getAttackTarget() != null, 4); setBoolFlag(!getNavigator().noPath(), 1); setBoolFlag(isInteracting(), 2); - + combatHandler.update(); onCollide(); } @@ -334,6 +336,12 @@ public abstract class EntityNPCInterface extends EntityCreature implements IEnti } } + @Override + protected void damageEntity(DamageSource damageSrc, float damageAmount){ + super.damageEntity(damageSrc, damageAmount); + combatHandler.damage(damageSrc, damageAmount); + } + public void updateClient() { NBTTagCompound compound = writeSpawnData(); compound.setInteger("EntityId", getEntityId()); @@ -661,19 +669,21 @@ public abstract class EntityNPCInterface extends EntityCreature implements IEnti removeTask(aiRange); aiLeap = aiAttackTarget = aiResponse = aiSprint = aiRange = null; + if (this.ai.canSprint) + this.tasks.addTask(this.taskCount++, new EntityAISprintToTarget(this)); + if (this.ai.onAttack == 1) this.tasks.addTask(this.taskCount++, aiResponse = new EntityAIPanic(this, 1.2F)); else if (this.ai.onAttack == 2) { this.tasks.addTask(this.taskCount++, aiResponse = new EntityAIAvoidTarget(this)); - this.setCanSprint(); } else if (this.ai.onAttack == 0) { this.setCanLeap(); - this.setCanSprint(); if (this.inventory.getProjectile() == null || this.ai.useRangeMelee == 2) { + System.out.println("checking this stuff"); switch(this.ai.tacticalVariant) { case Dodge : this.tasks.addTask(this.taskCount++, aiResponse = new EntityAIZigZagTarget(this, 1.0D, this.ai.tacticalRadius)); break; @@ -759,15 +769,7 @@ public abstract class EntityNPCInterface extends EntityCreature implements IEnti */ public void setCanLeap() { if (this.ai.canLeap) - this.tasks.addTask(this.taskCount++, aiLeap = new EntityAILeapAtTarget(this, 0.4F)); - } - - /* - * Branch task function for sprinting - */ - public void setCanSprint() { - if (this.ai.canSprint) - this.tasks.addTask(this.taskCount++, aiSprint = new EntityAISprintToTarget(this)); + this.tasks.addTask(this.taskCount++, aiLeap = new EntityAIPounceTarget(this)); } /* @@ -1063,6 +1065,8 @@ public abstract class EntityNPCInterface extends EntityCreature implements IEnti setHealth(getMaxHealth()); dataWatcher.updateObject(14, 0); // animation Normal dataWatcher.updateObject(15, 0); + + combatHandler.reset(); this.setAttackTarget(null); this.setRevengeTarget(null); this.deathTime = 0; @@ -1462,6 +1466,7 @@ public abstract class EntityNPCInterface extends EntityCreature implements IEnti this.motionY = 0.4000000059604645D; } } + @Override public void addVelocity(double p_70024_1_, double p_70024_3_, double p_70024_5_) { if (this.attackingPlayer != null) { @@ -1667,12 +1672,26 @@ public abstract class EntityNPCInterface extends EntityCreature implements IEnti super.setInWeb(); } + public boolean isInRange(Entity entity, double range){ + return this.isInRange(entity.posX, entity.posY, entity.posZ, range); + } + + public boolean isInRange(double posX, double posY, double posZ, double range){ + double y = Math.abs(this.posY - posY); + if(posY >= 0 && y > range) + return false; + + double x = Math.abs(this.posX - posX); + double z = Math.abs(this.posZ - posZ); + + return x <= range && z <= range; + } + @Override public boolean canBeCollidedWith(){ return !isKilled(); } - // obviously we dont want this @Override public boolean canBePushed() { return this.display.collidesWith == 0;