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

Jastey

Matron Modderholic
Registriert
16.05.2004
Beiträge
12.922
@Taimon danke für Deine Mühe! Ich bin auf BGT 1.21, weidu v246 wobei das keinen Unterschied machen sollte.
Brandock war im "7. Gruppenmitgliedsmodus" also als Familiar in der Gruppe, als der Dialog von Firebead durch seine Anwesenheit (und die vom HC) gestartet wurde bzw. er das Item in seinem Inventar zerstören sollte.
Vielleicht lag es daran. Die Engine spinnt ziemlich in diesem Fall: Items in seinem Inventar werden nicht über PartyHasItem() erkannt wenn er im 7.GMM ist; es werden auch Items nicht (nur) in seinem Inventar erzeugt über GiveItemCreate wenn er 7. GMM ist, sondern es gibt dann zwei Exemplare, eins bei ihm, eins beim HC. Die Übergabe von Items an Questcharaktere wird nicht ausgeführt wenn er 7. GMM ist (also z.B. "ActionOverride("C#Brandock",GiveItem("c#broink","FIREBE"))"). Er kann nur Items dem HC geben ("ActionOverride("C#Brandock",GiveItem("c#broink",Player1))"), so dass sie danach von Firebead aus dem Gruppeninventar genommen werden etc.
Insgesamt ist das alles ziemlich unvorhersehbar (aus meiner Sicht).

Ach, und wenn er ein Item aus einem Nimmervollen Beutel /seiner Buchtasche an den HC übergibt als 7.GMM und man ihn danach wieder richtig in die Gruppe aufnimmt, dann stürzt das Spiel ab (friert ein mit blauem Kreiskursor auf Windows). Das war allerdings in der BGII:EE, in BGT hatte ich das noch nicht probiert.
 

Taimon

Infinity Engineer
Registriert
25.11.2001
Beiträge
1.501
Aus irgendeinem Grund kann ich das bei mir nicht nachstellen. Selbst direkt mit Deinem Mod nicht, wenn ich Brandock als Familiar aufnehme.
(Ich hab "c#bran01" gespawnt, die Spawnvariable gesetzt, ihn angesprochen, BookRestore auf 4 gesetzt und ihm die Items gegeben. Anschließend dann "firebe" gespawnt.)
Da muss es noch eine Zusatzbedingungen geben. (Mein Test war mit BGT v1.05b)

Aber gut, Du hast eine funktionierende Lösung. Lohnt sich jetzt nicht, hier weiter zu forschen.
 

Jastey

Matron Modderholic
Registriert
16.05.2004
Beiträge
12.922
Sehr interessant. Wenn mir was auf- oder einfällt melde ich mich nochmal. Spontan wüsste ich nicht, was es gewesen sein könnte. Zumindest ist mir nicht bewusst, dass er unter einem Effekt o.ä. stand (außer denen als Familiar damit er nicht sterben kann).
Ich sag's mal so: ich freue mich jetzt einfach mal, dass es bei jemand anderem besser geklappt hat als bei mir. Normalerweise kriege ich immer Bugreports für Dinge, die bei mir problemlos geklappt haben...
Danke für's Ausprobieren!
 

Taimon

Infinity Engineer
Registriert
25.11.2001
Beiträge
1.501
Mit einer neuen BGT-Installation kann ich es jetzt doch nachstellen. Die Situation ist bei mir aber leicht anders, als bisher vermutet.
Wenn man Brandock als Familiar aufnimmt, muss man ihn ja vorher aus der Gruppe schmeißen. Dabei werden automatisch Questgegenstände (Critical Items) aus seinem Inventar der Party übergeben.
Ich hatte ihm die Tinte schon gegeben, bevor er Familiar wurde. Sie landet nach dem Rausschmiss dann bei Player1.
Code:
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
Im Dialog mit Firebead triggert also immer die obere Response, da das HasItem("c#broink","C#Brandock") nicht zutrifft.
Das muss bei Dir auch so sein, denn Du hast ja die Meldung "Gruppe hat Gegenstände verloren" gesehen. Die kommt bei TakePartyItem().
Und in diesem Fall ist es dann wahrscheinlich so wie vermutet, dass das DestroyItem() das SetGlobal() blockiert.

Warum ich das mit meiner alten Installation nicht nachstellen konnte, ist mir aber weiterhin schleierhaft.
Ich vermute ein Timingproblem, da das Ausführen der Aktionen und die Anzeige des Dialogs in unterschiedlichen Threads passiert.

/Edit:
Mittlerweile ist mir klar, warum die alte Installation keine Probleme hatte. Der Scriptname für Firebead ist nicht gesetzt, deswegen klappt das ActionOverride() nicht.
Liegt also wahrscheinlich an der alten BGT-Version.
 
Zuletzt bearbeitet:

Jastey

Matron Modderholic
Registriert
16.05.2004
Beiträge
12.922
Wow, Du hast Recht, das ist als critical item getaggt. LOL Das ist jetzt kein bisschen peinlich.
Funktioniert denn das folgende bei Dir auch, das funktionierte dann nämlich bei mir (die Cutscne habe ich mal rausgenommen). Also, vorausgesetzt Du hast Lust, das noch weiter zu testen.
Code:
/* Brandock comes with ingredients */
/* POTN42 - potion of Regeneration */
/* Star Sapphire MISC41.itm */


/* 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 ~SetGlobal("C#Br_HaveInk","MYAREA",1)~ + ingredient_04
IF ~HasItem("c#broink","C#Brandock")~ THEN DO ~ActionOverride("C#Brandock",GiveItem("c#broink",Player1))
SetGlobal("C#Br_HaveInk","MYAREA",1)~ + ingredient_04
END

/* potion of regeneration */
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("POTN42") HasItem("POTN42","C#Brandock")
Global("C#Br_HavePotion","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_02
SAY @751 /* ~Ah, the young <CHARNAME> and <PRO_HISHER> unfortunate friend. I see you have ingredients I requested.~ */
IF ~HasItem("POTN42","C#Brandock")~ THEN DO ~ActionOverride("C#Brandock",GiveItem("POTN42",Player1)) SetGlobal("C#Br_HavePotion","MYAREA",1)~ + ingredient_05
IF ~PartyHasItem("POTN42")~ THEN DO ~SetGlobal("C#Br_HavePotion","MYAREA",1)~ + ingredient_05
END

/* star saphire */
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("MISC41") HasItem("MISC41","C#Brandock")
Global("C#Br_HaveSaphire","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_03
SAY @751 /* ~Ah, the young <CHARNAME> and <PRO_HISHER> unfortunate friend. I see you have ingredients I requested.~ */
IF ~HasItem("MISC41","C#Brandock")~ THEN DO ~ActionOverride("C#Brandock",GiveItem("MISC41",Player1))
SetGlobal("C#Br_HaveSaphire","MYAREA",1)~ + ingredient_06
IF ~PartyHasItem("MISC41")~ THEN DO ~SetGlobal("C#Br_HaveSaphire","MYAREA",1)~ + ingredient_06
END

/* octopus ink */
IF ~~ THEN ingredient_04
SAY @754 /* ~Octopus ink!~ */
IF ~~ THEN DO ~ActionOverride("FIREBE",TakePartyItem("c#broink"))
ActionOverride("FIREBE",DestroyItem("c#broink"))~ + ingredient_04_1
END

IF ~~ THEN ingredient_04_1
SAY @759 /* ~Always needed for the right consistency of magical ink.~ */
IF ~~ THEN + not_all_ingredients
IF ~Global("C#Br_HaveInk","MYAREA",1) Global("C#Br_HavePotion","MYAREA",1) Global("C#Br_HaveSaphire","MYAREA",1)~ THEN DO ~ActionOverride("C#Brandock",GiveItem("c#br0001",Player1))~ + bookrestore
IF ~Global("C#Br_HaveInk","MYAREA",1) Global("C#Br_HavePotion","MYAREA",1) Global("C#Br_HaveSaphire","MYAREA",1)
PartyHasItem("c#br0001")~ THEN + bookrestore
IF ~Global("C#Br_HaveSaphire","MYAREA",0)
HasItem("MISC41","C#Brandock")
~ THEN DO ~ActionOverride("C#Brandock",GiveItem("MISC41",Player1))
SetGlobal("C#Br_HaveSaphire","MYAREA",1)~ + ingredient_06
IF ~Global("C#Br_HaveSaphire","MYAREA",0) PartyHasItem("MISC41")~ THEN DO ~SetGlobal("C#Br_HaveSaphire","MYAREA",1)~ + ingredient_06
IF ~Global("C#Br_HavePotion","MYAREA",0) HasItem("POTN42","C#Brandock")~ THEN DO ~ActionOverride("C#Brandock",GiveItem("POTN42",Player1))
SetGlobal("C#Br_HavePotion","MYAREA",1)~ + ingredient_05
IF ~Global("C#Br_HavePotion","MYAREA",0) PartyHasItem("POTN42")~ THEN DO ~SetGlobal("C#Br_HavePotion","MYAREA",1)~ + ingredient_05
END

/* potion of regeneration */
IF ~~ THEN ingredient_05
SAY @762 /* ~A potion of Regeneration!~ */
IF ~~ THEN DO ~ActionOverride("FIREBE",TakePartyItemNum("POTN42",1))
ActionOverride("FIREBE",DestroyItem("POTN42"))~ + ingredient_05_1
END

IF ~~ THEN ingredient_05_1
SAY @983 /* ~A powerful magic, and useful in more than one way if you know how.~ */
IF ~~ THEN + not_all_ingredients
IF ~Global("C#Br_HaveInk","MYAREA",1) Global("C#Br_HavePotion","MYAREA",1) Global("C#Br_HaveSaphire","MYAREA",1)~ THEN DO ~ActionOverride("C#Brandock",GiveItem("c#br0001",Player1))~ + bookrestore
IF ~Global("C#Br_HaveInk","MYAREA",1) Global("C#Br_HavePotion","MYAREA",1) Global("C#Br_HaveSaphire","MYAREA",1)
PartyHasItem("c#br0001")~ THEN + bookrestore
IF ~Global("C#Br_HaveSaphire","MYAREA",0)
HasItem("MISC41","C#Brandock")~ THEN DO ~ActionOverride("C#Brandock",GiveItem("MISC41",Player1))
SetGlobal("C#Br_HaveSaphire","MYAREA",1)~ + ingredient_06
IF ~Global("C#Br_HaveSaphire","MYAREA",0) PartyHasItem("MISC41")~ THEN DO ~SetGlobal("C#Br_HaveSaphire","MYAREA",1)~ + ingredient_06
END

/* star spahire */
IF ~~ THEN ingredient_06
SAY @984 /* ~A Star Saphire!~ */
IF ~~ THEN DO ~ActionOverride("FIREBE",TakePartyItemNum("MISC41",1))
ActionOverride("FIREBE",DestroyItem("MISC41"))~ + ingredient_06_1
END


IF ~~ THEN ingredient_06_1
SAY @985 /* ~Always a sight for sore eyes.~ */
IF ~~ THEN + not_all_ingredients
IF ~Global("C#Br_HaveInk","MYAREA",1) Global("C#Br_HavePotion","MYAREA",1) Global("C#Br_HaveSaphire","MYAREA",1)~ THEN DO ~ActionOverride("C#Brandock",GiveItem("c#br0001",Player1))~ + bookrestore
IF ~Global("C#Br_HaveInk","MYAREA",1) Global("C#Br_HavePotion","MYAREA",1) Global("C#Br_HaveSaphire","MYAREA",1)
PartyHasItem("c#br0001")~ THEN + bookrestore
END

IF ~~ THEN not_all_ingredients
SAY @986 /* ~Come back when you have all needed ingredients.~ */
IF ~~ THEN EXIT
END

IF ~~ THEN bookrestore
SAY @987 /* ~Let us begin with preserving the remaining book snippets against further destruction, shall we?~ */
IF ~~ THEN DO ~ActionOverride("FIREBE",TakePartyItem("c#br0001"))
ActionOverride("FIREBE",DestroyItem("c#br0001")) SetGlobal("C#Br_BookRestore","GLOBAL",5)
//ClearAllActions() StartCutSceneMode() StartCutScene("c#brcu11")
~ EXIT
END
 

Taimon

Infinity Engineer
Registriert
25.11.2001
Beiträge
1.501
Hier muss niemandem irgendwas peinlich sein. Die Tätigkeit ist nun mal recht komplex, da macht man zwangsläufig Fehler. (Geht zumindest mir so.)

Funktioniert denn das folgende bei Dir auch, das funktionierte dann nämlich bei mir (die Cutscne habe ich mal rausgenommen).
Ja, ging ohne Probleme. Wenn ich das richtig sehe, sind da auch gar keine Loops möglich, da es nur eine lineare Abfolge von States ist.
 

Jastey

Matron Modderholic
Registriert
16.05.2004
Beiträge
12.922
Wenn ich das richtig sehe, sind da auch gar keine Loops möglich, da es nur eine lineare Abfolge von States ist.
Das stimmt, ich hatte die Transaktionen die gar nicht auftreten können wegen der Reihenfolge entfernt. "Trotzdem" werden hier jetzt alle Variablen gesetzt, sonst würde es am Ende nicht weitergehen sondern Elfenhaar nur nach weiteren Zutaten fragen. Jetzt muss ich mir noch überlegen, ob ich den Critical Item Tag für die Tinte rausnehme wie ich es eigentlich schon lange geplant hatte.
Das Problem war also nicht mit dem 7. GMM verbunden sondern das DestroyItem von Elfenhaar blockierte das "SetGlobal", wenn DestroyItem vorher stattfand. In der jetzigen Version setze ich erst die Variable und dann im nächsten State wird das Item von Elfenhaar genommen und zerstört und das klappt ja offensichtlich. Lustigerweise klappen auch alle SetGlobals danach, was bei meinem Problembeispiel nicht der Fall war. Im Grunde verstehe ich jetzt noch weniger, warum es jetzt funktioniert und vorher nicht. Aaaber ich gucke dem geschenkten Gaul jetzt nicht (mehr) in den Maul und freue mich, dass es so funktioniert wie es funktioniert.
Vielen Dank für's Testen!
 

Taimon

Infinity Engineer
Registriert
25.11.2001
Beiträge
1.501
Noch ein paar Erkenntnisse, die Dir wahrscheinlich nicht gefallen werden:
Dein jetztiger Code funktioniert nur, weil das DestroyItem() die letzte Aktion im Block ist. Und "funktionieren" stimmt auch nicht ganz, denn das DestroyItem() wird einfach nicht ausgeführt.
Um das zu verifizieren, kannst Du Dir die Items von Firebead nach dem Dialog anschauen. (Zum Beispiel im Savegame, wenn Du danach speicherst.)

Die Details werde ich Dir ersparen. Alles habe ich hier auch noch nicht genau verstanden.
Man kann sich vielleicht merken, dass Aktionen, die nicht instant sind, während des Dialogs nicht abgearbeitet werden. Sollten im selben Block noch weitere Aktionen sein, blockiert die ganze Ausführung, da die Aktion-Queue nie leer wird. Das kann man umgehen, indem man ein SetInterrupt(TRUE) dazwischen schiebt. (Die Engine packt automatisch ein SetInterrupt(FALSE) ... SetInterrupt(TRUE) um den ganzen Aktion-Block.)
Aber es wäre sicher einfacher, die fragliche Aktion komplett zu streichen, denn sie wird ja eh nicht während des Dialogs ausgeführt.

Nebenbei ist mir aufgefallen, dass ein ActionOverride() Aktionen aus der Aktion-Queue entfernen kann, wenn diese kein ActionOverride() waren.
 

Maus

Senior Member
Registriert
07.08.2002
Beiträge
9.380
Für Leute, die nicht so tief drin stecken: kann man zusammengefasst sagen: im Dialog die Variablen setzen und von den gesteuert im Skript die Aktionen dann bringen?
 

Taimon

Infinity Engineer
Registriert
25.11.2001
Beiträge
1.501
Damit ist man auf jeden Fall auf der sicheren Seite, zumindest was diese Problematik angeht.
 

Taimon

Infinity Engineer
Registriert
25.11.2001
Beiträge
1.501
Für die technisch Interessierten hier noch die Erklärung, warum es keine Blockade gibt, wenn man ActionOverride(...,"DestroyItem()") ans Ende des Blocks packt.
Die Blockade entsteht, wenn man eine Aktion ausführen will, die nicht INSTANT und der Akteur im Zustand NONINTERRUPTABLE ist. Da kommt man während des Dialogs nicht mehr raus, bzw. so lange wie der Worldtimer stillsteht.
Ich hatte es weiter oben schon mal beschrieben, die Aktions einer Transition werden zusammen in einen non-interruptable Block gepackt. (via SetInterrupt(FALSE/TRUE))
Aus
Code:
TakePartyItem("c#broink")
DestroyItem("c#broink")
SetGlobal("C#Br_HaveInk","MYAREA",1)
wird also
Code:
SetInterrupt(FALSE)
TakePartyItem("c#broink")
DestroyItem("c#broink")
SetGlobal("C#Br_HaveInk","MYAREA",1)
SetInterrupt(TRUE)
In diesem Beispiel ist der Akteur ganz klar non-interruptable, wenn es zur Ausführung von DestroyItem() kommt. Selbst wenn man das SetGlobal() vorzieht, ist das DestroyItem() immer noch problematisch, da erst danach SetInterrupt(TRUE) aufgerufen wird. (Es sei denn, man fügt es manuell vorher ein.)

Jetzt kommt der schwierige Teil, ein Beispiel mit ActionOverride():
Code:
ActionOverride("FIREBE",TakePartyItem("c#broink"))
ActionOverride("FIREBE",DestroyItem("c#broink"))
wird zu:
Code:
SetInterrupt(FALSE)
ActionOverride("FIREBE",TakePartyItem("c#broink"))
ActionOverride("FIREBE",DestroyItem("c#broink"))
SetInterrupt(TRUE)
ActionOverride() ist ein Sonderfall, da die Aktion nicht direkt ausgeführt, sondern über ein Nachrichtensystem an die Aktion-Queue angehängt wird. Das passiert nicht synchron, sondern leicht verzögert. (multi-threading)
Zusätzlich werden beim Anhängen alle Aktionen aus der Aktion-Queue entfernt, die kein ActionOverride() als Ursprung haben.
Falls die Engine beim Holen der nächsten Aktion auf ein ActionOverride trifft, wird dann gleich weiter zur nächsten Aktion gegangen.
Für das Beispiel bedeutet das, dass die eigentliche Ausführreihenfolge dann eher so aussieht:
Code:
SetInterrupt(FALSE)
SetInterrupt(TRUE)
TakePartyItem("c#broink")
DestroyItem("c#broink")
Damit blockiert nichts, aber da DestroyItem() nicht INSTANT ist, wird es auch nicht ausgeführt, sondern einfach ignoriert.

Und jetzt noch zum ursprünglichen Problem:
Code:
ActionOverride("FIREBE",TakePartyItem("c#broink"))
ActionOverride("FIREBE",DestroyItem("c#broink"))
SetGlobal("C#Br_HaveInk","MYAREA",1)
wird zu:
Code:
SetInterrupt(FALSE)
ActionOverride("FIREBE",TakePartyItem("c#broink"))
ActionOverride("FIREBE",DestroyItem("c#broink"))
SetGlobal("C#Br_HaveInk","MYAREA",1)
SetInterrupt(TRUE)
ActionOverride() wird verzögert, das SetGlobal() wird noch ausgeführt, aber dann werden die Nachrichten (vom ActionOverride()) verarbeitet.
Das bedeutet auch, dass alle Aktions, die kein ActionOverride() waren, gelöscht werden.
Sieht dann vielleicht so aus:
Code:
SetInterrupt(FALSE)
SetGlobal("C#Br_HaveInk","MYAREA",1)
TakePartyItem("c#broink")
DestroyItem("c#broink")
Das "SetInterrupt(TRUE)" ist entfernt worden, damit ist der Akteur noch im non-interruptable Zustand, wenn DestroyItem() dran kommt und die Aktion-Queue ist somit blockiert.

Soviel zu meinem aktuellen Erklärungsansatz. Glückwunsch, falls mir irgendjemand bis hierhin folgen konnte. :)

Auf jeden Fall vorsichtig mit ActionOverride() sein, wenn man es denselben Akteur machen lässt, der auch die anderen Aktions ausführt.
 
Zuletzt bearbeitet:

Jastey

Matron Modderholic
Registriert
16.05.2004
Beiträge
12.922
Mir fällt jetzt erst auf, dass in Firebeads Dialog er selbst natürlich keine Handlung über ActionOverride() ausführen muss. Meinst Du das mit "alle Aktions, die kein ActionOverride() waren"?
Noch verstehe ich es nicht ganz. Auf alle Fälle danke für Deine Ausführungen.
Das "SetInterrupt(TRUE)" ist entfernt worden, damit ist der Akteur noch im non-interruptable Zustand, wenn DestroyItem() dran kommt und die Aktion-Queue ist somit blockiert.
Was ich noch gar nicht verstehe - aber vielleicht fehlt mir auch noch das prinzipielle Verstandnis dessen, was Du erklärt hast, ist, wie dann nach dem ersten DestroyItem() überhaupt noch was anderes passieren kann, in diesem Fall das Setzen der Variablen und das Nehmen der anderen zwei Items aus dem Inventar. Als das DestroyItem vom Player1 getan werden sollte, wurde alles ignoriert (in meiner ersten Version die Probleme machte). Da es nun Firebead selbst macht werden die anderen Befehle ausgeführt und nur die DestroyItem() wie Du meintest ignoriert?
Ist es also genau andersrum als ich dachte, das heißt: wäre das Brandocks Dialog, dann würde ein
~ActionOverride("FIREBE",TakePartyItemNum("POTN42",1))
ActionOverride("FIREBE",DestroyItem("POTN42"))~
alles andere blockieren?
 

Taimon

Infinity Engineer
Registriert
25.11.2001
Beiträge
1.501
Ich sehe schon, ich konnte meine Erkenntnisse nicht gut rüberbringen. Wahrscheinlich hab ich Dich nur noch mehr verwirrt.
Ist auch schwierig zu verstehen, insbesondere die Sache mit ActionOverride().
Man muss immer im Hinterkopf behalten, wer die Aktionen zu welchem Zeitpunkt durchführt.

Kannst Du mir vielleicht anhand meines Beitrages sagen, welche Stellen genau unklar sind?

Im Prinzip hab ich drei voneinander unabhängige Beispiele mit Erläuterung aufgelistet.
1. DestroyItem() direkt verwendet, führt immer zur Blockade (egal ob am Blockende oder nicht)
2. ActionOverride(...,DestroyItem()) am Blockende, führt nicht zur Blockade
3. ActionOverride(...,DestroyItem()) vor dem Blockende, führt zur Blockade (das ist Dein ursprüngliche Code)

Was ich noch gar nicht verstehe - aber vielleicht fehlt mir auch noch das prinzipielle Verstandnis dessen, was Du erklärt hast, ist, wie dann nach dem ersten DestroyItem() überhaupt noch was anderes passieren kann, in diesem Fall das Setzen der Variablen und das Nehmen der anderen zwei Items aus dem Inventar.
Auf welches Beispiel beziehst Du Dich hier?
Ein normales DestroyItem() (ohne ActionOverride()) wird auf jeden Fall alles weitere im Dialog blockieren. (Wegen dem automatischen SetInterrupt()).
Einzige Ausnahme wäre, wenn man direkt davor SetInterrupt(TRUE) aufruft.

Ist es also genau andersrum als ich dachte, das heißt: wäre das Brandocks Dialog, dann würde ein
~ActionOverride("FIREBE",TakePartyItemNum("POTN42",1))
ActionOverride("FIREBE",DestroyItem("POTN42"))~
alles andere blockieren?
Nein, das würde nichts blockieren, da das DestroyItem() ja im Kontext von "FIREBE" ausgeführt wird (wegen ActionOverride()), also überhaupt nicht in die Aktion-Queue von Brandock kommt.
 
Zuletzt bearbeitet:

Jastey

Matron Modderholic
Registriert
16.05.2004
Beiträge
12.922
3. ActionOverride(...,DestroyItem()) vor dem Blockende, führt zur Blockade (das ist Dein ursprüngliche Code)
Ah, ich glaub mir dämmert langsam was.

Der problematische Trasaktionblock war ja
Code:
IF ~~ THEN DO ~ActionOverride("FIREBE",TakePartyItem("c#broink"))
ActionOverride("FIREBE",DestroyItem("c#broink"))
SetGlobal("C#Br_HaveInk","MYAREA",1)~ + ingredient_04

Das heißt, statt meines Aufteilens auf verschiedene States hätte es auch gereicht, wenn ich gemacht hätte (SetGlobal nach vorne?):
Code:
IF ~~ THEN DO ~SetGlobal("C#Br_HaveInk","MYAREA",1)
ActionOverride("FIREBE",TakePartyItem("c#broink"))
ActionOverride("FIREBE",DestroyItem("c#broink"))~ + ingredient_04

Aber:
2. ActionOverride(...,DestroyItem()) am Blockende, führt nicht zur Blockade
Was genau ist das Blockende. Ich verstehe es jetzt so, dass das was Du aufgelistet hast nur für die Transaktionen eines States gilt? Weil sonst meine aktuelle Version ja nicht funktionieren können sollte, weil da ja lauter SetGlobal() und ActionOverride(DestroyItem()) hintereinander in den aufeinander folgenden States kommt. Darauf bezog sich auch meine Nachfrage, wie nach dem ersten DestroyItem() (ich meinte in ActionOverride :o) die nachfolgenden SetGlobals() ausgeführt werden können.

Und meine Erkenntnis, dass ich in Firebeads Dialog gar kein "ActionOverride()" für ihn bräuchte würde dazu führen - wenn ich es weglasse und direkt mit ~DestroyItem()~ arbeite, dass die Aktionen danach wieder gar nicht ausgeführt werden würden?

Und in meiner aktuellen Version blockiert das ActionOverride(DestroyItem()) die anderen Aktionen zwar nicht, weil es ein ActionOverride Befehl ist, wird aber auch nicht ausgeführt weil es..
Ne verdammt, ich muss da nochmal drüber schlafen.
 

Taimon

Infinity Engineer
Registriert
25.11.2001
Beiträge
1.501
Das heißt, statt meines Aufteilens auf verschiedene States hätte es auch gereicht, wenn ich gemacht hätte (SetGlobal nach vorne?)
Ja, das hätte die Blockade verhindert.

Was genau ist das Blockende. Ich verstehe es jetzt so, dass das was Du aufgelistet hast nur für die Transaktionen eines States gilt?
Genau, ich bezog mich auf den Aktion-Block in der Transaktion (transition).

Und meine Erkenntnis, dass ich in Firebeads Dialog gar kein "ActionOverride()" für ihn bräuchte würde dazu führen - wenn ich es weglasse und direkt mit ~DestroyItem()~ arbeite, dass die Aktionen danach wieder gar nicht ausgeführt werden würden?
Ja, die würden bis zum Dialogende in der Queue durch das DestroyItem() blockiert werden. (Beispiel 1)

Und in meiner aktuellen Version blockiert das ActionOverride(DestroyItem()) die anderen Aktionen zwar nicht, weil es ein ActionOverride Befehl ist, wird aber auch nicht ausgeführt weil es..
Dieser Fall ist mein zweites Beispiel. Hier wird ja ActionOverride() mit demselben Akteur (Firebead) verwendet, der auch die normalen Aktionen durchführt.
Das sorgt dafür, dass die Aktionen später ausgeführt werden, als die, die direkt danach kommen.
Bedingung für die Blockade ist, dass der Akteur im Zustand NONINTERRUPTABLE (durch SetInterrupt(FALSE)) ist und eine Aktion ausführt, die nicht INSTANT ist. (z. B. DestroyItem()) ActionOverride() an sich ist übrigens INSTANT.
Durch die Änderung der Ausführreihenfolge, rutscht das SetInterrupt(TRUE) vor das DestroyItem(), deswegen blockiert es nicht.
Aber generell gilt: Aktionen die nicht INSTANT sind, werden im Dialog nicht ausgeführt. Und wenn die Aktion-Queue nicht blockiert ist, muss es also ignoriert werden.

Der dritte Fall verkompliziert die Sache noch ein wenig, da einige Aktionen aus der Aktion-Queue entfernt werden, wenn das ActionOverride() vom Nachrichtensystem verarbeitet wird. Das passiert nicht in dem Moment, wenn der Akteur den ActionOverride()-Befehl in der Queue abarbeitet, sondern erst etwas später. Die Abarbeitung in der Queue sorgt nur dafür, dass die Nachricht ans System geschickt wird.
Wenn wirklich Bedarf besteht, gehe ich hier noch einmal genauer darauf ein. Aber ich denke, es ist okay, das für den Moment zu ignorieren.
 

Jastey

Matron Modderholic
Registriert
16.05.2004
Beiträge
12.922
Durch die Änderung der Ausführreihenfolge, rutscht das SetInterrupt(TRUE) vor das DestroyItem(), deswegen blockiert es nicht.
Aber generell gilt: Aktionen die nicht INSTANT sind, werden im Dialog nicht ausgeführt. Und wenn die Aktion-Queue nicht blockiert ist, muss es also ignoriert werden.
Ich glaube, die zwei Sätze haben meinen Horizonz sehr erweitert.
Vielen Dank nochmal!

Zu meinem Dialog:
-Sehe ich das richtig, dass das Nichtausführen/Ignorieren/Blockieren daran liegt, dass der Dialog nicht nach der Aktion endet? Also, würden die Transitions eines Dialogs, der nur aus folgendem besteht, bis zu Ende ausgeführt werden, weil es nach dem Schließen des Dialogs abgearbeitet wird?
Code:
IF ~Global("C#Br_HaveInk","MYAREA",0)~ THEN test
SAY ~blabla~
IF ~~ THEN DO ~TakePartyItem("c#broink")
DestroyItem("c#broink")
SetGlobal("C#Br_HaveInk","MYAREA",1)~ EXIT
END
Aktionen die nicht INSTANT sind, werden im Dialog nicht ausgeführt. Und wenn die Aktion-Queue nicht blockiert ist, muss es also ignoriert werden.
Ist das der Grund, warum die ActionOverride("FIREBE",DestroyItem("xxx")) übersprungen/ignoriert werden anstatt dass sie nach dem Dialog abgearbeitet werden? Weil sie sozusagen "weg" sind weil bereits die nachfolgenden Befehle abgearbeitet werden?

Mein momentaner Dialog funktioniert ja soweit, dass die Items aus dem Inventar verschwinden und die Variablen gesetzt werden. Die Items verbleiben aber in Firebeads Inventar, wie Du rausgefunden hattest.
Was wäre das Ergebnis, wenn ich statt ActionOverride("FIREBE",DestroyItem("xxx")) direkt mit DestroyItem() arbeiten würde, da es ja Firebeads Dialog ist:
-Alle Aktionen nach dem DestroyItem() würden bis zum Ende des Dialogs blockiert werden. Meine eigentliche Frage:
-Nach Beenden des Dialogs würden die Aktionen, die blockiert waren, ausgeführt werden? Also "alle", inklusive des DestroyItem() und aller nachfolgenden? (Ist eine Verständnisfrage, da ein solcherart gescripteter Dialog für mich nicht in Frage kommt).

Vermute ich richtig, dass die einzige Lösung, die Variablen im Dialog gesetzt zu bekommen und nach dem Dialog alle Items weg sind wäre, das DestryItem() in ein Skript zu verlagern, also dass es in einem Dialog so wie ich mir das vorstelle nie klappen würde? Oder warte, es könnte funktionieren, das ganz ans Ende des Dialogs, eventuell sogar nach der kurzen Fade-To-Black Cutscene wenn ein neuer Dialog gestartet wurde zu stellen. Wenn nichts mehr danach kommt müsste es nach Beenden des Dialogs abgearbeitet werden?

Ich hoffe, meine Fragen nerven nicht.
 

Taimon

Infinity Engineer
Registriert
25.11.2001
Beiträge
1.501
Sehe ich das richtig, dass das Nichtausführen/Ignorieren/Blockieren daran liegt, dass der Dialog nicht nach der Aktion endet? Also, würden die Transitions eines Dialogs, der nur aus folgendem besteht, bis zu Ende ausgeführt werden, weil es nach dem Schließen des Dialogs abgearbeitet wird?
Jein. :)
Der Grund, warum es eine Blockade geben kann, ist, dass die Zeit während des Dialogs stillsteht und deswegen nur INSTANT Aktionen ausgeführt werden. Wenn der Akteur zu diesem Zeitpunkt NONINTERRUPTABLE ist und auf eine entsprechende Aktion trifft, dann werden keine weiteren Aktionen abgearbeitet. Solange, bis die Zeit weiterläuft, was normalerweise erst am Dialogende der Fall sein sollte. Dann geht es normal mit der Abarbeitung weiter.
Sollte der Akteur aber INTERRUPTABLE gewesen sein, dann wird die entsprechende Aktion ignoriert.

Deinen restlichen Fragen entnehme ich, dass Du das alles schon richtig verstanden hast. Also nicht zuviel über meine Worte hier grübeln.

Ist das der Grund, warum die ActionOverride("FIREBE",DestroyItem("xxx")) übersprungen/ignoriert werden anstatt dass sie nach dem Dialog abgearbeitet werden? Weil sie sozusagen "weg" sind weil bereits die nachfolgenden Befehle abgearbeitet werden?
Korrekt, jetzt musst Du nur noch verstehen, warum in diesem konkreten Fall das ActionOverride() nicht zur Blockade geführt hat. (Blockende vs. davor)

Nach Beenden des Dialogs würden die Aktionen, die blockiert waren, ausgeführt werden? Also "alle", inklusive des DestroyItem() und aller nachfolgenden? (Ist eine Verständnisfrage, da ein solcherart gescripteter Dialog für mich nicht in Frage kommt)
Ja, sie würde alle ausgeführt werden, auch das DestroyItem(), wenn die Zeit wieder weiterläuft.

Es sei denn, es kommt irgendwann später im Dialog ein ActionOverride() mit dem entsprechenden Akteur, dann würden alle Aktionen entfernt werden, die nicht über ein ActionOverride() in die Aktion-Queue gekommen sind. (So gesehen ergibt der Funktionsname nun auch einen gewissen Sinn.)
(Das betrifft aber nur die Aktionen, die in der Aktion-Queue sind. Wenn man im Blockade-Zustand ist, dann ist die blockierende Aktion nicht mehr in der Queue, sondern schon "in Ausführung". Die würde nicht entfernt werden.)

Vermute ich richtig, dass die einzige Lösung, die Variablen im Dialog gesetzt zu bekommen und nach dem Dialog alle Items weg sind wäre, das DestryItem() in ein Skript zu verlagern, also dass es in einem Dialog so wie ich mir das vorstelle nie klappen würde? Oder warte, es könnte funktionieren, das ganz ans Ende des Dialogs, eventuell sogar nach der kurzen Fade-To-Black Cutscene wenn ein neuer Dialog gestartet wurde zu stellen. Wenn nichts mehr danach kommt müsste es nach Beenden des Dialogs abgearbeitet werden?
Sollte beides gehen. Während der Cutscene sollte die Zeit ebenfalls weiterlaufen, d. h. dort dürften auch Aktionen abgearbeitet werden, die nicht INSTANT sind.
Und: Man könnte die fraglichen Aktionen auch einfach jemand anderen machen lassen, der nicht Speaker im Dialog ist.

Ich hoffe, meine Fragen nerven nicht.
Im Gegenteil, nur so kann man doch Wissen vermitteln.
 

Jastey

Matron Modderholic
Registriert
16.05.2004
Beiträge
12.922
@Taimon vielen Dank für die geduldigen Ausführungen. Ich glaub ich hab es zu mindesten 87,5 % verstanden. Sehr erhellend!
So gesehen ergibt der Funktionsname nun auch einen gewissen Sinn.
In der Tat bekommt ActionOverride damit nochmal einen ganz neuen Sinn.
Es ist aber trotzdem die einzige Möglichkeit, um anderen Akteure als den Sprecher mit Aktionen anzusprechen, oder?
Und nochmal nachgefragt: wenn sich das ActionOverride nicht auf den Sprecher, sondern einen anderen Akteur bezieht, dann blockiert es nichts? Würde es aber eventuell ignoriert werden?
 

Taimon

Infinity Engineer
Registriert
25.11.2001
Beiträge
1.501
Es ist aber trotzdem die einzige Möglichkeit, um anderen Akteure als den Sprecher mit Aktionen anzusprechen, oder?
Ja, zumindest fällt mir auf die Schnelle nichts anderes ein.
Evtl. könnte man was mit SendTrigger() machen, aber das ist schon sehr umständlich.
Letztendlich wäre es dann genauso gut, einfach eine Variable zu setzen und diese in einem Skript auszuwerten.

Und nochmal nachgefragt: wenn sich das ActionOverride nicht auf den Sprecher, sondern einen anderen Akteur bezieht, dann blockiert es nichts? Würde es aber eventuell ignoriert werden?
Kann ich so pauschal nicht sagen, hängt sehr von der Situation ab.
Ich nehme mal an, dass man weiterhin im Dialog ist und folglich die Zeit stillsteht. Dann gilt auch für den anderen Akteur, dass er nur INSTANT Aktionen ausführt.
Ob die Aktion ignoriert wird oder nicht, hängt davon ab, ob der Akteur INTERRUPTABLE ist und ob noch weitere Aktionen in der Action-Queue sind. Wenn beides zutrifft, dann sollte sie einfach übersprungen werden.
Der Unterschied zum normalen Speaker ist, dass die Aktionen, die mit ActionOverride() geschickt werden, nicht in einen SetInterruptable()-Block gepackt werden.
Es ist also relativ wahrscheinlich, dass der Akteur INTERRUPTABLE ist. (Müsste man sich mal anschauen, ob das auch tatsächlich so ist.)

Aus meiner Sicht kann man also nicht garantieren, dass eine Aktion, die nicht INSTANT ist, dann auch wirklich ausgeführt wird.
So gesehen ziehe ich meinen Vorschlag zurück, die Aktion von jemand anderem machen zu lassen. :)
Ich dachte nur, dass man damit auf keinen Fall das Problem mit der Blockade und dem SetGlobal() beim Speaker hat.
 

Jastey

Matron Modderholic
Registriert
16.05.2004
Beiträge
12.922
Ich nehme mal an, dass man weiterhin im Dialog ist und folglich die Zeit stillsteht. Dann gilt auch für den anderen Akteur, dass er nur INSTANT Aktionen ausführt.
Ob die Aktion ignoriert wird oder nicht, hängt davon ab, ob der Akteur INTERRUPTABLE ist und ob noch weitere Aktionen in der Action-Queue sind. Wenn beides zutrifft, dann sollte sie einfach übersprungen werden.
Der Unterschied zum normalen Speaker ist, dass die Aktionen, die mit ActionOverride() geschickt werden, nicht in einen SetInterruptable()-Block gepackt werden.
Es ist also relativ wahrscheinlich, dass der Akteur INTERRUPTABLE ist. (Müsste man sich mal anschauen, ob das auch tatsächlich so ist.)
Ah! Natürlich. Ich bilde mir ein, das verstanden zu haben.
Vielen Dank!
 
Oben