Das Scripting im TRNG

  • Das Scripting im TRNG

    Inhaltsverzeichnis

    eingestellt von Raymond

    Das Scripting im TRNG


    Allgemeines


    Für Das Scripting im TRNG gibt es ein eigenes Programm, das man benutzen muss! Im Scripter-Zip sind drei Dateien entalten. Die entpackt man und dann einfach auf Setup klicken. Die Dateien werden dann im NG_Scripter innerhalb des Programme-Ordner auf dem Computer installiert. Dann geht man in den NG_Scripter-Ordner und klickt auf NG_Center. Beim ersten mal wird man anfangs noch nach dem Ort des trle-Hauptordners gefragt, damit das Programm automatisch die Skriptdateien finden kann.

    Die Programmoberfläche des NG_Centers


    So sieht die Programmoberfläche dann aus:


    Oben findet man fünf Auswahlmöglichkeiten. Script öffnet die script.txt zur Bearbeitung (siehe oben). Strings öffnet die english (german ,...).txt. IM Reference fenster findet man eine sehr gute Dokumentation aller Skriptkommandos. Im Settingsfenster kann man den Ort des trle-Hauptordners ändern. Im Toolsfenster findet man ein Programm zur Überwachung von Animationen. Dazu kann ich leider nicht viel sagen.

    Das Scriptfenster

    Man bearbeitet hier die scripteinträge wie in einer Textbearbeitung. Mit dem Feld Save wird gesichert und mit dem Feld Build wird die script.dat erstellt. dabei wird automatisch auch gesichert. Mit Find kann man im Text nach Wörtern usw. suchen lassen.
    Im grünen Feld unten werden die Fehler beim Konvertieren angezeigt. Die Fehler kann man sich mit Show Errors auch als Textdatei ausgeben lassen.

    Das Stringsfenster

    [

    Hier bearbeitet man die english(german,..).txt. Den String, den man ändern möchte anklicken und dann kann man ihn im Textfeld unten ändern und unten auf Update klicken. Die Dateien werden konvertiert, wenn man im Scriptfenster auf Build klickt.

    Das Referenzfenster

    [

    Hier findet man umfangreiche Dokumentationen zu verschiedenen Bereichen. Die Bereiche können oben aus dem Menü ausgewählt werden:
    1. Script new commands
    Hier sind die ganzen neuen Scriptkommandos beschrieben. Man klickt auf das Scriptkommando, das man erläutert haben möchte und bekommt unten im kleinen grünen Feld die nformation angezeigt. Man kann sich diese Information aber auch ausführlich in einem eigenen Textfenster anzeigen lassen, in dem man auf Expand Info klickt. Mit Output list in text file wird die Info als eine txt-Datei im NG_Scripter Ordner hinterlegt. Mit Copy name in Clipboard kann man sich das Kommando in die Zwischenablage speichern und dann in sein Script einfügen. In den anderen Bereichen funktioniert das analog.
    2. Mnemonic Constants
    Hier werden die ganzen Teilbestandteile der neuen Scriptkommandos erläutert. Wenn hier was zu finden ist, wird vom obigen Erläuterungen hierher verwiesen. Man kann drei verschiedene Werte von diesen Indexlisten in die Scriptkommandos übertragen: einen dezimalen Zahlenwert, einen hexadezimalen Zahlenwert und einen Textwert. Mit Copy Value in Clipboard wird der dezimale Wert in der Zwischenablage gespeichert.
    3. Es gibt auch einen Extrabereich für die alten Scriptkommandos (Script old commands)
    4. OCB list: eine Liste aller OCB-Werte
    5. Damage Enemy list gibt wichtige Informationen für die Anpassung von Feinden, die beim Enemy-Scriptkommando gebraucht werden
    6. Keybord Scancodes list, Slot Moveable-, Slot Statics- und Sound SFX indices lists: Hier findet man Indexlisten für Tastaturtasten, Moveable- und Static slots und die Sound SFX- Dateien. Man kann drei verschiedene Werte von diesen Indexlisten in die Scriptkommandos übertragen: einen dezimalen Zahlenwert, einen hexadezimalen Zahlenwert und einen Textwert. Mit Copy Value in Clipboard wird der dezimale Wert in der Zwischenablage gespeichert.

    Die Grundstruktur von Scriptkommandos (Syntax)


    Die Grundstruktur kennt man ja schon vom alten script: Scriptkommando= Wert, ....,.....,..... ; Kommentare zur Dokumentation
    Je nach verwendeten Scriptkommando kann der Wertebereich kürzer oder ziemlich lang werden.

    Beispiel Triggergroup
    TriggerGroup=1,$2000, 89, $12 (siehe vorangeganges Kapitel)
    Die allgmeine Syntax für das Kommando ist: TriggerGroup= IdGroup, ExportValue1 + TGROUP_ flags, ExportValue2, ExportValue3, Other Values 1/2/3 of exported triggers or conditions.
    Der erste Werte ist also die ID des Triggergroupkommandos. Dann folgen Dreiergruppen mit den Werten für die exportierten Trigger (siehe auch vorhergehendes Kapitel). Wenn wir in einer Gruppe sieben Trigger hätten, dann hätten wir also insgesamt 1+7*3=22 durch Kommas abgetrennte Werte dazustehen. Die Parametertrigger mit den Bedingungen stehen immer vor den anderen triggern.
    Bei einem Parametertrigger können zu dem ersten Zahlenwert mit einem Plus noch ein Flag (TGROUP_) hinzufügen. Dieser Flag kann z.B. ein logischer Operator sein: and, or , not, else. Ohne einen solchen Operator werden alle Bedingungen in den Parametertriggern abgefragt. Wenn alle erfüllt sind, werden die nachfolgenden Trigger ausgelöst. Durch den Operator wird die Abfrage modifiziert.
    Beispiele: A sei ein Parametertrigger mit der Bedingung 1, B sei ein Trigger mit der Bedingung 2 , C sei ein beliebiger Actiontrigger:
    C soll ausgeführt werden, wenn einer der beiden Bedingungen erfült ist:
    Triggergroup=1, A1, A2,A3,B1+TGROUP_OR,B2,B3,C1,C2,C3
    C soll ausgeführt werden, wenn die Bedingung A nicht erfüllt ist und die Bedingung B erfült ist
    Triggergroup=1, A1+TGROUP_NOT, A2,A3,B1,B2,B3,C1,C2,C3

    Stellen wir uns mal folgende praktische Situation am Ende einer Levelserie vor. Wir wollen den Zugriff zum Bonuslevel von den gefundenen Secrets abhängig machen:
    Wenn der Spieler weniger als 10 Secrets gefunden hat, dann Einblendung: Du Looser! Gehe durch Tür 1 und die Serie ist zu Ende (Es gibt eine Gruppe von Flippeffekttriggern, die Texteinblendungen ermöglichen.)! Tür 1 wird geöffnet. Spieler hat 10-19 Secrets gefunden: Ganz gut, geht aber noch besser! Geh durch Tür 2 und du kannst ein Teil des Bonuslevels spielen.Tür 2 wird geöffnet.
    Der Spieler hat mindestens 20 Secrets: Du bist ein Champion! Gehe durch Tür 3 und spiele das Bonuslevel! Tür 3 wird geöffnet.
    Trigger A- Parametertrigger mit der Bedingung, dass Lara mindestens 10 Secrets hat
    Trigger B- Parametertrigger mit der Bedingung, dass Lara mindestens 20 Secrets hat
    Trigger C, D bzw. E für die Texteinblendungen 1,2 bzw, 3.
    Trigger F,G bzw. H für die Öffnung der Türen 1,2 bzw. 3.
    Dann sieht die Triggergruppe so aus (ohne Gewähr):
    Triggergroup= 2,A1+TGroup_NOT, A2,A3,C1,C2,C3,F1,F2,F3, A1+TRGROUP_ELSE,A2,A3,B1+TRGROUP_NOT,B2,B3,D1,D2,D3,G1,G2,G3,B1+TRGROUP_ELSE,B2,B3,E1,E2,E3,H1,H2,H3
    Wenn also der ELSE-Operator benutzt wird, sieht die Syntax ein bisschen anders aus. Jeder Else-Operator bezieht sich auf einen eigenen Triggerblock: also erster Triggerblock mit Bedingungen und auszuführenden Triggern, dann Bedingung mit dem Else-Operator und weiteren Bedingungen und auszuführenden Triggern usw..
    Ich habe so etwas bis jetzt noch nicht ausgetestet, aber damit kann man offensichtlich großartige Sachen anstellen.


    Beispiel Parameters
    Parameters=PARAM_ROTATE_ITEM, 2,FROT_LOOP,103,ROTH_CLOCKWISE,IGNORE,$180,IGNORE,IGNORE,IGNORE,IGNORE,IGNORE
    Sieht kompliziert aus, ist aber halb so wild! Zur Erinnerung: das Parameters-Kommando gibt Werte an verschiedene Flipeffekttrigger weiter (z.B. Move Moveable). Mit der Zuhilfenahme der Referenz entschlüsselt sich alles.
    Die allgemeine Syntax des Kommandor ist: Parameters= Type of parameters (PARAM_...), IdParameterList, parameter array.
    Den ersten Wert findet man bei den Mnemonic constants in der Referenz. Wir hätten da drei zur Verfügung, die die Art der Bewegung/Färbung festlegen: Param_Move_Item-geradlinige Bewegung, Param_Rotate_Item-Rotation des Objekts, Param_Color_Item-Färbung.
    Der zweite Wert ist die ID des Parameterkommandos. Diese ID wird an entsprechender Stelle in den Flipeffekttrigger eingetragen.
    An dritter Stelle kommt das Parameterarray, das je nach gewählten Parameterart aus verschiedenen Werten besteht. Die Details findet man wieder in der Referenz bei den Mnemonic Constants. Bei Param_Rotate_Item sieht das Parameterkommando dann folgendermaßen aus: Parameters=PARAM_ROTATE_ITEM, IdParamList, FlagsRotation (FROT_), ItemIndex, DirHRotation (ROTH_...), HRotationAngle, SpeedHRotation, DirVRotation (ROTV_..), VRotationAngle, SpeedVRotation, MovingSound, FinalSound
    Im Parameterarry ab dritten Wert stehen dann also insgesamt 10 Werte. Im ersten dieser Werte steht ein sogenanntes Flag (Zeichen), das Grundeigenschaften der Bewegung festlegt. Unter FROT findet man die entsprechenden Möglichkeiten. In unserem Beispiel ist es FROT_LOOP. Die Bewegung erfolgt also in einer kontinuierlichen Schleife, d.h. das Objekt rotiert also so lange, bis es wieder antitriggert wird. Im nächsten Wert tragen wir den Indexwert des Objekts ein (Das ist die gelbe Zahl, wenn man im Editor mit der rechten Maustaste auf das Objekt klickt.) Mit dem nächsten Wert wird die Richtung der horizontalen Rotation festgelegt. im unseren Fall erfolgt sie im Uhrzeigersinn (clockwise). Dann wird der horizontale Rotationswinkel (angle) eingetragen. Bei einem Loop wird hier kein speziller wert eingetragen und sobald das an irgendeiner Stelle in einem Kommando so ist, muß man IGNORE hinschreiben. Soll nur eine einmalige Rotation erfolgen kann man die einzutragenden hexadezimalen Werte in der Referenz sehen. Im nächsten Feld wird dann die Rotationgeschwindigkeit. Wie bei allen Werten kann man den Wert dezimal oder hexadezimal eintragen, wobei die hexadezimale hin-und wieder recht vorteilhaft ist. Hexadezimale Werte müssen mit einem Dollarzeichen anfangen (wie z.B. bei uns $180). Komplexer wird die Sache, wenn wir keine Rotationsschleife haben, denn dann muss der Wert für den Winkel durch den Geschwindigkeitswert teilbar sein. In den nächsten drei Feldern folgen analog die Werte für die vertikale Rotation (bei uns gibt es dreimal IGNORE, weil wir keine vertikale Rotation haben wollen). In den beiden letzten Feldern werden der Bewegung Sounds zugewiesen. Im vorletzten Feld kommt die Sound SFX ID für einen Sound während der Rotation und im letzten Feld kommt die Sound SFX ID für einen Sound am Ende der Rotation. In unserem Beispiel verwenden wir keine Sounds.

    Beispiel Animations
    Animation= 456, KEY1_ACTION+KEY1_JUMP+KEY1_DOWN,IGNORE, FAN_SET_FREE_HANDS, ENV_CLIMB_WALL_IN_FRONT, IGNORE, IGNORE,-164; ladder to monkey
    Die allgemeine Syntax des Kommandos ist: Animation=AnimIndex, KEY1_ , KEY2_ , FAN_ flags, ENV_ Environment, Distance for Env, Extra, StateId or AnimationId array (...).
    Mit dem obenstehenden Animationskommando soll Lara in der Lage sein, von einer Leiter an eine Hangelstrecke zu springen.
    In ersten Feld steht die Animationnummer, die Lara ausführen soll. Das ist bei mir die Animation 456. Ich benutze eine Animation, die von Jesse erstellt wurde und auf trsearch.org verfügbar ist. Bei dieser Animation springt Lara mit einer 180 Grad-Drehung.
    In den folgenden beiden Feldern stehen die Tasten, die gedrückt werden müssen, damit diese animation ausgeführt wird. Die Actiontaste ist an der Leiter so und so gedrückt. Jump habe ich gewählt, weil das ein Sprung ist. Down habe ich gewählt, um noch weiter zu unterscheiden, weil ich in meinem Level verschiedene Sprünge an der Leiter habe. Da ist ja schon mal der Standardsprung, der im Spiel normalerweise mit Action und Jump funktioniert. Dann habe ich noch einen Aufwärtssprung, der mit Action+Jump+Up funtioniert. Inmienem Fall werden die Tasten alle im ersten von beiden Feldern festgelegt. IM zweiten Feld können noch bestimmte andere Tasten festgelgt werde, was bei mir nicht gebraucht wird. Im nächsten Feld können Flags gesetzt werden. Mit FAN_SET_FREE_HANDS bestimme iich, das Laras Hände fei sind und somit greifen können. das kann eben eine Hangelstrecke sein, die sich direkt über Lara befindet, aber in meinem Fall durchaus auch ein Jumpswitch oder eine Kante sein kann, die in bestimmter Höhe und Entfernung liegen müssen.
    Im nächsten Feld werden bestimmte Umgebungsbedingungen festgelegt, die erfüllt sein müssen, damit diese Animation gestartet wird. Ich denke, dass ich die von mir verwendete Bedingung gar nicht setzen müsste, da Lara bei Ausführung der Animation so und so an einer Leiter hängt (siehe Erläuterung für das letzte Feld!) , aber sie hat jedenfalls auch nicht geschadet.
    Das nächste Feld bezieht sich auf das vorhergehende. Hier wird die Distanz zu Lara festgelgt, in der die Umgebungsbedingung zutrifft. Für genaueres siehe bei ENV_ in der Mnemonic constants-Liste in der Referenz.
    Man kann auch mehrere Umgebungsbedingungen bestimmen. Wenn bei keiner Bedingung etwas im Distanzefeld festgelegt werden muß, dann kann man diese einfach mit + verbinden.
    Bsp.2: Animation= 421, KEY1_JUMP, IGNORE, FAN_SET_NEUTRAL_STATE_ID, ENV_POS_HORTOGONAL + ENV_HOLE_FLOOR_IN_FRONT + ENV_POS_STRIP_1, IGNORE, IGNORE, 80; crawlspace exit- Rolle aus dem Kriechgang heraus
    Wenn man mehrere Bedingungen hat, die Werte im Distanzfeld erfordern, dann muss man dafür ein neues kommando MultEnvCond verwenden und im Animationskommando bei den Umgebungsbedingungen ENV_MULTI_CONDITIONS eintragen und im Distanzfeld die ID des MultiEnvCond-Kommandos.
    Bsp.3: Animation=218, IGNORE, KEY2_DASH, FAN_KEEP_NEXT_STATEID, ENV_MULT_CONDITION, 3, IGNORE, -222, -353, -354 ;roll in crawlspace-Kriechgangrolle
    MultEnvCondition= 3 ,ENV_NO_BLOCK_IN_FRONT, 256, IGNORE, ENV_NON_TRUE + ENV_HOLE_FLOOR_IN_FRONT, 512, IGNORE

    Im vorletzten Feld können noch Werte in Verbindung mit bestimmten Fan-Flags bestimmt werden.
    Im letzten Feld werden dann die Animationen eingetragen, von wo aus die Animation gestartet wirdoder die StateID, die Lara gerade haben muß. Vor die Animationsnummern muß ein Minuszeichen. Im ersten Beispiel startet die Animation von Animation 164. In zweiten feld von StateID 80 (Lara in Kriechposition auf den Knien). Im dritten Beispiel sind mehrere Animationen als Ausgangspunkt festgelegt. Übrigens kann man die Scriptkommandos für Beispiel zwei und drei einfach in jedes andere Script übernehmen, weil alle Animationen (in der Regel) in Lara´s Standardanimationen enthalten sind.

    Wie man sieht, braucht man einiges Grundwissen zu Lara´s Animationen und StateID´s , sowie über die verfügbaren Umgebungsbedingungen and Fan-Flags. Außerdem gehört noch eine gehörige Portion Experimentierfreude dazu. Dann kann man eine ganze Menge verrückter Sachen mit Laras Animationen anstellen. Mit Hilfe des Animationskommandos haben Titak und ich es geschafft, auch alle TREP-Moves mit dem TRNG zu ermöglichen. In meinem Script habe ich außerdem Jesses Leiteranimationen mit einer viel übersichtlicheren Struktur von Tastenbelegungen versehen und sie außerdem noch viel spezifischer auf die gewünschte Umgebung festgelegt.

    Diese drei Beispiele für Scriptkommandos sollten vermitteln, wie der Syntax von Scriptkommandos aufgebaut ist. Mit Hilfe der Referenz im NG_Center sollte die Syntax anderer Kommandos gut verstehbar sein.
    Im letzten Kapitel möchte ich einen groben Überblick über die Vielzahl der Scriptkommandos und der damit verbundenen neuen Möglichkeiten geben.


    Eine Übersicht der neuen Scriptkommando


    Hier soll es eine grobe Übersicht über die verfügbaren Scriptkommandos geben, ohne dass ich in die Details der Syntax eingehe.Die meisten Kommandos sind für die Levelsektionen des Scripts, manche kommen in die Optionssektion. Diese werde ich entsprechend anmerken.

    Addeffect: Das Kommando ermöglicht das Hinzufügen von Partikeleffekten (Flammen, Rauch, Nebelbälle, Blut) zu Moveables.

    Animation: siehe vorhergehenden Abschnitt
    AssignSlot: Hiermit wird einem Objekt aus einem anderen TR-Level ein bekannter tr4-slot zugewiesen. das macht die Verwendung des TR2 bzw.TR-3-Motorbootes möglich, was bislang aber die einzigen derartigen Objekte sind,für die das möglich ist.
    ColorRGB: Hier werden RGB-Farben für andere Kommandos bereigestellt.
    CRS: CrashResumeSystem, ist ein Kommando in der Optionssektion. Wenn das CRS nicht arbeitet (DISABLED), dann gibt es Crashreports, was für die Bau-und Testphase wichtig sein kan. Wenn es arbeitet (ENABLED), dann werden Abstürze der Gameengine sehr unwahrscheinlich. Diese Einstellung sollte man also für die Veröffentlichung wählen. Ist analog zum CRS des NGLE.
    Costumize: Hier findet man viele Anpassungsmöglichkeiten ( z.B. für die Ammo, den Ammo Counter, die Waffen, die neue Soundengine (mehr dazu später) und viele andere kleine Anpassungen.)
    Cutscene:Das Level wird wie ein Cutscene-Level behandelt (keine Beeinflussung durch Tastaturkommandos)
    Damage:Hier kann man die Grundeinstellungen für Damagerooms seinen Bedürfnissen anpassen.
    Detector: Das ist ein neues Objekt der TRNG. Man braucht dafür ein von Paolone auf der TRNG-Webseite bereitgestelltes Wadobjekt (ng.wad, ng2.wad). Mit dem Detektor kann Lara Ziele in Bezug zu ihrer Position ausmachen. Der Detektor hat zwei verschiedene Modes: pointer detector und radar detector. Dder Pointer Detector zeigt wie ein Kompass auf das nächtsliegende ausgewählte Objekt, bis es aufgehoben bzw. getötet ist. dann zeigt es zum nächsten ausgewählten Objekt usw. Der Radar Detector zeigt alle ausgewählten Objekte, die in seinem Erfassuingsradius liegen. Für den Detektor gibt es zur Erläuterng auch ein Beispielprojekt von Paolone.
    Diagnostics: (Optionssektion), Sehr nützlich beim Levelbauen: Man bekommt im Spiel z.B. Lara gegenwärtige Animation und State-ID, abgespielte und vermisste Soundnummern usw. angezeigt.
    Elevator: Damit macht man Oneblock/Twoblockplatforms zu Fahrstühlen. Es gibt eine Vielzahl von Einstellungsmöglichkeiten für Höhen, Stockwerkanzahl, Geschindigkeit, Haltedauern, Türöffnung, Steuerung durch Keypad usw). Man kann damit bis zu 20 verschiedene Fahrstühle im Level haben! Hierzu gibt es ebenfalls ein Beispielprojekt von Paolone.
    Enemy:Hier passt man die Feinde an seine Bedürfnisse an.
    Equipment: Hier kann man das gewünschte Inventory für den Start des Levels zusammenbasteln.
    FMV: Die im Spiel genutzten Videosequenzen werden hier bestimmt.
    FogRange: dient der Festlegung der Nebelbereiche (für Fogbulbs und Distant Fog
    ForceBumpMapping:Optionssektion, erklärt sich von selbst
    ForceVolumetricFX:ebenfalls selbst erklärend
    GlobalTrigger:siehe hier
    ImportFile:Hat sich mir noch nicht so ganz erschlossen!
    Itemgroup:Erlaubt Gruppen von Objekten festzulgen, die dann gemeinsam mit einem Flipeffekttrigger ItemGroup manipuliert werden können!
    Keypad:Manipuliert die Standarts (Sounds;Lara`s Animationen) für das Keypad-Objekt (Kann man im ng.wad von Paolone finden!)
    Levelfarview: Legt die Drawing Distance für das Level fest (bis 127 Sektoren).Siehe auch Worldfarview!
    MirrorEffect: Spiegelräume können derzeit im Westen, an der Decke und am Boden gemacht werdem. Moveables können auch gespiegelt werden.
    MultEnvCondition:siehe hier
    NewSoundEngine: Optionssektion, die Engine ist als Standard eingeschaltet.
    Die Engine basiert auf dr bass.dll von Un4seen Developments. Sie ermöglicht das Abspielen auf zwei Kanälen mit samt vielfältiger Manipulierungen durch Flipeefekte( Abspielen als Loop, Lautstärke usw.). Mit dem Kommando costumize kann man das Abspielen verschiedener Soundformate ermöglichen, wobei alles mit dem wav-Format möglich ist. Wav muß auch nicht im bisher üblichen Format sein. Außerdem lassen sich hier auch die FadeOuts einstellen. Es können auch verschiedene Soundformate in einem Level gemixt werde. Man kann also gleichzeitig wav, mp3 oder ogg in einem Level nutzen. Mit der neuen Soundengine sind 256 Sounds abspielbar. Alle können beliebig oft
    abgespielt werden und alle können auch als Loop abgespielt werden!
    Organizer:siehe hier
    Parameters: dito
    PreserveInventory: Wenn man ResetHUB machen mußte, wird hiermit das Inventar wiederhergestellt, so wie es am Ende des vorhergehenden Levels war!
    Rain:Wenn man Regen in den gewünschten Räumen im Level haben möchte!
    Settings:Optionsektion, Hier kann man bestimmte globale Einstellungen machen:z.B. Cheats oder die Manipulierung von Saves unmöglich machen, das Script verschlüsseln, Level von CD ausführen ermöglichen
    ShowLaraInTitle: Lara im Title-Level sichtbar machen!
    Snow:Lasst es im Level schneien! Tipp: Zusammen mit dem Organizer und der Vielfalt von Flippeffekten/Flipmaps kann man recht eindrucksvolle dynamische Wetterabläfe im Level simulieren! Siehe Paolones Beispielprojekt.
    SoundSettings:Einstellung der Soundqualität und Laustärke von CD- und SFX-Sound
    TextFormat:Grundeinstellung für die Formatierung von durch Flipeffekten eingeblendeten Text
    TextureSequence: ermöglicht das vielfvältige Abspielen von Texturensequenzen
    Triggergroup:siehe hier
    Turbo: ermöglicht einige Tricks zur beschleuniguung der Gameengine, wenn die Framerate im Level zu langsam wird (Z.B. das dynamische Heruntersetzen der LevelfarView)
    WorldFarView:Optionssektion, hier wird die maximale Sichtweite in allen Leveln eingstellt, die durch LevelFarView nicht überschritten werden darf

    3.053 mal gelesen