The specific version of wine can be set in the registry for each app. Also, add fakejapanese to the Shadow Line installation, though it is still shitting the bed.
710 lines
28 KiB
Bash
Executable File
710 lines
28 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
|
|
# Get script directory for relative paths
|
|
scriptDir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
|
|
# Dialog accessibility
|
|
export DIALOGOPTS='--no-lines --visit-items'
|
|
|
|
# Wine32 version for SAPI compatibility
|
|
wineThirtyTwoVersion="9.0"
|
|
|
|
# Check and manage wine32 installation
|
|
check_wine32() {
|
|
local wine32Dir="${XDG_DATA_HOME:-$HOME/.local/share}/audiogame-manager/wine32"
|
|
local versionFile="$wine32Dir/VERSION"
|
|
local currentVersion=""
|
|
|
|
# Check current installed version
|
|
[[ -f "$versionFile" ]] && currentVersion=$(cat "$versionFile")
|
|
|
|
# If version mismatch or missing, install/update
|
|
if [[ "$currentVersion" != "$wineThirtyTwoVersion" ]]; then
|
|
# Remove old installation
|
|
rm -rf "$wine32Dir" 2>/dev/null
|
|
mkdir -p "$wine32Dir"
|
|
|
|
# Download wine32 using existing download function
|
|
local wineFile="PlayOnLinux-wine-${wineThirtyTwoVersion}-upstream-linux-x86.tar.gz"
|
|
local wineUrl="https://www.playonlinux.com/wine/binaries/phoenicis/upstream-linux-x86/${wineFile}"
|
|
|
|
# Use existing download function which handles progress
|
|
download "$wineUrl"
|
|
|
|
# Extract with progress feedback
|
|
{
|
|
echo "# Extracting Wine32 version $wineThirtyTwoVersion..."
|
|
if tar xf "${cache}/${wineFile}" -C "$wine32Dir" --strip-components=1; then
|
|
echo "$wineThirtyTwoVersion" > "$versionFile"
|
|
echo "# Wine32 setup complete."
|
|
else
|
|
echo "# Failed to extract wine32. SAPI games may not work properly."
|
|
rm -rf "$wine32Dir"
|
|
fi
|
|
} | agm_progressbox "Wine32 Setup" "Extracting Wine32 for SAPI compatibility..."
|
|
fi
|
|
|
|
# Export wine32 path for bottle creation
|
|
if [[ -f "$wine32Dir/bin/wine" ]]; then
|
|
export wine32="$wine32Dir/bin/wine"
|
|
export wine32server="$wine32Dir/bin/wineserver"
|
|
fi
|
|
}
|
|
|
|
# Ensure wine64 bottle exists with all dependencies (wine32 no longer needed!)
|
|
ensure_wine_bottles() {
|
|
local wine64Bottle="$HOME/.local/wine64"
|
|
|
|
# Create wine64 bottle if missing - now includes SAPI support via WINETRICKS_FORCE=1
|
|
if [[ ! -d "$wine64Bottle" ]] || [[ ! -f "$wine64Bottle/system.reg" ]]; then
|
|
{
|
|
echo "# Creating wine64 bottle for modern games..."
|
|
|
|
# Set up environment for wine64
|
|
export WINEPREFIX="$wine64Bottle"
|
|
export WINE="wine"
|
|
export WINESERVER="wineserver"
|
|
unset WINEARCH
|
|
|
|
# Initialize wine64 bottle
|
|
echo "# Initializing wine64 environment..."
|
|
DISPLAY="" wine wineboot -u
|
|
|
|
# Install mono and gecko
|
|
echo "# Installing .NET Framework..."
|
|
monoPath="$(find /usr/share/wine/ -maxdepth 1 -type d -name mono 2> /dev/null)"
|
|
if [[ -z "$monoPath" ]]; then
|
|
download 'http://dl.winehq.org/wine/wine-mono/6.0.0/wine-mono-6.0.0-x86.msi'
|
|
monoPath="${cache}/wine-mono-6.0.0-x86.msi"
|
|
fi
|
|
wine msiexec /i z:"$monoPath" /quiet
|
|
|
|
echo "# Installing web browser support..."
|
|
geckoPath="$(find /usr/share/wine/ -maxdepth 1 -type d -name "gecko" 2> /dev/null)"
|
|
if [[ -z "$geckoPath" ]]; then
|
|
download 'http://dl.winehq.org/wine/wine-gecko/2.40/wine_gecko-2.40-x86.msi'
|
|
geckoPath="${cache}/wine_gecko-2.40-x86.msi"
|
|
fi
|
|
wine msiexec /i z:"$geckoPath" /quiet
|
|
|
|
# Install common dependencies for modern games
|
|
echo "# Installing common dependencies..."
|
|
winetricks -q isolate_home corefonts vcrun2019 win10
|
|
|
|
# Install Speech SDK for SAPI compatibility (experimental - requires WINETRICKS_FORCE=1)
|
|
echo "# Installing Speech SDK for wine64 SAPI support..."
|
|
env WINE="$WINE" WINESERVER="$WINESERVER" DISPLAY="${DISPLAY:-:0}" WINETRICKS_FORCE=1 winetricks -q speechsdk
|
|
|
|
# Restore win10 after speechsdk (speechsdk sets winxp)
|
|
winetricks -q win10
|
|
|
|
# Initialize SAPI and set Microsoft Mike as default voice
|
|
echo "# Setting Microsoft Mike as default voice..."
|
|
mkdir -p "${WINEPREFIX}/drive_c/windows/temp"
|
|
cat << "EOF" > "${WINEPREFIX}/drive_c/windows/temp/init_sapi.vbs"
|
|
dim speechobject
|
|
set speechobject=createobject("sapi.spvoice")
|
|
speechobject.speak ""
|
|
EOF
|
|
wine cscript "c:\\windows\\temp\\init_sapi.vbs"
|
|
|
|
wine reg add "HKCU\\SOFTWARE\\Microsoft\\Speech\\Voices" /v "DefaultTokenId" /t REG_SZ /d "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Speech\\Voices\\Tokens\\MSMike" /f
|
|
wine reg add "HKCU\\SOFTWARE\\Microsoft\\Speech\\Voices" /v "DefaultTTSRate" /t REG_DWORD /d "7" /f
|
|
echo "Set Microsoft Mike as default voice for wine64"
|
|
|
|
# Setup nvda2speechd for accessibility
|
|
echo "# Setting up accessibility support..."
|
|
download "${nvda2speechdBinary}"
|
|
if [[ ! -f "${XDG_DATA_HOME:-$HOME/.local/share}/audiogame-manager/nvda2speechd" ]]; then
|
|
cp "${cache}/nvda2speechd" "${XDG_DATA_HOME:-$HOME/.local/share}/audiogame-manager/nvda2speechd"
|
|
chmod +x "${XDG_DATA_HOME:-$HOME/.local/share}/audiogame-manager/nvda2speechd"
|
|
fi
|
|
|
|
echo "# Wine64 bottle creation complete."
|
|
} | agm_progressbox "Wine Bottle Setup" "Creating unified wine64 bottle with SAPI support (this may take several minutes)..."
|
|
fi
|
|
}
|
|
|
|
|
|
# Install games
|
|
game_installer() {
|
|
export LANG="en_US.UTF-8"
|
|
# Get list of installed games from config file
|
|
mapfile -t installedGames < <(sed -e '/^$/d' -e '/^[[:space:]]*#/d' "${configFile}" 2> /dev/null | cut -d '|' -f3)
|
|
# Create the menu of available games by reading from .install directory
|
|
declare -a menuList
|
|
# Get all .sh files from .install directory, excluding those starting with # as first line.
|
|
mapfile -t sortedGames < <(for f in "${scriptDir}/.install/"*.sh; do
|
|
# Skip if first line starts with #
|
|
[[ $(head -n1 "$f") == "#"* ]] && continue
|
|
echo "${f##*/%.sh}"
|
|
done | sort)
|
|
for i in "${sortedGames[@]}"; do
|
|
local menuItem="${i%.sh}"
|
|
menuItem="${menuItem##*/}"
|
|
# Check if game is already installed
|
|
for j in "${installedGames[@]}"; do
|
|
if [[ "$j" == "$menuItem" ]]; then
|
|
unset menuItem
|
|
break
|
|
fi
|
|
done
|
|
# Add to menu if not installed
|
|
if [[ -n "$menuItem" ]]; then
|
|
menuList+=("$menuItem" "$menuItem")
|
|
fi
|
|
done
|
|
# If all games are installed, exit
|
|
if [[ ${#menuList[@]} -eq 0 ]]; then
|
|
agm_msgbox "Audio Game Installer" "" "All games are already installed."
|
|
exit 0
|
|
fi
|
|
menuList+=("Donate" "Donate")
|
|
menuList+=("Become a Patron" "Become a Patron")
|
|
# Show game selection dialog
|
|
game="$(agm_menu "Audio Game Installer" "Audio Game Installer" "Please select a game to install" "${menuList[@]}")"
|
|
[[ $? -ne 0 ]] && exit 0
|
|
# Handle selection
|
|
if [[ -n "$game" ]]; then
|
|
case "$game" in
|
|
"Donate")
|
|
open_url "https://ko-fi.com/stormux"
|
|
exit 0
|
|
;;
|
|
"Become a Patron")
|
|
open_url "https://patreon.com/stormux"
|
|
exit 0
|
|
;;
|
|
*)
|
|
# Convert game name to filename format
|
|
local installScript="${scriptDir}/.install/${game}.sh"
|
|
# Check if install script exists
|
|
if [[ -f "$installScript" ]]; then
|
|
# Source and execute the install script
|
|
source "$installScript"
|
|
# Show success message
|
|
agm_msgbox "Installation Complete" "Audio Game Installer" "Game \"${game}\" has been successfully installed."
|
|
else
|
|
agm_msgbox "Audio Game Installer" "Audio Game Installer" "Installation script not found for ${game}"
|
|
exit 1
|
|
fi
|
|
;;
|
|
esac
|
|
fi
|
|
}
|
|
|
|
# remove games
|
|
game_removal() {
|
|
source "${scriptDir}/.includes/bottle.sh"
|
|
# Modern wine is unified - no architecture-specific wine executables needed
|
|
mapfile -t lines < <(sed -e '/^$/d' -e '/^[[:space:]]*#/d' "${configFile}" 2> /dev/null)
|
|
if [[ ${#lines} -eq 0 ]]; then
|
|
agm_msgbox "Audio Game Removal" "" "No games found."
|
|
exit 0
|
|
fi
|
|
# Create the menu of installed games
|
|
declare -a menuList
|
|
for i in "${lines[@]}" ; do
|
|
IFS='|' read -ra gameInfo <<< "$i"
|
|
menuList+=("${gameInfo[0]}|${gameInfo[1]}" "${gameInfo[2]}")
|
|
done
|
|
menuList+=("Donate" "Donate")
|
|
menuList+=("Become a Patron" "Become a Patron")
|
|
local game
|
|
game="$(agm_menu "Audio Game Removal" "Audio Game Removal" "Please select a game to delete" "${menuList[@]}")"
|
|
if [[ ${#game} -gt 0 ]]; then
|
|
if [[ "$game" == "Donate" ]]; then
|
|
open_url "https://ko-fi.com/stormux"
|
|
exit 0
|
|
fi
|
|
if [[ "$game" == "Become a Patron" ]]; then
|
|
open_url "https://2mb.games/product/2mb-patron/"
|
|
exit 0
|
|
fi
|
|
# Parse game info before create_game_array overwrites $game
|
|
local selectedGame="$game"
|
|
local winePath="${game#*|}"
|
|
export winePath="${winePath%\\*.exe}"
|
|
local wineExec="${game#*|}"
|
|
wineExec="${wineExec%|*}"
|
|
wineExec="${wineExec##*\\}"
|
|
|
|
# With shared bottles, always remove only the game files, never the entire bottle
|
|
create_game_array "$selectedGame"
|
|
if [[ ${#game[@]} -gt 0 ]]; then
|
|
# Set up wine environment for this game
|
|
source "${scriptDir}/.includes/bottle.sh"
|
|
get_bottle "${game[0]}"
|
|
|
|
if ! agm_yesno "Confirm Removal" "Audio Game Removal" "Are you sure you want to remove \"${game[2]}\"?"; then
|
|
agm_msgbox "Audio Game Removal" "" "Removal cancelled."
|
|
exit 0
|
|
fi
|
|
|
|
# kill any previous existing wineservers for this prefix in case they didn't shut down properly.
|
|
wineserver -k
|
|
|
|
# Remove only the game's installation directory
|
|
if [[ -n "$winePath" ]]; then
|
|
local gameDir="$(winepath "$winePath")"
|
|
if [[ -d "$gameDir" ]]; then
|
|
rm -rfv "$gameDir" | agm_progressbox "Removing Game" "Removing \"${game[2]}\" files..."
|
|
else
|
|
agm_msgbox "Game Removal" "" "Game directory not found, skipping file removal."
|
|
fi
|
|
fi
|
|
fi
|
|
# remove the launcher using the original selected game info
|
|
gawk -i inplace -vLine="${selectedGame//\\/\\\\}" '!index($0,Line)' "$configFile"
|
|
agm_msgbox "Game Removal" "" "\"${game[2]}\" has been successfully removed."
|
|
fi
|
|
exit 0
|
|
}
|
|
|
|
# kill games that are stuck
|
|
kill_game() {
|
|
source "${scriptDir}/.includes/bottle.sh"
|
|
# Modern wine is unified - no architecture-specific wine executables needed
|
|
mapfile -t lines < <(sed '/^$/d' "${configFile}" 2> /dev/null)
|
|
if [[ ${#lines} -eq 0 ]]; then
|
|
agm_msgbox "Audio Game Killer" "" "No games found."
|
|
exit 0
|
|
fi
|
|
# Create the menu of installed games
|
|
declare -a menuList
|
|
for i in "${lines[@]}" ; do
|
|
IFS='|' read -ra gameInfo <<< "$i"
|
|
menuList+=("${gameInfo[0]}|${gameInfo[1]}" "${gameInfo[2]}")
|
|
done
|
|
menuList+=("Donate" "Donate")
|
|
menuList+=("Become a Patron" "Become a Patron")
|
|
local game="$(agm_menu "Audio Game Killer" "Audio Game Killer" "Please select a game to force stop" "${menuList[@]}")"
|
|
if [[ ${#game} -gt 0 ]]; then
|
|
if [[ "$game" == "Donate" ]]; then
|
|
open_url "https://ko-fi.com/stormux"
|
|
exit 0
|
|
fi
|
|
if [[ "$game" == "Become a Patron" ]]; then
|
|
open_url "https://2mb.games/product/2mb-patron/"
|
|
exit 0
|
|
fi
|
|
local winePath="${game#*|}"
|
|
winePath="${winePath%\\*.exe}"
|
|
local wineExec="${game#*|}"
|
|
wineExec="${wineExec%|*}"
|
|
wineExec="${wineExec##*\\}"
|
|
# kill the wine server.
|
|
get_bottle "${game%|*}"
|
|
wineserver -k
|
|
agm_msgbox "Audio Game Killer" "" "The selected game has been stopped."
|
|
fi
|
|
exit 0
|
|
}
|
|
|
|
# for games that require custom scripts before launch or custom launch parameters
|
|
custom_launch_parameters() {
|
|
if [[ "${game[2]}" == "Dragon Pong" ]]; then
|
|
"${scriptDir}/speech/speak_window_title.sh" DragonPong.exe &
|
|
pushd "$(winepath "$winePath")"
|
|
wine "$wineExec"
|
|
popd
|
|
exit 0
|
|
fi
|
|
if [[ "${game[2]}" == "Dreamland" ]]; then
|
|
"$WINE" "${game[1]}" &> /dev/null &
|
|
exit 0
|
|
fi
|
|
# executioner's-rage: DLL replacement now handled by update_nvda_dlls()
|
|
if [[ "${game[2]}" == "Laser Breakout" ]]; then
|
|
"${scriptDir}/speech/speak_window_title.sh" play.exe &
|
|
fi
|
|
if [[ "${game[2]}" == "Bokurano Daibouken 2" ]]; then
|
|
find "${WINEPREFIX}/drive_c/nyanchangame/bk2" -type f -name 'nvdaControllerClient.dll' -exec rm -v "{}" \;
|
|
"${scriptDir}/speech/clipboard_translator.sh" "play.exe" bokurano-daibouken2 &
|
|
fi
|
|
if [[ "${game[2]}" == "Bokurano Daibouken" ]]; then
|
|
find "${WINEPREFIX}/drive_c/nyanchangame/bk" -type f -name 'nvdaControllerClient.dll' -exec rm -v "{}" \;
|
|
"${scriptDir}/speech/clipboard_translator.sh" "play.exe" bokurano-daibouken &
|
|
fi
|
|
if [[ "${game[2]}" == "Bokurano Daibouken 3" ]]; then
|
|
dictPath="$(winepath "${winePath}")"
|
|
if [[ -r "${cache}/bk3-dict.dat" ]] && [[ ! -d "${dictPath}/dict" ]]; then
|
|
cp "${cache}/bk3-dict.dat" "${dictPath}/dict.dat"
|
|
fi
|
|
# DLL replacement now handled by update_nvda_dlls()
|
|
if [[ ! -d "${dictPath}/dict" ]] && [[ ! -r "${cache}/bk3-dict.dat" ]]; then
|
|
find "${WINEPREFIX}/drive_c/nyanchangame/bk3" -type f -name 'nvdaControllerClient.dll' -exec rm -v "{}" \;
|
|
"${scriptDir}/speech/clipboard_translator.sh" "play.exe" bokurano-daibouken3 &
|
|
fi
|
|
fi
|
|
if [[ "${game[2]}" == "Bop It Emulator" ]]; then
|
|
"${scriptDir}/speech/speak_window_title.sh" bop.exe &
|
|
fi
|
|
if [[ "${game[2]}" == "Road to Rage" ]]; then
|
|
"${scriptDir}/speech/speak_window_title.sh" trtr.exe &
|
|
fi
|
|
if [[ "${game[2]}" == "Sequence Storm" ]]; then
|
|
"${scriptDir}/speech/clipboard_reader.sh" SequenceStorm &
|
|
fi
|
|
#if [[ "${game[2]}" == "Shadow Line" ]]; then
|
|
#find "${WINEPREFIX}/drive_c/" -type f -name 'nvdaControllerClient.dll' -exec rm -v "{}" \;
|
|
#"${scriptDir}/speech/clipboard_translator.sh" play_sr.exe shadow-line &
|
|
#fi
|
|
# sketchbook: DLL replacement now handled by update_nvda_dlls()
|
|
if [[ "${game[2]}" == "Audiodisc" ]]; then
|
|
wine "$winePath\\$wineExec"
|
|
exit 0
|
|
fi
|
|
if [[ "${game[2]}" == "Audioquake" ]]; then
|
|
wine "$winePath\\$wineExec"
|
|
exit 0
|
|
fi
|
|
if [[ "${game[2]}" == "Screaming Strike 2" ]]; then
|
|
pushd "$(winepath "$winePath")"
|
|
wine "$wineExec"
|
|
popd
|
|
exit 0
|
|
fi
|
|
if [[ "${game[2]}" == "Warsim" ]]; then
|
|
pushd "$(winepath "${game[1]%\\*}")"
|
|
wine "${game[1]##*\\}"
|
|
popd
|
|
exit 0
|
|
fi
|
|
if [[ "${game[2]}" == "Interceptor" ]]; then
|
|
pushd "$(winepath "$winePath")"
|
|
wine "$wineExec"
|
|
popd
|
|
exit 0
|
|
fi
|
|
}
|
|
|
|
# Process game launcher flags
|
|
process_launcher_flags() {
|
|
flags=("${game[@]:3}")
|
|
for i in "${flags[@]}" ; do
|
|
if [[ "${i}" =~ ^export\ [a-zA-Z_][a-zA-Z0-9_]*=\'?.*\'?$ ]]; then
|
|
eval "${i}"
|
|
fi
|
|
done
|
|
}
|
|
|
|
create_game_array() {
|
|
# Game array 0 bottle, 1 path, 2 title, 3+ flags
|
|
game="$1"
|
|
for i in "${lines[@]}" ; do
|
|
# Only compare the launcher section
|
|
j="${game#*|}"
|
|
k="${i#*|}"
|
|
k="${k%%|*}"
|
|
if [[ "$j" == "$k" ]]; then
|
|
IFS='|' read -ra game <<< "$i"
|
|
break
|
|
fi
|
|
done
|
|
}
|
|
|
|
# Update NVDA controller client DLLs in wine bottles
|
|
update_nvda_dlls() {
|
|
# Ensure we have the replacement DLLs
|
|
source "${scriptDir}/.includes/functions.sh"
|
|
download "${nvdaControllerClientDll}" "${nvdaControllerClient64Dll}"
|
|
|
|
# Update wine64 bottle (most common)
|
|
if [[ -d "$HOME/.local/wine64" ]]; then
|
|
find "$HOME/.local/wine64" -type f \( -iname "nvdaControllerClient*.dll" \) -print0 | while IFS= read -r -d '' dllFile; do
|
|
local basename="${dllFile##*/}"
|
|
local replacement=""
|
|
|
|
case "${basename,,}" in
|
|
"nvdacontrollerclient32.dll")
|
|
replacement="${cache}/nvdaControllerClient32.dll"
|
|
;;
|
|
"nvdacontrollerclient64.dll")
|
|
replacement="${cache}/nvdaControllerClient64.dll"
|
|
;;
|
|
"nvdacontrollerclient.dll")
|
|
# Use file command to detect architecture
|
|
if file "$dllFile" | grep -q "PE32+"; then
|
|
replacement="${cache}/nvdaControllerClient64.dll"
|
|
elif file "$dllFile" | grep -q "PE32"; then
|
|
replacement="${cache}/nvdaControllerClient32.dll"
|
|
fi
|
|
;;
|
|
esac
|
|
|
|
if [[ -n "$replacement" ]] && [[ -f "$replacement" ]]; then
|
|
echo "Updating $dllFile with nvdaControllerClient"
|
|
cp "$replacement" "$dllFile"
|
|
fi
|
|
done
|
|
fi
|
|
|
|
# Note: 32-bit games running via WOW64 in wine64 bottle are handled above
|
|
# The 'file' command detects PE32 vs PE32+ and applies the correct DLL version
|
|
}
|
|
|
|
# launch games that are installed
|
|
game_launcher() {
|
|
# For use by update scripts that want to source functions in this file.
|
|
[[ "$agmNoLaunch" == "true" ]] && return
|
|
source "${scriptDir}/.includes/bottle.sh"
|
|
|
|
# Start nvda2speechd if available
|
|
if [[ -x ${XDG_DATA_HOME:-$HOME/.local/share}/audiogame-manager/nvda2speechd ]]; then
|
|
${XDG_DATA_HOME:-$HOME/.local/share}/audiogame-manager/nvda2speechd &> /dev/null &
|
|
fi
|
|
|
|
# Replace NVDA controller client DLLs in wine64 bottle
|
|
update_nvda_dlls
|
|
mapfile -t lines < <(sed -e '/^$/d' -e '/^ *#/d' "${configFile}" 2> /dev/null)
|
|
if [[ ${#lines} -eq 0 ]]; then
|
|
agm_msgbox "Audio Game Launcher" "" "Install some games first."
|
|
exit 0
|
|
fi
|
|
if [[ $# -eq 0 ]]; then
|
|
# Create the menu of installed games
|
|
declare -a menuList
|
|
for i in "${lines[@]}" ; do
|
|
IFS='|' read -ra gameInfo <<< "$i"
|
|
menuList+=("${gameInfo[0]}|${gameInfo[1]}" "${gameInfo[2]}")
|
|
done
|
|
menuList+=("Donate" "Donate")
|
|
menuList+=("Become a Patron" "Become a Patron")
|
|
local game=""
|
|
game="$(agm_menu "Audio Game Launcher" "Audio Game Launcher" "Please select a game to play" "${menuList[@]}")"
|
|
local menuCode=$?
|
|
if [[ $menuCode -eq 1 ]] || [[ $menuCode -eq 255 ]]; then
|
|
exit 0
|
|
elif [[ $menuCode -eq 3 ]]; then
|
|
source "${scriptDir}/.includes/help.sh" # Make available in this function
|
|
documentation "$game" "$(echo "$game" | cut -d '|' -f2)"
|
|
fi
|
|
|
|
# Safety check: don't proceed if game is empty
|
|
if [[ -z "$game" ]]; then
|
|
exit 0
|
|
fi
|
|
|
|
create_game_array "$game"
|
|
else
|
|
create_game_array "$game"
|
|
if [[ -z "$game" ]]; then
|
|
agm_msgbox "Audio Game Launcher" "" "Game $1 not found."
|
|
exit 1
|
|
fi
|
|
fi
|
|
if [[ ${#game[@]} -gt 0 ]]; then
|
|
if [[ "${game[0]}" == "Donate" ]]; then
|
|
open_url "https://ko-fi.com/stormux"
|
|
exit 0
|
|
fi
|
|
if [[ "${game[0]}" == "Become a Patron" ]]; then
|
|
open_url "https://2mb.games/product/2mb-patron/"
|
|
exit 0
|
|
fi
|
|
get_bottle "${game[0]}"
|
|
echo -n "launching "
|
|
wine --version
|
|
# kill any previous existing wineservers for this prefix in case they didn't shut down properly.
|
|
wineserver -k
|
|
# launch the game
|
|
if command -v qjoypad &> /dev/null ; then
|
|
mkdir -p ~/.qjoypad3
|
|
touch "${HOME}/.qjoypad3/${game[2]}.lyt"
|
|
# A | separated list of games that should not start with qjoypad.
|
|
noQjoypadGames="A Hero's Call"
|
|
if [[ "${noqjoypad}" != "true" ]] && ! [[ "${game[2]}" =~ ${noQjoypadGames} ]]; then
|
|
if pgrep qjoypad &> /dev/null ; then
|
|
qjoypad -T "${game[2]}" 2> /dev/null
|
|
else
|
|
qjoypad -T "${game[2]}" 2> /dev/null &
|
|
fi
|
|
fi
|
|
fi
|
|
process_launcher_flags
|
|
custom_launch_parameters
|
|
if [[ "$debugGdb" == "1" ]]; then
|
|
# Change to game directory before launching
|
|
pushd "$(winepath "${game[1]%\\*}")" > /dev/null
|
|
winedbg --gdb "${game[1]##*\\}"
|
|
popd > /dev/null
|
|
else
|
|
wine start /d "${game[1]%\\*}" "${game[1]##*\\}" /realtime
|
|
fi
|
|
fi
|
|
exit 0
|
|
}
|
|
|
|
|
|
# main script
|
|
|
|
trap "exit 0" SIGINT
|
|
|
|
# Detect dialog interface type BEFORE potentially setting DISPLAY
|
|
# This must happen before we modify DISPLAY to preserve console detection
|
|
if [[ -z "$DISPLAY" ]]; then
|
|
dialogType="dialog"
|
|
elif command -v yad &> /dev/null; then
|
|
dialogType="yad"
|
|
else
|
|
dialogType="dialog"
|
|
fi
|
|
|
|
# Source dialog interface early for progress display
|
|
source "${scriptDir}/.includes/dialog-interface.sh"
|
|
|
|
# If display isn't set assume we are launching from console and an X environment is running using display :0
|
|
if [[ -z "$DISPLAY" ]]; then
|
|
export DISPLAY=":0"
|
|
fi
|
|
# Settings file
|
|
export cache="${XDG_CACHE_HOME:-$HOME/.cache}/audiogame-manager"
|
|
export configFile="${XDG_CONFIG_HOME:-$HOME/.config}/storm-games/audiogame-manager/games.conf"
|
|
mkdir -p "${cache}"
|
|
mkdir -p "${configFile%/*}"
|
|
# Create the path for AGM's helper programs.
|
|
# Originally this was only winetricks, thus the name, and I'm too lazy to change it now.
|
|
winetricksPath="${XDG_DATA_HOME:-$HOME/.local/share}/audiogame-manager"
|
|
mkdir -p "${winetricksPath}"
|
|
# Load any arguments from settings.conf file
|
|
if [[ -r "${configFile%/*}/settings.conf" ]]; then
|
|
source "${configFile%/*}/settings.conf"
|
|
fi
|
|
# Update the cache for older versions of audiogame-manager
|
|
if [[ -d "${configFile%/*}/cache" ]]; then
|
|
{ mv -v "${configFile%/*}/cache/"* "${cache}"
|
|
rmdir -v "${configFile%/*}/cache/"; } | agm_progressbox "Audiogame Manager" "Updating cache, please wait..."
|
|
fi
|
|
checkWinetricksUpdate="false"
|
|
# Turn off debug messages
|
|
export WINEDEBUG="${winedebug:--all}"
|
|
# During installation, you can set winVer to the versions available.
|
|
# To set winetricks arguments, such as virtual desktop, set the winetricksSettings variable.
|
|
# Example: winetricksSettings="vd=1024x768"
|
|
# Files are cached unless -N no cache is set.
|
|
unset noCache
|
|
# Manual installation is not default, make sure it's unset
|
|
unset manualInstall
|
|
unset version
|
|
# ipfs gateway
|
|
export ipfsGateway="${ipfsGateway:-https://ipfs.stormux.org}"
|
|
export nvdaControllerClientDll="${ipfsGateway}/ipfs/Qmd1JXdDoKJVnoaQssDiBgRpbgwKUwdJigiPw8iiYro3vt?filename=nvdaControllerClient32.dll"
|
|
export nvdaControllerClient64Dll="${ipfsGateway}/ipfs/QmcPoBTm6eCFF4R4uUc1of3rtrqMVx3HFN1U1jHosay8EX?filename=nvdaControllerClient64.dll"
|
|
export nvda2speechdBinary="${ipfsGateway}/ipfs/QmPxhoNsoFoJC7bCfioBBCcK8tEoSoYpm342z6u7KjFsVz?filename=nvda2speechd"
|
|
|
|
# nvda2speechd server startup is now handled in game_launcher()
|
|
|
|
|
|
# Source helper functions
|
|
source "${scriptDir}/.includes/bottle.sh" # Also sourced in functions that need it
|
|
source "${scriptDir}/.includes/desktop.sh"
|
|
# dialog-interface.sh already sourced earlier
|
|
source "${scriptDir}/.includes/functions.sh"
|
|
source "${scriptDir}/.includes/help.sh"
|
|
source "${scriptDir}/.includes/update.sh"
|
|
|
|
# Check minimum requirements
|
|
check_requirements || exit 1
|
|
# Wine32 no longer needed - all games use wine64 with SAPI support via WINETRICKS_FORCE=1
|
|
# check_wine32 # Disabled - wine32 eliminated 2025-12-06
|
|
# Ensure wine bottles exist with dependencies
|
|
ensure_wine_bottles
|
|
# Check for updates
|
|
update
|
|
# Get latest news if available
|
|
check_news
|
|
|
|
# With no arguments, open the game launcher.
|
|
if [[ $# -eq 0 ]]; then
|
|
game_launcher
|
|
fi
|
|
|
|
# Array of command line arguments
|
|
declare -A command=(
|
|
[c]="Check your system for necessary components."
|
|
[C]="Clear the cache. All game installers will be deleted."
|
|
[D]="Create desktop shortcut. You can launch audiogame-manager from the desktop or applications menu."
|
|
[d]="Debug mode, wine will be much more verbose when games are installed with this flag."
|
|
[g]="Debug with GDB. Launch game with winedbg --gdb for step-through debugging."
|
|
[h]="This help screen."
|
|
[i]="Install games."
|
|
[I:]="Noninteractive game installation."
|
|
[k]="Kill a running game that is stuck."
|
|
[L]="Display license information."
|
|
[l:]="Launch given game without interactive audiogame-manager menu specified by its wine bottle."
|
|
[N]="No cache, delete the installer after it has been extracted."
|
|
[n]="No RHVoice, do not install RHVoice when the game is installed."
|
|
[P]="Print a list of packages required by audiogame-manager."
|
|
[q]="No qjoypad. Does not launch qjoypad if it is detected."
|
|
[R]="Redownload. Removes old versions of packages from cache before installing."
|
|
[r]="Remove a game. This will delete all game data."
|
|
[S:]="Speech rate. Requires -V voice name, the default is 7. Values 0-9 or A."
|
|
[t]="Total games. Show how many games are currently available."
|
|
[v:]="Select the voice to be installed, default is Bdl. Options are alan, bdl, clb, or slt."
|
|
[V:]="Select the default voice for a bottle."
|
|
)
|
|
|
|
# Convert the keys of the associative array to a format usable by getopts
|
|
args="${!command[*]}"
|
|
args="${args//[[:space:]]/}"
|
|
while getopts "${args}" i ; do
|
|
case "$i" in
|
|
c) "${scriptDir}/.includes/checkup.sh";;
|
|
C) clear_cache;;
|
|
D) desktop_launcher;;
|
|
d)
|
|
unset WINEDEBUG
|
|
game_installer
|
|
;;
|
|
g)
|
|
debugGdb=1
|
|
game_launcher;;
|
|
h) help;;
|
|
i) game_installer;;
|
|
I)
|
|
export game="${OPTARG}"
|
|
export noninteractiveInstall="true"
|
|
break;;
|
|
k) kill_game;;
|
|
L) license;;
|
|
l) game_launcher "${OPTARG}";;
|
|
N) noCache="true";;
|
|
n) norh="true";;
|
|
P) checklist quiet;;
|
|
q)
|
|
noqjoypad="true"
|
|
game_launcher;;
|
|
R) redownload="true";;
|
|
r) game_removal;;
|
|
S) defaultRate="${OPTARG}";;
|
|
t)
|
|
gameCount=$(find "${scriptDir}/.install" -type f -iname "*.sh" | wc -l)
|
|
agm_infobox "Linux Game Manager" "Linux Game Manager" "There are currently ${gameCount} games available."
|
|
exit 0
|
|
;;
|
|
v) voiceName="${OPTARG}";;
|
|
V) defaultVoice="${OPTARG}";;
|
|
esac
|
|
done
|
|
|
|
# If agmNoLaunch is set, exit (script is being sourced)
|
|
[[ "$agmNoLaunch" == "true" ]] && exit 0
|
|
|
|
# Only proceed with noninteractive installation if explicitly requested
|
|
if [[ "$noninteractiveInstall" == "true" ]]; then
|
|
# If no game specified for noninteractive install, exit
|
|
[[ ${#game} -lt 1 ]] && exit 0
|
|
|
|
# Install the specified game noninteractively
|
|
if [[ -f "${scriptDir}/.install/${game}.sh" ]]; then
|
|
export LANG="en_US.UTF-8"
|
|
. "${scriptDir}/.install/${game}.sh"
|
|
# Show success message
|
|
agm_msgbox "Installation Complete" "Audio Game Installer" "Game \"${game}\" has been successfully installed."
|
|
else
|
|
agm_msgbox "Audio Game Installer" "" "Error: Game '${game}' not found in .install directory"
|
|
exit 1
|
|
fi
|
|
fi
|