rpgsheet

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

commit 17c0c246ce8908671870fc8e00c17aaf844547f6
parent 4765933a119c88357dfd695c88fc8a6e76414da4
Author: Skylar Hill <stellarskylark@posteo.net>
Date:   Thu,  2 Jun 2022 02:07:24 -0500

Add dnd5e template, make small bugfixes and improvements

Diffstat:
Dexamplesheet.yaml | 39---------------------------------------
Msrc/rpgsheet.nim | 2++
Msrc/tui.nim | 31++++++++++++++++++++++++++++---
Msrc/verb.nim | 6+++++-
Atemplates/dnd5e.yaml | 363+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 398 insertions(+), 43 deletions(-)

diff --git a/examplesheet.yaml b/examplesheet.yaml @@ -1,39 +0,0 @@ -name: Cragthar -class: Paladin (Oath of Failure) -level: 3 -tabs: - - main: - - ability-scores - - ability-modifiers - - skills - - misc - - attacks: - - weapons -expressions: - dexterity: - modifier: 16 - tab: main - window: ability-scores - DEX: - modifier: "(dexterity-10)/2" - tab: main - window: ability-modifiers - proficiency: - modifier: 2 - tab: main - window: misc - sleight-of-hand: - dice: d20 - modifier: "DEX+proficiency" - tab: main - window: skills - shortsword-attack: - dice: d20 - modifier: "DEX+proficiency" - tab: attacks - window: weapons - shortsword-damage: - dice: d6 - modifier: "DEX" - tab: attacks - window: weapons diff --git a/src/rpgsheet.nim b/src/rpgsheet.nim @@ -42,6 +42,8 @@ proc main(): void = else: quit(usage) + if arg == 1: # Assume interactive mode is desired if only one argument is provided + verb = Tui if arg < 2 and verb != Tui: quit(usage) diff --git a/src/tui.nim b/src/tui.nim @@ -1,13 +1,15 @@ import illwill, os, + strutils, strformat, tables, + std/wordwrap, yaml import utils, verb -proc placeWindows(tb: TerminalBuffer, windows: seq[YamlNode]): Table[string, (int, int, int, int)] = +proc placeWindows(tb: TerminalBuffer, windows: seq[YamlNode], descY: int): Table[string, (int, int, int, int)] = result = initTable[string, (int, int, int, int)]() let windowWidth = if windows.len == 1: @@ -17,7 +19,7 @@ proc placeWindows(tb: TerminalBuffer, windows: seq[YamlNode]): Table[string, (in var currentX = 1 for win in windows: - result[win.content] = (currentX, 3, currentX + windowWidth - 1, tb.height - 1) + result[win.content] = (currentX, 3, currentX + windowWidth - 1, descY - 1) currentX += windowWidth proc exitProc() {.noconv.} = @@ -43,6 +45,8 @@ proc runTui*(sheet: YamlDocument): void = var bb = newBoxBuffer(tb.width, tb.height) var sbb = newBoxBuffer(tb.width, tb.height) + let descY = tb.height - 7 + var currentTabName: string var currentTabWindows: seq[YamlNode] # There should only be one item, but because @@ -52,7 +56,7 @@ proc runTui*(sheet: YamlDocument): void = currentTabName = n.content currentTabWindows = w.elems - let windowPositions = placeWindows(tb, currentTabWindows) + let windowPositions = placeWindows(tb, currentTabWindows, descY) for win in currentTabWindows: if win.content notin itemsByWindow: @@ -174,6 +178,27 @@ proc runTui*(sheet: YamlDocument): void = tb.setForegroundColor(fgNone) itemsbyWindow[win] = currentItems + # Write description + bb.drawRect(1, descY, tb.width - 1, tb.height - 1, doubleStyle = true) + let selWin = currentTabWindows[selectedWindowIndex].content + let sel = itemsByWindow[selWin][selectedByWindow[selWin]] + let item = sheet.root["expressions"][sel] + let desc = item.getContent("desc") + let val = (item.getContent("dice") & " " & item.getContent("modifier")).strip + let roll = + if not item.contains("dice"): + let rolled = doVerb(sel, Roll, sheet) + if rolled != item.getContent("modifier"): + rolled + else: "hardcoded" + else: "Press ENTER to roll" + tb.write(3, descY + 1, fmt"Value: {val} [{roll}]") + if desc != "": + let formattedDesc = desc.wrapWords(maxLineWidth = tb.width - 6) + let lines = formattedDesc.splitLines + for i in 0..lines.high: + tb.write(3, descY + 2 + i, lines[i]) + tb.write(bb) tb.setForegroundColor(fgBlue) tb.write(sbb) diff --git a/src/verb.nim b/src/verb.nim @@ -66,7 +66,11 @@ proc roll(action: string, sheet: YamlNode): string = "" # the minus is the negative sign in the int else: "+" - let rollexp = dice & op & modifier + let rollexp = + if modifier == "0": + dice + else: + dice & op & modifier let (output, code) = execCmdEx("rolldice -s", input = rollexp) if code == 0: # rolldice returns its input; the actual roll is the second line diff --git a/templates/dnd5e.yaml b/templates/dnd5e.yaml @@ -0,0 +1,363 @@ +# Change name, class, level +name: Character Name +class: Character Class +level: 1 +tabs: + - main: + - stats + - ability-modifiers + - skills + - features + - inventory-and-attacks: + - attacks + - equipment + - wallet + - spells: # You can remove this section if you're not a caster + - spell-slots + - spellcasting-stats + - spells +expressions: + # Change "race" to your character's race + race: + desc: Description of your character's race here + tab: main + window: features + # Add as many more of these as you want. Make the key + # like this; if you have Unarmored Defense, add an + # unarmored-defense field. + your-feature: + desc: Your character's awesome feature + tab: main + window: features + # Set these equal to your stats + max-health: + modifier: 10 + tab: main + window: stats + current-health: + modifier: 10 + tab: main + window: stats + temporary-health: + modifier: 0 + tab: main + window: stats + speed: + modifier: 30 + tab: main + window: stats + armor-class: + modifier: 10 + tab: main + window: stats + proficiency: + modifier: 2 + tab: main + window: stats + strength: + modifier: 10 + tab: main + window: stats + dexterity: + modifier: 10 + tab: main + window: stats + constitution: + modifier: 10 + tab: main + window: stats + intelligence: + modifier: 10 + tab: main + window: stats + wisdom: + modifier: 10 + tab: main + window: stats + charisma: + modifier: 10 + tab: main + window: stats + # Add your tool and language proficiencies here + other-proficiencies: + tab: main + window: stats + desc: Common, Simple weapons + # You probably don't want to change these + STR: + modifier: "(strength-10)/2" + tab: main + window: ability-modifiers + DEX: + modifier: "(dexterity-10)/2" + tab: main + window: ability-modifiers + CON: + modifier: "(constitution-10)/2" + tab: main + window: ability-modifiers + INT: + modifier: "(intelligence-10)/2" + tab: main + window: ability-modifiers + WIS: + modifier: "(wisdom-10)/2" + tab: main + window: ability-modifiers + CHA: + modifier: "(charisma-10)/2" + tab: main + window: ability-modifiers + # Add "+proficiency" to the skills you are proficient in, + # and "+(proficiency*2)" if you hvae expertise + passive-perception: + modifier: 10+WIS + tab: main + window: skills + strength-saving-throw: + dice: d20 + modifier: STR + tab: main + window: skills + dexterity-saving-throw: + dice: d20 + modifier: DEX + tab: main + window: skills + constitution-saving-throw: + dice: d20 + modifier: CON + tab: main + window: skills + intelligence-saving-throw: + dice: d20 + modifier: INT + tab: main + window: skills + wisdom-saving-throw: + dice: d20 + modifier: WIS + tab: main + window: skills + charisma-saving-throw: + dice: d20 + modifier: CHA + tab: main + window: skills + acrobatics: + dice: d20 + modifier: DEX + tab: main + window: skills + animal-handling: + dice: d20 + modifier: WIS + tab: main + window: skills + arcana: + dice: d20 + modifier: INT + tab: main + window: skills + athletics: + dice: d20 + modifier: STR + tab: main + window: skills + deception: + dice: d20 + modifier: CHA + tab: main + window: skills + history: + dice: d20 + modifier: INT + tab: main + window: skills + insight: + dice: d20 + modifier: WIS + tab: main + window: skills + intimidation: + dice: d20 + modifier: CHA + tab: main + window: skills + investigation: + dice: d20 + modifier: INT + tab: main + window: skills + medicine: + dice: d20 + modifier: WIS + tab: main + window: skills + nature: + dice: d20 + modifier: INT + tab: main + window: skills + perception: + dice: d20 + modifier: WIS + tab: main + window: skills + performance: + dice: d20 + modifier: CHA + tab: main + window: skills + persuasion: + dice: d20 + modifier: CHA + tab: main + window: skills + religion: + dice: d20 + modifier: INT + tab: main + window: skills + sleight-of-hand: + dice: d20 + modifier: DEX + tab: main + window: skills + stealth: + dice: d20 + modifier: DEX + tab: main + window: skills + survival: + dice: d20 + modifier: WIS + tab: main + window: skills + # Attacks; add two items for every way you have to attack, + # one for the attack roll, and the second for damage + unarmed-strike: + dice: d20 + modifier: STR+proficiency + tab: inventory-and-attacks + window: attacks + desc: A simple attack with the body + unarmed-strike-damage: + modifier: 1+STR + tab: inventory-and-attacks + window: attacks + # Inventory; add an item for whatever you happen to have + common-clothes: + desc: Simple, common clothes for a simple, common person. Nothing wrong with that. + tab: inventory-and-attacks + window: equipment + copper-pieces: + modifier: 0 + tab: inventory-and-attacks + window: wallet + silver-pieces: + modifier: 0 + tab: inventory-and-attacks + window: wallet + gold-pieces: + modifier: 0 + tab: inventory-and-attacks + window: wallet + electrum-pieces: + modifier: 0 + tab: inventory-and-attacks + window: wallet + platinum-pieces: + modifier: 0 + tab: inventory-and-attacks + window: wallet + # You can remove these if you're not a caster + first-level-spell-slots: + modifier: 1 + tab: spells + window: spell-slots + second-level-spell-slots: + modifier: 0 + tab: spells + window: spell-slots + third-level-spell-slots: + modifier: 0 + tab: spells + window: spell-slots + fourth-level-spell-slots: + modifier: 0 + tab: spells + window: spell-slots + fifth-level-spell-slots: + modifier: 0 + tab: spells + window: spell-slots + sixth-level-spell-slots: + modifier: 0 + tab: spells + window: spell-slots + seventh-level-spell-slots: + modifier: 0 + tab: spells + window: spell-slots + eighth-level-spell-slots: + modifier: 0 + tab: spells + window: spell-slots + ninth-level-spell-slots: + modifier: 0 + tab: spells + window: spell-slots + first-level-slots-expended: + modifier: 1 + tab: spells + window: spell-slots + second-level-slots-expended: + modifier: 0 + tab: spells + window: spell-slots + third-level-slots-expended: + modifier: 0 + tab: spells + window: spell-slots + fourth-level-slots-expended: + modifier: 0 + tab: spells + window: spell-slots + fifth-level-slots-expended: + modifier: 0 + tab: spells + window: spell-slots + sixth-level-slots-expended: + modifier: 0 + tab: spells + window: spell-slots + seventh-level-slots-expended: + modifier: 0 + tab: spells + window: spell-slots + eighth-level-slots-expended: + modifier: 0 + tab: spells + window: spell-slots + ninth-level-slots-expended: + modifier: 0 + tab: spells + window: spell-slots + spellcasting-ability: + modifier: CHA # set this appropriately + tab: spells + window: spellcasting-stats + spell-save-dc: + modifier: 8+spellcasting-ability+proficiency + tab: spells + window: spellcasting-stats + spell-attack-bonus: + dice: 1d20 + modifier: spellcasting-ability+proficiency + tab: spells + window: spellcasting-stats + prestidigitation: + desc: "Cantrip. This spell is a minor magical trick that novice spellcasters use for practice. You create one of the following magical effects within range: 1) You create an instantaneous, harmless sensory effect, such as a shower of sparks, a puff of wind, faint musical notes, or an odd odor. 2) You instantaneously light or snuff out a candle, a torch, or a small campfire. 3) You instantaneously clean or soil an object no larger than 1 cubic foot. 4) You chill, warm, or flavor up to 1 cubic foot of nonliving material for 1 hour. 5) You make a color, a small mark, or a symbol appear on an object or a surface for 1 hour. 6) You create a nonmagical trinket or an illusory image that can fit in your hand and that lasts until the end of your next turn. If you cast this spell multiple times, you can have up to three of its non-instantaneous effects active at a time, and you can dismiss such an effect as an action." + tab: spells + window: spells