HalestormXV Posted August 23, 2015 Posted August 23, 2015 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? Quote
Tyron Posted August 23, 2015 Posted August 23, 2015 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 Quote
HalestormXV Posted August 23, 2015 Author Posted August 23, 2015 No such luck. I really feel like I am overlooking something so simple and it is just due to my ignorance. Quote
HalestormXV Posted August 25, 2015 Author Posted August 25, 2015 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. Quote
jabelar Posted August 25, 2015 Posted August 25, 2015 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. Quote Check out my tutorials here: http://jabelarminecraft.blogspot.com/
HalestormXV Posted August 25, 2015 Author Posted August 25, 2015 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. Quote
UberAffe Posted August 25, 2015 Posted August 25, 2015 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. Quote Current Project: Armerger Planned mods: Light Drafter | Ore Swords Looking for help getting a mod off the ground? Coding | Textures
coolAlias Posted August 25, 2015 Posted August 25, 2015 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 Quote http://i.imgur.com/NdrFdld.png[/img]
HalestormXV Posted August 25, 2015 Author Posted August 25, 2015 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. Quote
coolAlias Posted August 26, 2015 Posted August 26, 2015 If you want the player's experience to decrease with time rather than as an initial cost, then what you're doing is pretty much the only way. Doing it in your entity's onUpdate method is the right way to go. Nothing wrong with doing it each tick, either, when that's what's called for. Quote http://i.imgur.com/NdrFdld.png[/img]
HalestormXV Posted August 26, 2015 Author Posted August 26, 2015 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. Quote
SanAndreaP Posted August 26, 2015 Posted August 26, 2015 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 Quote 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.
HalestormXV Posted August 27, 2015 Author Posted August 27, 2015 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? Quote
coolAlias Posted August 27, 2015 Posted August 27, 2015 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. Quote http://i.imgur.com/NdrFdld.png[/img]
HalestormXV Posted August 27, 2015 Author Posted August 27, 2015 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. Quote
coolAlias Posted August 27, 2015 Posted August 27, 2015 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. Quote http://i.imgur.com/NdrFdld.png[/img]
HalestormXV Posted August 27, 2015 Author Posted August 27, 2015 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? Quote
coolAlias Posted August 27, 2015 Posted August 27, 2015 Sounds about right - best way to find out is to try it! May want to use 'this.setDead()' though, rather than removing it from the world manually. Quote http://i.imgur.com/NdrFdld.png[/img]
HalestormXV Posted August 27, 2015 Author Posted August 27, 2015 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. Quote
coolAlias Posted August 27, 2015 Posted August 27, 2015 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. Quote http://i.imgur.com/NdrFdld.png[/img]
HalestormXV Posted August 27, 2015 Author Posted August 27, 2015 Duly noted. Thank you for that heads-up. I was not aware of that and have fixed it. Quote
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.