audiogame-manager/audiogame-manager.sh
2025-05-18 20:16:22 -04:00

885 lines
33 KiB
Bash
Executable File

#!/usr/bin/env bash
# Dialog accessibility
export DIALOGOPTS='--no-lines --visit-items'
# Wine configuration section
clear_cache() {
local answer
if [[ ! -d "${cache}" ]]; then
echo "No cache found at ${cache}."
return
fi
while ! [[ "${answer,,}" =~ ^yes$|^no$ ]]; do
echo "This will delete all contents of ${cache}. Are you sure you want to continue?"
echo "Please type yes or no."
echo
read -r answer
done
if [[ "$answer" == "no" ]]; then
return
fi
# All safety checks done. Delete the cache.
rm -rfv "${cache}"
echo "Cache deleted."
}
get_bottle() {
# Handles games that use the same wine bottle
case "${game}" in
# Aprone (Jeremy Kaldobsky) games.
"castaways"*) ;&
"castaways-2"*) ;&
"daytona-and-the-book-of-gold"*) ;&
"dog-who-hates-toast"*) ;&
"lunimals"*) ;&
"paw-prints"*) ;&
"penta-path"*) ;&
"preludeamals"*) ;&
"puzzle-divided"*) ;&
"rettou"*) ;&
"revelation"*) ;&
"swamp"*) ;&
"tarot-assistant"*) ;&
"triple-triad"*)
export WINEPREFIX="${HOME}/.local/wine/aprone" ;;
"bg-"*) export WINEPREFIX="${HOME}/.local/wine/bg";;
# draconis games
"esp-pinball-classic"*) ;&
"esp-pinball-extreme"*) ;&
"esp-pinball-party-pack"*) ;&
"silver-dollar"*) ;&
"monkey-business"*) ;&
"alien-outback"*) ;&
"dyna-man"*) ;&
"change-reaction"*) ;&
"ten-pin-alley"*) export WINEPREFIX="${HOME}/.local/wine/draconis";;
# l-works games group
"duck-hunt"*) ;&
"judgement-day"*) ;&
"lockpick"*) ;&
"pigeon-panic"*) ;&
"smashathon"*) ;&
"super-egg-hunt"*) ;&
"super-liam"*) ;&
"the-great-toy-robbery"*) export WINEPREFIX="${HOME}/.local/wine/l-works";;
# Nyanchan games group
"bokurano-daibouken"*) ;&
"laser-breakout"*) ;&
"marina-break"*) ;&
"mp5"*) ;&
"screaming-strike-2"*) ;&
"world-of-war"*) export WINEPREFIX="${HOME}/.local/wine/nyanchan";;
# Oriol Gomez games group
"bombercats"*) ;&
"copter-mission"*) ;&
"danger-on-the-wheel"*) ;&
"death-on-the-road"*) ;&
"fuck-that-bird"*) ;&
"hammer-of-glory"*) ;&
"insect-therapy"*) ;&
"rhythm-rage"*) ;&
"run-for-your-life"*) ;&
"thief"*) ;&
"villains-from-beyond"*) export WINEPREFIX="${HOME}/.local/wine/oriol-gomez";;
# pbgames group
"dark-destroyer"*) ;&
"PBGames TMP") export WINEPREFIX="$HOME/.local/wine/pbgames" ;;
# tunmi13 games group
"battle-of-the-hunter"*) ;&
"clashes-of-the-sky"*) ;&
"challenge-of-the-horse"*) export WINEPREFIX="${HOME}/.local/wine/tunmi13";;
# tunmi13-64bit games group
"battlefield-2d"*) ;&
"haunted-party"*) ;&
"skateboarder-pro"*) export WINEPREFIX="${HOME}/.local/wine/tunmi13-64bit";;
# Dan Z games group
"lost"*) ;&
"maze-craze"*) ;&
"super-deekout"*)
export norh="true"
export WINEPREFIX="$HOME/.local/wine/dan-z"
;;
*) export WINEPREFIX="${HOME}/.local/wine/${game%|*}";;
esac
# Wine version for bottles
if [[ "$game" =~ entombed ]]; then
install_wine "6.18" "32"
fi
if [[ "$game" =~ rs-games ]]; then
install_wine "7.0" "32"
fi
if [[ "$game" =~ shadow-line ]]; then
install_wine "7.7" "32"
fi
}
get_installer() {
trap "exit 0" SIGINT
# If the file is in cache nothing else needs to be done.
if [[ -f "${cache}/$1" ]]; then
return
fi
# Create message for dialog.
local message="Make sure $1 is available in either your Downloads or Desktop directory and press enter to continue."
if [[ -n "$2" ]]; then
message+="\n\nThe last good known URL for $game is:"
message+="\n$2"
fi
if echo "$2" | xclip -selection clipboard 2> /dev/null ; then
message+="\n\nThe URL has been copied to the clipboard."
fi
dialog --ok-label "Continue" \
--backtitle "Audiogame Manager" \
--msgbox "$message" -1 -1
# Search the Desktop and Downloads directories for the installation file
for i in ~/Downloads ~/Desktop ; do
find $i -type f -name "$1" -exec cp -v {} "${cache}/" \;
done
# If the file is still not available abort.
if [[ ! -f "${cache}/$1" ]]; then
echo "couldn't find $1. Please download the file and try again."
exit 1
fi
}
get_steam() {
# Arguments: $1 id of item for download, $2 url for game
trap "exit 0" SIGINT
echo "manual intervention required."
alert
dialog --backtitle "Audiogame Manager" \
--yes-label "Continue with Steam" \
--no-label "Install manually" \
--extra-button \
--extra-label "Exit" \
--yesno "To install the game manually, place files in \"${WINEPREFIX}/drive_c/Program Files/${game}\"" -1 -1 --stdout
case $? in
0) echo "The next steps will install through steamcmd." ;;
1)
mkdir -p "${WINEPREFIX}/drive_c/Program Files/${game}"
dialog --backtitle "Audiogame Manager" \
--msgbox "Place game files in \"${WINEPREFIX}/drive_c/Program Files/${game}\" and press enter to continue." -1 -1 --stdout
return
;;
*) exit 0 ;;
esac
# Check for steamcmd
if ! command -v steamcmd &> /dev/null ; then
dialog --backtitle "Audiogame Manager" \
--infobox "This installer requires steamcmd. Please install steamcmd and try again." -1 -1
exit 1
fi
# Create message for dialog.
local message="Make sure ${game} is available in your Steam library and press enter to continue. The URL for ${game} is $2"
if echo "$2" | xclip -selection clipboard 2> /dev/null ; then
message+="\n\nThe URL has been copied to the clipboard."
fi
dialog --ok-label "Continue" \
--backtitle "Audiogame Manager" \
--msgbox "$message" -1 -1
# Get Steam user name.
steamUser="$(dialog --ok-label "Continue" \
--backtitle "Audiogame Manager" \
--inputbox "Please enter your Steam user name:" -1 -1 --stdout)"
# Download the game
mkdir -p "${WINEPREFIX}/drive_c/Program Files/${game}"
steamcmd +@sSteamCmdForcePlatformType windows +force_install_dir "${WINEPREFIX}/drive_c/Program Files/$game" +login "$steamUser" +app_update "$1" +quit || { dialog --backtitle "Audiogame Manager" \
--infobox "Something went wrong. Please make sure you have a stable internet connection, and if the problem persists, contact audiogame-manager's developers." -1 -1
exit 1; }
}
install_wine() {
# Requires wine version, e.g. 7.7 and architecture, 32|64
if [[ $# -ne 2 ]]; then
exit 1
fi
# Figure out wineInstallationPath
wineInstallationPath="${XDG_DATA_HOME:-$HOME/.local/share}/audiogame-manager/wine_$2/$1"
export wine="${wineInstallationPath}/bin/wine"
# If the path exists, wine should already be installed.
# Just make sure we didn't wind up with a empty directory for some reason
rmdir "${wineInstallationPath}" 2> /dev/null
if [[ -d "${wineInstallationPath}" ]]; then
return
fi
mkdir -p "${wineInstallationPath}" 2> /dev/null
# This probably does not need to be cached, so download to tmp.
installationFile="$(mktemp)"
local v=$2
v="${v/32/x86}"
v="${v/64/x64}" # Probably wrong, so just a place holder.
# If this goes wrong, bail out
set -e
{ curl -L --output "${installationFile}" "https://www.playonlinux.com/wine/binaries/phoenicis/upstream-linux-x86/PlayOnLinux-wine-${1}-upstream-linux-${v}.tar.gz"
tar xf "${installationFile}" -C "${wineInstallationPath}"; } | dialog --progressbox "Installing $2 bit Wine version $1." -1 -1
set +e
}
unix2dos() {
if [[ $# -eq 0 ]]; then
echo "Usage: unix2dos file(s)."
exit 1
fi
for file in "${@}" ; do
sed -i 's/$/\r/' "${file}"
done
}
winetricks() {
# Report used packages to the winetricks maintainer so he knows they are being used.
if ! [[ -e "${XDG_CACHE_HOME:-$HOME/.cache}/winetricks/track_usage" ]]; then
mkdir -p "${XDG_CACHE_HOME:-$HOME/.cache}/winetricks/"
echo "1" > "${XDG_CACHE_HOME:-$HOME/.cache}/winetricks/track_usage"
fi
# Temporary work around for winetricks git bugs. Requires winetricks be installed from package manager.
/usr/bin/winetricks "$@"
return
# Download or update agm's copy of winetricks
if [[ ! -e "${winetricksPath}/winetricks" ]]; then
checkWinetricksUpdate="true"
download "https://raw.githubusercontent.com/Winetricks/winetricks/master/src/winetricks"
mv "${cache}/winetricks" "${winetricksPath}"
chmod 755 "${winetricksPath}/winetricks"
else
if [[ "$checkWinetricksUpdate" != "true" ]]; then
checkWinetricksUpdate="true"
${winetricksPath}/winetricks --self-update
fi
fi
# Run the requested winetricks parameters
if command -v FEXLoader &> /dev/null ; then
WINE="" FEXLoader -- ${winetricksPath}/winetricks "$@"
else
${winetricksPath}/winetricks "$@"
fi
}
install_rhvoice() {
if [[ -d "$HOME/.local/wine/${bottle}/drive_c/Program Files/Olga Yakovleva/" ]]; then
return
fi
if [[ "$norh" == "true" ]]; then
# Try to prevent the user from breaking speech
# Also useful for games that do not work with RHVoice
if [[ "${defaultVoice}" == "RHVoice" ]]; then
unset defaultVoice
fi
return
fi
declare -A RHVoice=(
[alan]="https://github.com/RHVoice/alan-eng/releases/download/4.0/RHVoice-voice-English-Alan-v4.0.2016.21-setup.exe"
[bdl]="https://github.com/RHVoice/bdl-eng/releases/download/4.1/RHVoice-voice-English-Bdl-v4.1.2016.21-setup.exe"
[clb]="https://github.com/RHVoice/clb-eng/releases/download/4.0/RHVoice-voice-English-Clb-v4.0.2016.21-setup.exe"
[lyubov]="https://rhvoice.eu-central-1.linodeobjects.com/RHVoice-voice-English-Lyubov-v4.0.2008.15-setup.exe"
[slt]="https://github.com/RHVoice/slt-eng/releases/download/4.1/RHVoice-voice-English-Slt-v4.1.2016.21-setup.exe"
)
voiceName="${voiceName:-bdl}"
voiceName="${voiceName,,}"
if [[ "${RHVoice[${voiceName}]}" == "" ]]; then
echo "Invalid RHVoice name specified, defaulting to Bdl."
voiceName="bdl"
fi
local voiceFile="${RHVoice[${voiceName}]##*/}"
download "${RHVoice[${voiceName}]}"
winetricks -q win8
echo "Installing RHVoice ${voiceName^}..."
${wine} "${cache}/${voiceFile}" &
sleep 20
${wine}server -k
}
install_wine_bottle() {
# 32 bit installations work best and are the default here, if you need to override it, do it in the game specific installation steps.
export WINEARCH="${WINEARCH:-win32}"
# Figure out if we are using a specific version of wine
export wine="${wine:-$(command -v wine)}"
# Set the WINE and WINESERVER environmental variables so winetricks will use the right installation.
export WINE="${wine}"
export WINESERVER="${wine}server"
if [[ -z "$bottle" ]]; then
local bottle="${game,,}"
bottle="${bottle//[[:space:]]/-}"
if [[ -d "$HOME/.local/wine/${bottle}" ]]; then
echo "$HOME/.local/wine/${bottle} exists. Please remove it before running this installer."
exit 1
fi
fi
export WINEPREFIX="$HOME/.local/wine/${bottle}"
# Arguments to the function are dependancies to be installed.
# Get location of mono and gecko.
monoPath="$(find /usr/share/wine/ -maxdepth 1 -type d -name mono 2> /dev/null)"
geckoPath="$(find /usr/share/wine/ -maxdepth 1 -type d -name "gecko" 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
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
# This is in a brace list to pipe through dialog.
{ echo -n "Using "
${wine} --version
DISPLAY="" ${wine}boot -u
${wine} msiexec /i z:"$monoPath" /quiet
${wine} msiexec /i z:"$geckoPath" /quiet
if [[ "${*}" =~ (speechsdk|sapi) ]]; then
install_rhvoice
fi
if [[ "${WINEARCH}" == "win64" ]]; then
download "https://github.com/RastislavKish/nvda2speechd/releases/download/v0.1/nvda2speechd"
fi
if [[ "${WINEARCH}" == "win64" ]] && [[ ! -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
winetricks -q isolate_home $@ ${winVer:-winxp} ${winetricksSettings}; } | dialog --progressbox "Installing wine bottle, please wait..." -1 -1
# make it easy for game scripts to know which version of wine to use.
echo "WINE=\"${WINE}\"" > "$HOME/.local/wine/${bottle}/agm.conf"
echo "WINESERVER=\"${WINESERVER}\"" >> "$HOME/.local/wine/${bottle}/agm.conf"
# If default voice is set, change it for the bottle
if [[ ${#defaultVoice} -ge 2 ]] && [[ "${*}" =~ (speechsdk|sapi) ]]; then
echo "Setting default voice for bottle \"${bottle}\" to \"${defaultVoice}\"."
"${0%/*}/speech/set-voice.sh" -b "${bottle}" -r "${defaultRate:-7}" -v "${defaultVoice}"
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 "${0%/*}/.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
echo "All games are already installed."
exit 0
fi
menuList+=("Donate" "Donate")
menuList+=("Become a Patron" "Become a Patron")
# Show game selection dialog
game="$(dialog --backtitle "Audio Game Installer" \
--clear \
--ok-label "Install" \
--no-tags \
--menu "Please select a game to install" 0 0 0 "${menuList[@]}" --stdout)"
[[ $? -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="${0%/*}/.install/${game}.sh"
# Check if install script exists
if [[ -f "$installScript" ]]; then
# Source and execute the install script
source "$installScript"
else
dialog --backtitle "Audio Game Installer" \
--msgbox "Installation script not found for ${game}" -1 -1
exit 1
fi
;;
esac
fi
}
# remove games
game_removal() {
if [[ "$(uname -m)" == "aarch64" ]]; then
export wine="${wine:-/usr/bin/wine}"
else
export wine="${wine:-/usr/bin/wine}"
fi
mapfile -t lines < <(sed -e '/^$/d' -e '/^[[:space:]]*#/d' "${configFile}" 2> /dev/null)
if [[ ${#lines} -eq 0 ]]; then
echo "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="$(dialog --backtitle "Audio Game Removal" \
--clear \
--ok-label "Remove" \
--no-tags \
--menu "Please select a game to delete" 0 0 0 "${menuList[@]}" --stdout)"
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#*|}"
export winePath="${winePath%\\*.exe}"
local wineExec="${game#*|}"
wineExec="${wineExec%|*}"
wineExec="${wineExec##*\\}"
# Confirm removal
get_bottle "${game%|*}"
# Make sure the game can be handled by remove
if [[ "${HOME}/.local/wine/${game%|*}" == "${WINEPREFIX}" ]]; then
read -rp "To remove the wine bottle \"${WINEPREFIX##*/}\" and all of its contents press enter. To cancel press control+c. " continue
# kill any previous existing wineservers for this prefix in case they didn't shut down properly.
${wine}server -k
# remove the game
rm -rf "${WINEPREFIX}"
else
read -rp "This bottle \"${WINEPREFIX##*/}\" contains multiple entries, so only the game will be removed. To continue press enter. To cancel press control+c. " continue
rm -rf "$(winepath "${winePath}")"
fi
# remove the launcher
gawk -i inplace -vLine="${game//\\/\\\\}" '!index($0,Line)' "$configFile"
echo "The selected item has been deleted."
fi
exit 0
}
# kill games that are stuck
kill_game() {
if [[ "$(uname -m)" == "aarch64" ]]; then
export wine="${wine:-/usr/bin/wine}"
else
export wine="${wine:-/usr/bin/wine}"
fi
mapfile -t lines < <(sed '/^$/d' "${configFile}" 2> /dev/null)
if [[ ${#lines} -eq 0 ]]; then
echo "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="$(dialog --backtitle "Audio Game Killer" \
--clear \
--ok-label "Kill" \
--no-tags \
--menu "Please select a game to force stop" 0 0 0 "${menuList[@]}" --stdout)"
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%|*}"
${wine}server -k
echo "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[0]}" == "dragon-pong" ]]; then
"${0%/*}/speech/speak_window_title.sh" DragonPong.exe &
pushd "$(winepath "$winePath")"
wine "$wineExec"
popd
exit 0
fi
if [[ "${game[0]}" == "executioner's-rage" ]]; then
find "${WINEPREFIX}/drive_c/Program Files" -type f -name 'nvdaControllerClient64.dll' -exec cp -v "${cache}/nvda2speechd64.dll" "{}" \;
fi
if [[ "${game[0]}" == "laser-breakout" ]]; then
"${0%/*}/speech/speak_window_title.sh" play.exe &
fi
if [[ "${game[0]}" == "bokurano-daibouken-2" ]]; then
"${0%/*}/speech/clipboard_translator.sh" play.exe bokurano-daibouken2 &
fi
if [[ "${game[0]}" == "bokurano-daibouken" ]]; then
"${0%/*}/speech/clipboard_translator.sh" play.exe bokurano-daibouken &
fi
if [[ "${game[0]}" =~ "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
if [[ -d "${dictPath}/dict" ]]; then
if [[ ! -e "${dictPath}/data/nvdaControllerClient.dll" ]]; then
cp "${cache}/nvda2speechd32.dll" "${dictPath}/data/nvdaControllerClient.dll"
fi
fi
if [[ ! -d "${dictPath}/dict" ]] && [[ ! -r "${cache}/bk3-dict.dat" ]]; then
find "${WINEPREFIX}/drive_c/nyanchangame/bk3" -type f -name 'nvdaControllerClient.dll' -exec rm -v "{}" \;
"${0%/*}/speech/clipboard_translator.sh" play.exe bokurano-daibouken3 &
fi
fi
if [[ "${game[0]}" == "bop-it-emulator" ]]; then
"${0%/*}/speech/speak_window_title.sh" bop.exe &
fi
if [[ "${game[0]}" == "road-to-rage" ]]; then
"${0%/*}/speech/speak_window_title.sh" trtr.exe &
fi
if [[ "${game[0]}" == "sequence-storm" ]]; then
"${0%/*}/speech/clipboard_reader.sh" SequenceStorm &
fi
#if [[ "${game[0]}" == "shadow-line" ]]; then
#find "${WINEPREFIX}/drive_c/" -type f -name 'nvdaControllerClient.dll' -exec rm -v "{}" \;
#"${0%/*}/speech/clipboard_translator.sh" play_sr.exe shadow-line &
#fi
if [[ "${game[0]}" == "sketchbook" ]]; then
find "${WINEPREFIX}" -type f -name 'nvdaControllerClient32.dll' -exec cp -v "${cache}/nvdaControllerClient32.dll" "{}" \;
fi
if [[ "${game[0]}" == "audiodisc" ]]; then
wine "$winePath\\$wineExec"
exit 0
fi
if [[ "${game[0]}" == "audioquake" ]]; then
wine "$winePath\\$wineExec"
exit 0
fi
if [[ "${game[0]}" == "screaming-strike-2" ]]; then
pushd "$(winepath "$winePath")"
${wine} "$wineExec"
popd
exit 0
fi
if [[ "${game[0]}" == "warsim" ]]; then
pushd "$(winepath "${game[1]%\\*}")"
wine "${game[1]##*\\}"
popd
exit 0
fi
if [[ "${game[0]}" == "interceptor" ]]; then
pushd "$(winepath "$winePath")"
wine "$wineExec"
popd
exit 0
fi
if [[ -d "${WINEPREFIX}/drive_c/windows/syswow64" ]]; then
# switch to wine64 for 64 bit prefix.
[[ "${wine}" == "/usr/bin/wine" ]] && export wine="/usr/bin/wine64"
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
for i in "${lines[@]}" ; do
if [[ "${game}" =~ ^${i} ]]; then
# This is weird. Why do I have to set game to i before making the array?
game="$i"
IFS='|' read -ra game <<< "$i"
break
fi
done
}
# launch games that are installed
game_launcher() {
# For use by update scripts that want to source functions in this file.
[[ "$agmNoLaunch" == "true" ]] && return
pgrep -u "$USER" nvda2speechd &> /dev/null || {
if [[ -x ${XDG_DATA_HOME:-$HOME/.local/share}/audiogame-manager/nvda2speechd ]]; then
if command -v FEXLoader &> /dev/null ; then
FEXLoader -- ${XDG_DATA_HOME:-$HOME/.local/share}/audiogame-manager/nvda2speechd &> /dev/null &
else
${XDG_DATA_HOME:-$HOME/.local/share}/audiogame-manager/nvda2speechd &> /dev/null &
fi
fi; }
mapfile -t lines < <(sed -e '/^$/d' -e '/^ *#/d' "${configFile}" 2> /dev/null)
if [[ ${#lines} -eq 0 ]]; then
echo "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="$(dialog --backtitle "Audio Game Launcher" \
--clear \
--extra-button \
--extra-label "Documentation" \
--ok-label "Launch" \
--no-tags \
--menu "Please select a game to play" 0 0 0 "${menuList[@]}" --stdout)"
local menuCode=$?
if [[ $menuCode -eq 1 ]] || [[ $menuCode -eq 255 ]]; then
exit 0
elif [[ $menuCode -eq 3 ]]; then
source .includes/help.sh # Make available in this function
documentation "$game" "$(echo "$game" | cut -d '|' -f2)"
fi
create_game_array
else
create_game_array
if [[ -z "$game" ]]; then
echo "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]}"
# make sure wine is actually set to something
if [[ "$(uname -m)" == "aarch64" ]]; then
export wine="${wine:-/usr/bin/wine}"
else
export wine="${wine:-/usr/bin/wine}"
fi
echo -n "launching "
${wine} --version
# kill any previous existing wineservers for this prefix in case they didn't shut down properly.
${wine}server -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
${wine:-/usr/bin/wine} start /d "${game[1]%\\*}" "${game[1]##*\\}" /realtime
fi
exit 0
}
# main script
#functions
add_launcher() {
local launchSettings="${game,,}"
launchSettings="${launchSettings//[[:space:]]/-}|${1}|${game}"
shift
while [[ $# -gt 0 ]]; do
launchSettings+="|$1"
shift
done
if ! grep -F -q -x "${launchSettings}" "${configFile}" 2> /dev/null ; then
echo "${launchSettings}" >> "${configFile}"
sort -o "${configFile}" "${configFile}"
# Remove .lnk files because they don't work.
find ~/Desktop -type f -iname '*.lnk' -exec bash -c '
for f ; do
mimeType="$(file -b "$f")"
mimeType="${mimeType%%,*}"
if [[ "$mimeType" == "MS Windows shortcut" ]]; then
rm -v "$f"
fi
done' _ {} +
if [[ "${noCache}" == "true" ]]; then
rm -f "${cache}/${1##*\\}"
fi
fi
}
trap "exit 0" SIGINT
# 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/"; } | dialog \
--backtitle "Audiogame Manager" --progressbox "Updating cache, please wait..." -1 -1
fi
checkWinetricksUpdate="false"
# Turn off debug messages
export WINEDEBUG="${winedebug:--all}"
# Compatibility with box86
export BOX86_NOBANNER=1
# 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/QmWu7YdSbKMk1Qm5DKvEA5hk1YuAK8wVkwhDf2CsmPkmF1?filename=nvdaControllerClient32.dll"
# Source helper functions
source .includes/functions.sh
source .includes/help.sh
source .includes/update.sh
# Check minimum requirements
check_requirements || exit 1
# 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."
[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) ./.includes/checkup.sh;;
C) clear_cache;;
D) desktop_launcher;;
d)
unset WINEDEBUG
game_installer
;;
h) help;;
i) game_installer;;
I)
game="${OPTARG}"
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 .install -type f -iname "*.sh" | wc -l)
dialog --backtitle "Linux Game Manager" \
--infobox "There are currently ${gameCount} games available." -1 -1
exit 0
;;
v) voiceName="${OPTARG}";;
V) defaultVoice="${OPTARG}";;
esac
done
[[ ${#game} -lt 1 ]] && exit 0
[[ "$agmNoLaunch" != "true" ]] && winetricks sandbox
[[ "$agmNoLaunch" != "true" ]] && exit 0