Crystal Entity Layer: 4.5 The XML Behaviour Layer

[ < ] | [ > ] |  | [ << ] | [ Up ] | [ >> ] |  |  |  |  | [Top] | [Contents] | [Index] | [ ? ]

## 4.5 The XML Behaviour Layer

One of the predefined behaviour layers in Crystal Entity Layer is the XML behaviour layer. In this behaviour layer XML is used a simple scripting language. This allows one to create game logic using XML that one can embed in a map file.

### Example

The easiest way to describe the basics behind the XML behaviour layer is with an example:

    <world>
        <textures>
            <texture name="chair">
                <file>/cellib/images/chair5.gif</file>
            </texture>
        </textures>
        <materials>
            <material name="chair">
    	    <texture>chair</texture>
    	</material>
        </materials>
        <settings>
            <clearscreen>yes</clearscreen>
        </settings>

        <addon plugin="cel.addons.xmlscripts">
            <pcfactory>cel.pcfactory.billboard</pcfactory>
            <pcfactory>cel.pcfactory.timer</pcfactory>
            <pcfactory>cel.pcfactory.properties</pcfactory>

            <script name="chair_clicker">
                <event name="init">
                    <var name="counter" value="0" />
                </event>
                <event name="pcbillboard_select">
                    <var name="counter" value="?counter+1" />
                    <if eval="?counter < 10">
                        <true>
                           <print value="'You clicked '+?counter+' times.'" />
                        </true>
                        <false>
                            <print value="'It is time you stopped clicking!'" />
                        </false>
                    </if>
                </event>
            </script>

            <script name="chair_mover">
                <event name="pctimer_wakeup">
                    <bb_move x="rand(1)*250000" y="rand(1)*250000" delta="500" />
                </event>
            </script>
        </addon>

        <addon plugin="cel.addons.celentity" entityname="red_chair">
            <propclass name="pcbillboard">
                <property name="name" string="red_chair" />
                <property name="materialname" string="chair" />
                <property name="clickable" bool="1" />
                <property name="movable" bool="1" />
                <property name="restack" bool="1" />
                <property name="color" color="1,1,1" />
                <property name="widthpct" float=".7" />
                <property name="heightpct" float=".7" />
            </propclass>
            <behaviour name="chair_clicker" />
        </addon>

        <addon plugin="cel.addons.celentity" entityname="green_chair">
            <propclass name="pcbillboard">
                <property name="name" string="green_chair" />
                <property name="materialname" string="chair" />
                <property name="clickable" bool="1" />
                <property name="movable" bool="0" />
                <property name="restack" bool="1" />
                <property name="color" color="0,1,0" />
                <property name="widthpct" float=".7" />
                <property name="heightpct" float=".7" />
                <property name="x" long="100000" />
                <property name="y" long="100000" />
            </propclass>
            <propclass name="pctimer">
                <action name="WakeUp">
                        <par name="time" long="500" />
                        <par name="repeat" bool="true" />
                </action>
            </propclass>
            <behaviour name="chair_mover" />
        </addon>
    </world>

To run this example you can put this XML file in the current directory and then do this on Windows:

    bootstrap.exe cel.behaviourlayer.xml bootstrap load //this testscript.xml

Or on GNU/Linux:

    ./bootstrap cel.behaviourlayer.xml bootstrap load /this testscript.xml

In this example we create two entities using the ``cel.addons.celentity'` addon (see section CelEntity Addon). The ``red_chair'` entity just has one property classes which is the ``pcbillboard'` property class. This property class is designed for simple 2D graphics. You can use it to build a complete 2D game (like the Boulderdash game that is included with Crystal Entity Layer) or else you can use it for HUD elements in a 3D game. The ``green_chair'` entity has a ``pcbillboard'` property class and a ``pctimer'` (see section Timer).

### Scripts

When using the XML behaviour layer you basically create scripts. Every script corresponds to a behaviour for an entity (multiple entities can use it of course). In this particular example we use the ``cel.addons.xmlscripts'` addon (see section XML Scripts Addon) to create the two scripts that we will use for the two entities. The ``chair_clicker'` script simply waits until the billboard is clicked and increments a counter. If the counter is less then 10 then it will print out the count. Otherwise it issues a warning. The ``chair_mover'` script simply waits until the timer fires and then it initiates a move of the billboard to another location. The ``bb_move'` will make sure the billboard keeps moving gradually to the desired location (side note, the location system for billboards uses a coordinate system where 0,0 it top-left and 307200,307200 is bottom-right, independent of window resolution).

### Events

