Now you can extract letters/numerals in ChoiceScript

I was playing around with this, and it looks like you can’t create a permanent variable for the first letter, only a temporary one. Is that true, or am I doing something wrong?

I’m not 100% certain what you’re trying to do, but I’m guessing it’s something like:

*create name "J"
*input_text name
*create initial name#1

If I guessed that correctly you need to the start of the game, as *create is restricted to being the very first lines in your game (aside from other game setup commands). Any other commands disables the ability to use *create. (So what you should do is something like this):

*create name "Jessie"
*create initial "J"
*input_text name
*set initial name#1
2 Likes

I keep encountering this error message when i try to run/compile:

line 7: Non-existent variable 'length'

But in the online IDE it works properly…

What i’m supposedly doing wrong?

*temp abc "abcd"
*temp map_x length(abc)

*comment there was a bug here "not located variable 'length'"! 



*temp last_letter abc#map_x

*label while

The word ${abc} is ${map_x}, and so its last letter is ${last_letter}.

Is it possible to test if a letter or numeral is in the variable at all? Or would you just have to brute force it with a subroutine: “Is “b” the first letter? The second? The third? The fourth?”

Seems like you’re maybe not using the latest version of ChoiceScript?

1 Like

Brute force will be required. Try it like this.

*temp haystack "haystack"

*temp i 0
*label while
*set i+1
*if i <= length(haystack)
  *if (haystack#i) = "c"
    ${haystack} contains the letter "c" at position ${i}!
    *goto end
  *goto while
 ${haystack} doesn't contain the letter "c."
 *label end

Thank you! Now I have a solution for the question I posed in “Holding multiple, testable values in one variable”. Well, I already had a solution, but it was a dire workaround that was harder to scale.

Here it is on my dropbox because it’s a bit too large for a forum post. It could be useful for an inventory system, or for creating summaries. Regardless of its use, it was fun to make.

1 Like

I wrote up a cross-platform, customizable password system using this functionality, but I either failed to explain how to use it well enough, or I over looked a serious bug in the parsing code, so it didn’t really take off (especially since I haven’t had the time or motivation to take a closer look at it :stuck_out_tongue: ). The main concern I have for it in general though is that its really slow, even with only a handful of variables to save, it lags choicescript really bad, mostly due to the large number of loops that need to be done to make sure A) The password is a valid one (uses a checksum-like system) and B) Actually make sure the correct value is being put into the correct variable. My other issue with it is that it’s difficult to obfuscate the password without slowing things down even worse and doing hackish things. It would be nice to have the ability to convert to and from ASCII values.

Thankyou!

That was the problem! when i downloaded the latest version it worked properly!

https://dl.dropboxusercontent.com/s/fm7wllt05fzwr7o/map_navigator.htm?dl=0

If I wanted to use the extract characters ability to remove capitalization from the first letter of a variable, would I need a very long version of the example in post 26? And then reset all the capitals to lower case manually? Or is there an obvious easier solution that I’ve overlooked?

I have kind of an odd situation where I need to use the MC’s surname without a capital in just one specific instance. I’m pretty sure if I change the original variable, {surname}, to be lower case, I will consistently forget to list it as !{surname} because, habits.

Natively I think the easiest solution would be to create a specific ${lowercase_surname} and brute force check every letter. So, not insanely long, probably about about a hundred lines give or take. Oh, and remember that some people have capitals in places other than the first letter of their name, so depending on what you’re using it for, you might want to check ever letter:

