🧰 [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.

44 Likes

@CJW @choicehacker

gif: it's alive!

1 Like

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:

9 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.

11 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)

3 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.

3 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.

1 Like

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