[Tutorial] Moddingerfahrungen - Tricks und Kniffe

Lich

Senior Member
Registriert
14.09.2007
Beiträge
1.560
Ja das würde alle Preise dieses Ladens verändern. Wenn du den Preis einzelner items verändern willst, musst du schon das entsprechende item editieren.

Lich
 

Kyros

Senior Member
Registriert
05.03.2006
Beiträge
113
@Lich

Ja das hatte ich ja versucht, aber wenn ich die Itemdatei da öffne sehe ich nirgends einen Wert, der für den Preis stehen könnte. Kannste mir da bisschen was erklären? Danke.

EDIT:Ok erledigt bin draufgekommen.:)
 
Zuletzt bearbeitet:

Jastey

Matron Modderholic
Registriert
16.05.2004
Beiträge
12.922
In Guter Tradition führe ich das mal fort. Es gibt so viele kleine Dinge, die man einfach wissen muss, da man sonst ewig am debuggen ist. So, wie ich gerade über sie stolpere, so werde ich sie hier posten.

CreateItem(S:ResRef*,I:Usage1*,I:Usage2*,I:Usage3*) nicht für das Bestücken von NPCs mit Gegenständen verwenden, da diese sonst im "magische Waffenslot" abgelegt werden und der NPC daraufhin nicht mehr seine Waffen ausrüsten kann (Meldung "Magical Weapon in use").
Für NPC immer das GiveItemCreate(S:ResRef*,O:Object*,I:Usage1*,I:Usage2*,I:Usage3*) verwenden.

CreateItem() funktioniert wunderbar, wenn Gegenstände z.B. in einer Truhe/Container erzeugt werden sollen.
 

Maus

Senior Member
Registriert
07.08.2002
Beiträge
9.380
Was ist in dem Zusammenhang mit den Belohnungsitems für die Gruppe (HC)? Ich meine, da müsste CreateItem() funktionieren, oder? Liegt dann glaube ich im Rucksack... und konnte man bei CreateItem() nicht auch den Slot angeben?
 

Jastey

Matron Modderholic
Registriert
16.05.2004
Beiträge
12.922
Ich kenne mich mit den Belohnungsitems nicht so aus. Du meinst die in den EE-Spielen (SoD?)?. In der "explore.bcs" von SoD habe ich z.B. das gefunden:
IF
!HasItemEquiped("BOOT01",Player1) // The Paws of the Cheetah
!HasItem("BOOT01",Player1) // The Paws of the Cheetah
THEN
RESPONSE #100
ActionOverride(Player1,CreateItem("BOOT01",0,0,0)) // The Paws of the Cheetah
ActionOverride(Player1,FillSlot(SLOT_BOOTS))
Continue()
END

Das scheint ja dann zu funktionieren, sollte man meinen.

Ich habe aber genau diese Aktion(en) für meinen mod NPC verwendet, und das führte zu dem "Magical Weapon in use"-Bug.

Den Slot kann man im eigentlichen "CreateItem"-Befehl nicht auswählen.

In der EE und klassischem BGII wird dieses "Feature" glaube ich gerne ausgenutzt, um Gegenstände so bei NPCs zu platzieren, dass sie nicht stehlbar sind. Zumindest vermute ich das, da hier z.B. in der AR0115.bcs Marek sein Gegengift auf diese Weise erzeugt bekommt. Im original BG1 wurde CreateItem nicht einmal verwendet (funktioniert für Truhen ja auch nicht richtig im klassichen original BG1:TotSC).
 
Zuletzt bearbeitet:

Jastey

Matron Modderholic
Registriert
16.05.2004
Beiträge
12.922
Unterschied zwischen der klassischen BGII-Engine und der EE:
Verlässt ein NPC die Gruppe über ein gescriptetes LeaveParty(), dann wird bei der EE automatisch auf den "Kickout"-Dialog geändert (xxxP.dlg).
In der klassischen BGII muss der Wechsel zur xxxP.dlg ebenfalls gescriptet werden über SetLeavePartyDialogFile(), oder die xxxJ.dlg ist weiterhin aktiv.
 

Jastey

