Scripteditor - Anleitung&Beispiele - United Script Tutor
Moderators: Moderatoren für Deutsches X-Forum, Scripting / Modding Moderators
-
- Posts: 231
- Joined: Thu, 11. Mar 04, 12:00
Scripteditor - Anleitung&Beispiele - United Script Tutor
Das Tutorial als HTML mit Navigation
Download
X2 Script Tutorial
Dieses Tutorial ist ein Werk von uns Allen für Uns selbst und vor allem für Jene die nach uns kommen und dieses Forum, X2 und die Gemeinschaft bereichern.
---------Externe Referenzen -----------------
X2soUrcerer's Script-Befehlsliste
XML Page-ID, Kommandokonsolenbefehle von MrMilti
0.1dat / Vollständiger Wavetable Katalog von esd
Sprach/Soundnachrichten von Moonraven
X² Math library - fixed point decimal & trig functions by Reven
Inhaltsverzeichniss
I. BurnIt!-Aktivierung des Scripteditors
II. Scripts ins Spiel einhängen
II.1 GothicK's Tutorial No1: Scripts in's Spiel einbinden.
II.1.1 Grundlagen
II.1.2 Bearbeiten der Textdateien
II.1.3 Der Scripteditor
II.2 Nemesi$ Tutorial-Wie hänge ich ein eigenes Script in die Menüs ein
II.2.1 Einleitung
II.2.2 Anforderungen
II.2.3 Vorgehensweise
II.2.4 Installation
II.2.5 Anmerkung
IV. Vanoblis - Der ScriptDebugger - Anleitung (v1.3 UPDATED)
IV.1 Allgemeines
IV.2 Menüpunkte des Debuggers
IV.3 Einstellungen des Debuggers
IV.4 Starten, Stoppen und Debugging von Scripten
IV.5 Debugmodi in Scripten von Metuelisator
X. jnrk's Programming Tutorial
X.0 Allgemeine Programmiertipps
X.1 Grundelemente
X.1.0 Ausgabe
X.1.1 Variable
X.1.2 Schleifen
X.1.3 Bedingungen
X.2 erweiterte Grundelemente
X.2.0 Formatierte Ausgabe von ArcaJeth[D6a]
X.2.1 Arrays
X.2.2 Gültigkeitsbereich/Sichtbarkeit von Variablen
X.2.3 erweiterte Schleifen
X.2.4 erweiterte Bedingungen
X.3. Scripte miteinander verbinden / Unterscripte
X.3.1 Teile und Herrsche - Scripte aufteilen
X.3.2 Übergabe- und Rückgabe-Parameter
X.3.3 präventive Fehlerbehandlung
X.4 Form und Stil von Scripten
X.4.1 Namenskonvention für Dateinamen
X.4.2 Variable initialisieren und Namenskonvention ungarische Notation
X.4.3 Dokumentation
X.6 Mathematik und Logik im Script
X.6.1 Mathematische und Logische Ausdrücke von ArcaJeth[D6a]
------Coming soon-----
X.5 Objekte
X.5.1 exists&get&set
--------------------
------Bits'n Bytes Nützliche Routinen-------
a) Flugblock und Andockcheck von mkess
b) Wurzel+Potenzfunktion von ArcaJeth[D6a]
c) Alle Schiffe/Stationen im Universum auflisten von ticaki und ArcaJeth[D6a]
d) Inhalte von Arrays ausgeben am Beispiel von Sprungtoren von SpaceTycoon
-----------Noch nicht Einsortiertes-------------
Waren nach Main und Subtypes von ArcaJeth[D6a]
Farbigen Text im Logbuch / Nachricht von ArcaJeth[D6a]
Sprachausgabe bei Stationswaren! von SpaceTycoon
Tinte/Toner sparen von SpaceTycoon
-
- Posts: 231
- Joined: Thu, 11. Mar 04, 12:00
a
I. BurnIt-Aktivierung des Scripteditors
Der Scripteditor oder auch das "Manuelle Schiffscomputer Interface" (M.S.C.I.) ist ein Werkzeug innerhalb des Spieles, mit dem Regeln für das Verhalten der KI im Spiel erzeugt oder verändert werden können. Es ermöglicht es außerdem Objekte innerhalb des Spieluniversums zu beeinflußen oder einzufügen.
Das bedeutet jedoch, dass es extrem einflussreich ist und durch unachtsamen Gebrauch erheblicher Schaden am Spieluniversum bewirkt werden kann.
Eine Warnung: Seid euch darüber im Klaren, dass die Benutzung des Scripteditors den Spielspaß vollkommen verderben kann!
Da die Freigabe des Editors auf ausdrücklichen Wunsch vieler Spieler früher als vorgesehen erfolgt, sollte jedem Nutzer dieses mächtigen Werkzeuges bewußt sein, dass, solange die Arbeiten an der Dokumentation noch andauern, es durch Egosoft und die Betatester keinerlei Unterstützung gibt und im Problemfall auch nicht geholfen werden kann. Bis zur Freigabe der offiziellen Dokumentation seid Ihr also auf Euch allein gestellt.
Die Arbeiten an der Dokumentation sollen bis Ende Januar 2004 abgeschlossen werden.
Wenn Ihr Euch sicher seid, dass Ihr auch ohne Unterstützung mit diesem Feature experimentieren wollt, gebt während Ihr im All fliegt Thereshallbewings (beachtet das große "T") ein. Das aktiviert den Menüpunkt "Script Editor" in der Kommandokonsole. Die korrekte Aktivierung wird durch einen Beep bestätigt.
Denkt daran, dass der Scripteditor ein optionales und sehr fortgeschrittenes Werkzeug ist; es ist nicht nötig ihn zu benutzen um X² zu spielen.
Wenn Ihr noch keinerlei Erfahrung mit der Programmierung von Scripts habt, ist es wahrscheinlich besser, wenn Ihr den Editor einfach ignoriert.
II. Scripts ins Spiel einhängen
II.1 GothicK's Tutorial No1: Scripts in's Spiel einbinden.
Wegen der regen Nachfrage gibts hier mal ne Anleitung zum Einbinden der Scripts in's Spiel.
Erst mal Grundsätzliches:
1. Legt euch einen Ordner an, in den ihr die neuen Scripts downloadet.
2. Entpackt jedes Scriptpaket in einen _extra_ Ordner. (WinRAR ist sehr empfehlenswert. Einfach mit Rechtsklick auf die .zip/.rar-Datei und 'entpacken in "Ordner" ' auswählen.
3. Legt je einen Testordner für Scripts und Textdateien an, in die ihr die neuen Dateien kopiert.
Wenn dann Scripts den selben Dateinamen benutzen merkt ihr das sofort.
3.a Im Test"t"-Ordner könnt ihr dann die Textdateien bearbeiten. Dazu später mehr.
3.b In den Test"scripts"-Ordner kopiert ihr noch die x2script.xsl aus dem X²/scripts-Ordner.
Die benötigt ihr um die Scripts im I-Explorer anzuzeigen.
Hier nochmal, für alle die's noch nicht wissen, die Grundlagen:
Aus allen Dateien 44xxxx.xml(english) und 49xxxx.xml(deutsch) lädt X² den Text, der im Spiel angezeigt wird.
Diese Dateien sind im X²/t-Ordner und neue Dateien dieses Typs gehören dann auch in diesen Ordner.
Alle anderen .xml-Dateien gehören in den X²/scripts-Ordner.
Und nun zu den Texten.
Hier liegen die grössten Probleme, wenn es um englishe Scripts geht.
Aber auch generell, weil immer wieder gleiche Dateinamen verwendet werden. Benennt erst einmal (beim deutschen Spiel) die mit 44 beginnenden Dateien um.
Die deutsche Version benötigt Dateien, die mit 49 anfangen.
Wenn ihr ein neues Script entpackt habt und die Dateien in euren Testordner kopieren wollt: Überschreibt nicht die schon vorhandenen Dateien!
In diesem Fall schaut nach, welche Datei überschrieben werden soll.
Öffnet beide Dateien und schaut erstmal, ob die Einträge, die die neue Datei setzen will, schon in der alten enthalten sind. oder andersherum.
Es gibt inzwischen einige Scripts, die die Texte anderer Scripts mitliefern.
Ist das der Fall, dann benutzt das File mit allen Einträgen.
Wenn nicht, gibt es zwei Möglichkeiten:
Jetzt ist es eine Frage, ob ihr die Möglichkeit behalten wollt, Scripts schnell wieder zu entfernen.
Wenn ja, dann müsst ihr den Dateinamen ändern.
z.B.: von 440013 in 440014.
Anschliessend müsst ihr aber auch das Script selbst noch etwas umschreiben. Dazu komme ich später.
Is das nicht so wichtig, könnt ihr auch die Einträge des neuen Scripts in die schon vorhandene Datei einfügen.
Alle Textdateien lassen sich einfach mit einem Texteditor öffnen und bearbeiten. Ich nutze das Windows-Notepad.
Rechtsklick auf die Datei -> bearbeiten.
Fügt alle neuen Einträge an den etsprechenden Position ein.
Wie erkläre ich im nächsten Post.
Jetzt müsst ihr noch schauen, ob das script den Text auch wirklich lädt.
Öffnet dafür die entsprechende Scriptdatei, die mit "init." anfängt.
Wie weiter oben schon geschrieben braucht ihr dafür die x2script.xsl-Datei im selben Ordner.
Jetzt sucht ihr nach dem Eintrag "load text: id=xxxx"
Dort wird festgehalten, welche Textdatei das Spiel lädt.
Wenn das Script mit der Datei 490012.xml arbeitet muss im init.-Script der Eintrag: "load text: id=12" stehen. (die vorn anstehenden Nullen werden ausgeblendet)
Ist das nicht der Fall, oder fehlt dieser Eintrag muss das Script im Editor angepasst werden.
Dazu später mehr.
Wenn alles passt könnt ihr die fertigen Dateien in die entsprechenden Ordner des Spieles kopieren.
II.1.2 Bearbeiten der Textdateien
Ich nehme als Beispiel hier den "Handelscomputer MK3" von Burnit und die erste Version des "Teladi Autotrader" von xscripting.com
Hier gab es nämlich schon die ersten Probleme, weil beide mit der 490003.xml daherkahmen. (der Autotrader eigendlich mit der 440003.xml aber das haben wir ja schon geändert)
Wie gesagt: Diese Dateien lassen sich mit dem InternetExplorer anschauen und mit einem Texteditor bearbeiten.
Ich erkläre jetzt die Datei des HandelscomputerMK3:
Code: Select all
<?xml version="1.0" encoding="UTF-8" ?>
<language id="49">
X² kann sonst, trotz geändertem Dateinamen, den Text nicht laden.
Code: Select all
<page id="17" title="Boardcomp. objects">
<t id="5873">Handelssoftware MK3</t>
</page>
Damit weiss X² den Namen, den Produkttyp und den Preis des neuen Produkts. Aber damit schweife ich schon ins scripten ab.
Code: Select all
<page id="1500" title="Trader scripts" descr=" ">
<t id="10">Der Pilot des Schiffes </t>
<t id="11"> in Sektor </t>
<t id="12"> braucht ihre Hilfe. </t>
,..,
<t id="100">Der Pilot des Schiffes %s in Sektor %s braucht ihre Hilfe. </t>
<t id="101"> Bisher verdientes Geld: %s Cr. Anzahl Handelsfahrten: %s.</t>
</page>
Code: Select all
<page id="2010" title="Commands" descr=" ">
<t id="400">Starte Sektorhandel</t>
</page>
Die Seite (page id) "2010" enthält die langen und...
Code: Select all
</page><page id="2011" title="Commands" descr=" ">
<t id="400">Starte Sektorhandel</t>
</page>
Code: Select all
</language>
Schauen wir noch nach dem "Teladi.."Script:
Code: Select all
<?xml version="1.0" encoding="UTF-8" ?>
<language id="44">
<page id="2008" title="Script Object Commands" descr="0">
<t id="410">COMMAND_TELADI_AUTO_TRADE</t>
<t id="411">COMMAND_TELADI_IMPORT</t>
<t id="412">COMMAND_TELADI_EXPORT</t>
<t id="413">COMMAND_TELADI_BUY_WARE</t>
<t id="414">COMMAND_TELADI_SELL_WARE</t>
<t id="415">COMMAND_TELADI_REPORT</t>
<t id="729">COMMAND_TELADI_LOAD</t>
<t id="730">COMMAND_TELADI_UNLOAD</t>
<t id="731">COMMAND_TELADI_THINK</t>
</page>
<page id="2010" title="Script Cmd Names" descr=" ">
<t id="410">Teladi Automated Trader</t>
<t id="411">Teladi Importer</t>
<t id="412">Teladi Exporter</t>
<t id="413">Teladi Buy ware</t>
<t id="414">Teladi Sell Ware</t>
<t id="415">Request progress log</t>
<t id="729">Load ware...</t>
<t id="730">Unload ware...</t>
<t id="731">Calculating...</t>
</page>
<page id="2011" title="Script Cmd Shorts" descr=" ">
<t id="410">TAT</t>
<t id="411">TIMP</t>
<t id="412">TEXP</t>
<t id="413">TBUY</t>
<t id="414">TSELL</t>
<t id="415">TREQ</t>
</page>
</language>
Alles unter "2010" gehört an die entsprechende Stelle unter "2010" im ersten Script usw.
Wenn, wie hier der Fall, eine neue "page id" auftaucht (2008) dann gehört die natürlich zwischen die "1500" und die "2010".
Wenn ihr fertig seid könnte das Ganze so aussehen:
Code: Select all
<?xml version="1.0" encoding="UTF-8" ?>
<language id="49">
<page id="17" title="Boardcomp. objects">
<t id="5873">Handelssoftware MK3</t>
</page>
<page id="1500" title="Trader scripts" descr=" ">
<t id="10">Der Pilot des Schiffes </t>
<t id="11"> in Sektor </t>
<t id="12"> braucht ihre Hilfe. </t>
<t id="13"> Bisher verdientes Geld: </t>
<t id="14"> Anzahl Handelsfahrten: </t>
<t id="20"> Mein Laderaum ist voll. Ich kann nichts mehr kaufen.</t>
<t id="21"> Ich habe keine Stationen gefunden, mir denen ich handeln kann. Was soll ich jetzt machen? </t>
<t id="22"> Mein Schiff ist zu angeschlagen, um weiterzumachen. Sie finden mich in der Station </t>
<t id="23"> Die Leute HASSEN mich hier, was soll ich jetzt machen? </t>
<t id="24"> Ich konnte meine Ware nicht komplett verkaufen. Brauche Anweisungen. </t>
<t id="25"> Ich bin jetzt im Sektor %s. Mein Schiff ist zu angeschlagen, um weiterzumachen. Sie finden mich in der Station %s.</t>
<t id="100">Der Pilot des Schiffes %s in Sektor %s braucht ihre Hilfe. </t>
<t id="101"> Bisher verdientes Geld: %s Cr. Anzahl Handelsfahrten: %s.</t>
</page>
<page id="2008" title="Script Object Commands" descr="0">
<t id="410">COMMAND_TELADI_AUTO_TRADE</t>
<t id="411">COMMAND_TELADI_IMPORT</t>
<t id="412">COMMAND_TELADI_EXPORT</t>
<t id="413">COMMAND_TELADI_BUY_WARE</t>
<t id="414">COMMAND_TELADI_SELL_WARE</t>
<t id="415">COMMAND_TELADI_REPORT</t>
<t id="729">COMMAND_TELADI_LOAD</t>
<t id="730">COMMAND_TELADI_UNLOAD</t>
<t id="731">COMMAND_TELADI_THINK</t>
</page>
<page id="2010" title="Commands" descr=" ">
<t id="400">Starte Sektorhandel</t>
<t id="410">Teladi Automated Trader</t>
<t id="411">Teladi Importer</t>
<t id="412">Teladi Exporter</t>
<t id="413">Teladi Buy ware</t>
<t id="414">Teladi Sell Ware</t>
<t id="415">Request progress log</t>
<t id="729">Load ware...</t>
<t id="730">Unload ware...</t>
<t id="731">Calculating...</t>
</page>
</page><page id="2011" title="Commands" descr=" ">
<t id="400">Starte Sektorhandel</t>
<t id="410">TAT</t>
<t id="411">TIMP</t>
<t id="412">TEXP</t>
<t id="413">TBUY</t>
<t id="414">TSELL</t>
<t id="415">TREQ</t>
</page>
</language>
Beachtet dabei nur: Keine Umlaute und nur "," "." und "-" als zusätzliche Zeichen!
Wenn der InternetExplorer die Seite nicht anzeigen kann habt ihr einen Fehler gemacht. Meist sind das versehentlich benutzte Umlaute oder ähnliches.
Der Explorer sagt aber auch, in welcher Zeile der Fehler ist.
Fertig.
Jetzt das Ganze in den X²/t-Ordner kopieren und los gehts.
II.1.3 Nun gehts dem Scripteditor an den Kragen
Wenn ihr nicht den oben beschriebenen Weg gehen wollt oder in der init.-Datei des Scripts der Eintrag load text: id= fehlt müsst ihr in den Scripteditor des Spieles.
Erstmal aktivieren. Gebt irgendwo im Weltall (nicht angedockt) folgendes ein: Thereshallbewings und beachtet das grosse "T".
Daraufhin ertöhnt ein tülüt und der Scripteditor steht zur Benutzung frei.
Über die Commandokonsole des Hauptmenues ('Enter' dann 'S') oder im Commandomenue eines Schiffes ('S', 'C', und 'S') ist der Editor erreichbar.
Sucht im Editor die init.Datei und öffnet sie.
Ich nehme wieder den "TeladiTrader" als Beispiel.
Die Datei heist in diesem Fall init.mk2.bindCommands und sieht so aus:
Code: Select all
001 global ship map: set: key=COMMAND_TYPE_TRADE_10, class=Ship, race=Player, script='mk2.Command.localizedTrade', prio=0
002 global ship map: set: key=COMMAND_TYPE_TRADE_11, class=Ship, race=Player, script='mk2.Command.factoryBuy', prio=0
003 global ship map: set: key=COMMAND_TYPE_TRADE_12, class=Ship, race=Player, script='mk2.Command.factorySell', prio=0
004 global ship map: set: key=COMMAND_TYPE_TRADE_13, class=Ship, race=Player, script='mk2.Command.wareBuy', prio=0
005 global ship map: set: key=COMMAND_TYPE_TRADE_14, class=Ship, race=Player, script='mk2.Command.wareSell', prio=0
006 global ship map: set: key=COMMAND_TYPE_TRADE_15, class=Ship, race=Player, script='mk2.command.requestlog', prio=0
007
008 set ship command upgrade: command=COMMAND_TYPE_TRADE_10 upgrade=Handelssoftware MK2
009 set ship command upgrade: command=COMMAND_TYPE_TRADE_11 upgrade=Handelssoftware MK1
010 set ship command upgrade: command=COMMAND_TYPE_TRADE_12 upgrade=Handelssoftware MK2
011 set ship command upgrade: command=COMMAND_TYPE_TRADE_13 upgrade=Handelssoftware MK1
012 set ship command upgrade: command=COMMAND_TYPE_TRADE_14 upgrade=Handelssoftware MK2
013 set ship command upgrade: command=COMMAND_TYPE_TRADE_15 upgrade=Handelscomputer Erweiterung
014
015 return null
Gehen wir davon aus, dass wir die Textdatei in 491234.xml umbenannt haben.
Dann tragen wir die jetzt ein:
Geht mit dem Cursor auf eine Zeile am Anfang oder am Ende des Scripts und drückt 'Einfg'.
In die Neue Zeile kommt jetzt der Eintrag.
'Enter' drücken und aus dem folgenden Menue den ersten Punkt "Generell Commands" auswählen.
Im darauf folgenden Menue sucht ihr den Befehl "load text: id<Var\Num>" und drückt 'Enter'.
Der Befehl erscheint daraufhin im Script und der Cursor steht automatisch auf dem "<Var\Num>"-Teil.
Wieder 'Enter' gedückt und aus der erscheinenden Liste den Eintrag "<Nummer>" auswählen.
Dann könnt ihr die Zahl eintragen, die das Script benutzen soll.
In meinem Beispiel also die 1234.
So sollte das dann aussehen:
Code: Select all
015 load text: id=1234
Jetzt weiss X² welchen Text es benutzen soll.
Fertig.
P.S.: Der Autor übernimmt keine Verantwortung für eventuell entstandene Schäden.
P.P.S.: Wenn ich was vergessen, übersehen oder falsch dargestellt hab bitte berichtigt mich.
II.2 Nemesi$ Tutorial-Wie hänge ich ein eigenes Script in die Menüs ein
Sodele..dann will ich mich mal hier an die Übersetzung von Revens Tutorial wagen. Das Original ist unter http://www.egosoft.com/x2/forum/viewtopic.php?t=21585 aufzufinden.
Alles was ich geändert habe, oder einfach meine Meinung dazu schreibe bekommt die Farbe Orange
-----------------------------------------------------------------
Einleitung
Wir alle kennen die InGame-Kommandomenüs der Schiffe. Navigation, Kampf, Handeln und Spezial. Egosoft hat X² extrem erweiterbar gemacht, inklusive dieser Menüs. Viele von uns haben sich Scripte aus dem Web geholt die die Funktionalität von X² erweitern. Und wenn es auch nur BurnIt's neue Trade Command Extension MK3 mit seinem "Start Sector Trader" Kommando ist. Hier werde ich nun eine (vom Original leicht erweiterte) Schritt-für-Schritt Anleitung schreiben, wie man seine eigenen Scripte in die vorhandenen Menüs von X² einhängt.
In diesem Tutorial wird ein Script von Reven als Beispiel verwendet, das er selber geschrieben hat, und das ins Trademenü eingehängt wird. Dieses Script versucht die Anzahl der Produkte einer Fabrik auf einem vorgegebenen Füllstand zu halten. Das ist dann von Vorteil wenn man eine Fabrik hat, die nur eine minimale Anzahle ihrer Produkte bereit halten kann und man nicht ständig von Hand die Produkte in einen Frachter transferieren will. Eine detaillierte Beschreibung des Script und dem Grund hinter diesem Script findet man hier (in Englisch)
Anforderungen
- Eine Kopie der Beispielscripte von Frag-Warez.org
- Ein XML-Editor wäre praktisch, ist aber kein muss. Reven empfiehlt da den simplen Peter's XML Editor
- Ich selber habe den XMLMind XML Editor, habe aber meine ersten Gehversuche mit X²-Scripting und diesem Tutorial mit dem in X² eingebauten Editor gemacht.
Es sind hauptsächlich 3 Schritte notwendig um ein Script in die Menüs einzuhängen. Als erstes benötigt man natürlich das Script welches man einhängen will. Zweitens braucht man eine XML-Sprachdatei die den Text enthält, den man zum Spiel hinzufügt. Und als drittes und letztes braucht man ein Script welches automatisch von X² aufgerufen wird und das eigentliche Script in den Menübaum einhängt.
1. Schritt
Das eigentliche Script. Da dies kein Tutorial über Scripting allgemein ist werde ich hier nicht wirklich in die Tiefe gehen. Soviel sei aber über Scripting gesagt, das der beste Weg es zu lernen ist, wenn man sich einfach vorhandene Scripte anschaut. Als Anregung wären da die original Egosoft-Scripte. Dazu braucht man den X2Modder von OlisJ um die Egosoft-Scripte auszupacken. Alternativ dazu kann man auch den X² Archiver benutzen. Der kommt nämlich auch ohne das .NET Frameset 1.1 aus. Egosoft war so nett uns ein hübsches XSL-Stylesheet zu überlassen, mit dem man die Scripte einfach per Doppelklick zB. im Internet-Explorer anschauen kann, sobald sie einmal entpackt sind.
2. Schritt
Hier kommen wir zum eigentlichen Kern der Sache. Die meisten Spieltexte für so ziemlich alles, angefangen von Gütern bis zu den Schiffsbeschreibungen und Menükommandos sind in externen XML-Sprachsdateien abgelegt. Diese Dateien sind an 2 Orten anzutreffen: Entweder im "X2\t" Verzeichniss oder innerhalb der Kontainerdateien (die Zip-Dateien entsprechen aber keine Zips sind). Das meiste der bisherigen Spieltexte sind ind den XML-Sprachdateien innerhalb der *.CAT/*.DAT Dateipaare im eigentlichen X² Verzeichniss. Jede Datei innerhalb dieser Kontainer wird wie eine Datei in den "normalen" Unterverzeichnissen von X² behandelt. Man kann mit X2Modder eben diese Kontainer entpacken und schauen was sie so alles enthalten. Wenn X² auf die Version 1.2 gepatcht ist enthält das 03.CAT/03.DAT Dateipaar die aktuellsten XML-Sprachdateien des Spieltextes. Das wären dann die Dateien 440001.XML und 440002.XML. Wenn BurnIt's Trade Command Sofware MK3 installiert wurde dann kann man in "X2\t" die 440003.XML finden. Diese Datei enthält die Texte für dieses neue Script.
Vielleicht hat der aufmerksame Leser bemerkt das ein Muster in den Dateinamen steckt. Die ersten zwei Stellen bezeichnen den Sprachcode; 44 ist Englisch. BurnIt's Erweiterung hat zusätzlich noch eine Datei mit '49' installiert, welche die deutschen Texte enthält. Wenn das neu eingehängte Script in mehreren Sprachen funktionieren soll muss man die XML-Sprachateien für jede Sprache mitliefern. Das mag keine dumme Idee sein, selbst wenn der Text in den anderen Sprachdateien der gleiche ist. Englisch ist da natürlich bevorzugt, da das die meisten Spieler verstehen
Nach dem Sprachcode enthält der Dateiname einfach eine Nummer um die Datei für alle Scripte, die die Datei benötigen, zu identifizieren. Diese Nummer wird benötigt um die den Text einer Sprachdatei von einem Script aus zu laden.
Wenn der Sprachcode und die ID-Nummer zusammengesetzt werden erhalten wir den ganzen Dateinamen "440003.XML".
Viele Leute schreiben Scripte mit Install-Routinen die die eigentliche 440003.XML modifizieren um ihre Texte zu speichern. Das ist der falsche Weg um das zu erreichen. Ich gehe mal davon aus das Sie diesen Weg gewählt haben, weil sie den korrekten Weg wie man Dateien zu X² hinzufügt, nicht kennen. Der ganze Sinn hinter der Möglichkeit mehrere Sprachdateien zu haben ist, das man sich nicht mit anderen (evtl. von anderen Scriptern) angelegten Sprachdateien rumschlagen muss. Man fügt einfach ein neue Datei ein.
Für eine neue Datei muss man sich eine ID raussuchen. Wichtig ist dabei, das die ID nicht in Konflikt mit anderen IDs kommt, die unter Umständen von einem anderen Script oder Mod benutzt werden. Es wird zwar bisher die Anstrengung unternommen dafür eine zentrale Stelle einzurichten, die einem diese IDs zuweist, allerdings ist das bisher noch nicht umgsetzt worden. Bis dahin empfehle Ich die folgende Richtlinie einzuhalten:
- Am besten keine niedrigen IDs verwenden. 440001.XML bis 440003.XML wurden schon von Egosoft belegt. Und man kann ziemlich sicher davon ausgehen das offizielle Egosoft-Erweiterungen, die noch erscheinen werden, noch mehr dieser LowIDs belegen werden.
- Wenn mehrere Scripts von einer Person geschrieben und veröffentlicht werden sollte man dafür nur eine Sprachdatei verwenden. Auf den Punkt gebracht bedeutet das: Man hat nur eine XML-Sprachdatei für ALLE seine Scripte. Wenn man die Scripte veröffentlicht, dann am Besten in 2 Teilen -> die Scripte getrennt von der Sprachdatei. Nach dieser Methode bekommt jeder immer die aktuellste Sprachdatei, die mit all euren veröffentlichen Scripten funktioniert. Obwohl das bedeuten kann, dass in der Sprachdatei ein Text für ein Script vorhanden ist, das diese Person gar nicht nutzt. Obwohl mehr IDs zur Verfügung stehen als in den XML-Sprachdateien benutzt werden wird es über kurz oder lang Konflikte zwischen verschiedenen Scripten geben, die die gleiche ID benutzen. Und genau deshalb wird eine zentrale Verwaltung benötigt.
[ external image ]
In diesem Beispiel verwende Ich "Maintain Product Quantity" für den langen Namen und "MaintainQuant" für den kurzen.
Die Sprachdateien verwenden einen XML "PAGE" Tag um den Text für die verschiedenen Verwendungsmöglichkeiten zu identifizieren. Ein "PAGE" Tag mit einem ID Attribut von 2010 identifiziert den Text für einen langen Namen eines Kommandos, wohingegen 2011 den kurzen Namen des Kommandos identifiziert. Man sollte auch beachten das der "t" Text Tag, mit dem wir den Text bezeichnen ein ID Attribut von 421 (213) hat. Und das es bei beiden die gleiche ID ist, langer Name wir kurzer. Das wird in Schritt 3 wichtig.
Um nur ein Kommando einzuhängen ist das alles was man in der XML-Sprachdatei haben muss.
3. Schritt
Wir haben das Script, das wir für unser neues Kommando benutzen woll, und wir haben die zugehörige XML-Sprachdatei, die für den Text in den Menüs benötigt wird. Jetzt brauchen wir blos noch ein kleines Script, das diese 2 später im Spiel miteinander verknüpft. Und genau dafür benutzt man dann init-Scripte.
Jedes Script das im Dateinamen mit "init" beginnt ist automatisch ein init-Script und wird automatisch bei jedem Start von X² ausgeführt. Es ist absolut wichtig das man damit sehr vorsichtig umgeht. Ein Bug in einem der init-Scripte kann später beträchtliche Konsequenzen haben. Das Beispielscript hierzu hat den Namen "init.cmd.maintprod.xml".
Unser init-Script hat 3 Aufgaben: Es muss die XML-Sprachdatei laden, dem Spiel sagen welcher der Güter mit unserem Script verknüpft ist (Optional -> siehe mein Codebeispiel, wenn das Script immer verfügbar sein soll) und es muss unser Script noch mit einem Kommando verknüft werden und dem Spiel erklären welche Schiffe dieses Kommando verwenden können.
Als erstes wird die XML-Sprachdatei geladen. Der erste Ausdruck im Bespiel dafür ist:
Reven Code:
Code: Select all
load text: id=21
Code: Select all
load text: id=69
Jetzt müssen wir noch unser Script (Beispielscript: "ship.cmd.maintprod") mit einem Kommando vom Spiel verknüpfen. Ein X² "Kommando" ist einfach ein InGame Aktion die man durch die Menüsysteme erreichen kann. Es gibt (offensichtlich) eine ganze Menge vordefinierte InGame-Kommandos in X² -> und alle sind mit Scripten verbunden durch die im Spiel mitgelieferten init-Scripte. Es ist zwar möglich eigene Kommandos zu erstellen, aber das bringt auch wieder einen haufen Aufwand in die ganze Prozedur. Glücklicherweise müssen wir das aber nicht, denn Egosoft war so nett und hat uns 32 Extrakommandos für jeden Typ bereitgestellt. Das sind Kommandos, die noch mit keinem Script verknüpft sind -> der einzige Sinn dahinter ist, das sie von Leuten wie uns benutzt werden um unsere Scripte einzuhängen.
Um einen dieser Kommandos zu benutzen müssen wir dem Spiel erst erklären welches der Güter unser Kommando "enthält". Das bedeutet, was eine Person für ein Upgrade kaufen muss um das Kommando benutzen zu können. In diesem Fall wird die "Trade Command Software MK1" benötigt. So machen wir dem Spiel klar das jedes Schiff, das die "Trade Command Software MK1" eingebaut hat unser neues Kommando benutzen kann. Wie das geht? Nun, die nächtste Codezeile im init-Script will das verdeutlichen:
Reven Code:
Code: Select all
set ship command upgrade: command=COMMAND_TYPE_TRADE_21 upgrade=Trade Command Software MK1
Code: Select all
set ship command upgrade: command=COMMAND_TYPE_NAV_13 upgrade=[TRUE]
Erinnert ihr euch daran wie wir gesagt haben, das der Text ID Tag (412) (213) in der Sprachdatei später wichtig wird? Das ist er nämlich jetzt. ID #421 gehört zum Kommando COMMAND_TYPE_TRADE_21. Die "4" bezieht sich auf die Tradekommandos, die 21 auf die Nummer 21 (von 0 bis 31) aus der Kommandoliste.
ID #213 gehört zum Kommando COMMAND_TYPE_NAV_13. Die "2" bezieht sich auf die Navigationskommandos, die 13 auf die Nummer 13 (von 0 bis 31) aus der Kommandoliste.
Wenn wir zum Beispiel ein Commando zum Spezialmenü hinzufügen wollen, anstatt dem Handelsmenü, müssten wir im ID Tag der Sprachdatei "521" und das Kommando COMMAND_TYPE_SPECIAL_21 verwenden.
- Nav hat ID "2"
- Combat hat ID "3"
- Trade hat ID "4"
- Special hat ID "5"
Reven Code:
Code: Select all
global ship map: set: key=COMMAND_TYPE_TRADE_21, class=Ship, race=Player, script='ship.cmd.maintprod', prio=0
global ship map: ignore: key=COMMAND_TYPE_TRADE_21, class=Big Ship, race=Player
Code: Select all
global ship map: set: key=COMMAND_TYPE_NAV_13, class=Ship, race=Player, script='ship.cmd.maintprod', prio=0
global ship map: ignore: key=COMMAND_TYPE_NAV_13, class=Fight Drone, race=Player
Da dieses Kommando aber recht Nutzlos für ein Schiff der Klasse M6 oder grösser ist (da diese Schiffe sowieso nicht an Fabriken docken können), sagen wir in der zweiten Zeile dass der Verknüpfungsbefehl zwar für alle Schiffe gilt, aber eben nicht bei denen die der Klasse "Big Ships" angehören.
Wir hätten die auch anders machen können, indem wir einfach für jedes Schiff (M5, M4, M3, TS, TL, Goner) einzeln den Befehl ausgeführt hätten. Unsere Variante ist einfach ein wenig kürzer. ber man kann selber völlig frei entscheiden wierum man das ganze macht und was am besten für das eigene Script passt.
Installation
Jetzt haben wir ein Script, eine Sprachdatei für das zugehörige Kommando und haben das Kommando mit dem Script verknüpft. Alles was wir jetzt noch tun müssen ist unser neues Kommando an die passenden Orte kopieren. Die Scripte gehören nach "X2/scripts", die Sprachdatei nach "X2/t". Das wars schon. Wenn alles richtig gemacht wurde sollte man ein Menü wie das Folgende bekommen:
[ external image ]
Anmerkung
Ich habe die Nummer 21 hier zweimal benutzt. Einmal um die ID für die Sprachdatei festzulegen, und einmal um zu bezeichnen um welches Extra Trade Kommando es sich handelt. Das war möglicherweise eine schlechte Wahl und wird wohl bei so manchem etwas Verwirrung stiften. Wer mit dem Unterschied der zwei IDs nicht so ganz klar kommt sollte nochmal ganz sorgfältig den text durchgehen.
Und genau wegen dieser möglichen Fehlerquelle habe ich meine Orangefarbigen IDs noch hinzugefügt. Wer sich mit denen ein bisschen ausseinandersetzt sollte recht schnell auf den Trichter kommen.
Wer Fehler findet solls mir per PM oder hier im Topic mitteilen. Ich märze die dann nach Möglichkeit aus.
Und jetzt wünsche ich allen viel Spass beim ausprobieren ;]
Nemesi$
IV. Vanoblis - Der ScriptDebugger - Anleitung (v1.3 UPDATED)
Allgemeines
Der Debugger ist Bestandteil des Script Editors und ist "nur" Objektbezogen. Das heisst es werden alle Scriptbefehle eines Objektes mitgeloggt. (Hinweis: Will man z.b. nur das Flugscript untersuchen, sollte man die Turretscripte/Kommandos abschalten) Scripte, die auf keinem Ojekt(null) laufen, werden als Globale Scripte bezeichnet. Abhängig davon , auf welchem Objekt (zB einem Schiff) das Script läuft, das man debuggen will, muss man den Script Editor unterschiedlich aufrufen (Aktivierung mit "Thereshallbewings" vorrausgesetzt):
für Objektbezogene Scripte:
bestimmtes Schiffsmenu -> Kommando Konsole (des Schiffs) -> Script Editor
für Globale Scripte:
Main Menü -> Kommando Konsole -> Script Editor
Nun steht unter dem Menüpunkt "Script Debugging:XXX" bei XXX der Name des Objekts, das man debuggen will.
Menupunkte des Debuggers
Der Debugger besteht aus vier Menupunkten.
"Script Debugging:XXX"-Einstellung (XXX entweder "GLOBAL" oder ein Schiffsname),
"Clear Debug Messages" löscht alle Debugging Logs des aktuellen Objekts
"Script Debugger Menu". der eigentliche Debugger (Anzeige der Logs)
sei patch 1.3 neu:
"Global Script Tasks". hiermit kann man laufende globale Scripte beenden (Achtung! - Skripte die auf Stationen laufen können zur Zeit nicht abgebrochen werden!)
Einstellung des Debuggers
Diese Einstellung sollte man festlegen, bevor man das Script startet, das man debuggen will (ich hab mir schon mal bei laufendem Script und "Script Debugging:XXX" Wechsel mein Spiel zerschossen
unter dem Menupunkt :"Script Debugging:XXX" gibt es drei Einstellmöglichkeiten.
1) LOG
2) TRACE
3) OFF - deaktiviert den Debugger
---------------------------------
1) LOG:
Bei "LOG" werden alle Commandos, die im Script aufgerufen werden(sprich jede Zeile die auch wirklich ausgeführt wird) im "Script Debugger Menu" aufgelistet(also mitgeloggt). Das Loggen erfolgt so schnell wie die Befehle im Script von eurem Rechner abgearbeitet werden. Wenn also irgendwo im script zB ein " @ = wait 1000 ms" steht, hält der Loggingvorgang auch 1000 ms an. Rumscrollen geht mittels "Bild hoch/runter". Neue Logs werden einfach unten angehängt, solange man nicht mit "Clear Debug Messages" die Logs löscht(ein Menü höher).
die Logging Einträge haben diese Form (Beispiel):
Code: Select all
-----------Scriptname:Line:Stackdepth:Prio:PID:TaskID:Command--------
!trade.buywarebest.pl:22:0:0:164918987:$amount= This -> ....
!trade.buywarebest.pl:23:0:0:164918987: ...undweiterimcode....
!trade.buywarebest.pl:24:0:0:164918987: ...undweiterimcode....
...
Scriptname : Name des Scripts, was gerade ausführt wird (bei Namenswechsel muss ein ScriptCall stattgefunden haben)
Line : Zeile des Befehls im Script (!ACHTUNG in X2 v1.2 weicht diese Zeilennummerierung von der im Script ab, da hier nur die "ausgeführten Zeilen" durchnummeriert wurden - war vermutlich nicht so gewollt)
Stackdepth : Anzahl der Scripte auf dem Stack des Objekts(jedes Objekt hat seinen eigenen Stack)
Prio : Priorität des Scripts
PID :
TaskID :
Command : Der ausgeführte Befehl im Script
2) TRACE:
Der unterschied zu LOG ist klein aber fein. Im Trace-Modus loggt der Debugger auch wie LOG alle ausgeführten Befehlszeilen im schon oben erklährten Format mit. Nur findet hier das Logging nicht automatisch statt, sondern man muss mit "ENTER" einen "Step" (Schritt)im Code machen. Das Script steht also zu Beginn still und man muss sich mit <ENTER> quasi Schritt für Schritt durch seinen Code "steppen" und nach Fehlern suchen. Die nächste auszuführende Zeile wird zudem noch grün hervorgehoben. Zusätzlich werden im Trace-Modus auch noch die deklarierten Variablen des aktuell laufenden Scripts und deren Inhalt angezeigt. So kann man zB schnell fehlerhafte Belegungen von Variablen finden.
wenn "Script Debugging:XXX" auf TRACE gestellt ist schauts ungefähr so aus:
Code: Select all
-----------Scriptname:Line:Stackdepth:Prio:PID:TaskID:Command----------
!trade.buywarebest.pl:22:0:0:164918987:$amount= This -> ....
!trade.buywarebest.pl:23:0:0:164918987: ...undweiterimcode....
!trade.buywarebest.pl:24:0:0:164918987: ...undweiterimcode....
...
[b]VariableName: Datatype, Value (interger value) [/b]
$amount: DATATYP_NULL,null,(0) <---------- hier stehen deklarierte Variablen und deren Inhalt
...nochmehrvariablen....
...
Objektbezogene Scripte können entweder in die Command Console Menüs eingebunden und somit per Schiffbefehl gestartet werden, oder man startet ein Script mit "r" in der Scriptliste des Script Editors. Beim Starten mit "r" wird sofort nach einem Referenz Objekt, gefragt (Station oder Schiff), also dem Objekt, auf dem das Script nun laufen soll. Wählt man hier "null" , läuft das Script auf keinem Objekt, und wird als "Globales Script" bezeichnet.
Ob ein Script wirklich läuft, kann man sehen, indem man den Namen seines Scripts in der "Script Task Statistik" sucht. Die "Script Task Statistik" findet man auch im Scripteditor - mit der "Bild runter Taste" (also wenn ein Script gestartet wurde, einfach mit ESC ein Menü zurück und dann "Bild runter")
Hat man vor dem Start seines Scripts den Debubber eingeschaltet, werden alle ausgeführten Scriptbefehle des Objekts im "Script Debugger Menu" mitgeloggt.
Beenden kann man Objektgebundene Scripte durch Zuweisen eines neuen Befehls in der "Kommando Console" des Objekts(Schiffs). Skripte die auf Stationen laufen können zur Zeit nicht abgebrochen werden!
Global laufende Scripte kann man mit dem (seit patch 1.3) neuen "Global Script Tasks" Menüpunkt im Script Editor beenden. Einfach das zu beendende Script in der Liste raussuchen und mit <DEL> entfernen.
Damit müssten eigentlich die gröbsten Unklarheiten bezgl. des Script Debuggers beseitigt sein. Sicherlich lassen sich damit viele Programmierfehler aufspüren
Ich hoffe es hilft jemandem weiter...
Vanoblis
Debugmodi in Scripten von Metuelisator
Gerade bei grösseren Scripts ist die Fehlersuche nicht immer einfach.
Solange man an einem Script arbeitet kann man mit Zwischenmeldungen von wichtigen Variablen einen möglichen Fehler schneller finden.
also weist man seinem Script zu Anfang ein Argument "debugmode" vor, unter Eingabe "Number", string debugmode.
Beim starten des Scripts gibt man "0" fur debugmode aus, "1" für debugmode ein an.
Im Script selbst kann dann an beliebig vielen Stellen
Code: Select all
if $debugmode = 1
write to playerlogbook $wichtigeVariable1
write to playerlogbook $nochwichtigereVariable2
usw....
end
Ist nicht komplett auf meinem Mist gewachsen, bin in der Handel MK3 über was ähnliches gestolpert.
-
- Posts: 231
- Joined: Thu, 11. Mar 04, 12:00
Vorwort
Ich gebe verwandte Kommandos möglichst mit Referenznummer zur Befehlsübersicht http://www.egosoft.com/x2/forum/viewtopic.php?t=29054 an.
Alle Beispiele, Lösungsansätze etc sind stets als nur eine Möglichkeit zur Problemlösung anzusehen und stellen nicht das Ultimativ-Perfekte dar.
Mein Dank (alphabetisch) an dieser Stelle für Bugreport und Verbesserungen an:
ArcaJeth[D6a]
BurnIt!
Mr.Gee
Orka
ticaki
Vanoblis
X.0 Allgemeine Programmiertipps
Bevor man ans Umsetzen geht, sollte man erstmal niederschreiben/skizzieren, was - wer - wann - wo - mit wem - wie oft machen soll. Damit hat man schonmal eine Grobgliederung zur Hand und verzettelt sich bei der Umsetzung nicht so leicht. Mit etwas Übung kann man aus der Grobgliederung eine Feingliederung ableiten und hat bereits alle benötigten Elemente aufgeführt. Dann muss man nur noch die zugehörigen Befehle zusammensuchen.
X.1 Grundelemente
X.1.0 Ausgabe
Damit man überhaupt sehen kann, was passiert (also zB welche Werte an welchen Stellen auftreten), benötigt man eine Form der Ausgabe. X² stellt zB die Funktion "3.001 write to player logbook <Value>".
Also erstmal solch ein Script zum laufen Bringen:
->Scripteditor-><New Script>->Namen eingeben
->New Line->Enter->Logbook Commands->write to player logbook
-><STRING> auswählen und "Hallo Welt" (oder was auch immer) eingeben
->ESC->Speichern JA
->mittels "r" ausführen->NULL auswählen (dies gibt an wer das Script ausführen soll,
NULL=global, Schiff oder Station -kann auch NavSat oder Turret sein-)
->dann im Logbuch nachsehen, wenns funktioniert steht hier jetzt der Text
X.1.1 Variable
Damit man Werte/Texte/Objekte weiterverarbeiten kann, müssen sie irgendwo gespeichert werden, damit man dieses "Irgendwo" wiederfindet bekommen diese Speicherplätze Namen.
Laut Lehrbuch sind Variable Platzhalter bestehend aus Name, Typ und Inhalt zB. testtext='Hallo Welt', Typ wäre hierbei <STRING>
Ergänzen wir unser obiges Beispiel wie folgt:
-> Zeile mittels "Einfg" einfügen->Enter->General Commands->1.001 <RetVar/IF><Expression>
->Enter-><VARIABLE>->Name zB Outtext->Enter
das <?> wieder mittels Enter auswählen-><String>->"Wieder Hallo" eingeben
jetzt auf unsere "write to player ..." Zeile navigieren und Enter
->Outtext auswählen->Enter
Das Script müsste jetzt so aussehen:
Code: Select all
001 $Outtext = 'Wieder Hallo'
002 write to player logbook $Outtext
Der Typ heißt korrekterweise Datentyp und bestimmt in welcher Form die zu speichernden Informationen vorliegen, grundsätzlich sind die unterschiedlichen Typen nicht miteinander zu mischen. X² kennt jede Menge vorbestimmter Typen, die einfachsten sind <STRING> und <NUMBER>. <STRING> wie zuvor verwandt, speichert Text und <NUMBER> Zahlenwerte. Es können aber auch komplexe Dinge wie <Objects> (zB Schiffe mit all Ihren Daten und Ausrüstungen) hinterlegt, abgefragt und verändert werden. Dazu ein anderes mal mehr.
Zeit für ein weiteres Beispiel, ich denke die Eingabeschritte spar ich mir fortan, die Systematik ist ja trivial. Ich kommentiere die Zeilen/Fkten im Quellcode.
Code: Select all
001 $Werta = 30
002 $Wertb = 12
(bei Beiden ist der Typ <Number>)
003 $summe = $Werta + $Wertb
004 write to player logbook $summe
(so einfach geht das Rechnen mit Variablen :) )
005 $summe = $summe + $Werta
(unlogisch ? nicht für den Compi, er addiert einfach $Werta zur $summe und speichert das
Ergebnis wieder in $summe)
006 write to player logbook $summe
Möchte man eine Aktion (also einzelne Befehle oder Befehlsblöcke) mehrfach ausführen,
bietet es sich an dies mit einer Schleife zu realisieren. Ausgangsbasis ist die Funktion
1.001 <RetVar/IF><Expression> diesmal mit der Unterfunktion "while". Die Anzahl der
Durchläufe wird in einer hochzählenden Zählvariablen festgehalten.
(engl. while = dt. solange)
Code: Select all
001 $zaehler = 0
(Startwert ist unabdingbar, sonst gehts früher oder später schief)
002 while $zaehler < 5
(die Schleife soll also 5 mal durchlaufen werden von 0 bis 4)
003 write to player logbook 'X2 ist cool'
004 write to player logbook $zaehler
005 inc zaehler
(1.002 inc <RetVar> = erhöht den zaehler um 1, dieser muss erhöht werden, sonst befinden
wir uns in einer Endlosschleife. Es geht natürlich auch 005 $zaehler = $zaehler + 1)
006 end
(1.1.001 end conditional dient stets zum beenden eines Blocks, hier der While-Schleife)
Wollen wir das etwas in Abhängig von etwas anderem geschieht, hilft uns wiedereinmal
1.001 <RetVar/IF><Expression> weiter, wobei wir diesmal die Unterfunktion "if" benötigen.
Code: Select all
001 $Werta = 5
002 $Wertb = 7
003 if $Wertb > $Werta
004 write to player logbook 'b groesser a'
005 end
006 if $Werta > $Wertb
007 write to player logbook 'a groesser b'
008 end
009 if $Werta == $Wertb
010 write to player logbook 'a ist gleich b'
011 end
Interessanter wirds, wenn wir uns für $Werta und $Wertb Information aus dem Spiel nehmen.
Nach dem Ausführen mit "r" diesmal das Schiff als auszuführende Plattform heranziehen.
Code: Select all
001 $Werta = 0
002 $Wertb = 100
003 $Werta = THIS-> get free volume of cargo bay
(5.1.008 <RetVar/IF> <RefObj> get free volume of cargo bay
gibt uns den freien Laderaum der Plattform von dem dieses Script ausgeführt wird.)
004 if $Wertb > $Werta
005 write to player logbook 'Nicht mehr viel Platz im Laderaum'
006 end
007 if $Werta > $Wertb
008 write to player logbook 'Noch genuegend Platz zum shoppen'
009 end
Code: Select all
Arguments
1: schiff , Var/Ship , 'schiff'
001
002 wdh:
003 $missile2kill = $schiff -> find nearest missile aiming to me
004 $verfuegbare = $schiff -> get current missile
005 = $schiff -> fire missile $verfuegbare on $missile2kill
006 @ = wait randomly from 2000 to 3000 ms
007 goto label wdh
008
009
010 return null
Diesem Script wird mit dem Argument 1: übergeben welches Schiff sich verteidigen soll.
Praktischerweise kann es zB auf einer Station ausgeführt werden, damit ein Schiff sich
verteidigt. So ist es möglich mehrere Scripte gleichzeitig für ein Schiff arbeiten zu
lassen.
Code: Select all
002 das Label "wdh" damit das Skript endlos durchlaufen werden kann
003 in $missile2kill wird die nächste Rakete die auf das $schiff zielt abgelegt
004 die derzeit ausgewählte oder nächstbest-verfügbare Rakete des $schiff holen
005 das $schiff feuert seine Rakete vom Typ $verfuegbar auf die Angreifende
006 damit nicht alle Raketen nacheinander abgeschossen werden, gibts hier eine kleine
Zufallspause von 2-3 Sekunden
007 Springe zum Label
X.2.0 Formatierte Ausgabe von ArcaJeth[D6a]
Um die Logbuchnachrichten/incoming+blackboard messages etwas besser zu gestalten oder einfach nur übersichtlicher zu machen gibt es verschiedene Möglichkeiten.
Hier einmal 2 Bilder mit allem was mir so einfiel *g*
http://www.x2map.de.vu/X2Format-1.jpg
http://www.x2map.de.vu/X2Format-2.jpg
Bild 1:
Code: Select all
[author]hier könnte Ihr Name stehen[/author][title]Formatierungsbeispiele[/title]Hallo,\ndas ist ein normaler Text. Aber man kann auch viele bunte Farben hinein bringen:\n\033Agrau\033X \033Bblau\033X \033Ccyan\033X \033Ggrün\033X \033Mmagenta\033X \033Rrot\033X \033Wweiss\033X \033Ygelb\033X\nEbenfalls kann man einen Text [u]unterstreichen[/u].\n[center]Und sogar zentrierte[/center]\n[right]oder rechtsbündige Textpassagen sind möglich :-\)[/right]
[title] Formatierungsbeispiele [/title]: der Titel der Nachricht - wird zentriert und unterstrichen
Farben werden mit \033 und einem Buchstaben eingeleitet, dabei gilt:
A = Grau, B = Blau, C = Cyan, G = Grün, M = Magenta, R = Rot, W = Weiss, Y = Gelb und X beendet die Farbformatierung
[center] Text [/center]: zentiriert den Text
[right] Text [/right]: stellt den Text rechtsbündig dar
Bestimmte Zeichen werden innerhalb der Sprach-XMLs ignoriert - so zum Beispiel die Klammern ( ) und deren Inhalt. Um sie dennoch zu nutzen muss man einen Backslash \ davor setzen. Also \( und \)
Mit \n erzeugt man einen Zeilenumbruch.
Bild 2:
Code: Select all
[title]Text im Blocksatz und etwas eingeengt[/title][text colwidth='500'][justify]Deaktivieren Sie jede Art [..] die ständig im Hintergrund läuft.[/justify][/text]
Code: Select all
[title]Text in 2 Spalten[/title][text cols="2"][/text][justify]Deaktivieren Sie jede Art [..] die ständig im Hintergrund läuft.[/justify][/text]
Code: Select all
[title]Text in 3 Spalten und höherem Spaltenabstand[/title][text cols="3" colspacing='50'][justify]Deaktivieren Sie jede Art [..] die ständig im Hintergrund läuft.[/justify][/text]
X.2.1 Arrays
Vielseitig, mächtig und empfindlich im Umgang ist das erste was mir im Bezug auf Arrays
einfällt. Arrays sind im normalen Sprachgebrauch Listen, wobei eine Liste immer nur
Daten eines einzigen Datentyps aufnehmen kann. Die einzelnen Zellen der Liste werden
über ihren Index angesprochen. Eine der Besonderheiten, was immer wieder für
Schwierigkeiten sorgt, ist der Umstand das der Index bei Arrays bei 0 beginnt. Dh. der
erste Inhalt liegt im Folgenden bei $liste[0].
Code: Select all
001 $zaehler = 0
002 $anzahl = 0
003 $liste = array alloc: size=0
004 $liste = THIS get formation follower ships
005 $anzahl = size of array $liste
006 while $zaehler < $anzahl
007 $folgeschiff = $liste[$zaehler]
008 write to player logbook $folgeschiff
009 end
003 Fkt 1.3.001 legt im Speicher ein Array mit 0 Elementen an
004 Fkt 4.019 liefert eine Tabelle der Schiffe, die einem Führungsschiff folgen
005 Fkt 1.3.004 gibt einem die Anzahl der Elemente des Arrays zurück
006 Fkt 1.3.002 hier erhalten wir einen Eintrag aus dem Array mit dem Index $zaehler
beliebig viele Werte mit einem Namen greif und vor allem verarbeitbar zu machen.
X.2.2 Gültigkeitsbereich/Sichtbarkeit von Variablen
X2 kennt insgesamt 3 unterschiedliche Sichtbarkeitsvarianten, Script, Lokale (funktionieren
noch nicht korrekt in V1.3) und Globale-Variable (seit V1.3 sind leider noch nicht in der
Befehls-Übersicht).
Alle bisherigen verwandten Variablen sind immer nur innerhalb des jeweiligen Scripts gültig.
Ist auch naheliegend, schließlich soll ein Script gleichzeitig mehrfach ausgeführt werden
können, ohne das sich die einzelnen Abläufe gegenseitig beeinflussen. Ich nenne diese
Script-Variable.
Dank an ArcaJeth[D6a] für die Ausführung zu Lokalen-Variablen
Lokale-Variable, sind an das Objekt gebunden und können mit Bezug auf das jeweilige Objekt
abgefragt und gesetzt werden. So ist es möglich zB bei Bau einer Station mit der Ausführung
des folgenden 2-Zeilers seine Bauzeit zu speichern.
Code: Select all
001 $Time = get playtime
002 $Station -> set locale variable: name='Time' value=$Time
Später kann dies von einem beliebigen Script aus abgefragt werden:
001 $Time = $Station -> get local variable: name='Time'
002 write to player logbook $Time
oder um rauszufinden wie lange die Station besteht:
001 $Time.now = get playtime
002 $Time = $Station -> get local variable: name='Time'
003 $Time.diff = $Time - $Time.now
004 write to player logbook: printf: fmt='%s %s', $Station, $Time.diff, null, null, null
Folgende Beispiel zeigt nur die Systematik, da ich nur V1.2 im Einsatz habe.
Script1:
Code: Select all
001 $wert = 10
002 set global variable : name='globvar', value=$wert
003 while $wert > 0
004 $wert = get global variable : name='globvar'
005 write to player logbook $wert
006 @ = wait 2000 ms
007 end
Code: Select all
001 $wert = 0
002 $wert = get global variable : name='globvar'
003 while $wert > 0
004 $wert = get global variable : name='globvar'
005 dec $wert =
006 set global variable : name='globvar', value=$wert
007 @ = wait 5000 ms
008 end
Das Logbuch füllt sich mit Einträgen von 10 an runter auf 1, wobei Werte mehrfach vorkommen,
da die Pausen im Script2 deutlich größer sind als in Script1.
Unter Global Commands ganz unten aufgeführt:
set global variable : name=<String>, value=<Value>
<Retvar/value> get global variable : name=<String>
X.2.3 erweiterte Schleifen
Gerade wenn man Überwachungs-oder generell Endlosfunktionen in X2 einbauen will, benötigt
man Endlosschleifen. Doch wie beendet man solche Scripte, besonders wenn sie global, also
auf NULL ausgeführt werden ? Wie immer gibt es hierzu mehrere Möglichkeiten.
Code: Select all
001 $raus=0
002 while $raus == 0
tu irgend etwas
004 $raus = Ergebnis einer Funktion/Abfrage/Wasauchimmer
005 end
004 Die Schleife beendet sich also, wenn $raus durch diese Zeile != 0 wird
001 $raus=get global variable : name='globvar'
002 while $raus == 0
tu irgend etwas
004 $raus=get global variable : name='globvar'
005 end
004 Diese Schleife endet also, wenn ein anderes Script die 'globvar' != 0 setzt
001 $raus=0
001 $globalraus=get global variable : name='globvar'
002 while $raus == 0 AND $globalraus == 0
tu irgend etwas
004 $raus = Ergebnis einer Funktion/Abfrage/Wasauchimmer
005 $globalraus=get global variable : name='globvar'
006 end
sein, damit die while-Schleife ausgeführt wird. Wird $raus oder $globalraus
!= (ungleich) 0 , ists aus mit dem While-Zauber.
Achja, eine hätte ich beinahe vergessen:
Code: Select all
001 $raus=0
002 $raus2=0
003 while $raus == 0
004 tu irgend etwas
005 if $raus2 != 0
006 break
007 end
008 end
X.2.4 erweiterte Bedingungen
Code: Select all
001 $Werta = 5
002 $Wertb = 7
003 if $Wertb > $Werta
004 write to player logbook 'b groesser a'
005 else if $Werta > $Wertb
007 write to player logbook 'a groesser b'
008 else if $Werta == $Wertb
010 write to player logbook 'a ist gleich b'
011 end
den Einsparungseffekt bewundern kann. Dennoch gibt es einen Unterschied in der
Funktionsweise beider Beispiele, denn bei der "else if" Kombination wird der nachfolgende
"else if"-Zweig nur auf Gültigkeit überprüft, wenn alle vorangegangenen ungültig waren.
Dh. hier, wenn $wertb > $werta wird nicht mehr überprüft ob $werta > $wertb oder
$werta == $wertb ist. Nicht schlimm möchte man meinen, doch was geschieht wenn zuerst
$wertb > $werta ist und anstelle unserer Zeile 004 "004 $werta = $werta * 2". Dann
kommt es garnicht zur Ausführung von Zeile 007, da die Überprüfung in 005 nicht mehr
durchgeführt wird.
=> Hier ist besondere Vorsicht geboten.
IF THEN ELSE - WENN DANN SONST
Code: Select all
001 $kontakta=Khaak
002 $beziehung='nix'
003 $beziehung = PLAYERSHIP get notoriery to race $kontakta
004 if $beziehung == FEIND
005 write to player logbook 'Das hab ich mir gedacht'
006 else
007 write to player logbook 'Das wundert mich aber'
008 end
003 6.026 <RetVar/IF> <RefObj> get notoriery to race <Var/Race>
X.3. Scripte miteinander verbinden / Unterscripte
X.3.1 Teile und Herrsche - Scripte aufteilen
Bislang haben wir unsere Funktionen immer in ein Script integriert, doch mit der Zeit
wachsen unsere Wünsche und Anforderungen. Hier eine neue Funktion, dort eine kleine
Erweiterung, mein Ehrenwort irgendwann wird es richtig unübersichtlich (eine Gegenmassnahme
gibts in 4.4). Zudem gibt es einige Funktionen, die man in unterschiedlichen Scripten
oder sogar demselben Script immer wieder benötigt und Copy&Paste von Blöcken über
Scriptgrenzen hinweg gibt der (ansonsten gute) Scripteditor nicht her.
Die Lösung besteht im Aufteilen von funktionalen Scriptblöcken und dem Auslagern in weitere
Scriptdateien. Der Aufruf von anderen Scripten erfolgt mit der Funktion:
-----Ergänzung von Mr.Gee-------
Wird
(1.2.001) @ <RetVar/IF/START> <RefObj> call script <Script Name>:<Parameter>
ohne Variable aufgerufen als z.B
@ =[This] -> call sript '!ship.cmd.attack.std' : the victim=$target do not follow in new sector=[false]
Wartet das aktuelle script bis der call befehl bzw. das aufgerufene script beendet wurde.
Wird hingegen START vorne angestellt z. B
@ START [This] -> call sript '!ship.cmd.attack.std' : the victim=$target do not follow in new sector=[false]
wird in diesem Beispiel das script !ship.cmd.attack.std gestartet, jedoch läuft das aktuelle script weiter ohne auf eine Rückmeldung zu warten.
Ergänzung von mkess:
Es ist noch ein bischen kniffliger. wenn das Script starten auf einem anderen Object ausgeführt wird, dann beendet sich das rein ge-call-te script, wenn das Aufrufscript endet.
Es ist also unerlässlich, bei den Start eines scriptes auf fremden Objektes ein START voranzustellen, damit es auch nach beenden des "anwerfscriptes" noch weiterlaufen soll. (wer hat da gesagt, scripten ist einfach )
-------------------------------
Wenn man Kapitel 0 berücksichtigt hat, fällt eine sinnvolle Aufteilung viel
leichter. Daher hier ein Konzept mit (noch nicht guter) Umsetzung.
Die Idee:
AutoPatrol über ausgewählte Sektoren zur Sicherung meiner Transporter
Grobgliederung:
-Sektoren auf Feinde scannen
-Gegner gefunden ?
-Gegner bekämpfen bis Friede
-Weitersuchen
Feingliederung:
a) Sektoren per Eingabe abfragen
b) Sektoren zu einem Array zusammenfügen
c) Ein Sektor auswählen
d) Sektor überprüfen <- hier erkennt man das diese Fkt mehrfach benötigt wird
e) Wer ist überhaupt der Feind <-Feinderkennung oft benötigt, wäre also auch praktisch
f) Feind im Sektor suchen
g) Gefunden ?
h) Ja: Hinspringen, EZ Auffüllen wenn benötigt, Angreifen
Springen und Auffüllen sind ebenfalls vielseitig => ???
i) Nein: such im nächsten Sektor
Umsetzung:
Code: Select all
a)
Arguments
1: PatrolSektor1 , Var/Sector , 'PatrolSektor1'
2: PatrolSektor2 , Var/Sector , 'PatrolSektor2'
3: PatrolSektor3 , Var/Sector , 'PatrolSektor3'
4: PatrolSektor4 , Var/Sector , 'PatrolSektor4'
b)
001 write to player logbook 'Patrol-Script-neu-gestartet'
002 $PatrolSektors = array alloc: size=0
003 $i = 0
004 append $PatrolSektor1 to array $PatrolSektors
005 if $PatrolSektor2 != null
006 append $PatrolSektor2 to array $PatrolSektors
007 end
008 if $PatrolSektor3 != null
009 append $PatrolSektor3 to array $PatrolSektors
010 end
011 if $PatrolSektor4 != null
012 append $PatrolSektor4 to array $PatrolSektors
013 end
026 $anzahl = size of array $PatrolSektors
c+i)
029 while $i < $anzahl
030 $aktuellersektor = $PatrolSektors[$i]
031 @ = [THIS] -> call script 'jk.cmd.patrol2' : Bitte Sektor eingeben=$aktuellersektor
032 inc $i =
033 end
d) durch Zeile 031 gestartet
g)
049 while $gegner != null
050 if $anzahl > 0
051 $aktuellersektor = [THIS] -> get sector
052 if $aktuellersektor != $sekt
053 @ = [THIS] -> call script 'jk.cmd.jump' : Schiff=[THIS] Sprungziel=$sekt
064 end
065 @ = [THIS] -> call script '!fight.attack.object' : the victim=$gegner follow in new sector=[FALSE]
066 end
067 *write to player logbook 'Einer Hinne'
068 $gegner = [THIS] -> find nearest enemy ship: max.dist=9999999
069 end
h)
002 $menge = $schiff -> needed jump drive energy for jump to sector $Ziel
003 $ez = $schiff -> get volume of ware Energiezellen in cargo bay
004 if $ez < $menge
005 @ = [THIS] -> call script 'jk.cmd.refill' : schiff=$schiff
006 end
007 = $schiff -> use jump drive: target=$Ziel
X.3.2 Übergabe- und Rückgabe-Parameter
Durch das Aufteilen unseres Scripts in mehrere Einzelne, haben wir allerdings ein Problem,
denn unsere Variable sind alles Script-Variable (vgl. Kapitel 1.1) und somit nur im
jeweiligen Script verwendtbar. Einer der gegebenen Auswege stellen Übergabe und
Rückgabeparameter dar. Mit diesen können wir Werte an ein Script übergeben und von ihm
zurückerhalten. Aufrufparameter werden in den "Arguments" festgelegt und Rückgabeparameter
per "return" zurückgegeben, beim "return" nur ein einzelner Wert (kann auch ein
Objekt oder Array).
script1:
Code: Select all
001 $werta = 7
002 $wertb = 0
003 @ $wertb = [THIS] -> call script 'script2' : wert=$werta
004 write to player logbook $wertb
Code: Select all
Arguments
1: wert , Var , 'Rechenwert'
001 $wert = $wert * $wert
002 return $wert
X.3.3 präventive Fehlerbehandlung
In den vorangegangenen Beispielen haben wir sie kaun genutzt obwohl sie in der Befehlsliste
mehr als reichlich vorhanden sind. Die Rede ist von den <RetValue>, sie liefern uns nicht nur
ab und an die gewünschten Ergebnisse sondern stets auch Informationen ob das Kommando wie
gewünscht ausgeführt wurde. Es liegt an uns diese zusätzlichen Rückgabewerte auszuwerten und
somit Fehler rechtzeitig abzufangen.
So liefert die Funktion:
5.003 <RetVar/IF> <RefObj> add <Var/Number> units of <Var/Ware>
die tatsächliche Anzahl der hinzugefügten Ware zurück.
Ein Code sagt mehr als 1000 Worte
Code: Select all
001 $anzahl = 0
002 $menge = 0
003 $preis = get max price of ware Energiezelle
004 $kosten = 0
005 $negkosten = 0
006 $anzahl = THIS add 99999 units of Energiezelle
007 $kosten = $anzahl * $preis + 1000
008 $negkosten = - $kosten
009 add money to player: $negkosten
5.014 <RetVar> = get max price of ware <Var/Ware>
um diese "einfache" Einkaufsvariante zu rechtfertigen, bezahlen wir den Max-Preis der Ware
zzgl eines kleinen Lieferbonus von 1000Cr
5.002 add money to player: <Var/Number>
Fügt dem Spielerkonto Geld hinzu, damit etwas abgezogen wird, drehen wir die $kosten zu
$negkosten um
Doch dies ist nur ein Teil der Fehlerprävention, der Andere besteht darin, zu überprüfen ob
die Werte die man an andere Scripte/Funktionen/Schleifen/Abfragen übergibt, auch im erwarteten
Rahmen liegen.
Erweitertes Beispiel:
Code: Select all
$anzahl = 0
$menge = 0
$preis = 0
$kosten = 0
$preis = get max price of ware Energiezelle
$anzahl = THIS add 99999 units of Energiezelle
if $anzahl != NULL AND $preis != NULL
$kosten = $anzahl * $preis + 1000
$negkosten = - $kosten
add money to player: $negkosten
end
Somit hätten wir auf einen Schlag überprüft ob überhaupt ein Preis ermittelt und Ware geladen
wurde.
Code: Select all
001 $rueck find ship: sector=TRANTOR class or type=MOVEABLE race=Khaak flags=NULL refobj=NULL maxdist=NULL maxnum=9999 refpos=NULL
002 if $rueck != NULL
003 $jumprueck = THIS use jump drive: target=TRANTOR
004 if $jumprueck != NULL
005 write to player logbook 'Sprung erfolgt'
006 else
007 write to player logbook 'Etwas stimmt nicht...'
008 end
009 end
6.066 <RetVar/IF> find ship: sector=<Var/Sector> class or type=<Value> race=<Var/Race>
flags=<Var/Number> refobj=<Value> maxdist=<Var/Number> maxnum=<Var/Number> refpos=<Var/Array>
stimmen die Aufrufparameter dieser Funktion nicht, kommt nur NULL raus. Ansonsten ein ganzes
Array.
4.068 <RetVar/IF> <RefObj> use jump drive: target=<Value>
springt wenn möglich mit dem <RefObj> ans Ziel <value>
X.4 Form und Stil von Scripten
[Anmerkung: Bei Form+Stil scheiden sich die Geister, aber egal welcher Linie man folgt
hauptsache man folgt einer konsequent.]
Daher möchte ich hier nur einige wenige Tipps zur besseren Gestaltung von Programmcode geben.
X.4.1 Namenskonvention für Dateinamen
Bei X2 bietet es sich förmlich an, die Konvention von Egosoft zu übernehmen bzw. leicht zu
erweitern. Dies führt zu der einfachen Form:
{init.}autorkürzel.Ziel.{Typ.}name.xml
{}=muss nicht kann aber
init = wenn es beim Spielstart gestartet werden soll
Typ = cmd, bc (=battle-command), trade ...
Ziel = ship, turret, station, global, universal
X.4.2 Variable initialisieren und Namenskonvention ungarische Notation
Einen leichteren Überblick über die im Script verwandten Variablen erhält man, indem man sie
alle zu beginn bereits zB mit 0 als Wert anlegt. Dies hilft gleichzeitig Fehler zu vermeiden.
Dies läßt sich auch leicht in meinen Beispielen ersehen. Es ist definitiv in X2 nicht notwendig,
aber praktisch, denn hat man sie einmal eingegeben, kann man sie jederzeit im Script mit der
Auswahlbox auswählen.
Was ist die Ungarische Notation? von www.bytelords.de
Die ungarische Notation ist eine Konvention zur Benennung von Variablen. Sie hat in C und C++, vor allem unter Windows weite Verbreitung gefunden. Ungarisch deshalb, weil der Vater dieser Notation, Charles Simonyi, ein gebürtiger Ungar ist.
Namenskonventionen sollen die Lesbarkeit von Programmen erhöhen. Gerade, wenn Programme im Team entwickelt werden, ist die Standardisierung von Bezeichnungen sehr wichtig. Aber auch für die Wartung und die Verständlichkeit von Programmen ist es vorteilhaft, sich an bestimmte Regeln zu halten.
Der Aufbau des Variablennamens besteht bei der ungarischen Notation aus: Präfix und Bezeichner. Als Bezeichner sollte man einen aussagekräftigen Namen benutzen, die durchaus aus mehreren Teilworten bestehen sollen. Besteht der Bezeichner aus mehreren Teilworten, werden die einzelnen Teilworte jeweils mit einem Großbuchstaben begonnen z.B. SchleifenZaehleroder FehlerTextMain.
Ergänzt wird der Bezeichner durch den Präfix, der anzeigt, welchen Datentyp die Variable besitzt. Präfixe sind dem Bezeichner vorangestellt und werden immer klein geschrieben. Es ist möglich, mehrere Präfixe zu kombinieren, um zusammengesetzte Datentypen zu kennzeichnen, wie beispielsweise einen Zeiger auf eine int-Variable.
Folgende Tabelle enthält die wichtigsten Prefixe: (angepaßt für X2)
Code: Select all
Datentyp Präfix Beispiel
globale Variable g gVariable
lokale Variable l lPosition
script Variable sc scZaehler
Feld (Array) a aiFeld
Number/Int(Ganzzahl) i iNummer
Float f fGehalt
string(Zeichenkette) sz szString
Ware w wEnergiez
Kommando co coSuche
Signal si siAlarm
Rasse r rFreund
Objekt o oSchiff
Da testet und schreib man schön ein Script nach dem anderen und alles funktioniert soweit. Mit
der Zeit sammeln sich immer mehr eigene, aber auch Fremde Scripte an. Eine gewisse Zeit weiß
man selbst WAS man WO in welchem Script angestellt hat, aber woher wissen bei der Weitergabe
eigener Scripte andere Scripter dies. Und was ist wenn diese Verweilzeit des Wissens im Hirn
abgelaufen ist ? Ansehen und reinfuchsen in alte Arbeiten ist zeitintensiv und nervig.
In X2 lassen sich Kommentare nur bedingt gut einfügen, daher sollte die Beschreibung nicht nut
zur Anwendung, sondern auch zur Funktionsweise in der obligatorischen ReadMe ausführlicher sein.
im Code:
- Zu Beginn jeder Funktion eine kurze-Kurzbeschreibung
- Wichtige Zeile im Code kommentieren
in der ReadMe:
- Anwendung des Scripts
- Funktionen beschreiben, optimalerweise mit Aufruf und Rückgabeparameter
- Danksagungen
- Kontaktmöglichkeit
X.5 Objekte
X.5.1 exists&get&set
X.6 Mathematik und Logik im Script
X.6.1 Mathematische und Logische Ausdrücke von ArcaJeth[D6a]
Für Berechnungen, Vergleiche, If-Abfragen und While-Schleifen steht in X2 der Befehl
1.001 <RetVar/IF><Expression> zur Verfügung. Hier einige Ausdrücke die mit selbigem
genutzt werden können.
Code: Select all
== - für (if-)Vergleiche -> 'ist gleich'
!= - für (if-)Vergleiche -> 'ist nicht (gleich)'
> - für (if-)Vergleiche -> 'ist größer als'
< - für (if-)Vergleiche -> 'ist kleines als'
>= - für (if-)Vergleiche -> 'ist größer oder gleich'
<= - für (if-)Vergleiche -> 'ist kleiner oder gleich'
& - Binär 'und'
| - Binär 'nicht'
^ - Binär 'exklusiv und'
AND - zum verbinden von Voraussetzungen ('if a AND b') -> beide müssen wahr sein
OR - zum verbinden von Voraussetzungen ('if a OR b') -> eins muss wahr sein
+ - Grundrechenart Addition
- - Grundrechenart Subtraktion
* - Grundrechenart Multiplikation
/ - Grundrechenart Division
mod - Modulo -> Rest der Division (13 mod 4 = 1 ... 13 / 4 = 3 Rest 1)
[ - Klammer auf
] - Klammer zu
~ - Addiert eins zum Wert und nimmt *-1 zB ~5 => -6
! - Negierer zB TRUE<->FALSE
-to be continued-
Anregungen, Kritik und Verbesserungen wie immer allerherzlichst an mich:
jk@cinso.de
-
- Posts: 231
- Joined: Thu, 11. Mar 04, 12:00
a) Flugblock und Andockcheck von mkess
Code: Select all
init:
...
startloop:
....
Landinwhatever:
skip if DOCKEDAT == $targetstation
@ THIS-> !move.movetostation Station: $targetstation
if DOCKEDAT == $targetstation
.... Aktionen innerhalb der Station.
if not ..... --- Preis nicht in ordnung, Kram nicht zu bekommen, oder was auch immer
$targetstation = find:station ........ neue Station suchen.
skip if not $targetstation
goto Landinwhatever: -- zur neuen Station
goto exceptions:
end;
@ wait randomly 1000 to 5000 ms
end;
dothenextthing:
....
goto startloop:
return null
exceptions:
...
fehlerbehandlung
return FALSE;
!move.movetostation sollte man deswegen verwenden, weil damit relativ sichergestellt ist, da auch wirklich anzukommen.
Dadurch, das man das Movetostation( flytostation, !move.Jumptostation) mit in dem Ladeblock unterbringt, braucht man nur , wenn in der Station was nicht stimmt, eine neue Station finden, und wenn man eine gefunden hat, einfach nur zum label "Landinwhatever:" springen.
Exceptions sollte man auslagern. Eventuell kann man sie in weiteren Modulen gebrauchen. So wie man das übrigens mit allen immer wieder vorkommenden Programmteilen tun sollte (Sektorcheck, Refuelling, usw)
Dadurch kann man zum Beispiel eine "refueling" Routine bis zum Äußersten verbessern, und alle Scripte, die sie verwenden profitieren direkt davon.
b) Wurzel+Potenzfunktion von von ArcaJeth[D6a]
Wurzelfunktion:
Code: Select all
Arguments
1: Zahl , Var/Number , 'Zahl'
001 $Ergebnis = 1
002 while 1
003 $Ergebnis.alt = ( $Ergebnis + ( $Zahl / $Ergebnis ) ) / 2
004 if $Ergebnis.alt == $Ergebnis
005 return $Ergebnis.alt
006 else
007 $Ergebnis = $Ergebnis.alt
008 end
009 end
010 return null
Die Potenzfunktion sieht so aus: b^e also Basis hoch Exponent
=>
Code: Select all
Arguments:
basis, <Number>, Basis
exponent, <Number>, Exponent
i = 1
erg = basis
if exponent = 0
return 1
else if exponent = 1
return basis
end
while i < exponent
erg = erg * basis
inc i
end
return erg
c) Alle Schiffe/Stationen im Universum auflisten
von ticaki
Code: Select all
001 $ym = get max sectors in y direction
002 $xm = get max sectors in x direction
003 $x = 0
004 while $x < $xm
005 $y = 0
006 while $y < $ym
007 $Sector = get sector from universe index: x=$x, y=$y
008 $race = Player
009 $List = find ship: sector=$Sector class or type=Ship race=$race flags=[Find.Multiple] refobj=null maxdist=9999999 maxnum=99999 refpos=null
010 $high = size of array $List
011 $a = 0
012 while $a < $high
013 $Station = $List[$a]
014 $dummy = $Station -> install 1 units of BPH-Erweiterungskit MK1
015 skip if not $Station -> get amount of ware BPH-Erweiterungskit MK1 in cargo bay
016 @ START $Station -> call script 'TiCaKi.BPHE.Command.Standard' :
017 inc $a =
018 end
019 inc $y =
020 end
021 inc $x =
022 end
023 return null
von ArcaJeth[D6a]
Code: Select all
001 * Station.list - Array das am Ende wieder uebergeben wird
002 $Stations.list = array alloc: size=0
003 $Universe.maxX = get max sectors in x direction
004 $Universe.maxY = get max sectors in y direction
005
006 * Schleifen zum Durchlaufen aller Sektoren
007 $Universe.y = 0
008 while $Universe.y < $Universe.maxY
009 $Universe.x = 0
010 while $Universe.x < $Universe.maxX
011
012 * Pruefen ob Sektor bei Universe.x, Universe.y existriert
013 $Universe.sector = get sector from universe index: x=$Universe.x, y=$Universe.y
014 if $Universe.sector != null
015 * Sektor existiert - alle Stationen suchen
016 $Stations.result = find station: sector=$Universe.sector class or type=null race=$par.race flags=[Find.Multiple] refobj=null maxdist=null maxnum=1000 refpos=null
017 $Stations.result.size = size of array $Stations.result
018 * Gefundene Stationen an Stations.list anhaengen
019 $tmp.i = 0
020 while $tmp.i < $Stations.result.size
021 $Stations.result.tmp = $Stations.result[$tmp.i]
022 append $Stations.result.tmp to array $Stations.list
023 inc $tmp.i =
024 end
025
026 end
027
028 inc $Universe.x =
029 end
030 inc $Universe.y =
031 end
032 return $Stations.list
d) Inhalte von Arrays ausgeben von SpaceTycoon
Man möchte gerne mal die Inhalte eines Arrays wissen.
Folgendes Script trägt in das Logbuch den Inhalt des Arrays ein ("null" im Log bedeutet dabei dann: der Indexwert hat keinen Inhalt):
Code: Select all
Script help.objektarrays.anzeigen
Version: 1
for Script Engine Version: 24
Description
Inhalte von ArrayVariablen ins Log
Arguments
1: ARRAY , Value , 'ArrayVariable'
Source Text
001
002 $Spaces = ' '
003 $Size = size of array $ARRAY
004 $counter1 = 0
005 while $counter1 < $Size
006 $Value = $ARRAY[$counter1]
007 $TempStore = $Value + $Spaces
008 skip if $Message == null
009 $Message = $Message + $TempStore
010 skip if $Message != null
011 $Message = $TempStore
012 inc $counter1 =
013 end
014 send incoming message $Message to player: display it=[TRUE]
015 return null
Ich erzeuge folgendes Array:
Code: Select all
008 $GateN = $sector -> get north warp gate
009 $GateS = $sector -> get south warp gate
010 $GateE = $sector -> get east warp gate
011 $GateW = $sector -> get west warp gate
012 $AllGates = array alloc: size=4
013 insert $GateN into array $AllGates at index 0
014 insert $GateS into array $AllGates at index 1
015 insert $GateE into array $AllGates at index 2
016 insert $GateW into array $AllGates at index 3
Innerhalb eines Scripts das obige Hilfsscript wie folgt aufrufen:
Code: Select all
@ = [THIS] -> call script help.objektarrays.anzeigen' : ArrayVariable angeben=$AllGates
---------Zur weiteren Verwendung------------
1.016 <RefObj> connect ship command/signal <Object Command/Signal> to script <Script Name> with prio <Var/Number>
1.016 <RefObj> connect ship command/signal x to script y with prio 10
für x zB "unterattack", dann wird bei einem Angriff das Script y ausgeführt
-
- Posts: 231
- Joined: Thu, 11. Mar 04, 12:00
... die ganzen Waren sind in Maintypes Kategorisiert
8 Waffen
9 Schilde
10 Raketen
11 Waren Stufe 0 (Energiezellen)
12 Waren mit denen man nicht handeln kann es aber wahrscheinlich in SB-Missionen gibt
13 Waren Stufe 1 (benötigen Stufe 0 zur Herstellung)
14 Waren Stufe 2 (Benötigen 0 & 1)
15 Mineralien
16 Erweiterungen aber auch z.B. Kristalle, Quantumröhren ...
... ab Maintype 16 Subtype 11 sind nur die Erweiterungen die man in ein Schiff einbauen kann
... wie gewünscht hier mal die Liste der Waren, geordnet nach Main & Subtype
Code: Select all
Maintype Subtype Ware
8 0 Alpha Impulsstrahlen-Emitter
8 1 Beta Impulsstrahlen-Emitter
8 2 Gamma Impulsstrahlen-Emitter
8 3 Alpha Partikelbeschleunigerkanone
8 4 Beta Partikelbeschleunigerkanone
8 5 Gamma Partikelbeschleunigerkanone
8 6 Alpha Energieplasma-Werfer
8 7 Beta Energieplasma-Werfer
8 8 Gamma Energieplasma-Werfer
8 9 Alpha Schockwellen Generator
8 10 Beta Schockwellen Generator
8 11 Gamma Schockwellen Generator
8 12 Mobiles Bohrsystem
8 13 Unbekanntes Objekt
8 14 Unbekanntes Objekt
8 15 Unbekanntes Objekt
8 16 Projektilkanone
8 17 Ionen-Disruptor
8 18 Alpha Photonenimpulskanone
8 19 Beta Photonenimpulskanone
8 20 Gamma Photonenimpulskanone
8 21 Geschützturmlaser
8 22 Gamma Kyonen Emitter
8 23 Unbekanntes Objekt
9 0 1 MW Schild
9 1 5 MW Schild
9 2 25 MW Schild
9 3 125 MW Schild
10 0 Moskito
10 1 Wespe
10 2 Libelle
10 3 Hummel
10 4 Hornisse
10 5 Unbekanntes Objekt
10 7 Unbekanntes Objekt
11 0 Energiezellen
12 0 Wasser
12 1 Artefakte
12 2 Kunstdünger
12 3 Mikroorganismen
12 4 Kartographie-Chips
12 5 Bauausrüstung
12 6 Antriebselemente
12 7 Unterhaltungs-Chips
12 8 Nahrungsmittelrationen
12 9 Militärische Handfeuerwaffen
12 10 Luxus-Nahrungsmittel
12 11 Medizinische Ausrüstung
12 12 Bergbau-Ausrüstung
12 13 Nividium
12 14 Radioaktiver Abfall
12 15 Teladianiumplatten
12 16 Waffenkopplungs-Chip
12 17 Drogen
12 18 Nervenimplantate
12 19 Raumfliegeneier
12 20 Handfeuerwaffen der Piraten
12 21 Hackerchips
12 22 Militärisches Personal
12 23 Passagiere
12 24 Prominente Persönlichkeiten
13 0 Delexianischer Weizen
13 1 Argnufleisch
13 2 Plankton
13 3 BoGas
13 4 Scruffinknollen
13 5 Cheltfleisch
13 6 Sojabohnen
13 7 Maja Schnecken
13 8 Sonnenblumen
13 9 Teladianium
13 10 Sumpfpflanzen
14 0 Stoff-Rheime
14 1 Cahoona Fleischblöcke
14 2 Raumsprit
14 3 Stott-Gewürze
14 4 BoFu
14 5 Massom-Puder
14 6 Rastar-Öl
14 7 Majaglit
14 8 Sojagrütze
14 9 Nostropöl
14 10 Raumkraut
15 0 Erz
15 1 Siliziumscheiben
15 2 Nividium
16 0 Gefechtsköpfe
16 1 Kristalle
16 2 Quantumröhren
16 3 Mikrochips
16 4 Computerkomponenten
16 5 Raumfliegen
16 6 Sklaven
16 7 Navigationssatellit
16 8 SQUASH Mine
16 9 Geschützturm
16 10 Kampfdrohne
16 11 Bergungsversicherung
16 13 Frachtscanner
16 14 Handelscomputer Erweiterung
16 16 Laderaumerweiterung
16 17 Triebwerkstuning
16 18 Ruder-Optimierung
16 19 Landecomputer
16 20 Ziel Projektions Erweiterung
16 22 Digitales Sichtverbesserungssystem
16 23 Singularitäts Zeitverzerrungsantrieb
16 24 SINZA Boost Erweiterung
16 25 Ekliptik Projektor
16 26 Argon Polizeilizenz
16 27 Boron Polizeilizenz
16 28 Split Polizeilizenz
16 29 Paraniden Polizeilizenz
16 30 Teladi Polizeilizenz
16 31 Datenspeicher
16 32 Schnäppchen Finder
16 33 Verkaufspreis Finder
16 34 Transporter
16 35 Sprungantrieb
16 39 Lebenserhaltung für Frachtraum
16 40 Boost Erweiterung
16 41 Steuerdüsenerweiterung
16 43 Kameradrohne
16 44 Erweiterter Satellit
16 45 Mineralien Kollektor
16 46 Tarnvorrichtung
16 49 Raumfliegen Fangvorrichtung
16 50 Projektilkanone Munition
16 51 Duplex Scanner
16 52 Triplex Scanner
16 53 Navigationssoftware MK1
16 54 Handelssoftware MK1
16 55 Handelssoftware MK2
16 56 Kampfsoftware MK1
16 57 Kampfsoftware MK2
16 58 Spezialsoftware MK1
16 71 Handelssoftware MK3
Beispiel, wie man mit den Maintypes und Subtypes umgeht/umgehen kann...
Wenn ich ein Produkt mit der Liste aller Produkte abgleichen will, gibt es dafür nichts. Ich muß mir aus den Main- und Subtypes erst eine Produktliste 'basteln', die ich dann für Vergleichsoperationen heranziehen kann:
Code: Select all
010 * Figure out all products, write into array
011 $AllProducts = array alloc: size=0
012 $No.Maintype = 17
013 while $No.Maintype > 8
014 dec $No.Maintype =
015 $No.Subtype = get number of subtypes of maintype $No.Maintype
016 while $No.Subtype > 0
017 dec $No.Subtype =
018 $Product = get ware from maintype $No.Maintype and subtype $No.Subtype
019 skip if $Product == null
020 append $Product to array $AllProducts
021 end
022 end
-
- Posts: 231
- Joined: Thu, 11. Mar 04, 12:00
... farblich gehts nur wenn du das über eine Sprach-XML machst ...
Mit "\033R Text \033X" bekommst du den Text dann rot.
\033 + Farbcode:
B -> Blau
C -> Cyan
G -> Grün
M -> Magenta
R -> Rot
W -> Weiss
Y -> Geld
X -> Standard (bzw. Farbformat löschen)
PS: ohne XML ginge es sicher auch wenn man den \ in einen String bekommen könnte
sci wrote:Jeder der ein zusätzliches Ausrüstungsobjekt per script einbinden will muss dazu ein "Read-Text-Object" benutzen. Naja und ohne Modding muss man sich eines mit dem, für die neue Erweiterung passenden, Preis aussuchen. Damit ihr euch nicht dumm und dämlich sucht, hier als ganz ganz ganz kleine hilfe: die preislister in der version 1.3
Bitte die bereits durch bestimmte scripts belegten Objekte beachten!
Weitere infos dazu: http://www.egosoft.com/x2/forum/viewtopic.php?t=33680
...
392 = ReadText-17-5773
476 = ReadText-17-5763
1.572 = ReadText-17-5783
2.472 = ReadText-17-5793
7.944 = ReadText-17-5803
10.027 = ReadText-17-5813 GothicK *SDS Delivery*
38.996 = ReadText-17-5823 ticaki *?*
95.344 = ReadText-17-5833
118.336 = ReadText-17-5843
158.204 = ReadText-17-5853
995.124 = ReadText-17-5883 Mr.Milti *Return to Sender*
1.002.676 = ReadText-17-5753
1.845.524 = ReadText-17-5863 sci *Kampfsoftware MK3*
6.338.116 = ReadText-17-5913
9.110.824 = ReadText-17-5893
17.926.236 = ReadText-17-5903
54.228.224 = ReadText-17-5923
62.022.316 = ReadText-17-5933
188.877.700 = ReadText-17-5943
-
- Posts: 231
- Joined: Thu, 11. Mar 04, 12:00
...
ich bin nach langer Suche drauf gekommen, wie die Sprachausgabe (und parallele Textausgabe unten rechts im Bildschirm) bei Stationswaren funktioniert.
Anmerkung:
@Alle Autoren der Beiträge die das Einbinden von Scripten und Sprachdateien erklärten, sollten vielleicht Ihre Beiträge ergänzen/ändern.
Und so sieht das aus:
Bisher ist in allen Tutorials zu lesen, man solle die Sprachdateien 49xxxx.xml/44xxxx.xml im Verzeichnis \t so aufbauen (Beispiel für eine Schiffsausrüstung für 1572 Credits in einem Ausrüstungsdock):
Code: Select all
- <language id="49">
- <page id="17" title="Boardcomp. objects" descr="Produktname">
<t id="5793">Irgendeine neue Schiffsausrüstung</t>
</page>
Im Abschnitt Page ID 17 dieser Datei ist dort jede Ware aufgeführt, die in irgendeiner Fabrik zu kaufen ist. Einmal mit ihrer Bezeichnung, so wie man sie in der Fabrik/Dock in der Liste sieht und darunter mit nächst höherer Nummer steht der Text, welcher bei Markierung der Ware in Dock oder Fabrik vorgelesen wird und rechts unten erscheint.
Insofern: Wenn obiger Code in einer eigenen 49xxxx.xml wie folgt ergänzt wird:
Code: Select all
- <language id="49">
- <page id="17" title="Boardcomp. objects" descr="Produktname">
<t id="5793">Irgendeine neue Schiffsausrüstung</t>
<t id="5794">{17,5665}</t>
</page>
Code: Select all
<t id="5665">Dies ist eine Softwareerweiterung für alle gängigen Schiffscomputer Modelle. Erweiterte Kommandos werden durch ihre Installation der Kommandokonsole eines Schiffs hinzugefügt.</t>
<t id="5794">{17,5665}</t>
die Nummer {17,9002} eintragen, käme in der Fabrik bei Markierung der Ware zum Beispiel der Text und die Sprachausgabe
Code: Select all
<t id="9002">Über dieses Objekt sind in der Datenbank des Bordcomputers keine Daten verfügbar.</t>
Die obige Nummer 5794 gibt es übrigens im ganzen X2-Programm nicht. Ich hab sie einfach "erfunden". Da in der originalen "490001.xml" der Sprachtext immer eine Nummer höher ist als die Nummer der Warenbezeichnung, habe ich das in der eigenen Sprachdatei (sh. obiges Beispiel) einfach mal genauso gemacht - und siehe da - es klappt. Das heißt, alle freien Artikelnummern von 17-57xx bis 17-59xx können mit einer vorhandenen Sprachausgabe aus der 490001.xml belegt werden, wenn man dafür einfach so vorgeht wie oben zu sehen.
-------------------------------
Und vielleicht noch zur Ergänzung, wie man passend zur üblichen "Verhaltensweise" von X2 einen Logbucheintrag gestalten sollte:
Code: Select all
001 play sample 1008
002 *Spielt das "Jingle" vor/bei Ansage "Eingehende Nachricht"
003 wait 500
004 * etwas Warten schadet bei Audiosachen nie sonst überschlägt sichs
005
006 play sample: incoming transmission [IncomingTransmission.Message], from object null
007 * Spricht eine von vier möglichen Sprachausgaben, die unter den
008 * Systemkonstanten (Select Constant - "Incoming..." aufgeführt sind
009 * in diesem Fall: "Eingehende Nachricht"
010
011 $nachricht = sprintf: pageid={DeineID} textid={DeineID}, [THIS], [ENVIRONMENT], null, null, null
012 * Die Nachricht, die aus Deinem Sprachfile 49xxxx.xml gelesen wird
013
014 send incoming message $nachricht to player: display it=[TRUE]
015 * Eintrag ins Log und gleichzeitige Anzeige
Um die Sache komplett zu machen, hier die Textzeile, die in obiger Codezeile 11 aus der Sprachdatei im \t-Verzeichnis gelesen wird:
Code: Select all
<t id="1001">[author] Schiff [b]%s[/b][/author][text colwidth='500'][b]Ziel %s erreicht![/b] ...gehe in Bereitschaft...[/text]</t>
Ergänzung von ArcaJeth[D6a]
... dazu braucht man eigentlich auch nur das "send incoming message $nachricht to player: display it=[FLASE]" ... da kommt das "Palingpaling ... Eingehende Nachricht" und auch das kleine Symbol blinkt ... mit "display it=[TRUE]" kommt zwar keine akustische Meldung jedoch sieht man das jaSo läuft eine Lognachricht von einem Schiff an den Player genauso ab, wie es im Programm normal und üblich ist (abgesehen von der sofortigen Anzeige "display it=True").
Tinte/Toner sparen von SpaceTycoon
Hier hab ich dann noch ne' Kleinigkeit:
Wen hat es nicht schon angek***t wieviel Tinte/Toner durch den Ausdruck eines Scriptes verbraucht wird?
Daher hier noch eine geänderte x2script.xsl mit der das DRUCKEN von Scripten mehr Freude macht:
X2script.xsl zum Drucken von Scripten
Handhabung:
Die originale x2script.xsl im Ordner Scripts umbenennen. Dann diese Datei hineinkopieren. Man kann sie auch dauerhaft verwenden, hat keinen Einfluß auf das Scripten oder die Spielfunktion. Und man kann endlich Scripte auch ohne Horrorverbrauch an Tinte/Toner ausdrucken.
-
- Posts: 4861
- Joined: Wed, 6. Nov 02, 20:31
-
- Posts: 17833
- Joined: Sat, 6. Mar 04, 16:38