Change String List by Index

cybernetsurfer7
I was wondering if it is possible to change a String List by the index number of a string. For instance, if I have the following list:

StringListName( "Item1", "Item2", "Item3")

And I want to change the second item (so index 1) to be "Item4" so that the string now reads:

StringListName( "Item1", "Item4", "Item3")

Is there a way to do that?

Thanks!

HegemonKhan
A question about what you want:

do you just want to change the "2" to "4" (but the item itself remains the same), or do you want it to be a new "4th" item?

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

this is beyond my ability, as this probably deals with string patterns coding, as well as knowing the underlying code and~or workings of the list functionality, but I suppose you could probably do it this way:

(I'm presuming your want to replace your item2 with a new "4th" item4)

http://quest5.net/wiki/If
http://quest5.net/wiki/EndsWith
http://quest5.net/wiki/StringListItem
http://quest5.net/wiki/Split
http://quest5.net/wiki/List_add
http://quest5.net/wiki/NewStringList
http://quest5.net/wiki/List_remove

Scripting: whatever_function_name (item4_name)

<function name="whatever_function_name" parameters="item4">
-> if (EndsWith (StringListItem (Object.string_list_name, 1),"2") = true) {
->-> Object.string_list_name = split ("item1;item4;item3",";")
-> }
</function>

~ OR, maybe this would work too... ~

<function name="whatever_function_name" parameters="item4">
-> if (EndsWith (StringListItem (Object.string_list_name, 1),"2") = true) {
->-> list remove (Object.string_list_name, "item3")
->-> list remove (Object.string_list_name, "item2")
->-> list remove (Object.string_list_name, "item1")
->-> list add (Object.string_list_name, "item1")
->-> list add (Object.string_list_name, "item4")
->-> list add (Object.string_list_name, "item3")
-> }
</function>

~ OR, maybe it has to be done this way instead... ~

<function name="whatever_function_name" parameters="item4">
-> if (EndsWith (StringListItem (Object.string_list_name, 1),"2") = true) {
->-> list remove (Object.string_list_name, "item3")
->-> list remove (Object.string_list_name, "item2")
->-> list remove (Object.string_list_name, "item1")
->-> Object.string_list_name = NewStringList ()
->-> list add (Object.string_list_name, "item1")
->-> list add (Object.string_list_name, "item4")
->-> list add (Object.string_list_name, "item3")
-> }
</function>

Liam315
You can remove one item and add another, but aside from StringListSort which orders the list alphabetically, there's no way to affect the position of an item in the list in a way that isn't a massive unwieldy hassle.

If the order of the list is important, you'd be better off using a string dictionary instead, using numbers as the keys. e.g.

dictionary:
1 - item1
2 - item2
3 - item3


dictionary remove (dictionary,"2")
dictionary add (dictionary,"2","item4")


the dictionary would now read
1 - item1
2 - item4
3 - item3

EDIT: I put quotation marks around the numbers in the add and remove functions; although a number, the keys are still strings by true definition and not having them will throw up an error.

cybernetsurfer7
HegemonKhan: Your suggestion was more or less what I was trying to do. After getting into it I realized what a pain that was going to be. I know from other coding experience that in an array you can target an index and change its value. I don't think Quest treats stringlists quite like arrays, which is why there isn't a built in option to alter the value based on its index (unless there is and all of us have missed it).

Liam315: Your suggestion is exactly what I need. It's essentially like building an array with custom index numbers. I'm making the conversation system for my game and I wanted to be able to have one talking point replaced by another but remain in the same order. I just created a master list of responses in a switch statement and then I can dynamically add and remove my desired items from the dictionary attribute. Thanks very much!

george
I agree with Liam that mucking around with list order probably isn't what you want to do, but just for fun I gave this a try.

Demo:


You are in a room.

> jump
List: cat; mouse; dog;

> replace crow 1
List: cat; crow; dog;




<!--Saved by Quest 5.4.4873.16527-->
<asl version="540">
<include ref="English.aslx" />
<include ref="Core.aslx" />
<game name="list insert">
<gameid>e2a3af6b-89b2-471b-b251-7e9b45fd4eb5</gameid>
<version>1.0</version>
<firstpublished>2014</firstpublished>
</game>
<command name="jump">
<pattern type="string">^jump$</pattern>
<script>
msg (game.pov.myList)
</script>
</command>
<object name="room">
<inherit name="editor_room" />
<object name="player">
<inherit name="editor_object" />
<inherit name="editor_player" />
<myList type="stringlist">
<value>cat</value>
<value>mouse</value>
<value>dog</value>
</myList>
</object>
</object>
<command>
<script>
msg (StringListReplace (game.pov.myList, text1, text2))
</script>
<pattern>replace #text1# #text2#</pattern>
</command>
<function name="StringListReplace" parameters="xs, x, pos" type="stringlist">
pos = ToInt(pos)
tmp = NewStringList()
for (i, 0, pos - 1) {
list add (tmp, StringListItem(xs, i))
}
list add (tmp, x)
for (i, pos + 1, ListCount(xs) - 1) {
list add (tmp, StringListItem(xs, i))
}
return (tmp)
</function>
</asl>


I don't really catch any errors (like picking a position out of bounds) but it would be simple to add.

HegemonKhan
doh, my stupid uncreative~un'innovative~"in_the_box" thinking~brain was stuck on using a String List, argh.

I should've mentioned about string dictionaries... lol (too tunnel visioned on you asking about with string lists, sighs)

-----

anyways, I don't understand arrays very well... but if arrays are just tables (or whatever they're called), than that's quest's dictionaries:

