Jump to content

Recommended Posts

Posted

Alright, I have been posting some issues while coding my mod here and each and every time I have been able to solve it with the help of a post. And I thank you greatly to those of you that take the time to explain and correct my errors and nudge me in the right direction. I need assistance once more.

 

My mod is coming along nicely. I have managed to do what I deem, in my noobyness, to be some quite complicated things. However now I am stuck with something probably so basic. I created a new companion entity that the player can summon via an item. It works great, the entity gets summoned and follows you around. I basically just took the Wolf entity and changed it around. However I cannot seem to figure out how to set the entity's Strength.

 

Here is my entity class where everything is taken care of with the exception of setting the owner. (That is done in the item class used to summon this creature).

 

Entity Code: http://pastebin.com/VBMUrjuz

 

So that is the code. I have tried this.getEntityAttribute(SharedMonsterAttributes.attackDamage).setBaseValue(12.0D);

 

I imagine that happens because this is extending the Tameable class and not the Mob class which is fine. So then in doing some further search I cant seem to figure out where the attack damage for this entity is handled.

 

 

Personally i thought it was somewhere in here:

    public boolean attackEntityFrom(DamageSource targeted, float power)
    {
        if (this.isEntityInvulnerable())
        {
            return false;
        }
        else
        {
            Entity entity = targeted.getEntity();
            this.aiSit.setSitting(false);

            if (entity != null && !(entity instanceof EntityPlayer) && !(entity instanceof EntityArrow))
            {
                power = (power + 12.0F) / 2.0F;
            }

            return super.attackEntityFrom(targeted, power);
        }
    }

    public boolean attackEntityAsMob(Entity entity)
    {
        int i = this.isTamed() ? 4 : 2;
        return entity.attackEntityFrom(DamageSource.causeMobDamage(this), (float)i);
    }

 

But that doesn't seem to be it. So can anyone give me a shove in the right direct as to where I handle the entity's strength, or any other attributes that are valuable to know?

Posted

I can't look up the source code right now, but what I remember mobs harming entities is done in their respective Entity AI Tasks. I'd Check EntityAIAttackOnCollide and EntityAINearestAttackableTarget

Posted

I feel like an idiot bumping this. But right now I think I just need a confirmation. Does the function happen to control tameable mob damage be this.

    public boolean attackEntityAsMob(Entity entity)
    {
        int i = this.isTamed() ? 4 : 2;
        return entity.attackEntityFrom(DamageSource.causeMobDamage(this), (float)12.0F); //i
    }

 

entity.attackEntityFrom(DamageSource.causeMobDamage(this), (float)12.0F

 

And in my case I set that to 12 to indicate 6 hearts of damage. I ask because originally it was set to i.

 

Sorry for the bump and thanks in advanced.

Posted

Yes, attackEntityAsMob() is the right method.

 

Instead of hardcoding the 12, it is preferable to look up the attribute you set for attack damage. But hardcoding should work.

 

Isn't it working?

 

If it isn't doing any damage, then there are usually three places to look:

1) make sure you've set the attackDamage attribute. It sounds like you've done that.

2) make sure you've overridden the attackEntityAsMob() method. It sounds like you've done that.

3) make sure the entity is actually colliding when attacking -- as mentioned above you might need to check out your AI for collisions.

Check out my tutorials here: http://jabelarminecraft.blogspot.com/

Posted

Thank you. Yes it does seem to be working. I would rather not hard-code it to be quite honest as you stated. So this bring me to another point that perhaps I can get help with. I cannot seem to figure it out for the life of me. Rather than start a new thread I will just post it here as it is related to the same matter.

 

There are 12 different types of these creatures that you summon and they are all extending the tamable class. Rather than hardcode the damage value I would like to try and use a formula that take the current experience points of the owner and perhaps divide it by something so that the creature actually gets stronger the stronger you are. Where exactly or how exactly would I go about doing that?

 

I can't seem to figure out how to have the entity check via an onUpdate event what that entity's owner's experience points are. Then in that onUpdate event it would calculate what the current power of the entity is and return it in the attackEntityAsMob function.

 

Thanks in advanced.

Posted

Not positive if this would fix your problem but using either the onplayertick event or the onplayerxpgained event(thats probably not the name). Those should give you access to the player and somewhere, either in its own public class or as additional nbt info on the player you could store the pets it has, then you would have access to both the player and the pet and you could do what you need with them.

