added Scoundrel port
This commit is contained in:
@@ -6,7 +6,8 @@ For POSIX shell compatible scripts, see the [sh-goodies](https://codeberg.org/lu
|
||||
|
||||
## List
|
||||
|
||||
* [bmux](./bmux): a simple, dmux-like session manager in Bash on top of just dtach
|
||||
* [YouStore](./ys): a way to securely store any set of files/directories inside a video
|
||||
* [1DLife](./1dlife): Jon Millen's 1D Game of Life in pure Bash
|
||||
* [Elem](./elem): Stephen Wolfram's elementary cellular automatons in pure Bash
|
||||
* [bmux](./bmux): a simple, dmux-like session manager in Bash on top of just dtach
|
||||
* [Scoundrel](./scoundrel): A Bash port of the Scoundrel roguelike solitaire game
|
||||
|
||||
@@ -0,0 +1,164 @@
|
||||
#!/usr/bin/env bash
|
||||
# SHoundrel: a Bash version of Scoundrel roguelike solitaire
|
||||
# Created by Luxferre in 2026, released into public domain
|
||||
|
||||
# helpers
|
||||
|
||||
get_choice() {
|
||||
local c
|
||||
read -r -p "$1" -n 1 c
|
||||
printf '%s' "${c@L}"
|
||||
}
|
||||
|
||||
get_valid_choice() {
|
||||
local pr="$1" vcs="$2" c="_"
|
||||
until [[ "$vcs" == *$c* ]]; do
|
||||
c="$(get_choice "$pr")"
|
||||
done
|
||||
echo $c
|
||||
}
|
||||
|
||||
# variables and states
|
||||
|
||||
declare -i score=-208 hp=20 can_run=1 engaged=0 drank=0 \
|
||||
weapon=0 durability=0 rooms_clrd=0 last_potion_val=0
|
||||
declare -a deck room=()
|
||||
mapfile -t deck < <(shuf -e {1..13} {1..31})
|
||||
|
||||
# game logic functions
|
||||
|
||||
game_field_display() {
|
||||
local -i x
|
||||
echo '--------------------------'
|
||||
printf 'H%02d | W%02d | D%02d | Deck: %02d\n' $hp $weapon $durability ${#deck[@]}
|
||||
echo '--------------------------'
|
||||
for x in "${room[@]}"; do
|
||||
if ((x < 14)); then
|
||||
printf 'M%02d ' $((x + 1))
|
||||
elif ((x < 23)); then
|
||||
printf 'W%02d ' $((x - 12))
|
||||
else
|
||||
printf 'H%02d ' $((x - 21))
|
||||
fi
|
||||
done
|
||||
printf '\n %s' '1 2 3 4'
|
||||
if ((can_run && !engaged)); then
|
||||
printf '%s' ' r)un->'
|
||||
fi
|
||||
echo
|
||||
}
|
||||
|
||||
# monster handling logic (adds monster value to the score)
|
||||
handle_monster() {
|
||||
local -i val="$1" healthlost="$1"
|
||||
printf 'You encounter a monster of strength %d.\n' $val
|
||||
if ((weapon > 0 && durability >= val)); then # can use weapon
|
||||
if [[ "$(get_valid_choice 'Use weapon? (y/n) ' 'yn')" = 'y' ]]; then
|
||||
healthlost=$((val - weapon))
|
||||
((healthlost < 0)) && healthlost=0
|
||||
printf '\nYou fight the monster with your %d-level weapon.\n' $weapon
|
||||
durability=$((val - 1))
|
||||
if ((durability < 2)); then
|
||||
durability=0
|
||||
weapon=0
|
||||
echo 'Your weapon fully breaks!'
|
||||
fi
|
||||
else # barehanded encounter
|
||||
printf '\nYou fight the monster barehanded.\n'
|
||||
fi
|
||||
else # barehanded encounter
|
||||
printf '\nYou fight the monster barehanded.\n'
|
||||
fi
|
||||
((hp -= healthlost))
|
||||
((hp < 0)) && hp=0
|
||||
printf 'Lost %d HP. New HP: %d\n' $healthlost $hp
|
||||
((score += val))
|
||||
}
|
||||
|
||||
# weapon handling logic
|
||||
handle_weapon() {
|
||||
weapon="$1"
|
||||
durability=14
|
||||
printf 'Equipped a %d-level weapon.\n' $weapon
|
||||
}
|
||||
|
||||
# potion handling logic
|
||||
handle_potion() {
|
||||
if ((drank > 0)); then
|
||||
echo 'Already drank a potion here! Discarding...'
|
||||
else
|
||||
local -i val="$1"
|
||||
((${#room[@]} == 1 && ${#deck[@]} == 0)) && last_potion_val=$val
|
||||
((hp += val))
|
||||
((hp > 20)) && hp=20
|
||||
drank=1
|
||||
printf 'Drank a %d-level potion. New HP: %d\n' $val $hp
|
||||
fi
|
||||
}
|
||||
|
||||
# main game loop
|
||||
declare choice
|
||||
declare -i item idx
|
||||
|
||||
echo '----- Scoundrel 2026 -----'
|
||||
echo ' Bash port by Luxferre'
|
||||
echo ' Good luck!'
|
||||
|
||||
while (( (${#deck[@]} + ${#room[@]}) > 0 && hp > 0 )); do
|
||||
if (( !engaged )); then # build the room
|
||||
while (( ${#deck[@]} > 0 && ${#room[@]} < 4 )); do
|
||||
room+=("${deck[0]}")
|
||||
unset 'deck[0]'
|
||||
deck=("${deck[@]}")
|
||||
done
|
||||
fi
|
||||
game_field_display
|
||||
if ((can_run == 1 && engaged == 0)); then
|
||||
choice=$(get_valid_choice 'Your choice: ' '1234r')
|
||||
else
|
||||
choice=$(get_valid_choice 'Your choice: ' '1234')
|
||||
fi
|
||||
echo
|
||||
if [[ "$choice" = 'r' ]] ; then # running logic
|
||||
can_run=0 # cannot run twice in a row
|
||||
while (( ${#room[@]} > 0 )); do
|
||||
idx=$((RANDOM % ${#room[@]}))
|
||||
deck+=("${room[$idx]}")
|
||||
unset 'room[idx]'
|
||||
room=("${room[@]}")
|
||||
done
|
||||
echo 'You run from the room.'
|
||||
else # engagement logic
|
||||
((-- choice))
|
||||
item=${room[$choice]}
|
||||
if ((item > 0)); then
|
||||
engaged=1
|
||||
unset 'room[choice]'
|
||||
room=("${room[@]}")
|
||||
if ((item < 14)); then
|
||||
handle_monster $((item + 1))
|
||||
elif ((item < 23)); then
|
||||
handle_weapon $((item - 12))
|
||||
else
|
||||
handle_potion $((item - 21))
|
||||
fi
|
||||
if (( ${#deck[@]} > 0 && ${#room[@]} == 1 )); then
|
||||
can_run=1
|
||||
engaged=0
|
||||
drank=0
|
||||
((++ rooms_clrd))
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
# now score and output the game result
|
||||
if ((hp > 0)); then
|
||||
score=$hp
|
||||
((hp == 20)) && ((score += last_potion_val))
|
||||
((++ rooms_clrd))
|
||||
printf 'You win! '
|
||||
else
|
||||
printf 'You lose! '
|
||||
fi
|
||||
printf 'Your score: %d. Rooms cleared: %d\n' $score $rooms_clrd
|
||||
Reference in New Issue
Block a user