Files
bamort/backend/gsmaster/learning_costs_enhancement.go
T
Frank 39659bcb3e New test TestCalculateSkillImproveCostNewSystem in chain of learning system
Updated learning_skill_category_difficulties to match rule set
removed SkillImprovementCost replaced by SkillImprovementCost2
2026-02-01 13:21:16 +01:00

351 lines
12 KiB
Go

package gsmaster
import (
"bamort/database"
"bamort/models"
"fmt"
"log"
)
// EnhanceLearningDataWithExistingTables ergänzt die neuen Lernkosten-Tabellen mit Daten aus den bereits vorhandenen Tabellen
func EnhanceLearningDataWithExistingTables() error {
log.Println("Starting enhancement of learning data with existing tables...")
// 1. Fertigkeiten aus der bestehenden Skill-Tabelle in SkillCategoryDifficulty einbinden
if err := linkExistingSkillsToCategories(); err != nil {
return fmt.Errorf("failed to link existing skills to categories: %w", err)
}
// 2. Zauber aus der bestehenden Spell-Tabelle mit Zauberschulen verknüpfen
if err := linkExistingSpellsToSchools(); err != nil {
return fmt.Errorf("failed to link existing spells to schools: %w", err)
}
// 3. Charaktere aus der bestehenden Character-Tabelle mit Charakterklassen verknüpfen
if err := linkExistingCharactersToClasses(); err != nil {
return fmt.Errorf("failed to link existing characters to classes: %w", err)
}
// 4. Fehlende Fertigkeiten aus der bestehenden Tabelle zu den Kategorien hinzufügen
if err := addMissingSkillsToCategories(); err != nil {
return fmt.Errorf("failed to add missing skills to categories: %w", err)
}
// 5. Verknüpfe bestehende Fertigkeiten und Zauber mit Standardquellen
if err := linkExistingItemsToDefaultSources(); err != nil {
return fmt.Errorf("failed to link existing items to default sources: %w", err)
}
log.Println("Enhancement completed successfully!")
return nil
}
// linkExistingSkillsToCategories verknüpft vorhandene Fertigkeiten mit Kategorien und Schwierigkeiten
func linkExistingSkillsToCategories() error {
var skills []models.Skill
if err := database.DB.Find(&skills).Error; err != nil {
return fmt.Errorf("failed to fetch existing skills: %w", err)
}
for _, skill := range skills {
// Prüfe ob bereits Verknüpfungen für diese Fertigkeit existieren
var existingLinks []models.SkillCategoryDifficulty
if err := database.DB.Where("skill_id = ?", skill.ID).Find(&existingLinks).Error; err != nil {
return fmt.Errorf("failed to check existing links for skill %s: %w", skill.Name, err)
}
// Wenn bereits Verknüpfungen existieren, überspringe
if len(existingLinks) > 0 {
log.Printf("Skill %s already has category links, skipping", skill.Name)
continue
}
// Suche nach der Fertigkeit in den lerningCostsData
category, difficulty := findSkillInLearningData(skill.Name)
if category == "" {
log.Printf("Warning: Skill %s not found in learning data, using default category", skill.Name)
// Verwende eine Standard-Kategorie basierend auf der bestehenden Category
if skill.Category != "" {
category = skill.Category
difficulty = skill.Difficulty
if difficulty == "" {
difficulty = "normal"
}
} else {
category = "Unbekannt"
difficulty = "normal"
}
}
// Erstelle Verknüpfung
if err := createSkillCategoryLink(skill.ID, skill.Name, category, difficulty); err != nil {
log.Printf("Warning: Failed to create category link for skill %s: %v", skill.Name, err)
}
}
return nil
}
// linkExistingSpellsToSchools verknüpft vorhandene Zauber mit Zauberschulen
func linkExistingSpellsToSchools() error {
var spells []models.Spell
if err := database.DB.Find(&spells).Error; err != nil {
return fmt.Errorf("failed to fetch existing spells: %w", err)
}
for _, spell := range spells {
// Prüfe ob die Zauberschule existiert
if spell.Category == "" {
log.Printf("Warning: Spell %s has no category, skipping", spell.Name)
continue
}
var spellSchool models.SpellSchool
if err := spellSchool.FirstByName(spell.Category); err != nil {
// Zauberschule existiert nicht, erstelle sie
newSchool := models.SpellSchool{
Name: spell.Category,
GameSystemId: 1,
}
if err := newSchool.Create(); err != nil {
log.Printf("Warning: Failed to create spell school %s for spell %s: %v", spell.Category, spell.Name, err)
continue
}
log.Printf("Created new spell school: %s", spell.Category)
}
log.Printf("Spell %s linked to school %s", spell.Name, spell.Category)
}
return nil
}
// linkExistingCharactersToClasses verknüpft vorhandene Charaktere mit Charakterklassen
func linkExistingCharactersToClasses() error {
var characters []models.Char
if err := database.DB.Find(&characters).Error; err != nil {
return fmt.Errorf("failed to fetch existing characters: %w", err)
}
// Lade alle verfügbaren Charakterklassen aus der Datenbank
var characterClasses []models.CharacterClass
if err := database.DB.Find(&characterClasses).Error; err != nil {
return fmt.Errorf("failed to fetch character classes from database: %w", err)
}
// Erstelle Mapping-Maps für beide Richtungen (Code->Klasse und Name->Klasse)
codeToClass := make(map[string]models.CharacterClass)
nameToClass := make(map[string]models.CharacterClass)
for _, class := range characterClasses {
codeToClass[class.Code] = class
nameToClass[class.Name] = class
}
for _, character := range characters {
var characterClass models.CharacterClass
var found bool
// Versuche zuerst über Code zu finden (falls character.Typ bereits ein Code ist)
if class, exists := codeToClass[character.Typ]; exists {
characterClass = class
found = true
} else if class, exists := nameToClass[character.Typ]; exists {
// Wenn nicht über Code gefunden, versuche über vollständigen Namen
characterClass = class
found = true
}
if !found {
log.Printf("Warning: Character class '%s' not found in database for character %s", character.Typ, character.Name)
continue
}
log.Printf("Character %s linked to class %s (%s)", character.Name, characterClass.Code, characterClass.Name)
}
return nil
}
// addMissingSkillsToCategories fügt Fertigkeiten hinzu, die in der Datenbank existieren aber nicht in den Lernkosten-Daten
func addMissingSkillsToCategories() error {
var skills []models.Skill
if err := database.DB.Find(&skills).Error; err != nil {
return fmt.Errorf("failed to fetch skills: %w", err)
}
for _, skill := range skills {
// Prüfe ob bereits Kategorien-Verknüpfungen existieren
var count int64
if err := database.DB.Model(&models.SkillCategoryDifficulty{}).Where("skill_id = ?", skill.ID).Count(&count).Error; err != nil {
return fmt.Errorf("failed to count category links for skill %s: %w", skill.Name, err)
}
if count == 0 {
// Keine Kategorien-Verknüpfung gefunden, erstelle eine Standard-Verknüpfung
category := "Unbekannt"
difficulty := "normal"
// Verwende bestehende Kategorie falls vorhanden
if skill.Category != "" {
category = skill.Category
}
if skill.Difficulty != "" {
difficulty = skill.Difficulty
}
if err := createSkillCategoryLink(skill.ID, skill.Name, category, difficulty); err != nil {
log.Printf("Warning: Failed to create default category link for skill %s: %v", skill.Name, err)
} else {
log.Printf("Created default category link for skill %s: %s - %s", skill.Name, category, difficulty)
}
}
}
return nil
}
// Hilfsfunktionen
// findSkillInLearningData sucht eine Fertigkeit in den learningCostsData und gibt Kategorie und Schwierigkeit zurück
func findSkillInLearningData(skillName string) (string, string) {
for categoryName, difficulties := range learningCostsData.ImprovementCost {
for difficultyName, data := range difficulties {
for _, skill := range data.Skills {
if skill == skillName {
return categoryName, difficultyName
}
}
}
}
return "", ""
}
// createSkillCategoryLink erstellt eine Verknüpfung zwischen Fertigkeit, Kategorie und Schwierigkeit
func createSkillCategoryLink(skillID uint, skillName, categoryName, difficultyName string) error {
// Hole oder erstelle die Kategorie
var skillCategory models.SkillCategory
gs := GetGameSystem(0, "midgard")
if err := skillCategory.FirstByName(categoryName); err != nil {
// Kategorie existiert nicht, erstelle sie
skillCategory = models.SkillCategory{
Name: categoryName,
GameSystemId: gs.ID,
}
if err := skillCategory.Create(); err != nil {
return fmt.Errorf("failed to create skill category %s: %w", categoryName, err)
}
log.Printf("Created new skill category: %s", categoryName)
}
// Hole oder erstelle die Schwierigkeit
var skillDifficulty models.SkillDifficulty
if err := skillDifficulty.FirstByName(difficultyName); err != nil {
// Schwierigkeit existiert nicht, erstelle sie
skillDifficulty = models.SkillDifficulty{
Name: difficultyName,
GameSystemId: gs.ID,
}
if err := skillDifficulty.Create(); err != nil {
return fmt.Errorf("failed to create skill difficulty %s: %w", difficultyName, err)
}
log.Printf("Created new skill difficulty: %s", difficultyName)
}
// Bestimme LearnCost basierend auf den learningCostsData
learnCost := 2 // Standard-Wert
if categoryData, exists := learningCostsData.ImprovementCost[categoryName]; exists {
if difficultyData, exists := categoryData[difficultyName]; exists {
learnCost = difficultyData.LearnCost
}
}
// Erstelle die Verknüpfung
categoryDifficulty := models.SkillCategoryDifficulty{
SkillID: skillID,
SkillCategoryID: skillCategory.ID,
SkillDifficultyID: skillDifficulty.ID,
LearnCost: learnCost,
}
if err := categoryDifficulty.Create(); err != nil {
return fmt.Errorf("failed to create skill category difficulty link: %w", err)
}
log.Printf("Created skill category link: %s - %s - %s (Learn: %d LE)", skillName, categoryName, difficultyName, learnCost)
return nil
}
// CreateLearningCostsTables erstellt alle neuen Tabellen für das Lernkosten-System
func CreateLearningCostsTables() error {
log.Println("Creating learning costs tables...")
// Liste aller neuen Modelle
models := []interface{}{
&models.Source{},
&models.CharacterClass{},
&models.SkillCategory{},
&models.SkillDifficulty{},
&models.SpellSchool{},
&models.ClassCategoryEPCost{},
&models.ClassSpellSchoolEPCost{},
&models.SpellLevelLECost{},
&models.SkillCategoryDifficulty{},
&models.SkillImprovementCost2{},
}
// Erstelle oder migriere alle Tabellen
for _, model := range models {
if err := database.DB.AutoMigrate(model); err != nil {
return fmt.Errorf("failed to migrate table for model %T: %w", model, err)
}
}
log.Println("Learning costs tables created successfully!")
return nil
}
// linkExistingItemsToDefaultSources verknüpft bestehende Fertigkeiten und Zauber mit Standardquellen
func linkExistingItemsToDefaultSources() error {
// Hole die Standardquellen
var kodSource models.Source
if err := kodSource.FirstByCode("KOD"); err != nil {
return fmt.Errorf("KOD source not found: %w", err)
}
var arkSource models.Source
if err := arkSource.FirstByCode("ARK"); err != nil {
return fmt.Errorf("ARK source not found: %w", err)
}
// Verknüpfe Fertigkeiten mit KOD (falls noch keine Quelle zugeordnet)
var skills []models.Skill
if err := database.DB.Where("source_id IS NULL OR source_id = 0").Find(&skills).Error; err != nil {
return fmt.Errorf("failed to fetch skills without source: %w", err)
}
for _, skill := range skills {
if err := database.DB.Model(&skill).Update("source_id", kodSource.ID).Error; err != nil {
log.Printf("Warning: Failed to update source for skill %s: %v", skill.Name, err)
} else {
log.Printf("Linked skill %s to source KOD", skill.Name)
}
}
// Verknüpfe Zauber mit ARK (falls noch keine Quelle zugeordnet)
var spells []models.Spell
if err := database.DB.Where("source_id IS NULL OR source_id = 0").Find(&spells).Error; err != nil {
return fmt.Errorf("failed to fetch spells without source: %w", err)
}
for _, spell := range spells {
if err := database.DB.Model(&spell).Update("source_id", arkSource.ID).Error; err != nil {
log.Printf("Warning: Failed to update source for spell %s: %v", spell.Name, err)
} else {
log.Printf("Linked spell %s to source ARK", spell.Name)
}
}
return nil
}