Several bug fixes, added optional DOOM Metal X file tracking.

This commit is contained in:
Storm Dragon
2025-08-08 23:54:38 -04:00
parent 5ac894a6ec
commit f1e197729a
6 changed files with 144 additions and 130 deletions

View File

@@ -1459,8 +1459,10 @@ class DoomLauncher(QMainWindow):
mapFiles = ["None"] # Start with None option
mapsDir = self.gamePath / "Addons/MAPS"
if mapsDir.exists():
mapFiles.extend([p.name for p in mapsDir.glob("*.wad")
if p.name not in ["TobyDeathArena_V2-0.wad"]])
# Include both .wad and .pk3 files for maps
for extension in ["*.wad", "*.pk3"]:
mapFiles.extend([p.name for p in mapsDir.glob(extension)
if p.name not in ["TobyDeathArena_V2-0.wad"]])
# Add Operation MDK as special case
opMDK = self.gamePath / "OpMDK.wad"
@@ -1524,11 +1526,12 @@ class DoomLauncher(QMainWindow):
if fullPath.exists():
gameFiles.append(str(fullPath))
# Add optional files last
# Add optional files last (only first one found, for priority)
for optFile in config.get('optional_files', []):
optPath = self.gamePath / optFile
if optPath.exists():
gameFiles.append(str(optPath))
break # Only add the first optional file found
# Get any custom flags
gameFlags = config.get('flags', [])
@@ -1762,6 +1765,19 @@ class DoomLauncher(QMainWindow):
mainLayout.addWidget(QLabel("Narration Style:"))
mainLayout.addWidget(self.narrationCombo)
# Speech method selection (only show when TTS is enabled)
self.speechMethodCombo = AccessibleComboBox(self)
self.speechMethodCombo.setAccessibleName("Speech Method")
self.populate_speech_methods()
self.speechMethodCombo.currentTextChanged.connect(self.speech_method_changed)
self.speechMethodLabel = QLabel("Speech Method:")
mainLayout.addWidget(self.speechMethodLabel)
mainLayout.addWidget(self.speechMethodCombo)
# Show/hide speech method based on current narration type
self.update_speech_method_visibility()
# Create button layouts with pairs of launch and generate buttons
# Single Player
singlePlayerLayout = QHBoxLayout()
@@ -1907,6 +1923,121 @@ class DoomLauncher(QMainWindow):
else:
# Update speech handler state directly
self.speechHandler.set_tts_state(value == 2)
# Update speech method visibility
self.update_speech_method_visibility()
def detect_available_speech_providers(self):
"""Detect which speech providers are available on the current platform"""
available_providers = []
if platform.system() == "Windows":
# On Windows, only accessible_output2 is used
try:
import accessible_output2.outputs.auto
available_providers.append("accessible_output2")
except ImportError:
pass
else:
# On Linux, check each provider
# Check Orca remote controller
orca_remote = OrcaRemoteController()
if orca_remote.available:
available_providers.append("orca_remote")
# Check Cthulhu
try:
subprocess.check_output(["pgrep", "cthulhu"])
available_providers.append("cthulhu")
except (subprocess.CalledProcessError, FileNotFoundError):
pass
# Check accessible_output2
try:
import accessible_output2.outputs.auto
available_providers.append("accessible_output2")
except ImportError:
pass
# Check speechd
try:
import speechd
available_providers.append("speechd")
except ImportError:
pass
return available_providers
def populate_speech_methods(self):
"""Populate the speech method combobox with available providers"""
available_providers = self.detect_available_speech_providers()
# Map internal names to user-friendly names
provider_names = {
"accessible_output2": "Accessible Output2",
"orca_remote": "Orca Remote",
"cthulhu": "Cthulhu",
"speechd": "Speech Dispatcher"
}
self.speechMethodCombo.clear()
for provider in available_providers:
friendly_name = provider_names.get(provider, provider)
self.speechMethodCombo.addItem(friendly_name, provider)
# Set current selection based on global speech provider
current_provider = self.get_current_speech_provider()
for i in range(self.speechMethodCombo.count()):
if self.speechMethodCombo.itemData(i) == current_provider:
self.speechMethodCombo.setCurrentIndex(i)
break
def get_current_speech_provider(self):
"""Get the current speech provider being used globally"""
global speechProvider
return speechProvider
def update_speech_method_visibility(self):
"""Show/hide speech method combobox based on narration type"""
is_tts = self.get_narration_type() == 2
self.speechMethodLabel.setVisible(is_tts)
self.speechMethodCombo.setVisible(is_tts)
def speech_method_changed(self, text: str):
"""Handle speech method combobox changes"""
selected_provider = self.speechMethodCombo.currentData()
if selected_provider:
self.set_speech_provider(selected_provider)
def set_speech_provider(self, provider: str):
"""Update the global speech provider"""
global speechProvider, s, spd, orca
try:
if provider == "accessible_output2":
import accessible_output2.outputs.auto
s = accessible_output2.outputs.auto.Auto()
speechProvider = "accessible_output2"
elif provider == "orca_remote":
orca_remote = OrcaRemoteController()
if orca_remote.available:
orca = orca_remote
speechProvider = "orca_remote"
else:
QMessageBox.warning(self, "Error", "Orca Remote is not available")
return
elif provider == "cthulhu":
try:
subprocess.check_output(["pgrep", "cthulhu"])
speechProvider = "cthulhu"
except (subprocess.CalledProcessError, FileNotFoundError):
QMessageBox.warning(self, "Error", "Cthulhu is not running")
return
elif provider == "speechd":
import speechd
spd = speechd.Client()
speechProvider = "speechd"
except Exception as e:
QMessageBox.warning(self, "Error", f"Failed to initialize {provider}: {e}")
def populate_game_list(self):
"""Populate the game selection combo box"""
@@ -2325,8 +2456,10 @@ class DoomLauncher(QMainWindow):
mapFiles = ["None"] # Start with None option
mapsDir = self.gamePath / "Addons/MAPS"
if mapsDir.exists():
mapFiles.extend([p.name for p in mapsDir.glob("*.wad")
if p.name not in ["TobyDeathArena_V2-0.wad"]])
# Include both .wad and .pk3 files for maps
for extension in ["*.wad", "*.pk3"]:
mapFiles.extend([p.name for p in mapsDir.glob(extension)
if p.name not in ["TobyDeathArena_V2-0.wad"]])
# Add Operation MDK as special case
opMDK = self.gamePath / "OpMDK.wad"
@@ -2406,11 +2539,12 @@ class DoomLauncher(QMainWindow):
if fullPath.exists():
gameFiles.append(str(fullPath))
# Add optional files last
# Add optional files last (only first one found, for priority)
for optFile in config.get('optional_files', []):
optPath = self.gamePath / optFile
if optPath.exists():
gameFiles.append(str(optPath))
break # Only add the first optional file found
# Get any custom flags
gameFlags = config.get('flags', [])