šŸ§° [TOOL] CSLIB - ChoiceScript Library

banner

A compass for the maze.

Hi all! @cjw, @choicehacker, and I would like to introduce to you CSLIB v0.1!

:gem: CSLIB is a high-quality collection of helpful routines/functions (known collectively as a ā€œlibraryā€) for ChoiceScript.

:gem: CSLIB aims to add a whole host of new functionality to ChoiceScript via *gosub_scene calls, for e.g.:

*gosub_scene cslib_string reverse ā€œHello World!ā€

${cslib_ret} = !dlroW olleH

direct-link download button


āœØ Features

CSLIB provides handy ready-made routines that allow you to do things like:

  • Manipulate strings (concatenate them, force them to lowercase, grab a substring)
  • Present simple choices/menus in just a couple of lines of code
  • Perform mathematical and numerical functions (min, mean, max, sin, cos, pi)
  • Better support working with ChoiceScript ā€œarraysā€ (grow/shrink, loop over, filter, clone)

And best of all? The library itself is written in 100% vanilla ChoiceScript (thereā€™s no *script usage here!), so you are absolutely free to use it in any games you plan to publish. And for added confidence, weā€™ve given CSLIB its own test suite, with over 100 individual unit tests to help maintain and assure users of its quality.


šŸŒŸ Installation Instructions

ā €

  • Copy the module files (the ones that start with cslib_ ) to your game folder, together with your scene files.
  • Create a global variable called cslib_ret to hold return values.
  • Create/set implicit_control_flow to true.
__startup.txt__
*create implicit_control_flow true
*create cslib_ret 0
  • Thatā€™s it! :partying_face:

For more details on how to use, contribute or what you can do, visit the projectā€™s page.


šŸ“ƒ List of Functions (not necessarily up-to-date)

cslib_util:

  • repeat

cslib_number:

  • is_number
  • are_numbers
  • mean
  • max
  • min
  • max_stat
  • min_stat

cslib_menu:

  • build_array
  • build_array_filter
  • build_simple
  • build_simple_cancel

cslib_string:

  • concat
  • lowercase
  • substring
  • find
  • replace
  • index
  • reverse
  • contains
  • consists_of
  • extract_tokens

cslib_array:

  • filter_by_routine
  • clone
  • clean
  • set_all
  • set_from
  • set
  • unshift
  • push
  • insert
  • shift
  • pop
  • remove
  • join
  • reverse
  • for_each
  • test_any
  • test_some

cslib_math:

  • pi
  • sin
  • cos
  • sinh
  • cosh

ā €

json
{
    "cslib_util": [
        "repeat"
    ],
    "cslib_number": [
        "is_number",
        "are_numbers",
        "mean",
        "max",
        "min",
        "max_stat",
        "min_stat"
    ],
    "cslib_menu": [
        "build_array",
        "build_array_filter",
        "build_simple",
        "build_simple_cancel"
    ],
    "cslib_string": [
        "concat",
        "lowercase",
        "substring",
        "find",
        "replace",
        "index",
        "reverse",
        "contains",
        "consists_of",
        "extract_tokens"
    ],
    "cslib_array": [
        "filter_by_routine",
        "clone",
        "clean",
        "set_all",
        "set_from",
        "set",
        "unshift",
        "push",
        "insert",
        "shift",
        "pop",
        "remove",
        "join",
        "reverse",
        "for_each",
        "test_any",
        "test_some"
    ],
    "cslib_math": [
        "pi",
        "sin",
        "cos",
        "sinh",
        "cosh"
    ]
}

We hope CSLIB can provide the community with an accessible and fully supported way of extending the functionality of the ChoiceScript language, without relying on hacks, mods, or untested snippets of code. We wanted to encourage the creation of something that could be built for and by all users of ChoiceScript. We hope it will help people learn and grow, together as a community. What weā€™re showing you here is really just the beginning, a framework or base architecture. We hope you will all help us extend and improve on it over time. For example, have you ever wondered how you would implement a substring function in ChoiceScript? Go take a look! Did you spot a bug, or think you can optimize a routine? Submit a patch!

You can download it, here:

Play around with it in a CSIDE-based playground, here:

See a small example of a game (with comments) using it, here:

And find information about usage and installation, here:

Please do let us know what you think. As mentioned above, weā€™re in the very early stages here, and very keen to hear all kinds of feedback.

Special thanks to @sargent and @twiger_fluff for their suggestions.