Current Project: Armerger 

Planned mods: Light Drafter  | Ore Swords

Looking for help getting a mod off the ground? Coding  | Textures

Posted

You shouldn't need to calculate it every tick, only when the entity actually attacks. If you copied / mimicked EntityWolf, then your Entity should have a method like #getOwner that returns the player who owns it. You can use that method at any time, such as when your entity is attacking, to get the owner and thereby any information about the owner that you want.

 

Roughly:

@Override
public boolean attackEntityAsMob(Entity entity) {
// get the base damage from your entity's attributes, if you added that attribute
// if not, just start with a base of 2.0F or something
float damage = (float) getEntityAttribute(SharedMonsterAttributes.attackDamage).getAttributeValue();
EntityLivingBase owner = this.getOwner();
if (owner instanceof EntityPlayer) {
  EntityPlayer player = (EntityPlayer) owner;
  // now you've got the player owner - go to town modifying the damage
}
// finally, attack the target entity with the adjusted damage amount

Never calculate something every tick if you can get away with calculating it only when it needs to be used ;)

Posted

Outstanding! That seems to work exactly how I wanted. I had to change up the code because it seems that the EntityTameable class does not like the:

float damage = (float) getEntityAttribute(SharedMonsterAttributes.attackDamage).getAttributeValue();

 

So by simply defining float damage without the EntityAttribute it worked. Here is the updated FULL entity class: http://pastebin.com/6ra1ewWn

 

Now the next question and this will probably finish up my entity inquiry. I want the entity to have a cost to stay summoned. Now I don't exactly want this to be subtracted every tick. May I want to have it subtracted every two seconds or so, and then once it reaches a certain threshold the entity despawns itself.

 

If my guess is correct, I know the general makeup will be something along the lines of

public void onUpdate()
{
	super.onUpdate();
	EntityLivingBase owner = this.getOwner();
	this.iAmF = this.iAmE;
	if (owner instanceof EntityPlayer) 
	{
		EntityPlayer player = (EntityPlayer) owner;
		player.addExperienceLevel(-ariesSummonCost);
		if (player.experienceTotal < ariesSummonCost)
		{
			this.worldObj.removeEntity(this);
		}
	}

	if (this.watchingYou())
	{
		this.iAmE += (1.0F - this.iAmF) * 0.4F;
	}
	else
	{
		this.iAmF += (0.0F - this.iAmE) * 0.4F;
	}

	if (this.watchingYou())
	{
		this.numTicksToChaseTarget = 10;
	}
}

 

But reading your statement above that probably isn't the most efficient way to go about it (althought that code does work and subtracts 1 EXP level every tick). So how could I make it so that this summon cost is only applied every two seconds or four seconds or so, or in minecraft terms every 40 or 80 ticks? In doing my searching I imagine this would have to do something relating to a tick handler? As I am still new to this I really am trying to find where to start. I did find this tutorial, actually by you coolAlias lol

http://www.minecraftforum.net/forums/mapping-and-modding/mapping-and-modding-tutorials/1571567-forge-1-6-4-1-8-eventhandler-and

 

But in summary, how would I go about doing that so that it only happens every 4 seconds while the entity is spawned? I do apologize but I am trying to learn. So any examples would be most beneficial, or even a code with comments so I can learn from it.

Posted

Ultimately I'd like to try and have it be called every 4 seconds instead of every tick. So every 4 seconds or 80 ticks their, the player, EXP level drops by 1.

 

However, if it is more effective and efficient to do it during the onUpdate than that is fine as I can just adjust to cost to compensate. Ultimately that would result in the player losing .25 EXP per tick which when calculated would be 1 EXP every 4 seconds. The only problem is that the XP functions only take intergers so I can't decrease them by decimals. And yes I know that the numbers we see are not the "actual" values. So like 3000XP might actually be level 43 but I am just speaking using these terms to make it clear.

 

So I guess my question now becomes is their really no way to do this via a Tickhandler so that the cost is removed every 4 seconds? And if so then how can I set it up so that the player is losing XP at a much slower rate than every tick be it subtracting decimals or what have you.

Posted

Ultimately that would result in the player losing .25 EXP per tick which when calculated would be 1 EXP every 4 seconds.

 

