Files
bamort/backend/gsmaster/learning_costs_migration.go
T

534 lines
16 KiB
Go

package gsmaster
import (
"bamort/database"
"bamort/models"
"fmt"
"log"
)
// MigrateLearningCostsToDatabase überträgt die Daten aus learningCostsData in die Datenbank
func MigrateLearningCostsToDatabase() error {
log.Println("Starting migration of learning costs data to database...")
// 1. Quellen migrieren
if err := migrateSources(); err != nil {
return fmt.Errorf("failed to migrate sources: %w", err)
}
// 2. Charakterklassen migrieren
if err := migrateCharacterClasses(); err != nil {
return fmt.Errorf("failed to migrate character classes: %w", err)
}
// 2. Fertigkeitskategorien migrieren
if err := migrateSkillCategories(); err != nil {
return fmt.Errorf("failed to migrate skill categories: %w", err)
}
// 3. Schwierigkeitsgrade migrieren
if err := migrateSkillDifficulties(); err != nil {
return fmt.Errorf("failed to migrate skill difficulties: %w", err)
}
// 4. Zauberschulen migrieren
if err := migrateSpellSchools(); err != nil {
return fmt.Errorf("failed to migrate spell schools: %w", err)
}
// 5. EP-Kosten für Kategorien migrieren
if err := migrateClassCategoryEPCosts(); err != nil {
return fmt.Errorf("failed to migrate class category EP costs: %w", err)
}
// 5a. EP-Kosten für "Unbekannt"-Kategorie hinzufügen
if err := migrateUnknownCategoryEPCosts(); err != nil {
return fmt.Errorf("failed to migrate unknown category EP costs: %w", err)
}
// 6. EP-Kosten für Zauberschulen migrieren
if err := migrateClassSpellSchoolEPCosts(); err != nil {
return fmt.Errorf("failed to migrate class spell school EP costs: %w", err)
}
// 7. Zauber-Level LE-Kosten migrieren
if err := migrateSpellLevelLECosts(); err != nil {
return fmt.Errorf("failed to migrate spell level LE costs: %w", err)
}
// 8. Fertigkeits-Kategorien-Schwierigkeiten migrieren
if err := migrateSkillCategoryDifficulties(); err != nil {
return fmt.Errorf("failed to migrate skill category difficulties: %w", err)
}
// 9. Verbesserungskosten migrieren
if err := migrateSkillImprovementCosts(); err != nil {
return fmt.Errorf("failed to migrate skill improvement costs: %w", err)
}
log.Println("Migration completed successfully!")
return nil
}
// migrateSources erstellt die Standardquellen
func migrateSources() error {
sources := []models.Source{
{
Code: "KOD",
Name: "Kodex",
FullName: "Midgard Regelwerk - Kodex",
Edition: "5. Edition",
Publisher: "Pegasus Spiele",
IsCore: true,
IsActive: true,
GameSystem: "midgard",
Description: "Grundregelwerk für Midgard",
},
{
Code: "ARK",
Name: "Arkanum",
FullName: "Midgard Arkanum",
Edition: "5. Edition",
Publisher: "Pegasus Spiele",
IsCore: false,
IsActive: true,
GameSystem: "midgard",
Description: "Erweiterungsregelwerk für Zauber und Magie",
},
{
Code: "MYS",
Name: "Mysterium",
FullName: "Midgard Mysterium",
Edition: "5. Edition",
Publisher: "Pegasus Spiele",
IsCore: false,
IsActive: true,
GameSystem: "midgard",
Description: "Erweiterungsregelwerk für Geheimnisse und Mysterien",
},
{
Code: "UNB",
Name: "Unbekannt",
FullName: "Unbekannte Quelle",
IsCore: false,
IsActive: true,
GameSystem: "midgard",
Description: "Für Inhalte ohne bekannte Quelle",
},
}
for _, source := range sources {
// Prüfe ob die Quelle bereits existiert
var existing models.Source
if err := existing.FirstByCode(source.Code); err != nil {
// Quelle existiert nicht, erstelle sie
if err := source.Create(); err != nil {
return fmt.Errorf("failed to create source %s: %w", source.Code, err)
}
log.Printf("Created source: %s - %s", source.Code, source.Name)
}
}
return nil
}
// migrateCharacterClasses erstellt Charakterklassen-Einträge
func migrateCharacterClasses() error {
// Hole die KOD-Quelle für Charakterklassen (alle Grundklassen sind im Kodex)
var kodSource models.Source
if err := kodSource.FirstByCode("KOD"); err != nil {
return fmt.Errorf("KOD source not found: %w", err)
}
characterClasses := map[string]string{
"As": "Assassine",
"Bb": "Barbar",
"Gl": "Glücksritter",
"Hä": "Händler",
"Kr": "Krieger",
"Sp": "Spitzbube",
"Wa": "Waldläufer",
"Ba": "Barde",
"Or": "Ordenskrieger",
"Dr": "Druide",
"Hx": "Hexer",
"Ma": "Magier",
"PB": "Priester Beschützer",
"PS": "Priester Streiter",
"Sc": "Schamane",
}
for code, name := range characterClasses {
class := models.CharacterClass{
Code: code,
Name: name,
SourceID: kodSource.ID,
GameSystem: "midgard",
}
// Prüfe ob die Klasse bereits existiert
var existing models.CharacterClass
if err := existing.FirstByCode(code); err != nil {
// Klasse existiert nicht, erstelle sie
if err := class.Create(); err != nil {
return fmt.Errorf("failed to create character class %s: %w", code, err)
}
log.Printf("Created character class: %s - %s (Source: %s)", code, name, kodSource.Code)
}
}
return nil
}
// migrateSkillCategories erstellt Fertigkeitskategorien
func migrateSkillCategories() error {
// Hole die KOD-Quelle für Kategorien
var kodSource models.Source
if err := kodSource.FirstByCode("KOD"); err != nil {
return fmt.Errorf("KOD source not found: %w", err)
}
categories := []string{
"Unbekannt", // Für Fertigkeiten ohne bekannte Kategorie
"Alltag", "Freiland", "Halbwelt", "Kampf", "Körper",
"Sozial", "Unterwelt", "Waffen", "Wissen", "Schilde und Parierwaffen",
}
for _, categoryName := range categories {
sourceID := kodSource.ID
// "Unbekannt" bekommt die UNB-Quelle
if categoryName == "Unbekannt" {
var unbSource models.Source
if err := unbSource.FirstByCode("UNB"); err != nil {
return fmt.Errorf("UNB source not found: %w", err)
}
sourceID = unbSource.ID
}
category := models.SkillCategory{
Name: categoryName,
SourceID: sourceID,
GameSystem: "midgard",
}
// Prüfe ob die Kategorie bereits existiert
var existing models.SkillCategory
if err := existing.FirstByName(categoryName); err != nil {
// Kategorie existiert nicht, erstelle sie
if err := category.Create(); err != nil {
return fmt.Errorf("failed to create skill category %s: %w", categoryName, err)
}
log.Printf("Created skill category: %s", categoryName)
}
}
return nil
}
// migrateSkillDifficulties erstellt Schwierigkeitsgrade
func migrateSkillDifficulties() error {
difficulties := []string{"leicht", "normal", "schwer", "sehr schwer"}
for _, difficultyName := range difficulties {
difficulty := models.SkillDifficulty{
Name: difficultyName,
GameSystem: "midgard",
}
// Prüfe ob die Schwierigkeit bereits existiert
var existing models.SkillDifficulty
if err := existing.FirstByName(difficultyName); err != nil {
// Schwierigkeit existiert nicht, erstelle sie
if err := difficulty.Create(); err != nil {
return fmt.Errorf("failed to create skill difficulty %s: %w", difficultyName, err)
}
log.Printf("Created skill difficulty: %s", difficultyName)
}
}
return nil
}
// migrateSpellSchools erstellt Zauberschulen
func migrateSpellSchools() error {
// Hole die KOD-Quelle für Basis-Zauberschulen, ARK für erweiterte
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)
}
schools := map[string]uint{
// Basis-Zauberschulen (Kodex)
"Beherrschen": kodSource.ID,
"Bewegen": kodSource.ID,
"Erkennen": kodSource.ID,
"Erschaffen": kodSource.ID,
"Formen": kodSource.ID,
"Verändern": kodSource.ID,
"Zerstören": kodSource.ID,
"Wunder": kodSource.ID,
// Erweiterte Zauberschulen (Arkanum)
"Dweomer": arkSource.ID,
"Lied": arkSource.ID,
}
for schoolName, sourceID := range schools {
school := models.SpellSchool{
Name: schoolName,
SourceID: sourceID,
GameSystem: "midgard",
}
// Prüfe ob die Schule bereits existiert
var existing models.SpellSchool
if err := existing.FirstByName(schoolName); err != nil {
// Schule existiert nicht, erstelle sie
if err := school.Create(); err != nil {
return fmt.Errorf("failed to create spell school %s: %w", schoolName, err)
}
log.Printf("Created spell school: %s", schoolName)
}
}
return nil
}
// migrateClassCategoryEPCosts migriert EP-Kosten für Kategorien
func migrateClassCategoryEPCosts() error {
for classCode, categories := range learningCostsData.EPPerTE {
// Hole die Charakterklasse
var characterClass models.CharacterClass
if err := characterClass.FirstByCode(classCode); err != nil {
return fmt.Errorf("character class %s not found: %w", classCode, err)
}
for categoryName, epCost := range categories {
// Hole die Kategorie
var skillCategory models.SkillCategory
if err := skillCategory.FirstByName(categoryName); err != nil {
return fmt.Errorf("skill category %s not found: %w", categoryName, err)
}
// Erstelle EP-Kosten-Eintrag
cost := models.ClassCategoryEPCost{
CharacterClassID: characterClass.ID,
SkillCategoryID: skillCategory.ID,
EPPerTE: epCost,
}
if err := cost.Create(); err != nil {
return fmt.Errorf("failed to create EP cost for class %s category %s: %w", classCode, categoryName, err)
}
log.Printf("Created EP cost: %s - %s = %d EP/TE", classCode, categoryName, epCost)
}
}
return nil
}
// migrateClassSpellSchoolEPCosts migriert EP-Kosten für Zauberschulen
func migrateClassSpellSchoolEPCosts() error {
for classCode, schools := range learningCostsData.SpellEPPerLE {
// Hole die Charakterklasse
var characterClass models.CharacterClass
if err := characterClass.FirstByCode(classCode); err != nil {
return fmt.Errorf("character class %s not found: %w", classCode, err)
}
for schoolName, epCost := range schools {
// Überspringe Schulen mit 0 EP-Kosten (nicht verfügbar)
if epCost == 0 {
continue
}
// Hole die Zauberschule
var spellSchool models.SpellSchool
if err := spellSchool.FirstByName(schoolName); err != nil {
return fmt.Errorf("spell school %s not found: %w", schoolName, err)
}
// Erstelle EP-Kosten-Eintrag
cost := models.ClassSpellSchoolEPCost{
CharacterClassID: characterClass.ID,
SpellSchoolID: spellSchool.ID,
EPPerLE: epCost,
}
if err := cost.Create(); err != nil {
return fmt.Errorf("failed to create spell EP cost for class %s school %s: %w", classCode, schoolName, err)
}
log.Printf("Created spell EP cost: %s - %s = %d EP/LE", classCode, schoolName, epCost)
}
}
return nil
}
// migrateSpellLevelLECosts migriert LE-Kosten pro Zauber-Level
func migrateSpellLevelLECosts() error {
for level, leCost := range learningCostsData.SpellLEPerLevel {
cost := models.SpellLevelLECost{
Level: level,
LERequired: leCost,
GameSystem: "midgard",
}
if err := cost.Create(); err != nil {
return fmt.Errorf("failed to create spell level LE cost for level %d: %w", level, err)
}
log.Printf("Created spell level LE cost: Level %d = %d LE", level, leCost)
}
return nil
}
// migrateSkillCategoryDifficulties migriert Fertigkeits-Kategorien-Schwierigkeiten
func migrateSkillCategoryDifficulties() error {
for categoryName, difficulties := range learningCostsData.ImprovementCost {
// Hole die Kategorie
var skillCategory models.SkillCategory
if err := skillCategory.FirstByName(categoryName); err != nil {
return fmt.Errorf("skill category %s not found: %w", categoryName, err)
}
for difficultyName, data := range difficulties {
// Hole die Schwierigkeit
var skillDifficulty models.SkillDifficulty
if err := skillDifficulty.FirstByName(difficultyName); err != nil {
return fmt.Errorf("skill difficulty %s not found: %w", difficultyName, err)
}
// Für jede Fertigkeit in dieser Kategorie/Schwierigkeit
for _, skillName := range data.Skills {
// Hole die Fertigkeit aus der bestehenden Skill-Tabelle
var skill models.Skill
if err := skill.First(skillName); err != nil {
// Wenn die Fertigkeit nicht existiert, überspringe sie oder logge eine Warnung
log.Printf("Warning: Skill %s not found in database, skipping", skillName)
continue
}
// Erstelle Kategorie-Schwierigkeits-Eintrag
categoryDifficulty := models.SkillCategoryDifficulty{
SkillID: skill.ID,
SkillCategoryID: skillCategory.ID,
SkillDifficultyID: skillDifficulty.ID,
LearnCost: data.LearnCost,
}
if err := categoryDifficulty.Create(); err != nil {
return fmt.Errorf("failed to create skill category difficulty for %s: %w", skillName, err)
}
log.Printf("Created skill category difficulty: %s - %s - %s (Learn: %d LE)",
skillName, categoryName, difficultyName, data.LearnCost)
}
}
}
return nil
}
// migrateSkillImprovementCosts migriert Verbesserungskosten
func migrateSkillImprovementCosts() error {
for categoryName, difficulties := range learningCostsData.ImprovementCost {
// Hole die Kategorie
var skillCategory models.SkillCategory
if err := skillCategory.FirstByName(categoryName); err != nil {
return fmt.Errorf("skill category %s not found: %w", categoryName, err)
}
for difficultyName, data := range difficulties {
// Hole die Schwierigkeit
var skillDifficulty models.SkillDifficulty
if err := skillDifficulty.FirstByName(difficultyName); err != nil {
return fmt.Errorf("skill difficulty %s not found: %w", difficultyName, err)
}
// Für jede Fertigkeit in dieser Kategorie/Schwierigkeit
for _, skillName := range data.Skills {
// Hole die Fertigkeit
var skill models.Skill
if err := skill.First(skillName); err != nil {
log.Printf("Warning: Skill %s not found in database, skipping improvement costs", skillName)
continue
}
// Finde den entsprechenden SkillCategoryDifficulty-Eintrag
var categoryDifficulty models.SkillCategoryDifficulty
if err := database.DB.Where("skill_id = ? AND skill_category_id = ? AND skill_difficulty_id = ?",
skill.ID, skillCategory.ID, skillDifficulty.ID).First(&categoryDifficulty).Error; err != nil {
log.Printf("Warning: SkillCategoryDifficulty not found for %s, skipping improvement costs", skillName)
continue
}
// Für jeden Level in TrainCosts
for level, teCost := range data.TrainCosts {
improvementCost := models.SkillImprovementCost{
SkillCategoryDifficultyID: categoryDifficulty.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)
}
log.Printf("Created improvement cost: %s - %s - %s Level %d = %d TE",
skillName, categoryName, difficultyName, level, teCost)
}
}
}
}
return nil
}
// migrateUnknownCategoryEPCosts fügt EP-Kosten für die "Unbekannt"-Kategorie hinzu
func migrateUnknownCategoryEPCosts() error {
// Hole die "Unbekannt"-Kategorie
var unknownCategory models.SkillCategory
if err := unknownCategory.FirstByName("Unbekannt"); err != nil {
return fmt.Errorf("unknown category not found: %w", err)
}
// Hole alle Charakterklassen
var characterClasses []models.CharacterClass
if err := database.DB.Find(&characterClasses).Error; err != nil {
return fmt.Errorf("failed to fetch character classes: %w", err)
}
// Standard EP-Kosten für "Unbekannt": 50 EP/TE
standardEPCost := 50
for _, characterClass := range characterClasses {
// Prüfe ob bereits EP-Kosten für diese Klasse und "Unbekannt" existieren
var existingCost models.ClassCategoryEPCost
err := database.DB.Where("character_class_id = ? AND skill_category_id = ?",
characterClass.ID, unknownCategory.ID).First(&existingCost).Error
if err == nil {
// EP-Kosten existieren bereits, überspringe
log.Printf("EP cost for class %s and category 'Unbekannt' already exists, skipping", characterClass.Code)
continue
}
// Erstelle EP-Kosten-Eintrag für "Unbekannt"
cost := models.ClassCategoryEPCost{
CharacterClassID: characterClass.ID,
SkillCategoryID: unknownCategory.ID,
EPPerTE: standardEPCost,
}
if err := cost.Create(); err != nil {
return fmt.Errorf("failed to create EP cost for class %s category 'Unbekannt': %w", characterClass.Code, err)
}
log.Printf("Created EP cost: %s - Unbekannt = %d EP/TE", characterClass.Code, standardEPCost)
}
return nil
}