grimoire/bash/roller

116 lines
2.1 KiB
Bash
Executable file

#!/usr/bin/env bash
die() {
printf "invalid roll: $1\n" "${@:2}" >&2
exit 1
}
debug() {
if [[ -v opts[debug] ]]; then
printf "DEBUG: $1\n" "${@:2}"
fi
}
verbose() {
if [[ -v opts[verbose] ]]; then
printf "$1\n" "${@:2}"
fi
}
is_integer() {
if (( $# )); then
[[ $1 =~ ^[0-9]+$ ]]
else
return 1
fi
}
roll_die() {
if (( $# )); then
printf %d "$(( (RANDOM % $1) + 1 ))"
else
printf 0
fi
}
declare -A opts
while (( $# )); do
case $1 in
-v)
opts[verbose]=1
;;
-d)
opts[debug]=1
;;
-x)
set -x
;;
-*)
die "unknown option '%s'" "$1"
;;
*)
break
esac
shift
done
if (( $# )); then
IFS=d read -r quantity rest <<< "$1"
if [[ -z $quantity ]]; then
quantity=1
elif ! is_integer "$quantity"; then
die "dice quantity is not a number"
fi
debug "quantity of dice is %d" "$quantity"
while (( ${#rest} )) && [[ ${rest:0:1} != @(+|-) ]]; do
sides+=${rest:0:1} rest=${rest:1}
done
if ! is_integer "$sides"; then
die "not a good number of die sides"
fi
debug "die has %d side(s)" "$sides"
total_mod=0
while (( ${#rest} )); do
mod_type=${rest:0:1} rest=${rest:1} next_mod=
while [[ -n $rest && ${rest:0:1} != @(+|-) ]]; do
next_mod+=${rest:0:1} rest=${rest:1}
done
if ! is_integer "$next_mod"; then
die "'%s' is not a proper modifier" "$next_mod"
elif [[ $mod_type = + ]]; then
(( total_mod += next_mod ))
debug "adding %d to modifier for a total of %d" "$next_mod" "$total_mod"
else
(( total_mod -= next_mod ))
debug "subtracting %d from modifier for a total of %d" "$next_mod" "$total_mod"
fi
done
score=0 count=0
while (( quantity-- )); do
roll=$(roll_die "$sides")
(( score += roll ))
debug "rolled a %d. score is now %d" "$roll" "$score"
verbose "roll %d: %d" "$(( count++ ))" "$roll"
done
verbose "score before modifier: %d" "$score"
(( score += total_mod ))
verbose "score after modifier: %d" "$score"
debug "score total after modifier is %d" "$score"
if [[ ! -v opts[verbose] ]]; then
printf '%d\n' "$score"
fi
fi