GAH!! MY BRAIN HURTS!

Blitz3D Forums/Blitz3D Beginners Area/GAH!! MY BRAIN HURTS!

chwaga(Posted 2007) [#1]
My brain hurts!! I need help lol. I'm trying to create a program that can generate conversation functions. I'm trying to use types (for the first time I might add) and I've got a TON of questions.

This code is text-based and asks you what you want the filename, and function name are to be. It then asks you what you want the NPC to say, and what you list of responses are (tree-style). Using the code below, how can I be able to insert a type system where the user can type "(/end)" (which can be achieved with Instr()) to make that particular response end the conversation, and when that isn't done, continue asking for what the NPC says, and your responses (I'm thinking of developing a graphical tree system to make things easier). The big question is how to do this with types.

Here's the code:
AppTitle "SW:WRH Conversation creator"
Global filename$=""
Global launcher$=""
Global funcname$=""
Global npc1$=""
Global r1$=""
Global r2$=""
Global r3$=""
Global npc2$=""
Global quit=0
Global check$=""
 
Graphics 1280,1024,32,2



While quit=0


;createconversation
;create the conversation
Text 1, 1, "WELCOME TO THE SW:WRH CONVERSATION CREATOR. FOLLOW GIVEN INSTRUCTIONS. TYPE 'quit' AT ANY TIME TO QUIT WITHOUT SAVING YOUR CONVERSATION. HIT ANY KEY TO CONTINUE"
WaitKey()
Cls 

filename$=Input$("What should the filename of this conversation be (if the file already exhists, put its name here too, extensions are unnecesary)? ") + ".bb"
check(filename$)
If quit=1 Then Goto quitlabel


funcname$=Input$("What would you like the Function name For this conversation To be?   ")
check(funcname$)
If quit=1 Then Goto quitlabel

npc1$=Input$("What would the first thing the NPC says be?   ")
Text 1000,15,"npc1= " + npc1
check(npc1$)
If quit=1 Then Goto quitlabel

r1$=Input$("What do you want response1 to be?   ")
Text 1000, 30,"r1= " + r1
check(r1$)
If quit=1 Then Goto quitlabel

r2$=Input$("What do you want response2 to be?   ")
Text 1000, 45,"r2= " + r2
check(r2$)
If quit=1 Then Goto quitlabel

r3$=Input$("What do you want response3 to be?   ")
Text 1000, 60,"r3= " + r3
check(r3$)
If quit=1 Then Goto quitlabel

writetofile 


Cls 

Wend 
.quitlabel
End 

Function check(check$)
If check$="quit" Then quit=1
;Goto quitlabel
;EndIf 
End Function 

Function writetofile()


test = FileType(filename$)

;if it doesn't
If Not test Then
		
	;createfile
	file = WriteFile(filename$)


;if it does		
Else
	
	;open file
	file = OpenFile(filename$)
	;seek to end of file
	SeekFile file, FileSize(filename$)
	
End If

WriteLine file, ""

WriteLine file, "Function " + funcname$ + "()"

WriteLine file, "npc1$ = " + Chr(34) + npc1$ + Chr(34)
WriteLine file, "r1$ = " + Chr(34) + r1$ + Chr(34)

WriteLine file, "Repeat"


WriteLine file, "Flip()"

WriteLine file, "If (MouseY() < ((displayheight/4)*3)+((displayheight/4)*.3) + 12) And MouseY() > ((displayheight/4)*3)+((displayheight/4)*.3) Then"
WriteLine file, "Color 50, 50, 245"
WriteLine file, "Rect 0, ((displayheight/4)*3)+((displayheight/4)*.3), displaywidth, 12, 1"
WriteLine file, "Color 255, 255, 255"
WriteLine file, "EndIf"

WriteLine file, "Color 0,0,0"
WriteLine file, "Rect 0,0,displaywidth,displayheight/4,1"
WriteLine file, "Color 0,0,0"
WriteLine file, "Rect 0,(displayheight/4)*3,displaywidth,displayheight/4,1"
WriteLine file, "Color 255, 255, 255"

;HIGHLIGHTS========================

WriteLine file, "If (MouseY() < ((displayheight/4)*3)+((displayheight/4)*.3) + 12) And MouseY() > ((displayheight/4)*3)+((displayheight/4)*.3) Then"
WriteLine file, "Color 50, 50, 245"
WriteLine file, "Rect 0, ((displayheight/4)*3)+((displayheight/4)*.3), displaywidth, 12, 1"
WriteLine file, "Color 255, 255, 255"
WriteLine file, "EndIf"

