User:Banana gun/Making Games In DWAINE
Making Games In DWAINE
Here's a handy finite state machine that can be used as a choose-your-own-adventure game, a quiz, or whatever your creativity allows it to be.
I'll also describe how it works and some of the tips and tricks I've learned for DWAINE.
The code
The code below is formatted in a specific way: there are double backslashes on places where a normal backslash is intended. This is for the purpose of correct copy-pasting into paper; they serve no purpose in the actual code.
File: ./game
#! if $argc 1 lt | echo Valid arguments: start, help, scene | break eval $arg0 to argument if $argument help eq | echo {How to play: Actions are performed by commands starting with "act", and then the action you wish to perform. Potential actions are generally all lowercase, and designated by quotations in the scene dialogue. } | break if $argument start eq | rm ./bin/scene | echo {Tutorial: Actions in this game are performed by first typing "act", and then the action you wish to perform. To start the game, perform the action "play", by typing "act play".} 0:play ^ ./bin/scene grep -o \\{.*?\\} ./bin/scene
File: ./act
#! if $argc 1 lt | echo An action is required. | else | eval (\d+)\\: to regex | eval regex $arg0 + to regex | eval $(grep -o $regex ./bin/scene) to currentsave | eval (.\*?)\\( to regex | eval regex $currentsave + to regex | eval regex \\) + to regex | rm ./bin/scene | grep -o $regex ./bin/source ^ ./bin/scene grep -o \\{.\*?\\} ./bin/scene
How to use it
There are 3 files that are required to get this engine working:
- game
- act
- bin/source
First, locate a suitable DWAINE console, and the nearest scanner. The easiest way to load all files in reasonable time is to play as a silicon, since they have access to an integrated typewriter, and can access the DWAINE console from right next to the scanner. Copy and paste each code above into 2 separate papers, then locate your scanner's path with ls /mnt, and call this function for each of the papers:
mv /mnt/sc-location/document ./filename
Replace filename with the aforementioned names, and sc-location with your actual scanner's location.
The names of the commands aren't super important, so you can rename them for your preferred theme.
Source
The last file, bin/source, is up to you to create. The format for it is simple enough, it follows a pattern of
{scenedisplay} sceneindex:word (sceneindex)
An example of this format in action:
{This is scene 0, which is the starting point. Call act with arg0 "one" to go to scene 1, or "two" to go to scene two} 1:one 2:two (0) {This is scene 1. Call act with arg0 "zero" to go to scene 0, or "two" to go to scene two} 0:zero 2:two (1) {This is scene 2. Scene two has multiple lines!} (2) {Type act zero to go to scene 0, or act one to go to scene one.} 0:zero 1:one (2)
At this point, you can just call mkdir bin
, scan the file, and put it in your new directory.
To start the game, call game start
which should automatically create the scene file with the format specified within the game file.
Code explanation (AKA the NERD ZONE)
DWAINE is difficult to use for advanced projects. However, there is a saving grace that can ease the pain a bit.
The grep command has two specific features that allow for a lot more freedom in development.
- It allows for a variable to be used in the regex format argument: ie
grep -o $regex ./bin/scene
, where $regex is the format that you can construct yourself. - It can pipe to a file: ie
grep -o $regex ./bin/source ^ ./bin/scene
, where the result of the grep is put into bin/scene.
Those two features allow for a lot of freedom, and if you know regex, you can do a whole lot with it. Let's walk through the act file, and see where the aforementioned concepts come in handy.
eval (\d+)\: to regex eval regex $arg0 + to regex eval $(grep -o $regex ./bin/scene) to currentsave
This code constructs a regex format like this: (\d+)\:$arg0
. Let's assume that $arg0 is "play", so this becomes (\d+)\:play
.
That regex extracts any format like number:play from the given file, bin/scene, and stores it in the currentsave variable. The :play portion is excluded, because DWAINE is wacky. Let's assume that $currentsave is 1 in this case.
This is used in this segment:
eval (.*?)\( to regex eval regex $currentsave + to regex eval regex \) + to regex
This creates a regex like (.*?)\(1\), which gets all the characters in the line behind (1). When applied from bin/source in grep -o $regex ./bin/source ^ ./bin/scene
, it applies the scene that was extracted from the option in $arg0 to bin/scene.
After all that, it's relatively simple to print the current scene. Just calling grep -o \{.*?\} ./bin/scene
shows all lines enclosed in {}.
To recap: bin/scene acts as a buffer for the current scene, holding the display and the options. bin/source acts as a database for all options from which bin/scene pulls from using the scene index, which was extracted from the last bin/scene.
Closing notes
Using the concepts above, it should not be impossible to expand the capabilities of this "engine" to include some more features.
I've also noted that the date
command gets the current time in the round, and can be redirected to a file with a ^. This can be used for a psuedo random number generator, probably by ($(date) * 12345) % $range
or something along those lines.
If you're having trouble with performance in your DWAINE scripts, try batching calls together. You can do that by putting them in an if/else statement. If your program doesn't need one, then you can format your code like if 1 | code | morecode | evenmorecode
.
My act command used to take 3-5 seconds to run with all commands seperated, but when I batched them all into the initial if/else statement, it worked perfectly, running in roughly a second, give or take. Just keep in mind that DWAINE stream redirection is weird: I found that putting the grep -o \{.*?\} ./bin/scene
inside the if statement would not output it to the console.