Matron Modderholic
Registriert
16.05.2004
Beiträge
12.922
Wenn NPCs tot in der Gruppe sind und man rasten möchte, dann kann das "Dreamskript" des NPC (= Skript, das Dialogue etc. beim Rasten auslöst) zu einem CTD führen, wenn die Trigger in ungünstiger Reihenfolge angeordnet sind.
Dieser Skriptblock löst einen CTD aus:
IF %BGT_VAR%
AreaType(FOREST)
InParty("%IMOEN_DV%")
InParty(Myself)
CombatCounter(0)
!See([ENEMY])
See("%IMOEN_DV%")
!StateCheck("%IMOEN_DV%",CD_STATE_NOTVALID)
!StateCheck(Myself,CD_STATE_NOTVALID)
RealGlobalTimerExpired("X#DreamTalk","GLOBAL")
Global("X#XZIM1","GLOBAL",2)
THEN
RESPONSE #100
IncrementGlobal("X#XZIM1","GLOBAL",1)
RealSetGlobalTimer("Xz1BackUpTimer","GLOBAL",18)
RealSetGlobalTimer("X#DreamTalk","GLOBAL",180)
StartDialogueNoSet("%IMOEN_DV%")
END

Dieser nicht. Der AreaType() check ist nun so weit unten, dass vorher überprüft wird, ob der NPC überhaupt sprechen kann:
IF
!StateCheck(Myself,CD_STATE_NOTVALID)
%BGT_VAR%
AreaType(FOREST)
InParty("%IMOEN_DV%")
InParty(Myself)
CombatCounter(0)
!See([ENEMY])
See("%IMOEN_DV%")
!StateCheck("%IMOEN_DV%",CD_STATE_NOTVALID)
RealGlobalTimerExpired("X#DreamTalk","GLOBAL")
Global("X#XZIM1","GLOBAL",2)
THEN
RESPONSE #100
IncrementGlobal("X#XZIM1","GLOBAL",1)
RealSetGlobalTimer("Xz1BackUpTimer","GLOBAL",18)
RealSetGlobalTimer("X#DreamTalk","GLOBAL",180)
StartDialogueNoSet("%IMOEN_DV%")
END
Als dieser Zusammenhang beim Testen des BG1NPC Projekts vor Jahren festgestellt wurde, wurde damals der AreaType() check als Ursache identifiziert. Ich hatte aber auch für eine andere Mod erst vor "kurzem" einen ähnlichen Bericht über einen Absturz beim Rasten mit totem NPC, ohne dass sich im Dreamscript ein AreaType() befand. Es ist also ratsam, Skriptblöcke im Dreamskript immer mit dem !StateCheck(Myself,CD_STATE_NOTVALID) zu beginnen.
(Festgestellt für die klassische Engine, aber eventuell auch noch für EE relevant.)
 

Jastey

Matron Modderholic
Registriert
16.05.2004
Beiträge
12.922
Geben Charaktere - vor allem in der EE - plötzlich völlig willkürliche Textzeilen als Kommentare im Textfenster von sich, dann ist höchstwahrscheinlich der .cre-Datei ein willkürlicher String als Soundreferenz zugeordnet.
In der klassischen Engine fiel das nicht (so) auf, da die ganzen Engine-gefeuerten (nicht gescripteten) Situationskommentare nicht wirklich getriggert wurden (außer den bekannten, wie "im Wald", "in der Stadt", "müde", "im Dungeon", "zu viel Gepäck" etc.).
Um die Stringreferenzen los zu kriegen, die cre-Datei in NI öffnen, und die falschen Nummern in den Soundreferenzen mit "-1" (No such index) ersetzen.
 

Jastey

Matron Modderholic
Registriert
16.05.2004
Beiträge
12.922
Wenn eine Area / das Spiel plötzlich abstürzt, dann sind die Gründe meistens:

-eine Kreatur hat eine nicht-existente/fehlerhafte Animation zugewiesen
-eine Kreatur hat eine falsche Farbe zugewiesen (für die verschiedenen Bereiche Haare/Rüstung/Haut/etc.) gibt es bestimmte Farbdefinitionen, die eingehalten werden müssen
-die Waffe einer Kreatur hat eine nicht-existente/fehlerhafte Animation zugewiesen
-eine Hintergrundanimation ist nicht im selben Biff/Overide wie die Area (Kaminfeuer, Wasserfall, etc.)
-die Area schmiert randommäßig ab: die Engine wollte einen Ambientsound triggern, der sich nicht im selben Biff/Override befindet
-oder: ein Spawnpunkt hat fehlerhafte Kreaturen spawnen wollen
 

Jastey