66 Likes

@CJW @choicehacker

gif: it's alive!

4 Likes

oh this is exciting. Very much looking forward to playing with this. Great stuff!

2 Likes

image

...

(But reallyā€¦)

Eeeek! Iā€™m so psyched, and excited to finally be able to share this with everyone.
Thank you so much @cup_half_empty and @choicehacker, itā€™s been such great fun, and Iā€™m so incredibly proud of the end result :blush:

11 Likes

This is great!! Iā€™m so excited to dig into it!!

2 Likes

Wow, this looks super cool! It would have made a lot of the things I was trying to do easierā€¦

OMG I canā€™t believe you actually implemented the taylor polynomials for sin and cos in choicescript! :sweat_smile: It must be somewhat inefficient to do them directly in choicescript rather than just handing it over to js. I had a fork of choicescript where I added the math functions directly to the parser (this was when I was trying to make a battletech-esque mech combat simulator lol); I wonder if this could be accepted as a pull request into choicescript?

Also I wonder if there are any performance/efficiency considerations? I remember that having tons of gosub_scene had a negative impact on performanceā€¦

4 Likes

It depends!

Iā€™ll quote from a comment I wrote in the contribution guide:

ChoiceScript isnā€™t built for performance, and cslib isnā€™t going to make that any better.
The library relies heavily on usage of *gosub_scene, which is costly but itā€™s also the only reliable way to handle complex variable scoping.
If youā€™re using the odd function or two as a utility here and there, then you shouldnā€™t have any problems.
If, however, youā€™re planning on a super awesome complex simulator that loops through thousands of strings which it passes to cslib:replace or cslib:findā€¦
At that point, you might want to consider other options (including a different scripting language!).

Also worth noting that some CSLIB routines are significantly worse than othersā€¦ Some of the cslib_string routines (like find), for example, do perform a lot of nested gosub_scene calls, which definitely does result in a noticeable performance hit.

But the overhead of most of the number routines will be negligible (compared to doing it in the same scene; ChoiceScript is still slow, of course!).

If you end up using it, weā€™d love to hear your feedback. Iā€™m sure thereā€™s plenty of opportunities for improvements and optimisations, and I look forward to exploring those as a community!

Outside of performance, I do want to highlight that a library has other benefits to offer. It should certainly encourage better code structure, and - in theory - less bugs, both from that, but also from so many people relying on/testing the same code.

This is always going to the best option of course, but as a community we donā€™t have a huge amount of control over that. So thatā€™s why weā€™re hoping CSLIB proves to be a good functional compromise. If features in the library eventually find their way into the interpreter, then I think itā€™s fair to say weā€™d look to remove/deprecate them from the library and encourage ā€œnativeā€ adoption :slight_smile:


tl;dr Yes, there are definitely performance concerns, but I donā€™t think theyā€™re specific to this library, but rather ChoiceScript generally. You could maybe cut a few extra corners by copying code to your scene, but that has its own issues (code thatā€™s hard to read/maintain, for one).

EDIT: Oh, and you are welcome to do that by the way! It should be no trouble to copy and paste specific routines from CSLIB into your game directly.

13 Likes

This is incredible, bookmarked!

If youā€™re open to suggestions, Iā€™d say you could easily get the find function to look for the first character after a specific index as opposed to the start of the string, although I canā€™tā€¦ actuallyā€¦ think of a situation in which that would be necessary lol.

Something like this?
*label find
*params p_str p_find_str
*comment param_3 = starting char
*temp p_str_len length(p_str)
*temp p_find_str_len length(p_find_str)
*if (p_find_str = p_str)
	*set cslib_ret 1
	*return
*if (p_find_str_len > p_str_len)
	*set cslib_ret 0
	*return
*temp find_e_index 0
*temp find_s_index 1
*if (param_count > 2)
	*set find_s_index param_3

You could probably also modify it to look for the second occasion, third occasion, etc. of a substring rather than the first, but performance would probably decrease from that. (disclaimer I am a high schooler and very amateur at coding please donā€™t take me too seriously)

4 Likes

Loved this as soon as I saw the highest stat functionality!

Is there a full list of functions somewhere Iā€™m missing? I can only find examples of a few routines on your github.

4 Likes

You can find the list of scene files in the download by clicking on the ā€˜scenesā€™ folder in the Code section. (Alternatively: link.) Then you can look at the contents by clicking on the name of a file.