Every event in a script roughly corresponds with a method call in a normal programming language. You can make as many events as you want but there are a few special cases. First there is the ``init'` event which is called when the entity with that script is first executed. It is a kind of constructor. Secondly when the entity gets a message from one of the property classes this message is also translated to an event. In the example above the ``chair_clicker'` script reacted on billboard selection which is a message from the billboard property class that is named ``pcbillboard_select'`. The ``chair_mover'` script reacted on timer events which is a message from the timer proerty class that is named ``pctimer_wakeup'`.

### Variables

You can use two kinds of variables in an event. First there are global variables. To assign a value to such a variable you use:

    <var name="variable" value="1000" />

Note that variables are typed. The following types are possible:

- ``int32'` (signed 32-bit integer): This is recognized by a value like ``345'` or ``-398'`.
- ``uint32'` (unsigned 32-bit integer): This is recognized by a value like ``345u'`.
- ``float'` (floating point number): Possibilities are ``342.33'` or ``-2.33e-33'`.
- ``bool'` (true or false): Possible values are ``true'` or ``false'`.
- ``vector2'` (two dimensional vector): Written as ``[x,y]'`.
- ``vector3'` (three dimensional vector): Written as ``[x,y,z]'`.
- ``string'` (a string): Written as a simple token with no spaces or special tokens (like 'bla321') or else surrounded by single quotes.

To use a global variable you use the ``?'` operator like this:

    <print value="?variable" />

You can combine this in complex expressions:

    <print value="3.14*(?variable+?othervar)" />

Global variables have one big advantage: they are persistant. Internally the XML behaviour layer will automatically use a ``pcproperties'` property class to store these variables (such a property class will be created on the entity if it doesn't already exist). This also means you can set and access variables from other entities (notice how the ``?'` operator is combined with the ``.'` operator to access the variable from another entity):

    <var entity="other_entity" var="variable" value="'some string'" />
    <print value="'x in other_entity is equal to '+?other_entity.x" />

In contrast with global variables you also have local variables. Local variables don't remember their value and you can't access local variables from other entities either. On the other hand they are considerably more performant to work with. Here is how you set and use a local variable:

    <lvar name="localvar" value="3.1415" />
    <print value="'Our local variable is equal to '+#localvar"/>

This can become pretty complex. For example take this:

    <print value="?#entity.#variable" />

This will print out the variable which has the name given in the local variable called ``variable'` from the entity which has the name given in the local variable called ``entity'`.

### Calling Events

Some events (like ``init'` and messages from property classes) are automatically called but you can also define your own events and in that case you need to be able to call them (like you would call functions). Here is an example on how to call an event:

    <call event="myevent" />

This is the simplest example. In this case we will simply pass control to the ``myevent'` event and when that finishes execution will resume at the operation after the `call`.

It is also possible to call an event in another entity. Basically what this will do is call the event in the script (behaviour) that is attached to that other entity:

    <call entity="other_entities" event="myevent" />

You can also pass parameters in an event call:

    <call event="myevent">
        <par id="parid(x)" value="100" />
        <par id="parid(y)" value="50" />
    </call>

This will pass the ``x'` and ``y'` parameters to the event. In the event you can access these parameters with the ``@'` operator like this:

    <event name="addsomething">
        <print value="@x+@y" />
    </event>

Events can also be used as functions that return a value. In that case you write the event like this:

    <event name="addsomething">
        <return value="@x+@y" />
    </event>

Then you can use this function as follows:

    <print value="addsomething(x=3,y=5)" />

You can see how the parameters are passed by name.

It is also possible to call an event in another entity as a function by using the scope (``::'`) operator:

    <print value="otherentity::addsomething(x=3,y=5)" />

A special case for function calling is the ``...'` operator. If you use that then the parameters for the function will be the same as the parameters that called this function. For example:

    <event name="process">
        <return value="addsomething(...)*3" />
    </event>

This function will call ``addsomething'` with the same parameters that are given to ``process'` and then multiply the result with 3.

### Arrays

The XML behaviour layer supports sparse one and two dimensional arrays. They are sparse in the sense that only elements that are assigned really exist and consume memory. So you can put a value in the array at index 5 and one at index 1000000 and the array will be essentially only two items big. Also the indices don't have to be numeric. You can use any kind of type. Internally arrays work by concatenating the array name with the index. For example: ``bla['testing',3]'` actually corresponds with a normal variable that is called ``bla_testing_3'`. So every element in an array is actually just a normal variable. The array syntax is just syntax to help you write arrays more easily. Here is an example on how to assign a value in an array and how to use it:

    <lvar name="index" value="1000" />
    <var name="bla[#index,3]" value="100" />
    <print value="?bla[#index,3]" />

[ < ] | [ > ] |  | [ << ] | [ Up ] | [ >> ]

This document was generated using texi2html 1.76.