Working with both Dice and Frequency tables

Some of these tables are getting complicated, so I have created three
different tables, and this should be sufficient.

Describing it, however, seems to be a lot for source code, and I thought
I would describe it using a literate programming style. We'll see.
This commit is contained in:
Howard Abrams 2021-02-08 15:26:16 -08:00
parent 558d7eb984
commit 7dab533415
7 changed files with 975 additions and 270 deletions

169
rpgdm-npc.el Normal file
View file

@ -0,0 +1,169 @@
;;; rpgdm-npc.el --- Random NPC Generation -*- lexical-binding: t; -*-
;;
;; Copyright (C) 2021 Howard X. Abrams
;;
;; Author: Howard X. Abrams <http://gitlab.com/howardabrams>
;; Maintainer: Howard X. Abrams <howard.abrams@workday.com>
;; Created: January 8, 2021
;;
;; This file is not part of GNU Emacs.
;;
;;; Commentary:
;;
;; Choosing a good NPC is about the location:
;; - City
;; - Town
;; - Village
;; - Road
;; - Feywild, etc.
;;
;; As this will really affect the occupation.
;;
;; Also, the /purpose/ may also change whether we are looking for a companion
;; or guild, or just a random person on the street.
;;
;; Obviously, I won't worry about giving incorrect answers, as anything that
;; doesn't /fit/ will just be ignored.
;;
;;;
;;; CCode:
(defvar rpgdm-base ".")
(require 'rpgdm-dice (expand-file-name "rpgdm-dice.el" rpgdm-base) t)
(require 'rpgdm-dice (expand-file-name "rpgdm-tables.el" rpgdm-base) t)
(defun rpgdm-npc-gender-name ()
"Return nil or non-nil for male or female names."
(= (random 2) 0))
(defun rpgdm-npc-choose (&rest choices)
"Randomly return from from CHOICES, one of the parameters."
(seq-random-elt choices))
(defun rpgdm-npc-adventuring-age ()
"Return string representing the age of an NPC available to physically aide the adventures."
(let ((roll (rpgdm--roll-die 100)))
(cond
((= roll 1) "Very young (child)")
((<= roll 10) "Coming of age")
((<= roll 60) "Young adult")
((<= roll 90) "Middle Aged")
((<= roll 99) "Old")
(t "Past normal lifespan (very old)"))))
(defun rpgdm-npc-age ()
"Return string representing an age of a random NPC."
(let ((roll (rpgdm--roll-die 100)))
(cond
((= roll 1) "Very young (child)")
((<= roll 10) "Coming of age")
((<= roll 40) "Young adult")
((<= roll 70) "Middle Aged")
((<= roll 96) "Old")
(t "Past normal lifespan (very old)"))))
(defun rpgdm-npc-known-parents ()
"Return non-nil if PC knew their parents."
(< (rpgdm--roll-die 100) 96))
(defun rpgdm-npc--parents ()
"Return a tuple of `father' and `mother' in either order."
(seq-random-elt '((father mother) (mother father))))
(defun rpgdm-npc--parent-assignment (x y)
"Given two parental types, X and Y, assign them to father or mother."
(seq-let (a b) (rpgdm-npc--parents)
(format "%s was %s, and %s was %s" a x b y)))
(defun rpgdm-npc-halfelf-parents ()
(let ((roll (rpgdm--roll-die 8)))
(cond
((<= roll 5) (rpgdm-npc--parent-assignment "an elf" "human"))
((= roll 6) (rpgdm-npc--parent-assignment "an elf" "half-elven"))
((= roll 7) (rpgdm-npc--parent-assignment "human" "half-elven"))
((= roll 8) "both parents were half-elven"))))
(defun rpgdm-npc-halforc-parents ()
(let ((roll (rpgdm--roll-die 8)))
(cond
((<= roll 3) (rpgdm-npc--parent-assignment "an orc" "human"))
((= roll 5) (rpgdm-npc--parent-assignment "an orc" "a half-orc"))
((= roll 7) (rpgdm-npc--parent-assignment "human" "a half-orc"))
((= roll 8) "both parents were half-orcs"))))
(defun rpgdm-npc-tiefling-parents ()
(let ((roll (rpgdm--roll-die 8)))
(cond
((<= roll 4) "both parents were human, their infernal heritage dormant until their child was born")
((= roll 6) (rpgdm-npc--parent-assignment "a tiefling" "human"))
((= roll 7) (rpgdm-npc--parent-assignment "a tiefling" "a devil"))
((= roll 8) (rpgdm-npc--parent-assignment "human" "a devil")))))
(defun rpgdm-npc-birthplace ()
"Return string of a random birthplace."
(let ((roll (rpgdm--roll-die 100)))
(cond
((<= roll 50) "at home")
((<= roll 55) "in the home of a family friend")
((<= roll 63) "in the home of a healer or midwife")
((<= roll 65) (format "in a %s" (rpgdm-npc-choose "carriage" "cart or wagon")))
((<= roll 68) "in a barn, shed, or other outbuilding")
((<= roll 70) "in a cave")
((<= roll 72) "in a field")
((<= roll 74) "in a forest")
((<= roll 77) "in a Temple")
((= roll 78) "in a battlefield")
((<= roll 80) "in an alley or street")
((<= roll 82) "in a brothel, tavern, or inn")
((<= roll 84) "in a castle, keep, tower, or palace")
((= roll 85) (format "in %s" (rpgdm-npc-choose "the sewers" "a rubbish heap")))
((<= roll 88) (format "among people of a different race: %s" (rpgdm-tables-choose "npc-race")))
((<= roll 91) (format "on board a %s" (rpgdm-npc-choose "boat" "ship")))
((<= roll 93) (format "in %s of a secret organization" (rpgdm-npc-choose "a prison" "the headquarters")))
((<= roll 95) "in a sages laboratory")
((= roll 96) "in the Feywild")
((= roll 97) "in the Shadowfell")
((= roll 98) (format "on the %s Plane" (rpgdm-npc-choose "Astral" "Ethereal")))
((= roll 99) "on an Inner Plane")
(t "on an Outer Plane"))))
(defun rpgdm-npc--cause-of-death ()
"Return string from a random cause of death."
(let ((roll (rpgdm--roll-die 12)))
(cond
((= roll 1) "unknown")
((= roll 2) "murdered")
((= roll 3) "killed in battle")
((= roll 4) (format "accident related to %s"
(rpgdm-npc-choose "class" "occupation")))
((= roll 5) "accident unrelated to class or occupation")
((= roll 6) "disease, natural causes")
((= roll 7) "old age, natural causes")
((= roll 8) "apparent suicide")
((= roll 9) (rpgdm-npc-choose "torn apart by an animal" "natural disaster"))
((= roll 10) "consumed by a monster")
((= roll 11) (rpgdm-npc-choose "executed for a crime" "tortured to death"))
((= roll 12) "bizarre event, such as being hit by a meteorite, struck down by an angry god, or killed by a hatching slaad egg"))))
(defun rpgdm-npc-siblings ()
"Return string of the number of siblihngs.
I am not sure why Xanathar's Guide had such a complicated
way of rolloing for siblings. But I recreated it."
(let ((roll (rpgdm--roll-die 10)))
(cond
((<= roll 2) 0)
((<= roll 4) (rpgdm-roll-sum "1d3"))
((<= roll 6) (rpgdm-roll-sum "1d4+1"))
((<= roll 8) (rpgdm-roll-sum "1d6+2"))
((<= roll 10) (rpgdm-roll-sum "1d8+3")))))
(defun rpgdm-npc-birth-order ()
"A string results of whether a sibling is older or younger."
(let ((roll (rpgdm-roll-sum "2d6")))
(cond
((= roll 2) "Twin, triplet, or quadruplet")
((<= roll 7) "Older")
(t "Younger"))))
(provide 'rpgdm-npc)
;;; rpgdm-npc.el ends here