1. Généralités
Le système de scripts dans OMSI sert d'interface entre le noyau du jeu OMSI (y compris le moteur graphique et sonore) et les objets du décor ou les véhicules. La communication se fait dans les deux sens, de sorte que les objets du décor ou les véhicules peuvent être équipés de routines de script individuelles qui interprètent les entrées ou les informations du noyau de jeu OMSI ou qui transmettent des informations au noyau de jeu.
2. Conditions préalables
Pour étendre son propre contenu avec des fonctions de script, les conditions préalables suivantes sont nécessaires:
- un (ou plusieurs) fichier(s) de script avec code exécutable (*.osc)
- Fichiers varlist et stringvarlist pour la définition de variables locales
- Fichiers constfile pour définir les constantes utilisateur et le tableau des fonctions
Tous les fichiers qui doivent être lus par le véhicule/l'objet de scénario doivent être définis dans le fichier de configuration correspondant. Cela ne s'applique pas aux variables prédéfinies, qui peuvent être lues et écrites dans les fichiers de script sans être explicitement définies.
3. Application
Dans la configuration, les commandes suivantes peuvent être utilisées pour mettre en œuvre les différents fichiers:
- [script]
- [varnamelist]
- [stringvarnamelist]
- [constfile]
La commande est suivie du nombre de fichiers définis, puis des fichiers avec le chemin correspondant par rapport au fichier de configuration. Le nom du fichier peut être choisi librement, mais il faut éviter les caractères spéciaux comme "Ä,Ö,Ü", car cela peut poser des problèmes avec les systèmes qui n'ont pas installé de Windows en allemand. Il est préférable de s'en tenir à l'alphabet anglais, qui est généralement pris en charge de manière native par chaque système.
4. Les bases du langage de script
Le système de scripts d'OMSI utilise les notation polonaise inversée (RPN). Contrairement à l'écriture typique d'une opération arithmétique (2+5), l'opérateur ne se trouve pas entre les opérandes, mais derrière (25+). Même si la RPN semble inhabituelle au premier abord, elle présente quelques avantages que nous examinerons plus loin. Outre l'entrée plus efficace des opérations arithmétiques), la RPN permet également le traitement par lots, qui a une grande importance dans OMSI. Un exemple plus compliqué : " (1 + 2) * (3 + 4) " correspond à 1 2 + 3 4 + *.
Lors de la création de fichiers texte OMSI et de scripts, il faut faire attention aux majuscules et aux minuscules. OMSI est Case-Sensitive.
5. Stack(pile) et registre
Grâce à l'utilisation du RPN, OMSI possède une pile de chaînes (chaînes de caractères complexes) et une pile de virgules flottantes. Dans ce qui suit, le terme "pile" désigne toujours la pile en virgule flottante, sinon on parle de "pile de chaînes".
Les deux piles contiennent 8 emplacements de mémoire numérotés de 0 à 7 (basés sur 0). Chaque opération de script insère une nouvelle valeur dans la pile (push) ou extrait des valeurs de la pile (pop/pull). Une lecture (peek) sans modification de la pile est également possible. La dernière valeur définie prend alors la première place dans la pile, chaque valeur définie précédemment "monte" d'une place.
Si des valeurs doivent être stockées temporairement pour un traitement ultérieur dans le script, sans utiliser de variables locales, OMSI propose huit emplacements de mémoire indexés (0-7), qui peuvent être lus et écrits directement et se trouvent dans le registre. Cela ne vaut toutefois que pour les nombres à virgule flottante, il n'y a pas de registre pour les chaînes de caractères.
6. Exemple d'opérations
exemple:
L'opération est 1 + 2. Le code de script pour cela ressemble à ceci:
1 2 +
Le tableau suivant illustre le comportement de la pile lors de l'opération susmentionnée:
Emplacement de la pile 0 |
Emplacement de la pile 1 |
Emplacement de la pile 2 |
Emplacement de la pile 3 |
Emplacement de la pile 4 |
Emplacement de la pile 5 |
Emplacement de la pile 6 |
Emplacement de la pile 7 |
|
avant: | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
"1" | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
"2" | 2 | 1 | 0 | 0 | 0 | 0 | 0 | 0 |
"+" | 3 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
Dans l'état initial, la pile est généralement remplie de zéros. La commande "1" déplace le 1 vers le haut de la pile, tous les chiffres déjà présents remontent d'une place. La commande "4" place le quatre en haut de la pile, le un en deuxième position et tous les autres chiffres en troisième position. La commande "+" compare les deux premières valeurs de la pile et place le résultat à la première place de la pile. Lors de l'utilisation d'opérateurs, les valeurs à calculer sont retirées de la pile, le résultat se trouve alors à la place la plus haute de la pile.
Un autre exemple:
(1 + 2) * (3 + 4) doit être noté de la manière suivante, comme indiqué plus haut:
1 2 + 3 4 + *
Der Stack verhält sich somit folgendermaßen:
Emplacement de la pile 0 |
Emplacement de la pile 1 |
Emplacement de la pile 2 |
Emplacement de la pile 3 |
Emplacement de la pile 4 |
Emplacement de la pile 5 |
Emplacement de la pile 6 |
Emplacement de la pile 7 |
|
avant: | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
"1" | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
"2" | 2 | 1 | 0 | 0 | 0 | 0 | 0 | 0 |
"+" | 3 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
"3" | 3 | 3 | 0 | 0 | 0 | 0 | 0 | 0 |
"4" | 4 | 3 | 3 | 0 | 0 | 0 | 0 | 0 |
"+" | 7 | 3 | 0 | 0 | 0 | 0 | 0 | 0 |
"*" | 21 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
A la fin de l'opération, le résultat correct se trouve dans l'emplacement de pile 0.
Au lieu de chiffres, il est également possible d'utiliser des variables ou des résultats d'autres calculs comme opérandes.
7. Nombres flottants et chaînes de caractères
OMSI travaille exclusivement avec les types de données nombre à virgule flottante et chaîne de caractères. Ces types de fichiers ont des piles séparées et fonctionnent donc en général indépendamment l'un de l'autre. Il est toutefois possible de convertir des valeurs à virgule flottante en chaînes de caractères ou des chaînes de caractères en valeurs à virgule flottante - certaines fonctions peuvent donc avoir accès aux deux domaines en même temps.
Les variables booléennes ne sont pas utilisées dans OMSI. En règle générale, les valeurs numériques 0 et 1 sont utilisées pour true et false - c'est-à-dire le principe classique de oui/non en informatique.
8. Mots-clés de script
8.1. Commentaires
Les annotations ne sont possibles qu'en plaçant une apostrophe ' tout au début de la ligne à supprimer:
OMSI ne reconnaît pas non plus une zone en retrait via des tabulations comme un commentaire - la tabulation est interprétée comme un signe. Tout à l'avant signifie donc tout à l'avant!
8.2. Entry-/Exitpoints, Trigger, Macros
Toutes les commandes doivent se situer entre un point d'entrée et un point de sortie. Les points d'entrée sont identifiés à l'aide des mots-clés suivants:
{frame} | Les scripts définis dans cette zone sont exécutés une fois dans chaque cadre. |
{init} | Les scripts définis dans cette zone sont exécutés une seule fois lors de l'initialisation du script. |
{frame_ai} | Les scripts définis dans cette zone sont exécutés une fois par image - mais uniquement si le véhicule n'est pas dans le champ de vision du joueur. Ne fonctionne PAS pour les objets du décor! |
{macro:''name''} | Les scripts définis dans cette zone ne sont exécutés que lorsque la macro est appelée. |
{trigger:''name''} | Les scripts définis dans cette zone ne sont exécutés que si le joueur ou l'OMSI appelle ce déclencheur, par exemple en appuyant sur une touche. |
{end} | Point de sortie universel. doit être défini pour chacune des commandes mentionnées ci-dessus. À la fin d'un script, il doit y avoir autant de points de sortie que de points d'entrée! |
8.3. Appel de macro
L'appel d'une macro se fait par (M.L.''nom''). L'appel d'une macro doit toujours se faire AVANT la macro elle-même.
8.4. Division du script en plusieurs fichiers
Pour les scripts simples ou courts, l'utilisation du bloc principal {frame}-{end} (éventuellement en combinaison avec un bloc {init}-{end}) peut suffire. Pour les scripts complexes, il est recommandé d'utiliser un script principal qui contient un bloc de script principal et un bloc d'initialisation. Dans ce bloc, il est possible de définir des sous-scripts dans des fichiers séparés à l'aide d'un {Macro:Name}.
Il convient à cet égard de respecter les consignes suivantes:
- Un script principal qui contient les blocs {frame} et {init}, mais qui n'appelle que les subscripts à l'aide d'une macro
- Chaque script devrait avoir son propre fichier *.osc et - selon les besoins - ses propres Varlist et Consfiles. Les déclencheurs de touches qui appartiennent à cette section de script devraient également être définis dans le script correspondant.
- Les macros doivent être nommées de manière appropriée afin que les tiers puissent suivre les scripts - par exemple {macro:''subsystem''_frame} et {macro:''subsystem''_init}.
- Rappelons que l'appel d'une macro doit toujours se faire AVANT la macro elle-même. Si des sous-scripts sont utilisés, le script principal doit être appelé en premier dans le fichier de configuration. En cas d'appel de macros dans plusieurs fichiers, il faut également veiller à respecter l'ordre correct.
8.5. Trigger
Une section {trigger:''name''}...{end} peut être appelée de différentes manières à partir du programme principal. Il s'agit notamment de
- Déclenchement par le clavier.
Si la combinaison de touches a été nommée ''Combinaison de touches'', {trigger:Combinaison de touches} est appelé lorsque la touche est enfoncée, {trigger:Combinaison de touches_off} est appelé lorsque la touche est relâchée - Déclenchement par la souris.
Si l'on a cliqué sur un maillage dont la désignation [mouseevent] est ''mouse_event'', {trigger:mouse_event} est appelé. En maintenant le bouton de la souris enfoncé, {trigger:mouse_event_drag} est appelé et en relâchant le bouton de la souris, {trigger:mouse_event_off} est appelé. Un déclencheur normal peut également être attribué à un mesh avec [mouseevent]. - Cette distinction n'est en général nécessaire que lorsque le mouvement de la souris a une influence sur l'animation ou les valeurs transmises (par ex. commutateur rotatif).
* Il existe également une série de LINK:Systemtrigger, qui sont définis par le noyau du jeu OMSI.
9. Operationen
9.1. Stack-Operationen
%stackdump% | Affiche une boîte de dialogue avec le contenu de la pile en virgule flottante (ne doit être utilisé qu'à des fins de débogage). |
s0, s1, ..., s7 | Enregistrement de la valeur actuelle de la pile dans le registre indiqué par le chiffre. La valeur reste dans la pile. |
l0, l1, ..., l7 | Chargement de la valeur de registre correspondante et déplacement dans la pile. La valeur reste dans le registre. |
d | Duplique la valeur supérieure de la pile ; toutes les autres valeurs de la pile passent à l'arrière. |
$msg | Écrit la valeur de la pile de chaînes la plus élevée dans la ligne de débogage d'OMSI - qu'il s'agisse d'un véhicule ou d'un objet du décor. |
$d | analogue à "d" - duplique la valeur supérieure de la pile de chaînes. |
9.2. Opérations logiques
Les opérations logiques fonctionnent selon le principe 0 = FALSE, tout le reste est TRUE.
&& | Si la valeur dans la pile 0 et dans la pile 1 est identique, cet opérateur renvoie 1 ; sinon, il renvoie 0. |
|| | ou |
! | Négation (Inverse la variable) |
9.3. Opérations de comparaison
Les opérations de comparaison comparent les valeurs dans les deux emplacements de pile les plus élevés respectifs et insèrent ensuite un 1 ou un 0 dans l'emplacement de pile le plus élevé, en fonction du résultat.
= | "1" si les valeurs supérieures de la pile sont identiques, sinon "0". |
< |
"1" si la valeur de la pile 1 est inférieure à la valeur de la pile 0, sinon "0". |
> | "1" si la valeur de la pile 1 est supérieure à la valeur de la pile 0, sinon "0". |
<= | "1" si la valeur de la pile 1 est inférieure ou égale à la valeur de la pile 0, sinon "0". |
>= | "1" si la valeur de la pile 1 est supérieure ou égale à la valeur de la pile 0, sinon "0". |
$= | Comme "=", mais pour les deux premières places de la pile de chaînes. |
$< | $< Inférieur à (chaîne). Les opérations d'inégalité sur les chaînes de caractères vérifient l'ordre alphabétique. Ainsi, "A" est plus petit que "B". |
$> | $>plus grand que (chaîne). Les opérations inégales sur les chaînes de caractères vérifient l'ordre alphabétique. Ainsi, "A" est plus grand que "B". |
$<= | Inférieur ou égal à (chaîne). |
$>= | Supérieur ou égal (chaîne). |
9.4. Opérations mathématiques
+ | Addition |
- | Soustraction |
* | Multiplication |
/ | Division |
% | Reste de la division (étendu comme suit pour les nombres à virgule flottante : Stack0 - trunc(Stack1 / Stack0) * Stack1 ) |
/-/ | Changement de signe |
sin | Sinus |
arcsin | Fonction inverse du sinus |
arctan | Fonction inverse de la tangente |
min | Choix de la plus petite des deux valeurs supérieures de la pile |
max | Choix de la plus grande des deux valeurs supérieures de la pile |
exp | Fonction exponentielle de base e (e^Stack0) |
sqrt | Racine carrée |
sqr | Carré |
sgn | Retour du signe ; selon le cas, soit -1, 0 ou 1 |
pi | Nombre de cercles pi (3,14159265...) |
random | nombre entier aléatoire 0 <= x < Stack0 |
trunc | Arrondir au nombre entier le plus proche |
9.5. Opérations sur les chaînes de caractères
"blubb" | Insertion de la chaîne "blubb" sur l'emplacement supérieur de la pile de chaînes |
$+ | Fusionner deux chaînes de caractères. "Tutti" "Frutti" $+ donne "TuttiFrutti". |
$* | La chaîne de la pile supérieure est répétée jusqu'à ce que la longueur de caractère résultante soit juste inférieure ou égale à la valeur de la pile supérieure. Exemple : "nom" 8 $* donne "nomnomno". |
$length | Renvoie le nombre de caractères de la chaîne supérieure de la pile dans la pile. |
$cutBegin | Coupe les caractères "stack0" à l'avant de la chaîne supérieure de la pile. |
$cutEnd | Coupe les caractères ''stack0'' à l'arrière de la chaîne supérieure de la pile. |
$SetLengthR | Ajuste la longueur de la chaîne supérieure de la pile sur ''stack0'' alignée à droite en supprimant des caractères au début ou en ajoutant des espaces.* |
$SetLengthC | Ajuste la longueur de la chaîne supérieure de la pile sur ''stack0'' au milieu en supprimant des caractères au début ou en ajoutant des espaces.* |
$SetLengthL | Ajuste la longueur de la chaîne de la pile la plus haute sur ''stack0'' alignée à gauche en supprimant des caractères ou en ajoutant des espaces au début*. |
$IntToStr | Arrondit ''stack0'' et convertit l'entier résultant en une chaîne de caractères. |
$IntToStrEnh | La version étendue de IntToStr. Sert à remplir la chaîne avec des caractères. Exemple : 11 " 5" $IntToStrEnh donne " 11" et 123456789 "X11" $IntToStrEnh donne "XX123456789". En cas d'erreur, "ERROR" est affiché. |
$StrToFloat | Convertit la chaîne de pile supérieure en un nombre à virgule flottante, si possible. Dans le cas contraire, un -1 est écrit. |
$RemoveSpaces | Supprime tous les espaces avant et après la chaîne de caractères proprement dite. Les "caractères vides" deviennent "caractères vides". |
* Attention: la commande ne supprime pas l'opérateur float de la pile. La valeur à la longueur de laquelle la chaîne a été raccourcie reste donc sur la pile0.
10. Accès aux variables
OMSI fait la différence entre les variables système et les variables locales. Les variables système peuvent être lues partout, les variables locales sont liées au véhicule/objet. Les variables système sont par exemple l'heure ou la météo, les variables locales sont par exemple la position d'un interrupteur dans le véhicule ou la température du chauffage.
Il existe également des variables locales prédéfinies qui ne sont pas définies par l'utilisateur. Il s'agit par exemple de la vitesse du bus. Les variables locales peuvent être attribuées par l'utilisateur de manière illimitée. Il existe également des variables "à la demande" qui sont prédéfinies par OMSI, mais qui doivent être définies par l'utilisateur.
(L.S.''varname'') | Charge la variable système ''varname'' dans l'emplacement supérieur de la pile |
(L.L.''varname'') | Charge la variable locale ''varname'' dans l'emplacement supérieur de la pile |
(S.L.''varname'') | Enregistre l'emplacement supérieur de la pile dans la variable locale ''varname |
(L.$.''varname'') | Charge la variable de chaîne locale ''varname'' dans l'emplacement de pile de chaîne le plus élevé |
(S.$.''varname'') | Enregistre l'emplacement supérieur de la pile de chaînes dans la variable locale de chaînes ''varname |
Vous trouverez ici une description détaillée des différentes variables système et variables locales prédéfinies disponibles : LINK Variables
11. Constantes et fonctions
Les constantes locales et les fonctions définies à la pièce peuvent être définies dans les fichiers de constantes (''constfiles'', ''~_constfile.txt''). La structure de chaque fichier de constantes se compose d'un mot-clé, d'une variable et des valeurs correspondantes. Seules les valeurs en virgule flottante peuvent être définies, pas les chaînes de caractères.
[const] définit une nouvelle constante et indique sa valeur :
exemple:
[newcurve] introduit la définition d'une nouvelle fonction (linéaire par morceaux):
[pnt] ajoute une nouvelle paire x-y à la fonction définie précédemment avec [newcurve]. Chaque fonction doit normalement disposer d'au moins deux paires. L'ordre des paires ''doit'' être croissant dans la direction x!
exemple:
Les constantes sont appelées par la commande (C.L.''Constante'') dans le script et chargées dans la pile.
Les fonctions sont appelées par la commande (F.L.''Fonction''). La valeur qui se trouve sur la position supérieure de la pile est utilisée comme "entrée" (paramètre X) pour la courbe. La valeur Y définie par la fonction en position X est émise. Si la valeur x se déplace en dehors des limites des points d'angle définis par les entrées [pnt], la valeur y du point d'angle le plus proche est toujours utilisée. La fonction est donc prolongée horizontalement à l'infini avant le premier et après le dernier point d'angle.
12. Déclencheur de son
Les déclencheurs sonores ne sont pas des déclencheurs qui peuvent être contrôlés par des entrées au clavier ou à la souris. Les déclencheurs sonores sont déclenchés par le véhicule/script de scène et servent à la possibilité de jouer des sons. Il existe deux possibilités:
(T.F.''Soundtrigger'') Joue une fois un son défini par le script. Pour cela, la chaîne de pile la plus haute est lue et utilisée comme nom de fichier, le chemin d'accès au fichier étant interprété relativement au dossier son de l'objet.
exemple:
Le fichier son "Test.wav" défini avec le déclencheur "Soundtrigger" est lu lorsque (T.L.MeinTrigger) est appelé dans le script.
"Test2.wav" (T.F.MeinTrigger) joue le fichier Test2.wav. Ceci est nécessaire par exemple pour les annonces d'arrêts, pour lesquelles le script du véhicule calcule l'arrêt actuel et permet ainsi de jouer un fichier son différent à chaque arrêt avec le même déclencheur.
13. Macros système
Les fonctions mises en lumière jusqu'à présent permettent au script de communiquer avec OMSI de la manière suivante:
- Lecture de valeurs via des variables système et des variables locales prédéfinies
- Écriture de valeurs via ces mêmes valeurs
- Réception de déclenchements clavier, souris ou système
Outre ces possibilités, il existe également des "macros système". Ces macros sont des fonctions complexes qui attendent des entrées du script OMSI et qui transmettent des données au script en fonction de leur fonction. Ceci est par exemple nécessaire pour la lecture du fichier de la ferme.
L'application est identique à celle des macros définies par l'utilisateur, mais la macro système attend des informations qu'elle récupère dans la pile et réécrit le résultat dans la pile.
Une liste de toutes les macros système se trouve ici: LINK System-Makros
14. Conditions et boucles
Le seul contrôle du déroulement du programme n'est pour l'instant possible qu'avec la condition IF. Les boucles et les go-to ne sont que partiellement possibles avec le système de scripts OMSI.
14.1. Condition IF
'Il doit y avoir une condition:
(L.L.blubb) 1 =
{if}
'Cette section est exécutée si blubb = 1:
2 3 +
{else}
'Dans le cas contraire, cette section sera exécutée:
3 4 +
{endif}
(S.L.bla)
En raison de la notation inversée avec traitement par lots, il est également logique que la condition soit définie en premier : les valeurs doivent d'abord être placées dans la pile pour que l'opérateur puisse les comparer. Le résultat est 0 ou 1, par conséquent true ou false. La condition {if} peut alors être évaluée avec cette valeur.
Ainsi, dans l'exemple ci-dessus, si ''blubb'' a la valeur 1, ''bla'' aura la valeur 5, sinon elle aura la valeur 7.
Les imbrications de la condition IF servent à remplacer les constructions "Else-If" (qui n'existent pas) :
'Une condition doit figurer ici, par exemple:
(L.L.blubb) 1 =
{if}
'Cette section est exécutée si blubb = 1:
2 3 +
{else}
(L.L.blubb) 5 =
{if}
'Cette section est exécutée lorsque blubb = 5:
3 4 +
{else}
'Dans le cas contraire, cette section sera exécutée:
13
{endif}
{endif}
(S.L.bla)
Alles anzeigen
Il faut ici faire particulièrement attention au double {endif} ! Pour chaque condition {if} ouverte, il faut également placer un {endif}.