1280 lines
49 KiB
Bash
Executable File
1280 lines
49 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
|
|
license() {
|
|
cat << EOF
|
|
■The contents of this file are subject to the Common Public Attribution
|
|
License Version 1.0 (the ■License■); you may not use this file except in
|
|
compliance with the License. You may obtain a copy of the License at
|
|
https://opensource.org/licenses/CPAL-1.0. The License is based on the Mozilla Public License Version
|
|
1.1 but Sections 14 and 15 have been added to cover use of software over a
|
|
computer network and provide for limited attribution for the Original
|
|
Developer. In addition, Exhibit A has been modified to be consistent with
|
|
Exhibit B.
|
|
|
|
Software distributed under the License is distributed on an ■AS IS■ basis,
|
|
WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
for the specific language governing rights and limitations under the
|
|
License.
|
|
|
|
The Original Code is audiogame manager.
|
|
|
|
The Original Developer is not the Initial Developer and is . If
|
|
left blank, the Original Developer is the Initial Developer.
|
|
|
|
The Initial Developer of the Original Code is Billy "Storm Dragon" Wolfe. All portions of
|
|
the code written by Billy Wolfe are Copyright (c) 2020, 2024. All Rights
|
|
Reserved.
|
|
|
|
Contributor Michael Taboada.
|
|
|
|
Attribution Copyright Notice: Audiogame manager copyright 2020 Storm Dragon. All rights reserved.
|
|
|
|
Attribution Phrase (not exceeding 10 words): A Stormux project
|
|
|
|
Attribution URL: https://stormgames.wolfe.casa
|
|
|
|
Graphic Image as provided in the Covered Code, if any.
|
|
|
|
Display of Attribution Information is required in Larger
|
|
Works which are defined in the CPAL as a work which combines Covered Code
|
|
or portions thereof with code not governed by the terms of the CPAL.
|
|
EOF
|
|
}
|
|
|
|
# Dialog accessibility
|
|
export DIALOGOPTS='--no-lines --visit-items'
|
|
|
|
|
|
# Alerts, for when user needs to read something.
|
|
alert() {
|
|
play -qnV0 synth 3 pluck D3 pluck A3 pluck D4 pluck F4 pluck A4 delay 0 .1 .2 .3 .4 remix - chorus 0.9 0.9 38 0.75 0.3 0.5 -t
|
|
echo
|
|
read -rp "Press enter to continue." continue
|
|
}
|
|
|
|
# Check for latest news
|
|
check_news() {
|
|
# For use by update scripts that want to source functions in this file.
|
|
[[ "$agmNoLaunch" == "true" ]] && return
|
|
trap return INT
|
|
# url for news file
|
|
local newsFile="https://stormgames.wolfe.casa/media/agm.ogg"
|
|
local newsPath="${configFile%/*.conf}/.news"
|
|
local newsTag="$(curl --connect-timeout 5 -sI "$newsFile" | grep -i '^etag: "' | cut -d '"' -f2)"
|
|
if [[ -z "${newsTag}" ]]; then
|
|
return
|
|
fi
|
|
local newsOldTag="$(cat "$newsPath" 2> /dev/null)"
|
|
if [[ "$newsTag" != "$newsOldTag" ]]; then
|
|
dialog --yes-label 'Play' \
|
|
--no-label 'Later' \
|
|
--backtitle 'Audiogame Manager News' \
|
|
--yesno 'Audiogame manager news is available. Please use left and right arrows to navigate and enter to confirm.' -1 -1 || return
|
|
sox -qV0 "$newsFile" -d &> /dev/null
|
|
echo -n "$newsTag" > "$newsPath"
|
|
fi
|
|
}
|
|
|
|
# Automatic update function
|
|
# Automatic update function
|
|
update() {
|
|
if ! [[ -d ".git" ]]; then
|
|
return
|
|
fi
|
|
local url="$(git ls-remote --get-url)"
|
|
if [[ "$url" =~ ^ssh://|git@|gitea@ ]] || [[ -z "$url" ]]; then
|
|
return
|
|
fi
|
|
git remote update &> /dev/null
|
|
local upstream='@{u}'
|
|
local home="$(git rev-parse @)"
|
|
local remote="$(git rev-parse "$upstream")"
|
|
if [[ "$home" == "$remote" ]]; then
|
|
return
|
|
fi
|
|
dialog --backtitle "Audiogame Manager" \
|
|
--yesno "Updates are available. Would you like to update now?" -1 -1 --stdout || return
|
|
{ git pull
|
|
git log '@{1}..' --pretty=format:'%an: %s'; }
|
|
exit $?
|
|
}
|
|
|
|
# Function to open urls across OS.
|
|
open_url() {
|
|
if [[ "$(uname)" == "Darwin" ]]; then
|
|
open "${*}" 2> /dev/null
|
|
else
|
|
xdg-open "${*}" 2> /dev/null
|
|
fi
|
|
}
|
|
|
|
# Create desktop launcher file
|
|
desktop_launcher() {
|
|
local desktopFile="${HOME}/audiogame-manager.desktop"
|
|
if [[ -e "${desktopFile}" ]]; then
|
|
echo "the file ${desktopFile} exists. Cannot create the launcher."
|
|
exit 1
|
|
fi
|
|
local dotDesktop
|
|
local terminal
|
|
# Try to find an accessible terminal
|
|
for i in mate-terminal lxterminal terminator gnome-terminal ; do
|
|
if command -v $i &> /dev/null ; then
|
|
terminal="$i"
|
|
break
|
|
fi
|
|
done
|
|
dotDesktop=('[Desktop Entry]'
|
|
'Name=Audiogame manager'
|
|
'GenericName=Audiogame Manager'
|
|
'Comment=Play audio games'
|
|
"Exec=${terminal} -t \"Audiogame Manager\" -e \"/usr/bin/bash -c 'nohup $(readlink -e "$0") 2> /dev/null'\""
|
|
'Terminal=false'
|
|
'Type=Application'
|
|
'StartupNotify=false'
|
|
'Keywords=game;'
|
|
'Categories=Game;'
|
|
'Version=1.0')
|
|
for i in "${dotDesktop[@]}" ; do
|
|
echo "$i" >> "${desktopFile}"
|
|
done
|
|
desktop-file-install --dir "${HOME}/.local/share/applications" -m 755 "${desktopFile}"
|
|
xdg-desktop-icon install ~/.local/share/applications/audiogame-manager.desktop
|
|
rm "${desktopFile}"
|
|
exit 0
|
|
}
|
|
|
|
|
|
# Wine configuration section
|
|
|
|
checklist() {
|
|
declare -a errorList
|
|
declare -a packageList
|
|
if [[ $# -eq 0 ]]; then
|
|
echo "Checking your system..."
|
|
echo
|
|
fi
|
|
if command -v wine &> /dev/null ; then
|
|
[[ $# -eq 0 ]] && echo "Wine is installed."
|
|
else
|
|
errorList+=("Critical: Wine is not installed. You will not be able to play any games.")
|
|
fi
|
|
packageList+=("wine")
|
|
if command -v curl &> /dev/null ; then
|
|
[[ $# -eq 0 ]] && echo "Curl is installed."
|
|
else
|
|
errorList+=("Critical: Curl is not installed. Critical functionality will not work.")
|
|
fi
|
|
packageList+=("curl")
|
|
if command -v dialog &> /dev/null ; then
|
|
[[ $# -eq 0 ]] && echo "Dialog is installed."
|
|
else
|
|
errorList+=("Critical: Dialog is not installed. You will not be able to install, launch, or remove any games.")
|
|
fi
|
|
packageList+=("dialog")
|
|
for i in 7z cabextract unzip xz ; do
|
|
if command -v $i &> /dev/null ; then
|
|
[[ $# -eq 0 ]] && echo "${i^} is installed."
|
|
else
|
|
errorList+=("Critical: ${i^} is not installed. You will not be able to install some games or their components.")
|
|
fi
|
|
packageList+=("$i")
|
|
done
|
|
if command -v gawk &> /dev/null ; then
|
|
[[ $# -eq 0 ]] && echo "Gawk is installed."
|
|
else
|
|
errorList+=("Warning: gawk is not installed. Game removal with -r will not work.")
|
|
fi
|
|
packageList+=("gawk")
|
|
if command -v ocrdesktop &> /dev/null ; then
|
|
[[ $# -eq 0 ]] && echo "Ocrdesktop is installed."
|
|
else
|
|
errorList+=("Warning: ocrdesktop is not installed. It can help if the installer gets stuck to figure out what is happening.")
|
|
fi
|
|
packageList+=("ocrdesktop")
|
|
if command -v qjoypad &> /dev/null ; then
|
|
[[ $# -eq 0 ]] && echo "Qjoypad is installed."
|
|
else
|
|
errorList+=("Warning: qjoypad is not installed. Qjoypad allows you to play keyboard only games with a gamepad.")
|
|
fi
|
|
packageList+=("qjoypad")
|
|
if command -v sox &> /dev/null ; then
|
|
[[ $# -eq 0 ]] && echo "Sox is installed."
|
|
else
|
|
errorList+=("Warning: Sox is not installed. Audio will not work.")
|
|
fi
|
|
packageList+=("sox")
|
|
if command -v trans &> /dev/null ; then
|
|
[[ $# -eq 0 ]] && echo "Translate-shell is installed."
|
|
else
|
|
errorList+=("Warning: translate-shell is not installed. Games that require translation will not be translated.")
|
|
fi
|
|
packageList+=("translate-shell")
|
|
if command -v sqlite3 &> /dev/null ; then
|
|
[[ $# -eq 0 ]] && echo "Sqlite3 is installed."
|
|
else
|
|
errorList+=("Warning: sqlite is not installed. Required for games that need to be translated.")
|
|
fi
|
|
if command -v perl &> /dev/null ; then
|
|
[[ $# -eq 0 ]] && echo "Perl is installed."
|
|
else
|
|
errorList+=("Warning: perl is not installed. Required for games that need to be translated.")
|
|
fi
|
|
packageList+=("perl")
|
|
packageList+=("sqlite")
|
|
if command -v w3m &> /dev/null ; then
|
|
[[ $# -eq 0 ]] && echo "W3m is installed."
|
|
else
|
|
errorList+=("Warning: w3m is not installed. W3m is used to view game documentation.")
|
|
fi
|
|
packageList+=("w3m")
|
|
if command -v xclip &> /dev/null ; then
|
|
[[ $# -eq 0 ]] && echo "Xclip is installed."
|
|
else
|
|
errorList+=("Warning: Xclip is not installed. Some games may not speak or register properly.")
|
|
fi
|
|
packageList+=("xclip")
|
|
if command -v xdotool &> /dev/null ; then
|
|
[[ $# -eq 0 ]] && echo "Xdotool is installed."
|
|
else
|
|
errorList+=("Warning: Xdotool is not installed. Some installers may not work or may need manual intervention.")
|
|
fi
|
|
packageList+=("xdotool")
|
|
# Show the results
|
|
if [[ $# -ne 0 ]]; then
|
|
for i in "${packageList[@]}" ; do
|
|
echo "$i"
|
|
done | sort
|
|
exit 0
|
|
fi
|
|
if [[ ${#errorList[@]} -eq 0 ]]; then
|
|
echo "No problems found, you are good to go."
|
|
exit 0
|
|
fi
|
|
echo "Errors detected, here is a list along with the severity."
|
|
echo "Note that errors marked critical mean that you will not be able to install and play games until they are resolved."
|
|
for i in "${errorList[@]}" ; do
|
|
echo "$i"
|
|
done
|
|
exit 0
|
|
}
|
|
|
|
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."
|
|
}
|
|
|
|
download() {
|
|
local source=($@)
|
|
for i in "${source[@]}" ; do
|
|
local dest="${i##*/}"
|
|
dest="${dest//%20/ }"
|
|
dest="${dest#*\?filename=}"
|
|
dest="${dest%\?*}"
|
|
# Remove the destination file if it is empty.
|
|
[[ -s "${cache}/${dest}" ]] || rm -f "${cache}/${dest}" 2> /dev/null
|
|
if [[ "${redownload}" == "true" ]] && [[ -e "${cache}/${dest}" ]]; then
|
|
rm -v "${cache}/${dest}"
|
|
fi
|
|
# Skip if the item is in cache.
|
|
[[ -e "${cache}/${dest}" ]] && continue
|
|
{ if ! curl -L4 -C - --retry 10 --output "${cache}/${dest}" "${i}" ; then
|
|
echo "Could not download \"$i\"..."
|
|
exit 1
|
|
fi; } | dialog --backtitle "Audio Game Manager" \
|
|
--progressbox "Downloading \"$dest\" from \"$i\"" -1 -1
|
|
local downloadError=1
|
|
case "${dest##*.}" in
|
|
"pk3"|"zip")
|
|
unzip -tq "${cache}/${dest}" | dialog --backtitle "Audio Game Manager" \
|
|
--progressbox "Validating ${dest##*.} file" -1 -1 --stdout
|
|
downloadError=$?
|
|
;;
|
|
"7z")
|
|
7z t "${cache}/${dest}" | dialog --backtitle "Audio Game Manager" \
|
|
--progressbox "Validating 7z file" -1 -1 --stdout
|
|
downloadError=$?
|
|
;;
|
|
"exe")
|
|
# Check if it's a valid Windows executable by looking at the MZ header
|
|
if ! hexdump -n 2 -v -e '/1 "%02X"' "${cache}/${dest}" | grep -q "4D5A"; then
|
|
downloadError=0
|
|
fi
|
|
;;
|
|
"wad")
|
|
if [[ "$(file -b --mime-type "${cache}/${dest}")" != "application/octet-stream" ]]; then
|
|
downloadError=0
|
|
fi
|
|
;;
|
|
*)
|
|
# Add HTML check for other file types
|
|
if file -b "${cache}/${dest}" | grep -q "HTML document" ; then
|
|
echo "File not found: \"$i\" (HTML document probably 404)"
|
|
downloadError=0
|
|
fi
|
|
;;
|
|
esac
|
|
if [[ $downloadError -eq 0 ]]; then
|
|
rm -fv "${cache}/${dest}"
|
|
dialog --backtitle "Audio Game Manager" \
|
|
--infobox "Error downloading \"${dest}\". Installation cannot continue." -1 -1 --stdout
|
|
alert
|
|
exit 1
|
|
fi
|
|
done
|
|
}
|
|
|
|
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"*) ;&
|
|
"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; }
|
|
}
|
|
|
|
help() {
|
|
echo "${0##*/}"
|
|
echo "Released under the terms of the Common Public Attribution License Version 1.0"
|
|
echo -e "This is a Stormux project: https://stormux.org\n"
|
|
echo -e "Usage:\n"
|
|
echo "With no arguments, open the game launcher."
|
|
for i in "${!command[@]}" ; do
|
|
echo "-${i/:/ <parameter>}: ${command[${i}]}"
|
|
done | sort
|
|
echo
|
|
echo "Some settings that are often used can be stored in a settings.conf file."
|
|
echo "If wanted, place it at the following location:"
|
|
echo "${configFile%/*}/settings.conf"
|
|
echo "The syntax is variable=\"value\""
|
|
echo
|
|
echo "ipfsGateway=\"https://ipfs.stormux.org\" # Gateway to be used for ipfs downloads."
|
|
echo "noCache=\"true\" # Do not keep downloaded items in the cache."
|
|
echo "noqjoypad=\"true\" # Do not launch qjoypad."
|
|
echo "norh=\"true\" # Do not install RHVoice."
|
|
echo "redownload=\"true\" # Redownload sources, do not use the version stored in cache."
|
|
echo "voiceName=\"voicename\" # Select the voice to be installed (default Bdl)."
|
|
echo "defaultVoice=\"voicename\" # Select the default voice to use for the bottle, e.g. MSMike or RHVoice."
|
|
echo "defaultRate=\"Default voice rate for the bottle, default 7, may not work in all games. Values 1-9 or A."
|
|
echo "winedebug=\"flag(s)\" # Set wine debug flags, useful for development."
|
|
exit 0
|
|
}
|
|
|
|
documentation() {
|
|
if [[ "$2" == "Become a Patron" ]]; then
|
|
return
|
|
fi
|
|
if [[ "$2" == "Donate" ]]; then
|
|
return
|
|
fi
|
|
if ! command -v w3m &> /dev/null ; then
|
|
echo "This feature of audiogame-manager requires w3m. Please install it before continuing."
|
|
exit 1
|
|
fi
|
|
get_bottle "$1"
|
|
echo "Loading documentation, please wait..."
|
|
# Try to find documentation based on common naming conventions.
|
|
local gamePath="$(winepath -u "$2" 2> /dev/null)"
|
|
gamePath="${gamePath%/*}"
|
|
local gameDoc="$(find "$gamePath" -type f -iname 'user_manual.htm*' -or -iname 'user manual.htm*' -or -iname '*user guide.htm*' | head -1)"
|
|
# Game name specific docs, add the name to the for loop.
|
|
if [[ -z "$gameDoc" ]]; then
|
|
for i in "troopanum.txt" "superdeekout.txt" scw.html ; do
|
|
gameDoc="$(find "$gamePath" -type f -iname "$i" -or -iname 'manual.htm' | head -1)"
|
|
done
|
|
fi
|
|
if [[ -z "$gameDoc" ]]; then
|
|
gameDoc="$(find "$gamePath" -type f -path '*/Manual/index.html' | head -1)"
|
|
fi
|
|
if [[ -z "$gameDoc" ]]; then
|
|
gameDoc="$(find "$gamePath" -type f -iname '[A-Z]*Help.htm' -or -iname '[A-Z]*Help.html' | head -1)"
|
|
fi
|
|
if [[ -z "$gameDoc" ]]; then
|
|
gameDoc="$(find "$gamePath" -type f -iname 'manual.html' -or -iname 'manual.htm' | head -1)"
|
|
fi
|
|
if [[ -z "$gameDoc" ]]; then
|
|
gameDoc="$(find "$gamePath" -type f -iname 'en.html' -or -iname 'en.htm' | head -1)"
|
|
fi
|
|
if [[ -z "$gameDoc" ]]; then
|
|
gameDoc="$(find "$gamePath" -type f -iname 'readme.html' -or -iname 'readme.htm' | head -1)"
|
|
fi
|
|
if [[ -z "$gameDoc" ]]; then
|
|
gameDoc="$(find "$gamePath" -type f -iname 'manual.txt' | head -1)"
|
|
fi
|
|
if [[ -z "$gameDoc" ]]; then
|
|
gameDoc="$(find "$gamePath" -type f -iname 'readme.txt' -or -iname 'help.txt' | head -1)"
|
|
fi
|
|
if [[ -z "$gameDoc" ]]; then
|
|
gameDoc="$(find "$gamePath" -type f -iname '*.url' -exec grep -i 'url=' {} \; | grep -iv 'score' | head -1)"
|
|
gameDoc="${gameDoc#*=}"
|
|
gameDoc="${gameDoc//[[:cntrl:]]/}"
|
|
fi
|
|
# Display documentation if available.
|
|
if [[ -n "$gameDoc" ]]; then
|
|
w3m "$gameDoc"
|
|
else
|
|
echo "No documentation found."
|
|
fi
|
|
exit 0
|
|
}
|
|
|
|
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
|
|
# 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
|
|
${winetricksPath}/winetricks "$@"
|
|
}
|
|
|
|
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://rhvoice.eu-central-1.linodeobjects.com/RHVoice-voice-English-Alan-v4.0.2008.15-setup.exe"
|
|
[bdl]="https://rhvoice.eu-central-1.linodeobjects.com/RHVoice-voice-English-Bdl-v4.1.2008.15-setup.exe"
|
|
[clb]="https://rhvoice.eu-central-1.linodeobjects.com/RHVoice-voice-English-Clb-v4.0.2008.15-setup.exe"
|
|
[slt]="https://rhvoice.eu-central-1.linodeobjects.com/RHVoice-voice-English-Slt-v4.0.2008.15-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 "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() {
|
|
wine="${wine:-wine}"
|
|
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() {
|
|
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]}" == "haunted-party" ]]; then
|
|
pgrep -u "$USER" nvda2speechd &> /dev/null || ${XDG_DATA_HOME:-$HOME/.local/share}/audiogame-manager/nvda2speechd &
|
|
fi
|
|
if [[ "${game[0]}" == "laser-breakout" ]]; then
|
|
pgrep -u "$USER" nvda2speechd &> /dev/null || ${XDG_DATA_HOME:-$HOME/.local/share}/audiogame-manager/nvda2speechd &
|
|
"${0%/*}/speech/speak_window_title.sh" play.exe &
|
|
fi
|
|
if [[ "${game[0]}" == "light-battles" ]]; then
|
|
pgrep -u "$USER" nvda2speechd &> /dev/null || ${XDG_DATA_HOME:-$HOME/.local/share}/audiogame-manager/nvda2speechd &
|
|
fi
|
|
if [[ "${game[0]}" == "mist-world" ]]; then
|
|
"${0%/*}/speech/speak_window_title.sh" mw.exe &
|
|
pgrep -u "$USER" nvda2speechd &> /dev/null || ${XDG_DATA_HOME:-$HOME/.local/share}/audiogame-manager/nvda2speechd &
|
|
fi
|
|
if [[ "${game[0]}" == "oh-shit" ]]; then
|
|
pgrep -u "$USER" nvda2speechd &> /dev/null || ${XDG_DATA_HOME:-$HOME/.local/share}/audiogame-manager/nvda2speechd &
|
|
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
|
|
pgrep -u "$USER" nvda2speechd &> /dev/null || ${XDG_DATA_HOME:-$HOME/.local/share}/audiogame-manager/nvda2speechd &
|
|
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]}" == "breu2-shadow-hunt" ]]; then
|
|
pgrep -u "$USER" nvda2speechd &> /dev/null || ${XDG_DATA_HOME:-$HOME/.local/share}/audiogame-manager/nvda2speechd &
|
|
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 [[ "${game[0]}" == "vip-mud" ]]; then
|
|
pgrep -u "$USER" nvda2speechd &> /dev/null || ${XDG_DATA_HOME:-$HOME/.local/share}/audiogame-manager/nvda2speechd &
|
|
fi
|
|
if [[ -d "${WINEPREFIX}/drive_c/windows/syswow64" ]]; then
|
|
pgrep -u "$USER" nvda2speechd &> /dev/null || ${XDG_DATA_HOME:-$HOME/.local/share}/audiogame-manager/nvda2speechd &
|
|
# switch to wine64 for 64 bit prefix.
|
|
[[ "${wine}" == "wine" ]] && export wine="wine64"
|
|
fi
|
|
if [[ "${game[0]}" == "the-great-toy-robbery" ]] ; then
|
|
pgrep -u "$USER" nvda2speechd &> /dev/null || ${XDG_DATA_HOME:-$HOME/.local/share}/audiogame-manager/nvda2speechd &
|
|
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
|
|
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")
|
|
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 ]]; then
|
|
exit 0
|
|
elif [[ $menuCode -eq 3 ]]; then
|
|
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
|
|
export wine="${wine:-wine}"
|
|
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:-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
|
|
}
|
|
|
|
# Check for updates
|
|
update
|
|
# 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
|
|
cache="${XDG_CACHE_HOME:-$HOME/.cache}/audiogame-manager"
|
|
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"
|
|
|
|
|
|
# Make sure the minimum of curl, sox, wine, and winetricks are installed or fex-emu on aarch64
|
|
if [[ "$(uname -m)" == "aarch64" ]]; then
|
|
minimumDependencies=("FEXLoader")
|
|
wine="FEXLoader -- /usr/bin/wine"
|
|
else
|
|
minimumDependencies=("curl" "sox" "wine")
|
|
fi
|
|
for i in "${minimumDependencies[@]}" ; do
|
|
if ! command -v $i &> /dev/null ; then
|
|
echo "Please install $i before continuing."
|
|
exit 1
|
|
fi
|
|
done
|
|
# 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) checklist;;
|
|
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)
|
|
dialog --backtitle "Audiogame Manager" \
|
|
--infobox "There are currently $(ls -1 "${0%/*}/.install" | wc -l) games available." -1 -1
|
|
exit 0
|
|
;;
|
|
v) voiceName="${OPTARG}";;
|
|
V) defaultVoice="${OPTARG}";;
|
|
esac
|
|
done
|
|
|
|
# Install game based on the selection above.
|
|
# make sure wine is actually set to something
|
|
export wine="${wine:-wine}"
|
|
[[ "$agmNoLaunch" != "true" ]] && winetricks sandbox
|
|
|
|
[[ "$agmNoLaunch" != "true" ]] && exit 0
|