SSE SFX Fade During Dialogue triggern

PRieST

Bürger
Hey, vielleicht kann mir hier ja jemand helfen.

In Skyrim(SE) werden, sofern man in ein Gespräch mit einem NPC kommt, einige/alle anderen Spielspounds leiser bzw. sind nicht mehr zu hören.
Soweit ich das sehe hat das mit der Sound-Kategorie "SFX Fade During Dialogue" zu tun.

Was ich bisher nicht herausgefunden habe ist, wie das ganze abgefragt und/oder umgesetzt wird.
Vielleicht per Script oder Plugin - gefunden habe ich jedoch nichts, was darauf schließen lässt.
Eventuell braucht es ja auch ein bestimmtes Keyword, damit das ausgelöst wird - aber auch hier habe ich nichts eindeutiges entdecken können.
Sodern das ganze auf Enginelevel beruht, muss das ja trotzdem irgendwie provoziert werden.

Ich frage daher, weil ich das ähnliche Verhalten bei meiner Mod Voiced Books of Skyrim umsetzen möchte so lange ein Buch vorgelesen wird. Da es aber kein Dialog ist, weiß ich nun nicht welche Einstellung oder sonstiges es braucht, damit die anderen Geräusche leiser werden oder für die Zeit ausgehen.

Ich hoffe hier hat jemand eine Idee, treibe mich auch schon auf diversen englischen Modding Discord-Servern rum mit der Frage, bisher jedoch ohne Antwort.
Reddit hab ich noch nicht versucht und weil ich mich damit nicht so recht auskenne, hat da wer den passenden Link für mich parat.

Vielen Dank vorab
PRieST
 
Hab das nun anders gelöst, was mehr oder weniger gut funktioniert, ich stehe jetzt vor einem neuen Problem.

Hier erst einmal das Script:
Code:
ScriptName PRKF_VoicedBooksPerk Extends Perk Hidden

Form Property BookObject Auto
Formlist Property VoicedBooksFormlistAudioBooks Auto
Formlist Property VoicedBooksFormlistAudioSounds Auto
Int Property BookNumber = -1 Auto
Int Property KeyCodeActivate = 207 Auto
Int Property SoundPlayInstance Auto
Sound Property BookSound Auto
SoundCategory Master
VoicedBooksMCMScript Property MCMScript Auto

Event OnInit()
   UnregisterForAllKeys()
   RegisterForKey(KeyCodeActivate)
EndEvent

Event OnUpdate()
   UnregisterForAllKeys()
   RegisterForKey(KeyCodeActivate)
EndEvent

Event OnKeyDown(Int KeyCode)
   If KeyCode == KeyCodeActivate && MCMScript.bAutomaticReading == True
       StopReading()
   EndIf
EndEvent

Function Fragment(ObjectReference akTargetRef, Actor akActor)
   Self.CheckBooks(akTargetRef)
EndFunction

Function Update()
   Self.RegisterForSingleUpdate(0.5)
EndFunction

Function ReadBook()
   If UI.IsMenuOpen("Book Menu") == False
       Return
   EndIf
   StopReading()
   BookSound = VoicedBooksFormlistAudioSounds.GetAt(BookNumber) As Sound
   SilentAudio()
   SoundPlayInstance = BookSound.Play(Game.GetPlayer() As ObjectReference)
EndFunction

Function CheckBooks(ObjectReference akTargetRef)
   BookObject = akTargetRef.GetBaseObject()
   BookNumber = VoicedBooksFormlistAudioBooks.Find(akTargetRef As Form)
   If BookNumber < 0
       BookNumber = VoicedBooksFormlistAudioBooks.Find(BookObject)
   EndIf
EndFunction

Function RestoreAudio()
   Master = Game.GetFormFromFile(0x000EB803, "Skyrim.esm") As SoundCategory
    Master.SetVolume(Utility.GetINIfloat("fAudioMasterVolume:AudioMenu"))
EndFunction