WriteLine file, "If (MouseY() < ((displayheight/4)*3)+((displayheight/4)*.3) + 12 +50) And MouseY() > ((displayheight/4)*3)+((displayheight/4)*.3)+50 Then"
WriteLine file, "Color 50, 50, 245"
WriteLine file, "Rect 0, ((displayheight/4)*3)+((displayheight/4)*.3)+50, displaywidth, 12, 1"
WriteLine file, "Color 255, 255, 255"
WriteLine file, "EndIf"

WriteLine file, "If (MouseY() < ((displayheight/4)*3)+((displayheight/4)*.3)+12+100) And MouseY() > ((displayheight/4)*3)+((displayheight/4)*.3)+100 Then"
WriteLine file, "Color 50, 50, 245"
WriteLine file, "Rect 0, ((displayheight/4)*3)+((displayheight/4)*.3)+100, displaywidth, 12, 1"
WriteLine file, "Color 255, 255, 255"
WriteLine file, "EndIf"
;====================================

WriteLine file, "Text 250,100, " + Chr(34) + npc1$ + Chr(34) 
WriteLine file, "Text 250,((displayheight/4)*3)+((displayheight/4)*.3), " + Chr(34) + r1$ + Chr(34)
WriteLine file, "Text 250,((displayheight/4)*3)+((displayheight/4)*.3)+50, " + Chr(34) + r2$ + Chr(34)
WriteLine file, "Text 250,((displayheight/4)*3)+((displayheight/4)*.3)+100, " + Chr(34) + r3$ + Chr(34)

WriteLine file, "Until KeyHit(1)"

WriteLine file, "End Function"

CloseFile file



End Function 


Sorry about the questions...I wasn't very clear...I'm tired :) Ask for clarifications if need be.

Thanks for any help!

PS: is there a way to have 3d animations played with my models during the Repeat ... Until loop for the conversation?


