lifelike / decide-mode

Random decisions for emacs, with functions and a minor mode. Roll various types of dice etc.
49 stars 12 forks source link

A ? followed by space, enter, or a closing parenthesis will insert the ? itself and the next key as expected, so normally /decide-mode/ should not interfere with typing.

The default binding of "? ?" (since version 0.7) is /decide-dwim-insert/, a function that looks in the buffer immediately before point and if it finds a dice or range specification there it will replace it with the result of rolling the dice or picking a random number from the range. If no dice or range is found it will fall back to the normal /decide-for-me-normal/ function that outputs a simple YES or NO result.

See the decide.el file itself for some documentation and a list of all the keybindings in /decide-mode/. There is an overview of important features below, but all the details and more features can be found in the source. ** Yes or No The simplest function of /decide-mode/ is /decide-for-me-normal/ that will insert a /Yes/ or /No/ with equal probability. By default it is triggered by pressing "? ?", unless what is in the buffer just before point is a valid dice-specification or range (see descriptions of those below), in which case that will be used instead.

To get a Yes only with 33% probability use "? -" (/decide-for-me-unlikely/) and for 67% probability "? +" (/decide-for-me-likely/).

When inserting a Yes or No using these functions there will sometimes, randomly, be a + or - inserted as well. Those can be ignored or interpreted as for instance "and" and "or", for use in some RPG systems. The probability of a + or - appearing will depend on which of the functions is called (see the confusingly named function /decide-for-me-dice/ for the exact probabilities). ** Installation Load the file /decide.el/ (e.g. /(load-file "~/.emacs.d/lisp/decide.el")) and then enable it in a buffer by running /M-x decide-mode/.

To always have it enabled for a specific major-mode, add it to the appropriate hook, e.g.:

+BEGIN_EXAMPLE

(defun my-org-mode-hook () (decide-mode 1)) (add-hook 'org-mode-hook 'my-org-mode-hook))

+END_EXAMPLE