Function SilentAudio()
   Master = Game.GetFormFromFile(0x000EB803, "Skyrim.esm") As SoundCategory
   Master.SetVolume(0.2)
EndFunction

Function StopReading()
   If SoundPlayInstance > 0
       Sound.StopInstance(SoundPlayInstance)
       RestoreAudio()
       SoundPlayInstance = -1
   EndIf
EndFunction
Was ich nun für ein Problem habe ist, dass, sofern der Sound abgespielt wird ich keine Möglichkeit habe "RestoreAudio" nach dem Abspielen des Sounds aufzurufen.
Alternativ zu dieser Zeile
SoundPlayInstance = BookSound.Play(Game.GetPlayer() As ObjectReference)
könnte ich ja auch BookSound.PlayAndWait(...) benutzen, was true/false herausgibt, wenn der Sound erfolgreich abgespielt wurde. Zusmmen mit einem If wäre dann der Aufruf meiner Funktion möglich.
Dabei hab ich jedoch den Nachteil, dass ich keine InstanceID bekomme und sofern ich beides (Play und PlayAndWait) benutze, der Sound doppelt abgespielt wird. So oder so also ein NoGo.

Kann ich nun irgendwie die instanceID vom PlayAndWait sound bekommen, damit ich dies für "StopReading" benutzen kann?
Oder die einfach stumm schalten?
Oder gibt es eine andere Möglichkeit zu prüfen, ob das Abspielen des Soundfiles beendet ist, woraufhin ich dann "RestoreAudio" ausführen lassen kann.

Aktuell würde das ganze nur per definiertem Tastendruck funktionieren, was ich so nicht möchte bzw. nicht das alleine.
 
Zuletzt bearbeitet:
Das müsste ich dann mit dem PlayAndWait machen, von dem kenne ich aber die InstanceID nicht.
Wenn ich das If-Statement drin lasse, werde beide sounds wie gesagt gleichzeitig abgespielt (beide haben also unterschiedliche IDs) und nur den ersten (also mit Play) kann ich gezielt ansprechen/stoppen.
 
So hätte ich es gerne.
Was ich dann aber nicht mehr kann: Auf Knopfdruck oder wenn ein anderes Buch geöffnet wird, den aktuellen Sound stoppen.
Dafür gibt es anscheinend nur "Sound.StopInstance(int InstanceID)" - Diese ID habe ich aber bei "PlayAndWait" nicht, da diese Funktion nur einen Bool wiedergibt. Ich bräuchte aber quasi beides, die InstanceID (zum gezielten Stoppen) und den Bool (damit ich prüfen kann, ob der Sound zuende gespielt ist, damit dann die Audio-Settings wiederhergestellt werden).

Ich glaube das benötigt einen "hacky way", dafür versteh ich aber zu wenig von Papyrus.
Mir würde es ja auch schon reichen, wenn ich irgendwie die Duration von dem abzuspielenden soundfile herausbekommen könnte, dann würde ich das script einfach entsprechend pausieren (also quasi: utility.wait(getDurationOfSound(InstanceID)) )
und dann einfach RestoreAudio()

Das ist aber eine Funktion die ich natürlich selbst schreiben müsste, aber ich hätte keine Ahnung ob ich das überhaupt mit Papyrus realisieren könnte.
Ich bräuchte also quasi die PlayAndWait Funktion, ohne dass der Sound selbst abgespielt wird, warum ich das nicht mit "Play" abfragen kann ist mir auch ein Rätsel.

Also 2 Funktionen, die immer den Sound abspielen und ich brauche nur einmal den Sound und einmal die Kontrolle, dass der Sound fertig abgespielt wurde.
Das macht mich grad wild, dass es da keine (einfache) Lösung zu geben scheint.
 
