Several bug fixes, added optional DOOM Metal X file tracking.
This commit is contained in:
@@ -1459,7 +1459,9 @@ 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")
|
||||
# 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
|
||||
@@ -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,7 +2456,9 @@ 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")
|
||||
# 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
|
||||
@@ -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', [])
|
||||
|
124
TobyCustom/'
124
TobyCustom/'
@@ -1,124 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
pushd "$doomPath"
|
||||
|
||||
# Set up the pk3 and wad files
|
||||
gameOption=(
|
||||
"$(find /usr/share/games/ -name 'Project_Brutality-master.pk3')"
|
||||
"${doomPath}/TobyAccMod_V${tobyVersion}.pk3"
|
||||
"${doomPath}/PB-Toby-Compatibility-Addon.pk3"
|
||||
"${doomPath}/Toby-Universal-Pickup-Beacon-Prototype.pk3"
|
||||
"${doomPath}/TobyDeathArena_V1-0.wad"
|
||||
)
|
||||
|
||||
# Death match setup
|
||||
ipAddress="$(dialog --backtitle "Deathmatch Options" \
|
||||
--clear \
|
||||
--no-tags \
|
||||
--ok-label "Join" \
|
||||
--cancel-label "Exit" \
|
||||
--extra-button \
|
||||
--extra-label "Host" \
|
||||
--inputbox "Enter ip or URL, required for join." -1 -1 --stdout)"
|
||||
buttonCode=$?
|
||||
[[ $buttonCode -eq 1 ]] && exit 0
|
||||
if [[ $buttonCode -eq 0 ]]; then
|
||||
if [[ "${#ipAddress}" -lt 3 ]]; then
|
||||
dialog --backtitle "Deathmatch" --clear --msgbox "No ip address or URL given." -1 -1 --stdout
|
||||
exit 1
|
||||
fi
|
||||
flags=('-join' "${ipAddress}")
|
||||
else
|
||||
# List of maps included:
|
||||
maps=(
|
||||
"1" "Com Station (2-4 players)"
|
||||
"2" "Warehouse (2-4 players)"
|
||||
"3" "Sector 3 (2-4 players)"
|
||||
"4" "Dungeon of Doom (2-4 players)"
|
||||
"5" "Ocean Fortress (2-4 players)"
|
||||
"6" "Water Treatment Facility (2-4 players)"
|
||||
"7" "Phobos Base Site 4 (2-4 players)"
|
||||
"8" "Hangar Bay 18 (2-4 players)")
|
||||
# Array of how many players a given map supports in dialog rangebox syntax
|
||||
declare -a mapPlayers=(
|
||||
[1]="2 4"
|
||||
[2]="2 4"
|
||||
[3]="2 4"
|
||||
[4]="2 4"
|
||||
[5]="2 4"
|
||||
[6]="2 4"
|
||||
[7]="2 4"
|
||||
[8]="2 4")
|
||||
map="$(dialog --backtitle "Select Map" \
|
||||
--clear \
|
||||
--no-tags \
|
||||
--cancel-label "Exit" \
|
||||
--ok-label "Next" \
|
||||
--menu "Please select one" 0 0 0 "${maps[@]}" --stdout)"
|
||||
fraglimit="$(dialog --backtitle "Fraglimit" \
|
||||
--clear \
|
||||
--ok-label "Next" \
|
||||
--cancel-label "Exit" \
|
||||
--rangebox "Select Fraglimit" -1 -1 1 500 20 --stdout)"
|
||||
[[ $? -eq 1 ]] && exit 0
|
||||
# Get ip address
|
||||
yourIpAddress="$(curl -4s https://icanhazip.com)"
|
||||
players="$(dialog --backtitle "Host Deathmatch Game" \
|
||||
--clear \
|
||||
--ok-label "Next" \
|
||||
--cancel-label "Exit" \
|
||||
--rangebox "Select number of players. Remember to give them your IP address: ${yourIpAddress}" -1 -1 ${mapPlayers[$map]} --stdout)"
|
||||
[[ $? -eq 1 ]] && exit 0
|
||||
skillLevel="$(dialog --backtitle "Host Deathmatch Game" \
|
||||
--clear \
|
||||
--ok-label "Start" \
|
||||
--cancel-label "Exit" \
|
||||
--extra-button \
|
||||
--extra-label "Bots Only" \
|
||||
--rangebox "Select difficulty. 1 easiest, 5 hardest." -1 -1 1 5 3 --stdout)"
|
||||
code=$?
|
||||
[[ $code -eq 1 ]] && exit 0
|
||||
if [[ $code -eq 3 ]]; then
|
||||
players=1
|
||||
dialog --backtitle "Preparing to Launch" \
|
||||
--msgbox "When the game starts, press \` to open the console. Type addbot, press enter. Repeat addbot for as many bots as you would like. Press \` again to close the console." -1 -1 --stdout
|
||||
fi
|
||||
flags=(
|
||||
'-host' "${players}"
|
||||
'-skill' "${skillLevel}"
|
||||
'-deathmatch'
|
||||
'+set' 'sv_cheats' '1'
|
||||
'+fraglimit' "$fraglimit"
|
||||
'+dmflags' '16384' '+dmflags' '4' '+dmflags' '128' '+dmflags' '4096'
|
||||
'+dmflags2' '512' '+dmflags2' '1024'
|
||||
'-extratic' '-dup' '3'
|
||||
'-warp' "$map"
|
||||
)
|
||||
fi
|
||||
|
||||
# Check for and include if present a wad. Some people may not have it.
|
||||
if [[ -e "${doomPath}/DoomMetalVol7.wad" ]]; then
|
||||
gameOption+=" DoomMetalVol7.wad"
|
||||
elif [[ -e "${doomPath}/DoomMetalVol6.wad" ]]; then
|
||||
gameOption+=" DoomMetalVol6.wad"
|
||||
fi
|
||||
|
||||
# Extend the search for new messages to be read.
|
||||
grepStrings+=('-e' ' died.'
|
||||
'-e' 'Ectoplasmic Surge!'
|
||||
'-e' ' has been '
|
||||
'-e' '^(Armor|Health) boosted!'
|
||||
'-e' 'Lesser demon energy'
|
||||
'-e' '^Found '
|
||||
'-e' 'Got the '
|
||||
'-e' 'Picked up '
|
||||
'-e' '^(Mega|Soul)sphere$'
|
||||
'-e' '^Took '
|
||||
'-e' ' was .*(\.|!)'
|
||||
'-e' '^Vanguard of the gods!$'
|
||||
'-e' "You've found "
|
||||
'-e' 'You (collected|got|found|picked up) ')
|
||||
|
||||
# Launch the game and pipe things to be spoken through speech-dispatcher.
|
||||
# This also leaves the console output intact for people who may want to read it.
|
||||
exec stdbuf -oL ${gzdoom} ${gameOption[@]} "${flags[@]}" | while IFS= read -r l ; do echo "$l" | { grep "${grepStrings[@]}" | grep "${antiGrepStrings[@]}" | sed "${sedStrings[@]}" | spd-say -e ${spd_module} ${spd_pitch} ${spd_rate} ${spd_voice} ${spd_volume} -- > /dev/null 2>&1; }; echo "$l";done
|
@@ -14,6 +14,7 @@
|
||||
"aoddoom1.wad"
|
||||
],
|
||||
"optional_files": [
|
||||
"DOOM Metal X IDKFA Soundtrack.pk3",
|
||||
"DoomMetalVol7.wad",
|
||||
"DoomMetalVol6.wad"
|
||||
],
|
||||
|
@@ -17,6 +17,7 @@
|
||||
"DoomguyVsTheDaleks_V1.1.wad"
|
||||
],
|
||||
"optional_files": [
|
||||
"DOOM Metal X IDKFA Soundtrack.pk3",
|
||||
"DoomMetalVol7.wad",
|
||||
"DoomMetalVol6.wad"
|
||||
],
|
||||
|
@@ -17,6 +17,7 @@
|
||||
"Project_Brutality.pk3"
|
||||
],
|
||||
"optional_files": [
|
||||
"DOOM Metal X IDKFA Soundtrack.pk3",
|
||||
"DoomMetalVol7.wad",
|
||||
"DoomMetalVol6.wad"
|
||||
],
|
||||
|
@@ -15,6 +15,7 @@
|
||||
"Project_Brutality-Latest.pk3"
|
||||
],
|
||||
"optional_files": [
|
||||
"DOOM Metal X IDKFA Soundtrack.pk3",
|
||||
"DoomMetalVol7.wad",
|
||||
"DoomMetalVol6.wad"
|
||||
],
|
||||
|
Reference in New Issue
Block a user