I'm having trouble with a list function I in the documentation.

So, I started making a text game years ago, and I found a function that creates a list of strings. I attached it to a verb, so when the verb is used, one of the listed strings, in this case, a message, is played, then that message is removed from the list. When all all the message strings have been cycled through the game executes code to move on in the programming.
Unfortunately, I accidentally deleted the object that contained this code and haven't been able to find a suitable replacement. I thought I had this code from the Documentation, but it doesn't function like the description said it would and not in the way I need.
The code I found was
list = Split ("One;Two;Three")
for (i, 1, 5) {
if (ListCount(list) > 0) {
s = PickOneString (list)
list remove (list, s)
msg (list)
}
else {
msg ("Default")
}
}

When I run it, it shows it's process by printing
List: One; Two;
List: One;
List:
Default
Default

It always leaves out one of the strings and does not remove the one that was selected. My old code just printed the selected string without Springs the process of choosing it.
What is a code I can use to achieve the effect I want?


It always leaves out one of the strings and does not remove the one that was selected.

I'm not sure what you mean there. In your example, the first string it selected was Three, which was removed (as demonstrated by the fact that it output "List: One; Two;"

It selects a string from the list, removes it, and then displays the remaining contents of the list.

We can probably help you, but it's not clear what you expected this code to do.
You've shown us what it does do, but could you give an example of the output you want to see? Show what it should look like.


Okay, I did give an example of what happens when I run the code, but I see it could be expanded so I will try again.
I have revised the code a little to hopefully make it a little more clear.
Here is the revised code.
"list = Split ("Hey;Hi;Hello")
for (i, 1, 5) {
if (ListCount(list) > 0) {
s = PickOneString (list)
list remove (list, s)
msg (list)
}
else {
msg ("Goodbye")
}
}"
As you can see it has three options to run and remove before it does the default message of Goodbye.
Now I will show you what happens when I use the verb in the game. I want you to keep in mind that everything I show is printed when the code is run.
(First Run)
List: Hey; Hi;
List: Hi;
List:
Goodbye
Goodbye
(Second Run)
List: Hey; Hello;
List: Hello;
List:
Goodbye
Goodbye
(Third Run)
List: Hi; Hello;
List: Hi;
List:
Goodbye
Goodbye
(Fourth Run)
List: Hey; Hi;
List: Hey;
List:
Goodbye
Goodbye

What is supposed to happen, according to the documentation, is that it should have randomly selected one of the three strings once each, then when it ran out, give the default message of Goodbye. Instead, it selected the same string multiple times and printed the default message after it each time.
Also, in my old code it did not show its process running the code that I wanted. With my old code, it looked like this.
(First Run)
Hello
(Second Run)
Hey
(Third Run)
Hi
(Final Run)
GoodBye

How do I get the results I just gave an example of?


Instead of msg(list) you probably want to put msg(s) in your code, since s is the word that was picked.


Okay, so it did make a change. Instead of this
List: Hey; Hi;
List: Hi;
List:
Goodbye
Goodbye
After your suggestion, it now says
Hey
Hello
Hi
Goodbye
Goodbye
I guess I can call that an improvement because it no longer says List: before a lot of the text. However, I still show all the possible messages and repeat the default. As I said, I just want the code to run, and it only says the one message it selected randomly, then removed it from the list and keeps doing so until none are left, and it plays the default message.
It still is not what I want as this point. Any further suggestions?


I really need help with this. As I said, this is the last coding hurdle I have to overcome, and then I can just focus on creating content. I know it's possible because someone on here told me how to before. It's an important component to give my game a way to stand out in design.
It occurs to me that I might not have explained the issue in a way that makes sense for everybody. So I you have a question about my explanations or for clarification, just ask.


I feel like I saw this in the tutorial where you make zombies? Let me look

It looks like Pixie spent some time talking about various ways to use split lists when programming NPCs to pick from lists of actions. Maybe this will help https://docs.textadventures.co.uk/quest/independent_npcs.html

I'm only just surface-level learning with the lists and dictionaries yet. So I might not be far behind you before i'm wondering something like this myself.


Okay, I think I misunderstood what you meant with "first run", "second run"... Each time you run the function/verb you only want to print one of the options, not all of them, correct?

In this case there are two changes you need to make:
The list needs to be persistent and not recreated every time the function is run. Easiest way would be to add a string list as an attribute to the object the verb is running on. After this you need to access this attribute, which depend on the way you implemented it.

The second change is to get rid off the for-loop. That one is responsible for printing everything at once, which you don't want.

With these two changes the script of a verb on an object, which holds the list on a string list attribute called greetings would look like this:

if (ListCount(this.greetings) > 0) {
  picked = PickOneString (this.greetings)
  list remove (this.greetings, picked)
  msg (picked)
}
else {
  msg ("Goodbye")
}

I also renamed the variable as I personally don't like one letter variables. The keyword this only works for scripts that belong to the same object that also holds the attribute. You could also use the name of the object ( my_talking_npc.greetings), which would break in case you rename the object.
If you use a function instead, you either would need to either provide the list (and I am not even sure that removing from that list would be a persistent change (aka "call by reference")) or the object that holds the list and make sure the attribute actually exists on that object. So a lot more complicated and volatile.

If this is about conversations, take a look at Pixies Conversations Lib.:
https://github.com/ThePix/quest/wiki/Library:-Conversations


@GeminiNeule
I tried what you suggested, and it works great. In fact, it's even better than the old code I was using because in that one, I had to enter the text of each message in the split part of the code, and it was very confusing the longer it got. This way, the messages are in an attribute with a separate entry for each response. Much more organized and easier to edit.
Thank you so much.
And thanks to everyone else who replied.


If you go to the "Attributes" tab on an object, you can add an attribute in the bottom section. When you select that new attribute, you can select the type in a combobox on the right section next to the list. Default attribute type would be "String", you should be able to switch that to "String List".

You can also set up an attribute via code, but this should not be within the verb script, because this would basically restore the list to it's original state everytime and you never run out of options. Such code would look like this:

my_talking_npc.greetings = Split ("Hey;Hi;Hello")

Or you could first create an empty StringList and add items to it seperately. I use this often when the content of the list depends on other conditions.

my_talking_npc.greetings = NewStringlist()
list add (my_talking_npc.greetings, "Hi")

I try to not add attributes within the code, because this is harder to maintain if you need to find out which piece of code adds a certain attribute and you need to check whether or not a certain object possesses the attribute you are looking for (there is a function for that, but using it everywhere bloats the code).

If you want to know how it actually looks like in code view, look at inventoryverbs in the following sample.

      <object name="example_object">
        <inherit name="editor_object" />
        <drop type="boolean">false</drop>
        <inventoryverbs type="stringlist">
          <value>Untersuche</value>
          <value>Benutze</value>
        </inventoryverbs>
        <feature_usegive />
        <use type="script">
        </use>
      </object>

@GeminiNeule
I tried what you suggested, and it works great. In fact, it's even better than the old code I was using because in that one, I had to enter the text of each message in the split part of the code, and it was very confusing the longer it got. This way, the messages are in an attribute with a separate entry for each response. It is much more organized and easier to edit.
However, I just turned the attribute into a list of strings and entered each response individually which worked great when called by your code.
Thank you so much.
And thanks to everyone else who replied.


Glad to help. Happy writing! :)


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

Support

Forums