Jump to content

Using xPath to change quest rewards


OgreLXXV

Recommended Posts

I'm trying to change the quest rewards for all Challenges so they award only XP, but significantly more and based on difficulty. I know I could simply remove the quests and replace them with copies that have different rewards, but as I am working on my first mod this seems like an opportunity to learn how to "do it right" from the beginning.

 

My thought is that I should be able to do a conditional xPath for each of the difficulties, then use it to delete the rewards I don't want and change the Exp values to what I do want. For example I would find any node for a quest where the category_key="challenge" and the difficulty="hard", then find the reward where type="Exp" and change the value to 10000 or something. I should then be able to, in that same node, remove reward type="item" so that no Dukes are awarded. However, I am having a hard time figuring out the proper syntax. The AND to identify the correct nodes combined with trying to change a specific value in that node is too much for my rookie XML brain to wrap around. Here is what I have tried, but I know it isn't right. Any help would be greatly appreciated.

 

<set xpath="/quests/quest/property[@category_key='challenge'] and /quests/quest/property[@difficulty='hard']@reward type='Exp' @value='10000'" />

Link to comment
Share on other sites

Hey.

 

Since you're a beginner, I will give you some head massage with the theory...

 

First of all, what you're trying to achieve here is NOT an EASY task for beginners and the broken xpath in your example makes me feel like you will first need to learn how to use xpath commands properly. It's best if you can learn by example, so learning it by trying to write your own mod with it is a good way of doing it, just don't expect it will be simple, because you're trying to bite off a big chunk here lol...

 

Every time you're planning to make some changes to the files using xpath, it's always a very good idea to write a list of actions and changes that you plan to apply in the files, it's especially important when you need to perform such complex chain of changes like in this case. Really, write a 1,2,3... step by step list of planned changes. Then go through the list and in each step, check the xpath guide and try to find the xpath command that would be best for that particular step. There is literally everything you need in that guide, you just need to identify the individual parts that you need to work with and learn how to use the individual commands properly.

 

Xpath itself is just that path to the node you need to work with and it's written inside the quotes "". You can have only one xpath and one command in one go, although depending on the command and xpath, you can apply the desired change to multiple nodes at once, as the command will adjust all the data targeted by xpath.

Link to comment
Share on other sites

1 hour ago, mr.devolver said:

Hey.

 

Since you're a beginner, I will give you some head massage with the theory...

 

First of all, what you're trying to achieve here is NOT an EASY task for beginners and the broken xpath in your example makes me feel like you will first need to learn how to use xpath commands properly. It's best if you can learn by example, so learning it by trying to write your own mod with it is a good way of doing it, just don't expect it will be simple, because you're trying to bite off a big chunk here lol...

 

Every time you're planning to make some changes to the files using xpath, it's always a very good idea to write a list of actions and changes that you plan to apply in the files, it's especially important when you need to perform such complex chain of changes like in this case. Really, write a 1,2,3... step by step list of planned changes. Then go through the list and in each step, check the xpath guide and try to find the xpath command that would be best for that particular step. There is literally everything you need in that guide, you just need to identify the individual parts that you need to work with and learn how to use the individual commands properly.

 

Xpath itself is just that path to the node you need to work with and it's written inside the quotes "". You can have only one xpath and one command in one go, although depending on the command and xpath, you can apply the desired change to multiple nodes at once, as the command will adjust all the data targeted by xpath.

Thank you? I appreciate that this is complicated, and as I mentioned in the OP, I felt that learning by doing would be the best way to get my head wrapped around it. I have read through the guide you linked of course, as well as others and watched a few videos. I am starting from scratch, but the challenge is the fun part and makes success all the more rewarding to me. Unfortunately while I can see a few commands that would apply in the guides, I don't see a good example of how to apply them in the way I am trying to. What I was hoping to get here would be a suggestion as to how I could proceed. As you said, learn by example. Seeing an example then allows me to use and adapt it later. Instead what I am hearing is, "That's hard. Good luck."