Uhhh... that would result in having the player lose 20 EXP every 4 sec.

 

Anyways, since you're using the entitys onUpdate, here's how to do it (pseudocode):

 

if this.ticksExisted % 80 == 0 then
    reduce player XP by 1
end

Don't ask for support per PM! They'll get ignored! | If a post helped you, click the "Thank You" button at the top right corner of said post! |

mah twitter

This thread makes me sad because people just post copy-paste-ready code when it's obvious that the OP has little to no programming experience. This is not how learning works.

Posted

Interesting way to do that. I didn't know you were able to measure how long the tick has existed for. However, inquiry, would it be more effective to write a loop into that method that increases an integer, and once the integer reaches a certain amount it reduces the player level and then the integer resets back to 0?

Posted

Interesting way to do that. I didn't know you were able to measure how long the tick has existed for. However, inquiry, would it be more effective to write a loop into that method that increases an integer, and once the integer reaches a certain amount it reduces the player level and then the integer resets back to 0?

No no no - definitely DO NOT write a loop.

public void onUpdate() { // executes each tick
for (int i = 0; i < 80; i++) {
  // now you are looping 80 times every tick...
}

Unless you meant have a class field for the counter, and increment that counter ONCE each tick during onUpdate until it reaches 80, at which point you subtract XP and reset the counter to 0 - THAT would be okay, and probably more efficient than using the modulo operator all the time, but not in a performance-telling sort of way.

Posted

Correct I meant in this way:

 

public int costCounter;

public void onUpdate() { // executes each tick
{
  costCounter += 1
  if (costCounter = 80){
      costCounter == 0;
      player.addExperienceLevel(-ariesSummonCost);
	if (player.experienceTotal < ariesSummonCost)
		{
			this.worldObj.removeEntity(this);
		}
}

}

 

I wasn't talking about looping in the onUpdate no. Is this method better than checking the tickLife?

 

NOTE: I might have some missing signs or incorrect signs in that sample as I typed the answer from my phone.

Posted

Is this method better than checking the tickLife?

As I said in my last reply, they are basically identical, though this one technically should have better performance than a modulo operation (since in the worst case modulo takes more work to calculate as ticksExisted increases toward infinity, but most implementations aren't that bad).

 

Anyway: pre-mature optimization. Use whichever one you want - you won't notice the difference, and neither will the computer.

Posted

Fantastic, now my probably one last final question is. If the owner of this entity disconnects or logs out I want this entity to despawn as it is not meant to be like a wolf and stay persistent. Now I know this probably has something to do with forge's events, but any guidance on how to take care of that? Or maybe I don't need the forge events at all and perhaps i can also take care of this in the onUpdate so that it checks in on the tick since I already have the owner referenced? I think once I can get that it will clean up this entity class nicely and I can finish it off.

 

My thought is since I am not writing this entity to NBT (I took it out of the code) once the user logs off teh server that user/owner becomes null? In which case I can just call a check and if null then call this.worldObj.removeEntity(this);

 

or is my thinking totally off?

Posted

Woohoo, thank you truly to everyone who helped me with this. I learned a TON from it. I am happy to report that it works wonderfully. Including the cleanup method if the user disconnects. Hopefully it will perform the same on a server.

 

Here is the finished class for those interested: http://pastebin.com/CWST7B4X

 

My mod uses EXP as an energy source. Please let me know if you think I could optimize this code in anyway. As I said I am new to all of this and am learning as I go. So my code may not be the most efficient but that is part of my learning curve.

Posted

Just an FYI: since you commented out the read/writeNBT methods entirely, you are not actually overriding them to do nothing, but instead allowing the super class version of those methods to be called.

 

Now I don't recommend doing this, as some parts of the game engine probably rely on the entity being able to write to and read from NBT, but to actually prevent the method from doing anything, you'd need to do this:

@Override
public void writeEntityToNBT(NBTTagCompound tag) {
  // leave this completely empty
}

@Override
public void readEntityFromNBT(NBTTagCompound tag) {
  // leave this completely empty
}

Again, I don't recommend that, but you should know that your code isn't doing quite what you seem to think it is, nor does it need to. Killing the entity when the owner is null is perfectly effective at preventing it from remaining in the game.

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.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Announcements



×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.