From 07717c103dfb7f0311ee57b0445be1a22b667008 Mon Sep 17 00:00:00 2001 From: Howard Abrams Date: Sat, 27 Feb 2021 00:06:43 -0800 Subject: [PATCH] Change the "dashboard" screen to popups I realized that a DM Screen isn't really what I want. If I want information about a particular rule or the magic school, then I want it to pop up, and then go away. --- dnd-5e/weapons.org | 4 ++ dnd-5e/weather-effects.org | 2 + rpgdm-custom.el | 41 +++++++++++++++ rpgdm-screen.el | 46 ++++++++++++++++- rpgdm.el | 100 +++++++++++++++++++++++++------------ 5 files changed, 159 insertions(+), 34 deletions(-) create mode 100644 rpgdm-custom.el diff --git a/dnd-5e/weapons.org b/dnd-5e/weapons.org index 2e7426b..a3e1321 100644 --- a/dnd-5e/weapons.org +++ b/dnd-5e/weapons.org @@ -56,3 +56,7 @@ - *Thrown*. If a weapon has the thrown property, you can throw the weapon to make a ranged attack. If the weapon is a melee weapon, you use the same ability modifier for that attack roll and damage roll that you would use for a melee attack with the weapon. For example, if you throw a handaxe, you use your Strength, but if you throw a dag-ger, you can use either your Strength or your Dexterity, since the dagger has the finesse property. - *Two-Handed.* This weapon requires two hands when you attack with it. - *Versatile*. This weapon can be used with one or two hands. A damage value in parentheses appears with the property—the damage when the weapon is used with two hands to make a melee attack. + +# Local Variables: +# eval: (progn (toggle-truncate-lines 1) (narrow-to-region 112 (point-max)) +# End: diff --git a/dnd-5e/weather-effects.org b/dnd-5e/weather-effects.org index e39d6ed..04d3111 100644 --- a/dnd-5e/weather-effects.org +++ b/dnd-5e/weather-effects.org @@ -1,3 +1,5 @@ +#+TITLE: Weather Effects + - Cold :: The temperature ranges between 0 and 32 degrees. This functions as Extreme Cold from Chapter 5 of the Dungeon Master’s Guide, except the saving throw is made with advantage - Extreme Cold :: This functions as Extreme Cold from Chapter 5 of the Dungeon Master’s Guide diff --git a/rpgdm-custom.el b/rpgdm-custom.el new file mode 100644 index 0000000..2e9efca --- /dev/null +++ b/rpgdm-custom.el @@ -0,0 +1,41 @@ +;;; rpgdm-custom.el --- Customizations for RPGDM -*- lexical-binding: t; -*- +;; +;; Copyright (C) 2021 Howard X. Abrams +;; +;; Author: Howard X. Abrams +;; Maintainer: Howard X. Abrams +;; Created: February 26, 2021 +;; +;; This file is not part of GNU Emacs. +;; +;; +;;; Code: + +(defgroup rpgdm nil + "Customization for the Dungeon Master support package." + :prefix "rpgdm-" + :group 'applications + :link '(url-link :tag "Github" "https://gitlab.com/howardabrams/emacs-rpgdm")) + +(defcustom rpgdm-screen-window-side :right + "Split new windows on a particular side. +For instance, `:below' or on the `:right'." + :type '(choice (const :tag "above" 'above) + (const :tag "below" 'below) + (const :tag "left" 'left) + (const :tag "right" 'right)) + :group 'rpgdm) + +(defcustom rpgdm-screen-window-size nil + "The size of new windows. Leave nil for half the frame." + :type '(integer) + :group 'rpgdm) + +(defcustom rpgdm-screen-fullscreen nil + "Should the displayed screen occupy the entire frame?" + :type '(boolean) + :group 'rpgdm) + + +(provide 'rpgdm-custom) +;;; rpgdm-custom.el ends here diff --git a/rpgdm-screen.el b/rpgdm-screen.el index 853f961..c057d5f 100644 --- a/rpgdm-screen.el +++ b/rpgdm-screen.el @@ -28,13 +28,55 @@ (expand-file-name "dnd-5e" rpgdm-base) "Directory path containing the tables to load and create functions.") +(defvar rpgdm-screen-files nil + "Associative list of files and their titles.") + +(defvar rpgdm-screen-window-side t) +(defvar rpgdm-screen-window-size nil) +(defvar rpgdm-screen-fullscreen nil) + +(defun rpgdm-screen-show (file-title) + "Display in a side-window, FILE-TITLE. +Interactively, display a list of files in `rpgdm-screen-directory'." + (interactive (list (completing-read "Show screen: " + (rpgdm-screen-screen-list)))) + (let ((filename (alist-get file-title (rpgdm-screen-screen-list) nil nil 'equal))) + (unless rpgdm-screen-fullscreen + (delete-other-windows)) + (save-excursion + (select-window + (split-window (frame-root-window) + rpgdm-screen-window-size + rpgdm-screen-window-side)) + (find-file filename)))) + + +(defun rpgdm-screen-screen-list () + "A memoized list of cons cells containing the title and fully-qualified filename." + (unless rpgdm-screen-files + (dolist (file (directory-files rpgdm-screen-directory t)) + (add-to-list 'rpgdm-screen-files (cons (rpgdm-screen--read-title file) file)))) + rpgdm-screen-files) + +(defun rpgdm-screen--read-title (file) + "Return the title of an org-formatted FILE or its first line of text." + (with-temp-buffer + (insert-file-contents file) + (goto-char (point-min)) + (if (re-search-forward (rx bol "#+title:" (one-or-more space) + (group (one-or-more any))) nil t) + (match-string 1) + (goto-char (point-min)) + (buffer-substring-no-properties (point-min) (line-end-position))))) + + (defun rpgdm-screen--get-list-items () "Return a list of all the list items in the org document." (org-element-map (org-element-parse-buffer) 'item (lambda (item) (buffer-substring-no-properties - (org-element-property :contents-begin item) - (org-element-property :contents-end item))))) + (org-element-property :contents-begin item) + (org-element-property :contents-end item))))) (defun rpgdm-screen-choose-list () "Randomly choose an elemeent from all lists in the current file. diff --git a/rpgdm.el b/rpgdm.el index 81464b0..9e729f7 100644 --- a/rpgdm.el +++ b/rpgdm.el @@ -27,12 +27,7 @@ (load-file (expand-file-name "rpgdm-dice.el" rpgdm-base)) (load-file (expand-file-name "rpgdm-screen.el" rpgdm-base)) (load-file (expand-file-name "rpgdm-tables.el" rpgdm-base)) - -(defgroup rpgdm nil - "Customization for the Dungeon Master support package." - :prefix "rpgdm-" - :group 'applications - :link '(url-link :tag "Github" "https://gitlab.com/howardabrams/emacs-rpgdm")) +(load-file (expand-file-name "rpgdm-npc.el" rpgdm-base)) (define-minor-mode rpgdm-mode "Minor mode for layering role-playing game master functions over your notes." @@ -43,14 +38,12 @@ (defhydra hydra-rpgdm (:color pink :hint nil) " - ^Dice^ ^Tables^ ^Checks^ - ^^^^^^^---------------------------------------------------------------------------------------- - _d_: Roll Dice _h_: Dashboard _s_: d20 Skill - _f_: Next Dice Expr _t_: Load Tables _e_: Easy check - _b_: Previous Expr _c_: Choose from _m_: Moderate - _z_: Flip a coin a table _h_: Hard check - _a_/_A_: Advantage/Disadvantage _v_: Difficult " - ("d" rpgdm-roll) ("" rpgdm-last-results) + ^Dice^ ^Tables^ ^Checks^ + ---------------------------------------------------------------------------------------- + _d_: Roll Dice _z_: Flip a coin _r_: Dashboard _s_: d20 Skill _m_: Moderate + _b_: Previous _f_: Next Dice Expr _t_: Load Tables _e_: Easy check _h_: Hard check + _a_/_A_: Advantage/Disadvantage _c_: Choose Item _v_: Difficult _i_: Impossible " + ("d" rpgdm-roll) ("f" rpgdm-forward-roll) ("b" rpgdm-forward-roll) ("a" rpgdm-roll-advantage) ("A" rpgdm-roll-disadvantage) ("z" rpgdm-yes-and-50/50) @@ -59,27 +52,68 @@ ("h" rpgdm-skill-check-hard) ("v" rpgdm-skill-check-difficult) ("t" rpgdm-tables-load) ("c" rpgdm-tables-choose) - ("h" rpgdm-screen) + ("r" rpgdm-screen-show) ("R" delete-window) + ("n" rpgdm-npc) - ("q" nil "quit")) + ("C-m" rpgdm-last-results) + ("C-n" rpgdm-last-results-next) ("C-p" rpgdm-last-results-previous) + ("s-l" rpgdm-last-results) + ("s-j" rpgdm-last-results-next) ("s-k" rpgdm-last-results-previous) + + ("q" nil "quit") ("" nil)) -(defvar rpgdm-last-results "" +(defvar rpgdm-last-results (make-ring 10) "The results from calls to `rpgdm-screen-' functions are stored here.") +(defvar rpgdm-last-results-ptr 0 + "Keeps track of where we are in the message display ring. +Each call to `rpgdm-last-results' resets this to 0.") + (defun rpgdm-message (format-string &rest args) "Replace `messasge' function allowing it to be re-displayed. The FORMAT-STRING is a standard string for the `format' function, and ARGS are substitued values." - ;; TODO Push this onto a ring instead of reset this string variable: - (setq rpgdm-last-results (apply 'format format-string args)) - (rpgdm-last-results)) + (let ((message (apply 'format format-string args))) + (ring-insert rpgdm-last-results message) + (rpgdm-last-results))) (defun rpgdm-last-results () - "Display results from the last call to a `rpgdm-screen-' function." - ;; TODO Need to add a prefix and display a numeric version with last as a ring. + "Display results from the last call to a `rpgdm-message' function." (interactive) - (message rpgdm-last-results)) + (setq rpgdm-last-results-ptr 0) + (message (ring-ref rpgdm-last-results rpgdm-last-results-ptr))) + +(defun rpgdm-last-results-previous () + "Display results from an earlier call to `rpgdm-message'." + (interactive) + (incf rpgdm-last-results-ptr) + (when (>= rpgdm-last-results-ptr (ring-length rpgdm-last-results)) + (setq rpgdm-last-results-ptr 0)) + (message "%d> %s" rpgdm-last-results-ptr (ring-ref rpgdm-last-results rpgdm-last-results-ptr))) + +(defun rpgdm-last-results-next () + "Display results from an later call to `rpgdm-message'. +Meant to be used with `rpgdm-last-results-previous'." + (interactive) + (when (> rpgdm-last-results-ptr 0) + (decf rpgdm-last-results-ptr)) + (message "%d> %s" rpgdm-last-results-ptr (ring-ref rpgdm-last-results rpgdm-last-results-ptr))) + +(ert-deftest rpgdm-last-results-test () + (progn + (setq rpgdm-last-results (make-ring 10)) + (rpgdm-message "First in, so this is the oldest") + (rpgdm-message "Something or other") + (rpgdm-message "Almost the newest") + (rpgdm-message "Newest")) + + (should (equal "Newest" (rpgdm-last-results))) + (should (equal "1> Almost the newest" (rpgdm-last-results-previous))) + (should (equal "2> Something other" (rpgdm-last-results-previous))) + (should (equal "1> Almost the newest" (rpgdm-last-results-next))) + (should (equal "0> Almost the newest" (rpgdm-last-results-next))) + (should (equal "0> Almost the newest" (rpgdm-last-results-next)))) (defun rpgdm-yes-and-50/50 () @@ -98,13 +132,14 @@ one of six answers with equal frequency: https://www.drivethrurpg.com/product/89534/FU-The-Freeform-Universal-RPG-Classic-rules" (interactive) - (let (rolled (rpgdm--roll-die 6)) - (cond ((= rolled 1) "No, and... (fails badly that you add a complication)") - ((= rolled 2) "No.") - ((= rolled 3) "No, but... (fails, but add a little bonus or consolation prize)") - ((= rolled 4) "Yes, but... (succeeds, but add a complication or caveat)") - ((= rolled 5) "Yes.") - (t "Yes, and... (succeeds, plus add a litle extra something-something)")))) + (let* ((rolled (rpgdm--roll-die 6)) + (results (cond ((= rolled 1) "No, and... (fails badly that you add a complication)") + ((= rolled 2) "No.") + ((= rolled 3) "No, but... (fails, but add a little bonus or consolation prize)") + ((= rolled 4) "Yes, but... (succeeds, but add a complication or caveat)") + ((= rolled 5) "Yes.") + (t "Yes, and... (succeeds, plus add a litle extra something-something)")))) + (rpgdm-message results))) ;; ---------------------------------------------------------------------- ;; SKILL CHECKS @@ -198,9 +233,10 @@ https://www.drivethrurpg.com/product/89534/FU-The-Freeform-Universal-RPG-Classic (should (equal (rpgdm--yes-and 10 16) "Yes.")) (should (equal (rpgdm--yes-and 10 17) "Yes, and..."))) -(defun rpgdm-skill-check (target rolled-results) +(defun rpgdm-skill-check (target rolled-results &optional label) "Given a TARGET skill check, and ROLLED-RESULTS, return pass/fail. -The string can return a bit of complications, from `rpgdm--yes-and'." +The string can return a bit of complications, from `rpgdm--yes-and'. +The LABEL will be append to the message, and used form other calls." (interactive (list (completing-read "Target Level: " '(Trivial Easy Moderate Hard Difficult Impossible)) (read-number "Rolled Results: ")))