#!/bin/bash
#
# Source is released to public domain.
#
# Based on tables in:
# 'Warhammer Fantasy Roleplay: A Grim World of Perilous Adventure' (2nd Ed.)
# Fantasy Flight Games / Games Workshop (2005)
#
# TODO
# - specific talents and equipment for career (lots of them, Ch. 3)
# - distinguishing characteristics, height/weight, etc from tables in Ch. 2
# - extend dice roller so as to handle stuff like '1d20*5+30' (elf's age)
roll () {
local -i N=1 D=6 M=0 R=0;
if [[ "$1" =~ ^([1-9][0-9]*)d([1-9][0-9]*)$ ]]; then
N=${BASH_REMATCH[1]}
D=${BASH_REMATCH[2]}
elif [[ "$1" =~ ^([1-9][0-9]*)d([1-9][0-9]*)\+([0-9]+)$ ]]; then
N=${BASH_REMATCH[1]}
D=${BASH_REMATCH[2]}
M=${BASH_REMATCH[3]}
elif [[ "$1" =~ ^([0-9]+)\+([1-9][0-9]*)d([1-9][0-9]*)$ ]]; then
N=${BASH_REMATCH[2]}
D=${BASH_REMATCH[3]}
M=${BASH_REMATCH[1]}
elif [[ "$1" =~ ^([1-9][0-9]*)d([1-9][0-9]*)-([0-9]+)$ ]]; then
N=${BASH_REMATCH[1]}
D=${BASH_REMATCH[2]}
M=-${BASH_REMATCH[3]};
elif [[ "$1" =~ ^[1-9][0-9]*$ ]]; then
N=${BASH_REMATCH[1]};
D=6;
fi
while (($N)); do
R=$(($R+($RANDOM*$D/32768)+1));
N=$(($N-1));
done
echo $(($R+$M))
}
roll-table () {
local N n T
N=$1
T=$2
n=$(roll $N)
for x in $(eval echo \${!$T[*]}); do
if [[ $x -ge ${n} ]]; then
echo $(eval echo \${$T[$x]})
return
fi
done
}
TableHumanBirthplace=(
[10]=Averland
[20]=Hochland
[30]=Middenland
[40]=Nordland
[50]=Ostermark
[60]=Ostland
[70]=Reikland
[80]=Stirland
[90]=Talabecland
[100]=Wissenland
)
TableHumanBirthplaceType=(
[10]="a city"
[20]="a prosperous town"
[30]="a market town"
[40]="a fortified town"
[50]="a farming village"
[60]="a poor village"
[70]="a small settlement"
[80]="a pig/cattle farm"
[90]="an arable farm"
[100]="a hovel"
)
TableDwarfBirthplace=(
[30]="human"
[40]="Karak Norn (Grey Mountains)"
[50]="Karak Izor (the Vaults)"
[60]="Karak Hirn (Black Mountains)"
[70]="Karak Kadrin (World's Edge Mountains)"
[80]="Karaz-A-Karak (World's Edge Mountains)"
[90]="Zhufbar (World's Edge Mountains)"
[100]="Barak Varr (the Black Gulf)"
)
TableElfBirthplace=(
[20]=Altdorf
[40]=Marienburg
[70]="Laurelorn Forest"
[85]="The Great Forest"
[100]="Reikwald Forest"
)
TableHalflingBirthplace=(
[50]="the Moot"
[100]="human"
)
TableSex=(
[1]="Female"
[2]="Male"
)
TableCareerDwarf=(
[2]="Agitator"
[6]="Bodyguard"
[10]="Burgher"
[12]="Coachman"
[15]="Entertainer"
[19]="Hunter"
[23]="Jailer"
[24]="Marine"
[30]="Merchant"
[34]="Militiaman"
[40]="Miner"
[42]="Noble"
[45]="Outlaw"
[50]="Pit Fighter"
[54]="Protagonist"
[58]="Rat Catcher"
[63]="Runebearer"
[65]="Scribe"
[66]="Seaman"
[68]="Servant"
[72]="Shieldbreaker"
[75]="Smuggler"
[79]="Soldier"
[81]="Student"
[84]="Thief"
[87]="Toll Keeper"
[90]="Tomb Robber"
[94]="Tradesman"
[98]="Troll Slayer"
[100]="Watchman"
)
TableCareerElf=(
[7]="Apprentice Wizard"
[12]="Entertainer"
[19]="Envoy"
[27]="Hunter"
[34]="Kithband Warrior"
[39]="Mercenary"
[45]="Messenger"
[51]="Outlaw"
[57]="Outrider"
[63]="Rogue"
[69]="Scribe"
[75]="Seaman"
[80]="Student"
[86]="Thief"
[93]="Tradesman"
[100]="Vagabon"
)
TableCareerHalfling=(
[3]="Agitator"
[4]="Barber-Surgeon"
[5]="Bone Picker"
[7]="Bounty Hunter"
[9]="Burgher"
[11]="Camp Follower"
[14]="Charcoal Burner"
[17]="Entertainer"
[18]="Ferryman"
[22]="Fieldwarden"
[23]="Fisherman"
[26]="Grave Robber"
[31]="Hunter"
[35]="Mercenary"
[40]="Messenger"
[45]="Militiaman"
[48]="Outlaw"
[54]="Peasant"
[55]="Rat Catcher"
[60]="Rogue"
[65]="Servant"
[68]="Smuggler"
[70]="Soldier"
[72]="Student"
[78]="Thief"
[80]="Toll Keeper"
[85]="Tomb Raider"
[90]="Tradesman"
[94]="Vaganod"
[96]="Valet"
[100]="Watchman"
)
TableCareerHuman=(
[2]="Agitator"
[4]="Apprentice Wizard"
[5]="Bailiff"
[6]="Barber-Surgeon"
[8]="Boatman"
[10]="Bodyguard"
[12]="Bone Picker"
[14]="Bounty Hunter"
[16]="Burgher"
[18]="Camp Follower"
[20]="Charcoal Burner"
[22]="Coachman"
[24]="Entertainer"
[25]="Estalian Diestro"
[26]="Ferryman"
[28]="Fisherman"
[30]="GraveRobber"
[31]="HedgeWizard"
[33]="Hunter"
[35]="Initiate"
[36]="Jailer"
[37]="Kislevite Kossar"
[39]="Marine"
[41]="Mercenary"
[43]="Messenger"
[45]="Militiaman"
[47]="Miner"
[49]="Noble"
[50]="Norse Berserker"
[52]="Outlaw"
[54]="Outrider"
[56]="Peasant"
[58]="Pit Fighter"
[60]="Protagonist"
[62]="Rat Catcher"
[64]="Roadwarden"
[66]="Rogue"
[68]="Scribe"
[70]="Seaman"
[72]="Servant"
[74]="Smuggler"
[76]="Soldier"
[78]="Squire"
[80]="Student"
[82]="Thief"
[84]="Thug"
[86]="Toll Keeper"
[88]="Tomb Robber"
[90]="Tradaesman"
[92]="Vagabond"
[94]="Valet"
[96]="Watchman"
[98]="Woodsman"
[100]="Zealot"
)
make-halfling ()
{
local -i WS BS S T Ag Int Fel W M SB TB W FP
declare Career
WS=$(roll 20+2d10)
BS=$(roll 20+2d10)
S=$(roll 20+2d10)
T=$(roll 20+2d10)
Ag=$(roll 20+2d10)
Int=$(roll 20+2d10)
WP=$(roll 20+2d10)
Fel=$(roll 20+$2d10)
M=4
SB=$(($S/10))
TB=$(($T/10))
Career=$(roll-table 1d100 TableCareerHalfling)
Age=$((20+($(roll 1d20)*5)))
Origin=$(roll-table 1d100 TableHalflingBirthplace)
if [ "$Origin" == "human" ]; then
Origin=$(roll-table 1d100 TableHumanBirthplace)
fi
TableName=(
[1]=Agnes,Adam
[2]=Alice,Albert
[3]=Elena,Alfred
[4]=Eva,Axel
[5]=Frida,Carl
[6]=Greta,Edgar
[7]=Hanna,Hugo
[8]=Heidi,Jakob
[9]=Hilda,Ludo
[10]=Janna,Max
[11]=Karin,Niklaus
[12]=Leni,Oskar
[13]=Marie,Paul
[14]=Petra,Ralf
[15]=Silma,Rudi
[16]=Sophia,Theo
[17]=Susi,Thomas
[18]=Theda,Udo
[19]=Ulla,Viktor
[20]=Wanda,Walter
)
Sex=$(roll 1d2)
if [ -z "$Name" ]; then
Name=$(roll-table 1d20 TableName | cut -f$Sex -d,)
fi
TableHalflingWounds=(
[3]=8
[6]=9
[9]=10
[10]=11
)
W=$(roll-table 1d10 TableHalflingWounds)
FP=$(roll-table 1d10 TableHalflingFate)
TableHalflingFP=(
[7]=2
[10]=3
)
FP=$(roll-table 1d10 TableHalflingFate)
halfling-talent () {
TableHalflingTalent=(
[1]="Acute Hearing"
[6]="Ambidextrous"
[11]="Coolheaded"
[16]="Excellent Vision"
[21]="Fleet Footed"
[26]="Hardy"
[30]="Lightning Reflexes"
[34]="Luck"
[42]="Marksman"
[47]="Mimic"
[51]="Resistance to Disease"
[52]="Resistance to Magic"
[54]="Resistance to Poison"
[58]="Savvy"
[63]="Sixth Sense"
[68]="Strong Minded"
[73]="Sturdy"
[78]="Suave"
[83]="Super Numerate"
[88]="Very Resilient"
[92]="Very Strong"
[100]="Warrior Born"
)
roll-table 1d100 TableHalflingTalent
}
cat <<EOF
$Name the Halfling $Career
$Age years old, from $Origin
WS BS S T Ag Int WP Fel
$(printf "%3d%3d%3d%3d%3d%4d%3d%4d" $WS $BS $S $T $Ag $Int $WP $Fel)
A W SB TB M Mag IP FP
$(printf "%3d%3d%3d%3d%3d%4d%3d $FP" $A $W $SB $TB $M $Mag $IP $FP)
Skills: Academic Knowledge (Geneaology/Heraldry)
Common Knowledge (Halflings)
Gossip
Speak Language (Halfling)
Speak Language (Reikspiel)
Trade (Cook or Farmer)
Talents: Night Vision
Resistance to Chaos
Specialist Weapon (Sling)
$(halfling-talent)
EOF
}
make-elf ()
{
local -i WS BS S T Ag Int Fel W M SB TB W FP
declare Career
WS=$(roll 20+2d10)
BS=$(roll 20+2d10)
S=$(roll 20+2d10)
T=$(roll 20+2d10)
Ag=$(roll 20+2d10)
Int=$(roll 20+2d10)
WP=$(roll 20+2d10)
Fel=$(roll 20+$2d10)
W=$(roll 1d10)
M=5
SB=$(($S/10))
TB=$(($T/10))
Career=$(roll-table 1d100 TableCareerElf)
Age=$((30+($(roll 1d20)*5)))
Origin=$(roll-table 1d100 TableElfBirthplace)
if [ "$Origin" == "human" ]; then
Origin=$(roll-table 1d100 TableHumanBirthplace)
fi
TableElfWounds=(
[3]=9
[6]=10
[9]=11
[10]=12
)
TableElfFP=(
[4]=1
[10]=2
)
W=$(roll-table 1d10 TableElfWounds)
FP=$(roll-table 1d10 TableElfFP)
TableName=(
[1]=Alane,Aluthol
[2]=Altronia,Amendil
[3]=Davandrel,Angran
[4]=Eldril,Cavindel
[5]=Eponia,Dolwen
[6]=Fanriel,Eldillor
[7]=Filamir,Falandar
[8]=Gallina,Farnoth
[9]=Halion,Gildiril
[10]=Iludil,Harrond
[11]=Ionor,Imhol
[12]=Lindara,Larandar
[13]=Lorandara,Laurenor
[14]=Maruviel,Mellion
[15]=Pelgrana,Mormacar
[16]=Siluvaine,Ravandil
[17]=Tallana,Torendil
[18]=Ulliana,Urdithane
[19]=Vivandrel,Valahuir
[20]=Yuviel,Yavandir
)
Sex=$(roll 1d2)
if [ -z "$Name" ]; then
Name=$(roll-table 1d20 TableName | cut -f$Sex -d,)
fi
cat <<EOF
$Name the Elven $Career
$Age years old, from $Origin
WS BS S T Ag Int WP Fel
$(printf "%3d%3d%3d%3d%3d%4d%3d%4d" $WS $BS $S $T $Ag $Int $WP $Fel)
A W SB TB M Mag IP FP
$(printf "%3d%3d%3d%3d%3d%4d%3d $FP" $A $W $SB $TB $M $Mag $IP $FP)
Skills: Common Knowledge (Elves)
Speak Language (Eltharin)
Speak Language (Reikspiel)
Talents: Aethyric Attunement -OR- Specialist Weapon (Longbow)
Coolheaded -OR Savvy
Excellent Vision
Night Vision
EOF
}
make-human ()
{
local -i WS BS S T Ag Int Fel W M SB TB W FP
declare Career
WS=$(roll 20+2d10)
BS=$(roll 20+2d10)
S=$(roll 20+2d10)
T=$(roll 20+2d10)
Ag=$(roll 20+2d10)
Int=$(roll 20+2d10)
WP=$(roll 20+2d10)
Fel=$(roll 20+$2d10)
W=$(roll 1d10)
M=4
SB=$(($S/10))
TB=$(($T/10))
Career=$(roll-table 1d100 TableCareerHuman)
Age=$(roll 15+1d20)
Origin=$(roll-table 1d100 TableHumanBirthplace)
OriginType=$(roll-table 1d100 TableHumanBirthplaceType)
TableHumanWounds=(
[3]=10
[6]=11
[9]=12
[10]=3
)
TableHumanFP=(
[7]=2
[10]=3
)
W=$(roll-table 1d10 TableHumanWounds)
FP=$(roll-table 1d10 TableHumanFP)
TableName=(
[1]=Alexa,Adelbert
[2]=Alfrida,Albrecht
[3]=Beatrix,Berthold
[4]=Bianka,Dieter
[5]=Carlott,Eckhart
[6]=Elfrida,Felix
[7]=Elise,Gottfried
[8]=Gabrielle,Gustav
[9]=Gretchen,Heinz
[10]=Hanna,Johann
[11]=Ilsa,Konrad
[12]=Klara,Leopold
[13]=Jarla,Magnus
[14]=Ludmilla,Otto
[15]=Mathilde,Pieter
[16]=Regina,Rudiger
[17]=Solveig,Siegfried
[18]=Theodora,Ulrich
[19]=Ulrike,Waldemar
[20]=Wertha,Wolfgang
)
Sex=$(roll 1d2)
if [ -z "$Name" ]; then
Name=$(roll-table 1d20 TableName | cut -f$Sex -d,)
fi
human-talent () {
TableHumanTalent=(
[4]="Acute Hearing"
[9]="Ambidextrous"
[13]="Coolheaded"
[18]="Excellent Vision"
[20]="Fleet Footed"
[21]="Hardy"
[31]="Lightning Reflexes"
[35]="Luck"
[40]="Marksman"
[44]="Mimic"
[49]="Night Vision"
[53]="Resistance to Disease"
[57]="Resistance to Magic"
[61]="Resistance to Poison"
[66]="Savvy"
[71]="Sixth Sense"
[75]="Strong Minded"
[79]="Sturdy"
[83]="Suave"
[87]="Super Numerate"
[91]="Very Resilient"
[95]="Very Strong"
[100]="Warrior Born"
)
roll-table 1d100 TableHumanTalent
}
cat <<EOF
$Name the Human $Career
$Age years old, from $OriginType in $Origin
WS BS S T Ag Int WP Fel
$(printf "%3d%3d%3d%3d%3d%4d%3d%4d" $WS $BS $S $T $Ag $Int $WP $Fel)
A W SB TB M Mag IP FP
$(printf "%3d%3d%3d%3d%3d%4d%3d $FP" $A $W $SB $TB $M $Mag $IP $FP)
Skills: Common Knowledge (the Empire)
Gossip
Speak Language (Reikspiel)
Talents: $(human-talent)
$(human-talent)
EOF
}
make-dwarf ()
{
local -i WS BS S T Ag Int Fel W M SB TB W FP
declare Career
WS=$(roll 30+2d10)
BS=$(roll 20+2d10)
S=$(roll 20+2d10)
T=$(roll 30+2d10)
Ag=$(roll 10+2d10)
Int=$(roll 20+2d10)
WP=$(roll 20+2d10)
Fel=$(roll 10+$2d10)
W=$(roll 1d10)
M=3
SB=$(($S/10))
TB=$(($T/10))
Career=$(roll-table 1d100 TableCareerDwarf)
Age=$((20+($(roll 1d20)*5)))
Origin=$(roll-table 1d100 TableDwarfBirthplace)
if [ "$Origin" == "human" ]; then
Origin=$(roll-table 1d100 TableHumanBirthplace)
fi
TableDwarfWounds=(
[3]=11
[6]=12
[9]=13
[10]=14
)
TableDwarfFP=(
[4]=1
[7]=2
[10]=3
)
W=$(roll-table 1d10 TableDwarfWounds)
FP=$(roll-table 1d10 TableDwarfFP)
TableName=(
[1]=Anika,Bardin
[2]=Asta,Brokk
[3]=Astrid,Dimzad
[4]=Berta,Durak
[5]=Birgit,Garil
[6]=Dagmar,Gottri
[7]=Elsa,Grundi
[8]=Erika,Hargin
[9]=Franziska,Imrak
[10]=Greta,Kargun
[11]=Hunni,Jotunn
[12]=Ingrid,Magnar
[13]=Janna,Mordrin
[14]=Karin,Nargond
[15]=Petra,Orzad
[16]=Sigrid,Ragnar
[17]=Sigrun,Snorri
[18]=Silma,Storri
[19]=Thylda,Thingrim
[20]=Ulla,Urgrim
)
Sex=$(roll 1d2)
if [ -z "$Name" ]; then
Name=$(roll-table 1d20 TableName | cut -f$Sex -d,)
fi
cat <<EOF
$Name the Dwarfish $Career
$Age years old, from $Origin
WS BS S T Ag Int WP Fel
$(printf "%3d%3d%3d%3d%3d%4d%3d%4d" $WS $BS $S $T $Ag $Int $WP $Fel)
A W SB TB M Mag IP FP
$(printf "%3d%3d%3d%3d%3d%4d%3d $FP" $A $W $SB $TB $M $Mag $IP $FP)
Skills: Common Knowledge (Dwarfs)
Speak Language (Khalazid)
Speak Language (Reikspiel)
Trade (Miner -OR- Smith -OR- Stoneworker)
Talents: Dwarfcraft
Grudge-born Fury
Night Vision
Resistance to Magic
Stout-hearted
Sturdy
EOF
}
select-race-and-name () {
echo -n "Character's Name (blank to auto-generate name and sex)? "; read Name
race=""
while [ -z "$race" ]; do
echo -n "Race (human, dwarf, elf, or halfling)? "
read race
echo
if [ "$race" == "human" ] || [ -z "$race" ]; then stats=$(make-human);
elif [ "$race" == "dwarf" ]; then stats=$(make-dwarf);
elif [ "$race" == "elf" ]; then stats=$(make-elf);
elif [ "$race" == "halfling" ]; then stats=$(make-halfling);
else race=""
fi
done
cat << EOF
$stats
EOF
}
select-race-and-name