2 Likes

Hmm, rather than overload find, youā€™d probably be better doing:

*gosub_scene cslib_string substring preferred_start_index length(mystring)
*temp short_string cslib_ret
*gosub_scene cslib_string find short_string "what I want to find"

Which is exactly what find would do under the hood anyway. Always open to discussion though!

This might have some merit, although it is possible to do already if you feed findā€™s return value back into substring repeatedly. Not entirely sure if thereā€™s a real-world use-case though.

Short answer: not officially, but Iā€™ve just added a very raw one to the original post.

Long answerā€¦
Because weā€™re publishing this at v0.1, weā€™re expecting lots of feedback and related changes. Routines might get added or removed. Their names might change, they might take different parameters (in different orders), or do slightly different things.

Thus, weā€™ve not wanted to invest too much time writing up documentation thatā€™s going to need to be changed anyway.

As @annwu23 said, the best place to check is in the scene files themselves. ā€œPublicā€ routines are denoted by any label that doesnā€™t start with an underscore, and should always have a large block comment above them describing the routine in great detail.

Once we hit a v1.0 milestone things will have to become more stable, and at that point weā€™ll make a much more concerted effort to formally describe what the library offers.


EDIT: Worth mentioning that if youā€™re using the (CSIDE) CSLIB Playground and turn on ā€œAuto Suggestā€ and ā€œCommand Help (prompts & links)ā€, it will offer you a lot of useful information regarding the library routines:

7 Likes

@autumnchen yes, we went all out with math. And yes, itā€™s inefficient. Donā€™t try to implement a 3D flight simulator using Choicescript! (My 3D maze is all precomputed) But for a text-based Artillery clone, it may do the job.

@dklindzic that feature has been requested on the forum multiple times over the years. Happy you found it useful.

Weā€™re happy to see your enthusiastic response. Let us know how you use the library and how it can be improved.

6 Likes

This is sick. Really excellent work.

2 Likes

Thereā€™s a really good opportunity for a ChoiceScript coder of almost any level to contribute to CSLIB in: Simplify library code with array commands Ā· Issue #47 Ā· ChoicescriptIDE/cslib Ā· GitHub

Essentially enhancing it to use the new *create_array and *temp_array commands.

I could and will happily do this myself if there is no interest, but with it being quite an accessible (and extremely useful!) change to make, I thought Iā€™d throw it open to the floor first :slight_smile:

If you were on the fence about jumping in and contributing, this is your chance!

EDIT: Done 8/9/22

6 Likes

This sounds great, thanks for developing this awesome project. I did manage to get the folder through the github page, but just a heads up the download button isnā€™t working, and would lead you to a dead page.

2 Likes

Thank you!

I had a very thoughtful nudge from someone in the community to raise awareness of this project again whilst CoGā€™s management games are on sale.

If youā€™re ever thinking of creating your own or working on a sequel. You might want to see if CSLIB can help you, by:

  • Providing boilerplate functionality, allowing you to focus on the story and game specific code
  • Keeping your code clean and easy to read
  • Reducing the chance of bugs, given the extensive test suite backing CSLIB
  • Inspiring you to do things you might not have realised were possible in CS
6 Likes

Can I use CSLIB for the following?

The player develops interests which, through choices, grow or shrink over time.

Is there

  1. a way to sort interests by value?
  2. Can I identify if an interest has the highest/lowest value or is among those that are?
    
  3. Can I average the values of all interests and then determine if an interest is above or below the average?
    

Sort
Thereā€™s nothing built-in for this at the moment, but itā€™s certainly something we can look to add if thereā€™s demand. This would probably be as a new method inside cslib_array, so your interests would have to be stored in a global array:

*create_array interest 2 0
*set interest_1 5
*set interest_2 6
...
*comment this doesn't exist yet
*gosub_scene cslib_array sort "interest"
*comment interest_1 would now be 6, interest_2 would now be 5 etc...

Highest/Lowest

*gosub_scene cslib_number max_stat "interest1" "interest2" "interest3" ...
The highest interest is ${cslib_ret}
*gosub_scene cslib_number min_stat "interest1" "interest2" "interest3" ...
The lowest interest is ${cslib_ret}

Average

*gosub_scene cslib_number mean interest1 interest2 interest3 ...
The mean is ${cslib_ret}
2 Likes

Thank you @CJW both for saving me time trying to track it down and for considering adding it in the future.

2 Likes