Zauber auswählen

This commit is contained in:
2025-08-27 21:36:06 +02:00
parent 66d38c0e88
commit 838e5fef32
4 changed files with 1196 additions and 257 deletions
+81 -8
View File
@@ -2137,7 +2137,10 @@ func getCharacterClassCode(className string) (string, error) {
var characterClass models.CharacterClass
err := characterClass.FirstByName(className)
if err != nil {
return "", fmt.Errorf("character class '%s' not found: %w", className, err)
err := characterClass.FirstByCode(className)
if err != nil {
return "", fmt.Errorf("character class '%s' not found: %w", className, err)
}
}
return characterClass.Code, nil
}
@@ -2178,6 +2181,14 @@ func GetAvailableSpellsForCreation(c *gin.Context) {
logger.Info("GetAvailableSpellsForCreation - Gefundene Kategorien: %d", len(spellsByCategory))
if len(spellsByCategory) == 0 {
logger.Warn("GetAvailableSpellsForCreation - Keine Zauber für Klasse %s gefunden", request.CharacterClass)
c.JSON(http.StatusNotFound, gin.H{
"spells_by_category": map[string][]gin.H{},
})
return
}
c.JSON(http.StatusOK, gin.H{
"spells_by_category": spellsByCategory,
})
@@ -2219,18 +2230,37 @@ func GetAvailableSkillsForCreation(c *gin.Context) {
func GetAllSpellsWithLE(characterClass string, maxLevel int) (map[string][]gin.H, error) {
// Create mapping of character classes to allowed learning categories
allowedLearningCategories := getCharacterClassSpellSchoolMapping()
allowedCategories := getCharacterClassSpellSchoolMapping()
allowedLearningCategories := getCharacterClassSpellLearningCategoriesMapping()
// Check if character class has allowed spell schools
allowedSchools, exists := allowedLearningCategories[characterClass]
allowedSchools, exists := allowedCategories[characterClass]
if !exists {
return map[string][]gin.H{}, nil // Return empty map if class can't learn spells
}
allowedSpellType, exists := allowedLearningCategories[characterClass]
if !exists {
return map[string][]gin.H{}, nil // Return empty map if class can't learn spells
}
// Extract allowed school names and spell types from maps
var allowedSchoolNames []string
for school, allowed := range allowedSchools {
if allowed {
allowedSchoolNames = append(allowedSchoolNames, school)
}
}
var allowedSpellTypeNames []string
for spellType, allowed := range allowedSpellType {
if allowed {
allowedSpellTypeNames = append(allowedSpellTypeNames, spellType)
}
}
// Get all spells from database with level filter
var spells []models.Spell
err := database.DB.Where("stufe <= ? AND learning_category != '' AND learning_category IS NOT NULL", maxLevel).Find(&spells).Error
err := database.DB.Where("stufe <= ? AND category in (?) and learning_category in (?) AND category IS NOT NULL AND learning_category IS NOT NULL", maxLevel, allowedSchoolNames, allowedSpellTypeNames).Find(&spells).Error
if err != nil {
return nil, fmt.Errorf("failed to fetch spells: %w", err)
}
@@ -2240,9 +2270,9 @@ func GetAllSpellsWithLE(characterClass string, maxLevel int) (map[string][]gin.H
for _, spell := range spells {
// Check if this character class can learn this spell school
if !allowedSchools[spell.LearningCategory] {
continue // Skip spells from schools this class can't learn
}
//if !allowedSchools[spell.Category] || !allowedSpellType[spell.LearningCategory] {
// continue // Skip spells from schools this class can't learn
//}
// Calculate learning cost for this spell
leCost := getSpellLECost(spell.Stufe)
@@ -2287,6 +2317,46 @@ func GetAllSpellsWithLE(characterClass string, maxLevel int) (map[string][]gin.H
return spellsByCategory, nil
}
func getCharacterClassSpellLearningCategoriesMapping() map[string]map[string]bool {
return map[string]map[string]bool{
"Ma": { // Magier
"Spruch": true,
//"Salz": true,
//"Runenstab": true,
},
"Hx": { // Hexer
"Spruch": true,
"Salz": true,
//"Runenstab": true,
},
"Dr": { // Druide
"Spruch": true,
//"Salz": true,
//"Runenstab": true,
"Dweomer": true,
},
"Sc": { // Schamane
"Spruch": true,
//"Salz": true,
//"Runenstab": true,
"Dweomer": true,
},
"PB": { // Priester Beschützer
"Salz": true,
"Wundertat": true,
},
"PS": { // Priester Streiter
"Salz": true,
"Wundertat": true,
},
"Ba": { // Barde
"Lied": true,
},
"Or": { // Ordenskrieger
"Wundertat": true,
},
}
}
// getCharacterClassSpellSchoolMapping returns the mapping of character classes to allowed spell schools
func getCharacterClassSpellSchoolMapping() map[string]map[string]bool {
@@ -2302,9 +2372,12 @@ func getCharacterClassSpellSchoolMapping() map[string]map[string]bool {
},
"Hx": { // Hexer
"Beherrschen": true,
"Dweomer": true,
"Zerstören": true,
"Erkennen": true,
"Verändern": true,
"Erschaffen": true,
"Bewegen": true,
"Formen": true,
},
"Dr": { // Druide
"Bewegen": true,
+117
View File
@@ -10,6 +10,7 @@ import (
"bamort/database"
"bamort/models"
"bamort/user"
"github.com/gin-gonic/gin"
"github.com/stretchr/testify/assert"
@@ -549,3 +550,119 @@ func TestGetAvailableSkillsForCreation(t *testing.T) {
})
}
}
func TestGetAvailableSpellsForCreation(t *testing.T) {
// Setup test database
database.SetupTestDB(true, true)
defer database.ResetTestDB()
tests := []struct {
name string
characterClass string
expectStatus int
expectError bool
findspells bool
}{
{
name: "ValidCharacterClass",
characterClass: "As",
expectStatus: http.StatusNotFound,
expectError: false,
findspells: false,
},
{
name: "MagierCharacterClass",
characterClass: "Ma",
expectStatus: http.StatusOK,
expectError: false,
findspells: true,
},
{
name: "NonMagicCharacterClass",
characterClass: "Kr",
expectStatus: http.StatusNotFound,
expectError: true,
findspells: false,
},
{
name: "EmptyCharacterClass",
characterClass: "",
expectStatus: http.StatusBadRequest,
expectError: true,
findspells: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// Create request
requestData := gin.H{
"characterClass": tt.characterClass,
}
requestBody, _ := json.Marshal(requestData)
u := user.User{}
u.FirstId(1)
token := user.GenerateToken(&u)
// Create HTTP request
req, _ := http.NewRequest("POST", "/api/characters/available-spells-creation", bytes.NewBuffer(requestBody))
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Authorization", "Bearer "+token)
// Create response recorder
w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)
c.Request = req
// Call the handler directly (it will handle JSON parsing internally)
GetAvailableSpellsForCreation(c)
// Verify response
assert.Equal(t, tt.expectStatus, w.Code)
if !tt.expectError {
var response map[string]interface{}
err := json.Unmarshal(w.Body.Bytes(), &response)
assert.NoError(t, err)
// Check response structure
assert.Contains(t, response, "spells_by_category")
spellsByCategory, ok := response["spells_by_category"].(map[string]interface{})
assert.True(t, ok)
if tt.findspells {
assert.Greater(t, len(spellsByCategory), 0, "Should have at least some spell categories")
// Verify spells have learnCost field
for categoryName, spells := range spellsByCategory {
if spellsList, ok := spells.([]interface{}); ok {
for _, spell := range spellsList {
if spellMap, ok := spell.(map[string]interface{}); ok {
assert.Contains(t, spellMap, "name", "Spell should have name")
assert.Contains(t, spellMap, "le_cost", "Spell should have learnCost")
learnCost := spellMap["le_cost"].(float64)
assert.Greater(t, learnCost, 0.0, "Learn cost should be positive")
assert.Less(t, learnCost, 500.0, "Learn cost should be reasonable for character creation")
}
}
}
_ = categoryName // Mark as used
}
// Log some sample data for verification
t.Logf("Character creation spells loaded for class %s: %d categories", tt.characterClass, len(spellsByCategory))
} else {
assert.Equal(t, len(spellsByCategory), 0, "Should not have any spell categories")
}
} else {
// For error cases, verify error response
var response map[string]interface{}
err := json.Unmarshal(w.Body.Bytes(), &response)
assert.NoError(t, err)
assert.Contains(t, response, "error")
}
})
}
}