*temp name
*input_text name
*temp lowercase_name ""
*temp i 0
*label while
*set i +1
*if i <= length(name)
  *if ((name#i) = "A") or ((name#i) = "a")
    *set lowercase_name & "a"
    *goto while
  *elseif ((name#i) = "B") or ((name#i) = "b")
    *set lowercase_name & "b"
    *goto while
  *comment ... (You can finish it on your own).
  *else
    *comment non-roman alphabet character
    *set name &(name#i)
    *goto while
Your name: ${name} and wispered: ${lowercase_name}

That said, just adding transform to lower case isn’t too difficult if you want a more straightfoward solution:

  1. Open scene.js
  2. Fine this line: var replacer = /($(\!?\!?)\{)/; (at about line 153)
  3. Add a couple of extra exclamations to the replace (should look like this: /($(\!?\!?\!?\!?)\{)/;
  4. Find this piece of code:
    if (capitalize == "!") {
      value = value.charAt(0).toUpperCase() + value.slice(1);
    } else if (capitalize == "!!") {
      value = value.toUpperCase();
    }
  1. Add the following (overwriting that last line obviously, so everything is proper closed):
    } else if (capitalize == "!!!") {
      value = value.charAt(0).toLowerCase() + value.slice(1);
    } else if (capitalize == "!!!!") {
      value = value.toLowerCase();
    }
  1. ???
  2. Profit!

(But seriously, I don’t think I missed anything with that little addition, other than maybe error reporting somewhere I didn’t look for).

3 Likes

Brilliant! That’s perfect; thanks so much. A practical solution AND a fun solution, what more could I ask?

From my knowledge this would work really well for checking imputed variables used to customize the player, like name, hair color, ect, to make sure they fit with how they will be used. So if someone doesn’t capitalize their name, you can use this to check and correct that so it appears formatted properly in the actual text as you read. I can’t remember if there’s an opposite version that would uncapitalize a letter on the same basis but I assume so, which would also be useful in a similar sense like someone inputting ‘Blonde’ for hair color when the game would want it to be read as ‘blonde’. Obviously having set choices can avoid this but having a box to input something else is common enough to warrant this.

Unfortunately, there is no easy way to force-lowercase a text. RETowers explained how to brute-force creating a lowercase copy of a variable.

However, the simplest way, if you don’t need to display it in lowercase to the player, is to just convert a copy of the variable to be compared into allcaps, and then compare it against an allcaps text.

If you’re using only the standard latin alphabet you could use a map/index:

*comment quick-access "array" map/index
*create lowercase_A "a"
*create lowercase_B "b"
*create lowercase_C "c"
*create lowercase_D "d"
*create lowercase_E "e"
*create lowercase_F "f"
*create lowercase_G "g"
*create lowercase_H "h"
*create lowercase_I "i"
*create lowercase_J "j"
*create lowercase_K "k"
*create lowercase_L "l"
*create lowercase_M "m"
*create lowercase_N "n"
*create lowercase_O "o"
*create lowercase_P "p"
*create lowercase_Q "q"
*create lowercase_R "r"
*create lowercase_S "s"
*create lowercase_T "t"
*create lowercase_U "u"
*create lowercase_V "v"
*create lowercase_W "w"
*create lowercase_X "x"
*create lowercase_Y "y"
*create lowercase_Z "z"

*comment lowercase first letter
*temp name "Craig"
*temp first_char_lower "${lowercase[name#1]}"

${name#1} -> ${first_char_lower}

*comment lowercase all
*temp name "CRAIG"
*temp name_len length(name)
*temp lower_name ""
*temp c 1
*label lowercase_loop
*if (c <= name_len)
    *set lower_name & (lowercase[name#c])
    *set c + 1
    *goto lowercase_loop

${name} -> ${lower_name}
5 Likes

Ooh, nice code. I always forget you can use a non-numeric array index.

You’ll also need a special case here to copy over non-alphabetic characters, like spaces and punctuation.

*comment lowercase all
*temp name "CRAIG"
*temp name_len length(name)
*temp lower_name ""
*temp c 1
*temp is_alpha false

*label lowercase_loop
*if (c <= name_len)
    *gosub is_alphabetic (name#c) "is_alpha"
    *if is_alpha
        *set lower_name & (lowercase[name#c])
    *else
        *set lower_name & (name#c)
    *set c + 1
    *goto lowercase_loop


*label is_alphabetic
*params test_char ret_val

*temp alphabet "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
*temp x 1
*set {ret_val} false

*label alphabetic_loop
*if x <= length(alphabet)
    *if (alphabet#x = "$!{test_char}")
        *set {ret_val} true
        *return
    *set x + 1
    *goto alphabetic_loop
*return
2 Likes

Hi Chris, yeah, I deliberately omitted this as otherwise you’re basically back to the performance/computational complexity of RETowers solution (you’re checking every single character 26 times). With the map/index it’s just a single operation per char, albeit with your noted caveat: no punctuation.

That said, the way you’ve used a string and indexed into it (rather than a long list of IFs) is much cleaner to read, so kudos there. Definitely the way to go if you can’t guarantee your strings are free of punctuation, or you’re doing it rarely enough that performance isn’t an issue.

2 Likes

If you wanted, you could punch through the abstraction and use one line of Javascript. (It may make your game unpublishable.)

*create name "UPPER"
*script this.stats.name = this.stats.name.toLowerCase();
I will print 'upper': ${name}
1 Like

CoG generally advise against usage of script, so by default we tend towards not recommending such solutions (as optimal as they may be).

1 Like

Thanks for reminding that, @cjw. I wanted to suggest a compact solution, as some users may get discouraged by multiple jumps and conditions.

I try to avoid JS when possible too, and it’s actually a fun challenge to implement something in basic CS :slight_smile:

1 Like