Updated Got to 1.25.5
made spells display correct spell information
This commit is contained in:
@@ -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.)
|
||||
|
||||
@@ -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"])
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
@@ -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
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
+3
-3
@@ -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
|
||||
|
||||
+4
-10
@@ -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=
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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,
|
||||
},
|
||||
{
|
||||
|
||||
@@ -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 (<!-- BLOCK: spells_left, TYPE: spells, MAX: 26 -->)
|
||||
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 (<!-- BLOCK: spells_left, TYPE: spells, MAX: 15 -->)
|
||||
if spellsLeft.MaxItems != 15 {
|
||||
t.Errorf("Expected spells_left MaxItems 15 (from template file), got %d", spellsLeft.MaxItems)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
<!-- BLOCK: skills_learned, TYPE: skills, MAX: 18, FILTER: learned -->
|
||||
<!-- BLOCK: skills_unlearned, TYPE: skills, MAX: 15, FILTER: unlearned -->
|
||||
**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 <!-- BLOCK: skills_languages, TYPE: skills, MAX: 5, FILTER: language -->
|
||||
in page 3 for <!-- BLOCK: magic_items, TYPE: magicItems, MAX: 8 -->
|
||||
**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.
|
||||
* The implementation is NOT correct, because the eapons_main shows weapon skills. But it should show the weapons list from the equipment
|
||||
@@ -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))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
<!-- Left section: Character icon, currency, and small containers -->
|
||||
<div class="equipment-left">
|
||||
<div class="char-icon-section">
|
||||
<img src="token_bebe.png" alt="Charakter" class="char-icon">
|
||||
<img src="shared/images/token_bebe.png" alt="Charakter" class="char-icon">
|
||||
</div>
|
||||
<table class="currency-table">
|
||||
<tr>
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
<div class="flex main-content">
|
||||
<!-- Left spell table -->
|
||||
<div class="left-section">
|
||||
<!-- BLOCK: spells_left, TYPE: spells, MAX: 26 -->
|
||||
<!-- BLOCK: spells_left, TYPE: spells, MAX: 15 -->
|
||||
<table class="spells-table">
|
||||
<tr>
|
||||
<th>AP<hr>Prozess *</th>
|
||||
@@ -38,12 +38,12 @@
|
||||
</tr>
|
||||
{{range .SpellsLeft}}
|
||||
<tr>
|
||||
<td>{{.AP}}<hr>{{.Notes}}</td>
|
||||
<td>{{.AP}}<hr>{{.Category}} </td>
|
||||
<td>{{.Name}}</td>
|
||||
<td>{{.CastTime}}<hr>{{.Range}}</td>
|
||||
<td>{{.Scope}}<hr>{{.Duration}}</td>
|
||||
<td>{{.Notes}}</td>
|
||||
<td>{{.Objective}}<hr>{{.CastingType}}</td>
|
||||
<td>{{.Zauberdauer}} <hr>{{.Reichweite}} </td>
|
||||
<td>{{.Wirkungsbereich}} <hr>{{.Wirkungsdauer}} </td>
|
||||
<td>{{.Beschreibung}} </td>
|
||||
<td>{{.Wirkungsziel}} <hr>{{.Art}} </td>
|
||||
</tr>
|
||||
{{end}}
|
||||
</table>
|
||||
@@ -51,7 +51,7 @@
|
||||
|
||||
<!-- Right spell table -->
|
||||
<div class="right-section">
|
||||
<!-- BLOCK: spells_right, TYPE: spells, MAX: 15 -->
|
||||
<!-- BLOCK: spells_right, TYPE: spells, MAX: 10 -->
|
||||
<table class="spells-table">
|
||||
<tr>
|
||||
<th>AP<br>Prozess *</th>
|
||||
@@ -63,18 +63,18 @@
|
||||
</tr>
|
||||
{{range .SpellsRight}}
|
||||
<tr>
|
||||
<td>{{.AP}}<hr>{{.Notes}}</td>
|
||||
<td>{{.AP}} <hr>{{.Category}} </td>
|
||||
<td>{{.Name}}</td>
|
||||
<td>{{.CastTime}}<hr>{{.Range}}</td>
|
||||
<td>{{.Scope}}<hr>{{.Duration}}</td>
|
||||
<td>{{.Notes}}</td>
|
||||
<td>{{.Objective}}<hr>{{.CastingType}}</td>
|
||||
<td>{{.Zauberdauer}} <hr>{{.Reichweite}} </td>
|
||||
<td>{{.Wirkungsbereich}} <hr>{{.Wirkungsdauer}} </td>
|
||||
<td>{{.Beschreibung}} </td>
|
||||
<td>{{.Wirkungsziel}} <hr>{{.Art}} </td>
|
||||
</tr>
|
||||
{{end}}
|
||||
</table>
|
||||
<div class="spell-footer">
|
||||
<p><em>wichtige magische Gegenstände, Tränke, Schriftrollen</em></p>
|
||||
<!-- BLOCK: magic_items, TYPE: magicItems, MAX: 8 -->
|
||||
<!-- BLOCK: magic_items, TYPE: magicItems, MAX: 5 -->
|
||||
<table class="items-table">
|
||||
<tr>
|
||||
<th>Gegenstand</th>
|
||||
|
||||
@@ -29,22 +29,24 @@
|
||||
<div class="char-icon-section">
|
||||
{{if .Character.IconBase64}}
|
||||
<img src="{{.Character.IconBase64}}" alt="Charakter" class="char-icon">
|
||||
{{else}}
|
||||
<img src="shared/images/token_bebe.png" alt="Charakter" class="char-icon">
|
||||
{{end}}
|
||||
</div>
|
||||
<table class="currency-table">
|
||||
<tr>
|
||||
<td><strong>GS</strong></td>
|
||||
<td>0</td>
|
||||
<td>{{.Character.Vermoegen.Goldstuecke}}</td>
|
||||
{{range $i := iterate 9}}<td> </td>{{end}}
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>SS</strong></td>
|
||||
<td>0</td>
|
||||
<td>{{.Character.Vermoegen.Silberstuecke}}</td>
|
||||
{{range $i := iterate 9}}<td></td>{{end}}
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>KS</strong></td>
|
||||
<td>0</td>
|
||||
<td>{{.Character.Vermoegen.Kupferstuecke}}</td>
|
||||
{{range $i := iterate 9}}<td></td>{{end}}
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Development Dockerfile für Go Backend mit Live-Reloading
|
||||
#FROM golang:1.23-alpine
|
||||
FROM golang:1.24-alpine
|
||||
FROM golang:1.25-alpine
|
||||
|
||||
# Install necessary packages for CGO and SQLite
|
||||
RUN apk add --no-cache gcc musl-dev sqlite-dev
|
||||
|
||||
Reference in New Issue
Block a user