Lernkosten altes SysLernkosten vergleich bugfixing
This commit is contained in:
@@ -714,12 +714,14 @@ func calculateMultiLevelCosts(character *models.Char, skillName string, currentL
|
||||
|
||||
// Berechne Kosten für jedes Level
|
||||
for _, targetLevel := range sortedLevels {
|
||||
classAbr := getCharacterClass(character)
|
||||
cat, difficulty, _ := gsmaster.FindBestCategoryForSkillLearning(skillName, classAbr)
|
||||
levelResult := gsmaster.SkillCostResultNew{
|
||||
CharacterID: fmt.Sprintf("%d", character.ID),
|
||||
CharacterClass: getCharacterClass(character),
|
||||
CharacterClass: classAbr,
|
||||
SkillName: skillName,
|
||||
Category: gsmaster.GetSkillCategory(skillName),
|
||||
Difficulty: gsmaster.GetSkillDifficulty(gsmaster.GetSkillCategory(skillName), skillName),
|
||||
Category: cat,
|
||||
Difficulty: gsmaster.GetSkillDifficulty(difficulty, skillName),
|
||||
TargetLevel: targetLevel,
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,485 @@
|
||||
package character
|
||||
|
||||
import (
|
||||
"bamort/database"
|
||||
"bamort/gsmaster"
|
||||
"bamort/models"
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
// TestCompareOldVsNewLearningCostSystems vergleicht die Ergebnisse von GetLernCost und GetLernCostNewSystem
|
||||
func TestCompareOldVsNewLearningCostSystems(t *testing.T) {
|
||||
// Setup test database
|
||||
database.SetupTestDB(true, true)
|
||||
defer database.ResetTestDB()
|
||||
|
||||
// Migrate the schema
|
||||
err := models.MigrateStructure()
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Setup Gin in test mode
|
||||
gin.SetMode(gin.TestMode)
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
charId uint
|
||||
skillName string
|
||||
currentLevel int
|
||||
TargetLevel int `json:"target_level,omitempty"` // Zielwert (optional, für Kostenberechnung bis zu einem bestimmten Level)
|
||||
usePP int
|
||||
useGold int
|
||||
description string
|
||||
Type string `json:"type" binding:"required,oneof=skill spell weapon"` // 'skill', 'spell' oder 'weapon' Waffenfertigkeiten sind normale Fertigkeiten (evtl. kann hier später der Name der Waffe angegeben werden )
|
||||
Action string `json:"action" binding:"required,oneof=learn improve"` // 'learn' oder 'improve'
|
||||
Reward *string `json:"reward" binding:"required,oneof=default noGold halveep halveepnoGold"` // Belohnungsoptionen Lernen als Belohnung
|
||||
}{
|
||||
{
|
||||
name: "improve Athletik Basic Test",
|
||||
charId: 20,
|
||||
skillName: "Athletik",
|
||||
currentLevel: 9,
|
||||
usePP: 0,
|
||||
useGold: 0,
|
||||
description: "Basic comparison for Athletik skill improvement",
|
||||
Type: "skill",
|
||||
Action: "improve",
|
||||
TargetLevel: 0, // Calculate all levels
|
||||
Reward: &[]string{"default"}[0],
|
||||
},
|
||||
{
|
||||
name: "improve Athletik with PP",
|
||||
charId: 20,
|
||||
skillName: "Athletik",
|
||||
currentLevel: 9,
|
||||
usePP: 10,
|
||||
useGold: 0,
|
||||
description: "Comparison with Practice Points usage",
|
||||
Type: "skill",
|
||||
Action: "improve",
|
||||
TargetLevel: 0, // Calculate all levels
|
||||
Reward: &[]string{"default"}[0],
|
||||
},
|
||||
{
|
||||
name: "improve Athletik with Gold",
|
||||
charId: 20,
|
||||
skillName: "Athletik",
|
||||
currentLevel: 9,
|
||||
usePP: 0,
|
||||
useGold: 100,
|
||||
description: "Comparison with Gold usage",
|
||||
Type: "skill",
|
||||
Action: "improve",
|
||||
TargetLevel: 0, // Calculate all levels
|
||||
Reward: &[]string{"default"}[0],
|
||||
},
|
||||
{
|
||||
name: "improve Athletik with 2000 Gold",
|
||||
charId: 20,
|
||||
skillName: "Athletik",
|
||||
currentLevel: 9,
|
||||
usePP: 0,
|
||||
useGold: 2000,
|
||||
description: "Comparison with Gold usage",
|
||||
Type: "skill",
|
||||
Action: "improve",
|
||||
TargetLevel: 0, // Calculate all levels
|
||||
Reward: &[]string{"default"}[0],
|
||||
},
|
||||
{
|
||||
name: "improve Athletik with PP and Gold",
|
||||
charId: 20,
|
||||
skillName: "Athletik",
|
||||
currentLevel: 9,
|
||||
usePP: 15,
|
||||
useGold: 150,
|
||||
description: "Comparison with both PP and Gold usage",
|
||||
Type: "skill",
|
||||
Action: "improve",
|
||||
TargetLevel: 0, // Calculate all levels
|
||||
Reward: &[]string{"default"}[0],
|
||||
},
|
||||
{
|
||||
name: "learn Naturkunde Basic Test",
|
||||
charId: 20,
|
||||
skillName: "Naturkunde",
|
||||
currentLevel: 9,
|
||||
usePP: 0,
|
||||
useGold: 0,
|
||||
description: "Comparison Learn Basic",
|
||||
Type: "skill",
|
||||
Action: "learn",
|
||||
TargetLevel: 0, // Calculate all levels
|
||||
Reward: &[]string{"default"}[0],
|
||||
},
|
||||
{
|
||||
name: "learn Naturkunde Test 100 Gold",
|
||||
charId: 20,
|
||||
skillName: "Naturkunde",
|
||||
currentLevel: 9,
|
||||
usePP: 0,
|
||||
useGold: 100,
|
||||
description: "Comparison Learn 100 Gold",
|
||||
Type: "skill",
|
||||
Action: "learn",
|
||||
TargetLevel: 0, // Calculate all levels
|
||||
Reward: &[]string{"default"}[0],
|
||||
},
|
||||
{
|
||||
name: "learn Naturkunde Test 2000 Gold",
|
||||
charId: 20,
|
||||
skillName: "Naturkunde",
|
||||
currentLevel: 9,
|
||||
usePP: 0,
|
||||
useGold: 2000,
|
||||
description: "Comparison Learn 2000 Gold",
|
||||
Type: "skill",
|
||||
Action: "learn",
|
||||
TargetLevel: 0, // Calculate all levels
|
||||
Reward: &[]string{"default"}[0],
|
||||
},
|
||||
{
|
||||
name: "learn Naturkunde Test 2 PP",
|
||||
charId: 20,
|
||||
skillName: "Naturkunde",
|
||||
currentLevel: 9,
|
||||
usePP: 2,
|
||||
useGold: 0,
|
||||
description: "Comparison Learn 2 PP",
|
||||
Type: "skill",
|
||||
Action: "learn",
|
||||
TargetLevel: 0, // Calculate all levels
|
||||
Reward: &[]string{"default"}[0],
|
||||
},
|
||||
{
|
||||
name: "learn Beeinflussen Test Basic",
|
||||
charId: 18,
|
||||
skillName: "Beeinflussen",
|
||||
currentLevel: 9,
|
||||
usePP: 2,
|
||||
useGold: 0,
|
||||
description: "Comparison Learn ",
|
||||
Type: "spell",
|
||||
Action: "learn",
|
||||
TargetLevel: 0, // Calculate all levels
|
||||
Reward: &[]string{"default"}[0],
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
fmt.Printf("\n=== Comparing Old vs New System: %s ===\n", tc.description)
|
||||
|
||||
// Prepare request data
|
||||
requestData := gsmaster.LernCostRequest{
|
||||
CharId: tc.charId,
|
||||
Name: tc.skillName,
|
||||
CurrentLevel: tc.currentLevel,
|
||||
Type: tc.Type,
|
||||
Action: tc.Action,
|
||||
TargetLevel: tc.TargetLevel, // Calculate all levels
|
||||
UsePP: tc.usePP,
|
||||
UseGold: tc.useGold,
|
||||
Reward: tc.Reward,
|
||||
}
|
||||
requestBody, _ := json.Marshal(requestData)
|
||||
|
||||
// Test Old System (GetLernCost)
|
||||
reqOld, _ := http.NewRequest("POST", "/api/characters/lerncost", bytes.NewBuffer(requestBody))
|
||||
reqOld.Header.Set("Content-Type", "application/json")
|
||||
|
||||
wOld := httptest.NewRecorder()
|
||||
cOld, _ := gin.CreateTestContext(wOld)
|
||||
cOld.Request = reqOld
|
||||
|
||||
GetLernCost(cOld)
|
||||
|
||||
// Test New System (GetLernCostNewSystem)
|
||||
reqNew, _ := http.NewRequest("POST", "/api/characters/lerncost-new", bytes.NewBuffer(requestBody))
|
||||
reqNew.Header.Set("Content-Type", "application/json")
|
||||
|
||||
wNew := httptest.NewRecorder()
|
||||
cNew, _ := gin.CreateTestContext(wNew)
|
||||
cNew.Request = reqNew
|
||||
|
||||
GetLernCostNewSystem(cNew)
|
||||
|
||||
// Check that both systems returned successful responses
|
||||
fmt.Printf("Old System Status: %d, New System Status: %d\n", wOld.Code, wNew.Code)
|
||||
|
||||
if wOld.Code != http.StatusOK && wNew.Code != http.StatusOK {
|
||||
fmt.Printf("Both systems failed - Old: %s, New: %s\n", wOld.Body.String(), wNew.Body.String())
|
||||
t.Skip("Both systems failed, skipping comparison")
|
||||
return
|
||||
}
|
||||
|
||||
if wOld.Code != http.StatusOK {
|
||||
fmt.Printf("Old system failed: %s\n", wOld.Body.String())
|
||||
fmt.Printf("New system succeeded with status %d\n", wNew.Code)
|
||||
t.Skip("Old system failed, new system comparison only")
|
||||
return
|
||||
}
|
||||
|
||||
if wNew.Code != http.StatusOK {
|
||||
fmt.Printf("New system failed: %s\n", wNew.Body.String())
|
||||
fmt.Printf("Old system succeeded with status %d\n", wOld.Code)
|
||||
t.Skip("New system failed, old system comparison only")
|
||||
return
|
||||
}
|
||||
|
||||
// Parse responses
|
||||
var oldResponse []gsmaster.SkillCostResultNew
|
||||
var newResponse []gsmaster.SkillCostResultNew
|
||||
|
||||
err := json.Unmarshal(wOld.Body.Bytes(), &oldResponse)
|
||||
assert.NoError(t, err, "Old system response should be valid JSON")
|
||||
|
||||
err = json.Unmarshal(wNew.Body.Bytes(), &newResponse)
|
||||
assert.NoError(t, err, "New system response should be valid JSON")
|
||||
|
||||
// Compare basic structure
|
||||
fmt.Printf("Old System: %d levels, New System: %d levels\n", len(oldResponse), len(newResponse))
|
||||
|
||||
// Create comparison table
|
||||
fmt.Printf("\n=== Detailed Cost Comparison ===\n")
|
||||
fmt.Printf("Level | Old EP | New EP | Old Gold | New Gold | Old LE | New LE | Old PP | New PP | Old Gold used | New Gold used | Match?\n")
|
||||
fmt.Printf("------|--------|--------|----------|----------|--------|--------|--------|--------|---------------|---------------|-------\n")
|
||||
|
||||
// Compare each level that exists in both systems
|
||||
maxLevels := len(oldResponse)
|
||||
if len(newResponse) < maxLevels {
|
||||
maxLevels = len(newResponse)
|
||||
}
|
||||
|
||||
exactMatches := 0
|
||||
totalComparisons := 0
|
||||
|
||||
for i := 0; i < maxLevels; i++ {
|
||||
old := oldResponse[i]
|
||||
new := newResponse[i]
|
||||
|
||||
// Check if target levels match
|
||||
/*if old.TargetLevel != new.TargetLevel {
|
||||
fmt.Printf("Level mismatch at index %d: Old=%d, New=%d\n", i, old.TargetLevel, new.TargetLevel)
|
||||
continue
|
||||
}*/
|
||||
|
||||
totalComparisons++
|
||||
|
||||
// Compare costs
|
||||
epMatch := old.EP == new.EP
|
||||
goldMatch := old.GoldCost == new.GoldCost
|
||||
leMatch := old.LE == new.LE
|
||||
ppMatch := old.PPUsed == new.PPUsed
|
||||
goldUsedMatch := old.GoldUsed == new.GoldUsed
|
||||
|
||||
overallMatch := epMatch && goldMatch && leMatch && ppMatch && goldUsedMatch
|
||||
if overallMatch {
|
||||
exactMatches++
|
||||
}
|
||||
|
||||
matchSymbol := "✓"
|
||||
if !overallMatch {
|
||||
matchSymbol = "✗"
|
||||
}
|
||||
|
||||
fmt.Printf("%5d | %6d | %6d | %8d | %8d | %6d | %6d | %6d | %6d | %13d | %13d | %7s\n",
|
||||
old.TargetLevel, old.EP, new.EP, old.GoldCost, new.GoldCost,
|
||||
old.LE, new.LE, old.PPUsed, new.PPUsed, old.GoldUsed, new.GoldUsed, matchSymbol)
|
||||
|
||||
// Individual field assertions for debugging
|
||||
if !epMatch {
|
||||
fmt.Printf(" EP mismatch at level %d: Old=%d, New=%d (diff=%d)\n",
|
||||
old.TargetLevel, old.EP, new.EP, old.EP-new.EP)
|
||||
}
|
||||
if !goldMatch {
|
||||
fmt.Printf(" GoldCost mismatch at level %d: Old=%d, New=%d (diff=%d)\n",
|
||||
old.TargetLevel, old.GoldCost, new.GoldCost, old.GoldCost-new.GoldCost)
|
||||
}
|
||||
if !leMatch {
|
||||
fmt.Printf(" LE mismatch at level %d: Old=%d, New=%d (diff=%d)\n",
|
||||
old.TargetLevel, old.LE, new.LE, old.LE-new.LE)
|
||||
}
|
||||
if !ppMatch {
|
||||
fmt.Printf(" PPUsed mismatch at level %d: Old=%d, New=%d (diff=%d)\n",
|
||||
old.TargetLevel, old.PPUsed, new.PPUsed, old.PPUsed-new.PPUsed)
|
||||
}
|
||||
if !goldUsedMatch {
|
||||
fmt.Printf(" GoldUsed mismatch at level %d: Old=%d, New=%d (diff=%d)\n",
|
||||
old.TargetLevel, old.GoldUsed, new.GoldUsed, old.GoldUsed-new.GoldUsed)
|
||||
}
|
||||
|
||||
// Verify basic consistency within each system
|
||||
assert.GreaterOrEqual(t, old.EP, 0, "Old system EP should be non-negative for level %d", old.TargetLevel)
|
||||
assert.GreaterOrEqual(t, new.EP, 0, "New system EP should be non-negative for level %d", new.TargetLevel)
|
||||
assert.GreaterOrEqual(t, old.LE, 0, "Old system LE should be non-negative for level %d", old.TargetLevel)
|
||||
assert.GreaterOrEqual(t, new.LE, 0, "New system LE should be non-negative for level %d", new.TargetLevel)
|
||||
}
|
||||
|
||||
// Summary statistics
|
||||
matchPercentage := float64(exactMatches) / float64(totalComparisons) * 100
|
||||
fmt.Printf("\n=== Comparison Summary ===\n")
|
||||
fmt.Printf("Total Comparisons: %d\n", totalComparisons)
|
||||
fmt.Printf("Exact Matches: %d\n", exactMatches)
|
||||
fmt.Printf("Match Percentage: %.1f%%\n", matchPercentage)
|
||||
|
||||
// Check for levels that exist in one system but not the other
|
||||
if len(oldResponse) != len(newResponse) {
|
||||
fmt.Printf("Length Difference: Old=%d levels, New=%d levels\n", len(oldResponse), len(newResponse))
|
||||
|
||||
if len(oldResponse) > len(newResponse) {
|
||||
fmt.Printf("Old system has additional levels:\n")
|
||||
for i := len(newResponse); i < len(oldResponse); i++ {
|
||||
fmt.Printf(" Level %d: EP=%d, Gold=%d, LE=%d\n",
|
||||
oldResponse[i].TargetLevel, oldResponse[i].EP, oldResponse[i].GoldCost, oldResponse[i].LE)
|
||||
}
|
||||
} else {
|
||||
fmt.Printf("New system has additional levels:\n")
|
||||
for i := len(oldResponse); i < len(newResponse); i++ {
|
||||
fmt.Printf(" Level %d: EP=%d, Gold=%d, LE=%d\n",
|
||||
newResponse[i].TargetLevel, newResponse[i].EP, newResponse[i].GoldCost, newResponse[i].LE)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Basic assertions for test validation
|
||||
assert.Greater(t, totalComparisons, 0, "Should have at least one level to compare")
|
||||
|
||||
// If systems are supposed to be equivalent, we might want exact matches
|
||||
// For now, we'll just document the differences and ensure both are reasonable
|
||||
if matchPercentage < 50.0 {
|
||||
t.Logf("WARNING: Low match percentage (%.1f%%) between old and new systems", matchPercentage)
|
||||
}
|
||||
|
||||
// Verify that both systems produce reasonable results
|
||||
if len(oldResponse) > 0 {
|
||||
assert.Equal(t, tc.skillName, oldResponse[0].SkillName, "Old system should return correct skill name")
|
||||
assert.Equal(t, fmt.Sprintf("%d", tc.charId), oldResponse[0].CharacterID, "Old system should return correct character ID")
|
||||
}
|
||||
|
||||
if len(newResponse) > 0 {
|
||||
assert.Equal(t, tc.skillName, newResponse[0].SkillName, "New system should return correct skill name")
|
||||
assert.Equal(t, fmt.Sprintf("%d", tc.charId), newResponse[0].CharacterID, "New system should return correct character ID")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// Summary test to compare system performance
|
||||
t.Run("System Performance Summary", func(t *testing.T) {
|
||||
fmt.Printf("\n=== Overall System Comparison Summary ===\n")
|
||||
fmt.Printf("Both systems tested with various configurations:\n")
|
||||
fmt.Printf("- Basic skill improvement (no resources)\n")
|
||||
fmt.Printf("- With Practice Points usage\n")
|
||||
fmt.Printf("- With Gold usage\n")
|
||||
fmt.Printf("- With combined PP and Gold usage\n")
|
||||
fmt.Printf("\nKey observations should be documented above.\n")
|
||||
fmt.Printf("Differences may indicate:\n")
|
||||
fmt.Printf("1. Different calculation methods\n")
|
||||
fmt.Printf("2. Different data sources (old vs new tables)\n")
|
||||
fmt.Printf("3. Implementation bugs in either system\n")
|
||||
fmt.Printf("4. Different business rules or assumptions\n")
|
||||
})
|
||||
}
|
||||
|
||||
// TestPerformanceComparison vergleicht die Performance der beiden Systeme
|
||||
func TestPerformanceComparison(t *testing.T) {
|
||||
// Setup test database
|
||||
database.SetupTestDB(true, true)
|
||||
defer database.ResetTestDB()
|
||||
|
||||
// Migrate the schema
|
||||
err := models.MigrateStructure()
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Setup Gin in test mode
|
||||
gin.SetMode(gin.TestMode)
|
||||
|
||||
fmt.Printf("\n=== Performance Comparison ===\n")
|
||||
|
||||
// Prepare test data
|
||||
requestData := gsmaster.LernCostRequest{
|
||||
CharId: 20,
|
||||
Name: "Athletik",
|
||||
CurrentLevel: 5,
|
||||
Type: "skill",
|
||||
Action: "improve",
|
||||
TargetLevel: 0,
|
||||
UsePP: 0,
|
||||
UseGold: 0,
|
||||
Reward: &[]string{"default"}[0],
|
||||
}
|
||||
requestBody, _ := json.Marshal(requestData)
|
||||
|
||||
// Test old system multiple times
|
||||
oldSystemTimes := make([]int64, 10)
|
||||
for i := 0; i < 10; i++ {
|
||||
req, _ := http.NewRequest("POST", "/api/characters/lerncost", bytes.NewBuffer(requestBody))
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
|
||||
w := httptest.NewRecorder()
|
||||
c, _ := gin.CreateTestContext(w)
|
||||
c.Request = req
|
||||
|
||||
start := getCurrentTime()
|
||||
GetLernCost(c)
|
||||
oldSystemTimes[i] = getCurrentTime() - start
|
||||
|
||||
if w.Code != http.StatusOK {
|
||||
t.Logf("Old system failed on iteration %d: %s", i, w.Body.String())
|
||||
}
|
||||
}
|
||||
|
||||
// Test new system multiple times
|
||||
newSystemTimes := make([]int64, 10)
|
||||
for i := 0; i < 10; i++ {
|
||||
req, _ := http.NewRequest("POST", "/api/characters/lerncost-new", bytes.NewBuffer(requestBody))
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
|
||||
w := httptest.NewRecorder()
|
||||
c, _ := gin.CreateTestContext(w)
|
||||
c.Request = req
|
||||
|
||||
start := getCurrentTime()
|
||||
GetLernCostNewSystem(c)
|
||||
newSystemTimes[i] = getCurrentTime() - start
|
||||
|
||||
if w.Code != http.StatusOK {
|
||||
t.Logf("New system failed on iteration %d: %s", i, w.Body.String())
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate averages
|
||||
oldAvg := calculateAverage(oldSystemTimes)
|
||||
newAvg := calculateAverage(newSystemTimes)
|
||||
|
||||
fmt.Printf("Old System Average Time: %d μs\n", oldAvg)
|
||||
fmt.Printf("New System Average Time: %d μs\n", newAvg)
|
||||
|
||||
if newAvg < oldAvg {
|
||||
improvement := float64(oldAvg-newAvg) / float64(oldAvg) * 100
|
||||
fmt.Printf("New system is %.1f%% faster\n", improvement)
|
||||
} else {
|
||||
regression := float64(newAvg-oldAvg) / float64(oldAvg) * 100
|
||||
fmt.Printf("New system is %.1f%% slower\n", regression)
|
||||
}
|
||||
}
|
||||
|
||||
// Helper functions for performance testing
|
||||
func getCurrentTime() int64 {
|
||||
return 0 // Placeholder - in real implementation would use time.Now().UnixNano()
|
||||
}
|
||||
|
||||
func calculateAverage(times []int64) int64 {
|
||||
var sum int64
|
||||
for _, t := range times {
|
||||
sum += t
|
||||
}
|
||||
return sum / int64(len(times))
|
||||
}
|
||||
@@ -92,39 +92,61 @@ func GetLernCost(c *gin.Context) {
|
||||
|
||||
// Normalize skill name (trim whitespace, proper case)
|
||||
costResult.SkillName = strings.TrimSpace(request.Name)
|
||||
costResult.Category = gsmaster.GetSkillCategory(request.Name)
|
||||
costResult.Difficulty = gsmaster.GetSkillDifficulty(costResult.Category, costResult.SkillName)
|
||||
|
||||
// Lasse Kategorie und Schwierigkeit leer, damit CalcSkillLernCost die beste Option wählt
|
||||
// costResult.Category = gsmaster.GetSkillCategory(request.Name)
|
||||
// costResult.Difficulty = gsmaster.GetSkillDifficulty(costResult.Category, costResult.SkillName)
|
||||
var response []gsmaster.SkillCostResultNew
|
||||
for i := request.CurrentLevel + 1; i <= 18; i++ {
|
||||
|
||||
// Für "learn" Aktion: nur eine Berechnung, da Lernkosten einmalig sind
|
||||
if request.Action == "learn" {
|
||||
levelResult := gsmaster.SkillCostResultNew{
|
||||
CharacterID: costResult.CharacterID,
|
||||
CharacterClass: costResult.CharacterClass,
|
||||
SkillName: costResult.SkillName,
|
||||
Category: costResult.Category,
|
||||
Difficulty: costResult.Difficulty,
|
||||
TargetLevel: i,
|
||||
TargetLevel: 1, // Lernkosten sind für das Erlernen der Fertigkeit (Level 1)
|
||||
}
|
||||
err := gsmaster.GetLernCostNextLevel(&request, &levelResult, request.Reward, i, character.Typ)
|
||||
err := gsmaster.GetLernCostNextLevel(&request, &levelResult, request.Reward, 1, character.Typ)
|
||||
if err != nil {
|
||||
respondWithError(c, http.StatusBadRequest, "Fehler bei der Kostenberechnung: "+err.Error())
|
||||
return
|
||||
}
|
||||
// für die nächste Runde die PP und Gold reduzieren die zum Lernen genutzt werden sollen
|
||||
if levelResult.PPUsed > 0 {
|
||||
request.UsePP -= levelResult.PPUsed
|
||||
// Sicherstellen, dass PP nicht unter 0 fallen
|
||||
if request.UsePP < 0 {
|
||||
request.UsePP = 0
|
||||
}
|
||||
}
|
||||
if levelResult.GoldUsed > 0 {
|
||||
request.UseGold -= levelResult.GoldUsed
|
||||
// Sicherstellen, dass Gold nicht unter 0 fällt
|
||||
if request.UseGold < 0 {
|
||||
request.UseGold = 0
|
||||
}
|
||||
}
|
||||
response = append(response, levelResult)
|
||||
} else {
|
||||
// Für "improve" Aktion: berechne für jedes Level von current+1 bis 18
|
||||
for i := request.CurrentLevel + 1; i <= 18; i++ {
|
||||
levelResult := gsmaster.SkillCostResultNew{
|
||||
CharacterID: costResult.CharacterID,
|
||||
CharacterClass: costResult.CharacterClass,
|
||||
SkillName: costResult.SkillName,
|
||||
Category: costResult.Category,
|
||||
Difficulty: costResult.Difficulty,
|
||||
TargetLevel: i,
|
||||
}
|
||||
err := gsmaster.GetLernCostNextLevel(&request, &levelResult, request.Reward, i, character.Typ)
|
||||
if err != nil {
|
||||
respondWithError(c, http.StatusBadRequest, "Fehler bei der Kostenberechnung: "+err.Error())
|
||||
return
|
||||
}
|
||||
// für die nächste Runde die PP und Gold reduzieren die zum Lernen genutzt werden sollen
|
||||
if levelResult.PPUsed > 0 {
|
||||
request.UsePP -= levelResult.PPUsed
|
||||
// Sicherstellen, dass PP nicht unter 0 fallen
|
||||
if request.UsePP < 0 {
|
||||
request.UsePP = 0
|
||||
}
|
||||
}
|
||||
if levelResult.GoldUsed > 0 {
|
||||
request.UseGold -= levelResult.GoldUsed
|
||||
// Sicherstellen, dass Gold nicht unter 0 fällt
|
||||
if request.UseGold < 0 {
|
||||
request.UseGold = 0
|
||||
}
|
||||
}
|
||||
response = append(response, levelResult)
|
||||
}
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, response)
|
||||
@@ -166,7 +188,7 @@ func GetLernCostNewSystem(c *gin.Context) {
|
||||
// Normalize skill name (trim whitespace, proper case)
|
||||
skillName := strings.TrimSpace(request.Name)
|
||||
|
||||
// Hole die beste Kategorie und Schwierigkeit für diese Fertigkeit und Klasse
|
||||
// Hole die beste Kategorie und Schwierigkeit für diese Fertigkeit und Klasse aus der neuen Datenbank
|
||||
skillInfo, err := models.GetSkillCategoryAndDifficulty(skillName, characterClass)
|
||||
if err != nil {
|
||||
respondWithError(c, http.StatusBadRequest, fmt.Sprintf("Fertigkeit '%s' nicht gefunden oder nicht für Klasse '%s' verfügbar: %v", skillName, characterClass, err))
|
||||
@@ -177,36 +199,54 @@ func GetLernCostNewSystem(c *gin.Context) {
|
||||
remainingPP := request.UsePP
|
||||
remainingGold := request.UseGold
|
||||
|
||||
for i := request.CurrentLevel + 1; i <= 18; i++ {
|
||||
// Für "learn" Aktion: nur eine Berechnung, da Lernkosten einmalig sind
|
||||
if request.Action == "learn" {
|
||||
levelResult := gsmaster.SkillCostResultNew{
|
||||
CharacterID: charID,
|
||||
CharacterClass: characterClass,
|
||||
SkillName: skillName,
|
||||
Category: skillInfo.CategoryName,
|
||||
Difficulty: skillInfo.DifficultyName,
|
||||
TargetLevel: i,
|
||||
TargetLevel: 1, // Lernkosten sind für das Erlernen der Fertigkeit (Level 1)
|
||||
}
|
||||
|
||||
// Berechne Kosten mit dem neuen System
|
||||
err := calculateCostNewSystem(&request, &levelResult, i, &remainingPP, &remainingGold, skillInfo)
|
||||
err = calculateSkillLearnCostNewSystem(&request, &levelResult, &remainingPP, &remainingGold, skillInfo)
|
||||
if err != nil {
|
||||
respondWithError(c, http.StatusBadRequest, "Fehler bei der Kostenberechnung: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
response = append(response, levelResult)
|
||||
} else {
|
||||
// Für "improve" Aktion: berechne für jedes Level von current+1 bis 18
|
||||
for i := request.CurrentLevel + 1; i <= 18; i++ {
|
||||
levelResult := gsmaster.SkillCostResultNew{
|
||||
CharacterID: charID,
|
||||
CharacterClass: characterClass,
|
||||
SkillName: skillName,
|
||||
Category: skillInfo.CategoryName,
|
||||
Difficulty: skillInfo.DifficultyName,
|
||||
TargetLevel: i,
|
||||
}
|
||||
|
||||
err = calculateSkillImproveCostNewSystem(&request, &levelResult, i, &remainingPP, &remainingGold, skillInfo)
|
||||
if err != nil {
|
||||
respondWithError(c, http.StatusBadRequest, "Fehler bei der Kostenberechnung: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
response = append(response, levelResult)
|
||||
}
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, response)
|
||||
}
|
||||
|
||||
// calculateCostNewSystem berechnet die Kosten für ein Level mit dem neuen Datenbank-System
|
||||
func calculateCostNewSystem(request *gsmaster.LernCostRequest, result *gsmaster.SkillCostResultNew, targetLevel int, remainingPP *int, remainingGold *int, skillInfo *models.SkillLearningInfo) error {
|
||||
func calculateSkillImproveCostNewSystem(request *gsmaster.LernCostRequest, result *gsmaster.SkillCostResultNew, targetLevel int, remainingPP *int, remainingGold *int, skillInfo *models.SkillLearningInfo) error {
|
||||
// 1. Hole die TE-Kosten für die Verbesserung vom aktuellen Level
|
||||
//currentLevel := targetLevel - 1
|
||||
teRequired, err := models.GetImprovementCost(skillInfo.SkillName, skillInfo.CategoryName, skillInfo.DifficultyName, targetLevel)
|
||||
if err != nil {
|
||||
// Fallback: Verwende das alte System falls keine Daten in der neuen Datenbank
|
||||
return fmt.Errorf("Verbesserungskosten nicht gefunden für %s (Level %d): %v", skillInfo.SkillName, targetLevel, err)
|
||||
}
|
||||
|
||||
@@ -216,27 +256,20 @@ func calculateCostNewSystem(request *gsmaster.LernCostRequest, result *gsmaster.
|
||||
return fmt.Errorf("EP-Kosten pro TE nicht gefunden für Klasse %s, Kategorie %s: %v", result.CharacterClass, skillInfo.CategoryName, err)
|
||||
}
|
||||
|
||||
// 3. Berechne Grundkosten
|
||||
baseEP := teRequired * epPerTE
|
||||
result.EP = baseEP
|
||||
result.GoldCost = baseEP // 1 EP = 1 GS
|
||||
// 3. Setze die ursprünglichen TE-Kosten
|
||||
trainCost := teRequired
|
||||
|
||||
// 4. Anwenden von Praxispunkten (PP)
|
||||
// 4. Anwenden von Praxispunkten (PP) - Exakt wie im alten System
|
||||
ppUsed := 0
|
||||
if *remainingPP > 0 {
|
||||
// Maximal 1 PP pro Level verwenden, und nur so viele wie verfügbar
|
||||
ppUsed = 1
|
||||
if ppUsed > *remainingPP {
|
||||
ppUsed = *remainingPP
|
||||
if trainCost < *remainingPP {
|
||||
ppUsed = trainCost // Maximal so viele PP verwenden wie TE benötigt werden
|
||||
trainCost = 0 // Wenn PP alle TE abdecken, setze trainCost auf 0
|
||||
} else if *remainingPP > 0 {
|
||||
ppUsed = *remainingPP // Verwende alle verfügbaren PP
|
||||
trainCost -= ppUsed // Reduziere TE um verwendete PP
|
||||
}
|
||||
|
||||
// PP reduzieren EP-Kosten: 1 PP = 1 TE weniger
|
||||
teAfterPP := teRequired - ppUsed
|
||||
if teAfterPP < 0 {
|
||||
teAfterPP = 0
|
||||
}
|
||||
|
||||
result.EP = teAfterPP * epPerTE
|
||||
result.PPUsed = ppUsed
|
||||
*remainingPP -= ppUsed
|
||||
|
||||
@@ -245,26 +278,34 @@ func calculateCostNewSystem(request *gsmaster.LernCostRequest, result *gsmaster.
|
||||
}
|
||||
}
|
||||
|
||||
// 5. Anwenden von Belohnungen
|
||||
// 5. Berechne Kosten nach PP-Anwendung (wie im alten System)
|
||||
result.LE = trainCost
|
||||
result.EP = epPerTE * trainCost
|
||||
result.GoldCost = trainCost * 20 // Wie im alten System: 20 Gold pro TE
|
||||
|
||||
// 6. Anwenden von Belohnungen
|
||||
if request.Reward != nil {
|
||||
applyRewardNewSystem(result, request.Reward, baseEP)
|
||||
applyRewardNewSystem(result, request.Reward, result.EP)
|
||||
}
|
||||
|
||||
// 6. Anwenden von Gold für EP (falls in Belohnung spezifiziert)
|
||||
// 7. Anwenden von Gold für EP (falls verfügbar) - Beschränkt auf EP/2
|
||||
goldUsed := 0
|
||||
if request.Reward != nil && *request.Reward == "gold_for_ep" && *remainingGold > 0 {
|
||||
// Maximal die Hälfte der EP durch Gold ersetzen (10 GS = 1 EP)
|
||||
if *remainingGold > 0 {
|
||||
// 10 Gold = 1 EP, aber maximal EP/2 kann durch Gold ersetzt werden
|
||||
maxEPFromGold := result.EP / 2
|
||||
maxGoldNeeded := maxEPFromGold * 10
|
||||
|
||||
goldUsed = maxGoldNeeded
|
||||
if goldUsed > *remainingGold {
|
||||
epFromGold := *remainingGold / 10
|
||||
|
||||
if epFromGold > maxEPFromGold {
|
||||
// Beschränke auf maximal EP/2
|
||||
epFromGold = maxEPFromGold
|
||||
goldUsed = epFromGold * 10
|
||||
} else {
|
||||
// Verwende das verfügbare Gold
|
||||
goldUsed = *remainingGold
|
||||
}
|
||||
|
||||
epFromGold := goldUsed / 10
|
||||
|
||||
// Reduziere EP um die durch Gold ersetzte Menge
|
||||
result.EP -= epFromGold
|
||||
result.GoldCost += goldUsed
|
||||
result.GoldUsed = goldUsed
|
||||
*remainingGold -= goldUsed
|
||||
|
||||
@@ -273,11 +314,83 @@ func calculateCostNewSystem(request *gsmaster.LernCostRequest, result *gsmaster.
|
||||
}
|
||||
}
|
||||
|
||||
// 7. Finale Geldkosten anpassen
|
||||
if result.GoldUsed == 0 {
|
||||
result.GoldCost = result.EP // Standard: 1 EP = 1 GS
|
||||
return nil
|
||||
}
|
||||
|
||||
// calculateSkillLearnCostNewSystem berechnet die Kosten für das Erlernen einer Fertigkeit (Action: "learn")
|
||||
func calculateSkillLearnCostNewSystem(request *gsmaster.LernCostRequest, result *gsmaster.SkillCostResultNew, remainingPP *int, remainingGold *int, skillInfo *models.SkillLearningInfo) error {
|
||||
// 1. Hole die EP-Kosten pro TE für diese Klasse und Kategorie
|
||||
epPerTE, err := models.GetEPPerTEForClassAndCategory(result.CharacterClass, skillInfo.CategoryName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("EP-Kosten pro TE nicht gefunden für Klasse %s, Kategorie %s: %v", result.CharacterClass, skillInfo.CategoryName, err)
|
||||
}
|
||||
|
||||
// 2. Verwende die Lernkosten (LE) direkt aus der skillInfo - diese enthält bereits alle benötigten Informationen
|
||||
learnCost := skillInfo.LearnCost
|
||||
|
||||
// 3. Berechne Kosten nach Lernregeln (wie im alten System)
|
||||
result.LE = learnCost
|
||||
result.EP = epPerTE * result.LE * 3 // Faktor 3 beim Lernen!
|
||||
result.GoldCost = result.LE * 200 // 200 Gold pro LE (nicht 20 Gold pro TE)
|
||||
|
||||
// 4. Anwenden von Belohnungen
|
||||
if request.Reward != nil {
|
||||
applyRewardNewSystem(result, request.Reward, result.EP)
|
||||
}
|
||||
|
||||
// 5. PP und Gold-für-EP Konvertierung beim Lernen
|
||||
if request.Type == "spell" {
|
||||
// PP-Anwendung für Zauber-Lernen: 1 PP = 1 LE Reduktion
|
||||
ppUsed := 0
|
||||
if *remainingPP > 0 {
|
||||
if result.LE <= *remainingPP {
|
||||
ppUsed = result.LE // Maximal so viele PP verwenden wie LE benötigt werden
|
||||
result.LE = 0 // Wenn PP alle LE abdecken
|
||||
} else {
|
||||
ppUsed = *remainingPP // Verwende alle verfügbaren PP
|
||||
result.LE -= ppUsed // Reduziere LE um verwendete PP
|
||||
}
|
||||
|
||||
result.PPUsed = ppUsed
|
||||
*remainingPP -= ppUsed
|
||||
|
||||
if *remainingPP < 0 {
|
||||
*remainingPP = 0
|
||||
}
|
||||
|
||||
// EP neu berechnen basierend auf reduzierter LE
|
||||
result.EP = epPerTE * result.LE * 3
|
||||
result.GoldCost = result.LE * 200
|
||||
}
|
||||
|
||||
// Gold-für-EP Konvertierung für Zauber-Lernen
|
||||
goldUsed := 0
|
||||
if *remainingGold > 0 {
|
||||
// 10 Gold = 1 EP, aber maximal EP/2 kann durch Gold ersetzt werden
|
||||
maxEPFromGold := result.EP / 2
|
||||
epFromGold := *remainingGold / 10
|
||||
|
||||
if epFromGold > maxEPFromGold {
|
||||
// Beschränke auf maximal EP/2
|
||||
epFromGold = maxEPFromGold
|
||||
goldUsed = epFromGold * 10
|
||||
} else {
|
||||
// Verwende das verfügbare Gold
|
||||
goldUsed = *remainingGold
|
||||
}
|
||||
|
||||
// Reduziere EP um die durch Gold ersetzte Menge
|
||||
result.EP -= epFromGold
|
||||
result.GoldUsed = goldUsed
|
||||
*remainingGold -= goldUsed
|
||||
|
||||
if *remainingGold < 0 {
|
||||
*remainingGold = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
// Für Skill-Lernen: Keine PP oder Gold-für-EP Anwendung erlaubt
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -612,8 +612,8 @@ func findBestCategoryForSkillImprovement(skillName, characterClass string, level
|
||||
return bestOption.category, bestOption.difficulty, nil
|
||||
}
|
||||
|
||||
// findBestCategoryForSkillLearning findet die Kategorie mit den niedrigsten EP-Kosten für das Lernen einer Fertigkeit
|
||||
func findBestCategoryForSkillLearning(skillName, characterClass string) (string, string, error) {
|
||||
// FindBestCategoryForSkillLearning findet die Kategorie mit den niedrigsten EP-Kosten für das Lernen einer Fertigkeit
|
||||
func FindBestCategoryForSkillLearning(skillName, characterClass string) (string, string, error) {
|
||||
classKey := characterClass
|
||||
|
||||
// Sammle alle Kategorien und Schwierigkeiten, in denen die Fertigkeit verfügbar ist
|
||||
@@ -669,7 +669,7 @@ func CalcSkillLernCost(costResult *SkillCostResultNew, reward *string) error {
|
||||
|
||||
// Wenn Kategorie und Schwierigkeit noch nicht gesetzt sind, finde die beste Option
|
||||
if costResult.Category == "" || costResult.Difficulty == "" {
|
||||
bestCategory, bestDifficulty, err := findBestCategoryForSkillLearning(costResult.SkillName, classKey)
|
||||
bestCategory, bestDifficulty, err := FindBestCategoryForSkillLearning(costResult.SkillName, classKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -758,16 +758,18 @@ func CalcSkillImproveCost(costResult *SkillCostResultNew, currentLevel int, rewa
|
||||
costResult.EP = costResult.EP / 2 // Halbiere die EP-Kosten für diese Belohnung
|
||||
}
|
||||
if costResult.GoldUsed > 0 {
|
||||
// 10 Gold = 1 EP
|
||||
// 10 Gold = 1 EP, aber maximal EP/2 kann durch Gold ersetzt werden
|
||||
maxEPFromGold := costResult.EP / 2
|
||||
epFromGold := costResult.GoldUsed / 10
|
||||
if epFromGold > costResult.EP {
|
||||
// Maximal so viel Gold verwenden wie EP benötigt werden
|
||||
costResult.GoldUsed = costResult.EP * 10
|
||||
costResult.EP = 0
|
||||
} else {
|
||||
// Reduziere EP um die Menge, die durch Gold ersetzt wird
|
||||
costResult.EP -= epFromGold
|
||||
|
||||
if epFromGold > maxEPFromGold {
|
||||
// Beschränke auf maximal EP/2
|
||||
epFromGold = maxEPFromGold
|
||||
costResult.GoldUsed = epFromGold * 10
|
||||
}
|
||||
|
||||
// Reduziere EP um die durch Gold ersetzte Menge
|
||||
costResult.EP -= epFromGold
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -819,6 +821,22 @@ func CalcSpellLernCost(costResult *SkillCostResultNew, reward *string) error {
|
||||
}
|
||||
}
|
||||
|
||||
// Anwenden von Gold für EP Konvertierung (falls Gold verwendet wird)
|
||||
if costResult.GoldUsed > 0 {
|
||||
// 10 Gold = 1 EP, aber maximal EP/2 kann durch Gold ersetzt werden
|
||||
maxEPFromGold := costResult.EP / 2
|
||||
epFromGold := costResult.GoldUsed / 10
|
||||
|
||||
if epFromGold > maxEPFromGold {
|
||||
// Beschränke auf maximal EP/2
|
||||
epFromGold = maxEPFromGold
|
||||
costResult.GoldUsed = epFromGold * 10
|
||||
}
|
||||
|
||||
// Reduziere EP um die durch Gold ersetzte Menge
|
||||
costResult.EP -= epFromGold
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -828,12 +846,15 @@ func GetLernCostNextLevel(request *LernCostRequest, costResult *SkillCostResultN
|
||||
// die Berechnung erfolgt immer für genau 1 Level
|
||||
// Diese Funktion wird in GetLernCost aufgerufen.
|
||||
|
||||
// Übertrage PP und Gold aus dem Request für die Kostenberechnung
|
||||
costResult.PPUsed = request.UsePP
|
||||
costResult.GoldUsed = request.UseGold
|
||||
// Übertrage PP aus dem Request für die Kostenberechnung
|
||||
// PP sind nur bei "improve" und "spell learn" erlaubt, nicht bei "skill learn"
|
||||
costResult.PPUsed = 0
|
||||
// Gold für EP wird nur bei "improve" Aktionen und "spell learn" verwendet, nicht beim "skill learn"
|
||||
costResult.GoldUsed = 0
|
||||
|
||||
switch {
|
||||
case request.Action == "learn" && request.Type == "skill":
|
||||
// Skill-Lernen: Kein PP und kein Gold für EP erlaubt
|
||||
err := CalcSkillLernCost(costResult, request.Reward)
|
||||
if err != nil {
|
||||
return fmt.Errorf("fehler bei der Kostenberechnung: %w", err)
|
||||
@@ -843,6 +864,9 @@ func GetLernCostNextLevel(request *LernCostRequest, costResult *SkillCostResultN
|
||||
costResult.EP += 6
|
||||
}
|
||||
case request.Action == "learn" && request.Type == "spell":
|
||||
// Zauber-Lernen: PP und Gold für EP ist erlaubt
|
||||
costResult.PPUsed = request.UsePP
|
||||
costResult.GoldUsed = request.UseGold
|
||||
err := CalcSpellLernCost(costResult, request.Reward)
|
||||
if err != nil {
|
||||
return fmt.Errorf("fehler bei der Kostenberechnung: %w", err)
|
||||
@@ -852,6 +876,9 @@ func GetLernCostNextLevel(request *LernCostRequest, costResult *SkillCostResultN
|
||||
costResult.EP += 6
|
||||
}
|
||||
case request.Action == "improve" && request.Type == "skill":
|
||||
// Skill-Verbesserung: PP und Gold für EP ist erlaubt
|
||||
costResult.PPUsed = request.UsePP
|
||||
costResult.GoldUsed = request.UseGold
|
||||
err := CalcSkillImproveCost(costResult, request.CurrentLevel, request.Reward)
|
||||
if err != nil {
|
||||
return fmt.Errorf("fehler bei der Kostenberechnung: %w", err)
|
||||
|
||||
@@ -62,6 +62,7 @@ func TestGetSkillCategory(t *testing.T) {
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
|
||||
result := GetSkillCategory(tt.skillName)
|
||||
|
||||
// Check if result is in the list of expected values
|
||||
@@ -569,11 +570,12 @@ func TestCalcSkillLernCostWithRewards(t *testing.T) {
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
// Create cost result
|
||||
cat, difficulty, _ := FindBestCategoryForSkillLearning(tt.skillName, tt.characterClass)
|
||||
costResult := &SkillCostResultNew{
|
||||
CharacterClass: tt.characterClass,
|
||||
SkillName: tt.skillName,
|
||||
Category: GetSkillCategory(tt.skillName),
|
||||
Difficulty: GetSkillDifficulty(GetSkillCategory(tt.skillName), tt.skillName),
|
||||
Category: cat,
|
||||
Difficulty: difficulty,
|
||||
}
|
||||
|
||||
// Calculate normal costs first to get baseline EP
|
||||
@@ -1009,7 +1011,7 @@ func TestFindBestCategoryForSkillLearning(t *testing.T) {
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
category, difficulty, err := findBestCategoryForSkillLearning(tt.skillName, tt.characterClass)
|
||||
category, difficulty, err := FindBestCategoryForSkillLearning(tt.skillName, tt.characterClass)
|
||||
|
||||
if tt.expectError {
|
||||
if err == nil {
|
||||
|
||||
@@ -320,6 +320,34 @@ func GetSkillCategoryAndDifficulty(skillName string, classCode string) (*SkillLe
|
||||
return &results[0], nil
|
||||
}
|
||||
|
||||
// GetSkillInfoForCategoryAndDifficulty holt die Informationen für eine spezifische Kategorie/Schwierigkeit
|
||||
func GetSkillInfoForCategoryAndDifficulty(skillName, category, difficulty, classCode string) (*SkillLearningInfo, error) {
|
||||
var result SkillLearningInfo
|
||||
|
||||
err := database.DB.Raw(`
|
||||
SELECT
|
||||
scd.skill_id,
|
||||
s.name as skill_name,
|
||||
scd.skill_category as category_name,
|
||||
scd.skill_difficulty as difficulty_name,
|
||||
scd.learn_cost,
|
||||
ccec.character_class as class_code,
|
||||
ccec.character_class as class_name,
|
||||
ccec.ep_per_te,
|
||||
(scd.learn_cost * ccec.ep_per_te) as total_cost
|
||||
FROM learning_skill_category_difficulties scd
|
||||
JOIN learning_class_category_ep_costs ccec ON scd.skill_category = ccec.skill_category
|
||||
JOIN gsm_skills s ON scd.skill_id = s.id
|
||||
WHERE s.name = ? AND scd.skill_category = ? AND scd.skill_difficulty = ? AND ccec.character_class = ?
|
||||
`, skillName, category, difficulty, classCode).Scan(&result).Error
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &result, nil
|
||||
}
|
||||
|
||||
// GetSpellLearningInfo holt alle Informationen für das Erlernen eines Zaubers
|
||||
func GetSpellLearningInfo(spellName string, classCode string) (*SpellLearningInfo, error) {
|
||||
var result SpellLearningInfo
|
||||
@@ -366,6 +394,19 @@ func GetImprovementCost(skillName string, categoryName string, difficultyName st
|
||||
return result.TERequired, nil
|
||||
}
|
||||
|
||||
// GetSkillLearnCost holt die Lernkosten (LE) für eine Fertigkeit basierend auf Kategorie und Schwierigkeit
|
||||
func GetSkillLearnCost(categoryName string, difficultyName string) (int, error) {
|
||||
var result SkillCategoryDifficulty
|
||||
err := database.DB.
|
||||
Where("skill_category = ? AND skill_difficulty = ?", categoryName, difficultyName).
|
||||
First(&result).Error
|
||||
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return result.LearnCost, nil
|
||||
}
|
||||
|
||||
// Quellenmanagement-Funktionen
|
||||
|
||||
// GetActiveSourceCodes gibt alle aktiven Quellencodes zurück
|
||||
|
||||
Reference in New Issue
Block a user