[Modding] [gelöst] Warum looped dieser Dialog? Brauche Hilfe.

Jastey

Matron Modderholic
Registriert
16.05.2004
Beiträge
12.946
Update: ich habe eine funktionierende Lösung gefunden. Vielen Dank an alle Mitwirkenden!
Wieso das ursprünglich nicht geklappt hat verstehe ich zwar noch immer nicht wirklich, aber zumindest klappt meine neuste Version jetzt.

--------
Ich habe folgenden Testdialog gescripted. Wie man beim state "ingredient_04" landet ist irrelevent (EDIT: war es natürlich nicht, s.u.). Es geht darum, dass der Dialog zwischen dem State "ingredient_05" und State "ingredient_06" looped, und zwar ohne Ende.
Da ich globale Variablen setze und Abfrage, dürfte das eigentlich nicht sein. Es befinden sich genug States zwischen dem Setzen und dem Abfragen der Variablen. Beide States dürften nach den normalen Regeln der Engine nur einmal erscheinen und dann müsste der Dialog enden, da die Variablen auf "1" stehen. Tun sie aber nicht, es loopt. Ich weiß nicht mehr weiter, sieht jemand was?
Code:
/* octopus ink */
IF ~~ THEN ingredient_04
SAY @754 /* ~Octopus ink!~ */
= @759 /* ~Always needed for the right consistency of magical ink.~ */
IF ~~ THEN DO ~SetGlobal("C#Br_HaveSaphire","GLOBAL",1)~ + ingredient_06
END

/* potion of regeneration */
IF ~~ THEN ingredient_05
SAY @762 /* ~A potion of Regeneration!~ */
= @983 /* ~A powerful magic, and useful in more than one way if you know how.~ */
IF ~~ THEN EXIT
IF ~Global("C#Br_HaveSaphire","GLOBAL",0)~ THEN DO ~SetGlobal("C#Br_HaveSaphire","GLOBAL",1)~ + ingredient_06
END

/* star spahire */
IF ~~ THEN ingredient_06
SAY @984 /* ~A Star Saphire!~ */
= @985 /* ~Always a sight for sore eyes.~ */
IF ~~ THEN EXIT
IF ~Global("C#Br_HavePotion","GLOBAL",0)~ THEN DO ~SetGlobal("C#Br_HavePotion","GLOBAL",1)~ + ingredient_05
END
 
Zuletzt bearbeitet:

Maus

Senior Member
Registriert
07.08.2002
Beiträge
9.400
Ist "Unterstrich" zulässig in Variablennamen? Wenn nicht hättest du keine Variablen gemacht und es würde einfach loopmässig laufen. Allerdings hätte ich da dann eine Fehlermeldung beim Kompilieren erwartet.
 

Acifer

Senior Member
Registriert
27.04.2019
Beiträge
2.190
Puh, das sieht eigentlich alles gut aus. Hast Du einmal versucht, zwischen ingredient_06 und ingredient_05 zusätzlich einen kleinen Unterdialog zu schieben, um der Engine "noch mehr Zeit" zu geben?
Ich hatte ganz, ganz selten einmal das Problem, dass WeiDU eine kleinere Änderung im Dialog nicht richtig kompiliert hatte. Hast Du einmal geschaut, ob das DLG-File in Ordnung ist? Das mit den "_" in Dialogen ist auch ein interessanter Gedanke.
 

Jastey

Matron Modderholic
Registriert
16.05.2004
Beiträge
12.946
@Maus Ja, Unterstrich hab ich ganz häufig.
Wenn ich den Dialog so scripte, dass er endet, iat die Variabke danach gesetzt (per Cheats überpüft).
Wenn ich das ganze mit dem Nehmen von Items aus dem Gruppeninventar verbinde loppt der (ursprüngliche) Dialog auch nicht, was nur geht, wird nn die Variablen gesetzt sind.
Wenn ich nur die Variablen setze loopt er. :confused:
Das macht einfach koinän Sinn!
 