To only enable it for a specific file, check the documentation for [[https://www.gnu.org/software/emacs/manual/html_node/emacs/File-Variables.html][GNU Emacs File Variables]], and of course it can also be [[https://www.gnu.org/software/emacs/manual/html_node/emacs/Directory-Variables.html][for an entire directory]]. ** Die Rolls Die-rolls are specified in common dice-notation, like 3d6 for rolling 3 6-sided dice, or 2d4+1 to roll 2 4-sided dice and add 1 to the result. If the number of dice is not given (e.g. d10) it is assumed to be a single die. If the number of sides is not given (e.g. 2d) a standard d6 is assumed, but that can be configured in the variable /decide-default-dice-faces/.

There are several ways to roll dice using /decide-mode/. The interactive function /decide-roll-dice/ will ask for a dice specification and then immediately insert the results of rolling that. The default keybinding "? d" will call that function. There are also some bindings that are "?" followed by one or more digits that will roll a single die immediately, e.g. "? 8" to roll 1d8 or "? 2 0" to roll 1d20. See the list at the end of decide.el. A few special bindings are also included, like "? %" to 1d100 and "? f" to roll 4dF. Common 1d6 can be rolled with "? 6", or 2d6 with "? D".

Dice are also rolled when pressing "? ?" (/decide-dwim-insert/) if point is immediately preceded by what can be parsed as a valid dice-specification.

It is also possible to use custom named dice that can have any number of sides that has any text on. Each side must still be given a value, as the sum of all rolled dice is always printed. Custom dice are specified in the variable /decide-custom-dice/ Included by default are dice F (for Fudge/Fate dice), S (results in Fail or Success), B6 (for rolling a bucket of dice, counting 6s as hits), B5 (like B6 but hits on 5-6), B4 (you get the idea), B3, B2, and A (average dice, a 6-sided die labelled 2, 3, 3, 4, 4, 5). To roll a custom die just use its name where the number of sides of a die would normally be, e.g. 4dF to roll 4 Fudge/Fate dice.

Custom dice can be given names of any length, but case is ignored, so a dF is the same as a df. It is thus not possible to specify dice that have the same names only differing in case. ** Random Ranges Ranges are a simpler way to specify a range of random numbers than to use dice. The default key-binding for ranges is "? r". The simplest range is just n-m, where n and m are integers (m must be positive) and m is greater than n. The inserted random number will be from n to m, inclusive. The range 1-6 is equivalent to rolling a standard 1d6.

Ranges also support some special syntax to make some numbers in the range more likely. Including more dashes between the numbers makes results in the middle of the range more likely by effectively generating as many random values as the number of dashes and then picking the median of all those numbers. The range 10---20 for instance would insert a number from 10 to 20, but numbers close to 15 would be more likely. Using greater-than or lower-than characters instead between the numbers will tend towards higher or lower numbers, by generating as many numbers as indicated and then picking the highest or lowest, so 1>>6 is effectively like rolling 2d6 and picking the highest rolled. It makes no sense to use only a single < or >.

The default binding for "? ?" will generate a random number from a range if point is immediately preceded by what can be parsed as a valid range specification. ** Random Choices The function /decide-random-choice/, by default bound to "? c", asks for a comma-separated list of things and then inserts one of those chosen at random. A random direction can for instance be requested by pressing "? c" and then "N,S,W,E" or a random color with "red,blue,green".

Some lists of choices are available at default key-bindings that can be seen at the end of the decide.el file. For instance the random directions in the last paragraph are available by pressing "? w 4" and there are several other similar bindings included.

See the Random Tables below for a more powerful way of asking for a random choice. A random choice using "? c" is good for a quick ad-hoc choice as it does not require setting up a table with choices. Choices are saved in mini-buffer history, and thus easily available to make new similar choices again until Emacs is restarted, but for more permanent lists of things to draw from it is better to create a table or set up a key-binding to call /decide-random-choice/ (see the functions at the end of decide.el for how to do that easily). ** Random Tables The function /decide-from-table/, by default bound to "? t" when /decide-mode/ is enabled, inserts random text generated from the table in variable /decide-table/. The table can be set up using elisp, but since version 0.8 there is a new, simpler, way of setting up the tables by using plain-text files. Text is generated by starting from a given table and picking a random phrase from that table. Phrases can be weighted to make some more likely to be chosen. A phrase can also contain references to other tables, which will be substituted by a random phrase from that table. It is also possible to insert die-rolls and random numbers from a given range.

The functions /decide-table-load-file/ and /decide-table-load-dir/ can be used to load random tables from text files into the /decide-tables/ variable. The latter recursively loads all files in a directory, while the former only loads a single file. Each file contains a single table, with one phrase per line. Weights are set by prefixing a line with a number and a comma, with no white-space before or after.

A line that begins with a semicolon begins a new table, and the name of the table is the text on the line after the semicolon. As a special case if the name is /main/ (case-insensitie match) instead the name of the file (sans extension) will be used for that table.

To refer to another table from a phrase, include the name of that table in brackets. Die-rolls can similarly be inserted by putting it in brackets. To get a simple random number in a range from n to m use [n-m], but it is also possible to use more advanced range-specifiers as described

References to other tables are first searched for in the same file. If no table matches in the file all file-names are searched instead. A name like /fff.ttt/ can be used for table /ttt/ that was declared in file /fff/.

A simple table to generate a primary color, with green being twice as likely to be chosen could look like this (in file /primary-color.txt/):

+BEGIN_EXAMPLE

;main red 2,green blue

+END_EXAMPLE

The following table in another file, /paint-buckets.txt/ refers to the previous table, and it also makes use of both a random range and a die-roll, where one of the phrases will be used four times as often as the other:

+BEGIN_EXAMPLE

;main 4,[2-4] buckets of [primary-color] paint [1d3+2] empty paint buckets

+END_EXAMPLE

The random-tables sub-directory contains a few example tables. The /decides-tables/ variable by default includes tables "card", "card.suit", and "card.rank" that can be used to draw random cards from an infinite deck. To load the other examples (all with names prefixed "example-") use the /decide-table-load-dir/ function. It makes sense to gather all table files in a directory and put a single call like /(decide-table-load-dir "~/.emacs.d/random-generators")/ in emacs' init script to make sure all tables are always loaded.

Blank lines in table files are ignored. If a blank phrase is needed (as in the /random-tables/example-dragon-prefix.txt/ file) a weight can be used alone on a line, just a number followed by a comma. Lines beginning with a # are comments and are ignored.

The format of the table files is based on the format used by [[http://www.random-generator.com/][Abulafia (random-generator.com)]], that is a site containing thousands of random-generator tables, but lacking most of the advanced functions on that site. (NOTE: It seems like Abulafia has had issues for many years now, and currently (August 2024) the site seems broken with just error messages and almost empty pages). The format is also similar to the format used for [[https://campaignwiki.org/hex-describe][Hex Describe's rules]] (but lacking most of the features supported by that generator). ** Customizing Output Since version 0.10.0 there is a variable /decide-output-format/ that can be used to control what is inserted by decide-mode functions.

If set to a string it is used as the format-string for a call to the standard emacs-lisp format function, that will also receive two strings: /what/ is being generated (e.g. a dice-specifier or name of a table) and the /result/ that was generated. The format-string can use %1$s and %2$s respectively to refer to the /what/ and /result/ strings (or use %s for both if used in that order).

For example to only output the generated result (without describing what was generated) and add a single trailing space:

+BEGIN_EXAMPLE

(setq decide-output-format "%2$s ")

+END_EXAMPLE

This outputs the result only, and also makes it appear bold in org-mode:

+BEGIN_EXAMPLE

(setq decide-output-format "%2$s ")

+END_EXAMPLE

If set to a function that function will be called with the two string arguments /what/ and /result/ and is expected to return the string to be inserted. If nil is returned nothing is inserted (other than what the function itself may already have inserted).

When creating custom functions for decide-mode, for instance to when binding a key to roll some special dice, note that /decide-output-format/ can be bound using /let/ around calls to /decide-mode/ functions to control the way the results are inserted without affecting the global (or buffer-local) configuration. ** Use in yasnippets Not a feature of /decide-mode/ itself, but it is easy to embed calls to various /decide-/ functions in yasnippet files. A random table set up to generate Victorian names (hint: you can easily make one based on [[http://www.random-generator.com/index.php?title=Victorian_Names&action=edit][the random Victorian names table on Abulafia]], but doing that is left as an exercise) can be used in a yasnippet snippet like this:

+BEGIN_EXAMPLE

(decide-choose-from-table "names-victorian").

+END_EXAMPLE

** Versions *** 0.10.0 2024-10-13