viewtopic.php?f=10&t=4195

I know you probably don't need dictionaries or lists explained, as you know coding and can work with arrays (which confuse me), but just for self completion of help to you, you can look at the link above. You'll need to scroll down a bit through my post.

also, if just in case you wanna see a way of using string dictionaries (though very amature coding), you can take a look at my "travel" coding:

<asl version="540">
<include ref="English.aslx" />
<include ref="Core.aslx" />
<game name="Testing Game Stuff">
<gameid>eef801a1-4e6b-4b0a-bdbf-8f3ecfa8389c</gameid>
<version>1.0</version>
<firstpublished>2013</firstpublished>
<turns type="int">0</turns>
<statusattributes type="simplestringdictionary">turns=</statusattributes>
<start type="script">
msg ("Important Note:")
msg ("Type in: help")
</start>
</game>
<object name="homeland">
<inherit name="editor_room" />
<object name="player">
<inherit name="editor_object" />
<inherit name="editor_player" />
</object>
</object>
<object name="grassland">
<inherit name="editor_room" />
</object>
<object name="plains">
<inherit name="editor_room" />
</object>
<object name="desert">
<inherit name="editor_room" />
</object>
<object name="tundra">
<inherit name="editor_room" />
</object>
<object name="swampland">
<inherit name="editor_room" />
</object>
<object name="mountains">
<inherit name="editor_room" />
</object>
<object name="forest">
<inherit name="editor_room" />
</object>
<object name="wasteland">
<inherit name="editor_room" />
</object>
<object name="coastland">
<inherit name="editor_room" />
</object>
<object name="hills">
<inherit name="editor_room" />
</object>
<command name="help_command">
<pattern>help</pattern>
<script>
help_function
</script>
</command>
<command name="explore_command">
<pattern>explore</pattern>
<script>
explore_function
</script>
</command>
<command name="travel_command">
<pattern>travel</pattern>
<script>
travel_function
</script>
</command>
<object name="data_object">
<inherit name="editor_object" />
<travel_string_list type="simplestringlist">homeland</travel_string_list>
<homeland_events_string_list type="simplestringlist">grassland_discovery;plains_discovery;desert_discovery;tundra_discovery;swampland_discovery;forest_discovery;mountains_discovery;hills_discovery;wasteland_discovery;coastland_discovery</homeland_events_string_list>
<homeland_events_script_dictionary type="scriptdictionary">
<item key="grassland_discovery">
list add (data_object.travel_string_list, "grassland")
msg ("You've discovered the grassland! Now, you can travel to the grassland and explore it!")
</item>
<item key="plains_discovery">
list add (data_object.travel_string_list, "plains")
msg ("You've discovered the plains! Now, you can travel to the plains and explore it!")
</item>
<item key="desert_discovery">
list add (data_object.travel_string_list, "desert")
msg ("You've discovered the desert! Now, you can travel to the desert and explore it!")
</item>
<item key="tundra_discovery">
list add (data_object.travel_string_list, "tundra")
msg ("You've discovered the tundra! Now, you can travel to the tundra and explore it!")
</item>
<item key="swampland_discovery">
list add (data_object.travel_string_list, "swampland")
msg ("You've discovered the swampland! Now, you can travel to the swampland and explore it!")
</item>
<item key="forest_discovery">
list add (data_object.travel_string_list, "forest")
msg ("You've discovered the forest! Now, you can travel to the forest and explore it!")
</item>
<item key="mountains_discovery">
list add (data_object.travel_string_list, "mountains")
msg ("You've discovered the mountains! Now, you can travel to the mountains and explore it!")
</item>
<item key="hills_discovery">
list add (data_object.travel_string_list, "hills")
msg ("You've discovered the hills! Now, you can travel to the hills and explore it!")
</item>
<item key="wasteland_discovery">
list add (data_object.travel_string_list, "wasteland")
msg ("You've discovered the wasteland! Now, you can travel to the wasteland and explore it!")
</item>
<item key="coastland_discovery">
list add (data_object.travel_string_list, "coastland")
msg ("You've discovered the coastland! Now, you can travel to the coastland and explore it!")
</item>
</homeland_events_script_dictionary>
</object>
<turnscript name="global_turnscript">
<enabled />
<script>
game.turns = game.turns + 1
</script>
</turnscript>
<function name="help_function">
msg ("Type 'explore' to explore your area.")
msg ("Type 'travel' to travel to different areas.")
</function>
<function name="explore_function"><![CDATA[
switch (game.pov.parent) {
case (homeland) {
result_1 = ListCount (data_object.homeland_events_string_list) - 1
if (result_1 >= 0) {
result_2 = StringListItem (data_object.homeland_events_string_list,GetRandomInt(0,result_1))
invoke (ScriptDictionaryItem (data_object.homeland_events_script_dictionary,result_2))
on ready {
foreach (item_x, split ("grassland_discovery;plains_discovery;desert_discovery;tundra_discovery;swampland_discovery;forest_discovery;mountains_discovery;hills_discovery;wasteland_discovery;coastland_discovery",";")) {
if (result_2 = item_x) {
list remove (data_object.homeland_events_string_list, result_2)
}
}
}
} else {
msg ("There seemingly is nothing left to explore in this area.")
}
}
}
]]></function>
<function name="travel_function">
show menu ("Where do you wish to travel?",data_object.travel_string_list,false) {
if (not game.pov.parent = GetObject (result)) {
game.pov.parent = GetObject (result)
} else {
msg ("You are already at this area.")
ask ("Try again?") {
if (result=true) {
travel_function
} else {
msg ("You realize that you need to discover a new area to travel to first, before you can travel to that place.")
}
}
}
}
</function>
</asl>


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

