jabelar Posted April 26, 2014 Posted April 26, 2014 Hi, I want to make an entity (an elephant) that rears up instead of fleeing when attacked. I know how to make complex model animations, so the actual rearing isn't hard -- to control it I just need a Boolean to indicate it isRearing and a rearingCounter to progress the animation through the cycle. So I don't need help with that. I have also set the knockbackResistance attribute to 1.0D so that it doesn't get knocked back. So I don't need help with that. However, for the life of me I can't get the EntityElephant to stop running away after being hit. I thought the fleeingTick variable was a clue based on its name and description, however I've overridden places where it is used and frankly after inspecting the vanilla code I don't think it really does much in terms of controlling the actual fleeing. There is only one place in the vanilla code where fleeingTick is even set (to 60) and if I override that and set it to other values it doesn't change the duration of the fleeing, so I'm pretty confident that isn't it (or enough). It seems that fleeingTick only controls whether the entity will try to attack, but doesn't control the actual duration it runs away. So then I figured that maybe overriding any sprinting would do it, but when the entity runs away it doesn't seem to test isSprinting as true (returns false even while entity is running away) so I guess the fleeing isn't counted as a type of sprint. It does seem that when it is fleeing it is using AIWander for the actual pathfinding and seems that it maybe overrides the movementSpeed attribute somehow. But basically I'm stuck and can't figure it out. I thought I could simply override the attackEntityFrom() method but it seems I'm missing something. I guess my main question is -- what is the field that controls/indicates that an Entity is fleeing? It seems to me that there is no such variable but rather it is a wander AI plus a movement modifier. Here is my attackEntityFrom() code, which is just lightly modified code from same method in EntityLivingBase class. (The fleeingTick = 1 is just my last attempt to control that variable, I tried 0 and also not setting it to anything, plus tried other values like 20 and 120 to see if it affected the length of the flight, but it didn't) /** * Called when the entity is attacked. */ @Override public boolean attackEntityFrom(DamageSource par1DamageSource, float parDamageAmount) { if (ForgeHooks.onLivingAttack(this, par1DamageSource, parDamageAmount)) return false; if (isEntityInvulnerable()) { return false; // not really "attacked" if invulnerable } else { if (worldObj.isRemote) // don't process attack on client side { return false; } else // on server side so process attack { fleeingTick = 1; // setting to 0 doesn't seem wise, because there is a decrement in super method if statement entityToAttack = null; resetInLove();; setRearing(true); // herd animals will rear when attacked entityAge = 0; if (getHealth() <= 0.0F) // not really "attacked" if already dead { return false; } else if (par1DamageSource.isFireDamage() && isPotionActive(Potion.fireResistance)) // fire resistance negates fire attack { return false; } else { if ((par1DamageSource == DamageSource.anvil || par1DamageSource == DamageSource.fallingBlock) && getEquipmentInSlot(4) != null) { getEquipmentInSlot(4).damageItem((int)(parDamageAmount * 4.0F + rand.nextFloat() * parDamageAmount * 2.0F), this); parDamageAmount *= 0.75F; } limbSwingAmount = 1.5F; boolean flag = true; if (hurtResistantTime > maxHurtResistantTime / 2.0F) { if (parDamageAmount <= lastDamage) { return false; } damageEntity(par1DamageSource, parDamageAmount - lastDamage); lastDamage = parDamageAmount; flag = false; } else { lastDamage = parDamageAmount; prevHealth = getHealth(); hurtResistantTime = maxHurtResistantTime; damageEntity(par1DamageSource, parDamageAmount); hurtTime = maxHurtTime = 10; } // process based on what is attacking attackedAtYaw = 0.0F; Entity entity = par1DamageSource.getEntity(); if (entity != null) { if (entity instanceof EntityLivingBase) // set revenge on any living entity that attacks { setRevengeTarget((EntityLivingBase)entity); } if (entity instanceof EntityPlayer) // identify attacking player or wolf with kill time determination { recentlyHit = 100; attackingPlayer = (EntityPlayer)entity; } else if (entity instanceof EntityWolf) { EntityWolf entitywolf = (EntityWolf)entity; if (entitywolf.isTamed()) { recentlyHit = 100; attackingPlayer = null; } } } if (flag) { worldObj.setEntityState(this, (byte)2); if (par1DamageSource != DamageSource.drown) { setBeenAttacked(); } if (entity != null) { double d1 = entity.posX - posX; double d0; for (d0 = entity.posZ - posZ; d1 * d1 + d0 * d0 < 1.0E-4D; d0 = (Math.random() - Math.random()) * 0.01D) { d1 = (Math.random() - Math.random()) * 0.01D; } attackedAtYaw = (float)(Math.atan2(d0, d1) * 180.0D / Math.PI) - rotationYaw; knockBack(entity, parDamageAmount, d1, d0); } else // not an entity that caused damage { attackedAtYaw = (int)(Math.random() * 2.0D) * 180; } } // play sounds for hurt or death String s; if (getHealth() <= 0.0F) // dead { s = getDeathSound(); if (flag && s != null) { playSound(s, getSoundVolume(), getSoundPitch()); } onDeath(par1DamageSource); } else // hurt { s = getHurtSound(); if (flag && s != null) { playSound(s, getSoundVolume(), getSoundPitch()); } } return true; } } } } Quote Check out my tutorials here: http://jabelarminecraft.blogspot.com/
acid1103 Posted April 26, 2014 Posted April 26, 2014 This may not help a ton, but I've found this in EntityCreature (of which all entities that flee are subclasses): public static final AttributeModifier field_110181_i = (new AttributeModifier(field_110179_h, "Fleeing speed bonus", 2.0D, 2)).setSaved(false); So, maybe if you trace that around, you can find where it's being used. For instance, in EntityAnimal: public boolean attackEntityFrom(DamageSource par1DamageSource, float par2) { if (this.isEntityInvulnerable()) { return false; } else { this.fleeingTick = 60; if (!this.isAIEnabled()) { IAttributeInstance iattributeinstance = this.getEntityAttribute(SharedMonsterAttributes.movementSpeed); if (iattributeinstance.getModifier(field_110179_h) == null) { iattributeinstance.applyModifier(field_110181_i); //It's being used right here! } } this.entityToAttack = null; this.inLove = 0; return super.attackEntityFrom(par1DamageSource, par2); } } Quote
jabelar Posted April 26, 2014 Author Posted April 26, 2014 On 4/26/2014 at 5:46 AM, acid1103 said: This may not help a ton, but I've found this in EntityCreature (of which all entities that flee are subclasses): public static final AttributeModifier field_110181_i = (new AttributeModifier(field_110179_h, "Fleeing speed bonus", 2.0D, 2)).setSaved(false); So, maybe if you trace that around, you can find where it's being used. For instance, in EntityAnimal: public boolean attackEntityFrom(DamageSource par1DamageSource, float par2) { if (this.isEntityInvulnerable()) { return false; } else { this.fleeingTick = 60; if (!this.isAIEnabled()) { IAttributeInstance iattributeinstance = this.getEntityAttribute(SharedMonsterAttributes.movementSpeed); if (iattributeinstance.getModifier(field_110179_h) == null) { iattributeinstance.applyModifier(field_110181_i); //It's being used right here! } } this.entityToAttack = null; this.inLove = 0; return super.attackEntityFrom(par1DamageSource, par2); } } Thanks. I actually already found that which is why I said "it is a wander AI plus a movement modifier." In fact if you compare my method code above with that vanilla code you posted, you'd see that I actually already deleted that portion of the code. Also, the code in vanilla seems to only execute if isAIEnabled() is false, but in my entity it is always true. I've found a lot of little things that are related, but not the actual variable that indicates it is fleeing. That is why I suspect that instead they are initiating an AIWander at a higher movement speed. The related variables I've found related to timing after an attack does damage are: fleeingTick seems to be a timer to prevent entity from attacking the player for 3 seconds after being hurt hurtResistanceTime seems to be a timer to prevent rapid hits hurtTime seems to be a timer for the red tint effect after entity is hurt recentlyHit seems to be a timer to determine how many drops the entity will give when it dies None of those seem to be used for any logic related to movement speed. I'm thinking that I'm going to poke around in the AIWander. I'll first try to confirm that it is invoked at that point, and if so, maybe I'll override it and create one where if it is hurt that the AIWander will be canceled. Quote Check out my tutorials here: http://jabelarminecraft.blogspot.com/
jabelar Posted April 26, 2014 Author Posted April 26, 2014 Actually, I solved it. There is actually an AI task on the entity called AIPanic. Removing that did the trick. I simply didn't know the word "panic" was something to search for ... Quote Check out my tutorials here: http://jabelarminecraft.blogspot.com/
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.