Within the actual vehicle, only "slots" have to be defined, which tell LOTUS where which module is to be installed and pass some additional necessary parameters. Which module is placed in which slot can be controlled in different ways - currently this is done by configuring the user vehicle and by the script system.
For example, a module is an IBIS device or display. Each module is a completely independent object, which is built and configured separately from the vehicle in the Object & Vehicle Tool. It can have scripts, sounds, animations etc.
To create a new module, "Module" (instead of scenery object or vehicle) is selected as the object class. The actual (visible) object should not be placed as it will be positioned in the vehicle, but centered and not rotated. The exact position and rotation, however, is defined in the vehicle.
1.1 Module Class
Each module is provided with a so-called module class. (Adjustable in the object settings.) The module class is a string that describes what kind of module it is. Each module slot is also provided with a module class. As a result, the player can later only put modules that have the same module class on a module slot. This prevents an IBIS device from being placed at the top of the destination display box - or vice versa, a roller conveyor directly in front of the user's nose where the IBIS is actually located... It is important that the module classes are always identical.
The placement of modules on the script side is not affected by this. The module can be freely selected here.
2 Module slots
Each vehicle, but also each module itself, can be provided with so-called module slots, which can then be equipped with appropriate modules as desired and optionally by script or by selection by the user when configuring his train.
The module slots are configured in the object settings. There you find the section "Modules", where you can add as many module slots as you like.
ATTENTION: Currently an error message appears after adding a new slot. Please ignore it, close the window with "OK" and open it again - then you can continue!
Each slot has the following parameters:
- Name: This name appears in the vehicle configuration window in the simulator
- Module class: Only modules with the same module class (upper and lower case is respected!) can be set to this slot by the user.
- Index within the module class: Assume that it is a bidirectional railcar that is to have an IBIS at both ends. Two slots are then set up. If the scripts of the IBIS devices now receive a message (see below) from the vehicle, this index is sent along with it and the script knows whether it is itself the IBIS of the front driver's compartment or the rear one.
- Position and rotation: These values determine where and how exactly the module should be placed.
- Invisible in the vehicle configuration in the simulator: If a slot is only to be filled by the script and therefore the player should not have any influence on it, the slot can be "hidden" with this parameter.
- Use this clearance: As with all other meshes and materials, you have to define to which clearance the module belongs and therefore by which light sources it should be illuminated.
- Parent animation: In order for the module to be attached to a moving object, this animation must be selected here.
- Standard module: As long as the player does not select anything else, each module slot is equipped with a standard module. This parameter determines which one this should be.
Communication between the subordinate objects (modules) and the superordinate objects (vehicle) takes place by means of procedure calls, the so-called "messages" and "broadcasts".
Messages send data specifically to certain modules or specifically to the superordinate object:
- procedure SendMessageToChildInteger(self: integer; slotindex: integer; messageId: string; value: integer);: This procedure call calls the GetMessageFromParentInteger procedure (see below) in the module script located in the slot with the slotindex index. A message ID and an integer value is passed. Similarly, there are SendMessageToChildSingle and SendMessageToChildString, each with a single and a string value.
- procedure SendMessageToParentInteger(self: integer; id: string; value: integer);: With this procedure call the GetMessageFromChildInteger procedure (see below) in the parent script. It passes a message ID and an integer value value. Analogous there are SendMessageToParentSingle and SendMessageToParentString with a single and a string value each.
Within the respective script, one of the following procedures can be declared, which is then called on the LOTUS side when one of the procedures described above is called by the respective "partner":
- procedure ReceiveMessageFromChildInteger(slotindex: integer; id: string; value: integer);: Is called when a (subordinate) module script calls the procedure SendMessageToParentInteger. slotindex identifies the slot of the module that has called this procedure. Analogously there are also ReceiveMessageFromChildSingle and ReceiveMessageFromChildString
- procedure ReceiveMessageFromParentInteger(indexOfClass: integer; id: string; value: integer);: Called when a (parent) object script (e.g. vehicle) calls SendMessageToChildInteger. indexOfClass is the value "index within the module class" of the slot where the module object of the script is located. Analogously there are also ReceiveMessageFromParentSingle and ReceiveMessageFromParentString.
Broadcasts are programmed in the same way as messages, but work differently: While messages address specific modules or the superordinate vehicle/object, in the case of broadcasts the receive procedures of all scripts of all modules and the parent object are addressed. In this way, modules such as IBIS can communicate with all other modules, e.g. the displays, without having to know how many displays are connected. In addition, the detour via the parent vehicle is not necessary. In addition to the actual ID, there is also a (data) bus ID here, i.e. it is simulated that the broadcast commands are routed in groups over specific data lines ("data buses"). In contrast, it is no longer possible to determine the origin of the broadcast.
The broadcast functions are as follows:
- procedure SendBroadcastInteger(self: integer; busId: string; id: string; value: integer); (optionally also ~Single or ~String
- procedure ReceiveBroadcastInteger(busId: string; id: string; value: integer); (optionally also ~Single or ~String
As mentioned - the functionality is the same as for the messages (see above).
3.2.1 Forward broadcasts via couplings
Broadcasts, however, have another very special function compared to the normal message system: They are not necessarily limited to your own vehicle! It is possible to tell the couplings of the vehicle that they transmit broadcasts of a certain bus ID to the neighboring vehicles. So they represent - completely independent of the module system - another variant with which vehicles can communicate across their couplings!
The following script procedures are available for this functionality:
- procedure CoupleBroadcastBus(self: integer; busID: string; couplingindex: byte); – enables the transmission of broadcasts with the specified bus-ID via the coupling with the index couplingindex.
- procedure UncoupleBroadcastBus(self: integer; busID: string; couplingindex: byte); – disables the transmission of broadcasts with the specified bus-ID via the specified coupling.
Of course, the broadcasts are only transmitted if both vehicles have enabled the corresponding bus. And of course only if the coupling was successful...
3.3 Script performance
It is important to know that the performance of the message commands is not completely "irrelevant"! In this respect, message procedures should only be called if it is really necessary. For example, the line number set in IBIS does not have to be transmitted to the vehicle with every frame, but only if it has been changed!