New test TestCalculateSkillImproveCostNewSystem in chain of learning system
Updated learning_skill_category_difficulties to match rule set removed SkillImprovementCost replaced by SkillImprovementCost2
This commit is contained in:
@@ -368,3 +368,116 @@ func TestCalculateSpellLearnCostNewSystem(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// ToDo: add more test cases for other classes dificulties and higher TEs
|
||||
func TestCalculateSkillImproveCostNewSystem(t *testing.T) {
|
||||
// Ensure DB is initialized so GetImprovementCost can run without nil DB
|
||||
database.SetupTestDB()
|
||||
defer database.ResetTestDB()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
request gsmaster.LernCostRequest
|
||||
skillInfo models.SkillLearningInfo
|
||||
targetLevel int
|
||||
requiredTE int
|
||||
requiredEP int
|
||||
requiredGold int
|
||||
availablePP int
|
||||
availableGold int
|
||||
}{
|
||||
{
|
||||
name: "Base cost calculation without rewards",
|
||||
request: gsmaster.LernCostRequest{},
|
||||
skillInfo: models.SkillLearningInfo{
|
||||
SkillName: "Schwimmen",
|
||||
CategoryName: "Körper",
|
||||
DifficultyName: "leicht",
|
||||
ClassCode: "Bb",
|
||||
EPPerTE: 10,
|
||||
LearnCost: 1,
|
||||
},
|
||||
requiredTE: 1,
|
||||
requiredEP: 10,
|
||||
requiredGold: 200,
|
||||
targetLevel: 13,
|
||||
availablePP: 0,
|
||||
availableGold: 0,
|
||||
}, {
|
||||
name: "applies PP reduction",
|
||||
request: gsmaster.LernCostRequest{},
|
||||
skillInfo: models.SkillLearningInfo{
|
||||
SkillName: "Schwimmen",
|
||||
CategoryName: "Körper",
|
||||
DifficultyName: "leicht",
|
||||
ClassCode: "Bb",
|
||||
EPPerTE: 10,
|
||||
LearnCost: 1,
|
||||
},
|
||||
requiredTE: 0,
|
||||
requiredEP: 0,
|
||||
requiredGold: 0,
|
||||
targetLevel: 13,
|
||||
availablePP: 1,
|
||||
availableGold: 0,
|
||||
},
|
||||
|
||||
{
|
||||
name: "converts gold up to half EP",
|
||||
request: gsmaster.LernCostRequest{},
|
||||
skillInfo: models.SkillLearningInfo{
|
||||
SkillName: "Schwimmen",
|
||||
CategoryName: "Körper",
|
||||
DifficultyName: "leicht",
|
||||
ClassCode: "Bb",
|
||||
EPPerTE: 10,
|
||||
},
|
||||
requiredTE: 1,
|
||||
requiredEP: 5,
|
||||
targetLevel: 13,
|
||||
availablePP: 0,
|
||||
availableGold: 50,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
remainingPP := tt.availablePP
|
||||
remainingGold := tt.availableGold
|
||||
|
||||
result := gsmaster.SkillCostResultNew{
|
||||
CharacterClass: tt.skillInfo.ClassCode,
|
||||
SkillName: tt.skillInfo.SkillName,
|
||||
Category: tt.skillInfo.CategoryName,
|
||||
Difficulty: tt.skillInfo.DifficultyName,
|
||||
TargetLevel: tt.targetLevel,
|
||||
}
|
||||
|
||||
err := CalculateSkillImproveCostNewSystem(&tt.request, &result, tt.targetLevel, &remainingPP, &remainingGold, &tt.skillInfo)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Base EP before gold conversion is computed from post-PP LE
|
||||
baseEP := tt.skillInfo.EPPerTE * result.LE
|
||||
originalTrain := result.LE + result.PPUsed
|
||||
|
||||
assert.Greater(t, originalTrain, 0, "should have positive training cost")
|
||||
assert.Equal(t, tt.availablePP-result.PPUsed, remainingPP, "PP tracking should be consistent")
|
||||
assert.Equal(t, tt.availableGold-result.GoldUsed, remainingGold, "Gold tracking should match usage")
|
||||
|
||||
if tt.availablePP > 0 {
|
||||
assert.Equal(t, tt.availablePP-remainingPP, result.PPUsed, "PP used should reduce remaining PP")
|
||||
assert.Equal(t, baseEP, result.EP, "No gold in this case; EP equals base")
|
||||
assert.Equal(t, tt.skillInfo.EPPerTE*result.LE, result.EP)
|
||||
} else {
|
||||
expectedGoldUsed := tt.availableGold
|
||||
halfEPCap := (baseEP / 2) * 10
|
||||
if expectedGoldUsed > halfEPCap {
|
||||
expectedGoldUsed = halfEPCap
|
||||
}
|
||||
assert.Equal(t, expectedGoldUsed, result.GoldUsed)
|
||||
assert.Equal(t, baseEP-expectedGoldUsed/10, result.EP)
|
||||
assert.Equal(t, tt.availableGold-expectedGoldUsed, remainingGold)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1254,30 +1254,37 @@ func ImportSpellLevelLECosts(inputDir string) error {
|
||||
|
||||
// ExportSkillImprovementCosts exports all skill improvement costs to a JSON file
|
||||
func ExportSkillImprovementCosts(outputDir string) error {
|
||||
var costs []models.SkillImprovementCost
|
||||
if err := database.DB.Preload("SkillCategoryDifficulty.Skill").
|
||||
Preload("SkillCategoryDifficulty.SkillCategory").
|
||||
Preload("SkillCategoryDifficulty.SkillDifficulty").
|
||||
Find(&costs).Error; err != nil {
|
||||
var costs []models.SkillImprovementCost2
|
||||
if err := database.DB.Find(&costs).Error; err != nil {
|
||||
return fmt.Errorf("failed to fetch skill improvement costs: %w", err)
|
||||
}
|
||||
|
||||
exportable := make([]ExportableSkillImprovementCost, 0, len(costs))
|
||||
for _, cost := range costs {
|
||||
// Skip records with incomplete relationships
|
||||
if cost.SkillCategoryDifficulty.Skill.Name == "" ||
|
||||
cost.SkillCategoryDifficulty.SkillCategory.Name == "" ||
|
||||
cost.SkillCategoryDifficulty.SkillDifficulty.Name == "" {
|
||||
var lc models.SkillCategory
|
||||
if err := database.DB.First(&lc, cost.CategoryID).Error; err != nil {
|
||||
continue
|
||||
}
|
||||
var ld models.SkillDifficulty
|
||||
if err := database.DB.First(&ld, cost.DifficultyID).Error; err != nil {
|
||||
continue
|
||||
}
|
||||
var scd models.SkillCategoryDifficulty
|
||||
if err := database.DB.Where("skill_category = ? AND skill_difficulty = ?", lc.Name, ld.Name).First(&scd).Error; err != nil {
|
||||
continue
|
||||
}
|
||||
var skill models.Skill
|
||||
if err := database.DB.First(&skill, scd.SkillID).Error; err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
exportable = append(exportable, ExportableSkillImprovementCost{
|
||||
SkillName: cost.SkillCategoryDifficulty.Skill.Name,
|
||||
SkillSystem: cost.SkillCategoryDifficulty.Skill.GameSystem,
|
||||
CategoryName: cost.SkillCategoryDifficulty.SkillCategory.Name,
|
||||
CategorySystem: cost.SkillCategoryDifficulty.SkillCategory.GameSystem,
|
||||
DifficultyName: cost.SkillCategoryDifficulty.SkillDifficulty.Name,
|
||||
DifficultySystem: cost.SkillCategoryDifficulty.SkillDifficulty.GameSystem,
|
||||
SkillName: skill.Name,
|
||||
SkillSystem: skill.GameSystem,
|
||||
CategoryName: lc.Name,
|
||||
CategorySystem: lc.GameSystem,
|
||||
DifficultyName: ld.Name,
|
||||
DifficultySystem: ld.GameSystem,
|
||||
CurrentLevel: cost.CurrentLevel,
|
||||
TERequired: cost.TERequired,
|
||||
})
|
||||
@@ -1325,16 +1332,17 @@ func ImportSkillImprovementCosts(inputDir string) error {
|
||||
exp.SkillName, exp.CategoryName, exp.DifficultyName, err)
|
||||
}
|
||||
|
||||
// Find or create SkillImprovementCost
|
||||
var cost models.SkillImprovementCost
|
||||
result := database.DB.Where("skill_category_difficulty_id = ? AND current_level = ?",
|
||||
scd.ID, exp.CurrentLevel).First(&cost)
|
||||
// Find or create SkillImprovementCost2 using category/difficulty IDs
|
||||
var cost models.SkillImprovementCost2
|
||||
result := database.DB.Where("skill_category_id = ? AND skill_difficulty_id = ? AND current_level = ?",
|
||||
categoryID, difficultyID, exp.CurrentLevel).First(&cost)
|
||||
|
||||
if result.Error == gorm.ErrRecordNotFound {
|
||||
cost = models.SkillImprovementCost{
|
||||
SkillCategoryDifficultyID: scd.ID,
|
||||
CurrentLevel: exp.CurrentLevel,
|
||||
TERequired: exp.TERequired,
|
||||
cost = models.SkillImprovementCost2{
|
||||
CategoryID: categoryID,
|
||||
DifficultyID: difficultyID,
|
||||
CurrentLevel: exp.CurrentLevel,
|
||||
TERequired: exp.TERequired,
|
||||
}
|
||||
if err := database.DB.Create(&cost).Error; err != nil {
|
||||
return fmt.Errorf("failed to create skill improvement cost: %w", err)
|
||||
|
||||
@@ -13,30 +13,39 @@ import (
|
||||
|
||||
// ExportSkillImprovementCosts exports all skill improvement costs to a JSON file
|
||||
func ExportSkillImprovementCosts(outputDir string) error {
|
||||
var costs []models.SkillImprovementCost
|
||||
if err := database.DB.Preload("SkillCategoryDifficulty.Skill").
|
||||
Preload("SkillCategoryDifficulty.SkillCategory").
|
||||
Preload("SkillCategoryDifficulty.SkillDifficulty").
|
||||
Find(&costs).Error; err != nil {
|
||||
var costs []models.SkillImprovementCost2
|
||||
if err := database.DB.Find(&costs).Error; err != nil {
|
||||
return fmt.Errorf("failed to fetch skill improvement costs: %w", err)
|
||||
}
|
||||
|
||||
exportable := make([]ExportableSkillImprovementCost, 0, len(costs))
|
||||
for _, cost := range costs {
|
||||
// Skip records with incomplete relationships
|
||||
if cost.SkillCategoryDifficulty.Skill.Name == "" ||
|
||||
cost.SkillCategoryDifficulty.SkillCategory.Name == "" ||
|
||||
cost.SkillCategoryDifficulty.SkillDifficulty.Name == "" {
|
||||
// Resolve category and difficulty names
|
||||
var lc models.SkillCategory
|
||||
if err := database.DB.First(&lc, cost.CategoryID).Error; err != nil {
|
||||
continue
|
||||
}
|
||||
var ld models.SkillDifficulty
|
||||
if err := database.DB.First(&ld, cost.DifficultyID).Error; err != nil {
|
||||
continue
|
||||
}
|
||||
// Find skill via learning_skill_category_difficulties
|
||||
var scd models.SkillCategoryDifficulty
|
||||
if err := database.DB.Where("skill_category = ? AND skill_difficulty = ?", lc.Name, ld.Name).First(&scd).Error; err != nil {
|
||||
continue
|
||||
}
|
||||
var skill models.Skill
|
||||
if err := database.DB.First(&skill, scd.SkillID).Error; err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
exportable = append(exportable, ExportableSkillImprovementCost{
|
||||
SkillName: cost.SkillCategoryDifficulty.Skill.Name,
|
||||
SkillSystem: cost.SkillCategoryDifficulty.Skill.GameSystem,
|
||||
CategoryName: cost.SkillCategoryDifficulty.SkillCategory.Name,
|
||||
CategorySystem: cost.SkillCategoryDifficulty.SkillCategory.GameSystem,
|
||||
DifficultyName: cost.SkillCategoryDifficulty.SkillDifficulty.Name,
|
||||
DifficultySystem: cost.SkillCategoryDifficulty.SkillDifficulty.GameSystem,
|
||||
SkillName: skill.Name,
|
||||
SkillSystem: skill.GameSystem,
|
||||
CategoryName: lc.Name,
|
||||
CategorySystem: lc.GameSystem,
|
||||
DifficultyName: ld.Name,
|
||||
DifficultySystem: ld.GameSystem,
|
||||
CurrentLevel: cost.CurrentLevel,
|
||||
TERequired: cost.TERequired,
|
||||
})
|
||||
@@ -84,16 +93,17 @@ func ImportSkillImprovementCosts(inputDir string) error {
|
||||
exp.SkillName, exp.CategoryName, exp.DifficultyName, err)
|
||||
}
|
||||
|
||||
// Find or create SkillImprovementCost
|
||||
var cost models.SkillImprovementCost
|
||||
result := database.DB.Where("skill_category_difficulty_id = ? AND current_level = ?",
|
||||
scd.ID, exp.CurrentLevel).First(&cost)
|
||||
// Find or create SkillImprovementCost2 using category/difficulty IDs
|
||||
var cost models.SkillImprovementCost2
|
||||
result := database.DB.Where("skill_category_id = ? AND skill_difficulty_id = ? AND current_level = ?",
|
||||
categoryID, difficultyID, exp.CurrentLevel).First(&cost)
|
||||
|
||||
if result.Error == gorm.ErrRecordNotFound {
|
||||
cost = models.SkillImprovementCost{
|
||||
SkillCategoryDifficultyID: scd.ID,
|
||||
CurrentLevel: exp.CurrentLevel,
|
||||
TERequired: exp.TERequired,
|
||||
cost = models.SkillImprovementCost2{
|
||||
CategoryID: categoryID,
|
||||
DifficultyID: difficultyID,
|
||||
CurrentLevel: exp.CurrentLevel,
|
||||
TERequired: exp.TERequired,
|
||||
}
|
||||
if err := database.DB.Create(&cost).Error; err != nil {
|
||||
return fmt.Errorf("failed to create skill improvement cost: %w", err)
|
||||
|
||||
@@ -893,11 +893,12 @@ func TestExportImportSkillImprovementCosts(t *testing.T) {
|
||||
t.Fatalf("Failed to query SkillCategoryDifficulty: %v", err)
|
||||
}
|
||||
|
||||
// Create SkillImprovementCost
|
||||
improvementCost := models.SkillImprovementCost{
|
||||
SkillCategoryDifficultyID: scd.ID,
|
||||
CurrentLevel: 15, // Use unique level to avoid conflicts
|
||||
TERequired: 5,
|
||||
// Create SkillImprovementCost2 (new model)
|
||||
improvementCost := models.SkillImprovementCost2{
|
||||
CategoryID: category.ID,
|
||||
DifficultyID: difficulty.ID,
|
||||
CurrentLevel: 15, // Use unique level to avoid conflicts
|
||||
TERequired: 5,
|
||||
}
|
||||
database.DB.Create(&improvementCost)
|
||||
|
||||
@@ -923,10 +924,10 @@ func TestExportImportSkillImprovementCosts(t *testing.T) {
|
||||
t.Fatalf("ImportSkillImprovementCosts failed: %v", err)
|
||||
}
|
||||
|
||||
var imported models.SkillImprovementCost
|
||||
result := database.DB.Where("skill_category_difficulty_id = ? AND current_level = ?", scd.ID, 15).First(&imported)
|
||||
var imported models.SkillImprovementCost2
|
||||
result := database.DB.Where("skill_category_id = ? AND skill_difficulty_id = ? AND current_level = ?", category.ID, difficulty.ID, 15).First(&imported)
|
||||
if result.Error != nil {
|
||||
t.Fatalf("SkillImprovementCost not found after import: %v", result.Error)
|
||||
t.Fatalf("SkillImprovementCost2 not found after import: %v", result.Error)
|
||||
}
|
||||
|
||||
// Should be restored to original value from export
|
||||
|
||||
@@ -291,7 +291,7 @@ func CreateLearningCostsTables() error {
|
||||
&models.ClassSpellSchoolEPCost{},
|
||||
&models.SpellLevelLECost{},
|
||||
&models.SkillCategoryDifficulty{},
|
||||
&models.SkillImprovementCost{},
|
||||
&models.SkillImprovementCost2{},
|
||||
}
|
||||
|
||||
// Erstelle oder migriere alle Tabellen
|
||||
|
||||
@@ -5,6 +5,8 @@ import (
|
||||
"bamort/models"
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// MigrateLearningCostsToDatabase überträgt die Daten aus learningCostsData in die Datenbank
|
||||
@@ -473,16 +475,32 @@ func migrateSkillImprovementCosts() error {
|
||||
|
||||
// Für jeden Level in TrainCosts
|
||||
for level, teCost := range data.TrainCosts {
|
||||
improvementCost := models.SkillImprovementCost{
|
||||
SkillCategoryDifficultyID: categoryDifficulty.ID,
|
||||
CurrentLevel: level,
|
||||
TERequired: teCost,
|
||||
var improvementCost models.SkillImprovementCost2
|
||||
err := database.DB.Where(
|
||||
"skill_category_id = ? AND skill_difficulty_id = ? AND current_level = ?",
|
||||
skillCategory.ID, skillDifficulty.ID, level,
|
||||
).First(&improvementCost).Error
|
||||
|
||||
if err == gorm.ErrRecordNotFound {
|
||||
improvementCost = models.SkillImprovementCost2{
|
||||
CategoryID: skillCategory.ID,
|
||||
DifficultyID: skillDifficulty.ID,
|
||||
CurrentLevel: level,
|
||||
TERequired: teCost,
|
||||
}
|
||||
if err := improvementCost.Create(); err != nil {
|
||||
return fmt.Errorf("failed to create improvement cost for %s level %d: %w", skillName, level, err)
|
||||
}
|
||||
} else if err != nil {
|
||||
return fmt.Errorf("failed to query improvement cost for %s level %d: %w", skillName, level, err)
|
||||
} else {
|
||||
improvementCost.TERequired = teCost
|
||||
if err := database.DB.Save(&improvementCost).Error; err != nil {
|
||||
return fmt.Errorf("failed to update improvement cost for %s level %d: %w", skillName, level, err)
|
||||
}
|
||||
}
|
||||
|
||||
if err := improvementCost.Create(); err != nil {
|
||||
return fmt.Errorf("failed to create improvement cost for %s level %d: %w", skillName, level, err)
|
||||
}
|
||||
log.Printf("Created improvement cost: %s - %s - %s Level %d = %d TE",
|
||||
log.Printf("Upserted improvement cost: %s - %s - %s Level %d = %d TE",
|
||||
skillName, categoryName, difficultyName, level, teCost)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -248,7 +248,7 @@ func copyMariaDBToSQLite(mariaDB, sqliteDB *gorm.DB) error {
|
||||
&models.SpellLevelLECost{},
|
||||
&models.SkillCategoryDifficulty{},
|
||||
&models.WeaponSkillCategoryDifficulty{},
|
||||
&models.SkillImprovementCost{},
|
||||
&models.SkillImprovementCost2{},
|
||||
&models.ClassCategoryLearningPoints{},
|
||||
&models.ClassSpellPoints{},
|
||||
&models.ClassTypicalSkill{},
|
||||
@@ -368,10 +368,11 @@ func copyTableData(sourceDB, targetDB *gorm.DB, model interface{}) error {
|
||||
}
|
||||
|
||||
// Batch in SQLite einfügen
|
||||
// Use Save() instead of Create() to avoid GORM applying default values to zero values (e.g., false for booleans)
|
||||
// Use Save() with SkipHooks to preserve raw values and avoid callbacks that rely on global DB state
|
||||
db := targetDB.Session(&gorm.Session{SkipHooks: true})
|
||||
for i := 0; i < recordsVal.Len(); i++ {
|
||||
record := recordsVal.Index(i).Addr().Interface()
|
||||
if err := targetDB.Save(record).Error; err != nil {
|
||||
if err := db.Save(record).Error; err != nil {
|
||||
logger.Error("Fehler beim Speichern von Datensatz in Batch %d für %s: %s", batchNum, tableName, err.Error())
|
||||
return err
|
||||
}
|
||||
@@ -770,7 +771,7 @@ func copySQLiteToMariaDB(sqliteDB, mariaDB *gorm.DB) error {
|
||||
&models.SpellLevelLECost{},
|
||||
&models.SkillCategoryDifficulty{}, // Jetzt nach Skills
|
||||
&models.WeaponSkillCategoryDifficulty{},
|
||||
&models.SkillImprovementCost{},
|
||||
&models.SkillImprovementCost2{},
|
||||
&models.ClassCategoryLearningPoints{},
|
||||
&models.ClassSpellPoints{},
|
||||
&models.ClassTypicalSkill{},
|
||||
@@ -923,8 +924,8 @@ func copyTableDataReverse(sourceDB, targetDB *gorm.DB, model interface{}) error
|
||||
return fmt.Errorf("failed to read batch from source: %w", err)
|
||||
}
|
||||
records = batch
|
||||
case *models.SkillImprovementCost:
|
||||
var batch []models.SkillImprovementCost
|
||||
case *models.SkillImprovementCost2:
|
||||
var batch []models.SkillImprovementCost2
|
||||
if err := sourceDB.Limit(batchSize).Offset(offset).Find(&batch).Error; err != nil {
|
||||
return fmt.Errorf("failed to read batch from source: %w", err)
|
||||
}
|
||||
@@ -1162,7 +1163,7 @@ func clearMariaDBData(db *gorm.DB) error {
|
||||
&models.Char{},
|
||||
|
||||
// Learning Costs System - Abhängige Tabellen (vor Skills/Spells löschen)
|
||||
&models.SkillImprovementCost{},
|
||||
&models.SkillImprovementCost2{},
|
||||
&models.WeaponSkillCategoryDifficulty{},
|
||||
&models.SkillCategoryDifficulty{},
|
||||
&models.SpellLevelLECost{},
|
||||
|
||||
@@ -32,7 +32,7 @@ func TestTableListCompleteness(t *testing.T) {
|
||||
"*models.SpellLevelLECost": true,
|
||||
"*models.SkillCategoryDifficulty": true,
|
||||
"*models.WeaponSkillCategoryDifficulty": true,
|
||||
"*models.SkillImprovementCost": true,
|
||||
"*models.SkillImprovementCost2": true,
|
||||
|
||||
// GSMaster Base Data
|
||||
"*models.Skill": true,
|
||||
@@ -88,7 +88,7 @@ func TestTableListCompleteness(t *testing.T) {
|
||||
&models.SpellLevelLECost{},
|
||||
&models.SkillCategoryDifficulty{},
|
||||
&models.WeaponSkillCategoryDifficulty{},
|
||||
&models.SkillImprovementCost{},
|
||||
&models.SkillImprovementCost2{},
|
||||
&models.Skill{},
|
||||
&models.WeaponSkill{},
|
||||
&models.Spell{},
|
||||
@@ -301,8 +301,8 @@ func getModelTypeName(model interface{}) string {
|
||||
return "*models.SkillCategoryDifficulty"
|
||||
case *models.WeaponSkillCategoryDifficulty:
|
||||
return "*models.WeaponSkillCategoryDifficulty"
|
||||
case *models.SkillImprovementCost:
|
||||
return "*models.SkillImprovementCost"
|
||||
case *models.SkillImprovementCost2:
|
||||
return "*models.SkillImprovementCost2"
|
||||
case *models.Skill:
|
||||
return "*models.Skill"
|
||||
case *models.WeaponSkill:
|
||||
|
||||
@@ -180,12 +180,12 @@ func learningMigrateStructure(db ...*gorm.DB) error {
|
||||
&SpellLevelLECost{},
|
||||
&SkillCategoryDifficulty{},
|
||||
&WeaponSkillCategoryDifficulty{},
|
||||
&SkillImprovementCost{},
|
||||
&ClassCategoryLearningPoints{},
|
||||
&ClassSpellPoints{},
|
||||
&ClassTypicalSkill{},
|
||||
&ClassTypicalSpell{},
|
||||
&AuditLogEntry{},
|
||||
&SkillImprovementCost2{},
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -306,7 +306,7 @@ func TestLearningMigrateStructure_VerifyStructures(t *testing.T) {
|
||||
&ClassSpellSchoolEPCost{},
|
||||
&SpellLevelLECost{},
|
||||
&SkillCategoryDifficulty{},
|
||||
&SkillImprovementCost{},
|
||||
&SkillImprovementCost2{},
|
||||
&AuditLogEntry{},
|
||||
}
|
||||
|
||||
|
||||
@@ -132,6 +132,7 @@ type WeaponSkillCategoryDifficulty struct {
|
||||
SCategory string `gorm:"column:skill_category;size:25;not null;index;default:Waffen" json:"skillCategory"`
|
||||
}
|
||||
|
||||
/*
|
||||
// SkillImprovementCost definiert TE-Kosten für Verbesserungen basierend auf Kategorie, Schwierigkeit und aktuellem Wert
|
||||
type SkillImprovementCost struct {
|
||||
ID uint `gorm:"primaryKey" json:"id"`
|
||||
@@ -139,6 +140,17 @@ type SkillImprovementCost struct {
|
||||
CurrentLevel int `gorm:"not null;index" json:"current_level"` // Aktueller Fertigkeitswert
|
||||
TERequired int `gorm:"not null" json:"te_required"` // Benötigte Trainingseinheiten
|
||||
SkillCategoryDifficulty SkillCategoryDifficulty `gorm:"foreignKey:SkillCategoryDifficultyID;constraint:OnUpdate:CASCADE,OnDelete:CASCADE" json:"skill_category_difficulty"`
|
||||
CategoryID uint `gorm:"column:skill_category_id;not null;index;default:1" json:"skillCategoryId"` // SkillCategoryID
|
||||
DifficultyID uint `gorm:"column:skill_difficulty_id;not null;index;default:1" json:"skillDifficultyId"` // SkillDifficultyID
|
||||
}
|
||||
*/
|
||||
// SkillImprovementCost definiert TE-Kosten für Verbesserungen basierend auf Kategorie, Schwierigkeit und aktuellem Wert
|
||||
type SkillImprovementCost2 struct {
|
||||
ID uint `gorm:"primaryKey" json:"id"`
|
||||
CurrentLevel int `gorm:"not null;index" json:"current_level"` // Aktueller Fertigkeitswert
|
||||
TERequired int `gorm:"not null" json:"te_required"` // Benötigte Trainingseinheiten
|
||||
CategoryID uint `gorm:"column:skill_category_id;not null;index;default:1" json:"skillCategoryId"` // SkillCategoryID
|
||||
DifficultyID uint `gorm:"column:skill_difficulty_id;not null;index;default:1" json:"skillDifficultyId"` // SkillDifficultyID
|
||||
}
|
||||
|
||||
// Für komplexere Queries: View oder Helper-Strukturen
|
||||
@@ -151,7 +163,7 @@ type SkillLearningInfo struct {
|
||||
CategoryName string `json:"category_name"`
|
||||
DifficultyID uint `json:"difficulty_id"`
|
||||
DifficultyName string `json:"difficulty_name"`
|
||||
LearnCost int `json:"learn_cost"` // LE-Kosten für das Erlernen
|
||||
LearnCost int `json:"learn_cost"` // LE-Kosten / TE-Kosten für das Erlernen
|
||||
CharacterClassID uint `json:"character_class_id"`
|
||||
ClassCode string `json:"class_code"`
|
||||
ClassName string `json:"class_name"`
|
||||
@@ -233,9 +245,15 @@ func (WeaponSkillCategoryDifficulty) TableName() string {
|
||||
return "learning_weaponskill_category_difficulties"
|
||||
}
|
||||
|
||||
/*
|
||||
func (SkillImprovementCost) TableName() string {
|
||||
return "learning_skill_improvement_costs"
|
||||
}
|
||||
*/
|
||||
|
||||
func (SkillImprovementCost2) TableName() string {
|
||||
return "skill_improvement_cost2"
|
||||
}
|
||||
|
||||
func (sllc *SpellLevelLECost) ensureGameSystem() {
|
||||
gs := GetGameSystem(sllc.GameSystemId, sllc.GameSystem)
|
||||
@@ -476,9 +494,15 @@ func (wscd *WeaponSkillCategoryDifficulty) Create() error {
|
||||
return database.DB.Create(wscd).Error
|
||||
}
|
||||
|
||||
/*
|
||||
func (sic *SkillImprovementCost) Create() error {
|
||||
return database.DB.Create(sic).Error
|
||||
}
|
||||
*/
|
||||
|
||||
func (sic *SkillImprovementCost2) Create() error {
|
||||
return database.DB.Create(sic).Error
|
||||
}
|
||||
|
||||
// Komplexere Query-Methoden
|
||||
|
||||
@@ -630,15 +654,20 @@ func GetSpellLearningInfoNewSystem(spellName string, classCode string) (*SpellLe
|
||||
|
||||
// GetImprovementCost holt die Verbesserungskosten für eine Fertigkeit
|
||||
func GetImprovementCost(skillName string, categoryName string, difficultyName string, currentLevel int) (int, error) {
|
||||
var result SkillImprovementCost
|
||||
var result SkillImprovementCost2
|
||||
|
||||
err := database.DB.Raw(`
|
||||
SELECT sic.te_required
|
||||
FROM learning_skill_improvement_costs sic
|
||||
JOIN learning_skill_category_difficulties scd ON sic.skill_category_difficulty_id = scd.id
|
||||
JOIN gsm_skills s ON scd.skill_id = s.id
|
||||
WHERE s.name = ? AND scd.skill_category = ? AND scd.skill_difficulty = ? AND sic.current_level = ?
|
||||
`, skillName, categoryName, difficultyName, currentLevel).Scan(&result).Error
|
||||
SELECT sic.te_required
|
||||
FROM skill_improvement_cost2 sic
|
||||
JOIN learning_skill_categories lc ON lc.id = sic.skill_category_id
|
||||
JOIN learning_skill_difficulties ld ON ld.id = sic.skill_difficulty_id
|
||||
JOIN learning_skill_category_difficulties scd ON scd.skill_category = lc.name AND scd.skill_difficulty = ld.name
|
||||
JOIN gsm_skills s ON scd.skill_id = s.id
|
||||
WHERE s.name = ?
|
||||
AND lc.name = ?
|
||||
AND ld.name = ?
|
||||
AND sic.current_level = ?
|
||||
`, skillName, categoryName, difficultyName, currentLevel).Scan(&result).Error
|
||||
|
||||
if err != nil {
|
||||
return 0, err
|
||||
|
||||
@@ -989,7 +989,7 @@ func TestLearningCostsWorkflow_CompleteDataValidation(t *testing.T) {
|
||||
assert.Equal(t, "leicht", skillInfo.DifficultyName)
|
||||
assert.Equal(t, "Bb", skillInfo.ClassCode)
|
||||
assert.Equal(t, 10, skillInfo.EPPerTE, "EP per TE should match the class/category cost")
|
||||
assert.Equal(t, 5, skillInfo.LearnCost, "Learn cost should be 5 for leicht difficulty")
|
||||
assert.Equal(t, 1, skillInfo.LearnCost, "Learn cost should be 5 for leicht difficulty")
|
||||
|
||||
// 3. Verify active source codes include expected values
|
||||
sourceCodes, err := GetActiveSourceCodes()
|
||||
|
||||
@@ -64,7 +64,7 @@ type DatabaseExport struct {
|
||||
ClassSpellSchoolEPCosts []models.ClassSpellSchoolEPCost `json:"learning_class_spell_school_ep_costs"`
|
||||
SpellLevelLECosts []models.SpellLevelLECost `json:"learning_spell_level_le_costs"`
|
||||
SkillCategoryDifficulties []models.SkillCategoryDifficulty `json:"learning_skill_category_difficulties"`
|
||||
SkillImprovementCosts []models.SkillImprovementCost `json:"learning_skill_improvement_costs"`
|
||||
SkillImprovementCosts []models.SkillImprovementCost2 `json:"learning_skill_improvement_costs"`
|
||||
AuditLogEntries []models.AuditLogEntry `json:"audit_log_entries"`
|
||||
}
|
||||
|
||||
|
||||
@@ -80,7 +80,7 @@ func TestImportDatabaseHandler_Success(t *testing.T) {
|
||||
|
||||
assert.Equal(t, "Database imported successfully", response["message"])
|
||||
assert.Greater(t, response["record_count"], float64(0))
|
||||
assert.Equal(t, response["record_count"], exportResult)
|
||||
assert.Equal(t, float64(exportResult.RecordCount), response["record_count"])
|
||||
}
|
||||
|
||||
func TestImportDatabaseHandler_MissingFilepath(t *testing.T) {
|
||||
|
||||
@@ -31,7 +31,7 @@ type LearningDataExport struct {
|
||||
ClassSpellSchoolEPCosts []models.ClassSpellSchoolEPCost `json:"class_spell_school_ep_costs"`
|
||||
SpellLevelLECosts []models.SpellLevelLECost `json:"spell_level_le_costs"`
|
||||
SkillCategoryDifficulties []models.SkillCategoryDifficulty `json:"skill_category_difficulties"`
|
||||
SkillImprovementCosts []models.SkillImprovementCost `json:"skill_improvement_costs"`
|
||||
SkillImprovementCosts []models.SkillImprovementCost2 `json:"skill_improvement_costs"`
|
||||
}
|
||||
|
||||
// ExportCharacter exports a complete character with all related data
|
||||
@@ -177,7 +177,7 @@ func ExportCharacter(characterID uint) (*CharacterExport, error) {
|
||||
ClassSpellSchoolEPCosts: make([]models.ClassSpellSchoolEPCost, 0),
|
||||
SpellLevelLECosts: make([]models.SpellLevelLECost, 0),
|
||||
SkillCategoryDifficulties: make([]models.SkillCategoryDifficulty, 0),
|
||||
SkillImprovementCosts: make([]models.SkillImprovementCost, 0),
|
||||
SkillImprovementCosts: make([]models.SkillImprovementCost2, 0),
|
||||
}
|
||||
|
||||
database.DB.Find(&export.LearningData.Sources)
|
||||
@@ -189,7 +189,7 @@ func ExportCharacter(characterID uint) (*CharacterExport, error) {
|
||||
database.DB.Preload("CharacterClass").Preload("SpellSchool").Find(&export.LearningData.ClassSpellSchoolEPCosts)
|
||||
database.DB.Find(&export.LearningData.SpellLevelLECosts)
|
||||
database.DB.Preload("Skill").Preload("SkillCategory").Preload("SkillDifficulty").Find(&export.LearningData.SkillCategoryDifficulties)
|
||||
database.DB.Preload("SkillCategoryDifficulty").Find(&export.LearningData.SkillImprovementCosts)
|
||||
database.DB.Find(&export.LearningData.SkillImprovementCosts)
|
||||
|
||||
// Load audit log entries
|
||||
export.AuditLogEntries = make([]models.AuditLogEntry, 0)
|
||||
|
||||
@@ -170,6 +170,11 @@ func importOrUpdateSkill(tx *gorm.DB, skill *models.Skill) error {
|
||||
skill.SourceID = 1
|
||||
}
|
||||
|
||||
// Ensure game system fields are populated so queries match existing records
|
||||
gs := models.GetGameSystem(skill.GameSystemId, skill.GameSystem)
|
||||
skill.GameSystem = gs.Name
|
||||
skill.GameSystemId = gs.ID
|
||||
|
||||
var existing models.Skill
|
||||
err := tx.Where("name = ? AND game_system = ?", skill.Name, skill.GameSystem).First(&existing).Error
|
||||
|
||||
|
||||
Reference in New Issue
Block a user