Add a number of Delve-specific moves
Combining the themes and domains to help make less table-consulting.
This commit is contained in:
parent
bea1a2a6b8
commit
e53d9f05a9
7 changed files with 636 additions and 275 deletions
258
README.org
258
README.org
|
@ -19,7 +19,7 @@ After listening to the author, [[https://twitter.com/ShawnTomkin][Shawn Tomkin]]
|
||||||
* Getting Started
|
* Getting Started
|
||||||
Neither this, nor the [[https://gitlab.com/howardabrams/emacs-rpgdm][rpgdm project]] are currently in MELPA, so if you wish to follow along at home, you'll need to clone both repos, and add them to your =load-path= variable with =add-to-list=:
|
Neither this, nor the [[https://gitlab.com/howardabrams/emacs-rpgdm][rpgdm project]] are currently in MELPA, so if you wish to follow along at home, you'll need to clone both repos, and add them to your =load-path= variable with =add-to-list=:
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+BEGIN_SRC emacs-lisp :tangle no
|
||||||
(add-to-list 'load-path (expand-file-name "~/other/rpgdm"))
|
(add-to-list 'load-path (expand-file-name "~/other/rpgdm"))
|
||||||
(add-to-list 'load-path (expand-file-name "~/other/rpgdm-ironsworn"))
|
(add-to-list 'load-path (expand-file-name "~/other/rpgdm-ironsworn"))
|
||||||
#+END_SRC
|
#+END_SRC
|
||||||
|
@ -136,6 +136,26 @@ Again, the UI will attempt to update all of these values, so you don't need to c
|
||||||
|
|
||||||
Details? Did someone say details? Let's talk about the code ... all the code that makes this work.
|
Details? Did someone say details? Let's talk about the code ... all the code that makes this work.
|
||||||
* Code
|
* Code
|
||||||
|
#+BEGIN_SRC emacs-lisp :exports none
|
||||||
|
;;; rpgdm-ironsworn -- Functions for integrating Ironsworn with Org
|
||||||
|
;;
|
||||||
|
;; Copyright (C) 2020 Howard X. Abrams
|
||||||
|
;;
|
||||||
|
;; Author: Howard X. Abrams <http://gitlab.com/howardabrams>
|
||||||
|
;; Maintainer: Howard X. Abrams
|
||||||
|
;; Created: September 18, 2020
|
||||||
|
;;
|
||||||
|
;; This file is not part of GNU Emacs.
|
||||||
|
;;
|
||||||
|
;;; Commentary:
|
||||||
|
;;
|
||||||
|
;; This file is conspicuously absent from commentary or even
|
||||||
|
;; comments. This is because this file is created from tangling
|
||||||
|
;; the README.org file in this directory.
|
||||||
|
;;
|
||||||
|
;;; Code:
|
||||||
|
|
||||||
|
#+END_SRC
|
||||||
To begin, we'll need the [[https://gitlab.com/howardabrams/emacs-rpgdm][rpgdm project]] cloned in the =load-path= variable so that we can load it simply by calling:
|
To begin, we'll need the [[https://gitlab.com/howardabrams/emacs-rpgdm][rpgdm project]] cloned in the =load-path= variable so that we can load it simply by calling:
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+BEGIN_SRC emacs-lisp
|
||||||
|
@ -146,7 +166,7 @@ We also need the name of the directory for this project, so that we can load tab
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+BEGIN_SRC emacs-lisp
|
||||||
(defvar rpgdm-ironsworn-project (file-name-directory load-file-name)
|
(defvar rpgdm-ironsworn-project (file-name-directory load-file-name)
|
||||||
"The root directory to the rpgdm-ironsworn project")
|
"The root directory to the rpgdm-ironsworn project.")
|
||||||
#+END_SRC
|
#+END_SRC
|
||||||
** Dice Roller
|
** Dice Roller
|
||||||
In *Ironsworn*, all dice rolls follow a pattern where you set the challenge level for a check by rolling /challenge dice/ (two d10s) and compare that against rolling an /action die/ (a single d6 ... adding all modifiers to that six-sided die). You always three possible values:
|
In *Ironsworn*, all dice rolls follow a pattern where you set the challenge level for a check by rolling /challenge dice/ (two d10s) and compare that against rolling an /action die/ (a single d6 ... adding all modifiers to that six-sided die). You always three possible values:
|
||||||
|
@ -162,6 +182,13 @@ When we roll, I want one of those three results printed, but in different colors
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+BEGIN_SRC emacs-lisp
|
||||||
(defun rpgdm-ironsworn--results (action modifier one-challenge two-challenge
|
(defun rpgdm-ironsworn--results (action modifier one-challenge two-challenge
|
||||||
&optional momentum)
|
&optional momentum)
|
||||||
|
"Return formatted string for an Ironsworn dice roll results.
|
||||||
|
The ACTION is the d6 which is added to the MODIFIER (which can
|
||||||
|
have character attribute values as well as any bonuses. The sum
|
||||||
|
is compared to the two d10, ONE-CHALLENGE and TWO-CHALLENGE.
|
||||||
|
|
||||||
|
The optional MOMENTUM can be specified to add a message that the
|
||||||
|
use could burn that in order to improve the roll."
|
||||||
(unless momentum
|
(unless momentum
|
||||||
(setq momentum 0))
|
(setq momentum 0))
|
||||||
|
|
||||||
|
@ -230,8 +257,11 @@ The basic interface will query for a modifer, roll all three dice, and then disp
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp :results silent
|
#+BEGIN_SRC emacs-lisp :results silent
|
||||||
(defun rpgdm-ironsworn-roll (modifier &optional momentum)
|
(defun rpgdm-ironsworn-roll (modifier &optional momentum)
|
||||||
"Display a Hit/Miss message based on comparing a d6 action
|
"Display a Hit/Miss message based on an Ironsworn roll.
|
||||||
roll (added to MODIFIER) vs. two d10 challenge dice."
|
Done by rolling and comparing a d6 action roll (summed with
|
||||||
|
MODIFIER) vs two d10 challenge dice. If given, the MOMENTUM may
|
||||||
|
trigger a message to the user that they can burn that for better
|
||||||
|
results."
|
||||||
(interactive "nModifier: ")
|
(interactive "nModifier: ")
|
||||||
(let ((one-challenge (rpgdm--roll-die 10))
|
(let ((one-challenge (rpgdm--roll-die 10))
|
||||||
(two-challenge (rpgdm--roll-die 10))
|
(two-challenge (rpgdm--roll-die 10))
|
||||||
|
@ -250,7 +280,9 @@ We assume you have created an org-file, and the /template/ will just append some
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+BEGIN_SRC emacs-lisp
|
||||||
(defun rpgdm-ironsworn--new-character-template (name)
|
(defun rpgdm-ironsworn--new-character-template (name)
|
||||||
"Insert a basic Ironsworn template at the end of the current buffer."
|
"Insert basic Ironsworn template at the end of the current buffer.
|
||||||
|
A header is created with NAME, but if this is an empty string,
|
||||||
|
a random name is generated for the purposes of the template."
|
||||||
(when (s-blank? name)
|
(when (s-blank? name)
|
||||||
(setq name (rpgdm-tables-choose "names-ironlander")))
|
(setq name (rpgdm-tables-choose "names-ironlander")))
|
||||||
|
|
||||||
|
@ -328,7 +360,7 @@ Let the user choose an asset and insert it into the file at the current point. W
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+BEGIN_SRC emacs-lisp
|
||||||
(defun rpgdm-ironsworn-insert-character-asset (asset)
|
(defun rpgdm-ironsworn-insert-character-asset (asset)
|
||||||
"Choose and insert the contents of an asset in the current buffer."
|
"Choose and insert the contents of an ASSET in the current buffer."
|
||||||
(interactive (list (rpgdm-ironsworn--pick-character-asset)))
|
(interactive (list (rpgdm-ironsworn--pick-character-asset)))
|
||||||
(let ((file (if (consp asset) (cdr asset) asset)))
|
(let ((file (if (consp asset) (cdr asset) asset)))
|
||||||
(insert-file-contents file nil)
|
(insert-file-contents file nil)
|
||||||
|
@ -412,6 +444,8 @@ Now we have a function that inserts the contents of three randomly chosen assets
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+BEGIN_SRC emacs-lisp
|
||||||
(defun rpgdm-ironsworn-random-character-assets (&optional number-of-assets)
|
(defun rpgdm-ironsworn-random-character-assets (&optional number-of-assets)
|
||||||
|
"Return the file names of NUMBER-OF-ASSETS from the `assets' directory.
|
||||||
|
The chosen assets are _good_ in that they won't have duplicates, etc."
|
||||||
(interactive "nHow many random assets should we insert? ")
|
(interactive "nHow many random assets should we insert? ")
|
||||||
(dolist (file (rpgdm-ironsworn--random-character-assets number-of-assets))
|
(dolist (file (rpgdm-ironsworn--random-character-assets number-of-assets))
|
||||||
(rpgdm-ironsworn-insert-character-asset file)))
|
(rpgdm-ironsworn-insert-character-asset file)))
|
||||||
|
@ -434,9 +468,10 @@ This function will query the user for all of the stats and other properties that
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+BEGIN_SRC emacs-lisp
|
||||||
(defun rpgdm-ironsworn--new-character-stats ()
|
(defun rpgdm-ironsworn--new-character-stats ()
|
||||||
"Query the user for a new character's stats, and add them as
|
"Insert character stats after querying user for them.
|
||||||
properties using the `rpgdm-ironsworn-store-character-state' and
|
Note: The stats are added as properties using the
|
||||||
the `rpgdm-ironsworn-progress-create' functions."
|
`rpgdm-ironsworn-store-character-state' and the
|
||||||
|
`rpgdm-ironsworn-progress-create' functions."
|
||||||
(dolist (stat '(edge heart iron shadow wits))
|
(dolist (stat '(edge heart iron shadow wits))
|
||||||
(rpgdm-ironsworn-store-character-state stat
|
(rpgdm-ironsworn-store-character-state stat
|
||||||
(read-string (format "What '%s' stat: " stat))))
|
(read-string (format "What '%s' stat: " stat))))
|
||||||
|
@ -458,13 +493,15 @@ Perhaps the clearest approach is to do both, create two process functions, and t
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+BEGIN_SRC emacs-lisp
|
||||||
(defun rpgdm-ironsworn--new-character-stats-first (&optional name)
|
(defun rpgdm-ironsworn--new-character-stats-first (&optional name)
|
||||||
"Insert a new character template, query for the stats, then insert assets."
|
"Insert a new character template for character, NAME.
|
||||||
|
The character stats are first queried, and then assets inserted."
|
||||||
(rpgdm-ironsworn--new-character-template name)
|
(rpgdm-ironsworn--new-character-template name)
|
||||||
(rpgdm-ironsworn--new-character-stats)
|
(rpgdm-ironsworn--new-character-stats)
|
||||||
(rpgdm-ironsworn--new-character-assets))
|
(rpgdm-ironsworn--new-character-assets))
|
||||||
|
|
||||||
(defun rpgdm-ironsworn--new-character-assets-first (&optional name)
|
(defun rpgdm-ironsworn--new-character-assets-first (&optional name)
|
||||||
"Insert a new character template, insert assets then query for the stats."
|
"Insert a new character template for character, NAME.
|
||||||
|
The assets are inserted first, and then character stats are queried."
|
||||||
(rpgdm-ironsworn--new-character-template name)
|
(rpgdm-ironsworn--new-character-template name)
|
||||||
;; Saving and restoring point, means the properties should be in the
|
;; Saving and restoring point, means the properties should be in the
|
||||||
;; correct, top-level position.
|
;; correct, top-level position.
|
||||||
|
@ -474,6 +511,8 @@ Perhaps the clearest approach is to do both, create two process functions, and t
|
||||||
|
|
||||||
(defun rpgdm-ironsworn-new-character (name order)
|
(defun rpgdm-ironsworn-new-character (name order)
|
||||||
"Interactively query the user for a new character's attribute.
|
"Interactively query the user for a new character's attribute.
|
||||||
|
The NAME is the character's name, and ORDER determines how the
|
||||||
|
template will generate and query the user for the rest of the data.
|
||||||
This function _appends_ this information to the current buffer,
|
This function _appends_ this information to the current buffer,
|
||||||
which should be using the `org-mode' major mode."
|
which should be using the `org-mode' major mode."
|
||||||
(interactive (list
|
(interactive (list
|
||||||
|
@ -490,6 +529,8 @@ Sure, you could open up the appropriate drawer to see a character's stats, but
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+BEGIN_SRC emacs-lisp
|
||||||
(defun rpgdm-ironsworn--display-stat (stat character)
|
(defun rpgdm-ironsworn--display-stat (stat character)
|
||||||
|
"Colorized the STAT from a CHARACTER hash containing it.
|
||||||
|
See `rpgdm-ironsworn-character-display'."
|
||||||
(let* ((value (gethash stat character))
|
(let* ((value (gethash stat character))
|
||||||
(s-val (number-to-string value))
|
(s-val (number-to-string value))
|
||||||
(color (cond
|
(color (cond
|
||||||
|
@ -522,7 +563,7 @@ We need an /internal representation/ of a character using a hash table of the at
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+BEGIN_SRC emacs-lisp
|
||||||
(defun rpgdm-ironsworn-to-string (a)
|
(defun rpgdm-ironsworn-to-string (a)
|
||||||
"Return a lowercase string from either a string, keyword or symbol."
|
"Return a lowercase string from either A, a string, keyword or symbol."
|
||||||
(downcase
|
(downcase
|
||||||
(cond
|
(cond
|
||||||
((keywordp a) (substring (symbol-name a) 1))
|
((keywordp a) (substring (symbol-name a) 1))
|
||||||
|
@ -541,7 +582,9 @@ And a help function to retrieve the stats of the character is just a wrapper aro
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+BEGIN_SRC emacs-lisp
|
||||||
(defun rpgdm-ironsworn-character-stat (stat &optional character)
|
(defun rpgdm-ironsworn-character-stat (stat &optional character)
|
||||||
"Return integer value associated with a character's STAT."
|
"Return integer value associated with a character's STAT.
|
||||||
|
If CHARACTER doesn't refer to a character hash, then this calls
|
||||||
|
the `rpgdm-ironsworn-current-character-state' function."
|
||||||
(when (null character)
|
(when (null character)
|
||||||
(setq character (rpgdm-ironsworn-current-character-state)))
|
(setq character (rpgdm-ironsworn-current-character-state)))
|
||||||
(gethash stat character 1))
|
(gethash stat character 1))
|
||||||
|
@ -561,7 +604,8 @@ We need to modify /some/ of the stored values, like =health= and =supply=:
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp :results silent
|
#+BEGIN_SRC emacs-lisp :results silent
|
||||||
(defun rpgdm-ironsworn-adjust-stat (stat adj &optional default)
|
(defun rpgdm-ironsworn-adjust-stat (stat adj &optional default)
|
||||||
"Increase or decrease the current character's STAT by ADJ."
|
"Increase or decrease the current character's STAT by ADJ.
|
||||||
|
If the STAT isn't found, returns DEFAULT."
|
||||||
(let* ((curr (rpgdm-ironsworn-character-stat stat))
|
(let* ((curr (rpgdm-ironsworn-character-stat stat))
|
||||||
(new (+ curr adj)))
|
(new (+ curr adj)))
|
||||||
(rpgdm-ironsworn-store-character-state stat new)))
|
(rpgdm-ironsworn-store-character-state stat new)))
|
||||||
|
@ -655,6 +699,9 @@ The [[file:moves][moves]] directory contains one org file for each move. These f
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+BEGIN_SRC emacs-lisp
|
||||||
(defun rpgdm-ironsworn--move-tuple (file)
|
(defun rpgdm-ironsworn--move-tuple (file)
|
||||||
|
"Return a list of a string representation of FILE, and FILE.
|
||||||
|
The string representation is created by looking at the parent
|
||||||
|
directory and file name."
|
||||||
(let* ((regx (rx "moves/"
|
(let* ((regx (rx "moves/"
|
||||||
(group (one-or-more (not "/")))
|
(group (one-or-more (not "/")))
|
||||||
"/"
|
"/"
|
||||||
|
@ -685,16 +732,18 @@ And let's verify the format:
|
||||||
Once I read the list of moves, I want to /cache/ it, using a poor-person's /memoize/ feature:
|
Once I read the list of moves, I want to /cache/ it, using a poor-person's /memoize/ feature:
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+BEGIN_SRC emacs-lisp
|
||||||
(defvar rpgdm-ironsworn-moves () "A list of tuples of the move and the file containing its goodness.")
|
(defvar rpgdm-ironsworn-moves ()
|
||||||
|
"A list of tuples of the move and the file containing its goodness.")
|
||||||
#+END_SRC
|
#+END_SRC
|
||||||
|
|
||||||
Oh, one issue... how do I know where the data files for the moves are?
|
Oh, one issue... how do I know where the data files for the moves are?
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+BEGIN_SRC emacs-lisp
|
||||||
(defun rpgdm-ironsworn-moves ()
|
(defun rpgdm-ironsworn-moves ()
|
||||||
"Return a list containing available moves, and the filename containing
|
"Return a list containing available moves and its filename.
|
||||||
the moves instructions, and other properties. Note that this function is
|
The file contains the move's instructions and other properties. Note
|
||||||
memoized, in that re-calling this function will return a cached copy."
|
that this function is memoized, in that re-calling this function
|
||||||
|
will return a cached copy."
|
||||||
(unless rpgdm-ironsworn-moves
|
(unless rpgdm-ironsworn-moves
|
||||||
(setq rpgdm-ironsworn-moves
|
(setq rpgdm-ironsworn-moves
|
||||||
(mapcar 'rpgdm-ironsworn--move-tuple
|
(mapcar 'rpgdm-ironsworn--move-tuple
|
||||||
|
@ -710,21 +759,33 @@ Choosing a move comes from using the =completing-read= along with a /list/ of al
|
||||||
(completing-read "Move: " (rpgdm-ironsworn-moves))
|
(completing-read "Move: " (rpgdm-ironsworn-moves))
|
||||||
#+END_SRC
|
#+END_SRC
|
||||||
|
|
||||||
We'll wrap that in a function to let the user choose a nicely formatted move, but return the file containing the move.
|
A frustrating lack-of-function is a [[help:completing-read][completing-read]] function that can take a plist, but return the /value/ instead of the key. Let’s creating one.
|
||||||
|
|
||||||
|
#+BEGIN_SRC emacs-lisp
|
||||||
|
(defun completing-read-value (prompt values)
|
||||||
|
"Like `completing-read' but returns the 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)
|
||||||
|
(assoc values)
|
||||||
|
(second)))
|
||||||
|
#+END_SRC
|
||||||
|
|
||||||
|
We can use that function to let the user choose a nicely formatted move, but return the file containing the move.
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+BEGIN_SRC emacs-lisp
|
||||||
(defun rpgdm-ironsworn-choose-move ()
|
(defun rpgdm-ironsworn-choose-move ()
|
||||||
(let* ((move (completing-read "Move: " (rpgdm-ironsworn-moves)))
|
"A `completing-read' for moves, but returns the move filename."
|
||||||
(tuple (assoc move (rpgdm-ironsworn-moves))))
|
(completing-read-value "Move: " (rpgdm-ironsworn-moves)))
|
||||||
(cadr tuple)))
|
|
||||||
#+END_SRC
|
#+END_SRC
|
||||||
|
|
||||||
Another feature I want, is that after completing a move, to put the results in a register, so that I can paste it into my notes file:
|
Another feature I want, is that after completing a move, to put the results in a register, so that I can paste it into my notes file:
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+BEGIN_SRC emacs-lisp
|
||||||
(defun rpgdm-ironsworn--store-move (title results)
|
(defun rpgdm-ironsworn--store-move (title results)
|
||||||
"Store the results in a `m' register. It should also include
|
"Store RESULTS in `m' register for later pasting.
|
||||||
the name of the move, based on the current file."
|
The register also has TITLE, the name of the move, based on the
|
||||||
|
current file."
|
||||||
(set-register ?m (format "# %s ... %s " title results)))
|
(set-register ?m (format "# %s ... %s " title results)))
|
||||||
#+END_SRC
|
#+END_SRC
|
||||||
|
|
||||||
|
@ -797,11 +858,11 @@ While the 10 boxes are easy for pen-and-paper games, we really need the number a
|
||||||
(cl-flet* ((faded (str) (propertize str 'face '(:foreground "#888")))
|
(cl-flet* ((faded (str) (propertize str 'face '(:foreground "#888")))
|
||||||
(msg (a b) (format "%s %s %s" a (faded "--") (faded b))))
|
(msg (a b) (format "%s %s %s" a (faded "--") (faded b))))
|
||||||
(defvar
|
(defvar
|
||||||
rpgdm-ironsworn-progress-levels `((,(msg "troublesome" "quick") . 12)
|
rpgdm-ironsworn-progress-levels `((,(msg "troublesome" "quick") 12)
|
||||||
(,(msg "dangerous" "short") . 8)
|
(,(msg "dangerous" "short") 8)
|
||||||
(,(msg "formidable" "long") . 4)
|
(,(msg "formidable" "long") 4)
|
||||||
(,(msg "extreme" "very long") . 2)
|
(,(msg "extreme" "very long") 2)
|
||||||
(,(msg "epic" "never-ending") . 1))
|
(,(msg "epic" "never-ending") 1))
|
||||||
"The five levels of progression for an Ironsworn progress track."))
|
"The five levels of progression for an Ironsworn progress track."))
|
||||||
#+END_SRC
|
#+END_SRC
|
||||||
|
|
||||||
|
@ -848,13 +909,27 @@ Adding a progress to a character amounts to an arbitrary name, and the number of
|
||||||
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."
|
NAME should be a short title, not a description."
|
||||||
(interactive (list (read-string "Progress Name: ")
|
(interactive (list (read-string "Progress Name: ")
|
||||||
(completing-read "Progress Level: "
|
(completing-read-value "Progress Level: "
|
||||||
rpgdm-ironsworn-progress-levels)))
|
rpgdm-ironsworn-progress-levels)))
|
||||||
|
|
||||||
(let* ((level-value (rpgdm-ironsworn-progress-level level))
|
(let* ((track-id (substring (secure-hash 'md5 name) 0 8))
|
||||||
(track-id (substring (secure-hash 'md5 name) 0 8))
|
|
||||||
(track-prop (format "ironsworn-progress-%s" track-id))
|
(track-prop (format "ironsworn-progress-%s" track-id))
|
||||||
(track-val (format "\"%s\" %d %d" name level-value 0)))
|
(track-val (format "\"%s\" %d %d" name level 0))
|
||||||
|
|
||||||
|
(title (org-get-heading))
|
||||||
|
(option '(("At the same level as a sibling?" same-level)
|
||||||
|
("As a subheading to this?" subheading)
|
||||||
|
("No new heading. Re-use this." no))))
|
||||||
|
|
||||||
|
(cl-case (completing-read-value "Create a new heading? " option)
|
||||||
|
('same-level (progn
|
||||||
|
(org-insert-heading-respect-content)
|
||||||
|
(insert name)))
|
||||||
|
('subheading (progn
|
||||||
|
(org-insert-heading-respect-content)
|
||||||
|
(org-shiftmetaright)
|
||||||
|
(insert name))))
|
||||||
|
|
||||||
(org-set-property track-prop track-val)))
|
(org-set-property track-prop track-val)))
|
||||||
#+END_SRC
|
#+END_SRC
|
||||||
|
|
||||||
|
@ -938,6 +1013,80 @@ Let's make sure these function work as we expect:
|
||||||
(rpgdm-ironsworn-progress-mark track 2)
|
(rpgdm-ironsworn-progress-mark track 2)
|
||||||
(should (= (rpgdm-ironsworn-progress-amount track) 1))))
|
(should (= (rpgdm-ironsworn-progress-amount track) 1))))
|
||||||
#+END_SRC
|
#+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.
|
||||||
|
|
||||||
|
#+BEGIN_SRC emacs-lisp
|
||||||
|
(defun rpgdm-ironsworn-discover-a-site (theme domain)
|
||||||
|
"Store a Delve Site information in the org file."
|
||||||
|
(interactive
|
||||||
|
(list
|
||||||
|
(completing-read "What is the site theme? " rpgdm-ironsworn-site-themes)
|
||||||
|
(completing-read "What is the domain? " rpgdm-ironsworn-site-domains)))
|
||||||
|
|
||||||
|
(rpgdm-ironsworn-progress-create
|
||||||
|
(read-string "Site Name: "
|
||||||
|
(rpgdm-ironsworn-oracle-site-name domain))
|
||||||
|
(completing-read-value "Progress Level: "
|
||||||
|
rpgdm-ironsworn-progress-levels))
|
||||||
|
(next-line 2)
|
||||||
|
(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."
|
||||||
|
(interactive (list (completing-read "Stat Choice: "
|
||||||
|
'("wits" "shadow" "edge"))))
|
||||||
|
(let ((table-name (format "delve/weak-hit/%s" stat)))
|
||||||
|
(message "Rolling on %s" table-name)
|
||||||
|
(rpgdm-tables-choose table-name)))
|
||||||
|
|
||||||
|
(defun rpgdm-ironsworn-delve-the-depths-weak-edge ()
|
||||||
|
(interactive)
|
||||||
|
(rpgdm-ironsworn-delve-the-depths-weak "edge"))
|
||||||
|
|
||||||
|
(defun rpgdm-ironsworn-delve-the-depths-weak-shadow ()
|
||||||
|
(interactive)
|
||||||
|
(rpgdm-ironsworn-delve-the-depths-weak "shadow"))
|
||||||
|
|
||||||
|
(defun rpgdm-ironsworn-delve-the-depths-weak-wits ()
|
||||||
|
(interactive)
|
||||||
|
(rpgdm-ironsworn-delve-the-depths-weak "wits"))
|
||||||
|
#+END_SRC
|
||||||
|
|
||||||
|
With the theme and domain properties in place, we can now do a much better job with the [[file:moves/delve/reveal-a-danger.org][Reveal a Danger]] move.
|
||||||
|
|
||||||
|
#+BEGIN_SRC emacs-lisp
|
||||||
|
(defun rpgdm-ironsworn--reveal-a-danger ()
|
||||||
|
"Return a random danger appropriate for Delve sites.
|
||||||
|
For instance, if the `danger' table states to consult the theme
|
||||||
|
or domain tables, this reads the `site-theme' and `site-domain'
|
||||||
|
properties in the current org file, and rolls on the appropriate
|
||||||
|
chart."
|
||||||
|
(let* ((theme (rpgdm-ironsworn-character-stat 'site-theme))
|
||||||
|
(domain (rpgdm-ironsworn-character-stat 'site-domain))
|
||||||
|
(danger (rpgdm-tables-choose "danger")))
|
||||||
|
(cond
|
||||||
|
((equal danger "Check the theme card.")
|
||||||
|
(rpgdm-tables-choose (format "danger/theme/%s" theme)))
|
||||||
|
|
||||||
|
((equal danger "Check the domain card.")
|
||||||
|
(rpgdm-tables-choose (format "danger/domain/%s" theme)))
|
||||||
|
|
||||||
|
(t danger))))
|
||||||
|
|
||||||
|
(defun rpgdm-ironsworn-reveal-a-danger ()
|
||||||
|
"Display a random danger appropriate for Delve sites.
|
||||||
|
For instance, if the `danger' table states to consult the theme
|
||||||
|
or domain tables, this reads the `site-theme' and `site-domain'
|
||||||
|
properties in the current org file, and rolls on the appropriate
|
||||||
|
chart."
|
||||||
|
(interactive)
|
||||||
|
(rpgdm-message "Revealed Danger: %s" (rpgdm-ironsworn--reveal-a-danger)))
|
||||||
|
#+END_SRC
|
||||||
** Oracles
|
** Oracles
|
||||||
Shawn Tompkin has created some useful oracles (random tables) to consult. I'm breaking my own [[https://gitlab.com/howardabrams/emacs-rpgdm][rpgdm project]] convention, and having this code automatically load those tables.
|
Shawn Tompkin has created some useful oracles (random tables) to consult. I'm breaking my own [[https://gitlab.com/howardabrams/emacs-rpgdm][rpgdm project]] convention, and having this code automatically load those tables.
|
||||||
|
|
||||||
|
@ -945,6 +1094,19 @@ Shawn Tompkin has created some useful oracles (random tables) to consult. I'm br
|
||||||
(rpgdm-tables-load (f-join rpgdm-ironsworn-project "tables"))
|
(rpgdm-tables-load (f-join rpgdm-ironsworn-project "tables"))
|
||||||
#+END_SRC
|
#+END_SRC
|
||||||
|
|
||||||
|
Some tables contain /code/ we need, so let’s gather those. The /trick/ is that the [[help:rpgdm-tables-load][rpgdm-tables-load]] function first stores only the /filename/ until we call [[help:rpgdm-tables-choose][rpgdm-tables-choose]], in which case, the contents of the table is now stored in the hash. So, to get the values, we first choose an item (and ignore it), and then just store the value from the hashtable.
|
||||||
|
|
||||||
|
#+BEGIN_SRC emacs-lisp
|
||||||
|
(defvar rpgdm-ironsworn-site-themes
|
||||||
|
(progn (rpgdm-tables-choose "site/theme")
|
||||||
|
(gethash "site/theme" rpgdm-tables))
|
||||||
|
"A list of the Delve site themes.")
|
||||||
|
|
||||||
|
(defvar rpgdm-ironsworn-site-domains
|
||||||
|
(progn (rpgdm-tables-choose "site/domain")
|
||||||
|
(gethash "site/domain" rpgdm-tables))
|
||||||
|
"A list of the Delve site domains.")
|
||||||
|
#+END_SRC
|
||||||
He designed many of the tables to work together, for instance, you should roll on both the [[file:tables/actions.org][actions]] and [[file:tables/themes.org][themes]] and combine the result to kick-start your ideas.
|
He designed many of the tables to work together, for instance, you should roll on both the [[file:tables/actions.org][actions]] and [[file:tables/themes.org][themes]] and combine the result to kick-start your ideas.
|
||||||
|
|
||||||
Rolling on one table is simple, but here we have a collection of helper function to roll on multiple tables, and display the result altogether.
|
Rolling on one table is simple, but here we have a collection of helper function to roll on multiple tables, and display the result altogether.
|
||||||
|
@ -1067,7 +1229,7 @@ Requires a =place-type= to help limit the values that can be in /place/ and then
|
||||||
(let ((description (rpgdm-tables-choose "site/name/description"))
|
(let ((description (rpgdm-tables-choose "site/name/description"))
|
||||||
(detail (rpgdm-tables-choose "site/name/detail"))
|
(detail (rpgdm-tables-choose "site/name/detail"))
|
||||||
(namesake (rpgdm-tables-choose "site/name/namesake"))
|
(namesake (rpgdm-tables-choose "site/name/namesake"))
|
||||||
(place (rpgdm-tables-choose (format "site/name/place/%s" place-type)))
|
(place (rpgdm-tables-choose (format "site/name/place/%s" (downcase place-type))))
|
||||||
(roll (rpgdm--roll-die 100)))
|
(roll (rpgdm--roll-die 100)))
|
||||||
(rpgdm-message
|
(rpgdm-message
|
||||||
(cond
|
(cond
|
||||||
|
@ -1194,12 +1356,22 @@ Can a Hydra call a hydra? Let's more all the special oracle and progress functio
|
||||||
("s" rpgdm-ironsworn-oracle-site-nature "Site Nature")
|
("s" rpgdm-ironsworn-oracle-site-nature "Site Nature")
|
||||||
("t" rpgdm-ironsworn-oracle-threat-goal "Threat's Goal"))
|
("t" rpgdm-ironsworn-oracle-threat-goal "Threat's Goal"))
|
||||||
|
|
||||||
|
(defhydra hydra-rpgdm-delve (:color blue)
|
||||||
|
"Delve site actions"
|
||||||
|
("n" rpgdm-ironsworn-discover-a-site "discover a site")
|
||||||
|
("w" rpgdm-ironsworn-delve-the-depths-weak "weak hit table")
|
||||||
|
("d" rpgdm-ironsworn-reveal-a-danger "reveal a danger")
|
||||||
|
("m" rpgdm-ironsworn-progress-mark "mark progress")
|
||||||
|
("p" rpgdm-ironsworn-progress-amount "show progress")
|
||||||
|
("x" rpgdm-ironsworn-progress-delete "delete")
|
||||||
|
("r" rpgdm-ironsworn-progress-roll "escape the depths"))
|
||||||
|
|
||||||
(defhydra hydra-rpgdm-progress (:color blue)
|
(defhydra hydra-rpgdm-progress (:color blue)
|
||||||
"Progress Tracks"
|
"Progress Tracks"
|
||||||
("n" rpgdm-ironsworn-progress-create "new")
|
("n" rpgdm-ironsworn-progress-create "new")
|
||||||
("m" rpgdm-ironsworn-progress-mark "mark")
|
("m" rpgdm-ironsworn-progress-mark "mark")
|
||||||
("p" rpgdm-ironsworn-progress-amount "show")
|
("p" rpgdm-ironsworn-progress-amount "show")
|
||||||
("d" rpgdm-ironsworn-progress-delete "delete")
|
("x" rpgdm-ironsworn-progress-delete "delete")
|
||||||
("r" rpgdm-ironsworn-progress-roll "roll"))
|
("r" rpgdm-ironsworn-progress-roll "roll"))
|
||||||
#+END_SRC
|
#+END_SRC
|
||||||
|
|
||||||
|
@ -1223,11 +1395,11 @@ But we roll some of these more than others, especially since "moves" does most o
|
||||||
"
|
"
|
||||||
^Dice^ 0=d100 1=d10 6=d6 ^Roll/Adjust^ ^Oracles/Tables^ ^Moving/Editing^ ^Messages^
|
^Dice^ 0=d100 1=d10 6=d6 ^Roll/Adjust^ ^Oracles/Tables^ ^Moving/Editing^ ^Messages^
|
||||||
----------------------------------------------------------------------------------------------------------------------------------------------------
|
----------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
_d_: Roll Dice _p_: Progress _l_/_L_: Health _z_/_Z_: Yes/No Oracle _o_: Links ⌘-h: Show Stats
|
_D_: Roll Dice _p_: Progress _l_/_L_: Health _z_/_Z_: Yes/No Oracle _o_: Links ⌘-h: Show Stats
|
||||||
_e_: Roll Edge _h_: Roll Shadow _t_/_T_: Spirit _c_/_C_: Show Oracle _J_/_K_: Page up/dn ⌘-l: Last Results
|
_e_: Roll Edge _h_: Roll Shadow _t_/_T_: Spirit _c_/_C_: Show Oracle _J_/_K_: Page up/dn ⌘-l: Last Results
|
||||||
_r_: Roll Heart _w_: Roll Wits _s_/_S_: Supply _O_: Load Oracles _N_/_W_: Narrow/Widen ⌘-k: ↑ Previous
|
_r_: Roll Heart _w_: Roll Wits _s_/_S_: Supply _O_: Load Oracles _N_/_W_: Narrow/Widen ⌘-k: ↑ Previous
|
||||||
_i_: Roll Iron _m_: Make Move _M_: Momentum _y_/_Y_: Yank/Move ⌘-j: ↓ Next "
|
_i_: Roll Iron _m_: Make Move _M_: Momentum _d_: Delve Actions _y_/_Y_: Yank/Move ⌘-j: ↓ Next "
|
||||||
("d" rpgdm-ironsworn-roll) ("D" rpgdm-ironsworn-progress-roll)
|
("D" rpgdm-ironsworn-roll)
|
||||||
("z" rpgdm-ironsworn-oracle) ("Z" rpgdm-yes-and-50/50)
|
("z" rpgdm-ironsworn-oracle) ("Z" rpgdm-yes-and-50/50)
|
||||||
|
|
||||||
("e" rpgdm-ironsworn-roll-edge)
|
("e" rpgdm-ironsworn-roll-edge)
|
||||||
|
@ -1246,6 +1418,8 @@ But we roll some of these more than others, especially since "moves" does most o
|
||||||
("M" rpgdm-ironsworn-adjust-momentum :color pink)
|
("M" rpgdm-ironsworn-adjust-momentum :color pink)
|
||||||
|
|
||||||
("O" rpgdm-tables-load) ("c" rpgdm-tables-choose) ("C" rpgdm-tables-choose :color pink)
|
("O" rpgdm-tables-load) ("c" rpgdm-tables-choose) ("C" rpgdm-tables-choose :color pink)
|
||||||
|
|
||||||
|
("d" hydra-rpgdm-delve/body)
|
||||||
("p" hydra-rpgdm-progress/body)
|
("p" hydra-rpgdm-progress/body)
|
||||||
|
|
||||||
("o" ace-link) ("N" org-narrow-to-subtree) ("W" widen)
|
("o" ace-link) ("N" org-narrow-to-subtree) ("W" widen)
|
||||||
|
@ -1388,9 +1562,15 @@ Enough chit-chat, let's write this function. While we are at it, let's convert t
|
||||||
lower levels of the tree headings take precedence."
|
lower levels of the tree headings take precedence."
|
||||||
(save-excursion
|
(save-excursion
|
||||||
(let ((results (make-hash-table :test 'str-or-keys)))
|
(let ((results (make-hash-table :test 'str-or-keys)))
|
||||||
(unless (eq 'headline (org-element-type (org-element-at-point)))
|
(unless (org-at-heading-p)
|
||||||
(org-up-element))
|
(org-up-element))
|
||||||
|
|
||||||
|
;; Put the lowest heading title in the results hashtable:
|
||||||
|
(puthash 'title (thread-first
|
||||||
|
(org-element-at-point)
|
||||||
|
(second)
|
||||||
|
(plist-get :raw-value))
|
||||||
|
results)
|
||||||
(rpgdm-ironsworn--current-character-state results)
|
(rpgdm-ironsworn--current-character-state results)
|
||||||
results)))
|
results)))
|
||||||
#+END_SRC
|
#+END_SRC
|
||||||
|
|
|
@ -2,17 +2,17 @@
|
||||||
|
|
||||||
When you traverse an area within a perilous site, envision your surroundings ([[file:/Volumes/Personal/personal/ironsworn/moves/fate/ask-the-oracle.org][Ask the Oracle]] if unsure). Then, consider your approach. If you navigate this area...
|
When you traverse an area within a perilous site, envision your surroundings ([[file:/Volumes/Personal/personal/ironsworn/moves/fate/ask-the-oracle.org][Ask the Oracle]] if unsure). Then, consider your approach. If you navigate this area...
|
||||||
|
|
||||||
- With haste: Roll +edge.
|
- With haste: Roll ~+edge~.
|
||||||
- With stealth or trickery: Roll +shadow.
|
- With stealth or trickery: Roll ~+shadow~.
|
||||||
- With observation, intuition, or expertise: Roll +wits.
|
- With observation, intuition, or expertise: Roll ~+wits~.
|
||||||
|
|
||||||
On a *strong hit*, you delve deeper. Mark progress and [[file:find-an-opportunity.org][Find an Opportunity]].
|
On a *strong hit*, you delve deeper. Mark progress and [[file:find-an-opportunity.org][Find an Opportunity]].
|
||||||
|
|
||||||
On a *weak hit*, roll on the following table according to your stat.
|
On a *weak hit*, [[elisp:rpgdm-ironsworn-delve-the-depths-weak][roll on the following table]] according to your stat.
|
||||||
|
|
||||||
On a *miss*, [[file:reveal-a-danger.org][Reveal a Danger]].
|
On a *miss*, [[file:reveal-a-danger.org][Reveal a Danger]].
|
||||||
|
|
||||||
| Edge | Shadow | Wits | Weak Hit Result |
|
| [[elisp:rpgdm-ironsworn-delve-the-depths-weak-edge][Edge]] | [[elisp:rpgdm-ironsworn-delve-the-depths-weak-shadow][Shadow]] | [[elisp:rpgdm-ironsworn-delve-the-depths-weak-wits][Wits]] | Weak Hit Result |
|
||||||
|-------+--------+-------+---------------------------------------------------|
|
|-------+--------+-------+---------------------------------------------------|
|
||||||
| 1-45 | 1-30 | 1-40 | Mark progress and Reveal a Danger. |
|
| 1-45 | 1-30 | 1-40 | Mark progress and Reveal a Danger. |
|
||||||
| 46-65 | 31-65 | 41-55 | Mark progress. |
|
| 46-65 | 31-65 | 41-55 | Mark progress. |
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
** Reveal a Danger
|
** Reveal a Danger
|
||||||
|
|
||||||
When you *encounter a risky situation within a site*, envision the danger
|
When you *encounter a risky situation within a site*, envision the danger
|
||||||
or [[elisp:(rpgdm-tables-choose "dangers")][roll on the following table]]:
|
or [[elisp:(rpgdm-tables-choose "dangers")][roll on the following table]], or better yet, call the function.
|
||||||
|
|
||||||
| Roll | Result |
|
| Roll | Result |
|
||||||
|-------+-------------------------------------------------------------|
|
|-------+-------------------------------------------------------------|
|
||||||
|
|
|
@ -1,13 +1,35 @@
|
||||||
(add-to-list 'load-path (expand-file-name "~/other/rpgdm"))
|
;;; rpgdm-ironsworn -- Functions for integrating Ironsworn with Org
|
||||||
(add-to-list 'load-path (expand-file-name "~/other/rpgdm-ironsworn"))
|
;;
|
||||||
|
;; Copyright (C) 2020 Howard X. Abrams
|
||||||
|
;;
|
||||||
|
;; Author: Howard X. Abrams <http://gitlab.com/howardabrams>
|
||||||
|
;; Maintainer: Howard X. Abrams
|
||||||
|
;; Created: September 18, 2020
|
||||||
|
;;
|
||||||
|
;; This file is not part of GNU Emacs.
|
||||||
|
;;
|
||||||
|
;;; Commentary:
|
||||||
|
;;
|
||||||
|
;; This file is conspicuously absent from commentary or even
|
||||||
|
;; comments. This is because this file is created from tangling
|
||||||
|
;; the README.org file in this directory.
|
||||||
|
;;
|
||||||
|
;;; Code:
|
||||||
|
|
||||||
(require 'rpgdm)
|
(require 'rpgdm)
|
||||||
|
|
||||||
(defvar rpgdm-ironsworn-project (file-name-directory load-file-name)
|
(defvar rpgdm-ironsworn-project (file-name-directory load-file-name)
|
||||||
"The root directory to the rpgdm-ironsworn project")
|
"The root directory to the rpgdm-ironsworn project.")
|
||||||
|
|
||||||
(defun rpgdm-ironsworn--results (action modifier one-challenge two-challenge
|
(defun rpgdm-ironsworn--results (action modifier one-challenge two-challenge
|
||||||
&optional momentum)
|
&optional momentum)
|
||||||
|
"Return formatted string for an Ironsworn dice roll results.
|
||||||
|
The ACTION is the d6 which is added to the MODIFIER (which can
|
||||||
|
have character attribute values as well as any bonuses. The sum
|
||||||
|
is compared to the two d10, ONE-CHALLENGE and TWO-CHALLENGE.
|
||||||
|
|
||||||
|
The optional MOMENTUM can be specified to add a message that the
|
||||||
|
use could burn that in order to improve the roll."
|
||||||
(unless momentum
|
(unless momentum
|
||||||
(setq momentum 0))
|
(setq momentum 0))
|
||||||
|
|
||||||
|
@ -53,8 +75,11 @@
|
||||||
matched-msg burn-msg))))
|
matched-msg burn-msg))))
|
||||||
|
|
||||||
(defun rpgdm-ironsworn-roll (modifier &optional momentum)
|
(defun rpgdm-ironsworn-roll (modifier &optional momentum)
|
||||||
"Display a Hit/Miss message based on comparing a d6 action
|
"Display a Hit/Miss message based on an Ironsworn roll.
|
||||||
roll (added to MODIFIER) vs. two d10 challenge dice."
|
Done by rolling and comparing a d6 action roll (summed with
|
||||||
|
MODIFIER) vs two d10 challenge dice. If given, the MOMENTUM may
|
||||||
|
trigger a message to the user that they can burn that for better
|
||||||
|
results."
|
||||||
(interactive "nModifier: ")
|
(interactive "nModifier: ")
|
||||||
(let ((one-challenge (rpgdm--roll-die 10))
|
(let ((one-challenge (rpgdm--roll-die 10))
|
||||||
(two-challenge (rpgdm--roll-die 10))
|
(two-challenge (rpgdm--roll-die 10))
|
||||||
|
@ -64,7 +89,9 @@ roll (added to MODIFIER) vs. two d10 challenge dice."
|
||||||
momentum))))
|
momentum))))
|
||||||
|
|
||||||
(defun rpgdm-ironsworn--new-character-template (name)
|
(defun rpgdm-ironsworn--new-character-template (name)
|
||||||
"Insert a basic Ironsworn template at the end of the current buffer."
|
"Insert basic Ironsworn template at the end of the current buffer.
|
||||||
|
A header is created with NAME, but if this is an empty string,
|
||||||
|
a random name is generated for the purposes of the template."
|
||||||
(when (s-blank? name)
|
(when (s-blank? name)
|
||||||
(setq name (rpgdm-tables-choose "names-ironlander")))
|
(setq name (rpgdm-tables-choose "names-ironlander")))
|
||||||
|
|
||||||
|
@ -122,7 +149,7 @@ the `assets' directory, otherwise, we return a cached version."
|
||||||
(cdr))))
|
(cdr))))
|
||||||
|
|
||||||
(defun rpgdm-ironsworn-insert-character-asset (asset)
|
(defun rpgdm-ironsworn-insert-character-asset (asset)
|
||||||
"Choose and insert the contents of an asset in the current buffer."
|
"Choose and insert the contents of an ASSET in the current buffer."
|
||||||
(interactive (list (rpgdm-ironsworn--pick-character-asset)))
|
(interactive (list (rpgdm-ironsworn--pick-character-asset)))
|
||||||
(let ((file (if (consp asset) (cdr asset) asset)))
|
(let ((file (if (consp asset) (cdr asset) asset)))
|
||||||
(insert-file-contents file nil)
|
(insert-file-contents file nil)
|
||||||
|
@ -133,7 +160,7 @@ the `assets' directory, otherwise, we return a cached version."
|
||||||
|
|
||||||
(defun rpgdm-ironsworn--good-character-assets (asset-files)
|
(defun rpgdm-ironsworn--good-character-assets (asset-files)
|
||||||
"Return ASSET-FILES if all given are _good enough_.
|
"Return ASSET-FILES if all given are _good enough_.
|
||||||
That is, all are unique, only one companion, etc."
|
That is, all are unique, only one companion, etc."
|
||||||
(cl-flet ((companion-p (entry)
|
(cl-flet ((companion-p (entry)
|
||||||
(when (consp entry)
|
(when (consp entry)
|
||||||
(setq entry (cdr entry)))
|
(setq entry (cdr entry)))
|
||||||
|
@ -167,6 +194,8 @@ The chosen assets are _good_ in that they won't have duplicates, etc."
|
||||||
(good-enough-list (rpgdm-ironsworn-character-assets)))
|
(good-enough-list (rpgdm-ironsworn-character-assets)))
|
||||||
|
|
||||||
(defun rpgdm-ironsworn-random-character-assets (&optional number-of-assets)
|
(defun rpgdm-ironsworn-random-character-assets (&optional number-of-assets)
|
||||||
|
"Return the file names of NUMBER-OF-ASSETS from the `assets' directory.
|
||||||
|
The chosen assets are _good_ in that they won't have duplicates, etc."
|
||||||
(interactive "nHow many random assets should we insert? ")
|
(interactive "nHow many random assets should we insert? ")
|
||||||
(dolist (file (rpgdm-ironsworn--random-character-assets number-of-assets))
|
(dolist (file (rpgdm-ironsworn--random-character-assets number-of-assets))
|
||||||
(rpgdm-ironsworn-insert-character-asset file)))
|
(rpgdm-ironsworn-insert-character-asset file)))
|
||||||
|
@ -181,9 +210,10 @@ The chosen assets are _good_ in that they won't have duplicates, etc."
|
||||||
(call-interactively 'rpgdm-ironsworn-insert-character-asset))))
|
(call-interactively 'rpgdm-ironsworn-insert-character-asset))))
|
||||||
|
|
||||||
(defun rpgdm-ironsworn--new-character-stats ()
|
(defun rpgdm-ironsworn--new-character-stats ()
|
||||||
"Query the user for a new character's stats, and add them as
|
"Insert character stats after querying user for them.
|
||||||
properties using the `rpgdm-ironsworn-store-character-state' and
|
Note: The stats are added as properties using the
|
||||||
the `rpgdm-ironsworn-progress-create' functions."
|
`rpgdm-ironsworn-store-character-state' and the
|
||||||
|
`rpgdm-ironsworn-progress-create' functions."
|
||||||
(dolist (stat '(edge heart iron shadow wits))
|
(dolist (stat '(edge heart iron shadow wits))
|
||||||
(rpgdm-ironsworn-store-character-state stat
|
(rpgdm-ironsworn-store-character-state stat
|
||||||
(read-string (format "What '%s' stat: " stat))))
|
(read-string (format "What '%s' stat: " stat))))
|
||||||
|
@ -200,13 +230,15 @@ the `rpgdm-ironsworn-progress-create' functions."
|
||||||
(insert (format " - Your home settlement of %s\n" (rpgdm-tables-choose "settlement-names"))))
|
(insert (format " - Your home settlement of %s\n" (rpgdm-tables-choose "settlement-names"))))
|
||||||
|
|
||||||
(defun rpgdm-ironsworn--new-character-stats-first (&optional name)
|
(defun rpgdm-ironsworn--new-character-stats-first (&optional name)
|
||||||
"Insert a new character template, query for the stats, then insert assets."
|
"Insert a new character template for character, NAME.
|
||||||
|
The character stats are first queried, and then assets inserted."
|
||||||
(rpgdm-ironsworn--new-character-template name)
|
(rpgdm-ironsworn--new-character-template name)
|
||||||
(rpgdm-ironsworn--new-character-stats)
|
(rpgdm-ironsworn--new-character-stats)
|
||||||
(rpgdm-ironsworn--new-character-assets))
|
(rpgdm-ironsworn--new-character-assets))
|
||||||
|
|
||||||
(defun rpgdm-ironsworn--new-character-assets-first (&optional name)
|
(defun rpgdm-ironsworn--new-character-assets-first (&optional name)
|
||||||
"Insert a new character template, insert assets then query for the stats."
|
"Insert a new character template for character, NAME.
|
||||||
|
The assets are inserted first, and then character stats are queried."
|
||||||
(rpgdm-ironsworn--new-character-template name)
|
(rpgdm-ironsworn--new-character-template name)
|
||||||
;; Saving and restoring point, means the properties should be in the
|
;; Saving and restoring point, means the properties should be in the
|
||||||
;; correct, top-level position.
|
;; correct, top-level position.
|
||||||
|
@ -216,8 +248,10 @@ the `rpgdm-ironsworn-progress-create' functions."
|
||||||
|
|
||||||
(defun rpgdm-ironsworn-new-character (name order)
|
(defun rpgdm-ironsworn-new-character (name order)
|
||||||
"Interactively query the user for a new character's attribute.
|
"Interactively query the user for a new character's attribute.
|
||||||
This function _appends_ this information to the current buffer,
|
The NAME is the character's name, and ORDER determines how the
|
||||||
which should be using the `org-mode' major mode."
|
template will generate and query the user for the rest of the data.
|
||||||
|
This function _appends_ this information to the current buffer,
|
||||||
|
which should be using the `org-mode' major mode."
|
||||||
(interactive (list
|
(interactive (list
|
||||||
(read-string "What is the new character's name? ")
|
(read-string "What is the new character's name? ")
|
||||||
(completing-read "What order should we build this? " '("Statistics first" "Assets first"))))
|
(completing-read "What order should we build this? " '("Statistics first" "Assets first"))))
|
||||||
|
@ -227,6 +261,8 @@ the `rpgdm-ironsworn-progress-create' functions."
|
||||||
(message "Alright, the template is complete. Edit away!" name))
|
(message "Alright, the template is complete. Edit away!" name))
|
||||||
|
|
||||||
(defun rpgdm-ironsworn--display-stat (stat character)
|
(defun rpgdm-ironsworn--display-stat (stat character)
|
||||||
|
"Colorized the STAT from a CHARACTER hash containing it.
|
||||||
|
See `rpgdm-ironsworn-character-display'."
|
||||||
(let* ((value (gethash stat character))
|
(let* ((value (gethash stat character))
|
||||||
(s-val (number-to-string value))
|
(s-val (number-to-string value))
|
||||||
(color (cond
|
(color (cond
|
||||||
|
@ -255,7 +291,7 @@ Health: %s Spirit: %s Supply: %s Momentum: %d"
|
||||||
(gethash 'momentum character 5))))
|
(gethash 'momentum character 5))))
|
||||||
|
|
||||||
(defun rpgdm-ironsworn-to-string (a)
|
(defun rpgdm-ironsworn-to-string (a)
|
||||||
"Return a lowercase string from either a string, keyword or symbol."
|
"Return a lowercase string from either A, a string, keyword or symbol."
|
||||||
(downcase
|
(downcase
|
||||||
(cond
|
(cond
|
||||||
((keywordp a) (substring (symbol-name a) 1))
|
((keywordp a) (substring (symbol-name a) 1))
|
||||||
|
@ -269,13 +305,16 @@ Health: %s Spirit: %s Supply: %s Momentum: %d"
|
||||||
(lambda (s) (sxhash-equal (rpgdm-ironsworn-to-string s))))
|
(lambda (s) (sxhash-equal (rpgdm-ironsworn-to-string s))))
|
||||||
|
|
||||||
(defun rpgdm-ironsworn-character-stat (stat &optional character)
|
(defun rpgdm-ironsworn-character-stat (stat &optional character)
|
||||||
"Return integer value associated with a character's STAT."
|
"Return integer value associated with a character's STAT.
|
||||||
|
If CHARACTER doesn't refer to a character hash, then this calls
|
||||||
|
the `rpgdm-ironsworn-current-character-state' function."
|
||||||
(when (null character)
|
(when (null character)
|
||||||
(setq character (rpgdm-ironsworn-current-character-state)))
|
(setq character (rpgdm-ironsworn-current-character-state)))
|
||||||
(gethash stat character 1))
|
(gethash stat character 1))
|
||||||
|
|
||||||
(defun rpgdm-ironsworn-adjust-stat (stat adj &optional default)
|
(defun rpgdm-ironsworn-adjust-stat (stat adj &optional default)
|
||||||
"Increase or decrease the current character's STAT by ADJ."
|
"Increase or decrease the current character's STAT by ADJ.
|
||||||
|
If the STAT isn't found, returns DEFAULT."
|
||||||
(let* ((curr (rpgdm-ironsworn-character-stat stat))
|
(let* ((curr (rpgdm-ironsworn-character-stat stat))
|
||||||
(new (+ curr adj)))
|
(new (+ curr adj)))
|
||||||
(rpgdm-ironsworn-store-character-state stat new)))
|
(rpgdm-ironsworn-store-character-state stat new)))
|
||||||
|
@ -353,6 +392,9 @@ Health: %s Spirit: %s Supply: %s Momentum: %d"
|
||||||
(rpgdm-ironsworn-character-stat :supply)))
|
(rpgdm-ironsworn-character-stat :supply)))
|
||||||
|
|
||||||
(defun rpgdm-ironsworn--move-tuple (file)
|
(defun rpgdm-ironsworn--move-tuple (file)
|
||||||
|
"Return a list of a string representation of FILE, and FILE.
|
||||||
|
The string representation is created by looking at the parent
|
||||||
|
directory and file name."
|
||||||
(let* ((regx (rx "moves/"
|
(let* ((regx (rx "moves/"
|
||||||
(group (one-or-more (not "/")))
|
(group (one-or-more (not "/")))
|
||||||
"/"
|
"/"
|
||||||
|
@ -367,12 +409,14 @@ Health: %s Spirit: %s Supply: %s Momentum: %d"
|
||||||
(s-replace-regexp "-" " "))))
|
(s-replace-regexp "-" " "))))
|
||||||
(list (format "%s :: %s" type name) file)))
|
(list (format "%s :: %s" type name) file)))
|
||||||
|
|
||||||
(defvar rpgdm-ironsworn-moves () "A list of tuples of the move and the file containing its goodness.")
|
(defvar rpgdm-ironsworn-moves ()
|
||||||
|
"A list of tuples of the move and the file containing its goodness.")
|
||||||
|
|
||||||
(defun rpgdm-ironsworn-moves ()
|
(defun rpgdm-ironsworn-moves ()
|
||||||
"Return a list containing available moves, and the filename containing
|
"Return a list containing available moves and its filename.
|
||||||
the moves instructions, and other properties. Note that this function is
|
The file contains the move's instructions and other properties. Note
|
||||||
memoized, in that re-calling this function will return a cached copy."
|
that this function is memoized, in that re-calling this function
|
||||||
|
will return a cached copy."
|
||||||
(unless rpgdm-ironsworn-moves
|
(unless rpgdm-ironsworn-moves
|
||||||
(setq rpgdm-ironsworn-moves
|
(setq rpgdm-ironsworn-moves
|
||||||
(mapcar 'rpgdm-ironsworn--move-tuple
|
(mapcar 'rpgdm-ironsworn--move-tuple
|
||||||
|
@ -381,14 +425,22 @@ Health: %s Spirit: %s Supply: %s Momentum: %d"
|
||||||
".*\.org$"))))
|
".*\.org$"))))
|
||||||
rpgdm-ironsworn-moves)
|
rpgdm-ironsworn-moves)
|
||||||
|
|
||||||
|
(defun completing-read-value (prompt values)
|
||||||
|
"Like `completing-read' but returns the 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)
|
||||||
|
(assoc values)
|
||||||
|
(second)))
|
||||||
|
|
||||||
(defun rpgdm-ironsworn-choose-move ()
|
(defun rpgdm-ironsworn-choose-move ()
|
||||||
(let* ((move (completing-read "Move: " (rpgdm-ironsworn-moves)))
|
"A `completing-read' for moves, but returns the move filename."
|
||||||
(tuple (assoc move (rpgdm-ironsworn-moves))))
|
(completing-read-value "Move: " (rpgdm-ironsworn-moves)))
|
||||||
(cadr tuple)))
|
|
||||||
|
|
||||||
(defun rpgdm-ironsworn--store-move (title results)
|
(defun rpgdm-ironsworn--store-move (title results)
|
||||||
"Store the results in a `m' register. It should also include
|
"Store RESULTS in `m' register for later pasting.
|
||||||
the name of the move, based on the current file."
|
The register also has TITLE, the name of the move, based on the
|
||||||
|
current file."
|
||||||
(set-register ?m (format "# %s ... %s " title results)))
|
(set-register ?m (format "# %s ... %s " title results)))
|
||||||
|
|
||||||
(defun rpgdm-ironsworn-make-move (move-file)
|
(defun rpgdm-ironsworn-make-move (move-file)
|
||||||
|
@ -438,11 +490,11 @@ See `rpgdm-ironsworn-roll-stat' for details."
|
||||||
(cl-flet* ((faded (str) (propertize str 'face '(:foreground "#888")))
|
(cl-flet* ((faded (str) (propertize str 'face '(:foreground "#888")))
|
||||||
(msg (a b) (format "%s %s %s" a (faded "--") (faded b))))
|
(msg (a b) (format "%s %s %s" a (faded "--") (faded b))))
|
||||||
(defvar
|
(defvar
|
||||||
rpgdm-ironsworn-progress-levels `((,(msg "troublesome" "quick") . 12)
|
rpgdm-ironsworn-progress-levels `((,(msg "troublesome" "quick") 12)
|
||||||
(,(msg "dangerous" "short") . 8)
|
(,(msg "dangerous" "short") 8)
|
||||||
(,(msg "formidable" "long") . 4)
|
(,(msg "formidable" "long") 4)
|
||||||
(,(msg "extreme" "very long") . 2)
|
(,(msg "extreme" "very long") 2)
|
||||||
(,(msg "epic" "never-ending") . 1))
|
(,(msg "epic" "never-ending") 1))
|
||||||
"The five levels of progression for an Ironsworn progress track."))
|
"The five levels of progression for an Ironsworn progress track."))
|
||||||
|
|
||||||
(defun rpgdm-ironsworn-progress-level (label)
|
(defun rpgdm-ironsworn-progress-level (label)
|
||||||
|
@ -473,13 +525,27 @@ of squares that have been marked against some progress."
|
||||||
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."
|
NAME should be a short title, not a description."
|
||||||
(interactive (list (read-string "Progress Name: ")
|
(interactive (list (read-string "Progress Name: ")
|
||||||
(completing-read "Progress Level: "
|
(completing-read-value "Progress Level: "
|
||||||
rpgdm-ironsworn-progress-levels)))
|
rpgdm-ironsworn-progress-levels)))
|
||||||
|
|
||||||
(let* ((level-value (rpgdm-ironsworn-progress-level level))
|
(let* ((track-id (substring (secure-hash 'md5 name) 0 8))
|
||||||
(track-id (substring (secure-hash 'md5 name) 0 8))
|
|
||||||
(track-prop (format "ironsworn-progress-%s" track-id))
|
(track-prop (format "ironsworn-progress-%s" track-id))
|
||||||
(track-val (format "\"%s\" %d %d" name level-value 0)))
|
(track-val (format "\"%s\" %d %d" name level 0))
|
||||||
|
|
||||||
|
(title (org-get-heading))
|
||||||
|
(option '(("At the same level as a sibling?" same-level)
|
||||||
|
("As a subheading to this?" subheading)
|
||||||
|
("No new heading. Re-use this." no))))
|
||||||
|
|
||||||
|
(cl-case (completing-read-value "Create a new heading? " option)
|
||||||
|
('same-level (progn
|
||||||
|
(org-insert-heading-respect-content)
|
||||||
|
(insert name)))
|
||||||
|
('subheading (progn
|
||||||
|
(org-insert-heading-respect-content)
|
||||||
|
(org-shiftmetaright)
|
||||||
|
(insert name))))
|
||||||
|
|
||||||
(org-set-property track-prop track-val)))
|
(org-set-property track-prop track-val)))
|
||||||
|
|
||||||
(defun rpgdm-ironsworn-progress-mark (name &optional times)
|
(defun rpgdm-ironsworn-progress-mark (name &optional times)
|
||||||
|
@ -523,8 +589,81 @@ to rolling two d10 challenge dice."
|
||||||
(ignore-errors
|
(ignore-errors
|
||||||
(remhash name tracks))))
|
(remhash name tracks))))
|
||||||
|
|
||||||
|
(defun rpgdm-ironsworn-discover-a-site (theme domain)
|
||||||
|
"Store a Delve Site information in the org file."
|
||||||
|
(interactive
|
||||||
|
(list
|
||||||
|
(completing-read "What is the site theme? " rpgdm-ironsworn-site-themes)
|
||||||
|
(completing-read "What is the domain? " rpgdm-ironsworn-site-domains)))
|
||||||
|
|
||||||
|
(rpgdm-ironsworn-progress-create
|
||||||
|
(read-string "Site Name: "
|
||||||
|
(rpgdm-ironsworn-oracle-site-name domain))
|
||||||
|
(completing-read-value "Progress Level: "
|
||||||
|
rpgdm-ironsworn-progress-levels))
|
||||||
|
(next-line 2)
|
||||||
|
(rpgdm-ironsworn-store-character-state 'site-theme (downcase theme))
|
||||||
|
(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."
|
||||||
|
(interactive (list (completing-read "Stat Choice: "
|
||||||
|
'("wits" "shadow" "edge"))))
|
||||||
|
(let ((table-name (format "delve/weak-hit/%s" stat)))
|
||||||
|
(message "Rolling on %s" table-name)
|
||||||
|
(rpgdm-tables-choose table-name)))
|
||||||
|
|
||||||
|
(defun rpgdm-ironsworn-delve-the-depths-weak-edge ()
|
||||||
|
(interactive)
|
||||||
|
(rpgdm-ironsworn-delve-the-depths-weak "edge"))
|
||||||
|
|
||||||
|
(defun rpgdm-ironsworn-delve-the-depths-weak-shadow ()
|
||||||
|
(interactive)
|
||||||
|
(rpgdm-ironsworn-delve-the-depths-weak "shadow"))
|
||||||
|
|
||||||
|
(defun rpgdm-ironsworn-delve-the-depths-weak-wits ()
|
||||||
|
(interactive)
|
||||||
|
(rpgdm-ironsworn-delve-the-depths-weak "wits"))
|
||||||
|
|
||||||
|
(defun rpgdm-ironsworn--reveal-a-danger ()
|
||||||
|
"Return a random danger appropriate for Delve sites.
|
||||||
|
For instance, if the `danger' table states to consult the theme
|
||||||
|
or domain tables, this reads the `site-theme' and `site-domain'
|
||||||
|
properties in the current org file, and rolls on the appropriate
|
||||||
|
chart."
|
||||||
|
(let* ((theme (rpgdm-ironsworn-character-stat 'site-theme))
|
||||||
|
(domain (rpgdm-ironsworn-character-stat 'site-domain))
|
||||||
|
(danger (rpgdm-tables-choose "danger")))
|
||||||
|
(cond
|
||||||
|
((equal danger "Check the theme card.")
|
||||||
|
(rpgdm-tables-choose (format "danger/theme/%s" theme)))
|
||||||
|
|
||||||
|
((equal danger "Check the domain card.")
|
||||||
|
(rpgdm-tables-choose (format "danger/domain/%s" theme)))
|
||||||
|
|
||||||
|
(t danger))))
|
||||||
|
|
||||||
|
(defun rpgdm-ironsworn-reveal-a-danger ()
|
||||||
|
"Display a random danger appropriate for Delve sites.
|
||||||
|
For instance, if the `danger' table states to consult the theme
|
||||||
|
or domain tables, this reads the `site-theme' and `site-domain'
|
||||||
|
properties in the current org file, and rolls on the appropriate
|
||||||
|
chart."
|
||||||
|
(interactive)
|
||||||
|
(rpgdm-message "Revealed Danger: %s" (rpgdm-ironsworn--reveal-a-danger)))
|
||||||
|
|
||||||
(rpgdm-tables-load (f-join rpgdm-ironsworn-project "tables"))
|
(rpgdm-tables-load (f-join rpgdm-ironsworn-project "tables"))
|
||||||
|
|
||||||
|
(defvar rpgdm-ironsworn-site-themes
|
||||||
|
(progn (rpgdm-tables-choose "site/theme")
|
||||||
|
(gethash "site/theme" rpgdm-tables))
|
||||||
|
"A list of the Delve site themes.")
|
||||||
|
|
||||||
|
(defvar rpgdm-ironsworn-site-domains
|
||||||
|
(progn (rpgdm-tables-choose "site/domain")
|
||||||
|
(gethash "site/domain" rpgdm-tables))
|
||||||
|
"A list of the Delve site domains.")
|
||||||
|
|
||||||
(defun rpgdm-ironsworn-oracle-action-theme ()
|
(defun rpgdm-ironsworn-oracle-action-theme ()
|
||||||
"Rolls on two tables at one time."
|
"Rolls on two tables at one time."
|
||||||
(interactive)
|
(interactive)
|
||||||
|
@ -605,7 +744,7 @@ You'll need to pick and choose what works and discard what doesn't."
|
||||||
(let ((description (rpgdm-tables-choose "site/name/description"))
|
(let ((description (rpgdm-tables-choose "site/name/description"))
|
||||||
(detail (rpgdm-tables-choose "site/name/detail"))
|
(detail (rpgdm-tables-choose "site/name/detail"))
|
||||||
(namesake (rpgdm-tables-choose "site/name/namesake"))
|
(namesake (rpgdm-tables-choose "site/name/namesake"))
|
||||||
(place (rpgdm-tables-choose (format "site/name/place/%s" place-type)))
|
(place (rpgdm-tables-choose (format "site/name/place/%s" (downcase place-type))))
|
||||||
(roll (rpgdm--roll-die 100)))
|
(roll (rpgdm--roll-die 100)))
|
||||||
(rpgdm-message
|
(rpgdm-message
|
||||||
(cond
|
(cond
|
||||||
|
@ -692,23 +831,33 @@ You'll need to pick and choose what works and discard what doesn't."
|
||||||
("s" rpgdm-ironsworn-oracle-site-nature "Site Nature")
|
("s" rpgdm-ironsworn-oracle-site-nature "Site Nature")
|
||||||
("t" rpgdm-ironsworn-oracle-threat-goal "Threat's Goal"))
|
("t" rpgdm-ironsworn-oracle-threat-goal "Threat's Goal"))
|
||||||
|
|
||||||
|
(defhydra hydra-rpgdm-delve (:color blue)
|
||||||
|
"Delve site actions"
|
||||||
|
("n" rpgdm-ironsworn-discover-a-site "discover a site")
|
||||||
|
("w" rpgdm-ironsworn-delve-the-depths-weak "weak hit table")
|
||||||
|
("d" rpgdm-ironsworn-reveal-a-danger "reveal a danger")
|
||||||
|
("m" rpgdm-ironsworn-progress-mark "mark progress")
|
||||||
|
("p" rpgdm-ironsworn-progress-amount "show progress")
|
||||||
|
("x" rpgdm-ironsworn-progress-delete "delete")
|
||||||
|
("r" rpgdm-ironsworn-progress-roll "escape the depths"))
|
||||||
|
|
||||||
(defhydra hydra-rpgdm-progress (:color blue)
|
(defhydra hydra-rpgdm-progress (:color blue)
|
||||||
"Progress Tracks"
|
"Progress Tracks"
|
||||||
("n" rpgdm-ironsworn-progress-create "new")
|
("n" rpgdm-ironsworn-progress-create "new")
|
||||||
("m" rpgdm-ironsworn-progress-mark "mark")
|
("m" rpgdm-ironsworn-progress-mark "mark")
|
||||||
("p" rpgdm-ironsworn-progress-amount "show")
|
("p" rpgdm-ironsworn-progress-amount "show")
|
||||||
("d" rpgdm-ironsworn-progress-delete "delete")
|
("x" rpgdm-ironsworn-progress-delete "delete")
|
||||||
("r" rpgdm-ironsworn-progress-roll "roll"))
|
("r" rpgdm-ironsworn-progress-roll "roll"))
|
||||||
|
|
||||||
(defhydra hydra-rpgdm (:color blue :hint nil)
|
(defhydra hydra-rpgdm (:color blue :hint nil)
|
||||||
"
|
"
|
||||||
^Dice^ 0=d100 1=d10 6=d6 ^Roll/Adjust^ ^Oracles/Tables^ ^Moving/Editing^ ^Messages^
|
^Dice^ 0=d100 1=d10 6=d6 ^Roll/Adjust^ ^Oracles/Tables^ ^Moving/Editing^ ^Messages^
|
||||||
----------------------------------------------------------------------------------------------------------------------------------------------------
|
----------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
_d_: Roll Dice _p_: Progress _l_/_L_: Health _z_/_Z_: Yes/No Oracle _o_: Links ⌘-h: Show Stats
|
_D_: Roll Dice _p_: Progress _l_/_L_: Health _z_/_Z_: Yes/No Oracle _o_: Links ⌘-h: Show Stats
|
||||||
_e_: Roll Edge _h_: Roll Shadow _t_/_T_: Spirit _c_/_C_: Show Oracle _J_/_K_: Page up/dn ⌘-l: Last Results
|
_e_: Roll Edge _h_: Roll Shadow _t_/_T_: Spirit _c_/_C_: Show Oracle _J_/_K_: Page up/dn ⌘-l: Last Results
|
||||||
_r_: Roll Heart _w_: Roll Wits _s_/_S_: Supply _O_: Load Oracles _N_/_W_: Narrow/Widen ⌘-k: ↑ Previous
|
_r_: Roll Heart _w_: Roll Wits _s_/_S_: Supply _O_: Load Oracles _N_/_W_: Narrow/Widen ⌘-k: ↑ Previous
|
||||||
_i_: Roll Iron _m_: Make Move _M_: Momentum _y_/_Y_: Yank/Move ⌘-j: ↓ Next "
|
_i_: Roll Iron _m_: Make Move _M_: Momentum _d_: Delve Actions _y_/_Y_: Yank/Move ⌘-j: ↓ Next "
|
||||||
("d" rpgdm-ironsworn-roll) ("D" rpgdm-ironsworn-progress-roll)
|
("D" rpgdm-ironsworn-roll)
|
||||||
("z" rpgdm-ironsworn-oracle) ("Z" rpgdm-yes-and-50/50)
|
("z" rpgdm-ironsworn-oracle) ("Z" rpgdm-yes-and-50/50)
|
||||||
|
|
||||||
("e" rpgdm-ironsworn-roll-edge)
|
("e" rpgdm-ironsworn-roll-edge)
|
||||||
|
@ -727,6 +876,8 @@ You'll need to pick and choose what works and discard what doesn't."
|
||||||
("M" rpgdm-ironsworn-adjust-momentum :color pink)
|
("M" rpgdm-ironsworn-adjust-momentum :color pink)
|
||||||
|
|
||||||
("O" rpgdm-tables-load) ("c" rpgdm-tables-choose) ("C" rpgdm-tables-choose :color pink)
|
("O" rpgdm-tables-load) ("c" rpgdm-tables-choose) ("C" rpgdm-tables-choose :color pink)
|
||||||
|
|
||||||
|
("d" hydra-rpgdm-delve/body)
|
||||||
("p" hydra-rpgdm-progress/body)
|
("p" hydra-rpgdm-progress/body)
|
||||||
|
|
||||||
("o" ace-link) ("N" org-narrow-to-subtree) ("W" widen)
|
("o" ace-link) ("N" org-narrow-to-subtree) ("W" widen)
|
||||||
|
@ -813,9 +964,15 @@ Note that values in sibling trees are ignored, and settings in
|
||||||
lower levels of the tree headings take precedence."
|
lower levels of the tree headings take precedence."
|
||||||
(save-excursion
|
(save-excursion
|
||||||
(let ((results (make-hash-table :test 'str-or-keys)))
|
(let ((results (make-hash-table :test 'str-or-keys)))
|
||||||
(unless (eq 'headline (org-element-type (org-element-at-point)))
|
(unless (org-at-heading-p)
|
||||||
(org-up-element))
|
(org-up-element))
|
||||||
|
|
||||||
|
;; Put the lowest heading title in the results hashtable:
|
||||||
|
(puthash 'title (thread-first
|
||||||
|
(org-element-at-point)
|
||||||
|
(second)
|
||||||
|
(plist-get :raw-value))
|
||||||
|
results)
|
||||||
(rpgdm-ironsworn--current-character-state results)
|
(rpgdm-ironsworn--current-character-state results)
|
||||||
results)))
|
results)))
|
||||||
|
|
||||||
|
|
8
tables/delve/weak-hit/edge.org
Normal file
8
tables/delve/weak-hit/edge.org
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
#+TITLE: Weak Hit Table for Edge
|
||||||
|
|
||||||
|
Roll on Table: d100
|
||||||
|
| 1-45 | Mark progress and Reveal a Danger. |
|
||||||
|
| 46-65 | Mark progress. |
|
||||||
|
| 66-75 | Choose one: Mark progress or Find an Opportunity. |
|
||||||
|
| 76-80 | Take both: Mark progress and Find an Opportunity. |
|
||||||
|
| 81-00 | Mark progress twice and Reveal a Danger. |
|
8
tables/delve/weak-hit/shadow.org
Normal file
8
tables/delve/weak-hit/shadow.org
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
#+TITLE: Weak Hit Table for Shadow
|
||||||
|
|
||||||
|
Roll on Table: d100
|
||||||
|
| 1-30 | Mark progress and Reveal a Danger. |
|
||||||
|
| 31-65 | Mark progress. |
|
||||||
|
| 66-90 | Choose one: Mark progress or Find an Opportunity. |
|
||||||
|
| 91-99 | Take both: Mark progress and Find an Opportunity. |
|
||||||
|
| 00 | Mark progress twice and Reveal a Danger. |
|
8
tables/delve/weak-hit/wits.org
Normal file
8
tables/delve/weak-hit/wits.org
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
#+TITLE: Weak Hit Table for Wits
|
||||||
|
|
||||||
|
Roll on Table: d100
|
||||||
|
| 1-40 | Mark progress and Reveal a Danger. |
|
||||||
|
| 41-55 | Mark progress. |
|
||||||
|
| 56-80 | Choose one: Mark progress or Find an Opportunity. |
|
||||||
|
| 81-99 | Take both: Mark progress and Find an Opportunity. |
|
||||||
|
| 00 | Mark progress twice and Reveal a Danger. |
|
Loading…
Reference in a new issue