I have been playing 7dtd for several years, but just created a forum account a few days ago as I have begun this trek toward making my own mod. If asking such ridiculous questions as "can any one help me understand" is not what these forums are for, I apologize for my ignorance and will look elsewhere for assistance in my learning process.

Link to comment
Share on other sites

10 minutes ago, OgreLXXV said:

Thank you? I appreciate that this is complicated, and as I mentioned in the OP, I felt that learning by doing would be the best way to get my head wrapped around it. I have read through the guide you linked of course, as well as others and watched a few videos. I am starting from scratch, but the challenge is the fun part and makes success all the more rewarding to me. Unfortunately while I can see a few commands that would apply in the guides, I don't see a good example of how to apply them in the way I am trying to. What I was hoping to get here would be a suggestion as to how I could proceed. As you said, learn by example. Seeing an example then allows me to use and adapt it later. Instead what I am hearing is, "That's hard. Good luck."

I have been playing 7dtd for several years, but just created a forum account a few days ago as I have begun this trek toward making my own mod. If asking such ridiculous questions as "can any one help me understand" is not what these forums are for, I apologize for my ignorance and will look elsewhere for assistance in my learning process.

I'm sorry if what I wrote sounded harsh, but the way you wrote your post, it sounded like you're looking for a general guidance that would help you learn how to work with xpath and so that was the way I tried to help you. By learning by example, I literally meant learning by creating this mod. If someone wrote the actual code for you, where would be the challenge? ;)

 

You need to plan this in advance if you want to succeed, so write that list of actions, like a step by step process and try to figure out the correct command and correct xpath for each step. Don't proceed to the next step before being absolutely sure that the current step is coded and working correctly. That way you will save yourself from headaches trying to figure out which part of your long code does not work. In each step, try different kinds of xpaths until you learn how to write a correct one - this is where you will have it much harder than many others before you, because you chose a mod which will require little more complex xpaths to make it work, so figuring it out without prior knowledge will not be easy.

 

SphereII's guide actually gives several examples for xpaths thanks to which you should be able to figure out how the xpath works and most importantly how to write your own xpaths. The thing is, you only need to get familiar with the individual commands like set, append, remove, etc. and how they work, what these commands do is well explained for each one of them. As for the xpath itself (not the command), all you need to know is that its syntax is just a general set of rules you need to follow to make it work, which is why any xpath example you will find in the guide can be re-used with other commands as well and not just with that one command that one xpath was used with in the guide, don't let that fool you lol. Think of xpath as of an advanced path that lets you navigate through the structure of xml code and allows you to specify the part of code you're trying to target, but it's always defined with the same rules or xpath commands if you will, which means that the individual nodes and whatever code is contained within them may have different names in your xpath (compared to the examples in the guide), but it's always targeted in the same fashion, using the same rules. It is up to you how exactly you define the xpath, as long as your xpath targets the exact spot in the code that you're trying to target and modify...

 

What I mean by this, is basically that you have one code you need to modify in several different ways. For example, you want to append something into that node and you also have to change some value in the same node. There will be two different commands with two separate xpaths, BUT the difference in the xpath will be negligible.

 