Matron Modderholic
Registriert
16.05.2004
Beiträge
12.922
Der Zusammenhang ist hier nochmal schöner präsentiert.

--

Wenn in der EE das Spiel plötzlich abschmiert / einfriert, dann wurden mit hoher Wahrscheinlichkeit Texte verwendet, die nicht im benötigten utf-8 (ohne BOM)-Format waren und Symbole enthielten (also andere Buchstaben als die lateinischen, u.a. ä,ö,ü,ß)*. Sobald ein solcher Text erscheinen würde, friert das Spiel ein und ist abgestürzt. Z.B.: beim Betreten einer Area, die ein Symbol in einem Mappoint hat. Beim Öffnen des Inventars bei einem Item, das ein Symbol im Namen hat. Beim Öffnen der Itembeschreibung, wenn hier ein Symbol verwendet wurde. Beim Erscheinen einer Dialogzeile während eines Dialogs, in der eins verwendet wurde.
Zum Debuggen überprüfen, ob HANDLE_CHARSETS richtig angewendet wurde.

*Die klassische Engine möchte die Texte in ANSI.
 
Zuletzt bearbeitet:

Jastey

Matron Modderholic
Registriert
16.05.2004
Beiträge
12.922
Bei der Kompilierung der tra-Dateien gibt es folgende Hirarchie:
TRA werden in der Reihenfolge LANGUAGE, WITH_TRA, USING und AUTO_TRA geladen. Das heißt: AUTO_TRA hat die höchste Priorität, und überschreibt die Zeilen der tra-Datei, die z.B. mit USING spezifiziert wurde.

Das ist zum Beispiel wichtig bei Dialogdateien und Skriptdateien eines Mod-NPC. Häufig heißen zwei gleich, nur eben die Endungen unterscheiden sich (d und baf). Wenn jetzt aber zu der d-Datei eine tra-Datei existiert, und das "gleichnamige" Skript hat ebenfalls Textzeilen (z.B. in DisplayStringHead oder über Soundreferenzen für ein Soundset), dann werden bei der Kompilierung immer erst die Textzeilen aus der tra-Datei der Dialogdatei verwendet, wenn ein AUTO_TRA-Pfad definiert wurde, auch wenn bei der Kompilierung eine andere tra-Datei über USING spezifiziert wurde. (Um das zu umgehen entweder alle Dateien unterschiedlich benennen, oder die Zeilennummern in den Skripten nicht bei @0 sondern z.B. @10000 beginnen lassen. Oder komplett ohne AUTO_TRA-Pfadangabe arbeiten, aber dann muss überall USING angegeben werden.).

Ich überarbeite gerade eine Mod, die sogar zwei gleichnamige d-Dateien nacheinander kompiliert (die Dialoge des "erweiterten" Freundschaftspfad werden mit anderen Triggern einfach an die kürzere Version drangehängt, also die j.dlg mit nicht-verwendeten Dialogen aufgebläht - kann man so machen, solange die Skripte sich einig sind...). Leider stimmen die Textzeilen nicht überein. Bei der Kompilierung der zweiten d-Datei wurde über USING eine andere tra-Datei spezifiziert, aber eben aufgrund des oben beschriebenen Umstands wurden erstmal die (nicht passenden) Textzeilen des "kürzeren" Freundschaftspfades verwendet. Die Dialoge, die da rauskamen, waren... interessant. :rolleyes:
 

Jastey

Matron Modderholic
Registriert
16.05.2004
Beiträge
12.922
Transactions: Reihenfolge muss beachtet werde Teil 1: Actions, die am Ende der Liste stehen müssen (weil sie nachfolgende blockieren können)

Es gibt actions, die in der Reihenfolge ganz hinten sein müssen, da sonst die dahinter nicht mehr ausgeführt werden. Hierzu gehören (nicht vollständige Liste):
-JoinParty()
-EscapeArea()
-EscapeAreaDestroy()
-MoveBetweenAreas()

Das heißt konret, wenn man die Reihenfolge so verwendet:

FALSCHE Reihenfolge -> DO ~JoinParty() SetGlobal("npcjoined","GLOBAL",1)~ <-- FALSCHE Reihenfolge

Dann wird die Varable nicht verlässlich gesetzt, und der NPC hat beim Rausschmeißen eventuell wieder vergessen, dass er in der Gruppe war und gibt den Dialog für "Global("npcjoined","GLOBAL",0)".

