package topdata import ( "fmt" "strings" ) func (ctx *wikiContext) renderWikiFormatter(spec string, page wikiTemplatePage) (string, error) { name := strings.Fields(spec) if len(name) == 0 { return "", fmt.Errorf("render wiki template for %s: empty formatter", page.PageID) } switch name[0] { case "Description": return dokuWikiToNodeBBHTML(toDokuWiki(ctx.resolveRowDescription(page.Category, page.Row))), nil case "FactsTable": return dokuWikiToNodeBBHTML(ctx.renderFacts(page.Category, page.Key, page.Row)), nil case "Prerequisites": return dokuWikiToNodeBBHTML(formatFact("Prerequisites", ctx.renderFeatPrerequisites(page.Row))), nil case "SkillList": if page.Category != "classes" { return "", nil } return dokuWikiToNodeBBHTML(ctx.renderClassSkillList(page.Row)), nil case "ClassFeatureTable": if page.Category != "classes" { return "", nil } return dokuWikiToNodeBBHTML(ctx.renderClassFeatureTable(page.Row)), nil case "FeatProgression": if page.Category != "classes" { return "", nil } return dokuWikiToNodeBBHTML(ctx.renderClassFeatProgression(page.Row)), nil case "SpellTable", "SavesProgression", "BABProgression": return "", nil case "RaceFeatList": return dokuWikiToNodeBBHTML(formatFact("Racial Feats", ctx.renderRaceFeatList(page.Row))), nil case "StatusCallout": return buildWikiStatusBlock(page.Status, page.Category), nil case "RaceNameForms": return dokuWikiToNodeBBHTML(ctx.renderRaceNameForms(page.Row)), nil case "UserBottomFallback": return "", nil default: return "", fmt.Errorf("render wiki template for %s: unknown formatter %q", page.PageID, name[0]) } } func (ctx *wikiContext) renderClassSkillList(row map[string]any) string { table := ctx.tableForValue(fieldValue(row, "SkillsTable"), ctx.classSkillTables) if table == nil { return "" } skills := []string{} for _, skillRow := range table.Rows { if stringValue(skillRow, "ClassSkill") != "1" { continue } name := ctx.renderReference(fieldValue(skillRow, "SkillIndex"), ctx.skillIDToKey, ctx.resolveSkillName) if name != "" { skills = append(skills, name) } } if len(skills) == 0 { return "" } return "==== Class Skills ====\n\n * " + strings.Join(skills, ", ") } func (ctx *wikiContext) renderClassFeatProgression(row map[string]any) string { table := ctx.tableForValue(fieldValue(row, "FeatsTable"), ctx.classFeatTables) if table == nil { return "" } lines := []string{} byLevel := map[string][]string{} selectable := []string{} for _, featRow := range table.Rows { name := ctx.renderReference(fieldValue(featRow, "FeatIndex"), ctx.featIDToKey, ctx.resolveFeatName) if name == "" { name = ctx.renderReference(fieldValue(featRow, "FeatIndex"), nil, func(string) string { return "" }) } if name == "" { continue } level := stringValue(featRow, "GrantedOnLevel") if level == "" || strings.HasPrefix(level, "-") { selectable = append(selectable, name) continue } byLevel[level] = append(byLevel[level], name) } if len(byLevel) > 0 { lines = append(lines, "==== Granted Feats ====", "") for _, level := range sortedKeys(byLevel) { lines = append(lines, " * Level "+level+": "+strings.Join(byLevel[level], ", ")) } lines = append(lines, "") } if len(selectable) > 0 { lines = append(lines, "==== Selectable Feats ====", "", " * "+strings.Join(selectable, ", "), "") } return strings.TrimSpace(strings.Join(lines, "\n")) } func (ctx *wikiContext) renderClassFeatureTable(row map[string]any) string { table := ctx.tableForValue(fieldValue(row, "BonusFeatsTable"), ctx.classBonusTables) if table == nil || len(table.Rows) == 0 { return "" } return "==== Bonus Feats ====\n\n * Bonus feat table: " + table.OutputStem }