Visit The new RRC2Soft Tutorials ^_-

We made available new tutorials in Enjoy!

"Script" languages, compilers and Interpreters

    Hi !. In this tutorial we will see something almost indispensable in a CRPG: A " script " language. We will see in that consists, why it's so important, and how to manage it in our executable.
    An advice for understanding this tutorial: you must have knowledge of programming languages (after all, we are programming a language). So catch air, breathe deep, and prepare you to a very theoretical and huge tutorial ^_-.
    Without more waits (that you have already had enough ^_-), we begin:

From design to the screen
Script language
The compiler and the interpreter
    Associating a tile with an event. Instruction files and index files
Compilation of instructions of our "script" language . How the compiler works
Compilation of an instruction. Syntax of a language
Visual compiler
Format of the instructions of the interpreter's pseudocode
How the interpreter's instructions are executed

FROM DESIGN TO THE SCREEN (Languages, compilers and Interpreters)


    When a game is designed, a very important part (besides the design of characters, of combats, graphic design,...) is the design of the script. This consists on having written what the characters of our game should make in each moment (What they say, what they should make in every moment, what should happen them according to what you/they have made before...)

    (Situation: The prison of the Imperial Star Destroyer " Sovereign ". The characters are without money neither equip)
    [Eric Mathesar enters in a cell. Inside it is the main character, alone. Eric looks at the main character. He is crestfallen, sat down in the bed]
    Eric: Mister <Name_1>. Finally we know each other in person.
        [The main character shows a surprise expression, at the same time that she lifts the head]
        <Name_1>: Mathesar!!
        [Mathesar shows a surprise expression, and then a smile]
        Eric: Hey. It has been all a surprise. I didn't know that I was so well-known among the scum like you.
    [The main character looks at a moment to Mathesar]
    <Name_1>: And ?. I should care about this?
    Eric: You should..., but I am being rude presenting me this way... I'm known as Eric Mathesar.

    But having the script, the characters of your game will not do what is written on it (It's a pity, by the way ^_-). We need to indicate to the game's engine what things must do, and in what moments should make them. For that we need a " script " language.

    Script Language

    A " script " language is a programming language (as Pascal, C) invented by ourselves (although we can take the syntax of other languages) whose function is to indicate to the game what should make in each moment.
    This " script " language is saved in a text file or in a binary one, and the procedures and functions that it has must access to the engine's capacities (Give_Money, Move_NPC, Teleport, Talk, Change_Tile, Night_Or_Day, Effect,...).

    Like example we will translate to a script language the upper script:

    Money()=0;                                           % The party has no money and no belongings
    Teleport(@SDPrisonMap, 30,70);         % Teleporting the camera to the tile X=30, Y=70
    TeleportNPC(@Mathesar,30,60);         % Teleport the two characters
    Fade(@BlackToNormal);                      % And I show the map after loading the things
    Talk(@MathesarFace, 'Eric: Mister <Nombre_1>. Finally we know each other in person.');
    If (Flag(@Main_Knows_Mathesar)=TRUE)
        Talk(@MainFace, '<Name_1>: Mathesar!!');
        Talk(@MathesarFace, 'Eric: Hey. It has been all a surprise. I didn't know that I was so well-known among the scum like you.');
        Talk(@MainFace, '<Name_1>: And ?. I should care about this?');
        Talk(@MathesarFace, 'Eric: You should..., but I am being rude presenting me this way... I'm known as Eric Mathesar.');

    The elements that our script language should have are:

    The instructions of our " script " language are executed step by step: First an instruction (Talk) then other (MoveNPC), then other (Talk), then other (Music),... and this way until we find a bifurcation instruction or a loop.

        Talk(0, ' Hello, <D001>, it has been a long time');    // 1º instruction that is executed
        MoveNPC(1, ' M2G014A203 ') ;                                // 2º instruction that is executed
        Talk(1, ' <D000>!!. You're alive!! ') ;                         // 3º instruction that is executed
        Music(#HappyMoment);                                            // 4º instruction that is executed

    The compiler and the interpreter

    Here we should make an stop and say something very important: the "script" language is used because it is a language for humans, simple of understanding for us (The step of translating the script to the language is relatively simple). If we read a "script" program, we know perfectly what will happen in a certain moment of the game.
    But for a machine (our game), it is not so simple. We must pass the "script" language to another language that can be understood more easily (and in less time), and be executed by our source code.

   Is like speaking of a Java program compiled for the Java Virtual Machine and of a Assembler program. Java is easily understandable for human, but it needs to translate its instructions in run-time to assembler => slow.
    Ensamblador is very difficult to understand at first sight (and at second sight, and at third sight,...), but a program compiled in assembler will go very quickly in comparison with the other one.

    So, we should create one mechanism to pass the instructions from the "script" to a more "machine" language, and other mechanism for executing those "machine" instructions. Those tasks are made by the compiler and the interpreter.
    An "script" instruction is translated to one or more "pseudocode" instructions (we will say "pseudocode" when talking about "machine" instructions). This is made this way 'cause if the pseudocode has lots of instructions, the interpreter will be more complex, and therefore slower.

    An example:

    You directly could execute the " script " language (without going previously by a compiler) during the game, but it would be slower, and therefore it would not be good.

    (NOTE: Technically the function of an Interpreter it is not the indicated (to execute the instructions compiled previously by a compiler ), but we believe that it is better "interpreter" that "executioner" (of instructions ^_-). For interested ones, the real function of an interpreter is to pick up the instructions of a high-level language and execute them [VisualBasic has interpreted instructions, the p-code]).

    Associating a tile with an event. Instruction files and index files

    Well, we already know how to pass our script to a "script" language, and we have seen that this language is translated to other ("pseudocode"), quicker of understanding for the computer.
    But what the script says happens when stepping certain tiles (p. e.g. in the previous example of the fountain) or when looking towards them. What solution can we take?.

    Like we comment in previous lessons, the solution is the following one: Each tile has associated an event, and that event is some lines of "script" code. When one steps a tile, we check if that tile has an associated event, and execute the code associated to that event.

    There's a curiosity about the game Ultima 9, of Origin. In an article, their developers commented that, in certain areas of the game, using a trick to fly means that there will be events that would not be executed, and therefore it would be impossible to advance correctly in the game.
    What happens? In Ultima 9 (We suppose) the events are associated with certain sections of the 3D map(i.e. a square that occupies the entrance to a town). If we don't pass through those sections, the events are not activated (imagine that there is an event in the drawbridge of a town, which shows the murder of somebody. If we enter flying [so we don't pass trough the drawbridge], we won't be able to see that murder, the flags of that event won't be activated, and possibly an error will happen).

    The question that arises is: What instructions are associated to an event?.
    The answer is the following one: When we associate "script" code to an event (Step in (45,3)=Talk ), those lines of code stay (compiled) in a binary file, in the position X. And that tile (45,3) has an event number that points to a file that indicates the first instruction of that event.

    Maybe sounds difficults (it "is" ^_-), but with an example all is solved:

    Instructions [_Pa 0 _Di 1]. _Pa is in the position 540 of the instructions' file of its map.
    That event should happen when stepping the tile (45,3).
    That tile has an event nº, 5.
    And in a file (index file), the position 5 contains the value 540.
    Therefore, when stepping the tile (45,3), we pick up their event number [5], we look in an index file where the first instruction of this event is [540] and we pick up from the instructions' file of instructions the 1º  instruction (_Pa).

    Then, for the execution of the instructions we need 2 files for each map (or for the whole game):

  1. One takes charge of keeping the position of the 1º instructions of each event (index File, extension .idx, binary)
  2. Other keeps the compiled instructions (it is a binary file).
    Compilación of instructions of our "script" language. How the compiler works

    Ok. We already know how to give to the interpreter a series of instructions so it could executes them (Nº Event = Index = 1º Instruction). And those instructions stay in a binary file. But now there is a detail: How we obtain those files (index and instructions) starting from the "script" language ?. That means: How the compiler works (not entering in details)?.

    Usually, each map has an associated file where our mini-programs stay. And each event of the map has associate one of those mini-programs:

    File of Map Number 1
    [0] <= event number
        #Talk(0, ' Hullo');
    [1] <= event Nº
        #Talk(0, ' Ey, I said hullo!');
        #Talk(1, ' Yes, I know.');

    The task that the compiler has is the following one:

    Compilación of an instruction. Syntax of a language

    And how we compile a single instruction?. For this, we need to know the format of all the instructions that exist in the language (SYNTAX), to fit our code in one of them.
    For being able to compile a language, we need to know the syntax of this language. That means to know the format of their instruciones. For example:

    Operand: (Operand = Element that is used to be assigned to a variable)
    [Variable | FunctionVariable | Number | ({Operand} Operators {Operand}) | NOT (Operand)]

    That means that and Operand can be a Variable, a FunctionVariable (a function that acts as variable), a number, or a group of operands with an operator ((#Variable(1)+4), 5, (NOT(4=4)),...)

    Therefore, for compiling a line of code, we have to look the type of that instruction (operand, function,...this's made using the syntax), look if that instruction fulfills the syntax, and translate that instruction to interpreter's pseudocode.

    Visual Compiler

    You will have been able to observe that making a compiler is a "peñazo" (it's a boring, time-eater task). But there is better solution that making the compiler in a manual way.

    We're sure that all the "official" (commercial) games has something very similar to what we're going to explain, although the idea was thanks to RPG Maker 2000, of ASCII Corp (we will speak from him to the end of this lesson).

    The solution consists in that the instructions of the language are not introduced using lines of text (that will be compiled), but  using menus in a visual enviroment. When the "line" of code is made, the program will take charge of keeping the code line (already compiled) in a list of instructions (that will be an array, a list of pointers,...) that will be saved into the instruction files and index files.

    Like always, with an example we solve everything ^.^:

#Talk(0, ' Hello, World! '); => Compiler (Syntactical Analysis, a "peñazo" of programming) => | _Pa 0 | _Pa 142 | _Di |


When pressing OK => | _Pa 0 | _Pa 142 | _Di | (LINE)
That LINE stays in a list of instructions.

    But with this method we need to make a "decompiler". Its task is to "decompile" a compiled line, so shows the instruction in the "script" language. ( | _Pa 0 | _Pa 142 | _Di | => #Talk(0, 'Hello, World!')). This is made 'cause without this the designer (us ^_^) will not know what happend with an specific event.

    Imagines the script exposed some pages ago. If we introduce the instructions this way but then we could not see them in "script" language, we would not know what is happening in that event.

    Format of the instructions of the interpreter's pseudocode

    The instructions of  the pseudocode must be stored in some format in the files that before have been commented. We're going to talk about this now.
    Each instruction (i. e. _Pa 0, or _Di ) is composed of their ID (_Pa) and their data (0). The ID takes charge of indicating to the interpreter what this instruction means (_Pa => This's the parameter of a function, _Di => shows a dialogue with the parameters that before have been passed) and the data indicate... well it's easy ^_-, one or more data associated to the ID (i.e. the parameter is a 0).
    But questions arises: Where are stored the strings that instructions uses?. The length of the instructions are fixed or variable?. In what format we save the instructions' ID?. Well: Now we will comment these questions:

    The format of the instructions of the pseudocode in this tutorial is using chains like ID, fixed instruction format and strings in different file (this model is more easy to understand).

    How the interpreter's instructions are executed

    After this "parrafada" (=lot of text), we already know that the interpreter begins to execute a series of instructions when an event is activated. What the interpreter receives are pseudocode instructions (p. e.g. _Pa 0).

    And how is executed a pseudocode instruction in our interpreter (->executable)?
    Using a CASE structure. It looks the type of that instruction, and according to what instruction is, it reads one or more data and certain tasks are made.

    Case IDInstructionRead Of:
            IDTalk:...                    // Shows a dialogue. It uses two parameters.
            IDMovement:...          // Move one NPC. Uses two parameters.
            IDParameter:...          // Saves a parameter in the stack of parameters

    But this is a little more complex. This is because our "script" language doesn't only support procedures, but also functions, expressions, control sentences...
    We will talk of those elements in the next part of this tutorial