Conversations, Script Dictionaries, And The Ask/Tell Feature

Liam315
09 May 2013, 10:11
Me again, I'm starting to implement my conversation code and I'm having trouble with using script dictionaries which I haven't used before.

What I want to do is simplify the ask/tell system by condensing both into one command "talk to [character] about [topic]," which I have done by editing the commands. Ask and Tell no longer exist, but the new "talk to" command still calls the function "DoAskTell" so that I can use the ask tab to organise all the scripts for the different topics.

So the expression for the command is-

^talk to (?<object>.*) about (?<text>.*)$

Which runs the script-
DoAskTell (object, text, "ask", "askdefault", "DefaultAsk")


That all works fine.

In the interest of keeping things simple, I also want to include responses to the command "talk to (character)" used by itself without any topic. What I am trying to do, is include the topic key "default" so that typing "talk to (character)" is the same as typing "talk to (character) about default." The point of this is to keep the conversation responses in one place (the ask/tell tab) rather than adding a verb for every character.

Putting it together in one command I have-

^talk to (?<object>.*) about (?<text>.*)$|^talk to (?<object>.*)$

if (not IsDefined("text")) {
if (HasAttribute(object, "ask")) {
invoke (object.ask, default) -----> ?
do (object, "ask", default) ----> ?
}
else {
msg ("There's no point talking to inanimate objects.")
}
}
else {
DoAskTell (object, text, "ask", "askdefault", "DefaultAsk")
}


All of the code works fine except for the lines marked with ---->? (I included both to show what I'd tried). From reading the forum I got the impression that you need to use invoke rather than do for script dictionaries, but I can't get either to work and run the script I've set to the key "default."

Alex
09 May 2013, 10:14
Try putting "default" in quotes, as there's no object or variable called default.

Also you probably don't need to combine the two commands as one. You can set up a separate command "talk to #object#" - it won't clash with "talk to ... about ...".

Liam315
09 May 2013, 11:03
Putting default in quotes doesn't help, I still get the same error message.

For invoke:
Error compiling expression 'object.ask': RootExpressionElement: Cannot convert type 'QuestDictionary`1' to expression result of 'IScript'

For do:
Error running script: Error compiling expression '"default"': RootExpressionElement: Cannot convert type 'String' to expression result of 'IDictionary'


(I know I don't need to join the commands but I only just learned about IsDefined and wanted to experiment with it.)

Alex
09 May 2013, 11:35
All the information you need is in the error message. For the "invoke" error, you're passing an entire dictionary, but the function only expects a script. So, you need to get the script item out of the dictionary before you can invoke it - using DictionaryItem.

For "do", you're passing in a string "default", but the three parameter version of "do" expects a dictionary (of parameters) as the third parameter. http://quest5.net/wiki/Do - I think you don't want "do" for this anyway, as you're not running a script attribute.

Liam315
09 May 2013, 12:16
Thanks Alex! Got it working. I'd tried using ScriptDictionaryItem before but couldn't because I didn't understand how to refer to the dictionary, that it is actually object.ask seems so obvious in hindsight.

HegemonKhan
12 May 2013, 03:58
Has the syntax~format changed for dictionaries? If not, then could someone explain how to get "ScriptDictionaryItem" to be recognized as a command, as it wants to read it as a function instead (which doesn't exist and thus the error message). I tried putting msg before it, so it looks like this: msg (ScriptDictionaryItem (object.scriptdictionary,"key"), which causes a seemingly strange result:

Script: msg ("my_scriptdictionary's_key's_script")

I'm just started working on trying to create a "pedia", but am having trouble with the dictionary coding, sighs.

here's my code, as maybe I'm completely not setting up the code correctly:

<asl version="540">
<include ref="English.aslx"/>
<include ref="Core.aslx"/>
<game name="HK Testing Stuff">
<gameid>85a24707-e27e-4071-b111-1d37d7f6f0d1</gameid>
<version>1.0</version>
<firstpublished>2013</firstpublished>
</game>
<object name="room">
<inherit name="editor_room" />
<object name="player">
<inherit name="editor_object" />
<inherit name="editor_player" />
</object>
</object>
<object name="species_structure">
<species_scriptdictionary type="scriptdictionary">
<item key="human_species">
msg ("Humans are a sentient species blah blah blah")
</item>
</species_scriptdictionary>
</object>
<command name="pedia_command">
<pattern>pedia</pattern>
<script>
pedia_function
</script>
</command>
<function name="pedia_function">
show menu ("What category?", split ("species",";"), true) {
switch (result) {
case ("species") {
show menu ("What species?", split ("humans",";"), true) {
switch (result) {
case ("humans") {
ScriptDictionaryItem (species_structure.species_scriptdictionary,"human_species")
}
}
}
}
}
}
</function>
</asl>

Sora574
12 May 2013, 04:19
@HK:
Are you trying to run the script from the dictionary?
If so, you should be using
invoke (ScriptDictionaryItem (species_structure.species_scriptdictionary,"human_species"))

as this runs the script. Keep in mind that ScriptDictionaryItem actually is just a glorified function with the return value of a script, so trying to call it without using it would be the same as:
game.script => {
msg (blah)
}
game.script


As for putting it into a message, the 'Script: msg ("my_scriptdictionary's_key's_script")' message happens because something tells Quest that what you're trying to get is a script, and then it says what the script is (this is most likely FLEE or something. I don't know, I'm still learning, I might be wrong about it even)
When you try to put that into a message, it's almost the same as using a 'ToString()'... Does that make sense?

jaynabonne
12 May 2013, 09:21
This brings us back to expressions: there are certain functions in Quest which are not functions in the same sense as functions we create with a "<function>" tag. These are "expression" functions, and they can only be used in an expression. (In other words, they are hooked into the expression parser, not into Quest in general.) These are typically built-in Quest functions that return a value. Since they return a value, they are expected to be used in the context of an expression (that is, an assignment operation - like: script = ScriptDictionaryItem(dict, "lookat")). They are simply not visible when called otherwise.

Besides ScriptDictionaryItem, the same goes for functions like HasString, TypeOf, NewList, etc. Even functions like SafeXML and ShowMenu *must* be used in an expression (typically an assignment, if, switch statement, etc).

(If it would be useful, I could start up another thread that lists these. But basically, if a function returns a value, you're pretty much expected to use it somehow.)

As Sora said, ScriptDictionaryItem returns a script for you to invoke or do something else with (assign to an attribute, pass to some function, etc). And he explained how to call the script (using "invoke"). I hope the above sheds some light on the error message you got.

HegemonKhan
12 May 2013, 22:33
thank you to both of you, I understand now! (my apologizes for not having tried "invoke" yet, and only having tried using the "msg" instead)

would these, get input ~ show menu ~ etc, also be "expression functions" ??? or are "expression functions" literally (I'm not sure if this would be correct usage of literally, lol) an (or used within an) expression, such as: (some label) = ScriptDictionaryItem (scriptdictionary,"key item's script", which I would~could~maybe then use the "some label" as the "call function" or not (wrong format or usage) ???

I had assumed that since it was a function which returned the dictionary's item key's script, I didn't need to apply any command to~upon it, not realizing that there's the ' <function name="blah"> ' and "expression functions".

it still seems a bit redundant though (probably in my code ignorance), as couldn't you just then "invoke the script itself", why then the reason or purpose of having a script dictionary, if there's not a quest function-command that works directly upon it, as I had wrongly thought the "scriptdictionaryitem" had done ???

jaynabonne
12 May 2013, 22:44
"get input" and "show menu" are not, as you would never say "something = get input { ... }". Rather, you just say "get input {...}" and the result shows up in the script.

What a script dictionary gives you (as with any dictionary) is a level of indirection; it allows you to look up a script via a name, as opposed to directly. That means that different scripts can be assigned to the name, even within the course of a single program, which means that the code invoking the script doesn't have to know what the script will be, and it can change dynamically if desired. What you do with the script once you look it up (invoke it, assign it to an attribute, pass it to a function, etc) is up to you, just as is the case with any other sort of variable you look up. (Imagine if you had a string dictionary, and when you called StringDictionaryItem, it just automatically printed the item instead of returning it for you to decide what needed to be done with it. It would not be very useful.)