aslain.dev
0%
01 Hizmetler 02 Hakkımda 03 Projeler 04 Stack 05 Blog 06 İletişim
← Tüm makaleler Metin2

Metin2 NPC-Dialog: Verzweigen mit select und confirm

Ein Metin2 NPC-Dialog beginnt in dem Moment, in dem ein Spieler das Gesprächsfenster mit einem NPC öffnet, und gut aufgebaut fühlt er sich wie eine kleine Geschichte an. Eine einzelne Textzeile anzuzeigen ist leicht; die eigentliche Arbeit besteht darin, dem Spieler Auswahlmöglichkeiten zu geben und das Gespräch je nach seiner Entscheidung zu verzweigen. In diesem Artikel gehe ich Schritt für Schritt durch das Erstellen von Auswahlmenüs mit select, Ja/Nein-Fenstern mit confirm und wie man sie zu einer sauberen, funktionierenden Lua-Quest kombiniert.

Das Grundgerüst eines Dialogs

Jedes NPC-Gespräch öffnet mit einem chat-Trigger. Du schreibst die vnum des NPCs, gibst dem Fenster einen Titel und legst den Text Zeile für Zeile mit say-Funktionen aus.

quest dorfbewohner_dialog begin
    state start begin
        when 9003.chat."Mit dem Dorfbewohner sprechen" begin
            say_title("Alter Dorfbewohner")
            say("Willkommen, Reisender.")
            say("")
            say("Was führt dich hierher?")
        end
    end
end

Hier ist 9003 die vnum des NPCs, say_title die Kopfzeile des Dialogfensters und say der Fließtext. Ein leeres say("") wird verwendet, um eine Leerzeile zu lassen. Dieser Block ist einseitig: Der Spieler liest nur und klickt auf „Schließen". Um Interaktion hinzuzufügen, brauchen wir die Auswahlmechanismen.

Auswahlmenüs mit select

select zeigt dem Spieler eine Liste von Schaltflächen und gibt den Index der gewählten Option zurück (beginnend bei 1). Du fängst den zurückgegebenen Wert in einer Variablen auf und verzweigst damit über if / elseif.

when 9003.chat."Mit dem Dorfbewohner sprechen" begin
    say_title("Alter Dorfbewohner")
    say("Wie kann ich dir helfen?")
    say("")
    local auswahl = select("Gib mir eine Quest", "Waren kaufen", "Erzähl deine Geschichte", "Vergiss es")

    if auswahl == 1 then
        say("Dann hör zu: räume die Wölfe im Wald aus.")
    elseif auswahl == 2 then
        say("Leider habe ich nichts mehr zu verkaufen.")
    elseif auswahl == 3 then
        say("Vor Jahren war dieses Dorf ein ganz anderer Ort...")
    else
        say("Gute Reise.")
    end
end

Ein paar Punkte zum Beachten: In der Praxis ist select bis etwa 6-7 Optionen komfortabel; mehr passen nicht ins Dialogfenster. Die letzte Option zu einem „Vergiss es"-Ausgang zu machen, ist eine gute Angewohnheit, damit der Spieler nie im Menü feststeckt. Speichere den zurückgegebenen Wert immer in einer local Variablen, denn wenn du ein zweites select aufrufst, geht der vorherige Wert verloren.

Ja/Nein-Bestätigung mit confirm

Vor einer unumkehrbaren Aktion (ein Item löschen, teleportieren, Yang ausgeben) willst du den Spieler um Bestätigung bitten. confirm("Text") ist genau dafür da: Es öffnet dem Spieler ein „Ja / Nein"-Fenster und gibt true zurück, wenn er zustimmt, und false, wenn er ablehnt.

when 9003.chat."In die Stadt teleportieren" begin
    say_title("Alter Dorfbewohner")
    say("Soll ich dich in die Stadt schicken?")
    say("Das kostet 50.000 Yang.")
    say("")

    if confirm("Möchtest du in die Stadt teleportieren?") then
        if pc.get_money() >= 50000 then
            pc.change_money(-50000)
            pc.warp(469000, 964000)
        else
            say("Du hast nicht genug Yang.")
        end
    else
        say("Vielleicht ein andermal.")
    end
end

confirm kann direkt innerhalb einer if-Bedingung verwendet werden, da es einen Boolean zurückgibt. Manche Versionen bieten auch confirm_with_button("Frage", "Ja-Beschriftung", "Nein-Beschriftung") für eigenen Schaltflächentext; da die Verfügbarkeit aber von deiner Source abhängt, bleib beim Standard-confirm, wenn du portabel bleiben willst.

select und confirm miteinander verketten

Die wahre Stärke zeigt sich, wenn du beide verschachtelst. Der Spieler wählt zuerst aus einem select-Menü und bestätigt dann am kritischen Schritt seine endgültige Entscheidung mit confirm. Unten ein Beispiel für einen Belohnungstruhen-NPC:

