route available-spells-new
This commit is contained in:
@@ -416,3 +416,209 @@ func TestGetAvailableSkillsNew(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetAvailableSpellsNew(t *testing.T) {
|
||||
database.SetupTestDB(true) // Setup test database
|
||||
// Initialize a Gin router
|
||||
r := gin.Default()
|
||||
router.SetupGin(r)
|
||||
|
||||
// Routes
|
||||
protected := router.BaseRouterGrp(r)
|
||||
character.RegisterRoutes(protected)
|
||||
gsmaster.RegisterRoutes(protected)
|
||||
protected.GET("/test", func(c *gin.Context) {
|
||||
c.JSON(http.StatusOK, gin.H{"status": "Test OK"})
|
||||
})
|
||||
|
||||
u := user.User{}
|
||||
|
||||
u.First("testuser")
|
||||
|
||||
// Create request body for available spells
|
||||
spellRequest := gsmaster.LernCostRequest{
|
||||
CharId: 20,
|
||||
Name: "Angst", // Use a valid spell name for validation
|
||||
CurrentLevel: 0,
|
||||
Type: "spell",
|
||||
Action: "learn",
|
||||
TargetLevel: 1,
|
||||
UsePP: 0,
|
||||
UseGold: 0,
|
||||
Reward: &[]string{"default"}[0],
|
||||
}
|
||||
jsonData, _ := json.Marshal(spellRequest)
|
||||
|
||||
// Create a test HTTP request
|
||||
req, _ := http.NewRequest("POST", "/api/characters/available-spells-new", bytes.NewBuffer(jsonData))
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
token := user.GenerateToken(&u)
|
||||
req.Header.Set("Authorization", "Bearer "+token)
|
||||
|
||||
// Create a response recorder to capture the handler's response
|
||||
respRecorder := httptest.NewRecorder()
|
||||
|
||||
// Perform the test request
|
||||
r.ServeHTTP(respRecorder, req)
|
||||
|
||||
// Assert the response status code
|
||||
assert.Equal(t, http.StatusOK, respRecorder.Code)
|
||||
|
||||
// Parse the response to verify it contains spells by school
|
||||
var response map[string]interface{}
|
||||
err := json.Unmarshal(respRecorder.Body.Bytes(), &response)
|
||||
assert.NoError(t, err, "Response should be valid JSON")
|
||||
|
||||
// Check that the response contains spells_by_school
|
||||
spellsBySchool, exists := response["spells_by_school"]
|
||||
assert.True(t, exists, "Response should contain spells_by_school")
|
||||
assert.NotNil(t, spellsBySchool, "spells_by_school should not be nil")
|
||||
|
||||
// Convert to map for easier access
|
||||
spellsMap, ok := spellsBySchool.(map[string]interface{})
|
||||
assert.True(t, ok, "spells_by_school should be a map")
|
||||
assert.Greater(t, len(spellsMap), 0, "Should return at least one school of spells")
|
||||
|
||||
// Verify that each spell has the expected structure and check for fallback values
|
||||
fallbackSpells := []string{}
|
||||
totalSpells := 0
|
||||
|
||||
for schoolName, schoolSpellsInterface := range spellsMap {
|
||||
schoolSpells, ok := schoolSpellsInterface.([]interface{})
|
||||
assert.True(t, ok, "School %s should contain an array of spells", schoolName)
|
||||
|
||||
for _, spellInterface := range schoolSpells {
|
||||
spell, ok := spellInterface.(map[string]interface{})
|
||||
assert.True(t, ok, "Each spell should be a map")
|
||||
totalSpells++
|
||||
|
||||
// Check required fields
|
||||
name, hasName := spell["name"]
|
||||
level, hasLevel := spell["level"]
|
||||
epCost, hasEpCost := spell["epCost"]
|
||||
goldCost, hasGoldCost := spell["goldCost"]
|
||||
|
||||
assert.True(t, hasName, "Spell should have name field")
|
||||
assert.True(t, hasLevel, "Spell should have level field")
|
||||
assert.True(t, hasEpCost, "Spell should have epCost field")
|
||||
assert.True(t, hasGoldCost, "Spell should have goldCost field")
|
||||
|
||||
// Check for fallback values (10000 EP, 50000 GS)
|
||||
if epCostFloat, ok := epCost.(float64); ok && epCostFloat == 10000 {
|
||||
if goldCostFloat, ok := goldCost.(float64); ok && goldCostFloat == 50000 {
|
||||
fallbackSpells = append(fallbackSpells, name.(string))
|
||||
t.Logf("FALLBACK VALUES DETECTED: Spell '%s' (Level %v) - EP: %.0f, Gold: %.0f",
|
||||
name, level, epCostFloat, goldCostFloat)
|
||||
}
|
||||
}
|
||||
|
||||
// Log first few spells for debugging
|
||||
if totalSpells <= 5 {
|
||||
t.Logf("Spell '%s' (Level %v) - EP: %v, Gold: %v", name, level, epCost, goldCost)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Assert that no spells have fallback values
|
||||
if len(fallbackSpells) > 0 {
|
||||
t.Errorf("Found %d spells with fallback values (10000 EP, 50000 GS): %v",
|
||||
len(fallbackSpells), fallbackSpells)
|
||||
}
|
||||
|
||||
t.Logf("Total spells checked: %d, spells with fallback values: %d", totalSpells, len(fallbackSpells))
|
||||
}
|
||||
|
||||
func TestFallbackValueDetection(t *testing.T) {
|
||||
database.SetupTestDB(true) // Setup test database
|
||||
// Initialize a Gin router
|
||||
r := gin.Default()
|
||||
router.SetupGin(r)
|
||||
|
||||
// Routes
|
||||
protected := router.BaseRouterGrp(r)
|
||||
character.RegisterRoutes(protected)
|
||||
gsmaster.RegisterRoutes(protected)
|
||||
|
||||
u := user.User{}
|
||||
u.First("testuser")
|
||||
|
||||
// Test both skills and spells for fallback values
|
||||
testCases := []struct {
|
||||
endpoint string
|
||||
itemType string
|
||||
testName string
|
||||
}{
|
||||
{"/api/characters/available-skills-new", "skill", "Schwimmen"},
|
||||
{"/api/characters/available-spells-new", "spell", "Angst"},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.itemType, func(t *testing.T) {
|
||||
request := gsmaster.LernCostRequest{
|
||||
CharId: 20,
|
||||
Name: tc.testName,
|
||||
CurrentLevel: 0,
|
||||
Type: tc.itemType,
|
||||
Action: "learn",
|
||||
TargetLevel: 1,
|
||||
UsePP: 0,
|
||||
UseGold: 0,
|
||||
Reward: &[]string{"default"}[0],
|
||||
}
|
||||
jsonData, _ := json.Marshal(request)
|
||||
|
||||
req, _ := http.NewRequest("POST", tc.endpoint, bytes.NewBuffer(jsonData))
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
token := user.GenerateToken(&u)
|
||||
req.Header.Set("Authorization", "Bearer "+token)
|
||||
|
||||
respRecorder := httptest.NewRecorder()
|
||||
r.ServeHTTP(respRecorder, req)
|
||||
|
||||
assert.Equal(t, http.StatusOK, respRecorder.Code)
|
||||
|
||||
var response map[string]interface{}
|
||||
err := json.Unmarshal(respRecorder.Body.Bytes(), &response)
|
||||
assert.NoError(t, err)
|
||||
|
||||
fallbackCount := 0
|
||||
totalItems := 0
|
||||
|
||||
// Check for fallback values in response
|
||||
var dataKey string
|
||||
if tc.itemType == "skill" {
|
||||
dataKey = "skills_by_category"
|
||||
} else {
|
||||
dataKey = "spells_by_school"
|
||||
}
|
||||
|
||||
if data, exists := response[dataKey]; exists {
|
||||
if dataMap, ok := data.(map[string]interface{}); ok {
|
||||
for _, itemsInterface := range dataMap {
|
||||
if items, ok := itemsInterface.([]interface{}); ok {
|
||||
for _, itemInterface := range items {
|
||||
if item, ok := itemInterface.(map[string]interface{}); ok {
|
||||
totalItems++
|
||||
if epCost, hasEP := item["epCost"]; hasEP {
|
||||
if goldCost, hasGold := item["goldCost"]; hasGold {
|
||||
if epFloat, ok := epCost.(float64); ok && epFloat == 10000 {
|
||||
if goldFloat, ok := goldCost.(float64); ok && goldFloat == 50000 {
|
||||
fallbackCount++
|
||||
t.Logf("FALLBACK DETECTED in %s '%s': EP=%v, Gold=%v",
|
||||
tc.itemType, item["name"], epCost, goldCost)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
t.Logf("%s test: Total items=%d, Fallback values=%d", tc.itemType, totalItems, fallbackCount)
|
||||
assert.Equal(t, 0, fallbackCount, "No %s should have fallback values (10000 EP, 50000 GS)", tc.itemType)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1388,7 +1388,7 @@ func GetAvailableSkillsNewSystem(c *gin.Context) {
|
||||
|
||||
remainingPP := request.UsePP
|
||||
remainingGold := request.UseGold
|
||||
|
||||
|
||||
// Hole die vollständigen Skill-Informationen für die Kostenberechnung
|
||||
skillLearningInfo, err := models.GetSkillCategoryAndDifficulty(skill.Name, getCharacterClass(&character))
|
||||
if err != nil {
|
||||
@@ -1428,6 +1428,113 @@ func GetAvailableSkillsNewSystem(c *gin.Context) {
|
||||
})
|
||||
}
|
||||
|
||||
// GetAvailableSpellsNewSystem gibt alle verfügbaren Zauber mit Lernkosten zurück (POST mit LernCostRequest)
|
||||
func GetAvailableSpellsNewSystem(c *gin.Context) {
|
||||
characterID := c.Param("id")
|
||||
|
||||
// Parse LernCostRequest aus POST body
|
||||
var baseRequest gsmaster.LernCostRequest
|
||||
if err := c.ShouldBindJSON(&baseRequest); err != nil {
|
||||
respondWithError(c, http.StatusBadRequest, "Ungültige Anfrageparameter: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
var character models.Char
|
||||
if err := database.DB.Preload("Zauber").Preload("Erfahrungsschatz").Preload("Vermoegen").First(&character, characterID).Error; err != nil {
|
||||
respondWithError(c, http.StatusNotFound, "Character not found")
|
||||
return
|
||||
}
|
||||
|
||||
charakteClass := getCharacterClass(&character)
|
||||
// Hole alle verfügbaren Zauber aus der gsmaster Datenbank, aber filtere Placeholder aus
|
||||
var allSpells []models.Spell
|
||||
|
||||
allSpells, err := models.SelectSpells("", "")
|
||||
if err != nil {
|
||||
respondWithError(c, http.StatusInternalServerError, "Failed to retrieve spells from gsmaster")
|
||||
return
|
||||
}
|
||||
|
||||
// Erstelle eine Map der bereits gelernten Zauber
|
||||
learnedSpells := make(map[string]bool)
|
||||
for _, spell := range character.Zauber {
|
||||
learnedSpells[spell.Name] = true
|
||||
}
|
||||
|
||||
// Organisiere Zauber nach Schulen (analog zu Kategorien bei Fertigkeiten)
|
||||
spellsBySchool := make(map[string][]gin.H)
|
||||
|
||||
for _, spell := range allSpells {
|
||||
// Überspringe bereits gelernte Zauber
|
||||
if learnedSpells[spell.Name] {
|
||||
continue
|
||||
}
|
||||
// Überspringe Placeholder-Zauber (zusätzliche Sicherheit)
|
||||
if spell.Name == "Placeholder" {
|
||||
continue
|
||||
}
|
||||
|
||||
// Erstelle LernCostRequest für diesen Zauber basierend auf der Basis-Anfrage
|
||||
request := baseRequest
|
||||
request.CharId = character.ID
|
||||
request.Name = spell.Name
|
||||
request.CurrentLevel = 0 // Nicht gelernt
|
||||
request.TargetLevel = 1 // Auf Level 1 lernen
|
||||
request.Type = "spell"
|
||||
request.Action = "learn"
|
||||
|
||||
// Erstelle SkillCostResultNew
|
||||
levelResult := gsmaster.SkillCostResultNew{
|
||||
CharacterID: fmt.Sprintf("%d", character.ID),
|
||||
CharacterClass: charakteClass,
|
||||
SkillName: spell.Name,
|
||||
TargetLevel: 1,
|
||||
}
|
||||
|
||||
remainingPP := request.UsePP
|
||||
remainingGold := request.UseGold
|
||||
|
||||
// Hole die vollständigen Spell-Informationen für die Kostenberechnung
|
||||
spellLearningInfo, err := models.GetSpellLearningInfoNewSystem(spell.Name, charakteClass)
|
||||
if err != nil {
|
||||
// Fallback für unbekannte Zauber
|
||||
spellLearningInfo = &models.SpellLearningInfo{
|
||||
SpellName: spell.Name,
|
||||
SpellLevel: spell.Stufe,
|
||||
SchoolName: spell.Category,
|
||||
LERequired: 20, // Standard-Lernkosten für Zauber
|
||||
}
|
||||
}
|
||||
|
||||
// Berechne Lernkosten mit calculateSpellLearnCostNewSystem
|
||||
err = calculateSpellLearnCostNewSystem(&request, &levelResult, &remainingPP, &remainingGold, spellLearningInfo)
|
||||
epCost := 10000 // Fallback-Wert
|
||||
goldCost := 50000 // Fallback-Wert
|
||||
if err == nil {
|
||||
epCost = levelResult.EP
|
||||
goldCost = levelResult.GoldCost
|
||||
}
|
||||
|
||||
spellInfo := gin.H{
|
||||
"name": spell.Name,
|
||||
"level": spell.Stufe,
|
||||
"epCost": epCost,
|
||||
"goldCost": goldCost,
|
||||
}
|
||||
|
||||
school := spell.Category
|
||||
if school == "" {
|
||||
school = "Sonstige"
|
||||
}
|
||||
|
||||
spellsBySchool[school] = append(spellsBySchool[school], spellInfo)
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"spells_by_school": spellsBySchool,
|
||||
})
|
||||
}
|
||||
|
||||
// GetAvailableSkills gibt alle verfügbaren Fertigkeiten mit Lernkosten zurück
|
||||
func GetAvailableSkills(c *gin.Context) {
|
||||
characterID := c.Param("id")
|
||||
|
||||
@@ -196,7 +196,7 @@ func GetLernCostNewSystem(c *gin.Context) {
|
||||
if request.Action == "learn" {
|
||||
if request.Type == "spell" {
|
||||
// Spell learning logic
|
||||
spellInfo, err := models.GetSpellLearningInfo(skillName, characterClass)
|
||||
spellInfo, err := models.GetSpellLearningInfoNewSystem(skillName, characterClass)
|
||||
if err != nil {
|
||||
respondWithError(c, http.StatusBadRequest, fmt.Sprintf("Zauber '%s' nicht gefunden oder nicht für Klasse '%s' verfügbar: %v", skillName, characterClass, err))
|
||||
return
|
||||
|
||||
@@ -33,6 +33,7 @@ func RegisterRoutes(r *gin.RouterGroup) {
|
||||
// Fertigkeiten-Information
|
||||
charGrp.GET("/:id/available-skills", GetAvailableSkills) // Verfügbare Fertigkeiten mit Kosten (bereits gelernte ausgeschlossen)
|
||||
charGrp.POST("/available-skills-new", GetAvailableSkillsNewSystem) // Verfügbare Fertigkeiten mit Kosten (bereits gelernte ausgeschlossen)
|
||||
charGrp.POST("/available-spells-new", GetAvailableSpellsNewSystem) // Verfügbare Zauber mit Kosten (bereits gelernte ausgeschlossen)
|
||||
|
||||
// Belohnungsarten für verschiedene Lernszenarien
|
||||
charGrp.GET("/:id/reward-types", GetRewardTypes) // Verfügbare Belohnungsarten je nach Kontext
|
||||
|
||||
@@ -374,6 +374,32 @@ func (object *Spell) Save() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// SelectSpells gibt alle Zauber zurück, optional gefiltert nach einem Feld
|
||||
func SelectSpells(opts ...string) ([]Spell, error) {
|
||||
fieldName := ""
|
||||
value := ""
|
||||
gameSystem := "midgard"
|
||||
|
||||
if len(opts) > 1 {
|
||||
fieldName = opts[0]
|
||||
value = opts[1]
|
||||
}
|
||||
|
||||
var spells []Spell
|
||||
if fieldName == "" {
|
||||
err := database.DB.Find(&spells, "game_system=? AND name != 'Placeholder'", gameSystem).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
err := database.DB.Find(&spells, "game_system=? AND name != 'Placeholder' AND "+fieldName+" = ?", gameSystem, value).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return spells, nil
|
||||
}
|
||||
|
||||
func (object *Spell) GetSpellCategories() ([]string, error) {
|
||||
var categories []string
|
||||
gameSystem := "midgard"
|
||||
|
||||
@@ -349,8 +349,8 @@ func GetSkillInfoForCategoryAndDifficulty(skillName, category, difficulty, class
|
||||
return &result, nil
|
||||
}
|
||||
|
||||
// GetSpellLearningInfo holt alle Informationen für das Erlernen eines Zaubers
|
||||
func GetSpellLearningInfo(spellName string, classCode string) (*SpellLearningInfo, error) {
|
||||
// GetSpellLearningInfoNewSystem holt alle Informationen für das Erlernen eines Zaubers
|
||||
func GetSpellLearningInfoNewSystem(spellName string, classCode string) (*SpellLearningInfo, error) {
|
||||
var result SpellLearningInfo
|
||||
|
||||
err := database.DB.Raw(`
|
||||
|
||||
Reference in New Issue
Block a user