Triggern mit der TRNG

  • Triggern mit der TRNG

    Inhaltsverzeichnis

    eingestellt von Raymond

    Triggern mit der TRNG


    Das Triggerkonzept ist für mich das Prunkstück der TRNG. Es ermöglicht unendlich mehr kreative Möglichkeiten für das Levelbauen. Es ist damit natürlich auch komplexer als man vom alten Editor gewohnt ist.

    Das Triggerfenster




    Hier ist das neue Triggerfenster.
    In der ersten Zeile findet man, was zu triggern ist. Neu bzw. grundlegend ausgebaut sind Action, Flipeffect, Parameter, FMV und Timer Field. Im zweiten Feld findet man das zu triggernde "Objekt". Das sind dann Listen, die entweder die im Level vorhandenen Objekte enthalte, wie z.B. bei dem Actiontrigger oder es sind Listen der möglichen Flipeffekte für den Flippeffecttrigger. In der dritten Zeile findet man den Triggertyp, also die Art, wie etwas getriggert wird. Neu ist der Triggertyp Condition. In der vierten und fünften Zeile Timer & und (E)xtra findet man Parameter, die den gewählten Trigger, je nach Auswahl, noch näher beschreiben.
    Im gewählten Beispiel habe ich einen Flipeffekttrigger "Lara.(Health)Damage Lara, decreasing life by & percentage of full vitality in (E) way".
    Der Flippeffekt betrifft also Lara und zwar ihre Gesundheit (Health). Ihr wird Schaden (Damage) zugefügt, wobei ihre Lebenskaft um eine bestimmte Prozentzahl(percentage) in einer bestimmten Art (way) veringert wird. Da stehen auch die beiden Parameter & und E, die bestimmen, was genau geschieht. Wenn also E und & in der Triggerbeschreibung auftaucht, muss in Zeilen vier und fünf die Parmater noch näher bestimmt werden. Für & kann man nun aus einer langen Liste die gewünschte Prozentzahl auswählen, in meinem Fall um 10 Prozent. Für den Parameter E habe ich Immediatly (sofort), one shot(einmalig) gewählt. Ihr werden also sofort und einmalig zehn Prozent ihrer vollen Lebenskraft abgezogen. Es wäre noch continuously (kontinuierlich) möglich gewesen, d.h. so lange Lara auf dem Trigger steht, werden ihr kontinuierlich zehn Prozent abgezogen. Da würde es mit Lara schnell zu Ende gehen!

    Die neuen Triggertypen


    Flipeffekttrigger

    Es gibt in der zweiten Zeile unter Flipeffect gegenwärtig insgesamt rund 100 Flipeffekte zur Auswahl, die ihn Gruppen in alphabetischer Reihenfolge geordnet sind. Mal ein paar Beispiele:
    Animated Textures: Hier können Texturenfolgen in vielfältigster Weise animiert werden.
    Inventory Item: Hier kann man Laras Inventar manipulieren.
    Item Group: Man kann im Script definierte Objektgruppen manipulieren!
    Keyboard: Tastaturkommandos werden beeinflußt!
    Lara: Flipeffekte rund um Lara`s Eigenschaften
    Moveable: Moveables werden neue Bewegungseigenschaften verliehen!
    Sound: Umfangreiche Möglichkeiten der Beeinflußung von Audioeigenschaften
    Static: Statische Objekte bewegen und zahlreiche neue Eigenschaften verleihen!
    Text: Variable Texteinblendungen im Spiel!
    Weather: Beeinflussung des Wetters
    etc. etc. etc.

    Besonders umfangreiche Gruppen wie Lara und Statics sind dann nochmal unterteilt in Untergruppen:
    Bei Lara lassen sich z.B. folgende Breiche manipulieren: Animation, Health, Mesh, Physics(Bewegungseigenschften), Skills (Fähigkeiten), Weapon (Waffen).
    Bei Statics kann man folgendes beeinflussen: Burning (Lara bei Berührung verbrennen), Color (Farbe verändern), Collision-Kollision verändern, Damage-Lara bei Berührung schaden, Explosion-Objekte und Lara explodiern lassen oder Shattereigenschften zuweisen, Move-Static bewegen, Poison-Lara vergiften, Rotation-Static rotieren, Transperacy-dem Static transparente Glas- oder Eiseigenschaft verleihen, Visibility-Static verschwinden/auftauchen lassen
    Na wem an der Stelle noch nicht der Kinnladen runtergeklappt ist, dem wird dass spätestens geschehen, wenn er die Möglichkeiten im Spiel sieht. Ich werde später ein Beispielprojekte von Paolone vorstellen, wo man mal in den neuen Umgang mit Statics reinschnuppern kann.

    An späterer Stelle werde ich aus bestimmten Gründen eingehen, um was es bei Organizer, Triggergroup and Globaltrigger geht. Da eröffnen sich nochmal neue Welten.

    Actiontrigger
    Der Actiontrigger ist eigentlich auch ein Flipeffekttrigger. Früher gab es mal eine deutlichere Unterteilung. Der Bereich Flipeffekt bezog sich auf Flipeffekte um alles, was Lara betrifft oder nicht direktes Objekt im Spiel ist. Action bezog sich auf Objekte. Das ist mittlerweile aus bestimmten Gründen nicht mehr ganz so.
    In der zweiten Zeile bestimmt man das zu beeinflußende Objekt. In der vierten Zeile steht die Liste der Flipeffekte und in der fünften mögliche Parameter.
    Man kann hier bestimmte Effekte zu Objekten hinzufügen, Animationen und Meshes beeinflussen, Moveables/Animatings bewegen/rotieren und Feindeigenschaften verändern.
    Obercool sind die Möglichkeiten, eine Vielzahl verschiedener Fahrstühle einfügen zu können. Näheres kommt später auch in einem Beispielprojekt.
    Es sind hier auch ein paar von den normalen Objekttriggern abgewandelt zu finden, mit dem Vorteil, dass der Antitrigger für Objekte hier als Trigger zu finden ist. Der aufwendige Rollenballtrick für das Antitriggern mit Schaltern/Keys ist also Geschichte, weil man die jetzt auch unter einen Switch- oder Keytrigger bekommt.
    Außerdem ist es so möglich verschiedene Türen gleichzeitig auf einem Feld zu triggern bzw. zu antitriggern, oder Zeitaufgaben verschiedener Länge von einem Feld aus zu starten.

    Conditional Triggers - der Parametertrigger

    Mit Hilfe das Aktivierungstyps Condition (dritte Zeile), der nur mit dem Parametertrigger (erste Zeile) zusammenarbeitet, kann man eine Reihe von Bedingungen stellen, wann Trigger ausgeführt werden sollen. Dazu plaziert man diesen Trigger auf das Feld mit dem anderen Trigger. Es ist auch möglich mehrere Bedingungen zu stellen, in dem man mehrere Parametertrigger übereinander legt oder einen Parametertrigger Multiple Conditions wählt, wo man allerdings dann noch im Script etwas eintragen muß. Der Trigger, der unter dem Parametertrigger liegt, wird dann ausgeführt, wenn die Bedingungen erfüllt sind.
    Was können das für bedingungen sein? Hier einige Beispiele:
    Berührt Lara ein Objekt?
    Was treibt ein anderes Lebewesen im Level so (In welchen Zustand ist es? was für eine Animation macht es? Welche State-ID hat es?)
    Was treibt Lara gerade so? (Welche Animation, State-ID, Lebenskraft, Status, Aktion hat/macht sie gerade?)
    Wieviel Zeit ist auf dem Timer abgelaufen?
    Wo befindet sich gerade Lara im Raum? Es lassen sich eine Vielzahl von Bedingungen stellen, die sich auf die Umgebung beziehen.

    Fragmentierte Trigger
    Auf welchen Teil eines Triggerfeldes befindet Lara sich? Ja, es sind jetzt nicht nur Trigger möglich, die sich über ein ganzes Feld ausdehnen, sondern die sich nur auf Teile eines Feldes beziehen. Man kann dabei au einer Vielzahl von verschiedenen Konfigurationen auswählen. Die Grundunterteilungen umfassen dabei entweder vier, neun oder 16 Quadrate in einem Triggerfeld.

    Die Grundunterteilungen (die Bilder sind von Paolone)


    Beispiel zwei gekreuzte Streifen


    Beispiel zwei gekreuzte Diagonalen


    Damit kann man dann z.B. komplexe Sensorzonen erstellen.

    Vertikale Trigger
    In welcher Höhe soll der Trigger wirken!?
    Exzellente Sache, wenn man z.B. nur bestimmte Höhenbereiche einer Wand bekletterbar machen will. Dann setzt man eine Leiter auf einem Feld an einer Wand und auf dem selben Feld wird dann das Tastaturkommando Aktion nur in einer bestimmten Höhe wirksam, so dass Lara nur da klettern kann. Aber es sind da natürlich auch viele andere Anwendungen möglich! Später stelle ich noch ein Beispielprojekt von Paolone dazu vor!

    FMV-Trigger
    Kann ich nicht viel dazu sagen. Man kann jetzt halt FMV´s in ein Level einfach einbinden! Dafür ist aber auch ein Scripteintrag notwendig.

    Timer_Field-Trigger
    Bei den normalen Objekttriggern kann man, wie bisher, ganz normal die Zeit für eine Zeitaufgabe in das Timerparameterfeld eintragen (vierte Zeile). Es gibt aber jetzt ja eine ganze Menge von Triggern, in denen das Timerparameterfeld durch andere Sachen belegt ist. Dann muß man für eine Zeitaufgabe diesen Timer_Field-Trigger auf dem selben Feld plazieren. Die Zeit für die Zeitafgabe kommt hier aber in das zweite Feld!

    Trigger und Scripting - Triggergroup, Globaltrigger, Organizer und mehr


    Allgemeines

    Das Triggerkonzept ist nicht ohne das Scripting zu verstehen. Es gibt viele Schnittstellen, wo Parameter für manche Trigger über das Script definiert werden, oder wo Trigger in Scriptkommandos exportiert werden, um sie in gänzlich neue Zusammenhänge zu stellen. Genaueres zum Scripting gibt es dann in einem speziellen Kapitel zu dem Thema. An der Stelle möchte ich drei Scriptkommandos vorstellen, die Trigger auf verschiedene Weise zur Anwendung bringen. In diesem Kapitel werde ich die Syntax der Skriptkommandos noch nicht im Detail erläutern. Das mache ich dann aber im Kapitel über das Scripting.
    Ihr habt euch vielleicht schon gefragt, was das Feld Export Scripttrigger bedeutet. Wenn man den im falle meines Beispiels drückt erhält man folgengende Textdatei auf dem Bildschirm:
    ; Exporting: TRIGGER(18:0) for FLIPEFFECT(89)
    ; <#> : Lara. (Health) Damage Lara, decreasing life by <&>percentage of full vitality in (E) way
    ; <&> : 10 Percentage
    ; (E) : Immediatly, one-shot
    ;Add following three values in your script command:
    $2000, 89, $12
    Die ersten vier Zeilen enthalten nochmal eine Beschreibung des Triggers. Es ist äußerst empfehlenswert, diese als Dokumentation mit ins Script zu nehmen, damit man später auch noch weiß, was das alles zu bedeuten hat. In der sechsten Zeile steht dann das Entscheidende: drei hexidezimale Zahlen, die den Trigger beschreiben und die an vorgegebener Stelle in das Skriptkommando eingefügt werden müssen und zwar in unserem Fall in das Triggergroupkommando In dieses Kommando legt man Gruppen von Triggern (oder auch einzelne Trigger) ab, die dann gemeinsam ausgeführt werden. Es können Action-, Flipeffekt- und Parametertrigger exportiert werden.

    Die Triggergruppe
    Wenn ich obigen Trigger in das Skriptkommando Triggergroup exportiere, dann sieht meine Triggergruppe folgendermaßen aus:
    TriggerGroup=1,$2000, 89, $12.
    Das ist also meine erste Triggergruppe, die erst mal nur diesen einen Trigger enthält. Man kann aber beliebig viele Trigger in das Kommando exportieren, wobei man nacheinander immer diesen Dreierpack von Werten für die Trigger einfügt. Welchen Sinn kann eine solche Triigergruppe haben. Ich kann damit z.B. die anzahl der Trigger im Projekt erheblich reduzieren, was solchen Triggerfanatikern, wie ich es einer bin, hilft, nicht zu schnell an die Grenze von 512 möglichen Triggern im NGLE zu stoßen. Wenn ich z.B. fünf Dinge mit einem Schalter auslösen will, dann kann ich die fünf Trigger in eine Triggergrupe exprtieren und habe dann im Projekt statt der fünf nur einen Trigger beim Schalter, nämlich derjenige Flipeffekt, der die Triggergruppe auslöst! Der zweite wesentliche Grund für dieses Kommando ist, das ich es benötige, um Werte andere Skriptkommandos, z.B. an die Kommandos Globaltrigger und Organizer weiter zu geben.

    Globale Trigger

    Lassen wir die Sache mal praktisch werden. Mein Ziel ist es, folgendes zu schaffen. Ich will einen Stein auf Lara von der Decke fallen lassen, der Aua Aua macht, wenn er auf Lara trifft und Lara 10 Prozent von ihrer Lebenskraft nimmt. Ok, ich habe mir so ein Steinchen als Static gebaut und ihn an der Decke plaziert. Dann habe ich ein Flipeffekttrigger für Statics gesetzt, so dass der Stein mit rumpeln und Aufschlag nach unten fällt und dabei möglicherweise auch Lara trifft. Wie schaffe ich es, dass Lara dabei verletzt wird (Lebenskraft abgezogen wird)? Da hätten wir z.B. die Möglichkeit einen anderen Static-Flippeffekt zu nutzen, der ermöglicht, das Lara bei Berührung mit Objekten Lebenskraft abgezogen wird. der Wert, der abgezogen wird, ist aber festgelgt und er gefällt mir nicht. Ich möchte eben zehn Prozent haben. Da kommt jetzt der Globaltrigger ins Spiel. Globale Trigger sind Trigger, in einem beliebigen Bereich des Levels nach der Erfüllung einer Bedingung ausgeführt werden. da gibt es einen Globalen Trigger (GT_COLLIDE_...) , der nach der Berührung durch ein Objekt eines bestimmten Slots (bei uns der Staticslot für den Stein) ausgelöst wird. Aber leider muß ich in der Beschreibung des NGCenters für diese Bedingung lesen, dass dass nur für Moveableslots gilt.
    Da muß ich mir also etwas anderes einfallen lassen! Es gibt meist mehrere Wege zum Ziel. Bedingungen kann ich mittels der Parametertrigger auch direkt in die Triggergruppe reinpacken. Was steht uns da zur Verfügung? Da haben wir die Trigger, die abfragen, ob Lara etwas berührt ( Collision. Lara is touching...). Wieder geht es aber nur mit Moveables.
    Ich bin hartnäckig und erinnere mich, dass es noch eine dritte Möglichkeit geben könnte mit Hife des Scriptkommandos MultEnvCondition, in dem eine oder mehrere sogenannte Environmental Conditions (Umgebungsbedingungen) festgelegt werden können. Diese Umgebungsbedingungen werden dann in den Parametertrigger Multiple Condition of MultiEnvCondition-script command eingefügt. In der Liste der Möglichkeiten finde ich zwar Bedingungen, die sich auf Objekte beziehen (Env_Item_Extra_ ...), aber wieder geht es leider nur mit Moveables.
    Was nun? Entweder ich packe den Stein dann doch einfach in ein MoveableSlot oder ich frage bei Paolone an, ob es nicht möglich wäre, das auch für Statics möglich zu machen und warte auf seine nächsten Updates. Natürlich warte ich jetzt nicht, sondern packe den Stein in ein Moveable Slot und setze die erste und einfachste von obigen drei Möglichkeiten um. Mein Globaler Trigger nimmt dann folgende Form an:
    GlobalTrigger=1, IGNORE,GT_COLLIDE_ITEM, 20, IGNORE, 1. Was bedeutet das: Das ist mein Globaler Trigger Nr. 1, der wirksam wird, wenn Lara mit dem Objekt ID 20 (das sei mein Stein) kollidiert und dann meine Triggergruppe 1 triggert. Die Objekt ID sieht man im Editor in dem kleinen gelben Feld, wenn man mit dem Mauszeiger über das Objekt fährt. Globale Trigger fragen grundsätzlich im ganzen Level ab, ob die gegebene Bedingung efüllt ist, also auch vom Levelstart an. Wenn man aber aus bestimten Gründen will, das der Globale Trigger das nur für bestimmte Teile des Levels tut, dann muß man den Globalen Trigger mittels dem Flipeffekttriggers GlobalTriggers. &Enable/Disable the E Global Trigger je nach Bedarf aus-bzw. anschalten.
    Nach all der Mühe entdecke ich doch noch einen einfacheren Weg. Statics können mittels OCB neue Eigenschaften zugewiesen werden. Man kann ihn so auch die Eigenschaft zuweisen, das sie Lara schaden, wen Lara sie berührt. Der angerichtete Schaden hat zwar einen voreingstellten Wert, man kann ihn aber mit Hilfe eines Skriptkommandos Costumize auf den gewünschten Wert verändern. Also könnten wir den Stein doch in einem Staticslot verwenden. Viele Wege führen zum Ziel und mit Forschergeist findet man einen, der wirklich funktioniert bzw. den besten von einigen!

    Jetzt muß ich noch den Flipeffekt starten, um den an der Decke plazierten Stein im rechten Moment runter purzeln lassen. Dazu verwende ich den Flipeffekttrigger Moveable Move. Move Moveable with data in & parameter list (wenn der Stein in einem Moveable Slot ist) oder Statics. Move. Move static with data in <&>parameters list (wenn der Stein im Static Slot ist). Paramater list bezieht sich auf ein anderes Scriptkommando Parameter, in dem ich zahlreiche Parameter für die Bewegung diese Moveables (Statics) festlegen kann, die Richtung der Bewegung (in unserem Fall nach unten), die Länge der Bewegung (Da muß man im Editor natürlich nachschauen, wie groß der Abstand zwischen Stein und Boden ist!), die Geschwindigkeit der Bewegung. Außerdem kan ich noch einen Sound während der Bewegung abspielen lassen und ebenso einen Sound am Ende der Bewegung, was bei uns natürlich ein schöner Sound für den Aufschlag des Steines auf dem Boden wäre. Diesen Trigger setze ich natürlich so, dass Lara potenziell genau in den fallenden Stein reinläuft. Ist schonmal ein bisschen Arbeit, um so etwas zu erschaffen, aber damit habe ich praktisch eine neue Falle kreiert. Nun fehlt natürlich noch der Test, ob wirklich alles so läuft, wie ich es mir vorgestellt habe. Unter Umständen muss ich dann halt noch weiter an der ganzen Sache basteln, bis es auch wirklich so funktioniert, wie ich es mir vorgestellt habe.
    Aber Moment mal! Ich will doch nicht nur ein einziges Steinchen runterpurzeln lassen. Nein, ich will gleich mehrere Steine in einer bestimmten zeitlichen Reihenfolge von der Decke auf Lara herabregnen lassen! Ach Quatsch, ich will ganz großes Theater: es bebt, die Steine regnen herab, Objekte bewegen sich durch die Gegend, der Boden reißt auf und Lava quillt hervor, giftige Dämpfe steigen auf, Wege werden verschüttet, wenn Lara nicht schnell genug ist usw. und das alles schön zeitlich choreographiert. Da kommen wir zum Organizer.

    Das Organizer-Skriptkommando

    Wie sieht so ein Organizer aus: Organizer=1, IGNORE, IGNORE, 6, 1, 5, 2, 4, 3.
    Das ist mein Organizer Nr.1. In den nächsten beiden Feldern kann man bestimmte Flags (Zeichen) bestimmen, die das Verhalten des Organizers bestimmen. Die Felder werden hier nicht genutzt, weswegen dort IGNORE (ignorieren) steht. Die Reihe der Zahlen besagt folgendes Nach 6 s wird meine erste Triggergruppe aktiviert, nach weiteren 5 s die zweite und nach weiteren 4 s die dritte. Als mögliche Flags im dritten Feld kann z.B. FO_LOOP stehen, was bedeutet, das mein Organizer als Schleife sich ständig wiederholt. Mit FO_TICK_TIME kann man die Zeitzählung verändern. Im obigen Organizer sind die Zeitabstände in Sekunden. Wenn ich aber dieses Flag eintrage, werden die Zeitabstände in 1/30s angegeben (Wenn man also einen Zeitabstand von einer halben Sekunde haben will, müßte man 15 an entsprechender Stelle eintragen und für eine Sekunde 30 usw.). Wenn man also sehr genau steuern muß (z.B. bei einer Fallensequenz) oder Ereignisse sehr schnell hintereinander stattfinden sollen, dann setzt man dieses Flag.
    So eine Abfolge, wie weiter oben beschrieben, ließe sich also mit einem Organizer sehr gut zeitlich steuern. Ein Organizer kann übrigens bis zu 18 Stunden lang sein!
    Lassen sich obige Ereignisse auch mit em TRNG umsetzen und wie ginge das (grob beschrieben)? Ja, es geht prinzipiell alles und wirklich im erstaunlich flexiblen Ausmaß, was man sich füher hätte sicher nicht vorstellen können. Ok, ein beben kenne wir ja schon als alten Flipeffekt. Wie man Steine herabregnen lässt, habe ich ausführlich beschrieben. Für die Bewegung von Objekten gibt es auch eine ganze Menge von schon teilweise hier erwähnten Flipeffekten. Damit kann man natürlich nicht alles erreichen, aber mit der Überlagerung von mehreren Bewegungen/Rotationen kann man Objekte schon recht komplex bewegen. Eine umfallende Säule z.B. dürfte mit diesen Mitteln schwer zu erreichen sein. Für ein paar Sachen müsste man dann halt Moveables mit entsprechenden Animationen bauen. Den Boden kann man natürlich mit Flipmaps aufreißen lassen. Veränderungen der Raumgeometrie und der Raumbeleuchtung ist bisher nur mit Flipmaps möglich, von denen ja jetzt mit dem TRNG 32 statt bisher 8 möglich sind. Nach wie vor kann man einen Raum nur einmal flippen. Es gibt aber Tricks, da noch variabler zu arbeiten. Mit einem Flipeffekttrigger kann man Lara wirklich absolut unbemerkt ohne Unterbrechung des Spielflusses in einen neuen, gleichartigen Raum Teleportieren. So könnte man dann mit etwas Aufwand natürlich, Raumgeometrie und Beleuchtung eines Raums scheinbar mehrfach verändern. Also Wege verschütten und den Boden aufreißen läßt sich sehr flexibel bewerkstelligen. Um einen Wasserraum zu erstellen, braucht man übrigens keine Flipmap mehr (Für unsere Zwecke könnten wir so recht einfach einen Lavasee erstellen.).Da gibt es auch einen Flipeffekt. Texturen lassen sich mit der Flipeffektgruppe Animated Textures auch auf sehr flexible Art und Weise verändern. Himmel und Wetter kann man auch sehr effektvoll mit der Flipeffektgruppe Weather steuern. Da gibt dazu es ein sehr schönes Beispielprojekt von Paolone (siehe später).
    Wie man sieht ist mit dem TRNG eine unglaubliche neue Flexibilität möglich, von der man früher nur träumen konnte. Es erfordet natürlich viel Wille und Zeit zu lernen und alles mögliche und ummögliche auzuprobieren, um die neuen Möglichkeiten in ihrem ganzen Potential auszuschöpfen.
    Aber so können wir dann völlig neuartige Sachen in Costumlevels sehen und die Costumlevelszene lebendig halten.
    Das war aber nur ein neuer wesentlicher Bereich der TRNG. Auch das Scripting hat sich stark verändert. Dazu noch mehr im nächsten Kapitel. Vorher nochmal eine Übersicht für das Zusammenwirken von Triggern und Scripting.

    Übersicht der Verbindungen zwischen Triggern und Scripting

    Action-, Flipeffekt und Parametertrigger können in das Scriptkommando Triggergroup transportiert werden und dort zusammengefasst werden. Triggergroups können mit einem Flipeffekttrigger auf einem Feld ausgelöst werden. Triggergroups können in die Scriptkommandos Globaltrigger und Organizer transportiert werden, wo sie in flexibler räumlicher und zeitlicher Reihenfolge organisiert werden. Globaltrigger und Organizer werden dann mit Flipeffekttriggern im Level ausgelöst/gestoppt.
    Einige Flipeffekttrigger, wie z.B. die Flippeffekte Moveable Move oder viele Flippeffekte Statics brauchen Parameter, die mit dem Parameter-Scriptkommando bereitgestellt werden.
    Das Scriptkommando MultEnvCondition stellte Umgebungsparameter für den Parametertrigger MultEnvCondition bereit.
    Das sind nur Verbindungen, die in den vergangenen Abschnitten in der einen oder anderen Weise näher erläutert wurden. In anderen Bereichen gibt es natürlich noch mehr Verbindungen.

    2.891 mal gelesen