b32(Posted 2007) [#2]
That looks nice. It can be a good method to write a program that generates code. However, with this method, you generate a separate function for each conversation. It might be better to create a single function that can handle all conversations.

For checking the input for (/end), in the function check, use:
Function check(check$)
  ;look for (/end)
  cc = Instr(check$, "(/end)")
  If cc > 0 Then
        ;remove (/end) from input
	check$ = Left$(check$, cc - 1) + Mid$(check$, cc + 6)
	quit = 1
  End If
End Function 

Then, to complete the entire input sequence before quitting, only check if quit = 1 after asking for response3.

You could make a type for the questions.
The type should look sort of like this:
Type TQuestion
 field question$
 field answer1$
 field answer2$
 field answer3$
End Type


After completing a question (when npc$, r1$, r2$ and r3$ are filled in), create a new instance of this type by using:
q.TQuestion = new TQuestion

Then fill in the fields:
q\question$ = npc1$
q\answer1$ = r1$
q\answer2$ = r2$
q\answer3$ = r3$


When all questions are entered, you could write the data to a file like this:
ff = WriteFile("questiondata.txt")
For q.TQuestion = each TQuestion
WriteLine ff, q\question$
WriteLine ff, q\answer1$
WriteLine ff, q\answer2$
WriteLine ff, q\answer3$
Next
CloseFile ff


And load it back using:
ff = ReadFile("questiondata.txt")
Delete Each TQuestion
while not(eof(ff))
   q.TQuestion = new TQuestion
   q\question$ = ReadLine(ff)
   q\answer1$ = REadLine(ff)
   q\answer2$ = REadLine(ff)
   q\answer3$ = REadLine(ff)
wend
CloseFile ff


However, you could also intergrate the type with the system you made allready.

3D Animations can be played back using the Animate Command.
The models have to be loaded with the LoadAnimMesh command.

In the generated function, the first lines of the loop are:
Repeat
Flip()


These should be changed to
Repeat
UpdateWorld
RenderWorld
Flip

For an example, look for the LoadAnimMesh example in the Blitz3D help section.


chwaga(Posted 2007) [#3]
wow! Thanks! However, I have one question.

how could I be able to make clicking the choices during the loadback, and every time you click on, it brings up the next set of questions and replies? It needs to be flexible to an infinite number of replies, but terminatable at any time. (the termination can be done with the /end command, does a check for it, and then snaps to an end label)
In other words, how can I set up a hirarchy that extends all the way to the end of how many responses there are. That could be possible if fields have can have fields...is that possible?

Thanks!


b32(Posted 2007) [#4]
Ah, I see. Well, there is a command called Replace$
ShowText$ = Replace$(OriginalText$, "(/end)", "")


With this construction, you can keep the (/end) bit in the answers until they are displayed on the screen. 'ShowText' is what is shown on the screen, and 'OriginalText' is the text/answers as the Function deals with it.
If Instr(OriginalText$, "(/end)") < 1 Then ;Continue Conversation


Then, for enabling the mouse, I would use RectsOverlap.
First, store MouseX, MouseY and MouseHit(1) in variables. That is needed, because they should be read only once each loop.
Repeat

msX = MouseX()
msY = MouseY()
msH = MouseHit(1)

.. etc


Then, use
RectsOverlap(msX, msY, 1, 1, AnswerX, AnswerY, AnswerWidth, AnswerHeight) And msH 
to check if the user clicks the answer, where AnswerWidth and AnswerHeight can be calculated using the StringWidth and StringHeight commands.

Here is an example:


As for the hierachic structure, you would need a way to link questions to each other. Do you want to use them in a random order ? Else you would need to specify how questions should be linked somehow.

For instance, you could mark each question with a 'order' property. For instance, some questions are marked with a a '1', and other questions with a '2', or a '3' etc.
First, the computer picks a question out of the '1' pool. Then, after that, it picks a follow-up question of the '2' pool, then '3' etc.

Another way would be indicating which questions can follow which answer.
             ____ bad ----- why is that ?
            /
how are you ----- fine ----- are you allways fine ?
            \____
                  mwoah ----- what would you like to buy ?


In that case, you could maybe best use a recursive structure. That is a function that calls itself.
The following example demonstrates that:

For each answer, a 'followed by' field is asked. If the answer shouldn't be followed by a new question, leave the field empty.

It would come in handy to reuse some questions. In that case, the GetQuestion() function should look if a certain 'followed by' question allready exists before re-calling itself. (Because if the question allready exists, there is no need to enter new answers for it)

To store this structure, you'll need a type like this:
Type TQuestion
 field question$
 field answer1$
 field answer2$
 field answer3$
 field followup1$
 field followup2$
 field followup3$
End Type
or
Type TQuestion
 field question$
 field answer$[3]
 field followup$[3]
End Type


After the user selects one of the answers, the computer checks the appropriate 'followup' field, and searches for a question that matches this 'followup'.
If this followup$ = "", then the conversation should end.


chwaga(Posted 2007) [#5]
That code works beautifully, and integrated almost perfectly.

BUT:
I can't figure out how to use the recursive function to write into the file. Here's my current code:



b32(Posted 2007) [#6]
To write this data to a file, place the 'writetofile' function after the 'quitlabel' label.
Instead of writing the data to the file, store them into the type first.
After everything is entered, dump all the Type data to the file at once.


chwaga(Posted 2007) [#7]
yeah, I was trying that and ran into some trouble with making the fields = follow1, etc. Here:


It doesn't let me run the program, I get runtime error "Expecting 'End Function' "


b32(Posted 2007) [#8]
That is because you need to use the backslash instead of the slash. I was thinking .. maybe you could simply call/put the WriteToFile stuff in the GetQuestion function. That should also work.

edit: and there is a typo in this line:
GetQuestion$(initquiestion$)



chwaga(Posted 2007) [#9]
DOH thanks!!! Lol, that backslash is gonna be my death...

Now I'm getting a variable type mismatch in this line:
	q.TQuestion = New TQuestion



PowerPC603(Posted 2007) [#10]
This error is because your variable "q" was declared as a string-variable within your function declaration:
Function GetQuestion$(q$)

Further within the function you re-use the same variable
for storing a TQuestion type:
q.TQuestion = New TQuestion
q/question$ = q$

Within this function, you could use another variable for storing the TQuestion type.
This last bit is a bit confusing, as you want to store a TQuestion type variable into q, while q already has a string assigned to it.
If Blitz where to convert (which it doesn't) your q-string into a q-TQuestion type, your string would be gone (overwritten by a new TQuestion type object) and you would store the handle of the q-variable into q/question$.


chwaga(Posted 2007) [#11]
got it. Thanks!


chwaga(Posted 2007) [#12]
How will I be able able to write to the file according to the length of the hirarchy?


b32(Posted 2007) [#13]
The simplest form would be something like this:
ff = WriteFile("questiondata.txt")
For q.TQuestion = each TQuestion
WriteLine ff, q\question$
WriteLine ff, q\answer1$
WriteLine ff, q\answer2$
WriteLine ff, q\answer3$
Next
CloseFile ff



chwaga(Posted 2007) [#14]
but then I wouldn't be able to click things to bring up new questions and answers.


b32(Posted 2007) [#15]
That is right. There are several ways to make that possible.
One of them would be writing the file as you did before, as a complete .bb program.
However, you could also write a single Function that takes a question as a parameter.
It should wait for the user to select one of the answers, then look for the follow-up question, and if that is defined, the function should call itself with this new question.


chwaga(Posted 2007) [#16]
ooh....That last idea could work...


chwaga(Posted 2007) [#17]
What's the [3] in
Type TQuestion
 field question$
 field answer$[3]
 field followup$[3]
End Type

do?


b32(Posted 2007) [#18]
Instead of a single answer$ field, you can use 4 answer$s, from zero to three.
q.TQuestion = New TQuestion
q\answer$[0] = 'option 1'
q\answer$[1] = 'option 2'
q\answer$[2] = 'option 3'
q\answer$[3] = 'option 4'


This could be handy when you want to use a For..Next loop to read the answers, for instance:
For i = 0 to 3

  print q\answer$[i]

Next



chwaga(Posted 2007) [#19]
that could be useful...thanks


chwaga(Posted 2007) [#20]
It's almost done...but i've got a problem with your function idea, what do you mean by
It should wait for the user to select one of the answers, then look for the follow-up question, and if that is defined, the function should call itself with this new question.


if you could give some code to explain that I would hugely appreciate it!! (by the way, for helping me so much I'll probably give you credit in game and a blitz3d cookiee :D)


b32(Posted 2007) [#21]
Well, if you put the first question in a string, say 'questiontoask$', you could use this to search for the TQuestion that holds this question:
questiontoask$ = "How are you ?" ;<-- first question

;reset 'q' to empty before searching
q.TQuestion = null

;scan all TQuestions
For temp.TQuestion = Each TQuestion

  ;if temp's question is the question to ask, then select temp and leave loop
  if temp\question$ = questiontoask$ Then q = temp: Exit

Next

if q = Null then Return ;--> the question was not found


After this, 'q' holds the question you were searching for.
Print q\question$

q\answer1$, q\answer2$, q\answer3$ are the possible answers

After the user picks one of them (1/2/3), get the followup$ that belongs to this answer
q\followup1$, q\followup2$, q\followup3$

--> I would start off with a simple Input, so you can enter 1, 2 or 3 directly. Later on, you can replace this with a mouse interface.

user = Input(">")
if user = 1 then followup$ = q\followup1$
if user = 2 then followup$ = q\followup2$
if user = 3 then followup$ = q\followup3$

If this 'followup$' is empty, leave the function (Return)
This happens when this question is a last question
If followup$ = "" Then Return


This 'followup$' is the new 'questiontoask$' that can be inserted at the start again.

You can use a Repeat..Forever loop as well as a Function.


chwaga(Posted 2007) [#22]
what do you mean in using a repeat forever loop?


b32(Posted 2007) [#23]
Instead of making a loop with Repeat..Until, you could also use Repeat..Forever. Then you can use the Exit command to end it. I find that easier, it means you can say something like
If <thisandthis> Then Exit
anywhere in the loop.


If the loop is placed inside a function, you can also break the loop (and the Function at the same time) with the Return command.


chwaga(Posted 2007) [#24]
dang, this should be working, here's the creator:



and here's my function:


and I'm using this to call it:
If KeyHit( 43 ) Then 

conversation("testing!.bb", "Hi")
 
EndIf 


and finally the file testing!.bb is as follows:



I'm leaving soon so if you could get me an answer ASAP I'd hugely appreciate it!

I'm getting the error message: "cannot open include file!" on the function...the file "testing!.bb" is in the same folder as the function...I don't get it!


b32(Posted 2007) [#25]
It's more than that, I think. The strings are missing quotes:
question1\question$ = Hi
should be
question1\question$ = "Hi"

Instead of exporting, say, a$ to the file, export:
Chr$(34) + a$ + Chr$(34)

And you can't use Include with a string-variable.
You should enter a direct value to it.
a$ = "testing!.bb"
Include a$
won't work. It should be
Include "testing!.bb"
instead.
Then, there were a minor issues in this part:

The 3d mode wasn't set, so renderworld didn't work.
A few typos, and the fields didn't match the type.


chwaga(Posted 2007) [#26]
Awesome!! It kinda works! Except, I don't want to have all the variables in play throughout the entire game, which
Include "bram.bb"
does. How can I have the file included based on a variable. Also, types can only be declared outside the main program, so using a conversation inside the game loop with my current method, is problematic.


b32(Posted 2007) [#27]
I think you should then use ReadFile/WriteFile to include variable data, like this:
;Delete Each TQuestion <-- delete possible existing questions
a$ = "Conversation12.dat"
ff = ReadFile(a$)
While Not(Eof(ff))

   q.TQuestion = New TQuestion
   q\question$ = ReadLine(ff)
   ..etc

Wend
Closefile ff


You could however also use Read&Data.
With the Restore command, you can determine where Read should start reading data. Using a Select..Case structure, you can use a variable to Restore to the right label.

I'm not sure if you're familiair with the Data command ?
Here is an example:

And about Types, you can include Types whereever you like in the program, but they should appear before they are used.
So, if you're using them in an Included file, and you want to define them in the main program, they should appear before the Include command.


chwaga(Posted 2007) [#28]
on your first method (not the data one) how should I make the code-generator (with a potentially-forever-expanding-hiarchy)


b32(Posted 2007) [#29]
Well, you could write all the data to the file, without any code. Every dialog (multiple questions) could be an a separate file.
ff = WriteFile("questiondata.txt")
For q.TQuestion = each TQuestion
WriteLine ff, q\question$
WriteLine ff, q\answer1$
WriteLine ff, q\answer2$
WriteLine ff, q\answer3$
Next
CloseFile ff


Then, you could write a function that loads the data from the file, and then enters a Repeat..Forever loop that allows the user to answer the questions until they end.



chwaga(Posted 2007) [#30]
OK, It's nearly done, I've got 2 small questions left,


1 - EXCACTLY how do I ";;;---> read questions from file here"

2 - By the looks of your above codebox stuff, the main game should always have the Type "TQuestion" in play, but unless a conversation is currently in play, it's an empty type. When calling a conversation in-game, the text file is read, and the text is then "converted" to a type in the type "group" called TQuestion. As soon as the conversation is over, the type is flushed and emptied, leaving no unnecesary conversation-related variables in game. IS THIS CORRECT?


b32(Posted 2007) [#31]
1.
ff = ReadFile("questiondata.txt")
Delete Each TQuestion
while not(eof(ff))
   q.TQuestion = new TQuestion
   q\question$ = ReadLine(ff)
   q\answer1$ = REadLine(ff)
   q\answer2$ = REadLine(ff)
   q\answer3$ = REadLine(ff)
wend
CloseFile ff

2. A Type is not a variable. It is a type of variable. So the Type remains available, however there are no instances of this type.


chwaga(Posted 2007) [#32]
grrr....I'm having all sorts of problems with this, could you help me out?

this is the creator :


and this is the conversation function (need a TON of work here):


and in the main program, the code :


and being called like so:


finally, the text file generated by the creator is as follows:


Any help?


chwaga(Posted 2007) [#33]
by the way, I'm giving you an uber-cookiee for all your help :) and super-credits


Techlord(Posted 2007) [#34]
Binary Decision Tree
http://www.blitzbasic.com/codearcs/codearcs.php?code=1455


chwaga(Posted 2007) [#35]
... wish i saw that, how do I use it? Better yet, what's wrong with the system I'm using ( I like to have SOME hand in my creations)


b32(Posted 2007) [#36]
I looked at the code. Actually there wasn't much wrong. In the first loop, the Type that is filled in has another name than the Type that is created.
Other than that, I moved the file-reading to the beginning of the function, and added 'Delete Each TQuestion' for every 'Return' call.
Also I changed the loops to Repeat-Forever, and put the conditions (such as KeyHit(1)) that exit the loop in If statements.
In order to get it to work, at the end of the loop, I added questiontoask$ = followup$, so that the Function could search for the next question:



chwaga(Posted 2007) [#37]
it almost works! the code you gave does work, but I'm getting a mem access violation when i use it in-game. Here's my new functions (small revisions, mainly got rid of semicolons):



What wrong with it?

I found that getting rid of:

makes using the function do nothing.


b32(Posted 2007) [#38]
Try enable debug mode ? Program->Debug enabled ?
On what line do you get this error ?
I think the mouse image is missing, or it can't find 'text.txt'


chwaga(Posted 2007) [#39]
lol, stupid typo on calling it!! IT WORKS!

if you could email me at chwaga@... I can give you credits, I'm leaving soon so I'll make your cookiee later today! THANKS!! (do you think this could find it's place in the code arcs?)


b32(Posted 2007) [#40]
No problem. As for the archive entry, why not ? I would make a very basic version, single source, that immediately makes clear what it does. If people want to use it, they might tweak it to be able to include it in their own sources. So if your version is easily tweakable, then chances are, people will use it.


chwaga(Posted 2007) [#41]
Thanks, here's your cookiee, as promised:
[a http://files.filefront.com/Have+A+Cookieezip/;8531738;/fileinfo.html] have a cookiee[/a]

Thanks for all your help!


b32(Posted 2007) [#42]
Great :) thanks a lot.