From 981288f09ed805657910a307ae07041e0d97138d Mon Sep 17 00:00:00 2001 From: vickydotbat Date: Wed, 27 May 2026 08:45:45 +0200 Subject: [PATCH] Manually-authored class notes --- internal/topdata/metadata_wiki.go | 2 ++ internal/topdata/wiki_native_test.go | 11 ++++++-- internal/topdata/wiki_tables.go | 41 +++++++++++++++++++++++++++- 3 files changed, 51 insertions(+), 3 deletions(-) diff --git a/internal/topdata/metadata_wiki.go b/internal/topdata/metadata_wiki.go index c836813..875fe5c 100644 --- a/internal/topdata/metadata_wiki.go +++ b/internal/topdata/metadata_wiki.go @@ -26,6 +26,8 @@ func normalizeWikiMetadataKey(key string) string { return "canonical" case "status", "wikistatus": return "status" + case "progressionnotes", "progression_notes", "classprogressionnotes", "class_progression_notes": + return "progression_notes" default: return "" } diff --git a/internal/topdata/wiki_native_test.go b/internal/topdata/wiki_native_test.go index 075fde9..e7e8f79 100644 --- a/internal/topdata/wiki_native_test.go +++ b/internal/topdata/wiki_native_test.go @@ -1506,7 +1506,7 @@ tables: value: "{{range(HPMin, HPMax)}}" - key: notes label: Notes - value: "{{if(Level == 4 && BonusFeat != \"0\", link(\"feat:weapon_specialization\", \"Weapon Specialization\") + \" first available.\", Notes)}}" + value: "{{if(Level == 4 && BonusFeat != \"0\", link(\"feat:weapon_specialization\", \"Weapon Specialization\") + \" first available.\" + if(present(Notes), \" \" + Notes, \"\"), Notes)}}" empty: "" allow_wiki_markup: true `) @@ -1521,6 +1521,13 @@ tables: "FeatsTable": map[string]any{"table": "classes/feats:fighter"}, "HitDie": 10, "SavingThrowTable": map[string]any{"table": "classes/saves:fortitude"}, + "meta": map[string]any{ + "wiki": map[string]any{ + "progression_notes": map[string]any{ + "4": "Manual level note.", + }, + }, + }, }, } @@ -1538,7 +1545,7 @@ tables: `2`, `[[Feats/Literate|Literate]], [[Feats/Simple_Weapon_Proficiency|Simple Weapon Proficiency]]`, `1-10`, - `[[Feats/Weapon_Specialization|Weapon Specialization]] first available.`, + `[[Feats/Weapon_Specialization|Weapon Specialization]] first available. Manual level note.`, } { if !strings.Contains(got, expected) { t.Fatalf("expected %q in rendered table:\n%s", expected, got) diff --git a/internal/topdata/wiki_tables.go b/internal/topdata/wiki_tables.go index 466681b..7e3c310 100644 --- a/internal/topdata/wiki_tables.go +++ b/internal/topdata/wiki_tables.go @@ -441,7 +441,14 @@ func (ctx *wikiContext) classProgressionRows(levels string, projections map[stri if hitDie > 0 { row["HPMax"] = level * hitDie } - row["Notes"] = "" + if !presentWikiValue(fieldValue(row, "Notes")) { + if note := ctx.classProgressionNote(classRow, level); note != "" { + row["Notes"] = note + } + } + if _, ok := row["Notes"]; !ok { + row["Notes"] = "" + } row["HasSpellProgression"] = hasSpellProgression(classRow) row["HasSpellsPerDay"] = hasPerDay row["HasSpellsKnown"] = hasKnown @@ -452,6 +459,38 @@ func (ctx *wikiContext) classProgressionRows(levels string, projections map[stri return out, nil } +func (ctx *wikiContext) classProgressionNote(classRow map[string]any, level int) string { + meta, err := parseExistingMetadata(classRow) + if err != nil || meta == nil { + return "" + } + wiki, _ := meta["wiki"].(map[string]any) + if wiki == nil { + return "" + } + raw := wiki["progression_notes"] + if raw == nil { + return "" + } + switch typed := raw.(type) { + case map[string]any: + for _, key := range []string{strconv.Itoa(level), formatLevelNoteKey(level)} { + if value, ok := typed[key]; ok { + return strings.TrimSpace(ctx.resolveTextValue(value, nil)) + } + } + case []any: + if level > 0 && level <= len(typed) { + return strings.TrimSpace(ctx.resolveTextValue(typed[level-1], nil)) + } + } + return "" +} + +func formatLevelNoteKey(level int) string { + return "level_" + strconv.Itoa(level) +} + func classSpellProgressionByLevel(table *wikiTable) map[int]map[int]string { out := map[int]map[int]string{} if table == nil {