MechaniQue
MechaniQue is an esoteric programming language (http://gabordemooij.com/mechanique/) used for writing interactive fiction, designed by Gabor de Mooij in 2006. MechaniQue lacks variables and explicit calculations while still offering complex dynamics.
Instead of variables MechaniQue uses locks and keys. A key can be added using the + command. For instance: +lantern will add a key called 'lantern' to the program. This key can be used to unlock lines of codes in the program. For example, the lantern key might unlock a line like : {lantern} you are now in a very dark cave... If the program does not have the lantern key, this line will be skipped.
The general idea behind MechaniQue is to invent a programming language that has an internal structure and logic that maps somehow on the way adventure games behave. However, MechaniQue is not as limited as a map-based approach in which each location on a map has certain properties, items and restrictions.
@^#EXAMPLE: something different than hello world @[question]^:You are on a purple planet with lemons @^:dancing around you. @^:a. try to imitate a lemon @^:b. ask one of them where the tonic is. @^? @{_a}^->answer1 @{_b}^->answer2 @^->question @[answer1]^:Hmm @^:The other lemons think you dont look like one of them. @^? @^->fin @[answer2]^:Good question. Do you like rhetoric questions? @^? @[fin]^#you cannot place a label at the end-line. @fin
What is MechaniQue/J ?
MechaniQue/J 2.0 (MQJ2) is a compiler for the MechaniQue programming language. The MechaniQue programming language (MPL) is an esoteric programming language designed to create interactive fiction with. MPL is less complex than traditional programming languages and makes creating amateur-level adventures a breeze. For instance, the MPL is not object-oriented and has no concept of functions. This is ideal for creating small sized text-adventures because in this case you don't need these concepts at all. Of course I could have created just another BASIC clone, but I choose not to. I wanted to create a specialist-language, focused on just interactive fiction and nothing else. I even wanted the syntax of the language to map somehow on the way adventure games are played. It's also esoteric because the language abandons the concept of variables. Instead it uses a lock and key system which could be compared with a global-space inventory that holds booleans. MQJ2 is written in JAVA and comes in two flavours, a full blown JAVA package and a JIT Compiler (which runs your code immediately) called the 'Web Edition'.
Running MechaniQue
MQJ2 thinks in 'books', 'rolls' and 'parsers'. An MQJ2 program is usually written using a simple text editor like nano and should be saved using the .book extension. To compile a book-file named test.book invoke the compiler like this:
java m2 -c test.book
This will create a .roll file which is a kind of executable to MechaniQue. A roll-file is not readable for humans and contains JVM bytecode. However you still need MQJ2 to run it.
java m2 -r test.roll
Will run the roll-file we just created. You could also use the -s option, on MAC OSX this will cause the system to activate the speech-engine to read the adventure to you, while -d is a debug option.
Syntax of MechaniQue Overview A mechaniQue program consists of code-lines; each line starts with a @. The last line in a program file; a book-file, should be like this:
@fin All other lines have the same format:
@ [Label] {Slot} ^Action
Labels A label is just a name that can be given to a row. Labels are optional, but are used as a reference by other lines. This way another line can jump to the labeled line by specifying the name.
Locks Instead of conditional statements like IF ... ELSE, MPL uses locks and keys. This way, each line of code incorporates its own conditional statement. The actions in a code line are not executed unless all locks in the lock-section have been opened successfully. To open a lock ( {coffee} for example ), the program needs to have a key called 'coffee', which can be given by an action. Some keys are given by the system at so-called interaction moments; which are also initiated by actions.
Actions The 'Action' is the real MPL instruction. There are only 7 instructions / actions in the MPL. Here is an overview: Each Action begins with a ^. A line can contain more than just one action, multiple actions are separated by a pipe |.
Action Explanation :X Prints X. ? Asks for user input and builds a key based upon the input (see next chapter). +X Adds key X. -X Drops key X. ->X Jumps to line with label X. Jumps should always be placed at the end of a multiple action line, this is because if you jump back (next action) it will jump back to the line as a whole and not to a specific action in that line. <- Jumps back. In contrast to traditional languages, MPL does not seperate a GOTO and GOSUB, you can always jump back after a jump. #X Just a comment or a NOP instruction.
Interaction Key The ? instructions creates a so-called interaction moment. During this phase the player may type in some text until he/she presses enter. The user-input will then be used to build a key. This happens as follows. First all spaces are removed from the user-input, next the resulting text is prefixed with the interaction symbol: _ the underscore. So, answering 'a' will result in key : _a and answering 'hello world' will result in a key: _helloworld. Using this mechanism a player can influence the course of a MPL program.
User commands During an interaction moment, the player can enter a predefined command. there are only two such commands: #exit (to stop the program) and #save to save the current state of the program; reload with -l option.
Example Here's a little example of an MPL program that uses an interactive key. The program offers two choices, because the answers are converted to keys this will result in different output.
@[spaceship]^:You are in a spaceship @^:The captain has just been shot. @^:What do you want to do? @^:a. grab the steering wheel of the spaceship @^:b. first read the manual that lies on the floor.. @^:'how do I navigate a spaceship?' @^? @{_a}^->steer @{_b}^->readmanual @^->spaceship @[steer]^:You are not very experienced at steering @^:spaceships and you crash into a comet.. @^->end @[readmanual]^:Very interesting manual @^:before you reached chapter 2 of 100 you crashed @^:into a certain planet named Pluto. @[end]^# @fin
System keys At each interaction moment the system generates a series of system keys. These keys enable you to simulate time, randomness and intelligence. Here is an overview:
System Key Explanation DICEX Where X is a random number between 1 and 6. Using this key you can add a sense of randomness to your interactive fiction: unexpected things that happen or random extra descriptions of a scene. ROTX Where X goes from 1 to 6 and then becomes 1 again. Using this key you can simulate circular processes in your game, like buses that drive by or elevators that stop at each store in a building. PATHX Where X goes from A to F and from F to A and again. Using this key you can simulate intelligence in your game: like guards that follow a certain path. TIMEX Where X is the current amount of interaction moments. Using this key you can add time pressure to certain tasks in your adventure, or you can let things evolve. TWISTX A TWIST key is given (or not) at the begin of the program and does not change over time, X can be either 1 or 2. Using this key you can let the story behave differently across sessions. OCCX This key is set at the beginning of the program and contains the current date, February 2nd is OCC1_2 (0=January). Using this key you can make certain things happen at certain dates in your adventure. For instance you can make a christmas tree appear on the scene with christmas. Time locks A time lock {TIME10} for instance, acts a bit differently from other locks. Instead of opening if the program has a key TIME10, this lock opens if the program has one of these keys: TIME0, TIME1, TIME2....TIME10. In other words the total amount of interaction must be <= 10.
Some examples of system keys
Time for some examples! All programs that are listed below are actually some kind of infinite loops; to quit, use the #exit command at an interaction moment. The following example prints 'patatoes' or 'tomatoes' randomly using the dice key:
@[start]^:Today, the cook bakes @{DICE3}^:patatoes @{!DICE3}^:tomatoes @^? @^->start
The following example demonstrates the use of the twist key. You'll see that the value of the twist key will not change during one game-session.
@[start]^:You were born @{TWIST2}^:rich @{!TWIST2}^:poor @^:and that will not change during this game! @^? @^->start @end
Now, we are going to demonstrate the time key. The time key will be given when the iteration number in the key is reached.
@[start]^:after three times @{!TIME3}^:this message will change.... @{TIME3}^:this message has been CHANGED... @^? @^->start @fin
To simulate events that are cyclic you can use the rotation key:
@[start]^:You are waiting for the bus at the busstop. @{ROT1}^:The road is empty. @{ROT2}^:You suddenly hear an engine. @{ROT3}^:A bus is nearing @{ROT4}^:The bus stops at the busstop, it's the wrong bus. @{ROT5}^:The bus drives off @{ROT6}^:In the distance you see the back of a bus. @^? @^->start
Negative locks A negative lock starts with a ! and only opens if the specified key is NOT present. So imagine we have line like {!lamp}^:there lies a lamp on the floor.. In this case you will see the lamp on the floor only if you do not have that lamp, which makes perfect sense of course. The example below demonstrates the use of negative locks.
@[forest]^:You are in a forest. @^:a. enter the cave in the east. @{!lamp}^:b. take the lamp that lies on the grass. @^? @{_b}{!lamp}^+lamp @{_a}{!lamp}^:Way to dark!!|^->forest @{_a}{lamp}^->cave @^->forest @[cave]^:You are in the cave.. @fin
Extended locks An extended lock enables you to make a lock apply to more than just one line. This is best illustrated by a comparison. Imagine you have two locks a and b. One line just demands that you have key a, while the other demands both. Instead of writing:
@^+a @^+b @{a}^:this line needs a @{a}^:this line needs a as well @{a}{b}^:this line needs both a and b @{a}{b}^:this line needs both a and b as well @{a}^:this line needs a @fin
the MPL allows you to write a shorter version using extended locks (<< and >>)
@^+a @^+b @{a}<<^:this line needs a @^:this line needs a as well @{b}<<^:this line needs both a and b @{a}{b}>>^:this line needs both a and b as well @>>^:this line needs a @fin
Slots A slot is just like a lock. However, if the line as a whole can be opened the keys that have been used on slots will be dropped automatically. Slots are prefixed with a $. Negative slots do not exist. The following example demonstrates the usage of slots.
@^+coin @[again]^:a. insert coin into vending machine @^? @{_a}{!coin}^:no more coins! @{_a}{$coin}^:OK you got yourself a coke. @^->again @fin
The OR lock An OR lock {OR} is a very special lock. It gets unlocked if ONE of the previous locks could be opened, but that's not all. It also opens the rest of the previous locks. Imagine a line like {a}{b}{OR}{c}, in this case both a-c and b-c combinations will open the line, a-b however is not enough to open these locks, because the c lock will prevent the line from unlocking.
Magic Ink Sometimes you want to describe a scene thoroughfully the first time you arrive at it, but not the second time. This is especially true if you are using the audio version of a story; it's very annoying to hear a complete description of a room only because you misspelled the answer. In order to accomplish this you can use magic ink ';' . If a ; is placed directly after a ^: then, the text will be printed only once: @^:;this text will disappear..
@[start]^:;this text will dissappear.. @^? @^->start
The ZERO key New in MPL 2.0 is the ZERO key. This key is generated by the system at each interaction moment. This key is automatically dropped by the first line that can be unlocked. Using the ZERO key you can open locks like {ZERO}. This is useful if you want to implement an action which should only be performed if none of the other lines has been unlocked. Actually, ZERO is MechaniQue's way of saying... 'else'.
@^? @{_a}^:you entered a. @{ZERO}^:you entered something ELSE.. @fin
Quantifiers New in MPL 2.0 are quantifiers. MechaniQue does not have variables. But, with quantifiers I gave MechaniQue an opportunity to 'deal with numbers'. Using qualifiers you can build loops, perform calculations and print numbers. Imagine we want to add a lamp to our inventory. Normally we would say something like :
^+lamp
But what if you were writing a Christmas games, and you need lots of little lightbulbs to decorate the Christmas tree? To add more lamps you can now say:
^+lamp|^+lamp Which will result in MechaniQue's inventory holding 2 lamps instead of one.
A lock like:
{lamp} will still open. So what has changed? You can use a lock like:
{lamp*2} and it will only unlock if you have 2 OR MORE lamps. This is the reason why {lock} opens as well; locks without quantifiers are treated as if they were locks with quantifier 1: {lock*1}. And because this lock opens if the amount of lamps >= 1, it will also unlock if you have 2 lamps. If we want to write a lock that opens if you have 1 lamp but not 2; we could write {!lamp*2} which will unlock in case of < 2 lamps. However that lock will also open for 0 lamps. But if we need exactly 1 lamp we have to write: {!lamps*2}{lamp*1} (or {=lamp2}).
Of course it is quite annoying to add five lamps like this:
^+lamp|^+lamp|^+lamp|^+lamp|^+lamp This is why you may use a quantifier here as well:
^+lamp*5 Both statements do exactly the same, they both add 5 lamps to the inventory. Using quantifiers applies to the - instruction as well:
^-lamp*5 simply meand you want to drop all 5 lamps.
To print the quantity of an item in your inventory on the screen use %%X%% where X is the item. So: %%lamp%% will print the current amount of lamps in the inventory. Here is an example..
Using quantifiers, it's easy to build a loop:
@^+lamp*10 @[counter]^:there are %%lamp%% left... oops I broke one! @^-lamp @{lamp*1}^->counter @fin
Magic Ink Key Visually impaired people benefit from correct textual interaction. If they listen to your game and they have to hear the same description time after time, it's becoming pretty boring. This also applies to other players of course, they might skip reading textblocks because they are increasingly repetetive. To fix this issue there is a new special key in MechaniQue.
The function of magic ink has changed a bit. Instead of hiding text forever, it will be reshown if you have a special key: _DESCRIBE_FULL, this key can be generated using parsing: look=DESCRIBE_FULL will do the job. This makes Magic Ink behave more like look-commands in traditional adventures.
Parsing in MechaniQue Maybe you wonder if you can only make multiple choice games with MechaniQue. This is not the case. MechaniQue can parse complete sentences as well. To make use of parsing you need to compile a parser file with your game. A parser file includes rules that describe how answers are turned into keys. Each line of a parser file (which is just an ASCII file as well) starts with a @, just like a book-file. There are two kinds of rules:
A A=B In the first case a is filtered from the answer. In the second case, a is replaced for b. Imagine a parser file like: @talk=u @to @the @old We could save this file as test.parser and compile it together with test.book like this:
java m2 -c test.book test.parser
Now imagine we meet an old man in the game and we want to ask the way. If we would type something like: talk to the old man, or talk to old man, or talk to man A line like @{_uman}^:the man says you need to go east. will just open. This is because all words are being filtered except talk and man, talk gets replaced by u and if the prefix for interaction keys is added we het _uman. This means we don't have to add locks like: {talktooldman}{talktoman}{talkman}{talk}{OR} Which is of course annoying. However we could add the option to unlock the line also in case the player only uses a verb: {_uman}{_u}{OR}. MPL Parsing is very simple but allows you to make simple adventures. What's more is that you can use different languages for your parser while still using the same book-file.
Some notes on the compiler The MQJ2 compiler produces MQJ2-reader specific code. If there is an MQJ2 upgrade you should re-compile your code in order to get it running with the new version. If this is not what you want, you should either use JIT, distribute books instead of rolls or download an older version of the MQJ2.
A note about the end-statement Each MechaniQue program ends with @fin. This end-tag is taken quite literally by the compiler, meaning only @fin is accepted; not @{key}fin or @[a]{b}fin. However, because you can also have only 1 @fin in your program you might need to jump to it from other locations. The right way to achieve this would be:
@[end]^# @fin This is a bit cumbersome to accomplish. Therefore, the compiler accepts a line like
@[end]fin ...as well. In fact, it replaces this line for the two in the previous code snippet.
See also
External resources
- http://gabordemooij.com/mechanique/
- MechaniQue website (from the Wayback Machine; retrieved on 24 February 2008)