Richtige Reihenfolge ist daher:
DO ~SetGlobal("npcjoined","GLOBAL",1) JoinParty()~
 
Zuletzt bearbeitet:

Jastey

Matron Modderholic
Registriert
16.05.2004
Beiträge
12.922
Wenn man für andere NPCs Dialoge erstellt, die in den "joined"-Dialog sollen, dann *müssen* diese mit einem WEIGHT #-1 markiert werden. Hierbei ist es egal, ob es sich um originale BioWare / BeamDog NPCs handelt oder um Crossmod mit anderen Mod-NPCs. (Wobei man Crossmod-Banter zwischen zwei NPCs eher in die "B" Banter-dlg steckt.)

Grund ist, dass sonst Eure Dialoge nicht mehr laufen können, wenn der NPC einen PID ("Klickdialog") hat - wenn dieser vor Eurem Dialog in der dlg steht. PID sind von Natur aus "immer wahre" Dialoge, da sie ohne spezielle Konditionen aufgerufen werden (die einzige wäre, dass es der HC ist, der den NPC anspricht "IsGabber(Player1)"). Es wurde für diese Klickdialoge sozusagen der Umstand ausgenutzt, dass ein "immer wahrer" Dialogblock in der Dlg eben immer getriggert wird, und man so diesen auch zu sehen bekommt, wenn man mit dem NPC über den "Dialog"-Button im Spiel spricht.
Dies hat aber den Nachteil, dass die Engine keinen Dialog starten kann, der sich unterhalb dieses PIDs in der Dlg befindet - sofern der darunter liegende Dialog nicht eine größere "Wichtung" hat, die dazu führt, dass die Engine ihn trotz der Lage "ganz unten" als erstes aufruft.
Somit würde, wenn Euer Dialog triggern soll, die Engine jedes mal am PID "hängen bleiben" und der Spieler einen Stutterbug in seinem Spiel erleben, den man normalerweise nur beenden kann, indem man Euen Dialog durch Cheats verindert, was natürlich schade wäre.

Daher folgende Faustregeln:
-Dialoge in die joined-Dlg, die Ihr für andere NPCs in Euren Mods habt, immer mit WEIGHT #-1 taggen.
-Wenn Euer Mod-NPC einen PID hat, als eventuellen Notnagel eine Variable in den Trigger aufnehmen, mit dem der PID - über Cheats - deaktiviert werden kann. Das gibt dem Spieler die Möglichkeit, beim "Hängenbleiben" an den PIDs diese kurz zu deaktivieren, so dass der eigentliche Dialog stattfinden kann (von einer Mod, die sich nicht an den hier beschriebenen Tipp gehalten hat. ;) )

Und für Spieler:
-Mods, die PIDs zu originalen NPCs einfügen möglichst ans Ende der Installationsreihenfolge.
 
Zuletzt bearbeitet:

Maus

Senior Member
Registriert
07.08.2002
Beiträge
9.380
Schreibfehler? IsGabber?

Könnte bei Leuten, die das lesen, zu einem Code-Fehler führen ;)
 

Jastey

Matron Modderholic
Registriert
16.05.2004
Beiträge
12.922
Huch, danke @Maus , ist korrigiert.
(Hm, eigentlich gar nicht so verkehrt, da merke ich wenigstens, dass meine Weisheitenergüsse auch gelesen werden. ;) )
 

Callindor

Senior Member
Registriert
03.05.2008
Beiträge
2.180
Also ich finde diese Hinweise toll, die du hier erstellst. Die wohl größte Hürde für mich, mich mal einer NPC-Mod zu versuchen, ist das fehlende Tutorial, dass einen als absoluten Neuling an die Hand nimmt. Ist mit dem EE eigentlich eine einfachere/kompliziertere Art des Modding eingeführt worden?
 

Jastey