http://quest5.net/wiki/Using_Dictionaries
http://quest5.net/wiki/Scriptdictionary
http://quest5.net/wiki/ScriptDictionaryItem

you may want to look into using Script Dictionaries, as I think they'd cut down on the amount of coding~writing~pasting you'd need to do, as opposed to using "Switch" or multiple "Ifs" Scripts.

Script Dictionaries:

String_1 = Script_1

Scripting: invoke (ScriptDictionaryItem (Object.ScriptDictionary, "string_1"))

cybernetsurfer7
Ok, so I'm running into another issue here. I'm using a string dictionary to show conversation options. I'm trying to have a list like this:

Key Value
1 Option 1
2 Option 2
4 Option 4

Now, when you click on say, Option 2, I want to remove it and add in an Option 3, however it ends up like this:

Key Value
1 Option 1
4 Option 4
3 Option 3

Is there any way to sort a string dictionary based on its key?

george
Good question. Looking here,

http://quest5.net/w/index.php?title=Cat ... t#mw-pages

I don't see that you can easily sort dictionaries by key.

Now, you can sort string lists, http://quest5.net/wiki/StringListSort

So perhaps you can use a StringList for the presentation to easily sort, and use a backing Dictionary as the conversation database.

Otherwise, you'll have to write your own dictionary sort. It's not hard, but maybe tedious in pure Quest and not necessary for what you want to do.