Die Audio-Funkrionen sind ziemlich dünn.
Ich habe das System nicht völlig begriffen. Das Script ist ja auf einem Perk, der scheinbar diese Funktionen zur Kontrolle trägt. Aber wie wird ReadBook() ausgelöst? Ist das auf einem Buch-Script oder einem Event?
Liesse sich diese Funktion auch auf einer Quest oder Quest-Alias machen? Auf Quests können andere Funktionen zugreifen, auf Perks nicht. D.h. wenn die Funktion und Sound-Instanz global ist, kann sie kontrollieren, dass immer nur ein Sound aktiv ist.
 
Sorry, ausgelöst wird dieses Script durch ein Questscript, im grunde genommen sobald das Buch aus dem Inventar aufgerufen wird. Danach übernimmt das Perk-Script.
Ich sag mal so, ich bin schon froh, dass ich das überhaupt bis hier so weit hinbekommen habe :oops: bin wie gesagt nicht so gut in dem erstellen von Quest-Mod/Scripten.

Damit würde ich jetzt wiederum vor dem Problem stehen: Was muss ich wie umschreiben, damit das noch genau so funktioniert.
Würde es dir (für Hilfestellung) helfen, wenn du alle Scripte und das .esp Plugin hast?

Edit:
Hier dann zu finden
 
Zuletzt bearbeitet:
Gut wird man, indem man übt :)
Ich sehe es mir mal an. Mich interessiert das auch persönlich, weil ich sowas gerne auch für Fallout 4 hätte, wo Dialoge sehr oft unverständlich sind. Es wird verstärkt durch Mods wie True Storms und andere Audio-Overhauls, aber es scheint auf jeden Fall so zu sein, wie wenn das ein weiteres essenzielles Ding wäre, das Bethesda gegenüber Skyrim wegrationalisiert hat, da wird überhaupt kein Sound gedimmt.
 
Funktioniert das wirklich? Kriegt der Perk tatsächlich die richtige Buch-Nummer? Eigentlich kann jeder NPC eine Instanz desselben Perks haben, du weist die Nummer aber irgendeinem zu.

PerkScript.BookNumber = BookNumber
PerkScript.ReadBook()


Ich habe mal in die Scripte geschaut. Wobei ich heute schon den ganzen Tag in PHP-Scripten zu Gange war, und ich mag kein PHP. Bei Bedarf sehe ich es mir am Wochenende genauer an.
Nur schon mal Input: Wieso brauchst du überhaupt einen Perk? Ein ReferenceAlias-Script ist praktisch einem Perk gleichwertig. Allerdings hat es auch den Vorteil, dass es global ist und einfach von überall her aufgerufen werden kann.
Ich würde mal versuchen, alles in das Alias-Script zu stopfen. Wenn ein neues Buch geöffnet wird, kannst du die aktuelle Sound-Instanz stoppen und dann eine neue starten, wobei du dir es in dem Fall ersparen kannst, den Sound zu muten.

Was du allerdings tun willst, ist echt eine Knacknuss.
Im Prinzip könnte man zweimal denselben Sound starten, wobei einer hörbar sein soll und der andere unhörbar mit PlayAndWait(), um am Ende den Sound zu restoren. Aber PlayAndWait lässt sich nicht unterbrechen oder muten, während man von dem, der vorbildlicherweise eine Nummer zurückgibt und den man stoppen und unhörbar machen kann, keine Ahnung hat, wie lange er läuft.
 
Also ja, das funktioniert so =)

Müsste ich mir mal genauer ansehen mit dem ReferenceAlias-Script, ob ich das hinbekomme, wie gesagt: Wie das mit den Scripten und wann muss ich das über PERK, Quest oder in dem Fall ReferenceAlias laufen lassen - kein Plan - da bin ich noch nie dahinter gestiegen. Ich schau mir öfter mal die Source-Scripte von diversen Mods an um zu verstehen warum wieso weshalb. Meistens ist das aber eher: "Ah ich glaube ich verstehe, wäre ich aber nie selber drauf gekommen...trotzdem bleibt, warum so und nicht anders".

