Rescue Script QOL Updates
Now that I've written a few rescue scripts, I've noticed a few areas that can be improved. The following changes will increase script readability and make writing scripts faster and easier.
Removed Semicolon Requirement
Semicolons are no longer required at the end of a command. I made this change because the semicolons don't fit well with the other changes I will discuss below. And it turns out, the semicolons weren't actually doing anything. After I removed the requirement, the script parses exactly the same without any issues. So now the compiler will ignore any semicolons, which means that old scripts will still work fine but new ones don't need to use them.
Shortened Dialogue Command
In old scripts, a dialogue command looked like:
dialogue.label(R).text("Hello, here's some example dialogue.");
This was fine on its own, but it made blocks of dialogue hard to read. It was also annoying to write out, and copy-pasting the command often interrupted the writing flow. The original reason I designed the command this way was because I wanted all commands to behave the same. This made the code for the compiler really simple and elegant. In order to keep it that way, I considered shortening the command to:
d.l(R).t("Hello, here's some example dialogue.");
This makes the command faster to write, but it increases the visual noise and doesn't solve the root problem. And since dialogue is the main point of the rescue script system, I realized I needed to sacrifice the compiler's simplicity for the sake of a better user experience. So I ripped all of the extra noise out of the command. Now writing dialogue is as simple as:
R "Hello, here's some example dialogue."
This is so much more readable, and writing the dialogue is so simple that you no longer feel compelled to copy-paste it from a previous line. I've already updated the recent Bedroom script to this new system, and its so much nicer to look at. I also added a new dialogue label type. Using an '_' will make the dialogue box use the same label as the previous one. This further improves the readability of blocks of text. Compare this example of the old system:
dialogue.label("Narrator").text("I am the narrator and I'm going to say some example text."); dialogue.label("Narrator").text("Here I go, typing out a bunch of words."); dialogue.label("Narrator").text("And here's even more words to read.");
and the new system:
"Narrator" "I am the narrator and I'm going to say some example text." _ "Here I go, typing out a bunch of words." _ "And here's even more words to read."
Shortened Wait Command
Now that I've discarded the compiler's simplicity to shorten the dialogue command, I figured I might as well shorten some other commands while I'm at it. And the most obvious command to target was the script.wait command, which used to look like:
script.wait(1.5);
Now it's as simple as:
wait 1.5
This isn't as much easier to write than the new dialogue command, but it's still a big improvement considering how often I use the wait command. Timing is so important when writing rescue scripts, and I litter this command everywhere. So even a small change in readability can make a big difference.
Asynchronous Blocks
The previous changes were designed around simplicity. This feature arguably makes things more complicated, but it's also very powerful. Before I explain how it works, I need to explain the problem it solves. If you've played through my previous scripts, you'll know that I like to put dialogue while the character is doing something (ex, during chest compressions). In the script, this used to look like:
dialogue.label(R).text("Come on, [victim]").next(); cpr_side.repeat(15).rate(110, 105); dialogue.label(R).text("I hope I'm doing this right.").next(); cpr_side.repeat(15).rate(105, 120);
The .next() dialogue option would cause the script to skip waiting on it and immediately continue to the next line. However, splitting up the cpr_side command into two parts created a small, but noticeable hitch. This is very obvious in the Office3 script, if you've seen that. To solve this problem, I've recently introduced the .delay() dialogue option, which waits for the given seconds before showing the dialogue. Using this option, the above commands look like:
dialogue.label(R).text("Come on, [victim]").next(); dialogue.label(R).text("I hope I'm doing this right.").delay(8); cpr_side.repeat(30).rate(110, 105, 120);
This option helps avoid splitting up the cpr_side command, removing the hitch. But what if I wanted to change the camera-angle mid compressions? Or if I wanted to change the heart rhythm, or enable a condition? I didn't want to add the .delay() option to every possible command. Not to mention, neither the .next() or the .delay() option works with the new short-form dialogue. And while the old dialogue form still works, mix and matching the old and new forms would hurt readability.
To solve this problem, I'm introducing async blocks. Using this new feature, the above example looks like:
async { R "Come on, [victim]" wait 4 R "I hope I'm doing this right." } cpr_side.repeat(30).rate(110, 105, 120)
An async block works by splitting off from the scripts main time flow. All the commands within a block operate on their own time flow, running alongside the main script. So the first command within the async block runs at the same time as the cpr_side command. This means the first line of dialogue doesn't need the .next() command. You may notice that the wait is only 4 seconds, compared to the previous .delay()'s 8 seconds. This is because the first dialogue isn't skipped, and it takes around 4 seconds to run.
Hopefully you can see how powerful these async blocks can be. Any command can run inside them, like camera, heart, and condition commands. And these blocks allow the new forms of dialogue without any issues. In fact, async blocks can even be nested, although I'm not sure why someone would want to do that.
My only issue with these blocks is that a bit of clarity is lost. In the above example, its not clear that the async block is meant to go with the cpr_side command. However, I realized readability can be improved by shoving everything on one line, like this:
async { R "Come on, [victim]"; wait 4; R "I hope I'm doing this right." } cpr_side.repeat(30).rate(110, 105, 120)
This makes it more clear that the async block runs with the cpr_side command. I added in semicolons above to distinguish between the commands on a single line, but like I said before, these don't actually do anything. The above example is just a formatting decision that I plan to use on my own scripts, but feel free to format things however you want.
Anyway, these are the changes I've made so far. I've updated the recent Bedroom1 script to account for these changes, and I will post it on my discord if you want to look at it. It won't actually run, since I haven't released the update yet, but I'm looking for feedback on these changes so if you have ideas for further improvements let me know.