Jastey

Matron Modderholic
Registriert
16.05.2004
Beiträge
12.946
@Acifer es sind jetzt schon 3+ Zeilen/States zwischen Setzen und Abfrage, das reicht "normalerweise" dicke - ich verwende das in jedem sonstigen Dialog und dann nochmal einmal mehr!
Ich hatte mir eine vorherige Version mal angesehen, aber ich werde diesen auch nochmal dekompilieren lassen und auch den Text nochmal ändern um ganz sicher zu gehen. Ich komm mir mittlerweile hochgradig veräppelt vor von dem ganzen.

Danke für Eure Rückmsungen!
 

Jastey

Matron Modderholic
Registriert
16.05.2004
Beiträge
12.946
@Callindor ohne Bedingung wird das immer ausgeführt, das soll so sein.

So sieht der Dialog von oben installiert und dekompiliert aus:
IF ~~ THEN BEGIN 12 // from: 11.0 11.1
SAY #97703 /* ~Octopus ink!~ */
IF ~~ THEN GOTO 13
END

IF ~~ THEN BEGIN 13 // from: 12.0
SAY #97704 /* ~Always needed for the right consistency of magical ink.~ */
IF ~~ THEN DO ~SetGlobal("C#Br_HaveSaphire","GLOBAL",1)
~ GOTO 16
END

IF ~~ THEN BEGIN 14 // from: 17.1
SAY #97705 /* ~A potion of Regeneration!~ */
IF ~~ THEN GOTO 15
END

IF ~~ THEN BEGIN 15 // from: 14.0
SAY #97706 /* ~A powerful magic, and useful in more than one way if you know how.~ */
IF ~~ THEN EXIT
IF ~ Global("C#Br_HaveSaphire","GLOBAL",0)
~ THEN DO ~SetGlobal("C#Br_HaveSaphire","GLOBAL",1)
~ GOTO 16
END

IF ~~ THEN BEGIN 16 // from: 13.0 15.1
SAY #97707 /* ~A Star Saphire!~ */
IF ~~ THEN GOTO 17
END

IF ~~ THEN BEGIN 17 // from: 16.0
SAY #97708 /* ~Always a sight for sore eyes.~ */
IF ~~ THEN EXIT
IF ~ Global("C#Br_HavePotion","GLOBAL",0)
~ THEN DO ~SetGlobal("C#Br_HavePotion","GLOBAL",1)
~ GOTO 14
END

Und es loopt immer noch! OK, ich werde mal ein neues Spiel starten. Vielleicht liegt's an meinem Save. Fragt mich nicht, wie das an einem Save liegen kann, aber mehr fällt mir gerade nicht ein.
 

Maus

Senior Member
Registriert
07.08.2002
Beiträge
9.400
SaveGame wäre jetzt mein letzter Tip gewesen, dass da irgendwas falsch abgespeichert wurde bei einem der Updates...
 

Jastey

Matron Modderholic
Registriert
16.05.2004
Beiträge
12.946
Neues Spiel, Brandock neu aufgenommen, dann zum Queststatus hingecheated - selber Loop, der streng genommen ja nichts mit Brandock oder seinem Quest zu tun hat, da alle anderen Abfragen entfent sind. Ich bin mit meinem Latein am Ende.
 

Maus

Senior Member
Registriert
07.08.2002
Beiträge
9.400
Hast du dir die dlg selbst mal angeschaut? NI z.B.? Wäre zwar seltsam, dass da etwas faul ist und bei der Rücktransformation alles in Ordnung, aber die "normalen" Sachen haben wir ja schon durch...
 

Jastey

Matron Modderholic
Registriert
16.05.2004
Beiträge
12.946
Ich bin mittlerweile bei "neues BGT aufsetzen" angekommen. Dazu muss ich mich aber erstmal aufraffen, da ich natürlich keine saubere Sicherungskopie gemacht hatte, wozu auch.
 

Jastey

