#!/bin/bash # Defaults FEAT_COUNT=1 SUCCESS_COUNT=0 ROLL_MODE="" # adv, disadv, or empty BONUS_VALUE=0 # bonus/debuff value # Macro configuration MACRO_FILE="$HOME/.tor-roller-macros" # Help function show_help() { echo "Usage: $0 [FEAT_DICE] [SUCCESS_DICE] [OPTIONS]" echo "" echo "Arguments:" echo " FEAT_DICE Number of 1d12 Feat Dice to roll (default: 1)" echo " SUCCESS_DICE Number of 1d6 Success Dice to roll (default: 0)" echo "" echo "Options:" echo " -h, --help Show this help message" echo " macro Use a saved macro (see --macro-help)" echo "" echo "Examples:" echo " $0 # Rolls 1 Feat Die" echo " $0 1 3 # Rolls 1 Feat Die and 3 Success Dice" echo " $0 2 0 # Rolls 2 Feat Dice" echo "" echo "Macro Examples:" echo " $0 --macro-help # Show macro usage" echo " $0 --save-macro hero 1 3 # Save macro named 'hero' with 1d12+3d6" echo " $0 --save-macro attack 2 4 adv # Save with advantage" echo " $0 --save-macro spell 1 2 disadv # Save with disadvantage" echo " $0 --save-macro skill 1 2 +5 # Save with +5 bonus" echo " $0 --list-macros # List all saved macros" echo " $0 hero # Use saved macro" exit 0 } # Show macro help show_macro_help() { echo "Macro Usage:" echo "" echo "Save Macros:" echo " --save-macro NAME FEAT_DICE SUCCESS_DICE [ADV|DISADV] [BONUS]" echo " NAME: Name for the macro" echo " FEAT_DICE: Number of d12 dice (1-99)" echo " SUCCESS_DICE: Number of d6 dice (0-99)" echo " ADV: Advantage (roll 2 sets, keep highest)" echo " DISADV: Disadvantage (roll 2 sets, drop highest)" echo " BONUS: Bonus/debuff value (+5, -3, etc.)" echo "" echo "Examples:" echo " $0 --save-macro hero 1 3" echo " $0 --save-macro attack 2 4 adv" echo " $0 --save-macro spell 1 2 disadv" echo " $0 --save-macro skill 1 2 +5" echo "" echo "Use Macros:" echo " $0 MACRO_NAME" echo "" echo "List Macros:" echo " $0 --list-macros" echo "" echo "Delete Macros:" echo " $0 --delete-macro MACRO_NAME" echo "" exit 0 } # Save a macro save_macro() { local name="$1" local feat="$2" local success="$3" local mode="$4" local bonus="$5" # Validate inputs if [[ ! "$feat" =~ ^[0-9]+$ ]] || [ "$feat" -lt 1 ] || [ "$feat" -gt 99 ]; then echo "Error: FEAT_DICE must be a number between 1 and 99" exit 1 fi if [[ ! "$success" =~ ^[0-9]+$ ]] || [ "$success" -gt 99 ]; then echo "Error: SUCCESS_DICE must be a number between 0 and 99" exit 1 fi # Handle mode and bonus arguments if [[ "$mode" == "adv" ]] || [[ "$mode" == "ADV" ]]; then mode="adv" bonus="$5" elif [[ "$mode" == "disadv" ]] || [[ "$mode" == "DISADV" ]]; then mode="disadv" bonus="$5" elif [[ "$mode" =~ ^[+-]?[0-9]+$ ]]; then # This is a bonus, mode is empty mode="" bonus="$4" # bonus is in the mode position else mode="" bonus="$4" # bonus is in the mode position if provided fi # Validate bonus if provided if [[ "$bonus" != "" ]] && [[ "$bonus" != "0" ]] && [[ ! "$bonus" =~ ^[+-]?[0-9]+$ ]]; then echo "Error: BONUS must be a number with + or - (e.g., +5, -3)" exit 1 fi # If bonus is empty or not a number, set to 0 if [[ "$bonus" == "" ]] || [[ ! "$bonus" =~ ^[+-]?[0-9]+$ ]]; then bonus="0" fi # Create macro entry local entry="$name|$feat|$success|$mode|$bonus" # Create directory if it doesn't exist mkdir -p "$(dirname "$MACRO_FILE")" # Remove existing macro with same name if [ -f "$MACRO_FILE" ]; then grep -v "^$name|" "$MACRO_FILE" > "${MACRO_FILE}.tmp" 2>/dev/null || true mv "${MACRO_FILE}.tmp" "$MACRO_FILE" fi # Add new macro echo "$entry" >> "$MACRO_FILE" echo "Macro '$name' saved successfully!" echo " Feat Dice: $feat d12, Success Dice: $success d6" if [[ "$mode" == "adv" ]]; then echo " Mode: Advantage" elif [[ "$mode" == "disadv" ]]; then echo " Mode: Disadvantage" fi if [[ "$bonus" != "0" ]]; then echo " Bonus: $bonus" fi exit 0 } # List all macros list_macros() { echo "Saved Macros:" echo "" if [ ! -f "$MACRO_FILE" ]; then echo "No macros saved yet." echo "" echo "Use --save-macro to create a macro, or --macro-help for examples." exit 0 fi printf "%-20s %-10s %-12s %-12s %s\n" "NAME" "FEAT_DICE" "SUCCESS_DICE" "MODE" "BONUS" printf "%-20s %-10s %-12s %-12s %s\n" "----" "---------" "------------" "----" "-----" while IFS='|' read -r name feat success mode bonus; do local mode_display="${mode:-(none)}" local bonus_display="$bonus" if [[ "$bonus" == "0" ]]; then bonus_display="(none)" fi printf "%-20s %-10s %-12s %-12s %s\n" "$name" "${feat}d12" "${success}d6" "$mode_display" "$bonus_display" done < "$MACRO_FILE" exit 0 } # Delete a macro delete_macro() { local name="$1" if [ ! -f "$MACRO_FILE" ]; then echo "No macros saved yet." exit 1 fi if ! grep -q "^$name|" "$MACRO_FILE"; then echo "Macro '$name' not found." exit 1 fi # Remove the macro grep -v "^$name|" "$MACRO_FILE" > "${MACRO_FILE}.tmp" mv "${MACRO_FILE}.tmp" "$MACRO_FILE" echo "Macro '$name' deleted successfully!" exit 0 } # Load and execute a macro load_macro() { local name="$1" if [ ! -f "$MACRO_FILE" ]; then echo "No macros saved yet. Use --save-macro to create one." exit 1 fi local macro_data=$(grep "^$name|" "$MACRO_FILE") if [ -z "$macro_data" ]; then echo "Macro '$name' not found. Use --list-macros to see available macros." exit 1 fi # Parse macro data IFS='|' read -r macro_name feat success mode bonus <<< "$macro_data" echo "Using macro: $name" echo "" # Set global variables for rolling FEAT_COUNT=$feat SUCCESS_COUNT=$success ROLL_MODE=$mode BONUS_VALUE=$bonus } # Check for help flag if [[ "$1" == "-h" || "$1" == "--help" ]]; then show_help fi # Check for macro commands if [[ "$1" == "--macro-help" ]]; then show_macro_help elif [[ "$1" == "--save-macro" ]]; then if [ "$#" -lt 4 ]; then echo "Error: --save-macro requires NAME FEAT_DICE SUCCESS_DICE" echo "Use --macro-help for examples" exit 1 fi save_macro "$2" "$3" "$4" "$5" "$6" elif [[ "$1" == "--list-macros" ]]; then list_macros elif [[ "$1" == "--delete-macro" ]]; then if [ "$#" -lt 2 ]; then echo "Error: --delete-macro requires MACRO_NAME" exit 1 fi delete_macro "$2" fi # Check if using a saved macro if [ "$#" -eq 1 ] && [ "$1" != "" ]; then # Check if it's a macro name (not numeric) if ! [[ "$1" =~ ^[0-9]+$ ]]; then load_macro "$1" # Macro will set FEAT_COUNT, SUCCESS_COUNT, etc. else FEAT_COUNT=$1 fi elif [[ "$1" =~ ^[0-9]+$ ]]; then FEAT_COUNT=$1 if [[ "$2" =~ ^[0-9]+$ ]]; then SUCCESS_COUNT=$2 fi fi # Colors and formatting BOLD='\033[1m' RED='\033[31m' GREEN='\033[32m' CYAN='\033[36m' # Using Cyan for Gandalf as it's bright/distinct RESET='\033[0m' # Function to generate a random number between 1 and max roll() { local max=$1 # Read 2 bytes from /dev/urandom, convert to decimal, modulo max, add 1 # This provides better randomness than $RANDOM val=$(od -An -N2 -tu2 /dev/urandom) echo $(( (val % max) + 1 )) } gum spin --spinner moon --title "🔮 Consulting Palantir..." -- sleep 1 echo "" # Display macro name if using one if [ -n "$macro_name" ]; then if [[ "$ROLL_MODE" == "adv" ]]; then echo "Mode: Advantage (roll 2 sets, keep highest)" elif [[ "$ROLL_MODE" == "disadv" ]]; then echo "Mode: Disadvantage (roll 2 sets, drop highest)" fi if [[ "$BONUS_VALUE" != "0" ]]; then if [[ "$BONUS_VALUE" =~ ^- ]]; then echo "Effect: $BONUS_VALUE (debuff)" else echo "Effect: $BONUS_VALUE (bonus)" fi fi echo "" fi TOTAL=0 # Roll Feat Dice (1d12) if [ "$FEAT_COUNT" -gt 0 ]; then echo -n -e "Feat Dice (${FEAT_COUNT}d12 ): " # Handle advantage/disadvantage for Feat Dice if [[ "$ROLL_MODE" == "adv" ]]; then echo -n "Set 1: " total_set1=0 for ((i=0; i