How To: List/Array in Choicescript v4.1

Alright, so you can make lists in choicescript using the *script command and whatnot, but that will make it hard/impossible to get your game published (So I've heard).
That is why I made this code. It uses just a few variables to:
-make an unlimited number of lists with unlimited length
-add items to lists
-read any item from the list, ie the first item or the twentieth item, etc
-replace an item in the list with something new, no hassle
-deleting an item in a list by index (aka deleting item one or item ten)
-a way to count the number of items in the list easily

I plan to add:
-finding which items in the list have a certain string or number, ie "apple" is the first, third, and eleventh item in the list  (will look like 1^3^11  or something)
-inserting an item bewteen two existing items
-a lot more that I forgot I'm going to add
-whatever you people suggest (reply below)

**I plan to make it so when new versions come out, your old scripts will still work 100%.**

You can use this in your own game to make lists.
So without further ado, take a look at this:

You must first place the twiger_functions file **([Get it Here](https://www.dropbox.com/s/ygmxd9tjqcm7tty/twiger_functions.txt?dl=0)v4)** in your scenes list.

---
Making lists/arrays. (one dimensional) You can use this to store strings or numbers.
All done by Twiger_Fluff aka Twig Wisp       (and the ChoiceScript makers,   Choice of Games LLC)
This is merely version 4

Time spent making so far: 12 hours

---

To create list variable (in startup.txt):
---
*create MyList "aa"
*set Mylist ""
**Does not need to be called MyList but you do need to create it with "aa"


Please also make these variables (only one of each needed, no matter how many lists you have.):

*create lists_listname "aa"
*create lists_index 0
*create lists_output ""
*create lists_replace ""
*set lists_listname ""
---
(same as the list variable, needs to be set to any two characters then to "" in order to pass quicktest

---

To add and item to the list (if you want oranges in your list) (must have a ^ and no space):
---
*set Mylist MyList & "^Oranges"
You can also add several at one time:
*set Mylist Mylist & "^Apples^Oranges^Bananas"

---
Your list should look like this (should start with a caret [the ^ symbol]):   ^Apple^Oranges^Bananas^other stuff^all the words I want^blah^blah^code by Twiger_Fluff^bleh^one^1^2^two
---
---

To count the number of items in a list:
---
*set lists_listname "mylist"
**The name of your list must be in quotes.**
*gosub_scene twiger_functions count
num of items: ${lists_output}
**The number of items will be stored in ${lists_output}
---


---
Next is how to read any item from a list, ie item one is apples, item three is bananas.
note: list name should be in quotes ( "  " )
---
*set lists_listname "mylist"
**Set this to the name of your list, does not need to be used if your list's name is already in it.**
*set lists_index 1
**Set this to the number of the item you want to refer to. ie: milk, cheese, eggs. #2 is cheese. Does not need to be set if already the right number.**
*gosub_scene twiger_functions find
**This runs the function and once it is done, the item will be named in lists_output**
You have ${lists_output}.
**This will give you the statement "You have milk." assuming your lists is ^milk^cheese^eggs**
**You must use lists_output before running the function again.**
---

To delete an item by index:
---
*set lists_listname "mylist"
**Set this to the name of your list, does not need to be used if your list's name is already in it.**
*set lists_index 1
**Set this to the number of the item you want to refer to. ie: milk, cheese, eggs. #2 is cheese. Does not need to be set if already the right number.**
*gosub_scene twiger_functions delete
**Unlike the find function, this does not have an output, it just changes the list
---
To replace an item in a list, such as making ^apples^oranges^my bad, sire^giant become ^apples^bananas^my bad, sire^giant
---
*set lists_listname "mylist"
**Set this to the name of your list, does not need to be used if your list's name is already in it.**
*set lists_index 2
**Set this to the number of the item you want to refer to. ie: milk, cheese, eggs. #2 is cheese. Does not need to be set if already the right number.**
*set lists_replace "bananas"
**This is for what you are putting in place of the previous item**
*gosub_scene twiger_functions replace
**Unlike the find function, this does not have an output, it just changes the list**

That is all for now. Check in later for updates.
I will no longer post untest/non-working versions here. All posted versions are stable.
9 Likes

Itā€™s a clever idea to use the string manipulation mechanics to allow for unlimited length. Iā€™m not sure how well it will perform on longer lists/strings, but seeing as thereā€™s no current alternative, I wonā€™t knock it!

Only other thing Iā€™d say is you should test it yourself as well :slight_smile:

5 Likes

HAAAGGHHH!!!
I know you havenā€™t tested it nor you try it in actual ā€œin-gameā€ simulation, but I can see where youā€™re going with this snippet of code.

AWWEEE SOOOMM. :star_struck:

But, TBH, itā€™s pretty hard to get the motivation to try my hand on it. Not especially when youā€™ve this WIP where you promised everyone to be updated under 7 days :crazy_face:

:exploding_head:


IDK. I think when I have a huge sparetime, I can give your code an actual in-game simulation :wink:

3 Likes

In under seven days, huh? Well this friday Iā€™m leaving for a week long trip, so Iā€™d have to work on it now.
Itā€™s 1 AM and you know what? Iā€™m not tired. Iā€™m going to first test what I have so far, then add some more stuff to it, test that, and then go back to sleep at like 10 am, lol.

Edit: the problem is Iā€™m not far enough into a game to start using list so testing it will take awhile.

1 Like

These scripts are so long, maybe they should be put into their own scenes.
It will be a while (if ever) before I test just how long these can be/how fast it runs. Right now Iā€™m focused on it working, period.

@Szaal @CJW Hereā€™s a great idea:
What if I made it so people could just copy and paste this whole script into a .txt file in their scenes folder, and all theyā€™d have to do is something like (the ā€˜funā€™ is short for function, since itā€™s just like custom functions):

*set fun_listname MyList
*set fun_item 1
*set fun_output MyVarible
*goto_scene read

(Tthat scene would have a *return command and leave the output in the MyVariable or whatever they set it as.)

2 Likes

When I think about it, I think this code is suitable for inventory system, but using *temp instead of *create command, perhaps?

I mean, I used similar method of concatenation to make a record of ā€œlegendary deedsā€ of MCā€™s choice, but thatā€™s about it. A string of text.

Itā€™s not necessarily a bad code, tho. Besides, itā€™s much more less off-putting to code

rather to go back to startup.txt, *create several new boolean variables, and go back and *set them to true.

But with *temp command, weā€™ll probably have a less luxury of ā€œpermanently-saved value.ā€
Take example of MC enchancing their weapon and have its [DMG] increased by +5. With temp, weā€™ll probably have to go retrack and re-*set these changes.

But IDK. I guess Iā€™m just rambling. :crazy_face:
Weā€™ll see when I finally can figure a proper system for it.

1 Like

I specifically use non-temp values because itā€™s supposed to last the whole game.
Edit: Or did you mean temp variables for the scenes specifically for running the function, in which case, yes, several of those could be temps, thank you.

P.S. can you help me with this problem?:

When I do something like:

*set lists_listname mylist
${lists_listname}#4

or

mylist#4

It always gives me the entire contents of that variable instead of just the 4th character.

I also get this error: Invalid expression, couldnā€™t extract another token: ${lists_listname}#lists_char = ā€œ^ā€

I think it should be
${mylist#4}

But let me check back the wiki quick.
Here is the link if you want to read it yourself (Search ā€œText Tricksā€ section)


About the non-temp variables, I mean there will be these moments where the author ā€œOh yeah, weā€™ll probably need a new item. Letā€™s write the variables for itā€ and they go back to the startup.txt for etc.etc.

And when you think about it, you might as well write those new variables instead of updating the array and *set the new variablesā€¦
unless Iā€™m missing something here?

1 Like

Yes, this works for that case.

However, still no idea about the token thing and *if ${lists_listname}#${lists_char} = ā€œ^ā€ doesnā€™t work either. nor *if ${lists_listname#lists_char} = ā€œ^ā€

Iā€™m not sure what youā€™re saying here.

I see. You can only do a conditional check with boolean variables, not string.

Your case

is actually doing a conditional check with string. ${lists_listname} donā€™t contain any TRUE/FALSE value, which should be the reason why you keep getting the ā€œtoken error.ā€

Plus, youā€™d like to put a space between the *if and the #Option. (ex: *if (variable) #Option)
CScript seems donā€™t particularly fond of it.


Meeh, NVM with that. Not really a big issue, actually.
TBH, I donā€™t even know what was Iā€™m saying, too :sweat_smile:

1 Like

But isnā€™t ${lists_listname}#lists_char = ā€œ^ā€ one big boolean? or at least (${lists_listname}#lists_char = ā€œ^ā€) should be considered a boolean.
Removing spaced did nothing.

When I change it to: (which probably ruins it anyway)

*if lists_listname#lists_char = "^"

it gives me this error instead:
functions/read line 8: Invalid expression at char 27, expected no more tokens, found: EQUALITY [=]

Hmmā€¦ letā€™s take several steps back here and re-track everything from there.

So you want an #Option thatā€™s only shows up when certain condition is met, right?

And in this case, the condition is (${lists_listname}#list_char = ā€œ^ā€ā€¦

waitā€¦

ā€¦

Ah! I see where youā€™re going! I keep mistaking the # as #Option under *choice ! silly me :sweat_smile: :rofl:
Let me reread your code first :sweat:

1 Like

O-M-Gosh I forgot thatā€™s very similar the syntax for like hidden/unavailable choice. I see how I confused you.
The full code for it is this:

*comment takes in lists_listname, lists_index, and lists_output

*temp lists_char 0
*temp lists_count 0
*temp lists_string ""
*label alpha
*set lists_char (lists_char + 1)
*if ${lists_listname}#lists_char = "^"
  *set lists_count (lists_count + 1)
  *if lists_count = lists_index
    *goto beta
  *else
    *goto alpha
*else
  *goto alpha

*label beta
*set lists_char (lists_char + 1)
*if ((${lists_listname}#lists_char = "") OR (${lists_listname}#lists_char = "^"))
  *goto endofthisone
*else
  *set lists_string (lists_string & ${lists_listname}#lists_char)
  *goto beta
  
*label endofthisone
*set ${lists_output} lists_string
*return
1 Like

Alright, got it all sorted.

Itā€™ll be kinda hard to explain, so Iā€™ll just go on with the code.
Try this one

*if ({lists_listname}#list_char = "^")

What I did is removing the $ mark and put the condition on another parentheses.

1 Like

Yeah. Itā€™s odd because when you use two (maybe less even) variables to find a specific character, it counts as an entire condition, even before the ā€˜=ā€™, and having two or more conditions requires parenthesis.

I was not aware of this when I wrote How to deal with arrays
I am glad somebody figured out how to do arrays out of strings. Probably the performance is an issueā€¦ To access an element you have to scan the whole string every time. In any case, very nice concept.

I donā€™t think itā€™ll ever be a problem unless you have 1000+ elements in the array. Computers these days are very fast and javascript is made with large strings in mind.

1 Like

Hmmm. Been thinking. What if I somehow set a ā€œstandardā€ value for the length of each element of the string and adapt the function to simply ā€œjumpā€ that length each time.

IIRC it is how C language work while addressing memory allocation. Iā€™ve been thinking of how to implement something like that in choiceScript.

Iā€™ve once used the AMAZING @Twiger_Fluff 's Twiger_Fluff code to store long arrays of information in Arrays. But eventually I begin to have these slowdowns while addressing, retrieving or updating data in long-ass arrays of stringsā€¦

For example Iā€™ve got this time when I had to create a subroutine that updated the weekdays each time the player got to bed. To do that I counted how many letters each day of the week got, and discovered the longest word: Wednesday. with nine letters.

So I created it:

*create ArrayDay "Sunday|***Monday|***Tuesday|**Wednesday|Thursday|*Friday|***Saturday||"

And each Time I needed to update a new weekday, I simply used a *gosub that multiplied the week day (0 for Sunday, 6 for Saturday) for 10 and ā€œretrievedā€ the substring with the week day name for a weekday variable. (I used a simple parser that read the ā€œ|ā€ symbol as ā€œend of wordā€)

My proposition is, What if I create a routine that read the ā€œbiggestā€ word or string length in a array of strings and simply make that the length of each sub-string in the array, like I did in the example above?

fast travel index access without have to use an for each that read each and all chararcters in a (looong) string of characters to find the desired value.

That ā€œstandard lengthā€ of each sub-string can be used by fast access when using a hypothetical ā€œfind by Indexā€ command and, and store that length value in the very array as a metadata stored in the very array. (so no conflict with arrays with different sub-string lengths of indexers)

makes sense?

I was trying to code a farming system in my game, but I found a problem. For example: If you plant 1 acre on day 1, it finishes on day 21. And if you plant another on day 2, it finishes on day 22. You can plant up to 1000 acres. The problem is that you would need to keep track of up to 1000 times that you planted an acre. This couldnā€™t be achieved with variables, because it would need 1000 of them.

I needed a list/array function, but I couldnā€™t find a pre-programmed way to do this. So I figured out a way to do it with only 1 variable.

IF YOU IMPROVE THIS OR HAVE SUGGESTIONS, PLEASE TELL ME. Thanks!

Here is the codeā€¦

*comment first letters will always be the smallest numbers
*label start
*temp day 30
*comment the rounds that you planted an acre. The "A's" separate the numbers.
*temp daysPlanted "7A12A13A19A24A"
*comment currentSimulatedDay is the first part of "daysPlanted". This is the part this is being "simulated".
*temp currentSimulatedDay ""
*comment this is "dayPlanted" w/o days planted on > 20 days ago
*temp newDaysPlanted ""
*comment index is a number that increases. This makes it simulate each letter individually.
*temp index 0
*temp index2 0
*comment you get $1 from each planting from longer than 20 days ago
*temp moneyMade 0
*label go1
*comment if the current index is not at the last letter of the "daysPlanted" code.
*if not(index = (length(daysPlanted)))
	*comment goes to next letter
	*set index +1
	*comment if index is on "A"
	*if ("${daysPlanted#index}" = "A")
		*comment if the first crop was planted > 20 days ago
		*if (currentSimulatedDay + 20) < day
			*set moneyMade +1
			daysPlanted ${daysplanted}
			currentSimulatedDay ${currentSimulatedDay}
			*label go2
			*comment if the current index is not at the last letter of the "daysPlanted" code.
			*if not(index = ((length(daysPlanted))))
				*comment goes to next letter
				*set index +1
				*comment writes newDaysPlanted as daysPlanted w/o days more than 20 days ago
				*set newDaysPlanted "${newDaysPlanted}${daysPlanted#index}"
				*goto go2
			*comment goes to next letter
			*set index +1
			newDaysPlanted ${newDaysPlanted}
			*comment deletes the first letters of daysPlanted
			*set daysPlanted newDaysPlanted
			*comment resets necessary code 
			*set newDaysPlanted ""
			*set index 0
			*set currentSimulatedDay ""
			*goto go1
		*else
			*goto end
			
	*else
		*comment sets "temp" to the first part of daysPlanted
		*set currentSimulatedDay "${currentSimulatedDay}${daysPlanted#index}"
		*goto go1

*label end
currentSimulatedDay ${currentSimulatedDay}
You made $${moneyMade}!

daysPlanted is now ${daysPlanted}.
1 Like