commit 52d1c5cab0df5f8e62c758c412494684435fc39f
Author: Skylar Hill <stellarskylark@posteo.net>
Date: Mon, 30 May 2022 20:12:06 -0500
First commit
Diffstat:
4 files changed, 111 insertions(+), 0 deletions(-)
diff --git a/README.md b/README.md
@@ -0,0 +1,12 @@
+# rpgsheets
+
+`rpgsheets` is a CLI/TUI character sheet application for tabletop RPGs.
+
+## Features
+* **System-agnostic:** Character sheets are stored as YAML files, and the data structure is not designed with a particular TTRPG system (ie DnD5e). You can make a template for your favorite system!
+* **Auto-rolling:** As long as your system uses dice rolls that can be represented with the standard `NUMdFACES+MOD` notation, you can easily define actions which will automatically be rolled.
+* **Auto-calculation:** You can define values in your character sheet which are dependent on other values. For instance, you can define a hard-coded `proficiency` value, and then define your shortsword attack modifier as `3+proficiency`. (For DnD, you probably actually want a hard-coded `strength` ability score, then a `STR` value defined as `(strength-10)/2`, then define your shortsword attack as `STR+proficiency`.)
+
+## Dependencies:
+* `rolldice` for, uh, rolling dice
+* `bc` for calculations
diff --git a/examplesheet.yaml b/examplesheet.yaml
@@ -0,0 +1,34 @@
+tabs:
+ main:
+ - ability-scores
+ - ability-modifiers
+ - skills
+ - misc
+ attacks:
+ - weapons
+expressions:
+ dexterity:
+ exp: "16"
+ tab: main
+ window: ability-scores
+ DEX:
+ exp: "(dexterity-10)/2"
+ tab: main
+ window: ability-modifiers
+ prof:
+ exp: "2"
+ tab: main
+ window: misc
+ sleight-of-hand:
+ dice: "d20"
+ exp: "DEX+prof"
+ shortsword-atk:
+ dice: "d20"
+ exp: "DEX+prof"
+ tab: attacks
+ window: weapons
+ shortsword-dmg:
+ dice: "d6"
+ exp: "DEX"
+ tab: attacks
+ window: weapons
diff --git a/rpgsheet.nimble b/rpgsheet.nimble
@@ -0,0 +1,14 @@
+# Package
+
+version = "0.0.1"
+author = "Skylar Hill"
+description = "CLI/TUI application for TTRPG character sheets"
+license = "GPL-3.0-only"
+srcDir = "src"
+bin = @["rpgsheet"]
+
+
+# Dependencies
+
+requires "nim >= 1.6.6"
+requires "yaml >= 0.16.0"
diff --git a/src/rpgsheet.nim b/src/rpgsheet.nim
@@ -0,0 +1,51 @@
+import json, yaml, re, strutils, osproc, os
+
+let reRawExp = re"([a-zA-Z\-]+[a-zA-Z])"
+let reProcessedExp = re"^[\d*+\-/()]*$"
+
+proc decodeExpression(exp: string, sheet: JsonNode): string =
+ var working = exp
+ if exp.contains(reProcessedExp):
+ # I think that execCmdEx adds whitespace in input;
+ # the xargs pipe first is necessary to prevent bc
+ # from throwing up
+ let (output, code) = execCmdEx("xargs | bc", input=exp)
+ if code == 0:
+ working = output.strip
+ return working
+
+ if sheet["expressions"].contains exp:
+ working = decodeExpression(sheet["expressions"][exp]["exp"].getStr, sheet)
+ return working
+
+ for match in exp.findAll reRawExp:
+ working = working.replace(match, decodeExpression(match, sheet))
+ return decodeExpression(working, sheet)
+
+proc roll(action: string, sheet: JsonNode): string =
+ let exp = sheet["expressions"][action]
+ if not exp.contains "dice":
+ return decodeExpression(exp["exp"].getStr, sheet)
+ let dice = exp["dice"].getStr
+ var modifier = decodeExpression(exp["exp"].getStr, sheet)
+ var op =
+ if modifier.parseInt < 0:
+ "" # the minus is the negative sign in the int
+ else:
+ "+"
+ let rollexp = dice & op & modifier
+ let (output, code) = execCmdEx("rolldice", input = rollexp)
+ if code == 0:
+ # rolldice returns its input; the actual roll is the second line
+ result = output.splitLines[1]
+
+if paramCount() < 2:
+ quit(
+ """Usage:
+ ./rpgsheet sheet.yaml action
+ """
+ )
+
+let file = open(paramStr(1))
+let sheetNode = file.readAll.loadtoJson[0]
+echo roll(paramStr(2), sheetNode)