Ja leider, da sind die Funktionen von Papyrus leider echt nicht gut oder anders gesagt, warum kann ich nicht einfach von der PlayAndWait-Funktion eine Instanz bekommen, oder einfach Sounds muten, also ala BookSound.PlayAndWait(Game.GetPlayer() As ObjectReference).Mute() wäre ja zu einfach.
Es muss doch einen Workaround dazu geben...irgendwie macht das Hauptspiel sowas doch auch oder wirklich gar nicht?
 
Hast du eigentlich dieses System mit dem Perk an einem anderen Ort abgeschaut? Ich habe mir fast alles beigebracht, indem ich nachgesehen habe, wie andere, auch Bethesda, Probleme gelöst haben. Allerdings kann man dann irgendwann sagen, dass es auch Bethesda nicht immer auf die richtige oder effizienteste Art löst.

Auf jeden Fall können bestimmte Objekte bestimmte Script-Typen tragen. Z.B. muss ein Script auf einem ActorEffect von MagicEffect ableiten und ein Actor-Script von ObjectReference. Und je nach Objekt kann man gewisse Operationen nicht machen, z.B. auf einem Aktivator ein GetRace(). Wenn aber eine Referenz mit ObjectReference-Script ein Actor ist, kann man das unbestimmte Objekt übersetzen, damit man das Actor-Interface bekommt, z.B. target as Actor. Ein ReferenceAlias hat im Prinzip dieselben Möglichkeiten wie ein Actor-Script. Aber ist fast immer egal, was in Function BlaBla() kommt. D.h. du kannst im Prinzip alle Funktionen aus dem Perk in das Alias-Script rauskopieren und sie neu verlinken. Dabei den Perk nicht mehr vergeben.
Gefühlsmässig würde ich dafür nicht mal einen Alias nutzen, es wäre alles in einem Quest-Script, weil Quests global und dafür ausgelegt sind. Aber generell ist es eine gute Idee, so viele Funktionen wie möglich in eine zentrale Quest auszulagern, während Perks, Aktivatoren und andere Objekte diese nur aufrufen und selbst möglichst wenig können.

Allerdings ist ja immer noch nicht geklärt, wie du überhaupt dein Ziel erreichen kannst. Das Hauptspiel hat ein Set von Fähigkeiten, und mit Scripten kann man einen Teil davon abgreifen. Aber nicht alles, was die Engine macht, lässt sich per Script steuern oder auch mit einem Script machen, selbst mit SKSE, das mehr Features der Engine zur Verfügung stellt. Das Muten macht wahrscheinlich die Engine, man nennt es hardgecodet. Normalerweise habe ich oft eine Idee, wie und worauf man eine Funktion umsetzt, aber bei deinem Ziel bin ich auch gerade ratlos.
 
Hab mich stark am Original orientiert, wo es mit dem Perk gelöst wurde und dann alles so umgeschrieben, damit es zu meiner Umsetzung passt (mit der Implementierung vom MCM-Menu, Hotkey und co.).
Wenn ich das aber, wie du sagst, quasi alles in das andere Script schreiben kann, dann werd ich mich die Tage mal ransetzen und das machen...bisher bin ich davon ausgegangen, mangels Erfahrung, dass ich den Perk unbedingt brauche.

Wenn das nicht zu lösen ist - sollte man nicht sagen müssen in der Welt der IT und "Pogrammierung" - werd ich das eventuell als Alternative anbieten. Mit Hotkey lassen sich die Audio-Einstellungen ja problemlos wiederherstellen, man muss es halt nur jedes mal machen, wenn ein Buch vorgelesen wurde.
 
Vielen Dank @PixelMurder, aufgrund von deinem Hinweis hab ich nun die komplette Funktionalität der Mod in das Alias Script gesteckt. Musste hier und da einige Sachen anders machen, worüber ich im ersten Moment nicht gestoplert bin, nun läuft aber alles einwandfrei.
Dazu dann noch das MCM-Script und "jeder" Nutzer sollte zufrieden sein =)

Dank der riesen Modding-Community auf Nexus hab ich dann auch noch jemanden gefunden, welcher die notwendige(n) Funktion(en) geschaffen hat, welche ich nun nutzen konnte um den abspielbaren Sound zu tracken.

