Fix warnings in generated lisp code.
This commit is contained in:
parent
e53d9f05a9
commit
0f03c237d2
5 changed files with 223 additions and 179 deletions
243
README.org
243
README.org
|
@ -749,7 +749,7 @@ Oh, one issue... how do I know where the data files for the moves are?
|
|||
(mapcar 'rpgdm-ironsworn--move-tuple
|
||||
(directory-files-recursively
|
||||
(f-join rpgdm-ironsworn-project "moves")
|
||||
".*\.org$"))))
|
||||
(rx (1+ any) ".org" eos)))))
|
||||
rpgdm-ironsworn-moves)
|
||||
#+END_SRC
|
||||
|
||||
|
@ -763,7 +763,7 @@ A frustrating lack-of-function is a [[help:completing-read][completing-read]] fu
|
|||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(defun completing-read-value (prompt values)
|
||||
"Like `completing-read' but returns the value from VALUES instead of key.
|
||||
"Like `completing-read' but return value from VALUES instead of key.
|
||||
Display PROMPT, and has a list of choices displayed for the user to select."
|
||||
(thread-first prompt
|
||||
(completing-read values)
|
||||
|
@ -793,14 +793,15 @@ Now, let's do the Move interface. We need to load the documentation, and retriev
|
|||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(defun rpgdm-ironsworn-make-move (move-file)
|
||||
"Make an Ironsworn move by loading MOVE-FILE, and optionally querying the
|
||||
user to make an initial roll based on the properties in the file."
|
||||
"Make an Ironsworn move by loading MOVE-FILE.
|
||||
Optionally query the user to make an initial roll based
|
||||
on the properties in the file."
|
||||
(interactive (list (rpgdm-ironsworn-choose-move)))
|
||||
|
||||
;; Normally, we'd call `save-window-excursion', however, that buries the file
|
||||
;; we show, and I think we should leave it up for study.
|
||||
(let (props title
|
||||
(orig-buf (window-buffer)))
|
||||
(orig-buf (window-buffer)))
|
||||
(find-file-other-window move-file)
|
||||
(goto-char (point-min))
|
||||
(setq title (cdr (assoc "ITEM" (org-entry-properties))))
|
||||
|
@ -887,18 +888,19 @@ A helper function for allowing the user to choose which track to mark progress a
|
|||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(defun rpgdm-ironsworn-progress-track-choose (&optional allow-other)
|
||||
"Query the user for a particular stored track. If ALLOW-OTHER is non-nil,
|
||||
we append a choice, <other>, which allows the user to choose the number
|
||||
of squares that have been marked against some progress."
|
||||
"Query the user to choose a track stored in the org file.
|
||||
If ALLOW-OTHER is non-nil, we append a choice, <other>, which
|
||||
allows the user to choose the number of squares that have been
|
||||
marked against some progress."
|
||||
(let* ((other "<other>")
|
||||
(tracks (rpgdm-ironsworn-character-progresses))
|
||||
(choices (if allow-other
|
||||
(append tracks (list other))
|
||||
tracks))
|
||||
(original (completing-read "Progress Track: " choices)))
|
||||
(tracks (rpgdm-ironsworn-character-progresses))
|
||||
(choices (if allow-other
|
||||
(append tracks (list other))
|
||||
tracks))
|
||||
(original (completing-read "Progress Track: " choices)))
|
||||
(if (and allow-other (equal original other))
|
||||
(read-number "Completed Track Amount [0-10]: ")
|
||||
original)))
|
||||
(read-number "Completed Track Amount [0-10]: ")
|
||||
original)))
|
||||
#+END_SRC
|
||||
|
||||
Adding a progress to a character amounts to an arbitrary name, and the number of ticks, that amount to a /level/. For instance, we want to mark two boxes against a /dangerous/ track, which is =8= ticks. We store this in the character's hash-table, under the key, =progress-tracks=:
|
||||
|
@ -906,7 +908,7 @@ Adding a progress to a character amounts to an arbitrary name, and the number of
|
|||
#+BEGIN_SRC emacs-lisp
|
||||
(defun rpgdm-ironsworn-progress-create (name level)
|
||||
"Add a new progress track, NAME, of a particular LEVEL.
|
||||
Stored as a property in the org file. Keep in mind that the
|
||||
Stored as a property in the org file. Keep in mind that the
|
||||
NAME should be a short title, not a description."
|
||||
(interactive (list (read-string "Progress Name: ")
|
||||
(completing-read-value "Progress Level: "
|
||||
|
@ -937,8 +939,9 @@ Interactively, we can call the =-mark= function multiple times, but we might wan
|
|||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(defun rpgdm-ironsworn-progress-mark (name &optional times)
|
||||
"Mark progress against a track, NAME. Instead of calling this function multiple
|
||||
times, you can specify the number of TIMES to mark progress."
|
||||
"Mark progress against a track, NAME, storing result.
|
||||
Instead of calling this function multiple times, you can specify
|
||||
the number of TIMES to mark progress."
|
||||
(interactive (list (rpgdm-ironsworn-progress-track-choose)))
|
||||
(unless times (setq times 1))
|
||||
(dotimes (idx times)
|
||||
|
@ -967,8 +970,8 @@ Rolling against the progress just means we need to request that value instead of
|
|||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(defun rpgdm-ironsworn-progress-roll (progress-value)
|
||||
"Display a Hit/Miss message based on comparing the PROGRESS-VALUE
|
||||
to rolling two d10 challenge dice."
|
||||
"Display a Hit/Miss message based on the PROGRESS-VALUE.
|
||||
This value is compared to rolling two d10 challenge dice."
|
||||
(interactive (list (rpgdm-ironsworn-progress-track-choose t)))
|
||||
(unless (numberp progress-value)
|
||||
(setq progress-value (rpgdm-ironsworn-progress-amount progress-value)))
|
||||
|
@ -1014,11 +1017,95 @@ Let's make sure these function work as we expect:
|
|||
(should (= (rpgdm-ironsworn-progress-amount track) 1))))
|
||||
#+END_SRC
|
||||
*** Delve Site Progress
|
||||
In the Ironsworn Delve expansion, you can venture in a /dangerous place/, and this is a slightly different progress. To begin, you choose a /theme/ and a /domain/, and then many oracles can refer to a combination of them. Let’a have a function that allows us to choose both (and store) so that we can refer to them again.
|
||||
In the Ironsworn Delve expansion, you can venture in a /dangerous place/, and this is a slightly different progress.
|
||||
|
||||
Using the interesting random name generator from the Ironsworn: Delve source book.
|
||||
Requires a =place-type= to help limit the values that can be in /place/ and then looks up the details on various tables.
|
||||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(defun rpgdm-ironsworn-oracle-site-name (&optional place-type)
|
||||
"Return a randomly generated name for a dangerous site.
|
||||
The PLACE-TYPE is something like 'shadowfen or 'sea-cave,
|
||||
and helps to make the new name more meaningful to the place."
|
||||
(interactive (list (completing-read "Place type: "
|
||||
'(barrow cavern icereach mine pass ruin
|
||||
sea-cave shadowfen stronghold
|
||||
tanglewood underkeep))))
|
||||
(unless place-type
|
||||
(setq place-type "unknown"))
|
||||
(let ((description (rpgdm-tables-choose "site/name/description"))
|
||||
(detail (rpgdm-tables-choose "site/name/detail"))
|
||||
(namesake (rpgdm-tables-choose "site/name/namesake"))
|
||||
(place (rpgdm-tables-choose (format "site/name/place/%s" (downcase place-type))))
|
||||
(roll (rpgdm--roll-die 100)))
|
||||
(rpgdm-message
|
||||
(cond
|
||||
((<= roll 25) (format "%s %s" description place))
|
||||
((<= roll 50) (format "%s of %s" place detail))
|
||||
((<= roll 70) (format "%s of %s %s" place description detail))
|
||||
((<= roll 80) (format "%s of %s's %s" place namesake detail))
|
||||
((<= roll 85) (format "%s's %s" namesake place))
|
||||
((<= roll 95) (format "%s %s of %s" description place namesake))
|
||||
(t (format "%s of %s" place namesake))))))
|
||||
#+END_SRC
|
||||
While the following functions can take advantage of this function, we also want to place it in our normal =rpgdm-tables= hash, so that we can choose it there:
|
||||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(puthash "site/name" 'rpgdm-ironsworn-oracle-site-name rpgdm-tables)
|
||||
#+END_SRC
|
||||
|
||||
So, let's generate some random place names as examples of it working:
|
||||
#+BEGIN_SRC emacs-lisp :tangle no
|
||||
(rpgdm-ironsworn-oracle-site-name "barrow") ; "Tomb of Storms"
|
||||
(rpgdm-ironsworn-oracle-site-name "cavern") ; "Lair of Khulan’s Truth"
|
||||
(rpgdm-ironsworn-oracle-site-name "icereach") ; "Barrens of Erisia’s Winter"
|
||||
(rpgdm-ironsworn-oracle-site-name "mine") ; "Lode of Ashen Lament"
|
||||
(rpgdm-ironsworn-oracle-site-name "pass") ; "Sunken Highlands"
|
||||
(rpgdm-ironsworn-oracle-site-name "ruin") ; "Sanctum of Khulan’s Truth"
|
||||
(rpgdm-ironsworn-oracle-site-name "sea-cave") ; "Silent Caves"
|
||||
(rpgdm-ironsworn-oracle-site-name "shadowfen") ; "Floodlands of Nightmare Despair"
|
||||
(rpgdm-ironsworn-oracle-site-name "stronghold") ; "Crumbling Bastion"
|
||||
(rpgdm-ironsworn-oracle-site-name "tanglewood") ; "Bramble of Endless Strife"
|
||||
(rpgdm-ironsworn-oracle-site-name "underkeep") ; "Underkeep of Lament"
|
||||
(rpgdm-ironsworn-oracle-site-name) ; "Sundered Mists of Khulan"
|
||||
#+END_SRC
|
||||
|
||||
What makes these unique is the combination a place type, called a /domain/, and an aspect, called a /theme/, and then many oracles can refer to a combination of both tables. We could randomly choose a place, rolling randomly on both theme and domain, for instance:
|
||||
- Ravaged Shadowfen :: Mire of Shrouded Silence
|
||||
- Haunted Barrow :: Grave of Radek’s Shadow
|
||||
- Infested Barrow :: Selpulcher of Wasted Bone
|
||||
Notice we also generate a name for the place.
|
||||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(defun rpgdm-ironsworn-oracle-site-nature ()
|
||||
"Return a name and nature of a dangerous site.
|
||||
The nature is a combination of theme and domain."
|
||||
(interactive)
|
||||
(let* ((theme (rpgdm-tables-choose "site/theme"))
|
||||
(domain (rpgdm-tables-choose "site/domain"))
|
||||
(place (downcase domain))
|
||||
(name (rpgdm-ironsworn-oracle-site-name place)))
|
||||
(rpgdm-message "%s %s :: %s" theme domain name)))
|
||||
#+END_SRC
|
||||
|
||||
Let’s put this function too in our =rpgdm-tables= hash table, so I can easily grab a unique random dangerous site.
|
||||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(puthash "site" 'rpgdm-ironsworn-oracle-site-nature rpgdm-tables)
|
||||
#+END_SRC
|
||||
|
||||
To begin delving into a site, you choose a /theme/ and a /domain/, and then . Let’a have a function that allows us to choose both (and store) so that we can refer to them again.
|
||||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(defun rpgdm-ironsworn-discover-a-site (theme domain)
|
||||
"Store a Delve Site information in the org file."
|
||||
"Store a Delve Site information in the org file.
|
||||
The THEME and DOMAIN need to match org files in the `tables'
|
||||
directory, and the choices themselves come from these files.
|
||||
See the helper functions,
|
||||
`rpgdm-ironsworn-site-themes' and `rpgdm-ironsworn-site-domains'.
|
||||
|
||||
Note, this function also queries the user for the name of the site
|
||||
and progress level, and stores all this information in the org file."
|
||||
(interactive
|
||||
(list
|
||||
(completing-read "What is the site theme? " rpgdm-ironsworn-site-themes)
|
||||
|
@ -1033,11 +1120,13 @@ In the Ironsworn Delve expansion, you can venture in a /dangerous place/, and th
|
|||
(rpgdm-ironsworn-store-character-state 'site-theme (downcase theme))
|
||||
(rpgdm-ironsworn-store-character-state 'site-domain (downcase domain)))
|
||||
#+END_SRC
|
||||
|
||||
With these properties in place, we can now do a much better job with the [[file:moves/delve/delve-the-depths.org][Delve the Depths]] move.
|
||||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(defun rpgdm-ironsworn-delve-the-depths-weak (stat)
|
||||
"Return random results from weak hit table for Delve the Depths."
|
||||
"Return random result from weak hit table for Delve the Depths.
|
||||
The STAT should be the symbol, 'wits, 'shadow, or 'edge."
|
||||
(interactive (list (completing-read "Stat Choice: "
|
||||
'("wits" "shadow" "edge"))))
|
||||
(let ((table-name (format "delve/weak-hit/%s" stat)))
|
||||
|
@ -1045,14 +1134,17 @@ With these properties in place, we can now do a much better job with the [[file:
|
|||
(rpgdm-tables-choose table-name)))
|
||||
|
||||
(defun rpgdm-ironsworn-delve-the-depths-weak-edge ()
|
||||
"Return random result from `edge` version of the weak hit table."
|
||||
(interactive)
|
||||
(rpgdm-ironsworn-delve-the-depths-weak "edge"))
|
||||
|
||||
(defun rpgdm-ironsworn-delve-the-depths-weak-shadow ()
|
||||
"Return random result from `shadow` version of the weak hit table."
|
||||
(interactive)
|
||||
(rpgdm-ironsworn-delve-the-depths-weak "shadow"))
|
||||
|
||||
(defun rpgdm-ironsworn-delve-the-depths-weak-wits ()
|
||||
"Return random result from `wits` version of the weak hit table."
|
||||
(interactive)
|
||||
(rpgdm-ironsworn-delve-the-depths-weak "wits"))
|
||||
#+END_SRC
|
||||
|
@ -1153,14 +1245,14 @@ The [[file:tables/combat-action.org][combat action]] table isn't often tactical,
|
|||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(defun rpgdm-ironsworn-oracle-combat ()
|
||||
"Return combat response combined from three combat tables."
|
||||
(interactive)
|
||||
(let ((action (rpgdm-tables-choose "combat-action"))
|
||||
(method (rpgdm-tables-choose "combat-event-method"))
|
||||
(target (rpgdm-tables-choose "combat-event-target")))
|
||||
(let ((action (rpgdm-tables-choose "combat/action"))
|
||||
(method (rpgdm-tables-choose "combat/event-method"))
|
||||
(target (rpgdm-tables-choose "combat/event-target")))
|
||||
(rpgdm-message "%s %s or %s" method target action)))
|
||||
|
||||
(puthash "combat-action-events :: Roll on all combat tables"
|
||||
'rpgdm-ironsworn-oracle-combat rpgdm-tables)
|
||||
(puthash "combat" 'rpgdm-ironsworn-oracle-combat rpgdm-tables)
|
||||
#+END_SRC
|
||||
*** Feature
|
||||
This function combines the [[file:tables/feature-aspect.org][aspect]] and [[file:tables/feature-focus.org][focus]] of a /feature/, for instance:
|
||||
|
@ -1170,7 +1262,7 @@ This function combines the [[file:tables/feature-aspect.org][aspect]] and [[file
|
|||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(defun rpgdm-ironsworn-oracle-feature ()
|
||||
"Rolls on two tables at one time for a Site's feature."
|
||||
"Roll on two tables at one time for a Site's feature."
|
||||
(interactive)
|
||||
(let ((aspect (rpgdm-tables-choose "feature/aspect"))
|
||||
(focus (rpgdm-tables-choose "feature/focus")))
|
||||
|
@ -1184,7 +1276,7 @@ And a Waypoint is similar:
|
|||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(defun rpgdm-ironsworn-oracle-waypoint ()
|
||||
"Rolls on two tables at one time for a Site's feature."
|
||||
"Roll on two tables at one time for a Site's feature."
|
||||
(interactive)
|
||||
(let ((location (rpgdm-tables-choose "location"))
|
||||
(description (rpgdm-tables-choose "location-descriptors")))
|
||||
|
@ -1193,73 +1285,6 @@ And a Waypoint is similar:
|
|||
(puthash "location-and-descriptor :: Roll on two tables for a waypoint"
|
||||
'rpgdm-ironsworn-oracle-waypoint rpgdm-tables)
|
||||
#+END_SRC
|
||||
*** Site Nature
|
||||
In the Ironsworn Delve expansion, you can randomly choose a /dangerous place/, for instance:
|
||||
- Ravaged Shadowfen :: Mire of Shrouded Silence
|
||||
- Haunted Barrow :: Grave of Radek’s Shadow
|
||||
- Infested Barrow :: Selpulcher of Wasted Bone
|
||||
Notice we also generate a name for the place.
|
||||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(defun rpgdm-ironsworn-oracle-site-nature ()
|
||||
"Rolls on two tables at one time for a random Site."
|
||||
(interactive)
|
||||
(let* ((theme (rpgdm-tables-choose "site/theme"))
|
||||
(domain (rpgdm-tables-choose "site/domain"))
|
||||
(place (downcase domain))
|
||||
(name (rpgdm-ironsworn-oracle-site-name place)))
|
||||
(rpgdm-message "%s %s :: %s" theme domain name)))
|
||||
|
||||
(puthash "site-nature :: Roll on both site theme and domain tables"
|
||||
'rpgdm-ironsworn-oracle-site-nature rpgdm-tables)
|
||||
#+END_SRC
|
||||
*** Site Name
|
||||
Using the interesting random name generator from the Ironsworn: Delve source book.
|
||||
Requires a =place-type= to help limit the values that can be in /place/ and then looks up the details on the tables in the =ironsworn= directory.
|
||||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(defun rpgdm-ironsworn-oracle-site-name (&optional place-type)
|
||||
"Rolling on multiple tables to return a random site name."
|
||||
(interactive (list (completing-read "Place type: "
|
||||
'(barrow cavern icereach mine pass ruin
|
||||
sea-cave shadowfen stronghold
|
||||
tanglewood underkeep))))
|
||||
(unless place-type
|
||||
(setq place-type "unknown"))
|
||||
(let ((description (rpgdm-tables-choose "site/name/description"))
|
||||
(detail (rpgdm-tables-choose "site/name/detail"))
|
||||
(namesake (rpgdm-tables-choose "site/name/namesake"))
|
||||
(place (rpgdm-tables-choose (format "site/name/place/%s" (downcase place-type))))
|
||||
(roll (rpgdm--roll-die 100)))
|
||||
(rpgdm-message
|
||||
(cond
|
||||
((<= roll 25) (format "%s %s" description place))
|
||||
((<= roll 50) (format "%s of %s" place detail))
|
||||
((<= roll 70) (format "%s of %s %s" place description detail))
|
||||
((<= roll 80) (format "%s of %s's %s" place namesake detail))
|
||||
((<= roll 85) (format "%s's %s" namesake place))
|
||||
((<= roll 95) (format "%s %s of %s" description place namesake))
|
||||
(t (format "%s of %s" place namesake))))))
|
||||
|
||||
(puthash "site-name :: Generate a name for a dangerous site"
|
||||
'rpgdm-ironsworn-oracle-site-name rpgdm-tables)
|
||||
#+END_SRC
|
||||
|
||||
So, let's generate some random place names:
|
||||
#+BEGIN_SRC emacs-lisp :tangle no
|
||||
(rpgdm-ironsworn-oracle-site-name "barrow") ; "Tomb of Storms"
|
||||
(rpgdm-ironsworn-oracle-site-name "cavern") ; "Lair of Khulan’s Truth"
|
||||
(rpgdm-ironsworn-oracle-site-name "icereach") ; "Barrens of Erisia’s Winter"
|
||||
(rpgdm-ironsworn-oracle-site-name "mine") ; "Lode of Ashen Lament"
|
||||
(rpgdm-ironsworn-oracle-site-name "pass") ; "Sunken Highlands"
|
||||
(rpgdm-ironsworn-oracle-site-name "ruin") ; "Sanctum of Khulan’s Truth"
|
||||
(rpgdm-ironsworn-oracle-site-name "sea-cave") ; "Silent Caves"
|
||||
(rpgdm-ironsworn-oracle-site-name "shadowfen") ; "Floodlands of Nightmare Despair"
|
||||
(rpgdm-ironsworn-oracle-site-name "stronghold") ; "Crumbling Bastion"
|
||||
(rpgdm-ironsworn-oracle-site-name "tanglewood") ; "Bramble of Endless Strife"
|
||||
(rpgdm-ironsworn-oracle-site-name "underkeep") ; "Underkeep of Lament"
|
||||
(rpgdm-ironsworn-oracle-site-name) ; "Sundered Mists of Khulan"
|
||||
#+END_SRC
|
||||
*** Threat
|
||||
Generate a random threat and its motivations by coding the threat, but using the many [[file:tables/threat-category.org][threats]] available:
|
||||
|
||||
|
@ -1269,7 +1294,7 @@ Generate a random threat and its motivations by coding the threat, but using the
|
|||
"Scheming Leader" "Zealous Cult"
|
||||
"Environmental Calamity" "Power-Hungry Mystic"
|
||||
"Rampaging Creature")
|
||||
"A list of threats that correspond to tables")
|
||||
"A list of threats that correspond to tables.")
|
||||
|
||||
(defun rpgdm-ironsworn-oracle-threat-goal (&optional category)
|
||||
"Given a CATEGORY, display a threat goal."
|
||||
|
@ -1483,6 +1508,7 @@ Since we store both normal and progress props together, we need to distinguish b
|
|||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(defun rpgdm-ironsworn--short-progress-p (prop)
|
||||
"Return non-nil if symbol, PROP, begins with progress."
|
||||
(let ((p (symbol-name prop)))
|
||||
(s-starts-with-p "progress-" p)))
|
||||
#+END_SRC
|
||||
|
@ -1519,11 +1545,12 @@ So the general idea is:
|
|||
Since we need to know if we are at the top-level, we could have a function, =org-heading-level= that returns =1= if we are at the top-level, and =0= if we aren't at any level:
|
||||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(defun org-heading-level ()
|
||||
"Return heading level of the element at the point. 0 otherwise."
|
||||
(if-let ((level-str (org-element-property :level (org-element-at-point))))
|
||||
level-str
|
||||
0))
|
||||
(defun org-heading-level ()
|
||||
"Return heading level of the element at the point.
|
||||
Return 0 if not at a heading, or above first headline."
|
||||
(if-let ((level-str (org-element-property :level (org-element-at-point))))
|
||||
level-str
|
||||
0))
|
||||
#+END_SRC
|
||||
|
||||
Enough chit-chat, let's write this function. While we are at it, let's convert the property symbols into short symbols, e.g. =:IRONSWORN-SHADOW= should just be =shadow=, and number values should be numeric:
|
||||
|
@ -1531,8 +1558,8 @@ Enough chit-chat, let's write this function. While we are at it, let's convert t
|
|||
#+BEGIN_SRC emacs-lisp
|
||||
(defun rpgdm-ironsworn--current-character-state (results)
|
||||
"Recursive helper to insert current header properties in RESULTS.
|
||||
Calls itself if it is not looking at the top-level header in the
|
||||
file. If a property is already in the hash table, RESULTS, it is
|
||||
Calls itself if it is not looking at the top level header in the
|
||||
file. If a property is already in the hash table, RESULTS, it is
|
||||
not overwritten, thereby having lower-level subtrees take
|
||||
precendence over similar settings in higher headers."
|
||||
(defun key-convert (ironsworn-prop)
|
||||
|
@ -1586,8 +1613,8 @@ Org can return the value, but breaking it up requires a regular expression:
|
|||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(defun rpgdm-ironsworn--progress-values (value)
|
||||
"Parse a string VALUE returning a list of parts,
|
||||
Including the initial name, the number of ticks to mark,
|
||||
"Parse a string VALUE returning a list of parts.
|
||||
This includes the initial name, the number of ticks to mark,
|
||||
and the current progress of the track."
|
||||
(let ((regxp (rx "\""
|
||||
(group (one-or-more (not "\"")))
|
||||
|
@ -1649,7 +1676,7 @@ And since we move the cursor, we need to [[help:save-excursion][save-excursion]]
|
|||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(defun rpgdm-ironsworn-mark-progress-track (label)
|
||||
"Given a progress track's name, STR, update its progress mark."
|
||||
"Given a progress track's name, LABEL, update its progress mark."
|
||||
(interactive (list (completing-read "Progress: " (rpgdm-ironsworn--progresses))))
|
||||
(save-excursion
|
||||
(rpgdm-ironsworn--mark-progress-track label)))
|
||||
|
|
|
@ -422,11 +422,11 @@ will return a cached copy."
|
|||
(mapcar 'rpgdm-ironsworn--move-tuple
|
||||
(directory-files-recursively
|
||||
(f-join rpgdm-ironsworn-project "moves")
|
||||
".*\.org$"))))
|
||||
(rx (1+ any) ".org" eos)))))
|
||||
rpgdm-ironsworn-moves)
|
||||
|
||||
(defun completing-read-value (prompt values)
|
||||
"Like `completing-read' but returns the value from VALUES instead of key.
|
||||
"Like `completing-read' but return value from VALUES instead of key.
|
||||
Display PROMPT, and has a list of choices displayed for the user to select."
|
||||
(thread-first prompt
|
||||
(completing-read values)
|
||||
|
@ -444,14 +444,15 @@ current file."
|
|||
(set-register ?m (format "# %s ... %s " title results)))
|
||||
|
||||
(defun rpgdm-ironsworn-make-move (move-file)
|
||||
"Make an Ironsworn move by loading MOVE-FILE, and optionally querying the
|
||||
user to make an initial roll based on the properties in the file."
|
||||
"Make an Ironsworn move by loading MOVE-FILE.
|
||||
Optionally query the user to make an initial roll based
|
||||
on the properties in the file."
|
||||
(interactive (list (rpgdm-ironsworn-choose-move)))
|
||||
|
||||
;; Normally, we'd call `save-window-excursion', however, that buries the file
|
||||
;; we show, and I think we should leave it up for study.
|
||||
(let (props title
|
||||
(orig-buf (window-buffer)))
|
||||
(orig-buf (window-buffer)))
|
||||
(find-file-other-window move-file)
|
||||
(goto-char (point-min))
|
||||
(setq title (cdr (assoc "ITEM" (org-entry-properties))))
|
||||
|
@ -507,22 +508,23 @@ For instance, if LABEL is `Dangerous', this returns `8'."
|
|||
(car (rassoc level rpgdm-ironsworn-progress-levels)))
|
||||
|
||||
(defun rpgdm-ironsworn-progress-track-choose (&optional allow-other)
|
||||
"Query the user for a particular stored track. If ALLOW-OTHER is non-nil,
|
||||
we append a choice, <other>, which allows the user to choose the number
|
||||
of squares that have been marked against some progress."
|
||||
"Query the user to choose a track stored in the org file.
|
||||
If ALLOW-OTHER is non-nil, we append a choice, <other>, which
|
||||
allows the user to choose the number of squares that have been
|
||||
marked against some progress."
|
||||
(let* ((other "<other>")
|
||||
(tracks (rpgdm-ironsworn-character-progresses))
|
||||
(choices (if allow-other
|
||||
(append tracks (list other))
|
||||
tracks))
|
||||
(original (completing-read "Progress Track: " choices)))
|
||||
(tracks (rpgdm-ironsworn-character-progresses))
|
||||
(choices (if allow-other
|
||||
(append tracks (list other))
|
||||
tracks))
|
||||
(original (completing-read "Progress Track: " choices)))
|
||||
(if (and allow-other (equal original other))
|
||||
(read-number "Completed Track Amount [0-10]: ")
|
||||
(read-number "Completed Track Amount [0-10]: ")
|
||||
original)))
|
||||
|
||||
(defun rpgdm-ironsworn-progress-create (name level)
|
||||
"Add a new progress track, NAME, of a particular LEVEL.
|
||||
Stored as a property in the org file. Keep in mind that the
|
||||
Stored as a property in the org file. Keep in mind that the
|
||||
NAME should be a short title, not a description."
|
||||
(interactive (list (read-string "Progress Name: ")
|
||||
(completing-read-value "Progress Level: "
|
||||
|
@ -549,8 +551,9 @@ NAME should be a short title, not a description."
|
|||
(org-set-property track-prop track-val)))
|
||||
|
||||
(defun rpgdm-ironsworn-progress-mark (name &optional times)
|
||||
"Mark progress against a track, NAME. Instead of calling this function multiple
|
||||
times, you can specify the number of TIMES to mark progress."
|
||||
"Mark progress against a track, NAME, storing result.
|
||||
Instead of calling this function multiple times, you can specify
|
||||
the number of TIMES to mark progress."
|
||||
(interactive (list (rpgdm-ironsworn-progress-track-choose)))
|
||||
(unless times (setq times 1))
|
||||
(dotimes (idx times)
|
||||
|
@ -571,8 +574,8 @@ times, you can specify the number of TIMES to mark progress."
|
|||
boxes)))
|
||||
|
||||
(defun rpgdm-ironsworn-progress-roll (progress-value)
|
||||
"Display a Hit/Miss message based on comparing the PROGRESS-VALUE
|
||||
to rolling two d10 challenge dice."
|
||||
"Display a Hit/Miss message based on the PROGRESS-VALUE.
|
||||
This value is compared to rolling two d10 challenge dice."
|
||||
(interactive (list (rpgdm-ironsworn-progress-track-choose t)))
|
||||
(unless (numberp progress-value)
|
||||
(setq progress-value (rpgdm-ironsworn-progress-amount progress-value)))
|
||||
|
@ -589,8 +592,54 @@ to rolling two d10 challenge dice."
|
|||
(ignore-errors
|
||||
(remhash name tracks))))
|
||||
|
||||
(defun rpgdm-ironsworn-oracle-site-name (&optional place-type)
|
||||
"Return a randomly generated name for a dangerous site.
|
||||
The PLACE-TYPE is something like 'shadowfen or 'sea-cave,
|
||||
and helps to make the new name more meaningful to the place."
|
||||
(interactive (list (completing-read "Place type: "
|
||||
'(barrow cavern icereach mine pass ruin
|
||||
sea-cave shadowfen stronghold
|
||||
tanglewood underkeep))))
|
||||
(unless place-type
|
||||
(setq place-type "unknown"))
|
||||
(let ((description (rpgdm-tables-choose "site/name/description"))
|
||||
(detail (rpgdm-tables-choose "site/name/detail"))
|
||||
(namesake (rpgdm-tables-choose "site/name/namesake"))
|
||||
(place (rpgdm-tables-choose (format "site/name/place/%s" (downcase place-type))))
|
||||
(roll (rpgdm--roll-die 100)))
|
||||
(rpgdm-message
|
||||
(cond
|
||||
((<= roll 25) (format "%s %s" description place))
|
||||
((<= roll 50) (format "%s of %s" place detail))
|
||||
((<= roll 70) (format "%s of %s %s" place description detail))
|
||||
((<= roll 80) (format "%s of %s's %s" place namesake detail))
|
||||
((<= roll 85) (format "%s's %s" namesake place))
|
||||
((<= roll 95) (format "%s %s of %s" description place namesake))
|
||||
(t (format "%s of %s" place namesake))))))
|
||||
|
||||
(puthash "site/name" 'rpgdm-ironsworn-oracle-site-name rpgdm-tables)
|
||||
|
||||
(defun rpgdm-ironsworn-oracle-site-nature ()
|
||||
"Return a name and nature of a dangerous site.
|
||||
The nature is a combination of theme and domain."
|
||||
(interactive)
|
||||
(let* ((theme (rpgdm-tables-choose "site/theme"))
|
||||
(domain (rpgdm-tables-choose "site/domain"))
|
||||
(place (downcase domain))
|
||||
(name (rpgdm-ironsworn-oracle-site-name place)))
|
||||
(rpgdm-message "%s %s :: %s" theme domain name)))
|
||||
|
||||
(puthash "site" 'rpgdm-ironsworn-oracle-site-nature rpgdm-tables)
|
||||
|
||||
(defun rpgdm-ironsworn-discover-a-site (theme domain)
|
||||
"Store a Delve Site information in the org file."
|
||||
"Store a Delve Site information in the org file.
|
||||
The THEME and DOMAIN need to match org files in the `tables'
|
||||
directory, and the choices themselves come from these files.
|
||||
See the helper functions,
|
||||
`rpgdm-ironsworn-site-themes' and `rpgdm-ironsworn-site-domains'.
|
||||
|
||||
Note, this function also queries the user for the name of the site
|
||||
and progress level, and stores all this information in the org file."
|
||||
(interactive
|
||||
(list
|
||||
(completing-read "What is the site theme? " rpgdm-ironsworn-site-themes)
|
||||
|
@ -606,7 +655,8 @@ to rolling two d10 challenge dice."
|
|||
(rpgdm-ironsworn-store-character-state 'site-domain (downcase domain)))
|
||||
|
||||
(defun rpgdm-ironsworn-delve-the-depths-weak (stat)
|
||||
"Return random results from weak hit table for Delve the Depths."
|
||||
"Return random result from weak hit table for Delve the Depths.
|
||||
The STAT should be the symbol, 'wits, 'shadow, or 'edge."
|
||||
(interactive (list (completing-read "Stat Choice: "
|
||||
'("wits" "shadow" "edge"))))
|
||||
(let ((table-name (format "delve/weak-hit/%s" stat)))
|
||||
|
@ -614,14 +664,17 @@ to rolling two d10 challenge dice."
|
|||
(rpgdm-tables-choose table-name)))
|
||||
|
||||
(defun rpgdm-ironsworn-delve-the-depths-weak-edge ()
|
||||
"Return random result from `edge` version of the weak hit table."
|
||||
(interactive)
|
||||
(rpgdm-ironsworn-delve-the-depths-weak "edge"))
|
||||
|
||||
(defun rpgdm-ironsworn-delve-the-depths-weak-shadow ()
|
||||
"Return random result from `shadow` version of the weak hit table."
|
||||
(interactive)
|
||||
(rpgdm-ironsworn-delve-the-depths-weak "shadow"))
|
||||
|
||||
(defun rpgdm-ironsworn-delve-the-depths-weak-wits ()
|
||||
"Return random result from `wits` version of the weak hit table."
|
||||
(interactive)
|
||||
(rpgdm-ironsworn-delve-the-depths-weak "wits"))
|
||||
|
||||
|
@ -692,17 +745,17 @@ You'll need to pick and choose what works and discard what doesn't."
|
|||
'rpgdm-ironsworn-oracle-npc rpgdm-tables)
|
||||
|
||||
(defun rpgdm-ironsworn-oracle-combat ()
|
||||
"Return combat response combined from three combat tables."
|
||||
(interactive)
|
||||
(let ((action (rpgdm-tables-choose "combat-action"))
|
||||
(method (rpgdm-tables-choose "combat-event-method"))
|
||||
(target (rpgdm-tables-choose "combat-event-target")))
|
||||
(let ((action (rpgdm-tables-choose "combat/action"))
|
||||
(method (rpgdm-tables-choose "combat/event-method"))
|
||||
(target (rpgdm-tables-choose "combat/event-target")))
|
||||
(rpgdm-message "%s %s or %s" method target action)))
|
||||
|
||||
(puthash "combat-action-events :: Roll on all combat tables"
|
||||
'rpgdm-ironsworn-oracle-combat rpgdm-tables)
|
||||
(puthash "combat" 'rpgdm-ironsworn-oracle-combat rpgdm-tables)
|
||||
|
||||
(defun rpgdm-ironsworn-oracle-feature ()
|
||||
"Rolls on two tables at one time for a Site's feature."
|
||||
"Roll on two tables at one time for a Site's feature."
|
||||
(interactive)
|
||||
(let ((aspect (rpgdm-tables-choose "feature/aspect"))
|
||||
(focus (rpgdm-tables-choose "feature/focus")))
|
||||
|
@ -712,7 +765,7 @@ You'll need to pick and choose what works and discard what doesn't."
|
|||
'rpgdm-ironsworn-oracle-feature rpgdm-tables)
|
||||
|
||||
(defun rpgdm-ironsworn-oracle-waypoint ()
|
||||
"Rolls on two tables at one time for a Site's feature."
|
||||
"Roll on two tables at one time for a Site's feature."
|
||||
(interactive)
|
||||
(let ((location (rpgdm-tables-choose "location"))
|
||||
(description (rpgdm-tables-choose "location-descriptors")))
|
||||
|
@ -721,50 +774,12 @@ You'll need to pick and choose what works and discard what doesn't."
|
|||
(puthash "location-and-descriptor :: Roll on two tables for a waypoint"
|
||||
'rpgdm-ironsworn-oracle-waypoint rpgdm-tables)
|
||||
|
||||
(defun rpgdm-ironsworn-oracle-site-nature ()
|
||||
"Rolls on two tables at one time for a random Site."
|
||||
(interactive)
|
||||
(let* ((theme (rpgdm-tables-choose "site/theme"))
|
||||
(domain (rpgdm-tables-choose "site/domain"))
|
||||
(place (downcase domain))
|
||||
(name (rpgdm-ironsworn-oracle-site-name place)))
|
||||
(rpgdm-message "%s %s :: %s" theme domain name)))
|
||||
|
||||
(puthash "site-nature :: Roll on both site theme and domain tables"
|
||||
'rpgdm-ironsworn-oracle-site-nature rpgdm-tables)
|
||||
|
||||
(defun rpgdm-ironsworn-oracle-site-name (&optional place-type)
|
||||
"Rolling on multiple tables to return a random site name."
|
||||
(interactive (list (completing-read "Place type: "
|
||||
'(barrow cavern icereach mine pass ruin
|
||||
sea-cave shadowfen stronghold
|
||||
tanglewood underkeep))))
|
||||
(unless place-type
|
||||
(setq place-type "unknown"))
|
||||
(let ((description (rpgdm-tables-choose "site/name/description"))
|
||||
(detail (rpgdm-tables-choose "site/name/detail"))
|
||||
(namesake (rpgdm-tables-choose "site/name/namesake"))
|
||||
(place (rpgdm-tables-choose (format "site/name/place/%s" (downcase place-type))))
|
||||
(roll (rpgdm--roll-die 100)))
|
||||
(rpgdm-message
|
||||
(cond
|
||||
((<= roll 25) (format "%s %s" description place))
|
||||
((<= roll 50) (format "%s of %s" place detail))
|
||||
((<= roll 70) (format "%s of %s %s" place description detail))
|
||||
((<= roll 80) (format "%s of %s's %s" place namesake detail))
|
||||
((<= roll 85) (format "%s's %s" namesake place))
|
||||
((<= roll 95) (format "%s %s of %s" description place namesake))
|
||||
(t (format "%s of %s" place namesake))))))
|
||||
|
||||
(puthash "site-name :: Generate a name for a dangerous site"
|
||||
'rpgdm-ironsworn-oracle-site-name rpgdm-tables)
|
||||
|
||||
(defvar rpgdm-ironsworn-oracle-threats '("Burgeoning Conflict" "Ravaging Horde"
|
||||
"Cursed Site" "Malignant Plague"
|
||||
"Scheming Leader" "Zealous Cult"
|
||||
"Environmental Calamity" "Power-Hungry Mystic"
|
||||
"Rampaging Creature")
|
||||
"A list of threats that correspond to tables")
|
||||
"A list of threats that correspond to tables.")
|
||||
|
||||
(defun rpgdm-ironsworn-oracle-threat-goal (&optional category)
|
||||
"Given a CATEGORY, display a threat goal."
|
||||
|
@ -918,6 +933,7 @@ Specifically, does it begin with `:IRONSWORN-PROGRESS'"
|
|||
(string-match (rx bos ":IRONSWORN-PROGRESS-") p)))
|
||||
|
||||
(defun rpgdm-ironsworn--short-progress-p (prop)
|
||||
"Return non-nil if symbol, PROP, begins with progress."
|
||||
(let ((p (symbol-name prop)))
|
||||
(s-starts-with-p "progress-" p)))
|
||||
|
||||
|
@ -926,7 +942,8 @@ Specifically, does it begin with `:IRONSWORN-PROGRESS'"
|
|||
(downcase (substring (symbol-name prop) 1)))
|
||||
|
||||
(defun org-heading-level ()
|
||||
"Return heading level of the element at the point. 0 otherwise."
|
||||
"Return heading level of the element at the point.
|
||||
Return 0 if not at a heading, or above first headline."
|
||||
(if-let ((level-str (org-element-property :level (org-element-at-point))))
|
||||
level-str
|
||||
0))
|
||||
|
@ -977,8 +994,8 @@ lower levels of the tree headings take precedence."
|
|||
results)))
|
||||
|
||||
(defun rpgdm-ironsworn--progress-values (value)
|
||||
"Parse a string VALUE returning a list of parts,
|
||||
Including the initial name, the number of ticks to mark,
|
||||
"Parse a string VALUE returning a list of parts.
|
||||
This includes the initial name, the number of ticks to mark,
|
||||
and the current progress of the track."
|
||||
(let ((regxp (rx "\""
|
||||
(group (one-or-more (not "\"")))
|
||||
|
@ -1020,7 +1037,7 @@ and the current progress of the track."
|
|||
(rpgdm-ironsworn--mark-progress-track str)))
|
||||
|
||||
(defun rpgdm-ironsworn-mark-progress-track (label)
|
||||
"Given a progress track's name, STR, update its progress mark."
|
||||
"Given a progress track's name, LABEL, update its progress mark."
|
||||
(interactive (list (completing-read "Progress: " (rpgdm-ironsworn--progresses))))
|
||||
(save-excursion
|
||||
(rpgdm-ironsworn--mark-progress-track label)))
|
||||
|
|
Loading…
Reference in a new issue