Matron Modderholic
Registriert
16.05.2004
Beiträge
12.922
Die EE bietet noch viel mehr Möglichkeiten, weil lauter Sachen externalisiert wurden, die vorher hardgecodet waren etc. Ich kenne mich da aber nicht so aus. Das Problem mit alten Tutorials ist eigentlich, dass die vorhandene WeiDU-Syntax mit allen möglichen fertigen Funktionen etc. um Größenordnungen komfortabler geworden ist einerseits (beispiel hier: Einfügen neuer Traveltrigger in Gebiete ist mittlerweile wirklich einfach geworden, früher war das erstmal gar nicht möglich, dann eine hochkomplexe Angelegenheit mit HEX Bytes-Zählen usw.), und neuen Standards andererseits (also wie scripte ich stabil die Dialoge mit den dazugehörigen Skripten, welche Trigger setze ich da wo hin etc.). Was mir da bei den älteren Mods so unterkommt wenn ich aktualisiere ist echt zum Heulen, aber man wusste es damals halt noch nicht besser.
Das ist aber auch ein Grund, warum ich nicht spontan ein gutes Tutorial empfehlen kann, schon gar nicht auf deutsch. Wenn Du in englisch fit bist, dann gäbe es aber schon Material, mit dem Du Dich beschäftigen könntest.
 

Jastey

Matron Modderholic
Registriert
16.05.2004
Beiträge
12.922
Ich mache einfach mal weiter.

Skripten eines stabilen Dialogaufrufs

Euer NPC hat einen joined-Dialog namens xxmyNPCJ.dlg. Ihr habt nun einen Dialog geschrieben, und dieser soll, wenn sich der NPC bei Tag in den Slums aufhält, getriggert werden. (xx steht hier für Euer Modding-Präfix).

Der Beispieldialog sei folgender:
[NPC] ~Boah, was ist denn das für eine riesige Kugel? Die war letztes mal noch nicht da!~

Euer NPC hat ein sogenanntes OVERRIDE-Skript namens xxmyNPC.bcs. In dieses Skript kommen nun die Skriptblöcke, die den Dialog aufrufen werden. Damit der Dialog auf alle Fälle triggert und nicht durch einen zeitlich ungünstigen "Kursorklick" des Spielers im Nirvana verschwindet, verwenden wir auf alle Fälle schon mal das von Kulyok zusammengefasste Prinzip des "How to ensure your banters always run when you want them to" (wie man sicherstellt, dass Dialoge immer laufen, wenn sie sollen). Kurz zusammengefasst ist das Prinzip folgendes: wenn die richtige Situation eingetreten ist, dann wird eine Variable gesetzt. Mit dieser aktiven Variable wird dann in einem separaten Skriptblock der Dialog so lange immer wieder ausgelöst, bis der Dialog wirklich stattgefunden hat. Im Dialog wird die aktive Variable "deaktiviert", indem sie auf einen anderen Wert gesetzt wird. (Der Kenner unter den Spielern ahnt es schon: ja, genau da kommen die Stutterbugs her, bei denen ein NPC konstant die ganze Zeit einen Dialog initiieren will, dieser aber aufgrund eines Bugs nicht läuft. Die Alternative aber wäre gewesen: der Dialog wird einfach übersprungen, und die Romanze / der Freundschaftspfad hängt eventuell komplett, weil die Variablen nicht mehr passen.)

Als Variable, mit der der Dialog ausgelöst werden soll, nehmen wir: Global("xxmyNPC_SlumKommentar","GLOBAL",1).

Und damit haben wir auch schon alles, was wir - im Dialog! - für das Triggern brauchen. Denn alle anderen Konditionen, also - ist der NPC in der Gruppe? Ist es wirklich Tag? Ist die Gruppe in den Slums? Kann der NPC den HC überhaupt sehen? Befinden wir uns nicht in einem Kampf? Können der NPC und der HC überhaupt sprechen, oder ist mein NPC gar gerade tot?- diese ganzen Abfragen, die sind nämlich NUR im Skript, nicht im Dialog. Der Dialog arbeitet NUR mit unserer sogenannten Triggervariablen, also mit Global("xx_meinNPC-SlumKommentar","GLOBAL",1). Der Grund ist einfach: die Trigger im Dialog dürfen nicht restriktiver sein als die im Skript, sonst kann der Dialog nicht laufen und der Spieler hat einen Stutterbug!

Dies ist der Inhalt der d.-Datei. Achtung: BEGIN xxmyNPCJ schreibt einen neuen j-dlg und darf natürlich nur einmal am Anfang verwendet werden. In allen weiteren .d-Dateien müsstet Ihr dann APPEND xxmyNPCJ ... END verwenden.
Code:
BEGIN xxmyNPCJ
IF ~Global("xxmyNPC_SlumKommentar","GLOBAL",1)~ THEN slumkommentar //wenn die Variable auf "1" steht, wird dieser Dialog gestartet. 
SAY ~Boah, was ist denn das für eine riesige Kugel? Die war letztes mal noch nicht da!~
IF ~~ THEN DO ~SetGlobal("xxmyNPC_SlumKommentar","GLOBAL",2)~ EXIT //Variable wird durch Setzen auf "2" geschlossen.
END

