Logo

dev-resources.site

for different kinds of informations.

How to play a bunch of lemmings

Published at
11/25/2024
Categories
bash
lemmings
Author
gunitinug
Categories
2 categories in total
bash
open
lemmings
open
Author
9 person written this
gunitinug
open
How to play a bunch of lemmings

cute lemmings

I've download a bunch of lemmings games for MS-DOS from an abandonware site (so there were all abandonwares). Since there were like six or seven different zip files (each different lemmings game), I used this script to unzip them:

files=()

for file in *Lemmings*.zip; do
  # If the item is a file, add it to the array
  if [[ -f "$file" ]]; then
    files+=("$file")
  fi
done

for file in "${files[@]}"; do
  #echo "make directory ${file%.zip}"

  # unzip into directory where directory name is the filename with extension
  # removed.
  echo unzipping "/my-downloads/$file" to "$HOME/my-dos/${file%.zip}/"...
  unzip "/my-downloads/$file" -d "$HOME/my-dos/${file%.zip}/"
done
Enter fullscreen mode Exit fullscreen mode

As you can see, each zip file was unzipped to a directory with same name as zip file's file name minus its .zip extension.

Since I have unzipped all files, now I needed a way to choose and execute each game. I came up with a way to list the executables (including .exe and .bat files) and choose the game to execute by line number.

I declared an associative array execs_dict and populated it with the names of executables as keys and their path as values.

declare -A execs_dict

for exe in "L3D.EXE" "VGALEMMI.EXE" "l2p1.exe" "l2p2.exe" "vgalemmi.exe" "VGALEMM2.EXE" "L3F.EXE" "VGAL.EXE" "lemmings.bat" "L3.BAT" "VGALEMMI.BAT" "Lemmings.bat" "LEMMINGSH.B\
AT"; do
        dir="$(find ~/my-dos -name $exe | tr '\/' '\\')"
        c_dir="${dir/\\home\\logan\\my-dos\\/}"
        execs_dict["$exe"]="$c_dir"
done
Enter fullscreen mode Exit fullscreen mode

The "LSD.EXE", "VGALEMMI.EXE",... are the game executables across different lemmings games I've unzipped.

First, I've changed all slashes in the path to backslashes (to be compatiable in dos). Since the paths are to be used inside dosbox, I've removed the leading /home/logan/mydos/. The resulting string represents the path to the different lemmings executables including the path and executable file.

Now to implement a way to list all executables and to choose one of them using the line number:

# Initialize counter for line number                                                                                                                                            
counter=1

# Print the list of keys with line numbers                                                                                                                                      
echo "Lemmings...:"
for key in "${!execs_dict[@]}"; do
    echo "$counter) $key"
    ((counter++))
done

# Ask the user to choose a line number                                                                                                                                          
echo -n "Enter the number: "
read choice

# Get the key corresponding to the chosen number                                                                                                                                
chosen_key=$(echo "${!execs_dict[@]}" | cut -d' ' -f$choice)
Enter fullscreen mode Exit fullscreen mode

Here chosen_key is the key of execs_dict we've populated earlier. It will be used to execute the lemmings game later. So we've printed all lemmings executables (.exe and .bat files) one on each line. Then we chose the game to execute using the line number. Then, we figured out the key in execs_dict which is the executable that we will run.

But there's a problem: when I run dosbox on linux, it will shorten any file names that are too long. It follows the so-called 8.3 convention. It means the part before the dot, the max length is eight characters. After the dot, the max is three characters. Before the dot, any name longer than eight characters long will be transformed: first six characters plus ~ and then a number (eg. ~1 or ~2).

I'll give an example. If the file name (could be a file or directory) is LEMMINGSISAWESOME.REALLY, this will be transformed to LEMMIN~1.REA. Do you get this?

Anyways, in order to run the game I must first shorten both directory and file names from the game executable path. So I wrote these functions shortenDir, convertDir, and convertExec.

First shortenDir function.

# long dir names to dos 8.3 name
function shortenDir() {
    if grep -q '\.' <<< "$1"; then
        # get f and e where the filename comprised of f.e
        f="$(cut -d'.' -f1 <<<"$1")"
        e="$(cut -d'.' -f2 <<<"$1")"

        #echo f: "$f"
        #echo e: "$e"

        # get length of f and e
        n=$(($(wc -m <<<"$f")-1))
        m=$(($(wc -m <<<"$e")-1))

        #echo n: "$n"
        #echo m: "$m"

        # construct new name in the form a.b
        if [[ "$n" -gt 8 ]]; then
            a="$(cut -c1-6 <<< "$f")~1"
        else
            a="$f"
        fi

        if [[ "$m" -gt 3 ]]; then
            b="$(cut -c1-3 <<< "$e")"
        else
            b="$e"
        fi
        s="$a.$b"

        # convert all lowercase to capitals
        S="$(tr 'a-z' 'A-Z' <<< "$s")"

        echo "$S"
    else
        f="$1"
        n=$(($(wc -m <<<"$f")-1))

        if [[ "$n" -gt 8 ]]; then
                        a="$(cut -c1-6 <<< "$f")~1"
        else
            a="$f"
                fi
        s="$a"

        # convert all lowercase to capitals
                S="$(tr 'a-z' 'A-Z' <<< "$s")"

        echo "$S"

    fi
}
Enter fullscreen mode Exit fullscreen mode