when 9003.chat."Belohnungstruhe" begin
    say_title("Geheimnisvolle Truhe")
    say("Wähle eine Belohnung aus dem Inneren, aber sei vorsichtig.")
    say("Nach deiner Wahl gibt es kein Zurück.")
    say("")
    local belohnung = select("Schwert", "Rüstung", "Yang", "Später")

    if belohnung == 4 then
        say("Die Truhe schloss sich.")
        return
    end

    if not confirm("Bist du dir bei deiner Wahl sicher?") then
        say("Du hast einen Moment vor der Truhe gezögert.")
        return
    end

    if belohnung == 1 then
        pc.give_item2(11209, 1)
        say("Du hast ein scharfes Schwert erhalten!")
    elseif belohnung == 2 then
        pc.give_item2(11949, 1)
        say("Du hast eine robuste Rüstung erhalten!")
    elseif belohnung == 3 then
        pc.change_money(500000)
        say("Du hast 500.000 Yang erhalten!")
    end
end

Drei Techniken arbeiten hier zusammen: select bestimmt den Zweig, ein frühes return behandelt den „Später"-Fall sauber, und confirm setzt vor der Ausgabe der unumkehrbaren Belohnung ein letztes Sicherheitstor. Der Einsatz von return hält den Code aus tiefen if-Verschachtelungen heraus und gut lesbar.

Den Text dynamisch machen

Statischer Text wird schnell langweilig. Um den Namen des Spielers, sein Level oder die Anzahl der Items in den Text einzuweben, nutze die String-Verkettung innerhalb von say. In Lua ist der Verkettungsoperator zwei Punkte (..).

when 9003.chat."Begrüßen" begin
    say_title("Alter Dorfbewohner")
    say("Hallo "..pc.get_name()..", schön dich zu sehen.")
    say("Du bist Level "..pc.get_level()..", du bist schnell vorangekommen.")
end

Dadurch fühlt sich derselbe Dialog für jeden Spieler persönlich an. Wenn du numerische Werte (pc.get_level()) in Text mischst, wandelt Lua sie automatisch um, sodass du nicht einmal tostring() aufrufen musst.

Häufige Fehler und Tipps

  • Vergessen, das select-Ergebnis zu prüfen: Der Spieler kann das Fenster mit ESC schließen; definiere einen Zweig für jede Option plus einen „Vergiss es"-Ausgang.
  • confirm wie ein einfaches if schreiben und die Klammern vergessen: confirm(...) braucht immer ein Textargument, lass es nicht leer.
  • Zu lange say-Ketten: Zeige dem Spieler nach 4-5 Zeilen eine „Weiter"-Schaltfläche mit wait(); sonst läuft das Textfenster über.
  • Sonderzeichen: Speichere Quest-Dateien in der vom Server erwarteten Kodierung (meist UTF-8 oder die entsprechende Locale); eine falsche Kodierung erscheint als verstümmelte Zeichen im Dialog.
  • Vergiss nicht, die Quest nach einer Änderung zu kompilieren und neu zu laden; sonst zeigt der Game-Core weiterhin den alten Text an.

Häufige Fragen

Wie viele Optionen unterstützt select?

Es gibt keine harte technische Grenze, aber in der Praxis passen 6-7 Optionen bequem ins Dialogfenster. Brauchst du mehr, teile die Optionen in Kategorien auf: zeige die Gruppen im ersten Menü und öffne dann ein zweites select je nach gewählter Gruppe. Das sieht sauberer aus und bleibt lesbar.

Kann ich den Schaltflächentext im confirm-Fenster ändern?

Das Standard-confirm nutzt feste „Ja/Nein"-Schaltflächen. Manche Sources enthalten eine erweiterte Version, mit der du eigenen Schaltflächentext setzen kannst, aber das hängt von deiner Version ab. Willst du Portabilität, ist der sicherste Weg, die eigentliche Frage klar mit say zu formulieren und confirm einfach zu halten.

Kann ich das select-Ergebnis direkt in einem if verwenden?

Du kannst, aber es ist nicht empfehlenswert. select zeigt das Menü und gibt den Wert zurück; wiederholst du denselben Aufruf in zwei if-Zweigen, öffnet sich das Menü zweimal. Fang das Ergebnis stattdessen in einer local Variablen auf und vergleiche dann diese Variable.

Bei NPC-Dialogen festgefahren? Wenn du Hilfe bei verzweigten Questketten, mehrstufigen Dialogsystemen oder dem Menüentwurf für deinen Server brauchst, melde dich bei mir — bauen wir es gemeinsam.

Bu kategorideki tüm yazılar →

Devamı için