It probably would be rather easier in Javascript though, so there is that option.

Pertex
cybernetsurfer7 wrote:
Now, when you click on say, Option 2, I want to remove it and add in an Option 3, however it ends up like this:

Key Value
1 Option 1
4 Option 4
3 Option 3

Is there any way to sort a string dictionary based on its key?


Is it necessary to sort a dictionary??? I would access the dictionary by key.

Liam315
What you need to do will depend on how you're building your conversation menus. Something like the following would display the values of a dictionary in numerical order determined by key -

maxkey = 1
foreach (key, dictionary) {
if (ToInt(key) > maxkey) {
maxkey = ToInt(key)
}
}
for (i, 1, maxkey, 1) {
if (DictionaryContains(dictionary, i)) {
msg (StringDictionaryItem(dictionary, i))
}
}


This would only print every item in the dictionary in numerical order, to display them as a list of options in a menu would be slightly different. You'd do something like:

sorteddictionary = NewStringDictionary()
maxkey = 1
foreach (key, dictionary) {
if (ToInt(key) > maxkey) {
maxkey = ToInt(key)
}
}
for (i, 1, maxkey, 1) {
if (DictionaryContains(dictionary, i)) {
dictionary add (sorteddictionary, i, StringDictionaryItem(dictionary, i))
}
}
ShowMenu ("", sorteddictionary, true) {
//rest of script here
}


Depending on the specifics of what you're trying to achieve you may need to do things differently, but hopefully this helps. I haven't tested the script so there may be bugs.

cybernetsurfer7
Liam,

Thank you! I used a variation on what you sent me. Here:

sorteddictionary = NewStringDictionary()
//stores maximum key number in dictionary
maxkey = 1
//finds maximum key number in dictionary
foreach (key, unsortedDict) {
if (ToInt(key) > maxkey) {
maxkey = ToInt(key)
}
}
//finds and sorts entries from unsortedDict into sorteddictionary
for (i, 1, maxkey, 1) {
i = ToString(i)
if (DictionaryContains(unsortedDict, i)) {
dictionary add (sorteddictionary, i, DictionaryItem(unsortedDict, i))
// dictionary remove (unsortedDict, i)
}
i = ToInt(i)
}
//returns sorted dictionary
return (sorteddictionary)


unsortedDict is a Parameter that gets passed to it from another function that controls the conversation switch. The issue was that, in order to correctly identify the entry in the dictionary, I had to first transfer the "i", an integer, into a string. And then after I'd used the string, I had to turn it back into an integer so that it could get added to and reused for the next loop. It returns the string and restores it in whatever was passed to it. Now I can reuse this Function whenever I need to sort any dictionary by having that dictionary set itself to this function with itself passed to it (ie. myDictionary = SortDictionary(myDictionary)) This of course only works if the keys for the dictionary are numbers. Thanks so much for all of your help!

Liam315
Cool, glad you got it working :)

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

Support

Forums