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.
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
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.
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
IDK. I think when I have a huge sparetime, I can give your code an actual in-game simulation
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.
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.)
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.
Weāll see when I finally can figure a proper system for it.
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?
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
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
Let me reread your code first
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
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.
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.
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}.