Ich würde sagen, zumindest für mich, ein Erfolg auf ganzer Linie.
 
  • Like
Reaktionen: PixelMurder
@PixelMurder Ich bin gerade dabei noch hier und da weitere Funktionen in das Script einzubauen.
Mit ist dabei aufgefallen, dass die Mod auch ohne das Script Fragment läuft (wie gesagt, ist ja jetzt alles im Alias Script) - kannst du mir sagen, ob ich das überhaupt brauche?
Hab selbst mal ein wenig versucht zu recherchieren, aber ne richtige Antwort hab ich nicht gefunden, ich denke mal ich brauche es in meinem Fall nicht.

Auserdem hab ich nun eine Abfrage am Anfang eingebaut, welche eine Textbox ausgibt, wenn Mod-Voraussetzungen nicht in der richtigen Version vorliegen. Diese hab ich ins OnInit() Event gepackt - damit hier aber die Box nicht zweimal kommt, hab ich im esp Plugin die "Run Once" Flag gesetzt.
Von dem was ich gelesen hab, bräuchte ich den "Reset" nicht, der gemacht, wenn die Flag nicht gesetzt ist - sicher bin ich mir aber nicht, kannst du da eventuell mehr zu sagen?
Oder macht so eine Abfrage im OnInit() einfach keinen Sinn und ich sollte es woanders abbacken?

Viele Fragen, aber ich hoffe du/gerne auch jemand anders, kann mir da ein wenig Licht ins Dunkle bringen.
 
Das Script-Fragment brauchst du nicht. Es ist sowieso immer sinnvoll, alles rauszuräumen, was du nicht brauchst.

Kommt sich darauf an, für grosse Scripte würde man eine Funktion ModCheck() schreiben, die in OnInit und OnPlayerLoadGame aufgerufen wird. Eine Funktion sollte es immer dann sein, wenn du etwas zweimal schreiben musst. Und du solltest den Mod-Check auch beim Laden eines Saves machen, denn jemand könnte Mods deinstalliert haben inzwischen.

Und gleich noch ein Tipp: Es mag sinnvoll sein, Debug.Trace zu nutzen, um interne Zustände zu loggen. Aber du solltest das auskommentieren, wenn du es nicht mehr brauchst, um nicht die Logs von Spielern zuzumüllen. Die einzige sinnvolle Meldung ist es, wenn ein Fehler auftreten würde. Z.B. "Mein Modname - Notwendige Mod X nicht geladen." Und der Name deiner Mod sollte drin sein, damit solche Spieler, die Logs lesen können, auch wissen, dass die Meldung von dir kam (unter 500 Mods) und gegebenenfalls für Auskunft auf deine Mod-Seite gehen können.

Ein weiterer Tipp: Auf der CK-Seite hat es manchmal nicht ausreichend Infos, um wirklich zu wissen, was eine Funktion macht und unter welchen Umständen es problematisch ist. Ich mache es jeweils so, dass ich in Notepad++ im Source-Ordner nach der Funktion suche und dann diverse Scripte ansehe, wie das verwendet wird. Wobei hier natürlich Vorsicht geboten ist, es ist absolut nicht gesagt, dass ein Script von Bethesda richtig programmiert ist. Z.B. ist es eine Seuche, dass mit OnCellAttach statt OnLoad NPC initialisiert werden, denn dann ist oft ihr 3D nicht geladen und selbst BookSound.Play(NPCX) failt. Wobei ich alle Scripte des USK nach Source entpackt habe, damit ich mit gefixten Scripten arbeiten kann.
 
  • Like
Reaktionen: PRieST
Danke für die Antwort.
Ich denke, dass ich mittlerweile, zumindest auf mein Script bezogen, deutlich mehr von Papyrus verstanden habe.

Komplett steig ich da noch nicht dahinter, aber es wird.
 
  • Like
Reaktionen: PixelMurder