In das Skript des NPC kommen nun die nötigen Skriptblöcke:
Code:
/* Slumkommentar - Aktivierung */
IF
  InParty(Myself)                                             //Euer NPC ist in der Gruppe
  !StateCheck(Myself,CD_STATE_NOTVALID)   //Euer NPC kann sprechen
  See(Player1)                                                //Euer NPC sieht den HC (ist in der Nähe)
  !StateCheck(Player1,CD_STATE_NOTVALID) //der HC kann sprechen - bräuchten wir hier eigentlich nicht unbedingt
  !Detect([ENEMY])                                        //es ist kein Feind in der Nähe
  CombatCounter(0)                                      //es findet kein Kampf statt
  AreaCheck("AR0400")                                 //Gebiet ist Slums in Athkatla  -- war die erste geforderte Kondition
  TimeOfDay(DAY)                                         //Es ist Tag -- war die zweite geforderte Kondition
  Global("xxmyNPC_SlumKommentar","GLOBAL",0) //Dialog ist noch nicht gelaufen
THEN
  RESPONSE #100
      SetGlobal("xxmyNPC_SlumKommentar","GLOBAL",1) //Triggervariable ist gesetzt
END

/* Slumkommentar - Triggern des Dialogs */
IF
/* diese Konditionen frage ich noch einmal ab, damit der Dialog problemfrei triggert */
  InParty(Myself)                                             //Euer NPC ist in der Gruppe
  !StateCheck(Myself,CD_STATE_NOTVALID)   //Euer NPC kann sprechen
  See(Player1)                                                //Euer NPC sieht den HC (ist in der Nähe)
  !StateCheck(Player1,CD_STATE_NOTVALID) //der HC kann sprechen - bräuchten wir hier eigentlich nicht unbedingt
  !Detect([ENEMY])                                        //es ist kein Feind in der Nähe
  CombatCounter(0)                                      //es findet kein Kampf statt

/* von den anderen Konditionen, also Slums + Tag, bleibt nun nur noch die Triggervariable: */
  Global("xxmyNPC_SlumKommentar","GLOBAL",1) //aktive Triggervariable
THEN
  RESPONSE #100
     StartDialogNoSet(Player1)
END

Und das war's. Der zweite Skriptblock füht dazu, dass der NPC den Dialog so lange versucht auszulösen, bis er tatsächlich stattfindet. Im Dialog wird die Variable auf "2" gesetzt, und das Spiel geht weiter.

Wichtige Moddingressource: das IESDP, das gesammelte Wissen der IE-Moddingcommunity.
 

Jastey

Matron Modderholic
Registriert
16.05.2004
Beiträge
12.922
Nomenklatur: Bezeichnung für Dialoge des NPC

Hierzu auch den nachfolgenden Post beachten!

Banter, Dialoge, Einmischdialoge - was für jemanden mit wenig Dialog-Moddingerfahrung nach ein- und demselben anhören mag, bezeichnet für den alten Hasen ganz unterschiedliche Dinge:

Banter: wenn der NPC mit einem anderen NPC einen Dialog führt, ohne Antwortoptionen für den HC.

Dialog: wenn der NPC mit dem HC spricht, enthält entsprechend Antwortmöglichkeiten für den Spieler.

Einmischdialog (Interjections): wenn der NPC direkt eine Bemerkung einwirft, während ein Quest-Charakter gerade spricht (bzw. direkt überleitendbevor das Gespräch beendet wird).
 
Zuletzt bearbeitet:

Jastey

Matron Modderholic
Registriert
16.05.2004
Beiträge
12.922
Dialogdateien eines aufnehmbaren NPC - welche für was?

Für einen aufnehmbaren NPC werden in der pdialog.2da und der interdia.2da die Namen der Dialogdateien definiert, die die Engine für diesen NPC aufrufen kann. Welche gibt es denn da so und wofür sind die eigentlich?
Achtung: dies ist für BGII(:EE), BGT und BG:EE. In SoD und vor allem EET gibt es weitere 2da-Dateien hierfür.