Example (from SphereII's guide):

<set xpath="/lootcontainers/lootcontainer[@id='62']/@size">7,6</set>

This goes into lootcontainers, looks for a lootcontainer with id 62 and in this lootcontainer changes value called "size" to 7,6.

 

As you may already know, lootcontainers contain loot items either directly or from a loot group. So let's say you would want to append your own loot into the same lootcontainer with id 62. How would you write it?

<append xpath="/lootcontainers/lootcontainer[@id='62']">
	<YOUR NEWLY ADDED LOOT GOES HERE>
</append>

See? The command changed from set to append, BUT the only difference in the xpath itself is that in this append case we removed the last part "/@size" as that really targeted the value called "size" in our previous set command.

 

I hope this gives you an idea how to read SphereII's guide.

 

Going back to the plan / list of actions you want to perform with the file, in case you end up having a trouble with some commands or xpath in the individual steps of your plan, feel free to come back here and write what exactly you were trying to achieve in that particular step you had problem with and also write your best lines of code you could come up with in that particular step and then I might be able to tell you why it didn't work and perhaps suggest how to fix the problem if you absolutely give up trying to figure it out on your own lol

Link to comment
Share on other sites

I honestly feel like I'm being trolled at this point. But just in case I am completely misunderstanding the tone and this is not in fact a condescending attempt to educate my poor little child brain on how to learn a new skill, I will ask my original question in another way.

How do I use xpath to change the quest reward for all Hard difficulty Challenges to award Exp in the amount of 10,000 and nothing else?

More generically how do I change specific values for a group of quests, such as Hard Challenges, but not for all quests or even all Challenges or Hard quests? It's easy enough to simply remove the entire quest node and replace it with a new one that has my reward changes, but I am trying to do this the "proper" way and change the specific values. I am having a hard time finding any good examples of how to identify a specific element within a defined group of nodes. I assume I need to use the AND operator on multiple levels, but the structure doesn't make sense with what I am trying to do, since the identifying properties are on the same relationship level. I am looking for nodes that have specific sibling property values, then changing other sibling values, rather than values with a parent/child relationship. Seeing the code itself, how would someone who knows what they are doing write it, gives me a visual aid that I can then first dissect and then adapt to use in similar ways. So I am asking for the actual code, not a suggestion on how to learn xpath.

Again, if this is not an appropriate question, or if I am in the wrong place, then I apologize. My assumption was that the Suggestions and Requests subforum under Modding would be the right place to ask. As the only response I seem to be getting is to go figure it out on my own (see: git gud) I am getting the impression that my original assumption was woefully inaccurate.

Link to comment
Share on other sites

Speaking theoretically as I didn't test if it works at all, but here it goes:

 

The stuff starting with '<' are nodes, like '<property ' for example. They are adressed in xpath with "/property/" wheras attributes are adressed with "@category_key".

 

You want to do changes to quest, not to the property with the attribute category_key.

 

This:

 

"<set xpath="/quests/quest/property[@category_key='challenge']"

 

says to make changes to the property, not the quest, but you don't want that.

 

This:

 

"<set xpath="/quests/quest[/property/@category_key='challenge']" 

 

says to make changes to quest, where a property with category_key challenge exists. At least how I understand XPATH.

 

So: Test it, my knowledge in xpath is incomplete and rusty and may not even  be correct. Try to do an easy append first to just test if you really got all quests with the right property selected.

Then in a next step add the "and" condition and see if it still works as expected and you now only got quests with both conditions true.

Finally try to really change the exact property you wanted to change (You probably have to add the "property" that you removed before the condition to after the condition).

 

This may be what Mr.Devolver was trying to say, that you have to develop complex lines step by step.

 

PS: When asking questions you might also post the xml you want to change so people don't need to look up the xml.

 

 

Link to comment
Share on other sites

Hi Ogre,

First of all, don't let anyone discourage you from pursuing this!

 

To answer your question, the XPath you need is:

<set xpath="/quests/quest/property[@name='category_key'][@value='challenge']/../property[@name='difficulty'][@value='hard']/../reward[@type='Exp']/@value">10000</set>

Now, let's break down the xpath and figure out what's going on here:

 

  • `/quests/quest`
    • This will fetch all quests. Not very useful so let's be more specific.
  • `/quests/quest/property[@name='category_key'][@value='challenge']`
    • This will find all `<property>` nodes with `name='category_key'` and `value='challenge'`. Now we don't really want these, we actually want their parents (which are the entire quests), so we need to go up one element. That's easy, the notation of going `up` is just '..', so let's grab those
  • `/quests/quest/property[@name='category_key'][@value='challenge']/..`
    • Great, we have all quests that are challenges. However, we want only those who are with "hard" difficulty. Instead of some clever shenanigans we can simply repeat the filtering for property but this time with hard difficulty
  • `/quests/quest/property[@name='category_key'][@value='challenge']/../property[@name='difficulty'][@value='hard']`
    • It looks like we took a step back, as we again have a collection of `<property>` elements, but they are only from hard challenges now. So we go up an element with the `..` and since we're interested in the reward, we can directly grab that as well
  • `/quests/quest/property[@name='category_key'][@value='challenge']/../property[@name='difficulty'][@value='hard']/../reward`
    • Now, we have a list of all <reward> elements, but some challenges have more than 1, so we need to be specific. We're looking for the experience one, so we just specify it
  • `/quests/quest/property[@name='category_key'][@value='challenge']/../property[@name='difficulty'][@value='hard']/../reward[@type='Exp']`
    • Almost there. We have the rewards we're looking for, but we don't want to edit the entire element, but just it's `value` attribute. Now, as others outlined, you access attributes by prefixing them with `@` so let's go ahead and fetch the value attribute:
  • `/quests/quest/property[@name='category_key'][@value='challenge']/../property[@name='difficulty'][@value='hard']/../reward[@type='Exp']/@value`
    • And we're here. Now all that's left is to patch this up into the `<set>` element TFP provided and we're good to go.

 

I suggest you pick up a code editor that understands XML and XPath, so that you can evaluate it as you go. There are A LOT out there, I personally use Visual Studio Code with the XML Tools plugin, though it's not the best for a beginner. It does have the "Evaluate XPath" command which is more than enough for me.

 

Hope this helps and happy modding!

Link to comment
Share on other sites

2 hours ago, OgreLXXV said:

I honestly feel like I'm being trolled at this point. But just in case I am completely misunderstanding the tone and this is not in fact a condescending attempt to educate my poor little child brain on how to learn a new skill, I will ask my original question in another way.

How do I use xpath to change the quest reward for all Hard difficulty Challenges to award Exp in the amount of 10,000 and nothing else?

More generically how do I change specific values for a group of quests, such as Hard Challenges, but not for all quests or even all Challenges or Hard quests? It's easy enough to simply remove the entire quest node and replace it with a new one that has my reward changes, but I am trying to do this the "proper" way and change the specific values. I am having a hard time finding any good examples of how to identify a specific element within a defined group of nodes. I assume I need to use the AND operator on multiple levels, but the structure doesn't make sense with what I am trying to do, since the identifying properties are on the same relationship level. I am looking for nodes that have specific sibling property values, then changing other sibling values, rather than values with a parent/child relationship. Seeing the code itself, how would someone who knows what they are doing write it, gives me a visual aid that I can then first dissect and then adapt to use in similar ways. So I am asking for the actual code, not a suggestion on how to learn xpath.

Again, if this is not an appropriate question, or if I am in the wrong place, then I apologize. My assumption was that the Suggestions and Requests subforum under Modding would be the right place to ask. As the only response I seem to be getting is to go figure it out on my own (see: git gud) I am getting the impression that my original assumption was woefully inaccurate.

Learning how to write your own xpath, so that you will be able to write your own in your future projects without needing anyone's help is not the same as just skipping the learning process entirely and asking people to write the actual code for you which now seems to be what you're looking for.

 

While in both cases you would be in the right place here, I was under impression that you're looking for help with the former - learning how to write your own xpath by yourself. I offered you a solution to your modding problem in my long posts, I even gave you an example of xpath in order to illustrate the difference between two separate commands and the negligible change in the xpath between them, then I proposed that if you tried a specific approach by learning from the plenty of xpath examples in the SphereII's guide and tried to adapt what you learn there to your own situation by trying to write your own code, I would then gladly tell you which part of your code works and which part needs to be fixed and how to fix it, if you showed me the actual code that you already tried.

 

If you wanted to skip all of this and just get someone to write the final working code for you, that would be a request for a mod to be created for you, not a request to get help with learning how to write that code by yourself! You were given plenty of examples of xpath you could try by yourself and experiment with to learn how it all works, if you were really serious about learning it, you would be experimenting with your own code by now, not accusing someone of trolling when in reality they're spending their own spare time trying to help you. Enough is enough. Have a nice day...

Link to comment
Share on other sites

1 hour ago, axtroz said:

Hi Ogre,

First of all, don't let anyone discourage you from pursuing this!

 

To answer your question, the XPath you need is:


<set xpath="/quests/quest/property[@name='category_key'][@value='challenge']/../property[@name='difficulty'][@value='hard']/../reward[@type='Exp']/@value">10000</set>

Now, let's break down the xpath and figure out what's going on here:

 

  • `/quests/quest`
    • This will fetch all quests. Not very useful so let's be more specific.
  • `/quests/quest/property[@name='category_key'][@value='challenge']`
    • This will find all `<property>` nodes with `name='category_key'` and `value='challenge'`. Now we don't really want these, we actually want their parents (which are the entire quests), so we need to go up one element. That's easy, the notation of going `up` is just '..', so let's grab those
  • `/quests/quest/property[@name='category_key'][@value='challenge']/..`
    • Great, we have all quests that are challenges. However, we want only those who are with "hard" difficulty. Instead of some clever shenanigans we can simply repeat the filtering for property but this time with hard difficulty
  • `/quests/quest/property[@name='category_key'][@value='challenge']/../property[@name='difficulty'][@value='hard']`
    • It looks like we took a step back, as we again have a collection of `<property>` elements, but they are only from hard challenges now. So we go up an element with the `..` and since we're interested in the reward, we can directly grab that as well
  • `/quests/quest/property[@name='category_key'][@value='challenge']/../property[@name='difficulty'][@value='hard']/../reward`
    • Now, we have a list of all <reward> elements, but some challenges have more than 1, so we need to be specific. We're looking for the experience one, so we just specify it
  • `/quests/quest/property[@name='category_key'][@value='challenge']/../property[@name='difficulty'][@value='hard']/../reward[@type='Exp']`
    • Almost there. We have the rewards we're looking for, but we don't want to edit the entire element, but just it's `value` attribute. Now, as others outlined, you access attributes by prefixing them with `@` so let's go ahead and fetch the value attribute:
  • `/quests/quest/property[@name='category_key'][@value='challenge']/../property[@name='difficulty'][@value='hard']/../reward[@type='Exp']/@value`
    • And we're here. Now all that's left is to patch this up into the `<set>` element TFP provided and we're good to go.

 

I suggest you pick up a code editor that understands XML and XPath, so that you can evaluate it as you go. There are A LOT out there, I personally use Visual Studio Code with the XML Tools plugin, though it's not the best for a beginner. It does have the "Evaluate XPath" command which is more than enough for me.

 

Hope this helps and happy modding!

This is fantastic, thank you! Seeing how you did it helps me to understand where I was going wrong. Since it's all new to me, I'm learning both the concept and the proper syntax, so we're killing both birds with this stone. I believe that the roadblock I kept hitting was backup up to the parent after using the category_key and difficulty properties to identify the correct quests. This is immensely helpful, thanks again.

Link to comment
Share on other sites

FYI, after playing with this I realized that it was selecting effectively all quests, since it appears they all use the category_key of "challenge" with just a few exceptions. My goal was to change the Challenge Quests to award better experience, tiered by difficulty, but also remove any other rewards for them. This is a small part of my overall mod vision, but a huge step forward in my understanding of how to make it happen. Using the example provided and the clear breakdown of what it means, I was able to modify the code to accomplish exactly what I wanted.

    <set xpath="/quests/quest[contains(@id,'challenge')]/property[@name='difficulty'][@value='easy']/../reward[@type='Exp']/@value">1000</set>
    <set xpath="/quests/quest[contains(@id,'challenge')]/property[@name='difficulty'][@value='medium']/../reward[@type='Exp']/@value">2500</set>
    <set xpath="/quests/quest[contains(@id,'challenge')]/property[@name='difficulty'][@value='hard']/../reward[@type='Exp']/@value">10000</set>
    <set xpath="/quests/quest[contains(@id,'challenge')]/property[@name='difficulty'][@value='insane']/../reward[@type='Exp']/@value">25000</set>
    <remove xpath="/quests/quest[contains(@id,'challenge')]/reward[@type='Item']"></remove>

 

Once again, thank you for the help on this. I now have a much greater understanding of how xPath operates within a node.

Link to comment
Share on other sites

Archived

This topic is now archived and is closed to further replies.

×
×
  • Create New...