Hi,
it's me again, I keep running into issues with Custom Conditions that call C# functions.
Quick summary: I have a condition that calls a boolean from a C# script but it chooses the "condition bool == true" path even though the condition is false.
(Warning: wall of text ahead....)
EDIT: I found the error before I even sent the message. I'm sending it anyways in case someone else has a similar issue. Yet, dear support person: If you have any ideas on how I could achieve my goal in a more elegant way- I appreciate any suggestions
Also: Do you have an answer for question 2 at the end of the text? It works just fine, I'm rather asking out of curiosity
What I want to have:
In the game some characters hesistate to speak to others due to various reasons. You (the player) can give them energy to overcome those impediments. If you start a conversation you get to read the thoughts of the character. Depending on how much energy the character has they either say the impediment text (e.g. "I'm afraid!") or its counterpart (e.g. "I'm afraid - but I should tell them anyways!"). In my example there are 3 impediments + counterparts.
(dialogue entries are structured as follows: start -> introduction -> imp 1 OR counterpart 1 -> imp 2 OR counterpart 2 -> imp 3 OR counterpart 3)
Each impediment has an individual energy-cost. The costs add up for each impediment and you have to pay the total cost to gain access to the respective counterparts.
Example:
imp 1 cost: 20 energy --> you need 20 energy in total
imp 2 cost: 50 energy --> you need 70 energy in total
imp 3 cost: 40 energy --> you need 110 energy in total
So far I used the following conditions which worked fine:
imp 1: GetEnergy("Harald") < 20
counterpart 1: GetEnergy("Harald") >= 20
imp 2: GetEnergy("Harald") < 70
counterpart 1: GetEnergy("Harald") >= 70
imp 3: GetEnergy("Harald") < 110
counterpart 3: GetEnergy("Harald") >= 110
However, I want to control those costs outside the dialogue database so if I want to change values later I don't have to go into each conversation and change (and calculate) them manually for each entry (there will be a LOT of dialogue).
What I did:
There's another script (Opportunity) that sits on a GameObject in the scene. The NPC GameObjects that are involved in the opportunity are children objects of the Opportunity-GameObject. Opportunity counts the dialogue entries that I marked as impediments using a custom field and creates an int[] of the respective length. I made this function available in editor: you press a button in the inspector, it calls initializeImpedimentArray, and you can assign the values for each impediment. This works fine.
Code: Select all
public int impedimentsCount()
{
int sum = 0;
//conversation = DialogueManager.MasterDatabase.GetConversation(conversationName); //copy pasted from Dialogue System Trigger -- might not work in editor, since master database is created during runtime?
conversation = dialogueDatabase.GetConversation(conversationName);
foreach (DialogueEntry entry in conversation.dialogueEntries)
{
if (Field.LookupValue(entry.fields, "IsImpediment") == "True")
{
sum += 1;
}
}
return sum;
}
public void initializeImpedimentArray() //Forum entry: https://www.pixelcrushers.com/phpbb/viewtopic.php?f=3&t=3737&p=20811&hilit=access+custom+field+by+code#p20811
{
impedimentCosts = new float[impedimentsCount()];
}
My NPC has access to this array. A boolean (HasEnoughEnergy) compares the NPC's current energy to the energy cost values.
The dialogue manager has access to specific instances of the NPC script using the approach you suggested me earlier: It calls a function on an NPCLua script that sits on the Dialogue Manager GameObject in the scen and the NPCLua calls the NPC function with the given actor.
This is the code in NPCLua:
Code: Select all
public bool GetHasEnoughEnergy(string actorName, double impedimentIndex)
{
NPC npc = FindNPC(actorName);
if (npc != null)
{
//Debug.Log(this + " npc.HasEnoughEnergy(impedimentIndex): " + npc.HasEnoughEnergy(impedimentIndex));
return npc.HasEnoughEnergy(impedimentIndex);
}
else
{
Debug.Log(this + "npc = null, actorName: " + actorName);
return false;
}
}
This is the code in my NPC script:
Code: Select all
public bool HasEnoughEnergy(double impedimentIndex)
{
//int index = (int)dialogueEntryIndex;
int index = Mathf.RoundToInt((float)impedimentIndex); //convert double to int
//Debug.Log("dialogueEntryIndex: " + impedimentIndex + " index: " + index);
double cost = 0;
if (opportunity != null) //check if there is an Opportunity script attached to a parent
{
if (opportunity.impedimentCosts.Length > 0) //check if array has any values
{
for (int i = 0; i < index; i++) //energy cost ist checked in each dialogue entry and you need the complete amount of energy to make the character talk so all values up to the current dialogue entry are added together
{
cost += opportunity.impedimentCosts[i];
Debug.Log(this + " dialogueEntryIndex (input): " + impedimentIndex + " index: " + index + " i: " + i + " dialogueEntryIndex (input): " + impedimentIndex + " cost: " + cost + " energy: " + energy);
//Debug.Log(this + " energy: " + energy);
}
}
}
if(energy >= cost)
{
Debug.Log(this + " energy: " + energy + " cost: " + cost + " returning true");
return true;
}
else
{
Debug.Log(this + " energy: " + energy + " cost: " + cost + " returning false");
return false;
}
}
These are the conditions (in my example there are 3 impediments):
imp 1: GetHasEnoughEnergy("Harald", 0) == false
counterpart 1: GetHasEnoughEnergy("Harald", 0) == true
imp 2: GetHasEnoughEnergy("Harald", 1) == false
counterpart2: GetHasEnoughEnergy("Harald", 1) == true
imp 3: GetHasEnoughEnergy("Harald", 2) == false
counterpart 3: GetHasEnoughEnergy("Harald", 2) == true
The issue
The character starts with 0 energy. Still, when I start the conversation, it directly goes to counterpart 1, then continues with imp 2 and imp 3. In this example this should be the case when character.energy >= 20
The first dialogue entry (ID 1 - right after the 'Start' entry) has no conditions. It is an introduction to what the character is thinking about, and only then come the impediments.
Starting the conversation: It shows the introduction.
Console Output:
Harald (NPC) energy: 0 cost: 0 returning true
Harald (NPC) energy: 0 cost: 0 returning true
(--> it does not enter the for-loop in HasEnoughEnergy in NPC; --> is that why cost is 0? Also why does it call the function at all even though this dialoge entry does not have any conditions? edit after I found my error: I think I understand it now, apparently the conditions are already called in the previous entry)
Clicking "continue" first time: It shows counterpart 1 (should be impediment 1).
Console Output:
Harald (NPC) dialogueEntryIndex (input): 1 index: 1 i: 0 dialogueEntryIndex (input): 1 cost: 20 energy: 0
Harald (NPC) energy: 0 cost: 20 returning false
Harald (NPC) dialogueEntryIndex (input): 1 index: 1 i: 0 dialogueEntryIndex (input): 1 cost: 20 energy: 0
Harald (NPC) energy: 0 cost: 20 returning false
(--> dialogueEntryIndex (input) shouldn't it be 0? Also why does it enter the "condition = true" entry even though the function returns false? edit after I found my error: I think I understand it now, apparently the conditions are already called in the previous entry, so 1 is correct)
Clicking "continue" second time: It shows impediment 2.
Console Output:
Harald (NPC) dialogueEntryIndex (input): 2 index: 2 i: 0 dialogueEntryIndex (input): 2 cost: 20 energy: 0
Harald (NPC) dialogueEntryIndex (input): 2 index: 2 i: 1 dialogueEntryIndex (input): 2 cost: 70 energy: 0
Harald (NPC) energy: 0 cost: 70 returning false
(--> dialogueEntryIndex (input) shouldn't it be 1? edit after I found my error: I think I understand it now, apparently the conditions are already called in the previous entry, so 2 is correct)
Clicking "continue" third time: It shows impediment 3.
Console Output:
(--> shouldn't there be any output? edit after I found my error: I think I understand it now, apparently the conditions are already called in the previous entry, so the call for this condition already happened)
My questions are:
1: Where does it get the energy cost value "0" from? (values are not assigned at runtime - none of the values in the array is 0)
2: When entering imp2/counterpart2: Why does it only call the function once (There are 2 possible options - shouldn't it check all of them like it did before)?
3 (main question): It seems to me like there is an offset of 1 in the function calls (so conditions are already called on entering the previous dialogue entry). This worked fine with the conditions I used before (mentioned further up in the text). I think the error has to do with accessing the ImpedimentCosts Array. For some reason it returns a 0 value (and thus returns HasEnoughEnergy == true) which should not happen bc. there IS no 0 value.
Any ideas / suggestions / solutions?
I apologize for the massive amount of text that I threw at you. I appreciate any kind of help with this issue, any insight on the execution order of the condition calls or any suggestions of how I could handle the "energy costs" somewhere outside of the database in an easier, more elegant way (like I mentioned before - I'm not a total beginner to scripting but still quite a beginner ^^")
Thanks in advance!
lol, I found the error whilst writing down the issue: It's in the for loop in HasEnoughEnergy in my NPC script:
I wrote:
--> when it is called for the first time index = 0 so it doesn't enter the for loop and returns energy = 0.
It should be: