#!/usr/bin/env bash # Source installation helper source /usr/local/bin/stormux_install_helper.sh # Function to run a game with FEXLoader fex_load() { local gameDir="$1" local exeName="$2" export SPD_SOCKET=/run/user/1000/speech-dispatcher/speechd.sock pushd "$HOME/.local/games/$gameDir" if [[ "$(uname -m)" != "x86_64" ]]; then export FEX_NO_SANDBOX=1 export MESA_GL_VERSION_OVERRIDE=3.2 FEX_NO_SANDBOX=1 MESA_GL_VERSION_OVERRIDE=3.2 BOX64_DYNAREC_STRONGMEM=1 DISPLAY=:0 FEXLoader ./$exeName else export MESA_GL_VERSION_OVERRIDE=3.2 MESA_GL_VERSION_OVERRIDE=3.2 DISPLAY=:0 ./$exeName fi popd } # Function to run a Windows game with wine via FEXBash run_wine() { local gameDir="$1" local exeName="$2" local needNvda="${3:-}" pushd "$HOME/.local/games/$gameDir" if [[ "$(uname -m)" != "x86_64" ]]; then if [[ ${#needNvda} -gt 1 ]]; then systemctl --user start "${needNvda}.service" FEXBash -c "wine \"$exeName\"" systemctl --user stop "${needNvda}.service" else FEXBash -c "wine $exeName" fi else if [[ ${#needNvda} -gt 1 ]]; then systemctl --user start "${needNvda}.service" wine "$exeName" systemctl --user stop "${needNvda}.service" else wine "$exeName" fi fi popd } # Function to handle downloadable games with installation setup_and_run_downloadable() { local zipName="$1" local gameDir="$2" local executable="$3" local fallbackUrl="$4" local needNvda="$5" local zipPath=~/Downloads/"$zipName" local extractDir="$HOME/.local/games/$gameDir" if [[ -e "$zipPath" ]]; then # Recreate extractDir rm -rf "$extractDir" mkdir -p "$extractDir" # Get the first path component of each file in the zip mapfile -t topDirs < <(unzip -l "$zipPath" | awk 'NR>3 {print $4}' | grep '/$' | cut -d/ -f1 | sort -u | grep -v '^$') if [[ ${#topDirs[@]} -eq 1 ]]; then # Zip has a single top-level dir �se it as final dir unzip -q "$zipPath" -d ~/.local/games else # Unzips file into the given directory without creating a subdirectory unzip -q "$zipPath" -d "$extractDir" fi # Copy NVDA DLLs for i in 32 64; do find "$extractDir" -type f -name "nvdaControllerClient${i}.dll" -exec cp -v "$HOME/.local/games/nvda/nvdaControllerClient${i}.dll" '{}' \; done rm -f "$zipPath" fi if [[ -e "$extractDir/$executable" ]]; then run_wine "${extractDir##*/}" "./$executable" "$needNvda" else run_web "$fallbackUrl" fi } # Enhanced function to handle downloadable games with direct URL support setup_and_run_downloadable_url() { local downloadUrl="$1" local gameDir="$2" local executable="$3" local fallbackUrl="$4" local needNvda="$5" local extractDir="$HOME/.local/games/$gameDir" local tempZip="/tmp/${gameDir}_download.zip" # Check if game is already installed if [[ -e "$extractDir/$executable" ]]; then run_wine "$gameDir" "./$executable" "$needNvda" return fi # Download the game echo "Downloading $gameDir..." if curl -L -o "$tempZip" "$downloadUrl"; then # Recreate extractDir rm -rf "$extractDir" mkdir -p "$extractDir" # Get the first path component of each file in the zip mapfile -t topDirs < <(unzip -l "$tempZip" | awk 'NR>3 {print $4}' | grep '/$' | cut -d/ -f1 | sort -u | grep -v '^$') if [[ ${#topDirs[@]} -eq 1 ]]; then # Zip has a single top-level dir - extract to ~/.local/games, then rename unzip -q "$tempZip" -d ~/.local/games # If the extracted dir name differs from gameDir, rename it if [[ "${topDirs[0]}" != "$gameDir" ]]; then mv ~/.local/games/"${topDirs[0]}" "$extractDir" fi else # Unzips file into the given directory without creating a subdirectory unzip -q "$tempZip" -d "$extractDir" fi # Copy NVDA DLLs for i in 32 64; do find "$extractDir" -type f -name "nvdaControllerClient${i}.dll" -exec cp -v "$HOME/.local/games/nvda/nvdaControllerClient${i}.dll" '{}' \; done rm -f "$tempZip" echo "Download and installation complete!" # Now run the game if [[ -e "$extractDir/$executable" ]]; then run_wine "$gameDir" "./$executable" "$needNvda" else echo "Error: Game executable not found after installation" run_web "$fallbackUrl" fi else echo "Download failed, opening fallback URL" run_web "$fallbackUrl" fi } # Function to handle all web-based games run_web() { cthulhu & exec brave "$1" } # Function to handle unpacked web games # Function to handle unpacked web games setup_and_run_web_game() { local zipName="$1" local gameDir="$2" local htmlPath="$3" local fallbackUrl="$4" local zipPath=~/Downloads/"$zipName" local extractDir="$HOME/.local/games/$gameDir" if [[ -e "$zipPath" ]]; then # Recreate extractDir rm -rf "$extractDir" mkdir -p "$extractDir" # Get the first path component of each file in the zip mapfile -t topDirs < <(unzip -l "$zipPath" | awk 'NR>3 {print $4}' | grep '/$' | cut -d/ -f1 | sort -u | grep -v '^$') if [[ ${#topDirs[@]} -eq 1 ]]; then # Zip has a single top-level dir - extract to ~/.local/games unzip -q "$zipPath" -d "$HOME/.local/games" else # Unzips file into the given directory unzip -q "$zipPath" -d "$extractDir" fi rm -f "$zipPath" fi if [[ -e "$extractDir/$htmlPath" ]]; then run_web "$extractDir/$htmlPath" else run_web "$fallbackUrl" fi } # Function to run native applications run_native() { local gameDir="$1" local exeName="$2" pushd "/home/stormux/.local/games/$gameDir" case "${exeName##*.}" in "py") python3 "$exeName" ;; *) ./"$exeName" ;; esac popd } # Initial setup if [[ -e /etc/X11/xorg.conf.d/10-headless.conf ]]; then export LIBGL_ALWAYS_SOFTWARE=1 fi [ -f /etc/xprofile ] && . /etc/xprofile [ -f ~/.xprofile ] && . ~/.xprofile if [[ "$(uname -m)" != "x86_64" ]]; then export BOX64_PATH="$HOME/.fex-emu/RootFS/ArchLinux/usr/bin" export BOX64_NOBANNER=1 export BOX64_DYNAREC_STRONGMEM=1 fi export MESA_GL_VERSION_OVERRIDE=3.2 export DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus export DBUS_SESSION_BUS_PID exec dwm & xbindkeys # Main game launcher case "$GAME" in "Apple 2e") exec mame apple2ee -sl1 echoii -flop1 ~/.local/games/apple2e/Echo\ II\ -\ Textalker\ DOS\ 3.3.dsk -samplerate 48000 -sound pulse ;; "Audio Disc") run_wine "audiodisc" "disco.exe" ;; "BallBouncer") fex_load BallBouncer BallBouncer ;; "Battle of the Hunter") run_wine "Battle of the Hunter" "bth.exe" "nvda2speechd" ;; "blueman-manager") cthulhu & blueman-manager ;; "BookStorm") exec /usr/bin/bookstorm ;; "Bokurano Daibouken") /home/stormux/.local/files/clipboard_translator.sh play.exe bokurano-daibouken & run_wine "bk" "play.exe" killall speech-dispatcher ;; "Bokurano Daibouken 2") /home/stormux/.local/files/clipboard_translator.sh play.exe bokurano-daibouken2 & run_wine "bk2" "play.exe" killall speech-dispatcher ;; "Bokurano Daibouken 3") if [[ -d /home/stormux/.local/games/bk3/dict ]] || [[ -e ~/Downloads/dict.dat ]]; then [[ -e ~/Downloads/dict.dat ]] && mv ~/Downloads/dict.dat /home/stormux/.local/games/bk3/ run_wine "bk3" "play.exe" "nvda2speechd" else /home/stormux/.local/files/clipboard_translator.sh play.exe bokurano-daibouken3 & run_wine "bk3" "play.exe" fi killall speech-dispatcher ;; "Bop It") ~/.local/files/speak_window_title.sh bop.exe & run_wine "BopIt" "bop.exe" ;; "Brave") run_web "" # Runs brave without a specific URL ;; "Challenge of the Horse") run_wine "Challenge of the Horse" "game.exe" "nvda2speechd" ;; "Clashes of the Sky") run_wine "clashes_of_the_sky" "clash.exe" "nvda2speechd" ;; "Constant Motion") run_wine "ConstantMotion" "cm.exe" "nvda2speechd" ;; "Crazy Party") run_wine "Crazy-Party-beta82" "Crazy Party.exe" "nvda2speechd-important" ;; "Doom") pushd /home/stormux/.local/games/doom/toby-doom-launcher git pull -q cthulhu & exec "./Toby Doom Launcher.py" popd ;; "Dosbox") exec dosbox-x -fastlaunch -conf /opt/talking-dosbox/dosbox-x.conf ;; "Fantasy Story 2") pushd "/home/stormux/.local/games/Fantasy Story 2/FS2_3.0_Linux" if [[ "$(uname -m)" != "x86_64" ]]; then FEXBash './fs2.x86_64' else './fs2.x86_64' fi popd ;; "Golf") run_wine "golf" "golf.exe" ;; "Horseshoes") pushd /home/stormux/.local/games/horseshoes ./horseshoes popd ;; "Haunted House") pushd /home/stormux/.local/games/haunted-house ./runner haunted-house popd ;; "Haunted Party") setup_and_run_downloadable "hp.zip" "hp" "hp.exe" "https://tunmi13.itch.io/haunted-party" "nvda2speechd" ;; "Kaskade") setup_and_run_downloadable "battlefield-2d-win.zip" "bf" "bf.exe" "https://tunmi13.itch.io/kaskade" "nvda2speechd" ;; "Mach1") run_wine "mach1" "mach1.exe" ;; "Manamon 2") run_wine "Manamon 2" "rpg.exe" "nvda2speechd" ;; "Mine Racer") pushd /home/stormux/.local/games/Mineracer ./mineracer popd ;; "Oh Shit") run_wine "oh_shit" "OhShit.exe" "nvda2speechd" ;; "Pong") run_wine "pong" "pong.exe" ;; "Q9 Action Game") run_wine "Q9 Action Game" "q9.exe" ;; "Retro Arch") /usr/bin/retroarch --accessibility killall speech-dispatcher ;; "River Raiders") run_wine "River Raiders" "raid.exe" ;; "RS Games") run_wine "RS Games Client" "rsg.exe" "nvda2speechd-important" ;; "Scramble") run_wine "scramble_win32" "scramble.exe" "nvda2speechd" ;; "Screaming Strike 2") run_wine "Screaming Strike 2" "play.exe" "nvda2speechd" ;; "Scrolling Battles") run_wine "Scrolling Battles" "sb.exe" "nvda2speechd" ;; "Shadow Line") run_wine "ShadowRine_FullVoice" "play_sr.exe" "nvda2speechd" ;; "Shooter") run_wine "shooter" "Shooter.exe" "nvda2speechd" ;; "Side Party") setup_and_run_downloadable "sideparty-win.zip" "SideParty" "SideParty.exe" "https://masonasons.itch.io/sideparty" "nvda2speechd" ;; "Skateboarder Pro") run_wine "sb_pro_rw" "sb_pro.exe" "nvda2speechd" ;; "Sketchbook (Your World)") run_wine "SBYW" "SBYW.exe" "nvda2speechd-important" ;; "SoundRTS") run_native "SoundRTS" "soundrts.py" ;; "Steam") cthulhu & exec steam -bigpicture ;; "thunderbird") auto_install "thunderbird" cthulhu & exec thunderbird ;; "libreoffice") auto_install "libreoffice" cthulhu & exec libreoffice ;; "Super Egg Hunt") run_wine "super egg hunt" "superegghunt.exe" ;; "Super Liam") fex_load "Super Liam" "SuperLiam" ;; "The Blind Swordsman") if [[ "$(uname -m)" != "x86_64" ]]; then FEXBash -c 'wine ~/.local/games/TheBlindSwordsman.exe' else wine ~/.local/games/TheBlindSwordsman.exe fi ;; "The Great Toy Robbery") fex_load "The Great Toy Robbery" "tgtr" ;; "The Tornado Chicken") fex_load "The Tornado Chicken" "Ttc" ;; "Top Speed 3") fex_load "Top Speed 3" "TopSpeed" ;; "Toy Mania") if [[ -e ~/Downloads/ToyMania_windows_portable_password_is_GrateCollector.7z ]]; then rm -rf ~/.local/games/ToyMania mkdir -p ~/.local/games/ToyMania 7z x ~/Downloads/ToyMania_windows_portable_password_is_GrateCollector.7z -o/home/stormux/.local/games/ToyMania -pGrateCollector rm -f ~/Downloads/ToyMania_windows_portable_password_is_GrateCollector.7z fi if [[ -e ~/.local/games/ToyMania/tm.exe ]]; then cp ~/.local/games/nvda/nvdaControllerClient64.dll ~/.local/games/ToyMania/lib/nvdaControllerClient64.dll systemctl --user start nvda2speechd-important.service pushd ~/.local/games/ToyMania if [[ "$(uname -m)" != "x86_64" ]]; then exec FEXBash -c 'wine ./tm.exe' else exec wine ./tm.exe fi popd systemctl --user stop nvda2speechd-important.service else cthulhu & exec brave "https://tsatria03.itch.io/toymania" fi ;; "Upheaval") setup_and_run_downloadable "upheaval-linux-console.zip" "Upheaval" "Upheaval_Command_Line" "https://leonegaming.itch.io/upheaval" ;; "Villains From Beyond") run_wine "villains from beyond" "game.exe" ;; "Warsim") setup_and_run_downloadable "Warsim Full Game.zip" "Warsim" "Warsim.exe" "https://huw2k8.itch.io/warsim" ;; "Wheels of Prio") fex_load "Wheels of Prio" "Wp" ;; "Wicked Quest") git -C /home/stormux/.local/games/wicked-quest pull git -C /home/stormux/.local/games/wicked-quest submodule update run_native "wicked-quest" "wicked_quest.py" ;; "Wreckingball") auto_install "wreckingball" && run_wine "wreckingball" "wreckingball.exe" "nvda2speechd" ;; "Wreckingball (Pulped)") auto_install "wreckingball-pulped" && run_wine "wreckingball-pulped" "wreckingball.exe" "nvda2speechd" ;; "Kitchensinc") pushd "/home/stormux/.wine32/drive_c/Program Files/Kitchen's Sink" WINEPREFIX=/home/stormux/.wine32 /home/stormux/.local/wine32/bin/wine gamemenu.exe popd ;; "Swamp") pushd "/home/stormux/.wine32/drive_c/Program Files/swamp" WINEPREFIX=/home/stormux/.wine32 /home/stormux/.local/wine32/bin/wine Swamp.exe popd ;; "Zombowl") run_native "zombowl" "zombowl.py" ;; "https://shiftbacktick.itch.io/periphery-synthetic-ep") setup_and_run_web_game "periphery-synthetic-ep-html5.zip" "periphery-synthetic-ep" "index.html" "$GAME" ;; "https://"*) run_web "$GAME" ;; "DISK_ONLY:"*) DISK_PATH="${GAME#DISK_ONLY:}" xbindkeys exec mame apple2ee -sl1 echoii -flop1 "$DISK_PATH" -samplerate 48000 -sound pulse ;; *".dsk") xbindkeys exec mame apple2ee -sl1 echoii -flop1 ~/.local/games/apple2e/Echo\ II\ -\ Textalker\ DOS\ 3.3.dsk -flop2 "$GAME" -samplerate 48000 -sound pulse ;; *"/Roms/"*) exec mednafen -sounddriver sdl -sound 1 "$GAME" ;; *) echo "No valid game specified in \$GAME" sleep 5 ;; esac # Make sure X goes down after game ends pkill -15 Xorg