Schauen wir uns mal den Eintrag an, der in der Ajantis BGII-Mod für Ajantis gesetzt wird:
Code:
APPEND ~pdialog.2da~
~C#Ajantis     C#AjanP     C#AjanJ     C#AjanD     C#Aja25P     C#Aja25J         C#Aja25D     C#Ajan25~
UNLESS ~C#Ajantis~

Für die Interdia.2da steht da folgendes:
Code:
APPEND ~interdia.2da~
~C#Ajantis     C#AjanB      C#Aja25B~
UNLESS ~C#Ajantis~

Also, wenn es noch einen Eintrag für Ajantis gibt, dann sollen diese Einträge für Ajantis gepatcht werden: C#AjanP, C#AjanJ, C#AjanD, C#Aja25P, C#Aja25J, C#Aja25D, C#Ajan25, C#AjanB, C#Aja25B. Und was bedeuten die jetzt bitte?

C#AjanP: "P" kennzeichnet im originalen BG den sogenannten "Kickout"-Dialog. Also, der Dialog, der getriggert wird, wenn sich der NPC nicht mehr in der Gruppe befindet bzw. wenn man ihn gerade über den "Gruppe Ändern" (Reform Party) Knopf aus der Gruppe entlassen hat, oder wenn er irgendwo rumsteht und man ihn dann anspricht, umihn wieder in die Gruppe aufzunehmen. Hierzu auch den Tipp für das gescriptete Verlassen der Gruppe beachten.

C#AjanJ: "J" steht für den "joined" Dialog. Dialoge in dieser dlg werden mit StartDialogNoSet() oder Dialogue() gestartet. Das ist der Dialog, mit dem der NPC spricht, wenn er sich in der Gruppe befindet, und zu einer ganz bestimmten Sache etwas sagen soll, also einen geskripteten Dialog in einem ganz bestimmten Moment starten soll, oder für Einmischdialoge. Alle geskripteten Dialoge gehen hier hinein, also auch Romanzen- oder Freundschaftsdialoge.

C#AjanD: "D" steht für das "Dreamscript" und hierbei handelt es sich eigentlich um ein Skript, also bcs. Dieses Skript wird aufgerufen, wenn der Spieler den "Rasten"-Knopf drückt oder über Skript RestParty() ausgeführt wird. Hierüber lassen sich zu. Beispiel Dialoge triggern, die "am Abend" vor dem Schlafengehen passieren sollen. Auch die Träume in BGII werden hierüber ausgelöst, da es auch ein "Dreamscript" für den "Player1" gibt.

C#Aja25P: Die "25" steht in BGII für ToB - warum auch immer. Daher handelt es sich hier um den "Kickout"-Dialog für ToB.

C#Aja25J: analog: der Joined-Dialog für ToB.

C#Aja25D: Dreamscript für ToB.

C#Ajan25: dies ist das Override Skript für ToB. Die Engine schaltet in ToB automatisch auf dieses Skript um. Außer in EET, dort muss man es skripten (bzw. die NPC-Transitionfunktion verwenden).

C#AjanB: "B" steht für Banter. In BGII steht das "B" am Anfang des dlg-Namens, aber wenn man das als Modder machte, hätte man gerade sein Präfix ad-absurdum geführt, daher sollte das B am Ende des Namens stehen. Die dlg kann man gescriptet aufrufen über Interact(). Allerdings beinhaltet die B.dlg auch die ganzen ungescripteten NPC-NPC-Banter, so dass dieser Dialog nicht für gescriptete Banter verwendet weden sollte - auch wenn es im Originalspiel für die Romanzen so gehandhabt wurde. ;) Die B.dlg wird von der Engine immer wieder willkürlich aufgerufen, so dass die NPC-NPC Banter hier ohne Skriptaufrufe im Lauf des Spiels getriggert werden.

C#Aja25B: Banter-Dialogname für ToB.


Und was fehlt? Richtig - der Aufnahmedialog. Also der, mit der NPC spricht, wenn man ihn das alleraller erste mal begegnet, und bevor er das erste mal in der Gruppe ist. Dieser Dialogname ist der einzige, den man direkt in der cre-Datei hinterlegen kann, daher gibt es dafür wohl keinen 2da-Eintrag. Hierfür wähle ich gerne einen Namen ohne "Postfix", z.B. C#Ajan.dlg für SoA und C#Aja25.dlg für ToB.

Übrigens: alle Dialognamen dürfen nur maximal 8 Zeichen lang sein!
 
Oben