-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathdnd-mode.el
349 lines (296 loc) · 12.7 KB
/
dnd-mode.el
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
;;; package --- dnd
;;; Commentary:
;;; This is the first draft of function to utilize when playing DnD
;;; Code:
(require 'yasnippet)
(require 'org)
;; === Variables ===
(setq dnd-srd-dir "~/org-dnd-srd/")
(setq dnd-snippet-dir "~/dnd-mode/snippets")
(setq dnd-org-capture-templates `(("i" "Inbox" entry (file "inbox.org")
,(concat "* TODO %?\n"
"/Entered on/ %U"))
("n" "Note" entry (file "notes.org")
,(concat "* %?\n"
"/Entered on/ %U"))))
;; === Functions ===
(defun dnd-read-lines (filePath)
"Return a list of lines of a file at filePath."
(with-temp-buffer
(insert-file-contents filePath)
(split-string (buffer-string) "\n" t)))
(defun dnd-load-srd-agenda ()
"Loads the DnD SRD files in the directory defined by 'dnd-srd-dir' into the org agenda"
(setq org-agenda-files (mapcar (lambda (path) (concat dnd-srd-dir path))
(dnd-read-lines (concat dnd-srd-dir ".agenda-index")))))
(defun dnd-select-session-target ()
"Sets the org agenda/capture to a the specified directory"
(interactive)
(setq dir (read-directory-name "dir:"))
(progn (dnd-load-srd-agenda)
(setq org-agenda-files (append org-agenda-files (mapcar (lambda (path) (concat dir path))
(dnd-read-lines (concat dir ".agenda-index")))))
(setq org-directory (concat dir "org/"))
(setq org-capture-templates dnd-org-capture-templates)))
(defun rtd ()
"Sometimes you just got to roll the dice. This function currently expects the patter of '1d4 + 0' (the spaces are needed and you must have an add, sorry)"
(interactive)
(setq dnd-text (buffer-substring (region-beginning) (region-end)))
(setq dnd-text-values (split-string dnd-text " "))
(setq dnd-dice-text (nth 0 dnd-text-values))
(setq dnd-mod-text (nth 2 dnd-text-values))
(setq dnd-values (split-string dnd-dice-text "d"))
(setq dnd-count (string-to-number (nth 0 dnd-values)))
(setq dnd-limit (string-to-number (nth 1 dnd-values)))
(setq dnd-total 0)
(let ((dnd-x 0))
(while (< dnd-x dnd-count)
(setq dnd-rand (random dnd-limit))
(setq dnd-roll (+ dnd-rand 1))
(setq dnd-total (+ dnd-total dnd-roll))
(message "Dice %d was %d" (+ 1 dnd-x) dnd-roll)
(setq dnd-x (+ dnd-x 1))))
(message "Mod was %s" dnd-mod-text)
(if dnd-mod-text
(setq dnd-total (+ dnd-total (string-to-number dnd-mod-text)))
(nil))
(message "You rolled %d" dnd-total))
(defun dnd-calc-mod (score)
"Calculates the modifier of the given DND ability score"
(message "input is: %d" score)
(floor (- (/ score 2) 5)))
(defun dnd-calc-pb (pb check)
"Calculates the Proficiency Bonus to use based on the check and value provided"
(if (string= check "X")
pb
(if (string= check "XX")
(* 2 pb)
0)))
(defun dnd-calc-offhand-mod (mod check)
"Calculates the Proficiency Bonus to use based on the check and value provided"
(if (string= check "X")
0
mod))
(defun dnd-calc-bonus-dmg (bonus)
"Calculates the Proficiency Bonus to use based on the check and value provided"
(if (string= bonus "-")
""
(concat " + " bonus)))
(defun dnd-reset-based-on-rest (sr lr used sr_refill lr_refill)
"Calculates the Proficiency Bonus to use based on the check and value provided"
(if (string= sr "X")
(if (string= sr_refill "X")
0
(if (string= sr_refill "-")
used
(- (string-to-number used) (string-to-number sr_refill))))
(if (string= lr "X")
(if (string= lr_refill "X")
0
(if (string= lr_refill "-")
(string-to-number used)
(- used (string-to-number lr_refill))))
used)))
(defun dnd-index (object list)
"return the index of object in list"
(let ((counter 0)
(found nil))
(catch 'finished
(dolist (listelement list counter)
(if (equal object listelement)
(progn
(setq found t)
(throw 'finished counter))
;; else increment counter
(incf counter)))
;; if we found it return counter otherwise return nil
(if found counter nil))))
(defun dnd-calc-size-mod (size)
"Outputs constants for the Ability Modifiers"
(if (string= size "Tiny") 0.5
(if (string= size "Small") 1
(if (string= size "Medium") 1
(if (string= size "Large") 2
(if (string= size "Huge") 3
(if (string= size "Gargantuan") 4 1)))))))
(defun dnd-calc-carry-capacity (STR size bonus)
"Outputs constants for the Ability Modifiers"
(setq carryMod 7.5)
(setq sizeScale (+ (truncate (dnd-calc-size-mod size)) bonus))
(setq iterator 0)
(while (< iterator sizeScale)
(setq carryMod (* carryMod 2))
(setq iterator (1+ iterator)))
(* STR carryMod))
(defun dnd-calc-drag-capacity (STR size bonus)
"Outputs constants for the Ability Modifiers"
(setq carryMod 15)
(setq sizeScale (+ (truncate (dnd-calc-size-mod size)) bonus))
(setq iterator 0)
(while (< iterator sizeScale)
(setq carryMod (* carryMod 2))
(setq iterator (1+ iterator)))
(* STR carryMod))
(defun dnd-calc-hp (CON hitDie level)
"Outputs constants for the Ability Modifiers"
(setq conMod (dnd-calc-mod CON))
(setq hp (+ hitDie conMod))
(setq iterator 1)
(while (< iterator level)
(setq hp (+ hp (+ (ceiling (/ hitDie 2)) conMod)))
(setq iterator (1+ iterator)))
(format "%s" hp))
(defun dnd-half-die (die)
"Outputs constants for the Ability Modifiers"
(setq halvedDie (/ die 2))
(if (= (% halvedDie 2) 0)
halvedDie
(- halvedDie 1)
))
(defun dnd-calc-dice (die count size)
"Outputs constants for the Ability Modifiers"
(setq sizeMod (dnd-calc-size-mod size))
(if (>= sizeMod 1)
(progn
(setq diceCount (* (string-to-number count) sizeMod))
(format "%sd%s" diceCount die))
(format "%sd%s" count (dnd-half-die (string-to-number die)))))
(defun dnd-calc-unarmored-defense (dex con)
"Outputs constants for the Ability Modifiers"
(+ 10 (dnd-calc-mod dex) (dnd-calc-mod con)))
(defun dnd-calc-spell-save-dc (ability prof has_dc)
"Outputs constants for the Ability Modifiers"
(if (string= has_dc "X")
(+ prof (dnd-calc-mod ability) 8)
(format "%s" "-")))
(defun dnd-calc-ac (armor dex con bonus shield)
"Outputs constants for the Ability Modifiers"
(setq mod (dnd-calc-mod dex))
(setq conMod (dnd-calc-mod con))
(setq armorBaseAc (dnd-get-armor-base-ac armor))
(setq armorType (dnd-get-armor-type armor))
(if (string= armorType "light") (+ armorBaseAc mod bonus shield)
(if (string= armorType "medium") (+ armorBaseAc (if (> mod 2) 2 mod) bonus shield)
(if (string= armorType "heavy") (+ armorBaseAc bonus shield)
(if (string= armorType "unarmored") (+ armorBaseAc mod conMod bonus shield) (+ armorBaseAc mod bonus shield))))))
(defun dnd-get-armor-type (armor)
"Outputs constants for the Ability Modifiers"
(if (string= armor "Padded") "light"
(if (string= armor "Leather") "light"
(if (string= armor "Studded Leather") "light"
(if (string= armor "Hide") "medium"
(if (string= armor "Chain Shirt") "medium"
(if (string= armor "Scale Mail") "medium"
(if (string= armor "Spiked Armor") "medium"
(if (string= armor "Breastplate") "medium"
(if (string= armor "Halfplate") "medium"
(if (string= armor "Ring Mail") "heavy"
(if (string= armor "Chain Mail") "heavy"
(if (string= armor "Splint") "heavy"
(if (string= armor "Plate") "heavy"
(if (string= armor "Unarmored") "unarmored" "none")))))))))))))))
(defun dnd-get-armor-base-ac (armor)
"Outputs constants for the Ability Modifiers"
(if (string= armor "Padded") 11
(if (string= armor "Leather") 11
(if (string= armor "Studded Leather") 12
(if (string= armor "Hide") 12
(if (string= armor "Chain Shirt") 13
(if (string= armor "Scale Mail") 14
(if (string= armor "Spiked Armor") 14
(if (string= armor "Breastplate") 14
(if (string= armor "Halfplate") 15
(if (string= armor "Ring Mail") 14
(if (string= armor "Chain Mail") 16
(if (string= armor "Splint") 17
(if (string= armor "Plate") 18 10))))))))))))))
(defun dnd-get-stat (ability)
"Outputs constants for the Ability Modifiers"
(setq values (org-table-get-remote-range "stats" "@2$1..@>$>"))
(setq abilities (mapcar (lambda (field) (org-no-properties field)) (org-table-get-remote-range "stats" "@1$1..@1$>")))
(setq abilityIndex (dnd-index ability abilities))
(setq value (nth abilityIndex values))
(if (string-match-p "^-?\\(?:\\(?:\\(?:0\\|[1-9][0-9]*\\)?[.][0-9]+\\)\\|\\(?:0\\|[1-9][0-9]*\\)\\)\\(?:e-?\\(?:0\\|[1-9][0-9]*\\)?\\)?$" (format "%s" value))
(string-to-number (format "%s" value))
(format "%s" value)))
(defun dnd-output-ability-constants (table)
"Outputs constants for the Ability Modifiers"
(setq consts (mapcar (lambda (row) (format "#+CONSTANTS: %s=%s\n" (nth 0 row) (if (string= (format "%s" (nth 1 row)) "X") (format "\"%s\"" (nth 1 row)) (if (string= (format "%s" (nth 1 row)) "-") (format "\"%s\"" (nth 1 row)) (nth 1 row))))) table))
(while consts
(if (string= "#+CONSTANTS: Allowed=27\n" (car consts))
(setq consts (cdr consts))
(if (string= "#+CONSTANTS: =\n" (car consts))
(setq consts (cdr consts))
(progn (princ (car consts))
(setq consts (cdr consts)))))))
(defun dnd-calc-point-buy-cost (score)
"Calculates the point buy value of the given ability score"
(setq base-cost (- (string-to-number score) 8))
(setq cost 0)
(if (> base-cost 5)
(if (> base-cost 6)
(setq cost (+ base-cost 2))
(setq cost (+ base-cost 1)))
(setq cost base-cost))
(if (> cost 9)
"Value Too High"
(if (< cost 0)
"Value Too Low"
cost)))
(defun dnd-eval-charsheet ()
"Evaluates the dnd character sheet that you are currently in"
(interactive)
(setq starting-point (point))
(outline-show-all)
(goto-char (point-min))
;; (search-forward "BEGIN_SRC")
;; (org-babel-execute-src-block)
;; (search-forward ":results:")
;; (next-line)
;; (backward-word)
(defun my-org-confirm-babel-evaluate (lang body)
(not (string= lang "elisp"))) ;don't ask for ditaa
(setq org-confirm-babel-evaluate #'my-org-confirm-babel-evaluate)
;;(org-ctrl-c-ctrl-c)
(unwind-protect
(while (string= "1" "1")
(search-forward "TBLFM")
(org-ctrl-c-ctrl-c))
(progn
(goto-char (point-min))
;; (search-forward "* Constants")
;; (outline-hide-leaves)
(goto-char starting-point))))
;; ==== Minor Mode ===
(define-minor-mode dnd-mode
"Toggles global dnd-mode"
nil
:global t
:lighter " dnd"
:keymap (let ((map (make-sparse-keymap)))
(define-key map (kbd "C-c r") 'rtd)
(define-key map (kbd "C-c e") 'org-table-recalculate-buffer-tables)
(define-key map (kbd "C-c s") 'dnd-select-session-target)
map)
(if dnd-mode
(message "dnd-mode activated!")
(message "dnd-mode deactivated!")))
(add-hook 'dnd-mode-hook (lambda () (message "Dnd Mode did thing")))
(add-hook 'dnd-mode-on-hook (lambda () (progn
(setq dnd-prev-org-capture-templates org-capture-templates)
(setq dnd-prev-org-directory org-directory)
(setq dnd-prev-org-agenda-files org-agenda-files)
(setq dnd-prev-yas-snippet-dirs yas-snippet-dirs)
(dnd-load-srd-agenda)
(setq yas-snippet-dirs (append yas-snippet-dirs '(dnd-snippet-dir)))
(yas-reload-all)
(message "Dnd Mode is On!"))))
(add-hook 'dnd-mode-off-hook (lambda () (progn
(setq org-capture-templates dnd-prev-org-capture-templates)
(setq org-directory dnd-prev-org-directory)
(setq org-agenda-files dnd-prev-org-agenda-files)
(setq yas-snippet-dirs dnd-prev-yas-snippet-dirs)
(yas-reload-all)
(message "Dnd Mode is Off!"))))
(provide 'dnd)
;;; dnd.el ends here