diff --git a/Toby Doom Launcher.py b/Toby Doom Launcher.py index b8d0fcc..49ad7f6 100755 --- a/Toby Doom Launcher.py +++ b/Toby Doom Launcher.py @@ -853,11 +853,197 @@ class DoomLauncher(QMainWindow): self.gamePath = Path.home() / ".local/games/doom" self.configFile = Path(os.getenv('XDG_CONFIG_HOME', Path.home() / '.config')) / 'gzdoom/gzdoom.ini' + # Make sure controls are set + self.checkAndFixControls() + self.tobyVersion = TOBY_VERSION self.speechHandler = SpeechHandler(self.configFile) self.iwadSelector = IWADSelector() # Add IWAD selector self.init_launcher_ui() + def checkAndFixControls(self): + """Check and fix control bindings in GZDoom configuration for all game types.""" + if not self.configFile.exists(): + print("Config file not found") + return False + + try: + # Read config file + with open(self.configFile, 'r') as f: + configLines = f.readlines() + + changesNeeded = False + + standardControls = { + 'attack': 'Ctrl', + 'altattack': 'Alt', + 'use': 'Space', + 'turn180': 'X' + } + + tobyAccessibilityControls = { + 'E': 'pukename TurnCompass 1', # Turn compass right + 'R': 'pukename TurnCompass 0', # Turn compass left + 'Q': 'pukename CompassScript', # Compass script + ';': 'netevent Toby_CheckLevelStats', # Check level stats + "'": 'toby_proximity_toggle_keybind' # Toggle proximity detector + } + + # Map section prefixes to their control sections + controlSections = {} + + currentSection = None + for i, line in enumerate(configLines): + line = line.strip() + + # Detect section headers + if line.startswith('[') and line.endswith(']'): + currentSection = line[1:-1] + + # If this is a bindings section, extract the game prefix + if '.Bindings' in currentSection: + prefix = currentSection.split('.')[0] # e.g., 'Doom', 'Heretic' + controlSections[prefix] = controlSections.get(prefix, []) + [currentSection] + + continue + + # Check if we're in any Bindings section + if currentSection and '.Bindings' in currentSection and '=' in line: + key, binding = line.split('=', 1) + key = key.strip() + binding = binding.strip() + + # Check if this line defines a binding we want to change + for control, standardKey in standardControls.items(): + if binding == f"+{control}" and key != standardKey: + # This is a binding we want to fix + configLines[i] = f"{standardKey}=+{control}\n" + changesNeeded = True + print(f"Fixed {control} binding in {currentSection} from {key} to {standardKey}") + + # Check for the Toby accessibility controls across all game types + # For each game prefix, check if it has the correct CompassMod.Bindings, etc. + for prefix, sections in controlSections.items(): + mainBindingSection = f"{prefix}.Bindings" + compassModSection = f"{prefix}.CompassMod.Bindings" + proximitySection = f"{prefix}.ProximityDetector.Bindings" + checkModSection = f"{prefix}.CheckMod.Bindings" + + # Check if the accessibility sections exist, create them if not + if compassModSection not in sections: + # Add this section after the main Bindings section + for i, line in enumerate(configLines): + if line.strip() == f"[{mainBindingSection}]": + # Find the next section + nextSectionIdx = next((j for j in range(i+1, len(configLines)) if configLines[j].strip().startswith('[')), len(configLines)) + # Insert the new section + configLines.insert(nextSectionIdx, f"\n[{compassModSection}]\n") + configLines.insert(nextSectionIdx+1, "Q=pukename CompassScript\n") + configLines.insert(nextSectionIdx+2, "F=pukename FaceNorth\n") + configLines.insert(nextSectionIdx+3, "E=pukename TurnCompass 1\n") + configLines.insert(nextSectionIdx+4, "R=pukename TurnCompass 0\n\n") + changesNeeded = True + print(f"Added {compassModSection} section") + break + + if proximitySection not in sections: + # Need to add this section + for i, line in enumerate(configLines): + if line.strip() == f"[{mainBindingSection}]": + # Find the next section + nextSectionIdx = next((j for j in range(i+1, len(configLines)) if configLines[j].strip().startswith('[')), len(configLines)) + # Insert the new section before the next section + configLines.insert(nextSectionIdx, f"\n[{proximitySection}]\n") + configLines.insert(nextSectionIdx+1, "'=toby_proximity_toggle_keybind\n\n") + changesNeeded = True + print(f"Added {proximitySection} section") + break + + if checkModSection not in sections: + # Need to add this section + for i, line in enumerate(configLines): + if line.strip() == f"[{mainBindingSection}]": + # Find the next section + nextSectionIdx = next((j for j in range(i+1, len(configLines)) if configLines[j].strip().startswith('[')), len(configLines)) + # Insert the new section before the next section + configLines.insert(nextSectionIdx, f"\n[{checkModSection}]\n") + configLines.insert(nextSectionIdx+1, "U=netevent Toby_CheckCoordinates\n") + configLines.insert(nextSectionIdx+2, "H=netevent Toby_CheckHealth\n") + configLines.insert(nextSectionIdx+3, "N=netevent Toby_CheckArmor\n") + configLines.insert(nextSectionIdx+4, "B=netevent Toby_CheckAmmo\n") + configLines.insert(nextSectionIdx+5, "K=netevent Toby_CheckKeys\n") + configLines.insert(nextSectionIdx+6, "I=netevent Toby_CheckCurrentItem\n") + configLines.insert(nextSectionIdx+7, ";=netevent Toby_CheckLevelStats\n\n") + changesNeeded = True + print(f"Added {checkModSection} section") + break + + # Check if accessibility keys are correctly set in existing sections + currentSection = None + for i, line in enumerate(configLines): + line = line.strip() + + # Detect section headers + if line.startswith('[') and line.endswith(']'): + currentSection = line[1:-1] + continue + + # Process compass mod bindings + if currentSection == compassModSection and '=' in line: + key, binding = line.split('=', 1) + key = key.strip() + binding = binding.strip() + + # Check E and R keys for compass functions + if key == 'E' and binding != 'pukename TurnCompass 1': + configLines[i] = "E=pukename TurnCompass 1\n" + changesNeeded = True + print(f"Fixed E key in {compassModSection}") + elif key == 'R' and binding != 'pukename TurnCompass 0': + configLines[i] = "R=pukename TurnCompass 0\n" + changesNeeded = True + print(f"Fixed R key in {compassModSection}") + elif key == 'Q' and binding != 'pukename CompassScript': + configLines[i] = "Q=pukename CompassScript\n" + changesNeeded = True + print(f"Fixed Q key in {compassModSection}") + + # Process proximity detector bindings + if currentSection == proximitySection and '=' in line: + key, binding = line.split('=', 1) + key = key.strip() + binding = binding.strip() + + # Check apostrophe key for proximity toggle + if key == "'" and binding != 'toby_proximity_toggle_keybind': + configLines[i] = "'=toby_proximity_toggle_keybind\n" + changesNeeded = True + print(f"Fixed ' key in {proximitySection}") + + # Process check mod bindings + if currentSection == checkModSection and '=' in line: + key, binding = line.split('=', 1) + key = key.strip() + binding = binding.strip() + + # Check semicolon key for level stats + if key == ";" and binding != 'netevent Toby_CheckLevelStats': + configLines[i] = ";=netevent Toby_CheckLevelStats\n" + changesNeeded = True + print(f"Fixed ; key in {checkModSection}") + + # Write the config if needed + if changesNeeded: + with open(self.configFile, 'w') as f: + f.writelines(configLines) + print("Updated GZDoom configuration with standard key bindings") + + return changesNeeded + + except Exception as e: + print(f"Error checking/fixing controls: {e}", file=sys.stderr) + return False + def generate_single_player_script(self): """Generate script for single player game""" selectedGame = self.gameCombo.currentText()