Matron Modderholic
Registriert
16.05.2004
Beiträge
12.946
Argent hat mich wahrscheinlich gerettet. "Wahrscheinlich" schreibe ich deshalb, weil ich es noch nicht auprobiert habe. Stellt sich raus: es liegt wohl an einem davor liegenden DestroyItem(), das Brandock ausführt. Das blockiert alle dahinter liegenden Befehle im selben Dialog. Ich zitiere:
The action DestroyItem() appears to block further script execution. I remember that lynx (or Avenger?) mentioned some time ago that only script actions listed in INSTANT.IDS are safe to be used in dialogs. Most other script actions block further script execution.
Link zum Thread bei G3.

Da wäre ich nie drauf gekommen! Zumindest nicht mir diesem Rchner, der wäre zwischenzeitig aus dem Fenster geflogen.
 

Jastey

Matron Modderholic
Registriert
16.05.2004
Beiträge
12.946
Dann hättest Du den Befehl DestroyItem() vielleicht etwas zu wörtlich genommen...
Hahahaha! :D :D
Nach dem Motto: wenn's im verflixten Spiel schon nicht klappt, dann mach ich jetzt was richtiges kaputt! - So weit hatte ich gar nicht gedacht. Ich hatte nur meinen Aggressionslevel von heute Vormittag extrapoliert.

Tatsächlich lag es an dem DestroyItem() von Brandock. Was ich also für eine Verschlankung des Codes hielt (wenn ich schon weiß, dass das Item sich bei ihm im Inventar befindet, kann er es bitte selbst entfernen) stellte sich also als NoGo heraus. Was ich nicht weiß ist, ob es am "Familiarstatus" im 7. GMM lag oder ob das auch für richtige Gruppenmitglieder gilt. Jedenfalls blockierte das hier alle nachfolgenden Transaktionen des gesamten Dialogs:
ActionOverride("C#Brandock",DestroyItem("c#broink"))
Wohingegen das Ausführen über einen Questcharakter der nicht zur Gruppe gehört kein Problem bereitet:
ActionOverride("FIREBE",TakePartyItem("c#broink"))
ActionOverride("FIREBE",DestroyItem("c#broink"))
Und das, obwohl wir uns hier in Elvenhairs dlg befinden, nicht etwa in Brandocks!
 

Taimon

Infinity Engineer
Registriert
25.11.2001
Beiträge
1.501
Kann ich bei Bedarf ausführlicher erklären, aber ich bin mir nicht sicher, ob das wirklich gewollt ist. :)

Vielleicht ganz grob:
Jeder "Akteur" in der Engine (CGameAIBase) hat so etwas wie eine Liste von Aktionen (Action-Queue), die er ausführt oder demnächst ausführen soll.
Während eines die Dialogs werden die Aktionen offenbar im Kontext des jeweiligen Akteurs in diese Queue eingereiht. (Müsste ich mir nochmal genauer anschauen.)
Zusätzlich steht während des Dialogs die Uhr still (Worldtimer läuft nicht). In diesem Zustand können nur Aktionen ausgeführt werden, die "instant" sind.
Und da die Aktionen der Reihe nach durchgeführt werden (Queue) blockiert das DestroyItem() im Dialog das "SetGlobal()", wenn beide vom selben Akteur durchgeführt werden sollen.
 

Jastey

Matron Modderholic
Registriert
16.05.2004
Beiträge
12.946
@Taimon sehr gerne.
Während eines die Dialogs werden die Aktionen offenbar im Kontext des jeweiligen Akteurs in diese Queue eingereiht. (...) Und da die Aktionen der Reihe nach durchgeführt werden (Queue) blockiert das DestroyItem() im Dialog das "SetGlobal()", wenn beide vom selben Akteur durchgeführt werden sollen.
Das klänge für mich logisch.
Das Problem in diesem Fall: Elvenhair spricht (FIREBE.dlg), also müsste er doch die Aktionen ausführen? Es blockiert aber ein ActionOverride(DestroyItem()) für Brandock die Aktionen - wenn Elvenhair sie ausführen soll, funktioniert alles.
Elvenhairs Dialog wurde zwar durch Brandocks und des HCs Anwesenheit ausgelöst, hat doch aber ansonsten mit Bandock nichts zu tun?
 

