Dialog conditionals help
#1
Posté 21 décembre 2009 - 05:53
The problem I have right now is how to make the plot flag system check for multiple conditions.
Example: I have a simple quest, a guard asks the player to clear out some rats from 2 places. I have 3 plot flags (main, not defined ... not sure the difference ... HAS_RATQUEST, RATS_KILLED1, RATS_KILLED2). If you do the quest, it works. BUT, the line the NPC speaks for the old parts of the quest always appears, which looks silly.
Here are the NPCs 3 lines of text (simplified)
** Help me kill rats (conditional checks to see if quest has been accepted)
** You killed that first rat, good job, please help me kill another rat (conditional checks to see rat1 is dead)
** Great, you killed both sets of rats, have Starfang as my thanks (conditional checks to see if rat 2 is dead)
The problem is that the last 2 two lines appear if the quest is complete ... is there any way to check for multiple conditions using plot flags? Or do you have to set up a separate plot flag that combines those conditions?
Do I need a another flag and set it to true if both sets of rats are dead? If so, that seems like extra work ... and just writing your own conditionals would be easier. If you had 5 groups of rats, it would be chaos!
Or am I missing something simple?
Thanks.
#2
Posté 21 décembre 2009 - 06:26
I also asked about the "kill 5 rats" thing too. He said if the goal was to kill ALL 5 rats then you should make them a "team" and somehow killing the team can be made to set a plot flag. Or if it is to kill ANY 5 rats out of a crowd of rats, then... I forget what he said. Maybe make a local variable called rat_counter and increment it in the DYING event.
For your specific situation, I would think you need a rat counter stored somewhere.
Modifié par FalloutBoy, 21 décembre 2009 - 06:29 .
#3
Posté 21 décembre 2009 - 06:31
The simplest way is have the rat groups only be killable in a specific order. Then, use different NPC conversation branches in inverse chronological order. Each one only needs to check for one group killed, since they have to be killed in order.
If they can be killed in any order, and what's significant is if you've killed one or if you've killed both, there are two ways to do that.
One is to put the logic in the team death scripts. Have a plot flag for team A being dead, a flag for team B being dead, a flag for at least one team being dead and a flag for both teams being dead. In the team death event after setting the A or B flag, check if the other team's flag has already been set. If not, set the at least one flag. If so, set the both flag. If for some reason ordering the NPC lines in inverse chronological order is not sufficient, you could rename the at least one flag to exactly one and unset it when you set the both flag.
The other way is to put the logic in defined conditions. I think this is what you've been missing. To make a defined condition, make a defined flag instead of a main flag. Defined flags cannot be set, and the flag itself has no true/false value. Instead, checking a defined flag runs the plot script, and within the appropriate case statement you put whatever logic you want and return TRUE or FALSE.
The easiest way to see how plot scripts work, if you're having trouble, is to open an existing one. There should be a few examples in the cores scripts, including ones with defined conditions. You can also look at the plot script template. The defined conditions are in the second half of the script, after the actions.
#4
Posté 21 décembre 2009 - 06:42
If someone from the BioWare is reading this... What's the status of GetConversationEntryParameter() ? The section referred above is saying that it was not operational during the release of the Toolset.
A script called by a line of the conversation can be passed an integer as a parameter, which is retrieved by the function GetConversationEntryParameter. Note that as of November 18 this function is not currently functional. A patch will be needed for the game executable to repair this.
Modifié par BioSpirit, 21 décembre 2009 - 07:02 .
#5
Posté 21 décembre 2009 - 07:00
switch(nFlag)
{
case PLOT_KILLED_SOME_RATS:
{
UT_IncLocalInt(RATS_KILLED); // Increment number of rats killed
if (GetLocalInt(RATS_KILLED)=5) WR_SetPlotFlag(PLOT_KILLED_ALL_RATS);
}
}
Now if you set the plot flag PLOT_KILLED_SOME_RATS every time you kill a rat (evenif it's already set) it could fire the plot script and count the rats.
#6
Posté 21 décembre 2009 - 07:14
BioSpirit wrote...
I am not sure does this work but how about someting like this:switch(nFlag)
{
case PLOT_KILLED_SOME_RATS:
{
UT_IncLocalInt(RATS_KILLED); // Increment number of rats killed
if (GetLocalInt(RATS_KILLED)=5) WR_SetPlotFlag(PLOT_KILLED_ALL_RATS);
}
}
Now if you set the plot flag PLOT_KILLED_SOME_RATS every time you kill a rat (evenif it's already set) it could fire the plot script and count the rats.
I see a few potential problems with the above script. One is that UT_IncLocalInt must be using OBJECT_SELF because no object parameter is specified. You have no idea what OBJECT_SELF is going to be when running a plot script, since the flag could be set from anywhere. Second, RATS_KILLED is not a variable defined in any default variables list. You'd have to make a new variables 2da or add it to an existing one. You could use a default variable like CREATURE_COUNTER_1, but then you have to be careful you're not using that variable for anything else.
If you want to detect when 5 rats are dead, the easiest thing to do is put them in a team, and when they are all dead a TEAM_DESTROYED event will be fired to the area. The player would be forced to kill all the rats rather than just some of them, and you're limited to one area, but otherwise it's a very easy way to script this.
Due to the limitations of local variables I would only use that method as a last resort. Instead, if I needed to overcome the above limitations, I would make 5 plot flags and use them as a counter. Plot flags don't rely on OBJECT_SELF, they don't require variables be declared in a 2da, there's no risk of double purposing an existing variable and they can be set/checked in any area.
Modifié par DavidSims, 21 décembre 2009 - 07:15 .
#7
Posté 21 décembre 2009 - 08:46
DavidSims wrote...
Due to the limitations of local variables I would only use that method as a last resort. Instead, if I needed to overcome the above limitations, I would make 5 plot flags and use them as a counter. Plot flags don't rely on OBJECT_SELF, they don't require variables be declared in a 2da, there's no risk of double purposing an existing variable and they can be set/checked in any area.
So let's say you made 5 plot flags, one per rat. Would you also make a defined flag called ALL_RATS_DEAD and in your plot script for this flag, return TRUE if your 5 plot flags are all TRUE?
I think maybe I finally understand what a defined flag is. :happy:
#8
Posté 21 décembre 2009 - 10:59
FalloutBoy wrote...
DavidSims wrote...
Due to the limitations of local variables I would only use that method as a last resort. Instead, if I needed to overcome the above limitations, I would make 5 plot flags and use them as a counter. Plot flags don't rely on OBJECT_SELF, they don't require variables be declared in a 2da, there's no risk of double purposing an existing variable and they can be set/checked in any area.
So let's say you made 5 plot flags, one per rat. Would you also make a defined flag called ALL_RATS_DEAD and in your plot script for this flag, return TRUE if your 5 plot flags are all TRUE?
I think maybe I finally understand what a defined flag is. :happy:
Yes, that's a common use for a defined flag, and that's certainly one way to implement the quest; to make each flag represent a different and unique rat. If you've only got 5 rats, I'd probably do it that way*. If there were many rats and you just wanted to know if the player has killed at least 5, you could run something like the following when any rat dies:
if (WR_GetPlotFlag(PLT_RATS, RATS_DEAD_4) WR_SetPlotFlag(PLT_RATS, RATS_DEAD_5, TRUE);
else if (WR_GetPlotFlag(PLT_RATS, RATS_DEAD_3) WR_SetPlotFlag(PLT_RATS, RATS_DEAD_4, TRUE);
else if (WR_GetPlotFlag(PLT_RATS, RATS_DEAD_2) WR_SetPlotFlag(PLT_RATS, RATS_DEAD_3, TRUE);
else if (WR_GetPlotFlag(PLT_RATS, RATS_DEAD_1) WR_SetPlotFlag(PLT_RATS, RATS_DEAD_2, TRUE);
else WR_SetPlotFlag(PLT_RATS, RATS_DEAD_1, TRUE);
*Assuming I wasn't using a single team, probably because the rats are split up in different areas, or because I want the journal to update every kill rather than only when they are all dead. If all of the rats are in one place, the team would definitely be the easier way to do it.
#9
Posté 22 décembre 2009 - 06:36
#10
Posté 22 décembre 2009 - 11:01
#11
Posté 22 décembre 2009 - 01:23
To avoid confusion it should be noted that David's reference to the use of defined flag approach is the one outlined by FalloutBoy but that his own example (quoted) is implemented using main flags. You cannot set a defined flag as its state is calculated or derived from one or more other states (e.g. from main flags, local variables, object validity, companions in party, etc.)DavidSims wrote...
Yes, that's a common use for a defined flag, and that's certainly one way to implement the quest; to make each flag represent a different and unique rat. If you've only got 5 rats, I'd probably do it that way*. If there were many rats and you just wanted to know if the player has killed at least 5, you could run something like the following when any rat dies:
if (WR_GetPlotFlag(PLT_RATS, RATS_DEAD_4) WR_SetPlotFlag(PLT_RATS, RATS_DEAD_5, TRUE);
else if (WR_GetPlotFlag(PLT_RATS, RATS_DEAD_3) WR_SetPlotFlag(PLT_RATS, RATS_DEAD_4, TRUE);
else if (WR_GetPlotFlag(PLT_RATS, RATS_DEAD_2) WR_SetPlotFlag(PLT_RATS, RATS_DEAD_3, TRUE);
else if (WR_GetPlotFlag(PLT_RATS, RATS_DEAD_1) WR_SetPlotFlag(PLT_RATS, RATS_DEAD_2, TRUE);
else WR_SetPlotFlag(PLT_RATS, RATS_DEAD_1, TRUE);
*Assuming I wasn't using a single team, probably because the rats are split up in different areas, or because I want the journal to update every kill rather than only when they are all dead. If all of the rats are in one place, the team would definitely be the easier way to do it.
Anyone struggling with concept of defined flags may find this (draft) article provides better a better example: social.bioware.com/wiki/datoolset/index.php/User:Sunjammer/Plot_flags_%28draft%29. Additionally you can have a look in the Little Red Riding Hood Redux builder's resources to see a working example using both main and defined flags: social.bioware.com/project/334/discussion/586/.
Modifié par Sunjammer, 22 décembre 2009 - 01:25 .
#12
Posté 22 décembre 2009 - 01:30
You could use another defined flag, or another main flag which is set when the player returns to claim his reward. Also if you used David's example you could simply just check if the 5th main flag had been set.Axe_Murderer wrote...
I think the main problem with the OP's original post is that his quest design requires 4 steps (conditions to be met) but there are only 3 flags to track them. It lacks a plot flag to indicate when the entire quest is complete...only the first 3 parts of the quest are being tracked. The only way to know if the entire quest is complete would be to check whether all three of them are set. So the conversation line conditionals would have to not only check if the one flag is set, but also ensure all three are not set in order to determine if the line should appear. Having that fourth condition representing "everything done" would make those conditionals more obvious to write correctly because you could more directly ask "is everything not done and quest not accepted" or "is everything not done and rats not killed". Or even simpler, put a new line one in there at the very top saying "Thanks for helping with those rats" and base its condition on the "everything done" flag. A defined flag would be perfect for implementing the missing fourth flag...all it would have to do is return true when all three of the other plot flags are set and false otherwise.
#13
Posté 22 décembre 2009 - 04:52
Function flags?
Modifié par Axe_Murderer, 22 décembre 2009 - 05:16 .
#14
Posté 22 décembre 2009 - 06:24
Axe_Murderer wrote...
Just read that wiki from Sunjammer and I can't help agreeing that "defined" flag is a misnomer of a name for them. In truth, they are exactly opposite of defined...they are computed dynamically. There is nothing about them that is defined other than their ID. The fact that you can't set them also means that you cannot define them. Oh I guess you could say they are defined by code rather than values, but I don't think that way. I would have called them computed flags or computing flags or maybe evaluating flags since their value is determined by a computational evaluation made in code on the fly at the time they are examined (Get). They are basically just a function call invoked thru event signals rather than direct execution. I like them muchly they are incredibly elegant. but the name chosen is confusing because its really completely opposite...to me anyway.
Function flags?
Does the toolset call them defined flags? I've always called them defined conditions. I think name comes from the fact that the condition is defined by the script, rather than the value of the flag. I agree it's not the best naming, but the system works quite well once you wrap your head around it.
#15
Posté 22 décembre 2009 - 06:29
#16
Posté 22 décembre 2009 - 06:43
I think this explanation might make it in to the next draft.DavidSims wrote...
I've always called them defined conditions. I think name comes from the fact that the condition is defined by the script, rather than the value of the flag.
#17
Posté 22 décembre 2009 - 06:56
DavidSims wrote...
Axe_Murderer wrote...
Just read that wiki from Sunjammer and I can't help agreeing that "defined" flag is a misnomer of a name for them. In truth, they are exactly opposite of defined...they are computed dynamically. There is nothing about them that is defined other than their ID. The fact that you can't set them also means that you cannot define them. Oh I guess you could say they are defined by code rather than values, but I don't think that way. I would have called them computed flags or computing flags or maybe evaluating flags since their value is determined by a computational evaluation made in code on the fly at the time they are examined (Get). They are basically just a function call invoked thru event signals rather than direct execution. I like them muchly they are incredibly elegant. but the name chosen is confusing because its really completely opposite...to me anyway.
Function flags?
Does the toolset call them defined flags? I've always called them defined conditions. I think name comes from the fact that the condition is defined by the script, rather than the value of the flag. I agree it's not the best naming, but the system works quite well once you wrap your head around it.
It's okay, I bet he's not really an axe murderer either.
At least I hope not.
#18
Posté 23 décembre 2009 - 12:34
What is this include?
#include "PLT_NO_GOOD_DEED"
I am unsure what the include is pointing to. Another script? I tried pointing it at the name of my plot "rat_quest" but that gave an error indicating is was looking for a script.
EDIT: OK, I think I should NAME my plot and use that as the include? I tried that and at least my case switches are now recognized. Plots apparently do not have a default name ... so you have to fill that field in under properties.
Modifié par georage, 23 décembre 2009 - 02:34 .
#19
Posté 23 décembre 2009 - 10:29
georage wrote...
What is this include?
#include "PLT_NO_GOOD_DEED"
I am unsure what the include is pointing to. Another script? I tried pointing it at the name of my plot "rat_quest" but that gave an error indicating is was looking for a script.
Basically when you create a plot resource, the toolset automatically create an header declarating your plot GUID and flag constants. And that header is named "plt_yourplot"
So in your case, if your plot tag is "rat_quest" you'll have to include "plt_rat_quest"
#20
Posté 23 décembre 2009 - 05:16
#21
Posté 23 décembre 2009 - 05:50
#22
Posté 23 décembre 2009 - 07:11
#23
Posté 26 décembre 2009 - 06:44
Flags of both kinds evaluate as TRUE or FALSE either by being told so directly (main flags) or through a script (defined flags).
But what I see when I look at a plot file are flags that are either SET or NOT SET.
Is SET the same as TRUE, and NOT SET the same as FALSE? Or is NOT SET an undefined state that evaluates to neither TRUE nor FALSE?
Modifié par Lady Olivia, 26 décembre 2009 - 06:52 .
#24
Posté 26 décembre 2009 - 08:09
Modifié par Sunjammer, 26 décembre 2009 - 08:10 .





Retour en haut






