#!/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=()

# initialize the deck
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[@]} == 0 && ${#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