Jastey

Matron Modderholic
Registriert
16.05.2004
Beiträge
12.946
Hier nochmal der "ganze" (gestutzte) Dialog:
Code:
APPEND FIREBE

/* octopus ink */
IF WEIGHT #-1
~OR(2)
    Global("C#Br_BookRestore","GLOBAL",2)
    Global("C#Br_BookRestore","GLOBAL",4)
OR(2) PartyHasItem("c#br0001") HasItem("c#br0001","C#Brandock")
OR(2) PartyHasItem("c#broink") HasItem("c#broink","C#Brandock")
Global("C#Br_HaveInk","MYAREA",0)
InMyArea(Player1)
InMyArea("C#Brandock")
OR(2) InParty("C#Brandock") Global("C#BrandockJoined","GLOBAL",2)
!StateCheck("C#Brandock",CD_STATE_NOTVALID)~ THEN ingredient_01
SAY @751 /* ~Ah, the young <CHARNAME> and <PRO_HISHER> unfortunate friend. I see you have ingredients I requested.~ */
IF ~~ THEN DO ~ActionOverride("FIREBE",TakePartyItem("c#broink"))
ActionOverride("FIREBE",DestroyItem("c#broink"))
SetGlobal("C#Br_HaveInk","MYAREA",1)~ + ingredient_04
IF ~HasItem("c#broink","C#Brandock")~ THEN DO ~ActionOverride("C#Brandock",DestroyItem("c#broink"))
SetGlobal("C#Br_HaveInk","MYAREA",1)~ + ingredient_04
END

/* octopus ink */
IF ~~ THEN ingredient_04
SAY @754 /* ~Octopus ink!~ */
= @759 /* ~Always needed for the right consistency of magical ink.~ */
IF ~~ THEN DO ~SetGlobal("C#Br_HaveSaphire","GLOBAL",1)~ + ingredient_06
END

/* potion of regeneration */
IF ~~ THEN ingredient_05
SAY @762 /* ~A potion of Regeneration!~ */
= @983 /* ~A powerful magic, and useful in more than one way if you know how.~ */
IF ~~ THEN EXIT
IF ~Global("C#Br_HaveSaphire","GLOBAL",0)~ THEN DO ~SetGlobal("C#Br_HaveSaphire","GLOBAL",1)~ + ingredient_06
END

/* star spahire */
IF ~~ THEN ingredient_06
SAY @984 /* ~A Star Saphire!~ */
= @985 /* ~Always a sight for sore eyes.~ */
IF ~~ THEN EXIT
IF ~Global("C#Br_HavePotion","GLOBAL",0)~ THEN DO ~SetGlobal("C#Br_HavePotion","GLOBAL",1)~ + ingredient_05
END

END //APPEND
 

Taimon

Infinity Engineer
Registriert
25.11.2001
Beiträge
1.501
Das Problem in diesem Fall: Elvenhair spricht (FIREBE.dlg), also müsste er doch die Aktionen ausführen?
Das ist in der Engine manchmal nicht ganz so eindeutig, aber ja, so hätte ich das auch interpretiert.
Im Dialog-Kontext hab' ich mir damals die Begriffe "speaker" und "gabber" mit folgenden Kommentaren notiert:
Code:
00000030 gabber          object_id ?             ; was spoken to (usually constant during dialogue)
00000034 speaker         object_id ?             ; intiated dialogue (the various dialogue partners)
Die Aktionen werden jeweils dem Speaker hinzugefügt. (Die Zahlen am Anfang ignorieren, sind Offsets in der internen Dialog-Struktur.)
Es blockiert aber ein ActionOverride(DestroyItem()) für Brandock die Aktionen - wenn Elvenhair sie ausführen soll, funktioniert alles.
Spontan ergibt das für mich erst einmal keinen Sinn. Es sei denn, das hängt mit der "speaker" vs. "gabber" Geschichte zusammen.

/Edit:
Testweise könnte man mal das SetGlobal() via ActionOverride() jemand anderen machen lassen und so schauen, bei wem es nicht blockiert wird.
 
Zuletzt bearbeitet:

Jastey

Matron Modderholic
Registriert
16.05.2004
Beiträge
12.946
Testweise könnte man mal das SetGlobal() via ActionOverride() jemand anderen machen lassen und so schauen, bei wem es nicht blockiert wird.
Interessante Idee.
In diesem konkreten Beispiel klappt nun alles wie es soll, wenn Elvenhair ("FIREBE") selbst das Item nimmt und zerstört. Wie gesagt :confused: warum das in seinem eigenen dlg die SetGlobal()-Befehle nicht blockiert und Brandock es tut, aber - das klappt jetzt und ich fass das nicht mehr an.. Ich habe das erstmal unter "DestroyItem() Befehl von Gruppenmitgliedern kann die Befehlsausführung im Dialog behindern, bei Questcharakteren nicht" abgespeichert.
Vielen Dank für Deine Erklärungen!
 

Taimon

Infinity Engineer
Registriert
25.11.2001
Beiträge
1.501
Kannst du mir sagen, mit welcher Engine du auf das Problem gestoßen bist?
Meine Aussagen beziehen sich immer nur auf die originale ToB-Engine.
Es kann sein, dass sich beispielsweise die BG2EE anders verhält.

Ich hab heute kurz versucht, das Problem nachzustellen, bei mir gab es aber keine Dialogschleife.
Da ich Brandock nicht installiert habe, musste ich den Dialog leicht modifizieren:
Code:
APPEND FIREBE

/* octopus ink */
IF WEIGHT #-1
~HasItem("btest1",Player1)
Global("C#Br_HaveInk","MYAREA",0)
InMyArea(Player1)~ THEN ingredient_01
SAY ~Ah, the young <CHARNAME> and <PRO_HISHER> unfortunate friend. I see you have ingredients I requested.~
IF ~~ THEN DO ~ActionOverride("FIREBE",TakePartyItem("btest1"))
ActionOverride("FIREBE",DestroyItem("btest1"))
SetGlobal("C#Br_HaveInk","MYAREA",1)~ + ingredient_04
IF ~HasItem("btest1",Player1)~ THEN DO ~ActionOverride(Player1,DestroyItem("btest1"))
SetGlobal("C#Br_HaveInk","MYAREA",1)~ + ingredient_04
END

/* octopus ink */
IF ~~ THEN ingredient_04
SAY  ~Octopus ink!~
= ~Always needed for the right consistency of magical ink.~
IF ~~ THEN DO ~SetGlobal("C#Br_HaveSaphire","GLOBAL",1)~ + ingredient_06
END

/* potion of regeneration */
IF ~~ THEN ingredient_05
SAY ~A potion of Regeneration!~
= ~A powerful magic, and useful in more than one way if you know how.~
IF ~~ THEN EXIT
IF ~Global("C#Br_HaveSaphire","GLOBAL",0)~ THEN DO ~SetGlobal("C#Br_HaveSaphire","GLOBAL",1)~ + ingredient_06
END

/* star spahire */
IF ~~ THEN ingredient_06
SAY ~A Star Saphire!~
= ~Always a sight for sore eyes.~
IF ~~ THEN EXIT
IF ~Global("C#Br_HavePotion","GLOBAL",0)~ THEN DO ~SetGlobal("C#Br_HavePotion","GLOBAL",1)~ + ingredient_05
END

END //APPEND
Die WeiDU-Version sollte hoffentlich keine Rolle spielen, ich hab' da eine von vor 10 Jahren genommen.
 
Oben