#!/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 linux-game-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. All Rights Reserved. Contributor Michael Taboada. Attribution Copyright Notice: linux-game-manager copyright 2022 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' # Check for updates check_update() { local url="$(git ls-remote --get-url)" if [[ "$url" =~ ^ssh://|git@ ]] || [[ -z "$url" ]]; then return fi git remote update > /dev/null 2>&1 local upstream='@{u}' local home="$(git rev-parse @)" local remote="$(git rev-parse "$upstream")" if [[ "$home" == "$remote" ]]; then return fi dialog --backtitle "Linux Game manager" \ --yesno "Updates are available. Would you like to update now?" -1 -1 --stdout || return # Store the current commit before pulling local before_pull=$(git rev-parse HEAD) git pull # Show changes between the stored commit and current HEAD git log "$before_pull..HEAD" --pretty=format:'%an: %s' exit $? } # Check architecture compatibility check_architecture() { local architecture="$(uname -m)" for i in "$@" ; do if [[ "${architecture}" == "$i" ]]; then return fi done dialog --backtitle "Linux Game Manager" \ --infobox "This game is not compatible with $architecture architecture." -1 -1 exit 1 } # Check dependencies required for games check_dependencies() { local dependencies for i in "${@}"; do if [[ "$i" =~ ^python- ]]; then if ! python3 -c "import ${i#*:}" &> /dev/null ; then dependencies+=("${i%:*}") fi elif ! command -v "$i" > /dev/null 2>&1 ; then dependencies+=("$i") fi done if [[ "${#dependencies[@]}" -eq 0 ]]; then return fi echo "missing dependencies. Please install the following:" echo for i in "${dependencies[@]}" ; do echo "$i" done exit 1 } # Function to open a terminal emulator terminal_emulator() { terminals=( "lxterminal" "mate-terminal" "gnome-terminal" ) for i in "${terminals[@]}" ; do if command $i --working-directory="${game%/*}" -e $* ; then return fi done echo "No suitable terminal emulators found, please install one of:" for i in "${terminals[@]}" ; do echo "$i" done } # Function to open urls open_url() { xdg-open "${*}" 2> /dev/null } # Create desktop launcher file desktop_launcher() { local desktopFile="${HOME}/linux-game-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 2>&1 ; then terminal="$i" break fi done dotDesktop=('[Desktop Entry]' 'Name=Linux game manager' 'GenericName=Linux game Manager' 'Comment=Install and launch games that are accessible to the blind' "Exec=${terminal} -t \"Linux Game 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/linux-game-manager.desktop rm "${desktopFile}" exit 0 } # 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 } 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 "Linux Game Manager" \ --progressbox "Downloading \"$dest\" from \"$i\"" -1 -1 local downloadError=1 case "${dest##*.}" in "pk3"|"zip") unzip -tq "${cache}/${dest}" | dialog --backtitle "Linux Game Manager" \ --progressbox "Validating ${dest##*.} file" -1 -1 --stdout downloadError=$? ;; "7z") 7z t "${cache}/${dest}" | dialog --backtitle "Linux 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 "Linux Game Manager" \ --infobox "Error downloading \"${dest}\". Installation cannot continue." -1 -1 --stdout alert exit 1 fi done } download_named() { # Only needed if url breaks the name, e.g. downloads/?filename=1234 # Required arguments: filename url # Only works with one file at a time. local dest="$1" # Remove the destination file if it is empty. test -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. test -e "${cache}/${dest}" && return if ! curl -L4 --output "${cache}/${dest}" "${2}" ; then echo "Could not download \"$dest\"..." exit 1 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 echo "Manual intervention required..." alert dialog --ok-label "Continue" \ --backtitle "Linux Game 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 mv -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 } 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/:/ }: ${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 "doomLanguage=\"en\" # 2 letter language code for translation." 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 "spd_module=\\" # set speech-dispatcher module." echo "spd_pitch=\\" # set speech-dispatcher speech pitch." echo "spd_rate=\\" # set speech-dispatcher speech rate." echo "spd_voice=\\" # set speech-dispatcher voice. Be sure module is correct." echo "spd_volume=\\" # set speech-dispatcher speech volume." exit 0 } # main script add_launcher() { local launchSettings="${game}|${*}" if ! grep -F -q -x "${launchSettings}" "${configFile}" 2> /dev/null ; then echo "${launchSettings}" >> "${configFile}" sort -o "${configFile}" "${configFile}" fi } # Install games game_installer() { mapfile -t installedGames < <(sed '/^$/d' "${configFile}" 2> /dev/null | cut -d '|' -f1) # Create the menu of installed games declare -a menuList for i in "${gameList[@]}" ; do local menuItem="$i" for j in "${installedGames[@]}" ; do if [[ "$j" == "$menuItem" ]]; then unset menuItem fi done if [[ -n "$menuItem" ]]; then menuList+=("$menuItem" "$menuItem") fi done if [[ ${#menuList[@]} -eq 0 ]]; then echo "All games are already installed." exit 0 fi menuList+=("Donate" "Donate") game="$(dialog --backtitle "Game Installer" \ --clear \ --no-tags \ --menu "Please select a game to install" 0 0 0 "${menuList[@]}" --stdout)" } # remove games game_removal() { 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 menuList+=("${i#*|}" "${i%|*}") done menuList+=("Donate" "Donate") menuList+=("Become a Patron" "Become a Patron") local game="$(dialog --backtitle "Audio Game Removal" \ --clear \ --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 fi local launcherPath="$(readlink -f "$0")" launcherPath="${launcherPath%/*}" local noRemove="no" if [[ "${game%/*}" =~ ^$launcherPath ]] ; then # The launcher is actually a script under lgm, do not remove. noRemove="yes" dialog --backtitle "Linux Game Manager" \ --yesno "This will remove the game from your game list, but will not remove any files. Do you want to continue?." -1 -1 --stdout || exit 0 else dialog --backtitle "Linux Game Manager" \ --yesno "This will remove the directory \"${game%/*}\" and all of its contents. Do you want to continue?." -1 -1 --stdout || exit 0 fi export noRemove { [ "$noRemove" == "no" ] && rm -rfv "${game%/*}"; sed -i "/${game//\//\\/}/d" "$configFile"; } | dialog --backtitle "Linux Game Manager" --progressbox "Removing game..." -1 -1 exit 0 } # update games game_update() { mapfile -t lines < <(find .update -type f -iname '*.sh' 2> /dev/null) if [[ ${#lines} -eq 0 ]]; then echo "No games found." exit 0 fi # Create the menu of updatable games declare -a menuList for i in "${lines[@]}" ; do menuList+=("${i}" "${i##*/}") done menuList+=("Donate" "Donate") menuList+=("Become a Patron" "Become a Patron") local game="$(dialog --backtitle "Audio Game Updater" \ --clear \ --no-tags \ --menu "Please select a game to update" 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 fi source "${game}" run_update exit 0 } # launch games that are installed game_launcher() { mapfile -t lines < <(sed '/^$/d' "${configFile}" 2> /dev/null) # Create the menu of installed games declare -a menuList for i in "${lines[@]}" ; do menuList+=("${i#*|}" "${i%|*}") done # Web based games and donation menuList+=("Aliens" "Aliens") menuList+=("Cacophony" "Cacophony") menuList+=("Battle Weary" "Battle Weary") menuList+=("QuentinC Play Room" "QuentinC Play Room") menuList+=("Trigaea" "Trigaea") menuList+=("Donate" "Donate") game="$(dialog --backtitle "Linux Game Launcher" \ --clear \ --no-tags \ --menu "Please select a game to play" 0 0 0 "${menuList[@]}" --stdout)" local menuCode=$? if [[ $menuCode -eq 1 ]]; then exit 0 fi # Remove any trailing | from game variable. game="${game%|}" case "${game}" in "Aliens") open_url "https://files.jantrid.net/aliens/" ;; "Battle Weary") open_url "https://lonespelunker.itch.io/battle-weary" ;; "Cacophony") open_url "https://tianmaru.itch.io/cacophony" ;; "QuentinC Play Room") open_url "https://qcsalon.net/" ;; "Trigaea") open_url "https://ryngm.itch.io/trigaea" ;; "Donate") open_url "https://ko-fi.com/stormux" ;; *".tin") git -C "${game%/*}" pull | \ dialog --progressbox "Checking for updates, please wait..." -1 -1 if [[ -n "${COLORTERM}" ]]; then terminal_emulator tt++ ${game##*/} else pushd "${game%/*}" exec tt++ ${game##*/} fi ;; *"main.py") pushd "${game%/*}" git pull -q | dialog --progressbox "Checking for updates, please wait..." -1 -1 python3 ${game} ;; *) pushd "${game%/*}" exec ${game} ;; esac exit 0 } # If display isn't set assume we are launching from console and an X environment is running using display :0 # Warning, launching games from console is not recommended. if [[ -z "$DISPLAY" ]]; then export DISPLAY=":0" fi # Settings file cache="${XDG_CACHE_HOME:-$HOME/.cache}/linux-game-manager" configFile="${XDG_CONFIG_HOME:-$HOME/.config}/storm-games/linux-game-manager/games.conf" mkdir -p "${cache}" mkdir -p "${configFile%/*}" # Load any arguments from settings.conf file if [[ -r "${configFile%/*}/settings.conf" ]]; then source "${configFile%/*}/settings.conf" fi unset noCache export doomLanguage="${doomLanguage:-en}" export ipfsGateway="${ipfsGateway:-https://ipfs.stormux.org}" export spd_module="${spd_module:+ -o ${spd_module}}" export spd_pitch="${spd_pitch:+ -p ${spd_pitch}}" export spd_rate="${spd_rate:+ -r ${spd_rate}}" export spd_voice="${spd_voice:+ -y ${spd_voice}}" export spd_volume="${spd_volume:+ -i ${spd_volume}}" # The list of games available for installation. # Use menu friendly names. gameList=( "Aliens" "Alter Aeon" "Audo" "Auroboros" "Ball Bouncer" "Battle Weary" "Bladius" "Cacophony" "Chimera" "Critter Sanctuary" "Echo Command" "E.X.O." "EmpireMUD" "End of Time" "Fantasy Story II" "Freedoom" "Monkey Spank" "Numnastics" "Onslaught" "QuentinC Play Room" "Periphery Synthetic EP" "S.E.A." "Slay the Spire" "Slay the Text" "SoundRTS" "soundStrider" "Stardew Valley" "StickMUD" "System Fault" "Trigaea" "Upheaval Commandline" "Upheaval Gui" "Wurmus" "Zombowl" ) # Check for required packages requiredPackages=( "7z" "curl" "dialog" "unzip" ) for i in "${requiredPackages[@]}" ; do if ! command -v $i > /dev/null 2>&1 ; then echo "Please install ${i/7z/p7zip} before continuing." exit 1 fi done check_update # With no arguments, open the game launcher. if [[ $# -eq 0 ]]; then game_launcher fi # Array of command line arguments declare -A command=( [C]="Clear the cache. All game installers will be deleted." [D]="Create desktop shortcut. You can launch Linux Game Manager from the desktop or applications menu." [h]="This help screen." [i]="Install games." [L]="Display license information." [N]="No cache, delete the installer after it has been extracted." [R]="Redownload. Removes old versions of packages from cache before installing." [r]="Remove game. Remove a game and its menu entry." [t]="Total games. Show how many games are currently available." [u]="Update games. Run available game update scripts." ) # 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) clear_cache ;; D) desktop_launcher ;; h) help ;; i) game_installer ;; L) license ;; N) noCache="true" ;; R) redownload="true" ;; r) game_removal ;; t) dialog --backtitle "Linux Game Manager" \ --infobox "There are currently ${#gameList[@]} games available." -1 -1 exit 0 ;; u) game_update ;; esac done # Install game based on the selection above. installPath="${HOME}/.local/games" mkdir -p "${installPath}" case "${game}" in "Aliens"|"Battle Weary"|"Cacophony"|"QuentinC Play Room"|"Trigaea") dialog --backtitle "Linux Game manager" \ --infobox "${game} is a web based game and does not need to be installed." -1 -1 ;; "Alter Aeon") check_dependencies git sox tt++ git -C "${installPath}/" clone --recurse-submodules https://github.com/lilmike/tintin-alteraeon.git | \ dialog --progressbox "Installing \"${game}\", please wait..." -1 -1 add_launcher "${installPath}/tintin-alteraeon/aa.tin" ;; "Audo") check_architecture x86_64 get_installer "Audo-linux-x64.zip" "https://shiftbacktick.itch.io/audo" mkdir -p "${installPath}/Audo" unzip -d "${installPath}/Audo" "${cache}/Audo-linux-x64.zip" add_launcher "${installPath}/Audo/Audo" ;; "Auroboros") check_architecture x86_64 get_installer "Auroboros-linux-x64.zip" "https://shiftbacktick.itch.io/auroboros" mkdir -p "${installPath}/Auroboros" unzip -d "${installPath}/Auroboros" "${cache}/Auroboros-linux-x64.zip" add_launcher "${installPath}/Auroboros/Auroboros" ;; "Ball Bouncer") check_architecture x86_64 download "https://files.sooslandia.ru/BallBouncer/1.2.1/BallBouncer-linux-1.2.1.zip" unzip -d "${installPath}/" "${cache}/BallBouncer-linux-1.2.1.zip" chmod +x "${installPath}/BallBouncer/BallBouncer" add_launcher "${installPath}/BallBouncer/BallBouncer" ;; "Bladius") check_architecture x86_64 get_installer "Bladius-linux-x64.zip" "https://shiftbacktick.itch.io/bladius" mkdir -p "${installPath}/Bladius" unzip -d "${installPath}/Bladius" "${cache}/Bladius-linux-x64.zip" add_launcher "${installPath}/Bladius/Bladius" ;; "Chimera") check_architecture x86_64 get_installer "Chimera-linux-x64.zip" "https://shiftbacktick.itch.io/chimera" mkdir -p "${installPath}/Chimera" unzip -d "${installPath}/Chimera" "${cache}/Chimera-linux-x64.zip" add_launcher "${installPath}/Chimera/Chimera" ;; "Critter Sanctuary") check_architecture x86_64 get_installer "critter-sanctuary-linux.zip" "https://punishedfelix.itch.io/critter-sanctuary" mkdir -p "${installPath}/critter-sanctuary" unzip -d "${installPath}/critter-sanctuary" "${cache}/critter-sanctuary-linux.zip" mkdir -p "${XDG_DATA_HOME:-${HOME}/.local}/share/godot/app_userdata/OverworldMovementEngine" cp -v "${installPath}/critter-sanctuary/blind_options.save" "${XDG_DATA_HOME:-${HOME}/.local}/share/godot/app_userdata/OverworldMovementEngine/options.save" add_launcher "${installPath}/critter-sanctuary/linux.x86_64" ;; "Echo Command") check_architecture x86_64 get_installer "Echo Command.tar.xz" "https://pancakedev.itch.io/echo-command" mkdir -p "${installPath}/Echo-Command" tar xf "${cache}/Echo Command.tar.xz" -C "${installPath}/Echo-Command" ln -sr "${installPath}/Echo-Command/Echo Command.x86_64" "${installPath}/Echo-Command/Echo_Command.x86_64" add_launcher "${installPath}/Echo-Command/Echo_Command.x86_64" ;; "E.X.O.") check_architecture x86_64 get_installer "EXO-linux-x64.zip" "https://shiftbacktick.itch.io/exo" mkdir -p "${installPath}/E.X.O." unzip -d "${installPath}/E.X.O." "${cache}/EXO-linux-x64.zip" add_launcher "${installPath}/E.X.O./EXO" ;; "EmpireMUD") check_dependencies git sox tt++ git -C "${installPath}/" clone --recurse-submodules https://github.com/lilmike/tintin-empiremud.git | \ dialog --progressbox "Installing \"${game}\", please wait..." -1 -1 add_launcher "${installPath}/tintin-empiremud/em.tin" ;; "End of Time") check_dependencies git opusdec sox tt++ git -C "${installPath}/" clone https://git.2mb.codes/~stormdragon2976/tintin-endoftime | \ dialog --progressbox "Installing \"${game}\", please wait..." -1 -1 add_launcher "${installPath}/tintin-endoftime/eot.tin" ;; "Fantasy Story II") check_architecture x86_64 get_installer "FS2_3.0_Linux.zip" "https://drive.google.com/file/d/15Y5nxR1zl9vVNzMilpaXdCSBFhNUIDC9/view" unzip -d "${installPath}" "${cache}/FS2_3.0_Linux.zip" chmod +x "${installPath}/FS2_3.0_Linux/fs2.x86_64" add_launcher "${installPath}/FS2_3.0_Linux/fs2.x86_64" "-ESpeakApplication=espeak-ng" ;; "Freedoom") tobyVersion="7-5" mkdir -p "${installPath}/doom" doomPath="$(find /usr/share -type d -name "doom" 2> /dev/null)" if [[ ${#doomPath} -lt 5 ]]; then dialog --backtitle "Linux Game Manager" \ --yesno "Do you want Linux Game Manager to install freedoom and gzdoom for you? If you want to do this manually, select no." -1 -1 --stdout || exit 0 if command -v yay &> /dev/null ; then yay -Sy --noconfirm --sudoloop freedoom gzdoom freedm blasphemer-wad elif command -v slapt-src &> /dev/null ; then su -c 'slapt-src -i freedoom gzdoom' elif command -v dnf &> /dev/null ; then sudo dnf copr -y enable nalika/gzdoom sudo dnf -q -y install freedoom sudo dnf -q -y install gzdoom else dialog --backtitle "Linux Game Manager" --msgbox "No supported package managers found. Please install the freedoom and gzdoom packages manually." -1 -1 exit 0 fi fi doomPath="$(find /usr/share -type d -name "doom" 2> /dev/null | head -1)" if ! [[ -e "${installPath}/doom/DoomMetalVol6.wad" ]] && ! [[ -e "${installPath}/doom/DoomMetalVol7.wad" ]]; then alert dialog --backtitle "Linux Game manager" \ --extra-button \ --yes-label "6" \ --no-label "7" \ --extra-label "None" \ --yesno "Would you like Doom Metal Volume 6 or 7? Use arrow keys to select your answer." \ -1 -1 --stdout buttonCode=$? if [[ $buttonCode -eq 0 ]]; then download "${ipfsGateway}/ipfs/QmSzWKtP3wPvzn5GNd9F7n4RAhkFHxh2UHxXGefiAufwQW?filename=DoomMetalVol6.wad" fi if [[ $buttonCode -eq 1 ]]; then download "${ipfsGateway}/ipfs/QmfXkz3tzicKGfhcYSiWUZkjkDKP2aVp53Y49n127wMr7D?filename=DoomMetalVol7.wad" fi fi # The url breaks the normal download function download_named "keyshare-universal.pk3" "https://forum.zdoom.org/download/file.php?id=42262" download "${ipfsGateway}/ipfs/QmRjg1GSBmVCCtPv8GRTZSjNNDMjHEXE2k5hKxoBnYMFKQ?filename=TobyAccessibilityMod_V${tobyVersion}.zip" [[ -e "${cache}/DoomMetalVol6.wad" ]] && mv "${cache}/DoomMetalVol6.wad" "${installPath}/doom" [[ -e "${cache}/DoomMetalVol7.wad" ]] && mv "${cache}/DoomMetalVol7.wad" "${installPath}/doom" unzip -n -d "${installPath}/doom" "${cache}/TobyAccessibilityMod_V${tobyVersion}.zip" unzip -n -d "${installPath}/doom" "${cache}/OpMDK_ForV${tobyVersion}.zip" cp -v "${cache}/keyshare-universal.pk3" "${installPath}/doom" rm -fv "${installPath}/doom/"*.{ahk,bat,exe,dll,ps1} if [[ -e /usr/share/doom/blasphem.wad ]]; then ln -s /usr/share/doom/blasphem.wad "${installPath}/doom/" fi mkdir -p "${XDG_CONFIG_HOME:-$HOME/.config}/gzdoom" cp "${installPath}/doom/TobyConfig.ini" "${XDG_CONFIG_HOME:-$HOME/.config}/gzdoom/gzdoom.ini" cp "${installPath}/doom/zcajun/bots.cfg" "${XDG_CONFIG_HOME:-$HOME/.config}/gzdoom/" sed -i "s;^\[IWADSearch.Directories\]$;[IWADSearch.Directories]\nPath=${doomPath}\nPath=${installPath}/doom;" "${XDG_CONFIG_HOME:-$HOME/.config}/gzdoom/gzdoom.ini" sed -i "s;^\[FileSearch.Directories\]$;[FileSearch.Directories]\nPath=${doomPath}\nPath=${installPath}/doom;" "${XDG_CONFIG_HOME:-$HOME/.config}/gzdoom/gzdoom.ini" sed -i "s;^\[SoundfontSearch.Directories\]$;[SoundfontSearch.Directories]\nPath=${doomPath}/fm_banks\nPath=${doomPath}/soundfonts\nPath=${installPath}/doom/soundfonts\nPath=${installPath}/doom/fm_banks;" "${XDG_CONFIG_HOME:-$HOME/.config}/gzdoom/gzdoom.ini" # sed -i 's/Mouse1=+attack/CTRL=+attack/' "${XDG_CONFIG_HOME:-$HOME/.config}/gzdoom/gzdoom.ini" launcherPath="$(readlink -f "$0")" launcherPath="${launcherPath%/*}" add_launcher "${launcherPath}/.scripts/FreeDoom.sh" ;; "Monkey Spank") check_dependencies python-pygame:pygame python-xdg:xdg python-pyperclip:pyperclip python-requests:requests python-setproctitle:setproctitle git -C "${installPath}" clone --recurse-submodules https://gitlab.com/stormdragon2976/monkeyspank.git add_launcher "${installPath}/monkeyspank/monkeyspank" ;; "Numnastics") check_dependencies python-pygame:pygame python-xdg:xdg python-pyperclip:pyperclip python-requests:requests python-setproctitle:setproctitle git -C "${installPath}" clone --recurse-submodules https://gitlab.com/stormdragon2976/numnastics.git add_launcher "${installPath}/numnastics/numnastics" ;; "Onslaught") check_architecture x86_64 get_installer "onslaught.AppImage" "https://lightsoutgames.itch.io/onslaught" mkdir -p "${installPath}/Onslaught" cp -v "${cache}/onslaught.AppImage" "${installPath}/Onslaught/onslaught.AppImage" chmod +x "${installPath}/Onslaught/onslaught.AppImage" add_launcher "${installPath}/Onslaught/onslaught.AppImage" ;; "Periphery Synthetic EP") check_architecture x86_64 get_installer "periphery-synthetic-ep-linux-x64.zip" "https://shiftbacktick.itch.io/periphery-synthetic-ep" mkdir -p "${installPath}/periphery-synthetic-ep" unzip -d "${installPath}/periphery-synthetic-ep" "${cache}/periphery-synthetic-ep-linux-x64.zip" add_launcher "${installPath}/periphery-synthetic-ep/periphery-synthetic-ep" ;; "S.E.A.") check_architecture x86_64 get_installer "SEA-linux-x64.zip" "https://shiftbacktick.itch.io/sea" mkdir -p "${installPath}/S.E.A." unzip -d "${installPath}/S.E.A." "${cache}/SEA-linux-x64.zip" add_launcher "${installPath}/S.E.A./SEA" ;; "Slay the Spire") check_architecture x86_64 echo "Please note this requires the game to be available either in your Steam library" echo "or as the installer purchased from gog.com." echo "If using the gog.com installer, please use the default path when prompted." alert check_dependencies steamcmd appId="646570" if ! [[ -f ~/Downloads/slay_the_spire_2020_12_15_8735c9fe3cc2280b76aa3ec47c953352a7df1f65_43444.sh ]] && ! [[ -f ~/Desktop/slay_the_spire_2020_12_15_8735c9fe3cc2280b76aa3ec47c953352a7df1f65_43444.sh ]]; then echo "Please enter Steam user name:" read -er steamUser steamcmd +@sSteamCmdForcePlatformType linux +force_install_dir "${HOME}/.local/games/SlayTheSpire" +login "$steamUser" +app_update "$appId" +quit else DISPLAY="" find ~/Downloads -maxdepth 1 -type f -name 'slay_the_spire_2020_12_15_8735c9fe3cc2280b76aa3ec47c953352a7df1f65_43444.sh' -exec bash "{}" \; || find ~/Desktop -maxdepth 1 -type f -name 'slay_the_spire_2020_12_15_8735c9fe3cc2280b76aa3ec47c953352a7df1f65_43444.sh' -exec bash "{}" \; if [[ $? -eq 0 ]]; then ln -sf "${HOME}/GOG Games/Slay the Spire/game" "${installPath}/SlayTheSpire" || { echo "Error creating link." exit 1; } else echo "Error installing game." exit 1 fi fi # Move files into place mkdir -p "${HOME}/.config/ModTheSpire" if [[ -f ~"/.config/ModTheSpire/mod_lists.json" ]]; then dialog --backtitle "Linux Game manager" \ --yesno "Existing mod_lists.json file found. Would you like to replace it?" -1 -1 --stdout && cp -v .files/SlayTheSpire/mod_lists.json "${HOME}/.config/ModTheSpire/mod_lists.json" else cp -v .files/SlayTheSpire/mod_lists.json "${HOME}/.config/ModTheSpire/mod_lists.json" fi cp -v .files/SlayTheSpire/MTS.sh "${HOME}/.local/games/SlayTheSpire/" # Get mods declare -A mods=( [mod the spire]=1605060445 [base mod]=1605833019 [stslib]=1609158507 [curses come first]=2304840098 [achievement enabler]=1692554109 [say the spire]=2239220106 ) installString="" for x in ${mods[@]} ; do installString="$installString +workshop_download_item $appId $x" done steamcmd +@sSteamCmdForcePlatformType linux +force_install_dir "${HOME}/.local/games/SlayTheSpire/" +login anonymous $installString +quit mkdir -p "$HOME/.local/games/SlayTheSpire/mods" for x in "${!mods[@]}" ; do if [ "$x" == "mod the spire" ] ; then ln -sr "$HOME/.local/games/SlayTheSpire/steamapps/workshop/content/$appId/${mods[$x]}"/* "$HOME/.local/games/SlayTheSpire/" else ln -sr "$HOME/.local/games/SlayTheSpire/steamapps/workshop/content/$appId/${mods[$x]}"/* "$HOME/.local/games/SlayTheSpire/mods/" fi done launcherPath="$(readlink -f "$0")" launcherPath="${launcherPath%/*}" add_launcher "${launcherPath}/.scripts/SlayTheSpire.sh" ;; "Slay the Text") check_dependencies python-ansimarkup:ansimarkup git -C "${installPath}/" clone https://github.com/Difio3333/slaythetext.git | \ dialog --progressbox "Installing \"${game}\", please wait..." -1 -1 add_launcher "${installPath}/slaythetext/main.py" ;; "SoundRTS") check_dependencies python3 mkdir -p "${installPath}" git -C "${installPath}" clone "https://github.com/soundmud/soundrts.git" git -C "${installPath}/soundrts" checkout v1.3.8 sed -i 's;git+https://github.com/soundmud/accessible_output2;accessible_output2;' "${installPath}/soundrts/requirements.txt" python3 -m venv --system-site-packages "${installPath}/soundrts/.venv" "${installPath}/soundrts/.venv/bin/"pip3 install -r "${installPath}/soundrts/requirements.txt" if [ $(python3 --version | cut -d. -f2) -ge 12 ] ; then "${installPath}/soundrts/.venv/bin/"pip3 install pyasyncore pyasynchat fi chmod +x "${installPath}/soundrts/soundrts.py" sed -i '1c\#!'"${installPath}/soundrts/.venv/bin/python3" "${installPath}/soundrts/soundrts.py" add_launcher "${installPath}/soundrts/soundrts.py" ;; "soundStrider") check_architecture x86_64 get_installer "soundStrider-linux-x64.zip" "https://shiftbacktick.itch.io/soundstrider" mkdir -p "${installPath}/soundStrider" unzip -d "${installPath}/soundStrider" "${cache}/soundStrider-linux-x64.zip" add_launcher "${installPath}/soundStrider/soundStrider" ;; "Stardew Valley") check_architecture x86_64 DISPLAY="" echo "Please select the default path when prompted by the installer." alert get_installer "stardew_valley_1_5_6_1988831614_53040.sh" "https://www.gog.com/game/stardew_valley" bash "${cache}/stardew_valley_1_5_6_1988831614_53040.sh" || { echo "Error installing game." exit 1; } smapiVersion="3.18.4" download "https://github.com/Pathoschild/SMAPI/releases/download/${smapiVersion}/SMAPI-${smapiVersion}-installer.zip" "https://stormgames.wolfe.casa/downloads/stardew-valley/Mods.tar.xz" smapiTmp="$(mktemp -d)" unzip "${cache}/SMAPI-${smapiVersion}-installer.zip" -d "$smapiTmp" echo "Preparing to install mods. Please select the same path as before when prompted." echo "When it says SMAPI has been installed, press enter to finish installation." alert bash "${smapiTmp}/SMAPI ${smapiVersion} installer/install on Linux.sh" ln -sf "${HOME}/GOG Games/Stardew Valley/game" "${installPath}/StardewValley" tar -xvf "${cache}/Mods.tar.xz" -C "${installPath}/StardewValley/" add_launcher "${installPath}/StardewValley/StardewValley" ;; "StickMUD") check_dependencies git sox tt++ git -C "${installPath}/" clone --recurse-submodules https://github.com/stormdragon2976/tintin-stickmud.git | \ dialog --progressbox "Installing \"${game}\", please wait..." -1 -1 add_launcher "${installPath}/tintin-stickmud/stickmud.tin" ;; "System Fault") check_architecture x86_64 get_installer "system-fault-linux-x86_64.AppImage" "https://lightsoutgames.itch.io/systemfault" mkdir -p "${installPath}/System_Fault" cp -v "${cache}/system-fault-linux-x86_64.AppImage" "${installPath}/System_Fault/system-fault-linux-x86_64.AppImage" chmod +x "${installPath}/System_Fault/system-fault-linux-x86_64.AppImage" add_launcher "${installPath}/System_Fault/system-fault-linux-x86_64.AppImage" ;; "Upheaval Commandline") check_architecture x86_64 check_dependencies dmidecode get_installer "upheaval-linux-console.zip" "https://leonegaming.itch.io/upheaval" mkdir -p "${installPath}/Upheaval_Commandline" unzip -d "${installPath}/Upheaval_Commandline" "${cache}/upheaval-linux-console.zip" add_launcher "${installPath}/Upheaval_Commandline/Upheaval_Command_Line" ;; "Upheaval Gui") check_architecture x86_64 check_dependencies dmidecode get_installer "upheaval-linux.zip" "https://leonegaming.itch.io/upheaval" mkdir -p "${installPath}/Upheaval_Gui" unzip -d "${installPath}/Upheaval_Gui" "${cache}/upheaval-linux.zip" add_launcher "${installPath}/Upheaval_Gui/Upheaval" echo "To enable accessibility, press shift t when the game starts." alert ;; "Wurmus") check_architecture x86_64 get_installer "Wurmus-linux-x64.zip" "https://shiftbacktick.itch.io/wurmus" mkdir -p "${installPath}/Wurmus" unzip -d "${installPath}/Wurmus" "${cache}/Wurmus-linux-x64.zip" add_launcher "${installPath}/Wurmus/Wurmus" ;; "Zombowl") architecture="$(uname -m)" if [[ "${architecture}" == "aarch64" ]]; then pkgname="Zombowl-Linux-aarch64.zip" elif [[ "${architecture}" == "x86_64" ]]; then pkgname="Zombowl-Linux-X86_64.zip" else echo "Architecture ${architecture} is not supported." exit 1 fi get_installer "${pkgname}" "https://stormdragon2976.itch.io/zombowl" mkdir -p "${installPath}/" unzip -d "${installPath}/" "${cache}/${pkgname}" add_launcher "${installPath}/${pkgname%.*}/Zombowl" ;; "Donate") open_url "https://ko-fi.com/stormux" ;; *) [[ -n "${game}" ]] && echo "Game \"${game}\" not found." exit 1 ;; esac exit 0