diff --git a/backend/character/handlers.go b/backend/character/handlers.go
index 680b599..65db65e 100644
--- a/backend/character/handlers.go
+++ b/backend/character/handlers.go
@@ -210,9 +210,9 @@ func GetCharacterExperienceAndWealth(c *gin.Context) {
// Berechne Gesamtvermögen in Silbergroschen
// Annahme: 1 GS = 10 SS, 1 SS = 10 KS (typische Midgard Währung)
- gs := character.Vermoegen.Goldstücke
- ss := character.Vermoegen.Silberstücke
- ks := character.Vermoegen.Kupferstücke
+ gs := character.Vermoegen.Goldstuecke
+ ss := character.Vermoegen.Silberstuecke
+ ks := character.Vermoegen.Kupferstuecke
totalInSS := (gs * 10) + ss + (ks / 10)
response := ExperienceAndWealthResponse{
@@ -355,9 +355,9 @@ func UpdateCharacterWealth(c *gin.Context) {
oldSilver := 0
oldCopper := 0
if character.Vermoegen.ID != 0 {
- oldGold = character.Vermoegen.Goldstücke
- oldSilver = character.Vermoegen.Silberstücke
- oldCopper = character.Vermoegen.Kupferstücke
+ oldGold = character.Vermoegen.Goldstuecke
+ oldSilver = character.Vermoegen.Silberstuecke
+ oldCopper = character.Vermoegen.Kupferstuecke
}
// Aktualisiere oder erstelle Vermögen
@@ -369,9 +369,9 @@ func UpdateCharacterWealth(c *gin.Context) {
CharacterID: character.ID,
UserID: userID,
},
- Goldstücke: getValueOrDefault(req.Goldstücke, 0),
- Silberstücke: getValueOrDefault(req.Silberstücke, 0),
- Kupferstücke: getValueOrDefault(req.Kupferstücke, 0),
+ Goldstuecke: getValueOrDefault(req.Goldstücke, 0),
+ Silberstuecke: getValueOrDefault(req.Silberstücke, 0),
+ Kupferstuecke: getValueOrDefault(req.Kupferstücke, 0),
}
if err := database.DB.Create(&character.Vermoegen).Error; err != nil {
respondWithError(c, http.StatusInternalServerError, "Failed to create wealth record")
@@ -380,13 +380,13 @@ func UpdateCharacterWealth(c *gin.Context) {
} else {
// Aktualisiere existierendes Vermögen
if req.Goldstücke != nil {
- character.Vermoegen.Goldstücke = *req.Goldstücke
+ character.Vermoegen.Goldstuecke = *req.Goldstücke
}
if req.Silberstücke != nil {
- character.Vermoegen.Silberstücke = *req.Silberstücke
+ character.Vermoegen.Silberstuecke = *req.Silberstücke
}
if req.Kupferstücke != nil {
- character.Vermoegen.Kupferstücke = *req.Kupferstücke
+ character.Vermoegen.Kupferstuecke = *req.Kupferstücke
}
if err := database.DB.Save(&character.Vermoegen).Error; err != nil {
respondWithError(c, http.StatusInternalServerError, "Failed to update wealth")
@@ -398,36 +398,36 @@ func UpdateCharacterWealth(c *gin.Context) {
// TODO: User-ID aus dem Authentifizierungs-Context holen
userID := uint(0) // Placeholder
- if req.Goldstücke != nil && oldGold != character.Vermoegen.Goldstücke {
+ if req.Goldstücke != nil && oldGold != character.Vermoegen.Goldstuecke {
CreateAuditLogEntry(
character.ID,
"gold",
oldGold,
- character.Vermoegen.Goldstücke,
+ character.Vermoegen.Goldstuecke,
AuditLogReason(req.Reason),
userID,
req.Notes,
)
}
- if req.Silberstücke != nil && oldSilver != character.Vermoegen.Silberstücke {
+ if req.Silberstücke != nil && oldSilver != character.Vermoegen.Silberstuecke {
CreateAuditLogEntry(
character.ID,
"silver",
oldSilver,
- character.Vermoegen.Silberstücke,
+ character.Vermoegen.Silberstuecke,
AuditLogReason(req.Reason),
userID,
req.Notes,
)
}
- if req.Kupferstücke != nil && oldCopper != character.Vermoegen.Kupferstücke {
+ if req.Kupferstücke != nil && oldCopper != character.Vermoegen.Kupferstuecke {
CreateAuditLogEntry(
character.ID,
"copper",
oldCopper,
- character.Vermoegen.Kupferstücke,
+ character.Vermoegen.Kupferstuecke,
AuditLogReason(req.Reason),
userID,
req.Notes,
@@ -437,9 +437,9 @@ func UpdateCharacterWealth(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
"message": "Wealth updated successfully",
"wealth": gin.H{
- "goldstücke": character.Vermoegen.Goldstücke,
- "silberstücke": character.Vermoegen.Silberstücke,
- "kupferstücke": character.Vermoegen.Kupferstücke,
+ "goldstücke": character.Vermoegen.Goldstuecke,
+ "silberstücke": character.Vermoegen.Silberstuecke,
+ "kupferstücke": character.Vermoegen.Kupferstuecke,
},
})
}
@@ -742,7 +742,7 @@ func deductResourcesForLearning(char *models.Char, skillName string, finalLevel,
// deductResourcesWithAuditReason zieht EP, Gold und PP ab und erstellt entsprechende Audit-Log-Einträge
func deductResourcesWithAuditReason(char *models.Char, itemName string, finalLevel, totalEP, totalGold, totalPP int, auditReason AuditLogReason) (int, int, error) {
currentEP := char.Erfahrungsschatz.EP
- currentGold := char.Vermoegen.Goldstücke
+ currentGold := char.Vermoegen.Goldstuecke
// EP abziehen und Audit-Log erstellen
newEP := currentEP - totalEP
@@ -780,7 +780,7 @@ func deductResourcesWithAuditReason(char *models.Char, itemName string, finalLev
if err != nil {
return 0, 0, fmt.Errorf("fehler beim Erstellen des Audit-Log-Eintrags: %v", err)
}
- char.Vermoegen.Goldstücke = newGold
+ char.Vermoegen.Goldstuecke = newGold
if err := database.DB.Save(&char.Vermoegen).Error; err != nil {
return 0, 0, fmt.Errorf("fehler beim Speichern des Vermögens: %v", err)
}
@@ -920,7 +920,7 @@ func validateResources(char *models.Char, skillName string, totalEP, totalGold,
}
// Prüfe, ob genügend Gold vorhanden ist
- currentGold := char.Vermoegen.Goldstücke
+ currentGold := char.Vermoegen.Goldstuecke
if currentGold < totalGold {
return fmt.Errorf("Nicht genügend Gold vorhanden")
}
@@ -953,7 +953,7 @@ func validateResources(char *models.Char, skillName string, totalEP, totalGold,
// TODO Fehlerbehandlung (Falls Tabelle nicht vorhanden ist)
func deductResources(char *models.Char, skillName string, currentLevel, finalLevel, totalEP, totalGold, totalPP int) (int, int, error) {
currentEP := char.Erfahrungsschatz.EP
- currentGold := char.Vermoegen.Goldstücke
+ currentGold := char.Vermoegen.Goldstuecke
// EP abziehen und Audit-Log erstellen
newEP := currentEP - totalEP
@@ -986,7 +986,7 @@ func deductResources(char *models.Char, skillName string, currentLevel, finalLev
if err != nil {
return newEP, newGold, fmt.Errorf("Fehler beim Erstellen des Audit-Log-Eintrags: %v", err)
}
- char.Vermoegen.Goldstücke = newGold
+ char.Vermoegen.Goldstuecke = newGold
if err := database.DB.Save(&char.Vermoegen).Error; err != nil {
return newEP, newGold, fmt.Errorf("Fehler beim Speichern des Vermögens: %v", err)
}
@@ -2769,7 +2769,7 @@ func FinalizeCharacterCreation(c *gin.Context) {
BamortCharTrait: models.BamortCharTrait{
UserID: userID,
},
- Goldstücke: 80,
+ Goldstuecke: 80,
},
// Bennies (Glückspunkte, etc.)
diff --git a/backend/character/handlers_test.go b/backend/character/handlers_test.go
index a1d847c..89e3d19 100644
--- a/backend/character/handlers_test.go
+++ b/backend/character/handlers_test.go
@@ -154,11 +154,11 @@ func TestImproveSkillHandler(t *testing.T) {
assert.Equal(t, 250, updatedChar.Erfahrungsschatz.EP, "Character should have 316 EP remaining")
// Check that Gold was deducted correctly
- assert.Equal(t, 290, updatedChar.Vermoegen.Goldstücke, "Character should have 370 Gold remaining")
+ assert.Equal(t, 290, updatedChar.Vermoegen.Goldstuecke, "Character should have 370 Gold remaining")
t.Logf("Test completed successfully!")
t.Logf("EP: %d -> %d (cost: %.0f)", 326, updatedChar.Erfahrungsschatz.EP, response["ep_cost"])
- t.Logf("Gold: %d -> %d (cost: %.0f)", 390, updatedChar.Vermoegen.Goldstücke, response["gold_cost"])
+ t.Logf("Gold: %d -> %d (cost: %.0f)", 390, updatedChar.Vermoegen.Goldstuecke, response["gold_cost"])
})
}
diff --git a/backend/character/learn_spell_test.go b/backend/character/learn_spell_test.go
index c578ca6..fb3e41d 100644
--- a/backend/character/learn_spell_test.go
+++ b/backend/character/learn_spell_test.go
@@ -37,14 +37,14 @@ func TestLearnSpell(t *testing.T) {
database.DB.Model(&character).Where("id = ?", 18).Update("erfahrungsschatz", character.Erfahrungsschatz)
}
- if character.Vermoegen.Goldstücke < 200 {
- character.Vermoegen.Goldstücke = 500
+ if character.Vermoegen.Goldstuecke < 200 {
+ character.Vermoegen.Goldstuecke = 500
database.DB.Model(&character).Where("id = ?", 18).Update("vermoegen", character.Vermoegen)
}
// Store initial resources for comparison
initialEP := character.Erfahrungsschatz.EP
- initialGold := character.Vermoegen.Goldstücke
+ initialGold := character.Vermoegen.Goldstuecke
// Create LernCostRequest (new format)
request := map[string]interface{}{
@@ -294,7 +294,7 @@ func TestLearnSpell(t *testing.T) {
BamortCharTrait: models.BamortCharTrait{
CharacterID: 22,
},
- Goldstücke: 10, // Insufficient gold
+ Goldstuecke: 10, // Insufficient gold
},
}
diff --git a/backend/go.mod b/backend/go.mod
index 09b950a..08c488b 100644
--- a/backend/go.mod
+++ b/backend/go.mod
@@ -6,8 +6,11 @@ go 1.24.0
toolchain go1.24.4
require (
+ github.com/chromedp/cdproto v0.0.0-20250803210736-d308e07a266d
+ github.com/chromedp/chromedp v0.14.2
github.com/gin-contrib/cors v1.7.3
github.com/gin-gonic/gin v1.10.0
+ github.com/pdfcpu/pdfcpu v0.11.1
github.com/stretchr/testify v1.10.0
gorm.io/driver/mysql v1.5.7
gorm.io/driver/sqlite v1.5.7
@@ -18,8 +21,6 @@ require (
filippo.io/edwards25519 v1.1.0 // indirect
github.com/bytedance/sonic v1.12.8 // indirect
github.com/bytedance/sonic/loader v0.2.3 // indirect
- github.com/chromedp/cdproto v0.0.0-20250803210736-d308e07a266d // indirect
- github.com/chromedp/chromedp v0.14.2 // indirect
github.com/chromedp/sysutil v1.1.0 // indirect
github.com/clipperhouse/uax29/v2 v2.2.0 // indirect
github.com/cloudwego/base64x v0.1.5 // indirect
@@ -49,7 +50,6 @@ require (
github.com/mattn/go-sqlite3 v1.14.24 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
- github.com/pdfcpu/pdfcpu v0.11.1 // indirect
github.com/pelletier/go-toml/v2 v2.2.3 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
diff --git a/backend/go.sum b/backend/go.sum
index 01c26e7..772c897 100644
--- a/backend/go.sum
+++ b/backend/go.sum
@@ -72,6 +72,8 @@ github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
+github.com/ledongthuc/pdf v0.0.0-20220302134840-0c2507a12d80 h1:6Yzfa6GP0rIo/kULo2bwGEkFvCePZ3qHDDTC3/J9Swo=
+github.com/ledongthuc/pdf v0.0.0-20220302134840-0c2507a12d80/go.mod h1:imJHygn/1yfhB7XSJJKlFZKl/J+dCPAknuiaGOshXAs=
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
@@ -85,6 +87,8 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
+github.com/orisano/pixelmatch v0.0.0-20220722002657-fb0b55479cde h1:x0TT0RDC7UhAVbbWWBzr41ElhJx5tXPWkIHA2HWPRuw=
+github.com/orisano/pixelmatch v0.0.0-20220722002657-fb0b55479cde/go.mod h1:nZgzbfBr3hhjoZnS66nKrHmduYNpc34ny7RK4z5/HM0=
github.com/pdfcpu/pdfcpu v0.11.1 h1:htHBSkGH5jMKWC6e0sihBFbcKZ8vG1M67c8/dJxhjas=
github.com/pdfcpu/pdfcpu v0.11.1/go.mod h1:pP3aGga7pRvwFWAm9WwFvo+V68DfANi9kxSQYioNYcw=
github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M=
@@ -113,25 +117,15 @@ github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65E
github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
golang.org/x/arch v0.13.0 h1:KCkqVVV1kGg0X87TFysjCJ8MxtZEIU4Ja/yXGeoECdA=
golang.org/x/arch v0.13.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
-golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc=
-golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc=
golang.org/x/crypto v0.43.0 h1:dduJYIi3A3KOfdGOHX8AVZ/jGiyPa3IbBozJ5kNuE04=
golang.org/x/crypto v0.43.0/go.mod h1:BFbav4mRNlXJL4wNeejLpWxB7wMbc79PdRGhWKncxR0=
golang.org/x/image v0.32.0 h1:6lZQWq75h7L5IWNk0r+SCpUJ6tUVd3v4ZHnbRKLkUDQ=
golang.org/x/image v0.32.0/go.mod h1:/R37rrQmKXtO6tYXAjtDLwQgFLHmhW+V6ayXlxzP2Pc=
-golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0=
-golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k=
golang.org/x/net v0.45.0 h1:RLBg5JKixCy82FtLJpeNlVM0nrSqpCRYzVU1n8kj0tM=
golang.org/x/net v0.45.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=
-golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
-golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA=
-golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ=
golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
-golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
-golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k=
golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
diff --git a/backend/models/model_character.go b/backend/models/model_character.go
index 19d90bf..de5ad94 100644
--- a/backend/models/model_character.go
+++ b/backend/models/model_character.go
@@ -69,9 +69,9 @@ type Bennies struct {
type Vermoegen struct {
BamortCharTrait
- Goldstücke int `json:"goldstücke"` // GS
- Silberstücke int `json:"silberstücke"` // SS
- Kupferstücke int `json:"kupferstücke"` // KS
+ Goldstuecke int `json:"goldstücke"` // GS
+ Silberstuecke int `json:"silberstücke"` // SS
+ Kupferstuecke int `json:"kupferstücke"` // KS
}
type Char struct {
diff --git a/backend/models/model_character_test.go b/backend/models/model_character_test.go
index d963a08..c75f922 100644
--- a/backend/models/model_character_test.go
+++ b/backend/models/model_character_test.go
@@ -79,9 +79,9 @@ func createTestChar(name string) *Char {
Sg: 0,
},
Vermoegen: Vermoegen{
- Goldstücke: 100,
- Silberstücke: 50,
- Kupferstücke: 25,
+ Goldstuecke: 100,
+ Silberstuecke: 50,
+ Kupferstuecke: 25,
},
Erfahrungsschatz: Erfahrungsschatz{
ES: 150,
@@ -435,7 +435,7 @@ func TestChar_CreateWithCompleteData(t *testing.T) {
assert.Equal(t, testChar.B.Max, foundChar.B.Max)
assert.Equal(t, testChar.Merkmale.Augenfarbe, foundChar.Merkmale.Augenfarbe)
assert.Equal(t, testChar.Bennies.Gg, foundChar.Bennies.Gg)
- assert.Equal(t, testChar.Vermoegen.Goldstücke, foundChar.Vermoegen.Goldstücke)
+ assert.Equal(t, testChar.Vermoegen.Goldstuecke, foundChar.Vermoegen.Goldstuecke)
assert.Equal(t, testChar.Erfahrungsschatz.ES, foundChar.Erfahrungsschatz.ES)
}
@@ -467,9 +467,9 @@ func TestChar_WealthManagement(t *testing.T) {
setupCharacterTestDB(t)
testChar := createTestChar("Wealthy Character")
- testChar.Vermoegen.Goldstücke = 1000
- testChar.Vermoegen.Silberstücke = 500
- testChar.Vermoegen.Kupferstücke = 100
+ testChar.Vermoegen.Goldstuecke = 1000
+ testChar.Vermoegen.Silberstuecke = 500
+ testChar.Vermoegen.Kupferstuecke = 100
err := testChar.Create()
require.NoError(t, err, "Character creation should succeed")
@@ -479,9 +479,9 @@ func TestChar_WealthManagement(t *testing.T) {
err = foundChar.First(testChar.Name)
require.NoError(t, err, "Character should be found")
- assert.Equal(t, 1000, foundChar.Vermoegen.Goldstücke, "Gold should match")
- assert.Equal(t, 500, foundChar.Vermoegen.Silberstücke, "Silver should match")
- assert.Equal(t, 100, foundChar.Vermoegen.Kupferstücke, "Copper should match")
+ assert.Equal(t, 1000, foundChar.Vermoegen.Goldstuecke, "Gold should match")
+ assert.Equal(t, 500, foundChar.Vermoegen.Silberstuecke, "Silver should match")
+ assert.Equal(t, 100, foundChar.Vermoegen.Kupferstuecke, "Copper should match")
}
func TestChar_EdgeCases(t *testing.T) {
diff --git a/backend/pdfrender/integration_test.go b/backend/pdfrender/integration_test.go
index 5214d60..2dac4c0 100644
--- a/backend/pdfrender/integration_test.go
+++ b/backend/pdfrender/integration_test.go
@@ -1,6 +1,7 @@
package pdfrender
import (
+ "bamort/database"
"bamort/models"
"os"
"strings"
@@ -48,6 +49,11 @@ func TestIntegration_FullPDFGeneration(t *testing.T) {
B: models.B{
Value: 15,
},
+ Vermoegen: models.Vermoegen{
+ Goldstuecke: 100,
+ Silberstuecke: 50,
+ Kupferstuecke: 25,
+ },
Fertigkeiten: []models.SkFertigkeit{
{
BamortCharTrait: models.BamortCharTrait{
@@ -151,9 +157,9 @@ func TestIntegration_TemplateMetadata(t *testing.T) {
expectedMax int
}{
{"page1_stats.html", "skills_column1", 29},
- {"page2_play.html", "skills_learned", 18}, // From template: MAX: 18
- {"page3_spell.html", "spells_left", 26}, // From template: MAX: 26
- {"page3_spell.html", "spells_right", 15}, // From template: MAX: 15
+ {"page2_play.html", "skills_learned", 17}, // From template: MAX: 17
+ {"page3_spell.html", "spells_left", 15}, // From template: MAX: 15
+ {"page3_spell.html", "spells_right", 10}, // From template: MAX: 10
{"page4_equip.html", "equipment_worn", 10},
}
@@ -278,11 +284,11 @@ func TestIntegration_MultiPageSpellList(t *testing.T) {
spells := make([]SpellViewModel, 30)
for i := 0; i < 30; i++ {
spells[i] = SpellViewModel{
- Name: "Zauber Nr. " + string(rune('A'+i%26)),
- AP: 5,
- Category: 1,
- Duration: "1 Minute",
- CastTime: "1 sec",
+ Name: "Zauber Nr. " + string(rune('A'+i%26)),
+ AP: "5",
+ Stufe: 1,
+ Wirkungsdauer: "1 Minute",
+ Zauberdauer: "1 sec",
}
}
@@ -296,21 +302,21 @@ func TestIntegration_MultiPageSpellList(t *testing.T) {
t.Fatalf("Failed to paginate spells: %v", err)
}
- // With 30 capacity (20+10), should create 1 page for 30 spells
+ // With 25 capacity (15+10), 30 spells should need 2 pages
// Verify distribution
- // With 20+10 capacity, 30 spells should fit on 1 page
- if len(pages) != 1 {
- t.Fatalf("Expected 1 page for 30 spells, got %d", len(pages))
+ // With 15+10 capacity, 30 spells should need 2 pages
+ if len(pages) != 2 {
+ t.Fatalf("Expected 2 pages for 30 spells, got %d", len(pages))
}
- // Page 1: 20 (left) + 10 (right) = 30 spells
+ // Page 1: 15 (left) + 10 (right) = 25 spells
leftPage1 := pages[0].Data["spells_left"].([]SpellViewModel)
rightPage1 := pages[0].Data["spells_right"].([]SpellViewModel)
totalPage1 := len(leftPage1) + len(rightPage1)
- if totalPage1 != 30 {
- t.Errorf("Expected 30 spells on page 1 (20+10), got %d", totalPage1)
+ if totalPage1 != 25 {
+ t.Errorf("Expected 25 spells on page 1 (15+10), got %d", totalPage1)
}
t.Logf("Successfully distributed 30 spells: Page 1 has %d (left %d, right %d)", totalPage1, len(leftPage1), len(rightPage1))
@@ -451,6 +457,7 @@ func TestIntegration_CompleteWorkflow(t *testing.T) {
// TestVisualInspection_AllPages generates all 4 page types and saves them to disk
// Run with: go test -v ./pdfrender/... -run TestVisualInspection
func TestVisualInspection_AllPages(t *testing.T) {
+ database.SetupTestDB()
// Create a rich character with data for all page types
char := &models.Char{
BamortBase: models.BamortBase{
@@ -479,6 +486,11 @@ func TestVisualInspection_AllPages(t *testing.T) {
Lp: models.Lp{Value: 42, Max: 48},
Ap: models.Ap{Value: 28, Max: 32},
B: models.B{Value: 18},
+ Vermoegen: models.Vermoegen{
+ Goldstuecke: 100,
+ Silberstuecke: 50,
+ Kupferstuecke: 2,
+ },
}
// Add skills
@@ -486,11 +498,9 @@ func TestVisualInspection_AllPages(t *testing.T) {
"Schwimmen", "Klettern", "Reiten", "Laufen", "Springen",
"Balancieren", "Schleichen", "Sich Verstecken", "Singen",
"Tanzen", "Musizieren", "Malen", "Kochen", "Erste Hilfe",
- "Himmelskunde", "Pflanzenkunde", "Tierkunde", "Geografie",
+ "Himmelskunde", "Pflanzenkunde", "Tierkunde", "Heilkunde",
"Geschichte", "Lesen/Schreiben", "Rechnen", "Schätzen",
- "Heilkunde", "Giftmischen", "Alchimie", "Schmieden",
- "Lederarbeiten", "Holzbearbeitung", "Steinmetzkunst",
- "Schlösser öffnen", "Fallen entschärfen", "Taschendiebstahl",
+ "Heilkunde", "Giftmischen", "Alchimie", "Schlösser öffnen",
}
char.Fertigkeiten = make([]models.SkFertigkeit, len(skillNames))
for i, name := range skillNames {
@@ -526,8 +536,7 @@ func TestVisualInspection_AllPages(t *testing.T) {
"Macht über die belebte Natur", "Macht über das Selbst",
"Erkennen von Gift", "Heilen von Wunden", "Bannen von Zauberwerk",
"Schutz vor Dämonen", "Macht über Unbelebtes", "Angst",
- "Unsichtbarkeit", "Feuerlanze", "Eisstrahl", "Blitz",
- "Verwandlung", "Teleportation", "Hellsicht",
+ "Unsichtbarkeit", "Feuerlanze",
}
char.Zauber = make([]models.SkZauber, len(spellNames))
for i, name := range spellNames {
diff --git a/backend/pdfrender/mapper.go b/backend/pdfrender/mapper.go
index 9aa6513..45c6675 100644
--- a/backend/pdfrender/mapper.go
+++ b/backend/pdfrender/mapper.go
@@ -1,6 +1,9 @@
package pdfrender
import (
+ "fmt"
+
+ "bamort/database"
"bamort/models"
)
@@ -28,6 +31,11 @@ func MapCharacterToViewModel(char *models.Char) (*CharacterSheetViewModel, error
Religion: char.Glaube,
Stand: char.SocialClass,
IconBase64: "", // Will be set later if image exists
+ Vermoegen: WealthInfo{
+ Goldstuecke: char.Vermoegen.Goldstuecke,
+ Silberstuecke: char.Vermoegen.Silberstuecke,
+ Kupferstuecke: char.Vermoegen.Kupferstuecke,
+ },
}
// Map attributes
@@ -129,10 +137,45 @@ func mapWeapons(char *models.Char) []WeaponViewModel {
func mapSpells(char *models.Char) []SpellViewModel {
spells := make([]SpellViewModel, 0, len(char.Zauber))
- for _, spell := range char.Zauber {
- spells = append(spells, SpellViewModel{
- Name: spell.Name,
- })
+ for _, charSpell := range char.Zauber {
+ vm := SpellViewModel{
+ Name: charSpell.Name,
+ Bonus: charSpell.Bonus,
+ }
+
+ // Try to load spell details from gsmaster (only if database is available)
+ // In test environments without DB, we skip this enrichment
+ if database.DB != nil {
+ masterSpell := &models.Spell{}
+ err := masterSpell.First(charSpell.Name)
+
+ // If master spell found, add all details
+ if err == nil && masterSpell.ID > 0 {
+ vm.Stufe = masterSpell.Stufe
+ vm.AP = masterSpell.AP
+ vm.Art = masterSpell.Art
+ vm.Zauberdauer = masterSpell.Zauberdauer
+ vm.Reichweite = masterSpell.Reichweite
+ vm.Wirkungsziel = masterSpell.Wirkungsziel
+ vm.Wirkungsbereich = masterSpell.Wirkungsbereich
+ vm.Wirkungsdauer = masterSpell.Wirkungsdauer
+ vm.Ursprung = masterSpell.Ursprung
+ vm.Category = masterSpell.Category
+ vm.LearningCategory = masterSpell.LearningCategory
+ vm.Beschreibung = masterSpell.Beschreibung
+
+ // If description is empty, use source code and page number
+ if vm.Beschreibung == "" && masterSpell.SourceID > 0 && masterSpell.PageNumber > 0 {
+ source := &models.Source{}
+ if err := database.DB.First(source, masterSpell.SourceID).Error; err == nil {
+ vm.Beschreibung = source.Code + " S." + fmt.Sprintf("%d", masterSpell.PageNumber)
+ }
+ }
+ }
+ }
+ // If spell details not found or DB not available, just use name and bonus from character
+
+ spells = append(spells, vm)
}
return spells
diff --git a/backend/pdfrender/pagination_test.go b/backend/pdfrender/pagination_test.go
index 1e742d2..6cfe058 100644
--- a/backend/pdfrender/pagination_test.go
+++ b/backend/pdfrender/pagination_test.go
@@ -243,20 +243,20 @@ func TestPaginateSpells_MultiPage(t *testing.T) {
t.Fatalf("Expected no error, got %v", err)
}
- // With capacity of 26+15=41 (from template), all 30 spells fit on 1 page
- if len(pages) != 1 {
- t.Fatalf("Expected 1 page, got %d", len(pages))
+ // With capacity of 15+10=25 (from template), 30 spells require 2 pages
+ if len(pages) != 2 {
+ t.Fatalf("Expected 2 pages, got %d", len(pages))
}
- // Page 1 should have all 30 spells (26 left + 4 right, since we only have 30 total)
+ // Page 1 should have 25 spells (15 left + 10 right)
page1 := pages[0]
leftPage1 := page1.Data["spells_left"].([]SpellViewModel)
rightPage1 := page1.Data["spells_right"].([]SpellViewModel)
- if len(leftPage1) != 26 {
- t.Errorf("Page 1 left: expected 26 spells (template capacity), got %d", len(leftPage1))
+ if len(leftPage1) != 15 {
+ t.Errorf("Page 1 left: expected 15 spells (template capacity), got %d", len(leftPage1))
}
- if len(rightPage1) != 4 {
- t.Errorf("Page 1 right: expected 4 spells (remaining from 30), got %d", len(rightPage1))
+ if len(rightPage1) != 10 {
+ t.Errorf("Page 1 right: expected 10 spells (template capacity), got %d", len(rightPage1))
}
}
@@ -294,7 +294,7 @@ func TestPaginateWeapons_MultiPage(t *testing.T) {
templateSet := DefaultA4QuerTemplateSet()
paginator := NewPaginator(templateSet)
- // Create 50 weapons - should span 3 pages (24 capacity per page from template)
+ // Create 50 weapons - should span 3 pages (22 capacity per page from template)
weapons := make([]WeaponViewModel, 50)
for i := 0; i < 50; i++ {
weapons[i] = WeaponViewModel{Name: "Weapon" + string(rune(i))}
@@ -309,25 +309,25 @@ func TestPaginateWeapons_MultiPage(t *testing.T) {
}
if len(pages) != 3 {
- t.Fatalf("Expected 3 pages (24+24+2 from template capacity), got %d", len(pages))
+ t.Fatalf("Expected 3 pages (22+22+6 from template capacity), got %d", len(pages))
}
- // Page 1 should have 24 weapons
+ // Page 1 should have 22 weapons
page1Weapons := pages[0].Data["weapons_main"].([]WeaponViewModel)
- if len(page1Weapons) != 24 {
- t.Errorf("Page 1: expected 24 weapons (template capacity), got %d", len(page1Weapons))
+ if len(page1Weapons) != 22 {
+ t.Errorf("Page 1: expected 22 weapons (template capacity), got %d", len(page1Weapons))
}
- // Page 2 should have 24 weapons
+ // Page 2 should have 22 weapons
page2Weapons := pages[1].Data["weapons_main"].([]WeaponViewModel)
- if len(page2Weapons) != 24 {
- t.Errorf("Page 2: expected 24 weapons (template capacity), got %d", len(page2Weapons))
+ if len(page2Weapons) != 22 {
+ t.Errorf("Page 2: expected 22 weapons (template capacity), got %d", len(page2Weapons))
}
- // Page 3 should have 2 weapons (remaining)
+ // Page 3 should have 6 weapons (remaining)
page3Weapons := pages[2].Data["weapons_main"].([]WeaponViewModel)
- if len(page3Weapons) != 2 {
- t.Errorf("Page 3: expected 2 weapons (remaining), got %d", len(page3Weapons))
+ if len(page3Weapons) != 6 {
+ t.Errorf("Page 3: expected 6 weapons (remaining), got %d", len(page3Weapons))
}
}
@@ -348,11 +348,11 @@ func TestCalculatePagesNeeded(t *testing.T) {
{"59 skills on page1", "page1_stats.html", "skills", 59, 2}, // 59 requires 2 pages
{"100 skills on page1", "page1_stats.html", "skills", 100, 2},
{"10 weapons on page2", "page2_play.html", "weapons", 10, 1},
- {"24 weapons on page2", "page2_play.html", "weapons", 24, 1}, // MAX:24 from template
- {"25 weapons on page2", "page2_play.html", "weapons", 25, 2}, // exceeds capacity
+ {"22 weapons on page2", "page2_play.html", "weapons", 22, 1}, // MAX:22 from template
+ {"23 weapons on page2", "page2_play.html", "weapons", 23, 2}, // exceeds capacity
{"10 spells on page3", "page3_spell.html", "spells", 10, 1},
- {"41 spells on page3", "page3_spell.html", "spells", 41, 1}, // 26+15 = 41 fits on 1 page (from template)
- {"42 spells on page3", "page3_spell.html", "spells", 42, 2}, // 42 requires 2 pages
+ {"25 spells on page3", "page3_spell.html", "spells", 25, 1}, // 15+10 = 25 fits on 1 page (from template)
+ {"26 spells on page3", "page3_spell.html", "spells", 26, 2}, // 26 requires 2 pages
}
for _, tc := range testCases {
diff --git a/backend/pdfrender/template_metadata.go b/backend/pdfrender/template_metadata.go
index 30e22b9..6697d0c 100644
--- a/backend/pdfrender/template_metadata.go
+++ b/backend/pdfrender/template_metadata.go
@@ -153,7 +153,7 @@ func getHardcodedTemplateSet() TemplateSet {
{
Name: "weapons_main",
ListType: "weapons",
- MaxItems: 30,
+ MaxItems: 22,
},
},
},
@@ -168,7 +168,7 @@ func getHardcodedTemplateSet() TemplateSet {
{
Name: "spells_left",
ListType: "spells",
- MaxItems: 20,
+ MaxItems: 15,
Column: 1,
},
{
diff --git a/backend/pdfrender/template_metadata_loader_test.go b/backend/pdfrender/template_metadata_loader_test.go
index 7518b23..bdba9fc 100644
--- a/backend/pdfrender/template_metadata_loader_test.go
+++ b/backend/pdfrender/template_metadata_loader_test.go
@@ -89,9 +89,9 @@ func TestDefaultA4QuerTemplateSet_LoadsFromFiles(t *testing.T) {
if spellsLeft == nil {
t.Error("spells_left block not found")
} else {
- // Should be 26 from the template file ()
- if spellsLeft.MaxItems != 26 {
- t.Errorf("Expected spells_left MaxItems 26 (from template file), got %d", spellsLeft.MaxItems)
+ // Should be 15 from the template file ()
+ if spellsLeft.MaxItems != 15 {
+ t.Errorf("Expected spells_left MaxItems 15 (from template file), got %d", spellsLeft.MaxItems)
}
}
}
diff --git a/backend/pdfrender/templates_test.go b/backend/pdfrender/templates_test.go
index f52a708..49f7db4 100644
--- a/backend/pdfrender/templates_test.go
+++ b/backend/pdfrender/templates_test.go
@@ -82,23 +82,23 @@ func TestGetTemplateMetadata(t *testing.T) {
t.Fatal("Expected metadata blocks, got none")
}
- // Check for spells_left block (template says MAX: 26)
+ // Check for spells_left block (template says MAX: 15)
leftBlock := GetBlockByName(metadata, "spells_left")
if leftBlock == nil {
t.Error("Expected to find 'spells_left' block")
} else {
- if leftBlock.MaxItems != 26 {
- t.Errorf("Expected spells_left max 26 (from template), got %d", leftBlock.MaxItems)
+ if leftBlock.MaxItems != 15 {
+ t.Errorf("Expected spells_left max 15 (from template), got %d", leftBlock.MaxItems)
}
}
- // Check for spells_right block (template says MAX: 15)
+ // Check for spells_right block (template says MAX: 10)
rightBlock := GetBlockByName(metadata, "spells_right")
if rightBlock == nil {
t.Error("Expected to find 'spells_right' block")
} else {
- if rightBlock.MaxItems != 15 {
- t.Errorf("Expected spells_right max 15 (from template), got %d", rightBlock.MaxItems)
+ if rightBlock.MaxItems != 10 {
+ t.Errorf("Expected spells_right max 10 (from template), got %d", rightBlock.MaxItems)
}
}
}
diff --git a/backend/pdfrender/todo.md b/backend/pdfrender/todo.md
index 178dd79..e737886 100644
--- a/backend/pdfrender/todo.md
+++ b/backend/pdfrender/todo.md
@@ -1,29 +1,5 @@
-* ✓ Template meta data must NOT be hard coded (func DefaultA4QuerTemplateSet ) but must be read from theTemplate itself.
- OR if default values must be defined they must be overwritten from the statements fount in the template
- **COMPLETED**: DefaultA4QuerTemplateSet() now calls LoadTemplateSetFromFiles() which parses HTML comments.
- Falls back to hardcoded values if files can't be read.
-* ✓ fill table with empty lines up to the my max value
- **COMPLETED**: Added FillToCapacity() function, integrated into PreparePaginatedPageData().
- All lists now filled to MAX capacity from template metadata.
-
-* ✓ the tests for pagination must take the max values to test against from the template or from the metadata already updated by loading from template
- **COMPLETED**: All tests updated to read MAX values from templates dynamically using GetBlockCapacity().
- Tests no longer hardcode expected values.
-
-* ✓ paginating does not work in page 2 for
-
-
- **COMPLETED**: PreparePaginatedPageData() now reads capacities from template metadata using GetBlockCapacity().
- Page2 correctly uses MAX:18 for skills_learned, MAX:15 for skills_unlearned, MAX:5 for skills_languages, MAX:24 for weapons_main.
-
-* ✓ FillToCapacity() does not work
- in page 2 for
- in page 3 for
- **COMPLETED**: Fixed PreparePaginatedPageData() to read correct MAX values from templates.
- skills_languages now uses MAX:5 (not 11), magic_items now uses MAX:8 (not 5).
- All blocks properly filled to capacity with empty rows.
-
* weapons_main list currently uses Waffenfertigkeiten (weapon skills).
NOTE: Equipment.Weapons (EqWaffe) contains physical weapons with metadata like Abwb/Schb.
Waffenfertigkeiten already provides EW (Fertigkeitswert) which is the skill value needed for the character sheet.
- Current implementation is correct - weapons_main shows weapon skills with their EW values.
\ No newline at end of file
+ Current implementation is correct - weapons_main shows weapon skills with their EW values.
+ * The implementation is NOT correct, because the eapons_main shows weapon skills. But it should show the weapons list from the equipment
\ No newline at end of file
diff --git a/backend/pdfrender/todo_fixes_test.go b/backend/pdfrender/todo_fixes_test.go
index 3a3a2ce..ddd6cc8 100644
--- a/backend/pdfrender/todo_fixes_test.go
+++ b/backend/pdfrender/todo_fixes_test.go
@@ -28,24 +28,24 @@ func TestPaginationUsesTemplateMetadata(t *testing.T) {
if skillsLearned == nil {
t.Fatal("skills_learned block not found")
}
- if skillsLearned.MaxItems != 18 {
- t.Errorf("skills_learned: expected MAX 18 from template, got %d", skillsLearned.MaxItems)
+ if skillsLearned.MaxItems != 17 {
+ t.Errorf("skills_learned: expected MAX 17 from template, got %d", skillsLearned.MaxItems)
}
skillsLanguages := GetBlockByName(page2.Metadata.Blocks, "skills_languages")
if skillsLanguages == nil {
t.Fatal("skills_languages block not found")
}
- if skillsLanguages.MaxItems != 5 {
- t.Errorf("skills_languages: expected MAX 5 from template, got %d", skillsLanguages.MaxItems)
+ if skillsLanguages.MaxItems != 4 {
+ t.Errorf("skills_languages: expected MAX 4 from template, got %d", skillsLanguages.MaxItems)
}
weaponsMain := GetBlockByName(page2.Metadata.Blocks, "weapons_main")
if weaponsMain == nil {
t.Fatal("weapons_main block not found")
}
- if weaponsMain.MaxItems != 24 {
- t.Errorf("weapons_main: expected MAX 24 from template, got %d", weaponsMain.MaxItems)
+ if weaponsMain.MaxItems != 22 {
+ t.Errorf("weapons_main: expected MAX 22 from template, got %d", weaponsMain.MaxItems)
}
}
@@ -70,16 +70,16 @@ func TestPage2PaginationWithCorrectCapacities(t *testing.T) {
}
// Verify capacities match template (18, 5, 24)
- if len(pageData.SkillsLearned) != 18 {
- t.Errorf("SkillsLearned should be filled to 18, got %d", len(pageData.SkillsLearned))
+ if len(pageData.SkillsLearned) != 17 {
+ t.Errorf("SkillsLearned should be filled to 17, got %d", len(pageData.SkillsLearned))
}
- if len(pageData.SkillsLanguage) != 5 {
- t.Errorf("SkillsLanguage should be filled to 5, got %d", len(pageData.SkillsLanguage))
+ if len(pageData.SkillsLanguage) != 4 {
+ t.Errorf("SkillsLanguage should be filled to 4, got %d", len(pageData.SkillsLanguage))
}
- if len(pageData.Weapons) != 24 {
- t.Errorf("Weapons should be filled to 24, got %d", len(pageData.Weapons))
+ if len(pageData.Weapons) != 22 {
+ t.Errorf("Weapons should be filled to 22, got %d", len(pageData.Weapons))
}
}
@@ -101,8 +101,8 @@ func TestPage3MagicItemsCapacity(t *testing.T) {
}
// Template says MAX: 8 for magic_items
- if len(pageData.MagicItems) != 8 {
- t.Errorf("MagicItems should be filled to 8, got %d", len(pageData.MagicItems))
+ if len(pageData.MagicItems) != 5 {
+ t.Errorf("MagicItems should be filled to 5, got %d", len(pageData.MagicItems))
}
}
diff --git a/backend/pdfrender/viewmodel.go b/backend/pdfrender/viewmodel.go
index dca030a..03d6015 100644
--- a/backend/pdfrender/viewmodel.go
+++ b/backend/pdfrender/viewmodel.go
@@ -31,6 +31,14 @@ type CharacterInfo struct {
Homeland string
Religion string
Stand string // Sozialer Stand
+ Vermoegen WealthInfo
+}
+
+// WealthInfo contains character wealth/money
+type WealthInfo struct {
+ Goldstuecke int
+ Silberstuecke int
+ Kupferstuecke int
}
// AttributeValues contains all character attributes
@@ -110,17 +118,20 @@ type WeaponViewModel struct {
// SpellViewModel represents a spell for display
type SpellViewModel struct {
- Name string
- AP int // Abenteuerpunkte
- Category int // Kategorie (z.B. "Beherrschen", "Erkennen")
- //CastValue int // Zauberwert
- CastTime string // Zauberdauer (z.B. "1 sec", "10 min")
- Range string // Reichweite (z.B. "0", "30m")
- Scope string // Wirkungsbereich (z.B. "1-10 Wesen", "Kegel 5m", "Zauberer", "m²", ...)
- Duration string // Wirkungsdauer (z.B. "0", "10 min")
- Objective string // wirkungsziel (z.B. Körper, Geist, Umgebung)
- CastingType string // Art des Zaubers (z.B. "Geste", "Wort", "Gedanke")
- Notes string // Notizen/Besonderheiten
+ Name string
+ Bonus int // Character's bonus for this spell
+ Stufe int // Spell level
+ AP string // Abenteuerpunkte cost
+ Art string // Art des Zaubers (z.B. "Gestenzauber", "Wortzauber")
+ Zauberdauer string // Zauberdauer (z.B. "1 sec", "10 min")
+ Reichweite string // Reichweite (z.B. "0", "30m")
+ Wirkungsziel string // Wirkungsziel (z.B. Körper, Geist, Umgebung)
+ Wirkungsbereich string // Wirkungsbereich (z.B. "1-10 Wesen", "Kegel 5m")
+ Wirkungsdauer string // Wirkungsdauer (z.B. "0", "10 min")
+ Ursprung string // Origin/source of the spell
+ Category string // Spell school/category
+ LearningCategory string // Learning category
+ Beschreibung string // Description
}
// MagicItemViewModel represents a magical item
diff --git a/backend/templates/Default_A4_Quer/char_p4_equip_a4_quer.html b/backend/templates/Default_A4_Quer/char_p4_equip_a4_quer.html
index a0759a4..9944ef1 100644
--- a/backend/templates/Default_A4_Quer/char_p4_equip_a4_quer.html
+++ b/backend/templates/Default_A4_Quer/char_p4_equip_a4_quer.html
@@ -27,7 +27,7 @@
-

+
diff --git a/backend/templates/Default_A4_Quer/page3_spell.html b/backend/templates/Default_A4_Quer/page3_spell.html
index e8f0b80..ae725a8 100644
--- a/backend/templates/Default_A4_Quer/page3_spell.html
+++ b/backend/templates/Default_A4_Quer/page3_spell.html
@@ -26,7 +26,7 @@
-
+
AP Prozess * |
@@ -38,12 +38,12 @@
{{range .SpellsLeft}}
- {{.AP}} {{.Notes}} |
+ {{.AP}} {{.Category}} |
{{.Name}} |
- {{.CastTime}} {{.Range}} |
- {{.Scope}} {{.Duration}} |
- {{.Notes}} |
- {{.Objective}} {{.CastingType}} |
+ {{.Zauberdauer}} {{.Reichweite}} |
+ {{.Wirkungsbereich}} {{.Wirkungsdauer}} |
+ {{.Beschreibung}} |
+ {{.Wirkungsziel}} {{.Art}} |
{{end}}
@@ -51,7 +51,7 @@
-
+
AP Prozess * |
@@ -63,18 +63,18 @@
{{range .SpellsRight}}
- {{.AP}} {{.Notes}} |
+ {{.AP}} {{.Category}} |
{{.Name}} |
- {{.CastTime}} {{.Range}} |
- {{.Scope}} {{.Duration}} |
- {{.Notes}} |
- {{.Objective}} {{.CastingType}} |
+ {{.Zauberdauer}} {{.Reichweite}} |
+ {{.Wirkungsbereich}} {{.Wirkungsdauer}} |
+ {{.Beschreibung}} |
+ {{.Wirkungsziel}} {{.Art}} |
{{end}}