This function will receive a single argument that is the long name to be converted according to the 8.3 rule. But we need more than that. We will receive a full path to the executable - something like D1\D2...\exec.bat. So we need to run the shortenDir function on each of D1, D2, ... Dn parts. So I wrote convertDir function for this:

# use shortenDir function to convert all directories from a line
# and reassemble the line.
# We have:
# D1\D2\...\exec.bat
# and
# we want to shorten all D's: D1,D2,...
# then reassemble:
# S1\S2\...\Sn
function convertDir() {
    input="$1"
    base_path="${input%\\*}"
    exec_bat="${input##*\\}"

    # Split the string into components
    IFS='\\' read -r -a components <<< "$base_path"

    #echo components: "${components[@]}"

    conv_d="" #converted dir
    # Process each component
    for component in "${components[@]}"; do
        conv_d+="$(shortenDir "$component")"
        conv_d+="\\" 
    done

    # add back the exec.bat at the end
    # chose to not add exec.bat at the end.
    #conv_d+="$exec_bat"
    echo "$conv_d"
}
Enter fullscreen mode Exit fullscreen mode

For technicality, it's easier to work with if I omit the exec.bat part at the end, so that's what this function will spit out. It takes a line D1\D2...\Dn\exec.bat as the single argument and converts it to S1\S2....\Sn, where Sn denotes a shortend directory name converted from Dn by shortenDir function.

Next, not only directory but an executable file name is also converted using the 8.3 rule. So we make another function convertExec:

function convertExec() {
    shortenDir "$1" 
}
Enter fullscreen mode Exit fullscreen mode

Now, we are ready to use these functions to convert a line of the form D1\D2...D2\exec.bat to S1\S2...\Sn and shortened.bat.

if [[ -n "$chosen_key" ]]; then
    echo "Running ${chosen_key}..."
    # Run the chosen executable
    dosbox -c "mount C /home/logan/my-dos" -c "C:" -c "cd $(convertDir ${execs_dict[$chosen_key]})" -c "$(convertExec $chosen_key)" -conf ~/my-dos/lemmings-dosbox.conf

else
    echo "Invalid choice or file not found."
fi
Enter fullscreen mode Exit fullscreen mode

The actual bash command that is executed is:

dosbox -c "mount C /home/logan/my-dos" -c "C:" -c "cd $(convertDir ${execs_dict[$chosen_key]})" -c "$(convertExec $chosen_key)" -conf ~/my-dos/lemmings-dosbox.conf
Enter fullscreen mode Exit fullscreen mode

Using the -c flag this allows me to run commands that will be run inside dosbox from command line:

mount C /home/logan/my-dos
C:
cd path\to\lemmings\
game
Enter fullscreen mode Exit fullscreen mode

Lastly, -conf option allows me to load a conf file named lemmings-dosbox.conf. I need this to set a screen resolution so the game is displayed in a decent size on my screen. Here's the content of the conf file:

[sdl]
windowresolution=1600x1200
output=opengl
Enter fullscreen mode Exit fullscreen mode

That's about it! Now I'm happy that I can play some lemmings!!!! Have a blessed day!

bash Article's
30 articles in total
Favicon
Understanding Linux Shells: Interactive, Non-Interactive, and RC Files
Favicon
Fixing Linux Backup Sync Issues for exFAT Compatibility
Favicon
Ergonomic Pyhon Text Piping Solution for Linux Shell with pypyp and uv
Favicon
Changing the Login Shell with Security and Interactivity
Favicon
Final Bash Script Series Mastering Remote Server Management and Web App Deployment
Favicon
Writting a GH extension with AI
Favicon
Test GPIO pins on BeagleBone Black by toggling high to low
Favicon
NYP Infosec December CTF 2024 writeup!
Favicon
Building a Smart Heater Controller with Python, Docker, and Bluetooth #3
Favicon
The Complete Guide to Bash Commands
Favicon
How to Get Started with Bash Scripting for Automation
Favicon
Building a Basic Testing Framework in Bash 🐚
Favicon
Funny how, as I was writing this, I started wondering—could we make this pipeline even smarter? That’s when SonarQube came to mind. But can it even work with Bash scripts? I’d love to hear your thoughts!
Favicon
Domina Bash con ejemplos prácticos de Git
Favicon
Explaining Null Device or Black Hole Register in Vim
Favicon
A Media Server on Steroids - Walkthrough
Favicon
From FZF file preview to a browser for cht.sh to discovering the ideal solution
Favicon
Code. Battery notifier.
Favicon
🌟Simplifying User Account Management with Bash Scripting Day3🌟
Favicon
Become a Bash Scripting Pro in 10 Minutes: A Quick Guide for Beginners
Favicon
Automatically Monitor and Manage RAM Usage for Next.js Development
Favicon
Bash Script - Task Management
Favicon
Bash Your Tools
Favicon
Bash Script Series: Automating Log Analysis with Bash Script or Shell Script
Favicon
The Most Interesting Mostly Tech Reads of 2024
Favicon
🚀 Automating Process Monitoring & Restarting with Bash Scripting Day4! 🔧
Favicon
🚀 RazzShell v1.0.1 is Here: Plugin Support, Enhanced Job Management, and More! 🌟
Favicon
Step-by-Step Guide: Assigning a Namecheap Domain to DigitalOcean Hosting with Nginx
Favicon
Simplify GitHub Workflow Management with My-GitHub-Manager
Favicon
How to play a bunch of lemmings

Featured ones: