Drawing randomly from a script dictionary

XanMag
So, I am talking to an NPC. His responses are randomly pulled from a string list of 7 or 8 responses.

From within the GUI, is there a way to set a flag when he specifically says one or two of those responses? If so how? If not, I guess I can weasel around in code view... :shock:

<value>'I'm old.  I'm hungry.  And I don't need you!'</value>


Here is one of the comments he makes. Where would I put --> SetObjectFlagOn (chickens, "ready")

'I'm old. I'm hungry. And I don't need you!'</value> SetObjectFlagOn (chickens, "ready") ???

'I'm old. I'm hungry. And I don't need you!'</value>
SetObjectFlagOn (chickens, "ready") ?????

And... certainly, if it is after, I would need a separator, right? Maybe a ,
And... certainly, if it is under that response, would it need indented?

I don't know!! Code syntax kills me!

Thanks!

HegemonKhan
if you don't mind trying to use a Script Dictionary Attribute instead of a String List Attribute, it'd be an "easy" (riiight) way to do this stuff, as a Script Dictionary Attribute allows you to add Scripts (you'd use the 'msg' Script for your responses, and after that Script you can have your Boolean Attribute setting Script, and then an 'if' Script to check the Boolean Attribute, with Scripts for each condition, boolean = true vs boolean = false, though I think you'd have to do the randomization-selection of your responses a bit differently in code design, as I don't think dictionaries also have index numbers ~ I could be wrong):

Conceptually, a Script Dictionary Attribute:

key item 1: evil_wizard
value 1A: (whatever script)
value 1B: (whatever script)
value 1etc: (whatever script)

key item 2: dragon_slaying_sword
value 2A: (whatever script)
value 2B: (whatever script)
value 2etc: (whatever script)

key item 3: dragon
value 3A: (whatever script)
value 3B: (whatever script)
value 3etc: (whatever script)

key item 4: king
value 4A: (whatever script)
value 4B: (whatever script)
value 4etc: (whatever script)

key item 5: princess
value 5A: (whatever script)
value 5B: (whatever script)
value 5etc: (whatever script)

item key X: whatever
value XA: (whatever script)
value XB: (whatever script)
value Xetc: (whatever script)

instead of a stringlist using index~position numbers for its items, you use actual words~strings, so if "evil_wizard" is selected, you'd do all of its values (added scripts), if "dragon_slaying_sword" is selected, you'd do all of its values (scripts), etc etc etc

A stringlist is stuck to using just strings (a limited msg script only), whereas a scriptdictionary you can use scripts (which means you can do ANY script: a 'msg' Script, a 'set a variable or attribute' Script, an 'if' Script, and etc, AND as many scripts as you want too).

Conceptually a String List Attribute:

(the index, number ~ position, starts from: the first added item to your list if using the GUI~Editor ===or=== the leftmost item in your list if doing it in code)

key (index number~position): 0
value (string): (whatever phrase: a word or sentence or paragraph)

key (index number~position): 1
value (string): (whatever phrase: a word or sentence or paragraph)

key (index number~position): 2
value (string): (whatever phrase: a word or sentence or paragraph)

key (index number~position): #etc
value (string): (whatever phrase: a word or sentence or paragraph)

----------------------------

(you still want to have a stringlist of, to hold~store, your responses, but we'll be using a scriptdictionary for adding in our scripts)

------------------------------

(a very complex-advance example, lol - sorry this interested me, so I tried to make it as powerful as I could in my limited ability)

<command name="npc_response_command">
<pattern>response #object#</pattern>
<script>
if (ListContains (global_data_object.npc_response_list, object.name)) {
invoke (global_data_object.npc_selection_dictionary, object.name)
} else {
msg ("Your inputted object is not an npc or it is not an npc that can respond to you")
}
</script>
<unresolved>Your input is not a visable object, or is not an existing object in the game</unresolved>
</command>

<object name="global_data_object">

<npc_response_list type="stringlist">
<value>npc1</value>
<value>npc2</value>
// etc npcs
</npc_response_list>

<npc1_response_list type="stringlist">
<value>hi, how are you?</value>
<value>goodbye, have a nice day.</value>
// etc
</npc1_response_list>

<npc2_response_list type="stringlist">
<value>what time is it?</value>
<value>what day is it?</value>
// etc
</npc2_response_list>

// etc npcX response stringlists

<npc_selection_dictionary type="scriptdictionary">

<item key="npc1">
random_selection = GetRandomInt (0, ListCount (global_data_object.npc1_response_list) - 1)
invoke (StringListItem (global_data_object.npc1_response_list, random_selection))
invoke (ScriptDictionaryItem (global_data_object.npc1_response_dictionary, random_selection))
</item>

<item key="npc2">
random_selection = GetRandomInt (0, ListCount (global_data_object.npc2_response_list) - 1)
invoke (StringListItem (global_data_object.npc2_response_list, random_selection))
invoke (ScriptDictionaryItem (global_data_object.npc2_response_dictionary, random_selection))
</item>

// etc etc etc

</npc_selection_dictionary>

<npc1_response_dictionary type="scriptdictionary">

<item key="0">
// script that sets your flag Attribute for response '0', so, for this example, let's say: SetObjectFlagOn (npc1, "hi_boolean_flag")
// actually, with this design, you really don't need to set a flag attribute, you can just add your desired script (your script that runs when: as if we were using a boolean flag and its set to true) right here
</item>

<item key="1">
// script that sets your flag Attribute for response '1', so, for this example, let's say: SetObjectFlagOn (npc1, "bye_boolean_flag")
// actually, with this design, you really don't need to set a flag attribute, you can just add your desired script (your script that runs when: as if we were using a boolean flag and its set to true) right here
</item>

// etc etc etc

</npc1_response_dictionary>

<npc2_response_dictionary type="scriptdictionary">

<item key="0">
// script that sets your flag Attribute for response '0', so, for this example, let's say: SetObjectFlagOn (npc2, "time_boolean_flag")
</item>

<item key="1">
// script that sets your flag Attribute for response '1', so, for this example, let's say: SetObjectFlagOn (npc2, "day_boolean_flag")
</item>

// etc etc etc

</npc2_response_dictionary>

// etc npcX response dictionaries

</object>


------------

if you don't want to use a scriptdictionary attribute instead...

you need to be able to collect~store (aka: set to another Attribute, or use, set to, a variable in your scripting block) your randomly selected response or its flag attribute, so you can then check it, if~switch (response_or_flag_X), to do the conditional of whether you run that following~nested script or not.

my complex code does have some example ways of doing this, albiet possibly not easily to notice~recognize, though

XanMag
So, a string dictionary is just like a string list except instead of adding strings (messages in this case), I would add scripts in which I could place a flag?

I've obviously never used string dictionaries. :)

HegemonKhan
yes, except you hopefully meant a *SCRIPT* Dictionary, not a String Dictionary, and there's the difference of it's key-value using 'words (actually you can use phrases: single words or multiple words: sentences ~ generally usually you'd use just a word though... unless you really want~need to match-up-use an entire msg block-response in~for your game design)' instead of index numbers

(think of dictionaries as like 'input->output' boxes, or if you rather, think of it kinda like the 'switch' Function~Script or an 'if-then' Script~Function)

String Dictionary:

string = string

example:

// horizontal:

<example_stringdictionary type="simplestringdictionary">dragon = Dragons breath fire; wizard = Wizards use magic; princess = Princesses always need rescuing</example_string_dictionary>

// vertical:

<example_stringdictionary type="stringdictionary">
<item>
<key>dragon</key>
<value>Dragons breath fire</value>
</item>
<item>
<key>wizard</key>
<value>Wizards use magic</value>
</item>
<item>
<key>princess</key>
<value>Princesses always need rescuing</value>
</item>
</example_string_dictionary>

examples in scripting:

x = "dragon"
y = StringDictionaryItem (Object_name.Stringdictionary_Attribute_name, x)
// you used "dragon" for the input, which thus outputs:
// y = "Dragons breath fire"

x = "wizard"
y = StringDictionaryItem (Object_name.Stringdictionary_Attribute_name, x)
// you used "dragon" for the input, which thus outputs:
// y = "Wizards use magic"

x = "wizard"
y = StringDictionaryItem (Object_name.Stringdictionary_Attribute_name, x)
// you used "dragon" for the input, which thus outputs:
// y = "Wizards use magic"


Object Dictionary:

string = Object

// see String Dictionary example above, same thing except the returned value~ouput is an Object: the name of the Object, not merely a string~text

// so, for example:

// (Room) Objects in the game: town, forest, mountain, swamp

<example_stringdictionary type="simplestringdictionary">0 = town; 1 = forest; 2 = swamp; 3 = mountain</example_string_dictionary>

x = "0"
y = ObjectDictionaryItem (Object_name.Object_Dictionary_name, x)
MoveObject (player, y)
// player is moved~set to~into the town

x = "1"
y = ObjectDictionaryItem (Object_name.Object_Dictionary_name, x)
MoveObject (player, y)
// player is moved~set to~into the forest

x = "2"
y = ObjectDictionaryItem (Object_name.Object_Dictionary_name, x)
MoveObject (player, y)
// player is moved~set to~into the swamp

x = "3"
y = ObjectDictionaryItem (Object_name.Object_Dictionary_name, x)
MoveObject (player, y)
// player is moved~set to~into the mountain


Script Dictionary:

string = Script(s)

(I hope you get the idea now)

----------

there's also this (instead of the specific dictionary types, which this generalized may probably be easier for you, and it is more powerful too, due to not being limited to those specific types ~ I just personally so far for what I do in my code like using the specific types of dictionaries):

(general) Dictionary:

string = (quest will handle whether your output~return values are strings, Objects, or Scripts)

and its 'DictionaryItem()' Function: http://docs.textadventures.co.uk/quest/ ... yitem.html

---------

I don't know if you'll notice that instead of my use of an 'x' variable merely holding the name of the input key to be used, you can use a List to return the name of the input key to be used, which thus also enables you to use randomization (if you want to):

game.example_stringlist = split ("dragon; wizard; princess", ";")

w = GetRandomInt (0, ListCount (Object_name.String_List_name) - 1)
x = StringListItem (Object_name.String_List_name, w)
y = StringDictionaryItem (Object_name.String_Dictionary_name, x)
// randomly selects (dragon, wizard, or princess), and returns~outputs:
// y = "Dragons breath fire"
// or
// y = "Wizards use magic"
// or
// y = "Princesses always need rescuing"

also, I made it easier to understand by using an 'x' (and for this final example, also a 'w') and separating it out on its own line, but if you prefer you can combine them into a single line (though separating them is probably better to do ~ I just like to combine them usually in my own scripting for personal preference), so for example with using this last example (there's two combinings: the 'w' into the 'x' and the 'x' into the 'y'):

y = StringDictionaryItem (Object_name.String_Dictionary_name, StringListItem (Object_name.String_List_name, GetRandomInt (0, ListCount (Object_name.String_List_name) - 1)))

XanMag
Yes, I meant script dictionaries, but...

Still ain't getting it!

Here is some code:

      <speak type="script">
n = GetRandomInt (0, ListCount (grumpy man.convo2) - 1)
msg ("The man glares at you and says, " + ScriptDictionaryItem(grumpy man.convo2, n))
</speak>
<convo2 type="scriptdictionary">
<item key="1">
msg ("Test 1")
</item>
<item key="2">
msg ("Test 2")
</item>
</convo2>


Are the item keys incorrect? I get this error message: Error running script: Error compiling expression '"The man glares at you and says, " + ScriptDictionaryItem(grumpy man.convo2, n)': FunctionCallElement: Could find not function 'ScriptDictionaryItem(QuestDictionary`1, Int32)'

Could find not function 'ScriptDictionaryItem(QuestDictionary`1, Int32)' : does this message mean the I need to Add a dictionary? I don't know... I've also done some stupid things like changing the ListCount to StringDictionaryCount. I've also butchered the code enough that the above is probably TOTALLY messed up!

I thought that would be correct...

HegemonKhan
you actually did something better in your design than mine, as I keep forgetting that there is the 'DictionaryCount()' for you to use (but there's no individual-separate 'String/Object/Script-DictionaryCount()' - but good guess at it!), so you can just change this line of yours:

n = GetRandomInt (0, ListCount (grumpy man.convo2) - 1)

to this:

n = GetRandomInt (0, DictionaryCount (grumpy man.convo2) - 1)

-----------------

and then (if it still doesn't work), due to my mistake, try changing the same line, from:

n = GetRandomInt (0, DictionaryCount (grumpy man.convo2) - 1)

to this:

n = ToString (GetRandomInt (0, DictionaryCount (grumpy man.convo2) - 1))

// I think this is what the error means (HK is crossing his fingers that this is the needed fix, lol), in that the 'GetRandomInt' is giving you an INTEGER value, but the 'ScriptDictionaryItem' requires a STRING value. If this does fix it (makes your code work), this is my fault, so my apologies for not originally providing this info about it and the code needed. Unfortunately, many of the Error Codes are still a bit cryptic and~or ambigious for me too, sighs.

------------

if it's still not working, possibly (but unlikely though) you need to separate out the 'ScriptDictionaryItem, so thus here's the corrected code for you, of what I mean:

      <speak type="script">
n = ToString (GetRandomInt (0, DictionaryCount (grumpy man.convo2) - 1))
m = ScriptDictionaryItem(grumpy man.convo2, n)
msg ("The man glares at you and says, " + m)
</speak>
<convo2 type="scriptdictionary">
<item key="1">
msg ("Test 1")
</item>
<item key="2">
msg ("Test 2")
</item>
</convo2>


------------

let me know if this works for you or not

XanMag
I currently have this code attached to the 'speak to' verb
n = ToString (GetRandomInt (0, DictionaryCount (grumpy man.convo2) - 1))
msg ("The man glares at you and says, " + ScriptDictionaryItem(grumpy man.convo2, n))


and this code attached to the convo2 attribute
      <convo2 type="scriptdictionary">
<item key="1">
msg ("Test 1")
</item>
<item key="2">
msg ("Test 2")
</item>
</convo2>


I get the same error message for each situation you proposed above! Argh.

Error running script: Error evaluating expression 'ScriptDictionaryItem(grumpy man.convo2, n)': The given key was not present in the dictionary.

HegemonKhan
oh my, the fix now may be a simple one... as I think (HOPE) it's *MAYBE* working now... except...

you need to change it to either:

n = ToString (GetRandomInt (0, DictionaryCount (grumpy man.convo2) - 1))
msg ("The man glares at you and says, " + ScriptDictionaryItem(grumpy man.convo2, n))

<convo2 type="scriptdictionary">
<item key="0">
msg ("Test 1")
</item>
<item key="1">
msg ("Test 2")
</item>
</convo2>


OR

n = ToString (GetRandomInt (0, DictionaryCount (grumpy man.convo2)))
msg ("The man glares at you and says, " + ScriptDictionaryItem(grumpy man.convo2, n))

<convo2 type="scriptdictionary">
<item key="1">
msg ("Test 1")
</item>
<item key="2">
msg ("Test 2")
</item>
</convo2>


--------------------------------

if not... you may need to use 'invoke',

msg ("The man glares at you and says, " + invoke (ScriptDictionaryItem(grumpy man.convo2, n)))

or, otherwise, maybe you can't have a msg Script having another msg script in it...

you may have to use a String Dictionary instead if you want to put your response into your msg script

or... we could (may have to) use concatenation, combining the two scripts' string responses together first and store it in a variable, which we than display it with the msg script.

XanMag
Simple error in my code maybe?

This is the code I have for 'speak to; talk to man'. I'm pretty sure my error is in here somewhere...
n = ToString (GetRandomInt (0, DictionaryCount (grumpy man.convo2) - 1))
m = ScriptDictionaryItem(grumpy man.convo2, n)
msg ("The man glares at you and says, " + m)


Here is the attribute I have on grumpy man called convo2:
<speak type="script">
n = ToString (GetRandomInt (0, DictionaryCount (grumpy man.convo2) - 1))
m = ScriptDictionaryItem(grumpy man.convo2, n)
msg ("The man glares at you and says, " + m)
</speak>
<convo2 type="scriptdictionary">
<item key="1">
msg ("Test 1")
</item>
<item key="2">
msg ("Test 2")
</item>
<item key="3">
msg ("Test 3.")
</item>
<item key="4">
msg ("Test 4")
</item>
</convo2>


Tests 1,2,3 work. 4 gives me an error: Error running script: Error evaluating expression 'ScriptDictionaryItem(grumpy man.convo2, n)': The given key was not present in the dictionary.

If I only have 2 keys added, I get an error on key 2. When I have 5 keys added, I get an error on 5.

I also get this when the non-error message fires: The man glares at you and says, Script: msg ("Test 3.")
Obviously I do not want that "script: msg ()" in there. Just the message! :)

The reason I have it set up as a script dictionary as opposed to a string list is because I want one of the things he says to trigger a flag, which I could not figure out how to do with a string list.

jaynabonne
Since your keys start with 1 and run to 4, you'd want this line:

n = ToString (GetRandomInt (1, DictionaryCount (grumpy man.convo2)))

(HK's post didn't have it right either, though you made it worse by grabbing the wrong line for the wrong case. :) )

jaynabonne
Also, you don't want to append the script onto the string. You want to run the script, but you can't invoke it inline either. You'd need to use a delegate for that, which is much more complicated. What you can do is:

OutputTextNoBr ("The man glares at you and says, ")
invoke(m)

The Pixie
You can use a generic list, and use that to store scripts. That might be easier than a dictionary (it might not; initialising the script dictionary will be easier). The basic format is like this:
l = NewList()
list add (l, this.script1)
scr = ListItem(l, 0)
invoke (scr)

HegemonKhan
sorry about that XanMag, I forgot to change the beginning of the range (dictionary's first item key) from 0 to 1 in the second example of mine. I was only looking at the ending range values, not the beginning.

----------

a List's items are automatically assigned these index numbers:

0 to (ListCount - 1)

ListCount = quantity of items in list, so since the list starts from 0, you need the 'ListCount - 1', as seen above

an example:

10 (quantity of) numbers, starting from 1:

(1) 1, (2) 2, (3) 3 (4) 4, (5) 5, (6) 6, (7) 7, (8) 8, (9) 9, (10) 10
1 to 10

this is why we like starting from 1, lol

10 (quantity of) numbers, starting from (0):

(1) 0, (2) 1, (3) 2 (4) 3, (5) 4, (6) 5, (7) 6, (8) 7, (9) 8, (10) 9
0 to 9

----------

a Dictionary has item keys, instead of the List's automatically assigned index numbers, which means that you have to manually type in the names for those item keys.

So, if you like (or it works better) working with ranges that start at zero, than you need to have your dictionary's item keys be named (manually) from 0 to whatever is your max range value.

likewise, if you like (or it works better) working with ranges that start at one, than you need to have your dictionary's item keys be named (manually) from 1 to whatever is your max range value.

This topic is now closed. Topics are closed after 60 days of inactivity.

Support

Forums