From b7b1a95a5191dc24173c8ee127101243d2e7c938 Mon Sep 17 00:00:00 2001 From: Erin Schnabel Date: Tue, 10 Oct 2023 00:42:39 -0400 Subject: [PATCH] =?UTF-8?q?=F0=9F=90=9B=20Improve=20handling=20of=20supers?= =?UTF-8?q?cript=20in=20footnotes;=20resolves=20#232?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../tools/dnd5e/JsonTextReplacement.java | 20 +++- src/test/resources/other/monster-all.txt | 100 ++++++++++++++++++ src/test/resources/sources-homebrew.json | 5 +- 3 files changed, 120 insertions(+), 5 deletions(-) create mode 100644 src/test/resources/other/monster-all.txt diff --git a/src/main/java/dev/ebullient/convert/tools/dnd5e/JsonTextReplacement.java b/src/main/java/dev/ebullient/convert/tools/dnd5e/JsonTextReplacement.java index cb1dcb1e0..31334275e 100644 --- a/src/main/java/dev/ebullient/convert/tools/dnd5e/JsonTextReplacement.java +++ b/src/main/java/dev/ebullient/convert/tools/dnd5e/JsonTextReplacement.java @@ -34,6 +34,7 @@ public interface JsonTextReplacement extends JsonTextConverter Pattern homebrewPattern = Pattern.compile("\\{@homebrew ([^}]+)}"); Pattern quickRefPattern = Pattern.compile("\\{@quickref ([^}]+)}"); Pattern notePattern = Pattern.compile("\\{@note (\\*|Note:)?\\s?([^}]+)}"); + Pattern footnotePattern = Pattern.compile("\\{@footnote ([^}]+)}"); Pattern abilitySavePattern = Pattern.compile("\\{@(ability|savingThrow) ([^}]+)}"); // {@ability str 20} Pattern skillCheckPattern = Pattern.compile("\\{@skillCheck ([^}]+)}"); // {@skillCheck animal_handling 5} Pattern optionalFeaturesFilter = Pattern.compile("\\{@filter ([^|}]+)\\|optionalfeatures\\|([^}]+)*}"); @@ -213,10 +214,6 @@ default String _replaceTokenText(String input, boolean nested) { .replaceAll("\\{@cult ([^|}]+)\\|([^|}]+)\\|[^|}]*}", "$2") .replaceAll("\\{@cult ([^|}]+)\\|[^}]*}", "$1") .replaceAll("\\{@cult ([^|}]+)}", "$1") - // {@footnote directly in text|This is primarily for homebrew purposes, as the official texts (so far) avoid using footnotes}, - // {@footnote optional reference information|This is the footnote. References are free text.|Footnote 1, page 20}.", - .replaceAll("\\{@footnote ([^|}]+)\\|([^|}]+)\\|([^}]*)}", "$1 ^[$2, _$3_]") - .replaceAll("\\{@footnote ([^|}]+)\\|([^}]*)}", "$1 ^[$2]") .replaceAll("\\{@language ([^|}]+)\\|?[^}]*}", "$1") .replaceAll("\\{@book ([^}|]+)\\|?[^}]*}", "\"$1\"") .replaceAll("\\{@hit ([+-][^}<]+)}", "$1") @@ -265,6 +262,21 @@ default String _replaceTokenText(String input, boolean nested) { tui().errorf(e, "Unable to parse string from %s: %s", getSources().getKey(), input); } + result = footnotePattern.matcher(result).replaceAll((match) -> { + // {@footnote directly in text|This is primarily for homebrew purposes, as the official texts (so far) avoid using footnotes}, + // {@footnote optional reference information|This is the footnote. References are free text.|Footnote 1, page 20}.", + // We're converting these to _inline_ markdown footnotes, as numbering is difficult to track + String[] parts = match.group(1).split("\\|"); + if (parts[0].contains("")) { + // This already assumes what the footnote name will be + return String.format("%s", parts[0]); + } + if (parts.length > 2) { + return String.format("%s ^[%s, _%s_]", parts[0], parts[1], parts[2]); + } + return String.format("%s ^[%s]", parts[0], parts[1]); + }); + result = notePattern.matcher(result).replaceAll((match) -> { if (nested) { return "***Note:** " + match.group(2).trim() + "*"; diff --git a/src/test/resources/other/monster-all.txt b/src/test/resources/other/monster-all.txt new file mode 100644 index 000000000..9eefff6a8 --- /dev/null +++ b/src/test/resources/other/monster-all.txt @@ -0,0 +1,100 @@ +--- +obsidianUIMode: preview +cssclass: json5e-monster +{#if resource.tags } +tags: +{#for tag in resource.tags} +- {tag} +{/for} +{/if} +aliases: ["{resource.name}"] +--- + +# {resource.name} +*Source: {resource.source}* + +{#if resource.description } +{resource.description} + +{/if} +```statblock +{resource.5eStatblockYaml} +``` +^statblock + +```ad-statblock +title: {resource.name}{#if resource.token} +![{resource.token.title}]({resource.token.vaultPath}#token){/if} +*{resource.size} {resource.fullType}, {resource.alignment}* + +- **Armor Class** {#if resource.ac }{resource.ac} {/if}{#if resource.acText }({resource.acText}){/if} +- **Hit Points** {resource.hp or ' '} {#if resource.hitDice }(`{resource.hitDice}`){/if} {#if resource.hpText }({resource.hpText}){/if} +- **Speed** {resource.speed} + +|STR|DEX|CON|INT|WIS|CHA| +|:---:|:---:|:---:|:---:|:---:|:---:| +|{resource.scores}| + +- **Proficiency Bonus** {resource.pb} +- **Saving Throws** {#if resource.savingThrows }{resource.savingThrows}{#else}⏤{/if} +- **Skills** {#if resource.skills }{resource.skills}{#else}⏤{/if} +- **Senses** {#if resource.senses }{resource.senses}, {/if}passive Perception {resource.passive} +{#if resource.vulnerable } +- **Damage Vulnerabilities** {resource.vulnerable} +{/if}{#if resource.resist} +- **Damage Resistances** {resource.resist} +{/if}{#if resource.immune} +- **Damage Immunities** {resource.immune} +{/if}{#if resource.conditionImmune} +- **Condition Immunities** {resource.conditionImmune} +{/if} +- **Languages** {#if resource.languages }{resource.languages}{#else}—{/if} +- **Challenge** {resource.cr} +{#if resource.trait} + +## Traits +{#for trait in resource.trait} + +{#if trait.name }***{trait.name}.*** {/if}{trait.desc} +{/for}{/if}{#if resource.spellcasting}{#for spellcasting in resource.spellcasting} + +***{spellcasting.name}.*** {spellcasting.desc} +{/for}{/if}{#if resource.action} + +## Actions +{#for action in resource.action} + +{#if action.name }***{action.name}.*** {/if}{action.desc} +{/for}{/if}{#if resource.bonusAction} + +## Bonus Actions +{#for bonusAction in resource.bonusAction} + +{#if bonusAction.name }***{bonusAction.name}.*** {/if}{bonusAction.desc} +{/for}{/if}{#if resource.reaction} + +## Reactions +{#for reaction in resource.reaction} + +{#if reaction.name }***{reaction.name}.*** {/if}{reaction.desc} +{/for}{/if}{#if resource.legendary} + +## Legendary Actions +{#for legendary in resource.legendary} + +{#if legendary.name }***{legendary.name}.*** {/if}{legendary.desc} +{/for}{/if}{#if resource.legendaryGroup}{#for group in resource.legendaryGroup} + +## {group.name} + +{group.desc} +{/for}{/if} +``` +^statblock-manual + +{#if resource.environment } + +## Environment + +{resource.environment} +{/if} diff --git a/src/test/resources/sources-homebrew.json b/src/test/resources/sources-homebrew.json index f8cb7868e..e936eed23 100644 --- a/src/test/resources/sources-homebrew.json +++ b/src/test/resources/sources-homebrew.json @@ -33,5 +33,8 @@ ], "excludePattern": [ "race|.*|dmg" - ] + ], + "template": { + "monster": "src/test/resources/other/monster-all.txt" + } }