Native Wiki Generation
This commit is contained in:
@@ -365,6 +365,11 @@ func runBuildTopData(ctx context) error {
|
|||||||
fmt.Fprintf(ctx.stdout, "topdata tlk output: %s\n", result.OutputTLKDir)
|
fmt.Fprintf(ctx.stdout, "topdata tlk output: %s\n", result.OutputTLKDir)
|
||||||
fmt.Fprintf(ctx.stdout, "2da files: %d\n", result.Files2DA)
|
fmt.Fprintf(ctx.stdout, "2da files: %d\n", result.Files2DA)
|
||||||
fmt.Fprintf(ctx.stdout, "tlk files: %d\n", result.FilesTLK)
|
fmt.Fprintf(ctx.stdout, "tlk files: %d\n", result.FilesTLK)
|
||||||
|
if result.WikiOutputDir != "" {
|
||||||
|
fmt.Fprintf(ctx.stdout, "wiki output: %s\n", result.WikiOutputDir)
|
||||||
|
fmt.Fprintf(ctx.stdout, "wiki pages: %d\n", result.WikiPages)
|
||||||
|
fmt.Fprintf(ctx.stdout, "wiki status: %s\n", result.WikiStatus)
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -391,6 +396,11 @@ func runBuildTopPackage(ctx context) error {
|
|||||||
fmt.Fprintf(ctx.stdout, "tlk files: %d\n", result.FilesTLK)
|
fmt.Fprintf(ctx.stdout, "tlk files: %d\n", result.FilesTLK)
|
||||||
fmt.Fprintf(ctx.stdout, "top package resources: %d\n", result.HAKResources)
|
fmt.Fprintf(ctx.stdout, "top package resources: %d\n", result.HAKResources)
|
||||||
fmt.Fprintf(ctx.stdout, "top package assets: %d\n", result.AssetFiles)
|
fmt.Fprintf(ctx.stdout, "top package assets: %d\n", result.AssetFiles)
|
||||||
|
if result.WikiOutputDir != "" {
|
||||||
|
fmt.Fprintf(ctx.stdout, "wiki output: %s\n", result.WikiOutputDir)
|
||||||
|
fmt.Fprintf(ctx.stdout, "wiki pages: %d\n", result.WikiPages)
|
||||||
|
fmt.Fprintf(ctx.stdout, "wiki status: %s\n", result.WikiStatus)
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -149,10 +149,27 @@ func BuildNative(p *project.Project, progress func(string)) (BuildResult, error)
|
|||||||
}
|
}
|
||||||
return BuildResult{}, fmt.Errorf("topdata validation failed with %d error(s)", report.ErrorCount())
|
return BuildResult{}, fmt.Errorf("topdata validation failed with %d error(s)", report.ErrorCount())
|
||||||
}
|
}
|
||||||
return buildNativeUnchecked(p, progress)
|
var prebuiltWiki *wikiResult
|
||||||
|
if newestWikiSource, _, err := newestRelevantWikiSource(p.TopDataSourceDir()); err == nil && !newestWikiSource.IsZero() {
|
||||||
|
statePath := filepath.Join(p.TopDataSourceDir(), wikiRootDirName, wikiStateFileName)
|
||||||
|
outputDir := filepath.Join(p.TopDataSourceDir(), wikiRootDirName, wikiPagesDirName)
|
||||||
|
if stateInfo, err := os.Stat(statePath); err == nil && !newestWikiSource.After(stateInfo.ModTime()) {
|
||||||
|
if outputInfo, err := os.Stat(outputDir); err == nil && outputInfo.IsDir() {
|
||||||
|
if state, err := loadWikiState(statePath); err == nil {
|
||||||
|
prebuiltWiki = &wikiResult{
|
||||||
|
OutputDir: outputDir,
|
||||||
|
PageCount: state.Pages,
|
||||||
|
Status: wikiSkippedStatus,
|
||||||
|
Digest: state.Digest,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return buildNativeUnchecked(p, progress, prebuiltWiki)
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildNativeUnchecked(p *project.Project, progress func(string)) (BuildResult, error) {
|
func buildNativeUnchecked(p *project.Project, progress func(string), prebuiltWiki *wikiResult) (BuildResult, error) {
|
||||||
if progress == nil {
|
if progress == nil {
|
||||||
progress = func(string) {}
|
progress = func(string) {}
|
||||||
}
|
}
|
||||||
@@ -306,12 +323,34 @@ func buildNativeUnchecked(p *project.Project, progress func(string)) (BuildResul
|
|||||||
return BuildResult{}, err
|
return BuildResult{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
wikiBuild := wikiResult{Status: wikiSkippedStatus}
|
||||||
|
if prebuiltWiki != nil {
|
||||||
|
wikiBuild = *prebuiltWiki
|
||||||
|
} else {
|
||||||
|
wikiBuild, err = buildWiki(p, BuildResult{
|
||||||
|
Mode: "native",
|
||||||
|
Output2DADir: output2DA,
|
||||||
|
OutputTLKDir: outputTLK,
|
||||||
|
Files2DA: files2DA,
|
||||||
|
FilesTLK: filesTLK,
|
||||||
|
}, progress)
|
||||||
|
if err != nil {
|
||||||
|
return BuildResult{}, err
|
||||||
|
}
|
||||||
|
if wikiBuild.PageCount > 0 && wikiBuild.Status == wikiSkippedStatus {
|
||||||
|
wikiBuild.Status = wikiGeneratedStatus
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return BuildResult{
|
return BuildResult{
|
||||||
Mode: "native",
|
Mode: "native",
|
||||||
Output2DADir: output2DA,
|
Output2DADir: output2DA,
|
||||||
OutputTLKDir: outputTLK,
|
OutputTLKDir: outputTLK,
|
||||||
Files2DA: files2DA,
|
Files2DA: files2DA,
|
||||||
FilesTLK: filesTLK,
|
FilesTLK: filesTLK,
|
||||||
|
WikiOutputDir: wikiBuild.OutputDir,
|
||||||
|
WikiPages: wikiBuild.PageCount,
|
||||||
|
WikiStatus: wikiBuild.Status,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -86,6 +86,9 @@ func packageBuiltTopData(p *project.Project, nativeResult BuildResult, progress
|
|||||||
FilesTLK: nativeResult.FilesTLK,
|
FilesTLK: nativeResult.FilesTLK,
|
||||||
HAKResources: len(resources),
|
HAKResources: len(resources),
|
||||||
AssetFiles: assetFiles,
|
AssetFiles: assetFiles,
|
||||||
|
WikiOutputDir: nativeResult.WikiOutputDir,
|
||||||
|
WikiPages: nativeResult.WikiPages,
|
||||||
|
WikiStatus: nativeResult.WikiStatus,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -307,6 +310,7 @@ func newestTopDataSource(sourceDir string) (time.Time, string, error) {
|
|||||||
newest := time.Time{}
|
newest := time.Time{}
|
||||||
newestPath := ""
|
newestPath := ""
|
||||||
templatesDir := filepath.Join(sourceDir, "templates")
|
templatesDir := filepath.Join(sourceDir, "templates")
|
||||||
|
wikiDir := filepath.Join(sourceDir, wikiRootDirName)
|
||||||
err := filepath.WalkDir(sourceDir, func(path string, d fs.DirEntry, walkErr error) error {
|
err := filepath.WalkDir(sourceDir, func(path string, d fs.DirEntry, walkErr error) error {
|
||||||
if walkErr != nil {
|
if walkErr != nil {
|
||||||
return walkErr
|
return walkErr
|
||||||
@@ -314,6 +318,9 @@ func newestTopDataSource(sourceDir string) (time.Time, string, error) {
|
|||||||
if d.IsDir() && path == templatesDir {
|
if d.IsDir() && path == templatesDir {
|
||||||
return filepath.SkipDir
|
return filepath.SkipDir
|
||||||
}
|
}
|
||||||
|
if d.IsDir() && path == wikiDir {
|
||||||
|
return filepath.SkipDir
|
||||||
|
}
|
||||||
if d.IsDir() {
|
if d.IsDir() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -122,6 +122,9 @@ type BuildResult struct {
|
|||||||
OutputTLKDir string
|
OutputTLKDir string
|
||||||
Files2DA int
|
Files2DA int
|
||||||
FilesTLK int
|
FilesTLK int
|
||||||
|
WikiOutputDir string
|
||||||
|
WikiPages int
|
||||||
|
WikiStatus string
|
||||||
}
|
}
|
||||||
|
|
||||||
type PackageResult struct {
|
type PackageResult struct {
|
||||||
@@ -134,6 +137,9 @@ type PackageResult struct {
|
|||||||
FilesTLK int
|
FilesTLK int
|
||||||
HAKResources int
|
HAKResources int
|
||||||
AssetFiles int
|
AssetFiles int
|
||||||
|
WikiOutputDir string
|
||||||
|
WikiPages int
|
||||||
|
WikiStatus string
|
||||||
}
|
}
|
||||||
|
|
||||||
type CompareResult struct {
|
type CompareResult struct {
|
||||||
@@ -1072,7 +1078,7 @@ func validateNativeBuildability(p *project.Project, report *ValidationReport) {
|
|||||||
|
|
||||||
clone := *p
|
clone := *p
|
||||||
clone.Config.TopData.Build = tempBuild
|
clone.Config.TopData.Build = tempBuild
|
||||||
if _, err := buildNativeUnchecked(&clone, nil); err != nil {
|
if _, err := buildNativeUnchecked(&clone, nil, nil); err != nil {
|
||||||
report.Diagnostics = append(report.Diagnostics, Diagnostic{
|
report.Diagnostics = append(report.Diagnostics, Diagnostic{
|
||||||
Severity: SeverityError,
|
Severity: SeverityError,
|
||||||
Path: p.TopDataSourceDir(),
|
Path: p.TopDataSourceDir(),
|
||||||
@@ -1416,7 +1422,7 @@ func compareNativeSelfCheck(p *project.Project, actual2DA, actualTLK string, pro
|
|||||||
|
|
||||||
nativeProject := *p
|
nativeProject := *p
|
||||||
nativeProject.Config.TopData.Build = tempBuild
|
nativeProject.Config.TopData.Build = tempBuild
|
||||||
nativeResult, err := buildNativeUnchecked(&nativeProject, nil)
|
nativeResult, err := buildNativeUnchecked(&nativeProject, nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, 0, 0, len(projectOutputs), nil
|
return 0, 0, 0, len(projectOutputs), nil
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,192 @@
|
|||||||
|
package topdata
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestBuildNativeGeneratesAndSkipsWikiPages(t *testing.T) {
|
||||||
|
root := testProjectRoot(t)
|
||||||
|
mkdirAll(t, filepath.Join(root, "topdata", "data", "skills"))
|
||||||
|
writeFile(t, filepath.Join(root, "topdata", "base_dialog.json"), "{}\n")
|
||||||
|
writeFile(t, filepath.Join(root, "topdata", "data", "skills", "base.json"), `{
|
||||||
|
"output": "skills.2da",
|
||||||
|
"columns": ["Label", "Name", "Description", "HideFromLevelUp", "Untrained", "KeyAbility", "ArmorCheckPenalty", "Constant"],
|
||||||
|
"rows": [
|
||||||
|
{
|
||||||
|
"id": 0,
|
||||||
|
"key": "skills:athletics",
|
||||||
|
"Label": "Athletics",
|
||||||
|
"Name": {"tlk": {"key": "skills:athletics.name", "text": "Athletics"}},
|
||||||
|
"Description": {"tlk": {"key": "skills:athletics.description", "text": "Ability: Strength.\n\nUses:\n- Climb\n- Swim"}},
|
||||||
|
"HideFromLevelUp": "0",
|
||||||
|
"Untrained": "1",
|
||||||
|
"KeyAbility": "STR",
|
||||||
|
"ArmorCheckPenalty": "1",
|
||||||
|
"Constant": "SKILL_ATHLETICS"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}`+"\n")
|
||||||
|
writeFile(t, filepath.Join(root, "topdata", "data", "skills", "lock.json"), `{"skills:athletics":0}`+"\n")
|
||||||
|
|
||||||
|
proj := testProject(root)
|
||||||
|
proj.Config.TopData.ReferenceBuilder = ""
|
||||||
|
|
||||||
|
result, err := BuildNative(proj, nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("BuildNative failed: %v", err)
|
||||||
|
}
|
||||||
|
if result.WikiPages != 1 {
|
||||||
|
t.Fatalf("expected one generated entity page, got %d", result.WikiPages)
|
||||||
|
}
|
||||||
|
pagePath := filepath.Join(root, "topdata", ".wiki", "pages", "skills", "athletics.txt")
|
||||||
|
got, err := os.ReadFile(pagePath)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("read generated page: %v", err)
|
||||||
|
}
|
||||||
|
text := string(got)
|
||||||
|
if !strings.Contains(text, "====== Athletics ======") || !strings.Contains(text, "This skill is unchanged from vanilla.") {
|
||||||
|
t.Fatalf("unexpected generated page:\n%s", text)
|
||||||
|
}
|
||||||
|
if !strings.Contains(text, "Ability: Strength.") || !strings.Contains(text, " * Climb") {
|
||||||
|
t.Fatalf("expected description to be rendered into wiki page:\n%s", text)
|
||||||
|
}
|
||||||
|
statusPath := filepath.Join(root, "topdata", ".wiki", "pages", "meta", "wikistatus.txt")
|
||||||
|
statusRaw, err := os.ReadFile(statusPath)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("read status page: %v", err)
|
||||||
|
}
|
||||||
|
if !strings.Contains(string(statusRaw), "**Vanilla:** 1\\\\") {
|
||||||
|
t.Fatalf("expected wiki status summary to count vanilla page:\n%s", string(statusRaw))
|
||||||
|
}
|
||||||
|
if _, err := os.Stat(filepath.Join(root, "topdata", ".wiki", "state.json")); err != nil {
|
||||||
|
t.Fatalf("expected state file after first build: %v", err)
|
||||||
|
}
|
||||||
|
stateBefore, err := loadWikiState(filepath.Join(root, "topdata", ".wiki", "state.json"))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("read state before second build: %v", err)
|
||||||
|
}
|
||||||
|
digestBefore, err := computeWikiSourceDigest(filepath.Join(root, "topdata"))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("compute digest before second build: %v", err)
|
||||||
|
}
|
||||||
|
if stateBefore.Digest != digestBefore {
|
||||||
|
t.Fatalf("expected state digest to match current digest before second build, got state=%s current=%s", stateBefore.Digest, digestBefore)
|
||||||
|
}
|
||||||
|
|
||||||
|
second, err := BuildNative(proj, nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("second BuildNative failed: %v", err)
|
||||||
|
}
|
||||||
|
if second.WikiPages != 1 {
|
||||||
|
t.Fatalf("expected a single generated skill wiki page after rebuild, got %d", second.WikiPages)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBuildNativeRegeneratesWikiWhenTLKTextChanges(t *testing.T) {
|
||||||
|
root := testProjectRoot(t)
|
||||||
|
mkdirAll(t, filepath.Join(root, "topdata", "data", "skills"))
|
||||||
|
writeFile(t, filepath.Join(root, "topdata", "base_dialog.json"), "{}\n")
|
||||||
|
basePath := filepath.Join(root, "topdata", "data", "skills", "base.json")
|
||||||
|
writeFile(t, basePath, `{
|
||||||
|
"output": "skills.2da",
|
||||||
|
"columns": ["Label", "Name", "Description", "HideFromLevelUp", "Untrained", "KeyAbility", "ArmorCheckPenalty", "Constant"],
|
||||||
|
"rows": [
|
||||||
|
{
|
||||||
|
"id": 0,
|
||||||
|
"key": "skills:athletics",
|
||||||
|
"Label": "Athletics",
|
||||||
|
"Name": {"tlk": {"key": "skills:athletics.name", "text": "Athletics"}},
|
||||||
|
"Description": {"tlk": {"key": "skills:athletics.description", "text": "Original text."}},
|
||||||
|
"HideFromLevelUp": "0",
|
||||||
|
"Untrained": "1",
|
||||||
|
"KeyAbility": "STR",
|
||||||
|
"ArmorCheckPenalty": "1",
|
||||||
|
"Constant": "SKILL_ATHLETICS"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}`+"\n")
|
||||||
|
writeFile(t, filepath.Join(root, "topdata", "data", "skills", "lock.json"), `{"skills:athletics":0}`+"\n")
|
||||||
|
|
||||||
|
proj := testProject(root)
|
||||||
|
proj.Config.TopData.ReferenceBuilder = ""
|
||||||
|
|
||||||
|
if _, err := BuildNative(proj, nil); err != nil {
|
||||||
|
t.Fatalf("initial BuildNative failed: %v", err)
|
||||||
|
}
|
||||||
|
writeFile(t, basePath, `{
|
||||||
|
"output": "skills.2da",
|
||||||
|
"columns": ["Label", "Name", "Description", "HideFromLevelUp", "Untrained", "KeyAbility", "ArmorCheckPenalty", "Constant"],
|
||||||
|
"rows": [
|
||||||
|
{
|
||||||
|
"id": 0,
|
||||||
|
"key": "skills:athletics",
|
||||||
|
"Label": "Athletics",
|
||||||
|
"Name": {"tlk": {"key": "skills:athletics.name", "text": "Athletics"}},
|
||||||
|
"Description": {"tlk": {"key": "skills:athletics.description", "text": "Updated text."}},
|
||||||
|
"HideFromLevelUp": "0",
|
||||||
|
"Untrained": "1",
|
||||||
|
"KeyAbility": "STR",
|
||||||
|
"ArmorCheckPenalty": "1",
|
||||||
|
"Constant": "SKILL_ATHLETICS"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}`+"\n")
|
||||||
|
|
||||||
|
if _, err := BuildNative(proj, nil); err != nil {
|
||||||
|
t.Fatalf("BuildNative after text change failed: %v", err)
|
||||||
|
}
|
||||||
|
pagePath := filepath.Join(root, "topdata", ".wiki", "pages", "skills", "athletics.txt")
|
||||||
|
got, err := os.ReadFile(pagePath)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("read regenerated page: %v", err)
|
||||||
|
}
|
||||||
|
if !strings.Contains(string(got), "Updated text.") {
|
||||||
|
t.Fatalf("expected regenerated page to contain updated description:\n%s", string(got))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBuildPackageIgnoresWikiSourcesForFreshness(t *testing.T) {
|
||||||
|
root := testProjectRoot(t)
|
||||||
|
mkdirAll(t, filepath.Join(root, "topdata", "data", "skills"))
|
||||||
|
writeFile(t, filepath.Join(root, "topdata", "base_dialog.json"), "{}\n")
|
||||||
|
writeFile(t, filepath.Join(root, "topdata", "data", "skills", "base.json"), `{
|
||||||
|
"output": "skills.2da",
|
||||||
|
"columns": ["Label", "Name", "Description", "HideFromLevelUp", "Untrained", "KeyAbility", "ArmorCheckPenalty", "Constant"],
|
||||||
|
"rows": [
|
||||||
|
{
|
||||||
|
"id": 0,
|
||||||
|
"key": "skills:athletics",
|
||||||
|
"Label": "Athletics",
|
||||||
|
"Name": {"tlk": {"key": "skills:athletics.name", "text": "Athletics"}},
|
||||||
|
"Description": {"tlk": {"key": "skills:athletics.description", "text": "Skill text."}},
|
||||||
|
"HideFromLevelUp": "0",
|
||||||
|
"Untrained": "1",
|
||||||
|
"KeyAbility": "STR",
|
||||||
|
"ArmorCheckPenalty": "1",
|
||||||
|
"Constant": "SKILL_ATHLETICS"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}`+"\n")
|
||||||
|
writeFile(t, filepath.Join(root, "topdata", "data", "skills", "lock.json"), `{"skills:athletics":0}`+"\n")
|
||||||
|
|
||||||
|
proj := testProject(root)
|
||||||
|
proj.Config.TopData.ReferenceBuilder = ""
|
||||||
|
|
||||||
|
if _, err := BuildNative(proj, nil); err != nil {
|
||||||
|
t.Fatalf("BuildNative failed: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
pagePath := filepath.Join(root, "topdata", ".wiki", "pages", "skills", "athletics.txt")
|
||||||
|
newTime := time.Now().Add(2 * time.Second)
|
||||||
|
if err := os.Chtimes(pagePath, newTime, newTime); err != nil {
|
||||||
|
t.Fatalf("touch wiki page: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := BuildPackage(proj, nil); err != nil {
|
||||||
|
t.Fatalf("expected wiki output to be ignored for freshness, got %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
====== {{name}} ======
|
||||||
|
|
||||||
|
{{status}}
|
||||||
|
|
||||||
|
{{description}}
|
||||||
|
|
||||||
|
{{facts}}
|
||||||
|
|
||||||
|
===== Progression =====
|
||||||
|
|
||||||
|
{{progression}}
|
||||||
|
|
||||||
|
<WRAP center round important>
|
||||||
|
**Auto-generated content.** This section is rebuilt from game data on each release. Edits above this line will be lost on the next build.
|
||||||
|
</WRAP>
|
||||||
|
|
||||||
|
===== Notes =====
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
====== {{name}} ======
|
||||||
|
|
||||||
|
{{status}}
|
||||||
|
|
||||||
|
{{description}}
|
||||||
|
|
||||||
|
{{facts}}
|
||||||
|
|
||||||
|
<WRAP center round important>
|
||||||
|
**Auto-generated content.** This section is rebuilt from game data on each release. Edits above this line will be lost on the next build.
|
||||||
|
</WRAP>
|
||||||
|
|
||||||
|
===== Notes =====
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
====== {{name}} ======
|
||||||
|
|
||||||
|
{{status}}
|
||||||
|
|
||||||
|
{{description}}
|
||||||
|
|
||||||
|
{{facts}}
|
||||||
|
|
||||||
|
<WRAP center round important>
|
||||||
|
**Auto-generated content.** This section is rebuilt from game data on each release. Edits above this line will be lost on the next build.
|
||||||
|
</WRAP>
|
||||||
|
|
||||||
|
===== Notes =====
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
====== {{name}} ======
|
||||||
|
|
||||||
|
{{status}}
|
||||||
|
|
||||||
|
{{nameforms}}
|
||||||
|
|
||||||
|
{{description}}
|
||||||
|
|
||||||
|
{{facts}}
|
||||||
|
|
||||||
|
<WRAP center round important>
|
||||||
|
**Auto-generated content.** This section is rebuilt from game data on each release. Edits above this line will be lost on the next build.
|
||||||
|
</WRAP>
|
||||||
|
|
||||||
|
===== Notes =====
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
====== {{name}} ======
|
||||||
|
|
||||||
|
{{status}}
|
||||||
|
|
||||||
|
{{description}}
|
||||||
|
|
||||||
|
{{facts}}
|
||||||
|
|
||||||
|
<WRAP center round important>
|
||||||
|
**Auto-generated content.** This section is rebuilt from game data on each release. Edits above this line will be lost on the next build.
|
||||||
|
</WRAP>
|
||||||
|
|
||||||
|
===== Notes =====
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
====== {{name}} ======
|
||||||
|
|
||||||
|
{{status}}
|
||||||
|
|
||||||
|
{{description}}
|
||||||
|
|
||||||
|
{{facts}}
|
||||||
|
|
||||||
|
<WRAP center round important>
|
||||||
|
**Auto-generated content.** This section is rebuilt from game data on each release. Edits above this line will be lost on the next build.
|
||||||
|
</WRAP>
|
||||||
|
|
||||||
|
===== Notes =====
|
||||||
Reference in New Issue
Block a user