518 lines
19 KiB
Bash
Executable File
518 lines
19 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
|
|
# Dialog accessibility
|
|
export DIALOGOPTS='--no-lines --visit-items'
|
|
|
|
# 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() {
|
|
source .includes/bottle.sh
|
|
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() {
|
|
source .includes/bottle.sh
|
|
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
|
|
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
|
|
}
|
|
|
|
# launch games that are installed
|
|
game_launcher() {
|
|
# For use by update scripts that want to source functions in this file.
|
|
[[ "$agmNoLaunch" == "true" ]] && return
|
|
source .includes/bottle.sh
|
|
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 "$game"
|
|
else
|
|
create_game_array "$game"
|
|
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
|
|
|
|
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/bottle.sh # Also sourced in functions that need it
|
|
source .includes/desktop.sh
|
|
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" ]] && exit 0
|